diff options
1680 files changed, 151874 insertions, 80329 deletions
diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt index 65a1482457a8..86334b6f8238 100644 --- a/Documentation/feature-removal-schedule.txt +++ b/Documentation/feature-removal-schedule.txt @@ -308,9 +308,31 @@ Who: Matthew Wilcox <willy@linux.intel.com> --------------------------- +What: SCTP_GET_PEER_ADDRS_NUM_OLD, SCTP_GET_PEER_ADDRS_OLD, + SCTP_GET_LOCAL_ADDRS_NUM_OLD, SCTP_GET_LOCAL_ADDRS_OLD +When: June 2009 +Why: A newer version of the options have been introduced in 2005 that + removes the limitions of the old API. The sctp library has been + converted to use these new options at the same time. Any user + space app that directly uses the old options should convert to using + the new options. +Who: Vlad Yasevich <vladislav.yasevich@hp.com> + +--------------------------- + What: CONFIG_THERMAL_HWMON When: January 2009 Why: This option was introduced just to allow older lm-sensors userspace to keep working over the upgrade to 2.6.26. At the scheduled time of removal fixed lm-sensors (2.x or 3.x) should be readily available. Who: Rene Herman <rene.herman@gmail.com> + +--------------------------- + +What: Code that is now under CONFIG_WIRELESS_EXT_SYSFS + (in net/core/net-sysfs.c) +When: After the only user (hal) has seen a release with the patches + for enough time, probably some time in 2010. +Why: Over 1K .text/.data size reduction, data is available in other + ways (ioctls) +Who: Johannes Berg <johannes@sipsolutions.net> diff --git a/Documentation/filesystems/configfs/configfs.txt b/Documentation/filesystems/configfs/configfs.txt index 15838d706ea2..44c97e6accb2 100644 --- a/Documentation/filesystems/configfs/configfs.txt +++ b/Documentation/filesystems/configfs/configfs.txt @@ -233,12 +233,10 @@ accomplished via the group operations specified on the group's config_item_type. struct configfs_group_operations { - int (*make_item)(struct config_group *group, - const char *name, - struct config_item **new_item); - int (*make_group)(struct config_group *group, - const char *name, - struct config_group **new_group); + struct config_item *(*make_item)(struct config_group *group, + const char *name); + struct config_group *(*make_group)(struct config_group *group, + const char *name); int (*commit_item)(struct config_item *item); void (*disconnect_notify)(struct config_group *group, struct config_item *item); diff --git a/Documentation/filesystems/configfs/configfs_example.c b/Documentation/filesystems/configfs/configfs_example.c index 0b422acd470c..039648791701 100644 --- a/Documentation/filesystems/configfs/configfs_example.c +++ b/Documentation/filesystems/configfs/configfs_example.c @@ -273,13 +273,13 @@ static inline struct simple_children *to_simple_children(struct config_item *ite return item ? container_of(to_config_group(item), struct simple_children, group) : NULL; } -static int simple_children_make_item(struct config_group *group, const char *name, struct config_item **new_item) +static struct config_item *simple_children_make_item(struct config_group *group, const char *name) { struct simple_child *simple_child; simple_child = kzalloc(sizeof(struct simple_child), GFP_KERNEL); if (!simple_child) - return -ENOMEM; + return ERR_PTR(-ENOMEM); config_item_init_type_name(&simple_child->item, name, @@ -287,8 +287,7 @@ static int simple_children_make_item(struct config_group *group, const char *nam simple_child->storeme = 0; - *new_item = &simple_child->item; - return 0; + return &simple_child->item; } static struct configfs_attribute simple_children_attr_description = { @@ -360,21 +359,20 @@ static struct configfs_subsystem simple_children_subsys = { * children of its own. */ -static int group_children_make_group(struct config_group *group, const char *name, struct config_group **new_group) +static struct config_group *group_children_make_group(struct config_group *group, const char *name) { struct simple_children *simple_children; simple_children = kzalloc(sizeof(struct simple_children), GFP_KERNEL); if (!simple_children) - return -ENOMEM; + return ERR_PTR(-ENOMEM); config_group_init_type_name(&simple_children->group, name, &simple_children_type); - *new_group = &simple_children->group; - return 0; + return &simple_children->group; } static struct configfs_attribute group_children_attr_description = { diff --git a/Documentation/filesystems/nfs-rdma.txt b/Documentation/filesystems/nfs-rdma.txt index d0ec45ae4e7d..44bd766f2e5d 100644 --- a/Documentation/filesystems/nfs-rdma.txt +++ b/Documentation/filesystems/nfs-rdma.txt @@ -5,7 +5,7 @@ ################################################################################ Author: NetApp and Open Grid Computing - Date: April 15, 2008 + Date: May 29, 2008 Table of Contents ~~~~~~~~~~~~~~~~~ @@ -60,16 +60,18 @@ Installation The procedures described in this document have been tested with distributions from Red Hat's Fedora Project (http://fedora.redhat.com/). - - Install nfs-utils-1.1.1 or greater on the client + - Install nfs-utils-1.1.2 or greater on the client - An NFS/RDMA mount point can only be obtained by using the mount.nfs - command in nfs-utils-1.1.1 or greater. To see which version of mount.nfs - you are using, type: + An NFS/RDMA mount point can be obtained by using the mount.nfs command in + nfs-utils-1.1.2 or greater (nfs-utils-1.1.1 was the first nfs-utils + version with support for NFS/RDMA mounts, but for various reasons we + recommend using nfs-utils-1.1.2 or greater). To see which version of + mount.nfs you are using, type: - > /sbin/mount.nfs -V + $ /sbin/mount.nfs -V - If the version is less than 1.1.1 or the command does not exist, - then you will need to install the latest version of nfs-utils. + If the version is less than 1.1.2 or the command does not exist, + you should install the latest version of nfs-utils. Download the latest package from: @@ -77,22 +79,33 @@ Installation Uncompress the package and follow the installation instructions. - If you will not be using GSS and NFSv4, the installation process - can be simplified by disabling these features when running configure: + If you will not need the idmapper and gssd executables (you do not need + these to create an NFS/RDMA enabled mount command), the installation + process can be simplified by disabling these features when running + configure: - > ./configure --disable-gss --disable-nfsv4 + $ ./configure --disable-gss --disable-nfsv4 - For more information on this see the package's README and INSTALL files. + To build nfs-utils you will need the tcp_wrappers package installed. For + more information on this see the package's README and INSTALL files. After building the nfs-utils package, there will be a mount.nfs binary in the utils/mount directory. This binary can be used to initiate NFS v2, v3, - or v4 mounts. To initiate a v4 mount, the binary must be called mount.nfs4. - The standard technique is to create a symlink called mount.nfs4 to mount.nfs. + or v4 mounts. To initiate a v4 mount, the binary must be called + mount.nfs4. The standard technique is to create a symlink called + mount.nfs4 to mount.nfs. - NOTE: mount.nfs and therefore nfs-utils-1.1.1 or greater is only needed + This mount.nfs binary should be installed at /sbin/mount.nfs as follows: + + $ sudo cp utils/mount/mount.nfs /sbin/mount.nfs + + In this location, mount.nfs will be invoked automatically for NFS mounts + by the system mount commmand. + + NOTE: mount.nfs and therefore nfs-utils-1.1.2 or greater is only needed on the NFS client machine. You do not need this specific version of nfs-utils on the server. Furthermore, only the mount.nfs command from - nfs-utils-1.1.1 is needed on the client. + nfs-utils-1.1.2 is needed on the client. - Install a Linux kernel with NFS/RDMA @@ -156,8 +169,8 @@ Check RDMA and NFS Setup this time. For example, if you are using a Mellanox Tavor/Sinai/Arbel card: - > modprobe ib_mthca - > modprobe ib_ipoib + $ modprobe ib_mthca + $ modprobe ib_ipoib If you are using InfiniBand, make sure there is a Subnet Manager (SM) running on the network. If your IB switch has an embedded SM, you can @@ -166,7 +179,7 @@ Check RDMA and NFS Setup If an SM is running on your network, you should see the following: - > cat /sys/class/infiniband/driverX/ports/1/state + $ cat /sys/class/infiniband/driverX/ports/1/state 4: ACTIVE where driverX is mthca0, ipath5, ehca3, etc. @@ -174,10 +187,10 @@ Check RDMA and NFS Setup To further test the InfiniBand software stack, use IPoIB (this assumes you have two IB hosts named host1 and host2): - host1> ifconfig ib0 a.b.c.x - host2> ifconfig ib0 a.b.c.y - host1> ping a.b.c.y - host2> ping a.b.c.x + host1$ ifconfig ib0 a.b.c.x + host2$ ifconfig ib0 a.b.c.y + host1$ ping a.b.c.y + host2$ ping a.b.c.x For other device types, follow the appropriate procedures. @@ -202,11 +215,11 @@ NFS/RDMA Setup /vol0 192.168.0.47(fsid=0,rw,async,insecure,no_root_squash) /vol0 192.168.0.0/255.255.255.0(fsid=0,rw,async,insecure,no_root_squash) - The IP address(es) is(are) the client's IPoIB address for an InfiniBand HCA or the - cleint's iWARP address(es) for an RNIC. + The IP address(es) is(are) the client's IPoIB address for an InfiniBand + HCA or the cleint's iWARP address(es) for an RNIC. - NOTE: The "insecure" option must be used because the NFS/RDMA client does not - use a reserved port. + NOTE: The "insecure" option must be used because the NFS/RDMA client does + not use a reserved port. Each time a machine boots: @@ -214,43 +227,45 @@ NFS/RDMA Setup For InfiniBand using a Mellanox adapter: - > modprobe ib_mthca - > modprobe ib_ipoib - > ifconfig ib0 a.b.c.d + $ modprobe ib_mthca + $ modprobe ib_ipoib + $ ifconfig ib0 a.b.c.d NOTE: use unique addresses for the client and server - Start the NFS server - If the NFS/RDMA server was built as a module (CONFIG_SUNRPC_XPRT_RDMA=m in kernel config), - load the RDMA transport module: + If the NFS/RDMA server was built as a module (CONFIG_SUNRPC_XPRT_RDMA=m in + kernel config), load the RDMA transport module: - > modprobe svcrdma + $ modprobe svcrdma - Regardless of how the server was built (module or built-in), start the server: + Regardless of how the server was built (module or built-in), start the + server: - > /etc/init.d/nfs start + $ /etc/init.d/nfs start or - > service nfs start + $ service nfs start Instruct the server to listen on the RDMA transport: - > echo rdma 2050 > /proc/fs/nfsd/portlist + $ echo rdma 2050 > /proc/fs/nfsd/portlist - On the client system - If the NFS/RDMA client was built as a module (CONFIG_SUNRPC_XPRT_RDMA=m in kernel config), - load the RDMA client module: + If the NFS/RDMA client was built as a module (CONFIG_SUNRPC_XPRT_RDMA=m in + kernel config), load the RDMA client module: - > modprobe xprtrdma.ko + $ modprobe xprtrdma.ko - Regardless of how the client was built (module or built-in), issue the mount.nfs command: + Regardless of how the client was built (module or built-in), use this + command to mount the NFS/RDMA server: - > /path/to/your/mount.nfs <IPoIB-server-name-or-address>:/<export> /mnt -i -o rdma,port=2050 + $ mount -o rdma,port=2050 <IPoIB-server-name-or-address>:/<export> /mnt - To verify that the mount is using RDMA, run "cat /proc/mounts" and check the - "proto" field for the given mount. + To verify that the mount is using RDMA, run "cat /proc/mounts" and check + the "proto" field for the given mount. Congratulations! You're using NFS/RDMA! diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index 09ad7450647b..25e88cf5d84e 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -1206,7 +1206,7 @@ and is between 256 and 4096 characters. It is defined in the file or memmap=0x10000$0x18690000 - memtest= [KNL,X86_64] Enable memtest + memtest= [KNL,X86] Enable memtest Format: <integer> range: 0,4 : pattern number default : 0 <disable> @@ -2158,6 +2158,10 @@ and is between 256 and 4096 characters. It is defined in the file Note that genuine overcurrent events won't be reported either. + unknown_nmi_panic + [X86-32,X86-64] + Set unknown_nmi_panic=1 early on boot. + usbcore.autosuspend= [USB] The autosuspend time delay (in seconds) used for newly-detected USB devices (default 2). This diff --git a/Documentation/networking/bonding.txt b/Documentation/networking/bonding.txt index a0cda062bc33..7fa7fe71d7a8 100644 --- a/Documentation/networking/bonding.txt +++ b/Documentation/networking/bonding.txt @@ -289,35 +289,73 @@ downdelay fail_over_mac Specifies whether active-backup mode should set all slaves to - the same MAC address (the traditional behavior), or, when - enabled, change the bond's MAC address when changing the - active interface (i.e., fail over the MAC address itself). - - Fail over MAC is useful for devices that cannot ever alter - their MAC address, or for devices that refuse incoming - broadcasts with their own source MAC (which interferes with - the ARP monitor). - - The down side of fail over MAC is that every device on the - network must be updated via gratuitous ARP, vs. just updating - a switch or set of switches (which often takes place for any - traffic, not just ARP traffic, if the switch snoops incoming - traffic to update its tables) for the traditional method. If - the gratuitous ARP is lost, communication may be disrupted. - - When fail over MAC is used in conjuction with the mii monitor, - devices which assert link up prior to being able to actually - transmit and receive are particularly susecptible to loss of - the gratuitous ARP, and an appropriate updelay setting may be - required. - - A value of 0 disables fail over MAC, and is the default. A - value of 1 enables fail over MAC. This option is enabled - automatically if the first slave added cannot change its MAC - address. This option may be modified via sysfs only when no - slaves are present in the bond. - - This option was added in bonding version 3.2.0. + the same MAC address at enslavement (the traditional + behavior), or, when enabled, perform special handling of the + bond's MAC address in accordance with the selected policy. + + Possible values are: + + none or 0 + + This setting disables fail_over_mac, and causes + bonding to set all slaves of an active-backup bond to + the same MAC address at enslavement time. This is the + default. + + active or 1 + + The "active" fail_over_mac policy indicates that the + MAC address of the bond should always be the MAC + address of the currently active slave. The MAC + address of the slaves is not changed; instead, the MAC + address of the bond changes during a failover. + + This policy is useful for devices that cannot ever + alter their MAC address, or for devices that refuse + incoming broadcasts with their own source MAC (which + interferes with the ARP monitor). + + The down side of this policy is that every device on + the network must be updated via gratuitous ARP, + vs. just updating a switch or set of switches (which + often takes place for any traffic, not just ARP + traffic, if the switch snoops incoming traffic to + update its tables) for the traditional method. If the + gratuitous ARP is lost, communication may be + disrupted. + + When this policy is used in conjuction with the mii + monitor, devices which assert link up prior to being + able to actually transmit and receive are particularly + susecptible to loss of the gratuitous ARP, and an + appropriate updelay setting may be required. + + follow or 2 + + The "follow" fail_over_mac policy causes the MAC + address of the bond to be selected normally (normally + the MAC address of the first slave added to the bond). + However, the second and subsequent slaves are not set + to this MAC address while they are in a backup role; a + slave is programmed with the bond's MAC address at + failover time (and the formerly active slave receives + the newly active slave's MAC address). + + This policy is useful for multiport devices that + either become confused or incur a performance penalty + when multiple ports are programmed with the same MAC + address. + + + The default policy is none, unless the first slave cannot + change its MAC address, in which case the active policy is + selected by default. + + This option may be modified via sysfs only when no slaves are + present in the bond. + + This option was added in bonding version 3.2.0. The "follow" + policy was added in bonding version 3.3.0. lacp_rate @@ -338,7 +376,8 @@ max_bonds Specifies the number of bonding devices to create for this instance of the bonding driver. E.g., if max_bonds is 3, and the bonding driver is not already loaded, then bond0, bond1 - and bond2 will be created. The default value is 1. + and bond2 will be created. The default value is 1. Specifying + a value of 0 will load bonding, but will not create any devices. miimon @@ -501,6 +540,17 @@ mode swapped with the new curr_active_slave that was chosen. +num_grat_arp + + Specifies the number of gratuitous ARPs to be issued after a + failover event. One gratuitous ARP is issued immediately after + the failover, subsequent ARPs are sent at a rate of one per link + monitor interval (arp_interval or miimon, whichever is active). + + The valid range is 0 - 255; the default value is 1. This option + affects only the active-backup mode. This option was added for + bonding version 3.3.0. + primary A string (eth0, eth2, etc) specifying which slave is the diff --git a/Documentation/networking/dm9000.txt b/Documentation/networking/dm9000.txt new file mode 100644 index 000000000000..65df3dea5561 --- /dev/null +++ b/Documentation/networking/dm9000.txt @@ -0,0 +1,167 @@ +DM9000 Network driver +===================== + +Copyright 2008 Simtec Electronics, + Ben Dooks <ben@simtec.co.uk> <ben-linux@fluff.org> + + +Introduction +------------ + +This file describes how to use the DM9000 platform-device based network driver +that is contained in the files drivers/net/dm9000.c and drivers/net/dm9000.h. + +The driver supports three DM9000 variants, the DM9000E which is the first chip +supported as well as the newer DM9000A and DM9000B devices. It is currently +maintained and tested by Ben Dooks, who should be CC: to any patches for this +driver. + + +Defining the platform device +---------------------------- + +The minimum set of resources attached to the platform device are as follows: + + 1) The physical address of the address register + 2) The physical address of the data register + 3) The IRQ line the device's interrupt pin is connected to. + +These resources should be specified in that order, as the ordering of the +two address regions is important (the driver expects these to be address +and then data). + +An example from arch/arm/mach-s3c2410/mach-bast.c is: + +static struct resource bast_dm9k_resource[] = { + [0] = { + .start = S3C2410_CS5 + BAST_PA_DM9000, + .end = S3C2410_CS5 + BAST_PA_DM9000 + 3, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = S3C2410_CS5 + BAST_PA_DM9000 + 0x40, + .end = S3C2410_CS5 + BAST_PA_DM9000 + 0x40 + 0x3f, + .flags = IORESOURCE_MEM, + }, + [2] = { + .start = IRQ_DM9000, + .end = IRQ_DM9000, + .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL, + } +}; + +static struct platform_device bast_device_dm9k = { + .name = "dm9000", + .id = 0, + .num_resources = ARRAY_SIZE(bast_dm9k_resource), + .resource = bast_dm9k_resource, +}; + +Note the setting of the IRQ trigger flag in bast_dm9k_resource[2].flags, +as this will generate a warning if it is not present. The trigger from +the flags field will be passed to request_irq() when registering the IRQ +handler to ensure that the IRQ is setup correctly. + +This shows a typical platform device, without the optional configuration +platform data supplied. The next example uses the same resources, but adds +the optional platform data to pass extra configuration data: + +static struct dm9000_plat_data bast_dm9k_platdata = { + .flags = DM9000_PLATF_16BITONLY, +}; + +static struct platform_device bast_device_dm9k = { + .name = "dm9000", + .id = 0, + .num_resources = ARRAY_SIZE(bast_dm9k_resource), + .resource = bast_dm9k_resource, + .dev = { + .platform_data = &bast_dm9k_platdata, + } +}; + +The platform data is defined in include/linux/dm9000.h and described below. + + +Platform data +------------- + +Extra platform data for the DM9000 can describe the IO bus width to the +device, whether or not an external PHY is attached to the device and +the availability of an external configuration EEPROM. + +The flags for the platform data .flags field are as follows: + +DM9000_PLATF_8BITONLY + + The IO should be done with 8bit operations. + +DM9000_PLATF_16BITONLY + + The IO should be done with 16bit operations. + +DM9000_PLATF_32BITONLY + + The IO should be done with 32bit operations. + +DM9000_PLATF_EXT_PHY + + The chip is connected to an external PHY. + +DM9000_PLATF_NO_EEPROM + + This can be used to signify that the board does not have an + EEPROM, or that the EEPROM should be hidden from the user. + +DM9000_PLATF_SIMPLE_PHY + + Switch to using the simpler PHY polling method which does not + try and read the MII PHY state regularly. This is only available + when using the internal PHY. See the section on link state polling + for more information. + + The config symbol DM9000_FORCE_SIMPLE_PHY_POLL, Kconfig entry + "Force simple NSR based PHY polling" allows this flag to be + forced on at build time. + + +PHY Link state polling +---------------------- + +The driver keeps track of the link state and informs the network core +about link (carrier) availablilty. This is managed by several methods +depending on the version of the chip and on which PHY is being used. + +For the internal PHY, the original (and currently default) method is +to read the MII state, either when the status changes if we have the +necessary interrupt support in the chip or every two seconds via a +periodic timer. + +To reduce the overhead for the internal PHY, there is now the option +of using the DM9000_FORCE_SIMPLE_PHY_POLL config, or DM9000_PLATF_SIMPLE_PHY +platform data option to read the summary information without the +expensive MII accesses. This method is faster, but does not print +as much information. + +When using an external PHY, the driver currently has to poll the MII +link status as there is no method for getting an interrupt on link change. + + +DM9000A / DM9000B +----------------- + +These chips are functionally similar to the DM9000E and are supported easily +by the same driver. The features are: + + 1) Interrupt on internal PHY state change. This means that the periodic + polling of the PHY status may be disabled on these devices when using + the internal PHY. + + 2) TCP/UDP checksum offloading, which the driver does not currently support. + + +ethtool +------- + +The driver supports the ethtool interface for access to the driver +state information, the PHY state and the EEPROM. diff --git a/Documentation/networking/ip-sysctl.txt b/Documentation/networking/ip-sysctl.txt index 946b66e1b652..d84932650fd3 100644 --- a/Documentation/networking/ip-sysctl.txt +++ b/Documentation/networking/ip-sysctl.txt @@ -551,8 +551,9 @@ icmp_echo_ignore_broadcasts - BOOLEAN icmp_ratelimit - INTEGER Limit the maximal rates for sending ICMP packets whose type matches icmp_ratemask (see below) to specific targets. - 0 to disable any limiting, otherwise the maximal rate in jiffies(1) - Default: 100 + 0 to disable any limiting, + otherwise the minimal space between responses in milliseconds. + Default: 1000 icmp_ratemask - INTEGER Mask made of ICMP types for which rates are being limited. @@ -1023,11 +1024,23 @@ max_addresses - INTEGER autoconfigured addresses. Default: 16 +disable_ipv6 - BOOLEAN + Disable IPv6 operation. + Default: FALSE (enable IPv6 operation) + +accept_dad - INTEGER + Whether to accept DAD (Duplicate Address Detection). + 0: Disable DAD + 1: Enable DAD (default) + 2: Enable DAD, and disable IPv6 operation if MAC-based duplicate + link-local address has been found. + icmp/*: ratelimit - INTEGER Limit the maximal rates for sending ICMPv6 packets. - 0 to disable any limiting, otherwise the maximal rate in jiffies(1) - Default: 100 + 0 to disable any limiting, + otherwise the minimal space between responses in milliseconds. + Default: 1000 IPv6 Update by: diff --git a/Documentation/networking/ixgb.txt b/Documentation/networking/ixgb.txt index 7c98277777eb..a0d0ffb5e584 100644 --- a/Documentation/networking/ixgb.txt +++ b/Documentation/networking/ixgb.txt @@ -1,7 +1,7 @@ -Linux* Base Driver for the Intel(R) PRO/10GbE Family of Adapters -================================================================ +Linux Base Driver for 10 Gigabit Intel(R) Network Connection +============================================================= -November 17, 2004 +October 9, 2007 Contents @@ -9,94 +9,151 @@ Contents - In This Release - Identifying Your Adapter +- Building and Installation - Command Line Parameters - Improving Performance +- Additional Configurations +- Known Issues/Troubleshooting - Support + In This Release =============== -This file describes the Linux* Base Driver for the Intel(R) PRO/10GbE Family -of Adapters, version 1.0.x. +This file describes the ixgb Linux Base Driver for the 10 Gigabit Intel(R) +Network Connection. This driver includes support for Itanium(R)2-based +systems. + +For questions related to hardware requirements, refer to the documentation +supplied with your 10 Gigabit adapter. All hardware requirements listed apply +to use with Linux. + +The following features are available in this kernel: + - Native VLANs + - Channel Bonding (teaming) + - SNMP + +Channel Bonding documentation can be found in the Linux kernel source: +/Documentation/networking/bonding.txt + +The driver information previously displayed in the /proc filesystem is not +supported in this release. Alternatively, you can use ethtool (version 1.6 +or later), lspci, and ifconfig to obtain the same information. + +Instructions on updating ethtool can be found in the section "Additional +Configurations" later in this document. -For questions related to hardware requirements, refer to the documentation -supplied with your Intel PRO/10GbE adapter. All hardware requirements listed -apply to use with Linux. Identifying Your Adapter ======================== -To verify your Intel adapter is supported, find the board ID number on the -adapter. Look for a label that has a barcode and a number in the format -A12345-001. +The following Intel network adapters are compatible with the drivers in this +release: + +Controller Adapter Name Physical Layer +---------- ------------ -------------- +82597EX Intel(R) PRO/10GbE LR/SR/CX4 10G Base-LR (1310 nm optical fiber) + Server Adapters 10G Base-SR (850 nm optical fiber) + 10G Base-CX4(twin-axial copper cabling) + +For more information on how to identify your adapter, go to the Adapter & +Driver ID Guide at: + + http://support.intel.com/support/network/sb/CS-012904.htm + + +Building and Installation +========================= + +select m for "Intel(R) PRO/10GbE support" located at: + Location: + -> Device Drivers + -> Network device support (NETDEVICES [=y]) + -> Ethernet (10000 Mbit) (NETDEV_10000 [=y]) +1. make modules && make modules_install + +2. Load the module: + +Â Â Â Â modprobe ixgb <parameter>=<value> + + The insmod command can be used if the full + path to the driver module is specified. For example: + + insmod /lib/modules/<KERNEL VERSION>/kernel/drivers/net/ixgb/ixgb.ko + + With 2.6 based kernels also make sure that older ixgb drivers are + removed from the kernel, before loading the new module: -Use the above information and the Adapter & Driver ID Guide at: + rmmod ixgb; modprobe ixgb - http://support.intel.com/support/network/adapter/pro100/21397.htm +3. Assign an IP address to the interface by entering the following, where + x is the interface number: -For the latest Intel network drivers for Linux, go to: + ifconfig ethx <IP_address> + +4. Verify that the interface works. Enter the following, where <IP_address> + is the IP address for another machine on the same subnet as the interface + that is being tested: + + ping <IP_address> - http://downloadfinder.intel.com/scripts-df/support_intel.asp Command Line Parameters ======================= -If the driver is built as a module, the following optional parameters are -used by entering them on the command line with the modprobe or insmod command -using this syntax: +If the driver is built as a module, the following optional parameters are +used by entering them on the command line with the modprobe command using +this syntax: modprobe ixgb [<option>=<VAL1>,<VAL2>,...] - insmod ixgb [<option>=<VAL1>,<VAL2>,...] +For example, with two 10GbE PCI adapters, entering: -For example, with two PRO/10GbE PCI adapters, entering: + modprobe ixgb TxDescriptors=80,128 - insmod ixgb TxDescriptors=80,128 - -loads the ixgb driver with 80 TX resources for the first adapter and 128 TX +loads the ixgb driver with 80 TX resources for the first adapter and 128 TX resources for the second adapter. The default value for each parameter is generally the recommended setting, -unless otherwise noted. Also, if the driver is statically built into the -kernel, the driver is loaded with the default values for all the parameters. -Ethtool can be used to change some of the parameters at runtime. +unless otherwise noted. FlowControl Valid Range: 0-3 (0=none, 1=Rx only, 2=Tx only, 3=Rx&Tx) Default: Read from the EEPROM - If EEPROM is not detected, default is 3 - This parameter controls the automatic generation(Tx) and response(Rx) to - Ethernet PAUSE frames. + If EEPROM is not detected, default is 1 + This parameter controls the automatic generation(Tx) and response(Rx) to + Ethernet PAUSE frames. There are hardware bugs associated with enabling + Tx flow control so beware. RxDescriptors Valid Range: 64-512 Default Value: 512 - This value is the number of receive descriptors allocated by the driver. - Increasing this value allows the driver to buffer more incoming packets. - Each descriptor is 16 bytes. A receive buffer is also allocated for - each descriptor and can be either 2048, 4056, 8192, or 16384 bytes, - depending on the MTU setting. When the MTU size is 1500 or less, the + This value is the number of receive descriptors allocated by the driver. + Increasing this value allows the driver to buffer more incoming packets. + Each descriptor is 16 bytes. A receive buffer is also allocated for + each descriptor and can be either 2048, 4056, 8192, or 16384 bytes, + depending on the MTU setting. When the MTU size is 1500 or less, the receive buffer size is 2048 bytes. When the MTU is greater than 1500 the - receive buffer size will be either 4056, 8192, or 16384 bytes. The + receive buffer size will be either 4056, 8192, or 16384 bytes. The maximum MTU size is 16114. RxIntDelay Valid Range: 0-65535 (0=off) -Default Value: 6 - This value delays the generation of receive interrupts in units of - 0.8192 microseconds. Receive interrupt reduction can improve CPU - efficiency if properly tuned for specific network traffic. Increasing - this value adds extra latency to frame reception and can end up - decreasing the throughput of TCP traffic. If the system is reporting - dropped receives, this value may be set too high, causing the driver to +Default Value: 72 + This value delays the generation of receive interrupts in units of + 0.8192 microseconds. Receive interrupt reduction can improve CPU + efficiency if properly tuned for specific network traffic. Increasing + this value adds extra latency to frame reception and can end up + decreasing the throughput of TCP traffic. If the system is reporting + dropped receives, this value may be set too high, causing the driver to run out of available receive descriptors. TxDescriptors Valid Range: 64-4096 Default Value: 256 This value is the number of transmit descriptors allocated by the driver. - Increasing this value allows the driver to queue more transmits. Each + Increasing this value allows the driver to queue more transmits. Each descriptor is 16 bytes. XsumRX @@ -105,51 +162,49 @@ Default Value: 1 A value of '1' indicates that the driver should enable IP checksum offload for received packets (both UDP and TCP) to the adapter hardware. -XsumTX -Valid Range: 0-1 -Default Value: 1 - A value of '1' indicates that the driver should enable IP checksum - offload for transmitted packets (both UDP and TCP) to the adapter - hardware. Improving Performance ===================== -With the Intel PRO/10 GbE adapter, the default Linux configuration will very -likely limit the total available throughput artificially. There is a set of -things that when applied together increase the ability of Linux to transmit -and receive data. The following enhancements were originally acquired from -settings published at http://www.spec.org/web99 for various submitted results -using Linux. +With the 10 Gigabit server adapters, the default Linux configuration will +very likely limit the total available throughput artificially. There is a set +of configuration changes that, when applied together, will increase the ability +of Linux to transmit and receive data. The following enhancements were +originally acquired from settings published at http://www.spec.org/web99/ for +various submitted results using Linux. -NOTE: These changes are only suggestions, and serve as a starting point for -tuning your network performance. +NOTE: These changes are only suggestions, and serve as a starting point for + tuning your network performance. The changes are made in three major ways, listed in order of greatest effect: -- Use ifconfig to modify the mtu (maximum transmission unit) and the txqueuelen +- Use ifconfig to modify the mtu (maximum transmission unit) and the txqueuelen parameter. - Use sysctl to modify /proc parameters (essentially kernel tuning) -- Use setpci to modify the MMRBC field in PCI-X configuration space to increase +- Use setpci to modify the MMRBC field in PCI-X configuration space to increase transmit burst lengths on the bus. -NOTE: setpci modifies the adapter's configuration registers to allow it to read -up to 4k bytes at a time (for transmits). However, for some systems the -behavior after modifying this register may be undefined (possibly errors of some -kind). A power-cycle, hard reset or explicitly setting the e6 register back to -22 (setpci -d 8086:1048 e6.b=22) may be required to get back to a stable -configuration. +NOTE: setpci modifies the adapter's configuration registers to allow it to read +up to 4k bytes at a time (for transmits). However, for some systems the +behavior after modifying this register may be undefined (possibly errors of +some kind). A power-cycle, hard reset or explicitly setting the e6 register +back to 22 (setpci -d 8086:1a48 e6.b=22) may be required to get back to a +stable configuration. - COPY these lines and paste them into ixgb_perf.sh: #!/bin/bash -echo "configuring network performance , edit this file to change the interface" +echo "configuring network performance , edit this file to change the interface +or device ID of 10GbE card" # set mmrbc to 4k reads, modify only Intel 10GbE device IDs -setpci -d 8086:1048 e6.b=2e -# set the MTU (max transmission unit) - it requires your switch and clients to change too! +# replace 1a48 with appropriate 10GbE device's ID installed on the system, +# if needed. +setpci -d 8086:1a48 e6.b=2e +# set the MTU (max transmission unit) - it requires your switch and clients +# to change as well. # set the txqueuelen # your ixgb adapter should be loaded as eth1 for this to work, change if needed ifconfig eth1 mtu 9000 txqueuelen 1000 up -# call the sysctl utility to modify /proc/sys entries -sysctl -p ./sysctl_ixgb.conf +# call the sysctl utility to modify /proc/sys entries +sysctl -p ./sysctl_ixgb.conf - END ixgb_perf.sh - COPY these lines and paste them into sysctl_ixgb.conf: @@ -159,54 +214,220 @@ sysctl -p ./sysctl_ixgb.conf # several network benchmark tests, your mileage may vary ### IPV4 specific settings -net.ipv4.tcp_timestamps = 0 # turns TCP timestamp support off, default 1, reduces CPU use -net.ipv4.tcp_sack = 0 # turn SACK support off, default on -# on systems with a VERY fast bus -> memory interface this is the big gainer -net.ipv4.tcp_rmem = 10000000 10000000 10000000 # sets min/default/max TCP read buffer, default 4096 87380 174760 -net.ipv4.tcp_wmem = 10000000 10000000 10000000 # sets min/pressure/max TCP write buffer, default 4096 16384 131072 -net.ipv4.tcp_mem = 10000000 10000000 10000000 # sets min/pressure/max TCP buffer space, default 31744 32256 32768 +# turn TCP timestamp support off, default 1, reduces CPU use +net.ipv4.tcp_timestamps = 0 +# turn SACK support off, default on +# on systems with a VERY fast bus -> memory interface this is the big gainer +net.ipv4.tcp_sack = 0 +# set min/default/max TCP read buffer, default 4096 87380 174760 +net.ipv4.tcp_rmem = 10000000 10000000 10000000 +# set min/pressure/max TCP write buffer, default 4096 16384 131072 +net.ipv4.tcp_wmem = 10000000 10000000 10000000 +# set min/pressure/max TCP buffer space, default 31744 32256 32768 +net.ipv4.tcp_mem = 10000000 10000000 10000000 ### CORE settings (mostly for socket and UDP effect) -net.core.rmem_max = 524287 # maximum receive socket buffer size, default 131071 -net.core.wmem_max = 524287 # maximum send socket buffer size, default 131071 -net.core.rmem_default = 524287 # default receive socket buffer size, default 65535 -net.core.wmem_default = 524287 # default send socket buffer size, default 65535 -net.core.optmem_max = 524287 # maximum amount of option memory buffers, default 10240 -net.core.netdev_max_backlog = 300000 # number of unprocessed input packets before kernel starts dropping them, default 300 +# set maximum receive socket buffer size, default 131071 +net.core.rmem_max = 524287 +# set maximum send socket buffer size, default 131071 +net.core.wmem_max = 524287 +# set default receive socket buffer size, default 65535 +net.core.rmem_default = 524287 +# set default send socket buffer size, default 65535 +net.core.wmem_default = 524287 +# set maximum amount of option memory buffers, default 10240 +net.core.optmem_max = 524287 +# set number of unprocessed input packets before kernel starts dropping them; default 300 +net.core.netdev_max_backlog = 300000 - END sysctl_ixgb.conf -Edit the ixgb_perf.sh script if necessary to change eth1 to whatever interface -your ixgb driver is using. +Edit the ixgb_perf.sh script if necessary to change eth1 to whatever interface +your ixgb driver is using and/or replace '1a48' with appropriate 10GbE device's +ID installed on the system. -NOTE: Unless these scripts are added to the boot process, these changes will -only last only until the next system reboot. +NOTE: Unless these scripts are added to the boot process, these changes will + only last only until the next system reboot. Resolving Slow UDP Traffic -------------------------- +If your server does not seem to be able to receive UDP traffic as fast as it +can receive TCP traffic, it could be because Linux, by default, does not set +the network stack buffers as large as they need to be to support high UDP +transfer rates. One way to alleviate this problem is to allow more memory to +be used by the IP stack to store incoming data. -If your server does not seem to be able to receive UDP traffic as fast as it -can receive TCP traffic, it could be because Linux, by default, does not set -the network stack buffers as large as they need to be to support high UDP -transfer rates. One way to alleviate this problem is to allow more memory to -be used by the IP stack to store incoming data. - -For instance, use the commands: +For instance, use the commands: sysctl -w net.core.rmem_max=262143 and sysctl -w net.core.rmem_default=262143 -to increase the read buffer memory max and default to 262143 (256k - 1) from -defaults of max=131071 (128k - 1) and default=65535 (64k - 1). These variables -will increase the amount of memory used by the network stack for receives, and +to increase the read buffer memory max and default to 262143 (256k - 1) from +defaults of max=131071 (128k - 1) and default=65535 (64k - 1). These variables +will increase the amount of memory used by the network stack for receives, and can be increased significantly more if necessary for your application. + +Additional Configurations +========================= + + Configuring the Driver on Different Distributions + ------------------------------------------------- + Configuring a network driver to load properly when the system is started is + distribution dependent. Typically, the configuration process involves adding + an alias line to /etc/modprobe.conf as well as editing other system startup + scripts and/or configuration files. Many popular Linux distributions ship + with tools to make these changes for you. To learn the proper way to + configure a network device for your system, refer to your distribution + documentation. If during this process you are asked for the driver or module + name, the name for the Linux Base Driver for the Intel 10GbE Family of + Adapters is ixgb. + + Viewing Link Messages + --------------------- + Link messages will not be displayed to the console if the distribution is + restricting system messages. In order to see network driver link messages on + your console, set dmesg to eight by entering the following: + + dmesg -n 8 + + NOTE: This setting is not saved across reboots. + + + Jumbo Frames + ------------ + The driver supports Jumbo Frames for all adapters. Jumbo Frames support is + enabled by changing the MTU to a value larger than the default of 1500. + The maximum value for the MTU is 16114. Use the ifconfig command to + increase the MTU size. For example: + + ifconfig ethx mtu 9000 up + + The maximum MTU setting for Jumbo Frames is 16114. This value coincides + with the maximum Jumbo Frames size of 16128. + + + Ethtool + ------- + The driver utilizes the ethtool interface for driver configuration and + diagnostics, as well as displaying statistical information. Ethtool + version 1.6 or later is required for this functionality. + + The latest release of ethtool can be found from + http://sourceforge.net/projects/gkernel + + NOTE: Ethtool 1.6 only supports a limited set of ethtool options. Support + for a more complete ethtool feature set can be enabled by upgrading + to the latest version. + + + NAPI + ---- + + NAPI (Rx polling mode) is supported in the ixgb driver. NAPI is enabled + or disabled based on the configuration of the kernel. see CONFIG_IXGB_NAPI + + See www.cyberus.ca/~hadi/usenix-paper.tgz for more information on NAPI. + + +Known Issues/Troubleshooting +============================ + + NOTE: After installing the driver, if your Intel Network Connection is not + working, verify in the "In This Release" section of the readme that you have + installed the correct driver. + + Intel(R) PRO/10GbE CX4 Server Adapter Cable Interoperability Issue with + Fujitsu XENPAK Module in SmartBits Chassis + --------------------------------------------------------------------- + Excessive CRC errors may be observed if the Intel(R) PRO/10GbE CX4 + Server adapter is connected to a Fujitsu XENPAK CX4 module in a SmartBits + chassis using 15 m/24AWG cable assemblies manufactured by Fujitsu or Leoni. + The CRC errors may be received either by the Intel(R) PRO/10GbE CX4 + Server adapter or the SmartBits. If this situation occurs using a different + cable assembly may resolve the issue. + + CX4 Server Adapter Cable Interoperability Issues with HP Procurve 3400cl + Switch Port + ------------------------------------------------------------------------ + Excessive CRC errors may be observed if the Intel(R) PRO/10GbE CX4 Server + adapter is connected to an HP Procurve 3400cl switch port using short cables + (1 m or shorter). If this situation occurs, using a longer cable may resolve + the issue. + + Excessive CRC errors may be observed using Fujitsu 24AWG cable assemblies that + Are 10 m or longer or where using a Leoni 15 m/24AWG cable assembly. The CRC + errors may be received either by the CX4 Server adapter or at the switch. If + this situation occurs, using a different cable assembly may resolve the issue. + + + Jumbo Frames System Requirement + ------------------------------- + Memory allocation failures have been observed on Linux systems with 64 MB + of RAM or less that are running Jumbo Frames. If you are using Jumbo + Frames, your system may require more than the advertised minimum + requirement of 64 MB of system memory. + + + Performance Degradation with Jumbo Frames + ----------------------------------------- + Degradation in throughput performance may be observed in some Jumbo frames + environments. If this is observed, increasing the application's socket buffer + size and/or increasing the /proc/sys/net/ipv4/tcp_*mem entry values may help. + See the specific application manual and /usr/src/linux*/Documentation/ + networking/ip-sysctl.txt for more details. + + + Allocating Rx Buffers when Using Jumbo Frames + --------------------------------------------- + Allocating Rx buffers when using Jumbo Frames on 2.6.x kernels may fail if + the available memory is heavily fragmented. This issue may be seen with PCI-X + adapters or with packet split disabled. This can be reduced or eliminated + by changing the amount of available memory for receive buffer allocation, by + increasing /proc/sys/vm/min_free_kbytes. + + + Multiple Interfaces on Same Ethernet Broadcast Network + ------------------------------------------------------ + Due to the default ARP behavior on Linux, it is not possible to have + one system on two IP networks in the same Ethernet broadcast domain + (non-partitioned switch) behave as expected. All Ethernet interfaces + will respond to IP traffic for any IP address assigned to the system. + This results in unbalanced receive traffic. + + If you have multiple interfaces in a server, do either of the following: + + - Turn on ARP filtering by entering: + echo 1 > /proc/sys/net/ipv4/conf/all/arp_filter + + - Install the interfaces in separate broadcast domains - either in + different switches or in a switch partitioned to VLANs. + + + UDP Stress Test Dropped Packet Issue + -------------------------------------- + Under small packets UDP stress test with 10GbE driver, the Linux system + may drop UDP packets due to the fullness of socket buffers. You may want + to change the driver's Flow Control variables to the minimum value for + controlling packet reception. + + + Tx Hangs Possible Under Stress + ------------------------------ + Under stress conditions, if TX hangs occur, turning off TSO + "ethtool -K eth0 tso off" may resolve the problem. + + Support ======= -For general information and support, go to the Intel support website at: +For general information, go to the Intel support website at: http://support.intel.com +or the Intel Wired Networking project hosted by Sourceforge at: + + http://sourceforge.net/projects/e1000 + If an issue is identified with the released source code on the supported -kernel with a supported adapter, email the specific information related to -the issue to linux.nics@intel.com. +kernel with a supported adapter, email the specific information related +to the issue to e1000-devel@lists.sf.net diff --git a/Documentation/networking/mac80211_hwsim/README b/Documentation/networking/mac80211_hwsim/README new file mode 100644 index 000000000000..2ff8ccb8dc37 --- /dev/null +++ b/Documentation/networking/mac80211_hwsim/README @@ -0,0 +1,67 @@ +mac80211_hwsim - software simulator of 802.11 radio(s) for mac80211 +Copyright (c) 2008, Jouni Malinen <j@w1.fi> + +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. + + +Introduction + +mac80211_hwsim is a Linux kernel module that can be used to simulate +arbitrary number of IEEE 802.11 radios for mac80211. It can be used to +test most of the mac80211 functionality and user space tools (e.g., +hostapd and wpa_supplicant) in a way that matches very closely with +the normal case of using real WLAN hardware. From the mac80211 view +point, mac80211_hwsim is yet another hardware driver, i.e., no changes +to mac80211 are needed to use this testing tool. + +The main goal for mac80211_hwsim is to make it easier for developers +to test their code and work with new features to mac80211, hostapd, +and wpa_supplicant. The simulated radios do not have the limitations +of real hardware, so it is easy to generate an arbitrary test setup +and always reproduce the same setup for future tests. In addition, +since all radio operation is simulated, any channel can be used in +tests regardless of regulatory rules. + +mac80211_hwsim kernel module has a parameter 'radios' that can be used +to select how many radios are simulated (default 2). This allows +configuration of both very simply setups (e.g., just a single access +point and a station) or large scale tests (multiple access points with +hundreds of stations). + +mac80211_hwsim works by tracking the current channel of each virtual +radio and copying all transmitted frames to all other radios that are +currently enabled and on the same channel as the transmitting +radio. Software encryption in mac80211 is used so that the frames are +actually encrypted over the virtual air interface to allow more +complete testing of encryption. + +A global monitoring netdev, hwsim#, is created independent of +mac80211. This interface can be used to monitor all transmitted frames +regardless of channel. + + +Simple example + +This example shows how to use mac80211_hwsim to simulate two radios: +one to act as an access point and the other as a station that +associates with the AP. hostapd and wpa_supplicant are used to take +care of WPA2-PSK authentication. In addition, hostapd is also +processing access point side of association. + +Please note that the current Linux kernel does not enable AP mode, so a +simple patch is needed to enable AP mode selection: +http://johannes.sipsolutions.net/patches/kernel/all/LATEST/006-allow-ap-vlan-modes.patch + + +# Build mac80211_hwsim as part of kernel configuration + +# Load the module +modprobe mac80211_hwsim + +# Run hostapd (AP) for wlan0 +hostapd hostapd.conf + +# Run wpa_supplicant (station) for wlan1 +wpa_supplicant -Dwext -iwlan1 -c wpa_supplicant.conf diff --git a/Documentation/networking/mac80211_hwsim/hostapd.conf b/Documentation/networking/mac80211_hwsim/hostapd.conf new file mode 100644 index 000000000000..08cde7e35f2e --- /dev/null +++ b/Documentation/networking/mac80211_hwsim/hostapd.conf @@ -0,0 +1,11 @@ +interface=wlan0 +driver=nl80211 + +hw_mode=g +channel=1 +ssid=mac80211 test + +wpa=2 +wpa_key_mgmt=WPA-PSK +wpa_pairwise=CCMP +wpa_passphrase=12345678 diff --git a/Documentation/networking/mac80211_hwsim/wpa_supplicant.conf b/Documentation/networking/mac80211_hwsim/wpa_supplicant.conf new file mode 100644 index 000000000000..299128cff035 --- /dev/null +++ b/Documentation/networking/mac80211_hwsim/wpa_supplicant.conf @@ -0,0 +1,10 @@ +ctrl_interface=/var/run/wpa_supplicant + +network={ + ssid="mac80211 test" + psk="12345678" + key_mgmt=WPA-PSK + proto=WPA2 + pairwise=CCMP + group=CCMP +} diff --git a/Documentation/networking/multiqueue.txt b/Documentation/networking/multiqueue.txt index ea5a42e8f79f..d391ea631141 100644 --- a/Documentation/networking/multiqueue.txt +++ b/Documentation/networking/multiqueue.txt @@ -3,19 +3,11 @@ =========================================== Section 1: Base driver requirements for implementing multiqueue support -Section 2: Qdisc support for multiqueue devices -Section 3: Brief howto using PRIO or RR for multiqueue devices - Intro: Kernel support for multiqueue devices --------------------------------------------------------- -Kernel support for multiqueue devices is only an API that is presented to the -netdevice layer for base drivers to implement. This feature is part of the -core networking stack, and all network devices will be running on the -multiqueue-aware stack. If a base driver only has one queue, then these -changes are transparent to that driver. - +Kernel support for multiqueue devices is always present. Section 1: Base driver requirements for implementing multiqueue support ----------------------------------------------------------------------- @@ -32,84 +24,4 @@ netif_{start|stop|wake}_subqueue() functions to manage each queue while the device is still operational. netdev->queue_lock is still used when the device comes online or when it's completely shut down (unregister_netdev(), etc.). -Finally, the base driver should indicate that it is a multiqueue device. The -feature flag NETIF_F_MULTI_QUEUE should be added to the netdev->features -bitmap on device initialization. Below is an example from e1000: - -#ifdef CONFIG_E1000_MQ - if ( (adapter->hw.mac.type == e1000_82571) || - (adapter->hw.mac.type == e1000_82572) || - (adapter->hw.mac.type == e1000_80003es2lan)) - netdev->features |= NETIF_F_MULTI_QUEUE; -#endif - - -Section 2: Qdisc support for multiqueue devices ------------------------------------------------ - -Currently two qdiscs support multiqueue devices. A new round-robin qdisc, -sch_rr, and sch_prio. The qdisc is responsible for classifying the skb's to -bands and queues, and will store the queue mapping into skb->queue_mapping. -Use this field in the base driver to determine which queue to send the skb -to. - -sch_rr has been added for hardware that doesn't want scheduling policies from -software, so it's a straight round-robin qdisc. It uses the same syntax and -classification priomap that sch_prio uses, so it should be intuitive to -configure for people who've used sch_prio. - -In order to utilitize the multiqueue features of the qdiscs, the network -device layer needs to enable multiple queue support. This can be done by -selecting NETDEVICES_MULTIQUEUE under Drivers. - -The PRIO qdisc naturally plugs into a multiqueue device. If -NETDEVICES_MULTIQUEUE is selected, then on qdisc load, the number of -bands requested is compared to the number of queues on the hardware. If they -are equal, it sets a one-to-one mapping up between the queues and bands. If -they're not equal, it will not load the qdisc. This is the same behavior -for RR. Once the association is made, any skb that is classified will have -skb->queue_mapping set, which will allow the driver to properly queue skb's -to multiple queues. - - -Section 3: Brief howto using PRIO and RR for multiqueue devices ---------------------------------------------------------------- - -The userspace command 'tc,' part of the iproute2 package, is used to configure -qdiscs. To add the PRIO qdisc to your network device, assuming the device is -called eth0, run the following command: - -# tc qdisc add dev eth0 root handle 1: prio bands 4 multiqueue - -This will create 4 bands, 0 being highest priority, and associate those bands -to the queues on your NIC. Assuming eth0 has 4 Tx queues, the band mapping -would look like: - -band 0 => queue 0 -band 1 => queue 1 -band 2 => queue 2 -band 3 => queue 3 - -Traffic will begin flowing through each queue if your TOS values are assigning -traffic across the various bands. For example, ssh traffic will always try to -go out band 0 based on TOS -> Linux priority conversion (realtime traffic), -so it will be sent out queue 0. ICMP traffic (pings) fall into the "normal" -traffic classification, which is band 1. Therefore pings will be send out -queue 1 on the NIC. - -Note the use of the multiqueue keyword. This is only in versions of iproute2 -that support multiqueue networking devices; if this is omitted when loading -a qdisc onto a multiqueue device, the qdisc will load and operate the same -if it were loaded onto a single-queue device (i.e. - sends all traffic to -queue 0). - -Another alternative to multiqueue band allocation can be done by using the -multiqueue option and specify 0 bands. If this is the case, the qdisc will -allocate the number of bands to equal the number of queues that the device -reports, and bring the qdisc online. - -The behavior of tc filters remains the same, where it will override TOS priority -classification. - - Author: Peter P. Waskiewicz Jr. <peter.p.waskiewicz.jr@intel.com> diff --git a/Documentation/networking/s2io.txt b/Documentation/networking/s2io.txt index 1e28e2ddb90a..c3d6b4d5d014 100644 --- a/Documentation/networking/s2io.txt +++ b/Documentation/networking/s2io.txt @@ -52,13 +52,10 @@ d. MSI/MSI-X. Can be enabled on platforms which support this feature (IA64, Xeon) resulting in noticeable performance improvement(upto 7% on certain platforms). -e. NAPI. Compile-time option(CONFIG_S2IO_NAPI) for better Rx interrupt -moderation. - -f. Statistics. Comprehensive MAC-level and software statistics displayed +e. Statistics. Comprehensive MAC-level and software statistics displayed using "ethtool -S" option. -g. Multi-FIFO/Ring. Supports up to 8 transmit queues and receive rings, +f. Multi-FIFO/Ring. Supports up to 8 transmit queues and receive rings, with multiple steering options. 4. Command line parameters diff --git a/Documentation/powerpc/booting-without-of.txt b/Documentation/powerpc/booting-without-of.txt index de2e5c05d6e7..aee243a846a2 100644 --- a/Documentation/powerpc/booting-without-of.txt +++ b/Documentation/powerpc/booting-without-of.txt @@ -41,12 +41,24 @@ Table of Contents VI - System-on-a-chip devices and nodes 1) Defining child nodes of an SOC 2) Representing devices without a current OF specification - a) PHY nodes - b) Interrupt controllers - c) CFI or JEDEC memory-mapped NOR flash - d) 4xx/Axon EMAC ethernet nodes - e) Xilinx IP cores - f) USB EHCI controllers + a) MDIO IO device + b) Gianfar-compatible ethernet nodes + c) PHY nodes + d) Interrupt controllers + e) I2C + f) Freescale SOC USB controllers + g) Freescale SOC SEC Security Engines + h) Board Control and Status (BCSR) + i) Freescale QUICC Engine module (QE) + j) CFI or JEDEC memory-mapped NOR flash + k) Global Utilities Block + l) Freescale Communications Processor Module + m) Chipselect/Local Bus + n) 4xx/Axon EMAC ethernet nodes + o) Xilinx IP cores + p) Freescale Synchronous Serial Interface + q) USB EHCI controllers + r) MDIO on GPIOs VII - Marvell Discovery mv64[345]6x System Controller chips 1) The /system-controller node @@ -1815,6 +1827,60 @@ platforms are moved over to use the flattened-device-tree model. big-endian; }; + r) Freescale Display Interface Unit + + The Freescale DIU is a LCD controller, with proper hardware, it can also + drive DVI monitors. + + Required properties: + - compatible : should be "fsl-diu". + - reg : should contain at least address and length of the DIU register + set. + - Interrupts : one DIU interrupt should be describe here. + + Example (MPC8610HPCD) + display@2c000 { + compatible = "fsl,diu"; + reg = <0x2c000 100>; + interrupts = <72 2>; + interrupt-parent = <&mpic>; + }; + + s) Freescale on board FPGA + + This is the memory-mapped registers for on board FPGA. + + Required properities: + - compatible : should be "fsl,fpga-pixis". + - reg : should contain the address and the lenght of the FPPGA register + set. + + Example (MPC8610HPCD) + board-control@e8000000 { + compatible = "fsl,fpga-pixis"; + reg = <0xe8000000 32>; + }; + + r) MDIO on GPIOs + + Currently defined compatibles: + - virtual,gpio-mdio + + MDC and MDIO lines connected to GPIO controllers are listed in the + gpios property as described in section VIII.1 in the following order: + + MDC, MDIO. + + Example: + + mdio { + compatible = "virtual,mdio-gpio"; + #address-cells = <1>; + #size-cells = <0>; + gpios = <&qe_pio_a 11 + &qe_pio_c 6>; + }; + VII - Marvell Discovery mv64[345]6x System Controller chips =========================================================== diff --git a/Documentation/rfkill.txt b/Documentation/rfkill.txt index a83ff23cd68c..0843ed0163a5 100644 --- a/Documentation/rfkill.txt +++ b/Documentation/rfkill.txt @@ -1,89 +1,528 @@ rfkill - RF switch subsystem support ==================================== -1 Implementation details -2 Driver support -3 Userspace 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: Implementation details -The rfkill switch subsystem offers support for keys often found on laptops -to enable wireless devices like WiFi and Bluetooth. +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. -This is done by providing the user 3 possibilities: - 1 - The rfkill system handles all events; userspace is not aware of events. - 2 - The rfkill system handles all events; userspace is informed about the events. - 3 - The rfkill system does not handle events; userspace handles all events. +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 buttons to enable and disable the wireless radios are important in +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 -wireless radios _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 still provides userspace the possibility -to take over the task to handle the key events. +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 + +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). Note that the opposite event (power on all + transmitters) is handled normally. + +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. -The system inside the kernel has been split into 2 separate sections: - 1 - RFKILL - 2 - RFKILL_INPUT + Please refer to the corner cases and examples section for more details. -The first option enables rfkill support and will make sure userspace will -be notified of any events through the input device. It also creates several -sysfs entries which can be used by userspace. See section "Userspace support". +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. -The second option provides an rfkill input handler. This handler will -listen to all rfkill key events and will toggle the radio accordingly. -With this option enabled userspace could either do nothing or simply -perform monitoring tasks. +Corner cases and examples: ==================================== -2: Driver support -To build a driver with rfkill subsystem support, the driver should -depend on the Kconfig symbol RFKILL; it should _not_ depend on -RKFILL_INPUT. +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. -Unless key events trigger an interrupt to which the driver listens, polling -will be required to determine the key state changes. For this the input -layer providers the input-polldev handler. +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). -A driver should implement a few steps to correctly make use of the -rfkill subsystem. First for non-polling drivers: +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. - - rfkill_allocate() - - input_allocate_device() - - rfkill_register() - - input_register_device() +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 switch that kills radios +in hardware, even if the O.S. has gone to lunch. An example of an input device +which SHOULD NOT generate *_RFKILL_ALL events by default, is any sort of hot +key that does nothing by itself, as well as any hot key that is type-specific +(e.g. the one for WLAN). + + +3.1 Guidelines for wireless device drivers +------------------------------------------ + +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. + +Example of a WLAN wireless driver connected to the rfkill subsystem: +-------------------------------------------------------------------- + +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 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. + +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. -For polling drivers: +If it doesn't implement the get_state() hook, it must make sure that its calls +to rfkill_force_state() are enough to keep the status always up-to-date, and it +must do a rfkill_force_state() on resume from sleep. +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. + +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 + +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. + +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. + +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. + +There is no provision for a statically-allocated rfkill struct. You must +use rfkill_allocate() to allocate one. + +You should: - rfkill_allocate() - - input_allocate_polled_device() + - modify rfkill fields (flags, name) + - modify state to the current hardware state (THIS IS THE ONLY TIME + YOU CAN ACCESS state DIRECTLY) - rfkill_register() - - input_register_polled_device() -When a key event has been detected, the correct event should be -sent over the input device which has been registered by the driver. +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(). -==================================== -3: Userspace support +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. -For each key an input device will be created which will send out the correct -key event when the rfkill key has been pressed. +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 + +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. + +******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. + +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: 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 key. 1: On, 0: Off. + 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; + 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); + 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 all radios, not yet in the requested -state, will be will be toggled accordingly. +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. +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. diff --git a/Documentation/serial/driver b/Documentation/serial/driver index 88ad615dd338..77ba0afbe4db 100644 --- a/Documentation/serial/driver +++ b/Documentation/serial/driver @@ -186,6 +186,17 @@ hardware. Locking: port_sem taken. Interrupts: caller dependent. + flush_buffer(port) + Flush any write buffers, reset any DMA state and stop any + ongoing DMA transfers. + + This will be called whenever the port->info->xmit circular + buffer is cleared. + + Locking: port->lock taken. + Interrupts: locally disabled. + This call must not sleep + set_termios(port,termios,oldtermios) Change the port parameters, including word length, parity, stop bits. Update read_status_mask and ignore_status_mask to indicate diff --git a/Documentation/video4linux/CARDLIST.cx23885 b/Documentation/video4linux/CARDLIST.cx23885 index 191194ea1e25..f0e613ba55b8 100644 --- a/Documentation/video4linux/CARDLIST.cx23885 +++ b/Documentation/video4linux/CARDLIST.cx23885 @@ -8,3 +8,4 @@ 7 -> Hauppauge WinTV-HVR1200 [0070:71d1,0070:71d3] 8 -> Hauppauge WinTV-HVR1700 [0070:8101] 9 -> Hauppauge WinTV-HVR1400 [0070:8010] + 10 -> DViCO FusionHDTV7 Dual Express [18ac:d618] diff --git a/Documentation/video4linux/CARDLIST.em28xx b/Documentation/video4linux/CARDLIST.em28xx index 1d6a245c828f..10591467ef16 100644 --- a/Documentation/video4linux/CARDLIST.em28xx +++ b/Documentation/video4linux/CARDLIST.em28xx @@ -8,10 +8,13 @@ 7 -> Leadtek Winfast USB II (em2800) 8 -> Kworld USB2800 (em2800) 9 -> Pinnacle Dazzle DVC 90/DVC 100 (em2820/em2840) [2304:0207,2304:021a] - 10 -> Hauppauge WinTV HVR 900 (em2880) [2040:6500,2040:6502] + 10 -> Hauppauge WinTV HVR 900 (em2880) [2040:6500] 11 -> Terratec Hybrid XS (em2880) [0ccd:0042] 12 -> Kworld PVR TV 2800 RF (em2820/em2840) 13 -> Terratec Prodigy XS (em2880) [0ccd:0047] 14 -> Pixelview Prolink PlayTV USB 2.0 (em2820/em2840) 15 -> V-Gear PocketTV (em2800) 16 -> Hauppauge WinTV HVR 950 (em2880) [2040:6513,2040:6517,2040:651b,2040:651f] + 17 -> Pinnacle PCTV HD Pro Stick (em2880) [2304:0227] + 18 -> Hauppauge WinTV HVR 900 (R2) (em2880) [2040:6502] + 19 -> PointNix Intra-Oral Camera (em2860) diff --git a/Documentation/video4linux/CARDLIST.saa7134 b/Documentation/video4linux/CARDLIST.saa7134 index 67937df1e974..39868af9cf9f 100644 --- a/Documentation/video4linux/CARDLIST.saa7134 +++ b/Documentation/video4linux/CARDLIST.saa7134 @@ -37,7 +37,7 @@ 36 -> UPMOST PURPLE TV [12ab:0800] 37 -> Items MuchTV Plus / IT-005 38 -> Terratec Cinergy 200 TV [153b:1152] - 39 -> LifeView FlyTV Platinum Mini [5168:0212,4e42:0212] + 39 -> LifeView FlyTV Platinum Mini [5168:0212,4e42:0212,5169:1502] 40 -> Compro VideoMate TV PVR/FM [185b:c100] 41 -> Compro VideoMate TV Gold+ [185b:c100] 42 -> Sabrent SBT-TVFM (saa7130) @@ -128,7 +128,7 @@ 127 -> Beholder BeholdTV 507 FM/RDS / BeholdTV 509 FM [0000:5071,0000:507B,5ace:5070,5ace:5090] 128 -> Beholder BeholdTV Columbus TVFM [0000:5201] 129 -> Beholder BeholdTV 607 / BeholdTV 609 [5ace:6070,5ace:6071,5ace:6072,5ace:6073,5ace:6090,5ace:6091,5ace:6092,5ace:6093] -130 -> Beholder BeholdTV M6 / BeholdTV M6 Extra [5ace:6190,5ace:6193,5ace:6191] +130 -> Beholder BeholdTV M6 [5ace:6190] 131 -> Twinhan Hybrid DTV-DVB 3056 PCI [1822:0022] 132 -> Genius TVGO AM11MCE 133 -> NXP Snake DVB-S reference design @@ -141,3 +141,7 @@ 140 -> Avermedia DVB-S Pro A700 [1461:a7a1] 141 -> Avermedia DVB-S Hybrid+FM A700 [1461:a7a2] 142 -> Beholder BeholdTV H6 [5ace:6290] +143 -> Beholder BeholdTV M63 [5ace:6191] +144 -> Beholder BeholdTV M6 Extra [5ace:6193] +145 -> AVerMedia MiniPCI DVB-T Hybrid M103 [1461:f636] +146 -> ASUSTeK P7131 Analog diff --git a/Documentation/video4linux/cx18.txt b/Documentation/video4linux/cx18.txt index 6842c262890f..914cb7e734a2 100644 --- a/Documentation/video4linux/cx18.txt +++ b/Documentation/video4linux/cx18.txt @@ -1,36 +1,30 @@ Some notes regarding the cx18 driver for the Conexant CX23418 MPEG encoder chip: -1) The only hardware currently supported is the Hauppauge HVR-1600 - card and the Compro VideoMate H900 (note that this card only - supports analog input, it has no digital tuner!). +1) Currently supported are: -2) Some people have problems getting the i2c bus to work. Cause unknown. - The symptom is that the eeprom cannot be read and the card is - unusable. + - Hauppauge HVR-1600 + - Compro VideoMate H900 + - Yuan MPC718 + - Conexant Raptor PAL/SECAM devkit -3) The audio from the analog tuner is mono only. Probably caused by - incorrect audio register information in the datasheet. We are - waiting for updated information from Conexant. +2) Some people have problems getting the i2c bus to work. + The symptom is that the eeprom cannot be read and the card is + unusable. This is probably fixed, but if you have problems + then post to the video4linux or ivtv-users mailinglist. -4) VBI (raw or sliced) has not yet been implemented. +3) VBI (raw or sliced) has not yet been implemented. -5) MPEG indexing is not yet implemented. +4) MPEG indexing is not yet implemented. -6) The driver is still a bit rough around the edges, this should +5) The driver is still a bit rough around the edges, this should improve over time. Firmware: -The firmware needs to be extracted from the Windows Hauppauge HVR-1600 -driver, available here: - -http://hauppauge.lightpath.net/software/install_cd/hauppauge_cd_3.4d1.zip +You can obtain the firmware files here: -Unzip, then copy the following files to the firmware directory -and rename them as follows: +http://dl.ivtvdriver.org/ivtv/firmware/cx18-firmware.tar.gz -Drivers/Driver18/hcw18apu.rom -> v4l-cx23418-apu.fw -Drivers/Driver18/hcw18enc.rom -> v4l-cx23418-cpu.fw -Drivers/Driver18/hcw18mlC.rom -> v4l-cx23418-dig.fw +Untar and copy the .fw files to your firmware directory. diff --git a/Documentation/video4linux/gspca.txt b/Documentation/video4linux/gspca.txt new file mode 100644 index 000000000000..0c4880af57a3 --- /dev/null +++ b/Documentation/video4linux/gspca.txt @@ -0,0 +1,243 @@ +List of the webcams know by gspca. + +The modules are: + gspca_main main driver + gspca_xxxx subdriver module with xxxx as follows + +xxxx vend:prod +---- +spca501 0000:0000 MystFromOri Unknow Camera +spca501 040a:0002 Kodak DVC-325 +spca500 040a:0300 Kodak EZ200 +zc3xx 041e:041e Creative WebCam Live! +spca500 041e:400a Creative PC-CAM 300 +sunplus 041e:400b Creative PC-CAM 600 +sunplus 041e:4012 PC-Cam350 +sunplus 041e:4013 Creative Pccam750 +zc3xx 041e:4017 Creative Webcam Mobile PD1090 +spca508 041e:4018 Creative Webcam Vista (PD1100) +spca561 041e:401a Creative Webcam Vista (PD1100) +zc3xx 041e:401c Creative NX +spca505 041e:401d Creative Webcam NX ULTRA +zc3xx 041e:401e Creative Nx Pro +zc3xx 041e:401f Creative Webcam Notebook PD1171 +pac207 041e:4028 Creative Webcam Vista Plus +zc3xx 041e:4029 Creative WebCam Vista Pro +zc3xx 041e:4034 Creative Instant P0620 +zc3xx 041e:4035 Creative Instant P0620D +zc3xx 041e:4036 Creative Live ! +zc3xx 041e:403a Creative Nx Pro 2 +spca561 041e:403b Creative Webcam Vista (VF0010) +zc3xx 041e:4051 Creative Live!Cam Notebook Pro (VF0250) +ov519 041e:4052 Creative Live! VISTA IM +zc3xx 041e:4053 Creative Live!Cam Video IM +ov519 041e:405f Creative Live! VISTA VF0330 +ov519 041e:4060 Creative Live! VISTA VF0350 +ov519 041e:4061 Creative Live! VISTA VF0400 +ov519 041e:4064 Creative Live! VISTA VF0420 +ov519 041e:4068 Creative Live! VISTA VF0470 +spca561 0458:7004 Genius VideoCAM Express V2 +sunplus 0458:7006 Genius Dsc 1.3 Smart +zc3xx 0458:7007 Genius VideoCam V2 +zc3xx 0458:700c Genius VideoCam V3 +zc3xx 0458:700f Genius VideoCam Web V2 +sonixj 0458:7025 Genius Eye 311Q +sonixj 045e:00f5 MicroSoft VX3000 +sonixj 045e:00f7 MicroSoft VX1000 +ov519 045e:028c Micro$oft xbox cam +spca508 0461:0815 Micro Innovation IC200 +sunplus 0461:0821 Fujifilm MV-1 +zc3xx 0461:0a00 MicroInnovation WebCam320 +spca500 046d:0890 Logitech QuickCam traveler +vc032x 046d:0892 Logitech Orbicam +vc032x 046d:0896 Logitech Orbicam +zc3xx 046d:08a0 Logitech QC IM +zc3xx 046d:08a1 Logitech QC IM 0x08A1 +sound +zc3xx 046d:08a2 Labtec Webcam Pro +zc3xx 046d:08a3 Logitech QC Chat +zc3xx 046d:08a6 Logitech QCim +zc3xx 046d:08a7 Logitech QuickCam Image +zc3xx 046d:08a9 Logitech Notebook Deluxe +zc3xx 046d:08aa Labtec Webcam Notebook +zc3xx 046d:08ac Logitech QuickCam Cool +zc3xx 046d:08ad Logitech QCCommunicate STX +zc3xx 046d:08ae Logitech QuickCam for Notebooks +zc3xx 046d:08af Logitech QuickCam Cool +zc3xx 046d:08b9 Logitech QC IM ??? +zc3xx 046d:08d7 Logitech QCam STX +zc3xx 046d:08d9 Logitech QuickCam IM/Connect +zc3xx 046d:08d8 Logitech Notebook Deluxe +zc3xx 046d:08da Logitech QuickCam Messenger +zc3xx 046d:08dd Logitech QuickCam for Notebooks +spca500 046d:0900 Logitech Inc. ClickSmart 310 +spca500 046d:0901 Logitech Inc. ClickSmart 510 +sunplus 046d:0905 Logitech ClickSmart 820 +tv8532 046d:0920 QC Express +tv8532 046d:0921 Labtec Webcam +spca561 046d:0928 Logitech QC Express Etch2 +spca561 046d:0929 Labtec Webcam Elch2 +spca561 046d:092a Logitech QC for Notebook +spca561 046d:092b Labtec Webcam Plus +spca561 046d:092c Logitech QC chat Elch2 +spca561 046d:092d Logitech QC Elch2 +spca561 046d:092e Logitech QC Elch2 +spca561 046d:092f Logitech QC Elch2 +sunplus 046d:0960 Logitech ClickSmart 420 +sunplus 0471:0322 Philips DMVC1300K +zc3xx 0471:0325 Philips SPC 200 NC +zc3xx 0471:0326 Philips SPC 300 NC +sonixj 0471:0327 Philips SPC 600 NC +sonixj 0471:0328 Philips SPC 700 NC +zc3xx 0471:032d Philips spc210nc +zc3xx 0471:032e Philips spc315nc +sonixj 0471:0330 Philips SPC 710NC +spca501 0497:c001 Smile International +sunplus 04a5:3003 Benq DC 1300 +sunplus 04a5:3008 Benq DC 1500 +sunplus 04a5:300a Benq DC3410 +spca500 04a5:300c Benq DC1016 +sunplus 04f1:1001 JVC GC A50 +spca561 04fc:0561 Flexcam 100 +sunplus 04fc:500c Sunplus CA500C +sunplus 04fc:504a Aiptek Mini PenCam 1.3 +sunplus 04fc:504b Maxell MaxPocket LE 1.3 +sunplus 04fc:5330 Digitrex 2110 +sunplus 04fc:5360 Sunplus Generic +spca500 04fc:7333 PalmPixDC85 +sunplus 04fc:ffff Pure DigitalDakota +spca501 0506:00df 3Com HomeConnect Lite +sunplus 052b:1513 Megapix V4 +tv8532 0545:808b Veo Stingray +tv8532 0545:8333 Veo Stingray +sunplus 0546:3155 Polaroid PDC3070 +sunplus 0546:3191 Polaroid Ion 80 +sunplus 0546:3273 Polaroid PDC2030 +ov519 054c:0154 Sonny toy4 +ov519 054c:0155 Sonny toy5 +zc3xx 055f:c005 Mustek Wcam300A +spca500 055f:c200 Mustek Gsmart 300 +sunplus 055f:c211 Kowa Bs888e Microcamera +spca500 055f:c220 Gsmart Mini +sunplus 055f:c230 Mustek Digicam 330K +sunplus 055f:c232 Mustek MDC3500 +sunplus 055f:c360 Mustek DV4000 Mpeg4 +sunplus 055f:c420 Mustek gSmart Mini 2 +sunplus 055f:c430 Mustek Gsmart LCD 2 +sunplus 055f:c440 Mustek DV 3000 +sunplus 055f:c520 Mustek gSmart Mini 3 +sunplus 055f:c530 Mustek Gsmart LCD 3 +sunplus 055f:c540 Gsmart D30 +sunplus 055f:c630 Mustek MDC4000 +sunplus 055f:c650 Mustek MDC5500Z +zc3xx 055f:d003 Mustek WCam300A +zc3xx 055f:d004 Mustek WCam300 AN +conex 0572:0041 Creative Notebook cx11646 +ov519 05a9:0519 OmniVision +ov519 05a9:0530 OmniVision +ov519 05a9:4519 OmniVision +ov519 05a9:8519 OmniVision +sunplus 05da:1018 Digital Dream Enigma 1.3 +stk014 05e1:0893 Syntek DV4000 +spca561 060b:a001 Maxell Compact Pc PM3 +zc3xx 0698:2003 CTX M730V built in +spca500 06bd:0404 Agfa CL20 +spca500 06be:0800 Optimedia +sunplus 06d6:0031 Trust 610 LCD PowerC@m Zoom +spca506 06e1:a190 ADS Instant VCD +spca508 0733:0110 ViewQuest VQ110 +spca508 0130:0130 Clone Digital Webcam 11043 +spca501 0733:0401 Intel Create and Share +spca501 0733:0402 ViewQuest M318B +spca505 0733:0430 Intel PC Camera Pro +sunplus 0733:1311 Digital Dream Epsilon 1.3 +sunplus 0733:1314 Mercury 2.1MEG Deluxe Classic Cam +sunplus 0733:2211 Jenoptik jdc 21 LCD +sunplus 0733:2221 Mercury Digital Pro 3.1p +sunplus 0733:3261 Concord 3045 spca536a +sunplus 0733:3281 Cyberpix S550V +spca506 0734:043b 3DeMon USB Capture aka +spca500 084d:0003 D-Link DSC-350 +spca500 08ca:0103 Aiptek PocketDV +sunplus 08ca:0104 Aiptek PocketDVII 1.3 +sunplus 08ca:0106 Aiptek Pocket DV3100+ +sunplus 08ca:2008 Aiptek Mini PenCam 2 M +sunplus 08ca:2010 Aiptek PocketCam 3M +sunplus 08ca:2016 Aiptek PocketCam 2 Mega +sunplus 08ca:2018 Aiptek Pencam SD 2M +sunplus 08ca:2020 Aiptek Slim 3000F +sunplus 08ca:2022 Aiptek Slim 3200 +sunplus 08ca:2024 Aiptek DV3500 Mpeg4 +sunplus 08ca:2028 Aiptek PocketCam4M +sunplus 08ca:2040 Aiptek PocketDV4100M +sunplus 08ca:2042 Aiptek PocketDV5100 +sunplus 08ca:2050 Medion MD 41437 +sunplus 08ca:2060 Aiptek PocketDV5300 +tv8532 0923:010f ICM532 cams +mars 093a:050f Mars-Semi Pc-Camera +pac207 093a:2460 PAC207 Qtec Webcam 100 +pac207 093a:2463 Philips spc200nc pac207 +pac207 093a:2464 Labtec Webcam 1200 +pac207 093a:2468 PAC207 +pac207 093a:2470 Genius GF112 +pac207 093a:2471 PAC207 Genius VideoCam ge111 +pac207 093a:2472 PAC207 Genius VideoCam ge110 +pac7311 093a:2600 PAC7311 Typhoon +pac7311 093a:2601 PAC7311 Phillips SPC610NC +pac7311 093a:2603 PAC7312 +pac7311 093a:2608 PAC7311 Trust WB-3300p +pac7311 093a:260e PAC7311 Gigaware VGA PC Camera, Trust WB-3350p, SIGMA cam 2350 +pac7311 093a:260f PAC7311 SnakeCam +pac7311 093a:2621 PAC731x +zc3xx 0ac8:0302 Z-star Vimicro zc0302 +vc032x 0ac8:0321 Vimicro generic vc0321 +vc032x 0ac8:0323 Vimicro Vc0323 +vc032x 0ac8:0328 A4Tech PK-130MG +zc3xx 0ac8:301b Z-Star zc301b +zc3xx 0ac8:303b Vimicro 0x303b +zc3xx 0ac8:305b Z-star Vimicro zc0305b +zc3xx 0ac8:307b Ldlc VC302+Ov7620 +vc032x 0ac8:c001 Sony embedded vimicro +vc032x 0ac8:c002 Sony embedded vimicro +spca508 0af9:0010 Hama USB Sightcam 100 +spca508 0af9:0011 Hama USB Sightcam 100 +sonixb 0c45:6001 Genius VideoCAM NB +sonixb 0c45:6005 Microdia Sweex Mini Webcam +sonixb 0c45:6007 Sonix sn9c101 + Tas5110D +sonixb 0c45:6009 spcaCam@120 +sonixb 0c45:600d spcaCam@120 +sonixb 0c45:6011 Microdia PC Camera (SN9C102) +sonixb 0c45:6019 Generic Sonix OV7630 +sonixb 0c45:6024 Generic Sonix Tas5130c +sonixb 0c45:6025 Xcam Shanga +sonixb 0c45:6028 Sonix Btc Pc380 +sonixb 0c45:6029 spcaCam@150 +sonixb 0c45:602c Generic Sonix OV7630 +sonixb 0c45:602d LIC-200 LG +sonixb 0c45:602e Genius VideoCam Messenger +sonixj 0c45:6040 Speed NVC 350K +sonixj 0c45:607c Sonix sn9c102p Hv7131R +sonixj 0c45:60c0 Sangha Sn535 +sonixj 0c45:60ec SN9C105+MO4000 +sonixj 0c45:60fb Surfer NoName +sonixj 0c45:60fc LG-LIC300 +sonixj 0c45:612a Avant Camera +sonixj 0c45:612c Typhoon Rasy Cam 1.3MPix +sonixj 0c45:6130 Sonix Pccam +sonixj 0c45:6138 Sn9c120 Mo4000 +sonixj 0c45:613b Surfer SN-206 +sonixj 0c45:613c Sonix Pccam168 +sunplus 0d64:0303 Sunplus FashionCam DXG +etoms 102c:6151 Qcam Sangha CIF +etoms 102c:6251 Qcam xxxxxx VGA +zc3xx 10fd:0128 Typhoon Webshot II USB 300k 0x0128 +spca561 10fd:7e50 FlyCam Usb 100 +zc3xx 10fd:8050 Typhoon Webshot II USB 300k +spca501 1776:501c Arowana 300K CMOS Camera +t613 17a1:0128 T613/TAS5130A +vc032x 17ef:4802 Lenovo Vc0323+MI1310_SOC +pac207 2001:f115 D-Link DSB-C120 +spca500 2899:012c Toptro Industrial +spca508 8086:0110 Intel Easy PC Camera +spca500 8086:0630 Intel Pocket PC Camera +spca506 99fa:8988 Grandtec V.cap +spca561 abcd:cdee Petcam diff --git a/MAINTAINERS b/MAINTAINERS index 93fd6b2efeee..ec0c9c914f17 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2189,6 +2189,8 @@ P: Jesse Brandeburg M: jesse.brandeburg@intel.com P: Bruce Allan M: bruce.w.allan@intel.com +P: PJ Waskiewicz +M: peter.p.waskiewicz.jr@intel.com P: John Ronciak M: john.ronciak@intel.com L: e1000-devel@lists.sourceforge.net @@ -2725,12 +2727,10 @@ L: libertas-dev@lists.infradead.org S: Maintained MARVELL MV643XX ETHERNET DRIVER -P: Dale Farnsworth -M: dale@farnsworth.org -P: Manish Lachwani -M: mlachwani@mvista.com +P: Lennert Buytenhek +M: buytenh@marvell.com L: netdev@vger.kernel.org -S: Odd Fixes for 2.4; Maintained for 2.6. +S: Supported MATROX FRAMEBUFFER DRIVER P: Petr Vandrovec @@ -3274,14 +3274,6 @@ L: linux-kernel@vger.kernel.org T: git git.infradead.org/battery-2.6.git S: Maintained -POWERPC 4xx EMAC DRIVER -P: Eugene Surovegin -M: ebs@ebshome.net -W: http://kernel.ebshome.net/emac/ -L: linuxppc-dev@ozlabs.org -L: netdev@vger.kernel.org -S: Maintained - PNP SUPPORT P: Adam Belay M: ambx1@neo.rr.com diff --git a/arch/blackfin/mach-bf527/boards/ezkit.c b/arch/blackfin/mach-bf527/boards/ezkit.c index 5958eecefcf1..689b69c98ee4 100644 --- a/arch/blackfin/mach-bf527/boards/ezkit.c +++ b/arch/blackfin/mach-bf527/boards/ezkit.c @@ -323,10 +323,15 @@ static struct platform_device smc91x_device = { static struct resource dm9000_resources[] = { [0] = { .start = 0x203FB800, - .end = 0x203FB800 + 8, + .end = 0x203FB800 + 1, .flags = IORESOURCE_MEM, }, [1] = { + .start = 0x203FB800 + 4, + .end = 0x203FB800 + 5, + .flags = IORESOURCE_MEM, + }, + [2] = { .start = IRQ_PF9, .end = IRQ_PF9, .flags = (IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHEDGE), diff --git a/arch/blackfin/mach-bf533/boards/H8606.c b/arch/blackfin/mach-bf533/boards/H8606.c index 7cc4864f6aaf..4103a97c1a70 100644 --- a/arch/blackfin/mach-bf533/boards/H8606.c +++ b/arch/blackfin/mach-bf533/boards/H8606.c @@ -65,10 +65,15 @@ static struct platform_device rtc_device = { static struct resource dm9000_resources[] = { [0] = { .start = 0x20300000, - .end = 0x20300000 + 8, + .end = 0x20300000 + 1, .flags = IORESOURCE_MEM, }, [1] = { + .start = 0x20300000 + 4, + .end = 0x20300000 + 5, + .flags = IORESOURCE_MEM, + }, + [2] = { .start = IRQ_PF10, .end = IRQ_PF10, .flags = (IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHEDGE), diff --git a/arch/blackfin/mach-bf537/boards/generic_board.c b/arch/blackfin/mach-bf537/boards/generic_board.c index 7d250828dad8..01b63e2ec18f 100644 --- a/arch/blackfin/mach-bf537/boards/generic_board.c +++ b/arch/blackfin/mach-bf537/boards/generic_board.c @@ -166,10 +166,15 @@ static struct platform_device smc91x_device = { static struct resource dm9000_resources[] = { [0] = { .start = 0x203FB800, - .end = 0x203FB800 + 8, + .end = 0x203FB800 + 1, .flags = IORESOURCE_MEM, }, [1] = { + .start = 0x203FB800 + 4, + .end = 0x203FB800 + 5, + .flags = IORESOURCE_MEM, + }, + [2] = { .start = IRQ_PF9, .end = IRQ_PF9, .flags = (IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHEDGE), diff --git a/arch/cris/arch-v10/boot/Makefile b/arch/cris/arch-v10/boot/Makefile index 20c83a53caf3..217203014433 100644 --- a/arch/cris/arch-v10/boot/Makefile +++ b/arch/cris/arch-v10/boot/Makefile @@ -2,7 +2,6 @@ # arch/cris/arch-v10/boot/Makefile # -OBJCOPY = objcopy-cris OBJCOPYFLAGS = -O binary --remove-section=.bss subdir- := compressed rescue diff --git a/arch/cris/arch-v10/boot/compressed/Makefile b/arch/cris/arch-v10/boot/compressed/Makefile index 4a031cb27eb9..08d943ce4be7 100644 --- a/arch/cris/arch-v10/boot/compressed/Makefile +++ b/arch/cris/arch-v10/boot/compressed/Makefile @@ -2,12 +2,10 @@ # arch/cris/arch-v10/boot/compressed/Makefile # -CC = gcc-cris -melf $(LINUXINCLUDE) -ccflags-y += -O2 -LD = ld-cris -ldflags-y += -T $(obj)/decompress.ld +asflags-y += $(LINUXINCLUDE) +ccflags-y += -O2 $(LINUXINCLUDE) +ldflags-y += -T $(srctree)/$(obj)/decompress.ld OBJECTS = $(obj)/head.o $(obj)/misc.o -OBJCOPY = objcopy-cris OBJCOPYFLAGS = -O binary --remove-section=.bss quiet_cmd_image = BUILD $@ @@ -21,12 +19,6 @@ $(obj)/decompress.o: $(OBJECTS) FORCE $(obj)/decompress.bin: $(obj)/decompress.o FORCE $(call if_changed,objcopy) -$(obj)/head.o: $(obj)/head.S .config - @$(CC) -D__ASSEMBLY__ -traditional -c $< -o $@ - -$(obj)/misc.o: $(obj)/misc.c .config - @$(CC) -D__KERNEL__ -c $< -o $@ - $(obj)/vmlinux: $(obj)/piggy.gz $(obj)/decompress.bin FORCE $(call if_changed,image) diff --git a/arch/cris/arch-v10/boot/compressed/decompress.ld b/arch/cris/arch-v10/boot/compressed/decompress.ld index 0b0a14fe6177..e80f4594d543 100644 --- a/arch/cris/arch-v10/boot/compressed/decompress.ld +++ b/arch/cris/arch-v10/boot/compressed/decompress.ld @@ -1,4 +1,5 @@ -OUTPUT_FORMAT(elf32-us-cris) +/* OUTPUT_FORMAT(elf32-us-cris) */ +OUTPUT_FORMAT(elf32-cris) MEMORY { diff --git a/arch/cris/arch-v10/boot/compressed/head.S b/arch/cris/arch-v10/boot/compressed/head.S index 610bdb237553..981fbae84959 100644 --- a/arch/cris/arch-v10/boot/compressed/head.S +++ b/arch/cris/arch-v10/boot/compressed/head.S @@ -15,77 +15,77 @@ #define COMMAND_LINE_MAGIC 0x87109563 ;; Exported symbols - - .globl _input_data - + .globl input_data + + .text nop di ;; We need to initialze DRAM registers before we start using the DRAM - - cmp.d RAM_INIT_MAGIC, r8 ; Already initialized? + + cmp.d RAM_INIT_MAGIC, $r8 ; Already initialized? beq dram_init_finished nop - + #include "../../lib/dram_init.S" - -dram_init_finished: - + +dram_init_finished: + ;; Initiate the PA and PB ports - move.b CONFIG_ETRAX_DEF_R_PORT_PA_DATA, r0 - move.b r0, [R_PORT_PA_DATA] + move.b CONFIG_ETRAX_DEF_R_PORT_PA_DATA, $r0 + move.b $r0, [R_PORT_PA_DATA] - move.b CONFIG_ETRAX_DEF_R_PORT_PA_DIR, r0 - move.b r0, [R_PORT_PA_DIR] + move.b CONFIG_ETRAX_DEF_R_PORT_PA_DIR, $r0 + move.b $r0, [R_PORT_PA_DIR] - move.b CONFIG_ETRAX_DEF_R_PORT_PB_DATA, r0 - move.b r0, [R_PORT_PB_DATA] + move.b CONFIG_ETRAX_DEF_R_PORT_PB_DATA, $r0 + move.b $r0, [R_PORT_PB_DATA] - move.b CONFIG_ETRAX_DEF_R_PORT_PB_DIR, r0 - move.b r0, [R_PORT_PB_DIR] + move.b CONFIG_ETRAX_DEF_R_PORT_PB_DIR, $r0 + move.b $r0, [R_PORT_PB_DIR] ;; Setup the stack to a suitably high address. ;; We assume 8 MB is the minimum DRAM in an eLinux ;; product and put the sp at the top for now. - move.d 0x40800000, sp + move.d 0x40800000, $sp ;; Figure out where the compressed piggyback image is ;; in the flash (since we wont try to copy it to DRAM ;; before unpacking). It is at _edata, but in flash. ;; Use (_edata - basse) as offset to the current PC. - -basse: move.d pc, r5 - and.d 0x7fffffff, r5 ; strip any non-cache bit - subq 2, r5 ; compensate for the move.d pc instr - move.d r5, r0 ; save for later - flash address of 'basse' - add.d _edata, r5 - sub.d basse, r5 ; r5 = flash address of '_edata' - + +basse: move.d $pc, $r5 + and.d 0x7fffffff, $r5 ; strip any non-cache bit + subq 2, $r5 ; compensate for the move.d $pc instr + move.d $r5, $r0 ; save for later - flash address of 'basse' + add.d _edata, $r5 + sub.d basse, $r5 ; $r5 = flash address of '_edata' + ;; Copy text+data to DRAM - - move.d basse, r1 ; destination - move.d _edata, r2 ; end destination -1: move.w [r0+], r3 - move.w r3, [r1+] - cmp.d r2, r1 + + move.d basse, $r1 ; destination + move.d _edata, $r2 ; end destination +1: move.w [$r0+], $r3 + move.w $r3, [$r1+] + cmp.d $r2, $r1 bcs 1b nop - move.d r5, [_input_data] ; for the decompressor + move.d $r5, [input_data] ; for the decompressor ;; Clear the decompressors BSS (between _edata and _end) - - moveq 0, r0 - move.d _edata, r1 - move.d _end, r2 -1: move.w r0, [r1+] - cmp.d r2, r1 + + moveq 0, $r0 + move.d _edata, $r1 + move.d _end, $r2 +1: move.w $r0, [$r1+] + cmp.d $r2, $r1 bcs 1b nop @@ -94,16 +94,16 @@ basse: move.d pc, r5 move.d $r10, [$r12] move.d _cmd_line_addr, $r12 move.d $r11, [$r12] - - ;; Do the decompression and save compressed size in _inptr - jsr _decompress_kernel - - ;; Put start address of root partition in r9 so the kernel can use it + ;; Do the decompression and save compressed size in inptr + + jsr decompress_kernel + + ;; Put start address of root partition in $r9 so the kernel can use it ;; when mounting from flash - move.d [_input_data], r9 ; flash address of compressed kernel - add.d [_inptr], r9 ; size of compressed kernel + move.d [input_data], $r9 ; flash address of compressed kernel + add.d [inptr], $r9 ; size of compressed kernel ;; Restore command line magic and address. move.d _cmd_line_magic, $r10 @@ -112,12 +112,12 @@ basse: move.d pc, r5 move.d [$r11], $r11 ;; Enter the decompressed kernel - move.d RAM_INIT_MAGIC, r8 ; Tell kernel that DRAM is initialized + move.d RAM_INIT_MAGIC, $r8 ; Tell kernel that DRAM is initialized jump 0x40004000 ; kernel is linked to this address - + .data -_input_data: +input_data: .dword 0 ; used by the decompressor _cmd_line_magic: .dword 0 diff --git a/arch/cris/arch-v10/boot/compressed/misc.c b/arch/cris/arch-v10/boot/compressed/misc.c index 9a43ab19391e..18e13bce1400 100644 --- a/arch/cris/arch-v10/boot/compressed/misc.c +++ b/arch/cris/arch-v10/boot/compressed/misc.c @@ -29,12 +29,10 @@ #define OF(args) args #define STATIC static -void* memset(void* s, int c, size_t n); -void* memcpy(void* __dest, __const void* __src, - size_t __n); - -#define memzero(s, n) memset ((s), 0, (n)) +void *memset(void *s, int c, size_t n); +void *memcpy(void *__dest, __const void *__src, size_t __n); +#define memzero(s, n) memset((s), 0, (n)) typedef unsigned char uch; typedef unsigned short ush; @@ -62,57 +60,69 @@ static unsigned outcnt = 0; /* bytes in output buffer */ #define ENCRYPTED 0x20 /* bit 5 set: file is encrypted */ #define RESERVED 0xC0 /* bit 6,7: reserved */ -#define get_byte() inbuf[inptr++] - +#define get_byte() (inbuf[inptr++]) + /* Diagnostic functions */ #ifdef DEBUG -# define Assert(cond,msg) {if(!(cond)) error(msg);} +# define Assert(cond, msg) do { \ + if (!(cond)) \ + error(msg); \ + } while (0) # define Trace(x) fprintf x -# define Tracev(x) {if (verbose) fprintf x ;} -# define Tracevv(x) {if (verbose>1) fprintf x ;} -# define Tracec(c,x) {if (verbose && (c)) fprintf x ;} -# define Tracecv(c,x) {if (verbose>1 && (c)) fprintf x ;} +# define Tracev(x) do { \ + if (verbose) \ + fprintf x; \ + } while (0) +# define Tracevv(x) do { \ + if (verbose > 1) \ + fprintf x; \ + } while (0) +# define Tracec(c, x) do { \ + if (verbose && (c)) \ + fprintf x; \ + } while (0) +# define Tracecv(c, x) do { \ + if (verbose > 1 && (c)) \ + fprintf x; \ + } while (0) #else -# define Assert(cond,msg) +# define Assert(cond, msg) # define Trace(x) # define Tracev(x) # define Tracevv(x) -# define Tracec(c,x) -# define Tracecv(c,x) +# define Tracec(c, x) +# define Tracecv(c, x) #endif -static int fill_inbuf(void); static void flush_window(void); static void error(char *m); -static void gzip_mark(void **); -static void gzip_release(void **); extern char *input_data; /* lives in head.S */ static long bytes_out = 0; static uch *output_data; static unsigned long output_ptr = 0; - + static void *malloc(int size); static void free(void *where); -static void error(char *m); static void gzip_mark(void **); static void gzip_release(void **); - + static void puts(const char *); /* the "heap" is put directly after the BSS ends, at end */ - -extern int end; -static long free_mem_ptr = (long)&end; - + +extern int _end; +static long free_mem_ptr = (long)&_end; + #include "../../../../../lib/inflate.c" static void *malloc(int size) { void *p; - if (size <0) error("Malloc error"); + if (size < 0) + error("Malloc error"); free_mem_ptr = (free_mem_ptr + 3) & ~3; /* Align */ @@ -142,44 +152,47 @@ static void puts(const char *s) { #ifndef CONFIG_ETRAX_DEBUG_PORT_NULL - while(*s) { + while (*s) { #ifdef CONFIG_ETRAX_DEBUG_PORT0 - while(!(*R_SERIAL0_STATUS & (1 << 5))) ; + while (!(*R_SERIAL0_STATUS & (1 << 5))) ; *R_SERIAL0_TR_DATA = *s++; #endif #ifdef CONFIG_ETRAX_DEBUG_PORT1 - while(!(*R_SERIAL1_STATUS & (1 << 5))) ; + while (!(*R_SERIAL1_STATUS & (1 << 5))) ; *R_SERIAL1_TR_DATA = *s++; #endif #ifdef CONFIG_ETRAX_DEBUG_PORT2 - while(!(*R_SERIAL2_STATUS & (1 << 5))) ; + while (!(*R_SERIAL2_STATUS & (1 << 5))) ; *R_SERIAL2_TR_DATA = *s++; #endif #ifdef CONFIG_ETRAX_DEBUG_PORT3 - while(!(*R_SERIAL3_STATUS & (1 << 5))) ; + while (!(*R_SERIAL3_STATUS & (1 << 5))) ; *R_SERIAL3_TR_DATA = *s++; #endif } #endif } -void* -memset(void* s, int c, size_t n) +void *memset(void *s, int c, size_t n) { int i; - char *ss = (char*)s; + char *ss = (char *)s; + + for (i = 0; i < n; i++) + ss[i] = c; - for (i=0;i<n;i++) ss[i] = c; + return s; } -void* -memcpy(void* __dest, __const void* __src, - size_t __n) +void *memcpy(void *__dest, __const void *__src, size_t __n) { int i; char *d = (char *)__dest, *s = (char *)__src; - for (i=0;i<__n;i++) d[i] = s[i]; + for (i = 0; i < __n; i++) + d[i] = s[i]; + + return __dest; } /* =========================================================================== @@ -187,46 +200,44 @@ memcpy(void* __dest, __const void* __src, * (Used for the decompressed data only.) */ -static void -flush_window() +static void flush_window(void) { - ulg c = crc; /* temporary variable */ - unsigned n; - uch *in, *out, ch; - - in = window; - out = &output_data[output_ptr]; - for (n = 0; n < outcnt; n++) { - ch = *out++ = *in++; - c = crc_32_tab[((int)c ^ ch) & 0xff] ^ (c >> 8); - } - crc = c; - bytes_out += (ulg)outcnt; - output_ptr += (ulg)outcnt; - outcnt = 0; + ulg c = crc; /* temporary variable */ + unsigned n; + uch *in, *out, ch; + + in = window; + out = &output_data[output_ptr]; + for (n = 0; n < outcnt; n++) { + ch = *out = *in; + out++; + in++; + c = crc_32_tab[((int)c ^ ch) & 0xff] ^ (c >> 8); + } + crc = c; + bytes_out += (ulg)outcnt; + output_ptr += (ulg)outcnt; + outcnt = 0; } -static void -error(char *x) +static void error(char *x) { puts("\n\n"); puts(x); puts("\n\n -- System halted\n"); - while(1); /* Halt */ + while (1); /* Halt */ } -void -setup_normal_output_buffer() +void setup_normal_output_buffer(void) { output_data = (char *)KERNEL_LOAD_ADR; } -void -decompress_kernel() +void decompress_kernel(void) { char revision; - + /* input_data is set in head.S */ inbuf = input_data; @@ -257,11 +268,10 @@ decompress_kernel() makecrc(); - __asm__ volatile ("move vr,%0" : "=rm" (revision)); - if (revision < 10) - { + __asm__ volatile ("move $vr,%0" : "=rm" (revision)); + if (revision < 10) { puts("You need an ETRAX 100LX to run linux 2.6\n"); - while(1); + while (1); } puts("Uncompressing Linux...\n"); diff --git a/arch/cris/arch-v10/boot/rescue/Makefile b/arch/cris/arch-v10/boot/rescue/Makefile index 2e5045b9e19c..07688da92708 100644 --- a/arch/cris/arch-v10/boot/rescue/Makefile +++ b/arch/cris/arch-v10/boot/rescue/Makefile @@ -2,12 +2,9 @@ # Makefile for rescue (bootstrap) code # -CC = gcc-cris -mlinux $(LINUXINCLUDE) -ccflags-y += -O2 -asflags-y += -traditional -LD = gcc-cris -mlinux -nostdlib -ldflags-y += -T $(obj)/rescue.ld -OBJCOPY = objcopy-cris +ccflags-y += -O2 $(LINUXINCLUDE) +asflags-y += $(LINUXINCLUDE) +ldflags-y += -T $(srctree)/$(obj)/rescue.ld OBJCOPYFLAGS = -O binary --remove-section=.bss obj-$(CONFIG_ETRAX_AXISFLASHMAP) = head.o OBJECT := $(obj)/head.o diff --git a/arch/cris/arch-v10/drivers/pcf8563.c b/arch/cris/arch-v10/drivers/pcf8563.c index 52103d16dc6c..8769dc914073 100644 --- a/arch/cris/arch-v10/drivers/pcf8563.c +++ b/arch/cris/arch-v10/drivers/pcf8563.c @@ -233,7 +233,7 @@ int pcf8563_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, if (copy_to_user((struct rtc_time *) arg, &tm, sizeof tm)) { - spin_unlock(&rtc_lock); + mutex_unlock(&rtc_lock); return -EFAULT; } diff --git a/arch/cris/arch-v10/kernel/debugport.c b/arch/cris/arch-v10/kernel/debugport.c index 04d5eee2c90c..3dc6e91ba39e 100644 --- a/arch/cris/arch-v10/kernel/debugport.c +++ b/arch/cris/arch-v10/kernel/debugport.c @@ -426,12 +426,18 @@ static int dummy_write(struct tty_struct * tty, return count; } -static int -dummy_write_room(struct tty_struct *tty) +static int dummy_write_room(struct tty_struct *tty) { return 8192; } +static const struct tty_operations dummy_ops = { + .open = dummy_open, + .close = dummy_close, + .write = dummy_write, + .write_room = dummy_write_room, +}; + void __init init_dummy_console(void) { @@ -444,14 +450,14 @@ init_dummy_console(void) dummy_driver.type = TTY_DRIVER_TYPE_SERIAL; dummy_driver.subtype = SERIAL_TYPE_NORMAL; dummy_driver.init_termios = tty_std_termios; + /* Normally B9600 default... */ dummy_driver.init_termios.c_cflag = - B115200 | CS8 | CREAD | HUPCL | CLOCAL; /* is normally B9600 default... */ + B115200 | CS8 | CREAD | HUPCL | CLOCAL; dummy_driver.flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV; + dummy_driver.init_termios.c_ispeed = 115200; + dummy_driver.init_termios.c_ospeed = 115200; - dummy_driver.open = dummy_open; - dummy_driver.close = dummy_close; - dummy_driver.write = dummy_write; - dummy_driver.write_room = dummy_write_room; + dummy_driver.ops = &dummy_ops; if (tty_register_driver(&dummy_driver)) panic("Couldn't register dummy serial driver\n"); } diff --git a/arch/cris/arch-v32/boot/Makefile b/arch/cris/arch-v32/boot/Makefile index 3f91349c5f12..99896ad60b30 100644 --- a/arch/cris/arch-v32/boot/Makefile +++ b/arch/cris/arch-v32/boot/Makefile @@ -2,7 +2,6 @@ # arch/cris/arch-v32/boot/Makefile # -OBJCOPY = objcopy-cris OBJCOPYFLAGS = -O binary -R .note -R .comment subdir- := compressed rescue diff --git a/arch/cris/arch-v32/boot/compressed/Makefile b/arch/cris/arch-v32/boot/compressed/Makefile index 2c8c2c3039c5..d6335f26083b 100644 --- a/arch/cris/arch-v32/boot/compressed/Makefile +++ b/arch/cris/arch-v32/boot/compressed/Makefile @@ -2,14 +2,10 @@ # arch/cris/arch-v32/boot/compressed/Makefile # -CC = gcc-cris -mlinux -march=v32 $(LINUXINCLUDE) asflags-y += -I $(srctree)/include/asm/mach/ -I $(srctree)/include/asm/arch ccflags-y += -O2 -I $(srctree)/include/asm/mach/ -I $(srctree)/include/asm/arch -LD = gcc-cris -mlinux -march=v32 -nostdlib -ldflags-y += -T $(obj)/decompress.ld -obj-y = head.o misc.o +ldflags-y += -T $(srctree)/$(obj)/decompress.ld OBJECTS = $(obj)/head.o $(obj)/misc.o -OBJCOPY = objcopy-cris OBJCOPYFLAGS = -O binary --remove-section=.bss quiet_cmd_image = BUILD $@ diff --git a/arch/cris/arch-v32/boot/rescue/Makefile b/arch/cris/arch-v32/boot/rescue/Makefile index c0987795dcb7..44ae0ad61f90 100644 --- a/arch/cris/arch-v32/boot/rescue/Makefile +++ b/arch/cris/arch-v32/boot/rescue/Makefile @@ -7,9 +7,8 @@ ccflags-y += -O2 -I $(srctree)/include/asm/arch/mach/ \ -I $(srctree)/include/asm/arch asflags-y += -I $(srctree)/include/asm/arch/mach/ -I $(srctree)/include/asm/arch LD = gcc-cris -mlinux -march=v32 -nostdlib -ldflags-y += -T $(obj)/rescue.ld +ldflags-y += -T $(srctree)/$(obj)/rescue.ld LDPOSTFLAGS = -lgcc -OBJCOPY = objcopy-cris OBJCOPYFLAGS = -O binary --remove-section=.bss obj-$(CONFIG_ETRAX_AXISFLASHMAP) = head.o OBJECT := $(obj)/head.o diff --git a/arch/cris/arch-v32/drivers/pcf8563.c b/arch/cris/arch-v32/drivers/pcf8563.c index 53db3870ba04..f263ab571221 100644 --- a/arch/cris/arch-v32/drivers/pcf8563.c +++ b/arch/cris/arch-v32/drivers/pcf8563.c @@ -229,7 +229,7 @@ int pcf8563_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, if (copy_to_user((struct rtc_time *) arg, &tm, sizeof tm)) { - spin_unlock(&rtc_lock); + mutex_unlock(&rtc_lock); return -EFAULT; } diff --git a/arch/ia64/hp/sim/simserial.c b/arch/ia64/hp/sim/simserial.c index 23cafc80d2a4..24b1ad5334cb 100644 --- a/arch/ia64/hp/sim/simserial.c +++ b/arch/ia64/hp/sim/simserial.c @@ -193,18 +193,6 @@ static irqreturn_t rs_interrupt_single(int irq, void *dev_id) * ------------------------------------------------------------------- */ -#if 0 -/* - * not really used in our situation so keep them commented out for now - */ -static DECLARE_TASK_QUEUE(tq_serial); /* used to be at the top of the file */ -static void do_serial_bh(void) -{ - run_task_queue(&tq_serial); - printk(KERN_ERR "do_serial_bh: called\n"); -} -#endif - static void do_softint(struct work_struct *private_) { printk(KERN_ERR "simserial: do_softint called\n"); @@ -351,11 +339,7 @@ static void rs_flush_buffer(struct tty_struct *tty) info->xmit.head = info->xmit.tail = 0; local_irq_restore(flags); - wake_up_interruptible(&tty->write_wait); - - if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && - tty->ldisc.write_wakeup) - (tty->ldisc.write_wakeup)(tty); + tty_wakeup(tty); } /* @@ -404,12 +388,6 @@ static void rs_unthrottle(struct tty_struct * tty) printk(KERN_INFO "simrs_unthrottle called\n"); } -/* - * rs_break() --- routine which turns the break handling on or off - */ -static void rs_break(struct tty_struct *tty, int break_state) -{ -} static int rs_ioctl(struct tty_struct *tty, struct file * file, unsigned int cmd, unsigned long arg) @@ -422,14 +400,6 @@ static int rs_ioctl(struct tty_struct *tty, struct file * file, } switch (cmd) { - case TIOCMGET: - printk(KERN_INFO "rs_ioctl: TIOCMGET called\n"); - return -EINVAL; - case TIOCMBIS: - case TIOCMBIC: - case TIOCMSET: - printk(KERN_INFO "rs_ioctl: TIOCMBIS/BIC/SET called\n"); - return -EINVAL; case TIOCGSERIAL: printk(KERN_INFO "simrs_ioctl TIOCGSERIAL called\n"); return 0; @@ -488,14 +458,6 @@ static int rs_ioctl(struct tty_struct *tty, struct file * file, static void rs_set_termios(struct tty_struct *tty, struct ktermios *old_termios) { - unsigned int cflag = tty->termios->c_cflag; - - if ( (cflag == old_termios->c_cflag) - && ( RELEVANT_IFLAG(tty->termios->c_iflag) - == RELEVANT_IFLAG(old_termios->c_iflag))) - return; - - /* Handle turning off CRTSCTS */ if ((old_termios->c_cflag & CRTSCTS) && !(tty->termios->c_cflag & CRTSCTS)) { @@ -623,9 +585,8 @@ static void rs_close(struct tty_struct *tty, struct file * filp) * the line discipline to only process XON/XOFF characters. */ shutdown(info); - if (tty->ops->flush_buffer) - tty->ops->flush_buffer(tty); - if (tty->ldisc.flush_buffer) tty->ldisc.flush_buffer(tty); + rs_flush_buffer(tty); + tty_ldisc_flush(tty); info->event = 0; info->tty = NULL; if (info->blocked_open) { @@ -955,7 +916,6 @@ static const struct tty_operations hp_ops = { .stop = rs_stop, .start = rs_start, .hangup = rs_hangup, - .break_ctl = rs_break, .wait_until_sent = rs_wait_until_sent, .read_proc = rs_read_proc, }; diff --git a/arch/ia64/kvm/Makefile b/arch/ia64/kvm/Makefile index 112791dd2542..bf22fb9e6dcf 100644 --- a/arch/ia64/kvm/Makefile +++ b/arch/ia64/kvm/Makefile @@ -43,7 +43,8 @@ $(obj)/$(offsets-file): arch/ia64/kvm/asm-offsets.s EXTRA_CFLAGS += -Ivirt/kvm -Iarch/ia64/kvm/ EXTRA_AFLAGS += -Ivirt/kvm -Iarch/ia64/kvm/ -common-objs = $(addprefix ../../../virt/kvm/, kvm_main.o ioapic.o) +common-objs = $(addprefix ../../../virt/kvm/, kvm_main.o ioapic.o \ + coalesced_mmio.o) kvm-objs := $(common-objs) kvm-ia64.o kvm_fw.o obj-$(CONFIG_KVM) += kvm.o diff --git a/arch/ia64/kvm/kvm-ia64.c b/arch/ia64/kvm/kvm-ia64.c index 68c978be9a51..2672f4d278ac 100644 --- a/arch/ia64/kvm/kvm-ia64.c +++ b/arch/ia64/kvm/kvm-ia64.c @@ -187,6 +187,9 @@ int kvm_dev_ioctl_check_extension(long ext) r = 1; break; + case KVM_CAP_COALESCED_MMIO: + r = KVM_COALESCED_MMIO_PAGE_OFFSET; + break; default: r = 0; } @@ -195,11 +198,11 @@ int kvm_dev_ioctl_check_extension(long ext) } static struct kvm_io_device *vcpu_find_mmio_dev(struct kvm_vcpu *vcpu, - gpa_t addr) + gpa_t addr, int len, int is_write) { struct kvm_io_device *dev; - dev = kvm_io_bus_find_dev(&vcpu->kvm->mmio_bus, addr); + dev = kvm_io_bus_find_dev(&vcpu->kvm->mmio_bus, addr, len, is_write); return dev; } @@ -231,7 +234,7 @@ static int handle_mmio(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) kvm_run->exit_reason = KVM_EXIT_MMIO; return 0; mmio: - mmio_dev = vcpu_find_mmio_dev(vcpu, p->addr); + mmio_dev = vcpu_find_mmio_dev(vcpu, p->addr, p->size, !p->dir); if (mmio_dev) { if (!p->dir) kvm_iodevice_write(mmio_dev, p->addr, p->size, @@ -1035,14 +1038,6 @@ static void kvm_free_vmm_area(void) } } -/* - * Make sure that a cpu that is being hot-unplugged does not have any vcpus - * cached on it. Leave it as blank for IA64. - */ -void decache_vcpus_on_cpu(int cpu) -{ -} - static void vti_vcpu_load(struct kvm_vcpu *vcpu, int cpu) { } @@ -1460,6 +1455,9 @@ int kvm_arch_set_memory_region(struct kvm *kvm, return 0; } +void kvm_arch_flush_shadow(struct kvm *kvm) +{ +} long kvm_arch_dev_ioctl(struct file *filp, unsigned int ioctl, unsigned long arg) diff --git a/arch/m68k/Kconfig b/arch/m68k/Kconfig index 55ea52fe6aca..8c5e1de68fcb 100644 --- a/arch/m68k/Kconfig +++ b/arch/m68k/Kconfig @@ -490,28 +490,6 @@ config ATARI_MFPSER Note for Falcon users: You also have an MFP port, it's just not wired to the outside... But you could use the port under Linux. -config ATARI_SCC - tristate "Atari SCC serial support" - depends on ATARI - ---help--- - If you have serial ports based on a Zilog SCC chip (Modem2, Serial2, - LAN) and like to use them under Linux, say Y. All built-in SCC's are - supported (TT, MegaSTE, Falcon), and also the ST-ESCC. If you have - two connectors for channel A (Serial2 and LAN), they are visible as - two separate devices. - - To compile this driver as a module, choose M here. - -config ATARI_SCC_DMA - bool "Atari SCC serial DMA support" - depends on ATARI_SCC - help - This enables DMA support for receiving data on channel A of the SCC. - If you have a TT you may say Y here and read - drivers/char/atari_SCC.README. All other users should say N here, - because only the TT has SCC-DMA, even if your machine keeps claiming - so at boot time. - config ATARI_MIDI tristate "Atari MIDI serial support" depends on ATARI @@ -578,18 +556,6 @@ config MAC_HID depends on INPUT_ADBHID default y -config ADB_KEYBOARD - bool "Support for ADB keyboard (old driver)" - depends on MAC && !INPUT_ADBHID - help - This option allows you to use an ADB keyboard attached to your - machine. Note that this disables any other (ie. PS/2) keyboard - support, even if your machine is physically capable of using both at - the same time. - - If you use an ADB keyboard (4 pin connector), say Y here. - If you use a PS/2 keyboard (6 pin connector), say N here. - config HPDCA tristate "HP DCA serial support" depends on DIO && SERIAL_8250 @@ -640,7 +606,7 @@ config DN_SERIAL config SERIAL_CONSOLE bool "Support for serial port console" - depends on (AMIGA || ATARI || MAC || SUN3 || SUN3X || VME || APOLLO) && (ATARI_MFPSER=y || ATARI_SCC=y || ATARI_MIDI=y || MAC_SCC=y || AMIGA_BUILTIN_SERIAL=y || GVPIOEXT=y || MULTIFACE_III_TTY=y || SERIAL=y || MVME147_SCC || SERIAL167 || MVME162_SCC || BVME6000_SCC || DN_SERIAL) + depends on (AMIGA || ATARI || MAC || SUN3 || SUN3X || VME || APOLLO) && (ATARI_MFPSER=y || ATARI_MIDI=y || MAC_SCC=y || AMIGA_BUILTIN_SERIAL=y || GVPIOEXT=y || MULTIFACE_III_TTY=y || SERIAL=y || MVME147_SCC || SERIAL167 || MVME162_SCC || BVME6000_SCC || DN_SERIAL) ---help--- If you say Y here, it will be possible to use a serial port as the system console (the system console is the device which receives all diff --git a/arch/m68k/Makefile b/arch/m68k/Makefile index b15173f28a23..8133dbc44964 100644 --- a/arch/m68k/Makefile +++ b/arch/m68k/Makefile @@ -13,7 +13,7 @@ # Copyright (C) 1994 by Hamish Macdonald # -KBUILD_DEFCONFIG := amiga_defconfig +KBUILD_DEFCONFIG := multi_defconfig # override top level makefile AS += -m68020 diff --git a/arch/m68k/amiga/config.c b/arch/m68k/amiga/config.c index 50f5daab46b7..df679d96b1cb 100644 --- a/arch/m68k/amiga/config.c +++ b/arch/m68k/amiga/config.c @@ -36,14 +36,11 @@ #include <asm/machdep.h> #include <asm/io.h> -unsigned long amiga_model; -EXPORT_SYMBOL(amiga_model); +static unsigned long amiga_model; unsigned long amiga_eclock; EXPORT_SYMBOL(amiga_eclock); -unsigned long amiga_masterclock; - unsigned long amiga_colorclock; EXPORT_SYMBOL(amiga_colorclock); @@ -51,7 +48,9 @@ unsigned long amiga_chipset; EXPORT_SYMBOL(amiga_chipset); unsigned char amiga_vblank; -unsigned char amiga_psfreq; +EXPORT_SYMBOL(amiga_vblank); + +static unsigned char amiga_psfreq; struct amiga_hw_present amiga_hw_present; EXPORT_SYMBOL(amiga_hw_present); @@ -92,8 +91,6 @@ static char *amiga_models[] __initdata = { static char amiga_model_name[13] = "Amiga "; static void amiga_sched_init(irq_handler_t handler); -/* amiga specific irq functions */ -extern void amiga_init_IRQ(void); static void amiga_get_model(char *model); static int amiga_get_hardware_list(char *buffer); /* amiga specific timer functions */ @@ -107,8 +104,6 @@ static void amiga_reset(void); extern void amiga_init_sound(void); static void amiga_mem_console_write(struct console *co, const char *b, unsigned int count); -void amiga_serial_console_write(struct console *co, const char *s, - unsigned int count); #ifdef CONFIG_HEARTBEAT static void amiga_heartbeat(int on); #endif @@ -418,8 +413,7 @@ void __init config_amiga(void) mach_heartbeat = amiga_heartbeat; #endif - /* Fill in the clock values (based on the 700 kHz E-Clock) */ - amiga_masterclock = 40*amiga_eclock; /* 28 MHz */ + /* Fill in the clock value (based on the 700 kHz E-Clock) */ amiga_colorclock = 5*amiga_eclock; /* 3.5 MHz */ /* clear all DMA bits */ @@ -817,8 +811,8 @@ static void amiga_serial_putc(char c) ; } -void amiga_serial_console_write(struct console *co, const char *s, - unsigned int count) +static void amiga_serial_console_write(struct console *co, const char *s, + unsigned int count) { while (count--) { if (*s == '\n') @@ -827,7 +821,7 @@ void amiga_serial_console_write(struct console *co, const char *s, } } -#ifdef CONFIG_SERIAL_CONSOLE +#if 0 void amiga_serial_puts(const char *s) { amiga_serial_console_write(NULL, s, strlen(s)); diff --git a/arch/m68k/atari/debug.c b/arch/m68k/atari/debug.c index 043ddbc61c7b..702b15ccfab7 100644 --- a/arch/m68k/atari/debug.c +++ b/arch/m68k/atari/debug.c @@ -20,14 +20,6 @@ #include <asm/atarihw.h> #include <asm/atariints.h> -/* Flag that Modem1 port is already initialized and used */ -int atari_MFP_init_done; -EXPORT_SYMBOL(atari_MFP_init_done); - -/* Flag that Modem1 port is already initialized and used */ -int atari_SCC_init_done; -EXPORT_SYMBOL(atari_SCC_init_done); - /* Can be set somewhere, if a SCC master reset has already be done and should * not be repeated; used by kgdb */ int atari_SCC_reset_done; @@ -47,8 +39,8 @@ static inline void ata_mfp_out(char c) mfp.usart_dta = c; } -void atari_mfp_console_write(struct console *co, const char *str, - unsigned int count) +static void atari_mfp_console_write(struct console *co, const char *str, + unsigned int count) { while (count--) { if (*str == '\n') @@ -66,8 +58,8 @@ static inline void ata_scc_out(char c) scc.cha_b_data = c; } -void atari_scc_console_write(struct console *co, const char *str, - unsigned int count) +static void atari_scc_console_write(struct console *co, const char *str, + unsigned int count) { while (count--) { if (*str == '\n') @@ -83,8 +75,8 @@ static inline void ata_midi_out(char c) acia.mid_data = c; } -void atari_midi_console_write(struct console *co, const char *str, - unsigned int count) +static void atari_midi_console_write(struct console *co, const char *str, + unsigned int count) { while (count--) { if (*str == '\n') @@ -136,7 +128,7 @@ static void atari_par_console_write(struct console *co, const char *str, } } -#ifdef CONFIG_SERIAL_CONSOLE +#if 0 int atari_mfp_console_wait_key(struct console *co) { while (!(mfp.rcv_stat & 0x80)) /* wait for rx buf filled */ @@ -166,11 +158,7 @@ int atari_midi_console_wait_key(struct console *co) * SCC serial ports. They're used by the debugging interface, kgdb, and the * serial console code. */ -#ifndef CONFIG_SERIAL_CONSOLE static void __init atari_init_mfp_port(int cflag) -#else -void atari_init_mfp_port(int cflag) -#endif { /* * timer values for 1200...115200 bps; > 38400 select 110, 134, or 150 @@ -193,8 +181,6 @@ void atari_init_mfp_port(int cflag) mfp.tim_dt_d = baud_table[baud]; mfp.tim_ct_cd |= 0x01; /* start timer D, 1:4 */ mfp.trn_stat |= 0x01; /* enable TX */ - - atari_MFP_init_done = 1; } #define SCC_WRITE(reg, val) \ @@ -214,11 +200,7 @@ void atari_init_mfp_port(int cflag) MFPDELAY(); \ } while (0) -#ifndef CONFIG_SERIAL_CONSOLE static void __init atari_init_scc_port(int cflag) -#else -void atari_init_scc_port(int cflag) -#endif { extern int atari_SCC_reset_done; static int clksrc_table[9] = @@ -277,14 +259,9 @@ void atari_init_scc_port(int cflag) SCC_WRITE(5, reg5 | 8); atari_SCC_reset_done = 1; - atari_SCC_init_done = 1; } -#ifndef CONFIG_SERIAL_CONSOLE static void __init atari_init_midi_port(int cflag) -#else -void atari_init_midi_port(int cflag) -#endif { int baud = cflag & CBAUD; int csize = ((cflag & CSIZE) == CS8) ? 0x10 : 0x00; diff --git a/arch/m68k/fpsp040/Makefile b/arch/m68k/fpsp040/Makefile index 0214d2f6f8b0..9506d883ace5 100644 --- a/arch/m68k/fpsp040/Makefile +++ b/arch/m68k/fpsp040/Makefile @@ -10,7 +10,6 @@ obj-y := bindec.o binstr.o decbin.o do_func.o gen_except.o get_op.o \ x_bsun.o x_fline.o x_operr.o x_ovfl.o x_snan.o x_store.o \ x_unfl.o x_unimp.o x_unsupp.o bugfix.o skeleton.o -EXTRA_AFLAGS := -traditional EXTRA_LDFLAGS := -x $(OS_OBJS): fpsp.h diff --git a/arch/m68k/ifpsp060/Makefile b/arch/m68k/ifpsp060/Makefile index 2fe8472cb5e3..43b435049452 100644 --- a/arch/m68k/ifpsp060/Makefile +++ b/arch/m68k/ifpsp060/Makefile @@ -6,5 +6,4 @@ obj-y := fskeleton.o iskeleton.o os.o -EXTRA_AFLAGS := -traditional EXTRA_LDFLAGS := -x diff --git a/arch/m68k/kernel/Makefile b/arch/m68k/kernel/Makefile index 7a62a718143b..3a7f62225504 100644 --- a/arch/m68k/kernel/Makefile +++ b/arch/m68k/kernel/Makefile @@ -16,5 +16,3 @@ devres-y = ../../../kernel/irq/devres.o obj-$(CONFIG_PCI) += bios32.o obj-y$(CONFIG_MMU_SUN3) += dma.o # no, it's not a typo - -EXTRA_AFLAGS := -traditional diff --git a/arch/m68k/kernel/setup.c b/arch/m68k/kernel/setup.c index a9fb83a8c180..ea1e44da19b9 100644 --- a/arch/m68k/kernel/setup.c +++ b/arch/m68k/kernel/setup.c @@ -26,6 +26,7 @@ #include <asm/bootinfo.h> #include <asm/setup.h> +#include <asm/fpu.h> #include <asm/irq.h> #include <asm/io.h> #include <asm/machdep.h> @@ -40,6 +41,11 @@ #include <asm/dvma.h> #endif +#if !FPSTATESIZE || !NR_IRQS +#warning No CPU/platform type selected, your kernel will not work! +#warning Are you building an allnoconfig kernel? +#endif + unsigned long m68k_machtype; EXPORT_SYMBOL(m68k_machtype); unsigned long m68k_cputype; @@ -116,6 +122,7 @@ extern int bvme6000_parse_bootinfo(const struct bi_record *); extern int mvme16x_parse_bootinfo(const struct bi_record *); extern int mvme147_parse_bootinfo(const struct bi_record *); extern int hp300_parse_bootinfo(const struct bi_record *); +extern int apollo_parse_bootinfo(const struct bi_record *); extern void config_amiga(void); extern void config_atari(void); @@ -183,6 +190,8 @@ static void __init m68k_parse_bootinfo(const struct bi_record *record) unknown = mvme147_parse_bootinfo(record); else if (MACH_IS_HP300) unknown = hp300_parse_bootinfo(record); + else if (MACH_IS_APOLLO) + unknown = apollo_parse_bootinfo(record); else unknown = 1; } diff --git a/arch/m68k/kernel/vmlinux-std.lds b/arch/m68k/kernel/vmlinux-std.lds index 7537cc5e6159..99b0784c0552 100644 --- a/arch/m68k/kernel/vmlinux-std.lds +++ b/arch/m68k/kernel/vmlinux-std.lds @@ -1,6 +1,7 @@ /* ld script to make m68k Linux kernel */ #include <asm-generic/vmlinux.lds.h> +#include <asm/page.h> OUTPUT_FORMAT("elf32-m68k", "elf32-m68k", "elf32-m68k") OUTPUT_ARCH(m68k) @@ -41,7 +42,7 @@ SECTIONS _edata = .; /* End of data section */ /* will be freed after init */ - . = ALIGN(4096); /* Init code and data */ + . = ALIGN(PAGE_SIZE); /* Init code and data */ __init_begin = .; .init.text : { _sinittext = .; diff --git a/arch/m68k/kernel/vmlinux-sun3.lds b/arch/m68k/kernel/vmlinux-sun3.lds index cdc313e7c299..8a4919e4d36a 100644 --- a/arch/m68k/kernel/vmlinux-sun3.lds +++ b/arch/m68k/kernel/vmlinux-sun3.lds @@ -1,6 +1,7 @@ /* ld script to make m68k Linux kernel */ #include <asm-generic/vmlinux.lds.h> +#include <asm/page.h> OUTPUT_FORMAT("elf32-m68k", "elf32-m68k", "elf32-m68k") OUTPUT_ARCH(m68k) @@ -34,7 +35,7 @@ SECTIONS _edata = .; /* will be freed after init */ - . = ALIGN(8192); /* Init code and data */ + . = ALIGN(PAGE_SIZE); /* Init code and data */ __init_begin = .; .init.text : { _sinittext = .; @@ -61,12 +62,12 @@ __init_begin = .; } SECURITY_INIT #ifdef CONFIG_BLK_DEV_INITRD - . = ALIGN(8192); + . = ALIGN(PAGE_SIZE); __initramfs_start = .; .init.ramfs : { *(.init.ramfs) } __initramfs_end = .; #endif - . = ALIGN(8192); + . = ALIGN(PAGE_SIZE); __init_end = .; .data.init.task : { *(.data.init_task) } diff --git a/arch/m68k/lib/Makefile b/arch/m68k/lib/Makefile index a18af095cd7c..af9abf8d9d98 100644 --- a/arch/m68k/lib/Makefile +++ b/arch/m68k/lib/Makefile @@ -2,7 +2,5 @@ # Makefile for m68k-specific library files.. # -EXTRA_AFLAGS := -traditional - lib-y := ashldi3.o ashrdi3.o lshrdi3.o muldi3.o \ checksum.o string.o uaccess.o diff --git a/arch/m68k/mac/Makefile b/arch/m68k/mac/Makefile index 1d265ba365ad..daebd80bdef0 100644 --- a/arch/m68k/mac/Makefile +++ b/arch/m68k/mac/Makefile @@ -2,5 +2,5 @@ # Makefile for Linux arch/m68k/mac source directory # -obj-y := config.o bootparse.o macints.o iop.o via.o oss.o psc.o \ +obj-y := config.o macints.o iop.o via.o oss.o psc.o \ baboon.o macboing.o debug.o misc.o diff --git a/arch/m68k/mac/baboon.c b/arch/m68k/mac/baboon.c index 673a1085984d..dae9c982aa89 100644 --- a/arch/m68k/mac/baboon.c +++ b/arch/m68k/mac/baboon.c @@ -23,9 +23,7 @@ /* #define DEBUG_IRQS */ int baboon_present; -volatile struct baboon *baboon; - -irqreturn_t baboon_irq(int, void *); +static volatile struct baboon *baboon; #if 0 extern int macide_ack_intr(struct ata_channel *); @@ -50,20 +48,10 @@ void __init baboon_init(void) } /* - * Register the Baboon interrupt dispatcher on nubus slot $C. - */ - -void __init baboon_register_interrupts(void) -{ - request_irq(IRQ_NUBUS_C, baboon_irq, IRQ_FLG_LOCK|IRQ_FLG_FAST, - "baboon", (void *) baboon); -} - -/* * Baboon interrupt handler. This works a lot like a VIA. */ -irqreturn_t baboon_irq(int irq, void *dev_id) +static irqreturn_t baboon_irq(int irq, void *dev_id) { int irq_bit, irq_num; unsigned char events; @@ -95,6 +83,16 @@ irqreturn_t baboon_irq(int irq, void *dev_id) return IRQ_HANDLED; } +/* + * Register the Baboon interrupt dispatcher on nubus slot $C. + */ + +void __init baboon_register_interrupts(void) +{ + request_irq(IRQ_NUBUS_C, baboon_irq, IRQ_FLG_LOCK|IRQ_FLG_FAST, + "baboon", (void *) baboon); +} + void baboon_irq_enable(int irq) { #ifdef DEBUG_IRQUSE printk("baboon_irq_enable(%d)\n", irq); diff --git a/arch/m68k/mac/bootparse.c b/arch/m68k/mac/bootparse.c deleted file mode 100644 index 36d223609823..000000000000 --- a/arch/m68k/mac/bootparse.c +++ /dev/null @@ -1,122 +0,0 @@ -#include <linux/string.h> -#include <linux/kernel.h> -#include <linux/sched.h> -#include <asm/irq.h> -#include <asm/setup.h> -#include <asm/bootinfo.h> -#include <asm/macintosh.h> - -/* - * Booter vars - */ - -int boothowto; -int _boothowto; - -/* - * Called early to parse the environment (passed to us from the booter) - * into a bootinfo struct. Will die as soon as we have our own booter - */ - -#define atol(x) simple_strtoul(x,NULL,0) - -void parse_booter(char *env) -{ - char *name; - char *value; -#if 0 - while(0 && *env) -#else - while(*env) -#endif - { - name=env; - value=name; - while(*value!='='&&*value) - value++; - if(*value=='=') - *value++=0; - env=value; - while(*env) - env++; - env++; -#if 0 - if(strcmp(name,"VIDEO_ADDR")==0) - mac_mch.videoaddr=atol(value); - if(strcmp(name,"ROW_BYTES")==0) - mac_mch.videorow=atol(value); - if(strcmp(name,"SCREEN_DEPTH")==0) - mac_mch.videodepth=atol(value); - if(strcmp(name,"DIMENSIONS")==0) - mac_mch.dimensions=atol(value); -#endif - if(strcmp(name,"BOOTTIME")==0) - mac_bi_data.boottime=atol(value); - if(strcmp(name,"GMTBIAS")==0) - mac_bi_data.gmtbias=atol(value); - if(strcmp(name,"BOOTERVER")==0) - mac_bi_data.bootver=atol(value); - if(strcmp(name,"MACOS_VIDEO")==0) - mac_bi_data.videological=atol(value); - if(strcmp(name,"MACOS_SCC")==0) - mac_bi_data.sccbase=atol(value); - if(strcmp(name,"MACHINEID")==0) - mac_bi_data.id=atol(value); - if(strcmp(name,"MEMSIZE")==0) - mac_bi_data.memsize=atol(value); - if(strcmp(name,"SERIAL_MODEM_FLAGS")==0) - mac_bi_data.serialmf=atol(value); - if(strcmp(name,"SERIAL_MODEM_HSKICLK")==0) - mac_bi_data.serialhsk=atol(value); - if(strcmp(name,"SERIAL_MODEM_GPICLK")==0) - mac_bi_data.serialgpi=atol(value); - if(strcmp(name,"SERIAL_PRINT_FLAGS")==0) - mac_bi_data.printmf=atol(value); - if(strcmp(name,"SERIAL_PRINT_HSKICLK")==0) - mac_bi_data.printhsk=atol(value); - if(strcmp(name,"SERIAL_PRINT_GPICLK")==0) - mac_bi_data.printgpi=atol(value); - if(strcmp(name,"PROCESSOR")==0) - mac_bi_data.cpuid=atol(value); - if(strcmp(name,"ROMBASE")==0) - mac_bi_data.rombase=atol(value); - if(strcmp(name,"TIMEDBRA")==0) - mac_bi_data.timedbra=atol(value); - if(strcmp(name,"ADBDELAY")==0) - mac_bi_data.adbdelay=atol(value); - } -#if 0 /* XXX: TODO with m68k_mach_* */ - /* Fill in the base stuff */ - boot_info.machtype=MACH_MAC; - /* Read this from the macinfo we got ! */ -/* boot_info.cputype=CPU_68020|FPUB_68881;*/ -/* boot_info.memory[0].addr=0;*/ -/* boot_info.memory[0].size=((mac_bi_data.id>>7)&31)<<20;*/ - boot_info.num_memory=1; /* On a MacII */ - boot_info.ramdisk_size=0; /* For now */ - *boot_info.command_line=0; -#endif - } - - -void print_booter(char *env) -{ - char *name; - char *value; - while(*env) - { - name=env; - value=name; - while(*value!='='&&*value) - value++; - if(*value=='=') - *value++=0; - env=value; - while(*env) - env++; - env++; - printk("%s=%s\n", name,value); - } - } - - diff --git a/arch/m68k/mac/config.c b/arch/m68k/mac/config.c index ad3e3bacae39..c45e18449f32 100644 --- a/arch/m68k/mac/config.c +++ b/arch/m68k/mac/config.c @@ -46,7 +46,6 @@ /* Mac bootinfo struct */ struct mac_booter_data mac_bi_data; -int mac_bisize = sizeof mac_bi_data; /* New m68k bootinfo stuff and videobase */ @@ -55,10 +54,8 @@ extern struct mem_info m68k_memory[NUM_MEMINFO]; extern struct mem_info m68k_ramdisk; -void *mac_env; /* Loaded by the boot asm */ - /* The phys. video addr. - might be bogus on some machines */ -unsigned long mac_orig_videoaddr; +static unsigned long mac_orig_videoaddr; /* Mac specific timer functions */ extern unsigned long mac_gettimeoffset(void); @@ -79,6 +76,8 @@ extern void mac_mksound(unsigned int, unsigned int); extern void nubus_sweep_video(void); static void mac_get_model(char *str); +static void mac_identify(void); +static void mac_report_hardware(void); static void __init mac_sched_init(irq_handler_t vector) { @@ -765,7 +764,7 @@ static struct mac_model mac_data_table[] = { } }; -void __init mac_identify(void) +static void __init mac_identify(void) { struct mac_model *m; @@ -821,7 +820,7 @@ void __init mac_identify(void) baboon_init(); } -void __init mac_report_hardware(void) +static void __init mac_report_hardware(void) { printk(KERN_INFO "Apple Macintosh %s\n", macintosh_config->name); } diff --git a/arch/m68k/mac/debug.c b/arch/m68k/mac/debug.c index e8a57138b4a6..2165740786a5 100644 --- a/arch/m68k/mac/debug.c +++ b/arch/m68k/mac/debug.c @@ -51,6 +51,8 @@ extern void mac_serial_print(const char *); static int peng, line; #endif +#if 0 + void mac_debugging_short(int pos, short num) { #ifdef DEBUG_SCREEN @@ -125,6 +127,8 @@ void mac_debugging_long(int pos, long addr) #endif } +#endif /* 0 */ + #ifdef DEBUG_SERIAL /* * TODO: serial debug code @@ -142,12 +146,6 @@ struct mac_SCC { # define scc (*((volatile struct mac_SCC*)mac_bi_data.sccbase)) -/* Flag that serial port is already initialized and used */ -int mac_SCC_init_done; -/* Can be set somewhere, if a SCC master reset has already be done and should - * not be repeated; used by kgdb */ -int mac_SCC_reset_done; - static int scc_port = -1; static struct console mac_console_driver = { @@ -171,8 +169,8 @@ static struct console mac_console_driver = { * this driver if Mac. */ -void mac_debug_console_write(struct console *co, const char *str, - unsigned int count) +static void mac_debug_console_write(struct console *co, const char *str, + unsigned int count) { mac_serial_print(str); } @@ -209,8 +207,8 @@ static inline void mac_scca_out(char c) scc.cha_a_data = c; } -void mac_sccb_console_write(struct console *co, const char *str, - unsigned int count) +static void mac_sccb_console_write(struct console *co, const char *str, + unsigned int count) { while (count--) { if (*str == '\n') @@ -219,8 +217,8 @@ void mac_sccb_console_write(struct console *co, const char *str, } } -void mac_scca_console_write(struct console *co, const char *str, - unsigned int count) +static void mac_scca_console_write(struct console *co, const char *str, + unsigned int count) { while (count--) { if (*str == '\n') @@ -265,14 +263,8 @@ void mac_scca_console_write(struct console *co, const char *str, barrier(); \ } while(0) -#ifndef CONFIG_SERIAL_CONSOLE static void __init mac_init_scc_port(int cflag, int port) -#else -void mac_init_scc_port(int cflag, int port) -#endif { - extern int mac_SCC_reset_done; - /* * baud rates: 1200, 1800, 2400, 4800, 9600, 19.2k, 38.4k, 57.6k, 115.2k */ @@ -340,22 +332,9 @@ void mac_init_scc_port(int cflag, int port) SCCA_WRITE(3, reg3 | 1); SCCA_WRITE(5, reg5 | 8); } - - mac_SCC_reset_done = 1; - mac_SCC_init_done = 1; } #endif /* DEBUG_SERIAL */ -void mac_init_scca_port(int cflag) -{ - mac_init_scc_port(cflag, 0); -} - -void mac_init_sccb_port(int cflag) -{ - mac_init_scc_port(cflag, 1); -} - static int __init mac_debug_setup(char *arg) { if (!MACH_IS_MAC) diff --git a/arch/m68k/mac/oss.c b/arch/m68k/mac/oss.c index 3c943d2ec570..43d83e054b8e 100644 --- a/arch/m68k/mac/oss.c +++ b/arch/m68k/mac/oss.c @@ -30,8 +30,8 @@ int oss_present; volatile struct mac_oss *oss; -irqreturn_t oss_irq(int, void *); -irqreturn_t oss_nubus_irq(int, void *); +static irqreturn_t oss_irq(int, void *); +static irqreturn_t oss_nubus_irq(int, void *); extern irqreturn_t via1_irq(int, void *); extern irqreturn_t mac_scc_dispatch(int, void *); @@ -92,7 +92,7 @@ void __init oss_nubus_init(void) * and SCSI; everything else is routed to its own autovector IRQ. */ -irqreturn_t oss_irq(int irq, void *dev_id) +static irqreturn_t oss_irq(int irq, void *dev_id) { int events; @@ -126,7 +126,7 @@ irqreturn_t oss_irq(int irq, void *dev_id) * Unlike the VIA/RBV this is on its own autovector interrupt level. */ -irqreturn_t oss_nubus_irq(int irq, void *dev_id) +static irqreturn_t oss_nubus_irq(int irq, void *dev_id) { int events, irq_bit, i; diff --git a/arch/m68k/mac/psc.c b/arch/m68k/mac/psc.c index d66f723b17c3..f84a4dd64f94 100644 --- a/arch/m68k/mac/psc.c +++ b/arch/m68k/mac/psc.c @@ -36,7 +36,7 @@ irqreturn_t psc_irq(int, void *); * Debugging dump, used in various places to see what's going on. */ -void psc_debug_dump(void) +static void psc_debug_dump(void) { int i; @@ -55,7 +55,7 @@ void psc_debug_dump(void) * expanded to cover what I think are the other 7 channels. */ -void psc_dma_die_die_die(void) +static void psc_dma_die_die_die(void) { int i; diff --git a/arch/m68k/mac/via.c b/arch/m68k/mac/via.c index fa485df4160e..f3b27d04a31f 100644 --- a/arch/m68k/mac/via.c +++ b/arch/m68k/mac/via.c @@ -45,7 +45,7 @@ volatile long *via_memory_bogon=(long *)&via_memory_bogon; int rbv_present; int via_alt_mapping; EXPORT_SYMBOL(via_alt_mapping); -__u8 rbv_clear; +static __u8 rbv_clear; /* * Globals for accessing the VIA chip registers without having to diff --git a/arch/m68k/math-emu/Makefile b/arch/m68k/math-emu/Makefile index 539940401814..a0935bf98362 100644 --- a/arch/m68k/math-emu/Makefile +++ b/arch/m68k/math-emu/Makefile @@ -2,8 +2,6 @@ # Makefile for the linux kernel. # -EXTRA_AFLAGS := -traditional - #EXTRA_AFLAGS += -DFPU_EMU_DEBUG #EXTRA_CFLAGS += -DFPU_EMU_DEBUG diff --git a/arch/m68k/mm/motorola.c b/arch/m68k/mm/motorola.c index 30d34f285024..226795bdf355 100644 --- a/arch/m68k/mm/motorola.c +++ b/arch/m68k/mm/motorola.c @@ -285,7 +285,6 @@ void __init paging_init(void) * to a couple of allocated pages */ empty_zero_page = alloc_bootmem_pages(PAGE_SIZE); - memset(empty_zero_page, 0, PAGE_SIZE); /* * Set up SFC/DFC registers diff --git a/arch/m68k/mm/sun3mmu.c b/arch/m68k/mm/sun3mmu.c index 6a6513aa1ce8..edceefc18870 100644 --- a/arch/m68k/mm/sun3mmu.c +++ b/arch/m68k/mm/sun3mmu.c @@ -53,7 +53,6 @@ void __init paging_init(void) wp_works_ok = 0; #endif empty_zero_page = alloc_bootmem_pages(PAGE_SIZE); - memset(empty_zero_page, 0, PAGE_SIZE); address = PAGE_OFFSET; pg_dir = swapper_pg_dir; diff --git a/arch/m68k/q40/config.c b/arch/m68k/q40/config.c index 476e18eca758..be9de2f3dc48 100644 --- a/arch/m68k/q40/config.c +++ b/arch/m68k/q40/config.c @@ -41,14 +41,12 @@ static void q40_get_model(char *model); static int q40_get_hardware_list(char *buffer); extern void q40_sched_init(irq_handler_t handler); -extern unsigned long q40_gettimeoffset(void); -extern int q40_hwclk(int, struct rtc_time *); -extern unsigned int q40_get_ss(void); -extern int q40_set_clock_mmss(unsigned long); +static unsigned long q40_gettimeoffset(void); +static int q40_hwclk(int, struct rtc_time *); +static unsigned int q40_get_ss(void); +static int q40_set_clock_mmss(unsigned long); static int q40_get_rtc_pll(struct rtc_pll_info *pll); static int q40_set_rtc_pll(struct rtc_pll_info *pll); -extern void q40_reset(void); -void q40_halt(void); extern void q40_waitbut(void); void q40_set_vectors(void); @@ -127,7 +125,7 @@ static void q40_heartbeat(int on) } #endif -void q40_reset(void) +static void q40_reset(void) { halted = 1; printk("\n\n*******************************************\n" @@ -137,7 +135,8 @@ void q40_reset(void) while (1) ; } -void q40_halt(void) + +static void q40_halt(void) { halted = 1; printk("\n\n*******************\n" @@ -165,7 +164,8 @@ static unsigned int serports[] = { 0x3f8,0x2f8,0x3e8,0x2e8,0 }; -void q40_disable_irqs(void) + +static void q40_disable_irqs(void) { unsigned i, j; @@ -227,7 +227,7 @@ static inline unsigned char bin2bcd(unsigned char b) } -unsigned long q40_gettimeoffset(void) +static unsigned long q40_gettimeoffset(void) { return 5000 * (ql_ticks != 0); } @@ -248,7 +248,7 @@ unsigned long q40_gettimeoffset(void) * }; */ -int q40_hwclk(int op, struct rtc_time *t) +static int q40_hwclk(int op, struct rtc_time *t) { if (op) { /* Write.... */ @@ -285,7 +285,7 @@ int q40_hwclk(int op, struct rtc_time *t) return 0; } -unsigned int q40_get_ss(void) +static unsigned int q40_get_ss(void) { return bcd2bin(Q40_RTC_SECS); } @@ -295,7 +295,7 @@ unsigned int q40_get_ss(void) * clock is out by > 30 minutes. Logic lifted from atari code. */ -int q40_set_clock_mmss(unsigned long nowtime) +static int q40_set_clock_mmss(unsigned long nowtime) { int retval = 0; short real_seconds = nowtime % 60, real_minutes = (nowtime / 60) % 60; diff --git a/arch/m68k/sun3/Makefile b/arch/m68k/sun3/Makefile index be1a8470d636..38ba0e0cedad 100644 --- a/arch/m68k/sun3/Makefile +++ b/arch/m68k/sun3/Makefile @@ -2,6 +2,6 @@ # Makefile for Linux arch/m68k/sun3 source directory # -obj-y := sun3ints.o sun3dvma.o sbus.o idprom.o +obj-y := sun3ints.o sun3dvma.o idprom.o obj-$(CONFIG_SUN3) += config.o mmu_emu.o leds.o dvma.o intersil.o diff --git a/arch/m68k/sun3/config.c b/arch/m68k/sun3/config.c index c0fbd278fbb1..732087d0735c 100644 --- a/arch/m68k/sun3/config.c +++ b/arch/m68k/sun3/config.c @@ -36,7 +36,7 @@ extern char _text, _end; char sun3_reserved_pmeg[SUN3_PMEGS_NUM]; extern unsigned long sun3_gettimeoffset(void); -extern void sun3_sched_init(irq_handler_t handler); +static void sun3_sched_init(irq_handler_t handler); extern void sun3_get_model (char* model); extern void idprom_init (void); extern int sun3_hwclk(int set, struct rtc_time *t); @@ -114,7 +114,8 @@ static void sun3_halt (void) /* sun3 bootmem allocation */ -void __init sun3_bootmem_alloc(unsigned long memory_start, unsigned long memory_end) +static void __init sun3_bootmem_alloc(unsigned long memory_start, + unsigned long memory_end) { unsigned long start_page; @@ -164,7 +165,7 @@ void __init config_sun3(void) sun3_bootmem_alloc(memory_start, memory_end); } -void __init sun3_sched_init(irq_handler_t timer_routine) +static void __init sun3_sched_init(irq_handler_t timer_routine) { sun3_disable_interrupts(); intersil_clock->cmd_reg=(INTERSIL_RUN|INTERSIL_INT_DISABLE|INTERSIL_24H_MODE); diff --git a/arch/m68k/sun3/dvma.c b/arch/m68k/sun3/dvma.c index d2b3093f2405..d522eaab4551 100644 --- a/arch/m68k/sun3/dvma.c +++ b/arch/m68k/sun3/dvma.c @@ -19,7 +19,7 @@ static unsigned long ptelist[120]; -inline unsigned long dvma_page(unsigned long kaddr, unsigned long vaddr) +static unsigned long dvma_page(unsigned long kaddr, unsigned long vaddr) { unsigned long pte; unsigned long j; diff --git a/arch/m68k/sun3/idprom.c b/arch/m68k/sun3/idprom.c index dca6ab6a4ede..c86ac37d1983 100644 --- a/arch/m68k/sun3/idprom.c +++ b/arch/m68k/sun3/idprom.c @@ -1,4 +1,4 @@ -/* $Id: idprom.c,v 1.22 1996/11/13 05:09:25 davem Exp $ +/* * idprom.c: Routines to load the idprom into kernel addresses and * interpret the data contained within. * @@ -25,7 +25,7 @@ static struct idprom idprom_buffer; * of the Sparc CPU and have a meaningful IDPROM machtype value that we * know about. See asm-sparc/machines.h for empirical constants. */ -struct Sun_Machine_Models Sun_Machines[NUM_SUN_MACHINES] = { +static struct Sun_Machine_Models Sun_Machines[NUM_SUN_MACHINES] = { /* First, Sun3's */ { .name = "Sun 3/160 Series", .id_machtype = (SM_SUN3 | SM_3_160) }, { .name = "Sun 3/50", .id_machtype = (SM_SUN3 | SM_3_50) }, diff --git a/arch/m68k/sun3/mmu_emu.c b/arch/m68k/sun3/mmu_emu.c index fb0f6a20cc3c..60f9d4500d72 100644 --- a/arch/m68k/sun3/mmu_emu.c +++ b/arch/m68k/sun3/mmu_emu.c @@ -55,7 +55,7 @@ unsigned char pmeg_ctx[PMEGS_NUM]; /* pointers to the mm structs for each task in each context. 0xffffffff is a marker for kernel context */ -struct mm_struct *ctx_alloc[CONTEXTS_NUM] = { +static struct mm_struct *ctx_alloc[CONTEXTS_NUM] = { [0] = (struct mm_struct *)0xffffffff }; diff --git a/arch/m68k/sun3/prom/Makefile b/arch/m68k/sun3/prom/Makefile index 6e48ae2a7175..da7eac06bca0 100644 --- a/arch/m68k/sun3/prom/Makefile +++ b/arch/m68k/sun3/prom/Makefile @@ -1,4 +1,3 @@ -# $Id: Makefile,v 1.5 1995/11/25 00:59:48 davem Exp $ # Makefile for the Sun Boot PROM interface library under # Linux. # diff --git a/arch/m68k/sun3/prom/console.c b/arch/m68k/sun3/prom/console.c index 52c1427863de..2bcb6e4bfe54 100644 --- a/arch/m68k/sun3/prom/console.c +++ b/arch/m68k/sun3/prom/console.c @@ -1,4 +1,4 @@ -/* $Id: console.c,v 1.10 1996/12/18 06:46:54 tridge Exp $ +/* * console.c: Routines that deal with sending and receiving IO * to/from the current console device using the PROM. * @@ -104,8 +104,6 @@ prom_query_input_device() return PROMDEV_ITTYB; } return PROMDEV_I_UNK; - case PROM_AP1000: - return PROMDEV_I_UNK; }; } #endif @@ -166,8 +164,6 @@ prom_query_output_device() }; } break; - case PROM_AP1000: - return PROMDEV_I_UNK; }; return PROMDEV_O_UNK; } diff --git a/arch/m68k/sun3/prom/init.c b/arch/m68k/sun3/prom/init.c index 202adfcc316e..d8e6349336b4 100644 --- a/arch/m68k/sun3/prom/init.c +++ b/arch/m68k/sun3/prom/init.c @@ -1,4 +1,4 @@ -/* $Id: init.c,v 1.9 1996/12/18 06:46:55 tridge Exp $ +/* * init.c: Initialize internal variables used by the PROM * library functions. * @@ -31,11 +31,6 @@ extern void prom_ranges_init(void); void __init prom_init(struct linux_romvec *rp) { -#ifdef CONFIG_AP1000 - extern struct linux_romvec *ap_prom_init(void); - rp = ap_prom_init(); -#endif - romvec = rp; #ifndef CONFIG_SUN3 switch(romvec->pv_romvers) { @@ -53,10 +48,6 @@ void __init prom_init(struct linux_romvec *rp) prom_printf("PROMLIB: Sun IEEE Prom not supported yet\n"); prom_halt(); break; - case 42: /* why not :-) */ - prom_vers = PROM_AP1000; - break; - default: prom_printf("PROMLIB: Bad PROM version %d\n", romvec->pv_romvers); diff --git a/arch/m68k/sun3/prom/misc.c b/arch/m68k/sun3/prom/misc.c index b88716f2c68c..3d60e1337f75 100644 --- a/arch/m68k/sun3/prom/misc.c +++ b/arch/m68k/sun3/prom/misc.c @@ -1,4 +1,4 @@ -/* $Id: misc.c,v 1.15 1997/05/14 20:45:00 davem Exp $ +/* * misc.c: Miscellaneous prom functions that don't belong * anywhere else. * diff --git a/arch/m68k/sun3/prom/printf.c b/arch/m68k/sun3/prom/printf.c index e7bfde377b5e..df85018f487a 100644 --- a/arch/m68k/sun3/prom/printf.c +++ b/arch/m68k/sun3/prom/printf.c @@ -1,4 +1,4 @@ -/* $Id: printf.c,v 1.5 1996/04/04 16:31:07 tridge Exp $ +/* * printf.c: Internal prom library printf facility. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -37,10 +37,6 @@ prom_printf(char *fmt, ...) bptr = ppbuf; -#ifdef CONFIG_AP1000 - ap_write(1,bptr,strlen(bptr)); -#else - #ifdef CONFIG_KGDB if (kgdb_initialized) { printk("kgdb_initialized = %d\n", kgdb_initialized); @@ -54,7 +50,6 @@ prom_printf(char *fmt, ...) prom_putchar(ch); } #endif -#endif va_end(args); return; } diff --git a/arch/m68k/sun3/sbus.c b/arch/m68k/sun3/sbus.c deleted file mode 100644 index babdbfa3cda7..000000000000 --- a/arch/m68k/sun3/sbus.c +++ /dev/null @@ -1,27 +0,0 @@ -/* - * SBus helper functions - * - * Sun3 don't have a sbus, but many of the used devices are also - * used on Sparc machines with sbus. To avoid having a lot of - * duplicate code, we provide necessary glue stuff to make using - * of the sbus driver code possible. - * - * (C) 1999 Thomas Bogendoerfer (tsbogend@alpha.franken.de) - */ - -#include <linux/types.h> -#include <linux/compiler.h> -#include <linux/init.h> - -int __init sbus_init(void) -{ - return 0; -} - -void *sparc_alloc_io (u32 address, void *virtual, int len, char *name, - u32 bus_type, int rdonly) -{ - return (void *)address; -} - -subsys_initcall(sbus_init); diff --git a/arch/m68k/sun3/sun3dvma.c b/arch/m68k/sun3/sun3dvma.c index 8709677fa025..f9277e8b4159 100644 --- a/arch/m68k/sun3/sun3dvma.c +++ b/arch/m68k/sun3/sun3dvma.c @@ -29,7 +29,7 @@ static inline void dvma_unmap_iommu(unsigned long a, int b) extern void sun3_dvma_init(void); #endif -unsigned long iommu_use[IOMMU_TOTAL_ENTRIES]; +static unsigned long iommu_use[IOMMU_TOTAL_ENTRIES]; #define dvma_index(baddr) ((baddr - DVMA_START) >> DVMA_PAGE_SHIFT) diff --git a/arch/m68k/sun3/sun3ints.c b/arch/m68k/sun3/sun3ints.c index cf93481adb1d..7364cd67455e 100644 --- a/arch/m68k/sun3/sun3ints.c +++ b/arch/m68k/sun3/sun3ints.c @@ -30,7 +30,7 @@ void sun3_enable_interrupts(void) sun3_enable_irq(0); } -int led_pattern[8] = { +static int led_pattern[8] = { ~(0x80), ~(0x01), ~(0x40), ~(0x02), ~(0x20), ~(0x04), diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index d21df5f1b1f3..b9c754f4070c 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -330,6 +330,7 @@ config SGI_IP22 select SGI_HAS_DS1286 select SGI_HAS_I8042 select SGI_HAS_INDYDOG + select SGI_HAS_HAL2 select SGI_HAS_SEEQ select SGI_HAS_WD93 select SGI_HAS_ZILOG @@ -386,7 +387,6 @@ config SGI_IP28 select SGI_HAS_I8042 select SGI_HAS_INDYDOG select SGI_HAS_HAL2 - select SGI_HAS_HAL2 select SGI_HAS_SEEQ select SGI_HAS_WD93 select SGI_HAS_ZILOG @@ -558,6 +558,24 @@ config MACH_TX39XX config MACH_TX49XX bool "Toshiba TX49 series based machines" +config MIKROTIK_RB532 + bool "Mikrotik RB532 boards" + select CEVT_R4K + select CSRC_R4K + select DMA_NONCOHERENT + select GENERIC_HARDIRQS_NO__DO_IRQ + select HW_HAS_PCI + select IRQ_CPU + select SYS_HAS_CPU_MIPS32_R1 + select SYS_SUPPORTS_32BIT_KERNEL + select SYS_SUPPORTS_LITTLE_ENDIAN + select SWAP_IO_SPACE + select BOOT_RAW + select GENERIC_GPIO + help + Support the Mikrotik(tm) RouterBoard 532 series, + based on the IDT RC32434 SoC. + config WR_PPMC bool "Wind River PPMC board" select CEVT_R4K @@ -899,7 +917,7 @@ config BOOT_ELF32 config MIPS_L1_CACHE_SHIFT int - default "4" if MACH_DECSTATION + default "4" if MACH_DECSTATION || MIKROTIK_RB532 default "7" if SGI_IP22 || SGI_IP27 || SGI_IP28 || SNI_RM default "4" if PMC_MSP4200_EVAL default "5" diff --git a/arch/mips/Makefile b/arch/mips/Makefile index 356453322b49..9aab51caf16a 100644 --- a/arch/mips/Makefile +++ b/arch/mips/Makefile @@ -560,6 +560,13 @@ load-$(CONFIG_MACH_TX49XX) += 0xffffffff80100000 core-$(CONFIG_TOSHIBA_JMR3927) += arch/mips/txx9/jmr3927/ # +# Routerboard 532 board +# +core-$(CONFIG_MIKROTIK_RB532) += arch/mips/rb532/ +cflags-$(CONFIG_MIKROTIK_RB532) += -Iinclude/asm-mips/mach-rc32434 +load-$(CONFIG_MIKROTIK_RB532) += 0xffffffff80101000 + +# # Toshiba RBTX4927 board or # Toshiba RBTX4937 board # diff --git a/arch/mips/cobalt/setup.c b/arch/mips/cobalt/setup.c index dd23beb8604f..b51644227241 100644 --- a/arch/mips/cobalt/setup.c +++ b/arch/mips/cobalt/setup.c @@ -81,8 +81,8 @@ void __init plat_mem_setup(void) set_io_port_base(CKSEG1ADDR(GT_DEF_PCI0_IO_BASE)); - /* I/O port resource must include LCD/buttons */ - ioport_resource.end = 0x0fffffff; + /* I/O port resource */ + ioport_resource.end = 0x01ffffff; /* These resources have been reserved by VIA SuperI/O chip. */ for (i = 0; i < ARRAY_SIZE(cobalt_reserved_resources); i++) diff --git a/arch/mips/configs/rb532_defconfig b/arch/mips/configs/rb532_defconfig new file mode 100644 index 000000000000..f28dc32974e5 --- /dev/null +++ b/arch/mips/configs/rb532_defconfig @@ -0,0 +1,1314 @@ +# +# Automatically generated make config: don't edit +# Linux kernel version: 2.6.25 +# Mon Apr 28 12:24:17 2008 +# +CONFIG_MIPS=y + +# +# Machine selection +# +# CONFIG_MACH_ALCHEMY is not set +# CONFIG_BASLER_EXCITE is not set +# CONFIG_BCM47XX is not set +# CONFIG_MIPS_COBALT is not set +# CONFIG_MACH_DECSTATION is not set +# CONFIG_MACH_JAZZ is not set +# CONFIG_LASAT is not set +# CONFIG_LEMOTE_FULONG is not set +# CONFIG_MIPS_ATLAS is not set +# CONFIG_MIPS_MALTA is not set +# CONFIG_MIPS_SEAD is not set +# CONFIG_MIPS_SIM is not set +# CONFIG_MARKEINS is not set +# CONFIG_MACH_VR41XX is not set +# CONFIG_PNX8550_JBS is not set +# CONFIG_PNX8550_STB810 is not set +# CONFIG_PMC_MSP is not set +# CONFIG_PMC_YOSEMITE is not set +# CONFIG_SGI_IP22 is not set +# CONFIG_SGI_IP27 is not set +# CONFIG_SGI_IP28 is not set +# CONFIG_SGI_IP32 is not set +# CONFIG_SIBYTE_CRHINE is not set +# CONFIG_SIBYTE_CARMEL is not set +# CONFIG_SIBYTE_CRHONE is not set +# CONFIG_SIBYTE_RHONE is not set +# CONFIG_SIBYTE_SWARM is not set +# CONFIG_SIBYTE_LITTLESUR is not set +# CONFIG_SIBYTE_SENTOSA is not set +# CONFIG_SIBYTE_BIGSUR is not set +# CONFIG_SNI_RM is not set +# CONFIG_TOSHIBA_JMR3927 is not set +CONFIG_MIKROTIK_RB532=y +# CONFIG_TOSHIBA_RBTX4927 is not set +# CONFIG_TOSHIBA_RBTX4938 is not set +# CONFIG_WR_PPMC is not set +CONFIG_RWSEM_GENERIC_SPINLOCK=y +# CONFIG_ARCH_HAS_ILOG2_U32 is not set +# CONFIG_ARCH_HAS_ILOG2_U64 is not set +CONFIG_ARCH_SUPPORTS_OPROFILE=y +CONFIG_GENERIC_FIND_NEXT_BIT=y +CONFIG_GENERIC_HWEIGHT=y +CONFIG_GENERIC_CALIBRATE_DELAY=y +CONFIG_GENERIC_CLOCKEVENTS=y +CONFIG_GENERIC_TIME=y +CONFIG_GENERIC_CMOS_UPDATE=y +CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y +CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y +CONFIG_BOOT_RAW=y +CONFIG_CEVT_R4K=y +CONFIG_CSRC_R4K=y +CONFIG_DMA_NONCOHERENT=y +CONFIG_DMA_NEED_PCI_MAP_STATE=y +# CONFIG_HOTPLUG_CPU is not set +# CONFIG_NO_IOPORT is not set +CONFIG_GENERIC_GPIO=y +# CONFIG_CPU_BIG_ENDIAN is not set +CONFIG_CPU_LITTLE_ENDIAN=y +CONFIG_SYS_SUPPORTS_LITTLE_ENDIAN=y +CONFIG_IRQ_CPU=y +CONFIG_SWAP_IO_SPACE=y +CONFIG_MIPS_L1_CACHE_SHIFT=4 + +# +# CPU selection +# +# CONFIG_CPU_LOONGSON2 is not set +CONFIG_CPU_MIPS32_R1=y +# CONFIG_CPU_MIPS32_R2 is not set +# CONFIG_CPU_MIPS64_R1 is not set +# CONFIG_CPU_MIPS64_R2 is not set +# CONFIG_CPU_R3000 is not set +# CONFIG_CPU_TX39XX is not set +# CONFIG_CPU_VR41XX is not set +# CONFIG_CPU_R4300 is not set +# CONFIG_CPU_R4X00 is not set +# CONFIG_CPU_TX49XX is not set +# CONFIG_CPU_R5000 is not set +# CONFIG_CPU_R5432 is not set +# CONFIG_CPU_R6000 is not set +# CONFIG_CPU_NEVADA is not set +# CONFIG_CPU_R8000 is not set +# CONFIG_CPU_R10000 is not set +# CONFIG_CPU_RM7000 is not set +# CONFIG_CPU_RM9000 is not set +# CONFIG_CPU_SB1 is not set +CONFIG_SYS_HAS_CPU_MIPS32_R1=y +CONFIG_CPU_MIPS32=y +CONFIG_CPU_MIPSR1=y +CONFIG_SYS_SUPPORTS_32BIT_KERNEL=y +CONFIG_CPU_SUPPORTS_32BIT_KERNEL=y + +# +# Kernel type +# +CONFIG_32BIT=y +# CONFIG_64BIT is not set +CONFIG_PAGE_SIZE_4KB=y +# CONFIG_PAGE_SIZE_8KB is not set +# CONFIG_PAGE_SIZE_16KB is not set +# CONFIG_PAGE_SIZE_64KB is not set +CONFIG_CPU_HAS_PREFETCH=y +CONFIG_MIPS_MT_DISABLED=y +# CONFIG_MIPS_MT_SMP is not set +# CONFIG_MIPS_MT_SMTC is not set +CONFIG_CPU_HAS_LLSC=y +CONFIG_CPU_HAS_SYNC=y +CONFIG_GENERIC_HARDIRQS=y +CONFIG_GENERIC_IRQ_PROBE=y +CONFIG_CPU_SUPPORTS_HIGHMEM=y +CONFIG_ARCH_FLATMEM_ENABLE=y +CONFIG_ARCH_POPULATES_NODE_MAP=y +CONFIG_SELECT_MEMORY_MODEL=y +CONFIG_FLATMEM_MANUAL=y +# CONFIG_DISCONTIGMEM_MANUAL is not set +# CONFIG_SPARSEMEM_MANUAL is not set +CONFIG_FLATMEM=y +CONFIG_FLAT_NODE_MEM_MAP=y +# CONFIG_SPARSEMEM_STATIC is not set +# CONFIG_SPARSEMEM_VMEMMAP_ENABLE is not set +CONFIG_SPLIT_PTLOCK_CPUS=4 +# CONFIG_RESOURCES_64BIT is not set +CONFIG_ZONE_DMA_FLAG=0 +CONFIG_VIRT_TO_BUS=y +CONFIG_TICK_ONESHOT=y +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y +CONFIG_GENERIC_CLOCKEVENTS_BUILD=y +# CONFIG_HZ_48 is not set +CONFIG_HZ_100=y +# CONFIG_HZ_128 is not set +# CONFIG_HZ_250 is not set +# CONFIG_HZ_256 is not set +# CONFIG_HZ_1000 is not set +# CONFIG_HZ_1024 is not set +CONFIG_SYS_SUPPORTS_ARBIT_HZ=y +CONFIG_HZ=100 +CONFIG_PREEMPT_NONE=y +# CONFIG_PREEMPT_VOLUNTARY is not set +# CONFIG_PREEMPT is not set +# CONFIG_KEXEC is not set +# CONFIG_SECCOMP is not set +CONFIG_LOCKDEP_SUPPORT=y +CONFIG_STACKTRACE_SUPPORT=y +CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" + +# +# General setup +# +CONFIG_EXPERIMENTAL=y +CONFIG_BROKEN_ON_SMP=y +CONFIG_INIT_ENV_ARG_LIMIT=32 +CONFIG_LOCALVERSION="" +# CONFIG_LOCALVERSION_AUTO is not set +CONFIG_SWAP=y +CONFIG_SYSVIPC=y +CONFIG_SYSVIPC_SYSCTL=y +# CONFIG_POSIX_MQUEUE is not set +CONFIG_BSD_PROCESS_ACCT=y +# CONFIG_BSD_PROCESS_ACCT_V3 is not set +# CONFIG_TASKSTATS is not set +# CONFIG_AUDIT is not set +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_LOG_BUF_SHIFT=14 +# CONFIG_CGROUPS is not set +CONFIG_GROUP_SCHED=y +CONFIG_FAIR_GROUP_SCHED=y +# CONFIG_RT_GROUP_SCHED is not set +CONFIG_USER_SCHED=y +# CONFIG_CGROUP_SCHED is not set +CONFIG_SYSFS_DEPRECATED=y +CONFIG_SYSFS_DEPRECATED_V2=y +# CONFIG_RELAY is not set +# CONFIG_NAMESPACES is not set +CONFIG_BLK_DEV_INITRD=y +CONFIG_INITRAMFS_SOURCE="" +CONFIG_CC_OPTIMIZE_FOR_SIZE=y +CONFIG_SYSCTL=y +CONFIG_EMBEDDED=y +CONFIG_SYSCTL_SYSCALL=y +# CONFIG_KALLSYMS is not set +CONFIG_HOTPLUG=y +CONFIG_PRINTK=y +CONFIG_BUG=y +# CONFIG_ELF_CORE is not set +CONFIG_COMPAT_BRK=y +CONFIG_BASE_FULL=y +CONFIG_FUTEX=y +CONFIG_ANON_INODES=y +CONFIG_EPOLL=y +CONFIG_SIGNALFD=y +CONFIG_TIMERFD=y +CONFIG_EVENTFD=y +CONFIG_SHMEM=y +# CONFIG_VM_EVENT_COUNTERS is not set +CONFIG_SLAB=y +# CONFIG_SLUB is not set +# CONFIG_SLOB is not set +# CONFIG_PROFILING is not set +# CONFIG_MARKERS is not set +CONFIG_HAVE_OPROFILE=y +# CONFIG_HAVE_KPROBES is not set +# CONFIG_HAVE_KRETPROBES is not set +CONFIG_PROC_PAGE_MONITOR=y +CONFIG_SLABINFO=y +CONFIG_RT_MUTEXES=y +# CONFIG_TINY_SHMEM is not set +CONFIG_BASE_SMALL=0 +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +# CONFIG_MODULE_FORCE_UNLOAD is not set +# CONFIG_MODVERSIONS is not set +# CONFIG_MODULE_SRCVERSION_ALL is not set +# CONFIG_KMOD is not set +CONFIG_BLOCK=y +# CONFIG_LBD is not set +# CONFIG_BLK_DEV_IO_TRACE is not set +# CONFIG_LSF is not set +# CONFIG_BLK_DEV_BSG is not set + +# +# IO Schedulers +# +CONFIG_IOSCHED_NOOP=y +# CONFIG_IOSCHED_AS is not set +CONFIG_IOSCHED_DEADLINE=y +# CONFIG_IOSCHED_CFQ is not set +# CONFIG_DEFAULT_AS is not set +CONFIG_DEFAULT_DEADLINE=y +# CONFIG_DEFAULT_CFQ is not set +# CONFIG_DEFAULT_NOOP is not set +CONFIG_DEFAULT_IOSCHED="deadline" +CONFIG_CLASSIC_RCU=y + +# +# Bus options (PCI, PCMCIA, EISA, ISA, TC) +# +CONFIG_HW_HAS_PCI=y +CONFIG_PCI=y +CONFIG_PCI_DOMAINS=y +# CONFIG_ARCH_SUPPORTS_MSI is not set +CONFIG_PCI_LEGACY=y +CONFIG_MMU=y +# CONFIG_PCCARD is not set +# CONFIG_HOTPLUG_PCI is not set + +# +# Executable file formats +# +CONFIG_BINFMT_ELF=y +# CONFIG_BINFMT_MISC is not set +CONFIG_TRAD_SIGNALS=y + +# +# Power management options +# +CONFIG_ARCH_SUSPEND_POSSIBLE=y +# CONFIG_PM is not set + +# +# Networking +# +CONFIG_NET=y + +# +# Networking options +# +CONFIG_PACKET=y +CONFIG_PACKET_MMAP=y +CONFIG_UNIX=y +# CONFIG_NET_KEY is not set +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +CONFIG_IP_ADVANCED_ROUTER=y +CONFIG_ASK_IP_FIB_HASH=y +# CONFIG_IP_FIB_TRIE is not set +CONFIG_IP_FIB_HASH=y +CONFIG_IP_MULTIPLE_TABLES=y +CONFIG_IP_ROUTE_MULTIPATH=y +CONFIG_IP_ROUTE_VERBOSE=y +# CONFIG_IP_PNP is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_IP_MROUTE is not set +CONFIG_ARPD=y +CONFIG_SYN_COOKIES=y +# CONFIG_INET_AH is not set +# CONFIG_INET_ESP is not set +# CONFIG_INET_IPCOMP is not set +# CONFIG_INET_XFRM_TUNNEL is not set +# CONFIG_INET_TUNNEL is not set +# CONFIG_INET_XFRM_MODE_TRANSPORT is not set +# CONFIG_INET_XFRM_MODE_TUNNEL is not set +# CONFIG_INET_XFRM_MODE_BEET is not set +# CONFIG_INET_LRO is not set +CONFIG_INET_DIAG=m +CONFIG_INET_TCP_DIAG=m +CONFIG_TCP_CONG_ADVANCED=y +CONFIG_TCP_CONG_BIC=m +CONFIG_TCP_CONG_CUBIC=m +CONFIG_TCP_CONG_WESTWOOD=m +CONFIG_TCP_CONG_HTCP=m +CONFIG_TCP_CONG_HSTCP=m +CONFIG_TCP_CONG_HYBLA=m +CONFIG_TCP_CONG_VEGAS=y +CONFIG_TCP_CONG_SCALABLE=m +CONFIG_TCP_CONG_LP=m +CONFIG_TCP_CONG_VENO=m +CONFIG_TCP_CONG_YEAH=m +CONFIG_TCP_CONG_ILLINOIS=m +# CONFIG_DEFAULT_BIC is not set +# CONFIG_DEFAULT_CUBIC is not set +# CONFIG_DEFAULT_HTCP is not set +CONFIG_DEFAULT_VEGAS=y +# CONFIG_DEFAULT_WESTWOOD is not set +# CONFIG_DEFAULT_RENO is not set +CONFIG_DEFAULT_TCP_CONG="vegas" +# CONFIG_TCP_MD5SIG is not set +# CONFIG_IP_VS is not set +# CONFIG_IPV6 is not set +# CONFIG_NETWORK_SECMARK is not set +CONFIG_NETFILTER=y +# CONFIG_NETFILTER_DEBUG is not set +CONFIG_NETFILTER_ADVANCED=y +# CONFIG_BRIDGE_NETFILTER is not set + +# +# Core Netfilter Configuration +# +# CONFIG_NETFILTER_NETLINK_QUEUE is not set +# CONFIG_NETFILTER_NETLINK_LOG is not set +CONFIG_NF_CONNTRACK=y +CONFIG_NF_CT_ACCT=y +CONFIG_NF_CONNTRACK_MARK=y +# CONFIG_NF_CONNTRACK_EVENTS is not set +# CONFIG_NF_CT_PROTO_DCCP is not set +# CONFIG_NF_CT_PROTO_SCTP is not set +# CONFIG_NF_CT_PROTO_UDPLITE is not set +# CONFIG_NF_CONNTRACK_AMANDA is not set +CONFIG_NF_CONNTRACK_FTP=m +# CONFIG_NF_CONNTRACK_H323 is not set +CONFIG_NF_CONNTRACK_IRC=m +# CONFIG_NF_CONNTRACK_NETBIOS_NS is not set +# CONFIG_NF_CONNTRACK_PPTP is not set +# CONFIG_NF_CONNTRACK_SANE is not set +# CONFIG_NF_CONNTRACK_SIP is not set +CONFIG_NF_CONNTRACK_TFTP=m +# CONFIG_NF_CT_NETLINK is not set +CONFIG_NETFILTER_XTABLES=y +# CONFIG_NETFILTER_XT_TARGET_CLASSIFY is not set +# CONFIG_NETFILTER_XT_TARGET_CONNMARK is not set +# CONFIG_NETFILTER_XT_TARGET_DSCP is not set +# CONFIG_NETFILTER_XT_TARGET_MARK is not set +CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m +CONFIG_NETFILTER_XT_TARGET_NFLOG=m +# CONFIG_NETFILTER_XT_TARGET_NOTRACK is not set +# CONFIG_NETFILTER_XT_TARGET_RATEEST is not set +CONFIG_NETFILTER_XT_TARGET_TRACE=m +# CONFIG_NETFILTER_XT_TARGET_TCPMSS is not set +# CONFIG_NETFILTER_XT_TARGET_TCPOPTSTRIP is not set +CONFIG_NETFILTER_XT_MATCH_COMMENT=m +# CONFIG_NETFILTER_XT_MATCH_CONNBYTES is not set +CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=m +# CONFIG_NETFILTER_XT_MATCH_CONNMARK is not set +# CONFIG_NETFILTER_XT_MATCH_CONNTRACK is not set +CONFIG_NETFILTER_XT_MATCH_DCCP=m +# CONFIG_NETFILTER_XT_MATCH_DSCP is not set +# CONFIG_NETFILTER_XT_MATCH_ESP is not set +# CONFIG_NETFILTER_XT_MATCH_HELPER is not set +# CONFIG_NETFILTER_XT_MATCH_IPRANGE is not set +# CONFIG_NETFILTER_XT_MATCH_LENGTH is not set +CONFIG_NETFILTER_XT_MATCH_LIMIT=y +# CONFIG_NETFILTER_XT_MATCH_MAC is not set +# CONFIG_NETFILTER_XT_MATCH_MARK is not set +# CONFIG_NETFILTER_XT_MATCH_OWNER is not set +CONFIG_NETFILTER_XT_MATCH_MULTIPORT=y +# CONFIG_NETFILTER_XT_MATCH_PKTTYPE is not set +# CONFIG_NETFILTER_XT_MATCH_QUOTA is not set +# CONFIG_NETFILTER_XT_MATCH_RATEEST is not set +CONFIG_NETFILTER_XT_MATCH_REALM=m +CONFIG_NETFILTER_XT_MATCH_SCTP=m +CONFIG_NETFILTER_XT_MATCH_STATE=y +# CONFIG_NETFILTER_XT_MATCH_STATISTIC is not set +# CONFIG_NETFILTER_XT_MATCH_STRING is not set +# CONFIG_NETFILTER_XT_MATCH_TCPMSS is not set +# CONFIG_NETFILTER_XT_MATCH_TIME is not set +CONFIG_NETFILTER_XT_MATCH_U32=m +CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=m + +# +# IP: Netfilter Configuration +# +CONFIG_NF_CONNTRACK_IPV4=y +CONFIG_NF_CONNTRACK_PROC_COMPAT=y +# CONFIG_IP_NF_QUEUE is not set +CONFIG_IP_NF_IPTABLES=y +# CONFIG_IP_NF_MATCH_RECENT is not set +# CONFIG_IP_NF_MATCH_ECN is not set +# CONFIG_IP_NF_MATCH_AH is not set +# CONFIG_IP_NF_MATCH_TTL is not set +CONFIG_IP_NF_MATCH_ADDRTYPE=m +CONFIG_IP_NF_FILTER=y +CONFIG_IP_NF_TARGET_REJECT=y +# CONFIG_IP_NF_TARGET_LOG is not set +# CONFIG_IP_NF_TARGET_ULOG is not set +CONFIG_NF_NAT=y +CONFIG_NF_NAT_NEEDED=y +CONFIG_IP_NF_TARGET_MASQUERADE=y +# CONFIG_IP_NF_TARGET_REDIRECT is not set +# CONFIG_IP_NF_TARGET_NETMAP is not set +# CONFIG_NF_NAT_SNMP_BASIC is not set +CONFIG_NF_NAT_FTP=m +CONFIG_NF_NAT_IRC=m +CONFIG_NF_NAT_TFTP=m +# CONFIG_NF_NAT_AMANDA is not set +# CONFIG_NF_NAT_PPTP is not set +# CONFIG_NF_NAT_H323 is not set +# CONFIG_NF_NAT_SIP is not set +CONFIG_IP_NF_MANGLE=y +# CONFIG_IP_NF_TARGET_ECN is not set +# CONFIG_IP_NF_TARGET_TTL is not set +# CONFIG_IP_NF_TARGET_CLUSTERIP is not set +CONFIG_IP_NF_RAW=m +# CONFIG_IP_NF_ARPTABLES is not set +# CONFIG_IP_DCCP is not set +# CONFIG_IP_SCTP is not set +# CONFIG_TIPC is not set +# CONFIG_ATM is not set +CONFIG_BRIDGE=y +CONFIG_VLAN_8021Q=y +# CONFIG_DECNET is not set +CONFIG_LLC=y +CONFIG_LLC2=m +# CONFIG_IPX is not set +# CONFIG_ATALK is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set +CONFIG_NET_SCHED=y + +# +# Queueing/Scheduling +# +CONFIG_NET_SCH_CBQ=m +# CONFIG_NET_SCH_HTB is not set +# CONFIG_NET_SCH_HFSC is not set +CONFIG_NET_SCH_PRIO=m +CONFIG_NET_SCH_RR=m +# CONFIG_NET_SCH_RED is not set +# CONFIG_NET_SCH_SFQ is not set +# CONFIG_NET_SCH_TEQL is not set +# CONFIG_NET_SCH_TBF is not set +# CONFIG_NET_SCH_GRED is not set +# CONFIG_NET_SCH_DSMARK is not set +CONFIG_NET_SCH_NETEM=m +# CONFIG_NET_SCH_INGRESS is not set + +# +# Classification +# +CONFIG_NET_CLS=y +CONFIG_NET_CLS_BASIC=m +CONFIG_NET_CLS_TCINDEX=m +CONFIG_NET_CLS_ROUTE4=m +CONFIG_NET_CLS_ROUTE=y +CONFIG_NET_CLS_FW=m +CONFIG_NET_CLS_U32=m +CONFIG_CLS_U32_PERF=y +CONFIG_CLS_U32_MARK=y +CONFIG_NET_CLS_RSVP=m +CONFIG_NET_CLS_RSVP6=m +# CONFIG_NET_CLS_FLOW is not set +CONFIG_NET_EMATCH=y +CONFIG_NET_EMATCH_STACK=32 +CONFIG_NET_EMATCH_CMP=m +CONFIG_NET_EMATCH_NBYTE=m +CONFIG_NET_EMATCH_U32=m +CONFIG_NET_EMATCH_META=m +CONFIG_NET_EMATCH_TEXT=m +CONFIG_NET_CLS_ACT=y +CONFIG_NET_ACT_POLICE=y +CONFIG_NET_ACT_GACT=m +CONFIG_GACT_PROB=y +CONFIG_NET_ACT_MIRRED=m +CONFIG_NET_ACT_IPT=m +# CONFIG_NET_ACT_NAT is not set +CONFIG_NET_ACT_PEDIT=m +# CONFIG_NET_ACT_SIMP is not set +CONFIG_NET_CLS_IND=y +CONFIG_NET_SCH_FIFO=y + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set +CONFIG_HAMRADIO=y + +# +# Packet Radio protocols +# +# CONFIG_AX25 is not set +# CONFIG_CAN is not set +# CONFIG_IRDA is not set +# CONFIG_BT is not set +# CONFIG_AF_RXRPC is not set +CONFIG_FIB_RULES=y + +# +# Wireless +# +# CONFIG_CFG80211 is not set +CONFIG_WIRELESS_EXT=y +# CONFIG_MAC80211 is not set +# CONFIG_IEEE80211 is not set +# CONFIG_RFKILL is not set +# CONFIG_NET_9P is not set + +# +# Device Drivers +# + +# +# Generic Driver Options +# +CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" +CONFIG_STANDALONE=y +CONFIG_PREVENT_FIRMWARE_BUILD=y +CONFIG_FW_LOADER=y +# CONFIG_SYS_HYPERVISOR is not set +# CONFIG_CONNECTOR is not set +CONFIG_MTD=y +# CONFIG_MTD_DEBUG is not set +# CONFIG_MTD_CONCAT is not set +CONFIG_MTD_PARTITIONS=y +# CONFIG_MTD_REDBOOT_PARTS is not set +# CONFIG_MTD_CMDLINE_PARTS is not set +# CONFIG_MTD_AR7_PARTS is not set + +# +# User Modules And Translation Layers +# +CONFIG_MTD_CHAR=y +CONFIG_MTD_BLKDEVS=y +CONFIG_MTD_BLOCK=y +# CONFIG_FTL is not set +# CONFIG_NFTL is not set +# CONFIG_INFTL is not set +# CONFIG_RFD_FTL is not set +# CONFIG_SSFDC is not set +# CONFIG_MTD_OOPS is not set + +# +# RAM/ROM/Flash chip drivers +# +# CONFIG_MTD_CFI is not set +# CONFIG_MTD_JEDECPROBE is not set +CONFIG_MTD_MAP_BANK_WIDTH_1=y +CONFIG_MTD_MAP_BANK_WIDTH_2=y +CONFIG_MTD_MAP_BANK_WIDTH_4=y +# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set +# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set +# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set +CONFIG_MTD_CFI_I1=y +CONFIG_MTD_CFI_I2=y +# CONFIG_MTD_CFI_I4 is not set +# CONFIG_MTD_CFI_I8 is not set +# CONFIG_MTD_RAM is not set +# CONFIG_MTD_ROM is not set +# CONFIG_MTD_ABSENT is not set + +# +# Mapping drivers for chip access +# +# CONFIG_MTD_COMPLEX_MAPPINGS is not set +# CONFIG_MTD_INTEL_VR_NOR is not set +# CONFIG_MTD_PLATRAM is not set + +# +# Self-contained MTD device drivers +# +# CONFIG_MTD_PMC551 is not set +# CONFIG_MTD_SLRAM is not set +# CONFIG_MTD_PHRAM is not set +# CONFIG_MTD_MTDRAM is not set +CONFIG_MTD_BLOCK2MTD=y + +# +# Disk-On-Chip Device Drivers +# +# CONFIG_MTD_DOC2000 is not set +# CONFIG_MTD_DOC2001 is not set +# CONFIG_MTD_DOC2001PLUS is not set +CONFIG_MTD_NAND=y +CONFIG_MTD_NAND_VERIFY_WRITE=y +# CONFIG_MTD_NAND_ECC_SMC is not set +# CONFIG_MTD_NAND_MUSEUM_IDS is not set +CONFIG_MTD_NAND_IDS=y +# CONFIG_MTD_NAND_DISKONCHIP is not set +# CONFIG_MTD_NAND_CAFE is not set +# CONFIG_MTD_NAND_NANDSIM is not set +CONFIG_MTD_NAND_PLATFORM=y +# CONFIG_MTD_ONENAND is not set + +# +# UBI - Unsorted block images +# +# CONFIG_MTD_UBI is not set +# CONFIG_PARPORT is not set +CONFIG_BLK_DEV=y +# CONFIG_BLK_CPQ_DA is not set +# CONFIG_BLK_CPQ_CISS_DA is not set +# CONFIG_BLK_DEV_DAC960 is not set +# CONFIG_BLK_DEV_UMEM is not set +# CONFIG_BLK_DEV_COW_COMMON is not set +# CONFIG_BLK_DEV_LOOP is not set +# CONFIG_BLK_DEV_NBD is not set +# CONFIG_BLK_DEV_SX8 is not set +# CONFIG_BLK_DEV_RAM is not set +# CONFIG_CDROM_PKTCDVD is not set +# CONFIG_ATA_OVER_ETH is not set +CONFIG_MISC_DEVICES=y +# CONFIG_PHANTOM is not set +# CONFIG_EEPROM_93CX6 is not set +# CONFIG_SGI_IOC4 is not set +# CONFIG_TIFM_CORE is not set +# CONFIG_ENCLOSURE_SERVICES is not set +CONFIG_HAVE_IDE=y +# CONFIG_IDE is not set + +# +# SCSI device support +# +# CONFIG_RAID_ATTRS is not set +CONFIG_SCSI=y +CONFIG_SCSI_DMA=y +# CONFIG_SCSI_TGT is not set +# CONFIG_SCSI_NETLINK is not set +CONFIG_SCSI_PROC_FS=y + +# +# SCSI support type (disk, tape, CD-ROM) +# +# CONFIG_BLK_DEV_SD is not set +# CONFIG_CHR_DEV_ST is not set +# CONFIG_CHR_DEV_OSST is not set +# CONFIG_BLK_DEV_SR is not set +# CONFIG_CHR_DEV_SG is not set +# CONFIG_CHR_DEV_SCH is not set + +# +# Some SCSI devices (e.g. CD jukebox) support multiple LUNs +# +# CONFIG_SCSI_MULTI_LUN is not set +# CONFIG_SCSI_CONSTANTS is not set +# CONFIG_SCSI_LOGGING is not set +# CONFIG_SCSI_SCAN_ASYNC is not set +CONFIG_SCSI_WAIT_SCAN=m + +# +# SCSI Transports +# +# CONFIG_SCSI_SPI_ATTRS is not set +# CONFIG_SCSI_FC_ATTRS is not set +# CONFIG_SCSI_ISCSI_ATTRS is not set +# CONFIG_SCSI_SAS_LIBSAS is not set +# CONFIG_SCSI_SRP_ATTRS is not set +CONFIG_SCSI_LOWLEVEL=y +# CONFIG_ISCSI_TCP 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 +# CONFIG_SCSI_AACRAID is not set +# CONFIG_SCSI_AIC7XXX is not set +# CONFIG_SCSI_AIC7XXX_OLD is not set +# CONFIG_SCSI_AIC79XX is not set +# CONFIG_SCSI_AIC94XX is not set +# CONFIG_SCSI_DPT_I2O is not set +# CONFIG_SCSI_ADVANSYS is not set +# CONFIG_SCSI_ARCMSR is not set +# CONFIG_MEGARAID_NEWGEN is not set +# CONFIG_MEGARAID_LEGACY is not set +# CONFIG_MEGARAID_SAS is not set +# CONFIG_SCSI_HPTIOP is not set +# CONFIG_SCSI_DMX3191D is not set +# CONFIG_SCSI_FUTURE_DOMAIN is not set +# 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_IPR is not set +# CONFIG_SCSI_QLOGIC_1280 is not set +# CONFIG_SCSI_QLA_FC is not set +# CONFIG_SCSI_QLA_ISCSI is not set +# CONFIG_SCSI_LPFC is not set +# CONFIG_SCSI_DC395x is not set +# CONFIG_SCSI_DC390T is not set +# CONFIG_SCSI_NSP32 is not set +# CONFIG_SCSI_DEBUG is not set +# CONFIG_SCSI_SRP is not set +CONFIG_ATA=y +# CONFIG_ATA_NONSTANDARD is not set +# CONFIG_SATA_PMP is not set +# CONFIG_SATA_AHCI is not set +# CONFIG_SATA_SIL24 is not set +CONFIG_ATA_SFF=y +# CONFIG_SATA_SVW is not set +# CONFIG_ATA_PIIX is not set +# CONFIG_SATA_MV is not set +# CONFIG_SATA_NV is not set +# CONFIG_PDC_ADMA is not set +# CONFIG_SATA_QSTOR is not set +# CONFIG_SATA_PROMISE is not set +# CONFIG_SATA_SX4 is not set +# CONFIG_SATA_SIL is not set +# CONFIG_SATA_SIS is not set +# CONFIG_SATA_ULI is not set +# CONFIG_SATA_VIA is not set +# CONFIG_SATA_VITESSE is not set +# CONFIG_SATA_INIC162X is not set +# CONFIG_PATA_ALI is not set +# CONFIG_PATA_AMD is not set +# CONFIG_PATA_ARTOP is not set +# CONFIG_PATA_ATIIXP is not set +# CONFIG_PATA_CMD640_PCI is not set +# CONFIG_PATA_CMD64X is not set +# CONFIG_PATA_CS5520 is not set +# CONFIG_PATA_CS5530 is not set +# CONFIG_PATA_CYPRESS is not set +# CONFIG_PATA_EFAR is not set +# CONFIG_ATA_GENERIC is not set +# CONFIG_PATA_HPT366 is not set +# CONFIG_PATA_HPT37X is not set +# CONFIG_PATA_HPT3X2N is not set +# CONFIG_PATA_HPT3X3 is not set +# CONFIG_PATA_IT821X is not set +# CONFIG_PATA_IT8213 is not set +# CONFIG_PATA_JMICRON is not set +# CONFIG_PATA_TRIFLEX is not set +# CONFIG_PATA_MARVELL is not set +# CONFIG_PATA_MPIIX is not set +# CONFIG_PATA_OLDPIIX is not set +# CONFIG_PATA_NETCELL is not set +# CONFIG_PATA_NINJA32 is not set +# CONFIG_PATA_NS87410 is not set +# CONFIG_PATA_NS87415 is not set +# CONFIG_PATA_OPTI is not set +# CONFIG_PATA_OPTIDMA is not set +# CONFIG_PATA_PDC_OLD is not set +# CONFIG_PATA_RADISYS is not set +CONFIG_PATA_RB532=y +# CONFIG_PATA_RZ1000 is not set +# CONFIG_PATA_SC1200 is not set +# CONFIG_PATA_SERVERWORKS is not set +# CONFIG_PATA_PDC2027X is not set +# CONFIG_PATA_SIL680 is not set +# CONFIG_PATA_SIS is not set +# CONFIG_PATA_VIA is not set +# CONFIG_PATA_WINBOND is not set +# CONFIG_PATA_PLATFORM is not set +# CONFIG_MD is not set +# CONFIG_FUSION is not set + +# +# IEEE 1394 (FireWire) support +# +# CONFIG_FIREWIRE is not set +# CONFIG_IEEE1394 is not set +# CONFIG_I2O is not set +CONFIG_NETDEVICES=y +# CONFIG_NETDEVICES_MULTIQUEUE is not set +CONFIG_IFB=m +# CONFIG_DUMMY is not set +# CONFIG_BONDING is not set +# CONFIG_MACVLAN is not set +# CONFIG_EQUALIZER is not set +# CONFIG_TUN is not set +# CONFIG_VETH is not set +# CONFIG_ARCNET is not set +# CONFIG_PHYLIB is not set +CONFIG_NET_ETHERNET=y +CONFIG_MII=y +# CONFIG_AX88796 is not set +CONFIG_KORINA=y +# CONFIG_HAPPYMEAL is not set +# CONFIG_SUNGEM is not set +# CONFIG_CASSINI is not set +# CONFIG_NET_VENDOR_3COM is not set +# CONFIG_DM9000 is not set +# CONFIG_NET_TULIP is not set +# CONFIG_HP100 is not set +# CONFIG_IBM_NEW_EMAC_ZMII is not set +# CONFIG_IBM_NEW_EMAC_RGMII is not set +# CONFIG_IBM_NEW_EMAC_TAH is not set +# CONFIG_IBM_NEW_EMAC_EMAC4 is not set +CONFIG_NET_PCI=y +# CONFIG_PCNET32 is not set +# CONFIG_AMD8111_ETH is not set +# CONFIG_ADAPTEC_STARFIRE is not set +# CONFIG_B44 is not set +# CONFIG_FORCEDETH is not set +# CONFIG_TC35815 is not set +# CONFIG_EEPRO100 is not set +# CONFIG_E100 is not set +# CONFIG_FEALNX is not set +# CONFIG_NATSEMI is not set +# CONFIG_NE2K_PCI is not set +# CONFIG_8139CP is not set +# CONFIG_8139TOO is not set +# CONFIG_R6040 is not set +# CONFIG_SIS900 is not set +# CONFIG_EPIC100 is not set +# CONFIG_SUNDANCE is not set +# CONFIG_TLAN is not set +CONFIG_VIA_RHINE=y +# CONFIG_VIA_RHINE_MMIO is not set +CONFIG_VIA_RHINE_NAPI=y +# CONFIG_SC92031 is not set +# CONFIG_NETDEV_1000 is not set +# CONFIG_NETDEV_10000 is not set +# CONFIG_TR is not set + +# +# Wireless LAN +# +# CONFIG_WLAN_PRE80211 is not set +CONFIG_WLAN_80211=y +# CONFIG_IPW2100 is not set +# CONFIG_IPW2200 is not set +# CONFIG_LIBERTAS is not set +# CONFIG_HERMES is not set +CONFIG_ATMEL=m +# CONFIG_PCI_ATMEL is not set +# CONFIG_PRISM54 is not set +# CONFIG_IWLWIFI_LEDS is not set +# CONFIG_HOSTAP is not set +# CONFIG_WAN is not set +# CONFIG_FDDI is not set +# CONFIG_HIPPI is not set +CONFIG_PPP=m +CONFIG_PPP_MULTILINK=y +CONFIG_PPP_FILTER=y +CONFIG_PPP_ASYNC=m +# CONFIG_PPP_SYNC_TTY is not set +CONFIG_PPP_DEFLATE=m +CONFIG_PPP_BSDCOMP=m +# CONFIG_PPP_MPPE is not set +CONFIG_PPPOE=m +CONFIG_PPPOL2TP=m +# CONFIG_SLIP is not set +CONFIG_SLHC=m +# CONFIG_NET_FC is not set +# CONFIG_NETCONSOLE is not set +# CONFIG_NETPOLL is not set +# CONFIG_NET_POLL_CONTROLLER is not set +# CONFIG_ISDN is not set +# CONFIG_PHONE is not set + +# +# Input device support +# +CONFIG_INPUT=y +# CONFIG_INPUT_FF_MEMLESS is not set +# CONFIG_INPUT_POLLDEV is not set + +# +# Userland interfaces +# +# CONFIG_INPUT_MOUSEDEV is not set +# CONFIG_INPUT_JOYDEV is not set +# CONFIG_INPUT_EVDEV is not set +# CONFIG_INPUT_EVBUG is not set + +# +# Input Device Drivers +# +CONFIG_INPUT_KEYBOARD=y +# CONFIG_KEYBOARD_ATKBD is not set +# CONFIG_KEYBOARD_SUNKBD is not set +# CONFIG_KEYBOARD_LKKBD is not set +# CONFIG_KEYBOARD_XTKBD is not set +# CONFIG_KEYBOARD_NEWTON is not set +# CONFIG_KEYBOARD_STOWAWAY is not set +# CONFIG_KEYBOARD_GPIO is not set +# CONFIG_INPUT_MOUSE is not set +# CONFIG_INPUT_JOYSTICK is not set +# CONFIG_INPUT_TABLET is not set +# CONFIG_INPUT_TOUCHSCREEN is not set +# CONFIG_INPUT_MISC is not set + +# +# Hardware I/O ports +# +# CONFIG_SERIO is not set +# CONFIG_GAMEPORT is not set + +# +# Character devices +# +# CONFIG_VT is not set +# CONFIG_SERIAL_NONSTANDARD is not set +# CONFIG_NOZOMI is not set + +# +# Serial drivers +# +CONFIG_SERIAL_8250=y +CONFIG_SERIAL_8250_CONSOLE=y +# CONFIG_SERIAL_8250_PCI is not set +CONFIG_SERIAL_8250_NR_UARTS=2 +CONFIG_SERIAL_8250_RUNTIME_UARTS=2 +# CONFIG_SERIAL_8250_EXTENDED is not set + +# +# Non-8250 serial port support +# +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +# CONFIG_SERIAL_JSM is not set +CONFIG_UNIX98_PTYS=y +# CONFIG_LEGACY_PTYS is not set +# CONFIG_IPMI_HANDLER is not set +CONFIG_HW_RANDOM=y +# CONFIG_RTC is not set +# CONFIG_R3964 is not set +# CONFIG_APPLICOM is not set +# CONFIG_RAW_DRIVER is not set +# CONFIG_TCG_TPM is not set +CONFIG_DEVPORT=y +# CONFIG_I2C is not set + +# +# SPI support +# +# CONFIG_SPI is not set +# CONFIG_SPI_MASTER is not set +# CONFIG_W1 is not set +# CONFIG_POWER_SUPPLY is not set +# CONFIG_HWMON is not set +# CONFIG_THERMAL is not set +CONFIG_WATCHDOG=y +# CONFIG_WATCHDOG_NOWAYOUT is not set + +# +# Watchdog Device Drivers +# +# CONFIG_SOFT_WATCHDOG is not set + +# +# PCI-based Watchdog Cards +# +# CONFIG_PCIPCWATCHDOG is not set +# CONFIG_WDTPCI is not set + +# +# Sonics Silicon Backplane +# +CONFIG_SSB_POSSIBLE=y +# CONFIG_SSB is not set + +# +# Multifunction device drivers +# +# CONFIG_MFD_SM501 is not set +# CONFIG_HTC_PASIC3 is not set + +# +# Multimedia devices +# +CONFIG_VIDEO_DEV=m +CONFIG_VIDEO_V4L2_COMMON=m +CONFIG_VIDEO_ALLOW_V4L1=y +CONFIG_VIDEO_V4L1_COMPAT=y +CONFIG_VIDEO_V4L2=m +CONFIG_VIDEO_V4L1=m +CONFIG_VIDEO_CAPTURE_DRIVERS=y +# CONFIG_VIDEO_ADV_DEBUG is not set +# CONFIG_VIDEO_HELPER_CHIPS_AUTO is not set + +# +# Encoders/decoders and other helper chips +# + +# +# Audio decoders +# + +# +# Video decoders +# + +# +# Video and audio decoders +# + +# +# MPEG video encoders +# +# CONFIG_VIDEO_CX2341X is not set + +# +# Video encoders +# + +# +# Video improvement chips +# +# CONFIG_VIDEO_VIVI is not set +# CONFIG_VIDEO_CPIA is not set +# CONFIG_VIDEO_STRADIS is not set +# CONFIG_SOC_CAMERA is not set +# CONFIG_RADIO_ADAPTERS is not set +# CONFIG_DVB_CORE is not set +# CONFIG_DAB is not set + +# +# Graphics support +# +# CONFIG_DRM is not set +# CONFIG_VGASTATE is not set +# CONFIG_VIDEO_OUTPUT_CONTROL is not set +# CONFIG_FB is not set +# CONFIG_BACKLIGHT_LCD_SUPPORT is not set + +# +# Display device support +# +# CONFIG_DISPLAY_SUPPORT is not set + +# +# Sound +# +# CONFIG_SOUND is not set +CONFIG_HID_SUPPORT=y +# CONFIG_HID is not set +CONFIG_USB_SUPPORT=y +CONFIG_USB_ARCH_HAS_HCD=y +CONFIG_USB_ARCH_HAS_OHCI=y +CONFIG_USB_ARCH_HAS_EHCI=y +# CONFIG_USB is not set +# CONFIG_USB_OTG_WHITELIST is not set +# CONFIG_USB_OTG_BLACKLIST_HUB is not set + +# +# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' +# +# CONFIG_USB_GADGET is not set +# CONFIG_MMC is not set +# CONFIG_MEMSTICK is not set +CONFIG_NEW_LEDS=y +CONFIG_LEDS_CLASS=y + +# +# LED drivers +# +# CONFIG_LEDS_GPIO is not set + +# +# LED Triggers +# +CONFIG_LEDS_TRIGGERS=y +CONFIG_LEDS_TRIGGER_TIMER=y +CONFIG_LEDS_TRIGGER_HEARTBEAT=y +# CONFIG_LEDS_TRIGGER_DEFAULT_ON is not set +# CONFIG_INFINIBAND is not set +CONFIG_RTC_LIB=y +# CONFIG_RTC_CLASS is not set +# CONFIG_UIO is not set + +# +# File systems +# +CONFIG_EXT2_FS=y +# CONFIG_EXT2_FS_XATTR is not set +# CONFIG_EXT2_FS_XIP is not set +# CONFIG_EXT3_FS is not set +# CONFIG_EXT4DEV_FS is not set +# CONFIG_REISERFS_FS is not set +# CONFIG_JFS_FS is not set +# CONFIG_FS_POSIX_ACL is not set +# CONFIG_XFS_FS is not set +# CONFIG_OCFS2_FS is not set +# CONFIG_DNOTIFY is not set +# CONFIG_INOTIFY is not set +# CONFIG_QUOTA is not set +# CONFIG_AUTOFS_FS is not set +# CONFIG_AUTOFS4_FS is not set +# CONFIG_FUSE_FS is not set + +# +# CD-ROM/DVD Filesystems +# +# CONFIG_ISO9660_FS is not set +# CONFIG_UDF_FS is not set + +# +# DOS/FAT/NT Filesystems +# +# CONFIG_MSDOS_FS is not set +# CONFIG_VFAT_FS is not set +# CONFIG_NTFS_FS is not set + +# +# Pseudo filesystems +# +CONFIG_PROC_FS=y +CONFIG_PROC_KCORE=y +CONFIG_PROC_SYSCTL=y +CONFIG_SYSFS=y +CONFIG_TMPFS=y +# CONFIG_TMPFS_POSIX_ACL is not set +# CONFIG_HUGETLB_PAGE is not set +CONFIG_CONFIGFS_FS=y + +# +# Miscellaneous filesystems +# +# CONFIG_ADFS_FS is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_HFSPLUS_FS is not set +# CONFIG_BEFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_EFS_FS is not set +CONFIG_JFFS2_FS=y +CONFIG_JFFS2_FS_DEBUG=0 +CONFIG_JFFS2_FS_WRITEBUFFER=y +# CONFIG_JFFS2_FS_WBUF_VERIFY is not set +CONFIG_JFFS2_SUMMARY=y +# CONFIG_JFFS2_FS_XATTR is not set +CONFIG_JFFS2_COMPRESSION_OPTIONS=y +CONFIG_JFFS2_ZLIB=y +# CONFIG_JFFS2_LZO is not set +CONFIG_JFFS2_RTIME=y +# CONFIG_JFFS2_RUBIN is not set +# CONFIG_JFFS2_CMODE_NONE is not set +CONFIG_JFFS2_CMODE_PRIORITY=y +# CONFIG_JFFS2_CMODE_SIZE is not set +# CONFIG_JFFS2_CMODE_FAVOURLZO is not set +# CONFIG_CRAMFS is not set +# CONFIG_VXFS_FS is not set +# CONFIG_MINIX_FS is not set +# CONFIG_HPFS_FS is not set +# CONFIG_QNX4FS_FS is not set +# CONFIG_ROMFS_FS is not set +# CONFIG_SYSV_FS is not set +# CONFIG_UFS_FS is not set +CONFIG_NETWORK_FILESYSTEMS=y +# CONFIG_NFS_FS is not set +# CONFIG_NFSD is not set +# CONFIG_SMB_FS is not set +# CONFIG_CIFS is not set +# CONFIG_NCP_FS is not set +# CONFIG_CODA_FS is not set +# CONFIG_AFS_FS is not set + +# +# Partition Types +# +CONFIG_PARTITION_ADVANCED=y +# CONFIG_ACORN_PARTITION is not set +# CONFIG_OSF_PARTITION is not set +# CONFIG_AMIGA_PARTITION is not set +# CONFIG_ATARI_PARTITION is not set +CONFIG_MAC_PARTITION=y +CONFIG_MSDOS_PARTITION=y +CONFIG_BSD_DISKLABEL=y +# CONFIG_MINIX_SUBPARTITION is not set +# CONFIG_SOLARIS_X86_PARTITION is not set +# CONFIG_UNIXWARE_DISKLABEL is not set +# CONFIG_LDM_PARTITION is not set +# CONFIG_SGI_PARTITION is not set +# CONFIG_ULTRIX_PARTITION is not set +# CONFIG_SUN_PARTITION is not set +# CONFIG_KARMA_PARTITION is not set +# CONFIG_EFI_PARTITION is not set +# CONFIG_SYSV68_PARTITION is not set +# CONFIG_NLS is not set +# CONFIG_DLM is not set + +# +# Kernel hacking +# +CONFIG_TRACE_IRQFLAGS_SUPPORT=y +# CONFIG_PRINTK_TIME is not set +CONFIG_ENABLE_WARN_DEPRECATED=y +# CONFIG_ENABLE_MUST_CHECK is not set +CONFIG_FRAME_WARN=1024 +# CONFIG_MAGIC_SYSRQ is not set +# CONFIG_UNUSED_SYMBOLS is not set +# CONFIG_DEBUG_FS is not set +# CONFIG_HEADERS_CHECK is not set +# CONFIG_DEBUG_KERNEL is not set +# CONFIG_SAMPLES is not set +CONFIG_CMDLINE="" + +# +# Security options +# +# CONFIG_KEYS is not set +# CONFIG_SECURITY is not set +# CONFIG_SECURITY_FILE_CAPABILITIES is not set +CONFIG_CRYPTO=y + +# +# Crypto core or helper +# +CONFIG_CRYPTO_ALGAPI=m +CONFIG_CRYPTO_AEAD=m +CONFIG_CRYPTO_BLKCIPHER=m +# CONFIG_CRYPTO_MANAGER is not set +# CONFIG_CRYPTO_GF128MUL is not set +# CONFIG_CRYPTO_NULL is not set +# CONFIG_CRYPTO_CRYPTD is not set +# CONFIG_CRYPTO_AUTHENC is not set +CONFIG_CRYPTO_TEST=m + +# +# Authenticated Encryption with Associated Data +# +# CONFIG_CRYPTO_CCM is not set +# CONFIG_CRYPTO_GCM is not set +# CONFIG_CRYPTO_SEQIV is not set + +# +# Block modes +# +# CONFIG_CRYPTO_CBC is not set +# CONFIG_CRYPTO_CTR is not set +# CONFIG_CRYPTO_CTS is not set +# CONFIG_CRYPTO_ECB is not set +# CONFIG_CRYPTO_LRW is not set +# CONFIG_CRYPTO_PCBC is not set +# CONFIG_CRYPTO_XTS is not set + +# +# Hash modes +# +# CONFIG_CRYPTO_HMAC is not set +# CONFIG_CRYPTO_XCBC is not set + +# +# Digest +# +# CONFIG_CRYPTO_CRC32C is not set +# CONFIG_CRYPTO_MD4 is not set +# CONFIG_CRYPTO_MD5 is not set +# CONFIG_CRYPTO_MICHAEL_MIC is not set +# CONFIG_CRYPTO_SHA1 is not set +# CONFIG_CRYPTO_SHA256 is not set +# CONFIG_CRYPTO_SHA512 is not set +# CONFIG_CRYPTO_TGR192 is not set +# CONFIG_CRYPTO_WP512 is not set + +# +# Ciphers +# +# CONFIG_CRYPTO_AES is not set +# CONFIG_CRYPTO_ANUBIS is not set +# CONFIG_CRYPTO_ARC4 is not set +# CONFIG_CRYPTO_BLOWFISH is not set +# CONFIG_CRYPTO_CAMELLIA is not set +# CONFIG_CRYPTO_CAST5 is not set +# CONFIG_CRYPTO_CAST6 is not set +# CONFIG_CRYPTO_DES is not set +# CONFIG_CRYPTO_FCRYPT is not set +# CONFIG_CRYPTO_KHAZAD is not set +# CONFIG_CRYPTO_SALSA20 is not set +# CONFIG_CRYPTO_SEED is not set +# CONFIG_CRYPTO_SERPENT is not set +# CONFIG_CRYPTO_TEA is not set +# CONFIG_CRYPTO_TWOFISH is not set + +# +# Compression +# +# CONFIG_CRYPTO_DEFLATE is not set +# CONFIG_CRYPTO_LZO is not set +# CONFIG_CRYPTO_HW is not set + +# +# Library routines +# +CONFIG_BITREVERSE=y +# CONFIG_GENERIC_FIND_FIRST_BIT is not set +CONFIG_CRC_CCITT=m +CONFIG_CRC16=m +# CONFIG_CRC_ITU_T is not set +CONFIG_CRC32=y +# CONFIG_CRC7 is not set +CONFIG_LIBCRC32C=m +CONFIG_ZLIB_INFLATE=y +CONFIG_ZLIB_DEFLATE=y +CONFIG_TEXTSEARCH=y +CONFIG_TEXTSEARCH_KMP=m +CONFIG_TEXTSEARCH_BM=m +CONFIG_TEXTSEARCH_FSM=m +CONFIG_PLIST=y +CONFIG_HAS_IOMEM=y +CONFIG_HAS_IOPORT=y +CONFIG_HAS_DMA=y diff --git a/arch/mips/kernel/linux32.c b/arch/mips/kernel/linux32.c index 65af3cc90abb..c266211ed653 100644 --- a/arch/mips/kernel/linux32.c +++ b/arch/mips/kernel/linux32.c @@ -129,23 +129,6 @@ out: return error; } - -asmlinkage int sys_truncate64(const char __user *path, unsigned int high, - unsigned int low) -{ - if ((int)high < 0) - return -EINVAL; - return sys_truncate(path, ((long) high << 32) | low); -} - -asmlinkage int sys_ftruncate64(unsigned int fd, unsigned int high, - unsigned int low) -{ - if ((int)high < 0) - return -EINVAL; - return sys_ftruncate(fd, ((long) high << 32) | low); -} - /* * sys_execve() executes a new program. */ diff --git a/arch/mips/kernel/scall32-o32.S b/arch/mips/kernel/scall32-o32.S index c058c0b61a2a..fc4fd4d705e2 100644 --- a/arch/mips/kernel/scall32-o32.S +++ b/arch/mips/kernel/scall32-o32.S @@ -354,7 +354,7 @@ einval: li v0, -EINVAL sys sys_mkdir 2 sys sys_rmdir 1 /* 4040 */ sys sys_dup 1 - sys sys_pipe 0 + sys sysm_pipe 0 sys sys_times 1 sys sys_ni_syscall 0 sys sys_brk 1 /* 4045 */ diff --git a/arch/mips/kernel/scall64-64.S b/arch/mips/kernel/scall64-64.S index dc597b600c68..2b73fd1e4528 100644 --- a/arch/mips/kernel/scall64-64.S +++ b/arch/mips/kernel/scall64-64.S @@ -219,7 +219,7 @@ sys_call_table: PTR sys_readv PTR sys_writev PTR sys_access /* 5020 */ - PTR sys_pipe + PTR sysm_pipe PTR sys_select PTR sys_sched_yield PTR sys_mremap diff --git a/arch/mips/kernel/scall64-n32.S b/arch/mips/kernel/scall64-n32.S index 12940eca7893..2654e75d2fef 100644 --- a/arch/mips/kernel/scall64-n32.S +++ b/arch/mips/kernel/scall64-n32.S @@ -141,7 +141,7 @@ EXPORT(sysn32_call_table) PTR compat_sys_readv PTR compat_sys_writev PTR sys_access /* 6020 */ - PTR sys_pipe + PTR sysm_pipe PTR compat_sys_select PTR sys_sched_yield PTR sys_mremap diff --git a/arch/mips/kernel/scall64-o32.S b/arch/mips/kernel/scall64-o32.S index 9a275efb4f04..76167bea5a70 100644 --- a/arch/mips/kernel/scall64-o32.S +++ b/arch/mips/kernel/scall64-o32.S @@ -247,7 +247,7 @@ sys_call_table: PTR sys_mkdir PTR sys_rmdir /* 4040 */ PTR sys_dup - PTR sys_pipe + PTR sysm_pipe PTR compat_sys_times PTR sys_ni_syscall PTR sys_brk /* 4045 */ diff --git a/arch/mips/kernel/syscall.c b/arch/mips/kernel/syscall.c index af1bdc897488..3523c8d12eda 100644 --- a/arch/mips/kernel/syscall.c +++ b/arch/mips/kernel/syscall.c @@ -40,7 +40,14 @@ #include <asm/sysmips.h> #include <asm/uaccess.h> -asmlinkage int sys_pipe(nabi_no_regargs volatile struct pt_regs regs) +/* + * For historic reasons the pipe(2) syscall on MIPS has an unusual calling + * convention. It returns results in registers $v0 / $v1 which means there + * is no need for it to do verify the validity of a userspace pointer + * argument. Historically that used to be expensive in Linux. These days + * the performance advantage is negligible. + */ +asmlinkage int sysm_pipe(nabi_no_regargs volatile struct pt_regs regs) { int fd[2]; int error, res; diff --git a/arch/mips/math-emu/kernel_linkage.c b/arch/mips/math-emu/kernel_linkage.c index ed49ef01ac53..52e6c58c8de1 100644 --- a/arch/mips/math-emu/kernel_linkage.c +++ b/arch/mips/math-emu/kernel_linkage.c @@ -24,6 +24,7 @@ #include <asm/signal.h> #include <asm/uaccess.h> +#include <asm/fpu.h> #include <asm/fpu_emulator.h> #define SIGNALLING_NAN 0x7ff800007ff80000LL diff --git a/arch/mips/pci/Makefile b/arch/mips/pci/Makefile index 57e34cafa497..15e01aec37fd 100644 --- a/arch/mips/pci/Makefile +++ b/arch/mips/pci/Makefile @@ -49,3 +49,4 @@ obj-$(CONFIG_TOSHIBA_RBTX4938) += fixup-rbtx4938.o obj-$(CONFIG_VICTOR_MPC30X) += fixup-mpc30x.o obj-$(CONFIG_ZAO_CAPCELLA) += fixup-capcella.o obj-$(CONFIG_WR_PPMC) += fixup-wrppmc.o +obj-$(CONFIG_MIKROTIK_RB532) += pci-rc32434.o ops-rc32434.o fixup-rc32434.o diff --git a/arch/mips/pci/fixup-rc32434.c b/arch/mips/pci/fixup-rc32434.c new file mode 100644 index 000000000000..75b90dcb7a09 --- /dev/null +++ b/arch/mips/pci/fixup-rc32434.c @@ -0,0 +1,69 @@ +/* + * Copyright 2001 MontaVista Software Inc. + * Author: MontaVista Software, Inc. + * stevel@mvista.com or source@mvista.com + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * THIS SOFTWARE IS PROVIDED ``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 AUTHOR 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. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include <linux/types.h> +#include <linux/pci.h> +#include <linux/kernel.h> +#include <linux/init.h> + +#include <asm/mach-rc32434/rc32434.h> + +static int __devinitdata irq_map[2][12] = { + {0, 0, 2, 3, 2, 3, 0, 0, 0, 0, 0, 1}, + {0, 0, 1, 3, 0, 2, 1, 3, 0, 2, 1, 3} +}; + +int __devinit pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin) +{ + int irq = 0; + + if (dev->bus->number < 2 && PCI_SLOT(dev->devfn) < 12) + irq = irq_map[dev->bus->number][PCI_SLOT(dev->devfn)]; + + return irq + GROUP4_IRQ_BASE + 4; +} + +static void rc32434_pci_early_fixup(struct pci_dev *dev) +{ + if (PCI_SLOT(dev->devfn) == 6 && dev->bus->number == 0) { + /* disable prefetched memory range */ + pci_write_config_word(dev, PCI_PREF_MEMORY_LIMIT, 0); + pci_write_config_word(dev, PCI_PREF_MEMORY_BASE, 0x10); + + pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, 4); + } +} + +/* + * The fixup applies to both the IDT and VIA devices present on the board + */ +DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, rc32434_pci_early_fixup); + +/* Do platform specific device initialization at pci_enable_device() time */ +int pcibios_plat_dev_init(struct pci_dev *dev) +{ + return 0; +} diff --git a/arch/mips/pci/ops-rc32434.c b/arch/mips/pci/ops-rc32434.c new file mode 100644 index 000000000000..d1f8fa210ca1 --- /dev/null +++ b/arch/mips/pci/ops-rc32434.c @@ -0,0 +1,207 @@ +/* + * BRIEF MODULE DESCRIPTION + * pci_ops for IDT EB434 board + * + * Copyright 2004 IDT Inc. (rischelp@idt.com) + * Copyright 2006 Felix Fietkau <nbd@openwrt.org> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * THIS SOFTWARE IS PROVIDED ``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 AUTHOR 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. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include <linux/delay.h> +#include <linux/init.h> +#include <linux/io.h> +#include <linux/pci.h> +#include <linux/types.h> + +#include <asm/cpu.h> +#include <asm/mach-rc32434/rc32434.h> +#include <asm/mach-rc32434/pci.h> + +#define PCI_ACCESS_READ 0 +#define PCI_ACCESS_WRITE 1 + + +#define PCI_CFG_SET(bus, slot, func, off) \ + (rc32434_pci->pcicfga = (0x80000000 | \ + ((bus) << 16) | ((slot)<<11) | \ + ((func)<<8) | (off))) + +static inline int config_access(unsigned char access_type, + struct pci_bus *bus, unsigned int devfn, + unsigned char where, u32 *data) +{ + unsigned int slot = PCI_SLOT(devfn); + u8 func = PCI_FUNC(devfn); + + /* Setup address */ + PCI_CFG_SET(bus->number, slot, func, where); + rc32434_sync(); + + if (access_type == PCI_ACCESS_WRITE) + rc32434_pci->pcicfgd = *data; + else + *data = rc32434_pci->pcicfgd; + + rc32434_sync(); + + return 0; +} + + +/* + * We can't address 8 and 16 bit words directly. Instead we have to + * read/write a 32bit word and mask/modify the data we actually want. + */ +static int read_config_byte(struct pci_bus *bus, unsigned int devfn, + int where, u8 *val) +{ + u32 data; + int ret; + + ret = config_access(PCI_ACCESS_READ, bus, devfn, where, &data); + *val = (data >> ((where & 3) << 3)) & 0xff; + return ret; +} + +static int read_config_word(struct pci_bus *bus, unsigned int devfn, + int where, u16 *val) +{ + u32 data; + int ret; + + ret = config_access(PCI_ACCESS_READ, bus, devfn, where, &data); + *val = (data >> ((where & 3) << 3)) & 0xffff; + return ret; +} + +static int read_config_dword(struct pci_bus *bus, unsigned int devfn, + int where, u32 *val) +{ + int ret; + int delay = 1; + + /* + * Don't scan too far, else there will be errors with plugged in + * daughterboard (rb564). + */ + if (bus->number == 0 && PCI_SLOT(devfn) > 21) + return 0; + +retry: + ret = config_access(PCI_ACCESS_READ, bus, devfn, where, val); + + /* + * Certain devices react delayed at device scan time, this + * gives them time to settle + */ + if (where == PCI_VENDOR_ID) { + if (ret == 0xffffffff || ret == 0x00000000 || + ret == 0x0000ffff || ret == 0xffff0000) { + if (delay > 4) + return 0; + delay *= 2; + msleep(delay); + goto retry; + } + } + + return ret; +} + +static int +write_config_byte(struct pci_bus *bus, unsigned int devfn, int where, + u8 val) +{ + u32 data = 0; + + if (config_access(PCI_ACCESS_READ, bus, devfn, where, &data)) + return -1; + + data = (data & ~(0xff << ((where & 3) << 3))) | + (val << ((where & 3) << 3)); + + if (config_access(PCI_ACCESS_WRITE, bus, devfn, where, &data)) + return -1; + + return PCIBIOS_SUCCESSFUL; +} + + +static int +write_config_word(struct pci_bus *bus, unsigned int devfn, int where, + u16 val) +{ + u32 data = 0; + + if (config_access(PCI_ACCESS_READ, bus, devfn, where, &data)) + return -1; + + data = (data & ~(0xffff << ((where & 3) << 3))) | + (val << ((where & 3) << 3)); + + if (config_access(PCI_ACCESS_WRITE, bus, devfn, where, &data)) + return -1; + + + return PCIBIOS_SUCCESSFUL; +} + + +static int +write_config_dword(struct pci_bus *bus, unsigned int devfn, int where, + u32 val) +{ + if (config_access(PCI_ACCESS_WRITE, bus, devfn, where, &val)) + return -1; + + return PCIBIOS_SUCCESSFUL; +} + +static int pci_config_read(struct pci_bus *bus, unsigned int devfn, + int where, int size, u32 *val) +{ + switch (size) { + case 1: + return read_config_byte(bus, devfn, where, (u8 *) val); + case 2: + return read_config_word(bus, devfn, where, (u16 *) val); + default: + return read_config_dword(bus, devfn, where, val); + } +} + +static int pci_config_write(struct pci_bus *bus, unsigned int devfn, + int where, int size, u32 val) +{ + switch (size) { + case 1: + return write_config_byte(bus, devfn, where, (u8) val); + case 2: + return write_config_word(bus, devfn, where, (u16) val); + default: + return write_config_dword(bus, devfn, where, val); + } +} + +struct pci_ops rc32434_pci_ops = { + .read = pci_config_read, + .write = pci_config_write, +}; diff --git a/arch/mips/pci/pci-rc32434.c b/arch/mips/pci/pci-rc32434.c new file mode 100644 index 000000000000..1c2821e2f494 --- /dev/null +++ b/arch/mips/pci/pci-rc32434.c @@ -0,0 +1,221 @@ +/* + * BRIEF MODULE DESCRIPTION + * PCI initialization for IDT EB434 board + * + * Copyright 2004 IDT Inc. (rischelp@idt.com) + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * THIS SOFTWARE IS PROVIDED ``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 AUTHOR 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. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include <linux/types.h> +#include <linux/pci.h> +#include <linux/kernel.h> +#include <linux/init.h> + +#include <asm/mach-rc32434/rc32434.h> +#include <asm/mach-rc32434/pci.h> + +#define PCI_ACCESS_READ 0 +#define PCI_ACCESS_WRITE 1 + +/* define an unsigned array for the PCI registers */ +static unsigned int korina_cnfg_regs[25] = { + KORINA_CNFG1, KORINA_CNFG2, KORINA_CNFG3, KORINA_CNFG4, + KORINA_CNFG5, KORINA_CNFG6, KORINA_CNFG7, KORINA_CNFG8, + KORINA_CNFG9, KORINA_CNFG10, KORINA_CNFG11, KORINA_CNFG12, + KORINA_CNFG13, KORINA_CNFG14, KORINA_CNFG15, KORINA_CNFG16, + KORINA_CNFG17, KORINA_CNFG18, KORINA_CNFG19, KORINA_CNFG20, + KORINA_CNFG21, KORINA_CNFG22, KORINA_CNFG23, KORINA_CNFG24 +}; +static struct resource rc32434_res_pci_mem1; +static struct resource rc32434_res_pci_mem2; + +static struct resource rc32434_res_pci_mem1 = { + .name = "PCI MEM1", + .start = 0x50000000, + .end = 0x5FFFFFFF, + .flags = IORESOURCE_MEM, + .parent = &rc32434_res_pci_mem1, + .sibling = NULL, + .child = &rc32434_res_pci_mem2 +}; + +static struct resource rc32434_res_pci_mem2 = { + .name = "PCI Mem2", + .start = 0x60000000, + .end = 0x6FFFFFFF, + .flags = IORESOURCE_MEM, + .parent = &rc32434_res_pci_mem1, + .sibling = NULL, + .child = NULL +}; + +static struct resource rc32434_res_pci_io1 = { + .name = "PCI I/O1", + .start = 0x18800000, + .end = 0x188FFFFF, + .flags = IORESOURCE_IO, +}; + +extern struct pci_ops rc32434_pci_ops; + +#define PCI_MEM1_START PCI_ADDR_START +#define PCI_MEM1_END (PCI_ADDR_START + CPUTOPCI_MEM_WIN - 1) +#define PCI_MEM2_START (PCI_ADDR_START + CPUTOPCI_MEM_WIN) +#define PCI_MEM2_END (PCI_ADDR_START + (2 * CPUTOPCI_MEM_WIN) - 1) +#define PCI_IO1_START (PCI_ADDR_START + (2 * CPUTOPCI_MEM_WIN)) +#define PCI_IO1_END \ + (PCI_ADDR_START + (2 * CPUTOPCI_MEM_WIN) + CPUTOPCI_IO_WIN - 1) +#define PCI_IO2_START \ + (PCI_ADDR_START + (2 * CPUTOPCI_MEM_WIN) + CPUTOPCI_IO_WIN) +#define PCI_IO2_END \ + (PCI_ADDR_START + (2 * CPUTOPCI_MEM_WIN) + (2 * CPUTOPCI_IO_WIN) - 1) + +struct pci_controller rc32434_controller2; + +struct pci_controller rc32434_controller = { + .pci_ops = &rc32434_pci_ops, + .mem_resource = &rc32434_res_pci_mem1, + .io_resource = &rc32434_res_pci_io1, + .mem_offset = 0, + .io_offset = 0, + +}; + +#ifdef __MIPSEB__ +#define PCI_ENDIAN_FLAG PCILBAC_sb_m +#else +#define PCI_ENDIAN_FLAG 0 +#endif + +static int __init rc32434_pcibridge_init(void) +{ + unsigned int pcicvalue, pcicdata = 0; + unsigned int dummyread, pcicntlval; + int loopCount; + unsigned int pci_config_addr; + + pcicvalue = rc32434_pci->pcic; + pcicvalue = (pcicvalue >> PCIM_SHFT) & PCIM_BIT_LEN; + if (!((pcicvalue == PCIM_H_EA) || + (pcicvalue == PCIM_H_IA_FIX) || + (pcicvalue == PCIM_H_IA_RR))) { + pr_err(KERN_ERR "PCI init error!!!\n"); + /* Not in Host Mode, return ERROR */ + return -1; + } + /* Enables the Idle Grant mode, Arbiter Parking */ + pcicdata |= (PCI_CTL_IGM | PCI_CTL_EAP | PCI_CTL_EN); + rc32434_pci->pcic = pcicdata; /* Enable the PCI bus Interface */ + /* Zero out the PCI status & PCI Status Mask */ + for (;;) { + pcicdata = rc32434_pci->pcis; + if (!(pcicdata & PCI_STAT_RIP)) + break; + } + + rc32434_pci->pcis = 0; + rc32434_pci->pcism = 0xFFFFFFFF; + /* Zero out the PCI decoupled registers */ + rc32434_pci->pcidac = 0; /* + * disable PCI decoupled accesses at + * initialization + */ + rc32434_pci->pcidas = 0; /* clear the status */ + rc32434_pci->pcidasm = 0x0000007F; /* Mask all the interrupts */ + /* Mask PCI Messaging Interrupts */ + rc32434_pci_msg->pciiic = 0; + rc32434_pci_msg->pciiim = 0xFFFFFFFF; + rc32434_pci_msg->pciioic = 0; + rc32434_pci_msg->pciioim = 0; + + + /* Setup PCILB0 as Memory Window */ + rc32434_pci->pcilba[0].address = (unsigned int) (PCI_ADDR_START); + + /* setup the PCI map address as same as the local address */ + + rc32434_pci->pcilba[0].mapping = (unsigned int) (PCI_ADDR_START); + + + /* Setup PCILBA1 as MEM */ + rc32434_pci->pcilba[0].control = + (((SIZE_256MB & 0x1f) << PCI_LBAC_SIZE_BIT) | PCI_ENDIAN_FLAG); + dummyread = rc32434_pci->pcilba[0].control; /* flush the CPU write Buffers */ + rc32434_pci->pcilba[1].address = 0x60000000; + rc32434_pci->pcilba[1].mapping = 0x60000000; + + /* setup PCILBA2 as IO Window */ + rc32434_pci->pcilba[1].control = + (((SIZE_256MB & 0x1f) << PCI_LBAC_SIZE_BIT) | PCI_ENDIAN_FLAG); + dummyread = rc32434_pci->pcilba[1].control; /* flush the CPU write Buffers */ + rc32434_pci->pcilba[2].address = 0x18C00000; + rc32434_pci->pcilba[2].mapping = 0x18FFFFFF; + + /* setup PCILBA2 as IO Window */ + rc32434_pci->pcilba[2].control = + (((SIZE_4MB & 0x1f) << PCI_LBAC_SIZE_BIT) | PCI_ENDIAN_FLAG); + dummyread = rc32434_pci->pcilba[2].control; /* flush the CPU write Buffers */ + + /* Setup PCILBA3 as IO Window */ + rc32434_pci->pcilba[3].address = 0x18800000; + rc32434_pci->pcilba[3].mapping = 0x18800000; + rc32434_pci->pcilba[3].control = + ((((SIZE_1MB & 0x1ff) << PCI_LBAC_SIZE_BIT) | PCI_LBAC_MSI) | + PCI_ENDIAN_FLAG); + dummyread = rc32434_pci->pcilba[3].control; /* flush the CPU write Buffers */ + + pci_config_addr = (unsigned int) (0x80000004); + for (loopCount = 0; loopCount < 24; loopCount++) { + rc32434_pci->pcicfga = pci_config_addr; + dummyread = rc32434_pci->pcicfga; + rc32434_pci->pcicfgd = korina_cnfg_regs[loopCount]; + dummyread = rc32434_pci->pcicfgd; + pci_config_addr += 4; + } + rc32434_pci->pcitc = + (unsigned int) ((PCITC_RTIMER_VAL & 0xff) << PCI_TC_RTIMER_BIT) | + ((PCITC_DTIMER_VAL & 0xff) << PCI_TC_DTIMER_BIT); + + pcicntlval = rc32434_pci->pcic; + pcicntlval &= ~PCI_CTL_TNR; + rc32434_pci->pcic = pcicntlval; + pcicntlval = rc32434_pci->pcic; + + return 0; +} + +static int __init rc32434_pci_init(void) +{ + pr_info("PCI: Initializing PCI\n"); + + ioport_resource.start = rc32434_res_pci_io1.start; + ioport_resource.end = rc32434_res_pci_io1.end; + + rc32434_pcibridge_init(); + + register_pci_controller(&rc32434_controller); + rc32434_sync(); + + return 0; +} + +arch_initcall(rc32434_pci_init); diff --git a/arch/mips/pci/pci.c b/arch/mips/pci/pci.c index d7d6cb063d26..77bd5b68dc43 100644 --- a/arch/mips/pci/pci.c +++ b/arch/mips/pci/pci.c @@ -204,7 +204,7 @@ static int pcibios_enable_resources(struct pci_dev *dev, int mask) * If we set up a device for bus mastering, we need to check the latency * timer as certain crappy BIOSes forget to set it properly. */ -unsigned int pcibios_max_latency = 255; +static unsigned int pcibios_max_latency = 255; void pcibios_set_master(struct pci_dev *dev) { diff --git a/arch/mips/rb532/Makefile b/arch/mips/rb532/Makefile new file mode 100644 index 000000000000..8f0b6b6a1625 --- /dev/null +++ b/arch/mips/rb532/Makefile @@ -0,0 +1,7 @@ +# +# Makefile for the RB532 board specific parts of the kernel +# + +obj-y += irq.o time.o setup.o serial.o prom.o gpio.o devices.o + +EXTRA_CFLAGS += -Werror diff --git a/arch/mips/rb532/devices.c b/arch/mips/rb532/devices.c new file mode 100644 index 000000000000..44fb0a62877f --- /dev/null +++ b/arch/mips/rb532/devices.c @@ -0,0 +1,331 @@ +/* + * RouterBoard 500 Platform devices + * + * Copyright (C) 2006 Felix Fietkau <nbd@openwrt.org> + * Copyright (C) 2007 Florian Fainelli <florian@openwrt.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/ctype.h> +#include <linux/string.h> +#include <linux/platform_device.h> +#include <linux/mtd/nand.h> +#include <linux/mtd/mtd.h> +#include <linux/mtd/partitions.h> +#include <linux/gpio_keys.h> +#include <linux/input.h> + +#include <asm/bootinfo.h> + +#include <asm/mach-rc32434/rc32434.h> +#include <asm/mach-rc32434/dma.h> +#include <asm/mach-rc32434/dma_v.h> +#include <asm/mach-rc32434/eth.h> +#include <asm/mach-rc32434/rb.h> +#include <asm/mach-rc32434/integ.h> +#include <asm/mach-rc32434/gpio.h> + +#define ETH0_DMA_RX_IRQ (GROUP1_IRQ_BASE + 0) +#define ETH0_DMA_TX_IRQ (GROUP1_IRQ_BASE + 1) +#define ETH0_RX_OVR_IRQ (GROUP3_IRQ_BASE + 9) +#define ETH0_TX_UND_IRQ (GROUP3_IRQ_BASE + 10) + +#define ETH0_RX_DMA_ADDR (DMA0_BASE_ADDR + 0 * DMA_CHAN_OFFSET) +#define ETH0_TX_DMA_ADDR (DMA0_BASE_ADDR + 1 * DMA_CHAN_OFFSET) + +/* NAND definitions */ +#define GPIO_RDY (1 << 0x08) +#define GPIO_WPX (1 << 0x09) +#define GPIO_ALE (1 << 0x0a) +#define GPIO_CLE (1 << 0x0b) + +extern char *board_type; + +static struct resource korina_dev0_res[] = { + { + .name = "korina_regs", + .start = ETH0_BASE_ADDR, + .end = ETH0_BASE_ADDR + sizeof(struct eth_regs), + .flags = IORESOURCE_MEM, + }, { + .name = "korina_rx", + .start = ETH0_DMA_RX_IRQ, + .end = ETH0_DMA_RX_IRQ, + .flags = IORESOURCE_IRQ + }, { + .name = "korina_tx", + .start = ETH0_DMA_TX_IRQ, + .end = ETH0_DMA_TX_IRQ, + .flags = IORESOURCE_IRQ + }, { + .name = "korina_ovr", + .start = ETH0_RX_OVR_IRQ, + .end = ETH0_RX_OVR_IRQ, + .flags = IORESOURCE_IRQ + }, { + .name = "korina_und", + .start = ETH0_TX_UND_IRQ, + .end = ETH0_TX_UND_IRQ, + .flags = IORESOURCE_IRQ + }, { + .name = "korina_dma_rx", + .start = ETH0_RX_DMA_ADDR, + .end = ETH0_RX_DMA_ADDR + DMA_CHAN_OFFSET - 1, + .flags = IORESOURCE_MEM, + }, { + .name = "korina_dma_tx", + .start = ETH0_TX_DMA_ADDR, + .end = ETH0_TX_DMA_ADDR + DMA_CHAN_OFFSET - 1, + .flags = IORESOURCE_MEM, + } +}; + +static struct korina_device korina_dev0_data = { + .name = "korina0", + .mac = {0xde, 0xca, 0xff, 0xc0, 0xff, 0xee} +}; + +static struct platform_device korina_dev0 = { + .id = 0, + .name = "korina", + .dev.platform_data = &korina_dev0_data, + .resource = korina_dev0_res, + .num_resources = ARRAY_SIZE(korina_dev0_res), +}; + +#define CF_GPIO_NUM 13 + +static struct resource cf_slot0_res[] = { + { + .name = "cf_membase", + .flags = IORESOURCE_MEM + }, { + .name = "cf_irq", + .start = (8 + 4 * 32 + CF_GPIO_NUM), /* 149 */ + .end = (8 + 4 * 32 + CF_GPIO_NUM), + .flags = IORESOURCE_IRQ + } +}; + +static struct cf_device cf_slot0_data = { + .gpio_pin = 13 +}; + +static struct platform_device cf_slot0 = { + .id = 0, + .name = "pata-rb532-cf", + .dev.platform_data = &cf_slot0_data, + .resource = cf_slot0_res, + .num_resources = ARRAY_SIZE(cf_slot0_res), +}; + +/* Resources and device for NAND */ +static int rb532_dev_ready(struct mtd_info *mtd) +{ + return readl(IDT434_REG_BASE + GPIOD) & GPIO_RDY; +} + +static void rb532_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl) +{ + struct nand_chip *chip = mtd->priv; + unsigned char orbits, nandbits; + + if (ctrl & NAND_CTRL_CHANGE) { + orbits = (ctrl & NAND_CLE) << 1; + orbits |= (ctrl & NAND_ALE) >> 1; + + nandbits = (~ctrl & NAND_CLE) << 1; + nandbits |= (~ctrl & NAND_ALE) >> 1; + + set_latch_u5(orbits, nandbits); + } + if (cmd != NAND_CMD_NONE) + writeb(cmd, chip->IO_ADDR_W); +} + +static struct resource nand_slot0_res[] = { + [0] = { + .name = "nand_membase", + .flags = IORESOURCE_MEM + } +}; + +static struct platform_nand_data rb532_nand_data = { + .ctrl.dev_ready = rb532_dev_ready, + .ctrl.cmd_ctrl = rb532_cmd_ctrl, +}; + +static struct platform_device nand_slot0 = { + .name = "gen_nand", + .id = -1, + .resource = nand_slot0_res, + .num_resources = ARRAY_SIZE(nand_slot0_res), + .dev.platform_data = &rb532_nand_data, +}; + +static struct mtd_partition rb532_partition_info[] = { + { + .name = "Routerboard NAND boot", + .offset = 0, + .size = 4 * 1024 * 1024, + }, { + .name = "rootfs", + .offset = MTDPART_OFS_NXTBLK, + .size = MTDPART_SIZ_FULL, + } +}; + +static struct platform_device rb532_led = { + .name = "rb532-led", + .id = 0, +}; + +static struct gpio_keys_button rb532_gpio_btn[] = { + { + .gpio = 1, + .code = BTN_0, + .desc = "S1", + .active_low = 1, + } +}; + +static struct gpio_keys_platform_data rb532_gpio_btn_data = { + .buttons = rb532_gpio_btn, + .nbuttons = ARRAY_SIZE(rb532_gpio_btn), +}; + +static struct platform_device rb532_button = { + .name = "gpio-keys", + .id = -1, + .dev = { + .platform_data = &rb532_gpio_btn_data, + } +}; + +static struct resource rb532_wdt_res[] = { + { + .name = "rb532_wdt_res", + .start = INTEG0_BASE_ADDR, + .end = INTEG0_BASE_ADDR + sizeof(struct integ), + .flags = IORESOURCE_MEM, + } +}; + +static struct platform_device rb532_wdt = { + .name = "rc32434_wdt", + .id = -1, + .resource = rb532_wdt_res, + .num_resources = ARRAY_SIZE(rb532_wdt_res), +}; + +static struct platform_device *rb532_devs[] = { + &korina_dev0, + &nand_slot0, + &cf_slot0, + &rb532_led, + &rb532_button, + &rb532_wdt +}; + +static void __init parse_mac_addr(char *macstr) +{ + int i, j; + unsigned char result, value; + + for (i = 0; i < 6; i++) { + result = 0; + + if (i != 5 && *(macstr + 2) != ':') + return; + + for (j = 0; j < 2; j++) { + if (isxdigit(*macstr) + && (value = + isdigit(*macstr) ? *macstr - + '0' : toupper(*macstr) - 'A' + 10) < 16) { + result = result * 16 + value; + macstr++; + } else + return; + } + + macstr++; + korina_dev0_data.mac[i] = result; + } +} + + +/* DEVICE CONTROLLER 1 */ +#define CFG_DC_DEV1 ((void *)0xb8010010) +#define CFG_DC_DEV2 ((void *)0xb8010020) +#define CFG_DC_DEVBASE 0x0 +#define CFG_DC_DEVMASK 0x4 +#define CFG_DC_DEVC 0x8 +#define CFG_DC_DEVTC 0xC + +/* NAND definitions */ +#define NAND_CHIP_DELAY 25 + +static void __init rb532_nand_setup(void) +{ + switch (mips_machtype) { + case MACH_MIKROTIK_RB532A: + set_latch_u5(LO_FOFF | LO_CEX, + LO_ULED | LO_ALE | LO_CLE | LO_WPX); + break; + default: + set_latch_u5(LO_WPX | LO_FOFF | LO_CEX, + LO_ULED | LO_ALE | LO_CLE); + break; + } + + /* Setup NAND specific settings */ + rb532_nand_data.chip.nr_chips = 1; + rb532_nand_data.chip.nr_partitions = ARRAY_SIZE(rb532_partition_info); + rb532_nand_data.chip.partitions = rb532_partition_info; + rb532_nand_data.chip.chip_delay = NAND_CHIP_DELAY; + rb532_nand_data.chip.options = NAND_NO_AUTOINCR; +} + + +static int __init plat_setup_devices(void) +{ + /* Look for the CF card reader */ + if (!readl(CFG_DC_DEV1 + CFG_DC_DEVMASK)) + rb532_devs[1] = NULL; + else { + cf_slot0_res[0].start = + readl(CFG_DC_DEV1 + CFG_DC_DEVBASE); + cf_slot0_res[0].end = cf_slot0_res[0].start + 0x1000; + } + + /* Read the NAND resources from the device controller */ + nand_slot0_res[0].start = readl(CFG_DC_DEV2 + CFG_DC_DEVBASE); + nand_slot0_res[0].end = nand_slot0_res[0].start + 0x1000; + + /* Initialise the NAND device */ + rb532_nand_setup(); + + return platform_add_devices(rb532_devs, ARRAY_SIZE(rb532_devs)); +} + +static int __init setup_kmac(char *s) +{ + printk(KERN_INFO "korina mac = %s\n", s); + parse_mac_addr(s); + return 0; +} + +__setup("kmac=", setup_kmac); + +arch_initcall(plat_setup_devices); diff --git a/arch/mips/rb532/gpio.c b/arch/mips/rb532/gpio.c new file mode 100644 index 000000000000..b2fe82dba0a5 --- /dev/null +++ b/arch/mips/rb532/gpio.c @@ -0,0 +1,220 @@ +/* + * Miscellaneous functions for IDT EB434 board + * + * Copyright 2004 IDT Inc. (rischelp@idt.com) + * Copyright 2006 Phil Sutter <n0-1@freewrt.org> + * Copyright 2007 Florian Fainelli <florian@openwrt.org> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * THIS SOFTWARE IS PROVIDED ``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 AUTHOR 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. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include <linux/kernel.h> +#include <linux/gpio.h> +#include <linux/init.h> +#include <linux/types.h> +#include <linux/pci.h> +#include <linux/spinlock.h> +#include <linux/io.h> +#include <linux/platform_device.h> + +#include <asm/addrspace.h> + +#include <asm/mach-rc32434/rb.h> + +struct rb532_gpio_reg __iomem *rb532_gpio_reg0; +EXPORT_SYMBOL(rb532_gpio_reg0); + +struct mpmc_device dev3; + +static struct resource rb532_gpio_reg0_res[] = { + { + .name = "gpio_reg0", + .start = (u32)(IDT434_REG_BASE + GPIOBASE), + .end = (u32)(IDT434_REG_BASE + GPIOBASE + sizeof(struct rb532_gpio_reg)), + .flags = IORESOURCE_MEM, + } +}; + +static struct resource rb532_dev3_ctl_res[] = { + { + .name = "dev3_ctl", + .start = (u32)(IDT434_REG_BASE + DEV3BASE), + .end = (u32)(IDT434_REG_BASE + DEV3BASE + sizeof(struct dev_reg)), + .flags = IORESOURCE_MEM, + } +}; + +void set_434_reg(unsigned reg_offs, unsigned bit, unsigned len, unsigned val) +{ + unsigned flags, data; + unsigned i = 0; + + spin_lock_irqsave(&dev3.lock, flags); + + data = *(volatile unsigned *) (IDT434_REG_BASE + reg_offs); + for (i = 0; i != len; ++i) { + if (val & (1 << i)) + data |= (1 << (i + bit)); + else + data &= ~(1 << (i + bit)); + } + writel(data, (IDT434_REG_BASE + reg_offs)); + + spin_unlock_irqrestore(&dev3.lock, flags); +} +EXPORT_SYMBOL(set_434_reg); + +unsigned get_434_reg(unsigned reg_offs) +{ + return readl(IDT434_REG_BASE + reg_offs); +} +EXPORT_SYMBOL(get_434_reg); + +void set_latch_u5(unsigned char or_mask, unsigned char nand_mask) +{ + unsigned flags; + + spin_lock_irqsave(&dev3.lock, flags); + + dev3.state = (dev3.state | or_mask) & ~nand_mask; + writel(dev3.state, &dev3.base); + + spin_unlock_irqrestore(&dev3.lock, flags); +} +EXPORT_SYMBOL(set_latch_u5); + +unsigned char get_latch_u5(void) +{ + return dev3.state; +} +EXPORT_SYMBOL(get_latch_u5); + +int rb532_gpio_get_value(unsigned gpio) +{ + return readl(&rb532_gpio_reg0->gpiod) & (1 << gpio); +} +EXPORT_SYMBOL(rb532_gpio_get_value); + +void rb532_gpio_set_value(unsigned gpio, int value) +{ + unsigned tmp; + + tmp = readl(&rb532_gpio_reg0->gpiod) & ~(1 << gpio); + if (value) + tmp |= 1 << gpio; + + writel(tmp, (void *)&rb532_gpio_reg0->gpiod); +} +EXPORT_SYMBOL(rb532_gpio_set_value); + +int rb532_gpio_direction_input(unsigned gpio) +{ + writel(readl(&rb532_gpio_reg0->gpiocfg) & ~(1 << gpio), + (void *)&rb532_gpio_reg0->gpiocfg); + + return 0; +} +EXPORT_SYMBOL(rb532_gpio_direction_input); + +int rb532_gpio_direction_output(unsigned gpio, int value) +{ + gpio_set_value(gpio, value); + writel(readl(&rb532_gpio_reg0->gpiocfg) | (1 << gpio), + (void *)&rb532_gpio_reg0->gpiocfg); + + return 0; +} +EXPORT_SYMBOL(rb532_gpio_direction_output); + +void rb532_gpio_set_int_level(unsigned gpio, int value) +{ + unsigned tmp; + + tmp = readl(&rb532_gpio_reg0->gpioilevel) & ~(1 << gpio); + if (value) + tmp |= 1 << gpio; + writel(tmp, (void *)&rb532_gpio_reg0->gpioilevel); +} +EXPORT_SYMBOL(rb532_gpio_set_int_level); + +int rb532_gpio_get_int_level(unsigned gpio) +{ + return readl(&rb532_gpio_reg0->gpioilevel) & (1 << gpio); +} +EXPORT_SYMBOL(rb532_gpio_get_int_level); + +void rb532_gpio_set_int_status(unsigned gpio, int value) +{ + unsigned tmp; + + tmp = readl(&rb532_gpio_reg0->gpioistat); + if (value) + tmp |= 1 << gpio; + writel(tmp, (void *)&rb532_gpio_reg0->gpioistat); +} +EXPORT_SYMBOL(rb532_gpio_set_int_status); + +int rb532_gpio_get_int_status(unsigned gpio) +{ + return readl(&rb532_gpio_reg0->gpioistat) & (1 << gpio); +} +EXPORT_SYMBOL(rb532_gpio_get_int_status); + +void rb532_gpio_set_func(unsigned gpio, int value) +{ + unsigned tmp; + + tmp = readl(&rb532_gpio_reg0->gpiofunc); + if (value) + tmp |= 1 << gpio; + writel(tmp, (void *)&rb532_gpio_reg0->gpiofunc); +} +EXPORT_SYMBOL(rb532_gpio_set_func); + +int rb532_gpio_get_func(unsigned gpio) +{ + return readl(&rb532_gpio_reg0->gpiofunc) & (1 << gpio); +} +EXPORT_SYMBOL(rb532_gpio_get_func); + +int __init rb532_gpio_init(void) +{ + rb532_gpio_reg0 = ioremap_nocache(rb532_gpio_reg0_res[0].start, + rb532_gpio_reg0_res[0].end - + rb532_gpio_reg0_res[0].start); + + if (!rb532_gpio_reg0) { + printk(KERN_ERR "rb532: cannot remap GPIO register 0\n"); + return -ENXIO; + } + + dev3.base = ioremap_nocache(rb532_dev3_ctl_res[0].start, + rb532_dev3_ctl_res[0].end - + rb532_dev3_ctl_res[0].start); + + if (!dev3.base) { + printk(KERN_ERR "rb532: cannot remap device controller 3\n"); + return -ENXIO; + } + + return 0; +} +arch_initcall(rb532_gpio_init); diff --git a/arch/mips/rb532/irq.c b/arch/mips/rb532/irq.c new file mode 100644 index 000000000000..c0d0f950caf2 --- /dev/null +++ b/arch/mips/rb532/irq.c @@ -0,0 +1,209 @@ +/* + * 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 SOFTWARE IS PROVIDED ``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 AUTHOR 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. + * + * 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. + * + * Copyright 2002 MontaVista Software Inc. + * Author: MontaVista Software, Inc. + * stevel@mvista.com or source@mvista.com + */ + +#include <linux/bitops.h> +#include <linux/errno.h> +#include <linux/init.h> +#include <linux/io.h> +#include <linux/kernel_stat.h> +#include <linux/module.h> +#include <linux/signal.h> +#include <linux/sched.h> +#include <linux/types.h> +#include <linux/interrupt.h> +#include <linux/ioport.h> +#include <linux/timex.h> +#include <linux/slab.h> +#include <linux/random.h> +#include <linux/delay.h> + +#include <asm/bootinfo.h> +#include <asm/time.h> +#include <asm/mipsregs.h> +#include <asm/system.h> + +#include <asm/mach-rc32434/rc32434.h> + +struct intr_group { + u32 mask; /* mask of valid bits in pending/mask registers */ + volatile u32 *base_addr; +}; + +#define RC32434_NR_IRQS (GROUP4_IRQ_BASE + 32) + +#if (NR_IRQS < RC32434_NR_IRQS) +#error Too little irqs defined. Did you override <asm/irq.h> ? +#endif + +static const struct intr_group intr_group[NUM_INTR_GROUPS] = { + { + .mask = 0x0000efff, + .base_addr = (u32 *) KSEG1ADDR(IC_GROUP0_PEND + 0 * IC_GROUP_OFFSET)}, + { + .mask = 0x00001fff, + .base_addr = (u32 *) KSEG1ADDR(IC_GROUP0_PEND + 1 * IC_GROUP_OFFSET)}, + { + .mask = 0x00000007, + .base_addr = (u32 *) KSEG1ADDR(IC_GROUP0_PEND + 2 * IC_GROUP_OFFSET)}, + { + .mask = 0x0003ffff, + .base_addr = (u32 *) KSEG1ADDR(IC_GROUP0_PEND + 3 * IC_GROUP_OFFSET)}, + { + .mask = 0xffffffff, + .base_addr = (u32 *) KSEG1ADDR(IC_GROUP0_PEND + 4 * IC_GROUP_OFFSET)} +}; + +#define READ_PEND(base) (*(base)) +#define READ_MASK(base) (*(base + 2)) +#define WRITE_MASK(base, val) (*(base + 2) = (val)) + +static inline int irq_to_group(unsigned int irq_nr) +{ + return (irq_nr - GROUP0_IRQ_BASE) >> 5; +} + +static inline int group_to_ip(unsigned int group) +{ + return group + 2; +} + +static inline void enable_local_irq(unsigned int ip) +{ + int ipnum = 0x100 << ip; + + set_c0_status(ipnum); +} + +static inline void disable_local_irq(unsigned int ip) +{ + int ipnum = 0x100 << ip; + + clear_c0_status(ipnum); +} + +static inline void ack_local_irq(unsigned int ip) +{ + int ipnum = 0x100 << ip; + + clear_c0_cause(ipnum); +} + +static void rb532_enable_irq(unsigned int irq_nr) +{ + int ip = irq_nr - GROUP0_IRQ_BASE; + unsigned int group, intr_bit; + volatile unsigned int *addr; + + if (ip < 0) + enable_local_irq(irq_nr); + else { + group = ip >> 5; + + ip &= (1 << 5) - 1; + intr_bit = 1 << ip; + + enable_local_irq(group_to_ip(group)); + + addr = intr_group[group].base_addr; + WRITE_MASK(addr, READ_MASK(addr) & ~intr_bit); + } +} + +static void rb532_disable_irq(unsigned int irq_nr) +{ + int ip = irq_nr - GROUP0_IRQ_BASE; + unsigned int group, intr_bit, mask; + volatile unsigned int *addr; + + if (ip < 0) { + disable_local_irq(irq_nr); + } else { + group = ip >> 5; + + ip &= (1 << 5) - 1; + intr_bit = 1 << ip; + addr = intr_group[group].base_addr; + mask = READ_MASK(addr); + mask |= intr_bit; + WRITE_MASK(addr, mask); + + /* + * if there are no more interrupts enabled in this + * group, disable corresponding IP + */ + if (mask == intr_group[group].mask) + disable_local_irq(group_to_ip(group)); + } +} + +static void rb532_mask_and_ack_irq(unsigned int irq_nr) +{ + rb532_disable_irq(irq_nr); + ack_local_irq(group_to_ip(irq_to_group(irq_nr))); +} + +static struct irq_chip rc32434_irq_type = { + .name = "RB532", + .ack = rb532_disable_irq, + .mask = rb532_disable_irq, + .mask_ack = rb532_mask_and_ack_irq, + .unmask = rb532_enable_irq, +}; + +void __init arch_init_irq(void) +{ + int i; + + pr_info("Initializing IRQ's: %d out of %d\n", RC32434_NR_IRQS, NR_IRQS); + + for (i = 0; i < RC32434_NR_IRQS; i++) + set_irq_chip_and_handler(i, &rc32434_irq_type, + handle_level_irq); +} + +/* Main Interrupt dispatcher */ +asmlinkage void plat_irq_dispatch(void) +{ + unsigned int ip, pend, group; + volatile unsigned int *addr; + unsigned int cp0_cause = read_c0_cause() & read_c0_status(); + + if (cp0_cause & CAUSEF_IP7) { + do_IRQ(7); + } else { + ip = (cp0_cause & 0x7c00); + if (ip) { + group = 21 + (fls(ip) - 32); + + addr = intr_group[group].base_addr; + + pend = READ_PEND(addr); + pend &= ~READ_MASK(addr); /* only unmasked interrupts */ + pend = 39 + (fls(pend) - 32); + do_IRQ((group << 5) + pend); + } + } +} diff --git a/arch/mips/rb532/prom.c b/arch/mips/rb532/prom.c new file mode 100644 index 000000000000..1bc0af8febf4 --- /dev/null +++ b/arch/mips/rb532/prom.c @@ -0,0 +1,158 @@ +/* + * RouterBoard 500 specific prom routines + * + * Copyright (C) 2003, Peter Sadik <peter.sadik@idt.com> + * Copyright (C) 2005-2006, P.Christeas <p_christ@hol.gr> + * Copyright (C) 2007, Gabor Juhos <juhosg@openwrt.org> + * Felix Fietkau <nbd@openwrt.org> + * Florian Fainelli <florian@openwrt.org> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#include <linux/init.h> +#include <linux/mm.h> +#include <linux/module.h> +#include <linux/string.h> +#include <linux/console.h> +#include <linux/bootmem.h> +#include <linux/ioport.h> +#include <linux/blkdev.h> + +#include <asm/bootinfo.h> +#include <asm/mach-rc32434/ddr.h> +#include <asm/mach-rc32434/prom.h> + +extern void __init setup_serial_port(void); + +unsigned int idt_cpu_freq = 132000000; +EXPORT_SYMBOL(idt_cpu_freq); +unsigned int gpio_bootup_state; +EXPORT_SYMBOL(gpio_bootup_state); + +static struct resource ddr_reg[] = { + { + .name = "ddr-reg", + .start = DDR0_PHYS_ADDR, + .end = DDR0_PHYS_ADDR + sizeof(struct ddr_ram), + .flags = IORESOURCE_MEM, + } +}; + +void __init prom_free_prom_memory(void) +{ + /* No prom memory to free */ +} + +static inline int match_tag(char *arg, const char *tag) +{ + return strncmp(arg, tag, strlen(tag)) == 0; +} + +static inline unsigned long tag2ul(char *arg, const char *tag) +{ + char *num; + + num = arg + strlen(tag); + return simple_strtoul(num, 0, 10); +} + +void __init prom_setup_cmdline(void) +{ + char cmd_line[CL_SIZE]; + char *cp, *board; + int prom_argc; + char **prom_argv, **prom_envp; + int i; + + prom_argc = fw_arg0; + prom_argv = (char **) fw_arg1; + prom_envp = (char **) fw_arg2; + + cp = cmd_line; + /* Note: it is common that parameters start + * at argv[1] and not argv[0], + * however, our elf loader starts at [0] */ + for (i = 0; i < prom_argc; i++) { + if (match_tag(prom_argv[i], FREQ_TAG)) { + idt_cpu_freq = tag2ul(prom_argv[i], FREQ_TAG); + continue; + } +#ifdef IGNORE_CMDLINE_MEM + /* parses out the "mem=xx" arg */ + if (match_tag(prom_argv[i], MEM_TAG)) + continue; +#endif + if (i > 0) + *(cp++) = ' '; + if (match_tag(prom_argv[i], BOARD_TAG)) { + board = prom_argv[i] + strlen(BOARD_TAG); + + if (match_tag(board, BOARD_RB532A)) + mips_machtype = MACH_MIKROTIK_RB532A; + else + mips_machtype = MACH_MIKROTIK_RB532; + } + + if (match_tag(prom_argv[i], GPIO_TAG)) + gpio_bootup_state = tag2ul(prom_argv[i], GPIO_TAG); + + strcpy(cp, prom_argv[i]); + cp += strlen(prom_argv[i]); + } + *(cp++) = ' '; + + i = strlen(arcs_cmdline); + if (i > 0) { + *(cp++) = ' '; + strcpy(cp, arcs_cmdline); + cp += strlen(arcs_cmdline); + } + if (gpio_bootup_state & 0x02) + strcpy(cp, GPIO_INIT_NOBUTTON); + else + strcpy(cp, GPIO_INIT_BUTTON); + + cmd_line[CL_SIZE-1] = '\0'; + + strcpy(arcs_cmdline, cmd_line); +} + +void __init prom_init(void) +{ + struct ddr_ram __iomem *ddr; + phys_t memsize; + phys_t ddrbase; + + ddr = ioremap_nocache(ddr_reg[0].start, + ddr_reg[0].end - ddr_reg[0].start); + + if (!ddr) { + printk(KERN_ERR "Unable to remap DDR register\n"); + return; + } + + ddrbase = (phys_t)&ddr->ddrbase; + memsize = (phys_t)&ddr->ddrmask; + memsize = 0 - memsize; + + prom_setup_cmdline(); + + /* give all RAM to boot allocator, + * except for the first 0x400 and the last 0x200 bytes */ + add_memory_region(ddrbase + 0x400, memsize - 0x600, BOOT_MEM_RAM); +} diff --git a/arch/mips/rb532/serial.c b/arch/mips/rb532/serial.c new file mode 100644 index 000000000000..1a05b5ddee09 --- /dev/null +++ b/arch/mips/rb532/serial.c @@ -0,0 +1,53 @@ +/* + * BRIEF MODULE DESCRIPTION + * Serial port initialisation. + * + * Copyright 2004 IDT Inc. (rischelp@idt.com) + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * THIS SOFTWARE IS PROVIDED ``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 AUTHOR 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. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include <linux/init.h> +#include <linux/tty.h> +#include <linux/serial_core.h> +#include <linux/serial_8250.h> + +#include <asm/serial.h> +#include <asm/mach-rc32434/rc32434.h> + +extern unsigned int idt_cpu_freq; + +static struct uart_port rb532_uart = { + .type = PORT_16550A, + .line = 0, + .irq = RC32434_UART0_IRQ, + .iotype = UPIO_MEM, + .membase = (char *)KSEG1ADDR(RC32434_UART0_BASE), + .regshift = 2 +}; + +int __init setup_serial_port(void) +{ + rb532_uart.uartclk = idt_cpu_freq; + + return early_serial_setup(&rb532_uart); +} +arch_initcall(setup_serial_port); diff --git a/arch/mips/rb532/setup.c b/arch/mips/rb532/setup.c new file mode 100644 index 000000000000..7aafa95ac20b --- /dev/null +++ b/arch/mips/rb532/setup.c @@ -0,0 +1,79 @@ +/* + * setup.c - boot time setup code + */ + +#include <linux/init.h> + +#include <asm/bootinfo.h> +#include <asm/reboot.h> +#include <asm/time.h> +#include <linux/ioport.h> + +#include <asm/mach-rc32434/rc32434.h> +#include <asm/mach-rc32434/pci.h> + +struct pci_reg __iomem *pci_reg; +EXPORT_SYMBOL(pci_reg); + +static struct resource pci0_res[] = { + { + .name = "pci_reg0", + .start = PCI0_BASE_ADDR, + .end = PCI0_BASE_ADDR + sizeof(struct pci_reg), + .flags = IORESOURCE_MEM, + } +}; + +static void rb_machine_restart(char *command) +{ + /* just jump to the reset vector */ + writel(0x80000001, (void *)KSEG1ADDR(RC32434_REG_BASE + RC32434_RST)); + ((void (*)(void)) KSEG1ADDR(0x1FC00000u))(); +} + +static void rb_machine_halt(void) +{ + for (;;) + continue; +} + +void __init plat_mem_setup(void) +{ + u32 val; + + _machine_restart = rb_machine_restart; + _machine_halt = rb_machine_halt; + pm_power_off = rb_machine_halt; + + set_io_port_base(KSEG1); + + pci_reg = ioremap_nocache(pci0_res[0].start, + pci0_res[0].end - pci0_res[0].start); + if (!pci_reg) { + printk(KERN_ERR "Could not remap PCI registers\n"); + return; + } + + val = __raw_readl(&pci_reg->pcic); + val &= 0xFFFFFF7; + __raw_writel(val, (void *)&pci_reg->pcic); + +#ifdef CONFIG_PCI + /* Enable PCI interrupts in EPLD Mask register */ + *epld_mask = 0x0; + *(epld_mask + 1) = 0x0; +#endif + write_c0_wired(0); +} + +const char *get_system_type(void) +{ + switch (mips_machtype) { + case MACH_MIKROTIK_RB532A: + return "Mikrotik RB532A"; + break; + default: + return "Mikrotik RB532"; + break; + } +} diff --git a/arch/mips/rb532/time.c b/arch/mips/rb532/time.c new file mode 100644 index 000000000000..db74edf8cefb --- /dev/null +++ b/arch/mips/rb532/time.c @@ -0,0 +1,67 @@ +/* + * Carsten Langgaard, carstenl@mips.com + * Copyright (C) 1999,2000 MIPS Technologies, Inc. All rights reserved. + * + * This program is free software; you can distribute 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 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. + * + * Setting up the clock on the MIPS boards. + */ + +#include <linux/init.h> +#include <linux/kernel_stat.h> +#include <linux/ptrace.h> +#include <linux/sched.h> +#include <linux/spinlock.h> +#include <linux/mc146818rtc.h> +#include <linux/irq.h> +#include <linux/timex.h> + +#include <asm/mipsregs.h> +#include <asm/debug.h> +#include <asm/time.h> +#include <asm/mach-rc32434/rc32434.h> + +extern unsigned int idt_cpu_freq; + +/* + * Figure out the r4k offset, the amount to increment the compare + * register for each time tick. There is no RTC available. + * + * The RC32434 counts at half the CPU *core* speed. + */ +static unsigned long __init cal_r4koff(void) +{ + mips_hpt_frequency = idt_cpu_freq * IDT_CLOCK_MULT / 2; + + return mips_hpt_frequency / HZ; +} + +void __init plat_time_init(void) +{ + unsigned int est_freq, flags; + unsigned long r4k_offset; + + local_irq_save(flags); + + printk(KERN_INFO "calculating r4koff... "); + r4k_offset = cal_r4koff(); + printk("%08lx(%d)\n", r4k_offset, (int) r4k_offset); + + est_freq = 2 * r4k_offset * HZ; + est_freq += 5000; /* round */ + est_freq -= est_freq % 10000; + printk(KERN_INFO "CPU frequency %d.%02d MHz\n", est_freq / 1000000, + (est_freq % 1000000) * 100 / 1000000); + local_irq_restore(flags); +} diff --git a/arch/mips/sgi-ip22/ip22-platform.c b/arch/mips/sgi-ip22/ip22-platform.c index fc6df96305ed..60141235ec40 100644 --- a/arch/mips/sgi-ip22/ip22-platform.c +++ b/arch/mips/sgi-ip22/ip22-platform.c @@ -188,8 +188,7 @@ static int __init sgi_button_devinit(void) if (ip22_is_fullhouse()) return 0; /* full house has no volume buttons */ - return IS_ERR(platform_device_register_simple("sgiindybtns", - -1, NULL, 0)); + return IS_ERR(platform_device_register_simple("sgibtns", -1, NULL, 0)); } device_initcall(sgi_button_devinit); diff --git a/arch/mips/sgi-ip22/ip28-berr.c b/arch/mips/sgi-ip22/ip28-berr.c index fee7a2e0e538..30e12e2ec4b5 100644 --- a/arch/mips/sgi-ip22/ip28-berr.c +++ b/arch/mips/sgi-ip22/ip28-berr.c @@ -412,7 +412,7 @@ static int ip28_be_interrupt(const struct pt_regs *regs) * Now we have an asynchronous bus error, speculatively or DMA caused. * Need to search all DMA descriptors for the error address. */ - for (i = 0; i < ARRAY_SIZE(hpc3); ++i) { + for (i = 0; i < sizeof(hpc3)/sizeof(struct hpc3_stat); ++i) { struct hpc3_stat *hp = (struct hpc3_stat *)&hpc3 + i; if ((cpu_err_stat & CPU_ERRMASK) && (cpu_err_addr == hp->ndptr || cpu_err_addr == hp->cbp)) @@ -421,7 +421,7 @@ static int ip28_be_interrupt(const struct pt_regs *regs) (gio_err_addr == hp->ndptr || gio_err_addr == hp->cbp)) break; } - if (i < ARRAY_SIZE(hpc3)) { + if (i < sizeof(hpc3)/sizeof(struct hpc3_stat)) { struct hpc3_stat *hp = (struct hpc3_stat *)&hpc3 + i; printk(KERN_ERR "at DMA addresses: HPC3 @ %08lx:" " ctl %08x, ndp %08x, cbp %08x\n", diff --git a/arch/mips/sgi-ip32/ip32-platform.c b/arch/mips/sgi-ip32/ip32-platform.c index 2ee401ba0b25..3d63721e0e80 100644 --- a/arch/mips/sgi-ip32/ip32-platform.c +++ b/arch/mips/sgi-ip32/ip32-platform.c @@ -85,18 +85,7 @@ device_initcall(sgio2audio_devinit); static __init int sgio2btns_devinit(void) { - struct platform_device *pd; - int ret; - - pd = platform_device_alloc("sgio2btns", -1); - if (!pd) - return -ENOMEM; - - ret = platform_device_add(pd); - if (ret) - platform_device_put(pd); - - return ret; + return IS_ERR(platform_device_register_simple("sgibtns", -1, NULL, 0)); } device_initcall(sgio2btns_devinit); diff --git a/arch/mips/txx9/Kconfig b/arch/mips/txx9/Kconfig index b92a134ef124..6de4c5aa92be 100644 --- a/arch/mips/txx9/Kconfig +++ b/arch/mips/txx9/Kconfig @@ -7,6 +7,8 @@ config TOSHIBA_RBTX4927 bool "Toshiba RBTX49[23]7 board" depends on MACH_TX49XX select SOC_TX4927 + # TX4937 is subset of TX4938 + select SOC_TX4938 help This Toshiba board is based on the TX4927 processor. Say Y here to support this machine type diff --git a/arch/mips/txx9/generic/Makefile b/arch/mips/txx9/generic/Makefile index 668fdaad6448..9c120771e65f 100644 --- a/arch/mips/txx9/generic/Makefile +++ b/arch/mips/txx9/generic/Makefile @@ -4,8 +4,8 @@ obj-y += setup.o obj-$(CONFIG_PCI) += pci.o -obj-$(CONFIG_SOC_TX4927) += mem_tx4927.o irq_tx4927.o -obj-$(CONFIG_SOC_TX4938) += mem_tx4938.o irq_tx4938.o +obj-$(CONFIG_SOC_TX4927) += mem_tx4927.o setup_tx4927.o irq_tx4927.o +obj-$(CONFIG_SOC_TX4938) += mem_tx4927.o setup_tx4938.o irq_tx4938.o obj-$(CONFIG_TOSHIBA_FPCIB0) += smsc_fdc37m81x.o obj-$(CONFIG_KGDB) += dbgio.o diff --git a/arch/mips/txx9/generic/irq_tx4927.c b/arch/mips/txx9/generic/irq_tx4927.c index 6377bd8a9050..cbea1fdde82b 100644 --- a/arch/mips/txx9/generic/irq_tx4927.c +++ b/arch/mips/txx9/generic/irq_tx4927.c @@ -31,7 +31,7 @@ void __init tx4927_irq_init(void) { mips_cpu_irq_init(); - txx9_irq_init(TX4927_IRC_REG); + txx9_irq_init(TX4927_IRC_REG & 0xfffffffffULL); set_irq_chained_handler(MIPS_CPU_IRQ_BASE + TX4927_IRC_INT, handle_simple_irq); } diff --git a/arch/mips/txx9/generic/irq_tx4938.c b/arch/mips/txx9/generic/irq_tx4938.c index 5fc86c9c9d2f..6eac684bf190 100644 --- a/arch/mips/txx9/generic/irq_tx4938.c +++ b/arch/mips/txx9/generic/irq_tx4938.c @@ -19,7 +19,7 @@ void __init tx4938_irq_init(void) { mips_cpu_irq_init(); - txx9_irq_init(TX4938_IRC_REG); + txx9_irq_init(TX4938_IRC_REG & 0xfffffffffULL); set_irq_chained_handler(MIPS_CPU_IRQ_BASE + TX4938_IRC_INT, handle_simple_irq); } diff --git a/arch/mips/txx9/generic/mem_tx4927.c b/arch/mips/txx9/generic/mem_tx4927.c index 12dfc377bf2f..ef6ea6e97873 100644 --- a/arch/mips/txx9/generic/mem_tx4927.c +++ b/arch/mips/txx9/generic/mem_tx4927.c @@ -1,5 +1,5 @@ /* - * linux/arch/mips/tx4927/common/tx4927_prom.c + * linux/arch/mips/txx9/generic/mem_tx4927.c * * common tx4927 memory interface * @@ -32,8 +32,9 @@ #include <linux/init.h> #include <linux/types.h> #include <linux/io.h> +#include <asm/txx9/tx4927.h> -static unsigned int __init tx4927_process_sdccr(unsigned long addr) +static unsigned int __init tx4927_process_sdccr(u64 __iomem *addr) { u64 val; unsigned int sdccr_ce; @@ -45,97 +46,32 @@ static unsigned int __init tx4927_process_sdccr(unsigned long addr) unsigned int rs = 0; unsigned int cs = 0; unsigned int mw = 0; - unsigned int msize = 0; - val = __raw_readq((void __iomem *)addr); + val = __raw_readq(addr); /* MVMCP -- need #defs for these bits masks */ sdccr_ce = ((val & (1 << 10)) >> 10); sdccr_bs = ((val & (1 << 8)) >> 8); sdccr_rs = ((val & (3 << 5)) >> 5); - sdccr_cs = ((val & (3 << 2)) >> 2); + sdccr_cs = ((val & (7 << 2)) >> 2); sdccr_mw = ((val & (1 << 0)) >> 0); if (sdccr_ce) { - switch (sdccr_bs) { - case 0:{ - bs = 2; - break; - } - case 1:{ - bs = 4; - break; - } - } - switch (sdccr_rs) { - case 0:{ - rs = 2048; - break; - } - case 1:{ - rs = 4096; - break; - } - case 2:{ - rs = 8192; - break; - } - case 3:{ - rs = 0; - break; - } - } - switch (sdccr_cs) { - case 0:{ - cs = 256; - break; - } - case 1:{ - cs = 512; - break; - } - case 2:{ - cs = 1024; - break; - } - case 3:{ - cs = 2048; - break; - } - } - switch (sdccr_mw) { - case 0:{ - mw = 8; - break; - } /* 8 bytes = 64 bits */ - case 1:{ - mw = 4; - break; - } /* 4 bytes = 32 bits */ - } + bs = 2 << sdccr_bs; + rs = 2048 << sdccr_rs; + cs = 256 << sdccr_cs; + mw = 8 >> sdccr_mw; } - /* bytes per chip MB per chip num chips */ - msize = (((rs * cs * mw) / (1024 * 1024)) * bs); - - return (msize); + return rs * cs * mw * bs; } - unsigned int __init tx4927_get_mem_size(void) { - unsigned int c0; - unsigned int c1; - unsigned int c2; - unsigned int c3; - unsigned int total; - - /* MVMCP -- need #defs for these registers */ - c0 = tx4927_process_sdccr(0xff1f8000); - c1 = tx4927_process_sdccr(0xff1f8008); - c2 = tx4927_process_sdccr(0xff1f8010); - c3 = tx4927_process_sdccr(0xff1f8018); - total = c0 + c1 + c2 + c3; + unsigned int total = 0; + int i; - return (total); + for (i = 0; i < ARRAY_SIZE(tx4927_sdramcptr->cr); i++) + total += tx4927_process_sdccr(&tx4927_sdramcptr->cr[i]); + return total; } diff --git a/arch/mips/txx9/generic/mem_tx4938.c b/arch/mips/txx9/generic/mem_tx4938.c deleted file mode 100644 index 20baeaeba4cd..000000000000 --- a/arch/mips/txx9/generic/mem_tx4938.c +++ /dev/null @@ -1,124 +0,0 @@ -/* - * linux/arch/mips/tx4938/common/prom.c - * - * common tx4938 memory interface - * Copyright (C) 2000-2001 Toshiba Corporation - * - * 2003-2005 (c) MontaVista Software, Inc. This file is licensed under the - * terms of the GNU General Public License version 2. This program is - * licensed "as is" without any warranty of any kind, whether express - * or implied. - * - * Support for TX4938 in 2.6 - Manish Lachwani (mlachwani@mvista.com) - */ - -#include <linux/init.h> -#include <linux/types.h> -#include <linux/io.h> - -static unsigned int __init -tx4938_process_sdccr(u64 * addr) -{ - u64 val; - unsigned int sdccr_ce; - unsigned int sdccr_rs; - unsigned int sdccr_cs; - unsigned int sdccr_mw; - unsigned int rs = 0; - unsigned int cs = 0; - unsigned int mw = 0; - unsigned int bc = 4; - unsigned int msize = 0; - - val = ____raw_readq((void __iomem *)addr); - - /* MVMCP -- need #defs for these bits masks */ - sdccr_ce = ((val & (1 << 10)) >> 10); - sdccr_rs = ((val & (3 << 5)) >> 5); - sdccr_cs = ((val & (7 << 2)) >> 2); - sdccr_mw = ((val & (1 << 0)) >> 0); - - if (sdccr_ce) { - switch (sdccr_rs) { - case 0:{ - rs = 2048; - break; - } - case 1:{ - rs = 4096; - break; - } - case 2:{ - rs = 8192; - break; - } - default:{ - rs = 0; - break; - } - } - switch (sdccr_cs) { - case 0:{ - cs = 256; - break; - } - case 1:{ - cs = 512; - break; - } - case 2:{ - cs = 1024; - break; - } - case 3:{ - cs = 2048; - break; - } - case 4:{ - cs = 4096; - break; - } - default:{ - cs = 0; - break; - } - } - switch (sdccr_mw) { - case 0:{ - mw = 8; - break; - } /* 8 bytes = 64 bits */ - case 1:{ - mw = 4; - break; - } /* 4 bytes = 32 bits */ - } - } - - /* bytes per chip MB per chip bank count */ - msize = (((rs * cs * mw) / (1024 * 1024)) * (bc)); - - /* MVMCP -- bc hard coded to 4 from table 9.3.1 */ - /* boad supports bc=2 but no way to detect */ - - return (msize); -} - -unsigned int __init -tx4938_get_mem_size(void) -{ - unsigned int c0; - unsigned int c1; - unsigned int c2; - unsigned int c3; - unsigned int total; - - /* MVMCP -- need #defs for these registers */ - c0 = tx4938_process_sdccr((u64 *) 0xff1f8000); - c1 = tx4938_process_sdccr((u64 *) 0xff1f8008); - c2 = tx4938_process_sdccr((u64 *) 0xff1f8010); - c3 = tx4938_process_sdccr((u64 *) 0xff1f8018); - total = c0 + c1 + c2 + c3; - - return (total); -} diff --git a/arch/mips/txx9/generic/setup.c b/arch/mips/txx9/generic/setup.c index 5afc5d5cab03..8c60c78b9a9e 100644 --- a/arch/mips/txx9/generic/setup.c +++ b/arch/mips/txx9/generic/setup.c @@ -19,7 +19,9 @@ #include <linux/module.h> #include <linux/clk.h> #include <linux/err.h> +#include <linux/gpio.h> #include <asm/bootinfo.h> +#include <asm/time.h> #include <asm/txx9/generic.h> #ifdef CONFIG_CPU_TX49XX #include <asm/txx9/tx4938.h> @@ -30,6 +32,7 @@ struct resource txx9_ce_res[8]; static char txx9_ce_res_name[8][4]; /* "CEn" */ /* pcode, internal register */ +unsigned int txx9_pcode; char txx9_pcode_str[8]; static struct resource txx9_reg_res = { .name = txx9_pcode_str, @@ -59,15 +62,16 @@ unsigned int txx9_master_clock; unsigned int txx9_cpu_clock; unsigned int txx9_gbus_clock; +int txx9_ccfg_toeon __initdata = 1; /* Minimum CLK support */ struct clk *clk_get(struct device *dev, const char *id) { if (!strcmp(id, "spi-baseclk")) - return (struct clk *)(txx9_gbus_clock / 2 / 4); + return (struct clk *)((unsigned long)txx9_gbus_clock / 2 / 4); if (!strcmp(id, "imbus_clk")) - return (struct clk *)(txx9_gbus_clock / 2); + return (struct clk *)((unsigned long)txx9_gbus_clock / 2); return ERR_PTR(-ENOENT); } EXPORT_SYMBOL(clk_get); @@ -94,6 +98,22 @@ void clk_put(struct clk *clk) } EXPORT_SYMBOL(clk_put); +/* GPIO support */ + +#ifdef CONFIG_GENERIC_GPIO +int gpio_to_irq(unsigned gpio) +{ + return -EINVAL; +} +EXPORT_SYMBOL(gpio_to_irq); + +int irq_to_gpio(unsigned irq) +{ + return -EINVAL; +} +EXPORT_SYMBOL(irq_to_gpio); +#endif + extern struct txx9_board_vec jmr3927_vec; extern struct txx9_board_vec rbtx4927_vec; extern struct txx9_board_vec rbtx4937_vec; @@ -107,6 +127,12 @@ void __init prom_init_cmdline(void) int argc = (int)fw_arg0; char **argv = (char **)fw_arg1; int i; /* Always ignore the "-c" at argv[0] */ +#ifdef CONFIG_64BIT + char *fixed_argv[32]; + for (i = 0; i < argc; i++) + fixed_argv[i] = (char *)(long)(*((__s32 *)argv + i)); + argv = fixed_argv; +#endif /* ignore all built-in args if any f/w args given */ if (argc > 1) @@ -126,15 +152,19 @@ void __init prom_init(void) #endif #ifdef CONFIG_CPU_TX49XX switch (TX4938_REV_PCODE()) { +#ifdef CONFIG_TOSHIBA_RBTX4927 case 0x4927: txx9_board_vec = &rbtx4927_vec; break; case 0x4937: txx9_board_vec = &rbtx4937_vec; break; +#endif +#ifdef CONFIG_TOSHIBA_RBTX4938 case 0x4938: txx9_board_vec = &rbtx4938_vec; break; +#endif } #endif @@ -160,6 +190,10 @@ char * __init prom_getcmdline(void) /* wrappers */ void __init plat_mem_setup(void) { + ioport_resource.start = 0; + ioport_resource.end = ~0UL; /* no limit */ + iomem_resource.start = 0; + iomem_resource.end = ~0UL; /* no limit */ txx9_board_vec->mem_setup(); } diff --git a/arch/mips/txx9/generic/setup_tx4927.c b/arch/mips/txx9/generic/setup_tx4927.c new file mode 100644 index 000000000000..89d6e28add93 --- /dev/null +++ b/arch/mips/txx9/generic/setup_tx4927.c @@ -0,0 +1,194 @@ +/* + * TX4927 setup routines + * Based on linux/arch/mips/txx9/rbtx4938/setup.c, + * and RBTX49xx patch from CELF patch archive. + * + * 2003-2005 (c) MontaVista Software, Inc. + * (C) Copyright TOSHIBA CORPORATION 2000-2001, 2004-2007 + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + */ +#include <linux/init.h> +#include <linux/ioport.h> +#include <linux/delay.h> +#include <linux/serial_core.h> +#include <linux/param.h> +#include <asm/txx9irq.h> +#include <asm/txx9tmr.h> +#include <asm/txx9pio.h> +#include <asm/txx9/generic.h> +#include <asm/txx9/tx4927.h> + +void __init tx4927_wdr_init(void) +{ + /* clear WatchDogReset (W1C) */ + tx4927_ccfg_set(TX4927_CCFG_WDRST); + /* do reset on watchdog */ + tx4927_ccfg_set(TX4927_CCFG_WR); +} + +static struct resource tx4927_sdram_resource[4]; + +void __init tx4927_setup(void) +{ + int i; + __u32 divmode; + int cpuclk = 0; + u64 ccfg; + + txx9_reg_res_init(TX4927_REV_PCODE(), TX4927_REG_BASE, + TX4927_REG_SIZE); + + /* SDRAMC,EBUSC are configured by PROM */ + for (i = 0; i < 8; i++) { + if (!(TX4927_EBUSC_CR(i) & 0x8)) + continue; /* disabled */ + txx9_ce_res[i].start = (unsigned long)TX4927_EBUSC_BA(i); + txx9_ce_res[i].end = + txx9_ce_res[i].start + TX4927_EBUSC_SIZE(i) - 1; + request_resource(&iomem_resource, &txx9_ce_res[i]); + } + + /* clocks */ + ccfg = ____raw_readq(&tx4927_ccfgptr->ccfg); + if (txx9_master_clock) { + /* calculate gbus_clock and cpu_clock from master_clock */ + divmode = (__u32)ccfg & TX4927_CCFG_DIVMODE_MASK; + switch (divmode) { + case TX4927_CCFG_DIVMODE_8: + case TX4927_CCFG_DIVMODE_10: + case TX4927_CCFG_DIVMODE_12: + case TX4927_CCFG_DIVMODE_16: + txx9_gbus_clock = txx9_master_clock * 4; break; + default: + txx9_gbus_clock = txx9_master_clock; + } + switch (divmode) { + case TX4927_CCFG_DIVMODE_2: + case TX4927_CCFG_DIVMODE_8: + cpuclk = txx9_gbus_clock * 2; break; + case TX4927_CCFG_DIVMODE_2_5: + case TX4927_CCFG_DIVMODE_10: + cpuclk = txx9_gbus_clock * 5 / 2; break; + case TX4927_CCFG_DIVMODE_3: + case TX4927_CCFG_DIVMODE_12: + cpuclk = txx9_gbus_clock * 3; break; + case TX4927_CCFG_DIVMODE_4: + case TX4927_CCFG_DIVMODE_16: + cpuclk = txx9_gbus_clock * 4; break; + } + txx9_cpu_clock = cpuclk; + } else { + if (txx9_cpu_clock == 0) + txx9_cpu_clock = 200000000; /* 200MHz */ + /* calculate gbus_clock and master_clock from cpu_clock */ + cpuclk = txx9_cpu_clock; + divmode = (__u32)ccfg & TX4927_CCFG_DIVMODE_MASK; + switch (divmode) { + case TX4927_CCFG_DIVMODE_2: + case TX4927_CCFG_DIVMODE_8: + txx9_gbus_clock = cpuclk / 2; break; + case TX4927_CCFG_DIVMODE_2_5: + case TX4927_CCFG_DIVMODE_10: + txx9_gbus_clock = cpuclk * 2 / 5; break; + case TX4927_CCFG_DIVMODE_3: + case TX4927_CCFG_DIVMODE_12: + txx9_gbus_clock = cpuclk / 3; break; + case TX4927_CCFG_DIVMODE_4: + case TX4927_CCFG_DIVMODE_16: + txx9_gbus_clock = cpuclk / 4; break; + } + switch (divmode) { + case TX4927_CCFG_DIVMODE_8: + case TX4927_CCFG_DIVMODE_10: + case TX4927_CCFG_DIVMODE_12: + case TX4927_CCFG_DIVMODE_16: + txx9_master_clock = txx9_gbus_clock / 4; break; + default: + txx9_master_clock = txx9_gbus_clock; + } + } + /* change default value to udelay/mdelay take reasonable time */ + loops_per_jiffy = txx9_cpu_clock / HZ / 2; + + /* CCFG */ + tx4927_wdr_init(); + /* clear BusErrorOnWrite flag (W1C) */ + tx4927_ccfg_set(TX4927_CCFG_BEOW); + /* enable Timeout BusError */ + if (txx9_ccfg_toeon) + tx4927_ccfg_set(TX4927_CCFG_TOE); + + /* DMA selection */ + txx9_clear64(&tx4927_ccfgptr->pcfg, TX4927_PCFG_DMASEL_ALL); + + /* Use external clock for external arbiter */ + if (!(____raw_readq(&tx4927_ccfgptr->ccfg) & TX4927_CCFG_PCIARB)) + txx9_clear64(&tx4927_ccfgptr->pcfg, TX4927_PCFG_PCICLKEN_ALL); + + printk(KERN_INFO "%s -- %dMHz(M%dMHz) CRIR:%08x CCFG:%llx PCFG:%llx\n", + txx9_pcode_str, + (cpuclk + 500000) / 1000000, + (txx9_master_clock + 500000) / 1000000, + (__u32)____raw_readq(&tx4927_ccfgptr->crir), + (unsigned long long)____raw_readq(&tx4927_ccfgptr->ccfg), + (unsigned long long)____raw_readq(&tx4927_ccfgptr->pcfg)); + + printk(KERN_INFO "%s SDRAMC --", txx9_pcode_str); + for (i = 0; i < 4; i++) { + __u64 cr = TX4927_SDRAMC_CR(i); + unsigned long base, size; + if (!((__u32)cr & 0x00000400)) + continue; /* disabled */ + base = (unsigned long)(cr >> 49) << 21; + size = (((unsigned long)(cr >> 33) & 0x7fff) + 1) << 21; + printk(" CR%d:%016llx", i, (unsigned long long)cr); + tx4927_sdram_resource[i].name = "SDRAM"; + tx4927_sdram_resource[i].start = base; + tx4927_sdram_resource[i].end = base + size - 1; + tx4927_sdram_resource[i].flags = IORESOURCE_MEM; + request_resource(&iomem_resource, &tx4927_sdram_resource[i]); + } + printk(" TR:%09llx\n", + (unsigned long long)____raw_readq(&tx4927_sdramcptr->tr)); + + /* TMR */ + /* disable all timers */ + for (i = 0; i < TX4927_NR_TMR; i++) + txx9_tmr_init(TX4927_TMR_REG(i) & 0xfffffffffULL); + + /* PIO */ + txx9_gpio_init(TX4927_PIO_REG & 0xfffffffffULL, 0, TX4927_NUM_PIO); + __raw_writel(0, &tx4927_pioptr->maskcpu); + __raw_writel(0, &tx4927_pioptr->maskext); +} + +void __init tx4927_time_init(unsigned int tmrnr) +{ + if (____raw_readq(&tx4927_ccfgptr->ccfg) & TX4927_CCFG_TINTDIS) + txx9_clockevent_init(TX4927_TMR_REG(tmrnr) & 0xfffffffffULL, + TXX9_IRQ_BASE + TX4927_IR_TMR(tmrnr), + TXX9_IMCLK); +} + +void __init tx4927_setup_serial(void) +{ +#ifdef CONFIG_SERIAL_TXX9 + int i; + struct uart_port req; + + for (i = 0; i < 2; i++) { + memset(&req, 0, sizeof(req)); + req.line = i; + req.iotype = UPIO_MEM; + req.membase = (unsigned char __iomem *)TX4927_SIO_REG(i); + req.mapbase = TX4927_SIO_REG(i) & 0xfffffffffULL; + req.irq = TXX9_IRQ_BASE + TX4927_IR_SIO(i); + req.flags |= UPF_BUGGY_UART /*HAVE_CTS_LINE*/; + req.uartclk = TXX9_IMCLK; + early_serial_txx9_setup(&req); + } +#endif /* CONFIG_SERIAL_TXX9 */ +} diff --git a/arch/mips/txx9/generic/setup_tx4938.c b/arch/mips/txx9/generic/setup_tx4938.c new file mode 100644 index 000000000000..317378d8579d --- /dev/null +++ b/arch/mips/txx9/generic/setup_tx4938.c @@ -0,0 +1,259 @@ +/* + * TX4938/4937 setup routines + * Based on linux/arch/mips/txx9/rbtx4938/setup.c, + * and RBTX49xx patch from CELF patch archive. + * + * 2003-2005 (c) MontaVista Software, Inc. + * (C) Copyright TOSHIBA CORPORATION 2000-2001, 2004-2007 + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + */ +#include <linux/init.h> +#include <linux/ioport.h> +#include <linux/delay.h> +#include <linux/serial_core.h> +#include <linux/param.h> +#include <asm/txx9irq.h> +#include <asm/txx9tmr.h> +#include <asm/txx9pio.h> +#include <asm/txx9/generic.h> +#include <asm/txx9/tx4938.h> + +void __init tx4938_wdr_init(void) +{ + /* clear WatchDogReset (W1C) */ + tx4938_ccfg_set(TX4938_CCFG_WDRST); + /* do reset on watchdog */ + tx4938_ccfg_set(TX4938_CCFG_WR); +} + +static struct resource tx4938_sdram_resource[4]; +static struct resource tx4938_sram_resource; + +#define TX4938_SRAM_SIZE 0x800 + +void __init tx4938_setup(void) +{ + int i; + __u32 divmode; + int cpuclk = 0; + u64 ccfg; + + txx9_reg_res_init(TX4938_REV_PCODE(), TX4938_REG_BASE, + TX4938_REG_SIZE); + + /* SDRAMC,EBUSC are configured by PROM */ + for (i = 0; i < 8; i++) { + if (!(TX4938_EBUSC_CR(i) & 0x8)) + continue; /* disabled */ + txx9_ce_res[i].start = (unsigned long)TX4938_EBUSC_BA(i); + txx9_ce_res[i].end = + txx9_ce_res[i].start + TX4938_EBUSC_SIZE(i) - 1; + request_resource(&iomem_resource, &txx9_ce_res[i]); + } + + /* clocks */ + ccfg = ____raw_readq(&tx4938_ccfgptr->ccfg); + if (txx9_master_clock) { + /* calculate gbus_clock and cpu_clock from master_clock */ + divmode = (__u32)ccfg & TX4938_CCFG_DIVMODE_MASK; + switch (divmode) { + case TX4938_CCFG_DIVMODE_8: + case TX4938_CCFG_DIVMODE_10: + case TX4938_CCFG_DIVMODE_12: + case TX4938_CCFG_DIVMODE_16: + case TX4938_CCFG_DIVMODE_18: + txx9_gbus_clock = txx9_master_clock * 4; break; + default: + txx9_gbus_clock = txx9_master_clock; + } + switch (divmode) { + case TX4938_CCFG_DIVMODE_2: + case TX4938_CCFG_DIVMODE_8: + cpuclk = txx9_gbus_clock * 2; break; + case TX4938_CCFG_DIVMODE_2_5: + case TX4938_CCFG_DIVMODE_10: + cpuclk = txx9_gbus_clock * 5 / 2; break; + case TX4938_CCFG_DIVMODE_3: + case TX4938_CCFG_DIVMODE_12: + cpuclk = txx9_gbus_clock * 3; break; + case TX4938_CCFG_DIVMODE_4: + case TX4938_CCFG_DIVMODE_16: + cpuclk = txx9_gbus_clock * 4; break; + case TX4938_CCFG_DIVMODE_4_5: + case TX4938_CCFG_DIVMODE_18: + cpuclk = txx9_gbus_clock * 9 / 2; break; + } + txx9_cpu_clock = cpuclk; + } else { + if (txx9_cpu_clock == 0) + txx9_cpu_clock = 300000000; /* 300MHz */ + /* calculate gbus_clock and master_clock from cpu_clock */ + cpuclk = txx9_cpu_clock; + divmode = (__u32)ccfg & TX4938_CCFG_DIVMODE_MASK; + switch (divmode) { + case TX4938_CCFG_DIVMODE_2: + case TX4938_CCFG_DIVMODE_8: + txx9_gbus_clock = cpuclk / 2; break; + case TX4938_CCFG_DIVMODE_2_5: + case TX4938_CCFG_DIVMODE_10: + txx9_gbus_clock = cpuclk * 2 / 5; break; + case TX4938_CCFG_DIVMODE_3: + case TX4938_CCFG_DIVMODE_12: + txx9_gbus_clock = cpuclk / 3; break; + case TX4938_CCFG_DIVMODE_4: + case TX4938_CCFG_DIVMODE_16: + txx9_gbus_clock = cpuclk / 4; break; + case TX4938_CCFG_DIVMODE_4_5: + case TX4938_CCFG_DIVMODE_18: + txx9_gbus_clock = cpuclk * 2 / 9; break; + } + switch (divmode) { + case TX4938_CCFG_DIVMODE_8: + case TX4938_CCFG_DIVMODE_10: + case TX4938_CCFG_DIVMODE_12: + case TX4938_CCFG_DIVMODE_16: + case TX4938_CCFG_DIVMODE_18: + txx9_master_clock = txx9_gbus_clock / 4; break; + default: + txx9_master_clock = txx9_gbus_clock; + } + } + /* change default value to udelay/mdelay take reasonable time */ + loops_per_jiffy = txx9_cpu_clock / HZ / 2; + + /* CCFG */ + tx4938_wdr_init(); + /* clear BusErrorOnWrite flag (W1C) */ + tx4938_ccfg_set(TX4938_CCFG_BEOW); + /* enable Timeout BusError */ + if (txx9_ccfg_toeon) + tx4938_ccfg_set(TX4938_CCFG_TOE); + + /* DMA selection */ + txx9_clear64(&tx4938_ccfgptr->pcfg, TX4938_PCFG_DMASEL_ALL); + + /* Use external clock for external arbiter */ + if (!(____raw_readq(&tx4938_ccfgptr->ccfg) & TX4938_CCFG_PCIARB)) + txx9_clear64(&tx4938_ccfgptr->pcfg, TX4938_PCFG_PCICLKEN_ALL); + + printk(KERN_INFO "%s -- %dMHz(M%dMHz) CRIR:%08x CCFG:%llx PCFG:%llx\n", + txx9_pcode_str, + (cpuclk + 500000) / 1000000, + (txx9_master_clock + 500000) / 1000000, + (__u32)____raw_readq(&tx4938_ccfgptr->crir), + (unsigned long long)____raw_readq(&tx4938_ccfgptr->ccfg), + (unsigned long long)____raw_readq(&tx4938_ccfgptr->pcfg)); + + printk(KERN_INFO "%s SDRAMC --", txx9_pcode_str); + for (i = 0; i < 4; i++) { + __u64 cr = TX4938_SDRAMC_CR(i); + unsigned long base, size; + if (!((__u32)cr & 0x00000400)) + continue; /* disabled */ + base = (unsigned long)(cr >> 49) << 21; + size = (((unsigned long)(cr >> 33) & 0x7fff) + 1) << 21; + printk(" CR%d:%016llx", i, (unsigned long long)cr); + tx4938_sdram_resource[i].name = "SDRAM"; + tx4938_sdram_resource[i].start = base; + tx4938_sdram_resource[i].end = base + size - 1; + tx4938_sdram_resource[i].flags = IORESOURCE_MEM; + request_resource(&iomem_resource, &tx4938_sdram_resource[i]); + } + printk(" TR:%09llx\n", + (unsigned long long)____raw_readq(&tx4938_sdramcptr->tr)); + + /* SRAM */ + if (txx9_pcode == 0x4938 && ____raw_readq(&tx4938_sramcptr->cr) & 1) { + unsigned int size = TX4938_SRAM_SIZE; + tx4938_sram_resource.name = "SRAM"; + tx4938_sram_resource.start = + (____raw_readq(&tx4938_sramcptr->cr) >> (39-11)) + & ~(size - 1); + tx4938_sram_resource.end = + tx4938_sram_resource.start + TX4938_SRAM_SIZE - 1; + tx4938_sram_resource.flags = IORESOURCE_MEM; + request_resource(&iomem_resource, &tx4938_sram_resource); + } + + /* TMR */ + /* disable all timers */ + for (i = 0; i < TX4938_NR_TMR; i++) + txx9_tmr_init(TX4938_TMR_REG(i) & 0xfffffffffULL); + + /* DMA */ + for (i = 0; i < 2; i++) + ____raw_writeq(TX4938_DMA_MCR_MSTEN, + (void __iomem *)(TX4938_DMA_REG(i) + 0x50)); + + /* PIO */ + txx9_gpio_init(TX4938_PIO_REG & 0xfffffffffULL, 0, TX4938_NUM_PIO); + __raw_writel(0, &tx4938_pioptr->maskcpu); + __raw_writel(0, &tx4938_pioptr->maskext); + + if (txx9_pcode == 0x4938) { + __u64 pcfg = ____raw_readq(&tx4938_ccfgptr->pcfg); + /* set PCIC1 reset */ + txx9_set64(&tx4938_ccfgptr->clkctr, TX4938_CLKCTR_PCIC1RST); + if (pcfg & (TX4938_PCFG_ETH0_SEL | TX4938_PCFG_ETH1_SEL)) { + mdelay(1); /* at least 128 cpu clock */ + /* clear PCIC1 reset */ + txx9_clear64(&tx4938_ccfgptr->clkctr, + TX4938_CLKCTR_PCIC1RST); + } else { + printk(KERN_INFO "%s: stop PCIC1\n", txx9_pcode_str); + /* stop PCIC1 */ + txx9_set64(&tx4938_ccfgptr->clkctr, + TX4938_CLKCTR_PCIC1CKD); + } + if (!(pcfg & TX4938_PCFG_ETH0_SEL)) { + printk(KERN_INFO "%s: stop ETH0\n", txx9_pcode_str); + txx9_set64(&tx4938_ccfgptr->clkctr, + TX4938_CLKCTR_ETH0RST); + txx9_set64(&tx4938_ccfgptr->clkctr, + TX4938_CLKCTR_ETH0CKD); + } + if (!(pcfg & TX4938_PCFG_ETH1_SEL)) { + printk(KERN_INFO "%s: stop ETH1\n", txx9_pcode_str); + txx9_set64(&tx4938_ccfgptr->clkctr, + TX4938_CLKCTR_ETH1RST); + txx9_set64(&tx4938_ccfgptr->clkctr, + TX4938_CLKCTR_ETH1CKD); + } + } +} + +void __init tx4938_time_init(unsigned int tmrnr) +{ + if (____raw_readq(&tx4938_ccfgptr->ccfg) & TX4938_CCFG_TINTDIS) + txx9_clockevent_init(TX4938_TMR_REG(tmrnr) & 0xfffffffffULL, + TXX9_IRQ_BASE + TX4938_IR_TMR(tmrnr), + TXX9_IMCLK); +} + +void __init tx4938_setup_serial(void) +{ +#ifdef CONFIG_SERIAL_TXX9 + int i; + struct uart_port req; + unsigned int ch_mask = 0; + + if (__raw_readq(&tx4938_ccfgptr->pcfg) & TX4938_PCFG_ETH0_SEL) + ch_mask |= 1 << 1; /* disable SIO1 by PCFG setting */ + for (i = 0; i < 2; i++) { + if ((1 << i) & ch_mask) + continue; + memset(&req, 0, sizeof(req)); + req.line = i; + req.iotype = UPIO_MEM; + req.membase = (unsigned char __iomem *)TX4938_SIO_REG(i); + req.mapbase = TX4938_SIO_REG(i) & 0xfffffffffULL; + req.irq = TXX9_IRQ_BASE + TX4938_IR_SIO(i); + req.flags |= UPF_BUGGY_UART /*HAVE_CTS_LINE*/; + req.uartclk = TXX9_IMCLK; + early_serial_txx9_setup(&req); + } +#endif /* CONFIG_SERIAL_TXX9 */ +} diff --git a/arch/mips/txx9/jmr3927/setup.c b/arch/mips/txx9/jmr3927/setup.c index 5e35ef73c5a5..03647ebe4130 100644 --- a/arch/mips/txx9/jmr3927/setup.c +++ b/arch/mips/txx9/jmr3927/setup.c @@ -105,14 +105,6 @@ static void __init jmr3927_mem_setup(void) _machine_halt = jmr3927_machine_halt; pm_power_off = jmr3927_machine_power_off; - /* - * IO/MEM resources. - */ - ioport_resource.start = 0; - ioport_resource.end = 0xffffffff; - iomem_resource.start = 0; - iomem_resource.end = 0xffffffff; - /* Reboot on panic */ panic_timeout = 180; diff --git a/arch/mips/txx9/rbtx4927/irq.c b/arch/mips/txx9/rbtx4927/irq.c index 70f13211bc2a..cd748a930328 100644 --- a/arch/mips/txx9/rbtx4927/irq.c +++ b/arch/mips/txx9/rbtx4927/irq.c @@ -126,14 +126,12 @@ static struct irq_chip toshiba_rbtx4927_irq_ioc_type = { .mask_ack = toshiba_rbtx4927_irq_ioc_disable, .unmask = toshiba_rbtx4927_irq_ioc_enable, }; -#define TOSHIBA_RBTX4927_IOC_INTR_ENAB (void __iomem *)0xbc002000UL -#define TOSHIBA_RBTX4927_IOC_INTR_STAT (void __iomem *)0xbc002006UL static int toshiba_rbtx4927_irq_nested(int sw_irq) { u8 level3; - level3 = readb(TOSHIBA_RBTX4927_IOC_INTR_STAT) & 0x1f; + level3 = readb(rbtx4927_imstat_addr) & 0x1f; if (level3) sw_irq = RBTX4927_IRQ_IOC + fls(level3) - 1; return (sw_irq); @@ -154,18 +152,18 @@ static void toshiba_rbtx4927_irq_ioc_enable(unsigned int irq) { unsigned char v; - v = readb(TOSHIBA_RBTX4927_IOC_INTR_ENAB); + v = readb(rbtx4927_imask_addr); v |= (1 << (irq - RBTX4927_IRQ_IOC)); - writeb(v, TOSHIBA_RBTX4927_IOC_INTR_ENAB); + writeb(v, rbtx4927_imask_addr); } static void toshiba_rbtx4927_irq_ioc_disable(unsigned int irq) { unsigned char v; - v = readb(TOSHIBA_RBTX4927_IOC_INTR_ENAB); + v = readb(rbtx4927_imask_addr); v &= ~(1 << (irq - RBTX4927_IRQ_IOC)); - writeb(v, TOSHIBA_RBTX4927_IOC_INTR_ENAB); + writeb(v, rbtx4927_imask_addr); mmiowb(); } diff --git a/arch/mips/txx9/rbtx4927/prom.c b/arch/mips/txx9/rbtx4927/prom.c index 942e627d2dc1..5c0de54ebdd2 100644 --- a/arch/mips/txx9/rbtx4927/prom.c +++ b/arch/mips/txx9/rbtx4927/prom.c @@ -36,10 +36,6 @@ void __init rbtx4927_prom_init(void) { - extern int tx4927_get_mem_size(void); - int msize; - prom_init_cmdline(); - msize = tx4927_get_mem_size(); - add_memory_region(0, msize << 20, BOOT_MEM_RAM); + add_memory_region(0, tx4927_get_mem_size(), BOOT_MEM_RAM); } diff --git a/arch/mips/txx9/rbtx4927/setup.c b/arch/mips/txx9/rbtx4927/setup.c index 1657fd935da8..3da20ea3e55c 100644 --- a/arch/mips/txx9/rbtx4927/setup.c +++ b/arch/mips/txx9/rbtx4927/setup.c @@ -53,17 +53,10 @@ #include <asm/io.h> #include <asm/processor.h> #include <asm/reboot.h> -#include <asm/time.h> -#include <asm/txx9tmr.h> #include <asm/txx9/generic.h> #include <asm/txx9/pci.h> #include <asm/txx9/rbtx4927.h> #include <asm/txx9/tx4938.h> /* for TX4937 */ -#ifdef CONFIG_SERIAL_TXX9 -#include <linux/serial_core.h> -#endif - -static int tx4927_ccfg_toeon = 1; #ifdef CONFIG_PCI static void __init tx4927_pci_setup(void) @@ -184,14 +177,14 @@ static void toshiba_rbtx4927_restart(char *command) printk(KERN_NOTICE "System Rebooting...\n"); /* enable the s/w reset register */ - writeb(RBTX4927_SW_RESET_ENABLE_SET, RBTX4927_SW_RESET_ENABLE); + writeb(1, rbtx4927_softresetlock_addr); /* wait for enable to be seen */ - while ((readb(RBTX4927_SW_RESET_ENABLE) & - RBTX4927_SW_RESET_ENABLE_SET) == 0x00); + while (!(readb(rbtx4927_softresetlock_addr) & 1)) + ; /* do a s/w reset */ - writeb(RBTX4927_SW_RESET_DO_SET, RBTX4927_SW_RESET_DO); + writeb(1, rbtx4927_softreset_addr); /* do something passive while waiting for reset */ local_irq_disable(); @@ -213,9 +206,11 @@ static void toshiba_rbtx4927_power_off(void) /* no return */ } +static void __init rbtx4927_clock_init(void); +static void __init rbtx4937_clock_init(void); + static void __init rbtx4927_mem_setup(void) { - int i; u32 cp0_config; char *argptr; @@ -227,16 +222,18 @@ static void __init rbtx4927_mem_setup(void) cp0_config = cp0_config & ~(TX49_CONF_IC | TX49_CONF_DC); write_c0_config(cp0_config); - ioport_resource.end = 0xffffffff; - iomem_resource.end = 0xffffffff; + if (TX4927_REV_PCODE() == 0x4927) { + rbtx4927_clock_init(); + tx4927_setup(); + } else { + rbtx4937_clock_init(); + tx4938_setup(); + } _machine_restart = toshiba_rbtx4927_restart; _machine_halt = toshiba_rbtx4927_halt; pm_power_off = toshiba_rbtx4927_power_off; - for (i = 0; i < TX4927_NR_TMR; i++) - txx9_tmr_init(TX4927_TMR_REG(0) & 0xfffffffffULL); - #ifdef CONFIG_PCI txx9_alloc_pci_controller(&txx9_primary_pcic, RBTX4927_PCIMEM, RBTX4927_PCIMEM_SIZE, @@ -245,36 +242,13 @@ static void __init rbtx4927_mem_setup(void) set_io_port_base(KSEG1 + RBTX4927_ISA_IO_OFFSET); #endif - /* CCFG */ - /* do reset on watchdog */ - tx4927_ccfg_set(TX4927_CCFG_WR); - /* enable Timeout BusError */ - if (tx4927_ccfg_toeon) - tx4927_ccfg_set(TX4927_CCFG_TOE); - -#ifdef CONFIG_SERIAL_TXX9 - { - extern int early_serial_txx9_setup(struct uart_port *port); - struct uart_port req; - for(i = 0; i < 2; i++) { - memset(&req, 0, sizeof(req)); - req.line = i; - req.iotype = UPIO_MEM; - req.membase = (char *)(0xff1ff300 + i * 0x100); - req.mapbase = 0xff1ff300 + i * 0x100; - req.irq = TXX9_IRQ_BASE + TX4927_IR_SIO(i); - req.flags |= UPF_BUGGY_UART /*HAVE_CTS_LINE*/; - req.uartclk = 50000000; - early_serial_txx9_setup(&req); - } - } + tx4927_setup_serial(); #ifdef CONFIG_SERIAL_TXX9_CONSOLE argptr = prom_getcmdline(); if (strstr(argptr, "console=") == NULL) { strcat(argptr, " console=ttyS0,38400"); } #endif -#endif #ifdef CONFIG_ROOT_NFS argptr = prom_getcmdline(); @@ -291,19 +265,7 @@ static void __init rbtx4927_mem_setup(void) #endif } -static void __init rbtx49x7_common_time_init(void) -{ - /* change default value to udelay/mdelay take reasonable time */ - loops_per_jiffy = txx9_cpu_clock / HZ / 2; - - mips_hpt_frequency = txx9_cpu_clock / 2; - if (____raw_readq(&tx4927_ccfgptr->ccfg) & TX4927_CCFG_TINTDIS) - txx9_clockevent_init(TX4927_TMR_REG(0) & 0xfffffffffULL, - TXX9_IRQ_BASE + 17, - 50000000); -} - -static void __init rbtx4927_time_init(void) +static void __init rbtx4927_clock_init(void) { /* * ASSUMPTION: PCIDIVMODE is configured for PCI 33MHz or 66MHz. @@ -325,11 +287,9 @@ static void __init rbtx4927_time_init(void) default: txx9_cpu_clock = 200000000; /* 200MHz */ } - - rbtx49x7_common_time_init(); } -static void __init rbtx4937_time_init(void) +static void __init rbtx4937_clock_init(void) { /* * ASSUMPTION: PCIDIVMODE is configured for PCI 33MHz or 66MHz. @@ -357,15 +317,18 @@ static void __init rbtx4937_time_init(void) default: txx9_cpu_clock = 333333333; /* 333MHz */ } +} - rbtx49x7_common_time_init(); +static void __init rbtx4927_time_init(void) +{ + tx4927_time_init(0); } static int __init toshiba_rbtx4927_rtc_init(void) { - static struct resource __initdata res = { - .start = 0x1c010000, - .end = 0x1c010000 + 0x800 - 1, + struct resource res = { + .start = RBTX4927_BRAMRTC_BASE - IO_BASE, + .end = RBTX4927_BRAMRTC_BASE - IO_BASE + 0x800 - 1, .flags = IORESOURCE_MEM, }; struct platform_device *dev = @@ -375,7 +338,7 @@ static int __init toshiba_rbtx4927_rtc_init(void) static int __init rbtx4927_ne_init(void) { - static struct resource __initdata res[] = { + struct resource res[] = { { .start = RBTX4927_RTL_8019_BASE, .end = RBTX4927_RTL_8019_BASE + 0x20 - 1, @@ -434,7 +397,7 @@ struct txx9_board_vec rbtx4937_vec __initdata = { .prom_init = rbtx4927_prom_init, .mem_setup = rbtx4927_mem_setup, .irq_setup = rbtx4927_irq_setup, - .time_init = rbtx4937_time_init, + .time_init = rbtx4927_time_init, .device_init = rbtx4927_device_init, .arch_init = rbtx4937_arch_init, #ifdef CONFIG_PCI diff --git a/arch/mips/txx9/rbtx4938/prom.c b/arch/mips/txx9/rbtx4938/prom.c index fbb37458ddb2..ee189519ce5a 100644 --- a/arch/mips/txx9/rbtx4938/prom.c +++ b/arch/mips/txx9/rbtx4938/prom.c @@ -18,12 +18,8 @@ void __init rbtx4938_prom_init(void) { - extern int tx4938_get_mem_size(void); - int msize; #ifndef CONFIG_TX4938_NAND_BOOT prom_init_cmdline(); #endif - - msize = tx4938_get_mem_size(); - add_memory_region(0, msize << 20, BOOT_MEM_RAM); + add_memory_region(0, tx4938_get_mem_size(), BOOT_MEM_RAM); } diff --git a/arch/mips/txx9/rbtx4938/setup.c b/arch/mips/txx9/rbtx4938/setup.c index aaa987ae0f83..6c2b99bb8af6 100644 --- a/arch/mips/txx9/rbtx4938/setup.c +++ b/arch/mips/txx9/rbtx4938/setup.c @@ -20,21 +20,14 @@ #include <linux/gpio.h> #include <asm/reboot.h> -#include <asm/time.h> -#include <asm/txx9tmr.h> #include <asm/io.h> #include <asm/txx9/generic.h> #include <asm/txx9/pci.h> #include <asm/txx9/rbtx4938.h> -#ifdef CONFIG_SERIAL_TXX9 -#include <linux/serial_core.h> -#endif #include <linux/spi/spi.h> #include <asm/txx9/spi.h> #include <asm/txx9pio.h> -static int tx4938_ccfg_toeon = 1; - static void rbtx4938_machine_halt(void) { printk(KERN_NOTICE "System Halted\n"); @@ -182,188 +175,10 @@ static void __init rbtx4938_spi_setup(void) } static struct resource rbtx4938_fpga_resource; -static struct resource tx4938_sdram_resource[4]; -static struct resource tx4938_sram_resource; - -void __init tx4938_board_setup(void) -{ - int i; - unsigned long divmode; - int cpuclk = 0; - unsigned long pcode = TX4938_REV_PCODE(); - - ioport_resource.start = 0; - ioport_resource.end = 0xffffffff; - iomem_resource.start = 0; - iomem_resource.end = 0xffffffff; /* expand to 4GB */ - - txx9_reg_res_init(pcode, TX4938_REG_BASE, - TX4938_REG_SIZE); - /* SDRAMC,EBUSC are configured by PROM */ - for (i = 0; i < 8; i++) { - if (!(TX4938_EBUSC_CR(i) & 0x8)) - continue; /* disabled */ - txx9_ce_res[i].start = (unsigned long)TX4938_EBUSC_BA(i); - txx9_ce_res[i].end = - txx9_ce_res[i].start + TX4938_EBUSC_SIZE(i) - 1; - request_resource(&iomem_resource, &txx9_ce_res[i]); - } - - /* clocks */ - if (txx9_master_clock) { - u64 ccfg = ____raw_readq(&tx4938_ccfgptr->ccfg); - /* calculate gbus_clock and cpu_clock_freq from master_clock */ - divmode = (__u32)ccfg & TX4938_CCFG_DIVMODE_MASK; - switch (divmode) { - case TX4938_CCFG_DIVMODE_8: - case TX4938_CCFG_DIVMODE_10: - case TX4938_CCFG_DIVMODE_12: - case TX4938_CCFG_DIVMODE_16: - case TX4938_CCFG_DIVMODE_18: - txx9_gbus_clock = txx9_master_clock * 4; break; - default: - txx9_gbus_clock = txx9_master_clock; - } - switch (divmode) { - case TX4938_CCFG_DIVMODE_2: - case TX4938_CCFG_DIVMODE_8: - cpuclk = txx9_gbus_clock * 2; break; - case TX4938_CCFG_DIVMODE_2_5: - case TX4938_CCFG_DIVMODE_10: - cpuclk = txx9_gbus_clock * 5 / 2; break; - case TX4938_CCFG_DIVMODE_3: - case TX4938_CCFG_DIVMODE_12: - cpuclk = txx9_gbus_clock * 3; break; - case TX4938_CCFG_DIVMODE_4: - case TX4938_CCFG_DIVMODE_16: - cpuclk = txx9_gbus_clock * 4; break; - case TX4938_CCFG_DIVMODE_4_5: - case TX4938_CCFG_DIVMODE_18: - cpuclk = txx9_gbus_clock * 9 / 2; break; - } - txx9_cpu_clock = cpuclk; - } else { - u64 ccfg = ____raw_readq(&tx4938_ccfgptr->ccfg); - if (txx9_cpu_clock == 0) { - txx9_cpu_clock = 300000000; /* 300MHz */ - } - /* calculate gbus_clock and master_clock from cpu_clock_freq */ - cpuclk = txx9_cpu_clock; - divmode = (__u32)ccfg & TX4938_CCFG_DIVMODE_MASK; - switch (divmode) { - case TX4938_CCFG_DIVMODE_2: - case TX4938_CCFG_DIVMODE_8: - txx9_gbus_clock = cpuclk / 2; break; - case TX4938_CCFG_DIVMODE_2_5: - case TX4938_CCFG_DIVMODE_10: - txx9_gbus_clock = cpuclk * 2 / 5; break; - case TX4938_CCFG_DIVMODE_3: - case TX4938_CCFG_DIVMODE_12: - txx9_gbus_clock = cpuclk / 3; break; - case TX4938_CCFG_DIVMODE_4: - case TX4938_CCFG_DIVMODE_16: - txx9_gbus_clock = cpuclk / 4; break; - case TX4938_CCFG_DIVMODE_4_5: - case TX4938_CCFG_DIVMODE_18: - txx9_gbus_clock = cpuclk * 2 / 9; break; - } - switch (divmode) { - case TX4938_CCFG_DIVMODE_8: - case TX4938_CCFG_DIVMODE_10: - case TX4938_CCFG_DIVMODE_12: - case TX4938_CCFG_DIVMODE_16: - case TX4938_CCFG_DIVMODE_18: - txx9_master_clock = txx9_gbus_clock / 4; break; - default: - txx9_master_clock = txx9_gbus_clock; - } - } - /* change default value to udelay/mdelay take reasonable time */ - loops_per_jiffy = txx9_cpu_clock / HZ / 2; - - /* CCFG */ - /* clear WatchDogReset,BusErrorOnWrite flag (W1C) */ - tx4938_ccfg_set(TX4938_CCFG_WDRST | TX4938_CCFG_BEOW); - /* do reset on watchdog */ - tx4938_ccfg_set(TX4938_CCFG_WR); - /* clear PCIC1 reset */ - txx9_clear64(&tx4938_ccfgptr->clkctr, TX4938_CLKCTR_PCIC1RST); - - /* enable Timeout BusError */ - if (tx4938_ccfg_toeon) - tx4938_ccfg_set(TX4938_CCFG_TOE); - - /* DMA selection */ - txx9_clear64(&tx4938_ccfgptr->pcfg, TX4938_PCFG_DMASEL_ALL); - - /* Use external clock for external arbiter */ - if (!(____raw_readq(&tx4938_ccfgptr->ccfg) & TX4938_CCFG_PCIARB)) - txx9_clear64(&tx4938_ccfgptr->pcfg, TX4938_PCFG_PCICLKEN_ALL); - - printk(KERN_INFO "%s -- %dMHz(M%dMHz) CRIR:%08x CCFG:%llx PCFG:%llx\n", - txx9_pcode_str, - (cpuclk + 500000) / 1000000, - (txx9_master_clock + 500000) / 1000000, - (__u32)____raw_readq(&tx4938_ccfgptr->crir), - (unsigned long long)____raw_readq(&tx4938_ccfgptr->ccfg), - (unsigned long long)____raw_readq(&tx4938_ccfgptr->pcfg)); - - printk(KERN_INFO "%s SDRAMC --", txx9_pcode_str); - for (i = 0; i < 4; i++) { - unsigned long long cr = tx4938_sdramcptr->cr[i]; - unsigned long ram_base, ram_size; - if (!((unsigned long)cr & 0x00000400)) - continue; /* disabled */ - ram_base = (unsigned long)(cr >> 49) << 21; - ram_size = ((unsigned long)(cr >> 33) + 1) << 21; - if (ram_base >= 0x20000000) - continue; /* high memory (ignore) */ - printk(" CR%d:%016Lx", i, cr); - tx4938_sdram_resource[i].name = "SDRAM"; - tx4938_sdram_resource[i].start = ram_base; - tx4938_sdram_resource[i].end = ram_base + ram_size - 1; - tx4938_sdram_resource[i].flags = IORESOURCE_MEM; - request_resource(&iomem_resource, &tx4938_sdram_resource[i]); - } - printk(" TR:%09Lx\n", tx4938_sdramcptr->tr); - - /* SRAM */ - if (tx4938_sramcptr->cr & 1) { - unsigned int size = 0x800; - unsigned long base = - (tx4938_sramcptr->cr >> (39-11)) & ~(size - 1); - tx4938_sram_resource.name = "SRAM"; - tx4938_sram_resource.start = base; - tx4938_sram_resource.end = base + size - 1; - tx4938_sram_resource.flags = IORESOURCE_MEM; - request_resource(&iomem_resource, &tx4938_sram_resource); - } - - /* TMR */ - for (i = 0; i < TX4938_NR_TMR; i++) - txx9_tmr_init(TX4938_TMR_REG(i) & 0xfffffffffULL); - - /* enable DMA */ - for (i = 0; i < 2; i++) - ____raw_writeq(TX4938_DMA_MCR_MSTEN, - (void __iomem *)(TX4938_DMA_REG(i) + 0x50)); - - /* PIO */ - __raw_writel(0, &tx4938_pioptr->maskcpu); - __raw_writel(0, &tx4938_pioptr->maskext); - -#ifdef CONFIG_PCI - txx9_alloc_pci_controller(&txx9_primary_pcic, 0, 0, 0, 0); -#endif -} static void __init rbtx4938_time_init(void) { - mips_hpt_frequency = txx9_cpu_clock / 2; - if (____raw_readq(&tx4938_ccfgptr->ccfg) & TX4938_CCFG_TINTDIS) - txx9_clockevent_init(TX4938_TMR_REG(0) & 0xfffffffffULL, - TXX9_IRQ_BASE + TX4938_IR_TMR(0), - txx9_gbus_clock / 2); + tx4938_time_init(0); } static void __init rbtx4938_mem_setup(void) @@ -371,39 +186,24 @@ static void __init rbtx4938_mem_setup(void) unsigned long long pcfg; char *argptr; - iomem_resource.end = 0xffffffff; /* 4GB */ - if (txx9_master_clock == 0) txx9_master_clock = 25000000; /* 25MHz */ - tx4938_board_setup(); -#ifndef CONFIG_PCI + + tx4938_setup(); + +#ifdef CONFIG_PCI + txx9_alloc_pci_controller(&txx9_primary_pcic, 0, 0, 0, 0); +#else set_io_port_base(RBTX4938_ETHER_BASE); #endif -#ifdef CONFIG_SERIAL_TXX9 - { - extern int early_serial_txx9_setup(struct uart_port *port); - int i; - struct uart_port req; - for(i = 0; i < 2; i++) { - memset(&req, 0, sizeof(req)); - req.line = i; - req.iotype = UPIO_MEM; - req.membase = (char *)(0xff1ff300 + i * 0x100); - req.mapbase = 0xff1ff300 + i * 0x100; - req.irq = RBTX4938_IRQ_IRC_SIO(i); - req.flags |= UPF_BUGGY_UART /*HAVE_CTS_LINE*/; - req.uartclk = 50000000; - early_serial_txx9_setup(&req); - } - } + tx4938_setup_serial(); #ifdef CONFIG_SERIAL_TXX9_CONSOLE argptr = prom_getcmdline(); if (strstr(argptr, "console=") == NULL) { strcat(argptr, " console=ttyS0,38400"); } #endif -#endif #ifdef CONFIG_TOSHIBA_RBTX4938_MPLEX_PIO58_61 printk("PIOSEL: disabling both ata and nand selection\n"); @@ -457,7 +257,7 @@ static void __init rbtx4938_mem_setup(void) rbtx4938_fpga_resource.start = CPHYSADDR(RBTX4938_FPGA_REG_ADDR); rbtx4938_fpga_resource.end = CPHYSADDR(RBTX4938_FPGA_REG_ADDR) + 0xffff; rbtx4938_fpga_resource.flags = IORESOURCE_MEM | IORESOURCE_BUSY; - if (request_resource(&iomem_resource, &rbtx4938_fpga_resource)) + if (request_resource(&txx9_ce_res[2], &rbtx4938_fpga_resource)) printk("request resource for fpga failed\n"); _machine_restart = rbtx4938_machine_restart; @@ -488,18 +288,6 @@ static int __init rbtx4938_ne_init(void) return IS_ERR(dev) ? PTR_ERR(dev) : 0; } -/* GPIO support */ - -int gpio_to_irq(unsigned gpio) -{ - return -EINVAL; -} - -int irq_to_gpio(unsigned irq) -{ - return -EINVAL; -} - static DEFINE_SPINLOCK(rbtx4938_spi_gpio_lock); static void rbtx4938_spi_gpio_set(struct gpio_chip *chip, unsigned int offset, @@ -579,7 +367,6 @@ static int __init rbtx4938_spi_init(void) static void __init rbtx4938_arch_init(void) { - txx9_gpio_init(TX4938_PIO_REG & 0xfffffffffULL, 0, 16); gpiochip_add(&rbtx4938_spi_gpio_chip); rbtx4938_pci_setup(); rbtx4938_spi_init(); diff --git a/arch/mn10300/kernel/mn10300-serial.c b/arch/mn10300/kernel/mn10300-serial.c index b9c268c6b2fb..8b054e7a8ae8 100644 --- a/arch/mn10300/kernel/mn10300-serial.c +++ b/arch/mn10300/kernel/mn10300-serial.c @@ -392,7 +392,7 @@ static int mask_test_and_clear(volatile u8 *ptr, u8 mask) static void mn10300_serial_receive_interrupt(struct mn10300_serial_port *port) { struct uart_icount *icount = &port->uart.icount; - struct tty_struct *tty = port->uart.info->tty; + struct tty_struct *tty = port->uart.info->port.tty; unsigned ix; int count; u8 st, ch, push, status, overrun; diff --git a/arch/powerpc/kvm/Makefile b/arch/powerpc/kvm/Makefile index d0d358d367ec..04e3449e1f42 100644 --- a/arch/powerpc/kvm/Makefile +++ b/arch/powerpc/kvm/Makefile @@ -4,7 +4,7 @@ EXTRA_CFLAGS += -Ivirt/kvm -Iarch/powerpc/kvm -common-objs = $(addprefix ../../../virt/kvm/, kvm_main.o) +common-objs = $(addprefix ../../../virt/kvm/, kvm_main.o coalesced_mmio.o) kvm-objs := $(common-objs) powerpc.o emulate.o booke_guest.o obj-$(CONFIG_KVM) += kvm.o diff --git a/arch/powerpc/kvm/powerpc.c b/arch/powerpc/kvm/powerpc.c index 777e0f34e0ea..53826a5f6c06 100644 --- a/arch/powerpc/kvm/powerpc.c +++ b/arch/powerpc/kvm/powerpc.c @@ -145,6 +145,9 @@ int kvm_dev_ioctl_check_extension(long ext) case KVM_CAP_USER_MEMORY: r = 1; break; + case KVM_CAP_COALESCED_MMIO: + r = KVM_COALESCED_MMIO_PAGE_OFFSET; + break; default: r = 0; break; @@ -167,6 +170,10 @@ int kvm_arch_set_memory_region(struct kvm *kvm, return 0; } +void kvm_arch_flush_shadow(struct kvm *kvm) +{ +} + struct kvm_vcpu *kvm_arch_vcpu_create(struct kvm *kvm, unsigned int id) { struct kvm_vcpu *vcpu; @@ -240,10 +247,6 @@ void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu) { } -void decache_vcpus_on_cpu(int cpu) -{ -} - int kvm_arch_vcpu_ioctl_debug_guest(struct kvm_vcpu *vcpu, struct kvm_debug_guest *dbg) { diff --git a/arch/s390/kvm/interrupt.c b/arch/s390/kvm/interrupt.c index 84a7fed4cd4e..11230b0db957 100644 --- a/arch/s390/kvm/interrupt.c +++ b/arch/s390/kvm/interrupt.c @@ -31,7 +31,7 @@ static int psw_interrupts_disabled(struct kvm_vcpu *vcpu) } static int __interrupt_is_deliverable(struct kvm_vcpu *vcpu, - struct interrupt_info *inti) + struct kvm_s390_interrupt_info *inti) { switch (inti->type) { case KVM_S390_INT_EMERGENCY: @@ -91,7 +91,7 @@ static void __set_cpuflag(struct kvm_vcpu *vcpu, u32 flag) } static void __set_intercept_indicator(struct kvm_vcpu *vcpu, - struct interrupt_info *inti) + struct kvm_s390_interrupt_info *inti) { switch (inti->type) { case KVM_S390_INT_EMERGENCY: @@ -111,7 +111,7 @@ static void __set_intercept_indicator(struct kvm_vcpu *vcpu, } static void __do_deliver_interrupt(struct kvm_vcpu *vcpu, - struct interrupt_info *inti) + struct kvm_s390_interrupt_info *inti) { const unsigned short table[] = { 2, 4, 4, 6 }; int rc, exception = 0; @@ -290,9 +290,9 @@ static int __try_deliver_ckc_interrupt(struct kvm_vcpu *vcpu) int kvm_cpu_has_interrupt(struct kvm_vcpu *vcpu) { - struct local_interrupt *li = &vcpu->arch.local_int; - struct float_interrupt *fi = vcpu->arch.local_int.float_int; - struct interrupt_info *inti; + struct kvm_s390_local_interrupt *li = &vcpu->arch.local_int; + struct kvm_s390_float_interrupt *fi = vcpu->arch.local_int.float_int; + struct kvm_s390_interrupt_info *inti; int rc = 0; if (atomic_read(&li->active)) { @@ -408,9 +408,9 @@ void kvm_s390_idle_wakeup(unsigned long data) void kvm_s390_deliver_pending_interrupts(struct kvm_vcpu *vcpu) { - struct local_interrupt *li = &vcpu->arch.local_int; - struct float_interrupt *fi = vcpu->arch.local_int.float_int; - struct interrupt_info *n, *inti = NULL; + struct kvm_s390_local_interrupt *li = &vcpu->arch.local_int; + struct kvm_s390_float_interrupt *fi = vcpu->arch.local_int.float_int; + struct kvm_s390_interrupt_info *n, *inti = NULL; int deliver; __reset_intercept_indicators(vcpu); @@ -465,8 +465,8 @@ void kvm_s390_deliver_pending_interrupts(struct kvm_vcpu *vcpu) int kvm_s390_inject_program_int(struct kvm_vcpu *vcpu, u16 code) { - struct local_interrupt *li = &vcpu->arch.local_int; - struct interrupt_info *inti; + struct kvm_s390_local_interrupt *li = &vcpu->arch.local_int; + struct kvm_s390_interrupt_info *inti; inti = kzalloc(sizeof(*inti), GFP_KERNEL); if (!inti) @@ -487,9 +487,9 @@ int kvm_s390_inject_program_int(struct kvm_vcpu *vcpu, u16 code) int kvm_s390_inject_vm(struct kvm *kvm, struct kvm_s390_interrupt *s390int) { - struct local_interrupt *li; - struct float_interrupt *fi; - struct interrupt_info *inti; + struct kvm_s390_local_interrupt *li; + struct kvm_s390_float_interrupt *fi; + struct kvm_s390_interrupt_info *inti; int sigcpu; inti = kzalloc(sizeof(*inti), GFP_KERNEL); @@ -544,8 +544,8 @@ int kvm_s390_inject_vm(struct kvm *kvm, int kvm_s390_inject_vcpu(struct kvm_vcpu *vcpu, struct kvm_s390_interrupt *s390int) { - struct local_interrupt *li; - struct interrupt_info *inti; + struct kvm_s390_local_interrupt *li; + struct kvm_s390_interrupt_info *inti; inti = kzalloc(sizeof(*inti), GFP_KERNEL); if (!inti) diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c index 6558b09ff579..1782cbcd2829 100644 --- a/arch/s390/kvm/kvm-s390.c +++ b/arch/s390/kvm/kvm-s390.c @@ -79,10 +79,6 @@ void kvm_arch_hardware_disable(void *garbage) { } -void decache_vcpus_on_cpu(int cpu) -{ -} - int kvm_arch_hardware_setup(void) { return 0; @@ -198,6 +194,7 @@ out_nokvm: void kvm_arch_destroy_vm(struct kvm *kvm) { debug_unregister(kvm->arch.dbf); + kvm_free_physmem(kvm); free_page((unsigned long)(kvm->arch.sca)); kfree(kvm); module_put(THIS_MODULE); @@ -250,11 +247,16 @@ static void kvm_s390_vcpu_initial_reset(struct kvm_vcpu *vcpu) vcpu->arch.sie_block->gbea = 1; } +/* The current code can have up to 256 pages for virtio */ +#define VIRTIODESCSPACE (256ul * 4096ul) + int kvm_arch_vcpu_setup(struct kvm_vcpu *vcpu) { atomic_set(&vcpu->arch.sie_block->cpuflags, CPUSTAT_ZARCH); - vcpu->arch.sie_block->gmslm = 0xffffffffffUL; - vcpu->arch.sie_block->gmsor = 0x000000000000; + vcpu->arch.sie_block->gmslm = vcpu->kvm->arch.guest_memsize + + vcpu->kvm->arch.guest_origin + + VIRTIODESCSPACE - 1ul; + vcpu->arch.sie_block->gmsor = vcpu->kvm->arch.guest_origin; vcpu->arch.sie_block->ecb = 2; vcpu->arch.sie_block->eca = 0xC1002001U; setup_timer(&vcpu->arch.ckc_timer, kvm_s390_idle_wakeup, @@ -273,7 +275,8 @@ struct kvm_vcpu *kvm_arch_vcpu_create(struct kvm *kvm, if (!vcpu) goto out_nomem; - vcpu->arch.sie_block = (struct sie_block *) get_zeroed_page(GFP_KERNEL); + vcpu->arch.sie_block = (struct kvm_s390_sie_block *) + get_zeroed_page(GFP_KERNEL); if (!vcpu->arch.sie_block) goto out_free_cpu; @@ -672,6 +675,10 @@ int kvm_arch_set_memory_region(struct kvm *kvm, return 0; } +void kvm_arch_flush_shadow(struct kvm *kvm) +{ +} + gfn_t unalias_gfn(struct kvm *kvm, gfn_t gfn) { return gfn; diff --git a/arch/s390/kvm/priv.c b/arch/s390/kvm/priv.c index c02286c6a931..2e2d2ffb6a07 100644 --- a/arch/s390/kvm/priv.c +++ b/arch/s390/kvm/priv.c @@ -199,7 +199,7 @@ out: static void handle_stsi_3_2_2(struct kvm_vcpu *vcpu, struct sysinfo_3_2_2 *mem) { - struct float_interrupt *fi = &vcpu->kvm->arch.float_int; + struct kvm_s390_float_interrupt *fi = &vcpu->kvm->arch.float_int; int cpus = 0; int n; diff --git a/arch/s390/kvm/sigp.c b/arch/s390/kvm/sigp.c index 0a236acfb5f6..5a556114eaa5 100644 --- a/arch/s390/kvm/sigp.c +++ b/arch/s390/kvm/sigp.c @@ -45,7 +45,7 @@ static int __sigp_sense(struct kvm_vcpu *vcpu, u16 cpu_addr, u64 *reg) { - struct float_interrupt *fi = &vcpu->kvm->arch.float_int; + struct kvm_s390_float_interrupt *fi = &vcpu->kvm->arch.float_int; int rc; if (cpu_addr >= KVM_MAX_VCPUS) @@ -71,9 +71,9 @@ static int __sigp_sense(struct kvm_vcpu *vcpu, u16 cpu_addr, u64 *reg) static int __sigp_emergency(struct kvm_vcpu *vcpu, u16 cpu_addr) { - struct float_interrupt *fi = &vcpu->kvm->arch.float_int; - struct local_interrupt *li; - struct interrupt_info *inti; + struct kvm_s390_float_interrupt *fi = &vcpu->kvm->arch.float_int; + struct kvm_s390_local_interrupt *li; + struct kvm_s390_interrupt_info *inti; int rc; if (cpu_addr >= KVM_MAX_VCPUS) @@ -108,9 +108,9 @@ unlock: static int __sigp_stop(struct kvm_vcpu *vcpu, u16 cpu_addr, int store) { - struct float_interrupt *fi = &vcpu->kvm->arch.float_int; - struct local_interrupt *li; - struct interrupt_info *inti; + struct kvm_s390_float_interrupt *fi = &vcpu->kvm->arch.float_int; + struct kvm_s390_local_interrupt *li; + struct kvm_s390_interrupt_info *inti; int rc; if (cpu_addr >= KVM_MAX_VCPUS) @@ -169,9 +169,9 @@ static int __sigp_set_arch(struct kvm_vcpu *vcpu, u32 parameter) static int __sigp_set_prefix(struct kvm_vcpu *vcpu, u16 cpu_addr, u32 address, u64 *reg) { - struct float_interrupt *fi = &vcpu->kvm->arch.float_int; - struct local_interrupt *li; - struct interrupt_info *inti; + struct kvm_s390_float_interrupt *fi = &vcpu->kvm->arch.float_int; + struct kvm_s390_local_interrupt *li; + struct kvm_s390_interrupt_info *inti; int rc; u8 tmp; diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index 96e0c2ebc388..03980cb04291 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -447,7 +447,6 @@ config PARAVIRT_DEBUG config MEMTEST bool "Memtest" - depends on X86_64 help This option adds a kernel parameter 'memtest', which allows memtest to be set. diff --git a/arch/x86/Kconfig.debug b/arch/x86/Kconfig.debug index ae36bfa814e5..85a87d2ac0c0 100644 --- a/arch/x86/Kconfig.debug +++ b/arch/x86/Kconfig.debug @@ -5,13 +5,15 @@ config TRACE_IRQFLAGS_SUPPORT source "lib/Kconfig.debug" -config NONPROMISC_DEVMEM +config STRICT_DEVMEM bool "Filter access to /dev/mem" help - If this option is left off, you allow userspace access to all + If this option is left on, you allow userspace (root) access to all of memory, including kernel and userspace memory. Accidental access to this is obviously disastrous, but specific access can - be used by people debugging the kernel. + be used by people debugging the kernel. Note that with PAT support + enabled, even in this case there are restrictions on /dev/mem + use due to the cache aliasing requirements. If this option is switched on, the /dev/mem file only allows userspace access to PCI space and the BIOS code and data regions. @@ -287,7 +289,6 @@ config CPA_DEBUG config OPTIMIZE_INLINING bool "Allow gcc to uninline functions marked 'inline'" - depends on BROKEN help This option determines if the kernel forces gcc to inline the functions developers have marked 'inline'. Doing so takes away freedom from gcc to @@ -298,5 +299,7 @@ config OPTIMIZE_INLINING become the default in the future, until then this option is there to test gcc for this. + If unsure, say N. + endmenu diff --git a/arch/x86/boot/edd.c b/arch/x86/boot/edd.c index 03399d64013b..d93cbc6464d0 100644 --- a/arch/x86/boot/edd.c +++ b/arch/x86/boot/edd.c @@ -167,9 +167,8 @@ void query_edd(void) * Scan the BIOS-supported hard disks and query EDD * information... */ - get_edd_info(devno, &ei); - - if (boot_params.eddbuf_entries < EDDMAXNR) { + if (!get_edd_info(devno, &ei) + && boot_params.eddbuf_entries < EDDMAXNR) { memcpy(edp, &ei, sizeof ei); edp++; boot_params.eddbuf_entries++; diff --git a/arch/x86/boot/pm.c b/arch/x86/boot/pm.c index 328956fdb59e..85a1cd8a8ff8 100644 --- a/arch/x86/boot/pm.c +++ b/arch/x86/boot/pm.c @@ -98,12 +98,6 @@ static void reset_coprocessor(void) /* * Set up the GDT */ -#define GDT_ENTRY(flags, base, limit) \ - (((u64)(base & 0xff000000) << 32) | \ - ((u64)flags << 40) | \ - ((u64)(limit & 0x00ff0000) << 32) | \ - ((u64)(base & 0x00ffffff) << 16) | \ - ((u64)(limit & 0x0000ffff))) struct gdt_ptr { u16 len; diff --git a/arch/x86/configs/i386_defconfig b/arch/x86/configs/i386_defconfig index 9bc34e2033ec..4d73f53287b6 100644 --- a/arch/x86/configs/i386_defconfig +++ b/arch/x86/configs/i386_defconfig @@ -2047,7 +2047,7 @@ CONFIG_PROVIDE_OHCI1394_DMA_INIT=y # CONFIG_SAMPLES is not set # CONFIG_KGDB is not set CONFIG_HAVE_ARCH_KGDB=y -# CONFIG_NONPROMISC_DEVMEM is not set +# CONFIG_STRICT_DEVMEM is not set CONFIG_EARLY_PRINTK=y CONFIG_DEBUG_STACKOVERFLOW=y CONFIG_DEBUG_STACK_USAGE=y diff --git a/arch/x86/configs/x86_64_defconfig b/arch/x86/configs/x86_64_defconfig index ae5124e064d4..a40452429625 100644 --- a/arch/x86/configs/x86_64_defconfig +++ b/arch/x86/configs/x86_64_defconfig @@ -2012,7 +2012,7 @@ CONFIG_PROVIDE_OHCI1394_DMA_INIT=y # CONFIG_SAMPLES is not set # CONFIG_KGDB is not set CONFIG_HAVE_ARCH_KGDB=y -# CONFIG_NONPROMISC_DEVMEM is not set +# CONFIG_STRICT_DEVMEM is not set CONFIG_EARLY_PRINTK=y CONFIG_DEBUG_STACKOVERFLOW=y CONFIG_DEBUG_STACK_USAGE=y diff --git a/arch/x86/ia32/ia32_signal.c b/arch/x86/ia32/ia32_signal.c index cb3856a18c85..20af4c79579a 100644 --- a/arch/x86/ia32/ia32_signal.c +++ b/arch/x86/ia32/ia32_signal.c @@ -36,6 +36,11 @@ #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) +#define FIX_EFLAGS (X86_EFLAGS_AC | X86_EFLAGS_OF | \ + X86_EFLAGS_DF | X86_EFLAGS_TF | X86_EFLAGS_SF | \ + X86_EFLAGS_ZF | X86_EFLAGS_AF | X86_EFLAGS_PF | \ + X86_EFLAGS_CF) + asmlinkage int do_signal(struct pt_regs *regs, sigset_t *oldset); void signal_fault(struct pt_regs *regs, void __user *frame, char *where); @@ -248,7 +253,7 @@ static int ia32_restore_sigcontext(struct pt_regs *regs, regs->ss |= 3; err |= __get_user(tmpflags, &sc->flags); - regs->flags = (regs->flags & ~0x40DD5) | (tmpflags & 0x40DD5); + regs->flags = (regs->flags & ~FIX_EFLAGS) | (tmpflags & FIX_EFLAGS); /* disable syscall checks */ regs->orig_ax = -1; @@ -515,7 +520,6 @@ int ia32_setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, compat_sigset_t *set, struct pt_regs *regs) { struct rt_sigframe __user *frame; - struct exec_domain *ed = current_thread_info()->exec_domain; void __user *restorer; int err = 0; @@ -538,8 +542,7 @@ int ia32_setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) goto give_sigsegv; - err |= __put_user((ed && ed->signal_invmap && sig < 32 - ? ed->signal_invmap[sig] : sig), &frame->sig); + err |= __put_user(sig, &frame->sig); err |= __put_user(ptr_to_compat(&frame->info), &frame->pinfo); err |= __put_user(ptr_to_compat(&frame->uc), &frame->puc); err |= copy_siginfo_to_user32(&frame->info, info); diff --git a/arch/x86/ia32/ia32entry.S b/arch/x86/ia32/ia32entry.S index 20371d0635e4..23d146ce676b 100644 --- a/arch/x86/ia32/ia32entry.S +++ b/arch/x86/ia32/ia32entry.S @@ -37,6 +37,11 @@ movq %rax,R8(%rsp) .endm + /* + * Reload arg registers from stack in case ptrace changed them. + * We don't reload %eax because syscall_trace_enter() returned + * the value it wants us to use in the table lookup. + */ .macro LOAD_ARGS32 offset movl \offset(%rsp),%r11d movl \offset+8(%rsp),%r10d @@ -46,7 +51,6 @@ movl \offset+48(%rsp),%edx movl \offset+56(%rsp),%esi movl \offset+64(%rsp),%edi - movl \offset+72(%rsp),%eax .endm .macro CFI_STARTPROC32 simple @@ -137,13 +141,12 @@ ENTRY(ia32_sysenter_target) .previous GET_THREAD_INFO(%r10) orl $TS_COMPAT,TI_status(%r10) - testl $(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT|_TIF_SECCOMP), \ - TI_flags(%r10) + testl $_TIF_WORK_SYSCALL_ENTRY,TI_flags(%r10) CFI_REMEMBER_STATE jnz sysenter_tracesys -sysenter_do_call: cmpl $(IA32_NR_syscalls-1),%eax ja ia32_badsys +sysenter_do_call: IA32_ARG_FIXUP 1 call *ia32_sys_call_table(,%rax,8) movq %rax,RAX-ARGOFFSET(%rsp) @@ -242,8 +245,7 @@ ENTRY(ia32_cstar_target) .previous GET_THREAD_INFO(%r10) orl $TS_COMPAT,TI_status(%r10) - testl $(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT|_TIF_SECCOMP), \ - TI_flags(%r10) + testl $_TIF_WORK_SYSCALL_ENTRY,TI_flags(%r10) CFI_REMEMBER_STATE jnz cstar_tracesys cstar_do_call: @@ -321,6 +323,7 @@ ENTRY(ia32_syscall) /*CFI_REL_OFFSET rflags,EFLAGS-RIP*/ /*CFI_REL_OFFSET cs,CS-RIP*/ CFI_REL_OFFSET rip,RIP-RIP + PARAVIRT_ADJUST_EXCEPTION_FRAME SWAPGS /* * No need to follow this irqs on/off section: the syscall @@ -336,8 +339,7 @@ ENTRY(ia32_syscall) SAVE_ARGS 0,0,1 GET_THREAD_INFO(%r10) orl $TS_COMPAT,TI_status(%r10) - testl $(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT|_TIF_SECCOMP), \ - TI_flags(%r10) + testl $_TIF_WORK_SYSCALL_ENTRY,TI_flags(%r10) jnz ia32_tracesys ia32_do_syscall: cmpl $(IA32_NR_syscalls-1),%eax diff --git a/arch/x86/kernel/Makefile b/arch/x86/kernel/Makefile index da140611bb57..b78a17b12810 100644 --- a/arch/x86/kernel/Makefile +++ b/arch/x86/kernel/Makefile @@ -102,6 +102,7 @@ obj-$(CONFIG_OLPC) += olpc.o # 64 bit specific files ifeq ($(CONFIG_X86_64),y) obj-y += genapic_64.o genapic_flat_64.o genx2apic_uv_x.o tlb_uv.o + obj-y += bios_uv.o obj-$(CONFIG_X86_PM_TIMER) += pmtimer_64.o obj-$(CONFIG_AUDIT) += audit_64.o diff --git a/arch/x86/kernel/acpi/sleep.c b/arch/x86/kernel/acpi/sleep.c index 868de3d5c39d..a3ddad18aaa3 100644 --- a/arch/x86/kernel/acpi/sleep.c +++ b/arch/x86/kernel/acpi/sleep.c @@ -9,6 +9,7 @@ #include <linux/bootmem.h> #include <linux/dmi.h> #include <linux/cpumask.h> +#include <asm/segment.h> #include "realmode/wakeup.h" #include "sleep.h" @@ -23,15 +24,6 @@ static unsigned long acpi_realmode; static char temp_stack[10240]; #endif -/* XXX: this macro should move to asm-x86/segment.h and be shared with the - boot code... */ -#define GDT_ENTRY(flags, base, limit) \ - (((u64)(base & 0xff000000) << 32) | \ - ((u64)flags << 40) | \ - ((u64)(limit & 0x00ff0000) << 32) | \ - ((u64)(base & 0x00ffffff) << 16) | \ - ((u64)(limit & 0x0000ffff))) - /** * acpi_save_state_mem - save kernel state * diff --git a/arch/x86/kernel/amd_iommu.c b/arch/x86/kernel/amd_iommu.c index f2766d84c7a0..c25210e6ac88 100644 --- a/arch/x86/kernel/amd_iommu.c +++ b/arch/x86/kernel/amd_iommu.c @@ -23,7 +23,7 @@ #include <linux/scatterlist.h> #include <linux/iommu-helper.h> #include <asm/proto.h> -#include <asm/gart.h> +#include <asm/iommu.h> #include <asm/amd_iommu_types.h> #include <asm/amd_iommu.h> @@ -32,21 +32,37 @@ #define to_pages(addr, size) \ (round_up(((addr) & ~PAGE_MASK) + (size), PAGE_SIZE) >> PAGE_SHIFT) +#define EXIT_LOOP_COUNT 10000000 + static DEFINE_RWLOCK(amd_iommu_devtable_lock); -struct command { +/* + * general struct to manage commands send to an IOMMU + */ +struct iommu_cmd { u32 data[4]; }; static int dma_ops_unity_map(struct dma_ops_domain *dma_dom, struct unity_map_entry *e); +/* returns !0 if the IOMMU is caching non-present entries in its TLB */ static int iommu_has_npcache(struct amd_iommu *iommu) { return iommu->cap & IOMMU_CAP_NPCACHE; } -static int __iommu_queue_command(struct amd_iommu *iommu, struct command *cmd) +/**************************************************************************** + * + * IOMMU command queuing functions + * + ****************************************************************************/ + +/* + * Writes the command to the IOMMUs command buffer and informs the + * hardware about the new command. Must be called with iommu->lock held. + */ +static int __iommu_queue_command(struct amd_iommu *iommu, struct iommu_cmd *cmd) { u32 tail, head; u8 *target; @@ -63,7 +79,11 @@ static int __iommu_queue_command(struct amd_iommu *iommu, struct command *cmd) return 0; } -static int iommu_queue_command(struct amd_iommu *iommu, struct command *cmd) +/* + * General queuing function for commands. Takes iommu->lock and calls + * __iommu_queue_command(). + */ +static int iommu_queue_command(struct amd_iommu *iommu, struct iommu_cmd *cmd) { unsigned long flags; int ret; @@ -75,16 +95,24 @@ static int iommu_queue_command(struct amd_iommu *iommu, struct command *cmd) return ret; } +/* + * This function is called whenever we need to ensure that the IOMMU has + * completed execution of all commands we sent. It sends a + * COMPLETION_WAIT command and waits for it to finish. The IOMMU informs + * us about that by writing a value to a physical address we pass with + * the command. + */ static int iommu_completion_wait(struct amd_iommu *iommu) { int ret; - struct command cmd; + struct iommu_cmd cmd; volatile u64 ready = 0; unsigned long ready_phys = virt_to_phys(&ready); + unsigned long i = 0; memset(&cmd, 0, sizeof(cmd)); cmd.data[0] = LOW_U32(ready_phys) | CMD_COMPL_WAIT_STORE_MASK; - cmd.data[1] = HIGH_U32(ready_phys); + cmd.data[1] = upper_32_bits(ready_phys); cmd.data[2] = 1; /* value written to 'ready' */ CMD_SET_TYPE(&cmd, CMD_COMPL_WAIT); @@ -95,15 +123,23 @@ static int iommu_completion_wait(struct amd_iommu *iommu) if (ret) return ret; - while (!ready) + while (!ready && (i < EXIT_LOOP_COUNT)) { + ++i; cpu_relax(); + } + + if (unlikely((i == EXIT_LOOP_COUNT) && printk_ratelimit())) + printk(KERN_WARNING "AMD IOMMU: Completion wait loop failed\n"); return 0; } +/* + * Command send function for invalidating a device table entry + */ static int iommu_queue_inv_dev_entry(struct amd_iommu *iommu, u16 devid) { - struct command cmd; + struct iommu_cmd cmd; BUG_ON(iommu == NULL); @@ -116,20 +152,23 @@ static int iommu_queue_inv_dev_entry(struct amd_iommu *iommu, u16 devid) return iommu_queue_command(iommu, &cmd); } +/* + * Generic command send function for invalidaing TLB entries + */ static int iommu_queue_inv_iommu_pages(struct amd_iommu *iommu, u64 address, u16 domid, int pde, int s) { - struct command cmd; + struct iommu_cmd cmd; memset(&cmd, 0, sizeof(cmd)); address &= PAGE_MASK; CMD_SET_TYPE(&cmd, CMD_INV_IOMMU_PAGES); cmd.data[1] |= domid; cmd.data[2] = LOW_U32(address); - cmd.data[3] = HIGH_U32(address); - if (s) + cmd.data[3] = upper_32_bits(address); + if (s) /* size bit - we flush more than one 4kb page */ cmd.data[2] |= CMD_INV_IOMMU_PAGES_SIZE_MASK; - if (pde) + if (pde) /* PDE bit - we wan't flush everything not only the PTEs */ cmd.data[2] |= CMD_INV_IOMMU_PAGES_PDE_MASK; iommu->need_sync = 1; @@ -137,6 +176,11 @@ static int iommu_queue_inv_iommu_pages(struct amd_iommu *iommu, return iommu_queue_command(iommu, &cmd); } +/* + * TLB invalidation function which is called from the mapping functions. + * It invalidates a single PTE if the range to flush is within a single + * page. Otherwise it flushes the whole TLB of the IOMMU. + */ static int iommu_flush_pages(struct amd_iommu *iommu, u16 domid, u64 address, size_t size) { @@ -159,6 +203,20 @@ static int iommu_flush_pages(struct amd_iommu *iommu, u16 domid, return 0; } +/**************************************************************************** + * + * The functions below are used the create the page table mappings for + * unity mapped regions. + * + ****************************************************************************/ + +/* + * Generic mapping functions. It maps a physical address into a DMA + * address space. It allocates the page table pages if necessary. + * In the future it can be extended to a generic mapping function + * supporting all features of AMD IOMMU page tables like level skipping + * and full 64 bit address spaces. + */ static int iommu_map(struct protection_domain *dom, unsigned long bus_addr, unsigned long phys_addr, @@ -209,6 +267,10 @@ static int iommu_map(struct protection_domain *dom, return 0; } +/* + * This function checks if a specific unity mapping entry is needed for + * this specific IOMMU. + */ static int iommu_for_unity_map(struct amd_iommu *iommu, struct unity_map_entry *entry) { @@ -223,6 +285,12 @@ static int iommu_for_unity_map(struct amd_iommu *iommu, return 0; } +/* + * Init the unity mappings for a specific IOMMU in the system + * + * Basically iterates over all unity mapping entries and applies them to + * the default domain DMA of that IOMMU if necessary. + */ static int iommu_init_unity_mappings(struct amd_iommu *iommu) { struct unity_map_entry *entry; @@ -239,6 +307,10 @@ static int iommu_init_unity_mappings(struct amd_iommu *iommu) return 0; } +/* + * This function actually applies the mapping to the page table of the + * dma_ops domain. + */ static int dma_ops_unity_map(struct dma_ops_domain *dma_dom, struct unity_map_entry *e) { @@ -261,6 +333,9 @@ static int dma_ops_unity_map(struct dma_ops_domain *dma_dom, return 0; } +/* + * Inits the unity mappings required for a specific device + */ static int init_unity_mappings_for_device(struct dma_ops_domain *dma_dom, u16 devid) { @@ -278,12 +353,26 @@ static int init_unity_mappings_for_device(struct dma_ops_domain *dma_dom, return 0; } +/**************************************************************************** + * + * The next functions belong to the address allocator for the dma_ops + * interface functions. They work like the allocators in the other IOMMU + * drivers. Its basically a bitmap which marks the allocated pages in + * the aperture. Maybe it could be enhanced in the future to a more + * efficient allocator. + * + ****************************************************************************/ static unsigned long dma_mask_to_pages(unsigned long mask) { return (mask >> PAGE_SHIFT) + (PAGE_ALIGN(mask & ~PAGE_MASK) >> PAGE_SHIFT); } +/* + * The address allocator core function. + * + * called with domain->lock held + */ static unsigned long dma_ops_alloc_addresses(struct device *dev, struct dma_ops_domain *dom, unsigned int pages) @@ -317,6 +406,11 @@ static unsigned long dma_ops_alloc_addresses(struct device *dev, return address; } +/* + * The address free function. + * + * called with domain->lock held + */ static void dma_ops_free_addresses(struct dma_ops_domain *dom, unsigned long address, unsigned int pages) @@ -325,6 +419,16 @@ static void dma_ops_free_addresses(struct dma_ops_domain *dom, iommu_area_free(dom->bitmap, address, pages); } +/**************************************************************************** + * + * The next functions belong to the domain allocation. A domain is + * allocated for every IOMMU as the default domain. If device isolation + * is enabled, every device get its own domain. The most important thing + * about domains is the page table mapping the DMA address space they + * contain. + * + ****************************************************************************/ + static u16 domain_id_alloc(void) { unsigned long flags; @@ -342,6 +446,10 @@ static u16 domain_id_alloc(void) return id; } +/* + * Used to reserve address ranges in the aperture (e.g. for exclusion + * ranges. + */ static void dma_ops_reserve_addresses(struct dma_ops_domain *dom, unsigned long start_page, unsigned int pages) @@ -382,6 +490,10 @@ static void dma_ops_free_pagetable(struct dma_ops_domain *dma_dom) free_page((unsigned long)p1); } +/* + * Free a domain, only used if something went wrong in the + * allocation path and we need to free an already allocated page table + */ static void dma_ops_domain_free(struct dma_ops_domain *dom) { if (!dom) @@ -396,6 +508,11 @@ static void dma_ops_domain_free(struct dma_ops_domain *dom) kfree(dom); } +/* + * Allocates a new protection domain usable for the dma_ops functions. + * It also intializes the page table and the address allocator data + * structures required for the dma_ops interface + */ static struct dma_ops_domain *dma_ops_domain_alloc(struct amd_iommu *iommu, unsigned order) { @@ -436,6 +553,7 @@ static struct dma_ops_domain *dma_ops_domain_alloc(struct amd_iommu *iommu, dma_dom->bitmap[0] = 1; dma_dom->next_bit = 0; + /* Intialize the exclusion range if necessary */ if (iommu->exclusion_start && iommu->exclusion_start < dma_dom->aperture_size) { unsigned long startpage = iommu->exclusion_start >> PAGE_SHIFT; @@ -444,6 +562,11 @@ static struct dma_ops_domain *dma_ops_domain_alloc(struct amd_iommu *iommu, dma_ops_reserve_addresses(dma_dom, startpage, pages); } + /* + * At the last step, build the page tables so we don't need to + * allocate page table pages in the dma_ops mapping/unmapping + * path. + */ num_pte_pages = dma_dom->aperture_size / (PAGE_SIZE * 512); dma_dom->pte_pages = kzalloc(num_pte_pages * sizeof(void *), GFP_KERNEL); @@ -472,6 +595,10 @@ free_dma_dom: return NULL; } +/* + * Find out the protection domain structure for a given PCI device. This + * will give us the pointer to the page table root for example. + */ static struct protection_domain *domain_for_device(u16 devid) { struct protection_domain *dom; @@ -484,6 +611,10 @@ static struct protection_domain *domain_for_device(u16 devid) return dom; } +/* + * If a device is not yet associated with a domain, this function does + * assigns it visible for the hardware + */ static void set_device_domain(struct amd_iommu *iommu, struct protection_domain *domain, u16 devid) @@ -508,6 +639,19 @@ static void set_device_domain(struct amd_iommu *iommu, iommu->need_sync = 1; } +/***************************************************************************** + * + * The next functions belong to the dma_ops mapping/unmapping code. + * + *****************************************************************************/ + +/* + * In the dma_ops path we only have the struct device. This function + * finds the corresponding IOMMU, the protection domain and the + * requestor id for a given device. + * If the device is not yet associated with a domain this is also done + * in this function. + */ static int get_device_resources(struct device *dev, struct amd_iommu **iommu, struct protection_domain **domain, @@ -520,8 +664,9 @@ static int get_device_resources(struct device *dev, BUG_ON(!dev || dev->bus != &pci_bus_type || !dev->dma_mask); pcidev = to_pci_dev(dev); - _bdf = (pcidev->bus->number << 8) | pcidev->devfn; + _bdf = calc_devid(pcidev->bus->number, pcidev->devfn); + /* device not translated by any IOMMU in the system? */ if (_bdf >= amd_iommu_last_bdf) { *iommu = NULL; *domain = NULL; @@ -547,6 +692,10 @@ static int get_device_resources(struct device *dev, return 1; } +/* + * This is the generic map function. It maps one 4kb page at paddr to + * the given address in the DMA address space for the domain. + */ static dma_addr_t dma_ops_domain_map(struct amd_iommu *iommu, struct dma_ops_domain *dom, unsigned long address, @@ -578,6 +727,9 @@ static dma_addr_t dma_ops_domain_map(struct amd_iommu *iommu, return (dma_addr_t)address; } +/* + * The generic unmapping function for on page in the DMA address space. + */ static void dma_ops_domain_unmap(struct amd_iommu *iommu, struct dma_ops_domain *dom, unsigned long address) @@ -597,6 +749,12 @@ static void dma_ops_domain_unmap(struct amd_iommu *iommu, *pte = 0ULL; } +/* + * This function contains common code for mapping of a physically + * contiguous memory region into DMA address space. It is uses by all + * mapping functions provided by this IOMMU driver. + * Must be called with the domain lock held. + */ static dma_addr_t __map_single(struct device *dev, struct amd_iommu *iommu, struct dma_ops_domain *dma_dom, @@ -628,6 +786,10 @@ out: return address; } +/* + * Does the reverse of the __map_single function. Must be called with + * the domain lock held too + */ static void __unmap_single(struct amd_iommu *iommu, struct dma_ops_domain *dma_dom, dma_addr_t dma_addr, @@ -652,6 +814,9 @@ static void __unmap_single(struct amd_iommu *iommu, dma_ops_free_addresses(dma_dom, dma_addr, pages); } +/* + * The exported map_single function for dma_ops. + */ static dma_addr_t map_single(struct device *dev, phys_addr_t paddr, size_t size, int dir) { @@ -664,6 +829,7 @@ static dma_addr_t map_single(struct device *dev, phys_addr_t paddr, get_device_resources(dev, &iommu, &domain, &devid); if (iommu == NULL || domain == NULL) + /* device not handled by any AMD IOMMU */ return (dma_addr_t)paddr; spin_lock_irqsave(&domain->lock, flags); @@ -683,6 +849,9 @@ out: return addr; } +/* + * The exported unmap_single function for dma_ops. + */ static void unmap_single(struct device *dev, dma_addr_t dma_addr, size_t size, int dir) { @@ -692,6 +861,7 @@ static void unmap_single(struct device *dev, dma_addr_t dma_addr, u16 devid; if (!get_device_resources(dev, &iommu, &domain, &devid)) + /* device not handled by any AMD IOMMU */ return; spin_lock_irqsave(&domain->lock, flags); @@ -706,6 +876,10 @@ static void unmap_single(struct device *dev, dma_addr_t dma_addr, spin_unlock_irqrestore(&domain->lock, flags); } +/* + * This is a special map_sg function which is used if we should map a + * device which is not handled by an AMD IOMMU in the system. + */ static int map_sg_no_iommu(struct device *dev, struct scatterlist *sglist, int nelems, int dir) { @@ -720,6 +894,10 @@ static int map_sg_no_iommu(struct device *dev, struct scatterlist *sglist, return nelems; } +/* + * The exported map_sg function for dma_ops (handles scatter-gather + * lists). + */ static int map_sg(struct device *dev, struct scatterlist *sglist, int nelems, int dir) { @@ -775,6 +953,10 @@ unmap: goto out; } +/* + * The exported map_sg function for dma_ops (handles scatter-gather + * lists). + */ static void unmap_sg(struct device *dev, struct scatterlist *sglist, int nelems, int dir) { @@ -804,6 +986,9 @@ static void unmap_sg(struct device *dev, struct scatterlist *sglist, spin_unlock_irqrestore(&domain->lock, flags); } +/* + * The exported alloc_coherent function for dma_ops. + */ static void *alloc_coherent(struct device *dev, size_t size, dma_addr_t *dma_addr, gfp_t flag) { @@ -851,6 +1036,11 @@ out: return virt_addr; } +/* + * The exported free_coherent function for dma_ops. + * FIXME: fix the generic x86 DMA layer so that it actually calls that + * function. + */ static void free_coherent(struct device *dev, size_t size, void *virt_addr, dma_addr_t dma_addr) { @@ -879,6 +1069,8 @@ free_mem: } /* + * The function for pre-allocating protection domains. + * * If the driver core informs the DMA layer if a driver grabs a device * we don't need to preallocate the protection domains anymore. * For now we have to. @@ -921,12 +1113,20 @@ static struct dma_mapping_ops amd_iommu_dma_ops = { .unmap_sg = unmap_sg, }; +/* + * The function which clues the AMD IOMMU driver into dma_ops. + */ int __init amd_iommu_init_dma_ops(void) { struct amd_iommu *iommu; int order = amd_iommu_aperture_order; int ret; + /* + * first allocate a default protection domain for every IOMMU we + * found in the system. Devices not assigned to any other + * protection domain will be assigned to the default one. + */ list_for_each_entry(iommu, &amd_iommu_list, list) { iommu->default_dom = dma_ops_domain_alloc(iommu, order); if (iommu->default_dom == NULL) @@ -936,6 +1136,10 @@ int __init amd_iommu_init_dma_ops(void) goto free_domains; } + /* + * If device isolation is enabled, pre-allocate the protection + * domains for each device. + */ if (amd_iommu_isolate) prealloc_protection_domains(); @@ -947,6 +1151,7 @@ int __init amd_iommu_init_dma_ops(void) gart_iommu_aperture = 0; #endif + /* Make the driver finally visible to the drivers */ dma_ops = &amd_iommu_dma_ops; return 0; diff --git a/arch/x86/kernel/amd_iommu_init.c b/arch/x86/kernel/amd_iommu_init.c index 2a13e430437d..c9d8ff2eb130 100644 --- a/arch/x86/kernel/amd_iommu_init.c +++ b/arch/x86/kernel/amd_iommu_init.c @@ -25,20 +25,13 @@ #include <asm/pci-direct.h> #include <asm/amd_iommu_types.h> #include <asm/amd_iommu.h> -#include <asm/gart.h> +#include <asm/iommu.h> /* * definitions for the ACPI scanning code */ -#define UPDATE_LAST_BDF(x) do {\ - if ((x) > amd_iommu_last_bdf) \ - amd_iommu_last_bdf = (x); \ - } while (0); - -#define DEVID(bus, devfn) (((bus) << 8) | (devfn)) #define PCI_BUS(x) (((x) >> 8) & 0xff) #define IVRS_HEADER_LENGTH 48 -#define TBL_SIZE(x) (1 << (PAGE_SHIFT + get_order(amd_iommu_last_bdf * (x)))) #define ACPI_IVHD_TYPE 0x10 #define ACPI_IVMD_TYPE_ALL 0x20 @@ -71,6 +64,17 @@ #define ACPI_DEVFLAG_LINT1 0x80 #define ACPI_DEVFLAG_ATSDIS 0x10000000 +/* + * ACPI table definitions + * + * These data structures are laid over the table to parse the important values + * out of it. + */ + +/* + * structure describing one IOMMU in the ACPI table. Typically followed by one + * or more ivhd_entrys. + */ struct ivhd_header { u8 type; u8 flags; @@ -83,6 +87,10 @@ struct ivhd_header { u32 reserved; } __attribute__((packed)); +/* + * A device entry describing which devices a specific IOMMU translates and + * which requestor ids they use. + */ struct ivhd_entry { u8 type; u16 devid; @@ -90,6 +98,10 @@ struct ivhd_entry { u32 ext; } __attribute__((packed)); +/* + * An AMD IOMMU memory definition structure. It defines things like exclusion + * ranges for devices and regions that should be unity mapped. + */ struct ivmd_header { u8 type; u8 flags; @@ -103,22 +115,80 @@ struct ivmd_header { static int __initdata amd_iommu_detected; -u16 amd_iommu_last_bdf; -struct list_head amd_iommu_unity_map; -unsigned amd_iommu_aperture_order = 26; -int amd_iommu_isolate; +u16 amd_iommu_last_bdf; /* largest PCI device id we have + to handle */ +LIST_HEAD(amd_iommu_unity_map); /* a list of required unity mappings + we find in ACPI */ +unsigned amd_iommu_aperture_order = 26; /* size of aperture in power of 2 */ +int amd_iommu_isolate; /* if 1, device isolation is enabled */ + +LIST_HEAD(amd_iommu_list); /* list of all AMD IOMMUs in the + system */ -struct list_head amd_iommu_list; +/* + * Pointer to the device table which is shared by all AMD IOMMUs + * it is indexed by the PCI device id or the HT unit id and contains + * information about the domain the device belongs to as well as the + * page table root pointer. + */ struct dev_table_entry *amd_iommu_dev_table; + +/* + * The alias table is a driver specific data structure which contains the + * mappings of the PCI device ids to the actual requestor ids on the IOMMU. + * More than one device can share the same requestor id. + */ u16 *amd_iommu_alias_table; + +/* + * The rlookup table is used to find the IOMMU which is responsible + * for a specific device. It is also indexed by the PCI device id. + */ struct amd_iommu **amd_iommu_rlookup_table; + +/* + * The pd table (protection domain table) is used to find the protection domain + * data structure a device belongs to. Indexed with the PCI device id too. + */ struct protection_domain **amd_iommu_pd_table; + +/* + * AMD IOMMU allows up to 2^16 differend protection domains. This is a bitmap + * to know which ones are already in use. + */ unsigned long *amd_iommu_pd_alloc_bitmap; -static u32 dev_table_size; -static u32 alias_table_size; -static u32 rlookup_table_size; +static u32 dev_table_size; /* size of the device table */ +static u32 alias_table_size; /* size of the alias table */ +static u32 rlookup_table_size; /* size if the rlookup table */ +static inline void update_last_devid(u16 devid) +{ + if (devid > amd_iommu_last_bdf) + amd_iommu_last_bdf = devid; +} + +static inline unsigned long tbl_size(int entry_size) +{ + unsigned shift = PAGE_SHIFT + + get_order(amd_iommu_last_bdf * entry_size); + + return 1UL << shift; +} + +/**************************************************************************** + * + * AMD IOMMU MMIO register space handling functions + * + * These functions are used to program the IOMMU device registers in + * MMIO space required for that driver. + * + ****************************************************************************/ + +/* + * This function set the exclusion range in the IOMMU. DMA accesses to the + * exclusion range are passed through untranslated + */ static void __init iommu_set_exclusion_range(struct amd_iommu *iommu) { u64 start = iommu->exclusion_start & PAGE_MASK; @@ -137,6 +207,7 @@ static void __init iommu_set_exclusion_range(struct amd_iommu *iommu) &entry, sizeof(entry)); } +/* Programs the physical address of the device table into the IOMMU hardware */ static void __init iommu_set_device_table(struct amd_iommu *iommu) { u32 entry; @@ -149,6 +220,7 @@ static void __init iommu_set_device_table(struct amd_iommu *iommu) &entry, sizeof(entry)); } +/* Generic functions to enable/disable certain features of the IOMMU. */ static void __init iommu_feature_enable(struct amd_iommu *iommu, u8 bit) { u32 ctrl; @@ -167,6 +239,7 @@ static void __init iommu_feature_disable(struct amd_iommu *iommu, u8 bit) writel(ctrl, iommu->mmio_base + MMIO_CONTROL_OFFSET); } +/* Function to enable the hardware */ void __init iommu_enable(struct amd_iommu *iommu) { printk(KERN_INFO "AMD IOMMU: Enabling IOMMU at "); @@ -176,6 +249,10 @@ void __init iommu_enable(struct amd_iommu *iommu) iommu_feature_enable(iommu, CONTROL_IOMMU_EN); } +/* + * mapping and unmapping functions for the IOMMU MMIO space. Each AMD IOMMU in + * the system has one. + */ static u8 * __init iommu_map_mmio_space(u64 address) { u8 *ret; @@ -199,16 +276,33 @@ static void __init iommu_unmap_mmio_space(struct amd_iommu *iommu) release_mem_region(iommu->mmio_phys, MMIO_REGION_LENGTH); } +/**************************************************************************** + * + * The functions below belong to the first pass of AMD IOMMU ACPI table + * parsing. In this pass we try to find out the highest device id this + * code has to handle. Upon this information the size of the shared data + * structures is determined later. + * + ****************************************************************************/ + +/* + * This function reads the last device id the IOMMU has to handle from the PCI + * capability header for this IOMMU + */ static int __init find_last_devid_on_pci(int bus, int dev, int fn, int cap_ptr) { u32 cap; cap = read_pci_config(bus, dev, fn, cap_ptr+MMIO_RANGE_OFFSET); - UPDATE_LAST_BDF(DEVID(MMIO_GET_BUS(cap), MMIO_GET_LD(cap))); + update_last_devid(calc_devid(MMIO_GET_BUS(cap), MMIO_GET_LD(cap))); return 0; } +/* + * After reading the highest device id from the IOMMU PCI capability header + * this function looks if there is a higher device id defined in the ACPI table + */ static int __init find_last_devid_from_ivhd(struct ivhd_header *h) { u8 *p = (void *)h, *end = (void *)h; @@ -229,7 +323,8 @@ static int __init find_last_devid_from_ivhd(struct ivhd_header *h) case IVHD_DEV_RANGE_END: case IVHD_DEV_ALIAS: case IVHD_DEV_EXT_SELECT: - UPDATE_LAST_BDF(dev->devid); + /* all the above subfield types refer to device ids */ + update_last_devid(dev->devid); break; default: break; @@ -242,6 +337,11 @@ static int __init find_last_devid_from_ivhd(struct ivhd_header *h) return 0; } +/* + * Iterate over all IVHD entries in the ACPI table and find the highest device + * id which we need to handle. This is the first of three functions which parse + * the ACPI table. So we check the checksum here. + */ static int __init find_last_devid_acpi(struct acpi_table_header *table) { int i; @@ -277,19 +377,31 @@ static int __init find_last_devid_acpi(struct acpi_table_header *table) return 0; } +/**************************************************************************** + * + * The following functions belong the the code path which parses the ACPI table + * the second time. In this ACPI parsing iteration we allocate IOMMU specific + * data structures, initialize the device/alias/rlookup table and also + * basically initialize the hardware. + * + ****************************************************************************/ + +/* + * Allocates the command buffer. This buffer is per AMD IOMMU. We can + * write commands to that buffer later and the IOMMU will execute them + * asynchronously + */ static u8 * __init alloc_command_buffer(struct amd_iommu *iommu) { - u8 *cmd_buf = (u8 *)__get_free_pages(GFP_KERNEL, + u8 *cmd_buf = (u8 *)__get_free_pages(GFP_KERNEL | __GFP_ZERO, get_order(CMD_BUFFER_SIZE)); - u64 entry = 0; + u64 entry; if (cmd_buf == NULL) return NULL; iommu->cmd_buf_size = CMD_BUFFER_SIZE; - memset(cmd_buf, 0, CMD_BUFFER_SIZE); - entry = (u64)virt_to_phys(cmd_buf); entry |= MMIO_CMD_SIZE_512; memcpy_toio(iommu->mmio_base + MMIO_CMD_BUF_OFFSET, @@ -302,11 +414,10 @@ static u8 * __init alloc_command_buffer(struct amd_iommu *iommu) static void __init free_command_buffer(struct amd_iommu *iommu) { - if (iommu->cmd_buf) - free_pages((unsigned long)iommu->cmd_buf, - get_order(CMD_BUFFER_SIZE)); + free_pages((unsigned long)iommu->cmd_buf, get_order(CMD_BUFFER_SIZE)); } +/* sets a specific bit in the device table entry. */ static void set_dev_entry_bit(u16 devid, u8 bit) { int i = (bit >> 5) & 0x07; @@ -315,7 +426,18 @@ static void set_dev_entry_bit(u16 devid, u8 bit) amd_iommu_dev_table[devid].data[i] |= (1 << _bit); } -static void __init set_dev_entry_from_acpi(u16 devid, u32 flags, u32 ext_flags) +/* Writes the specific IOMMU for a device into the rlookup table */ +static void __init set_iommu_for_device(struct amd_iommu *iommu, u16 devid) +{ + amd_iommu_rlookup_table[devid] = iommu; +} + +/* + * This function takes the device specific flags read from the ACPI + * table and sets up the device table entry with that information + */ +static void __init set_dev_entry_from_acpi(struct amd_iommu *iommu, + u16 devid, u32 flags, u32 ext_flags) { if (flags & ACPI_DEVFLAG_INITPASS) set_dev_entry_bit(devid, DEV_ENTRY_INIT_PASS); @@ -331,13 +453,14 @@ static void __init set_dev_entry_from_acpi(u16 devid, u32 flags, u32 ext_flags) set_dev_entry_bit(devid, DEV_ENTRY_LINT0_PASS); if (flags & ACPI_DEVFLAG_LINT1) set_dev_entry_bit(devid, DEV_ENTRY_LINT1_PASS); -} -static void __init set_iommu_for_device(struct amd_iommu *iommu, u16 devid) -{ - amd_iommu_rlookup_table[devid] = iommu; + set_iommu_for_device(iommu, devid); } +/* + * Reads the device exclusion range from ACPI and initialize IOMMU with + * it + */ static void __init set_device_exclusion_range(u16 devid, struct ivmd_header *m) { struct amd_iommu *iommu = amd_iommu_rlookup_table[devid]; @@ -346,12 +469,22 @@ static void __init set_device_exclusion_range(u16 devid, struct ivmd_header *m) return; if (iommu) { + /* + * We only can configure exclusion ranges per IOMMU, not + * per device. But we can enable the exclusion range per + * device. This is done here + */ set_dev_entry_bit(m->devid, DEV_ENTRY_EX); iommu->exclusion_start = m->range_start; iommu->exclusion_length = m->range_length; } } +/* + * This function reads some important data from the IOMMU PCI space and + * initializes the driver data structure with it. It reads the hardware + * capabilities and the first/last device entries + */ static void __init init_iommu_from_pci(struct amd_iommu *iommu) { int bus = PCI_BUS(iommu->devid); @@ -363,10 +496,16 @@ static void __init init_iommu_from_pci(struct amd_iommu *iommu) iommu->cap = read_pci_config(bus, dev, fn, cap_ptr+MMIO_CAP_HDR_OFFSET); range = read_pci_config(bus, dev, fn, cap_ptr+MMIO_RANGE_OFFSET); - iommu->first_device = DEVID(MMIO_GET_BUS(range), MMIO_GET_FD(range)); - iommu->last_device = DEVID(MMIO_GET_BUS(range), MMIO_GET_LD(range)); + iommu->first_device = calc_devid(MMIO_GET_BUS(range), + MMIO_GET_FD(range)); + iommu->last_device = calc_devid(MMIO_GET_BUS(range), + MMIO_GET_LD(range)); } +/* + * Takes a pointer to an AMD IOMMU entry in the ACPI table and + * initializes the hardware and our data structures with it. + */ static void __init init_iommu_from_acpi(struct amd_iommu *iommu, struct ivhd_header *h) { @@ -374,7 +513,7 @@ static void __init init_iommu_from_acpi(struct amd_iommu *iommu, u8 *end = p, flags = 0; u16 dev_i, devid = 0, devid_start = 0, devid_to = 0; u32 ext_flags = 0; - bool alias = 0; + bool alias = false; struct ivhd_entry *e; /* @@ -414,22 +553,23 @@ static void __init init_iommu_from_acpi(struct amd_iommu *iommu, case IVHD_DEV_ALL: for (dev_i = iommu->first_device; dev_i <= iommu->last_device; ++dev_i) - set_dev_entry_from_acpi(dev_i, e->flags, 0); + set_dev_entry_from_acpi(iommu, dev_i, + e->flags, 0); break; case IVHD_DEV_SELECT: devid = e->devid; - set_dev_entry_from_acpi(devid, e->flags, 0); + set_dev_entry_from_acpi(iommu, devid, e->flags, 0); break; case IVHD_DEV_SELECT_RANGE_START: devid_start = e->devid; flags = e->flags; ext_flags = 0; - alias = 0; + alias = false; break; case IVHD_DEV_ALIAS: devid = e->devid; devid_to = e->ext >> 8; - set_dev_entry_from_acpi(devid, e->flags, 0); + set_dev_entry_from_acpi(iommu, devid, e->flags, 0); amd_iommu_alias_table[devid] = devid_to; break; case IVHD_DEV_ALIAS_RANGE: @@ -437,24 +577,25 @@ static void __init init_iommu_from_acpi(struct amd_iommu *iommu, flags = e->flags; devid_to = e->ext >> 8; ext_flags = 0; - alias = 1; + alias = true; break; case IVHD_DEV_EXT_SELECT: devid = e->devid; - set_dev_entry_from_acpi(devid, e->flags, e->ext); + set_dev_entry_from_acpi(iommu, devid, e->flags, + e->ext); break; case IVHD_DEV_EXT_SELECT_RANGE: devid_start = e->devid; flags = e->flags; ext_flags = e->ext; - alias = 0; + alias = false; break; case IVHD_DEV_RANGE_END: devid = e->devid; for (dev_i = devid_start; dev_i <= devid; ++dev_i) { if (alias) amd_iommu_alias_table[dev_i] = devid_to; - set_dev_entry_from_acpi( + set_dev_entry_from_acpi(iommu, amd_iommu_alias_table[dev_i], flags, ext_flags); } @@ -467,6 +608,7 @@ static void __init init_iommu_from_acpi(struct amd_iommu *iommu, } } +/* Initializes the device->iommu mapping for the driver */ static int __init init_iommu_devices(struct amd_iommu *iommu) { u16 i; @@ -494,6 +636,11 @@ static void __init free_iommu_all(void) } } +/* + * This function clues the initialization function for one IOMMU + * together and also allocates the command buffer and programs the + * hardware. It does NOT enable the IOMMU. This is done afterwards. + */ static int __init init_iommu_one(struct amd_iommu *iommu, struct ivhd_header *h) { spin_lock_init(&iommu->lock); @@ -521,6 +668,10 @@ static int __init init_iommu_one(struct amd_iommu *iommu, struct ivhd_header *h) return 0; } +/* + * Iterates over all IOMMU entries in the ACPI table, allocates the + * IOMMU structure and initializes it with init_iommu_one() + */ static int __init init_iommu_all(struct acpi_table_header *table) { u8 *p = (u8 *)table, *end = (u8 *)table; @@ -528,8 +679,6 @@ static int __init init_iommu_all(struct acpi_table_header *table) struct amd_iommu *iommu; int ret; - INIT_LIST_HEAD(&amd_iommu_list); - end += table->length; p += IVRS_HEADER_LENGTH; @@ -555,6 +704,14 @@ static int __init init_iommu_all(struct acpi_table_header *table) return 0; } +/**************************************************************************** + * + * The next functions belong to the third pass of parsing the ACPI + * table. In this last pass the memory mapping requirements are + * gathered (like exclusion and unity mapping reanges). + * + ****************************************************************************/ + static void __init free_unity_maps(void) { struct unity_map_entry *entry, *next; @@ -565,6 +722,7 @@ static void __init free_unity_maps(void) } } +/* called when we find an exclusion range definition in ACPI */ static int __init init_exclusion_range(struct ivmd_header *m) { int i; @@ -588,6 +746,7 @@ static int __init init_exclusion_range(struct ivmd_header *m) return 0; } +/* called for unity map ACPI definition */ static int __init init_unity_map_range(struct ivmd_header *m) { struct unity_map_entry *e = 0; @@ -619,13 +778,12 @@ static int __init init_unity_map_range(struct ivmd_header *m) return 0; } +/* iterates over all memory definitions we find in the ACPI table */ static int __init init_memory_definitions(struct acpi_table_header *table) { u8 *p = (u8 *)table, *end = (u8 *)table; struct ivmd_header *m; - INIT_LIST_HEAD(&amd_iommu_unity_map); - end += table->length; p += IVRS_HEADER_LENGTH; @@ -642,6 +800,10 @@ static int __init init_memory_definitions(struct acpi_table_header *table) return 0; } +/* + * This function finally enables all IOMMUs found in the system after + * they have been initialized + */ static void __init enable_iommus(void) { struct amd_iommu *iommu; @@ -678,6 +840,34 @@ static struct sys_device device_amd_iommu = { .cls = &amd_iommu_sysdev_class, }; +/* + * This is the core init function for AMD IOMMU hardware in the system. + * This function is called from the generic x86 DMA layer initialization + * code. + * + * This function basically parses the ACPI table for AMD IOMMU (IVRS) + * three times: + * + * 1 pass) Find the highest PCI device id the driver has to handle. + * Upon this information the size of the data structures is + * determined that needs to be allocated. + * + * 2 pass) Initialize the data structures just allocated with the + * information in the ACPI table about available AMD IOMMUs + * in the system. It also maps the PCI devices in the + * system to specific IOMMUs + * + * 3 pass) After the basic data structures are allocated and + * initialized we update them with information about memory + * remapping requirements parsed out of the ACPI table in + * this last pass. + * + * After that the hardware is initialized and ready to go. In the last + * step we do some Linux specific things like registering the driver in + * the dma_ops interface and initializing the suspend/resume support + * functions. Finally it prints some information about AMD IOMMUs and + * the driver state and enables the hardware. + */ int __init amd_iommu_init(void) { int i, ret = 0; @@ -699,14 +889,14 @@ int __init amd_iommu_init(void) if (acpi_table_parse("IVRS", find_last_devid_acpi) != 0) return -ENODEV; - dev_table_size = TBL_SIZE(DEV_TABLE_ENTRY_SIZE); - alias_table_size = TBL_SIZE(ALIAS_TABLE_ENTRY_SIZE); - rlookup_table_size = TBL_SIZE(RLOOKUP_TABLE_ENTRY_SIZE); + dev_table_size = tbl_size(DEV_TABLE_ENTRY_SIZE); + alias_table_size = tbl_size(ALIAS_TABLE_ENTRY_SIZE); + rlookup_table_size = tbl_size(RLOOKUP_TABLE_ENTRY_SIZE); ret = -ENOMEM; /* Device table - directly used by all IOMMUs */ - amd_iommu_dev_table = (void *)__get_free_pages(GFP_KERNEL, + amd_iommu_dev_table = (void *)__get_free_pages(GFP_KERNEL | __GFP_ZERO, get_order(dev_table_size)); if (amd_iommu_dev_table == NULL) goto out; @@ -730,27 +920,23 @@ int __init amd_iommu_init(void) * Protection Domain table - maps devices to protection domains * This table has the same size as the rlookup_table */ - amd_iommu_pd_table = (void *)__get_free_pages(GFP_KERNEL, + amd_iommu_pd_table = (void *)__get_free_pages(GFP_KERNEL | __GFP_ZERO, get_order(rlookup_table_size)); if (amd_iommu_pd_table == NULL) goto free; - amd_iommu_pd_alloc_bitmap = (void *)__get_free_pages(GFP_KERNEL, + amd_iommu_pd_alloc_bitmap = (void *)__get_free_pages( + GFP_KERNEL | __GFP_ZERO, get_order(MAX_DOMAIN_ID/8)); if (amd_iommu_pd_alloc_bitmap == NULL) goto free; /* - * memory is allocated now; initialize the device table with all zeroes - * and let all alias entries point to itself + * let all alias entries point to itself */ - memset(amd_iommu_dev_table, 0, dev_table_size); for (i = 0; i < amd_iommu_last_bdf; ++i) amd_iommu_alias_table[i] = i; - memset(amd_iommu_pd_table, 0, rlookup_table_size); - memset(amd_iommu_pd_alloc_bitmap, 0, MAX_DOMAIN_ID / 8); - /* * never allocate domain 0 because its used as the non-allocated and * error value placeholder @@ -795,24 +981,19 @@ out: return ret; free: - if (amd_iommu_pd_alloc_bitmap) - free_pages((unsigned long)amd_iommu_pd_alloc_bitmap, 1); + free_pages((unsigned long)amd_iommu_pd_alloc_bitmap, 1); - if (amd_iommu_pd_table) - free_pages((unsigned long)amd_iommu_pd_table, - get_order(rlookup_table_size)); + free_pages((unsigned long)amd_iommu_pd_table, + get_order(rlookup_table_size)); - if (amd_iommu_rlookup_table) - free_pages((unsigned long)amd_iommu_rlookup_table, - get_order(rlookup_table_size)); + free_pages((unsigned long)amd_iommu_rlookup_table, + get_order(rlookup_table_size)); - if (amd_iommu_alias_table) - free_pages((unsigned long)amd_iommu_alias_table, - get_order(alias_table_size)); + free_pages((unsigned long)amd_iommu_alias_table, + get_order(alias_table_size)); - if (amd_iommu_dev_table) - free_pages((unsigned long)amd_iommu_dev_table, - get_order(dev_table_size)); + free_pages((unsigned long)amd_iommu_dev_table, + get_order(dev_table_size)); free_iommu_all(); @@ -821,6 +1002,13 @@ free: goto out; } +/**************************************************************************** + * + * Early detect code. This code runs at IOMMU detection time in the DMA + * layer. It just looks if there is an IVRS ACPI table to detect AMD + * IOMMUs + * + ****************************************************************************/ static int __init early_amd_iommu_detect(struct acpi_table_header *table) { return 0; @@ -828,7 +1016,7 @@ static int __init early_amd_iommu_detect(struct acpi_table_header *table) void __init amd_iommu_detect(void) { - if (swiotlb || no_iommu || iommu_detected) + if (swiotlb || no_iommu || (iommu_detected && !gart_iommu_aperture)) return; if (acpi_table_parse("IVRS", early_amd_iommu_detect) == 0) { @@ -841,6 +1029,13 @@ void __init amd_iommu_detect(void) } } +/**************************************************************************** + * + * Parsing functions for the AMD IOMMU specific kernel command line + * options. + * + ****************************************************************************/ + static int __init parse_amd_iommu_options(char *str) { for (; *str; ++str) { @@ -853,20 +1048,10 @@ static int __init parse_amd_iommu_options(char *str) static int __init parse_amd_iommu_size_options(char *str) { - for (; *str; ++str) { - if (strcmp(str, "32M") == 0) - amd_iommu_aperture_order = 25; - if (strcmp(str, "64M") == 0) - amd_iommu_aperture_order = 26; - if (strcmp(str, "128M") == 0) - amd_iommu_aperture_order = 27; - if (strcmp(str, "256M") == 0) - amd_iommu_aperture_order = 28; - if (strcmp(str, "512M") == 0) - amd_iommu_aperture_order = 29; - if (strcmp(str, "1G") == 0) - amd_iommu_aperture_order = 30; - } + unsigned order = PAGE_SHIFT + get_order(memparse(str, &str)); + + if ((order > 24) && (order < 31)) + amd_iommu_aperture_order = order; return 1; } diff --git a/arch/x86/kernel/aperture_64.c b/arch/x86/kernel/aperture_64.c index 9f907806c1a5..44e21826db11 100644 --- a/arch/x86/kernel/aperture_64.c +++ b/arch/x86/kernel/aperture_64.c @@ -21,6 +21,7 @@ #include <linux/suspend.h> #include <asm/e820.h> #include <asm/io.h> +#include <asm/iommu.h> #include <asm/gart.h> #include <asm/pci-direct.h> #include <asm/dma.h> diff --git a/arch/x86/kernel/apic_32.c b/arch/x86/kernel/apic_32.c index 7f30c0f3dbe4..d6c898358371 100644 --- a/arch/x86/kernel/apic_32.c +++ b/arch/x86/kernel/apic_32.c @@ -1218,9 +1218,6 @@ int apic_version[MAX_APICS]; int __init APIC_init_uniprocessor(void) { - if (disable_apic) - clear_cpu_cap(&boot_cpu_data, X86_FEATURE_APIC); - if (!smp_found_config && !cpu_has_apic) return -1; @@ -1704,7 +1701,7 @@ early_param("lapic", parse_lapic); static int __init parse_nolapic(char *arg) { disable_apic = 1; - clear_cpu_cap(&boot_cpu_data, X86_FEATURE_APIC); + setup_clear_cpu_cap(X86_FEATURE_APIC); return 0; } early_param("nolapic", parse_nolapic); diff --git a/arch/x86/kernel/apic_64.c b/arch/x86/kernel/apic_64.c index 98c70f044e19..7f1f030da7ee 100644 --- a/arch/x86/kernel/apic_64.c +++ b/arch/x86/kernel/apic_64.c @@ -1341,7 +1341,7 @@ early_param("apic", apic_set_verbosity); static __init int setup_disableapic(char *str) { disable_apic = 1; - clear_cpu_cap(&boot_cpu_data, X86_FEATURE_APIC); + setup_clear_cpu_cap(X86_FEATURE_APIC); return 0; } early_param("disableapic", setup_disableapic); diff --git a/arch/x86/kernel/asm-offsets_64.c b/arch/x86/kernel/asm-offsets_64.c index bacf5deeec2d..aa89387006fe 100644 --- a/arch/x86/kernel/asm-offsets_64.c +++ b/arch/x86/kernel/asm-offsets_64.c @@ -18,6 +18,8 @@ #include <asm/ia32.h> #include <asm/bootparam.h> +#include <xen/interface/xen.h> + #define __NO_STUBS 1 #undef __SYSCALL #undef _ASM_X86_64_UNISTD_H_ @@ -131,5 +133,14 @@ int main(void) OFFSET(BP_loadflags, boot_params, hdr.loadflags); OFFSET(BP_hardware_subarch, boot_params, hdr.hardware_subarch); OFFSET(BP_version, boot_params, hdr.version); + + BLANK(); + DEFINE(PAGE_SIZE_asm, PAGE_SIZE); +#ifdef CONFIG_XEN + BLANK(); + OFFSET(XEN_vcpu_info_mask, vcpu_info, evtchn_upcall_mask); + OFFSET(XEN_vcpu_info_pending, vcpu_info, evtchn_upcall_pending); +#undef ENTRY +#endif return 0; } diff --git a/arch/x86/kernel/bios_uv.c b/arch/x86/kernel/bios_uv.c new file mode 100644 index 000000000000..c639bd55391c --- /dev/null +++ b/arch/x86/kernel/bios_uv.c @@ -0,0 +1,48 @@ +/* + * BIOS run time interface routines. + * + * Copyright (c) 2008 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <asm/uv/bios.h> + +const char * +x86_bios_strerror(long status) +{ + const char *str; + switch (status) { + case 0: str = "Call completed without error"; break; + case -1: str = "Not implemented"; break; + case -2: str = "Invalid argument"; break; + case -3: str = "Call completed with error"; break; + default: str = "Unknown BIOS status code"; break; + } + return str; +} + +long +x86_bios_freq_base(unsigned long which, unsigned long *ticks_per_second, + unsigned long *drift_info) +{ + struct uv_bios_retval isrv; + + BIOS_CALL(isrv, BIOS_FREQ_BASE, which, 0, 0, 0, 0, 0, 0); + *ticks_per_second = isrv.v0; + *drift_info = isrv.v1; + return isrv.status; +} +EXPORT_SYMBOL_GPL(x86_bios_freq_base); diff --git a/arch/x86/kernel/cpu/amd.c b/arch/x86/kernel/cpu/amd.c index 81a07ca65d44..cae9cabc3031 100644 --- a/arch/x86/kernel/cpu/amd.c +++ b/arch/x86/kernel/cpu/amd.c @@ -24,8 +24,6 @@ extern void vide(void); __asm__(".align 4\nvide: ret"); -int force_mwait __cpuinitdata; - static void __cpuinit early_init_amd(struct cpuinfo_x86 *c) { if (cpuid_eax(0x80000000) >= 0x80000007) { diff --git a/arch/x86/kernel/cpu/amd_64.c b/arch/x86/kernel/cpu/amd_64.c index 7c36fb8a28d4..d1692b2a41ff 100644 --- a/arch/x86/kernel/cpu/amd_64.c +++ b/arch/x86/kernel/cpu/amd_64.c @@ -115,6 +115,8 @@ static void __cpuinit early_init_amd(struct cpuinfo_x86 *c) /* c->x86_power is 8000_0007 edx. Bit 8 is constant TSC */ if (c->x86_power & (1<<8)) set_cpu_cap(c, X86_FEATURE_CONSTANT_TSC); + + set_cpu_cap(c, X86_FEATURE_SYSCALL32); } static void __cpuinit init_amd(struct cpuinfo_x86 *c) diff --git a/arch/x86/kernel/cpu/common_64.c b/arch/x86/kernel/cpu/common_64.c index 7b8cc72feb40..dd6e3f15017e 100644 --- a/arch/x86/kernel/cpu/common_64.c +++ b/arch/x86/kernel/cpu/common_64.c @@ -7,15 +7,13 @@ #include <linux/module.h> #include <linux/kgdb.h> #include <linux/topology.h> -#include <linux/string.h> #include <linux/delay.h> #include <linux/smp.h> -#include <linux/module.h> #include <linux/percpu.h> -#include <asm/processor.h> #include <asm/i387.h> #include <asm/msr.h> #include <asm/io.h> +#include <asm/linkage.h> #include <asm/mmu_context.h> #include <asm/mtrr.h> #include <asm/mce.h> @@ -305,7 +303,6 @@ static void __cpuinit early_identify_cpu(struct cpuinfo_x86 *c) c->x86_capability[2] = cpuid_edx(0x80860001); } - c->extended_cpuid_level = cpuid_eax(0x80000000); if (c->extended_cpuid_level >= 0x80000007) c->x86_power = cpuid_edx(0x80000007); @@ -316,18 +313,11 @@ static void __cpuinit early_identify_cpu(struct cpuinfo_x86 *c) c->x86_phys_bits = eax & 0xff; } - /* Assume all 64-bit CPUs support 32-bit syscall */ - set_cpu_cap(c, X86_FEATURE_SYSCALL32); - if (c->x86_vendor != X86_VENDOR_UNKNOWN && cpu_devs[c->x86_vendor]->c_early_init) cpu_devs[c->x86_vendor]->c_early_init(c); validate_pat_support(c); - - /* early_param could clear that, but recall get it set again */ - if (disable_apic) - clear_cpu_cap(c, X86_FEATURE_APIC); } /* @@ -517,8 +507,7 @@ void pda_init(int cpu) } char boot_exception_stacks[(N_EXCEPTION_STACKS - 1) * EXCEPTION_STKSZ + - DEBUG_STKSZ] -__attribute__((section(".bss.page_aligned"))); + DEBUG_STKSZ] __page_aligned_bss; extern asmlinkage void ignore_sysret(void); diff --git a/arch/x86/kernel/cpu/intel_cacheinfo.c b/arch/x86/kernel/cpu/intel_cacheinfo.c index 2c8afafa18e8..ff517f0b8cc4 100644 --- a/arch/x86/kernel/cpu/intel_cacheinfo.c +++ b/arch/x86/kernel/cpu/intel_cacheinfo.c @@ -780,15 +780,14 @@ static int __cpuinit cache_add_dev(struct sys_device * sys_dev) } kobject_put(per_cpu(cache_kobject, cpu)); cpuid4_cache_sysfs_exit(cpu); - break; + return retval; } kobject_uevent(&(this_object->kobj), KOBJ_ADD); } - if (!retval) - cpu_set(cpu, cache_dev_map); + cpu_set(cpu, cache_dev_map); kobject_uevent(per_cpu(cache_kobject, cpu), KOBJ_ADD); - return retval; + return 0; } static void __cpuinit cache_remove_dev(struct sys_device * sys_dev) diff --git a/arch/x86/kernel/e820.c b/arch/x86/kernel/e820.c index 28c29180b380..9af89078f7bb 100644 --- a/arch/x86/kernel/e820.c +++ b/arch/x86/kernel/e820.c @@ -877,7 +877,8 @@ void __init early_res_to_bootmem(u64 start, u64 end) for (i = 0; i < MAX_EARLY_RES && early_res[i].end; i++) count++; - printk(KERN_INFO "(%d early reservations) ==> bootmem\n", count); + printk(KERN_INFO "(%d early reservations) ==> bootmem [%010llx - %010llx]\n", + count, start, end); for (i = 0; i < count; i++) { struct early_res *r = &early_res[i]; printk(KERN_INFO " #%d [%010llx - %010llx] %16s", i, @@ -1298,11 +1299,6 @@ void __init e820_reserve_resources(void) } } -/* - * Non-standard memory setup can be specified via this quirk: - */ -char * (*arch_memory_setup_quirk)(void); - char *__init default_machine_specific_memory_setup(void) { char *who = "BIOS-e820"; @@ -1343,8 +1339,8 @@ char *__init default_machine_specific_memory_setup(void) char *__init __attribute__((weak)) machine_specific_memory_setup(void) { - if (arch_memory_setup_quirk) { - char *who = arch_memory_setup_quirk(); + if (x86_quirks->arch_memory_setup) { + char *who = x86_quirks->arch_memory_setup(); if (who) return who; @@ -1367,24 +1363,3 @@ void __init setup_memory_map(void) printk(KERN_INFO "BIOS-provided physical RAM map:\n"); e820_print_map(who); } - -#ifdef CONFIG_X86_64 -int __init arch_get_ram_range(int slot, u64 *addr, u64 *size) -{ - int i; - - if (slot < 0 || slot >= e820.nr_map) - return -1; - for (i = slot; i < e820.nr_map; i++) { - if (e820.map[i].type != E820_RAM) - continue; - break; - } - if (i == e820.nr_map || e820.map[i].addr > (max_pfn << PAGE_SHIFT)) - return -1; - *addr = e820.map[i].addr; - *size = min_t(u64, e820.map[i].size + e820.map[i].addr, - max_pfn << PAGE_SHIFT) - *addr; - return i + 1; -} -#endif diff --git a/arch/x86/kernel/early-quirks.c b/arch/x86/kernel/early-quirks.c index a0e11c0cc872..4353cf5e6fac 100644 --- a/arch/x86/kernel/early-quirks.c +++ b/arch/x86/kernel/early-quirks.c @@ -16,10 +16,7 @@ #include <asm/dma.h> #include <asm/io_apic.h> #include <asm/apic.h> - -#ifdef CONFIG_GART_IOMMU -#include <asm/gart.h> -#endif +#include <asm/iommu.h> static void __init fix_hypertransport_config(int num, int slot, int func) { diff --git a/arch/x86/kernel/entry_32.S b/arch/x86/kernel/entry_32.S index 6bc07f0f1202..cdfd94cc6b14 100644 --- a/arch/x86/kernel/entry_32.S +++ b/arch/x86/kernel/entry_32.S @@ -332,7 +332,7 @@ sysenter_past_esp: GET_THREAD_INFO(%ebp) /* Note, _TIF_SECCOMP is bit number 8, and so it needs testw and not testb */ - testw $(_TIF_SYSCALL_EMU|_TIF_SYSCALL_TRACE|_TIF_SECCOMP|_TIF_SYSCALL_AUDIT),TI_flags(%ebp) + testw $_TIF_WORK_SYSCALL_ENTRY,TI_flags(%ebp) jnz syscall_trace_entry cmpl $(nr_syscalls), %eax jae syscall_badsys @@ -370,7 +370,7 @@ ENTRY(system_call) GET_THREAD_INFO(%ebp) # system call tracing in operation / emulation /* Note, _TIF_SECCOMP is bit number 8, and so it needs testw and not testb */ - testw $(_TIF_SYSCALL_EMU|_TIF_SYSCALL_TRACE|_TIF_SECCOMP|_TIF_SYSCALL_AUDIT),TI_flags(%ebp) + testw $_TIF_WORK_SYSCALL_ENTRY,TI_flags(%ebp) jnz syscall_trace_entry cmpl $(nr_syscalls), %eax jae syscall_badsys @@ -383,10 +383,6 @@ syscall_exit: # setting need_resched or sigpending # between sampling and the iret TRACE_IRQS_OFF - testl $X86_EFLAGS_TF,PT_EFLAGS(%esp) # If tracing set singlestep flag on exit - jz no_singlestep - orl $_TIF_SINGLESTEP,TI_flags(%ebp) -no_singlestep: movl TI_flags(%ebp), %ecx testw $_TIF_ALLWORK_MASK, %cx # current->work jne syscall_exit_work @@ -514,12 +510,8 @@ END(work_pending) syscall_trace_entry: movl $-ENOSYS,PT_EAX(%esp) movl %esp, %eax - xorl %edx,%edx - call do_syscall_trace - cmpl $0, %eax - jne resume_userspace # ret != 0 -> running under PTRACE_SYSEMU, - # so must skip actual syscall - movl PT_ORIG_EAX(%esp), %eax + call syscall_trace_enter + /* What it returned is what we'll actually use. */ cmpl $(nr_syscalls), %eax jnae syscall_call jmp syscall_exit @@ -528,14 +520,13 @@ END(syscall_trace_entry) # perform syscall exit tracing ALIGN syscall_exit_work: - testb $(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT|_TIF_SINGLESTEP), %cl + testb $_TIF_WORK_SYSCALL_EXIT, %cl jz work_pending TRACE_IRQS_ON - ENABLE_INTERRUPTS(CLBR_ANY) # could let do_syscall_trace() call + ENABLE_INTERRUPTS(CLBR_ANY) # could let syscall_trace_leave() call # schedule() instead movl %esp, %eax - movl $1, %edx - call do_syscall_trace + call syscall_trace_leave jmp resume_userspace END(syscall_exit_work) CFI_ENDPROC @@ -1024,6 +1015,7 @@ ENDPROC(kernel_thread_helper) ENTRY(xen_sysenter_target) RING0_INT_FRAME addl $5*4, %esp /* remove xen-provided frame */ + CFI_ADJUST_CFA_OFFSET -5*4 jmp sysenter_past_esp CFI_ENDPROC diff --git a/arch/x86/kernel/entry_64.S b/arch/x86/kernel/entry_64.S index ae63e584c340..8410e26f4183 100644 --- a/arch/x86/kernel/entry_64.S +++ b/arch/x86/kernel/entry_64.S @@ -349,8 +349,7 @@ ENTRY(system_call_after_swapgs) movq %rcx,RIP-ARGOFFSET(%rsp) CFI_REL_OFFSET rip,RIP-ARGOFFSET GET_THREAD_INFO(%rcx) - testl $(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT|_TIF_SECCOMP), \ - TI_flags(%rcx) + testl $_TIF_WORK_SYSCALL_ENTRY,TI_flags(%rcx) jnz tracesys cmpq $__NR_syscall_max,%rax ja badsys @@ -430,7 +429,12 @@ tracesys: FIXUP_TOP_OF_STACK %rdi movq %rsp,%rdi call syscall_trace_enter - LOAD_ARGS ARGOFFSET /* reload args from stack in case ptrace changed it */ + /* + * Reload arg registers from stack in case ptrace changed them. + * We don't reload %rax because syscall_trace_enter() returned + * the value it wants us to use in the table lookup. + */ + LOAD_ARGS ARGOFFSET, 1 RESTORE_REST cmpq $__NR_syscall_max,%rax ja int_ret_from_sys_call /* RAX(%rsp) set to -ENOSYS above */ @@ -483,7 +487,7 @@ int_very_careful: ENABLE_INTERRUPTS(CLBR_NONE) SAVE_REST /* Check for syscall exit trace */ - testl $(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT|_TIF_SINGLESTEP),%edx + testl $_TIF_WORK_SYSCALL_EXIT,%edx jz int_signal pushq %rdi CFI_ADJUST_CFA_OFFSET 8 @@ -491,7 +495,7 @@ int_very_careful: call syscall_trace_leave popq %rdi CFI_ADJUST_CFA_OFFSET -8 - andl $~(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT|_TIF_SINGLESTEP),%edi + andl $~(_TIF_WORK_SYSCALL_EXIT|_TIF_SYSCALL_EMU),%edi jmp int_restore_rest int_signal: @@ -1189,6 +1193,7 @@ END(device_not_available) /* runs on exception stack */ KPROBE_ENTRY(debug) INTR_FRAME + PARAVIRT_ADJUST_EXCEPTION_FRAME pushq $0 CFI_ADJUST_CFA_OFFSET 8 paranoidentry do_debug, DEBUG_STACK @@ -1198,6 +1203,7 @@ KPROBE_END(debug) /* runs on exception stack */ KPROBE_ENTRY(nmi) INTR_FRAME + PARAVIRT_ADJUST_EXCEPTION_FRAME pushq $-1 CFI_ADJUST_CFA_OFFSET 8 paranoidentry do_nmi, 0, 0 @@ -1211,6 +1217,7 @@ KPROBE_END(nmi) KPROBE_ENTRY(int3) INTR_FRAME + PARAVIRT_ADJUST_EXCEPTION_FRAME pushq $0 CFI_ADJUST_CFA_OFFSET 8 paranoidentry do_int3, DEBUG_STACK @@ -1237,6 +1244,7 @@ END(coprocessor_segment_overrun) /* runs on exception stack */ ENTRY(double_fault) XCPT_FRAME + PARAVIRT_ADJUST_EXCEPTION_FRAME paranoidentry do_double_fault jmp paranoid_exit1 CFI_ENDPROC @@ -1253,6 +1261,7 @@ END(segment_not_present) /* runs on exception stack */ ENTRY(stack_segment) XCPT_FRAME + PARAVIRT_ADJUST_EXCEPTION_FRAME paranoidentry do_stack_segment jmp paranoid_exit1 CFI_ENDPROC @@ -1278,6 +1287,7 @@ END(spurious_interrupt_bug) /* runs on exception stack */ ENTRY(machine_check) INTR_FRAME + PARAVIRT_ADJUST_EXCEPTION_FRAME pushq $0 CFI_ADJUST_CFA_OFFSET 8 paranoidentry do_machine_check @@ -1312,3 +1322,103 @@ KPROBE_ENTRY(ignore_sysret) sysret CFI_ENDPROC ENDPROC(ignore_sysret) + +#ifdef CONFIG_XEN +ENTRY(xen_hypervisor_callback) + zeroentry xen_do_hypervisor_callback +END(xen_hypervisor_callback) + +/* +# A note on the "critical region" in our callback handler. +# We want to avoid stacking callback handlers due to events occurring +# during handling of the last event. To do this, we keep events disabled +# until we've done all processing. HOWEVER, we must enable events before +# popping the stack frame (can't be done atomically) and so it would still +# be possible to get enough handler activations to overflow the stack. +# Although unlikely, bugs of that kind are hard to track down, so we'd +# like to avoid the possibility. +# So, on entry to the handler we detect whether we interrupted an +# existing activation in its critical region -- if so, we pop the current +# activation and restart the handler using the previous one. +*/ +ENTRY(xen_do_hypervisor_callback) # do_hypervisor_callback(struct *pt_regs) + CFI_STARTPROC +/* Since we don't modify %rdi, evtchn_do_upall(struct *pt_regs) will + see the correct pointer to the pt_regs */ + movq %rdi, %rsp # we don't return, adjust the stack frame + CFI_ENDPROC + CFI_DEFAULT_STACK +11: incl %gs:pda_irqcount + movq %rsp,%rbp + CFI_DEF_CFA_REGISTER rbp + cmovzq %gs:pda_irqstackptr,%rsp + pushq %rbp # backlink for old unwinder + call xen_evtchn_do_upcall + popq %rsp + CFI_DEF_CFA_REGISTER rsp + decl %gs:pda_irqcount + jmp error_exit + CFI_ENDPROC +END(do_hypervisor_callback) + +/* +# Hypervisor uses this for application faults while it executes. +# We get here for two reasons: +# 1. Fault while reloading DS, ES, FS or GS +# 2. Fault while executing IRET +# Category 1 we do not need to fix up as Xen has already reloaded all segment +# registers that could be reloaded and zeroed the others. +# Category 2 we fix up by killing the current process. We cannot use the +# normal Linux return path in this case because if we use the IRET hypercall +# to pop the stack frame we end up in an infinite loop of failsafe callbacks. +# We distinguish between categories by comparing each saved segment register +# with its current contents: any discrepancy means we in category 1. +*/ +ENTRY(xen_failsafe_callback) + framesz = (RIP-0x30) /* workaround buggy gas */ + _frame framesz + CFI_REL_OFFSET rcx, 0 + CFI_REL_OFFSET r11, 8 + movw %ds,%cx + cmpw %cx,0x10(%rsp) + CFI_REMEMBER_STATE + jne 1f + movw %es,%cx + cmpw %cx,0x18(%rsp) + jne 1f + movw %fs,%cx + cmpw %cx,0x20(%rsp) + jne 1f + movw %gs,%cx + cmpw %cx,0x28(%rsp) + jne 1f + /* All segments match their saved values => Category 2 (Bad IRET). */ + movq (%rsp),%rcx + CFI_RESTORE rcx + movq 8(%rsp),%r11 + CFI_RESTORE r11 + addq $0x30,%rsp + CFI_ADJUST_CFA_OFFSET -0x30 + pushq $0 + CFI_ADJUST_CFA_OFFSET 8 + pushq %r11 + CFI_ADJUST_CFA_OFFSET 8 + pushq %rcx + CFI_ADJUST_CFA_OFFSET 8 + jmp general_protection + CFI_RESTORE_STATE +1: /* Segment mismatch => Category 1 (Bad segment). Retry the IRET. */ + movq (%rsp),%rcx + CFI_RESTORE rcx + movq 8(%rsp),%r11 + CFI_RESTORE r11 + addq $0x30,%rsp + CFI_ADJUST_CFA_OFFSET -0x30 + pushq $0 + CFI_ADJUST_CFA_OFFSET 8 + SAVE_ALL + jmp error_exit + CFI_ENDPROC +END(xen_failsafe_callback) + +#endif /* CONFIG_XEN */ diff --git a/arch/x86/kernel/genx2apic_uv_x.c b/arch/x86/kernel/genx2apic_uv_x.c index 711f11c30b06..3c3929340692 100644 --- a/arch/x86/kernel/genx2apic_uv_x.c +++ b/arch/x86/kernel/genx2apic_uv_x.c @@ -24,6 +24,7 @@ #include <asm/pgtable.h> #include <asm/uv/uv_mmrs.h> #include <asm/uv/uv_hub.h> +#include <asm/uv/bios.h> DEFINE_PER_CPU(struct uv_hub_info_s, __uv_hub_info); EXPORT_PER_CPU_SYMBOL_GPL(__uv_hub_info); @@ -40,6 +41,9 @@ EXPORT_SYMBOL_GPL(uv_cpu_to_blade); short uv_possible_blades; EXPORT_SYMBOL_GPL(uv_possible_blades); +unsigned long sn_rtc_cycles_per_second; +EXPORT_SYMBOL(sn_rtc_cycles_per_second); + /* Start with all IRQs pointing to boot CPU. IRQ balancing will shift them. */ static cpumask_t uv_target_cpus(void) @@ -272,6 +276,23 @@ static __init void map_mmioh_high(int max_pnode) map_high("MMIOH", mmioh.s.base, shift, map_uc); } +static __init void uv_rtc_init(void) +{ + long status, ticks_per_sec, drift; + + status = + x86_bios_freq_base(BIOS_FREQ_BASE_REALTIME_CLOCK, &ticks_per_sec, + &drift); + if (status != 0 || ticks_per_sec < 100000) { + printk(KERN_WARNING + "unable to determine platform RTC clock frequency, " + "guessing.\n"); + /* BIOS gives wrong value for clock freq. so guess */ + sn_rtc_cycles_per_second = 1000000000000UL / 30000UL; + } else + sn_rtc_cycles_per_second = ticks_per_sec; +} + static __init void uv_system_init(void) { union uvh_si_addr_map_config_u m_n_config; @@ -326,6 +347,8 @@ static __init void uv_system_init(void) gnode_upper = (((unsigned long)node_id.s.node_id) & ~((1 << n_val) - 1)) << m_val; + uv_rtc_init(); + for_each_present_cpu(cpu) { nid = cpu_to_node(cpu); pnode = uv_apicid_to_pnode(per_cpu(x86_cpu_to_apicid, cpu)); diff --git a/arch/x86/kernel/head64.c b/arch/x86/kernel/head64.c index c97819829146..1b318e903bf6 100644 --- a/arch/x86/kernel/head64.c +++ b/arch/x86/kernel/head64.c @@ -39,6 +39,13 @@ static struct x8664_pda *__cpu_pda[NR_CPUS] __initdata; static struct x8664_pda *__cpu_pda[NR_CPUS] __read_mostly; #endif +void __init x86_64_init_pda(void) +{ + _cpu_pda = __cpu_pda; + cpu_pda(0) = &_boot_cpu_pda; + pda_init(0); +} + static void __init zap_identity_mappings(void) { pgd_t *pgd = pgd_offset_k(0UL); @@ -102,9 +109,7 @@ void __init x86_64_start_kernel(char * real_mode_data) early_printk("Kernel alive\n"); - _cpu_pda = __cpu_pda; - cpu_pda(0) = &_boot_cpu_pda; - pda_init(0); + x86_64_init_pda(); early_printk("Kernel really alive\n"); diff --git a/arch/x86/kernel/head_64.S b/arch/x86/kernel/head_64.S index b07ac7b217cb..db3280afe886 100644 --- a/arch/x86/kernel/head_64.S +++ b/arch/x86/kernel/head_64.S @@ -407,6 +407,7 @@ ENTRY(phys_base) /* This must match the first entry in level2_kernel_pgt */ .quad 0x0000000000000000 +#include "../../x86/xen/xen-head.S" .section .bss, "aw", @nobits .align L1_CACHE_BYTES diff --git a/arch/x86/kernel/io_delay.c b/arch/x86/kernel/io_delay.c index 5921e5f0a640..1c3a66a67f83 100644 --- a/arch/x86/kernel/io_delay.c +++ b/arch/x86/kernel/io_delay.c @@ -103,6 +103,9 @@ void __init io_delay_init(void) static int __init io_delay_param(char *s) { + if (!s) + return -EINVAL; + if (!strcmp(s, "0x80")) io_delay_type = CONFIG_IO_DELAY_TYPE_0X80; else if (!strcmp(s, "0xed")) diff --git a/arch/x86/kernel/irq_32.c b/arch/x86/kernel/irq_32.c index 47a6f6f12478..1cf8c1fcc088 100644 --- a/arch/x86/kernel/irq_32.c +++ b/arch/x86/kernel/irq_32.c @@ -83,11 +83,8 @@ union irq_ctx { static union irq_ctx *hardirq_ctx[NR_CPUS] __read_mostly; static union irq_ctx *softirq_ctx[NR_CPUS] __read_mostly; -static char softirq_stack[NR_CPUS * THREAD_SIZE] - __attribute__((__section__(".bss.page_aligned"))); - -static char hardirq_stack[NR_CPUS * THREAD_SIZE] - __attribute__((__section__(".bss.page_aligned"))); +static char softirq_stack[NR_CPUS * THREAD_SIZE] __page_aligned_bss; +static char hardirq_stack[NR_CPUS * THREAD_SIZE] __page_aligned_bss; static void call_on_stack(void *func, void *stack) { diff --git a/arch/x86/kernel/kdebugfs.c b/arch/x86/kernel/kdebugfs.c index c03205991718..f2d43bc75514 100644 --- a/arch/x86/kernel/kdebugfs.c +++ b/arch/x86/kernel/kdebugfs.c @@ -12,9 +12,13 @@ #include <linux/init.h> #include <linux/io.h> #include <linux/mm.h> +#include <linux/module.h> #include <asm/setup.h> +struct dentry *arch_debugfs_dir; +EXPORT_SYMBOL(arch_debugfs_dir); + #ifdef CONFIG_DEBUG_BOOT_PARAMS struct setup_data_node { u64 paddr; @@ -209,6 +213,10 @@ static int __init arch_kdebugfs_init(void) { int error = 0; + arch_debugfs_dir = debugfs_create_dir("x86", NULL); + if (!arch_debugfs_dir) + return -ENOMEM; + #ifdef CONFIG_DEBUG_BOOT_PARAMS error = boot_params_kdebugfs_init(); #endif diff --git a/arch/x86/kernel/kprobes.c b/arch/x86/kernel/kprobes.c index b8c6743a13da..43c019f85f0d 100644 --- a/arch/x86/kernel/kprobes.c +++ b/arch/x86/kernel/kprobes.c @@ -860,7 +860,6 @@ static int __kprobes post_kprobe_handler(struct pt_regs *regs) resume_execution(cur, regs, kcb); regs->flags |= kcb->kprobe_saved_flags; - trace_hardirqs_fixup_flags(regs->flags); if ((kcb->kprobe_status != KPROBE_REENTER) && cur->post_handler) { kcb->kprobe_status = KPROBE_HIT_SSDONE; diff --git a/arch/x86/kernel/kvmclock.c b/arch/x86/kernel/kvmclock.c index 87edf1ceb1df..d02def06ca91 100644 --- a/arch/x86/kernel/kvmclock.c +++ b/arch/x86/kernel/kvmclock.c @@ -113,7 +113,7 @@ static void kvm_setup_secondary_clock(void) #endif #ifdef CONFIG_SMP -void __init kvm_smp_prepare_boot_cpu(void) +static void __init kvm_smp_prepare_boot_cpu(void) { WARN_ON(kvm_register_clock("primary cpu clock")); native_smp_prepare_boot_cpu(); diff --git a/arch/x86/kernel/module_64.c b/arch/x86/kernel/module_64.c index a888e67f5874..0e867676b5a5 100644 --- a/arch/x86/kernel/module_64.c +++ b/arch/x86/kernel/module_64.c @@ -150,7 +150,8 @@ int module_finalize(const Elf_Ehdr *hdr, const Elf_Shdr *sechdrs, struct module *me) { - const Elf_Shdr *s, *text = NULL, *alt = NULL, *locks = NULL; + const Elf_Shdr *s, *text = NULL, *alt = NULL, *locks = NULL, + *para = NULL; char *secstrings = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset; for (s = sechdrs; s < sechdrs + hdr->e_shnum; s++) { @@ -160,6 +161,8 @@ int module_finalize(const Elf_Ehdr *hdr, alt = s; if (!strcmp(".smp_locks", secstrings + s->sh_name)) locks= s; + if (!strcmp(".parainstructions", secstrings + s->sh_name)) + para = s; } if (alt) { @@ -175,6 +178,11 @@ int module_finalize(const Elf_Ehdr *hdr, tseg, tseg + text->sh_size); } + if (para) { + void *pseg = (void *)para->sh_addr; + apply_paravirt(pseg, pseg + para->sh_size); + } + return module_bug_finalize(hdr, sechdrs, me); } diff --git a/arch/x86/kernel/mpparse.c b/arch/x86/kernel/mpparse.c index 3b25e49380c6..6ae005ccaed8 100644 --- a/arch/x86/kernel/mpparse.c +++ b/arch/x86/kernel/mpparse.c @@ -27,6 +27,7 @@ #include <asm/bios_ebda.h> #include <asm/e820.h> #include <asm/trampoline.h> +#include <asm/setup.h> #include <mach_apic.h> #ifdef CONFIG_X86_32 @@ -48,76 +49,6 @@ static int __init mpf_checksum(unsigned char *mp, int len) return sum & 0xFF; } -#ifdef CONFIG_X86_NUMAQ -int found_numaq; -/* - * Have to match translation table entries to main table entries by counter - * hence the mpc_record variable .... can't see a less disgusting way of - * doing this .... - */ -struct mpc_config_translation { - unsigned char mpc_type; - unsigned char trans_len; - unsigned char trans_type; - unsigned char trans_quad; - unsigned char trans_global; - unsigned char trans_local; - unsigned short trans_reserved; -}; - - -static int mpc_record; -static struct mpc_config_translation *translation_table[MAX_MPC_ENTRY] - __cpuinitdata; - -static inline int generate_logical_apicid(int quad, int phys_apicid) -{ - return (quad << 4) + (phys_apicid ? phys_apicid << 1 : 1); -} - - -static inline int mpc_apic_id(struct mpc_config_processor *m, - struct mpc_config_translation *translation_record) -{ - int quad = translation_record->trans_quad; - int logical_apicid = generate_logical_apicid(quad, m->mpc_apicid); - - printk(KERN_DEBUG "Processor #%d %u:%u APIC version %d (quad %d, apic %d)\n", - m->mpc_apicid, - (m->mpc_cpufeature & CPU_FAMILY_MASK) >> 8, - (m->mpc_cpufeature & CPU_MODEL_MASK) >> 4, - m->mpc_apicver, quad, logical_apicid); - return logical_apicid; -} - -int mp_bus_id_to_node[MAX_MP_BUSSES]; - -int mp_bus_id_to_local[MAX_MP_BUSSES]; - -static void mpc_oem_bus_info(struct mpc_config_bus *m, char *name, - struct mpc_config_translation *translation) -{ - int quad = translation->trans_quad; - int local = translation->trans_local; - - mp_bus_id_to_node[m->mpc_busid] = quad; - mp_bus_id_to_local[m->mpc_busid] = local; - printk(KERN_INFO "Bus #%d is %s (node %d)\n", - m->mpc_busid, name, quad); -} - -int quad_local_to_mp_bus_id [NR_CPUS/4][4]; -static void mpc_oem_pci_bus(struct mpc_config_bus *m, - struct mpc_config_translation *translation) -{ - int quad = translation->trans_quad; - int local = translation->trans_local; - - quad_local_to_mp_bus_id[quad][local] = m->mpc_busid; -} - -#endif - static void __cpuinit MP_processor_info(struct mpc_config_processor *m) { int apicid; @@ -127,14 +58,12 @@ static void __cpuinit MP_processor_info(struct mpc_config_processor *m) disabled_cpus++; return; } -#ifdef CONFIG_X86_NUMAQ - if (found_numaq) - apicid = mpc_apic_id(m, translation_table[mpc_record]); + + if (x86_quirks->mpc_apic_id) + apicid = x86_quirks->mpc_apic_id(m); else apicid = m->mpc_apicid; -#else - apicid = m->mpc_apicid; -#endif + if (m->mpc_cpuflag & CPU_BOOTPROCESSOR) { bootup_cpu = " (Bootup-CPU)"; boot_cpu_physical_apicid = m->mpc_apicid; @@ -151,12 +80,10 @@ static void __init MP_bus_info(struct mpc_config_bus *m) memcpy(str, m->mpc_bustype, 6); str[6] = 0; -#ifdef CONFIG_X86_NUMAQ - if (found_numaq) - mpc_oem_bus_info(m, str, translation_table[mpc_record]); -#else - printk(KERN_INFO "Bus #%d is %s\n", m->mpc_busid, str); -#endif + if (x86_quirks->mpc_oem_bus_info) + x86_quirks->mpc_oem_bus_info(m, str); + else + printk(KERN_INFO "Bus #%d is %s\n", m->mpc_busid, str); #if MAX_MP_BUSSES < 256 if (m->mpc_busid >= MAX_MP_BUSSES) { @@ -173,10 +100,9 @@ static void __init MP_bus_info(struct mpc_config_bus *m) mp_bus_id_to_type[m->mpc_busid] = MP_BUS_ISA; #endif } else if (strncmp(str, BUSTYPE_PCI, sizeof(BUSTYPE_PCI) - 1) == 0) { -#ifdef CONFIG_X86_NUMAQ - if (found_numaq) - mpc_oem_pci_bus(m, translation_table[mpc_record]); -#endif + if (x86_quirks->mpc_oem_pci_bus) + x86_quirks->mpc_oem_pci_bus(m); + clear_bit(m->mpc_busid, mp_bus_not_pci); #if defined(CONFIG_EISA) || defined (CONFIG_MCA) mp_bus_id_to_type[m->mpc_busid] = MP_BUS_PCI; @@ -316,83 +242,6 @@ static void __init MP_lintsrc_info(struct mpc_config_lintsrc *m) m->mpc_srcbusirq, m->mpc_destapic, m->mpc_destapiclint); } -#ifdef CONFIG_X86_NUMAQ -static void __init MP_translation_info(struct mpc_config_translation *m) -{ - printk(KERN_INFO - "Translation: record %d, type %d, quad %d, global %d, local %d\n", - mpc_record, m->trans_type, m->trans_quad, m->trans_global, - m->trans_local); - - if (mpc_record >= MAX_MPC_ENTRY) - printk(KERN_ERR "MAX_MPC_ENTRY exceeded!\n"); - else - translation_table[mpc_record] = m; /* stash this for later */ - if (m->trans_quad < MAX_NUMNODES && !node_online(m->trans_quad)) - node_set_online(m->trans_quad); -} - -/* - * Read/parse the MPC oem tables - */ - -static void __init smp_read_mpc_oem(struct mp_config_oemtable *oemtable, - unsigned short oemsize) -{ - int count = sizeof(*oemtable); /* the header size */ - unsigned char *oemptr = ((unsigned char *)oemtable) + count; - - mpc_record = 0; - printk(KERN_INFO "Found an OEM MPC table at %8p - parsing it ... \n", - oemtable); - if (memcmp(oemtable->oem_signature, MPC_OEM_SIGNATURE, 4)) { - printk(KERN_WARNING - "SMP mpc oemtable: bad signature [%c%c%c%c]!\n", - oemtable->oem_signature[0], oemtable->oem_signature[1], - oemtable->oem_signature[2], oemtable->oem_signature[3]); - return; - } - if (mpf_checksum((unsigned char *)oemtable, oemtable->oem_length)) { - printk(KERN_WARNING "SMP oem mptable: checksum error!\n"); - return; - } - while (count < oemtable->oem_length) { - switch (*oemptr) { - case MP_TRANSLATION: - { - struct mpc_config_translation *m = - (struct mpc_config_translation *)oemptr; - MP_translation_info(m); - oemptr += sizeof(*m); - count += sizeof(*m); - ++mpc_record; - break; - } - default: - { - printk(KERN_WARNING - "Unrecognised OEM table entry type! - %d\n", - (int)*oemptr); - return; - } - } - } -} - -void numaq_mps_oem_check(struct mp_config_table *mpc, char *oem, - char *productid) -{ - if (strncmp(oem, "IBM NUMA", 8)) - printk("Warning! Not a NUMA-Q system!\n"); - else - found_numaq = 1; - - if (mpc->mpc_oemptr) - smp_read_mpc_oem((struct mp_config_oemtable *)mpc->mpc_oemptr, - mpc->mpc_oemsize); -} -#endif /* CONFIG_X86_NUMAQ */ - /* * Read/parse the MPC */ @@ -457,7 +306,6 @@ static int __init smp_read_mpc(struct mp_config_table *mpc, unsigned early) } else mps_oem_check(mpc, oem, str); #endif - /* save the local APIC address, it might be non-default */ if (!acpi_lapic) mp_lapic_addr = mpc->mpc_lapic; @@ -465,12 +313,17 @@ static int __init smp_read_mpc(struct mp_config_table *mpc, unsigned early) if (early) return 1; + if (mpc->mpc_oemptr && x86_quirks->smp_read_mpc_oem) { + struct mp_config_oemtable *oem_table = (struct mp_config_oemtable *)(unsigned long)mpc->mpc_oemptr; + x86_quirks->smp_read_mpc_oem(oem_table, mpc->mpc_oemsize); + } + /* * Now process the configuration blocks. */ -#ifdef CONFIG_X86_NUMAQ - mpc_record = 0; -#endif + if (x86_quirks->mpc_record) + *x86_quirks->mpc_record = 0; + while (count < mpc->mpc_length) { switch (*mpt) { case MP_PROCESSOR: @@ -536,9 +389,8 @@ static int __init smp_read_mpc(struct mp_config_table *mpc, unsigned early) count = mpc->mpc_length; break; } -#ifdef CONFIG_X86_NUMAQ - ++mpc_record; -#endif + if (x86_quirks->mpc_record) + (*x86_quirks->mpc_record)++; } #ifdef CONFIG_X86_GENERICARCH @@ -726,20 +578,14 @@ static inline void __init construct_default_ISA_mptable(int mpc_default_type) static struct intel_mp_floating *mpf_found; /* - * Machine specific quirk for finding the SMP config before other setup - * activities destroy the table: - */ -int (*mach_get_smp_config_quirk)(unsigned int early); - -/* * Scan the memory blocks for an SMP configuration block. */ static void __init __get_smp_config(unsigned int early) { struct intel_mp_floating *mpf = mpf_found; - if (mach_get_smp_config_quirk) { - if (mach_get_smp_config_quirk(early)) + if (x86_quirks->mach_get_smp_config) { + if (x86_quirks->mach_get_smp_config(early)) return; } if (acpi_lapic && early) @@ -899,14 +745,12 @@ static int __init smp_scan_config(unsigned long base, unsigned long length, return 0; } -int (*mach_find_smp_config_quirk)(unsigned int reserve); - static void __init __find_smp_config(unsigned int reserve) { unsigned int address; - if (mach_find_smp_config_quirk) { - if (mach_find_smp_config_quirk(reserve)) + if (x86_quirks->mach_find_smp_config) { + if (x86_quirks->mach_find_smp_config(reserve)) return; } /* diff --git a/arch/x86/kernel/nmi.c b/arch/x86/kernel/nmi.c index 384b49fed598..ac6d51222e7d 100644 --- a/arch/x86/kernel/nmi.c +++ b/arch/x86/kernel/nmi.c @@ -448,6 +448,13 @@ nmi_watchdog_tick(struct pt_regs *regs, unsigned reason) #ifdef CONFIG_SYSCTL +static int __init setup_unknown_nmi_panic(char *str) +{ + unknown_nmi_panic = 1; + return 1; +} +__setup("unknown_nmi_panic", setup_unknown_nmi_panic); + static int unknown_nmi_panic_callback(struct pt_regs *regs, int cpu) { unsigned char reason = get_nmi_reason(); diff --git a/arch/x86/kernel/numaq_32.c b/arch/x86/kernel/numaq_32.c index a23e8233b9ac..b8c45610b20a 100644 --- a/arch/x86/kernel/numaq_32.c +++ b/arch/x86/kernel/numaq_32.c @@ -33,6 +33,7 @@ #include <asm/processor.h> #include <asm/mpspec.h> #include <asm/e820.h> +#include <asm/setup.h> #define MB_TO_PAGES(addr) ((addr) << (20 - PAGE_SHIFT)) @@ -71,6 +72,188 @@ static void __init smp_dump_qct(void) } } + +void __init numaq_tsc_disable(void) +{ + if (!found_numaq) + return; + + if (num_online_nodes() > 1) { + printk(KERN_DEBUG "NUMAQ: disabling TSC\n"); + setup_clear_cpu_cap(X86_FEATURE_TSC); + } +} + +static int __init numaq_pre_time_init(void) +{ + numaq_tsc_disable(); + return 0; +} + +int found_numaq; +/* + * Have to match translation table entries to main table entries by counter + * hence the mpc_record variable .... can't see a less disgusting way of + * doing this .... + */ +struct mpc_config_translation { + unsigned char mpc_type; + unsigned char trans_len; + unsigned char trans_type; + unsigned char trans_quad; + unsigned char trans_global; + unsigned char trans_local; + unsigned short trans_reserved; +}; + +/* x86_quirks member */ +static int mpc_record; +static struct mpc_config_translation *translation_table[MAX_MPC_ENTRY] + __cpuinitdata; + +static inline int generate_logical_apicid(int quad, int phys_apicid) +{ + return (quad << 4) + (phys_apicid ? phys_apicid << 1 : 1); +} + +/* x86_quirks member */ +static int mpc_apic_id(struct mpc_config_processor *m) +{ + int quad = translation_table[mpc_record]->trans_quad; + int logical_apicid = generate_logical_apicid(quad, m->mpc_apicid); + + printk(KERN_DEBUG "Processor #%d %u:%u APIC version %d (quad %d, apic %d)\n", + m->mpc_apicid, + (m->mpc_cpufeature & CPU_FAMILY_MASK) >> 8, + (m->mpc_cpufeature & CPU_MODEL_MASK) >> 4, + m->mpc_apicver, quad, logical_apicid); + return logical_apicid; +} + +int mp_bus_id_to_node[MAX_MP_BUSSES]; + +int mp_bus_id_to_local[MAX_MP_BUSSES]; + +/* x86_quirks member */ +static void mpc_oem_bus_info(struct mpc_config_bus *m, char *name) +{ + int quad = translation_table[mpc_record]->trans_quad; + int local = translation_table[mpc_record]->trans_local; + + mp_bus_id_to_node[m->mpc_busid] = quad; + mp_bus_id_to_local[m->mpc_busid] = local; + printk(KERN_INFO "Bus #%d is %s (node %d)\n", + m->mpc_busid, name, quad); +} + +int quad_local_to_mp_bus_id [NR_CPUS/4][4]; + +/* x86_quirks member */ +static void mpc_oem_pci_bus(struct mpc_config_bus *m) +{ + int quad = translation_table[mpc_record]->trans_quad; + int local = translation_table[mpc_record]->trans_local; + + quad_local_to_mp_bus_id[quad][local] = m->mpc_busid; +} + +static void __init MP_translation_info(struct mpc_config_translation *m) +{ + printk(KERN_INFO + "Translation: record %d, type %d, quad %d, global %d, local %d\n", + mpc_record, m->trans_type, m->trans_quad, m->trans_global, + m->trans_local); + + if (mpc_record >= MAX_MPC_ENTRY) + printk(KERN_ERR "MAX_MPC_ENTRY exceeded!\n"); + else + translation_table[mpc_record] = m; /* stash this for later */ + if (m->trans_quad < MAX_NUMNODES && !node_online(m->trans_quad)) + node_set_online(m->trans_quad); +} + +static int __init mpf_checksum(unsigned char *mp, int len) +{ + int sum = 0; + + while (len--) + sum += *mp++; + + return sum & 0xFF; +} + +/* + * Read/parse the MPC oem tables + */ + +static void __init smp_read_mpc_oem(struct mp_config_oemtable *oemtable, + unsigned short oemsize) +{ + int count = sizeof(*oemtable); /* the header size */ + unsigned char *oemptr = ((unsigned char *)oemtable) + count; + + mpc_record = 0; + printk(KERN_INFO "Found an OEM MPC table at %8p - parsing it ... \n", + oemtable); + if (memcmp(oemtable->oem_signature, MPC_OEM_SIGNATURE, 4)) { + printk(KERN_WARNING + "SMP mpc oemtable: bad signature [%c%c%c%c]!\n", + oemtable->oem_signature[0], oemtable->oem_signature[1], + oemtable->oem_signature[2], oemtable->oem_signature[3]); + return; + } + if (mpf_checksum((unsigned char *)oemtable, oemtable->oem_length)) { + printk(KERN_WARNING "SMP oem mptable: checksum error!\n"); + return; + } + while (count < oemtable->oem_length) { + switch (*oemptr) { + case MP_TRANSLATION: + { + struct mpc_config_translation *m = + (struct mpc_config_translation *)oemptr; + MP_translation_info(m); + oemptr += sizeof(*m); + count += sizeof(*m); + ++mpc_record; + break; + } + default: + { + printk(KERN_WARNING + "Unrecognised OEM table entry type! - %d\n", + (int)*oemptr); + return; + } + } + } +} + +static struct x86_quirks numaq_x86_quirks __initdata = { + .arch_pre_time_init = numaq_pre_time_init, + .arch_time_init = NULL, + .arch_pre_intr_init = NULL, + .arch_memory_setup = NULL, + .arch_intr_init = NULL, + .arch_trap_init = NULL, + .mach_get_smp_config = NULL, + .mach_find_smp_config = NULL, + .mpc_record = &mpc_record, + .mpc_apic_id = mpc_apic_id, + .mpc_oem_bus_info = mpc_oem_bus_info, + .mpc_oem_pci_bus = mpc_oem_pci_bus, + .smp_read_mpc_oem = smp_read_mpc_oem, +}; + +void numaq_mps_oem_check(struct mp_config_table *mpc, char *oem, + char *productid) +{ + if (strncmp(oem, "IBM NUMA", 8)) + printk("Warning! Not a NUMA-Q system!\n"); + else + found_numaq = 1; +} + static __init void early_check_numaq(void) { /* @@ -82,6 +265,9 @@ static __init void early_check_numaq(void) */ if (smp_found_config) early_get_smp_config(); + + if (found_numaq) + x86_quirks = &numaq_x86_quirks; } int __init get_memcfg_numaq(void) @@ -92,14 +278,3 @@ int __init get_memcfg_numaq(void) smp_dump_qct(); return 1; } - -void __init numaq_tsc_disable(void) -{ - if (!found_numaq) - return; - - if (num_online_nodes() > 1) { - printk(KERN_DEBUG "NUMAQ: disabling TSC\n"); - setup_clear_cpu_cap(X86_FEATURE_TSC); - } -} diff --git a/arch/x86/kernel/paravirt.c b/arch/x86/kernel/paravirt.c index 5d7326a60b7c..b4564d089b43 100644 --- a/arch/x86/kernel/paravirt.c +++ b/arch/x86/kernel/paravirt.c @@ -29,6 +29,7 @@ #include <asm/desc.h> #include <asm/setup.h> #include <asm/arch_hooks.h> +#include <asm/pgtable.h> #include <asm/time.h> #include <asm/pgalloc.h> #include <asm/irq.h> @@ -372,6 +373,9 @@ struct pv_mmu_ops pv_mmu_ops = { #ifndef CONFIG_X86_64 .pagetable_setup_start = native_pagetable_setup_start, .pagetable_setup_done = native_pagetable_setup_done, +#else + .pagetable_setup_start = paravirt_nop, + .pagetable_setup_done = paravirt_nop, #endif .read_cr2 = native_read_cr2, diff --git a/arch/x86/kernel/pci-calgary_64.c b/arch/x86/kernel/pci-calgary_64.c index 6959b5c45df4..151f2d171f7c 100644 --- a/arch/x86/kernel/pci-calgary_64.c +++ b/arch/x86/kernel/pci-calgary_64.c @@ -36,7 +36,7 @@ #include <linux/delay.h> #include <linux/scatterlist.h> #include <linux/iommu-helper.h> -#include <asm/gart.h> +#include <asm/iommu.h> #include <asm/calgary.h> #include <asm/tce.h> #include <asm/pci-direct.h> diff --git a/arch/x86/kernel/pci-dma.c b/arch/x86/kernel/pci-dma.c index 8467ec2320f1..a4213c00dffc 100644 --- a/arch/x86/kernel/pci-dma.c +++ b/arch/x86/kernel/pci-dma.c @@ -5,12 +5,11 @@ #include <asm/proto.h> #include <asm/dma.h> -#include <asm/gart.h> +#include <asm/iommu.h> #include <asm/calgary.h> #include <asm/amd_iommu.h> -int forbid_dac __read_mostly; -EXPORT_SYMBOL(forbid_dac); +static int forbid_dac __read_mostly; const struct dma_mapping_ops *dma_ops; EXPORT_SYMBOL(dma_ops); @@ -114,21 +113,15 @@ void __init pci_iommu_alloc(void) * The order of these functions is important for * fall-back/fail-over reasons */ -#ifdef CONFIG_GART_IOMMU gart_iommu_hole_init(); -#endif -#ifdef CONFIG_CALGARY_IOMMU detect_calgary(); -#endif detect_intel_iommu(); amd_iommu_detect(); -#ifdef CONFIG_SWIOTLB pci_swiotlb_init(); -#endif } #endif @@ -184,9 +177,7 @@ static __init int iommu_setup(char *p) swiotlb = 1; #endif -#ifdef CONFIG_GART_IOMMU gart_parse_options(p); -#endif #ifdef CONFIG_CALGARY_IOMMU if (!strncmp(p, "calgary", 7)) @@ -500,17 +491,13 @@ EXPORT_SYMBOL(dma_free_coherent); static int __init pci_iommu_init(void) { -#ifdef CONFIG_CALGARY_IOMMU calgary_iommu_init(); -#endif intel_iommu_init(); amd_iommu_init(); -#ifdef CONFIG_GART_IOMMU gart_iommu_init(); -#endif no_iommu_init(); return 0; diff --git a/arch/x86/kernel/pci-gart_64.c b/arch/x86/kernel/pci-gart_64.c index c3fe78406d18..be60961f8695 100644 --- a/arch/x86/kernel/pci-gart_64.c +++ b/arch/x86/kernel/pci-gart_64.c @@ -32,6 +32,7 @@ #include <asm/mtrr.h> #include <asm/pgtable.h> #include <asm/proto.h> +#include <asm/iommu.h> #include <asm/gart.h> #include <asm/cacheflush.h> #include <asm/swiotlb.h> diff --git a/arch/x86/kernel/pci-nommu.c b/arch/x86/kernel/pci-nommu.c index aec43d56f49c..792b9179eff3 100644 --- a/arch/x86/kernel/pci-nommu.c +++ b/arch/x86/kernel/pci-nommu.c @@ -7,7 +7,7 @@ #include <linux/dma-mapping.h> #include <linux/scatterlist.h> -#include <asm/gart.h> +#include <asm/iommu.h> #include <asm/processor.h> #include <asm/dma.h> diff --git a/arch/x86/kernel/pci-swiotlb_64.c b/arch/x86/kernel/pci-swiotlb_64.c index 82299cd1d04d..20df839b9c20 100644 --- a/arch/x86/kernel/pci-swiotlb_64.c +++ b/arch/x86/kernel/pci-swiotlb_64.c @@ -5,7 +5,7 @@ #include <linux/module.h> #include <linux/dma-mapping.h> -#include <asm/gart.h> +#include <asm/iommu.h> #include <asm/swiotlb.h> #include <asm/dma.h> diff --git a/arch/x86/kernel/process.c b/arch/x86/kernel/process.c index 4d629c62f4f8..7fc4d5b0a6a0 100644 --- a/arch/x86/kernel/process.c +++ b/arch/x86/kernel/process.c @@ -15,6 +15,7 @@ unsigned long idle_nomwait; EXPORT_SYMBOL(idle_nomwait); struct kmem_cache *task_xstate_cachep; +static int force_mwait __cpuinitdata; int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src) { @@ -199,6 +200,7 @@ static void poll_idle(void) * * idle=mwait overrides this decision and forces the usage of mwait. */ +static int __cpuinitdata force_mwait; #define MWAIT_INFO 0x05 #define MWAIT_ECX_EXTENDED_INFO 0x01 @@ -326,6 +328,9 @@ void __cpuinit select_idle_routine(const struct cpuinfo_x86 *c) static int __init idle_setup(char *str) { + if (!str) + return -EINVAL; + if (!strcmp(str, "poll")) { printk("using polling idle threads.\n"); pm_idle = poll_idle; diff --git a/arch/x86/kernel/process_64.c b/arch/x86/kernel/process_64.c index a8e53626ac9a..e8a8e1b99817 100644 --- a/arch/x86/kernel/process_64.c +++ b/arch/x86/kernel/process_64.c @@ -537,8 +537,8 @@ static inline void __switch_to_xtra(struct task_struct *prev_p, struct task_struct * __switch_to(struct task_struct *prev_p, struct task_struct *next_p) { - struct thread_struct *prev = &prev_p->thread, - *next = &next_p->thread; + struct thread_struct *prev = &prev_p->thread; + struct thread_struct *next = &next_p->thread; int cpu = smp_processor_id(); struct tss_struct *tss = &per_cpu(init_tss, cpu); unsigned fsindex, gsindex; @@ -586,35 +586,34 @@ __switch_to(struct task_struct *prev_p, struct task_struct *next_p) /* * Switch FS and GS. + * + * Segment register != 0 always requires a reload. Also + * reload when it has changed. When prev process used 64bit + * base always reload to avoid an information leak. */ - { - /* segment register != 0 always requires a reload. - also reload when it has changed. - when prev process used 64bit base always reload - to avoid an information leak. */ - if (unlikely(fsindex | next->fsindex | prev->fs)) { - loadsegment(fs, next->fsindex); - /* check if the user used a selector != 0 - * if yes clear 64bit base, since overloaded base - * is always mapped to the Null selector - */ - if (fsindex) + if (unlikely(fsindex | next->fsindex | prev->fs)) { + loadsegment(fs, next->fsindex); + /* + * Check if the user used a selector != 0; if yes + * clear 64bit base, since overloaded base is always + * mapped to the Null selector + */ + if (fsindex) prev->fs = 0; - } - /* when next process has a 64bit base use it */ - if (next->fs) - wrmsrl(MSR_FS_BASE, next->fs); - prev->fsindex = fsindex; - - if (unlikely(gsindex | next->gsindex | prev->gs)) { - load_gs_index(next->gsindex); - if (gsindex) + } + /* when next process has a 64bit base use it */ + if (next->fs) + wrmsrl(MSR_FS_BASE, next->fs); + prev->fsindex = fsindex; + + if (unlikely(gsindex | next->gsindex | prev->gs)) { + load_gs_index(next->gsindex); + if (gsindex) prev->gs = 0; - } - if (next->gs) - wrmsrl(MSR_KERNEL_GS_BASE, next->gs); - prev->gsindex = gsindex; } + if (next->gs) + wrmsrl(MSR_KERNEL_GS_BASE, next->gs); + prev->gsindex = gsindex; /* Must be after DS reload */ unlazy_fpu(prev_p); @@ -627,7 +626,8 @@ __switch_to(struct task_struct *prev_p, struct task_struct *next_p) write_pda(pcurrent, next_p); write_pda(kernelstack, - (unsigned long)task_stack_page(next_p) + THREAD_SIZE - PDA_STACKOFFSET); + (unsigned long)task_stack_page(next_p) + + THREAD_SIZE - PDA_STACKOFFSET); #ifdef CONFIG_CC_STACKPROTECTOR write_pda(stack_canary, next_p->stack_canary); /* diff --git a/arch/x86/kernel/ptrace.c b/arch/x86/kernel/ptrace.c index 77040b6070e1..e37dccce85db 100644 --- a/arch/x86/kernel/ptrace.c +++ b/arch/x86/kernel/ptrace.c @@ -1357,8 +1357,6 @@ const struct user_regset_view *task_user_regset_view(struct task_struct *task) #endif } -#ifdef CONFIG_X86_32 - void send_sigtrap(struct task_struct *tsk, struct pt_regs *regs, int error_code) { struct siginfo info; @@ -1377,89 +1375,10 @@ void send_sigtrap(struct task_struct *tsk, struct pt_regs *regs, int error_code) force_sig_info(SIGTRAP, &info, tsk); } -/* notification of system call entry/exit - * - triggered by current->work.syscall_trace - */ -int do_syscall_trace(struct pt_regs *regs, int entryexit) -{ - int is_sysemu = test_thread_flag(TIF_SYSCALL_EMU); - /* - * With TIF_SYSCALL_EMU set we want to ignore TIF_SINGLESTEP for syscall - * interception - */ - int is_singlestep = !is_sysemu && test_thread_flag(TIF_SINGLESTEP); - int ret = 0; - - /* do the secure computing check first */ - if (!entryexit) - secure_computing(regs->orig_ax); - - if (unlikely(current->audit_context)) { - if (entryexit) - audit_syscall_exit(AUDITSC_RESULT(regs->ax), - regs->ax); - /* Debug traps, when using PTRACE_SINGLESTEP, must be sent only - * on the syscall exit path. Normally, when TIF_SYSCALL_AUDIT is - * not used, entry.S will call us only on syscall exit, not - * entry; so when TIF_SYSCALL_AUDIT is used we must avoid - * calling send_sigtrap() on syscall entry. - * - * Note that when PTRACE_SYSEMU_SINGLESTEP is used, - * is_singlestep is false, despite his name, so we will still do - * the correct thing. - */ - else if (is_singlestep) - goto out; - } - - if (!(current->ptrace & PT_PTRACED)) - goto out; - - /* If a process stops on the 1st tracepoint with SYSCALL_TRACE - * and then is resumed with SYSEMU_SINGLESTEP, it will come in - * here. We have to check this and return */ - if (is_sysemu && entryexit) - return 0; - - /* Fake a debug trap */ - if (is_singlestep) - send_sigtrap(current, regs, 0); - - if (!test_thread_flag(TIF_SYSCALL_TRACE) && !is_sysemu) - goto out; - - /* the 0x80 provides a way for the tracing parent to distinguish - between a syscall stop and SIGTRAP delivery */ - /* Note that the debugger could change the result of test_thread_flag!*/ - ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD) ? 0x80:0)); - - /* - * this isn't the same as continuing with a signal, but it will do - * for normal use. strace only continues with a signal if the - * stopping signal is not SIGTRAP. -brl - */ - if (current->exit_code) { - send_sig(current->exit_code, current, 1); - current->exit_code = 0; - } - ret = is_sysemu; -out: - if (unlikely(current->audit_context) && !entryexit) - audit_syscall_entry(AUDIT_ARCH_I386, regs->orig_ax, - regs->bx, regs->cx, regs->dx, regs->si); - if (ret == 0) - return 0; - - regs->orig_ax = -1; /* force skip of syscall restarting */ - if (unlikely(current->audit_context)) - audit_syscall_exit(AUDITSC_RESULT(regs->ax), regs->ax); - return 1; -} - -#else /* CONFIG_X86_64 */ - static void syscall_trace(struct pt_regs *regs) { + if (!(current->ptrace & PT_PTRACED)) + return; #if 0 printk("trace %s ip %lx sp %lx ax %d origrax %d caller %lx tiflags %x ptrace %x\n", @@ -1481,39 +1400,81 @@ static void syscall_trace(struct pt_regs *regs) } } -asmlinkage void syscall_trace_enter(struct pt_regs *regs) +#ifdef CONFIG_X86_32 +# define IS_IA32 1 +#elif defined CONFIG_IA32_EMULATION +# define IS_IA32 test_thread_flag(TIF_IA32) +#else +# define IS_IA32 0 +#endif + +/* + * We must return the syscall number to actually look up in the table. + * This can be -1L to skip running any syscall at all. + */ +asmregparm long syscall_trace_enter(struct pt_regs *regs) { + long ret = 0; + + /* + * If we stepped into a sysenter/syscall insn, it trapped in + * kernel mode; do_debug() cleared TF and set TIF_SINGLESTEP. + * If user-mode had set TF itself, then it's still clear from + * do_debug() and we need to set it again to restore the user + * state. If we entered on the slow path, TF was already set. + */ + if (test_thread_flag(TIF_SINGLESTEP)) + regs->flags |= X86_EFLAGS_TF; + /* do the secure computing check first */ secure_computing(regs->orig_ax); - if (test_thread_flag(TIF_SYSCALL_TRACE) - && (current->ptrace & PT_PTRACED)) + if (unlikely(test_thread_flag(TIF_SYSCALL_EMU))) + ret = -1L; + + if (ret || test_thread_flag(TIF_SYSCALL_TRACE)) syscall_trace(regs); if (unlikely(current->audit_context)) { - if (test_thread_flag(TIF_IA32)) { + if (IS_IA32) audit_syscall_entry(AUDIT_ARCH_I386, regs->orig_ax, regs->bx, regs->cx, regs->dx, regs->si); - } else { +#ifdef CONFIG_X86_64 + else audit_syscall_entry(AUDIT_ARCH_X86_64, regs->orig_ax, regs->di, regs->si, regs->dx, regs->r10); - } +#endif } + + return ret ?: regs->orig_ax; } -asmlinkage void syscall_trace_leave(struct pt_regs *regs) +asmregparm void syscall_trace_leave(struct pt_regs *regs) { if (unlikely(current->audit_context)) audit_syscall_exit(AUDITSC_RESULT(regs->ax), regs->ax); - if ((test_thread_flag(TIF_SYSCALL_TRACE) - || test_thread_flag(TIF_SINGLESTEP)) - && (current->ptrace & PT_PTRACED)) + if (test_thread_flag(TIF_SYSCALL_TRACE)) syscall_trace(regs); -} -#endif /* CONFIG_X86_32 */ + /* + * If TIF_SYSCALL_EMU is set, we only get here because of + * TIF_SINGLESTEP (i.e. this is PTRACE_SYSEMU_SINGLESTEP). + * We already reported this syscall instruction in + * syscall_trace_enter(), so don't do any more now. + */ + if (unlikely(test_thread_flag(TIF_SYSCALL_EMU))) + return; + + /* + * If we are single-stepping, synthesize a trap to follow the + * system call instruction. + */ + if (test_thread_flag(TIF_SINGLESTEP) && + (current->ptrace & PT_PTRACED)) + send_sigtrap(current, regs, 0); +} diff --git a/arch/x86/kernel/reboot.c b/arch/x86/kernel/reboot.c index f8a62160e151..9dcf39c02972 100644 --- a/arch/x86/kernel/reboot.c +++ b/arch/x86/kernel/reboot.c @@ -177,6 +177,14 @@ static struct dmi_system_id __initdata reboot_dmi_table[] = { DMI_MATCH(DMI_PRODUCT_NAME, "PowerEdge 2400"), }, }, + { /* Handle problems with rebooting on Dell T5400's */ + .callback = set_bios_reboot, + .ident = "Dell Precision T5400", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), + DMI_MATCH(DMI_PRODUCT_NAME, "Precision WorkStation T5400"), + }, + }, { /* Handle problems with rebooting on HP laptops */ .callback = set_bios_reboot, .ident = "HP Compaq Laptop", diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c index 531b55b8e81a..ec952aa5394a 100644 --- a/arch/x86/kernel/setup.c +++ b/arch/x86/kernel/setup.c @@ -57,12 +57,8 @@ #include <linux/slab.h> #include <linux/user.h> #include <linux/delay.h> -#include <linux/highmem.h> #include <linux/kallsyms.h> -#include <linux/edd.h> -#include <linux/iscsi_ibft.h> -#include <linux/kexec.h> #include <linux/cpufreq.h> #include <linux/dma-mapping.h> #include <linux/ctype.h> @@ -96,7 +92,7 @@ #include <asm/smp.h> #include <asm/desc.h> #include <asm/dma.h> -#include <asm/gart.h> +#include <asm/iommu.h> #include <asm/mmu_context.h> #include <asm/proto.h> @@ -104,7 +100,6 @@ #include <asm/paravirt.h> #include <asm/percpu.h> -#include <asm/sections.h> #include <asm/topology.h> #include <asm/apicdef.h> #ifdef CONFIG_X86_64 @@ -579,6 +574,10 @@ static int __init setup_elfcorehdr(char *arg) early_param("elfcorehdr", setup_elfcorehdr); #endif +static struct x86_quirks default_x86_quirks __initdata; + +struct x86_quirks *x86_quirks __initdata = &default_x86_quirks; + /* * Determine if we were loaded by an EFI loader. If so, then we have also been * passed the efi memmap, systab, etc., so we should use these data structures @@ -824,7 +823,10 @@ void __init setup_arch(char **cmdline_p) vmi_init(); #endif + paravirt_pagetable_setup_start(swapper_pg_dir); paging_init(); + paravirt_pagetable_setup_done(swapper_pg_dir); + paravirt_post_allocator_init(); #ifdef CONFIG_X86_64 map_vsyscall(); @@ -854,14 +856,6 @@ void __init setup_arch(char **cmdline_p) init_cpu_to_node(); #endif -#ifdef CONFIG_X86_NUMAQ - /* - * need to check online nodes num, call it - * here before time_init/tsc_init - */ - numaq_tsc_disable(); -#endif - init_apic_mappings(); ioapic_init_mappings(); diff --git a/arch/x86/kernel/signal_32.c b/arch/x86/kernel/signal_32.c index d92373630963..07faaa5109cb 100644 --- a/arch/x86/kernel/signal_32.c +++ b/arch/x86/kernel/signal_32.c @@ -212,7 +212,7 @@ asmlinkage unsigned long sys_sigreturn(unsigned long __unused) badframe: if (show_unhandled_signals && printk_ratelimit()) { - printk(KERN_INFO "%s%s[%d] bad frame in sigreturn frame:" + printk("%s%s[%d] bad frame in sigreturn frame:" "%p ip:%lx sp:%lx oeax:%lx", task_pid_nr(current) > 1 ? KERN_INFO : KERN_EMERG, current->comm, task_pid_nr(current), frame, regs->ip, @@ -657,12 +657,6 @@ static void do_signal(struct pt_regs *regs) void do_notify_resume(struct pt_regs *regs, void *unused, __u32 thread_info_flags) { - /* Pending single-step? */ - if (thread_info_flags & _TIF_SINGLESTEP) { - regs->flags |= X86_EFLAGS_TF; - clear_thread_flag(TIF_SINGLESTEP); - } - /* deal with pending signal delivery */ if (thread_info_flags & _TIF_SIGPENDING) do_signal(regs); diff --git a/arch/x86/kernel/signal_64.c b/arch/x86/kernel/signal_64.c index e53b267662e7..bf87684474f1 100644 --- a/arch/x86/kernel/signal_64.c +++ b/arch/x86/kernel/signal_64.c @@ -487,12 +487,6 @@ static void do_signal(struct pt_regs *regs) void do_notify_resume(struct pt_regs *regs, void *unused, __u32 thread_info_flags) { - /* Pending single-step? */ - if (thread_info_flags & _TIF_SINGLESTEP) { - regs->flags |= X86_EFLAGS_TF; - clear_thread_flag(TIF_SINGLESTEP); - } - #ifdef CONFIG_X86_MCE /* notify userspace of pending MCEs */ if (thread_info_flags & _TIF_MCE_NOTIFY) diff --git a/arch/x86/kernel/smpboot.c b/arch/x86/kernel/smpboot.c index f251f5c38823..27640196eb7c 100644 --- a/arch/x86/kernel/smpboot.c +++ b/arch/x86/kernel/smpboot.c @@ -757,7 +757,7 @@ static void __cpuinit do_fork_idle(struct work_struct *work) * * Must be called after the _cpu_pda pointer table is initialized. */ -static int __cpuinit get_local_pda(int cpu) +int __cpuinit get_local_pda(int cpu) { struct x8664_pda *oldpda, *newpda; unsigned long size = sizeof(struct x8664_pda); @@ -1300,7 +1300,7 @@ static void __ref remove_cpu_from_maps(int cpu) cpu_clear(cpu, cpu_callout_map); cpu_clear(cpu, cpu_callin_map); /* was set by cpu_init() */ - clear_bit(cpu, (unsigned long *)&cpu_initialized); + cpu_clear(cpu, cpu_initialized); numa_remove_cpu(cpu); } @@ -1379,7 +1379,8 @@ static int __init parse_maxcpus(char *arg) { extern unsigned int maxcpus; - maxcpus = simple_strtoul(arg, NULL, 0); + if (arg) + maxcpus = simple_strtoul(arg, NULL, 0); return 0; } early_param("maxcpus", parse_maxcpus); diff --git a/arch/x86/kernel/smpcommon_32.c b/arch/x86/kernel/smpcommon_32.c deleted file mode 100644 index 8b137891791f..000000000000 --- a/arch/x86/kernel/smpcommon_32.c +++ /dev/null @@ -1 +0,0 @@ - diff --git a/arch/x86/kernel/step.c b/arch/x86/kernel/step.c index 92c20fee6781..e8b9863ef8c4 100644 --- a/arch/x86/kernel/step.c +++ b/arch/x86/kernel/step.c @@ -105,6 +105,20 @@ static int is_setting_trap_flag(struct task_struct *child, struct pt_regs *regs) static int enable_single_step(struct task_struct *child) { struct pt_regs *regs = task_pt_regs(child); + unsigned long oflags; + + /* + * If we stepped into a sysenter/syscall insn, it trapped in + * kernel mode; do_debug() cleared TF and set TIF_SINGLESTEP. + * If user-mode had set TF itself, then it's still clear from + * do_debug() and we need to set it again to restore the user + * state so we don't wrongly set TIF_FORCED_TF below. + * If enable_single_step() was used last and that is what + * set TIF_SINGLESTEP, then both TF and TIF_FORCED_TF are + * already set and our bookkeeping is fine. + */ + if (unlikely(test_tsk_thread_flag(child, TIF_SINGLESTEP))) + regs->flags |= X86_EFLAGS_TF; /* * Always set TIF_SINGLESTEP - this guarantees that @@ -113,11 +127,7 @@ static int enable_single_step(struct task_struct *child) */ set_tsk_thread_flag(child, TIF_SINGLESTEP); - /* - * If TF was already set, don't do anything else - */ - if (regs->flags & X86_EFLAGS_TF) - return 0; + oflags = regs->flags; /* Set TF on the kernel stack.. */ regs->flags |= X86_EFLAGS_TF; @@ -126,9 +136,22 @@ static int enable_single_step(struct task_struct *child) * ..but if TF is changed by the instruction we will trace, * don't mark it as being "us" that set it, so that we * won't clear it by hand later. + * + * Note that if we don't actually execute the popf because + * of a signal arriving right now or suchlike, we will lose + * track of the fact that it really was "us" that set it. */ - if (is_setting_trap_flag(child, regs)) + if (is_setting_trap_flag(child, regs)) { + clear_tsk_thread_flag(child, TIF_FORCED_TF); return 0; + } + + /* + * If TF was already set, check whether it was us who set it. + * If not, we should never attempt a block step. + */ + if (oflags & X86_EFLAGS_TF) + return test_tsk_thread_flag(child, TIF_FORCED_TF); set_tsk_thread_flag(child, TIF_FORCED_TF); diff --git a/arch/x86/kernel/time_32.c b/arch/x86/kernel/time_32.c index 059ca6ee59b4..ffe3c664afc0 100644 --- a/arch/x86/kernel/time_32.c +++ b/arch/x86/kernel/time_32.c @@ -129,6 +129,7 @@ void __init hpet_time_init(void) */ void __init time_init(void) { + pre_time_init_hook(); tsc_init(); late_time_init = choose_time_init(); } diff --git a/arch/x86/kernel/traps_32.c b/arch/x86/kernel/traps_32.c index 8a768973c4f0..03df8e45e5a1 100644 --- a/arch/x86/kernel/traps_32.c +++ b/arch/x86/kernel/traps_32.c @@ -58,6 +58,7 @@ #include <asm/nmi.h> #include <asm/smp.h> #include <asm/io.h> +#include <asm/traps.h> #include "mach_traps.h" @@ -77,26 +78,6 @@ char ignore_fpu_irq; gate_desc idt_table[256] __attribute__((__section__(".data.idt"))) = { { { { 0, 0 } } }, }; -asmlinkage void divide_error(void); -asmlinkage void debug(void); -asmlinkage void nmi(void); -asmlinkage void int3(void); -asmlinkage void overflow(void); -asmlinkage void bounds(void); -asmlinkage void invalid_op(void); -asmlinkage void device_not_available(void); -asmlinkage void coprocessor_segment_overrun(void); -asmlinkage void invalid_TSS(void); -asmlinkage void segment_not_present(void); -asmlinkage void stack_segment(void); -asmlinkage void general_protection(void); -asmlinkage void page_fault(void); -asmlinkage void coprocessor_error(void); -asmlinkage void simd_coprocessor_error(void); -asmlinkage void alignment_check(void); -asmlinkage void spurious_interrupt_bug(void); -asmlinkage void machine_check(void); - int panic_on_unrecovered_nmi; int kstack_depth_to_print = 24; static unsigned int code_bytes = 64; @@ -256,7 +237,7 @@ static const struct stacktrace_ops print_trace_ops = { static void show_trace_log_lvl(struct task_struct *task, struct pt_regs *regs, - unsigned long *stack, unsigned long bp, char *log_lvl) + unsigned long *stack, unsigned long bp, char *log_lvl) { dump_trace(task, regs, stack, bp, &print_trace_ops, log_lvl); printk("%s =======================\n", log_lvl); @@ -383,6 +364,54 @@ int is_valid_bugaddr(unsigned long ip) return ud2 == 0x0b0f; } +static raw_spinlock_t die_lock = __RAW_SPIN_LOCK_UNLOCKED; +static int die_owner = -1; +static unsigned int die_nest_count; + +unsigned __kprobes long oops_begin(void) +{ + unsigned long flags; + + oops_enter(); + + if (die_owner != raw_smp_processor_id()) { + console_verbose(); + raw_local_irq_save(flags); + __raw_spin_lock(&die_lock); + die_owner = smp_processor_id(); + die_nest_count = 0; + bust_spinlocks(1); + } else { + raw_local_irq_save(flags); + } + die_nest_count++; + return flags; +} + +void __kprobes oops_end(unsigned long flags, struct pt_regs *regs, int signr) +{ + bust_spinlocks(0); + die_owner = -1; + add_taint(TAINT_DIE); + __raw_spin_unlock(&die_lock); + raw_local_irq_restore(flags); + + if (!regs) + return; + + if (kexec_should_crash(current)) + crash_kexec(regs); + + if (in_interrupt()) + panic("Fatal exception in interrupt"); + + if (panic_on_oops) + panic("Fatal exception"); + + oops_exit(); + do_exit(signr); +} + int __kprobes __die(const char *str, struct pt_regs *regs, long err) { unsigned short ss; @@ -423,31 +452,9 @@ int __kprobes __die(const char *str, struct pt_regs *regs, long err) */ void die(const char *str, struct pt_regs *regs, long err) { - static struct { - raw_spinlock_t lock; - u32 lock_owner; - int lock_owner_depth; - } die = { - .lock = __RAW_SPIN_LOCK_UNLOCKED, - .lock_owner = -1, - .lock_owner_depth = 0 - }; - unsigned long flags; - - oops_enter(); - - if (die.lock_owner != raw_smp_processor_id()) { - console_verbose(); - raw_local_irq_save(flags); - __raw_spin_lock(&die.lock); - die.lock_owner = smp_processor_id(); - die.lock_owner_depth = 0; - bust_spinlocks(1); - } else { - raw_local_irq_save(flags); - } + unsigned long flags = oops_begin(); - if (++die.lock_owner_depth < 3) { + if (die_nest_count < 3) { report_bug(regs->ip, regs); if (__die(str, regs, err)) @@ -456,26 +463,7 @@ void die(const char *str, struct pt_regs *regs, long err) printk(KERN_EMERG "Recursive die() failure, output suppressed\n"); } - bust_spinlocks(0); - die.lock_owner = -1; - add_taint(TAINT_DIE); - __raw_spin_unlock(&die.lock); - raw_local_irq_restore(flags); - - if (!regs) - return; - - if (kexec_should_crash(current)) - crash_kexec(regs); - - if (in_interrupt()) - panic("Fatal exception in interrupt"); - - if (panic_on_oops) - panic("Fatal exception"); - - oops_exit(); - do_exit(SIGSEGV); + oops_end(flags, regs, SIGSEGV); } static inline void diff --git a/arch/x86/kernel/traps_64.c b/arch/x86/kernel/traps_64.c index 2696a6837782..3f18d73f420c 100644 --- a/arch/x86/kernel/traps_64.c +++ b/arch/x86/kernel/traps_64.c @@ -51,30 +51,10 @@ #include <asm/pgalloc.h> #include <asm/proto.h> #include <asm/pda.h> +#include <asm/traps.h> #include <mach_traps.h> -asmlinkage void divide_error(void); -asmlinkage void debug(void); -asmlinkage void nmi(void); -asmlinkage void int3(void); -asmlinkage void overflow(void); -asmlinkage void bounds(void); -asmlinkage void invalid_op(void); -asmlinkage void device_not_available(void); -asmlinkage void double_fault(void); -asmlinkage void coprocessor_segment_overrun(void); -asmlinkage void invalid_TSS(void); -asmlinkage void segment_not_present(void); -asmlinkage void stack_segment(void); -asmlinkage void general_protection(void); -asmlinkage void page_fault(void); -asmlinkage void coprocessor_error(void); -asmlinkage void simd_coprocessor_error(void); -asmlinkage void alignment_check(void); -asmlinkage void spurious_interrupt_bug(void); -asmlinkage void machine_check(void); - int panic_on_unrecovered_nmi; int kstack_depth_to_print = 12; static unsigned int code_bytes = 64; @@ -355,17 +335,24 @@ static const struct stacktrace_ops print_trace_ops = { .address = print_trace_address, }; -void show_trace(struct task_struct *task, struct pt_regs *regs, - unsigned long *stack, unsigned long bp) +static void +show_trace_log_lvl(struct task_struct *task, struct pt_regs *regs, + unsigned long *stack, unsigned long bp, char *log_lvl) { printk("\nCall Trace:\n"); - dump_trace(task, regs, stack, bp, &print_trace_ops, NULL); + dump_trace(task, regs, stack, bp, &print_trace_ops, log_lvl); printk("\n"); } +void show_trace(struct task_struct *task, struct pt_regs *regs, + unsigned long *stack, unsigned long bp) +{ + show_trace_log_lvl(task, regs, stack, bp, ""); +} + static void -_show_stack(struct task_struct *task, struct pt_regs *regs, - unsigned long *sp, unsigned long bp) +show_stack_log_lvl(struct task_struct *task, struct pt_regs *regs, + unsigned long *sp, unsigned long bp, char *log_lvl) { unsigned long *stack; int i; @@ -399,12 +386,12 @@ _show_stack(struct task_struct *task, struct pt_regs *regs, printk(" %016lx", *stack++); touch_nmi_watchdog(); } - show_trace(task, regs, sp, bp); + show_trace_log_lvl(task, regs, sp, bp, log_lvl); } void show_stack(struct task_struct *task, unsigned long *sp) { - _show_stack(task, NULL, sp, 0); + show_stack_log_lvl(task, NULL, sp, 0, ""); } /* @@ -454,7 +441,8 @@ void show_registers(struct pt_regs *regs) u8 *ip; printk("Stack: "); - _show_stack(NULL, regs, (unsigned long *)sp, regs->bp); + show_stack_log_lvl(NULL, regs, (unsigned long *)sp, + regs->bp, ""); printk("\n"); printk(KERN_EMERG "Code: "); @@ -518,7 +506,7 @@ unsigned __kprobes long oops_begin(void) } void __kprobes oops_end(unsigned long flags, struct pt_regs *regs, int signr) -{ +{ die_owner = -1; bust_spinlocks(0); die_nest_count--; diff --git a/arch/x86/kernel/visws_quirks.c b/arch/x86/kernel/visws_quirks.c index e94bdb6add1d..41e01b145c48 100644 --- a/arch/x86/kernel/visws_quirks.c +++ b/arch/x86/kernel/visws_quirks.c @@ -73,7 +73,7 @@ int is_visws_box(void) return visws_board_type >= 0; } -static int __init visws_time_init_quirk(void) +static int __init visws_time_init(void) { printk(KERN_INFO "Starting Cobalt Timer system clock\n"); @@ -93,7 +93,7 @@ static int __init visws_time_init_quirk(void) return 0; } -static int __init visws_pre_intr_init_quirk(void) +static int __init visws_pre_intr_init(void) { init_VISWS_APIC_irqs(); @@ -114,7 +114,7 @@ EXPORT_SYMBOL(sgivwfb_mem_size); long long mem_size __initdata = 0; -static char * __init visws_memory_setup_quirk(void) +static char * __init visws_memory_setup(void) { long long gfx_mem_size = 8 * MB; @@ -176,7 +176,7 @@ static void visws_machine_power_off(void) outl(PIIX_SPECIAL_STOP, 0xCFC); } -static int __init visws_get_smp_config_quirk(unsigned int early) +static int __init visws_get_smp_config(unsigned int early) { /* * Prevent MP-table parsing by the generic code: @@ -192,7 +192,7 @@ extern unsigned int __cpuinitdata maxcpus; * No problem for Linux. */ -static void __init MP_processor_info (struct mpc_config_processor *m) +static void __init MP_processor_info(struct mpc_config_processor *m) { int ver, logical_apicid; physid_mask_t apic_cpus; @@ -232,7 +232,7 @@ static void __init MP_processor_info (struct mpc_config_processor *m) apic_version[m->mpc_apicid] = ver; } -int __init visws_find_smp_config_quirk(unsigned int reserve) +static int __init visws_find_smp_config(unsigned int reserve) { struct mpc_config_processor *mp = phys_to_virt(CO_CPU_TAB_PHYS); unsigned short ncpus = readw(phys_to_virt(CO_CPU_NUM_PHYS)); @@ -258,7 +258,17 @@ int __init visws_find_smp_config_quirk(unsigned int reserve) return 1; } -extern int visws_trap_init_quirk(void); +static int visws_trap_init(void); + +static struct x86_quirks visws_x86_quirks __initdata = { + .arch_time_init = visws_time_init, + .arch_pre_intr_init = visws_pre_intr_init, + .arch_memory_setup = visws_memory_setup, + .arch_intr_init = NULL, + .arch_trap_init = visws_trap_init, + .mach_get_smp_config = visws_get_smp_config, + .mach_find_smp_config = visws_find_smp_config, +}; void __init visws_early_detect(void) { @@ -272,16 +282,10 @@ void __init visws_early_detect(void) /* * Install special quirks for timer, interrupt and memory setup: - */ - arch_time_init_quirk = visws_time_init_quirk; - arch_pre_intr_init_quirk = visws_pre_intr_init_quirk; - arch_memory_setup_quirk = visws_memory_setup_quirk; - - /* * Fall back to generic behavior for traps: + * Override generic MP-table parsing: */ - arch_intr_init_quirk = NULL; - arch_trap_init_quirk = visws_trap_init_quirk; + x86_quirks = &visws_x86_quirks; /* * Install reboot quirks: @@ -294,12 +298,6 @@ void __init visws_early_detect(void) */ no_broadcast = 0; - /* - * Override generic MP-table parsing: - */ - mach_get_smp_config_quirk = visws_get_smp_config_quirk; - mach_find_smp_config_quirk = visws_find_smp_config_quirk; - #ifdef CONFIG_X86_IO_APIC /* * Turn off IO-APIC detection and initialization: @@ -426,7 +424,7 @@ static __init void cobalt_init(void) co_apic_read(CO_APIC_ID)); } -int __init visws_trap_init_quirk(void) +static int __init visws_trap_init(void) { lithium_init(); cobalt_init(); diff --git a/arch/x86/kvm/Makefile b/arch/x86/kvm/Makefile index c97d35c218db..d0e940bb6f40 100644 --- a/arch/x86/kvm/Makefile +++ b/arch/x86/kvm/Makefile @@ -2,7 +2,8 @@ # Makefile for Kernel-based Virtual Machine module # -common-objs = $(addprefix ../../../virt/kvm/, kvm_main.o ioapic.o) +common-objs = $(addprefix ../../../virt/kvm/, kvm_main.o ioapic.o \ + coalesced_mmio.o) ifeq ($(CONFIG_KVM_TRACE),y) common-objs += $(addprefix ../../../virt/kvm/, kvm_trace.o) endif diff --git a/arch/x86/kvm/i8254.c b/arch/x86/kvm/i8254.c index 3829aa7b663f..c0f7872a9124 100644 --- a/arch/x86/kvm/i8254.c +++ b/arch/x86/kvm/i8254.c @@ -91,7 +91,7 @@ static void pit_set_gate(struct kvm *kvm, int channel, u32 val) c->gate = val; } -int pit_get_gate(struct kvm *kvm, int channel) +static int pit_get_gate(struct kvm *kvm, int channel) { WARN_ON(!mutex_is_locked(&kvm->arch.vpit->pit_state.lock)); @@ -193,19 +193,16 @@ static void pit_latch_status(struct kvm *kvm, int channel) } } -int __pit_timer_fn(struct kvm_kpit_state *ps) +static int __pit_timer_fn(struct kvm_kpit_state *ps) { struct kvm_vcpu *vcpu0 = ps->pit->kvm->vcpus[0]; struct kvm_kpit_timer *pt = &ps->pit_timer; - atomic_inc(&pt->pending); - smp_mb__after_atomic_inc(); - if (vcpu0) { + if (!atomic_inc_and_test(&pt->pending)) set_bit(KVM_REQ_PENDING_TIMER, &vcpu0->requests); - if (waitqueue_active(&vcpu0->wq)) { - vcpu0->arch.mp_state = KVM_MP_STATE_RUNNABLE; - wake_up_interruptible(&vcpu0->wq); - } + if (vcpu0 && waitqueue_active(&vcpu0->wq)) { + vcpu0->arch.mp_state = KVM_MP_STATE_RUNNABLE; + wake_up_interruptible(&vcpu0->wq); } pt->timer.expires = ktime_add_ns(pt->timer.expires, pt->period); @@ -308,6 +305,7 @@ static void pit_load_count(struct kvm *kvm, int channel, u32 val) create_pit_timer(&ps->pit_timer, val, 0); break; case 2: + case 3: create_pit_timer(&ps->pit_timer, val, 1); break; default: @@ -459,7 +457,8 @@ static void pit_ioport_read(struct kvm_io_device *this, mutex_unlock(&pit_state->lock); } -static int pit_in_range(struct kvm_io_device *this, gpa_t addr) +static int pit_in_range(struct kvm_io_device *this, gpa_t addr, + int len, int is_write) { return ((addr >= KVM_PIT_BASE_ADDRESS) && (addr < KVM_PIT_BASE_ADDRESS + KVM_PIT_MEM_LENGTH)); @@ -500,7 +499,8 @@ static void speaker_ioport_read(struct kvm_io_device *this, mutex_unlock(&pit_state->lock); } -static int speaker_in_range(struct kvm_io_device *this, gpa_t addr) +static int speaker_in_range(struct kvm_io_device *this, gpa_t addr, + int len, int is_write) { return (addr == KVM_SPEAKER_BASE_ADDRESS); } @@ -575,7 +575,7 @@ void kvm_free_pit(struct kvm *kvm) } } -void __inject_pit_timer_intr(struct kvm *kvm) +static void __inject_pit_timer_intr(struct kvm *kvm) { mutex_lock(&kvm->lock); kvm_ioapic_set_irq(kvm->arch.vioapic, 0, 1); diff --git a/arch/x86/kvm/i8259.c b/arch/x86/kvm/i8259.c index ab29cf2def47..c31164e8aa46 100644 --- a/arch/x86/kvm/i8259.c +++ b/arch/x86/kvm/i8259.c @@ -130,8 +130,10 @@ void kvm_pic_set_irq(void *opaque, int irq, int level) { struct kvm_pic *s = opaque; - pic_set_irq1(&s->pics[irq >> 3], irq & 7, level); - pic_update_irq(s); + if (irq >= 0 && irq < PIC_NUM_PINS) { + pic_set_irq1(&s->pics[irq >> 3], irq & 7, level); + pic_update_irq(s); + } } /* @@ -346,7 +348,8 @@ static u32 elcr_ioport_read(void *opaque, u32 addr1) return s->elcr; } -static int picdev_in_range(struct kvm_io_device *this, gpa_t addr) +static int picdev_in_range(struct kvm_io_device *this, gpa_t addr, + int len, int is_write) { switch (addr) { case 0x20: diff --git a/arch/x86/kvm/irq.h b/arch/x86/kvm/irq.h index 2a15be2275c0..7ca47cbb48bb 100644 --- a/arch/x86/kvm/irq.h +++ b/arch/x86/kvm/irq.h @@ -30,6 +30,8 @@ #include "ioapic.h" #include "lapic.h" +#define PIC_NUM_PINS 16 + struct kvm; struct kvm_vcpu; diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c index ebc03f5ae162..73f43de69f67 100644 --- a/arch/x86/kvm/lapic.c +++ b/arch/x86/kvm/lapic.c @@ -356,8 +356,9 @@ static int __apic_accept_irq(struct kvm_lapic *apic, int delivery_mode, case APIC_DM_SMI: printk(KERN_DEBUG "Ignoring guest SMI\n"); break; + case APIC_DM_NMI: - printk(KERN_DEBUG "Ignoring guest NMI\n"); + kvm_inject_nmi(vcpu); break; case APIC_DM_INIT: @@ -572,6 +573,8 @@ static u32 __apic_read(struct kvm_lapic *apic, unsigned int offset) { u32 val = 0; + KVMTRACE_1D(APIC_ACCESS, apic->vcpu, (u32)offset, handler); + if (offset >= LAPIC_MMIO_LENGTH) return 0; @@ -695,6 +698,8 @@ static void apic_mmio_write(struct kvm_io_device *this, offset &= 0xff0; + KVMTRACE_1D(APIC_ACCESS, apic->vcpu, (u32)offset, handler); + switch (offset) { case APIC_ID: /* Local APIC ID */ apic_set_reg(apic, APIC_ID, val); @@ -780,7 +785,8 @@ static void apic_mmio_write(struct kvm_io_device *this, } -static int apic_mmio_range(struct kvm_io_device *this, gpa_t addr) +static int apic_mmio_range(struct kvm_io_device *this, gpa_t addr, + int len, int size) { struct kvm_lapic *apic = (struct kvm_lapic *)this->private; int ret = 0; @@ -939,8 +945,8 @@ static int __apic_timer_fn(struct kvm_lapic *apic) int result = 0; wait_queue_head_t *q = &apic->vcpu->wq; - atomic_inc(&apic->timer.pending); - set_bit(KVM_REQ_PENDING_TIMER, &apic->vcpu->requests); + if(!atomic_inc_and_test(&apic->timer.pending)) + set_bit(KVM_REQ_PENDING_TIMER, &apic->vcpu->requests); if (waitqueue_active(q)) { apic->vcpu->arch.mp_state = KVM_MP_STATE_RUNNABLE; wake_up_interruptible(q); diff --git a/arch/x86/kvm/lapic.h b/arch/x86/kvm/lapic.h index 676c396c9cee..81858881287e 100644 --- a/arch/x86/kvm/lapic.h +++ b/arch/x86/kvm/lapic.h @@ -31,6 +31,7 @@ void kvm_lapic_reset(struct kvm_vcpu *vcpu); u64 kvm_lapic_get_cr8(struct kvm_vcpu *vcpu); void kvm_lapic_set_tpr(struct kvm_vcpu *vcpu, unsigned long cr8); void kvm_lapic_set_base(struct kvm_vcpu *vcpu, u64 value); +u64 kvm_lapic_get_base(struct kvm_vcpu *vcpu); int kvm_apic_match_physical_addr(struct kvm_lapic *apic, u16 dest); int kvm_apic_match_logical_addr(struct kvm_lapic *apic, u8 mda); diff --git a/arch/x86/kvm/mmu.c b/arch/x86/kvm/mmu.c index 7e7c3969f7a2..b0e4ddca6c18 100644 --- a/arch/x86/kvm/mmu.c +++ b/arch/x86/kvm/mmu.c @@ -66,7 +66,8 @@ static void kvm_mmu_audit(struct kvm_vcpu *vcpu, const char *msg) {} #endif #if defined(MMU_DEBUG) || defined(AUDIT) -static int dbg = 1; +static int dbg = 0; +module_param(dbg, bool, 0644); #endif #ifndef MMU_DEBUG @@ -776,6 +777,15 @@ static void mmu_page_remove_parent_pte(struct kvm_mmu_page *sp, BUG(); } +static void nonpaging_prefetch_page(struct kvm_vcpu *vcpu, + struct kvm_mmu_page *sp) +{ + int i; + + for (i = 0; i < PT64_ENT_PER_PAGE; ++i) + sp->spt[i] = shadow_trap_nonpresent_pte; +} + static struct kvm_mmu_page *kvm_mmu_lookup_page(struct kvm *kvm, gfn_t gfn) { unsigned index; @@ -841,7 +851,10 @@ static struct kvm_mmu_page *kvm_mmu_get_page(struct kvm_vcpu *vcpu, hlist_add_head(&sp->hash_link, bucket); if (!metaphysical) rmap_write_protect(vcpu->kvm, gfn); - vcpu->arch.mmu.prefetch_page(vcpu, sp); + if (shadow_trap_nonpresent_pte != shadow_notrap_nonpresent_pte) + vcpu->arch.mmu.prefetch_page(vcpu, sp); + else + nonpaging_prefetch_page(vcpu, sp); return sp; } @@ -917,14 +930,17 @@ static void kvm_mmu_zap_page(struct kvm *kvm, struct kvm_mmu_page *sp) } kvm_mmu_page_unlink_children(kvm, sp); if (!sp->root_count) { - if (!sp->role.metaphysical) + if (!sp->role.metaphysical && !sp->role.invalid) unaccount_shadowed(kvm, sp->gfn); hlist_del(&sp->hash_link); kvm_mmu_free_page(kvm, sp); } else { + int invalid = sp->role.invalid; list_move(&sp->link, &kvm->arch.active_mmu_pages); sp->role.invalid = 1; kvm_reload_remote_mmus(kvm); + if (!sp->role.metaphysical && !invalid) + unaccount_shadowed(kvm, sp->gfn); } kvm_mmu_reset_last_pte_updated(kvm); } @@ -1103,7 +1119,7 @@ static void mmu_set_spte(struct kvm_vcpu *vcpu, u64 *shadow_pte, mark_page_dirty(vcpu->kvm, gfn); pgprintk("%s: setting spte %llx\n", __func__, spte); - pgprintk("instantiating %s PTE (%s) at %d (%llx) addr %llx\n", + pgprintk("instantiating %s PTE (%s) at %ld (%llx) addr %p\n", (spte&PT_PAGE_SIZE_MASK)? "2MB" : "4kB", (spte&PT_WRITABLE_MASK)?"RW":"R", gfn, spte, shadow_pte); set_shadow_pte(shadow_pte, spte); @@ -1122,8 +1138,10 @@ static void mmu_set_spte(struct kvm_vcpu *vcpu, u64 *shadow_pte, else kvm_release_pfn_clean(pfn); } - if (!ptwrite || !*ptwrite) + if (speculative) { vcpu->arch.last_pte_updated = shadow_pte; + vcpu->arch.last_pte_gfn = gfn; + } } static void nonpaging_new_cr3(struct kvm_vcpu *vcpu) @@ -1171,9 +1189,10 @@ static int __direct_map(struct kvm_vcpu *vcpu, gpa_t v, int write, return -ENOMEM; } - table[index] = __pa(new_table->spt) - | PT_PRESENT_MASK | PT_WRITABLE_MASK - | shadow_user_mask | shadow_x_mask; + set_shadow_pte(&table[index], + __pa(new_table->spt) + | PT_PRESENT_MASK | PT_WRITABLE_MASK + | shadow_user_mask | shadow_x_mask); } table_addr = table[index] & PT64_BASE_ADDR_MASK; } @@ -1211,15 +1230,6 @@ static int nonpaging_map(struct kvm_vcpu *vcpu, gva_t v, int write, gfn_t gfn) } -static void nonpaging_prefetch_page(struct kvm_vcpu *vcpu, - struct kvm_mmu_page *sp) -{ - int i; - - for (i = 0; i < PT64_ENT_PER_PAGE; ++i) - sp->spt[i] = shadow_trap_nonpresent_pte; -} - static void mmu_free_roots(struct kvm_vcpu *vcpu) { int i; @@ -1671,6 +1681,18 @@ static void mmu_guess_page_from_pte_write(struct kvm_vcpu *vcpu, gpa_t gpa, vcpu->arch.update_pte.pfn = pfn; } +static void kvm_mmu_access_page(struct kvm_vcpu *vcpu, gfn_t gfn) +{ + u64 *spte = vcpu->arch.last_pte_updated; + + if (spte + && vcpu->arch.last_pte_gfn == gfn + && shadow_accessed_mask + && !(*spte & shadow_accessed_mask) + && is_shadow_present_pte(*spte)) + set_bit(PT_ACCESSED_SHIFT, (unsigned long *)spte); +} + void kvm_mmu_pte_write(struct kvm_vcpu *vcpu, gpa_t gpa, const u8 *new, int bytes) { @@ -1694,6 +1716,7 @@ void kvm_mmu_pte_write(struct kvm_vcpu *vcpu, gpa_t gpa, pgprintk("%s: gpa %llx bytes %d\n", __func__, gpa, bytes); mmu_guess_page_from_pte_write(vcpu, gpa, new, bytes); spin_lock(&vcpu->kvm->mmu_lock); + kvm_mmu_access_page(vcpu, gfn); kvm_mmu_free_some_pages(vcpu); ++vcpu->kvm->stat.mmu_pte_write; kvm_mmu_audit(vcpu, "pre pte write"); @@ -1948,7 +1971,7 @@ void kvm_mmu_zap_all(struct kvm *kvm) kvm_flush_remote_tlbs(kvm); } -void kvm_mmu_remove_one_alloc_mmu_page(struct kvm *kvm) +static void kvm_mmu_remove_one_alloc_mmu_page(struct kvm *kvm) { struct kvm_mmu_page *page; @@ -1968,6 +1991,8 @@ static int mmu_shrink(int nr_to_scan, gfp_t gfp_mask) list_for_each_entry(kvm, &vm_list, vm_list) { int npages; + if (!down_read_trylock(&kvm->slots_lock)) + continue; spin_lock(&kvm->mmu_lock); npages = kvm->arch.n_alloc_mmu_pages - kvm->arch.n_free_mmu_pages; @@ -1980,6 +2005,7 @@ static int mmu_shrink(int nr_to_scan, gfp_t gfp_mask) nr_to_scan--; spin_unlock(&kvm->mmu_lock); + up_read(&kvm->slots_lock); } if (kvm_freed) list_move_tail(&kvm_freed->vm_list, &vm_list); diff --git a/arch/x86/kvm/mmu.h b/arch/x86/kvm/mmu.h index 1730757bbc7a..258e5d56298e 100644 --- a/arch/x86/kvm/mmu.h +++ b/arch/x86/kvm/mmu.h @@ -15,7 +15,8 @@ #define PT_USER_MASK (1ULL << 2) #define PT_PWT_MASK (1ULL << 3) #define PT_PCD_MASK (1ULL << 4) -#define PT_ACCESSED_MASK (1ULL << 5) +#define PT_ACCESSED_SHIFT 5 +#define PT_ACCESSED_MASK (1ULL << PT_ACCESSED_SHIFT) #define PT_DIRTY_MASK (1ULL << 6) #define PT_PAGE_SIZE_MASK (1ULL << 7) #define PT_PAT_MASK (1ULL << 7) diff --git a/arch/x86/kvm/paging_tmpl.h b/arch/x86/kvm/paging_tmpl.h index 934c7b619396..4d918220baeb 100644 --- a/arch/x86/kvm/paging_tmpl.h +++ b/arch/x86/kvm/paging_tmpl.h @@ -460,8 +460,9 @@ static gpa_t FNAME(gva_to_gpa)(struct kvm_vcpu *vcpu, gva_t vaddr) static void FNAME(prefetch_page)(struct kvm_vcpu *vcpu, struct kvm_mmu_page *sp) { - int i, offset = 0, r = 0; - pt_element_t pt; + int i, j, offset, r; + pt_element_t pt[256 / sizeof(pt_element_t)]; + gpa_t pte_gpa; if (sp->role.metaphysical || (PTTYPE == 32 && sp->role.level > PT_PAGE_TABLE_LEVEL)) { @@ -469,19 +470,20 @@ static void FNAME(prefetch_page)(struct kvm_vcpu *vcpu, return; } - if (PTTYPE == 32) + pte_gpa = gfn_to_gpa(sp->gfn); + if (PTTYPE == 32) { offset = sp->role.quadrant << PT64_LEVEL_BITS; + pte_gpa += offset * sizeof(pt_element_t); + } - for (i = 0; i < PT64_ENT_PER_PAGE; ++i) { - gpa_t pte_gpa = gfn_to_gpa(sp->gfn); - pte_gpa += (i+offset) * sizeof(pt_element_t); - - r = kvm_read_guest_atomic(vcpu->kvm, pte_gpa, &pt, - sizeof(pt_element_t)); - if (r || is_present_pte(pt)) - sp->spt[i] = shadow_trap_nonpresent_pte; - else - sp->spt[i] = shadow_notrap_nonpresent_pte; + for (i = 0; i < PT64_ENT_PER_PAGE; i += ARRAY_SIZE(pt)) { + r = kvm_read_guest_atomic(vcpu->kvm, pte_gpa, pt, sizeof pt); + pte_gpa += ARRAY_SIZE(pt) * sizeof(pt_element_t); + for (j = 0; j < ARRAY_SIZE(pt); ++j) + if (r || is_present_pte(pt[j])) + sp->spt[i+j] = shadow_trap_nonpresent_pte; + else + sp->spt[i+j] = shadow_notrap_nonpresent_pte; } } diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c index 6b0d5fa5bab3..b756e876dce3 100644 --- a/arch/x86/kvm/svm.c +++ b/arch/x86/kvm/svm.c @@ -27,6 +27,8 @@ #include <asm/desc.h> +#define __ex(x) __kvm_handle_fault_on_reboot(x) + MODULE_AUTHOR("Qumranet"); MODULE_LICENSE("GPL"); @@ -129,17 +131,17 @@ static inline void push_irq(struct kvm_vcpu *vcpu, u8 irq) static inline void clgi(void) { - asm volatile (SVM_CLGI); + asm volatile (__ex(SVM_CLGI)); } static inline void stgi(void) { - asm volatile (SVM_STGI); + asm volatile (__ex(SVM_STGI)); } static inline void invlpga(unsigned long addr, u32 asid) { - asm volatile (SVM_INVLPGA :: "a"(addr), "c"(asid)); + asm volatile (__ex(SVM_INVLPGA) :: "a"(addr), "c"(asid)); } static inline unsigned long kvm_read_cr2(void) @@ -270,19 +272,11 @@ static int has_svm(void) static void svm_hardware_disable(void *garbage) { - struct svm_cpu_data *svm_data - = per_cpu(svm_data, raw_smp_processor_id()); - - if (svm_data) { - uint64_t efer; + uint64_t efer; - wrmsrl(MSR_VM_HSAVE_PA, 0); - rdmsrl(MSR_EFER, efer); - wrmsrl(MSR_EFER, efer & ~MSR_EFER_SVME_MASK); - per_cpu(svm_data, raw_smp_processor_id()) = NULL; - __free_page(svm_data->save_area); - kfree(svm_data); - } + wrmsrl(MSR_VM_HSAVE_PA, 0); + rdmsrl(MSR_EFER, efer); + wrmsrl(MSR_EFER, efer & ~MSR_EFER_SVME_MASK); } static void svm_hardware_enable(void *garbage) @@ -321,6 +315,19 @@ static void svm_hardware_enable(void *garbage) page_to_pfn(svm_data->save_area) << PAGE_SHIFT); } +static void svm_cpu_uninit(int cpu) +{ + struct svm_cpu_data *svm_data + = per_cpu(svm_data, raw_smp_processor_id()); + + if (!svm_data) + return; + + per_cpu(svm_data, raw_smp_processor_id()) = NULL; + __free_page(svm_data->save_area); + kfree(svm_data); +} + static int svm_cpu_init(int cpu) { struct svm_cpu_data *svm_data; @@ -458,6 +465,11 @@ err: static __exit void svm_hardware_unsetup(void) { + int cpu; + + for_each_online_cpu(cpu) + svm_cpu_uninit(cpu); + __free_pages(pfn_to_page(iopm_base >> PAGE_SHIFT), IOPM_ALLOC_ORDER); iopm_base = 0; } @@ -707,10 +719,6 @@ static void svm_vcpu_put(struct kvm_vcpu *vcpu) rdtscll(vcpu->arch.host_tsc); } -static void svm_vcpu_decache(struct kvm_vcpu *vcpu) -{ -} - static void svm_cache_regs(struct kvm_vcpu *vcpu) { struct vcpu_svm *svm = to_svm(vcpu); @@ -949,7 +957,9 @@ static void new_asid(struct vcpu_svm *svm, struct svm_cpu_data *svm_data) static unsigned long svm_get_dr(struct kvm_vcpu *vcpu, int dr) { - return to_svm(vcpu)->db_regs[dr]; + unsigned long val = to_svm(vcpu)->db_regs[dr]; + KVMTRACE_2D(DR_READ, vcpu, (u32)dr, (u32)val, handler); + return val; } static void svm_set_dr(struct kvm_vcpu *vcpu, int dr, unsigned long value, @@ -1004,6 +1014,16 @@ static int pf_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run) fault_address = svm->vmcb->control.exit_info_2; error_code = svm->vmcb->control.exit_info_1; + + if (!npt_enabled) + KVMTRACE_3D(PAGE_FAULT, &svm->vcpu, error_code, + (u32)fault_address, (u32)(fault_address >> 32), + handler); + else + KVMTRACE_3D(TDP_FAULT, &svm->vcpu, error_code, + (u32)fault_address, (u32)(fault_address >> 32), + handler); + return kvm_mmu_page_fault(&svm->vcpu, fault_address, error_code); } @@ -1081,6 +1101,19 @@ static int io_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run) return kvm_emulate_pio(&svm->vcpu, kvm_run, in, size, port); } +static int nmi_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run) +{ + KVMTRACE_0D(NMI, &svm->vcpu, handler); + return 1; +} + +static int intr_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run) +{ + ++svm->vcpu.stat.irq_exits; + KVMTRACE_0D(INTR, &svm->vcpu, handler); + return 1; +} + static int nop_on_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run) { return 1; @@ -1219,6 +1252,9 @@ static int rdmsr_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run) if (svm_get_msr(&svm->vcpu, ecx, &data)) kvm_inject_gp(&svm->vcpu, 0); else { + KVMTRACE_3D(MSR_READ, &svm->vcpu, ecx, (u32)data, + (u32)(data >> 32), handler); + svm->vmcb->save.rax = data & 0xffffffff; svm->vcpu.arch.regs[VCPU_REGS_RDX] = data >> 32; svm->next_rip = svm->vmcb->save.rip + 2; @@ -1284,16 +1320,19 @@ static int svm_set_msr(struct kvm_vcpu *vcpu, unsigned ecx, u64 data) case MSR_K7_EVNTSEL1: case MSR_K7_EVNTSEL2: case MSR_K7_EVNTSEL3: + case MSR_K7_PERFCTR0: + case MSR_K7_PERFCTR1: + case MSR_K7_PERFCTR2: + case MSR_K7_PERFCTR3: /* - * only support writing 0 to the performance counters for now - * to make Windows happy. Should be replaced by a real - * performance counter emulation later. + * Just discard all writes to the performance counters; this + * should keep both older linux and windows 64-bit guests + * happy */ - if (data != 0) - goto unhandled; + pr_unimpl(vcpu, "unimplemented perfctr wrmsr: 0x%x data 0x%llx\n", ecx, data); + break; default: - unhandled: return kvm_set_msr_common(vcpu, ecx, data); } return 0; @@ -1304,6 +1343,10 @@ static int wrmsr_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run) u32 ecx = svm->vcpu.arch.regs[VCPU_REGS_RCX]; u64 data = (svm->vmcb->save.rax & -1u) | ((u64)(svm->vcpu.arch.regs[VCPU_REGS_RDX] & -1u) << 32); + + KVMTRACE_3D(MSR_WRITE, &svm->vcpu, ecx, (u32)data, (u32)(data >> 32), + handler); + svm->next_rip = svm->vmcb->save.rip + 2; if (svm_set_msr(&svm->vcpu, ecx, data)) kvm_inject_gp(&svm->vcpu, 0); @@ -1323,6 +1366,8 @@ static int msr_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run) static int interrupt_window_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run) { + KVMTRACE_0D(PEND_INTR, &svm->vcpu, handler); + svm->vmcb->control.intercept &= ~(1ULL << INTERCEPT_VINTR); svm->vmcb->control.int_ctl &= ~V_IRQ_MASK; /* @@ -1364,8 +1409,8 @@ static int (*svm_exit_handlers[])(struct vcpu_svm *svm, [SVM_EXIT_EXCP_BASE + PF_VECTOR] = pf_interception, [SVM_EXIT_EXCP_BASE + NM_VECTOR] = nm_interception, [SVM_EXIT_EXCP_BASE + MC_VECTOR] = mc_interception, - [SVM_EXIT_INTR] = nop_on_interception, - [SVM_EXIT_NMI] = nop_on_interception, + [SVM_EXIT_INTR] = intr_interception, + [SVM_EXIT_NMI] = nmi_interception, [SVM_EXIT_SMI] = nop_on_interception, [SVM_EXIT_INIT] = nop_on_interception, [SVM_EXIT_VINTR] = interrupt_window_interception, @@ -1397,6 +1442,9 @@ static int handle_exit(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu) struct vcpu_svm *svm = to_svm(vcpu); u32 exit_code = svm->vmcb->control.exit_code; + KVMTRACE_3D(VMEXIT, vcpu, exit_code, (u32)svm->vmcb->save.rip, + (u32)((u64)svm->vmcb->save.rip >> 32), entryexit); + if (npt_enabled) { int mmu_reload = 0; if ((vcpu->arch.cr0 ^ svm->vmcb->save.cr0) & X86_CR0_PG) { @@ -1470,6 +1518,8 @@ static inline void svm_inject_irq(struct vcpu_svm *svm, int irq) { struct vmcb_control_area *control; + KVMTRACE_1D(INJ_VIRQ, &svm->vcpu, (u32)irq, handler); + control = &svm->vmcb->control; control->int_vector = irq; control->int_ctl &= ~V_INTR_PRIO_MASK; @@ -1660,9 +1710,9 @@ static void svm_vcpu_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) sync_lapic_to_cr8(vcpu); save_host_msrs(vcpu); - fs_selector = read_fs(); - gs_selector = read_gs(); - ldt_selector = read_ldt(); + fs_selector = kvm_read_fs(); + gs_selector = kvm_read_gs(); + ldt_selector = kvm_read_ldt(); svm->host_cr2 = kvm_read_cr2(); svm->host_dr6 = read_dr6(); svm->host_dr7 = read_dr7(); @@ -1716,17 +1766,17 @@ static void svm_vcpu_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) /* Enter guest mode */ "push %%rax \n\t" "mov %c[vmcb](%[svm]), %%rax \n\t" - SVM_VMLOAD "\n\t" - SVM_VMRUN "\n\t" - SVM_VMSAVE "\n\t" + __ex(SVM_VMLOAD) "\n\t" + __ex(SVM_VMRUN) "\n\t" + __ex(SVM_VMSAVE) "\n\t" "pop %%rax \n\t" #else /* Enter guest mode */ "push %%eax \n\t" "mov %c[vmcb](%[svm]), %%eax \n\t" - SVM_VMLOAD "\n\t" - SVM_VMRUN "\n\t" - SVM_VMSAVE "\n\t" + __ex(SVM_VMLOAD) "\n\t" + __ex(SVM_VMRUN) "\n\t" + __ex(SVM_VMSAVE) "\n\t" "pop %%eax \n\t" #endif @@ -1795,9 +1845,9 @@ static void svm_vcpu_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) write_dr7(svm->host_dr7); kvm_write_cr2(svm->host_cr2); - load_fs(fs_selector); - load_gs(gs_selector); - load_ldt(ldt_selector); + kvm_load_fs(fs_selector); + kvm_load_gs(gs_selector); + kvm_load_ldt(ldt_selector); load_host_msrs(vcpu); reload_tss(vcpu); @@ -1889,7 +1939,6 @@ static struct kvm_x86_ops svm_x86_ops = { .prepare_guest_switch = svm_prepare_guest_switch, .vcpu_load = svm_vcpu_load, .vcpu_put = svm_vcpu_put, - .vcpu_decache = svm_vcpu_decache, .set_guest_debug = svm_guest_debug, .get_msr = svm_get_msr, diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c index 10ce6ee4c491..0cac63701719 100644 --- a/arch/x86/kvm/vmx.c +++ b/arch/x86/kvm/vmx.c @@ -30,6 +30,8 @@ #include <asm/io.h> #include <asm/desc.h> +#define __ex(x) __kvm_handle_fault_on_reboot(x) + MODULE_AUTHOR("Qumranet"); MODULE_LICENSE("GPL"); @@ -53,6 +55,7 @@ struct vmcs { struct vcpu_vmx { struct kvm_vcpu vcpu; + struct list_head local_vcpus_link; int launched; u8 fail; u32 idt_vectoring_info; @@ -88,9 +91,11 @@ static inline struct vcpu_vmx *to_vmx(struct kvm_vcpu *vcpu) } static int init_rmode(struct kvm *kvm); +static u64 construct_eptp(unsigned long root_hpa); static DEFINE_PER_CPU(struct vmcs *, vmxarea); static DEFINE_PER_CPU(struct vmcs *, current_vmcs); +static DEFINE_PER_CPU(struct list_head, vcpus_on_cpu); static struct page *vmx_io_bitmap_a; static struct page *vmx_io_bitmap_b; @@ -260,6 +265,11 @@ static inline int cpu_has_vmx_vpid(void) SECONDARY_EXEC_ENABLE_VPID); } +static inline int cpu_has_virtual_nmis(void) +{ + return vmcs_config.pin_based_exec_ctrl & PIN_BASED_VIRTUAL_NMIS; +} + static int __find_msr_index(struct vcpu_vmx *vmx, u32 msr) { int i; @@ -278,7 +288,7 @@ static inline void __invvpid(int ext, u16 vpid, gva_t gva) u64 gva; } operand = { vpid, 0, gva }; - asm volatile (ASM_VMX_INVVPID + asm volatile (__ex(ASM_VMX_INVVPID) /* CF==1 or ZF==1 --> rc = -1 */ "; ja 1f ; ud2 ; 1:" : : "a"(&operand), "c"(ext) : "cc", "memory"); @@ -290,7 +300,7 @@ static inline void __invept(int ext, u64 eptp, gpa_t gpa) u64 eptp, gpa; } operand = {eptp, gpa}; - asm volatile (ASM_VMX_INVEPT + asm volatile (__ex(ASM_VMX_INVEPT) /* CF==1 or ZF==1 --> rc = -1 */ "; ja 1f ; ud2 ; 1:\n" : : "a" (&operand), "c" (ext) : "cc", "memory"); @@ -311,7 +321,7 @@ static void vmcs_clear(struct vmcs *vmcs) u64 phys_addr = __pa(vmcs); u8 error; - asm volatile (ASM_VMX_VMCLEAR_RAX "; setna %0" + asm volatile (__ex(ASM_VMX_VMCLEAR_RAX) "; setna %0" : "=g"(error) : "a"(&phys_addr), "m"(phys_addr) : "cc", "memory"); if (error) @@ -329,6 +339,9 @@ static void __vcpu_clear(void *arg) if (per_cpu(current_vmcs, cpu) == vmx->vmcs) per_cpu(current_vmcs, cpu) = NULL; rdtscll(vmx->vcpu.arch.host_tsc); + list_del(&vmx->local_vcpus_link); + vmx->vcpu.cpu = -1; + vmx->launched = 0; } static void vcpu_clear(struct vcpu_vmx *vmx) @@ -336,7 +349,6 @@ static void vcpu_clear(struct vcpu_vmx *vmx) if (vmx->vcpu.cpu == -1) return; smp_call_function_single(vmx->vcpu.cpu, __vcpu_clear, vmx, 1); - vmx->launched = 0; } static inline void vpid_sync_vcpu_all(struct vcpu_vmx *vmx) @@ -378,7 +390,7 @@ static unsigned long vmcs_readl(unsigned long field) { unsigned long value; - asm volatile (ASM_VMX_VMREAD_RDX_RAX + asm volatile (__ex(ASM_VMX_VMREAD_RDX_RAX) : "=a"(value) : "d"(field) : "cc"); return value; } @@ -413,7 +425,7 @@ static void vmcs_writel(unsigned long field, unsigned long value) { u8 error; - asm volatile (ASM_VMX_VMWRITE_RAX_RDX "; setna %0" + asm volatile (__ex(ASM_VMX_VMWRITE_RAX_RDX) "; setna %0" : "=q"(error) : "a"(value), "d"(field) : "cc"); if (unlikely(error)) vmwrite_error(field, value); @@ -431,10 +443,8 @@ static void vmcs_write32(unsigned long field, u32 value) static void vmcs_write64(unsigned long field, u64 value) { -#ifdef CONFIG_X86_64 - vmcs_writel(field, value); -#else vmcs_writel(field, value); +#ifndef CONFIG_X86_64 asm volatile (""); vmcs_writel(field+1, value >> 32); #endif @@ -474,7 +484,7 @@ static void reload_tss(void) struct descriptor_table gdt; struct desc_struct *descs; - get_gdt(&gdt); + kvm_get_gdt(&gdt); descs = (void *)gdt.base; descs[GDT_ENTRY_TSS].type = 9; /* available TSS */ load_TR_desc(); @@ -530,9 +540,9 @@ static void vmx_save_host_state(struct kvm_vcpu *vcpu) * Set host fs and gs selectors. Unfortunately, 22.2.3 does not * allow segment selectors with cpl > 0 or ti == 1. */ - vmx->host_state.ldt_sel = read_ldt(); + vmx->host_state.ldt_sel = kvm_read_ldt(); vmx->host_state.gs_ldt_reload_needed = vmx->host_state.ldt_sel; - vmx->host_state.fs_sel = read_fs(); + vmx->host_state.fs_sel = kvm_read_fs(); if (!(vmx->host_state.fs_sel & 7)) { vmcs_write16(HOST_FS_SELECTOR, vmx->host_state.fs_sel); vmx->host_state.fs_reload_needed = 0; @@ -540,7 +550,7 @@ static void vmx_save_host_state(struct kvm_vcpu *vcpu) vmcs_write16(HOST_FS_SELECTOR, 0); vmx->host_state.fs_reload_needed = 1; } - vmx->host_state.gs_sel = read_gs(); + vmx->host_state.gs_sel = kvm_read_gs(); if (!(vmx->host_state.gs_sel & 7)) vmcs_write16(HOST_GS_SELECTOR, vmx->host_state.gs_sel); else { @@ -576,15 +586,15 @@ static void __vmx_load_host_state(struct vcpu_vmx *vmx) ++vmx->vcpu.stat.host_state_reload; vmx->host_state.loaded = 0; if (vmx->host_state.fs_reload_needed) - load_fs(vmx->host_state.fs_sel); + kvm_load_fs(vmx->host_state.fs_sel); if (vmx->host_state.gs_ldt_reload_needed) { - load_ldt(vmx->host_state.ldt_sel); + kvm_load_ldt(vmx->host_state.ldt_sel); /* * If we have to reload gs, we must take care to * preserve our gs base. */ local_irq_save(flags); - load_gs(vmx->host_state.gs_sel); + kvm_load_gs(vmx->host_state.gs_sel); #ifdef CONFIG_X86_64 wrmsrl(MSR_GS_BASE, vmcs_readl(HOST_GS_BASE)); #endif @@ -617,13 +627,17 @@ static void vmx_vcpu_load(struct kvm_vcpu *vcpu, int cpu) vcpu_clear(vmx); kvm_migrate_timers(vcpu); vpid_sync_vcpu_all(vmx); + local_irq_disable(); + list_add(&vmx->local_vcpus_link, + &per_cpu(vcpus_on_cpu, cpu)); + local_irq_enable(); } if (per_cpu(current_vmcs, cpu) != vmx->vmcs) { u8 error; per_cpu(current_vmcs, cpu) = vmx->vmcs; - asm volatile (ASM_VMX_VMPTRLD_RAX "; setna %0" + asm volatile (__ex(ASM_VMX_VMPTRLD_RAX) "; setna %0" : "=g"(error) : "a"(&phys_addr), "m"(phys_addr) : "cc"); if (error) @@ -640,8 +654,8 @@ static void vmx_vcpu_load(struct kvm_vcpu *vcpu, int cpu) * Linux uses per-cpu TSS and GDT, so set these when switching * processors. */ - vmcs_writel(HOST_TR_BASE, read_tr_base()); /* 22.2.4 */ - get_gdt(&dt); + vmcs_writel(HOST_TR_BASE, kvm_read_tr_base()); /* 22.2.4 */ + kvm_get_gdt(&dt); vmcs_writel(HOST_GDTR_BASE, dt.base); /* 22.2.4 */ rdmsrl(MSR_IA32_SYSENTER_ESP, sysenter_esp); @@ -684,11 +698,6 @@ static void vmx_fpu_deactivate(struct kvm_vcpu *vcpu) update_exception_bitmap(vcpu); } -static void vmx_vcpu_decache(struct kvm_vcpu *vcpu) -{ - vcpu_clear(to_vmx(vcpu)); -} - static unsigned long vmx_get_rflags(struct kvm_vcpu *vcpu) { return vmcs_readl(GUEST_RFLAGS); @@ -913,6 +922,18 @@ static int vmx_set_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 data) case MSR_IA32_TIME_STAMP_COUNTER: guest_write_tsc(data); break; + case MSR_P6_PERFCTR0: + case MSR_P6_PERFCTR1: + case MSR_P6_EVNTSEL0: + case MSR_P6_EVNTSEL1: + /* + * Just discard all writes to the performance counters; this + * should keep both older linux and windows 64-bit guests + * happy + */ + pr_unimpl(vcpu, "unimplemented perfctr wrmsr: 0x%x data 0x%llx\n", msr_index, data); + + break; default: vmx_load_host_state(vmx); msr = find_msr_entry(vmx, msr_index); @@ -1022,6 +1043,7 @@ static void hardware_enable(void *garbage) u64 phys_addr = __pa(per_cpu(vmxarea, cpu)); u64 old; + INIT_LIST_HEAD(&per_cpu(vcpus_on_cpu, cpu)); rdmsrl(MSR_IA32_FEATURE_CONTROL, old); if ((old & (MSR_IA32_FEATURE_CONTROL_LOCKED | MSR_IA32_FEATURE_CONTROL_VMXON_ENABLED)) @@ -1032,13 +1054,25 @@ static void hardware_enable(void *garbage) MSR_IA32_FEATURE_CONTROL_LOCKED | MSR_IA32_FEATURE_CONTROL_VMXON_ENABLED); write_cr4(read_cr4() | X86_CR4_VMXE); /* FIXME: not cpu hotplug safe */ - asm volatile (ASM_VMX_VMXON_RAX : : "a"(&phys_addr), "m"(phys_addr) + asm volatile (ASM_VMX_VMXON_RAX + : : "a"(&phys_addr), "m"(phys_addr) : "memory", "cc"); } +static void vmclear_local_vcpus(void) +{ + int cpu = raw_smp_processor_id(); + struct vcpu_vmx *vmx, *n; + + list_for_each_entry_safe(vmx, n, &per_cpu(vcpus_on_cpu, cpu), + local_vcpus_link) + __vcpu_clear(vmx); +} + static void hardware_disable(void *garbage) { - asm volatile (ASM_VMX_VMXOFF : : : "cc"); + vmclear_local_vcpus(); + asm volatile (__ex(ASM_VMX_VMXOFF) : : : "cc"); write_cr4(read_cr4() & ~X86_CR4_VMXE); } @@ -1072,7 +1106,7 @@ static __init int setup_vmcs_config(struct vmcs_config *vmcs_conf) u32 _vmentry_control = 0; min = PIN_BASED_EXT_INTR_MASK | PIN_BASED_NMI_EXITING; - opt = 0; + opt = PIN_BASED_VIRTUAL_NMIS; if (adjust_vmx_controls(min, opt, MSR_IA32_VMX_PINBASED_CTLS, &_pin_based_exec_control) < 0) return -EIO; @@ -1389,6 +1423,8 @@ static void exit_lmode(struct kvm_vcpu *vcpu) static void vmx_flush_tlb(struct kvm_vcpu *vcpu) { vpid_sync_vcpu_all(to_vmx(vcpu)); + if (vm_need_ept()) + ept_sync_context(construct_eptp(vcpu->arch.mmu.root_hpa)); } static void vmx_decache_cr4_guest_bits(struct kvm_vcpu *vcpu) @@ -1420,7 +1456,7 @@ static void ept_update_paging_mode_cr0(unsigned long *hw_cr0, if (!(cr0 & X86_CR0_PG)) { /* From paging/starting to nonpaging */ vmcs_write32(CPU_BASED_VM_EXEC_CONTROL, - vmcs_config.cpu_based_exec_ctrl | + vmcs_read32(CPU_BASED_VM_EXEC_CONTROL) | (CPU_BASED_CR3_LOAD_EXITING | CPU_BASED_CR3_STORE_EXITING)); vcpu->arch.cr0 = cr0; @@ -1430,7 +1466,7 @@ static void ept_update_paging_mode_cr0(unsigned long *hw_cr0, } else if (!is_paging(vcpu)) { /* From nonpaging to paging */ vmcs_write32(CPU_BASED_VM_EXEC_CONTROL, - vmcs_config.cpu_based_exec_ctrl & + vmcs_read32(CPU_BASED_VM_EXEC_CONTROL) & ~(CPU_BASED_CR3_LOAD_EXITING | CPU_BASED_CR3_STORE_EXITING)); vcpu->arch.cr0 = cr0; @@ -1821,7 +1857,7 @@ static void allocate_vpid(struct vcpu_vmx *vmx) spin_unlock(&vmx_vpid_lock); } -void vmx_disable_intercept_for_msr(struct page *msr_bitmap, u32 msr) +static void vmx_disable_intercept_for_msr(struct page *msr_bitmap, u32 msr) { void *va; @@ -1907,8 +1943,8 @@ static int vmx_vcpu_setup(struct vcpu_vmx *vmx) vmcs_write16(HOST_CS_SELECTOR, __KERNEL_CS); /* 22.2.4 */ vmcs_write16(HOST_DS_SELECTOR, __KERNEL_DS); /* 22.2.4 */ vmcs_write16(HOST_ES_SELECTOR, __KERNEL_DS); /* 22.2.4 */ - vmcs_write16(HOST_FS_SELECTOR, read_fs()); /* 22.2.4 */ - vmcs_write16(HOST_GS_SELECTOR, read_gs()); /* 22.2.4 */ + vmcs_write16(HOST_FS_SELECTOR, kvm_read_fs()); /* 22.2.4 */ + vmcs_write16(HOST_GS_SELECTOR, kvm_read_gs()); /* 22.2.4 */ vmcs_write16(HOST_SS_SELECTOR, __KERNEL_DS); /* 22.2.4 */ #ifdef CONFIG_X86_64 rdmsrl(MSR_FS_BASE, a); @@ -1922,7 +1958,7 @@ static int vmx_vcpu_setup(struct vcpu_vmx *vmx) vmcs_write16(HOST_TR_SELECTOR, GDT_ENTRY_TSS*8); /* 22.2.4 */ - get_idt(&dt); + kvm_get_idt(&dt); vmcs_writel(HOST_IDTR_BASE, dt.base); /* 22.2.4 */ asm("mov $.Lkvm_vmx_return, %0" : "=r"(kvm_vmx_return)); @@ -2114,6 +2150,13 @@ static void vmx_inject_irq(struct kvm_vcpu *vcpu, int irq) irq | INTR_TYPE_EXT_INTR | INTR_INFO_VALID_MASK); } +static void vmx_inject_nmi(struct kvm_vcpu *vcpu) +{ + vmcs_write32(VM_ENTRY_INTR_INFO_FIELD, + INTR_TYPE_NMI_INTR | INTR_INFO_VALID_MASK | NMI_VECTOR); + vcpu->arch.nmi_pending = 0; +} + static void kvm_do_inject_irq(struct kvm_vcpu *vcpu) { int word_index = __ffs(vcpu->arch.irq_summary); @@ -2554,8 +2597,6 @@ static int handle_apic_access(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) exit_qualification = vmcs_read64(EXIT_QUALIFICATION); offset = exit_qualification & 0xffful; - KVMTRACE_1D(APIC_ACCESS, vcpu, (u32)offset, handler); - er = emulate_instruction(vcpu, kvm_run, 0, 0, 0); if (er != EMULATE_DONE) { @@ -2639,6 +2680,19 @@ static int handle_ept_violation(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) return 1; } +static int handle_nmi_window(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) +{ + u32 cpu_based_vm_exec_control; + + /* clear pending NMI */ + cpu_based_vm_exec_control = vmcs_read32(CPU_BASED_VM_EXEC_CONTROL); + cpu_based_vm_exec_control &= ~CPU_BASED_VIRTUAL_NMI_PENDING; + vmcs_write32(CPU_BASED_VM_EXEC_CONTROL, cpu_based_vm_exec_control); + ++vcpu->stat.nmi_window_exits; + + return 1; +} + /* * The exit handlers return 1 if the exit was handled fully and guest execution * may resume. Otherwise they set the kvm_run parameter to indicate what needs @@ -2649,6 +2703,7 @@ static int (*kvm_vmx_exit_handlers[])(struct kvm_vcpu *vcpu, [EXIT_REASON_EXCEPTION_NMI] = handle_exception, [EXIT_REASON_EXTERNAL_INTERRUPT] = handle_external_interrupt, [EXIT_REASON_TRIPLE_FAULT] = handle_triple_fault, + [EXIT_REASON_NMI_WINDOW] = handle_nmi_window, [EXIT_REASON_IO_INSTRUCTION] = handle_io, [EXIT_REASON_CR_ACCESS] = handle_cr, [EXIT_REASON_DR_ACCESS] = handle_dr, @@ -2736,17 +2791,52 @@ static void enable_irq_window(struct kvm_vcpu *vcpu) vmcs_write32(CPU_BASED_VM_EXEC_CONTROL, cpu_based_vm_exec_control); } +static void enable_nmi_window(struct kvm_vcpu *vcpu) +{ + u32 cpu_based_vm_exec_control; + + if (!cpu_has_virtual_nmis()) + return; + + cpu_based_vm_exec_control = vmcs_read32(CPU_BASED_VM_EXEC_CONTROL); + cpu_based_vm_exec_control |= CPU_BASED_VIRTUAL_NMI_PENDING; + vmcs_write32(CPU_BASED_VM_EXEC_CONTROL, cpu_based_vm_exec_control); +} + +static int vmx_nmi_enabled(struct kvm_vcpu *vcpu) +{ + u32 guest_intr = vmcs_read32(GUEST_INTERRUPTIBILITY_INFO); + return !(guest_intr & (GUEST_INTR_STATE_NMI | + GUEST_INTR_STATE_MOV_SS | + GUEST_INTR_STATE_STI)); +} + +static int vmx_irq_enabled(struct kvm_vcpu *vcpu) +{ + u32 guest_intr = vmcs_read32(GUEST_INTERRUPTIBILITY_INFO); + return (!(guest_intr & (GUEST_INTR_STATE_MOV_SS | + GUEST_INTR_STATE_STI)) && + (vmcs_readl(GUEST_RFLAGS) & X86_EFLAGS_IF)); +} + +static void enable_intr_window(struct kvm_vcpu *vcpu) +{ + if (vcpu->arch.nmi_pending) + enable_nmi_window(vcpu); + else if (kvm_cpu_has_interrupt(vcpu)) + enable_irq_window(vcpu); +} + static void vmx_intr_assist(struct kvm_vcpu *vcpu) { struct vcpu_vmx *vmx = to_vmx(vcpu); - u32 idtv_info_field, intr_info_field; - int has_ext_irq, interrupt_window_open; + u32 idtv_info_field, intr_info_field, exit_intr_info_field; int vector; update_tpr_threshold(vcpu); - has_ext_irq = kvm_cpu_has_interrupt(vcpu); intr_info_field = vmcs_read32(VM_ENTRY_INTR_INFO_FIELD); + exit_intr_info_field = vmcs_read32(VM_EXIT_INTR_INFO); idtv_info_field = vmx->idt_vectoring_info; if (intr_info_field & INTR_INFO_VALID_MASK) { if (idtv_info_field & INTR_INFO_VALID_MASK) { @@ -2754,8 +2844,7 @@ static void vmx_intr_assist(struct kvm_vcpu *vcpu) if (printk_ratelimit()) printk(KERN_ERR "Fault when IDT_Vectoring\n"); } - if (has_ext_irq) - enable_irq_window(vcpu); + enable_intr_window(vcpu); return; } if (unlikely(idtv_info_field & INTR_INFO_VALID_MASK)) { @@ -2765,30 +2854,56 @@ static void vmx_intr_assist(struct kvm_vcpu *vcpu) u8 vect = idtv_info_field & VECTORING_INFO_VECTOR_MASK; vmx_inject_irq(vcpu, vect); - if (unlikely(has_ext_irq)) - enable_irq_window(vcpu); + enable_intr_window(vcpu); return; } KVMTRACE_1D(REDELIVER_EVT, vcpu, idtv_info_field, handler); - vmcs_write32(VM_ENTRY_INTR_INFO_FIELD, idtv_info_field); + /* + * SDM 3: 25.7.1.2 + * Clear bit "block by NMI" before VM entry if a NMI delivery + * faulted. + */ + if ((idtv_info_field & VECTORING_INFO_TYPE_MASK) + == INTR_TYPE_NMI_INTR && cpu_has_virtual_nmis()) + vmcs_write32(GUEST_INTERRUPTIBILITY_INFO, + vmcs_read32(GUEST_INTERRUPTIBILITY_INFO) & + ~GUEST_INTR_STATE_NMI); + + vmcs_write32(VM_ENTRY_INTR_INFO_FIELD, idtv_info_field + & ~INTR_INFO_RESVD_BITS_MASK); vmcs_write32(VM_ENTRY_INSTRUCTION_LEN, vmcs_read32(VM_EXIT_INSTRUCTION_LEN)); if (unlikely(idtv_info_field & INTR_INFO_DELIVER_CODE_MASK)) vmcs_write32(VM_ENTRY_EXCEPTION_ERROR_CODE, vmcs_read32(IDT_VECTORING_ERROR_CODE)); - if (unlikely(has_ext_irq)) - enable_irq_window(vcpu); + enable_intr_window(vcpu); return; } - if (!has_ext_irq) + if (cpu_has_virtual_nmis()) { + /* + * SDM 3: 25.7.1.2 + * Re-set bit "block by NMI" before VM entry if vmexit caused by + * a guest IRET fault. + */ + if ((exit_intr_info_field & INTR_INFO_UNBLOCK_NMI) && + (exit_intr_info_field & INTR_INFO_VECTOR_MASK) != 8) + vmcs_write32(GUEST_INTERRUPTIBILITY_INFO, + vmcs_read32(GUEST_INTERRUPTIBILITY_INFO) | + GUEST_INTR_STATE_NMI); + else if (vcpu->arch.nmi_pending) { + if (vmx_nmi_enabled(vcpu)) + vmx_inject_nmi(vcpu); + enable_intr_window(vcpu); + return; + } + + } + if (!kvm_cpu_has_interrupt(vcpu)) return; - interrupt_window_open = - ((vmcs_readl(GUEST_RFLAGS) & X86_EFLAGS_IF) && - (vmcs_read32(GUEST_INTERRUPTIBILITY_INFO) & 3) == 0); - if (interrupt_window_open) { + if (vmx_irq_enabled(vcpu)) { vector = kvm_cpu_get_interrupt(vcpu); vmx_inject_irq(vcpu, vector); kvm_timer_intr_post(vcpu, vector); @@ -2838,7 +2953,7 @@ static void vmx_vcpu_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) "push %%edx; push %%ebp;" "push %%ecx \n\t" #endif - ASM_VMX_VMWRITE_RSP_RDX "\n\t" + __ex(ASM_VMX_VMWRITE_RSP_RDX) "\n\t" /* Check if vmlaunch of vmresume is needed */ "cmpl $0, %c[launched](%0) \n\t" /* Load guest registers. Don't clobber flags. */ @@ -2873,9 +2988,9 @@ static void vmx_vcpu_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) #endif /* Enter guest mode */ "jne .Llaunched \n\t" - ASM_VMX_VMLAUNCH "\n\t" + __ex(ASM_VMX_VMLAUNCH) "\n\t" "jmp .Lkvm_vmx_return \n\t" - ".Llaunched: " ASM_VMX_VMRESUME "\n\t" + ".Llaunched: " __ex(ASM_VMX_VMRESUME) "\n\t" ".Lkvm_vmx_return: " /* Save guest registers, load host registers, keep flags */ #ifdef CONFIG_X86_64 @@ -2949,7 +3064,8 @@ static void vmx_vcpu_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) fixup_rmode_irq(vmx); vcpu->arch.interrupt_window_open = - (vmcs_read32(GUEST_INTERRUPTIBILITY_INFO) & 3) == 0; + (vmcs_read32(GUEST_INTERRUPTIBILITY_INFO) & + (GUEST_INTR_STATE_STI | GUEST_INTR_STATE_MOV_SS)) == 0; asm("mov %0, %%ds; mov %0, %%es" : : "r"(__USER_DS)); vmx->launched = 1; @@ -2957,7 +3073,8 @@ static void vmx_vcpu_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) intr_info = vmcs_read32(VM_EXIT_INTR_INFO); /* We need to handle NMIs before interrupts are enabled */ - if ((intr_info & INTR_INFO_INTR_TYPE_MASK) == 0x200) { /* nmi */ + if ((intr_info & INTR_INFO_INTR_TYPE_MASK) == 0x200 && + (intr_info & INTR_INFO_VALID_MASK)) { KVMTRACE_0D(NMI, vcpu, handler); asm("int $2"); } @@ -2968,7 +3085,7 @@ static void vmx_free_vmcs(struct kvm_vcpu *vcpu) struct vcpu_vmx *vmx = to_vmx(vcpu); if (vmx->vmcs) { - on_each_cpu(__vcpu_clear, vmx, 1); + vcpu_clear(vmx); free_vmcs(vmx->vmcs); vmx->vmcs = NULL; } @@ -3095,7 +3212,6 @@ static struct kvm_x86_ops vmx_x86_ops = { .prepare_guest_switch = vmx_save_host_state, .vcpu_load = vmx_vcpu_load, .vcpu_put = vmx_vcpu_put, - .vcpu_decache = vmx_vcpu_decache, .set_guest_debug = set_guest_debug, .guest_debug_pre = kvm_guest_debug_pre, diff --git a/arch/x86/kvm/vmx.h b/arch/x86/kvm/vmx.h index 79d94c610dfe..425a13436b3f 100644 --- a/arch/x86/kvm/vmx.h +++ b/arch/x86/kvm/vmx.h @@ -40,6 +40,7 @@ #define CPU_BASED_CR8_LOAD_EXITING 0x00080000 #define CPU_BASED_CR8_STORE_EXITING 0x00100000 #define CPU_BASED_TPR_SHADOW 0x00200000 +#define CPU_BASED_VIRTUAL_NMI_PENDING 0x00400000 #define CPU_BASED_MOV_DR_EXITING 0x00800000 #define CPU_BASED_UNCOND_IO_EXITING 0x01000000 #define CPU_BASED_USE_IO_BITMAPS 0x02000000 @@ -216,7 +217,7 @@ enum vmcs_field { #define EXIT_REASON_TRIPLE_FAULT 2 #define EXIT_REASON_PENDING_INTERRUPT 7 - +#define EXIT_REASON_NMI_WINDOW 8 #define EXIT_REASON_TASK_SWITCH 9 #define EXIT_REASON_CPUID 10 #define EXIT_REASON_HLT 12 @@ -251,7 +252,9 @@ enum vmcs_field { #define INTR_INFO_VECTOR_MASK 0xff /* 7:0 */ #define INTR_INFO_INTR_TYPE_MASK 0x700 /* 10:8 */ #define INTR_INFO_DELIVER_CODE_MASK 0x800 /* 11 */ +#define INTR_INFO_UNBLOCK_NMI 0x1000 /* 12 */ #define INTR_INFO_VALID_MASK 0x80000000 /* 31 */ +#define INTR_INFO_RESVD_BITS_MASK 0x7ffff000 #define VECTORING_INFO_VECTOR_MASK INTR_INFO_VECTOR_MASK #define VECTORING_INFO_TYPE_MASK INTR_INFO_INTR_TYPE_MASK @@ -259,9 +262,16 @@ enum vmcs_field { #define VECTORING_INFO_VALID_MASK INTR_INFO_VALID_MASK #define INTR_TYPE_EXT_INTR (0 << 8) /* external interrupt */ +#define INTR_TYPE_NMI_INTR (2 << 8) /* NMI */ #define INTR_TYPE_EXCEPTION (3 << 8) /* processor exception */ #define INTR_TYPE_SOFT_INTR (4 << 8) /* software interrupt */ +/* GUEST_INTERRUPTIBILITY_INFO flags. */ +#define GUEST_INTR_STATE_STI 0x00000001 +#define GUEST_INTR_STATE_MOV_SS 0x00000002 +#define GUEST_INTR_STATE_SMI 0x00000004 +#define GUEST_INTR_STATE_NMI 0x00000008 + /* * Exit Qualifications for MOV for Control Register Access */ diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 0faa2546b1cd..9f1cdb011cff 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -72,6 +72,7 @@ struct kvm_stats_debugfs_item debugfs_entries[] = { { "mmio_exits", VCPU_STAT(mmio_exits) }, { "signal_exits", VCPU_STAT(signal_exits) }, { "irq_window", VCPU_STAT(irq_window_exits) }, + { "nmi_window", VCPU_STAT(nmi_window_exits) }, { "halt_exits", VCPU_STAT(halt_exits) }, { "halt_wakeup", VCPU_STAT(halt_wakeup) }, { "hypercalls", VCPU_STAT(hypercalls) }, @@ -173,6 +174,12 @@ void kvm_inject_page_fault(struct kvm_vcpu *vcpu, unsigned long addr, kvm_queue_exception_e(vcpu, PF_VECTOR, error_code); } +void kvm_inject_nmi(struct kvm_vcpu *vcpu) +{ + vcpu->arch.nmi_pending = 1; +} +EXPORT_SYMBOL_GPL(kvm_inject_nmi); + void kvm_queue_exception_e(struct kvm_vcpu *vcpu, unsigned nr, u32 error_code) { WARN_ON(vcpu->arch.exception.pending); @@ -604,6 +611,38 @@ static void kvm_write_guest_time(struct kvm_vcpu *v) mark_page_dirty(v->kvm, vcpu->time >> PAGE_SHIFT); } +static bool msr_mtrr_valid(unsigned msr) +{ + switch (msr) { + case 0x200 ... 0x200 + 2 * KVM_NR_VAR_MTRR - 1: + case MSR_MTRRfix64K_00000: + case MSR_MTRRfix16K_80000: + case MSR_MTRRfix16K_A0000: + case MSR_MTRRfix4K_C0000: + case MSR_MTRRfix4K_C8000: + case MSR_MTRRfix4K_D0000: + case MSR_MTRRfix4K_D8000: + case MSR_MTRRfix4K_E0000: + case MSR_MTRRfix4K_E8000: + case MSR_MTRRfix4K_F0000: + case MSR_MTRRfix4K_F8000: + case MSR_MTRRdefType: + case MSR_IA32_CR_PAT: + return true; + case 0x2f8: + return true; + } + return false; +} + +static int set_msr_mtrr(struct kvm_vcpu *vcpu, u32 msr, u64 data) +{ + if (!msr_mtrr_valid(msr)) + return 1; + + vcpu->arch.mtrr[msr - 0x200] = data; + return 0; +} int kvm_set_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 data) { @@ -625,8 +664,9 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 data) break; case MSR_IA32_UCODE_REV: case MSR_IA32_UCODE_WRITE: - case 0x200 ... 0x2ff: /* MTRRs */ break; + case 0x200 ... 0x2ff: + return set_msr_mtrr(vcpu, msr, data); case MSR_IA32_APICBASE: kvm_set_apic_base(vcpu, data); break; @@ -684,6 +724,15 @@ int kvm_get_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 *pdata) return kvm_x86_ops->get_msr(vcpu, msr_index, pdata); } +static int get_msr_mtrr(struct kvm_vcpu *vcpu, u32 msr, u64 *pdata) +{ + if (!msr_mtrr_valid(msr)) + return 1; + + *pdata = vcpu->arch.mtrr[msr - 0x200]; + return 0; +} + int kvm_get_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 *pdata) { u64 data; @@ -705,11 +754,13 @@ int kvm_get_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 *pdata) case MSR_IA32_MC0_MISC+16: case MSR_IA32_UCODE_REV: case MSR_IA32_EBL_CR_POWERON: - /* MTRR registers */ - case 0xfe: - case 0x200 ... 0x2ff: data = 0; break; + case MSR_MTRRcap: + data = 0x500 | KVM_NR_VAR_MTRR; + break; + case 0x200 ... 0x2ff: + return get_msr_mtrr(vcpu, msr, pdata); case 0xcd: /* fsb frequency */ data = 3; break; @@ -817,41 +868,6 @@ out: return r; } -/* - * Make sure that a cpu that is being hot-unplugged does not have any vcpus - * cached on it. - */ -void decache_vcpus_on_cpu(int cpu) -{ - struct kvm *vm; - struct kvm_vcpu *vcpu; - int i; - - spin_lock(&kvm_lock); - list_for_each_entry(vm, &vm_list, vm_list) - for (i = 0; i < KVM_MAX_VCPUS; ++i) { - vcpu = vm->vcpus[i]; - if (!vcpu) - continue; - /* - * If the vcpu is locked, then it is running on some - * other cpu and therefore it is not cached on the - * cpu in question. - * - * If it's not locked, check the last cpu it executed - * on. - */ - if (mutex_trylock(&vcpu->mutex)) { - if (vcpu->cpu == cpu) { - kvm_x86_ops->vcpu_decache(vcpu); - vcpu->cpu = -1; - } - mutex_unlock(&vcpu->mutex); - } - } - spin_unlock(&kvm_lock); -} - int kvm_dev_ioctl_check_extension(long ext) { int r; @@ -869,6 +885,9 @@ int kvm_dev_ioctl_check_extension(long ext) case KVM_CAP_MP_STATE: r = 1; break; + case KVM_CAP_COALESCED_MMIO: + r = KVM_COALESCED_MMIO_PAGE_OFFSET; + break; case KVM_CAP_VAPIC: r = !kvm_x86_ops->cpu_has_accelerated_tpr(); break; @@ -1781,13 +1800,14 @@ static void kvm_init_msr_list(void) * Only apic need an MMIO device hook, so shortcut now.. */ static struct kvm_io_device *vcpu_find_pervcpu_dev(struct kvm_vcpu *vcpu, - gpa_t addr) + gpa_t addr, int len, + int is_write) { struct kvm_io_device *dev; if (vcpu->arch.apic) { dev = &vcpu->arch.apic->dev; - if (dev->in_range(dev, addr)) + if (dev->in_range(dev, addr, len, is_write)) return dev; } return NULL; @@ -1795,13 +1815,15 @@ static struct kvm_io_device *vcpu_find_pervcpu_dev(struct kvm_vcpu *vcpu, static struct kvm_io_device *vcpu_find_mmio_dev(struct kvm_vcpu *vcpu, - gpa_t addr) + gpa_t addr, int len, + int is_write) { struct kvm_io_device *dev; - dev = vcpu_find_pervcpu_dev(vcpu, addr); + dev = vcpu_find_pervcpu_dev(vcpu, addr, len, is_write); if (dev == NULL) - dev = kvm_io_bus_find_dev(&vcpu->kvm->mmio_bus, addr); + dev = kvm_io_bus_find_dev(&vcpu->kvm->mmio_bus, addr, len, + is_write); return dev; } @@ -1869,7 +1891,7 @@ mmio: * Is this MMIO handled locally? */ mutex_lock(&vcpu->kvm->lock); - mmio_dev = vcpu_find_mmio_dev(vcpu, gpa); + mmio_dev = vcpu_find_mmio_dev(vcpu, gpa, bytes, 0); if (mmio_dev) { kvm_iodevice_read(mmio_dev, gpa, bytes, val); mutex_unlock(&vcpu->kvm->lock); @@ -1924,7 +1946,7 @@ mmio: * Is this MMIO handled locally? */ mutex_lock(&vcpu->kvm->lock); - mmio_dev = vcpu_find_mmio_dev(vcpu, gpa); + mmio_dev = vcpu_find_mmio_dev(vcpu, gpa, bytes, 1); if (mmio_dev) { kvm_iodevice_write(mmio_dev, gpa, bytes, val); mutex_unlock(&vcpu->kvm->lock); @@ -2020,6 +2042,7 @@ int emulate_invlpg(struct kvm_vcpu *vcpu, gva_t address) int emulate_clts(struct kvm_vcpu *vcpu) { + KVMTRACE_0D(CLTS, vcpu, handler); kvm_x86_ops->set_cr0(vcpu, vcpu->arch.cr0 & ~X86_CR0_TS); return X86EMUL_CONTINUE; } @@ -2053,21 +2076,19 @@ int emulator_set_dr(struct x86_emulate_ctxt *ctxt, int dr, unsigned long value) void kvm_report_emulation_failure(struct kvm_vcpu *vcpu, const char *context) { - static int reported; u8 opcodes[4]; unsigned long rip = vcpu->arch.rip; unsigned long rip_linear; - rip_linear = rip + get_segment_base(vcpu, VCPU_SREG_CS); - - if (reported) + if (!printk_ratelimit()) return; + rip_linear = rip + get_segment_base(vcpu, VCPU_SREG_CS); + emulator_read_std(rip_linear, (void *)opcodes, 4, vcpu); printk(KERN_ERR "emulation failed (%s) rip %lx %02x %02x %02x %02x\n", context, rip, opcodes[0], opcodes[1], opcodes[2], opcodes[3]); - reported = 1; } EXPORT_SYMBOL_GPL(kvm_report_emulation_failure); @@ -2105,27 +2126,6 @@ int emulate_instruction(struct kvm_vcpu *vcpu, ? X86EMUL_MODE_PROT64 : cs_db ? X86EMUL_MODE_PROT32 : X86EMUL_MODE_PROT16; - if (vcpu->arch.emulate_ctxt.mode == X86EMUL_MODE_PROT64) { - vcpu->arch.emulate_ctxt.cs_base = 0; - vcpu->arch.emulate_ctxt.ds_base = 0; - vcpu->arch.emulate_ctxt.es_base = 0; - vcpu->arch.emulate_ctxt.ss_base = 0; - } else { - vcpu->arch.emulate_ctxt.cs_base = - get_segment_base(vcpu, VCPU_SREG_CS); - vcpu->arch.emulate_ctxt.ds_base = - get_segment_base(vcpu, VCPU_SREG_DS); - vcpu->arch.emulate_ctxt.es_base = - get_segment_base(vcpu, VCPU_SREG_ES); - vcpu->arch.emulate_ctxt.ss_base = - get_segment_base(vcpu, VCPU_SREG_SS); - } - - vcpu->arch.emulate_ctxt.gs_base = - get_segment_base(vcpu, VCPU_SREG_GS); - vcpu->arch.emulate_ctxt.fs_base = - get_segment_base(vcpu, VCPU_SREG_FS); - r = x86_decode_insn(&vcpu->arch.emulate_ctxt, &emulate_ops); /* Reject the instructions other than VMCALL/VMMCALL when @@ -2300,9 +2300,10 @@ static void pio_string_write(struct kvm_io_device *pio_dev, } static struct kvm_io_device *vcpu_find_pio_dev(struct kvm_vcpu *vcpu, - gpa_t addr) + gpa_t addr, int len, + int is_write) { - return kvm_io_bus_find_dev(&vcpu->kvm->pio_bus, addr); + return kvm_io_bus_find_dev(&vcpu->kvm->pio_bus, addr, len, is_write); } int kvm_emulate_pio(struct kvm_vcpu *vcpu, struct kvm_run *run, int in, @@ -2331,11 +2332,10 @@ int kvm_emulate_pio(struct kvm_vcpu *vcpu, struct kvm_run *run, int in, kvm_x86_ops->cache_regs(vcpu); memcpy(vcpu->arch.pio_data, &vcpu->arch.regs[VCPU_REGS_RAX], 4); - kvm_x86_ops->decache_regs(vcpu); kvm_x86_ops->skip_emulated_instruction(vcpu); - pio_dev = vcpu_find_pio_dev(vcpu, port); + pio_dev = vcpu_find_pio_dev(vcpu, port, size, !in); if (pio_dev) { kernel_pio(pio_dev, vcpu, vcpu->arch.pio_data); complete_pio(vcpu); @@ -2417,7 +2417,9 @@ int kvm_emulate_pio_string(struct kvm_vcpu *vcpu, struct kvm_run *run, int in, } } - pio_dev = vcpu_find_pio_dev(vcpu, port); + pio_dev = vcpu_find_pio_dev(vcpu, port, + vcpu->arch.pio.cur_count, + !vcpu->arch.pio.in); if (!vcpu->arch.pio.in) { /* string PIO write */ ret = pio_copy_data(vcpu); @@ -2600,27 +2602,41 @@ void realmode_lmsw(struct kvm_vcpu *vcpu, unsigned long msw, unsigned long realmode_get_cr(struct kvm_vcpu *vcpu, int cr) { + unsigned long value; + kvm_x86_ops->decache_cr4_guest_bits(vcpu); switch (cr) { case 0: - return vcpu->arch.cr0; + value = vcpu->arch.cr0; + break; case 2: - return vcpu->arch.cr2; + value = vcpu->arch.cr2; + break; case 3: - return vcpu->arch.cr3; + value = vcpu->arch.cr3; + break; case 4: - return vcpu->arch.cr4; + value = vcpu->arch.cr4; + break; case 8: - return kvm_get_cr8(vcpu); + value = kvm_get_cr8(vcpu); + break; default: vcpu_printf(vcpu, "%s: unexpected cr %u\n", __func__, cr); return 0; } + KVMTRACE_3D(CR_READ, vcpu, (u32)cr, (u32)value, + (u32)((u64)value >> 32), handler); + + return value; } void realmode_set_cr(struct kvm_vcpu *vcpu, int cr, unsigned long val, unsigned long *rflags) { + KVMTRACE_3D(CR_WRITE, vcpu, (u32)cr, (u32)val, + (u32)((u64)val >> 32), handler); + switch (cr) { case 0: kvm_set_cr0(vcpu, mk_cr_64(vcpu->arch.cr0, val)); @@ -2771,8 +2787,10 @@ static void vapic_exit(struct kvm_vcpu *vcpu) if (!apic || !apic->vapic_addr) return; + down_read(&vcpu->kvm->slots_lock); kvm_release_page_dirty(apic->vapic_page); mark_page_dirty(vcpu->kvm, apic->vapic_addr >> PAGE_SHIFT); + up_read(&vcpu->kvm->slots_lock); } static int __vcpu_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) @@ -2928,9 +2946,7 @@ out: post_kvm_run_save(vcpu, kvm_run); - down_read(&vcpu->kvm->slots_lock); vapic_exit(vcpu); - up_read(&vcpu->kvm->slots_lock); return r; } @@ -2942,15 +2958,15 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) vcpu_load(vcpu); + if (vcpu->sigset_active) + sigprocmask(SIG_SETMASK, &vcpu->sigset, &sigsaved); + if (unlikely(vcpu->arch.mp_state == KVM_MP_STATE_UNINITIALIZED)) { kvm_vcpu_block(vcpu); - vcpu_put(vcpu); - return -EAGAIN; + r = -EAGAIN; + goto out; } - if (vcpu->sigset_active) - sigprocmask(SIG_SETMASK, &vcpu->sigset, &sigsaved); - /* re-sync apic's tpr */ if (!irqchip_in_kernel(vcpu->kvm)) kvm_set_cr8(vcpu, kvm_run->cr8); @@ -3070,8 +3086,8 @@ int kvm_arch_vcpu_ioctl_set_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs) return 0; } -static void get_segment(struct kvm_vcpu *vcpu, - struct kvm_segment *var, int seg) +void kvm_get_segment(struct kvm_vcpu *vcpu, + struct kvm_segment *var, int seg) { kvm_x86_ops->get_segment(vcpu, var, seg); } @@ -3080,7 +3096,7 @@ void kvm_get_cs_db_l_bits(struct kvm_vcpu *vcpu, int *db, int *l) { struct kvm_segment cs; - get_segment(vcpu, &cs, VCPU_SREG_CS); + kvm_get_segment(vcpu, &cs, VCPU_SREG_CS); *db = cs.db; *l = cs.l; } @@ -3094,15 +3110,15 @@ int kvm_arch_vcpu_ioctl_get_sregs(struct kvm_vcpu *vcpu, vcpu_load(vcpu); - get_segment(vcpu, &sregs->cs, VCPU_SREG_CS); - get_segment(vcpu, &sregs->ds, VCPU_SREG_DS); - get_segment(vcpu, &sregs->es, VCPU_SREG_ES); - get_segment(vcpu, &sregs->fs, VCPU_SREG_FS); - get_segment(vcpu, &sregs->gs, VCPU_SREG_GS); - get_segment(vcpu, &sregs->ss, VCPU_SREG_SS); + kvm_get_segment(vcpu, &sregs->cs, VCPU_SREG_CS); + kvm_get_segment(vcpu, &sregs->ds, VCPU_SREG_DS); + kvm_get_segment(vcpu, &sregs->es, VCPU_SREG_ES); + kvm_get_segment(vcpu, &sregs->fs, VCPU_SREG_FS); + kvm_get_segment(vcpu, &sregs->gs, VCPU_SREG_GS); + kvm_get_segment(vcpu, &sregs->ss, VCPU_SREG_SS); - get_segment(vcpu, &sregs->tr, VCPU_SREG_TR); - get_segment(vcpu, &sregs->ldt, VCPU_SREG_LDTR); + kvm_get_segment(vcpu, &sregs->tr, VCPU_SREG_TR); + kvm_get_segment(vcpu, &sregs->ldt, VCPU_SREG_LDTR); kvm_x86_ops->get_idt(vcpu, &dt); sregs->idt.limit = dt.limit; @@ -3154,7 +3170,7 @@ int kvm_arch_vcpu_ioctl_set_mpstate(struct kvm_vcpu *vcpu, return 0; } -static void set_segment(struct kvm_vcpu *vcpu, +static void kvm_set_segment(struct kvm_vcpu *vcpu, struct kvm_segment *var, int seg) { kvm_x86_ops->set_segment(vcpu, var, seg); @@ -3191,7 +3207,7 @@ static void get_segment_descritptor_dtable(struct kvm_vcpu *vcpu, if (selector & 1 << 2) { struct kvm_segment kvm_seg; - get_segment(vcpu, &kvm_seg, VCPU_SREG_LDTR); + kvm_get_segment(vcpu, &kvm_seg, VCPU_SREG_LDTR); if (kvm_seg.unusable) dtable->limit = 0; @@ -3297,7 +3313,7 @@ static u16 get_segment_selector(struct kvm_vcpu *vcpu, int seg) { struct kvm_segment kvm_seg; - get_segment(vcpu, &kvm_seg, seg); + kvm_get_segment(vcpu, &kvm_seg, seg); return kvm_seg.selector; } @@ -3313,8 +3329,8 @@ static int load_segment_descriptor_to_kvm_desct(struct kvm_vcpu *vcpu, return 0; } -static int load_segment_descriptor(struct kvm_vcpu *vcpu, u16 selector, - int type_bits, int seg) +int kvm_load_segment_descriptor(struct kvm_vcpu *vcpu, u16 selector, + int type_bits, int seg) { struct kvm_segment kvm_seg; @@ -3327,7 +3343,7 @@ static int load_segment_descriptor(struct kvm_vcpu *vcpu, u16 selector, if (!kvm_seg.s) kvm_seg.unusable = 1; - set_segment(vcpu, &kvm_seg, seg); + kvm_set_segment(vcpu, &kvm_seg, seg); return 0; } @@ -3373,25 +3389,25 @@ static int load_state_from_tss32(struct kvm_vcpu *vcpu, vcpu->arch.regs[VCPU_REGS_RSI] = tss->esi; vcpu->arch.regs[VCPU_REGS_RDI] = tss->edi; - if (load_segment_descriptor(vcpu, tss->ldt_selector, 0, VCPU_SREG_LDTR)) + if (kvm_load_segment_descriptor(vcpu, tss->ldt_selector, 0, VCPU_SREG_LDTR)) return 1; - if (load_segment_descriptor(vcpu, tss->es, 1, VCPU_SREG_ES)) + if (kvm_load_segment_descriptor(vcpu, tss->es, 1, VCPU_SREG_ES)) return 1; - if (load_segment_descriptor(vcpu, tss->cs, 9, VCPU_SREG_CS)) + if (kvm_load_segment_descriptor(vcpu, tss->cs, 9, VCPU_SREG_CS)) return 1; - if (load_segment_descriptor(vcpu, tss->ss, 1, VCPU_SREG_SS)) + if (kvm_load_segment_descriptor(vcpu, tss->ss, 1, VCPU_SREG_SS)) return 1; - if (load_segment_descriptor(vcpu, tss->ds, 1, VCPU_SREG_DS)) + if (kvm_load_segment_descriptor(vcpu, tss->ds, 1, VCPU_SREG_DS)) return 1; - if (load_segment_descriptor(vcpu, tss->fs, 1, VCPU_SREG_FS)) + if (kvm_load_segment_descriptor(vcpu, tss->fs, 1, VCPU_SREG_FS)) return 1; - if (load_segment_descriptor(vcpu, tss->gs, 1, VCPU_SREG_GS)) + if (kvm_load_segment_descriptor(vcpu, tss->gs, 1, VCPU_SREG_GS)) return 1; return 0; } @@ -3432,24 +3448,24 @@ static int load_state_from_tss16(struct kvm_vcpu *vcpu, vcpu->arch.regs[VCPU_REGS_RSI] = tss->si; vcpu->arch.regs[VCPU_REGS_RDI] = tss->di; - if (load_segment_descriptor(vcpu, tss->ldt, 0, VCPU_SREG_LDTR)) + if (kvm_load_segment_descriptor(vcpu, tss->ldt, 0, VCPU_SREG_LDTR)) return 1; - if (load_segment_descriptor(vcpu, tss->es, 1, VCPU_SREG_ES)) + if (kvm_load_segment_descriptor(vcpu, tss->es, 1, VCPU_SREG_ES)) return 1; - if (load_segment_descriptor(vcpu, tss->cs, 9, VCPU_SREG_CS)) + if (kvm_load_segment_descriptor(vcpu, tss->cs, 9, VCPU_SREG_CS)) return 1; - if (load_segment_descriptor(vcpu, tss->ss, 1, VCPU_SREG_SS)) + if (kvm_load_segment_descriptor(vcpu, tss->ss, 1, VCPU_SREG_SS)) return 1; - if (load_segment_descriptor(vcpu, tss->ds, 1, VCPU_SREG_DS)) + if (kvm_load_segment_descriptor(vcpu, tss->ds, 1, VCPU_SREG_DS)) return 1; return 0; } -int kvm_task_switch_16(struct kvm_vcpu *vcpu, u16 tss_selector, +static int kvm_task_switch_16(struct kvm_vcpu *vcpu, u16 tss_selector, struct desc_struct *cseg_desc, struct desc_struct *nseg_desc) { @@ -3472,7 +3488,7 @@ out: return ret; } -int kvm_task_switch_32(struct kvm_vcpu *vcpu, u16 tss_selector, +static int kvm_task_switch_32(struct kvm_vcpu *vcpu, u16 tss_selector, struct desc_struct *cseg_desc, struct desc_struct *nseg_desc) { @@ -3502,7 +3518,7 @@ int kvm_task_switch(struct kvm_vcpu *vcpu, u16 tss_selector, int reason) struct desc_struct nseg_desc; int ret = 0; - get_segment(vcpu, &tr_seg, VCPU_SREG_TR); + kvm_get_segment(vcpu, &tr_seg, VCPU_SREG_TR); if (load_guest_segment_descriptor(vcpu, tss_selector, &nseg_desc)) goto out; @@ -3561,7 +3577,7 @@ int kvm_task_switch(struct kvm_vcpu *vcpu, u16 tss_selector, int reason) kvm_x86_ops->set_cr0(vcpu, vcpu->arch.cr0 | X86_CR0_TS); seg_desct_to_kvm_desct(&nseg_desc, tss_selector, &tr_seg); tr_seg.type = 11; - set_segment(vcpu, &tr_seg, VCPU_SREG_TR); + kvm_set_segment(vcpu, &tr_seg, VCPU_SREG_TR); out: kvm_x86_ops->decache_regs(vcpu); return ret; @@ -3628,15 +3644,15 @@ int kvm_arch_vcpu_ioctl_set_sregs(struct kvm_vcpu *vcpu, } } - set_segment(vcpu, &sregs->cs, VCPU_SREG_CS); - set_segment(vcpu, &sregs->ds, VCPU_SREG_DS); - set_segment(vcpu, &sregs->es, VCPU_SREG_ES); - set_segment(vcpu, &sregs->fs, VCPU_SREG_FS); - set_segment(vcpu, &sregs->gs, VCPU_SREG_GS); - set_segment(vcpu, &sregs->ss, VCPU_SREG_SS); + kvm_set_segment(vcpu, &sregs->cs, VCPU_SREG_CS); + kvm_set_segment(vcpu, &sregs->ds, VCPU_SREG_DS); + kvm_set_segment(vcpu, &sregs->es, VCPU_SREG_ES); + kvm_set_segment(vcpu, &sregs->fs, VCPU_SREG_FS); + kvm_set_segment(vcpu, &sregs->gs, VCPU_SREG_GS); + kvm_set_segment(vcpu, &sregs->ss, VCPU_SREG_SS); - set_segment(vcpu, &sregs->tr, VCPU_SREG_TR); - set_segment(vcpu, &sregs->ldt, VCPU_SREG_LDTR); + kvm_set_segment(vcpu, &sregs->tr, VCPU_SREG_TR); + kvm_set_segment(vcpu, &sregs->ldt, VCPU_SREG_LDTR); vcpu_put(vcpu); @@ -3751,14 +3767,14 @@ void fx_init(struct kvm_vcpu *vcpu) * allocate ram with GFP_KERNEL. */ if (!used_math()) - fx_save(&vcpu->arch.host_fx_image); + kvm_fx_save(&vcpu->arch.host_fx_image); /* Initialize guest FPU by resetting ours and saving into guest's */ preempt_disable(); - fx_save(&vcpu->arch.host_fx_image); - fx_finit(); - fx_save(&vcpu->arch.guest_fx_image); - fx_restore(&vcpu->arch.host_fx_image); + kvm_fx_save(&vcpu->arch.host_fx_image); + kvm_fx_finit(); + kvm_fx_save(&vcpu->arch.guest_fx_image); + kvm_fx_restore(&vcpu->arch.host_fx_image); preempt_enable(); vcpu->arch.cr0 |= X86_CR0_ET; @@ -3775,8 +3791,8 @@ void kvm_load_guest_fpu(struct kvm_vcpu *vcpu) return; vcpu->guest_fpu_loaded = 1; - fx_save(&vcpu->arch.host_fx_image); - fx_restore(&vcpu->arch.guest_fx_image); + kvm_fx_save(&vcpu->arch.host_fx_image); + kvm_fx_restore(&vcpu->arch.guest_fx_image); } EXPORT_SYMBOL_GPL(kvm_load_guest_fpu); @@ -3786,8 +3802,8 @@ void kvm_put_guest_fpu(struct kvm_vcpu *vcpu) return; vcpu->guest_fpu_loaded = 0; - fx_save(&vcpu->arch.guest_fx_image); - fx_restore(&vcpu->arch.host_fx_image); + kvm_fx_save(&vcpu->arch.guest_fx_image); + kvm_fx_restore(&vcpu->arch.host_fx_image); ++vcpu->stat.fpu_reload; } EXPORT_SYMBOL_GPL(kvm_put_guest_fpu); @@ -4016,6 +4032,11 @@ int kvm_arch_set_memory_region(struct kvm *kvm, return 0; } +void kvm_arch_flush_shadow(struct kvm *kvm) +{ + kvm_mmu_zap_all(kvm); +} + int kvm_arch_vcpu_runnable(struct kvm_vcpu *vcpu) { return vcpu->arch.mp_state == KVM_MP_STATE_RUNNABLE diff --git a/arch/x86/kvm/x86_emulate.c b/arch/x86/kvm/x86_emulate.c index 932f216d890c..f2f90468f8b1 100644 --- a/arch/x86/kvm/x86_emulate.c +++ b/arch/x86/kvm/x86_emulate.c @@ -121,7 +121,7 @@ static u16 opcode_table[256] = { 0, 0, 0, DstReg | SrcMem32 | ModRM | Mov /* movsxd (x86/64) */ , 0, 0, 0, 0, /* 0x68 - 0x6F */ - 0, 0, ImplicitOps | Mov | Stack, 0, + SrcImm | Mov | Stack, 0, SrcImmByte | Mov | Stack, 0, SrcNone | ByteOp | ImplicitOps, SrcNone | ImplicitOps, /* insb, insw/insd */ SrcNone | ByteOp | ImplicitOps, SrcNone | ImplicitOps, /* outsb, outsw/outsd */ /* 0x70 - 0x77 */ @@ -138,9 +138,11 @@ static u16 opcode_table[256] = { /* 0x88 - 0x8F */ ByteOp | DstMem | SrcReg | ModRM | Mov, DstMem | SrcReg | ModRM | Mov, ByteOp | DstReg | SrcMem | ModRM | Mov, DstReg | SrcMem | ModRM | Mov, - 0, ModRM | DstReg, 0, Group | Group1A, - /* 0x90 - 0x9F */ - 0, 0, 0, 0, 0, 0, 0, 0, + DstMem | SrcReg | ModRM | Mov, ModRM | DstReg, + DstReg | SrcMem | ModRM | Mov, Group | Group1A, + /* 0x90 - 0x97 */ + DstReg, DstReg, DstReg, DstReg, DstReg, DstReg, DstReg, DstReg, + /* 0x98 - 0x9F */ 0, 0, 0, 0, ImplicitOps | Stack, ImplicitOps | Stack, 0, 0, /* 0xA0 - 0xA7 */ ByteOp | DstReg | SrcMem | Mov | MemAbs, DstReg | SrcMem | Mov | MemAbs, @@ -152,7 +154,8 @@ static u16 opcode_table[256] = { ByteOp | ImplicitOps | Mov | String, ImplicitOps | Mov | String, ByteOp | ImplicitOps | String, ImplicitOps | String, /* 0xB0 - 0xBF */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + DstReg | SrcImm | Mov, 0, 0, 0, 0, 0, 0, 0, /* 0xC0 - 0xC7 */ ByteOp | DstMem | SrcImm | ModRM, DstMem | SrcImmByte | ModRM, 0, ImplicitOps | Stack, 0, 0, @@ -168,7 +171,8 @@ static u16 opcode_table[256] = { /* 0xE0 - 0xE7 */ 0, 0, 0, 0, 0, 0, 0, 0, /* 0xE8 - 0xEF */ - ImplicitOps | Stack, SrcImm|ImplicitOps, 0, SrcImmByte|ImplicitOps, + ImplicitOps | Stack, SrcImm | ImplicitOps, + ImplicitOps, SrcImmByte | ImplicitOps, 0, 0, 0, 0, /* 0xF0 - 0xF7 */ 0, 0, 0, 0, @@ -215,7 +219,7 @@ static u16 twobyte_table[256] = { /* 0xA0 - 0xA7 */ 0, 0, 0, DstMem | SrcReg | ModRM | BitOp, 0, 0, 0, 0, /* 0xA8 - 0xAF */ - 0, 0, 0, DstMem | SrcReg | ModRM | BitOp, 0, 0, 0, 0, + 0, 0, 0, DstMem | SrcReg | ModRM | BitOp, 0, 0, ModRM, 0, /* 0xB0 - 0xB7 */ ByteOp | DstMem | SrcReg | ModRM, DstMem | SrcReg | ModRM, 0, DstMem | SrcReg | ModRM | BitOp, @@ -518,6 +522,39 @@ static inline void jmp_rel(struct decode_cache *c, int rel) register_address_increment(c, &c->eip, rel); } +static void set_seg_override(struct decode_cache *c, int seg) +{ + c->has_seg_override = true; + c->seg_override = seg; +} + +static unsigned long seg_base(struct x86_emulate_ctxt *ctxt, int seg) +{ + if (ctxt->mode == X86EMUL_MODE_PROT64 && seg < VCPU_SREG_FS) + return 0; + + return kvm_x86_ops->get_segment_base(ctxt->vcpu, seg); +} + +static unsigned long seg_override_base(struct x86_emulate_ctxt *ctxt, + struct decode_cache *c) +{ + if (!c->has_seg_override) + return 0; + + return seg_base(ctxt, c->seg_override); +} + +static unsigned long es_base(struct x86_emulate_ctxt *ctxt) +{ + return seg_base(ctxt, VCPU_SREG_ES); +} + +static unsigned long ss_base(struct x86_emulate_ctxt *ctxt) +{ + return seg_base(ctxt, VCPU_SREG_SS); +} + static int do_fetch_insn_byte(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops, unsigned long linear, u8 *dest) @@ -660,7 +697,7 @@ static int decode_modrm(struct x86_emulate_ctxt *ctxt, { struct decode_cache *c = &ctxt->decode; u8 sib; - int index_reg = 0, base_reg = 0, scale, rip_relative = 0; + int index_reg = 0, base_reg = 0, scale; int rc = 0; if (c->rex_prefix) { @@ -731,47 +768,28 @@ static int decode_modrm(struct x86_emulate_ctxt *ctxt, } if (c->modrm_rm == 2 || c->modrm_rm == 3 || (c->modrm_rm == 6 && c->modrm_mod != 0)) - if (!c->override_base) - c->override_base = &ctxt->ss_base; + if (!c->has_seg_override) + set_seg_override(c, VCPU_SREG_SS); c->modrm_ea = (u16)c->modrm_ea; } else { /* 32/64-bit ModR/M decode. */ - switch (c->modrm_rm) { - case 4: - case 12: + if ((c->modrm_rm & 7) == 4) { sib = insn_fetch(u8, 1, c->eip); index_reg |= (sib >> 3) & 7; base_reg |= sib & 7; scale = sib >> 6; - switch (base_reg) { - case 5: - if (c->modrm_mod != 0) - c->modrm_ea += c->regs[base_reg]; - else - c->modrm_ea += - insn_fetch(s32, 4, c->eip); - break; - default: + if ((base_reg & 7) == 5 && c->modrm_mod == 0) + c->modrm_ea += insn_fetch(s32, 4, c->eip); + else c->modrm_ea += c->regs[base_reg]; - } - switch (index_reg) { - case 4: - break; - default: + if (index_reg != 4) c->modrm_ea += c->regs[index_reg] << scale; - } - break; - case 5: - if (c->modrm_mod != 0) - c->modrm_ea += c->regs[c->modrm_rm]; - else if (ctxt->mode == X86EMUL_MODE_PROT64) - rip_relative = 1; - break; - default: + } else if ((c->modrm_rm & 7) == 5 && c->modrm_mod == 0) { + if (ctxt->mode == X86EMUL_MODE_PROT64) + c->rip_relative = 1; + } else c->modrm_ea += c->regs[c->modrm_rm]; - break; - } switch (c->modrm_mod) { case 0: if (c->modrm_rm == 5) @@ -785,22 +803,6 @@ static int decode_modrm(struct x86_emulate_ctxt *ctxt, break; } } - if (rip_relative) { - c->modrm_ea += c->eip; - switch (c->d & SrcMask) { - case SrcImmByte: - c->modrm_ea += 1; - break; - case SrcImm: - if (c->d & ByteOp) - c->modrm_ea += 1; - else - if (c->op_bytes == 8) - c->modrm_ea += 4; - else - c->modrm_ea += c->op_bytes; - } - } done: return rc; } @@ -838,6 +840,7 @@ x86_decode_insn(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops) memset(c, 0, sizeof(struct decode_cache)); c->eip = ctxt->vcpu->arch.rip; + ctxt->cs_base = seg_base(ctxt, VCPU_SREG_CS); memcpy(c->regs, ctxt->vcpu->arch.regs, sizeof c->regs); switch (mode) { @@ -876,23 +879,15 @@ x86_decode_insn(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops) /* switch between 2/4 bytes */ c->ad_bytes = def_ad_bytes ^ 6; break; + case 0x26: /* ES override */ case 0x2e: /* CS override */ - c->override_base = &ctxt->cs_base; - break; + case 0x36: /* SS override */ case 0x3e: /* DS override */ - c->override_base = &ctxt->ds_base; - break; - case 0x26: /* ES override */ - c->override_base = &ctxt->es_base; + set_seg_override(c, (c->b >> 3) & 3); break; case 0x64: /* FS override */ - c->override_base = &ctxt->fs_base; - break; case 0x65: /* GS override */ - c->override_base = &ctxt->gs_base; - break; - case 0x36: /* SS override */ - c->override_base = &ctxt->ss_base; + set_seg_override(c, c->b & 7); break; case 0x40 ... 0x4f: /* REX */ if (mode != X86EMUL_MODE_PROT64) @@ -964,15 +959,11 @@ done_prefixes: if (rc) goto done; - if (!c->override_base) - c->override_base = &ctxt->ds_base; - if (mode == X86EMUL_MODE_PROT64 && - c->override_base != &ctxt->fs_base && - c->override_base != &ctxt->gs_base) - c->override_base = NULL; + if (!c->has_seg_override) + set_seg_override(c, VCPU_SREG_DS); - if (c->override_base) - c->modrm_ea += *c->override_base; + if (!(!c->twobyte && c->b == 0x8d)) + c->modrm_ea += seg_override_base(ctxt, c); if (c->ad_bytes != 8) c->modrm_ea = (u32)c->modrm_ea; @@ -1049,6 +1040,7 @@ done_prefixes: break; case DstMem: if ((c->d & ModRM) && c->modrm_mod == 3) { + c->dst.bytes = (c->d & ByteOp) ? 1 : c->op_bytes; c->dst.type = OP_REG; c->dst.val = c->dst.orig_val = c->modrm_val; c->dst.ptr = c->modrm_ptr; @@ -1058,6 +1050,9 @@ done_prefixes: break; } + if (c->rip_relative) + c->modrm_ea += c->eip; + done: return (rc == X86EMUL_UNHANDLEABLE) ? -1 : 0; } @@ -1070,7 +1065,7 @@ static inline void emulate_push(struct x86_emulate_ctxt *ctxt) c->dst.bytes = c->op_bytes; c->dst.val = c->src.val; register_address_increment(c, &c->regs[VCPU_REGS_RSP], -c->op_bytes); - c->dst.ptr = (void *) register_address(c, ctxt->ss_base, + c->dst.ptr = (void *) register_address(c, ss_base(ctxt), c->regs[VCPU_REGS_RSP]); } @@ -1080,7 +1075,7 @@ static inline int emulate_grp1a(struct x86_emulate_ctxt *ctxt, struct decode_cache *c = &ctxt->decode; int rc; - rc = ops->read_std(register_address(c, ctxt->ss_base, + rc = ops->read_std(register_address(c, ss_base(ctxt), c->regs[VCPU_REGS_RSP]), &c->dst.val, c->dst.bytes, ctxt->vcpu); if (rc != 0) @@ -1402,11 +1397,11 @@ special_insn: register_address_increment(c, &c->regs[VCPU_REGS_RSP], -c->op_bytes); c->dst.ptr = (void *) register_address( - c, ctxt->ss_base, c->regs[VCPU_REGS_RSP]); + c, ss_base(ctxt), c->regs[VCPU_REGS_RSP]); break; case 0x58 ... 0x5f: /* pop reg */ pop_instruction: - if ((rc = ops->read_std(register_address(c, ctxt->ss_base, + if ((rc = ops->read_std(register_address(c, ss_base(ctxt), c->regs[VCPU_REGS_RSP]), c->dst.ptr, c->op_bytes, ctxt->vcpu)) != 0) goto done; @@ -1420,9 +1415,8 @@ special_insn: goto cannot_emulate; c->dst.val = (s32) c->src.val; break; + case 0x68: /* push imm */ case 0x6a: /* push imm8 */ - c->src.val = 0L; - c->src.val = insn_fetch(s8, 1, c->eip); emulate_push(ctxt); break; case 0x6c: /* insb */ @@ -1433,7 +1427,7 @@ special_insn: c->rep_prefix ? address_mask(c, c->regs[VCPU_REGS_RCX]) : 1, (ctxt->eflags & EFLG_DF), - register_address(c, ctxt->es_base, + register_address(c, es_base(ctxt), c->regs[VCPU_REGS_RDI]), c->rep_prefix, c->regs[VCPU_REGS_RDX]) == 0) { @@ -1449,9 +1443,8 @@ special_insn: c->rep_prefix ? address_mask(c, c->regs[VCPU_REGS_RCX]) : 1, (ctxt->eflags & EFLG_DF), - register_address(c, c->override_base ? - *c->override_base : - ctxt->ds_base, + register_address(c, + seg_override_base(ctxt, c), c->regs[VCPU_REGS_RSI]), c->rep_prefix, c->regs[VCPU_REGS_RDX]) == 0) { @@ -1490,6 +1483,7 @@ special_insn: emulate_2op_SrcV("test", c->src, c->dst, ctxt->eflags); break; case 0x86 ... 0x87: /* xchg */ + xchg: /* Write back the register source. */ switch (c->dst.bytes) { case 1: @@ -1514,14 +1508,60 @@ special_insn: break; case 0x88 ... 0x8b: /* mov */ goto mov; + case 0x8c: { /* mov r/m, sreg */ + struct kvm_segment segreg; + + if (c->modrm_reg <= 5) + kvm_get_segment(ctxt->vcpu, &segreg, c->modrm_reg); + else { + printk(KERN_INFO "0x8c: Invalid segreg in modrm byte 0x%02x\n", + c->modrm); + goto cannot_emulate; + } + c->dst.val = segreg.selector; + break; + } case 0x8d: /* lea r16/r32, m */ c->dst.val = c->modrm_ea; break; + case 0x8e: { /* mov seg, r/m16 */ + uint16_t sel; + int type_bits; + int err; + + sel = c->src.val; + if (c->modrm_reg <= 5) { + type_bits = (c->modrm_reg == 1) ? 9 : 1; + err = kvm_load_segment_descriptor(ctxt->vcpu, sel, + type_bits, c->modrm_reg); + } else { + printk(KERN_INFO "Invalid segreg in modrm byte 0x%02x\n", + c->modrm); + goto cannot_emulate; + } + + if (err < 0) + goto cannot_emulate; + + c->dst.type = OP_NONE; /* Disable writeback. */ + break; + } case 0x8f: /* pop (sole member of Grp1a) */ rc = emulate_grp1a(ctxt, ops); if (rc != 0) goto done; break; + case 0x90: /* nop / xchg r8,rax */ + if (!(c->rex_prefix & 1)) { /* nop */ + c->dst.type = OP_NONE; + break; + } + case 0x91 ... 0x97: /* xchg reg,rax */ + c->src.type = c->dst.type = OP_REG; + c->src.bytes = c->dst.bytes = c->op_bytes; + c->src.ptr = (unsigned long *) &c->regs[VCPU_REGS_RAX]; + c->src.val = *(c->src.ptr); + goto xchg; case 0x9c: /* pushf */ c->src.val = (unsigned long) ctxt->eflags; emulate_push(ctxt); @@ -1540,11 +1580,10 @@ special_insn: c->dst.type = OP_MEM; c->dst.bytes = (c->d & ByteOp) ? 1 : c->op_bytes; c->dst.ptr = (unsigned long *)register_address(c, - ctxt->es_base, + es_base(ctxt), c->regs[VCPU_REGS_RDI]); if ((rc = ops->read_emulated(register_address(c, - c->override_base ? *c->override_base : - ctxt->ds_base, + seg_override_base(ctxt, c), c->regs[VCPU_REGS_RSI]), &c->dst.val, c->dst.bytes, ctxt->vcpu)) != 0) @@ -1560,8 +1599,7 @@ special_insn: c->src.type = OP_NONE; /* Disable writeback. */ c->src.bytes = (c->d & ByteOp) ? 1 : c->op_bytes; c->src.ptr = (unsigned long *)register_address(c, - c->override_base ? *c->override_base : - ctxt->ds_base, + seg_override_base(ctxt, c), c->regs[VCPU_REGS_RSI]); if ((rc = ops->read_emulated((unsigned long)c->src.ptr, &c->src.val, @@ -1572,7 +1610,7 @@ special_insn: c->dst.type = OP_NONE; /* Disable writeback. */ c->dst.bytes = (c->d & ByteOp) ? 1 : c->op_bytes; c->dst.ptr = (unsigned long *)register_address(c, - ctxt->es_base, + es_base(ctxt), c->regs[VCPU_REGS_RDI]); if ((rc = ops->read_emulated((unsigned long)c->dst.ptr, &c->dst.val, @@ -1596,7 +1634,7 @@ special_insn: c->dst.type = OP_MEM; c->dst.bytes = (c->d & ByteOp) ? 1 : c->op_bytes; c->dst.ptr = (unsigned long *)register_address(c, - ctxt->es_base, + es_base(ctxt), c->regs[VCPU_REGS_RDI]); c->dst.val = c->regs[VCPU_REGS_RAX]; register_address_increment(c, &c->regs[VCPU_REGS_RDI], @@ -1608,8 +1646,7 @@ special_insn: c->dst.bytes = (c->d & ByteOp) ? 1 : c->op_bytes; c->dst.ptr = (unsigned long *)&c->regs[VCPU_REGS_RAX]; if ((rc = ops->read_emulated(register_address(c, - c->override_base ? *c->override_base : - ctxt->ds_base, + seg_override_base(ctxt, c), c->regs[VCPU_REGS_RSI]), &c->dst.val, c->dst.bytes, @@ -1622,6 +1659,8 @@ special_insn: case 0xae ... 0xaf: /* scas */ DPRINTF("Urk! I don't handle SCAS.\n"); goto cannot_emulate; + case 0xb8: /* mov r, imm */ + goto mov; case 0xc0 ... 0xc1: emulate_grp2(ctxt); break; @@ -1660,13 +1699,39 @@ special_insn: break; } case 0xe9: /* jmp rel */ - case 0xeb: /* jmp rel short */ + goto jmp; + case 0xea: /* jmp far */ { + uint32_t eip; + uint16_t sel; + + switch (c->op_bytes) { + case 2: + eip = insn_fetch(u16, 2, c->eip); + break; + case 4: + eip = insn_fetch(u32, 4, c->eip); + break; + default: + DPRINTF("jmp far: Invalid op_bytes\n"); + goto cannot_emulate; + } + sel = insn_fetch(u16, 2, c->eip); + if (kvm_load_segment_descriptor(ctxt->vcpu, sel, 9, VCPU_SREG_CS) < 0) { + DPRINTF("jmp far: Failed to load CS descriptor\n"); + goto cannot_emulate; + } + + c->eip = eip; + break; + } + case 0xeb: + jmp: /* jmp rel short */ jmp_rel(c, c->src.val); c->dst.type = OP_NONE; /* Disable writeback. */ break; case 0xf4: /* hlt */ ctxt->vcpu->arch.halt_request = 1; - goto done; + break; case 0xf5: /* cmc */ /* complement carry flag from eflags reg */ ctxt->eflags ^= EFLG_CF; @@ -1882,6 +1947,8 @@ twobyte_insn: c->src.val &= (c->dst.bytes << 3) - 1; emulate_2op_SrcV_nobyte("bts", c->src, c->dst, ctxt->eflags); break; + case 0xae: /* clflush */ + break; case 0xb0 ... 0xb1: /* cmpxchg */ /* * Save real source value, then compare EAX against diff --git a/arch/x86/mach-default/setup.c b/arch/x86/mach-default/setup.c index 48278fa7d3de..3d317836be9e 100644 --- a/arch/x86/mach-default/setup.c +++ b/arch/x86/mach-default/setup.c @@ -10,14 +10,6 @@ #include <asm/e820.h> #include <asm/setup.h> -/* - * Any quirks to be performed to initialize timers/irqs/etc? - */ -int (*arch_time_init_quirk)(void); -int (*arch_pre_intr_init_quirk)(void); -int (*arch_intr_init_quirk)(void); -int (*arch_trap_init_quirk)(void); - #ifdef CONFIG_HOTPLUG_CPU #define DEFAULT_SEND_IPI (1) #else @@ -37,8 +29,8 @@ int no_broadcast=DEFAULT_SEND_IPI; **/ void __init pre_intr_init_hook(void) { - if (arch_pre_intr_init_quirk) { - if (arch_pre_intr_init_quirk()) + if (x86_quirks->arch_pre_intr_init) { + if (x86_quirks->arch_pre_intr_init()) return; } init_ISA_irqs(); @@ -64,8 +56,8 @@ static struct irqaction irq2 = { **/ void __init intr_init_hook(void) { - if (arch_intr_init_quirk) { - if (arch_intr_init_quirk()) + if (x86_quirks->arch_intr_init) { + if (x86_quirks->arch_intr_init()) return; } #ifdef CONFIG_X86_LOCAL_APIC @@ -97,8 +89,8 @@ void __init pre_setup_arch_hook(void) **/ void __init trap_init_hook(void) { - if (arch_trap_init_quirk) { - if (arch_trap_init_quirk()) + if (x86_quirks->arch_trap_init) { + if (x86_quirks->arch_trap_init()) return; } } @@ -111,6 +103,16 @@ static struct irqaction irq0 = { }; /** + * pre_time_init_hook - do any specific initialisations before. + * + **/ +void __init pre_time_init_hook(void) +{ + if (x86_quirks->arch_pre_time_init) + x86_quirks->arch_pre_time_init(); +} + +/** * time_init_hook - do any specific initialisations for the system timer. * * Description: @@ -119,13 +121,13 @@ static struct irqaction irq0 = { **/ void __init time_init_hook(void) { - if (arch_time_init_quirk) { + if (x86_quirks->arch_time_init) { /* * A nonzero return code does not mean failure, it means * that the architecture quirk does not want any * generic (timer) setup to be performed after this: */ - if (arch_time_init_quirk()) + if (x86_quirks->arch_time_init()) return; } diff --git a/arch/x86/mm/Makefile b/arch/x86/mm/Makefile index 9873716e9f76..1fbb844c3d7a 100644 --- a/arch/x86/mm/Makefile +++ b/arch/x86/mm/Makefile @@ -21,3 +21,4 @@ obj-$(CONFIG_K8_NUMA) += k8topology_64.o endif obj-$(CONFIG_ACPI_NUMA) += srat_$(BITS).o +obj-$(CONFIG_MEMTEST) += memtest.o diff --git a/arch/x86/mm/init_32.c b/arch/x86/mm/init_32.c index 9689a5138e64..d37f29376b0c 100644 --- a/arch/x86/mm/init_32.c +++ b/arch/x86/mm/init_32.c @@ -844,6 +844,9 @@ unsigned long __init_refok init_memory_mapping(unsigned long start, reserve_early(table_start << PAGE_SHIFT, table_end << PAGE_SHIFT, "PGTABLE"); + if (!after_init_bootmem) + early_memtest(start, end); + return end >> PAGE_SHIFT; } @@ -868,8 +871,6 @@ void __init paging_init(void) */ sparse_init(); zone_sizes_init(); - - paravirt_post_allocator_init(); } /* diff --git a/arch/x86/mm/init_64.c b/arch/x86/mm/init_64.c index 306049edd553..ec37121f6709 100644 --- a/arch/x86/mm/init_64.c +++ b/arch/x86/mm/init_64.c @@ -517,118 +517,6 @@ static void __init init_gbpages(void) direct_gbpages = 0; } -#ifdef CONFIG_MEMTEST - -static void __init memtest(unsigned long start_phys, unsigned long size, - unsigned pattern) -{ - unsigned long i; - unsigned long *start; - unsigned long start_bad; - unsigned long last_bad; - unsigned long val; - unsigned long start_phys_aligned; - unsigned long count; - unsigned long incr; - - switch (pattern) { - case 0: - val = 0UL; - break; - case 1: - val = -1UL; - break; - case 2: - val = 0x5555555555555555UL; - break; - case 3: - val = 0xaaaaaaaaaaaaaaaaUL; - break; - default: - return; - } - - incr = sizeof(unsigned long); - start_phys_aligned = ALIGN(start_phys, incr); - count = (size - (start_phys_aligned - start_phys))/incr; - start = __va(start_phys_aligned); - start_bad = 0; - last_bad = 0; - - for (i = 0; i < count; i++) - start[i] = val; - for (i = 0; i < count; i++, start++, start_phys_aligned += incr) { - if (*start != val) { - if (start_phys_aligned == last_bad + incr) { - last_bad += incr; - } else { - if (start_bad) { - printk(KERN_CONT "\n %016lx bad mem addr %016lx - %016lx reserved", - val, start_bad, last_bad + incr); - reserve_early(start_bad, last_bad - start_bad, "BAD RAM"); - } - start_bad = last_bad = start_phys_aligned; - } - } - } - if (start_bad) { - printk(KERN_CONT "\n %016lx bad mem addr %016lx - %016lx reserved", - val, start_bad, last_bad + incr); - reserve_early(start_bad, last_bad - start_bad, "BAD RAM"); - } - -} - -/* default is disabled */ -static int memtest_pattern __initdata; - -static int __init parse_memtest(char *arg) -{ - if (arg) - memtest_pattern = simple_strtoul(arg, NULL, 0); - return 0; -} - -early_param("memtest", parse_memtest); - -static void __init early_memtest(unsigned long start, unsigned long end) -{ - u64 t_start, t_size; - unsigned pattern; - - if (!memtest_pattern) - return; - - printk(KERN_INFO "early_memtest: pattern num %d", memtest_pattern); - for (pattern = 0; pattern < memtest_pattern; pattern++) { - t_start = start; - t_size = 0; - while (t_start < end) { - t_start = find_e820_area_size(t_start, &t_size, 1); - - /* done ? */ - if (t_start >= end) - break; - if (t_start + t_size > end) - t_size = end - t_start; - - printk(KERN_CONT "\n %016llx - %016llx pattern %d", - (unsigned long long)t_start, - (unsigned long long)t_start + t_size, pattern); - - memtest(t_start, t_size, pattern); - - t_start += t_size; - } - } - printk(KERN_CONT "\n"); -} -#else -static void __init early_memtest(unsigned long start, unsigned long end) -{ -} -#endif - static unsigned long __init kernel_physical_mapping_init(unsigned long start, unsigned long end, unsigned long page_size_mask) diff --git a/arch/x86/mm/memtest.c b/arch/x86/mm/memtest.c new file mode 100644 index 000000000000..672e17f8262a --- /dev/null +++ b/arch/x86/mm/memtest.c @@ -0,0 +1,123 @@ +#include <linux/kernel.h> +#include <linux/errno.h> +#include <linux/string.h> +#include <linux/types.h> +#include <linux/mm.h> +#include <linux/smp.h> +#include <linux/init.h> +#include <linux/pfn.h> + +#include <asm/e820.h> + +static void __init memtest(unsigned long start_phys, unsigned long size, + unsigned pattern) +{ + unsigned long i; + unsigned long *start; + unsigned long start_bad; + unsigned long last_bad; + unsigned long val; + unsigned long start_phys_aligned; + unsigned long count; + unsigned long incr; + + switch (pattern) { + case 0: + val = 0UL; + break; + case 1: + val = -1UL; + break; + case 2: +#ifdef CONFIG_X86_64 + val = 0x5555555555555555UL; +#else + val = 0x55555555UL; +#endif + break; + case 3: +#ifdef CONFIG_X86_64 + val = 0xaaaaaaaaaaaaaaaaUL; +#else + val = 0xaaaaaaaaUL; +#endif + break; + default: + return; + } + + incr = sizeof(unsigned long); + start_phys_aligned = ALIGN(start_phys, incr); + count = (size - (start_phys_aligned - start_phys))/incr; + start = __va(start_phys_aligned); + start_bad = 0; + last_bad = 0; + + for (i = 0; i < count; i++) + start[i] = val; + for (i = 0; i < count; i++, start++, start_phys_aligned += incr) { + if (*start != val) { + if (start_phys_aligned == last_bad + incr) { + last_bad += incr; + } else { + if (start_bad) { + printk(KERN_CONT "\n %010lx bad mem addr %010lx - %010lx reserved", + val, start_bad, last_bad + incr); + reserve_early(start_bad, last_bad - start_bad, "BAD RAM"); + } + start_bad = last_bad = start_phys_aligned; + } + } + } + if (start_bad) { + printk(KERN_CONT "\n %016lx bad mem addr %010lx - %010lx reserved", + val, start_bad, last_bad + incr); + reserve_early(start_bad, last_bad - start_bad, "BAD RAM"); + } + +} + +/* default is disabled */ +static int memtest_pattern __initdata; + +static int __init parse_memtest(char *arg) +{ + if (arg) + memtest_pattern = simple_strtoul(arg, NULL, 0); + return 0; +} + +early_param("memtest", parse_memtest); + +void __init early_memtest(unsigned long start, unsigned long end) +{ + u64 t_start, t_size; + unsigned pattern; + + if (!memtest_pattern) + return; + + printk(KERN_INFO "early_memtest: pattern num %d", memtest_pattern); + for (pattern = 0; pattern < memtest_pattern; pattern++) { + t_start = start; + t_size = 0; + while (t_start < end) { + t_start = find_e820_area_size(t_start, &t_size, 1); + + /* done ? */ + if (t_start >= end) + break; + if (t_start + t_size > end) + t_size = end - t_start; + + printk(KERN_CONT "\n %010llx - %010llx pattern %d", + (unsigned long long)t_start, + (unsigned long long)t_start + t_size, pattern); + + memtest(t_start, t_size, pattern); + + t_start += t_size; + } + } + printk(KERN_CONT "\n"); +} diff --git a/arch/x86/mm/pat.c b/arch/x86/mm/pat.c index d4585077977a..2fe30916d4b6 100644 --- a/arch/x86/mm/pat.c +++ b/arch/x86/mm/pat.c @@ -12,6 +12,8 @@ #include <linux/gfp.h> #include <linux/fs.h> #include <linux/bootmem.h> +#include <linux/debugfs.h> +#include <linux/seq_file.h> #include <asm/msr.h> #include <asm/tlbflush.h> @@ -373,8 +375,8 @@ pgprot_t phys_mem_access_prot(struct file *file, unsigned long pfn, return vma_prot; } -#ifdef CONFIG_NONPROMISC_DEVMEM -/* This check is done in drivers/char/mem.c in case of NONPROMISC_DEVMEM*/ +#ifdef CONFIG_STRICT_DEVMEM +/* This check is done in drivers/char/mem.c in case of STRICT_DEVMEM*/ static inline int range_is_allowed(unsigned long pfn, unsigned long size) { return 1; @@ -398,7 +400,7 @@ static inline int range_is_allowed(unsigned long pfn, unsigned long size) } return 1; } -#endif /* CONFIG_NONPROMISC_DEVMEM */ +#endif /* CONFIG_STRICT_DEVMEM */ int phys_mem_access_prot_allowed(struct file *file, unsigned long pfn, unsigned long size, pgprot_t *vma_prot) @@ -489,3 +491,89 @@ void unmap_devmem(unsigned long pfn, unsigned long size, pgprot_t vma_prot) free_memtype(addr, addr + size); } + +#if defined(CONFIG_DEBUG_FS) + +/* get Nth element of the linked list */ +static struct memtype *memtype_get_idx(loff_t pos) +{ + struct memtype *list_node, *print_entry; + int i = 1; + + print_entry = kmalloc(sizeof(struct memtype), GFP_KERNEL); + if (!print_entry) + return NULL; + + spin_lock(&memtype_lock); + list_for_each_entry(list_node, &memtype_list, nd) { + if (pos == i) { + *print_entry = *list_node; + spin_unlock(&memtype_lock); + return print_entry; + } + ++i; + } + spin_unlock(&memtype_lock); + kfree(print_entry); + return NULL; +} + +static void *memtype_seq_start(struct seq_file *seq, loff_t *pos) +{ + if (*pos == 0) { + ++*pos; + seq_printf(seq, "PAT memtype list:\n"); + } + + return memtype_get_idx(*pos); +} + +static void *memtype_seq_next(struct seq_file *seq, void *v, loff_t *pos) +{ + ++*pos; + return memtype_get_idx(*pos); +} + +static void memtype_seq_stop(struct seq_file *seq, void *v) +{ +} + +static int memtype_seq_show(struct seq_file *seq, void *v) +{ + struct memtype *print_entry = (struct memtype *)v; + + seq_printf(seq, "%s @ 0x%Lx-0x%Lx\n", cattr_name(print_entry->type), + print_entry->start, print_entry->end); + kfree(print_entry); + return 0; +} + +static struct seq_operations memtype_seq_ops = { + .start = memtype_seq_start, + .next = memtype_seq_next, + .stop = memtype_seq_stop, + .show = memtype_seq_show, +}; + +static int memtype_seq_open(struct inode *inode, struct file *file) +{ + return seq_open(file, &memtype_seq_ops); +} + +static const struct file_operations memtype_fops = { + .open = memtype_seq_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release, +}; + +static int __init pat_memtype_list_init(void) +{ + debugfs_create_file("pat_memtype_list", S_IRUSR, arch_debugfs_dir, + NULL, &memtype_fops); + return 0; +} + +late_initcall(pat_memtype_list_init); + +#endif /* CONFIG_DEBUG_FS */ diff --git a/arch/x86/pci/Makefile b/arch/x86/pci/Makefile index e515e8db842a..d49202e740ea 100644 --- a/arch/x86/pci/Makefile +++ b/arch/x86/pci/Makefile @@ -5,13 +5,13 @@ obj-$(CONFIG_PCI_MMCONFIG) += mmconfig_$(BITS).o direct.o mmconfig-shared.o obj-$(CONFIG_PCI_DIRECT) += direct.o obj-$(CONFIG_PCI_OLPC) += olpc.o -pci-y := fixup.o -pci-$(CONFIG_ACPI) += acpi.o -pci-y += legacy.o irq.o +obj-y += fixup.o +obj-$(CONFIG_ACPI) += acpi.o +obj-y += legacy.o irq.o -pci-$(CONFIG_X86_VISWS) += visws.o +obj-$(CONFIG_X86_VISWS) += visws.o -pci-$(CONFIG_X86_NUMAQ) += numa.o +obj-$(CONFIG_X86_NUMAQ) += numaq_32.o -obj-y += $(pci-y) common.o early.o +obj-y += common.o early.o obj-y += amd_bus.o diff --git a/arch/x86/pci/legacy.c b/arch/x86/pci/legacy.c index 132876cc6fca..ec9ce35e44d6 100644 --- a/arch/x86/pci/legacy.c +++ b/arch/x86/pci/legacy.c @@ -57,14 +57,17 @@ static int __init pci_legacy_init(void) int __init pci_subsys_init(void) { +#ifdef CONFIG_X86_NUMAQ + pci_numaq_init(); +#endif #ifdef CONFIG_ACPI pci_acpi_init(); #endif +#ifdef CONFIG_X86_VISWS + pci_visws_init(); +#endif pci_legacy_init(); pcibios_irq_init(); -#ifdef CONFIG_X86_NUMAQ - pci_numa_init(); -#endif pcibios_init(); return 0; diff --git a/arch/x86/pci/numa.c b/arch/x86/pci/numaq_32.c index 8b5ca1966731..f4b16dc11dad 100644 --- a/arch/x86/pci/numa.c +++ b/arch/x86/pci/numaq_32.c @@ -1,5 +1,5 @@ /* - * numa.c - Low-level PCI access for NUMA-Q machines + * numaq_32.c - Low-level PCI access for NUMA-Q machines */ #include <linux/pci.h> @@ -151,7 +151,7 @@ static void __devinit pci_fixup_i450nx(struct pci_dev *d) } DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82451NX, pci_fixup_i450nx); -int __init pci_numa_init(void) +int __init pci_numaq_init(void) { int quad; diff --git a/arch/x86/pci/pci.h b/arch/x86/pci/pci.h index 3e25deb821ac..15b9cf6be729 100644 --- a/arch/x86/pci/pci.h +++ b/arch/x86/pci/pci.h @@ -108,7 +108,8 @@ extern void __init dmi_check_skip_isa_align(void); /* some common used subsys_initcalls */ extern int __init pci_acpi_init(void); extern int __init pcibios_irq_init(void); -extern int __init pci_numa_init(void); +extern int __init pci_visws_init(void); +extern int __init pci_numaq_init(void); extern int __init pcibios_init(void); /* pci-mmconfig.c */ diff --git a/arch/x86/pci/visws.c b/arch/x86/pci/visws.c index 1a7bed492bb1..42f4cb19faca 100644 --- a/arch/x86/pci/visws.c +++ b/arch/x86/pci/visws.c @@ -86,8 +86,14 @@ void __init pcibios_update_irq(struct pci_dev *dev, int irq) pci_write_config_byte(dev, PCI_INTERRUPT_LINE, irq); } -static int __init pci_visws_init(void) +int __init pci_visws_init(void) { + if (!is_visws_box()) + return -1; + + pcibios_enable_irq = &pci_visws_enable_irq; + pcibios_disable_irq = &pci_visws_disable_irq; + /* The VISWS supports configuration access type 1 only */ pci_probe = (pci_probe | PCI_PROBE_CONF1) & ~(PCI_PROBE_BIOS | PCI_PROBE_CONF2); @@ -105,18 +111,3 @@ static int __init pci_visws_init(void) pcibios_resource_survey(); return 0; } - -static __init int pci_subsys_init(void) -{ - if (!is_visws_box()) - return -1; - - pcibios_enable_irq = &pci_visws_enable_irq; - pcibios_disable_irq = &pci_visws_disable_irq; - - pci_visws_init(); - pcibios_init(); - - return 0; -} -subsys_initcall(pci_subsys_init); diff --git a/arch/x86/vdso/Makefile b/arch/x86/vdso/Makefile index b7ad9f89d21f..4d6ef0a336d6 100644 --- a/arch/x86/vdso/Makefile +++ b/arch/x86/vdso/Makefile @@ -62,7 +62,7 @@ $(obj)/%-syms.lds: $(obj)/%.so.dbg FORCE # Build multiple 32-bit vDSO images to choose from at boot time. # obj-$(VDSO32-y) += vdso32-syms.lds -vdso32.so-$(CONFIG_X86_32) += int80 +vdso32.so-$(VDSO32-y) += int80 vdso32.so-$(CONFIG_COMPAT) += syscall vdso32.so-$(VDSO32-y) += sysenter diff --git a/arch/x86/vdso/vdso32-setup.c b/arch/x86/vdso/vdso32-setup.c index 0bce5429a515..513f330c5832 100644 --- a/arch/x86/vdso/vdso32-setup.c +++ b/arch/x86/vdso/vdso32-setup.c @@ -193,17 +193,12 @@ static __init void relocate_vdso(Elf32_Ehdr *ehdr) } } -/* - * These symbols are defined by vdso32.S to mark the bounds - * of the ELF DSO images included therein. - */ -extern const char vdso32_default_start, vdso32_default_end; -extern const char vdso32_sysenter_start, vdso32_sysenter_end; static struct page *vdso32_pages[1]; #ifdef CONFIG_X86_64 #define vdso32_sysenter() (boot_cpu_has(X86_FEATURE_SYSENTER32)) +#define vdso32_syscall() (boot_cpu_has(X86_FEATURE_SYSCALL32)) /* May not be __init: called during resume */ void syscall32_cpu_init(void) @@ -226,6 +221,7 @@ static inline void map_compat_vdso(int map) #else /* CONFIG_X86_32 */ #define vdso32_sysenter() (boot_cpu_has(X86_FEATURE_SEP)) +#define vdso32_syscall() (0) void enable_sep_cpu(void) { @@ -296,12 +292,15 @@ int __init sysenter_setup(void) gate_vma_init(); #endif - if (!vdso32_sysenter()) { - vsyscall = &vdso32_default_start; - vsyscall_len = &vdso32_default_end - &vdso32_default_start; - } else { + if (vdso32_syscall()) { + vsyscall = &vdso32_syscall_start; + vsyscall_len = &vdso32_syscall_end - &vdso32_syscall_start; + } else if (vdso32_sysenter()){ vsyscall = &vdso32_sysenter_start; vsyscall_len = &vdso32_sysenter_end - &vdso32_sysenter_start; + } else { + vsyscall = &vdso32_int80_start; + vsyscall_len = &vdso32_int80_end - &vdso32_int80_start; } memcpy(syscall_page, vsyscall, vsyscall_len); diff --git a/arch/x86/vdso/vdso32.S b/arch/x86/vdso/vdso32.S index 1e36f72cab86..2ce5f82c333b 100644 --- a/arch/x86/vdso/vdso32.S +++ b/arch/x86/vdso/vdso32.S @@ -2,14 +2,17 @@ __INITDATA - .globl vdso32_default_start, vdso32_default_end -vdso32_default_start: -#ifdef CONFIG_X86_32 + .globl vdso32_int80_start, vdso32_int80_end +vdso32_int80_start: .incbin "arch/x86/vdso/vdso32-int80.so" -#else +vdso32_int80_end: + + .globl vdso32_syscall_start, vdso32_syscall_end +vdso32_syscall_start: +#ifdef CONFIG_COMPAT .incbin "arch/x86/vdso/vdso32-syscall.so" #endif -vdso32_default_end: +vdso32_syscall_end: .globl vdso32_sysenter_start, vdso32_sysenter_end vdso32_sysenter_start: diff --git a/arch/x86/vdso/vma.c b/arch/x86/vdso/vma.c index 19a6cfaf5db9..257ba4a10abf 100644 --- a/arch/x86/vdso/vma.c +++ b/arch/x86/vdso/vma.c @@ -21,7 +21,8 @@ unsigned int __read_mostly vdso_enabled = 1; extern char vdso_start[], vdso_end[]; extern unsigned short vdso_sync_cpuid; -struct page **vdso_pages; +static struct page **vdso_pages; +static unsigned vdso_size; static inline void *var_ref(void *p, char *name) { @@ -38,6 +39,7 @@ static int __init init_vdso_vars(void) int i; char *vbase; + vdso_size = npages << PAGE_SHIFT; vdso_pages = kmalloc(sizeof(struct page *) * npages, GFP_KERNEL); if (!vdso_pages) goto oom; @@ -101,20 +103,19 @@ int arch_setup_additional_pages(struct linux_binprm *bprm, int exstack) struct mm_struct *mm = current->mm; unsigned long addr; int ret; - unsigned len = round_up(vdso_end - vdso_start, PAGE_SIZE); if (!vdso_enabled) return 0; down_write(&mm->mmap_sem); - addr = vdso_addr(mm->start_stack, len); - addr = get_unmapped_area(NULL, addr, len, 0, 0); + addr = vdso_addr(mm->start_stack, vdso_size); + addr = get_unmapped_area(NULL, addr, vdso_size, 0, 0); if (IS_ERR_VALUE(addr)) { ret = addr; goto up_fail; } - ret = install_special_mapping(mm, addr, len, + ret = install_special_mapping(mm, addr, vdso_size, VM_READ|VM_EXEC| VM_MAYREAD|VM_MAYWRITE|VM_MAYEXEC| VM_ALWAYSDUMP, diff --git a/arch/x86/xen/Kconfig b/arch/x86/xen/Kconfig index c2cc99580871..3815e425f470 100644 --- a/arch/x86/xen/Kconfig +++ b/arch/x86/xen/Kconfig @@ -6,8 +6,8 @@ config XEN bool "Xen guest support" select PARAVIRT select PARAVIRT_CLOCK - depends on X86_32 - depends on X86_CMPXCHG && X86_TSC && X86_PAE && !(X86_VISWS || X86_VOYAGER) + depends on X86_64 || (X86_32 && X86_PAE && !(X86_VISWS || X86_VOYAGER)) + depends on X86_CMPXCHG && X86_TSC help This is the Linux Xen port. Enabling this will allow the kernel to boot in a paravirtualized environment under the @@ -15,10 +15,16 @@ config XEN config XEN_MAX_DOMAIN_MEMORY int "Maximum allowed size of a domain in gigabytes" - default 8 + default 8 if X86_32 + default 32 if X86_64 depends on XEN help The pseudo-physical to machine address array is sized according to the maximum possible memory size of a Xen domain. This array uses 1 page per gigabyte, so there's no - need to be too stingy here.
\ No newline at end of file + need to be too stingy here. + +config XEN_SAVE_RESTORE + bool + depends on PM + default y
\ No newline at end of file diff --git a/arch/x86/xen/Makefile b/arch/x86/xen/Makefile index 2ba2d1649131..59c1e539aed2 100644 --- a/arch/x86/xen/Makefile +++ b/arch/x86/xen/Makefile @@ -1,4 +1,4 @@ obj-y := enlighten.o setup.o multicalls.o mmu.o \ - time.o xen-asm.o grant-table.o suspend.o + time.o xen-asm_$(BITS).o grant-table.o suspend.o obj-$(CONFIG_SMP) += smp.o diff --git a/arch/x86/xen/enlighten.c b/arch/x86/xen/enlighten.c index 7f26c3718777..194bbd6e3241 100644 --- a/arch/x86/xen/enlighten.c +++ b/arch/x86/xen/enlighten.c @@ -33,6 +33,7 @@ #include <xen/interface/sched.h> #include <xen/features.h> #include <xen/page.h> +#include <xen/hvc-console.h> #include <asm/paravirt.h> #include <asm/page.h> @@ -40,12 +41,12 @@ #include <asm/xen/hypervisor.h> #include <asm/fixmap.h> #include <asm/processor.h> +#include <asm/msr-index.h> #include <asm/setup.h> #include <asm/desc.h> #include <asm/pgtable.h> #include <asm/tlbflush.h> #include <asm/reboot.h> -#include <asm/pgalloc.h> #include "xen-ops.h" #include "mmu.h" @@ -57,6 +58,18 @@ DEFINE_PER_CPU(struct vcpu_info *, xen_vcpu); DEFINE_PER_CPU(struct vcpu_info, xen_vcpu_info); /* + * Identity map, in addition to plain kernel map. This needs to be + * large enough to allocate page table pages to allocate the rest. + * Each page can map 2MB. + */ +static pte_t level1_ident_pgt[PTRS_PER_PTE * 4] __page_aligned_bss; + +#ifdef CONFIG_X86_64 +/* l3 pud for userspace vsyscall mapping */ +static pud_t level3_user_vsyscall[PTRS_PER_PUD] __page_aligned_bss; +#endif /* CONFIG_X86_64 */ + +/* * Note about cr3 (pagetable base) values: * * xen_cr3 contains the current logical cr3 value; it contains the @@ -167,10 +180,14 @@ void xen_vcpu_restore(void) static void __init xen_banner(void) { + unsigned version = HYPERVISOR_xen_version(XENVER_version, NULL); + struct xen_extraversion extra; + HYPERVISOR_xen_version(XENVER_extraversion, &extra); + printk(KERN_INFO "Booting paravirtualized kernel on %s\n", pv_info.name); - printk(KERN_INFO "Hypervisor signature: %s%s\n", - xen_start_info->magic, + printk(KERN_INFO "Xen version: %d.%d%s%s\n", + version >> 16, version & 0xffff, extra.extraversion, xen_feature(XENFEAT_mmu_pt_update_preserve_ad) ? " (preserve-AD)" : ""); } @@ -363,14 +380,6 @@ static void load_TLS_descriptor(struct thread_struct *t, static void xen_load_tls(struct thread_struct *t, unsigned int cpu) { - xen_mc_batch(); - - load_TLS_descriptor(t, cpu, 0); - load_TLS_descriptor(t, cpu, 1); - load_TLS_descriptor(t, cpu, 2); - - xen_mc_issue(PARAVIRT_LAZY_CPU); - /* * XXX sleazy hack: If we're being called in a lazy-cpu zone, * it means we're in a context switch, and %gs has just been @@ -379,10 +388,39 @@ static void xen_load_tls(struct thread_struct *t, unsigned int cpu) * Either way, it has been saved, and the new value will get * loaded properly. This will go away as soon as Xen has been * modified to not save/restore %gs for normal hypercalls. + * + * On x86_64, this hack is not used for %gs, because gs points + * to KERNEL_GS_BASE (and uses it for PDA references), so we + * must not zero %gs on x86_64 + * + * For x86_64, we need to zero %fs, otherwise we may get an + * exception between the new %fs descriptor being loaded and + * %fs being effectively cleared at __switch_to(). */ - if (paravirt_get_lazy_mode() == PARAVIRT_LAZY_CPU) + if (paravirt_get_lazy_mode() == PARAVIRT_LAZY_CPU) { +#ifdef CONFIG_X86_32 loadsegment(gs, 0); +#else + loadsegment(fs, 0); +#endif + } + + xen_mc_batch(); + + load_TLS_descriptor(t, cpu, 0); + load_TLS_descriptor(t, cpu, 1); + load_TLS_descriptor(t, cpu, 2); + + xen_mc_issue(PARAVIRT_LAZY_CPU); +} + +#ifdef CONFIG_X86_64 +static void xen_load_gs_index(unsigned int idx) +{ + if (HYPERVISOR_set_segment_base(SEGBASE_GS_USER_SEL, idx)) + BUG(); } +#endif static void xen_write_ldt_entry(struct desc_struct *dt, int entrynum, const void *ptr) @@ -400,23 +438,18 @@ static void xen_write_ldt_entry(struct desc_struct *dt, int entrynum, preempt_enable(); } -static int cvt_gate_to_trap(int vector, u32 low, u32 high, +static int cvt_gate_to_trap(int vector, const gate_desc *val, struct trap_info *info) { - u8 type, dpl; - - type = (high >> 8) & 0x1f; - dpl = (high >> 13) & 3; - - if (type != 0xf && type != 0xe) + if (val->type != 0xf && val->type != 0xe) return 0; info->vector = vector; - info->address = (high & 0xffff0000) | (low & 0x0000ffff); - info->cs = low >> 16; - info->flags = dpl; + info->address = gate_offset(*val); + info->cs = gate_segment(*val); + info->flags = val->dpl; /* interrupt gates clear IF */ - if (type == 0xe) + if (val->type == 0xe) info->flags |= 4; return 1; @@ -443,11 +476,10 @@ static void xen_write_idt_entry(gate_desc *dt, int entrynum, const gate_desc *g) if (p >= start && (p + 8) <= end) { struct trap_info info[2]; - u32 *desc = (u32 *)g; info[1].address = 0; - if (cvt_gate_to_trap(entrynum, desc[0], desc[1], &info[0])) + if (cvt_gate_to_trap(entrynum, g, &info[0])) if (HYPERVISOR_set_trap_table(info)) BUG(); } @@ -460,13 +492,13 @@ static void xen_convert_trap_info(const struct desc_ptr *desc, { unsigned in, out, count; - count = (desc->size+1) / 8; + count = (desc->size+1) / sizeof(gate_desc); BUG_ON(count > 256); for (in = out = 0; in < count; in++) { - const u32 *entry = (u32 *)(desc->address + in * 8); + gate_desc *entry = (gate_desc*)(desc->address) + in; - if (cvt_gate_to_trap(in, entry[0], entry[1], &traps[out])) + if (cvt_gate_to_trap(in, entry, &traps[out])) out++; } traps[out].address = 0; @@ -695,33 +727,89 @@ static void set_current_cr3(void *v) x86_write_percpu(xen_current_cr3, (unsigned long)v); } -static void xen_write_cr3(unsigned long cr3) +static void __xen_write_cr3(bool kernel, unsigned long cr3) { struct mmuext_op *op; struct multicall_space mcs; - unsigned long mfn = pfn_to_mfn(PFN_DOWN(cr3)); + unsigned long mfn; - BUG_ON(preemptible()); + if (cr3) + mfn = pfn_to_mfn(PFN_DOWN(cr3)); + else + mfn = 0; - mcs = xen_mc_entry(sizeof(*op)); /* disables interrupts */ + WARN_ON(mfn == 0 && kernel); - /* Update while interrupts are disabled, so its atomic with - respect to ipis */ - x86_write_percpu(xen_cr3, cr3); + mcs = __xen_mc_entry(sizeof(*op)); op = mcs.args; - op->cmd = MMUEXT_NEW_BASEPTR; + op->cmd = kernel ? MMUEXT_NEW_BASEPTR : MMUEXT_NEW_USER_BASEPTR; op->arg1.mfn = mfn; MULTI_mmuext_op(mcs.mc, op, 1, NULL, DOMID_SELF); - /* Update xen_update_cr3 once the batch has actually - been submitted. */ - xen_mc_callback(set_current_cr3, (void *)cr3); + if (kernel) { + x86_write_percpu(xen_cr3, cr3); + + /* Update xen_current_cr3 once the batch has actually + been submitted. */ + xen_mc_callback(set_current_cr3, (void *)cr3); + } +} + +static void xen_write_cr3(unsigned long cr3) +{ + BUG_ON(preemptible()); + + xen_mc_batch(); /* disables interrupts */ + + /* Update while interrupts are disabled, so its atomic with + respect to ipis */ + x86_write_percpu(xen_cr3, cr3); + + __xen_write_cr3(true, cr3); + +#ifdef CONFIG_X86_64 + { + pgd_t *user_pgd = xen_get_user_pgd(__va(cr3)); + if (user_pgd) + __xen_write_cr3(false, __pa(user_pgd)); + else + __xen_write_cr3(false, 0); + } +#endif xen_mc_issue(PARAVIRT_LAZY_CPU); /* interrupts restored */ } +static int xen_write_msr_safe(unsigned int msr, unsigned low, unsigned high) +{ + int ret; + + ret = 0; + + switch(msr) { +#ifdef CONFIG_X86_64 + unsigned which; + u64 base; + + case MSR_FS_BASE: which = SEGBASE_FS; goto set; + case MSR_KERNEL_GS_BASE: which = SEGBASE_GS_USER; goto set; + case MSR_GS_BASE: which = SEGBASE_GS_KERNEL; goto set; + + set: + base = ((u64)high << 32) | low; + if (HYPERVISOR_set_segment_base(which, base) != 0) + ret = -EFAULT; + break; +#endif + default: + ret = native_write_msr_safe(msr, low, high); + } + + return ret; +} + /* Early in boot, while setting up the initial pagetable, assume everything is pinned. */ static __init void xen_alloc_pte_init(struct mm_struct *mm, u32 pfn) @@ -778,6 +866,48 @@ static void xen_alloc_pmd(struct mm_struct *mm, u32 pfn) xen_alloc_ptpage(mm, pfn, PT_PMD); } +static int xen_pgd_alloc(struct mm_struct *mm) +{ + pgd_t *pgd = mm->pgd; + int ret = 0; + + BUG_ON(PagePinned(virt_to_page(pgd))); + +#ifdef CONFIG_X86_64 + { + struct page *page = virt_to_page(pgd); + pgd_t *user_pgd; + + BUG_ON(page->private != 0); + + ret = -ENOMEM; + + user_pgd = (pgd_t *)__get_free_page(GFP_KERNEL | __GFP_ZERO); + page->private = (unsigned long)user_pgd; + + if (user_pgd != NULL) { + user_pgd[pgd_index(VSYSCALL_START)] = + __pgd(__pa(level3_user_vsyscall) | _PAGE_TABLE); + ret = 0; + } + + BUG_ON(PagePinned(virt_to_page(xen_get_user_pgd(pgd)))); + } +#endif + + return ret; +} + +static void xen_pgd_free(struct mm_struct *mm, pgd_t *pgd) +{ +#ifdef CONFIG_X86_64 + pgd_t *user_pgd = xen_get_user_pgd(pgd); + + if (user_pgd) + free_page((unsigned long)user_pgd); +#endif +} + /* This should never happen until we're OK to use struct page */ static void xen_release_ptpage(u32 pfn, unsigned level) { @@ -803,6 +933,18 @@ static void xen_release_pmd(u32 pfn) xen_release_ptpage(pfn, PT_PMD); } +#if PAGETABLE_LEVELS == 4 +static void xen_alloc_pud(struct mm_struct *mm, u32 pfn) +{ + xen_alloc_ptpage(mm, pfn, PT_PUD); +} + +static void xen_release_pud(u32 pfn) +{ + xen_release_ptpage(pfn, PT_PUD); +} +#endif + #ifdef CONFIG_HIGHPTE static void *xen_kmap_atomic_pte(struct page *page, enum km_type type) { @@ -841,68 +983,16 @@ static __init void xen_set_pte_init(pte_t *ptep, pte_t pte) static __init void xen_pagetable_setup_start(pgd_t *base) { - pgd_t *xen_pgd = (pgd_t *)xen_start_info->pt_base; - int i; - - /* special set_pte for pagetable initialization */ - pv_mmu_ops.set_pte = xen_set_pte_init; - - init_mm.pgd = base; - /* - * copy top-level of Xen-supplied pagetable into place. This - * is a stand-in while we copy the pmd pages. - */ - memcpy(base, xen_pgd, PTRS_PER_PGD * sizeof(pgd_t)); - - /* - * For PAE, need to allocate new pmds, rather than - * share Xen's, since Xen doesn't like pmd's being - * shared between address spaces. - */ - for (i = 0; i < PTRS_PER_PGD; i++) { - if (pgd_val_ma(xen_pgd[i]) & _PAGE_PRESENT) { - pmd_t *pmd = (pmd_t *)alloc_bootmem_low_pages(PAGE_SIZE); - - memcpy(pmd, (void *)pgd_page_vaddr(xen_pgd[i]), - PAGE_SIZE); - - make_lowmem_page_readonly(pmd); - - set_pgd(&base[i], __pgd(1 + __pa(pmd))); - } else - pgd_clear(&base[i]); - } - - /* make sure zero_page is mapped RO so we can use it in pagetables */ - make_lowmem_page_readonly(empty_zero_page); - make_lowmem_page_readonly(base); - /* - * Switch to new pagetable. This is done before - * pagetable_init has done anything so that the new pages - * added to the table can be prepared properly for Xen. - */ - xen_write_cr3(__pa(base)); - - /* Unpin initial Xen pagetable */ - pin_pagetable_pfn(MMUEXT_UNPIN_TABLE, - PFN_DOWN(__pa(xen_start_info->pt_base))); } void xen_setup_shared_info(void) { if (!xen_feature(XENFEAT_auto_translated_physmap)) { - unsigned long addr = fix_to_virt(FIX_PARAVIRT_BOOTMAP); - - /* - * Create a mapping for the shared info page. - * Should be set_fixmap(), but shared_info is a machine - * address with no corresponding pseudo-phys address. - */ - set_pte_mfn(addr, - PFN_DOWN(xen_start_info->shared_info), - PAGE_KERNEL); - - HYPERVISOR_shared_info = (struct shared_info *)addr; + set_fixmap(FIX_PARAVIRT_BOOTMAP, + xen_start_info->shared_info); + + HYPERVISOR_shared_info = + (struct shared_info *)fix_to_virt(FIX_PARAVIRT_BOOTMAP); } else HYPERVISOR_shared_info = (struct shared_info *)__va(xen_start_info->shared_info); @@ -917,26 +1007,32 @@ void xen_setup_shared_info(void) static __init void xen_pagetable_setup_done(pgd_t *base) { - /* This will work as long as patching hasn't happened yet - (which it hasn't) */ - pv_mmu_ops.alloc_pte = xen_alloc_pte; - pv_mmu_ops.alloc_pmd = xen_alloc_pmd; - pv_mmu_ops.release_pte = xen_release_pte; - pv_mmu_ops.release_pmd = xen_release_pmd; - pv_mmu_ops.set_pte = xen_set_pte; - xen_setup_shared_info(); - - /* Actually pin the pagetable down, but we can't set PG_pinned - yet because the page structures don't exist yet. */ - pin_pagetable_pfn(MMUEXT_PIN_L3_TABLE, PFN_DOWN(__pa(base))); } static __init void xen_post_allocator_init(void) { + pv_mmu_ops.set_pte = xen_set_pte; pv_mmu_ops.set_pmd = xen_set_pmd; pv_mmu_ops.set_pud = xen_set_pud; +#if PAGETABLE_LEVELS == 4 + pv_mmu_ops.set_pgd = xen_set_pgd; +#endif + + /* This will work as long as patching hasn't happened yet + (which it hasn't) */ + pv_mmu_ops.alloc_pte = xen_alloc_pte; + pv_mmu_ops.alloc_pmd = xen_alloc_pmd; + pv_mmu_ops.release_pte = xen_release_pte; + pv_mmu_ops.release_pmd = xen_release_pmd; +#if PAGETABLE_LEVELS == 4 + pv_mmu_ops.alloc_pud = xen_alloc_pud; + pv_mmu_ops.release_pud = xen_release_pud; +#endif +#ifdef CONFIG_X86_64 + SetPagePinned(virt_to_page(level3_user_vsyscall)); +#endif xen_mark_init_mm_pinned(); } @@ -950,6 +1046,7 @@ void xen_setup_vcpu_info_placement(void) /* xen_vcpu_setup managed to place the vcpu_info within the percpu area for all cpus, so make use of it */ +#ifdef CONFIG_X86_32 if (have_vcpu_info_placement) { printk(KERN_INFO "Xen: using vcpu_info placement\n"); @@ -959,6 +1056,7 @@ void xen_setup_vcpu_info_placement(void) pv_irq_ops.irq_enable = xen_irq_enable_direct; pv_mmu_ops.read_cr2 = xen_read_cr2_direct; } +#endif } static unsigned xen_patch(u8 type, u16 clobbers, void *insnbuf, @@ -979,10 +1077,12 @@ static unsigned xen_patch(u8 type, u16 clobbers, void *insnbuf, goto patch_site switch (type) { +#ifdef CONFIG_X86_32 SITE(pv_irq_ops, irq_enable); SITE(pv_irq_ops, irq_disable); SITE(pv_irq_ops, save_fl); SITE(pv_irq_ops, restore_fl); +#endif /* CONFIG_X86_32 */ #undef SITE patch_site: @@ -1025,8 +1125,15 @@ static void xen_set_fixmap(unsigned idx, unsigned long phys, pgprot_t prot) #ifdef CONFIG_X86_F00F_BUG case FIX_F00F_IDT: #endif +#ifdef CONFIG_X86_32 case FIX_WP_TEST: case FIX_VDSO: +# ifdef CONFIG_HIGHMEM + case FIX_KMAP_BEGIN ... FIX_KMAP_END: +# endif +#else + case VSYSCALL_LAST_PAGE ... VSYSCALL_FIRST_PAGE: +#endif #ifdef CONFIG_X86_LOCAL_APIC case FIX_APIC_BASE: /* maps dummy local APIC */ #endif @@ -1039,6 +1146,15 @@ static void xen_set_fixmap(unsigned idx, unsigned long phys, pgprot_t prot) } __native_set_fixmap(idx, pte); + +#ifdef CONFIG_X86_64 + /* Replicate changes to map the vsyscall page into the user + pagetable vsyscall mapping. */ + if (idx >= VSYSCALL_LAST_PAGE && idx <= VSYSCALL_FIRST_PAGE) { + unsigned long vaddr = __fix_to_virt(idx); + set_pte_vaddr_pud(level3_user_vsyscall, vaddr, pte); + } +#endif } static const struct pv_info xen_info __initdata = { @@ -1084,18 +1200,25 @@ static const struct pv_cpu_ops xen_cpu_ops __initdata = { .wbinvd = native_wbinvd, .read_msr = native_read_msr_safe, - .write_msr = native_write_msr_safe, + .write_msr = xen_write_msr_safe, .read_tsc = native_read_tsc, .read_pmc = native_read_pmc, .iret = xen_iret, .irq_enable_sysexit = xen_sysexit, +#ifdef CONFIG_X86_64 + .usergs_sysret32 = xen_sysret32, + .usergs_sysret64 = xen_sysret64, +#endif .load_tr_desc = paravirt_nop, .set_ldt = xen_set_ldt, .load_gdt = xen_load_gdt, .load_idt = xen_load_idt, .load_tls = xen_load_tls, +#ifdef CONFIG_X86_64 + .load_gs_index = xen_load_gs_index, +#endif .store_gdt = native_store_gdt, .store_idt = native_store_idt, @@ -1109,14 +1232,34 @@ static const struct pv_cpu_ops xen_cpu_ops __initdata = { .set_iopl_mask = xen_set_iopl_mask, .io_delay = xen_io_delay, + /* Xen takes care of %gs when switching to usermode for us */ + .swapgs = paravirt_nop, + .lazy_mode = { .enter = paravirt_enter_lazy_cpu, .leave = xen_leave_lazy, }, }; +static void __init __xen_init_IRQ(void) +{ +#ifdef CONFIG_X86_64 + int i; + + /* Create identity vector->irq map */ + for(i = 0; i < NR_VECTORS; i++) { + int cpu; + + for_each_possible_cpu(cpu) + per_cpu(vector_irq, cpu)[i] = i; + } +#endif /* CONFIG_X86_64 */ + + xen_init_IRQ(); +} + static const struct pv_irq_ops xen_irq_ops __initdata = { - .init_IRQ = xen_init_IRQ, + .init_IRQ = __xen_init_IRQ, .save_fl = xen_save_fl, .restore_fl = xen_restore_fl, .irq_disable = xen_irq_disable, @@ -1124,7 +1267,7 @@ static const struct pv_irq_ops xen_irq_ops __initdata = { .safe_halt = xen_safe_halt, .halt = xen_halt, #ifdef CONFIG_X86_64 - .adjust_exception_frame = paravirt_nop, + .adjust_exception_frame = xen_adjust_exception_frame, #endif }; @@ -1156,8 +1299,8 @@ static const struct pv_mmu_ops xen_mmu_ops __initdata = { .pte_update = paravirt_nop, .pte_update_defer = paravirt_nop, - .pgd_alloc = __paravirt_pgd_alloc, - .pgd_free = paravirt_nop, + .pgd_alloc = xen_pgd_alloc, + .pgd_free = xen_pgd_free, .alloc_pte = xen_alloc_pte_init, .release_pte = xen_release_pte_init, @@ -1169,7 +1312,11 @@ static const struct pv_mmu_ops xen_mmu_ops __initdata = { .kmap_atomic_pte = xen_kmap_atomic_pte, #endif - .set_pte = NULL, /* see xen_pagetable_setup_* */ +#ifdef CONFIG_X86_64 + .set_pte = xen_set_pte, +#else + .set_pte = xen_set_pte_init, +#endif .set_pte_at = xen_set_pte_at, .set_pmd = xen_set_pmd_hyper, @@ -1183,15 +1330,26 @@ static const struct pv_mmu_ops xen_mmu_ops __initdata = { .make_pte = xen_make_pte, .make_pgd = xen_make_pgd, +#ifdef CONFIG_X86_PAE .set_pte_atomic = xen_set_pte_atomic, .set_pte_present = xen_set_pte_at, - .set_pud = xen_set_pud_hyper, .pte_clear = xen_pte_clear, .pmd_clear = xen_pmd_clear, +#endif /* CONFIG_X86_PAE */ + .set_pud = xen_set_pud_hyper, .make_pmd = xen_make_pmd, .pmd_val = xen_pmd_val, +#if PAGETABLE_LEVELS == 4 + .pud_val = xen_pud_val, + .make_pud = xen_make_pud, + .set_pgd = xen_set_pgd_hyper, + + .alloc_pud = xen_alloc_pte_init, + .release_pud = xen_release_pte_init, +#endif /* PAGETABLE_LEVELS == 4 */ + .activate_mm = xen_activate_mm, .dup_mmap = xen_dup_mmap, .exit_mmap = xen_exit_mmap, @@ -1204,21 +1362,6 @@ static const struct pv_mmu_ops xen_mmu_ops __initdata = { .set_fixmap = xen_set_fixmap, }; -#ifdef CONFIG_SMP -static const struct smp_ops xen_smp_ops __initdata = { - .smp_prepare_boot_cpu = xen_smp_prepare_boot_cpu, - .smp_prepare_cpus = xen_smp_prepare_cpus, - .cpu_up = xen_cpu_up, - .smp_cpus_done = xen_smp_cpus_done, - - .smp_send_stop = xen_smp_send_stop, - .smp_send_reschedule = xen_smp_send_reschedule, - - .send_call_func_ipi = xen_smp_send_call_function_ipi, - .send_call_func_single_ipi = xen_smp_send_call_function_single_ipi, -}; -#endif /* CONFIG_SMP */ - static void xen_reboot(int reason) { struct sched_shutdown r = { .reason = reason }; @@ -1263,6 +1406,7 @@ static const struct machine_ops __initdata xen_machine_ops = { static void __init xen_reserve_top(void) { +#ifdef CONFIG_X86_32 unsigned long top = HYPERVISOR_VIRT_START; struct xen_platform_parameters pp; @@ -1270,8 +1414,248 @@ static void __init xen_reserve_top(void) top = pp.virt_start; reserve_top_address(-top + 2 * PAGE_SIZE); +#endif /* CONFIG_X86_32 */ +} + +/* + * Like __va(), but returns address in the kernel mapping (which is + * all we have until the physical memory mapping has been set up. + */ +static void *__ka(phys_addr_t paddr) +{ +#ifdef CONFIG_X86_64 + return (void *)(paddr + __START_KERNEL_map); +#else + return __va(paddr); +#endif } +/* Convert a machine address to physical address */ +static unsigned long m2p(phys_addr_t maddr) +{ + phys_addr_t paddr; + + maddr &= PTE_MASK; + paddr = mfn_to_pfn(maddr >> PAGE_SHIFT) << PAGE_SHIFT; + + return paddr; +} + +/* Convert a machine address to kernel virtual */ +static void *m2v(phys_addr_t maddr) +{ + return __ka(m2p(maddr)); +} + +#ifdef CONFIG_X86_64 +static void walk(pgd_t *pgd, unsigned long addr) +{ + unsigned l4idx = pgd_index(addr); + unsigned l3idx = pud_index(addr); + unsigned l2idx = pmd_index(addr); + unsigned l1idx = pte_index(addr); + pgd_t l4; + pud_t l3; + pmd_t l2; + pte_t l1; + + xen_raw_printk("walk %p, %lx -> %d %d %d %d\n", + pgd, addr, l4idx, l3idx, l2idx, l1idx); + + l4 = pgd[l4idx]; + xen_raw_printk(" l4: %016lx\n", l4.pgd); + xen_raw_printk(" %016lx\n", pgd_val(l4)); + + l3 = ((pud_t *)(m2v(l4.pgd)))[l3idx]; + xen_raw_printk(" l3: %016lx\n", l3.pud); + xen_raw_printk(" %016lx\n", pud_val(l3)); + + l2 = ((pmd_t *)(m2v(l3.pud)))[l2idx]; + xen_raw_printk(" l2: %016lx\n", l2.pmd); + xen_raw_printk(" %016lx\n", pmd_val(l2)); + + l1 = ((pte_t *)(m2v(l2.pmd)))[l1idx]; + xen_raw_printk(" l1: %016lx\n", l1.pte); + xen_raw_printk(" %016lx\n", pte_val(l1)); +} +#endif + +static void set_page_prot(void *addr, pgprot_t prot) +{ + unsigned long pfn = __pa(addr) >> PAGE_SHIFT; + pte_t pte = pfn_pte(pfn, prot); + + xen_raw_printk("addr=%p pfn=%lx mfn=%lx prot=%016llx pte=%016llx\n", + addr, pfn, get_phys_to_machine(pfn), + pgprot_val(prot), pte.pte); + + if (HYPERVISOR_update_va_mapping((unsigned long)addr, pte, 0)) + BUG(); +} + +static __init void xen_map_identity_early(pmd_t *pmd, unsigned long max_pfn) +{ + unsigned pmdidx, pteidx; + unsigned ident_pte; + unsigned long pfn; + + ident_pte = 0; + pfn = 0; + for(pmdidx = 0; pmdidx < PTRS_PER_PMD && pfn < max_pfn; pmdidx++) { + pte_t *pte_page; + + /* Reuse or allocate a page of ptes */ + if (pmd_present(pmd[pmdidx])) + pte_page = m2v(pmd[pmdidx].pmd); + else { + /* Check for free pte pages */ + if (ident_pte == ARRAY_SIZE(level1_ident_pgt)) + break; + + pte_page = &level1_ident_pgt[ident_pte]; + ident_pte += PTRS_PER_PTE; + + pmd[pmdidx] = __pmd(__pa(pte_page) | _PAGE_TABLE); + } + + /* Install mappings */ + for(pteidx = 0; pteidx < PTRS_PER_PTE; pteidx++, pfn++) { + pte_t pte; + + if (pfn > max_pfn_mapped) + max_pfn_mapped = pfn; + + if (!pte_none(pte_page[pteidx])) + continue; + + pte = pfn_pte(pfn, PAGE_KERNEL_EXEC); + pte_page[pteidx] = pte; + } + } + + for(pteidx = 0; pteidx < ident_pte; pteidx += PTRS_PER_PTE) + set_page_prot(&level1_ident_pgt[pteidx], PAGE_KERNEL_RO); + + set_page_prot(pmd, PAGE_KERNEL_RO); +} + +#ifdef CONFIG_X86_64 +static void convert_pfn_mfn(void *v) +{ + pte_t *pte = v; + int i; + + /* All levels are converted the same way, so just treat them + as ptes. */ + for(i = 0; i < PTRS_PER_PTE; i++) + pte[i] = xen_make_pte(pte[i].pte); +} + +/* + * Set up the inital kernel pagetable. + * + * We can construct this by grafting the Xen provided pagetable into + * head_64.S's preconstructed pagetables. We copy the Xen L2's into + * level2_ident_pgt, level2_kernel_pgt and level2_fixmap_pgt. This + * means that only the kernel has a physical mapping to start with - + * but that's enough to get __va working. We need to fill in the rest + * of the physical mapping once some sort of allocator has been set + * up. + */ +static __init pgd_t *xen_setup_kernel_pagetable(pgd_t *pgd, unsigned long max_pfn) +{ + pud_t *l3; + pmd_t *l2; + + /* Zap identity mapping */ + init_level4_pgt[0] = __pgd(0); + + /* Pre-constructed entries are in pfn, so convert to mfn */ + convert_pfn_mfn(init_level4_pgt); + convert_pfn_mfn(level3_ident_pgt); + convert_pfn_mfn(level3_kernel_pgt); + + l3 = m2v(pgd[pgd_index(__START_KERNEL_map)].pgd); + l2 = m2v(l3[pud_index(__START_KERNEL_map)].pud); + + memcpy(level2_ident_pgt, l2, sizeof(pmd_t) * PTRS_PER_PMD); + memcpy(level2_kernel_pgt, l2, sizeof(pmd_t) * PTRS_PER_PMD); + + l3 = m2v(pgd[pgd_index(__START_KERNEL_map + PMD_SIZE)].pgd); + l2 = m2v(l3[pud_index(__START_KERNEL_map + PMD_SIZE)].pud); + memcpy(level2_fixmap_pgt, l2, sizeof(pmd_t) * PTRS_PER_PMD); + + /* Set up identity map */ + xen_map_identity_early(level2_ident_pgt, max_pfn); + + /* Make pagetable pieces RO */ + set_page_prot(init_level4_pgt, PAGE_KERNEL_RO); + set_page_prot(level3_ident_pgt, PAGE_KERNEL_RO); + set_page_prot(level3_kernel_pgt, PAGE_KERNEL_RO); + set_page_prot(level3_user_vsyscall, PAGE_KERNEL_RO); + set_page_prot(level2_kernel_pgt, PAGE_KERNEL_RO); + set_page_prot(level2_fixmap_pgt, PAGE_KERNEL_RO); + + /* Pin down new L4 */ + pin_pagetable_pfn(MMUEXT_PIN_L4_TABLE, + PFN_DOWN(__pa_symbol(init_level4_pgt))); + + /* Unpin Xen-provided one */ + pin_pagetable_pfn(MMUEXT_UNPIN_TABLE, PFN_DOWN(__pa(pgd))); + + /* Switch over */ + pgd = init_level4_pgt; + + /* + * At this stage there can be no user pgd, and no page + * structure to attach it to, so make sure we just set kernel + * pgd. + */ + xen_mc_batch(); + __xen_write_cr3(true, __pa(pgd)); + xen_mc_issue(PARAVIRT_LAZY_CPU); + + reserve_early(__pa(xen_start_info->pt_base), + __pa(xen_start_info->pt_base + + xen_start_info->nr_pt_frames * PAGE_SIZE), + "XEN PAGETABLES"); + + return pgd; +} +#else /* !CONFIG_X86_64 */ +static pmd_t level2_kernel_pgt[PTRS_PER_PMD] __page_aligned_bss; + +static __init pgd_t *xen_setup_kernel_pagetable(pgd_t *pgd, unsigned long max_pfn) +{ + pmd_t *kernel_pmd; + + init_pg_tables_start = __pa(pgd); + init_pg_tables_end = __pa(pgd) + xen_start_info->nr_pt_frames*PAGE_SIZE; + max_pfn_mapped = PFN_DOWN(init_pg_tables_end + 512*1024); + + kernel_pmd = m2v(pgd[KERNEL_PGD_BOUNDARY].pgd); + memcpy(level2_kernel_pgt, kernel_pmd, sizeof(pmd_t) * PTRS_PER_PMD); + + xen_map_identity_early(level2_kernel_pgt, max_pfn); + + memcpy(swapper_pg_dir, pgd, sizeof(pgd_t) * PTRS_PER_PGD); + set_pgd(&swapper_pg_dir[KERNEL_PGD_BOUNDARY], + __pgd(__pa(level2_kernel_pgt) | _PAGE_PRESENT)); + + set_page_prot(level2_kernel_pgt, PAGE_KERNEL_RO); + set_page_prot(swapper_pg_dir, PAGE_KERNEL_RO); + set_page_prot(empty_zero_page, PAGE_KERNEL_RO); + + pin_pagetable_pfn(MMUEXT_UNPIN_TABLE, PFN_DOWN(__pa(pgd))); + + xen_write_cr3(__pa(swapper_pg_dir)); + + pin_pagetable_pfn(MMUEXT_PIN_L3_TABLE, PFN_DOWN(__pa(swapper_pg_dir))); + + return swapper_pg_dir; +} +#endif /* CONFIG_X86_64 */ + /* First C function to be called on Xen boot */ asmlinkage void __init xen_start_kernel(void) { @@ -1300,53 +1684,56 @@ asmlinkage void __init xen_start_kernel(void) machine_ops = xen_machine_ops; -#ifdef CONFIG_SMP - smp_ops = xen_smp_ops; +#ifdef CONFIG_X86_64 + /* Disable until direct per-cpu data access. */ + have_vcpu_info_placement = 0; + x86_64_init_pda(); #endif + xen_smp_init(); + /* Get mfn list */ if (!xen_feature(XENFEAT_auto_translated_physmap)) xen_build_dynamic_phys_to_machine(); pgd = (pgd_t *)xen_start_info->pt_base; - init_pg_tables_start = __pa(pgd); - init_pg_tables_end = __pa(pgd) + xen_start_info->nr_pt_frames*PAGE_SIZE; - max_pfn_mapped = (init_pg_tables_end + 512*1024) >> PAGE_SHIFT; - - init_mm.pgd = pgd; /* use the Xen pagetables to start */ - - /* keep using Xen gdt for now; no urgent need to change it */ - - x86_write_percpu(xen_cr3, __pa(pgd)); - x86_write_percpu(xen_current_cr3, __pa(pgd)); + /* Prevent unwanted bits from being set in PTEs. */ + __supported_pte_mask &= ~_PAGE_GLOBAL; + if (!is_initial_xendomain()) + __supported_pte_mask &= ~(_PAGE_PWT | _PAGE_PCD); /* Don't do the full vcpu_info placement stuff until we have a possible map and a non-dummy shared_info. */ per_cpu(xen_vcpu, 0) = &HYPERVISOR_shared_info->vcpu_info[0]; + xen_raw_console_write("mapping kernel into physical memory\n"); + pgd = xen_setup_kernel_pagetable(pgd, xen_start_info->nr_pages); + + init_mm.pgd = pgd; + + /* keep using Xen gdt for now; no urgent need to change it */ + pv_info.kernel_rpl = 1; if (xen_feature(XENFEAT_supervisor_mode_kernel)) pv_info.kernel_rpl = 0; - /* Prevent unwanted bits from being set in PTEs. */ - __supported_pte_mask &= ~_PAGE_GLOBAL; - if (!is_initial_xendomain()) - __supported_pte_mask &= ~(_PAGE_PWT | _PAGE_PCD); - /* set the limit of our address space */ xen_reserve_top(); +#ifdef CONFIG_X86_32 /* set up basic CPUID stuff */ cpu_detect(&new_cpu_data); new_cpu_data.hard_math = 1; new_cpu_data.x86_capability[0] = cpuid_edx(1); +#endif /* Poke various useful things into boot_params */ boot_params.hdr.type_of_loader = (9 << 4) | 0; boot_params.hdr.ramdisk_image = xen_start_info->mod_start ? __pa(xen_start_info->mod_start) : 0; boot_params.hdr.ramdisk_size = xen_start_info->mod_len; + boot_params.hdr.cmd_line_ptr = __pa(xen_start_info->cmd_line); if (!is_initial_xendomain()) { add_preferred_console("xenboot", 0, NULL); @@ -1354,6 +1741,21 @@ asmlinkage void __init xen_start_kernel(void) add_preferred_console("hvc", 0, NULL); } + xen_raw_console_write("about to get started...\n"); + +#if 0 + xen_raw_printk("&boot_params=%p __pa(&boot_params)=%lx __va(__pa(&boot_params))=%lx\n", + &boot_params, __pa_symbol(&boot_params), + __va(__pa_symbol(&boot_params))); + + walk(pgd, &boot_params); + walk(pgd, __va(__pa(&boot_params))); +#endif + /* Start the world */ +#ifdef CONFIG_X86_32 i386_start_kernel(); +#else + x86_64_start_reservations((char *)__pa_symbol(&boot_params)); +#endif } diff --git a/arch/x86/xen/mmu.c b/arch/x86/xen/mmu.c index ff0aa74afaa1..a44d56e38bd1 100644 --- a/arch/x86/xen/mmu.c +++ b/arch/x86/xen/mmu.c @@ -44,8 +44,10 @@ #include <asm/pgtable.h> #include <asm/tlbflush.h> +#include <asm/fixmap.h> #include <asm/mmu_context.h> #include <asm/paravirt.h> +#include <asm/linkage.h> #include <asm/xen/hypercall.h> #include <asm/xen/hypervisor.h> @@ -56,26 +58,29 @@ #include "multicalls.h" #include "mmu.h" +/* + * Just beyond the highest usermode address. STACK_TOP_MAX has a + * redzone above it, so round it up to a PGD boundary. + */ +#define USER_LIMIT ((STACK_TOP_MAX + PGDIR_SIZE - 1) & PGDIR_MASK) + + #define P2M_ENTRIES_PER_PAGE (PAGE_SIZE / sizeof(unsigned long)) #define TOP_ENTRIES (MAX_DOMAIN_PAGES / P2M_ENTRIES_PER_PAGE) /* Placeholder for holes in the address space */ -static unsigned long p2m_missing[P2M_ENTRIES_PER_PAGE] - __attribute__((section(".data.page_aligned"))) = +static unsigned long p2m_missing[P2M_ENTRIES_PER_PAGE] __page_aligned_data = { [ 0 ... P2M_ENTRIES_PER_PAGE-1 ] = ~0UL }; /* Array of pointers to pages containing p2m entries */ -static unsigned long *p2m_top[TOP_ENTRIES] - __attribute__((section(".data.page_aligned"))) = +static unsigned long *p2m_top[TOP_ENTRIES] __page_aligned_data = { [ 0 ... TOP_ENTRIES - 1] = &p2m_missing[0] }; /* Arrays of p2m arrays expressed in mfns used for save/restore */ -static unsigned long p2m_top_mfn[TOP_ENTRIES] - __attribute__((section(".bss.page_aligned"))); +static unsigned long p2m_top_mfn[TOP_ENTRIES] __page_aligned_bss; -static unsigned long p2m_top_mfn_list[ - PAGE_ALIGN(TOP_ENTRIES / P2M_ENTRIES_PER_PAGE)] - __attribute__((section(".bss.page_aligned"))); +static unsigned long p2m_top_mfn_list[TOP_ENTRIES / P2M_ENTRIES_PER_PAGE] + __page_aligned_bss; static inline unsigned p2m_top_index(unsigned long pfn) { @@ -181,15 +186,16 @@ void set_phys_to_machine(unsigned long pfn, unsigned long mfn) p2m_top[topidx][idx] = mfn; } -xmaddr_t arbitrary_virt_to_machine(unsigned long address) +xmaddr_t arbitrary_virt_to_machine(void *vaddr) { + unsigned long address = (unsigned long)vaddr; unsigned int level; pte_t *pte = lookup_address(address, &level); unsigned offset = address & ~PAGE_MASK; BUG_ON(pte == NULL); - return XMADDR((pte_mfn(*pte) << PAGE_SHIFT) + offset); + return XMADDR(((phys_addr_t)pte_mfn(*pte) << PAGE_SHIFT) + offset); } void make_lowmem_page_readonly(void *vaddr) @@ -256,7 +262,8 @@ void xen_set_pmd_hyper(pmd_t *ptr, pmd_t val) xen_mc_batch(); - u.ptr = virt_to_machine(ptr).maddr; + /* ptr may be ioremapped for 64-bit pagetable setup */ + u.ptr = arbitrary_virt_to_machine(ptr).maddr; u.val = pmd_val_ma(val); extend_mmu_update(&u); @@ -283,35 +290,7 @@ void xen_set_pmd(pmd_t *ptr, pmd_t val) */ void set_pte_mfn(unsigned long vaddr, unsigned long mfn, pgprot_t flags) { - pgd_t *pgd; - pud_t *pud; - pmd_t *pmd; - pte_t *pte; - - pgd = swapper_pg_dir + pgd_index(vaddr); - if (pgd_none(*pgd)) { - BUG(); - return; - } - pud = pud_offset(pgd, vaddr); - if (pud_none(*pud)) { - BUG(); - return; - } - pmd = pmd_offset(pud, vaddr); - if (pmd_none(*pmd)) { - BUG(); - return; - } - pte = pte_offset_kernel(pmd, vaddr); - /* <mfn,flags> stored as-is, to permit clearing entries */ - xen_set_pte(pte, mfn_pte(mfn, flags)); - - /* - * It's enough to flush this one mapping. - * (PGE mappings get flushed as well) - */ - __flush_tlb_one(vaddr); + set_pte_vaddr(vaddr, mfn_pte(mfn, flags)); } void xen_set_pte_at(struct mm_struct *mm, unsigned long addr, @@ -418,7 +397,8 @@ void xen_set_pud_hyper(pud_t *ptr, pud_t val) xen_mc_batch(); - u.ptr = virt_to_machine(ptr).maddr; + /* ptr may be ioremapped for 64-bit pagetable setup */ + u.ptr = arbitrary_virt_to_machine(ptr).maddr; u.val = pud_val_ma(val); extend_mmu_update(&u); @@ -441,14 +421,19 @@ void xen_set_pud(pud_t *ptr, pud_t val) void xen_set_pte(pte_t *ptep, pte_t pte) { +#ifdef CONFIG_X86_PAE ptep->pte_high = pte.pte_high; smp_wmb(); ptep->pte_low = pte.pte_low; +#else + *ptep = pte; +#endif } +#ifdef CONFIG_X86_PAE void xen_set_pte_atomic(pte_t *ptep, pte_t pte) { - set_64bit((u64 *)ptep, pte_val_ma(pte)); + set_64bit((u64 *)ptep, native_pte_val(pte)); } void xen_pte_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep) @@ -462,6 +447,7 @@ void xen_pmd_clear(pmd_t *pmdp) { set_pmd(pmdp, __pmd(0)); } +#endif /* CONFIG_X86_PAE */ pmd_t xen_make_pmd(pmdval_t pmd) { @@ -469,78 +455,189 @@ pmd_t xen_make_pmd(pmdval_t pmd) return native_make_pmd(pmd); } +#if PAGETABLE_LEVELS == 4 +pudval_t xen_pud_val(pud_t pud) +{ + return pte_mfn_to_pfn(pud.pud); +} + +pud_t xen_make_pud(pudval_t pud) +{ + pud = pte_pfn_to_mfn(pud); + + return native_make_pud(pud); +} + +pgd_t *xen_get_user_pgd(pgd_t *pgd) +{ + pgd_t *pgd_page = (pgd_t *)(((unsigned long)pgd) & PAGE_MASK); + unsigned offset = pgd - pgd_page; + pgd_t *user_ptr = NULL; + + if (offset < pgd_index(USER_LIMIT)) { + struct page *page = virt_to_page(pgd_page); + user_ptr = (pgd_t *)page->private; + if (user_ptr) + user_ptr += offset; + } + + return user_ptr; +} + +static void __xen_set_pgd_hyper(pgd_t *ptr, pgd_t val) +{ + struct mmu_update u; + + u.ptr = virt_to_machine(ptr).maddr; + u.val = pgd_val_ma(val); + extend_mmu_update(&u); +} + +/* + * Raw hypercall-based set_pgd, intended for in early boot before + * there's a page structure. This implies: + * 1. The only existing pagetable is the kernel's + * 2. It is always pinned + * 3. It has no user pagetable attached to it + */ +void __init xen_set_pgd_hyper(pgd_t *ptr, pgd_t val) +{ + preempt_disable(); + + xen_mc_batch(); + + __xen_set_pgd_hyper(ptr, val); + + xen_mc_issue(PARAVIRT_LAZY_MMU); + + preempt_enable(); +} + +void xen_set_pgd(pgd_t *ptr, pgd_t val) +{ + pgd_t *user_ptr = xen_get_user_pgd(ptr); + + /* If page is not pinned, we can just update the entry + directly */ + if (!page_pinned(ptr)) { + *ptr = val; + if (user_ptr) { + WARN_ON(page_pinned(user_ptr)); + *user_ptr = val; + } + return; + } + + /* If it's pinned, then we can at least batch the kernel and + user updates together. */ + xen_mc_batch(); + + __xen_set_pgd_hyper(ptr, val); + if (user_ptr) + __xen_set_pgd_hyper(user_ptr, val); + + xen_mc_issue(PARAVIRT_LAZY_MMU); +} +#endif /* PAGETABLE_LEVELS == 4 */ + /* - (Yet another) pagetable walker. This one is intended for pinning a - pagetable. This means that it walks a pagetable and calls the - callback function on each page it finds making up the page table, - at every level. It walks the entire pagetable, but it only bothers - pinning pte pages which are below pte_limit. In the normal case - this will be TASK_SIZE, but at boot we need to pin up to - FIXADDR_TOP. But the important bit is that we don't pin beyond - there, because then we start getting into Xen's ptes. -*/ -static int pgd_walk(pgd_t *pgd_base, int (*func)(struct page *, enum pt_level), + * (Yet another) pagetable walker. This one is intended for pinning a + * pagetable. This means that it walks a pagetable and calls the + * callback function on each page it finds making up the page table, + * at every level. It walks the entire pagetable, but it only bothers + * pinning pte pages which are below limit. In the normal case this + * will be STACK_TOP_MAX, but at boot we need to pin up to + * FIXADDR_TOP. + * + * For 32-bit the important bit is that we don't pin beyond there, + * because then we start getting into Xen's ptes. + * + * For 64-bit, we must skip the Xen hole in the middle of the address + * space, just after the big x86-64 virtual hole. + */ +static int pgd_walk(pgd_t *pgd, int (*func)(struct page *, enum pt_level), unsigned long limit) { - pgd_t *pgd = pgd_base; int flush = 0; - unsigned long addr = 0; - unsigned long pgd_next; + unsigned hole_low, hole_high; + unsigned pgdidx_limit, pudidx_limit, pmdidx_limit; + unsigned pgdidx, pudidx, pmdidx; - BUG_ON(limit > FIXADDR_TOP); + /* The limit is the last byte to be touched */ + limit--; + BUG_ON(limit >= FIXADDR_TOP); if (xen_feature(XENFEAT_auto_translated_physmap)) return 0; - for (; addr != FIXADDR_TOP; pgd++, addr = pgd_next) { + /* + * 64-bit has a great big hole in the middle of the address + * space, which contains the Xen mappings. On 32-bit these + * will end up making a zero-sized hole and so is a no-op. + */ + hole_low = pgd_index(USER_LIMIT); + hole_high = pgd_index(PAGE_OFFSET); + + pgdidx_limit = pgd_index(limit); +#if PTRS_PER_PUD > 1 + pudidx_limit = pud_index(limit); +#else + pudidx_limit = 0; +#endif +#if PTRS_PER_PMD > 1 + pmdidx_limit = pmd_index(limit); +#else + pmdidx_limit = 0; +#endif + + flush |= (*func)(virt_to_page(pgd), PT_PGD); + + for (pgdidx = 0; pgdidx <= pgdidx_limit; pgdidx++) { pud_t *pud; - unsigned long pud_limit, pud_next; - pgd_next = pud_limit = pgd_addr_end(addr, FIXADDR_TOP); + if (pgdidx >= hole_low && pgdidx < hole_high) + continue; - if (!pgd_val(*pgd)) + if (!pgd_val(pgd[pgdidx])) continue; - pud = pud_offset(pgd, 0); + pud = pud_offset(&pgd[pgdidx], 0); if (PTRS_PER_PUD > 1) /* not folded */ flush |= (*func)(virt_to_page(pud), PT_PUD); - for (; addr != pud_limit; pud++, addr = pud_next) { + for (pudidx = 0; pudidx < PTRS_PER_PUD; pudidx++) { pmd_t *pmd; - unsigned long pmd_limit; - pud_next = pud_addr_end(addr, pud_limit); - - if (pud_next < limit) - pmd_limit = pud_next; - else - pmd_limit = limit; + if (pgdidx == pgdidx_limit && + pudidx > pudidx_limit) + goto out; - if (pud_none(*pud)) + if (pud_none(pud[pudidx])) continue; - pmd = pmd_offset(pud, 0); + pmd = pmd_offset(&pud[pudidx], 0); if (PTRS_PER_PMD > 1) /* not folded */ flush |= (*func)(virt_to_page(pmd), PT_PMD); - for (; addr != pmd_limit; pmd++) { - addr += (PAGE_SIZE * PTRS_PER_PTE); - if ((pmd_limit-1) < (addr-1)) { - addr = pmd_limit; - break; - } + for (pmdidx = 0; pmdidx < PTRS_PER_PMD; pmdidx++) { + struct page *pte; + + if (pgdidx == pgdidx_limit && + pudidx == pudidx_limit && + pmdidx > pmdidx_limit) + goto out; - if (pmd_none(*pmd)) + if (pmd_none(pmd[pmdidx])) continue; - flush |= (*func)(pmd_page(*pmd), PT_PTE); + pte = pmd_page(pmd[pmdidx]); + flush |= (*func)(pte, PT_PTE); } } } - - flush |= (*func)(virt_to_page(pgd_base), PT_PGD); +out: return flush; } @@ -622,14 +719,31 @@ void xen_pgd_pin(pgd_t *pgd) { xen_mc_batch(); - if (pgd_walk(pgd, pin_page, TASK_SIZE)) { + if (pgd_walk(pgd, pin_page, USER_LIMIT)) { /* re-enable interrupts for kmap_flush_unused */ xen_mc_issue(0); kmap_flush_unused(); xen_mc_batch(); } +#ifdef CONFIG_X86_64 + { + pgd_t *user_pgd = xen_get_user_pgd(pgd); + + xen_do_pin(MMUEXT_PIN_L4_TABLE, PFN_DOWN(__pa(pgd))); + + if (user_pgd) { + pin_page(virt_to_page(user_pgd), PT_PGD); + xen_do_pin(MMUEXT_PIN_L4_TABLE, PFN_DOWN(__pa(user_pgd))); + } + } +#else /* CONFIG_X86_32 */ +#ifdef CONFIG_X86_PAE + /* Need to make sure unshared kernel PMD is pinnable */ + pin_page(virt_to_page(pgd_page(pgd[pgd_index(TASK_SIZE)])), PT_PMD); +#endif xen_do_pin(MMUEXT_PIN_L3_TABLE, PFN_DOWN(__pa(pgd))); +#endif /* CONFIG_X86_64 */ xen_mc_issue(0); } @@ -656,9 +770,11 @@ void xen_mm_pin_all(void) spin_unlock_irqrestore(&pgd_lock, flags); } -/* The init_mm pagetable is really pinned as soon as its created, but - that's before we have page structures to store the bits. So do all - the book-keeping now. */ +/* + * The init_mm pagetable is really pinned as soon as its created, but + * that's before we have page structures to store the bits. So do all + * the book-keeping now. + */ static __init int mark_pinned(struct page *page, enum pt_level level) { SetPagePinned(page); @@ -708,7 +824,23 @@ static void xen_pgd_unpin(pgd_t *pgd) xen_do_pin(MMUEXT_UNPIN_TABLE, PFN_DOWN(__pa(pgd))); - pgd_walk(pgd, unpin_page, TASK_SIZE); +#ifdef CONFIG_X86_64 + { + pgd_t *user_pgd = xen_get_user_pgd(pgd); + + if (user_pgd) { + xen_do_pin(MMUEXT_UNPIN_TABLE, PFN_DOWN(__pa(user_pgd))); + unpin_page(virt_to_page(user_pgd), PT_PGD); + } + } +#endif + +#ifdef CONFIG_X86_PAE + /* Need to make sure unshared kernel PMD is unpinned */ + pin_page(virt_to_page(pgd_page(pgd[pgd_index(TASK_SIZE)])), PT_PMD); +#endif + + pgd_walk(pgd, unpin_page, USER_LIMIT); xen_mc_issue(0); } @@ -727,7 +859,6 @@ void xen_mm_unpin_all(void) list_for_each_entry(page, &pgd_list, lru) { if (PageSavePinned(page)) { BUG_ON(!PagePinned(page)); - printk("unpinning pinned %p\n", page_address(page)); xen_pgd_unpin((pgd_t *)page_address(page)); ClearPageSavePinned(page); } @@ -757,8 +888,15 @@ void xen_dup_mmap(struct mm_struct *oldmm, struct mm_struct *mm) static void drop_other_mm_ref(void *info) { struct mm_struct *mm = info; + struct mm_struct *active_mm; + +#ifdef CONFIG_X86_64 + active_mm = read_pda(active_mm); +#else + active_mm = __get_cpu_var(cpu_tlbstate).active_mm; +#endif - if (__get_cpu_var(cpu_tlbstate).active_mm == mm) + if (active_mm == mm) leave_mm(smp_processor_id()); /* If this cpu still has a stale cr3 reference, then make sure diff --git a/arch/x86/xen/mmu.h b/arch/x86/xen/mmu.h index 297bf9f5b8bc..0f59bd03f9e3 100644 --- a/arch/x86/xen/mmu.h +++ b/arch/x86/xen/mmu.h @@ -10,18 +10,6 @@ enum pt_level { PT_PTE }; -/* - * Page-directory addresses above 4GB do not fit into architectural %cr3. - * When accessing %cr3, or equivalent field in vcpu_guest_context, guests - * must use the following accessor macros to pack/unpack valid MFNs. - * - * Note that Xen is using the fact that the pagetable base is always - * page-aligned, and putting the 12 MSB of the address into the 12 LSB - * of cr3. - */ -#define xen_pfn_to_cr3(pfn) (((unsigned)(pfn) << 12) | ((unsigned)(pfn) >> 20)) -#define xen_cr3_to_pfn(cr3) (((unsigned)(cr3) >> 12) | ((unsigned)(cr3) << 20)) - void set_pte_mfn(unsigned long vaddr, unsigned long pfn, pgprot_t flags); @@ -44,13 +32,26 @@ pgd_t xen_make_pgd(pgdval_t); void xen_set_pte(pte_t *ptep, pte_t pteval); void xen_set_pte_at(struct mm_struct *mm, unsigned long addr, pte_t *ptep, pte_t pteval); + +#ifdef CONFIG_X86_PAE void xen_set_pte_atomic(pte_t *ptep, pte_t pte); +void xen_pte_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep); +void xen_pmd_clear(pmd_t *pmdp); +#endif /* CONFIG_X86_PAE */ + void xen_set_pmd(pmd_t *pmdp, pmd_t pmdval); void xen_set_pud(pud_t *ptr, pud_t val); void xen_set_pmd_hyper(pmd_t *pmdp, pmd_t pmdval); void xen_set_pud_hyper(pud_t *ptr, pud_t val); -void xen_pte_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep); -void xen_pmd_clear(pmd_t *pmdp); + +#if PAGETABLE_LEVELS == 4 +pudval_t xen_pud_val(pud_t pud); +pud_t xen_make_pud(pudval_t pudval); +void xen_set_pgd(pgd_t *pgdp, pgd_t pgd); +void xen_set_pgd_hyper(pgd_t *pgdp, pgd_t pgd); +#endif + +pgd_t *xen_get_user_pgd(pgd_t *pgd); pte_t xen_ptep_modify_prot_start(struct mm_struct *mm, unsigned long addr, pte_t *ptep); void xen_ptep_modify_prot_commit(struct mm_struct *mm, unsigned long addr, diff --git a/arch/x86/xen/multicalls.c b/arch/x86/xen/multicalls.c index 3c63c4da7ed1..9efd1c6c9776 100644 --- a/arch/x86/xen/multicalls.c +++ b/arch/x86/xen/multicalls.c @@ -76,6 +76,7 @@ void xen_mc_flush(void) if (ret) { printk(KERN_ERR "%d multicall(s) failed: cpu %d\n", ret, smp_processor_id()); + dump_stack(); for (i = 0; i < b->mcidx; i++) { printk(" call %2d/%d: op=%lu arg=[%lx] result=%ld\n", i+1, b->mcidx, diff --git a/arch/x86/xen/setup.c b/arch/x86/xen/setup.c index e0a39595bde3..b6acc3a0af46 100644 --- a/arch/x86/xen/setup.c +++ b/arch/x86/xen/setup.c @@ -83,30 +83,72 @@ static void xen_idle(void) /* * Set the bit indicating "nosegneg" library variants should be used. + * We only need to bother in pure 32-bit mode; compat 32-bit processes + * can have un-truncated segments, so wrapping around is allowed. */ static void __init fiddle_vdso(void) { - extern const char vdso32_default_start; - u32 *mask = VDSO32_SYMBOL(&vdso32_default_start, NOTE_MASK); +#ifdef CONFIG_X86_32 + u32 *mask; + mask = VDSO32_SYMBOL(&vdso32_int80_start, NOTE_MASK); *mask |= 1 << VDSO_NOTE_NONEGSEG_BIT; + mask = VDSO32_SYMBOL(&vdso32_sysenter_start, NOTE_MASK); + *mask |= 1 << VDSO_NOTE_NONEGSEG_BIT; +#endif } -void xen_enable_sysenter(void) +static __cpuinit int register_callback(unsigned type, const void *func) { - int cpu = smp_processor_id(); - extern void xen_sysenter_target(void); - /* Mask events on entry, even though they get enabled immediately */ - static struct callback_register sysenter = { - .type = CALLBACKTYPE_sysenter, - .address = { __KERNEL_CS, (unsigned long)xen_sysenter_target }, + struct callback_register callback = { + .type = type, + .address = XEN_CALLBACK(__KERNEL_CS, func), .flags = CALLBACKF_mask_events, }; - if (!boot_cpu_has(X86_FEATURE_SEP) || - HYPERVISOR_callback_op(CALLBACKOP_register, &sysenter) != 0) { - clear_cpu_cap(&cpu_data(cpu), X86_FEATURE_SEP); - clear_cpu_cap(&boot_cpu_data, X86_FEATURE_SEP); + return HYPERVISOR_callback_op(CALLBACKOP_register, &callback); +} + +void __cpuinit xen_enable_sysenter(void) +{ + extern void xen_sysenter_target(void); + int ret; + unsigned sysenter_feature; + +#ifdef CONFIG_X86_32 + sysenter_feature = X86_FEATURE_SEP; +#else + sysenter_feature = X86_FEATURE_SYSENTER32; +#endif + + if (!boot_cpu_has(sysenter_feature)) + return; + + ret = register_callback(CALLBACKTYPE_sysenter, xen_sysenter_target); + if(ret != 0) + setup_clear_cpu_cap(sysenter_feature); +} + +void __cpuinit xen_enable_syscall(void) +{ +#ifdef CONFIG_X86_64 + int ret; + extern void xen_syscall_target(void); + extern void xen_syscall32_target(void); + + ret = register_callback(CALLBACKTYPE_syscall, xen_syscall_target); + if (ret != 0) { + printk(KERN_ERR "Failed to set syscall callback: %d\n", ret); + /* Pretty fatal; 64-bit userspace has no other + mechanism for syscalls. */ } + + if (boot_cpu_has(X86_FEATURE_SYSCALL32)) { + ret = register_callback(CALLBACKTYPE_syscall32, + xen_syscall32_target); + if (ret != 0) + setup_clear_cpu_cap(X86_FEATURE_SYSCALL32); + } +#endif /* CONFIG_X86_64 */ } void __init xen_arch_setup(void) @@ -120,10 +162,12 @@ void __init xen_arch_setup(void) if (!xen_feature(XENFEAT_auto_translated_physmap)) HYPERVISOR_vm_assist(VMASST_CMD_enable, VMASST_TYPE_pae_extended_cr3); - HYPERVISOR_set_callbacks(__KERNEL_CS, (unsigned long)xen_hypervisor_callback, - __KERNEL_CS, (unsigned long)xen_failsafe_callback); + if (register_callback(CALLBACKTYPE_event, xen_hypervisor_callback) || + register_callback(CALLBACKTYPE_failsafe, xen_failsafe_callback)) + BUG(); xen_enable_sysenter(); + xen_enable_syscall(); set_iopl.iopl = 1; rc = HYPERVISOR_physdev_op(PHYSDEVOP_set_iopl, &set_iopl); @@ -143,11 +187,6 @@ void __init xen_arch_setup(void) pm_idle = xen_idle; -#ifdef CONFIG_SMP - /* fill cpus_possible with all available cpus */ - xen_fill_possible_map(); -#endif - paravirt_disable_iospace(); fiddle_vdso(); diff --git a/arch/x86/xen/smp.c b/arch/x86/xen/smp.c index 233156f39b7f..f702199312a5 100644 --- a/arch/x86/xen/smp.c +++ b/arch/x86/xen/smp.c @@ -66,13 +66,22 @@ static __cpuinit void cpu_bringup_and_idle(void) int cpu = smp_processor_id(); cpu_init(); + preempt_disable(); + xen_enable_sysenter(); + xen_enable_syscall(); - preempt_disable(); - per_cpu(cpu_state, cpu) = CPU_ONLINE; + cpu = smp_processor_id(); + smp_store_cpu_info(cpu); + cpu_data(cpu).x86_max_cores = 1; + set_cpu_sibling_map(cpu); xen_setup_cpu_clockevents(); + cpu_set(cpu, cpu_online_map); + x86_write_percpu(cpu_state, CPU_ONLINE); + wmb(); + /* We can take interrupts now: we're officially "up". */ local_irq_enable(); @@ -141,56 +150,37 @@ static int xen_smp_intr_init(unsigned int cpu) return rc; } -void __init xen_fill_possible_map(void) +static void __init xen_fill_possible_map(void) { int i, rc; for (i = 0; i < NR_CPUS; i++) { rc = HYPERVISOR_vcpu_op(VCPUOP_is_up, i, NULL); - if (rc >= 0) + if (rc >= 0) { + num_processors++; cpu_set(i, cpu_possible_map); + } } } -void __init xen_smp_prepare_boot_cpu(void) +static void __init xen_smp_prepare_boot_cpu(void) { - int cpu; - BUG_ON(smp_processor_id() != 0); native_smp_prepare_boot_cpu(); /* We've switched to the "real" per-cpu gdt, so make sure the old memory can be recycled */ - make_lowmem_page_readwrite(&per_cpu__gdt_page); - - for_each_possible_cpu(cpu) { - cpus_clear(per_cpu(cpu_sibling_map, cpu)); - /* - * cpu_core_map lives in a per cpu area that is cleared - * when the per cpu array is allocated. - * - * cpus_clear(per_cpu(cpu_core_map, cpu)); - */ - } + make_lowmem_page_readwrite(&per_cpu_var(gdt_page)); xen_setup_vcpu_info_placement(); } -void __init xen_smp_prepare_cpus(unsigned int max_cpus) +static void __init xen_smp_prepare_cpus(unsigned int max_cpus) { unsigned cpu; - for_each_possible_cpu(cpu) { - cpus_clear(per_cpu(cpu_sibling_map, cpu)); - /* - * cpu_core_ map will be zeroed when the per - * cpu area is allocated. - * - * cpus_clear(per_cpu(cpu_core_map, cpu)); - */ - } - smp_store_cpu_info(0); + cpu_data(0).x86_max_cores = 1; set_cpu_sibling_map(0); if (xen_smp_intr_init(0)) @@ -225,7 +215,7 @@ static __cpuinit int cpu_initialize_context(unsigned int cpu, struct task_struct *idle) { struct vcpu_guest_context *ctxt; - struct gdt_page *gdt = &per_cpu(gdt_page, cpu); + struct desc_struct *gdt; if (cpu_test_and_set(cpu, xen_cpu_initialized_map)) return 0; @@ -234,12 +224,15 @@ cpu_initialize_context(unsigned int cpu, struct task_struct *idle) if (ctxt == NULL) return -ENOMEM; + gdt = get_cpu_gdt_table(cpu); + ctxt->flags = VGCF_IN_KERNEL; ctxt->user_regs.ds = __USER_DS; ctxt->user_regs.es = __USER_DS; - ctxt->user_regs.fs = __KERNEL_PERCPU; - ctxt->user_regs.gs = 0; ctxt->user_regs.ss = __KERNEL_DS; +#ifdef CONFIG_X86_32 + ctxt->user_regs.fs = __KERNEL_PERCPU; +#endif ctxt->user_regs.eip = (unsigned long)cpu_bringup_and_idle; ctxt->user_regs.eflags = 0x1000; /* IOPL_RING1 */ @@ -249,11 +242,11 @@ cpu_initialize_context(unsigned int cpu, struct task_struct *idle) ctxt->ldt_ents = 0; - BUG_ON((unsigned long)gdt->gdt & ~PAGE_MASK); - make_lowmem_page_readonly(gdt->gdt); + BUG_ON((unsigned long)gdt & ~PAGE_MASK); + make_lowmem_page_readonly(gdt); - ctxt->gdt_frames[0] = virt_to_mfn(gdt->gdt); - ctxt->gdt_ents = ARRAY_SIZE(gdt->gdt); + ctxt->gdt_frames[0] = virt_to_mfn(gdt); + ctxt->gdt_ents = GDT_ENTRIES; ctxt->user_regs.cs = __KERNEL_CS; ctxt->user_regs.esp = idle->thread.sp0 - sizeof(struct pt_regs); @@ -261,9 +254,11 @@ cpu_initialize_context(unsigned int cpu, struct task_struct *idle) ctxt->kernel_ss = __KERNEL_DS; ctxt->kernel_sp = idle->thread.sp0; +#ifdef CONFIG_X86_32 ctxt->event_callback_cs = __KERNEL_CS; - ctxt->event_callback_eip = (unsigned long)xen_hypervisor_callback; ctxt->failsafe_callback_cs = __KERNEL_CS; +#endif + ctxt->event_callback_eip = (unsigned long)xen_hypervisor_callback; ctxt->failsafe_callback_eip = (unsigned long)xen_failsafe_callback; per_cpu(xen_cr3, cpu) = __pa(swapper_pg_dir); @@ -276,7 +271,7 @@ cpu_initialize_context(unsigned int cpu, struct task_struct *idle) return 0; } -int __cpuinit xen_cpu_up(unsigned int cpu) +static int __cpuinit xen_cpu_up(unsigned int cpu) { struct task_struct *idle = idle_task(cpu); int rc; @@ -287,11 +282,28 @@ int __cpuinit xen_cpu_up(unsigned int cpu) return rc; #endif +#ifdef CONFIG_X86_64 + /* Allocate node local memory for AP pdas */ + WARN_ON(cpu == 0); + if (cpu > 0) { + rc = get_local_pda(cpu); + if (rc) + return rc; + } +#endif + +#ifdef CONFIG_X86_32 init_gdt(cpu); per_cpu(current_task, cpu) = idle; irq_ctx_init(cpu); +#else + cpu_pda(cpu)->pcurrent = idle; + clear_tsk_thread_flag(idle, TIF_FORK); +#endif xen_setup_timer(cpu); + per_cpu(cpu_state, cpu) = CPU_UP_PREPARE; + /* make sure interrupts start blocked */ per_cpu(xen_vcpu, cpu)->evtchn_upcall_mask = 1; @@ -306,20 +318,18 @@ int __cpuinit xen_cpu_up(unsigned int cpu) if (rc) return rc; - smp_store_cpu_info(cpu); - set_cpu_sibling_map(cpu); - /* This must be done before setting cpu_online_map */ - wmb(); - - cpu_set(cpu, cpu_online_map); - rc = HYPERVISOR_vcpu_op(VCPUOP_up, cpu, NULL); BUG_ON(rc); + while(per_cpu(cpu_state, cpu) != CPU_ONLINE) { + HYPERVISOR_sched_op(SCHEDOP_yield, 0); + barrier(); + } + return 0; } -void xen_smp_cpus_done(unsigned int max_cpus) +static void xen_smp_cpus_done(unsigned int max_cpus) { } @@ -335,12 +345,12 @@ static void stop_self(void *v) BUG(); } -void xen_smp_send_stop(void) +static void xen_smp_send_stop(void) { smp_call_function(stop_self, NULL, 0); } -void xen_smp_send_reschedule(int cpu) +static void xen_smp_send_reschedule(int cpu) { xen_send_IPI_one(cpu, XEN_RESCHEDULE_VECTOR); } @@ -355,7 +365,7 @@ static void xen_send_IPI_mask(cpumask_t mask, enum ipi_vector vector) xen_send_IPI_one(cpu, vector); } -void xen_smp_send_call_function_ipi(cpumask_t mask) +static void xen_smp_send_call_function_ipi(cpumask_t mask) { int cpu; @@ -370,7 +380,7 @@ void xen_smp_send_call_function_ipi(cpumask_t mask) } } -void xen_smp_send_call_function_single_ipi(int cpu) +static void xen_smp_send_call_function_single_ipi(int cpu) { xen_send_IPI_mask(cpumask_of_cpu(cpu), XEN_CALL_FUNCTION_SINGLE_VECTOR); } @@ -379,7 +389,11 @@ static irqreturn_t xen_call_function_interrupt(int irq, void *dev_id) { irq_enter(); generic_smp_call_function_interrupt(); +#ifdef CONFIG_X86_32 __get_cpu_var(irq_stat).irq_call_count++; +#else + add_pda(irq_call_count, 1); +#endif irq_exit(); return IRQ_HANDLED; @@ -389,8 +403,31 @@ static irqreturn_t xen_call_function_single_interrupt(int irq, void *dev_id) { irq_enter(); generic_smp_call_function_single_interrupt(); +#ifdef CONFIG_X86_32 __get_cpu_var(irq_stat).irq_call_count++; +#else + add_pda(irq_call_count, 1); +#endif irq_exit(); return IRQ_HANDLED; } + +static const struct smp_ops xen_smp_ops __initdata = { + .smp_prepare_boot_cpu = xen_smp_prepare_boot_cpu, + .smp_prepare_cpus = xen_smp_prepare_cpus, + .cpu_up = xen_cpu_up, + .smp_cpus_done = xen_smp_cpus_done, + + .smp_send_stop = xen_smp_send_stop, + .smp_send_reschedule = xen_smp_send_reschedule, + + .send_call_func_ipi = xen_smp_send_call_function_ipi, + .send_call_func_single_ipi = xen_smp_send_call_function_single_ipi, +}; + +void __init xen_smp_init(void) +{ + smp_ops = xen_smp_ops; + xen_fill_possible_map(); +} diff --git a/arch/x86/xen/suspend.c b/arch/x86/xen/suspend.c index 251669a932d4..2a234db5949b 100644 --- a/arch/x86/xen/suspend.c +++ b/arch/x86/xen/suspend.c @@ -38,8 +38,11 @@ void xen_post_suspend(int suspend_cancelled) xen_cpu_initialized_map = cpu_online_map; #endif xen_vcpu_restore(); - xen_timer_resume(); } } +void xen_arch_resume(void) +{ + /* nothing */ +} diff --git a/arch/x86/xen/xen-asm.S b/arch/x86/xen/xen-asm_32.S index 2497a30f41de..2497a30f41de 100644 --- a/arch/x86/xen/xen-asm.S +++ b/arch/x86/xen/xen-asm_32.S diff --git a/arch/x86/xen/xen-asm_64.S b/arch/x86/xen/xen-asm_64.S new file mode 100644 index 000000000000..4038cbfe3331 --- /dev/null +++ b/arch/x86/xen/xen-asm_64.S @@ -0,0 +1,271 @@ +/* + Asm versions of Xen pv-ops, suitable for either direct use or inlining. + The inline versions are the same as the direct-use versions, with the + pre- and post-amble chopped off. + + This code is encoded for size rather than absolute efficiency, + with a view to being able to inline as much as possible. + + We only bother with direct forms (ie, vcpu in pda) of the operations + here; the indirect forms are better handled in C, since they're + generally too large to inline anyway. + */ + +#include <linux/linkage.h> + +#include <asm/asm-offsets.h> +#include <asm/processor-flags.h> +#include <asm/errno.h> +#include <asm/segment.h> + +#include <xen/interface/xen.h> + +#define RELOC(x, v) .globl x##_reloc; x##_reloc=v +#define ENDPATCH(x) .globl x##_end; x##_end=. + +/* Pseudo-flag used for virtual NMI, which we don't implement yet */ +#define XEN_EFLAGS_NMI 0x80000000 + +#if 0 +#include <asm/percpu.h> + +/* + Enable events. This clears the event mask and tests the pending + event status with one and operation. If there are pending + events, then enter the hypervisor to get them handled. + */ +ENTRY(xen_irq_enable_direct) + /* Unmask events */ + movb $0, PER_CPU_VAR(xen_vcpu_info, XEN_vcpu_info_mask) + + /* Preempt here doesn't matter because that will deal with + any pending interrupts. The pending check may end up being + run on the wrong CPU, but that doesn't hurt. */ + + /* Test for pending */ + testb $0xff, PER_CPU_VAR(xen_vcpu_info, XEN_vcpu_info_pending) + jz 1f + +2: call check_events +1: +ENDPATCH(xen_irq_enable_direct) + ret + ENDPROC(xen_irq_enable_direct) + RELOC(xen_irq_enable_direct, 2b+1) + +/* + Disabling events is simply a matter of making the event mask + non-zero. + */ +ENTRY(xen_irq_disable_direct) + movb $1, PER_CPU_VAR(xen_vcpu_info, XEN_vcpu_info_mask) +ENDPATCH(xen_irq_disable_direct) + ret + ENDPROC(xen_irq_disable_direct) + RELOC(xen_irq_disable_direct, 0) + +/* + (xen_)save_fl is used to get the current interrupt enable status. + Callers expect the status to be in X86_EFLAGS_IF, and other bits + may be set in the return value. We take advantage of this by + making sure that X86_EFLAGS_IF has the right value (and other bits + in that byte are 0), but other bits in the return value are + undefined. We need to toggle the state of the bit, because + Xen and x86 use opposite senses (mask vs enable). + */ +ENTRY(xen_save_fl_direct) + testb $0xff, PER_CPU_VAR(xen_vcpu_info, XEN_vcpu_info_mask) + setz %ah + addb %ah,%ah +ENDPATCH(xen_save_fl_direct) + ret + ENDPROC(xen_save_fl_direct) + RELOC(xen_save_fl_direct, 0) + +/* + In principle the caller should be passing us a value return + from xen_save_fl_direct, but for robustness sake we test only + the X86_EFLAGS_IF flag rather than the whole byte. After + setting the interrupt mask state, it checks for unmasked + pending events and enters the hypervisor to get them delivered + if so. + */ +ENTRY(xen_restore_fl_direct) + testb $X86_EFLAGS_IF>>8, %ah + setz PER_CPU_VAR(xen_vcpu_info, XEN_vcpu_info_mask) + /* Preempt here doesn't matter because that will deal with + any pending interrupts. The pending check may end up being + run on the wrong CPU, but that doesn't hurt. */ + + /* check for unmasked and pending */ + cmpw $0x0001, PER_CPU_VAR(xen_vcpu_info, XEN_vcpu_info_pending) + jz 1f +2: call check_events +1: +ENDPATCH(xen_restore_fl_direct) + ret + ENDPROC(xen_restore_fl_direct) + RELOC(xen_restore_fl_direct, 2b+1) + + +/* + Force an event check by making a hypercall, + but preserve regs before making the call. + */ +check_events: + push %rax + push %rcx + push %rdx + push %rsi + push %rdi + push %r8 + push %r9 + push %r10 + push %r11 + call force_evtchn_callback + pop %r11 + pop %r10 + pop %r9 + pop %r8 + pop %rdi + pop %rsi + pop %rdx + pop %rcx + pop %rax + ret +#endif + +ENTRY(xen_adjust_exception_frame) + mov 8+0(%rsp),%rcx + mov 8+8(%rsp),%r11 + ret $16 + +hypercall_iret = hypercall_page + __HYPERVISOR_iret * 32 +/* + Xen64 iret frame: + + ss + rsp + rflags + cs + rip <-- standard iret frame + + flags + + rcx } + r11 }<-- pushed by hypercall page +rsp -> rax } + */ +ENTRY(xen_iret) + pushq $0 +1: jmp hypercall_iret +ENDPATCH(xen_iret) +RELOC(xen_iret, 1b+1) + +/* + sysexit is not used for 64-bit processes, so it's + only ever used to return to 32-bit compat userspace. + */ +ENTRY(xen_sysexit) + pushq $__USER32_DS + pushq %rcx + pushq $X86_EFLAGS_IF + pushq $__USER32_CS + pushq %rdx + + pushq $VGCF_in_syscall +1: jmp hypercall_iret +ENDPATCH(xen_sysexit) +RELOC(xen_sysexit, 1b+1) + +ENTRY(xen_sysret64) + /* We're already on the usermode stack at this point, but still + with the kernel gs, so we can easily switch back */ + movq %rsp, %gs:pda_oldrsp + movq %gs:pda_kernelstack,%rsp + + pushq $__USER_DS + pushq %gs:pda_oldrsp + pushq %r11 + pushq $__USER_CS + pushq %rcx + + pushq $VGCF_in_syscall +1: jmp hypercall_iret +ENDPATCH(xen_sysret64) +RELOC(xen_sysret64, 1b+1) + +ENTRY(xen_sysret32) + /* We're already on the usermode stack at this point, but still + with the kernel gs, so we can easily switch back */ + movq %rsp, %gs:pda_oldrsp + movq %gs:pda_kernelstack, %rsp + + pushq $__USER32_DS + pushq %gs:pda_oldrsp + pushq %r11 + pushq $__USER32_CS + pushq %rcx + + pushq $VGCF_in_syscall +1: jmp hypercall_iret +ENDPATCH(xen_sysret32) +RELOC(xen_sysret32, 1b+1) + +/* + Xen handles syscall callbacks much like ordinary exceptions, + which means we have: + - kernel gs + - kernel rsp + - an iret-like stack frame on the stack (including rcx and r11): + ss + rsp + rflags + cs + rip + r11 + rsp-> rcx + + In all the entrypoints, we undo all that to make it look + like a CPU-generated syscall/sysenter and jump to the normal + entrypoint. + */ + +.macro undo_xen_syscall + mov 0*8(%rsp),%rcx + mov 1*8(%rsp),%r11 + mov 5*8(%rsp),%rsp +.endm + +/* Normal 64-bit system call target */ +ENTRY(xen_syscall_target) + undo_xen_syscall + jmp system_call_after_swapgs +ENDPROC(xen_syscall_target) + +#ifdef CONFIG_IA32_EMULATION + +/* 32-bit compat syscall target */ +ENTRY(xen_syscall32_target) + undo_xen_syscall + jmp ia32_cstar_target +ENDPROC(xen_syscall32_target) + +/* 32-bit compat sysenter target */ +ENTRY(xen_sysenter_target) + undo_xen_syscall + jmp ia32_sysenter_target +ENDPROC(xen_sysenter_target) + +#else /* !CONFIG_IA32_EMULATION */ + +ENTRY(xen_syscall32_target) +ENTRY(xen_sysenter_target) + lea 16(%rsp), %rsp /* strip %rcx,%r11 */ + mov $-ENOSYS, %rax + pushq $VGCF_in_syscall + jmp hypercall_iret +ENDPROC(xen_syscall32_target) +ENDPROC(xen_sysenter_target) + +#endif /* CONFIG_IA32_EMULATION */ diff --git a/arch/x86/xen/xen-head.S b/arch/x86/xen/xen-head.S index 7c0cf6320a0a..63d49a523ed3 100644 --- a/arch/x86/xen/xen-head.S +++ b/arch/x86/xen/xen-head.S @@ -5,15 +5,24 @@ #include <linux/elfnote.h> #include <linux/init.h> + #include <asm/boot.h> +#include <asm/asm.h> +#include <asm/page.h> + #include <xen/interface/elfnote.h> #include <asm/xen/interface.h> __INIT ENTRY(startup_xen) - movl %esi,xen_start_info cld - movl $(init_thread_union+THREAD_SIZE),%esp +#ifdef CONFIG_X86_32 + mov %esi,xen_start_info + mov $init_thread_union+THREAD_SIZE,%esp +#else + mov %rsi,xen_start_info + mov $init_thread_union+THREAD_SIZE,%rsp +#endif jmp xen_start_kernel __FINIT @@ -21,21 +30,26 @@ ENTRY(startup_xen) .pushsection .text .align PAGE_SIZE_asm ENTRY(hypercall_page) - .skip 0x1000 + .skip PAGE_SIZE_asm .popsection ELFNOTE(Xen, XEN_ELFNOTE_GUEST_OS, .asciz "linux") ELFNOTE(Xen, XEN_ELFNOTE_GUEST_VERSION, .asciz "2.6") ELFNOTE(Xen, XEN_ELFNOTE_XEN_VERSION, .asciz "xen-3.0") - ELFNOTE(Xen, XEN_ELFNOTE_VIRT_BASE, .long __PAGE_OFFSET) - ELFNOTE(Xen, XEN_ELFNOTE_ENTRY, .long startup_xen) - ELFNOTE(Xen, XEN_ELFNOTE_HYPERCALL_PAGE, .long hypercall_page) +#ifdef CONFIG_X86_32 + ELFNOTE(Xen, XEN_ELFNOTE_VIRT_BASE, _ASM_PTR __PAGE_OFFSET) +#else + ELFNOTE(Xen, XEN_ELFNOTE_VIRT_BASE, _ASM_PTR __START_KERNEL_map) +#endif + ELFNOTE(Xen, XEN_ELFNOTE_ENTRY, _ASM_PTR startup_xen) + ELFNOTE(Xen, XEN_ELFNOTE_HYPERCALL_PAGE, _ASM_PTR hypercall_page) ELFNOTE(Xen, XEN_ELFNOTE_FEATURES, .asciz "!writable_page_tables|pae_pgdir_above_4gb") ELFNOTE(Xen, XEN_ELFNOTE_PAE_MODE, .asciz "yes") ELFNOTE(Xen, XEN_ELFNOTE_LOADER, .asciz "generic") ELFNOTE(Xen, XEN_ELFNOTE_L1_MFN_VALID, .quad _PAGE_PRESENT; .quad _PAGE_PRESENT) ELFNOTE(Xen, XEN_ELFNOTE_SUSPEND_CANCEL, .long 1) - ELFNOTE(Xen, XEN_ELFNOTE_HV_START_LOW, .long __HYPERVISOR_VIRT_START) + ELFNOTE(Xen, XEN_ELFNOTE_HV_START_LOW, _ASM_PTR __HYPERVISOR_VIRT_START) + ELFNOTE(Xen, XEN_ELFNOTE_PADDR_OFFSET, _ASM_PTR 0) #endif /*CONFIG_XEN */ diff --git a/arch/x86/xen/xen-ops.h b/arch/x86/xen/xen-ops.h index 6f4b1045c1c2..dd3c23152a2e 100644 --- a/arch/x86/xen/xen-ops.h +++ b/arch/x86/xen/xen-ops.h @@ -26,6 +26,7 @@ char * __init xen_memory_setup(void); void __init xen_arch_setup(void); void __init xen_init_IRQ(void); void xen_enable_sysenter(void); +void xen_enable_syscall(void); void xen_vcpu_restore(void); void __init xen_build_dynamic_phys_to_machine(void); @@ -37,7 +38,6 @@ void __init xen_time_init(void); unsigned long xen_get_wallclock(void); int xen_set_wallclock(unsigned long time); unsigned long long xen_sched_clock(void); -void xen_timer_resume(void); irqreturn_t xen_debug_interrupt(int irq, void *dev_id); @@ -45,20 +45,15 @@ bool xen_vcpu_stolen(int vcpu); void xen_mark_init_mm_pinned(void); -void __init xen_fill_possible_map(void); - void __init xen_setup_vcpu_info_placement(void); -void xen_smp_prepare_boot_cpu(void); -void xen_smp_prepare_cpus(unsigned int max_cpus); -int xen_cpu_up(unsigned int cpu); -void xen_smp_cpus_done(unsigned int max_cpus); -void xen_smp_send_stop(void); -void xen_smp_send_reschedule(int cpu); -void xen_smp_send_call_function_ipi(cpumask_t mask); -void xen_smp_send_call_function_single_ipi(int cpu); +#ifdef CONFIG_SMP +void xen_smp_init(void); extern cpumask_t xen_cpu_initialized_map; +#else +static inline void xen_smp_init(void) {} +#endif /* Declare an asm function, along with symbols needed to make it @@ -73,7 +68,11 @@ DECL_ASM(void, xen_irq_disable_direct, void); DECL_ASM(unsigned long, xen_save_fl_direct, void); DECL_ASM(void, xen_restore_fl_direct, unsigned long); +/* These are not functions, and cannot be called normally */ void xen_iret(void); void xen_sysexit(void); +void xen_sysret32(void); +void xen_sysret64(void); +void xen_adjust_exception_frame(void); #endif /* XEN_OPS_H */ diff --git a/drivers/Makefile b/drivers/Makefile index fda44679dffc..808e0ae66aa8 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -10,7 +10,6 @@ obj-$(CONFIG_PCI) += pci/ obj-$(CONFIG_PARISC) += parisc/ obj-$(CONFIG_RAPIDIO) += rapidio/ obj-y += video/ -obj-y += gpu/ obj-$(CONFIG_ACPI) += acpi/ # PnP must come after ACPI since it will eventually need to check if acpi # was used and do nothing if so @@ -23,6 +22,9 @@ obj-$(CONFIG_XEN) += xen/ # default. obj-y += char/ +# gpu/ comes after char for AGP vs DRM startup +obj-y += gpu/ + obj-$(CONFIG_CONNECTOR) += connector/ # i810fb and intelfb depend on char/agp/ diff --git a/drivers/acpi/bay.c b/drivers/acpi/bay.c index e6caf5d42e0e..61b6c5beb2d3 100644 --- a/drivers/acpi/bay.c +++ b/drivers/acpi/bay.c @@ -380,9 +380,6 @@ static int __init bay_init(void) if (acpi_disabled) return -ENODEV; - if (acpi_disabled) - return -ENODEV; - /* look for dockable drive bays */ acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, ACPI_UINT32_MAX, find_bay, &bays, NULL); diff --git a/drivers/acpi/dock.c b/drivers/acpi/dock.c index 1e872e79db33..bb7c51f712bd 100644 --- a/drivers/acpi/dock.c +++ b/drivers/acpi/dock.c @@ -920,9 +920,6 @@ static int __init dock_init(void) if (acpi_disabled) return 0; - if (acpi_disabled) - return 0; - /* look for a dock station */ acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, ACPI_UINT32_MAX, find_dock, &num, NULL); diff --git a/drivers/acpi/glue.c b/drivers/acpi/glue.c index 0f2dd81736bd..2f173e83f8a7 100644 --- a/drivers/acpi/glue.c +++ b/drivers/acpi/glue.c @@ -338,9 +338,6 @@ static int __init acpi_rtc_init(void) if (acpi_disabled) return 0; - if (acpi_disabled) - return 0; - if (dev) { rtc_wake_setup(); rtc_info.wake_on = rtc_wake_on; diff --git a/drivers/atm/Kconfig b/drivers/atm/Kconfig index b554edac1ced..f197a193633a 100644 --- a/drivers/atm/Kconfig +++ b/drivers/atm/Kconfig @@ -294,7 +294,7 @@ config ATM_HORIZON_DEBUG config ATM_IA tristate "Interphase ATM PCI x575/x525/x531" - depends on PCI && !64BIT + depends on PCI ---help--- This is a driver for the Interphase (i)ChipSAR adapter cards which include a variety of variants in term of the size of the @@ -325,81 +325,22 @@ config ATM_IA_DEBUG speed of the driver, and the size of your syslog files! When inactive, they will have only a modest impact on performance. -config ATM_FORE200E_MAYBE +config ATM_FORE200E tristate "FORE Systems 200E-series" - depends on PCI || SBUS + depends on (PCI || SBUS) + select FW_LOADER ---help--- This is a driver for the FORE Systems 200E-series ATM adapter cards. It simultaneously supports PCA-200E and SBA-200E models on PCI and SBUS hosts. Say Y (or M to compile as a module named fore_200e) here if you have one of these ATM adapters. - Note that the driver will actually be compiled only if you - additionally enable the support for PCA-200E and/or SBA-200E - cards. - See the file <file:Documentation/networking/fore200e.txt> for further details. -config ATM_FORE200E_PCA - bool "PCA-200E support" - depends on ATM_FORE200E_MAYBE && PCI - help - Say Y here if you want your PCA-200E cards to be probed. - -config ATM_FORE200E_PCA_DEFAULT_FW - bool "Use default PCA-200E firmware (normally enabled)" - depends on ATM_FORE200E_PCA - help - Use the default PCA-200E firmware data shipped with the driver. - - Normal users do not have to deal with the firmware stuff, so - they should say Y here. - -config ATM_FORE200E_PCA_FW - string "Pathname of user-supplied binary firmware" - depends on ATM_FORE200E_PCA && !ATM_FORE200E_PCA_DEFAULT_FW - default "" - help - This defines the pathname of an alternative PCA-200E binary - firmware image supplied by the user. This pathname may be - absolute or relative to the drivers/atm directory. - - The driver comes with an adequate firmware image, so normal users do - not have to supply an alternative one. They just say Y to "Use - default PCA-200E firmware" instead. - -config ATM_FORE200E_SBA - bool "SBA-200E support" - depends on ATM_FORE200E_MAYBE && SBUS - help - Say Y here if you want your SBA-200E cards to be probed. - -config ATM_FORE200E_SBA_DEFAULT_FW - bool "Use default SBA-200E firmware (normally enabled)" - depends on ATM_FORE200E_SBA - help - Use the default SBA-200E firmware data shipped with the driver. - - Normal users do not have to deal with the firmware stuff, so - they should say Y here. - -config ATM_FORE200E_SBA_FW - string "Pathname of user-supplied binary firmware" - depends on ATM_FORE200E_SBA && !ATM_FORE200E_SBA_DEFAULT_FW - default "" - help - This defines the pathname of an alternative SBA-200E binary - firmware image supplied by the user. This pathname may be - absolute or relative to the drivers/atm directory. - - The driver comes with an adequate firmware image, so normal users do - not have to supply an alternative one. They just say Y to "Use - default SBA-200E firmware", above. - config ATM_FORE200E_USE_TASKLET bool "Defer interrupt work to a tasklet" - depends on (PCI || SBUS) && (ATM_FORE200E_PCA || ATM_FORE200E_SBA) + depends on ATM_FORE200E default n help This defers work to be done by the interrupt handler to a @@ -408,7 +349,7 @@ config ATM_FORE200E_USE_TASKLET config ATM_FORE200E_TX_RETRY int "Maximum number of tx retries" - depends on (PCI || SBUS) && (ATM_FORE200E_PCA || ATM_FORE200E_SBA) + depends on ATM_FORE200E default "16" ---help--- Specifies the number of times the driver attempts to transmit @@ -425,7 +366,7 @@ config ATM_FORE200E_TX_RETRY config ATM_FORE200E_DEBUG int "Debugging level (0-3)" - depends on (PCI || SBUS) && (ATM_FORE200E_PCA || ATM_FORE200E_SBA) + depends on ATM_FORE200E default "0" help Specifies the level of debugging messages issued by the driver. @@ -436,12 +377,6 @@ config ATM_FORE200E_DEBUG the performances of the driver, and the size of your syslog files! Keep the debugging level to 0 during normal operations. -config ATM_FORE200E - tristate - depends on (PCI || SBUS) && (ATM_FORE200E_PCA || ATM_FORE200E_SBA) - default m if ATM_FORE200E_MAYBE!=y - default y if ATM_FORE200E_MAYBE=y - config ATM_HE tristate "ForeRunner HE Series" depends on PCI diff --git a/drivers/atm/Makefile b/drivers/atm/Makefile index 749266e955cd..0bfb31748ecf 100644 --- a/drivers/atm/Makefile +++ b/drivers/atm/Makefile @@ -3,14 +3,6 @@ # fore_200e-objs := fore200e.o -hostprogs-y := fore200e_mkfirm - -# Files generated that shall be removed upon make clean -clean-files := pca200e.bin pca200e.bin1 pca200e.bin2 pca200e_ecd.bin \ - pca200e_ecd.bin1 pca200e_ecd.bin2 sba200e_ecd.bin sba200e_ecd.bin1 \ - sba200e_ecd.bin2 -# Firmware generated that shall be removed upon make clean -clean-files += fore200e_pca_fw.c fore200e_sba_fw.c obj-$(CONFIG_ATM_ZATM) += zatm.o uPD98402.o obj-$(CONFIG_ATM_NICSTAR) += nicstar.o @@ -36,38 +28,7 @@ obj-$(CONFIG_ATM_TCP) += atmtcp.o obj-$(CONFIG_ATM_FIRESTREAM) += firestream.o obj-$(CONFIG_ATM_LANAI) += lanai.o -ifeq ($(CONFIG_ATM_FORE200E_PCA),y) - fore_200e-objs += fore200e_pca_fw.o - # guess the target endianess to choose the right PCA-200E firmware image - ifeq ($(CONFIG_ATM_FORE200E_PCA_DEFAULT_FW),y) - byteorder.h := include$(if $(patsubst $(srctree),,$(objtree)),2)/asm/byteorder.h - CONFIG_ATM_FORE200E_PCA_FW := $(obj)/pca200e$(if $(shell $(CC) $(KBUILD_CPPFLAGS) -E -dM $(byteorder.h) | grep ' __LITTLE_ENDIAN '),.bin,_ecd.bin2) - endif -endif - -ifeq ($(CONFIG_ATM_FORE200E_SBA),y) - fore_200e-objs += fore200e_sba_fw.o - ifeq ($(CONFIG_ATM_FORE200E_SBA_DEFAULT_FW),y) - CONFIG_ATM_FORE200E_SBA_FW := $(obj)/sba200e_ecd.bin2 - endif -endif obj-$(CONFIG_ATM_HE) += he.o ifeq ($(CONFIG_ATM_HE_USE_SUNI),y) obj-$(CONFIG_ATM_HE) += suni.o endif - -# FORE Systems 200E-series firmware magic -$(obj)/fore200e_pca_fw.c: $(patsubst "%", %, $(CONFIG_ATM_FORE200E_PCA_FW)) \ - $(obj)/fore200e_mkfirm - $(obj)/fore200e_mkfirm -k -b _fore200e_pca_fw \ - -i $(CONFIG_ATM_FORE200E_PCA_FW) -o $@ - -$(obj)/fore200e_sba_fw.c: $(patsubst "%", %, $(CONFIG_ATM_FORE200E_SBA_FW)) \ - $(obj)/fore200e_mkfirm - $(obj)/fore200e_mkfirm -k -b _fore200e_sba_fw \ - -i $(CONFIG_ATM_FORE200E_SBA_FW) -o $@ - -# deal with the various suffixes of the binary firmware images -$(obj)/%.bin $(obj)/%.bin1 $(obj)/%.bin2: $(src)/%.data - objcopy -Iihex $< -Obinary $@.gz - gzip -n -df $@.gz diff --git a/drivers/atm/fore200e.c b/drivers/atm/fore200e.c index 432181ed7bb5..d5c1bbfbe79d 100644 --- a/drivers/atm/fore200e.c +++ b/drivers/atm/fore200e.c @@ -36,6 +36,7 @@ #include <linux/atm_suni.h> #include <linux/dma-mapping.h> #include <linux/delay.h> +#include <linux/firmware.h> #include <asm/io.h> #include <asm/string.h> #include <asm/page.h> @@ -45,7 +46,7 @@ #include <asm/uaccess.h> #include <asm/atomic.h> -#ifdef CONFIG_ATM_FORE200E_SBA +#ifdef CONFIG_SBUS #include <asm/idprom.h> #include <asm/sbus.h> #include <asm/openprom.h> @@ -382,9 +383,6 @@ fore200e_shutdown(struct fore200e* fore200e) case FORE200E_STATE_START_FW: /* nothing to do for that state */ - case FORE200E_STATE_LOAD_FW: - /* nothing to do for that state */ - case FORE200E_STATE_RESET: /* nothing to do for that state */ @@ -405,7 +403,7 @@ fore200e_shutdown(struct fore200e* fore200e) } -#ifdef CONFIG_ATM_FORE200E_PCA +#ifdef CONFIG_PCI static u32 fore200e_pca_read(volatile u32 __iomem *addr) { @@ -658,10 +656,10 @@ fore200e_pca_proc_read(struct fore200e* fore200e, char *page) pci_dev->bus->number, PCI_SLOT(pci_dev->devfn), PCI_FUNC(pci_dev->devfn)); } -#endif /* CONFIG_ATM_FORE200E_PCA */ +#endif /* CONFIG_PCI */ -#ifdef CONFIG_ATM_FORE200E_SBA +#ifdef CONFIG_SBUS static u32 fore200e_sba_read(volatile u32 __iomem *addr) @@ -907,7 +905,7 @@ fore200e_sba_proc_read(struct fore200e* fore200e, char *page) return sprintf(page, " SBUS slot/device:\t\t%d/'%s'\n", sbus_dev->slot, sbus_dev->prom_name); } -#endif /* CONFIG_ATM_FORE200E_SBA */ +#endif /* CONFIG_SBUS */ static void @@ -2552,13 +2550,53 @@ fore200e_monitor_puts(struct fore200e* fore200e, char* str) while (fore200e_monitor_getc(fore200e) >= 0); } +#ifdef __LITTLE_ENDIAN +#define FW_EXT ".bin" +#else +#define FW_EXT "_ecd.bin2" +#endif static int __devinit -fore200e_start_fw(struct fore200e* fore200e) -{ - int ok; - char cmd[ 48 ]; - struct fw_header* fw_header = (struct fw_header*) fore200e->bus->fw_data; +fore200e_load_and_start_fw(struct fore200e* fore200e) +{ + const struct firmware *firmware; + struct device *device; + struct fw_header *fw_header; + u32 *fw_data, fw_size; + u32 __iomem *load_addr; + char buf[48]; + int err = -ENODEV; + + if (strcmp(fore200e->bus->model_name, "PCA-200E") == 0) + device = &((struct pci_dev *) fore200e->bus_dev)->dev; +#ifdef CONFIG_SBUS + else if (strcmp(fore200e->bus->model_name, "SBA-200E") == 0) + device = &((struct sbus_dev *) fore200e->bus_dev)->ofdev.dev; +#endif + else + return err; + + sprintf(buf, "%s%s", fore200e->bus->proc_name, FW_EXT); + if (request_firmware(&firmware, buf, device) == 1) { + printk(FORE200E "missing %s firmware image\n", fore200e->bus->model_name); + return err; + } + + fw_data = (u32 *) firmware->data; + fw_size = firmware->size / sizeof(u32); + fw_header = (struct fw_header *) firmware->data; + load_addr = fore200e->virt_base + le32_to_cpu(fw_header->load_offset); + + DPRINTK(2, "device %s firmware being loaded at 0x%p (%d words)\n", + fore200e->name, load_addr, fw_size); + + if (le32_to_cpu(fw_header->magic) != FW_HEADER_MAGIC) { + printk(FORE200E "corrupted %s firmware image\n", fore200e->bus->model_name); + goto release; + } + + for (; fw_size--; fw_data++, load_addr++) + fore200e->bus->write(le32_to_cpu(*fw_data), load_addr); DPRINTK(2, "device %s firmware being started\n", fore200e->name); @@ -2567,46 +2605,22 @@ fore200e_start_fw(struct fore200e* fore200e) fore200e_spin(100); #endif - sprintf(cmd, "\rgo %x\r", le32_to_cpu(fw_header->start_offset)); + sprintf(buf, "\rgo %x\r", le32_to_cpu(fw_header->start_offset)); + fore200e_monitor_puts(fore200e, buf); - fore200e_monitor_puts(fore200e, cmd); - - ok = fore200e_io_poll(fore200e, &fore200e->cp_monitor->bstat, BSTAT_CP_RUNNING, 1000); - if (ok == 0) { + if (fore200e_io_poll(fore200e, &fore200e->cp_monitor->bstat, BSTAT_CP_RUNNING, 1000) == 0) { printk(FORE200E "device %s firmware didn't start\n", fore200e->name); - return -ENODEV; + goto release; } printk(FORE200E "device %s firmware started\n", fore200e->name); fore200e->state = FORE200E_STATE_START_FW; - return 0; -} + err = 0; - -static int __devinit -fore200e_load_fw(struct fore200e* fore200e) -{ - __le32* fw_data = (__le32*) fore200e->bus->fw_data; - u32 fw_size = (u32) *fore200e->bus->fw_size / sizeof(u32); - - struct fw_header* fw_header = (struct fw_header*) fw_data; - - u32 __iomem *load_addr = fore200e->virt_base + le32_to_cpu(fw_header->load_offset); - - DPRINTK(2, "device %s firmware being loaded at 0x%p (%d words)\n", - fore200e->name, load_addr, fw_size); - - if (le32_to_cpu(fw_header->magic) != FW_HEADER_MAGIC) { - printk(FORE200E "corrupted %s firmware image\n", fore200e->bus->model_name); - return -ENODEV; - } - - for (; fw_size--; fw_data++, load_addr++) - fore200e->bus->write(le32_to_cpu(*fw_data), load_addr); - - fore200e->state = FORE200E_STATE_LOAD_FW; - return 0; +release: + release_firmware(firmware); + return err; } @@ -2652,10 +2666,7 @@ fore200e_init(struct fore200e* fore200e) if (fore200e_reset(fore200e, 1) < 0) return -ENODEV; - if (fore200e_load_fw(fore200e) < 0) - return -ENODEV; - - if (fore200e_start_fw(fore200e) < 0) + if (fore200e_load_and_start_fw(fore200e) < 0) return -ENODEV; if (fore200e_initialize(fore200e) < 0) @@ -2689,7 +2700,7 @@ fore200e_init(struct fore200e* fore200e) return 0; } -#ifdef CONFIG_ATM_FORE200E_PCA +#ifdef CONFIG_PCI static int __devinit fore200e_pca_detect(struct pci_dev *pci_dev, const struct pci_device_id *pci_ent) { @@ -2804,7 +2815,7 @@ fore200e_module_init(void) } } -#ifdef CONFIG_ATM_FORE200E_PCA +#ifdef CONFIG_PCI if (!pci_register_driver(&fore200e_pca_driver)) return 0; #endif @@ -2821,7 +2832,7 @@ fore200e_module_cleanup(void) { struct fore200e *fore200e, *next; -#ifdef CONFIG_ATM_FORE200E_PCA +#ifdef CONFIG_PCI pci_unregister_driver(&fore200e_pca_driver); #endif @@ -3140,19 +3151,9 @@ static const struct atmdev_ops fore200e_ops = }; -#ifdef CONFIG_ATM_FORE200E_PCA -extern const unsigned char _fore200e_pca_fw_data[]; -extern const unsigned int _fore200e_pca_fw_size; -#endif -#ifdef CONFIG_ATM_FORE200E_SBA -extern const unsigned char _fore200e_sba_fw_data[]; -extern const unsigned int _fore200e_sba_fw_size; -#endif - static const struct fore200e_bus fore200e_bus[] = { -#ifdef CONFIG_ATM_FORE200E_PCA +#ifdef CONFIG_PCI { "PCA-200E", "pca200e", 32, 4, 32, - _fore200e_pca_fw_data, &_fore200e_pca_fw_size, fore200e_pca_read, fore200e_pca_write, fore200e_pca_dma_map, @@ -3173,9 +3174,8 @@ static const struct fore200e_bus fore200e_bus[] = { fore200e_pca_proc_read, }, #endif -#ifdef CONFIG_ATM_FORE200E_SBA +#ifdef CONFIG_SBUS { "SBA-200E", "sba200e", 32, 64, 32, - _fore200e_sba_fw_data, &_fore200e_sba_fw_size, fore200e_sba_read, fore200e_sba_write, fore200e_sba_dma_map, diff --git a/drivers/atm/fore200e.h b/drivers/atm/fore200e.h index 8dd4aa76c3bd..5c6e7adcb19c 100644 --- a/drivers/atm/fore200e.h +++ b/drivers/atm/fore200e.h @@ -754,7 +754,6 @@ typedef enum fore200e_state { FORE200E_STATE_CONFIGURE, /* bus interface configured */ FORE200E_STATE_MAP, /* board space mapped in host memory */ FORE200E_STATE_RESET, /* board resetted */ - FORE200E_STATE_LOAD_FW, /* firmware loaded */ FORE200E_STATE_START_FW, /* firmware started */ FORE200E_STATE_INITIALIZE, /* initialize command successful */ FORE200E_STATE_INIT_CMDQ, /* command queue initialized */ @@ -803,8 +802,6 @@ typedef struct fore200e_bus { int descr_alignment; /* tpd/rpd/rbd DMA alignment requirement */ int buffer_alignment; /* rx buffers DMA alignment requirement */ int status_alignment; /* status words DMA alignment requirement */ - const unsigned char* fw_data; /* address of firmware data start */ - const unsigned int* fw_size; /* address of firmware data size */ u32 (*read)(volatile u32 __iomem *); void (*write)(u32, volatile u32 __iomem *); u32 (*dma_map)(struct fore200e*, void*, int, int); diff --git a/drivers/atm/fore200e_firmware_copyright b/drivers/atm/fore200e_firmware_copyright deleted file mode 100644 index d58e6490836e..000000000000 --- a/drivers/atm/fore200e_firmware_copyright +++ /dev/null @@ -1,31 +0,0 @@ - -These microcode data are placed under the terms of the GNU General Public License. - -We would prefer you not to distribute modified versions of it and not to ask -for assembly or other microcode source. - -Copyright (c) 1995-2000 FORE Systems, Inc., as an unpublished work. This -notice does not imply unrestricted or public access to these materials which -are a trade secret of FORE Systems, Inc. or its subsidiaries or affiliates -(together referred to as "FORE"), and which may not be reproduced, used, sold -or transferred to any third party without FORE's prior written consent. All -rights reserved. - -U.S. Government Restricted Rights. If you are licensing the Software on -behalf of the U.S. Government ("Government"), the following provisions apply -to you. If the software is supplied to the Department of Defense ("DoD"), it -is classified as "Commercial Computer Software" under paragraph 252.227-7014 -of the DoD Supplement to the Federal Acquisition Regulations ("DFARS") (or any -successor regulations) and the Government is acquiring only the license -rights granted herein (the license rights customarily provided to non-Government -users). If the Software is supplied to any unit or agency of the Government -other than the DoD, it is classified as "Restricted Computer Software" and -the Government's rights in the Software are defined in paragraph 52.227-19 of -the Federal Acquisition Regulations ("FAR") (or any successor regulations) or, -in the cases of NASA, in paragraph 18.52.227-86 of the NASA Supplement to the FAR -(or any successor regulations). - -FORE Systems is a registered trademark, and ForeRunner, ForeRunnerLE, and -ForeThought are trademarks of FORE Systems, Inc. All other brands or product -names are trademarks or registered trademarks of their respective holders. - diff --git a/drivers/atm/fore200e_mkfirm.c b/drivers/atm/fore200e_mkfirm.c deleted file mode 100644 index 520e14b488ff..000000000000 --- a/drivers/atm/fore200e_mkfirm.c +++ /dev/null @@ -1,154 +0,0 @@ -/* - mkfirm.c: generates a C readable file from a binary firmware image - - Christophe Lizzi (lizzi@{csti.fr, cnam.fr}), June 1999. - - This software may be used and distributed according to the terms - of the GNU General Public License, incorporated herein by reference. -*/ - -#include <stdio.h> -#include <stdlib.h> -#include <sys/types.h> -#include <time.h> - -char* default_basename = "pca200e"; /* was initially written for the PCA-200E firmware */ -char* default_infname = "<stdin>"; -char* default_outfname = "<stdout>"; - -char* progname; -int verbose = 0; -int inkernel = 0; - - -void usage(void) -{ - fprintf(stderr, - "%s: [-v] [-k] [-b basename ] [-i firmware.bin] [-o firmware.c]\n", - progname); - exit(-1); -} - - -int main(int argc, char** argv) -{ - time_t now; - char* infname = NULL; - char* outfname = NULL; - char* basename = NULL; - FILE* infile; - FILE* outfile; - unsigned firmsize; - int c; - - progname = *(argv++); - - while (argc > 1) { - if ((*argv)[0] == '-') { - switch ((*argv)[1]) { - case 'i': - if (argc-- < 3) - usage(); - infname = *(++argv); - break; - case 'o': - if (argc-- < 3) - usage(); - outfname = *(++argv); - break; - case 'b': - if (argc-- < 3) - usage(); - basename = *(++argv); - break; - case 'v': - verbose = 1; - break; - case 'k': - inkernel = 1; - break; - default: - usage(); - } - } - else { - usage(); - } - argc--; - argv++; - } - - if (infname != NULL) { - infile = fopen(infname, "r"); - if (infile == NULL) { - fprintf(stderr, "%s: can't open %s for reading\n", - progname, infname); - exit(-2); - } - } - else { - infile = stdin; - infname = default_infname; - } - - if (outfname) { - outfile = fopen(outfname, "w"); - if (outfile == NULL) { - fprintf(stderr, "%s: can't open %s for writing\n", - progname, outfname); - exit(-3); - } - } - else { - outfile = stdout; - outfname = default_outfname; - } - - if (basename == NULL) - basename = default_basename; - - if (verbose) { - fprintf(stderr, "%s: input file = %s\n", progname, infname ); - fprintf(stderr, "%s: output file = %s\n", progname, outfname ); - fprintf(stderr, "%s: firmware basename = %s\n", progname, basename ); - } - - time(&now); - fprintf(outfile, "/*\n generated by %s from %s on %s" - " DO NOT EDIT!\n*/\n\n", - progname, infname, ctime(&now)); - - if (inkernel) - fprintf(outfile, "#include <linux/init.h>\n\n" ); - - /* XXX force 32 bit alignment? */ - fprintf(outfile, "const unsigned char%s %s_data[] = {\n", - inkernel ? " __initdata" : "", basename ); - - c = getc(infile); - fprintf(outfile,"\t0x%02x", c); - firmsize = 1; - - while ((c = getc(infile)) >= 0) { - - if (firmsize++ % 8) - fprintf(outfile,", 0x%02x", c); - else - fprintf(outfile,",\n\t0x%02x", c); - } - - fprintf(outfile, "\n};\n\n"); - - fprintf(outfile, "const unsigned int%s %s_size = %u;\n", - inkernel ? " __initdata" : "", basename, firmsize ); - - if (infile != stdin) - fclose(infile); - if (outfile != stdout) - fclose(outfile); - - if(verbose) - fprintf(stderr, "%s: firmware size = %u\n", progname, firmsize); - - exit(0); -} diff --git a/drivers/atm/he.c b/drivers/atm/he.c index ea495b21f916..bdbad7edf682 100644 --- a/drivers/atm/he.c +++ b/drivers/atm/he.c @@ -75,14 +75,8 @@ #include <linux/atm.h> #include <linux/sonet.h> -#define USE_TASKLET #undef USE_SCATTERGATHER #undef USE_CHECKSUM_HW /* still confused about this */ -#define USE_RBPS -#undef USE_RBPS_POOL /* if memory is tight try this */ -#undef USE_RBPL_POOL /* if memory is tight try this */ -#define USE_TPD_POOL -/* #undef CONFIG_ATM_HE_USE_SUNI */ /* #undef HE_DEBUG */ #include "he.h" @@ -388,9 +382,7 @@ he_init_one(struct pci_dev *pci_dev, const struct pci_device_id *pci_ent) he_dev->atm_dev->dev_data = he_dev; atm_dev->dev_data = he_dev; he_dev->number = atm_dev->number; -#ifdef USE_TASKLET tasklet_init(&he_dev->tasklet, he_tasklet, (unsigned long) he_dev); -#endif spin_lock_init(&he_dev->global_lock); if (he_start(atm_dev)) { @@ -787,23 +779,13 @@ he_init_group(struct he_dev *he_dev, int group) { int i; -#ifdef USE_RBPS /* small buffer pool */ -#ifdef USE_RBPS_POOL he_dev->rbps_pool = pci_pool_create("rbps", he_dev->pci_dev, CONFIG_RBPS_BUFSIZE, 8, 0); if (he_dev->rbps_pool == NULL) { hprintk("unable to create rbps pages\n"); return -ENOMEM; } -#else /* !USE_RBPS_POOL */ - he_dev->rbps_pages = pci_alloc_consistent(he_dev->pci_dev, - CONFIG_RBPS_SIZE * CONFIG_RBPS_BUFSIZE, &he_dev->rbps_pages_phys); - if (he_dev->rbps_pages == NULL) { - hprintk("unable to create rbps page pool\n"); - return -ENOMEM; - } -#endif /* USE_RBPS_POOL */ he_dev->rbps_base = pci_alloc_consistent(he_dev->pci_dev, CONFIG_RBPS_SIZE * sizeof(struct he_rbp), &he_dev->rbps_phys); @@ -818,14 +800,9 @@ he_init_group(struct he_dev *he_dev, int group) dma_addr_t dma_handle; void *cpuaddr; -#ifdef USE_RBPS_POOL cpuaddr = pci_pool_alloc(he_dev->rbps_pool, GFP_KERNEL|GFP_DMA, &dma_handle); if (cpuaddr == NULL) return -ENOMEM; -#else - cpuaddr = he_dev->rbps_pages + (i * CONFIG_RBPS_BUFSIZE); - dma_handle = he_dev->rbps_pages_phys + (i * CONFIG_RBPS_BUFSIZE); -#endif he_dev->rbps_virt[i].virt = cpuaddr; he_dev->rbps_base[i].status = RBP_LOANED | RBP_SMALLBUF | (i << RBP_INDEX_OFF); @@ -844,30 +821,14 @@ he_init_group(struct he_dev *he_dev, int group) RBP_QSIZE(CONFIG_RBPS_SIZE - 1) | RBP_INT_ENB, G0_RBPS_QI + (group * 32)); -#else /* !USE_RBPS */ - he_writel(he_dev, 0x0, G0_RBPS_S + (group * 32)); - he_writel(he_dev, 0x0, G0_RBPS_T + (group * 32)); - he_writel(he_dev, 0x0, G0_RBPS_QI + (group * 32)); - he_writel(he_dev, RBP_THRESH(0x1) | RBP_QSIZE(0x0), - G0_RBPS_BS + (group * 32)); -#endif /* USE_RBPS */ /* large buffer pool */ -#ifdef USE_RBPL_POOL he_dev->rbpl_pool = pci_pool_create("rbpl", he_dev->pci_dev, CONFIG_RBPL_BUFSIZE, 8, 0); if (he_dev->rbpl_pool == NULL) { hprintk("unable to create rbpl pool\n"); return -ENOMEM; } -#else /* !USE_RBPL_POOL */ - he_dev->rbpl_pages = (void *) pci_alloc_consistent(he_dev->pci_dev, - CONFIG_RBPL_SIZE * CONFIG_RBPL_BUFSIZE, &he_dev->rbpl_pages_phys); - if (he_dev->rbpl_pages == NULL) { - hprintk("unable to create rbpl pages\n"); - return -ENOMEM; - } -#endif /* USE_RBPL_POOL */ he_dev->rbpl_base = pci_alloc_consistent(he_dev->pci_dev, CONFIG_RBPL_SIZE * sizeof(struct he_rbp), &he_dev->rbpl_phys); @@ -882,14 +843,9 @@ he_init_group(struct he_dev *he_dev, int group) dma_addr_t dma_handle; void *cpuaddr; -#ifdef USE_RBPL_POOL cpuaddr = pci_pool_alloc(he_dev->rbpl_pool, GFP_KERNEL|GFP_DMA, &dma_handle); if (cpuaddr == NULL) return -ENOMEM; -#else - cpuaddr = he_dev->rbpl_pages + (i * CONFIG_RBPL_BUFSIZE); - dma_handle = he_dev->rbpl_pages_phys + (i * CONFIG_RBPL_BUFSIZE); -#endif he_dev->rbpl_virt[i].virt = cpuaddr; he_dev->rbpl_base[i].status = RBP_LOANED | (i << RBP_INDEX_OFF); @@ -1475,7 +1431,6 @@ he_start(struct atm_dev *dev) he_init_tpdrq(he_dev); -#ifdef USE_TPD_POOL he_dev->tpd_pool = pci_pool_create("tpd", he_dev->pci_dev, sizeof(struct he_tpd), TPD_ALIGNMENT, 0); if (he_dev->tpd_pool == NULL) { @@ -1484,20 +1439,6 @@ he_start(struct atm_dev *dev) } INIT_LIST_HEAD(&he_dev->outstanding_tpds); -#else - he_dev->tpd_base = (void *) pci_alloc_consistent(he_dev->pci_dev, - CONFIG_NUMTPDS * sizeof(struct he_tpd), &he_dev->tpd_base_phys); - if (!he_dev->tpd_base) - return -ENOMEM; - - for (i = 0; i < CONFIG_NUMTPDS; ++i) { - he_dev->tpd_base[i].status = (i << TPD_ADDR_SHIFT); - he_dev->tpd_base[i].inuse = 0; - } - - he_dev->tpd_head = he_dev->tpd_base; - he_dev->tpd_end = &he_dev->tpd_base[CONFIG_NUMTPDS - 1]; -#endif if (he_init_group(he_dev, 0) != 0) return -ENOMEM; @@ -1606,9 +1547,7 @@ he_stop(struct he_dev *he_dev) gen_cntl_0 &= ~(INT_PROC_ENBL | INIT_ENB); pci_write_config_dword(pci_dev, GEN_CNTL_0, gen_cntl_0); -#ifdef USE_TASKLET tasklet_disable(&he_dev->tasklet); -#endif /* disable recv and transmit */ @@ -1638,7 +1577,6 @@ he_stop(struct he_dev *he_dev) he_dev->hsp, he_dev->hsp_phys); if (he_dev->rbpl_base) { -#ifdef USE_RBPL_POOL int i; for (i = 0; i < CONFIG_RBPL_SIZE; ++i) { @@ -1647,22 +1585,14 @@ he_stop(struct he_dev *he_dev) pci_pool_free(he_dev->rbpl_pool, cpuaddr, dma_handle); } -#else - pci_free_consistent(he_dev->pci_dev, CONFIG_RBPL_SIZE - * CONFIG_RBPL_BUFSIZE, he_dev->rbpl_pages, he_dev->rbpl_pages_phys); -#endif pci_free_consistent(he_dev->pci_dev, CONFIG_RBPL_SIZE * sizeof(struct he_rbp), he_dev->rbpl_base, he_dev->rbpl_phys); } -#ifdef USE_RBPL_POOL if (he_dev->rbpl_pool) pci_pool_destroy(he_dev->rbpl_pool); -#endif -#ifdef USE_RBPS if (he_dev->rbps_base) { -#ifdef USE_RBPS_POOL int i; for (i = 0; i < CONFIG_RBPS_SIZE; ++i) { @@ -1671,20 +1601,12 @@ he_stop(struct he_dev *he_dev) pci_pool_free(he_dev->rbps_pool, cpuaddr, dma_handle); } -#else - pci_free_consistent(he_dev->pci_dev, CONFIG_RBPS_SIZE - * CONFIG_RBPS_BUFSIZE, he_dev->rbps_pages, he_dev->rbps_pages_phys); -#endif pci_free_consistent(he_dev->pci_dev, CONFIG_RBPS_SIZE * sizeof(struct he_rbp), he_dev->rbps_base, he_dev->rbps_phys); } -#ifdef USE_RBPS_POOL if (he_dev->rbps_pool) pci_pool_destroy(he_dev->rbps_pool); -#endif - -#endif /* USE_RBPS */ if (he_dev->rbrq_base) pci_free_consistent(he_dev->pci_dev, CONFIG_RBRQ_SIZE * sizeof(struct he_rbrq), @@ -1698,14 +1620,8 @@ he_stop(struct he_dev *he_dev) pci_free_consistent(he_dev->pci_dev, CONFIG_TBRQ_SIZE * sizeof(struct he_tbrq), he_dev->tpdrq_base, he_dev->tpdrq_phys); -#ifdef USE_TPD_POOL if (he_dev->tpd_pool) pci_pool_destroy(he_dev->tpd_pool); -#else - if (he_dev->tpd_base) - pci_free_consistent(he_dev->pci_dev, CONFIG_NUMTPDS * sizeof(struct he_tpd), - he_dev->tpd_base, he_dev->tpd_base_phys); -#endif if (he_dev->pci_dev) { pci_read_config_word(he_dev->pci_dev, PCI_COMMAND, &command); @@ -1720,7 +1636,6 @@ he_stop(struct he_dev *he_dev) static struct he_tpd * __alloc_tpd(struct he_dev *he_dev) { -#ifdef USE_TPD_POOL struct he_tpd *tpd; dma_addr_t dma_handle; @@ -1735,27 +1650,6 @@ __alloc_tpd(struct he_dev *he_dev) tpd->iovec[2].addr = 0; tpd->iovec[2].len = 0; return tpd; -#else - int i; - - for (i = 0; i < CONFIG_NUMTPDS; ++i) { - ++he_dev->tpd_head; - if (he_dev->tpd_head > he_dev->tpd_end) { - he_dev->tpd_head = he_dev->tpd_base; - } - - if (!he_dev->tpd_head->inuse) { - he_dev->tpd_head->inuse = 1; - he_dev->tpd_head->status &= TPD_MASK; - he_dev->tpd_head->iovec[0].addr = 0; he_dev->tpd_head->iovec[0].len = 0; - he_dev->tpd_head->iovec[1].addr = 0; he_dev->tpd_head->iovec[1].len = 0; - he_dev->tpd_head->iovec[2].addr = 0; he_dev->tpd_head->iovec[2].len = 0; - return he_dev->tpd_head; - } - } - hprintk("out of tpds -- increase CONFIG_NUMTPDS (%d)\n", CONFIG_NUMTPDS); - return NULL; -#endif } #define AAL5_LEN(buf,len) \ @@ -1804,11 +1698,9 @@ he_service_rbrq(struct he_dev *he_dev, int group) RBRQ_CON_CLOSED(he_dev->rbrq_head) ? " CON_CLOSED" : "", RBRQ_HBUF_ERR(he_dev->rbrq_head) ? " HBUF_ERR" : ""); -#ifdef USE_RBPS if (RBRQ_ADDR(he_dev->rbrq_head) & RBP_SMALLBUF) rbp = &he_dev->rbps_base[RBP_INDEX(RBRQ_ADDR(he_dev->rbrq_head))]; else -#endif rbp = &he_dev->rbpl_base[RBP_INDEX(RBRQ_ADDR(he_dev->rbrq_head))]; buf_len = RBRQ_BUFLEN(he_dev->rbrq_head) * 4; @@ -1887,12 +1779,10 @@ he_service_rbrq(struct he_dev *he_dev, int group) for (iov = he_vcc->iov_head; iov < he_vcc->iov_tail; ++iov) { -#ifdef USE_RBPS if (iov->iov_base & RBP_SMALLBUF) memcpy(skb_put(skb, iov->iov_len), he_dev->rbps_virt[RBP_INDEX(iov->iov_base)].virt, iov->iov_len); else -#endif memcpy(skb_put(skb, iov->iov_len), he_dev->rbpl_virt[RBP_INDEX(iov->iov_base)].virt, iov->iov_len); } @@ -1937,11 +1827,9 @@ return_host_buffers: for (iov = he_vcc->iov_head; iov < he_vcc->iov_tail; ++iov) { -#ifdef USE_RBPS if (iov->iov_base & RBP_SMALLBUF) rbp = &he_dev->rbps_base[RBP_INDEX(iov->iov_base)]; else -#endif rbp = &he_dev->rbpl_base[RBP_INDEX(iov->iov_base)]; rbp->status &= ~RBP_LOANED; @@ -1977,9 +1865,7 @@ he_service_tbrq(struct he_dev *he_dev, int group) he_dev->hsp->group[group].tbrq_tail); struct he_tpd *tpd; int slot, updated = 0; -#ifdef USE_TPD_POOL struct he_tpd *__tpd; -#endif /* 2.1.6 transmit buffer return queue */ @@ -1991,7 +1877,6 @@ he_service_tbrq(struct he_dev *he_dev, int group) TBRQ_TPD(he_dev->tbrq_head), TBRQ_EOS(he_dev->tbrq_head) ? " EOS" : "", TBRQ_MULTIPLE(he_dev->tbrq_head) ? " MULTIPLE" : ""); -#ifdef USE_TPD_POOL tpd = NULL; list_for_each_entry(__tpd, &he_dev->outstanding_tpds, entry) { if (TPD_ADDR(__tpd->status) == TBRQ_TPD(he_dev->tbrq_head)) { @@ -2006,9 +1891,6 @@ he_service_tbrq(struct he_dev *he_dev, int group) TBRQ_TPD(he_dev->tbrq_head)); goto next_tbrq_entry; } -#else - tpd = &he_dev->tpd_base[ TPD_INDEX(TBRQ_TPD(he_dev->tbrq_head)) ]; -#endif if (TBRQ_EOS(he_dev->tbrq_head)) { HPRINTK("wake_up(tx_waitq) cid 0x%x\n", @@ -2038,12 +1920,8 @@ he_service_tbrq(struct he_dev *he_dev, int group) } next_tbrq_entry: -#ifdef USE_TPD_POOL if (tpd) pci_pool_free(he_dev->tpd_pool, tpd, TPD_ADDR(tpd->status)); -#else - tpd->inuse = 0; -#endif he_dev->tbrq_head = (struct he_tbrq *) ((unsigned long) he_dev->tbrq_base | TBRQ_MASK(++he_dev->tbrq_head)); @@ -2086,7 +1964,6 @@ he_service_rbpl(struct he_dev *he_dev, int group) he_writel(he_dev, RBPL_MASK(he_dev->rbpl_tail), G0_RBPL_T); } -#ifdef USE_RBPS static void he_service_rbps(struct he_dev *he_dev, int group) { @@ -2113,7 +1990,6 @@ he_service_rbps(struct he_dev *he_dev, int group) if (moved) he_writel(he_dev, RBPS_MASK(he_dev->rbps_tail), G0_RBPS_T); } -#endif /* USE_RBPS */ static void he_tasklet(unsigned long data) @@ -2124,9 +2000,7 @@ he_tasklet(unsigned long data) int updated = 0; HPRINTK("tasklet (0x%lx)\n", data); -#ifdef USE_TASKLET spin_lock_irqsave(&he_dev->global_lock, flags); -#endif while (he_dev->irq_head != he_dev->irq_tail) { ++updated; @@ -2141,9 +2015,7 @@ he_tasklet(unsigned long data) case ITYPE_RBRQ_TIMER: if (he_service_rbrq(he_dev, group)) { he_service_rbpl(he_dev, group); -#ifdef USE_RBPS he_service_rbps(he_dev, group); -#endif /* USE_RBPS */ } break; case ITYPE_TBRQ_THRESH: @@ -2156,9 +2028,7 @@ he_tasklet(unsigned long data) he_service_rbpl(he_dev, group); break; case ITYPE_RBPS_THRESH: -#ifdef USE_RBPS he_service_rbps(he_dev, group); -#endif /* USE_RBPS */ break; case ITYPE_PHY: HPRINTK("phy interrupt\n"); @@ -2186,9 +2056,7 @@ he_tasklet(unsigned long data) he_service_rbrq(he_dev, 0); he_service_rbpl(he_dev, 0); -#ifdef USE_RBPS he_service_rbps(he_dev, 0); -#endif /* USE_RBPS */ he_service_tbrq(he_dev, 0); break; default: @@ -2210,9 +2078,7 @@ he_tasklet(unsigned long data) IRQ_TAIL(he_dev->irq_tail), IRQ0_HEAD); (void) he_readl(he_dev, INT_FIFO); /* 8.1.2 controller errata; flush posted writes */ } -#ifdef USE_TASKLET spin_unlock_irqrestore(&he_dev->global_lock, flags); -#endif } static irqreturn_t @@ -2244,11 +2110,7 @@ he_irq_handler(int irq, void *dev_id) if (he_dev->irq_head != he_dev->irq_tail) { handled = 1; -#ifdef USE_TASKLET tasklet_schedule(&he_dev->tasklet); -#else - he_tasklet((unsigned long) he_dev); -#endif he_writel(he_dev, INT_CLEAR_A, INT_FIFO); /* clear interrupt */ (void) he_readl(he_dev, INT_FIFO); /* flush posted writes */ } @@ -2305,23 +2167,14 @@ __enqueue_tpd(struct he_dev *he_dev, struct he_tpd *tpd, unsigned cid) dev_kfree_skb_any(tpd->skb); atomic_inc(&tpd->vcc->stats->tx_err); } -#ifdef USE_TPD_POOL pci_pool_free(he_dev->tpd_pool, tpd, TPD_ADDR(tpd->status)); -#else - tpd->inuse = 0; -#endif return; } } /* 2.1.5 transmit packet descriptor ready queue */ -#ifdef USE_TPD_POOL list_add_tail(&tpd->entry, &he_dev->outstanding_tpds); he_dev->tpdrq_tail->tpd = TPD_ADDR(tpd->status); -#else - he_dev->tpdrq_tail->tpd = he_dev->tpd_base_phys + - (TPD_INDEX(tpd->status) * sizeof(struct he_tpd)); -#endif he_dev->tpdrq_tail->cid = cid; wmb(); @@ -2511,13 +2364,8 @@ he_open(struct atm_vcc *vcc) goto open_failed; } -#ifdef USE_RBPS rsr1 = RSR1_GROUP(0); rsr4 = RSR4_GROUP(0); -#else /* !USE_RBPS */ - rsr1 = RSR1_GROUP(0)|RSR1_RBPL_ONLY; - rsr4 = RSR4_GROUP(0)|RSR4_RBPL_ONLY; -#endif /* USE_RBPS */ rsr0 = vcc->qos.rxtp.traffic_class == ATM_UBR ? (RSR0_EPD_ENABLE|RSR0_PPD_ENABLE) : 0; diff --git a/drivers/atm/he.h b/drivers/atm/he.h index b87d6ccabac1..c2983e0d4ec1 100644 --- a/drivers/atm/he.h +++ b/drivers/atm/he.h @@ -51,8 +51,6 @@ #define CONFIG_IRQ_SIZE 128 #define CONFIG_IRQ_THRESH (CONFIG_IRQ_SIZE/2) -#define CONFIG_NUMTPDS 256 - #define CONFIG_TPDRQ_SIZE 512 #define TPDRQ_MASK(x) (((unsigned long)(x))&((CONFIG_TPDRQ_SIZE<<3)-1)) @@ -140,12 +138,7 @@ struct he_tpd { struct sk_buff *skb; struct atm_vcc *vcc; -#ifdef USE_TPD_POOL struct list_head entry; -#else - u32 inuse; - char padding[32 - sizeof(u32) - (2*sizeof(void*))]; -#endif }; #define TPD_ALIGNMENT 64 @@ -291,16 +284,9 @@ struct he_dev { volatile unsigned *irq_tailoffset; int irq_peak; -#ifdef USE_TASKLET struct tasklet_struct tasklet; -#endif -#ifdef USE_TPD_POOL struct pci_pool *tpd_pool; struct list_head outstanding_tpds; -#else - struct he_tpd *tpd_head, *tpd_base, *tpd_end; - dma_addr_t tpd_base_phys; -#endif dma_addr_t tpdrq_phys; struct he_tpdrq *tpdrq_base, *tpdrq_tail, *tpdrq_head; @@ -311,25 +297,13 @@ struct he_dev { struct he_rbrq *rbrq_base, *rbrq_head; int rbrq_peak; -#ifdef USE_RBPL_POOL struct pci_pool *rbpl_pool; -#else - void *rbpl_pages; - dma_addr_t rbpl_pages_phys; -#endif dma_addr_t rbpl_phys; struct he_rbp *rbpl_base, *rbpl_tail; struct he_virt *rbpl_virt; int rbpl_peak; -#ifdef USE_RBPS -#ifdef USE_RBPS_POOL struct pci_pool *rbps_pool; -#else - void *rbps_pages; - dma_addr_t rbps_pages_phys; -#endif -#endif dma_addr_t rbps_phys; struct he_rbp *rbps_base, *rbps_tail; struct he_virt *rbps_virt; diff --git a/drivers/atm/iphase.c b/drivers/atm/iphase.c index 139fce6968a6..24df73ad326d 100644 --- a/drivers/atm/iphase.c +++ b/drivers/atm/iphase.c @@ -65,12 +65,7 @@ #include "iphase.h" #include "suni.h" #define swap(x) (((x & 0xff) << 8) | ((x & 0xff00) >> 8)) -struct suni_priv { - struct k_sonet_stats sonet_stats; /* link diagnostics */ - unsigned char loop_mode; /* loopback mode */ - struct atm_dev *dev; /* device back-pointer */ - struct suni_priv *next; /* next SUNI */ -}; + #define PRIV(dev) ((struct suni_priv *) dev->phy_data) static unsigned char ia_phy_get(struct atm_dev *dev, unsigned long addr); @@ -94,10 +89,6 @@ module_param(IADebugFlag, uint, 0644); MODULE_LICENSE("GPL"); -#if BITS_PER_LONG != 32 -# error FIXME: this driver only works on 32-bit platforms -#endif - /**************************** IA_LIB **********************************/ static void ia_init_rtn_q (IARTN_Q *que) @@ -1411,7 +1402,6 @@ static int rx_init(struct atm_dev *dev) struct abr_vc_table *abr_vc_table; u16 *vc_table; u16 *reass_table; - u16 *ptr16; int i,j, vcsize_sel; u_short freeq_st_adr; u_short *freeq_start; @@ -1426,14 +1416,15 @@ static int rx_init(struct atm_dev *dev) printk(KERN_ERR DEV_LABEL "can't allocate DLEs\n"); goto err_out; } - iadev->rx_dle_q.start = (struct dle*)dle_addr; + iadev->rx_dle_q.start = (struct dle *)dle_addr; iadev->rx_dle_q.read = iadev->rx_dle_q.start; iadev->rx_dle_q.write = iadev->rx_dle_q.start; - iadev->rx_dle_q.end = (struct dle*)((u32)dle_addr+sizeof(struct dle)*DLE_ENTRIES); + iadev->rx_dle_q.end = (struct dle*)((unsigned long)dle_addr+sizeof(struct dle)*DLE_ENTRIES); /* the end of the dle q points to the entry after the last DLE that can be used. */ /* write the upper 20 bits of the start address to rx list address register */ + /* We know this is 32bit bus addressed so the following is safe */ writel(iadev->rx_dle_dma & 0xfffff000, iadev->dma + IPHASE5575_RX_LIST_ADDR); IF_INIT(printk("Tx Dle list addr: 0x%08x value: 0x%0x\n", @@ -1587,11 +1578,12 @@ static int rx_init(struct atm_dev *dev) Set Packet Aging Interval count register to overflow in about 4 us */ writew(0xF6F8, iadev->reass_reg+PKT_TM_CNT ); - ptr16 = (u16*)j; - i = ((u32)ptr16 >> 6) & 0xff; - ptr16 += j - 1; - i |=(((u32)ptr16 << 2) & 0xff00); + + i = (j >> 6) & 0xFF; + j += 2 * (j - 1); + i |= ((j << 2) & 0xFF00); writew(i, iadev->reass_reg+TMOUT_RANGE); + /* initiate the desc_tble */ for(i=0; i<iadev->num_tx_desc;i++) iadev->desc_tbl[i].timestamp = 0; @@ -1914,7 +1906,7 @@ static int tx_init(struct atm_dev *dev) iadev->tx_dle_q.start = (struct dle*)dle_addr; iadev->tx_dle_q.read = iadev->tx_dle_q.start; iadev->tx_dle_q.write = iadev->tx_dle_q.start; - iadev->tx_dle_q.end = (struct dle*)((u32)dle_addr+sizeof(struct dle)*DLE_ENTRIES); + iadev->tx_dle_q.end = (struct dle*)((unsigned long)dle_addr+sizeof(struct dle)*DLE_ENTRIES); /* write the upper 20 bits of the start address to tx list address register */ writel(iadev->tx_dle_dma & 0xfffff000, @@ -2907,7 +2899,7 @@ static int ia_pkt_tx (struct atm_vcc *vcc, struct sk_buff *skb) { dev_kfree_skb_any(skb); return 0; } - if ((u32)skb->data & 3) { + if ((unsigned long)skb->data & 3) { printk("Misaligned SKB\n"); if (vcc->pop) vcc->pop(vcc, skb); diff --git a/drivers/atm/pca200e.data b/drivers/atm/pca200e.data deleted file mode 100644 index e78e83becd95..000000000000 --- a/drivers/atm/pca200e.data +++ /dev/null @@ -1,850 +0,0 @@ -:150000001F8B0808AB5A10380203706361323030652E62696E4D -:150015007D00E43A0D7014D7796FA5BDE84EC86211A7333020EE -:15002A00AD89C00A23EA83AA589C7E7C38D8152EB887477677D3 -:15003F0095C39C3DB2AB388CA324C4A509352BFBB085BBD0C73F -:150054007210B903C92991CCD1B1C242255BCCD81EA5C34C6826 -:1500690006271AC6D36A3A31B976D4A9A683DB4B07BB38265C56 -:15007E00BFEFBDB7777BA7030B2733994C35737AFBBEF7BDEFE7 -:15009300EF7DDFF7BEF7769FFEEAD79F221221E1ED844C3E4677 -:1500A8007EA3BFF036F827CF8597C3AF0C7E920B16595BCE5AA8 -:1500BD00296B6483D83E9F7DBE8FF50BE74A0B45FB1F274FAA79 -:1500D200D82E2867139DF637FD937EF1D55FB0769FE8678BDAFB -:1500E7007D9BD8885451515172FE27E4138E9FC9949CBFF026BC -:1500FC00741DF83ECE59823FF23BF89346493F6B4F17C1B3A7CE -:15011100B3B79C97D3275B5ABFEC3CF9579457703B3CBFEFD600 -:15012600FC38236CA91B5E347EDBFA67F7ED4397956EA4D3C5F4 -:15013B007CE6A567799EFFF5CFC4FF7BDF938BF83E83EDE59F02 -:15015000FEAC24BF8A3C3F2FF9FDFF933CF51EF2FFEC2FEBFA11 -:150165002341C38CBC5F4EAA265F5EAF04BC51F0059FD1419ED8 -:15017A00063493D465A2384E66A0171C30231F40AB5CB5646FC8 -:15018F005CBFB633DECCC614D2DAF622F15D3189EFEA3EE28B83 -:1501A4007D99F8DABE4D7C2418A438AF3129015D7507F1032EBA -:1501B900E174827F46C82229AE2BC63A9D50E9253960EC005FCA -:1501CE00F2EDFE0AF12A9D5EBD6A35F1B5AC441A49BAD94F22C6 -:1501E300DECB544F180D1A51FACD8C4A7C034B93DAFD6455A8F9 -:1501F8009AAC5AB74C9542EF11E23DB0946A0F1B0DA10BF0CC0C -:15020D00F9A4A8097BCA1D751474A02FEC02593C75C9E870D176 -:15022200B8CF352EC3783C379E1C2893C98017C6A57B3CDD0E4D -:15023700CE32426A9CB99F03FC2E81BF46AD0D06544FD0190B08 -:15024C00C0580B8E897EFDF490DE08FD652E9CFAE911DD5F24FE -:15026100CF832469DAB1116BE0F3C437B686F8D275C437AC9220 -:150276000542BFF6CC0320B22AB7237E1F5B97A4E927A397490C -:15028B0064C43AFF0CD8ACCE8886D37F632A7F4C16005E289CAF -:1502A0003E491DDAFB083513C6B0A6B8E4929626F531E0877479 -:1502B50082E58C9E2503DDD45DC4777E3BF1051F253E09684E42 -:1502CA00C3BAC26825AC39F5225F6598EE23B366227C52ABFC3A -:1502DF00BC2754E61BD1FFEBAE6DCDFE8D49AAEA38EE89A35A1B -:1502F4009DF0DCF4254234681BBB09E98536033F2F3C5F835F24 -:15030900107E147E1AE8AA0406A36989DB63C95ADE9F9272EBA7 -:15031E00C17C6131AC4519193457028723BE118D0433D6F063E5 -:150333005C6E1C77EC2981FD118663B2FA3A455F8D11A2D66BC0 -:15034800AFE9B096E6D4A38454D70D004ECA8235541117C7A5F2 -:15035D002D26F8E4B07D3848BA956402FC7BF8EC956CB6B6D35F -:1503720091EB21B280C218CAB04122B5957583D126189B7D88FF -:15038700FB2BDA46560F52056C867C6CE85FF1135F19E0C948D1 -:15039C0023873342916798F3A6E45FA58C9021887DB9A8DF9307 -:1503B1002EECF7421F693AB054DE6F73F4FDF414E83A6B66B2C0 -:1503C6000B11C3BA0E45D0D1074E3318C92C24FE074FF267E847 -:1503DB00E03AE67193D635C40D9FD66A65B471CABA5AC66D9C17 -:1503F00081B68DE4F5200AEA316B3E3EF5F8D4CAF0C902BFBC6E -:1504050003FD12ED00BE39F8E7C4E765F2A6F8BCC8083DA6B648 -:15041A00335DAAA0AFC4DEA66A6CDC8418EA26910FAD6A0821BE -:15042F0012B4A9C269D1DDAC9DB05A98BD06B91D807702D6021B -:15044400F02CA479BF88CD3D82BE3F92D49137C262E0EB5969BB -:15045900D6AC8DA4F4A3A0EB808FEB8570E6F34897F9F77CE4C2 -:15046E0071E4E07C73F2C0FC256AC3208B2D5C834D43BA3F060F -:15048300F39566B386103FC611E321E23D02F1168A79426C3DFD -:15049800E159DA32AAA34C083FBA62DC2474847A94BF031D86A2 -:1504AD00ACE5EAEB969CDC4FF3F3216F03DE5414FD8ED3DA3050 -:1504C2005F5AC953795A804F2146D05612811C0DB6A0BC0E67DE -:1504D7007C6E471FC3A5CFA04B06639EFA201E11FA182E7D3E53 -:1504EC009556913E89227D129F511FDBA5CF05970CF63CF54199 -:15050100BCE097B83EB64B9F4FA555A4CF60913E839F511F752A -:1505160026AF4FCB4C5E0684CF471FC48B75737DF079C37C69B3 -:15052B0015E973BC489FE32E7DC231AFD997FEF15925301975DC -:150540007CBC5E33F5D918F2E53E82FD69D1B745FF82E8237F22 -:15055500EC4FB07ED2A4626FD8C3F7363321FA29D11F14FD6938 -:15056A00D13F2EFA9D40678FFA1ACBD131181B507F88FBA8451E -:15057F00E179507D8362EC4FC2734A7D8786D5D526CF431356CC -:1505940010E6D51152BB2CE6690F243DED35694FBB17D6017487 -:1505A900B251C766F514A3D3037337AB67189D043C77A9E728AB -:1505BE00CE3FCFE5A0C8B347ED17F9CDB09A812EE4A09AFBC861 -:1505D30005F3ECCE1F76B0B8059C6AD51342D87777BEC16093F7 -:1505E8002ED82B3BDF613094C9813DB7F3A50E87FE6A95AF1F58 -:1505FD00D259C69E53B447F047991EAA1FDDE8D0747091968332 -:15061200EBC88AB2D5095CA4FB07AA87ED030961D37494DB348F -:15062700C27225D77D497EBF32958271CE6F8DA0D12CF612E37F -:15063C00718ED32568206F3FDF874C7B477EAC4DD8310AE35B40 -:15065100C17E683B139EA3EA6178A6D65B4CA65926E72EF555F4 -:150666007A82D977D06A9A610E58F3D80D4F6BFDF4DDFAC37506 -:15067B00E7D67D672AA93DD881720C301B55C6E4D0860EB97506 -:150690007D5DFF3A0A636BD898CDE4AD4C7A42CBDE915B037587 -:1506A50087D7593056DDC1E5477B55429CDCF8B5DCFAAB15AFBD -:1506BA00AE3B0263FFD3EE69AF8C5584FEF3FD0FDA90E6BFADE7 -:1506CF0030DB70FEBF9C186B43DC4BEFBFDE4682BD8C27C86F5A -:1506E400B3BC185CC264063DED086BF730DA2418B655D6F63110 -:1506F900394850B53126EEFCD1AC2EBD1B83F83B6D56056C5662 -:15070E0027F079B3565739DFC3A2AC8D591AB48B37FD4097B6BD -:150723007D4527CA41F38E00D6C48665887A30CEDA5E6BA09CE8 -:15073800EF7568CF8A7EC03FF80DC05F6B56078280AFB25C86D9 -:15074D00F863ACEDB32658DBC26CBEE04780FFEEB7017F9BB98C -:15076200301001FCB0C5E54E5A0DD0BEC8D6618FD53893DFDBC0 -:15077700489D0A781A5B9B27616DFAD4435409C08E179C365B01 -:15078C00B86D2C5EB34E5BCDD0CEC0B98106CBBA25A29A87AEC7 -:1507A100676BD0977601BC4A7DCDC2BA15ED575E1DD7B78610CF -:1507B6008FC715EE954F0A5CB4B78837139F9F079E8AEFA21E32 -:1507CB00DF9814679714AB9163E99F59FEBDE3263A704FFA4DF8 -:1507E0000BFAD400D9FCE1115DF1C541C7772D591DB7BA1C7929 -:1507F500D4BBCC1B9F701EC761BE22E4A1429EB736E6E5C1BDA9 -:15080A00EE92C09D74C933790B79222E79BA401EE8535A429E39 -:15081F00F3ABF2F23C2B785CC43812F24C0A799A5CF2E05E759D -:15083400BFC0457F73E4C1E79BC91376C9B319E4813E4D9690D5 -:15084900A7D925CFE55F711E6D33B8A771799007CA73BC252F86 -:15085E000FEE3567392EE35506B935DE3E625D87B3AC9363DDC5 -:15087300675D387B325FEEC53DCA370CF1D064D2707F1F9E1BAD -:15088800BCCC7732962CFCB60AF76B17AFD80C1694A4D6EBDAB7 -:15089D0047E58DFC1CEB75E1E10563311E21B6794C95704FA00C -:1508B20031EEBF8BC93DD0270326EC0F8A54674771FCCEF0B040 -:1508C7007E67F81CD864D8EA401CC819480FE1811DBC76E5FDFE -:1508DC00733A83FDD508D6AA24406D9DCF3FA75FCC66FD65D592 -:1508F100FDFAEE7BF332F5F0FDC225936D769033AD01550A3A24 -:15090600BCF12CBF86F184F305E007567C68E59EDB3FCCF1498D -:15091B00D79F692B73E8803CC25E4CAEDA152370463A4A2DE42F -:15093000AB34998BC0DE1BD01C0AA7C5715314ED0FC74F4B510E -:150945005ED2BDC9319893001F18B3A2AE734B17D4E2CFA89EB1 -:15095A00D6B7245E6394E2F350520E95A6DD6079943780F65B70 -:15096F00507B1C857AE36D0B6B12491D8133EA88E6D41A72B92A -:15098400A835607E52D421448C255D7548EE0F723FD656E84744 -:15099900CA3D28974DE33C4751AF90CFEB9603D61BE545BA8197 -:1509AE00906D2A44D446CA190BE550DE5F85B273DF637264CCC1 -:1509C300C15E487501388B928C8974B4ED9C4E8FD80F395D9B32 -:1509D800D9A7F6FDFD5482B3B6141B358F92514D3A30CEEA2EE8 -:1509ED003EC7B6108744E478BE6ECB98555F46FA54D0E77A23D8 -:150A0200FDE876AE1FE7932AE0C3EC226CC2EC98E676BC7347DE -:150A1700DC0A446C361675F3A48267306C72595A4C85D9A5D310 -:150A2C006467AB60D0E4761AA00C1E19A6CFDE057584F27DAC4C -:150A4100810A64F09F5845DD6B073896ACC05936324E1D3FC1D0 -:150A56001C843796C7485C2391FD168998CC2EAC0E807119F419 -:150A6B00A52D86899716E555719D1E5CABF77860FDA686D87D2E -:150A8000881FD74839ABCBEADB34C06AE6FC196F49F9DC3367A7 -:150A9500FF9653FCBCE83E774E9DC198FD9433E7203F734E0EF2 -:150AAA00E7CE9BECEC19F9BEE5F8961C30A2634DFCFEA0D0B70D -:150ABF00B82FA14CBDC23E6C6D4249E6574419B2081DA247F1E2 -:150AD400AE02FC0A7D81D9CC00FA74C84ADCC82E72F9336B3524 -:150AE90075186487D8A757CCC5B06FE37D56B5BAAAF912D674D6 -:150AFE0012F13EA3AE0D5D83985C9FF6B7B3DAEE31CEB713DA06 -:150B130045E420F33B90DB12700BE117C47D4058E0468A700568 -:150B2800DC42F87111EF0EFD1E316777D11C01B710DE2BE8F75C -:150B3D000A5CA30857C02D84B709FA2B05FD06818B78F8BCDCC9 -:150B5200956F1A5D63F88C67293C4379C18FCAAB46C037862CF0 -:150B6700B497ACBCA2E37A07D5613B00F6AA091FED901553AFF3 -:150B7C00EDBFA257A9A7AC65C6076D814DFFADCBB131EB44D2FC -:150B9100D3ED8D9966269B5D0C355EAB1CBB62393E5B09B92DA1 -:150BA6007D3DEB73C7C0B7A0CE95599D4AE7C4A388AF5C5E4121 -:150BBB001ACAA1213D513EACA16C353B1A2C279ED9DA634E30EB -:150BD0002027A4DFC63C22E273C22A8E67F405C61362C61D27AE -:150BE5002FDE11D7C365DC0F1591D33E2D4E5E82FD3B17230768 -:150BFA008634CC078AD84F31565642CAC2B3E0D3AC9E17310500 -:150C0F00F1F318F89BA8DF73B0FBC5B9E2E6B1D4226269A8F448 -:150C2400FD8D2B9E7ABEF0DBCFD57473E2296C3D2DEC7EBCF2E1 -:150C3900AE00DF13950DDEA802CFB7FA713CC25A35E0ECA52AC3 -:150C4E00D412F544A96ED2E3655F78CA23E0B4C678CA19C73BC6 -:150C63007A25DCF084ECD008279EA8719E37E5E1B9FD8ADDB182 -:150C78000DC0764CD423AADC4D73B519BFDF7C84EDF7B3589BA5 -:150C8D002978178F2324729206D4F666ACDF181C6C7FFDBEF62F -:150CA2003F04FFB4091D3E8BEDE2C8A08EF7A1481361354A427E -:150CB700BF0075C79CFD52F0EFBA09FFF58CFF80C9F2281DB6EB -:150CCC00918E943ECEE946809780E173BA047D6A637DC3E9E326 -:150CE100FD30D41426ABD5A0BF066353F5B7AD57AB426111E732 -:150CF6002175793BD0A435CA01DD9101E36E51513FF72CF85916 -:150D0B00533FD0D6AB0F846AD4079A03EAAAD056276FA94F71C2 -:150D2000DA82A6E43B3E87AEF48FB786AD4E2F6F75EEA36584E2 -:150D3500837D8F64208743DE10F7CD8B56A7E5565C0F7627CD82 -:150D4A0071E811C84132E2404C200ECA9A85BA8E1AFB35425244 -:150D5F00980BCDECDF9F97C1AF71CF55D02E2C2EA660BF823D2D -:150D74006135190E61FC6476BEDEE1BEA7FD9C787F107F84E908 -:150D89005860EF2C9930495D2A9AA76D08DAB6C1624F81FD644F -:150D9E0072445B638C94A45D2168373E42BCEE7D285F5F65CC2D -:150DB300E4D7B03E3172F5C9FCF381CDF301E856321F28AE3A51 -:150DC80028771E688C4A5BD641CD07B107B58A72379C210E6DFD -:150DDD00D477415EF648712D0AAD1C4846132A3F977C1772DDE5 -:150DF200B1E4C7CDE4EA10BDF6B5FC7B8D3D5FFFDDFEA623C476 -:150E070037F149D60767196DF37D72BB73D787F76764B77176CD -:150E1C0012DFEDED4E9E9D62ED24C612B4E9B319F6CE0FCEC553 -:150E310060A795E28EC5592B49ACD55EA03DFBA77C1F408D2F19 -:150E4600C19925111ED61AB1FD22D431CC768DCC76686BC46913 -:150E5B00025948755C5BFE89B05F4C62F603E3079A805E15C03F -:150E70007F7E9F7C2F5BCFEDA2BE82166B17AC59900EF6BB59E8 -:150E85003D95F781473ED50706C49DFE70491F5072FB7DC6422E -:150E9A009DC136B6B08D2D6C630BDBD8689B72C8E56E9F99AF8B -:150EAF003DF1DD13D451C14A757F10CEF8BE3C6C2DC00E06535C -:150EC40005B03F02D8D1E09803AB42582DC056042711C6EE3D4A -:150ED900B87DDFFB18EC09763DFFF15CBBBEF730F18D7D8C764C -:150EEE006DB877BE7ACD579F7809FF2813FE1105BE17B615CA1F -:150F0300D922135F23C8E20159979490B511E67899AC4DF7DEFF -:150F1800CE1ACC57DEDE12F2960B795F0759976C9BEBCF06FAC8 -:150F2D004B095F8E5DCBFACA408FC8B5B97AC4804EF81AEAE194 -:150F4200BFF7767DE976F4E929A18F2CF4F9F956E2EB84DF675D -:150F5700E1BFF97F4127B5812A6A1365EFE620074AB029B701EC -:150F6C001CFB32E934357C0E6AA60AD659AEEA96A26EFA5B76F9 -:150F8100970E79676B6C88BD2B8E7D53DCF73CC76A5433FD0D60 -:150F9600A89D643847E33B55DC9401EF62EC9455F5C419EBC295 -:150FAB00479C3601BAD9858639057D89F7BD631F15CA33267057 -:150FC000DF83B68B244DBFCAF9118DF3433EC8CFDE5DC86F3932 -:150FD500E0553D71CADA0AFC3441837EC4F9C5043FE87BDDF609 -:150FEA0054843DCD3FE1EFB8AF3E440AC61789F15D62FCBDA29D -:150FFF00F11A31BE558C8F158D2F16E34D623CC1C63366D79E29 -:15101400FC793F0B3A5202FB37ECD5DEE52452707687BF81A5FC -:15102900B646E14C41EA923BF0AC5963EC5F87EFF53591D70ED8 -:15103E002C9DD53AC22F873A5DF7E92F4C3CF113B4D573BB2F35 -:1510530075045DF0CBAFFEF57584B7EEF84987FBFE7DFA8D6F83 -:151068009D40F893FFF0E30EC2BE871834E3FFFC179BFC0163E8 -:15107D0047B297F8269F24BE3972BAEE17827F59B87FCB380E23 -:15109200F9167388548D39197231C24AECC74EAE81B351FBEE40 -:1510A7002DE2DE07700F6C19D52A638F065F811671F66EE7672C -:1510BC003C1C73CE320C5644AF8EDFF7F1EF332E0FE8F683F8F2 -:1510D1001D01FB1640C47E8ADD2918BE51B6571056CB2419BE69 -:1510E6005F39CDEE52768B7B1784A9EA283B4BED71C18202D67F -:1510FB00E7823509D8DE99FCB707866B1CED4B26086954472D8C -:15111000370CBF436C2882554932692E84518A67BFD838550E10 -:151125008DEA2D3826F4C6EF6508BD9BD99D8AF91FDC58F453B2 -:15113A002F9B9FF345D18A7E649C4A07F09C0338ECFD3DE713EE -:15114F005647E93EA827B19EC2F3EE65F0B7441FE9C6F74ED3D0 -:15116400397FE1B66DACE2760DA74FE6E40CA74FD3FE2DE3DA2C -:151179006675DC72D37C79E98086FB33D28C15ECEFA3ECEE6226 -:15118E00AB80ED1132EE113206605F6732E27B2576864DE1DED8 -:1511A300CF6A05B6F78BB51C106B298B6F2998CDA06605DE16C5 -:1511B8007EFF9280338317CFA17866127A7845AB14B5176F64D1 -:1511CD000BEA546EDF93EC5E0EF76903F4C3332E3E3B30F2F086 -:1511E2005C58991BC6EAE794D509272B493C6F56381C6C66A124 -:1511F700DD6A33CCCE0143C8C160013B1AD89812E727389FC223 -:15120C009C5A03D60DD688B591717321D2A3A356297C52029F42 -:15122100E4F0DFE4F605183C5B7B9DCFF944FCBD20F4E4B19C55 -:1512360062758BE4E804CF57A514F3F7A03F3FFEF296FCB8034D -:15124B007BA9044C7E782ECCE386B9623AE7DF22A69C7875C78E -:15126000727F512C633B25C66E36C72831C7196BC4F68BF9B97C -:151275009590BB8DBBC902278FA04D5E747C0E9EEBA7E37AAC39 -:15128A00687CC1E594CE69A4CC1648B68998A71B7CAC06F7016D -:15129F0073733E27A17F605C38637DEE31F6ED1BA7C35A178D76 -:1512B400CE221A8E0DB80F7298510C037A2F38307F1E66948027 -:1512C900555617C250A7FD2E9D1D58BC04ACBCDA0D334CBB4EC1 -:1512DE0026E1D5C23EB08F60CEC0B8F483CF634D85DFE4B17ECD -:1512F3002015AD75BD4B225584BD3342FFF533FF1D311D3FAFDB -:151308003C84DF1BD87400BFB50BF35C568A8672DB34600CF7B2 -:15131D00176514F12C2D1717498AF91CF3E12ECC25D0C77907C1 -:1513320097A634461F7DC54F6829B8E2829B6EFC25A5E10AC018 -:151347007B9DEFDEEA788E75DB6BAB74137BF94BEBBAE0B20DCC -:15135C0067E4D1BE83504BB03C301FBBFD1669A19EB75A03F3CC -:1513710076E4FACCB40AD7D51679DED9AB793E2EB475613E2E11 -:15138600210BCCE1B2A44CD602ED85480F6ABE927628814F729C -:15139B00F885F2ED75F91DC6AF543D37BE49F5DCF82EAB9E1BB7 -:1513B000CBA404EC15DFDCF8F654CF8D65B90886F847DC73F32E -:1513C500EF3C2B79FD8531CEF706B469BD6BEF83D6D825BEDF9F -:1513DA0020AEBD50291A935D63FEA231AF6B6C49D158956B6C58 -:1513EF00B922F611E52D4A1493CAEA307BCFC4BF63A4F41A6BD3 -:1514040007E9F532BEE765581B34A1A82072F5889E30C635FCEE -:151419005676B13CA21F2B1FD78E854735AC55BE639CD3BC1730 -:15142E003FD0192E201F360E68CA5653AF81BC5CE97AFF8BDFE1 -:151443008FCAE638833F17AB0ACDB8D613DFFBFFD37DFC7B9AE7 -:1514580058EEDB1B80CFF0335F65F2D7CDCB92DFC4EF4EC4B7BF -:15146D003313ECBB277E5F3EC1BF8D080E50FEBD0C1538830C25 -:15148200A7D7F57E03DF9F3F2BF84CCEE17347011FFE7DCD0460 -:15149700FB7ECAE1630B3E5D820FC719345551A725A13D119479 -:1514AC00BA2B0E8DE8FEF02AFD353C9FC4EE6E0BC42A425745A7 -:1514C1007C5D8ADD139A85672FD8BF5E8BEBD433DA5719F3B4AB -:1514D600E33A292ABE8B033BBE097935297577A9A72C388AD66C -:1514EB00C8CA5A88EB03B42E7CB0ED30665CA5DFC46F5D37FF53 -:151500003B9CEB22BFB41AD45F5ACEFBE836F58015560F5BFEA9 -:15151500F408FDBFF6BE3E3A8AEBCAF355AB5A6A498DA816ADA6 -:15152A0046C2209588708447715A422648964C43182F78306934 -:15153F00639CAD12C26EDB644C1C26A3DD61E7704E58BB255AC4 -:1515540020E10729D548462638B4B064E30938322B123C47248E -:1515690062E275F02C61B48CC390C4269D19C626332456BC4A65 -:15157E0086CD38F4DEDFABAAEE9210FE9839B367FF58D5D1A9A8 -:15159300EA57EFE3BE7BEFBBEFDEF7EEBB657887B6D5087BF17D -:1515A800081FA63A83A941B22B5F3491CE945E0EDF6E779BEBA1 -:1515BD00BF3ED0EC2E5FA1FD996EDA75A02C9E5157FCDBF00DF9 -:1515D200AF6E8D4C2B5F4CE523EA336693FA8A5DBE77C6F2D17B -:1515E700E31818D5AD80254CEF6AD47623AC7673ACFB9A2CD1D0 -:1515FC00A6A93F37BD12FC228E7293F5B5C9B184594CF2CC8307 -:151611007DE9E8A0E98BF59AFED8A869EDDBB8F9F8A4CDC7F152 -:15162600297C9CE1DFB1214D71F16F51CCDB98E151EC1B61AFE5 -:15163B008478348FE466095BA45B7DABB6FA16196876F3735093 -:15165000ED364231F94E6BBFC1E0F0E51DF97BAC8FC45BA1DF9D -:15166500AF6E60F987CA929AA22E16B459053AC0F5491D31629D -:15167A00EA5123A26EE04A68756B1FE9A75864EF1B7F41737C57 -:15168F00777BEDF1DB6FF95B14BBFD285AA9BF3945A7743575DF -:1516A4008C67CB1C31B9ED0FE7E415FB9AE349AD9878DC5D3E9C -:1516B900AAF61A1BA87D8DE0D0D483F47FD56853AB8CED6A8D70 -:1516CE001157EB8D2EB5C930D45544BB477493FD595B754AEC79 -:1516E3009FB6F553FEA43A6A1C51B9D1F7EC515EC28EE97336A4 -:1516F8003DCB17BC759527367D92772E58CC776DAAE5BB9F6D89 -:15170D00E05D6FADE04F2F38CEB166F2B91FC0892426ECBAFDF3 -:15172200CF9EE2FED387F59EB7F6F262B677A91B2E3205F38BA3 -:15173700D455CD99B46807AF92587EB13B4D74A083F39BA4BF13 -:15174C0071217D43BA16EB3032FB606FDDF89E191DFCFD821912 -:15176100EA235E1B79279D5F953C6C88B1053FE0CB37DAD7F014 -:151776008388129F788B3A85AE7290F2BC1FCCFA9DF8A6FB9DCA -:15178B0010AF1E14B65E3B7C7A4CE13F4D63DF4B32A32F49FA86 -:1517A0006CD3104F596B5EA6DF3A5F31A744D87D9326DEAB6A39 -:1517B500027BA94167BC63FD5E8B55124FE0EC483B8FBBDA56CD -:1517CA0066F0C3F1C5A85D3127C44DEC57F6A9528B323AC0AF33 -:1517DF00D96D627F734A9BF4DE37ADCDE9FB071B5CED3357FB1F -:1517F400EA0CEDCBAEF6E7CFD07ED5C76C1FFE3589863077601A -:15180900010C3BE65830CCA7B6A6B7AF8CBE28DA526303A46BCC -:15181E000CB732A5D384EF8F4CB67188DA9D1F1B309E5EF06B13 -:15183300E1D331E9F6F371EDCFAC7D2AEB3F22E52774A9ECA464 -:15184800BE7EACB3D1B78E0B5D46B92FA995EC18E1511F8B60C6 -:15185D007C96EC18E4317A866F01F21B296F0B337E6D62EF18A4 -:15187200699E6969D4D712C77F24188AB5865929DFD939B88DCC -:15188700190F70F08FFA790234A4B5FACEEDA1F64EF292D096AF -:15189C00D6B93B8EF208B5118C5B3A33F2083F10E3707FF1B807 -:1518B10021F67738C13277473D27B9DDD6B177ADF0F3098696FE -:1518C600B576DCFB29FD3CE1E9B598E74ECFA5FF20CE4084AD8B -:1518DB00730562BF0D739DBD9F2CF6434331A9B94059AFA36E52 -:1518F00094654A3397A5C37AA7381BF0B258170EC2C732BA3C2A -:15190500B35621C717E9589F484C785A426F35F0D08A7B74362A -:15191A003E6286562CB6FD5AC4BA96B557611C3597624F3D3A72 -:15192F0018BF4DDDB4043693D88735068633FFCA603C4875F9B3 -:15194400F32BF52BE974E08DE57AD3E34F7A9A1C5A5DA0BEB02D -:15195900F0761BEEB69BC2EDB954A1CBA79337C21E5E6686ED09 -:15196E00F593E9F04346032FE883D59719FA30FE0D731DFA6039 -:151983003C175F29FA10113028D1B80EF80D35A70577C08F3B83 -:15199800F15EC92CCC25E37BF8E0EFD285428F540EC7C7976FC2 -:1519AD00AA1FA5BEADA2BE39EF77FCCE75D410FE24048BAFE8E2 -:1519C200A8E085B93B4EF00999C598B16838A00CEA993335F4F6 -:1519D7005B8D25E8FD31FE3EDEC37710FB414A3B6C06E386DFF9 -:1519EC006E7FA97D597EF71525048FB3FA041F233316FB9D6202 -:151A0100BF69D883FD6A137BBB57D3E950D6FF89C6CBBFB17C5F -:151A1600625F767D5894CF961DB6FF8DCCFFB4F5E2B6988F27FD -:151A2B0053DF3715E2733535305C1CDA4EF56CE1C154A5312B41 -:151A400095D3B22AB5D80884DA88DE63A2CE10CDC92CFAFBFC5E -:151A55003519FBF21A87AF8EFCFA2384C752BE16FABD021FF809 -:151A6A00A8F0B5EA8DD7697F1EA96DBE47F5349FF75EE1A1C844 -:151A7F002797826E1BD2E9C249C9B193BA8D3CD02D2AEF32DA11 -:151A9400E013B89683D6C85743F9CEDAF9C2A91554EF6A739572 -:151AA900C573C38286F6BD26760FEF16FB8295246F5682A68619 -:151ABE0045C3A9F70E09EB8657787A391C7107881F3FAD4DE607 -:151AD30058F517F101FD41755663B13AABF6A5CA924673E18293 -:151AE800C657F18EE018BC9E2E5CA84A8D024E85F4B072A3D58F -:151AFD00C7FAF9E51FA7F333E7F1C60F5B7B8DE387CD4365D585 -:151B12001AF58C63BFABD7AE9FCA37A32E8DEA72F23AF9B6524A -:151B27009E7D6B06B45D34C6D0875B49E64D6F6BFB8FAD3D8A0C -:151B3C00522AFFAA64C185737B5D180BE37163BE7F500FFE6E98 -:151B5100BF8101BE3AF5A2619DD34A3333F282D647F5CEF3D710 -:151B6600E8A42B97C0D7BC865DE189C837DB70F62E89B1BB66B3 -:151B7B00B16E12AD72D990EE25FEC7DE506364A89129CF59B491 -:151B9000B1F5378C6159F0994A70455A05FCCA73E69B3F4AE70C -:151BA5001FF558FD5C49B46E9A81A6B751DBD3FB34F8A3B4D82E -:151BBA0013443D5BEDF2F36252A3779C6440740FF7F8137A2424 -:151BCF00B59F375D4AE73B6573699CE02CDDA88D779CE714B2F2 -:151BE40080F0E0E4E9A777E2D9788AC77F98B6CE3F529E37DF4D -:151BF9009F8A7BF0E04CB012FE4B4A53ED46FD050BE783D3CA28 -:151C0E008D02FFE07371566D0F77708D3371AB530326C73E7BDE -:151C2300785ABF5957A6DF472F5AFD06ED515F1BD55763D34CAD -:151C3800F0E6A0C59BF04B97D6FCBE1EA5F7B73AFC67D3C2C2FA -:151C4D0063B60EEDA2056B1BF1C4C8BF583C31CF5FAF8706A432 -:151C6200468737B662BC5BE73B6DDE209D3F32A42D64279AC1E8 -:151C770017C18661C10F667CA1E6EB7E519769AE5C68F381E5DB -:151C8C00F73A95EEA493FA42CA61E2F9765E447C116CAFD595EC -:151CA100376C7C3BE3C15506F6D44CF8BE1DE39DF203E737B4A5 -:151CB60043E3E928D5E9F8D3E4BA78631BF186FAA6C51B12E1DB -:151CCB0057B67963EDDF5AF8157B568493CBBFCDD20FF5CD8A7C -:151CE0006ED1B59F7CA99E649C599D5A6356A5569824E74C9214 -:151CF50083C60CFB4DE21C33F4143FD901C2276E063F6FD2937B -:151D0A00785E51B7DE06BF4CD2DFA09749F9033AF6B5BAEC73CC -:151D1F000BF02D7B50F8330D0B5B4AF877E34C34D94F87CA4E3B -:151D34006ACC1812BEDE4AB2D384BDBB2A794AE877F1E410782A -:151D4900728EA2769AABD453A641F712E388FEAA6ABD67954398 -:151D5E00FCF24DF43FD8438150B4750FE66FA58A17939CAF263F -:151D73003BE676F8E23B7633D96915DA55BD27B2BF0DF8F35FD4 -:151D8800C8DACDADEA7DE6DB3F93EE94957BF52A7505AF225DD7 -:151D9D00FE92EA6D0ED2FD5BF04514E36C0F2F3D9FCE7FAD5214 -:151DB2006E249BDC207BD698C78EDD15211B50B6694D76AC01A8 -:151DC70059D9E44A433E25146EA53ACD2ED5DFECF8589692BDD0 -:151DDC009BC72C3D0DBF8F52DDBB95A7DAA08F55CF618580CB48 -:151DF1006D67BA6DCCE80FAD71D029F257F36BC5AC9029EF99AF -:151E0600412A0399E186C9E2BF7A7E3BCD0B800F7004D5970D68 -:151E1B00F4218F781FEBE76C7C31749E6068C5A774F41D7A90B7 -:151E3000F774834E6085AAA82E21038C1E1E559FE1AFCE26DABE -:151E45002BC46754DE6907766090F41F4A33DD6DDE934E8B36D0 -:151E5A00855EA51C364748472B8FD9B22C6AC939D4D9361BEBFD -:151E6F00F6614A3B2CE0F2B2BD7A0FE08AEE3121A71CBA396BC1 -:151E84001ED13740BBF704ED707E5C55498F573A877DEA1DA687 -:151E99007705E940D1BDA26EE8F5D0E9FDEAB366CD75A929AB9C -:151EAE00CF583470F0EDA6C360C0F2BFBCD97B1E60856E7A0042 -:151EC3009EB1BFA139D2A117E495526526D6701D7AD4E49355C5 -:151ED800774DE7D7A87D9E2F9E7AC72C095D6CCD49922D7DFE54 -:151EED000A8D8D2FF00AED4FF425B16FF37D9D27DAC43E90ED91 -:151F0200971EA6BBB087B08608C28CC1C77DD80C8BB3DCDF30DF -:151F1700E684CE50BB3F249952DAEA8B3D493AED72CC2B66C792 -:151F2C00BD0F918E7BBFD171EFBD7A774A024E857E9B87392E76 -:151F41001CB5F5DB2ECB2F8FC66CCCF6B31F16F76ADB0638627B -:151F56008CDC073B2B4265B6087D3A2D7C44525C444EC819E394 -:151F6B00E1582D9F9DCC69093CBB9E074EB7E852F2040F40BFA2 -:151F8000879E7C1F7CD25F163EB87DEC9B1ACABD4FCA53DF677C -:151F9500BF69EDA7517DFBD97734B6ED1847F4903EF66D0DBA40 -:151FAA0018E4771F7B4D832F2DE089920E87FC80E55689059E76 -:151FBF00227915185BA9DF4DFDF12B8FE8B2FA9C81BE3A7E50F6 -:151FD4002C7A9FD931EB5EE1039C4F3031638DD9C70632FE501A -:151FE90028CFA2CF99AF125FFACE8DE86CA4D384FD04FA0FDB39 -:151FFE007BCC68ABE8524AEFCD7941E8F56BB1AE3C72CC1C63DA -:15201300225F1CFA3CFCE2B0B78867D80758AF213917C7BC7364 -:15202800ADE27073B9EA69F49D233DBCFE18A7726DED852B5BE4 -:15203D00A05F930D5A124DBD635468DFD3674BCF0B9DD8E33F85 -:15205200A1236F09FC1BEA87903F7270672FCD457DC236050FD3 -:15206700887764234E923CF49D3BA8CF3BF79CCE2607054C382D -:15207C00EF437C2564FC1FC6D6365978F986E13BFD72960F9219 -:15209100DE0C1F84C007842787F6BEC82ABDABCD63D111F4336D -:1520A600BA4D879E4FB31735879E2CFA0D73103ABACD2B53F1A0 -:1520BB0067E1EDABAFFF9186337253717644E0ACA44DF848DBB0 -:1520D000381B06CE026CFC581CBEDAD79EBC7789A80FB6CCA84C -:1520E5008533165D346CFD77F65B733B1B9E3B7A42E047AC7FA6 -:1520FA0019C7CC02E8C5935FE16F104B127F9414A53CCDC0ED45 -:15210F00E39E2796FE69CA736728E66976F30978C373E91DDDF8 -:1521240027BDA077AB599C04A78C0DCBF6035D2D7EB6C60AF085 -:1521390094E1F5E9769FBDEF6EAAEBEFF49DBBAAC367D9EAA701 -:15214E00C1710644E83FE1301778D9F669AB7FCA401C6BEB2D2E -:15216300EA034BB0FFE1659D7A70C75745FFD8E6E778EFD81756 -:15217800493E7CD174D93BFDC2D6C19E36E18245474CA78E203C -:15218D00D951852E5C8C117F2797AF6FBA7EDDC2C76FCA9FA8EE -:1521A200DD40FA96859FBFD7EBA4273F003FDF27FC3CFFEF82DF -:1521B7009F97809F7577E98E6D9E6661CE267F6EE1836CE6DE14 -:1521CC0038EC050B1F0BD8223DF8FE62818F9C68A95E1E2F6F3A -:1521E100BE45CC71FB782CF5AEB9ED97B0974B5BE9D9807CB1CE -:1521F600EC1FC21BFBE32C0F2A583310FF84BB0117EE5E369D99 -:15220B00F6A6E3AE9770B78D70F77736EE2E12EED07EC8D5FE2D -:15222000B55F586D4F6DF7056D5FFE505666DC5C56CC71C98A24 -:15223500A64C3EEBEC74667C2CC4BAEEBAE7333244D8E7E3545F -:15224A002E3EA44D2EF70AD8204B204722A4E3418E604D0A67B3 -:15225F002050EEE9944B9EE4BCA461FF0FE736F05EBCB3E449EC -:15227400896FDD4BFA016A5BC8946D4362CC627D0A7D2E76F53C -:1522890059A63EBB65CD74FFA551F8E6285C2FBA64E801D20F34 -:15229E00FA9232F547354EDE27F4CA906B8F8C063EE99034B72D -:1522B3000357276DFE4079DF42962F8FEFD495F33BB5A9FEFC1E -:1522C80086B0357697F56B42B7945917703526D65C86E20BB10B -:1522DD00A743632327752C2EA74EC47D7ED27308BF05F1A1C669 -:1522F200E2A841F301E73D29B94556137CAEF217382B182AC2CA -:1523070019BA0C4C5161776CC799BBF2D5ADD0B1587958D821CF -:15231C00D095271EB07C67AFE15EBE8CE6DDDF3F207CF7C2EA17 -:15233100F1D40333FB731B87B07ED12FD62F76931E5C34D629A3 -:15234600D609D8B89C301A8E58B04787E245F06FB4D33DB1A12D -:15235B00B8D2302CFAD7C3F66A384FE85B47F3883104BD08739A -:152370008C41735BA67FC591C146A7ACB58F9B79BE019E6B8741 -:15238500B2EB31BBCB86B5A2B80D8F711378285D215B1AB0B83F -:15239A00DB94ACFD988ECC5A8DBD3F8FBD68567ED2DAF7B4FD65 -:1523AF00110977167EACB5F4A978543A0F4CF12FA27110BF1F74 -:1523C4007D305A31164897E928B77CA2E21D94DE1B4D6ABE22CE -:1523D9004B2F4B114C5772E258F32AC4FBE87ACB96C1DAC1428D -:1523EE00DB8F6AB5E09123F1FBE89D03BB809BF26BEBC51EA3A5 -:15240300D8075C6BE7D35DF956A45EE8A0FF38D28DF558CFF983 -:15241800761CF31EFA82FD4FC0D1BB73480B8ED9F050BAD3EE10 -:15242D0016BBBE9E19DAED77B5BBD5CEF78C2BDF4A6A17F99220 -:15244200AE7C6D76BE8119E05B99FA661C67108E0818BF1BC70A -:152457001ED815824521F89E16BC734CF8CDF47E8F6065D6BA3B -:15246C00E01517ACDBECBA5F9C01D661170CDBED7C2FCF00EB9F -:152481004957BE1D76BE573E0056D0D881F5EA87C07AD5056B9E -:15249600CAAEBBFDFE1B61EDBA3F0BC3653B5FF7FD37A1E7FD24 -:1524AB00597A5EBE093D2FBBDABDE2D0738676FB5DED5E75E845 -:1524C000799376B76CC0F81A050E8C0977BBE8AFBD7E8F74875A -:1524D500E71FA7FCFBD95086E737782D9E7F5FB2783EB621DB46 -:1524EA0076D46BB5FDF0860F681BFBA576BB4E7B93AE7E6EB0F7 -:1524FF00EBF8E2CC751818B38E6FCEB5E9328FE4CBE5C1ACBCF8 -:1525140013E359ACCD22E69421FC099832624057F1F93BF5DD6E -:152529006586A6D0FCA0AC3DA597F213FA3E9A12DC32E809EAA9 -:15253E00D74CB2C729179286B4FDA437825F2CFFC7BD644B24A5 -:152553003BE0EFBD52D4959D1BEAA82E0FCD0B19B94A7A896F04 -:15256800DD9090A9429E3AF3451CF27448C853650DC14F725439 -:15257D00723D4F9D8FB0DFDBAF4965869EC61A18F6DAADB37498 -:15259200F6DC346CB56FD8F234DA678A35D5F121C3EACBA0069B -:1525A7007F17EC0B189897C85E99ABBCA2FB48E7C6DC34E37C24 -:1525BC0032945D0FC73A1CF6944270D7856FBEFD9BE6F339D379 -:1525D100D7C2AD75DCA3864CF348A0419C756301E917FA933497 -:1525E600B72D10BAC911331264D1D7688EF6150D0A9F0E2B1601 -:1525FB0058B5D807DA5DA66AAC7E2F6F13FB0B3D64EF579AE254 -:152610004CDCFFEDFFC3BD1C30B36DEFF238D159C0EE7ABF99F3 -:15262500F4B6E5F4FECBEC1F9722C609FAB0ABEC88735E5915B9 -:15263A007D237D48F44321BBE2E3FE0FF4F29215EFEAD9B4A1AD -:15264F00E175B1F412A7AD0ACDB2D53F4A5BF1E48D7535C6BE43 -:152664002BEA8A7E40F918952B5D33B5DCEDB18796587433CC8C -:15267900D5A09B5D2E4C79FDD3F2D6C52AECBC2A17FB43365DAB -:15268E006591AFC75C3061C77B237CE26C5D5D2CAF51ECBDC060 -:1526A3007F53E44F7092F13109F989A7113746B6E2C319880F2E -:1526B80027CE3F132F89B399E383A67B3FA9F5886B3F087BA603 -:1526CD00DB388F603F272A6C1B71BE5251E0FF613FAB3807990B -:1526E200DD0FEA75955F18931B9D3D21D421AFE17A8F589B1E44 -:1526F7001C9E74EDA33AECEF63A3F96FC977E57CD9F39EF47519 -:15270C00E951E9335250BAC6FE8EFD35FB2E7B990DB1AF319314 -:1527210075B30EB683FD2929DA5F628FB147D9436C23D3D8036A -:152736006C3DFB1CBB97FD015BCDEE66ABD84AB6822D67CDACF0 -:15274B008935B206B68C2D6577B07AB684D5B15A16669F66B73C -:15276000B34FB11ABA7E8FDDC616D355CD3E49D7AD6C115D55E8 -:15277500747D82AE857455D2A5D25521AE72BA16886BBEB86E5A -:15278A0011D73CFB2A1357A97DCDCD5C21FB2AC95C41D735C7EC -:15279F0075154FB902D32EE5866BF60D57D18CD7AC9B5EFE0F7A -:1527B400BC0A3FF42AF8C857FE875E3E26CE181FB7D6B754E111 -:1527C9008B4EBA3DE9F151A61E475A15A519F673353D8FDBCFB4 -:1527DE0035F4AC48F48C35BEF26ACA1FE1065BCDC7C95E5024A0 -:1527F3008D2BEAC2E34A8CFE93F49F5A785C8C2BB11E522DF667 -:15280800DB55D54ECBB7D3244A8BD96905769A87D292765AA167 -:15281D009D964369A88FDA14B02B2C1AB6EB825F60D8AE037E98 -:152832008061BB2CFCFEC254262AC16651F9F04B5828BD8D33C0 -:1528470075E1016F6899A8272AE2EED41AC549A9CE776631CD9E -:15285C006B95077C671A843C887FC0BBE10F78073F38BC2BA2B2 -:1528710077946E225D7EBD41176D8F2F361DDC3938473FC66D43 -:15288600189561411343153E7661037E200CFD1465C2ADC02FED -:15289B0070A878ACFCA96FDBEF99CA9BD485A661D7C35EB1D235 -:1528B000A3942F8A754A65A129FBC8A6BFC93D2A65F38CBB9EA0 -:1528C500154FF6D9B0D345FD63E9D988ED64F947AA7C42ACE7CD -:1528DA00A8563C48B12EAA8A5891B9F6B3F043F310AF617D2323 -:1528EF00BC8C477FE16109CF32332FA4B6CA91067DA2B241C487 -:15290400A998F8AEF70EE004BFE12B3046E5FC6C19CEE49A35C6 -:15291900840B529EB84FAD33F3D86D04FB6DA63714691D9F2168 -:15292E004D91AC34A6BE67C2BEAACE99AE9FA98648037FD3FD64 -:152943004155AA9389664ABCBD4E86FF8C5209F9ED634A2D354B -:15295800B9CCA81171196A4DA6002E55C012F594521B8B0DB4AE -:15296D002F9F29D595F8E27ADC7DF1C575B847D1D7F1B090F94B -:15298200C82BF818F29DF489B81813CB7844F8D946901E4BCFE8 -:152997005E4D79A2464CAC776BF659FC188F88B5932DD699FCEB -:1529AC00709B75469E6DB7E3F076D9677810F764360195205DD9 -:1529C1002461182CA141FFC1EFF796CB77B0F10EC3AFCA752C4C -:1529D600BAD39844BFC655C35A07B2CE2DD7A472EA449D549F2D -:1529EB00386783E768AFD15516D72431FFF59A9973E3D1FFDE24 -:152A00008FFECD579F3664F575D21913464495EF78E9A197A820 -:152A1500FED7FA918EB41A4A3B302DAD94D2764D4BDBB69CE0E0 -:152A2A0052DEEEFFF243EFD49262C6FDEA25633B3BC3E7AF7812 -:152A3F00476FA9F869EDD7965DB17DA5E362BD6D41FC027C739B -:152A5400845EB160C5395D4E0E1A9EF223ADAAFAAD7E664C9A2E -:152A6900BEAE5EA193637EF68DF52D0D618EA47698F10DF3161F -:152A7E00E91D1D7828603FAD1D7EE8974B0906A2E92582EB9C07 -:152A930021F17DFAD736BDCD6F89D05CACEC330967F1EBCB57B1 -:152AA800D5FABAA9BDE8CE617624176BE5C33E1F7483DD077C9B -:152ABD00ABDFA1F4FD07ACDF2FD8BFBF7DE00CCDB7C9EBD3C29B -:152AD20060477FD89FF09C3180B7ED6C8CC7BF935BF7C413B97E -:152AE70075581F3830FE356DDEF9FD5ACEB937F4BBD985DA799A -:152AFC0063A774C41685FE62AD2F8E8BBE96287FAE4F3E7CC918 -:152B11009C27BD46EF2F98BEF8B1A5D88342DD130F9F337CC974 -:152B2600DCBA912773EF10671887451C98E3090FD90CCA090325 -:152B3B007DF9EDA1CEFAD069AA5BF9078EFE28803BFABD611FD5 -:152B5000620529BB8F2B02FEEF1F7F9BC66081BAB70B6BB57987 -:152B65006A67BC27CE3589F49389CA1F1AD05192A4777CD58762 -:152B7A00F83ABC6BA2F2D726E5DDF34BB5E68E28E5DF115B5586 -:152B8F0007BB4A8C2DE59821279F2519E9AD8B8D1DAD63C60920 -:152BA4006302BC47EF317ED653BA9C3C46FCD3297C13ABEDD81E -:152BB9006D62AC197BC53E47B5186706F725F7D2388B73996858 -:152BCE00AB305E8FBB8FF13ADC113FCA97ECA33AC68C36EC2BC0 -:152BE300261386E4231C85C74CFC061F627C9CF92EDE0D923EE6 -:152BF800493A7F3261DE16E7227D8CD2F11BFBC81395DCF0C751 -:152C0D00E4BA00E96B1827139583E63CB22746AF7BEF205C9AE6 -:152C220067DE4FFB1482A789DAB8807115EEE71324839BA85E80 -:152C3700963C68BE91F1E7EE32FC8481300177A193D733E374C9 -:152C4C00BFF0632179D61D39A7FDE51772EBFA59A7D61FEFD3ED -:152C61007E5925DFD14FF6DADC44AFDEB3936B3D0D17C55EB4FD -:152C7600927ABAFFB645E59F11BA5B383E8C9824810509C4C806 -:152C8B0032E627459FAC182F3EE8A37111C3A55AC6DEFBDB8611 -:152CA000B41AF18A5F357BC6B806FF415FF22095DB0D3C8B58F6 -:152CB50057A5A9A7CDF9A9AF9BD5849BF9D4D7642EF634778BAF -:152CCA00F159ADEE16BEF1A20E85236E9FAF54FDAA217CF63673 -:152CDF00714EE50CC806393662D4A7BE437977D358E9A579EE05 -:152CF400A08E3A3D6787442CE5B6BF60AC0CF62FD980885722D7 -:152D0900AFDBA5539F0E78D6EDD3B7E4B1A9E3631CB16EBAF850 -:152D1E0057DE92BFFFB424E82262000553F033EA177E46C029AE -:152D3300E2FE045942AC5F8A78669FB77CBF906E8EF56AA5A9CF -:152D48005DFDE1D4F3496505D77DA403E7ACE5BAAC72D3EF4371 -:152D5D008CB783BC3AD2B714EBBE25EDC43FEA102F8DE3F709B1 -:152D72003364FF464C0D4BEE937D9AF2D7210DEBC2BE8CFF7CCB -:152D8700BF8881E3016EC67B8D2A4107EB8CA2447637CEE55AC6 -:152D9C006713AD3DBD37A92E896000ED413FA9EB981E5AD069C0 -:152DB100EE8F58E7DA104346FA032EF47445D0D1107E6A8AE003 -:152DC600EBE78E5F1636449788B723A748868D4F0A3C07C84604 -:152DDB00F60B1F837E116FC72362565BBE6BCC78CA443C46C088 -:152DF00029A5BEC2AB539FA875CB76C874D04FC8F58C4C27F975 -:152E0500BE25B72598FA8D29E22C1E07FFED32F7FC2E5D520F81 -:152E1A003F3B9B06C07130B5CFF0F05E3DD068C5BCF3906C4040 -:152E2F00DC763FEB5DE2271E99C77A6B41BFAD2EDEDC6AD1C9B0 -:152E4400D88E7BF99556C15B4437FC96C5B982B888E3047A8367 -:152E5900BE22361FC632D1733A2D6551D6A2C387E1F623D3083F -:152E6E003470E3DEA1C7C7A04181A041BF1DE7284B8B0FA58182 -:152E83006B6E75F03FF62DC4A72C0ABB69511CFB64ADB04BA3BE -:152E9800EDC3D79EFCE452259647F368BB01DB13B28A7F25B730 -:152EAD00EEE2BF38F2C79217A544ABE205DC94A84FA01DFA68E6 -:152EC200C53AB2DA407BA83B130F23A31F59F42873D1628780A9 -:152ED700A7CB3AB740EF11574B49ED33253521F808BF35D77979 -:152EEC00E0A0AB7CF0F399F8E022AE783F1B12FB163ED0BC7DCA -:152F010048F3AB5E218B15F007C99EB288257B32E38EFA2C6D48 -:152F1600C1FC4BF735E7040E689C06FB7F6BF53735EDB313D89E -:152F2B00A3290D75B596D1DCAFB2E4F1301B3B1E61A9E3D72E7F -:152F4000A4F3E93E4CBF87297D58B3CBDF2CFF9137A7E6AFB6EC -:152F5500F3631E1FFD8DDBFF14F32C8BBACB8AB8C362CF8D1B4F -:152F6A00D79F94EF6882BF8B3A1AFFEA99535A2E9917B2DADB5D -:152F7F0085B84805EAAB5D38FF68F9838F8933508A3A42764A45 -:152F9400C2F0A716D5C97F93CE071ECE5E4AE74FAFD30D9B3808 -:152FA9003B48659BD4678CC99F71D2890C1173C9E2C33F330520 -:152FBE00EF5AB19D267A483FAC233DE8E3F0E6C4CF7A8D84A7CE -:152FD300CB6047E496899F7133E1E9379BD41EF337D7313EE251 -:152FE800B62DD26E5E86EE13361CBDD48AEB6E1C34A0034B3494 -:152FFD006E003BFD3677FC17D2FBC25113FAAE83B39387B2F8C4 -:153012006EFD7516BFF3110B22544A7A79BB7196E0DECE629CE6 -:15302700A5C2FDD88FF2A7AA8DDCD3B5FAB7E28B6B3B972D9B72 -:15303C00A22BE631F8892E13FA539EF428C98F35869A8AF63372 -:15305100E557A6CF57A9C3D7D4D213172E2D205BC453AE8936F5 -:15306600105F167AB6B7BD562F8AD4D617509B472BEE5C3A3F3C -:15307B00A5D25C576D94A6C286E46FD43B9FADE5DE31B2FBC612 -:153090009799CE1E37621B0A5D5D6927FDB1AA56C65E6AF49146 -:1530A50061663C7CC0D785F301FF49DC53CB3D7764D7834AED9C -:1530BA00B882D5B69C0A939C5AA6414F9FA74A61118F54C869C1 -:1530CF00B241A83FB22B2695357F3E3F5C3676502FB3D7338382 -:1530E400340F63BE65E3AF9801E9B25E5759F419567EA695B16D -:1530F9002B5C61FFB03428BDABEF53BD75D005C32413E74B43AF -:15310E007A49E864AB2FF20F4BE6D3DD73AE4FF8AD601D6FEEF2 -:153123000AC4C23B69FBC7C4F9159AD78BE327F4C07CD24B94E8 -:153138008EE18FFA3F97746FDCFB97E7D517C7F2C82679C5604B -:15314D00A9E78FBF41E3687EEA6903B24AC411A0FE07683EBE55 -:153162005AD6BB2442BA0CE69B07BC86D05F7EFC0CAF75749694 -:15317700ABBF4BDF546719FEDFE99BEA2CCB6EA6B344DFE129A5 -:15318C00E7FC27640CE1CA57F985A505620F0F783BB53478FAFC -:1531A1001754FF29BE9E70B77F99E19CA917780AC54732780A6C -:1531B600A516D5FAAE604FB963587EFD14E473685E6A562DFD13 -:1531CB00368A5325E25E905A20EE06C9F199FA4FF369BD67F568 -:1531E000BBFAE56B691FF080BED6D87D9F78DFEAFBFC19FA8E7C -:1531F50032C3D73E7EFF1710DD4B2147A33DFD6DBF9966BF5070 -:15320A001FC55AAA8B9E6BDD79A27DC63DAC9F6F201D3DF78709 -:15321F00BD4B54F5345920295E2C91DEA55C3083365FCA381F10 -:15323400A4FCC4DCCE2EF280745587DCBB65C5BB7A78EC3BF5FD -:15324900B73458F8BC85BD63F975517BB7C05E095F143805CF3D -:15325E00C1BF133EA2E5296F9D9367EEE94B19BCCFA5B28ADA53 -:15327300DE1F2F4CB420EF56ECE54447FA117B31E7CC29BC3BCF -:15328800E0397B4A37D26427D1FB6AF50B4B71073C93CBF3EE4B -:15329D00D8F6D04F491FFC89E1535F3E50A3FEC85C3669F73195 -:1532B200BA6BD88FF8AAC9F5DC7A86ADB46BF8CA72ABFC49C28D -:1532C7005BD0AEEBDAF2C796DECE5EA813B68E2B2FCAA20E77B1 -:1532DC00B9B394A7E3A90B5A58FD8F4B908EF99154E5CFE1F98C -:1532F10019CC91D15D49E89F285B803D65C225BE1F33BFE7B062 -:15330600C0EB3C957402BBFEA229CF736B3DD6737F813ABB967E -:15331B00EE86A7C8D2CB51BFE7EB7B74A1037C876405E9576696 -:15333000E4794D8924F4529A3B443C16C53A83F361FF34A7745C -:15334500495DEB75F8193265A7987794129A3FEC7947CC41785F -:15335A00F731E61F67EEB1E7A119E71FCC3D9883EAC599FBCC51 -:15336F005CC3D5316BAEB1DA5159A9FA2B730E74099A977C6AF3 -:15338400B7B9E5BDB4AF20C9BB0A08EEFA48A2CEB1FF4A691EE8 -:15339900439ED5EF39F4EE349AEA2CBB716254BC37F03E4CF834 -:1533AE00417996BC6C486557881F39D98D5D3C37998817533BB2 -:1533C3004A72A41F632E27758AA34EF01A78AE5AFDD901F0D4A9 -:1533D800C5F71DFDCC8699607DA3E7591AC3EDC6D65F58F3BB94 -:1533ED005897A5B6467F951D5F8190E5EFE1B3CF1924432C9F18 -:1534020074CFFC2B01EB77DCCBF23748AC707B0ECBC77986F8A2 -:15341700D8D46F3B4DFC2D4D4C1711129DBA46FF6DF46FD0FFC6 -:15342C0030FD8FD3FF04FD2B3FA2F73FB2F28ABD83A0EAC46896 -:15344100E467C7F0E1884A1DB1F06F555B97B0FA5F755EA47C51 -:1534560015FDCF100EAE926CBE6AB2FA761EFB4B7B9DAD7E8045 -:15346B0027E9B947F5B62834AEC7DE465F470DC4BC14E73EEA46 -:15348000BB39DAA977F43BCA1FA7FCB7B2BDCDE299DA539A5FFA -:15349500340CF4433961C0BF36B4E298CE627B39DEA3EC7EF867 -:1534AA0063217634D5592CEA7C45B429621B7D601DC77851E412 -:1534BF005433F2A3CDB9A11BFDA9597082F7B2ECFEADF0DF0892 -:1534D40066CFECBF799A1AA43993D59FE216AEE1DB316CF5B34B -:1534E9007E888B36C73B0DAC81948C1DD3156AB7247E54878F79 -:1534FE009EAC4E4DC31A888FD202E35D7ACF84A7C5FDCE47EF92 -:1535130042CA7FD3FD64878E601FD4D97725F8FCCC155F697AF0 -:153528000CA57FE37B9C131A0922364775EB55BA7B953A1D3188 -:15353D0072FDB14A3397CA5C0BB142F9BFB61B56BC617917D2C3 -:153552000629CD1F1BA03967917E71B9749757E9D0C7290DF1AC -:153567004BBB903F5669E07C8D8A73A29426C706CC61A4D3B355 -:15357C00417C7B9164217CFC6BE63271C68307B23609CE1C5FF6 -:15359100F558F1B2B6219DE007C079471077F45DAE9C7F464330 -:1535A6003F4AE11BA48C709FFF98BE8E6CB339AADC92973A2800 -:1535BB00E2B610FCC5A114F2EFED90BA7B853F27CE18DE966C99 -:1535D0005AA2F82D5F0BC466982DEA1C3AE0A33C3E2B4FB034D1 -:1535E500292F918EDC589645F304DE0C9AF7AAE658DF8082FF11 -:1535FA00BDC3E7E373E0979EC8F887C9EAA4D95A427822B92460 -:15360F00137EA2F4CC66F0E72F25BC5BDF3CF96B737BEA6F0F36 -:15362400C897DAF5CBC553EBC7F744DAECFABDA1B156CA6B50E9 -:15363900DE7ED4B58764E75A196B3AED343E2254FF6AEE53F13D -:15364E001C6D853FB7447A2EE9C2A65FD5CDB504838C33722494 -:15366300A7F17D95F96A3B87DCDC537646C37AECAAD43F13CFF4 -:15367800FEC05C4DF724F1C25ABAAF4E7DA61FB410FEE76AEDB5 -:15368D00011FD5514FF59706587E581DE0169C5FE8079C388F73 -:1536A200BD92F475D8309EF258EB9EB2360DF23E42EDC4A82EF4 -:1536B700CA773C4AF7CDF41FA1FA733167184D7C436AB919A3B7 -:1536CC0076A2A9FDFD38F3B09ADA89AA3D070E521E8DDA3AAA9F -:1536E100D8676C4987403B84C0923D6549AD551D306304D7662A -:1536F600AA7F82F07335C00A7D54E632DD714E9EF8CFBC46CFF7 -:15370B00ABA88E8900CE1924F8167A7E35007E575BDFA4FB6AE1 -:153720004A93296D989EFD418B46D371ECA697F7525CDF4C7926 -:153735008B55B939C745CFB03A48B8867F31F68427699C0F9A63 -:15374A008A4A73DA349A875F9B2AAFE12FA284734806776564EA -:15375F00301C123057DF4DD38107E71CB78D7051CE386594ECF6 -:1537740018B4E4DCB663960C8AEE35E0D33217320A6B58888D3C -:1537890019957765DADD3669CBEF1E9249581B3C684A65713D24 -:15379E00E37F4678A0692F9FE62E23389BE5E3AC06D9408DFDF8 -:1537B30012CB273E32A89F8D7E1AC705EA82CFACCA63F9F3E96C -:1537C80019DF929195DDFA28F169BFC20ABFCCAA1A494008FC7C -:1537DD003E42CF09C5C26B39AB6A8EDA721FB240C04675602E4B -:1537F20088501E12E685CBE8AE282FEA997874341F5FA8686FF7 -:1538070084CFA788BD46F7ABCBBDCD0AE5DB5A7CE31872C60954 -:15381C00F6CC300E2798F50D3C278F9FF860A7FD9DBA72D5DBD0 -:153831005C4DF5E4975F213A1D9A820B85FA73167CA3DC26CE74 -:15384600D0EC8AE13B033DC613915ED1FFFC4FD3FC46F800FFDC -:15385B002D25B4416F7FB508E30EFD7AD1C01CD1C83A455EA932 -:153870002CAC77E663AD63C0AC72FAA5741B32E916D5E0BD40AC -:1538850017740503FE7E0AD581323EF5457AFF2B33BFC82AC7C6 -:15389A0094174DE0783BE5CF75CD5B6AD1D4F59B6B45AC3048CA -:1538AF0079268AC0F35546428C936A314EE0DF0499FBE6F5749D -:1538C4003EFC750AE289466FB45A57D54AE3CA72A97994CAD023 -:1538D900382EF4BAEA2FB6CFD665ED55D598781B01B576EAA8ED -:1538EE005B39FF7B22D6307CB5B09624931C95A9BE2292F7E8B6 -:15390300C7C44303F50FD2337CAD64711EC8D603E0E3F536F634 -:15391800F82CF8E5D810C9A4170D712EDDD255D3C53407E3FBCC -:15392D0055B2FA8C69CB9300BE0D09F926C33FC2FEFEC424D5C1 -:15394200F3E318F1606CC85E334EA7FF6A6CB0D14FBF713687E5 -:1539570045DBF9F642969F5B4934B4EBFE2DF5DDE90BD67050D7 -:15396C008785AB230257F0FB0DB1458D4E7F0AA80F93158B9A3D -:1539810071CE7372162BACB8981D3F326414D96517C986FC2802 -:15399600FDC4FE9B809FF409C0E21D233B3B3A4A750D4057248D -:1539AB003C7467FC45BC946FB480E5DFA30276AB6F778D250892 -:1539C000B735A60337F611FFC7B19F1CC5FA83A82F84B58C55BA -:1539D50007A03FE3BD903D36BEEAA7ED4F59E36515B7F15B828E -:1539EA00FD0F3FE5298EC9CD9B73B26347C9AFC1B7BB047ED1E3 -:1539FF00D6BCB141D2A306B1A79816E71AE9AF3CF242E3453F3E -:153A140070F373DD194F23F6F95EE80781F1A7F4C0F9255AB02E -:153A2900BD419F97929A049F19DD7C07CDEFBE50360E0960AEE7 -:153A3E00639F6A862E3096EFD0CDEAFB6FD177AA0BF97136C947 -:153A53001FB3E28A20CDDBB448C46C9745DC120BA6BF2298E058 -:153A6800DF081AECC7593A9A0333F44D791BA103CAA9534601AC -:153A7D007BA57132ED6D9E97F23607A7F58164880F78925343FB -:153A920037A72BE1183038FCE84F9D30FA52DE9650D3908009B9 -:153AA7007066F4D570B5A08B22F42AC0FD29EC41091CCD8B0F3C -:153ABC00D43B78D94C32D76BD3CD473A5451A5D468F5CDC2C5E5 -:153AD10075C1E30306C64D89DDCE3F52F98FD3DF85D4DFAA4288 -:153AE600F437ABCF839FB723662FF1815F75F529F6B2D117930E -:153AFB00B27D52AD3E59F850459F9CF3D2363D44BF0CD798284B -:153B100076E10E7A01F0E6F4674EE84A2BC9419A7F7F6EE6B539 -:153B2500D3F852F6F0373C969E087C6C60D9710F19B839730EAD -:153B3A00D7D28BC4B96ABBDC412A071E49A28C4B9E857F379504 -:153B4F00FFFDEA51923983FC4F2343B5CA8E11D12F5FB2D374B5 -:153B6400FA0C79017E2F16B1E59F35DDB20973899C7CD6EC230E -:153B79005D5321FB3E4032DF9F841CE3A6D5CFE12C9D934346AA -:153B8E00A8E984C04788FA60AF6F171440BE8AF1C5752BEEFC13 -:153BA30015D1DEC2152FB8C697859FA2D38322FE2F70F7C8C3D1 -:153BB80096BF2BEAFF0EDB4B7C3068049A3A6DFE1FCCF0FF61C9 -:153BCD00E27FC0073B05EB7C820F62E003C3E683D10CDFCFCFB8 -:153BE2009FCAF747057F0E66E9AF8E18A82BCBD3832EFA774D11 -:153BF700A33FE0D96BF537293763ECB8C70C7ECB49C4324A1863 -:153C0C004F936CB360B6FAB98BF8DAE1E110C1574C7CEBC07AA5 -:153C21008D602D2758DB7C37F2ECABBF01BFBAE08D11BC311723 -:153C3600BCAA1B5E4B36BAF502A5A953C0EBC8216B6EE8123030 -:153C4B00CB31CB87CF8824DA8A5C7362EADA541EC4B91256DF0C -:153C60006BE0FB53B01DB5FF952ECCF01FD92E6F2256C061F98F -:153C75004E2566D92FC591A33AA972C52595724BE07CBFE6913D -:153C8A0058600EDE8D8F18CAF9A426930D739CE055C8E6958910 -:153C9F00C7B0AEE5F321561CE721A2A74AB64FFCA9DE960EA415 -:153CB40077FD33E6910EDFD953629FF44AC5DE3BD8F8A8618648 -:153CC900A516D4539ED88B98C1C1B988EF41E9896EEC77ED3513 -:153CDE0065AA0F7B61E237B52B8BB5FABDA62887B68CBD387FDC -:153CF3003CA73C2937B65B653AE26413E16C936F2DD785BF237A -:153D08007C526C9B08B0A2FE9DABB996B36E528FD370E9FD2C8B -:153D1D00D7D06799CA94278E6D02FC98CF010B60036F2E2318BE -:153D32004ACE9FD4E662CE7FFD59BD98719A2F92DAB7302FD91C -:153D470075E2FB086DD4579473FABE8BEAEFDA7742F851827F75 -:153D5C0044DEE84887AFFB9FF51460A33EA12F6CF220CE5EA6C6 -:153D71008107D29D39F0B9142C4BEF1D5C5CCCE0C16A2B830789 -:153D8600ACDF8D5B78087D576EEC5A873DC921DE4EE9BD185FB6 -:153D9B008413A4C13644AC330BDE538483631AEACF59F76B7D0D -:153DB00087C0C3312D40FD030E149C3BC6DA3BF4326A0B310BAB -:153DC500C3D47E39C941271EA1751E24CED93B8CED29EBD2DED5 -:153DDA0023DD754198FD61952ADFE5C45B1FFEBC88472874DE64 -:153DEF00D5C2AE5A7420286268EE16DF804059E2EB7CFA3D8C92 -:153E04007DC0F17F72C5B3251B113184845E087F7AF8A685976F -:153E190071863C4ADD01D249C6E2D5DE16C957A3CB91C5FA20AF -:153E2E00C18AF80B48AFD0FA750573907A6FA34FFDA346457D70 -:153E4300A0598EAA3ADEA54847C77DB3388FF4E722966149836F -:153E58006A5AF51E860E34B68CDE5568861E8E0F36D6501DD54A -:153E6D00544795FA40A35347A9783FB58DCBCB1F10F5FA45BD41 -:153E8200BFEA70F25ABF0F1B89E57D778A33DA0D13565B510BB7 -:153E97007EE0EAACF0EFAF36A3948E39F62A6385D2EAC5BA120B -:153EAC00818E68F793F20D8A7C61BE01E58DC526F28ECD90178A -:153EC1006D6F07ED92569E8337C9B30163D3CEB3FD2679C294B6 -:153ED600C76FE7D9302D4FAE522FBE37847CE095ADCB7F762708 -:153EEB006425FA21533F719F43F2DCA79AE64CEB596166FBCB27 -:153F0000638C2A8363D86F147A0B3DE34CAD88371B8D0BDE2D37 -:153F1500B1CECE67D68424C9E2B74CBD549FEAAC1F093F34B224 -:153F2A004F7F90C3B07E029FEF94A06FB6BC150BEB8881746A9C -:153F3F00D3AA9FDE958C3FA707CF3FA7C1462DA1B1126C1A1181 -:153F54006397F836A0B013F598673FF7560E53E3234B133497BD -:153F6900FBC9362A461F146E5A3E6FC233A400318BFDF1634B40 -:153F7E00A04B237F10F53B700839DE65C11749D48BEFFDD9F533 -:153F9300CE8F0F2EAD99566FC60EA6B941949F617DE61FEDF10C -:153FA800877EC15626788B2F63DC2855D9F2EE785B347E71160F -:153FBD00EB9F662877745A391A9F379C27B4CA1FE23F9FA1FCAC -:153FD200D68F50FEDD19CAD57F28BC87F89519CABDCF3EBCBDF5 -:153FE700D434FD0AFC1274F31FD6D5FFC9F54DBA19DEC7AF7EC8 -:153FFC00F0FB890F7BFFEF5DFFB4F77EF778F8A0F5D6FFFFFE71 -:154011005FF55E71E1BF789A7CFA7F077E9B3FA69D399A78FFE4 -:15402600C6F1F061F5B9F94D2A3BA2F779129B3F2ABF61BCCE52 -:15403B009155FE79711EAABAB553896D5E49C3DA1FF8828EF8BF -:1540500077F80EB8FFEE6E1D631E3A823FB0459FB5AA5B57D5B8 -:154065002FF15977B7EBC1755CF34B957AB0A8524F90CE66CB4D -:15407A00874DD7482F5102D53AEAFBD7D675680DD786E173B5CB -:15408F00AE4A877F33BC776435A7E57192F925FE4ABD605D8D23 -:1540A400FEF5358BB58A758BB5907FB3DE99F37B1AF6A316C828 -:1540B90031C4C70922AF2C7D4217EB40ABDA850C822CAA284A4F -:1540CE0068F08372DE178BF78B756F202EF4DA8A07E3BAF0CFA1 -:1540E3002438CFCED0FE4ABBFD426AFF10B55FE26A1BED9653F3 -:1540F800FBC827EAA5FADD6D5FB3EB9D70D59B4EFF34ED474C7B -:15410D00C55AD6B29E4C18D41DCF8971E022CDACBA6EA7297B4C -:154122002EE1C54F6DE6AF5D4CF8A9D416F86BF4F99F965BBC93 -:15413700AC7D63C51FCB2D87662704FEB12E457378106BA2B712 -:15414C0009DD240BBB881D01FD90C59F147D2398CEDA308DA2A4 -:15416100EFFE0D7AC5BEF5BA54E4C096BEEEC0D648B095FA2B21 -:15417600457A9C14638756F94535BA5FC0D4AD2D284AE83D3BB9 -:15418B00F764F80078FE6D3A6DC3C0443F71F6CEDA779D78128F -:1541A000ED8EDB7048655DF8269C6F36B76008ECABD203D41E5E -:1541B500FAD662FBB8C3394CE0252F8B970AE29BC2B54D7AC9E4 -:1541CA00BA7A01CFEE9C6EAD80F052E84FE8B92CB1718FCD975C -:1541DF000B45DFB3ED5EA1B60C7A17207C11DD8B1D1840FB8A9B -:1541F400D51B34D8DC15EB3668D3E94F83275020CE13B2828A7C -:154209003307C57BE95C8D5EF2604C97D997F45994E780C44203 -:15421E005EFB791F3D17AE23F8884F0A8BEA75FEBD06EDD0EB49 -:154233000D5AE1B9B57A09A7B47DAB74FED97B88DFEFD140FB92 -:1542480012C265C55A0B07724C6A51D9165E4F38F34A0FEBFE75 -:15425D00580E62F807F3B15753BEBA7596F4A8EE9757EAFE153F -:15427200D4D6DD8FEBFE55F7E87B73566A5823975764F3E7852A -:15428700AC3324227FA2D6CAFFDA1775FFAB0DFADE9DB59A97C5 -:15429C00E6ECC0F7366B159FCE69C177627CF1DA8DF9630D1B06 -:1542B1009FC6B78679AD5E71EE615D3ADBA073CA2BF9B2F8DF16 -:1542C60086311D12674E362176B4AF9DCA9D6ED828ECDA65ACCF -:1542DB00253710DE981758B6B1A26BBDB69B6401E982C5BBE8C3 -:1542F000FE879031FFF331DDBFAB41870DA1AA8F72B16F98F838 -:15430500A22EADFD922EDEBDD640EF6BF5BD842FD01C7C0DFB89 -:15431A00ABE09B524BC539C21F6FD74BCE7D512F3CDB2DE8DE86 -:15432F0043749F45F42E88F08D6E39045A835EC25FD7A623F818 -:15434400F06E82A505F0138E11377A1D3D2772B66AB3A81DC03C -:15435900DFB9D37ABEFB7ABA0472C8F98DBC34AF6C3A4869289B -:15436E000B7E36C98C04FE20E7C8BE9CE3F0D276CA237CAB09C3 -:1543830086ADF41CF8DE7CADE26C29E1B3549F896F7EC9B27C78 -:15439800F377CCE21BE0BD80F826E4DF2A70F1759B77C03725B1 -:1543AD009CD2A6F14E77FCBEC70A425B8826B1D66EF6E863B372 -:1543C20042D156C9FFB8EEFC2E8C3CFA186833AB7DFD46F67A95 -:1543D700CB46E75EF1AE477C1FA220BE7E63E158CB46299FE89F -:1543EC00FC894AEE25DC5F277A0367B70BFC7B5A0A7907E1FE98 -:1544010071C2FD1E21B7DDF8CFB1F19FB0BE4B11947C9FA0B6CC -:15441600A39BCE085A8057A29B46A7D102DF6D7BD0A605C9D76D -:15442B00E2F52E5ADCEAA2C57BC287303B8677D2F8ED75D106C1 -:15444000EB55A03BD277D8F4394FB471E8B1659AFFE787D1E3D1 -:15445500828B1E7F65D30363B8C4A6C50D7420DAB86991177966 -:15446A00E4B1DCC8FAC7D876D6E21F7B64E32C65CBC63CF69F69 -:15447F001F2B88FFC946FFD8A3E277C51F8B315AEC67F43BF207 -:15449400258177794725F7908CBD9E17E5050EDE696C16FA775A -:1544A900929CBB5F2F5CFBD414BC17CC84F7AE85A0B90BEF3177 -:1544BE008177A7BF6EFC936C2FBEDBC63FD67C30361CFC17BBB3 -:1544D300F0EF116B37167E7B6DFC164136D13BEC33BBF9DE2957 -:1544E800FF4B21FF2D9AA19C887B69D3C1C279FD14589E408C43 -:1544FD00AAA4D48273D5099237B954C72304C3A17B37EB15EBF0 -:154512009A34256789969773A7061EF693BC61AF376C3CF4031B -:154527007A776EAD569CF3592D3FE70FAC77D2CA8D6CCD3D1BF6 -:15453C0077C73C2D806B2170522ED6B603B9AA47CC8548473C72 -:1545510037C7A641FBD89BCA71E6687B9E403EF80E03AEB7C9AB -:15456600ECA43C99F1FE1A8D77CC5117D26905EB41D003684EA5 -:15457B000BBE6AE7FF163D57BC2BE35E7CD2EA77C1FF01EF9849 -:06459000C0E6B892000035 -:00000001FF diff --git a/drivers/atm/pca200e_ecd.data b/drivers/atm/pca200e_ecd.data deleted file mode 100644 index eca84aa7e0c0..000000000000 --- a/drivers/atm/pca200e_ecd.data +++ /dev/null @@ -1,906 +0,0 @@ -:150000001F8B0808AC5A10380203706361323030655F65636428 -:150015002E62696E327D00DC3A0D7054459AFD261333136278A4 -:15002A00192663E02479728060A10E9063213F64F0700F3DE05E -:15003F009E6CDC7B2F3514B35EF0A28B9A5A731E554B91474C5C -:1500540034E11AB6692618B7609D8404A2121CA8648D7551435D -:150069009DA578A56C8AF276A9AB829DF3AC92DD52CC5EB177A0 -:15007E00D4CA32F77DDD6F665E263FA25B775B7753D5E9F7BEA8 -:15009300FEFAFBEBEFFBFAEB7E79F4A91F6C270A21A1870849C1 -:1500A8007C974CFA8536C11F37B9A99FFEAD9C49302569258321 -:1500BD00D8EF4EEE6E14EF59E3B3EDFED3E3C735EC67E50822CC -:1500D200A9FE0FFD29BF7CEA97A26F4EC993D537AF13234A5E2D -:1500E7005EDE94F3BF245F4AFCF1F129E7CF9E866E0ADE2C3919 -:1500FC002BF0237F849F3240F688FEB5EC75792D39E3BCB43E9B -:15011100C9A9F54BDE24FFBC9C3C6987DDCD33F3938CB0674E4E -:1501260078D6F8D7D63FD9DC8CEEABDC4824B2F9DC949E391965 -:15013B00FED7BF11FF975E7267F17D1CFB4BE77E3625BFBC0C26 -:150150003F0FF9BFFF5372CB72671A1F3D3EF99DF51312ECCF0D -:15016500C070095C0E5FF8FFFE4B3A7E246851FDD31C5230FA46 -:15017A00FC0A35E009832F79ADB5E45140A3A4743C8CE3E39F62 -:15018F00C35BB09DEAFF05BD7A95BB3DADE6B56DADE538465425 -:1501A40052C90E11EF08B4773A8857FB013CB7112F090619CEAC -:1501B9005B125380AEB695F80197D874FE9A9022A5D554ADE572 -:1501CE002661CA73EE80B5F5F26AE22D7F9A78FC814838484AB5 -:1501E300E8B36DBD4D843D4C4930CE42B06FCC091861CFB9BDAD -:1501F8002621C3B438D010BE6DD7091AF29090DFEA334930C6AA -:15020D001187E86D9CB09E2EDF18033C8DD220A9BB6D57390DB4 -:1502220011D2D8B26F23C02CEA0FAC0EB76CBADB3C4F48F1BBF2 -:150237001157A5EBD25FC0FCCB804A3412ECA211D133EA167DD2 -:15024C003B8518510311A53A5FDD62226D9C4BD46AEA567ACCA9 -:15026100362DB78EE8A7683E21017F201E4E927EEAB6169944DB -:15027600AFE1ADE3AEBAC0C53534B0EE4194CF8AC2FE47C6065E -:15028B007960DD5253D1FA6834346000BC45C0D909BE0A681025 -:1502A000BDD7BA4BDBBA12ED8A7C09EB8EA79BDA6BF9816681AC -:1502B500F70EF3723259F4518D59F578B3AB0A66E7A3597F0E69 -:1502CA00BA90E04E5BEEC669E5765D2A33DD6762936427C1D5C0 -:1502DF005CDA40CA8A7AA03EA807AC0147BBA02E52A72974180E -:1502F4007B956F461DD851EB3EA14348C8A0EA9689F2332DA72B -:150309000E7B941FFB00D8FFD6801526637B69AB8FCC22A5F03C -:15031E00ACF65863355BCB4740B7F5A05B6A3CEC239954156CC1 -:15033300E7B09E9AA7F084F085DB760DD171378910B6285EA406 -:15034800F64A5F403DE05D8BB4C2F800BD8EE3418BAF06B8AA3D -:15035D00EE81F5E96393DE6D3B92E0385D564748698085091946 -:15037200A79EC256E0D34F49792B1D759310AC032BD6FBCDCEAF -:1503870038D845EFE5456A87F95932097ABB5B050D98BFE30F8A -:15039C009CDF2BE6B767E667E6C6EDC6D24DB7E7A56AA4888777 -:1503B1003626DE3B6D253EE5C5810BE19CD8095A7CFEB241D8BF -:1503C600765A663C6DAE8CBC4EF7B70D35420264F51833C16105 -:1503DB00A6438F32018C232C303A64E29A23DCADBDCAE604CE52 -:1503F000C2DAFC0BE48392B027D20C3E546386122FF0964DDB3D -:15040500C0A7BEC35A366D323B120AE8B357F8531ECA1ED46DF0 -:15041A007F6AE732A6800FFA49302E6321B8C48EB97E560BEFE0 -:15042F00458110CC6910FE9B84D825C10415992A67940623CBF7 -:15044400E9EC584E5DD1912DB4E84C9DA9C486689188ABB8F0F0 -:15045900BD43E494A124DEA49DE43503E75D87B4D6F9E7F81CCD -:15046E00E748EF05F296419A062866F84EF23AC04791363CBF24 -:150483000BCFC31CE5D213EF71C44759162BA4E81F2077148DF9 -:15049800DE677E1BF429501F117ABAB5A3E037FD527EFD21DE68 -:1504AD0072EB2653890C502FC844D803BC937403BD7E2113CE66 -:1504C20027FA51FE0EC4AAE7DCA04906DB38E62BF04FDB0E52E9 -:1504D700EFC24B09339A731CE3886F2C203A191CE0A344E0591A -:1504EC00183F514DC49F88258C471F213EC2FAAC68A8CFB85650 -:15050100D6535DAAB92A3CE7C0EFCB0728CC6BDC33EBBE3AF4E9 -:15051600E76BC964B19EF8949519FF64CE568E091F74150C995D -:15052B00885B1C83D82FEF43FCD0E167A306513B39C4E31CF4C7 -:150540000131A6FE965F4D26FD9E7387CD79E78E9AE46AAF90F1 -:1505550009FC2A0E7E2562E5D1C8C62AB40BFA87E7CCA98C1F9A -:15056A00E07CDB0F02E0079ED07A136DD5DEE892EB27D74DDAA8 -:15057F009075F0D47A1E222F1BA9F524FAABBC1763C2F6998923 -:15059400F69376FBD1FB4F007E4396CDFA85CD8A1BD166C3B678 -:1505A900CDE268B322323660755A03C6B5E64D2B053DCC1D2390 -:1505BE00D266445F1497ADAD0B68E03E15BF6D6448D8278AEB56 -:1505D300C80678BEF73EB0C30FE947E092E01FC585095735DAFE -:1505E800F671D7EE55CF245C958188AB5ADA037C046D01BEE121 -:1505FD00BAF4A9E9518E9B1D5AC626FE09B121732DAEABB48BBB -:150612008C15B459DAD7B3F32CC428FA34D7B6547ACE7D067369 -:15062700345B4F0631B39A266B102748855D9AEE95FAA9DD5677 -:15063C00D4EA35EAB4875792D2583897B499FE5D3F12FA91FA31 -:15065100A3343AFA18E487C7B823BF7489DC027E87B620FA20D5 -:150666004FD1F043DE9AE5B0C528F877AC664BD58D1BD21EFFFA -:15067B0059BA7B79AD423CD23EFF6EAE509A67B0CF7B609F6360 -:15069000FF23F63989F6D9BCD64CED8550E85072F557D21EB076 -:1506A5004745AD6EE339DB1EF3C922D37F7DA9B0478E5E629653 -:1506BA005AA5D57F827B8FBE9F46125FF04F66E1FE5412866761 -:1506CF0086F945D818ED469ECAF8A08A7BB46860BB6E87ED4EC3 -:1506E400F114BF6CDB45C1764D60BB8F6DDB5D00DB21FF8083E0 -:1506F9007F83CD7B22DFE3C67E6F5F26674C9F2BE638724555DF -:15070E001A0F7DDA111F0B20A778361F4BE710B11F8EC13CAB3F -:15072300CFB85A932B64C35C82792494788F611E51E60E9B4A3C -:1507380007E413987728E1C8273927219F0C603EF1E1B81893A8 -:15074D00F9A4D8B3F9A4F963E02D724A539F88D97980873AFBA5 -:150762001C3A37E59359CE5C33A1781D3BC1DC9B7BCDA235ED12 -:15077700A29E2C523E379B4988CE17BAF7F3909FE8EF821F7925 -:15078C000AB11608D25AE1474B445DF7FC5CCD20E5FB68A3A870 -:1507A100170E70A2DF010DFCFD7FBBF54429CA4C9ABEA016F86E -:1507B6008190DD315E0F7E5103E34F925FAF825A94A30ECFCD41 -:1507CB00EDC7BD45FA3FEA06F6167AA890B7BE6EEB8ED2E275F7 -:1507E0005F9819585F7C7324B932C5ABCC90B5C0CDF0B262939A -:1507F500695544DE16B4F419E647605EC90313E7DD13D9B652B6 -:15080A00AE1BE31B70DDEC7941C02DC8C25D1129B371352AEAA4 -:15081F003D7B5DDD02EF009F3F4EEA549887F684FAAA68452469 -:15083400AF42D45290DF570BFC56BA0BF015C4D73BF911F04B90 -:1508490037E243DE03FC62DCA7D1977CA206EDE5CEFA7063BDC6 -:15085E00A3BEDB4CC197290D617DA68BDC791A7B55055EA967AE -:150873000D7A477DD7EA98BF20E2AE48D57848C3FD00350F601C -:150888007C421EC69849CFB37FEA060FC6604F20B001CE496318 -:15089D00F45BB141FAE3B6A126DC2B99A8E7346641AFCCBD0C5D -:1508B200FC9F80B3D24E383761AD1C83FDE1320F41BEF0EFBA70 -:1508C7005F9C89FC501BE39EAAC2D98AE8F5D48775DE582DD4FD -:1508DC0079C130D653FB649EE04837404E899AD0B2CF592B7220 -:1508F10048F13F47DC707EFA7B13EB3699AF0DFBFCA4DB755C24 -:150906003B75477AA046AD605EF541B3E5D6BBCD36A0A978FFF8 -:15091B00C6DC8B750C9CBB3007DDB2E7553337827B40B7D80387 -:150930008A033190A792DF42FECCF4C379E3167106B1EBAEB1A5 -:150945001EEEC7F307D45D9DA1DE74BD05671CBE429CA18E43BC -:15095A00BE5B682CD0CC95E2ACA1F6C4DD381FFA828EE5E21D9F -:15096F00CF4F17DE36CBDB9B95EA476A72D279D11F53A6CF9FA5 -:150984002F7597077ACCF25BD6C49886A7633517D785EC80E7CC -:15099900C4DF12320AAD0BDA4E683AB425D008B40B301E87C6CB -:1509AE00A0E9625E4FDC6EB04FF43059BBFD16CF2CA13DDE56FB -:1509C30043BEDBB50EF83FC2317F3629F20C3409C7410F71268F -:1509D8008F2F88CBF60A4BF1D9381D5E9ADF82B8362D3FA475C3 -:1509ED00BA4BD293F8E3643ABE8067E39C2533D1CBD03A3C13A1 -:150A02009E8DD33425BF89326D9C964E46A68553D2C9D040BBF7 -:150A17007F55C31A995C3D2CF1C7A25CE40D8CB1E29881790360 -:150A2C00623586F12B629A58F412FA289C3F647C34424C9608E5 -:150A41007F9B2E4E5E8138715DFA8579CB9E939363247D66979D -:150A5600B181F1823501C620C60CC64E3A56ACA39958518FC96B -:150A6B00B3FA18D457D69F1A6B2156F09CCE223913E224153FF3 -:150A80001F431E9A8D7990EDA5175CF2ACFE817D7D38027114D6 -:150A950081380A7D8D38DA6CC751C3639938FA009E23DF07232E -:150AAA004223D0128F43850E8D416B8016825602ED1AE0753D49 -:150ABF0036318EC41D03C412CAEFD9DF938E27E09B965B03B992 -:150AD400F7BCFF8A21C70726C557AA05537E9F8DEBE047317E33 -:150AE900DEEF81F157441D23C75BE2B2C13A3649FEF5022F9BEF -:150AFE004E8B23CE5AE21F91E9F8B54C8AB35E320D3D874FEF6F -:150B13009A915E86969EC69B420F382B230E9D92DF4499668A69 -:150B28008D7A32959D60BE4D7FE194E3683F394E74A0F3154D74 -:150B3D00CE4DE17F988EBFD4BA8B38D4FBB846C8AC542C4EA83B -:150B520027713FDF91D98F156FABA86DB78CB65588BD1DFC5798 -:150B67007D286614EF1AA4BA479E078B77F5D28847D6AE88CF94 -:150B7C00B0C665526784B9B260E38E7DBC445B88674CB6E10A5C -:150B910021EE75DDA61F635A2DC718F12B780796AE33FA999E1D -:150BA60043484524B702756A8067E58101519721BC73FE108595 -:150BBB009862B92AE8AF77F3DBB513DC1D6B73DC635914F1AC84 -:150BD00087F12E56D25A75B3B4622F6768017E1CF67CBF1E338F -:150BE50015C85F985FE2F23B9EE0F375F4B11CFA743964B06EE9 -:150BFA00521FC48BD74A7D2C873E5F492B4B9FC12C7D06BFA10A -:150C0F003E71873E671D32C46F521FC44B7C47EA1377E8F3954C -:150C2400B4B2F419CED267F81BEAA35EC9E8B3E44A460684DF02 -:150C39008C3E88A7DAFAE0F3AA9BA595A5CF48963E230E7D4207 -:150C4E00F6FDA61A180DA77CBCCCA066BB897CA58FE0FB4EFBF0 -:150C63003D6EBF37D8EFC81FDF0DF11EA3C29781C7CE1CD1D360 -:150C780041FBBDDF7E1FB6DF2FD8EF23F6FB6AA0B3533BC6C47E -:150C8D007E0B63EDDA49BC1BE40C9EBBB49FE2F99F8FC273BFE6 -:150CA200F6160B698BA97DE6E61ACC2B857D695E24B73A10CB76 -:150CB700ADF62572AB3DB00E78DE451DCBB597059D7A98BB5EAC -:150CCC003B25E844E1B9567B83E1FC77A41C0C79D66B7B98A408 -:150CE1006BF18540B710724F0D394B4F6F3BB916715096422D36 -:150CF600B702613FD9F653011B75C0F66E7B4BC050A614EC99A4 -:150D0B006DCFAD4DD15FACC9F5433AF3C4733FABB7F9A34C0FC4 -:150D2000960DAC49D14CE122AD146E4A5694ADD4C645BAF768FE -:150D3500B9D5381EB56DAA3D216D1ABA22EF6F904789BD3FE19D -:150D4A00B8BEC3392EF9DD65D358286174F44989B3DEA681BC57 -:150D5F00FD4803C6C69FC88C55D9760CC3F846B01FDA8EC2739B -:150D7400583BC0F0DC392264BA2CE4DCA1BDC88E08FB76F1DBED -:150D8900AF0807F47DF7466E65D9853BCDCDA56F2C7F612C6631 -:150D9E007C7B2DCAD12E6C940F67B9556BDD952B4AF72C6730C3 -:150DB3007697188B0B79F363B915F3DE7257064A0F2CE7305641 -:150DC800B856CA8FF6CA8738B9F17B77E5EFE6BFB8FC208CFDBE -:150DDD0047756E753E9C577F7DF1F32AA4F9F17C5A85F3FFF557 -:150DF200C86015E29EBF78026AAD06C113E48F5BA22F113283A0 -:150E07009E715DF43B056D120CC555D1370A39E07C18C798B8BB -:150E1C00EDCC6553F93002F1F71A2D10DF7F625CCEBBCC6B45C5 -:150E31002F6D4482116E403F67DD5153D9F47DA8B3F6D15B712C -:150E4600AF04BB49BE31DE2AFA06DE2EFA2E61CFBC3D80BFEF5E -:150E5B0069C0BF9B16068280AF895C26F2ADE81BF9B0E8570B92 -:150E70009BCF3A03F81FFE10F037D1D9011DF0435CCA1DE37EDB -:150E8500E89F15EBB093975CC9EC6DA454033C43ACCD23B0367D -:150E9A008DDA7EA606C6007681AE96B6E141D15FE0E5D037AD30 -:150EAF00245E1674D52944A3FBAF277DE84B3B005EA01D83BA29 -:150EC400C112F6CB81B3F8ED77209E8C2BDC2B1FB171D1DE7613 -:150ED900BC517CDE0D3C55EF0766EB9A98FD6DB39F22BF48E2BF -:150EEE0067DCBF6B08EB5F529F789DC33BB340367FA8CF54BDFC -:150F0300782FF021776B43FC9315B63CDA1DF4C69792C76198CC -:150F1800AFDAF2305B1EAA65E4C1BDEEBC8D3BEA9067740679E9 -:150F2D0074873CB5200FBC3336853CB50E799EB4797C807164D6 -:150F4200CB336ACB73BD2C230FEE55F7D9B8E86F2979F0793A72 -:150F570079420E79D6833CF0CE6253C8F3CEF28C3C977E277943 -:150F6C002CBB827B9A940779A03C3B1CF2E05E735AE20A5E2E36 -:150F8100C8ADADD57DFC7A32994CE55867F917D10659443B01F6 -:150F960039BA96AA810DE1CE35FD14FF4FA873ECB821758973F1 -:150FAB00DDCE291BAFE0A505F1791CFB6658EB6539856F9A5A59 -:150FC00002CE58E939FD7C839D8F53B806E04521B67D901B9DD8 -:150FD500F3752DCA6A81BF017218DA61689FB1466D21DBA92DFB -:150FEA00039F2967ED5A15ACD57A56663C627272B07149A28F90 -:150FFF0046ADBEC62EC08F6923AC5FA3ACF3C8095A4C06CC398E -:151014005B8FD0F9173FA3AD5BEFA46DF397D2E7B62EA7CF1F57 -:151029005943DB2FAEA387E69FA6783FF357BFC8C198A6F8BFCB -:15103E00542F1C7993169CE9310F5CDC07F5C0BE554EB9CEDE5D -:1510530043BC85DAFAEA344C6FA1E5F712AFCF09130AB4D0C3DD -:15106800D3C06BAF2527C18D480BC37C89F6F12F9E621E6BA1D1 -:15107D00CBD64C01875AE093F9C4BB30D6C3704D312FD45EC9C3 -:15109200D405E99F3AC2884A995B13DF2FD855FCC78E2063D72D -:1510A70044DFC5AEBB64AD33EE92DF494812EAA2C23E336A0D67 -:1510BC0019F87D638EBBCF3C9433641C0A0D189DB0962F586F8B -:1510D100189E0F3E1777C9F825E280D561A81BA9897E90EF9079 -:1510E6000FCFF76E3A24E0CF440A2A3E49FD7B8D9D377E5E23CE -:1510FB00F7C7487A2F8D31947F01EC63F9B1DF97CF8BFD1DEE8E -:1511100023F65E382CEA18B97F0DCB5C073693FB1FB371BA04B5 -:151125004E43669F14F1F0A4CD6774129F5B27F091FBE5B0A8F2 -:15113A0087527CE2369FF5361F89D345651EEE67B171428E04DB -:15114F0095BABCFD7DA63FB4C83C06BAFA2277560560AFBA7A78 -:1511640043EA7B3E726FC56578F680FDCB0C3807E50E34C29EFD -:1511790055AD94F687550DBF8B04E9D8DB9027624A5DADF6326D -:15118E00DED9F9DCEADDB00F75B0D2D0BEAA0324DA48D43DD4DD -:1511A30055DA15762F851A4DFF0D5FA8FD86BB6C5B57691D3C31 -:1511B800A41DE0FE441F63B97D4DCBB46E8E79C51A053D12BD56 -:1511CD004C059A08276A94C281CBE3E4B9E527DDD5CEF965C6B7 -:1511E2004193DB34702E3E232D1D68B94B97844359F37D303FCA -:1511F700A4BDC8A186B0E747A79CAFFE23EE4D4BC2284B10C611 -:15120C0096419D11D43AC45D3427AD8D86F62B9EAB609E3B411A -:1512210039E96C74475AB90FF66017D6BB7A2FF744A2BC2032BB -:1512360022EE9C27FAF1B0EDC7D6043F4EFBEF689FA13AFCB79B -:15124B00106A85B48F821FE0FAA18FE6ED1F308BC92253EAB616 -:1512600044EA16EAAE76FAB35FEB608188BBD28DE768C2A807ED -:15127500D6A3E94EE2C5F7E7E7B61B259B89F7A5B93143D596FA -:15128A008AB5598FEB0073D9FAE876EC73578BFF21CABF23206C -:15129F0069AAAB3C61159E676A128F885E0BA4E4D620EECA880B -:1512B4005AB8CC6C752DDD9E6BC399CFDA9E1AC7FF6352430BCD -:1512C900BFE74ED10845BFE74B3DAFCBC0459C801EF81D11EF02 -:1512DE00CD0E6AEE3A96DE9BE4BDD916BCABB2EFA5314E08DEDD -:1512F300AFE9C75940AB2EC7B51570BD8F5DAFA95E29EEFB990A -:15130800BCE39FA37799F8BD016922CCA746CDB3C9A47F527EA9 -:15131D00B2F9D74EE2DF6EDF9D4B39EE127766BD71A4A3240E38 -:151332004BBA3A7E4790307C4E4C419FC571FF91F4D500F0620B -:1513470094E2BE68D3F4F9347FD50AADA02264E78D0AEDF66A05 -:15135C00A0C97C6A47FAEE1068B3A2ACF7F4B3CD8F8F1D355654 -:1513710068F757F8B4FBCB03DAA28AD47DEB0A6DBBA46DD35490 -:15138600BC8727D155DE9F19B638717B25D610F8EC4638D8F716 -:15139B00207ECF8950FC3E731ABFE72C4EB82B713D104791385F -:1513B000EC20E660C4D1FB38E2A0ACA501AC11A1B67B88903162 -:1513C5000236FE4BE255C5DD690CCF9BEA79D24FF15ED2F20E35 -:1513DA0088EF6B44AC7B4CE0FBD5D7E47730FBDC81304D1BA0C3 -:1513EF00E28CE280056D58A303B6CC8635E0D9B754F0E33B1C7E -:15140400E3E2FF0C865D648936C09D30DC971766C188CB4DCA55 -:1514190027C2583DF46A6488A910CBABB3C712CAF87016AC0146 -:15142E0060235930F7BF29E3A3593002B0771066AFF37F13F3E9 -:1514430084C1511569F6242F3203617CC0644C280C0F0C1AF656 -:15145800229960D0640871E2A297502C37025AEFB141264ADC60 -:15146D00E0A1CC4156D92DEE7CC144126CB07926122DDD9DB8D3 -:1514820099327844070F14B7425DEE8E73BD2D6A2B6559B7D497 -:151497009D52B355DE15578538BAE8B2559C73DFD7DD6FE6CDD5 -:1514AC006450F1F6EA7E4CBD37DDFDBEEFEBAFBFFEBEAFFBFBA7 -:1514C100BA31DE44D82DB80EE738919E4FBE9AF31B37FF6E8C0B -:1514D600D97D8E4A1BC19FE113CC3500EB7D15DAA8986B25E05C -:1514EB0087B471F62449D02133CEFDA473208FA0ED37A19F74B0 -:151500003663C7C458757D99E6E3144ABE9AA12F947C9BF50CD4 -:151515008CEBAB1D34234CD447180B4298111E57823AA4431D81 -:15152A006768C3D7CAB2AD92C6AD92463FE63CA91C16DF3FF7EC -:15153F00E1FF709CDAB90469291BFD5236446E9DE415D833C0CF -:151554000DBEEBAB6C10E61C105FC6F58DEC875B3ED5BCE799CF -:15156900AF3269B70EFEBE8AB2C2569792B0D97682E72DADE6FD -:15157E00717D5146D64D2F2B7296012DDCE704CDE492EFAB5527 -:15159300511E4ABE0134BEC1CA529CCF7E53D2C1CBC0E6F81BA9 -:1515A800C7A4FE495015BE293361DC608CF8337C825E8FF0D8F6 -:1515BD00B855A83D29D09E64DABF2DF80B65F06EEDC9F843208F -:1515D200770BC03B94FDC477DE271FD06EF709DE2FB9C6F8FCD9 -:1515E70009F8B2F5FBDAB2F576D9D305CA9475D3CB4A9C65796F -:1515FC00F1542EDF728EDAF3DFA91B7AF274033EA764DDD5BE7C -:15161100310B7C63D755E3F3FBD96FD1EE4ECD27B36CBD843CC7 -:1516260079CA9639785F78B6D748E4D5CF3A3766081863B4A142 -:15163B001CFCA948C92615F7A301D6853FCFEA38940F9C17769B -:15165000DD94B30E78E19670F8D301632C0F86CD032183A2CC22 -:15166500CC2F03787BED325FB6CC2C5036D39B5B867DEA73F4B0 -:15167A00D92EEB2D5056EC7596993451A9105621F9436214752A -:15168F0006CE4B1FC83CC6CA306EC2FFFBC7DACB1C6B51524A3A -:1516A400F89A13E5D7C7E5374E6D399F7910F72B13AC1DE6BA33 -:1516B9003F2474592118EA35C380BA700CDFB19DA53BD60968C7 -:1516CE001F501F6E475D02FFF1BB0315633A878FB2E223AC503C -:1516E300B9EA28A7CEF6E585CB5528EF92712E94FB7C7E617C84 -:1516F800B820BF7C85FB3AEB5CC21832C7A3072A123AD703DF1D -:15170D00866F7F4258D8CFAF1B037A2D747D6758B9E39A907AAE -:15172200DEB6FD421FE7F23A571F17A005BE11B48C51FE04D841 -:15173700D7233CF06F0AF2A1407B92699F4BDF1E87DCE1FC7519 -:15174C0079A7CF6FE29D3EBF8BBCD3E7322950B6DF337D7E97A8 -:1517610078A7CF6525AF0CDB3FE7FC36BB26E13ABB92CF716123 -:151776001B90A70B1DB60FE3E0DD72AF86386CA19A57A738EAD9 -:15178B007C79756E475D795E5DA9A36E812AED48204577F72309 -:1517A0005D268F1F667D8F380BDA7BE6DCDF88338C69E058640C -:1517B500FD8D98217C8BDCDC45A266737E547F75BBABAD8E9F57 -:1517CA0067C09C7AF516428A0E361AC9CFD31E5843EA53F054F3 -:1517DF00802798FB87FB643F03997A3EF6C77A726984BDD79F79 -:1517F4008DAFB70EFCFFFECEB7104F0DD0CA423DFAEA3B9555D3 -:1518090076EC09E339A4DB7C7312CFA274C7DE9CE2CF495CDB6C -:15181E00C033F9668A9F5101FFF25EB157E2F039A98B8C9F43E4 -:151833007E52807D39C4E339D2CEF6839D1D053B0BCFEF8FEA65 -:151848008277D59C77B6CD8D7D96F6106FAFCE3E93FC8BB8384D -:15185D00FF50FF35013C13CA3FBC53B903F1EDB957CC93DDF0B5 -:15187200447F12734E79CC08FEAFCFF137E36CCD771C7335E3A0 -:15188700FFA62CEC2BF024217992903C49489E249027C5B09E3B -:15189C00BE16FEE15CF26A4B0233B5BEC04BC58257A2EC562824 -:1518B1003B1018CB295B01654381E3765929969541D98D8149CF -:1518C6002CE3FBEE829F7A0AF8077C6C4D4DE7E3A53B89A721F4 -:1518DB00857CACBAE34FDD9FFE02F25024E5610FE03DDF9C4B45 -:1518F0006783423C473F853903B4BEF4E9745A5BE11BFA29D2CB -:151905005AF3AD69B5E391DF86DEED05E82D96F49E015A1B9ABF -:15191A00A7CBAF8939BE0564F7E38B694F11F4E3838BD3FB616C -:15192F00029CD317B11FBE6BEA47E63CEEB7EC4F5781FE28B23F -:151944003F5756114F17FCBE0BFEF73E813E69554CD56A18D73C -:15195900FDA0F35CCB09998472FCAF9056FA21BE0774AA017723 -:15196E00166886A56A2D2F22FE08E899B511DC0F8C51DC35426B -:151983009B98A262AD12DB0FB65831C11EF6F3FD2C0AEDCE4436 -:151998008E58A51DC7ACB512762F3CD3D79B74233C5DE2BFBBA6 -:1519AD00218F9E06D95687E746F0357D9AC04774810FF120BED8 -:1519C200E833B9F81640BBD28E23D65AC0F7E10501C327F17D8A -:1519D7007C41E083FF6E273F55C9CFA34D44D437919CFA39B6C6 -:1519EC00FE93F59756E6D6CF95F5DB65FD0779F5F364FD5A59A5 -:151A01007F9CD7A7A8EFD9ECF9A334F491913E1DF790DC68A32C -:151A1600F3CE1BF5833FC4F0CC47656C7333EE2F997D75959A13 -:151A2B0012D4A53E1BA838AF3787F6055B1DF1DCBD273B7E8D0B -:151A4000BC7ABCFBFDE680A3FCDC0BCF5CC1F2959B7FDDEC8CD9 -:151A5500FF9E7DEBA72F63F983FFF8AB665289B1C761DAFBDB56 -:151A6A00275A7C7E7373EC87C433761FF14CA3D391AF9B7A36C9 -:151A7F00D73E0B5F2365A10E7179C53A8C97A9B97DB3FD236C72 -:151A94003713647D3028721BB0ED40DBB83E33725F607F1BD7AA -:151AA900E5CCB47539D4719D0F3079591E3C5C6F52B02D5D5C15 -:151ABE0086ED35183306CD2A1DF7BDC16FF4F457C4F4BBC89216 -:151AD300A0972CA99BAFB98298233650C1F4756655F0BD0C5F2F -:151AE800C6F83EC46CCE0FB6177D9412F0F546F3EA3D8E7A059E -:151AFD00EA7BB37CED2F5248BF1BEA5DB5307EB2CD7C6ECFC40A -:151B1200B7D741FB8DB2FDF740FFFBB592805DE787BA0622E42F -:151B270009FF2F3C3B6254C3FFF98E360BCFC60D5F1E3DF7C0A8 -:151B3C0038252271CB0DBAB6FECBB4277625EDD9FA557A96EC0C -:151B5100DFAA49D0D3203F397AC527E574B491F079134A3E4B1F -:151B660093256416CA19FAC136EC27619E610C4775D0E5AA8842 -:151B7B0019C723DCFED2808C3FEF01B8D5C0FFDE45C493AA12E9 -:151B9000B27FB20160CB7D72226DF99364980E4E8EEA336F4273 -:151BA5009B1EA0C297D5E43E6D35C576459EB8F1AF8B7E50EF22 -:151BBA006B8CB1062BEB6F45E0BD669090283C1B9E23C484E70C -:151BCF0065F895C3FB65F885E0C79E13FB5D08A7F53FD29ED399 -:151BE400B82693FFDDE7D39EE3F89F8DB079303E181BA8E47B6F -:151BF9000929EBF4FD843C87B6818D58367FED75C669919FC22E -:151C0E0061281AC6285EC77C7A9ABA8F102FEA228C9B711FF33D -:151C230088E56AA306EE2763EC8AE7CAAB23B8B75AD6E4A0E3B9 -:151C3800AC9BCCC2D82AE2C7734FB857B100EAC73CD25E713CCB -:151C4D000798CA7535A326FC5FF05F609F501F89FC8B0C2D99AC -:151C6200B39958F63B570AF0F17D3CC5F18E7B97F63BEE59F2DD -:151C7700B80FFC1F73C4B96C783E76C4405D904A5FCFE71EC6BA -:151C8C004486FEF9282F23A9EB89EFDD51F10E7F701CB36D6341 -:151CA10016C65186268FEA650ADF43B1447C2566613CA5C94103 -:151CB600B7D8BF1CA60F4C3D30B5787234472E67A35C227D20D4 -:151CCB009BBB6F271E1EAF0C1F61E8F7EDD7560510861B73A2DD -:151CE00022A798163941FDFC9CD3179697E700279862EF075FF5 -:151CF50014F916FC5C82DAC3F74C791C397CCC7A5CCEC76BF51C -:151D0A00279B1CFCFA661A246E3CAB84F80BCC81F25560EBE5AC -:151D1F00FC60B8F7AC522E5764B288801D328662CA263C7B40E5 -:151D3400EFE5716FBFBD6E9B43460CD46BC85B2AE9C3EFCFDEF8 -:151D4900463CCAD45386FAFE53BA5347E2792466821EE76BBC5A -:151D5E007E9AFEBBD30AC626152EFBA6581F4D017FCCB87E3379 -:151D7300190DE299C5D496A3CDCE71B94EEA8BEE159C0779F150 -:151D8800175CBFD9704D0E374D4ED2CC99447594611CED7B66CF -:151D9D00BC20EC191276F90A92B38F9B858F79A4FD745FC5B0E0 -:151DB200CECFC7838E45FA63FCEC42DC5C8CEB03C0519C1C3729 -:151DC70095E409D35D1A37704F7026E09B1B66862B42E9A1A492 -:151DDC00B249D17AE90DEA2F8D33E9B4DF1B5382D9757098A279 -:151DF1005FBBDB85BAB015CAAAF9790D9EAE8B3EC3FD620D515C -:151E06008ECFCA06983B77BFC8D75A01ED4D727F017AC13E46AC -:151E1B000EA37D1CE6F6715FC549DD3BD9773BC737A5F4B2C6FC -:151E300031417B386E7AD1DF93E54591B8A9362678FF0E9103BC -:151E4500BA05F2EA5E07F38DC5AD9BC51955E68A8C67FA3737FD -:151E5A00341AB4BF15FA2AF33E8D9EF70E67F371F7817FE13540 -:151E6F00253DEC2AF440B90AFA176971E2748978EADE9C3334E2 -:151E8400A82741C648E549B18F20FD33E09DE08FC82DC8E5A33C -:151E9900DAF762CE7E3DCCBDC806EC036BC7791A4A1EDE5B29A3 -:151EAE00D681E683503E188EE96EAFD86B4B024DE78B4D3CA3AA -:151EC3003E0BEB03EB458E0CDAB0C572EDD8CA6564CCAC833ABB -:151ED8009B764E37B46F58CFFD6C1EC75F2BDB353ADAB5245FE1 -:151EED00DD0B3F13CBA3EB798CC4C43831F605D7AA48C7E05399 -:151F020071DD3729F704A1DCC6DB25E1FD5501BCBB1D78B7CB1C -:151F1700763F71B4BB0BF0623BD3D12E2ADBF514A0EFAEE41B6C -:151F2C0026CEB17E4EE3DF9B685FDC408B0AF43DCF65679CEF03 -:151F4100430FFE13D04AC4397EB783D66E097BA000ADCC41C374 -:151F56006ED9EE50015A871DEDF6C8762F7C0DAD38C636ADA5E6 -:151F6B00DF406BA983D6A484DDB1613AAD5D1BB2347C2CDB6D89 -:151F8000DB7095F1DC901D4FE52AE3A938F09EB7C7B300DEDD56 -:151F95000EBC17ECF1BC0ADED68D38BF2690074C75E2C5FECA8E -:151FAA00FB36B0DC96F935D0FE308967647E638990F92B2E21E2 -:151FBF00F3A18D59DCE11281BB65E3D7E006BC3E89D7C6E77309 -:151FD400F473A384D1561806C3396BEF7597E7EB3CD02FC75F90 -:151FE900CAEA3B3E9FF95D0A4719B767784F8E7A9CA11FE92EF7 -:151FFE00ED33F6815FAA826D53D79E32CAE909E32021739C3A1C -:15201300E86FA05F85748FFD9DDF15D70F9BE33ACA8B88271E8C -:15202800D0613DBC17D7BF77715859DBB01C6015815DC8E8D5B4 -:15203D00D0B8EE5E17E73A95EB53DB5E98A84FE35C9FAA6D40B2 -:152052003FE85197E33DA7BF9598AF31ACBB2A9881E7F178AE2F -:152067008CB0F9D23625047E26F5697848F8946063455F46F90A -:15207C00F9097E3E08ED52641CECD23B863B7682A26D2A684F28 -:152091005ECEAE1F193FC7D46BF8319C8E7B15F2FFA5747A5E1E -:1520A600FE5A52EC77F278BD359C02FDEA81B915AEA12CD41386 -:1520BB00455DEC2E163A59917E7C293CA37F486772FF588AE7B0 -:1520D000E79539F3C6944671EF4CABA31D5EF893DF0E6DC2F3A4 -:1520E5001A9E5B3AC910CE83987F510BFF8167E877BB2A13EDD1 -:1520FA00587F4368D4B821F40ECA8CD5CC7345C618C2C372FF1D -:15210F00E6B895FDFF8EC1CBFE3A8E3E0BF1B38421BE7F076D69 -:15212400BAAFC8DB631CFF324BD3608AFB4D0E9A12B4991C5B1C -:15213900E9D75C011B37DEBDC3F34230FF1ADAFB6FFCC2CABCBE -:15214E00AFFA228327B9F058535126EF07D6AB320F1BE92ABB9B -:15216300310E7EFE10B3F819D31A3A07F87D3BB24315B044DB21 -:152178003186FC07B368A9EAD330D6C7E19B414BD18E5BED0E8D -:15218D00BF12D6DDE411AD64E5844BAE8B0BE05983BE4B41D8DD -:1521A200555689FA16C09EA0840D594AEC94856704C4797E691E -:1521B700BB51BF15CBF98B396DF25C0091759305FD19915B88C8 -:1521CC0072746106D29560ED226798B9257D6E271D682B8B05AC -:1521E1005C7F30415522CF2AA8C72CA443FD6889C56D51868E26 -:1521F60014ED8A65E51BE11CBD4FC0194C09F8026E82F3A7EC3D -:15220B00A33EE68235223F8347C6753C138F3EB0F82661619B93 -:152220009C7900F03F8C65FD1FBBDF083F719FE89FC0339683D4 -:15223500C7DE73C0B69C8F49C1C71B36F75AFE7082D7259C38A8 -:15224A0033E7914354D0D24055CE975679875080BA653E202FCF -:15225F000F8FB28717A1EFFA0ACF4773D2E07B7909738E1DB4DE -:15227400B114F508C6FE992D27E80BE30D65CF935E9DDFD31477 -:15228900A69C2FFCAC05D42BD05FD660525C841797F61AECC022 -:15229E00ADC607FF96F690A911BEBEF7E118A96F1A8A768AF9BB -:1522B30023E24E017B0D535E3C7D1DD5D37624735E3EB39E9A77 -:1522C8003A66DD7EADEBA9F06B962D539847365C22D6BDB93243 -:1522DD002564086919967CE163128C7179E2EB5958C7A33D4393 -:1522F200794219E0BC32C51AFEA5AF44AE52A1F504CF1B0EC06E -:15230700DC6717E83C7FA01DF767BCDA92FAF7D19EC23AFC1118 -:15231C00EDD6E0659893CB93BE55DC36DE2FF37DEEC74B4F0E1C -:1523310070B9E3F960A2DCC2F2F7E4FA3622DB46F3DACA720B9E -:15234600CBEDF3B836FC5EF9CD60DE37B2DCC2F22E09BF5FB607 -:15235B008DE5B595E51696DBEBD4C512FE6AD916DBE1FB028718 -:15237000BE6975D4E13B9E6DC2334D6E90A362B0558A36622134 -:15238500BF1475BF81E31DD046F19EA9B9734343CD0AAC57CB16 -:15239A007A2E18A5DA116BBEF94993BFE55343891CB75E8E95C9 -:1523AF006C72C39A0BECF1BC9991192B95C805CB96D999A0DB1C -:1523C4009257709F2E3B077E0A3652E1E746D8B4F928E757464D -:1523D900AF200CF5E08831583CAA236D73375759F67CE632C014 -:1523EE00CFE58EF3BB8BF8592FA147ACFCF92CF2400127CC19EB -:15240300E73C796A76AF91F8ADD84754A54EFBA679F27480DF1E -:152418008D23E6C8C008CF89518BB3F98F8B31F7007C8D07F85F -:15242D00DE7E36AEB50EE4CD67CBCDFF36BEE9984FAD45FF072C -:152442003A3ACF9F086B23ACC4DBC7F9F912C06BFAD4E10B5CB6 -:15245700CCB3BB400BB611FB20A6C5F7472AC7DA4B0EC68D21C8 -:15246C009015B5294E93220662B9C57E29BF37096D33D66BB0B8 -:152481006E4FA17D97F0307EAB4716B1622FDE75D743272F66C3 -:1524960071AB05FC107704F0F23D0AD3C2F11A02BBAF4E8CD0AA -:1524AB00CB12278E6F0E4EA877E7E1CCED7F75FB4607FE900352 -:1524C000BF5600BFE2C0BFA000FEAA6BC48FFE456F6380DAB4A9 -:1524D500200D139F081A1600AE7CFCEAC4118E4B8B8CC0DA3C30 -:1524EA00D10E6B6F0B7D1F45E377CACC5B101961CF83DF833679 -:1524FF00ED92D3CFC1589F5A65F5B65103EF74BBF46455338FA4 -:152514002756DFB4B4AA6D6B50FB6143E366ED9EBF587FB7B6A6 -:15252900E127BBBA3B1FDDA5ADEFDCDED9B1AB33A8B56CB9679D -:15253E00C7CECE8D5D3B7EFCA3AEEE2DF5CB6E5B16D0AA1FD909 -:15255300D5B56DE7CE1D8F6DE978BC235457D75877DBD23F5BD6 -:15256800AE3DBC6D7BE72E2DD0585BD750DB7807BC04EB03C11A -:15257D00FADBB4AA4CFCCCC6575BBBB533BAA3BBF6A11D8F4646 -:152592006B3BB67644773D51FB68C7B6C76A77ED7CA8B6735700 -:1525A700B4F6E1276A3B3AB6F3B2ED3B764497EDBAA96E857601 -:1525BC00ABD6B9755BB7B6B5F3E18E1F6FEFD61EEAEA78EC478C -:1525D1009D5AF5EEEECEDDDD4B11CBB783BF75E7B6C73B77D624 -:1525E6003E0CDDDAD2D1FDE896AD3B1F5FF6D04D2B1AAE063F10 -:1525FB00039E9F6799E30FB7EFC77D42B58ACEF537B4576BF5C9 -:152610006C199EE5B1F3F423CACA85FA05E350E870B4880CD334 -:15262500F63FA63379FAEDDABDD67FFECEB552517F6054692D59 -:15263A00B40AE6DE39D0253E78BE85BA539ECBEEFA22ED797785 -:15264F009112DCA81D613550379F8C3787B401C6EBC3CAD30165 -:1526640028437DD3E428C3762AD8408069F56BA5AB6C9B500E21 -:15267900BA710611BE04FEBF02B0F7A9CF44D14F1CFE657A16F7 -:15268E00D2E5CC6B77E6B4C72E8B585C1F6F5F4DBBA03D513FA2 -:1526A300B77CF0CD04E68D39F0B328E1676797B9C85CA40FE9F8 -:1526B800F069C718F66106AC53317F8E4C2DC538ACCFDF72AB4E -:1526CD00817DC77B164BFEA1D1C02B54AA0096D8AF3A44C3DAC6 -:1526E2000BB4FE6DC00DFE940FBEB7F1E0391EBCB301CA2C2721 -:1526F700CE35E934C7C9EF6D04FFEA783A3DA732E2127B6AE153 -:15270C00017A1DD80584997C0BF3660350F60AA7AB04ECE521AB -:152721007E6FC47EDC972BB3C7CD3E6311FB038EDDE77CEC30F5 -:152736007EA36930EFD4BE845B5B6195B41C85F13EC061E33C5F -:15274B00C43958AABD6CD57CE56ACAFAAB620C6C7E3BC7C1F730 -:152760004EDAFD75F5574EA66739C703E951811E9F63BCA211D6 -:15277500378D257F65A920875A722431D7BF1BDA76515F7211DD -:15278A009B9D2CDEB43AB914E435DA8E776AE01D89782F0E0997 -:15279F00DF4DDF55709DA453F465947F79D0C07B36D662FC4621 -:1527B400C533BB61EE8B0E9ACBF5D74275ABD66845ABDE2F396E -:1527C9004FFDA15BF83E63EFEBE959975C765ED6009B9133FE04 -:1527DE006B29DE5D89EDDAA1DD19D92E906C01B8ADD66A11DF97 -:1527F30048F03B29E5B326B2860EF0BC9145D485F77F014FC4CC -:152808009D94B9CFBD2E71278EB8E76B047CE95AFD52B180EFB5 -:15281D00A523C603DAECE05C6D76DDEB8BCA82D6E21B83A7B1E3 -:152832000EE3BAE3E9598B355790D3A90E50DC8376C3BC3C0DA3 -:15284700F320137F9B7A45D8E7A957AC9F5754EB7CBF1874E630 -:15285C00A0840FDFF3BDD47E8065B7B5DB6D873607DBF0BEB4B9 -:1528710012DE07DCDFCDC7A57F21E6512B7CCFE358324E77F2F6 -:1528860028C233D982D251C3F7DF87190A4E6B12CF389FE7E720 -:15289B00A9ACD0ABFA10C09D5F5A632C07BEE2D9D81A729EF631 -:1528B00086DE88624C2D896B83B6A5860563751DC84EC99E710C -:1528C5008AB90441DCFF507F21C646CE65F4A915BE2ED380AECD -:1528DA00503BA75FFD85357129ED395A24FA79178C75538131D3 -:1528EF00857575597E9F7A2FA5790E09C2D92EBF9F0F73AE6456 -:15290400CA34F0BEBA2258A784928729FD4DDA637F8B730575F3 -:15291900E284E43BC66F911701E083DD6618EAF83B7B864652D2 -:15292E006911EF8436A54773798F325888569CC7E5C91EE6FB92 -:152943004CF0FC83BFCDFD6E02F98F72CE75C37E6AF37A1078EE -:15295800DD9A1CB1265E933E80B3DFB83724FB4D7F2FFA8D63CC -:15296D008FF0A200AF468E1997CD51219B788ED6D576B71186B2 -:15298200FA9B6DF9936321F89885D1F07B416B1464E2E3D78499 -:152997004CCC2FAD37FC23AEA02D1B78CC3B2AE2B952364EE849 -:1529AC00E8DF2D262756A15CF81A135C1E2C73B1EE1E386228C5 -:1529C100A073174B3910FB02B9E37E12F8EC575F0199EFA15EF8 -:1529D600900B5F4F9D91BA28F96DCF07C737181B2FC4EF6538A7 -:1529EB00DFA13DE7793E1E984F9837649F7FB9CE211BDD201B4B -:152A0000D13342365C781796940DCC8343DEF01C07CCEB782D44 -:152A15003B7E086F76B8CBD0FFFD2FEB41C759D5C936AB2AD9BA -:152A2A0062819EB3400FB202F909FC5E665CEF946A553CC61AE4 -:152A3F002BB00F06FA9BCEF00E1891728C1B8DB5A3DFE6F28C47 -:152A540018B89FA6CB73D6E8833FC0F79712FCAC18DFFF8275A5 -:152A69003B9E0FFB79C54958ABC6F95E981AEBB3300F7275EC6C -:152A7E0014F7FFCC581C65729EAAF559ABB553168367191B3372 -:152A93004E6BA29E2C8AD38FAFE21FBAC984E723A5B9F8B1A2B3 -:152AA800CF5D3F73FD4F7B4F1B1DC575DD9BD5AC342B0D627676 -:152ABD00D95D495848232C12C9519C5DB1C8922CC242A88FEC13 -:152AD20010654B9D744612F63AB603B19D84B634C7E784C42B00 -:152AE7005889058FF03015F65A266695480E6E209539909014D9 -:152AFC0092A5761C9152B2E1381C9AA4F638716C9AB8B6EC6293 -:152B110087A436DB7BEFCCAC56027F25ED39FDD13367CECCFB72 -:152B2600BEEFDEF7EEBBEFBDFBEEBB95BB86F37317D82FD98F5D -:152B3B00D9F7D9636C823DC40CB69D6D619BD917D84676275BBC -:152B5000CF6E6537B33EA6B04FB0B5ECE3EC63ECA3AC9B5DC784 -:152B650056B3556C255BC196C38CB29375B076D6C696B1085B45 -:152B7A00CA5A599885D887D8D5EC83AC059E0FB0AB58333C4D64 -:152B8F00ECFDF0BC8F2D81A7119E2BE1590C4F033C323CF5F4B3 -:152BA400D4C1B3889E5A7AAEA067A1FDD4D0536D3F558527687B -:152BB9003F81C2E32F7A16143DBE598F77CE235DF2CCBFE4A91D -:152BCE00BCEC33EF2D1FF16D9F8A777CCADFF5E379C747C0C3D7 -:152BE300535AF6BB963D6099CEB280EC52D7DE1F63F241F46BAC -:152BF800043FDDFE6F82FF9CFDDF02FF1207FFC863EA9A207EDC -:152C0D0054D359B7968349B2C4299A242F3E28C5E1CDC06B2E5B -:152C22003E487602C97E6C13D9BE9365DBCF63FB71E017B7FD26 -:152C3700CA6D3F17F8656CBF0ADBAF04FC303F2893CE264A2C4B -:152C4C0016B2F342BDE2909D07EA1187ECB4A8371C8234310E91 -:152C6100F768656DE3B751D0BA4A83D9F6A81BE41AF48BD1B952 -:152C7600FFB0EECB70ADC25433F081865161AA83EC1B26DE2674 -:152C8B006CF26DC2C81E0B84554218F81BE8CF9FE850A9EC5CF1 -:152CA000B3E1E0CEC139D62367C3983B4234D1659A8787749C89 -:152CB500F731AC27A509F5237E118792CB8A3F99B5C3813776CE -:152CCA00C98B0DDDC9E7B8E51F837831E49BD262831740067A12 -:152CDF008B6F8C9B89932BFA975C33FFBAED4FF8CFE6E7A36DBF -:152CF40009EB3CB7AC4D93FD5BD9D2E720DD4999743D4AED7F28 -:152D09003A37EB82B686F66043EDC03B5D2CE96A37CA609ECA75 -:152D1E00473BD4E9860E5A9F9BFEBE7B19E204DDB8469A857495 -:152D3300226B471D6CA30570018C5613E456A38C5D05B05F65E1 -:152D4800B883D1FEDC65FC24CEF263F2AB06F2DAA6B96B14217A -:152D5D0059273F6CDFF0BD49E65A79A099941868E571BE2C35E6 -:152D7200A03D4A18CFC35064BBDE42EB5061834908974CB0C425 -:152D87005CD55046B38EE5F353D5AA94688EE0574834B7E23778 -:152D9C008675CD8548A6C6B8D48ED15E6528A425A84FB46B511B -:152DB100D26D8AA27F3C3FBF1BE2C4C88E24CAD0D659D8B8163F -:152DC600A573001BAC33B1A18D961E14BBDBBE272065EB48E02C -:152DDB003AEF7C002A09F397A4AEB3A482FB3DE87E7505BF8CF3 -:152DF000E5B6E8A2CCB7B2D856FD3CD62B27EB96DD5C4B6FAAC7 -:152E0500C52C69A53C213F5A57C2FFD8889EAA49281CD9F31C8E -:152E1A00310A7A20B11FA4B17EB5F2FD3A2F9F30989E84791408 -:152E2F00BFEC9B377F13F27F328DFEE8D7027EA373FCAAC16F26 -:152E4400688EDFA6150097F47CFA7337BF1006815913E5A7F5FB -:152E5900BBD99456BBF205B5B7FE99F043EDE7ECB316093A3FF3 -:152E6E00BC287106EF0EA075B3452B4FA97C665C77C1B828CBA6 -:152E8300DF4A33FDBC21A44668AE836B6D4276775B10E7515087 -:152E98000ED3BF615CC1BDA0221ECAD933E1C99B5F6A031880EB -:152EAD00A64F035CA7744EDBA93EB4EE79ED8AA806ED68A70154 -:152EC200384B5C5CB13A2C6C87F2625B27D9BE52B42D3E2908A7 -:152ED70068EB74DBA8D0FD02F83F306AB9BF6EBBBF3D3A95CFC1 -:152EEC00073217E75CF311FB693AE99AD2116F77B3AC96F85E05 -:152F010069EB97BF5CDA8AFA10A3B9879485A71F504A4E3DA5BB -:152F16005EC7CE8417668FA964672DA4DB76067354D780F4F77E -:152F2B00EAF95B9E3616724F42F81943481C68C3392CE63D7D7E -:152F4000CB295DC894B61EBAA77419CA26C447A4B18349570694 -:152F5500E87C58C7BAFC61EF6024781CF2967EAD617D24843B52 -:152F6A00F6F8A4807B23D2B68312C1FFC383CF431F2C978753B1 -:152F7F0068DBBA4C1E4CEC4A680AD7A3411FFDA98E3657E38FD5 -:152F940031769F80FB095A6ABAE13503E2EE78496E591683F8DE -:152FA9009BE3AB5B518EA1BE251DD0F9CC578047BA5BE3D9FD8E -:152FBE00AD4C3FAC4F63DB8370EC3F6BC19FCF1C80F63348B612 -:152FD300299A6CDB31D4D7F461B20BDF44FD0C64DBCC30F4B3E3 -:152FE80084C6036D25A645F02B30AD15BFB85F266476431E596D -:152FFD00B2C55A9D49EA9C00380A65C9862AB643EC1FFBA6308D -:153012006CDC88A1CC9D491A572534F2CF803FBA512E9C6ED029 -:153027007431CEB77A4176C47E32DD306E2C0C66FA8F5E742F22 -:15303C00035C1A536FE40509E0E98232CE60BF0AA5B52CF0E088 -:153051002EC89765F6184F15CEF7A47411301002E09E1FD42243 -:153066004C3F9EA67929F0B3EDD153CAE9DB4B5BD36C504927FD -:15307B00762B171BF965E9E8B052951C51776DD5945D1D6749C3 -:15309000B694CCFBD39D4BEAAEA13DA3506212D762BD8B92B8B7 -:1530A50027A8D766A84ED69AB680F67513B466DDCEA32CFDBCA3 -:1530BA00CE75A38EE113C6AEACA6E07AA190D903E9B6219E69A5 -:1530CF006FAFDABCDFA8351F369A0037B550D75C298805108ECA -:1530E400FDB349DE46B63C280F49439B4E42B57C9F4E36F7D6B9 -:1530F900691AA4D39137F0F1437AC4FC1EC4DD66A00D4E616AB7 -:15310E008F8A79BA4E4E908E5AEC71C66A70BF3F74846C05F0F8 -:153123003D432AD469D4D5B3534D95B1D9FD23876BFB29ED8BE7 -:15313800FFC6FFF0618EE8427B1E7EF311D203A45B7670CD1FF4 -:15314D00FD5892F4B5B0CED6FE478AF63F8CEC88526D0EA543D0 -:15316200E6231969A5A60AD76B6AC91A4DE565CD1005DCD3DEE3 -:15317700A3354577B7E1B9B1C000B41F98B75627D07DD808DA47 -:15318C006E3CD36EF1FDDD86DF145BD18FEC8D16F643D2B4E610 -:1531A100EF42DCE446F446A28375C69963FB34D4CBB6CE365B69 -:1531B6007720FC02F2E2D6A0CE5E86E8C7A50EA8C14583C60317 -:1531CB0051EB5C2CAE9DBB7A2CDBCB3716D921E03EAA912D62AA -:1531E0000969AB7FED20D93284FAE33A346F022FCB9D277C7B31 -:1531F5004DBE57A4B9439AF6195CA46B6ADDB101F35C03ED4235 -:15320A0021BC9CF945ADC95C102EE6F1C8DB918EC4DF0BBC1DC8 -:15321F00F8FC86D25EBFF9BA4176DBFE11DBE190B1E5CD7CA012 -:15323400E54DECBB162D10D77E73A7EED246546FA7B5D7EF02FD -:153249001E81F7CB886C64A9086D65211B09231DB5A236AA591F -:15325E00F4D2D3A4F375AE9FDA18D00FDD3CB3F45F5336DD9182 -:15327300CE9806DD48D7B934251AD8F478271CBF5B5AFD4FD299 -:15328800A29C6891B6F7796668F28EB4281A6B1D3AE8DF477B45 -:15329D005995A1629AF8E2EF0F93DDEDD8C0E4857BDEDF26C538 -:1532B200CB605C1DD0D1B636F2AECD5F2C6D9DFA2F871F59FCB0 -:1532C700A31A68E65BA4191CF04DA421D6D5DAF3B1CAC0F230DC -:1532DC00EFC2B9A882BC64D1A5A688269B099E94657705C27175 -:1532F1005F5132771A9C9CA4F6846EA5C8BE40A4287DE4930561 -:153306007D5FD2134EB309D2DB6C42DA0F4C28A2EC26DE1C225F -:15331B003D404DAF895ABCA8D00FA1CEDC061C8FE17BFD29C2BE -:1533300001F45B7FEA0F567DCD39D76CA18DFBEA60AABF06645E -:153345000199650E8658F660949907AB7F9BF7C07712DC93E0AA -:15335A003FD96DA77FABF8CAB9D9F1ABEDF838AEEF7FBDA84C2E -:15336F00D4C780F947715AB2CF45771668FAC57BF8655DB87E3E -:153384002E1F4DDC37754C2985E9062F8FA4D04E49B9FC448ADD -:15339900EC86D37E5096CE544AF22198B72475D15CD27AE3FDB6 -:1533AE00790FE2417B30EF999B67316CA4770869BBE407F5F373 -:1533C300CF6A2023E96403C56A877F6750DBB56CAD4CEF0279DE -:1533D800B115E4A2F7D236A79F1DD193AE94CEF6F1BDD3CF6A0E -:1533ED0046D29536BAE45DC6EB17B17F24ECB9C980F11CCA42CA -:15340200407FDC5F95A18C629C5C787A363E717FD796672D5DEB -:15341700687D8F8EB23307FD0BEB086E63F5DF82BC188A914D54 -:15342C0074279FEC8F67F2697C2D2FD4E2D9A16035C8F103FAC1 -:153441004928F36E16D798194AE3BA986836E9A5C7C3EAB7121E -:15345600CDE1C1F6F659B26519C375E276EAF765DCADC067AE49 -:15346B00D765339666D22B862034A8B8D66CC9958BDBCA61EE8B -:15348000E2AA53A80CB4878769DC0361B5321A8E944399FBEB54 -:15349500AF6DAB3565181B9BF46A33A47362A73AF895B0E6CE17 -:1534AA00C23C31D76E387788A0EE07B374D041DE6C0CF3B8563E -:1534BF001DFBD424D36F191552B87FF857F43557B896CDACFF5A -:1534D40057DB7A174D363F0B013F6B5750AEF7C95C88E62A504F -:1534E9000FDEB11D937B64B226BB47ADB1EF6FF0C3388DE3317F -:1534FE00CB7DC7F072CFA9AD0D95D7B0BAA97EC6CE6912FB759A -:153513009B9F7B59DD29BB5B51560C01AFACE526D440F048BF54 -:1535280010FDF5D25AF8BA4EED26BBF4C827AB56A26EC011FBD2 -:15353D00BEA1843605E3BE2F7158F5D682DC52B0CFFCCE6F157A -:15355200C8E6F84DAF288BF8E2653067F98ECECC470E8E83CCE6 -:15356700556BDEAF23EFC276817BD85E18AF9FAA19591A05598C -:15357C0007C7A14FB875926FFEE9412DECC8346FBC997F4B99EA -:1535910026FDFBFC5BCA34ED6F25D3C45ED04CE77C39F21CC0B6 -:1535A60095D0707B5B39E93423DE8EB5F98FFF07E47F4C5B0B28 -:1535BB00B87BA05D776C76109E828943053C05CD2561E11CEEF2 -:1535D000296D99E44F1C437E1D5C68CE0B835BF79901FA969B53 -:1535E5008BE8AB035FBF5CFD619C8DB8BA5F564F5EC80B880779 -:1535FA00AC6B8B5D7766D7BDF63275C734E90BEFBDFE8B80EE1D -:15360F00D5C85763BBD2B1D7E7CC6FA08E747744113D5B8AE3A5 -:15362400C476EB37B0B47623C8F0CF3F35B254968F4F0297D654 -:153639007C1C8CB7D219C36FB74B1EF505A49F1B77B3B39A97FE -:15364E007B91EE4FB862E5CB6A28FBBDC8151D163EAF602F502E -:15366300DBC3FE7A05CE67426709A7D8E6703D17D784EB4C771E -:15367800AB13A7EAF8D305BC57415A491E48272A92BD18F72EE4 -:15368D005CB28D1D4AA32E4AC9D4310C1B759D3CA6EA799847E0 -:1536A2004178937C7B1B7E119EF32BCA966DBAF91990177FAEFD -:1536B7000BF263A32DF2BF1AD5E7ED3AC6862645D437CBACD512 -:1536CC00AC7F9C4B0D4D9E5B61A53F0278F3DB795D58B1BEED6D -:1536E1006AF6F5569A0B15C5C5B49847713AB4F7BEE5DE334AFE -:1536F60048FECBA5E88FE32588D21FC7FF0771CC8C0D65503E7B -:15370B00C5B4E5A8630FB8C4F361B5BBBE4A785D28838C60E796 -:153720005F39EBBF2AECB2FED3E5F2FC307C7557A525B763FE8C -:15373500AE8777A83437FA21F00A90BB8CE8238A144DAAD5302F -:15374A0096D079BD7761A31F5F1863525C6AAD8AFB984CDA4A08 -:15375F00E3901480F1C41E87684CC2B0F7301E3963913D2E5D94 -:15377400763CC2B108C7A408D9F4288C291A3B618D29563932C9 -:15378900AB965F3116A06C01E394206F37BA5FCD0BE5192D5589 -:15379E000E7047A2C956677E580DE31AC6697AD5A1F7A05EDB5A -:1537B3006ACD2B733FA0701DC343801F4CCF32CFE97417484EF5 -:1537C8008379654A2BCD24133E2847CA1C4A639F2B318F699847 -:1537DD0027B6356C734DF2B3A3D8A6CEBEE1C86B36CC00EBA1A5 -:1537F2005D5F813E3CA0D37959B439FA5D6B5CDDF3CA4CFFF2E4 -:1538070006ADF32F82BD5F3659C53C208B7AF62DB0DC719E794D -:15381C0036BB98670A5E4BCE6EB27993A523E2C6BB03FCCE58AA -:1538310098D136039EFCC73BD45520CFBA07C6D491DC98522753 -:15384600BB3B17CA1FFC30AE9D511AA9592D9C178D3540BBE016 -:15385B0086F87883EE96701D8E1B7A716F73849D1FD0CC1378F1 -:15387000B9D15C797276F9AB12CD4BFFA4722ED1BF09F53756D0 -:15388500B10A495AACA2BE2DEE75476A58855BFA06E9475E9528 -:15389A0079B30B75A7825F0AA3AC4B3A51645F00CFE5423CA71A -:1538AF003CF4EF02F78CCD6E9AEB94E3BEF81341B47DD3D4FF48 -:1538C4004610F36D253D9F5C35AB10E363C05797A8EF93B98E87 -:1538D90052482FC61B8C0BE0CF7F6940B7F412F921679DC02DFA -:1538EE006D517F0161685F6F04E340BD704F4F46DD29F0E3E3FC -:1539030063C651F487FF17618E7ED64E877B5BCF813F7EC78161 -:15391800C6783EF0A8CB3A53398234F74FA31D4656B60FEDE209 -:15392D00BDAC49A71F5450AFB51AE737D2214D100FA83D40DB6E -:153942000532DF5B66EE21BB48B5C00B8326C61FDEC26D1FA1AC -:15395700FBE170AE7355A66BA9245A672FD0F6C97CCA736254CD -:15396C0080388215C75F9DE19772FB2E4DCB6265A4EFAA03DE24 -:153981002201EB4C23EAB7A0DD41DCCF37C18F49C9C2FE1A2F08 -:153996009F37EE02BAF1801711FA66BCCABEA3720E7D437141CA -:1539AB008B9B3F3CC83F3DA0BEE177F2AD2DE49BB2F38DDBB65E -:1539C000677700AF385A86B695E47E964B18B4FE2E4534AEAEF2 -:1539D500BD9F379B0CC1443FA095D94EE5579BD306CA4392991B -:1539EA00813CE3FDB82EB9A3668342BCAA6E637FAD8967CCCFD0 -:1539FF00F6F3F2678DA341AB7D34429A263337DA02E923905F61 -:153A1400D702E609417A0BB63F4B236C68A77415CAA076FB725B -:153A2900D545FBA3E6EF8C1D3531254A792AFD317043FC83ABCF -:153A3E00E11B87BC4B614E70A3B9D7889A0FA4BB4D7D34065FA4 -:153A5300DCD38BC17F16C215282BE7B36DF1B20CE1009015D890 -:153A6800519351FACD8C711BE41B07D8FCD85E01572DF015E0BB -:153A7D008B362E6508AF85FFD590871FBE8D3077DB00FFE716D1 -:153A920060DB065C815F37F8F1C06F9E02BF50D0A2477C8E4D94 -:153AA7005FF7D30915DA5D854FE6979714D18B4378E47103D74A -:153ABC00A042F2B826E0FFE5F4E5E83C48448BB958C5D5995BCC -:153AD10022D86F4A3B642D4B3A81CD7A359E6991068C52DA2366 -:153AE600E6869C3C3250667D7A8CCE0570350975C67E4B14E2A1 -:153AFB00453406F90D215EFC4D05DEA69CC231AD5945BBE28BDE -:153B1000E5DEA56CD32B8353CF32E6E4C3360D68999FD8FB05AF -:153B25009BC63413FE51074328C0D3A12FC47105C39EB5F48CEF -:153B3A005B1CFE047ED99FA0AEDEB2E502C00A3207C1EDD09B26 -:153B4F00492097DBE9826CF972B6A983F277F46D310DE45551D0 -:153B6400C9BA280CF32A0B5E8A2FECDF7E6E461F5EC2BB96FCCD -:153B7900FB0A75ECFA31D6F1807A030C0DD29726F4F88F11604E -:153B8E00B44D64ADF7EBE0CEC03B096F16DE1CBC26BCD3787B99 -:153BA300758E0CAD3119DE50CE8ACB360D5A75B574E6C9CD7E81 -:153BB80039DB2DCF7147E7B8E373DC8939EECC1C77768EDB9CD5 -:153BCD00E366BF9A53FEAF8A74FA013FDDDC6CFB0393483BFFD1 -:153BE20064C16E531CEA161838AC56D2D9503B1F9873E3DCFA61 -:153BF70086F8BA48E0D8849ECE219D66F03605EEB3F09E83F799 -:153C0C0002BC02D0A71ADE2678DBE1ED86578177C34FACB8ECF6 -:153C2100D004E12DE3D01FDC8837BDC88D784B14B9116F1B8B77 -:153C3600DC88B778911BF1162B7223DEA2456EC45BA8C88D78AC -:153C4B00938BCBFFD58C5D442A1FDC818E8C816D1BF54BF97BFD -:153C6000D65DEB9C6B279C5DCE3E03E0576445F89D1BE74F0C29 -:153C750047DE7314E417908DF427E6310FEA1AC29CBA33CD31E8 -:153C8A008F00FFC0673A451823CBE545D73C05E3622DFC231DFB -:153C9F0079699B7A971778D67C5671076BEC8CCEB778DA4DF0DC -:153CB4001F996FF1B23AD6B8DCD11B91D1CE2F8CF93AE48138E6 -:153CC9009BAE84F11BD29FAB44D9E1D1193B0A20EF9DA91F80D0 -:153CDE0071793FCA08FAF40AF7F227208EECBDFCF8E48C73B8E8 -:153CF3009789E311A0D1531C4F8472B7DA67BC41DE597E16F2D1 -:153D0800F290FC3E9B8FD502BC9B251C0F51BED8AEEF88E3B99A -:153D1D009E47F52DD1FD547FCF87DCBD92DCAC23CF6F03B4794F -:153D320057EEC6B5306DE33C5CCF1FD399FEA81E80B97B271B90 -:153D4700A4F8839E0985AB6987B175CCC07B8078905BC9B66F83 -:153D5C006C587B6A3E8E637ABFE44D511E47459021218D203F57 -:153D7100AAF330167B2A715D6ECC401B0688E746C9923F10D617 -:153D86009C385BBEDB378F553C01F965E6E138D3A827696C6ACA -:153D9B00A2B109CF137235213A9F7EF662DE539E18E874C79ABA -:153DB00054596ED05F5CC12DBF0BD24CCDB76422070F3E5B5772 -:153DC5006B66FD43D6A7A7914F6D25BB6B98BF74FA030A9ED3D9 -:153DDA0040987DD1B1A53CC82A3CE4390D79F6824C85E7407863 -:153DEF00D265A57138407607A62D9BA17C7CC21065EBFED03C4A -:153E0400E9413FAA0580E7F3F26306C6AF043E4AF7A59780FC2C -:153E19008C770C16DDDF721EF2F8511CDA5E1C6D16587691BFD7 -:153E2E00CBC63A4570E33883B88C9633CFEBD0665F65039D0EF2 -:153E4300EC164EF6116FC23CE8CC045BD2E9C07D1EE046FD401A -:153E5800A04305DAF9C0B6C1A3DED985BCC7B1FB5D5CA7605144 -:153E6D009D9CF106EB45FBBCC0EF102E777618E039AA511DA462 -:153E8200319C7340BDB7CFD89D8D0F68231EE6B9016075D27CEB -:153E9700383AD8897BD4FF7CE0E7FB45B9C50890AEA70A7D760A -:153EAC00B5E1C0CECBFB691E86FF38C64B368ED6D8703A7A6FBD -:153EC100362E03B8BFD60261BE38BFDC5F32D337244FA36ADD4C -:153ED600E39AA6F28CE3E3CB5924827BD6796BEF219FFFF2F1E0 -:153EEB0008F82575BC5BC09BBB57F59EBE56918EAF54EB645735 -:153F000017E9B4E6B6A30E89C7533C6EDA70B6B225342E4F0ACC -:153F1500CCF334D4F167D0F6D8A6AF525E185F405E1F19A77B66 -:153F2A000BE8FC47570B9D7B00395CFF6662AC13CF44207E1FE7 -:153F3F00887374AF9C8D779FCF747756A1BC6E1ED3CFDFFC9DFD -:153F5400E53F0337D69937272EDFDE0047567BB3DA8F681ED6B2 -:153F6900779BEEDE60D7049587FDCCA2A74C3875F835DFB5043E -:153F7E00F729315CAFCB8E459CFAC6B8D9ED12F5122EC6B94E46 -:153F930084DBC1DB4BD971E201621C78825DCECF208F775BA70C -:153FA8003AD3BD3C543EBB2D76BF9EF7AC063A8AF1A2BAC88FA0 -:153FBD00E9A87F56A80BCC61ACFA3715EA8270F05D1FA4BA1001 -:153FD2009EE2636F8927B7D4A8DAEB1E79ACAF707C17E9FAE127 -:153FE700DC688FCBE6138003E0E99E82CDF1DC8076F2BF1C7DE8 -:153FFC00CB16AA13EACF3A696F837448EF34A429E63377BF6960 -:15401100B55751DEAFCBF171ED73D18930968D6D51DA7CD43A54 -:1540260057969B80F9C2A041F6E1A72D5EEEF415DE3C60489E81 -:15403B0009D50B3CF77E985B8926F215CDAEFF9199FA43BBA8E9 -:15405000EA3A46F5AF02BAD9F42D8C21E5C8EFA83F68AA6507E9 -:15406500DCEA0F17D1164AE4D0ACFEF09BEC21B28F82386BBD10 -:15407A00C53AEF8DE53CCC863BA12D5BFDA46BD06AC700EB5097 -:15408F0002CF30EBFDBBC9B6F9B139F4D62D7AD71F5D6E805B09 -:1540A4008C8F17D1F5908E6966E83A6ED72B45F5429EE3ED1A8C -:1540B900A63A2DCCF0CBB1ED3BB42CB45FF0E333686B3FA90FC2 -:1540CE0041FFB3ECEC5BF5F802B44FA72DFAD8D1CE4A281F618E -:1540E300B900B02C84B677A86C76DB3BF99FD0EEE422F8E200AC -:1540F8005FBC083ED981CFE24B84CFAE4182AF982F4C4F5B7B51 -:15410D00C8F8E5E3D69DB37A34B9B1B268CC49FCDE694B85B9DC -:15412200AB8F454608B768CB223D9DAF28B43D906D7E81BADD7A -:154137005FE5AF95E2D6FCDB17DDAF3E0969020D7CAFF7745A0A -:15414C007171CCBB00C3728774E97446E1610E7E10609570CC13 -:1541610081F683EB92828072A7A6058347FA65909112F78EF437 -:154176006E41FFD4EF90876F114E1EA37DF073F5C3CB58EEA8CC -:15418B006E84B85ECCA72E398C36C1FC5578BF10F827613ECE96 -:1541A000A4618387FC708F93DC502E4F7B2AC306A5C3B2F461E7 -:1541B500D4175D5097E13B07AC345B1230A7C77511618DA6D2CC -:1541CA00FDBCA87364CFE91156CC7F6BB7A694F49C5713F9BC33 -:1541DF006FE4239A8275E6214D5DF2C03A841FC74E840561C3C2 -:1541F4003D8476802170FA88521587BA9EF88AEA631AF0F08C51 -:15420900F22D1C17EC3CD1FE3CC8C03E4CE7D47D08F24FED3C5F -:15421E004CF7FE627BA1B8B1435B84EDBF534D840DEA8475C1C0 -:154233007B41912E8807A61FD3109F6DA83600E10E2ECE16F0E9 -:15424800609555C003AEBFE62C3C04BFCF77A67A70AF79421B7B -:15425D0000FF11EC2F8013F4C3B50D1C832D788F010E0E289865 -:154272007F49CF6BEA66C2C301C50BF5431C48782E05F74EF013 -:15428700CE0D280B6DDA86A0FCBAE0B97EC75EAD65DF04E6FFDB -:15429C00AF30B6A326A5BCCACE698B42ECD38D32FF61C79E62DB -:1542B100EE9364AF96ECCE74D31AC19251EB6C608AD245CD6D7D -:1542C6001AB46D0F7C711FCDC8BD36D3CEF13C18AE55611B6D33 -:1542DB00C1B934EA1E86DA35F61AE9B58DC2989B4D34B97B3965 -:1542F00021A2F289B0BA0760AD5726F19E385D977777D1FC14F6 -:15430500E248C03B44F9639D82FCD94E49FEC4723E26E3789DC3 -:15431A007D0EE461FCF6E35C2AF628D9BC0D74C886953FCA8CB7 -:15432F0063D91084B540FA2648DF08E9D1AF56FE44A79307B46F -:15434400A74E11C205087F6EC567293F91E666AF6C71E26CC493 -:154359007200267FC7B495B76EC18D388A60DF00385BE467BB1B -:15436E00F88E901183705C2FE882F934970AAB5202F7D2ACF8F1 -:15438300981FB481000FF9603CD2E77E0DCF015AF769601F6EDA -:1543980067F6FC1ADBBC346E97B3AF1F6D3254D3D97DCB0FE76F -:1543AD004CE8876D2260E9B05F325FE2388B9E057FC8BFD6990B -:1543C200FF901E1F944F7704650CF3B54BE75CD6D9C17D3A8668 -:1543D70021FF015E6B95057102B9AFA9FED35F53505EF5771D0F -:1543EC00B2EEE580303FCEFDD9611CDFB58FBF50C26AB387DBB4 -:1544010036C2B827DAF30C4B67D09273D066BC9038B0B40A64E3 -:154416004F3FE61BDA67C151E0932982CF1F4D46C83E04B8311D -:15442B00CFEAE8785B6D519E85B90BF05C4A6FF3CFDFD8ED19DF -:15444000EB81733B80CDF71CADE934CEA4293E8F48F76DDFA789 -:15445500FDF632E9F6CF4907ED5DBFDC7A52D4DCABFDFB65D2F4 -:15446A00DFF52ED2BF7C997491778477AF76EE32E9DE60EF5C67 -:15447F00DEF49B73F6D3707DA7B8FD01ADA65F9BBDBE31373CC9 -:15449400F1FADB874FBF53F8FF76FE73C2C5E2F6FF76EB03FFC6 -:1544A9001FFE47854B45F8F7CDE54BFF67E0B7DB47ECBDA5C765 -:1544BE00FEB580974916FB24D9B869EA1F94E2B7AD82AE287AF2 -:1544D3006F573508C7BB56C5EBB6AB74D607656EEF0675DEEA92 -:1544E800EDAA2CDFA9CDBB6E40F5F7688AC835A8FECA063509AF -:1544FD00728BDDA7D75D80B159F236A998DF1F9BD7DEEB35652F -:154512001275FF7A70EE12D7502389974B7A3F073C392036A83C -:15452700E53D2DEAC3D7372BF53DCD4A50BC4D1D2CF98082F66E -:15453C002017F17167AEE2C7F83C77A54A6B0FAB078877200F1F -:15455100A9AF4C2AA8DFE584FB28BC59757B1324DFD5DF9450C1 -:15456600697FC9BE2F7C2E0CAB6C182A0086BD0043A0A87C2C1D -:15457B00B70E60C078942FE45F5CF6053BDFE9A27CF3F967F20B -:15459000229E150FB3DEB578473AE49D28896B888F3CB3F2BAA4 -:1545A5009AB10555801B11CAF4AC69061C35288BC416B5F6430B -:1545BA007CAF9B0DF4D57F9EEFDD3B3F4934C0759110C0817BDE -:1545CF00705791DD9019D81126929358E21EAA1BC074D286E933 -:1545E40028D65DBC51ADDFB956E52A1DD8F2171DD83A01B66A62 -:1545F900B181FC1320203AF4F254B6A822C1B45D595499547755 -:15460E006DDD51680B88E73FE4F3360C8CEA893695ACFDE3E983 -:154623007BB0DC9C0D075793C2BBA784F99A05837767A3EA852E -:15463800F2B06EBDB62E3F2ABD115ECA66F0520F6DA7624D974C -:15464D001AE889103CDB4AB62BE580970A31A996B264DF0EBB47 -:154662006D2EA6BACF947B0ECAD221CC0BF802BAFB1C1890F65F -:15467700F5DD372A280BD5F7DCA8CCA53F74226F39ED1BCCF4C2 -:15468C00A7FAA93D148F3BD5A2066E8AAB3CBB539D07711FE630 -:1546A10058D06DFF1BF05FD10370427BA9A88CA8DAE31DCADEFE -:1546B600131D4AC5A9356A4003BF9DAB55ED233740DBBF41C1A6 -:1546CB003610009CD6AFB170C1C7B95E996DA0B60D729ADFCD92 -:1546E000DDA28AF112BCF7C4EFC1BD9ABAEEFE79DCADAAC8AF72 -:1546F50052C59550DE7577A8E2EA1BD4E192554A04D70156CE75 -:15470A00C42F0B5AE766287E326CC57FF233AAF844873ABC35B0 -:15471F00ACB861DCF53E7E9B52FFA1925EB48D2C24C27D9E6CDC -:1547340047DFFD684F4A0BABF5A76E51B9931DAA067139618691 -:15474900169BB08F07E99CCD3AB4A5220C40BAE31D7D34D76B64 -:15475E0067BDA5DE505F99B7BDAF3EB556D906BC4106FF21F8F1 -:154773007E1A79CE4FD6ABE250878A72B52CDF8AB29D20263FAF -:15478800A3726BEE5429ECC90E080FABC38033A43FB6719C93FD -:15479D0094FF03D75B7F0A70A80DA881539F512B4E6EA736B0B1 -:1547B2000BDAC03CA07D7954EB2BE64B4877A41DE928DB34C57B -:1547C70036791DC0D28BF0039EF16EBF1EF84F96DCA5CC837208 -:1547DC0010FEC1ADD6FFAA8BF900F225C78D71616C58B7278FDB -:1547F1006B3856DB36606A85F843BE0773AE054EBBBA1BE290E4 -:154806003E39C070D71CFD4AEFE3B54AFDC96AC06DB57AB97630 -:15481B00F4129B6947BF64563B421A94433B0A8A77115E1EB6C7 -:15483000DB12B6A380067E73DAD2F6C49FAF2F0F6E00FAC4FB9D -:15484500B7B35BD7CF0BC6FA39F10ED57157446F5D8F749A376F -:15485A00B0B68F9DE8ED73BEF52FBBE87E9DF2C4DABE8A6C6F1C -:15486F001FE7019A5FD9A0B9810E1781F688BFAB8916AEDE0ABE -:154884006D0BD0E10EA0C30EE2E9C5B428B16991B4EEF5F17365 -:15489900C29550766CDD14D105DB4D6CDDD13974019AF86EB218 -:1548AE00E9027CD7B7B6882EEF2BA2CBABA43339D3B7B742BF10 -:1548C3001E29A213D987863680FE9B6D5A9D063A39B4D9F01E37 -:1548D800E971A6881E3FB2E9817D3A60D3E2123A006D8A695101 -:1548ED0016FDD4FAD2E8DAF5EC6ED62B663FD5374FDAD057C62A -:15490200FE7A7D79E26FFAC4ECADE4AEFF3CF5579FC8C01DBD70 -:1549170093F0CE6F6ED05CC07B2F96C5B47207EFD04F2BC4AD95 -:15492C00C0FFFE42AD5873EF2CBC975F0EEFA9C548F322BCC7E7 -:1549410009EF4E7D8BF10F3CDF779D8D7F5C13C17EE2E0DF5732 -:15495600847F17AD6D58F81DB1F15B897C0AC2F0DEF0E23EE01F -:15496B00A47F89C6058B66988EECD3DB74B0701E9905CB97015C -:15498000CF6286EB7D12BE49E03DA59007DE9FBCF763B7A9F5A9 -:154995003D5D8A54B254292BB956C1362C02EF61273AFAF6FE68 -:1549AA000B849D5AA3F84A3EA2784A3E6A8571ABFAD8F537F4B0 -:1549BF006D8BBB7A11AEC5F69DF2D046BCA5B28BC648F4477B35 -:1549D40018CE1C05CB47BB9125CED86D8F1F180F75A511AEE79C -:1549E900F3793FC429F4FD27A1EFE3D87506A693B85E82F2017F -:1549FE008C75FE27ECF8DF82FFFA9779FCFA8E505E2975976B5E -:154A1300FC36D4D3629C7597298C2C795F74FC768369A4F38504 -:104A2800FEFE99F5D6F2FF06E2E5D1A4A89C0000A7 -:00000001FF diff --git a/drivers/atm/sba200e_ecd.data b/drivers/atm/sba200e_ecd.data deleted file mode 100644 index d097e743b846..000000000000 --- a/drivers/atm/sba200e_ecd.data +++ /dev/null @@ -1,928 +0,0 @@ -:150000001F8B0808AC5A10380203736261323030655F65636426 -:150015002E62696E327D00DC3A0D6C14D7996FD7B3F5AE71CCD4 -:15002A0078592F3F8DD70F0AA949E8DD022E07F61A1644AA40C3 -:15003F00012D88A433EE52268844E8924B571792229D1B0F8EB1 -:15005400013B7DD0C7608813E1640D5E58529C6C909D101DE4AC -:1500690016357749A4E4BA8A7227541DC9AA17295C4A2F76455E -:15007E00259438EC7DDF9B19EF7831C4A1524F772B8DDF9BF742 -:15009300BEF7FDBFEFFBDE1B3FFCD3BF7F88B808896E2484FED3 -:1500A8008890844A880EFD1CB4BBA00DB710128396439B8076CC -:1500BD0018DA4E68B51FC3036D16DA1DB8364E88026DE92FBA6D -:1500D2001EFE486452BF7C63D90D63AE825E0863FB54E1A984C2 -:1500E700782F999F6AB59F9E3C49B19D522690D8ED9FFB737D9F -:1500FC00FCD38F45DB66F353D2B6AD1433AEF2F2F209D77F491D -:15011100BE34E18787275C3FF52678EDF13693B20B7EE47FE17D -:15012600E71A20BB45FB4AA95D5E29DC72DD983C8589E52B4C68 -:15013B00927E7959B9A987A7DA6E4DCF24842D778E97CC7F63BA -:15015000F90B6D6DE8BEAEEBF97C299D49C95956A43F7A5BF4D5 -:150165005F7C512AA1FBB7D87EF4AFBF99905E79919E97FCDF83 -:15017A00FFB93C759E5BCDF3F48DEFDA29E89C2A8EA109DC0E0B -:15018F005FF8FFFE2B387E24ACB3FC6765A432BB6F911CF4C674 -:1501A400C1977CFA72F2308031121A8EE3BC3E026FE14E96FF67 -:1501B900025AF9AA21793BD46B5B3B1A708EC8A429FF1CF1557A -:1501CE003E4F7C81FDC4977802FA5DC447C2618EEBEA932EC057 -:1501E3004BB79000C012130F873C52EDEA50657DA14AB86BAFA6 -:1501F80014D4B75C5C467C1D4F126F20B8231E269759EF9EFE32 -:15020D009D846F61249CE1FA03844C0B6A716FD52F20EB9C6518 -:1502220035C1447C7AEB6916F59268404FA9249C341086C4F6C2 -:15023700182477ACC79FE300570FFC87E3FBC3A4657AEB6A1692 -:15024C0085F4D4BE7FB34AE4F5AC7D7DB3FA3C213546D2DD045F -:150261007C32C81F7230EF6A9E22B7A8B81EE7116EDFCCCB8A9D -:1502760067E549751FF5B490DC6C5641483010844C26EF66BEA1 -:15028B006067FCC3B9C4E721F3D53DC3EE1669F72655BAB04CF6 -:1502A00095B6AC654B008EF03EFD6EBA6531EA08F113F958A63E -:1502B500F8F4EB015853B966BE7AB950A8FEB04D8DB4FF933BA0 -:1502CA00021254BC2478DA75DB3C456FC2D306E429775C5F2546 -:1502DF0078A202FFB7626115F9D9AB95B5608BFC601B04DD5402 -:1502F4000575C0F90BA1C39DD5640A91FBF4DC8A2D0DE780D715 -:150309001DC0AB3D1FAB26E3C3487898BD07DA0F053964FC6180 -:15031E00B09F6E2C85F4EFDDC054B2B33F93978886ED30B49447 -:15033300768879E085CA723BCEF75CC37918AB1763BB718C8F81 -:15034800E218973A503F887F41CB78FCF545FC0256ACB3E8DA10 -:15035D0034052D8BEE84341DF8D924F1874DFC62BDC065D1B458 -:1503720069396575E2BF52823F5CC47F03AE9BF17F2BFD283F5C -:15038700BE7DFE1BC41863C362AC4325B1FE8C3D3EF66ED31296 -:15039C00F6BE39FF0257281DAF69ED17F8883C2F83386A5A1923 -:1503B1001BB5E418C30B73E3E48AF573539E9BF37F2BFCD76E07 -:1503C600827FCCEEB1FE1E1B7F838D9FA45929AE521C387FCD8B -:1503DB00E143B62C02A73CD433A10CE3F647A7B91FAAFA55D204 -:1503F00030CFB4AD06B685FE0DBED990327DD38903EC5BB9A572 -:15040500685F6F5587E09B3474B0AC44A2105B784D2CAD1ECE76 -:15041A00B85B80BE512D77A9570A85A0D33FD6FD99EB3BC4FAF6 -:15042F00CE09D78FAD053C57715DCCE12B18A2352F4BE4DF3E26 -:15044400A3E73F3562F9670D7FEEAC3AFD034D21B14BAC4EB966 -:15045900475D4C7FC5F6DC3B9020F2BF81EF26793FC4F5605035 -:15046E0089631EE0D00FC49222DEE3788D3E00FDB481E324B744 -:15048300A8470EEE8A93DC7B10B366C4F7CDDCA178E9E3ACFDEA -:15049800FD956A27C4B7F6F7D7837DE688787987152FBF0532CD -:1504AD00C87598AB92BC1BCF26E134E7D056692EE07F3ED0CF67 -:1504C20033CC96D2CAB56AA12CCB24D72A55EADDC8BAC949C5A3 -:1504D700A50DB0EEB2E30AC28C421A3D4C5E56C05E0CAB886E6F -:1504EC00F23A8C67712DF4FF45113C02DE68FE6D03E4309096C9 -:15050100DB45AABB203749D1BBD5BB80A7629CBF17F86C6701DD -:15051600E06D6788F8BC40FB933677C4BBE135950CFEDCC09CF9 -:15052B0087FC728B5FC455F5515EED2E3BA9A05ED65592181934 -:150540001C30B244C0E918E7BB519E705AC4FC2A42FC2496D294 -:1505550047B7F635873457A377C309F0B30106F089DD3F9C0F86 -:15056A00364FF16B85424D9DF26B359AFF9457B94EA8B1FCDB9D -:15057F009C84327177E57915E18379C83D202BD2385A0672CBE6 -:1505940003461053742C63CEC97F32C0F601EF8697D559078ED5 -:1505A900C3BE4D097EC0EE19B0BBD8136BE99A8829F3A21ECFAA -:1505BE00CAE3AAB013E634CB4601878D1EADB5725A02721ADA1A -:1505D30000748276C8A27FA15F800E9016D959D40FEAE5975DB2 -:1505E800DF079D844D9D583CD83A09002E874EAA854E56AC5F7D -:1505FD002CF0900C0BB60AF9C00FF764AC07F676126B984CB013 -:1506120055E82BFA3CD80FD619159837071F671F423DF547CC48 -:150627009D9ABBB94EF94FD5EDFED9920D9ABB2948DDCDE3ED05 -:15063C007B3FE4F1ACE201DD96CA8CF2A1DC1EB2006AA3679877 -:150651000CB2CABD9BD88E3B896FAFB6B1C9BBE105F0796ED6EE -:1506660014E1A5ACB002FD803221E3D52B26CFBC5F7F80DEBF28 -:15067B00988492F15AB2470D8C32C12FE9EF63DDD98560AF85B3 -:1506900006ECCF8CF5F4E05E053D0AD9486CD0C0F501D8C35394 -:1506A5001C72BD05754ABA6D6364519B29DBDD753F5B485DC4FE -:1506BA006BCAFA6BF53A79F216B2E641D6939396B5F5DBC477B6 -:1506CF004CC8FA30C8BAC39435047BBBE1F7A67CB1E3FA532095 -:1506E4005F6DF63BEAD4489390AD2C36430DE9A1E66F635D12CB -:1506F9003B20628096FFDC38EB2553A0E5B81F85AE5007644910 -:15070E00D12FE4BE8CF5801EFA8A7AC8BD6A209D523DF4801E4A -:1507230074D043D0D24325E80169074B68831F4E194FF38472E3 -:15073800C0972AEED189F7E6346B6F46C6E6D1C78027EC8760F4 -:15074D00EF3AF72BEE55C253FAB5151EC10BC417D8AF2761BF9D -:150762007ECADD9543AA6BE659D5D53524F6EC11C79EED297B45 -:15077700C5DEB37E9C3F52DCB335E8FFE8D7CE7D3B0BE05046FB -:15078C00BF4346AD9C4C71EEE7B1FC943BCDFDC1CBF1EA46B191 -:1507A1005788F48AD452BDAC53F4AB5DEB45BC8E06486C8EF056 -:1507B6005F6EE65EC88572F20A93D6ACC59C974940CE2B4C4D3A -:1507CB00B05EFDB8C2662694C06E880F77A4541FFA4FCCB0FC60 -:1507E00087C7671D931ABD55AB61BFC6581BD118FA4ADA05352E -:1507F50041586188A322F20CD3A03568598B1F7CEB04ACF36627 -:15080A008FA9011DF3FFEF0D51CBE01EF84BB6DB3E6764B09B53 -:15081F00E9E04BC89773FE51F0AD1524C1B6E9879693F065A3B1 -:150834001E6581396FB61DCE4A585F7C435A0F9AB4B278CE7380 -:15084900CCAD4A8E3621FE34B9357E5D33D7E74BD637265BC568 -:15085E00FAA513ACA7DA492677758B1C6DCF47110FCCDD958C37 -:1508730034A1FEEDB501FD984A61CE8BF0B1B9803B950925C1C8 -:15088800A6164C8305238BF5A9CC647C22F0A6D48CF11F7DAC82 -:15089D00167D35D76F94D64FEB1E76D43FA2AE642C8AB58F2916 -:1508B200DF196CCD7ACFEA53689DF58F63FD1C0D7D1060A1FEDC -:1508C700411CD21AA61EC43D0BF2E27E1A572BE3F1F93E2FEEED -:1508DC0053C31FCCC6F17C5BA75C51FF86BE06E7DDA19D24F6BF -:1508F10004C39C9E7B40D4893C8BF50E9C875D33CD9A270A7153 -:1509060003EB2B92DB8E7006C2C9C119702E7E5A9C8BA747FA68 -:15091B00C59938181D54B1CEC0F544AE15676212AA8F4F8F3447 -:150930008873309E89CB8066FBFEFBADF3F0BDEAF32EFB3CBC70 -:15094500D43C7BDE10C78B67CF89F2349E3DDFAA29397B62AE9C -:15095A00B6CFC3B992F33087986B3F373B0F7F4D8C7C4CDB1875 -:15096F00F11C3CA3BA601DC6BA3D10C776BF9B56BC55C7314647 -:150984008A5A40C43898C739A0853569CD9CA4A7C98449A13EBA -:15099900A222060A9B891858EDADFA15F8C48098DB4EACF36D2F -:1509AE0091DF1EC423D60B9D9B7024F62763F7BB19657A24259F -:1509C3006C00670103C726F7FCB3217C16EC1BA8492A585360D5 -:1509D8002C47BF7906F9224BD94BA843FB5EE0366C531F98D827 -:1509ED003613DD0B94C796AA28EB3EBC178056DC0B403BFE5E71 -:150A020060693CEEBAF15EE0EB6CD6FE17B0D944FAE413D8D15A -:150A17005B750FD830CA2C7939CAEB6D9D6DE290470CBF43DE6A -:150A2C00042153049FAD7D967D070C8499DC73613C3F729F6190 -:150A4100E39D01786D5BDBF1E9CE478AF1C5E5EB107ADA94DD30 -:150A5600D3689F51E58D49A5A67590C5800FAC0FF04CAA79CD1A -:150A6B003C8DF05CE80DFC0A748363EE92B161475C9A41E7F61F -:150A800060CCB93802B97A659F1AD0D07F1A18C81E708580C77E -:150A950031BED23C564648A3E66944597640DFB5C63C7FE1F838 -:150AAA00E1DA2106B508F7C82F412CEF33EEA4A70D29B9C7210B -:150ABF0097CE104EFF119EB74C5C4B268B2B79AA880BE087AD61 -:150AD40073A08BE8784634F0DDA6F34DE4D11DF2F43878D02783 -:150AE900290FC2651E30E5D11DF27C2DAE1279AE96C873F536FA -:150AFE00E5C938E479C7C1436692F2205CFE7E539E8C439EAFE6 -:150B1300C55522CFB51279AEDDA63CC991A23C67478A3CE0F891 -:150B280064E44138D99207FB4B268BAB449ED11279461DF2440C -:150B3D00ADFB0C19F3B9E5E3750A53EFFB09D2357D04DF975A45 -:150B5200EF19EBBDDE7A47FAF83E43BC2799F065A0B1AB4CB4FF -:150B6700ECAAF59EB6DEAF59EF17ADF751EBFD1DC0B38B9EE038 -:150B7C00D8D760AE93BECCC5BD03F47BE86B5CD403D04FD337E7 -:150B91007994DEC5CC73C5592303EBE05C51334BF33407939EC7 -:150BA600667FDED3EC053B606D8F3236D05302CF7658BB9ABEDF -:150BBB002AF074437F337D83E3FAB74C3E38D2DC4E777313AFA4 -:150BD0006E0C025EBC6B5841DE6167B6BEBC5CDC59004C15F5B9 -:150BE50034E2D80B5B5F136359C7D8335BDF1463C8933DF6E484 -:150BFA00D6BDCB6DFC7751D37E886796E8A7F9768B3EF2B4B65E -:150C0F006E60998DD386455C36ACCD2BF216B26011EF5F514FEF -:150C2400B3B84BB1743AFC88A9D39CF8EE61CA3EC3CE1F304F8C -:150C3900C7CD9BF4EEB6700C9A638CFF9D09F3A1850369071099 -:150C4E0007CC651F2DCE452C3DC6617E1DE80F75C7A01FA7072F -:150C6300399E8FCE099E2E0B3E1FA5CFF15EA1DF1EE3F48870DB -:150C780040FF03D73D4D7B67526543E88D85CFE692CA0F962315 -:150C8D001F9D424715509B2E592E352D0AED5EC861EE6E319754 -:150CA20011FC56243D8DB3DE949A82A1830B0D98AB5A6EF28FE3 -:150CB700FAAA807D72FD2BA9E98BDAE7161E82B93F367B9A2BEB -:150CCC00B4F2C6CF2EFD2182387F57CB22B8FEB7BD831184FDD0 -:150CE100E0D269C8FB3B044DE03FA38B7686E019E4CCC444BBDF -:150CF6004BE026E1682629DA84E0036A8E0CEE89E9172EABAEBD -:150D0B00F735D87FAFB0CA60268EFA31D75D36368BD6D41109F9 -:150D20006B8602EDB495C755D7FA47A0F6D9CFEEC05C097A3363 -:150D3500E9268D0ED1EE303A45DB23F4590EE705D7FEC701FEB1 -:150D4A007BAC2A1806782A6219C20F8A36619C15ED52A1F32969 -:150D5F001700FEFD7F10B5D5D4600CE0A386C977D2E887F6692B -:150D740061875D467AA498DB4808EAADB0226CB30D6C93A007C3 -:150D8900B81CCCC1D845B6B4CCBA2B17ED45A301DA9DDF273E14 -:150D9E001E76B7C0318F1D182DF8D1971E85F14A7A02EA055D0D -:150DB300E8AF0CCE160BBE8370E6BEC25CB9CD82457D5BFB8D79 -:150DC80061FF29A029FBDE533B9625AD6F6D507FC1B896FF8DAF -:150DDD0011681D62E8C0DBF3AF1BF0CE75E02D104DA9B20FCFF3 -:150DF20039EF1B121D323E69B0F8A1B3D9F52F4D1A4761BD6C70 -:150E0700F1C32D7E8ECE29F283B9EE030B36EBE0277B0B7E623A -:150E1C000E7E36033FF0CEF904FC6C76F0F39845E33DDC47160B -:150E31003F598B9F4A073F98AB5659B0E86F363FD8BF193F51AC -:150E4600073FAB811F78E7C909F8796B71919F8FBE30699C1BBB -:150E5B00C19C66F28334909FD6D9457E30D79C3161052D37C413 -:150E7000D68EE694310A676A3BC63A3F0F6874906BF434C4E84F -:150E8500CD4C0EDE173FBC2CCDF0FF560EE74E2AD65D9091B78B -:150E9A0062CA7F8CE0652EF17B1D79334EFB7959D57995E60779 -:150EAF0058714DDAB868C5631B5601B86ED8DB7E888DCEF53124 -:150EC400DACD37037D05F850E85178AEF0049DCB77D105E03353 -:150ED9000DBC9346C056AB799DB24D35C8A1447D3EC5BAF55427 -:150EEE00A207E093F41C4F53C60FF79E663564409DB6A597D514 -:150F03005EBAC23AB67C97EDA99DCFF66E59C8F6F52E639D97C5 -:150F180056B223B56718DED37CFCDB32DCD30CFFB7E7D9DEF32D -:150F2D00ACF2C231F5E0A5FD500FEC5FE2E4EB9D30F155D1D593 -:150F4200CD6363B176D6B090F8FCCE3121403B3B7A93F1CDD75E -:150F57000A378C2B5A3BC77889FA09D44FB08EB7B33B9B26184E -:150F6C00875AE06A1DF179434911ABC046F2DCE4318EF6C5F74D -:150F81004F46AC1A413EC789CCB844C51D2BBF8AFF6810E6FCBA -:150F96009A687BF8A8DBAC7586451B66A4007551554AEDD6878E -:150FAB00946EBD5F9926A5D4236543CA91E88072186CF9ACFEB4 -:150FC00086E27DEF0FAA8005E0837A9722AF632AFA4185833FB6 -:150FD500BC8390D890187F52AB6CFCC4FE770F2B6EFCFB0A33BF -:150FEA003F6A63B934C991E73990C72A925F35CC4A3E8179C4C6 -:150FFF00CA8567451D63E6AFB366AC039D99F98F5B303D026617 -:1510140047314F8AFDF09845277B039D3BC6D131F3E559510FD6 -:15102900D97432169D0F2D3A264C0F33E3709A87AF12D21B76BE -:15103E00B5941F48A981E83CBCDFF3FBB5EF468290ABAE5E372C -:15105300E5FD40FBEBC6CBD0F782FEEB14380779061290B39AFC -:151068005DA1745CA678DF1B66C92CC489A4AB65333D652C022E -:15107D001C92FC3DC8435D3C14DD1F3948BA13788676877AE21E -:15109200D23D50A3C5468CB974C4705BBA8ED02E234A0F1A8197 -:1510A7007C8A734F6AE702DA67605C895D0039F2FD5C069C38D8 -:1510BC000E276206072EAF93E6A617FA9A9DEBEB9443AA61E19E -:1510D100C0B5D8475C147049A1FA78B464BD1FD647E97306D4F3 -:1510E60010D6FAEE09D7E7FE1173537D1C7909C3DC02A833C232 -:1510FB00B48BE1DD96413A120AFD2FC3E3C238779A19E470422A -:15111000D23A0C3FE46037D6BBB17EC3AB751B95DA39718F365C -:15112500DE8FCF5A7EAC8FF3E331FFCDA614D9E1BF55502B8C04 -:15113A00F928F801DA0F7DB4FCC0805A43E6A9A66CF5A66CD11A -:15114F00BE66A73F0768170F6A529384E766C29917ECB1733E0C -:15116400F1E1FBBE999DCAC54DC4F7E2CCA422D3F9C236ABD16A -:151179000EB096AFEE7E085BCF52F13F2D15B383264E79893719 -:15118E002E43FF568F0947444B8336DF14F65D1D91AB16A81DE5 -:1511A300EEF90F79AC71EED71FB2E7F1FF6AE4E8DC07251B479E -:1511B800B4FB41BFDD5F591C17FB04E498438E36617E801A931D -:1511CD004E8BF5604D631CA2520BD51883B37A0061360998CB74 -:1511E200D6779F4EBCA3A0247692076973837DCF82DF034657E0 -:1511F700342F36BFD19B7797884F4E7633C487637EB95B7D077F -:15120C00713AE82F17B829C33B5949FE0CE87719B80EE95BEBFC -:1512210032B80EE89D71F62F3AF158BF83B9E39073F0FBEF1552 -:15123600568DF74FFC285B8BFB92DE1B09D2798DCC8A0F3FA1C4 -:15124B000F35EA629F778AEFE5BBA75C413ADC2F3F67DE75C28B -:1512600018E4AB1A1BBFA4CD6558B309D81F7EDE4272FD7C9ADA -:1512750003B6C2829520374F16EE10F0BA0AE2DD0B5A5D13D6FA -:15128A0008E677FE432A9C9E184473435AF339F8E46CD63B4C08 -:15129F00104FA67AF42893454EE83FF3BB42A11AEF06B789B5BD -:1512B40069B17681B69FD5C84FAB776AE759448333656C9E811D -:1512C900F489DC6F081EB09F4B19923C5745DC52FEA88DDBE4E5 -:1512DE0011F6DA589FA78C2CD058A44D6FACD2A6477EA04D6DF9 -:1512F30044BE376975CDB67C923C5B2D956F3273820F7BACC455 -:151308007E7C18BF7D9F03DB65E24B08A9C63AC6E53BA7BEE98E -:15131D00C2FBC734D64D747A10725E6CC8C0DA424A0E31D7BBE7 -:15133200E7D5FF065E7B5CC48BF6C77BF9465AD358456B227E15 -:151347007A47E366D0D32A5ADBB8CEB237E2A8965F1577D4E057 -:15135C000C34289F51CB80C60298AF86BE1BFA088773F6B90BB5 -:15137100E15DD638AE0F26E78571BD8CB2027D19F8284CA5ECCB -:1513860008E953189C8702AE3EF17DE059F17F5203D67D685A64 -:15139B009CD1719F797D57D4368823337C4755D7CC4EF57052CB -:1513B0006AA9B9705E9D23EE5933868EDF5E760E88EF34384755 -:1513C5008E0DB1CBE2FB0C65B3C8A9E508432C18F17DA56F880C -:1513DA00CDD2BE6A126B89398EDF4DF4248EFFBC89C883064DB6 -:1513EF00A6F03B8821AF1950A330EED79AC5B817DEA980AB6D72 -:1514040092F05E22F6BA7118FC026582FD5F8D7715B3A2A71B27 -:15141900C59D456ED038AC4942EF788FF70CC43C5BC6A0252368 -:15142E00CA11B1F27D7D01CF75FF43CC13064755A4D993BC91CC -:151443001988C3038611280C0F1CD6E045326894648038C168C9 -:151458002556E40688EE7B5CD089266EB450729055768B5B5FCA -:15146D003081041F5CF34C206BE1DE84CD94932B2203071A3D8B -:15148200ACCBDE79BB68A5AE721677C7D5B9DEECD69E4779615E -:151497008D6CDC65AB38E7BEAFBBDFCC9BC9A0E0DED5FD987AC3 -:1514AC006FBEEEF77D5F7FFDF5F77DDDFD7547F5F31B315A88AC -:1514C1001BB88ED10BB618607BCEF31C0253B2E941318E59B05A -:1514D600E751CCF18671A03F4CDCB28FC53814642D3F01387A39 -:1514EB00433155770FB3BC0699D9A328ABEF954FB03595493179 -:151500002F4698A20CB3BD8A291B2C2060E47206562A6057702E -:151515006D46C454576DDF30DD1B292025CAB0698761DCE8CF5F -:15152A00819102899467C3E8203CE5C8192A83AFA9C032D15E21 -:15153F00DC8F21F4769E6B22BEBFF4E59C7F70B1EFE3D4E291CB -:151554003FC5FFF019EAE881BE606BC0316AD10929C3F44592AE -:1515690030FAF4188BBB3F01BB07D1C3168CBB93E9B888CB7601 -:15157E00C1548AC935947C3DCD6728F916EDE819566B6CBC2309 -:151593004EF46F7DA14186B319437E5C0345D9C8C3B42F1C65B4 -:1515A800F07A019F12B1117B029F3EDC2F92193EA6035EFC1FE0 -:1515BD008E1956FFA7447F768BFE64BA60C90D6224A00FF3A197 -:1515D200D7696F826C29B2D96359B4C7259E72CEF3BD2FD3E9DE -:1515E700C559F685CBFB75B6CF555344C27ADD1915C74C0DDB68 -:1515FC0013E730B2613AACC00E2BC6711C376BC1E339C47B8D20 -:15161100CCE1A1E409E0F7049D3FC9E4EED3053F0C0636CD57B4 -:15162600191773BF8421C3372C8708FA8C3DC3678CD9888F0E7C -:15163B009BF9EA933CF549BAFE5B5CD600837773773ADE8E53ED -:151650006931CC3E443BF19DB5C90BBC5B6D82F729479CE97FDA -:15166500C09B29DF579729B7607BF3C0A40DD3614E3B2C67FFB1 -:15167A0091E9BB1863D6F8B58FED8E9CB18D4FE7C7710DCBAE50 -:15168F00F58D9EE71BABEC255B19C674ED8BC82CCBA6A03CAC55 -:1516A400727C5F72A1536BC8299F85B4EF47DA71A3028C776FB2 -:1516B900C4B945C6BD0EC0157E28639F5037702C5865E5F6325F -:1516CE0090834BE0614F1B8EA21C1C56FBB9FE71989E0B037C5D -:1516E3007B2C983703D3F3C0667AB261D8A62E5B9B2D58671E54 -:1516F80058A1C70ED38D4431D8B685423E246AA0FDC0F1E915CD -:15170D00FA1E4FEB3BC0D017D8D63A4811616B1AA8BF5EA6BF42 -:1517220031C3D2F39907713D3C418FC2B8F785B86DCB8743BE31 -:15173700611C5086397BF230D6331B6CF350B4EF681FB7A15DC2 -:15174C00C1B526F8EEC0C2B8CAF0839EC14490E683CB36B861D9 -:15176100AFBF203F5C0678AB43D8DF626E732D99615C500F659D -:1517760079E5E5CDDFD6591F27B43E7DB8EDC0C284CA7310AFE4 -:15178B00436EFF8BB8B09D5FD507C68DF0F58D7165F76B42D8B7 -:1517A0007BCB77737B9C2DEB6C7B9C8717F886F302710A3E0187 -:1517B500F76CC4C7F6C3F3C8214F7D92AE9FCDDF6E9BDEE11865 -:1517CA007678A68F71E2993EC60B3CD3C733C903DBEF9E3EC6AB -:1517DF009D9EE9E359CA8161FD57ECDF66E6BC221EC371CE7D03 -:1517F40003CA7489CDF7C15397785C62129B2F9473CA245B99AC -:1518090037A7CC652B5B905356642B5B2C0B3F129834E23DC8D7 -:15181E00972EF2CBAD582446838A3390893D6294E5EA425F6464 -:15183300628FA8C6E38C9CD853CEE4C8C8BE924647DD2AE853AA -:1518480098670742867C3B2105072B357D32E5763A3AD5367878 -:15185D004A20935E85AFC3FE0874EA70F4F7E5646A805EE941AA -:15187200044EC44576EDFFFFFDD5D610F7D86729370D75A835F8 -:15188700F749EBACBD4DDC2F24EDFA293667688F9E1A67CFD1D9 -:15189C00532CC7AA3D796A929DC989D2C446BE16678B410D07AF -:1518B10019FE18E539713F71ABF7F3BC65EE67BBC1CF0E829F2F -:1518C600051FC9E456C2E466F9EA1AE083783AD5F2CF84EC22A0 -:1518DB000E263BB47D51C0E307F847F749AB91D6D98D7C8C8CD2 -:1518F000C013D71B1D0A8B154DFCBF212BF68CD107BF617F17F3 -:15190500B179E0A4896D045924842C12421609218B04CAA2F079 -:15191A005E57A33D7EB95EF9E158F228CB033395AEC0D1422EFD -:15192F002B0EBB13600702F12CD83D00EB0B9CB66045089B0F62 -:15194400B05B03A30863FB3A5CA6572E810C4196172F4D9765C3 -:15195900C37AE2BE700965E95F7DBDEDBADEF69CCBA30F054261 -:15196E001F3EAA26EEDAEA6C3E2B24E2AE075E9CC0EBDA3CBC7E -:15198300C6A17E29E3B574F58DF4C1F5F27B3C0FBF8582DF525A -:15199800A0DD1F9AAEBFFA35F4B77322E52E8076B44F4C6F471A -:1519AD0012F0344F603BBCAB6F54976EA43DF13CED91447B1A71 -:1519C200818773F7417BBE01FDD6FF8236297E2A2BA594D97E0D -:1519D700B0798EBB0889001CFF4BA4D6D88DEF01D550403A8B99 -:1519EC0015CD9495EA57D91E33D899FA08AE37478DF001EE1352 -:151A010095837CAE32FE32F86249077FD8CDD64B0DA837161922 -:151A1600328B9A4E9A139F72DC7EC09B9AAD1B53F0DFC1FFBBA4 -:151A2B002E7C9ACDCF0551F70A3C1B20DEF42A9C1E51393DA4D7 -:151A400083F4D02BDBE92D867A454D43663DD0DB2D709CFE9440 -:151A5500D3EB14F4E0BFCB2E4F59C8B3086489E5ED5524AB7C94 -:151A6A008E65FFAA7879434EF95C513E26CACB73CAE789F2E328 -:151A7F00A2DCCBCA278D1A9A39CF92823652D2A5E2DE9D0B7DD7 -:151A940074CEF9956E888768D4B905E28CAD55B8AEA977AD2A29 -:151AA90056A4A02AE29A9E8517D5AAD0BE60AD2D5F60CF48D3BE -:151ABE000728ABE7DB3FAC0AD8E01FFFF0E5AB085FB3F5832A70 -:151AD3007B7EC18537BFFF1AC29FF8DB9F559162DCDBEE373A7F -:151AE800FFE5856AAF4FDF4A1E236E974ADCD3F8B4E58F2987E0 -:151AFD00B2FD338F35264DB4210E0F9FC331989CDD362B3EC2C4 -:151B12007A3341D7A7D6F2DC19ACDB5337ACCE8C3C12D85FC732 -:151B2700EC391DB5EC39945967724637E69FEF1B9FA7DCF14B5D -:151B3C002977661E46B55EDDAFE2BE0AC48DEEEE8551753D59D3 -:151B51001EF490E5AB16298EE0799045CF42AA6ED0FDC17369BF -:151B6600B9C4D99AC4CD4C1E740FC6284E88F50673CADDB672FB -:151B7B0009CA3B3372ED2E9048B70BCA1D65D07FA2CE22E6D307 -:151B9000F8B73741FD0651FF0EB0FF3EE1DFB0CC07651584EB9F -:151BA50013FE5F7261402B81FF8B6C75965C8869DE1C7E1E8494 -:151BBA007E4A4462A60B7C6CF96F53EEE8D594BBF9CBD42CD1C5 -:151BCF00BE7511B0D3A03F5976C52BF45442F9839E86927F6EF3 -:151BE400E84E320BF50CE3600B37AE5FE21EA16CE30B73854FA4 -:151BF90047980F360222BFA108F02E00F97B9712B7EEE7BABFE7 -:151C0E00600DE016FB3054F8F31749BFD13B3AA8BEB90CF7E984 -:151C230002068F654B0C561EA830D07717B863DA0F963E5CEE8D -:151C3800AD8CD2D65732F1168577A90F2255788EC2EF1CFC9498 -:151C4D005EB0AFF01B17BFD65EBEFE85F82EFE12D7BF94C6F455 -:151C6200BC4CC0A3FFC1E161012F009F5683EF7480CE837E2B7B -:151C770000FF50CCD618264DE9DB84BC823E830E9896DCADF9D7 -:151C8C000796596D9394037406B3ADD4083C4A48D17FA6DC93CD -:151CA100249BAEEE22B370AD1BF1FF33CC476702DD31A81376E8 -:151CB600733F65E191051EF932E76DF493947B90E7F5883A101A -:151CCB0007D1210DC7EC646A361B23B837D6F7F7C7198C4CCED0 -:151CE00026DE9F0EF277F883F2CED48D9AB89FD6377A5C9D2F99 -:151CF500B1F50E93EFB3454DDC575B6BA3C3D71DFB8DC7C61FD8 -:151D0A001B5F363A98A53F37A3FE209FA043814ADCA386B8203C -:151D1F003C443146DBAFAC0BB01C45CC8D8BBC4B95C819C3C77B -:151D340072E8BF303D7CED9BF68A7557BE8E3BC2F70C020ADF8D -:151D49002F40BA387EC227CDE7593FDC40FC373E8438D2F3B0B3 -:151D5E00AFE741D0065A69FA79F475DB3AF0CB69FB17A5E3B899 -:151D7300D62B1BEC9C14192D20E037D8FA3EE0A0631B591E841D -:151D8800CF9A67CD2103EC0C12CA784CD834FCBEFB5EE296C690 -:151D9D005FD2E40F5F52ED362D6D77D99C6CC448FDD57B923824 -:151DB2003324A32D66F3191AA37790C120E6EA4FFDFB7095BD05 -:151DC7006F6E1263BBA482E45D1FE56B9BBAC03B22F026742EFA -:151DDC003FC0ABC738DE25C7B3F0CE1078C757E7E0457B08F1E8 -:151DF100D5BE85FD2A3BAF0F3610F126393E7D19EEC9CB83B482 -:151E06003039AC4BC933BAAB28C6D6F966029DB961AA3922869F -:151E1B007128296D91944EE316F91D6D2C95F279A25230334FC2 -:151E30000D1B1877EE72A0ADAA6DB4CEDD635E358B4B587EE23F -:151E4500A4A9E2B3B8A291C80FBCCAE64201E554E8D13CED0713 -:151E5A00FF15E847FFD5CFFCD7BE8523AA67B4EB5E466F5CEA4B -:151E6F00A49571CE7B38A67B301E13F082484C972B13AC7D8726 -:151E8400C801D584B1ECDA30C8F6D1BE85361EFAC411194EB76D -:151E99006F6E6830687DCBED46FA7D1A3FFDFD997CEC7DE0FFB5 -:151EAE003DBAE0875E831F80CB601F91173B4D07DF4FDF9375AB -:151EC3002604ED1501BE8B47F83C5FC44F203B2E1F9E4F922D53 -:151ED80047B9EBD5ACFD0B186FC88303FA1AD73F43C9237B8A4E -:151EED00F95C4DFF25C07BC351D5E5116B64C0D3C5421DCF3873 -:151F0200CFC2F2B64D3C470A7DCC3231BFAB653A12D7FF14CA3C -:151F17002CDE19DF507FD7261607B33C8E7A51EF7BB67AD5C94A -:151F2C00D7F7C04F47786213DBD3D0314F00DB82F349E4A3F77A -:151F4100A598EA1DE5FC20DCA2DB2AF09DCC4377C446779BA8EC -:151F5600F7B6ADDE7AA08BF5466DF5DA44BD9FE4E16F7DF2845B -:151F6B008EE3EA1CE3F16F74F403B5789E06F83BCC746798AD4C -:151F800015F7FE1DF04A0619AFB5365EDB05EEF7F3F03A6EE3A1 -:151F95006197A8F78F7978BD60ABB75BD4FBD7AFE035BA39C326 -:151FAA006BFDD7F05A6FE33529700F6C9ECE6B7C7386875F8943 -:151FBF007A439BAFD19F9B33FD59738DFEACB1D1BD68F5671EA7 -:151FD400BA2336BA13567F5E836E77038EAFB328031AB6D3C5F7 -:151FE900F68AFB3F106EE9FC7EA87F84C4D23ADFE0E43A7FD59C -:151FFE00C1755E6FC8D00E3B39ED8E86AFA00D741B045D8B5E7B -:1520130083AD9D0D02474F7E1C14C7ACB516ADE6DA3C3C4FF630 -:152028005AC6DEB1F18CE771E5E394F92FBCB7473E4D31CE73E4 -:15203D00157569FB206E94C197C9F5EF6A0B8C33DA41DCA3B7F4 -:15205200D9A01F40BBF2D91EEB3B9F23A61ED18755D417BEF704 -:15206700774085F9EA1E9C9FAE67B832BEE12EC055007E216DFF -:15207C005743C3AA6B438CD954664F2D7FA1A33D8D317B2AD7C5 -:1520910001FF60471DB6F7ACF61663BE4EBFEA5848B514E65951 -:1520A600E0BAEF659EFBC57D5382D3A7C29E86FB786C07BE8FF4 -:1520BB00B765909DE791C3BA46D12F4586C12FBDADB9A2670C99 -:1520D000F44D79FDC98F32F33B9ECFD0A9F970BB1AD712C4FFBC -:1520E500A9546A5EEE5C8FAF47B2FD70B3640AECAB1BC656B88C -:1520FA00D4A0A18E36B4C5AE426E93252BCEC6F32DBF4BA57368 -:15210F003F9529969F39DF9E372855F27B70545B3DBC8028B73B -:152124001EFA84C30A9EA11AA188E7093C4355E6C0DBD558FC4D -:15213900EB284E3462F92DA141ED96D0DBA8336615D6C19800DF -:15214E00F3A901EEDB1A3333FFDFD618ECCF6218A3101F4D680E -:15216300FCFBB7D1A77B0B3C1DDA7BBFCDF0E49F6271928DA775 -:152178008451454EAEF1298E80451BEF02BA83D18C52ACEFBB81 -:15218D00F50B33FDBEEE8B349DE492936B0BD2795F309F147980 -:1521A200F8C8D7FC5B3127A28F9AEC2C5729CB19BA17C5217371 -:1521B7005CBC6E9CA2FCC12D9AB2BC17FAFA347CD36B4ACA69E7 -:1521CC00B3D1164F5E7C84906714E79AB30E316FCD43E7218C26 -:1521E1005DF2E2F69B4EF94DC07DD620B4CF94A2EF9A986F8196 -:1521F600EB9F69DF8DF38A42317E11EFB7C57D14A20CFFE7B9AD -:15220B00EF83E596A21E4DCC40BE127482E78C5397E0CF65E79A -:1522200003FA1BF945BCBE6082E51BB1BC0FF9A4897CC83F5F73 -:152235008EBC73DD13EBF1150319FD463C138F703CFE298E9FB9 -:15224A00E34D30F9CCFF791775C01C0EEFAFE823C32A9EA3C3D2 -:15225F0098977F9330B14ED63800FCC707ECF7C9F07623FEC926 -:152274004778FB389D78161D6B4D00EB323926B91C6FD9DA6987 -:15228900E23D116C4E63A7993E5F1B32382F1586CCE4526BF06A -:15229E009C8480E112F9A00C1E1EA44F2DC5D8F518CB47B4F334 -:1522B300E07D6D39B5F71DD431257908F7E6A9A5272CC606DB7A -:1522C8007A9874AAECDEA8B0C1E4827C61B904EDA515BA819379 -:1522DD00E4C2A24E8D1EB8533B7F21E526E3036CFEEDC53E92E8 -:1522F2004F6992F22EF545F8F9796BEEB2A070FAFCA9A36E8876 -:15230700CDE7B2E650E327CD7B6F740E15FE4BD3D229CC23ECDB -:15231C0077F2F969B64E711D425E4A845C589F04A33C7F4D1EC1 -:1523310030713E8DFE0CF5097580C94AE773E9A35FA6E6D8F47E -:15234600384B9F59DE7800C63E9D30E6F9028DB87EE2519697DC -:15235B007F88FE14E6E9CF287706AFC098BC2BE965E7B07B1FA4 -:15237000E5F4E38FE2251B0798DE610E97809B083F27E6B551F3 -:152385005137915357C04D841F15E3DDC2FF9EF8E67CCE37023B -:15239A006E22BC55E03F27EA2673EA0AB889F0B502FF3281BF77 -:1523AF0053D4C57AF8BED8666FBA6D65F88E67DBF04C9B0BF426 -:1523C400A8107C95A40C98282F49DEAFA19F092883788676EE70 -:1523D900DC505F9504F3D3F91D135A9132642ED22FADF5557FB6 -:1523EE00A64991D3E66B51E71617CFFB9C373332638D14993002 -:152403002D9D9D09B62D7915D7D13263E0FBE02325766E884EE9 -:152418001B8F627CA5ED0AE2900F0E68BD85832AF23677ABDF7C -:15242D00B4C633D301B409101B3892EFB2FD46FEFD88993B9E8E -:1524420079FE24D08431631F272FDDDCA925FE89AFF3C9C2A6AC -:152457007DDD38D98BB9A2D618E91960392BB2F0A7385696619D -:15246C006E00C41A8FB1B5F7CCDED306C51910E7A9FEF0FD47F0 -:15248100DB78AA2DF83FB0D139F1445819A04E4F17936729E02E -:15249600ABFF2CE377E9E7397E1778C13A44EEC03326265B170D -:1524AB00298E373A0FC6B43ED015796D8CDFCF00B8703D05C6F8 -:1524C000E33C764700F8662CC77BC33087D8F2BFB8BFAA46965F -:1524D500D2420FDEBDD7618CFF3A435BCE1387B8224097AF4988 -:1524EA0098D85F7DE0F7E5B303C6154113FB378B2694BB7268E4 -:1524FF0066B7BFA4B1C1463F6CA3AFE4A12FD9E82FCE43DF7F80 -:1525140083F431BEE8AC0C18162FC8C3D825CEC362A0954B5FF5 -:152529003E3BC46829910103EF4082B9B789B18FA4F03B8F16DC -:15253E004706E861887BD0A74DD9E31C5C7393FD66679DA1E108 -:152553005D60532FFAABD87E5FC96D2BFC75CD41E54F2A2AB7BB -:152568002A0FFEF1A60794CDDFDBD9DEF2EC4E6553CBB696A616 -:15257D009D2D41A5FAF107B7EF686968DDFEDDEFB4B63F5EBE5C -:15259200F2EE9501A5E4999DAD4FEFD8B1FDB9C79B9E6F0AADAF -:1525A7005A55B9EAEE157F7497F2D4D3DB5A762A81CAB255156B -:1525BC006595ABE125581E0896DFADF8D3FB5B16BDB2B2E696EB -:1525D100B6EDED654F6E7FB6ADACA9B9A96DE70B65CF363DFDA7 -:1525E6005CD9CE1D4F96B5EC6C2B7BEA85B2A6A66D0CB66DFB24 -:1525FB00F6B6953B6F5B758F72A7D2D2FC74BBD2DCF254D3775B -:15261000B7B52B4FB6363DF79D16A564577BCBAEF61548E5FA76 -:15262500F037EF78FAF9961D654F41B31E6F6A7FF6F1E61DCF95 -:15263A00AF7CF2B67B2AAE853F8D9E9D679AE30B37EE67F71A4D -:15264F00F88DB9BE8AC612A59CAEC4B35CD6398D88B406EFD1B8 -:1526640038143AD25640FA8DC6DFA7D2E7341A958DE627BF703B -:15267900AC91E48735BF526DF861EC7D0CB6C40BCF37D176E26F -:15268E003E09DD6FB47E9172FF74A9146C50866829942D22C3C6 -:1526A3005521A587B2F2B0B4370030B4376B6D30AC27830F04B5 -:1526B8009C66B752B4CEF2090BC036CE203C96C0FF5701F73E78 -:1526CD00F9E5368C13CFFD756A16F2653FD7603FD310BDC2F71F -:1526E200CABA58FD12A31FEA13F9B2E9856FCE027D3B4FB48D99 -:1526F700B0B3D32B1D642EF2877C78959314DB3003E6A998E3FD -:15270C0046C657E03EA9D7577DA7866DEF02393A7F52A9E1B5D5 -:152721006A7EC0C5D7AB0E1961E58746CD08D08678CA0BDF5BC8 -:1527360074F01C97B77A850630D34EF3A1548AD1EC62FD72CC9E -:15274B003C9D4ACDC1FBC4F8BA738F7113F805C439F916AEE733 -:152760000700768CF1E5047F7908F90AEFC775B9F956BF5967CC -:152775006CA2BFC3BEBBCCFA0EF7571405C69DDC957029F7980F -:15278A00CEEAE3D0DF07186E1C8738068B94D7CCD22F1D6BED4A -:15279F00EBBF28734BDEF67EA87927E5FAAAF2D27752B3ECFD49 -:1527B40081FCC8C08FD7D65F6D1197114DFEEC556C93121D4848 -:1527C900CCC13BE7E8622314ED4890E2B6464F926CF14697828B -:1527DE003F3EC7EEC3F3F96AA1ED0F18787F29CE1DDF9470BE3A -:1527F300A41A18D348EF3FA3E11D51F5B8CF12C6B3DB611693D4 -:15280800F6EA41D50C55AEDBA414ACFBD079D1F0856E67EB8DA0 -:15281D00462235EB23B12F128AF6D09BB2F4A01EF3BFE763BD01 -:1528320066A8773ABDAF1231F07EEE40B49A12F915EA666D83D9 -:15284700793795F63ADCEB35DC4767F617BEDFE3C0F58C8BFC2C -:15285C00CEAAE601889DCB204E78925E29242ECFD880F69872A0 -:152871007370AE72F3AA3796CE0FBEBAECD6E018C091DED4894A -:15288600D4AC658A23C8F8917B0C5C7376C1383C0F7A9FDE0F44 -:15289B001B3FC6FDF1F831F32F1696A86C7D186CE4D142116F97 -:1528B000290EB6761A075C565DAB5E3BD4395837A0E29DA7C812 -:1528C5002FAEE7E6D2C2F18BDFB7C2F7EF39385FB8A679E10D71 -:1528DA001C3F7BE9E2A241CDFBDF47282A4A6D14CFB45F64E72D -:1528EF00E7CCD0EB6A1FE05D5454AADD8577C28E47D55272D174 -:15290400E80C9D68C33D2E05FBA96E8566429FA0AE38770F1B8D -:15291900B8B71FC4F58EF08F791F88B18B31B4C4E6610AF015FA -:15292E006A64FC877F6C8E4DA5DCA70B783BD7439FAECDD37719 -:15294300308F9E9FDBA6DEA914CBE9403CEDE2FB4530C69CE3B3 -:152958003A8C83FD4601CC4B42C923863196725BDFCE80B1811F -:15296D0036F0AC903BEEA7A22CC22007AB4E3F94B1F7F1970D63 -:15298200CCA762FB8F50A7F48D6CD95F0539E6E315C7ED82680B -:1529970007F57FCE653E359CFD1D933FEA33B305FB0D4BD6BDC7 -:1529AC0020EBDAE88079F5B8F0F9F676A34E8A761FFD0D6F378E -:1529C100F63DE2DB05F84A599F458C5D2C6E133AFA2BAEA378CF -:1529D6007EDA51F780867B86DFB2F450F40997670657E8379C5D -:1529EB00E736D00DE083E9C6A2A2B59AEF178EA0A523783CBFC9 -:152A00008DEFB30A1D39A3625CB78C9C5987FAE1AD4C30BD3021 -:152A1500F565AAEBFD214D025BBB4CE8035F0FC8EEFF1190B788 -:152A2A004F3EC6E29DD9A01F5EB0BF577E2DE46E8D0BDB37B8AA -:152A3F00679D4FEE2B717C437D94FD343A30AE7A218EAC17FDA3 -:152A54003EC3A623EDA023AD1F701D71809C25A123E597B99C53 -:152A690059EE01F6FFF14C3F223E4FB84D6BFDB7B672B0676627 -:152A7E0049B4CEF447FFA7BDEF8F8EE2B8F3AC1EF54833D22015 -:152A93005AC3CC20B0905A443892A33833625024598481B05E2D -:152AA8009910769673B2DD92B0C7B1BD109B64B93B6E1FEF85E7 -:152ABD00C42318890137B8E913589615337224AF7C0B398507C9 -:152AD200397C4F24E2C239B021DC2C211C9764F1388FD8BAACE3 -:152AE700CF283E62E3C466EEFBA9EE1E8D846CECDDBDF7EE8F21 -:152AFC009B7EF3BAEBF7B7BEDF6F557DABEA5BDF5A69AC4D3DC0 -:152B110064AC4ED519D4075AF65353DC2E34E6371EB9869F2B10 -:152B26000ACEB2EE45FDB55654BA5B0DDE817DA2914EC869824F -:152B3B007B50C5FAD98475AE1E32F7037C3D69949F0DE4EB5DA3 -:152B5000B09131CED8A10527686E3ACCD7BEA454B701BDC4D514 -:152B6500A9935CDE8BA786C193F324B9DB582D9F34747AFBF5F8 -:152B7A0011F5B46C86B3EA61EDEA07C8832E36E6FE07F17305BB -:152B8F005F77BC253C273C2C7C56F00937D8AFD97F633F64DFE9 -:152BA40063C3EC5966B0DD6C07DBCEFE9A6D618FB38DEC61F62A -:152BB90020EB600AFB125BCFFE8C7D917D81B5B17BD96AB68A61 -:152BCE00AD642BD8729A41B6B066D6C41AD93216664B59030BD8 -:152BE300B120FB0CBB9B7D9AD5D3F3297617ABA3A7967D929E0F -:152BF8003BD9127A6AE8F9043D8BE9A9A647A6A78A3F95F42CC7 -:152C0D00E24F057FEEE0CF42EB59C09F72EB999F7B02D6E3CFE1 -:152C22003DBEBC675EDEE39DF694CD78A45B9EB9B73CA5B33E15 -:152C3700733EF0F17CE85372DBA7F8233FEEDB3E2E6E3B338E52 -:152C4C00F3B1C15A4DE6674B4856A96CEA8C32F928FC6AC84FD6 -:152C6100B7BE6BE93B6D7DD7D3B724D037FA96CA5A8A1FD17442 -:152C7600D6A6A569522C098A26C98B8F4A31FAA7E89F597C1419 -:152C8B00E598B6496BB90D3659B6FCDC969F407E31CBAFD8F202 -:152CA00073905FCAF22BB1FC0AC80FF95199FC2CAAC4A2412BC1 -:152CB5002FE8F906AD3CA0D71BB4D2428F374869A202F66465D7 -:152CCA002D880E49BE4BA3D975BF93E469F845B99D8790EE4D6B -:152CDF00090DAE3375D4FEABFB5D679A558E9F0F091BFD90302C -:152CF4006E7F87C24A298CFC0DF88B679B555E76BACEB07167CF -:152D0900E31CF5485B30EA2F719AE8329F770775CCF318EAC994 -:152D1E00D3043B815FE0507298F1E3A7AC70EA135BE5C5866EE7 -:152D3300E593FA2FA67F94E245D15F4A8B0DD105BBA3B3BFA3AF -:152D4800C2549C74DEB7E498FAD62D7F8EFFF1EC5CE82698E770 -:152D5D00F7656DD2B4C76AEA6D705D4699EB74145ADFFC9CB4E6 -:152D720083788DD11C34D8447DA783251C4D4611ECA1469AD5B9 -:152D8700C9EA66BE1E37F943E732E0046EAC898E533A0F6B8218 -:152D9C004EB4514FB8A08E5673C90D4611BB8B60BFCB700622DC -:152DB1009DE959FC24C1F463F25B06FADADA996B124159E77EE0 -:152DC600E0EF029CCB151A44A29914EF6A10313F96AAF537A019 -:152DDB003B2F85A8C826BD9EAF3BC17E6C33D7C9803BEA28A727 -:152DF00032EA74942F9E2957A5785D186F57BCAE01EF28EA9AFF -:152E05000E72191A71391FC3DE6230A8C5799B68D2225CD728D1 -:152E1A0002FF58766E1BC58972FB879095CD33CF312DC2F5F20E -:152E2F0037F133A82CB8C53C03CDB659F714242D5D08ACEBCEA1 -:152E440025A012345F49E83A4B28D8DF81FBAD15E23296DEA113 -:152E59007B64B1814577C2AE9C8BA565DDB4FF6AEA31D5670A9B -:152E6E001A789E941F5F47C277B4574F2E882B42AA17DF464EDC -:152E8300CF23FA5FFB50BF0AF9A02ECA670DA62768DE242EFB76 -:152E9800EE83DFA5FC5FEE833FFCEAC9AF7F865F39F9F5CCF080 -:152EAD00DBBA82E0925EEBFBFA83AF874860D63CF2157D1B3BFC -:152EC200A355AC7C5D6DAF7A25F46CD3045FB75814BF44F57999 -:152ED7004A5BB4F2BCEABA4FE336CACB2DBBF3934F88CBC4D496 -:152EEC0090EEA0F15196BFDFC7F4EB862B69DAE3E476D4C70FBC -:152F01003406307FA2F298FEB7C61DC2EB2AF051CC5E098D3CFA -:152F1600F86623C142B4BD42F09DD7056D9FFAEC86D7B43B22A6 -:152F2B005486B4CF20DCC56FAE581D72ED46F93B47D94821CDB2 -:152F4000E3BE33EA725DA3F05DFDAEB6D7C9FFE97ED3FD3796FB -:152F5500FB3FF59FC966FD7DF679C0E8CFFB128E333AF0B68DCF -:152F6A008D6BF11F14367CEB5B850DD07FE84F3FAB2CBCF0B4B0 -:152F7F005270FEA2BA865D0A2D1C3FA9422748F8C900F4F5CCDC -:152F94003A120D70EED52FFD07F5FA43578C85C2CB14E792E1D4 -:152FA9008A1F69C4BC15F94F3E745E77A50A1B469F285CC6F5AF -:152FBE00645FE26BDE47138E14D1FAB88E7AFCE1507738708AB3 -:152FD300F2977EA3A12E12608EFE68D485FD1069D75189C3FEC9 -:152FE800E3A3AF513B2C96F726B3244F16C9DDF1FD714D11D6BF -:152FFD0069D44E7FAEC36E288D00EC2917F610B4E464F5EF0D02 -:153012008ABBE74DB97E5994E26F8FAD6EE0EBAF05E6594D31D5 -:15302700F56DEA279D0DB1F1C30D4C3FAE4F82FFB0BE47E1EB7B -:15303C00C95F4C1D211EEAE6F6486A2D7B41BCBDE97BB9DDF0EB -:153051005ADED648AE4DEDA5B616D744A2ABC4B430DE2EA635C4 -:15306600E08D3D3257EA00EC1D733BA2E5A9842EB85EC63C93F4 -:15307B00DB0B052FA28DB8CE216CC88842EE4E258CBBE21AF7B7 -:153090007FEF27541EB921134ED2D4D013131BCA486E445B997A -:1530A500AC1E321606529D63379DCB0897C6E9F7B22E89E06916 -:1530BA00A5322EA16D05FB349DFAE156CA97A5068C8BBC7E4946 -:1530CF009DDAA91424C0DEEED6C24C3F053BDAA3E82F7747CE85 -:1530E4002BBF7EB4B0A18F752B7DF1034AE91271595F64AF3217 -:1530F9003FD1ABEEDFA929FB9B2F73D952CA1CEC5BB3A4F2B3DC -:15310E007C8F28181FC5DA6BD9A204F600F58A14AF8FB986EDC6 -:1531230032EDF5E3BB4D24193AF39A2EB411EFEAA78DFDE39A1A -:1531380082F541576A80D2ED028EF95E5E79E6A0519179CEA8B5 -:15314D0025BC54503D338524165038DA67ADBC8BDB6EE1794811 -:153162009A7191E6A1E5F2533AB7B1B841D3289D8EBE418C1DA2 -:15317700D3C3991F50DC5DD4467A699C1B509167762EF4786000 -:15318C004B80BAFC7327D583F15EC5BBB257756843AA6B7CB87A -:1531A10011E7E87DA78E98F6BC4F33B6003A00D029A39FB8AE2A -:1531B60047A57AF73BD6ED53134579776CA4B1D69FD4BEF10F46 -:1531CB00E28F0F0A9C667C0FC4977981EB03F25B806033057EB2 -:1531E0002CC1F5B78013733F24C9F7438CF15EA53CD3D317CC90 -:1531F500BC9092566ABC0F2958ABA9A2AC191E17F6B807B4DAA8 -:15320A00C881469CF3F277116FD1BCB63C0EF7712360B985B33F -:15321F0003AA392E1C307C194F03FCB0B6EFCAED8FF4F13D009A -:15323400077097EED56B389DCCF3C9021BD1A0476D9E4B1EE5BE -:153249007DE9AF282F612DFAB214A7AF903CA20616751B4F47B0 -:15325E00CC73AC584B17BEA071BBBA12A7B3693B5AE23CFF9D4E -:15327300A35761D392EA8DF56831437D5BFA3AA7435946C4B92C -:15328800E57980A79CDB5F4A76DA773430FD4903F6C100A7902A -:15329D00F986569B9917CAEFFBD1E783BEBCDFCFF5F9D4FF6FB5 -:1532B2002A6CF765DEC638C06DAB48991EE3B1F7B37EDFFBE0EC -:1532C700779306C0B12FB34F7768BD6A598BB9E7EFA07E03F7AF -:1532DC00DE7858EF520FF1D042D61B02FDCE7D798A77CF59B649 -:1532F1007F2F73DDAF894ECE7B4437B845BEDF11E7FB58A037C4 -:15330600E8CB6D5EA19D133D67D292E3DEA2C3ED70FB9169045F -:15331B001AE4E3DEA6C7C7A04131A7419FB5CF33458BDBD220BD -:153330006FECB5F11F1B87BDB4D2603E2DBCB14F86605F8345EF -:15334500BB466F3CF1C946295644E36C972E901FFAB1CDDF28C2 -:15335A006C38F147FB3CA0D99F9413ADBC8B3443A03A8176A8A8 -:15336F00A3B9E7639681F290B77DBE7D4A7E32E9B1208F16DB67 -:15338400393C49D3EE0E85635F51CAEC3304EBBE1BB8953CFDD8 -:15339900E3AD79E9B77E39A7E7CBF583FBD830D7DBDC049A7748 -:1533AE000D2B1ED9C9FBE92D5C0F50D31744CCBE29D7EEA8CE2A -:1533C300C2268CCBF4BEEF3CC701B553DFB63F98F5CDCCB8F661 -:1533D8000BF6DCCB03C9CE052413C82C7534C8C68F4658E668BC -:1533ED00F93F66DDF41E25F728F98F3659E93F28BE32313DBE77 -:15340200CB8A8F717EE0EDBC32B1DF48F391FCB4A80F9F7B51F9 -:153417007D6E92FCD28AF573792CFED499934A2189F6A2DC9BBD -:15342C00849D9A62F97412679ECDFDA0717EE651928FD13C2606 -:15344100A17B324B1A4E1FC8BA81878167B3EE9979E6C3C6F7CB -:1534560031296DABFC8C7EFD558D64259C19485A7CF8EF0DCEEC -:15346B00BB416EB37E723FC98F0D241F7D1CDE9C7CB5574F3836 -:15348000481E1D11DB275FD58C84A3CF6895F71B6FDF44FB88C7 -:153495005B73952EE32A6422A23FF657652A231F2737AE4CC7E0 -:1534AA0027F6772DF9D6D47FD60774C8D202B52FD491DC46F8DA -:1534BF00DF91FC188C72BBDF763E727A2A1FDFEFB3AE0A9CED31 -:1534D4000994C32EB47E91CADC06BBF91968DC46344FA6562FE1 -:1534E9003C15527F10AF0B753735F13EAB88D1DC287D9F562434 -:1534FE003C4C7DCB9A19B2A6639928DFA7CB99681FEC1CBB5C2A -:15351300D514DE66C9998B1B8B694EE3A8547859B08B0879DDE3 -:15352800D915524B23A17031953D54754F634546A631B3562FB7 -:15353D00CF0475C1D3A2767F3BA439C769FE986E326C7BD4D0FD -:1535520001E132BFD445F2674D4874134CD1AF8C32FDA17E5706 -:1535670012FB88FF9ABF332B1CCB6ED5BF29B7F4306AAD7E2D55 -:15357C0048FD5A9302B9DF2B0B413E9709364DD94049BF30BA8B -:15359100607C405D60DD59E0A3711C63314BBF64940957D55FDC -:1535A60057977E96914CCED88426B1DF34FA846B6A69B5B301F8 -:1535BB0072648464F60A6158D593DD4A39E618D46FA29F14DD49 -:1535D000AF73FB344CDA31FA00FBEF212ECBC1760CB91792FC9F -:1535E5008DB7FD5F2817B5E7DC83669A8FF23F9CCD06642ABF7B -:1535FA00D1CA9FDBF69F257FFB1F4F4DE57DA7FCA73C0DEC3F98 -:15360F0049B566F92E8259B6E250BF1E58287F32945F1FF84BF5 -:15362400DC864D11CDA95ED259E685A33E6AE7C998735945E6DD -:15363900A08EFE14BC8A7DF5329219DA16F42E8D903C8631F194 -:15364E004B4E9DCB608DCF68215BEEDAF47EF603E52ECFBBD91D -:153663000F94BB9A6691BB1CE78EA890BD206FD9F2574EEE8AAB -:153678000C37E28CBB6F25CEBABFAE35DD9CDE1FF23E9368DB97 -:15368D0056FD686331D7C99ED03CEC64A3EFD4FF22584E6A8B1D -:1536A200334B7278704D38DB6D3CC006D104E1E9DECC1C93BEB6 -:1536B700382B6386EB62F2B87A37A1A1006E2B0C7E080B4085CD -:1536CC006486DF091AAF3E088F243B841D6DD7D41BEF645DC0D6 -:1536E1002770566FE1B0E63D138715B3E010694EBFF32F8B4708 -:1536F6003FE457C2E3A2C089CECBC063747F5FECF733AE95B49A -:15370B007065F3FFEDDCF2CCF4D103FA1AD6A7DD4FF39DEFFF58 -:15372000AC77A92C9F1AA5514CF30A24A74A970C9FD54E45E8FD -:153735005348BF34B6B1CB5A99F0867AC7CA6BEA216A87341F91 -:15374A006FC01AB85466A898FBB2F401CD357E90DE07B53B5395 -:15375F00628397E6805EF6BAEA3D754515F8BD15A3DCBE14B79D -:15377400AFF4438C1B716D60FC07E13B28DE1D142F30DE13B21D -:153789006D3F4994066D54A638B63F6C3FC11FEDAB32736F4889 -:15379E009A28E434E736A7CE5EE16D0AF76905327786A6EC5777 -:1537B3005DE1FD43F0D5D2507EF9F2AB81696EE9D5CA696EE8E9 -:1537C8005BCDA7B2E673B8BAF3E03A990757771E5C272DB8FEA1 -:1537DD0084E072E6C175320FAE25A19976B582164FE7E0CAF8FC -:1537F200A7C3955934CD0D9EA9A0B1B531833E90DF11C9F8DC00 -:153807004700EF8C111DC61AE711CFCC3F457C263F63283769B9 -:15381C009E9E7E5E0F73FB865D7DF192443BDCDBF85D55C7FA7E -:15383100A00F5570866091BBFA1DE7BECD797284AFDD3CAF0766 -:15384600E5471BCDB897B5EB2B8A96791E7885E629BFD45DF29A -:15385B00F7FAEBE5FF61C47F37939F7A463DD07F4CADD7CC6F34 -:15387000CCF37B46275698F98C52BE3E2BCF1B2B3636DECDFE86 -:15388500A681CFD3F3E2222DF2C84F778EE2EC78F2921294FFC4 -:15389A006229FC21BFD134EECFF0FD0C64B8684F0AF323A42D33 -:1538AF00C6990FE25D9C27ACD8FF3CE763F4AFA2957FE9B4EFA6 -:1538C400F92187F9DD572CCF0DD15B7770BD769DE7EF786E8FEB -:1538D900CA714CF3761FC9FF46E405458A24D472C23F3FDF2953 -:1538EE009936FF6FF72799272924D7ABD85767D24E2E1749FE99 -:15390300B862CB455C4642D8C7908F6CD9C8929366958F201BEC -:1539180041460A731B30391947D3CF99328E598ECCCAE5DF195D -:15392D00F320EB92DCE492771B23D7B2AEE294962C26B8C3914D -:153942004483BD76514E7216E224AF8166DD3AAB15DBB75F33B8 -:15395700E5AEF11FF3701DE141C20FD2B3D4555D583041E3BBD3 -:15396C00466D21A915A612712F9523A58EF5A19F04DF214FCC1D -:15398100DFC17FB5F2ABFDE6BC7E265FF7F2FE653EC9C5DE53D5 -:153996007B492619D3C08315046BEB1FF3E55FAB8E54B7792958 -:1539AB00677BE6CDACBF96E4DD6DBF356556BE1741F09D79D3A5 -:1539C0004C531630CF6FB9ACFDDFD1F9CC4D7329F7C83CD38DB4 -:1539D500F3A3DB1DCC7D86FEE6FCB0D6B28F62EA383953423B4C -:1539EA00F33569F6D962CF4F894F4E35ABAB683EE6EC1A547BD6 -:1539FF00D3834AA5EC6C59287FFA73580BE669A43A35771E3916 -:153A14005A4D7C24F488B16ADD29615D59E879E3505D985DEFCD -:153A2900D2B6FC149750CD9C0F4D2F7F55BC6EE93FAB9C5BF459 -:153A3E00C7829D35F35989242D56A12F0E5D0DD843724A7FCB73 -:153A5300F57BEF4ABDDF0ADDBFC03743E8C3B84E1FB761111D23 -:153A680036D6523CBB3CF8B7927BEACE013E472F96024D9DA766 -:153A7D0003B0AF54DBF95E00F936987A72E5ACC4131BA4B1734E -:153A9200897AA72C34632FD513AB366E90BFF8CD2EDDD4AB1599 -:153AA7007B2E5AF32BA7B443FD1585C13E682FE250BDB0372D1B -:153ABC0043F78FFCC4D8A031067FFA7EA390B92F5BE98AC87D98 -:153AD10095FCF11E221AC35ED698C33CB3DB0B9AFB26614796E4 -:153AE600158DC02EE7354DBAF08C02BDEC729C75938E692ECFE7 -:153AFB0011751DD1769E2CB6176506349CF3A8A07E349041FC40 -:153B1000BD3B30C60996EDC0BB52AD4B258F797608B675E6F2B3 -:153B25003C87FB711F93CB8CE32B4F894B85915BD3B26811D7DC -:153B3A00D7D6096F61BF797616FA59B09B0A3D948C1F77C324AA -:153B4F0072F73188F2756333D14D24BC78A82DC7E89BCDB21F0F -:153B64001B8CB9B458E6C747C52B5DEA7B3E3BDF8A5CBE492BCA -:153B7900DF98653B7B0FF52D63458C9F1966E9B8C1F793A4B0E2 -:153B8E00265436758A995AC395811FD12AD3C4CB2FCF4C92FB54 -:153BA3004CA79449519EB14EACB3EF59B049E17D5BE596CE8A23 -:153BB8000C6C185CEE14E5AF196301933F6A284D6D26DD5F4F2A -:153BCD00E9C3945FEB3CE60E527A13B63FE9036CB0B3BC0A7361 -:153BE20028669F5B8E744632EF187B16449508CF53E98C929B8F -:153BF700E21F5D4DEF18E55D4873DAFB33878C48E6E9BEB68CD8 -:153C0C00DE1FA537F6A8A3F43D4EE10A9595F65AB6C4598AE365 -:153C210000F64B61F3B13393321EA17C63049B0FFC4AB8AAA7B5 -:153C3600B78BDEB0D12B5378057DAFA63C7CF4AEA1F9DA26FA1D -:153C4B009E9807DE265C915F1BF989D4D75C24BF60C0A4476CD9 -:153C6000864D72E795B84A7C57E295C5E50579F412008F3C64E5 -:153C7500604D35280F515F3764CC464FF33C53588B3A58C9DDD8 -:153C8A00A987C2683785CDB216E53AAD757A39BF43A8CB30756C -:153C9F001D841E3B8F149559D537C8CFB5080BE2EA947DA00895 -:153CB400C50B6B8CF2EB015E7CB5B9BE6DE2EF3106D6A9B8178D -:153CC90061B1DCBE946DFD5DB7F21BC6EC7CD8D62E2DF8736B0E -:153CDE00FF6BEBA0B685BE7B6467BB2B074FB3BE10E310C27EAD -:153CF30063EAC9D7DBFD13F9457F0E5DD365CB5D046B8C997058 -:153D0800DBF4E6772A5AE9026CF972B6B599E76FEB8B230DE54F -:153D1D005552CA5A7918F22A0ADC8A2FB46F9F30759E439A7424 -:153D3200501D4772753C7701753CA2AE8149D46F0EEB9317007C -:153D4700306C5F99FB57F2CF281AFD23F48FD23F46FF2DF48FD5 -:153D5C00D35FA77F8AFEA3F41FFF9919976DED36EB6A9EF9E018 -:153D71006E7D867B74863B3DC33D39C32DBD36DD1D9CE18ECEF0 -:153D8600706F99E1D667B8475FCB3B9342F86913A6DBB78880A5 -:153D9B0076BED19C5DB049AA97BFEBB85ACACF365BF9548E74A6 -:153DB000626D684D6C43D87F7258AFBD083A4DE14D21F726FA49 -:153DC5006FA37F92FE7DF41FA1FF09FA9FA1FF65FA4FD0FFC613 -:153DDA0045332E3B36CCF196B2E94F6EE04DCF73036FF13C37CD -:153DEF00F0B625CF0DBCC5F2DCC05B34CF0DBC45F2DCC05B3084 -:153E0400CF0DBCC9F9E5BF36657F93974F6E7F73CA006F433FFD -:153E19005A7C62C33DB67D048EB3D9EC7F107E3D2C0FBF33E3C5 -:153E2E00FC33C3D1F78C91FC42B2947E7A0E734357B658165B92 -:153E4300FA04E676D137F5332D1E1A238BE5459FBD48E36205B5 -:153E58007D838EA2B44BDD5C467DD65C56F218AB6989CC35FBFF -:153E6D00B407E83B3CD7ECCB2A59CD725BFF49869D72DCFB4582 -:153E820079006793A5347E53FA8952C80E2F4ED9E92019F152A8 -:153E970055178DCB872123E8932B9CCB4F531CB96CF6F1C91EC9 -:153EAC00E7B0378FF1689299363AEC781E2A77A7659780E49DE9 -:153EC100E597292F3797F7A7F7631504EF7609E321E48BDDFA81 -:153ED6009E18CEA5BDA8EF881CE6F5777FC6D92EC9753AFA7C2A -:153EEB009C112A5B79006BB9DA9639D89F1AD499FEA2EE178621 -:153F0000D516D6CDE377BB87156141138DAD83460DD54D243929 -:153F150097DB268FEED52ECEC538A6774A65499EC7988764486F -:153F2A004AE3925FD4451A8BDDA558571EA4BEFC450378AE91FA -:153F3F004CF903B0A63DD3E5BB9139ACE434E5979A8371A6469B -:153F54004FF0B1A9968F4D380F2B2C08727B0A976F66DDC5F1B1 -:153F6900AE1667B45695E56AFD8D15C2F2CD94E6CC5C5326B23D -:153F7E00F1E0B5740FA7F477653D4EBC29A57772BB7EC85FBA96 -:153F9300F02905E78C00B33732B854245945A43C2729CF769297 -:153FA800A9708E49E4BAD87C1C862D490379A0BD8BB161C323AE -:153FBD009BF7BA66B91EFF8B9A9FFA7C51FE9E81F8B8FB976419 -:153FD200B00D1305243FE3CEC7BCFBA71294C7DFC588F762B02A -:153FE700B561DA75FFCF6CB0C5436E8C33C065A498B9DF269E84 -:153FFC007D8B75B5D8B09B3819E17D13F2E0677ED892161BEE59 -:15401100EB0437F45D890E25B02303DE100907176F64DDF6BD19 -:1540260005F9750AE4D5C91E6F502FAEB740FD1DE0728ED39C6C -:15403B00233AA6F13A4883FD34F7A07AEF9EB2731CEBD27ADD53 -:15405000CCBD8660B5D37C2ED2DD029D8B9F1CF9E5618F5C6F8D -:15406500F8B9AEB24A6D76B561C32ECA87F9BC0DDF18E3250BE4 -:15407A00476B2D386D3D4E0B977EEC15D7539837262EF7154C5C -:15408F00B50DC95DA39AF7EBF6F1F28C5343CB59380C1D8CAC5D -:1540A400B96796CD7EEB5498FC123AEE46294B3FA9965DB84765 -:1540B900914EAD542B65472BD7C94EEF864E94DB9D3F6E5A70DC -:1540CE0036B0257C5C1E7531F715AAE32F88F7D8D6E7795E88FB -:1540E300EF425F1F1EE2F7AEF0F34BADF5FCDC0EC9E1FA77E3C0 -:1540F800832D38D303FC3E8D7B0B49A6B5F0EEF5669C2DF321EE -:15410D00AF674EEAD71F7C69F92FC88D3A8B99E1D9F98D706485 -:15412200F29BC93F9ECC71FD40C6D91E681DE6E5A19D99F4946F -:15413700394EEDFE5A6C5D82B51884EB95E38361BBBE51613A5F -:15414C005F42CFE6664C6801DC36DEDE1C1FE27D8027467D8299 -:1541610055CE2F288F8F5AA7CA8C7379B0783A2FB6BD9D75AFA9 -:15417600263A7A62797591BFA7439F3257179AC398F5AFCDD556 -:15418B00057088AD9FE675E1788A0D7E209E9C528D6AAD9364C6 -:1541A000515FD7A9FD5C671573A30187D54F100EA84F77E7EEE2 -:1541B5004C487769E7FE68EB0FD7F33A411FDC4EFB08A503BD44 -:1541CA00FB284D7E3FB3ED7D935F3DF2615D8E0D695F8F0C8732 -:1541DF0050367851DA3E669E8B4C0FD37CA11BFB9D567D877409 -:1541F400BBAD88992386E41E56CBA8CF3D48732B4F06FD8A6685 -:15420900D5FFC454FD892FE6B79EE4F59F4F74B3E89B1B438A6B -:15421E00D1DFF1F6A0C1DE7FAE3DDC840D9FF0B169EDE1B7E3CD -:15423300C7B85D1FE0ACE121D35E01CA798EED6D215E36DB49B7 -:154248006BB7C9C7046B4F1C67F0F5CE03B8B3217A7206BD7508 -:15425D0093DE5563CB0D727B624379743DA623CD145D87AC7ADB -:154272002579BDD0E794B5EEE5755A98129783F76D5AE6F89743 -:15428700FCC414EE0A49E83DD4FECC7B42CC7AFC35F1A7CD8B26 -:15429C005E36D6524AE503961B04CB42E2BD6345D379EFDCFF00 -:1542B10026BE93F3E08B117CB13CF8641B3EB35FE2F86CEDE6C9 -:1542C600F0E5F70BF1EBA6CE03DE62CCBC07588F24B694E68D22 -:1542DB0039F1776D5ECACD5DBD2CDCCB710B5B2C7D93D9921C44 -:1542F000EF916CF32B9C55785EBC478A99F36F6FE4B0FA32A58C -:15430500F1578BED6517FA1487C0CAE6212C7D4C972EA414DCF3 -:15431A00F17094609530E610FF6C06AFBA20776A5A2070A253C4 -:15432F00261929FE646FFB0EF827DF411FBEC375EE24D7DB9887 -:15434400A8DABB8CA5C7742328B4239FCAC45ED89CF3CDC7FD16 -:1543590068E49FC07AB5B4D710293FECCD7337952BF23DC1BDA2 -:15436E00064F87B2F4BDD07F9E87BB95BBCC343BE234A7C7BA03 -:15438300886BAD063D0E3FD7A1B3E6F412BF4F604CDFD9A6299D -:1543980005EBAEABF16CD6DBFB794D419D454A539938B201F0C4 -:1543AD0063EC042C80CD4F75692218FC174E28F36354D7B3DF2C -:1543C20056BD4CA33E3CA57C1FE38295A77876402519D88B7446 -:1543D70076DD7B28FFE4BEE3FC1E66F00B8F1B3DB6C3B5FB1DAF -:1543EC003503D8A84EA80BBB3EA0812EC003D34F6AC06723D44E -:154401005C28DCC6C5E51C1ECCB27278C07A6DDAC443E08762E3 -:154416004B721D742486B52EF2EF457B219CC00F6B1B18834D1B -:15442B00784F120E8E28C8BF60DDEFD5ED1C0F479432AA1F70F9 -:1544400020E15C15D5DB853B83A82CD84C0E52F99581894EDBE9 -:154455001EB2699F27AEE9C4837B162495B7D884B628C8FEB2C2 -:15446A0046163F97B3D7F917DC1E32B79BD4C6D70896F49B67EE -:15447F005B933C5D24B30B7756B8E98D7D6023F6EE149FE33C0E -:1544940023D6AAC0A3F5984B439736D8A4E937B89E663F8DB948 -:1544A900E3F15A67BBE00AAB623CA40E10AC55CA28EEB9D475D6 -:1544BE00F9402B9F9F521C89FA0E8FFCC51697FCB51649FED26B -:1544D30072312A63BC1EBF4AF230DE9D984B455FE43695FDCD24 -:1544E800B261E60F9971703C4861F594BE96D2D7507AF855C8F3 -:1544FD005F6AB1F3207E6AF150B88BC2AFAEF81ACFCFC3E766D2 -:15451200BFDB61C7D9827208265FF3A499B76EC20D1C85D136AC -:1545270008CE7AF9D556B1396864281CEB05AD349F1692215583 -:15453C008A630FD88C8FFC8807FC22E58378FC7C020EA4C7CC33 -:15455100FB80D0869B9835BF06CF4B435639239DB02952CE6D45 -:154566004F987E9833C18FEB1B9A67316E992F098249CF9C3FD4 -:15457B00E55F61CF7FB85E2A95CFEF384B195BDEBD75CE659ECD -:154590007D1DD11186FE07772CF8ADFEC69FFE8EEABBF01D0521 -:1545A500F2AAAFF59879AF1085F930F767C731BE6BAFFCB680E3 -:1545BA00558C1F6FDC42E39EC79A67983AB0A69C833B095CF13E -:1545CF00234BE793ECE943BEC111138E5C3F99E4F0F9228930CA -:1545E400B76F426EE4591E196AACC8CB333777A13E97A7B7FA20 -:1545F900CFDF5AFC8C7A606E47B079AFF2359D9AA934F9E76932 -:15460E00F9FDE74F69FF384BBAC333D211BFEBB3AD27453287BE -:15462300B4FF394BFACD1F21FDB559D2856F0BEF216D6296747F -:15463800EFB1DB9737F9FE8CFD27ACEFE4F31FD6FCDF9DBEBE22 -:15464D0031335CFAC38787C76F17FE7F3BFF19E19E7CFEFFB008 -:15466200F581FF1FFE4F0A97F2F0EF9DD92FFD3F03BFC51FD198 -:154677008F971EED6B9E287359ECCBDC46536D67B7147B641541 -:15468C0035454FD9A3AA46E1B82BDA73EF6E15ED14E3A4A76CC6 -:1546A100933A67F56E55961FD7E6DCDBA5FAD6698A47A8567DC5 -:1546B600A5D56A82E416AB4D6FB84163B35456AB22BF7F6A5E9C -:1546CB0087EED314EC110BEB30778969D0A813E582F6AF539F69 -:1546E000ECF754ABC5EBEAD5E7EEAB53AAD6D52901CF236A774F -:1546F500C1A714DCC5B8488CD973151FE28BC22754BEF6B0BABF -:15470A008BF71DE843AA4A130AF413ED702F0FAF539D65712E7A -:15471F00DF553D1057F9FE1264E459605865C15042301C22180D -:15473400FC79E5A3DC4A8201F178BE947F7ED937AC7C27F3F2CE -:15474900CD665FC97A60EB20C4DAD7331640DEF18298067C644E -:15475E009999D7DD8CCD9B4FB8F15099EEB57584A36A6591A745 -:154773005EADF88CD8EE645D1D557F25B61F9A9BE034C0BA4825 -:1547880090E0C01EDC5DDC76DA14EC5EAE07833DB8F813BC6EA9 -:15479D0004D3390BA631D4DD73BF5AB56FBD2A94DAB0656FDA01 -:1547B200B0B5106CE59E6AEE1F2701D1A697BBB45EF5709876A1 -:1547C7002B8B4A13EAFE9D7B72BC003CFF219BB56060BC9EB026 -:1547DC000966EE374F3E8172D3161CB81FEC0C7DCFD54C18CA91 -:1547F100F6D5A865541EEAD66E9D4D81D226C74BD1145EAA8851 -:15480600774AD6B6AAFE75610ECFAE82DD4A31E1A5C493500B35 -:15481B0059A2638FC59B8B79DDA7CA9DA0B2740A2B237C11DDC4 -:15483000BD360CA07D55DBFD0A64A1AA75F72B33E94F8DA8AC8E -:1548450098EF1B4CB5A7AA33033C9E70BE5EF53F105345F6B844 -:15485A003A87E23E27B080D3FA36E8BB641DC149FC52521A56D0 -:15486F00B51F352B87CE362B25E7D7AA7E8DFCF6AD56B5CFAF8A -:1548840021DE5FA38007FC84D3AAB5262EC498D02EB34D9CB7E4 -:15489900494EF3398587544FAC0077EBF8DCD8ABA96CEB9C2374 -:1548AE003CAC7AC455AA67259577EF63AA67F51A756FC12A05F2 -:1548C300FA1EE2CAA9F84501F31C188F9F0899F15FFEAAEA3924 -:1548D800DDACEEDD19529C34EE96FDE811A5EA3305EDB0BDEDB4 -:1548ED008A873ADCE3CD1D07610F4D0BA955E71F528573CDAA2E -:15490200467105D7142DB6A28D07F8B9B10DB005E4EAA274A731 -:154917009A3BF85CAF89B51796053B8ACA9A3AAA92EB955DD473 -:15492C0037C8E4DF43EFBF449FF3F71B554F4FB30AB95A961F63 -:15494100866CE7F224BEAA0A6B1F5779D8CBCD141E52F712CEDB -:15495600407FF038E624C5FF5168AF3A4F38D4BA54FFF9AFAA3B -:15496B0025E776731ED84F3C3087685F1CD13AF2FB25D01DB469 -:15498000E33AF5164DC193F7122CED809FF08CBB49D7D177A2D7 -:1549950060B33287CA01FCDD3BCDEF5537B37EF44BB61B7169FF -:1549AA006CD83090C51A8EC9DB064DAD803FF47B34E79A67F3A6 -:1549BF00D5368AC3CF47100C9B67E80797FDA842A93A574EB8AA -:1549D4002D5767E3A337D9141FFD9A997C041A14131F053C9B2E -:1549E900395E9EB378097CE4D7C86F062FED8EFFF9C6E2C026AC -:1549FE00A24FAC73377B78E39C40B453F03CA6DAEE92C8C31BD2 -:154A130041A7395DEB3BD8D9F60EFB5D75CDC1EF702A8EAFEF25 -:154A280028196FEF10DC44F34F546B4EA2C34DA23DF07737A785 -:154A3D0085A3BD44DB4174788CE8B087F7E9F9B428B0689130FA -:154A5200EF8EF209AE4F50D9D10D67385DC037D10D6333E84242 -:154A670034F13E60D185FA5DEFFA3CBADC994797B7B8CEEF5418 -:154A7C00DBDE49EDBA378F4EDCFE38F100FCB75BB4BA803BFF2F -:154A91002CDA6CFA98F4B894478FBFB3E88136EDB768710B1D40 -:154AA6008836F9B4288A7C65636164FD46B68DB57BC6BFD23197 -:154ABB0047DAD451C4FECDC6E2F8BFEDF08C3FCCDD557FC5DBED -:154AD000ABD7C3C81D799CE35DDC5EAD39A8EFBD5914D58A6DA5 -:154AE500BC533B2DF1ECA4FEEF5FA9256B9F9C86F7E2D9F09E3E -:154AFA005C0C9AE7E13DC6F16ED7371FFFD4E77BEFB5F08F35C1 -:154B0F0011B4131BFFDE3CFC3BF8DA8689DF5E0BBFA5E8A7280A -:154B2400AC92E65AF96DC04EFF261F174C9A211DE8A658743081 -:154B3900711E9E06CBB708CF9E94D0FE32BD13D4F714521EB8D2 -:154B4E00FFFDD0171F51ABD6B52A52C152A5A8E01E053CECA121 -:154B6300BE879D6DEE38F4530A3BBF56F1167C5E71177CC10C75 -:154B7800135675B0FBD674EC8A39DA01D762E084CA261E292BCC -:154B8D00941D7C8C843FECB9D87314940FBBA705F6D86D8D1FA2 -:154BA20088075D7FC0F55A36EBA338B9B6FF32B57D8C5D9768CE -:154BB7003A89F512C80734D6F94E5BF1BF4FDF55D744BCBD27B6 -:154BCC00785E4975BF63E8117EC65230EF62A69125EB8D0C3DF1 -:154BE1006A308DEB88C1DF37B5DE5AFC7F00E871AED038A00037 -:014BF60000BE -:00000001FF diff --git a/drivers/atm/suni.c b/drivers/atm/suni.c index b1d063cc4fbe..6dd3f5919968 100644 --- a/drivers/atm/suni.c +++ b/drivers/atm/suni.c @@ -1,8 +1,14 @@ -/* drivers/atm/suni.c - PMC PM5346 SUNI (PHY) driver */ +/* + * drivers/atm/suni.c - S/UNI PHY driver + * + * Supports the following: + * PMC PM5346 S/UNI LITE + * PMC PM5350 S/UNI 155 ULTRA + * PMC PM5355 S/UNI 622 + */ /* Written 1995-2000 by Werner Almesberger, EPFL LRC/ICA */ - #include <linux/module.h> #include <linux/jiffies.h> #include <linux/kernel.h> @@ -29,15 +35,6 @@ #define DPRINTK(format,args...) #endif - -struct suni_priv { - struct k_sonet_stats sonet_stats; /* link diagnostics */ - int loop_mode; /* loopback mode */ - struct atm_dev *dev; /* device back-pointer */ - struct suni_priv *next; /* next SUNI */ -}; - - #define PRIV(dev) ((struct suni_priv *) dev->phy_data) #define PUT(val,reg) dev->ops->phy_put(dev,val,SUNI_##reg) @@ -155,25 +152,105 @@ static int get_diag(struct atm_dev *dev,void __user *arg) static int set_loopback(struct atm_dev *dev,int mode) { unsigned char control; + int reg, dle, lle; + + if (PRIV(dev)->type == SUNI_MRI_TYPE_PM5355) { + reg = SUNI_MCM; + dle = SUNI_MCM_DLE; + lle = SUNI_MCM_LLE; + } else { + reg = SUNI_MCT; + dle = SUNI_MCT_DLE; + lle = SUNI_MCT_LLE; + } - control = GET(MCT) & ~(SUNI_MCT_DLE | SUNI_MCT_LLE); + control = dev->ops->phy_get(dev, reg) & ~(dle | lle); switch (mode) { case ATM_LM_NONE: break; case ATM_LM_LOC_PHY: - control |= SUNI_MCT_DLE; + control |= dle; break; case ATM_LM_RMT_PHY: - control |= SUNI_MCT_LLE; + control |= lle; break; default: return -EINVAL; } - PUT(control,MCT); + dev->ops->phy_put(dev, control, reg); PRIV(dev)->loop_mode = mode; return 0; } +/* + * SONET vs. SDH Configuration + * + * Z0INS (register 0x06): 0 for SONET, 1 for SDH + * ENSS (register 0x3D): 0 for SONET, 1 for SDH + * LEN16 (register 0x28): 0 for SONET, 1 for SDH (n/a for S/UNI 155 QUAD) + * LEN16 (register 0x50): 0 for SONET, 1 for SDH (n/a for S/UNI 155 QUAD) + * S[1:0] (register 0x46): 00 for SONET, 10 for SDH + */ + +static int set_sonet(struct atm_dev *dev) +{ + if (PRIV(dev)->type == SUNI_MRI_TYPE_PM5355) { + PUT(GET(RPOP_RC) & ~SUNI_RPOP_RC_ENSS, RPOP_RC); + PUT(GET(SSTB_CTRL) & ~SUNI_SSTB_CTRL_LEN16, SSTB_CTRL); + PUT(GET(SPTB_CTRL) & ~SUNI_SPTB_CTRL_LEN16, SPTB_CTRL); + } + + REG_CHANGE(SUNI_TPOP_APM_S, SUNI_TPOP_APM_S_SHIFT, + SUNI_TPOP_S_SONET, TPOP_APM); + + return 0; +} + +static int set_sdh(struct atm_dev *dev) +{ + if (PRIV(dev)->type == SUNI_MRI_TYPE_PM5355) { + PUT(GET(RPOP_RC) | SUNI_RPOP_RC_ENSS, RPOP_RC); + PUT(GET(SSTB_CTRL) | SUNI_SSTB_CTRL_LEN16, SSTB_CTRL); + PUT(GET(SPTB_CTRL) | SUNI_SPTB_CTRL_LEN16, SPTB_CTRL); + } + + REG_CHANGE(SUNI_TPOP_APM_S, SUNI_TPOP_APM_S_SHIFT, + SUNI_TPOP_S_SDH, TPOP_APM); + + return 0; +} + + +static int get_framing(struct atm_dev *dev, void __user *arg) +{ + int framing; + unsigned char s; + + + s = (GET(TPOP_APM) & SUNI_TPOP_APM_S) >> SUNI_TPOP_APM_S_SHIFT; + if (s == SUNI_TPOP_S_SONET) + framing = SONET_FRAME_SONET; + else + framing = SONET_FRAME_SDH; + + return put_user(framing, (int __user *) arg) ? -EFAULT : 0; +} + +static int set_framing(struct atm_dev *dev, void __user *arg) +{ + int mode; + + if (get_user(mode, (int __user *) arg)) + return -EFAULT; + + if (mode == SONET_FRAME_SONET) + return set_sonet(dev); + else if (mode == SONET_FRAME_SDH) + return set_sdh(dev); + + return -EINVAL; +} + static int suni_ioctl(struct atm_dev *dev,unsigned int cmd,void __user *arg) { @@ -188,14 +265,16 @@ static int suni_ioctl(struct atm_dev *dev,unsigned int cmd,void __user *arg) case SONET_GETDIAG: return get_diag(dev,arg); case SONET_SETFRAMING: - if ((int)(unsigned long)arg != SONET_FRAME_SONET) return -EINVAL; - return 0; + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + return set_framing(dev, arg); case SONET_GETFRAMING: - return put_user(SONET_FRAME_SONET,(int __user *)arg) ? - -EFAULT : 0; + return get_framing(dev, arg); case SONET_GETFRSENSE: return -EINVAL; case ATM_SETLOOP: + if (!capable(CAP_NET_ADMIN)) + return -EPERM; return set_loopback(dev,(int)(unsigned long)arg); case ATM_GETLOOP: return put_user(PRIV(dev)->loop_mode,(int __user *)arg) ? @@ -229,10 +308,6 @@ static int suni_start(struct atm_dev *dev) unsigned long flags; int first; - if (!(dev->phy_data = kmalloc(sizeof(struct suni_priv),GFP_KERNEL))) - return -ENOMEM; - - PRIV(dev)->dev = dev; spin_lock_irqsave(&sunis_lock,flags); first = !sunis; PRIV(dev)->next = sunis; @@ -293,16 +368,21 @@ int suni_init(struct atm_dev *dev) { unsigned char mri; + if (!(dev->phy_data = kmalloc(sizeof(struct suni_priv),GFP_KERNEL))) + return -ENOMEM; + PRIV(dev)->dev = dev; + mri = GET(MRI); /* reset SUNI */ + PRIV(dev)->type = (mri & SUNI_MRI_TYPE) >> SUNI_MRI_TYPE_SHIFT; PUT(mri | SUNI_MRI_RESET,MRI); PUT(mri,MRI); PUT((GET(MT) & SUNI_MT_DS27_53),MT); /* disable all tests */ - REG_CHANGE(SUNI_TPOP_APM_S,SUNI_TPOP_APM_S_SHIFT,SUNI_TPOP_S_SONET, - TPOP_APM); /* use SONET */ + set_sonet(dev); REG_CHANGE(SUNI_TACP_IUCHP_CLP,0,SUNI_TACP_IUCHP_CLP, TACP_IUCHP); /* idle cells */ PUT(SUNI_IDLE_PATTERN,TACP_IUCPOP); dev->phy = &suni_ops; + return 0; } diff --git a/drivers/atm/suni.h b/drivers/atm/suni.h index d14c835abc97..7e3e656b3993 100644 --- a/drivers/atm/suni.h +++ b/drivers/atm/suni.h @@ -1,14 +1,15 @@ -/* drivers/atm/suni.h - PMC PM5346 SUNI (PHY) declarations */ +/* + * drivers/atm/suni.h - S/UNI PHY driver + */ /* Written 1995-2000 by Werner Almesberger, EPFL LRC/ICA */ - #ifndef DRIVER_ATM_SUNI_H #define DRIVER_ATM_SUNI_H #include <linux/atmdev.h> #include <linux/atmioc.h> - +#include <linux/sonet.h> /* SUNI registers */ @@ -39,7 +40,8 @@ #define SUNI_RLOP_LFM 0x1F /* RLOP Line FEBE MSB */ #define SUNI_TLOP_CTRL 0x20 /* TLOP Control */ #define SUNI_TLOP_DIAG 0x21 /* TLOP Diagnostic */ - /* 0x22-0x2F reserved */ + /* 0x22-0x27 reserved */ +#define SUNI_SSTB_CTRL 0x28 #define SUNI_RPOP_SC 0x30 /* RPOP Status/Control */ #define SUNI_RPOP_IS 0x31 /* RPOP Interrupt Status */ /* 0x32 reserved */ @@ -52,6 +54,7 @@ #define SUNI_RPOP_PFM 0x3B /* RPOP Path FEBE MSB */ /* 0x3C reserved */ #define SUNI_RPOP_PBC 0x3D /* RPOP Path BIP-8 Configuration */ +#define SUNI_RPOP_RC 0x3D /* RPOP Ring Control (PM5355) */ /* 0x3E-0x3F reserved */ #define SUNI_TPOP_CD 0x40 /* TPOP Control/Diagnostic */ #define SUNI_TPOP_PC 0x41 /* TPOP Pointer Control */ @@ -82,7 +85,8 @@ #define SUNI_TACP_TCC 0x65 /* TACP Transmit Cell Counter */ #define SUNI_TACP_TCCM 0x66 /* TACP Transmit Cell Counter MSB */ #define SUNI_TACP_CFG 0x67 /* TACP Configuration */ - /* 0x68-0x7F reserved */ +#define SUNI_SPTB_CTRL 0x68 /* SPTB Control */ + /* 0x69-0x7F reserved */ #define SUNI_MT 0x80 /* Master Test */ /* 0x81-0xFF reserved */ @@ -94,9 +98,18 @@ #define SUNI_MRI_ID_SHIFT 0 #define SUNI_MRI_TYPE 0x70 /* R, SUNI type (lite is 011) */ #define SUNI_MRI_TYPE_SHIFT 4 +#define SUNI_MRI_TYPE_PM5346 0x3 /* S/UNI 155 LITE */ +#define SUNI_MRI_TYPE_PM5347 0x4 /* S/UNI 155 PLUS */ +#define SUNI_MRI_TYPE_PM5350 0x7 /* S/UNI 155 ULTRA */ +#define SUNI_MRI_TYPE_PM5355 0x1 /* S/UNI 622 */ #define SUNI_MRI_RESET 0x80 /* RW, reset & power down chip 0: normal operation 1: reset & low power */ + +/* MCM is reg 0x4 */ +#define SUNI_MCM_LLE 0x20 /* line loopback (PM5355) */ +#define SUNI_MCM_DLE 0x10 /* diagnostic loopback (PM5355) */ + /* MCT is reg 5 */ #define SUNI_MCT_LOOPT 0x01 /* RW, timing source, 0: from TRCLK+/- */ @@ -144,6 +157,12 @@ /* TLOP_DIAG is reg 0x21 */ #define SUNI_TLOP_DIAG_DBIP 0x01 /* insert line BIP err (continuously) */ +/* SSTB_CTRL is reg 0x28 */ +#define SUNI_SSTB_CTRL_LEN16 0x01 /* path trace message length bit */ + +/* RPOP_RC is reg 0x3D (PM5355) */ +#define SUNI_RPOP_RC_ENSS 0x40 /* enable size bit */ + /* TPOP_DIAG is reg 0x40 */ #define SUNI_TPOP_DIAG_PAIS 0x01 /* insert STS path alarm ind (cont) */ #define SUNI_TPOP_DIAG_DB3 0x02 /* insert path BIP err (continuously) */ @@ -191,6 +210,9 @@ pattern */ #define SUNI_TACP_IUCHP_GFC_SHIFT 4 +/* SPTB_CTRL is reg 0x68 */ +#define SUNI_SPTB_CTRL_LEN16 0x01 /* path trace message length */ + /* MT is reg 0x80 */ #define SUNI_MT_HIZIO 0x01 /* RW, all but data bus & MP interface tri-state */ @@ -205,6 +227,14 @@ #ifdef __KERNEL__ +struct suni_priv { + struct k_sonet_stats sonet_stats; /* link diagnostics */ + int loop_mode; /* loopback mode */ + int type; /* phy type */ + struct atm_dev *dev; /* device back-pointer */ + struct suni_priv *next; /* next SUNI */ +}; + int suni_init(struct atm_dev *dev); #endif diff --git a/drivers/block/ataflop.c b/drivers/block/ataflop.c index 424995073c6b..49f274197b16 100644 --- a/drivers/block/ataflop.c +++ b/drivers/block/ataflop.c @@ -1880,11 +1880,11 @@ static int __init atari_floppy_init (void) if (!MACH_IS_ATARI) /* Amiga, Mac, ... don't have Atari-compatible floppy :-) */ - return -ENXIO; + return -ENODEV; if (MACH_IS_HADES) /* Hades doesn't have Atari-compatible floppy */ - return -ENXIO; + return -ENODEV; if (register_blkdev(FLOPPY_MAJOR,"fd")) return -EBUSY; diff --git a/drivers/bluetooth/Kconfig b/drivers/bluetooth/Kconfig index 075598e1c502..a235ca787465 100644 --- a/drivers/bluetooth/Kconfig +++ b/drivers/bluetooth/Kconfig @@ -71,6 +71,7 @@ config BT_HCIUART_H4 config BT_HCIUART_BCSP bool "BCSP protocol support" depends on BT_HCIUART + select BITREVERSE help BCSP (BlueCore Serial Protocol) is serial protocol for communication between Bluetooth device and host. This protocol is required for non diff --git a/drivers/bluetooth/hci_bcsp.c b/drivers/bluetooth/hci_bcsp.c index 696f7528f022..4d37bb312ee3 100644 --- a/drivers/bluetooth/hci_bcsp.c +++ b/drivers/bluetooth/hci_bcsp.c @@ -39,6 +39,8 @@ #include <linux/signal.h> #include <linux/ioctl.h> #include <linux/skbuff.h> +#include <linux/bitrev.h> +#include <asm/unaligned.h> #include <net/bluetooth/bluetooth.h> #include <net/bluetooth/hci_core.h> @@ -124,27 +126,6 @@ static void bcsp_crc_update(u16 *crc, u8 d) *crc = reg; } -/* - Get reverse of generated crc - - Implementation note - The crc generator (bcsp_crc_init() and bcsp_crc_update()) - creates a reversed crc, so it needs to be swapped back before - being passed on. -*/ -static u16 bcsp_crc_reverse(u16 crc) -{ - u16 b, rev; - - for (b = 0, rev = 0; b < 16; b++) { - rev = rev << 1; - rev |= (crc & 1); - crc = crc >> 1; - } - - return (rev); -} - /* ---- BCSP core ---- */ static void bcsp_slip_msgdelim(struct sk_buff *skb) @@ -235,10 +216,10 @@ static struct sk_buff *bcsp_prepare_pkt(struct bcsp_struct *bcsp, u8 *data, } if (hciextn && chan == 5) { - struct hci_command_hdr *hdr = (struct hci_command_hdr *) data; + __le16 opcode = ((struct hci_command_hdr *)data)->opcode; /* Vendor specific commands */ - if (hci_opcode_ogf(__le16_to_cpu(hdr->opcode)) == 0x3f) { + if (hci_opcode_ogf(__le16_to_cpu(opcode)) == 0x3f) { u8 desc = *(data + HCI_COMMAND_HDR_SIZE); if ((desc & 0xf0) == 0xc0) { data += HCI_COMMAND_HDR_SIZE + 1; @@ -296,7 +277,7 @@ static struct sk_buff *bcsp_prepare_pkt(struct bcsp_struct *bcsp, u8 *data, /* Put CRC */ if (bcsp->use_crc) { - bcsp_txmsg_crc = bcsp_crc_reverse(bcsp_txmsg_crc); + bcsp_txmsg_crc = bitrev16(bcsp_txmsg_crc); bcsp_slip_one_byte(nskb, (u8) ((bcsp_txmsg_crc >> 8) & 0x00ff)); bcsp_slip_one_byte(nskb, (u8) (bcsp_txmsg_crc & 0x00ff)); } @@ -566,6 +547,11 @@ static void bcsp_complete_rx_pkt(struct hci_uart *hu) bcsp->rx_skb = NULL; } +static u16 bscp_get_crc(struct bcsp_struct *bcsp) +{ + return get_unaligned_be16(&bcsp->rx_skb->data[bcsp->rx_skb->len - 2]); +} + /* Recv data */ static int bcsp_recv(struct hci_uart *hu, void *data, int count) { @@ -624,14 +610,10 @@ static int bcsp_recv(struct hci_uart *hu, void *data, int count) continue; case BCSP_W4_CRC: - if (bcsp_crc_reverse(bcsp->message_crc) != - (bcsp->rx_skb->data[bcsp->rx_skb->len - 2] << 8) + - bcsp->rx_skb->data[bcsp->rx_skb->len - 1]) { - + if (bitrev16(bcsp->message_crc) != bscp_get_crc(bcsp)) { BT_ERR ("Checksum failed: computed %04x received %04x", - bcsp_crc_reverse(bcsp->message_crc), - (bcsp->rx_skb-> data[bcsp->rx_skb->len - 2] << 8) + - bcsp->rx_skb->data[bcsp->rx_skb->len - 1]); + bitrev16(bcsp->message_crc), + bscp_get_crc(bcsp)); kfree_skb(bcsp->rx_skb); bcsp->rx_state = BCSP_W4_PKT_DELIMITER; diff --git a/drivers/bluetooth/hci_ldisc.c b/drivers/bluetooth/hci_ldisc.c index e5cd856a2fea..69df187d74ce 100644 --- a/drivers/bluetooth/hci_ldisc.c +++ b/drivers/bluetooth/hci_ldisc.c @@ -282,8 +282,8 @@ static int hci_uart_tty_open(struct tty_struct *tty) /* FIXME: why is this needed. Note don't use ldisc_ref here as the open path is before the ldisc is referencable */ - if (tty->ldisc.flush_buffer) - tty->ldisc.flush_buffer(tty); + if (tty->ldisc.ops->flush_buffer) + tty->ldisc.ops->flush_buffer(tty); tty_driver_flush_buffer(tty); return 0; @@ -514,7 +514,7 @@ static unsigned int hci_uart_tty_poll(struct tty_struct *tty, static int __init hci_uart_init(void) { - static struct tty_ldisc hci_uart_ldisc; + static struct tty_ldisc_ops hci_uart_ldisc; int err; BT_INFO("HCI UART driver ver %s", VERSION); diff --git a/drivers/char/cyclades.c b/drivers/char/cyclades.c index 6bff9d87dc57..e991dc85f2fb 100644 --- a/drivers/char/cyclades.c +++ b/drivers/char/cyclades.c @@ -762,7 +762,7 @@ static int cy_next_channel; /* next minor available */ /* * This is used to look up the divisor speeds and the timeouts * We're normally limited to 15 distinct baud rates. The extra - * are accessed via settings in info->flags. + * are accessed via settings in info->port.flags. * 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, * 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, * HI VHI @@ -1003,7 +1003,7 @@ static void cyy_chip_rx(struct cyclades_card *cinfo, int chip, cy_writeb(base_addr + (CyCAR << index), save_xir); /* if there is nowhere to put the data, discard it */ - if (info->tty == NULL) { + if (info->port.tty == NULL) { if ((readb(base_addr + (CyRIVR << index)) & CyIVRMask) == CyIVRRxEx) { /* exception */ data = readb(base_addr + (CyRDSR << index)); @@ -1015,7 +1015,7 @@ static void cyy_chip_rx(struct cyclades_card *cinfo, int chip, goto end; } /* there is an open port for this data */ - tty = info->tty; + tty = info->port.tty; if ((readb(base_addr + (CyRIVR << index)) & CyIVRMask) == CyIVRRxEx) { /* exception */ data = readb(base_addr + (CyRDSR << index)); @@ -1041,7 +1041,7 @@ static void cyy_chip_rx(struct cyclades_card *cinfo, int chip, readb(base_addr + (CyRDSR << index)), TTY_BREAK); info->icount.rx++; - if (info->flags & ASYNC_SAK) + if (info->port.flags & ASYNC_SAK) do_SAK(tty); } else if (data & CyFRAME) { tty_insert_flip_char(tty, @@ -1145,7 +1145,7 @@ static void cyy_chip_tx(struct cyclades_card *cinfo, unsigned int chip, goto end; } info = &cinfo->ports[channel + chip * 4]; - if (info->tty == NULL) { + if (info->port.tty == NULL) { cy_writeb(base_addr + (CySRER << index), readb(base_addr + (CySRER << index)) & ~CyTxRdy); goto end; @@ -1190,13 +1190,13 @@ static void cyy_chip_tx(struct cyclades_card *cinfo, unsigned int chip, } goto done; } - if (info->xmit_buf == NULL) { + if (info->port.xmit_buf == NULL) { cy_writeb(base_addr + (CySRER << index), readb(base_addr + (CySRER << index)) & ~CyTxRdy); goto done; } - if (info->tty->stopped || info->tty->hw_stopped) { + if (info->port.tty->stopped || info->port.tty->hw_stopped) { cy_writeb(base_addr + (CySRER << index), readb(base_addr + (CySRER << index)) & ~CyTxRdy); @@ -1211,7 +1211,7 @@ static void cyy_chip_tx(struct cyclades_card *cinfo, unsigned int chip, * character. This is necessary because there may not be room * for the two chars needed to send a NULL.) */ - outch = info->xmit_buf[info->xmit_tail]; + outch = info->port.xmit_buf[info->xmit_tail]; if (outch) { info->xmit_cnt--; info->xmit_tail = (info->xmit_tail + 1) & @@ -1232,7 +1232,7 @@ static void cyy_chip_tx(struct cyclades_card *cinfo, unsigned int chip, } done: - tty_wakeup(info->tty); + tty_wakeup(info->port.tty); end: /* end of service */ cy_writeb(base_addr + (CyTIR << index), save_xir & 0x3f); @@ -1256,7 +1256,7 @@ static void cyy_chip_modem(struct cyclades_card *cinfo, int chip, mdm_change = readb(base_addr + (CyMISR << index)); mdm_status = readb(base_addr + (CyMSVR1 << index)); - if (!info->tty) + if (!info->port.tty) goto end; if (mdm_change & CyANY_DELTA) { @@ -1273,29 +1273,29 @@ static void cyy_chip_modem(struct cyclades_card *cinfo, int chip, wake_up_interruptible(&info->delta_msr_wait); } - if ((mdm_change & CyDCD) && (info->flags & ASYNC_CHECK_CD)) { + if ((mdm_change & CyDCD) && (info->port.flags & ASYNC_CHECK_CD)) { if (!(mdm_status & CyDCD)) { - tty_hangup(info->tty); - info->flags &= ~ASYNC_NORMAL_ACTIVE; + tty_hangup(info->port.tty); + info->port.flags &= ~ASYNC_NORMAL_ACTIVE; } - wake_up_interruptible(&info->open_wait); + wake_up_interruptible(&info->port.open_wait); } - if ((mdm_change & CyCTS) && (info->flags & ASYNC_CTS_FLOW)) { - if (info->tty->hw_stopped) { + if ((mdm_change & CyCTS) && (info->port.flags & ASYNC_CTS_FLOW)) { + if (info->port.tty->hw_stopped) { if (mdm_status & CyCTS) { /* cy_start isn't used because... !!! */ - info->tty->hw_stopped = 0; + info->port.tty->hw_stopped = 0; cy_writeb(base_addr + (CySRER << index), readb(base_addr + (CySRER << index)) | CyTxRdy); - tty_wakeup(info->tty); + tty_wakeup(info->port.tty); } } else { if (!(mdm_status & CyCTS)) { /* cy_stop isn't used because ... !!! */ - info->tty->hw_stopped = 1; + info->port.tty->hw_stopped = 1; cy_writeb(base_addr + (CySRER << index), readb(base_addr + (CySRER << index)) & ~CyTxRdy); @@ -1449,7 +1449,7 @@ static void cyz_handle_rx(struct cyclades_port *info, struct BUF_CTRL __iomem *buf_ctrl) { struct cyclades_card *cinfo = info->card; - struct tty_struct *tty = info->tty; + struct tty_struct *tty = info->port.tty; unsigned int char_count; int len; #ifdef BLOCKMOVE @@ -1542,7 +1542,7 @@ static void cyz_handle_tx(struct cyclades_port *info, struct BUF_CTRL __iomem *buf_ctrl) { struct cyclades_card *cinfo = info->card; - struct tty_struct *tty = info->tty; + struct tty_struct *tty = info->port.tty; u8 data; unsigned int char_count; #ifdef BLOCKMOVE @@ -1585,7 +1585,7 @@ static void cyz_handle_tx(struct cyclades_port *info, memcpy_toio((char *)(cinfo->base_addr + tx_bufaddr + tx_put), - &info->xmit_buf[info->xmit_tail], + &info->port.xmit_buf[info->xmit_tail], small_count); tx_put = (tx_put + small_count) & (tx_bufsize - 1); @@ -1597,7 +1597,7 @@ static void cyz_handle_tx(struct cyclades_port *info, } #else while (info->xmit_cnt && char_count) { - data = info->xmit_buf[info->xmit_tail]; + data = info->port.xmit_buf[info->xmit_tail]; info->xmit_cnt--; info->xmit_tail = (info->xmit_tail + 1) & (SERIAL_XMIT_SIZE - 1); @@ -1642,7 +1642,7 @@ static void cyz_handle_cmd(struct cyclades_card *cinfo) special_count = 0; delta_count = 0; info = &cinfo->ports[channel]; - tty = info->tty; + tty = info->port.tty; if (tty == NULL) continue; @@ -1668,15 +1668,15 @@ static void cyz_handle_cmd(struct cyclades_card *cinfo) case C_CM_MDCD: info->icount.dcd++; delta_count++; - if (info->flags & ASYNC_CHECK_CD) { + if (info->port.flags & ASYNC_CHECK_CD) { if ((fw_ver > 241 ? ((u_long) param) : readl(&ch_ctrl->rs_status)) & C_RS_DCD) { - wake_up_interruptible(&info->open_wait); + wake_up_interruptible(&info->port.open_wait); } else { - tty_hangup(info->tty); - wake_up_interruptible(&info->open_wait); - info->flags &= ~ASYNC_NORMAL_ACTIVE; + tty_hangup(info->port.tty); + wake_up_interruptible(&info->port.open_wait); + info->port.flags &= ~ASYNC_NORMAL_ACTIVE; } } break; @@ -1814,7 +1814,7 @@ static void cyz_poll(unsigned long arg) for (port = 0; port < cinfo->nports; port++) { info = &cinfo->ports[port]; - tty = info->tty; + tty = info->port.tty; buf_ctrl = &(zfw_ctrl->buf_ctrl[port]); if (!info->throttle) @@ -1853,22 +1853,22 @@ static int startup(struct cyclades_port *info) spin_lock_irqsave(&card->card_lock, flags); - if (info->flags & ASYNC_INITIALIZED) { + if (info->port.flags & ASYNC_INITIALIZED) { free_page(page); goto errout; } if (!info->type) { - if (info->tty) - set_bit(TTY_IO_ERROR, &info->tty->flags); + if (info->port.tty) + set_bit(TTY_IO_ERROR, &info->port.tty->flags); free_page(page); goto errout; } - if (info->xmit_buf) + if (info->port.xmit_buf) free_page(page); else - info->xmit_buf = (unsigned char *)page; + info->port.xmit_buf = (unsigned char *)page; spin_unlock_irqrestore(&card->card_lock, flags); @@ -1909,10 +1909,10 @@ static int startup(struct cyclades_port *info) cy_writeb(base_addr + (CySRER << index), readb(base_addr + (CySRER << index)) | CyRxData); - info->flags |= ASYNC_INITIALIZED; + info->port.flags |= ASYNC_INITIALIZED; - if (info->tty) - clear_bit(TTY_IO_ERROR, &info->tty->flags); + if (info->port.tty) + clear_bit(TTY_IO_ERROR, &info->port.tty->flags); info->xmit_cnt = info->xmit_head = info->xmit_tail = 0; info->breakon = info->breakoff = 0; memset((char *)&info->idle_stats, 0, sizeof(info->idle_stats)); @@ -1994,9 +1994,9 @@ static int startup(struct cyclades_port *info) /* enable send, recv, modem !!! */ - info->flags |= ASYNC_INITIALIZED; - if (info->tty) - clear_bit(TTY_IO_ERROR, &info->tty->flags); + info->port.flags |= ASYNC_INITIALIZED; + if (info->port.tty) + clear_bit(TTY_IO_ERROR, &info->port.tty->flags); info->xmit_cnt = info->xmit_head = info->xmit_tail = 0; info->breakon = info->breakoff = 0; memset((char *)&info->idle_stats, 0, sizeof(info->idle_stats)); @@ -2065,7 +2065,7 @@ static void shutdown(struct cyclades_port *info) void __iomem *base_addr; int chip, channel, index; - if (!(info->flags & ASYNC_INITIALIZED)) + if (!(info->port.flags & ASYNC_INITIALIZED)) return; card = info->card; @@ -2087,14 +2087,14 @@ static void shutdown(struct cyclades_port *info) /* Clear delta_msr_wait queue to avoid mem leaks. */ wake_up_interruptible(&info->delta_msr_wait); - if (info->xmit_buf) { + if (info->port.xmit_buf) { unsigned char *temp; - temp = info->xmit_buf; - info->xmit_buf = NULL; + temp = info->port.xmit_buf; + info->port.xmit_buf = NULL; free_page((unsigned long)temp); } cy_writeb(base_addr + (CyCAR << index), (u_char) channel); - if (!info->tty || (info->tty->termios->c_cflag & HUPCL)) { + if (!info->port.tty || (info->port.tty->termios->c_cflag & HUPCL)) { cy_writeb(base_addr + (CyMSVR1 << index), ~CyRTS); cy_writeb(base_addr + (CyMSVR2 << index), ~CyDTR); #ifdef CY_DEBUG_DTR @@ -2108,9 +2108,9 @@ static void shutdown(struct cyclades_port *info) /* it may be appropriate to clear _XMIT at some later date (after testing)!!! */ - if (info->tty) - set_bit(TTY_IO_ERROR, &info->tty->flags); - info->flags &= ~ASYNC_INITIALIZED; + if (info->port.tty) + set_bit(TTY_IO_ERROR, &info->port.tty->flags); + info->port.flags &= ~ASYNC_INITIALIZED; spin_unlock_irqrestore(&card->card_lock, flags); } else { struct FIRM_ID __iomem *firm_id; @@ -2136,14 +2136,14 @@ static void shutdown(struct cyclades_port *info) spin_lock_irqsave(&card->card_lock, flags); - if (info->xmit_buf) { + if (info->port.xmit_buf) { unsigned char *temp; - temp = info->xmit_buf; - info->xmit_buf = NULL; + temp = info->port.xmit_buf; + info->port.xmit_buf = NULL; free_page((unsigned long)temp); } - if (!info->tty || (info->tty->termios->c_cflag & HUPCL)) { + if (!info->port.tty || (info->port.tty->termios->c_cflag & HUPCL)) { cy_writel(&ch_ctrl[channel].rs_control, (__u32)(readl(&ch_ctrl[channel].rs_control) & ~(C_RS_RTS | C_RS_DTR))); @@ -2158,9 +2158,9 @@ static void shutdown(struct cyclades_port *info) #endif } - if (info->tty) - set_bit(TTY_IO_ERROR, &info->tty->flags); - info->flags &= ~ASYNC_INITIALIZED; + if (info->port.tty) + set_bit(TTY_IO_ERROR, &info->port.tty->flags); + info->port.flags &= ~ASYNC_INITIALIZED; spin_unlock_irqrestore(&card->card_lock, flags); } @@ -2194,10 +2194,10 @@ block_til_ready(struct tty_struct *tty, struct file *filp, * If the device is in the middle of being closed, then block * until it's done, and then try again. */ - if (tty_hung_up_p(filp) || (info->flags & ASYNC_CLOSING)) { - wait_event_interruptible(info->close_wait, - !(info->flags & ASYNC_CLOSING)); - return (info->flags & ASYNC_HUP_NOTIFY) ? -EAGAIN: -ERESTARTSYS; + if (tty_hung_up_p(filp) || (info->port.flags & ASYNC_CLOSING)) { + wait_event_interruptible(info->port.close_wait, + !(info->port.flags & ASYNC_CLOSING)); + return (info->port.flags & ASYNC_HUP_NOTIFY) ? -EAGAIN: -ERESTARTSYS; } /* @@ -2206,32 +2206,32 @@ block_til_ready(struct tty_struct *tty, struct file *filp, */ if ((filp->f_flags & O_NONBLOCK) || (tty->flags & (1 << TTY_IO_ERROR))) { - info->flags |= ASYNC_NORMAL_ACTIVE; + info->port.flags |= ASYNC_NORMAL_ACTIVE; return 0; } /* * Block waiting for the carrier detect and the line to become * free (i.e., not in use by the callout). While we are in - * this loop, info->count is dropped by one, so that + * this loop, info->port.count is dropped by one, so that * cy_close() knows when to free things. We restore it upon * exit, either normal or abnormal. */ retval = 0; - add_wait_queue(&info->open_wait, &wait); + add_wait_queue(&info->port.open_wait, &wait); #ifdef CY_DEBUG_OPEN printk(KERN_DEBUG "cyc block_til_ready before block: ttyC%d, " - "count = %d\n", info->line, info->count); + "count = %d\n", info->line, info->port.count); #endif spin_lock_irqsave(&cinfo->card_lock, flags); if (!tty_hung_up_p(filp)) - info->count--; + info->port.count--; spin_unlock_irqrestore(&cinfo->card_lock, flags); #ifdef CY_DEBUG_COUNT printk(KERN_DEBUG "cyc block_til_ready: (%d): decrementing count to " - "%d\n", current->pid, info->count); + "%d\n", current->pid, info->port.count); #endif - info->blocked_open++; + info->port.blocked_open++; if (!IS_CYC_Z(*cinfo)) { chip = channel >> 2; @@ -2260,8 +2260,8 @@ block_til_ready(struct tty_struct *tty, struct file *filp, set_current_state(TASK_INTERRUPTIBLE); if (tty_hung_up_p(filp) || - !(info->flags & ASYNC_INITIALIZED)) { - retval = ((info->flags & ASYNC_HUP_NOTIFY) ? + !(info->port.flags & ASYNC_INITIALIZED)) { + retval = ((info->port.flags & ASYNC_HUP_NOTIFY) ? -EAGAIN : -ERESTARTSYS); break; } @@ -2269,7 +2269,7 @@ block_til_ready(struct tty_struct *tty, struct file *filp, spin_lock_irqsave(&cinfo->card_lock, flags); cy_writeb(base_addr + (CyCAR << index), (u_char) channel); - if (!(info->flags & ASYNC_CLOSING) && (C_CLOCAL(tty) || + if (!(info->port.flags & ASYNC_CLOSING) && (C_CLOCAL(tty) || (readb(base_addr + (CyMSVR1 << index)) & CyDCD))) { spin_unlock_irqrestore(&cinfo->card_lock, flags); @@ -2284,7 +2284,7 @@ block_til_ready(struct tty_struct *tty, struct file *filp, #ifdef CY_DEBUG_OPEN printk(KERN_DEBUG "cyc block_til_ready blocking: " "ttyC%d, count = %d\n", - info->line, info->count); + info->line, info->port.count); #endif schedule(); } @@ -2298,7 +2298,7 @@ block_til_ready(struct tty_struct *tty, struct file *filp, firm_id = base_addr + ID_ADDRESS; if (!ISZLOADED(*cinfo)) { __set_current_state(TASK_RUNNING); - remove_wait_queue(&info->open_wait, &wait); + remove_wait_queue(&info->port.open_wait, &wait); return -EINVAL; } @@ -2327,12 +2327,12 @@ block_til_ready(struct tty_struct *tty, struct file *filp, set_current_state(TASK_INTERRUPTIBLE); if (tty_hung_up_p(filp) || - !(info->flags & ASYNC_INITIALIZED)) { - retval = ((info->flags & ASYNC_HUP_NOTIFY) ? + !(info->port.flags & ASYNC_INITIALIZED)) { + retval = ((info->port.flags & ASYNC_HUP_NOTIFY) ? -EAGAIN : -ERESTARTSYS); break; } - if (!(info->flags & ASYNC_CLOSING) && (C_CLOCAL(tty) || + if (!(info->port.flags & ASYNC_CLOSING) && (C_CLOCAL(tty) || (readl(&ch_ctrl[channel].rs_status) & C_RS_DCD))) { break; @@ -2344,28 +2344,28 @@ block_til_ready(struct tty_struct *tty, struct file *filp, #ifdef CY_DEBUG_OPEN printk(KERN_DEBUG "cyc block_til_ready blocking: " "ttyC%d, count = %d\n", - info->line, info->count); + info->line, info->port.count); #endif schedule(); } } __set_current_state(TASK_RUNNING); - remove_wait_queue(&info->open_wait, &wait); + remove_wait_queue(&info->port.open_wait, &wait); if (!tty_hung_up_p(filp)) { - info->count++; + info->port.count++; #ifdef CY_DEBUG_COUNT printk(KERN_DEBUG "cyc:block_til_ready (%d): incrementing " - "count to %d\n", current->pid, info->count); + "count to %d\n", current->pid, info->port.count); #endif } - info->blocked_open--; + info->port.blocked_open--; #ifdef CY_DEBUG_OPEN printk(KERN_DEBUG "cyc:block_til_ready after blocking: ttyC%d, " - "count = %d\n", info->line, info->count); + "count = %d\n", info->line, info->port.count); #endif if (retval) return retval; - info->flags |= ASYNC_NORMAL_ACTIVE; + info->port.flags |= ASYNC_NORMAL_ACTIVE; return 0; } /* block_til_ready */ @@ -2456,27 +2456,27 @@ static int cy_open(struct tty_struct *tty, struct file *filp) printk(KERN_DEBUG "cyc:cy_open ttyC%d\n", info->line); #endif tty->driver_data = info; - info->tty = tty; + info->port.tty = tty; if (serial_paranoia_check(info, tty->name, "cy_open")) return -ENODEV; #ifdef CY_DEBUG_OPEN printk(KERN_DEBUG "cyc:cy_open ttyC%d, count = %d\n", info->line, - info->count); + info->port.count); #endif - info->count++; + info->port.count++; #ifdef CY_DEBUG_COUNT printk(KERN_DEBUG "cyc:cy_open (%d): incrementing count to %d\n", - current->pid, info->count); + current->pid, info->port.count); #endif /* * If the port is the middle of closing, bail out now */ - if (tty_hung_up_p(filp) || (info->flags & ASYNC_CLOSING)) { - wait_event_interruptible(info->close_wait, - !(info->flags & ASYNC_CLOSING)); - return (info->flags & ASYNC_HUP_NOTIFY) ? -EAGAIN: -ERESTARTSYS; + if (tty_hung_up_p(filp) || (info->port.flags & ASYNC_CLOSING)) { + wait_event_interruptible(info->port.close_wait, + !(info->port.flags & ASYNC_CLOSING)); + return (info->port.flags & ASYNC_HUP_NOTIFY) ? -EAGAIN: -ERESTARTSYS; } /* @@ -2641,9 +2641,9 @@ static void cy_close(struct tty_struct *tty, struct file *filp) } #ifdef CY_DEBUG_OPEN printk(KERN_DEBUG "cyc:cy_close ttyC%d, count = %d\n", info->line, - info->count); + info->port.count); #endif - if ((tty->count == 1) && (info->count != 1)) { + if ((tty->count == 1) && (info->port.count != 1)) { /* * Uh, oh. tty->count is 1, which means that the tty * structure will be freed. Info->count should always @@ -2652,24 +2652,24 @@ static void cy_close(struct tty_struct *tty, struct file *filp) * serial port won't be shutdown. */ printk(KERN_ERR "cyc:cy_close: bad serial port count; " - "tty->count is 1, info->count is %d\n", info->count); - info->count = 1; + "tty->count is 1, info->port.count is %d\n", info->port.count); + info->port.count = 1; } #ifdef CY_DEBUG_COUNT printk(KERN_DEBUG "cyc:cy_close at (%d): decrementing count to %d\n", - current->pid, info->count - 1); + current->pid, info->port.count - 1); #endif - if (--info->count < 0) { + if (--info->port.count < 0) { #ifdef CY_DEBUG_COUNT printk(KERN_DEBUG "cyc:cyc_close setting count to 0\n"); #endif - info->count = 0; + info->port.count = 0; } - if (info->count) { + if (info->port.count) { spin_unlock_irqrestore(&card->card_lock, flags); return; } - info->flags |= ASYNC_CLOSING; + info->port.flags |= ASYNC_CLOSING; /* * Now we wait for the transmit buffer to clear; and we notify @@ -2677,8 +2677,8 @@ static void cy_close(struct tty_struct *tty, struct file *filp) */ tty->closing = 1; spin_unlock_irqrestore(&card->card_lock, flags); - if (info->closing_wait != CY_CLOSING_WAIT_NONE) - tty_wait_until_sent(tty, info->closing_wait); + if (info->port.closing_wait != CY_CLOSING_WAIT_NONE) + tty_wait_until_sent(tty, info->port.closing_wait); spin_lock_irqsave(&card->card_lock, flags); @@ -2692,7 +2692,7 @@ static void cy_close(struct tty_struct *tty, struct file *filp) cy_writeb(base_addr + (CyCAR << index), (u_char) channel); cy_writeb(base_addr + (CySRER << index), readb(base_addr + (CySRER << index)) & ~CyRxData); - if (info->flags & ASYNC_INITIALIZED) { + if (info->port.flags & ASYNC_INITIALIZED) { /* Waiting for on-board buffers to be empty before closing the port */ spin_unlock_irqrestore(&card->card_lock, flags); @@ -2731,18 +2731,18 @@ static void cy_close(struct tty_struct *tty, struct file *filp) spin_lock_irqsave(&card->card_lock, flags); tty->closing = 0; - info->tty = NULL; - if (info->blocked_open) { + info->port.tty = NULL; + if (info->port.blocked_open) { spin_unlock_irqrestore(&card->card_lock, flags); - if (info->close_delay) { + if (info->port.close_delay) { msleep_interruptible(jiffies_to_msecs - (info->close_delay)); + (info->port.close_delay)); } - wake_up_interruptible(&info->open_wait); + wake_up_interruptible(&info->port.open_wait); spin_lock_irqsave(&card->card_lock, flags); } - info->flags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_CLOSING); - wake_up_interruptible(&info->close_wait); + info->port.flags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_CLOSING); + wake_up_interruptible(&info->port.close_wait); #ifdef CY_DEBUG_OTHER printk(KERN_DEBUG "cyc:cy_close done\n"); @@ -2777,7 +2777,7 @@ static int cy_write(struct tty_struct *tty, const unsigned char *buf, int count) if (serial_paranoia_check(info, tty->name, "cy_write")) return 0; - if (!info->xmit_buf) + if (!info->port.xmit_buf) return 0; spin_lock_irqsave(&info->card->card_lock, flags); @@ -2788,7 +2788,7 @@ static int cy_write(struct tty_struct *tty, const unsigned char *buf, int count) if (c <= 0) break; - memcpy(info->xmit_buf + info->xmit_head, buf, c); + memcpy(info->port.xmit_buf + info->xmit_head, buf, c); info->xmit_head = (info->xmit_head + c) & (SERIAL_XMIT_SIZE - 1); info->xmit_cnt += c; @@ -2826,7 +2826,7 @@ static int cy_put_char(struct tty_struct *tty, unsigned char ch) if (serial_paranoia_check(info, tty->name, "cy_put_char")) return 0; - if (!info->xmit_buf) + if (!info->port.xmit_buf) return 0; spin_lock_irqsave(&info->card->card_lock, flags); @@ -2835,7 +2835,7 @@ static int cy_put_char(struct tty_struct *tty, unsigned char ch) return 0; } - info->xmit_buf[info->xmit_head++] = ch; + info->port.xmit_buf[info->xmit_head++] = ch; info->xmit_head &= SERIAL_XMIT_SIZE - 1; info->xmit_cnt++; info->idle_stats.xmit_bytes++; @@ -2860,7 +2860,7 @@ static void cy_flush_chars(struct tty_struct *tty) return; if (info->xmit_cnt <= 0 || tty->stopped || tty->hw_stopped || - !info->xmit_buf) + !info->port.xmit_buf) return; start_xmit(info); @@ -2988,27 +2988,27 @@ static void set_line_char(struct cyclades_port *info) int baud, baud_rate = 0; int i; - if (!info->tty || !info->tty->termios) + if (!info->port.tty || !info->port.tty->termios) return; if (info->line == -1) return; - cflag = info->tty->termios->c_cflag; - iflag = info->tty->termios->c_iflag; + cflag = info->port.tty->termios->c_cflag; + iflag = info->port.tty->termios->c_iflag; /* * Set up the tty->alt_speed kludge */ - if (info->tty) { - if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI) - info->tty->alt_speed = 57600; - if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI) - info->tty->alt_speed = 115200; - if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI) - info->tty->alt_speed = 230400; - if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP) - info->tty->alt_speed = 460800; + if (info->port.tty) { + if ((info->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI) + info->port.tty->alt_speed = 57600; + if ((info->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI) + info->port.tty->alt_speed = 115200; + if ((info->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI) + info->port.tty->alt_speed = 230400; + if ((info->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP) + info->port.tty->alt_speed = 460800; } card = info->card; @@ -3020,8 +3020,8 @@ static void set_line_char(struct cyclades_port *info) index = card->bus_index; /* baud rate */ - baud = tty_get_baud_rate(info->tty); - if (baud == 38400 && (info->flags & ASYNC_SPD_MASK) == + baud = tty_get_baud_rate(info->port.tty); + if (baud == 38400 && (info->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST) { if (info->custom_divisor) baud_rate = info->baud / info->custom_divisor; @@ -3038,7 +3038,7 @@ static void set_line_char(struct cyclades_port *info) if (i == 20) i = 19; /* CD1400_MAX_SPEED */ - if (baud == 38400 && (info->flags & ASYNC_SPD_MASK) == + if (baud == 38400 && (info->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST) { cyy_baud_calc(info, baud_rate); } else { @@ -3059,7 +3059,7 @@ static void set_line_char(struct cyclades_port *info) /* get it right for 134.5 baud */ info->timeout = (info->xmit_fifo_size * HZ * 30 / 269) + 2; - } else if (baud == 38400 && (info->flags & ASYNC_SPD_MASK) == + } else if (baud == 38400 && (info->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST) { info->timeout = (info->xmit_fifo_size * HZ * 15 / baud_rate) + 2; @@ -3108,16 +3108,16 @@ static void set_line_char(struct cyclades_port *info) /* CTS flow control flag */ if (cflag & CRTSCTS) { - info->flags |= ASYNC_CTS_FLOW; + info->port.flags |= ASYNC_CTS_FLOW; info->cor2 |= CyCtsAE; } else { - info->flags &= ~ASYNC_CTS_FLOW; + info->port.flags &= ~ASYNC_CTS_FLOW; info->cor2 &= ~CyCtsAE; } if (cflag & CLOCAL) - info->flags &= ~ASYNC_CHECK_CD; + info->port.flags &= ~ASYNC_CHECK_CD; else - info->flags |= ASYNC_CHECK_CD; + info->port.flags |= ASYNC_CHECK_CD; /*********************************************** The hardware option, CyRtsAO, presents RTS when @@ -3146,8 +3146,8 @@ static void set_line_char(struct cyclades_port *info) /* set line characteristics according configuration */ cy_writeb(base_addr + (CySCHR1 << index), - START_CHAR(info->tty)); - cy_writeb(base_addr + (CySCHR2 << index), STOP_CHAR(info->tty)); + START_CHAR(info->port.tty)); + cy_writeb(base_addr + (CySCHR2 << index), STOP_CHAR(info->port.tty)); cy_writeb(base_addr + (CyCOR1 << index), info->cor1); cy_writeb(base_addr + (CyCOR2 << index), info->cor2); cy_writeb(base_addr + (CyCOR3 << index), info->cor3); @@ -3163,7 +3163,7 @@ static void set_line_char(struct cyclades_port *info) (info->default_timeout ? info->default_timeout : 0x02)); /* 10ms rx timeout */ - if (C_CLOCAL(info->tty)) { + if (C_CLOCAL(info->port.tty)) { /* without modem intr */ cy_writeb(base_addr + (CySRER << index), readb(base_addr + (CySRER << index)) | CyMdmCh); @@ -3226,8 +3226,8 @@ static void set_line_char(struct cyclades_port *info) #endif } - if (info->tty) - clear_bit(TTY_IO_ERROR, &info->tty->flags); + if (info->port.tty) + clear_bit(TTY_IO_ERROR, &info->port.tty->flags); spin_unlock_irqrestore(&card->card_lock, flags); } else { @@ -3250,8 +3250,8 @@ static void set_line_char(struct cyclades_port *info) buf_ctrl = &zfw_ctrl->buf_ctrl[channel]; /* baud rate */ - baud = tty_get_baud_rate(info->tty); - if (baud == 38400 && (info->flags & ASYNC_SPD_MASK) == + baud = tty_get_baud_rate(info->port.tty); + if (baud == 38400 && (info->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST) { if (info->custom_divisor) baud_rate = info->baud / info->custom_divisor; @@ -3266,7 +3266,7 @@ static void set_line_char(struct cyclades_port *info) /* get it right for 134.5 baud */ info->timeout = (info->xmit_fifo_size * HZ * 30 / 269) + 2; - } else if (baud == 38400 && (info->flags & ASYNC_SPD_MASK) == + } else if (baud == 38400 && (info->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST) { info->timeout = (info->xmit_fifo_size * HZ * 15 / baud_rate) + 2; @@ -3318,7 +3318,7 @@ static void set_line_char(struct cyclades_port *info) } /* As the HW flow control is done in firmware, the driver doesn't need to care about it */ - info->flags &= ~ASYNC_CTS_FLOW; + info->port.flags &= ~ASYNC_CTS_FLOW; /* XON/XOFF/XANY flow control flags */ sw_flow = 0; @@ -3337,9 +3337,9 @@ static void set_line_char(struct cyclades_port *info) /* CD sensitivity */ if (cflag & CLOCAL) - info->flags &= ~ASYNC_CHECK_CD; + info->port.flags &= ~ASYNC_CHECK_CD; else - info->flags |= ASYNC_CHECK_CD; + info->port.flags |= ASYNC_CHECK_CD; if (baud == 0) { /* baud rate is zero, turn off line */ cy_writel(&ch_ctrl->rs_control, @@ -3361,8 +3361,8 @@ static void set_line_char(struct cyclades_port *info) "was %x\n", info->line, retval); } - if (info->tty) - clear_bit(TTY_IO_ERROR, &info->tty->flags); + if (info->port.tty) + clear_bit(TTY_IO_ERROR, &info->port.tty->flags); } } /* set_line_char */ @@ -3381,9 +3381,9 @@ get_serial_info(struct cyclades_port *info, tmp.port = (info->card - cy_card) * 0x100 + info->line - cinfo->first_line; tmp.irq = cinfo->irq; - tmp.flags = info->flags; - tmp.close_delay = info->close_delay; - tmp.closing_wait = info->closing_wait; + tmp.flags = info->port.flags; + tmp.close_delay = info->port.close_delay; + tmp.closing_wait = info->port.closing_wait; tmp.baud_base = info->baud; tmp.custom_divisor = info->custom_divisor; tmp.hub6 = 0; /*!!! */ @@ -3402,13 +3402,13 @@ set_serial_info(struct cyclades_port *info, old_info = *info; if (!capable(CAP_SYS_ADMIN)) { - if (new_serial.close_delay != info->close_delay || + if (new_serial.close_delay != info->port.close_delay || new_serial.baud_base != info->baud || (new_serial.flags & ASYNC_FLAGS & ~ASYNC_USR_MASK) != - (info->flags & ASYNC_FLAGS & ~ASYNC_USR_MASK)) + (info->port.flags & ASYNC_FLAGS & ~ASYNC_USR_MASK)) return -EPERM; - info->flags = (info->flags & ~ASYNC_USR_MASK) | + info->port.flags = (info->port.flags & ~ASYNC_USR_MASK) | (new_serial.flags & ASYNC_USR_MASK); info->baud = new_serial.baud_base; info->custom_divisor = new_serial.custom_divisor; @@ -3422,13 +3422,13 @@ set_serial_info(struct cyclades_port *info, info->baud = new_serial.baud_base; info->custom_divisor = new_serial.custom_divisor; - info->flags = (info->flags & ~ASYNC_FLAGS) | + info->port.flags = (info->port.flags & ~ASYNC_FLAGS) | (new_serial.flags & ASYNC_FLAGS); - info->close_delay = new_serial.close_delay * HZ / 100; - info->closing_wait = new_serial.closing_wait * HZ / 100; + info->port.close_delay = new_serial.close_delay * HZ / 100; + info->port.closing_wait = new_serial.closing_wait * HZ / 100; check_and_exit: - if (info->flags & ASYNC_INITIALIZED) { + if (info->port.flags & ASYNC_INITIALIZED) { set_line_char(info); return 0; } else { @@ -3971,11 +3971,11 @@ cy_ioctl(struct tty_struct *tty, struct file *file, break; #endif /* CONFIG_CYZ_INTR */ case CYSETWAIT: - info->closing_wait = (unsigned short)arg * HZ / 100; + info->port.closing_wait = (unsigned short)arg * HZ / 100; ret_val = 0; break; case CYGETWAIT: - ret_val = info->closing_wait / (HZ / 100); + ret_val = info->port.closing_wait / (HZ / 100); break; case TIOCGSERIAL: ret_val = get_serial_info(info, argp); @@ -4097,7 +4097,7 @@ static void cy_set_termios(struct tty_struct *tty, struct ktermios *old_termios) */ if (!(old_termios->c_cflag & CLOCAL) && (tty->termios->c_cflag & CLOCAL)) - wake_up_interruptible(&info->open_wait); + wake_up_interruptible(&info->port.open_wait); #endif } /* cy_set_termios */ @@ -4326,14 +4326,14 @@ static void cy_hangup(struct tty_struct *tty) cy_flush_buffer(tty); shutdown(info); - info->count = 0; + info->port.count = 0; #ifdef CY_DEBUG_COUNT printk(KERN_DEBUG "cyc:cy_hangup (%d): setting count to 0\n", current->pid); #endif - info->tty = NULL; - info->flags &= ~ASYNC_NORMAL_ACTIVE; - wake_up_interruptible(&info->open_wait); + info->port.tty = NULL; + info->port.flags &= ~ASYNC_NORMAL_ACTIVE; + wake_up_interruptible(&info->port.open_wait); } /* cy_hangup */ /* @@ -4376,15 +4376,14 @@ static int __devinit cy_init_card(struct cyclades_card *cinfo) for (port = cinfo->first_line; port < cinfo->first_line + nports; port++) { info = &cinfo->ports[port - cinfo->first_line]; + tty_port_init(&info->port); info->magic = CYCLADES_MAGIC; info->card = cinfo; info->line = port; - info->flags = STD_COM_FLAGS; - info->closing_wait = CLOSING_WAIT_DELAY; - info->close_delay = 5 * HZ / 10; - init_waitqueue_head(&info->open_wait); - init_waitqueue_head(&info->close_wait); + info->port.closing_wait = CLOSING_WAIT_DELAY; + info->port.close_delay = 5 * HZ / 10; + info->port.flags = STD_COM_FLAGS; init_completion(&info->shutdown_wait); init_waitqueue_head(&info->delta_msr_wait); @@ -5237,7 +5236,7 @@ cyclades_get_proc_info(char *buf, char **start, off_t offset, int length, for (j = 0; j < cy_card[i].nports; j++) { info = &cy_card[i].ports[j]; - if (info->count) + if (info->port.count) size = sprintf(buf + len, "%3d %8lu %10lu %8lu " "%10lu %8lu %9lu %6ld\n", info->line, (cur_jifs - info->idle_stats.in_use) / @@ -5246,7 +5245,8 @@ cyclades_get_proc_info(char *buf, char **start, off_t offset, int length, HZ, info->idle_stats.recv_bytes, (cur_jifs - info->idle_stats.recv_idle)/ HZ, info->idle_stats.overruns, - (long)info->tty->ldisc.num); + /* FIXME: double check locking */ + (long)info->port.tty->ldisc.ops->num); else size = sprintf(buf + len, "%3d %8lu %10lu %8lu " "%10lu %8lu %9lu %6ld\n", diff --git a/drivers/char/epca.c b/drivers/char/epca.c index 60a4df7dac12..ac9995f6578b 100644 --- a/drivers/char/epca.c +++ b/drivers/char/epca.c @@ -432,7 +432,7 @@ static void pc_close(struct tty_struct *tty, struct file *filp) spin_unlock_irqrestore(&epca_lock, flags); return; } - if (ch->count-- > 1) { + if (ch->port.count-- > 1) { /* Begin channel is open more than once */ /* * Return without doing anything. Someone might still @@ -442,19 +442,19 @@ static void pc_close(struct tty_struct *tty, struct file *filp) return; } /* Port open only once go ahead with shutdown & reset */ - BUG_ON(ch->count < 0); + BUG_ON(ch->port.count < 0); /* * Let the rest of the driver know the channel is being closed. * This becomes important if an open is attempted before close * is finished. */ - ch->asyncflags |= ASYNC_CLOSING; + ch->port.flags |= ASYNC_CLOSING; tty->closing = 1; spin_unlock_irqrestore(&epca_lock, flags); - if (ch->asyncflags & ASYNC_INITIALIZED) { + if (ch->port.flags & ASYNC_INITIALIZED) { /* Setup an event to indicate when the transmit buffer empties */ setup_empty_event(tty, ch); @@ -469,17 +469,17 @@ static void pc_close(struct tty_struct *tty, struct file *filp) spin_lock_irqsave(&epca_lock, flags); tty->closing = 0; ch->event = 0; - ch->tty = NULL; + ch->port.tty = NULL; spin_unlock_irqrestore(&epca_lock, flags); - if (ch->blocked_open) { + if (ch->port.blocked_open) { if (ch->close_delay) msleep_interruptible(jiffies_to_msecs(ch->close_delay)); - wake_up_interruptible(&ch->open_wait); + wake_up_interruptible(&ch->port.open_wait); } - ch->asyncflags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_INITIALIZED | + ch->port.flags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_INITIALIZED | ASYNC_CLOSING); - wake_up_interruptible(&ch->close_wait); + wake_up_interruptible(&ch->port.close_wait); } } @@ -489,7 +489,7 @@ static void shutdown(struct channel *ch) struct tty_struct *tty; struct board_chan __iomem *bc; - if (!(ch->asyncflags & ASYNC_INITIALIZED)) + if (!(ch->port.flags & ASYNC_INITIALIZED)) return; spin_lock_irqsave(&epca_lock, flags); @@ -504,7 +504,7 @@ static void shutdown(struct channel *ch) */ if (bc) writeb(0, &bc->idata); - tty = ch->tty; + tty = ch->port.tty; /* If we're a modem control device and HUPCL is on, drop RTS & DTR. */ if (tty->termios->c_cflag & HUPCL) { @@ -518,7 +518,7 @@ static void shutdown(struct channel *ch) * will have to reinitialized. Set a flag to indicate this. */ /* Prevent future Digi programmed interrupts from coming active */ - ch->asyncflags &= ~ASYNC_INITIALIZED; + ch->port.flags &= ~ASYNC_INITIALIZED; spin_unlock_irqrestore(&epca_lock, flags); } @@ -538,12 +538,12 @@ static void pc_hangup(struct tty_struct *tty) shutdown(ch); spin_lock_irqsave(&epca_lock, flags); - ch->tty = NULL; + ch->port.tty = NULL; ch->event = 0; - ch->count = 0; - ch->asyncflags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_INITIALIZED); + ch->port.count = 0; + ch->port.flags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_INITIALIZED); spin_unlock_irqrestore(&epca_lock, flags); - wake_up_interruptible(&ch->open_wait); + wake_up_interruptible(&ch->port.open_wait); } } @@ -795,7 +795,7 @@ static int block_til_ready(struct tty_struct *tty, unsigned long flags; if (tty_hung_up_p(filp)) { - if (ch->asyncflags & ASYNC_HUP_NOTIFY) + if (ch->port.flags & ASYNC_HUP_NOTIFY) retval = -EAGAIN; else retval = -ERESTARTSYS; @@ -806,10 +806,10 @@ static int block_til_ready(struct tty_struct *tty, * If the device is in the middle of being closed, then block until * it's done, and then try again. */ - if (ch->asyncflags & ASYNC_CLOSING) { - interruptible_sleep_on(&ch->close_wait); + if (ch->port.flags & ASYNC_CLOSING) { + interruptible_sleep_on(&ch->port.close_wait); - if (ch->asyncflags & ASYNC_HUP_NOTIFY) + if (ch->port.flags & ASYNC_HUP_NOTIFY) return -EAGAIN; else return -ERESTARTSYS; @@ -820,7 +820,7 @@ static int block_til_ready(struct tty_struct *tty, * If non-blocking mode is set, then make the check up front * and then exit. */ - ch->asyncflags |= ASYNC_NORMAL_ACTIVE; + ch->port.flags |= ASYNC_NORMAL_ACTIVE; return 0; } if (tty->termios->c_cflag & CLOCAL) @@ -828,24 +828,24 @@ static int block_til_ready(struct tty_struct *tty, /* Block waiting for the carrier detect and the line to become free */ retval = 0; - add_wait_queue(&ch->open_wait, &wait); + add_wait_queue(&ch->port.open_wait, &wait); spin_lock_irqsave(&epca_lock, flags); /* We dec count so that pc_close will know when to free things */ if (!tty_hung_up_p(filp)) - ch->count--; - ch->blocked_open++; + ch->port.count--; + ch->port.blocked_open++; while (1) { set_current_state(TASK_INTERRUPTIBLE); if (tty_hung_up_p(filp) || - !(ch->asyncflags & ASYNC_INITIALIZED)) { - if (ch->asyncflags & ASYNC_HUP_NOTIFY) + !(ch->port.flags & ASYNC_INITIALIZED)) { + if (ch->port.flags & ASYNC_HUP_NOTIFY) retval = -EAGAIN; else retval = -ERESTARTSYS; break; } - if (!(ch->asyncflags & ASYNC_CLOSING) && + if (!(ch->port.flags & ASYNC_CLOSING) && (do_clocal || (ch->imodem & ch->dcd))) break; if (signal_pending(current)) { @@ -864,17 +864,17 @@ static int block_til_ready(struct tty_struct *tty, } __set_current_state(TASK_RUNNING); - remove_wait_queue(&ch->open_wait, &wait); + remove_wait_queue(&ch->port.open_wait, &wait); if (!tty_hung_up_p(filp)) - ch->count++; - ch->blocked_open--; + ch->port.count++; + ch->port.blocked_open--; spin_unlock_irqrestore(&epca_lock, flags); if (retval) return retval; - ch->asyncflags |= ASYNC_NORMAL_ACTIVE; + ch->port.flags |= ASYNC_NORMAL_ACTIVE; return 0; } @@ -933,7 +933,7 @@ static int pc_open(struct tty_struct *tty, struct file *filp) * necessary because we do not wish to flush and shutdown the channel * until the last app holding the channel open, closes it. */ - ch->count++; + ch->port.count++; /* * Set a kernel structures pointer to our local channel structure. This * way we can get to it when passed only a tty struct. @@ -957,14 +957,14 @@ static int pc_open(struct tty_struct *tty, struct file *filp) writew(head, &bc->rout); /* Set the channels associated tty structure */ - ch->tty = tty; + ch->port.tty = tty; /* * The below routine generally sets up parity, baud, flow control * issues, etc.... It effect both control flags and input flags. */ epcaparam(tty, ch); - ch->asyncflags |= ASYNC_INITIALIZED; + ch->port.flags |= ASYNC_INITIALIZED; memoff(ch); spin_unlock_irqrestore(&epca_lock, flags); @@ -976,7 +976,7 @@ static int pc_open(struct tty_struct *tty, struct file *filp) * waiting for the line... */ spin_lock_irqsave(&epca_lock, flags); - ch->tty = tty; + ch->port.tty = tty; globalwinon(ch); /* Enable Digi Data events */ writeb(1, &bc->idata); @@ -1017,8 +1017,8 @@ static void __exit epca_module_exit(void) } ch = card_ptr[crd]; for (count = 0; count < bd->numports; count++, ch++) { - if (ch && ch->tty) - tty_hangup(ch->tty); + if (ch && ch->port.tty) + tty_hangup(ch->port.tty); } } pci_unregister_driver(&epca_driver); @@ -1427,7 +1427,7 @@ static void post_fep_init(unsigned int crd) ch->boardnum = crd; ch->channelnum = i; ch->magic = EPCA_MAGIC; - ch->tty = NULL; + ch->port.tty = NULL; if (shrinkmem) { fepcmd(ch, SETBUFFER, 32, 0, 0, 0); @@ -1510,10 +1510,10 @@ static void post_fep_init(unsigned int crd) ch->fepstopca = 0; ch->close_delay = 50; - ch->count = 0; - ch->blocked_open = 0; - init_waitqueue_head(&ch->open_wait); - init_waitqueue_head(&ch->close_wait); + ch->port.count = 0; + ch->port.blocked_open = 0; + init_waitqueue_head(&ch->port.open_wait); + init_waitqueue_head(&ch->port.close_wait); spin_unlock_irqrestore(&epca_lock, flags); } @@ -1633,15 +1633,15 @@ static void doevent(int crd) if (event & MODEMCHG_IND) { /* A modem signal change has been indicated */ ch->imodem = mstat; - if (ch->asyncflags & ASYNC_CHECK_CD) { + if (ch->port.flags & ASYNC_CHECK_CD) { /* We are now receiving dcd */ if (mstat & ch->dcd) - wake_up_interruptible(&ch->open_wait); + wake_up_interruptible(&ch->port.open_wait); else /* No dcd; hangup */ pc_sched_event(ch, EPCA_EVENT_HANGUP); } } - tty = ch->tty; + tty = ch->port.tty; if (tty) { if (event & BREAK_IND) { /* A break has been indicated */ @@ -1880,9 +1880,9 @@ static void epcaparam(struct tty_struct *tty, struct channel *ch) * that the driver will wait on carrier detect. */ if (ts->c_cflag & CLOCAL) - ch->asyncflags &= ~ASYNC_CHECK_CD; + ch->port.flags &= ~ASYNC_CHECK_CD; else - ch->asyncflags |= ASYNC_CHECK_CD; + ch->port.flags |= ASYNC_CHECK_CD; mval = ch->m_dtr | ch->m_rts; } /* End CBAUD not detected */ iflag = termios2digi_i(ch, ts->c_iflag); @@ -1972,7 +1972,7 @@ static void receive_data(struct channel *ch) globalwinon(ch); if (ch->statusflags & RXSTOPPED) return; - tty = ch->tty; + tty = ch->port.tty; if (tty) ts = tty->termios; bc = ch->brdchan; @@ -2032,7 +2032,7 @@ static void receive_data(struct channel *ch) globalwinon(ch); writew(tail, &bc->rout); /* Must be called with global data */ - tty_schedule_flip(ch->tty); + tty_schedule_flip(ch->port.tty); } static int info_ioctl(struct tty_struct *tty, struct file *file, @@ -2262,8 +2262,8 @@ static int pc_ioctl(struct tty_struct *tty, struct file *file, tty_wait_until_sent(tty, 0); } else { /* ldisc lock already held in ioctl */ - if (tty->ldisc.flush_buffer) - tty->ldisc.flush_buffer(tty); + if (tty->ldisc.ops->flush_buffer) + tty->ldisc.ops->flush_buffer(tty); } unlock_kernel(); /* Fall Thru */ @@ -2376,7 +2376,7 @@ static void pc_set_termios(struct tty_struct *tty, struct ktermios *old_termios) if (!(old_termios->c_cflag & CLOCAL) && (tty->termios->c_cflag & CLOCAL)) - wake_up_interruptible(&ch->open_wait); + wake_up_interruptible(&ch->port.open_wait); } /* End if channel valid */ } @@ -2386,13 +2386,13 @@ static void do_softint(struct work_struct *work) struct channel *ch = container_of(work, struct channel, tqueue); /* Called in response to a modem change event */ if (ch && ch->magic == EPCA_MAGIC) { - struct tty_struct *tty = ch->tty; + struct tty_struct *tty = ch->port.tty; if (tty && tty->driver_data) { if (test_and_clear_bit(EPCA_EVENT_HANGUP, &ch->event)) { tty_hangup(tty); - wake_up_interruptible(&ch->open_wait); - ch->asyncflags &= ~ASYNC_NORMAL_ACTIVE; + wake_up_interruptible(&ch->port.open_wait); + ch->port.flags &= ~ASYNC_NORMAL_ACTIVE; } } } diff --git a/drivers/char/epca.h b/drivers/char/epca.h index 3c77c02b5d65..d414bf2dbf7c 100644 --- a/drivers/char/epca.h +++ b/drivers/char/epca.h @@ -84,6 +84,7 @@ static char *board_desc[] = struct channel { long magic; + struct tty_port port; unsigned char boardnum; unsigned char channelnum; unsigned char omodem; /* FEP output modem status */ @@ -117,10 +118,7 @@ struct channel unsigned short rxbufhead; unsigned short rxbufsize; int close_delay; - int count; - int blocked_open; unsigned long event; - int asyncflags; uint dev; unsigned long statusflags; unsigned long c_iflag; @@ -132,9 +130,6 @@ struct channel struct board_info *board; struct board_chan __iomem *brdchan; struct digi_struct digiext; - struct tty_struct *tty; - wait_queue_head_t open_wait; - wait_queue_head_t close_wait; struct work_struct tqueue; struct global_data __iomem *mailbox; }; diff --git a/drivers/char/esp.c b/drivers/char/esp.c index 84840ba13ff0..2eaf09f93e3d 100644 --- a/drivers/char/esp.c +++ b/drivers/char/esp.c @@ -128,9 +128,9 @@ static struct tty_driver *esp_driver; #if defined(MODULE) && defined(SERIAL_DEBUG_MCOUNT) #define DBG_CNT(s) printk(KERN_DEBUG "(%s): [%x] refc=%d, serc=%d, ttyc=%d -> %s\n", \ - tty->name, info->flags, \ + tty->name, info->port.flags, \ serial_driver.refcount, \ - info->count, tty->count, s) + info->port.count, tty->count, s) #else #define DBG_CNT(s) #endif @@ -172,13 +172,13 @@ static inline int serial_paranoia_check(struct esp_struct *info, static inline unsigned int serial_in(struct esp_struct *info, int offset) { - return inb(info->port + offset); + return inb(info->io_port + offset); } static inline void serial_out(struct esp_struct *info, int offset, unsigned char value) { - outb(value, info->port+offset); + outb(value, info->io_port+offset); } /* @@ -273,7 +273,7 @@ static inline void release_pio_buffer(struct esp_pio_buffer *buf) static inline void receive_chars_pio(struct esp_struct *info, int num_bytes) { - struct tty_struct *tty = info->tty; + struct tty_struct *tty = info->port.tty; int i; struct esp_pio_buffer *pio_buf; struct esp_pio_buffer *err_buf; @@ -295,7 +295,7 @@ static inline void receive_chars_pio(struct esp_struct *info, int num_bytes) for (i = 0; i < num_bytes - 1; i += 2) { *((unsigned short *)(pio_buf->data + i)) = - inw(info->port + UART_ESI_RX); + inw(info->io_port + UART_ESI_RX); err_buf->data[i] = serial_in(info, UART_ESI_RWS); err_buf->data[i + 1] = (err_buf->data[i] >> 3) & status_mask; err_buf->data[i] &= status_mask; @@ -308,7 +308,7 @@ static inline void receive_chars_pio(struct esp_struct *info, int num_bytes) } /* make sure everything is still ok since interrupts were enabled */ - tty = info->tty; + tty = info->port.tty; if (!tty) { release_pio_buffer(pio_buf); @@ -325,7 +325,7 @@ static inline void receive_chars_pio(struct esp_struct *info, int num_bytes) if (err_buf->data[i] & 0x04) { flag = TTY_BREAK; - if (info->flags & ASYNC_SAK) + if (info->port.flags & ASYNC_SAK) do_SAK(tty); } else if (err_buf->data[i] & 0x02) flag = TTY_FRAME; @@ -370,7 +370,7 @@ static void receive_chars_dma(struct esp_struct *info, int num_bytes) static inline void receive_chars_dma_done(struct esp_struct *info, int status) { - struct tty_struct *tty = info->tty; + struct tty_struct *tty = info->port.tty; int num_bytes; unsigned long flags; @@ -396,7 +396,7 @@ static inline void receive_chars_dma_done(struct esp_struct *info, if (status & 0x10) { statflag = TTY_BREAK; (info->icount.brk)++; - if (info->flags & ASYNC_SAK) + if (info->port.flags & ASYNC_SAK) do_SAK(tty); } else if (status & 0x08) { statflag = TTY_FRAME; @@ -451,7 +451,7 @@ static inline void transmit_chars_pio(struct esp_struct *info, for (i = 0; i < space_avail - 1; i += 2) { outw(*((unsigned short *)(pio_buf->data + i)), - info->port + UART_ESI_TX); + info->io_port + UART_ESI_TX); } if (space_avail & 0x0001) @@ -470,8 +470,8 @@ static inline void transmit_chars_pio(struct esp_struct *info, } if (info->xmit_cnt < WAKEUP_CHARS) { - if (info->tty) - tty_wakeup(info->tty); + if (info->port.tty) + tty_wakeup(info->port.tty); #ifdef SERIAL_DEBUG_INTR printk("THRE..."); @@ -507,8 +507,8 @@ static inline void transmit_chars_dma(struct esp_struct *info, int num_bytes) info->xmit_tail = (info->xmit_tail + dma_bytes) & (ESP_XMIT_SIZE - 1); if (info->xmit_cnt < WAKEUP_CHARS) { - if (info->tty) - tty_wakeup(info->tty); + if (info->port.tty) + tty_wakeup(info->port.tty); #ifdef SERIAL_DEBUG_INTR printk("THRE..."); @@ -575,18 +575,18 @@ static void check_modem_status(struct esp_struct *info) wake_up_interruptible(&info->delta_msr_wait); } - if ((info->flags & ASYNC_CHECK_CD) && (status & UART_MSR_DDCD)) { + if ((info->port.flags & ASYNC_CHECK_CD) && (status & UART_MSR_DDCD)) { #if (defined(SERIAL_DEBUG_OPEN) || defined(SERIAL_DEBUG_INTR)) printk("ttys%d CD now %s...", info->line, (status & UART_MSR_DCD) ? "on" : "off"); #endif if (status & UART_MSR_DCD) - wake_up_interruptible(&info->open_wait); + wake_up_interruptible(&info->port.open_wait); else { #ifdef SERIAL_DEBUG_OPEN printk("scheduling hangup..."); #endif - tty_hangup(info->tty); + tty_hangup(info->port.tty); } } } @@ -609,7 +609,7 @@ static irqreturn_t rs_interrupt_single(int irq, void *dev_id) spin_lock(&info->lock); - if (!info->tty) { + if (!info->port.tty) { spin_unlock(&info->lock); return IRQ_NONE; } @@ -647,7 +647,7 @@ static irqreturn_t rs_interrupt_single(int irq, void *dev_id) num_bytes = serial_in(info, UART_ESI_STAT1) << 8; num_bytes |= serial_in(info, UART_ESI_STAT2); - num_bytes = tty_buffer_request_room(info->tty, num_bytes); + num_bytes = tty_buffer_request_room(info->port.tty, num_bytes); if (num_bytes) { if (dma_bytes || @@ -661,7 +661,7 @@ static irqreturn_t rs_interrupt_single(int irq, void *dev_id) if (!(info->stat_flags & (ESP_STAT_DMA_RX | ESP_STAT_DMA_TX)) && (scratch & 0x02) && (info->IER & UART_IER_THRI)) { - if ((info->xmit_cnt <= 0) || info->tty->stopped) { + if ((info->xmit_cnt <= 0) || info->port.tty->stopped) { info->IER &= ~UART_IER_THRI; serial_out(info, UART_ESI_CMD1, ESI_SET_SRV_MASK); serial_out(info, UART_ESI_CMD2, info->IER); @@ -782,7 +782,7 @@ static int startup(struct esp_struct *info) spin_lock_irqsave(&info->lock, flags); - if (info->flags & ASYNC_INITIALIZED) + if (info->port.flags & ASYNC_INITIALIZED) goto out; if (!info->xmit_buf) { @@ -806,7 +806,7 @@ static int startup(struct esp_struct *info) num_chars |= serial_in(info, UART_ESI_STAT2); while (num_chars > 1) { - inw(info->port + UART_ESI_RX); + inw(info->io_port + UART_ESI_RX); num_chars -= 2; } @@ -834,9 +834,9 @@ static int startup(struct esp_struct *info) if (retval) { if (capable(CAP_SYS_ADMIN)) { - if (info->tty) + if (info->port.tty) set_bit(TTY_IO_ERROR, - &info->tty->flags); + &info->port.tty->flags); retval = 0; } goto out_unlocked; @@ -874,30 +874,30 @@ static int startup(struct esp_struct *info) serial_out(info, UART_ESI_CMD1, ESI_SET_SRV_MASK); serial_out(info, UART_ESI_CMD2, info->IER); - if (info->tty) - clear_bit(TTY_IO_ERROR, &info->tty->flags); + if (info->port.tty) + clear_bit(TTY_IO_ERROR, &info->port.tty->flags); info->xmit_cnt = info->xmit_head = info->xmit_tail = 0; spin_unlock_irqrestore(&info->lock, flags); /* * Set up the tty->alt_speed kludge */ - if (info->tty) { - if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI) - info->tty->alt_speed = 57600; - if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI) - info->tty->alt_speed = 115200; - if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI) - info->tty->alt_speed = 230400; - if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP) - info->tty->alt_speed = 460800; + if (info->port.tty) { + if ((info->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI) + info->port.tty->alt_speed = 57600; + if ((info->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI) + info->port.tty->alt_speed = 115200; + if ((info->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI) + info->port.tty->alt_speed = 230400; + if ((info->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP) + info->port.tty->alt_speed = 460800; } /* * set the speed of the serial port */ change_speed(info); - info->flags |= ASYNC_INITIALIZED; + info->port.flags |= ASYNC_INITIALIZED; return 0; out: @@ -914,7 +914,7 @@ static void shutdown(struct esp_struct *info) { unsigned long flags, f; - if (!(info->flags & ASYNC_INITIALIZED)) + if (!(info->port.flags & ASYNC_INITIALIZED)) return; #ifdef SERIAL_DEBUG_OPEN @@ -951,7 +951,7 @@ static void shutdown(struct esp_struct *info) while (current_port) { if ((current_port != info) && - (current_port->flags & ASYNC_INITIALIZED)) + (current_port->port.flags & ASYNC_INITIALIZED)) break; current_port = current_port->next_port; @@ -974,7 +974,7 @@ static void shutdown(struct esp_struct *info) serial_out(info, UART_ESI_CMD1, ESI_SET_SRV_MASK); serial_out(info, UART_ESI_CMD2, 0x00); - if (!info->tty || (info->tty->termios->c_cflag & HUPCL)) + if (!info->port.tty || (info->port.tty->termios->c_cflag & HUPCL)) info->MCR &= ~(UART_MCR_DTR|UART_MCR_RTS); info->MCR &= ~UART_MCR_OUT2; @@ -982,10 +982,10 @@ static void shutdown(struct esp_struct *info) serial_out(info, UART_ESI_CMD2, UART_MCR); serial_out(info, UART_ESI_CMD2, info->MCR); - if (info->tty) - set_bit(TTY_IO_ERROR, &info->tty->flags); + if (info->port.tty) + set_bit(TTY_IO_ERROR, &info->port.tty->flags); - info->flags &= ~ASYNC_INITIALIZED; + info->port.flags &= ~ASYNC_INITIALIZED; spin_unlock_irqrestore(&info->lock, flags); } @@ -1002,10 +1002,10 @@ static void change_speed(struct esp_struct *info) unsigned char flow1 = 0, flow2 = 0; unsigned long flags; - if (!info->tty || !info->tty->termios) + if (!info->port.tty || !info->port.tty->termios) return; - cflag = info->tty->termios->c_cflag; - port = info->port; + cflag = info->port.tty->termios->c_cflag; + port = info->io_port; /* byte size and parity */ switch (cflag & CSIZE) { @@ -1029,9 +1029,9 @@ static void change_speed(struct esp_struct *info) if (cflag & CMSPAR) cval |= UART_LCR_SPAR; #endif - baud = tty_get_baud_rate(info->tty); + baud = tty_get_baud_rate(info->port.tty); if (baud == 38400 && - ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST)) + ((info->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST)) quot = info->custom_divisor; else { if (baud == 134) /* Special case since 134 is really 134.5 */ @@ -1046,49 +1046,49 @@ static void change_speed(struct esp_struct *info) if (baud) { /* Actual rate */ baud = BASE_BAUD/quot; - tty_encode_baud_rate(info->tty, baud, baud); + tty_encode_baud_rate(info->port.tty, baud, baud); } info->timeout = ((1024 * HZ * bits * quot) / BASE_BAUD) + (HZ / 50); /* CTS flow control flag and modem status interrupts */ /* info->IER &= ~UART_IER_MSI; */ if (cflag & CRTSCTS) { - info->flags |= ASYNC_CTS_FLOW; + info->port.flags |= ASYNC_CTS_FLOW; /* info->IER |= UART_IER_MSI; */ flow1 = 0x04; flow2 = 0x10; } else - info->flags &= ~ASYNC_CTS_FLOW; + info->port.flags &= ~ASYNC_CTS_FLOW; if (cflag & CLOCAL) - info->flags &= ~ASYNC_CHECK_CD; + info->port.flags &= ~ASYNC_CHECK_CD; else - info->flags |= ASYNC_CHECK_CD; + info->port.flags |= ASYNC_CHECK_CD; /* * Set up parity check flag */ info->read_status_mask = UART_LSR_OE | UART_LSR_THRE | UART_LSR_DR; - if (I_INPCK(info->tty)) + if (I_INPCK(info->port.tty)) info->read_status_mask |= UART_LSR_FE | UART_LSR_PE; - if (I_BRKINT(info->tty) || I_PARMRK(info->tty)) + if (I_BRKINT(info->port.tty) || I_PARMRK(info->port.tty)) info->read_status_mask |= UART_LSR_BI; info->ignore_status_mask = 0; #if 0 /* This should be safe, but for some broken bits of hardware... */ - if (I_IGNPAR(info->tty)) { + if (I_IGNPAR(info->port.tty)) { info->ignore_status_mask |= UART_LSR_PE | UART_LSR_FE; info->read_status_mask |= UART_LSR_PE | UART_LSR_FE; } #endif - if (I_IGNBRK(info->tty)) { + if (I_IGNBRK(info->port.tty)) { info->ignore_status_mask |= UART_LSR_BI; info->read_status_mask |= UART_LSR_BI; /* * If we're ignore parity and break indicators, ignore * overruns too. (For real raw support). */ - if (I_IGNPAR(info->tty)) { + if (I_IGNPAR(info->port.tty)) { info->ignore_status_mask |= UART_LSR_OE | \ UART_LSR_PE | UART_LSR_FE; info->read_status_mask |= UART_LSR_OE | \ @@ -1096,7 +1096,7 @@ static void change_speed(struct esp_struct *info) } } - if (I_IXOFF(info->tty)) + if (I_IXOFF(info->port.tty)) flow1 |= 0x81; spin_lock_irqsave(&info->lock, flags); @@ -1116,10 +1116,10 @@ static void change_speed(struct esp_struct *info) serial_out(info, UART_ESI_CMD2, flow2); /* set flow control characters (XON/XOFF only) */ - if (I_IXOFF(info->tty)) { + if (I_IXOFF(info->port.tty)) { serial_out(info, UART_ESI_CMD1, ESI_SET_FLOW_CHARS); - serial_out(info, UART_ESI_CMD2, START_CHAR(info->tty)); - serial_out(info, UART_ESI_CMD2, STOP_CHAR(info->tty)); + serial_out(info, UART_ESI_CMD2, START_CHAR(info->port.tty)); + serial_out(info, UART_ESI_CMD2, STOP_CHAR(info->port.tty)); serial_out(info, UART_ESI_CMD2, 0x10); serial_out(info, UART_ESI_CMD2, 0x21); switch (cflag & CSIZE) { @@ -1355,9 +1355,9 @@ static int get_serial_info(struct esp_struct *info, memset(&tmp, 0, sizeof(tmp)); tmp.type = PORT_16550A; tmp.line = info->line; - tmp.port = info->port; + tmp.port = info->io_port; tmp.irq = info->irq; - tmp.flags = info->flags; + tmp.flags = info->port.flags; tmp.xmit_fifo_size = 1024; tmp.baud_base = BASE_BAUD; tmp.close_delay = info->close_delay; @@ -1407,7 +1407,7 @@ static int set_serial_info(struct esp_struct *info, if ((new_serial.type != PORT_16550A) || (new_serial.hub6) || - (info->port != new_serial.port) || + (info->io_port != new_serial.port) || (new_serial.baud_base != BASE_BAUD) || (new_serial.irq > 15) || (new_serial.irq < 2) || @@ -1425,9 +1425,9 @@ static int set_serial_info(struct esp_struct *info, if (change_irq || (new_serial.close_delay != info->close_delay) || ((new_serial.flags & ~ASYNC_USR_MASK) != - (info->flags & ~ASYNC_USR_MASK))) + (info->port.flags & ~ASYNC_USR_MASK))) return -EPERM; - info->flags = ((info->flags & ~ASYNC_USR_MASK) | + info->port.flags = ((info->port.flags & ~ASYNC_USR_MASK) | (new_serial.flags & ASYNC_USR_MASK)); info->custom_divisor = new_serial.custom_divisor; } else { @@ -1441,9 +1441,9 @@ static int set_serial_info(struct esp_struct *info, if ((current_async->line >= info->line) && (current_async->line < (info->line + 8))) { if (current_async == info) { - if (current_async->count > 1) + if (current_async->port.count > 1) return -EBUSY; - } else if (current_async->count) + } else if (current_async->port.count) return -EBUSY; } @@ -1456,7 +1456,7 @@ static int set_serial_info(struct esp_struct *info, * At this point, we start making changes..... */ - info->flags = ((info->flags & ~ASYNC_FLAGS) | + info->port.flags = ((info->port.flags & ~ASYNC_FLAGS) | (new_serial.flags & ASYNC_FLAGS)); info->custom_divisor = new_serial.custom_divisor; info->close_delay = new_serial.close_delay * HZ/100; @@ -1487,18 +1487,18 @@ static int set_serial_info(struct esp_struct *info, } } - if (info->flags & ASYNC_INITIALIZED) { - if (((old_info.flags & ASYNC_SPD_MASK) != - (info->flags & ASYNC_SPD_MASK)) || + if (info->port.flags & ASYNC_INITIALIZED) { + if (((old_info.port.flags & ASYNC_SPD_MASK) != + (info->port.flags & ASYNC_SPD_MASK)) || (old_info.custom_divisor != info->custom_divisor)) { - if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI) - info->tty->alt_speed = 57600; - if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI) - info->tty->alt_speed = 115200; - if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI) - info->tty->alt_speed = 230400; - if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP) - info->tty->alt_speed = 460800; + if ((info->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI) + info->port.tty->alt_speed = 57600; + if ((info->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI) + info->port.tty->alt_speed = 115200; + if ((info->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI) + info->port.tty->alt_speed = 230400; + if ((info->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP) + info->port.tty->alt_speed = 460800; change_speed(info); } } else @@ -1554,9 +1554,9 @@ static int set_esp_config(struct esp_struct *info, while (current_async) { if (current_async == info) { - if (current_async->count > 1) + if (current_async->port.count > 1) return -EBUSY; - } else if (current_async->count) + } else if (current_async->port.count) return -EBUSY; current_async = current_async->next_port; @@ -1578,7 +1578,7 @@ static int set_esp_config(struct esp_struct *info, spin_unlock_irqrestore(&info->lock, flags); } else { /* DMA mode to PIO mode only */ - if (info->count > 1) + if (info->port.count > 1) return -EBUSY; shutdown(info); @@ -1634,7 +1634,7 @@ static int set_esp_config(struct esp_struct *info, spin_unlock_irqrestore(&info->lock, flags); } - if (!(info->flags & ASYNC_INITIALIZED)) + if (!(info->port.flags & ASYNC_INITIALIZED)) retval = startup(info); return retval; @@ -1917,9 +1917,9 @@ static void rs_close(struct tty_struct *tty, struct file *filp) #ifdef SERIAL_DEBUG_OPEN printk(KERN_DEBUG "rs_close ttys%d, count = %d\n", - info->line, info->count); + info->line, info->port.count); #endif - if (tty->count == 1 && info->count != 1) { + if (tty->count == 1 && info->port.count != 1) { /* * Uh, oh. tty->count is 1, which means that the tty * structure will be freed. Info->count should always @@ -1927,19 +1927,19 @@ static void rs_close(struct tty_struct *tty, struct file *filp) * one, we've got real problems, since it means the * serial port won't be shutdown. */ - printk(KERN_DEBUG "rs_close: bad serial port count; tty->count is 1, info->count is %d\n", info->count); - info->count = 1; + printk(KERN_DEBUG "rs_close: bad serial port count; tty->count is 1, info->port.count is %d\n", info->port.count); + info->port.count = 1; } - if (--info->count < 0) { + if (--info->port.count < 0) { printk(KERN_ERR "rs_close: bad serial port count for ttys%d: %d\n", - info->line, info->count); - info->count = 0; + info->line, info->port.count); + info->port.count = 0; } - if (info->count) { + if (info->port.count) { DBG_CNT("before DEC-2"); goto out; } - info->flags |= ASYNC_CLOSING; + info->port.flags |= ASYNC_CLOSING; spin_unlock_irqrestore(&info->lock, flags); /* @@ -1958,7 +1958,7 @@ static void rs_close(struct tty_struct *tty, struct file *filp) /* info->IER &= ~UART_IER_RLSI; */ info->IER &= ~UART_IER_RDI; info->read_status_mask &= ~UART_LSR_DR; - if (info->flags & ASYNC_INITIALIZED) { + if (info->port.flags & ASYNC_INITIALIZED) { spin_lock_irqsave(&info->lock, flags); serial_out(info, UART_ESI_CMD1, ESI_SET_SRV_MASK); @@ -1981,15 +1981,15 @@ static void rs_close(struct tty_struct *tty, struct file *filp) rs_flush_buffer(tty); tty_ldisc_flush(tty); tty->closing = 0; - info->tty = NULL; + info->port.tty = NULL; - if (info->blocked_open) { + if (info->port.blocked_open) { if (info->close_delay) msleep_interruptible(jiffies_to_msecs(info->close_delay)); - wake_up_interruptible(&info->open_wait); + wake_up_interruptible(&info->port.open_wait); } - info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING); - wake_up_interruptible(&info->close_wait); + info->port.flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING); + wake_up_interruptible(&info->port.close_wait); return; out: @@ -2047,10 +2047,10 @@ static void esp_hangup(struct tty_struct *tty) rs_flush_buffer(tty); shutdown(info); - info->count = 0; - info->flags &= ~ASYNC_NORMAL_ACTIVE; - info->tty = NULL; - wake_up_interruptible(&info->open_wait); + info->port.count = 0; + info->port.flags &= ~ASYNC_NORMAL_ACTIVE; + info->port.tty = NULL; + wake_up_interruptible(&info->port.open_wait); } /* @@ -2071,11 +2071,11 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp, * until it's done, and then try again. */ if (tty_hung_up_p(filp) || - (info->flags & ASYNC_CLOSING)) { - if (info->flags & ASYNC_CLOSING) - interruptible_sleep_on(&info->close_wait); + (info->port.flags & ASYNC_CLOSING)) { + if (info->port.flags & ASYNC_CLOSING) + interruptible_sleep_on(&info->port.close_wait); #ifdef SERIAL_DO_RESTART - if (info->flags & ASYNC_HUP_NOTIFY) + if (info->port.flags & ASYNC_HUP_NOTIFY) return -EAGAIN; else return -ERESTARTSYS; @@ -2090,7 +2090,7 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp, */ if ((filp->f_flags & O_NONBLOCK) || (tty->flags & (1 << TTY_IO_ERROR))) { - info->flags |= ASYNC_NORMAL_ACTIVE; + info->port.flags |= ASYNC_NORMAL_ACTIVE; return 0; } @@ -2100,20 +2100,20 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp, /* * Block waiting for the carrier detect and the line to become * free (i.e., not in use by the callout). While we are in - * this loop, info->count is dropped by one, so that + * this loop, info->port.count is dropped by one, so that * rs_close() knows when to free things. We restore it upon * exit, either normal or abnormal. */ retval = 0; - add_wait_queue(&info->open_wait, &wait); + add_wait_queue(&info->port.open_wait, &wait); #ifdef SERIAL_DEBUG_OPEN printk(KERN_DEBUG "block_til_ready before block: ttys%d, count = %d\n", - info->line, info->count); + info->line, info->port.count); #endif spin_lock_irqsave(&info->lock, flags); if (!tty_hung_up_p(filp)) - info->count--; - info->blocked_open++; + info->port.count--; + info->port.blocked_open++; while (1) { if ((tty->termios->c_cflag & CBAUD)) { unsigned int scratch; @@ -2128,9 +2128,9 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp, } set_current_state(TASK_INTERRUPTIBLE); if (tty_hung_up_p(filp) || - !(info->flags & ASYNC_INITIALIZED)) { + !(info->port.flags & ASYNC_INITIALIZED)) { #ifdef SERIAL_DO_RESTART - if (info->flags & ASYNC_HUP_NOTIFY) + if (info->port.flags & ASYNC_HUP_NOTIFY) retval = -EAGAIN; else retval = -ERESTARTSYS; @@ -2144,7 +2144,7 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp, if (serial_in(info, UART_ESI_STAT2) & UART_MSR_DCD) do_clocal = 1; - if (!(info->flags & ASYNC_CLOSING) && + if (!(info->port.flags & ASYNC_CLOSING) && (do_clocal)) break; if (signal_pending(current)) { @@ -2153,25 +2153,25 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp, } #ifdef SERIAL_DEBUG_OPEN printk(KERN_DEBUG "block_til_ready blocking: ttys%d, count = %d\n", - info->line, info->count); + info->line, info->port.count); #endif spin_unlock_irqrestore(&info->lock, flags); schedule(); spin_lock_irqsave(&info->lock, flags); } set_current_state(TASK_RUNNING); - remove_wait_queue(&info->open_wait, &wait); + remove_wait_queue(&info->port.open_wait, &wait); if (!tty_hung_up_p(filp)) - info->count++; - info->blocked_open--; + info->port.count++; + info->port.blocked_open--; spin_unlock_irqrestore(&info->lock, flags); #ifdef SERIAL_DEBUG_OPEN printk(KERN_DEBUG "block_til_ready after blocking: ttys%d, count = %d\n", - info->line, info->count); + info->line, info->port.count); #endif if (retval) return retval; - info->flags |= ASYNC_NORMAL_ACTIVE; + info->port.flags |= ASYNC_NORMAL_ACTIVE; return 0; } @@ -2204,12 +2204,12 @@ static int esp_open(struct tty_struct *tty, struct file *filp) } #ifdef SERIAL_DEBUG_OPEN - printk(KERN_DEBUG "esp_open %s, count = %d\n", tty->name, info->count); + printk(KERN_DEBUG "esp_open %s, count = %d\n", tty->name, info->port.count); #endif spin_lock_irqsave(&info->lock, flags); - info->count++; + info->port.count++; tty->driver_data = info; - info->tty = tty; + info->port.tty = tty; spin_unlock_irqrestore(&info->lock, flags); @@ -2263,7 +2263,7 @@ static int autoconfig(struct esp_struct *info) int port_detected = 0; unsigned long flags; - if (!request_region(info->port, REGION_SIZE, "esp serial")) + if (!request_region(info->io_port, REGION_SIZE, "esp serial")) return -EIO; spin_lock_irqsave(&info->lock, flags); @@ -2300,7 +2300,7 @@ static int autoconfig(struct esp_struct *info) } } if (!port_detected) - release_region(info->port, REGION_SIZE); + release_region(info->io_port, REGION_SIZE); spin_unlock_irqrestore(&info->lock, flags); return (port_detected); @@ -2414,7 +2414,7 @@ static int __init espserial_init(void) offset = 0; do { - info->port = esp[i] + offset; + info->io_port = esp[i] + offset; info->irq = irq[i]; info->line = (i * 8) + (offset / 8); @@ -2425,9 +2425,9 @@ static int __init espserial_init(void) } info->custom_divisor = (divisor[i] >> (offset / 2)) & 0xf; - info->flags = STD_COM_FLAGS; + info->port.flags = STD_COM_FLAGS; if (info->custom_divisor) - info->flags |= ASYNC_SPD_CUST; + info->port.flags |= ASYNC_SPD_CUST; info->magic = ESP_MAGIC; info->close_delay = 5*HZ/10; info->closing_wait = 30*HZ; @@ -2436,13 +2436,13 @@ static int __init espserial_init(void) info->config.flow_off = flow_off; info->config.pio_threshold = pio_threshold; info->next_port = ports; - init_waitqueue_head(&info->open_wait); - init_waitqueue_head(&info->close_wait); + init_waitqueue_head(&info->port.open_wait); + init_waitqueue_head(&info->port.close_wait); init_waitqueue_head(&info->delta_msr_wait); init_waitqueue_head(&info->break_wait); ports = info; printk(KERN_INFO "ttyP%d at 0x%04x (irq = %d) is an ESP ", - info->line, info->port, info->irq); + info->line, info->io_port, info->irq); if (info->line % 8) { printk("secondary port\n"); @@ -2498,8 +2498,8 @@ static void __exit espserial_exit(void) put_tty_driver(esp_driver); while (ports) { - if (ports->port) - release_region(ports->port, REGION_SIZE); + if (ports->io_port) + release_region(ports->io_port, REGION_SIZE); temp_async = ports->next_port; kfree(ports); ports = temp_async; diff --git a/drivers/char/generic_serial.c b/drivers/char/generic_serial.c index 252f73e48596..19d3afb0e50c 100644 --- a/drivers/char/generic_serial.c +++ b/drivers/char/generic_serial.c @@ -60,7 +60,7 @@ int gs_put_char(struct tty_struct * tty, unsigned char ch) if (!port) return 0; - if (! (port->flags & ASYNC_INITIALIZED)) return 0; + if (! (port->port.flags & ASYNC_INITIALIZED)) return 0; /* Take a lock on the serial tranmit buffer! */ mutex_lock(& port->port_write_mutex); @@ -103,7 +103,7 @@ int gs_write(struct tty_struct * tty, if (!port) return 0; - if (! (port->flags & ASYNC_INITIALIZED)) + if (! (port->port.flags & ASYNC_INITIALIZED)) return 0; /* get exclusive "write" access to this port (problem 3) */ @@ -141,13 +141,13 @@ int gs_write(struct tty_struct * tty, mutex_unlock(& port->port_write_mutex); gs_dprintk (GS_DEBUG_WRITE, "write: interrupts are %s\n", - (port->flags & GS_TX_INTEN)?"enabled": "disabled"); + (port->port.flags & GS_TX_INTEN)?"enabled": "disabled"); if (port->xmit_cnt && !tty->stopped && !tty->hw_stopped && - !(port->flags & GS_TX_INTEN)) { - port->flags |= GS_TX_INTEN; + !(port->port.flags & GS_TX_INTEN)) { + port->port.flags |= GS_TX_INTEN; port->rd->enable_tx_interrupts (port); } func_exit (); @@ -208,7 +208,7 @@ static int gs_wait_tx_flushed (void * ptr, unsigned long timeout) gs_dprintk (GS_DEBUG_FLUSH, "port=%p.\n", port); if (port) { gs_dprintk (GS_DEBUG_FLUSH, "xmit_cnt=%x, xmit_buf=%p, tty=%p.\n", - port->xmit_cnt, port->xmit_buf, port->tty); + port->xmit_cnt, port->xmit_buf, port->port.tty); } if (!port || port->xmit_cnt < 0 || !port->xmit_buf) { @@ -217,7 +217,7 @@ static int gs_wait_tx_flushed (void * ptr, unsigned long timeout) return -EINVAL; /* This is an error which we don't know how to handle. */ } - rcib = gs_real_chars_in_buffer(port->tty); + rcib = gs_real_chars_in_buffer(port->port.tty); if(rcib <= 0) { gs_dprintk (GS_DEBUG_FLUSH, "nothing to wait for.\n"); @@ -236,7 +236,7 @@ static int gs_wait_tx_flushed (void * ptr, unsigned long timeout) /* the expression is actually jiffies < end_jiffies, but that won't work around the wraparound. Tricky eh? */ - while ((charsleft = gs_real_chars_in_buffer (port->tty)) && + while ((charsleft = gs_real_chars_in_buffer (port->port.tty)) && time_after (end_jiffies, jiffies)) { /* Units check: chars * (bits/char) * (jiffies /sec) / (bits/sec) = jiffies! @@ -309,7 +309,7 @@ void gs_flush_chars(struct tty_struct * tty) } /* Beats me -- REW */ - port->flags |= GS_TX_INTEN; + port->port.flags |= GS_TX_INTEN; port->rd->enable_tx_interrupts (port); func_exit (); } @@ -329,8 +329,8 @@ void gs_stop(struct tty_struct * tty) if (port->xmit_cnt && port->xmit_buf && - (port->flags & GS_TX_INTEN) ) { - port->flags &= ~GS_TX_INTEN; + (port->port.flags & GS_TX_INTEN) ) { + port->port.flags &= ~GS_TX_INTEN; port->rd->disable_tx_interrupts (port); } func_exit (); @@ -349,8 +349,8 @@ void gs_start(struct tty_struct * tty) if (port->xmit_cnt && port->xmit_buf && - !(port->flags & GS_TX_INTEN) ) { - port->flags |= GS_TX_INTEN; + !(port->port.flags & GS_TX_INTEN) ) { + port->port.flags |= GS_TX_INTEN; port->rd->enable_tx_interrupts (port); } func_exit (); @@ -365,7 +365,7 @@ static void gs_shutdown_port (struct gs_port *port) if (!port) return; - if (!(port->flags & ASYNC_INITIALIZED)) + if (!(port->port.flags & ASYNC_INITIALIZED)) return; spin_lock_irqsave(&port->driver_lock, flags); @@ -375,12 +375,12 @@ static void gs_shutdown_port (struct gs_port *port) port->xmit_buf = NULL; } - if (port->tty) - set_bit(TTY_IO_ERROR, &port->tty->flags); + if (port->port.tty) + set_bit(TTY_IO_ERROR, &port->port.tty->flags); port->rd->shutdown_port (port); - port->flags &= ~ASYNC_INITIALIZED; + port->port.flags &= ~ASYNC_INITIALIZED; spin_unlock_irqrestore(&port->driver_lock, flags); func_exit(); @@ -396,16 +396,16 @@ void gs_hangup(struct tty_struct *tty) if (!tty) return; port = tty->driver_data; - tty = port->tty; + tty = port->port.tty; if (!tty) return; gs_shutdown_port (port); - port->flags &= ~(ASYNC_NORMAL_ACTIVE|GS_ACTIVE); - port->tty = NULL; - port->count = 0; + port->port.flags &= ~(ASYNC_NORMAL_ACTIVE|GS_ACTIVE); + port->port.tty = NULL; + port->port.count = 0; - wake_up_interruptible(&port->open_wait); + wake_up_interruptible(&port->port.open_wait); func_exit (); } @@ -424,7 +424,7 @@ int gs_block_til_ready(void *port_, struct file * filp) if (!port) return 0; - tty = port->tty; + tty = port->port.tty; if (!tty) return 0; @@ -433,9 +433,9 @@ int gs_block_til_ready(void *port_, struct file * filp) * If the device is in the middle of being closed, then block * until it's done, and then try again. */ - if (tty_hung_up_p(filp) || port->flags & ASYNC_CLOSING) { - interruptible_sleep_on(&port->close_wait); - if (port->flags & ASYNC_HUP_NOTIFY) + if (tty_hung_up_p(filp) || port->port.flags & ASYNC_CLOSING) { + interruptible_sleep_on(&port->port.close_wait); + if (port->port.flags & ASYNC_HUP_NOTIFY) return -EAGAIN; else return -ERESTARTSYS; @@ -449,7 +449,7 @@ int gs_block_til_ready(void *port_, struct file * filp) */ if ((filp->f_flags & O_NONBLOCK) || (tty->flags & (1 << TTY_IO_ERROR))) { - port->flags |= ASYNC_NORMAL_ACTIVE; + port->port.flags |= ASYNC_NORMAL_ACTIVE; return 0; } @@ -461,34 +461,34 @@ int gs_block_til_ready(void *port_, struct file * filp) /* * Block waiting for the carrier detect and the line to become * free (i.e., not in use by the callout). While we are in - * this loop, port->count is dropped by one, so that + * this loop, port->port.count is dropped by one, so that * rs_close() knows when to free things. We restore it upon * exit, either normal or abnormal. */ retval = 0; - add_wait_queue(&port->open_wait, &wait); + add_wait_queue(&port->port.open_wait, &wait); gs_dprintk (GS_DEBUG_BTR, "after add waitq.\n"); spin_lock_irqsave(&port->driver_lock, flags); if (!tty_hung_up_p(filp)) { - port->count--; + port->port.count--; } spin_unlock_irqrestore(&port->driver_lock, flags); - port->blocked_open++; + port->port.blocked_open++; while (1) { CD = port->rd->get_CD (port); gs_dprintk (GS_DEBUG_BTR, "CD is now %d.\n", CD); set_current_state (TASK_INTERRUPTIBLE); if (tty_hung_up_p(filp) || - !(port->flags & ASYNC_INITIALIZED)) { - if (port->flags & ASYNC_HUP_NOTIFY) + !(port->port.flags & ASYNC_INITIALIZED)) { + if (port->port.flags & ASYNC_HUP_NOTIFY) retval = -EAGAIN; else retval = -ERESTARTSYS; break; } - if (!(port->flags & ASYNC_CLOSING) && + if (!(port->port.flags & ASYNC_CLOSING) && (do_clocal || CD)) break; gs_dprintk (GS_DEBUG_BTR, "signal_pending is now: %d (%lx)\n", @@ -500,17 +500,17 @@ int gs_block_til_ready(void *port_, struct file * filp) schedule(); } gs_dprintk (GS_DEBUG_BTR, "Got out of the loop. (%d)\n", - port->blocked_open); + port->port.blocked_open); set_current_state (TASK_RUNNING); - remove_wait_queue(&port->open_wait, &wait); + remove_wait_queue(&port->port.open_wait, &wait); if (!tty_hung_up_p(filp)) { - port->count++; + port->port.count++; } - port->blocked_open--; + port->port.blocked_open--; if (retval) return retval; - port->flags |= ASYNC_NORMAL_ACTIVE; + port->port.flags |= ASYNC_NORMAL_ACTIVE; func_exit (); return 0; } @@ -529,10 +529,10 @@ void gs_close(struct tty_struct * tty, struct file * filp) if (!port) return; - if (!port->tty) { + if (!port->port.tty) { /* This seems to happen when this is called from vhangup. */ - gs_dprintk (GS_DEBUG_CLOSE, "gs: Odd: port->tty is NULL\n"); - port->tty = tty; + gs_dprintk (GS_DEBUG_CLOSE, "gs: Odd: port->port.tty is NULL\n"); + port->port.tty = tty; } spin_lock_irqsave(&port->driver_lock, flags); @@ -545,23 +545,23 @@ void gs_close(struct tty_struct * tty, struct file * filp) return; } - if ((tty->count == 1) && (port->count != 1)) { + if ((tty->count == 1) && (port->port.count != 1)) { printk(KERN_ERR "gs: gs_close port %p: bad port count;" - " tty->count is 1, port count is %d\n", port, port->count); - port->count = 1; + " tty->count is 1, port count is %d\n", port, port->port.count); + port->port.count = 1; } - if (--port->count < 0) { - printk(KERN_ERR "gs: gs_close port %p: bad port count: %d\n", port, port->count); - port->count = 0; + if (--port->port.count < 0) { + printk(KERN_ERR "gs: gs_close port %p: bad port count: %d\n", port, port->port.count); + port->port.count = 0; } - if (port->count) { - gs_dprintk(GS_DEBUG_CLOSE, "gs_close port %p: count: %d\n", port, port->count); + if (port->port.count) { + gs_dprintk(GS_DEBUG_CLOSE, "gs_close port %p: count: %d\n", port, port->port.count); spin_unlock_irqrestore(&port->driver_lock, flags); func_exit (); return; } - port->flags |= ASYNC_CLOSING; + port->port.flags |= ASYNC_CLOSING; /* * Now we wait for the transmit buffer to clear; and we notify @@ -585,7 +585,7 @@ void gs_close(struct tty_struct * tty, struct file * filp) if (port->closing_wait != ASYNC_CLOSING_WAIT_NONE) gs_wait_tx_flushed (port, port->closing_wait); - port->flags &= ~GS_ACTIVE; + port->port.flags &= ~GS_ACTIVE; gs_flush_buffer(tty); @@ -595,18 +595,18 @@ void gs_close(struct tty_struct * tty, struct file * filp) port->event = 0; port->rd->close (port); port->rd->shutdown_port (port); - port->tty = NULL; + port->port.tty = NULL; - if (port->blocked_open) { + if (port->port.blocked_open) { if (port->close_delay) { spin_unlock_irqrestore(&port->driver_lock, flags); msleep_interruptible(jiffies_to_msecs(port->close_delay)); spin_lock_irqsave(&port->driver_lock, flags); } - wake_up_interruptible(&port->open_wait); + wake_up_interruptible(&port->port.open_wait); } - port->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING | ASYNC_INITIALIZED); - wake_up_interruptible(&port->close_wait); + port->port.flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING | ASYNC_INITIALIZED); + wake_up_interruptible(&port->port.close_wait); func_exit (); } @@ -626,10 +626,10 @@ void gs_set_termios (struct tty_struct * tty, port = tty->driver_data; if (!port) return; - if (!port->tty) { + if (!port->port.tty) { /* This seems to happen when this is called after gs_close. */ - gs_dprintk (GS_DEBUG_TERMIOS, "gs: Odd: port->tty is NULL\n"); - port->tty = tty; + gs_dprintk (GS_DEBUG_TERMIOS, "gs: Odd: port->port.tty is NULL\n"); + port->port.tty = tty; } @@ -651,15 +651,15 @@ void gs_set_termios (struct tty_struct * tty, baudrate = tty_get_baud_rate(tty); if ((tiosp->c_cflag & CBAUD) == B38400) { - if ( (port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI) + if ( (port->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI) baudrate = 57600; - else if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI) + else if ((port->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI) baudrate = 115200; - else if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI) + else if ((port->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI) baudrate = 230400; - else if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP) + else if ((port->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP) baudrate = 460800; - else if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST) + else if ((port->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST) baudrate = (port->baud_base / port->custom_divisor); } @@ -715,7 +715,7 @@ int gs_init_port(struct gs_port *port) func_enter (); - if (port->flags & ASYNC_INITIALIZED) { + if (port->port.flags & ASYNC_INITIALIZED) { func_exit (); return 0; } @@ -737,15 +737,15 @@ int gs_init_port(struct gs_port *port) } spin_lock_irqsave (&port->driver_lock, flags); - if (port->tty) - clear_bit(TTY_IO_ERROR, &port->tty->flags); + if (port->port.tty) + clear_bit(TTY_IO_ERROR, &port->port.tty->flags); mutex_init(&port->port_write_mutex); port->xmit_cnt = port->xmit_head = port->xmit_tail = 0; spin_unlock_irqrestore(&port->driver_lock, flags); - gs_set_termios(port->tty, NULL); + gs_set_termios(port->port.tty, NULL); spin_lock_irqsave (&port->driver_lock, flags); - port->flags |= ASYNC_INITIALIZED; - port->flags &= ~GS_TX_INTEN; + port->port.flags |= ASYNC_INITIALIZED; + port->port.flags &= ~GS_TX_INTEN; spin_unlock_irqrestore(&port->driver_lock, flags); func_exit (); @@ -764,11 +764,11 @@ int gs_setserial(struct gs_port *port, struct serial_struct __user *sp) if ((sio.baud_base != port->baud_base) || (sio.close_delay != port->close_delay) || ((sio.flags & ~ASYNC_USR_MASK) != - (port->flags & ~ASYNC_USR_MASK))) + (port->port.flags & ~ASYNC_USR_MASK))) return(-EPERM); } - port->flags = (port->flags & ~ASYNC_USR_MASK) | + port->port.flags = (port->port.flags & ~ASYNC_USR_MASK) | (sio.flags & ASYNC_USR_MASK); port->baud_base = sio.baud_base; @@ -776,7 +776,7 @@ int gs_setserial(struct gs_port *port, struct serial_struct __user *sp) port->closing_wait = sio.closing_wait; port->custom_divisor = sio.custom_divisor; - gs_set_termios (port->tty, NULL); + gs_set_termios (port->port.tty, NULL); return 0; } @@ -793,7 +793,7 @@ int gs_getserial(struct gs_port *port, struct serial_struct __user *sp) struct serial_struct sio; memset(&sio, 0, sizeof(struct serial_struct)); - sio.flags = port->flags; + sio.flags = port->port.flags; sio.baud_base = port->baud_base; sio.close_delay = port->close_delay; sio.closing_wait = port->closing_wait; @@ -821,10 +821,10 @@ void gs_got_break(struct gs_port *port) { func_enter (); - tty_insert_flip_char(port->tty, 0, TTY_BREAK); - tty_schedule_flip(port->tty); - if (port->flags & ASYNC_SAK) { - do_SAK (port->tty); + tty_insert_flip_char(port->port.tty, 0, TTY_BREAK); + tty_schedule_flip(port->port.tty); + if (port->port.flags & ASYNC_SAK) { + do_SAK (port->port.tty); } func_exit (); diff --git a/drivers/char/ip2/i2lib.c b/drivers/char/ip2/i2lib.c index 938879cc7bcc..0061e18aff60 100644 --- a/drivers/char/ip2/i2lib.c +++ b/drivers/char/ip2/i2lib.c @@ -868,11 +868,11 @@ i2Input(i2ChanStrPtr pCh) amountToMove = count; } // Move the first block - pCh->pTTY->ldisc.receive_buf( pCh->pTTY, + pCh->pTTY->ldisc.ops->receive_buf( pCh->pTTY, &(pCh->Ibuf[stripIndex]), NULL, amountToMove ); // If we needed to wrap, do the second data move if (count > amountToMove) { - pCh->pTTY->ldisc.receive_buf( pCh->pTTY, + pCh->pTTY->ldisc.ops->receive_buf( pCh->pTTY, pCh->Ibuf, NULL, count - amountToMove ); } // Bump and wrap the stripIndex all at once by the amount of data read. This diff --git a/drivers/char/ip2/ip2main.c b/drivers/char/ip2/ip2main.c index 9a2394cda943..5dc74404058f 100644 --- a/drivers/char/ip2/ip2main.c +++ b/drivers/char/ip2/ip2main.c @@ -1289,11 +1289,12 @@ static void do_input(struct work_struct *work) // code duplicated from n_tty (ldisc) static inline void isig(int sig, struct tty_struct *tty, int flush) { + /* FIXME: This is completely bogus */ if (tty->pgrp) kill_pgrp(tty->pgrp, sig, 1); if (flush || !L_NOFLSH(tty)) { - if ( tty->ldisc.flush_buffer ) - tty->ldisc.flush_buffer(tty); + if ( tty->ldisc.ops->flush_buffer ) + tty->ldisc.ops->flush_buffer(tty); i2InputFlush( tty->driver_data ); } } @@ -1342,7 +1343,7 @@ static void do_status(struct work_struct *work) } tmp = pCh->pTTY->real_raw; pCh->pTTY->real_raw = 0; - pCh->pTTY->ldisc.receive_buf( pCh->pTTY, &brkc, &brkf, 1 ); + pCh->pTTY->ldisc->ops.receive_buf( pCh->pTTY, &brkc, &brkf, 1 ); pCh->pTTY->real_raw = tmp; } #endif /* NEVER_HAPPENS_AS_SETUP_XXX */ diff --git a/drivers/char/isicom.c b/drivers/char/isicom.c index 4f3cefa8eb0e..d4281df10c22 100644 --- a/drivers/char/isicom.c +++ b/drivers/char/isicom.c @@ -198,17 +198,10 @@ struct isi_board { struct isi_port { unsigned short magic; - unsigned int flags; - int count; - int blocked_open; - int close_delay; + struct tty_port port; u16 channel; u16 status; - u16 closing_wait; struct isi_board *card; - struct tty_struct *tty; - wait_queue_head_t close_wait; - wait_queue_head_t open_wait; unsigned char *xmit_buf; int xmit_head; int xmit_tail; @@ -430,11 +423,11 @@ static void isicom_tx(unsigned long _data) for (; count > 0; count--, port++) { /* port not active or tx disabled to force flow control */ - if (!(port->flags & ASYNC_INITIALIZED) || + if (!(port->port.flags & ASYNC_INITIALIZED) || !(port->status & ISI_TXOK)) continue; - tty = port->tty; + tty = port->port.tty; if (tty == NULL) continue; @@ -458,7 +451,7 @@ static void isicom_tx(unsigned long _data) if (residue == YES) { residue = NO; if (cnt > 0) { - wrd |= (port->xmit_buf[port->xmit_tail] + wrd |= (port->port.xmit_buf[port->xmit_tail] << 8); port->xmit_tail = (port->xmit_tail + 1) & (SERIAL_XMIT_SIZE - 1); @@ -474,14 +467,14 @@ static void isicom_tx(unsigned long _data) if (cnt <= 0) break; word_count = cnt >> 1; - outsw(base, port->xmit_buf+port->xmit_tail, word_count); + outsw(base, port->port.xmit_buf+port->xmit_tail, word_count); port->xmit_tail = (port->xmit_tail + (word_count << 1)) & (SERIAL_XMIT_SIZE - 1); txcount -= (word_count << 1); port->xmit_cnt -= (word_count << 1); if (cnt & 0x0001) { residue = YES; - wrd = port->xmit_buf[port->xmit_tail]; + wrd = port->port.xmit_buf[port->xmit_tail]; port->xmit_tail = (port->xmit_tail + 1) & (SERIAL_XMIT_SIZE - 1); port->xmit_cnt--; @@ -548,13 +541,13 @@ static irqreturn_t isicom_interrupt(int irq, void *dev_id) return IRQ_HANDLED; } port = card->ports + channel; - if (!(port->flags & ASYNC_INITIALIZED)) { + if (!(port->port.flags & ASYNC_INITIALIZED)) { outw(0x0000, base+0x04); /* enable interrupts */ spin_unlock(&card->card_lock); return IRQ_HANDLED; } - tty = port->tty; + tty = port->port.tty; if (tty == NULL) { word_count = byte_count >> 1; while (byte_count > 1) { @@ -572,7 +565,7 @@ static irqreturn_t isicom_interrupt(int irq, void *dev_id) header = inw(base); switch (header & 0xff) { case 0: /* Change in EIA signals */ - if (port->flags & ASYNC_CHECK_CD) { + if (port->port.flags & ASYNC_CHECK_CD) { if (port->status & ISI_DCD) { if (!(header & ISI_DCD)) { /* Carrier has been lost */ @@ -585,7 +578,7 @@ static irqreturn_t isicom_interrupt(int irq, void *dev_id) /* Carrier has been detected */ pr_dbg("interrupt: DCD->high.\n"); port->status |= ISI_DCD; - wake_up_interruptible(&port->open_wait); + wake_up_interruptible(&port->port.open_wait); } } else { if (header & ISI_DCD) @@ -594,17 +587,17 @@ static irqreturn_t isicom_interrupt(int irq, void *dev_id) port->status &= ~ISI_DCD; } - if (port->flags & ASYNC_CTS_FLOW) { - if (port->tty->hw_stopped) { + if (port->port.flags & ASYNC_CTS_FLOW) { + if (port->port.tty->hw_stopped) { if (header & ISI_CTS) { - port->tty->hw_stopped = 0; + port->port.tty->hw_stopped = 0; /* start tx ing */ port->status |= (ISI_TXOK | ISI_CTS); tty_wakeup(tty); } } else if (!(header & ISI_CTS)) { - port->tty->hw_stopped = 1; + port->port.tty->hw_stopped = 1; /* stop tx ing */ port->status &= ~(ISI_TXOK | ISI_CTS); } @@ -629,7 +622,7 @@ static irqreturn_t isicom_interrupt(int irq, void *dev_id) case 1: /* Received Break !!! */ tty_insert_flip_char(tty, 0, TTY_BREAK); - if (port->flags & ASYNC_SAK) + if (port->port.flags & ASYNC_SAK) do_SAK(tty); tty_flip_buffer_push(tty); break; @@ -681,7 +674,7 @@ static void isicom_config_port(struct isi_port *port) shift_count = card->shift_count; unsigned char flow_ctrl; - tty = port->tty; + tty = port->port.tty; if (tty == NULL) return; @@ -697,7 +690,7 @@ static void isicom_config_port(struct isi_port *port) /* 1,2,3,4 => 57.6, 115.2, 230, 460 kbps resp. */ if (baud < 1 || baud > 4) - port->tty->termios->c_cflag &= ~CBAUDEX; + port->port.tty->termios->c_cflag &= ~CBAUDEX; else baud += 15; } @@ -708,13 +701,13 @@ static void isicom_config_port(struct isi_port *port) * the 'setserial' utility. */ - if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI) + if ((port->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI) baud++; /* 57.6 Kbps */ - if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI) + if ((port->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI) baud += 2; /* 115 Kbps */ - if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI) + if ((port->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI) baud += 3; /* 230 kbps*/ - if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP) + if ((port->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP) baud += 4; /* 460 kbps*/ } if (linuxb_to_isib[baud] == -1) { @@ -754,15 +747,15 @@ static void isicom_config_port(struct isi_port *port) InterruptTheCard(base); } if (C_CLOCAL(tty)) - port->flags &= ~ASYNC_CHECK_CD; + port->port.flags &= ~ASYNC_CHECK_CD; else - port->flags |= ASYNC_CHECK_CD; + port->port.flags |= ASYNC_CHECK_CD; /* flow control settings ...*/ flow_ctrl = 0; - port->flags &= ~ASYNC_CTS_FLOW; + port->port.flags &= ~ASYNC_CTS_FLOW; if (C_CRTSCTS(tty)) { - port->flags |= ASYNC_CTS_FLOW; + port->port.flags |= ASYNC_CTS_FLOW; flow_ctrl |= ISICOM_CTSRTS; } if (I_IXON(tty)) @@ -809,23 +802,15 @@ static int isicom_setup_port(struct isi_port *port) struct isi_board *card = port->card; unsigned long flags; - if (port->flags & ASYNC_INITIALIZED) + if (port->port.flags & ASYNC_INITIALIZED) return 0; - if (!port->xmit_buf) { - /* Relies on BKL */ - unsigned long page = get_zeroed_page(GFP_KERNEL); - if (page == 0) - return -ENOMEM; - if (port->xmit_buf) - free_page(page); - else - port->xmit_buf = (unsigned char *) page; - } + if (tty_port_alloc_xmit_buf(&port->port) < 0) + return -ENOMEM; spin_lock_irqsave(&card->card_lock, flags); - if (port->tty) - clear_bit(TTY_IO_ERROR, &port->tty->flags); - if (port->count == 1) + if (port->port.tty) + clear_bit(TTY_IO_ERROR, &port->port.tty->flags); + if (port->port.count == 1) card->count++; port->xmit_cnt = port->xmit_head = port->xmit_tail = 0; @@ -839,7 +824,7 @@ static int isicom_setup_port(struct isi_port *port) } isicom_config_port(port); - port->flags |= ASYNC_INITIALIZED; + port->port.flags |= ASYNC_INITIALIZED; spin_unlock_irqrestore(&card->card_lock, flags); return 0; @@ -855,10 +840,10 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp, /* block if port is in the process of being closed */ - if (tty_hung_up_p(filp) || port->flags & ASYNC_CLOSING) { + if (tty_hung_up_p(filp) || port->port.flags & ASYNC_CLOSING) { pr_dbg("block_til_ready: close in progress.\n"); - interruptible_sleep_on(&port->close_wait); - if (port->flags & ASYNC_HUP_NOTIFY) + interruptible_sleep_on(&port->port.close_wait); + if (port->port.flags & ASYNC_HUP_NOTIFY) return -EAGAIN; else return -ERESTARTSYS; @@ -869,7 +854,7 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp, if ((filp->f_flags & O_NONBLOCK) || (tty->flags & (1 << TTY_IO_ERROR))) { pr_dbg("block_til_ready: non-block mode.\n"); - port->flags |= ASYNC_NORMAL_ACTIVE; + port->port.flags |= ASYNC_NORMAL_ACTIVE; return 0; } @@ -879,26 +864,26 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp, /* block waiting for DCD to be asserted, and while callout dev is busy */ retval = 0; - add_wait_queue(&port->open_wait, &wait); + add_wait_queue(&port->port.open_wait, &wait); spin_lock_irqsave(&card->card_lock, flags); if (!tty_hung_up_p(filp)) - port->count--; - port->blocked_open++; + port->port.count--; + port->port.blocked_open++; spin_unlock_irqrestore(&card->card_lock, flags); while (1) { raise_dtr_rts(port); set_current_state(TASK_INTERRUPTIBLE); - if (tty_hung_up_p(filp) || !(port->flags & ASYNC_INITIALIZED)) { - if (port->flags & ASYNC_HUP_NOTIFY) + if (tty_hung_up_p(filp) || !(port->port.flags & ASYNC_INITIALIZED)) { + if (port->port.flags & ASYNC_HUP_NOTIFY) retval = -EAGAIN; else retval = -ERESTARTSYS; break; } - if (!(port->flags & ASYNC_CLOSING) && + if (!(port->port.flags & ASYNC_CLOSING) && (do_clocal || (port->status & ISI_DCD))) { break; } @@ -909,15 +894,15 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp, schedule(); } set_current_state(TASK_RUNNING); - remove_wait_queue(&port->open_wait, &wait); + remove_wait_queue(&port->port.open_wait, &wait); spin_lock_irqsave(&card->card_lock, flags); if (!tty_hung_up_p(filp)) - port->count++; - port->blocked_open--; + port->port.count++; + port->port.blocked_open--; spin_unlock_irqrestore(&card->card_lock, flags); if (retval) return retval; - port->flags |= ASYNC_NORMAL_ACTIVE; + port->port.flags |= ASYNC_NORMAL_ACTIVE; return 0; } @@ -947,9 +932,9 @@ static int isicom_open(struct tty_struct *tty, struct file *filp) isicom_setup_board(card); - port->count++; + port->port.count++; tty->driver_data = port; - port->tty = tty; + port->port.tty = tty; error = isicom_setup_port(port); if (error == 0) error = block_til_ready(tty, filp, port); @@ -970,18 +955,15 @@ static void isicom_shutdown_port(struct isi_port *port) struct isi_board *card = port->card; struct tty_struct *tty; - tty = port->tty; + tty = port->port.tty; - if (!(port->flags & ASYNC_INITIALIZED)) + if (!(port->port.flags & ASYNC_INITIALIZED)) return; - if (port->xmit_buf) { - free_page((unsigned long) port->xmit_buf); - port->xmit_buf = NULL; - } - port->flags &= ~ASYNC_INITIALIZED; + tty_port_free_xmit_buf(&port->port); + port->port.flags &= ~ASYNC_INITIALIZED; /* 3rd October 2000 : Vinayak P Risbud */ - port->tty = NULL; + port->port.tty = NULL; /*Fix done by Anil .S on 30-04-2001 remote login through isi port has dtr toggle problem @@ -1046,33 +1028,33 @@ static void isicom_close(struct tty_struct *tty, struct file *filp) return; } - if (tty->count == 1 && port->count != 1) { + if (tty->count == 1 && port->port.count != 1) { printk(KERN_WARNING "ISICOM:(0x%lx) isicom_close: bad port " "count tty->count = 1 port count = %d.\n", - card->base, port->count); - port->count = 1; + card->base, port->port.count); + port->port.count = 1; } - if (--port->count < 0) { + if (--port->port.count < 0) { printk(KERN_WARNING "ISICOM:(0x%lx) isicom_close: bad port " "count for channel%d = %d", card->base, port->channel, - port->count); - port->count = 0; + port->port.count); + port->port.count = 0; } - if (port->count) { + if (port->port.count) { spin_unlock_irqrestore(&card->card_lock, flags); return; } - port->flags |= ASYNC_CLOSING; + port->port.flags |= ASYNC_CLOSING; tty->closing = 1; spin_unlock_irqrestore(&card->card_lock, flags); - if (port->closing_wait != ASYNC_CLOSING_WAIT_NONE) - tty_wait_until_sent(tty, port->closing_wait); + if (port->port.closing_wait != ASYNC_CLOSING_WAIT_NONE) + tty_wait_until_sent(tty, port->port.closing_wait); /* indicate to the card that no more data can be received on this port */ spin_lock_irqsave(&card->card_lock, flags); - if (port->flags & ASYNC_INITIALIZED) { + if (port->port.flags & ASYNC_INITIALIZED) { card->port_status &= ~(1 << port->channel); outw(card->port_status, card->base + 0x02); } @@ -1085,18 +1067,18 @@ static void isicom_close(struct tty_struct *tty, struct file *filp) spin_lock_irqsave(&card->card_lock, flags); tty->closing = 0; - if (port->blocked_open) { + if (port->port.blocked_open) { spin_unlock_irqrestore(&card->card_lock, flags); - if (port->close_delay) { + if (port->port.close_delay) { pr_dbg("scheduling until time out.\n"); msleep_interruptible( - jiffies_to_msecs(port->close_delay)); + jiffies_to_msecs(port->port.close_delay)); } spin_lock_irqsave(&card->card_lock, flags); - wake_up_interruptible(&port->open_wait); + wake_up_interruptible(&port->port.open_wait); } - port->flags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_CLOSING); - wake_up_interruptible(&port->close_wait); + port->port.flags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_CLOSING); + wake_up_interruptible(&port->port.close_wait); spin_unlock_irqrestore(&card->card_lock, flags); } @@ -1112,9 +1094,6 @@ static int isicom_write(struct tty_struct *tty, const unsigned char *buf, if (isicom_paranoia_check(port, tty->name, "isicom_write")) return 0; - if (!port->xmit_buf) - return 0; - spin_lock_irqsave(&card->card_lock, flags); while (1) { @@ -1123,7 +1102,7 @@ static int isicom_write(struct tty_struct *tty, const unsigned char *buf, if (cnt <= 0) break; - memcpy(port->xmit_buf + port->xmit_head, buf, cnt); + memcpy(port->port.xmit_buf + port->xmit_head, buf, cnt); port->xmit_head = (port->xmit_head + cnt) & (SERIAL_XMIT_SIZE - 1); port->xmit_cnt += cnt; @@ -1147,16 +1126,13 @@ static int isicom_put_char(struct tty_struct *tty, unsigned char ch) if (isicom_paranoia_check(port, tty->name, "isicom_put_char")) return 0; - if (!port->xmit_buf) - return 0; - spin_lock_irqsave(&card->card_lock, flags); if (port->xmit_cnt >= SERIAL_XMIT_SIZE - 1) { spin_unlock_irqrestore(&card->card_lock, flags); return 0; } - port->xmit_buf[port->xmit_head++] = ch; + port->port.xmit_buf[port->xmit_head++] = ch; port->xmit_head &= (SERIAL_XMIT_SIZE - 1); port->xmit_cnt++; spin_unlock_irqrestore(&card->card_lock, flags); @@ -1172,7 +1148,7 @@ static void isicom_flush_chars(struct tty_struct *tty) return; if (port->xmit_cnt <= 0 || tty->stopped || tty->hw_stopped || - !port->xmit_buf) + !port->port.xmit_buf) return; /* this tells the transmitter to consider this port for @@ -1274,23 +1250,23 @@ static int isicom_set_serial_info(struct isi_port *port, lock_kernel(); - reconfig_port = ((port->flags & ASYNC_SPD_MASK) != + reconfig_port = ((port->port.flags & ASYNC_SPD_MASK) != (newinfo.flags & ASYNC_SPD_MASK)); if (!capable(CAP_SYS_ADMIN)) { - if ((newinfo.close_delay != port->close_delay) || - (newinfo.closing_wait != port->closing_wait) || + if ((newinfo.close_delay != port->port.close_delay) || + (newinfo.closing_wait != port->port.closing_wait) || ((newinfo.flags & ~ASYNC_USR_MASK) != - (port->flags & ~ASYNC_USR_MASK))) { + (port->port.flags & ~ASYNC_USR_MASK))) { unlock_kernel(); return -EPERM; } - port->flags = ((port->flags & ~ASYNC_USR_MASK) | + port->port.flags = ((port->port.flags & ~ASYNC_USR_MASK) | (newinfo.flags & ASYNC_USR_MASK)); } else { - port->close_delay = newinfo.close_delay; - port->closing_wait = newinfo.closing_wait; - port->flags = ((port->flags & ~ASYNC_FLAGS) | + port->port.close_delay = newinfo.close_delay; + port->port.closing_wait = newinfo.closing_wait; + port->port.flags = ((port->port.flags & ~ASYNC_FLAGS) | (newinfo.flags & ASYNC_FLAGS)); } if (reconfig_port) { @@ -1314,10 +1290,10 @@ static int isicom_get_serial_info(struct isi_port *port, out_info.line = port - isi_ports; out_info.port = port->card->base; out_info.irq = port->card->irq; - out_info.flags = port->flags; + out_info.flags = port->port.flags; /* out_info.baud_base = ? */ - out_info.close_delay = port->close_delay; - out_info.closing_wait = port->closing_wait; + out_info.close_delay = port->port.close_delay; + out_info.closing_wait = port->port.closing_wait; unlock_kernel(); if (copy_to_user(info, &out_info, sizeof(out_info))) return -EFAULT; @@ -1454,10 +1430,10 @@ static void isicom_hangup(struct tty_struct *tty) isicom_shutdown_port(port); spin_unlock_irqrestore(&port->card->card_lock, flags); - port->count = 0; - port->flags &= ~ASYNC_NORMAL_ACTIVE; - port->tty = NULL; - wake_up_interruptible(&port->open_wait); + port->port.count = 0; + port->port.flags &= ~ASYNC_NORMAL_ACTIVE; + port->port.tty = NULL; + wake_up_interruptible(&port->port.open_wait); } @@ -1736,6 +1712,12 @@ static int __devinit isicom_probe(struct pci_dev *pdev, if (card_count >= BOARD_COUNT) goto err; + retval = pci_enable_device(pdev); + if (retval) { + dev_err(&pdev->dev, "failed to enable\n"); + goto err; + } + dev_info(&pdev->dev, "ISI PCI Card(Device ID 0x%x)\n", ent->device); /* allot the first empty slot in the array */ @@ -1790,6 +1772,7 @@ errunrr: errdec: board->base = 0; card_count--; + pci_disable_device(pdev); err: return retval; } @@ -1806,6 +1789,7 @@ static void __devexit isicom_remove(struct pci_dev *pdev) pci_release_region(pdev, 3); board->base = 0; card_count--; + pci_disable_device(pdev); } static int __init isicom_init(void) @@ -1818,14 +1802,13 @@ static int __init isicom_init(void) isi_card[idx].ports = port; spin_lock_init(&isi_card[idx].card_lock); for (channel = 0; channel < 16; channel++, port++) { + tty_port_init(&port->port); port->magic = ISICOM_MAGIC; port->card = &isi_card[idx]; port->channel = channel; - port->close_delay = 50 * HZ/100; - port->closing_wait = 3000 * HZ/100; + port->port.close_delay = 50 * HZ/100; + port->port.closing_wait = 3000 * HZ/100; port->status = 0; - init_waitqueue_head(&port->open_wait); - init_waitqueue_head(&port->close_wait); /* . . . */ } isi_card[idx].base = 0; diff --git a/drivers/char/istallion.c b/drivers/char/istallion.c index 7c8b62f162bf..6ef1c565705c 100644 --- a/drivers/char/istallion.c +++ b/drivers/char/istallion.c @@ -735,8 +735,8 @@ static void stli_cleanup_ports(struct stlibrd *brdp) for (j = 0; j < STL_MAXPORTS; j++) { portp = brdp->ports[j]; if (portp != NULL) { - if (portp->tty != NULL) - tty_hangup(portp->tty); + if (portp->port.tty != NULL) + tty_hangup(portp->port.tty); kfree(portp); } } @@ -811,9 +811,9 @@ static int stli_open(struct tty_struct *tty, struct file *filp) * The sleep here does not need interrupt protection since the wakeup * for it is done with the same context. */ - if (portp->flags & ASYNC_CLOSING) { - interruptible_sleep_on(&portp->close_wait); - if (portp->flags & ASYNC_HUP_NOTIFY) + if (portp->port.flags & ASYNC_CLOSING) { + interruptible_sleep_on(&portp->port.close_wait); + if (portp->port.flags & ASYNC_HUP_NOTIFY) return -EAGAIN; return -ERESTARTSYS; } @@ -824,7 +824,7 @@ static int stli_open(struct tty_struct *tty, struct file *filp) * requires several commands to the board we will need to wait for any * other open that is already initializing the port. */ - portp->tty = tty; + portp->port.tty = tty; tty->driver_data = portp; portp->refcount++; @@ -833,10 +833,10 @@ static int stli_open(struct tty_struct *tty, struct file *filp) if (signal_pending(current)) return -ERESTARTSYS; - if ((portp->flags & ASYNC_INITIALIZED) == 0) { + if ((portp->port.flags & ASYNC_INITIALIZED) == 0) { set_bit(ST_INITIALIZING, &portp->state); if ((rc = stli_initopen(brdp, portp)) >= 0) { - portp->flags |= ASYNC_INITIALIZED; + portp->port.flags |= ASYNC_INITIALIZED; clear_bit(TTY_IO_ERROR, &tty->flags); } clear_bit(ST_INITIALIZING, &portp->state); @@ -851,9 +851,9 @@ static int stli_open(struct tty_struct *tty, struct file *filp) * The sleep here does not need interrupt protection since the wakeup * for it is done with the same context. */ - if (portp->flags & ASYNC_CLOSING) { - interruptible_sleep_on(&portp->close_wait); - if (portp->flags & ASYNC_HUP_NOTIFY) + if (portp->port.flags & ASYNC_CLOSING) { + interruptible_sleep_on(&portp->port.close_wait); + if (portp->port.flags & ASYNC_HUP_NOTIFY) return -EAGAIN; return -ERESTARTSYS; } @@ -867,7 +867,7 @@ static int stli_open(struct tty_struct *tty, struct file *filp) if ((rc = stli_waitcarrier(brdp, portp, filp)) != 0) return rc; } - portp->flags |= ASYNC_NORMAL_ACTIVE; + portp->port.flags |= ASYNC_NORMAL_ACTIVE; return 0; } @@ -895,7 +895,7 @@ static void stli_close(struct tty_struct *tty, struct file *filp) return; } - portp->flags |= ASYNC_CLOSING; + portp->port.flags |= ASYNC_CLOSING; /* * May want to wait for data to drain before closing. The BUSY flag @@ -911,7 +911,7 @@ static void stli_close(struct tty_struct *tty, struct file *filp) if (portp->closing_wait != ASYNC_CLOSING_WAIT_NONE) tty_wait_until_sent(tty, portp->closing_wait); - portp->flags &= ~ASYNC_INITIALIZED; + portp->port.flags &= ~ASYNC_INITIALIZED; brdp = stli_brds[portp->brdnr]; stli_rawclose(brdp, portp, 0, 0); if (tty->termios->c_cflag & HUPCL) { @@ -931,16 +931,16 @@ static void stli_close(struct tty_struct *tty, struct file *filp) stli_flushbuffer(tty); tty->closing = 0; - portp->tty = NULL; + portp->port.tty = NULL; if (portp->openwaitcnt) { if (portp->close_delay) msleep_interruptible(jiffies_to_msecs(portp->close_delay)); - wake_up_interruptible(&portp->open_wait); + wake_up_interruptible(&portp->port.open_wait); } - portp->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING); - wake_up_interruptible(&portp->close_wait); + portp->port.flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING); + wake_up_interruptible(&portp->port.close_wait); } /*****************************************************************************/ @@ -970,7 +970,7 @@ static int stli_initopen(struct stlibrd *brdp, struct stliport *portp) sizeof(asynotify_t), 0)) < 0) return rc; - tty = portp->tty; + tty = portp->port.tty; if (tty == NULL) return -ENODEV; stli_mkasyport(portp, &aport, tty->termios); @@ -1169,7 +1169,7 @@ static int stli_setport(struct stliport *portp) if (portp == NULL) return -ENODEV; - if (portp->tty == NULL) + if (portp->port.tty == NULL) return -ENODEV; if (portp->brdnr >= stli_nrbrds) return -ENODEV; @@ -1177,7 +1177,7 @@ static int stli_setport(struct stliport *portp) if (brdp == NULL) return -ENODEV; - stli_mkasyport(portp, &aport, portp->tty->termios); + stli_mkasyport(portp, &aport, portp->port.tty->termios); return(stli_cmdwait(brdp, portp, A_SETPORT, &aport, sizeof(asyport_t), 0)); } @@ -1196,7 +1196,7 @@ static int stli_waitcarrier(struct stlibrd *brdp, struct stliport *portp, struct rc = 0; doclocal = 0; - if (portp->tty->termios->c_cflag & CLOCAL) + if (portp->port.tty->termios->c_cflag & CLOCAL) doclocal++; spin_lock_irqsave(&stli_lock, flags); @@ -1211,14 +1211,14 @@ static int stli_waitcarrier(struct stlibrd *brdp, struct stliport *portp, struct &portp->asig, sizeof(asysigs_t), 0)) < 0) break; if (tty_hung_up_p(filp) || - ((portp->flags & ASYNC_INITIALIZED) == 0)) { - if (portp->flags & ASYNC_HUP_NOTIFY) + ((portp->port.flags & ASYNC_INITIALIZED) == 0)) { + if (portp->port.flags & ASYNC_HUP_NOTIFY) rc = -EBUSY; else rc = -ERESTARTSYS; break; } - if (((portp->flags & ASYNC_CLOSING) == 0) && + if (((portp->port.flags & ASYNC_CLOSING) == 0) && (doclocal || (portp->sigs & TIOCM_CD))) { break; } @@ -1226,7 +1226,7 @@ static int stli_waitcarrier(struct stlibrd *brdp, struct stliport *portp, struct rc = -ERESTARTSYS; break; } - interruptible_sleep_on(&portp->open_wait); + interruptible_sleep_on(&portp->port.open_wait); } spin_lock_irqsave(&stli_lock, flags); @@ -1548,7 +1548,7 @@ static int stli_getserial(struct stliport *portp, struct serial_struct __user *s sio.type = PORT_UNKNOWN; sio.line = portp->portnr; sio.irq = 0; - sio.flags = portp->flags; + sio.flags = portp->port.flags; sio.baud_base = portp->baud_base; sio.close_delay = portp->close_delay; sio.closing_wait = portp->closing_wait; @@ -1583,11 +1583,11 @@ static int stli_setserial(struct stliport *portp, struct serial_struct __user *s if ((sio.baud_base != portp->baud_base) || (sio.close_delay != portp->close_delay) || ((sio.flags & ~ASYNC_USR_MASK) != - (portp->flags & ~ASYNC_USR_MASK))) + (portp->port.flags & ~ASYNC_USR_MASK))) return -EPERM; } - portp->flags = (portp->flags & ~ASYNC_USR_MASK) | + portp->port.flags = (portp->port.flags & ~ASYNC_USR_MASK) | (sio.flags & ASYNC_USR_MASK); portp->baud_base = sio.baud_base; portp->close_delay = sio.close_delay; @@ -1751,7 +1751,7 @@ static void stli_settermios(struct tty_struct *tty, struct ktermios *old) if ((old->c_cflag & CRTSCTS) && ((tiosp->c_cflag & CRTSCTS) == 0)) tty->hw_stopped = 0; if (((old->c_cflag & CLOCAL) == 0) && (tiosp->c_cflag & CLOCAL)) - wake_up_interruptible(&portp->open_wait); + wake_up_interruptible(&portp->port.open_wait); } /*****************************************************************************/ @@ -1834,7 +1834,7 @@ static void stli_hangup(struct tty_struct *tty) if (brdp == NULL) return; - portp->flags &= ~ASYNC_INITIALIZED; + portp->port.flags &= ~ASYNC_INITIALIZED; if (!test_bit(ST_CLOSING, &portp->state)) stli_rawclose(brdp, portp, 0, 0); @@ -1855,12 +1855,12 @@ static void stli_hangup(struct tty_struct *tty) clear_bit(ST_TXBUSY, &portp->state); clear_bit(ST_RXSTOP, &portp->state); set_bit(TTY_IO_ERROR, &tty->flags); - portp->tty = NULL; - portp->flags &= ~ASYNC_NORMAL_ACTIVE; + portp->port.tty = NULL; + portp->port.flags &= ~ASYNC_NORMAL_ACTIVE; portp->refcount = 0; spin_unlock_irqrestore(&stli_lock, flags); - wake_up_interruptible(&portp->open_wait); + wake_up_interruptible(&portp->port.open_wait); } /*****************************************************************************/ @@ -2188,7 +2188,7 @@ static void stli_read(struct stlibrd *brdp, struct stliport *portp) if (test_bit(ST_RXSTOP, &portp->state)) return; - tty = portp->tty; + tty = portp->port.tty; if (tty == NULL) return; @@ -2362,7 +2362,7 @@ static int stli_hostcmd(struct stlibrd *brdp, struct stliport *portp) if (ap->notify) { nt = ap->changed; ap->notify = 0; - tty = portp->tty; + tty = portp->port.tty; if (nt.signal & SG_DCD) { oldsigs = portp->sigs; @@ -2370,10 +2370,10 @@ static int stli_hostcmd(struct stlibrd *brdp, struct stliport *portp) clear_bit(ST_GETSIGS, &portp->state); if ((portp->sigs & TIOCM_CD) && ((oldsigs & TIOCM_CD) == 0)) - wake_up_interruptible(&portp->open_wait); + wake_up_interruptible(&portp->port.open_wait); if ((oldsigs & TIOCM_CD) && ((portp->sigs & TIOCM_CD) == 0)) { - if (portp->flags & ASYNC_CHECK_CD) { + if (portp->port.flags & ASYNC_CHECK_CD) { if (tty) tty_hangup(tty); } @@ -2392,7 +2392,7 @@ static int stli_hostcmd(struct stlibrd *brdp, struct stliport *portp) if ((nt.data & DT_RXBREAK) && (portp->rxmarkmsk & BRKINT)) { if (tty != NULL) { tty_insert_flip_char(tty, 0, TTY_BREAK); - if (portp->flags & ASYNC_SAK) { + if (portp->port.flags & ASYNC_SAK) { do_SAK(tty); EBRDENABLE(brdp); } @@ -2542,17 +2542,17 @@ static void stli_mkasyport(struct stliport *portp, asyport_t *pp, struct ktermio /* * Start of by setting the baud, char size, parity and stop bit info. */ - pp->baudout = tty_get_baud_rate(portp->tty); + pp->baudout = tty_get_baud_rate(portp->port.tty); if ((tiosp->c_cflag & CBAUD) == B38400) { - if ((portp->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI) + if ((portp->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI) pp->baudout = 57600; - else if ((portp->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI) + else if ((portp->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI) pp->baudout = 115200; - else if ((portp->flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI) + else if ((portp->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI) pp->baudout = 230400; - else if ((portp->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP) + else if ((portp->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP) pp->baudout = 460800; - else if ((portp->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST) + else if ((portp->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST) pp->baudout = (portp->baud_base / portp->custom_divisor); } if (pp->baudout > STL_MAXBAUD) @@ -2625,9 +2625,9 @@ static void stli_mkasyport(struct stliport *portp, asyport_t *pp, struct ktermio * Set up clocal processing as required. */ if (tiosp->c_cflag & CLOCAL) - portp->flags &= ~ASYNC_CHECK_CD; + portp->port.flags &= ~ASYNC_CHECK_CD; else - portp->flags |= ASYNC_CHECK_CD; + portp->port.flags |= ASYNC_CHECK_CD; /* * Transfer any persistent flags into the asyport structure. @@ -2703,8 +2703,8 @@ static int stli_initports(struct stlibrd *brdp) portp->baud_base = STL_BAUDBASE; portp->close_delay = STL_CLOSEDELAY; portp->closing_wait = 30 * HZ; - init_waitqueue_head(&portp->open_wait); - init_waitqueue_head(&portp->close_wait); + init_waitqueue_head(&portp->port.open_wait); + init_waitqueue_head(&portp->port.close_wait); init_waitqueue_head(&portp->raw_wait); panelport++; if (panelport >= brdp->panels[panelnr]) { @@ -4246,18 +4246,18 @@ static int stli_portcmdstats(struct stliport *portp) stli_comstats.panel = portp->panelnr; stli_comstats.port = portp->portnr; stli_comstats.state = portp->state; - stli_comstats.flags = portp->flags; + stli_comstats.flags = portp->port.flag; spin_lock_irqsave(&brd_lock, flags); - if (portp->tty != NULL) { - if (portp->tty->driver_data == portp) { - stli_comstats.ttystate = portp->tty->flags; + if (portp->port.tty != NULL) { + if (portp->port.tty->driver_data == portp) { + stli_comstats.ttystate = portp->port.tty->flags; stli_comstats.rxbuffered = -1; - if (portp->tty->termios != NULL) { - stli_comstats.cflags = portp->tty->termios->c_cflag; - stli_comstats.iflags = portp->tty->termios->c_iflag; - stli_comstats.oflags = portp->tty->termios->c_oflag; - stli_comstats.lflags = portp->tty->termios->c_lflag; + if (portp->port.tty->termios != NULL) { + stli_comstats.cflags = portp->port.tty->termios->c_cflag; + stli_comstats.iflags = portp->port.tty->termios->c_iflag; + stli_comstats.oflags = portp->port.tty->termios->c_oflag; + stli_comstats.lflags = portp->port.tty->termios->c_lflag; } } } diff --git a/drivers/char/mem.c b/drivers/char/mem.c index 070e22e8ea9e..b6772d657547 100644 --- a/drivers/char/mem.c +++ b/drivers/char/mem.c @@ -80,7 +80,7 @@ static inline int valid_mmap_phys_addr_range(unsigned long pfn, size_t size) } #endif -#ifdef CONFIG_NONPROMISC_DEVMEM +#ifdef CONFIG_STRICT_DEVMEM static inline int range_is_allowed(unsigned long pfn, unsigned long size) { u64 from = ((u64)pfn) << PAGE_SHIFT; diff --git a/drivers/char/moxa.c b/drivers/char/moxa.c index e21346da3101..2bba250ffc8e 100644 --- a/drivers/char/moxa.c +++ b/drivers/char/moxa.c @@ -130,17 +130,13 @@ struct moxaq_str { }; struct moxa_port { + struct tty_port port; struct moxa_board_conf *board; - struct tty_struct *tty; void __iomem *tableAddr; int type; - int close_delay; - unsigned int count; - int asyncflags; int cflag; unsigned long statusflags; - wait_queue_head_t open_wait; u8 DCDState; u8 lineCtrl; @@ -348,10 +344,10 @@ static int moxa_ioctl(struct tty_struct *tty, struct file *file, if (status & 4) tmp.dcd = 1; - if (!p->tty || !p->tty->termios) + if (!p->port.tty || !p->port.tty->termios) tmp.cflag = p->cflag; else - tmp.cflag = p->tty->termios->c_cflag; + tmp.cflag = p->port.tty->termios->c_cflag; copy: if (copy_to_user(argm, &tmp, sizeof(tmp))) { mutex_unlock(&moxa_openlock); @@ -825,10 +821,9 @@ static int moxa_init_board(struct moxa_board_conf *brd, struct device *dev) } for (i = 0, p = brd->ports; i < MAX_PORTS_PER_BOARD; i++, p++) { + tty_port_init(&p->port); p->type = PORT_16550A; - p->close_delay = 5 * HZ / 10; p->cflag = B9600 | CS8 | CREAD | CLOCAL | HUPCL; - init_waitqueue_head(&p->open_wait); } switch (brd->boardType) { @@ -884,12 +879,12 @@ static void moxa_board_deinit(struct moxa_board_conf *brd) /* pci hot-un-plug support */ for (a = 0; a < brd->numPorts; a++) - if (brd->ports[a].asyncflags & ASYNC_INITIALIZED) - tty_hangup(brd->ports[a].tty); + if (brd->ports[a].port.flags & ASYNC_INITIALIZED) + tty_hangup(brd->ports[a].port.tty); while (1) { opened = 0; for (a = 0; a < brd->numPorts; a++) - if (brd->ports[a].asyncflags & ASYNC_INITIALIZED) + if (brd->ports[a].port.flags & ASYNC_INITIALIZED) opened++; mutex_unlock(&moxa_openlock); if (!opened) @@ -1104,9 +1099,9 @@ static void moxa_close_port(struct moxa_port *ch) { moxa_shut_down(ch); MoxaPortFlushData(ch, 2); - ch->asyncflags &= ~ASYNC_NORMAL_ACTIVE; - ch->tty->driver_data = NULL; - ch->tty = NULL; + ch->port.flags &= ~ASYNC_NORMAL_ACTIVE; + ch->port.tty->driver_data = NULL; + ch->port.tty = NULL; } static int moxa_block_till_ready(struct tty_struct *tty, struct file *filp, @@ -1117,7 +1112,7 @@ static int moxa_block_till_ready(struct tty_struct *tty, struct file *filp, u8 dcd; while (1) { - prepare_to_wait(&ch->open_wait, &wait, TASK_INTERRUPTIBLE); + prepare_to_wait(&ch->port.open_wait, &wait, TASK_INTERRUPTIBLE); if (tty_hung_up_p(filp)) { #ifdef SERIAL_DO_RESTART retval = -ERESTARTSYS; @@ -1138,7 +1133,7 @@ static int moxa_block_till_ready(struct tty_struct *tty, struct file *filp, } schedule(); } - finish_wait(&ch->open_wait, &wait); + finish_wait(&ch->port.open_wait, &wait); return retval; } @@ -1163,16 +1158,16 @@ static int moxa_open(struct tty_struct *tty, struct file *filp) } ch = &brd->ports[port % MAX_PORTS_PER_BOARD]; - ch->count++; + ch->port.count++; tty->driver_data = ch; - ch->tty = tty; - if (!(ch->asyncflags & ASYNC_INITIALIZED)) { + ch->port.tty = tty; + if (!(ch->port.flags & ASYNC_INITIALIZED)) { ch->statusflags = 0; moxa_set_tty_param(tty, tty->termios); MoxaPortLineCtrl(ch, 1, 1); MoxaPortEnable(ch); MoxaSetFifo(ch, ch->type == PORT_16550A); - ch->asyncflags |= ASYNC_INITIALIZED; + ch->port.flags |= ASYNC_INITIALIZED; } mutex_unlock(&moxa_openlock); @@ -1181,11 +1176,11 @@ static int moxa_open(struct tty_struct *tty, struct file *filp) retval = moxa_block_till_ready(tty, filp, ch); mutex_lock(&moxa_openlock); if (retval) { - if (ch->count) /* 0 means already hung up... */ - if (--ch->count == 0) + if (ch->port.count) /* 0 means already hung up... */ + if (--ch->port.count == 0) moxa_close_port(ch); } else - ch->asyncflags |= ASYNC_NORMAL_ACTIVE; + ch->port.flags |= ASYNC_NORMAL_ACTIVE; mutex_unlock(&moxa_openlock); return retval; @@ -1204,21 +1199,21 @@ static void moxa_close(struct tty_struct *tty, struct file *filp) ch = tty->driver_data; if (ch == NULL) goto unlock; - if (tty->count == 1 && ch->count != 1) { + if (tty->count == 1 && ch->port.count != 1) { printk(KERN_WARNING "moxa_close: bad serial port count; " - "tty->count is 1, ch->count is %d\n", ch->count); - ch->count = 1; + "tty->count is 1, ch->port.count is %d\n", ch->port.count); + ch->port.count = 1; } - if (--ch->count < 0) { + if (--ch->port.count < 0) { printk(KERN_WARNING "moxa_close: bad serial port count, " "device=%s\n", tty->name); - ch->count = 0; + ch->port.count = 0; } - if (ch->count) + if (ch->port.count) goto unlock; ch->cflag = tty->termios->c_cflag; - if (ch->asyncflags & ASYNC_INITIALIZED) { + if (ch->port.flags & ASYNC_INITIALIZED) { moxa_setup_empty_event(tty); tty_wait_until_sent(tty, 30 * HZ); /* 30 seconds timeout */ } @@ -1374,7 +1369,7 @@ static void moxa_set_termios(struct tty_struct *tty, return; moxa_set_tty_param(tty, old_termios); if (!(old_termios->c_cflag & CLOCAL) && C_CLOCAL(tty)) - wake_up_interruptible(&ch->open_wait); + wake_up_interruptible(&ch->port.open_wait); } static void moxa_stop(struct tty_struct *tty) @@ -1412,20 +1407,20 @@ static void moxa_hangup(struct tty_struct *tty) mutex_unlock(&moxa_openlock); return; } - ch->count = 0; + ch->port.count = 0; moxa_close_port(ch); mutex_unlock(&moxa_openlock); - wake_up_interruptible(&ch->open_wait); + wake_up_interruptible(&ch->port.open_wait); } static void moxa_new_dcdstate(struct moxa_port *p, u8 dcd) { dcd = !!dcd; - if (dcd != p->DCDState && p->tty && C_CLOCAL(p->tty)) { + if (dcd != p->DCDState && p->port.tty && C_CLOCAL(p->port.tty)) { if (!dcd) - tty_hangup(p->tty); + tty_hangup(p->port.tty); } p->DCDState = dcd; } @@ -1433,9 +1428,9 @@ static void moxa_new_dcdstate(struct moxa_port *p, u8 dcd) static int moxa_poll_port(struct moxa_port *p, unsigned int handle, u16 __iomem *ip) { - struct tty_struct *tty = p->tty; + struct tty_struct *tty = p->port.tty; void __iomem *ofsAddr; - unsigned int inited = p->asyncflags & ASYNC_INITIALIZED; + unsigned int inited = p->port.flags & ASYNC_INITIALIZED; u16 intr; if (tty) { @@ -1566,9 +1561,9 @@ static void moxa_setup_empty_event(struct tty_struct *tty) static void moxa_shut_down(struct moxa_port *ch) { - struct tty_struct *tp = ch->tty; + struct tty_struct *tp = ch->port.tty; - if (!(ch->asyncflags & ASYNC_INITIALIZED)) + if (!(ch->port.flags & ASYNC_INITIALIZED)) return; MoxaPortDisable(ch); @@ -1580,7 +1575,7 @@ static void moxa_shut_down(struct moxa_port *ch) MoxaPortLineCtrl(ch, 0, 0); spin_lock_bh(&moxa_lock); - ch->asyncflags &= ~ASYNC_INITIALIZED; + ch->port.flags &= ~ASYNC_INITIALIZED; spin_unlock_bh(&moxa_lock); } @@ -1975,7 +1970,7 @@ static int MoxaPortWriteData(struct moxa_port *port, c = (head > tail) ? (head - tail - 1) : (head - tail + tx_mask); if (c > len) c = len; - moxaLog.txcnt[port->tty->index] += c; + moxaLog.txcnt[port->port.tty->index] += c; total = c; if (spage == epage) { bufhead = readw(ofsAddr + Ofs_txb); @@ -2017,7 +2012,7 @@ static int MoxaPortWriteData(struct moxa_port *port, static int MoxaPortReadData(struct moxa_port *port) { - struct tty_struct *tty = port->tty; + struct tty_struct *tty = port->port.tty; unsigned char *dst; void __iomem *baseAddr, *ofsAddr, *ofs; unsigned int count, len, total; @@ -2124,10 +2119,10 @@ static int moxa_get_serial_info(struct moxa_port *info, { struct serial_struct tmp = { .type = info->type, - .line = info->tty->index, - .flags = info->asyncflags, + .line = info->port.tty->index, + .flags = info->port.flags, .baud_base = 921600, - .close_delay = info->close_delay + .close_delay = info->port.close_delay }; return copy_to_user(retinfo, &tmp, sizeof(*retinfo)) ? -EFAULT : 0; } @@ -2148,13 +2143,13 @@ static int moxa_set_serial_info(struct moxa_port *info, if (!capable(CAP_SYS_ADMIN)) { if (((new_serial.flags & ~ASYNC_USR_MASK) != - (info->asyncflags & ~ASYNC_USR_MASK))) + (info->port.flags & ~ASYNC_USR_MASK))) return -EPERM; } else - info->close_delay = new_serial.close_delay * HZ / 100; + info->port.close_delay = new_serial.close_delay * HZ / 100; new_serial.flags = (new_serial.flags & ~ASYNC_FLAGS); - new_serial.flags |= (info->asyncflags & ASYNC_FLAGS); + new_serial.flags |= (info->port.flags & ASYNC_FLAGS); MoxaSetFifo(info, new_serial.type == PORT_16550A); diff --git a/drivers/char/mxser.c b/drivers/char/mxser.c index 4b81a85c5b53..6307e301bd26 100644 --- a/drivers/char/mxser.c +++ b/drivers/char/mxser.c @@ -222,8 +222,8 @@ struct mxser_mon_ext { struct mxser_board; struct mxser_port { + struct tty_port port; struct mxser_board *board; - struct tty_struct *tty; unsigned long ioaddr; unsigned long opmode_ioaddr; @@ -234,7 +234,6 @@ struct mxser_port { int rx_low_water; int baud_base; /* max. speed */ int type; /* UART type */ - int flags; /* defined in tty.h */ int x_char; /* xon/xoff character */ int IER; /* Interrupt Enable Register */ @@ -244,20 +243,14 @@ struct mxser_port { unsigned char ldisc_stop_rx; int custom_divisor; - int close_delay; - unsigned short closing_wait; unsigned char err_shadow; - unsigned long event; - int count; /* # of fd on device */ - int blocked_open; /* # of blocked opens */ struct async_icount icount; /* kernel counters for 4 input interrupts */ int timeout; int read_status_mask; int ignore_status_mask; int xmit_fifo_size; - unsigned char *xmit_buf; int xmit_head; int xmit_tail; int xmit_cnt; @@ -267,7 +260,6 @@ struct mxser_port { struct mxser_mon mon_data; spinlock_t slock; - wait_queue_head_t open_wait; wait_queue_head_t delta_msr_wait; }; @@ -575,7 +567,7 @@ static int mxser_block_til_ready(struct tty_struct *tty, struct file *filp, */ if ((filp->f_flags & O_NONBLOCK) || test_bit(TTY_IO_ERROR, &tty->flags)) { - port->flags |= ASYNC_NORMAL_ACTIVE; + port->port.flags |= ASYNC_NORMAL_ACTIVE; return 0; } @@ -585,32 +577,32 @@ static int mxser_block_til_ready(struct tty_struct *tty, struct file *filp, /* * Block waiting for the carrier detect and the line to become * free (i.e., not in use by the callout). While we are in - * this loop, port->count is dropped by one, so that + * this loop, port->port.count is dropped by one, so that * mxser_close() knows when to free things. We restore it upon * exit, either normal or abnormal. */ retval = 0; - add_wait_queue(&port->open_wait, &wait); + add_wait_queue(&port->port.open_wait, &wait); spin_lock_irqsave(&port->slock, flags); if (!tty_hung_up_p(filp)) - port->count--; + port->port.count--; spin_unlock_irqrestore(&port->slock, flags); - port->blocked_open++; + port->port.blocked_open++; while (1) { spin_lock_irqsave(&port->slock, flags); outb(inb(port->ioaddr + UART_MCR) | UART_MCR_DTR | UART_MCR_RTS, port->ioaddr + UART_MCR); spin_unlock_irqrestore(&port->slock, flags); set_current_state(TASK_INTERRUPTIBLE); - if (tty_hung_up_p(filp) || !(port->flags & ASYNC_INITIALIZED)) { - if (port->flags & ASYNC_HUP_NOTIFY) + if (tty_hung_up_p(filp) || !(port->port.flags & ASYNC_INITIALIZED)) { + if (port->port.flags & ASYNC_HUP_NOTIFY) retval = -EAGAIN; else retval = -ERESTARTSYS; break; } - if (!(port->flags & ASYNC_CLOSING) && + if (!(port->port.flags & ASYNC_CLOSING) && (do_clocal || (inb(port->ioaddr + UART_MSR) & UART_MSR_DCD))) break; @@ -621,13 +613,13 @@ static int mxser_block_til_ready(struct tty_struct *tty, struct file *filp, schedule(); } set_current_state(TASK_RUNNING); - remove_wait_queue(&port->open_wait, &wait); + remove_wait_queue(&port->port.open_wait, &wait); if (!tty_hung_up_p(filp)) - port->count++; - port->blocked_open--; + port->port.count++; + port->port.blocked_open--; if (retval) return retval; - port->flags |= ASYNC_NORMAL_ACTIVE; + port->port.flags |= ASYNC_NORMAL_ACTIVE; return 0; } @@ -636,7 +628,7 @@ static int mxser_set_baud(struct mxser_port *info, long newspd) int quot = 0, baud; unsigned char cval; - if (!info->tty || !info->tty->termios) + if (!info->port.tty || !info->port.tty->termios) return -1; if (!(info->ioaddr)) @@ -647,13 +639,13 @@ static int mxser_set_baud(struct mxser_port *info, long newspd) if (newspd == 134) { quot = 2 * info->baud_base / 269; - tty_encode_baud_rate(info->tty, 134, 134); + tty_encode_baud_rate(info->port.tty, 134, 134); } else if (newspd) { quot = info->baud_base / newspd; if (quot == 0) quot = 1; baud = info->baud_base/quot; - tty_encode_baud_rate(info->tty, baud, baud); + tty_encode_baud_rate(info->port.tty, baud, baud); } else { quot = 0; } @@ -679,7 +671,7 @@ static int mxser_set_baud(struct mxser_port *info, long newspd) outb(cval, info->ioaddr + UART_LCR); /* reset DLAB */ #ifdef BOTHER - if (C_BAUD(info->tty) == BOTHER) { + if (C_BAUD(info->port.tty) == BOTHER) { quot = info->baud_base % newspd; quot *= 8; if (quot % newspd > newspd / 2) { @@ -707,14 +699,14 @@ static int mxser_change_speed(struct mxser_port *info, int ret = 0; unsigned char status; - if (!info->tty || !info->tty->termios) + if (!info->port.tty || !info->port.tty->termios) return ret; - cflag = info->tty->termios->c_cflag; + cflag = info->port.tty->termios->c_cflag; if (!(info->ioaddr)) return ret; - if (mxser_set_baud_method[info->tty->index] == 0) - mxser_set_baud(info, tty_get_baud_rate(info->tty)); + if (mxser_set_baud_method[info->port.tty->index] == 0) + mxser_set_baud(info, tty_get_baud_rate(info->port.tty)); /* byte size and parity */ switch (cflag & CSIZE) { @@ -777,15 +769,15 @@ static int mxser_change_speed(struct mxser_port *info, info->IER &= ~UART_IER_MSI; info->MCR &= ~UART_MCR_AFE; if (cflag & CRTSCTS) { - info->flags |= ASYNC_CTS_FLOW; + info->port.flags |= ASYNC_CTS_FLOW; info->IER |= UART_IER_MSI; if ((info->type == PORT_16550A) || (info->board->chip_flag)) { info->MCR |= UART_MCR_AFE; } else { status = inb(info->ioaddr + UART_MSR); - if (info->tty->hw_stopped) { + if (info->port.tty->hw_stopped) { if (status & UART_MSR_CTS) { - info->tty->hw_stopped = 0; + info->port.tty->hw_stopped = 0; if (info->type != PORT_16550A && !info->board->chip_flag) { outb(info->IER & ~UART_IER_THRI, @@ -795,11 +787,11 @@ static int mxser_change_speed(struct mxser_port *info, outb(info->IER, info->ioaddr + UART_IER); } - tty_wakeup(info->tty); + tty_wakeup(info->port.tty); } } else { if (!(status & UART_MSR_CTS)) { - info->tty->hw_stopped = 1; + info->port.tty->hw_stopped = 1; if ((info->type != PORT_16550A) && (!info->board->chip_flag)) { info->IER &= ~UART_IER_THRI; @@ -810,13 +802,13 @@ static int mxser_change_speed(struct mxser_port *info, } } } else { - info->flags &= ~ASYNC_CTS_FLOW; + info->port.flags &= ~ASYNC_CTS_FLOW; } outb(info->MCR, info->ioaddr + UART_MCR); if (cflag & CLOCAL) { - info->flags &= ~ASYNC_CHECK_CD; + info->port.flags &= ~ASYNC_CHECK_CD; } else { - info->flags |= ASYNC_CHECK_CD; + info->port.flags |= ASYNC_CHECK_CD; info->IER |= UART_IER_MSI; } outb(info->IER, info->ioaddr + UART_IER); @@ -825,21 +817,21 @@ static int mxser_change_speed(struct mxser_port *info, * Set up parity check flag */ info->read_status_mask = UART_LSR_OE | UART_LSR_THRE | UART_LSR_DR; - if (I_INPCK(info->tty)) + if (I_INPCK(info->port.tty)) info->read_status_mask |= UART_LSR_FE | UART_LSR_PE; - if (I_BRKINT(info->tty) || I_PARMRK(info->tty)) + if (I_BRKINT(info->port.tty) || I_PARMRK(info->port.tty)) info->read_status_mask |= UART_LSR_BI; info->ignore_status_mask = 0; - if (I_IGNBRK(info->tty)) { + if (I_IGNBRK(info->port.tty)) { info->ignore_status_mask |= UART_LSR_BI; info->read_status_mask |= UART_LSR_BI; /* * If we're ignore parity and break indicators, ignore * overruns too. (For real raw support). */ - if (I_IGNPAR(info->tty)) { + if (I_IGNPAR(info->port.tty)) { info->ignore_status_mask |= UART_LSR_OE | UART_LSR_PE | @@ -851,16 +843,16 @@ static int mxser_change_speed(struct mxser_port *info, } } if (info->board->chip_flag) { - mxser_set_must_xon1_value(info->ioaddr, START_CHAR(info->tty)); - mxser_set_must_xoff1_value(info->ioaddr, STOP_CHAR(info->tty)); - if (I_IXON(info->tty)) { + mxser_set_must_xon1_value(info->ioaddr, START_CHAR(info->port.tty)); + mxser_set_must_xoff1_value(info->ioaddr, STOP_CHAR(info->port.tty)); + if (I_IXON(info->port.tty)) { mxser_enable_must_rx_software_flow_control( info->ioaddr); } else { mxser_disable_must_rx_software_flow_control( info->ioaddr); } - if (I_IXOFF(info->tty)) { + if (I_IXOFF(info->port.tty)) { mxser_enable_must_tx_software_flow_control( info->ioaddr); } else { @@ -890,15 +882,15 @@ static void mxser_check_modem_status(struct mxser_port *port, int status) port->mon_data.modem_status = status; wake_up_interruptible(&port->delta_msr_wait); - if ((port->flags & ASYNC_CHECK_CD) && (status & UART_MSR_DDCD)) { + if ((port->port.flags & ASYNC_CHECK_CD) && (status & UART_MSR_DDCD)) { if (status & UART_MSR_DCD) - wake_up_interruptible(&port->open_wait); + wake_up_interruptible(&port->port.open_wait); } - if (port->flags & ASYNC_CTS_FLOW) { - if (port->tty->hw_stopped) { + if (port->port.flags & ASYNC_CTS_FLOW) { + if (port->port.tty->hw_stopped) { if (status & UART_MSR_CTS) { - port->tty->hw_stopped = 0; + port->port.tty->hw_stopped = 0; if ((port->type != PORT_16550A) && (!port->board->chip_flag)) { @@ -908,11 +900,11 @@ static void mxser_check_modem_status(struct mxser_port *port, int status) outb(port->IER, port->ioaddr + UART_IER); } - tty_wakeup(port->tty); + tty_wakeup(port->port.tty); } } else { if (!(status & UART_MSR_CTS)) { - port->tty->hw_stopped = 1; + port->port.tty->hw_stopped = 1; if (port->type != PORT_16550A && !port->board->chip_flag) { port->IER &= ~UART_IER_THRI; @@ -935,23 +927,23 @@ static int mxser_startup(struct mxser_port *info) spin_lock_irqsave(&info->slock, flags); - if (info->flags & ASYNC_INITIALIZED) { + if (info->port.flags & ASYNC_INITIALIZED) { free_page(page); spin_unlock_irqrestore(&info->slock, flags); return 0; } if (!info->ioaddr || !info->type) { - if (info->tty) - set_bit(TTY_IO_ERROR, &info->tty->flags); + if (info->port.tty) + set_bit(TTY_IO_ERROR, &info->port.tty->flags); free_page(page); spin_unlock_irqrestore(&info->slock, flags); return 0; } - if (info->xmit_buf) + if (info->port.xmit_buf) free_page(page); else - info->xmit_buf = (unsigned char *) page; + info->port.xmit_buf = (unsigned char *) page; /* * Clear the FIFO buffers and disable them @@ -973,8 +965,8 @@ static int mxser_startup(struct mxser_port *info) if (inb(info->ioaddr + UART_LSR) == 0xff) { spin_unlock_irqrestore(&info->slock, flags); if (capable(CAP_SYS_ADMIN)) { - if (info->tty) - set_bit(TTY_IO_ERROR, &info->tty->flags); + if (info->port.tty) + set_bit(TTY_IO_ERROR, &info->port.tty->flags); return 0; } else return -ENODEV; @@ -1012,15 +1004,15 @@ static int mxser_startup(struct mxser_port *info) (void) inb(info->ioaddr + UART_IIR); (void) inb(info->ioaddr + UART_MSR); - if (info->tty) - clear_bit(TTY_IO_ERROR, &info->tty->flags); + if (info->port.tty) + clear_bit(TTY_IO_ERROR, &info->port.tty->flags); info->xmit_cnt = info->xmit_head = info->xmit_tail = 0; /* * and set the speed of the serial port */ mxser_change_speed(info, NULL); - info->flags |= ASYNC_INITIALIZED; + info->port.flags |= ASYNC_INITIALIZED; spin_unlock_irqrestore(&info->slock, flags); return 0; @@ -1034,7 +1026,7 @@ static void mxser_shutdown(struct mxser_port *info) { unsigned long flags; - if (!(info->flags & ASYNC_INITIALIZED)) + if (!(info->port.flags & ASYNC_INITIALIZED)) return; spin_lock_irqsave(&info->slock, flags); @@ -1048,15 +1040,15 @@ static void mxser_shutdown(struct mxser_port *info) /* * Free the IRQ, if necessary */ - if (info->xmit_buf) { - free_page((unsigned long) info->xmit_buf); - info->xmit_buf = NULL; + if (info->port.xmit_buf) { + free_page((unsigned long) info->port.xmit_buf); + info->port.xmit_buf = NULL; } info->IER = 0; outb(0x00, info->ioaddr + UART_IER); - if (!info->tty || (info->tty->termios->c_cflag & HUPCL)) + if (!info->port.tty || (info->port.tty->termios->c_cflag & HUPCL)) info->MCR &= ~(UART_MCR_DTR | UART_MCR_RTS); outb(info->MCR, info->ioaddr + UART_MCR); @@ -1072,10 +1064,10 @@ static void mxser_shutdown(struct mxser_port *info) /* read data port to reset things */ (void) inb(info->ioaddr + UART_RX); - if (info->tty) - set_bit(TTY_IO_ERROR, &info->tty->flags); + if (info->port.tty) + set_bit(TTY_IO_ERROR, &info->port.tty->flags); - info->flags &= ~ASYNC_INITIALIZED; + info->port.flags &= ~ASYNC_INITIALIZED; if (info->board->chip_flag) SET_MOXA_MUST_NO_SOFTWARE_FLOW_CONTROL(info->ioaddr); @@ -1105,12 +1097,12 @@ static int mxser_open(struct tty_struct *tty, struct file *filp) return -ENODEV; tty->driver_data = info; - info->tty = tty; + info->port.tty = tty; /* * Start up serial port */ spin_lock_irqsave(&info->slock, flags); - info->count++; + info->port.count++; spin_unlock_irqrestore(&info->slock, flags); retval = mxser_startup(info); if (retval) @@ -1170,42 +1162,42 @@ static void mxser_close(struct tty_struct *tty, struct file *filp) spin_unlock_irqrestore(&info->slock, flags); return; } - if ((tty->count == 1) && (info->count != 1)) { + if ((tty->count == 1) && (info->port.count != 1)) { /* * Uh, oh. tty->count is 1, which means that the tty - * structure will be freed. Info->count should always + * structure will be freed. Info->port.count should always * be one in these conditions. If it's greater than * one, we've got real problems, since it means the * serial port won't be shutdown. */ printk(KERN_ERR "mxser_close: bad serial port count; " - "tty->count is 1, info->count is %d\n", info->count); - info->count = 1; + "tty->count is 1, info->port.count is %d\n", info->port.count); + info->port.count = 1; } - if (--info->count < 0) { + if (--info->port.count < 0) { printk(KERN_ERR "mxser_close: bad serial port count for " - "ttys%d: %d\n", tty->index, info->count); - info->count = 0; + "ttys%d: %d\n", tty->index, info->port.count); + info->port.count = 0; } - if (info->count) { + if (info->port.count) { spin_unlock_irqrestore(&info->slock, flags); return; } - info->flags |= ASYNC_CLOSING; + info->port.flags |= ASYNC_CLOSING; spin_unlock_irqrestore(&info->slock, flags); /* * Save the termios structure, since this port may have * separate termios for callout and dialin. */ - if (info->flags & ASYNC_NORMAL_ACTIVE) + if (info->port.flags & ASYNC_NORMAL_ACTIVE) info->normal_termios = *tty->termios; /* * Now we wait for the transmit buffer to clear; and we notify * the line discipline to only process XON/XOFF characters. */ tty->closing = 1; - if (info->closing_wait != ASYNC_CLOSING_WAIT_NONE) - tty_wait_until_sent(tty, info->closing_wait); + if (info->port.closing_wait != ASYNC_CLOSING_WAIT_NONE) + tty_wait_until_sent(tty, info->port.closing_wait); /* * At this point we stop accepting input. To do this, we * disable the receive line status interrupts, and tell the @@ -1216,7 +1208,7 @@ static void mxser_close(struct tty_struct *tty, struct file *filp) if (info->board->chip_flag) info->IER &= ~MOXA_MUST_RECV_ISR; - if (info->flags & ASYNC_INITIALIZED) { + if (info->port.flags & ASYNC_INITIALIZED) { outb(info->IER, info->ioaddr + UART_IER); /* * Before we drop DTR, make sure the UART transmitter @@ -1236,15 +1228,14 @@ static void mxser_close(struct tty_struct *tty, struct file *filp) tty_ldisc_flush(tty); tty->closing = 0; - info->event = 0; - info->tty = NULL; - if (info->blocked_open) { - if (info->close_delay) - schedule_timeout_interruptible(info->close_delay); - wake_up_interruptible(&info->open_wait); + info->port.tty = NULL; + if (info->port.blocked_open) { + if (info->port.close_delay) + schedule_timeout_interruptible(info->port.close_delay); + wake_up_interruptible(&info->port.open_wait); } - info->flags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_CLOSING); + info->port.flags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_CLOSING); } static int mxser_write(struct tty_struct *tty, const unsigned char *buf, int count) @@ -1253,7 +1244,7 @@ static int mxser_write(struct tty_struct *tty, const unsigned char *buf, int cou struct mxser_port *info = tty->driver_data; unsigned long flags; - if (!info->xmit_buf) + if (!info->port.xmit_buf) return 0; while (1) { @@ -1262,7 +1253,7 @@ static int mxser_write(struct tty_struct *tty, const unsigned char *buf, int cou if (c <= 0) break; - memcpy(info->xmit_buf + info->xmit_head, buf, c); + memcpy(info->port.xmit_buf + info->xmit_head, buf, c); spin_lock_irqsave(&info->slock, flags); info->xmit_head = (info->xmit_head + c) & (SERIAL_XMIT_SIZE - 1); @@ -1294,14 +1285,14 @@ static int mxser_put_char(struct tty_struct *tty, unsigned char ch) struct mxser_port *info = tty->driver_data; unsigned long flags; - if (!info->xmit_buf) + if (!info->port.xmit_buf) return 0; if (info->xmit_cnt >= SERIAL_XMIT_SIZE - 1) return 0; spin_lock_irqsave(&info->slock, flags); - info->xmit_buf[info->xmit_head++] = ch; + info->port.xmit_buf[info->xmit_head++] = ch; info->xmit_head &= SERIAL_XMIT_SIZE - 1; info->xmit_cnt++; spin_unlock_irqrestore(&info->slock, flags); @@ -1327,7 +1318,7 @@ static void mxser_flush_chars(struct tty_struct *tty) if (info->xmit_cnt <= 0 || tty->stopped || - !info->xmit_buf || + !info->port.xmit_buf || (tty->hw_stopped && (info->type != PORT_16550A) && (!info->board->chip_flag) @@ -1370,13 +1361,13 @@ static int mxser_get_serial_info(struct mxser_port *info, { struct serial_struct tmp = { .type = info->type, - .line = info->tty->index, + .line = info->port.tty->index, .port = info->ioaddr, .irq = info->board->irq, - .flags = info->flags, + .flags = info->port.flags, .baud_base = info->baud_base, - .close_delay = info->close_delay, - .closing_wait = info->closing_wait, + .close_delay = info->port.close_delay, + .closing_wait = info->port.closing_wait, .custom_divisor = info->custom_divisor, .hub6 = 0 }; @@ -1403,33 +1394,33 @@ static int mxser_set_serial_info(struct mxser_port *info, new_serial.port != info->ioaddr) return -EINVAL; - flags = info->flags & ASYNC_SPD_MASK; + flags = info->port.flags & ASYNC_SPD_MASK; if (!capable(CAP_SYS_ADMIN)) { if ((new_serial.baud_base != info->baud_base) || - (new_serial.close_delay != info->close_delay) || - ((new_serial.flags & ~ASYNC_USR_MASK) != (info->flags & ~ASYNC_USR_MASK))) + (new_serial.close_delay != info->port.close_delay) || + ((new_serial.flags & ~ASYNC_USR_MASK) != (info->port.flags & ~ASYNC_USR_MASK))) return -EPERM; - info->flags = ((info->flags & ~ASYNC_USR_MASK) | + info->port.flags = ((info->port.flags & ~ASYNC_USR_MASK) | (new_serial.flags & ASYNC_USR_MASK)); } else { /* * OK, past this point, all the error checking has been done. * At this point, we start making changes..... */ - info->flags = ((info->flags & ~ASYNC_FLAGS) | + info->port.flags = ((info->port.flags & ~ASYNC_FLAGS) | (new_serial.flags & ASYNC_FLAGS)); - info->close_delay = new_serial.close_delay * HZ / 100; - info->closing_wait = new_serial.closing_wait * HZ / 100; - info->tty->low_latency = - (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0; - info->tty->low_latency = 0; - if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST && + info->port.close_delay = new_serial.close_delay * HZ / 100; + info->port.closing_wait = new_serial.closing_wait * HZ / 100; + info->port.tty->low_latency = + (info->port.flags & ASYNC_LOW_LATENCY) ? 1 : 0; + info->port.tty->low_latency = 0; + if ((info->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST && (new_serial.baud_base != info->baud_base || new_serial.custom_divisor != info->custom_divisor)) { baud = new_serial.baud_base / new_serial.custom_divisor; - tty_encode_baud_rate(info->tty, baud, baud); + tty_encode_baud_rate(info->port.tty, baud, baud); } } @@ -1437,8 +1428,8 @@ static int mxser_set_serial_info(struct mxser_port *info, process_txrx_fifo(info); - if (info->flags & ASYNC_INITIALIZED) { - if (flags != (info->flags & ASYNC_SPD_MASK)) { + if (info->port.flags & ASYNC_INITIALIZED) { + if (flags != (info->port.flags & ASYNC_SPD_MASK)) { spin_lock_irqsave(&info->slock, sl_flags); mxser_change_speed(info, NULL); spin_unlock_irqrestore(&info->slock, sl_flags); @@ -1693,12 +1684,12 @@ static int mxser_ioctl_special(unsigned int cmd, void __user *argp) continue; } - if (!port->tty || !port->tty->termios) + if (!port->port.tty || !port->port.tty->termios) GMStatus[i].cflag = port->normal_termios.c_cflag; else GMStatus[i].cflag = - port->tty->termios->c_cflag; + port->port.tty->termios->c_cflag; status = inb(port->ioaddr + UART_MSR); if (status & 0x80 /*UART_MSR_DCD */ ) @@ -1755,14 +1746,14 @@ static int mxser_ioctl_special(unsigned int cmd, void __user *argp) mon_data_ext.modem_status[i] = port->mon_data.modem_status; mon_data_ext.baudrate[i] = - tty_get_baud_rate(port->tty); + tty_get_baud_rate(port->port.tty); - if (!port->tty || !port->tty->termios) { + if (!port->port.tty || !port->port.tty->termios) { cflag = port->normal_termios.c_cflag; iflag = port->normal_termios.c_iflag; } else { - cflag = port->tty->termios->c_cflag; - iflag = port->tty->termios->c_iflag; + cflag = port->port.tty->termios->c_cflag; + iflag = port->port.tty->termios->c_iflag; } mon_data_ext.databits[i] = cflag & CSIZE; @@ -1989,7 +1980,7 @@ static int mxser_ioctl(struct tty_struct *tty, struct file *file, else info->mon_data.hold_reason |= NPPI_NOTIFY_XOFFXENT; - if (info->tty->hw_stopped) + if (info->port.tty->hw_stopped) info->mon_data.hold_reason |= NPPI_NOTIFY_CTSHOLD; else info->mon_data.hold_reason &= ~NPPI_NOTIFY_CTSHOLD; @@ -2038,7 +2029,7 @@ static void mxser_stoprx(struct tty_struct *tty) } } - if (info->tty->termios->c_cflag & CRTSCTS) { + if (info->port.tty->termios->c_cflag & CRTSCTS) { info->MCR &= ~UART_MCR_RTS; outb(info->MCR, info->ioaddr + UART_MCR); } @@ -2075,7 +2066,7 @@ static void mxser_unthrottle(struct tty_struct *tty) } } - if (info->tty->termios->c_cflag & CRTSCTS) { + if (info->port.tty->termios->c_cflag & CRTSCTS) { info->MCR |= UART_MCR_RTS; outb(info->MCR, info->ioaddr + UART_MCR); } @@ -2106,7 +2097,7 @@ static void mxser_start(struct tty_struct *tty) unsigned long flags; spin_lock_irqsave(&info->slock, flags); - if (info->xmit_cnt && info->xmit_buf) { + if (info->xmit_cnt && info->port.xmit_buf) { outb(info->IER & ~UART_IER_THRI, info->ioaddr + UART_IER); info->IER |= UART_IER_THRI; outb(info->IER, info->ioaddr + UART_IER); @@ -2219,11 +2210,10 @@ static void mxser_hangup(struct tty_struct *tty) mxser_flush_buffer(tty); mxser_shutdown(info); - info->event = 0; - info->count = 0; - info->flags &= ~ASYNC_NORMAL_ACTIVE; - info->tty = NULL; - wake_up_interruptible(&info->open_wait); + info->port.count = 0; + info->port.flags &= ~ASYNC_NORMAL_ACTIVE; + info->port.tty = NULL; + wake_up_interruptible(&info->port.open_wait); } /* @@ -2246,7 +2236,7 @@ static void mxser_rs_break(struct tty_struct *tty, int break_state) static void mxser_receive_chars(struct mxser_port *port, int *status) { - struct tty_struct *tty = port->tty; + struct tty_struct *tty = port->port.tty; unsigned char ch, gdl; int ignored = 0; int cnt = 0; @@ -2302,7 +2292,7 @@ intr_old: flag = TTY_BREAK; port->icount.brk++; - if (port->flags & ASYNC_SAK) + if (port->port.flags & ASYNC_SAK) do_SAK(tty); } else if (*status & UART_LSR_PE) { flag = TTY_PARITY; @@ -2333,7 +2323,7 @@ intr_old: } while (*status & UART_LSR_DR); end_intr: - mxvar_log.rxcnt[port->tty->index] += cnt; + mxvar_log.rxcnt[port->port.tty->index] += cnt; port->mon_data.rxcnt += cnt; port->mon_data.up_rxcnt += cnt; @@ -2354,18 +2344,18 @@ static void mxser_transmit_chars(struct mxser_port *port) if (port->x_char) { outb(port->x_char, port->ioaddr + UART_TX); port->x_char = 0; - mxvar_log.txcnt[port->tty->index]++; + mxvar_log.txcnt[port->port.tty->index]++; port->mon_data.txcnt++; port->mon_data.up_txcnt++; port->icount.tx++; return; } - if (port->xmit_buf == NULL) + if (port->port.xmit_buf == NULL) return; - if ((port->xmit_cnt <= 0) || port->tty->stopped || - (port->tty->hw_stopped && + if ((port->xmit_cnt <= 0) || port->port.tty->stopped || + (port->port.tty->hw_stopped && (port->type != PORT_16550A) && (!port->board->chip_flag))) { port->IER &= ~UART_IER_THRI; @@ -2376,20 +2366,20 @@ static void mxser_transmit_chars(struct mxser_port *port) cnt = port->xmit_cnt; count = port->xmit_fifo_size; do { - outb(port->xmit_buf[port->xmit_tail++], + outb(port->port.xmit_buf[port->xmit_tail++], port->ioaddr + UART_TX); port->xmit_tail = port->xmit_tail & (SERIAL_XMIT_SIZE - 1); if (--port->xmit_cnt <= 0) break; } while (--count > 0); - mxvar_log.txcnt[port->tty->index] += (cnt - port->xmit_cnt); + mxvar_log.txcnt[port->port.tty->index] += (cnt - port->xmit_cnt); port->mon_data.txcnt += (cnt - port->xmit_cnt); port->mon_data.up_txcnt += (cnt - port->xmit_cnt); port->icount.tx += (cnt - port->xmit_cnt); if (port->xmit_cnt < WAKEUP_CHARS) - tty_wakeup(port->tty); + tty_wakeup(port->port.tty); if (port->xmit_cnt <= 0) { port->IER &= ~UART_IER_THRI; @@ -2440,9 +2430,9 @@ static irqreturn_t mxser_interrupt(int irq, void *dev_id) if (iir & UART_IIR_NO_INT) break; iir &= MOXA_MUST_IIR_MASK; - if (!port->tty || - (port->flags & ASYNC_CLOSING) || - !(port->flags & + if (!port->port.tty || + (port->port.flags & ASYNC_CLOSING) || + !(port->port.flags & ASYNC_INITIALIZED)) { status = inb(port->ioaddr + UART_LSR); outb(0x27, port->ioaddr + UART_FCR); @@ -2550,6 +2540,7 @@ static int __devinit mxser_initbrd(struct mxser_board *brd, for (i = 0; i < brd->info->nports; i++) { info = &brd->ports[i]; + tty_port_init(&info->port); info->board = brd; info->stop_rx = 0; info->ldisc_stop_rx = 0; @@ -2558,16 +2549,15 @@ static int __devinit mxser_initbrd(struct mxser_board *brd, if (brd->chip_flag != MOXA_OTHER_UART) mxser_enable_must_enchance_mode(info->ioaddr); - info->flags = ASYNC_SHARE_IRQ; + info->port.flags = ASYNC_SHARE_IRQ; info->type = brd->uart_type; process_txrx_fifo(info); info->custom_divisor = info->baud_base * 16; - info->close_delay = 5 * HZ / 10; - info->closing_wait = 30 * HZ; + info->port.close_delay = 5 * HZ / 10; + info->port.closing_wait = 30 * HZ; info->normal_termios = mxvar_sdriver->init_termios; - init_waitqueue_head(&info->open_wait); init_waitqueue_head(&info->delta_msr_wait); memset(&info->mon_data, 0, sizeof(struct mxser_mon)); info->err_shadow = 0; diff --git a/drivers/char/n_hdlc.c b/drivers/char/n_hdlc.c index a35bfd7ee80e..ed4e03333ab4 100644 --- a/drivers/char/n_hdlc.c +++ b/drivers/char/n_hdlc.c @@ -199,7 +199,7 @@ static void n_hdlc_tty_wakeup(struct tty_struct *tty); #define tty2n_hdlc(tty) ((struct n_hdlc *) ((tty)->disc_data)) #define n_hdlc2tty(n_hdlc) ((n_hdlc)->tty) -static struct tty_ldisc n_hdlc_ldisc = { +static struct tty_ldisc_ops n_hdlc_ldisc = { .owner = THIS_MODULE, .magic = TTY_LDISC_MAGIC, .name = "hdlc", @@ -342,8 +342,8 @@ static int n_hdlc_tty_open (struct tty_struct *tty) #endif /* Flush any pending characters in the driver and discipline. */ - if (tty->ldisc.flush_buffer) - tty->ldisc.flush_buffer(tty); + if (tty->ldisc.ops->flush_buffer) + tty->ldisc.ops->flush_buffer(tty); tty_driver_flush_buffer(tty); diff --git a/drivers/char/n_r3964.c b/drivers/char/n_r3964.c index 902169062332..ae377aa473ba 100644 --- a/drivers/char/n_r3964.c +++ b/drivers/char/n_r3964.c @@ -143,7 +143,7 @@ static unsigned int r3964_poll(struct tty_struct *tty, struct file *file, static void r3964_receive_buf(struct tty_struct *tty, const unsigned char *cp, char *fp, int count); -static struct tty_ldisc tty_ldisc_N_R3964 = { +static struct tty_ldisc_ops tty_ldisc_N_R3964 = { .owner = THIS_MODULE, .magic = TTY_LDISC_MAGIC, .name = "R3964", diff --git a/drivers/char/n_tty.c b/drivers/char/n_tty.c index 8096389b0dc2..708c2b1dbe51 100644 --- a/drivers/char/n_tty.c +++ b/drivers/char/n_tty.c @@ -1573,7 +1573,7 @@ static unsigned int normal_poll(struct tty_struct *tty, struct file *file, return mask; } -struct tty_ldisc tty_ldisc_N_TTY = { +struct tty_ldisc_ops tty_ldisc_N_TTY = { .magic = TTY_LDISC_MAGIC, .name = "n_tty", .open = n_tty_open, diff --git a/drivers/char/nvram.c b/drivers/char/nvram.c index 197cd7a0c332..a22662b6a1a5 100644 --- a/drivers/char/nvram.c +++ b/drivers/char/nvram.c @@ -444,7 +444,7 @@ nvram_init(void) /* First test whether the driver should init at all */ if (!CHECK_DRIVER_INIT()) - return -ENXIO; + return -ENODEV; ret = misc_register(&nvram_dev); if (ret) { diff --git a/drivers/char/pcmcia/synclink_cs.c b/drivers/char/pcmcia/synclink_cs.c index 1dd0e992c83d..b694d430f10e 100644 --- a/drivers/char/pcmcia/synclink_cs.c +++ b/drivers/char/pcmcia/synclink_cs.c @@ -514,8 +514,8 @@ static void ldisc_receive_buf(struct tty_struct *tty, return; ld = tty_ldisc_ref(tty); if (ld) { - if (ld->receive_buf) - ld->receive_buf(tty, data, flags, count); + if (ld->ops->receive_buf) + ld->ops->receive_buf(tty, data, flags, count); tty_ldisc_deref(ld); } } @@ -3886,9 +3886,8 @@ static bool rx_get_frame(MGSLPC_INFO *info) framesize = 0; #if SYNCLINK_GENERIC_HDLC { - struct net_device_stats *stats = hdlc_stats(info->netdev); - stats->rx_errors++; - stats->rx_frame_errors++; + info->netdev->stats.rx_errors++; + info->netdev->stats.rx_frame_errors++; } #endif } else @@ -4144,7 +4143,6 @@ static int hdlcdev_attach(struct net_device *dev, unsigned short encoding, static int hdlcdev_xmit(struct sk_buff *skb, struct net_device *dev) { MGSLPC_INFO *info = dev_to_port(dev); - struct net_device_stats *stats = hdlc_stats(dev); unsigned long flags; if (debug_level >= DEBUG_LEVEL_INFO) @@ -4159,8 +4157,8 @@ static int hdlcdev_xmit(struct sk_buff *skb, struct net_device *dev) info->tx_put = info->tx_count = skb->len; /* update network statistics */ - stats->tx_packets++; - stats->tx_bytes += skb->len; + dev->stats.tx_packets++; + dev->stats.tx_bytes += skb->len; /* done with socket buffer, so free it */ dev_kfree_skb(skb); @@ -4376,14 +4374,13 @@ static int hdlcdev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) static void hdlcdev_tx_timeout(struct net_device *dev) { MGSLPC_INFO *info = dev_to_port(dev); - struct net_device_stats *stats = hdlc_stats(dev); unsigned long flags; if (debug_level >= DEBUG_LEVEL_INFO) printk("hdlcdev_tx_timeout(%s)\n",dev->name); - stats->tx_errors++; - stats->tx_aborted_errors++; + dev->stats.tx_errors++; + dev->stats.tx_aborted_errors++; spin_lock_irqsave(&info->lock,flags); tx_stop(info); @@ -4416,27 +4413,26 @@ static void hdlcdev_rx(MGSLPC_INFO *info, char *buf, int size) { struct sk_buff *skb = dev_alloc_skb(size); struct net_device *dev = info->netdev; - struct net_device_stats *stats = hdlc_stats(dev); if (debug_level >= DEBUG_LEVEL_INFO) printk("hdlcdev_rx(%s)\n",dev->name); if (skb == NULL) { printk(KERN_NOTICE "%s: can't alloc skb, dropping packet\n", dev->name); - stats->rx_dropped++; + dev->stats.rx_dropped++; return; } - memcpy(skb_put(skb, size),buf,size); + memcpy(skb_put(skb, size), buf, size); - skb->protocol = hdlc_type_trans(skb, info->netdev); + skb->protocol = hdlc_type_trans(skb, dev); - stats->rx_packets++; - stats->rx_bytes += size; + dev->stats.rx_packets++; + dev->stats.rx_bytes += size; netif_rx(skb); - info->netdev->last_rx = jiffies; + dev->last_rx = jiffies; } /** diff --git a/drivers/char/pty.c b/drivers/char/pty.c index 0a05c038ae6f..76b27932d229 100644 --- a/drivers/char/pty.c +++ b/drivers/char/pty.c @@ -111,7 +111,7 @@ static int pty_write(struct tty_struct * tty, const unsigned char *buf, int coun c = to->receive_room; if (c > count) c = count; - to->ldisc.receive_buf(to, buf, NULL, c); + to->ldisc.ops->receive_buf(to, buf, NULL, c); return c; } @@ -149,11 +149,11 @@ 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.chars_in_buffer) + if (!to || !to->ldisc.ops->chars_in_buffer) return 0; /* The ldisc must report 0 if no characters available to be read */ - count = to->ldisc.chars_in_buffer(to); + count = to->ldisc.ops->chars_in_buffer(to); if (tty->driver->subtype == PTY_TYPE_SLAVE) return count; @@ -186,8 +186,8 @@ static void pty_flush_buffer(struct tty_struct *tty) if (!to) return; - if (to->ldisc.flush_buffer) - to->ldisc.flush_buffer(to); + if (to->ldisc.ops->flush_buffer) + to->ldisc.ops->flush_buffer(to); if (to->packet) { spin_lock_irqsave(&tty->ctrl_lock, flags); diff --git a/drivers/char/rio/cirrus.h b/drivers/char/rio/cirrus.h index a03a538a3efb..5ab51679caa2 100644 --- a/drivers/char/rio/cirrus.h +++ b/drivers/char/rio/cirrus.h @@ -35,9 +35,6 @@ ***************************************************************************/ #ifndef _cirrus_h -#ifndef lint -/* static char* _cirrus_h_sccs = "@(#)cirrus.h 1.16"; */ -#endif #define _cirrus_h 1 /* Bit fields for particular registers shared with driver */ diff --git a/drivers/char/rio/cmdblk.h b/drivers/char/rio/cmdblk.h index c46b2fdb6626..9ed4f861675a 100644 --- a/drivers/char/rio/cmdblk.h +++ b/drivers/char/rio/cmdblk.h @@ -33,12 +33,6 @@ #ifndef __rio_cmdblk_h__ #define __rio_cmdblk_h__ -#ifdef SCCS_LABELS -#ifndef lint -static char *_cmdblk_h_sccs_ = "@(#)cmdblk.h 1.2"; -#endif -#endif - /* ** the structure of a command block, used to queue commands destined for ** a rup. diff --git a/drivers/char/rio/cmdpkt.h b/drivers/char/rio/cmdpkt.h index 357ae5722436..c1e7a2798070 100644 --- a/drivers/char/rio/cmdpkt.h +++ b/drivers/char/rio/cmdpkt.h @@ -32,12 +32,6 @@ #ifndef __rio_cmdpkt_h__ #define __rio_cmdpkt_h__ -#ifdef SCCS_LABELS -#ifndef lint -static char *_cmdpkt_h_sccs_ = "@(#)cmdpkt.h 1.2"; -#endif -#endif - /* ** overlays for the data area of a packet. Used in both directions ** (to build a packet to send, and to interpret a packet that arrives) diff --git a/drivers/char/rio/daemon.h b/drivers/char/rio/daemon.h index 6e63f8b2c479..4af90323fd00 100644 --- a/drivers/char/rio/daemon.h +++ b/drivers/char/rio/daemon.h @@ -33,12 +33,6 @@ #ifndef __rio_daemon_h__ #define __rio_daemon_h__ -#ifdef SCCS_LABELS -#ifndef lint -static char *_daemon_h_sccs_ = "@(#)daemon.h 1.3"; -#endif -#endif - /* ** structures used on /dev/rio diff --git a/drivers/char/rio/errors.h b/drivers/char/rio/errors.h index 1d0d89144337..bdb05234090a 100644 --- a/drivers/char/rio/errors.h +++ b/drivers/char/rio/errors.h @@ -33,12 +33,6 @@ #ifndef __rio_errors_h__ #define __rio_errors_h__ -#ifdef SCCS_LABELS -#ifndef lint -static char *_errors_h_sccs_ = "@(#)errors.h 1.2"; -#endif -#endif - /* ** error codes */ diff --git a/drivers/char/rio/func.h b/drivers/char/rio/func.h index 9e7283bd81a0..078d44f85e45 100644 --- a/drivers/char/rio/func.h +++ b/drivers/char/rio/func.h @@ -35,12 +35,6 @@ #include <linux/kdev_t.h> -#ifdef SCCS_LABELS -#ifndef lint -static char *_func_h_sccs_ = "@(#)func.h 1.3"; -#endif -#endif - /* rioboot.c */ int RIOBootCodeRTA(struct rio_info *, struct DownLoad *); int RIOBootCodeHOST(struct rio_info *, struct DownLoad *); diff --git a/drivers/char/rio/map.h b/drivers/char/rio/map.h index bdbcd09c8b81..8366978578c1 100644 --- a/drivers/char/rio/map.h +++ b/drivers/char/rio/map.h @@ -33,10 +33,6 @@ #ifndef __rio_map_h__ #define __rio_map_h__ -#ifdef SCCS_LABELS -static char *_map_h_sccs_ = "@(#)map.h 1.2"; -#endif - /* ** mapping structure passed to and from the config.rio program to ** determine the current topology of the world diff --git a/drivers/char/rio/param.h b/drivers/char/rio/param.h index 675c200b2459..7e9b6283e8aa 100644 --- a/drivers/char/rio/param.h +++ b/drivers/char/rio/param.h @@ -33,11 +33,6 @@ #ifndef __rio_param_h__ #define __rio_param_h__ -#ifdef SCCS_LABELS -static char *_param_h_sccs_ = "@(#)param.h 1.2"; -#endif - - /* ** the param command block, as used in OPEN and PARAM calls. */ diff --git a/drivers/char/rio/parmmap.h b/drivers/char/rio/parmmap.h index 9764ef85c5a6..acc8fa439df5 100644 --- a/drivers/char/rio/parmmap.h +++ b/drivers/char/rio/parmmap.h @@ -37,13 +37,6 @@ #ifndef _parmap_h #define _parmap_h - -#ifdef SCCS_LABELS -#ifndef lint -/* static char *_rio_parmmap_h_sccs = "@(#)parmmap.h 1.4"; */ -#endif -#endif - typedef struct PARM_MAP PARM_MAP; struct PARM_MAP { diff --git a/drivers/char/rio/pci.h b/drivers/char/rio/pci.h index 1eba9118079b..6032f9135956 100644 --- a/drivers/char/rio/pci.h +++ b/drivers/char/rio/pci.h @@ -33,10 +33,6 @@ #ifndef __rio_pci_h__ #define __rio_pci_h__ -#ifdef SCCS_LABELS -static char *_pci_h_sccs_ = "@(#)pci.h 1.2"; -#endif - /* ** PCI stuff */ diff --git a/drivers/char/rio/protsts.h b/drivers/char/rio/protsts.h index 69fc4bc34153..8ab79401d3ee 100644 --- a/drivers/char/rio/protsts.h +++ b/drivers/char/rio/protsts.h @@ -37,13 +37,6 @@ #ifndef _protsts_h #define _protsts_h 1 - -#ifdef SCCS_LABELS -#ifndef lint -/* static char *_rio_protsts_h_sccs = "@(#)protsts.h 1.4"; */ -#endif -#endif - /************************************************* * ACK bit. Last Packet received OK. Set by * rxpkt to indicate that the Packet has been diff --git a/drivers/char/rio/rio_linux.c b/drivers/char/rio/rio_linux.c index 412777cd1e68..0cdfee152916 100644 --- a/drivers/char/rio/rio_linux.c +++ b/drivers/char/rio/rio_linux.c @@ -25,11 +25,6 @@ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, * USA. * - * Revision history: - * $Log: rio.c,v $ - * Revision 1.1 1999/07/11 10:13:54 wolff - * Initial revision - * * */ #include <linux/module.h> @@ -436,7 +431,7 @@ static void rio_disable_tx_interrupts(void *ptr) { func_enter(); - /* port->gs.flags &= ~GS_TX_INTEN; */ + /* port->gs.port.flags &= ~GS_TX_INTEN; */ func_exit(); } @@ -460,7 +455,7 @@ static void rio_enable_tx_interrupts(void *ptr) * In general we cannot count on "tx empty" interrupts, although * the interrupt routine seems to be able to tell the difference. */ - PortP->gs.flags &= ~GS_TX_INTEN; + PortP->gs.port.flags &= ~GS_TX_INTEN; func_exit(); } @@ -515,7 +510,7 @@ static void rio_shutdown_port(void *ptr) func_enter(); PortP = (struct Port *) ptr; - PortP->gs.tty = NULL; + PortP->gs.port.tty = NULL; func_exit(); } @@ -534,7 +529,7 @@ static void rio_hungup(void *ptr) func_enter(); PortP = (struct Port *) ptr; - PortP->gs.tty = NULL; + PortP->gs.port.tty = NULL; func_exit(); } @@ -554,12 +549,12 @@ static void rio_close(void *ptr) riotclose(ptr); - if (PortP->gs.count) { - printk(KERN_ERR "WARNING port count:%d\n", PortP->gs.count); - PortP->gs.count = 0; + if (PortP->gs.port.count) { + printk(KERN_ERR "WARNING port count:%d\n", PortP->gs.port.count); + PortP->gs.port.count = 0; } - PortP->gs.tty = NULL; + PortP->gs.port.tty = NULL; func_exit(); } @@ -854,8 +849,8 @@ static int rio_init_datastructures(void) /* * Initializing wait queue */ - init_waitqueue_head(&port->gs.open_wait); - init_waitqueue_head(&port->gs.close_wait); + init_waitqueue_head(&port->gs.port.open_wait); + init_waitqueue_head(&port->gs.port.close_wait); } #else /* We could postpone initializing them to when they are configured. */ diff --git a/drivers/char/rio/rioboard.h b/drivers/char/rio/rioboard.h index 822c071a693b..252230043c82 100644 --- a/drivers/char/rio/rioboard.h +++ b/drivers/char/rio/rioboard.h @@ -29,12 +29,6 @@ /* */ /************************************************************************/ -/* History... - -1.0.0 26/04/99 NPV Creation. - -*/ - #ifndef _rioboard_h /* If RIOBOARD.H not already defined */ #define _rioboard_h 1 diff --git a/drivers/char/rio/riocmd.c b/drivers/char/rio/riocmd.c index 7b96e0814887..01f2654d5a2e 100644 --- a/drivers/char/rio/riocmd.c +++ b/drivers/char/rio/riocmd.c @@ -30,9 +30,6 @@ ** ** ----------------------------------------------------------------------------- */ -#ifdef SCCS_LABELS -static char *_riocmd_c_sccs_ = "@(#)riocmd.c 1.2"; -#endif #include <linux/module.h> #include <linux/slab.h> @@ -487,12 +484,12 @@ static int RIOCommandRup(struct rio_info *p, uint Rup, struct Host *HostP, struc ** If the device is a modem, then check the modem ** carrier. */ - if (PortP->gs.tty == NULL) + if (PortP->gs.port.tty == NULL) break; - if (PortP->gs.tty->termios == NULL) + if (PortP->gs.port.tty->termios == NULL) break; - if (!(PortP->gs.tty->termios->c_cflag & CLOCAL) && ((PortP->State & (RIO_MOPEN | RIO_WOPEN)))) { + if (!(PortP->gs.port.tty->termios->c_cflag & CLOCAL) && ((PortP->State & (RIO_MOPEN | RIO_WOPEN)))) { rio_dprintk(RIO_DEBUG_CMD, "Is there a Carrier?\n"); /* @@ -509,7 +506,7 @@ static int RIOCommandRup(struct rio_info *p, uint Rup, struct Host *HostP, struc ** wakeup anyone in WOPEN */ if (PortP->State & (PORT_ISOPEN | RIO_WOPEN)) - wake_up_interruptible(&PortP->gs.open_wait); + wake_up_interruptible(&PortP->gs.port.open_wait); } } else { /* @@ -517,7 +514,7 @@ static int RIOCommandRup(struct rio_info *p, uint Rup, struct Host *HostP, struc */ if (PortP->State & RIO_CARR_ON) { if (PortP->State & (PORT_ISOPEN | RIO_WOPEN | RIO_MOPEN)) - tty_hangup(PortP->gs.tty); + tty_hangup(PortP->gs.port.tty); PortP->State &= ~RIO_CARR_ON; rio_dprintk(RIO_DEBUG_CMD, "Carrirer just went down\n"); } diff --git a/drivers/char/rio/rioctrl.c b/drivers/char/rio/rioctrl.c index d65ceb9a434a..eecee0f576d2 100644 --- a/drivers/char/rio/rioctrl.c +++ b/drivers/char/rio/rioctrl.c @@ -29,10 +29,6 @@ ** ** ----------------------------------------------------------------------------- */ -#ifdef SCCS_LABELS -static char *_rioctrl_c_sccs_ = "@(#)rioctrl.c 1.3"; -#endif - #include <linux/module.h> #include <linux/slab.h> diff --git a/drivers/char/rio/riodrvr.h b/drivers/char/rio/riodrvr.h index 3cffe275f216..0907e711b355 100644 --- a/drivers/char/rio/riodrvr.h +++ b/drivers/char/rio/riodrvr.h @@ -35,10 +35,6 @@ #include <asm/param.h> /* for HZ */ -#ifdef SCCS_LABELS -static char *_riodrvr_h_sccs_ = "@(#)riodrvr.h 1.3"; -#endif - #define MEMDUMP_SIZE 32 #define MOD_DISABLE (RIO_NOREAD|RIO_NOWRITE|RIO_NOXPRINT) diff --git a/drivers/char/rio/rioinfo.h b/drivers/char/rio/rioinfo.h index 8de7966e603a..42ff1e79d96f 100644 --- a/drivers/char/rio/rioinfo.h +++ b/drivers/char/rio/rioinfo.h @@ -33,10 +33,6 @@ #ifndef __rioinfo_h #define __rioinfo_h -#ifdef SCCS_LABELS -static char *_rioinfo_h_sccs_ = "@(#)rioinfo.h 1.2"; -#endif - /* ** Host card data structure */ diff --git a/drivers/char/rio/rioinit.c b/drivers/char/rio/rioinit.c index add1718295ef..be0ba401966e 100644 --- a/drivers/char/rio/rioinit.c +++ b/drivers/char/rio/rioinit.c @@ -29,9 +29,6 @@ ** ** ----------------------------------------------------------------------------- */ -#ifdef SCCS_LABELS -static char *_rioinit_c_sccs_ = "@(#)rioinit.c 1.3"; -#endif #include <linux/module.h> #include <linux/slab.h> diff --git a/drivers/char/rio/riointr.c b/drivers/char/rio/riointr.c index ea21686c69a4..71f87600907c 100644 --- a/drivers/char/rio/riointr.c +++ b/drivers/char/rio/riointr.c @@ -29,10 +29,6 @@ ** ** ----------------------------------------------------------------------------- */ -#ifdef SCCS_LABELS -static char *_riointr_c_sccs_ = "@(#)riointr.c 1.2"; -#endif - #include <linux/module.h> #include <linux/slab.h> @@ -106,7 +102,7 @@ void RIOTxEnable(char *en) PortP = (struct Port *) en; p = (struct rio_info *) PortP->p; - tty = PortP->gs.tty; + tty = PortP->gs.port.tty; rio_dprintk(RIO_DEBUG_INTR, "tx port %d: %d chars queued.\n", PortP->PortNum, PortP->gs.xmit_cnt); @@ -162,7 +158,7 @@ void RIOTxEnable(char *en) rio_spin_unlock_irqrestore(&PortP->portSem, flags); if (PortP->gs.xmit_cnt <= (PortP->gs.wakeup_chars + 2 * PKT_MAX_DATA_LEN)) - tty_wakeup(PortP->gs.tty); + tty_wakeup(PortP->gs.port.tty); } @@ -245,7 +241,7 @@ void RIOServiceHost(struct rio_info *p, struct Host *HostP) ** find corresponding tty structure. The process of mapping ** the ports puts these here. */ - ttyP = PortP->gs.tty; + ttyP = PortP->gs.port.tty; /* ** Lock the port before we begin working on it. @@ -339,7 +335,7 @@ void RIOServiceHost(struct rio_info *p, struct Host *HostP) ** find corresponding tty structure. The process of mapping ** the ports puts these here. */ - ttyP = PortP->gs.tty; + ttyP = PortP->gs.port.tty; /* If ttyP is NULL, the port is getting closed. Forget about it. */ if (!ttyP) { rio_dprintk(RIO_DEBUG_INTR, "no tty, so skipping.\n"); @@ -546,7 +542,7 @@ static void RIOReceive(struct rio_info *p, struct Port *PortP) intCount++; - TtyP = PortP->gs.tty; + TtyP = PortP->gs.port.tty; if (!TtyP) { rio_dprintk(RIO_DEBUG_INTR, "RIOReceive: tty is null. \n"); return; diff --git a/drivers/char/rio/rioparam.c b/drivers/char/rio/rioparam.c index 4810b845cc21..d687c17be152 100644 --- a/drivers/char/rio/rioparam.c +++ b/drivers/char/rio/rioparam.c @@ -30,10 +30,6 @@ ** ----------------------------------------------------------------------------- */ -#ifdef SCCS_LABELS -static char *_rioparam_c_sccs_ = "@(#)rioparam.c 1.3"; -#endif - #include <linux/module.h> #include <linux/slab.h> #include <linux/errno.h> @@ -164,7 +160,7 @@ int RIOParam(struct Port *PortP, int cmd, int Modem, int SleepFlag) func_enter(); - TtyP = PortP->gs.tty; + TtyP = PortP->gs.port.tty; rio_dprintk(RIO_DEBUG_PARAM, "RIOParam: Port:%d cmd:%d Modem:%d SleepFlag:%d Mapped: %d, tty=%p\n", PortP->PortNum, cmd, Modem, SleepFlag, PortP->Mapped, TtyP); diff --git a/drivers/char/rio/rioroute.c b/drivers/char/rio/rioroute.c index 7a9df7dcf9a8..706c2a25f7aa 100644 --- a/drivers/char/rio/rioroute.c +++ b/drivers/char/rio/rioroute.c @@ -29,9 +29,6 @@ ** ** ----------------------------------------------------------------------------- */ -#ifdef SCCS_LABELS -static char *_rioroute_c_sccs_ = "@(#)rioroute.c 1.3"; -#endif #include <linux/module.h> #include <linux/slab.h> diff --git a/drivers/char/rio/riospace.h b/drivers/char/rio/riospace.h index 534f1f5b9f53..ffb31d4332b9 100644 --- a/drivers/char/rio/riospace.h +++ b/drivers/char/rio/riospace.h @@ -33,10 +33,6 @@ #ifndef __rio_riospace_h__ #define __rio_riospace_h__ -#ifdef SCCS_LABELS -static char *_riospace_h_sccs_ = "@(#)riospace.h 1.2"; -#endif - #define RIO_LOCATOR_LEN 16 #define MAX_RIO_BOARDS 4 diff --git a/drivers/char/rio/riotable.c b/drivers/char/rio/riotable.c index 2b24488e95f2..3d15802dc0f3 100644 --- a/drivers/char/rio/riotable.c +++ b/drivers/char/rio/riotable.c @@ -29,9 +29,6 @@ ** ** ----------------------------------------------------------------------------- */ -#ifdef SCCS_LABELS -static char *_riotable_c_sccs_ = "@(#)riotable.c 1.2"; -#endif #include <linux/module.h> #include <linux/slab.h> diff --git a/drivers/char/rio/riotty.c b/drivers/char/rio/riotty.c index c99354843be1..2fb49e89b324 100644 --- a/drivers/char/rio/riotty.c +++ b/drivers/char/rio/riotty.c @@ -29,10 +29,6 @@ ** ** ----------------------------------------------------------------------------- */ -#ifdef SCCS_LABELS -static char *_riotty_c_sccs_ = "@(#)riotty.c 1.3"; -#endif - #define __EXPLICIT_DEF_H__ @@ -144,14 +140,14 @@ int riotopen(struct tty_struct *tty, struct file *filp) tty->driver_data = PortP; - PortP->gs.tty = tty; - PortP->gs.count++; + PortP->gs.port.tty = tty; + PortP->gs.port.count++; rio_dprintk(RIO_DEBUG_TTY, "%d bytes in tx buffer\n", PortP->gs.xmit_cnt); retval = gs_init_port(&PortP->gs); if (retval) { - PortP->gs.count--; + PortP->gs.port.count--; return -ENXIO; } /* @@ -297,7 +293,7 @@ int riotopen(struct tty_struct *tty, struct file *filp) ** insert test for carrier here. -- ??? ** I already see that test here. What's the deal? -- REW */ - if ((PortP->gs.tty->termios->c_cflag & CLOCAL) || + if ((PortP->gs.port.tty->termios->c_cflag & CLOCAL) || (PortP->ModemState & RIOC_MSVR1_CD)) { rio_dprintk(RIO_DEBUG_TTY, "open(%d) Modem carr on\n", SysPort); /* @@ -305,16 +301,16 @@ int riotopen(struct tty_struct *tty, struct file *filp) wakeup((caddr_t) &tp->tm.c_canq); */ PortP->State |= RIO_CARR_ON; - wake_up_interruptible(&PortP->gs.open_wait); + wake_up_interruptible(&PortP->gs.port.open_wait); } else { /* no carrier - wait for DCD */ /* - while (!(PortP->gs.tty->termios->c_state & CARR_ON) && + while (!(PortP->gs.port.tty->termios->c_state & CARR_ON) && !(filp->f_flags & O_NONBLOCK) && !p->RIOHalted ) */ while (!(PortP->State & RIO_CARR_ON) && !(filp->f_flags & O_NONBLOCK) && !p->RIOHalted) { rio_dprintk(RIO_DEBUG_TTY, "open(%d) sleeping for carr on\n", SysPort); /* - PortP->gs.tty->termios->c_state |= WOPEN; + PortP->gs.port.tty->termios->c_state |= WOPEN; */ PortP->State |= RIO_WOPEN; rio_spin_unlock_irqrestore(&PortP->portSem, flags); @@ -384,7 +380,7 @@ int riotclose(void *ptr) /* PortP = p->RIOPortp[SysPort]; */ rio_dprintk(RIO_DEBUG_TTY, "Port is at address %p\n", PortP); /* tp = PortP->TtyP; *//* Get tty */ - tty = PortP->gs.tty; + tty = PortP->gs.port.tty; rio_dprintk(RIO_DEBUG_TTY, "TTY is at address %p\n", tty); if (PortP->gs.closing_wait) diff --git a/drivers/char/rio/route.h b/drivers/char/rio/route.h index 769744e575ab..20ed73f3fd7b 100644 --- a/drivers/char/rio/route.h +++ b/drivers/char/rio/route.h @@ -37,12 +37,6 @@ #ifndef _route_h #define _route_h -#ifdef SCCS_LABELS -#ifndef lint -/* static char *_rio_route_h_sccs = "@(#)route.h 1.3"; */ -#endif -#endif - #define MAX_LINKS 4 #define MAX_NODES 17 /* Maximum nodes in a subnet */ #define NODE_BYTES ((MAX_NODES / 8) + 1) /* Number of bytes needed for diff --git a/drivers/char/rio/unixrup.h b/drivers/char/rio/unixrup.h index 46bd532f7746..7abf0cba0f2c 100644 --- a/drivers/char/rio/unixrup.h +++ b/drivers/char/rio/unixrup.h @@ -33,10 +33,6 @@ #ifndef __rio_unixrup_h__ #define __rio_unixrup_h__ -#ifdef SCCS_LABELS -static char *_unixrup_h_sccs_ = "@(#)unixrup.h 1.2"; -#endif - /* ** UnixRup data structure. This contains pointers to actual RUPs on the ** host card, and all the command/boot control stuff. diff --git a/drivers/char/riscom8.c b/drivers/char/riscom8.c index f073c710ab8d..724b2b20f4b2 100644 --- a/drivers/char/riscom8.c +++ b/drivers/char/riscom8.c @@ -322,7 +322,7 @@ static struct riscom_port *rc_get_port(struct riscom_board const *bp, channel = rc_in(bp, CD180_GICR) >> GICR_CHAN_OFF; if (channel < CD180_NCH) { port = &rc_port[board_No(bp) * RC_NPORT + channel]; - if (port->flags & ASYNC_INITIALIZED) + if (port->port.flags & ASYNC_INITIALIZED) return port; } printk(KERN_ERR "rc%d: %s interrupt from invalid port %d\n", @@ -341,7 +341,7 @@ static void rc_receive_exc(struct riscom_board const *bp) if (port == NULL) return; - tty = port->tty; + tty = port->port.tty; #ifdef RC_REPORT_OVERRUN status = rc_in(bp, CD180_RCSR); @@ -364,7 +364,7 @@ static void rc_receive_exc(struct riscom_board const *bp) printk(KERN_INFO "rc%d: port %d: Handling break...\n", board_No(bp), port_No(port)); flag = TTY_BREAK; - if (port->flags & ASYNC_SAK) + if (port->port.flags & ASYNC_SAK) do_SAK(tty); } else if (status & RCSR_PE) @@ -392,7 +392,7 @@ static void rc_receive(struct riscom_board const *bp) if (port == NULL) return; - tty = port->tty; + tty = port->port.tty; count = rc_in(bp, CD180_RDCR); @@ -422,7 +422,7 @@ static void rc_transmit(struct riscom_board const *bp) if (port == NULL) return; - tty = port->tty; + tty = port->port.tty; if (port->IER & IER_TXEMPTY) { /* FIFO drained */ @@ -467,7 +467,7 @@ static void rc_transmit(struct riscom_board const *bp) count = CD180_NFIFO; do { - rc_out(bp, CD180_TDR, port->xmit_buf[port->xmit_tail++]); + rc_out(bp, CD180_TDR, port->port.xmit_buf[port->xmit_tail++]); port->xmit_tail = port->xmit_tail & (SERIAL_XMIT_SIZE-1); if (--port->xmit_cnt <= 0) break; @@ -492,12 +492,12 @@ static void rc_check_modem(struct riscom_board const *bp) if (port == NULL) return; - tty = port->tty; + tty = port->port.tty; mcr = rc_in(bp, CD180_MCR); if (mcr & MCR_CDCHG) { if (rc_in(bp, CD180_MSVR) & MSVR_CD) - wake_up_interruptible(&port->open_wait); + wake_up_interruptible(&port->port.open_wait); else tty_hangup(tty); } @@ -632,15 +632,12 @@ static void rc_shutdown_board(struct riscom_board *bp) */ static void rc_change_speed(struct riscom_board *bp, struct riscom_port *port) { - struct tty_struct *tty = port->tty; + struct tty_struct *tty = port->port.tty; unsigned long baud; long tmp; unsigned char cor1 = 0, cor3 = 0; unsigned char mcor1 = 0, mcor2 = 0; - if (tty == NULL || tty->termios == NULL) - return; - port->IER = 0; port->COR2 = 0; port->MSVR = MSVR_RTS; @@ -786,39 +783,30 @@ static int rc_setup_port(struct riscom_board *bp, struct riscom_port *port) { unsigned long flags; - if (port->flags & ASYNC_INITIALIZED) + if (port->port.flags & ASYNC_INITIALIZED) return 0; - if (!port->xmit_buf) { - /* We may sleep in get_zeroed_page() */ - unsigned long tmp = get_zeroed_page(GFP_KERNEL); - if (tmp == 0) - return -ENOMEM; - if (port->xmit_buf) - free_page(tmp); - else - port->xmit_buf = (unsigned char *) tmp; - } + if (tty_port_alloc_xmit_buf(&port->port) < 0) + return -ENOMEM; + spin_lock_irqsave(&riscom_lock, flags); - if (port->tty) - clear_bit(TTY_IO_ERROR, &port->tty->flags); - if (port->count == 1) + clear_bit(TTY_IO_ERROR, &port->port.tty->flags); + if (port->port.count == 1) bp->count++; port->xmit_cnt = port->xmit_head = port->xmit_tail = 0; rc_change_speed(bp, port); - port->flags |= ASYNC_INITIALIZED; + port->port.flags |= ASYNC_INITIALIZED; spin_unlock_irqrestore(&riscom_lock, flags); return 0; } /* Must be called with interrupts disabled */ -static void rc_shutdown_port(struct riscom_board *bp, struct riscom_port *port) +static void rc_shutdown_port(struct tty_struct *tty, + struct riscom_board *bp, struct riscom_port *port) { - struct tty_struct *tty; - - if (!(port->flags & ASYNC_INITIALIZED)) + if (!(port->port.flags & ASYNC_INITIALIZED)) return; #ifdef RC_REPORT_OVERRUN @@ -836,14 +824,8 @@ static void rc_shutdown_port(struct riscom_board *bp, struct riscom_port *port) printk("].\n"); } #endif - if (port->xmit_buf) { - free_page((unsigned long) port->xmit_buf); - port->xmit_buf = NULL; - } - - tty = port->tty; - - if (tty == NULL || C_HUPCL(tty)) { + tty_port_free_xmit_buf(&port->port); + if (C_HUPCL(tty)) { /* Drop DTR */ bp->DTR |= (1u << port_No(port)); rc_out(bp, RC_DTR, bp->DTR); @@ -858,9 +840,8 @@ static void rc_shutdown_port(struct riscom_board *bp, struct riscom_port *port) port->IER = 0; rc_out(bp, CD180_IER, port->IER); - if (tty) - set_bit(TTY_IO_ERROR, &tty->flags); - port->flags &= ~ASYNC_INITIALIZED; + set_bit(TTY_IO_ERROR, &tty->flags); + port->port.flags &= ~ASYNC_INITIALIZED; if (--bp->count < 0) { printk(KERN_INFO "rc%d: rc_shutdown_port: " @@ -890,9 +871,9 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp, * If the device is in the middle of being closed, then block * until it's done, and then try again. */ - if (tty_hung_up_p(filp) || port->flags & ASYNC_CLOSING) { - interruptible_sleep_on(&port->close_wait); - if (port->flags & ASYNC_HUP_NOTIFY) + if (tty_hung_up_p(filp) || port->port.flags & ASYNC_CLOSING) { + interruptible_sleep_on(&port->port.close_wait); + if (port->port.flags & ASYNC_HUP_NOTIFY) return -EAGAIN; else return -ERESTARTSYS; @@ -904,7 +885,7 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp, */ if ((filp->f_flags & O_NONBLOCK) || (tty->flags & (1 << TTY_IO_ERROR))) { - port->flags |= ASYNC_NORMAL_ACTIVE; + port->port.flags |= ASYNC_NORMAL_ACTIVE; return 0; } @@ -919,16 +900,16 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp, * exit, either normal or abnormal. */ retval = 0; - add_wait_queue(&port->open_wait, &wait); + add_wait_queue(&port->port.open_wait, &wait); spin_lock_irqsave(&riscom_lock, flags); if (!tty_hung_up_p(filp)) - port->count--; + port->port.count--; spin_unlock_irqrestore(&riscom_lock, flags); - port->blocked_open++; + port->port.blocked_open++; while (1) { spin_lock_irqsave(&riscom_lock, flags); @@ -942,14 +923,14 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp, set_current_state(TASK_INTERRUPTIBLE); if (tty_hung_up_p(filp) || - !(port->flags & ASYNC_INITIALIZED)) { - if (port->flags & ASYNC_HUP_NOTIFY) + !(port->port.flags & ASYNC_INITIALIZED)) { + if (port->port.flags & ASYNC_HUP_NOTIFY) retval = -EAGAIN; else retval = -ERESTARTSYS; break; } - if (!(port->flags & ASYNC_CLOSING) && + if (!(port->port.flags & ASYNC_CLOSING) && (do_clocal || CD)) break; if (signal_pending(current)) { @@ -959,14 +940,14 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp, schedule(); } __set_current_state(TASK_RUNNING); - remove_wait_queue(&port->open_wait, &wait); + remove_wait_queue(&port->port.open_wait, &wait); if (!tty_hung_up_p(filp)) - port->count++; - port->blocked_open--; + port->port.count++; + port->port.blocked_open--; if (retval) return retval; - port->flags |= ASYNC_NORMAL_ACTIVE; + port->port.flags |= ASYNC_NORMAL_ACTIVE; return 0; } @@ -990,9 +971,9 @@ static int rc_open(struct tty_struct *tty, struct file *filp) if (error) return error; - port->count++; + port->port.count++; tty->driver_data = port; - port->tty = tty; + port->port.tty = tty; error = rc_setup_port(bp, port); if (error == 0) @@ -1031,28 +1012,28 @@ static void rc_close(struct tty_struct *tty, struct file *filp) goto out; bp = port_Board(port); - if ((tty->count == 1) && (port->count != 1)) { + if ((tty->count == 1) && (port->port.count != 1)) { printk(KERN_INFO "rc%d: rc_close: bad port count;" " tty->count is 1, port count is %d\n", - board_No(bp), port->count); - port->count = 1; + board_No(bp), port->port.count); + port->port.count = 1; } - if (--port->count < 0) { + if (--port->port.count < 0) { printk(KERN_INFO "rc%d: rc_close: bad port count " "for tty%d: %d\n", - board_No(bp), port_No(port), port->count); - port->count = 0; + board_No(bp), port_No(port), port->port.count); + port->port.count = 0; } - if (port->count) + if (port->port.count) goto out; - port->flags |= ASYNC_CLOSING; + port->port.flags |= ASYNC_CLOSING; /* * Now we wait for the transmit buffer to clear; and we notify * the line discipline to only process XON/XOFF characters. */ tty->closing = 1; - if (port->closing_wait != ASYNC_CLOSING_WAIT_NONE) - tty_wait_until_sent(tty, port->closing_wait); + if (port->port.closing_wait != ASYNC_CLOSING_WAIT_NONE) + tty_wait_until_sent(tty, port->port.closing_wait); /* * At this point we stop accepting input. To do this, we * disable the receive line status interrupts, and tell the @@ -1060,7 +1041,7 @@ static void rc_close(struct tty_struct *tty, struct file *filp) * line status register. */ port->IER &= ~IER_RXD; - if (port->flags & ASYNC_INITIALIZED) { + if (port->port.flags & ASYNC_INITIALIZED) { port->IER &= ~IER_TXRDY; port->IER |= IER_TXEMPTY; rc_out(bp, CD180_CAR, port_No(port)); @@ -1077,19 +1058,19 @@ static void rc_close(struct tty_struct *tty, struct file *filp) break; } } - rc_shutdown_port(bp, port); + rc_shutdown_port(tty, bp, port); rc_flush_buffer(tty); tty_ldisc_flush(tty); tty->closing = 0; - port->tty = NULL; - if (port->blocked_open) { - if (port->close_delay) - msleep_interruptible(jiffies_to_msecs(port->close_delay)); - wake_up_interruptible(&port->open_wait); + port->port.tty = NULL; + if (port->port.blocked_open) { + if (port->port.close_delay) + msleep_interruptible(jiffies_to_msecs(port->port.close_delay)); + wake_up_interruptible(&port->port.open_wait); } - port->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING); - wake_up_interruptible(&port->close_wait); + port->port.flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING); + wake_up_interruptible(&port->port.close_wait); out: spin_unlock_irqrestore(&riscom_lock, flags); @@ -1108,9 +1089,6 @@ static int rc_write(struct tty_struct *tty, bp = port_Board(port); - if (!tty || !port->xmit_buf) - return 0; - while (1) { spin_lock_irqsave(&riscom_lock, flags); @@ -1119,7 +1097,7 @@ static int rc_write(struct tty_struct *tty, if (c <= 0) break; /* lock continues to be held */ - memcpy(port->xmit_buf + port->xmit_head, buf, c); + memcpy(port->port.xmit_buf + port->xmit_head, buf, c); port->xmit_head = (port->xmit_head + c) & (SERIAL_XMIT_SIZE-1); port->xmit_cnt += c; @@ -1151,15 +1129,12 @@ static int rc_put_char(struct tty_struct *tty, unsigned char ch) if (rc_paranoia_check(port, tty->name, "rc_put_char")) return 0; - if (!tty || !port->xmit_buf) - return 0; - spin_lock_irqsave(&riscom_lock, flags); if (port->xmit_cnt >= SERIAL_XMIT_SIZE - 1) goto out; - port->xmit_buf[port->xmit_head++] = ch; + port->port.xmit_buf[port->xmit_head++] = ch; port->xmit_head &= SERIAL_XMIT_SIZE - 1; port->xmit_cnt++; ret = 1; @@ -1177,8 +1152,7 @@ static void rc_flush_chars(struct tty_struct *tty) if (rc_paranoia_check(port, tty->name, "rc_flush_chars")) return; - if (port->xmit_cnt <= 0 || tty->stopped || tty->hw_stopped || - !port->xmit_buf) + if (port->xmit_cnt <= 0 || tty->stopped || tty->hw_stopped) return; spin_lock_irqsave(&riscom_lock, flags); @@ -1317,22 +1291,22 @@ static int rc_set_serial_info(struct riscom_port *port, return -EINVAL; #endif - change_speed = ((port->flags & ASYNC_SPD_MASK) != + change_speed = ((port->port.flags & ASYNC_SPD_MASK) != (tmp.flags & ASYNC_SPD_MASK)); if (!capable(CAP_SYS_ADMIN)) { - if ((tmp.close_delay != port->close_delay) || - (tmp.closing_wait != port->closing_wait) || + if ((tmp.close_delay != port->port.close_delay) || + (tmp.closing_wait != port->port.closing_wait) || ((tmp.flags & ~ASYNC_USR_MASK) != - (port->flags & ~ASYNC_USR_MASK))) + (port->port.flags & ~ASYNC_USR_MASK))) return -EPERM; - port->flags = ((port->flags & ~ASYNC_USR_MASK) | + port->port.flags = ((port->port.flags & ~ASYNC_USR_MASK) | (tmp.flags & ASYNC_USR_MASK)); } else { - port->flags = ((port->flags & ~ASYNC_FLAGS) | + port->port.flags = ((port->port.flags & ~ASYNC_FLAGS) | (tmp.flags & ASYNC_FLAGS)); - port->close_delay = tmp.close_delay; - port->closing_wait = tmp.closing_wait; + port->port.close_delay = tmp.close_delay; + port->port.closing_wait = tmp.closing_wait; } if (change_speed) { unsigned long flags; @@ -1355,10 +1329,10 @@ static int rc_get_serial_info(struct riscom_port *port, tmp.line = port - rc_port; tmp.port = bp->base; tmp.irq = bp->irq; - tmp.flags = port->flags; + tmp.flags = port->port.flags; tmp.baud_base = (RC_OSCFREQ + CD180_TPC/2) / CD180_TPC; - tmp.close_delay = port->close_delay * HZ/100; - tmp.closing_wait = port->closing_wait * HZ/100; + tmp.close_delay = port->port.close_delay * HZ/100; + tmp.closing_wait = port->port.closing_wait * HZ/100; tmp.xmit_fifo_size = CD180_NFIFO; return copy_to_user(retinfo, &tmp, sizeof(tmp)) ? -EFAULT : 0; } @@ -1480,7 +1454,7 @@ static void rc_start(struct tty_struct *tty) spin_lock_irqsave(&riscom_lock, flags); - if (port->xmit_cnt && port->xmit_buf && !(port->IER & IER_TXRDY)) { + if (port->xmit_cnt && port->port.xmit_buf && !(port->IER & IER_TXRDY)) { port->IER |= IER_TXRDY; rc_out(bp, CD180_CAR, port_No(port)); rc_out(bp, CD180_IER, port->IER); @@ -1498,11 +1472,11 @@ static void rc_hangup(struct tty_struct *tty) bp = port_Board(port); - rc_shutdown_port(bp, port); - port->count = 0; - port->flags &= ~ASYNC_NORMAL_ACTIVE; - port->tty = NULL; - wake_up_interruptible(&port->open_wait); + rc_shutdown_port(tty, bp, port); + port->port.count = 0; + port->port.flags &= ~ASYNC_NORMAL_ACTIVE; + port->port.tty = NULL; + wake_up_interruptible(&port->port.open_wait); } static void rc_set_termios(struct tty_struct *tty, @@ -1575,11 +1549,8 @@ static int __init rc_init_drivers(void) } memset(rc_port, 0, sizeof(rc_port)); for (i = 0; i < RC_NPORT * RC_NBOARD; i++) { + tty_port_init(&rc_port[i].port); rc_port[i].magic = RISCOM8_MAGIC; - rc_port[i].close_delay = 50 * HZ / 100; - rc_port[i].closing_wait = 3000 * HZ / 100; - init_waitqueue_head(&rc_port[i].open_wait); - init_waitqueue_head(&rc_port[i].close_wait); } return 0; } diff --git a/drivers/char/riscom8.h b/drivers/char/riscom8.h index cdfdf4394477..c9876b3f9714 100644 --- a/drivers/char/riscom8.h +++ b/drivers/char/riscom8.h @@ -66,23 +66,15 @@ struct riscom_board { struct riscom_port { int magic; + struct tty_port port; int baud_base; - int flags; - struct tty_struct * tty; - int count; - int blocked_open; int timeout; - int close_delay; - unsigned char * xmit_buf; int custom_divisor; int xmit_head; int xmit_tail; int xmit_cnt; - wait_queue_head_t open_wait; - wait_queue_head_t close_wait; short wakeup_chars; short break_length; - unsigned short closing_wait; unsigned char mark_mask; unsigned char IER; unsigned char MSVR; diff --git a/drivers/char/rocket.c b/drivers/char/rocket.c index 743dc80a9325..e670eae2f510 100644 --- a/drivers/char/rocket.c +++ b/drivers/char/rocket.c @@ -72,6 +72,7 @@ #include <linux/tty.h> #include <linux/tty_driver.h> #include <linux/tty_flip.h> +#include <linux/serial.h> #include <linux/string.h> #include <linux/fcntl.h> #include <linux/ptrace.h> @@ -81,7 +82,7 @@ #include <linux/completion.h> #include <linux/wait.h> #include <linux/pci.h> -#include <asm/uaccess.h> +#include <linux/uaccess.h> #include <asm/atomic.h> #include <asm/unaligned.h> #include <linux/bitops.h> @@ -434,15 +435,15 @@ static void rp_do_transmit(struct r_port *info) #endif if (!info) return; - if (!info->tty) { + if (!info->port.tty) { printk(KERN_WARNING "rp: WARNING %s called with " - "info->tty==NULL\n", __func__); + "info->port.tty==NULL\n", __func__); clear_bit((info->aiop * 8) + info->chan, (void *) &xmit_flags[info->board]); return; } spin_lock_irqsave(&info->slock, flags); - tty = info->tty; + tty = info->port.tty; info->xmit_fifo_room = TXFIFO_SIZE - sGetTxCnt(cp); /* Loop sending data to FIFO until done or FIFO full */ @@ -502,13 +503,13 @@ static void rp_handle_port(struct r_port *info) "info->flags & NOT_INIT\n"); return; } - if (!info->tty) { + if (!info->port.tty) { printk(KERN_WARNING "rp: WARNING: rp_handle_port called with " - "info->tty==NULL\n"); + "info->port.tty==NULL\n"); return; } cp = &info->channel; - tty = info->tty; + tty = info->port.tty; IntMask = sGetChanIntID(cp) & info->intmask; #ifdef ROCKET_DEBUG_INTR @@ -530,7 +531,7 @@ static void rp_handle_port(struct r_port *info) tty_hangup(tty); } info->cd_status = (ChanStatus & CD_ACT) ? 1 : 0; - wake_up_interruptible(&info->open_wait); + wake_up_interruptible(&info->port.open_wait); } #ifdef ROCKET_DEBUG_INTR if (IntMask & DELTA_CTS) { /* CTS change */ @@ -648,9 +649,9 @@ static void init_r_port(int board, int aiop, int chan, struct pci_dev *pci_dev) info->board = board; info->aiop = aiop; info->chan = chan; - info->closing_wait = 3000; - info->close_delay = 50; - init_waitqueue_head(&info->open_wait); + info->port.closing_wait = 3000; + info->port.close_delay = 50; + init_waitqueue_head(&info->port.open_wait); init_completion(&info->close_wait); info->flags &= ~ROCKET_MODE_MASK; switch (pc104[board][line]) { @@ -717,7 +718,7 @@ static void configure_r_port(struct r_port *info, unsigned rocketMode; int bits, baud, divisor; CHANNEL_t *cp; - struct ktermios *t = info->tty->termios; + struct ktermios *t = info->port.tty->termios; cp = &info->channel; cflag = t->c_cflag; @@ -750,7 +751,7 @@ static void configure_r_port(struct r_port *info, } /* baud rate */ - baud = tty_get_baud_rate(info->tty); + baud = tty_get_baud_rate(info->port.tty); if (!baud) baud = 9600; divisor = ((rp_baud_base[info->board] + (baud >> 1)) / baud) - 1; @@ -768,7 +769,7 @@ static void configure_r_port(struct r_port *info, sSetBaud(cp, divisor); /* FIXME: Should really back compute a baud rate from the divisor */ - tty_encode_baud_rate(info->tty, baud, baud); + tty_encode_baud_rate(info->port.tty, baud, baud); if (cflag & CRTSCTS) { info->intmask |= DELTA_CTS; @@ -793,15 +794,15 @@ static void configure_r_port(struct r_port *info, * Handle software flow control in the board */ #ifdef ROCKET_SOFT_FLOW - if (I_IXON(info->tty)) { + if (I_IXON(info->port.tty)) { sEnTxSoftFlowCtl(cp); - if (I_IXANY(info->tty)) { + if (I_IXANY(info->port.tty)) { sEnIXANY(cp); } else { sDisIXANY(cp); } - sSetTxXONChar(cp, START_CHAR(info->tty)); - sSetTxXOFFChar(cp, STOP_CHAR(info->tty)); + sSetTxXONChar(cp, START_CHAR(info->port.tty)); + sSetTxXOFFChar(cp, STOP_CHAR(info->port.tty)); } else { sDisTxSoftFlowCtl(cp); sDisIXANY(cp); @@ -813,24 +814,24 @@ static void configure_r_port(struct r_port *info, * Set up ignore/read mask words */ info->read_status_mask = STMRCVROVRH | 0xFF; - if (I_INPCK(info->tty)) + if (I_INPCK(info->port.tty)) info->read_status_mask |= STMFRAMEH | STMPARITYH; - if (I_BRKINT(info->tty) || I_PARMRK(info->tty)) + if (I_BRKINT(info->port.tty) || I_PARMRK(info->port.tty)) info->read_status_mask |= STMBREAKH; /* * Characters to ignore */ info->ignore_status_mask = 0; - if (I_IGNPAR(info->tty)) + if (I_IGNPAR(info->port.tty)) info->ignore_status_mask |= STMFRAMEH | STMPARITYH; - if (I_IGNBRK(info->tty)) { + if (I_IGNBRK(info->port.tty)) { info->ignore_status_mask |= STMBREAKH; /* * If we're ignoring parity and break indicators, * ignore overruns too. (For real raw support). */ - if (I_IGNPAR(info->tty)) + if (I_IGNPAR(info->port.tty)) info->ignore_status_mask |= STMRCVROVRH; } @@ -863,7 +864,7 @@ static void configure_r_port(struct r_port *info, } } -/* info->count is considered critical, protected by spinlocks. */ +/* info->port.count is considered critical, protected by spinlocks. */ static int block_til_ready(struct tty_struct *tty, struct file *filp, struct r_port *info) { @@ -897,13 +898,13 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp, /* * Block waiting for the carrier detect and the line to become free. While we are in - * this loop, info->count is dropped by one, so that rp_close() knows when to free things. + * this loop, info->port.count is dropped by one, so that rp_close() knows when to free things. * We restore it upon exit, either normal or abnormal. */ retval = 0; - add_wait_queue(&info->open_wait, &wait); + add_wait_queue(&info->port.open_wait, &wait); #ifdef ROCKET_DEBUG_OPEN - printk(KERN_INFO "block_til_ready before block: ttyR%d, count = %d\n", info->line, info->count); + printk(KERN_INFO "block_til_ready before block: ttyR%d, count = %d\n", info->line, info->port.count); #endif spin_lock_irqsave(&info->slock, flags); @@ -912,10 +913,10 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp, #else if (!tty_hung_up_p(filp)) { extra_count = 1; - info->count--; + info->port.count--; } #endif - info->blocked_open++; + info->port.blocked_open++; spin_unlock_irqrestore(&info->slock, flags); @@ -940,24 +941,24 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp, } #ifdef ROCKET_DEBUG_OPEN printk(KERN_INFO "block_til_ready blocking: ttyR%d, count = %d, flags=0x%0x\n", - info->line, info->count, info->flags); + info->line, info->port.count, info->flags); #endif schedule(); /* Don't hold spinlock here, will hang PC */ } __set_current_state(TASK_RUNNING); - remove_wait_queue(&info->open_wait, &wait); + remove_wait_queue(&info->port.open_wait, &wait); spin_lock_irqsave(&info->slock, flags); if (extra_count) - info->count++; - info->blocked_open--; + info->port.count++; + info->port.blocked_open--; spin_unlock_irqrestore(&info->slock, flags); #ifdef ROCKET_DEBUG_OPEN printk(KERN_INFO "block_til_ready after blocking: ttyR%d, count = %d\n", - info->line, info->count); + info->line, info->port.count); #endif if (retval) return retval; @@ -1001,9 +1002,9 @@ static int rp_open(struct tty_struct *tty, struct file *filp) info->xmit_buf = (unsigned char *) page; tty->driver_data = info; - info->tty = tty; + info->port.tty = tty; - if (info->count++ == 0) { + if (info->port.count++ == 0) { atomic_inc(&rp_num_ports_open); #ifdef ROCKET_DEBUG_OPEN @@ -1012,7 +1013,7 @@ static int rp_open(struct tty_struct *tty, struct file *filp) #endif } #ifdef ROCKET_DEBUG_OPEN - printk(KERN_INFO "rp_open ttyR%d, count=%d\n", info->line, info->count); + printk(KERN_INFO "rp_open ttyR%d, count=%d\n", info->line, info->port.count); #endif /* @@ -1048,13 +1049,13 @@ static int rp_open(struct tty_struct *tty, struct file *filp) * Set up the tty->alt_speed kludge */ if ((info->flags & ROCKET_SPD_MASK) == ROCKET_SPD_HI) - info->tty->alt_speed = 57600; + info->port.tty->alt_speed = 57600; if ((info->flags & ROCKET_SPD_MASK) == ROCKET_SPD_VHI) - info->tty->alt_speed = 115200; + info->port.tty->alt_speed = 115200; if ((info->flags & ROCKET_SPD_MASK) == ROCKET_SPD_SHI) - info->tty->alt_speed = 230400; + info->port.tty->alt_speed = 230400; if ((info->flags & ROCKET_SPD_MASK) == ROCKET_SPD_WARP) - info->tty->alt_speed = 460800; + info->port.tty->alt_speed = 460800; configure_r_port(info, NULL); if (tty->termios->c_cflag & CBAUD) { @@ -1076,7 +1077,7 @@ static int rp_open(struct tty_struct *tty, struct file *filp) } /* - * Exception handler that closes a serial port. info->count is considered critical. + * Exception handler that closes a serial port. info->port.count is considered critical. */ static void rp_close(struct tty_struct *tty, struct file *filp) { @@ -1089,14 +1090,14 @@ static void rp_close(struct tty_struct *tty, struct file *filp) return; #ifdef ROCKET_DEBUG_OPEN - printk(KERN_INFO "rp_close ttyR%d, count = %d\n", info->line, info->count); + printk(KERN_INFO "rp_close ttyR%d, count = %d\n", info->line, info->port.count); #endif if (tty_hung_up_p(filp)) return; spin_lock_irqsave(&info->slock, flags); - if ((tty->count == 1) && (info->count != 1)) { + if ((tty->count == 1) && (info->port.count != 1)) { /* * Uh, oh. tty->count is 1, which means that the tty * structure will be freed. Info->count should always @@ -1105,15 +1106,15 @@ static void rp_close(struct tty_struct *tty, struct file *filp) * serial port won't be shutdown. */ printk(KERN_WARNING "rp_close: bad serial port count; " - "tty->count is 1, info->count is %d\n", info->count); - info->count = 1; + "tty->count is 1, info->port.count is %d\n", info->port.count); + info->port.count = 1; } - if (--info->count < 0) { + if (--info->port.count < 0) { printk(KERN_WARNING "rp_close: bad serial port count for " - "ttyR%d: %d\n", info->line, info->count); - info->count = 0; + "ttyR%d: %d\n", info->line, info->port.count); + info->port.count = 0; } - if (info->count) { + if (info->port.count) { spin_unlock_irqrestore(&info->slock, flags); return; } @@ -1137,8 +1138,8 @@ static void rp_close(struct tty_struct *tty, struct file *filp) /* * Wait for the transmit buffer to clear */ - if (info->closing_wait != ROCKET_CLOSING_WAIT_NONE) - tty_wait_until_sent(tty, info->closing_wait); + if (info->port.closing_wait != ROCKET_CLOSING_WAIT_NONE) + tty_wait_until_sent(tty, info->port.closing_wait); /* * Before we drop DTR, make sure the UART transmitter * has completely drained; this is especially @@ -1167,11 +1168,11 @@ static void rp_close(struct tty_struct *tty, struct file *filp) clear_bit((info->aiop * 8) + info->chan, (void *) &xmit_flags[info->board]); - if (info->blocked_open) { - if (info->close_delay) { - msleep_interruptible(jiffies_to_msecs(info->close_delay)); + if (info->port.blocked_open) { + if (info->port.close_delay) { + msleep_interruptible(jiffies_to_msecs(info->port.close_delay)); } - wake_up_interruptible(&info->open_wait); + wake_up_interruptible(&info->port.open_wait); } else { if (info->xmit_buf) { free_page((unsigned long) info->xmit_buf); @@ -1327,8 +1328,8 @@ static int get_config(struct r_port *info, struct rocket_config __user *retinfo) memset(&tmp, 0, sizeof (tmp)); tmp.line = info->line; tmp.flags = info->flags; - tmp.close_delay = info->close_delay; - tmp.closing_wait = info->closing_wait; + tmp.close_delay = info->port.close_delay; + tmp.closing_wait = info->port.closing_wait; tmp.port = rcktpt_io_addr[(info->line >> 5) & 3]; if (copy_to_user(retinfo, &tmp, sizeof (*retinfo))) @@ -1353,17 +1354,17 @@ static int set_config(struct r_port *info, struct rocket_config __user *new_info } info->flags = ((info->flags & ~ROCKET_FLAGS) | (new_serial.flags & ROCKET_FLAGS)); - info->close_delay = new_serial.close_delay; - info->closing_wait = new_serial.closing_wait; + info->port.close_delay = new_serial.close_delay; + info->port.closing_wait = new_serial.closing_wait; if ((info->flags & ROCKET_SPD_MASK) == ROCKET_SPD_HI) - info->tty->alt_speed = 57600; + info->port.tty->alt_speed = 57600; if ((info->flags & ROCKET_SPD_MASK) == ROCKET_SPD_VHI) - info->tty->alt_speed = 115200; + info->port.tty->alt_speed = 115200; if ((info->flags & ROCKET_SPD_MASK) == ROCKET_SPD_SHI) - info->tty->alt_speed = 230400; + info->port.tty->alt_speed = 230400; if ((info->flags & ROCKET_SPD_MASK) == ROCKET_SPD_WARP) - info->tty->alt_speed = 460800; + info->port.tty->alt_speed = 460800; configure_r_port(info, NULL); return 0; @@ -1636,13 +1637,13 @@ static void rp_hangup(struct tty_struct *tty) rp_flush_buffer(tty); if (info->flags & ROCKET_CLOSING) return; - if (info->count) + if (info->port.count) atomic_dec(&rp_num_ports_open); clear_bit((info->aiop * 8) + info->chan, (void *) &xmit_flags[info->board]); - info->count = 0; + info->port.count = 0; info->flags &= ~ROCKET_NORMAL_ACTIVE; - info->tty = NULL; + info->port.tty = NULL; cp = &info->channel; sDisRxFIFO(cp); @@ -1653,7 +1654,7 @@ static void rp_hangup(struct tty_struct *tty) sClrTxXOFF(cp); info->flags &= ~ROCKET_INITIALIZED; - wake_up_interruptible(&info->open_wait); + wake_up_interruptible(&info->port.open_wait); } /* @@ -1762,7 +1763,7 @@ static int rp_write(struct tty_struct *tty, /* Write remaining data into the port's xmit_buf */ while (1) { - if (!info->tty) /* Seemingly obligatory check... */ + if (!info->port.tty) /* Seemingly obligatory check... */ goto end; c = min(count, XMIT_BUF_SIZE - info->xmit_cnt - 1); c = min(c, XMIT_BUF_SIZE - info->xmit_head); diff --git a/drivers/char/rocket.h b/drivers/char/rocket.h index ae6b04f90c03..a8b09195ebba 100644 --- a/drivers/char/rocket.h +++ b/drivers/char/rocket.h @@ -64,8 +64,8 @@ struct rocket_version { /* * For closing_wait and closing_wait2 */ -#define ROCKET_CLOSING_WAIT_NONE 65535 -#define ROCKET_CLOSING_WAIT_INF 0 +#define ROCKET_CLOSING_WAIT_NONE ASYNC_CLOSING_WAIT_NONE +#define ROCKET_CLOSING_WAIT_INF ASYNC_CLOSING_WAIT_INF /* * Rocketport ioctls -- "RP" diff --git a/drivers/char/rocket_int.h b/drivers/char/rocket_int.h index 143cc432fdb2..21f3ff53ba32 100644 --- a/drivers/char/rocket_int.h +++ b/drivers/char/rocket_int.h @@ -1125,18 +1125,14 @@ Warnings: This function writes the data byte without checking to see if struct r_port { int magic; + struct tty_port port; int line; - int flags; - int count; - int blocked_open; - struct tty_struct *tty; + int flags; /* Don't yet match the ASY_ flags!! */ unsigned int board:3; unsigned int aiop:2; unsigned int chan:3; CONTROLLER_t *ctlp; CHANNEL_t channel; - int closing_wait; - int close_delay; int intmask; int xmit_fifo_room; /* room in xmit fifo */ unsigned char *xmit_buf; @@ -1148,8 +1144,7 @@ struct r_port { int read_status_mask; int cps; - wait_queue_head_t open_wait; - struct completion close_wait; + struct completion close_wait; /* Not yet matching the core */ spinlock_t slock; struct mutex write_mtx; }; diff --git a/drivers/char/selection.c b/drivers/char/selection.c index d63f5ccc29e6..2978a49a172b 100644 --- a/drivers/char/selection.c +++ b/drivers/char/selection.c @@ -327,7 +327,8 @@ int paste_selection(struct tty_struct *tty) } count = sel_buffer_lth - pasted; count = min(count, tty->receive_room); - tty->ldisc.receive_buf(tty, sel_buffer + pasted, NULL, count); + tty->ldisc.ops->receive_buf(tty, sel_buffer + pasted, + NULL, count); pasted += count; } remove_wait_queue(&vc->paste_wait, &wait); diff --git a/drivers/char/specialix.c b/drivers/char/specialix.c index 2ee4d9893757..037dc47e4cb1 100644 --- a/drivers/char/specialix.c +++ b/drivers/char/specialix.c @@ -608,9 +608,9 @@ static inline struct specialix_port * sx_get_port(struct specialix_board * bp, dprintk (SX_DEBUG_CHAN, "channel: %d\n", channel); if (channel < CD186x_NCH) { port = &sx_port[board_No(bp) * SX_NPORT + channel]; - dprintk (SX_DEBUG_CHAN, "port: %d %p flags: 0x%x\n",board_No(bp) * SX_NPORT + channel, port, port->flags & ASYNC_INITIALIZED); + dprintk (SX_DEBUG_CHAN, "port: %d %p flags: 0x%lx\n",board_No(bp) * SX_NPORT + channel, port, port->port.flags & ASYNC_INITIALIZED); - if (port->flags & ASYNC_INITIALIZED) { + if (port->port.flags & ASYNC_INITIALIZED) { dprintk (SX_DEBUG_CHAN, "port: %d %p\n", channel, port); func_exit(); return port; @@ -637,7 +637,7 @@ static inline void sx_receive_exc(struct specialix_board * bp) func_exit(); return; } - tty = port->tty; + tty = port->port.tty; status = sx_in(bp, CD186x_RCSR); @@ -673,7 +673,7 @@ static inline void sx_receive_exc(struct specialix_board * bp) dprintk(SX_DEBUG_RX, "sx%d: port %d: Handling break...\n", board_No(bp), port_No(port)); flag = TTY_BREAK; - if (port->flags & ASYNC_SAK) + if (port->port.flags & ASYNC_SAK) do_SAK(tty); } else if (status & RCSR_PE) @@ -707,7 +707,7 @@ static inline void sx_receive(struct specialix_board * bp) func_exit(); return; } - tty = port->tty; + tty = port->port.tty; count = sx_in(bp, CD186x_RDCR); dprintk (SX_DEBUG_RX, "port: %p: count: %d\n", port, count); @@ -734,7 +734,7 @@ static inline void sx_transmit(struct specialix_board * bp) return; } dprintk (SX_DEBUG_TX, "port: %p\n", port); - tty = port->tty; + tty = port->port.tty; if (port->IER & IER_TXEMPTY) { /* FIFO drained */ @@ -811,7 +811,7 @@ static inline void sx_check_modem(struct specialix_board * bp) if (!(port = sx_get_port(bp, "Modem"))) return; - tty = port->tty; + tty = port->port.tty; mcr = sx_in(bp, CD186x_MCR); printk ("mcr = %02x.\n", mcr); @@ -821,7 +821,7 @@ static inline void sx_check_modem(struct specialix_board * bp) msvr_cd = sx_in(bp, CD186x_MSVR) & MSVR_CD; if (msvr_cd) { dprintk (SX_DEBUG_SIGNALS, "Waking up guys in open.\n"); - wake_up_interruptible(&port->open_wait); + wake_up_interruptible(&port->port.open_wait); } else { dprintk (SX_DEBUG_SIGNALS, "Sending HUP.\n"); tty_hangup(tty); @@ -1030,7 +1030,7 @@ static void sx_change_speed(struct specialix_board *bp, struct specialix_port *p func_enter(); - if (!(tty = port->tty) || !tty->termios) { + if (!(tty = port->port.tty) || !tty->termios) { func_exit(); return; } @@ -1052,9 +1052,9 @@ static void sx_change_speed(struct specialix_board *bp, struct specialix_port *p baud = tty_get_baud_rate(tty); if (baud == 38400) { - if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI) + if ((port->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI) baud = 57600; - if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI) + if ((port->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI) baud = 115200; } @@ -1244,7 +1244,7 @@ static int sx_setup_port(struct specialix_board *bp, struct specialix_port *port func_enter(); - if (port->flags & ASYNC_INITIALIZED) { + if (port->port.flags & ASYNC_INITIALIZED) { func_exit(); return 0; } @@ -1268,12 +1268,12 @@ static int sx_setup_port(struct specialix_board *bp, struct specialix_port *port spin_lock_irqsave(&port->lock, flags); - if (port->tty) - clear_bit(TTY_IO_ERROR, &port->tty->flags); + if (port->port.tty) + clear_bit(TTY_IO_ERROR, &port->port.tty->flags); port->xmit_cnt = port->xmit_head = port->xmit_tail = 0; sx_change_speed(bp, port); - port->flags |= ASYNC_INITIALIZED; + port->port.flags |= ASYNC_INITIALIZED; spin_unlock_irqrestore(&port->lock, flags); @@ -1292,7 +1292,7 @@ static void sx_shutdown_port(struct specialix_board *bp, struct specialix_port * func_enter(); - if (!(port->flags & ASYNC_INITIALIZED)) { + if (!(port->port.flags & ASYNC_INITIALIZED)) { func_exit(); return; } @@ -1315,7 +1315,7 @@ static void sx_shutdown_port(struct specialix_board *bp, struct specialix_port * spin_lock_irqsave(&bp->lock, flags); sx_out(bp, CD186x_CAR, port_No(port)); - if (!(tty = port->tty) || C_HUPCL(tty)) { + if (!(tty = port->port.tty) || C_HUPCL(tty)) { /* Drop DTR */ sx_out(bp, CD186x_MSVDTR, 0); } @@ -1330,7 +1330,7 @@ static void sx_shutdown_port(struct specialix_board *bp, struct specialix_port * spin_unlock_irqrestore(&bp->lock, flags); if (tty) set_bit(TTY_IO_ERROR, &tty->flags); - port->flags &= ~ASYNC_INITIALIZED; + port->port.flags &= ~ASYNC_INITIALIZED; if (!bp->count) sx_shutdown_board(bp); @@ -1354,9 +1354,9 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp, * If the device is in the middle of being closed, then block * until it's done, and then try again. */ - if (tty_hung_up_p(filp) || port->flags & ASYNC_CLOSING) { - interruptible_sleep_on(&port->close_wait); - if (port->flags & ASYNC_HUP_NOTIFY) { + if (tty_hung_up_p(filp) || port->port.flags & ASYNC_CLOSING) { + interruptible_sleep_on(&port->port.close_wait); + if (port->port.flags & ASYNC_HUP_NOTIFY) { func_exit(); return -EAGAIN; } else { @@ -1371,7 +1371,7 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp, */ if ((filp->f_flags & O_NONBLOCK) || (tty->flags & (1 << TTY_IO_ERROR))) { - port->flags |= ASYNC_NORMAL_ACTIVE; + port->port.flags |= ASYNC_NORMAL_ACTIVE; func_exit(); return 0; } @@ -1387,13 +1387,13 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp, * exit, either normal or abnormal. */ retval = 0; - add_wait_queue(&port->open_wait, &wait); + add_wait_queue(&port->port.open_wait, &wait); spin_lock_irqsave(&port->lock, flags); if (!tty_hung_up_p(filp)) { - port->count--; + port->port.count--; } spin_unlock_irqrestore(&port->lock, flags); - port->blocked_open++; + port->port.blocked_open++; while (1) { spin_lock_irqsave(&bp->lock, flags); sx_out(bp, CD186x_CAR, port_No(port)); @@ -1410,14 +1410,14 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp, spin_unlock_irqrestore(&bp->lock, flags); set_current_state(TASK_INTERRUPTIBLE); if (tty_hung_up_p(filp) || - !(port->flags & ASYNC_INITIALIZED)) { - if (port->flags & ASYNC_HUP_NOTIFY) + !(port->port.flags & ASYNC_INITIALIZED)) { + if (port->port.flags & ASYNC_HUP_NOTIFY) retval = -EAGAIN; else retval = -ERESTARTSYS; break; } - if (!(port->flags & ASYNC_CLOSING) && + if (!(port->port.flags & ASYNC_CLOSING) && (do_clocal || CD)) break; if (signal_pending(current)) { @@ -1428,19 +1428,19 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp, } set_current_state(TASK_RUNNING); - remove_wait_queue(&port->open_wait, &wait); + remove_wait_queue(&port->port.open_wait, &wait); spin_lock_irqsave(&port->lock, flags); if (!tty_hung_up_p(filp)) { - port->count++; + port->port.count++; } - port->blocked_open--; + port->port.blocked_open--; spin_unlock_irqrestore(&port->lock, flags); if (retval) { func_exit(); return retval; } - port->flags |= ASYNC_NORMAL_ACTIVE; + port->port.flags |= ASYNC_NORMAL_ACTIVE; func_exit(); return 0; } @@ -1484,10 +1484,10 @@ static int sx_open(struct tty_struct * tty, struct file * filp) } spin_lock_irqsave(&bp->lock, flags); - port->count++; + port->port.count++; bp->count++; tty->driver_data = port; - port->tty = tty; + port->port.tty = tty; spin_unlock_irqrestore(&bp->lock, flags); if ((error = sx_setup_port(bp, port))) { @@ -1547,15 +1547,15 @@ static void sx_close(struct tty_struct * tty, struct file * filp) } bp = port_Board(port); - if ((tty->count == 1) && (port->count != 1)) { + if ((tty->count == 1) && (port->port.count != 1)) { printk(KERN_ERR "sx%d: sx_close: bad port count;" " tty->count is 1, port count is %d\n", - board_No(bp), port->count); - port->count = 1; + board_No(bp), port->port.count); + port->port.count = 1; } - if (port->count > 1) { - port->count--; + if (port->port.count > 1) { + port->port.count--; bp->count--; spin_unlock_irqrestore(&port->lock, flags); @@ -1563,7 +1563,7 @@ static void sx_close(struct tty_struct * tty, struct file * filp) func_exit(); return; } - port->flags |= ASYNC_CLOSING; + port->port.flags |= ASYNC_CLOSING; /* * Now we wait for the transmit buffer to clear; and we notify * the line discipline to only process XON/XOFF characters. @@ -1571,8 +1571,8 @@ static void sx_close(struct tty_struct * tty, struct file * filp) tty->closing = 1; spin_unlock_irqrestore(&port->lock, flags); dprintk (SX_DEBUG_OPEN, "Closing\n"); - if (port->closing_wait != ASYNC_CLOSING_WAIT_NONE) { - tty_wait_until_sent(tty, port->closing_wait); + if (port->port.closing_wait != ASYNC_CLOSING_WAIT_NONE) { + tty_wait_until_sent(tty, port->port.closing_wait); } /* * At this point we stop accepting input. To do this, we @@ -1582,7 +1582,7 @@ static void sx_close(struct tty_struct * tty, struct file * filp) */ dprintk (SX_DEBUG_OPEN, "Closed\n"); port->IER &= ~IER_RXD; - if (port->flags & ASYNC_INITIALIZED) { + if (port->port.flags & ASYNC_INITIALIZED) { port->IER &= ~IER_TXRDY; port->IER |= IER_TXEMPTY; spin_lock_irqsave(&bp->lock, flags); @@ -1611,10 +1611,10 @@ static void sx_close(struct tty_struct * tty, struct file * filp) board_No(bp), bp->count, tty->index); bp->count = 0; } - if (--port->count < 0) { + if (--port->port.count < 0) { printk(KERN_ERR "sx%d: sx_close: bad port count for tty%d: %d\n", - board_No(bp), port_No(port), port->count); - port->count = 0; + board_No(bp), port_No(port), port->port.count); + port->port.count = 0; } sx_shutdown_port(bp, port); @@ -1622,16 +1622,16 @@ static void sx_close(struct tty_struct * tty, struct file * filp) tty_ldisc_flush(tty); spin_lock_irqsave(&port->lock, flags); tty->closing = 0; - port->tty = NULL; + port->port.tty = NULL; spin_unlock_irqrestore(&port->lock, flags); - if (port->blocked_open) { - if (port->close_delay) { - msleep_interruptible(jiffies_to_msecs(port->close_delay)); + if (port->port.blocked_open) { + if (port->port.close_delay) { + msleep_interruptible(jiffies_to_msecs(port->port.close_delay)); } - wake_up_interruptible(&port->open_wait); + wake_up_interruptible(&port->port.open_wait); } - port->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING); - wake_up_interruptible(&port->close_wait); + port->port.flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING); + wake_up_interruptible(&port->port.close_wait); func_exit(); } @@ -1815,7 +1815,7 @@ static int sx_tiocmget(struct tty_struct *tty, struct file *file) dprintk (SX_DEBUG_INIT, "Got msvr[%d] = %02x, car = %d.\n", port_No(port), status, sx_in (bp, CD186x_CAR)); dprintk (SX_DEBUG_INIT, "sx_port = %p, port = %p\n", sx_port, port); - if (SX_CRTSCTS(port->tty)) { + if (SX_CRTSCTS(port->port.tty)) { result = /* (status & MSVR_RTS) ? */ TIOCM_DTR /* : 0) */ | ((status & MSVR_DTR) ? TIOCM_RTS : 0) | ((status & MSVR_CD) ? TIOCM_CAR : 0) @@ -1857,7 +1857,7 @@ static int sx_tiocmset(struct tty_struct *tty, struct file *file, /* if (set & TIOCM_DTR) port->MSVR |= MSVR_DTR; */ - if (SX_CRTSCTS(port->tty)) { + if (SX_CRTSCTS(port->port.tty)) { if (set & TIOCM_RTS) port->MSVR |= MSVR_DTR; } else { @@ -1869,7 +1869,7 @@ static int sx_tiocmset(struct tty_struct *tty, struct file *file, port->MSVR &= ~MSVR_RTS; */ /* if (clear & TIOCM_DTR) port->MSVR &= ~MSVR_DTR; */ - if (SX_CRTSCTS(port->tty)) { + if (SX_CRTSCTS(port->port.tty)) { if (clear & TIOCM_RTS) port->MSVR &= ~MSVR_DTR; } else { @@ -1929,27 +1929,27 @@ static inline int sx_set_serial_info(struct specialix_port * port, lock_kernel(); - change_speed = ((port->flags & ASYNC_SPD_MASK) != + change_speed = ((port->port.flags & ASYNC_SPD_MASK) != (tmp.flags & ASYNC_SPD_MASK)); change_speed |= (tmp.custom_divisor != port->custom_divisor); if (!capable(CAP_SYS_ADMIN)) { - if ((tmp.close_delay != port->close_delay) || - (tmp.closing_wait != port->closing_wait) || + if ((tmp.close_delay != port->port.close_delay) || + (tmp.closing_wait != port->port.closing_wait) || ((tmp.flags & ~ASYNC_USR_MASK) != - (port->flags & ~ASYNC_USR_MASK))) { + (port->port.flags & ~ASYNC_USR_MASK))) { func_exit(); unlock_kernel(); return -EPERM; } - port->flags = ((port->flags & ~ASYNC_USR_MASK) | + port->port.flags = ((port->port.flags & ~ASYNC_USR_MASK) | (tmp.flags & ASYNC_USR_MASK)); port->custom_divisor = tmp.custom_divisor; } else { - port->flags = ((port->flags & ~ASYNC_FLAGS) | + port->port.flags = ((port->port.flags & ~ASYNC_FLAGS) | (tmp.flags & ASYNC_FLAGS)); - port->close_delay = tmp.close_delay; - port->closing_wait = tmp.closing_wait; + port->port.close_delay = tmp.close_delay; + port->port.closing_wait = tmp.closing_wait; port->custom_divisor = tmp.custom_divisor; } if (change_speed) { @@ -1975,10 +1975,10 @@ static inline int sx_get_serial_info(struct specialix_port * port, tmp.line = port - sx_port; tmp.port = bp->base; tmp.irq = bp->irq; - tmp.flags = port->flags; + tmp.flags = port->port.flags; tmp.baud_base = (SX_OSCFREQ + CD186x_TPC/2) / CD186x_TPC; - tmp.close_delay = port->close_delay * HZ/100; - tmp.closing_wait = port->closing_wait * HZ/100; + tmp.close_delay = port->port.close_delay * HZ/100; + tmp.closing_wait = port->port.closing_wait * HZ/100; tmp.custom_divisor = port->custom_divisor; tmp.xmit_fifo_size = CD186x_NFIFO; unlock_kernel(); @@ -2199,17 +2199,17 @@ static void sx_hangup(struct tty_struct * tty) sx_shutdown_port(bp, port); spin_lock_irqsave(&port->lock, flags); - bp->count -= port->count; + bp->count -= port->port.count; if (bp->count < 0) { printk(KERN_ERR "sx%d: sx_hangup: bad board count: %d port: %d\n", board_No(bp), bp->count, tty->index); bp->count = 0; } - port->count = 0; - port->flags &= ~ASYNC_NORMAL_ACTIVE; - port->tty = NULL; + port->port.count = 0; + port->port.flags &= ~ASYNC_NORMAL_ACTIVE; + port->port.tty = NULL; spin_unlock_irqrestore(&port->lock, flags); - wake_up_interruptible(&port->open_wait); + wake_up_interruptible(&port->port.open_wait); func_exit(); } @@ -2224,10 +2224,6 @@ static void sx_set_termios(struct tty_struct * tty, struct ktermios * old_termio if (sx_paranoia_check(port, tty->name, "sx_set_termios")) return; - if (tty->termios->c_cflag == old_termios->c_cflag && - tty->termios->c_iflag == old_termios->c_iflag) - return; - bp = port_Board(port); spin_lock_irqsave(&port->lock, flags); sx_change_speed(port_Board(port), port); @@ -2297,10 +2293,7 @@ static int sx_init_drivers(void) memset(sx_port, 0, sizeof(sx_port)); for (i = 0; i < SX_NPORT * SX_NBOARD; i++) { sx_port[i].magic = SPECIALIX_MAGIC; - sx_port[i].close_delay = 50 * HZ/100; - sx_port[i].closing_wait = 3000 * HZ/100; - init_waitqueue_head(&sx_port[i].open_wait); - init_waitqueue_head(&sx_port[i].close_wait); + tty_port_init(&sx_port[i].port); spin_lock_init(&sx_port[i].lock); } diff --git a/drivers/char/specialix_io8.h b/drivers/char/specialix_io8.h index 3f2f85bdf516..c63005274d9b 100644 --- a/drivers/char/specialix_io8.h +++ b/drivers/char/specialix_io8.h @@ -107,23 +107,17 @@ struct specialix_board { struct specialix_port { int magic; + struct tty_port port; int baud_base; int flags; - struct tty_struct * tty; - int count; - int blocked_open; int timeout; - int close_delay; unsigned char * xmit_buf; int custom_divisor; int xmit_head; int xmit_tail; int xmit_cnt; - wait_queue_head_t open_wait; - wait_queue_head_t close_wait; short wakeup_chars; short break_length; - unsigned short closing_wait; unsigned char mark_mask; unsigned char IER; unsigned char MSVR; diff --git a/drivers/char/stallion.c b/drivers/char/stallion.c index d17be10c5d21..0243efb0be95 100644 --- a/drivers/char/stallion.c +++ b/drivers/char/stallion.c @@ -613,17 +613,17 @@ static void stl_cd_change(struct stlport *portp) { unsigned int oldsigs = portp->sigs; - if (!portp->tty) + if (!portp->port.tty) return; portp->sigs = stl_getsignals(portp); if ((portp->sigs & TIOCM_CD) && ((oldsigs & TIOCM_CD) == 0)) - wake_up_interruptible(&portp->open_wait); + wake_up_interruptible(&portp->port.open_wait); if ((oldsigs & TIOCM_CD) && ((portp->sigs & TIOCM_CD) == 0)) - if (portp->flags & ASYNC_CHECK_CD) - tty_hangup(portp->tty); + if (portp->port.flags & ASYNC_CHECK_CD) + tty_hangup(portp->port.tty); } /* @@ -734,11 +734,11 @@ static int stl_open(struct tty_struct *tty, struct file *filp) * On the first open of the device setup the port hardware, and * initialize the per port data structure. */ - portp->tty = tty; + portp->port.tty = tty; tty->driver_data = portp; - portp->refcount++; + portp->port.count++; - if ((portp->flags & ASYNC_INITIALIZED) == 0) { + if ((portp->port.flags & ASYNC_INITIALIZED) == 0) { if (!portp->tx.buf) { portp->tx.buf = kmalloc(STL_TXBUFSIZE, GFP_KERNEL); if (!portp->tx.buf) @@ -752,7 +752,7 @@ static int stl_open(struct tty_struct *tty, struct file *filp) stl_enablerxtx(portp, 1, 1); stl_startrxtx(portp, 1, 0); clear_bit(TTY_IO_ERROR, &tty->flags); - portp->flags |= ASYNC_INITIALIZED; + portp->port.flags |= ASYNC_INITIALIZED; } /* @@ -761,9 +761,9 @@ static int stl_open(struct tty_struct *tty, struct file *filp) * The sleep here does not need interrupt protection since the wakeup * for it is done with the same context. */ - if (portp->flags & ASYNC_CLOSING) { - interruptible_sleep_on(&portp->close_wait); - if (portp->flags & ASYNC_HUP_NOTIFY) + if (portp->port.flags & ASYNC_CLOSING) { + interruptible_sleep_on(&portp->port.close_wait); + if (portp->port.flags & ASYNC_HUP_NOTIFY) return -EAGAIN; return -ERESTARTSYS; } @@ -777,7 +777,7 @@ static int stl_open(struct tty_struct *tty, struct file *filp) if ((rc = stl_waitcarrier(portp, filp)) != 0) return rc; - portp->flags |= ASYNC_NORMAL_ACTIVE; + portp->port.flags |= ASYNC_NORMAL_ACTIVE; return 0; } @@ -801,25 +801,25 @@ static int stl_waitcarrier(struct stlport *portp, struct file *filp) spin_lock_irqsave(&stallion_lock, flags); - if (portp->tty->termios->c_cflag & CLOCAL) + if (portp->port.tty->termios->c_cflag & CLOCAL) doclocal++; portp->openwaitcnt++; if (! tty_hung_up_p(filp)) - portp->refcount--; + portp->port.count--; for (;;) { /* Takes brd_lock internally */ stl_setsignals(portp, 1, 1); if (tty_hung_up_p(filp) || - ((portp->flags & ASYNC_INITIALIZED) == 0)) { - if (portp->flags & ASYNC_HUP_NOTIFY) + ((portp->port.flags & ASYNC_INITIALIZED) == 0)) { + if (portp->port.flags & ASYNC_HUP_NOTIFY) rc = -EBUSY; else rc = -ERESTARTSYS; break; } - if (((portp->flags & ASYNC_CLOSING) == 0) && + if (((portp->port.flags & ASYNC_CLOSING) == 0) && (doclocal || (portp->sigs & TIOCM_CD))) break; if (signal_pending(current)) { @@ -827,11 +827,11 @@ static int stl_waitcarrier(struct stlport *portp, struct file *filp) break; } /* FIXME */ - interruptible_sleep_on(&portp->open_wait); + interruptible_sleep_on(&portp->port.open_wait); } if (! tty_hung_up_p(filp)) - portp->refcount++; + portp->port.count++; portp->openwaitcnt--; spin_unlock_irqrestore(&stallion_lock, flags); @@ -904,15 +904,15 @@ static void stl_close(struct tty_struct *tty, struct file *filp) spin_unlock_irqrestore(&stallion_lock, flags); return; } - if ((tty->count == 1) && (portp->refcount != 1)) - portp->refcount = 1; - if (portp->refcount-- > 1) { + if ((tty->count == 1) && (portp->port.count != 1)) + portp->port.count = 1; + if (portp->port.count-- > 1) { spin_unlock_irqrestore(&stallion_lock, flags); return; } - portp->refcount = 0; - portp->flags |= ASYNC_CLOSING; + portp->port.count = 0; + portp->port.flags |= ASYNC_CLOSING; /* * May want to wait for any data to drain before closing. The BUSY @@ -930,7 +930,7 @@ static void stl_close(struct tty_struct *tty, struct file *filp) spin_lock_irqsave(&stallion_lock, flags); - portp->flags &= ~ASYNC_INITIALIZED; + portp->port.flags &= ~ASYNC_INITIALIZED; spin_unlock_irqrestore(&stallion_lock, flags); stl_disableintrs(portp); @@ -949,16 +949,16 @@ static void stl_close(struct tty_struct *tty, struct file *filp) tty_ldisc_flush(tty); tty->closing = 0; - portp->tty = NULL; + portp->port.tty = NULL; if (portp->openwaitcnt) { if (portp->close_delay) msleep_interruptible(jiffies_to_msecs(portp->close_delay)); - wake_up_interruptible(&portp->open_wait); + wake_up_interruptible(&portp->port.open_wait); } - portp->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING); - wake_up_interruptible(&portp->close_wait); + portp->port.flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING); + wake_up_interruptible(&portp->port.close_wait); } /*****************************************************************************/ @@ -1153,7 +1153,7 @@ static int stl_getserial(struct stlport *portp, struct serial_struct __user *sp) memset(&sio, 0, sizeof(struct serial_struct)); sio.line = portp->portnr; sio.port = portp->ioaddr; - sio.flags = portp->flags; + sio.flags = portp->port.flags; sio.baud_base = portp->baud_base; sio.close_delay = portp->close_delay; sio.closing_wait = portp->closing_wait; @@ -1194,17 +1194,17 @@ static int stl_setserial(struct stlport *portp, struct serial_struct __user *sp) if ((sio.baud_base != portp->baud_base) || (sio.close_delay != portp->close_delay) || ((sio.flags & ~ASYNC_USR_MASK) != - (portp->flags & ~ASYNC_USR_MASK))) + (portp->port.flags & ~ASYNC_USR_MASK))) return -EPERM; } - portp->flags = (portp->flags & ~ASYNC_USR_MASK) | + portp->port.flags = (portp->port.flags & ~ASYNC_USR_MASK) | (sio.flags & ASYNC_USR_MASK); portp->baud_base = sio.baud_base; portp->close_delay = sio.close_delay; portp->closing_wait = sio.closing_wait; portp->custom_divisor = sio.custom_divisor; - stl_setport(portp, portp->tty->termios); + stl_setport(portp, portp->port.tty->termios); return 0; } @@ -1353,7 +1353,7 @@ static void stl_settermios(struct tty_struct *tty, struct ktermios *old) stl_start(tty); } if (((old->c_cflag & CLOCAL) == 0) && (tiosp->c_cflag & CLOCAL)) - wake_up_interruptible(&portp->open_wait); + wake_up_interruptible(&portp->port.open_wait); } /*****************************************************************************/ @@ -1438,7 +1438,7 @@ static void stl_hangup(struct tty_struct *tty) if (portp == NULL) return; - portp->flags &= ~ASYNC_INITIALIZED; + portp->port.flags &= ~ASYNC_INITIALIZED; stl_disableintrs(portp); if (tty->termios->c_cflag & HUPCL) stl_setsignals(portp, 0, 0); @@ -1452,10 +1452,10 @@ static void stl_hangup(struct tty_struct *tty) portp->tx.head = NULL; portp->tx.tail = NULL; } - portp->tty = NULL; - portp->flags &= ~ASYNC_NORMAL_ACTIVE; - portp->refcount = 0; - wake_up_interruptible(&portp->open_wait); + portp->port.tty = NULL; + portp->port.flags &= ~ASYNC_NORMAL_ACTIVE; + portp->port.count = 0; + wake_up_interruptible(&portp->port.open_wait); } /*****************************************************************************/ @@ -1814,8 +1814,8 @@ static int __devinit stl_initports(struct stlbrd *brdp, struct stlpanel *panelp) portp->baud_base = STL_BAUDBASE; portp->close_delay = STL_CLOSEDELAY; portp->closing_wait = 30 * HZ; - init_waitqueue_head(&portp->open_wait); - init_waitqueue_head(&portp->close_wait); + init_waitqueue_head(&portp->port.open_wait); + init_waitqueue_head(&portp->port.close_wait); portp->stats.brd = portp->brdnr; portp->stats.panel = portp->panelnr; portp->stats.port = portp->portnr; @@ -1840,8 +1840,8 @@ static void stl_cleanup_panels(struct stlbrd *brdp) portp = panelp->ports[k]; if (portp == NULL) continue; - if (portp->tty != NULL) - stl_hangup(portp->tty); + if (portp->port.tty != NULL) + stl_hangup(portp->port.tty); kfree(portp->tx.buf); kfree(portp); } @@ -2513,7 +2513,7 @@ static int stl_getportstats(struct stlport *portp, comstats_t __user *cp) } portp->stats.state = portp->istate; - portp->stats.flags = portp->flags; + portp->stats.flags = portp->port.flags; portp->stats.hwid = portp->hwid; portp->stats.ttystate = 0; @@ -2524,16 +2524,16 @@ static int stl_getportstats(struct stlport *portp, comstats_t __user *cp) portp->stats.rxbuffered = 0; spin_lock_irqsave(&stallion_lock, flags); - if (portp->tty != NULL) - if (portp->tty->driver_data == portp) { - portp->stats.ttystate = portp->tty->flags; + if (portp->port.tty != NULL) + if (portp->port.tty->driver_data == portp) { + portp->stats.ttystate = portp->port.tty->flags; /* No longer available as a statistic */ - portp->stats.rxbuffered = 1; /*portp->tty->flip.count; */ - if (portp->tty->termios != NULL) { - portp->stats.cflags = portp->tty->termios->c_cflag; - portp->stats.iflags = portp->tty->termios->c_iflag; - portp->stats.oflags = portp->tty->termios->c_oflag; - portp->stats.lflags = portp->tty->termios->c_lflag; + portp->stats.rxbuffered = 1; /*portp->port.tty->flip.count; */ + if (portp->port.tty->termios != NULL) { + portp->stats.cflags = portp->port.tty->termios->c_cflag; + portp->stats.iflags = portp->port.tty->termios->c_iflag; + portp->stats.oflags = portp->port.tty->termios->c_oflag; + portp->stats.lflags = portp->port.tty->termios->c_lflag; } } spin_unlock_irqrestore(&stallion_lock, flags); @@ -2939,15 +2939,15 @@ static void stl_cd1400setport(struct stlport *portp, struct ktermios *tiosp) } baudrate = stl_baudrates[baudrate]; if ((tiosp->c_cflag & CBAUD) == B38400) { - if ((portp->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI) + if ((portp->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI) baudrate = 57600; - else if ((portp->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI) + else if ((portp->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI) baudrate = 115200; - else if ((portp->flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI) + else if ((portp->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI) baudrate = 230400; - else if ((portp->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP) + else if ((portp->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP) baudrate = 460800; - else if ((portp->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST) + else if ((portp->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST) baudrate = (portp->baud_base / portp->custom_divisor); } if (baudrate > STL_CD1400MAXBAUD) @@ -2969,9 +2969,9 @@ static void stl_cd1400setport(struct stlport *portp, struct ktermios *tiosp) mcor1 |= MCOR1_DCD; mcor2 |= MCOR2_DCD; sreron |= SRER_MODEM; - portp->flags |= ASYNC_CHECK_CD; + portp->port.flags |= ASYNC_CHECK_CD; } else - portp->flags &= ~ASYNC_CHECK_CD; + portp->port.flags &= ~ASYNC_CHECK_CD; /* * Setup cd1400 enhanced modes if we can. In particular we want to @@ -3242,7 +3242,7 @@ static void stl_cd1400flowctrl(struct stlport *portp, int state) if (portp == NULL) return; - tty = portp->tty; + tty = portp->port.tty; if (tty == NULL) return; @@ -3304,7 +3304,7 @@ static void stl_cd1400sendflow(struct stlport *portp, int state) if (portp == NULL) return; - tty = portp->tty; + tty = portp->port.tty; if (tty == NULL) return; @@ -3503,8 +3503,8 @@ static void stl_cd1400txisr(struct stlpanel *panelp, int ioaddr) if ((len == 0) || ((len < STL_TXBUFLOW) && (test_bit(ASYI_TXLOW, &portp->istate) == 0))) { set_bit(ASYI_TXLOW, &portp->istate); - if (portp->tty) - tty_wakeup(portp->tty); + if (portp->port.tty) + tty_wakeup(portp->port.tty); } if (len == 0) { @@ -3568,7 +3568,7 @@ static void stl_cd1400rxisr(struct stlpanel *panelp, int ioaddr) return; } portp = panelp->ports[(ioack >> 3)]; - tty = portp->tty; + tty = portp->port.tty; if ((ioack & ACK_TYPMASK) == ACK_TYPRXGOOD) { outb((RDCR + portp->uartaddr), ioaddr); @@ -3613,7 +3613,7 @@ static void stl_cd1400rxisr(struct stlpanel *panelp, int ioaddr) if (portp->rxmarkmsk & status) { if (status & ST_BREAK) { status = TTY_BREAK; - if (portp->flags & ASYNC_SAK) { + if (portp->port.flags & ASYNC_SAK) { do_SAK(tty); BRDENABLE(portp->brdnr, portp->pagenr); } @@ -3899,15 +3899,15 @@ static void stl_sc26198setport(struct stlport *portp, struct ktermios *tiosp) } baudrate = stl_baudrates[baudrate]; if ((tiosp->c_cflag & CBAUD) == B38400) { - if ((portp->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI) + if ((portp->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI) baudrate = 57600; - else if ((portp->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI) + else if ((portp->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI) baudrate = 115200; - else if ((portp->flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI) + else if ((portp->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI) baudrate = 230400; - else if ((portp->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP) + else if ((portp->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP) baudrate = 460800; - else if ((portp->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST) + else if ((portp->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST) baudrate = (portp->baud_base / portp->custom_divisor); } if (baudrate > STL_SC26198MAXBAUD) @@ -3922,11 +3922,11 @@ static void stl_sc26198setport(struct stlport *portp, struct ktermios *tiosp) * Check what form of modem signaling is required and set it up. */ if (tiosp->c_cflag & CLOCAL) { - portp->flags &= ~ASYNC_CHECK_CD; + portp->port.flags &= ~ASYNC_CHECK_CD; } else { iopr |= IOPR_DCDCOS; imron |= IR_IOPORT; - portp->flags |= ASYNC_CHECK_CD; + portp->port.flags |= ASYNC_CHECK_CD; } /* @@ -4174,7 +4174,7 @@ static void stl_sc26198flowctrl(struct stlport *portp, int state) if (portp == NULL) return; - tty = portp->tty; + tty = portp->port.tty; if (tty == NULL) return; @@ -4243,7 +4243,7 @@ static void stl_sc26198sendflow(struct stlport *portp, int state) if (portp == NULL) return; - tty = portp->tty; + tty = portp->port.tty; if (tty == NULL) return; @@ -4421,8 +4421,8 @@ static void stl_sc26198txisr(struct stlport *portp) if ((len == 0) || ((len < STL_TXBUFLOW) && (test_bit(ASYI_TXLOW, &portp->istate) == 0))) { set_bit(ASYI_TXLOW, &portp->istate); - if (portp->tty) - tty_wakeup(portp->tty); + if (portp->port.tty) + tty_wakeup(portp->port.tty); } if (len == 0) { @@ -4475,7 +4475,7 @@ static void stl_sc26198rxisr(struct stlport *portp, unsigned int iack) pr_debug("stl_sc26198rxisr(portp=%p,iack=%x)\n", portp, iack); - tty = portp->tty; + tty = portp->port.tty; ioaddr = portp->ioaddr; outb(GIBCR, (ioaddr + XP_ADDR)); len = inb(ioaddr + XP_DATA) + 1; @@ -4527,7 +4527,7 @@ static void stl_sc26198rxbadch(struct stlport *portp, unsigned char status, char struct tty_struct *tty; unsigned int ioaddr; - tty = portp->tty; + tty = portp->port.tty; ioaddr = portp->ioaddr; if (status & SR_RXPARITY) @@ -4544,7 +4544,7 @@ static void stl_sc26198rxbadch(struct stlport *portp, unsigned char status, char if (portp->rxmarkmsk & status) { if (status & SR_RXBREAK) { status = TTY_BREAK; - if (portp->flags & ASYNC_SAK) { + if (portp->port.flags & ASYNC_SAK) { do_SAK(tty); BRDENABLE(portp->brdnr, portp->pagenr); } diff --git a/drivers/char/sx.c b/drivers/char/sx.c index b1a7a8cb65ea..d5cffcd6a572 100644 --- a/drivers/char/sx.c +++ b/drivers/char/sx.c @@ -1,4 +1,3 @@ - /* sx.c -- driver for the Specialix SX series cards. * * This driver will also support the older SI, and XIO cards. @@ -930,7 +929,7 @@ static int sx_set_real_termios(void *ptr) func_enter2(); - if (!port->gs.tty) + if (!port->gs.port.tty) return 0; /* What is this doing here? -- REW @@ -941,19 +940,19 @@ static int sx_set_real_termios(void *ptr) sx_set_baud(port); -#define CFLAG port->gs.tty->termios->c_cflag +#define CFLAG port->gs.port.tty->termios->c_cflag sx_write_channel_byte(port, hi_mr1, - (C_PARENB(port->gs.tty) ? MR1_WITH : MR1_NONE) | - (C_PARODD(port->gs.tty) ? MR1_ODD : MR1_EVEN) | - (C_CRTSCTS(port->gs.tty) ? MR1_RTS_RXFLOW : 0) | + (C_PARENB(port->gs.port.tty) ? MR1_WITH : MR1_NONE) | + (C_PARODD(port->gs.port.tty) ? MR1_ODD : MR1_EVEN) | + (C_CRTSCTS(port->gs.port.tty) ? MR1_RTS_RXFLOW : 0) | (((CFLAG & CSIZE) == CS8) ? MR1_8_BITS : 0) | (((CFLAG & CSIZE) == CS7) ? MR1_7_BITS : 0) | (((CFLAG & CSIZE) == CS6) ? MR1_6_BITS : 0) | (((CFLAG & CSIZE) == CS5) ? MR1_5_BITS : 0)); sx_write_channel_byte(port, hi_mr2, - (C_CRTSCTS(port->gs.tty) ? MR2_CTS_TXFLOW : 0) | - (C_CSTOPB(port->gs.tty) ? MR2_2_STOP : + (C_CRTSCTS(port->gs.port.tty) ? MR2_CTS_TXFLOW : 0) | + (C_CSTOPB(port->gs.port.tty) ? MR2_2_STOP : MR2_1_STOP)); switch (CFLAG & CSIZE) { @@ -976,44 +975,44 @@ static int sx_set_real_termios(void *ptr) } sx_write_channel_byte(port, hi_prtcl, - (I_IXON(port->gs.tty) ? SP_TXEN : 0) | - (I_IXOFF(port->gs.tty) ? SP_RXEN : 0) | - (I_IXANY(port->gs.tty) ? SP_TANY : 0) | SP_DCEN); + (I_IXON(port->gs.port.tty) ? SP_TXEN : 0) | + (I_IXOFF(port->gs.port.tty) ? SP_RXEN : 0) | + (I_IXANY(port->gs.port.tty) ? SP_TANY : 0) | SP_DCEN); sx_write_channel_byte(port, hi_break, - (I_IGNBRK(port->gs.tty) ? BR_IGN : 0 | - I_BRKINT(port->gs.tty) ? BR_INT : 0)); + (I_IGNBRK(port->gs.port.tty) ? BR_IGN : 0 | + I_BRKINT(port->gs.port.tty) ? BR_INT : 0)); - sx_write_channel_byte(port, hi_txon, START_CHAR(port->gs.tty)); - sx_write_channel_byte(port, hi_rxon, START_CHAR(port->gs.tty)); - sx_write_channel_byte(port, hi_txoff, STOP_CHAR(port->gs.tty)); - sx_write_channel_byte(port, hi_rxoff, STOP_CHAR(port->gs.tty)); + sx_write_channel_byte(port, hi_txon, START_CHAR(port->gs.port.tty)); + sx_write_channel_byte(port, hi_rxon, START_CHAR(port->gs.port.tty)); + sx_write_channel_byte(port, hi_txoff, STOP_CHAR(port->gs.port.tty)); + sx_write_channel_byte(port, hi_rxoff, STOP_CHAR(port->gs.port.tty)); sx_reconfigure_port(port); /* Tell line discipline whether we will do input cooking */ - if (I_OTHER(port->gs.tty)) { - clear_bit(TTY_HW_COOK_IN, &port->gs.tty->flags); + if (I_OTHER(port->gs.port.tty)) { + clear_bit(TTY_HW_COOK_IN, &port->gs.port.tty->flags); } else { - set_bit(TTY_HW_COOK_IN, &port->gs.tty->flags); + set_bit(TTY_HW_COOK_IN, &port->gs.port.tty->flags); } sx_dprintk(SX_DEBUG_TERMIOS, "iflags: %x(%d) ", - (unsigned int)port->gs.tty->termios->c_iflag, - I_OTHER(port->gs.tty)); + (unsigned int)port->gs.port.tty->termios->c_iflag, + I_OTHER(port->gs.port.tty)); /* Tell line discipline whether we will do output cooking. * If OPOST is set and no other output flags are set then we can do output * processing. Even if only *one* other flag in the O_OTHER group is set * we do cooking in software. */ - if (O_OPOST(port->gs.tty) && !O_OTHER(port->gs.tty)) { - set_bit(TTY_HW_COOK_OUT, &port->gs.tty->flags); + if (O_OPOST(port->gs.port.tty) && !O_OTHER(port->gs.port.tty)) { + set_bit(TTY_HW_COOK_OUT, &port->gs.port.tty->flags); } else { - clear_bit(TTY_HW_COOK_OUT, &port->gs.tty->flags); + clear_bit(TTY_HW_COOK_OUT, &port->gs.port.tty->flags); } sx_dprintk(SX_DEBUG_TERMIOS, "oflags: %x(%d)\n", - (unsigned int)port->gs.tty->termios->c_oflag, - O_OTHER(port->gs.tty)); + (unsigned int)port->gs.port.tty->termios->c_oflag, + O_OTHER(port->gs.port.tty)); /* port->c_dcd = sx_get_CD (port); */ func_exit(); return 0; @@ -1102,8 +1101,8 @@ static void sx_transmit_chars(struct sx_port *port) sx_disable_tx_interrupts(port); } - if ((port->gs.xmit_cnt <= port->gs.wakeup_chars) && port->gs.tty) { - tty_wakeup(port->gs.tty); + if ((port->gs.xmit_cnt <= port->gs.wakeup_chars) && port->gs.port.tty) { + tty_wakeup(port->gs.port.tty); sx_dprintk(SX_DEBUG_TRANSMIT, "Waking up.... ldisc (%d)....\n", port->gs.wakeup_chars); } @@ -1126,7 +1125,7 @@ static inline void sx_receive_chars(struct sx_port *port) unsigned char *rp; func_enter2(); - tty = port->gs.tty; + tty = port->gs.port.tty; while (1) { rx_op = sx_read_channel_byte(port, hi_rxopos); c = (sx_read_channel_byte(port, hi_rxipos) - rx_op) & 0xff; @@ -1211,12 +1210,12 @@ static inline void sx_check_modem_signals(struct sx_port *port) /* DCD went UP */ if ((sx_read_channel_byte(port, hi_hstat) != HS_IDLE_CLOSED) && - !(port->gs.tty->termios-> + !(port->gs.port.tty->termios-> c_cflag & CLOCAL)) { /* Are we blocking in open? */ sx_dprintk(SX_DEBUG_MODEMSIGNALS, "DCD " "active, unblocking open\n"); - wake_up_interruptible(&port->gs. + wake_up_interruptible(&port->gs.port. open_wait); } else { sx_dprintk(SX_DEBUG_MODEMSIGNALS, "DCD " @@ -1224,10 +1223,10 @@ static inline void sx_check_modem_signals(struct sx_port *port) } } else { /* DCD went down! */ - if (!(port->gs.tty->termios->c_cflag & CLOCAL)){ + if (!(port->gs.port.tty->termios->c_cflag & CLOCAL)){ sx_dprintk(SX_DEBUG_MODEMSIGNALS, "DCD " "dropped. hanging up....\n"); - tty_hangup(port->gs.tty); + tty_hangup(port->gs.port.tty); } else { sx_dprintk(SX_DEBUG_MODEMSIGNALS, "DCD " "dropped. ignoring.\n"); @@ -1325,7 +1324,7 @@ static irqreturn_t sx_interrupt(int irq, void *ptr) for (i = 0; i < board->nports; i++) { port = &board->ports[i]; - if (port->gs.flags & GS_ACTIVE) { + if (port->gs.port.flags & GS_ACTIVE) { if (sx_read_channel_byte(port, hi_state)) { sx_dprintk(SX_DEBUG_INTERRUPTS, "Port %d: " "modem signal change?... \n",i); @@ -1334,7 +1333,7 @@ static irqreturn_t sx_interrupt(int irq, void *ptr) if (port->gs.xmit_cnt) { sx_transmit_chars(port); } - if (!(port->gs.flags & SX_RX_THROTTLE)) { + if (!(port->gs.port.flags & SX_RX_THROTTLE)) { sx_receive_chars(port); } } @@ -1373,7 +1372,7 @@ static void sx_disable_tx_interrupts(void *ptr) struct sx_port *port = ptr; func_enter2(); - port->gs.flags &= ~GS_TX_INTEN; + port->gs.port.flags &= ~GS_TX_INTEN; func_exit(); } @@ -1394,7 +1393,7 @@ static void sx_enable_tx_interrupts(void *ptr) /* XXX Must be "HIGH_WATER" for SI card according to doc. */ if (data_in_buffer < LOW_WATER) - port->gs.flags &= ~GS_TX_INTEN; + port->gs.port.flags &= ~GS_TX_INTEN; func_exit(); } @@ -1442,8 +1441,8 @@ static void sx_shutdown_port(void *ptr) func_enter(); - port->gs.flags &= ~GS_ACTIVE; - if (port->gs.tty && (port->gs.tty->termios->c_cflag & HUPCL)) { + port->gs.port.flags &= ~GS_ACTIVE; + if (port->gs.port.tty && (port->gs.port.tty->termios->c_cflag & HUPCL)) { sx_setsignals(port, 0, 0); sx_reconfigure_port(port); } @@ -1485,8 +1484,8 @@ static int sx_open(struct tty_struct *tty, struct file *filp) spin_lock_irqsave(&port->gs.driver_lock, flags); tty->driver_data = port; - port->gs.tty = tty; - port->gs.count++; + port->gs.port.tty = tty; + port->gs.port.count++; spin_unlock_irqrestore(&port->gs.driver_lock, flags); sx_dprintk(SX_DEBUG_OPEN, "starting port\n"); @@ -1497,12 +1496,12 @@ static int sx_open(struct tty_struct *tty, struct file *filp) retval = gs_init_port(&port->gs); sx_dprintk(SX_DEBUG_OPEN, "done gs_init\n"); if (retval) { - port->gs.count--; + port->gs.port.count--; return retval; } - port->gs.flags |= GS_ACTIVE; - if (port->gs.count <= 1) + port->gs.port.flags |= GS_ACTIVE; + if (port->gs.port.count <= 1) sx_setsignals(port, 1, 1); #if 0 @@ -1513,12 +1512,12 @@ static int sx_open(struct tty_struct *tty, struct file *filp) my_hd_io(port->board->base + port->ch_base, sizeof(*port)); #endif - if (port->gs.count <= 1) { + if (port->gs.port.count <= 1) { if (sx_send_command(port, HS_LOPEN, -1, HS_IDLE_OPEN) != 1) { printk(KERN_ERR "sx: Card didn't respond to LOPEN " "command.\n"); spin_lock_irqsave(&port->gs.driver_lock, flags); - port->gs.count--; + port->gs.port.count--; spin_unlock_irqrestore(&port->gs.driver_lock, flags); return -EIO; } @@ -1526,11 +1525,11 @@ static int sx_open(struct tty_struct *tty, struct file *filp) retval = gs_block_til_ready(port, filp); sx_dprintk(SX_DEBUG_OPEN, "Block til ready returned %d. Count=%d\n", - retval, port->gs.count); + retval, port->gs.port.count); if (retval) { /* - * Don't lower gs.count here because sx_close() will be called later + * Don't lower gs.port.count here because sx_close() will be called later */ return retval; @@ -1571,14 +1570,14 @@ static void sx_close(void *ptr) } sx_dprintk(SX_DEBUG_CLOSE, "waited %d jiffies for close. count=%d\n", - 5 * HZ - to - 1, port->gs.count); + 5 * HZ - to - 1, port->gs.port.count); - if (port->gs.count) { + if (port->gs.port.count) { sx_dprintk(SX_DEBUG_CLOSE, "WARNING port count:%d\n", - port->gs.count); + port->gs.port.count); /*printk("%s SETTING port count to zero: %p count: %d\n", - __func__, port, port->gs.count); - port->gs.count = 0;*/ + __func__, port, port->gs.port.count); + port->gs.port.count = 0;*/ } func_exit(); @@ -1939,7 +1938,7 @@ static void sx_throttle(struct tty_struct *tty) * control then throttle the port. */ if ((tty->termios->c_cflag & CRTSCTS) || (I_IXOFF(tty))) { - port->gs.flags |= SX_RX_THROTTLE; + port->gs.port.flags |= SX_RX_THROTTLE; } func_exit(); } @@ -1953,7 +1952,7 @@ static void sx_unthrottle(struct tty_struct *tty) * this port in case we disabled flow control while the port * was throttled */ - port->gs.flags &= ~SX_RX_THROTTLE; + port->gs.port.flags &= ~SX_RX_THROTTLE; func_exit(); return; } @@ -2396,6 +2395,7 @@ static int sx_init_portstructs(int nboards, int nports) board->ports = port; for (j = 0; j < boards[i].nports; j++) { sx_dprintk(SX_DEBUG_INIT, "initing port %d\n", j); + tty_port_init(&port->gs.port); port->gs.magic = SX_MAGIC; port->gs.close_delay = HZ / 2; port->gs.closing_wait = 30 * HZ; @@ -2408,9 +2408,6 @@ static int sx_init_portstructs(int nboards, int nports) /* * Initializing wait queue */ - init_waitqueue_head(&port->gs.open_wait); - init_waitqueue_head(&port->gs.close_wait); - port++; } } diff --git a/drivers/char/synclink.c b/drivers/char/synclink.c index ac5080df2565..527d220aa4aa 100644 --- a/drivers/char/synclink.c +++ b/drivers/char/synclink.c @@ -180,19 +180,14 @@ struct tx_holding_buffer { struct mgsl_struct { int magic; - int flags; - int count; /* count of opens */ + struct tty_port port; int line; int hw_version; - unsigned short close_delay; - unsigned short closing_wait; /* time to wait before closing */ struct mgsl_icount icount; - struct tty_struct *tty; int timeout; int x_char; /* xon/xoff character */ - int blocked_open; /* # of blocked opens */ u16 read_status_mask; u16 ignore_status_mask; unsigned char *xmit_buf; @@ -200,9 +195,6 @@ struct mgsl_struct { int xmit_tail; int xmit_cnt; - wait_queue_head_t open_wait; - wait_queue_head_t close_wait; - wait_queue_head_t status_event_wait_q; wait_queue_head_t event_wait_q; struct timer_list tx_timer; /* HDLC transmit timeout timer */ @@ -975,8 +967,8 @@ static void ldisc_receive_buf(struct tty_struct *tty, return; ld = tty_ldisc_ref(tty); if (ld) { - if (ld->receive_buf) - ld->receive_buf(tty, data, flags, count); + if (ld->ops->receive_buf) + ld->ops->receive_buf(tty, data, flags, count); tty_ldisc_deref(ld); } } @@ -1134,7 +1126,7 @@ static void mgsl_bh_receive(struct mgsl_struct *info) static void mgsl_bh_transmit(struct mgsl_struct *info) { - struct tty_struct *tty = info->tty; + struct tty_struct *tty = info->port.tty; unsigned long flags; if ( debug_level >= DEBUG_LEVEL_BH ) @@ -1276,7 +1268,7 @@ static void mgsl_isr_transmit_status( struct mgsl_struct *info ) else #endif { - if (info->tty->stopped || info->tty->hw_stopped) { + if (info->port.tty->stopped || info->port.tty->hw_stopped) { usc_stop_transmitter(info); return; } @@ -1357,29 +1349,29 @@ static void mgsl_isr_io_pin( struct mgsl_struct *info ) wake_up_interruptible(&info->status_event_wait_q); wake_up_interruptible(&info->event_wait_q); - if ( (info->flags & ASYNC_CHECK_CD) && + if ( (info->port.flags & ASYNC_CHECK_CD) && (status & MISCSTATUS_DCD_LATCHED) ) { if ( debug_level >= DEBUG_LEVEL_ISR ) printk("%s CD now %s...", info->device_name, (status & MISCSTATUS_DCD) ? "on" : "off"); if (status & MISCSTATUS_DCD) - wake_up_interruptible(&info->open_wait); + wake_up_interruptible(&info->port.open_wait); else { if ( debug_level >= DEBUG_LEVEL_ISR ) printk("doing serial hangup..."); - if (info->tty) - tty_hangup(info->tty); + if (info->port.tty) + tty_hangup(info->port.tty); } } - if ( (info->flags & ASYNC_CTS_FLOW) && + if ( (info->port.flags & ASYNC_CTS_FLOW) && (status & MISCSTATUS_CTS_LATCHED) ) { - if (info->tty->hw_stopped) { + if (info->port.tty->hw_stopped) { if (status & MISCSTATUS_CTS) { if ( debug_level >= DEBUG_LEVEL_ISR ) printk("CTS tx start..."); - if (info->tty) - info->tty->hw_stopped = 0; + if (info->port.tty) + info->port.tty->hw_stopped = 0; usc_start_transmitter(info); info->pending_bh |= BH_TRANSMIT; return; @@ -1388,8 +1380,8 @@ static void mgsl_isr_io_pin( struct mgsl_struct *info ) if (!(status & MISCSTATUS_CTS)) { if ( debug_level >= DEBUG_LEVEL_ISR ) printk("CTS tx stop..."); - if (info->tty) - info->tty->hw_stopped = 1; + if (info->port.tty) + info->port.tty->hw_stopped = 1; usc_stop_transmitter(info); } } @@ -1423,7 +1415,7 @@ static void mgsl_isr_transmit_data( struct mgsl_struct *info ) usc_ClearIrqPendingBits( info, TRANSMIT_DATA ); - if (info->tty->stopped || info->tty->hw_stopped) { + if (info->port.tty->stopped || info->port.tty->hw_stopped) { usc_stop_transmitter(info); return; } @@ -1453,7 +1445,7 @@ static void mgsl_isr_receive_data( struct mgsl_struct *info ) u16 status; int work = 0; unsigned char DataByte; - struct tty_struct *tty = info->tty; + struct tty_struct *tty = info->port.tty; struct mgsl_icount *icount = &info->icount; if ( debug_level >= DEBUG_LEVEL_ISR ) @@ -1514,7 +1506,7 @@ static void mgsl_isr_receive_data( struct mgsl_struct *info ) if (status & RXSTATUS_BREAK_RECEIVED) { flag = TTY_BREAK; - if (info->flags & ASYNC_SAK) + if (info->port.flags & ASYNC_SAK) do_SAK(tty); } else if (status & RXSTATUS_PARITY_ERROR) flag = TTY_PARITY; @@ -1771,7 +1763,7 @@ static int startup(struct mgsl_struct * info) if ( debug_level >= DEBUG_LEVEL_INFO ) printk("%s(%d):mgsl_startup(%s)\n",__FILE__,__LINE__,info->device_name); - if (info->flags & ASYNC_INITIALIZED) + if (info->port.flags & ASYNC_INITIALIZED) return 0; if (!info->xmit_buf) { @@ -1798,8 +1790,8 @@ static int startup(struct mgsl_struct * info) retval = mgsl_adapter_test(info); if ( retval ) { - if (capable(CAP_SYS_ADMIN) && info->tty) - set_bit(TTY_IO_ERROR, &info->tty->flags); + if (capable(CAP_SYS_ADMIN) && info->port.tty) + set_bit(TTY_IO_ERROR, &info->port.tty->flags); mgsl_release_resources(info); return retval; } @@ -1807,10 +1799,10 @@ static int startup(struct mgsl_struct * info) /* program hardware for current parameters */ mgsl_change_params(info); - if (info->tty) - clear_bit(TTY_IO_ERROR, &info->tty->flags); + if (info->port.tty) + clear_bit(TTY_IO_ERROR, &info->port.tty->flags); - info->flags |= ASYNC_INITIALIZED; + info->port.flags |= ASYNC_INITIALIZED; return 0; @@ -1827,7 +1819,7 @@ static void shutdown(struct mgsl_struct * info) { unsigned long flags; - if (!(info->flags & ASYNC_INITIALIZED)) + if (!(info->port.flags & ASYNC_INITIALIZED)) return; if (debug_level >= DEBUG_LEVEL_INFO) @@ -1864,7 +1856,7 @@ static void shutdown(struct mgsl_struct * info) /* on the ISA adapter. This has no effect for the PCI adapter */ usc_OutReg(info, PCR, (u16)((usc_InReg(info, PCR) | BIT13) | BIT12)); - if (!info->tty || info->tty->termios->c_cflag & HUPCL) { + if (!info->port.tty || info->port.tty->termios->c_cflag & HUPCL) { info->serial_signals &= ~(SerialSignal_DTR + SerialSignal_RTS); usc_set_serial_signals(info); } @@ -1873,10 +1865,10 @@ static void shutdown(struct mgsl_struct * info) mgsl_release_resources(info); - if (info->tty) - set_bit(TTY_IO_ERROR, &info->tty->flags); + if (info->port.tty) + set_bit(TTY_IO_ERROR, &info->port.tty->flags); - info->flags &= ~ASYNC_INITIALIZED; + info->port.flags &= ~ASYNC_INITIALIZED; } /* end of shutdown() */ @@ -1908,7 +1900,7 @@ static void mgsl_program_hw(struct mgsl_struct *info) usc_EnableInterrupts(info, IO_PIN); usc_get_serial_signals(info); - if (info->netcount || info->tty->termios->c_cflag & CREAD) + if (info->netcount || info->port.tty->termios->c_cflag & CREAD) usc_start_receiver(info); spin_unlock_irqrestore(&info->irq_spinlock,flags); @@ -1921,14 +1913,14 @@ static void mgsl_change_params(struct mgsl_struct *info) unsigned cflag; int bits_per_char; - if (!info->tty || !info->tty->termios) + if (!info->port.tty || !info->port.tty->termios) return; if (debug_level >= DEBUG_LEVEL_INFO) printk("%s(%d):mgsl_change_params(%s)\n", __FILE__,__LINE__, info->device_name ); - cflag = info->tty->termios->c_cflag; + cflag = info->port.tty->termios->c_cflag; /* if B0 rate (hangup) specified then negate DTR and RTS */ /* otherwise assert DTR and RTS */ @@ -1976,7 +1968,7 @@ static void mgsl_change_params(struct mgsl_struct *info) * current data rate. */ if (info->params.data_rate <= 460800) - info->params.data_rate = tty_get_baud_rate(info->tty); + info->params.data_rate = tty_get_baud_rate(info->port.tty); if ( info->params.data_rate ) { info->timeout = (32*HZ*bits_per_char) / @@ -1985,31 +1977,31 @@ static void mgsl_change_params(struct mgsl_struct *info) info->timeout += HZ/50; /* Add .02 seconds of slop */ if (cflag & CRTSCTS) - info->flags |= ASYNC_CTS_FLOW; + info->port.flags |= ASYNC_CTS_FLOW; else - info->flags &= ~ASYNC_CTS_FLOW; + info->port.flags &= ~ASYNC_CTS_FLOW; if (cflag & CLOCAL) - info->flags &= ~ASYNC_CHECK_CD; + info->port.flags &= ~ASYNC_CHECK_CD; else - info->flags |= ASYNC_CHECK_CD; + info->port.flags |= ASYNC_CHECK_CD; /* process tty input control flags */ info->read_status_mask = RXSTATUS_OVERRUN; - if (I_INPCK(info->tty)) + if (I_INPCK(info->port.tty)) info->read_status_mask |= RXSTATUS_PARITY_ERROR | RXSTATUS_FRAMING_ERROR; - if (I_BRKINT(info->tty) || I_PARMRK(info->tty)) + if (I_BRKINT(info->port.tty) || I_PARMRK(info->port.tty)) info->read_status_mask |= RXSTATUS_BREAK_RECEIVED; - if (I_IGNPAR(info->tty)) + if (I_IGNPAR(info->port.tty)) info->ignore_status_mask |= RXSTATUS_PARITY_ERROR | RXSTATUS_FRAMING_ERROR; - if (I_IGNBRK(info->tty)) { + if (I_IGNBRK(info->port.tty)) { info->ignore_status_mask |= RXSTATUS_BREAK_RECEIVED; /* If ignoring parity and break indicators, ignore * overruns too. (For real raw support). */ - if (I_IGNPAR(info->tty)) + if (I_IGNPAR(info->port.tty)) info->ignore_status_mask |= RXSTATUS_OVERRUN; } @@ -3113,32 +3105,32 @@ static void mgsl_close(struct tty_struct *tty, struct file * filp) if (debug_level >= DEBUG_LEVEL_INFO) printk("%s(%d):mgsl_close(%s) entry, count=%d\n", - __FILE__,__LINE__, info->device_name, info->count); + __FILE__,__LINE__, info->device_name, info->port.count); - if (!info->count) + if (!info->port.count) return; if (tty_hung_up_p(filp)) goto cleanup; - if ((tty->count == 1) && (info->count != 1)) { + if ((tty->count == 1) && (info->port.count != 1)) { /* * tty->count is 1 and the tty structure will be freed. - * info->count should be one in this case. + * info->port.count should be one in this case. * if it's not, correct it so that the port is shutdown. */ printk("mgsl_close: bad refcount; tty->count is 1, " - "info->count is %d\n", info->count); - info->count = 1; + "info->port.count is %d\n", info->port.count); + info->port.count = 1; } - info->count--; + info->port.count--; /* if at least one open remaining, leave hardware active */ - if (info->count) + if (info->port.count) goto cleanup; - info->flags |= ASYNC_CLOSING; + info->port.flags |= ASYNC_CLOSING; /* set tty->closing to notify line discipline to * only process XON/XOFF characters. Only the N_TTY @@ -3148,14 +3140,14 @@ static void mgsl_close(struct tty_struct *tty, struct file * filp) /* wait for transmit data to clear all layers */ - if (info->closing_wait != ASYNC_CLOSING_WAIT_NONE) { + if (info->port.closing_wait != ASYNC_CLOSING_WAIT_NONE) { if (debug_level >= DEBUG_LEVEL_INFO) printk("%s(%d):mgsl_close(%s) calling tty_wait_until_sent\n", __FILE__,__LINE__, info->device_name ); - tty_wait_until_sent(tty, info->closing_wait); + tty_wait_until_sent(tty, info->port.closing_wait); } - if (info->flags & ASYNC_INITIALIZED) + if (info->port.flags & ASYNC_INITIALIZED) mgsl_wait_until_sent(tty, info->timeout); mgsl_flush_buffer(tty); @@ -3165,23 +3157,23 @@ static void mgsl_close(struct tty_struct *tty, struct file * filp) shutdown(info); tty->closing = 0; - info->tty = NULL; + info->port.tty = NULL; - if (info->blocked_open) { - if (info->close_delay) { - msleep_interruptible(jiffies_to_msecs(info->close_delay)); + if (info->port.blocked_open) { + if (info->port.close_delay) { + msleep_interruptible(jiffies_to_msecs(info->port.close_delay)); } - wake_up_interruptible(&info->open_wait); + wake_up_interruptible(&info->port.open_wait); } - info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING); + info->port.flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING); - wake_up_interruptible(&info->close_wait); + wake_up_interruptible(&info->port.close_wait); cleanup: if (debug_level >= DEBUG_LEVEL_INFO) printk("%s(%d):mgsl_close(%s) exit, count=%d\n", __FILE__,__LINE__, - tty->driver->name, info->count); + tty->driver->name, info->port.count); } /* end of mgsl_close() */ @@ -3211,7 +3203,7 @@ static void mgsl_wait_until_sent(struct tty_struct *tty, int timeout) if (mgsl_paranoia_check(info, tty->name, "mgsl_wait_until_sent")) return; - if (!(info->flags & ASYNC_INITIALIZED)) + if (!(info->port.flags & ASYNC_INITIALIZED)) goto exit; orig_jiffies = jiffies; @@ -3283,11 +3275,11 @@ static void mgsl_hangup(struct tty_struct *tty) mgsl_flush_buffer(tty); shutdown(info); - info->count = 0; - info->flags &= ~ASYNC_NORMAL_ACTIVE; - info->tty = NULL; + info->port.count = 0; + info->port.flags &= ~ASYNC_NORMAL_ACTIVE; + info->port.tty = NULL; - wake_up_interruptible(&info->open_wait); + wake_up_interruptible(&info->port.open_wait); } /* end of mgsl_hangup() */ @@ -3319,7 +3311,7 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp, if (filp->f_flags & O_NONBLOCK || tty->flags & (1 << TTY_IO_ERROR)){ /* nonblock mode is set or port is not enabled */ - info->flags |= ASYNC_NORMAL_ACTIVE; + info->port.flags |= ASYNC_NORMAL_ACTIVE; return 0; } @@ -3328,25 +3320,25 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp, /* Wait for carrier detect and the line to become * free (i.e., not in use by the callout). While we are in - * this loop, info->count is dropped by one, so that + * this loop, info->port.count is dropped by one, so that * mgsl_close() knows when to free things. We restore it upon * exit, either normal or abnormal. */ retval = 0; - add_wait_queue(&info->open_wait, &wait); + add_wait_queue(&info->port.open_wait, &wait); if (debug_level >= DEBUG_LEVEL_INFO) printk("%s(%d):block_til_ready before block on %s count=%d\n", - __FILE__,__LINE__, tty->driver->name, info->count ); + __FILE__,__LINE__, tty->driver->name, info->port.count ); spin_lock_irqsave(&info->irq_spinlock, flags); if (!tty_hung_up_p(filp)) { extra_count = true; - info->count--; + info->port.count--; } spin_unlock_irqrestore(&info->irq_spinlock, flags); - info->blocked_open++; + info->port.blocked_open++; while (1) { if (tty->termios->c_cflag & CBAUD) { @@ -3358,8 +3350,8 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp, set_current_state(TASK_INTERRUPTIBLE); - if (tty_hung_up_p(filp) || !(info->flags & ASYNC_INITIALIZED)){ - retval = (info->flags & ASYNC_HUP_NOTIFY) ? + if (tty_hung_up_p(filp) || !(info->port.flags & ASYNC_INITIALIZED)){ + retval = (info->port.flags & ASYNC_HUP_NOTIFY) ? -EAGAIN : -ERESTARTSYS; break; } @@ -3368,7 +3360,7 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp, usc_get_serial_signals(info); spin_unlock_irqrestore(&info->irq_spinlock,flags); - if (!(info->flags & ASYNC_CLOSING) && + if (!(info->port.flags & ASYNC_CLOSING) && (do_clocal || (info->serial_signals & SerialSignal_DCD)) ) { break; } @@ -3380,24 +3372,24 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp, if (debug_level >= DEBUG_LEVEL_INFO) printk("%s(%d):block_til_ready blocking on %s count=%d\n", - __FILE__,__LINE__, tty->driver->name, info->count ); + __FILE__,__LINE__, tty->driver->name, info->port.count ); schedule(); } set_current_state(TASK_RUNNING); - remove_wait_queue(&info->open_wait, &wait); + remove_wait_queue(&info->port.open_wait, &wait); if (extra_count) - info->count++; - info->blocked_open--; + info->port.count++; + info->port.blocked_open--; if (debug_level >= DEBUG_LEVEL_INFO) printk("%s(%d):block_til_ready after blocking on %s count=%d\n", - __FILE__,__LINE__, tty->driver->name, info->count ); + __FILE__,__LINE__, tty->driver->name, info->port.count ); if (!retval) - info->flags |= ASYNC_NORMAL_ACTIVE; + info->port.flags |= ASYNC_NORMAL_ACTIVE; return retval; @@ -3435,22 +3427,22 @@ static int mgsl_open(struct tty_struct *tty, struct file * filp) return -ENODEV; tty->driver_data = info; - info->tty = tty; + info->port.tty = tty; if (debug_level >= DEBUG_LEVEL_INFO) printk("%s(%d):mgsl_open(%s), old ref count = %d\n", - __FILE__,__LINE__,tty->driver->name, info->count); + __FILE__,__LINE__,tty->driver->name, info->port.count); /* If port is closing, signal caller to try again */ - if (tty_hung_up_p(filp) || info->flags & ASYNC_CLOSING){ - if (info->flags & ASYNC_CLOSING) - interruptible_sleep_on(&info->close_wait); - retval = ((info->flags & ASYNC_HUP_NOTIFY) ? + if (tty_hung_up_p(filp) || info->port.flags & ASYNC_CLOSING){ + if (info->port.flags & ASYNC_CLOSING) + interruptible_sleep_on(&info->port.close_wait); + retval = ((info->port.flags & ASYNC_HUP_NOTIFY) ? -EAGAIN : -ERESTARTSYS); goto cleanup; } - info->tty->low_latency = (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0; + info->port.tty->low_latency = (info->port.flags & ASYNC_LOW_LATENCY) ? 1 : 0; spin_lock_irqsave(&info->netlock, flags); if (info->netcount) { @@ -3458,10 +3450,10 @@ static int mgsl_open(struct tty_struct *tty, struct file * filp) spin_unlock_irqrestore(&info->netlock, flags); goto cleanup; } - info->count++; + info->port.count++; spin_unlock_irqrestore(&info->netlock, flags); - if (info->count == 1) { + if (info->port.count == 1) { /* 1st open on this device, init hardware */ retval = startup(info); if (retval < 0) @@ -3484,9 +3476,9 @@ static int mgsl_open(struct tty_struct *tty, struct file * filp) cleanup: if (retval) { if (tty->count == 1) - info->tty = NULL; /* tty layer will release tty struct */ - if(info->count) - info->count--; + info->port.tty = NULL; /* tty layer will release tty struct */ + if(info->port.count) + info->port.count--; } return retval; @@ -4332,13 +4324,12 @@ static struct mgsl_struct* mgsl_allocate_device(void) if (!info) { printk("Error can't allocate device instance data\n"); } else { + tty_port_init(&info->port); info->magic = MGSL_MAGIC; INIT_WORK(&info->task, mgsl_bh_handler); info->max_frame_size = 4096; - info->close_delay = 5*HZ/10; - info->closing_wait = 30*HZ; - init_waitqueue_head(&info->open_wait); - init_waitqueue_head(&info->close_wait); + info->port.close_delay = 5*HZ/10; + info->port.closing_wait = 30*HZ; init_waitqueue_head(&info->status_event_wait_q); init_waitqueue_head(&info->event_wait_q); spin_lock_init(&info->irq_spinlock); @@ -6575,7 +6566,7 @@ static bool mgsl_get_rx_frame(struct mgsl_struct *info) unsigned int framesize = 0; bool ReturnCode = false; unsigned long flags; - struct tty_struct *tty = info->tty; + struct tty_struct *tty = info->port.tty; bool return_frame = false; /* @@ -6640,9 +6631,8 @@ static bool mgsl_get_rx_frame(struct mgsl_struct *info) framesize = 0; #if SYNCLINK_GENERIC_HDLC { - struct net_device_stats *stats = hdlc_stats(info->netdev); - stats->rx_errors++; - stats->rx_frame_errors++; + info->netdev->stats.rx_errors++; + info->netdev->stats.rx_frame_errors++; } #endif } else @@ -6774,7 +6764,7 @@ static bool mgsl_get_raw_rx_frame(struct mgsl_struct *info) unsigned int framesize = 0; bool ReturnCode = false; unsigned long flags; - struct tty_struct *tty = info->tty; + struct tty_struct *tty = info->port.tty; /* * current_rx_buffer points to the 1st buffer of the next available @@ -7711,7 +7701,7 @@ static int hdlcdev_attach(struct net_device *dev, unsigned short encoding, unsigned short new_crctype; /* return error if TTY interface open */ - if (info->count) + if (info->port.count) return -EBUSY; switch (encoding) @@ -7753,7 +7743,6 @@ static int hdlcdev_attach(struct net_device *dev, unsigned short encoding, static int hdlcdev_xmit(struct sk_buff *skb, struct net_device *dev) { struct mgsl_struct *info = dev_to_port(dev); - struct net_device_stats *stats = hdlc_stats(dev); unsigned long flags; if (debug_level >= DEBUG_LEVEL_INFO) @@ -7767,8 +7756,8 @@ static int hdlcdev_xmit(struct sk_buff *skb, struct net_device *dev) mgsl_load_tx_dma_buffer(info, skb->data, skb->len); /* update network statistics */ - stats->tx_packets++; - stats->tx_bytes += skb->len; + dev->stats.tx_packets++; + dev->stats.tx_bytes += skb->len; /* done with socket buffer, so free it */ dev_kfree_skb(skb); @@ -7808,7 +7797,7 @@ static int hdlcdev_open(struct net_device *dev) /* arbitrate between network and tty opens */ spin_lock_irqsave(&info->netlock, flags); - if (info->count != 0 || info->netcount != 0) { + if (info->port.count != 0 || info->netcount != 0) { printk(KERN_WARNING "%s: hdlc_open returning busy\n", dev->name); spin_unlock_irqrestore(&info->netlock, flags); return -EBUSY; @@ -7894,7 +7883,7 @@ static int hdlcdev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) printk("%s:hdlcdev_ioctl(%s)\n",__FILE__,dev->name); /* return error if TTY interface open */ - if (info->count) + if (info->port.count) return -EBUSY; if (cmd != SIOCWANDEV) @@ -7984,14 +7973,13 @@ static int hdlcdev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) static void hdlcdev_tx_timeout(struct net_device *dev) { struct mgsl_struct *info = dev_to_port(dev); - struct net_device_stats *stats = hdlc_stats(dev); unsigned long flags; if (debug_level >= DEBUG_LEVEL_INFO) printk("hdlcdev_tx_timeout(%s)\n",dev->name); - stats->tx_errors++; - stats->tx_aborted_errors++; + dev->stats.tx_errors++; + dev->stats.tx_aborted_errors++; spin_lock_irqsave(&info->irq_spinlock,flags); usc_stop_transmitter(info); @@ -8024,27 +8012,27 @@ static void hdlcdev_rx(struct mgsl_struct *info, char *buf, int size) { struct sk_buff *skb = dev_alloc_skb(size); struct net_device *dev = info->netdev; - struct net_device_stats *stats = hdlc_stats(dev); if (debug_level >= DEBUG_LEVEL_INFO) - printk("hdlcdev_rx(%s)\n",dev->name); + printk("hdlcdev_rx(%s)\n", dev->name); if (skb == NULL) { - printk(KERN_NOTICE "%s: can't alloc skb, dropping packet\n", dev->name); - stats->rx_dropped++; + printk(KERN_NOTICE "%s: can't alloc skb, dropping packet\n", + dev->name); + dev->stats.rx_dropped++; return; } - memcpy(skb_put(skb, size),buf,size); + memcpy(skb_put(skb, size), buf, size); - skb->protocol = hdlc_type_trans(skb, info->netdev); + skb->protocol = hdlc_type_trans(skb, dev); - stats->rx_packets++; - stats->rx_bytes += size; + dev->stats.rx_packets++; + dev->stats.rx_bytes += size; netif_rx(skb); - info->netdev->last_rx = jiffies; + dev->last_rx = jiffies; } /** diff --git a/drivers/char/synclink_gt.c b/drivers/char/synclink_gt.c index 55c1653be00c..2c3e43bb2cc9 100644 --- a/drivers/char/synclink_gt.c +++ b/drivers/char/synclink_gt.c @@ -244,11 +244,11 @@ struct _input_signal_events { */ struct slgt_info { void *if_ptr; /* General purpose pointer (used by SPPP) */ + struct tty_port port; struct slgt_info *next_device; /* device list link */ int magic; - int flags; char device_name[25]; struct pci_dev *pdev; @@ -260,23 +260,15 @@ struct slgt_info { /* array of pointers to port contexts on this adapter */ struct slgt_info *port_array[SLGT_MAX_PORTS]; - int count; /* count of opens */ int line; /* tty line instance number */ - unsigned short close_delay; - unsigned short closing_wait; /* time to wait before closing */ struct mgsl_icount icount; - struct tty_struct *tty; int timeout; int x_char; /* xon/xoff character */ - int blocked_open; /* # of blocked opens */ unsigned int read_status_mask; unsigned int ignore_status_mask; - wait_queue_head_t open_wait; - wait_queue_head_t close_wait; - wait_queue_head_t status_event_wait_q; wait_queue_head_t event_wait_q; struct timer_list tx_timer; @@ -641,8 +633,8 @@ static void ldisc_receive_buf(struct tty_struct *tty, return; ld = tty_ldisc_ref(tty); if (ld) { - if (ld->receive_buf) - ld->receive_buf(tty, data, flags, count); + if (ld->ops->receive_buf) + ld->ops->receive_buf(tty, data, flags, count); tty_ldisc_deref(ld); } } @@ -672,20 +664,20 @@ static int open(struct tty_struct *tty, struct file *filp) } tty->driver_data = info; - info->tty = tty; + info->port.tty = tty; - DBGINFO(("%s open, old ref count = %d\n", info->device_name, info->count)); + DBGINFO(("%s open, old ref count = %d\n", info->device_name, info->port.count)); /* If port is closing, signal caller to try again */ - if (tty_hung_up_p(filp) || info->flags & ASYNC_CLOSING){ - if (info->flags & ASYNC_CLOSING) - interruptible_sleep_on(&info->close_wait); - retval = ((info->flags & ASYNC_HUP_NOTIFY) ? + if (tty_hung_up_p(filp) || info->port.flags & ASYNC_CLOSING){ + if (info->port.flags & ASYNC_CLOSING) + interruptible_sleep_on(&info->port.close_wait); + retval = ((info->port.flags & ASYNC_HUP_NOTIFY) ? -EAGAIN : -ERESTARTSYS); goto cleanup; } - info->tty->low_latency = (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0; + info->port.tty->low_latency = (info->port.flags & ASYNC_LOW_LATENCY) ? 1 : 0; spin_lock_irqsave(&info->netlock, flags); if (info->netcount) { @@ -693,10 +685,10 @@ static int open(struct tty_struct *tty, struct file *filp) spin_unlock_irqrestore(&info->netlock, flags); goto cleanup; } - info->count++; + info->port.count++; spin_unlock_irqrestore(&info->netlock, flags); - if (info->count == 1) { + if (info->port.count == 1) { /* 1st open on this device, init hardware */ retval = startup(info); if (retval < 0) @@ -714,9 +706,9 @@ static int open(struct tty_struct *tty, struct file *filp) cleanup: if (retval) { if (tty->count == 1) - info->tty = NULL; /* tty layer will release tty struct */ - if(info->count) - info->count--; + info->port.tty = NULL; /* tty layer will release tty struct */ + if(info->port.count) + info->port.count--; } DBGINFO(("%s open rc=%d\n", info->device_name, retval)); @@ -729,32 +721,32 @@ static void close(struct tty_struct *tty, struct file *filp) if (sanity_check(info, tty->name, "close")) return; - DBGINFO(("%s close entry, count=%d\n", info->device_name, info->count)); + DBGINFO(("%s close entry, count=%d\n", info->device_name, info->port.count)); - if (!info->count) + if (!info->port.count) return; if (tty_hung_up_p(filp)) goto cleanup; - if ((tty->count == 1) && (info->count != 1)) { + if ((tty->count == 1) && (info->port.count != 1)) { /* * tty->count is 1 and the tty structure will be freed. - * info->count should be one in this case. + * info->port.count should be one in this case. * if it's not, correct it so that the port is shutdown. */ DBGERR(("%s close: bad refcount; tty->count=1, " - "info->count=%d\n", info->device_name, info->count)); - info->count = 1; + "info->port.count=%d\n", info->device_name, info->port.count)); + info->port.count = 1; } - info->count--; + info->port.count--; /* if at least one open remaining, leave hardware active */ - if (info->count) + if (info->port.count) goto cleanup; - info->flags |= ASYNC_CLOSING; + info->port.flags |= ASYNC_CLOSING; /* set tty->closing to notify line discipline to * only process XON/XOFF characters. Only the N_TTY @@ -764,12 +756,12 @@ static void close(struct tty_struct *tty, struct file *filp) /* wait for transmit data to clear all layers */ - if (info->closing_wait != ASYNC_CLOSING_WAIT_NONE) { + if (info->port.closing_wait != ASYNC_CLOSING_WAIT_NONE) { DBGINFO(("%s call tty_wait_until_sent\n", info->device_name)); - tty_wait_until_sent(tty, info->closing_wait); + tty_wait_until_sent(tty, info->port.closing_wait); } - if (info->flags & ASYNC_INITIALIZED) + if (info->port.flags & ASYNC_INITIALIZED) wait_until_sent(tty, info->timeout); flush_buffer(tty); tty_ldisc_flush(tty); @@ -777,21 +769,21 @@ static void close(struct tty_struct *tty, struct file *filp) shutdown(info); tty->closing = 0; - info->tty = NULL; + info->port.tty = NULL; - if (info->blocked_open) { - if (info->close_delay) { - msleep_interruptible(jiffies_to_msecs(info->close_delay)); + if (info->port.blocked_open) { + if (info->port.close_delay) { + msleep_interruptible(jiffies_to_msecs(info->port.close_delay)); } - wake_up_interruptible(&info->open_wait); + wake_up_interruptible(&info->port.open_wait); } - info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING); + info->port.flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING); - wake_up_interruptible(&info->close_wait); + wake_up_interruptible(&info->port.close_wait); cleanup: - DBGINFO(("%s close exit, count=%d\n", tty->driver->name, info->count)); + DBGINFO(("%s close exit, count=%d\n", tty->driver->name, info->port.count)); } static void hangup(struct tty_struct *tty) @@ -805,11 +797,11 @@ static void hangup(struct tty_struct *tty) flush_buffer(tty); shutdown(info); - info->count = 0; - info->flags &= ~ASYNC_NORMAL_ACTIVE; - info->tty = NULL; + info->port.count = 0; + info->port.flags &= ~ASYNC_NORMAL_ACTIVE; + info->port.tty = NULL; - wake_up_interruptible(&info->open_wait); + wake_up_interruptible(&info->port.open_wait); } static void set_termios(struct tty_struct *tty, struct ktermios *old_termios) @@ -959,7 +951,7 @@ static void wait_until_sent(struct tty_struct *tty, int timeout) if (sanity_check(info, tty->name, "wait_until_sent")) return; DBGINFO(("%s wait_until_sent entry\n", info->device_name)); - if (!(info->flags & ASYNC_INITIALIZED)) + if (!(info->port.flags & ASYNC_INITIALIZED)) goto exit; orig_jiffies = jiffies; @@ -1500,7 +1492,7 @@ static int hdlcdev_attach(struct net_device *dev, unsigned short encoding, unsigned short new_crctype; /* return error if TTY interface open */ - if (info->count) + if (info->port.count) return -EBUSY; DBGINFO(("%s hdlcdev_attach\n", info->device_name)); @@ -1544,7 +1536,6 @@ static int hdlcdev_attach(struct net_device *dev, unsigned short encoding, static int hdlcdev_xmit(struct sk_buff *skb, struct net_device *dev) { struct slgt_info *info = dev_to_port(dev); - struct net_device_stats *stats = hdlc_stats(dev); unsigned long flags; DBGINFO(("%s hdlc_xmit\n", dev->name)); @@ -1557,8 +1548,8 @@ static int hdlcdev_xmit(struct sk_buff *skb, struct net_device *dev) tx_load(info, skb->data, skb->len); /* update network statistics */ - stats->tx_packets++; - stats->tx_bytes += skb->len; + dev->stats.tx_packets++; + dev->stats.tx_bytes += skb->len; /* done with socket buffer, so free it */ dev_kfree_skb(skb); @@ -1600,7 +1591,7 @@ static int hdlcdev_open(struct net_device *dev) /* arbitrate between network and tty opens */ spin_lock_irqsave(&info->netlock, flags); - if (info->count != 0 || info->netcount != 0) { + if (info->port.count != 0 || info->netcount != 0) { DBGINFO(("%s hdlc_open busy\n", dev->name)); spin_unlock_irqrestore(&info->netlock, flags); return -EBUSY; @@ -1685,7 +1676,7 @@ static int hdlcdev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) DBGINFO(("%s hdlcdev_ioctl\n", dev->name)); /* return error if TTY interface open */ - if (info->count) + if (info->port.count) return -EBUSY; if (cmd != SIOCWANDEV) @@ -1775,13 +1766,12 @@ static int hdlcdev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) static void hdlcdev_tx_timeout(struct net_device *dev) { struct slgt_info *info = dev_to_port(dev); - struct net_device_stats *stats = hdlc_stats(dev); unsigned long flags; DBGINFO(("%s hdlcdev_tx_timeout\n", dev->name)); - stats->tx_errors++; - stats->tx_aborted_errors++; + dev->stats.tx_errors++; + dev->stats.tx_aborted_errors++; spin_lock_irqsave(&info->lock,flags); tx_stop(info); @@ -1814,26 +1804,25 @@ static void hdlcdev_rx(struct slgt_info *info, char *buf, int size) { struct sk_buff *skb = dev_alloc_skb(size); struct net_device *dev = info->netdev; - struct net_device_stats *stats = hdlc_stats(dev); DBGINFO(("%s hdlcdev_rx\n", dev->name)); if (skb == NULL) { DBGERR(("%s: can't alloc skb, drop packet\n", dev->name)); - stats->rx_dropped++; + dev->stats.rx_dropped++; return; } - memcpy(skb_put(skb, size),buf,size); + memcpy(skb_put(skb, size), buf, size); - skb->protocol = hdlc_type_trans(skb, info->netdev); + skb->protocol = hdlc_type_trans(skb, dev); - stats->rx_packets++; - stats->rx_bytes += size; + dev->stats.rx_packets++; + dev->stats.rx_bytes += size; netif_rx(skb); - info->netdev->last_rx = jiffies; + dev->last_rx = jiffies; } /** @@ -1906,7 +1895,7 @@ static void hdlcdev_exit(struct slgt_info *info) */ static void rx_async(struct slgt_info *info) { - struct tty_struct *tty = info->tty; + struct tty_struct *tty = info->port.tty; struct mgsl_icount *icount = &info->icount; unsigned int start, end; unsigned char *p; @@ -2057,7 +2046,7 @@ static void bh_handler(struct work_struct *work) static void bh_transmit(struct slgt_info *info) { - struct tty_struct *tty = info->tty; + struct tty_struct *tty = info->port.tty; DBGBH(("%s bh_transmit\n", info->device_name)); if (tty) @@ -2103,17 +2092,17 @@ static void cts_change(struct slgt_info *info, unsigned short status) wake_up_interruptible(&info->event_wait_q); info->pending_bh |= BH_STATUS; - if (info->flags & ASYNC_CTS_FLOW) { - if (info->tty) { - if (info->tty->hw_stopped) { + if (info->port.flags & ASYNC_CTS_FLOW) { + if (info->port.tty) { + if (info->port.tty->hw_stopped) { if (info->signals & SerialSignal_CTS) { - info->tty->hw_stopped = 0; + info->port.tty->hw_stopped = 0; info->pending_bh |= BH_TRANSMIT; return; } } else { if (!(info->signals & SerialSignal_CTS)) - info->tty->hw_stopped = 1; + info->port.tty->hw_stopped = 1; } } } @@ -2146,12 +2135,12 @@ static void dcd_change(struct slgt_info *info, unsigned short status) wake_up_interruptible(&info->event_wait_q); info->pending_bh |= BH_STATUS; - if (info->flags & ASYNC_CHECK_CD) { + if (info->port.flags & ASYNC_CHECK_CD) { if (info->signals & SerialSignal_DCD) - wake_up_interruptible(&info->open_wait); + wake_up_interruptible(&info->port.open_wait); else { - if (info->tty) - tty_hangup(info->tty); + if (info->port.tty) + tty_hangup(info->port.tty); } } } @@ -2194,12 +2183,12 @@ static void isr_serial(struct slgt_info *info) if ((status & IRQ_RXBREAK) && (status & RXBREAK)) { info->icount.brk++; /* process break detection if tty control allows */ - if (info->tty) { + if (info->port.tty) { if (!(status & info->ignore_status_mask)) { if (info->read_status_mask & MASK_BREAK) { - tty_insert_flip_char(info->tty, 0, TTY_BREAK); - if (info->flags & ASYNC_SAK) - do_SAK(info->tty); + tty_insert_flip_char(info->port.tty, 0, TTY_BREAK); + if (info->port.flags & ASYNC_SAK) + do_SAK(info->port.tty); } } } @@ -2319,7 +2308,7 @@ static void isr_txeom(struct slgt_info *info, unsigned short status) else #endif { - if (info->tty && (info->tty->stopped || info->tty->hw_stopped)) { + if (info->port.tty && (info->port.tty->stopped || info->port.tty->hw_stopped)) { tx_stop(info); return; } @@ -2395,7 +2384,7 @@ static irqreturn_t slgt_interrupt(int dummy, void *dev_id) for(i=0; i < info->port_count ; i++) { struct slgt_info *port = info->port_array[i]; - if (port && (port->count || port->netcount) && + if (port && (port->port.count || port->netcount) && port->pending_bh && !port->bh_running && !port->bh_requested) { DBGISR(("%s bh queued\n", port->device_name)); @@ -2414,7 +2403,7 @@ static int startup(struct slgt_info *info) { DBGINFO(("%s startup\n", info->device_name)); - if (info->flags & ASYNC_INITIALIZED) + if (info->port.flags & ASYNC_INITIALIZED) return 0; if (!info->tx_buf) { @@ -2432,10 +2421,10 @@ static int startup(struct slgt_info *info) /* program hardware for current parameters */ change_params(info); - if (info->tty) - clear_bit(TTY_IO_ERROR, &info->tty->flags); + if (info->port.tty) + clear_bit(TTY_IO_ERROR, &info->port.tty->flags); - info->flags |= ASYNC_INITIALIZED; + info->port.flags |= ASYNC_INITIALIZED; return 0; } @@ -2447,7 +2436,7 @@ static void shutdown(struct slgt_info *info) { unsigned long flags; - if (!(info->flags & ASYNC_INITIALIZED)) + if (!(info->port.flags & ASYNC_INITIALIZED)) return; DBGINFO(("%s shutdown\n", info->device_name)); @@ -2470,7 +2459,7 @@ static void shutdown(struct slgt_info *info) slgt_irq_off(info, IRQ_ALL | IRQ_MASTER); - if (!info->tty || info->tty->termios->c_cflag & HUPCL) { + if (!info->port.tty || info->port.tty->termios->c_cflag & HUPCL) { info->signals &= ~(SerialSignal_DTR + SerialSignal_RTS); set_signals(info); } @@ -2479,10 +2468,10 @@ static void shutdown(struct slgt_info *info) spin_unlock_irqrestore(&info->lock,flags); - if (info->tty) - set_bit(TTY_IO_ERROR, &info->tty->flags); + if (info->port.tty) + set_bit(TTY_IO_ERROR, &info->port.tty->flags); - info->flags &= ~ASYNC_INITIALIZED; + info->port.flags &= ~ASYNC_INITIALIZED; } static void program_hw(struct slgt_info *info) @@ -2511,7 +2500,7 @@ static void program_hw(struct slgt_info *info) get_signals(info); if (info->netcount || - (info->tty && info->tty->termios->c_cflag & CREAD)) + (info->port.tty && info->port.tty->termios->c_cflag & CREAD)) rx_start(info); spin_unlock_irqrestore(&info->lock,flags); @@ -2525,11 +2514,11 @@ static void change_params(struct slgt_info *info) unsigned cflag; int bits_per_char; - if (!info->tty || !info->tty->termios) + if (!info->port.tty || !info->port.tty->termios) return; DBGINFO(("%s change_params\n", info->device_name)); - cflag = info->tty->termios->c_cflag; + cflag = info->port.tty->termios->c_cflag; /* if B0 rate (hangup) specified then negate DTR and RTS */ /* otherwise assert DTR and RTS */ @@ -2561,7 +2550,7 @@ static void change_params(struct slgt_info *info) bits_per_char = info->params.data_bits + info->params.stop_bits + 1; - info->params.data_rate = tty_get_baud_rate(info->tty); + info->params.data_rate = tty_get_baud_rate(info->port.tty); if (info->params.data_rate) { info->timeout = (32*HZ*bits_per_char) / @@ -2570,30 +2559,30 @@ static void change_params(struct slgt_info *info) info->timeout += HZ/50; /* Add .02 seconds of slop */ if (cflag & CRTSCTS) - info->flags |= ASYNC_CTS_FLOW; + info->port.flags |= ASYNC_CTS_FLOW; else - info->flags &= ~ASYNC_CTS_FLOW; + info->port.flags &= ~ASYNC_CTS_FLOW; if (cflag & CLOCAL) - info->flags &= ~ASYNC_CHECK_CD; + info->port.flags &= ~ASYNC_CHECK_CD; else - info->flags |= ASYNC_CHECK_CD; + info->port.flags |= ASYNC_CHECK_CD; /* process tty input control flags */ info->read_status_mask = IRQ_RXOVER; - if (I_INPCK(info->tty)) + if (I_INPCK(info->port.tty)) info->read_status_mask |= MASK_PARITY | MASK_FRAMING; - if (I_BRKINT(info->tty) || I_PARMRK(info->tty)) + if (I_BRKINT(info->port.tty) || I_PARMRK(info->port.tty)) info->read_status_mask |= MASK_BREAK; - if (I_IGNPAR(info->tty)) + if (I_IGNPAR(info->port.tty)) info->ignore_status_mask |= MASK_PARITY | MASK_FRAMING; - if (I_IGNBRK(info->tty)) { + if (I_IGNBRK(info->port.tty)) { info->ignore_status_mask |= MASK_BREAK; /* If ignoring parity and break indicators, ignore * overruns too. (For real raw support). */ - if (I_IGNPAR(info->tty)) + if (I_IGNPAR(info->port.tty)) info->ignore_status_mask |= MASK_OVERRUN; } @@ -3144,7 +3133,7 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp, if (filp->f_flags & O_NONBLOCK || tty->flags & (1 << TTY_IO_ERROR)){ /* nonblock mode is set or port is not enabled */ - info->flags |= ASYNC_NORMAL_ACTIVE; + info->port.flags |= ASYNC_NORMAL_ACTIVE; return 0; } @@ -3153,21 +3142,21 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp, /* Wait for carrier detect and the line to become * free (i.e., not in use by the callout). While we are in - * this loop, info->count is dropped by one, so that + * this loop, info->port.count is dropped by one, so that * close() knows when to free things. We restore it upon * exit, either normal or abnormal. */ retval = 0; - add_wait_queue(&info->open_wait, &wait); + add_wait_queue(&info->port.open_wait, &wait); spin_lock_irqsave(&info->lock, flags); if (!tty_hung_up_p(filp)) { extra_count = true; - info->count--; + info->port.count--; } spin_unlock_irqrestore(&info->lock, flags); - info->blocked_open++; + info->port.blocked_open++; while (1) { if ((tty->termios->c_cflag & CBAUD)) { @@ -3179,8 +3168,8 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp, set_current_state(TASK_INTERRUPTIBLE); - if (tty_hung_up_p(filp) || !(info->flags & ASYNC_INITIALIZED)){ - retval = (info->flags & ASYNC_HUP_NOTIFY) ? + if (tty_hung_up_p(filp) || !(info->port.flags & ASYNC_INITIALIZED)){ + retval = (info->port.flags & ASYNC_HUP_NOTIFY) ? -EAGAIN : -ERESTARTSYS; break; } @@ -3189,7 +3178,7 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp, get_signals(info); spin_unlock_irqrestore(&info->lock,flags); - if (!(info->flags & ASYNC_CLOSING) && + if (!(info->port.flags & ASYNC_CLOSING) && (do_clocal || (info->signals & SerialSignal_DCD)) ) { break; } @@ -3204,14 +3193,14 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp, } set_current_state(TASK_RUNNING); - remove_wait_queue(&info->open_wait, &wait); + remove_wait_queue(&info->port.open_wait, &wait); if (extra_count) - info->count++; - info->blocked_open--; + info->port.count++; + info->port.blocked_open--; if (!retval) - info->flags |= ASYNC_NORMAL_ACTIVE; + info->port.flags |= ASYNC_NORMAL_ACTIVE; DBGINFO(("%s block_til_ready ready, rc=%d\n", tty->driver->name, retval)); return retval; @@ -3454,14 +3443,13 @@ static struct slgt_info *alloc_dev(int adapter_num, int port_num, struct pci_dev DBGERR(("%s device alloc failed adapter=%d port=%d\n", driver_name, adapter_num, port_num)); } else { + tty_port_init(&info->port); info->magic = MGSL_MAGIC; INIT_WORK(&info->task, bh_handler); info->max_frame_size = 4096; info->raw_rx_size = DMABUFSIZE; - info->close_delay = 5*HZ/10; - info->closing_wait = 30*HZ; - init_waitqueue_head(&info->open_wait); - init_waitqueue_head(&info->close_wait); + info->port.close_delay = 5*HZ/10; + info->port.closing_wait = 30*HZ; init_waitqueue_head(&info->status_event_wait_q); init_waitqueue_head(&info->event_wait_q); spin_lock_init(&info->netlock); @@ -4505,7 +4493,7 @@ static bool rx_get_frame(struct slgt_info *info) unsigned short status; unsigned int framesize = 0; unsigned long flags; - struct tty_struct *tty = info->tty; + struct tty_struct *tty = info->port.tty; unsigned char addr_field = 0xff; unsigned int crc_size = 0; @@ -4577,9 +4565,8 @@ check_again: #if SYNCLINK_GENERIC_HDLC if (framesize == 0) { - struct net_device_stats *stats = hdlc_stats(info->netdev); - stats->rx_errors++; - stats->rx_frame_errors++; + info->netdev->stats.rx_errors++; + info->netdev->stats.rx_frame_errors++; } #endif @@ -4656,7 +4643,7 @@ static bool rx_get_buf(struct slgt_info *info) DBGDATA(info, info->rbufs[i].buf, count, "rx"); DBGINFO(("rx_get_buf size=%d\n", count)); if (count) - ldisc_receive_buf(info->tty, info->rbufs[i].buf, + ldisc_receive_buf(info->port.tty, info->rbufs[i].buf, info->flag_buf, count); free_rbufs(info, i, i); return true; @@ -4765,11 +4752,11 @@ static int irq_test(struct slgt_info *info) { unsigned long timeout; unsigned long flags; - struct tty_struct *oldtty = info->tty; + struct tty_struct *oldtty = info->port.tty; u32 speed = info->params.data_rate; info->params.data_rate = 921600; - info->tty = NULL; + info->port.tty = NULL; spin_lock_irqsave(&info->lock, flags); async_mode(info); @@ -4797,7 +4784,7 @@ static int irq_test(struct slgt_info *info) spin_unlock_irqrestore(&info->lock,flags); info->params.data_rate = speed; - info->tty = oldtty; + info->port.tty = oldtty; info->init_error = info->irq_occurred ? 0 : DiagStatus_IrqFailure; return info->irq_occurred ? 0 : -ENODEV; @@ -4837,7 +4824,7 @@ static int loopback_test(struct slgt_info *info) int rc = -ENODEV; unsigned long flags; - struct tty_struct *oldtty = info->tty; + struct tty_struct *oldtty = info->port.tty; MGSL_PARAMS params; memcpy(¶ms, &info->params, sizeof(params)); @@ -4845,7 +4832,7 @@ static int loopback_test(struct slgt_info *info) info->params.mode = MGSL_MODE_ASYNC; info->params.data_rate = 921600; info->params.loopback = 1; - info->tty = NULL; + info->port.tty = NULL; /* build and send transmit frame */ for (count = 0; count < TESTFRAMESIZE; ++count) @@ -4883,7 +4870,7 @@ static int loopback_test(struct slgt_info *info) spin_unlock_irqrestore(&info->lock,flags); memcpy(&info->params, ¶ms, sizeof(info->params)); - info->tty = oldtty; + info->port.tty = oldtty; info->init_error = rc ? DiagStatus_DmaFailure : 0; return rc; diff --git a/drivers/char/synclinkmp.c b/drivers/char/synclinkmp.c index bec54866e0bb..5768c4136342 100644 --- a/drivers/char/synclinkmp.c +++ b/drivers/char/synclinkmp.c @@ -151,18 +151,15 @@ struct _input_signal_events { typedef struct _synclinkmp_info { void *if_ptr; /* General purpose pointer (used by SPPP) */ int magic; - int flags; - int count; /* count of opens */ + struct tty_port port; int line; unsigned short close_delay; unsigned short closing_wait; /* time to wait before closing */ struct mgsl_icount icount; - struct tty_struct *tty; int timeout; int x_char; /* xon/xoff character */ - int blocked_open; /* # of blocked opens */ u16 read_status_mask1; /* break detection (SR1 indications) */ u16 read_status_mask2; /* parity/framing/overun (SR2 indications) */ unsigned char ignore_status_mask1; /* break detection (SR1 indications) */ @@ -172,9 +169,6 @@ typedef struct _synclinkmp_info { int tx_get; int tx_count; - wait_queue_head_t open_wait; - wait_queue_head_t close_wait; - wait_queue_head_t status_event_wait_q; wait_queue_head_t event_wait_q; struct timer_list tx_timer; /* HDLC transmit timeout timer */ @@ -462,13 +456,13 @@ static int synclinkmp_device_count = 0; * .text section address and breakpoint on module load. * This is useful for use with gdb and add-symbol-file command. */ -static int break_on_load=0; +static int break_on_load = 0; /* * Driver major number, defaults to zero to get auto * assigned major number. May be forced as module parameter. */ -static int ttymajor=0; +static int ttymajor = 0; /* * Array of user specified options for ISA adapters. @@ -712,8 +706,8 @@ static void ldisc_receive_buf(struct tty_struct *tty, return; ld = tty_ldisc_ref(tty); if (ld) { - if (ld->receive_buf) - ld->receive_buf(tty, data, flags, count); + if (ld->ops->receive_buf) + ld->ops->receive_buf(tty, data, flags, count); tty_ldisc_deref(ld); } } @@ -747,22 +741,22 @@ static int open(struct tty_struct *tty, struct file *filp) } tty->driver_data = info; - info->tty = tty; + info->port.tty = tty; if (debug_level >= DEBUG_LEVEL_INFO) printk("%s(%d):%s open(), old ref count = %d\n", - __FILE__,__LINE__,tty->driver->name, info->count); + __FILE__,__LINE__,tty->driver->name, info->port.count); /* If port is closing, signal caller to try again */ - if (tty_hung_up_p(filp) || info->flags & ASYNC_CLOSING){ - if (info->flags & ASYNC_CLOSING) - interruptible_sleep_on(&info->close_wait); - retval = ((info->flags & ASYNC_HUP_NOTIFY) ? + if (tty_hung_up_p(filp) || info->port.flags & ASYNC_CLOSING){ + if (info->port.flags & ASYNC_CLOSING) + interruptible_sleep_on(&info->port.close_wait); + retval = ((info->port.flags & ASYNC_HUP_NOTIFY) ? -EAGAIN : -ERESTARTSYS); goto cleanup; } - info->tty->low_latency = (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0; + info->port.tty->low_latency = (info->port.flags & ASYNC_LOW_LATENCY) ? 1 : 0; spin_lock_irqsave(&info->netlock, flags); if (info->netcount) { @@ -770,10 +764,10 @@ static int open(struct tty_struct *tty, struct file *filp) spin_unlock_irqrestore(&info->netlock, flags); goto cleanup; } - info->count++; + info->port.count++; spin_unlock_irqrestore(&info->netlock, flags); - if (info->count == 1) { + if (info->port.count == 1) { /* 1st open on this device, init hardware */ retval = startup(info); if (retval < 0) @@ -796,9 +790,9 @@ static int open(struct tty_struct *tty, struct file *filp) cleanup: if (retval) { if (tty->count == 1) - info->tty = NULL; /* tty layer will release tty struct */ - if(info->count) - info->count--; + info->port.tty = NULL; /* tty layer will release tty struct */ + if(info->port.count) + info->port.count--; } return retval; @@ -816,33 +810,33 @@ static void close(struct tty_struct *tty, struct file *filp) if (debug_level >= DEBUG_LEVEL_INFO) printk("%s(%d):%s close() entry, count=%d\n", - __FILE__,__LINE__, info->device_name, info->count); + __FILE__,__LINE__, info->device_name, info->port.count); - if (!info->count) + if (!info->port.count) return; if (tty_hung_up_p(filp)) goto cleanup; - if ((tty->count == 1) && (info->count != 1)) { + if ((tty->count == 1) && (info->port.count != 1)) { /* * tty->count is 1 and the tty structure will be freed. - * info->count should be one in this case. + * info->port.count should be one in this case. * if it's not, correct it so that the port is shutdown. */ printk("%s(%d):%s close: bad refcount; tty->count is 1, " - "info->count is %d\n", - __FILE__,__LINE__, info->device_name, info->count); - info->count = 1; + "info->port.count is %d\n", + __FILE__,__LINE__, info->device_name, info->port.count); + info->port.count = 1; } - info->count--; + info->port.count--; /* if at least one open remaining, leave hardware active */ - if (info->count) + if (info->port.count) goto cleanup; - info->flags |= ASYNC_CLOSING; + info->port.flags |= ASYNC_CLOSING; /* set tty->closing to notify line discipline to * only process XON/XOFF characters. Only the N_TTY @@ -852,14 +846,14 @@ static void close(struct tty_struct *tty, struct file *filp) /* wait for transmit data to clear all layers */ - if (info->closing_wait != ASYNC_CLOSING_WAIT_NONE) { + if (info->port.closing_wait != ASYNC_CLOSING_WAIT_NONE) { if (debug_level >= DEBUG_LEVEL_INFO) printk("%s(%d):%s close() calling tty_wait_until_sent\n", __FILE__,__LINE__, info->device_name ); - tty_wait_until_sent(tty, info->closing_wait); + tty_wait_until_sent(tty, info->port.closing_wait); } - if (info->flags & ASYNC_INITIALIZED) + if (info->port.flags & ASYNC_INITIALIZED) wait_until_sent(tty, info->timeout); flush_buffer(tty); @@ -869,23 +863,23 @@ static void close(struct tty_struct *tty, struct file *filp) shutdown(info); tty->closing = 0; - info->tty = NULL; + info->port.tty = NULL; - if (info->blocked_open) { - if (info->close_delay) { - msleep_interruptible(jiffies_to_msecs(info->close_delay)); + if (info->port.blocked_open) { + if (info->port.close_delay) { + msleep_interruptible(jiffies_to_msecs(info->port.close_delay)); } - wake_up_interruptible(&info->open_wait); + wake_up_interruptible(&info->port.open_wait); } - info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING); + info->port.flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING); - wake_up_interruptible(&info->close_wait); + wake_up_interruptible(&info->port.close_wait); cleanup: if (debug_level >= DEBUG_LEVEL_INFO) printk("%s(%d):%s close() exit, count=%d\n", __FILE__,__LINE__, - tty->driver->name, info->count); + tty->driver->name, info->port.count); } /* Called by tty_hangup() when a hangup is signaled. @@ -905,11 +899,11 @@ static void hangup(struct tty_struct *tty) flush_buffer(tty); shutdown(info); - info->count = 0; - info->flags &= ~ASYNC_NORMAL_ACTIVE; - info->tty = NULL; + info->port.count = 0; + info->port.flags &= ~ASYNC_NORMAL_ACTIVE; + info->port.tty = NULL; - wake_up_interruptible(&info->open_wait); + wake_up_interruptible(&info->port.open_wait); } /* Set new termios settings @@ -1123,7 +1117,7 @@ static void wait_until_sent(struct tty_struct *tty, int timeout) lock_kernel(); - if (!(info->flags & ASYNC_INITIALIZED)) + if (!(info->port.flags & ASYNC_INITIALIZED)) goto exit; orig_jiffies = jiffies; @@ -1636,7 +1630,7 @@ static int hdlcdev_attach(struct net_device *dev, unsigned short encoding, unsigned short new_crctype; /* return error if TTY interface open */ - if (info->count) + if (info->port.count) return -EBUSY; switch (encoding) @@ -1678,7 +1672,6 @@ static int hdlcdev_attach(struct net_device *dev, unsigned short encoding, static int hdlcdev_xmit(struct sk_buff *skb, struct net_device *dev) { SLMP_INFO *info = dev_to_port(dev); - struct net_device_stats *stats = hdlc_stats(dev); unsigned long flags; if (debug_level >= DEBUG_LEVEL_INFO) @@ -1692,8 +1685,8 @@ static int hdlcdev_xmit(struct sk_buff *skb, struct net_device *dev) tx_load_dma_buffer(info, skb->data, skb->len); /* update network statistics */ - stats->tx_packets++; - stats->tx_bytes += skb->len; + dev->stats.tx_packets++; + dev->stats.tx_bytes += skb->len; /* done with socket buffer, so free it */ dev_kfree_skb(skb); @@ -1733,7 +1726,7 @@ static int hdlcdev_open(struct net_device *dev) /* arbitrate between network and tty opens */ spin_lock_irqsave(&info->netlock, flags); - if (info->count != 0 || info->netcount != 0) { + if (info->port.count != 0 || info->netcount != 0) { printk(KERN_WARNING "%s: hdlc_open returning busy\n", dev->name); spin_unlock_irqrestore(&info->netlock, flags); return -EBUSY; @@ -1819,7 +1812,7 @@ static int hdlcdev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) printk("%s:hdlcdev_ioctl(%s)\n",__FILE__,dev->name); /* return error if TTY interface open */ - if (info->count) + if (info->port.count) return -EBUSY; if (cmd != SIOCWANDEV) @@ -1909,14 +1902,13 @@ static int hdlcdev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) static void hdlcdev_tx_timeout(struct net_device *dev) { SLMP_INFO *info = dev_to_port(dev); - struct net_device_stats *stats = hdlc_stats(dev); unsigned long flags; if (debug_level >= DEBUG_LEVEL_INFO) printk("hdlcdev_tx_timeout(%s)\n",dev->name); - stats->tx_errors++; - stats->tx_aborted_errors++; + dev->stats.tx_errors++; + dev->stats.tx_aborted_errors++; spin_lock_irqsave(&info->lock,flags); tx_stop(info); @@ -1949,27 +1941,27 @@ static void hdlcdev_rx(SLMP_INFO *info, char *buf, int size) { struct sk_buff *skb = dev_alloc_skb(size); struct net_device *dev = info->netdev; - struct net_device_stats *stats = hdlc_stats(dev); if (debug_level >= DEBUG_LEVEL_INFO) printk("hdlcdev_rx(%s)\n",dev->name); if (skb == NULL) { - printk(KERN_NOTICE "%s: can't alloc skb, dropping packet\n", dev->name); - stats->rx_dropped++; + printk(KERN_NOTICE "%s: can't alloc skb, dropping packet\n", + dev->name); + dev->stats.rx_dropped++; return; } - memcpy(skb_put(skb, size),buf,size); + memcpy(skb_put(skb, size), buf, size); - skb->protocol = hdlc_type_trans(skb, info->netdev); + skb->protocol = hdlc_type_trans(skb, dev); - stats->rx_packets++; - stats->rx_bytes += size; + dev->stats.rx_packets++; + dev->stats.rx_bytes += size; netif_rx(skb); - info->netdev->last_rx = jiffies; + dev->last_rx = jiffies; } /** @@ -2128,7 +2120,7 @@ static void bh_receive(SLMP_INFO *info) static void bh_transmit(SLMP_INFO *info) { - struct tty_struct *tty = info->tty; + struct tty_struct *tty = info->port.tty; if ( debug_level >= DEBUG_LEVEL_BH ) printk( "%s(%d):%s bh_transmit() entry\n", @@ -2178,7 +2170,7 @@ static void isr_timer(SLMP_INFO * info) static void isr_rxint(SLMP_INFO * info) { - struct tty_struct *tty = info->tty; + struct tty_struct *tty = info->port.tty; struct mgsl_icount *icount = &info->icount; unsigned char status = read_reg(info, SR1) & info->ie1_value & (FLGD + IDLD + CDCD + BRKD); unsigned char status2 = read_reg(info, SR2) & info->ie2_value & OVRN; @@ -2205,7 +2197,7 @@ static void isr_rxint(SLMP_INFO * info) if (!(status & info->ignore_status_mask1)) { if (info->read_status_mask1 & BRKD) { tty_insert_flip_char(tty, 0, TTY_BREAK); - if (info->flags & ASYNC_SAK) + if (info->port.flags & ASYNC_SAK) do_SAK(tty); } } @@ -2239,7 +2231,7 @@ static void isr_rxrdy(SLMP_INFO * info) { u16 status; unsigned char DataByte; - struct tty_struct *tty = info->tty; + struct tty_struct *tty = info->port.tty; struct mgsl_icount *icount = &info->icount; if ( debug_level >= DEBUG_LEVEL_ISR ) @@ -2352,7 +2344,7 @@ static void isr_txeom(SLMP_INFO * info, unsigned char status) else #endif { - if (info->tty && (info->tty->stopped || info->tty->hw_stopped)) { + if (info->port.tty && (info->port.tty->stopped || info->port.tty->hw_stopped)) { tx_stop(info); return; } @@ -2407,7 +2399,7 @@ static void isr_txrdy(SLMP_INFO * info) return; } - if (info->tty && (info->tty->stopped || info->tty->hw_stopped)) { + if (info->port.tty && (info->port.tty->stopped || info->port.tty->hw_stopped)) { tx_stop(info); return; } @@ -2554,29 +2546,29 @@ static void isr_io_pin( SLMP_INFO *info, u16 status ) wake_up_interruptible(&info->status_event_wait_q); wake_up_interruptible(&info->event_wait_q); - if ( (info->flags & ASYNC_CHECK_CD) && + if ( (info->port.flags & ASYNC_CHECK_CD) && (status & MISCSTATUS_DCD_LATCHED) ) { if ( debug_level >= DEBUG_LEVEL_ISR ) printk("%s CD now %s...", info->device_name, (status & SerialSignal_DCD) ? "on" : "off"); if (status & SerialSignal_DCD) - wake_up_interruptible(&info->open_wait); + wake_up_interruptible(&info->port.open_wait); else { if ( debug_level >= DEBUG_LEVEL_ISR ) printk("doing serial hangup..."); - if (info->tty) - tty_hangup(info->tty); + if (info->port.tty) + tty_hangup(info->port.tty); } } - if ( (info->flags & ASYNC_CTS_FLOW) && + if ( (info->port.flags & ASYNC_CTS_FLOW) && (status & MISCSTATUS_CTS_LATCHED) ) { - if ( info->tty ) { - if (info->tty->hw_stopped) { + if ( info->port.tty ) { + if (info->port.tty->hw_stopped) { if (status & SerialSignal_CTS) { if ( debug_level >= DEBUG_LEVEL_ISR ) printk("CTS tx start..."); - info->tty->hw_stopped = 0; + info->port.tty->hw_stopped = 0; tx_start(info); info->pending_bh |= BH_TRANSMIT; return; @@ -2585,7 +2577,7 @@ static void isr_io_pin( SLMP_INFO *info, u16 status ) if (!(status & SerialSignal_CTS)) { if ( debug_level >= DEBUG_LEVEL_ISR ) printk("CTS tx stop..."); - info->tty->hw_stopped = 1; + info->port.tty->hw_stopped = 1; tx_stop(info); } } @@ -2701,7 +2693,7 @@ static irqreturn_t synclinkmp_interrupt(int dummy, void *dev_id) * do not request bottom half processing if the * device is not open in a normal mode. */ - if ( port && (port->count || port->netcount) && + if ( port && (port->port.count || port->netcount) && port->pending_bh && !port->bh_running && !port->bh_requested ) { if ( debug_level >= DEBUG_LEVEL_ISR ) @@ -2727,7 +2719,7 @@ static int startup(SLMP_INFO * info) if ( debug_level >= DEBUG_LEVEL_INFO ) printk("%s(%d):%s tx_releaseup()\n",__FILE__,__LINE__,info->device_name); - if (info->flags & ASYNC_INITIALIZED) + if (info->port.flags & ASYNC_INITIALIZED) return 0; if (!info->tx_buf) { @@ -2750,10 +2742,10 @@ static int startup(SLMP_INFO * info) mod_timer(&info->status_timer, jiffies + msecs_to_jiffies(10)); - if (info->tty) - clear_bit(TTY_IO_ERROR, &info->tty->flags); + if (info->port.tty) + clear_bit(TTY_IO_ERROR, &info->port.tty->flags); - info->flags |= ASYNC_INITIALIZED; + info->port.flags |= ASYNC_INITIALIZED; return 0; } @@ -2764,7 +2756,7 @@ static void shutdown(SLMP_INFO * info) { unsigned long flags; - if (!(info->flags & ASYNC_INITIALIZED)) + if (!(info->port.flags & ASYNC_INITIALIZED)) return; if (debug_level >= DEBUG_LEVEL_INFO) @@ -2786,17 +2778,17 @@ static void shutdown(SLMP_INFO * info) reset_port(info); - if (!info->tty || info->tty->termios->c_cflag & HUPCL) { + if (!info->port.tty || info->port.tty->termios->c_cflag & HUPCL) { info->serial_signals &= ~(SerialSignal_DTR + SerialSignal_RTS); set_signals(info); } spin_unlock_irqrestore(&info->lock,flags); - if (info->tty) - set_bit(TTY_IO_ERROR, &info->tty->flags); + if (info->port.tty) + set_bit(TTY_IO_ERROR, &info->port.tty->flags); - info->flags &= ~ASYNC_INITIALIZED; + info->port.flags &= ~ASYNC_INITIALIZED; } static void program_hw(SLMP_INFO *info) @@ -2827,7 +2819,7 @@ static void program_hw(SLMP_INFO *info) get_signals(info); - if (info->netcount || (info->tty && info->tty->termios->c_cflag & CREAD) ) + if (info->netcount || (info->port.tty && info->port.tty->termios->c_cflag & CREAD) ) rx_start(info); spin_unlock_irqrestore(&info->lock,flags); @@ -2840,14 +2832,14 @@ static void change_params(SLMP_INFO *info) unsigned cflag; int bits_per_char; - if (!info->tty || !info->tty->termios) + if (!info->port.tty || !info->port.tty->termios) return; if (debug_level >= DEBUG_LEVEL_INFO) printk("%s(%d):%s change_params()\n", __FILE__,__LINE__, info->device_name ); - cflag = info->tty->termios->c_cflag; + cflag = info->port.tty->termios->c_cflag; /* if B0 rate (hangup) specified then negate DTR and RTS */ /* otherwise assert DTR and RTS */ @@ -2895,7 +2887,7 @@ static void change_params(SLMP_INFO *info) * current data rate. */ if (info->params.data_rate <= 460800) { - info->params.data_rate = tty_get_baud_rate(info->tty); + info->params.data_rate = tty_get_baud_rate(info->port.tty); } if ( info->params.data_rate ) { @@ -2905,30 +2897,30 @@ static void change_params(SLMP_INFO *info) info->timeout += HZ/50; /* Add .02 seconds of slop */ if (cflag & CRTSCTS) - info->flags |= ASYNC_CTS_FLOW; + info->port.flags |= ASYNC_CTS_FLOW; else - info->flags &= ~ASYNC_CTS_FLOW; + info->port.flags &= ~ASYNC_CTS_FLOW; if (cflag & CLOCAL) - info->flags &= ~ASYNC_CHECK_CD; + info->port.flags &= ~ASYNC_CHECK_CD; else - info->flags |= ASYNC_CHECK_CD; + info->port.flags |= ASYNC_CHECK_CD; /* process tty input control flags */ info->read_status_mask2 = OVRN; - if (I_INPCK(info->tty)) + if (I_INPCK(info->port.tty)) info->read_status_mask2 |= PE | FRME; - if (I_BRKINT(info->tty) || I_PARMRK(info->tty)) + if (I_BRKINT(info->port.tty) || I_PARMRK(info->port.tty)) info->read_status_mask1 |= BRKD; - if (I_IGNPAR(info->tty)) + if (I_IGNPAR(info->port.tty)) info->ignore_status_mask2 |= PE | FRME; - if (I_IGNBRK(info->tty)) { + if (I_IGNBRK(info->port.tty)) { info->ignore_status_mask1 |= BRKD; /* If ignoring parity and break indicators, ignore * overruns too. (For real raw support). */ - if (I_IGNPAR(info->tty)) + if (I_IGNPAR(info->port.tty)) info->ignore_status_mask2 |= OVRN; } @@ -3348,7 +3340,7 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp, if (filp->f_flags & O_NONBLOCK || tty->flags & (1 << TTY_IO_ERROR)){ /* nonblock mode is set or port is not enabled */ /* just verify that callout device is not active */ - info->flags |= ASYNC_NORMAL_ACTIVE; + info->port.flags |= ASYNC_NORMAL_ACTIVE; return 0; } @@ -3357,25 +3349,25 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp, /* Wait for carrier detect and the line to become * free (i.e., not in use by the callout). While we are in - * this loop, info->count is dropped by one, so that + * this loop, info->port.count is dropped by one, so that * close() knows when to free things. We restore it upon * exit, either normal or abnormal. */ retval = 0; - add_wait_queue(&info->open_wait, &wait); + add_wait_queue(&info->port.open_wait, &wait); if (debug_level >= DEBUG_LEVEL_INFO) printk("%s(%d):%s block_til_ready() before block, count=%d\n", - __FILE__,__LINE__, tty->driver->name, info->count ); + __FILE__,__LINE__, tty->driver->name, info->port.count ); spin_lock_irqsave(&info->lock, flags); if (!tty_hung_up_p(filp)) { extra_count = true; - info->count--; + info->port.count--; } spin_unlock_irqrestore(&info->lock, flags); - info->blocked_open++; + info->port.blocked_open++; while (1) { if ((tty->termios->c_cflag & CBAUD)) { @@ -3387,8 +3379,8 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp, set_current_state(TASK_INTERRUPTIBLE); - if (tty_hung_up_p(filp) || !(info->flags & ASYNC_INITIALIZED)){ - retval = (info->flags & ASYNC_HUP_NOTIFY) ? + if (tty_hung_up_p(filp) || !(info->port.flags & ASYNC_INITIALIZED)){ + retval = (info->port.flags & ASYNC_HUP_NOTIFY) ? -EAGAIN : -ERESTARTSYS; break; } @@ -3397,7 +3389,7 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp, get_signals(info); spin_unlock_irqrestore(&info->lock,flags); - if (!(info->flags & ASYNC_CLOSING) && + if (!(info->port.flags & ASYNC_CLOSING) && (do_clocal || (info->serial_signals & SerialSignal_DCD)) ) { break; } @@ -3409,24 +3401,24 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp, if (debug_level >= DEBUG_LEVEL_INFO) printk("%s(%d):%s block_til_ready() count=%d\n", - __FILE__,__LINE__, tty->driver->name, info->count ); + __FILE__,__LINE__, tty->driver->name, info->port.count ); schedule(); } set_current_state(TASK_RUNNING); - remove_wait_queue(&info->open_wait, &wait); + remove_wait_queue(&info->port.open_wait, &wait); if (extra_count) - info->count++; - info->blocked_open--; + info->port.count++; + info->port.blocked_open--; if (debug_level >= DEBUG_LEVEL_INFO) printk("%s(%d):%s block_til_ready() after, count=%d\n", - __FILE__,__LINE__, tty->driver->name, info->count ); + __FILE__,__LINE__, tty->driver->name, info->port.count ); if (!retval) - info->flags |= ASYNC_NORMAL_ACTIVE; + info->port.flags |= ASYNC_NORMAL_ACTIVE; return retval; } @@ -3808,13 +3800,12 @@ static SLMP_INFO *alloc_dev(int adapter_num, int port_num, struct pci_dev *pdev) printk("%s(%d) Error can't allocate device instance data for adapter %d, port %d\n", __FILE__,__LINE__, adapter_num, port_num); } else { + tty_port_init(&info->port); info->magic = MGSL_MAGIC; INIT_WORK(&info->task, bh_handler); info->max_frame_size = 4096; - info->close_delay = 5*HZ/10; - info->closing_wait = 30*HZ; - init_waitqueue_head(&info->open_wait); - init_waitqueue_head(&info->close_wait); + info->port.close_delay = 5*HZ/10; + info->port.closing_wait = 30*HZ; init_waitqueue_head(&info->status_event_wait_q); init_waitqueue_head(&info->event_wait_q); spin_lock_init(&info->netlock); @@ -4885,7 +4876,7 @@ static bool rx_get_frame(SLMP_INFO *info) unsigned int framesize = 0; bool ReturnCode = false; unsigned long flags; - struct tty_struct *tty = info->tty; + struct tty_struct *tty = info->port.tty; unsigned char addr_field = 0xff; SCADESC *desc; SCADESC_EX *desc_ex; @@ -4983,9 +4974,8 @@ CheckAgain: framesize = 0; #if SYNCLINK_GENERIC_HDLC { - struct net_device_stats *stats = hdlc_stats(info->netdev); - stats->rx_errors++; - stats->rx_frame_errors++; + info->netdev->stats.rx_errors++; + info->netdev->stats.rx_frame_errors++; } #endif } @@ -5293,11 +5283,11 @@ static bool loopback_test(SLMP_INFO *info) bool rc = false; unsigned long flags; - struct tty_struct *oldtty = info->tty; + struct tty_struct *oldtty = info->port.tty; u32 speed = info->params.clock_speed; info->params.clock_speed = 3686400; - info->tty = NULL; + info->port.tty = NULL; /* assume failure */ info->init_error = DiagStatus_DmaFailure; @@ -5341,7 +5331,7 @@ static bool loopback_test(SLMP_INFO *info) spin_unlock_irqrestore(&info->lock,flags); info->params.clock_speed = speed; - info->tty = oldtty; + info->port.tty = oldtty; return rc; } diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c index 047a17339f83..82f6a8c86332 100644 --- a/drivers/char/tty_io.c +++ b/drivers/char/tty_io.c @@ -95,8 +95,9 @@ #include <linux/wait.h> #include <linux/bitops.h> #include <linux/delay.h> +#include <linux/seq_file.h> -#include <asm/uaccess.h> +#include <linux/uaccess.h> #include <asm/system.h> #include <linux/kbd_kern.h> @@ -682,7 +683,7 @@ static void tty_set_termios_ldisc(struct tty_struct *tty, int num) static DEFINE_SPINLOCK(tty_ldisc_lock); static DECLARE_WAIT_QUEUE_HEAD(tty_ldisc_wait); /* Line disc dispatch table */ -static struct tty_ldisc tty_ldiscs[NR_LDISCS]; +static struct tty_ldisc_ops *tty_ldiscs[NR_LDISCS]; /** * tty_register_ldisc - install a line discipline @@ -697,7 +698,7 @@ static struct tty_ldisc tty_ldiscs[NR_LDISCS]; * takes tty_ldisc_lock to guard against ldisc races */ -int tty_register_ldisc(int disc, struct tty_ldisc *new_ldisc) +int tty_register_ldisc(int disc, struct tty_ldisc_ops *new_ldisc) { unsigned long flags; int ret = 0; @@ -706,10 +707,9 @@ int tty_register_ldisc(int disc, struct tty_ldisc *new_ldisc) return -EINVAL; spin_lock_irqsave(&tty_ldisc_lock, flags); - tty_ldiscs[disc] = *new_ldisc; - tty_ldiscs[disc].num = disc; - tty_ldiscs[disc].flags |= LDISC_FLAG_DEFINED; - tty_ldiscs[disc].refcount = 0; + tty_ldiscs[disc] = new_ldisc; + new_ldisc->num = disc; + new_ldisc->refcount = 0; spin_unlock_irqrestore(&tty_ldisc_lock, flags); return ret; @@ -737,19 +737,56 @@ int tty_unregister_ldisc(int disc) return -EINVAL; spin_lock_irqsave(&tty_ldisc_lock, flags); - if (tty_ldiscs[disc].refcount) + if (tty_ldiscs[disc]->refcount) ret = -EBUSY; else - tty_ldiscs[disc].flags &= ~LDISC_FLAG_DEFINED; + tty_ldiscs[disc] = NULL; spin_unlock_irqrestore(&tty_ldisc_lock, flags); return ret; } EXPORT_SYMBOL(tty_unregister_ldisc); + +/** + * tty_ldisc_try_get - try and reference an ldisc + * @disc: ldisc number + * @ld: tty ldisc structure to complete + * + * Attempt to open and lock a line discipline into place. Return + * the line discipline refcounted and assigned in ld. On an error + * report the error code back + */ + +static int tty_ldisc_try_get(int disc, struct tty_ldisc *ld) +{ + unsigned long flags; + struct tty_ldisc_ops *ldops; + int err = -EINVAL; + + spin_lock_irqsave(&tty_ldisc_lock, flags); + ld->ops = NULL; + ldops = tty_ldiscs[disc]; + /* Check the entry is defined */ + if (ldops) { + /* If the module is being unloaded we can't use it */ + if (!try_module_get(ldops->owner)) + err = -EAGAIN; + else { + /* lock it */ + ldops->refcount++; + ld->ops = ldops; + err = 0; + } + } + spin_unlock_irqrestore(&tty_ldisc_lock, flags); + return err; +} + /** * tty_ldisc_get - take a reference to an ldisc * @disc: ldisc number + * @ld: tty line discipline structure to use * * Takes a reference to a line discipline. Deals with refcounts and * module locking counts. Returns NULL if the discipline is not available. @@ -760,32 +797,20 @@ EXPORT_SYMBOL(tty_unregister_ldisc); * takes tty_ldisc_lock to guard against ldisc races */ -struct tty_ldisc *tty_ldisc_get(int disc) +static int tty_ldisc_get(int disc, struct tty_ldisc *ld) { - unsigned long flags; - struct tty_ldisc *ld; + int err; if (disc < N_TTY || disc >= NR_LDISCS) - return NULL; - - spin_lock_irqsave(&tty_ldisc_lock, flags); - - ld = &tty_ldiscs[disc]; - /* Check the entry is defined */ - if (ld->flags & LDISC_FLAG_DEFINED) { - /* If the module is being unloaded we can't use it */ - if (!try_module_get(ld->owner)) - ld = NULL; - else /* lock it */ - ld->refcount++; - } else - ld = NULL; - spin_unlock_irqrestore(&tty_ldisc_lock, flags); - return ld; + return -EINVAL; + err = tty_ldisc_try_get(disc, ld); + if (err == -EAGAIN) { + request_module("tty-ldisc-%d", disc); + err = tty_ldisc_try_get(disc, ld); + } + return err; } -EXPORT_SYMBOL_GPL(tty_ldisc_get); - /** * tty_ldisc_put - drop ldisc reference * @disc: ldisc number @@ -797,22 +822,67 @@ EXPORT_SYMBOL_GPL(tty_ldisc_get); * takes tty_ldisc_lock to guard against ldisc races */ -void tty_ldisc_put(int disc) +static void tty_ldisc_put(struct tty_ldisc_ops *ld) { - struct tty_ldisc *ld; unsigned long flags; + int disc = ld->num; BUG_ON(disc < N_TTY || disc >= NR_LDISCS); spin_lock_irqsave(&tty_ldisc_lock, flags); - ld = &tty_ldiscs[disc]; + ld = tty_ldiscs[disc]; BUG_ON(ld->refcount == 0); ld->refcount--; module_put(ld->owner); spin_unlock_irqrestore(&tty_ldisc_lock, flags); } -EXPORT_SYMBOL_GPL(tty_ldisc_put); +static void * tty_ldiscs_seq_start(struct seq_file *m, loff_t *pos) +{ + return (*pos < NR_LDISCS) ? pos : NULL; +} + +static void * tty_ldiscs_seq_next(struct seq_file *m, void *v, loff_t *pos) +{ + (*pos)++; + return (*pos < NR_LDISCS) ? pos : NULL; +} + +static void tty_ldiscs_seq_stop(struct seq_file *m, void *v) +{ +} + +static int tty_ldiscs_seq_show(struct seq_file *m, void *v) +{ + int i = *(loff_t *)v; + struct tty_ldisc ld; + + if (tty_ldisc_get(i, &ld) < 0) + return 0; + seq_printf(m, "%-10s %2d\n", ld.ops->name ? ld.ops->name : "???", i); + tty_ldisc_put(ld.ops); + return 0; +} + +static const struct seq_operations tty_ldiscs_seq_ops = { + .start = tty_ldiscs_seq_start, + .next = tty_ldiscs_seq_next, + .stop = tty_ldiscs_seq_stop, + .show = tty_ldiscs_seq_show, +}; + +static int proc_tty_ldiscs_open(struct inode *inode, struct file *file) +{ + return seq_open(file, &tty_ldiscs_seq_ops); +} + +const struct file_operations tty_ldiscs_proc_fops = { + .owner = THIS_MODULE, + .open = proc_tty_ldiscs_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release, +}; /** * tty_ldisc_assign - set ldisc on a tty @@ -829,8 +899,8 @@ EXPORT_SYMBOL_GPL(tty_ldisc_put); static void tty_ldisc_assign(struct tty_struct *tty, struct tty_ldisc *ld) { + ld->refcount = 0; tty->ldisc = *ld; - tty->ldisc.refcount = 0; } /** @@ -954,6 +1024,41 @@ static void tty_ldisc_enable(struct tty_struct *tty) } /** + * tty_ldisc_restore - helper for tty ldisc change + * @tty: tty to recover + * @old: previous ldisc + * + * Restore the previous line discipline or N_TTY when a line discipline + * change fails due to an open error + */ + +static void tty_ldisc_restore(struct tty_struct *tty, struct tty_ldisc *old) +{ + char buf[64]; + struct tty_ldisc new_ldisc; + + /* There is an outstanding reference here so this is safe */ + tty_ldisc_get(old->ops->num, old); + tty_ldisc_assign(tty, old); + tty_set_termios_ldisc(tty, old->ops->num); + if (old->ops->open && (old->ops->open(tty) < 0)) { + tty_ldisc_put(old->ops); + /* This driver is always present */ + if (tty_ldisc_get(N_TTY, &new_ldisc) < 0) + panic("n_tty: get"); + tty_ldisc_assign(tty, &new_ldisc); + tty_set_termios_ldisc(tty, N_TTY); + if (new_ldisc.ops->open) { + int r = new_ldisc.ops->open(tty); + if (r < 0) + panic("Couldn't open N_TTY ldisc for " + "%s --- error %d.", + tty_name(tty, buf), r); + } + } +} + +/** * tty_set_ldisc - set line discipline * @tty: the terminal to set * @ldisc: the line discipline @@ -967,28 +1072,18 @@ static void tty_ldisc_enable(struct tty_struct *tty) static int tty_set_ldisc(struct tty_struct *tty, int ldisc) { - int retval = 0; - struct tty_ldisc o_ldisc; - char buf[64]; + int retval; + struct tty_ldisc o_ldisc, new_ldisc; int work; unsigned long flags; - struct tty_ldisc *ld; struct tty_struct *o_tty; - if ((ldisc < N_TTY) || (ldisc >= NR_LDISCS)) - return -EINVAL; - restart: - - ld = tty_ldisc_get(ldisc); - /* Eduardo Blanco <ejbs@cs.cs.com.uy> */ - /* Cyrus Durgin <cider@speakeasy.org> */ - if (ld == NULL) { - request_module("tty-ldisc-%d", ldisc); - ld = tty_ldisc_get(ldisc); - } - if (ld == NULL) - return -EINVAL; + /* This is a bit ugly for now but means we can break the 'ldisc + is part of the tty struct' assumption later */ + retval = tty_ldisc_get(ldisc, &new_ldisc); + if (retval) + return retval; /* * Problem: What do we do if this blocks ? @@ -996,8 +1091,8 @@ restart: tty_wait_until_sent(tty, 0); - if (tty->ldisc.num == ldisc) { - tty_ldisc_put(ldisc); + if (tty->ldisc.ops->num == ldisc) { + tty_ldisc_put(new_ldisc.ops); return 0; } @@ -1024,7 +1119,7 @@ restart: /* Free the new ldisc we grabbed. Must drop the lock first. */ spin_unlock_irqrestore(&tty_ldisc_lock, flags); - tty_ldisc_put(ldisc); + tty_ldisc_put(o_ldisc.ops); /* * There are several reasons we may be busy, including * random momentary I/O traffic. We must therefore @@ -1038,7 +1133,7 @@ restart: } if (o_tty && o_tty->ldisc.refcount) { spin_unlock_irqrestore(&tty_ldisc_lock, flags); - tty_ldisc_put(ldisc); + tty_ldisc_put(o_tty->ldisc.ops); if (wait_event_interruptible(tty_ldisc_wait, o_tty->ldisc.refcount == 0) < 0) return -ERESTARTSYS; goto restart; @@ -1049,8 +1144,9 @@ restart: * another ldisc change */ if (!test_bit(TTY_LDISC, &tty->flags)) { + struct tty_ldisc *ld; spin_unlock_irqrestore(&tty_ldisc_lock, flags); - tty_ldisc_put(ldisc); + tty_ldisc_put(new_ldisc.ops); ld = tty_ldisc_ref_wait(tty); tty_ldisc_deref(ld); goto restart; @@ -1060,7 +1156,7 @@ restart: if (o_tty) clear_bit(TTY_LDISC, &o_tty->flags); spin_unlock_irqrestore(&tty_ldisc_lock, flags); - + /* * From this point on we know nobody has an ldisc * usage reference, nor can they obtain one until @@ -1070,45 +1166,30 @@ restart: work = cancel_delayed_work(&tty->buf.work); /* * Wait for ->hangup_work and ->buf.work handlers to terminate + * MUST NOT hold locks here. */ flush_scheduled_work(); /* Shutdown the current discipline. */ - if (tty->ldisc.close) - (tty->ldisc.close)(tty); + if (o_ldisc.ops->close) + (o_ldisc.ops->close)(tty); /* Now set up the new line discipline. */ - tty_ldisc_assign(tty, ld); + tty_ldisc_assign(tty, &new_ldisc); tty_set_termios_ldisc(tty, ldisc); - if (tty->ldisc.open) - retval = (tty->ldisc.open)(tty); + if (new_ldisc.ops->open) + retval = (new_ldisc.ops->open)(tty); if (retval < 0) { - tty_ldisc_put(ldisc); - /* There is an outstanding reference here so this is safe */ - tty_ldisc_assign(tty, tty_ldisc_get(o_ldisc.num)); - tty_set_termios_ldisc(tty, tty->ldisc.num); - if (tty->ldisc.open && (tty->ldisc.open(tty) < 0)) { - tty_ldisc_put(o_ldisc.num); - /* This driver is always present */ - tty_ldisc_assign(tty, tty_ldisc_get(N_TTY)); - tty_set_termios_ldisc(tty, N_TTY); - if (tty->ldisc.open) { - int r = tty->ldisc.open(tty); - - if (r < 0) - panic("Couldn't open N_TTY ldisc for " - "%s --- error %d.", - tty_name(tty, buf), r); - } - } + tty_ldisc_put(new_ldisc.ops); + tty_ldisc_restore(tty, &o_ldisc); } /* At this point we hold a reference to the new ldisc and a a reference to the old ldisc. If we ended up flipping back to the existing ldisc we have two references to it */ - if (tty->ldisc.num != o_ldisc.num && tty->ops->set_ldisc) + if (tty->ldisc.ops->num != o_ldisc.ops->num && tty->ops->set_ldisc) tty->ops->set_ldisc(tty); - tty_ldisc_put(o_ldisc.num); + tty_ldisc_put(o_ldisc.ops); /* * Allow ldisc referencing to occur as soon as the driver @@ -1335,8 +1416,8 @@ void tty_wakeup(struct tty_struct *tty) if (test_bit(TTY_DO_WRITE_WAKEUP, &tty->flags)) { ld = tty_ldisc_ref(tty); if (ld) { - if (ld->write_wakeup) - ld->write_wakeup(tty); + if (ld->ops->write_wakeup) + ld->ops->write_wakeup(tty); tty_ldisc_deref(ld); } } @@ -1357,8 +1438,8 @@ void tty_ldisc_flush(struct tty_struct *tty) { struct tty_ldisc *ld = tty_ldisc_ref(tty); if (ld) { - if (ld->flush_buffer) - ld->flush_buffer(tty); + if (ld->ops->flush_buffer) + ld->ops->flush_buffer(tty); tty_ldisc_deref(ld); } tty_buffer_flush(tty); @@ -1386,7 +1467,7 @@ static void tty_reset_termios(struct tty_struct *tty) * do_tty_hangup - actual handler for hangup events * @work: tty device * - * This can be called by the "eventd" kernel thread. That is process +k * This can be called by the "eventd" kernel thread. That is process * synchronous but doesn't hold any locks, so we need to make sure we * have the appropriate locks for what we're doing. * @@ -1449,14 +1530,14 @@ static void do_tty_hangup(struct work_struct *work) ld = tty_ldisc_ref(tty); if (ld != NULL) { /* We may have no line discipline at this point */ - if (ld->flush_buffer) - ld->flush_buffer(tty); + if (ld->ops->flush_buffer) + ld->ops->flush_buffer(tty); tty_driver_flush_buffer(tty); if ((test_bit(TTY_DO_WRITE_WAKEUP, &tty->flags)) && - ld->write_wakeup) - ld->write_wakeup(tty); - if (ld->hangup) - ld->hangup(tty); + ld->ops->write_wakeup) + ld->ops->write_wakeup(tty); + if (ld->ops->hangup) + ld->ops->hangup(tty); } /* * FIXME: Once we trust the LDISC code better we can wait here for @@ -1825,8 +1906,8 @@ static ssize_t tty_read(struct file *file, char __user *buf, size_t count, /* We want to wait for the line discipline to sort out in this situation */ ld = tty_ldisc_ref_wait(tty); - if (ld->read) - i = (ld->read)(tty, file, buf, count); + if (ld->ops->read) + i = (ld->ops->read)(tty, file, buf, count); else i = -EIO; tty_ldisc_deref(ld); @@ -1978,10 +2059,10 @@ static ssize_t tty_write(struct file *file, const char __user *buf, printk(KERN_ERR "tty driver %s lacks a write_room method.\n", tty->driver->name); ld = tty_ldisc_ref_wait(tty); - if (!ld->write) + if (!ld->ops->write) ret = -EIO; else - ret = do_tty_write(ld->write, tty, file, buf, count); + ret = do_tty_write(ld->ops->write, tty, file, buf, count); tty_ldisc_deref(ld); return ret; } @@ -2007,6 +2088,42 @@ ssize_t redirected_tty_write(struct file *file, const char __user *buf, return tty_write(file, buf, count, ppos); } +void tty_port_init(struct tty_port *port) +{ + memset(port, 0, sizeof(*port)); + init_waitqueue_head(&port->open_wait); + init_waitqueue_head(&port->close_wait); + mutex_init(&port->mutex); + port->close_delay = (50 * HZ) / 100; + port->closing_wait = (3000 * HZ) / 100; +} +EXPORT_SYMBOL(tty_port_init); + +int tty_port_alloc_xmit_buf(struct tty_port *port) +{ + /* We may sleep in get_zeroed_page() */ + mutex_lock(&port->mutex); + if (port->xmit_buf == NULL) + port->xmit_buf = (unsigned char *)get_zeroed_page(GFP_KERNEL); + mutex_unlock(&port->mutex); + if (port->xmit_buf == NULL) + return -ENOMEM; + return 0; +} +EXPORT_SYMBOL(tty_port_alloc_xmit_buf); + +void tty_port_free_xmit_buf(struct tty_port *port) +{ + mutex_lock(&port->mutex); + if (port->xmit_buf != NULL) { + free_page((unsigned long)port->xmit_buf); + port->xmit_buf = NULL; + } + mutex_unlock(&port->mutex); +} +EXPORT_SYMBOL(tty_port_free_xmit_buf); + + static char ptychar[] = "pqrstuvwxyzabcde"; /** @@ -2076,6 +2193,7 @@ static int init_dev(struct tty_driver *driver, int idx, struct ktermios *tp, **tp_loc, *o_tp, **o_tp_loc; struct ktermios *ltp, **ltp_loc, *o_ltp, **o_ltp_loc; int retval = 0; + struct tty_ldisc *ld; /* check whether we're reopening an existing tty */ if (driver->flags & TTY_DRIVER_DEVPTS_MEM) { @@ -2224,17 +2342,19 @@ static int init_dev(struct tty_driver *driver, int idx, * If we fail here just call release_tty to clean up. No need * to decrement the use counts, as release_tty doesn't care. */ + + ld = &tty->ldisc; - if (tty->ldisc.open) { - retval = (tty->ldisc.open)(tty); + if (ld->ops->open) { + retval = (ld->ops->open)(tty); if (retval) goto release_mem_out; } - if (o_tty && o_tty->ldisc.open) { - retval = (o_tty->ldisc.open)(o_tty); + if (o_tty && o_tty->ldisc.ops->open) { + retval = (o_tty->ldisc.ops->open)(o_tty); if (retval) { - if (tty->ldisc.close) - (tty->ldisc.close)(tty); + if (ld->ops->close) + (ld->ops->close)(tty); goto release_mem_out; } tty_ldisc_enable(o_tty); @@ -2378,6 +2498,7 @@ static void release_tty(struct tty_struct *tty, int idx) static void release_dev(struct file *filp) { struct tty_struct *tty, *o_tty; + struct tty_ldisc ld; int pty_master, tty_closing, o_tty_closing, do_sleep; int devpts; int idx; @@ -2611,26 +2732,27 @@ static void release_dev(struct file *filp) spin_unlock_irqrestore(&tty_ldisc_lock, flags); /* * Shutdown the current line discipline, and reset it to N_TTY. - * N.B. why reset ldisc when we're releasing the memory?? * * FIXME: this MUST get fixed for the new reflocking */ - if (tty->ldisc.close) - (tty->ldisc.close)(tty); - tty_ldisc_put(tty->ldisc.num); + if (tty->ldisc.ops->close) + (tty->ldisc.ops->close)(tty); + tty_ldisc_put(tty->ldisc.ops); /* * Switch the line discipline back */ - tty_ldisc_assign(tty, tty_ldisc_get(N_TTY)); + WARN_ON(tty_ldisc_get(N_TTY, &ld)); + tty_ldisc_assign(tty, &ld); tty_set_termios_ldisc(tty, N_TTY); if (o_tty) { /* FIXME: could o_tty be in setldisc here ? */ clear_bit(TTY_LDISC, &o_tty->flags); - if (o_tty->ldisc.close) - (o_tty->ldisc.close)(o_tty); - tty_ldisc_put(o_tty->ldisc.num); - tty_ldisc_assign(o_tty, tty_ldisc_get(N_TTY)); + if (o_tty->ldisc.ops->close) + (o_tty->ldisc.ops->close)(o_tty); + tty_ldisc_put(o_tty->ldisc.ops); + WARN_ON(tty_ldisc_get(N_TTY, &ld)); + tty_ldisc_assign(o_tty, &ld); tty_set_termios_ldisc(o_tty, N_TTY); } /* @@ -2899,8 +3021,8 @@ static unsigned int tty_poll(struct file *filp, poll_table *wait) return 0; ld = tty_ldisc_ref_wait(tty); - if (ld->poll) - ret = (ld->poll)(tty, filp, wait); + if (ld->ops->poll) + ret = (ld->ops->poll)(tty, filp, wait); tty_ldisc_deref(ld); return ret; } @@ -2974,7 +3096,7 @@ static int tiocsti(struct tty_struct *tty, char __user *p) if (get_user(ch, p)) return -EFAULT; ld = tty_ldisc_ref_wait(tty); - ld->receive_buf(tty, &ch, &mbz, 1); + ld->ops->receive_buf(tty, &ch, &mbz, 1); tty_ldisc_deref(ld); return 0; } @@ -3395,35 +3517,31 @@ static int tty_tiocmget(struct tty_struct *tty, struct file *file, int __user *p static int tty_tiocmset(struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned __user *p) { - int retval = -EINVAL; - - if (tty->ops->tiocmset) { - unsigned int set, clear, val; - - retval = get_user(val, p); - if (retval) - return retval; - - set = clear = 0; - switch (cmd) { - case TIOCMBIS: - set = val; - break; - case TIOCMBIC: - clear = val; - break; - case TIOCMSET: - set = val; - clear = ~val; - break; - } + int retval; + unsigned int set, clear, val; - set &= TIOCM_DTR|TIOCM_RTS|TIOCM_OUT1|TIOCM_OUT2|TIOCM_LOOP; - clear &= TIOCM_DTR|TIOCM_RTS|TIOCM_OUT1|TIOCM_OUT2|TIOCM_LOOP; + if (tty->ops->tiocmset == NULL) + return -EINVAL; - retval = tty->ops->tiocmset(tty, file, set, clear); + retval = get_user(val, p); + if (retval) + return retval; + set = clear = 0; + switch (cmd) { + case TIOCMBIS: + set = val; + break; + case TIOCMBIC: + clear = val; + break; + case TIOCMSET: + set = val; + clear = ~val; + break; } - return retval; + set &= TIOCM_DTR|TIOCM_RTS|TIOCM_OUT1|TIOCM_OUT2|TIOCM_LOOP; + clear &= TIOCM_DTR|TIOCM_RTS|TIOCM_OUT1|TIOCM_OUT2|TIOCM_LOOP; + return tty->ops->tiocmset(tty, file, set, clear); } /* @@ -3528,7 +3646,7 @@ long tty_ioctl(struct file *file, unsigned int cmd, unsigned long arg) case TIOCGSID: return tiocgsid(tty, real_tty, p); case TIOCGETD: - return put_user(tty->ldisc.num, (int __user *)p); + return put_user(tty->ldisc.ops->num, (int __user *)p); case TIOCSETD: return tiocsetd(tty, p); #ifdef CONFIG_VT @@ -3581,8 +3699,8 @@ long tty_ioctl(struct file *file, unsigned int cmd, unsigned long arg) } ld = tty_ldisc_ref_wait(tty); retval = -EINVAL; - if (ld->ioctl) { - retval = ld->ioctl(tty, file, cmd, arg); + if (ld->ops->ioctl) { + retval = ld->ops->ioctl(tty, file, cmd, arg); if (retval == -ENOIOCTLCMD) retval = -EINVAL; } @@ -3609,8 +3727,8 @@ static long tty_compat_ioctl(struct file *file, unsigned int cmd, } ld = tty_ldisc_ref_wait(tty); - if (ld->compat_ioctl) - retval = ld->compat_ioctl(tty, file, cmd, arg); + if (ld->ops->compat_ioctl) + retval = ld->ops->compat_ioctl(tty, file, cmd, arg); tty_ldisc_deref(ld); return retval; @@ -3782,7 +3900,8 @@ static void flush_to_ldisc(struct work_struct *work) flag_buf = head->flag_buf_ptr + head->read; head->read += count; spin_unlock_irqrestore(&tty->buf.lock, flags); - disc->receive_buf(tty, char_buf, flag_buf, count); + disc->ops->receive_buf(tty, char_buf, + flag_buf, count); spin_lock_irqsave(&tty->buf.lock, flags); } /* Restore the queue head */ @@ -3843,9 +3962,12 @@ EXPORT_SYMBOL(tty_flip_buffer_push); static void initialize_tty_struct(struct tty_struct *tty) { + struct tty_ldisc ld; memset(tty, 0, sizeof(struct tty_struct)); tty->magic = TTY_MAGIC; - tty_ldisc_assign(tty, tty_ldisc_get(N_TTY)); + if (tty_ldisc_get(N_TTY, &ld) < 0) + panic("n_tty: init_tty"); + tty_ldisc_assign(tty, &ld); tty->session = NULL; tty->pgrp = NULL; tty->overrun_time = jiffies; diff --git a/drivers/char/tty_ioctl.c b/drivers/char/tty_ioctl.c index 8f81139d6194..ea9fc5d03b99 100644 --- a/drivers/char/tty_ioctl.c +++ b/drivers/char/tty_ioctl.c @@ -491,8 +491,8 @@ static void change_termios(struct tty_struct *tty, struct ktermios *new_termios) ld = tty_ldisc_ref(tty); if (ld != NULL) { - if (ld->set_termios) - (ld->set_termios)(tty, &old_termios); + if (ld->ops->set_termios) + (ld->ops->set_termios)(tty, &old_termios); tty_ldisc_deref(ld); } mutex_unlock(&tty->termios_mutex); @@ -552,8 +552,8 @@ static int set_termios(struct tty_struct *tty, void __user *arg, int opt) ld = tty_ldisc_ref(tty); if (ld != NULL) { - if ((opt & TERMIOS_FLUSH) && ld->flush_buffer) - ld->flush_buffer(tty); + if ((opt & TERMIOS_FLUSH) && ld->ops->flush_buffer) + ld->ops->flush_buffer(tty); tty_ldisc_deref(ld); } @@ -959,12 +959,12 @@ int tty_perform_flush(struct tty_struct *tty, unsigned long arg) ld = tty_ldisc_ref(tty); switch (arg) { case TCIFLUSH: - if (ld && ld->flush_buffer) - ld->flush_buffer(tty); + if (ld && ld->ops->flush_buffer) + ld->ops->flush_buffer(tty); break; case TCIOFLUSH: - if (ld && ld->flush_buffer) - ld->flush_buffer(tty); + if (ld && ld->ops->flush_buffer) + ld->ops->flush_buffer(tty); /* fall through */ case TCOFLUSH: tty_driver_flush_buffer(tty); diff --git a/drivers/dio/dio-driver.c b/drivers/dio/dio-driver.c index 8cd8507b1a8a..9c0c9afcd0ac 100644 --- a/drivers/dio/dio-driver.c +++ b/drivers/dio/dio-driver.c @@ -119,19 +119,7 @@ static int dio_bus_match(struct device *dev, struct device_driver *drv) if (!ids) return 0; - while (ids->id) { - if (ids->id == DIO_WILDCARD) - return 1; - if (DIO_NEEDSSECID(ids->id & 0xff)) { - if (ids->id == d->id) - return 1; - } else { - if ((ids->id & 0xff) == (d->id & 0xff)) - return 1; - } - ids++; - } - return 0; + return dio_match_device(ids, d) ? 1 : 0; } diff --git a/drivers/infiniband/ulp/ipoib/ipoib_multicast.c b/drivers/infiniband/ulp/ipoib/ipoib_multicast.c index 1fcc9a898d81..8950e9546f4e 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_multicast.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_multicast.c @@ -769,7 +769,7 @@ void ipoib_mcast_restart_task(struct work_struct *work) ipoib_mcast_stop_thread(dev, 0); local_irq_save(flags); - netif_tx_lock(dev); + netif_addr_lock(dev); spin_lock(&priv->lock); /* @@ -846,7 +846,7 @@ void ipoib_mcast_restart_task(struct work_struct *work) } spin_unlock(&priv->lock); - netif_tx_unlock(dev); + netif_addr_unlock(dev); local_irq_restore(flags); /* We have to cancel outside of the spinlock */ diff --git a/drivers/input/keyboard/atakbd.c b/drivers/input/keyboard/atakbd.c index 4e92100c56a8..1839194ea987 100644 --- a/drivers/input/keyboard/atakbd.c +++ b/drivers/input/keyboard/atakbd.c @@ -220,7 +220,7 @@ static int __init atakbd_init(void) int i, error; if (!MACH_IS_ATARI || !ATARIHW_PRESENT(ST_MFP)) - return -EIO; + return -ENODEV; // need to init core driver if not already done so if (atari_keyb_init()) diff --git a/drivers/input/serio/serport.c b/drivers/input/serio/serport.c index 7ff71ba7b7c9..b9694b6445d0 100644 --- a/drivers/input/serio/serport.c +++ b/drivers/input/serio/serport.c @@ -216,7 +216,7 @@ static void serport_ldisc_write_wakeup(struct tty_struct * tty) * The line discipline structure. */ -static struct tty_ldisc serport_ldisc = { +static struct tty_ldisc_ops serport_ldisc = { .owner = THIS_MODULE, .name = "input", .open = serport_ldisc_open, diff --git a/drivers/isdn/capi/capi.c b/drivers/isdn/capi/capi.c index 2095153582f1..8a35029caca0 100644 --- a/drivers/isdn/capi/capi.c +++ b/drivers/isdn/capi/capi.c @@ -466,7 +466,7 @@ static int handle_recv_skb(struct capiminor *mp, struct sk_buff *skb) ld = tty_ldisc_ref(mp->tty); if (ld == NULL) return -1; - if (ld->receive_buf == NULL) { + if (ld->ops->receive_buf == NULL) { #if defined(_DEBUG_DATAFLOW) || defined(_DEBUG_TTYFUNCS) printk(KERN_DEBUG "capi: ldisc has no receive_buf function\n"); #endif @@ -501,7 +501,7 @@ static int handle_recv_skb(struct capiminor *mp, struct sk_buff *skb) printk(KERN_DEBUG "capi: DATA_B3_RESP %u len=%d => ldisc\n", datahandle, skb->len); #endif - ld->receive_buf(mp->tty, skb->data, NULL, skb->len); + ld->ops->receive_buf(mp->tty, skb->data, NULL, skb->len); kfree_skb(skb); tty_ldisc_deref(ld); return 0; diff --git a/drivers/isdn/gigaset/ser-gigaset.c b/drivers/isdn/gigaset/ser-gigaset.c index 45d1ee93cd39..5e89fa177816 100644 --- a/drivers/isdn/gigaset/ser-gigaset.c +++ b/drivers/isdn/gigaset/ser-gigaset.c @@ -766,7 +766,7 @@ gigaset_tty_wakeup(struct tty_struct *tty) cs_put(cs); } -static struct tty_ldisc gigaset_ldisc = { +static struct tty_ldisc_ops gigaset_ldisc = { .owner = THIS_MODULE, .magic = TTY_LDISC_MAGIC, .name = "ser_gigaset", diff --git a/drivers/isdn/i4l/isdn_net.c b/drivers/isdn/i4l/isdn_net.c index ef1a300068dc..bb904a0a98bd 100644 --- a/drivers/isdn/i4l/isdn_net.c +++ b/drivers/isdn/i4l/isdn_net.c @@ -287,7 +287,7 @@ isdn_net_unbind_channel(isdn_net_local * lp) BEWARE! This chunk of code cannot be called from hardware interrupt handler. I hope it is true. --ANK */ - qdisc_reset(lp->netdev->dev->qdisc); + qdisc_reset_all_tx(lp->netdev->dev); } lp->dialstate = 0; dev->rx_netdev[isdn_dc2minor(lp->isdn_device, lp->isdn_channel)] = NULL; diff --git a/drivers/media/Kconfig b/drivers/media/Kconfig index 7a7803b5d497..93ea201f426c 100644 --- a/drivers/media/Kconfig +++ b/drivers/media/Kconfig @@ -38,7 +38,6 @@ config VIDEO_ALLOW_V4L1 bool "Enable Video For Linux API 1 (DEPRECATED)" depends on VIDEO_DEV && VIDEO_V4L2_COMMON default VIDEO_DEV && VIDEO_V4L2_COMMON - select VIDEO_V4L1_COMPAT ---help--- Enables drivers based on the legacy V4L1 API. @@ -49,9 +48,9 @@ config VIDEO_ALLOW_V4L1 If you are unsure as to whether this is required, answer Y. config VIDEO_V4L1_COMPAT - bool "Enable Video For Linux API 1 compatible Layer" + bool "Enable Video For Linux API 1 compatible Layer" if !VIDEO_ALLOW_V4L1 depends on VIDEO_DEV - default VIDEO_DEV + default y ---help--- Enables a compatibility API used by most V4L2 devices to allow its usage with legacy applications that supports only V4L1 api. diff --git a/drivers/media/common/ir-functions.c b/drivers/media/common/ir-functions.c index 266505207925..16792a68a449 100644 --- a/drivers/media/common/ir-functions.c +++ b/drivers/media/common/ir-functions.c @@ -66,7 +66,6 @@ void ir_input_init(struct input_dev *dev, struct ir_input_state *ir, if (ir_codes) memcpy(ir->ir_codes, ir_codes, sizeof(ir->ir_codes)); - dev->keycode = ir->ir_codes; dev->keycodesize = sizeof(IR_KEYTAB_TYPE); dev->keycodemax = IR_KEYTAB_SIZE; @@ -78,6 +77,7 @@ void ir_input_init(struct input_dev *dev, struct ir_input_state *ir, if (repeat) set_bit(EV_REP, dev->evbit); } +EXPORT_SYMBOL_GPL(ir_input_init); void ir_input_nokey(struct input_dev *dev, struct ir_input_state *ir) { @@ -86,6 +86,7 @@ void ir_input_nokey(struct input_dev *dev, struct ir_input_state *ir) ir_input_key_event(dev,ir); } } +EXPORT_SYMBOL_GPL(ir_input_nokey); void ir_input_keydown(struct input_dev *dev, struct ir_input_state *ir, u32 ir_key, u32 ir_raw) @@ -104,6 +105,7 @@ void ir_input_keydown(struct input_dev *dev, struct ir_input_state *ir, ir_input_key_event(dev,ir); } } +EXPORT_SYMBOL_GPL(ir_input_keydown); /* -------------------------------------------------------------------------- */ /* extract mask bits out of data and pack them into the result */ @@ -122,6 +124,7 @@ u32 ir_extract_bits(u32 data, u32 mask) return value; } +EXPORT_SYMBOL_GPL(ir_extract_bits); static int inline getbit(u32 *samples, int bit) { @@ -146,6 +149,7 @@ int ir_dump_samples(u32 *samples, int count) printk("\n"); return 0; } +EXPORT_SYMBOL_GPL(ir_dump_samples); /* decode raw samples, pulse distance coding used by NEC remotes */ int ir_decode_pulsedistance(u32 *samples, int count, int low, int high) @@ -212,6 +216,7 @@ int ir_decode_pulsedistance(u32 *samples, int count, int low, int high) return value; } +EXPORT_SYMBOL_GPL(ir_decode_pulsedistance); /* decode raw samples, biphase coding, used by rc5 for example */ int ir_decode_biphase(u32 *samples, int count, int low, int high) @@ -253,6 +258,7 @@ int ir_decode_biphase(u32 *samples, int count, int low, int high) } return value; } +EXPORT_SYMBOL_GPL(ir_decode_biphase); /* RC5 decoding stuff, moved from bttv-input.c to share it with * saa7134 */ @@ -353,6 +359,7 @@ void ir_rc5_timer_end(unsigned long data) } } } +EXPORT_SYMBOL_GPL(ir_rc5_timer_end); void ir_rc5_timer_keyup(unsigned long data) { @@ -361,21 +368,4 @@ void ir_rc5_timer_keyup(unsigned long data) dprintk(1, "ir-common: key released\n"); ir_input_nokey(ir->dev, &ir->ir); } - -EXPORT_SYMBOL_GPL(ir_input_init); -EXPORT_SYMBOL_GPL(ir_input_nokey); -EXPORT_SYMBOL_GPL(ir_input_keydown); - -EXPORT_SYMBOL_GPL(ir_extract_bits); -EXPORT_SYMBOL_GPL(ir_dump_samples); -EXPORT_SYMBOL_GPL(ir_decode_biphase); -EXPORT_SYMBOL_GPL(ir_decode_pulsedistance); - -EXPORT_SYMBOL_GPL(ir_rc5_timer_end); EXPORT_SYMBOL_GPL(ir_rc5_timer_keyup); - -/* - * Local variables: - * c-basic-offset: 8 - * End: - */ diff --git a/drivers/media/common/saa7146_core.c b/drivers/media/common/saa7146_core.c index 89c7660b85d6..d01965e96927 100644 --- a/drivers/media/common/saa7146_core.c +++ b/drivers/media/common/saa7146_core.c @@ -233,7 +233,7 @@ void saa7146_pgtable_free(struct pci_dev *pci, struct saa7146_pgtable *pt) int saa7146_pgtable_alloc(struct pci_dev *pci, struct saa7146_pgtable *pt) { - u32 *cpu; + __le32 *cpu; dma_addr_t dma_addr; cpu = pci_alloc_consistent(pci, PAGE_SIZE, &dma_addr); @@ -250,7 +250,7 @@ int saa7146_pgtable_alloc(struct pci_dev *pci, struct saa7146_pgtable *pt) int saa7146_pgtable_build_single(struct pci_dev *pci, struct saa7146_pgtable *pt, struct scatterlist *list, int sglen ) { - u32 *ptr, fill; + __le32 *ptr, fill; int nr_pages = 0; int i,p; diff --git a/drivers/media/common/saa7146_hlp.c b/drivers/media/common/saa7146_hlp.c index 9c905399a233..05bde9ccb770 100644 --- a/drivers/media/common/saa7146_hlp.c +++ b/drivers/media/common/saa7146_hlp.c @@ -338,7 +338,7 @@ static void calculate_clipping_registers_rect(struct saa7146_dev *dev, struct sa struct saa7146_video_dma *vdma2, u32* clip_format, u32* arbtr_ctrl, enum v4l2_field field) { struct saa7146_vv *vv = dev->vv_data; - u32 *clipping = vv->d_clipping.cpu_addr; + __le32 *clipping = vv->d_clipping.cpu_addr; int width = fh->ov.win.w.width; int height = fh->ov.win.w.height; diff --git a/drivers/media/common/saa7146_i2c.c b/drivers/media/common/saa7146_i2c.c index 35b01ec40a51..c11da4d09cd0 100644 --- a/drivers/media/common/saa7146_i2c.c +++ b/drivers/media/common/saa7146_i2c.c @@ -24,7 +24,7 @@ static inline u32 saa7146_i2c_status(struct saa7146_dev *dev) sent through the saa7146. have a look at the specifications p. 122 ff to understand this. it returns the number of u32s to send, or -1 in case of an error. */ -static int saa7146_i2c_msg_prepare(const struct i2c_msg *m, int num, u32 *op) +static int saa7146_i2c_msg_prepare(const struct i2c_msg *m, int num, __le32 *op) { int h1, h2; int i, j, addr; @@ -47,7 +47,7 @@ static int saa7146_i2c_msg_prepare(const struct i2c_msg *m, int num, u32 *op) } /* be careful: clear out the i2c-mem first */ - memset(op,0,sizeof(u32)*mem); + memset(op,0,sizeof(__le32)*mem); /* loop through all messages */ for(i = 0; i < num; i++) { @@ -57,16 +57,16 @@ static int saa7146_i2c_msg_prepare(const struct i2c_msg *m, int num, u32 *op) so we have to perform a translation */ addr = (m[i].addr*2) + ( (0 != (m[i].flags & I2C_M_RD)) ? 1 : 0); h1 = op_count/3; h2 = op_count%3; - op[h1] |= ( (u8)addr << ((3-h2)*8)); - op[h1] |= (SAA7146_I2C_START << ((3-h2)*2)); + op[h1] |= cpu_to_le32( (u8)addr << ((3-h2)*8)); + op[h1] |= cpu_to_le32(SAA7146_I2C_START << ((3-h2)*2)); op_count++; /* loop through all bytes of message i */ for(j = 0; j < m[i].len; j++) { /* insert the data bytes */ h1 = op_count/3; h2 = op_count%3; - op[h1] |= ( (u32)((u8)m[i].buf[j]) << ((3-h2)*8)); - op[h1] |= ( SAA7146_I2C_CONT << ((3-h2)*2)); + op[h1] |= cpu_to_le32( (u32)((u8)m[i].buf[j]) << ((3-h2)*8)); + op[h1] |= cpu_to_le32( SAA7146_I2C_CONT << ((3-h2)*2)); op_count++; } @@ -75,9 +75,9 @@ static int saa7146_i2c_msg_prepare(const struct i2c_msg *m, int num, u32 *op) /* have a look at the last byte inserted: if it was: ...CONT change it to ...STOP */ h1 = (op_count-1)/3; h2 = (op_count-1)%3; - if ( SAA7146_I2C_CONT == (0x3 & (op[h1] >> ((3-h2)*2))) ) { - op[h1] &= ~(0x2 << ((3-h2)*2)); - op[h1] |= (SAA7146_I2C_STOP << ((3-h2)*2)); + if ( SAA7146_I2C_CONT == (0x3 & (le32_to_cpu(op[h1]) >> ((3-h2)*2))) ) { + op[h1] &= ~cpu_to_le32(0x2 << ((3-h2)*2)); + op[h1] |= cpu_to_le32(SAA7146_I2C_STOP << ((3-h2)*2)); } /* return the number of u32s to send */ @@ -88,7 +88,7 @@ static int saa7146_i2c_msg_prepare(const struct i2c_msg *m, int num, u32 *op) which bytes were read through the adapter and write them back to the corresponding i2c-message. but instead, we simply write back all bytes. fixme: this could be improved. */ -static int saa7146_i2c_msg_cleanup(const struct i2c_msg *m, int num, u32 *op) +static int saa7146_i2c_msg_cleanup(const struct i2c_msg *m, int num, __le32 *op) { int i, j; int op_count = 0; @@ -101,7 +101,7 @@ static int saa7146_i2c_msg_cleanup(const struct i2c_msg *m, int num, u32 *op) /* loop throgh all bytes of message i */ for(j = 0; j < m[i].len; j++) { /* write back all bytes that could have been read */ - m[i].buf[j] = (op[op_count/3] >> ((3-(op_count%3))*8)); + m[i].buf[j] = (le32_to_cpu(op[op_count/3]) >> ((3-(op_count%3))*8)); op_count++; } } @@ -174,7 +174,7 @@ static int saa7146_i2c_reset(struct saa7146_dev *dev) /* this functions writes out the data-byte 'dword' to the i2c-device. it returns 0 if ok, -1 if the transfer failed, -2 if the transfer failed badly (e.g. address error) */ -static int saa7146_i2c_writeout(struct saa7146_dev *dev, u32* dword, int short_delay) +static int saa7146_i2c_writeout(struct saa7146_dev *dev, __le32 *dword, int short_delay) { u32 status = 0, mc2 = 0; int trial = 0; @@ -186,7 +186,7 @@ static int saa7146_i2c_writeout(struct saa7146_dev *dev, u32* dword, int short_d if( 0 != (SAA7146_USE_I2C_IRQ & dev->ext->flags)) { saa7146_write(dev, I2C_STATUS, dev->i2c_bitrate); - saa7146_write(dev, I2C_TRANSFER, *dword); + saa7146_write(dev, I2C_TRANSFER, le32_to_cpu(*dword)); dev->i2c_op = 1; SAA7146_ISR_CLEAR(dev, MASK_16|MASK_17); @@ -209,7 +209,7 @@ static int saa7146_i2c_writeout(struct saa7146_dev *dev, u32* dword, int short_d status = saa7146_read(dev, I2C_STATUS); } else { saa7146_write(dev, I2C_STATUS, dev->i2c_bitrate); - saa7146_write(dev, I2C_TRANSFER, *dword); + saa7146_write(dev, I2C_TRANSFER, le32_to_cpu(*dword)); saa7146_write(dev, MC2, (MASK_00 | MASK_16)); /* do not poll for i2c-status before upload is complete */ @@ -282,7 +282,7 @@ static int saa7146_i2c_writeout(struct saa7146_dev *dev, u32* dword, int short_d } /* read back data, just in case we were reading ... */ - *dword = saa7146_read(dev, I2C_TRANSFER); + *dword = cpu_to_le32(saa7146_read(dev, I2C_TRANSFER)); DEB_I2C(("after: 0x%08x\n",*dword)); return 0; @@ -291,7 +291,7 @@ static int saa7146_i2c_writeout(struct saa7146_dev *dev, u32* dword, int short_d static int saa7146_i2c_transfer(struct saa7146_dev *dev, const struct i2c_msg *msgs, int num, int retries) { int i = 0, count = 0; - u32* buffer = dev->d_i2c.cpu_addr; + __le32 *buffer = dev->d_i2c.cpu_addr; int err = 0; int address_err = 0; int short_delay = 0; @@ -376,7 +376,7 @@ out: /* another bug in revision 0: the i2c-registers get uploaded randomly by other uploads, so we better clear them out before continueing */ if( 0 == dev->revision ) { - u32 zero = 0; + __le32 zero = 0; saa7146_i2c_reset(dev); if( 0 != saa7146_i2c_writeout(dev, &zero, short_delay)) { INFO(("revision 0 error. this should never happen.\n")); diff --git a/drivers/media/common/saa7146_video.c b/drivers/media/common/saa7146_video.c index 3cbc6ebbe649..a5e62750eea3 100644 --- a/drivers/media/common/saa7146_video.c +++ b/drivers/media/common/saa7146_video.c @@ -605,8 +605,8 @@ static int saa7146_pgtable_build(struct saa7146_dev *dev, struct saa7146_buf *bu struct saa7146_pgtable *pt1 = &buf->pt[0]; struct saa7146_pgtable *pt2 = &buf->pt[1]; struct saa7146_pgtable *pt3 = &buf->pt[2]; - u32 *ptr1, *ptr2, *ptr3; - u32 fill; + __le32 *ptr1, *ptr2, *ptr3; + __le32 fill; int size = buf->fmt->width*buf->fmt->height; int i,p,m1,m2,m3,o1,o2; diff --git a/drivers/media/common/tuners/Kconfig b/drivers/media/common/tuners/Kconfig index 85482960d012..850d5689b14d 100644 --- a/drivers/media/common/tuners/Kconfig +++ b/drivers/media/common/tuners/Kconfig @@ -34,6 +34,7 @@ config MEDIA_TUNER menuconfig MEDIA_TUNER_CUSTOMIZE bool "Customize analog and hybrid tuner modules to build" depends on MEDIA_TUNER + default n help This allows the user to deselect tuner drivers unnecessary for their hardware from the build. Use this option with care diff --git a/drivers/media/common/tuners/tda18271-maps.c b/drivers/media/common/tuners/tda18271-maps.c index 83e7561960c1..ab14ceb9e0ce 100644 --- a/drivers/media/common/tuners/tda18271-maps.c +++ b/drivers/media/common/tuners/tda18271-maps.c @@ -1,5 +1,5 @@ /* - tda18271-tables.c - driver for the Philips / NXP TDA18271 silicon tuner + tda18271-maps.c - driver for the Philips / NXP TDA18271 silicon tuner Copyright (C) 2007, 2008 Michael Krufky <mkrufky@linuxtv.org> diff --git a/drivers/media/common/tuners/tuner-xc2028.c b/drivers/media/common/tuners/tuner-xc2028.c index 30eb07b7f9ef..4dd1d2421cc5 100644 --- a/drivers/media/common/tuners/tuner-xc2028.c +++ b/drivers/media/common/tuners/tuner-xc2028.c @@ -15,6 +15,7 @@ #include <linux/delay.h> #include <media/tuner.h> #include <linux/mutex.h> +#include <asm/unaligned.h> #include "tuner-i2c.h" #include "tuner-xc2028.h" #include "tuner-xc2028-types.h" @@ -292,10 +293,10 @@ static int load_all_firmwares(struct dvb_frontend *fe) name[sizeof(name) - 1] = 0; p += sizeof(name) - 1; - priv->firm_version = le16_to_cpu(*(__u16 *) p); + priv->firm_version = get_unaligned_le16(p); p += 2; - n_array = le16_to_cpu(*(__u16 *) p); + n_array = get_unaligned_le16(p); p += 2; tuner_info("Loading %d firmware images from %s, type: %s, ver %d.%d\n", @@ -324,26 +325,26 @@ static int load_all_firmwares(struct dvb_frontend *fe) } /* Checks if there's enough bytes to read */ - if (p + sizeof(type) + sizeof(id) + sizeof(size) > endp) { - tuner_err("Firmware header is incomplete!\n"); - goto corrupt; - } + if (endp - p < sizeof(type) + sizeof(id) + sizeof(size)) + goto header; - type = le32_to_cpu(*(__u32 *) p); + type = get_unaligned_le32(p); p += sizeof(type); - id = le64_to_cpu(*(v4l2_std_id *) p); + id = get_unaligned_le64(p); p += sizeof(id); if (type & HAS_IF) { - int_freq = le16_to_cpu(*(__u16 *) p); + int_freq = get_unaligned_le16(p); p += sizeof(int_freq); + if (endp - p < sizeof(size)) + goto header; } - size = le32_to_cpu(*(__u32 *) p); + size = get_unaligned_le32(p); p += sizeof(size); - if ((!size) || (size + p > endp)) { + if (!size || size > endp - p) { tuner_err("Firmware type "); dump_firm_type(type); printk("(%x), id %llx is corrupted " @@ -382,6 +383,8 @@ static int load_all_firmwares(struct dvb_frontend *fe) goto done; +header: + tuner_err("Firmware header is incomplete!\n"); corrupt: rc = -EINVAL; tuner_err("Error: firmware file is corrupted!\n"); diff --git a/drivers/media/common/tuners/xc5000.c b/drivers/media/common/tuners/xc5000.c index 4878d6477a8c..5f99de0ad612 100644 --- a/drivers/media/common/tuners/xc5000.c +++ b/drivers/media/common/tuners/xc5000.c @@ -36,6 +36,10 @@ static int debug; module_param(debug, int, 0644); MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off)."); +static int xc5000_load_fw_on_attach; +module_param_named(init_fw, xc5000_load_fw_on_attach, int, 0644); +MODULE_PARM_DESC(init_fw, "Load firmware during driver initialization."); + #define dprintk(level,fmt, arg...) if (debug >= level) \ printk(KERN_INFO "%s: " fmt, "xc5000", ## arg) @@ -972,6 +976,9 @@ struct dvb_frontend *xc5000_attach(struct dvb_frontend *fe, fe->tuner_priv = priv; + if (xc5000_load_fw_on_attach) + xc5000_init(fe); + return fe; } EXPORT_SYMBOL(xc5000_attach); diff --git a/drivers/media/dvb/Kconfig b/drivers/media/dvb/Kconfig index 7b21b49f1945..8bc1445bd33b 100644 --- a/drivers/media/dvb/Kconfig +++ b/drivers/media/dvb/Kconfig @@ -21,6 +21,7 @@ source "drivers/media/dvb/dvb-usb/Kconfig" source "drivers/media/dvb/ttusb-budget/Kconfig" source "drivers/media/dvb/ttusb-dec/Kconfig" source "drivers/media/dvb/cinergyT2/Kconfig" +source "drivers/media/dvb/siano/Kconfig" comment "Supported FlexCopII (B2C2) Adapters" depends on DVB_CORE && (PCI || USB) && I2C diff --git a/drivers/media/dvb/Makefile b/drivers/media/dvb/Makefile index a7ad0841e6fc..d6ba4d195201 100644 --- a/drivers/media/dvb/Makefile +++ b/drivers/media/dvb/Makefile @@ -2,4 +2,4 @@ # Makefile for the kernel multimedia device drivers. # -obj-y := dvb-core/ frontends/ ttpci/ ttusb-dec/ ttusb-budget/ b2c2/ bt8xx/ cinergyT2/ dvb-usb/ pluto2/ +obj-y := dvb-core/ frontends/ ttpci/ ttusb-dec/ ttusb-budget/ b2c2/ bt8xx/ cinergyT2/ dvb-usb/ pluto2/ siano/ diff --git a/drivers/media/dvb/bt8xx/bt878.h b/drivers/media/dvb/bt8xx/bt878.h index 375fd2892a11..d19b59299d78 100644 --- a/drivers/media/dvb/bt8xx/bt878.h +++ b/drivers/media/dvb/bt8xx/bt878.h @@ -128,7 +128,7 @@ struct bt878 { dma_addr_t buf_dma; u32 risc_size; - u32 *risc_cpu; + __le32 *risc_cpu; dma_addr_t risc_dma; u32 risc_pos; diff --git a/drivers/media/dvb/dvb-core/demux.h b/drivers/media/dvb/dvb-core/demux.h index b0d347daae47..eb91fd808c16 100644 --- a/drivers/media/dvb/dvb-core/demux.h +++ b/drivers/media/dvb/dvb-core/demux.h @@ -247,7 +247,7 @@ struct dmx_demux { void* priv; /* Pointer to private data of the API client */ int (*open) (struct dmx_demux* demux); int (*close) (struct dmx_demux* demux); - int (*write) (struct dmx_demux* demux, const char* buf, size_t count); + int (*write) (struct dmx_demux* demux, const char __user *buf, size_t count); int (*allocate_ts_feed) (struct dmx_demux* demux, struct dmx_ts_feed** feed, dmx_ts_cb callback); diff --git a/drivers/media/dvb/dvb-core/dmxdev.c b/drivers/media/dvb/dvb-core/dmxdev.c index df5bef6a2517..1cf9fcb6f514 100644 --- a/drivers/media/dvb/dvb-core/dmxdev.c +++ b/drivers/media/dvb/dvb-core/dmxdev.c @@ -96,7 +96,7 @@ static ssize_t dvb_dmxdev_buffer_read(struct dvb_ringbuffer *src, if (avail > todo) avail = todo; - ret = dvb_ringbuffer_read(src, (u8 *)buf, avail, 1); + ret = dvb_ringbuffer_read_user(src, buf, avail); if (ret < 0) break; diff --git a/drivers/media/dvb/dvb-core/dvb_ca_en50221.c b/drivers/media/dvb/dvb-core/dvb_ca_en50221.c index 588fbe105c27..8e5dd7b1f034 100644 --- a/drivers/media/dvb/dvb-core/dvb_ca_en50221.c +++ b/drivers/media/dvb/dvb-core/dvb_ca_en50221.c @@ -1357,7 +1357,7 @@ static int dvb_ca_en50221_io_read_condition(struct dvb_ca_private *ca, idx = dvb_ringbuffer_pkt_next(&ca->slot_info[slot].rx_buffer, -1, &fraglen); while (idx != -1) { - dvb_ringbuffer_pkt_read(&ca->slot_info[slot].rx_buffer, idx, 0, hdr, 2, 0); + dvb_ringbuffer_pkt_read(&ca->slot_info[slot].rx_buffer, idx, 0, hdr, 2); if (connection_id == -1) connection_id = hdr[0]; if ((hdr[0] == connection_id) && ((hdr[1] & 0x80) == 0)) { @@ -1438,7 +1438,7 @@ static ssize_t dvb_ca_en50221_io_read(struct file *file, char __user * buf, goto exit; } - dvb_ringbuffer_pkt_read(&ca->slot_info[slot].rx_buffer, idx, 0, hdr, 2, 0); + dvb_ringbuffer_pkt_read(&ca->slot_info[slot].rx_buffer, idx, 0, hdr, 2); if (connection_id == -1) connection_id = hdr[0]; if (hdr[0] == connection_id) { @@ -1449,8 +1449,8 @@ static ssize_t dvb_ca_en50221_io_read(struct file *file, char __user * buf, fraglen -= 2; } - if ((status = dvb_ringbuffer_pkt_read(&ca->slot_info[slot].rx_buffer, idx, 2, - (u8 *)buf + pktlen, fraglen, 1)) < 0) { + if ((status = dvb_ringbuffer_pkt_read_user(&ca->slot_info[slot].rx_buffer, idx, 2, + buf + pktlen, fraglen)) < 0) { goto exit; } pktlen += fraglen; diff --git a/drivers/media/dvb/dvb-core/dvb_demux.c b/drivers/media/dvb/dvb-core/dvb_demux.c index 934e15fffc56..e2eca0b1fe7c 100644 --- a/drivers/media/dvb/dvb-core/dvb_demux.c +++ b/drivers/media/dvb/dvb-core/dvb_demux.c @@ -1056,16 +1056,27 @@ static int dvbdmx_close(struct dmx_demux *demux) return 0; } -static int dvbdmx_write(struct dmx_demux *demux, const char *buf, size_t count) +static int dvbdmx_write(struct dmx_demux *demux, const char __user *buf, size_t count) { struct dvb_demux *dvbdemux = (struct dvb_demux *)demux; + void *p; if ((!demux->frontend) || (demux->frontend->source != DMX_MEMORY_FE)) return -EINVAL; - if (mutex_lock_interruptible(&dvbdemux->mutex)) + p = kmalloc(count, GFP_USER); + if (!p) + return -ENOMEM; + if (copy_from_user(p, buf, count)) { + kfree(p); + return -EFAULT; + } + if (mutex_lock_interruptible(&dvbdemux->mutex)) { + kfree(p); return -ERESTARTSYS; - dvb_dmx_swfilter(dvbdemux, (u8 *)buf, count); + } + dvb_dmx_swfilter(dvbdemux, p, count); + kfree(p); mutex_unlock(&dvbdemux->mutex); if (signal_pending(current)) diff --git a/drivers/media/dvb/dvb-core/dvb_net.c b/drivers/media/dvb/dvb-core/dvb_net.c index c2334aef4143..c93019ca519e 100644 --- a/drivers/media/dvb/dvb-core/dvb_net.c +++ b/drivers/media/dvb/dvb-core/dvb_net.c @@ -606,7 +606,7 @@ static void dvb_net_ule( struct net_device *dev, const u8 *buf, size_t buf_len ) if (priv->ule_dbit) { /* Set D-bit for CRC32 verification, * if it was set originally. */ - ulen |= 0x0080; + ulen |= htons(0x8000); } ule_crc = iov_crc32(ule_crc, iov, 3); @@ -1133,7 +1133,7 @@ static void wq_set_multicast_list (struct work_struct *work) dvb_net_feed_stop(dev); priv->rx_mode = RX_MODE_UNI; - netif_tx_lock_bh(dev); + netif_addr_lock_bh(dev); if (dev->flags & IFF_PROMISC) { dprintk("%s: promiscuous mode\n", dev->name); @@ -1158,7 +1158,7 @@ static void wq_set_multicast_list (struct work_struct *work) } } - netif_tx_unlock_bh(dev); + netif_addr_unlock_bh(dev); dvb_net_feed_start(dev); } diff --git a/drivers/media/dvb/dvb-core/dvb_ringbuffer.c b/drivers/media/dvb/dvb-core/dvb_ringbuffer.c index 872985b7912d..584bbd194dc8 100644 --- a/drivers/media/dvb/dvb-core/dvb_ringbuffer.c +++ b/drivers/media/dvb/dvb-core/dvb_ringbuffer.c @@ -107,35 +107,43 @@ void dvb_ringbuffer_flush_spinlock_wakeup(struct dvb_ringbuffer *rbuf) wake_up(&rbuf->queue); } - - -ssize_t dvb_ringbuffer_read(struct dvb_ringbuffer *rbuf, u8 *buf, size_t len, int usermem) +ssize_t dvb_ringbuffer_read_user(struct dvb_ringbuffer *rbuf, u8 __user *buf, size_t len) { size_t todo = len; size_t split; split = (rbuf->pread + len > rbuf->size) ? rbuf->size - rbuf->pread : 0; if (split > 0) { - if (!usermem) - memcpy(buf, rbuf->data+rbuf->pread, split); - else - if (copy_to_user(buf, rbuf->data+rbuf->pread, split)) - return -EFAULT; + if (copy_to_user(buf, rbuf->data+rbuf->pread, split)) + return -EFAULT; buf += split; todo -= split; rbuf->pread = 0; } - if (!usermem) - memcpy(buf, rbuf->data+rbuf->pread, todo); - else - if (copy_to_user(buf, rbuf->data+rbuf->pread, todo)) - return -EFAULT; + if (copy_to_user(buf, rbuf->data+rbuf->pread, todo)) + return -EFAULT; rbuf->pread = (rbuf->pread + todo) % rbuf->size; return len; } +void dvb_ringbuffer_read(struct dvb_ringbuffer *rbuf, u8 *buf, size_t len) +{ + size_t todo = len; + size_t split; + + split = (rbuf->pread + len > rbuf->size) ? rbuf->size - rbuf->pread : 0; + if (split > 0) { + memcpy(buf, rbuf->data+rbuf->pread, split); + buf += split; + todo -= split; + rbuf->pread = 0; + } + memcpy(buf, rbuf->data+rbuf->pread, todo); + + rbuf->pread = (rbuf->pread + todo) % rbuf->size; +} ssize_t dvb_ringbuffer_write(struct dvb_ringbuffer *rbuf, const u8 *buf, size_t len) @@ -171,8 +179,8 @@ ssize_t dvb_ringbuffer_pkt_write(struct dvb_ringbuffer *rbuf, u8* buf, size_t le return status; } -ssize_t dvb_ringbuffer_pkt_read(struct dvb_ringbuffer *rbuf, size_t idx, - int offset, u8* buf, size_t len, int usermem) +ssize_t dvb_ringbuffer_pkt_read_user(struct dvb_ringbuffer *rbuf, size_t idx, + int offset, u8 __user *buf, size_t len) { size_t todo; size_t split; @@ -187,21 +195,40 @@ ssize_t dvb_ringbuffer_pkt_read(struct dvb_ringbuffer *rbuf, size_t idx, todo = len; split = ((idx + len) > rbuf->size) ? rbuf->size - idx : 0; if (split > 0) { - if (!usermem) - memcpy(buf, rbuf->data+idx, split); - else - if (copy_to_user(buf, rbuf->data+idx, split)) - return -EFAULT; + if (copy_to_user(buf, rbuf->data+idx, split)) + return -EFAULT; buf += split; todo -= split; idx = 0; } - if (!usermem) - memcpy(buf, rbuf->data+idx, todo); - else - if (copy_to_user(buf, rbuf->data+idx, todo)) - return -EFAULT; + if (copy_to_user(buf, rbuf->data+idx, todo)) + return -EFAULT; + + return len; +} +ssize_t dvb_ringbuffer_pkt_read(struct dvb_ringbuffer *rbuf, size_t idx, + int offset, u8* buf, size_t len) +{ + size_t todo; + size_t split; + size_t pktlen; + + pktlen = rbuf->data[idx] << 8; + pktlen |= rbuf->data[(idx + 1) % rbuf->size]; + if (offset > pktlen) return -EINVAL; + if ((offset + len) > pktlen) len = pktlen - offset; + + idx = (idx + DVB_RINGBUFFER_PKTHDRSIZE + offset) % rbuf->size; + todo = len; + split = ((idx + len) > rbuf->size) ? rbuf->size - idx : 0; + if (split > 0) { + memcpy(buf, rbuf->data+idx, split); + buf += split; + todo -= split; + idx = 0; + } + memcpy(buf, rbuf->data+idx, todo); return len; } @@ -266,5 +293,6 @@ EXPORT_SYMBOL(dvb_ringbuffer_empty); EXPORT_SYMBOL(dvb_ringbuffer_free); EXPORT_SYMBOL(dvb_ringbuffer_avail); EXPORT_SYMBOL(dvb_ringbuffer_flush_spinlock_wakeup); +EXPORT_SYMBOL(dvb_ringbuffer_read_user); EXPORT_SYMBOL(dvb_ringbuffer_read); EXPORT_SYMBOL(dvb_ringbuffer_write); diff --git a/drivers/media/dvb/dvb-core/dvb_ringbuffer.h b/drivers/media/dvb/dvb-core/dvb_ringbuffer.h index 890826262966..41f04dae69b6 100644 --- a/drivers/media/dvb/dvb-core/dvb_ringbuffer.h +++ b/drivers/media/dvb/dvb-core/dvb_ringbuffer.h @@ -61,7 +61,7 @@ struct dvb_ringbuffer { ** *** read min. 1000, max. <bufsize> bytes *** ** avail = dvb_ringbuffer_avail(rbuf); ** if (avail >= 1000) -** count = dvb_ringbuffer_read(rbuf, buffer, min(avail, bufsize), 0); +** count = dvb_ringbuffer_read(rbuf, buffer, min(avail, bufsize)); ** else ** ... ** @@ -114,8 +114,10 @@ extern void dvb_ringbuffer_flush_spinlock_wakeup(struct dvb_ringbuffer *rbuf); ** <usermem> specifies whether <buf> resides in user space ** returns number of bytes transferred or -EFAULT */ -extern ssize_t dvb_ringbuffer_read(struct dvb_ringbuffer *rbuf, u8 *buf, - size_t len, int usermem); +extern ssize_t dvb_ringbuffer_read_user(struct dvb_ringbuffer *rbuf, + u8 __user *buf, size_t len); +extern void dvb_ringbuffer_read(struct dvb_ringbuffer *rbuf, + u8 *buf, size_t len); /* write routines & macros */ @@ -157,8 +159,10 @@ extern ssize_t dvb_ringbuffer_pkt_write(struct dvb_ringbuffer *rbuf, u8* buf, * <usermem> Set to 1 if <buf> is in userspace. * returns Number of bytes read, or -EFAULT. */ +extern ssize_t dvb_ringbuffer_pkt_read_user(struct dvb_ringbuffer *rbuf, size_t idx, + int offset, u8 __user *buf, size_t len); extern ssize_t dvb_ringbuffer_pkt_read(struct dvb_ringbuffer *rbuf, size_t idx, - int offset, u8* buf, size_t len, int usermem); + int offset, u8 *buf, size_t len); /** * Dispose of a packet in the ring buffer. diff --git a/drivers/media/dvb/dvb-usb/Kconfig b/drivers/media/dvb/dvb-usb/Kconfig index f00a0eb40420..a577c0f89f67 100644 --- a/drivers/media/dvb/dvb-usb/Kconfig +++ b/drivers/media/dvb/dvb-usb/Kconfig @@ -76,6 +76,7 @@ config DVB_USB_DIB0700 select DVB_DIB3000MC select MEDIA_TUNER_MT2060 if !DVB_FE_CUSTOMISE select MEDIA_TUNER_MT2266 if !DVB_FE_CUSTOMISE + select MEDIA_TUNER_XC2028 if !DVB_FE_CUSTOMISE select DVB_TUNER_DIB0070 help Support for USB2.0/1.1 DVB receivers based on the DiB0700 USB bridge. The @@ -107,6 +108,8 @@ config DVB_USB_CXUSB select DVB_MT352 if !DVB_FE_CUSTOMISE select DVB_ZL10353 if !DVB_FE_CUSTOMISE select MEDIA_TUNER_SIMPLE if !DVB_FE_CUSTOMISE + select MEDIA_TUNER_XC2028 if !DVB_FE_CUSTOMISE + select MEDIA_TUNER_MXL5005S if !DVB_FE_CUSTOMISE help Say Y here to support the Conexant USB2.0 hybrid reference design. Currently, only DVB and ATSC modes are supported, analog mode @@ -120,6 +123,8 @@ config DVB_USB_M920X depends on DVB_USB select DVB_MT352 if !DVB_FE_CUSTOMISE select MEDIA_TUNER_QT1010 if !DVB_FE_CUSTOMISE + select MEDIA_TUNER_TDA827X if !DVB_FE_CUSTOMISE + select DVB_TDA1004X if !DVB_FE_CUSTOMISE help Say Y here to support the MSI Mega Sky 580 USB2.0 DVB-T receiver. Currently, only devices with a product id of @@ -241,3 +246,13 @@ config DVB_USB_AF9005_REMOTE Say Y here to support the default remote control decoding for the Afatech AF9005 based receiver. +config DVB_USB_ANYSEE + tristate "Anysee DVB-T/C USB2.0 support" + depends on DVB_USB + select DVB_PLL if !DVB_FE_CUSTOMISE + select DVB_MT352 if !DVB_FE_CUSTOMISE + select DVB_ZL10353 if !DVB_FE_CUSTOMISE + select DVB_TDA10023 if !DVB_FE_CUSTOMISE + help + Say Y here to support the Anysee E30, Anysee E30 Plus or + Anysee E30 C Plus DVB USB2.0 receiver. diff --git a/drivers/media/dvb/dvb-usb/Makefile b/drivers/media/dvb/dvb-usb/Makefile index c6511a6c0ab8..44c11e45e564 100644 --- a/drivers/media/dvb/dvb-usb/Makefile +++ b/drivers/media/dvb/dvb-usb/Makefile @@ -61,6 +61,9 @@ obj-$(CONFIG_DVB_USB_AF9005) += dvb-usb-af9005.o dvb-usb-af9005-remote-objs = af9005-remote.o obj-$(CONFIG_DVB_USB_AF9005_REMOTE) += dvb-usb-af9005-remote.o +dvb-usb-anysee-objs = anysee.o +obj-$(CONFIG_DVB_USB_ANYSEE) += dvb-usb-anysee.o + EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/ # due to tuner-xc3028 EXTRA_CFLAGS += -Idrivers/media/common/tuners diff --git a/drivers/media/dvb/dvb-usb/anysee.c b/drivers/media/dvb/dvb-usb/anysee.c new file mode 100644 index 000000000000..adfd4fc82efd --- /dev/null +++ b/drivers/media/dvb/dvb-usb/anysee.c @@ -0,0 +1,553 @@ +/* + * DVB USB Linux driver for Anysee E30 DVB-C & DVB-T USB2.0 receiver + * + * Copyright (C) 2007 Antti Palosaari <crope@iki.fi> + * + * 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. + * + * TODO: + * - add smart card reader support for Conditional Access (CA) + * + * Card reader in Anysee is nothing more than ISO 7816 card reader. + * There is no hardware CAM in any Anysee device sold. + * In my understanding it should be implemented by making own module + * for ISO 7816 card reader, like dvb_ca_en50221 is implemented. This + * module registers serial interface that can be used to communicate + * with any ISO 7816 smart card. + * + * Any help according to implement serial smart card reader support + * is highly welcome! + */ + +#include "anysee.h" +#include "tda1002x.h" +#include "mt352.h" +#include "mt352_priv.h" +#include "zl10353.h" + +/* debug */ +static int dvb_usb_anysee_debug; +module_param_named(debug, dvb_usb_anysee_debug, int, 0644); +MODULE_PARM_DESC(debug, "set debugging level" DVB_USB_DEBUG_STATUS); +DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); + +struct mutex anysee_usb_mutex; + +static int anysee_ctrl_msg(struct dvb_usb_device *d, u8 *sbuf, u8 slen, + u8 *rbuf, u8 rlen) +{ + struct anysee_state *state = d->priv; + int act_len, ret; + u8 buf[64]; + + if (slen > sizeof(buf)) + slen = sizeof(buf); + memcpy(&buf[0], sbuf, slen); + buf[60] = state->seq++; + + if (mutex_lock_interruptible(&anysee_usb_mutex) < 0) + return -EAGAIN; + + /* We need receive one message more after dvb_usb_generic_rw due + to weird transaction flow, which is 1 x send + 2 x receive. */ + ret = dvb_usb_generic_rw(d, buf, sizeof(buf), buf, sizeof(buf), 0); + + if (!ret) { + /* receive 2nd answer */ + ret = usb_bulk_msg(d->udev, usb_rcvbulkpipe(d->udev, + d->props.generic_bulk_ctrl_endpoint), buf, sizeof(buf), + &act_len, 2000); + if (ret) + err("%s: recv bulk message failed: %d", __func__, ret); + else { + deb_xfer("<<< "); + debug_dump(buf, act_len, deb_xfer); + } + } + + /* read request, copy returned data to return buf */ + if (!ret && rbuf && rlen) + memcpy(rbuf, buf, rlen); + + mutex_unlock(&anysee_usb_mutex); + + return ret; +} + +static int anysee_read_reg(struct dvb_usb_device *d, u16 reg, u8 *val) +{ + u8 buf[] = {CMD_REG_READ, reg >> 8, reg & 0xff, 0x01}; + int ret; + ret = anysee_ctrl_msg(d, buf, sizeof(buf), val, 1); + deb_info("%s: reg:%04x val:%02x\n", __func__, reg, *val); + return ret; +} + +static int anysee_write_reg(struct dvb_usb_device *d, u16 reg, u8 val) +{ + u8 buf[] = {CMD_REG_WRITE, reg >> 8, reg & 0xff, 0x01, val}; + deb_info("%s: reg:%04x val:%02x\n", __func__, reg, val); + return anysee_ctrl_msg(d, buf, sizeof(buf), NULL, 0); +} + +static int anysee_get_hw_info(struct dvb_usb_device *d, u8 *id) +{ + u8 buf[] = {CMD_GET_HW_INFO}; + return anysee_ctrl_msg(d, buf, sizeof(buf), id, 3); +} + +static int anysee_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff) +{ + u8 buf[] = {CMD_STREAMING_CTRL, (u8)onoff, 0x00}; + deb_info("%s: onoff:%02x\n", __func__, onoff); + return anysee_ctrl_msg(adap->dev, buf, sizeof(buf), NULL, 0); +} + +static int anysee_led_ctrl(struct dvb_usb_device *d, u8 mode, u8 interval) +{ + u8 buf[] = {CMD_LED_AND_IR_CTRL, 0x01, mode, interval}; + deb_info("%s: state:%02x interval:%02x\n", __func__, mode, interval); + return anysee_ctrl_msg(d, buf, sizeof(buf), NULL, 0); +} + +static int anysee_ir_ctrl(struct dvb_usb_device *d, u8 onoff) +{ + u8 buf[] = {CMD_LED_AND_IR_CTRL, 0x02, onoff}; + deb_info("%s: onoff:%02x\n", __func__, onoff); + return anysee_ctrl_msg(d, buf, sizeof(buf), NULL, 0); +} + +static int anysee_init(struct dvb_usb_device *d) +{ + int ret; + /* LED light */ + ret = anysee_led_ctrl(d, 0x01, 0x03); + if (ret) + return ret; + + /* enable IR */ + ret = anysee_ir_ctrl(d, 1); + if (ret) + return ret; + + return 0; +} + +/* I2C */ +static int anysee_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msg, + int num) +{ + struct dvb_usb_device *d = i2c_get_adapdata(adap); + int ret, inc, i = 0; + + if (mutex_lock_interruptible(&d->i2c_mutex) < 0) + return -EAGAIN; + + while (i < num) { + if (num > i + 1 && (msg[i+1].flags & I2C_M_RD)) { + u8 buf[6]; + buf[0] = CMD_I2C_READ; + buf[1] = msg[i].addr + 1; + buf[2] = msg[i].buf[0]; + buf[3] = 0x00; + buf[4] = 0x00; + buf[5] = 0x01; + ret = anysee_ctrl_msg(d, buf, sizeof(buf), msg[i+1].buf, + msg[i+1].len); + inc = 2; + } else { + u8 buf[4+msg[i].len]; + buf[0] = CMD_I2C_WRITE; + buf[1] = msg[i].addr; + buf[2] = msg[i].len; + buf[3] = 0x01; + memcpy(&buf[4], msg[i].buf, msg[i].len); + ret = anysee_ctrl_msg(d, buf, sizeof(buf), NULL, 0); + inc = 1; + } + if (ret) + return ret; + + i += inc; + } + + mutex_unlock(&d->i2c_mutex); + + return i; +} + +static u32 anysee_i2c_func(struct i2c_adapter *adapter) +{ + return I2C_FUNC_I2C; +} + +static struct i2c_algorithm anysee_i2c_algo = { + .master_xfer = anysee_master_xfer, + .functionality = anysee_i2c_func, +}; + +static int anysee_mt352_demod_init(struct dvb_frontend *fe) +{ + static u8 clock_config [] = { CLOCK_CTL, 0x38, 0x28 }; + static u8 reset [] = { RESET, 0x80 }; + static u8 adc_ctl_1_cfg [] = { ADC_CTL_1, 0x40 }; + static u8 agc_cfg [] = { AGC_TARGET, 0x28, 0x20 }; + static u8 gpp_ctl_cfg [] = { GPP_CTL, 0x33 }; + static u8 capt_range_cfg[] = { CAPT_RANGE, 0x32 }; + + mt352_write(fe, clock_config, sizeof(clock_config)); + udelay(200); + mt352_write(fe, reset, sizeof(reset)); + mt352_write(fe, adc_ctl_1_cfg, sizeof(adc_ctl_1_cfg)); + + mt352_write(fe, agc_cfg, sizeof(agc_cfg)); + mt352_write(fe, gpp_ctl_cfg, sizeof(gpp_ctl_cfg)); + mt352_write(fe, capt_range_cfg, sizeof(capt_range_cfg)); + + return 0; +} + +/* Callbacks for DVB USB */ +static struct tda10023_config anysee_tda10023_config = { + .demod_address = 0x1a, + .invert = 0, + .xtal = 16000000, + .pll_m = 11, + .pll_p = 3, + .pll_n = 1, + .output_mode = TDA10023_OUTPUT_MODE_PARALLEL_C, + .deltaf = 0xfeeb, +}; + +static struct mt352_config anysee_mt352_config = { + .demod_address = 0x1e, + .demod_init = anysee_mt352_demod_init, +}; + +static struct zl10353_config anysee_zl10353_config = { + .demod_address = 0x1e, + .parallel_ts = 1, +}; + +static int anysee_frontend_attach(struct dvb_usb_adapter *adap) +{ + int ret; + struct anysee_state *state = adap->dev->priv; + u8 hw_info[3]; + u8 io_d; /* IO port D */ + + /* check which hardware we have + We must do this call two times to get reliable values (hw bug). */ + ret = anysee_get_hw_info(adap->dev, hw_info); + if (ret) + return ret; + ret = anysee_get_hw_info(adap->dev, hw_info); + if (ret) + return ret; + + /* Meaning of these info bytes are guessed. */ + info("firmware version:%d.%d.%d hardware id:%d", + 0, hw_info[1], hw_info[2], hw_info[0]); + + ret = anysee_read_reg(adap->dev, 0xb0, &io_d); /* IO port D */ + if (ret) + return ret; + deb_info("%s: IO port D:%02x\n", __func__, io_d); + + /* Select demod using trial and error method. */ + + /* Try to attach demodulator in following order: + model demod hw firmware + 1. E30 MT352 02 0.2.1 + 2. E30 ZL10353 02 0.2.1 + 3. E30 Plus ZL10353 06 0.1.0 + 4. E30C Plus TDA10023 0a 0.1.0 rev 0.2 + 4. E30C Plus TDA10023 0f 0.1.2 rev 0.4 + */ + + /* Zarlink MT352 DVB-T demod inside of Samsung DNOS404ZH102A NIM */ + adap->fe = dvb_attach(mt352_attach, &anysee_mt352_config, + &adap->dev->i2c_adap); + if (adap->fe != NULL) { + state->tuner = DVB_PLL_THOMSON_DTT7579; + return 0; + } + + /* Zarlink ZL10353 DVB-T demod inside of Samsung DNOS404ZH103A NIM */ + adap->fe = dvb_attach(zl10353_attach, &anysee_zl10353_config, + &adap->dev->i2c_adap); + if (adap->fe != NULL) { + state->tuner = DVB_PLL_THOMSON_DTT7579; + return 0; + } + + /* connect demod on IO port D for TDA10023 & ZL10353 */ + ret = anysee_write_reg(adap->dev, 0xb0, 0x25); + if (ret) + return ret; + + /* Zarlink ZL10353 DVB-T demod inside of Samsung DNOS404ZH103A NIM */ + adap->fe = dvb_attach(zl10353_attach, &anysee_zl10353_config, + &adap->dev->i2c_adap); + if (adap->fe != NULL) { + state->tuner = DVB_PLL_THOMSON_DTT7579; + return 0; + } + + /* IO port E - E30C rev 0.4 board requires this */ + ret = anysee_write_reg(adap->dev, 0xb1, 0xa7); + if (ret) + return ret; + + /* Philips TDA10023 DVB-C demod */ + adap->fe = dvb_attach(tda10023_attach, &anysee_tda10023_config, + &adap->dev->i2c_adap, 0x48); + if (adap->fe != NULL) { + state->tuner = DVB_PLL_SAMSUNG_DTOS403IH102A; + return 0; + } + + /* return IO port D to init value for safe */ + ret = anysee_write_reg(adap->dev, 0xb0, io_d); + if (ret) + return ret; + + err("Unkown Anysee version: %02x %02x %02x. "\ + "Please report the <linux-dvb@linuxtv.org>.", + hw_info[0], hw_info[1], hw_info[2]); + + return -ENODEV; +} + +static int anysee_tuner_attach(struct dvb_usb_adapter *adap) +{ + struct anysee_state *state = adap->dev->priv; + deb_info("%s: \n", __func__); + + switch (state->tuner) { + case DVB_PLL_THOMSON_DTT7579: + /* Thomson dtt7579 (not sure) PLL inside of: + Samsung DNOS404ZH102A NIM + Samsung DNOS404ZH103A NIM */ + dvb_attach(dvb_pll_attach, adap->fe, 0x61, + NULL, DVB_PLL_THOMSON_DTT7579); + break; + case DVB_PLL_SAMSUNG_DTOS403IH102A: + /* Unknown PLL inside of Samsung DTOS403IH102A tuner module */ + dvb_attach(dvb_pll_attach, adap->fe, 0xc0, + &adap->dev->i2c_adap, DVB_PLL_SAMSUNG_DTOS403IH102A); + break; + } + + return 0; +} + +static int anysee_rc_query(struct dvb_usb_device *d, u32 *event, int *state) +{ + u8 buf[] = {CMD_GET_IR_CODE}; + struct dvb_usb_rc_key *keymap = d->props.rc_key_map; + u8 ircode[2]; + int i, ret; + + ret = anysee_ctrl_msg(d, buf, sizeof(buf), &ircode[0], 2); + if (ret) + return ret; + + *event = 0; + *state = REMOTE_NO_KEY_PRESSED; + + for (i = 0; i < d->props.rc_key_map_size; i++) { + if (keymap[i].custom == ircode[0] && + keymap[i].data == ircode[1]) { + *event = keymap[i].event; + *state = REMOTE_KEY_PRESSED; + return 0; + } + } + return 0; +} + +static struct dvb_usb_rc_key anysee_rc_keys[] = { + { 0x01, 0x00, KEY_0 }, + { 0x01, 0x01, KEY_1 }, + { 0x01, 0x02, KEY_2 }, + { 0x01, 0x03, KEY_3 }, + { 0x01, 0x04, KEY_4 }, + { 0x01, 0x05, KEY_5 }, + { 0x01, 0x06, KEY_6 }, + { 0x01, 0x07, KEY_7 }, + { 0x01, 0x08, KEY_8 }, + { 0x01, 0x09, KEY_9 }, + { 0x01, 0x0a, KEY_POWER }, + { 0x01, 0x0b, KEY_DOCUMENTS }, /* * */ + { 0x01, 0x19, KEY_FAVORITES }, + { 0x01, 0x20, KEY_SLEEP }, + { 0x01, 0x21, KEY_MODE }, /* 4:3 / 16:9 select */ + { 0x01, 0x22, KEY_ZOOM }, + { 0x01, 0x47, KEY_TEXT }, + { 0x01, 0x16, KEY_TV }, /* TV / radio select */ + { 0x01, 0x1e, KEY_LANGUAGE }, /* Second Audio Program */ + { 0x01, 0x1a, KEY_SUBTITLE }, + { 0x01, 0x1b, KEY_CAMERA }, /* screenshot */ + { 0x01, 0x42, KEY_MUTE }, + { 0x01, 0x0e, KEY_MENU }, + { 0x01, 0x0f, KEY_EPG }, + { 0x01, 0x17, KEY_INFO }, + { 0x01, 0x10, KEY_EXIT }, + { 0x01, 0x13, KEY_VOLUMEUP }, + { 0x01, 0x12, KEY_VOLUMEDOWN }, + { 0x01, 0x11, KEY_CHANNELUP }, + { 0x01, 0x14, KEY_CHANNELDOWN }, + { 0x01, 0x15, KEY_OK }, + { 0x01, 0x1d, KEY_RED }, + { 0x01, 0x1f, KEY_GREEN }, + { 0x01, 0x1c, KEY_YELLOW }, + { 0x01, 0x44, KEY_BLUE }, + { 0x01, 0x0c, KEY_SHUFFLE }, /* snapshot */ + { 0x01, 0x48, KEY_STOP }, + { 0x01, 0x50, KEY_PLAY }, + { 0x01, 0x51, KEY_PAUSE }, + { 0x01, 0x49, KEY_RECORD }, + { 0x01, 0x18, KEY_PREVIOUS }, /* |<< */ + { 0x01, 0x0d, KEY_NEXT }, /* >>| */ + { 0x01, 0x24, KEY_PROG1 }, /* F1 */ + { 0x01, 0x25, KEY_PROG2 }, /* F2 */ +}; + +/* DVB USB Driver stuff */ +static struct dvb_usb_device_properties anysee_properties; + +static int anysee_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + struct dvb_usb_device *d; + struct usb_host_interface *alt; + int ret; + + mutex_init(&anysee_usb_mutex); + + /* There is one interface with two alternate settings. + Alternate setting 0 is for bulk transfer. + Alternate setting 1 is for isochronous transfer. + We use bulk transfer (alternate setting 0). */ + if (intf->num_altsetting < 1) + return -ENODEV; + + ret = dvb_usb_device_init(intf, &anysee_properties, THIS_MODULE, &d, + adapter_nr); + if (ret) + return ret; + + alt = usb_altnum_to_altsetting(intf, 0); + if (alt == NULL) { + deb_info("%s: no alt found!\n", __func__); + return -ENODEV; + } + + ret = usb_set_interface(d->udev, alt->desc.bInterfaceNumber, + alt->desc.bAlternateSetting); + if (ret) + return ret; + + if (d) + ret = anysee_init(d); + + return ret; +} + +static struct usb_device_id anysee_table [] = { + { USB_DEVICE(USB_VID_CYPRESS, USB_PID_ANYSEE) }, + { USB_DEVICE(USB_VID_AMT, USB_PID_ANYSEE) }, + { } /* Terminating entry */ +}; +MODULE_DEVICE_TABLE(usb, anysee_table); + +static struct dvb_usb_device_properties anysee_properties = { + .caps = DVB_USB_IS_AN_I2C_ADAPTER, + + .usb_ctrl = DEVICE_SPECIFIC, + + .size_of_priv = sizeof(struct anysee_state), + + .num_adapters = 1, + .adapter = { + { + .streaming_ctrl = anysee_streaming_ctrl, + .frontend_attach = anysee_frontend_attach, + .tuner_attach = anysee_tuner_attach, + .stream = { + .type = USB_BULK, + .count = 8, + .endpoint = 0x82, + .u = { + .bulk = { + .buffersize = 512, + } + } + }, + } + }, + + .rc_key_map = anysee_rc_keys, + .rc_key_map_size = ARRAY_SIZE(anysee_rc_keys), + .rc_query = anysee_rc_query, + .rc_interval = 200, /* windows driver uses 500ms */ + + .i2c_algo = &anysee_i2c_algo, + + .generic_bulk_ctrl_endpoint = 1, + + .num_device_descs = 1, + .devices = { + { + .name = "Anysee DVB USB2.0", + .cold_ids = {NULL}, + .warm_ids = {&anysee_table[0], + &anysee_table[1], NULL}, + }, + } +}; + +static struct usb_driver anysee_driver = { + .name = "dvb_usb_anysee", + .probe = anysee_probe, + .disconnect = dvb_usb_device_exit, + .id_table = anysee_table, +}; + +/* module stuff */ +static int __init anysee_module_init(void) +{ + int ret; + + ret = usb_register(&anysee_driver); + if (ret) + err("%s: usb_register failed. Error number %d", __func__, ret); + + return ret; +} + +static void __exit anysee_module_exit(void) +{ + /* deregister this driver from the USB subsystem */ + usb_deregister(&anysee_driver); +} + +module_init(anysee_module_init); +module_exit(anysee_module_exit); + +MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>"); +MODULE_DESCRIPTION("Driver Anysee E30 DVB-C & DVB-T USB2.0"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb/dvb-usb/anysee.h b/drivers/media/dvb/dvb-usb/anysee.h new file mode 100644 index 000000000000..7ca01ff6e13c --- /dev/null +++ b/drivers/media/dvb/dvb-usb/anysee.h @@ -0,0 +1,304 @@ +/* + * DVB USB Linux driver for Anysee E30 DVB-C & DVB-T USB2.0 receiver + * + * Copyright (C) 2007 Antti Palosaari <crope@iki.fi> + * + * 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. + * + * TODO: + * - add smart card reader support for Conditional Access (CA) + * + * Card reader in Anysee is nothing more than ISO 7816 card reader. + * There is no hardware CAM in any Anysee device sold. + * In my understanding it should be implemented by making own module + * for ISO 7816 card reader, like dvb_ca_en50221 is implemented. This + * module registers serial interface that can be used to communicate + * with any ISO 7816 smart card. + * + * Any help according to implement serial smart card reader support + * is highly welcome! + */ + +#ifndef _DVB_USB_ANYSEE_H_ +#define _DVB_USB_ANYSEE_H_ + +#define DVB_USB_LOG_PREFIX "anysee" +#include "dvb-usb.h" + +#define deb_info(args...) dprintk(dvb_usb_anysee_debug, 0x01, args) +#define deb_xfer(args...) dprintk(dvb_usb_anysee_debug, 0x02, args) +#define deb_rc(args...) dprintk(dvb_usb_anysee_debug, 0x04, args) +#define deb_reg(args...) dprintk(dvb_usb_anysee_debug, 0x08, args) +#define deb_i2c(args...) dprintk(dvb_usb_anysee_debug, 0x10, args) +#define deb_fw(args...) dprintk(dvb_usb_anysee_debug, 0x20, args) + +enum cmd { + CMD_I2C_READ = 0x33, + CMD_I2C_WRITE = 0x31, + CMD_REG_READ = 0xb0, + CMD_REG_WRITE = 0xb1, + CMD_STREAMING_CTRL = 0x12, + CMD_LED_AND_IR_CTRL = 0x16, + CMD_GET_IR_CODE = 0x41, + CMD_GET_HW_INFO = 0x19, + CMD_SMARTCARD = 0x34, +}; + +struct anysee_state { + u8 tuner; + u8 seq; +}; + +#endif + +/*************************************************************************** + * USB API description (reverse engineered) + *************************************************************************** + +Transaction flow: +================= +BULK[00001] >>> REQUEST PACKET 64 bytes +BULK[00081] <<< REPLY PACKET #1 64 bytes (PREVIOUS TRANSACTION REPLY) +BULK[00081] <<< REPLY PACKET #2 64 bytes (CURRENT TRANSACTION REPLY) + +General reply packet(s) are always used if not own reply defined. + +============================================================================ +| 00-63 | GENERAL REPLY PACKET #1 (PREVIOUS REPLY) +============================================================================ +| 00 | reply data (if any) from previous transaction +| | Just same reply packet as returned during previous transaction. +| | Needed only if reply is missed in previous transaction. +| | Just skip normally. +---------------------------------------------------------------------------- +| 01-59 | don't care +---------------------------------------------------------------------------- +| 60 | packet sequence number +---------------------------------------------------------------------------- +| 61-63 | don't care +---------------------------------------------------------------------------- + +============================================================================ +| 00-63 | GENERAL REPLY PACKET #2 (CURRENT REPLY) +============================================================================ +| 00 | reply data (if any) +---------------------------------------------------------------------------- +| 01-59 | don't care +---------------------------------------------------------------------------- +| 60 | packet sequence number +---------------------------------------------------------------------------- +| 61-63 | don't care +---------------------------------------------------------------------------- + +============================================================================ +| 00-63 | I2C WRITE REQUEST PACKET +============================================================================ +| 00 | 0x31 I2C write command +---------------------------------------------------------------------------- +| 01 | i2c address +---------------------------------------------------------------------------- +| 02 | data length +| | 0x02 (for typical I2C reg / val pair) +---------------------------------------------------------------------------- +| 03 | 0x01 +---------------------------------------------------------------------------- +| 04- | data +---------------------------------------------------------------------------- +| -59 | don't care +---------------------------------------------------------------------------- +| 60 | packet sequence number +---------------------------------------------------------------------------- +| 61-63 | don't care +---------------------------------------------------------------------------- + +============================================================================ +| 00-63 | I2C READ REQUEST PACKET +============================================================================ +| 00 | 0x33 I2C read command +---------------------------------------------------------------------------- +| 01 | i2c address + 1 +---------------------------------------------------------------------------- +| 02 | register +---------------------------------------------------------------------------- +| 03 | 0x00 +---------------------------------------------------------------------------- +| 04 | 0x00 +---------------------------------------------------------------------------- +| 05 | 0x01 +---------------------------------------------------------------------------- +| 06-59 | don't care +---------------------------------------------------------------------------- +| 60 | packet sequence number +---------------------------------------------------------------------------- +| 61-63 | don't care +---------------------------------------------------------------------------- + +============================================================================ +| 00-63 | USB CONTROLLER REGISTER WRITE REQUEST PACKET +============================================================================ +| 00 | 0xb1 register write command +---------------------------------------------------------------------------- +| 01-02 | register +---------------------------------------------------------------------------- +| 03 | 0x01 +---------------------------------------------------------------------------- +| 04 | value +---------------------------------------------------------------------------- +| 05-59 | don't care +---------------------------------------------------------------------------- +| 60 | packet sequence number +---------------------------------------------------------------------------- +| 61-63 | don't care +---------------------------------------------------------------------------- + +============================================================================ +| 00-63 | USB CONTROLLER REGISTER READ REQUEST PACKET +============================================================================ +| 00 | 0xb0 register read command +---------------------------------------------------------------------------- +| 01-02 | register +---------------------------------------------------------------------------- +| 03 | 0x01 +---------------------------------------------------------------------------- +| 04-59 | don't care +---------------------------------------------------------------------------- +| 60 | packet sequence number +---------------------------------------------------------------------------- +| 61-63 | don't care +---------------------------------------------------------------------------- + +============================================================================ +| 00-63 | LED CONTROL REQUEST PACKET +============================================================================ +| 00 | 0x16 LED and IR control command +---------------------------------------------------------------------------- +| 01 | 0x01 (LED) +---------------------------------------------------------------------------- +| 03 | 0x00 blink +| | 0x01 lights continuously +---------------------------------------------------------------------------- +| 04 | blink interval +| | 0x00 fastest (looks like LED lights continuously) +| | 0xff slowest +---------------------------------------------------------------------------- +| 05-59 | don't care +---------------------------------------------------------------------------- +| 60 | packet sequence number +---------------------------------------------------------------------------- +| 61-63 | don't care +---------------------------------------------------------------------------- + +============================================================================ +| 00-63 | IR CONTROL REQUEST PACKET +============================================================================ +| 00 | 0x16 LED and IR control command +---------------------------------------------------------------------------- +| 01 | 0x02 (IR) +---------------------------------------------------------------------------- +| 03 | 0x00 IR disabled +| | 0x01 IR enabled +---------------------------------------------------------------------------- +| 04-59 | don't care +---------------------------------------------------------------------------- +| 60 | packet sequence number +---------------------------------------------------------------------------- +| 61-63 | don't care +---------------------------------------------------------------------------- + +============================================================================ +| 00-63 | STREAMING CONTROL REQUEST PACKET +============================================================================ +| 00 | 0x12 streaming control command +---------------------------------------------------------------------------- +| 01 | 0x00 streaming disabled +| | 0x01 streaming enabled +---------------------------------------------------------------------------- +| 02 | 0x00 +---------------------------------------------------------------------------- +| 03-59 | don't care +---------------------------------------------------------------------------- +| 60 | packet sequence number +---------------------------------------------------------------------------- +| 61-63 | don't care +---------------------------------------------------------------------------- + +============================================================================ +| 00-63 | REMOTE CONTROL REQUEST PACKET +============================================================================ +| 00 | 0x41 remote control command +---------------------------------------------------------------------------- +| 01-59 | don't care +---------------------------------------------------------------------------- +| 60 | packet sequence number +---------------------------------------------------------------------------- +| 61-63 | don't care +---------------------------------------------------------------------------- + +============================================================================ +| 00-63 | REMOTE CONTROL REPLY PACKET +============================================================================ +| 00 | 0x00 code not received +| | 0x01 code received +---------------------------------------------------------------------------- +| 01 | remote control code +---------------------------------------------------------------------------- +| 02-59 | don't care +---------------------------------------------------------------------------- +| 60 | packet sequence number +---------------------------------------------------------------------------- +| 61-63 | don't care +---------------------------------------------------------------------------- + +============================================================================ +| 00-63 | GET HARDWARE INFO REQUEST PACKET +============================================================================ +| 00 | 0x19 get hardware info command +---------------------------------------------------------------------------- +| 01-59 | don't care +---------------------------------------------------------------------------- +| 60 | packet sequence number +---------------------------------------------------------------------------- +| 61-63 | don't care +---------------------------------------------------------------------------- + +============================================================================ +| 00-63 | GET HARDWARE INFO REPLY PACKET +============================================================================ +| 00 | hardware id +---------------------------------------------------------------------------- +| 01-02 | firmware version +---------------------------------------------------------------------------- +| 03-59 | don't care +---------------------------------------------------------------------------- +| 60 | packet sequence number +---------------------------------------------------------------------------- +| 61-63 | don't care +---------------------------------------------------------------------------- + +============================================================================ +| 00-63 | SMART CARD READER PACKET +============================================================================ +| 00 | 0x34 smart card reader command +---------------------------------------------------------------------------- +| xx | +---------------------------------------------------------------------------- +| xx-59 | don't care +---------------------------------------------------------------------------- +| 60 | packet sequence number +---------------------------------------------------------------------------- +| 61-63 | don't care +---------------------------------------------------------------------------- + +*/ diff --git a/drivers/media/dvb/dvb-usb/au6610.c b/drivers/media/dvb/dvb-usb/au6610.c index 2ccb90fa60c8..eb34cc3894e0 100644 --- a/drivers/media/dvb/dvb-usb/au6610.c +++ b/drivers/media/dvb/dvb-usb/au6610.c @@ -1,24 +1,31 @@ -/* DVB USB compliant linux driver for Sigmatek DVB-110 DVB-T USB2.0 receiver +/* + * DVB USB Linux driver for Alcor Micro AU6610 DVB-T USB2.0. * * Copyright (C) 2006 Antti Palosaari <crope@iki.fi> * - * 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. + * 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. * - * see Documentation/dvb/README.dvb-usb for more information + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include "au6610.h" - #include "zl10353.h" #include "qt1010.h" /* debug */ static int dvb_usb_au6610_debug; module_param_named(debug, dvb_usb_au6610_debug, int, 0644); -MODULE_PARM_DESC(debug, "set debugging level (1=rc (or-able))." DVB_USB_DEBUG_STATUS); - +MODULE_PARM_DESC(debug, "set debugging level" DVB_USB_DEBUG_STATUS); DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); static int au6610_usb_msg(struct dvb_usb_device *d, u8 operation, u8 addr, @@ -42,9 +49,8 @@ static int au6610_usb_msg(struct dvb_usb_device *d, u8 operation, u8 addr, } ret = usb_control_msg(d->udev, usb_rcvctrlpipe(d->udev, 0), operation, - USB_TYPE_VENDOR|USB_DIR_IN, addr << 1, index, usb_buf, - sizeof(usb_buf), AU6610_USB_TIMEOUT); - + USB_TYPE_VENDOR|USB_DIR_IN, addr << 1, index, + usb_buf, sizeof(usb_buf), AU6610_USB_TIMEOUT); if (ret < 0) return ret; @@ -116,15 +122,6 @@ static struct i2c_algorithm au6610_i2c_algo = { }; /* Callbacks for DVB USB */ -static int au6610_identify_state(struct usb_device *udev, - struct dvb_usb_device_properties *props, - struct dvb_usb_device_description **desc, - int *cold) -{ - *cold = 0; - return 0; -} - static struct zl10353_config au6610_zl10353_config = { .demod_address = 0x0f, .no_tuner = 1, @@ -133,12 +130,12 @@ static struct zl10353_config au6610_zl10353_config = { static int au6610_zl10353_frontend_attach(struct dvb_usb_adapter *adap) { - if ((adap->fe = dvb_attach(zl10353_attach, &au6610_zl10353_config, - &adap->dev->i2c_adap)) != NULL) { - return 0; - } + adap->fe = dvb_attach(zl10353_attach, &au6610_zl10353_config, + &adap->dev->i2c_adap); + if (adap->fe == NULL) + return -ENODEV; - return -EIO; + return 0; } static struct qt1010_config au6610_qt1010_config = { @@ -171,7 +168,7 @@ static int au6610_probe(struct usb_interface *intf, alt = usb_altnum_to_altsetting(intf, AU6610_ALTSETTING); if (alt == NULL) { - deb_rc("no alt found!\n"); + deb_info("%s: no alt found!\n", __func__); return -ENODEV; } ret = usb_set_interface(d->udev, alt->desc.bInterfaceNumber, @@ -181,18 +178,19 @@ static int au6610_probe(struct usb_interface *intf, return ret; } - static struct usb_device_id au6610_table [] = { { USB_DEVICE(USB_VID_ALCOR_MICRO, USB_PID_SIGMATEK_DVB_110) }, { } /* Terminating entry */ }; -MODULE_DEVICE_TABLE (usb, au6610_table); +MODULE_DEVICE_TABLE(usb, au6610_table); static struct dvb_usb_device_properties au6610_properties = { .caps = DVB_USB_IS_AN_I2C_ADAPTER, + .usb_ctrl = DEVICE_SPECIFIC, - .size_of_priv = 0, - .identify_state = au6610_identify_state, + + .size_of_priv = 0, + .num_adapters = 1, .adapter = { { @@ -206,20 +204,22 @@ static struct dvb_usb_device_properties au6610_properties = { .u = { .isoc = { .framesperurb = 40, - .framesize = 942, /* maximum packet size */ - .interval = 1.25, /* 125 us */ + .framesize = 942, + .interval = 1, } } }, } }, + .i2c_algo = &au6610_i2c_algo, + .num_device_descs = 1, .devices = { { - "Sigmatek DVB-110 DVB-T USB2.0", - { &au6610_table[0], NULL }, - { NULL }, + .name = "Sigmatek DVB-110 DVB-T USB2.0", + .cold_ids = {NULL}, + .warm_ids = {&au6610_table[0], NULL}, }, } }; @@ -236,12 +236,11 @@ static int __init au6610_module_init(void) { int ret; - if ((ret = usb_register(&au6610_driver))) { + ret = usb_register(&au6610_driver); + if (ret) err("usb_register failed. Error number %d", ret); - return ret; - } - return 0; + return ret; } static void __exit au6610_module_exit(void) @@ -250,10 +249,10 @@ static void __exit au6610_module_exit(void) usb_deregister(&au6610_driver); } -module_init (au6610_module_init); -module_exit (au6610_module_exit); +module_init(au6610_module_init); +module_exit(au6610_module_exit); MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>"); -MODULE_DESCRIPTION("Driver Sigmatek DVB-110 DVB-T USB2.0 / AU6610"); +MODULE_DESCRIPTION("Driver for Alcor Micro AU6610 DVB-T USB2.0"); MODULE_VERSION("0.1"); MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb/dvb-usb/au6610.h b/drivers/media/dvb/dvb-usb/au6610.h index 4161b054c713..7849abe2c614 100644 --- a/drivers/media/dvb/dvb-usb/au6610.h +++ b/drivers/media/dvb/dvb-usb/au6610.h @@ -1,10 +1,30 @@ +/* + * DVB USB Linux driver for Alcor Micro AU6610 DVB-T USB2.0. + * + * Copyright (C) 2006 Antti Palosaari <crope@iki.fi> + * + * 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 _DVB_USB_AU6610_H_ #define _DVB_USB_AU6610_H_ #define DVB_USB_LOG_PREFIX "au6610" #include "dvb-usb.h" -#define deb_rc(args...) dprintk(dvb_usb_au6610_debug,0x01,args) +#define deb_info(args...) dprintk(dvb_usb_au6610_debug, 0x01, args) #define AU6610_REQ_I2C_WRITE 0x14 #define AU6610_REQ_I2C_READ 0x13 diff --git a/drivers/media/dvb/dvb-usb/cxusb.c b/drivers/media/dvb/dvb-usb/cxusb.c index 0286156704f2..578afce6884c 100644 --- a/drivers/media/dvb/dvb-usb/cxusb.c +++ b/drivers/media/dvb/dvb-usb/cxusb.c @@ -35,6 +35,7 @@ #include "zl10353.h" #include "tuner-xc2028.h" #include "tuner-simple.h" +#include "mxl5005s.h" /* debug */ static int dvb_usb_cxusb_debug; @@ -43,9 +44,8 @@ MODULE_PARM_DESC(debug, "set debugging level (1=rc (or-able))." DVB_USB_DEBUG_ST DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); -#define deb_info(args...) dprintk(dvb_usb_cxusb_debug,0x01,args) -#define deb_i2c(args...) if (d->udev->descriptor.idVendor == USB_VID_MEDION) \ - dprintk(dvb_usb_cxusb_debug,0x01,args) +#define deb_info(args...) dprintk(dvb_usb_cxusb_debug, 0x03, args) +#define deb_i2c(args...) dprintk(dvb_usb_cxusb_debug, 0x02, args) static int cxusb_ctrl_msg(struct dvb_usb_device *d, u8 cmd, u8 *wbuf, int wlen, u8 *rbuf, int rlen) @@ -202,6 +202,46 @@ static int cxusb_power_ctrl(struct dvb_usb_device *d, int onoff) return cxusb_ctrl_msg(d, CMD_POWER_OFF, &b, 1, NULL, 0); } +static int cxusb_aver_power_ctrl(struct dvb_usb_device *d, int onoff) +{ + int ret; + if (!onoff) + return cxusb_ctrl_msg(d, CMD_POWER_OFF, NULL, 0, NULL, 0); + if (d->state == DVB_USB_STATE_INIT && + usb_set_interface(d->udev, 0, 0) < 0) + err("set interface failed"); + do; while (!(ret = cxusb_ctrl_msg(d, CMD_POWER_ON, NULL, 0, NULL, 0)) && + !(ret = cxusb_ctrl_msg(d, 0x15, NULL, 0, NULL, 0)) && + !(ret = cxusb_ctrl_msg(d, 0x17, NULL, 0, NULL, 0)) && 0); + if (!ret) { + /* FIXME: We don't know why, but we need to configure the + * lgdt3303 with the register settings below on resume */ + int i; + u8 buf, bufs[] = { + 0x0e, 0x2, 0x00, 0x7f, + 0x0e, 0x2, 0x02, 0xfe, + 0x0e, 0x2, 0x02, 0x01, + 0x0e, 0x2, 0x00, 0x03, + 0x0e, 0x2, 0x0d, 0x40, + 0x0e, 0x2, 0x0e, 0x87, + 0x0e, 0x2, 0x0f, 0x8e, + 0x0e, 0x2, 0x10, 0x01, + 0x0e, 0x2, 0x14, 0xd7, + 0x0e, 0x2, 0x47, 0x88, + }; + msleep(20); + for (i = 0; i < sizeof(bufs)/sizeof(u8); i += 4/sizeof(u8)) { + ret = cxusb_ctrl_msg(d, CMD_I2C_WRITE, + bufs+i, 4, &buf, 1); + if (ret) + break; + if (buf != 0x8) + return -EREMOTEIO; + } + } + return ret; +} + static int cxusb_bluebird_power_ctrl(struct dvb_usb_device *d, int onoff) { u8 b = 0; @@ -233,6 +273,16 @@ static int cxusb_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff) return 0; } +static int cxusb_aver_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff) +{ + if (onoff) + cxusb_ctrl_msg(adap->dev, CMD_AVER_STREAM_ON, NULL, 0, NULL, 0); + else + cxusb_ctrl_msg(adap->dev, CMD_AVER_STREAM_OFF, + NULL, 0, NULL, 0); + return 0; +} + static int cxusb_rc_query(struct dvb_usb_device *d, u32 *event, int *state) { struct dvb_usb_rc_key *keymap = d->props.rc_key_map; @@ -423,6 +473,12 @@ static struct lgdt330x_config cxusb_lgdt3303_config = { .demod_chip = LGDT3303, }; +static struct lgdt330x_config cxusb_aver_lgdt3303_config = { + .demod_address = 0x0e, + .demod_chip = LGDT3303, + .clock_polarity_flip = 2, +}; + static struct mt352_config cxusb_dee1601_config = { .demod_address = 0x0f, .demod_init = cxusb_dee1601_demod_init, @@ -453,6 +509,24 @@ static struct mt352_config cxusb_mt352_xc3028_config = { .demod_init = cxusb_mt352_demod_init, }; +/* FIXME: needs tweaking */ +static struct mxl5005s_config aver_a868r_tuner = { + .i2c_address = 0x63, + .if_freq = 6000000UL, + .xtal_freq = CRYSTAL_FREQ_16000000HZ, + .agc_mode = MXL_SINGLE_AGC, + .tracking_filter = MXL_TF_C, + .rssi_enable = MXL_RSSI_ENABLE, + .cap_select = MXL_CAP_SEL_ENABLE, + .div_out = MXL_DIV_OUT_4, + .clock_out = MXL_CLOCK_OUT_DISABLE, + .output_load = MXL5005S_IF_OUTPUT_LOAD_200_OHM, + .top = MXL5005S_TOP_25P2, + .mod_mode = MXL_DIGITAL_MODE, + .if_mode = MXL_ZERO_IF, + .AgcMasterByte = 0x00, +}; + /* Callbacks for DVB USB */ static int cxusb_fmd1216me_tuner_attach(struct dvb_usb_adapter *adap) { @@ -533,6 +607,13 @@ static int cxusb_dvico_xc3028_tuner_attach(struct dvb_usb_adapter *adap) return 0; } +static int cxusb_mxl5003s_tuner_attach(struct dvb_usb_adapter *adap) +{ + dvb_attach(mxl5005s_attach, adap->fe, + &adap->dev->i2c_adap, &aver_a868r_tuner); + return 0; +} + static int cxusb_cx22702_frontend_attach(struct dvb_usb_adapter *adap) { u8 b; @@ -562,6 +643,16 @@ static int cxusb_lgdt3303_frontend_attach(struct dvb_usb_adapter *adap) return -EIO; } +static int cxusb_aver_lgdt3303_frontend_attach(struct dvb_usb_adapter *adap) +{ + adap->fe = dvb_attach(lgdt330x_attach, &cxusb_aver_lgdt3303_config, + &adap->dev->i2c_adap); + if (adap->fe != NULL) + return 0; + + return -EIO; +} + static int cxusb_mt352_frontend_attach(struct dvb_usb_adapter *adap) { /* used in both lgz201 and th7579 */ @@ -736,6 +827,7 @@ static struct dvb_usb_device_properties cxusb_bluebird_dtt7579_properties; static struct dvb_usb_device_properties cxusb_bluebird_dualdig4_properties; static struct dvb_usb_device_properties cxusb_bluebird_nano2_properties; static struct dvb_usb_device_properties cxusb_bluebird_nano2_needsfirmware_properties; +static struct dvb_usb_device_properties cxusb_aver_a868r_properties; static int cxusb_probe(struct usb_interface *intf, const struct usb_device_id *id) @@ -756,7 +848,10 @@ static int cxusb_probe(struct usb_interface *intf, THIS_MODULE, NULL, adapter_nr) || 0 == dvb_usb_device_init(intf, &cxusb_bluebird_nano2_needsfirmware_properties, - THIS_MODULE, NULL, adapter_nr)) + THIS_MODULE, NULL, adapter_nr) || + 0 == dvb_usb_device_init(intf, &cxusb_aver_a868r_properties, + THIS_MODULE, NULL, adapter_nr) || + 0) return 0; return -EINVAL; @@ -779,6 +874,7 @@ static struct usb_device_id cxusb_table [] = { { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DUAL_4) }, { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DVB_T_NANO_2) }, { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DVB_T_NANO_2_NFW_WARM) }, + { USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_VOLAR_A868R) }, {} /* Terminating entry */ }; MODULE_DEVICE_TABLE (usb, cxusb_table); @@ -1182,6 +1278,48 @@ static struct dvb_usb_device_properties cxusb_bluebird_nano2_needsfirmware_prope } }; +static struct dvb_usb_device_properties cxusb_aver_a868r_properties = { + .caps = DVB_USB_IS_AN_I2C_ADAPTER, + + .usb_ctrl = CYPRESS_FX2, + + .size_of_priv = sizeof(struct cxusb_state), + + .num_adapters = 1, + .adapter = { + { + .streaming_ctrl = cxusb_aver_streaming_ctrl, + .frontend_attach = cxusb_aver_lgdt3303_frontend_attach, + .tuner_attach = cxusb_mxl5003s_tuner_attach, + /* parameter for the MPEG2-data transfer */ + .stream = { + .type = USB_BULK, + .count = 5, + .endpoint = 0x04, + .u = { + .bulk = { + .buffersize = 8192, + } + } + }, + + }, + }, + .power_ctrl = cxusb_aver_power_ctrl, + + .i2c_algo = &cxusb_i2c_algo, + + .generic_bulk_ctrl_endpoint = 0x01, + + .num_device_descs = 1, + .devices = { + { "AVerMedia AVerTVHD Volar (A868R)", + { NULL }, + { &cxusb_table[16], NULL }, + }, + } +}; + static struct usb_driver cxusb_driver = { .name = "dvb_usb_cxusb", .probe = cxusb_probe, diff --git a/drivers/media/dvb/dvb-usb/cxusb.h b/drivers/media/dvb/dvb-usb/cxusb.h index 4768a2c35517..1a51eafd31b9 100644 --- a/drivers/media/dvb/dvb-usb/cxusb.h +++ b/drivers/media/dvb/dvb-usb/cxusb.h @@ -20,6 +20,9 @@ #define CMD_STREAMING_ON 0x36 #define CMD_STREAMING_OFF 0x37 +#define CMD_AVER_STREAM_ON 0x18 +#define CMD_AVER_STREAM_OFF 0x19 + #define CMD_GET_IR_CODE 0x47 #define CMD_ANALOG 0x50 diff --git a/drivers/media/dvb/dvb-usb/dib0700_devices.c b/drivers/media/dvb/dvb-usb/dib0700_devices.c index c4d40fe01d57..3dd20bfbed32 100644 --- a/drivers/media/dvb/dvb-usb/dib0700_devices.c +++ b/drivers/media/dvb/dvb-usb/dib0700_devices.c @@ -1117,6 +1117,7 @@ struct usb_device_id dib0700_usb_id_table[] = { { USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_CINERGY_HT_EXPRESS) }, { USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_CINERGY_T_XXS) }, { USB_DEVICE(USB_VID_LEADTEK, USB_PID_WINFAST_DTV_DONGLE_STK7700P_2) }, + { USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_NOVA_TD_STICK_52009) }, { 0 } /* Terminating entry */ }; MODULE_DEVICE_TABLE(usb, dib0700_usb_id_table); @@ -1372,7 +1373,7 @@ struct dvb_usb_device_properties dib0700_devices[] = { } }, - .num_device_descs = 2, + .num_device_descs = 3, .devices = { { "DiBcom STK7070PD reference design", { &dib0700_usb_id_table[17], NULL }, @@ -1381,6 +1382,10 @@ struct dvb_usb_device_properties dib0700_devices[] = { { "Pinnacle PCTV Dual DVB-T Diversity Stick", { &dib0700_usb_id_table[18], NULL }, { NULL }, + }, + { "Hauppauge Nova-TD Stick (52009)", + { &dib0700_usb_id_table[35], NULL }, + { NULL }, } } }, { DIB0700_DEFAULT_DEVICE_PROPERTIES, diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-i2c.c b/drivers/media/dvb/dvb-usb/dvb-usb-i2c.c index 23428cd30756..326f7608954b 100644 --- a/drivers/media/dvb/dvb-usb/dvb-usb-i2c.c +++ b/drivers/media/dvb/dvb-usb/dvb-usb-i2c.c @@ -20,11 +20,7 @@ int dvb_usb_i2c_init(struct dvb_usb_device *d) } strncpy(d->i2c_adap.name, d->desc->name, sizeof(d->i2c_adap.name)); -#ifdef I2C_ADAP_CLASS_TV_DIGITAL - d->i2c_adap.class = I2C_ADAP_CLASS_TV_DIGITAL, -#else d->i2c_adap.class = I2C_CLASS_TV_DIGITAL, -#endif d->i2c_adap.algo = d->props.i2c_algo; d->i2c_adap.algo_data = NULL; d->i2c_adap.dev.parent = &d->udev->dev; diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h index 34245d1b7dd9..e5238b31e946 100644 --- a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h +++ b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h @@ -14,6 +14,7 @@ #define USB_VID_AFATECH 0x15a4 #define USB_VID_ALCOR_MICRO 0x058f #define USB_VID_ALINK 0x05e3 +#define USB_VID_AMT 0x1c73 #define USB_VID_ANCHOR 0x0547 #define USB_VID_ANSONIC 0x10b9 #define USB_VID_ANUBIS_ELECTRONIC 0x10fd @@ -57,6 +58,7 @@ #define USB_PID_AFATECH_AF9005 0x9020 #define USB_VID_ALINK_DTU 0xf170 #define USB_PID_ANSONIC_DVBT_USB 0x6000 +#define USB_PID_ANYSEE 0x861f #define USB_PID_AVERMEDIA_DVBT_USB_COLD 0x0001 #define USB_PID_AVERMEDIA_DVBT_USB_WARM 0x0002 #define USB_PID_AVERMEDIA_DVBT_USB2_COLD 0xa800 @@ -132,9 +134,15 @@ #define USB_PID_HAUPPAUGE_NOVA_T_STICK_3 0x7070 #define USB_PID_HAUPPAUGE_MYTV_T 0x7080 #define USB_PID_HAUPPAUGE_NOVA_TD_STICK 0x9580 +#define USB_PID_HAUPPAUGE_NOVA_TD_STICK_52009 0x5200 #define USB_PID_AVERMEDIA_EXPRESS 0xb568 #define USB_PID_AVERMEDIA_VOLAR 0xa807 #define USB_PID_AVERMEDIA_VOLAR_2 0xb808 +#define USB_PID_AVERMEDIA_VOLAR_A868R 0xa868 +#define USB_PID_AVERMEDIA_MCE_USB_M038 0x1228 +#define USB_PID_AVERMEDIA_HYBRID_ULTRA_USB_M039R 0x0039 +#define USB_PID_AVERMEDIA_HYBRID_ULTRA_USB_M039R_ATSC 0x1039 +#define USB_PID_AVERMEDIA_HYBRID_ULTRA_USB_M039R_DVBT 0x2039 #define USB_PID_TECHNOTREND_CONNECT_S2400 0x3006 #define USB_PID_TERRATEC_CINERGY_DT_XS_DIVERSITY 0x005a #define USB_PID_TERRATEC_CINERGY_HT_USB_XE 0x0058 diff --git a/drivers/media/dvb/dvb-usb/gl861.c b/drivers/media/dvb/dvb-usb/gl861.c index 037f7ffb47b2..6f596ed41761 100644 --- a/drivers/media/dvb/dvb-usb/gl861.c +++ b/drivers/media/dvb/dvb-usb/gl861.c @@ -1,8 +1,8 @@ /* DVB USB compliant linux driver for GL861 USB2.0 devices. * * 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. + * under the terms of the GNU General Public License as published by the + * Free Software Foundation, version 2. * * see Documentation/dvb/README.dvb-usb for more information */ @@ -13,9 +13,9 @@ /* debug */ static int dvb_usb_gl861_debug; -module_param_named(debug,dvb_usb_gl861_debug, int, 0644); -MODULE_PARM_DESC(debug, "set debugging level (1=rc (or-able))." DVB_USB_DEBUG_STATUS); - +module_param_named(debug, dvb_usb_gl861_debug, int, 0644); +MODULE_PARM_DESC(debug, "set debugging level (1=rc (or-able))." + DVB_USB_DEBUG_STATUS); DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); static int gl861_i2c_msg(struct dvb_usb_device *d, u8 addr, @@ -70,7 +70,7 @@ static int gl861_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], /* write/read request */ if (i+1 < num && (msg[i+1].flags & I2C_M_RD)) { if (gl861_i2c_msg(d, msg[i].addr, msg[i].buf, - msg[i].len, msg[i+1].buf, msg[i+1].len) < 0) + msg[i].len, msg[i+1].buf, msg[i+1].len) < 0) break; i++; } else @@ -102,12 +102,13 @@ static struct zl10353_config gl861_zl10353_config = { static int gl861_frontend_attach(struct dvb_usb_adapter *adap) { - if ((adap->fe = dvb_attach(zl10353_attach, &gl861_zl10353_config, - &adap->dev->i2c_adap)) != NULL) { - return 0; - } - return -EIO; + adap->fe = dvb_attach(zl10353_attach, &gl861_zl10353_config, + &adap->dev->i2c_adap); + if (adap->fe == NULL) + return -EIO; + + return 0; } static struct qt1010_config gl861_qt1010_config = { @@ -156,7 +157,7 @@ static struct usb_device_id gl861_table [] = { { USB_DEVICE(USB_VID_ALINK, USB_VID_ALINK_DTU) }, { } /* Terminating entry */ }; -MODULE_DEVICE_TABLE (usb, gl861_table); +MODULE_DEVICE_TABLE(usb, gl861_table); static struct dvb_usb_device_properties gl861_properties = { .caps = DVB_USB_IS_AN_I2C_ADAPTER, @@ -180,7 +181,7 @@ static struct dvb_usb_device_properties gl861_properties = { } } }, - }}, + } }, .i2c_algo = &gl861_i2c_algo, .num_device_descs = 2, @@ -210,12 +211,11 @@ static int __init gl861_module_init(void) { int ret; - if ((ret = usb_register(&gl861_driver))) { + ret = usb_register(&gl861_driver); + if (ret) err("usb_register failed. Error number %d", ret); - return ret; - } - return 0; + return ret; } static void __exit gl861_module_exit(void) @@ -224,8 +224,8 @@ static void __exit gl861_module_exit(void) usb_deregister(&gl861_driver); } -module_init (gl861_module_init); -module_exit (gl861_module_exit); +module_init(gl861_module_init); +module_exit(gl861_module_exit); MODULE_AUTHOR("Carl Lundqvist <comabug@gmail.com>"); MODULE_DESCRIPTION("Driver MSI Mega Sky 580 DVB-T USB2.0 / GL861"); diff --git a/drivers/media/dvb/dvb-usb/gl861.h b/drivers/media/dvb/dvb-usb/gl861.h index 72a51afd5ee3..c54855e2c233 100644 --- a/drivers/media/dvb/dvb-usb/gl861.h +++ b/drivers/media/dvb/dvb-usb/gl861.h @@ -4,7 +4,7 @@ #define DVB_USB_LOG_PREFIX "gl861" #include "dvb-usb.h" -#define deb_rc(args...) dprintk(dvb_usb_gl861_debug,0x01,args) +#define deb_rc(args...) dprintk(dvb_usb_gl861_debug, 0x01, args) #define GL861_WRITE 0x40 #define GL861_READ 0xc0 diff --git a/drivers/media/dvb/frontends/au8522.c b/drivers/media/dvb/frontends/au8522.c index 03900d241a76..f7b71657f0f6 100644 --- a/drivers/media/dvb/frontends/au8522.c +++ b/drivers/media/dvb/frontends/au8522.c @@ -26,7 +26,6 @@ #include <linux/slab.h> #include <linux/delay.h> #include "dvb_frontend.h" -#include "dvb-pll.h" #include "au8522.h" struct au8522_state { diff --git a/drivers/media/dvb/frontends/dvb-pll.c b/drivers/media/dvb/frontends/dvb-pll.c index a054894ff481..ea058153ebfa 100644 --- a/drivers/media/dvb/frontends/dvb-pll.c +++ b/drivers/media/dvb/frontends/dvb-pll.c @@ -343,6 +343,52 @@ static struct dvb_pll_desc dvb_pll_opera1 = { } }; +static void samsung_dtos403ih102a_set(struct dvb_frontend *fe, u8 *buf, + const struct dvb_frontend_parameters *params) +{ + struct dvb_pll_priv *priv = fe->tuner_priv; + struct i2c_msg msg = { + .addr = priv->pll_i2c_address, + .flags = 0, + .buf = buf, + .len = 4 + }; + int result; + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + + result = i2c_transfer(priv->i2c, &msg, 1); + if (result != 1) + printk(KERN_ERR "%s: i2c_transfer failed:%d", + __func__, result); + + buf[2] = 0x9e; + buf[3] = 0x90; + + return; +} + +/* unknown pll used in Samsung DTOS403IH102A DVB-C tuner */ +static struct dvb_pll_desc dvb_pll_samsung_dtos403ih102a = { + .name = "Samsung DTOS403IH102A", + .min = 44250000, + .max = 858000000, + .iffreq = 36125000, + .count = 8, + .set = samsung_dtos403ih102a_set, + .entries = { + { 135000000, 62500, 0xbe, 0x01 }, + { 177000000, 62500, 0xf6, 0x01 }, + { 370000000, 62500, 0xbe, 0x02 }, + { 450000000, 62500, 0xf6, 0x02 }, + { 466000000, 62500, 0xfe, 0x02 }, + { 538000000, 62500, 0xbe, 0x08 }, + { 826000000, 62500, 0xf6, 0x08 }, + { 999999999, 62500, 0xfe, 0x08 }, + } +}; + /* ----------------------------------------------------------- */ static struct dvb_pll_desc *pll_list[] = { @@ -360,6 +406,7 @@ static struct dvb_pll_desc *pll_list[] = { [DVB_PLL_SAMSUNG_TBMV] = &dvb_pll_samsung_tbmv, [DVB_PLL_PHILIPS_SD1878_TDA8261] = &dvb_pll_philips_sd1878_tda8261, [DVB_PLL_OPERA1] = &dvb_pll_opera1, + [DVB_PLL_SAMSUNG_DTOS403IH102A] = &dvb_pll_samsung_dtos403ih102a, }; /* ----------------------------------------------------------- */ diff --git a/drivers/media/dvb/frontends/dvb-pll.h b/drivers/media/dvb/frontends/dvb-pll.h index 872ca29e7cf3..05239f579ccf 100644 --- a/drivers/media/dvb/frontends/dvb-pll.h +++ b/drivers/media/dvb/frontends/dvb-pll.h @@ -22,6 +22,7 @@ #define DVB_PLL_SAMSUNG_TBMV 11 #define DVB_PLL_PHILIPS_SD1878_TDA8261 12 #define DVB_PLL_OPERA1 13 +#define DVB_PLL_SAMSUNG_DTOS403IH102A 14 /** * Attach a dvb-pll to the supplied frontend structure. diff --git a/drivers/media/dvb/frontends/lgdt330x.c b/drivers/media/dvb/frontends/lgdt330x.c index f0195c8272f4..056387b41a8f 100644 --- a/drivers/media/dvb/frontends/lgdt330x.c +++ b/drivers/media/dvb/frontends/lgdt330x.c @@ -226,11 +226,16 @@ static int lgdt330x_init(struct dvb_frontend* fe) 0x4c, 0x14 }; - static u8 flip_lgdt3303_init_data[] = { + static u8 flip_1_lgdt3303_init_data[] = { 0x4c, 0x14, 0x87, 0xf3 }; + static u8 flip_2_lgdt3303_init_data[] = { + 0x4c, 0x14, + 0x87, 0xda + }; + struct lgdt330x_state* state = fe->demodulator_priv; char *chip_name; int err; @@ -243,10 +248,19 @@ static int lgdt330x_init(struct dvb_frontend* fe) break; case LGDT3303: chip_name = "LGDT3303"; - if (state->config->clock_polarity_flip) { - err = i2c_write_demod_bytes(state, flip_lgdt3303_init_data, - sizeof(flip_lgdt3303_init_data)); - } else { + switch (state->config->clock_polarity_flip) { + case 2: + err = i2c_write_demod_bytes(state, + flip_2_lgdt3303_init_data, + sizeof(flip_2_lgdt3303_init_data)); + break; + case 1: + err = i2c_write_demod_bytes(state, + flip_1_lgdt3303_init_data, + sizeof(flip_1_lgdt3303_init_data)); + break; + case 0: + default: err = i2c_write_demod_bytes(state, lgdt3303_init_data, sizeof(lgdt3303_init_data)); } diff --git a/drivers/media/dvb/frontends/s5h1409.c b/drivers/media/dvb/frontends/s5h1409.c index b999ec424ff7..5ddb2dca305c 100644 --- a/drivers/media/dvb/frontends/s5h1409.c +++ b/drivers/media/dvb/frontends/s5h1409.c @@ -26,7 +26,6 @@ #include <linux/slab.h> #include <linux/delay.h> #include "dvb_frontend.h" -#include "dvb-pll.h" #include "s5h1409.h" struct s5h1409_state { diff --git a/drivers/media/dvb/frontends/s5h1411.c b/drivers/media/dvb/frontends/s5h1411.c index eb5bfc99d4e9..cff360ce1ba3 100644 --- a/drivers/media/dvb/frontends/s5h1411.c +++ b/drivers/media/dvb/frontends/s5h1411.c @@ -26,7 +26,6 @@ #include <linux/slab.h> #include <linux/delay.h> #include "dvb_frontend.h" -#include "dvb-pll.h" #include "s5h1411.h" struct s5h1411_state { diff --git a/drivers/media/dvb/frontends/tda10023.c b/drivers/media/dvb/frontends/tda10023.c index c6ff5b82ff80..a3c34eecdee9 100644 --- a/drivers/media/dvb/frontends/tda10023.c +++ b/drivers/media/dvb/frontends/tda10023.c @@ -38,75 +38,29 @@ #include "dvb_frontend.h" #include "tda1002x.h" +#define REG0_INIT_VAL 0x23 struct tda10023_state { struct i2c_adapter* i2c; /* configuration settings */ - const struct tda1002x_config* config; + const struct tda10023_config *config; struct dvb_frontend frontend; u8 pwm; u8 reg0; -}; + /* clock settings */ + u32 xtal; + u8 pll_m; + u8 pll_p; + u8 pll_n; + u32 sysclk; +}; #define dprintk(x...) static int verbose; -#define XTAL 28920000UL -#define PLL_M 8UL -#define PLL_P 4UL -#define PLL_N 1UL -#define SYSCLK (XTAL*PLL_M/(PLL_N*PLL_P)) // -> 57840000 - -static u8 tda10023_inittab[]={ - // reg mask val - 0x2a,0xff,0x02, // PLL3, Bypass, Power Down - 0xff,0x64,0x00, // Sleep 100ms - 0x2a,0xff,0x03, // PLL3, Bypass, Power Down - 0xff,0x64,0x00, // Sleep 100ms - 0x28,0xff,PLL_M-1, // PLL1 M=8 - 0x29,0xff,((PLL_P-1)<<6)|(PLL_N-1), // PLL2 - 0x00,0xff,0x23, // GPR FSAMPLING=1 - 0x2a,0xff,0x08, // PLL3 PSACLK=1 - 0xff,0x64,0x00, // Sleep 100ms - 0x1f,0xff,0x00, // RESET - 0xff,0x64,0x00, // Sleep 100ms - 0xe6,0x0c,0x04, // RSCFG_IND - 0x10,0xc0,0x80, // DECDVBCFG1 PBER=1 - - 0x0e,0xff,0x82, // GAIN1 - 0x03,0x08,0x08, // CLKCONF DYN=1 - 0x2e,0xbf,0x30, // AGCCONF2 TRIAGC=0,POSAGC=ENAGCIF=1 PPWMTUN=0 PPWMIF=0 - 0x01,0xff,0x30, // AGCREF - 0x1e,0x84,0x84, // CONTROL SACLK_ON=1 - 0x1b,0xff,0xc8, // ADC TWOS=1 - 0x3b,0xff,0xff, // IFMAX - 0x3c,0xff,0x00, // IFMIN - 0x34,0xff,0x00, // PWMREF - 0x35,0xff,0xff, // TUNMAX - 0x36,0xff,0x00, // TUNMIN - 0x06,0xff,0x7f, // EQCONF1 POSI=7 ENADAPT=ENEQUAL=DFE=1 // 0x77 - 0x1c,0x30,0x30, // EQCONF2 STEPALGO=SGNALGO=1 - 0x37,0xff,0xf6, // DELTAF_LSB - 0x38,0xff,0xff, // DELTAF_MSB - 0x02,0xff,0x93, // AGCCONF1 IFS=1 KAGCIF=2 KAGCTUN=3 - 0x2d,0xff,0xf6, // SWEEP SWPOS=1 SWDYN=7 SWSTEP=1 SWLEN=2 - 0x04,0x10,0x00, // SWRAMP=1 - 0x12,0xff,0xa1, // INTP1 POCLKP=1 FEL=1 MFS=0 - 0x2b,0x01,0xa1, // INTS1 - 0x20,0xff,0x04, // INTP2 SWAPP=? MSBFIRSTP=? INTPSEL=? - 0x2c,0xff,0x0d, // INTP/S TRIP=0 TRIS=0 - 0xc4,0xff,0x00, - 0xc3,0x30,0x00, - 0xb5,0xff,0x19, // ERAGC_THD - 0x00,0x03,0x01, // GPR, CLBS soft reset - 0x00,0x03,0x03, // GPR, CLBS soft reset - 0xff,0x64,0x00, // Sleep 100ms - 0xff,0xff,0xff -}; - static u8 tda10023_readreg (struct tda10023_state* state, u8 reg) { u8 b0 [] = { reg }; @@ -219,30 +173,34 @@ static int tda10023_set_symbolrate (struct tda10023_state* state, u32 sr) s16 SFIL=0; u16 NDEC = 0; - if (sr < (u32)(SYSCLK/98.40)) { + /* avoid floating point operations multiplying syscloc and divider + by 10 */ + u32 sysclk_x_10 = state->sysclk * 10; + + if (sr < (u32)(sysclk_x_10/984)) { NDEC=3; SFIL=1; - } else if (sr<(u32)(SYSCLK/64.0)) { + } else if (sr < (u32)(sysclk_x_10/640)) { NDEC=3; SFIL=0; - } else if (sr<(u32)(SYSCLK/49.2)) { + } else if (sr < (u32)(sysclk_x_10/492)) { NDEC=2; SFIL=1; - } else if (sr<(u32)(SYSCLK/32.0)) { + } else if (sr < (u32)(sysclk_x_10/320)) { NDEC=2; SFIL=0; - } else if (sr<(u32)(SYSCLK/24.6)) { + } else if (sr < (u32)(sysclk_x_10/246)) { NDEC=1; SFIL=1; - } else if (sr<(u32)(SYSCLK/16.0)) { + } else if (sr < (u32)(sysclk_x_10/160)) { NDEC=1; SFIL=0; - } else if (sr<(u32)(SYSCLK/12.3)) { + } else if (sr < (u32)(sysclk_x_10/123)) { NDEC=0; SFIL=1; } - BDRI=SYSCLK*16; + BDRI = (state->sysclk)*16; BDRI>>=NDEC; BDRI +=sr/2; BDRI /=sr; @@ -255,11 +213,12 @@ static int tda10023_set_symbolrate (struct tda10023_state* state, u32 sr) BDRX=1<<(24+NDEC); BDRX*=sr; - do_div(BDRX,SYSCLK); // BDRX/=SYSCLK; + do_div(BDRX, state->sysclk); /* BDRX/=SYSCLK; */ BDR=(s32)BDRX; } -// printk("Symbolrate %i, BDR %i BDRI %i, NDEC %i\n",sr,BDR,BDRI,NDEC); + dprintk("Symbolrate %i, BDR %i BDRI %i, NDEC %i\n", + sr, BDR, BDRI, NDEC); tda10023_writebit (state, 0x03, 0xc0, NDEC<<6); tda10023_writereg (state, 0x0a, BDR&255); tda10023_writereg (state, 0x0b, (BDR>>8)&255); @@ -272,8 +231,67 @@ static int tda10023_set_symbolrate (struct tda10023_state* state, u32 sr) static int tda10023_init (struct dvb_frontend *fe) { struct tda10023_state* state = fe->demodulator_priv; + u8 tda10023_inittab[] = { +/* reg mask val */ +/* 000 */ 0x2a, 0xff, 0x02, /* PLL3, Bypass, Power Down */ +/* 003 */ 0xff, 0x64, 0x00, /* Sleep 100ms */ +/* 006 */ 0x2a, 0xff, 0x03, /* PLL3, Bypass, Power Down */ +/* 009 */ 0xff, 0x64, 0x00, /* Sleep 100ms */ + /* PLL1 */ +/* 012 */ 0x28, 0xff, (state->pll_m-1), + /* PLL2 */ +/* 015 */ 0x29, 0xff, ((state->pll_p-1)<<6)|(state->pll_n-1), + /* GPR FSAMPLING=1 */ +/* 018 */ 0x00, 0xff, REG0_INIT_VAL, +/* 021 */ 0x2a, 0xff, 0x08, /* PLL3 PSACLK=1 */ +/* 024 */ 0xff, 0x64, 0x00, /* Sleep 100ms */ +/* 027 */ 0x1f, 0xff, 0x00, /* RESET */ +/* 030 */ 0xff, 0x64, 0x00, /* Sleep 100ms */ +/* 033 */ 0xe6, 0x0c, 0x04, /* RSCFG_IND */ +/* 036 */ 0x10, 0xc0, 0x80, /* DECDVBCFG1 PBER=1 */ + +/* 039 */ 0x0e, 0xff, 0x82, /* GAIN1 */ +/* 042 */ 0x03, 0x08, 0x08, /* CLKCONF DYN=1 */ +/* 045 */ 0x2e, 0xbf, 0x30, /* AGCCONF2 TRIAGC=0,POSAGC=ENAGCIF=1 + PPWMTUN=0 PPWMIF=0 */ +/* 048 */ 0x01, 0xff, 0x30, /* AGCREF */ +/* 051 */ 0x1e, 0x84, 0x84, /* CONTROL SACLK_ON=1 */ +/* 054 */ 0x1b, 0xff, 0xc8, /* ADC TWOS=1 */ +/* 057 */ 0x3b, 0xff, 0xff, /* IFMAX */ +/* 060 */ 0x3c, 0xff, 0x00, /* IFMIN */ +/* 063 */ 0x34, 0xff, 0x00, /* PWMREF */ +/* 066 */ 0x35, 0xff, 0xff, /* TUNMAX */ +/* 069 */ 0x36, 0xff, 0x00, /* TUNMIN */ +/* 072 */ 0x06, 0xff, 0x7f, /* EQCONF1 POSI=7 ENADAPT=ENEQUAL=DFE=1 */ +/* 075 */ 0x1c, 0x30, 0x30, /* EQCONF2 STEPALGO=SGNALGO=1 */ +/* 078 */ 0x37, 0xff, 0xf6, /* DELTAF_LSB */ +/* 081 */ 0x38, 0xff, 0xff, /* DELTAF_MSB */ +/* 084 */ 0x02, 0xff, 0x93, /* AGCCONF1 IFS=1 KAGCIF=2 KAGCTUN=3 */ +/* 087 */ 0x2d, 0xff, 0xf6, /* SWEEP SWPOS=1 SWDYN=7 SWSTEP=1 SWLEN=2 */ +/* 090 */ 0x04, 0x10, 0x00, /* SWRAMP=1 */ +/* 093 */ 0x12, 0xff, TDA10023_OUTPUT_MODE_PARALLEL_B, /* + INTP1 POCLKP=1 FEL=1 MFS=0 */ +/* 096 */ 0x2b, 0x01, 0xa1, /* INTS1 */ +/* 099 */ 0x20, 0xff, 0x04, /* INTP2 SWAPP=? MSBFIRSTP=? INTPSEL=? */ +/* 102 */ 0x2c, 0xff, 0x0d, /* INTP/S TRIP=0 TRIS=0 */ +/* 105 */ 0xc4, 0xff, 0x00, +/* 108 */ 0xc3, 0x30, 0x00, +/* 111 */ 0xb5, 0xff, 0x19, /* ERAGC_THD */ +/* 114 */ 0x00, 0x03, 0x01, /* GPR, CLBS soft reset */ +/* 117 */ 0x00, 0x03, 0x03, /* GPR, CLBS soft reset */ +/* 120 */ 0xff, 0x64, 0x00, /* Sleep 100ms */ +/* 123 */ 0xff, 0xff, 0xff +}; + dprintk("DVB: TDA10023(%d): init chip\n", fe->dvb->num); + + /* override default values if set in config */ + if (state->config->deltaf) { + tda10023_inittab[80] = (state->config->deltaf & 0xff); + tda10023_inittab[83] = (state->config->deltaf >> 8); + } - dprintk("DVB: TDA10023(%d): init chip\n", fe->adapter->num); + if (state->config->output_mode) + tda10023_inittab[95] = state->config->output_mode; tda10023_writetab(state, tda10023_inittab); @@ -460,12 +478,11 @@ static void tda10023_release(struct dvb_frontend* fe) static struct dvb_frontend_ops tda10023_ops; -struct dvb_frontend* tda10023_attach(const struct tda1002x_config* config, - struct i2c_adapter* i2c, +struct dvb_frontend *tda10023_attach(const struct tda10023_config *config, + struct i2c_adapter *i2c, u8 pwm) { struct tda10023_state* state = NULL; - int i; /* allocate memory for the internal state */ state = kzalloc(sizeof(struct tda10023_state), GFP_KERNEL); @@ -474,22 +491,40 @@ struct dvb_frontend* tda10023_attach(const struct tda1002x_config* config, /* setup the state */ state->config = config; state->i2c = i2c; - memcpy(&state->frontend.ops, &tda10023_ops, sizeof(struct dvb_frontend_ops)); - state->pwm = pwm; - for (i=0; i < ARRAY_SIZE(tda10023_inittab);i+=3) { - if (tda10023_inittab[i] == 0x00) { - state->reg0 = tda10023_inittab[i+2]; - break; - } - } - // Wakeup if in standby + /* wakeup if in standby */ tda10023_writereg (state, 0x00, 0x33); /* check if the demod is there */ if ((tda10023_readreg(state, 0x1a) & 0xf0) != 0x70) goto error; /* create dvb_frontend */ memcpy(&state->frontend.ops, &tda10023_ops, sizeof(struct dvb_frontend_ops)); + state->pwm = pwm; + state->reg0 = REG0_INIT_VAL; + if (state->config->xtal) { + state->xtal = state->config->xtal; + state->pll_m = state->config->pll_m; + state->pll_p = state->config->pll_p; + state->pll_n = state->config->pll_n; + } else { + /* set default values if not defined in config */ + state->xtal = 28920000; + state->pll_m = 8; + state->pll_p = 4; + state->pll_n = 1; + } + + /* calc sysclk */ + state->sysclk = (state->xtal * state->pll_m / \ + (state->pll_n * state->pll_p)); + + state->frontend.ops.info.symbol_rate_min = (state->sysclk/2)/64; + state->frontend.ops.info.symbol_rate_max = (state->sysclk/2)/4; + + dprintk("DVB: TDA10023 %s: xtal:%d pll_m:%d pll_p:%d pll_n:%d\n", + __func__, state->xtal, state->pll_m, state->pll_p, + state->pll_n); + state->frontend.demodulator_priv = state; return &state->frontend; @@ -504,10 +539,10 @@ static struct dvb_frontend_ops tda10023_ops = { .name = "Philips TDA10023 DVB-C", .type = FE_QAM, .frequency_stepsize = 62500, - .frequency_min = 47000000, + .frequency_min = 47000000, .frequency_max = 862000000, - .symbol_rate_min = (SYSCLK/2)/64, /* SACLK/64 == (SYSCLK/2)/64 */ - .symbol_rate_max = (SYSCLK/2)/4, /* SACLK/4 */ + .symbol_rate_min = 0, /* set in tda10023_attach */ + .symbol_rate_max = 0, /* set in tda10023_attach */ .caps = 0x400 | //FE_CAN_QAM_4 FE_CAN_QAM_16 | FE_CAN_QAM_32 | FE_CAN_QAM_64 | FE_CAN_QAM_128 | FE_CAN_QAM_256 | diff --git a/drivers/media/dvb/frontends/tda1002x.h b/drivers/media/dvb/frontends/tda1002x.h index 1bcc0d44b90b..04d19418bf20 100644 --- a/drivers/media/dvb/frontends/tda1002x.h +++ b/drivers/media/dvb/frontends/tda1002x.h @@ -26,13 +26,37 @@ #include <linux/dvb/frontend.h> -struct tda1002x_config -{ +struct tda1002x_config { /* the demodulator's i2c address */ u8 demod_address; u8 invert; }; +enum tda10023_output_mode { + TDA10023_OUTPUT_MODE_PARALLEL_A = 0xe0, + TDA10023_OUTPUT_MODE_PARALLEL_B = 0xa1, + TDA10023_OUTPUT_MODE_PARALLEL_C = 0xa0, + TDA10023_OUTPUT_MODE_SERIAL, /* TODO: not implemented */ +}; + +struct tda10023_config { + /* the demodulator's i2c address */ + u8 demod_address; + u8 invert; + + /* clock settings */ + u32 xtal; /* defaults: 28920000 */ + u8 pll_m; /* defaults: 8 */ + u8 pll_p; /* defaults: 4 */ + u8 pll_n; /* defaults: 1 */ + + /* MPEG2 TS output mode */ + u8 output_mode; + + /* input freq offset + baseband conversion type */ + u16 deltaf; +}; + #if defined(CONFIG_DVB_TDA10021) || (defined(CONFIG_DVB_TDA10021_MODULE) && defined(MODULE)) extern struct dvb_frontend* tda10021_attach(const struct tda1002x_config* config, struct i2c_adapter* i2c, u8 pwm); @@ -45,12 +69,15 @@ static inline struct dvb_frontend* tda10021_attach(const struct tda1002x_config* } #endif // CONFIG_DVB_TDA10021 -#if defined(CONFIG_DVB_TDA10023) || (defined(CONFIG_DVB_TDA10023_MODULE) && defined(MODULE)) -extern struct dvb_frontend* tda10023_attach(const struct tda1002x_config* config, - struct i2c_adapter* i2c, u8 pwm); +#if defined(CONFIG_DVB_TDA10023) || \ + (defined(CONFIG_DVB_TDA10023_MODULE) && defined(MODULE)) +extern struct dvb_frontend *tda10023_attach( + const struct tda10023_config *config, + struct i2c_adapter *i2c, u8 pwm); #else -static inline struct dvb_frontend* tda10023_attach(const struct tda1002x_config* config, - struct i2c_adapter* i2c, u8 pwm) +static inline struct dvb_frontend *tda10023_attach( + const struct tda10023_config *config, + struct i2c_adapter *i2c, u8 pwm) { printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); return NULL; diff --git a/drivers/media/dvb/pluto2/pluto2.c b/drivers/media/dvb/pluto2/pluto2.c index 960ed5763ae1..1360403b88b6 100644 --- a/drivers/media/dvb/pluto2/pluto2.c +++ b/drivers/media/dvb/pluto2/pluto2.c @@ -234,7 +234,7 @@ static void pluto_reset_ts(struct pluto *pluto, int reenable) static void pluto_set_dma_addr(struct pluto *pluto) { - pluto_writereg(pluto, REG_PCAR, cpu_to_le32(pluto->dma_addr)); + pluto_writereg(pluto, REG_PCAR, pluto->dma_addr); } static int __devinit pluto_dma_map(struct pluto *pluto) diff --git a/drivers/media/dvb/siano/Kconfig b/drivers/media/dvb/siano/Kconfig new file mode 100644 index 000000000000..dd863f261672 --- /dev/null +++ b/drivers/media/dvb/siano/Kconfig @@ -0,0 +1,26 @@ +# +# Siano Mobile Silicon Digital TV device configuration +# + +config DVB_SIANO_SMS1XXX + tristate "Siano SMS1XXX USB dongle support" + depends on DVB_CORE && USB + ---help--- + Choose Y here if you have a USB dongle with a SMS1XXX chipset. + + To compile this driver as a module, choose M here: the + module will be called sms1xxx. + +config DVB_SIANO_SMS1XXX_SMS_IDS + bool "Enable support for Siano Mobile Silicon default USB IDs" + depends on DVB_SIANO_SMS1XXX + default y + ---help--- + Choose Y here if you have a USB dongle with a SMS1XXX chipset + that uses Siano Mobile Silicon's default usb vid:pid. + + Choose N here if you would prefer to use Siano's external driver. + + Further documentation on this driver can be found on the WWW at + <http://www.siano-ms.com/>. + diff --git a/drivers/media/dvb/siano/Makefile b/drivers/media/dvb/siano/Makefile new file mode 100644 index 000000000000..ee0737af98c0 --- /dev/null +++ b/drivers/media/dvb/siano/Makefile @@ -0,0 +1,8 @@ +sms1xxx-objs := smscoreapi.o smsusb.o smsdvb.o sms-cards.o + +obj-$(CONFIG_DVB_SIANO_SMS1XXX) += sms1xxx.o + +EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core + +EXTRA_CFLAGS += $(extra-cflags-y) $(extra-cflags-m) + diff --git a/drivers/media/dvb/siano/sms-cards.c b/drivers/media/dvb/siano/sms-cards.c new file mode 100644 index 000000000000..e7a8ac0c4049 --- /dev/null +++ b/drivers/media/dvb/siano/sms-cards.c @@ -0,0 +1,102 @@ +/* + * Card-specific functions for the Siano SMS1xxx USB dongle + * + * Copyright (c) 2008 Michael Krufky <mkrufky@linuxtv.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 3 as + * published by the Free Software Foundation; + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. + * + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "sms-cards.h" + +struct usb_device_id smsusb_id_table[] = { +#ifdef CONFIG_DVB_SIANO_SMS1XXX_SMS_IDS + { USB_DEVICE(0x187f, 0x0010), + .driver_info = SMS1XXX_BOARD_SIANO_STELLAR }, + { USB_DEVICE(0x187f, 0x0100), + .driver_info = SMS1XXX_BOARD_SIANO_STELLAR }, + { USB_DEVICE(0x187f, 0x0200), + .driver_info = SMS1XXX_BOARD_SIANO_NOVA_A }, + { USB_DEVICE(0x187f, 0x0201), + .driver_info = SMS1XXX_BOARD_SIANO_NOVA_B }, + { USB_DEVICE(0x187f, 0x0300), + .driver_info = SMS1XXX_BOARD_SIANO_VEGA }, +#endif + { USB_DEVICE(0x2040, 0x1700), + .driver_info = SMS1XXX_BOARD_HAUPPAUGE_CATAMOUNT }, + { USB_DEVICE(0x2040, 0x1800), + .driver_info = SMS1XXX_BOARD_HAUPPAUGE_OKEMO_A }, + { USB_DEVICE(0x2040, 0x1801), + .driver_info = SMS1XXX_BOARD_HAUPPAUGE_OKEMO_B }, + { USB_DEVICE(0x2040, 0x5500), + .driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM }, + { USB_DEVICE(0x2040, 0x5580), + .driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM }, + { USB_DEVICE(0x2040, 0x5590), + .driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM }, + { } /* Terminating entry */ +}; +MODULE_DEVICE_TABLE(usb, smsusb_id_table); + +static struct sms_board sms_boards[] = { + [SMS_BOARD_UNKNOWN] = { + .name = "Unknown board", + }, + [SMS1XXX_BOARD_SIANO_STELLAR] = { + .name = "Siano Stellar Digital Receiver", + .type = SMS_STELLAR, + .fw[DEVICE_MODE_DVBT_BDA] = "sms1xxx-stellar-dvbt-01.fw", + }, + [SMS1XXX_BOARD_SIANO_NOVA_A] = { + .name = "Siano Nova A Digital Receiver", + .type = SMS_NOVA_A0, + .fw[DEVICE_MODE_DVBT_BDA] = "sms1xxx-nova-a-dvbt-01.fw", + }, + [SMS1XXX_BOARD_SIANO_NOVA_B] = { + .name = "Siano Nova B Digital Receiver", + .type = SMS_NOVA_B0, + .fw[DEVICE_MODE_DVBT_BDA] = "sms1xxx-nova-b-dvbt-01.fw", + }, + [SMS1XXX_BOARD_SIANO_VEGA] = { + .name = "Siano Vega Digital Receiver", + .type = SMS_VEGA, + }, + [SMS1XXX_BOARD_HAUPPAUGE_CATAMOUNT] = { + .name = "Hauppauge Catamount", + .type = SMS_STELLAR, + .fw[DEVICE_MODE_DVBT_BDA] = "sms1xxx-stellar-dvbt-01.fw", + }, + [SMS1XXX_BOARD_HAUPPAUGE_OKEMO_A] = { + .name = "Hauppauge Okemo-A", + .type = SMS_NOVA_A0, + .fw[DEVICE_MODE_DVBT_BDA] = "sms1xxx-nova-a-dvbt-01.fw", + }, + [SMS1XXX_BOARD_HAUPPAUGE_OKEMO_B] = { + .name = "Hauppauge Okemo-B", + .type = SMS_NOVA_B0, + .fw[DEVICE_MODE_DVBT_BDA] = "sms1xxx-nova-b-dvbt-01.fw", + }, + [SMS1XXX_BOARD_HAUPPAUGE_WINDHAM] = { + .name = "Hauppauge WinTV-Nova-T-MiniStick", + .type = SMS_NOVA_B0, + .fw[DEVICE_MODE_DVBT_BDA] = "sms1xxx-hcw-55xxx-dvbt-01.fw", + }, +}; + +struct sms_board *sms_get_board(int id) +{ + BUG_ON(id >= ARRAY_SIZE(sms_boards)); + + return &sms_boards[id]; +} + diff --git a/drivers/media/dvb/siano/sms-cards.h b/drivers/media/dvb/siano/sms-cards.h new file mode 100644 index 000000000000..83b39bc203fe --- /dev/null +++ b/drivers/media/dvb/siano/sms-cards.h @@ -0,0 +1,45 @@ +/* + * Card-specific functions for the Siano SMS1xxx USB dongle + * + * Copyright (c) 2008 Michael Krufky <mkrufky@linuxtv.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 3 as + * published by the Free Software Foundation; + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. + * + * 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 __SMS_CARDS_H__ +#define __SMS_CARDS_H__ + +#include <linux/usb.h> +#include "smscoreapi.h" + +#define SMS_BOARD_UNKNOWN 0 +#define SMS1XXX_BOARD_SIANO_STELLAR 1 +#define SMS1XXX_BOARD_SIANO_NOVA_A 2 +#define SMS1XXX_BOARD_SIANO_NOVA_B 3 +#define SMS1XXX_BOARD_SIANO_VEGA 4 +#define SMS1XXX_BOARD_HAUPPAUGE_CATAMOUNT 5 +#define SMS1XXX_BOARD_HAUPPAUGE_OKEMO_A 6 +#define SMS1XXX_BOARD_HAUPPAUGE_OKEMO_B 7 +#define SMS1XXX_BOARD_HAUPPAUGE_WINDHAM 8 + +struct sms_board { + enum sms_device_type_st type; + char *name, *fw[DEVICE_MODE_MAX]; +}; + +struct sms_board *sms_get_board(int id); + +extern struct usb_device_id smsusb_id_table[]; + +#endif /* __SMS_CARDS_H__ */ diff --git a/drivers/media/dvb/siano/smscoreapi.c b/drivers/media/dvb/siano/smscoreapi.c new file mode 100644 index 000000000000..b4b8ed795c95 --- /dev/null +++ b/drivers/media/dvb/siano/smscoreapi.c @@ -0,0 +1,1251 @@ +/* + * Siano core API module + * + * This file contains implementation for the interface to sms core component + * + * author: Anatoly Greenblat + * + * Copyright (c), 2005-2008 Siano Mobile Silicon, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 3 as + * published by the Free Software Foundation; + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. + * + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/dma-mapping.h> +#include <linux/delay.h> +#include <linux/io.h> + +#include <linux/firmware.h> + +#include "smscoreapi.h" +#include "sms-cards.h" + +int sms_debug; +module_param_named(debug, sms_debug, int, 0644); +MODULE_PARM_DESC(debug, "set debug level (info=1, adv=2 (or-able))"); + +struct smscore_device_notifyee_t { + struct list_head entry; + hotplug_t hotplug; +}; + +struct smscore_idlist_t { + struct list_head entry; + int id; + int data_type; +}; + +struct smscore_client_t { + struct list_head entry; + struct smscore_device_t *coredev; + void *context; + struct list_head idlist; + onresponse_t onresponse_handler; + onremove_t onremove_handler; +}; + +struct smscore_device_t { + struct list_head entry; + + struct list_head clients; + struct list_head subclients; + spinlock_t clientslock; + + struct list_head buffers; + spinlock_t bufferslock; + int num_buffers; + + void *common_buffer; + int common_buffer_size; + dma_addr_t common_buffer_phys; + + void *context; + struct device *device; + + char devpath[32]; + unsigned long device_flags; + + setmode_t setmode_handler; + detectmode_t detectmode_handler; + sendrequest_t sendrequest_handler; + preload_t preload_handler; + postload_t postload_handler; + + int mode, modes_supported; + + struct completion version_ex_done, data_download_done, trigger_done; + struct completion init_device_done, reload_start_done, resume_done; + + int board_id; +}; + +void smscore_set_board_id(struct smscore_device_t *core, int id) +{ + core->board_id = id; +} + +int smscore_get_board_id(struct smscore_device_t *core) +{ + return core->board_id; +} + +struct smscore_registry_entry_t { + struct list_head entry; + char devpath[32]; + int mode; + enum sms_device_type_st type; +}; + +struct list_head g_smscore_notifyees; +struct list_head g_smscore_devices; +struct mutex g_smscore_deviceslock; + +struct list_head g_smscore_registry; +struct mutex g_smscore_registrylock; + +static int default_mode = 4; + +module_param(default_mode, int, 0644); +MODULE_PARM_DESC(default_mode, "default firmware id (device mode)"); + +static struct smscore_registry_entry_t *smscore_find_registry(char *devpath) +{ + struct smscore_registry_entry_t *entry; + struct list_head *next; + + kmutex_lock(&g_smscore_registrylock); + for (next = g_smscore_registry.next; + next != &g_smscore_registry; + next = next->next) { + entry = (struct smscore_registry_entry_t *) next; + if (!strcmp(entry->devpath, devpath)) { + kmutex_unlock(&g_smscore_registrylock); + return entry; + } + } + entry = (struct smscore_registry_entry_t *) + kmalloc(sizeof(struct smscore_registry_entry_t), + GFP_KERNEL); + if (entry) { + entry->mode = default_mode; + strcpy(entry->devpath, devpath); + list_add(&entry->entry, &g_smscore_registry); + } else + sms_err("failed to create smscore_registry."); + kmutex_unlock(&g_smscore_registrylock); + return entry; +} + +int smscore_registry_getmode(char *devpath) +{ + struct smscore_registry_entry_t *entry; + + entry = smscore_find_registry(devpath); + if (entry) + return entry->mode; + else + sms_err("No registry found."); + + return default_mode; +} + +static enum sms_device_type_st smscore_registry_gettype(char *devpath) +{ + struct smscore_registry_entry_t *entry; + + entry = smscore_find_registry(devpath); + if (entry) + return entry->type; + else + sms_err("No registry found."); + + return -1; +} + +void smscore_registry_setmode(char *devpath, int mode) +{ + struct smscore_registry_entry_t *entry; + + entry = smscore_find_registry(devpath); + if (entry) + entry->mode = mode; + else + sms_err("No registry found."); +} + +static void smscore_registry_settype(char *devpath, + enum sms_device_type_st type) +{ + struct smscore_registry_entry_t *entry; + + entry = smscore_find_registry(devpath); + if (entry) + entry->type = type; + else + sms_err("No registry found."); +} + + +static void list_add_locked(struct list_head *new, struct list_head *head, + spinlock_t *lock) +{ + unsigned long flags; + + spin_lock_irqsave(lock, flags); + + list_add(new, head); + + spin_unlock_irqrestore(lock, flags); +} + +/** + * register a client callback that called when device plugged in/unplugged + * NOTE: if devices exist callback is called immediately for each device + * + * @param hotplug callback + * + * @return 0 on success, <0 on error. + */ +int smscore_register_hotplug(hotplug_t hotplug) +{ + struct smscore_device_notifyee_t *notifyee; + struct list_head *next, *first; + int rc = 0; + + kmutex_lock(&g_smscore_deviceslock); + + notifyee = kmalloc(sizeof(struct smscore_device_notifyee_t), + GFP_KERNEL); + if (notifyee) { + /* now notify callback about existing devices */ + first = &g_smscore_devices; + for (next = first->next; + next != first && !rc; + next = next->next) { + struct smscore_device_t *coredev = + (struct smscore_device_t *) next; + rc = hotplug(coredev, coredev->device, 1); + } + + if (rc >= 0) { + notifyee->hotplug = hotplug; + list_add(¬ifyee->entry, &g_smscore_notifyees); + } else + kfree(notifyee); + } else + rc = -ENOMEM; + + kmutex_unlock(&g_smscore_deviceslock); + + return rc; +} + +/** + * unregister a client callback that called when device plugged in/unplugged + * + * @param hotplug callback + * + */ +void smscore_unregister_hotplug(hotplug_t hotplug) +{ + struct list_head *next, *first; + + kmutex_lock(&g_smscore_deviceslock); + + first = &g_smscore_notifyees; + + for (next = first->next; next != first;) { + struct smscore_device_notifyee_t *notifyee = + (struct smscore_device_notifyee_t *) next; + next = next->next; + + if (notifyee->hotplug == hotplug) { + list_del(¬ifyee->entry); + kfree(notifyee); + } + } + + kmutex_unlock(&g_smscore_deviceslock); +} + +static void smscore_notify_clients(struct smscore_device_t *coredev) +{ + struct smscore_client_t *client; + + /* the client must call smscore_unregister_client from remove handler */ + while (!list_empty(&coredev->clients)) { + client = (struct smscore_client_t *) coredev->clients.next; + client->onremove_handler(client->context); + } +} + +static int smscore_notify_callbacks(struct smscore_device_t *coredev, + struct device *device, int arrival) +{ + struct list_head *next, *first; + int rc = 0; + + /* note: must be called under g_deviceslock */ + + first = &g_smscore_notifyees; + + for (next = first->next; next != first; next = next->next) { + rc = ((struct smscore_device_notifyee_t *) next)-> + hotplug(coredev, device, arrival); + if (rc < 0) + break; + } + + return rc; +} + +static struct +smscore_buffer_t *smscore_createbuffer(u8 *buffer, void *common_buffer, + dma_addr_t common_buffer_phys) +{ + struct smscore_buffer_t *cb = + kmalloc(sizeof(struct smscore_buffer_t), GFP_KERNEL); + if (!cb) { + sms_info("kmalloc(...) failed"); + return NULL; + } + + cb->p = buffer; + cb->offset_in_common = buffer - (u8 *) common_buffer; + cb->phys = common_buffer_phys + cb->offset_in_common; + + return cb; +} + +/** + * creates coredev object for a device, prepares buffers, + * creates buffer mappings, notifies registered hotplugs about new device. + * + * @param params device pointer to struct with device specific parameters + * and handlers + * @param coredev pointer to a value that receives created coredev object + * + * @return 0 on success, <0 on error. + */ +int smscore_register_device(struct smsdevice_params_t *params, + struct smscore_device_t **coredev) +{ + struct smscore_device_t *dev; + u8 *buffer; + + dev = kzalloc(sizeof(struct smscore_device_t), GFP_KERNEL); + if (!dev) { + sms_info("kzalloc(...) failed"); + return -ENOMEM; + } + + /* init list entry so it could be safe in smscore_unregister_device */ + INIT_LIST_HEAD(&dev->entry); + + /* init queues */ + INIT_LIST_HEAD(&dev->clients); + INIT_LIST_HEAD(&dev->buffers); + + /* init locks */ + spin_lock_init(&dev->clientslock); + spin_lock_init(&dev->bufferslock); + + /* init completion events */ + init_completion(&dev->version_ex_done); + init_completion(&dev->data_download_done); + init_completion(&dev->trigger_done); + init_completion(&dev->init_device_done); + init_completion(&dev->reload_start_done); + init_completion(&dev->resume_done); + + /* alloc common buffer */ + dev->common_buffer_size = params->buffer_size * params->num_buffers; + dev->common_buffer = dma_alloc_coherent(NULL, dev->common_buffer_size, + &dev->common_buffer_phys, + GFP_KERNEL | GFP_DMA); + if (!dev->common_buffer) { + smscore_unregister_device(dev); + return -ENOMEM; + } + + /* prepare dma buffers */ + for (buffer = dev->common_buffer; + dev->num_buffers < params->num_buffers; + dev->num_buffers++, buffer += params->buffer_size) { + struct smscore_buffer_t *cb = + smscore_createbuffer(buffer, dev->common_buffer, + dev->common_buffer_phys); + if (!cb) { + smscore_unregister_device(dev); + return -ENOMEM; + } + + smscore_putbuffer(dev, cb); + } + + sms_info("allocated %d buffers", dev->num_buffers); + + dev->mode = DEVICE_MODE_NONE; + dev->context = params->context; + dev->device = params->device; + dev->setmode_handler = params->setmode_handler; + dev->detectmode_handler = params->detectmode_handler; + dev->sendrequest_handler = params->sendrequest_handler; + dev->preload_handler = params->preload_handler; + dev->postload_handler = params->postload_handler; + + dev->device_flags = params->flags; + strcpy(dev->devpath, params->devpath); + + smscore_registry_settype(dev->devpath, params->device_type); + + /* add device to devices list */ + kmutex_lock(&g_smscore_deviceslock); + list_add(&dev->entry, &g_smscore_devices); + kmutex_unlock(&g_smscore_deviceslock); + + *coredev = dev; + + sms_info("device %p created", dev); + + return 0; +} + +/** + * sets initial device mode and notifies client hotplugs that device is ready + * + * @param coredev pointer to a coredev object returned by + * smscore_register_device + * + * @return 0 on success, <0 on error. + */ +int smscore_start_device(struct smscore_device_t *coredev) +{ + int rc = smscore_set_device_mode( + coredev, smscore_registry_getmode(coredev->devpath)); + if (rc < 0) { + sms_info("set device mode faile , rc %d", rc); + return rc; + } + + kmutex_lock(&g_smscore_deviceslock); + + rc = smscore_notify_callbacks(coredev, coredev->device, 1); + + sms_info("device %p started, rc %d", coredev, rc); + + kmutex_unlock(&g_smscore_deviceslock); + + return rc; +} + +static int smscore_sendrequest_and_wait(struct smscore_device_t *coredev, + void *buffer, size_t size, + struct completion *completion) +{ + int rc = coredev->sendrequest_handler(coredev->context, buffer, size); + if (rc < 0) { + sms_info("sendrequest returned error %d", rc); + return rc; + } + + return wait_for_completion_timeout(completion, + msecs_to_jiffies(10000)) ? + 0 : -ETIME; +} + +static int smscore_load_firmware_family2(struct smscore_device_t *coredev, + void *buffer, size_t size) +{ + struct SmsFirmware_ST *firmware = (struct SmsFirmware_ST *) buffer; + struct SmsMsgHdr_ST *msg; + u32 mem_address = firmware->StartAddress; + u8 *payload = firmware->Payload; + int rc = 0; + + sms_info("loading FW to addr 0x%x size %d", + mem_address, firmware->Length); + if (coredev->preload_handler) { + rc = coredev->preload_handler(coredev->context); + if (rc < 0) + return rc; + } + + /* PAGE_SIZE buffer shall be enough and dma aligned */ + msg = kmalloc(PAGE_SIZE, GFP_KERNEL | GFP_DMA); + if (!msg) + return -ENOMEM; + + if (coredev->mode != DEVICE_MODE_NONE) { + sms_debug("sending reload command."); + SMS_INIT_MSG(msg, MSG_SW_RELOAD_START_REQ, + sizeof(struct SmsMsgHdr_ST)); + rc = smscore_sendrequest_and_wait(coredev, msg, + msg->msgLength, + &coredev->reload_start_done); + mem_address = *(u32 *) &payload[20]; + } + + while (size && rc >= 0) { + struct SmsDataDownload_ST *DataMsg = + (struct SmsDataDownload_ST *) msg; + int payload_size = min((int) size, SMS_MAX_PAYLOAD_SIZE); + + SMS_INIT_MSG(msg, MSG_SMS_DATA_DOWNLOAD_REQ, + (u16)(sizeof(struct SmsMsgHdr_ST) + + sizeof(u32) + payload_size)); + + DataMsg->MemAddr = mem_address; + memcpy(DataMsg->Payload, payload, payload_size); + + if ((coredev->device_flags & SMS_ROM_NO_RESPONSE) && + (coredev->mode == DEVICE_MODE_NONE)) + rc = coredev->sendrequest_handler( + coredev->context, DataMsg, + DataMsg->xMsgHeader.msgLength); + else + rc = smscore_sendrequest_and_wait( + coredev, DataMsg, + DataMsg->xMsgHeader.msgLength, + &coredev->data_download_done); + + payload += payload_size; + size -= payload_size; + mem_address += payload_size; + } + + if (rc >= 0) { + if (coredev->mode == DEVICE_MODE_NONE) { + struct SmsMsgData_ST *TriggerMsg = + (struct SmsMsgData_ST *) msg; + + SMS_INIT_MSG(msg, MSG_SMS_SWDOWNLOAD_TRIGGER_REQ, + sizeof(struct SmsMsgHdr_ST) + + sizeof(u32) * 5); + + TriggerMsg->msgData[0] = firmware->StartAddress; + /* Entry point */ + TriggerMsg->msgData[1] = 5; /* Priority */ + TriggerMsg->msgData[2] = 0x200; /* Stack size */ + TriggerMsg->msgData[3] = 0; /* Parameter */ + TriggerMsg->msgData[4] = 4; /* Task ID */ + + if (coredev->device_flags & SMS_ROM_NO_RESPONSE) { + rc = coredev->sendrequest_handler( + coredev->context, TriggerMsg, + TriggerMsg->xMsgHeader.msgLength); + msleep(100); + } else + rc = smscore_sendrequest_and_wait( + coredev, TriggerMsg, + TriggerMsg->xMsgHeader.msgLength, + &coredev->trigger_done); + } else { + SMS_INIT_MSG(msg, MSG_SW_RELOAD_EXEC_REQ, + sizeof(struct SmsMsgHdr_ST)); + + rc = coredev->sendrequest_handler(coredev->context, + msg, msg->msgLength); + } + msleep(500); + } + + sms_debug("rc=%d, postload=%p ", rc, + coredev->postload_handler); + + kfree(msg); + + return ((rc >= 0) && coredev->postload_handler) ? + coredev->postload_handler(coredev->context) : + rc; +} + +/** + * loads specified firmware into a buffer and calls device loadfirmware_handler + * + * @param coredev pointer to a coredev object returned by + * smscore_register_device + * @param filename null-terminated string specifies firmware file name + * @param loadfirmware_handler device handler that loads firmware + * + * @return 0 on success, <0 on error. + */ +static int smscore_load_firmware_from_file(struct smscore_device_t *coredev, + char *filename, + loadfirmware_t loadfirmware_handler) +{ + int rc = -ENOENT; + const struct firmware *fw; + u8 *fw_buffer; + + if (loadfirmware_handler == NULL && !(coredev->device_flags & + SMS_DEVICE_FAMILY2)) + return -EINVAL; + + rc = request_firmware(&fw, filename, coredev->device); + if (rc < 0) { + sms_info("failed to open \"%s\"", filename); + return rc; + } + sms_info("read FW %s, size=%zd", filename, fw->size); + fw_buffer = kmalloc(ALIGN(fw->size, SMS_ALLOC_ALIGNMENT), + GFP_KERNEL | GFP_DMA); + if (fw_buffer) { + memcpy(fw_buffer, fw->data, fw->size); + + rc = (coredev->device_flags & SMS_DEVICE_FAMILY2) ? + smscore_load_firmware_family2(coredev, + fw_buffer, + fw->size) : + loadfirmware_handler(coredev->context, + fw_buffer, fw->size); + + kfree(fw_buffer); + } else { + sms_info("failed to allocate firmware buffer"); + rc = -ENOMEM; + } + + release_firmware(fw); + + return rc; +} + +/** + * notifies all clients registered with the device, notifies hotplugs, + * frees all buffers and coredev object + * + * @param coredev pointer to a coredev object returned by + * smscore_register_device + * + * @return 0 on success, <0 on error. + */ +void smscore_unregister_device(struct smscore_device_t *coredev) +{ + struct smscore_buffer_t *cb; + int num_buffers = 0; + int retry = 0; + + kmutex_lock(&g_smscore_deviceslock); + + smscore_notify_clients(coredev); + smscore_notify_callbacks(coredev, NULL, 0); + + /* at this point all buffers should be back + * onresponse must no longer be called */ + + while (1) { + while ((cb = smscore_getbuffer(coredev))) { + kfree(cb); + num_buffers++; + } + if (num_buffers == coredev->num_buffers) + break; + if (++retry > 10) { + sms_info("exiting although " + "not all buffers released."); + break; + } + + sms_info("waiting for %d buffer(s)", + coredev->num_buffers - num_buffers); + msleep(100); + } + + sms_info("freed %d buffers", num_buffers); + + if (coredev->common_buffer) + dma_free_coherent(NULL, coredev->common_buffer_size, + coredev->common_buffer, + coredev->common_buffer_phys); + + list_del(&coredev->entry); + kfree(coredev); + + kmutex_unlock(&g_smscore_deviceslock); + + sms_info("device %p destroyed", coredev); +} + +static int smscore_detect_mode(struct smscore_device_t *coredev) +{ + void *buffer = kmalloc(sizeof(struct SmsMsgHdr_ST) + SMS_DMA_ALIGNMENT, + GFP_KERNEL | GFP_DMA); + struct SmsMsgHdr_ST *msg = + (struct SmsMsgHdr_ST *) SMS_ALIGN_ADDRESS(buffer); + int rc; + + if (!buffer) + return -ENOMEM; + + SMS_INIT_MSG(msg, MSG_SMS_GET_VERSION_EX_REQ, + sizeof(struct SmsMsgHdr_ST)); + + rc = smscore_sendrequest_and_wait(coredev, msg, msg->msgLength, + &coredev->version_ex_done); + if (rc == -ETIME) { + sms_err("MSG_SMS_GET_VERSION_EX_REQ failed first try"); + + if (wait_for_completion_timeout(&coredev->resume_done, + msecs_to_jiffies(5000))) { + rc = smscore_sendrequest_and_wait( + coredev, msg, msg->msgLength, + &coredev->version_ex_done); + if (rc < 0) + sms_err("MSG_SMS_GET_VERSION_EX_REQ failed " + "second try, rc %d", rc); + } else + rc = -ETIME; + } + + kfree(buffer); + + return rc; +} + +static char *smscore_fw_lkup[][SMS_NUM_OF_DEVICE_TYPES] = { + /*Stellar NOVA A0 Nova B0 VEGA*/ + /*DVBT*/ + {"none", "dvb_nova_12mhz.inp", "dvb_nova_12mhz_b0.inp", "none"}, + /*DVBH*/ + {"none", "dvb_nova_12mhz.inp", "dvb_nova_12mhz_b0.inp", "none"}, + /*TDMB*/ + {"none", "tdmb_nova_12mhz.inp", "none", "none"}, + /*DABIP*/ + {"none", "none", "none", "none"}, + /*BDA*/ + {"none", "dvb_nova_12mhz.inp", "dvb_nova_12mhz_b0.inp", "none"}, + /*ISDBT*/ + {"none", "isdbt_nova_12mhz.inp", "dvb_nova_12mhz.inp", "none"}, + /*ISDBTBDA*/ + {"none", "isdbt_nova_12mhz.inp", "isdbt_nova_12mhz_b0.inp", "none"}, + /*CMMB*/ + {"none", "none", "none", "cmmb_vega_12mhz.inp"} +}; + +static inline char *sms_get_fw_name(struct smscore_device_t *coredev, + int mode, enum sms_device_type_st type) +{ + char **fw = sms_get_board(smscore_get_board_id(coredev))->fw; + return (fw && fw[mode]) ? fw[mode] : smscore_fw_lkup[mode][type]; +} + +/** + * calls device handler to change mode of operation + * NOTE: stellar/usb may disconnect when changing mode + * + * @param coredev pointer to a coredev object returned by + * smscore_register_device + * @param mode requested mode of operation + * + * @return 0 on success, <0 on error. + */ +int smscore_set_device_mode(struct smscore_device_t *coredev, int mode) +{ + void *buffer; + int rc = 0; + enum sms_device_type_st type; + + sms_debug("set device mode to %d", mode); + if (coredev->device_flags & SMS_DEVICE_FAMILY2) { + if (mode < DEVICE_MODE_DVBT || mode > DEVICE_MODE_RAW_TUNER) { + sms_err("invalid mode specified %d", mode); + return -EINVAL; + } + + smscore_registry_setmode(coredev->devpath, mode); + + if (!(coredev->device_flags & SMS_DEVICE_NOT_READY)) { + rc = smscore_detect_mode(coredev); + if (rc < 0) { + sms_err("mode detect failed %d", rc); + return rc; + } + } + + if (coredev->mode == mode) { + sms_info("device mode %d already set", mode); + return 0; + } + + if (!(coredev->modes_supported & (1 << mode))) { + char *fw_filename; + + type = smscore_registry_gettype(coredev->devpath); + fw_filename = sms_get_fw_name(coredev, mode, type); + + rc = smscore_load_firmware_from_file(coredev, + fw_filename, NULL); + if (rc < 0) { + sms_warn("error %d loading firmware: %s, " + "trying again with default firmware", + rc, fw_filename); + + /* try again with the default firmware */ + fw_filename = smscore_fw_lkup[mode][type]; + rc = smscore_load_firmware_from_file(coredev, + fw_filename, NULL); + + if (rc < 0) { + sms_warn("error %d loading " + "firmware: %s", rc, + fw_filename); + return rc; + } + } + sms_log("firmware download success: %s", fw_filename); + } else + sms_info("mode %d supported by running " + "firmware", mode); + + buffer = kmalloc(sizeof(struct SmsMsgData_ST) + + SMS_DMA_ALIGNMENT, GFP_KERNEL | GFP_DMA); + if (buffer) { + struct SmsMsgData_ST *msg = + (struct SmsMsgData_ST *) + SMS_ALIGN_ADDRESS(buffer); + + SMS_INIT_MSG(&msg->xMsgHeader, MSG_SMS_INIT_DEVICE_REQ, + sizeof(struct SmsMsgData_ST)); + msg->msgData[0] = mode; + + rc = smscore_sendrequest_and_wait( + coredev, msg, msg->xMsgHeader.msgLength, + &coredev->init_device_done); + + kfree(buffer); + } else { + sms_err("Could not allocate buffer for " + "init device message."); + rc = -ENOMEM; + } + } else { + if (mode < DEVICE_MODE_DVBT || mode > DEVICE_MODE_DVBT_BDA) { + sms_err("invalid mode specified %d", mode); + return -EINVAL; + } + + smscore_registry_setmode(coredev->devpath, mode); + + if (coredev->detectmode_handler) + coredev->detectmode_handler(coredev->context, + &coredev->mode); + + if (coredev->mode != mode && coredev->setmode_handler) + rc = coredev->setmode_handler(coredev->context, mode); + } + + if (rc >= 0) { + coredev->mode = mode; + coredev->device_flags &= ~SMS_DEVICE_NOT_READY; + } + + if (rc != 0) + sms_err("return error code %d.", rc); + return rc; +} + +/** + * calls device handler to get current mode of operation + * + * @param coredev pointer to a coredev object returned by + * smscore_register_device + * + * @return current mode + */ +int smscore_get_device_mode(struct smscore_device_t *coredev) +{ + return coredev->mode; +} + +/** + * find client by response id & type within the clients list. + * return client handle or NULL. + * + * @param coredev pointer to a coredev object returned by + * smscore_register_device + * @param data_type client data type (SMS_DONT_CARE for all types) + * @param id client id (SMS_DONT_CARE for all id) + * + */ +static struct +smscore_client_t *smscore_find_client(struct smscore_device_t *coredev, + int data_type, int id) +{ + struct smscore_client_t *client = NULL; + struct list_head *next, *first; + unsigned long flags; + struct list_head *firstid, *nextid; + + + spin_lock_irqsave(&coredev->clientslock, flags); + first = &coredev->clients; + for (next = first->next; + (next != first) && !client; + next = next->next) { + firstid = &((struct smscore_client_t *)next)->idlist; + for (nextid = firstid->next; + nextid != firstid; + nextid = nextid->next) { + if ((((struct smscore_idlist_t *)nextid)->id == id) && + (((struct smscore_idlist_t *)nextid)->data_type == data_type || + (((struct smscore_idlist_t *)nextid)->data_type == 0))) { + client = (struct smscore_client_t *) next; + break; + } + } + } + spin_unlock_irqrestore(&coredev->clientslock, flags); + return client; +} + +/** + * find client by response id/type, call clients onresponse handler + * return buffer to pool on error + * + * @param coredev pointer to a coredev object returned by + * smscore_register_device + * @param cb pointer to response buffer descriptor + * + */ +void smscore_onresponse(struct smscore_device_t *coredev, + struct smscore_buffer_t *cb) +{ + struct SmsMsgHdr_ST *phdr = + (struct SmsMsgHdr_ST *)((u8 *) cb->p + cb->offset); + struct smscore_client_t *client = + smscore_find_client(coredev, phdr->msgType, phdr->msgDstId); + int rc = -EBUSY; + + static unsigned long last_sample_time; /* = 0; */ + static int data_total; /* = 0; */ + unsigned long time_now = jiffies_to_msecs(jiffies); + + if (!last_sample_time) + last_sample_time = time_now; + + if (time_now - last_sample_time > 10000) { + sms_debug("\ndata rate %d bytes/secs", + (int)((data_total * 1000) / + (time_now - last_sample_time))); + + last_sample_time = time_now; + data_total = 0; + } + + data_total += cb->size; + /* If no client registered for type & id, + * check for control client where type is not registered */ + if (client) + rc = client->onresponse_handler(client->context, cb); + + if (rc < 0) { + switch (phdr->msgType) { + case MSG_SMS_GET_VERSION_EX_RES: + { + struct SmsVersionRes_ST *ver = + (struct SmsVersionRes_ST *) phdr; + sms_debug("MSG_SMS_GET_VERSION_EX_RES " + "id %d prots 0x%x ver %d.%d", + ver->FirmwareId, ver->SupportedProtocols, + ver->RomVersionMajor, ver->RomVersionMinor); + + coredev->mode = ver->FirmwareId == 255 ? + DEVICE_MODE_NONE : ver->FirmwareId; + coredev->modes_supported = ver->SupportedProtocols; + + complete(&coredev->version_ex_done); + break; + } + case MSG_SMS_INIT_DEVICE_RES: + sms_debug("MSG_SMS_INIT_DEVICE_RES"); + complete(&coredev->init_device_done); + break; + case MSG_SW_RELOAD_START_RES: + sms_debug("MSG_SW_RELOAD_START_RES"); + complete(&coredev->reload_start_done); + break; + case MSG_SMS_DATA_DOWNLOAD_RES: + complete(&coredev->data_download_done); + break; + case MSG_SW_RELOAD_EXEC_RES: + sms_debug("MSG_SW_RELOAD_EXEC_RES"); + break; + case MSG_SMS_SWDOWNLOAD_TRIGGER_RES: + sms_debug("MSG_SMS_SWDOWNLOAD_TRIGGER_RES"); + complete(&coredev->trigger_done); + break; + case MSG_SMS_SLEEP_RESUME_COMP_IND: + complete(&coredev->resume_done); + break; + default: + break; + } + smscore_putbuffer(coredev, cb); + } +} + +/** + * return pointer to next free buffer descriptor from core pool + * + * @param coredev pointer to a coredev object returned by + * smscore_register_device + * + * @return pointer to descriptor on success, NULL on error. + */ +struct smscore_buffer_t *smscore_getbuffer(struct smscore_device_t *coredev) +{ + struct smscore_buffer_t *cb = NULL; + unsigned long flags; + + spin_lock_irqsave(&coredev->bufferslock, flags); + + if (!list_empty(&coredev->buffers)) { + cb = (struct smscore_buffer_t *) coredev->buffers.next; + list_del(&cb->entry); + } + + spin_unlock_irqrestore(&coredev->bufferslock, flags); + + return cb; +} + +/** + * return buffer descriptor to a pool + * + * @param coredev pointer to a coredev object returned by + * smscore_register_device + * @param cb pointer buffer descriptor + * + */ +void smscore_putbuffer(struct smscore_device_t *coredev, + struct smscore_buffer_t *cb) +{ + list_add_locked(&cb->entry, &coredev->buffers, &coredev->bufferslock); +} + +static int smscore_validate_client(struct smscore_device_t *coredev, + struct smscore_client_t *client, + int data_type, int id) +{ + struct smscore_idlist_t *listentry; + struct smscore_client_t *registered_client; + + if (!client) { + sms_err("bad parameter."); + return -EFAULT; + } + registered_client = smscore_find_client(coredev, data_type, id); + if (registered_client == client) + return 0; + + if (registered_client) { + sms_err("The msg ID already registered to another client."); + return -EEXIST; + } + listentry = kzalloc(sizeof(struct smscore_idlist_t), GFP_KERNEL); + if (!listentry) { + sms_err("Can't allocate memory for client id."); + return -ENOMEM; + } + listentry->id = id; + listentry->data_type = data_type; + list_add_locked(&listentry->entry, &client->idlist, + &coredev->clientslock); + return 0; +} + +/** + * creates smsclient object, check that id is taken by another client + * + * @param coredev pointer to a coredev object from clients hotplug + * @param initial_id all messages with this id would be sent to this client + * @param data_type all messages of this type would be sent to this client + * @param onresponse_handler client handler that is called to + * process incoming messages + * @param onremove_handler client handler that is called when device is removed + * @param context client-specific context + * @param client pointer to a value that receives created smsclient object + * + * @return 0 on success, <0 on error. + */ +int smscore_register_client(struct smscore_device_t *coredev, + struct smsclient_params_t *params, + struct smscore_client_t **client) +{ + struct smscore_client_t *newclient; + /* check that no other channel with same parameters exists */ + if (smscore_find_client(coredev, params->data_type, + params->initial_id)) { + sms_err("Client already exist."); + return -EEXIST; + } + + newclient = kzalloc(sizeof(struct smscore_client_t), GFP_KERNEL); + if (!newclient) { + sms_err("Failed to allocate memory for client."); + return -ENOMEM; + } + + INIT_LIST_HEAD(&newclient->idlist); + newclient->coredev = coredev; + newclient->onresponse_handler = params->onresponse_handler; + newclient->onremove_handler = params->onremove_handler; + newclient->context = params->context; + list_add_locked(&newclient->entry, &coredev->clients, + &coredev->clientslock); + smscore_validate_client(coredev, newclient, params->data_type, + params->initial_id); + *client = newclient; + sms_debug("%p %d %d", params->context, params->data_type, + params->initial_id); + + return 0; +} + +/** + * frees smsclient object and all subclients associated with it + * + * @param client pointer to smsclient object returned by + * smscore_register_client + * + */ +void smscore_unregister_client(struct smscore_client_t *client) +{ + struct smscore_device_t *coredev = client->coredev; + unsigned long flags; + + spin_lock_irqsave(&coredev->clientslock, flags); + + + while (!list_empty(&client->idlist)) { + struct smscore_idlist_t *identry = + (struct smscore_idlist_t *) client->idlist.next; + list_del(&identry->entry); + kfree(identry); + } + + sms_info("%p", client->context); + + list_del(&client->entry); + kfree(client); + + spin_unlock_irqrestore(&coredev->clientslock, flags); +} + +/** + * verifies that source id is not taken by another client, + * calls device handler to send requests to the device + * + * @param client pointer to smsclient object returned by + * smscore_register_client + * @param buffer pointer to a request buffer + * @param size size (in bytes) of request buffer + * + * @return 0 on success, <0 on error. + */ +int smsclient_sendrequest(struct smscore_client_t *client, + void *buffer, size_t size) +{ + struct smscore_device_t *coredev; + struct SmsMsgHdr_ST *phdr = (struct SmsMsgHdr_ST *) buffer; + int rc; + + if (client == NULL) { + sms_err("Got NULL client"); + return -EINVAL; + } + + coredev = client->coredev; + + /* check that no other channel with same id exists */ + if (coredev == NULL) { + sms_err("Got NULL coredev"); + return -EINVAL; + } + + rc = smscore_validate_client(client->coredev, client, 0, + phdr->msgSrcId); + if (rc < 0) + return rc; + + return coredev->sendrequest_handler(coredev->context, buffer, size); +} + + +int smscore_module_init(void) +{ + int rc = 0; + + INIT_LIST_HEAD(&g_smscore_notifyees); + INIT_LIST_HEAD(&g_smscore_devices); + kmutex_init(&g_smscore_deviceslock); + + INIT_LIST_HEAD(&g_smscore_registry); + kmutex_init(&g_smscore_registrylock); + + /* USB Register */ + rc = smsusb_register(); + + /* DVB Register */ + rc = smsdvb_register(); + + sms_debug("rc %d", rc); + + return rc; +} + +void smscore_module_exit(void) +{ + + kmutex_lock(&g_smscore_deviceslock); + while (!list_empty(&g_smscore_notifyees)) { + struct smscore_device_notifyee_t *notifyee = + (struct smscore_device_notifyee_t *) + g_smscore_notifyees.next; + + list_del(¬ifyee->entry); + kfree(notifyee); + } + kmutex_unlock(&g_smscore_deviceslock); + + kmutex_lock(&g_smscore_registrylock); + while (!list_empty(&g_smscore_registry)) { + struct smscore_registry_entry_t *entry = + (struct smscore_registry_entry_t *) + g_smscore_registry.next; + + list_del(&entry->entry); + kfree(entry); + } + kmutex_unlock(&g_smscore_registrylock); + + /* DVB UnRegister */ + smsdvb_unregister(); + + /* Unregister USB */ + smsusb_unregister(); + + sms_debug(""); +} + +module_init(smscore_module_init); +module_exit(smscore_module_exit); + +MODULE_DESCRIPTION("Driver for the Siano SMS1XXX USB dongle"); +MODULE_AUTHOR("Siano Mobile Silicon,,, (doronc@siano-ms.com)"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb/siano/smscoreapi.h b/drivers/media/dvb/siano/smscoreapi.h new file mode 100644 index 000000000000..c1f8f1dccb11 --- /dev/null +++ b/drivers/media/dvb/siano/smscoreapi.h @@ -0,0 +1,434 @@ +/* + * Driver for the Siano SMS1xxx USB dongle + * + * author: Anatoly Greenblat + * + * Copyright (c), 2005-2008 Siano Mobile Silicon, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 3 as + * published by the Free Software Foundation; + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. + * + * 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 __smscoreapi_h__ +#define __smscoreapi_h__ + +#include <linux/version.h> +#include <linux/device.h> +#include <linux/list.h> +#include <linux/mm.h> +#include <linux/scatterlist.h> +#include <linux/types.h> +#include <asm/page.h> + +#include "dmxdev.h" +#include "dvbdev.h" +#include "dvb_demux.h" +#include "dvb_frontend.h" + +#include <linux/mutex.h> + +#define kmutex_init(_p_) mutex_init(_p_) +#define kmutex_lock(_p_) mutex_lock(_p_) +#define kmutex_trylock(_p_) mutex_trylock(_p_) +#define kmutex_unlock(_p_) mutex_unlock(_p_) + +#ifndef min +#define min(a, b) (((a) < (b)) ? (a) : (b)) +#endif + +#define SMS_ALLOC_ALIGNMENT 128 +#define SMS_DMA_ALIGNMENT 16 +#define SMS_ALIGN_ADDRESS(addr) \ + ((((uintptr_t)(addr)) + (SMS_DMA_ALIGNMENT-1)) & ~(SMS_DMA_ALIGNMENT-1)) + +#define SMS_DEVICE_FAMILY2 1 +#define SMS_ROM_NO_RESPONSE 2 +#define SMS_DEVICE_NOT_READY 0x8000000 + +enum sms_device_type_st { + SMS_STELLAR = 0, + SMS_NOVA_A0, + SMS_NOVA_B0, + SMS_VEGA, + SMS_NUM_OF_DEVICE_TYPES +}; + +struct smscore_device_t; +struct smscore_client_t; +struct smscore_buffer_t; + +typedef int (*hotplug_t)(struct smscore_device_t *coredev, + struct device *device, int arrival); + +typedef int (*setmode_t)(void *context, int mode); +typedef void (*detectmode_t)(void *context, int *mode); +typedef int (*sendrequest_t)(void *context, void *buffer, size_t size); +typedef int (*loadfirmware_t)(void *context, void *buffer, size_t size); +typedef int (*preload_t)(void *context); +typedef int (*postload_t)(void *context); + +typedef int (*onresponse_t)(void *context, struct smscore_buffer_t *cb); +typedef void (*onremove_t)(void *context); + +struct smscore_buffer_t { + /* public members, once passed to clients can be changed freely */ + struct list_head entry; + int size; + int offset; + + /* private members, read-only for clients */ + void *p; + dma_addr_t phys; + unsigned long offset_in_common; +}; + +struct smsdevice_params_t { + struct device *device; + + int buffer_size; + int num_buffers; + + char devpath[32]; + unsigned long flags; + + setmode_t setmode_handler; + detectmode_t detectmode_handler; + sendrequest_t sendrequest_handler; + preload_t preload_handler; + postload_t postload_handler; + + void *context; + enum sms_device_type_st device_type; +}; + +struct smsclient_params_t { + int initial_id; + int data_type; + onresponse_t onresponse_handler; + onremove_t onremove_handler; + + void *context; +}; + +/* GPIO definitions for antenna frequency domain control (SMS8021) */ +#define SMS_ANTENNA_GPIO_0 1 +#define SMS_ANTENNA_GPIO_1 0 + +#define BW_8_MHZ 0 +#define BW_7_MHZ 1 +#define BW_6_MHZ 2 +#define BW_5_MHZ 3 +#define BW_ISDBT_1SEG 4 +#define BW_ISDBT_3SEG 5 + +#define MSG_HDR_FLAG_SPLIT_MSG 4 + +#define MAX_GPIO_PIN_NUMBER 31 + +#define HIF_TASK 11 +#define SMS_HOST_LIB 150 +#define DVBT_BDA_CONTROL_MSG_ID 201 + +#define SMS_MAX_PAYLOAD_SIZE 240 +#define SMS_TUNE_TIMEOUT 500 + +#define MSG_SMS_GPIO_CONFIG_REQ 507 +#define MSG_SMS_GPIO_CONFIG_RES 508 +#define MSG_SMS_GPIO_SET_LEVEL_REQ 509 +#define MSG_SMS_GPIO_SET_LEVEL_RES 510 +#define MSG_SMS_GPIO_GET_LEVEL_REQ 511 +#define MSG_SMS_GPIO_GET_LEVEL_RES 512 +#define MSG_SMS_RF_TUNE_REQ 561 +#define MSG_SMS_RF_TUNE_RES 562 +#define MSG_SMS_INIT_DEVICE_REQ 578 +#define MSG_SMS_INIT_DEVICE_RES 579 +#define MSG_SMS_ADD_PID_FILTER_REQ 601 +#define MSG_SMS_ADD_PID_FILTER_RES 602 +#define MSG_SMS_REMOVE_PID_FILTER_REQ 603 +#define MSG_SMS_REMOVE_PID_FILTER_RES 604 +#define MSG_SMS_DAB_CHANNEL 607 +#define MSG_SMS_GET_PID_FILTER_LIST_REQ 608 +#define MSG_SMS_GET_PID_FILTER_LIST_RES 609 +#define MSG_SMS_GET_STATISTICS_REQ 615 +#define MSG_SMS_GET_STATISTICS_RES 616 +#define MSG_SMS_SET_ANTENNA_CONFIG_REQ 651 +#define MSG_SMS_SET_ANTENNA_CONFIG_RES 652 +#define MSG_SMS_GET_STATISTICS_EX_REQ 653 +#define MSG_SMS_GET_STATISTICS_EX_RES 654 +#define MSG_SMS_SLEEP_RESUME_COMP_IND 655 +#define MSG_SMS_DATA_DOWNLOAD_REQ 660 +#define MSG_SMS_DATA_DOWNLOAD_RES 661 +#define MSG_SMS_SWDOWNLOAD_TRIGGER_REQ 664 +#define MSG_SMS_SWDOWNLOAD_TRIGGER_RES 665 +#define MSG_SMS_SWDOWNLOAD_BACKDOOR_REQ 666 +#define MSG_SMS_SWDOWNLOAD_BACKDOOR_RES 667 +#define MSG_SMS_GET_VERSION_EX_REQ 668 +#define MSG_SMS_GET_VERSION_EX_RES 669 +#define MSG_SMS_SET_CLOCK_OUTPUT_REQ 670 +#define MSG_SMS_I2C_SET_FREQ_REQ 685 +#define MSG_SMS_GENERIC_I2C_REQ 687 +#define MSG_SMS_GENERIC_I2C_RES 688 +#define MSG_SMS_DVBT_BDA_DATA 693 +#define MSG_SW_RELOAD_REQ 697 +#define MSG_SMS_DATA_MSG 699 +#define MSG_SW_RELOAD_START_REQ 702 +#define MSG_SW_RELOAD_START_RES 703 +#define MSG_SW_RELOAD_EXEC_REQ 704 +#define MSG_SW_RELOAD_EXEC_RES 705 +#define MSG_SMS_SPI_INT_LINE_SET_REQ 710 +#define MSG_SMS_ISDBT_TUNE_REQ 776 +#define MSG_SMS_ISDBT_TUNE_RES 777 + +#define SMS_INIT_MSG_EX(ptr, type, src, dst, len) do { \ + (ptr)->msgType = type; (ptr)->msgSrcId = src; (ptr)->msgDstId = dst; \ + (ptr)->msgLength = len; (ptr)->msgFlags = 0; \ +} while (0) +#define SMS_INIT_MSG(ptr, type, len) \ + SMS_INIT_MSG_EX(ptr, type, 0, HIF_TASK, len) + +enum SMS_DEVICE_MODE { + DEVICE_MODE_NONE = -1, + DEVICE_MODE_DVBT = 0, + DEVICE_MODE_DVBH, + DEVICE_MODE_DAB_TDMB, + DEVICE_MODE_DAB_TDMB_DABIP, + DEVICE_MODE_DVBT_BDA, + DEVICE_MODE_ISDBT, + DEVICE_MODE_ISDBT_BDA, + DEVICE_MODE_CMMB, + DEVICE_MODE_RAW_TUNER, + DEVICE_MODE_MAX, +}; + +struct SmsMsgHdr_ST { + u16 msgType; + u8 msgSrcId; + u8 msgDstId; + u16 msgLength; /* Length of entire message, including header */ + u16 msgFlags; +}; + +struct SmsMsgData_ST { + struct SmsMsgHdr_ST xMsgHeader; + u32 msgData[1]; +}; + +struct SmsDataDownload_ST { + struct SmsMsgHdr_ST xMsgHeader; + u32 MemAddr; + u8 Payload[SMS_MAX_PAYLOAD_SIZE]; +}; + +struct SmsVersionRes_ST { + struct SmsMsgHdr_ST xMsgHeader; + + u16 ChipModel; /* e.g. 0x1102 for SMS-1102 "Nova" */ + u8 Step; /* 0 - Step A */ + u8 MetalFix; /* 0 - Metal 0 */ + + u8 FirmwareId; /* 0xFF � ROM, otherwise the + * value indicated by + * SMSHOSTLIB_DEVICE_MODES_E */ + u8 SupportedProtocols; /* Bitwise OR combination of + * supported protocols */ + + u8 VersionMajor; + u8 VersionMinor; + u8 VersionPatch; + u8 VersionFieldPatch; + + u8 RomVersionMajor; + u8 RomVersionMinor; + u8 RomVersionPatch; + u8 RomVersionFieldPatch; + + u8 TextLabel[34]; +}; + +struct SmsFirmware_ST { + u32 CheckSum; + u32 Length; + u32 StartAddress; + u8 Payload[1]; +}; + +struct SMSHOSTLIB_STATISTICS_ST { + u32 Reserved; /* Reserved */ + + /* Common parameters */ + u32 IsRfLocked; /* 0 - not locked, 1 - locked */ + u32 IsDemodLocked; /* 0 - not locked, 1 - locked */ + u32 IsExternalLNAOn; /* 0 - external LNA off, 1 - external LNA on */ + + /* Reception quality */ + s32 SNR; /* dB */ + u32 BER; /* Post Viterbi BER [1E-5] */ + u32 FIB_CRC; /* CRC errors percentage, valid only for DAB */ + u32 TS_PER; /* Transport stream PER, 0xFFFFFFFF indicate N/A, + * valid only for DVB-T/H */ + u32 MFER; /* DVB-H frame error rate in percentage, + * 0xFFFFFFFF indicate N/A, valid only for DVB-H */ + s32 RSSI; /* dBm */ + s32 InBandPwr; /* In band power in dBM */ + s32 CarrierOffset; /* Carrier Offset in bin/1024 */ + + /* Transmission parameters, valid only for DVB-T/H */ + u32 Frequency; /* Frequency in Hz */ + u32 Bandwidth; /* Bandwidth in MHz */ + u32 TransmissionMode; /* Transmission Mode, for DAB modes 1-4, + * for DVB-T/H FFT mode carriers in Kilos */ + u32 ModemState; /* from SMS_DvbModemState_ET */ + u32 GuardInterval; /* Guard Interval, 1 divided by value */ + u32 CodeRate; /* Code Rate from SMS_DvbModemState_ET */ + u32 LPCodeRate; /* Low Priority Code Rate from SMS_DvbModemState_ET */ + u32 Hierarchy; /* Hierarchy from SMS_Hierarchy_ET */ + u32 Constellation; /* Constellation from SMS_Constellation_ET */ + + /* Burst parameters, valid only for DVB-H */ + u32 BurstSize; /* Current burst size in bytes */ + u32 BurstDuration; /* Current burst duration in mSec */ + u32 BurstCycleTime; /* Current burst cycle time in mSec */ + u32 CalculatedBurstCycleTime; /* Current burst cycle time in mSec, + * as calculated by demodulator */ + u32 NumOfRows; /* Number of rows in MPE table */ + u32 NumOfPaddCols; /* Number of padding columns in MPE table */ + u32 NumOfPunctCols; /* Number of puncturing columns in MPE table */ + /* Burst parameters */ + u32 ErrorTSPackets; /* Number of erroneous transport-stream packets */ + u32 TotalTSPackets; /* Total number of transport-stream packets */ + u32 NumOfValidMpeTlbs; /* Number of MPE tables which do not include + * errors after MPE RS decoding */ + u32 NumOfInvalidMpeTlbs; /* Number of MPE tables which include errors + * after MPE RS decoding */ + u32 NumOfCorrectedMpeTlbs; /* Number of MPE tables which were corrected + * by MPE RS decoding */ + + /* Common params */ + u32 BERErrorCount; /* Number of errornous SYNC bits. */ + u32 BERBitCount; /* Total number of SYNC bits. */ + + /* Interface information */ + u32 SmsToHostTxErrors; /* Total number of transmission errors. */ + + /* DAB/T-DMB */ + u32 PreBER; /* DAB/T-DMB only: Pre Viterbi BER [1E-5] */ + + /* DVB-H TPS parameters */ + u32 CellId; /* TPS Cell ID in bits 15..0, bits 31..16 zero; + * if set to 0xFFFFFFFF cell_id not yet recovered */ + +}; + +struct SmsMsgStatisticsInfo_ST { + u32 RequestResult; + + struct SMSHOSTLIB_STATISTICS_ST Stat; + + /* Split the calc of the SNR in DAB */ + u32 Signal; /* dB */ + u32 Noise; /* dB */ + +}; + + +struct smsdvb_client_t { + struct list_head entry; + + struct smscore_device_t *coredev; + struct smscore_client_t *smsclient; + + struct dvb_adapter adapter; + struct dvb_demux demux; + struct dmxdev dmxdev; + struct dvb_frontend frontend; + + fe_status_t fe_status; + int fe_ber, fe_snr, fe_signal_strength; + + struct completion tune_done, stat_done; + + /* todo: save freq/band instead whole struct */ + struct dvb_frontend_parameters fe_params; + +}; + +extern void smscore_registry_setmode(char *devpath, int mode); +extern int smscore_registry_getmode(char *devpath); + +extern int smscore_register_hotplug(hotplug_t hotplug); +extern void smscore_unregister_hotplug(hotplug_t hotplug); + +extern int smscore_register_device(struct smsdevice_params_t *params, + struct smscore_device_t **coredev); +extern void smscore_unregister_device(struct smscore_device_t *coredev); + +extern int smscore_start_device(struct smscore_device_t *coredev); +extern int smscore_load_firmware(struct smscore_device_t *coredev, + char *filename, + loadfirmware_t loadfirmware_handler); + +extern int smscore_set_device_mode(struct smscore_device_t *coredev, int mode); +extern int smscore_get_device_mode(struct smscore_device_t *coredev); + +extern int smscore_register_client(struct smscore_device_t *coredev, + struct smsclient_params_t *params, + struct smscore_client_t **client); +extern void smscore_unregister_client(struct smscore_client_t *client); + +extern int smsclient_sendrequest(struct smscore_client_t *client, + void *buffer, size_t size); +extern void smscore_onresponse(struct smscore_device_t *coredev, + struct smscore_buffer_t *cb); + + +extern +struct smscore_buffer_t *smscore_getbuffer(struct smscore_device_t *coredev); +extern void smscore_putbuffer(struct smscore_device_t *coredev, + struct smscore_buffer_t *cb); + +void smscore_set_board_id(struct smscore_device_t *core, int id); +int smscore_get_board_id(struct smscore_device_t *core); + +/* smsdvb.c */ +int smsdvb_register(void); +void smsdvb_unregister(void); + +/* smsusb.c */ +int smsusb_register(void); +void smsusb_unregister(void); + +/* ------------------------------------------------------------------------ */ + +extern int sms_debug; + +#define DBG_INFO 1 +#define DBG_ADV 2 + +#define sms_printk(kern, fmt, arg...) \ + printk(kern "%s: " fmt "\n", __func__, ##arg) + +#define dprintk(kern, lvl, fmt, arg...) do {\ + if (sms_debug & lvl) \ + sms_printk(kern, fmt, ##arg); } while (0) + +#define sms_log(fmt, arg...) sms_printk(KERN_INFO, fmt, ##arg) +#define sms_err(fmt, arg...) \ + sms_printk(KERN_ERR, "line: %d: " fmt, __LINE__, ##arg) +#define sms_warn(fmt, arg...) sms_printk(KERN_WARNING, fmt, ##arg) +#define sms_info(fmt, arg...) \ + dprintk(KERN_INFO, DBG_INFO, fmt, ##arg) +#define sms_debug(fmt, arg...) \ + dprintk(KERN_DEBUG, DBG_ADV, fmt, ##arg) + + +#endif /* __smscoreapi_h__ */ diff --git a/drivers/media/dvb/siano/smsdvb.c b/drivers/media/dvb/siano/smsdvb.c new file mode 100644 index 000000000000..6f9c18563867 --- /dev/null +++ b/drivers/media/dvb/siano/smsdvb.c @@ -0,0 +1,449 @@ +/* + * Driver for the Siano SMS1xxx USB dongle + * + * author: Anatoly Greenblat + * + * Copyright (c), 2005-2008 Siano Mobile Silicon, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 3 as + * published by the Free Software Foundation; + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. + * + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include <linux/module.h> +#include <linux/init.h> + +#include "smscoreapi.h" +#include "sms-cards.h" + +DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); + +struct list_head g_smsdvb_clients; +struct mutex g_smsdvb_clientslock; + +static int smsdvb_onresponse(void *context, struct smscore_buffer_t *cb) +{ + struct smsdvb_client_t *client = (struct smsdvb_client_t *) context; + struct SmsMsgHdr_ST *phdr = + (struct SmsMsgHdr_ST *)(((u8 *) cb->p) + cb->offset); + + switch (phdr->msgType) { + case MSG_SMS_DVBT_BDA_DATA: + dvb_dmx_swfilter(&client->demux, (u8 *)(phdr + 1), + cb->size - sizeof(struct SmsMsgHdr_ST)); + break; + + case MSG_SMS_RF_TUNE_RES: + complete(&client->tune_done); + break; + + case MSG_SMS_GET_STATISTICS_RES: + { + struct SmsMsgStatisticsInfo_ST *p = + (struct SmsMsgStatisticsInfo_ST *)(phdr + 1); + + if (p->Stat.IsDemodLocked) { + client->fe_status = FE_HAS_SIGNAL | + FE_HAS_CARRIER | + FE_HAS_VITERBI | + FE_HAS_SYNC | + FE_HAS_LOCK; + + client->fe_snr = p->Stat.SNR; + client->fe_ber = p->Stat.BER; + + if (p->Stat.InBandPwr < -95) + client->fe_signal_strength = 0; + else if (p->Stat.InBandPwr > -29) + client->fe_signal_strength = 100; + else + client->fe_signal_strength = + (p->Stat.InBandPwr + 95) * 3 / 2; + } else { + client->fe_status = 0; + client->fe_snr = + client->fe_ber = + client->fe_signal_strength = 0; + } + + complete(&client->stat_done); + break; + } } + + smscore_putbuffer(client->coredev, cb); + + return 0; +} + +static void smsdvb_unregister_client(struct smsdvb_client_t *client) +{ + /* must be called under clientslock */ + + list_del(&client->entry); + + smscore_unregister_client(client->smsclient); + dvb_unregister_frontend(&client->frontend); + dvb_dmxdev_release(&client->dmxdev); + dvb_dmx_release(&client->demux); + dvb_unregister_adapter(&client->adapter); + kfree(client); +} + +static void smsdvb_onremove(void *context) +{ + kmutex_lock(&g_smsdvb_clientslock); + + smsdvb_unregister_client((struct smsdvb_client_t *) context); + + kmutex_unlock(&g_smsdvb_clientslock); +} + +static int smsdvb_start_feed(struct dvb_demux_feed *feed) +{ + struct smsdvb_client_t *client = + container_of(feed->demux, struct smsdvb_client_t, demux); + struct SmsMsgData_ST PidMsg; + + sms_debug("add pid %d(%x)", + feed->pid, feed->pid); + + PidMsg.xMsgHeader.msgSrcId = DVBT_BDA_CONTROL_MSG_ID; + PidMsg.xMsgHeader.msgDstId = HIF_TASK; + PidMsg.xMsgHeader.msgFlags = 0; + PidMsg.xMsgHeader.msgType = MSG_SMS_ADD_PID_FILTER_REQ; + PidMsg.xMsgHeader.msgLength = sizeof(PidMsg); + PidMsg.msgData[0] = feed->pid; + + return smsclient_sendrequest(client->smsclient, + &PidMsg, sizeof(PidMsg)); +} + +static int smsdvb_stop_feed(struct dvb_demux_feed *feed) +{ + struct smsdvb_client_t *client = + container_of(feed->demux, struct smsdvb_client_t, demux); + struct SmsMsgData_ST PidMsg; + + sms_debug("remove pid %d(%x)", + feed->pid, feed->pid); + + PidMsg.xMsgHeader.msgSrcId = DVBT_BDA_CONTROL_MSG_ID; + PidMsg.xMsgHeader.msgDstId = HIF_TASK; + PidMsg.xMsgHeader.msgFlags = 0; + PidMsg.xMsgHeader.msgType = MSG_SMS_REMOVE_PID_FILTER_REQ; + PidMsg.xMsgHeader.msgLength = sizeof(PidMsg); + PidMsg.msgData[0] = feed->pid; + + return smsclient_sendrequest(client->smsclient, + &PidMsg, sizeof(PidMsg)); +} + +static int smsdvb_sendrequest_and_wait(struct smsdvb_client_t *client, + void *buffer, size_t size, + struct completion *completion) +{ + int rc = smsclient_sendrequest(client->smsclient, buffer, size); + if (rc < 0) + return rc; + + return wait_for_completion_timeout(completion, + msecs_to_jiffies(2000)) ? + 0 : -ETIME; +} + +static int smsdvb_send_statistics_request(struct smsdvb_client_t *client) +{ + struct SmsMsgHdr_ST Msg = { MSG_SMS_GET_STATISTICS_REQ, + DVBT_BDA_CONTROL_MSG_ID, + HIF_TASK, sizeof(struct SmsMsgHdr_ST), 0 }; + return smsdvb_sendrequest_and_wait(client, &Msg, sizeof(Msg), + &client->stat_done); +} + +static int smsdvb_read_status(struct dvb_frontend *fe, fe_status_t *stat) +{ + struct smsdvb_client_t *client = + container_of(fe, struct smsdvb_client_t, frontend); + int rc = smsdvb_send_statistics_request(client); + + if (!rc) + *stat = client->fe_status; + + return rc; +} + +static int smsdvb_read_ber(struct dvb_frontend *fe, u32 *ber) +{ + struct smsdvb_client_t *client = + container_of(fe, struct smsdvb_client_t, frontend); + int rc = smsdvb_send_statistics_request(client); + + if (!rc) + *ber = client->fe_ber; + + return rc; +} + +static int smsdvb_read_signal_strength(struct dvb_frontend *fe, u16 *strength) +{ + struct smsdvb_client_t *client = + container_of(fe, struct smsdvb_client_t, frontend); + int rc = smsdvb_send_statistics_request(client); + + if (!rc) + *strength = client->fe_signal_strength; + + return rc; +} + +static int smsdvb_read_snr(struct dvb_frontend *fe, u16 *snr) +{ + struct smsdvb_client_t *client = + container_of(fe, struct smsdvb_client_t, frontend); + int rc = smsdvb_send_statistics_request(client); + + if (!rc) + *snr = client->fe_snr; + + return rc; +} + +static int smsdvb_get_tune_settings(struct dvb_frontend *fe, + struct dvb_frontend_tune_settings *tune) +{ + sms_debug(""); + + tune->min_delay_ms = 400; + tune->step_size = 250000; + tune->max_drift = 0; + return 0; +} + +static int smsdvb_set_frontend(struct dvb_frontend *fe, + struct dvb_frontend_parameters *fep) +{ + struct smsdvb_client_t *client = + container_of(fe, struct smsdvb_client_t, frontend); + + struct { + struct SmsMsgHdr_ST Msg; + u32 Data[3]; + } Msg; + + Msg.Msg.msgSrcId = DVBT_BDA_CONTROL_MSG_ID; + Msg.Msg.msgDstId = HIF_TASK; + Msg.Msg.msgFlags = 0; + Msg.Msg.msgType = MSG_SMS_RF_TUNE_REQ; + Msg.Msg.msgLength = sizeof(Msg); + Msg.Data[0] = fep->frequency; + Msg.Data[2] = 12000000; + + sms_debug("freq %d band %d", + fep->frequency, fep->u.ofdm.bandwidth); + + switch (fep->u.ofdm.bandwidth) { + case BANDWIDTH_8_MHZ: Msg.Data[1] = BW_8_MHZ; break; + case BANDWIDTH_7_MHZ: Msg.Data[1] = BW_7_MHZ; break; + case BANDWIDTH_6_MHZ: Msg.Data[1] = BW_6_MHZ; break; + case BANDWIDTH_AUTO: return -EOPNOTSUPP; + default: return -EINVAL; + } + + return smsdvb_sendrequest_and_wait(client, &Msg, sizeof(Msg), + &client->tune_done); +} + +static int smsdvb_get_frontend(struct dvb_frontend *fe, + struct dvb_frontend_parameters *fep) +{ + struct smsdvb_client_t *client = + container_of(fe, struct smsdvb_client_t, frontend); + + sms_debug(""); + + /* todo: */ + memcpy(fep, &client->fe_params, + sizeof(struct dvb_frontend_parameters)); + return 0; +} + +static void smsdvb_release(struct dvb_frontend *fe) +{ + /* do nothing */ +} + +static struct dvb_frontend_ops smsdvb_fe_ops = { + .info = { + .name = "Siano Mobile Digital SMS1xxx", + .type = FE_OFDM, + .frequency_min = 44250000, + .frequency_max = 867250000, + .frequency_stepsize = 250000, + .caps = FE_CAN_INVERSION_AUTO | + FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | + FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | + FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | + FE_CAN_QAM_AUTO | FE_CAN_TRANSMISSION_MODE_AUTO | + FE_CAN_GUARD_INTERVAL_AUTO | + FE_CAN_RECOVER | + FE_CAN_HIERARCHY_AUTO, + }, + + .release = smsdvb_release, + + .set_frontend = smsdvb_set_frontend, + .get_frontend = smsdvb_get_frontend, + .get_tune_settings = smsdvb_get_tune_settings, + + .read_status = smsdvb_read_status, + .read_ber = smsdvb_read_ber, + .read_signal_strength = smsdvb_read_signal_strength, + .read_snr = smsdvb_read_snr, +}; + +static int smsdvb_hotplug(struct smscore_device_t *coredev, + struct device *device, int arrival) +{ + struct smsclient_params_t params; + struct smsdvb_client_t *client; + int rc; + + /* device removal handled by onremove callback */ + if (!arrival) + return 0; + + if (smscore_get_device_mode(coredev) != 4) { + sms_err("SMS Device mode is not set for " + "DVB operation."); + return 0; + } + + client = kzalloc(sizeof(struct smsdvb_client_t), GFP_KERNEL); + if (!client) { + sms_err("kmalloc() failed"); + return -ENOMEM; + } + + /* register dvb adapter */ + rc = dvb_register_adapter(&client->adapter, + sms_get_board( + smscore_get_board_id(coredev))->name, + THIS_MODULE, device, adapter_nr); + if (rc < 0) { + sms_err("dvb_register_adapter() failed %d", rc); + goto adapter_error; + } + + /* init dvb demux */ + client->demux.dmx.capabilities = DMX_TS_FILTERING; + client->demux.filternum = 32; /* todo: nova ??? */ + client->demux.feednum = 32; + client->demux.start_feed = smsdvb_start_feed; + client->demux.stop_feed = smsdvb_stop_feed; + + rc = dvb_dmx_init(&client->demux); + if (rc < 0) { + sms_err("dvb_dmx_init failed %d", rc); + goto dvbdmx_error; + } + + /* init dmxdev */ + client->dmxdev.filternum = 32; + client->dmxdev.demux = &client->demux.dmx; + client->dmxdev.capabilities = 0; + + rc = dvb_dmxdev_init(&client->dmxdev, &client->adapter); + if (rc < 0) { + sms_err("dvb_dmxdev_init failed %d", rc); + goto dmxdev_error; + } + + /* init and register frontend */ + memcpy(&client->frontend.ops, &smsdvb_fe_ops, + sizeof(struct dvb_frontend_ops)); + + rc = dvb_register_frontend(&client->adapter, &client->frontend); + if (rc < 0) { + sms_err("frontend registration failed %d", rc); + goto frontend_error; + } + + params.initial_id = 1; + params.data_type = MSG_SMS_DVBT_BDA_DATA; + params.onresponse_handler = smsdvb_onresponse; + params.onremove_handler = smsdvb_onremove; + params.context = client; + + rc = smscore_register_client(coredev, ¶ms, &client->smsclient); + if (rc < 0) { + sms_err("smscore_register_client() failed %d", rc); + goto client_error; + } + + client->coredev = coredev; + + init_completion(&client->tune_done); + init_completion(&client->stat_done); + + kmutex_lock(&g_smsdvb_clientslock); + + list_add(&client->entry, &g_smsdvb_clients); + + kmutex_unlock(&g_smsdvb_clientslock); + + sms_info("success"); + + return 0; + +client_error: + dvb_unregister_frontend(&client->frontend); + +frontend_error: + dvb_dmxdev_release(&client->dmxdev); + +dmxdev_error: + dvb_dmx_release(&client->demux); + +dvbdmx_error: + dvb_unregister_adapter(&client->adapter); + +adapter_error: + kfree(client); + return rc; +} + +int smsdvb_register(void) +{ + int rc; + + INIT_LIST_HEAD(&g_smsdvb_clients); + kmutex_init(&g_smsdvb_clientslock); + + rc = smscore_register_hotplug(smsdvb_hotplug); + + sms_debug(""); + + return rc; +} + +void smsdvb_unregister(void) +{ + smscore_unregister_hotplug(smsdvb_hotplug); + + kmutex_lock(&g_smsdvb_clientslock); + + while (!list_empty(&g_smsdvb_clients)) + smsdvb_unregister_client( + (struct smsdvb_client_t *) g_smsdvb_clients.next); + + kmutex_unlock(&g_smsdvb_clientslock); +} diff --git a/drivers/media/dvb/siano/smsusb.c b/drivers/media/dvb/siano/smsusb.c new file mode 100644 index 000000000000..c10b1849c6a3 --- /dev/null +++ b/drivers/media/dvb/siano/smsusb.c @@ -0,0 +1,459 @@ +/* + * Driver for the Siano SMS1xxx USB dongle + * + * author: Anatoly Greenblat + * + * Copyright (c), 2005-2008 Siano Mobile Silicon, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 3 as + * published by the Free Software Foundation; + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. + * + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/usb.h> +#include <linux/firmware.h> + +#include "smscoreapi.h" +#include "sms-cards.h" + +#define USB1_BUFFER_SIZE 0x1000 +#define USB2_BUFFER_SIZE 0x4000 + +#define MAX_BUFFERS 50 +#define MAX_URBS 10 + +struct smsusb_device_t; + +struct smsusb_urb_t { + struct smscore_buffer_t *cb; + struct smsusb_device_t *dev; + + struct urb urb; +}; + +struct smsusb_device_t { + struct usb_device *udev; + struct smscore_device_t *coredev; + + struct smsusb_urb_t surbs[MAX_URBS]; + + int response_alignment; + int buffer_size; +}; + +static int smsusb_submit_urb(struct smsusb_device_t *dev, + struct smsusb_urb_t *surb); + +static void smsusb_onresponse(struct urb *urb) +{ + struct smsusb_urb_t *surb = (struct smsusb_urb_t *) urb->context; + struct smsusb_device_t *dev = surb->dev; + + if (urb->status < 0) { + sms_err("error, urb status %d, %d bytes", + urb->status, urb->actual_length); + return; + } + + if (urb->actual_length > 0) { + struct SmsMsgHdr_ST *phdr = (struct SmsMsgHdr_ST *) surb->cb->p; + + if (urb->actual_length >= phdr->msgLength) { + surb->cb->size = phdr->msgLength; + + if (dev->response_alignment && + (phdr->msgFlags & MSG_HDR_FLAG_SPLIT_MSG)) { + + surb->cb->offset = + dev->response_alignment + + ((phdr->msgFlags >> 8) & 3); + + /* sanity check */ + if (((int) phdr->msgLength + + surb->cb->offset) > urb->actual_length) { + sms_err("invalid response " + "msglen %d offset %d " + "size %d", + phdr->msgLength, + surb->cb->offset, + urb->actual_length); + goto exit_and_resubmit; + } + + /* move buffer pointer and + * copy header to its new location */ + memcpy((char *) phdr + surb->cb->offset, + phdr, sizeof(struct SmsMsgHdr_ST)); + } else + surb->cb->offset = 0; + + smscore_onresponse(dev->coredev, surb->cb); + surb->cb = NULL; + } else { + sms_err("invalid response " + "msglen %d actual %d", + phdr->msgLength, urb->actual_length); + } + } + +exit_and_resubmit: + smsusb_submit_urb(dev, surb); +} + +static int smsusb_submit_urb(struct smsusb_device_t *dev, + struct smsusb_urb_t *surb) +{ + if (!surb->cb) { + surb->cb = smscore_getbuffer(dev->coredev); + if (!surb->cb) { + sms_err("smscore_getbuffer(...) returned NULL"); + return -ENOMEM; + } + } + + usb_fill_bulk_urb( + &surb->urb, + dev->udev, + usb_rcvbulkpipe(dev->udev, 0x81), + surb->cb->p, + dev->buffer_size, + smsusb_onresponse, + surb + ); + surb->urb.transfer_dma = surb->cb->phys; + surb->urb.transfer_flags |= URB_NO_TRANSFER_DMA_MAP; + + return usb_submit_urb(&surb->urb, GFP_ATOMIC); +} + +static void smsusb_stop_streaming(struct smsusb_device_t *dev) +{ + int i; + + for (i = 0; i < MAX_URBS; i++) { + usb_kill_urb(&dev->surbs[i].urb); + + if (dev->surbs[i].cb) { + smscore_putbuffer(dev->coredev, dev->surbs[i].cb); + dev->surbs[i].cb = NULL; + } + } +} + +static int smsusb_start_streaming(struct smsusb_device_t *dev) +{ + int i, rc; + + for (i = 0; i < MAX_URBS; i++) { + rc = smsusb_submit_urb(dev, &dev->surbs[i]); + if (rc < 0) { + sms_err("smsusb_submit_urb(...) failed"); + smsusb_stop_streaming(dev); + break; + } + } + + return rc; +} + +static int smsusb_sendrequest(void *context, void *buffer, size_t size) +{ + struct smsusb_device_t *dev = (struct smsusb_device_t *) context; + int dummy; + + return usb_bulk_msg(dev->udev, usb_sndbulkpipe(dev->udev, 2), + buffer, size, &dummy, 1000); +} + +static char *smsusb1_fw_lkup[] = { + "dvbt_stellar_usb.inp", + "dvbh_stellar_usb.inp", + "tdmb_stellar_usb.inp", + "none", + "dvbt_bda_stellar_usb.inp", +}; + +static inline char *sms_get_fw_name(int mode, int board_id) +{ + char **fw = sms_get_board(board_id)->fw; + return (fw && fw[mode]) ? fw[mode] : smsusb1_fw_lkup[mode]; +} + +static int smsusb1_load_firmware(struct usb_device *udev, int id, int board_id) +{ + const struct firmware *fw; + u8 *fw_buffer; + int rc, dummy; + char *fw_filename; + + if (id < DEVICE_MODE_DVBT || id > DEVICE_MODE_DVBT_BDA) { + sms_err("invalid firmware id specified %d", id); + return -EINVAL; + } + + fw_filename = sms_get_fw_name(id, board_id); + + rc = request_firmware(&fw, fw_filename, &udev->dev); + if (rc < 0) { + sms_warn("failed to open \"%s\" mode %d, " + "trying again with default firmware", fw_filename, id); + + fw_filename = smsusb1_fw_lkup[id]; + rc = request_firmware(&fw, fw_filename, &udev->dev); + if (rc < 0) { + sms_warn("failed to open \"%s\" mode %d", + fw_filename, id); + + return rc; + } + } + + fw_buffer = kmalloc(fw->size, GFP_KERNEL); + if (fw_buffer) { + memcpy(fw_buffer, fw->data, fw->size); + + rc = usb_bulk_msg(udev, usb_sndbulkpipe(udev, 2), + fw_buffer, fw->size, &dummy, 1000); + + sms_info("sent %zd(%d) bytes, rc %d", fw->size, dummy, rc); + + kfree(fw_buffer); + } else { + sms_err("failed to allocate firmware buffer"); + rc = -ENOMEM; + } + sms_info("read FW %s, size=%zd", fw_filename, fw->size); + + release_firmware(fw); + + return rc; +} + +static void smsusb1_detectmode(void *context, int *mode) +{ + char *product_string = + ((struct smsusb_device_t *) context)->udev->product; + + *mode = DEVICE_MODE_NONE; + + if (!product_string) { + product_string = "none"; + sms_err("product string not found"); + } else if (strstr(product_string, "DVBH")) + *mode = 1; + else if (strstr(product_string, "BDA")) + *mode = 4; + else if (strstr(product_string, "DVBT")) + *mode = 0; + else if (strstr(product_string, "TDMB")) + *mode = 2; + + sms_info("%d \"%s\"", *mode, product_string); +} + +static int smsusb1_setmode(void *context, int mode) +{ + struct SmsMsgHdr_ST Msg = { MSG_SW_RELOAD_REQ, 0, HIF_TASK, + sizeof(struct SmsMsgHdr_ST), 0 }; + + if (mode < DEVICE_MODE_DVBT || mode > DEVICE_MODE_DVBT_BDA) { + sms_err("invalid firmware id specified %d", mode); + return -EINVAL; + } + + return smsusb_sendrequest(context, &Msg, sizeof(Msg)); +} + +static void smsusb_term_device(struct usb_interface *intf) +{ + struct smsusb_device_t *dev = + (struct smsusb_device_t *) usb_get_intfdata(intf); + + if (dev) { + smsusb_stop_streaming(dev); + + /* unregister from smscore */ + if (dev->coredev) + smscore_unregister_device(dev->coredev); + + kfree(dev); + + sms_info("device %p destroyed", dev); + } + + usb_set_intfdata(intf, NULL); +} + +static int smsusb_init_device(struct usb_interface *intf, int board_id) +{ + struct smsdevice_params_t params; + struct smsusb_device_t *dev; + int i, rc; + + /* create device object */ + dev = kzalloc(sizeof(struct smsusb_device_t), GFP_KERNEL); + if (!dev) { + sms_err("kzalloc(sizeof(struct smsusb_device_t) failed"); + return -ENOMEM; + } + + memset(¶ms, 0, sizeof(params)); + usb_set_intfdata(intf, dev); + dev->udev = interface_to_usbdev(intf); + + params.device_type = sms_get_board(board_id)->type; + + switch (params.device_type) { + case SMS_STELLAR: + dev->buffer_size = USB1_BUFFER_SIZE; + + params.setmode_handler = smsusb1_setmode; + params.detectmode_handler = smsusb1_detectmode; + break; + default: + sms_err("Unspecified sms device type!"); + /* fall-thru */ + case SMS_NOVA_A0: + case SMS_NOVA_B0: + case SMS_VEGA: + dev->buffer_size = USB2_BUFFER_SIZE; + dev->response_alignment = + dev->udev->ep_in[1]->desc.wMaxPacketSize - + sizeof(struct SmsMsgHdr_ST); + + params.flags |= SMS_DEVICE_FAMILY2; + break; + } + + params.device = &dev->udev->dev; + params.buffer_size = dev->buffer_size; + params.num_buffers = MAX_BUFFERS; + params.sendrequest_handler = smsusb_sendrequest; + params.context = dev; + snprintf(params.devpath, sizeof(params.devpath), + "usb\\%d-%s", dev->udev->bus->busnum, dev->udev->devpath); + + /* register in smscore */ + rc = smscore_register_device(¶ms, &dev->coredev); + if (rc < 0) { + sms_err("smscore_register_device(...) failed, rc %d", rc); + smsusb_term_device(intf); + return rc; + } + + smscore_set_board_id(dev->coredev, board_id); + + /* initialize urbs */ + for (i = 0; i < MAX_URBS; i++) { + dev->surbs[i].dev = dev; + usb_init_urb(&dev->surbs[i].urb); + } + + sms_info("smsusb_start_streaming(...)."); + rc = smsusb_start_streaming(dev); + if (rc < 0) { + sms_err("smsusb_start_streaming(...) failed"); + smsusb_term_device(intf); + return rc; + } + + rc = smscore_start_device(dev->coredev); + if (rc < 0) { + sms_err("smscore_start_device(...) failed"); + smsusb_term_device(intf); + return rc; + } + + sms_info("device %p created", dev); + + return rc; +} + +static int smsusb_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + struct usb_device *udev = interface_to_usbdev(intf); + char devpath[32]; + int i, rc; + + rc = usb_clear_halt(udev, usb_rcvbulkpipe(udev, 0x81)); + rc = usb_clear_halt(udev, usb_rcvbulkpipe(udev, 0x02)); + + if (intf->num_altsetting > 0) { + rc = usb_set_interface( + udev, intf->cur_altsetting->desc.bInterfaceNumber, 0); + if (rc < 0) { + sms_err("usb_set_interface failed, rc %d", rc); + return rc; + } + } + + sms_info("smsusb_probe %d", + intf->cur_altsetting->desc.bInterfaceNumber); + for (i = 0; i < intf->cur_altsetting->desc.bNumEndpoints; i++) + sms_info("endpoint %d %02x %02x %d", i, + intf->cur_altsetting->endpoint[i].desc.bEndpointAddress, + intf->cur_altsetting->endpoint[i].desc.bmAttributes, + intf->cur_altsetting->endpoint[i].desc.wMaxPacketSize); + + if ((udev->actconfig->desc.bNumInterfaces == 2) && + (intf->cur_altsetting->desc.bInterfaceNumber == 0)) { + sms_err("rom interface 0 is not used"); + return -ENODEV; + } + + if (intf->cur_altsetting->desc.bInterfaceNumber == 1) { + snprintf(devpath, sizeof(devpath), "usb\\%d-%s", + udev->bus->busnum, udev->devpath); + sms_info("stellar device was found."); + return smsusb1_load_firmware( + udev, smscore_registry_getmode(devpath), + id->driver_info); + } + + rc = smsusb_init_device(intf, id->driver_info); + sms_info("rc %d", rc); + return rc; +} + +static void smsusb_disconnect(struct usb_interface *intf) +{ + smsusb_term_device(intf); +} + +static struct usb_driver smsusb_driver = { + .name = "sms1xxx", + .probe = smsusb_probe, + .disconnect = smsusb_disconnect, + .id_table = smsusb_id_table, +}; + +int smsusb_register(void) +{ + int rc = usb_register(&smsusb_driver); + if (rc) + sms_err("usb_register failed. Error number %d", rc); + + sms_debug(""); + + return rc; +} + +void smsusb_unregister(void) +{ + sms_debug(""); + /* Regular USB Cleanup */ + usb_deregister(&smsusb_driver); +} + diff --git a/drivers/media/dvb/ttpci/Kconfig b/drivers/media/dvb/ttpci/Kconfig index 07643e010093..87c973ac668b 100644 --- a/drivers/media/dvb/ttpci/Kconfig +++ b/drivers/media/dvb/ttpci/Kconfig @@ -106,6 +106,8 @@ config DVB_BUDGET_CI select DVB_STV0299 if !DVB_FE_CUSTOMISE select DVB_TDA1004X if !DVB_FE_CUSTOMISE select DVB_LNBP21 if !DVB_FE_CUSTOMISE + select DVB_TDA10023 if !DVB_FE_CUSTOMISE + select MEDIA_TUNER_TDA827X if !DVB_FE_CUSTOMISE select VIDEO_IR help Support for simple SAA7146 based DVB cards diff --git a/drivers/media/dvb/ttpci/Makefile b/drivers/media/dvb/ttpci/Makefile index d7483f1a9b3f..71451237294c 100644 --- a/drivers/media/dvb/ttpci/Makefile +++ b/drivers/media/dvb/ttpci/Makefile @@ -3,7 +3,11 @@ # and the AV7110 DVB device driver # -dvb-ttpci-objs := av7110_hw.o av7110_v4l.o av7110_av.o av7110_ca.o av7110.o av7110_ipack.o av7110_ir.o +dvb-ttpci-objs := av7110_hw.o av7110_v4l.o av7110_av.o av7110_ca.o av7110.o av7110_ipack.o + +ifdef CONFIG_INPUT_EVDEV +dvb-ttpci-objs += av7110_ir.o +endif obj-$(CONFIG_TTPCI_EEPROM) += ttpci-eeprom.o obj-$(CONFIG_DVB_BUDGET_CORE) += budget-core.o @@ -14,6 +18,7 @@ obj-$(CONFIG_DVB_BUDGET_PATCH) += budget-patch.o obj-$(CONFIG_DVB_AV7110) += dvb-ttpci.o EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/ +EXTRA_CFLAGS += -Idrivers/media/common/tuners hostprogs-y := fdump diff --git a/drivers/media/dvb/ttpci/av7110.c b/drivers/media/dvb/ttpci/av7110.c index f05d43d8b5cf..0777e8f9544b 100644 --- a/drivers/media/dvb/ttpci/av7110.c +++ b/drivers/media/dvb/ttpci/av7110.c @@ -587,7 +587,7 @@ static void gpioirq(unsigned long data) } DVB_RINGBUFFER_SKIP(cibuf, 2); - dvb_ringbuffer_read(cibuf, av7110->debi_virt, len, 0); + dvb_ringbuffer_read(cibuf, av7110->debi_virt, len); iwdebi(av7110, DEBINOSWAP, TX_LEN, len, 2); iwdebi(av7110, DEBINOSWAP, IRQ_STATE_EXT, len, 2); @@ -1198,7 +1198,6 @@ static int start_ts_capture(struct av7110 *budget) if (budget->feeding1) return ++budget->feeding1; memset(budget->grabbing, 0x00, TS_HEIGHT * TS_WIDTH); - budget->tsf = 0xff; budget->ttbp = 0; SAA7146_IER_ENABLE(budget->dev, MASK_10); /* VPE */ saa7146_write(budget->dev, MC1, (MASK_04 | MASK_20)); /* DMA3 on */ @@ -2403,18 +2402,18 @@ static int __devinit av7110_attach(struct saa7146_dev* dev, saa7146_write(dev, MC1, MASK_29); /* RPS1 timeout disable */ saa7146_write(dev, RPS_TOV1, 0); - WRITE_RPS1(cpu_to_le32(CMD_PAUSE | EVT_VBI_B)); - WRITE_RPS1(cpu_to_le32(CMD_WR_REG_MASK | (GPIO_CTRL>>2))); - WRITE_RPS1(cpu_to_le32(GPIO3_MSK)); - WRITE_RPS1(cpu_to_le32(SAA7146_GPIO_OUTLO<<24)); + WRITE_RPS1(CMD_PAUSE | EVT_VBI_B); + WRITE_RPS1(CMD_WR_REG_MASK | (GPIO_CTRL>>2)); + WRITE_RPS1(GPIO3_MSK); + WRITE_RPS1(SAA7146_GPIO_OUTLO<<24); #if RPS_IRQ /* issue RPS1 interrupt to increment counter */ - WRITE_RPS1(cpu_to_le32(CMD_INTERRUPT)); + WRITE_RPS1(CMD_INTERRUPT); #endif - WRITE_RPS1(cpu_to_le32(CMD_STOP)); + WRITE_RPS1(CMD_STOP); /* Jump to begin of RPS program as safety measure (p37) */ - WRITE_RPS1(cpu_to_le32(CMD_JUMP)); - WRITE_RPS1(cpu_to_le32(dev->d_rps1.dma_handle)); + WRITE_RPS1(CMD_JUMP); + WRITE_RPS1(dev->d_rps1.dma_handle); #if RPS_IRQ /* set event counter 1 source as RPS1 interrupt (0x03) (rE4 p53) @@ -2472,11 +2471,7 @@ static int __devinit av7110_attach(struct saa7146_dev* dev, get recognized before the main driver is fully loaded */ saa7146_write(dev, GPIO_CTRL, 0x500000); -#ifdef I2C_ADAP_CLASS_TV_DIGITAL - av7110->i2c_adap.class = I2C_ADAP_CLASS_TV_DIGITAL; -#else av7110->i2c_adap.class = I2C_CLASS_TV_DIGITAL; -#endif strlcpy(av7110->i2c_adap.name, pci_ext->ext_priv, sizeof(av7110->i2c_adap.name)); saa7146_i2c_adapter_prepare(dev, &av7110->i2c_adap, SAA7146_I2C_BUS_BIT_RATE_120); /* 275 kHz */ @@ -2527,28 +2522,28 @@ static int __devinit av7110_attach(struct saa7146_dev* dev, count = 0; /* Wait Source Line Counter Threshold (p36) */ - WRITE_RPS1(cpu_to_le32(CMD_PAUSE | EVT_HS)); + WRITE_RPS1(CMD_PAUSE | EVT_HS); /* Set GPIO3=1 (p42) */ - WRITE_RPS1(cpu_to_le32(CMD_WR_REG_MASK | (GPIO_CTRL>>2))); - WRITE_RPS1(cpu_to_le32(GPIO3_MSK)); - WRITE_RPS1(cpu_to_le32(SAA7146_GPIO_OUTHI<<24)); + WRITE_RPS1(CMD_WR_REG_MASK | (GPIO_CTRL>>2)); + WRITE_RPS1(GPIO3_MSK); + WRITE_RPS1(SAA7146_GPIO_OUTHI<<24); #if RPS_IRQ /* issue RPS1 interrupt */ - WRITE_RPS1(cpu_to_le32(CMD_INTERRUPT)); + WRITE_RPS1(CMD_INTERRUPT); #endif /* Wait reset Source Line Counter Threshold (p36) */ - WRITE_RPS1(cpu_to_le32(CMD_PAUSE | RPS_INV | EVT_HS)); + WRITE_RPS1(CMD_PAUSE | RPS_INV | EVT_HS); /* Set GPIO3=0 (p42) */ - WRITE_RPS1(cpu_to_le32(CMD_WR_REG_MASK | (GPIO_CTRL>>2))); - WRITE_RPS1(cpu_to_le32(GPIO3_MSK)); - WRITE_RPS1(cpu_to_le32(SAA7146_GPIO_OUTLO<<24)); + WRITE_RPS1(CMD_WR_REG_MASK | (GPIO_CTRL>>2)); + WRITE_RPS1(GPIO3_MSK); + WRITE_RPS1(SAA7146_GPIO_OUTLO<<24); #if RPS_IRQ /* issue RPS1 interrupt */ - WRITE_RPS1(cpu_to_le32(CMD_INTERRUPT)); + WRITE_RPS1(CMD_INTERRUPT); #endif /* Jump to begin of RPS program (p37) */ - WRITE_RPS1(cpu_to_le32(CMD_JUMP)); - WRITE_RPS1(cpu_to_le32(dev->d_rps1.dma_handle)); + WRITE_RPS1(CMD_JUMP); + WRITE_RPS1(dev->d_rps1.dma_handle); /* Fix VSYNC level */ saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTLO); diff --git a/drivers/media/dvb/ttpci/av7110.h b/drivers/media/dvb/ttpci/av7110.h index e494e04eeee8..55f23ddcb994 100644 --- a/drivers/media/dvb/ttpci/av7110.h +++ b/drivers/media/dvb/ttpci/av7110.h @@ -188,7 +188,6 @@ struct av7110 { struct dvb_net dvb_net1; spinlock_t feedlock1; int feeding1; - u8 tsf; u32 ttbp; unsigned char *grabbing; struct saa7146_pgtable pt; diff --git a/drivers/media/dvb/ttpci/av7110_av.c b/drivers/media/dvb/ttpci/av7110_av.c index ec55a968f204..184647ad1c7c 100644 --- a/drivers/media/dvb/ttpci/av7110_av.c +++ b/drivers/media/dvb/ttpci/av7110_av.c @@ -269,7 +269,7 @@ int av7110_pes_play(void *dest, struct dvb_ringbuffer *buf, int dlen) return -1; } - dvb_ringbuffer_read(buf, dest, (size_t) blen, 0); + dvb_ringbuffer_read(buf, dest, (size_t) blen); dprintk(2, "pread=0x%08lx, pwrite=0x%08lx\n", (unsigned long) buf->pread, (unsigned long) buf->pwrite); diff --git a/drivers/media/dvb/ttpci/av7110_ca.c b/drivers/media/dvb/ttpci/av7110_ca.c index c58e3fc509ed..261135ded481 100644 --- a/drivers/media/dvb/ttpci/av7110_ca.c +++ b/drivers/media/dvb/ttpci/av7110_ca.c @@ -208,7 +208,7 @@ static ssize_t ci_ll_read(struct dvb_ringbuffer *cibuf, struct file *file, return -EINVAL; DVB_RINGBUFFER_SKIP(cibuf, 2); - return dvb_ringbuffer_read(cibuf, (u8 *)buf, len, 1); + return dvb_ringbuffer_read_user(cibuf, buf, len); } static int dvb_ca_open(struct inode *inode, struct file *file) diff --git a/drivers/media/dvb/ttpci/av7110_hw.h b/drivers/media/dvb/ttpci/av7110_hw.h index 74d940f75da6..ca99e5c1fc8a 100644 --- a/drivers/media/dvb/ttpci/av7110_hw.h +++ b/drivers/media/dvb/ttpci/av7110_hw.h @@ -305,7 +305,6 @@ enum av7110_command_type { #define IRQ_STATE (DPRAM_BASE + 0x0F4) #define IRQ_STATE_EXT (DPRAM_BASE + 0x0F6) #define MSGSTATE (DPRAM_BASE + 0x0F8) -#define FILT_STATE (DPRAM_BASE + 0x0FA) #define COMMAND (DPRAM_BASE + 0x0FC) #define COM_BUFF (DPRAM_BASE + 0x100) #define COM_BUFF_SIZE 0x20 @@ -332,8 +331,6 @@ enum av7110_command_type { /* firmware status area */ #define STATUS_BASE (DPRAM_BASE + 0x1FC0) -#define STATUS_SCR (STATUS_BASE + 0x00) -#define STATUS_MODES (STATUS_BASE + 0x04) #define STATUS_LOOPS (STATUS_BASE + 0x08) #define STATUS_MPEG_WIDTH (STATUS_BASE + 0x0C) diff --git a/drivers/media/dvb/ttpci/budget-av.c b/drivers/media/dvb/ttpci/budget-av.c index b30a5288e484..b7d1f2f18d3a 100644 --- a/drivers/media/dvb/ttpci/budget-av.c +++ b/drivers/media/dvb/ttpci/budget-av.c @@ -667,6 +667,11 @@ static struct tda1002x_config philips_cu1216_config_altaddress = { .invert = 0, }; +static struct tda10023_config philips_cu1216_tda10023_config = { + .demod_address = 0x0c, + .invert = 1, +}; + static int philips_tu1216_tuner_init(struct dvb_frontend *fe) { struct budget *budget = (struct budget *) fe->dvb->priv; @@ -1019,9 +1024,10 @@ static void frontend_init(struct budget_av *budget_av) case SUBID_DVBC_KNC1_PLUS_MK3: budget_av->reinitialise_demod = 1; budget_av->budget.dev->i2c_bitrate = SAA7146_I2C_BUS_BIT_RATE_240; - fe = dvb_attach(tda10023_attach, &philips_cu1216_config, - &budget_av->budget.i2c_adap, - read_pwm(budget_av)); + fe = dvb_attach(tda10023_attach, + &philips_cu1216_tda10023_config, + &budget_av->budget.i2c_adap, + read_pwm(budget_av)); if (fe) { fe->ops.tuner_ops.set_params = philips_cu1216_tuner_set_params; } diff --git a/drivers/media/dvb/ttpci/budget-ci.c b/drivers/media/dvb/ttpci/budget-ci.c index 6530323d5406..060e7c785326 100644 --- a/drivers/media/dvb/ttpci/budget-ci.c +++ b/drivers/media/dvb/ttpci/budget-ci.c @@ -46,6 +46,8 @@ #include "lnbp21.h" #include "bsbe1.h" #include "bsru6.h" +#include "tda1002x.h" +#include "tda827x.h" /* * Regarding DEBIADDR_IR: @@ -225,6 +227,7 @@ static int msp430_ir_init(struct budget_ci *budget_ci) break; case 0x1010: case 0x1017: + case 0x101a: /* for the Technotrend 1500 bundled remote */ ir_input_init(input_dev, &budget_ci->ir.state, IR_TYPE_RC5, ir_codes_tt_1500); @@ -1056,6 +1059,15 @@ static struct stv0297_config dvbc_philips_tdm1316l_config = { .stop_during_read = 1, }; +static struct tda10023_config tda10023_config = { + .demod_address = 0xc, + .invert = 0, + .xtal = 16000000, + .pll_m = 11, + .pll_p = 3, + .pll_n = 1, + .deltaf = 0xa511, +}; @@ -1126,7 +1138,17 @@ static void frontend_init(struct budget_ci *budget_ci) budget_ci->budget.dvb_frontend = NULL; } } + break; + case 0x101a: /* TT Budget-C-1501 (philips tda10023/philips tda8274A) */ + budget_ci->budget.dvb_frontend = dvb_attach(tda10023_attach, &tda10023_config, &budget_ci->budget.i2c_adap, 0x48); + if (budget_ci->budget.dvb_frontend) { + if (dvb_attach(tda827x_attach, budget_ci->budget.dvb_frontend, 0x61, &budget_ci->budget.i2c_adap, NULL) == NULL) { + printk(KERN_ERR "%s: No tda827x found!\n", __func__); + dvb_frontend_detach(budget_ci->budget.dvb_frontend); + budget_ci->budget.dvb_frontend = NULL; + } + } break; } @@ -1216,6 +1238,7 @@ MAKE_BUDGET_INFO(ttbci, "TT-Budget/WinTV-NOVA-CI PCI", BUDGET_TT_HW_DISEQC); MAKE_BUDGET_INFO(ttbt2, "TT-Budget/WinTV-NOVA-T PCI", BUDGET_TT); MAKE_BUDGET_INFO(ttbtci, "TT-Budget-T-CI PCI", BUDGET_TT); MAKE_BUDGET_INFO(ttbcci, "TT-Budget-C-CI PCI", BUDGET_TT); +MAKE_BUDGET_INFO(ttc1501, "TT-Budget C-1501 PCI", BUDGET_TT); static struct pci_device_id pci_tbl[] = { MAKE_EXTENSION_PCI(ttbci, 0x13c2, 0x100c), @@ -1224,6 +1247,7 @@ static struct pci_device_id pci_tbl[] = { MAKE_EXTENSION_PCI(ttbt2, 0x13c2, 0x1011), MAKE_EXTENSION_PCI(ttbtci, 0x13c2, 0x1012), MAKE_EXTENSION_PCI(ttbs2, 0x13c2, 0x1017), + MAKE_EXTENSION_PCI(ttc1501, 0x13c2, 0x101a), { .vendor = 0, } diff --git a/drivers/media/dvb/ttpci/budget-core.c b/drivers/media/dvb/ttpci/budget-core.c index 18cac4b12ab2..6f4ddb643fee 100644 --- a/drivers/media/dvb/ttpci/budget-core.c +++ b/drivers/media/dvb/ttpci/budget-core.c @@ -497,11 +497,7 @@ int ttpci_budget_init(struct budget *budget, struct saa7146_dev *dev, if (bi->type != BUDGET_FS_ACTIVY) saa7146_write(dev, GPIO_CTRL, 0x500000); /* GPIO 3 = 1 */ -#ifdef I2C_ADAP_CLASS_TV_DIGITAL - budget->i2c_adap.class = I2C_ADAP_CLASS_TV_DIGITAL; -#else budget->i2c_adap.class = I2C_CLASS_TV_DIGITAL; -#endif strlcpy(budget->i2c_adap.name, budget->card->name, sizeof(budget->i2c_adap.name)); diff --git a/drivers/media/dvb/ttpci/budget-patch.c b/drivers/media/dvb/ttpci/budget-patch.c index 9a155396d6ac..39bd0a20f53a 100644 --- a/drivers/media/dvb/ttpci/budget-patch.c +++ b/drivers/media/dvb/ttpci/budget-patch.c @@ -431,22 +431,22 @@ static int budget_patch_attach (struct saa7146_dev* dev, struct saa7146_pci_exte // in budget patch GPIO3 is connected to VSYNC_B count = 0; #if 0 - WRITE_RPS1(cpu_to_le32(CMD_UPLOAD | - MASK_10 | MASK_09 | MASK_08 | MASK_06 | MASK_05 | MASK_04 | MASK_03 | MASK_02 )); + WRITE_RPS1(CMD_UPLOAD | + MASK_10 | MASK_09 | MASK_08 | MASK_06 | MASK_05 | MASK_04 | MASK_03 | MASK_02 ); #endif - WRITE_RPS1(cpu_to_le32(CMD_PAUSE | EVT_VBI_B)); - WRITE_RPS1(cpu_to_le32(CMD_WR_REG_MASK | (GPIO_CTRL>>2))); - WRITE_RPS1(cpu_to_le32(GPIO3_MSK)); - WRITE_RPS1(cpu_to_le32(SAA7146_GPIO_OUTLO<<24)); + WRITE_RPS1(CMD_PAUSE | EVT_VBI_B); + WRITE_RPS1(CMD_WR_REG_MASK | (GPIO_CTRL>>2)); + WRITE_RPS1(GPIO3_MSK); + WRITE_RPS1(SAA7146_GPIO_OUTLO<<24); #if RPS_IRQ // issue RPS1 interrupt to increment counter - WRITE_RPS1(cpu_to_le32(CMD_INTERRUPT)); + WRITE_RPS1(CMD_INTERRUPT); // at least a NOP is neede between two interrupts - WRITE_RPS1(cpu_to_le32(CMD_NOP)); + WRITE_RPS1(CMD_NOP); // interrupt again - WRITE_RPS1(cpu_to_le32(CMD_INTERRUPT)); + WRITE_RPS1(CMD_INTERRUPT); #endif - WRITE_RPS1(cpu_to_le32(CMD_STOP)); + WRITE_RPS1(CMD_STOP); #if RPS_IRQ // set event counter 1 source as RPS1 interrupt (0x03) (rE4 p53) @@ -558,28 +558,28 @@ static int budget_patch_attach (struct saa7146_dev* dev, struct saa7146_pci_exte // Wait Source Line Counter Threshold (p36) - WRITE_RPS1(cpu_to_le32(CMD_PAUSE | EVT_HS)); + WRITE_RPS1(CMD_PAUSE | EVT_HS); // Set GPIO3=1 (p42) - WRITE_RPS1(cpu_to_le32(CMD_WR_REG_MASK | (GPIO_CTRL>>2))); - WRITE_RPS1(cpu_to_le32(GPIO3_MSK)); - WRITE_RPS1(cpu_to_le32(SAA7146_GPIO_OUTHI<<24)); + WRITE_RPS1(CMD_WR_REG_MASK | (GPIO_CTRL>>2)); + WRITE_RPS1(GPIO3_MSK); + WRITE_RPS1(SAA7146_GPIO_OUTHI<<24); #if RPS_IRQ // issue RPS1 interrupt - WRITE_RPS1(cpu_to_le32(CMD_INTERRUPT)); + WRITE_RPS1(CMD_INTERRUPT); #endif // Wait reset Source Line Counter Threshold (p36) - WRITE_RPS1(cpu_to_le32(CMD_PAUSE | RPS_INV | EVT_HS)); + WRITE_RPS1(CMD_PAUSE | RPS_INV | EVT_HS); // Set GPIO3=0 (p42) - WRITE_RPS1(cpu_to_le32(CMD_WR_REG_MASK | (GPIO_CTRL>>2))); - WRITE_RPS1(cpu_to_le32(GPIO3_MSK)); - WRITE_RPS1(cpu_to_le32(SAA7146_GPIO_OUTLO<<24)); + WRITE_RPS1(CMD_WR_REG_MASK | (GPIO_CTRL>>2)); + WRITE_RPS1(GPIO3_MSK); + WRITE_RPS1(SAA7146_GPIO_OUTLO<<24); #if RPS_IRQ // issue RPS1 interrupt - WRITE_RPS1(cpu_to_le32(CMD_INTERRUPT)); + WRITE_RPS1(CMD_INTERRUPT); #endif // Jump to begin of RPS program (p37) - WRITE_RPS1(cpu_to_le32(CMD_JUMP)); - WRITE_RPS1(cpu_to_le32(dev->d_rps1.dma_handle)); + WRITE_RPS1(CMD_JUMP); + WRITE_RPS1(dev->d_rps1.dma_handle); // Fix VSYNC level saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTLO); diff --git a/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c b/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c index bc2043e44ebd..e6c9cd2e3b94 100644 --- a/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c +++ b/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c @@ -12,6 +12,7 @@ #include <linux/init.h> #include <linux/slab.h> #include <linux/wait.h> +#include <linux/fs.h> #include <linux/module.h> #include <linux/usb.h> #include <linux/delay.h> @@ -990,22 +991,9 @@ static int stc_open(struct inode *inode, struct file *file) } static ssize_t stc_read(struct file *file, char *buf, size_t count, - loff_t * offset) + loff_t *offset) { - int tc = count; - - if ((tc + *offset) > 8192) - tc = 8192 - *offset; - - if (tc < 0) - return 0; - - if (copy_to_user(buf, stc_firmware + *offset, tc)) - return -EFAULT; - - *offset += tc; - - return tc; + return simple_read_from_buffer(buf, count, offset, stc_firmware, 8192); } static int stc_release(struct inode *inode, struct file *file) @@ -1693,11 +1681,7 @@ static int ttusb_probe(struct usb_interface *intf, const struct usb_device_id *i i2c_set_adapdata(&ttusb->i2c_adap, ttusb); -#ifdef I2C_ADAP_CLASS_TV_DIGITAL - ttusb->i2c_adap.class = I2C_ADAP_CLASS_TV_DIGITAL; -#else ttusb->i2c_adap.class = I2C_CLASS_TV_DIGITAL; -#endif ttusb->i2c_adap.algo = &ttusb_dec_algo; ttusb->i2c_adap.algo_data = NULL; ttusb->i2c_adap.dev.parent = &udev->dev; diff --git a/drivers/media/radio/radio-si470x.c b/drivers/media/radio/radio-si470x.c index 77354ca6e8e9..dc93a882b385 100644 --- a/drivers/media/radio/radio-si470x.c +++ b/drivers/media/radio/radio-si470x.c @@ -24,6 +24,19 @@ /* + * User Notes: + * - USB Audio is provided by the alsa snd_usb_audio module. + * For listing you have to redirect the sound, for example using: + * arecord -D hw:1,0 -r96000 -c2 -f S16_LE | artsdsp aplay -B - + * - regarding module parameters in /sys/module/radio_si470x/parameters: + * the contents of read-only files (0444) are not updated, even if + * space, band and de are changed using private video controls + * - increase tune_timeout, if you often get -EIO errors + * - hw_freq_seek returns -EAGAIN, when timed out or band limit is reached + */ + + +/* * History: * 2008-01-12 Tobias Lorenz <tobias.lorenz@gmx.net> * Version 1.0.0 @@ -85,10 +98,14 @@ * Oliver Neukum <oliver@neukum.org> * Version 1.0.7 * - usb autosuspend support - * - unplugging fixed + * - unplugging fixed + * 2008-05-07 Tobias Lorenz <tobias.lorenz@gmx.net> + * Version 1.0.8 + * - hardware frequency seek support + * - afc indication + * - more safety checks, let si470x_get_freq return errno * * ToDo: - * - add seeking support * - add firmware download/update support * - RDS support: interrupt mode, instead of polling * - add LED status output (check if that's not already done in firmware) @@ -98,10 +115,10 @@ /* driver definitions */ #define DRIVER_AUTHOR "Tobias Lorenz <tobias.lorenz@gmx.net>" #define DRIVER_NAME "radio-si470x" -#define DRIVER_KERNEL_VERSION KERNEL_VERSION(1, 0, 7) +#define DRIVER_KERNEL_VERSION KERNEL_VERSION(1, 0, 8) #define DRIVER_CARD "Silicon Labs Si470x FM Radio Receiver" #define DRIVER_DESC "USB radio driver for Si470x FM Radio Receivers" -#define DRIVER_VERSION "1.0.7" +#define DRIVER_VERSION "1.0.8" /* kernel includes */ @@ -175,6 +192,11 @@ static unsigned int tune_timeout = 3000; module_param(tune_timeout, uint, 0); MODULE_PARM_DESC(tune_timeout, "Tune timeout: *3000*"); +/* Seek timeout */ +static unsigned int seek_timeout = 5000; +module_param(seek_timeout, uint, 0); +MODULE_PARM_DESC(seek_timeout, "Seek timeout: *5000*"); + /* RDS buffer blocks */ static unsigned int rds_buf = 100; module_param(rds_buf, uint, 0); @@ -425,7 +447,8 @@ struct si470x_device { /* driver management */ unsigned int users; - unsigned char disconnected; + unsigned char disconnected; + struct mutex disconnect_lock; /* Silabs internal registers (0..15) */ unsigned short registers[RADIO_REGISTER_NUM]; @@ -442,12 +465,6 @@ struct si470x_device { /* - * Lock to prevent kfree of data before all users have releases the device. - */ -static DEFINE_MUTEX(open_close_lock); - - -/* * The frequency is set in units of 62.5 Hz when using V4L2_TUNER_CAP_LOW, * 62.5 kHz otherwise. * The tuner is able to have a channel spacing of 50, 100 or 200 kHz. @@ -476,11 +493,11 @@ static int si470x_get_report(struct si470x_device *radio, void *buf, int size) USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN, report[0], 2, buf, size, usb_timeout); + if (retval < 0) printk(KERN_WARNING DRIVER_NAME ": si470x_get_report: usb_control_msg returned %d\n", retval); - return retval; } @@ -499,11 +516,11 @@ static int si470x_set_report(struct si470x_device *radio, void *buf, int size) USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_OUT, report[0], 2, buf, size, usb_timeout); + if (retval < 0) printk(KERN_WARNING DRIVER_NAME ": si470x_set_report: usb_control_msg returned %d\n", retval); - return retval; } @@ -521,8 +538,7 @@ static int si470x_get_register(struct si470x_device *radio, int regnr) retval = si470x_get_report(radio, (void *) &buf, sizeof(buf)); if (retval >= 0) - radio->registers[regnr] = be16_to_cpu(get_unaligned( - (unsigned short *) &buf[1])); + radio->registers[regnr] = get_unaligned_be16(&buf[1]); return (retval < 0) ? -EINVAL : 0; } @@ -537,8 +553,7 @@ static int si470x_set_register(struct si470x_device *radio, int regnr) int retval; buf[0] = REGISTER_REPORT(regnr); - put_unaligned(cpu_to_be16(radio->registers[regnr]), - (unsigned short *) &buf[1]); + put_unaligned_be16(radio->registers[regnr], &buf[1]); retval = si470x_set_report(radio, (void *) &buf, sizeof(buf)); @@ -561,9 +576,8 @@ static int si470x_get_all_registers(struct si470x_device *radio) if (retval >= 0) for (regnr = 0; regnr < RADIO_REGISTER_NUM; regnr++) - radio->registers[regnr] = be16_to_cpu(get_unaligned( - (unsigned short *) - &buf[regnr * RADIO_REGISTER_SIZE + 1])); + radio->registers[regnr] = get_unaligned_be16( + &buf[regnr * RADIO_REGISTER_SIZE + 1]); return (retval < 0) ? -EINVAL : 0; } @@ -585,7 +599,7 @@ static int si470x_get_rds_registers(struct si470x_device *radio) usb_rcvintpipe(radio->usbdev, 1), (void *) &buf, sizeof(buf), &size, usb_timeout); if (size != sizeof(buf)) - printk(KERN_WARNING DRIVER_NAME ": si470x_get_rds_registers: " + printk(KERN_WARNING DRIVER_NAME ": si470x_get_rds_registers: " "return size differs: %d != %zu\n", size, sizeof(buf)); if (retval < 0) printk(KERN_WARNING DRIVER_NAME ": si470x_get_rds_registers: " @@ -594,8 +608,8 @@ static int si470x_get_rds_registers(struct si470x_device *radio) if (retval >= 0) for (regnr = 0; regnr < RDS_REGISTER_NUM; regnr++) radio->registers[STATUSRSSI + regnr] = - be16_to_cpu(get_unaligned((unsigned short *) - &buf[regnr * RADIO_REGISTER_SIZE + 1])); + get_unaligned_be16( + &buf[regnr * RADIO_REGISTER_SIZE + 1]); return (retval < 0) ? -EINVAL : 0; } @@ -615,33 +629,39 @@ static int si470x_set_chan(struct si470x_device *radio, unsigned short chan) radio->registers[CHANNEL] |= CHANNEL_TUNE | chan; retval = si470x_set_register(radio, CHANNEL); if (retval < 0) - return retval; + goto done; - /* wait till seek operation has completed */ + /* wait till tune operation has completed */ timeout = jiffies + msecs_to_jiffies(tune_timeout); do { retval = si470x_get_register(radio, STATUSRSSI); if (retval < 0) - return retval; + goto stop; timed_out = time_after(jiffies, timeout); } while (((radio->registers[STATUSRSSI] & STATUSRSSI_STC) == 0) && (!timed_out)); + if ((radio->registers[STATUSRSSI] & STATUSRSSI_STC) == 0) + printk(KERN_WARNING DRIVER_NAME ": tune does not complete\n"); if (timed_out) printk(KERN_WARNING DRIVER_NAME - ": seek does not finish after %u ms\n", tune_timeout); + ": tune timed out after %u ms\n", tune_timeout); +stop: /* stop tuning */ radio->registers[CHANNEL] &= ~CHANNEL_TUNE; - return si470x_set_register(radio, CHANNEL); + retval = si470x_set_register(radio, CHANNEL); + +done: + return retval; } /* * si470x_get_freq - get the frequency */ -static unsigned int si470x_get_freq(struct si470x_device *radio) +static int si470x_get_freq(struct si470x_device *radio, unsigned int *freq) { - unsigned int spacing, band_bottom, freq; + unsigned int spacing, band_bottom; unsigned short chan; int retval; @@ -667,14 +687,12 @@ static unsigned int si470x_get_freq(struct si470x_device *radio) /* read channel */ retval = si470x_get_register(radio, READCHAN); - if (retval < 0) - return retval; chan = radio->registers[READCHAN] & READCHAN_READCHAN; /* Frequency (MHz) = Spacing (kHz) x Channel + Bottom of Band (MHz) */ - freq = chan * spacing + band_bottom; + *freq = chan * spacing + band_bottom; - return freq; + return retval; } @@ -714,6 +732,62 @@ static int si470x_set_freq(struct si470x_device *radio, unsigned int freq) /* + * si470x_set_seek - set seek + */ +static int si470x_set_seek(struct si470x_device *radio, + unsigned int wrap_around, unsigned int seek_upward) +{ + int retval = 0; + unsigned long timeout; + bool timed_out = 0; + + /* start seeking */ + radio->registers[POWERCFG] |= POWERCFG_SEEK; + if (wrap_around == 1) + radio->registers[POWERCFG] &= ~POWERCFG_SKMODE; + else + radio->registers[POWERCFG] |= POWERCFG_SKMODE; + if (seek_upward == 1) + radio->registers[POWERCFG] |= POWERCFG_SEEKUP; + else + radio->registers[POWERCFG] &= ~POWERCFG_SEEKUP; + retval = si470x_set_register(radio, POWERCFG); + if (retval < 0) + goto done; + + /* wait till seek operation has completed */ + timeout = jiffies + msecs_to_jiffies(seek_timeout); + do { + retval = si470x_get_register(radio, STATUSRSSI); + if (retval < 0) + goto stop; + timed_out = time_after(jiffies, timeout); + } while (((radio->registers[STATUSRSSI] & STATUSRSSI_STC) == 0) && + (!timed_out)); + if ((radio->registers[STATUSRSSI] & STATUSRSSI_STC) == 0) + printk(KERN_WARNING DRIVER_NAME ": seek does not complete\n"); + if (radio->registers[STATUSRSSI] & STATUSRSSI_SF) + printk(KERN_WARNING DRIVER_NAME + ": seek failed / band limit reached\n"); + if (timed_out) + printk(KERN_WARNING DRIVER_NAME + ": seek timed out after %u ms\n", seek_timeout); + +stop: + /* stop seeking */ + radio->registers[POWERCFG] &= ~POWERCFG_SEEK; + retval = si470x_set_register(radio, POWERCFG); + +done: + /* try again, if timed out */ + if ((retval == 0) && timed_out) + retval = -EAGAIN; + + return retval; +} + + +/* * si470x_start - switch on radio */ static int si470x_start(struct si470x_device *radio) @@ -725,27 +799,30 @@ static int si470x_start(struct si470x_device *radio) POWERCFG_DMUTE | POWERCFG_ENABLE | POWERCFG_RDSM; retval = si470x_set_register(radio, POWERCFG); if (retval < 0) - return retval; + goto done; /* sysconfig 1 */ radio->registers[SYSCONFIG1] = SYSCONFIG1_DE; retval = si470x_set_register(radio, SYSCONFIG1); if (retval < 0) - return retval; + goto done; /* sysconfig 2 */ radio->registers[SYSCONFIG2] = - (0x3f << 8) | /* SEEKTH */ - (band << 6) | /* BAND */ - (space << 4) | /* SPACE */ - 15; /* VOLUME (max) */ + (0x3f << 8) | /* SEEKTH */ + ((band << 6) & SYSCONFIG2_BAND) | /* BAND */ + ((space << 4) & SYSCONFIG2_SPACE) | /* SPACE */ + 15; /* VOLUME (max) */ retval = si470x_set_register(radio, SYSCONFIG2); if (retval < 0) - return retval; + goto done; /* reset last channel */ - return si470x_set_chan(radio, + retval = si470x_set_chan(radio, radio->registers[CHANNEL] & CHANNEL_CHAN); + +done: + return retval; } @@ -760,13 +837,16 @@ static int si470x_stop(struct si470x_device *radio) radio->registers[SYSCONFIG1] &= ~SYSCONFIG1_RDS; retval = si470x_set_register(radio, SYSCONFIG1); if (retval < 0) - return retval; + goto done; /* powercfg */ radio->registers[POWERCFG] &= ~POWERCFG_DMUTE; /* POWERCFG_ENABLE has to automatically go low */ radio->registers[POWERCFG] |= POWERCFG_ENABLE | POWERCFG_DISABLE; - return si470x_set_register(radio, POWERCFG); + retval = si470x_set_register(radio, POWERCFG); + +done: + return retval; } @@ -843,7 +923,7 @@ static void si470x_rds(struct si470x_device *radio) }; /* Fill the V4L2 RDS buffer */ - put_unaligned(cpu_to_le16(rds), (unsigned short *) &tmpbuf); + put_unaligned_le16(rds, &tmpbuf); tmpbuf[2] = blocknum; /* offset name */ tmpbuf[2] |= blocknum << 3; /* received offset */ if (bler > max_rds_errors) @@ -883,8 +963,9 @@ static void si470x_work(struct work_struct *work) struct si470x_device *radio = container_of(work, struct si470x_device, work.work); - if (radio->disconnected) - return; + /* safety checks */ + if (radio->disconnected) + return; if ((radio->registers[SYSCONFIG1] & SYSCONFIG1_RDS) == 0) return; @@ -917,11 +998,15 @@ static ssize_t si470x_fops_read(struct file *file, char __user *buf, /* block if no new data available */ while (radio->wr_index == radio->rd_index) { - if (file->f_flags & O_NONBLOCK) - return -EWOULDBLOCK; + if (file->f_flags & O_NONBLOCK) { + retval = -EWOULDBLOCK; + goto done; + } if (wait_event_interruptible(radio->read_queue, - radio->wr_index != radio->rd_index) < 0) - return -EINTR; + radio->wr_index != radio->rd_index) < 0) { + retval = -EINTR; + goto done; + } } /* calculate block count from byte count */ @@ -950,6 +1035,7 @@ static ssize_t si470x_fops_read(struct file *file, char __user *buf, } mutex_unlock(&radio->lock); +done: return retval; } @@ -961,6 +1047,7 @@ static unsigned int si470x_fops_poll(struct file *file, struct poll_table_struct *pts) { struct si470x_device *radio = video_get_drvdata(video_devdata(file)); + int retval = 0; /* switch on rds reception */ if ((radio->registers[SYSCONFIG1] & SYSCONFIG1_RDS) == 0) { @@ -972,9 +1059,9 @@ static unsigned int si470x_fops_poll(struct file *file, poll_wait(file, &radio->read_queue, pts); if (radio->rd_index != radio->wr_index) - return POLLIN | POLLRDNORM; + retval = POLLIN | POLLRDNORM; - return 0; + return retval; } @@ -991,17 +1078,18 @@ static int si470x_fops_open(struct inode *inode, struct file *file) retval = usb_autopm_get_interface(radio->intf); if (retval < 0) { radio->users--; - return -EIO; + retval = -EIO; + goto done; } if (radio->users == 1) { retval = si470x_start(radio); if (retval < 0) usb_autopm_put_interface(radio->intf); - return retval; } - return 0; +done: + return retval; } @@ -1011,20 +1099,23 @@ static int si470x_fops_open(struct inode *inode, struct file *file) static int si470x_fops_release(struct inode *inode, struct file *file) { struct si470x_device *radio = video_get_drvdata(video_devdata(file)); - int retval = 0; + int retval = 0; - if (!radio) - return -ENODEV; + /* safety check */ + if (!radio) { + retval = -ENODEV; + goto done; + } - mutex_lock(&open_close_lock); + mutex_lock(&radio->disconnect_lock); radio->users--; if (radio->users == 0) { - if (radio->disconnected) { - video_unregister_device(radio->videodev); - kfree(radio->buffer); - kfree(radio); - goto done; - } + if (radio->disconnected) { + video_unregister_device(radio->videodev); + kfree(radio->buffer); + kfree(radio); + goto unlock; + } /* stop rds reception */ cancel_delayed_work_sync(&radio->work); @@ -1036,9 +1127,11 @@ static int si470x_fops_release(struct inode *inode, struct file *file) usb_autopm_put_interface(radio->intf); } +unlock: + mutex_unlock(&radio->disconnect_lock); + done: - mutex_unlock(&open_close_lock); - return retval; + return retval; } @@ -1116,7 +1209,8 @@ static int si470x_vidioc_querycap(struct file *file, void *priv, strlcpy(capability->card, DRIVER_CARD, sizeof(capability->card)); sprintf(capability->bus_info, "USB"); capability->version = DRIVER_KERNEL_VERSION; - capability->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO; + capability->capabilities = V4L2_CAP_HW_FREQ_SEEK | + V4L2_CAP_TUNER | V4L2_CAP_RADIO; return 0; } @@ -1125,7 +1219,7 @@ static int si470x_vidioc_querycap(struct file *file, void *priv, /* * si470x_vidioc_g_input - get input */ -static int si470x_vidioc_g_input(struct file *filp, void *priv, +static int si470x_vidioc_g_input(struct file *file, void *priv, unsigned int *i) { *i = 0; @@ -1137,12 +1231,18 @@ static int si470x_vidioc_g_input(struct file *filp, void *priv, /* * si470x_vidioc_s_input - set input */ -static int si470x_vidioc_s_input(struct file *filp, void *priv, unsigned int i) +static int si470x_vidioc_s_input(struct file *file, void *priv, unsigned int i) { + int retval = 0; + + /* safety checks */ if (i != 0) - return -EINVAL; + retval = -EINVAL; - return 0; + if (retval < 0) + printk(KERN_WARNING DRIVER_NAME + ": set input failed with %d\n", retval); + return retval; } @@ -1155,17 +1255,22 @@ static int si470x_vidioc_queryctrl(struct file *file, void *priv, unsigned char i; int retval = -EINVAL; + /* safety checks */ + if (!qc->id) + goto done; + for (i = 0; i < ARRAY_SIZE(si470x_v4l2_queryctrl); i++) { - if (qc->id && qc->id == si470x_v4l2_queryctrl[i].id) { + if (qc->id == si470x_v4l2_queryctrl[i].id) { memcpy(qc, &(si470x_v4l2_queryctrl[i]), sizeof(*qc)); retval = 0; break; } } + +done: if (retval < 0) printk(KERN_WARNING DRIVER_NAME - ": query control failed with %d\n", retval); - + ": query controls failed with %d\n", retval); return retval; } @@ -1177,9 +1282,13 @@ static int si470x_vidioc_g_ctrl(struct file *file, void *priv, struct v4l2_control *ctrl) { struct si470x_device *radio = video_get_drvdata(video_devdata(file)); + int retval = 0; - if (radio->disconnected) - return -EIO; + /* safety checks */ + if (radio->disconnected) { + retval = -EIO; + goto done; + } switch (ctrl->id) { case V4L2_CID_AUDIO_VOLUME: @@ -1190,9 +1299,15 @@ static int si470x_vidioc_g_ctrl(struct file *file, void *priv, ctrl->value = ((radio->registers[POWERCFG] & POWERCFG_DMUTE) == 0) ? 1 : 0; break; + default: + retval = -EINVAL; } - return 0; +done: + if (retval < 0) + printk(KERN_WARNING DRIVER_NAME + ": get control failed with %d\n", retval); + return retval; } @@ -1203,10 +1318,13 @@ static int si470x_vidioc_s_ctrl(struct file *file, void *priv, struct v4l2_control *ctrl) { struct si470x_device *radio = video_get_drvdata(video_devdata(file)); - int retval; + int retval = 0; - if (radio->disconnected) - return -EIO; + /* safety checks */ + if (radio->disconnected) { + retval = -EIO; + goto done; + } switch (ctrl->id) { case V4L2_CID_AUDIO_VOLUME: @@ -1224,10 +1342,11 @@ static int si470x_vidioc_s_ctrl(struct file *file, void *priv, default: retval = -EINVAL; } + +done: if (retval < 0) printk(KERN_WARNING DRIVER_NAME ": set control failed with %d\n", retval); - return retval; } @@ -1238,13 +1357,22 @@ static int si470x_vidioc_s_ctrl(struct file *file, void *priv, static int si470x_vidioc_g_audio(struct file *file, void *priv, struct v4l2_audio *audio) { - if (audio->index > 1) - return -EINVAL; + int retval = 0; + + /* safety checks */ + if (audio->index != 0) { + retval = -EINVAL; + goto done; + } strcpy(audio->name, "Radio"); audio->capability = V4L2_AUDCAP_STEREO; - return 0; +done: + if (retval < 0) + printk(KERN_WARNING DRIVER_NAME + ": get audio failed with %d\n", retval); + return retval; } @@ -1254,10 +1382,19 @@ static int si470x_vidioc_g_audio(struct file *file, void *priv, static int si470x_vidioc_s_audio(struct file *file, void *priv, struct v4l2_audio *audio) { - if (audio->index != 0) - return -EINVAL; + int retval = 0; - return 0; + /* safety checks */ + if (audio->index != 0) { + retval = -EINVAL; + goto done; + } + +done: + if (retval < 0) + printk(KERN_WARNING DRIVER_NAME + ": set audio failed with %d\n", retval); + return retval; } @@ -1268,20 +1405,23 @@ static int si470x_vidioc_g_tuner(struct file *file, void *priv, struct v4l2_tuner *tuner) { struct si470x_device *radio = video_get_drvdata(video_devdata(file)); - int retval; + int retval = 0; - if (radio->disconnected) - return -EIO; - if (tuner->index > 0) - return -EINVAL; + /* safety checks */ + if (radio->disconnected) { + retval = -EIO; + goto done; + } + if ((tuner->index != 0) && (tuner->type != V4L2_TUNER_RADIO)) { + retval = -EINVAL; + goto done; + } - /* read status rssi */ retval = si470x_get_register(radio, STATUSRSSI); if (retval < 0) - return retval; + goto done; strcpy(tuner->name, "FM"); - tuner->type = V4L2_TUNER_RADIO; switch (band) { /* 0: 87.5 - 108 MHz (USA, Europe, default) */ default: @@ -1313,9 +1453,14 @@ static int si470x_vidioc_g_tuner(struct file *file, void *priv, * 0x0101; /* automatic frequency control: -1: freq to low, 1 freq to high */ - tuner->afc = 0; + /* AFCRL does only indicate that freq. differs, not if too low/high */ + tuner->afc = (radio->registers[STATUSRSSI] & STATUSRSSI_AFCRL) ? 1 : 0; - return 0; +done: + if (retval < 0) + printk(KERN_WARNING DRIVER_NAME + ": get tuner failed with %d\n", retval); + return retval; } @@ -1326,12 +1471,17 @@ static int si470x_vidioc_s_tuner(struct file *file, void *priv, struct v4l2_tuner *tuner) { struct si470x_device *radio = video_get_drvdata(video_devdata(file)); - int retval; + int retval = 0; - if (radio->disconnected) - return -EIO; - if (tuner->index > 0) - return -EINVAL; + /* safety checks */ + if (radio->disconnected) { + retval = -EIO; + goto done; + } + if ((tuner->index != 0) && (tuner->type != V4L2_TUNER_RADIO)) { + retval = -EINVAL; + goto done; + } if (tuner->audmode == V4L2_TUNER_MODE_MONO) radio->registers[POWERCFG] |= POWERCFG_MONO; /* force mono */ @@ -1339,10 +1489,11 @@ static int si470x_vidioc_s_tuner(struct file *file, void *priv, radio->registers[POWERCFG] &= ~POWERCFG_MONO; /* try stereo */ retval = si470x_set_register(radio, POWERCFG); + +done: if (retval < 0) printk(KERN_WARNING DRIVER_NAME ": set tuner failed with %d\n", retval); - return retval; } @@ -1354,14 +1505,25 @@ static int si470x_vidioc_g_frequency(struct file *file, void *priv, struct v4l2_frequency *freq) { struct si470x_device *radio = video_get_drvdata(video_devdata(file)); + int retval = 0; - if (radio->disconnected) - return -EIO; + /* safety checks */ + if (radio->disconnected) { + retval = -EIO; + goto done; + } + if ((freq->tuner != 0) && (freq->type != V4L2_TUNER_RADIO)) { + retval = -EINVAL; + goto done; + } - freq->type = V4L2_TUNER_RADIO; - freq->frequency = si470x_get_freq(radio); + retval = si470x_get_freq(radio, &freq->frequency); - return 0; +done: + if (retval < 0) + printk(KERN_WARNING DRIVER_NAME + ": get frequency failed with %d\n", retval); + return retval; } @@ -1372,19 +1534,55 @@ static int si470x_vidioc_s_frequency(struct file *file, void *priv, struct v4l2_frequency *freq) { struct si470x_device *radio = video_get_drvdata(video_devdata(file)); - int retval; + int retval = 0; - if (radio->disconnected) - return -EIO; - if (freq->type != V4L2_TUNER_RADIO) - return -EINVAL; + /* safety checks */ + if (radio->disconnected) { + retval = -EIO; + goto done; + } + if ((freq->tuner != 0) && (freq->type != V4L2_TUNER_RADIO)) { + retval = -EINVAL; + goto done; + } retval = si470x_set_freq(radio, freq->frequency); + +done: if (retval < 0) printk(KERN_WARNING DRIVER_NAME ": set frequency failed with %d\n", retval); + return retval; +} - return 0; + +/* + * si470x_vidioc_s_hw_freq_seek - set hardware frequency seek + */ +static int si470x_vidioc_s_hw_freq_seek(struct file *file, void *priv, + struct v4l2_hw_freq_seek *seek) +{ + struct si470x_device *radio = video_get_drvdata(video_devdata(file)); + int retval = 0; + + /* safety checks */ + if (radio->disconnected) { + retval = -EIO; + goto done; + } + if ((seek->tuner != 0) && (seek->type != V4L2_TUNER_RADIO)) { + retval = -EINVAL; + goto done; + } + + retval = si470x_set_seek(radio, seek->wrap_around, seek->seek_upward); + +done: + if (retval < 0) + printk(KERN_WARNING DRIVER_NAME + ": set hardware frequency seek failed with %d\n", + retval); + return retval; } @@ -1408,6 +1606,7 @@ static struct video_device si470x_viddev_template = { .vidioc_s_tuner = si470x_vidioc_s_tuner, .vidioc_g_frequency = si470x_vidioc_g_frequency, .vidioc_s_frequency = si470x_vidioc_s_frequency, + .vidioc_s_hw_freq_seek = si470x_vidioc_s_hw_freq_seek, .owner = THIS_MODULE, }; @@ -1424,31 +1623,36 @@ static int si470x_usb_driver_probe(struct usb_interface *intf, const struct usb_device_id *id) { struct si470x_device *radio; - int retval = -ENOMEM; + int retval = 0; - /* private data allocation */ + /* private data allocation and initialization */ radio = kzalloc(sizeof(struct si470x_device), GFP_KERNEL); - if (!radio) + if (!radio) { + retval = -ENOMEM; goto err_initial; + } + radio->users = 0; + radio->disconnected = 0; + radio->usbdev = interface_to_usbdev(intf); + radio->intf = intf; + mutex_init(&radio->disconnect_lock); + mutex_init(&radio->lock); - /* video device allocation */ + /* video device allocation and initialization */ radio->videodev = video_device_alloc(); - if (!radio->videodev) + if (!radio->videodev) { + retval = -ENOMEM; goto err_radio; - - /* initial configuration */ + } memcpy(radio->videodev, &si470x_viddev_template, sizeof(si470x_viddev_template)); - radio->users = 0; - radio->usbdev = interface_to_usbdev(intf); - radio->intf = intf; - mutex_init(&radio->lock); video_set_drvdata(radio->videodev, radio); /* show some infos about the specific device */ - retval = -EIO; - if (si470x_get_all_registers(radio) < 0) + if (si470x_get_all_registers(radio) < 0) { + retval = -EIO; goto err_all; + } printk(KERN_INFO DRIVER_NAME ": DeviceID=0x%4.4hx ChipID=0x%4.4hx\n", radio->registers[DEVICEID], radio->registers[CHIPID]); @@ -1474,8 +1678,10 @@ static int si470x_usb_driver_probe(struct usb_interface *intf, /* rds buffer allocation */ radio->buf_size = rds_buf * 3; radio->buffer = kmalloc(radio->buf_size, GFP_KERNEL); - if (!radio->buffer) + if (!radio->buffer) { + retval = -EIO; goto err_all; + } /* rds buffer configuration */ radio->wr_index = 0; @@ -1487,6 +1693,7 @@ static int si470x_usb_driver_probe(struct usb_interface *intf, /* register video device */ if (video_register_device(radio->videodev, VFL_TYPE_RADIO, radio_nr)) { + retval = -EIO; printk(KERN_WARNING DRIVER_NAME ": Could not register video device\n"); goto err_all; @@ -1546,16 +1753,16 @@ static void si470x_usb_driver_disconnect(struct usb_interface *intf) { struct si470x_device *radio = usb_get_intfdata(intf); - mutex_lock(&open_close_lock); - radio->disconnected = 1; + mutex_lock(&radio->disconnect_lock); + radio->disconnected = 1; cancel_delayed_work_sync(&radio->work); usb_set_intfdata(intf, NULL); - if (radio->users == 0) { - video_unregister_device(radio->videodev); - kfree(radio->buffer); - kfree(radio); - } - mutex_unlock(&open_close_lock); + if (radio->users == 0) { + video_unregister_device(radio->videodev); + kfree(radio->buffer); + kfree(radio); + } + mutex_unlock(&radio->disconnect_lock); } diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig index 5ccb0aeca8cc..f606d2951fde 100644 --- a/drivers/media/video/Kconfig +++ b/drivers/media/video/Kconfig @@ -24,21 +24,21 @@ config VIDEOBUF_VMALLOC select VIDEOBUF_GEN tristate +config VIDEOBUF_DMA_CONTIG + depends on HAS_DMA + select VIDEOBUF_GEN + tristate + config VIDEOBUF_DVB tristate select VIDEOBUF_GEN - select VIDEOBUF_DMA_SG config VIDEO_BTCX tristate -config VIDEO_IR_I2C - tristate - config VIDEO_IR tristate depends on INPUT - select VIDEO_IR_I2C if I2C config VIDEO_TVEEPROM tristate @@ -84,6 +84,19 @@ config VIDEO_HELPER_CHIPS_AUTO In doubt, say Y. +config VIDEO_IR_I2C + tristate "I2C module for IR" if !VIDEO_HELPER_CHIPS_AUTO + depends on I2C && VIDEO_IR + default y + ---help--- + Most boards have an IR chip directly connected via GPIO. However, + some video boards have the IR connected via I2C bus. + + If your board doesn't have an I2C IR chip, you may disable this + option. + + In doubt, say Y. + # # Encoder / Decoder module configuration # @@ -600,9 +613,6 @@ config VIDEO_STRADIS driver for PCI. There is a product page at <http://www.stradis.com/>. -config VIDEO_ZORAN_ZR36060 - tristate - config VIDEO_ZORAN tristate "Zoran ZR36057/36067 Video For Linux" depends on PCI && I2C_ALGOBIT && VIDEO_V4L1 && VIRT_TO_BUS @@ -616,61 +626,64 @@ config VIDEO_ZORAN To compile this driver as a module, choose M here: the module will be called zr36067. +config VIDEO_ZORAN_DC30 + tristate "Pinnacle/Miro DC30(+) support" + depends on VIDEO_ZORAN + select VIDEO_ADV7175 if VIDEO_HELPER_CHIPS_AUTO + select VIDEO_VPX3220 if VIDEO_HELPER_CHIPS_AUTO + help + Support for the Pinnacle/Miro DC30(+) MJPEG capture/playback + card. This also supports really old DC10 cards based on the + zr36050 MJPEG codec and zr36016 VFE. + +config VIDEO_ZORAN_ZR36060 + tristate "Zoran ZR36060" + depends on VIDEO_ZORAN + help + Say Y to support Zoran boards based on 36060 chips. + This includes Iomega Bus, Pinnacle DC10, Linux media Labs 33 + and 33 R10 and AverMedia 6 boards. + config VIDEO_ZORAN_BUZ tristate "Iomega Buz support" - depends on VIDEO_ZORAN + depends on VIDEO_ZORAN_ZR36060 select VIDEO_SAA7111 if VIDEO_HELPER_CHIPS_AUTO select VIDEO_SAA7185 if VIDEO_HELPER_CHIPS_AUTO - select VIDEO_ZORAN_ZR36060 help Support for the Iomega Buz MJPEG capture/playback card. config VIDEO_ZORAN_DC10 tristate "Pinnacle/Miro DC10(+) support" - depends on VIDEO_ZORAN - select VIDEO_SAA7110 + depends on VIDEO_ZORAN_ZR36060 + select VIDEO_SAA7110 if VIDEO_HELPER_CHIPS_AUTO select VIDEO_ADV7175 if VIDEO_HELPER_CHIPS_AUTO - select VIDEO_ZORAN_ZR36060 help Support for the Pinnacle/Miro DC10(+) MJPEG capture/playback card. -config VIDEO_ZORAN_DC30 - tristate "Pinnacle/Miro DC30(+) support" - depends on VIDEO_ZORAN - select VIDEO_ADV7175 if VIDEO_HELPER_CHIPS_AUTO - select VIDEO_VPX3220 if VIDEO_HELPER_CHIPS_AUTO - help - Support for the Pinnacle/Miro DC30(+) MJPEG capture/playback - card. This also supports really old DC10 cards based on the - zr36050 MJPEG codec and zr36016 VFE. - config VIDEO_ZORAN_LML33 tristate "Linux Media Labs LML33 support" - depends on VIDEO_ZORAN + depends on VIDEO_ZORAN_ZR36060 select VIDEO_BT819 if VIDEO_HELPER_CHIPS_AUTO select VIDEO_BT856 if VIDEO_HELPER_CHIPS_AUTO - select VIDEO_ZORAN_ZR36060 help Support for the Linux Media Labs LML33 MJPEG capture/playback card. config VIDEO_ZORAN_LML33R10 tristate "Linux Media Labs LML33R10 support" - depends on VIDEO_ZORAN + depends on VIDEO_ZORAN_ZR36060 select VIDEO_SAA7114 if VIDEO_HELPER_CHIPS_AUTO select VIDEO_ADV7170 if VIDEO_HELPER_CHIPS_AUTO - select VIDEO_ZORAN_ZR36060 help support for the Linux Media Labs LML33R10 MJPEG capture/playback card. config VIDEO_ZORAN_AVS6EYES tristate "AverMedia 6 Eyes support (EXPERIMENTAL)" - depends on VIDEO_ZORAN && EXPERIMENTAL && VIDEO_V4L1 + depends on VIDEO_ZORAN_ZR36060 && EXPERIMENTAL && VIDEO_V4L1 select VIDEO_BT856 if VIDEO_HELPER_CHIPS_AUTO select VIDEO_KS0127 if VIDEO_HELPER_CHIPS_AUTO - select VIDEO_ZORAN_ZR36060 help Support for the AverMedia 6 Eyes video surveillance card. @@ -801,6 +814,8 @@ config USB_VIDEO_CLASS For more information see: <http://linux-uvc.berlios.de/> +source "drivers/media/video/gspca/Kconfig" + source "drivers/media/video/pvrusb2/Kconfig" source "drivers/media/video/em28xx/Kconfig" @@ -905,12 +920,21 @@ config USB_STKWEBCAM To compile this driver as a module, choose M here: the module will be called stkwebcam. +config USB_S2255 + tristate "USB Sensoray 2255 video capture device" + depends on VIDEO_V4L2 + select VIDEOBUF_VMALLOC + default n + help + Say Y here if you want support for the Sensoray 2255 USB device. + This driver can be compiled as a module, called s2255drv. + endif # V4L_USB_DRIVERS config SOC_CAMERA tristate "SoC camera support" depends on VIDEO_V4L2 && HAS_DMA - select VIDEOBUF_DMA_SG + select VIDEOBUF_GEN help SoC Camera is a common API to several cameras, not connecting over a bus like PCI or USB. For example some i2c camera connected @@ -945,11 +969,26 @@ config MT9V022_PCA9536_SWITCH Select this if your MT9V022 camera uses a PCA9536 I2C GPIO extender to switch between 8 and 10 bit datawidth modes +config SOC_CAMERA_PLATFORM + tristate "platform camera support" + depends on SOC_CAMERA + help + This is a generic SoC camera platform driver, useful for testing + config VIDEO_PXA27x tristate "PXA27x Quick Capture Interface driver" depends on VIDEO_DEV && PXA27x select SOC_CAMERA + select VIDEOBUF_DMA_SG ---help--- This is a v4l2 driver for the PXA27x Quick Capture Interface +config VIDEO_SH_MOBILE_CEU + tristate "SuperH Mobile CEU Interface driver" + depends on VIDEO_DEV + select SOC_CAMERA + select VIDEOBUF_DMA_CONTIG + ---help--- + This is a v4l2 driver for the SuperH Mobile CEU Interface + endif # VIDEO_CAPTURE_DRIVERS diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile index ecbbfaab24d5..45d5db5abb1e 100644 --- a/drivers/media/video/Makefile +++ b/drivers/media/video/Makefile @@ -88,6 +88,7 @@ obj-$(CONFIG_VIDEO_TUNER) += tuner.o obj-$(CONFIG_VIDEOBUF_GEN) += videobuf-core.o obj-$(CONFIG_VIDEOBUF_DMA_SG) += videobuf-dma-sg.o +obj-$(CONFIG_VIDEOBUF_DMA_CONTIG) += videobuf-dma-contig.o obj-$(CONFIG_VIDEOBUF_VMALLOC) += videobuf-vmalloc.o obj-$(CONFIG_VIDEOBUF_DVB) += videobuf-dvb.o obj-$(CONFIG_VIDEO_BTCX) += btcx-risc.o @@ -117,11 +118,13 @@ obj-$(CONFIG_USB_SN9C102) += sn9c102/ obj-$(CONFIG_USB_ET61X251) += et61x251/ obj-$(CONFIG_USB_PWC) += pwc/ obj-$(CONFIG_USB_ZC0301) += zc0301/ +obj-$(CONFIG_USB_GSPCA) += gspca/ obj-$(CONFIG_USB_IBMCAM) += usbvideo/ obj-$(CONFIG_USB_KONICAWC) += usbvideo/ obj-$(CONFIG_USB_VICAM) += usbvideo/ obj-$(CONFIG_USB_QUICKCAM_MESSENGER) += usbvideo/ +obj-$(CONFIG_USB_S2255) += s2255drv.o obj-$(CONFIG_VIDEO_IVTV) += ivtv/ obj-$(CONFIG_VIDEO_CX18) += cx18/ @@ -130,9 +133,11 @@ obj-$(CONFIG_VIDEO_VIVI) += vivi.o obj-$(CONFIG_VIDEO_CX23885) += cx23885/ obj-$(CONFIG_VIDEO_PXA27x) += pxa_camera.o +obj-$(CONFIG_VIDEO_SH_MOBILE_CEU) += sh_mobile_ceu_camera.o obj-$(CONFIG_SOC_CAMERA) += soc_camera.o obj-$(CONFIG_SOC_CAMERA_MT9M001) += mt9m001.o obj-$(CONFIG_SOC_CAMERA_MT9V022) += mt9v022.o +obj-$(CONFIG_SOC_CAMERA_PLATFORM) += soc_camera_platform.o obj-$(CONFIG_VIDEO_AU0828) += au0828/ diff --git a/drivers/media/video/bt819.c b/drivers/media/video/bt819.c index 8bfd5c75cb3a..ddd2a7964dec 100644 --- a/drivers/media/video/bt819.c +++ b/drivers/media/video/bt819.c @@ -516,7 +516,7 @@ bt819_detect_client (struct i2c_adapter *adapter, dprintk(1, KERN_INFO - "saa7111.c: detecting bt819 client on address 0x%x\n", + "bt819: detecting bt819 client on address 0x%x\n", address << 1); /* Check if the adapter supports the needed features */ diff --git a/drivers/media/video/bt8xx/bt832.c b/drivers/media/video/bt8xx/bt832.c index f92f06dec0d0..216fc9680e80 100644 --- a/drivers/media/video/bt8xx/bt832.c +++ b/drivers/media/video/bt8xx/bt832.c @@ -179,7 +179,6 @@ static int bt832_attach(struct i2c_adapter *adap, int addr, int kind) v4l_info(&t->client,"chip found @ 0x%x\n", addr<<1); - if(! bt832_init(&t->client)) { bt832_detach(&t->client); return -1; diff --git a/drivers/media/video/bt8xx/bttv-driver.c b/drivers/media/video/bt8xx/bttv-driver.c index 0165aac533bf..0ea559a7fe59 100644 --- a/drivers/media/video/bt8xx/bttv-driver.c +++ b/drivers/media/video/bt8xx/bttv-driver.c @@ -2448,7 +2448,7 @@ pix_format_set_size (struct v4l2_pix_format * f, } } -static int bttv_g_fmt_cap(struct file *file, void *priv, +static int bttv_g_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f) { struct bttv_fh *fh = priv; @@ -2461,7 +2461,7 @@ static int bttv_g_fmt_cap(struct file *file, void *priv, return 0; } -static int bttv_g_fmt_overlay(struct file *file, void *priv, +static int bttv_g_fmt_vid_overlay(struct file *file, void *priv, struct v4l2_format *f) { struct bttv_fh *fh = priv; @@ -2472,7 +2472,7 @@ static int bttv_g_fmt_overlay(struct file *file, void *priv, return 0; } -static int bttv_try_fmt_cap(struct file *file, void *priv, +static int bttv_try_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f) { const struct bttv_format *fmt; @@ -2532,7 +2532,7 @@ static int bttv_try_fmt_cap(struct file *file, void *priv, return 0; } -static int bttv_try_fmt_overlay(struct file *file, void *priv, +static int bttv_try_fmt_vid_overlay(struct file *file, void *priv, struct v4l2_format *f) { struct bttv_fh *fh = priv; @@ -2542,7 +2542,7 @@ static int bttv_try_fmt_overlay(struct file *file, void *priv, /* adjust_crop */ 0); } -static int bttv_s_fmt_cap(struct file *file, void *priv, +static int bttv_s_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f) { int retval; @@ -2556,7 +2556,7 @@ static int bttv_s_fmt_cap(struct file *file, void *priv, if (0 != retval) return retval; - retval = bttv_try_fmt_cap(file, priv, f); + retval = bttv_try_fmt_vid_cap(file, priv, f); if (0 != retval) return retval; @@ -2591,7 +2591,7 @@ static int bttv_s_fmt_cap(struct file *file, void *priv, return 0; } -static int bttv_s_fmt_overlay(struct file *file, void *priv, +static int bttv_s_fmt_vid_overlay(struct file *file, void *priv, struct v4l2_format *f) { struct bttv_fh *fh = priv; @@ -2661,7 +2661,7 @@ static int bttv_querycap(struct file *file, void *priv, return 0; } -static int bttv_enum_fmt_vbi(struct file *file, void *priv, +static int bttv_enum_fmt_vbi_cap(struct file *file, void *priv, struct v4l2_fmtdesc *f) { if (0 != f->index) @@ -2692,7 +2692,7 @@ static int bttv_enum_fmt_cap_ovr(struct v4l2_fmtdesc *f) return i; } -static int bttv_enum_fmt_cap(struct file *file, void *priv, +static int bttv_enum_fmt_vid_cap(struct file *file, void *priv, struct v4l2_fmtdesc *f) { int rc = bttv_enum_fmt_cap_ovr(f); @@ -2703,7 +2703,7 @@ static int bttv_enum_fmt_cap(struct file *file, void *priv, return 0; } -static int bttv_enum_fmt_overlay(struct file *file, void *priv, +static int bttv_enum_fmt_vid_overlay(struct file *file, void *priv, struct v4l2_fmtdesc *f) { int rc; @@ -3362,18 +3362,18 @@ static struct video_device bttv_video_template = .fops = &bttv_fops, .minor = -1, .vidioc_querycap = bttv_querycap, - .vidioc_enum_fmt_cap = bttv_enum_fmt_cap, - .vidioc_g_fmt_cap = bttv_g_fmt_cap, - .vidioc_try_fmt_cap = bttv_try_fmt_cap, - .vidioc_s_fmt_cap = bttv_s_fmt_cap, - .vidioc_enum_fmt_overlay = bttv_enum_fmt_overlay, - .vidioc_g_fmt_overlay = bttv_g_fmt_overlay, - .vidioc_try_fmt_overlay = bttv_try_fmt_overlay, - .vidioc_s_fmt_overlay = bttv_s_fmt_overlay, - .vidioc_enum_fmt_vbi = bttv_enum_fmt_vbi, - .vidioc_g_fmt_vbi = bttv_g_fmt_vbi, - .vidioc_try_fmt_vbi = bttv_try_fmt_vbi, - .vidioc_s_fmt_vbi = bttv_s_fmt_vbi, + .vidioc_enum_fmt_vid_cap = bttv_enum_fmt_vid_cap, + .vidioc_g_fmt_vid_cap = bttv_g_fmt_vid_cap, + .vidioc_try_fmt_vid_cap = bttv_try_fmt_vid_cap, + .vidioc_s_fmt_vid_cap = bttv_s_fmt_vid_cap, + .vidioc_enum_fmt_vid_overlay = bttv_enum_fmt_vid_overlay, + .vidioc_g_fmt_vid_overlay = bttv_g_fmt_vid_overlay, + .vidioc_try_fmt_vid_overlay = bttv_try_fmt_vid_overlay, + .vidioc_s_fmt_vid_overlay = bttv_s_fmt_vid_overlay, + .vidioc_enum_fmt_vbi_cap = bttv_enum_fmt_vbi_cap, + .vidioc_g_fmt_vbi_cap = bttv_g_fmt_vbi_cap, + .vidioc_try_fmt_vbi_cap = bttv_try_fmt_vbi_cap, + .vidioc_s_fmt_vbi_cap = bttv_s_fmt_vbi_cap, .vidioc_g_audio = bttv_g_audio, .vidioc_s_audio = bttv_s_audio, .vidioc_cropcap = bttv_cropcap, @@ -3705,7 +3705,7 @@ static void bttv_risc_disasm(struct bttv *btv, for (i = 0; i < (risc->size >> 2); i += n) { printk("%s: 0x%lx: ", btv->c.name, (unsigned long)(risc->dma + (i<<2))); - n = bttv_risc_decode(risc->cpu[i]); + n = bttv_risc_decode(le32_to_cpu(risc->cpu[i])); for (j = 1; j < n; j++) printk("%s: 0x%lx: 0x%08x [ arg #%d ]\n", btv->c.name, (unsigned long)(risc->dma + ((i+j)<<2)), @@ -3774,8 +3774,8 @@ static void bttv_irq_debug_low_latency(struct bttv *btv, u32 rc) printk("bttv%d: irq: skipped frame [main=%lx,o_vbi=%lx,o_field=%lx,rc=%lx]\n", btv->c.nr, (unsigned long)btv->main.dma, - (unsigned long)btv->main.cpu[RISC_SLOT_O_VBI+1], - (unsigned long)btv->main.cpu[RISC_SLOT_O_FIELD+1], + (unsigned long)le32_to_cpu(btv->main.cpu[RISC_SLOT_O_VBI+1]), + (unsigned long)le32_to_cpu(btv->main.cpu[RISC_SLOT_O_FIELD+1]), (unsigned long)rc); if (0 == (btread(BT848_DSTATUS) & BT848_DSTATUS_HLOC)) { @@ -4188,6 +4188,7 @@ static struct video_device *vdev_init(struct bttv *btv, vfd->dev = &btv->c.pci->dev; vfd->release = video_device_release; vfd->type = type; + vfd->debug = bttv_debug; snprintf(vfd->name, sizeof(vfd->name), "BT%d%s %s (%s)", btv->id, (btv->id==848 && btv->revision==0x12) ? "A" : "", type_name, bttv_tvcards[btv->c.type].name); diff --git a/drivers/media/video/bt8xx/bttv-i2c.c b/drivers/media/video/bt8xx/bttv-i2c.c index 4d5b8035e466..bcd2cd240a16 100644 --- a/drivers/media/video/bt8xx/bttv-i2c.c +++ b/drivers/media/video/bt8xx/bttv-i2c.c @@ -36,11 +36,6 @@ #include <linux/jiffies.h> #include <asm/io.h> -static struct i2c_algo_bit_data bttv_i2c_algo_bit_template; -static struct i2c_adapter bttv_i2c_adap_sw_template; -static struct i2c_adapter bttv_i2c_adap_hw_template; -static struct i2c_client bttv_i2c_client_template; - static int attach_inform(struct i2c_client *client); static int i2c_debug; @@ -104,7 +99,7 @@ static int bttv_bit_getsda(void *data) return state; } -static struct i2c_algo_bit_data bttv_i2c_algo_bit_template = { +static struct i2c_algo_bit_data __devinitdata bttv_i2c_algo_bit_template = { .setsda = bttv_bit_setsda, .setscl = bttv_bit_setscl, .getsda = bttv_bit_getsda, @@ -113,14 +108,6 @@ static struct i2c_algo_bit_data bttv_i2c_algo_bit_template = { .timeout = 200, }; -static struct i2c_adapter bttv_i2c_adap_sw_template = { - .owner = THIS_MODULE, - .class = I2C_CLASS_TV_ANALOG, - .name = "bttv", - .id = I2C_HW_B_BT848, - .client_register = attach_inform, -}; - /* ----------------------------------------------------------------------- */ /* I2C functions - hardware i2c */ @@ -270,20 +257,11 @@ static int bttv_i2c_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs, int return retval; } -static struct i2c_algorithm bttv_algo = { +static const struct i2c_algorithm bttv_algo = { .master_xfer = bttv_i2c_xfer, .functionality = functionality, }; -static struct i2c_adapter bttv_i2c_adap_hw_template = { - .owner = THIS_MODULE, - .class = I2C_CLASS_TV_ANALOG, - .name = "bt878", - .id = I2C_HW_B_BT848 /* FIXME */, - .algo = &bttv_algo, - .client_register = attach_inform, -}; - /* ----------------------------------------------------------------------- */ /* I2C functions - common stuff */ @@ -332,10 +310,6 @@ void bttv_call_i2c_clients(struct bttv *btv, unsigned int cmd, void *arg) i2c_clients_command(&btv->c.i2c_adap, cmd, arg); } -static struct i2c_client bttv_i2c_client_template = { - .name = "bttv internal", -}; - /* read I2C */ int bttv_I2CRead(struct bttv *btv, unsigned char addr, char *probe_for) @@ -417,29 +391,34 @@ static void do_i2c_scan(char *name, struct i2c_client *c) /* init + register i2c algo-bit adapter */ int __devinit init_bttv_i2c(struct bttv *btv) { - memcpy(&btv->i2c_client, &bttv_i2c_client_template, - sizeof(bttv_i2c_client_template)); + strlcpy(btv->i2c_client.name, "bttv internal", I2C_NAME_SIZE); if (i2c_hw) btv->use_i2c_hw = 1; if (btv->use_i2c_hw) { /* bt878 */ - memcpy(&btv->c.i2c_adap, &bttv_i2c_adap_hw_template, - sizeof(bttv_i2c_adap_hw_template)); + strlcpy(btv->c.i2c_adap.name, "bt878", + sizeof(btv->c.i2c_adap.name)); + btv->c.i2c_adap.id = I2C_HW_B_BT848; /* FIXME */ + btv->c.i2c_adap.algo = &bttv_algo; } else { /* bt848 */ /* Prevents usage of invalid delay values */ if (i2c_udelay<5) i2c_udelay=5; - bttv_i2c_algo_bit_template.udelay=i2c_udelay; - memcpy(&btv->c.i2c_adap, &bttv_i2c_adap_sw_template, - sizeof(bttv_i2c_adap_sw_template)); + strlcpy(btv->c.i2c_adap.name, "bttv", + sizeof(btv->c.i2c_adap.name)); + btv->c.i2c_adap.id = I2C_HW_B_BT848; memcpy(&btv->i2c_algo, &bttv_i2c_algo_bit_template, sizeof(bttv_i2c_algo_bit_template)); + btv->i2c_algo.udelay = i2c_udelay; btv->i2c_algo.data = btv; btv->c.i2c_adap.algo_data = &btv->i2c_algo; } + btv->c.i2c_adap.owner = THIS_MODULE; + btv->c.i2c_adap.class = I2C_CLASS_TV_ANALOG; + btv->c.i2c_adap.client_register = attach_inform; btv->c.i2c_adap.dev.parent = &btv->c.pci->dev; snprintf(btv->c.i2c_adap.name, sizeof(btv->c.i2c_adap.name), diff --git a/drivers/media/video/bt8xx/bttv-vbi.c b/drivers/media/video/bt8xx/bttv-vbi.c index bfdbc469e30f..68f28e5fa040 100644 --- a/drivers/media/video/bt8xx/bttv-vbi.c +++ b/drivers/media/video/bt8xx/bttv-vbi.c @@ -303,7 +303,7 @@ static int try_fmt(struct v4l2_vbi_format *f, const struct bttv_tvnorm *tvnorm, return 0; } -int bttv_try_fmt_vbi(struct file *file, void *f, struct v4l2_format *frt) +int bttv_try_fmt_vbi_cap(struct file *file, void *f, struct v4l2_format *frt) { struct bttv_fh *fh = f; struct bttv *btv = fh->btv; @@ -321,7 +321,7 @@ int bttv_try_fmt_vbi(struct file *file, void *f, struct v4l2_format *frt) } -int bttv_s_fmt_vbi(struct file *file, void *f, struct v4l2_format *frt) +int bttv_s_fmt_vbi_cap(struct file *file, void *f, struct v4l2_format *frt) { struct bttv_fh *fh = f; struct bttv *btv = fh->btv; @@ -369,7 +369,7 @@ int bttv_s_fmt_vbi(struct file *file, void *f, struct v4l2_format *frt) } -int bttv_g_fmt_vbi(struct file *file, void *f, struct v4l2_format *frt) +int bttv_g_fmt_vbi_cap(struct file *file, void *f, struct v4l2_format *frt) { struct bttv_fh *fh = f; const struct bttv_tvnorm *tvnorm; diff --git a/drivers/media/video/bt8xx/bttv.h b/drivers/media/video/bt8xx/bttv.h index f2393202904b..6d93d16c96e4 100644 --- a/drivers/media/video/bt8xx/bttv.h +++ b/drivers/media/video/bt8xx/bttv.h @@ -299,7 +299,6 @@ extern int bttv_write_gpio(unsigned int card, /* ---------------------------------------------------------- */ /* sysfs/driver-moded based gpio access interface */ - struct bttv_sub_device { struct device dev; struct bttv_core *core; diff --git a/drivers/media/video/bt8xx/bttvp.h b/drivers/media/video/bt8xx/bttvp.h index 27da7b423275..08ef54a22c9e 100644 --- a/drivers/media/video/bt8xx/bttvp.h +++ b/drivers/media/video/bt8xx/bttvp.h @@ -39,7 +39,6 @@ #include <linux/scatterlist.h> #include <asm/io.h> #include <media/v4l2-common.h> - #include <linux/device.h> #include <media/videobuf-dma-sg.h> #include <media/tveeprom.h> @@ -254,21 +253,19 @@ int bttv_overlay_risc(struct bttv *btv, struct bttv_overlay *ov, /* ---------------------------------------------------------- */ /* bttv-vbi.c */ -int bttv_try_fmt_vbi(struct file *file, void *fh, struct v4l2_format *f); -int bttv_g_fmt_vbi(struct file *file, void *fh, struct v4l2_format *f); -int bttv_s_fmt_vbi(struct file *file, void *fh, struct v4l2_format *f); +int bttv_try_fmt_vbi_cap(struct file *file, void *fh, struct v4l2_format *f); +int bttv_g_fmt_vbi_cap(struct file *file, void *fh, struct v4l2_format *f); +int bttv_s_fmt_vbi_cap(struct file *file, void *fh, struct v4l2_format *f); extern struct videobuf_queue_ops bttv_vbi_qops; /* ---------------------------------------------------------- */ /* bttv-gpio.c */ - extern struct bus_type bttv_sub_bus_type; int bttv_sub_add_device(struct bttv_core *core, char *name); int bttv_sub_del_devices(struct bttv_core *core); - /* ---------------------------------------------------------- */ /* bttv-driver.c */ diff --git a/drivers/media/video/cafe_ccic.c b/drivers/media/video/cafe_ccic.c index 5195b1f3378a..d99453faaab7 100644 --- a/drivers/media/video/cafe_ccic.c +++ b/drivers/media/video/cafe_ccic.c @@ -1593,7 +1593,7 @@ static struct v4l2_pix_format cafe_def_pix_format = { .sizeimage = VGA_WIDTH*VGA_HEIGHT*2, }; -static int cafe_vidioc_enum_fmt_cap(struct file *filp, +static int cafe_vidioc_enum_fmt_vid_cap(struct file *filp, void *priv, struct v4l2_fmtdesc *fmt) { struct cafe_camera *cam = priv; @@ -1608,7 +1608,7 @@ static int cafe_vidioc_enum_fmt_cap(struct file *filp, } -static int cafe_vidioc_try_fmt_cap (struct file *filp, void *priv, +static int cafe_vidioc_try_fmt_vid_cap(struct file *filp, void *priv, struct v4l2_format *fmt) { struct cafe_camera *cam = priv; @@ -1620,7 +1620,7 @@ static int cafe_vidioc_try_fmt_cap (struct file *filp, void *priv, return ret; } -static int cafe_vidioc_s_fmt_cap(struct file *filp, void *priv, +static int cafe_vidioc_s_fmt_vid_cap(struct file *filp, void *priv, struct v4l2_format *fmt) { struct cafe_camera *cam = priv; @@ -1635,7 +1635,7 @@ static int cafe_vidioc_s_fmt_cap(struct file *filp, void *priv, /* * See if the formatting works in principle. */ - ret = cafe_vidioc_try_fmt_cap(filp, priv, fmt); + ret = cafe_vidioc_try_fmt_vid_cap(filp, priv, fmt); if (ret) return ret; /* @@ -1670,7 +1670,7 @@ static int cafe_vidioc_s_fmt_cap(struct file *filp, void *priv, * The V4l2 spec wants us to be smarter, and actually get this from * the camera (and not mess with it at open time). Someday. */ -static int cafe_vidioc_g_fmt_cap(struct file *filp, void *priv, +static int cafe_vidioc_g_fmt_vid_cap(struct file *filp, void *priv, struct v4l2_format *f) { struct cafe_camera *cam = priv; @@ -1780,10 +1780,10 @@ static struct video_device cafe_v4l_template = { .release = cafe_v4l_dev_release, .vidioc_querycap = cafe_vidioc_querycap, - .vidioc_enum_fmt_cap = cafe_vidioc_enum_fmt_cap, - .vidioc_try_fmt_cap = cafe_vidioc_try_fmt_cap, - .vidioc_s_fmt_cap = cafe_vidioc_s_fmt_cap, - .vidioc_g_fmt_cap = cafe_vidioc_g_fmt_cap, + .vidioc_enum_fmt_vid_cap = cafe_vidioc_enum_fmt_vid_cap, + .vidioc_try_fmt_vid_cap = cafe_vidioc_try_fmt_vid_cap, + .vidioc_s_fmt_vid_cap = cafe_vidioc_s_fmt_vid_cap, + .vidioc_g_fmt_vid_cap = cafe_vidioc_g_fmt_vid_cap, .vidioc_enum_input = cafe_vidioc_enum_input, .vidioc_g_input = cafe_vidioc_g_input, .vidioc_s_input = cafe_vidioc_s_input, diff --git a/drivers/media/video/compat_ioctl32.c b/drivers/media/video/compat_ioctl32.c index cefd1381e8de..54de0cd482e9 100644 --- a/drivers/media/video/compat_ioctl32.c +++ b/drivers/media/video/compat_ioctl32.c @@ -884,6 +884,7 @@ long v4l_compat_ioctl32(struct file *file, unsigned int cmd, unsigned long arg) case VIDIOC_G_INPUT32: case VIDIOC_S_INPUT32: case VIDIOC_TRY_FMT32: + case VIDIOC_S_HW_FREQ_SEEK: ret = do_video_ioctl(file, cmd, arg); break; diff --git a/drivers/media/video/cs5345.c b/drivers/media/video/cs5345.c index 03411503457e..1c3fa3a7470a 100644 --- a/drivers/media/video/cs5345.c +++ b/drivers/media/video/cs5345.c @@ -173,4 +173,3 @@ static struct v4l2_i2c_driver_data v4l2_i2c_data = { .probe = cs5345_probe, .id_table = cs5345_id, }; - diff --git a/drivers/media/video/cs53l32a.c b/drivers/media/video/cs53l32a.c index d965af860ab2..645b339152d3 100644 --- a/drivers/media/video/cs53l32a.c +++ b/drivers/media/video/cs53l32a.c @@ -43,7 +43,6 @@ MODULE_PARM_DESC(debug, "Debugging messages\n\t\t\t0=Off (default), 1=On"); static unsigned short normal_i2c[] = { 0x22 >> 1, I2C_CLIENT_END }; - I2C_CLIENT_INSMOD; /* ----------------------------------------------------------------------- */ @@ -189,4 +188,3 @@ static struct v4l2_i2c_driver_data v4l2_i2c_data = { .probe = cs53l32a_probe, .id_table = cs53l32a_id, }; - diff --git a/drivers/media/video/cx18/cx18-audio.c b/drivers/media/video/cx18/cx18-audio.c index 1adc404d955e..6d5b94fc7087 100644 --- a/drivers/media/video/cx18/cx18-audio.c +++ b/drivers/media/video/cx18/cx18-audio.c @@ -26,13 +26,17 @@ #include "cx18-cards.h" #include "cx18-audio.h" +#define CX18_AUDIO_ENABLE 0xc72014 + /* Selects the audio input and output according to the current settings. */ int cx18_audio_set_io(struct cx18 *cx) { struct v4l2_routing route; u32 audio_input; + u32 val; int mux_input; + int err; /* Determine which input to use */ if (test_bit(CX18_F_I_RADIO_USER, &cx->i_flags)) { @@ -51,8 +55,17 @@ int cx18_audio_set_io(struct cx18 *cx) cx18_i2c_hw(cx, cx->card->hw_muxer, VIDIOC_INT_S_AUDIO_ROUTING, &route); route.input = audio_input; - return cx18_i2c_hw(cx, cx->card->hw_audio_ctrl, + err = cx18_i2c_hw(cx, cx->card->hw_audio_ctrl, VIDIOC_INT_S_AUDIO_ROUTING, &route); + if (err) + return err; + + val = read_reg(CX18_AUDIO_ENABLE) & ~0x30; + val |= (audio_input > CX18_AV_AUDIO_SERIAL2) ? 0x20 : + (audio_input << 4); + write_reg(val | 0xb00, CX18_AUDIO_ENABLE); + cx18_vapi(cx, CX18_APU_RESETAI, 1, 0); + return 0; } void cx18_audio_set_route(struct cx18 *cx, struct v4l2_routing *route) diff --git a/drivers/media/video/cx18/cx18-av-audio.c b/drivers/media/video/cx18/cx18-av-audio.c index 2dc3a5dd170e..c40a286de1b9 100644 --- a/drivers/media/video/cx18/cx18-av-audio.c +++ b/drivers/media/video/cx18/cx18-av-audio.c @@ -34,7 +34,7 @@ static int set_audclk_freq(struct cx18 *cx, u32 freq) /* SA_MCLK_SEL=1, SA_MCLK_DIV=0x10 */ cx18_av_write(cx, 0x127, 0x50); - if (state->aud_input != CX18_AV_AUDIO_SERIAL) { + if (state->aud_input > CX18_AV_AUDIO_SERIAL2) { switch (freq) { case 32000: /* VID_PLL and AUX_PLL */ @@ -148,7 +148,7 @@ void cx18_av_audio_set_path(struct cx18 *cx) /* Mute everything to prevent the PFFT! */ cx18_av_write(cx, 0x8d3, 0x1f); - if (state->aud_input == CX18_AV_AUDIO_SERIAL) { + if (state->aud_input <= CX18_AV_AUDIO_SERIAL2) { /* Set Path1 to Serial Audio Input */ cx18_av_write4(cx, 0x8d0, 0x01011012); @@ -165,7 +165,7 @@ void cx18_av_audio_set_path(struct cx18 *cx) /* deassert soft reset */ cx18_av_and_or(cx, 0x810, ~0x1, 0x00); - if (state->aud_input != CX18_AV_AUDIO_SERIAL) { + if (state->aud_input > CX18_AV_AUDIO_SERIAL2) { /* When the microcontroller detects the * audio format, it will unmute the lines */ cx18_av_and_or(cx, 0x803, ~0x10, 0x10); @@ -271,7 +271,7 @@ static void set_mute(struct cx18 *cx, int mute) { struct cx18_av_state *state = &cx->av_state; - if (state->aud_input != CX18_AV_AUDIO_SERIAL) { + if (state->aud_input > CX18_AV_AUDIO_SERIAL2) { /* Must turn off microcontroller in order to mute sound. * Not sure if this is the best method, but it does work. * If the microcontroller is running, then it will undo any @@ -298,14 +298,14 @@ int cx18_av_audio(struct cx18 *cx, unsigned int cmd, void *arg) switch (cmd) { case VIDIOC_INT_AUDIO_CLOCK_FREQ: - if (state->aud_input != CX18_AV_AUDIO_SERIAL) { + if (state->aud_input > CX18_AV_AUDIO_SERIAL2) { cx18_av_and_or(cx, 0x803, ~0x10, 0); cx18_av_write(cx, 0x8d3, 0x1f); } cx18_av_and_or(cx, 0x810, ~0x1, 1); retval = set_audclk_freq(cx, *(u32 *)arg); cx18_av_and_or(cx, 0x810, ~0x1, 0); - if (state->aud_input != CX18_AV_AUDIO_SERIAL) + if (state->aud_input > CX18_AV_AUDIO_SERIAL2) cx18_av_and_or(cx, 0x803, ~0x10, 0x10); return retval; diff --git a/drivers/media/video/cx18/cx18-av-core.c b/drivers/media/video/cx18/cx18-av-core.c index faca43eb940f..3b0a2c450605 100644 --- a/drivers/media/video/cx18/cx18-av-core.c +++ b/drivers/media/video/cx18/cx18-av-core.c @@ -69,58 +69,6 @@ int cx18_av_and_or4(struct cx18 *cx, u16 addr, u32 and_mask, or_value); } -int cx18_av_write_no_acfg(struct cx18 *cx, u16 addr, u8 value, int no_acfg_mask) -{ - int retval; - u32 saved_reg[8] = {0}; - - if (no_acfg_mask & CXADEC_NO_ACFG_AFE) { - saved_reg[0] = cx18_av_read4(cx, CXADEC_CHIP_CTRL); - saved_reg[1] = cx18_av_read4(cx, CXADEC_AFE_CTRL); - } - - if (no_acfg_mask & CXADEC_NO_ACFG_PLL) { - saved_reg[2] = cx18_av_read4(cx, CXADEC_PLL_CTRL1); - saved_reg[3] = cx18_av_read4(cx, CXADEC_VID_PLL_FRAC); - } - - if (no_acfg_mask & CXADEC_NO_ACFG_VID) { - saved_reg[4] = cx18_av_read4(cx, CXADEC_HORIZ_TIM_CTRL); - saved_reg[5] = cx18_av_read4(cx, CXADEC_VERT_TIM_CTRL); - saved_reg[6] = cx18_av_read4(cx, CXADEC_SRC_COMB_CFG); - saved_reg[7] = cx18_av_read4(cx, CXADEC_CHROMA_VBIOFF_CFG); - } - - retval = cx18_av_write(cx, addr, value); - - if (no_acfg_mask & CXADEC_NO_ACFG_AFE) { - cx18_av_write4(cx, CXADEC_CHIP_CTRL, saved_reg[0]); - cx18_av_write4(cx, CXADEC_AFE_CTRL, saved_reg[1]); - } - - if (no_acfg_mask & CXADEC_NO_ACFG_PLL) { - cx18_av_write4(cx, CXADEC_PLL_CTRL1, saved_reg[2]); - cx18_av_write4(cx, CXADEC_VID_PLL_FRAC, saved_reg[3]); - } - - if (no_acfg_mask & CXADEC_NO_ACFG_VID) { - cx18_av_write4(cx, CXADEC_HORIZ_TIM_CTRL, saved_reg[4]); - cx18_av_write4(cx, CXADEC_VERT_TIM_CTRL, saved_reg[5]); - cx18_av_write4(cx, CXADEC_SRC_COMB_CFG, saved_reg[6]); - cx18_av_write4(cx, CXADEC_CHROMA_VBIOFF_CFG, saved_reg[7]); - } - - return retval; -} - -int cx18_av_and_or_no_acfg(struct cx18 *cx, u16 addr, unsigned and_mask, - u8 or_value, int no_acfg_mask) -{ - return cx18_av_write_no_acfg(cx, addr, - (cx18_av_read(cx, addr) & and_mask) | - or_value, no_acfg_mask); -} - /* ----------------------------------------------------------------------- */ static int set_input(struct cx18 *cx, enum cx18_av_video_input vid_input, @@ -132,6 +80,7 @@ static void log_video_status(struct cx18 *cx); static void cx18_av_initialize(struct cx18 *cx) { + struct cx18_av_state *state = &cx->av_state; u32 v; cx18_av_loadfw(cx); @@ -211,6 +160,149 @@ static void cx18_av_initialize(struct cx18 *cx) /* CxDevWrReg(CXADEC_SRC_COMB_CFG, 0x6628021F); */ /* } */ cx18_av_write4(cx, CXADEC_SRC_COMB_CFG, 0x6628021F); + state->default_volume = 228 - cx18_av_read(cx, 0x8d4); + state->default_volume = ((state->default_volume / 2) + 23) << 9; +} + +/* ----------------------------------------------------------------------- */ + +void cx18_av_std_setup(struct cx18 *cx) +{ + struct cx18_av_state *state = &cx->av_state; + v4l2_std_id std = state->std; + int hblank, hactive, burst, vblank, vactive, sc; + int vblank656, src_decimation; + int luma_lpf, uv_lpf, comb; + u32 pll_int, pll_frac, pll_post; + + /* datasheet startup, step 8d */ + if (std & ~V4L2_STD_NTSC) + cx18_av_write(cx, 0x49f, 0x11); + else + cx18_av_write(cx, 0x49f, 0x14); + + if (std & V4L2_STD_625_50) { + hblank = 132; + hactive = 720; + burst = 93; + vblank = 36; + vactive = 580; + vblank656 = 40; + src_decimation = 0x21f; + + luma_lpf = 2; + if (std & V4L2_STD_PAL) { + uv_lpf = 1; + comb = 0x20; + sc = 688739; + } else if (std == V4L2_STD_PAL_Nc) { + uv_lpf = 1; + comb = 0x20; + sc = 556453; + } else { /* SECAM */ + uv_lpf = 0; + comb = 0; + sc = 672351; + } + } else { + hactive = 720; + hblank = 122; + vactive = 487; + luma_lpf = 1; + uv_lpf = 1; + vblank = 26; + vblank656 = 26; + + src_decimation = 0x21f; + if (std == V4L2_STD_PAL_60) { + burst = 0x5b; + luma_lpf = 2; + comb = 0x20; + sc = 688739; + } else if (std == V4L2_STD_PAL_M) { + burst = 0x61; + comb = 0x20; + sc = 555452; + } else { + burst = 0x5b; + comb = 0x66; + sc = 556063; + } + } + + /* DEBUG: Displays configured PLL frequency */ + pll_int = cx18_av_read(cx, 0x108); + pll_frac = cx18_av_read4(cx, 0x10c) & 0x1ffffff; + pll_post = cx18_av_read(cx, 0x109); + CX18_DEBUG_INFO("PLL regs = int: %u, frac: %u, post: %u\n", + pll_int, pll_frac, pll_post); + + if (pll_post) { + int fin, fsc; + int pll = 28636363L * ((((u64)pll_int) << 25) + pll_frac); + + pll >>= 25; + pll /= pll_post; + CX18_DEBUG_INFO("PLL = %d.%06d MHz\n", + pll / 1000000, pll % 1000000); + CX18_DEBUG_INFO("PLL/8 = %d.%06d MHz\n", + pll / 8000000, (pll / 8) % 1000000); + + fin = ((u64)src_decimation * pll) >> 12; + CX18_DEBUG_INFO("ADC Sampling freq = %d.%06d MHz\n", + fin / 1000000, fin % 1000000); + + fsc = (((u64)sc) * pll) >> 24L; + CX18_DEBUG_INFO("Chroma sub-carrier freq = %d.%06d MHz\n", + fsc / 1000000, fsc % 1000000); + + CX18_DEBUG_INFO("hblank %i, hactive %i, " + "vblank %i , vactive %i, vblank656 %i, src_dec %i," + "burst 0x%02x, luma_lpf %i, uv_lpf %i, comb 0x%02x," + " sc 0x%06x\n", + hblank, hactive, vblank, vactive, vblank656, + src_decimation, burst, luma_lpf, uv_lpf, comb, sc); + } + + /* Sets horizontal blanking delay and active lines */ + cx18_av_write(cx, 0x470, hblank); + cx18_av_write(cx, 0x471, 0xff & (((hblank >> 8) & 0x3) | + (hactive << 4))); + cx18_av_write(cx, 0x472, hactive >> 4); + + /* Sets burst gate delay */ + cx18_av_write(cx, 0x473, burst); + + /* Sets vertical blanking delay and active duration */ + cx18_av_write(cx, 0x474, vblank); + cx18_av_write(cx, 0x475, 0xff & (((vblank >> 8) & 0x3) | + (vactive << 4))); + cx18_av_write(cx, 0x476, vactive >> 4); + cx18_av_write(cx, 0x477, vblank656); + + /* Sets src decimation rate */ + cx18_av_write(cx, 0x478, 0xff & src_decimation); + cx18_av_write(cx, 0x479, 0xff & (src_decimation >> 8)); + + /* Sets Luma and UV Low pass filters */ + cx18_av_write(cx, 0x47a, luma_lpf << 6 | ((uv_lpf << 4) & 0x30)); + + /* Enables comb filters */ + cx18_av_write(cx, 0x47b, comb); + + /* Sets SC Step*/ + cx18_av_write(cx, 0x47c, sc); + cx18_av_write(cx, 0x47d, 0xff & sc >> 8); + cx18_av_write(cx, 0x47e, 0xff & sc >> 16); + + /* Sets VBI parameters */ + if (std & V4L2_STD_625_50) { + cx18_av_write(cx, 0x47f, 0x01); + state->vbi_line_offset = 5; + } else { + cx18_av_write(cx, 0x47f, 0x00); + state->vbi_line_offset = 8; + } } /* ----------------------------------------------------------------------- */ @@ -221,16 +313,9 @@ static void input_change(struct cx18 *cx) v4l2_std_id std = state->std; /* Follow step 8c and 8d of section 3.16 in the cx18_av datasheet */ - if (std & V4L2_STD_SECAM) - cx18_av_write_no_acfg(cx, 0x402, 0, CXADEC_NO_ACFG_ALL); - else { - cx18_av_write_no_acfg(cx, 0x402, 0x04, CXADEC_NO_ACFG_ALL); - cx18_av_write(cx, 0x49f, (std & V4L2_STD_NTSC) ? 0x14 : 0x11); - } - cx18_av_and_or_no_acfg(cx, 0x401, ~0x60, 0, - CXADEC_NO_ACFG_PLL | CXADEC_NO_ACFG_VID); - cx18_av_and_or_no_acfg(cx, 0x401, ~0x60, 0x60, - CXADEC_NO_ACFG_PLL | CXADEC_NO_ACFG_VID); + cx18_av_write(cx, 0x49f, (std & V4L2_STD_NTSC) ? 0x14 : 0x11); + cx18_av_and_or(cx, 0x401, ~0x60, 0); + cx18_av_and_or(cx, 0x401, ~0x60, 0x60); if (std & V4L2_STD_525_60) { if (std == V4L2_STD_NTSC_M_JP) { @@ -300,7 +385,8 @@ static int set_input(struct cx18 *cx, enum cx18_av_video_input vid_input, } switch (aud_input) { - case CX18_AV_AUDIO_SERIAL: + case CX18_AV_AUDIO_SERIAL1: + case CX18_AV_AUDIO_SERIAL2: /* do nothing, use serial audio input */ break; case CX18_AV_AUDIO4: reg &= ~0x30; break; @@ -316,8 +402,7 @@ static int set_input(struct cx18 *cx, enum cx18_av_video_input vid_input, cx18_av_write(cx, 0x103, reg); /* Set INPUT_MODE to Composite (0) or S-Video (1) */ - cx18_av_and_or_no_acfg(cx, 0x401, ~0x6, is_composite ? 0 : 0x02, - CXADEC_NO_ACFG_PLL | CXADEC_NO_ACFG_VID); + cx18_av_and_or(cx, 0x401, ~0x6, is_composite ? 0 : 0x02); /* Set CH_SEL_ADC2 to 1 if input comes from CH3 */ cx18_av_and_or(cx, 0x102, ~0x2, (reg & 0x80) == 0 ? 2 : 0); /* Set DUAL_MODE_ADC2 to 1 if input comes from both CH2 and CH3 */ @@ -373,13 +458,13 @@ static int set_v4lstd(struct cx18 *cx) This happens for example with the Yuan MPC622. */ if (fmt >= 4 && fmt < 8) { /* Set format to NTSC-M */ - cx18_av_and_or_no_acfg(cx, 0x400, ~0xf, 1, CXADEC_NO_ACFG_AFE); + cx18_av_and_or(cx, 0x400, ~0xf, 1); /* Turn off LCOMB */ cx18_av_and_or(cx, 0x47b, ~6, 0); } - cx18_av_and_or_no_acfg(cx, 0x400, ~0xf, fmt, CXADEC_NO_ACFG_AFE); - cx18_av_and_or_no_acfg(cx, 0x403, ~0x3, pal_m, CXADEC_NO_ACFG_ALL); - cx18_av_vbi_setup(cx); + cx18_av_and_or(cx, 0x400, ~0x2f, fmt | 0x20); + cx18_av_and_or(cx, 0x403, ~0x3, pal_m); + cx18_av_std_setup(cx); input_change(cx); return 0; } @@ -618,6 +703,8 @@ int cx18_av_cmd(struct cx18 *cx, unsigned int cmd, void *arg) switch (qc->id) { case V4L2_CID_AUDIO_VOLUME: + return v4l2_ctrl_query_fill(qc, 0, 65535, + 65535 / 100, state->default_volume); case V4L2_CID_AUDIO_MUTE: case V4L2_CID_AUDIO_BALANCE: case V4L2_CID_AUDIO_BASS: diff --git a/drivers/media/video/cx18/cx18-av-core.h b/drivers/media/video/cx18/cx18-av-core.h index c172823ce1d8..eb61fa1e0965 100644 --- a/drivers/media/video/cx18/cx18-av-core.h +++ b/drivers/media/video/cx18/cx18-av-core.h @@ -62,7 +62,8 @@ enum cx18_av_video_input { enum cx18_av_audio_input { /* Audio inputs: serial or In4-In8 */ - CX18_AV_AUDIO_SERIAL, + CX18_AV_AUDIO_SERIAL1, + CX18_AV_AUDIO_SERIAL2, CX18_AV_AUDIO4 = 4, CX18_AV_AUDIO5, CX18_AV_AUDIO6, @@ -78,6 +79,7 @@ struct cx18_av_state { u32 audclk_freq; int audmode; int vbi_line_offset; + int default_volume; u32 id; u32 rev; int is_initialized; @@ -295,25 +297,16 @@ struct cx18_av_state { #define CXADEC_SELECT_AUDIO_STANDARD_FM 0xF9 /* FM radio */ #define CXADEC_SELECT_AUDIO_STANDARD_AUTO 0xFF /* Auto detect */ -/* Flags on what to preserve on write to 0x400-0x403 with cx18_av_.*_no_acfg()*/ -#define CXADEC_NO_ACFG_AFE 0x01 /* Preserve 0x100-0x107 */ -#define CXADEC_NO_ACFG_PLL 0x02 /* Preserve 0x108-0x10f */ -#define CXADEC_NO_ACFG_VID 0x04 /* Preserve 0x470-0x47f */ -#define CXADEC_NO_ACFG_ALL 0x07 - /* ----------------------------------------------------------------------- */ /* cx18_av-core.c */ int cx18_av_write(struct cx18 *cx, u16 addr, u8 value); int cx18_av_write4(struct cx18 *cx, u16 addr, u32 value); -int cx18_av_write_no_acfg(struct cx18 *cx, u16 addr, u8 value, - int no_acfg_mask); u8 cx18_av_read(struct cx18 *cx, u16 addr); u32 cx18_av_read4(struct cx18 *cx, u16 addr); int cx18_av_and_or(struct cx18 *cx, u16 addr, unsigned mask, u8 value); int cx18_av_and_or4(struct cx18 *cx, u16 addr, u32 mask, u32 value); -int cx18_av_and_or_no_acfg(struct cx18 *cx, u16 addr, unsigned mask, u8 value, - int no_acfg_mask); int cx18_av_cmd(struct cx18 *cx, unsigned int cmd, void *arg); +void cx18_av_std_setup(struct cx18 *cx); /* ----------------------------------------------------------------------- */ /* cx18_av-firmware.c */ @@ -326,7 +319,6 @@ void cx18_av_audio_set_path(struct cx18 *cx); /* ----------------------------------------------------------------------- */ /* cx18_av-vbi.c */ -void cx18_av_vbi_setup(struct cx18 *cx); int cx18_av_vbi(struct cx18 *cx, unsigned int cmd, void *arg); #endif diff --git a/drivers/media/video/cx18/cx18-av-firmware.c b/drivers/media/video/cx18/cx18-av-firmware.c index a1a6af6c1c8f..834b9248242e 100644 --- a/drivers/media/video/cx18/cx18-av-firmware.c +++ b/drivers/media/video/cx18/cx18-av-firmware.c @@ -22,6 +22,7 @@ #include "cx18-driver.h" #include <linux/firmware.h> +#define CX18_AUDIO_ENABLE 0xc72014 #define FWFILE "v4l-cx23418-dig.fw" int cx18_av_loadfw(struct cx18 *cx) @@ -31,40 +32,58 @@ int cx18_av_loadfw(struct cx18 *cx) u32 v; const u8 *ptr; int i; + int retries = 0; if (request_firmware(&fw, FWFILE, &cx->dev->dev) != 0) { CX18_ERR("unable to open firmware %s\n", FWFILE); return -EINVAL; } - cx18_av_write4(cx, CXADEC_CHIP_CTRL, 0x00010000); - cx18_av_write(cx, CXADEC_STD_DET_CTL, 0xf6); /* Byte 0 */ - - /* Reset the Mako core (Register is undocumented.) */ - cx18_av_write4(cx, 0x8100, 0x00010000); - - /* Put the 8051 in reset and enable firmware upload */ - cx18_av_write4(cx, CXADEC_DL_CTL, 0x0F000000); - - ptr = fw->data; - size = fw->size; - - for (i = 0; i < size; i++) { - u32 dl_control = 0x0F000000 | ((u32)ptr[i] << 16); - u32 value = 0; - int retries; - - for (retries = 0; retries < 5; retries++) { - cx18_av_write4(cx, CXADEC_DL_CTL, dl_control); - value = cx18_av_read4(cx, CXADEC_DL_CTL); - if ((value & 0x3F00) == (dl_control & 0x3F00)) + /* The firmware load often has byte errors, so allow for several + retries, both at byte level and at the firmware load level. */ + while (retries < 5) { + cx18_av_write4(cx, CXADEC_CHIP_CTRL, 0x00010000); + cx18_av_write(cx, CXADEC_STD_DET_CTL, 0xf6); + + /* Reset the Mako core (Register is undocumented.) */ + cx18_av_write4(cx, 0x8100, 0x00010000); + + /* Put the 8051 in reset and enable firmware upload */ + cx18_av_write4(cx, CXADEC_DL_CTL, 0x0F000000); + + ptr = fw->data; + size = fw->size; + + for (i = 0; i < size; i++) { + u32 dl_control = 0x0F000000 | i | ((u32)ptr[i] << 16); + u32 value = 0; + int retries; + + for (retries = 0; retries < 5; retries++) { + cx18_av_write4(cx, CXADEC_DL_CTL, dl_control); + udelay(10); + value = cx18_av_read4(cx, CXADEC_DL_CTL); + if (value == dl_control) + break; + /* Check if we can correct the byte by changing + the address. We can only write the lower + address byte of the address. */ + if ((value & 0x3F00) != (dl_control & 0x3F00)) { + retries = 5; + break; + } + } + if (retries >= 5) break; } - if (retries >= 5) { - CX18_ERR("unable to load firmware %s\n", FWFILE); - release_firmware(fw); - return -EIO; - } + if (i == size) + break; + retries++; + } + if (retries >= 5) { + CX18_ERR("unable to load firmware %s\n", FWFILE); + release_firmware(fw); + return -EIO; } cx18_av_write4(cx, CXADEC_DL_CTL, 0x13000000 | fw->size); @@ -100,7 +119,6 @@ int cx18_av_loadfw(struct cx18 *cx) have a name in the spec. */ cx18_av_write4(cx, 0x09CC, 1); -#define CX18_AUDIO_ENABLE 0xc72014 v = read_reg(CX18_AUDIO_ENABLE); /* If bit 11 is 1 */ if (v & 0x800) diff --git a/drivers/media/video/cx18/cx18-av-vbi.c b/drivers/media/video/cx18/cx18-av-vbi.c index d09f1daf4ebf..02fdf57bb678 100644 --- a/drivers/media/video/cx18/cx18-av-vbi.c +++ b/drivers/media/video/cx18/cx18-av-vbi.c @@ -83,150 +83,6 @@ static int decode_vps(u8 *dst, u8 *p) return err & 0xf0; } -void cx18_av_vbi_setup(struct cx18 *cx) -{ - struct cx18_av_state *state = &cx->av_state; - v4l2_std_id std = state->std; - int hblank, hactive, burst, vblank, vactive, sc; - int vblank656, src_decimation; - int luma_lpf, uv_lpf, comb; - u32 pll_int, pll_frac, pll_post; - - /* datasheet startup, step 8d */ - if (std & ~V4L2_STD_NTSC) - cx18_av_write(cx, 0x49f, 0x11); - else - cx18_av_write(cx, 0x49f, 0x14); - - if (std & V4L2_STD_625_50) { - hblank = 0x084; - hactive = 0x2d0; - burst = 0x5d; - vblank = 0x024; - vactive = 0x244; - vblank656 = 0x28; - src_decimation = 0x21f; - - luma_lpf = 2; - if (std & V4L2_STD_SECAM) { - uv_lpf = 0; - comb = 0; - sc = 0x0a425f; - } else if (std == V4L2_STD_PAL_Nc) { - uv_lpf = 1; - comb = 0x20; - sc = 556453; - } else { - uv_lpf = 1; - comb = 0x20; - sc = 0x0a8263; - } - } else { - hactive = 720; - hblank = 122; - vactive = 487; - luma_lpf = 1; - uv_lpf = 1; - - src_decimation = 0x21f; - if (std == V4L2_STD_PAL_60) { - vblank = 26; - vblank656 = 26; - burst = 0x5b; - luma_lpf = 2; - comb = 0x20; - sc = 0x0a8263; - } else if (std == V4L2_STD_PAL_M) { - vblank = 20; - vblank656 = 24; - burst = 0x61; - comb = 0x20; - - sc = 555452; - } else { - vblank = 26; - vblank656 = 26; - burst = 0x5b; - comb = 0x66; - sc = 556063; - } - } - - /* DEBUG: Displays configured PLL frequency */ - pll_int = cx18_av_read(cx, 0x108); - pll_frac = cx18_av_read4(cx, 0x10c) & 0x1ffffff; - pll_post = cx18_av_read(cx, 0x109); - CX18_DEBUG_INFO("PLL regs = int: %u, frac: %u, post: %u\n", - pll_int, pll_frac, pll_post); - - if (pll_post) { - int fin, fsc; - int pll = 28636363L * ((((u64)pll_int) << 25) + pll_frac); - - pll >>= 25; - pll /= pll_post; - CX18_DEBUG_INFO("PLL = %d.%06d MHz\n", - pll / 1000000, pll % 1000000); - CX18_DEBUG_INFO("PLL/8 = %d.%06d MHz\n", - pll / 8000000, (pll / 8) % 1000000); - - fin = ((u64)src_decimation * pll) >> 12; - CX18_DEBUG_INFO("ADC Sampling freq = %d.%06d MHz\n", - fin / 1000000, fin % 1000000); - - fsc = (((u64)sc) * pll) >> 24L; - CX18_DEBUG_INFO("Chroma sub-carrier freq = %d.%06d MHz\n", - fsc / 1000000, fsc % 1000000); - - CX18_DEBUG_INFO("hblank %i, hactive %i, " - "vblank %i , vactive %i, vblank656 %i, src_dec %i," - "burst 0x%02x, luma_lpf %i, uv_lpf %i, comb 0x%02x," - " sc 0x%06x\n", - hblank, hactive, vblank, vactive, vblank656, - src_decimation, burst, luma_lpf, uv_lpf, comb, sc); - } - - /* Sets horizontal blanking delay and active lines */ - cx18_av_write(cx, 0x470, hblank); - cx18_av_write(cx, 0x471, 0xff & (((hblank >> 8) & 0x3) | - (hactive << 4))); - cx18_av_write(cx, 0x472, hactive >> 4); - - /* Sets burst gate delay */ - cx18_av_write(cx, 0x473, burst); - - /* Sets vertical blanking delay and active duration */ - cx18_av_write(cx, 0x474, vblank); - cx18_av_write(cx, 0x475, 0xff & (((vblank >> 8) & 0x3) | - (vactive << 4))); - cx18_av_write(cx, 0x476, vactive >> 4); - cx18_av_write(cx, 0x477, vblank656); - - /* Sets src decimation rate */ - cx18_av_write(cx, 0x478, 0xff & src_decimation); - cx18_av_write(cx, 0x479, 0xff & (src_decimation >> 8)); - - /* Sets Luma and UV Low pass filters */ - cx18_av_write(cx, 0x47a, luma_lpf << 6 | ((uv_lpf << 4) & 0x30)); - - /* Enables comb filters */ - cx18_av_write(cx, 0x47b, comb); - - /* Sets SC Step*/ - cx18_av_write(cx, 0x47c, sc); - cx18_av_write(cx, 0x47d, 0xff & sc >> 8); - cx18_av_write(cx, 0x47e, 0xff & sc >> 16); - - /* Sets VBI parameters */ - if (std & V4L2_STD_625_50) { - cx18_av_write(cx, 0x47f, 0x01); - state->vbi_line_offset = 5; - } else { - cx18_av_write(cx, 0x47f, 0x00); - state->vbi_line_offset = 8; - } -} - int cx18_av_vbi(struct cx18 *cx, unsigned int cmd, void *arg) { struct cx18_av_state *state = &cx->av_state; @@ -292,8 +148,8 @@ int cx18_av_vbi(struct cx18 *cx, unsigned int cmd, void *arg) /* raw VBI */ memset(svbi, 0, sizeof(*svbi)); - /* Setup VBI */ - cx18_av_vbi_setup(cx); + /* Setup standard */ + cx18_av_std_setup(cx); /* VBI Offset */ cx18_av_write(cx, 0x47f, vbi_offset); @@ -304,8 +160,8 @@ int cx18_av_vbi(struct cx18 *cx, unsigned int cmd, void *arg) for (x = 0; x <= 23; x++) lcr[x] = 0x00; - /* Setup VBI */ - cx18_av_vbi_setup(cx); + /* Setup standard */ + cx18_av_std_setup(cx); /* Sliced VBI */ cx18_av_write(cx, 0x404, 0x32); /* Ancillary data */ diff --git a/drivers/media/video/cx18/cx18-cards.c b/drivers/media/video/cx18/cx18-cards.c index c26e0ef5b075..8fe5f38c4d7c 100644 --- a/drivers/media/video/cx18/cx18-cards.c +++ b/drivers/media/video/cx18/cx18-cards.c @@ -27,6 +27,8 @@ #include "cx18-i2c.h" #include <media/cs5345.h> +#define V4L2_STD_PAL_SECAM (V4L2_STD_PAL|V4L2_STD_SECAM) + /********************** card configuration *******************************/ /* usual i2c tuner addresses to probe */ @@ -65,12 +67,12 @@ static const struct cx18_card cx18_card_hvr1600_esmt = { { CX18_CARD_INPUT_AUD_TUNER, CX18_AV_AUDIO8, CS5345_IN_1 | CS5345_MCLK_1_5 }, { CX18_CARD_INPUT_LINE_IN1, - CX18_AV_AUDIO_SERIAL, CS5345_IN_2 }, + CX18_AV_AUDIO_SERIAL1, CS5345_IN_2 }, { CX18_CARD_INPUT_LINE_IN2, - CX18_AV_AUDIO_SERIAL, CS5345_IN_3 }, + CX18_AV_AUDIO_SERIAL1, CS5345_IN_3 }, }, .radio_input = { CX18_CARD_INPUT_AUD_TUNER, - CX18_AV_AUDIO_SERIAL, CS5345_IN_4 }, + CX18_AV_AUDIO_SERIAL1, CS5345_IN_4 }, .ddr = { /* ESMT M13S128324A-5B memory */ .chip_config = 0x003, @@ -86,6 +88,7 @@ static const struct cx18_card cx18_card_hvr1600_esmt = { .active_lo_mask = 0x3001, .msecs_asserted = 10, .msecs_recovery = 40, + .ir_reset_mask = 0x0001, }, .i2c = &cx18_i2c_std, }; @@ -110,12 +113,12 @@ static const struct cx18_card cx18_card_hvr1600_samsung = { { CX18_CARD_INPUT_AUD_TUNER, CX18_AV_AUDIO8, CS5345_IN_1 | CS5345_MCLK_1_5 }, { CX18_CARD_INPUT_LINE_IN1, - CX18_AV_AUDIO_SERIAL, CS5345_IN_2 }, + CX18_AV_AUDIO_SERIAL1, CS5345_IN_2 }, { CX18_CARD_INPUT_LINE_IN2, - CX18_AV_AUDIO_SERIAL, CS5345_IN_3 }, + CX18_AV_AUDIO_SERIAL1, CS5345_IN_3 }, }, .radio_input = { CX18_CARD_INPUT_AUD_TUNER, - CX18_AV_AUDIO_SERIAL, CS5345_IN_4 }, + CX18_AV_AUDIO_SERIAL1, CS5345_IN_4 }, .ddr = { /* Samsung K4D263238G-VC33 memory */ .chip_config = 0x003, @@ -131,6 +134,7 @@ static const struct cx18_card cx18_card_hvr1600_samsung = { .active_lo_mask = 0x3001, .msecs_asserted = 10, .msecs_recovery = 40, + .ir_reset_mask = 0x0001, }, .i2c = &cx18_i2c_std, }; @@ -161,10 +165,10 @@ static const struct cx18_card cx18_card_h900 = { { CX18_CARD_INPUT_AUD_TUNER, CX18_AV_AUDIO8, 0 }, { CX18_CARD_INPUT_LINE_IN1, - CX18_AV_AUDIO_SERIAL, 0 }, + CX18_AV_AUDIO_SERIAL1, 0 }, }, .radio_input = { CX18_CARD_INPUT_AUD_TUNER, - CX18_AV_AUDIO_SERIAL, 0 }, + CX18_AV_AUDIO_SERIAL1, 0 }, .tuners = { { .std = V4L2_STD_ALL, .tuner = TUNER_XC2028 }, }, @@ -194,7 +198,7 @@ static const struct cx18_card_pci_info cx18_pci_mpc718[] = { static const struct cx18_card cx18_card_mpc718 = { .type = CX18_CARD_YUAN_MPC718, .name = "Yuan MPC718", - .comment = "Some Composite and S-Video inputs are currently working.\n", + .comment = "Analog video capture works; some audio line in may not.\n", .v4l2_capabilities = CX18_CAP_ENCODER, .hw_audio_ctrl = CX18_HW_CX23418, .hw_all = CX18_HW_TUNER, @@ -209,11 +213,11 @@ static const struct cx18_card cx18_card_mpc718 = { { CX18_CARD_INPUT_COMPOSITE3, 2, CX18_AV_COMPOSITE3 }, }, .audio_inputs = { - { CX18_CARD_INPUT_AUD_TUNER, CX18_AV_AUDIO5, 0 }, - { CX18_CARD_INPUT_LINE_IN1, CX18_AV_AUDIO_SERIAL, 0 }, - { CX18_CARD_INPUT_LINE_IN2, CX18_AV_AUDIO_SERIAL, 0 }, + { CX18_CARD_INPUT_AUD_TUNER, CX18_AV_AUDIO5, 0 }, + { CX18_CARD_INPUT_LINE_IN1, CX18_AV_AUDIO_SERIAL1, 0 }, + { CX18_CARD_INPUT_LINE_IN2, CX18_AV_AUDIO_SERIAL1, 0 }, }, - .radio_input = { CX18_CARD_INPUT_AUD_TUNER, CX18_AV_AUDIO_SERIAL, 0 }, + .radio_input = { CX18_CARD_INPUT_AUD_TUNER, CX18_AV_AUDIO_SERIAL1, 0 }, .tuners = { /* XC3028 tuner */ { .std = V4L2_STD_ALL, .tuner = TUNER_XC2028 }, @@ -227,16 +231,73 @@ static const struct cx18_card cx18_card_mpc718 = { .tune_lane = 0, .initial_emrs = 2, }, - .xceive_pin = 15, + .xceive_pin = 0, .pci_list = cx18_pci_mpc718, .i2c = &cx18_i2c_std, }; +/* ------------------------------------------------------------------------- */ + +/* Conexant Raptor PAL/SECAM: note that this card is analog only! */ + +static const struct cx18_card_pci_info cx18_pci_cnxt_raptor_pal[] = { + { PCI_DEVICE_ID_CX23418, CX18_PCI_ID_CONEXANT, 0x0009 }, + { 0, 0, 0 } +}; + +static const struct cx18_card cx18_card_cnxt_raptor_pal = { + .type = CX18_CARD_CNXT_RAPTOR_PAL, + .name = "Conexant Raptor PAL/SECAM", + .comment = "VBI is not yet supported\n", + .v4l2_capabilities = CX18_CAP_ENCODER, + .hw_audio_ctrl = CX18_HW_CX23418, + .hw_muxer = CX18_HW_GPIO, + .hw_all = CX18_HW_TUNER | CX18_HW_GPIO, + .video_inputs = { + { CX18_CARD_INPUT_VID_TUNER, 0, CX18_AV_COMPOSITE2 }, + { CX18_CARD_INPUT_SVIDEO1, 1, + CX18_AV_SVIDEO_LUMA3 | CX18_AV_SVIDEO_CHROMA4 }, + { CX18_CARD_INPUT_COMPOSITE1, 1, CX18_AV_COMPOSITE1 }, + { CX18_CARD_INPUT_SVIDEO2, 2, + CX18_AV_SVIDEO_LUMA7 | CX18_AV_SVIDEO_CHROMA8 }, + { CX18_CARD_INPUT_COMPOSITE2, 2, CX18_AV_COMPOSITE6 }, + }, + .audio_inputs = { + { CX18_CARD_INPUT_AUD_TUNER, CX18_AV_AUDIO5, 0 }, + { CX18_CARD_INPUT_LINE_IN1, CX18_AV_AUDIO_SERIAL1, 1 }, + { CX18_CARD_INPUT_LINE_IN2, CX18_AV_AUDIO_SERIAL2, 1 }, + }, + .tuners = { + { .std = V4L2_STD_PAL_SECAM, .tuner = TUNER_PHILIPS_FM1216ME_MK3 }, + }, + .radio_input = { CX18_CARD_INPUT_AUD_TUNER, CX18_AV_AUDIO_SERIAL1, 2 }, + .ddr = { + /* MT 46V16M16 memory */ + .chip_config = 0x50306, + .refresh = 0x753, + .timing1 = 0x33220953, + .timing2 = 0x09, + .tune_lane = 0, + .initial_emrs = 0, + }, + .gpio_init.initial_value = 0x1002, + .gpio_init.direction = 0xf002, + .gpio_audio_input = { .mask = 0xf002, + .tuner = 0x1002, /* LED D1 Tuner AF */ + .linein = 0x2000, /* LED D2 Line In 1 */ + .radio = 0x4002 }, /* LED D3 Tuner AF */ + .pci_list = cx18_pci_cnxt_raptor_pal, + .i2c = &cx18_i2c_std, +}; + +/* ------------------------------------------------------------------------- */ + static const struct cx18_card *cx18_card_list[] = { &cx18_card_hvr1600_esmt, &cx18_card_hvr1600_samsung, &cx18_card_h900, &cx18_card_mpc718, + &cx18_card_cnxt_raptor_pal, }; const struct cx18_card *cx18_get_card(u16 index) diff --git a/drivers/media/video/cx18/cx18-cards.h b/drivers/media/video/cx18/cx18-cards.h index dc2dd945d4c3..32155f6e6fe4 100644 --- a/drivers/media/video/cx18/cx18-cards.h +++ b/drivers/media/video/cx18/cx18-cards.h @@ -83,6 +83,14 @@ struct cx18_gpio_i2c_slave_reset { u32 active_hi_mask; /* GPIO outputs that reset i2c chips when high */ int msecs_asserted; /* time period reset must remain asserted */ int msecs_recovery; /* time after deassert for chips to be ready */ + u32 ir_reset_mask; /* GPIO to reset the Zilog Z8F0811 IR contoller */ +}; + +struct cx18_gpio_audio_input { /* select tuner/line in input */ + u32 mask; /* leave to 0 if not supported */ + u32 tuner; + u32 linein; + u32 radio; }; struct cx18_card_tuner { @@ -123,6 +131,7 @@ struct cx18_card { u8 xceive_pin; /* XCeive tuner GPIO reset pin */ struct cx18_gpio_init gpio_init; struct cx18_gpio_i2c_slave_reset gpio_i2c_slave_reset; + struct cx18_gpio_audio_input gpio_audio_input; struct cx18_card_tuner tuners[CX18_CARD_MAX_TUNERS]; struct cx18_card_tuner_i2c *i2c; diff --git a/drivers/media/video/cx18/cx18-controls.c b/drivers/media/video/cx18/cx18-controls.c index 87cf41021665..f46c7e5ed747 100644 --- a/drivers/media/video/cx18/cx18-controls.c +++ b/drivers/media/video/cx18/cx18-controls.c @@ -51,12 +51,11 @@ static const u32 *ctrl_classes[] = { NULL }; -static int cx18_queryctrl(struct cx18 *cx, struct v4l2_queryctrl *qctrl) +int cx18_queryctrl(struct file *file, void *fh, struct v4l2_queryctrl *qctrl) { + struct cx18 *cx = ((struct cx18_open_id *)fh)->cx; const char *name; - CX18_DEBUG_IOCTL("VIDIOC_QUERYCTRL(%08x)\n", qctrl->id); - qctrl->id = v4l2_ctrl_next(ctrl_classes, qctrl->id); if (qctrl->id == 0) return -EINVAL; @@ -91,21 +90,35 @@ static int cx18_queryctrl(struct cx18 *cx, struct v4l2_queryctrl *qctrl) return 0; } -static int cx18_querymenu(struct cx18 *cx, struct v4l2_querymenu *qmenu) +int cx18_querymenu(struct file *file, void *fh, struct v4l2_querymenu *qmenu) { + struct cx18 *cx = ((struct cx18_open_id *)fh)->cx; struct v4l2_queryctrl qctrl; qctrl.id = qmenu->id; - cx18_queryctrl(cx, &qctrl); - return v4l2_ctrl_query_menu(qmenu, &qctrl, cx2341x_ctrl_get_menu(qmenu->id)); + cx18_queryctrl(file, fh, &qctrl); + return v4l2_ctrl_query_menu(qmenu, &qctrl, + cx2341x_ctrl_get_menu(&cx->params, qmenu->id)); } -static int cx18_s_ctrl(struct cx18 *cx, struct v4l2_control *vctrl) +static int cx18_try_ctrl(struct file *file, void *fh, + struct v4l2_ext_control *vctrl) { - s32 v = vctrl->value; - - CX18_DEBUG_IOCTL("VIDIOC_S_CTRL(%08x, %x)\n", vctrl->id, v); + struct v4l2_queryctrl qctrl; + const char **menu_items = NULL; + int err; + + qctrl.id = vctrl->id; + err = cx18_queryctrl(file, fh, &qctrl); + if (err) + return err; + if (qctrl.type == V4L2_CTRL_TYPE_MENU) + menu_items = v4l2_ctrl_get_menu(qctrl.id); + return v4l2_ctrl_check(vctrl, &qctrl, menu_items); +} +static int cx18_s_ctrl(struct cx18 *cx, struct v4l2_control *vctrl) +{ switch (vctrl->id) { /* Standard V4L2 controls */ case V4L2_CID_BRIGHTNESS: @@ -123,7 +136,7 @@ static int cx18_s_ctrl(struct cx18 *cx, struct v4l2_control *vctrl) return cx18_i2c_hw(cx, cx->card->hw_audio_ctrl, VIDIOC_S_CTRL, vctrl); default: - CX18_DEBUG_IOCTL("invalid control %x\n", vctrl->id); + CX18_DEBUG_IOCTL("invalid control 0x%x\n", vctrl->id); return -EINVAL; } return 0; @@ -131,8 +144,6 @@ static int cx18_s_ctrl(struct cx18 *cx, struct v4l2_control *vctrl) static int cx18_g_ctrl(struct cx18 *cx, struct v4l2_control *vctrl) { - CX18_DEBUG_IOCTL("VIDIOC_G_CTRL(%08x)\n", vctrl->id); - switch (vctrl->id) { /* Standard V4L2 controls */ case V4L2_CID_BRIGHTNESS: @@ -149,7 +160,7 @@ static int cx18_g_ctrl(struct cx18 *cx, struct v4l2_control *vctrl) case V4L2_CID_AUDIO_LOUDNESS: return cx18_i2c_hw(cx, cx->card->hw_audio_ctrl, VIDIOC_G_CTRL, vctrl); default: - CX18_DEBUG_IOCTL("invalid control %x\n", vctrl->id); + CX18_DEBUG_IOCTL("invalid control 0x%x\n", vctrl->id); return -EINVAL; } return 0; @@ -194,113 +205,110 @@ static int cx18_setup_vbi_fmt(struct cx18 *cx, enum v4l2_mpeg_stream_vbi_fmt fmt return 0; } -int cx18_control_ioctls(struct cx18 *cx, unsigned int cmd, void *arg) +int cx18_g_ext_ctrls(struct file *file, void *fh, struct v4l2_ext_controls *c) { + struct cx18 *cx = ((struct cx18_open_id *)fh)->cx; struct v4l2_control ctrl; - switch (cmd) { - case VIDIOC_QUERYMENU: - CX18_DEBUG_IOCTL("VIDIOC_QUERYMENU\n"); - return cx18_querymenu(cx, arg); - - case VIDIOC_QUERYCTRL: - return cx18_queryctrl(cx, arg); - - case VIDIOC_S_CTRL: - return cx18_s_ctrl(cx, arg); - - case VIDIOC_G_CTRL: - return cx18_g_ctrl(cx, arg); - - case VIDIOC_S_EXT_CTRLS: - { - struct v4l2_ext_controls *c = arg; - - if (c->ctrl_class == V4L2_CTRL_CLASS_USER) { - int i; - int err = 0; - - for (i = 0; i < c->count; i++) { - ctrl.id = c->controls[i].id; - ctrl.value = c->controls[i].value; - err = cx18_s_ctrl(cx, &ctrl); - c->controls[i].value = ctrl.value; - if (err) { - c->error_idx = i; - break; - } + if (c->ctrl_class == V4L2_CTRL_CLASS_USER) { + int i; + int err = 0; + + for (i = 0; i < c->count; i++) { + ctrl.id = c->controls[i].id; + ctrl.value = c->controls[i].value; + err = cx18_g_ctrl(cx, &ctrl); + c->controls[i].value = ctrl.value; + if (err) { + c->error_idx = i; + break; } - return err; } - CX18_DEBUG_IOCTL("VIDIOC_S_EXT_CTRLS\n"); - if (c->ctrl_class == V4L2_CTRL_CLASS_MPEG) { - struct cx2341x_mpeg_params p = cx->params; - int err = cx2341x_ext_ctrls(&p, atomic_read(&cx->ana_capturing), arg, cmd); + return err; + } + if (c->ctrl_class == V4L2_CTRL_CLASS_MPEG) + return cx2341x_ext_ctrls(&cx->params, 0, c, VIDIOC_G_EXT_CTRLS); + return -EINVAL; +} - if (err) - return err; +int cx18_s_ext_ctrls(struct file *file, void *fh, struct v4l2_ext_controls *c) +{ + struct cx18_open_id *id = fh; + struct cx18 *cx = id->cx; + int ret; + struct v4l2_control ctrl; - if (p.video_encoding != cx->params.video_encoding) { - int is_mpeg1 = p.video_encoding == - V4L2_MPEG_VIDEO_ENCODING_MPEG_1; - struct v4l2_format fmt; + ret = v4l2_prio_check(&cx->prio, &id->prio); + if (ret) + return ret; - /* fix videodecoder resolution */ - fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - fmt.fmt.pix.width = cx->params.width / (is_mpeg1 ? 2 : 1); - fmt.fmt.pix.height = cx->params.height; - cx18_av_cmd(cx, VIDIOC_S_FMT, &fmt); + if (c->ctrl_class == V4L2_CTRL_CLASS_USER) { + int i; + int err = 0; + + for (i = 0; i < c->count; i++) { + ctrl.id = c->controls[i].id; + ctrl.value = c->controls[i].value; + err = cx18_s_ctrl(cx, &ctrl); + c->controls[i].value = ctrl.value; + if (err) { + c->error_idx = i; + break; } - err = cx2341x_update(cx, cx18_api_func, &cx->params, &p); - if (!err && cx->params.stream_vbi_fmt != p.stream_vbi_fmt) - err = cx18_setup_vbi_fmt(cx, p.stream_vbi_fmt); - cx->params = p; - cx->dualwatch_stereo_mode = p.audio_properties & 0x0300; - cx18_audio_set_audio_clock_freq(cx, p.audio_properties & 0x03); - return err; } - return -EINVAL; + return err; } + if (c->ctrl_class == V4L2_CTRL_CLASS_MPEG) { + struct cx2341x_mpeg_params p = cx->params; + int err = cx2341x_ext_ctrls(&p, atomic_read(&cx->ana_capturing), + c, VIDIOC_S_EXT_CTRLS); - case VIDIOC_G_EXT_CTRLS: - { - struct v4l2_ext_controls *c = arg; - - if (c->ctrl_class == V4L2_CTRL_CLASS_USER) { - int i; - int err = 0; - - for (i = 0; i < c->count; i++) { - ctrl.id = c->controls[i].id; - ctrl.value = c->controls[i].value; - err = cx18_g_ctrl(cx, &ctrl); - c->controls[i].value = ctrl.value; - if (err) { - c->error_idx = i; - break; - } - } + if (err) return err; + + if (p.video_encoding != cx->params.video_encoding) { + int is_mpeg1 = p.video_encoding == + V4L2_MPEG_VIDEO_ENCODING_MPEG_1; + struct v4l2_format fmt; + + /* fix videodecoder resolution */ + fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + fmt.fmt.pix.width = cx->params.width + / (is_mpeg1 ? 2 : 1); + fmt.fmt.pix.height = cx->params.height; + cx18_av_cmd(cx, VIDIOC_S_FMT, &fmt); } - CX18_DEBUG_IOCTL("VIDIOC_G_EXT_CTRLS\n"); - if (c->ctrl_class == V4L2_CTRL_CLASS_MPEG) - return cx2341x_ext_ctrls(&cx->params, 0, arg, cmd); - return -EINVAL; + err = cx2341x_update(cx, cx18_api_func, &cx->params, &p); + if (!err && cx->params.stream_vbi_fmt != p.stream_vbi_fmt) + err = cx18_setup_vbi_fmt(cx, p.stream_vbi_fmt); + cx->params = p; + cx->dualwatch_stereo_mode = p.audio_properties & 0x0300; + cx18_audio_set_audio_clock_freq(cx, p.audio_properties & 0x03); + return err; } + return -EINVAL; +} - case VIDIOC_TRY_EXT_CTRLS: - { - struct v4l2_ext_controls *c = arg; +int cx18_try_ext_ctrls(struct file *file, void *fh, struct v4l2_ext_controls *c) +{ + struct cx18 *cx = ((struct cx18_open_id *)fh)->cx; - CX18_DEBUG_IOCTL("VIDIOC_TRY_EXT_CTRLS\n"); - if (c->ctrl_class == V4L2_CTRL_CLASS_MPEG) - return cx2341x_ext_ctrls(&cx->params, - atomic_read(&cx->ana_capturing), arg, cmd); - return -EINVAL; - } + if (c->ctrl_class == V4L2_CTRL_CLASS_USER) { + int i; + int err = 0; - default: - return -EINVAL; + for (i = 0; i < c->count; i++) { + err = cx18_try_ctrl(file, fh, &c->controls[i]); + if (err) { + c->error_idx = i; + break; + } + } + return err; } - return 0; + if (c->ctrl_class == V4L2_CTRL_CLASS_MPEG) + return cx2341x_ext_ctrls(&cx->params, + atomic_read(&cx->ana_capturing), + c, VIDIOC_TRY_EXT_CTRLS); + return -EINVAL; } diff --git a/drivers/media/video/cx18/cx18-controls.h b/drivers/media/video/cx18/cx18-controls.h index 6e985cf422a0..e46323700b81 100644 --- a/drivers/media/video/cx18/cx18-controls.h +++ b/drivers/media/video/cx18/cx18-controls.h @@ -21,4 +21,9 @@ * 02111-1307 USA */ -int cx18_control_ioctls(struct cx18 *cx, unsigned int cmd, void *arg); +int cx18_queryctrl(struct file *file, void *fh, struct v4l2_queryctrl *a); +int cx18_g_ext_ctrls(struct file *file, void *fh, struct v4l2_ext_controls *a); +int cx18_s_ext_ctrls(struct file *file, void *fh, struct v4l2_ext_controls *a); +int cx18_try_ext_ctrls(struct file *file, void *fh, + struct v4l2_ext_controls *a); +int cx18_querymenu(struct file *file, void *fh, struct v4l2_querymenu *a); diff --git a/drivers/media/video/cx18/cx18-driver.c b/drivers/media/video/cx18/cx18-driver.c index 2b810bb2a4c7..22434aadde31 100644 --- a/drivers/media/video/cx18/cx18-driver.c +++ b/drivers/media/video/cx18/cx18-driver.c @@ -120,6 +120,7 @@ MODULE_PARM_DESC(cardtype, "\t\t\t 2 = Hauppauge HVR 1600 (Samsung memory)\n" "\t\t\t 3 = Compro VideoMate H900\n" "\t\t\t 4 = Yuan MPC718\n" + "\t\t\t 5 = Conexant Raptor PAL/SECAM\n" "\t\t\t 0 = Autodetect (default)\n" "\t\t\t-1 = Ignore this card\n\t\t"); MODULE_PARM_DESC(pal, "Set PAL standard: B, G, H, D, K, I, M, N, Nc, 60"); @@ -420,6 +421,7 @@ static int __devinit cx18_init_struct1(struct cx18 *cx) mutex_init(&cx->serialize_lock); mutex_init(&cx->i2c_bus_lock[0]); mutex_init(&cx->i2c_bus_lock[1]); + mutex_init(&cx->gpio_lock); spin_lock_init(&cx->lock); spin_lock_init(&cx->dma_reg_lock); @@ -435,7 +437,7 @@ static int __devinit cx18_init_struct1(struct cx18 *cx) (cx->params.video_temporal_filter_mode << 1) | (cx->params.video_median_filter_type << 2); cx->params.port = CX2341X_PORT_MEMORY; - cx->params.capabilities = CX2341X_CAP_HAS_SLICED_VBI; + cx->params.capabilities = CX2341X_CAP_HAS_TS; init_waitqueue_head(&cx->cap_w); init_waitqueue_head(&cx->mb_apu_waitq); init_waitqueue_head(&cx->mb_cpu_waitq); @@ -614,7 +616,7 @@ static int __devinit cx18_probe(struct pci_dev *dev, cx18_cards[cx18_cards_active] = cx; cx->dev = dev; cx->num = cx18_cards_active++; - snprintf(cx->name, sizeof(cx->name) - 1, "cx18-%d", cx->num); + snprintf(cx->name, sizeof(cx->name), "cx18-%d", cx->num); CX18_INFO("Initializing card #%d\n", cx->num); spin_unlock(&cx18_cards_lock); @@ -721,6 +723,12 @@ static int __devinit cx18_probe(struct pci_dev *dev, /* if no tuner was found, then pick the first tuner in the card list */ if (cx->options.tuner == -1 && cx->card->tuners[0].std) { cx->std = cx->card->tuners[0].std; + if (cx->std & V4L2_STD_PAL) + cx->std = V4L2_STD_PAL_BG | V4L2_STD_PAL_H; + else if (cx->std & V4L2_STD_NTSC) + cx->std = V4L2_STD_NTSC_M; + else if (cx->std & V4L2_STD_SECAM) + cx->std = V4L2_STD_SECAM_L; cx->options.tuner = cx->card->tuners[0].tuner; } if (cx->options.radio == -1) @@ -818,6 +826,9 @@ int cx18_init_on_first_open(struct cx18 *cx) int video_input; int fw_retry_count = 3; struct v4l2_frequency vf; + struct cx18_open_id fh; + + fh.cx = cx; if (test_bit(CX18_F_I_FAILED, &cx->i_flags)) return -ENXIO; @@ -869,13 +880,13 @@ int cx18_init_on_first_open(struct cx18 *cx) video_input = cx->active_input; cx->active_input++; /* Force update of input */ - cx18_v4l2_ioctls(cx, NULL, VIDIOC_S_INPUT, &video_input); + cx18_s_input(NULL, &fh, video_input); /* Let the VIDIOC_S_STD ioctl do all the work, keeps the code in one place. */ cx->std++; /* Force full standard initialization */ - cx18_v4l2_ioctls(cx, NULL, VIDIOC_S_STD, &cx->tuner_std); - cx18_v4l2_ioctls(cx, NULL, VIDIOC_S_FREQUENCY, &vf); + cx18_s_std(NULL, &fh, &cx->tuner_std); + cx18_s_frequency(NULL, &fh, &vf); return 0; } diff --git a/drivers/media/video/cx18/cx18-driver.h b/drivers/media/video/cx18/cx18-driver.h index de14ab59a206..45e31b04730e 100644 --- a/drivers/media/video/cx18/cx18-driver.h +++ b/drivers/media/video/cx18/cx18-driver.h @@ -75,7 +75,8 @@ #define CX18_CARD_HVR_1600_SAMSUNG 1 /* Hauppauge HVR 1600 (Samsung memory) */ #define CX18_CARD_COMPRO_H900 2 /* Compro VideoMate H900 */ #define CX18_CARD_YUAN_MPC718 3 /* Yuan MPC718 */ -#define CX18_CARD_LAST 3 +#define CX18_CARD_CNXT_RAPTOR_PAL 4 /* Conexant Raptor PAL */ +#define CX18_CARD_LAST 4 #define CX18_ENC_STREAM_TYPE_MPG 0 #define CX18_ENC_STREAM_TYPE_TS 1 @@ -94,6 +95,7 @@ #define CX18_PCI_ID_HAUPPAUGE 0x0070 #define CX18_PCI_ID_COMPRO 0x185b #define CX18_PCI_ID_YUAN 0x12ab +#define CX18_PCI_ID_CONEXANT 0x14f1 /* ======================================================================== */ /* ========================== START USER SETTABLE DMA VARIABLES =========== */ @@ -228,9 +230,7 @@ struct cx18_dvb { struct dvb_net dvbnet; int enabled; int feeding; - struct mutex feedlock; - }; struct cx18; /* forward reference */ @@ -427,6 +427,7 @@ struct cx18 { /* gpio */ u32 gpio_dir; u32 gpio_val; + struct mutex gpio_lock; /* v4l2 and User settings */ diff --git a/drivers/media/video/cx18/cx18-firmware.c b/drivers/media/video/cx18/cx18-firmware.c index 2694ce350631..2d630d9f7496 100644 --- a/drivers/media/video/cx18/cx18-firmware.c +++ b/drivers/media/video/cx18/cx18-firmware.c @@ -41,9 +41,6 @@ #define CX18_REG_BUS_TIMEOUT_EN 0xc72024 -#define CX18_AUDIO_ENABLE 0xc72014 -#define CX18_REG_BUS_TIMEOUT_EN 0xc72024 - #define CX18_FAST_CLOCK_PLL_INT 0xc78000 #define CX18_FAST_CLOCK_PLL_FRAC 0xc78004 #define CX18_FAST_CLOCK_PLL_POST 0xc78008 @@ -90,7 +87,7 @@ #define CX18_DSP0_INTERRUPT_MASK 0xd0004C /* Encoder/decoder firmware sizes */ -#define CX18_FW_CPU_SIZE (174716) +#define CX18_FW_CPU_SIZE (158332) #define CX18_FW_APU_SIZE (141200) #define APU_ROM_SYNC1 0x6D676553 /* "mgeS" */ @@ -345,6 +342,11 @@ int cx18_firmware_init(struct cx18 *cx) int sz = load_apu_fw_direct("v4l-cx23418-apu.fw", cx->enc_mem, cx, CX18_FW_APU_SIZE); + write_enc(0xE51FF004, 0); + write_enc(0xa00000, 4); /* todo: not hardcoded */ + write_reg(0x00010000, CX18_PROC_SOFT_RESET); /* Start APU */ + cx18_msleep_timeout(500, 0); + sz = sz <= 0 ? sz : load_cpu_fw_direct("v4l-cx23418-cpu.fw", cx->enc_mem, cx, CX18_FW_CPU_SIZE); diff --git a/drivers/media/video/cx18/cx18-gpio.c b/drivers/media/video/cx18/cx18-gpio.c index b302833f6f9d..3d495dba4983 100644 --- a/drivers/media/video/cx18/cx18-gpio.c +++ b/drivers/media/video/cx18/cx18-gpio.c @@ -69,6 +69,7 @@ void cx18_reset_i2c_slaves_gpio(struct cx18 *cx) /* Assuming that the masks are a subset of the bits in gpio_dir */ /* Assert */ + mutex_lock(&cx->gpio_lock); cx->gpio_val = (cx->gpio_val | p->active_hi_mask) & ~(p->active_lo_mask); gpio_write(cx); @@ -79,10 +80,53 @@ void cx18_reset_i2c_slaves_gpio(struct cx18 *cx) (cx->gpio_val | p->active_lo_mask) & ~(p->active_hi_mask); gpio_write(cx); schedule_timeout_uninterruptible(msecs_to_jiffies(p->msecs_recovery)); + mutex_unlock(&cx->gpio_lock); } +void cx18_reset_ir_gpio(void *data) +{ + struct cx18 *cx = ((struct cx18_i2c_algo_callback_data *)data)->cx; + const struct cx18_gpio_i2c_slave_reset *p; + + p = &cx->card->gpio_i2c_slave_reset; + + if (p->ir_reset_mask == 0) + return; + + CX18_DEBUG_INFO("Resetting IR microcontroller\n"); + + /* + Assert timing for the Z8F0811 on HVR-1600 boards: + 1. Assert RESET for min of 4 clock cycles at 18.432 MHz to initiate + 2. Reset then takes 66 WDT cycles at 10 kHz + 16 xtal clock cycles + (6,601,085 nanoseconds ~= 7 milliseconds) + 3. DBG pin must be high before chip exits reset for normal operation. + DBG is open drain and hopefully pulled high since we don't + normally drive it (GPIO 1?) for the HVR-1600 + 4. Z8F0811 won't exit reset until RESET is deasserted + */ + mutex_lock(&cx->gpio_lock); + cx->gpio_val = cx->gpio_val & ~p->ir_reset_mask; + gpio_write(cx); + mutex_unlock(&cx->gpio_lock); + schedule_timeout_uninterruptible(msecs_to_jiffies(p->msecs_asserted)); + + /* + Zilog comes out of reset, loads reset vector address and executes + from there. Required recovery delay unknown. + */ + mutex_lock(&cx->gpio_lock); + cx->gpio_val = cx->gpio_val | p->ir_reset_mask; + gpio_write(cx); + mutex_unlock(&cx->gpio_lock); + schedule_timeout_uninterruptible(msecs_to_jiffies(p->msecs_recovery)); +} +EXPORT_SYMBOL(cx18_reset_ir_gpio); +/* This symbol is exported for use by an infrared module for the IR-blaster */ + void cx18_gpio_init(struct cx18 *cx) { + mutex_lock(&cx->gpio_lock); cx->gpio_dir = cx->card->gpio_init.direction; cx->gpio_val = cx->card->gpio_init.initial_value; @@ -91,14 +135,17 @@ void cx18_gpio_init(struct cx18 *cx) cx->gpio_val |= 1 << cx->card->xceive_pin; } - if (cx->gpio_dir == 0) + if (cx->gpio_dir == 0) { + mutex_unlock(&cx->gpio_lock); return; + } CX18_DEBUG_INFO("GPIO initial dir: %08x/%08x out: %08x/%08x\n", read_reg(CX18_REG_GPIO_DIR1), read_reg(CX18_REG_GPIO_DIR2), read_reg(CX18_REG_GPIO_OUT1), read_reg(CX18_REG_GPIO_OUT2)); gpio_write(cx); + mutex_unlock(&cx->gpio_lock); } /* Xceive tuner reset function */ @@ -112,13 +159,52 @@ int cx18_reset_tuner_gpio(void *dev, int cmd, int value) return 0; CX18_DEBUG_INFO("Resetting tuner\n"); + mutex_lock(&cx->gpio_lock); cx->gpio_val &= ~(1 << cx->card->xceive_pin); - gpio_write(cx); + mutex_unlock(&cx->gpio_lock); schedule_timeout_interruptible(msecs_to_jiffies(1)); + mutex_lock(&cx->gpio_lock); cx->gpio_val |= 1 << cx->card->xceive_pin; gpio_write(cx); + mutex_unlock(&cx->gpio_lock); schedule_timeout_interruptible(msecs_to_jiffies(1)); return 0; } + +int cx18_gpio(struct cx18 *cx, unsigned int command, void *arg) +{ + struct v4l2_routing *route = arg; + u32 mask, data; + + switch (command) { + case VIDIOC_INT_S_AUDIO_ROUTING: + if (route->input > 2) + return -EINVAL; + mask = cx->card->gpio_audio_input.mask; + switch (route->input) { + case 0: + data = cx->card->gpio_audio_input.tuner; + break; + case 1: + data = cx->card->gpio_audio_input.linein; + break; + case 2: + default: + data = cx->card->gpio_audio_input.radio; + break; + } + break; + + default: + return -EINVAL; + } + if (mask) { + mutex_lock(&cx->gpio_lock); + cx->gpio_val = (cx->gpio_val & ~mask) | (data & mask); + gpio_write(cx); + mutex_unlock(&cx->gpio_lock); + } + return 0; +} diff --git a/drivers/media/video/cx18/cx18-gpio.h b/drivers/media/video/cx18/cx18-gpio.h index 525c328f748a..22cd7ddf8554 100644 --- a/drivers/media/video/cx18/cx18-gpio.h +++ b/drivers/media/video/cx18/cx18-gpio.h @@ -22,4 +22,6 @@ void cx18_gpio_init(struct cx18 *cx); void cx18_reset_i2c_slaves_gpio(struct cx18 *cx); +void cx18_reset_ir_gpio(void *data); int cx18_reset_tuner_gpio(void *dev, int cmd, int value); +int cx18_gpio(struct cx18 *cx, unsigned int command, void *arg); diff --git a/drivers/media/video/cx18/cx18-i2c.c b/drivers/media/video/cx18/cx18-i2c.c index 680bc4e35b79..6023ba3bd3a6 100644 --- a/drivers/media/video/cx18/cx18-i2c.c +++ b/drivers/media/video/cx18/cx18-i2c.c @@ -39,10 +39,6 @@ #define GETSCL_BIT 0x0004 #define GETSDL_BIT 0x0008 -#ifndef I2C_ADAP_CLASS_TV_ANALOG -#define I2C_ADAP_CLASS_TV_ANALOG I2C_CLASS_TV_ANALOG -#endif - #define CX18_CS5345_I2C_ADDR 0x4c /* This array should match the CX18_HW_ defines */ @@ -311,8 +307,12 @@ int cx18_i2c_hw(struct cx18 *cx, u32 hw, unsigned int cmd, void *arg) { int addr; - if (hw == CX18_HW_GPIO || hw == 0) + if (hw == 0) return 0; + + if (hw == CX18_HW_GPIO) + return cx18_gpio(cx, cmd, arg); + if (hw == CX18_HW_CX23418) return cx18_av_cmd(cx, cmd, arg); @@ -350,6 +350,8 @@ void cx18_call_i2c_clients(struct cx18 *cx, unsigned int cmd, void *arg) cx18_av_cmd(cx, cmd, arg); i2c_clients_command(&cx->i2c_adap[0], cmd, arg); i2c_clients_command(&cx->i2c_adap[1], cmd, arg); + if (cx->hw_flags & CX18_HW_GPIO) + cx18_gpio(cx, cmd, arg); } /* init + register i2c algo-bit adapter */ @@ -358,6 +360,18 @@ int init_cx18_i2c(struct cx18 *cx) int i; CX18_DEBUG_I2C("i2c init\n"); + /* Sanity checks for the I2C hardware arrays. They must be the + * same size and GPIO/CX23418 must be the last entries. + */ + if (ARRAY_SIZE(hw_driverids) != ARRAY_SIZE(hw_addrs) || + ARRAY_SIZE(hw_devicenames) != ARRAY_SIZE(hw_addrs) || + CX18_HW_GPIO != (1 << (ARRAY_SIZE(hw_addrs) - 2)) || + CX18_HW_CX23418 != (1 << (ARRAY_SIZE(hw_addrs) - 1)) || + hw_driverids[ARRAY_SIZE(hw_addrs) - 1]) { + CX18_ERR("Mismatched I2C hardware arrays\n"); + return -ENODEV; + } + for (i = 0; i < 2; i++) { memcpy(&cx->i2c_adap[i], &cx18_i2c_adap_template, sizeof(struct i2c_adapter)); @@ -391,6 +405,7 @@ int init_cx18_i2c(struct cx18 *cx) write_reg_sync(0x00c000c0, 0xc7001c); mdelay(10); write_reg_sync(0x00c00000, 0xc7001c); + mdelay(10); write_reg_sync(0x00c00000, 0xc730c8); /* Set to edge-triggered intrs. */ write_reg_sync(0x00c00000, 0xc730c4); /* Clear any stale intrs */ diff --git a/drivers/media/video/cx18/cx18-ioctl.c b/drivers/media/video/cx18/cx18-ioctl.c index 4151f1e5493f..0d74e59e503e 100644 --- a/drivers/media/video/cx18/cx18-ioctl.c +++ b/drivers/media/video/cx18/cx18-ioctl.c @@ -100,19 +100,6 @@ void cx18_expand_service_set(struct v4l2_sliced_vbi_format *fmt, int is_pal) } } -static int check_service_set(struct v4l2_sliced_vbi_format *fmt, int is_pal) -{ - int f, l; - u16 set = 0; - - for (f = 0; f < 2; f++) { - for (l = 0; l < 24; l++) { - fmt->service_lines[f][l] = select_service_from_set(f, l, fmt->service_lines[f][l], is_pal); - set |= fmt->service_lines[f][l]; - } - } - return set != 0; -} u16 cx18_get_service_set(struct v4l2_sliced_vbi_format *fmt) { @@ -126,35 +113,167 @@ u16 cx18_get_service_set(struct v4l2_sliced_vbi_format *fmt) return set; } -static const struct { - v4l2_std_id std; - char *name; -} enum_stds[] = { - { V4L2_STD_PAL_BG | V4L2_STD_PAL_H, "PAL-BGH" }, - { V4L2_STD_PAL_DK, "PAL-DK" }, - { V4L2_STD_PAL_I, "PAL-I" }, - { V4L2_STD_PAL_M, "PAL-M" }, - { V4L2_STD_PAL_N, "PAL-N" }, - { V4L2_STD_PAL_Nc, "PAL-Nc" }, - { V4L2_STD_SECAM_B | V4L2_STD_SECAM_G | V4L2_STD_SECAM_H, "SECAM-BGH" }, - { V4L2_STD_SECAM_DK, "SECAM-DK" }, - { V4L2_STD_SECAM_L, "SECAM-L" }, - { V4L2_STD_SECAM_LC, "SECAM-L'" }, - { V4L2_STD_NTSC_M, "NTSC-M" }, - { V4L2_STD_NTSC_M_JP, "NTSC-J" }, - { V4L2_STD_NTSC_M_KR, "NTSC-K" }, -}; - -static const struct v4l2_standard cx18_std_60hz = { - .frameperiod = {.numerator = 1001, .denominator = 30000}, - .framelines = 525, -}; - -static const struct v4l2_standard cx18_std_50hz = { - .frameperiod = { .numerator = 1, .denominator = 25 }, - .framelines = 625, -}; +static int cx18_g_fmt_vid_cap(struct file *file, void *fh, + struct v4l2_format *fmt) +{ + struct cx18_open_id *id = fh; + struct cx18 *cx = id->cx; + struct v4l2_pix_format *pixfmt = &fmt->fmt.pix; + + pixfmt->width = cx->params.width; + pixfmt->height = cx->params.height; + pixfmt->colorspace = V4L2_COLORSPACE_SMPTE170M; + pixfmt->field = V4L2_FIELD_INTERLACED; + pixfmt->priv = 0; + if (id->type == CX18_ENC_STREAM_TYPE_YUV) { + pixfmt->pixelformat = V4L2_PIX_FMT_HM12; + /* YUV size is (Y=(h*w) + UV=(h*(w/2))) */ + pixfmt->sizeimage = + pixfmt->height * pixfmt->width + + pixfmt->height * (pixfmt->width / 2); + pixfmt->bytesperline = 720; + } else { + pixfmt->pixelformat = V4L2_PIX_FMT_MPEG; + pixfmt->sizeimage = 128 * 1024; + pixfmt->bytesperline = 0; + } + return 0; +} + +static int cx18_g_fmt_vbi_cap(struct file *file, void *fh, + struct v4l2_format *fmt) +{ + struct cx18 *cx = ((struct cx18_open_id *)fh)->cx; + struct v4l2_vbi_format *vbifmt = &fmt->fmt.vbi; + + vbifmt->sampling_rate = 27000000; + vbifmt->offset = 248; + vbifmt->samples_per_line = cx->vbi.raw_decoder_line_size - 4; + vbifmt->sample_format = V4L2_PIX_FMT_GREY; + vbifmt->start[0] = cx->vbi.start[0]; + vbifmt->start[1] = cx->vbi.start[1]; + vbifmt->count[0] = vbifmt->count[1] = cx->vbi.count; + vbifmt->flags = 0; + vbifmt->reserved[0] = 0; + vbifmt->reserved[1] = 0; + return 0; +} + +static int cx18_g_fmt_sliced_vbi_cap(struct file *file, void *fh, + struct v4l2_format *fmt) +{ + return -EINVAL; +} + +static int cx18_try_fmt_vid_cap(struct file *file, void *fh, + struct v4l2_format *fmt) +{ + struct cx18_open_id *id = fh; + struct cx18 *cx = id->cx; + + int w = fmt->fmt.pix.width; + int h = fmt->fmt.pix.height; + + w = min(w, 720); + w = max(w, 1); + h = min(h, cx->is_50hz ? 576 : 480); + h = max(h, 2); + cx18_g_fmt_vid_cap(file, fh, fmt); + fmt->fmt.pix.width = w; + fmt->fmt.pix.height = h; + return 0; +} + +static int cx18_try_fmt_vbi_cap(struct file *file, void *fh, + struct v4l2_format *fmt) +{ + return cx18_g_fmt_vbi_cap(file, fh, fmt); +} + +static int cx18_try_fmt_sliced_vbi_cap(struct file *file, void *fh, + struct v4l2_format *fmt) +{ + return -EINVAL; +} + +static int cx18_s_fmt_vid_cap(struct file *file, void *fh, + struct v4l2_format *fmt) +{ + struct cx18_open_id *id = fh; + struct cx18 *cx = id->cx; + int ret; + int w = fmt->fmt.pix.width; + int h = fmt->fmt.pix.height; + + ret = v4l2_prio_check(&cx->prio, &id->prio); + if (ret) + return ret; + + ret = cx18_try_fmt_vid_cap(file, fh, fmt); + if (ret) + return ret; + + if (cx->params.width == w && cx->params.height == h) + return 0; + + if (atomic_read(&cx->ana_capturing) > 0) + return -EBUSY; + + cx->params.width = w; + cx->params.height = h; + cx18_av_cmd(cx, VIDIOC_S_FMT, fmt); + return cx18_g_fmt_vid_cap(file, fh, fmt); +} + +static int cx18_s_fmt_vbi_cap(struct file *file, void *fh, + struct v4l2_format *fmt) +{ + struct cx18_open_id *id = fh; + struct cx18 *cx = id->cx; + int ret; + + ret = v4l2_prio_check(&cx->prio, &id->prio); + if (ret) + return ret; + + if (id->type == CX18_ENC_STREAM_TYPE_VBI && + cx->vbi.sliced_in->service_set && + atomic_read(&cx->ana_capturing) > 0) + return -EBUSY; + + cx->vbi.sliced_in->service_set = 0; + cx18_av_cmd(cx, VIDIOC_S_FMT, &cx->vbi.in); + return cx18_g_fmt_vbi_cap(file, fh, fmt); +} + +static int cx18_s_fmt_sliced_vbi_cap(struct file *file, void *fh, + struct v4l2_format *fmt) +{ + return -EINVAL; +} +static int cx18_g_chip_ident(struct file *file, void *fh, + struct v4l2_chip_ident *chip) +{ + struct cx18 *cx = ((struct cx18_open_id *)fh)->cx; + + chip->ident = V4L2_IDENT_NONE; + chip->revision = 0; + if (chip->match_type == V4L2_CHIP_MATCH_HOST) { + if (v4l2_chip_match_host(chip->match_type, chip->match_chip)) + chip->ident = V4L2_IDENT_CX23418; + return 0; + } + if (chip->match_type == V4L2_CHIP_MATCH_I2C_DRIVER) + return cx18_i2c_id(cx, chip->match_chip, VIDIOC_G_CHIP_IDENT, + chip); + if (chip->match_type == V4L2_CHIP_MATCH_I2C_ADDR) + return cx18_call_i2c_client(cx, chip->match_chip, + VIDIOC_G_CHIP_IDENT, chip); + return -EINVAL; +} + +#ifdef CONFIG_VIDEO_ADV_DEBUG static int cx18_cxc(struct cx18 *cx, unsigned int cmd, void *arg) { struct v4l2_register *regs = arg; @@ -174,665 +293,478 @@ static int cx18_cxc(struct cx18 *cx, unsigned int cmd, void *arg) return 0; } -static int cx18_get_fmt(struct cx18 *cx, int streamtype, struct v4l2_format *fmt) -{ - switch (fmt->type) { - case V4L2_BUF_TYPE_VIDEO_CAPTURE: - fmt->fmt.pix.width = cx->params.width; - fmt->fmt.pix.height = cx->params.height; - fmt->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; - fmt->fmt.pix.field = V4L2_FIELD_INTERLACED; - if (streamtype == CX18_ENC_STREAM_TYPE_YUV) { - fmt->fmt.pix.pixelformat = V4L2_PIX_FMT_HM12; - /* YUV size is (Y=(h*w) + UV=(h*(w/2))) */ - fmt->fmt.pix.sizeimage = - fmt->fmt.pix.height * fmt->fmt.pix.width + - fmt->fmt.pix.height * (fmt->fmt.pix.width / 2); - } else { - fmt->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG; - fmt->fmt.pix.sizeimage = 128 * 1024; - } - break; - - case V4L2_BUF_TYPE_VBI_CAPTURE: - fmt->fmt.vbi.sampling_rate = 27000000; - fmt->fmt.vbi.offset = 248; - fmt->fmt.vbi.samples_per_line = cx->vbi.raw_decoder_line_size - 4; - fmt->fmt.vbi.sample_format = V4L2_PIX_FMT_GREY; - fmt->fmt.vbi.start[0] = cx->vbi.start[0]; - fmt->fmt.vbi.start[1] = cx->vbi.start[1]; - fmt->fmt.vbi.count[0] = fmt->fmt.vbi.count[1] = cx->vbi.count; - break; +static int cx18_g_register(struct file *file, void *fh, + struct v4l2_register *reg) +{ + struct cx18 *cx = ((struct cx18_open_id *)fh)->cx; + + if (v4l2_chip_match_host(reg->match_type, reg->match_chip)) + return cx18_cxc(cx, VIDIOC_DBG_G_REGISTER, reg); + if (reg->match_type == V4L2_CHIP_MATCH_I2C_DRIVER) + return cx18_i2c_id(cx, reg->match_chip, VIDIOC_DBG_G_REGISTER, + reg); + return cx18_call_i2c_client(cx, reg->match_chip, VIDIOC_DBG_G_REGISTER, + reg); +} - case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE: - { - struct v4l2_sliced_vbi_format *vbifmt = &fmt->fmt.sliced; +static int cx18_s_register(struct file *file, void *fh, + struct v4l2_register *reg) +{ + struct cx18 *cx = ((struct cx18_open_id *)fh)->cx; + + if (v4l2_chip_match_host(reg->match_type, reg->match_chip)) + return cx18_cxc(cx, VIDIOC_DBG_S_REGISTER, reg); + if (reg->match_type == V4L2_CHIP_MATCH_I2C_DRIVER) + return cx18_i2c_id(cx, reg->match_chip, VIDIOC_DBG_S_REGISTER, + reg); + return cx18_call_i2c_client(cx, reg->match_chip, VIDIOC_DBG_S_REGISTER, + reg); +} +#endif - vbifmt->io_size = sizeof(struct v4l2_sliced_vbi_data) * 36; - memset(vbifmt->reserved, 0, sizeof(vbifmt->reserved)); - memset(vbifmt->service_lines, 0, sizeof(vbifmt->service_lines)); +static int cx18_g_priority(struct file *file, void *fh, enum v4l2_priority *p) +{ + struct cx18 *cx = ((struct cx18_open_id *)fh)->cx; - cx18_av_cmd(cx, VIDIOC_G_FMT, fmt); - vbifmt->service_set = cx18_get_service_set(vbifmt); - break; - } - default: - return -EINVAL; - } + *p = v4l2_prio_max(&cx->prio); return 0; } -static int cx18_try_or_set_fmt(struct cx18 *cx, int streamtype, - struct v4l2_format *fmt, int set_fmt) +static int cx18_s_priority(struct file *file, void *fh, enum v4l2_priority prio) { - struct v4l2_sliced_vbi_format *vbifmt = &fmt->fmt.sliced; - u16 set; + struct cx18_open_id *id = fh; + struct cx18 *cx = id->cx; - /* set window size */ - if (fmt->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { - int w = fmt->fmt.pix.width; - int h = fmt->fmt.pix.height; + return v4l2_prio_change(&cx->prio, &id->prio, prio); +} - if (w > 720) - w = 720; - else if (w < 1) - w = 1; - if (h > (cx->is_50hz ? 576 : 480)) - h = (cx->is_50hz ? 576 : 480); - else if (h < 2) - h = 2; - cx18_get_fmt(cx, streamtype, fmt); - fmt->fmt.pix.width = w; - fmt->fmt.pix.height = h; +static int cx18_querycap(struct file *file, void *fh, + struct v4l2_capability *vcap) +{ + struct cx18 *cx = ((struct cx18_open_id *)fh)->cx; - if (!set_fmt || (cx->params.width == w && cx->params.height == h)) - return 0; - if (atomic_read(&cx->ana_capturing) > 0) - return -EBUSY; - - cx->params.width = w; - cx->params.height = h; - if (w != 720 || h != (cx->is_50hz ? 576 : 480)) - cx->params.video_temporal_filter = 0; - else - cx->params.video_temporal_filter = 8; - cx18_av_cmd(cx, VIDIOC_S_FMT, fmt); - return cx18_get_fmt(cx, streamtype, fmt); - } + strlcpy(vcap->driver, CX18_DRIVER_NAME, sizeof(vcap->driver)); + strlcpy(vcap->card, cx->card_name, sizeof(vcap->card)); + strlcpy(vcap->bus_info, pci_name(cx->dev), sizeof(vcap->bus_info)); + vcap->version = CX18_DRIVER_VERSION; /* version */ + vcap->capabilities = cx->v4l2_cap; /* capabilities */ + return 0; +} - /* set raw VBI format */ - if (fmt->type == V4L2_BUF_TYPE_VBI_CAPTURE) { - if (set_fmt && streamtype == CX18_ENC_STREAM_TYPE_VBI && - cx->vbi.sliced_in->service_set && - atomic_read(&cx->ana_capturing) > 0) - return -EBUSY; - if (set_fmt) { - cx->vbi.sliced_in->service_set = 0; - cx18_av_cmd(cx, VIDIOC_S_FMT, &cx->vbi.in); - } - return cx18_get_fmt(cx, streamtype, fmt); - } +static int cx18_enumaudio(struct file *file, void *fh, struct v4l2_audio *vin) +{ + struct cx18 *cx = ((struct cx18_open_id *)fh)->cx; - /* any else but sliced VBI capture is an error */ - if (fmt->type != V4L2_BUF_TYPE_SLICED_VBI_CAPTURE) - return -EINVAL; + return cx18_get_audio_input(cx, vin->index, vin); +} - /* TODO: implement sliced VBI, for now silently return 0 */ - return 0; +static int cx18_g_audio(struct file *file, void *fh, struct v4l2_audio *vin) +{ + struct cx18 *cx = ((struct cx18_open_id *)fh)->cx; - /* set sliced VBI capture format */ - vbifmt->io_size = sizeof(struct v4l2_sliced_vbi_data) * 36; - memset(vbifmt->reserved, 0, sizeof(vbifmt->reserved)); + vin->index = cx->audio_input; + return cx18_get_audio_input(cx, vin->index, vin); +} - if (vbifmt->service_set) - cx18_expand_service_set(vbifmt, cx->is_50hz); - set = check_service_set(vbifmt, cx->is_50hz); - vbifmt->service_set = cx18_get_service_set(vbifmt); +static int cx18_s_audio(struct file *file, void *fh, struct v4l2_audio *vout) +{ + struct cx18 *cx = ((struct cx18_open_id *)fh)->cx; - if (!set_fmt) - return 0; - if (set == 0) + if (vout->index >= cx->nof_audio_inputs) return -EINVAL; - if (atomic_read(&cx->ana_capturing) > 0 && cx->vbi.sliced_in->service_set == 0) - return -EBUSY; - cx18_av_cmd(cx, VIDIOC_S_FMT, fmt); - memcpy(cx->vbi.sliced_in, vbifmt, sizeof(*cx->vbi.sliced_in)); + cx->audio_input = vout->index; + cx18_audio_set_io(cx); return 0; } -static int cx18_debug_ioctls(struct file *filp, unsigned int cmd, void *arg) +static int cx18_enum_input(struct file *file, void *fh, struct v4l2_input *vin) { - struct cx18_open_id *id = (struct cx18_open_id *)filp->private_data; - struct cx18 *cx = id->cx; - struct v4l2_register *reg = arg; + struct cx18 *cx = ((struct cx18_open_id *)fh)->cx; - switch (cmd) { - /* ioctls to allow direct access to the encoder registers for testing */ - case VIDIOC_DBG_G_REGISTER: - if (v4l2_chip_match_host(reg->match_type, reg->match_chip)) - return cx18_cxc(cx, cmd, arg); - if (reg->match_type == V4L2_CHIP_MATCH_I2C_DRIVER) - return cx18_i2c_id(cx, reg->match_chip, cmd, arg); - return cx18_call_i2c_client(cx, reg->match_chip, cmd, arg); - - case VIDIOC_DBG_S_REGISTER: - if (v4l2_chip_match_host(reg->match_type, reg->match_chip)) - return cx18_cxc(cx, cmd, arg); - if (reg->match_type == V4L2_CHIP_MATCH_I2C_DRIVER) - return cx18_i2c_id(cx, reg->match_chip, cmd, arg); - return cx18_call_i2c_client(cx, reg->match_chip, cmd, arg); - - case VIDIOC_G_CHIP_IDENT: { - struct v4l2_chip_ident *chip = arg; - - chip->ident = V4L2_IDENT_NONE; - chip->revision = 0; - if (reg->match_type == V4L2_CHIP_MATCH_HOST) { - if (v4l2_chip_match_host(reg->match_type, reg->match_chip)) { - struct v4l2_chip_ident *chip = arg; - - chip->ident = V4L2_IDENT_CX23418; - } - return 0; - } - if (reg->match_type == V4L2_CHIP_MATCH_I2C_DRIVER) - return cx18_i2c_id(cx, reg->match_chip, cmd, arg); - if (reg->match_type == V4L2_CHIP_MATCH_I2C_ADDR) - return cx18_call_i2c_client(cx, reg->match_chip, cmd, arg); - return -EINVAL; - } - - case VIDIOC_INT_S_AUDIO_ROUTING: { - struct v4l2_routing *route = arg; + /* set it to defaults from our table */ + return cx18_get_input(cx, vin->index, vin); +} - cx18_audio_set_route(cx, route); - break; - } +static int cx18_cropcap(struct file *file, void *fh, + struct v4l2_cropcap *cropcap) +{ + struct cx18 *cx = ((struct cx18_open_id *)fh)->cx; - default: + if (cropcap->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) return -EINVAL; - } + cropcap->bounds.top = cropcap->bounds.left = 0; + cropcap->bounds.width = 720; + cropcap->bounds.height = cx->is_50hz ? 576 : 480; + cropcap->pixelaspect.numerator = cx->is_50hz ? 59 : 10; + cropcap->pixelaspect.denominator = cx->is_50hz ? 54 : 11; + cropcap->defrect = cropcap->bounds; return 0; } -int cx18_v4l2_ioctls(struct cx18 *cx, struct file *filp, unsigned cmd, void *arg) +static int cx18_s_crop(struct file *file, void *fh, struct v4l2_crop *crop) { - struct cx18_open_id *id = NULL; - - if (filp) - id = (struct cx18_open_id *)filp->private_data; - - switch (cmd) { - case VIDIOC_G_PRIORITY: - { - enum v4l2_priority *p = arg; + struct cx18_open_id *id = fh; + struct cx18 *cx = id->cx; + int ret; - *p = v4l2_prio_max(&cx->prio); - break; - } + ret = v4l2_prio_check(&cx->prio, &id->prio); + if (ret) + return ret; - case VIDIOC_S_PRIORITY: - { - enum v4l2_priority *prio = arg; + if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; + return cx18_av_cmd(cx, VIDIOC_S_CROP, crop); +} - return v4l2_prio_change(&cx->prio, &id->prio, *prio); - } +static int cx18_g_crop(struct file *file, void *fh, struct v4l2_crop *crop) +{ + struct cx18 *cx = ((struct cx18_open_id *)fh)->cx; - case VIDIOC_QUERYCAP:{ - struct v4l2_capability *vcap = arg; + if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; + return cx18_av_cmd(cx, VIDIOC_G_CROP, crop); +} - memset(vcap, 0, sizeof(*vcap)); - strlcpy(vcap->driver, CX18_DRIVER_NAME, sizeof(vcap->driver)); - strlcpy(vcap->card, cx->card_name, sizeof(vcap->card)); - strlcpy(vcap->bus_info, pci_name(cx->dev), sizeof(vcap->bus_info)); - vcap->version = CX18_DRIVER_VERSION; /* version */ - vcap->capabilities = cx->v4l2_cap; /* capabilities */ +static int cx18_enum_fmt_vid_cap(struct file *file, void *fh, + struct v4l2_fmtdesc *fmt) +{ + static struct v4l2_fmtdesc formats[] = { + { 0, V4L2_BUF_TYPE_VIDEO_CAPTURE, 0, + "HM12 (YUV 4:1:1)", V4L2_PIX_FMT_HM12, { 0, 0, 0, 0 } + }, + { 1, V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_FMT_FLAG_COMPRESSED, + "MPEG", V4L2_PIX_FMT_MPEG, { 0, 0, 0, 0 } + } + }; - /* reserved.. must set to 0! */ - vcap->reserved[0] = vcap->reserved[1] = - vcap->reserved[2] = vcap->reserved[3] = 0; - break; - } + if (fmt->index > 1) + return -EINVAL; + *fmt = formats[fmt->index]; + return 0; +} - case VIDIOC_ENUMAUDIO:{ - struct v4l2_audio *vin = arg; +static int cx18_g_input(struct file *file, void *fh, unsigned int *i) +{ + struct cx18 *cx = ((struct cx18_open_id *)fh)->cx; - return cx18_get_audio_input(cx, vin->index, vin); - } + *i = cx->active_input; + return 0; +} - case VIDIOC_G_AUDIO:{ - struct v4l2_audio *vin = arg; +int cx18_s_input(struct file *file, void *fh, unsigned int inp) +{ + struct cx18_open_id *id = fh; + struct cx18 *cx = id->cx; + int ret; - vin->index = cx->audio_input; - return cx18_get_audio_input(cx, vin->index, vin); - } + ret = v4l2_prio_check(&cx->prio, &id->prio); + if (ret) + return ret; - case VIDIOC_S_AUDIO:{ - struct v4l2_audio *vout = arg; + if (inp < 0 || inp >= cx->nof_inputs) + return -EINVAL; - if (vout->index >= cx->nof_audio_inputs) - return -EINVAL; - cx->audio_input = vout->index; - cx18_audio_set_io(cx); - break; + if (inp == cx->active_input) { + CX18_DEBUG_INFO("Input unchanged\n"); + return 0; } - case VIDIOC_ENUMINPUT:{ - struct v4l2_input *vin = arg; - - /* set it to defaults from our table */ - return cx18_get_input(cx, vin->index, vin); - } + CX18_DEBUG_INFO("Changing input from %d to %d\n", + cx->active_input, inp); - case VIDIOC_TRY_FMT: - case VIDIOC_S_FMT: { - struct v4l2_format *fmt = arg; + cx->active_input = inp; + /* Set the audio input to whatever is appropriate for the input type. */ + cx->audio_input = cx->card->video_inputs[inp].audio_index; - return cx18_try_or_set_fmt(cx, id->type, fmt, cmd == VIDIOC_S_FMT); - } + /* prevent others from messing with the streams until + we're finished changing inputs. */ + cx18_mute(cx); + cx18_video_set_io(cx); + cx18_audio_set_io(cx); + cx18_unmute(cx); + return 0; +} - case VIDIOC_G_FMT: { - struct v4l2_format *fmt = arg; - int type = fmt->type; +static int cx18_g_frequency(struct file *file, void *fh, + struct v4l2_frequency *vf) +{ + struct cx18 *cx = ((struct cx18_open_id *)fh)->cx; - memset(fmt, 0, sizeof(*fmt)); - fmt->type = type; - return cx18_get_fmt(cx, id->type, fmt); - } + if (vf->tuner != 0) + return -EINVAL; - case VIDIOC_CROPCAP: { - struct v4l2_cropcap *cropcap = arg; - - if (cropcap->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - cropcap->bounds.top = cropcap->bounds.left = 0; - cropcap->bounds.width = 720; - cropcap->bounds.height = cx->is_50hz ? 576 : 480; - cropcap->pixelaspect.numerator = cx->is_50hz ? 59 : 10; - cropcap->pixelaspect.denominator = cx->is_50hz ? 54 : 11; - cropcap->defrect = cropcap->bounds; - return 0; - } + cx18_call_i2c_clients(cx, VIDIOC_G_FREQUENCY, vf); + return 0; +} - case VIDIOC_S_CROP: { - struct v4l2_crop *crop = arg; +int cx18_s_frequency(struct file *file, void *fh, struct v4l2_frequency *vf) +{ + struct cx18_open_id *id = fh; + struct cx18 *cx = id->cx; + int ret; - if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - return cx18_av_cmd(cx, VIDIOC_S_CROP, arg); - } + ret = v4l2_prio_check(&cx->prio, &id->prio); + if (ret) + return ret; - case VIDIOC_G_CROP: { - struct v4l2_crop *crop = arg; + if (vf->tuner != 0) + return -EINVAL; - if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - return cx18_av_cmd(cx, VIDIOC_G_CROP, arg); - } + cx18_mute(cx); + CX18_DEBUG_INFO("v4l2 ioctl: set frequency %d\n", vf->frequency); + cx18_call_i2c_clients(cx, VIDIOC_S_FREQUENCY, vf); + cx18_unmute(cx); + return 0; +} - case VIDIOC_ENUM_FMT: { - static struct v4l2_fmtdesc formats[] = { - { 0, 0, 0, - "HM12 (YUV 4:1:1)", V4L2_PIX_FMT_HM12, - { 0, 0, 0, 0 } - }, - { 1, 0, V4L2_FMT_FLAG_COMPRESSED, - "MPEG", V4L2_PIX_FMT_MPEG, - { 0, 0, 0, 0 } - } - }; - struct v4l2_fmtdesc *fmt = arg; - enum v4l2_buf_type type = fmt->type; - - switch (type) { - case V4L2_BUF_TYPE_VIDEO_CAPTURE: - break; - default: - return -EINVAL; - } - if (fmt->index > 1) - return -EINVAL; - *fmt = formats[fmt->index]; - fmt->type = type; - return 0; - } +static int cx18_g_std(struct file *file, void *fh, v4l2_std_id *std) +{ + struct cx18 *cx = ((struct cx18_open_id *)fh)->cx; - case VIDIOC_G_INPUT:{ - *(int *)arg = cx->active_input; - break; - } + *std = cx->std; + return 0; +} - case VIDIOC_S_INPUT:{ - int inp = *(int *)arg; +int cx18_s_std(struct file *file, void *fh, v4l2_std_id *std) +{ + struct cx18_open_id *id = fh; + struct cx18 *cx = id->cx; + int ret; - if (inp < 0 || inp >= cx->nof_inputs) - return -EINVAL; + ret = v4l2_prio_check(&cx->prio, &id->prio); + if (ret) + return ret; - if (inp == cx->active_input) { - CX18_DEBUG_INFO("Input unchanged\n"); - break; - } - CX18_DEBUG_INFO("Changing input from %d to %d\n", - cx->active_input, inp); + if ((*std & V4L2_STD_ALL) == 0) + return -EINVAL; - cx->active_input = inp; - /* Set the audio input to whatever is appropriate for the - input type. */ - cx->audio_input = cx->card->video_inputs[inp].audio_index; + if (*std == cx->std) + return 0; - /* prevent others from messing with the streams until - we're finished changing inputs. */ - cx18_mute(cx); - cx18_video_set_io(cx); - cx18_audio_set_io(cx); - cx18_unmute(cx); - break; + if (test_bit(CX18_F_I_RADIO_USER, &cx->i_flags) || + atomic_read(&cx->ana_capturing) > 0) { + /* Switching standard would turn off the radio or mess + with already running streams, prevent that by + returning EBUSY. */ + return -EBUSY; } - case VIDIOC_G_FREQUENCY:{ - struct v4l2_frequency *vf = arg; + cx->std = *std; + cx->is_60hz = (*std & V4L2_STD_525_60) ? 1 : 0; + cx->params.is_50hz = cx->is_50hz = !cx->is_60hz; + cx->params.width = 720; + cx->params.height = cx->is_50hz ? 576 : 480; + cx->vbi.count = cx->is_50hz ? 18 : 12; + cx->vbi.start[0] = cx->is_50hz ? 6 : 10; + cx->vbi.start[1] = cx->is_50hz ? 318 : 273; + cx->vbi.sliced_decoder_line_size = cx->is_60hz ? 272 : 284; + CX18_DEBUG_INFO("Switching standard to %llx.\n", + (unsigned long long) cx->std); + + /* Tuner */ + cx18_call_i2c_clients(cx, VIDIOC_S_STD, &cx->std); + return 0; +} - if (vf->tuner != 0) - return -EINVAL; - cx18_call_i2c_clients(cx, cmd, arg); - break; - } +static int cx18_s_tuner(struct file *file, void *fh, struct v4l2_tuner *vt) +{ + struct cx18_open_id *id = fh; + struct cx18 *cx = id->cx; + int ret; - case VIDIOC_S_FREQUENCY:{ - struct v4l2_frequency vf = *(struct v4l2_frequency *)arg; + ret = v4l2_prio_check(&cx->prio, &id->prio); + if (ret) + return ret; - if (vf.tuner != 0) - return -EINVAL; + if (vt->index != 0) + return -EINVAL; - cx18_mute(cx); - CX18_DEBUG_INFO("v4l2 ioctl: set frequency %d\n", vf.frequency); - cx18_call_i2c_clients(cx, cmd, &vf); - cx18_unmute(cx); - break; - } + /* Setting tuner can only set audio mode */ + cx18_call_i2c_clients(cx, VIDIOC_S_TUNER, vt); - case VIDIOC_ENUMSTD:{ - struct v4l2_standard *vs = arg; - int idx = vs->index; + return 0; +} - if (idx < 0 || idx >= ARRAY_SIZE(enum_stds)) - return -EINVAL; +static int cx18_g_tuner(struct file *file, void *fh, struct v4l2_tuner *vt) +{ + struct cx18 *cx = ((struct cx18_open_id *)fh)->cx; - *vs = (enum_stds[idx].std & V4L2_STD_525_60) ? - cx18_std_60hz : cx18_std_50hz; - vs->index = idx; - vs->id = enum_stds[idx].std; - strlcpy(vs->name, enum_stds[idx].name, sizeof(vs->name)); - break; - } + if (vt->index != 0) + return -EINVAL; - case VIDIOC_G_STD:{ - *(v4l2_std_id *) arg = cx->std; - break; + cx18_call_i2c_clients(cx, VIDIOC_G_TUNER, vt); + + if (test_bit(CX18_F_I_RADIO_USER, &cx->i_flags)) { + strlcpy(vt->name, "cx18 Radio Tuner", sizeof(vt->name)); + vt->type = V4L2_TUNER_RADIO; + } else { + strlcpy(vt->name, "cx18 TV Tuner", sizeof(vt->name)); + vt->type = V4L2_TUNER_ANALOG_TV; } - case VIDIOC_S_STD: { - v4l2_std_id std = *(v4l2_std_id *) arg; + return 0; +} - if ((std & V4L2_STD_ALL) == 0) - return -EINVAL; +static int cx18_g_sliced_vbi_cap(struct file *file, void *fh, + struct v4l2_sliced_vbi_cap *cap) +{ + return -EINVAL; +} - if (std == cx->std) - break; +static int cx18_g_enc_index(struct file *file, void *fh, + struct v4l2_enc_idx *idx) +{ + return -EINVAL; +} - if (test_bit(CX18_F_I_RADIO_USER, &cx->i_flags) || - atomic_read(&cx->ana_capturing) > 0) { - /* Switching standard would turn off the radio or mess - with already running streams, prevent that by - returning EBUSY. */ - return -EBUSY; - } +static int cx18_encoder_cmd(struct file *file, void *fh, + struct v4l2_encoder_cmd *enc) +{ + struct cx18_open_id *id = fh; + struct cx18 *cx = id->cx; - cx->std = std; - cx->is_60hz = (std & V4L2_STD_525_60) ? 1 : 0; - cx->params.is_50hz = cx->is_50hz = !cx->is_60hz; - cx->params.width = 720; - cx->params.height = cx->is_50hz ? 576 : 480; - cx->vbi.count = cx->is_50hz ? 18 : 12; - cx->vbi.start[0] = cx->is_50hz ? 6 : 10; - cx->vbi.start[1] = cx->is_50hz ? 318 : 273; - cx->vbi.sliced_decoder_line_size = cx->is_60hz ? 272 : 284; - CX18_DEBUG_INFO("Switching standard to %llx.\n", (unsigned long long)cx->std); - - /* Tuner */ - cx18_call_i2c_clients(cx, VIDIOC_S_STD, &cx->std); + switch (enc->cmd) { + case V4L2_ENC_CMD_START: + CX18_DEBUG_IOCTL("V4L2_ENC_CMD_START\n"); + enc->flags = 0; + return cx18_start_capture(id); + + case V4L2_ENC_CMD_STOP: + CX18_DEBUG_IOCTL("V4L2_ENC_CMD_STOP\n"); + enc->flags &= V4L2_ENC_CMD_STOP_AT_GOP_END; + cx18_stop_capture(id, + enc->flags & V4L2_ENC_CMD_STOP_AT_GOP_END); break; - } - - case VIDIOC_S_TUNER: { /* Setting tuner can only set audio mode */ - struct v4l2_tuner *vt = arg; - if (vt->index != 0) - return -EINVAL; - - cx18_call_i2c_clients(cx, VIDIOC_S_TUNER, vt); + case V4L2_ENC_CMD_PAUSE: + CX18_DEBUG_IOCTL("V4L2_ENC_CMD_PAUSE\n"); + enc->flags = 0; + if (!atomic_read(&cx->ana_capturing)) + return -EPERM; + if (test_and_set_bit(CX18_F_I_ENC_PAUSED, &cx->i_flags)) + return 0; + cx18_mute(cx); + cx18_vapi(cx, CX18_CPU_CAPTURE_PAUSE, 1, cx18_find_handle(cx)); break; - } - - case VIDIOC_G_TUNER: { - struct v4l2_tuner *vt = arg; - - if (vt->index != 0) - return -EINVAL; - - memset(vt, 0, sizeof(*vt)); - cx18_call_i2c_clients(cx, VIDIOC_G_TUNER, vt); - if (test_bit(CX18_F_I_RADIO_USER, &cx->i_flags)) { - strlcpy(vt->name, "cx18 Radio Tuner", sizeof(vt->name)); - vt->type = V4L2_TUNER_RADIO; - } else { - strlcpy(vt->name, "cx18 TV Tuner", sizeof(vt->name)); - vt->type = V4L2_TUNER_ANALOG_TV; - } + case V4L2_ENC_CMD_RESUME: + CX18_DEBUG_IOCTL("V4L2_ENC_CMD_RESUME\n"); + enc->flags = 0; + if (!atomic_read(&cx->ana_capturing)) + return -EPERM; + if (!test_and_clear_bit(CX18_F_I_ENC_PAUSED, &cx->i_flags)) + return 0; + cx18_vapi(cx, CX18_CPU_CAPTURE_RESUME, 1, cx18_find_handle(cx)); + cx18_unmute(cx); break; - } - case VIDIOC_G_SLICED_VBI_CAP: { - struct v4l2_sliced_vbi_cap *cap = arg; - int set = cx->is_50hz ? V4L2_SLICED_VBI_625 : V4L2_SLICED_VBI_525; - int f, l; - enum v4l2_buf_type type = cap->type; - - memset(cap, 0, sizeof(*cap)); - cap->type = type; - if (type == V4L2_BUF_TYPE_SLICED_VBI_CAPTURE) { - for (f = 0; f < 2; f++) { - for (l = 0; l < 24; l++) { - if (valid_service_line(f, l, cx->is_50hz)) - cap->service_lines[f][l] = set; - } - } - return 0; - } + default: + CX18_DEBUG_IOCTL("Unknown cmd %d\n", enc->cmd); return -EINVAL; } + return 0; +} - case VIDIOC_ENCODER_CMD: - case VIDIOC_TRY_ENCODER_CMD: { - struct v4l2_encoder_cmd *enc = arg; - int try = cmd == VIDIOC_TRY_ENCODER_CMD; - - memset(&enc->raw, 0, sizeof(enc->raw)); - switch (enc->cmd) { - case V4L2_ENC_CMD_START: - enc->flags = 0; - if (try) - return 0; - return cx18_start_capture(id); - - case V4L2_ENC_CMD_STOP: - enc->flags &= V4L2_ENC_CMD_STOP_AT_GOP_END; - if (try) - return 0; - cx18_stop_capture(id, enc->flags & V4L2_ENC_CMD_STOP_AT_GOP_END); - return 0; +static int cx18_try_encoder_cmd(struct file *file, void *fh, + struct v4l2_encoder_cmd *enc) +{ + struct cx18 *cx = ((struct cx18_open_id *)fh)->cx; - case V4L2_ENC_CMD_PAUSE: - enc->flags = 0; - if (try) - return 0; - if (!atomic_read(&cx->ana_capturing)) - return -EPERM; - if (test_and_set_bit(CX18_F_I_ENC_PAUSED, &cx->i_flags)) - return 0; - cx18_mute(cx); - cx18_vapi(cx, CX18_CPU_CAPTURE_PAUSE, 1, cx18_find_handle(cx)); - break; - - case V4L2_ENC_CMD_RESUME: - enc->flags = 0; - if (try) - return 0; - if (!atomic_read(&cx->ana_capturing)) - return -EPERM; - if (!test_and_clear_bit(CX18_F_I_ENC_PAUSED, &cx->i_flags)) - return 0; - cx18_vapi(cx, CX18_CPU_CAPTURE_RESUME, 1, cx18_find_handle(cx)); - cx18_unmute(cx); - break; - default: - return -EINVAL; - } + switch (enc->cmd) { + case V4L2_ENC_CMD_START: + CX18_DEBUG_IOCTL("V4L2_ENC_CMD_START\n"); + enc->flags = 0; break; - } - case VIDIOC_LOG_STATUS: - { - struct v4l2_input vidin; - struct v4l2_audio audin; - int i; + case V4L2_ENC_CMD_STOP: + CX18_DEBUG_IOCTL("V4L2_ENC_CMD_STOP\n"); + enc->flags &= V4L2_ENC_CMD_STOP_AT_GOP_END; + break; - CX18_INFO("================= START STATUS CARD #%d =================\n", cx->num); - if (cx->hw_flags & CX18_HW_TVEEPROM) { - struct tveeprom tv; + case V4L2_ENC_CMD_PAUSE: + CX18_DEBUG_IOCTL("V4L2_ENC_CMD_PAUSE\n"); + enc->flags = 0; + break; - cx18_read_eeprom(cx, &tv); - } - cx18_call_i2c_clients(cx, VIDIOC_LOG_STATUS, NULL); - cx18_get_input(cx, cx->active_input, &vidin); - cx18_get_audio_input(cx, cx->audio_input, &audin); - CX18_INFO("Video Input: %s\n", vidin.name); - CX18_INFO("Audio Input: %s\n", audin.name); - CX18_INFO("Tuner: %s\n", - test_bit(CX18_F_I_RADIO_USER, &cx->i_flags) ? - "Radio" : "TV"); - cx2341x_log_status(&cx->params, cx->name); - CX18_INFO("Status flags: 0x%08lx\n", cx->i_flags); - for (i = 0; i < CX18_MAX_STREAMS; i++) { - struct cx18_stream *s = &cx->streams[i]; - - if (s->v4l2dev == NULL || s->buffers == 0) - continue; - CX18_INFO("Stream %s: status 0x%04lx, %d%% of %d KiB (%d buffers) in use\n", - s->name, s->s_flags, - (s->buffers - s->q_free.buffers) * 100 / s->buffers, - (s->buffers * s->buf_size) / 1024, s->buffers); - } - CX18_INFO("Read MPEG/VBI: %lld/%lld bytes\n", - (long long)cx->mpg_data_received, - (long long)cx->vbi_data_inserted); - CX18_INFO("================== END STATUS CARD #%d ==================\n", cx->num); + case V4L2_ENC_CMD_RESUME: + CX18_DEBUG_IOCTL("V4L2_ENC_CMD_RESUME\n"); + enc->flags = 0; break; - } default: + CX18_DEBUG_IOCTL("Unknown cmd %d\n", enc->cmd); return -EINVAL; } return 0; } -static int cx18_v4l2_do_ioctl(struct inode *inode, struct file *filp, - unsigned int cmd, void *arg) +static int cx18_log_status(struct file *file, void *fh) { - struct cx18_open_id *id = (struct cx18_open_id *)filp->private_data; - struct cx18 *cx = id->cx; - int ret; + struct cx18 *cx = ((struct cx18_open_id *)fh)->cx; + struct v4l2_input vidin; + struct v4l2_audio audin; + int i; + + CX18_INFO("================= START STATUS CARD #%d =================\n", cx->num); + if (cx->hw_flags & CX18_HW_TVEEPROM) { + struct tveeprom tv; + + cx18_read_eeprom(cx, &tv); + } + cx18_call_i2c_clients(cx, VIDIOC_LOG_STATUS, NULL); + cx18_get_input(cx, cx->active_input, &vidin); + cx18_get_audio_input(cx, cx->audio_input, &audin); + CX18_INFO("Video Input: %s\n", vidin.name); + CX18_INFO("Audio Input: %s\n", audin.name); + mutex_lock(&cx->gpio_lock); + CX18_INFO("GPIO: direction 0x%08x, value 0x%08x\n", + cx->gpio_dir, cx->gpio_val); + mutex_unlock(&cx->gpio_lock); + CX18_INFO("Tuner: %s\n", + test_bit(CX18_F_I_RADIO_USER, &cx->i_flags) ? "Radio" : "TV"); + cx2341x_log_status(&cx->params, cx->name); + CX18_INFO("Status flags: 0x%08lx\n", cx->i_flags); + for (i = 0; i < CX18_MAX_STREAMS; i++) { + struct cx18_stream *s = &cx->streams[i]; + + if (s->v4l2dev == NULL || s->buffers == 0) + continue; + CX18_INFO("Stream %s: status 0x%04lx, %d%% of %d KiB (%d buffers) in use\n", + s->name, s->s_flags, + (s->buffers - s->q_free.buffers) * 100 / s->buffers, + (s->buffers * s->buf_size) / 1024, s->buffers); + } + CX18_INFO("Read MPEG/VBI: %lld/%lld bytes\n", + (long long)cx->mpg_data_received, + (long long)cx->vbi_data_inserted); + CX18_INFO("================== END STATUS CARD #%d ==================\n", cx->num); + return 0; +} + +static int cx18_default(struct file *file, void *fh, int cmd, void *arg) +{ + struct cx18 *cx = ((struct cx18_open_id *)fh)->cx; - /* check priority */ switch (cmd) { - case VIDIOC_S_CTRL: - case VIDIOC_S_STD: - case VIDIOC_S_INPUT: - case VIDIOC_S_TUNER: - case VIDIOC_S_FREQUENCY: - case VIDIOC_S_FMT: - case VIDIOC_S_CROP: - case VIDIOC_S_EXT_CTRLS: - ret = v4l2_prio_check(&cx->prio, &id->prio); - if (ret) - return ret; + case VIDIOC_INT_S_AUDIO_ROUTING: { + struct v4l2_routing *route = arg; + + CX18_DEBUG_IOCTL("VIDIOC_INT_S_AUDIO_ROUTING(%d, %d)\n", + route->input, route->output); + cx18_audio_set_route(cx, route); + break; } - switch (cmd) { - case VIDIOC_DBG_G_REGISTER: - case VIDIOC_DBG_S_REGISTER: - case VIDIOC_G_CHIP_IDENT: - case VIDIOC_INT_S_AUDIO_ROUTING: - case VIDIOC_INT_RESET: - if (cx18_debug & CX18_DBGFLG_IOCTL) { - printk(KERN_INFO "cx18%d ioctl: ", cx->num); - v4l_printk_ioctl(cmd); - } - return cx18_debug_ioctls(filp, cmd, arg); - - case VIDIOC_G_PRIORITY: - case VIDIOC_S_PRIORITY: - case VIDIOC_QUERYCAP: - case VIDIOC_ENUMINPUT: - case VIDIOC_G_INPUT: - case VIDIOC_S_INPUT: - case VIDIOC_G_FMT: - case VIDIOC_S_FMT: - case VIDIOC_TRY_FMT: - case VIDIOC_ENUM_FMT: - case VIDIOC_CROPCAP: - case VIDIOC_G_CROP: - case VIDIOC_S_CROP: - case VIDIOC_G_FREQUENCY: - case VIDIOC_S_FREQUENCY: - case VIDIOC_ENUMSTD: - case VIDIOC_G_STD: - case VIDIOC_S_STD: - case VIDIOC_S_TUNER: - case VIDIOC_G_TUNER: - case VIDIOC_ENUMAUDIO: - case VIDIOC_S_AUDIO: - case VIDIOC_G_AUDIO: - case VIDIOC_G_SLICED_VBI_CAP: - case VIDIOC_LOG_STATUS: - case VIDIOC_G_ENC_INDEX: - case VIDIOC_ENCODER_CMD: - case VIDIOC_TRY_ENCODER_CMD: - if (cx18_debug & CX18_DBGFLG_IOCTL) { - printk(KERN_INFO "cx18%d ioctl: ", cx->num); - v4l_printk_ioctl(cmd); - } - return cx18_v4l2_ioctls(cx, filp, cmd, arg); - - case VIDIOC_QUERYMENU: - case VIDIOC_QUERYCTRL: - case VIDIOC_S_CTRL: - case VIDIOC_G_CTRL: - case VIDIOC_S_EXT_CTRLS: - case VIDIOC_G_EXT_CTRLS: - case VIDIOC_TRY_EXT_CTRLS: - if (cx18_debug & CX18_DBGFLG_IOCTL) { - printk(KERN_INFO "cx18%d ioctl: ", cx->num); - v4l_printk_ioctl(cmd); - } - return cx18_control_ioctls(cx, cmd, arg); + case VIDIOC_INT_RESET: { + u32 val = *(u32 *)arg; + + if ((val == 0) || (val & 0x01)) + cx18_reset_ir_gpio(&cx->i2c_algo_cb_data[0]); + break; + } - case 0x00005401: /* Handle isatty() calls */ - return -EINVAL; default: - return v4l_compat_translate_ioctl(inode, filp, cmd, arg, - cx18_v4l2_do_ioctl); + return -EINVAL; } return 0; } @@ -840,12 +772,65 @@ static int cx18_v4l2_do_ioctl(struct inode *inode, struct file *filp, int cx18_v4l2_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg) { + struct video_device *vfd = video_devdata(filp); struct cx18_open_id *id = (struct cx18_open_id *)filp->private_data; struct cx18 *cx = id->cx; int res; mutex_lock(&cx->serialize_lock); - res = video_usercopy(inode, filp, cmd, arg, cx18_v4l2_do_ioctl); + + if (cx18_debug & CX18_DBGFLG_IOCTL) + vfd->debug = V4L2_DEBUG_IOCTL | V4L2_DEBUG_IOCTL_ARG; + res = video_ioctl2(inode, filp, cmd, arg); + vfd->debug = 0; mutex_unlock(&cx->serialize_lock); return res; } + +void cx18_set_funcs(struct video_device *vdev) +{ + vdev->vidioc_querycap = cx18_querycap; + vdev->vidioc_g_priority = cx18_g_priority; + vdev->vidioc_s_priority = cx18_s_priority; + vdev->vidioc_s_audio = cx18_s_audio; + vdev->vidioc_g_audio = cx18_g_audio; + vdev->vidioc_enumaudio = cx18_enumaudio; + vdev->vidioc_enum_input = cx18_enum_input; + vdev->vidioc_cropcap = cx18_cropcap; + vdev->vidioc_s_crop = cx18_s_crop; + vdev->vidioc_g_crop = cx18_g_crop; + vdev->vidioc_g_input = cx18_g_input; + vdev->vidioc_s_input = cx18_s_input; + vdev->vidioc_g_frequency = cx18_g_frequency; + vdev->vidioc_s_frequency = cx18_s_frequency; + vdev->vidioc_s_tuner = cx18_s_tuner; + vdev->vidioc_g_tuner = cx18_g_tuner; + vdev->vidioc_g_enc_index = cx18_g_enc_index; + vdev->vidioc_g_std = cx18_g_std; + vdev->vidioc_s_std = cx18_s_std; + vdev->vidioc_log_status = cx18_log_status; + vdev->vidioc_enum_fmt_vid_cap = cx18_enum_fmt_vid_cap; + vdev->vidioc_encoder_cmd = cx18_encoder_cmd; + vdev->vidioc_try_encoder_cmd = cx18_try_encoder_cmd; + vdev->vidioc_g_fmt_vid_cap = cx18_g_fmt_vid_cap; + vdev->vidioc_g_fmt_vbi_cap = cx18_g_fmt_vbi_cap; + vdev->vidioc_g_fmt_sliced_vbi_cap = cx18_g_fmt_sliced_vbi_cap; + vdev->vidioc_s_fmt_vid_cap = cx18_s_fmt_vid_cap; + vdev->vidioc_s_fmt_vbi_cap = cx18_s_fmt_vbi_cap; + vdev->vidioc_s_fmt_sliced_vbi_cap = cx18_s_fmt_sliced_vbi_cap; + vdev->vidioc_try_fmt_vid_cap = cx18_try_fmt_vid_cap; + vdev->vidioc_try_fmt_vbi_cap = cx18_try_fmt_vbi_cap; + vdev->vidioc_try_fmt_sliced_vbi_cap = cx18_try_fmt_sliced_vbi_cap; + vdev->vidioc_g_sliced_vbi_cap = cx18_g_sliced_vbi_cap; + vdev->vidioc_g_chip_ident = cx18_g_chip_ident; +#ifdef CONFIG_VIDEO_ADV_DEBUG + vdev->vidioc_g_register = cx18_g_register; + vdev->vidioc_s_register = cx18_s_register; +#endif + vdev->vidioc_default = cx18_default; + vdev->vidioc_queryctrl = cx18_queryctrl; + vdev->vidioc_querymenu = cx18_querymenu; + vdev->vidioc_g_ext_ctrls = cx18_g_ext_ctrls; + vdev->vidioc_s_ext_ctrls = cx18_s_ext_ctrls; + vdev->vidioc_try_ext_ctrls = cx18_try_ext_ctrls; +} diff --git a/drivers/media/video/cx18/cx18-ioctl.h b/drivers/media/video/cx18/cx18-ioctl.h index 9f4c7eb2897f..2222f679d86d 100644 --- a/drivers/media/video/cx18/cx18-ioctl.h +++ b/drivers/media/video/cx18/cx18-ioctl.h @@ -24,7 +24,9 @@ u16 cx18_service2vbi(int type); void cx18_expand_service_set(struct v4l2_sliced_vbi_format *fmt, int is_pal); u16 cx18_get_service_set(struct v4l2_sliced_vbi_format *fmt); +void cx18_set_funcs(struct video_device *vdev); +int cx18_s_std(struct file *file, void *fh, v4l2_std_id *std); +int cx18_s_frequency(struct file *file, void *fh, struct v4l2_frequency *vf); +int cx18_s_input(struct file *file, void *fh, unsigned int inp); int cx18_v4l2_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg); -int cx18_v4l2_ioctls(struct cx18 *cx, struct file *filp, unsigned cmd, - void *arg); diff --git a/drivers/media/video/cx18/cx18-mailbox.c b/drivers/media/video/cx18/cx18-mailbox.c index 2a5ccef9185b..93177514e846 100644 --- a/drivers/media/video/cx18/cx18-mailbox.c +++ b/drivers/media/video/cx18/cx18-mailbox.c @@ -81,6 +81,7 @@ static const struct cx18_api_info api_info[] = { API_ENTRY(CPU, CX18_CPU_GET_ENC_PTS, 0), API_ENTRY(CPU, CX18_CPU_DE_SET_MDL_ACK, 0), API_ENTRY(CPU, CX18_CPU_DE_SET_MDL, API_FAST), + API_ENTRY(CPU, CX18_APU_RESETAI, API_FAST), API_ENTRY(0, 0, 0), }; diff --git a/drivers/media/video/cx18/cx18-streams.c b/drivers/media/video/cx18/cx18-streams.c index 1b921a336092..1728b1d832a9 100644 --- a/drivers/media/video/cx18/cx18-streams.c +++ b/drivers/media/video/cx18/cx18-streams.c @@ -39,6 +39,7 @@ static struct file_operations cx18_v4l2_enc_fops = { .owner = THIS_MODULE, .read = cx18_v4l2_read, .open = cx18_v4l2_open, + /* FIXME change to video_ioctl2 if serialization lock can be removed */ .ioctl = cx18_v4l2_ioctl, .compat_ioctl = v4l_compat_ioctl32, .release = cx18_v4l2_close, @@ -189,14 +190,15 @@ static int cx18_prep_dev(struct cx18 *cx, int type) s->v4l2dev->type = VID_TYPE_CAPTURE | VID_TYPE_TUNER | VID_TYPE_TELETEXT | VID_TYPE_CLIPPING | VID_TYPE_SCALES | VID_TYPE_MPEG_ENCODER; - snprintf(s->v4l2dev->name, sizeof(s->v4l2dev->name), "cx18%d %s", - cx->num, s->name); + snprintf(s->v4l2dev->name, sizeof(s->v4l2dev->name), "cx18-%d", + cx->num); s->v4l2dev->minor = minor; s->v4l2dev->dev = &cx->dev->dev; s->v4l2dev->fops = cx18_stream_info[type].fops; s->v4l2dev->release = video_device_release; - + s->v4l2dev->tvnorms = V4L2_STD_ALL; + cx18_set_funcs(s->v4l2dev); return 0; } @@ -309,8 +311,10 @@ void cx18_streams_cleanup(struct cx18 *cx, int unregister) /* Teardown all streams */ for (type = 0; type < CX18_MAX_STREAMS; type++) { - if (cx->streams[type].dvb.enabled) + if (cx->streams[type].dvb.enabled) { cx18_dvb_unregister(&cx->streams[type]); + cx->streams[type].dvb.enabled = false; + } vdev = cx->streams[type].v4l2dev; diff --git a/drivers/media/video/cx18/cx23418.h b/drivers/media/video/cx18/cx23418.h index 33f78da9dba8..e7ed053059a8 100644 --- a/drivers/media/video/cx18/cx23418.h +++ b/drivers/media/video/cx18/cx23418.h @@ -52,6 +52,11 @@ #define EPU_CMD_MASK_DEBUG (EPU_CMD_MASK | 0x000000) #define EPU_CMD_MASK_DE (EPU_CMD_MASK | 0x040000) +#define APU_CMD_MASK 0x10000000 +#define APU_CMD_MASK_ACK (APU_CMD_MASK | 0x80000000) + +#define CX18_APU_RESETAI (APU_CMD_MASK | 0x05) + /* Description: This command indicates that a Memory Descriptor List has been filled with the requested channel type IN[0] - Task handle. Handle of the task diff --git a/drivers/media/video/cx2341x.c b/drivers/media/video/cx2341x.c index c592899a2317..22847a0444f5 100644 --- a/drivers/media/video/cx2341x.c +++ b/drivers/media/video/cx2341x.c @@ -77,10 +77,65 @@ const u32 cx2341x_mpeg_ctrls[] = { }; EXPORT_SYMBOL(cx2341x_mpeg_ctrls); +static const struct cx2341x_mpeg_params default_params = { + /* misc */ + .capabilities = 0, + .port = CX2341X_PORT_MEMORY, + .width = 720, + .height = 480, + .is_50hz = 0, + + /* stream */ + .stream_type = V4L2_MPEG_STREAM_TYPE_MPEG2_PS, + .stream_vbi_fmt = V4L2_MPEG_STREAM_VBI_FMT_NONE, + .stream_insert_nav_packets = 0, + + /* audio */ + .audio_sampling_freq = V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000, + .audio_encoding = V4L2_MPEG_AUDIO_ENCODING_LAYER_2, + .audio_l2_bitrate = V4L2_MPEG_AUDIO_L2_BITRATE_224K, + .audio_mode = V4L2_MPEG_AUDIO_MODE_STEREO, + .audio_mode_extension = V4L2_MPEG_AUDIO_MODE_EXTENSION_BOUND_4, + .audio_emphasis = V4L2_MPEG_AUDIO_EMPHASIS_NONE, + .audio_crc = V4L2_MPEG_AUDIO_CRC_NONE, + .audio_mute = 0, + + /* video */ + .video_encoding = V4L2_MPEG_VIDEO_ENCODING_MPEG_2, + .video_aspect = V4L2_MPEG_VIDEO_ASPECT_4x3, + .video_b_frames = 2, + .video_gop_size = 12, + .video_gop_closure = 1, + .video_bitrate_mode = V4L2_MPEG_VIDEO_BITRATE_MODE_VBR, + .video_bitrate = 6000000, + .video_bitrate_peak = 8000000, + .video_temporal_decimation = 0, + .video_mute = 0, + .video_mute_yuv = 0x008080, /* YCbCr value for black */ + + /* encoding filters */ + .video_spatial_filter_mode = + V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_MANUAL, + .video_spatial_filter = 0, + .video_luma_spatial_filter_type = + V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_1D_HOR, + .video_chroma_spatial_filter_type = + V4L2_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE_1D_HOR, + .video_temporal_filter_mode = + V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_MANUAL, + .video_temporal_filter = 8, + .video_median_filter_type = + V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF, + .video_luma_median_filter_top = 255, + .video_luma_median_filter_bottom = 0, + .video_chroma_median_filter_top = 255, + .video_chroma_median_filter_bottom = 0, +}; + /* Map the control ID to the correct field in the cx2341x_mpeg_params struct. Return -EINVAL if the ID is unknown, else return 0. */ -static int cx2341x_get_ctrl(struct cx2341x_mpeg_params *params, +static int cx2341x_get_ctrl(const struct cx2341x_mpeg_params *params, struct v4l2_ext_control *ctrl) { switch (ctrl->id) { @@ -420,7 +475,7 @@ static int cx2341x_ctrl_query_fill(struct v4l2_queryctrl *qctrl, return 0; } -int cx2341x_ctrl_query(struct cx2341x_mpeg_params *params, +int cx2341x_ctrl_query(const struct cx2341x_mpeg_params *params, struct v4l2_queryctrl *qctrl) { int err; @@ -430,13 +485,13 @@ int cx2341x_ctrl_query(struct cx2341x_mpeg_params *params, return v4l2_ctrl_query_fill(qctrl, V4L2_MPEG_AUDIO_ENCODING_LAYER_2, V4L2_MPEG_AUDIO_ENCODING_LAYER_2, 1, - V4L2_MPEG_AUDIO_ENCODING_LAYER_2); + default_params.audio_encoding); case V4L2_CID_MPEG_AUDIO_L2_BITRATE: return v4l2_ctrl_query_fill(qctrl, V4L2_MPEG_AUDIO_L2_BITRATE_192K, V4L2_MPEG_AUDIO_L2_BITRATE_384K, 1, - V4L2_MPEG_AUDIO_L2_BITRATE_224K); + default_params.audio_l2_bitrate); case V4L2_CID_MPEG_AUDIO_L1_BITRATE: case V4L2_CID_MPEG_AUDIO_L3_BITRATE: @@ -479,17 +534,22 @@ int cx2341x_ctrl_query(struct cx2341x_mpeg_params *params, return cx2341x_ctrl_query_fill(qctrl, V4L2_MPEG_STREAM_VBI_FMT_NONE, V4L2_MPEG_STREAM_VBI_FMT_NONE, 1, - V4L2_MPEG_STREAM_VBI_FMT_NONE); + default_params.stream_vbi_fmt); + + case V4L2_CID_MPEG_VIDEO_GOP_SIZE: + return v4l2_ctrl_query_fill(qctrl, 1, 34, 1, + params->is_50hz ? 12 : 15); /* CX23415/6 specific */ case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE: return cx2341x_ctrl_query_fill(qctrl, V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_MANUAL, V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_AUTO, 1, - V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_MANUAL); + default_params.video_spatial_filter_mode); case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER: - cx2341x_ctrl_query_fill(qctrl, 0, 15, 1, 0); + cx2341x_ctrl_query_fill(qctrl, 0, 15, 1, + default_params.video_spatial_filter); qctrl->flags |= V4L2_CTRL_FLAG_SLIDER; if (params->video_spatial_filter_mode == V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_AUTO) @@ -501,7 +561,7 @@ int cx2341x_ctrl_query(struct cx2341x_mpeg_params *params, V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_OFF, V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_2D_SYM_NON_SEPARABLE, 1, - V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_OFF); + default_params.video_luma_spatial_filter_type); if (params->video_spatial_filter_mode == V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_AUTO) qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE; @@ -512,7 +572,7 @@ int cx2341x_ctrl_query(struct cx2341x_mpeg_params *params, V4L2_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE_OFF, V4L2_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE_1D_HOR, 1, - V4L2_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE_OFF); + default_params.video_chroma_spatial_filter_type); if (params->video_spatial_filter_mode == V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_AUTO) qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE; @@ -522,10 +582,11 @@ int cx2341x_ctrl_query(struct cx2341x_mpeg_params *params, return cx2341x_ctrl_query_fill(qctrl, V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_MANUAL, V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_AUTO, 1, - V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_MANUAL); + default_params.video_temporal_filter_mode); case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER: - cx2341x_ctrl_query_fill(qctrl, 0, 31, 1, 0); + cx2341x_ctrl_query_fill(qctrl, 0, 31, 1, + default_params.video_temporal_filter); qctrl->flags |= V4L2_CTRL_FLAG_SLIDER; if (params->video_temporal_filter_mode == V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_AUTO) @@ -536,10 +597,11 @@ int cx2341x_ctrl_query(struct cx2341x_mpeg_params *params, return cx2341x_ctrl_query_fill(qctrl, V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF, V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_DIAG, 1, - V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF); + default_params.video_median_filter_type); case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_TOP: - cx2341x_ctrl_query_fill(qctrl, 0, 255, 1, 255); + cx2341x_ctrl_query_fill(qctrl, 0, 255, 1, + default_params.video_luma_median_filter_top); qctrl->flags |= V4L2_CTRL_FLAG_SLIDER; if (params->video_median_filter_type == V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF) @@ -547,7 +609,8 @@ int cx2341x_ctrl_query(struct cx2341x_mpeg_params *params, return 0; case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_BOTTOM: - cx2341x_ctrl_query_fill(qctrl, 0, 255, 1, 0); + cx2341x_ctrl_query_fill(qctrl, 0, 255, 1, + default_params.video_luma_median_filter_bottom); qctrl->flags |= V4L2_CTRL_FLAG_SLIDER; if (params->video_median_filter_type == V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF) @@ -555,7 +618,8 @@ int cx2341x_ctrl_query(struct cx2341x_mpeg_params *params, return 0; case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_TOP: - cx2341x_ctrl_query_fill(qctrl, 0, 255, 1, 255); + cx2341x_ctrl_query_fill(qctrl, 0, 255, 1, + default_params.video_chroma_median_filter_top); qctrl->flags |= V4L2_CTRL_FLAG_SLIDER; if (params->video_median_filter_type == V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF) @@ -563,7 +627,8 @@ int cx2341x_ctrl_query(struct cx2341x_mpeg_params *params, return 0; case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_BOTTOM: - cx2341x_ctrl_query_fill(qctrl, 0, 255, 1, 0); + cx2341x_ctrl_query_fill(qctrl, 0, 255, 1, + default_params.video_chroma_median_filter_bottom); qctrl->flags |= V4L2_CTRL_FLAG_SLIDER; if (params->video_median_filter_type == V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF) @@ -571,7 +636,8 @@ int cx2341x_ctrl_query(struct cx2341x_mpeg_params *params, return 0; case V4L2_CID_MPEG_CX2341X_STREAM_INSERT_NAV_PACKETS: - return cx2341x_ctrl_query_fill(qctrl, 0, 1, 1, 0); + return cx2341x_ctrl_query_fill(qctrl, 0, 1, 1, + default_params.stream_insert_nav_packets); default: return v4l2_ctrl_query_fill_std(qctrl); @@ -580,9 +646,9 @@ int cx2341x_ctrl_query(struct cx2341x_mpeg_params *params, } EXPORT_SYMBOL(cx2341x_ctrl_query); -const char **cx2341x_ctrl_get_menu(u32 id) +const char **cx2341x_ctrl_get_menu(const struct cx2341x_mpeg_params *p, u32 id) { - static const char *mpeg_stream_type[] = { + static const char *mpeg_stream_type_without_ts[] = { "MPEG-2 Program Stream", "", "MPEG-1 System Stream", @@ -592,6 +658,16 @@ const char **cx2341x_ctrl_get_menu(u32 id) NULL }; + static const char *mpeg_stream_type_with_ts[] = { + "MPEG-2 Program Stream", + "MPEG-2 Transport Stream", + "MPEG-1 System Stream", + "MPEG-2 DVD-compatible Stream", + "MPEG-1 VCD-compatible Stream", + "MPEG-2 SVCD-compatible Stream", + NULL + }; + static const char *cx2341x_video_spatial_filter_mode_menu[] = { "Manual", "Auto", @@ -630,7 +706,8 @@ const char **cx2341x_ctrl_get_menu(u32 id) switch (id) { case V4L2_CID_MPEG_STREAM_TYPE: - return mpeg_stream_type; + return (p->capabilities & CX2341X_CAP_HAS_TS) ? + mpeg_stream_type_with_ts : mpeg_stream_type_without_ts; case V4L2_CID_MPEG_AUDIO_L1_BITRATE: case V4L2_CID_MPEG_AUDIO_L3_BITRATE: return NULL; @@ -690,7 +767,7 @@ int cx2341x_ext_ctrls(struct cx2341x_mpeg_params *params, int busy, if (err) break; if (qctrl.type == V4L2_CTRL_TYPE_MENU) - menu_items = cx2341x_ctrl_get_menu(qctrl.id); + menu_items = cx2341x_ctrl_get_menu(params, qctrl.id); err = v4l2_ctrl_check(ctrl, &qctrl, menu_items); if (err) break; @@ -714,61 +791,6 @@ EXPORT_SYMBOL(cx2341x_ext_ctrls); void cx2341x_fill_defaults(struct cx2341x_mpeg_params *p) { - static struct cx2341x_mpeg_params default_params = { - /* misc */ - .capabilities = 0, - .port = CX2341X_PORT_MEMORY, - .width = 720, - .height = 480, - .is_50hz = 0, - - /* stream */ - .stream_type = V4L2_MPEG_STREAM_TYPE_MPEG2_PS, - .stream_vbi_fmt = V4L2_MPEG_STREAM_VBI_FMT_NONE, - .stream_insert_nav_packets = 0, - - /* audio */ - .audio_sampling_freq = V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000, - .audio_encoding = V4L2_MPEG_AUDIO_ENCODING_LAYER_2, - .audio_l2_bitrate = V4L2_MPEG_AUDIO_L2_BITRATE_224K, - .audio_mode = V4L2_MPEG_AUDIO_MODE_STEREO, - .audio_mode_extension = V4L2_MPEG_AUDIO_MODE_EXTENSION_BOUND_4, - .audio_emphasis = V4L2_MPEG_AUDIO_EMPHASIS_NONE, - .audio_crc = V4L2_MPEG_AUDIO_CRC_NONE, - .audio_mute = 0, - - /* video */ - .video_encoding = V4L2_MPEG_VIDEO_ENCODING_MPEG_2, - .video_aspect = V4L2_MPEG_VIDEO_ASPECT_4x3, - .video_b_frames = 2, - .video_gop_size = 12, - .video_gop_closure = 1, - .video_bitrate_mode = V4L2_MPEG_VIDEO_BITRATE_MODE_VBR, - .video_bitrate = 6000000, - .video_bitrate_peak = 8000000, - .video_temporal_decimation = 0, - .video_mute = 0, - .video_mute_yuv = 0x008080, /* YCbCr value for black */ - - /* encoding filters */ - .video_spatial_filter_mode = - V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_MANUAL, - .video_spatial_filter = 0, - .video_luma_spatial_filter_type = - V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_1D_HOR, - .video_chroma_spatial_filter_type = - V4L2_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE_1D_HOR, - .video_temporal_filter_mode = - V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_MANUAL, - .video_temporal_filter = 8, - .video_median_filter_type = - V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF, - .video_luma_median_filter_top = 255, - .video_luma_median_filter_bottom = 0, - .video_chroma_median_filter_top = 255, - .video_chroma_median_filter_bottom = 0, - }; - *p = default_params; cx2341x_calc_audio_properties(p); } @@ -933,9 +955,9 @@ int cx2341x_update(void *priv, cx2341x_mbox_func func, } EXPORT_SYMBOL(cx2341x_update); -static const char *cx2341x_menu_item(struct cx2341x_mpeg_params *p, u32 id) +static const char *cx2341x_menu_item(const struct cx2341x_mpeg_params *p, u32 id) { - const char **menu = cx2341x_ctrl_get_menu(id); + const char **menu = cx2341x_ctrl_get_menu(p, id); struct v4l2_ext_control ctrl; if (menu == NULL) @@ -952,7 +974,7 @@ invalid: return "<invalid>"; } -void cx2341x_log_status(struct cx2341x_mpeg_params *p, const char *prefix) +void cx2341x_log_status(const struct cx2341x_mpeg_params *p, const char *prefix) { int is_mpeg1 = p->video_encoding == V4L2_MPEG_VIDEO_ENCODING_MPEG_1; int temporal = p->video_temporal_filter; diff --git a/drivers/media/video/cx23885/Kconfig b/drivers/media/video/cx23885/Kconfig index 7bf14c9a15c7..5cfb46bbdaa9 100644 --- a/drivers/media/video/cx23885/Kconfig +++ b/drivers/media/video/cx23885/Kconfig @@ -9,11 +9,13 @@ config VIDEO_CX23885 select VIDEO_TVEEPROM select VIDEO_IR select VIDEOBUF_DVB + select VIDEOBUF_DMA_SG select VIDEO_CX25840 select VIDEO_CX2341X select DVB_DIB7000P if !DVB_FE_CUSTOMISE select MEDIA_TUNER_MT2131 if !DVB_FE_CUSTOMISE select DVB_S5H1409 if !DVB_FE_CUSTOMISE + select DVB_S5H1411 if !DVB_FE_CUSTOMISE select DVB_LGDT330X if !DVB_FE_CUSTOMISE select MEDIA_TUNER_XC2028 if !DVB_FE_CUSTOMIZE select MEDIA_TUNER_TDA8290 if !DVB_FE_CUSTOMIZE diff --git a/drivers/media/video/cx23885/cx23885-417.c b/drivers/media/video/cx23885/cx23885-417.c index acdd3b6b3e7c..e7ef093265af 100644 --- a/drivers/media/video/cx23885/cx23885-417.c +++ b/drivers/media/video/cx23885/cx23885-417.c @@ -1173,379 +1173,404 @@ static int cx23885_querymenu(struct cx23885_dev *dev, qctrl.id = qmenu->id; cx23885_queryctrl(dev, &qctrl); return v4l2_ctrl_query_menu(qmenu, &qctrl, - cx2341x_ctrl_get_menu(qmenu->id)); + cx2341x_ctrl_get_menu(&dev->mpeg_params, qmenu->id)); } -int cx23885_do_ioctl(struct inode *inode, struct file *file, int radio, - struct cx23885_dev *dev, unsigned int cmd, void *arg, - v4l2_kioctl driver_ioctl) +static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *id) { - int err; + struct cx23885_fh *fh = file->private_data; + struct cx23885_dev *dev = fh->dev; + unsigned int i; - switch (cmd) { - /* ---------- tv norms ---------- */ - case VIDIOC_ENUMSTD: - { - struct v4l2_standard *e = arg; - unsigned int i; - - i = e->index; - if (i >= ARRAY_SIZE(cx23885_tvnorms)) - return -EINVAL; - err = v4l2_video_std_construct(e, - cx23885_tvnorms[e->index].id, - cx23885_tvnorms[e->index].name); - e->index = i; - if (err < 0) - return err; - return 0; - } - case VIDIOC_G_STD: - { - v4l2_std_id *id = arg; + for (i = 0; i < ARRAY_SIZE(cx23885_tvnorms); i++) + if (*id & cx23885_tvnorms[i].id) + break; + if (i == ARRAY_SIZE(cx23885_tvnorms)) + return -EINVAL; + dev->encodernorm = cx23885_tvnorms[i]; + return 0; +} - *id = dev->encodernorm.id; - return 0; - } - case VIDIOC_S_STD: - { - v4l2_std_id *id = arg; - unsigned int i; +static int vidioc_enum_input(struct file *file, void *priv, + struct v4l2_input *i) +{ + struct cx23885_fh *fh = file->private_data; + struct cx23885_dev *dev = fh->dev; + struct cx23885_input *input; + unsigned int n; - for (i = 0; i < ARRAY_SIZE(cx23885_tvnorms); i++) - if (*id & cx23885_tvnorms[i].id) - break; - if (i == ARRAY_SIZE(cx23885_tvnorms)) - return -EINVAL; - dev->encodernorm = cx23885_tvnorms[i]; + n = i->index; - return 0; - } + if (n >= 4) + return -EINVAL; - /* ------ input switching ---------- */ - case VIDIOC_ENUMINPUT: - { - struct cx23885_input *input; - struct v4l2_input *i = arg; - unsigned int n; - - n = i->index; - if (n >= 4) - return -EINVAL; - input = &cx23885_boards[dev->board].input[n]; - if (input->type == 0) - return -EINVAL; - memset(i, 0, sizeof(*i)); - i->index = n; - /* FIXME - * strcpy(i->name, input->name); */ - strcpy(i->name, "unset"); - if (input->type == CX23885_VMUX_TELEVISION || - input->type == CX23885_VMUX_CABLE) - i->type = V4L2_INPUT_TYPE_TUNER; - else - i->type = V4L2_INPUT_TYPE_CAMERA; + input = &cx23885_boards[dev->board].input[n]; - for (n = 0; n < ARRAY_SIZE(cx23885_tvnorms); n++) - i->std |= cx23885_tvnorms[n].id; - return 0; - } - case VIDIOC_G_INPUT: - { - unsigned int *i = arg; + if (input->type == 0) + return -EINVAL; - *i = dev->input; - return 0; - } - case VIDIOC_S_INPUT: - { - unsigned int *i = arg; + memset(i, 0, sizeof(*i)); + i->index = n; - if (*i >= 4) - return -EINVAL; + /* FIXME + * strcpy(i->name, input->name); */ + strcpy(i->name, "unset"); - return 0; - } + if (input->type == CX23885_VMUX_TELEVISION || + input->type == CX23885_VMUX_CABLE) + i->type = V4L2_INPUT_TYPE_TUNER; + else + i->type = V4L2_INPUT_TYPE_CAMERA; - /* --- tuner ioctls ------------------------------------------ */ - case VIDIOC_G_TUNER: - { - struct v4l2_tuner *t = arg; + for (n = 0; n < ARRAY_SIZE(cx23885_tvnorms); n++) + i->std |= cx23885_tvnorms[n].id; + return 0; +} - if (UNSET == dev->tuner_type) - return -EINVAL; - if (0 != t->index) - return -EINVAL; - memset(t, 0, sizeof(*t)); - strcpy(t->name, "Television"); - cx23885_call_i2c_clients(&dev->i2c_bus[2], VIDIOC_G_TUNER, t); - cx23885_call_i2c_clients(&dev->i2c_bus[1], VIDIOC_G_TUNER, t); +static int vidioc_g_input(struct file *file, void *priv, unsigned int *i) +{ + struct cx23885_fh *fh = file->private_data; + struct cx23885_dev *dev = fh->dev; - dprintk(1, "VIDIOC_G_TUNER: tuner type %d\n", t->type); + *i = dev->input; + return 0; +} - return 0; - } - case VIDIOC_S_TUNER: - { - struct v4l2_tuner *t = arg; +static int vidioc_s_input(struct file *file, void *priv, unsigned int i) +{ + if (i >= 4) + return -EINVAL; - if (UNSET == dev->tuner_type) - return -EINVAL; + return 0; +} - /* Update the A/V core */ - cx23885_call_i2c_clients(&dev->i2c_bus[2], VIDIOC_S_TUNER, t); +static int vidioc_g_tuner(struct file *file, void *priv, + struct v4l2_tuner *t) +{ + struct cx23885_fh *fh = file->private_data; + struct cx23885_dev *dev = fh->dev; - return 0; - } - case VIDIOC_G_FREQUENCY: - { - struct v4l2_frequency *f = arg; + if (UNSET == dev->tuner_type) + return -EINVAL; + if (0 != t->index) + return -EINVAL; + memset(t, 0, sizeof(*t)); + strcpy(t->name, "Television"); + cx23885_call_i2c_clients(&dev->i2c_bus[2], VIDIOC_G_TUNER, t); + cx23885_call_i2c_clients(&dev->i2c_bus[1], VIDIOC_G_TUNER, t); - memset(f, 0, sizeof(*f)); - if (UNSET == dev->tuner_type) - return -EINVAL; - f->type = V4L2_TUNER_ANALOG_TV; - f->frequency = dev->freq; + dprintk(1, "VIDIOC_G_TUNER: tuner type %d\n", t->type); - /* Assumption that tuner is always on bus 1 */ - cx23885_call_i2c_clients(&dev->i2c_bus[1], - VIDIOC_G_FREQUENCY, f); + return 0; +} - return 0; - } - case VIDIOC_S_FREQUENCY: - { - struct v4l2_frequency *f = arg; - - dprintk(1, "VIDIOC_S_FREQUENCY: dev type %d, f\n", - dev->tuner_type); - dprintk(1, "VIDIOC_S_FREQUENCY: f tuner %d, f type %d\n", - f->tuner, f->type); - if (UNSET == dev->tuner_type) - return -EINVAL; - if (f->tuner != 0) - return -EINVAL; - if (f->type != V4L2_TUNER_ANALOG_TV) - return -EINVAL; - dev->freq = f->frequency; - - /* Assumption that tuner is always on bus 1 */ - cx23885_call_i2c_clients(&dev->i2c_bus[1], - VIDIOC_S_FREQUENCY, f); - return 0; - } - case VIDIOC_S_CTRL: - { - /* Update the A/V core */ - cx23885_call_i2c_clients(&dev->i2c_bus[2], VIDIOC_S_CTRL, arg); - return 0; - } - default: - /* Convert V4L ioctl to V4L2 and call mpeg_do_ioctl - * (driver_ioctl) */ - return v4l_compat_translate_ioctl(inode, file, cmd, arg, - driver_ioctl); - } +static int vidioc_s_tuner(struct file *file, void *priv, + struct v4l2_tuner *t) +{ + struct cx23885_fh *fh = file->private_data; + struct cx23885_dev *dev = fh->dev; + + if (UNSET == dev->tuner_type) + return -EINVAL; + + /* Update the A/V core */ + cx23885_call_i2c_clients(&dev->i2c_bus[2], VIDIOC_S_TUNER, t); + + return 0; +} + +static int vidioc_g_frequency(struct file *file, void *priv, + struct v4l2_frequency *f) +{ + struct cx23885_fh *fh = file->private_data; + struct cx23885_dev *dev = fh->dev; + + memset(f, 0, sizeof(*f)); + if (UNSET == dev->tuner_type) + return -EINVAL; + f->type = V4L2_TUNER_ANALOG_TV; + f->frequency = dev->freq; + + /* Assumption that tuner is always on bus 1 */ + cx23885_call_i2c_clients(&dev->i2c_bus[1], VIDIOC_G_FREQUENCY, f); + + return 0; +} + +static int vidioc_s_frequency(struct file *file, void *priv, + struct v4l2_frequency *f) +{ + struct cx23885_fh *fh = file->private_data; + struct cx23885_dev *dev = fh->dev; + + cx23885_api_cmd(fh->dev, CX2341X_ENC_STOP_CAPTURE, 3, 0, + CX23885_END_NOW, CX23885_MPEG_CAPTURE, + CX23885_RAW_BITS_NONE); + + dprintk(1, "VIDIOC_S_FREQUENCY: dev type %d, f\n", + dev->tuner_type); + dprintk(1, "VIDIOC_S_FREQUENCY: f tuner %d, f type %d\n", + f->tuner, f->type); + if (UNSET == dev->tuner_type) + return -EINVAL; + if (f->tuner != 0) + return -EINVAL; + if (f->type != V4L2_TUNER_ANALOG_TV) + return -EINVAL; + dev->freq = f->frequency; + + /* Assumption that tuner is always on bus 1 */ + cx23885_call_i2c_clients(&dev->i2c_bus[1], VIDIOC_S_FREQUENCY, f); + + cx23885_initialize_codec(dev); return 0; } -static int mpeg_do_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, void *arg) +static int vidioc_s_ctrl(struct file *file, void *priv, + struct v4l2_control *ctl) +{ + struct cx23885_fh *fh = file->private_data; + struct cx23885_dev *dev = fh->dev; + + /* Update the A/V core */ + cx23885_call_i2c_clients(&dev->i2c_bus[2], VIDIOC_S_CTRL, ctl); + return 0; +} + +static int vidioc_querycap(struct file *file, void *priv, + struct v4l2_capability *cap) { struct cx23885_fh *fh = file->private_data; struct cx23885_dev *dev = fh->dev; struct cx23885_tsport *tsport = &dev->ts1; - if (v4l_debug > 1) - v4l_print_ioctl(dev->name, cmd); + memset(cap, 0, sizeof(*cap)); + strcpy(cap->driver, dev->name); + strlcpy(cap->card, cx23885_boards[tsport->dev->board].name, + sizeof(cap->card)); + sprintf(cap->bus_info, "PCI:%s", pci_name(dev->pci)); + cap->version = CX23885_VERSION_CODE; + cap->capabilities = + V4L2_CAP_VIDEO_CAPTURE | + V4L2_CAP_READWRITE | + V4L2_CAP_STREAMING | + 0; + if (UNSET != dev->tuner_type) + cap->capabilities |= V4L2_CAP_TUNER; - switch (cmd) { + return 0; +} - /* --- capabilities ------------------------------------------ */ - case VIDIOC_QUERYCAP: - { - struct v4l2_capability *cap = arg; - - memset(cap, 0, sizeof(*cap)); - strcpy(cap->driver, dev->name); - strlcpy(cap->card, cx23885_boards[tsport->dev->board].name, - sizeof(cap->card)); - sprintf(cap->bus_info, "PCI:%s", pci_name(dev->pci)); - cap->version = CX23885_VERSION_CODE; - cap->capabilities = - V4L2_CAP_VIDEO_CAPTURE | - V4L2_CAP_READWRITE | - V4L2_CAP_STREAMING | - 0; - if (UNSET != dev->tuner_type) - cap->capabilities |= V4L2_CAP_TUNER; - - return 0; - } +static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_fmtdesc *f) +{ + int index; - /* --- capture ioctls ---------------------------------------- */ - case VIDIOC_ENUM_FMT: - { - struct v4l2_fmtdesc *f = arg; - int index; - - index = f->index; - if (index != 0) - return -EINVAL; - - memset(f, 0, sizeof(*f)); - f->index = index; - strlcpy(f->description, "MPEG", sizeof(f->description)); - f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - f->pixelformat = V4L2_PIX_FMT_MPEG; - return 0; - } - case VIDIOC_G_FMT: - { - struct v4l2_format *f = arg; - - memset(f, 0, sizeof(*f)); - f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG; - f->fmt.pix.bytesperline = 0; - f->fmt.pix.sizeimage = - dev->ts1.ts_packet_size * dev->ts1.ts_packet_count; - f->fmt.pix.colorspace = 0; - f->fmt.pix.width = dev->ts1.width; - f->fmt.pix.height = dev->ts1.height; - f->fmt.pix.field = fh->mpegq.field; - dprintk(1, "VIDIOC_G_FMT: w: %d, h: %d, f: %d\n", - dev->ts1.width, dev->ts1.height, fh->mpegq.field); - return 0; - } - case VIDIOC_TRY_FMT: - { - struct v4l2_format *f = arg; - - f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG; - f->fmt.pix.bytesperline = 0; - f->fmt.pix.sizeimage = - dev->ts1.ts_packet_size * dev->ts1.ts_packet_count; - f->fmt.pix.sizeimage = - f->fmt.pix.colorspace = 0; - dprintk(1, "VIDIOC_TRY_FMT: w: %d, h: %d, f: %d\n", - dev->ts1.width, dev->ts1.height, fh->mpegq.field); - return 0; - } - case VIDIOC_S_FMT: - { - struct v4l2_format *f = arg; - - f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG; - f->fmt.pix.bytesperline = 0; - f->fmt.pix.sizeimage = - dev->ts1.ts_packet_size * dev->ts1.ts_packet_count; - f->fmt.pix.colorspace = 0; - dprintk(1, "VIDIOC_S_FMT: w: %d, h: %d, f: %d\n", - f->fmt.pix.width, f->fmt.pix.height, f->fmt.pix.field); - return 0; - } + index = f->index; + if (index != 0) + return -EINVAL; - /* --- streaming capture ------------------------------------- */ - case VIDIOC_REQBUFS: - return videobuf_reqbufs(&fh->mpegq, arg); + memset(f, 0, sizeof(*f)); + f->index = index; + strlcpy(f->description, "MPEG", sizeof(f->description)); + f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + f->pixelformat = V4L2_PIX_FMT_MPEG; - case VIDIOC_QUERYBUF: - return videobuf_querybuf(&fh->mpegq, arg); + return 0; +} - case VIDIOC_QBUF: - return videobuf_qbuf(&fh->mpegq, arg); +static int vidioc_g_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct cx23885_fh *fh = file->private_data; + struct cx23885_dev *dev = fh->dev; - case VIDIOC_DQBUF: - return videobuf_dqbuf(&fh->mpegq, arg, - file->f_flags & O_NONBLOCK); + memset(f, 0, sizeof(*f)); + f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG; + f->fmt.pix.bytesperline = 0; + f->fmt.pix.sizeimage = + dev->ts1.ts_packet_size * dev->ts1.ts_packet_count; + f->fmt.pix.colorspace = 0; + f->fmt.pix.width = dev->ts1.width; + f->fmt.pix.height = dev->ts1.height; + f->fmt.pix.field = fh->mpegq.field; + dprintk(1, "VIDIOC_G_FMT: w: %d, h: %d, f: %d\n", + dev->ts1.width, dev->ts1.height, fh->mpegq.field); + return 0; +} - case VIDIOC_STREAMON: - return videobuf_streamon(&fh->mpegq); +static int vidioc_try_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct cx23885_fh *fh = file->private_data; + struct cx23885_dev *dev = fh->dev; - case VIDIOC_STREAMOFF: - return videobuf_streamoff(&fh->mpegq); + f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG; + f->fmt.pix.bytesperline = 0; + f->fmt.pix.sizeimage = + dev->ts1.ts_packet_size * dev->ts1.ts_packet_count; + f->fmt.pix.sizeimage = + f->fmt.pix.colorspace = 0; + dprintk(1, "VIDIOC_TRY_FMT: w: %d, h: %d, f: %d\n", + dev->ts1.width, dev->ts1.height, fh->mpegq.field); + return 0; +} - case VIDIOC_G_EXT_CTRLS: - { - struct v4l2_ext_controls *f = arg; +static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct cx23885_fh *fh = file->private_data; + struct cx23885_dev *dev = fh->dev; - if (f->ctrl_class != V4L2_CTRL_CLASS_MPEG) - return -EINVAL; - return cx2341x_ext_ctrls(&dev->mpeg_params, 0, f, cmd); - } - case VIDIOC_S_EXT_CTRLS: - case VIDIOC_TRY_EXT_CTRLS: - { - struct v4l2_ext_controls *f = arg; - struct cx2341x_mpeg_params p; - int err; - - if (f->ctrl_class != V4L2_CTRL_CLASS_MPEG) - return -EINVAL; - p = dev->mpeg_params; - err = cx2341x_ext_ctrls(&p, 0, f, cmd); - if (err == 0 && cmd == VIDIOC_S_EXT_CTRLS) { - err = cx2341x_update(dev, cx23885_mbox_func, - &dev->mpeg_params, &p); - dev->mpeg_params = p; - } - return err; - } - case VIDIOC_S_FREQUENCY: - { - cx23885_api_cmd(fh->dev, CX2341X_ENC_STOP_CAPTURE, 3, 0, - CX23885_END_NOW, CX23885_MPEG_CAPTURE, - CX23885_RAW_BITS_NONE); - cx23885_do_ioctl(inode, file, 0, dev, cmd, arg, - mpeg_do_ioctl); - cx23885_initialize_codec(dev); - - return 0; - } - case VIDIOC_LOG_STATUS: - { - char name[32 + 2]; - - snprintf(name, sizeof(name), "%s/2", dev->name); - printk(KERN_INFO - "%s/2: ============ START LOG STATUS ============\n", - dev->name); - cx23885_call_i2c_clients(&dev->i2c_bus[0], VIDIOC_LOG_STATUS, - NULL); - cx23885_call_i2c_clients(&dev->i2c_bus[1], VIDIOC_LOG_STATUS, - NULL); - cx23885_call_i2c_clients(&dev->i2c_bus[2], VIDIOC_LOG_STATUS, - NULL); - cx2341x_log_status(&dev->mpeg_params, name); - printk(KERN_INFO - "%s/2: ============= END LOG STATUS =============\n", - dev->name); - return 0; - } - case VIDIOC_QUERYMENU: - return cx23885_querymenu(dev, arg); - case VIDIOC_QUERYCTRL: - { - struct v4l2_queryctrl *c = arg; + f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG; + f->fmt.pix.bytesperline = 0; + f->fmt.pix.sizeimage = + dev->ts1.ts_packet_size * dev->ts1.ts_packet_count; + f->fmt.pix.colorspace = 0; + dprintk(1, "VIDIOC_S_FMT: w: %d, h: %d, f: %d\n", + f->fmt.pix.width, f->fmt.pix.height, f->fmt.pix.field); + return 0; +} - return cx23885_queryctrl(dev, c); - } +static int vidioc_reqbufs(struct file *file, void *priv, + struct v4l2_requestbuffers *p) +{ + struct cx23885_fh *fh = file->private_data; - default: - return cx23885_do_ioctl(inode, file, 0, dev, cmd, arg, - mpeg_do_ioctl); + return videobuf_reqbufs(&fh->mpegq, p); +} + +static int vidioc_querybuf(struct file *file, void *priv, + struct v4l2_buffer *p) +{ + struct cx23885_fh *fh = file->private_data; + + return videobuf_querybuf(&fh->mpegq, p); +} + +static int vidioc_qbuf(struct file *file, void *priv, + struct v4l2_buffer *p) +{ + struct cx23885_fh *fh = file->private_data; + + return videobuf_qbuf(&fh->mpegq, p); +} + +static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b) +{ + struct cx23885_fh *fh = priv; + + return videobuf_dqbuf(&fh->mpegq, b, file->f_flags & O_NONBLOCK); +} + + +static int vidioc_streamon(struct file *file, void *priv, + enum v4l2_buf_type i) +{ + struct cx23885_fh *fh = file->private_data; + + return videobuf_streamon(&fh->mpegq); +} + +static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i) +{ + struct cx23885_fh *fh = file->private_data; + + return videobuf_streamoff(&fh->mpegq); +} + +static int vidioc_g_ext_ctrls(struct file *file, void *priv, + struct v4l2_ext_controls *f) +{ + struct cx23885_fh *fh = priv; + struct cx23885_dev *dev = fh->dev; + + if (f->ctrl_class != V4L2_CTRL_CLASS_MPEG) + return -EINVAL; + return cx2341x_ext_ctrls(&dev->mpeg_params, 0, f, VIDIOC_G_EXT_CTRLS); +} + +static int vidioc_s_ext_ctrls(struct file *file, void *priv, + struct v4l2_ext_controls *f) +{ + struct cx23885_fh *fh = priv; + struct cx23885_dev *dev = fh->dev; + struct cx2341x_mpeg_params p; + int err; + + if (f->ctrl_class != V4L2_CTRL_CLASS_MPEG) + return -EINVAL; + + p = dev->mpeg_params; + err = cx2341x_ext_ctrls(&p, 0, f, VIDIOC_S_EXT_CTRLS); + + if (err == 0) { + err = cx2341x_update(dev, cx23885_mbox_func, + &dev->mpeg_params, &p); + dev->mpeg_params = p; } + return err; +} + +static int vidioc_try_ext_ctrls(struct file *file, void *priv, + struct v4l2_ext_controls *f) +{ + struct cx23885_fh *fh = priv; + struct cx23885_dev *dev = fh->dev; + struct cx2341x_mpeg_params p; + int err; + + if (f->ctrl_class != V4L2_CTRL_CLASS_MPEG) + return -EINVAL; + + p = dev->mpeg_params; + err = cx2341x_ext_ctrls(&p, 0, f, VIDIOC_TRY_EXT_CTRLS); + return err; +} + +static int vidioc_log_status(struct file *file, void *priv) +{ + struct cx23885_fh *fh = priv; + struct cx23885_dev *dev = fh->dev; + char name[32 + 2]; + + snprintf(name, sizeof(name), "%s/2", dev->name); + printk(KERN_INFO + "%s/2: ============ START LOG STATUS ============\n", + dev->name); + cx23885_call_i2c_clients(&dev->i2c_bus[0], VIDIOC_LOG_STATUS, + NULL); + cx23885_call_i2c_clients(&dev->i2c_bus[1], VIDIOC_LOG_STATUS, + NULL); + cx23885_call_i2c_clients(&dev->i2c_bus[2], VIDIOC_LOG_STATUS, + NULL); + cx2341x_log_status(&dev->mpeg_params, name); + printk(KERN_INFO + "%s/2: ============= END LOG STATUS =============\n", + dev->name); return 0; } -static int mpeg_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg) +static int vidioc_querymenu(struct file *file, void *priv, + struct v4l2_querymenu *a) +{ + struct cx23885_fh *fh = priv; + struct cx23885_dev *dev = fh->dev; + + return cx23885_querymenu(dev, a); +} + +static int vidioc_queryctrl(struct file *file, void *priv, + struct v4l2_queryctrl *c) { - return video_usercopy(inode, file, cmd, arg, mpeg_do_ioctl); + struct cx23885_fh *fh = priv; + struct cx23885_dev *dev = fh->dev; + + return cx23885_queryctrl(dev, c); } static int mpeg_open(struct inode *inode, struct file *file) @@ -1670,7 +1695,7 @@ static struct file_operations mpeg_fops = { .read = mpeg_read, .poll = mpeg_poll, .mmap = mpeg_mmap, - .ioctl = mpeg_ioctl, + .ioctl = video_ioctl2, .llseek = no_llseek, }; @@ -1682,6 +1707,32 @@ static struct video_device cx23885_mpeg_template = { VID_TYPE_MPEG_ENCODER, .fops = &mpeg_fops, .minor = -1, + .vidioc_s_std = vidioc_s_std, + .vidioc_enum_input = vidioc_enum_input, + .vidioc_g_input = vidioc_g_input, + .vidioc_s_input = vidioc_s_input, + .vidioc_g_tuner = vidioc_g_tuner, + .vidioc_s_tuner = vidioc_s_tuner, + .vidioc_g_frequency = vidioc_g_frequency, + .vidioc_s_frequency = vidioc_s_frequency, + .vidioc_s_ctrl = vidioc_s_ctrl, + .vidioc_querycap = vidioc_querycap, + .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap, + .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap, + .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap, + .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap, + .vidioc_reqbufs = vidioc_reqbufs, + .vidioc_querybuf = vidioc_querybuf, + .vidioc_qbuf = vidioc_qbuf, + .vidioc_dqbuf = vidioc_dqbuf, + .vidioc_streamon = vidioc_streamon, + .vidioc_streamoff = vidioc_streamoff, + .vidioc_g_ext_ctrls = vidioc_g_ext_ctrls, + .vidioc_s_ext_ctrls = vidioc_s_ext_ctrls, + .vidioc_try_ext_ctrls = vidioc_try_ext_ctrls, + .vidioc_log_status = vidioc_log_status, + .vidioc_querymenu = vidioc_querymenu, + .vidioc_queryctrl = vidioc_queryctrl, }; void cx23885_417_unregister(struct cx23885_dev *dev) diff --git a/drivers/media/video/cx23885/cx23885-cards.c b/drivers/media/video/cx23885/cx23885-cards.c index 20e05f230546..fd7112c11d35 100644 --- a/drivers/media/video/cx23885/cx23885-cards.c +++ b/drivers/media/video/cx23885/cx23885-cards.c @@ -143,6 +143,10 @@ struct cx23885_board cx23885_boards[] = { .name = "Hauppauge WinTV-HVR1400", .portc = CX23885_MPEG_DVB, }, + [CX23885_BOARD_DVICO_FUSIONHDTV_7_DUAL_EXP] = { + .name = "DViCO FusionHDTV7 Dual Express", + .portc = CX23885_MPEG_DVB, + }, }; const unsigned int cx23885_bcount = ARRAY_SIZE(cx23885_boards); @@ -210,6 +214,10 @@ struct cx23885_subid cx23885_subids[] = { .subvendor = 0x0070, .subdevice = 0x8010, .card = CX23885_BOARD_HAUPPAUGE_HVR1400, + },{ + .subvendor = 0x18ac, + .subdevice = 0xd618, + .card = CX23885_BOARD_DVICO_FUSIONHDTV_7_DUAL_EXP, }, }; const unsigned int cx23885_idcount = ARRAY_SIZE(cx23885_subids); @@ -477,6 +485,11 @@ void cx23885_card_setup(struct cx23885_dev *dev) } switch (dev->board) { + case CX23885_BOARD_DVICO_FUSIONHDTV_7_DUAL_EXP: + ts2->gen_ctrl_val = 0xc; /* Serial bus + punctured clock */ + ts2->ts_clk_en_val = 0x1; /* Enable TS_CLK */ + ts2->src_sel_val = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO; + /* break omitted intentionally */ case CX23885_BOARD_DVICO_FUSIONHDTV_5_EXP: ts1->gen_ctrl_val = 0xc; /* Serial bus + punctured clock */ ts1->ts_clk_en_val = 0x1; /* Enable TS_CLK */ diff --git a/drivers/media/video/cx23885/cx23885-core.c b/drivers/media/video/cx23885/cx23885-core.c index c4cc2f3b8876..d17343ea0d33 100644 --- a/drivers/media/video/cx23885/cx23885-core.c +++ b/drivers/media/video/cx23885/cx23885-core.c @@ -291,9 +291,9 @@ int cx23885_sram_channel_setup(struct cx23885_dev *dev, lines = 6; BUG_ON(lines < 2); - cx_write(8 + 0, cpu_to_le32(RISC_JUMP | RISC_IRQ1 | RISC_CNT_INC) ); - cx_write(8 + 4, cpu_to_le32(8) ); - cx_write(8 + 8, cpu_to_le32(0) ); + cx_write(8 + 0, RISC_JUMP | RISC_IRQ1 | RISC_CNT_INC); + cx_write(8 + 4, 8); + cx_write(8 + 8, 0); /* write CDT */ for (i = 0; i < lines; i++) { @@ -408,11 +408,11 @@ static void cx23885_risc_disasm(struct cx23885_tsport *port, dev->name, risc->cpu, (unsigned long)risc->dma); for (i = 0; i < (risc->size >> 2); i += n) { printk("%s: %04d: ", dev->name, i); - n = cx23885_risc_decode(risc->cpu[i]); + n = cx23885_risc_decode(le32_to_cpu(risc->cpu[i])); for (j = 1; j < n; j++) printk("%s: %04d: 0x%08x [ arg #%d ]\n", dev->name, i + j, risc->cpu[i + j], j); - if (risc->cpu[i] == RISC_JUMP) + if (risc->cpu[i] == cpu_to_le32(RISC_JUMP)) break; } } diff --git a/drivers/media/video/cx23885/cx23885-dvb.c b/drivers/media/video/cx23885/cx23885-dvb.c index 022aa391937a..0a2e6558cd66 100644 --- a/drivers/media/video/cx23885/cx23885-dvb.c +++ b/drivers/media/video/cx23885/cx23885-dvb.c @@ -31,6 +31,7 @@ #include <media/v4l2-common.h> #include "s5h1409.h" +#include "s5h1411.h" #include "mt2131.h" #include "tda8290.h" #include "tda18271.h" @@ -164,12 +165,38 @@ static struct s5h1409_config hauppauge_hvr1500q_config = { .mpeg_timing = S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK, }; +static struct s5h1409_config dvico_s5h1409_config = { + .demod_address = 0x32 >> 1, + .output_mode = S5H1409_SERIAL_OUTPUT, + .gpio = S5H1409_GPIO_ON, + .qam_if = 44000, + .inversion = S5H1409_INVERSION_OFF, + .status_mode = S5H1409_DEMODLOCKING, + .mpeg_timing = S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK, +}; + +static struct s5h1411_config dvico_s5h1411_config = { + .output_mode = S5H1411_SERIAL_OUTPUT, + .gpio = S5H1411_GPIO_ON, + .qam_if = S5H1411_IF_44000, + .vsb_if = S5H1411_IF_44000, + .inversion = S5H1411_INVERSION_OFF, + .status_mode = S5H1411_DEMODLOCKING, + .mpeg_timing = S5H1411_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK, +}; + static struct xc5000_config hauppauge_hvr1500q_tunerconfig = { .i2c_address = 0x61, .if_khz = 5380, .tuner_callback = cx23885_tuner_callback }; +static struct xc5000_config dvico_xc5000_tunerconfig = { + .i2c_address = 0x64, + .if_khz = 5380, + .tuner_callback = cx23885_tuner_callback +}; + static struct tda829x_config tda829x_no_probe = { .probe_tuner = TDA829X_DONT_PROBE, }; @@ -453,6 +480,21 @@ static int dvb_register(struct cx23885_tsport *port) fe->ops.tuner_ops.set_config(fe, &ctl); } break; + case CX23885_BOARD_DVICO_FUSIONHDTV_7_DUAL_EXP: + i2c_bus = &dev->i2c_bus[port->nr - 1]; + + port->dvb.frontend = dvb_attach(s5h1409_attach, + &dvico_s5h1409_config, + &i2c_bus->i2c_adap); + if (port->dvb.frontend == NULL) + port->dvb.frontend = dvb_attach(s5h1411_attach, + &dvico_s5h1411_config, + &i2c_bus->i2c_adap); + if (port->dvb.frontend != NULL) + dvb_attach(xc5000_attach, port->dvb.frontend, + &i2c_bus->i2c_adap, + &dvico_xc5000_tunerconfig, i2c_bus); + break; default: printk("%s: The frontend of your DVB/ATSC card isn't supported yet\n", dev->name); diff --git a/drivers/media/video/cx23885/cx23885-video.c b/drivers/media/video/cx23885/cx23885-video.c index 84652210a28c..043fc4e5c586 100644 --- a/drivers/media/video/cx23885/cx23885-video.c +++ b/drivers/media/video/cx23885/cx23885-video.c @@ -915,7 +915,7 @@ static void init_controls(struct cx23885_dev *dev) /* ------------------------------------------------------------------ */ /* VIDEO IOCTLS */ -static int vidioc_g_fmt_cap(struct file *file, void *priv, +static int vidioc_g_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f) { struct cx23885_fh *fh = priv; @@ -932,7 +932,7 @@ static int vidioc_g_fmt_cap(struct file *file, void *priv, return 0; } -static int vidioc_try_fmt_cap(struct file *file, void *priv, +static int vidioc_try_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f) { struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev; @@ -983,7 +983,7 @@ static int vidioc_try_fmt_cap(struct file *file, void *priv, return 0; } -static int vidioc_s_fmt_cap(struct file *file, void *priv, +static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f) { struct cx23885_fh *fh = priv; @@ -991,7 +991,7 @@ static int vidioc_s_fmt_cap(struct file *file, void *priv, int err; dprintk(2, "%s()\n", __func__); - err = vidioc_try_fmt_cap(file, priv, f); + err = vidioc_try_fmt_vid_cap(file, priv, f); if (0 != err) return err; @@ -1025,7 +1025,7 @@ static int vidioc_querycap(struct file *file, void *priv, return 0; } -static int vidioc_enum_fmt_cap(struct file *file, void *priv, +static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv, struct v4l2_fmtdesc *f) { if (unlikely(f->index >= ARRAY_SIZE(formats))) @@ -1440,13 +1440,13 @@ static struct video_device cx23885_video_template = { .fops = &video_fops, .minor = -1, .vidioc_querycap = vidioc_querycap, - .vidioc_enum_fmt_cap = vidioc_enum_fmt_cap, - .vidioc_g_fmt_cap = vidioc_g_fmt_cap, - .vidioc_try_fmt_cap = vidioc_try_fmt_cap, - .vidioc_s_fmt_cap = vidioc_s_fmt_cap, - .vidioc_g_fmt_vbi = cx23885_vbi_fmt, - .vidioc_try_fmt_vbi = cx23885_vbi_fmt, - .vidioc_s_fmt_vbi = cx23885_vbi_fmt, + .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap, + .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap, + .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap, + .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap, + .vidioc_g_fmt_vbi_cap = cx23885_vbi_fmt, + .vidioc_try_fmt_vbi_cap = cx23885_vbi_fmt, + .vidioc_s_fmt_vbi_cap = cx23885_vbi_fmt, .vidioc_reqbufs = vidioc_reqbufs, .vidioc_querybuf = vidioc_querybuf, .vidioc_qbuf = vidioc_qbuf, diff --git a/drivers/media/video/cx23885/cx23885.h b/drivers/media/video/cx23885/cx23885.h index 32af87f25e7b..00dfdc89d641 100644 --- a/drivers/media/video/cx23885/cx23885.h +++ b/drivers/media/video/cx23885/cx23885.h @@ -63,6 +63,7 @@ #define CX23885_BOARD_HAUPPAUGE_HVR1200 7 #define CX23885_BOARD_HAUPPAUGE_HVR1700 8 #define CX23885_BOARD_HAUPPAUGE_HVR1400 9 +#define CX23885_BOARD_DVICO_FUSIONHDTV_7_DUAL_EXP 10 /* Currently unsupported by the driver: PAL/H, NTSC/Kr, SECAM B/G/H/LC */ #define CX23885_NORMS (\ diff --git a/drivers/media/video/cx25840/cx25840-core.c b/drivers/media/video/cx25840/cx25840-core.c index 1da6f134888d..e7bf4f4c1319 100644 --- a/drivers/media/video/cx25840/cx25840-core.c +++ b/drivers/media/video/cx25840/cx25840-core.c @@ -50,7 +50,6 @@ MODULE_LICENSE("GPL"); static unsigned short normal_i2c[] = { 0x88 >> 1, I2C_CLIENT_END }; - int cx25840_debug; module_param_named(debug,cx25840_debug, int, 0644); @@ -238,7 +237,7 @@ static void cx25840_initialize(struct i2c_client *client) cx25840_write(client, 0x8d3, 0x1f); cx25840_write(client, 0x8e3, 0x03); - cx25840_vbi_setup(client); + cx25840_std_setup(client); /* trial and error says these are needed to get audio */ cx25840_write(client, 0x914, 0xa0); @@ -338,7 +337,7 @@ static void cx23885_initialize(struct i2c_client *client) finish_wait(&state->fw_wait, &wait); destroy_workqueue(q); - cx25840_vbi_setup(client); + cx25840_std_setup(client); /* (re)set input */ set_input(client, state->vid_input, state->aud_input); @@ -349,6 +348,153 @@ static void cx23885_initialize(struct i2c_client *client) /* ----------------------------------------------------------------------- */ +void cx25840_std_setup(struct i2c_client *client) +{ + struct cx25840_state *state = i2c_get_clientdata(client); + v4l2_std_id std = state->std; + int hblank, hactive, burst, vblank, vactive, sc; + int vblank656, src_decimation; + int luma_lpf, uv_lpf, comb; + u32 pll_int, pll_frac, pll_post; + + /* datasheet startup, step 8d */ + if (std & ~V4L2_STD_NTSC) + cx25840_write(client, 0x49f, 0x11); + else + cx25840_write(client, 0x49f, 0x14); + + if (std & V4L2_STD_625_50) { + hblank = 132; + hactive = 720; + burst = 93; + vblank = 36; + vactive = 580; + vblank656 = 40; + src_decimation = 0x21f; + luma_lpf = 2; + + if (std & V4L2_STD_SECAM) { + uv_lpf = 0; + comb = 0; + sc = 0x0a425f; + } else if (std == V4L2_STD_PAL_Nc) { + uv_lpf = 1; + comb = 0x20; + sc = 556453; + } else { + uv_lpf = 1; + comb = 0x20; + sc = 688739; + } + } else { + hactive = 720; + hblank = 122; + vactive = 487; + luma_lpf = 1; + uv_lpf = 1; + + src_decimation = 0x21f; + if (std == V4L2_STD_PAL_60) { + vblank = 26; + vblank656 = 26; + burst = 0x5b; + luma_lpf = 2; + comb = 0x20; + sc = 688739; + } else if (std == V4L2_STD_PAL_M) { + vblank = 20; + vblank656 = 24; + burst = 0x61; + comb = 0x20; + sc = 555452; + } else { + vblank = 26; + vblank656 = 26; + burst = 0x5b; + comb = 0x66; + sc = 556063; + } + } + + /* DEBUG: Displays configured PLL frequency */ + pll_int = cx25840_read(client, 0x108); + pll_frac = cx25840_read4(client, 0x10c) & 0x1ffffff; + pll_post = cx25840_read(client, 0x109); + v4l_dbg(1, cx25840_debug, client, + "PLL regs = int: %u, frac: %u, post: %u\n", + pll_int, pll_frac, pll_post); + + if (pll_post) { + int fin, fsc; + int pll = (28636363L * ((((u64)pll_int) << 25L) + pll_frac)) >> 25L; + + pll /= pll_post; + v4l_dbg(1, cx25840_debug, client, "PLL = %d.%06d MHz\n", + pll / 1000000, pll % 1000000); + v4l_dbg(1, cx25840_debug, client, "PLL/8 = %d.%06d MHz\n", + pll / 8000000, (pll / 8) % 1000000); + + fin = ((u64)src_decimation * pll) >> 12; + v4l_dbg(1, cx25840_debug, client, + "ADC Sampling freq = %d.%06d MHz\n", + fin / 1000000, fin % 1000000); + + fsc = (((u64)sc) * pll) >> 24L; + v4l_dbg(1, cx25840_debug, client, + "Chroma sub-carrier freq = %d.%06d MHz\n", + fsc / 1000000, fsc % 1000000); + + v4l_dbg(1, cx25840_debug, client, "hblank %i, hactive %i, " + "vblank %i, vactive %i, vblank656 %i, src_dec %i, " + "burst 0x%02x, luma_lpf %i, uv_lpf %i, comb 0x%02x, " + "sc 0x%06x\n", + hblank, hactive, vblank, vactive, vblank656, + src_decimation, burst, luma_lpf, uv_lpf, comb, sc); + } + + /* Sets horizontal blanking delay and active lines */ + cx25840_write(client, 0x470, hblank); + cx25840_write(client, 0x471, + 0xff & (((hblank >> 8) & 0x3) | (hactive << 4))); + cx25840_write(client, 0x472, hactive >> 4); + + /* Sets burst gate delay */ + cx25840_write(client, 0x473, burst); + + /* Sets vertical blanking delay and active duration */ + cx25840_write(client, 0x474, vblank); + cx25840_write(client, 0x475, + 0xff & (((vblank >> 8) & 0x3) | (vactive << 4))); + cx25840_write(client, 0x476, vactive >> 4); + cx25840_write(client, 0x477, vblank656); + + /* Sets src decimation rate */ + cx25840_write(client, 0x478, 0xff & src_decimation); + cx25840_write(client, 0x479, 0xff & (src_decimation >> 8)); + + /* Sets Luma and UV Low pass filters */ + cx25840_write(client, 0x47a, luma_lpf << 6 | ((uv_lpf << 4) & 0x30)); + + /* Enables comb filters */ + cx25840_write(client, 0x47b, comb); + + /* Sets SC Step*/ + cx25840_write(client, 0x47c, sc); + cx25840_write(client, 0x47d, 0xff & sc >> 8); + cx25840_write(client, 0x47e, 0xff & sc >> 16); + + /* Sets VBI parameters */ + if (std & V4L2_STD_625_50) { + cx25840_write(client, 0x47f, 0x01); + state->vbi_line_offset = 5; + } else { + cx25840_write(client, 0x47f, 0x00); + state->vbi_line_offset = 8; + } +} + +/* ----------------------------------------------------------------------- */ + static void input_change(struct i2c_client *client) { struct cx25840_state *state = i2c_get_clientdata(client); @@ -566,7 +712,7 @@ static int set_v4lstd(struct i2c_client *client) } cx25840_and_or(client, 0x400, ~0xf, fmt); cx25840_and_or(client, 0x403, ~0x3, pal_m); - cx25840_vbi_setup(client); + cx25840_std_setup(client); if (!state->is_cx25836) input_change(client); return 0; @@ -1058,6 +1204,8 @@ static int cx25840_command(struct i2c_client *client, unsigned int cmd, switch (qc->id) { case V4L2_CID_AUDIO_VOLUME: + return v4l2_ctrl_query_fill(qc, 0, 65535, + 65535 / 100, state->default_volume); case V4L2_CID_AUDIO_MUTE: case V4L2_CID_AUDIO_BALANCE: case V4L2_CID_AUDIO_BASS: @@ -1265,6 +1413,8 @@ static int cx25840_probe(struct i2c_client *client, state->pvr150_workaround = 0; state->audmode = V4L2_TUNER_MODE_LANG1; state->unmute_volume = -1; + state->default_volume = 228 - cx25840_read(client, 0x8d4); + state->default_volume = ((state->default_volume / 2) + 23) << 9; state->vbi_line_offset = 8; state->id = id; state->rev = device_id; diff --git a/drivers/media/video/cx25840/cx25840-core.h b/drivers/media/video/cx25840/cx25840-core.h index 8bf797f48b09..72916ba975a8 100644 --- a/drivers/media/video/cx25840/cx25840-core.h +++ b/drivers/media/video/cx25840/cx25840-core.h @@ -44,6 +44,7 @@ struct cx25840_state { u32 audclk_freq; int audmode; int unmute_volume; /* -1 if not muted */ + int default_volume; int vbi_line_offset; u32 id; u32 rev; @@ -61,6 +62,7 @@ int cx25840_write4(struct i2c_client *client, u16 addr, u32 value); u8 cx25840_read(struct i2c_client *client, u16 addr); u32 cx25840_read4(struct i2c_client *client, u16 addr); int cx25840_and_or(struct i2c_client *client, u16 addr, unsigned mask, u8 value); +void cx25840_std_setup(struct i2c_client *client); /* ----------------------------------------------------------------------- */ /* cx25850-firmware.c */ @@ -73,7 +75,6 @@ void cx25840_audio_set_path(struct i2c_client *client); /* ----------------------------------------------------------------------- */ /* cx25850-vbi.c */ -void cx25840_vbi_setup(struct i2c_client *client); int cx25840_vbi(struct i2c_client *client, unsigned int cmd, void *arg); #endif diff --git a/drivers/media/video/cx25840/cx25840-vbi.c b/drivers/media/video/cx25840/cx25840-vbi.c index c754b9d13369..69f2bbdbb929 100644 --- a/drivers/media/video/cx25840/cx25840-vbi.c +++ b/drivers/media/video/cx25840/cx25840-vbi.c @@ -82,150 +82,6 @@ static int decode_vps(u8 * dst, u8 * p) return err & 0xf0; } -void cx25840_vbi_setup(struct i2c_client *client) -{ - struct cx25840_state *state = i2c_get_clientdata(client); - v4l2_std_id std = state->std; - int hblank,hactive,burst,vblank,vactive,sc,vblank656,src_decimation; - int luma_lpf,uv_lpf, comb; - u32 pll_int,pll_frac,pll_post; - - /* datasheet startup, step 8d */ - if (std & ~V4L2_STD_NTSC) { - cx25840_write(client, 0x49f, 0x11); - } else { - cx25840_write(client, 0x49f, 0x14); - } - - if (std & V4L2_STD_625_50) { - hblank=0x084; - hactive=0x2d0; - burst=0x5d; - vblank=0x024; - vactive=0x244; - vblank656=0x28; - src_decimation=0x21f; - - luma_lpf=2; - if (std & V4L2_STD_SECAM) { - uv_lpf=0; - comb=0; - sc=0x0a425f; - } else if (std == V4L2_STD_PAL_Nc) { - uv_lpf=1; - comb=0x20; - sc=556453; - } else { - uv_lpf=1; - comb=0x20; - sc=0x0a8263; - } - } else { - hactive=720; - hblank=122; - vactive=487; - luma_lpf=1; - uv_lpf=1; - - src_decimation=0x21f; - if (std == V4L2_STD_PAL_60) { - vblank=26; - vblank656=26; - burst=0x5b; - luma_lpf=2; - comb=0x20; - sc=0x0a8263; - } else if (std == V4L2_STD_PAL_M) { - vblank=20; - vblank656=24; - burst=0x61; - comb=0x20; - - sc=555452; - } else { - vblank=26; - vblank656=26; - burst=0x5b; - comb=0x66; - sc=556063; - } - } - - /* DEBUG: Displays configured PLL frequency */ - pll_int=cx25840_read(client, 0x108); - pll_frac=cx25840_read4(client, 0x10c)&0x1ffffff; - pll_post=cx25840_read(client, 0x109); - v4l_dbg(1, cx25840_debug, client, - "PLL regs = int: %u, frac: %u, post: %u\n", - pll_int,pll_frac,pll_post); - - if (pll_post) { - int fin, fsc; - int pll= (28636363L*((((u64)pll_int)<<25L)+pll_frac)) >>25L; - - pll/=pll_post; - v4l_dbg(1, cx25840_debug, client, "PLL = %d.%06d MHz\n", - pll/1000000, pll%1000000); - v4l_dbg(1, cx25840_debug, client, "PLL/8 = %d.%06d MHz\n", - pll/8000000, (pll/8)%1000000); - - fin=((u64)src_decimation*pll)>>12; - v4l_dbg(1, cx25840_debug, client, "ADC Sampling freq = " - "%d.%06d MHz\n", - fin/1000000,fin%1000000); - - fsc= (((u64)sc)*pll) >> 24L; - v4l_dbg(1, cx25840_debug, client, "Chroma sub-carrier freq = " - "%d.%06d MHz\n", - fsc/1000000,fsc%1000000); - - v4l_dbg(1, cx25840_debug, client, "hblank %i, hactive %i, " - "vblank %i, vactive %i, vblank656 %i, src_dec %i, " - "burst 0x%02x, luma_lpf %i, uv_lpf %i, comb 0x%02x," - " sc 0x%06x\n", - hblank, hactive, vblank, vactive, vblank656, - src_decimation, burst, luma_lpf, uv_lpf, comb, sc); - } - - /* Sets horizontal blanking delay and active lines */ - cx25840_write(client, 0x470, hblank); - cx25840_write(client, 0x471, 0xff&(((hblank>>8)&0x3)|(hactive <<4))); - cx25840_write(client, 0x472, hactive>>4); - - /* Sets burst gate delay */ - cx25840_write(client, 0x473, burst); - - /* Sets vertical blanking delay and active duration */ - cx25840_write(client, 0x474, vblank); - cx25840_write(client, 0x475, 0xff&(((vblank>>8)&0x3)|(vactive <<4))); - cx25840_write(client, 0x476, vactive>>4); - cx25840_write(client, 0x477, vblank656); - - /* Sets src decimation rate */ - cx25840_write(client, 0x478, 0xff&src_decimation); - cx25840_write(client, 0x479, 0xff&(src_decimation>>8)); - - /* Sets Luma and UV Low pass filters */ - cx25840_write(client, 0x47a, luma_lpf<<6|((uv_lpf<<4)&0x30)); - - /* Enables comb filters */ - cx25840_write(client, 0x47b, comb); - - /* Sets SC Step*/ - cx25840_write(client, 0x47c, sc); - cx25840_write(client, 0x47d, 0xff&sc>>8); - cx25840_write(client, 0x47e, 0xff&sc>>16); - - /* Sets VBI parameters */ - if (std & V4L2_STD_625_50) { - cx25840_write(client, 0x47f, 0x01); - state->vbi_line_offset = 5; - } else { - cx25840_write(client, 0x47f, 0x00); - state->vbi_line_offset = 8; - } -} - int cx25840_vbi(struct i2c_client *client, unsigned int cmd, void *arg) { struct cx25840_state *state = i2c_get_clientdata(client); @@ -292,8 +148,8 @@ int cx25840_vbi(struct i2c_client *client, unsigned int cmd, void *arg) /* raw VBI */ memset(svbi, 0, sizeof(*svbi)); - /* Setup VBI */ - cx25840_vbi_setup(client); + /* Setup standard */ + cx25840_std_setup(client); /* VBI Offset */ cx25840_write(client, 0x47f, vbi_offset); @@ -304,8 +160,8 @@ int cx25840_vbi(struct i2c_client *client, unsigned int cmd, void *arg) for (x = 0; x <= 23; x++) lcr[x] = 0x00; - /* Setup VBI */ - cx25840_vbi_setup(client); + /* Setup standard */ + cx25840_std_setup(client); /* Sliced VBI */ cx25840_write(client, 0x404, 0x32); /* Ancillary data */ diff --git a/drivers/media/video/cx88/cx88-alsa.c b/drivers/media/video/cx88/cx88-alsa.c index 80c8883e54b5..06f171ab6149 100644 --- a/drivers/media/video/cx88/cx88-alsa.c +++ b/drivers/media/video/cx88/cx88-alsa.c @@ -82,7 +82,6 @@ typedef struct cx88_audio_dev snd_cx88_card_t; - /**************************************************************************** Module global static vars ****************************************************************************/ diff --git a/drivers/media/video/cx88/cx88-blackbird.c b/drivers/media/video/cx88/cx88-blackbird.c index 6c0c94c5ef91..bfdca5847764 100644 --- a/drivers/media/video/cx88/cx88-blackbird.c +++ b/drivers/media/video/cx88/cx88-blackbird.c @@ -715,7 +715,8 @@ static int vidioc_querymenu (struct file *file, void *priv, qctrl.id = qmenu->id; blackbird_queryctrl(dev, &qctrl); - return v4l2_ctrl_query_menu(qmenu, &qctrl, cx2341x_ctrl_get_menu(qmenu->id)); + return v4l2_ctrl_query_menu(qmenu, &qctrl, + cx2341x_ctrl_get_menu(&dev->params, qmenu->id)); } static int vidioc_querycap (struct file *file, void *priv, @@ -737,7 +738,7 @@ static int vidioc_querycap (struct file *file, void *priv, return 0; } -static int vidioc_enum_fmt_cap (struct file *file, void *priv, +static int vidioc_enum_fmt_vid_cap (struct file *file, void *priv, struct v4l2_fmtdesc *f) { if (f->index != 0) @@ -749,7 +750,7 @@ static int vidioc_enum_fmt_cap (struct file *file, void *priv, return 0; } -static int vidioc_g_fmt_cap (struct file *file, void *priv, +static int vidioc_g_fmt_vid_cap (struct file *file, void *priv, struct v4l2_format *f) { struct cx8802_fh *fh = priv; @@ -768,7 +769,7 @@ static int vidioc_g_fmt_cap (struct file *file, void *priv, return 0; } -static int vidioc_try_fmt_cap (struct file *file, void *priv, +static int vidioc_try_fmt_vid_cap (struct file *file, void *priv, struct v4l2_format *f) { struct cx8802_fh *fh = priv; @@ -784,7 +785,7 @@ static int vidioc_try_fmt_cap (struct file *file, void *priv, return 0; } -static int vidioc_s_fmt_cap (struct file *file, void *priv, +static int vidioc_s_fmt_vid_cap (struct file *file, void *priv, struct v4l2_format *f) { struct cx8802_fh *fh = priv; @@ -1181,10 +1182,10 @@ static struct video_device cx8802_mpeg_template = .minor = -1, .vidioc_querymenu = vidioc_querymenu, .vidioc_querycap = vidioc_querycap, - .vidioc_enum_fmt_cap = vidioc_enum_fmt_cap, - .vidioc_g_fmt_cap = vidioc_g_fmt_cap, - .vidioc_try_fmt_cap = vidioc_try_fmt_cap, - .vidioc_s_fmt_cap = vidioc_s_fmt_cap, + .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap, + .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap, + .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap, + .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap, .vidioc_reqbufs = vidioc_reqbufs, .vidioc_querybuf = vidioc_querybuf, .vidioc_qbuf = vidioc_qbuf, diff --git a/drivers/media/video/cx88/cx88-i2c.c b/drivers/media/video/cx88/cx88-i2c.c index cb6a096069c7..d7406a994f09 100644 --- a/drivers/media/video/cx88/cx88-i2c.c +++ b/drivers/media/video/cx88/cx88-i2c.c @@ -103,7 +103,6 @@ static int attach_inform(struct i2c_client *client) dprintk(1, "%s i2c attach [addr=0x%x,client=%s]\n", client->driver->driver.name, client->addr, client->name); - return 0; } diff --git a/drivers/media/video/cx88/cx88-video.c b/drivers/media/video/cx88/cx88-video.c index eea23f95edb7..0fed5cd2ccea 100644 --- a/drivers/media/video/cx88/cx88-video.c +++ b/drivers/media/video/cx88/cx88-video.c @@ -1045,7 +1045,7 @@ static void init_controls(struct cx88_core *core) /* ------------------------------------------------------------------ */ /* VIDEO IOCTLS */ -static int vidioc_g_fmt_cap (struct file *file, void *priv, +static int vidioc_g_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f) { struct cx8800_fh *fh = priv; @@ -1061,7 +1061,7 @@ static int vidioc_g_fmt_cap (struct file *file, void *priv, return 0; } -static int vidioc_try_fmt_cap (struct file *file, void *priv, +static int vidioc_try_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f) { struct cx88_core *core = ((struct cx8800_fh *)priv)->dev->core; @@ -1112,11 +1112,11 @@ static int vidioc_try_fmt_cap (struct file *file, void *priv, return 0; } -static int vidioc_s_fmt_cap (struct file *file, void *priv, +static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f) { struct cx8800_fh *fh = priv; - int err = vidioc_try_fmt_cap (file,priv,f); + int err = vidioc_try_fmt_vid_cap (file,priv,f); if (0 != err) return err; @@ -1147,7 +1147,7 @@ static int vidioc_querycap (struct file *file, void *priv, return 0; } -static int vidioc_enum_fmt_cap (struct file *file, void *priv, +static int vidioc_enum_fmt_vid_cap (struct file *file, void *priv, struct v4l2_fmtdesc *f) { if (unlikely(f->index >= ARRAY_SIZE(formats))) @@ -1690,13 +1690,13 @@ static struct video_device cx8800_video_template = .fops = &video_fops, .minor = -1, .vidioc_querycap = vidioc_querycap, - .vidioc_enum_fmt_cap = vidioc_enum_fmt_cap, - .vidioc_g_fmt_cap = vidioc_g_fmt_cap, - .vidioc_try_fmt_cap = vidioc_try_fmt_cap, - .vidioc_s_fmt_cap = vidioc_s_fmt_cap, - .vidioc_g_fmt_vbi = cx8800_vbi_fmt, - .vidioc_try_fmt_vbi = cx8800_vbi_fmt, - .vidioc_s_fmt_vbi = cx8800_vbi_fmt, + .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap, + .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap, + .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap, + .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap, + .vidioc_g_fmt_vbi_cap = cx8800_vbi_fmt, + .vidioc_try_fmt_vbi_cap = cx8800_vbi_fmt, + .vidioc_s_fmt_vbi_cap = cx8800_vbi_fmt, .vidioc_reqbufs = vidioc_reqbufs, .vidioc_querybuf = vidioc_querybuf, .vidioc_qbuf = vidioc_qbuf, diff --git a/drivers/media/video/cx88/cx88-vp3054-i2c.c b/drivers/media/video/cx88/cx88-vp3054-i2c.c index 6ce5af488471..20800425c51e 100644 --- a/drivers/media/video/cx88/cx88-vp3054-i2c.c +++ b/drivers/media/video/cx88/cx88-vp3054-i2c.c @@ -30,7 +30,6 @@ #include "cx88.h" #include "cx88-vp3054-i2c.h" - MODULE_DESCRIPTION("driver for cx2388x VP3054 design"); MODULE_AUTHOR("Chris Pascoe <c.pascoe@itee.uq.edu.au>"); MODULE_LICENSE("GPL"); diff --git a/drivers/media/video/em28xx/em28xx-cards.c b/drivers/media/video/em28xx/em28xx-cards.c index 8cbda43727c3..05f0d5a15058 100644 --- a/drivers/media/video/em28xx/em28xx-cards.c +++ b/drivers/media/video/em28xx/em28xx-cards.c @@ -173,6 +173,27 @@ struct em28xx_board em28xx_boards[] = { .amux = 1, } }, }, + [EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900_R2] = { + .name = "Hauppauge WinTV HVR 900 (R2)", + .vchannels = 3, + .tda9887_conf = TDA9887_PRESENT, + .tuner_type = TUNER_XC2028, + .mts_firmware = 1, + .decoder = EM28XX_TVP5150, + .input = { { + .type = EM28XX_VMUX_TELEVISION, + .vmux = TVP5150_COMPOSITE0, + .amux = 0, + }, { + .type = EM28XX_VMUX_COMPOSITE1, + .vmux = TVP5150_COMPOSITE1, + .amux = 1, + }, { + .type = EM28XX_VMUX_SVIDEO, + .vmux = TVP5150_SVIDEO, + .amux = 1, + } }, + }, [EM2880_BOARD_HAUPPAUGE_WINTV_HVR_950] = { .name = "Hauppauge WinTV HVR 950", .vchannels = 3, @@ -196,6 +217,29 @@ struct em28xx_board em28xx_boards[] = { .amux = 1, } }, }, + [EM2880_BOARD_PINNACLE_PCTV_HD_PRO] = { + .name = "Pinnacle PCTV HD Pro Stick", + .vchannels = 3, + .tda9887_conf = TDA9887_PRESENT, + .tuner_type = TUNER_XC2028, + .mts_firmware = 1, + .has_12mhz_i2s = 1, + .has_dvb = 1, + .decoder = EM28XX_TVP5150, + .input = { { + .type = EM28XX_VMUX_TELEVISION, + .vmux = TVP5150_COMPOSITE0, + .amux = 0, + }, { + .type = EM28XX_VMUX_COMPOSITE1, + .vmux = TVP5150_COMPOSITE1, + .amux = 1, + }, { + .type = EM28XX_VMUX_SVIDEO, + .vmux = TVP5150_SVIDEO, + .amux = 1, + } }, + }, [EM2880_BOARD_TERRATEC_HYBRID_XS] = { .name = "Terratec Hybrid XS", .vchannels = 3, @@ -382,6 +426,19 @@ struct em28xx_board em28xx_boards[] = { .amux = EM28XX_AMUX_LINE_IN, } }, }, + [EM2860_BOARD_POINTNIX_INTRAORAL_CAMERA] = { + .name = "PointNix Intra-Oral Camera", + .has_snapshot_button = 1, + .vchannels = 1, + .tda9887_conf = TDA9887_PRESENT, + .tuner_type = TUNER_ABSENT, + .decoder = EM28XX_SAA7113, + .input = { { + .type = EM28XX_VMUX_SVIDEO, + .vmux = SAA7115_SVIDEO3, + .amux = 0, + } }, + }, }; const unsigned int em28xx_bcount = ARRAY_SIZE(em28xx_boards); @@ -417,10 +474,12 @@ struct usb_device_id em28xx_id_table [] = { .driver_info = EM2820_BOARD_PINNACLE_DVC_90 }, { USB_DEVICE(0x2304, 0x021a), .driver_info = EM2820_BOARD_PINNACLE_DVC_90 }, + { USB_DEVICE(0x2304, 0x0227), + .driver_info = EM2880_BOARD_PINNACLE_PCTV_HD_PRO }, { USB_DEVICE(0x2040, 0x6500), .driver_info = EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900 }, { USB_DEVICE(0x2040, 0x6502), - .driver_info = EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900 }, + .driver_info = EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900_R2 }, { USB_DEVICE(0x2040, 0x6513), /* HCW HVR-980 */ .driver_info = EM2880_BOARD_HAUPPAUGE_WINTV_HVR_950 }, { USB_DEVICE(0x2040, 0x6517), /* HP HVR-950 */ @@ -476,6 +535,7 @@ static struct em28xx_hash_table em28xx_eeprom_hash [] = { static struct em28xx_hash_table em28xx_i2c_hash[] = { {0xb06a32c3, EM2800_BOARD_TERRATEC_CINERGY_200, TUNER_LG_PAL_NEW_TAPC}, {0xf51200e3, EM2800_BOARD_VGEAR_POCKETTV, TUNER_LG_PAL_NEW_TAPC}, + {0x1ba50080, EM2860_BOARD_POINTNIX_INTRAORAL_CAMERA, TUNER_ABSENT}, }; int em28xx_tuner_callback(void *ptr, int command, int arg) @@ -508,6 +568,7 @@ static void em28xx_set_model(struct em28xx *dev) dev->has_12mhz_i2s = em28xx_boards[dev->model].has_12mhz_i2s; dev->max_range_640_480 = em28xx_boards[dev->model].max_range_640_480; dev->has_dvb = em28xx_boards[dev->model].has_dvb; + dev->has_snapshot_button = em28xx_boards[dev->model].has_snapshot_button; } /* Since em28xx_pre_card_setup() requires a proper dev->model, @@ -542,8 +603,10 @@ void em28xx_pre_card_setup(struct em28xx *dev) switch (dev->model) { case EM2880_BOARD_TERRATEC_PRODIGY_XS: case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900: + case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900_R2: case EM2880_BOARD_TERRATEC_HYBRID_XS: case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_950: + case EM2880_BOARD_PINNACLE_PCTV_HD_PRO: em28xx_write_regs(dev, EM28XX_R0F_XCLK, "\x27", 1); em28xx_write_regs(dev, EM28XX_R06_I2C_CLK, "\x40", 1); msleep(50); @@ -576,7 +639,12 @@ static void em28xx_setup_xc3028(struct em28xx *dev, struct xc2028_ctrl *ctl) case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900: ctl->demod = XC3028_FE_ZARLINK456; break; + case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900_R2: + /* djh - Not sure which demod we need here */ + ctl->demod = XC3028_FE_DEFAULT; + break; case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_950: + case EM2880_BOARD_PINNACLE_PCTV_HD_PRO: /* FIXME: Better to specify the needed IF */ ctl->demod = XC3028_FE_DEFAULT; break; @@ -754,6 +822,7 @@ void em28xx_card_setup(struct em28xx *dev) switch (dev->model) { case EM2820_BOARD_HAUPPAUGE_WINTV_USB_2: case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900: + case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900_R2: case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_950: { struct tveeprom tv; @@ -787,6 +856,9 @@ void em28xx_card_setup(struct em28xx *dev) em28xx_set_model(dev); } + if (dev->has_snapshot_button) + em28xx_register_snapshot_button(dev); + /* Allow override tuner type by a module parameter */ if (tuner >= 0) dev->tuner_type = tuner; diff --git a/drivers/media/video/em28xx/em28xx-dvb.c b/drivers/media/video/em28xx/em28xx-dvb.c index 0b2333ee07f8..cc61cfb23a4a 100644 --- a/drivers/media/video/em28xx/em28xx-dvb.c +++ b/drivers/media/video/em28xx/em28xx-dvb.c @@ -5,6 +5,7 @@ (c) 2008 Devin Heitmueller <devin.heitmueller@gmail.com> - Fixes for the driver to properly work with HVR-950 + - Fixes for the driver to properly work with Pinnacle PCTV HD Pro Stick (c) 2008 Aidan Thornton <makosoft@googlemail.com> @@ -26,6 +27,9 @@ #include "lgdt330x.h" #include "zl10353.h" +#ifdef EM28XX_DRX397XD_SUPPORT +#include "drx397xD.h" +#endif MODULE_DESCRIPTION("driver for em28xx based DVB cards"); MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@infradead.org>"); @@ -227,6 +231,13 @@ static struct zl10353_config em28xx_zl10353_with_xc3028 = { .if2 = 45600, }; +#ifdef EM28XX_DRX397XD_SUPPORT +/* [TODO] djh - not sure yet what the device config needs to contain */ +static struct drx397xD_config em28xx_drx397xD_with_xc3028 = { + .demod_address = (0xe0 >> 1), +}; +#endif + /* ------------------------------------------------------------------ */ static int attach_xc3028(u8 addr, struct em28xx *dev) @@ -399,6 +410,7 @@ static int dvb_init(struct em28xx *dev) /* init frontend */ switch (dev->model) { case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_950: + case EM2880_BOARD_PINNACLE_PCTV_HD_PRO: dvb->frontend = dvb_attach(lgdt330x_attach, &em2880_lgdt3303_dev, &dev->i2c_adap); @@ -416,6 +428,19 @@ static int dvb_init(struct em28xx *dev) goto out_free; } break; + case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900_R2: +#ifdef EM28XX_DRX397XD_SUPPORT + /* We don't have the config structure properly populated, so + this is commented out for now */ + dvb->frontend = dvb_attach(drx397xD_attach, + &em28xx_drx397xD_with_xc3028, + &dev->i2c_adap); + if (attach_xc3028(0x61, dev) < 0) { + result = -EINVAL; + goto out_free; + } + break; +#endif default: printk(KERN_ERR "%s/2: The frontend of your DVB/ATSC card" " isn't supported yet\n", diff --git a/drivers/media/video/em28xx/em28xx-i2c.c b/drivers/media/video/em28xx/em28xx-i2c.c index 6a78fd294cab..97853384c943 100644 --- a/drivers/media/video/em28xx/em28xx-i2c.c +++ b/drivers/media/video/em28xx/em28xx-i2c.c @@ -432,7 +432,6 @@ static u32 functionality(struct i2c_adapter *adap) return I2C_FUNC_SMBUS_EMUL; } - /* * attach_inform() * gets called when a device attaches to the i2c bus diff --git a/drivers/media/video/em28xx/em28xx-input.c b/drivers/media/video/em28xx/em28xx-input.c index bb5807159b8d..eab3d9511af3 100644 --- a/drivers/media/video/em28xx/em28xx-input.c +++ b/drivers/media/video/em28xx/em28xx-input.c @@ -30,6 +30,10 @@ #include "em28xx.h" +#define EM28XX_SNAPSHOT_KEY KEY_CAMERA +#define EM28XX_SBUTTON_QUERY_INTERVAL 500 +#define EM28XX_R0C_USBSUSP_SNAPSHOT 0x20 + static unsigned int ir_debug; module_param(ir_debug, int, 0644); MODULE_PARM_DESC(ir_debug, "enable debug messages [IR]"); @@ -124,6 +128,89 @@ int em28xx_get_key_pinnacle_usb_grey(struct IR_i2c *ir, u32 *ir_key, return 1; } +static void em28xx_query_sbutton(struct work_struct *work) +{ + /* Poll the register and see if the button is depressed */ + struct em28xx *dev = + container_of(work, struct em28xx, sbutton_query_work.work); + int ret; + + ret = em28xx_read_reg(dev, EM28XX_R0C_USBSUSP); + + if (ret & EM28XX_R0C_USBSUSP_SNAPSHOT) { + u8 cleared; + /* Button is depressed, clear the register */ + cleared = ((u8) ret) & ~EM28XX_R0C_USBSUSP_SNAPSHOT; + em28xx_write_regs(dev, EM28XX_R0C_USBSUSP, &cleared, 1); + + /* Not emulate the keypress */ + input_report_key(dev->sbutton_input_dev, EM28XX_SNAPSHOT_KEY, + 1); + /* Now unpress the key */ + input_report_key(dev->sbutton_input_dev, EM28XX_SNAPSHOT_KEY, + 0); + } + + /* Schedule next poll */ + schedule_delayed_work(&dev->sbutton_query_work, + msecs_to_jiffies(EM28XX_SBUTTON_QUERY_INTERVAL)); +} + +void em28xx_register_snapshot_button(struct em28xx *dev) +{ + struct input_dev *input_dev; + int err; + + em28xx_info("Registering snapshot button...\n"); + input_dev = input_allocate_device(); + if (!input_dev) { + em28xx_errdev("input_allocate_device failed\n"); + return; + } + + usb_make_path(dev->udev, dev->snapshot_button_path, + sizeof(dev->snapshot_button_path)); + strlcat(dev->snapshot_button_path, "/sbutton", + sizeof(dev->snapshot_button_path)); + INIT_DELAYED_WORK(&dev->sbutton_query_work, em28xx_query_sbutton); + + input_dev->name = "em28xx snapshot button"; + input_dev->phys = dev->snapshot_button_path; + input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP); + set_bit(EM28XX_SNAPSHOT_KEY, input_dev->keybit); + input_dev->keycodesize = 0; + input_dev->keycodemax = 0; + input_dev->id.bustype = BUS_USB; + input_dev->id.vendor = le16_to_cpu(dev->udev->descriptor.idVendor); + input_dev->id.product = le16_to_cpu(dev->udev->descriptor.idProduct); + input_dev->id.version = 1; + input_dev->dev.parent = &dev->udev->dev; + + err = input_register_device(input_dev); + if (err) { + em28xx_errdev("input_register_device failed\n"); + input_free_device(input_dev); + return; + } + + dev->sbutton_input_dev = input_dev; + schedule_delayed_work(&dev->sbutton_query_work, + msecs_to_jiffies(EM28XX_SBUTTON_QUERY_INTERVAL)); + return; + +} + +void em28xx_deregister_snapshot_button(struct em28xx *dev) +{ + if (dev->sbutton_input_dev != NULL) { + em28xx_info("Deregistering snapshot button\n"); + cancel_rearming_delayed_work(&dev->sbutton_query_work); + input_unregister_device(dev->sbutton_input_dev); + dev->sbutton_input_dev = NULL; + } + return; +} + /* ---------------------------------------------------------------------- * Local variables: * c-basic-offset: 8 diff --git a/drivers/media/video/em28xx/em28xx-video.c b/drivers/media/video/em28xx/em28xx-video.c index 285bc62bbe46..2d9f14d2a00b 100644 --- a/drivers/media/video/em28xx/em28xx-video.c +++ b/drivers/media/video/em28xx/em28xx-video.c @@ -683,7 +683,7 @@ static void get_scale(struct em28xx *dev, IOCTL vidioc handling ------------------------------------------------------------------*/ -static int vidioc_g_fmt_cap(struct file *file, void *priv, +static int vidioc_g_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f) { struct em28xx_fh *fh = priv; @@ -706,7 +706,7 @@ static int vidioc_g_fmt_cap(struct file *file, void *priv, return 0; } -static int vidioc_try_fmt_cap(struct file *file, void *priv, +static int vidioc_try_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f) { struct em28xx_fh *fh = priv; @@ -766,7 +766,7 @@ static int vidioc_try_fmt_cap(struct file *file, void *priv, return 0; } -static int vidioc_s_fmt_cap(struct file *file, void *priv, +static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f) { struct em28xx_fh *fh = priv; @@ -777,7 +777,7 @@ static int vidioc_s_fmt_cap(struct file *file, void *priv, if (rc < 0) return rc; - vidioc_try_fmt_cap(file, priv, f); + vidioc_try_fmt_vid_cap(file, priv, f); mutex_lock(&dev->lock); @@ -826,7 +826,7 @@ static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id * norm) /* Adjusts width/height, if needed */ f.fmt.pix.width = dev->width; f.fmt.pix.height = dev->height; - vidioc_try_fmt_cap(file, priv, &f); + vidioc_try_fmt_vid_cap(file, priv, &f); mutex_lock(&dev->lock); @@ -1277,7 +1277,7 @@ static int vidioc_querycap(struct file *file, void *priv, return 0; } -static int vidioc_enum_fmt_cap(struct file *file, void *priv, +static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv, struct v4l2_fmtdesc *fmtd) { if (fmtd->index != 0) @@ -1292,7 +1292,7 @@ static int vidioc_enum_fmt_cap(struct file *file, void *priv, } /* Sliced VBI ioctls */ -static int vidioc_g_fmt_vbi_capture(struct file *file, void *priv, +static int vidioc_g_fmt_sliced_vbi_cap(struct file *file, void *priv, struct v4l2_format *f) { struct em28xx_fh *fh = priv; @@ -1316,7 +1316,7 @@ static int vidioc_g_fmt_vbi_capture(struct file *file, void *priv, return rc; } -static int vidioc_try_set_vbi_capture(struct file *file, void *priv, +static int vidioc_try_set_sliced_vbi_cap(struct file *file, void *priv, struct v4l2_format *f) { struct em28xx_fh *fh = priv; @@ -1590,6 +1590,8 @@ static void em28xx_release_resources(struct em28xx *dev) dev->vdev->minor-MINOR_VFL_TYPE_GRABBER_MIN, dev->vbi_dev->minor-MINOR_VFL_TYPE_VBI_MIN); list_del(&dev->devlist); + if (dev->sbutton_input_dev) + em28xx_deregister_snapshot_button(dev); if (dev->radio_dev) { if (-1 != dev->radio_dev->minor) video_unregister_device(dev->radio_dev); @@ -1776,17 +1778,17 @@ static const struct video_device em28xx_video_template = { .minor = -1, .vidioc_querycap = vidioc_querycap, - .vidioc_enum_fmt_cap = vidioc_enum_fmt_cap, - .vidioc_g_fmt_cap = vidioc_g_fmt_cap, - .vidioc_try_fmt_cap = vidioc_try_fmt_cap, - .vidioc_s_fmt_cap = vidioc_s_fmt_cap, + .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap, + .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap, + .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap, + .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap, .vidioc_g_audio = vidioc_g_audio, .vidioc_s_audio = vidioc_s_audio, .vidioc_cropcap = vidioc_cropcap, - .vidioc_g_fmt_vbi_capture = vidioc_g_fmt_vbi_capture, - .vidioc_try_fmt_vbi_capture = vidioc_try_set_vbi_capture, - .vidioc_s_fmt_vbi_capture = vidioc_try_set_vbi_capture, + .vidioc_g_fmt_sliced_vbi_cap = vidioc_g_fmt_sliced_vbi_cap, + .vidioc_try_fmt_sliced_vbi_cap = vidioc_try_set_sliced_vbi_cap, + .vidioc_s_fmt_sliced_vbi_cap = vidioc_try_set_sliced_vbi_cap, .vidioc_reqbufs = vidioc_reqbufs, .vidioc_querybuf = vidioc_querybuf, diff --git a/drivers/media/video/em28xx/em28xx.h b/drivers/media/video/em28xx/em28xx.h index 002f170b211a..89842c5d64a1 100644 --- a/drivers/media/video/em28xx/em28xx.h +++ b/drivers/media/video/em28xx/em28xx.h @@ -55,6 +55,9 @@ #define EM2820_BOARD_PROLINK_PLAYTV_USB2 14 #define EM2800_BOARD_VGEAR_POCKETTV 15 #define EM2880_BOARD_HAUPPAUGE_WINTV_HVR_950 16 +#define EM2880_BOARD_PINNACLE_PCTV_HD_PRO 17 +#define EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900_R2 18 +#define EM2860_BOARD_POINTNIX_INTRAORAL_CAMERA 19 /* Limits minimum and default number of buffers */ #define EM28XX_MIN_BUF 4 @@ -247,6 +250,7 @@ struct em28xx_board { unsigned int has_12mhz_i2s:1; unsigned int max_range_640_480:1; unsigned int has_dvb:1; + unsigned int has_snapshot_button:1; enum em28xx_decoder decoder; @@ -326,6 +330,7 @@ struct em28xx { unsigned int has_12mhz_i2s:1; unsigned int max_range_640_480:1; unsigned int has_dvb:1; + unsigned int has_snapshot_button:1; /* Some older em28xx chips needs a waiting time after writing */ unsigned int wait_after_write; @@ -416,6 +421,11 @@ struct em28xx { /* Caches GPO and GPIO registers */ unsigned char reg_gpo, reg_gpio; + /* Snapshot button */ + char snapshot_button_path[30]; /* path of the input dev */ + struct input_dev *sbutton_input_dev; + struct delayed_work sbutton_query_work; + struct em28xx_dvb *dvb; }; @@ -481,6 +491,8 @@ int em28xx_get_key_terratec(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw); int em28xx_get_key_em_haup(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw); int em28xx_get_key_pinnacle_usb_grey(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw); +void em28xx_register_snapshot_button(struct em28xx *dev); +void em28xx_deregister_snapshot_button(struct em28xx *dev); /* printk macros */ diff --git a/drivers/media/video/gspca/Kconfig b/drivers/media/video/gspca/Kconfig new file mode 100644 index 000000000000..42b90742b40b --- /dev/null +++ b/drivers/media/video/gspca/Kconfig @@ -0,0 +1,13 @@ +config USB_GSPCA + tristate "USB GSPCA driver" + depends on VIDEO_V4L2 + ---help--- + Say Y here if you want support for various USB webcams. + + See <file:Documentation/video4linux/gspca.txt> for more info. + + This driver uses the Video For Linux API. You must say Y or M to + "Video For Linux" to use this driver. + + To compile this driver as modules, choose M here: the + modules will be called gspca_xxxx. diff --git a/drivers/media/video/gspca/Makefile b/drivers/media/video/gspca/Makefile new file mode 100644 index 000000000000..e68a8965297a --- /dev/null +++ b/drivers/media/video/gspca/Makefile @@ -0,0 +1,29 @@ +obj-$(CONFIG_USB_GSPCA) += gspca_main.o \ + gspca_conex.o gspca_etoms.o gspca_mars.o \ + gspca_ov519.o gspca_pac207.o gspca_pac7311.o \ + gspca_sonixb.o gspca_sonixj.o gspca_spca500.o gspca_spca501.o \ + gspca_spca505.o gspca_spca506.o gspca_spca508.o gspca_spca561.o \ + gspca_sunplus.o gspca_stk014.o gspca_t613.o gspca_tv8532.o \ + gspca_vc032x.o gspca_zc3xx.o + +gspca_main-objs := gspca.o +gspca_conex-objs := conex.o +gspca_etoms-objs := etoms.o +gspca_mars-objs := mars.o +gspca_ov519-objs := ov519.o +gspca_pac207-objs := pac207.o +gspca_pac7311-objs := pac7311.o +gspca_sonixb-objs := sonixb.o +gspca_sonixj-objs := sonixj.o +gspca_spca500-objs := spca500.o +gspca_spca501-objs := spca501.o +gspca_spca505-objs := spca505.o +gspca_spca506-objs := spca506.o +gspca_spca508-objs := spca508.o +gspca_spca561-objs := spca561.o +gspca_stk014-objs := stk014.o +gspca_sunplus-objs := sunplus.o +gspca_t613-objs := t613.o +gspca_tv8532-objs := tv8532.o +gspca_vc032x-objs := vc032x.o +gspca_zc3xx-objs := zc3xx.o diff --git a/drivers/media/video/gspca/conex.c b/drivers/media/video/gspca/conex.c new file mode 100644 index 000000000000..013d593b0c67 --- /dev/null +++ b/drivers/media/video/gspca/conex.c @@ -0,0 +1,1051 @@ +/* + * Connexant Cx11646 library + * Copyright (C) 2004 Michel Xhaard mxhaard@magic.fr + * + * V4L2 by Jean-Francois Moine <http://moinejf.free.fr> + * + * 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 + * 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 + */ + +#define MODULE_NAME "conex" + +#include "gspca.h" +#define CONEX_CAM 1 /* special JPEG header */ +#include "jpeg.h" + +#define DRIVER_VERSION_NUMBER KERNEL_VERSION(2, 1, 7) +static const char version[] = "2.1.7"; + +MODULE_AUTHOR("Michel Xhaard <mxhaard@users.sourceforge.net>"); +MODULE_DESCRIPTION("GSPCA USB Conexant Camera Driver"); +MODULE_LICENSE("GPL"); + +/* specific webcam descriptor */ +struct sd { + struct gspca_dev gspca_dev; /* !! must be the first item */ + + unsigned char brightness; + unsigned char contrast; + unsigned char colors; + + unsigned char qindex; +}; + +/* V4L2 controls supported by the driver */ +static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val); +static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val); +static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val); +static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val); +static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val); +static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val); + +static struct ctrl sd_ctrls[] = { + { + { + .id = V4L2_CID_BRIGHTNESS, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Brightness", + .minimum = 0, + .maximum = 255, + .step = 1, +#define BRIGHTNESS_DEF 0xd4 + .default_value = BRIGHTNESS_DEF, + }, + .set = sd_setbrightness, + .get = sd_getbrightness, + }, + { + { + .id = V4L2_CID_CONTRAST, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Contrast", + .minimum = 0x0a, + .maximum = 0x1f, + .step = 1, +#define CONTRAST_DEF 0x0c + .default_value = CONTRAST_DEF, + }, + .set = sd_setcontrast, + .get = sd_getcontrast, + }, + { + { + .id = V4L2_CID_SATURATION, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Color", + .minimum = 0, + .maximum = 7, + .step = 1, +#define COLOR_DEF 3 + .default_value = COLOR_DEF, + }, + .set = sd_setcolors, + .get = sd_getcolors, + }, +}; + +static struct v4l2_pix_format vga_mode[] = { + {176, 144, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, + .bytesperline = 176, + .sizeimage = 176 * 144 * 3 / 8 + 590, + .colorspace = V4L2_COLORSPACE_JPEG, + .priv = 3}, + {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, + .bytesperline = 320, + .sizeimage = 320 * 240 * 3 / 8 + 590, + .colorspace = V4L2_COLORSPACE_JPEG, + .priv = 2}, + {352, 288, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, + .bytesperline = 352, + .sizeimage = 352 * 288 * 3 / 8 + 590, + .colorspace = V4L2_COLORSPACE_JPEG, + .priv = 1}, + {640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, + .bytesperline = 640, + .sizeimage = 640 * 480 * 3 / 8 + 590, + .colorspace = V4L2_COLORSPACE_JPEG, + .priv = 0}, +}; + +/* the read bytes are found in gspca_dev->usb_buf */ +static void reg_r(struct gspca_dev *gspca_dev, + __u16 index, + __u16 len) +{ + struct usb_device *dev = gspca_dev->dev; + +#ifdef CONFIG_VIDEO_ADV_DEBUG + if (len > sizeof gspca_dev->usb_buf) { + err("reg_r: buffer overflow"); + return; + } +#endif + usb_control_msg(dev, + usb_rcvctrlpipe(dev, 0), + 0, + USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + 0, + index, gspca_dev->usb_buf, len, + 500); + PDEBUG(D_USBI, "reg read [%02x] -> %02x ..", + index, gspca_dev->usb_buf[0]); +} + +/* the bytes to write are in gspca_dev->usb_buf */ +static void reg_w_val(struct gspca_dev *gspca_dev, + __u16 index, + __u8 val) +{ + struct usb_device *dev = gspca_dev->dev; + + gspca_dev->usb_buf[0] = val; + usb_control_msg(dev, + usb_sndctrlpipe(dev, 0), + 0, + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + 0, + index, gspca_dev->usb_buf, 1, 500); +} + +static void reg_w(struct gspca_dev *gspca_dev, + __u16 index, + const __u8 *buffer, + __u16 len) +{ + struct usb_device *dev = gspca_dev->dev; + +#ifdef CONFIG_VIDEO_ADV_DEBUG + if (len > sizeof gspca_dev->usb_buf) { + err("reg_w: buffer overflow"); + return; + } + PDEBUG(D_USBO, "reg write [%02x] = %02x..", index, *buffer); +#endif + memcpy(gspca_dev->usb_buf, buffer, len); + usb_control_msg(dev, + usb_sndctrlpipe(dev, 0), + 0, + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + 0, + index, gspca_dev->usb_buf, len, 500); +} + +static const __u8 cx_sensor_init[][4] = { + {0x88, 0x11, 0x01, 0x01}, + {0x88, 0x12, 0x70, 0x01}, + {0x88, 0x0f, 0x00, 0x01}, + {0x88, 0x05, 0x01, 0x01}, + {} +}; + +static const __u8 cx11646_fw1[][3] = { + {0x00, 0x02, 0x00}, + {0x01, 0x43, 0x00}, + {0x02, 0xA7, 0x00}, + {0x03, 0x8B, 0x01}, + {0x04, 0xE9, 0x02}, + {0x05, 0x08, 0x04}, + {0x06, 0x08, 0x05}, + {0x07, 0x07, 0x06}, + {0x08, 0xE7, 0x06}, + {0x09, 0xC6, 0x07}, + {0x0A, 0x86, 0x08}, + {0x0B, 0x46, 0x09}, + {0x0C, 0x05, 0x0A}, + {0x0D, 0xA5, 0x0A}, + {0x0E, 0x45, 0x0B}, + {0x0F, 0xE5, 0x0B}, + {0x10, 0x85, 0x0C}, + {0x11, 0x25, 0x0D}, + {0x12, 0xC4, 0x0D}, + {0x13, 0x45, 0x0E}, + {0x14, 0xE4, 0x0E}, + {0x15, 0x64, 0x0F}, + {0x16, 0xE4, 0x0F}, + {0x17, 0x64, 0x10}, + {0x18, 0xE4, 0x10}, + {0x19, 0x64, 0x11}, + {0x1A, 0xE4, 0x11}, + {0x1B, 0x64, 0x12}, + {0x1C, 0xE3, 0x12}, + {0x1D, 0x44, 0x13}, + {0x1E, 0xC3, 0x13}, + {0x1F, 0x24, 0x14}, + {0x20, 0xA3, 0x14}, + {0x21, 0x04, 0x15}, + {0x22, 0x83, 0x15}, + {0x23, 0xE3, 0x15}, + {0x24, 0x43, 0x16}, + {0x25, 0xA4, 0x16}, + {0x26, 0x23, 0x17}, + {0x27, 0x83, 0x17}, + {0x28, 0xE3, 0x17}, + {0x29, 0x43, 0x18}, + {0x2A, 0xA3, 0x18}, + {0x2B, 0x03, 0x19}, + {0x2C, 0x63, 0x19}, + {0x2D, 0xC3, 0x19}, + {0x2E, 0x22, 0x1A}, + {0x2F, 0x63, 0x1A}, + {0x30, 0xC3, 0x1A}, + {0x31, 0x23, 0x1B}, + {0x32, 0x83, 0x1B}, + {0x33, 0xE2, 0x1B}, + {0x34, 0x23, 0x1C}, + {0x35, 0x83, 0x1C}, + {0x36, 0xE2, 0x1C}, + {0x37, 0x23, 0x1D}, + {0x38, 0x83, 0x1D}, + {0x39, 0xE2, 0x1D}, + {0x3A, 0x23, 0x1E}, + {0x3B, 0x82, 0x1E}, + {0x3C, 0xC3, 0x1E}, + {0x3D, 0x22, 0x1F}, + {0x3E, 0x63, 0x1F}, + {0x3F, 0xC1, 0x1F}, + {} +}; +static void cx11646_fw(struct gspca_dev*gspca_dev) +{ + int i = 0; + + reg_w_val(gspca_dev, 0x006a, 0x02); + while (cx11646_fw1[i][1]) { + reg_w(gspca_dev, 0x006b, cx11646_fw1[i], 3); + i++; + } + reg_w_val(gspca_dev, 0x006a, 0x00); +} + +static const __u8 cxsensor[] = { + 0x88, 0x12, 0x70, 0x01, + 0x88, 0x0d, 0x02, 0x01, + 0x88, 0x0f, 0x00, 0x01, + 0x88, 0x03, 0x71, 0x01, 0x88, 0x04, 0x00, 0x01, /* 3 */ + 0x88, 0x02, 0x10, 0x01, + 0x88, 0x00, 0xD4, 0x01, 0x88, 0x01, 0x01, 0x01, /* 5 */ + 0x88, 0x0B, 0x00, 0x01, + 0x88, 0x0A, 0x0A, 0x01, + 0x88, 0x00, 0x08, 0x01, 0x88, 0x01, 0x00, 0x01, /* 8 */ + 0x88, 0x05, 0x01, 0x01, + 0xA1, 0x18, 0x00, 0x01, + 0x00 +}; + +static const __u8 reg20[] = { 0x10, 0x42, 0x81, 0x19, 0xd3, 0xff, 0xa7, 0xff }; +static const __u8 reg28[] = { 0x87, 0x00, 0x87, 0x00, 0x8f, 0xff, 0xea, 0xff }; +static const __u8 reg10[] = { 0xb1, 0xb1 }; +static const __u8 reg71a[] = { 0x08, 0x18, 0x0a, 0x1e }; /* 640 */ +static const __u8 reg71b[] = { 0x04, 0x0c, 0x05, 0x0f }; + /* 352{0x04,0x0a,0x06,0x12}; //352{0x05,0x0e,0x06,0x11}; //352 */ +static const __u8 reg71c[] = { 0x02, 0x07, 0x03, 0x09 }; + /* 320{0x04,0x0c,0x05,0x0f}; //320 */ +static const __u8 reg71d[] = { 0x02, 0x07, 0x03, 0x09 }; /* 176 */ +static const __u8 reg7b[] = { 0x00, 0xff, 0x00, 0xff, 0x00, 0xff }; + +static void cx_sensor(struct gspca_dev*gspca_dev) +{ + int i = 0; + int length; + const __u8 *ptsensor = cxsensor; + + reg_w(gspca_dev, 0x0020, reg20, 8); + reg_w(gspca_dev, 0x0028, reg28, 8); + reg_w(gspca_dev, 0x0010, reg10, 8); + reg_w_val(gspca_dev, 0x0092, 0x03); + + switch (gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv) { + case 0: + reg_w(gspca_dev, 0x0071, reg71a, 4); + break; + case 1: + reg_w(gspca_dev, 0x0071, reg71b, 4); + break; + default: +/* case 2: */ + reg_w(gspca_dev, 0x0071, reg71c, 4); + break; + case 3: + reg_w(gspca_dev, 0x0071, reg71d, 4); + break; + } + reg_w(gspca_dev, 0x007b, reg7b, 6); + reg_w_val(gspca_dev, 0x00f8, 0x00); + reg_w(gspca_dev, 0x0010, reg10, 8); + reg_w_val(gspca_dev, 0x0098, 0x41); + for (i = 0; i < 11; i++) { + if (i == 3 || i == 5 || i == 8) + length = 8; + else + length = 4; + reg_w(gspca_dev, 0x00e5, ptsensor, length); + if (length == 4) + reg_r(gspca_dev, 0x00e8, 1); + else + reg_r(gspca_dev, 0x00e8, length); + ptsensor += length; + } + reg_r(gspca_dev, 0x00e7, 8); +} + +static const __u8 cx_inits_176[] = { + 0x33, 0x81, 0xB0, 0x00, 0x90, 0x00, 0x0A, 0x03, /* 176x144 */ + 0x00, 0x03, 0x03, 0x03, 0x1B, 0x05, 0x30, 0x03, + 0x65, 0x15, 0x18, 0x25, 0x03, 0x25, 0x08, 0x30, + 0x3B, 0x25, 0x10, 0x00, 0x04, 0x00, 0x00, 0x00, + 0xDC, 0xFF, 0xEE, 0xFF, 0xC5, 0xFF, 0xBF, 0xFF, + 0xF7, 0xFF, 0x88, 0xFF, 0x66, 0x02, 0x28, 0x02, + 0x1E, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; +static const __u8 cx_inits_320[] = { + 0x7f, 0x7f, 0x40, 0x01, 0xf0, 0x00, 0x02, 0x01, + 0x00, 0x01, 0x01, 0x01, 0x10, 0x00, 0x02, 0x01, + 0x65, 0x45, 0xfa, 0x4c, 0x2c, 0xdf, 0xb9, 0x81, + 0x30, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0xe2, 0xff, 0xf1, 0xff, 0xc2, 0xff, 0xbc, 0xff, + 0xf5, 0xff, 0x6d, 0xff, 0xf6, 0x01, 0x43, 0x02, + 0xd3, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; +static const __u8 cx_inits_352[] = { + 0x2e, 0x7c, 0x60, 0x01, 0x20, 0x01, 0x05, 0x03, + 0x00, 0x06, 0x03, 0x06, 0x1b, 0x10, 0x05, 0x3b, + 0x30, 0x25, 0x18, 0x25, 0x08, 0x30, 0x03, 0x25, + 0x3b, 0x30, 0x25, 0x1b, 0x10, 0x05, 0x00, 0x00, + 0xe3, 0xff, 0xf1, 0xff, 0xc2, 0xff, 0xbc, 0xff, + 0xf5, 0xff, 0x6b, 0xff, 0xee, 0x01, 0x43, 0x02, + 0xe4, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; +static const __u8 cx_inits_640[] = { + 0x7e, 0x7e, 0x80, 0x02, 0xe0, 0x01, 0x01, 0x01, + 0x00, 0x02, 0x01, 0x02, 0x10, 0x30, 0x01, 0x01, + 0x65, 0x45, 0xf7, 0x52, 0x2c, 0xdf, 0xb9, 0x81, + 0x30, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0xe2, 0xff, 0xf1, 0xff, 0xc2, 0xff, 0xbc, 0xff, + 0xf6, 0xff, 0x7b, 0xff, 0x01, 0x02, 0x43, 0x02, + 0x77, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +static void cx11646_initsize(struct gspca_dev *gspca_dev) +{ + const __u8 *cxinit; + static const __u8 reg12[] = { 0x08, 0x05, 0x07, 0x04, 0x24 }; + static const __u8 reg17[] = + { 0x0a, 0x00, 0xf2, 0x01, 0x0f, 0x00, 0x97, 0x02 }; + + switch (gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv) { + case 0: + cxinit = cx_inits_640; + break; + case 1: + cxinit = cx_inits_352; + break; + default: +/* case 2: */ + cxinit = cx_inits_320; + break; + case 3: + cxinit = cx_inits_176; + break; + } + reg_w_val(gspca_dev, 0x009a, 0x01); + reg_w_val(gspca_dev, 0x0010, 0x10); + reg_w(gspca_dev, 0x0012, reg12, 5); + reg_w(gspca_dev, 0x0017, reg17, 8); + reg_w_val(gspca_dev, 0x00c0, 0x00); + reg_w_val(gspca_dev, 0x00c1, 0x04); + reg_w_val(gspca_dev, 0x00c2, 0x04); + + reg_w(gspca_dev, 0x0061, cxinit, 8); + cxinit += 8; + reg_w(gspca_dev, 0x00ca, cxinit, 8); + cxinit += 8; + reg_w(gspca_dev, 0x00d2, cxinit, 8); + cxinit += 8; + reg_w(gspca_dev, 0x00da, cxinit, 6); + cxinit += 8; + reg_w(gspca_dev, 0x0041, cxinit, 8); + cxinit += 8; + reg_w(gspca_dev, 0x0049, cxinit, 8); + cxinit += 8; + reg_w(gspca_dev, 0x0051, cxinit, 2); + + reg_r(gspca_dev, 0x0010, 1); +} + +static const __u8 cx_jpeg_init[][8] = { + {0xff, 0xd8, 0xff, 0xdb, 0x00, 0x84, 0x00, 0x15}, /* 1 */ + {0x0f, 0x10, 0x12, 0x10, 0x0d, 0x15, 0x12, 0x11}, + {0x12, 0x18, 0x16, 0x15, 0x19, 0x20, 0x35, 0x22}, + {0x20, 0x1d, 0x1d, 0x20, 0x41, 0x2e, 0x31, 0x26}, + {0x35, 0x4d, 0x43, 0x51, 0x4f, 0x4b, 0x43, 0x4a}, + {0x49, 0x55, 0x5F, 0x79, 0x67, 0x55, 0x5A, 0x73}, + {0x5B, 0x49, 0x4A, 0x6A, 0x90, 0x6B, 0x73, 0x7D}, + {0x81, 0x88, 0x89, 0x88, 0x52, 0x66, 0x95, 0xA0}, + {0x94, 0x84, 0x9E, 0x79, 0x85, 0x88, 0x83, 0x01}, + {0x15, 0x0F, 0x10, 0x12, 0x10, 0x0D, 0x15, 0x12}, + {0x11, 0x12, 0x18, 0x16, 0x15, 0x19, 0x20, 0x35}, + {0x22, 0x20, 0x1D, 0x1D, 0x20, 0x41, 0x2E, 0x31}, + {0x26, 0x35, 0x4D, 0x43, 0x51, 0x4F, 0x4B, 0x43}, + {0x4A, 0x49, 0x55, 0x5F, 0x79, 0x67, 0x55, 0x5A}, + {0x73, 0x5B, 0x49, 0x4A, 0x6A, 0x90, 0x6B, 0x73}, + {0x7D, 0x81, 0x88, 0x89, 0x88, 0x52, 0x66, 0x95}, + {0xA0, 0x94, 0x84, 0x9E, 0x79, 0x85, 0x88, 0x83}, + {0xFF, 0xC4, 0x01, 0xA2, 0x00, 0x00, 0x01, 0x05}, + {0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02}, + {0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A}, + {0x0B, 0x01, 0x00, 0x03, 0x01, 0x01, 0x01, 0x01}, + {0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05}, + {0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x10, 0x00}, + {0x02, 0x01, 0x03, 0x03, 0x02, 0x04, 0x03, 0x05}, + {0x05, 0x04, 0x04, 0x00, 0x00, 0x01, 0x7D, 0x01}, + {0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12, 0x21}, + {0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07, 0x22}, + {0x71, 0x14, 0x32, 0x81, 0x91, 0xA1, 0x08, 0x23}, + {0x42, 0xB1, 0xC1, 0x15, 0x52, 0xD1, 0xF0, 0x24}, + {0x33, 0x62, 0x72, 0x82, 0x09, 0x0A, 0x16, 0x17}, + {0x18, 0x19, 0x1A, 0x25, 0x26, 0x27, 0x28, 0x29}, + {0x2A, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A}, + {0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A}, + {0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A}, + {0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A}, + {0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A}, + {0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A}, + {0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99}, + {0x9A, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8}, + {0xA9, 0xAA, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7}, + {0xB8, 0xB9, 0xBA, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6}, + {0xC7, 0xC8, 0xC9, 0xCA, 0xD2, 0xD3, 0xD4, 0xD5}, + {0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xE1, 0xE2, 0xE3}, + {0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xF1}, + {0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9}, + {0xFA, 0x11, 0x00, 0x02, 0x01, 0x02, 0x04, 0x04}, + {0x03, 0x04, 0x07, 0x05, 0x04, 0x04, 0x00, 0x01}, + {0x02, 0x77, 0x00, 0x01, 0x02, 0x03, 0x11, 0x04}, + {0x05, 0x21, 0x31, 0x06, 0x12, 0x41, 0x51, 0x07}, + {0x61, 0x71, 0x13, 0x22, 0x32, 0x81, 0x08, 0x14}, + {0x42, 0x91, 0xA1, 0xB1, 0xC1, 0x09, 0x23, 0x33}, + {0x52, 0xF0, 0x15, 0x62, 0x72, 0xD1, 0x0A, 0x16}, + {0x24, 0x34, 0xE1, 0x25, 0xF1, 0x17, 0x18, 0x19}, + {0x1A, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x35, 0x36}, + {0x37, 0x38, 0x39, 0x3A, 0x43, 0x44, 0x45, 0x46}, + {0x47, 0x48, 0x49, 0x4A, 0x53, 0x54, 0x55, 0x56}, + {0x57, 0x58, 0x59, 0x5A, 0x63, 0x64, 0x65, 0x66}, + {0x67, 0x68, 0x69, 0x6A, 0x73, 0x74, 0x75, 0x76}, + {0x77, 0x78, 0x79, 0x7A, 0x82, 0x83, 0x84, 0x85}, + {0x86, 0x87, 0x88, 0x89, 0x8A, 0x92, 0x93, 0x94}, + {0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0xA2, 0xA3}, + {0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xB2}, + {0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA}, + {0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9}, + {0xCA, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8}, + {0xD9, 0xDA, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7}, + {0xE8, 0xE9, 0xEA, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6}, + {0xF7, 0xF8, 0xF9, 0xFA, 0xFF, 0x20, 0x00, 0x1F}, + {0x02, 0x0C, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x11, 0x00, 0x11, 0x22, 0x00, 0x22}, + {0x22, 0x11, 0x22, 0x22, 0x11, 0x33, 0x33, 0x11}, + {0x44, 0x66, 0x22, 0x55, 0x66, 0xFF, 0xDD, 0x00}, + {0x04, 0x00, 0x14, 0xFF, 0xC0, 0x00, 0x11, 0x08}, + {0x00, 0xF0, 0x01, 0x40, 0x03, 0x00, 0x21, 0x00}, + {0x01, 0x11, 0x01, 0x02, 0x11, 0x01, 0xFF, 0xDA}, + {0x00, 0x0C, 0x03, 0x00, 0x00, 0x01, 0x11, 0x02}, + {0x11, 0x00, 0x3F, 0x00, 0xFF, 0xD9, 0x00, 0x00} /* 79 */ +}; + + +static const __u8 cxjpeg_640[][8] = { + {0xff, 0xd8, 0xff, 0xdb, 0x00, 0x84, 0x00, 0x10}, /* 1 */ + {0x0b, 0x0c, 0x0e, 0x0c, 0x0a, 0x10, 0x0e, 0x0d}, + {0x0e, 0x12, 0x11, 0x10, 0x13, 0x18, 0x28, 0x1a}, + {0x18, 0x16, 0x16, 0x18, 0x31, 0x23, 0x25, 0x1d}, + {0x28, 0x3a, 0x33, 0x3D, 0x3C, 0x39, 0x33, 0x38}, + {0x37, 0x40, 0x48, 0x5C, 0x4E, 0x40, 0x44, 0x57}, + {0x45, 0x37, 0x38, 0x50, 0x6D, 0x51, 0x57, 0x5F}, + {0x62, 0x67, 0x68, 0x67, 0x3E, 0x4D, 0x71, 0x79}, + {0x70, 0x64, 0x78, 0x5C, 0x65, 0x67, 0x63, 0x01}, + {0x10, 0x0B, 0x0C, 0x0E, 0x0C, 0x0A, 0x10, 0x0E}, + {0x0D, 0x0E, 0x12, 0x11, 0x10, 0x13, 0x18, 0x28}, + {0x1A, 0x18, 0x16, 0x16, 0x18, 0x31, 0x23, 0x25}, + {0x1D, 0x28, 0x3A, 0x33, 0x3D, 0x3C, 0x39, 0x33}, + {0x38, 0x37, 0x40, 0x48, 0x5C, 0x4E, 0x40, 0x44}, + {0x57, 0x45, 0x37, 0x38, 0x50, 0x6D, 0x51, 0x57}, + {0x5F, 0x62, 0x67, 0x68, 0x67, 0x3E, 0x4D, 0x71}, + {0x79, 0x70, 0x64, 0x78, 0x5C, 0x65, 0x67, 0x63}, + {0xFF, 0x20, 0x00, 0x1F, 0x00, 0x83, 0x00, 0x00}, + {0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00}, + {0x11, 0x22, 0x00, 0x22, 0x22, 0x11, 0x22, 0x22}, + {0x11, 0x33, 0x33, 0x11, 0x44, 0x66, 0x22, 0x55}, + {0x66, 0xFF, 0xDD, 0x00, 0x04, 0x00, 0x28, 0xFF}, + {0xC0, 0x00, 0x11, 0x08, 0x01, 0xE0, 0x02, 0x80}, + {0x03, 0x00, 0x21, 0x00, 0x01, 0x11, 0x01, 0x02}, + {0x11, 0x01, 0xFF, 0xDA, 0x00, 0x0C, 0x03, 0x00}, + {0x00, 0x01, 0x11, 0x02, 0x11, 0x00, 0x3F, 0x00}, + {0xFF, 0xD9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} /* 27 */ +}; +static const __u8 cxjpeg_352[][8] = { + {0xff, 0xd8, 0xff, 0xdb, 0x00, 0x84, 0x00, 0x0d}, + {0x09, 0x09, 0x0b, 0x09, 0x08, 0x0D, 0x0b, 0x0a}, + {0x0b, 0x0e, 0x0d, 0x0d, 0x0f, 0x13, 0x1f, 0x14}, + {0x13, 0x11, 0x11, 0x13, 0x26, 0x1b, 0x1d, 0x17}, + {0x1F, 0x2D, 0x28, 0x30, 0x2F, 0x2D, 0x28, 0x2C}, + {0x2B, 0x32, 0x38, 0x48, 0x3D, 0x32, 0x35, 0x44}, + {0x36, 0x2B, 0x2C, 0x3F, 0x55, 0x3F, 0x44, 0x4A}, + {0x4D, 0x50, 0x51, 0x50, 0x30, 0x3C, 0x58, 0x5F}, + {0x58, 0x4E, 0x5E, 0x48, 0x4F, 0x50, 0x4D, 0x01}, + {0x0D, 0x09, 0x09, 0x0B, 0x09, 0x08, 0x0D, 0x0B}, + {0x0A, 0x0B, 0x0E, 0x0D, 0x0D, 0x0F, 0x13, 0x1F}, + {0x14, 0x13, 0x11, 0x11, 0x13, 0x26, 0x1B, 0x1D}, + {0x17, 0x1F, 0x2D, 0x28, 0x30, 0x2F, 0x2D, 0x28}, + {0x2C, 0x2B, 0x32, 0x38, 0x48, 0x3D, 0x32, 0x35}, + {0x44, 0x36, 0x2B, 0x2C, 0x3F, 0x55, 0x3F, 0x44}, + {0x4A, 0x4D, 0x50, 0x51, 0x50, 0x30, 0x3C, 0x58}, + {0x5F, 0x58, 0x4E, 0x5E, 0x48, 0x4F, 0x50, 0x4D}, + {0xFF, 0x20, 0x00, 0x1F, 0x01, 0x83, 0x00, 0x00}, + {0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00}, + {0x11, 0x22, 0x00, 0x22, 0x22, 0x11, 0x22, 0x22}, + {0x11, 0x33, 0x33, 0x11, 0x44, 0x66, 0x22, 0x55}, + {0x66, 0xFF, 0xDD, 0x00, 0x04, 0x00, 0x16, 0xFF}, + {0xC0, 0x00, 0x11, 0x08, 0x01, 0x20, 0x01, 0x60}, + {0x03, 0x00, 0x21, 0x00, 0x01, 0x11, 0x01, 0x02}, + {0x11, 0x01, 0xFF, 0xDA, 0x00, 0x0C, 0x03, 0x00}, + {0x00, 0x01, 0x11, 0x02, 0x11, 0x00, 0x3F, 0x00}, + {0xFF, 0xD9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} +}; +static const __u8 cxjpeg_320[][8] = { + {0xff, 0xd8, 0xff, 0xdb, 0x00, 0x84, 0x00, 0x05}, + {0x03, 0x04, 0x04, 0x04, 0x03, 0x05, 0x04, 0x04}, + {0x04, 0x05, 0x05, 0x05, 0x06, 0x07, 0x0c, 0x08}, + {0x07, 0x07, 0x07, 0x07, 0x0f, 0x0b, 0x0b, 0x09}, + {0x0C, 0x11, 0x0F, 0x12, 0x12, 0x11, 0x0f, 0x11}, + {0x11, 0x13, 0x16, 0x1C, 0x17, 0x13, 0x14, 0x1A}, + {0x15, 0x11, 0x11, 0x18, 0x21, 0x18, 0x1A, 0x1D}, + {0x1D, 0x1F, 0x1F, 0x1F, 0x13, 0x17, 0x22, 0x24}, + {0x22, 0x1E, 0x24, 0x1C, 0x1E, 0x1F, 0x1E, 0x01}, + {0x05, 0x03, 0x04, 0x04, 0x04, 0x03, 0x05, 0x04}, + {0x04, 0x04, 0x05, 0x05, 0x05, 0x06, 0x07, 0x0C}, + {0x08, 0x07, 0x07, 0x07, 0x07, 0x0F, 0x0B, 0x0B}, + {0x09, 0x0C, 0x11, 0x0F, 0x12, 0x12, 0x11, 0x0F}, + {0x11, 0x11, 0x13, 0x16, 0x1C, 0x17, 0x13, 0x14}, + {0x1A, 0x15, 0x11, 0x11, 0x18, 0x21, 0x18, 0x1A}, + {0x1D, 0x1D, 0x1F, 0x1F, 0x1F, 0x13, 0x17, 0x22}, + {0x24, 0x22, 0x1E, 0x24, 0x1C, 0x1E, 0x1F, 0x1E}, + {0xFF, 0x20, 0x00, 0x1F, 0x02, 0x0C, 0x00, 0x00}, + {0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00}, + {0x11, 0x22, 0x00, 0x22, 0x22, 0x11, 0x22, 0x22}, + {0x11, 0x33, 0x33, 0x11, 0x44, 0x66, 0x22, 0x55}, + {0x66, 0xFF, 0xDD, 0x00, 0x04, 0x00, 0x14, 0xFF}, + {0xC0, 0x00, 0x11, 0x08, 0x00, 0xF0, 0x01, 0x40}, + {0x03, 0x00, 0x21, 0x00, 0x01, 0x11, 0x01, 0x02}, + {0x11, 0x01, 0xFF, 0xDA, 0x00, 0x0C, 0x03, 0x00}, + {0x00, 0x01, 0x11, 0x02, 0x11, 0x00, 0x3F, 0x00}, + {0xFF, 0xD9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} /* 27 */ +}; +static const __u8 cxjpeg_176[][8] = { + {0xff, 0xd8, 0xff, 0xdb, 0x00, 0x84, 0x00, 0x0d}, + {0x09, 0x09, 0x0B, 0x09, 0x08, 0x0D, 0x0B, 0x0A}, + {0x0B, 0x0E, 0x0D, 0x0D, 0x0F, 0x13, 0x1F, 0x14}, + {0x13, 0x11, 0x11, 0x13, 0x26, 0x1B, 0x1D, 0x17}, + {0x1F, 0x2D, 0x28, 0x30, 0x2F, 0x2D, 0x28, 0x2C}, + {0x2B, 0x32, 0x38, 0x48, 0x3D, 0x32, 0x35, 0x44}, + {0x36, 0x2B, 0x2C, 0x3F, 0x55, 0x3F, 0x44, 0x4A}, + {0x4D, 0x50, 0x51, 0x50, 0x30, 0x3C, 0x58, 0x5F}, + {0x58, 0x4E, 0x5E, 0x48, 0x4F, 0x50, 0x4D, 0x01}, + {0x0D, 0x09, 0x09, 0x0B, 0x09, 0x08, 0x0D, 0x0B}, + {0x0A, 0x0B, 0x0E, 0x0D, 0x0D, 0x0F, 0x13, 0x1F}, + {0x14, 0x13, 0x11, 0x11, 0x13, 0x26, 0x1B, 0x1D}, + {0x17, 0x1F, 0x2D, 0x28, 0x30, 0x2F, 0x2D, 0x28}, + {0x2C, 0x2B, 0x32, 0x38, 0x48, 0x3D, 0x32, 0x35}, + {0x44, 0x36, 0x2B, 0x2C, 0x3F, 0x55, 0x3F, 0x44}, + {0x4A, 0x4D, 0x50, 0x51, 0x50, 0x30, 0x3C, 0x58}, + {0x5F, 0x58, 0x4E, 0x5E, 0x48, 0x4F, 0x50, 0x4D}, + {0xFF, 0x20, 0x00, 0x1F, 0x03, 0xA1, 0x00, 0x00}, + {0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00}, + {0x11, 0x22, 0x00, 0x22, 0x22, 0x11, 0x22, 0x22}, + {0x11, 0x33, 0x33, 0x11, 0x44, 0x66, 0x22, 0x55}, + {0x66, 0xFF, 0xDD, 0x00, 0x04, 0x00, 0x0B, 0xFF}, + {0xC0, 0x00, 0x11, 0x08, 0x00, 0x90, 0x00, 0xB0}, + {0x03, 0x00, 0x21, 0x00, 0x01, 0x11, 0x01, 0x02}, + {0x11, 0x01, 0xFF, 0xDA, 0x00, 0x0C, 0x03, 0x00}, + {0x00, 0x01, 0x11, 0x02, 0x11, 0x00, 0x3F, 0x00}, + {0xFF, 0xD9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} +}; +/* 640 take with the zcx30x part */ +static const __u8 cxjpeg_qtable[][8] = { + {0xff, 0xd8, 0xff, 0xdb, 0x00, 0x84, 0x00, 0x08}, + {0x06, 0x06, 0x07, 0x06, 0x05, 0x08, 0x07, 0x07}, + {0x07, 0x09, 0x09, 0x08, 0x0a, 0x0c, 0x14, 0x0a}, + {0x0c, 0x0b, 0x0b, 0x0c, 0x19, 0x12, 0x13, 0x0f}, + {0x14, 0x1d, 0x1a, 0x1f, 0x1e, 0x1d, 0x1a, 0x1c}, + {0x1c, 0x20, 0x24, 0x2e, 0x27, 0x20, 0x22, 0x2c}, + {0x23, 0x1c, 0x1c, 0x28, 0x37, 0x29, 0x2c, 0x30}, + {0x31, 0x34, 0x34, 0x34, 0x1f, 0x27, 0x39, 0x3d}, + {0x38, 0x32, 0x3c, 0x2e, 0x33, 0x34, 0x32, 0x01}, + {0x09, 0x09, 0x09, 0x0c, 0x0b, 0x0c, 0x18, 0x0a}, + {0x0a, 0x18, 0x32, 0x21, 0x1c, 0x21, 0x32, 0x32}, + {0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32}, + {0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32}, + {0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32}, + {0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32}, + {0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32}, + {0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32}, + {0xFF, 0xD9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} /* 18 */ +}; + + +static void cx11646_jpegInit(struct gspca_dev*gspca_dev) +{ + int i; + int length; + + reg_w_val(gspca_dev, 0x00c0, 0x01); + reg_w_val(gspca_dev, 0x00c3, 0x00); + reg_w_val(gspca_dev, 0x00c0, 0x00); + reg_r(gspca_dev, 0x0001, 1); + length = 8; + for (i = 0; i < 79; i++) { + if (i == 78) + length = 6; + reg_w(gspca_dev, 0x0008, cx_jpeg_init[i], length); + } + reg_r(gspca_dev, 0x0002, 1); + reg_w_val(gspca_dev, 0x0055, 0x14); +} + +static const __u8 reg12[] = { 0x0a, 0x05, 0x07, 0x04, 0x19 }; +static const __u8 regE5_8[] = + { 0x88, 0x00, 0xd4, 0x01, 0x88, 0x01, 0x01, 0x01 }; +static const __u8 regE5a[] = { 0x88, 0x0a, 0x0c, 0x01 }; +static const __u8 regE5b[] = { 0x88, 0x0b, 0x12, 0x01 }; +static const __u8 regE5c[] = { 0x88, 0x05, 0x01, 0x01 }; +static const __u8 reg51[] = { 0x77, 0x03 }; +#define reg70 0x03 + +static void cx11646_jpeg(struct gspca_dev*gspca_dev) +{ + int i; + int length; + __u8 Reg55; + int retry; + + reg_w_val(gspca_dev, 0x00c0, 0x01); + reg_w_val(gspca_dev, 0x00c3, 0x00); + reg_w_val(gspca_dev, 0x00c0, 0x00); + reg_r(gspca_dev, 0x0001, 1); + length = 8; + switch (gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv) { + case 0: + for (i = 0; i < 27; i++) { + if (i == 26) + length = 2; + reg_w(gspca_dev, 0x0008, cxjpeg_640[i], length); + } + Reg55 = 0x28; + break; + case 1: + for (i = 0; i < 27; i++) { + if (i == 26) + length = 2; + reg_w(gspca_dev, 0x0008, cxjpeg_352[i], length); + } + Reg55 = 0x16; + break; + default: +/* case 2: */ + for (i = 0; i < 27; i++) { + if (i == 26) + length = 2; + reg_w(gspca_dev, 0x0008, cxjpeg_320[i], length); + } + Reg55 = 0x14; + break; + case 3: + for (i = 0; i < 27; i++) { + if (i == 26) + length = 2; + reg_w(gspca_dev, 0x0008, cxjpeg_176[i], length); + } + Reg55 = 0x0B; + break; + } + + reg_r(gspca_dev, 0x0002, 1); + reg_w_val(gspca_dev, 0x0055, Reg55); + reg_r(gspca_dev, 0x0002, 1); + reg_w(gspca_dev, 0x0010, reg10, 2); + reg_w_val(gspca_dev, 0x0054, 0x02); + reg_w_val(gspca_dev, 0x0054, 0x01); + reg_w_val(gspca_dev, 0x0000, 0x94); + reg_w_val(gspca_dev, 0x0053, 0xc0); + reg_w_val(gspca_dev, 0x00fc, 0xe1); + reg_w_val(gspca_dev, 0x0000, 0x00); + /* wait for completion */ + retry = 50; + while (retry--) { + reg_r(gspca_dev, 0x0002, 1); + /* 0x07 until 0x00 */ + if (gspca_dev->usb_buf[0] == 0x00) + break; + reg_w_val(gspca_dev, 0x0053, 0x00); + } + if (retry == 0) + PDEBUG(D_ERR, "Damned Errors sending jpeg Table"); + /* send the qtable now */ + reg_r(gspca_dev, 0x0001, 1); /* -> 0x18 */ + length = 8; + for (i = 0; i < 18; i++) { + if (i == 17) + length = 2; + reg_w(gspca_dev, 0x0008, cxjpeg_qtable[i], length); + + } + reg_r(gspca_dev, 0x0002, 1); /* 0x00 */ + reg_r(gspca_dev, 0x0053, 1); /* 0x00 */ + reg_w_val(gspca_dev, 0x0054, 0x02); + reg_w_val(gspca_dev, 0x0054, 0x01); + reg_w_val(gspca_dev, 0x0000, 0x94); + reg_w_val(gspca_dev, 0x0053, 0xc0); + + reg_r(gspca_dev, 0x0038, 1); /* 0x40 */ + reg_r(gspca_dev, 0x0038, 1); /* 0x40 */ + reg_r(gspca_dev, 0x001f, 1); /* 0x38 */ + reg_w(gspca_dev, 0x0012, reg12, 5); + reg_w(gspca_dev, 0x00e5, regE5_8, 8); + reg_r(gspca_dev, 0x00e8, 8); + reg_w(gspca_dev, 0x00e5, regE5a, 4); + reg_r(gspca_dev, 0x00e8, 1); /* 0x00 */ + reg_w_val(gspca_dev, 0x009a, 0x01); + reg_w(gspca_dev, 0x00e5, regE5b, 4); + reg_r(gspca_dev, 0x00e8, 1); /* 0x00 */ + reg_w(gspca_dev, 0x00e5, regE5c, 4); + reg_r(gspca_dev, 0x00e8, 1); /* 0x00 */ + + reg_w(gspca_dev, 0x0051, reg51, 2); + reg_w(gspca_dev, 0x0010, reg10, 2); + reg_w_val(gspca_dev, 0x0070, reg70); +} + +static void cx11646_init1(struct gspca_dev *gspca_dev) +{ + int i = 0; + + reg_w_val(gspca_dev, 0x0010, 0x00); + reg_w_val(gspca_dev, 0x0053, 0x00); + reg_w_val(gspca_dev, 0x0052, 0x00); + reg_w_val(gspca_dev, 0x009b, 0x2f); + reg_w_val(gspca_dev, 0x009c, 0x10); + reg_r(gspca_dev, 0x0098, 1); + reg_w_val(gspca_dev, 0x0098, 0x40); + reg_r(gspca_dev, 0x0099, 1); + reg_w_val(gspca_dev, 0x0099, 0x07); + reg_w_val(gspca_dev, 0x0039, 0x40); + reg_w_val(gspca_dev, 0x003c, 0xff); + reg_w_val(gspca_dev, 0x003f, 0x1f); + reg_w_val(gspca_dev, 0x003d, 0x40); +/* reg_w_val(gspca_dev, 0x003d, 0x60); */ + reg_r(gspca_dev, 0x0099, 1); /* ->0x07 */ + + while (cx_sensor_init[i][0]) { + reg_w_val(gspca_dev, 0x00e5, cx_sensor_init[i][0]); + reg_r(gspca_dev, 0x00e8, 1); /* -> 0x00 */ + if (i == 1) { + reg_w_val(gspca_dev, 0x00ed, 0x01); + reg_r(gspca_dev, 0x00ed, 1); /* -> 0x01 */ + } + i++; + } + reg_w_val(gspca_dev, 0x00c3, 0x00); +} + +/* this function is called at probe time */ +static int sd_config(struct gspca_dev *gspca_dev, + const struct usb_device_id *id) +{ + struct sd *sd = (struct sd *) gspca_dev; + struct cam *cam; + + cam = &gspca_dev->cam; + cam->dev_name = (char *) id->driver_info; + cam->epaddr = 0x01; + cam->cam_mode = vga_mode; + cam->nmodes = sizeof vga_mode / sizeof vga_mode[0]; + + sd->qindex = 0; /* set the quantization */ + sd->brightness = BRIGHTNESS_DEF; + sd->contrast = CONTRAST_DEF; + sd->colors = COLOR_DEF; + return 0; +} + +/* this function is called at open time */ +static int sd_open(struct gspca_dev *gspca_dev) +{ + cx11646_init1(gspca_dev); + cx11646_initsize(gspca_dev); + cx11646_fw(gspca_dev); + cx_sensor(gspca_dev); + cx11646_jpegInit(gspca_dev); + return 0; +} + +static void sd_start(struct gspca_dev *gspca_dev) +{ + cx11646_initsize(gspca_dev); + cx11646_fw(gspca_dev); + cx_sensor(gspca_dev); + cx11646_jpeg(gspca_dev); +} + +static void sd_stopN(struct gspca_dev *gspca_dev) +{ +} + +static void sd_stop0(struct gspca_dev *gspca_dev) +{ + int retry = 50; + + reg_w_val(gspca_dev, 0x0000, 0x00); + reg_r(gspca_dev, 0x0002, 1); + reg_w_val(gspca_dev, 0x0053, 0x00); + + while (retry--) { +/* reg_r(gspca_dev, 0x0002, 1);*/ + reg_r(gspca_dev, 0x0053, 1); + if (gspca_dev->usb_buf[0] == 0) + break; + } + reg_w_val(gspca_dev, 0x0000, 0x00); + reg_r(gspca_dev, 0x0002, 1); + + reg_w_val(gspca_dev, 0x0010, 0x00); + reg_r(gspca_dev, 0x0033, 1); + reg_w_val(gspca_dev, 0x00fc, 0xe0); +} + +static void sd_close(struct gspca_dev *gspca_dev) +{ +} + +static void sd_pkt_scan(struct gspca_dev *gspca_dev, + struct gspca_frame *frame, /* target */ + __u8 *data, /* isoc packet */ + int len) /* iso packet length */ +{ + if (data[0] == 0xff && data[1] == 0xd8) { + + /* start of frame */ + frame = gspca_frame_add(gspca_dev, LAST_PACKET, frame, + data, 0); + + /* put the JPEG header in the new frame */ + jpeg_put_header(gspca_dev, frame, + ((struct sd *) gspca_dev)->qindex, + 0x22); + data += 2; + len -= 2; + } + gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len); +} + +static void setbrightness(struct gspca_dev*gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + __u8 regE5cbx[] = { 0x88, 0x00, 0xd4, 0x01, 0x88, 0x01, 0x01, 0x01 }; + __u8 reg51c[2]; + __u8 bright; + __u8 colors; + + bright = sd->brightness; + regE5cbx[2] = bright; + reg_w(gspca_dev, 0x00e5, regE5cbx, 8); + reg_r(gspca_dev, 0x00e8, 8); + reg_w(gspca_dev, 0x00e5, regE5c, 4); + reg_r(gspca_dev, 0x00e8, 1); /* 0x00 */ + + colors = sd->colors; + reg51c[0] = 0x77; + reg51c[1] = colors; + reg_w(gspca_dev, 0x0051, reg51c, 2); + reg_w(gspca_dev, 0x0010, reg10, 2); + reg_w_val(gspca_dev, 0x0070, reg70); +} + +static void setcontrast(struct gspca_dev*gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + __u8 regE5acx[] = { 0x88, 0x0a, 0x0c, 0x01 }; /* seem MSB */ +/* __u8 regE5bcx[] = { 0x88, 0x0b, 0x12, 0x01}; * LSB */ + __u8 reg51c[2]; + + regE5acx[2] = sd->contrast; + reg_w(gspca_dev, 0x00e5, regE5acx, 4); + reg_r(gspca_dev, 0x00e8, 1); /* 0x00 */ + reg51c[0] = 0x77; + reg51c[1] = sd->colors; + reg_w(gspca_dev, 0x0051, reg51c, 2); + reg_w(gspca_dev, 0x0010, reg10, 2); + reg_w_val(gspca_dev, 0x0070, reg70); +} + +static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->brightness = val; + if (gspca_dev->streaming) + setbrightness(gspca_dev); + return 0; +} + +static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + *val = sd->brightness; + return 0; +} + +static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->contrast = val; + if (gspca_dev->streaming) + setcontrast(gspca_dev); + return 0; +} + +static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + *val = sd->contrast; + return 0; +} + +static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->colors = val; + if (gspca_dev->streaming) { + setbrightness(gspca_dev); + setcontrast(gspca_dev); + } + return 0; +} + +static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + *val = sd->colors; + return 0; +} + +/* sub-driver description */ +static struct sd_desc sd_desc = { + .name = MODULE_NAME, + .ctrls = sd_ctrls, + .nctrls = ARRAY_SIZE(sd_ctrls), + .config = sd_config, + .open = sd_open, + .start = sd_start, + .stopN = sd_stopN, + .stop0 = sd_stop0, + .close = sd_close, + .pkt_scan = sd_pkt_scan, +}; + +/* -- module initialisation -- */ +#define DVNM(name) .driver_info = (kernel_ulong_t) name +static __devinitdata struct usb_device_id device_table[] = { + {USB_DEVICE(0x0572, 0x0041), DVNM("Creative Notebook cx11646")}, + {} +}; +MODULE_DEVICE_TABLE(usb, device_table); + +/* -- device connect -- */ +static int sd_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd), + THIS_MODULE); +} + +static struct usb_driver sd_driver = { + .name = MODULE_NAME, + .id_table = device_table, + .probe = sd_probe, + .disconnect = gspca_disconnect, +}; + +/* -- module insert / remove -- */ +static int __init sd_mod_init(void) +{ + if (usb_register(&sd_driver) < 0) + return -1; + PDEBUG(D_PROBE, "v%s registered", version); + return 0; +} +static void __exit sd_mod_exit(void) +{ + usb_deregister(&sd_driver); + PDEBUG(D_PROBE, "deregistered"); +} + +module_init(sd_mod_init); +module_exit(sd_mod_exit); diff --git a/drivers/media/video/gspca/etoms.c b/drivers/media/video/gspca/etoms.c new file mode 100644 index 000000000000..8ab4ea7201a9 --- /dev/null +++ b/drivers/media/video/gspca/etoms.c @@ -0,0 +1,956 @@ +/* + * Etoms Et61x151 GPL Linux driver by Michel Xhaard (09/09/2004) + * + * V4L2 by Jean-Francois Moine <http://moinejf.free.fr> + * + * 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 + * 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 + */ + +#define MODULE_NAME "etoms" + +#include "gspca.h" + +#define DRIVER_VERSION_NUMBER KERNEL_VERSION(2, 1, 7) +static const char version[] = "2.1.7"; + +MODULE_AUTHOR("Michel Xhaard <mxhaard@users.sourceforge.net>"); +MODULE_DESCRIPTION("Etoms USB Camera Driver"); +MODULE_LICENSE("GPL"); + +/* specific webcam descriptor */ +struct sd { + struct gspca_dev gspca_dev; /* !! must be the first item */ + + unsigned char brightness; + unsigned char contrast; + unsigned char colors; + unsigned char autogain; + + char sensor; +#define SENSOR_PAS106 0 +#define SENSOR_TAS5130CXX 1 + signed char ag_cnt; +#define AG_CNT_START 13 +}; + +/* V4L2 controls supported by the driver */ +static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val); +static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val); +static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val); +static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val); +static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val); +static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val); +static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val); +static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val); + +static struct ctrl sd_ctrls[] = { + { + { + .id = V4L2_CID_BRIGHTNESS, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Brightness", + .minimum = 1, + .maximum = 127, + .step = 1, +#define BRIGHTNESS_DEF 63 + .default_value = BRIGHTNESS_DEF, + }, + .set = sd_setbrightness, + .get = sd_getbrightness, + }, + { + { + .id = V4L2_CID_CONTRAST, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Contrast", + .minimum = 0, + .maximum = 255, + .step = 1, +#define CONTRAST_DEF 127 + .default_value = CONTRAST_DEF, + }, + .set = sd_setcontrast, + .get = sd_getcontrast, + }, + { + { + .id = V4L2_CID_SATURATION, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Color", + .minimum = 0, + .maximum = 15, + .step = 1, +#define COLOR_DEF 7 + .default_value = COLOR_DEF, + }, + .set = sd_setcolors, + .get = sd_getcolors, + }, + { + { + .id = V4L2_CID_AUTOGAIN, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Auto Gain", + .minimum = 0, + .maximum = 1, + .step = 1, +#define AUTOGAIN_DEF 1 + .default_value = AUTOGAIN_DEF, + }, + .set = sd_setautogain, + .get = sd_getautogain, + }, +}; + +static struct v4l2_pix_format vga_mode[] = { + {320, 240, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE, + .bytesperline = 320, + .sizeimage = 320 * 240, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = 1}, +/* {640, 480, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE, + .bytesperline = 640, + .sizeimage = 640 * 480, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = 0}, */ +}; + +static struct v4l2_pix_format sif_mode[] = { + {176, 144, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE, + .bytesperline = 176, + .sizeimage = 176 * 144, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = 1}, + {352, 288, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE, + .bytesperline = 352, + .sizeimage = 352 * 288, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = 0}, +}; + +#define ETOMS_ALT_SIZE_1000 12 + +#define ET_GPIO_DIR_CTRL 0x04 /* Control IO bit[0..5] (0 in 1 out) */ +#define ET_GPIO_OUT 0x05 /* Only IO data */ +#define ET_GPIO_IN 0x06 /* Read Only IO data */ +#define ET_RESET_ALL 0x03 +#define ET_ClCK 0x01 +#define ET_CTRL 0x02 /* enable i2c OutClck Powerdown mode */ + +#define ET_COMP 0x12 /* Compression register */ +#define ET_MAXQt 0x13 +#define ET_MINQt 0x14 +#define ET_COMP_VAL0 0x02 +#define ET_COMP_VAL1 0x03 + +#define ET_REG1d 0x1d +#define ET_REG1e 0x1e +#define ET_REG1f 0x1f +#define ET_REG20 0x20 +#define ET_REG21 0x21 +#define ET_REG22 0x22 +#define ET_REG23 0x23 +#define ET_REG24 0x24 +#define ET_REG25 0x25 +/* base registers for luma calculation */ +#define ET_LUMA_CENTER 0x39 + +#define ET_G_RED 0x4d +#define ET_G_GREEN1 0x4e +#define ET_G_BLUE 0x4f +#define ET_G_GREEN2 0x50 +#define ET_G_GR_H 0x51 +#define ET_G_GB_H 0x52 + +#define ET_O_RED 0x34 +#define ET_O_GREEN1 0x35 +#define ET_O_BLUE 0x36 +#define ET_O_GREEN2 0x37 + +#define ET_SYNCHRO 0x68 +#define ET_STARTX 0x69 +#define ET_STARTY 0x6a +#define ET_WIDTH_LOW 0x6b +#define ET_HEIGTH_LOW 0x6c +#define ET_W_H_HEIGTH 0x6d + +#define ET_REG6e 0x6e /* OBW */ +#define ET_REG6f 0x6f /* OBW */ +#define ET_REG70 0x70 /* OBW_AWB */ +#define ET_REG71 0x71 /* OBW_AWB */ +#define ET_REG72 0x72 /* OBW_AWB */ +#define ET_REG73 0x73 /* Clkdelay ns */ +#define ET_REG74 0x74 /* test pattern */ +#define ET_REG75 0x75 /* test pattern */ + +#define ET_I2C_CLK 0x8c +#define ET_PXL_CLK 0x60 + +#define ET_I2C_BASE 0x89 +#define ET_I2C_COUNT 0x8a +#define ET_I2C_PREFETCH 0x8b +#define ET_I2C_REG 0x88 +#define ET_I2C_DATA7 0x87 +#define ET_I2C_DATA6 0x86 +#define ET_I2C_DATA5 0x85 +#define ET_I2C_DATA4 0x84 +#define ET_I2C_DATA3 0x83 +#define ET_I2C_DATA2 0x82 +#define ET_I2C_DATA1 0x81 +#define ET_I2C_DATA0 0x80 + +#define PAS106_REG2 0x02 /* pxlClk = systemClk/(reg2) */ +#define PAS106_REG3 0x03 /* line/frame H [11..4] */ +#define PAS106_REG4 0x04 /* line/frame L [3..0] */ +#define PAS106_REG5 0x05 /* exposure time line offset(default 5) */ +#define PAS106_REG6 0x06 /* exposure time pixel offset(default 6) */ +#define PAS106_REG7 0x07 /* signbit Dac (default 0) */ +#define PAS106_REG9 0x09 +#define PAS106_REG0e 0x0e /* global gain [4..0](default 0x0e) */ +#define PAS106_REG13 0x13 /* end i2c write */ + +static const __u8 GainRGBG[] = { 0x80, 0x80, 0x80, 0x80, 0x00, 0x00 }; + +static const __u8 I2c2[] = { 0x08, 0x08, 0x08, 0x08, 0x0d }; + +static const __u8 I2c3[] = { 0x12, 0x05 }; + +static const __u8 I2c4[] = { 0x41, 0x08 }; + +/* read 'len' bytes to gspca_dev->usb_buf */ +static void reg_r(struct gspca_dev *gspca_dev, + __u16 index, + __u16 len) +{ + struct usb_device *dev = gspca_dev->dev; + +#ifdef CONFIG_VIDEO_ADV_DEBUG + if (len > sizeof gspca_dev->usb_buf) { + err("reg_r: buffer overflow"); + return; + } +#endif + usb_control_msg(dev, + usb_rcvctrlpipe(dev, 0), + 0, + USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_INTERFACE, + 0, + index, gspca_dev->usb_buf, len, 500); + PDEBUG(D_USBI, "reg read [%02x] -> %02x ..", + index, gspca_dev->usb_buf[0]); +} + +static void reg_w_val(struct gspca_dev *gspca_dev, + __u16 index, + __u8 val) +{ + struct usb_device *dev = gspca_dev->dev; + + gspca_dev->usb_buf[0] = val; + usb_control_msg(dev, + usb_sndctrlpipe(dev, 0), + 0, + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE, + 0, + index, gspca_dev->usb_buf, 1, 500); +} + +static void reg_w(struct gspca_dev *gspca_dev, + __u16 index, + const __u8 *buffer, + __u16 len) +{ + struct usb_device *dev = gspca_dev->dev; + +#ifdef CONFIG_VIDEO_ADV_DEBUG + if (len > sizeof gspca_dev->usb_buf) { + err("reg_w: buffer overflow"); + return; + } + PDEBUG(D_USBO, "reg write [%02x] = %02x..", index, *buffer); +#endif + memcpy(gspca_dev->usb_buf, buffer, len); + usb_control_msg(dev, + usb_sndctrlpipe(dev, 0), + 0, + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE, + 0, index, gspca_dev->usb_buf, len, 500); +} + +static int i2c_w(struct gspca_dev *gspca_dev, + __u8 reg, + const __u8 *buffer, + int len, __u8 mode) +{ + /* buffer should be [D0..D7] */ + __u8 ptchcount; + + /* set the base address */ + reg_w_val(gspca_dev, ET_I2C_BASE, 0x40); + /* sensor base for the pas106 */ + /* set count and prefetch */ + ptchcount = ((len & 0x07) << 4) | (mode & 0x03); + reg_w_val(gspca_dev, ET_I2C_COUNT, ptchcount); + /* set the register base */ + reg_w_val(gspca_dev, ET_I2C_REG, reg); + while (--len >= 0) + reg_w_val(gspca_dev, ET_I2C_DATA0 + len, buffer[len]); + return 0; +} + +static int i2c_r(struct gspca_dev *gspca_dev, + __u8 reg) +{ + /* set the base address */ + reg_w_val(gspca_dev, ET_I2C_BASE, 0x40); + /* sensor base for the pas106 */ + /* set count and prefetch (cnd: 4 bits - mode: 4 bits) */ + reg_w_val(gspca_dev, ET_I2C_COUNT, 0x11); + reg_w_val(gspca_dev, ET_I2C_REG, reg); /* set the register base */ + reg_w_val(gspca_dev, ET_I2C_PREFETCH, 0x02); /* prefetch */ + reg_w_val(gspca_dev, ET_I2C_PREFETCH, 0x00); + reg_r(gspca_dev, ET_I2C_DATA0, 1); /* read one byte */ + return 0; +} + +static int Et_WaitStatus(struct gspca_dev *gspca_dev) +{ + int retry = 10; + + while (retry--) { + reg_r(gspca_dev, ET_ClCK, 1); + if (gspca_dev->usb_buf[0] != 0) + return 1; + } + return 0; +} + +static int et_video(struct gspca_dev *gspca_dev, + int on) +{ + int ret; + + reg_w_val(gspca_dev, ET_GPIO_OUT, + on ? 0x10 /* startvideo - set Bit5 */ + : 0); /* stopvideo */ + ret = Et_WaitStatus(gspca_dev); + if (ret != 0) + PDEBUG(D_ERR, "timeout video on/off"); + return ret; +} + +static void Et_init2(struct gspca_dev *gspca_dev) +{ + __u8 value; + static const __u8 FormLine[] = { 0x84, 0x03, 0x14, 0xf4, 0x01, 0x05 }; + + PDEBUG(D_STREAM, "Open Init2 ET"); + reg_w_val(gspca_dev, ET_GPIO_DIR_CTRL, 0x2f); + reg_w_val(gspca_dev, ET_GPIO_OUT, 0x10); + reg_r(gspca_dev, ET_GPIO_IN, 1); + reg_w_val(gspca_dev, ET_ClCK, 0x14); /* 0x14 // 0x16 enabled pattern */ + reg_w_val(gspca_dev, ET_CTRL, 0x1b); + + /* compression et subsampling */ + if (gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv) + value = ET_COMP_VAL1; /* 320 */ + else + value = ET_COMP_VAL0; /* 640 */ + reg_w_val(gspca_dev, ET_COMP, value); + reg_w_val(gspca_dev, ET_MAXQt, 0x1f); + reg_w_val(gspca_dev, ET_MINQt, 0x04); + /* undocumented registers */ + reg_w_val(gspca_dev, ET_REG1d, 0xff); + reg_w_val(gspca_dev, ET_REG1e, 0xff); + reg_w_val(gspca_dev, ET_REG1f, 0xff); + reg_w_val(gspca_dev, ET_REG20, 0x35); + reg_w_val(gspca_dev, ET_REG21, 0x01); + reg_w_val(gspca_dev, ET_REG22, 0x00); + reg_w_val(gspca_dev, ET_REG23, 0xff); + reg_w_val(gspca_dev, ET_REG24, 0xff); + reg_w_val(gspca_dev, ET_REG25, 0x0f); + /* colors setting */ + reg_w_val(gspca_dev, 0x30, 0x11); /* 0x30 */ + reg_w_val(gspca_dev, 0x31, 0x40); + reg_w_val(gspca_dev, 0x32, 0x00); + reg_w_val(gspca_dev, ET_O_RED, 0x00); /* 0x34 */ + reg_w_val(gspca_dev, ET_O_GREEN1, 0x00); + reg_w_val(gspca_dev, ET_O_BLUE, 0x00); + reg_w_val(gspca_dev, ET_O_GREEN2, 0x00); + /*************/ + reg_w_val(gspca_dev, ET_G_RED, 0x80); /* 0x4d */ + reg_w_val(gspca_dev, ET_G_GREEN1, 0x80); + reg_w_val(gspca_dev, ET_G_BLUE, 0x80); + reg_w_val(gspca_dev, ET_G_GREEN2, 0x80); + reg_w_val(gspca_dev, ET_G_GR_H, 0x00); + reg_w_val(gspca_dev, ET_G_GB_H, 0x00); /* 0x52 */ + /* Window control registers */ + reg_w_val(gspca_dev, 0x61, 0x80); /* use cmc_out */ + reg_w_val(gspca_dev, 0x62, 0x02); + reg_w_val(gspca_dev, 0x63, 0x03); + reg_w_val(gspca_dev, 0x64, 0x14); + reg_w_val(gspca_dev, 0x65, 0x0e); + reg_w_val(gspca_dev, 0x66, 0x02); + reg_w_val(gspca_dev, 0x67, 0x02); + + /**************************************/ + reg_w_val(gspca_dev, ET_SYNCHRO, 0x8f); /* 0x68 */ + reg_w_val(gspca_dev, ET_STARTX, 0x69); /* 0x6a //0x69 */ + reg_w_val(gspca_dev, ET_STARTY, 0x0d); /* 0x0d //0x0c */ + reg_w_val(gspca_dev, ET_WIDTH_LOW, 0x80); + reg_w_val(gspca_dev, ET_HEIGTH_LOW, 0xe0); + reg_w_val(gspca_dev, ET_W_H_HEIGTH, 0x60); /* 6d */ + reg_w_val(gspca_dev, ET_REG6e, 0x86); + reg_w_val(gspca_dev, ET_REG6f, 0x01); + reg_w_val(gspca_dev, ET_REG70, 0x26); + reg_w_val(gspca_dev, ET_REG71, 0x7a); + reg_w_val(gspca_dev, ET_REG72, 0x01); + /* Clock Pattern registers ***************** */ + reg_w_val(gspca_dev, ET_REG73, 0x00); + reg_w_val(gspca_dev, ET_REG74, 0x18); /* 0x28 */ + reg_w_val(gspca_dev, ET_REG75, 0x0f); /* 0x01 */ + /**********************************************/ + reg_w_val(gspca_dev, 0x8a, 0x20); + reg_w_val(gspca_dev, 0x8d, 0x0f); + reg_w_val(gspca_dev, 0x8e, 0x08); + /**************************************/ + reg_w_val(gspca_dev, 0x03, 0x08); + reg_w_val(gspca_dev, ET_PXL_CLK, 0x03); + reg_w_val(gspca_dev, 0x81, 0xff); + reg_w_val(gspca_dev, 0x80, 0x00); + reg_w_val(gspca_dev, 0x81, 0xff); + reg_w_val(gspca_dev, 0x80, 0x20); + reg_w_val(gspca_dev, 0x03, 0x01); + reg_w_val(gspca_dev, 0x03, 0x00); + reg_w_val(gspca_dev, 0x03, 0x08); + /********************************************/ + +/* reg_r(gspca_dev, ET_I2C_BASE, 1); + always 0x40 as the pas106 ??? */ + /* set the sensor */ + if (gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv) + value = 0x04; /* 320 */ + else /* 640 */ + value = 0x1e; /* 0x17 * setting PixelClock + * 0x03 mean 24/(3+1) = 6 Mhz + * 0x05 -> 24/(5+1) = 4 Mhz + * 0x0b -> 24/(11+1) = 2 Mhz + * 0x17 -> 24/(23+1) = 1 Mhz + */ + reg_w_val(gspca_dev, ET_PXL_CLK, value); + /* now set by fifo the FormatLine setting */ + reg_w(gspca_dev, 0x62, FormLine, 6); + + /* set exposure times [ 0..0x78] 0->longvalue 0x78->shortvalue */ + reg_w_val(gspca_dev, 0x81, 0x47); /* 0x47; */ + reg_w_val(gspca_dev, 0x80, 0x40); /* 0x40; */ + /* Pedro change */ + /* Brightness change Brith+ decrease value */ + /* Brigth- increase value */ + /* original value = 0x70; */ + reg_w_val(gspca_dev, 0x81, 0x30); /* 0x20; - set brightness */ + reg_w_val(gspca_dev, 0x80, 0x20); /* 0x20; */ +} + +static void setcolors(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + __u8 I2cc[] = { 0x05, 0x02, 0x02, 0x05, 0x0d }; + __u8 i2cflags = 0x01; + /* __u8 green = 0; */ + __u8 colors = sd->colors; + + I2cc[3] = colors; /* red */ + I2cc[0] = 15 - colors; /* blue */ + /* green = 15 - ((((7*I2cc[0]) >> 2 ) + I2cc[3]) >> 1); */ + /* I2cc[1] = I2cc[2] = green; */ + if (sd->sensor == SENSOR_PAS106) { + i2c_w(gspca_dev, PAS106_REG13, &i2cflags, 1, 3); + i2c_w(gspca_dev, PAS106_REG9, I2cc, sizeof I2cc, 1); + } +/* PDEBUG(D_CONF , "Etoms red %d blue %d green %d", + I2cc[3], I2cc[0], green); */ +} + +static void getcolors(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + + if (sd->sensor == SENSOR_PAS106) { +/* i2c_r(gspca_dev, PAS106_REG9); * blue */ + i2c_r(gspca_dev, PAS106_REG9 + 3); /* red */ + sd->colors = gspca_dev->usb_buf[0] & 0x0f; + } +} + +static void Et_init1(struct gspca_dev *gspca_dev) +{ + __u8 value; +/* __u8 I2c0 [] = {0x0a, 0x12, 0x05, 0x22, 0xac, 0x00, 0x01, 0x00}; */ + __u8 I2c0[] = { 0x0a, 0x12, 0x05, 0x6d, 0xcd, 0x00, 0x01, 0x00 }; + /* try 1/120 0x6d 0xcd 0x40 */ +/* __u8 I2c0 [] = {0x0a, 0x12, 0x05, 0xfe, 0xfe, 0xc0, 0x01, 0x00}; + * 1/60000 hmm ?? */ + + PDEBUG(D_STREAM, "Open Init1 ET"); + reg_w_val(gspca_dev, ET_GPIO_DIR_CTRL, 7); + reg_r(gspca_dev, ET_GPIO_IN, 1); + reg_w_val(gspca_dev, ET_RESET_ALL, 1); + reg_w_val(gspca_dev, ET_RESET_ALL, 0); + reg_w_val(gspca_dev, ET_ClCK, 0x10); + reg_w_val(gspca_dev, ET_CTRL, 0x19); + /* compression et subsampling */ + if (gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv) + value = ET_COMP_VAL1; + else + value = ET_COMP_VAL0; + PDEBUG(D_STREAM, "Open mode %d Compression %d", + gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv, + value); + reg_w_val(gspca_dev, ET_COMP, value); + reg_w_val(gspca_dev, ET_MAXQt, 0x1d); + reg_w_val(gspca_dev, ET_MINQt, 0x02); + /* undocumented registers */ + reg_w_val(gspca_dev, ET_REG1d, 0xff); + reg_w_val(gspca_dev, ET_REG1e, 0xff); + reg_w_val(gspca_dev, ET_REG1f, 0xff); + reg_w_val(gspca_dev, ET_REG20, 0x35); + reg_w_val(gspca_dev, ET_REG21, 0x01); + reg_w_val(gspca_dev, ET_REG22, 0x00); + reg_w_val(gspca_dev, ET_REG23, 0xf7); + reg_w_val(gspca_dev, ET_REG24, 0xff); + reg_w_val(gspca_dev, ET_REG25, 0x07); + /* colors setting */ + reg_w_val(gspca_dev, ET_G_RED, 0x80); + reg_w_val(gspca_dev, ET_G_GREEN1, 0x80); + reg_w_val(gspca_dev, ET_G_BLUE, 0x80); + reg_w_val(gspca_dev, ET_G_GREEN2, 0x80); + reg_w_val(gspca_dev, ET_G_GR_H, 0x00); + reg_w_val(gspca_dev, ET_G_GB_H, 0x00); + /* Window control registers */ + reg_w_val(gspca_dev, ET_SYNCHRO, 0xf0); + reg_w_val(gspca_dev, ET_STARTX, 0x56); /* 0x56 */ + reg_w_val(gspca_dev, ET_STARTY, 0x05); /* 0x04 */ + reg_w_val(gspca_dev, ET_WIDTH_LOW, 0x60); + reg_w_val(gspca_dev, ET_HEIGTH_LOW, 0x20); + reg_w_val(gspca_dev, ET_W_H_HEIGTH, 0x50); + reg_w_val(gspca_dev, ET_REG6e, 0x86); + reg_w_val(gspca_dev, ET_REG6f, 0x01); + reg_w_val(gspca_dev, ET_REG70, 0x86); + reg_w_val(gspca_dev, ET_REG71, 0x14); + reg_w_val(gspca_dev, ET_REG72, 0x00); + /* Clock Pattern registers */ + reg_w_val(gspca_dev, ET_REG73, 0x00); + reg_w_val(gspca_dev, ET_REG74, 0x00); + reg_w_val(gspca_dev, ET_REG75, 0x0a); + reg_w_val(gspca_dev, ET_I2C_CLK, 0x04); + reg_w_val(gspca_dev, ET_PXL_CLK, 0x01); + /* set the sensor */ + if (gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv) { + I2c0[0] = 0x06; + i2c_w(gspca_dev, PAS106_REG2, I2c0, sizeof I2c0, 1); + i2c_w(gspca_dev, PAS106_REG9, I2c2, sizeof I2c2, 1); + value = 0x06; + i2c_w(gspca_dev, PAS106_REG2, &value, 1, 1); + i2c_w(gspca_dev, PAS106_REG3, I2c3, sizeof I2c3, 1); + /* value = 0x1f; */ + value = 0x04; + i2c_w(gspca_dev, PAS106_REG0e, &value, 1, 1); + } else { + I2c0[0] = 0x0a; + + i2c_w(gspca_dev, PAS106_REG2, I2c0, sizeof I2c0, 1); + i2c_w(gspca_dev, PAS106_REG9, I2c2, sizeof I2c2, 1); + value = 0x0a; + i2c_w(gspca_dev, PAS106_REG2, &value, 1, 1); + i2c_w(gspca_dev, PAS106_REG3, I2c3, sizeof I2c3, 1); + value = 0x04; + /* value = 0x10; */ + i2c_w(gspca_dev, PAS106_REG0e, &value, 1, 1); + /* bit 2 enable bit 1:2 select 0 1 2 3 + value = 0x07; * curve 0 * + i2c_w(gspca_dev, PAS106_REG0f, &value, 1, 1); + */ + } + +/* value = 0x01; */ +/* value = 0x22; */ +/* i2c_w(gspca_dev, PAS106_REG5, &value, 1, 1); */ + /* magnetude and sign bit for DAC */ + i2c_w(gspca_dev, PAS106_REG7, I2c4, sizeof I2c4, 1); + /* now set by fifo the whole colors setting */ + reg_w(gspca_dev, ET_G_RED, GainRGBG, 6); + getcolors(gspca_dev); + setcolors(gspca_dev); +} + +/* this function is called at probe time */ +static int sd_config(struct gspca_dev *gspca_dev, + const struct usb_device_id *id) +{ + struct sd *sd = (struct sd *) gspca_dev; + struct cam *cam; + __u16 vendor; + __u16 product; + + vendor = id->idVendor; + product = id->idProduct; +/* switch (vendor) { */ +/* case 0x102c: * Etoms */ + switch (product) { + case 0x6151: + sd->sensor = SENSOR_PAS106; /* Etoms61x151 */ + break; + case 0x6251: + sd->sensor = SENSOR_TAS5130CXX; /* Etoms61x251 */ + break; +/* } */ +/* break; */ + } + cam = &gspca_dev->cam; + cam->dev_name = (char *) id->driver_info; + cam->epaddr = 1; + if (sd->sensor == SENSOR_PAS106) { + cam->cam_mode = sif_mode; + cam->nmodes = sizeof sif_mode / sizeof sif_mode[0]; + } else { + cam->cam_mode = vga_mode; + cam->nmodes = sizeof vga_mode / sizeof vga_mode[0]; + } + sd->brightness = BRIGHTNESS_DEF; + sd->contrast = CONTRAST_DEF; + sd->colors = COLOR_DEF; + sd->autogain = AUTOGAIN_DEF; + return 0; +} + +/* this function is called at open time */ +static int sd_open(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + + if (sd->sensor == SENSOR_PAS106) + Et_init1(gspca_dev); + else + Et_init2(gspca_dev); + reg_w_val(gspca_dev, ET_RESET_ALL, 0x08); + et_video(gspca_dev, 0); /* video off */ + return 0; +} + +/* -- start the camera -- */ +static void sd_start(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + + if (sd->sensor == SENSOR_PAS106) + Et_init1(gspca_dev); + else + Et_init2(gspca_dev); + + reg_w_val(gspca_dev, ET_RESET_ALL, 0x08); + et_video(gspca_dev, 1); /* video on */ +} + +static void sd_stopN(struct gspca_dev *gspca_dev) +{ + et_video(gspca_dev, 0); /* video off */ +} + +static void sd_stop0(struct gspca_dev *gspca_dev) +{ +} + +static void sd_close(struct gspca_dev *gspca_dev) +{ +} + +static void setbrightness(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + int i; + __u8 brightness = sd->brightness; + + for (i = 0; i < 4; i++) + reg_w_val(gspca_dev, ET_O_RED + i, brightness); +} + +static void getbrightness(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + int i; + int brightness = 0; + + for (i = 0; i < 4; i++) { + reg_r(gspca_dev, ET_O_RED + i, 1); + brightness += gspca_dev->usb_buf[0]; + } + sd->brightness = brightness >> 3; +} + +static void setcontrast(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + __u8 RGBG[] = { 0x80, 0x80, 0x80, 0x80, 0x00, 0x00 }; + __u8 contrast = sd->contrast; + + memset(RGBG, contrast, sizeof(RGBG) - 2); + reg_w(gspca_dev, ET_G_RED, RGBG, 6); +} + +static void getcontrast(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + int i; + int contrast = 0; + + for (i = 0; i < 4; i++) { + reg_r(gspca_dev, ET_G_RED + i, 1); + contrast += gspca_dev->usb_buf[0]; + } + sd->contrast = contrast >> 2; +} + +static __u8 Et_getgainG(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + + if (sd->sensor == SENSOR_PAS106) { + i2c_r(gspca_dev, PAS106_REG0e); + PDEBUG(D_CONF, "Etoms gain G %d", gspca_dev->usb_buf[0]); + return gspca_dev->usb_buf[0]; + } + return 0x1f; +} + +static void Et_setgainG(struct gspca_dev *gspca_dev, __u8 gain) +{ + struct sd *sd = (struct sd *) gspca_dev; + + if (sd->sensor == SENSOR_PAS106) { + __u8 i2cflags = 0x01; + + i2c_w(gspca_dev, PAS106_REG13, &i2cflags, 1, 3); + i2c_w(gspca_dev, PAS106_REG0e, &gain, 1, 1); + } +} + +#define BLIMIT(bright) \ + (__u8)((bright > 0x1f)?0x1f:((bright < 4)?3:bright)) +#define LIMIT(color) \ + (unsigned char)((color > 0xff)?0xff:((color < 0)?0:color)) + +static void setautogain(struct gspca_dev *gspca_dev) +{ + __u8 luma = 0; + __u8 luma_mean = 128; + __u8 luma_delta = 20; + __u8 spring = 4; + int Gbright = 0; + __u8 r, g, b; + + Gbright = Et_getgainG(gspca_dev); + reg_r(gspca_dev, ET_LUMA_CENTER, 4); + g = (gspca_dev->usb_buf[0] + gspca_dev->usb_buf[3]) >> 1; + r = gspca_dev->usb_buf[1]; + b = gspca_dev->usb_buf[2]; + r = ((r << 8) - (r << 4) - (r << 3)) >> 10; + b = ((b << 7) >> 10); + g = ((g << 9) + (g << 7) + (g << 5)) >> 10; + luma = LIMIT(r + g + b); + PDEBUG(D_FRAM, "Etoms luma G %d", luma); + if (luma < luma_mean - luma_delta || luma > luma_mean + luma_delta) { + Gbright += (luma_mean - luma) >> spring; + Gbright = BLIMIT(Gbright); + PDEBUG(D_FRAM, "Etoms Gbright %d", Gbright); + Et_setgainG(gspca_dev, (__u8) Gbright); + } +} + +#undef BLIMIT +#undef LIMIT + +static void sd_pkt_scan(struct gspca_dev *gspca_dev, + struct gspca_frame *frame, /* target */ + __u8 *data, /* isoc packet */ + int len) /* iso packet length */ +{ + struct sd *sd; + int seqframe; + + seqframe = data[0] & 0x3f; + len = (int) (((data[0] & 0xc0) << 2) | data[1]); + if (seqframe == 0x3f) { + PDEBUG(D_FRAM, + "header packet found datalength %d !!", len); + PDEBUG(D_FRAM, "G %d R %d G %d B %d", + data[2], data[3], data[4], data[5]); + data += 30; + /* don't change datalength as the chips provided it */ + frame = gspca_frame_add(gspca_dev, LAST_PACKET, frame, + data, 0); + gspca_frame_add(gspca_dev, FIRST_PACKET, frame, data, len); + sd = (struct sd *) gspca_dev; + if (sd->ag_cnt >= 0) { + if (--sd->ag_cnt < 0) { + sd->ag_cnt = AG_CNT_START; + setautogain(gspca_dev); + } + } + return; + } + if (len) { + data += 8; + gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len); + } else { /* Drop Packet */ + gspca_dev->last_packet_type = DISCARD_PACKET; + } +} + +static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->brightness = val; + if (gspca_dev->streaming) + setbrightness(gspca_dev); + return 0; +} + +static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + getbrightness(gspca_dev); + *val = sd->brightness; + return 0; +} + +static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->contrast = val; + if (gspca_dev->streaming) + setcontrast(gspca_dev); + return 0; +} + +static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + getcontrast(gspca_dev); + *val = sd->contrast; + return 0; +} + +static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->colors = val; + if (gspca_dev->streaming) + setcolors(gspca_dev); + return 0; +} + +static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + getcolors(gspca_dev); + *val = sd->colors; + return 0; +} + +static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->autogain = val; + if (val) + sd->ag_cnt = AG_CNT_START; + else + sd->ag_cnt = -1; + return 0; +} + +static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + *val = sd->autogain; + return 0; +} + +/* sub-driver description */ +static struct sd_desc sd_desc = { + .name = MODULE_NAME, + .ctrls = sd_ctrls, + .nctrls = ARRAY_SIZE(sd_ctrls), + .config = sd_config, + .open = sd_open, + .start = sd_start, + .stopN = sd_stopN, + .stop0 = sd_stop0, + .close = sd_close, + .pkt_scan = sd_pkt_scan, +}; + +/* -- module initialisation -- */ +#define DVNM(name) .driver_info = (kernel_ulong_t) name +static __devinitdata struct usb_device_id device_table[] = { +#ifndef CONFIG_USB_ET61X251 + {USB_DEVICE(0x102c, 0x6151), DVNM("Qcam Sangha CIF")}, +#endif + {USB_DEVICE(0x102c, 0x6251), DVNM("Qcam xxxxxx VGA")}, + {} +}; + +MODULE_DEVICE_TABLE(usb, device_table); + +/* -- device connect -- */ +static int sd_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd), + THIS_MODULE); +} + +static struct usb_driver sd_driver = { + .name = MODULE_NAME, + .id_table = device_table, + .probe = sd_probe, + .disconnect = gspca_disconnect, +}; + +/* -- module insert / remove -- */ +static int __init sd_mod_init(void) +{ + if (usb_register(&sd_driver) < 0) + return -1; + PDEBUG(D_PROBE, "v%s registered", version); + return 0; +} + +static void __exit sd_mod_exit(void) +{ + usb_deregister(&sd_driver); + PDEBUG(D_PROBE, "deregistered"); +} + +module_init(sd_mod_init); +module_exit(sd_mod_exit); diff --git a/drivers/media/video/gspca/gspca.c b/drivers/media/video/gspca/gspca.c new file mode 100644 index 000000000000..16e367cec760 --- /dev/null +++ b/drivers/media/video/gspca/gspca.c @@ -0,0 +1,1905 @@ +/* + * Main USB camera driver + * + * V4L2 by Jean-Francois Moine <http://moinejf.free.fr> + * + * 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. + */ + +#define MODULE_NAME "gspca" + +#include <linux/init.h> +#include <linux/fs.h> +#include <linux/vmalloc.h> +#include <linux/sched.h> +#include <linux/slab.h> +#include <linux/mm.h> +#include <linux/string.h> +#include <linux/pagemap.h> +#include <linux/io.h> +#include <asm/page.h> +#include <linux/uaccess.h> +#include <linux/jiffies.h> + +#include "gspca.h" + +/* global values */ +#define DEF_NURBS 2 /* default number of URBs */ + +MODULE_AUTHOR("Jean-Francois Moine <http://moinejf.free.fr>"); +MODULE_DESCRIPTION("GSPCA USB Camera Driver"); +MODULE_LICENSE("GPL"); + +#define DRIVER_VERSION_NUMBER KERNEL_VERSION(2, 1, 7) +static const char version[] = "2.1.7"; + +static int video_nr = -1; + +#ifdef CONFIG_VIDEO_ADV_DEBUG +int gspca_debug = D_ERR | D_PROBE; +EXPORT_SYMBOL(gspca_debug); + +static void PDEBUG_MODE(char *txt, __u32 pixfmt, int w, int h) +{ + if ((pixfmt >> 24) >= '0' && (pixfmt >> 24) <= 'z') { + PDEBUG(D_CONF|D_STREAM, "%s %c%c%c%c %dx%d", + txt, + pixfmt & 0xff, + (pixfmt >> 8) & 0xff, + (pixfmt >> 16) & 0xff, + pixfmt >> 24, + w, h); + } else { + PDEBUG(D_CONF|D_STREAM, "%s 0x%08x %dx%d", + txt, + pixfmt, + w, h); + } +} +#else +#define PDEBUG_MODE(txt, pixfmt, w, h) +#endif + +/* specific memory types - !! should different from V4L2_MEMORY_xxx */ +#define GSPCA_MEMORY_NO 0 /* V4L2_MEMORY_xxx starts from 1 */ +#define GSPCA_MEMORY_READ 7 + +#define BUF_ALL_FLAGS (V4L2_BUF_FLAG_QUEUED | V4L2_BUF_FLAG_DONE) + +/* + * VMA operations. + */ +static void gspca_vm_open(struct vm_area_struct *vma) +{ + struct gspca_frame *frame = vma->vm_private_data; + + frame->vma_use_count++; + frame->v4l2_buf.flags |= V4L2_BUF_FLAG_MAPPED; +} + +static void gspca_vm_close(struct vm_area_struct *vma) +{ + struct gspca_frame *frame = vma->vm_private_data; + + if (--frame->vma_use_count <= 0) + frame->v4l2_buf.flags &= ~V4L2_BUF_FLAG_MAPPED; +} + +static struct vm_operations_struct gspca_vm_ops = { + .open = gspca_vm_open, + .close = gspca_vm_close, +}; + +/* + * fill a video frame from an URB and resubmit + */ +static void fill_frame(struct gspca_dev *gspca_dev, + struct urb *urb) +{ + struct gspca_frame *frame; + __u8 *data; /* address of data in the iso message */ + int i, j, len, st; + cam_pkt_op pkt_scan; + + if (urb->status != 0) { + PDEBUG(D_ERR|D_PACK, "urb status: %d", urb->status); + return; /* disconnection ? */ + } + pkt_scan = gspca_dev->sd_desc->pkt_scan; + for (i = 0; i < urb->number_of_packets; i++) { + + /* check the availability of the frame buffer */ + j = gspca_dev->fr_i; + j = gspca_dev->fr_queue[j]; + frame = &gspca_dev->frame[j]; + if ((frame->v4l2_buf.flags & BUF_ALL_FLAGS) + != V4L2_BUF_FLAG_QUEUED) { + gspca_dev->last_packet_type = DISCARD_PACKET; + break; + } + + /* check the packet status and length */ + len = urb->iso_frame_desc[i].actual_length; + if (len == 0) + continue; + st = urb->iso_frame_desc[i].status; + if (st) { + PDEBUG(D_ERR, + "ISOC data error: [%d] len=%d, status=%d", + i, len, st); + gspca_dev->last_packet_type = DISCARD_PACKET; + continue; + } + + /* let the packet be analyzed by the subdriver */ + PDEBUG(D_PACK, "packet [%d] o:%d l:%d", + i, urb->iso_frame_desc[i].offset, len); + data = (__u8 *) urb->transfer_buffer + + urb->iso_frame_desc[i].offset; + pkt_scan(gspca_dev, frame, data, len); + } + + /* resubmit the URB */ + urb->status = 0; + st = usb_submit_urb(urb, GFP_ATOMIC); + if (st < 0) + PDEBUG(D_ERR|D_PACK, "usb_submit_urb() ret %d", st); +} + +/* + * ISOC message interrupt from the USB device + * + * Analyse each packet and call the subdriver for copy to the frame buffer. + */ +static void isoc_irq(struct urb *urb +) +{ + struct gspca_dev *gspca_dev = (struct gspca_dev *) urb->context; + + PDEBUG(D_PACK, "isoc irq"); + if (!gspca_dev->streaming) + return; + fill_frame(gspca_dev, urb); +} + +/* + * add data to the current frame + * + * This function is called by the subdrivers at interrupt level. + * + * To build a frame, these ones must add + * - one FIRST_PACKET + * - 0 or many INTER_PACKETs + * - one LAST_PACKET + * DISCARD_PACKET invalidates the whole frame. + * On LAST_PACKET, a new frame is returned. + */ +struct gspca_frame *gspca_frame_add(struct gspca_dev *gspca_dev, + int packet_type, + struct gspca_frame *frame, + const __u8 *data, + int len) +{ + int i, j; + + PDEBUG(D_PACK, "add t:%d l:%d", packet_type, len); + + /* when start of a new frame, if the current frame buffer + * is not queued, discard the whole frame */ + if (packet_type == FIRST_PACKET) { + if ((frame->v4l2_buf.flags & BUF_ALL_FLAGS) + != V4L2_BUF_FLAG_QUEUED) { + gspca_dev->last_packet_type = DISCARD_PACKET; + return frame; + } + frame->data_end = frame->data; + jiffies_to_timeval(get_jiffies_64(), + &frame->v4l2_buf.timestamp); + frame->v4l2_buf.sequence = ++gspca_dev->sequence; + } else if (gspca_dev->last_packet_type == DISCARD_PACKET) { + return frame; + } + + /* append the packet to the frame buffer */ + if (len > 0) { + if (frame->data_end - frame->data + len + > frame->v4l2_buf.length) { + PDEBUG(D_ERR|D_PACK, "frame overflow %zd > %d", + frame->data_end - frame->data + len, + frame->v4l2_buf.length); + packet_type = DISCARD_PACKET; + } else { + memcpy(frame->data_end, data, len); + frame->data_end += len; + } + } + gspca_dev->last_packet_type = packet_type; + + /* if last packet, wake the application and advance in the queue */ + if (packet_type == LAST_PACKET) { + frame->v4l2_buf.bytesused = frame->data_end - frame->data; + frame->v4l2_buf.flags &= ~V4L2_BUF_FLAG_QUEUED; + frame->v4l2_buf.flags |= V4L2_BUF_FLAG_DONE; + atomic_inc(&gspca_dev->nevent); + wake_up_interruptible(&gspca_dev->wq); /* event = new frame */ + i = (gspca_dev->fr_i + 1) % gspca_dev->nframes; + gspca_dev->fr_i = i; + PDEBUG(D_FRAM, "frame complete len:%d q:%d i:%d o:%d", + frame->v4l2_buf.bytesused, + gspca_dev->fr_q, + i, + gspca_dev->fr_o); + j = gspca_dev->fr_queue[i]; + frame = &gspca_dev->frame[j]; + } + return frame; +} +EXPORT_SYMBOL(gspca_frame_add); + +static int gspca_is_compressed(__u32 format) +{ + switch (format) { + case V4L2_PIX_FMT_MJPEG: + case V4L2_PIX_FMT_JPEG: + case V4L2_PIX_FMT_SPCA561: + case V4L2_PIX_FMT_PAC207: + return 1; + } + return 0; +} + +static void *rvmalloc(unsigned long size) +{ + void *mem; + unsigned long adr; + +/* size = PAGE_ALIGN(size); (already done) */ + mem = vmalloc_32(size); + if (mem != NULL) { + adr = (unsigned long) mem; + while ((long) size > 0) { + SetPageReserved(vmalloc_to_page((void *) adr)); + adr += PAGE_SIZE; + size -= PAGE_SIZE; + } + } + return mem; +} + +static void rvfree(void *mem, long size) +{ + unsigned long adr; + + adr = (unsigned long) mem; + while (size > 0) { + ClearPageReserved(vmalloc_to_page((void *) adr)); + adr += PAGE_SIZE; + size -= PAGE_SIZE; + } + vfree(mem); +} + +static int frame_alloc(struct gspca_dev *gspca_dev, + unsigned int count) +{ + struct gspca_frame *frame; + unsigned int frsz; + int i; + + i = gspca_dev->curr_mode; + frsz = gspca_dev->cam.cam_mode[i].sizeimage; + PDEBUG(D_STREAM, "frame alloc frsz: %d", frsz); + frsz = PAGE_ALIGN(frsz); + gspca_dev->frsz = frsz; + if (count > GSPCA_MAX_FRAMES) + count = GSPCA_MAX_FRAMES; + gspca_dev->frbuf = rvmalloc(frsz * count); + if (!gspca_dev->frbuf) { + err("frame alloc failed"); + return -ENOMEM; + } + gspca_dev->nframes = count; + for (i = 0; i < count; i++) { + frame = &gspca_dev->frame[i]; + frame->v4l2_buf.index = i; + frame->v4l2_buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + frame->v4l2_buf.flags = 0; + frame->v4l2_buf.field = V4L2_FIELD_NONE; + frame->v4l2_buf.length = frsz; + frame->v4l2_buf.memory = gspca_dev->memory; + frame->v4l2_buf.sequence = 0; + frame->data = frame->data_end = + gspca_dev->frbuf + i * frsz; + frame->v4l2_buf.m.offset = i * frsz; + } + gspca_dev->fr_i = gspca_dev->fr_o = gspca_dev->fr_q = 0; + gspca_dev->last_packet_type = DISCARD_PACKET; + gspca_dev->sequence = 0; + atomic_set(&gspca_dev->nevent, 0); + return 0; +} + +static void frame_free(struct gspca_dev *gspca_dev) +{ + int i; + + PDEBUG(D_STREAM, "frame free"); + if (gspca_dev->frbuf != NULL) { + rvfree(gspca_dev->frbuf, + gspca_dev->nframes * gspca_dev->frsz); + gspca_dev->frbuf = NULL; + for (i = 0; i < gspca_dev->nframes; i++) + gspca_dev->frame[i].data = NULL; + } + gspca_dev->nframes = 0; +} + +static void destroy_urbs(struct gspca_dev *gspca_dev) +{ + struct urb *urb; + unsigned int i; + + PDEBUG(D_STREAM, "kill transfer"); + for (i = 0; i < MAX_NURBS; ++i) { + urb = gspca_dev->urb[i]; + if (urb == NULL) + break; + + gspca_dev->urb[i] = NULL; + usb_kill_urb(urb); + if (urb->transfer_buffer != NULL) + usb_buffer_free(gspca_dev->dev, + urb->transfer_buffer_length, + urb->transfer_buffer, + urb->transfer_dma); + usb_free_urb(urb); + } +} + +/* + * search an input isochronous endpoint in an alternate setting + */ +static struct usb_host_endpoint *alt_isoc(struct usb_host_interface *alt, + __u8 epaddr) +{ + struct usb_host_endpoint *ep; + int i, attr; + + epaddr |= USB_DIR_IN; + for (i = 0; i < alt->desc.bNumEndpoints; i++) { + ep = &alt->endpoint[i]; + if (ep->desc.bEndpointAddress == epaddr) { + attr = ep->desc.bmAttributes + & USB_ENDPOINT_XFERTYPE_MASK; + if (attr == USB_ENDPOINT_XFER_ISOC) + return ep; + break; + } + } + return NULL; +} + +/* + * search an input isochronous endpoint + * + * The endpoint is defined by the subdriver. + * Use only the first isoc (some Zoran - 0x0572:0x0001 - have two such ep). + * This routine may be called many times when the bandwidth is too small + * (the bandwidth is checked on urb submit). + */ +struct usb_host_endpoint *get_isoc_ep(struct gspca_dev *gspca_dev) +{ + struct usb_interface *intf; + struct usb_host_endpoint *ep; + int i, ret; + + intf = usb_ifnum_to_if(gspca_dev->dev, gspca_dev->iface); + ep = NULL; + i = gspca_dev->alt; /* previous alt setting */ + while (--i > 0) { /* alt 0 is unusable */ + ep = alt_isoc(&intf->altsetting[i], gspca_dev->cam.epaddr); + if (ep) + break; + } + if (ep == NULL) { + err("no ISOC endpoint found"); + return NULL; + } + PDEBUG(D_STREAM, "use ISOC alt %d ep 0x%02x", + i, ep->desc.bEndpointAddress); + ret = usb_set_interface(gspca_dev->dev, gspca_dev->iface, i); + if (ret < 0) { + err("set interface err %d", ret); + return NULL; + } + gspca_dev->alt = i; /* memorize the current alt setting */ + return ep; +} + +/* + * create the isochronous URBs + */ +static int create_urbs(struct gspca_dev *gspca_dev, + struct usb_host_endpoint *ep) +{ + struct urb *urb; + int n, nurbs, i, psize, npkt, bsize; + + /* calculate the packet size and the number of packets */ + psize = le16_to_cpu(ep->desc.wMaxPacketSize); + + /* See paragraph 5.9 / table 5-11 of the usb 2.0 spec. */ + psize = (psize & 0x07ff) * (1 + ((psize >> 11) & 3)); + npkt = ISO_MAX_SIZE / psize; + if (npkt > ISO_MAX_PKT) + npkt = ISO_MAX_PKT; + bsize = psize * npkt; + PDEBUG(D_STREAM, + "isoc %d pkts size %d (bsize:%d)", npkt, psize, bsize); + nurbs = DEF_NURBS; + gspca_dev->nurbs = nurbs; + for (n = 0; n < nurbs; n++) { + urb = usb_alloc_urb(npkt, GFP_KERNEL); + if (!urb) { + err("usb_alloc_urb failed"); + return -ENOMEM; + } + urb->transfer_buffer = usb_buffer_alloc(gspca_dev->dev, + bsize, + GFP_KERNEL, + &urb->transfer_dma); + + if (urb->transfer_buffer == NULL) { + usb_free_urb(urb); + destroy_urbs(gspca_dev); + err("usb_buffer_urb failed"); + return -ENOMEM; + } + gspca_dev->urb[n] = urb; + urb->dev = gspca_dev->dev; + urb->context = gspca_dev; + urb->pipe = usb_rcvisocpipe(gspca_dev->dev, + ep->desc.bEndpointAddress); + urb->transfer_flags = URB_ISO_ASAP + | URB_NO_TRANSFER_DMA_MAP; + urb->interval = ep->desc.bInterval; + urb->complete = isoc_irq; + urb->number_of_packets = npkt; + urb->transfer_buffer_length = bsize; + for (i = 0; i < npkt; i++) { + urb->iso_frame_desc[i].length = psize; + urb->iso_frame_desc[i].offset = psize * i; + } + } + return 0; +} + +/* + * start the USB transfer + */ +static int gspca_init_transfer(struct gspca_dev *gspca_dev) +{ + struct usb_host_endpoint *ep; + int n, ret; + + if (mutex_lock_interruptible(&gspca_dev->usb_lock)) + return -ERESTARTSYS; + + /* set the higher alternate setting and + * loop until urb submit succeeds */ + gspca_dev->alt = gspca_dev->nbalt; + for (;;) { + PDEBUG(D_STREAM, "init transfer alt %d", gspca_dev->alt); + ep = get_isoc_ep(gspca_dev); + if (ep == NULL) { + ret = -EIO; + goto out; + } + ret = create_urbs(gspca_dev, ep); + if (ret < 0) + goto out; + + /* start the cam */ + gspca_dev->sd_desc->start(gspca_dev); + gspca_dev->streaming = 1; + atomic_set(&gspca_dev->nevent, 0); + + /* submit the URBs */ + for (n = 0; n < gspca_dev->nurbs; n++) { + ret = usb_submit_urb(gspca_dev->urb[n], GFP_KERNEL); + if (ret < 0) { + PDEBUG(D_ERR|D_STREAM, + "usb_submit_urb [%d] err %d", n, ret); + gspca_dev->streaming = 0; + destroy_urbs(gspca_dev); + if (ret == -ENOSPC) + break; /* try the previous alt */ + goto out; + } + } + if (ret >= 0) + break; + } +out: + mutex_unlock(&gspca_dev->usb_lock); + return ret; +} + +static int gspca_set_alt0(struct gspca_dev *gspca_dev) +{ + int ret; + + ret = usb_set_interface(gspca_dev->dev, gspca_dev->iface, 0); + if (ret < 0) + PDEBUG(D_ERR|D_STREAM, "set interface 0 err %d", ret); + return ret; +} + +/* Note both the queue and the usb lock should be hold when calling this */ +static void gspca_stream_off(struct gspca_dev *gspca_dev) +{ + gspca_dev->streaming = 0; + atomic_set(&gspca_dev->nevent, 0); + if (gspca_dev->present) { + gspca_dev->sd_desc->stopN(gspca_dev); + destroy_urbs(gspca_dev); + gspca_set_alt0(gspca_dev); + gspca_dev->sd_desc->stop0(gspca_dev); + PDEBUG(D_STREAM, "stream off OK"); + } +} + +static void gspca_set_default_mode(struct gspca_dev *gspca_dev) +{ + int i; + + i = gspca_dev->cam.nmodes - 1; /* take the highest mode */ + gspca_dev->curr_mode = i; + gspca_dev->width = gspca_dev->cam.cam_mode[i].width; + gspca_dev->height = gspca_dev->cam.cam_mode[i].height; + gspca_dev->pixfmt = gspca_dev->cam.cam_mode[i].pixelformat; +} + +static int wxh_to_mode(struct gspca_dev *gspca_dev, + int width, int height) +{ + int i; + + for (i = gspca_dev->cam.nmodes; --i > 0; ) { + if (width >= gspca_dev->cam.cam_mode[i].width + && height >= gspca_dev->cam.cam_mode[i].height) + break; + } + return i; +} + +/* + * search a mode with the right pixel format + */ +static int gspca_get_mode(struct gspca_dev *gspca_dev, + int mode, + int pixfmt) +{ + int modeU, modeD; + + modeU = modeD = mode; + while ((modeU < gspca_dev->cam.nmodes) || modeD >= 0) { + if (--modeD >= 0) { + if (gspca_dev->cam.cam_mode[modeD].pixelformat + == pixfmt) + return modeD; + } + if (++modeU < gspca_dev->cam.nmodes) { + if (gspca_dev->cam.cam_mode[modeU].pixelformat + == pixfmt) + return modeU; + } + } + return -EINVAL; +} + +static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_fmtdesc *fmtdesc) +{ + struct gspca_dev *gspca_dev = priv; + int i, j, index; + __u32 fmt_tb[8]; + + /* give an index to each format */ + index = 0; + j = 0; + for (i = gspca_dev->cam.nmodes; --i >= 0; ) { + fmt_tb[index] = gspca_dev->cam.cam_mode[i].pixelformat; + j = 0; + for (;;) { + if (fmt_tb[j] == fmt_tb[index]) + break; + j++; + } + if (j == index) { + if (fmtdesc->index == index) + break; /* new format */ + index++; + if (index >= sizeof fmt_tb / sizeof fmt_tb[0]) + return -EINVAL; + } + } + if (i < 0) + return -EINVAL; /* no more format */ + + fmtdesc->pixelformat = fmt_tb[index]; + if (gspca_is_compressed(fmt_tb[index])) + fmtdesc->flags = V4L2_FMT_FLAG_COMPRESSED; + fmtdesc->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + fmtdesc->description[0] = fmtdesc->pixelformat & 0xff; + fmtdesc->description[1] = (fmtdesc->pixelformat >> 8) & 0xff; + fmtdesc->description[2] = (fmtdesc->pixelformat >> 16) & 0xff; + fmtdesc->description[3] = fmtdesc->pixelformat >> 24; + fmtdesc->description[4] = '\0'; + return 0; +} + +static int vidioc_g_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_format *fmt) +{ + struct gspca_dev *gspca_dev = priv; + int mode; + + if (fmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; + mode = gspca_dev->curr_mode; + memcpy(&fmt->fmt.pix, &gspca_dev->cam.cam_mode[mode], + sizeof fmt->fmt.pix); + return 0; +} + +static int try_fmt_vid_cap(struct gspca_dev *gspca_dev, + struct v4l2_format *fmt) +{ + int w, h, mode, mode2; + + if (fmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; + w = fmt->fmt.pix.width; + h = fmt->fmt.pix.height; + +#ifdef CONFIG_VIDEO_ADV_DEBUG + if (gspca_debug & D_CONF) + PDEBUG_MODE("try fmt cap", fmt->fmt.pix.pixelformat, w, h); +#endif + /* search the closest mode for width and height */ + mode = wxh_to_mode(gspca_dev, w, h); + + /* OK if right palette */ + if (gspca_dev->cam.cam_mode[mode].pixelformat + != fmt->fmt.pix.pixelformat) { + + /* else, search the closest mode with the same pixel format */ + mode2 = gspca_get_mode(gspca_dev, mode, + fmt->fmt.pix.pixelformat); + if (mode2 >= 0) + mode = mode2; +/* else + ; * no chance, return this mode */ + } + memcpy(&fmt->fmt.pix, &gspca_dev->cam.cam_mode[mode], + sizeof fmt->fmt.pix); + return mode; /* used when s_fmt */ +} + +static int vidioc_try_fmt_vid_cap(struct file *file, + void *priv, + struct v4l2_format *fmt) +{ + struct gspca_dev *gspca_dev = priv; + int ret; + + ret = try_fmt_vid_cap(gspca_dev, fmt); + if (ret < 0) + return ret; + return 0; +} + +static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_format *fmt) +{ + struct gspca_dev *gspca_dev = priv; + int ret; + + if (mutex_lock_interruptible(&gspca_dev->queue_lock)) + return -ERESTARTSYS; + + ret = try_fmt_vid_cap(gspca_dev, fmt); + if (ret < 0) + goto out; + + if (gspca_dev->nframes != 0 + && fmt->fmt.pix.sizeimage > gspca_dev->frsz) { + ret = -EINVAL; + goto out; + } + + if (ret == gspca_dev->curr_mode) { + ret = 0; + goto out; /* same mode */ + } + + if (gspca_dev->streaming) { + ret = -EBUSY; + goto out; + } + gspca_dev->width = fmt->fmt.pix.width; + gspca_dev->height = fmt->fmt.pix.height; + gspca_dev->pixfmt = fmt->fmt.pix.pixelformat; + gspca_dev->curr_mode = ret; + + ret = 0; +out: + mutex_unlock(&gspca_dev->queue_lock); + return ret; +} + +static int dev_open(struct inode *inode, struct file *file) +{ + struct gspca_dev *gspca_dev; + int ret; + + PDEBUG(D_STREAM, "%s open", current->comm); + gspca_dev = (struct gspca_dev *) video_devdata(file); + if (mutex_lock_interruptible(&gspca_dev->queue_lock)) + return -ERESTARTSYS; + if (!gspca_dev->present) { + ret = -ENODEV; + goto out; + } + + /* if not done yet, initialize the sensor */ + if (gspca_dev->users == 0) { + if (mutex_lock_interruptible(&gspca_dev->usb_lock)) { + ret = -ERESTARTSYS; + goto out; + } + ret = gspca_dev->sd_desc->open(gspca_dev); + mutex_unlock(&gspca_dev->usb_lock); + if (ret != 0) { + PDEBUG(D_ERR|D_CONF, "init device failed %d", ret); + goto out; + } + } else if (gspca_dev->users > 4) { /* (arbitrary value) */ + ret = -EBUSY; + goto out; + } + gspca_dev->users++; + file->private_data = gspca_dev; +#ifdef CONFIG_VIDEO_ADV_DEBUG + /* activate the v4l2 debug */ + if (gspca_debug & D_V4L2) + gspca_dev->vdev.debug |= 3; + else + gspca_dev->vdev.debug &= ~3; +#endif +out: + mutex_unlock(&gspca_dev->queue_lock); + if (ret != 0) + PDEBUG(D_ERR|D_STREAM, "open failed err %d", ret); + else + PDEBUG(D_STREAM, "open done"); + return ret; +} + +static int dev_close(struct inode *inode, struct file *file) +{ + struct gspca_dev *gspca_dev = file->private_data; + + PDEBUG(D_STREAM, "%s close", current->comm); + if (mutex_lock_interruptible(&gspca_dev->queue_lock)) + return -ERESTARTSYS; + gspca_dev->users--; + + /* if the file did the capture, free the streaming resources */ + if (gspca_dev->capt_file == file) { + mutex_lock(&gspca_dev->usb_lock); + if (gspca_dev->streaming) + gspca_stream_off(gspca_dev); + gspca_dev->sd_desc->close(gspca_dev); + mutex_unlock(&gspca_dev->usb_lock); + frame_free(gspca_dev); + gspca_dev->capt_file = NULL; + gspca_dev->memory = GSPCA_MEMORY_NO; + } + file->private_data = NULL; + mutex_unlock(&gspca_dev->queue_lock); + PDEBUG(D_STREAM, "close done"); + return 0; +} + +static int vidioc_querycap(struct file *file, void *priv, + struct v4l2_capability *cap) +{ + struct gspca_dev *gspca_dev = priv; + + memset(cap, 0, sizeof *cap); + strncpy(cap->driver, gspca_dev->sd_desc->name, sizeof cap->driver); + strncpy(cap->card, gspca_dev->cam.dev_name, sizeof cap->card); + strncpy(cap->bus_info, gspca_dev->dev->bus->bus_name, + sizeof cap->bus_info); + cap->version = DRIVER_VERSION_NUMBER; + cap->capabilities = V4L2_CAP_VIDEO_CAPTURE + | V4L2_CAP_STREAMING + | V4L2_CAP_READWRITE; + return 0; +} + +/* the use of V4L2_CTRL_FLAG_NEXT_CTRL asks for the controls to be sorted */ +static int vidioc_queryctrl(struct file *file, void *priv, + struct v4l2_queryctrl *q_ctrl) +{ + struct gspca_dev *gspca_dev = priv; + int i; + u32 id; + + id = q_ctrl->id; + if (id & V4L2_CTRL_FLAG_NEXT_CTRL) { + id &= V4L2_CTRL_ID_MASK; + id++; + for (i = 0; i < gspca_dev->sd_desc->nctrls; i++) { + if (id >= gspca_dev->sd_desc->ctrls[i].qctrl.id) { + memcpy(q_ctrl, + &gspca_dev->sd_desc->ctrls[i].qctrl, + sizeof *q_ctrl); + return 0; + } + } + return -EINVAL; + } + for (i = 0; i < gspca_dev->sd_desc->nctrls; i++) { + if (id == gspca_dev->sd_desc->ctrls[i].qctrl.id) { + memcpy(q_ctrl, + &gspca_dev->sd_desc->ctrls[i].qctrl, + sizeof *q_ctrl); + return 0; + } + } + if (id >= V4L2_CID_BASE + && id <= V4L2_CID_LASTP1) { + q_ctrl->flags |= V4L2_CTRL_FLAG_DISABLED; + return 0; + } + return -EINVAL; +} + +static int vidioc_s_ctrl(struct file *file, void *priv, + struct v4l2_control *ctrl) +{ + struct gspca_dev *gspca_dev = priv; + const struct ctrl *ctrls; + int i, ret; + + for (i = 0, ctrls = gspca_dev->sd_desc->ctrls; + i < gspca_dev->sd_desc->nctrls; + i++, ctrls++) { + if (ctrl->id != ctrls->qctrl.id) + continue; + if (ctrl->value < ctrls->qctrl.minimum + && ctrl->value > ctrls->qctrl.maximum) + return -ERANGE; + PDEBUG(D_CONF, "set ctrl [%08x] = %d", ctrl->id, ctrl->value); + if (mutex_lock_interruptible(&gspca_dev->usb_lock)) + return -ERESTARTSYS; + ret = ctrls->set(gspca_dev, ctrl->value); + mutex_unlock(&gspca_dev->usb_lock); + return ret; + } + return -EINVAL; +} + +static int vidioc_g_ctrl(struct file *file, void *priv, + struct v4l2_control *ctrl) +{ + struct gspca_dev *gspca_dev = priv; + + const struct ctrl *ctrls; + int i, ret; + + for (i = 0, ctrls = gspca_dev->sd_desc->ctrls; + i < gspca_dev->sd_desc->nctrls; + i++, ctrls++) { + if (ctrl->id != ctrls->qctrl.id) + continue; + if (mutex_lock_interruptible(&gspca_dev->usb_lock)) + return -ERESTARTSYS; + ret = ctrls->get(gspca_dev, &ctrl->value); + mutex_unlock(&gspca_dev->usb_lock); + return ret; + } + return -EINVAL; +} + +static int vidioc_querymenu(struct file *file, void *priv, + struct v4l2_querymenu *qmenu) +{ + struct gspca_dev *gspca_dev = priv; + + if (!gspca_dev->sd_desc->querymenu) + return -EINVAL; + return gspca_dev->sd_desc->querymenu(gspca_dev, qmenu); +} + +static int vidioc_enum_input(struct file *file, void *priv, + struct v4l2_input *input) +{ + struct gspca_dev *gspca_dev = priv; + + if (input->index != 0) + return -EINVAL; + memset(input, 0, sizeof *input); + input->type = V4L2_INPUT_TYPE_CAMERA; + strncpy(input->name, gspca_dev->sd_desc->name, + sizeof input->name); + return 0; +} + +static int vidioc_g_input(struct file *file, void *priv, unsigned int *i) +{ + *i = 0; + return 0; +} + +static int vidioc_s_input(struct file *file, void *priv, unsigned int i) +{ + if (i > 0) + return -EINVAL; + return (0); +} + +static int vidioc_reqbufs(struct file *file, void *priv, + struct v4l2_requestbuffers *rb) +{ + struct gspca_dev *gspca_dev = priv; + int i, ret = 0; + + if (rb->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; + switch (rb->memory) { + case GSPCA_MEMORY_READ: /* (internal call) */ + case V4L2_MEMORY_MMAP: + case V4L2_MEMORY_USERPTR: + break; + default: + return -EINVAL; + } + if (mutex_lock_interruptible(&gspca_dev->queue_lock)) + return -ERESTARTSYS; + + if (gspca_dev->memory != GSPCA_MEMORY_NO + && gspca_dev->memory != rb->memory) { + ret = -EBUSY; + goto out; + } + + /* only one file may do the capture */ + if (gspca_dev->capt_file != NULL + && gspca_dev->capt_file != file) { + ret = -EBUSY; + goto out; + } + + /* if allocated, the buffers must not be mapped */ + for (i = 0; i < gspca_dev->nframes; i++) { + if (gspca_dev->frame[i].vma_use_count) { + ret = -EBUSY; + goto out; + } + } + + /* stop streaming */ + if (gspca_dev->streaming) { + mutex_lock(&gspca_dev->usb_lock); + gspca_stream_off(gspca_dev); + mutex_unlock(&gspca_dev->usb_lock); + } + + /* free the previous allocated buffers, if any */ + if (gspca_dev->nframes != 0) { + frame_free(gspca_dev); + gspca_dev->capt_file = NULL; + } + if (rb->count == 0) /* unrequest */ + goto out; + gspca_dev->memory = rb->memory; + ret = frame_alloc(gspca_dev, rb->count); + if (ret == 0) { + rb->count = gspca_dev->nframes; + gspca_dev->capt_file = file; + } +out: + mutex_unlock(&gspca_dev->queue_lock); + PDEBUG(D_STREAM, "reqbufs st:%d c:%d", ret, rb->count); + return ret; +} + +static int vidioc_querybuf(struct file *file, void *priv, + struct v4l2_buffer *v4l2_buf) +{ + struct gspca_dev *gspca_dev = priv; + struct gspca_frame *frame; + + if (v4l2_buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE + || v4l2_buf->index < 0 + || v4l2_buf->index >= gspca_dev->nframes) + return -EINVAL; + + frame = &gspca_dev->frame[v4l2_buf->index]; + memcpy(v4l2_buf, &frame->v4l2_buf, sizeof *v4l2_buf); + return 0; +} + +static int vidioc_streamon(struct file *file, void *priv, + enum v4l2_buf_type buf_type) +{ + struct gspca_dev *gspca_dev = priv; + int ret; + + if (buf_type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; + if (mutex_lock_interruptible(&gspca_dev->queue_lock)) + return -ERESTARTSYS; + if (!gspca_dev->present) { + ret = -ENODEV; + goto out; + } + if (gspca_dev->nframes == 0) { + ret = -EINVAL; + goto out; + } + if (!gspca_dev->streaming) { + ret = gspca_init_transfer(gspca_dev); + if (ret < 0) + goto out; + } +#ifdef CONFIG_VIDEO_ADV_DEBUG + if (gspca_debug & D_STREAM) { + PDEBUG_MODE("stream on OK", + gspca_dev->pixfmt, + gspca_dev->width, + gspca_dev->height); + } +#endif + ret = 0; +out: + mutex_unlock(&gspca_dev->queue_lock); + return ret; +} + +static int vidioc_streamoff(struct file *file, void *priv, + enum v4l2_buf_type buf_type) +{ + struct gspca_dev *gspca_dev = priv; + int i, ret; + + if (buf_type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; + if (!gspca_dev->streaming) + return 0; + if (mutex_lock_interruptible(&gspca_dev->queue_lock)) + return -ERESTARTSYS; + + /* stop streaming */ + if (mutex_lock_interruptible(&gspca_dev->usb_lock)) { + ret = -ERESTARTSYS; + goto out; + } + gspca_stream_off(gspca_dev); + mutex_unlock(&gspca_dev->usb_lock); + + /* empty the application queues */ + for (i = 0; i < gspca_dev->nframes; i++) + gspca_dev->frame[i].v4l2_buf.flags &= ~BUF_ALL_FLAGS; + gspca_dev->fr_i = gspca_dev->fr_o = gspca_dev->fr_q = 0; + gspca_dev->last_packet_type = DISCARD_PACKET; + gspca_dev->sequence = 0; + atomic_set(&gspca_dev->nevent, 0); + ret = 0; +out: + mutex_unlock(&gspca_dev->queue_lock); + return ret; +} + +static int vidioc_g_jpegcomp(struct file *file, void *priv, + struct v4l2_jpegcompression *jpegcomp) +{ + struct gspca_dev *gspca_dev = priv; + int ret; + + if (!gspca_dev->sd_desc->get_jcomp) + return -EINVAL; + if (mutex_lock_interruptible(&gspca_dev->usb_lock)) + return -ERESTARTSYS; + ret = gspca_dev->sd_desc->get_jcomp(gspca_dev, jpegcomp); + mutex_unlock(&gspca_dev->usb_lock); + return ret; +} + +static int vidioc_s_jpegcomp(struct file *file, void *priv, + struct v4l2_jpegcompression *jpegcomp) +{ + struct gspca_dev *gspca_dev = priv; + int ret; + + if (mutex_lock_interruptible(&gspca_dev->usb_lock)) + return -ERESTARTSYS; + if (!gspca_dev->sd_desc->set_jcomp) + return -EINVAL; + ret = gspca_dev->sd_desc->set_jcomp(gspca_dev, jpegcomp); + mutex_unlock(&gspca_dev->usb_lock); + return ret; +} + +static int vidioc_g_parm(struct file *filp, void *priv, + struct v4l2_streamparm *parm) +{ + struct gspca_dev *gspca_dev = priv; + + memset(parm, 0, sizeof *parm); + parm->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + parm->parm.capture.readbuffers = gspca_dev->nbufread; + return 0; +} + +static int vidioc_s_parm(struct file *filp, void *priv, + struct v4l2_streamparm *parm) +{ + struct gspca_dev *gspca_dev = priv; + int n; + + n = parm->parm.capture.readbuffers; + if (n == 0 || n > GSPCA_MAX_FRAMES) + parm->parm.capture.readbuffers = gspca_dev->nbufread; + else + gspca_dev->nbufread = n; + return 0; +} + +static int vidioc_s_std(struct file *filp, void *priv, + v4l2_std_id *parm) +{ + return 0; +} + +#ifdef CONFIG_VIDEO_V4L1_COMPAT +static int vidiocgmbuf(struct file *file, void *priv, + struct video_mbuf *mbuf) +{ + struct gspca_dev *gspca_dev = file->private_data; + int i; + + PDEBUG(D_STREAM, "cgmbuf"); + if (gspca_dev->nframes == 0) { + int ret; + + { + struct v4l2_format fmt; + + memset(&fmt, 0, sizeof fmt); + fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + i = gspca_dev->cam.nmodes - 1; /* highest mode */ + fmt.fmt.pix.width = gspca_dev->cam.cam_mode[i].width; + fmt.fmt.pix.height = gspca_dev->cam.cam_mode[i].height; + fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_BGR24; + ret = vidioc_s_fmt_vid_cap(file, priv, &fmt); + if (ret != 0) + return ret; + } + { + struct v4l2_requestbuffers rb; + + memset(&rb, 0, sizeof rb); + rb.count = 4; + rb.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + rb.memory = V4L2_MEMORY_MMAP; + ret = vidioc_reqbufs(file, priv, &rb); + if (ret != 0) + return ret; + } + } + mbuf->frames = gspca_dev->nframes; + mbuf->size = gspca_dev->frsz * gspca_dev->nframes; + for (i = 0; i < mbuf->frames; i++) + mbuf->offsets[i] = gspca_dev->frame[i].v4l2_buf.m.offset; + return 0; +} +#endif + +static int dev_mmap(struct file *file, struct vm_area_struct *vma) +{ + struct gspca_dev *gspca_dev = file->private_data; + struct gspca_frame *frame; + struct page *page; + unsigned long addr, start, size; + int i, ret; + + start = vma->vm_start; + size = vma->vm_end - vma->vm_start; + PDEBUG(D_STREAM, "mmap start:%08x size:%d", (int) start, (int) size); + + if (mutex_lock_interruptible(&gspca_dev->queue_lock)) + return -ERESTARTSYS; + if (!gspca_dev->present) { + ret = -ENODEV; + goto out; + } + if (gspca_dev->capt_file != file) { + ret = -EINVAL; + goto out; + } + + frame = NULL; + for (i = 0; i < gspca_dev->nframes; ++i) { + if (gspca_dev->frame[i].v4l2_buf.memory != V4L2_MEMORY_MMAP) { + PDEBUG(D_STREAM, "mmap bad memory type"); + break; + } + if ((gspca_dev->frame[i].v4l2_buf.m.offset >> PAGE_SHIFT) + == vma->vm_pgoff) { + frame = &gspca_dev->frame[i]; + break; + } + } + if (frame == NULL) { + PDEBUG(D_STREAM, "mmap no frame buffer found"); + ret = -EINVAL; + goto out; + } +#ifdef CONFIG_VIDEO_V4L1_COMPAT + /* v4l1 maps all the buffers */ + if (i != 0 + || size != frame->v4l2_buf.length * gspca_dev->nframes) +#endif + if (size != frame->v4l2_buf.length) { + PDEBUG(D_STREAM, "mmap bad size"); + ret = -EINVAL; + goto out; + } + + /* + * - VM_IO marks the area as being a mmaped region for I/O to a + * device. It also prevents the region from being core dumped. + */ + vma->vm_flags |= VM_IO; + + addr = (unsigned long) frame->data; + while (size > 0) { + page = vmalloc_to_page((void *) addr); + ret = vm_insert_page(vma, start, page); + if (ret < 0) + goto out; + start += PAGE_SIZE; + addr += PAGE_SIZE; + size -= PAGE_SIZE; + } + + vma->vm_ops = &gspca_vm_ops; + vma->vm_private_data = frame; + gspca_vm_open(vma); + ret = 0; +out: + mutex_unlock(&gspca_dev->queue_lock); + return ret; +} + +/* + * wait for a video frame + * + * If a frame is ready, its index is returned. + */ +static int frame_wait(struct gspca_dev *gspca_dev, + int nonblock_ing) +{ + struct gspca_frame *frame; + int i, j, ret; + + /* check if a frame is ready */ + i = gspca_dev->fr_o; + j = gspca_dev->fr_queue[i]; + frame = &gspca_dev->frame[j]; + if (frame->v4l2_buf.flags & V4L2_BUF_FLAG_DONE) { + atomic_dec(&gspca_dev->nevent); + goto ok; + } + if (nonblock_ing) /* no frame yet */ + return -EAGAIN; + + /* wait till a frame is ready */ + for (;;) { + ret = wait_event_interruptible_timeout(gspca_dev->wq, + atomic_read(&gspca_dev->nevent) > 0, + msecs_to_jiffies(3000)); + if (ret <= 0) { + if (ret < 0) + return ret; /* interrupt */ + return -EIO; /* timeout */ + } + atomic_dec(&gspca_dev->nevent); + if (!gspca_dev->streaming || !gspca_dev->present) + return -EIO; + i = gspca_dev->fr_o; + j = gspca_dev->fr_queue[i]; + frame = &gspca_dev->frame[j]; + if (frame->v4l2_buf.flags & V4L2_BUF_FLAG_DONE) + break; + } +ok: + gspca_dev->fr_o = (i + 1) % gspca_dev->nframes; + PDEBUG(D_FRAM, "frame wait q:%d i:%d o:%d", + gspca_dev->fr_q, + gspca_dev->fr_i, + gspca_dev->fr_o); + + if (gspca_dev->sd_desc->dq_callback) { + mutex_lock(&gspca_dev->usb_lock); + gspca_dev->sd_desc->dq_callback(gspca_dev); + mutex_unlock(&gspca_dev->usb_lock); + } + return j; +} + +/* + * dequeue a video buffer + * + * If nonblock_ing is false, block until a buffer is available. + */ +static int vidioc_dqbuf(struct file *file, void *priv, + struct v4l2_buffer *v4l2_buf) +{ + struct gspca_dev *gspca_dev = priv; + struct gspca_frame *frame; + int i, ret; + + PDEBUG(D_FRAM, "dqbuf"); + if (v4l2_buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; + if (v4l2_buf->memory != gspca_dev->memory) + return -EINVAL; + + /* if not streaming, be sure the application will not loop forever */ + if (!(file->f_flags & O_NONBLOCK) + && !gspca_dev->streaming && gspca_dev->users == 1) + return -EINVAL; + + /* only the capturing file may dequeue */ + if (gspca_dev->capt_file != file) + return -EINVAL; + + /* only one dequeue / read at a time */ + if (mutex_lock_interruptible(&gspca_dev->read_lock)) + return -ERESTARTSYS; + + ret = frame_wait(gspca_dev, file->f_flags & O_NONBLOCK); + if (ret < 0) + goto out; + i = ret; /* frame index */ + frame = &gspca_dev->frame[i]; + if (gspca_dev->memory == V4L2_MEMORY_USERPTR) { + if (copy_to_user((__u8 *) frame->v4l2_buf.m.userptr, + frame->data, + frame->v4l2_buf.bytesused)) { + PDEBUG(D_ERR|D_STREAM, + "dqbuf cp to user failed"); + ret = -EFAULT; + goto out; + } + } + frame->v4l2_buf.flags &= ~V4L2_BUF_FLAG_DONE; + memcpy(v4l2_buf, &frame->v4l2_buf, sizeof *v4l2_buf); + PDEBUG(D_FRAM, "dqbuf %d", i); + ret = 0; +out: + mutex_unlock(&gspca_dev->read_lock); + return ret; +} + +/* + * queue a video buffer + * + * Attempting to queue a buffer that has already been + * queued will return -EINVAL. + */ +static int vidioc_qbuf(struct file *file, void *priv, + struct v4l2_buffer *v4l2_buf) +{ + struct gspca_dev *gspca_dev = priv; + struct gspca_frame *frame; + int i, index, ret; + + PDEBUG(D_FRAM, "qbuf %d", v4l2_buf->index); + if (v4l2_buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; + + if (mutex_lock_interruptible(&gspca_dev->queue_lock)) + return -ERESTARTSYS; + + index = v4l2_buf->index; + if ((unsigned) index >= gspca_dev->nframes) { + PDEBUG(D_FRAM, + "qbuf idx %d >= %d", index, gspca_dev->nframes); + ret = -EINVAL; + goto out; + } + if (v4l2_buf->memory != gspca_dev->memory) { + PDEBUG(D_FRAM, "qbuf bad memory type"); + ret = -EINVAL; + goto out; + } + + frame = &gspca_dev->frame[index]; + if (frame->v4l2_buf.flags & BUF_ALL_FLAGS) { + PDEBUG(D_FRAM, "qbuf bad state"); + ret = -EINVAL; + goto out; + } + + frame->v4l2_buf.flags |= V4L2_BUF_FLAG_QUEUED; +/* frame->v4l2_buf.flags &= ~V4L2_BUF_FLAG_DONE; */ + + if (frame->v4l2_buf.memory == V4L2_MEMORY_USERPTR) { + frame->v4l2_buf.m.userptr = v4l2_buf->m.userptr; + frame->v4l2_buf.length = v4l2_buf->length; + } + + /* put the buffer in the 'queued' queue */ + i = gspca_dev->fr_q; + gspca_dev->fr_queue[i] = index; + gspca_dev->fr_q = (i + 1) % gspca_dev->nframes; + PDEBUG(D_FRAM, "qbuf q:%d i:%d o:%d", + gspca_dev->fr_q, + gspca_dev->fr_i, + gspca_dev->fr_o); + + v4l2_buf->flags |= V4L2_BUF_FLAG_QUEUED; + v4l2_buf->flags &= ~V4L2_BUF_FLAG_DONE; + ret = 0; +out: + mutex_unlock(&gspca_dev->queue_lock); + return ret; +} + +/* + * allocate the resources for read() + */ +static int read_alloc(struct gspca_dev *gspca_dev, + struct file *file) +{ + struct v4l2_buffer v4l2_buf; + int i, ret; + + PDEBUG(D_STREAM, "read alloc"); + if (gspca_dev->nframes == 0) { + struct v4l2_requestbuffers rb; + + memset(&rb, 0, sizeof rb); + rb.count = gspca_dev->nbufread; + rb.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + rb.memory = GSPCA_MEMORY_READ; + ret = vidioc_reqbufs(file, gspca_dev, &rb); + if (ret != 0) { + PDEBUG(D_STREAM, "read reqbuf err %d", ret); + return ret; + } + memset(&v4l2_buf, 0, sizeof v4l2_buf); + v4l2_buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + v4l2_buf.memory = GSPCA_MEMORY_READ; + for (i = 0; i < gspca_dev->nbufread; i++) { + v4l2_buf.index = i; + ret = vidioc_qbuf(file, gspca_dev, &v4l2_buf); + if (ret != 0) { + PDEBUG(D_STREAM, "read qbuf err: %d", ret); + return ret; + } + } + gspca_dev->memory = GSPCA_MEMORY_READ; + } + + /* start streaming */ + ret = vidioc_streamon(file, gspca_dev, V4L2_BUF_TYPE_VIDEO_CAPTURE); + if (ret != 0) + PDEBUG(D_STREAM, "read streamon err %d", ret); + return ret; +} + +static unsigned int dev_poll(struct file *file, poll_table *wait) +{ + struct gspca_dev *gspca_dev = file->private_data; + int i, ret; + + PDEBUG(D_FRAM, "poll"); + + poll_wait(file, &gspca_dev->wq, wait); + if (!gspca_dev->present) + return POLLERR; + + /* if reqbufs is not done, the user would use read() */ + if (gspca_dev->nframes == 0) { + if (gspca_dev->memory != GSPCA_MEMORY_NO) + return POLLERR; /* not the 1st time */ + ret = read_alloc(gspca_dev, file); + if (ret != 0) + return POLLERR; + } + + if (mutex_lock_interruptible(&gspca_dev->queue_lock) != 0) + return POLLERR; + if (!gspca_dev->present) { + ret = POLLERR; + goto out; + } + + /* check the next incoming buffer */ + i = gspca_dev->fr_o; + i = gspca_dev->fr_queue[i]; + if (gspca_dev->frame[i].v4l2_buf.flags & V4L2_BUF_FLAG_DONE) + ret = POLLIN | POLLRDNORM; /* something to read */ + else + ret = 0; +out: + mutex_unlock(&gspca_dev->queue_lock); + return ret; +} + +static ssize_t dev_read(struct file *file, char __user *data, + size_t count, loff_t *ppos) +{ + struct gspca_dev *gspca_dev = file->private_data; + struct gspca_frame *frame; + struct v4l2_buffer v4l2_buf; + struct timeval timestamp; + int n, ret, ret2; + + PDEBUG(D_FRAM, "read (%zd)", count); + if (!gspca_dev->present) + return -ENODEV; + switch (gspca_dev->memory) { + case GSPCA_MEMORY_NO: /* first time */ + ret = read_alloc(gspca_dev, file); + if (ret != 0) + return ret; + break; + case GSPCA_MEMORY_READ: + if (gspca_dev->capt_file == file) + break; + /* fall thru */ + default: + return -EINVAL; + } + + /* get a frame */ + jiffies_to_timeval(get_jiffies_64(), ×tamp); + timestamp.tv_sec--; + n = 2; + for (;;) { + memset(&v4l2_buf, 0, sizeof v4l2_buf); + v4l2_buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + v4l2_buf.memory = GSPCA_MEMORY_READ; + ret = vidioc_dqbuf(file, gspca_dev, &v4l2_buf); + if (ret != 0) { + PDEBUG(D_STREAM, "read dqbuf err %d", ret); + return ret; + } + + /* if the process slept for more than 1 second, + * get anewer frame */ + frame = &gspca_dev->frame[v4l2_buf.index]; + if (--n < 0) + break; /* avoid infinite loop */ + if (frame->v4l2_buf.timestamp.tv_sec >= timestamp.tv_sec) + break; + ret = vidioc_qbuf(file, gspca_dev, &v4l2_buf); + if (ret != 0) { + PDEBUG(D_STREAM, "read qbuf err %d", ret); + return ret; + } + } + + /* copy the frame */ + if (count > frame->v4l2_buf.bytesused) + count = frame->v4l2_buf.bytesused; + ret = copy_to_user(data, frame->data, count); + if (ret != 0) { + PDEBUG(D_ERR|D_STREAM, + "read cp to user lack %d / %zd", ret, count); + ret = -EFAULT; + goto out; + } + ret = count; +out: + /* in each case, requeue the buffer */ + ret2 = vidioc_qbuf(file, gspca_dev, &v4l2_buf); + if (ret2 != 0) + return ret2; + return ret; +} + +static void dev_release(struct video_device *vfd) +{ + /* nothing */ +} + +static struct file_operations dev_fops = { + .owner = THIS_MODULE, + .open = dev_open, + .release = dev_close, + .read = dev_read, + .mmap = dev_mmap, + .ioctl = video_ioctl2, +#ifdef CONFIG_COMPAT + .compat_ioctl = v4l_compat_ioctl32, +#endif + .llseek = no_llseek, + .poll = dev_poll, +}; + +static struct video_device gspca_template = { + .name = "gspca main driver", + .type = VID_TYPE_CAPTURE, + .fops = &dev_fops, + .release = dev_release, /* mandatory */ + .minor = -1, + .vidioc_querycap = vidioc_querycap, + .vidioc_dqbuf = vidioc_dqbuf, + .vidioc_qbuf = vidioc_qbuf, + .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap, + .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap, + .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap, + .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap, + .vidioc_streamon = vidioc_streamon, + .vidioc_queryctrl = vidioc_queryctrl, + .vidioc_g_ctrl = vidioc_g_ctrl, + .vidioc_s_ctrl = vidioc_s_ctrl, + .vidioc_querymenu = vidioc_querymenu, + .vidioc_enum_input = vidioc_enum_input, + .vidioc_g_input = vidioc_g_input, + .vidioc_s_input = vidioc_s_input, + .vidioc_reqbufs = vidioc_reqbufs, + .vidioc_querybuf = vidioc_querybuf, + .vidioc_streamoff = vidioc_streamoff, + .vidioc_g_jpegcomp = vidioc_g_jpegcomp, + .vidioc_s_jpegcomp = vidioc_s_jpegcomp, + .vidioc_g_parm = vidioc_g_parm, + .vidioc_s_parm = vidioc_s_parm, + .vidioc_s_std = vidioc_s_std, +#ifdef CONFIG_VIDEO_V4L1_COMPAT + .vidiocgmbuf = vidiocgmbuf, +#endif +}; + +/* + * probe and create a new gspca device + * + * This function must be called by the sub-driver when it is + * called for probing a new device. + */ +int gspca_dev_probe(struct usb_interface *intf, + const struct usb_device_id *id, + const struct sd_desc *sd_desc, + int dev_size, + struct module *module) +{ + struct usb_interface_descriptor *interface; + struct gspca_dev *gspca_dev; + struct usb_device *dev = interface_to_usbdev(intf); + int ret; + + PDEBUG(D_PROBE, "probing %04x:%04x", id->idVendor, id->idProduct); + + /* we don't handle multi-config cameras */ + if (dev->descriptor.bNumConfigurations != 1) + return -ENODEV; + interface = &intf->cur_altsetting->desc; + if (interface->bInterfaceNumber > 0) + return -ENODEV; + + /* create the device */ + if (dev_size < sizeof *gspca_dev) + dev_size = sizeof *gspca_dev; + gspca_dev = kzalloc(dev_size, GFP_KERNEL); + if (gspca_dev == NULL) { + err("couldn't kzalloc gspca struct"); + return -EIO; + } + gspca_dev->dev = dev; + gspca_dev->iface = interface->bInterfaceNumber; + gspca_dev->nbalt = intf->num_altsetting; + gspca_dev->sd_desc = sd_desc; +/* gspca_dev->users = 0; (done by kzalloc) */ + gspca_dev->nbufread = 2; + + /* configure the subdriver */ + ret = gspca_dev->sd_desc->config(gspca_dev, id); + if (ret < 0) + goto out; + ret = gspca_set_alt0(gspca_dev); + if (ret < 0) + goto out; + gspca_set_default_mode(gspca_dev); + + mutex_init(&gspca_dev->usb_lock); + mutex_init(&gspca_dev->read_lock); + mutex_init(&gspca_dev->queue_lock); + init_waitqueue_head(&gspca_dev->wq); + + /* init video stuff */ + memcpy(&gspca_dev->vdev, &gspca_template, sizeof gspca_template); + gspca_dev->vdev.dev = &dev->dev; + memcpy(&gspca_dev->fops, &dev_fops, sizeof gspca_dev->fops); + gspca_dev->vdev.fops = &gspca_dev->fops; + gspca_dev->fops.owner = module; /* module protection */ + ret = video_register_device(&gspca_dev->vdev, + VFL_TYPE_GRABBER, + video_nr); + if (ret < 0) { + err("video_register_device err %d", ret); + goto out; + } + + gspca_dev->present = 1; + usb_set_intfdata(intf, gspca_dev); + PDEBUG(D_PROBE, "probe ok"); + return 0; +out: + kfree(gspca_dev); + return ret; +} +EXPORT_SYMBOL(gspca_dev_probe); + +/* + * USB disconnection + * + * This function must be called by the sub-driver + * when the device disconnects, after the specific resources are freed. + */ +void gspca_disconnect(struct usb_interface *intf) +{ + struct gspca_dev *gspca_dev = usb_get_intfdata(intf); + + if (!gspca_dev) + return; + gspca_dev->present = 0; + mutex_lock(&gspca_dev->queue_lock); + mutex_lock(&gspca_dev->usb_lock); + gspca_dev->streaming = 0; + destroy_urbs(gspca_dev); + mutex_unlock(&gspca_dev->usb_lock); + mutex_unlock(&gspca_dev->queue_lock); + while (gspca_dev->users != 0) { /* wait until fully closed */ + atomic_inc(&gspca_dev->nevent); + wake_up_interruptible(&gspca_dev->wq); /* wake processes */ + schedule(); + } +/* We don't want people trying to open up the device */ + video_unregister_device(&gspca_dev->vdev); +/* Free the memory */ + kfree(gspca_dev); + PDEBUG(D_PROBE, "disconnect complete"); +} +EXPORT_SYMBOL(gspca_disconnect); + +/* -- cam driver utility functions -- */ + +/* auto gain and exposure algorithm based on the knee algorithm described here: + http://ytse.tricolour.net/docs/LowLightOptimization.html + + Returns 0 if no changes were made, 1 if the gain and or exposure settings + where changed. */ +int gspca_auto_gain_n_exposure(struct gspca_dev *gspca_dev, int avg_lum, + int desired_avg_lum, int deadzone, int gain_knee, int exposure_knee) +{ + int i, steps, gain, orig_gain, exposure, orig_exposure, autogain; + const struct ctrl *gain_ctrl = NULL; + const struct ctrl *exposure_ctrl = NULL; + const struct ctrl *autogain_ctrl = NULL; + int retval = 0; + + for (i = 0; i < gspca_dev->sd_desc->nctrls; i++) { + if (gspca_dev->sd_desc->ctrls[i].qctrl.id == V4L2_CID_GAIN) + gain_ctrl = &gspca_dev->sd_desc->ctrls[i]; + if (gspca_dev->sd_desc->ctrls[i].qctrl.id == V4L2_CID_EXPOSURE) + exposure_ctrl = &gspca_dev->sd_desc->ctrls[i]; + if (gspca_dev->sd_desc->ctrls[i].qctrl.id == V4L2_CID_AUTOGAIN) + autogain_ctrl = &gspca_dev->sd_desc->ctrls[i]; + } + if (!gain_ctrl || !exposure_ctrl || !autogain_ctrl) { + PDEBUG(D_ERR, "Error: gspca_auto_gain_n_exposure called " + "on cam without (auto)gain/exposure"); + return 0; + } + + if (gain_ctrl->get(gspca_dev, &gain) || + exposure_ctrl->get(gspca_dev, &exposure) || + autogain_ctrl->get(gspca_dev, &autogain) || !autogain) + return 0; + + orig_gain = gain; + orig_exposure = exposure; + + /* If we are of a multiple of deadzone, do multiple steps to reach the + desired lumination fast (with the risc of a slight overshoot) */ + steps = abs(desired_avg_lum - avg_lum) / deadzone; + + PDEBUG(D_FRAM, "autogain: lum: %d, desired: %d, steps: %d\n", + avg_lum, desired_avg_lum, steps); + + for (i = 0; i < steps; i++) { + if (avg_lum > desired_avg_lum) { + if (gain > gain_knee) + gain--; + else if (exposure > exposure_knee) + exposure--; + else if (gain > gain_ctrl->qctrl.default_value) + gain--; + else if (exposure > exposure_ctrl->qctrl.minimum) + exposure--; + else if (gain > gain_ctrl->qctrl.minimum) + gain--; + else + break; + } else { + if (gain < gain_ctrl->qctrl.default_value) + gain++; + else if (exposure < exposure_knee) + exposure++; + else if (gain < gain_knee) + gain++; + else if (exposure < exposure_ctrl->qctrl.maximum) + exposure++; + else if (gain < gain_ctrl->qctrl.maximum) + gain++; + else + break; + } + } + + if (gain != orig_gain) { + gain_ctrl->set(gspca_dev, gain); + retval = 1; + } + if (exposure != orig_exposure) { + exposure_ctrl->set(gspca_dev, exposure); + retval = 1; + } + + return retval; +} +EXPORT_SYMBOL(gspca_auto_gain_n_exposure); + +/* -- module insert / remove -- */ +static int __init gspca_init(void) +{ + info("main v%s registered", version); + return 0; +} +static void __exit gspca_exit(void) +{ + info("main deregistered"); +} + +module_init(gspca_init); +module_exit(gspca_exit); + +#ifdef CONFIG_VIDEO_ADV_DEBUG +module_param_named(debug, gspca_debug, int, 0644); +MODULE_PARM_DESC(debug, + "Debug (bit) 0x01:error 0x02:probe 0x04:config" + " 0x08:stream 0x10:frame 0x20:packet 0x40:USBin 0x80:USBout" + " 0x0100: v4l2"); +#endif diff --git a/drivers/media/video/gspca/gspca.h b/drivers/media/video/gspca/gspca.h new file mode 100644 index 000000000000..3fd2c4eee204 --- /dev/null +++ b/drivers/media/video/gspca/gspca.h @@ -0,0 +1,176 @@ +#ifndef GSPCAV2_H +#define GSPCAV2_H + +#include <linux/module.h> +#include <linux/version.h> +#include <linux/kernel.h> +#include <linux/usb.h> +#include <linux/videodev2.h> +#include <media/v4l2-common.h> +#include <linux/mutex.h> + +#ifdef CONFIG_VIDEO_ADV_DEBUG +/* GSPCA our debug messages */ +extern int gspca_debug; +#define PDEBUG(level, fmt, args...) \ + do {\ + if (gspca_debug & (level)) \ + printk(KERN_INFO MODULE_NAME ": " fmt "\n", ## args); \ + } while (0) +#define D_ERR 0x01 +#define D_PROBE 0x02 +#define D_CONF 0x04 +#define D_STREAM 0x08 +#define D_FRAM 0x10 +#define D_PACK 0x20 +#define D_USBI 0x40 +#define D_USBO 0x80 +#define D_V4L2 0x0100 +#else +#define PDEBUG(level, fmt, args...) +#endif +#undef err +#define err(fmt, args...) \ + do {\ + printk(KERN_ERR MODULE_NAME ": " fmt "\n", ## args); \ + } while (0) +#undef info +#define info(fmt, args...) \ + do {\ + printk(KERN_INFO MODULE_NAME ": " fmt "\n", ## args); \ + } while (0) +#undef warn +#define warn(fmt, args...) \ + do {\ + printk(KERN_WARNING MODULE_NAME ": " fmt "\n", ## args); \ + } while (0) + +#define GSPCA_MAX_FRAMES 16 /* maximum number of video frame buffers */ +/* ISOC transfers */ +#define MAX_NURBS 16 /* max number of URBs */ +#define ISO_MAX_PKT 32 /* max number of packets in an ISOC transfer */ +#define ISO_MAX_SIZE 0x8000 /* max size of one URB buffer (32 Kb) */ + +/* device information - set at probe time */ +struct cam { + char *dev_name; + struct v4l2_pix_format *cam_mode; /* size nmodes */ + char nmodes; + __u8 epaddr; +}; + +struct gspca_dev; +struct gspca_frame; + +/* subdriver operations */ +typedef int (*cam_op) (struct gspca_dev *); +typedef void (*cam_v_op) (struct gspca_dev *); +typedef int (*cam_cf_op) (struct gspca_dev *, const struct usb_device_id *); +typedef int (*cam_jpg_op) (struct gspca_dev *, + struct v4l2_jpegcompression *); +typedef int (*cam_qmnu_op) (struct gspca_dev *, + struct v4l2_querymenu *); +typedef void (*cam_pkt_op) (struct gspca_dev *gspca_dev, + struct gspca_frame *frame, + __u8 *data, + int len); + +struct ctrl { + struct v4l2_queryctrl qctrl; + int (*set)(struct gspca_dev *, __s32); + int (*get)(struct gspca_dev *, __s32 *); +}; + +/* subdriver description */ +struct sd_desc { +/* information */ + const char *name; /* sub-driver name */ +/* controls */ + const struct ctrl *ctrls; + int nctrls; +/* operations */ + cam_cf_op config; /* called on probe */ + cam_op open; /* called on open */ + cam_v_op start; /* called on stream on */ + cam_v_op stopN; /* called on stream off - main alt */ + cam_v_op stop0; /* called on stream off - alt 0 */ + cam_v_op close; /* called on close */ + cam_pkt_op pkt_scan; +/* optional operations */ + cam_v_op dq_callback; /* called when a frame has been dequeued */ + cam_jpg_op get_jcomp; + cam_jpg_op set_jcomp; + cam_qmnu_op querymenu; +}; + +/* packet types when moving from iso buf to frame buf */ +#define DISCARD_PACKET 0 +#define FIRST_PACKET 1 +#define INTER_PACKET 2 +#define LAST_PACKET 3 + +struct gspca_frame { + __u8 *data; /* frame buffer */ + __u8 *data_end; /* end of frame while filling */ + int vma_use_count; + struct v4l2_buffer v4l2_buf; +}; + +struct gspca_dev { + struct video_device vdev; /* !! must be the first item */ + struct file_operations fops; + struct usb_device *dev; + struct file *capt_file; /* file doing video capture */ + + struct cam cam; /* device information */ + const struct sd_desc *sd_desc; /* subdriver description */ + + __u8 usb_buf[8]; /* buffer for USB exchanges */ + struct urb *urb[MAX_NURBS]; + + __u8 *frbuf; /* buffer for nframes */ + struct gspca_frame frame[GSPCA_MAX_FRAMES]; + __u32 frsz; /* frame size */ + char nframes; /* number of frames */ + char fr_i; /* frame being filled */ + char fr_q; /* next frame to queue */ + char fr_o; /* next frame to dequeue */ + signed char fr_queue[GSPCA_MAX_FRAMES]; /* frame queue */ + char last_packet_type; + + __u8 iface; /* USB interface number */ + __u8 alt; /* USB alternate setting */ + __u8 curr_mode; /* current camera mode */ + __u32 pixfmt; /* current mode parameters */ + __u16 width; + __u16 height; + + atomic_t nevent; /* number of frames done */ + wait_queue_head_t wq; /* wait queue */ + struct mutex usb_lock; /* usb exchange protection */ + struct mutex read_lock; /* read protection */ + struct mutex queue_lock; /* ISOC queue protection */ + __u32 sequence; /* frame sequence number */ + char streaming; + char users; /* number of opens */ + char present; /* device connected */ + char nbufread; /* number of buffers for read() */ + char nurbs; /* number of allocated URBs */ + char memory; /* memory type (V4L2_MEMORY_xxx) */ + __u8 nbalt; /* number of USB alternate settings */ +}; + +int gspca_dev_probe(struct usb_interface *intf, + const struct usb_device_id *id, + const struct sd_desc *sd_desc, + int dev_size, + struct module *module); +void gspca_disconnect(struct usb_interface *intf); +struct gspca_frame *gspca_frame_add(struct gspca_dev *gspca_dev, + int packet_type, + struct gspca_frame *frame, + const __u8 *data, + int len); +int gspca_auto_gain_n_exposure(struct gspca_dev *gspca_dev, int avg_lum, + int desired_avg_lum, int deadzone, int gain_knee, int exposure_knee); +#endif /* GSPCAV2_H */ diff --git a/drivers/media/video/gspca/jpeg.h b/drivers/media/video/gspca/jpeg.h new file mode 100644 index 000000000000..d823b47bd4e6 --- /dev/null +++ b/drivers/media/video/gspca/jpeg.h @@ -0,0 +1,301 @@ +#ifndef JPEG_H +#define JPEG_H 1 +/* + * Insert a JPEG header at start of frame + * + * This module is used by the gspca subdrivers. + * A special case is done for Conexant webcams. + * + * Copyright (C) Jean-Francois Moine (http://moinejf.free.fr) + * + * 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 + * 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 + * + */ + +/* start of jpeg frame + quantization table */ +static const unsigned char quant[][0x88] = { +/* index 0 - Q40*/ + { + 0xff, 0xd8, /* jpeg */ + 0xff, 0xdb, 0x00, 0x84, /* DQT */ +0, /* quantization table part 1 */ + 20, 14, 15, 18, 15, 13, 20, 18, 16, 18, 23, 21, 20, 24, 30, 50, + 33, 30, 28, 28, 30, 61, 44, 46, 36, 50, 73, 64, 76, 75, 71, 64, + 70, 69, 80, 90, 115, 98, 80, 85, 109, 86, 69, 70, 100, 136, 101, + 109, + 119, 123, 129, 130, 129, 78, 96, 141, 151, 140, 125, 150, 115, + 126, 129, 124, +1, /* quantization table part 2 */ + 21, 23, 23, 30, 26, 30, 59, 33, 33, 59, 124, 83, 70, 83, 124, 124, + 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, + 124, 124, 124, + 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, + 124, 124, 124, + 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, + 124, 124, 124}, +/* index 1 - Q50 */ + { + 0xff, 0xd8, + 0xff, 0xdb, 0x00, 0x84, /* DQT */ +0, + 16, 11, 12, 14, 12, 10, 16, 14, 13, 14, 18, 17, 16, 19, 24, 40, + 26, 24, 22, 22, 24, 49, 35, 37, 29, 40, 58, 51, 61, 60, 57, 51, + 56, 55, 64, 72, 92, 78, 64, 68, 87, 69, 55, 56, 80, 109, 81, 87, + 95, 98, 103, 104, 103, 62, 77, 113, 121, 112, 100, 120, 92, 101, + 103, 99, +1, + 17, 18, 18, 24, 21, 24, 47, 26, 26, 47, 99, 66, 56, 66, 99, 99, + 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, + 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, + 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99}, +/* index 2 Q60 */ + { + 0xff, 0xd8, + 0xff, 0xdb, 0x00, 0x84, /* DQT */ +0, + 13, 9, 10, 11, 10, 8, 13, 11, 10, 11, 14, 14, 13, 15, 19, 32, + 21, 19, 18, 18, 19, 39, 28, 30, 23, 32, 46, 41, 49, 48, 46, 41, + 45, 44, 51, 58, 74, 62, 51, 54, 70, 55, 44, 45, 64, 87, 65, 70, + 76, 78, 82, 83, 82, 50, 62, 90, 97, 90, 80, 96, 74, 81, 82, 79, +1, + 14, 14, 14, 19, 17, 19, 38, 21, 21, 38, 79, 53, 45, 53, 79, 79, + 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, + 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, + 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79}, +/* index 3 - Q70 */ + { + 0xff, 0xd8, + 0xff, 0xdb, 0x00, 0x84, /* DQT */ +0, + 10, 7, 7, 8, 7, 6, 10, 8, 8, 8, 11, 10, 10, 11, 14, 24, + 16, 14, 13, 13, 14, 29, 21, 22, 17, 24, 35, 31, 37, 36, 34, 31, + 34, 33, 38, 43, 55, 47, 38, 41, 52, 41, 33, 34, 48, 65, 49, 52, + 57, 59, 62, 62, 62, 37, 46, 68, 73, 67, 60, 72, 55, 61, 62, 59, +1, + 10, 11, 11, 14, 13, 14, 28, 16, 16, 28, 59, 40, 34, 40, 59, 59, + 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, + 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, + 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59}, +/* index 4 - Q80 */ + { + 0xff, 0xd8, + 0xff, 0xdb, 0x00, 0x84, /* DQT */ +0, + 6, 4, 5, 6, 5, 4, 6, 6, 5, 6, 7, 7, 6, 8, 10, 16, + 10, 10, 9, 9, 10, 20, 14, 15, 12, 16, 23, 20, 24, 24, 23, 20, + 22, 22, 26, 29, 37, 31, 26, 27, 35, 28, 22, 22, 32, 44, 32, 35, + 38, 39, 41, 42, 41, 25, 31, 45, 48, 45, 40, 48, 37, 40, 41, 40, +1, + 7, 7, 7, 10, 8, 10, 19, 10, 10, 19, 40, 26, 22, 26, 40, 40, + 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, + 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, + 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40}, +/* index 5 - Q85 */ + { + 0xff, 0xd8, + 0xff, 0xdb, 0x00, 0x84, /* DQT */ +0, + 5, 3, 4, 4, 4, 3, 5, 4, 4, 4, 5, 5, 5, 6, 7, 12, + 8, 7, 7, 7, 7, 15, 11, 11, 9, 12, 17, 15, 18, 18, 17, 15, + 17, 17, 19, 22, 28, 23, 19, 20, 26, 21, 17, 17, 24, 33, 24, 26, + 29, 29, 31, 31, 31, 19, 23, 34, 36, 34, 30, 36, 28, 30, 31, 30, +1, + 5, 5, 5, 7, 6, 7, 14, 8, 8, 14, 30, 20, 17, 20, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30}, +/* index 6 - 86 */ +{ + 0xff, 0xd8, + 0xff, 0xdb, 0x00, 0x84, /* DQT */ +0, + 0x04, 0x03, 0x03, 0x04, 0x03, 0x03, 0x04, 0x04, + 0x04, 0x04, 0x05, 0x05, 0x04, 0x05, 0x07, 0x0B, + 0x07, 0x07, 0x06, 0x06, 0x07, 0x0E, 0x0A, 0x0A, + 0x08, 0x0B, 0x10, 0x0E, 0x11, 0x11, 0x10, 0x0E, + 0x10, 0x0F, 0x12, 0x14, 0x1A, 0x16, 0x12, 0x13, + 0x18, 0x13, 0x0F, 0x10, 0x16, 0x1F, 0x17, 0x18, + 0x1B, 0x1B, 0x1D, 0x1D, 0x1D, 0x11, 0x16, 0x20, + 0x22, 0x1F, 0x1C, 0x22, 0x1A, 0x1C, 0x1D, 0x1C, +1, + 0x05, 0x05, 0x05, 0x07, 0x06, 0x07, 0x0D, 0x07, + 0x07, 0x0D, 0x1C, 0x12, 0x10, 0x12, 0x1C, 0x1C, + 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, + 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, + 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, + 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, + 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, + 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, + }, +/* index 7 - 88 */ +{ + 0xff, 0xd8, + 0xff, 0xdb, 0x00, 0x84, /* DQT */ +0, + 0x04, 0x03, 0x03, 0x03, 0x03, 0x02, 0x04, 0x03, + 0x03, 0x03, 0x04, 0x04, 0x04, 0x05, 0x06, 0x0A, + 0x06, 0x06, 0x05, 0x05, 0x06, 0x0C, 0x08, 0x09, + 0x07, 0x0A, 0x0E, 0x0C, 0x0F, 0x0E, 0x0E, 0x0C, + 0x0D, 0x0D, 0x0F, 0x11, 0x16, 0x13, 0x0F, 0x10, + 0x15, 0x11, 0x0D, 0x0D, 0x13, 0x1A, 0x13, 0x15, + 0x17, 0x18, 0x19, 0x19, 0x19, 0x0F, 0x12, 0x1B, + 0x1D, 0x1B, 0x18, 0x1D, 0x16, 0x18, 0x19, 0x18, +1, + 0x04, 0x04, 0x04, 0x06, 0x05, 0x06, 0x0B, 0x06, + 0x06, 0x0B, 0x18, 0x10, 0x0D, 0x10, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, +}, +/* index 8 - ?? */ +{ + 0xff, 0xd8, + 0xff, 0xdb, 0x00, 0x84, /* DQT */ +0, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x03, 0x05, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x06, 0x04, 0x05, + 0x04, 0x05, 0x07, 0x06, 0x08, 0x08, 0x07, 0x06, + 0x07, 0x07, 0x08, 0x09, 0x0C, 0x0A, 0x08, 0x09, + 0x0B, 0x09, 0x07, 0x07, 0x0A, 0x0E, 0x0A, 0x0B, + 0x0C, 0x0C, 0x0D, 0x0D, 0x0D, 0x08, 0x0A, 0x0E, + 0x0F, 0x0E, 0x0D, 0x0F, 0x0C, 0x0D, 0x0D, 0x0C, +1, + 0x02, 0x02, 0x02, 0x03, 0x03, 0x03, 0x06, 0x03, + 0x03, 0x06, 0x0C, 0x08, 0x07, 0x08, 0x0C, 0x0C, + 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, + 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, + 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, + 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, + 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, + 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C +} +}; + +/* huffman table + start of SOF0 */ +static unsigned char huffman[] = { + 0xff, 0xc4, 0x01, 0xa2, + 0x00, 0x00, 0x01, 0x05, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, + 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x01, 0x00, 0x03, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x10, 0x00, 0x02, 0x01, 0x03, 0x03, + 0x02, 0x04, 0x03, 0x05, 0x05, 0x04, 0x04, 0x00, + 0x00, 0x01, 0x7d, 0x01, 0x02, 0x03, 0x00, 0x04, + 0x11, 0x05, 0x12, 0x21, 0x31, 0x41, 0x06, 0x13, + 0x51, 0x61, 0x07, 0x22, 0x71, 0x14, 0x32, 0x81, + 0x91, 0xa1, 0x08, 0x23, 0x42, 0xb1, 0xc1, 0x15, + 0x52, 0xd1, 0xf0, 0x24, 0x33, 0x62, 0x72, 0x82, + 0x09, 0x0a, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x25, + 0x26, 0x27, 0x28, 0x29, 0x2a, 0x34, 0x35, 0x36, + 0x37, 0x38, 0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, + 0x47, 0x48, 0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, + 0x57, 0x58, 0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, + 0x67, 0x68, 0x69, 0x6a, 0x73, 0x74, 0x75, 0x76, + 0x77, 0x78, 0x79, 0x7a, 0x83, 0x84, 0x85, 0x86, + 0x87, 0x88, 0x89, 0x8a, 0x92, 0x93, 0x94, 0x95, + 0x96, 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, + 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, + 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xc2, + 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, + 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, + 0xda, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, + 0xe8, 0xe9, 0xea, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, + 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0x11, 0x00, 0x02, + 0x01, 0x02, 0x04, 0x04, 0x03, 0x04, 0x07, 0x05, + 0x04, 0x04, 0x00, 0x01, 0x02, 0x77, 0x00, 0x01, + 0x02, 0x03, 0x11, 0x04, 0x05, 0x21, 0x31, 0x06, + 0x12, 0x41, 0x51, 0x07, 0x61, 0x71, 0x13, 0x22, + 0x32, 0x81, 0x08, 0x14, 0x42, 0x91, 0xa1, 0xb1, + 0xc1, 0x09, 0x23, 0x33, 0x52, 0xf0, 0x15, 0x62, + 0x72, 0xd1, 0x0a, 0x16, 0x24, 0x34, 0xe1, 0x25, + 0xf1, 0x17, 0x18, 0x19, 0x1a, 0x26, 0x27, 0x28, + 0x29, 0x2a, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, + 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, + 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, + 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, + 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, + 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, + 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, + 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, + 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, + 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5, + 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4, + 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe2, 0xe3, + 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xf2, + 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, +#ifdef CONEX_CAM +/* the Conexant frames start with SOF0 */ +#else + 0xff, 0xc0, 0x00, 0x11, /* SOF0 (start of frame 0 */ + 0x08, /* data precision */ +#endif +}; + +#ifndef CONEX_CAM +/* variable part: + * 0x01, 0xe0, height + * 0x02, 0x80, width + * 0x03, component number + * 0x01, + * 0x21, samples Y + */ + +/* end of header */ +static unsigned char eoh[] = { + 0x00, /* quant Y */ + 0x02, 0x11, 0x01, /* samples CbCr - quant CbCr */ + 0x03, 0x11, 0x01, + + 0xff, 0xda, 0x00, 0x0c, /* SOS (start of scan) */ + 0x03, 0x01, 0x00, 0x02, 0x11, 0x03, 0x11, 0x00, 0x3f, 0x00 +}; +#endif + +/* -- output the JPEG header -- */ +static void jpeg_put_header(struct gspca_dev *gspca_dev, + struct gspca_frame *frame, + int qindex, + int samplesY) +{ +#ifndef CONEX_CAM + unsigned char tmpbuf[8]; +#endif + + gspca_frame_add(gspca_dev, FIRST_PACKET, frame, + (unsigned char *) quant[qindex], sizeof quant[0]); + gspca_frame_add(gspca_dev, INTER_PACKET, frame, + (unsigned char *) huffman, sizeof huffman); +#ifndef CONEX_CAM + tmpbuf[0] = gspca_dev->height >> 8; + tmpbuf[1] = gspca_dev->height & 0xff; + tmpbuf[2] = gspca_dev->width >> 8; + tmpbuf[3] = gspca_dev->width & 0xff; + tmpbuf[4] = 0x03; /* component number */ + tmpbuf[5] = 0x01; /* first component */ + tmpbuf[6] = samplesY; + gspca_frame_add(gspca_dev, INTER_PACKET, frame, + tmpbuf, 7); + gspca_frame_add(gspca_dev, INTER_PACKET, frame, + eoh, sizeof eoh); +#endif +} +#endif diff --git a/drivers/media/video/gspca/mars.c b/drivers/media/video/gspca/mars.c new file mode 100644 index 000000000000..88c2b02f380a --- /dev/null +++ b/drivers/media/video/gspca/mars.c @@ -0,0 +1,464 @@ +/* + * Mars-Semi MR97311A library + * Copyright (C) 2005 <bradlch@hotmail.com> + * + * V4L2 by Jean-Francois Moine <http://moinejf.free.fr> + * + * 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 + * 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 + */ + +#define MODULE_NAME "mars" + +#include "gspca.h" +#include "jpeg.h" + +#define DRIVER_VERSION_NUMBER KERNEL_VERSION(2, 1, 7) +static const char version[] = "2.1.7"; + +MODULE_AUTHOR("Michel Xhaard <mxhaard@users.sourceforge.net>"); +MODULE_DESCRIPTION("GSPCA/Mars USB Camera Driver"); +MODULE_LICENSE("GPL"); + +/* specific webcam descriptor */ +struct sd { + struct gspca_dev gspca_dev; /* !! must be the first item */ + + char qindex; +}; + +/* V4L2 controls supported by the driver */ +static struct ctrl sd_ctrls[] = { +}; + +static struct v4l2_pix_format vga_mode[] = { + {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, + .bytesperline = 320, + .sizeimage = 320 * 240 * 3 / 8 + 589, + .colorspace = V4L2_COLORSPACE_JPEG, + .priv = 2}, + {640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, + .bytesperline = 640, + .sizeimage = 640 * 480 * 3 / 8 + 590, + .colorspace = V4L2_COLORSPACE_JPEG, + .priv = 1}, +}; + +/* MI Register table //elvis */ +enum { + REG_HW_MI_0, + REG_HW_MI_1, + REG_HW_MI_2, + REG_HW_MI_3, + REG_HW_MI_4, + REG_HW_MI_5, + REG_HW_MI_6, + REG_HW_MI_7, + REG_HW_MI_9 = 0x09, + REG_HW_MI_B = 0x0B, + REG_HW_MI_C, + REG_HW_MI_D, + REG_HW_MI_1E = 0x1E, + REG_HW_MI_20 = 0x20, + REG_HW_MI_2B = 0x2B, + REG_HW_MI_2C, + REG_HW_MI_2D, + REG_HW_MI_2E, + REG_HW_MI_35 = 0x35, + REG_HW_MI_5F = 0x5f, + REG_HW_MI_60, + REG_HW_MI_61, + REG_HW_MI_62, + REG_HW_MI_63, + REG_HW_MI_64, + REG_HW_MI_F1 = 0xf1, + ATTR_TOTAL_MI_REG = 0xf2 +}; + +/* the bytes to write are in gspca_dev->usb_buf */ +static int reg_w(struct gspca_dev *gspca_dev, + __u16 index, int len) +{ + int rc; + + rc = usb_control_msg(gspca_dev->dev, + usb_sndbulkpipe(gspca_dev->dev, 4), + 0x12, + 0xc8, /* ?? */ + 0, /* value */ + index, gspca_dev->usb_buf, len, 500); + if (rc < 0) + PDEBUG(D_ERR, "reg write [%02x] error %d", index, rc); + return rc; +} + +static int reg_w_buf(struct gspca_dev *gspca_dev, + __u16 index, __u8 *buf, int len) +{ + int rc; + + rc = usb_control_msg(gspca_dev->dev, + usb_sndbulkpipe(gspca_dev->dev, 4), + 0x12, + 0xc8, /* ?? */ + 0, /* value */ + index, buf, len, 500); + if (rc < 0) + PDEBUG(D_ERR, "reg write [%02x] error %d", index, rc); + return rc; +} + +static void bulk_w(struct gspca_dev *gspca_dev, + __u16 *pch, + __u16 Address) +{ + gspca_dev->usb_buf[0] = 0x1f; + gspca_dev->usb_buf[1] = 0; /* control byte */ + gspca_dev->usb_buf[2] = Address; + gspca_dev->usb_buf[3] = *pch >> 8; /* high byte */ + gspca_dev->usb_buf[4] = *pch; /* low byte */ + + reg_w(gspca_dev, Address, 5); +} + +/* this function is called at probe time */ +static int sd_config(struct gspca_dev *gspca_dev, + const struct usb_device_id *id) +{ + struct sd *sd = (struct sd *) gspca_dev; + struct cam *cam; + + cam = &gspca_dev->cam; + cam->dev_name = (char *) id->driver_info; + cam->epaddr = 0x01; + cam->cam_mode = vga_mode; + cam->nmodes = sizeof vga_mode / sizeof vga_mode[0]; + sd->qindex = 1; /* set the quantization table */ + return 0; +} + +/* this function is called at open time */ +static int sd_open(struct gspca_dev *gspca_dev) +{ + return 0; +} + +static void sd_start(struct gspca_dev *gspca_dev) +{ + int err_code; + __u8 *data; + __u16 *MI_buf; + int h_size, v_size; + int intpipe; + + PDEBUG(D_STREAM, "camera start, iface %d, alt 8", gspca_dev->iface); + if (usb_set_interface(gspca_dev->dev, gspca_dev->iface, 8) < 0) { + PDEBUG(D_ERR|D_STREAM, "Set packet size: set interface error"); + return; + } + + data = gspca_dev->usb_buf; + data[0] = 0x01; /* address */ + data[1] = 0x01; + + err_code = reg_w(gspca_dev, data[0], 2); + if (err_code < 0) + return; + + /* + Initialize the MR97113 chip register + */ + data = kmalloc(16, GFP_KERNEL); + data[0] = 0x00; /* address */ + data[1] = 0x0c | 0x01; /* reg 0 */ + data[2] = 0x01; /* reg 1 */ + h_size = gspca_dev->width; + v_size = gspca_dev->height; + data[3] = h_size / 8; /* h_size , reg 2 */ + data[4] = v_size / 8; /* v_size , reg 3 */ + data[5] = 0x30; /* reg 4, MI, PAS5101 : + * 0x30 for 24mhz , 0x28 for 12mhz */ + data[6] = 4; /* reg 5, H start */ + data[7] = 0xc0; /* reg 6, gamma 1.5 */ + data[8] = 3; /* reg 7, V start */ +/* if (h_size == 320 ) */ +/* data[9]= 0x56; * reg 8, 24MHz, 2:1 scale down */ +/* else */ + data[9] = 0x52; /* reg 8, 24MHz, no scale down */ + data[10] = 0x5d; /* reg 9, I2C device address + * [for PAS5101 (0x40)] [for MI (0x5d)] */ + + err_code = reg_w_buf(gspca_dev, data[0], data, 11); + kfree(data); + if (err_code < 0) + return; + + data = gspca_dev->usb_buf; + data[0] = 0x23; /* address */ + data[1] = 0x09; /* reg 35, append frame header */ + + err_code = reg_w(gspca_dev, data[0], 2); + if (err_code < 0) + return; + + data[0] = 0x3c; /* address */ +/* if (gspca_dev->width == 1280) */ +/* data[1] = 200; * reg 60, pc-cam frame size + * (unit: 4KB) 800KB */ +/* else */ + data[1] = 50; /* 50 reg 60, pc-cam frame size + * (unit: 4KB) 200KB */ + err_code = reg_w(gspca_dev, data[0], 2); + if (err_code < 0) + return; + + if (0) { /* fixed dark-gain */ + data[1] = 0; /* reg 94, Y Gain (1.75) */ + data[2] = 0; /* reg 95, UV Gain (1.75) */ + data[3] = 0x3f; /* reg 96, Y Gain/UV Gain/disable + * auto dark-gain */ + data[4] = 0; /* reg 97, set fixed dark level */ + data[5] = 0; /* reg 98, don't care */ + } else { /* auto dark-gain */ + data[1] = 0; /* reg 94, Y Gain (auto) */ + data[2] = 0; /* reg 95, UV Gain (1.75) */ + data[3] = 0x78; /* reg 96, Y Gain/UV Gain/disable + * auto dark-gain */ + switch (gspca_dev->width) { +/* case 1280: */ +/* data[4] = 154; + * reg 97, %3 shadow point (unit: 256 pixel) */ +/* data[5] = 51; + * reg 98, %1 highlight point + * (uint: 256 pixel) */ +/* break; */ + default: +/* case 640: */ + data[4] = 36; /* reg 97, %3 shadow point + * (unit: 256 pixel) */ + data[5] = 12; /* reg 98, %1 highlight point + * (uint: 256 pixel) */ + break; + case 320: + data[4] = 9; /* reg 97, %3 shadow point + * (unit: 256 pixel) */ + data[5] = 3; /* reg 98, %1 highlight point + * (uint: 256 pixel) */ + break; + } + } + /* auto dark-gain */ + data[0] = 0x5e; /* address */ + + err_code = reg_w(gspca_dev, data[0], 6); + if (err_code < 0) + return; + + data[0] = 0x67; + data[1] = 0x13; /* reg 103, first pixel B, disable sharpness */ + err_code = reg_w(gspca_dev, data[0], 2); + if (err_code < 0) + return; + + /* + * initialize the value of MI sensor... + */ + MI_buf = kzalloc(ATTR_TOTAL_MI_REG * sizeof *MI_buf, GFP_KERNEL); + MI_buf[REG_HW_MI_1] = 0x000a; + MI_buf[REG_HW_MI_2] = 0x000c; + MI_buf[REG_HW_MI_3] = 0x0405; + MI_buf[REG_HW_MI_4] = 0x0507; + /* mi_Attr_Reg_[REG_HW_MI_5] = 0x01ff;//13 */ + MI_buf[REG_HW_MI_5] = 0x0013; /* 13 */ + MI_buf[REG_HW_MI_6] = 0x001f; /* vertical blanking */ + /* mi_Attr_Reg_[REG_HW_MI_6] = 0x0400; // vertical blanking */ + MI_buf[REG_HW_MI_7] = 0x0002; + /* mi_Attr_Reg_[REG_HW_MI_9] = 0x015f; */ + /* mi_Attr_Reg_[REG_HW_MI_9] = 0x030f; */ + MI_buf[REG_HW_MI_9] = 0x0374; + MI_buf[REG_HW_MI_B] = 0x0000; + MI_buf[REG_HW_MI_C] = 0x0000; + MI_buf[REG_HW_MI_D] = 0x0000; + MI_buf[REG_HW_MI_1E] = 0x8000; +/* mi_Attr_Reg_[REG_HW_MI_20] = 0x1104; */ + MI_buf[REG_HW_MI_20] = 0x1104; /* 0x111c; */ + MI_buf[REG_HW_MI_2B] = 0x0008; +/* mi_Attr_Reg_[REG_HW_MI_2C] = 0x000f; */ + MI_buf[REG_HW_MI_2C] = 0x001f; /* lita suggest */ + MI_buf[REG_HW_MI_2D] = 0x0008; + MI_buf[REG_HW_MI_2E] = 0x0008; + MI_buf[REG_HW_MI_35] = 0x0051; + MI_buf[REG_HW_MI_5F] = 0x0904; /* fail to write */ + MI_buf[REG_HW_MI_60] = 0x0000; + MI_buf[REG_HW_MI_61] = 0x0000; + MI_buf[REG_HW_MI_62] = 0x0498; + MI_buf[REG_HW_MI_63] = 0x0000; + MI_buf[REG_HW_MI_64] = 0x0000; + MI_buf[REG_HW_MI_F1] = 0x0001; + /* changing while setting up the different value of dx/dy */ + + if (gspca_dev->width != 1280) { + MI_buf[0x01] = 0x010a; + MI_buf[0x02] = 0x014c; + MI_buf[0x03] = 0x01e5; + MI_buf[0x04] = 0x0287; + } + MI_buf[0x20] = 0x1104; + + bulk_w(gspca_dev, MI_buf + 1, 1); + bulk_w(gspca_dev, MI_buf + 2, 2); + bulk_w(gspca_dev, MI_buf + 3, 3); + bulk_w(gspca_dev, MI_buf + 4, 4); + bulk_w(gspca_dev, MI_buf + 5, 5); + bulk_w(gspca_dev, MI_buf + 6, 6); + bulk_w(gspca_dev, MI_buf + 7, 7); + bulk_w(gspca_dev, MI_buf + 9, 9); + bulk_w(gspca_dev, MI_buf + 0x0b, 0x0b); + bulk_w(gspca_dev, MI_buf + 0x0c, 0x0c); + bulk_w(gspca_dev, MI_buf + 0x0d, 0x0d); + bulk_w(gspca_dev, MI_buf + 0x1e, 0x1e); + bulk_w(gspca_dev, MI_buf + 0x20, 0x20); + bulk_w(gspca_dev, MI_buf + 0x2b, 0x2b); + bulk_w(gspca_dev, MI_buf + 0x2c, 0x2c); + bulk_w(gspca_dev, MI_buf + 0x2d, 0x2d); + bulk_w(gspca_dev, MI_buf + 0x2e, 0x2e); + bulk_w(gspca_dev, MI_buf + 0x35, 0x35); + bulk_w(gspca_dev, MI_buf + 0x5f, 0x5f); + bulk_w(gspca_dev, MI_buf + 0x60, 0x60); + bulk_w(gspca_dev, MI_buf + 0x61, 0x61); + bulk_w(gspca_dev, MI_buf + 0x62, 0x62); + bulk_w(gspca_dev, MI_buf + 0x63, 0x63); + bulk_w(gspca_dev, MI_buf + 0x64, 0x64); + bulk_w(gspca_dev, MI_buf + 0xf1, 0xf1); + kfree(MI_buf); + + intpipe = usb_sndintpipe(gspca_dev->dev, 0); + err_code = usb_clear_halt(gspca_dev->dev, intpipe); + + data[0] = 0x00; + data[1] = 0x4d; /* ISOC transfering enable... */ + reg_w(gspca_dev, data[0], 2); +} + +static void sd_stopN(struct gspca_dev *gspca_dev) +{ + int result; + + gspca_dev->usb_buf[0] = 1; + gspca_dev->usb_buf[1] = 0; + result = reg_w(gspca_dev, gspca_dev->usb_buf[0], 2); + if (result < 0) + PDEBUG(D_ERR, "Camera Stop failed"); +} + +static void sd_stop0(struct gspca_dev *gspca_dev) +{ +} + +static void sd_close(struct gspca_dev *gspca_dev) +{ +} + +static void sd_pkt_scan(struct gspca_dev *gspca_dev, + struct gspca_frame *frame, /* target */ + __u8 *data, /* isoc packet */ + int len) /* iso packet length */ +{ + struct sd *sd = (struct sd *) gspca_dev; + int p; + + if (len < 6) { +/* gspca_dev->last_packet_type = DISCARD_PACKET; */ + return; + } + for (p = 0; p < len - 6; p++) { + if (data[0 + p] == 0xff + && data[1 + p] == 0xff + && data[2 + p] == 0x00 + && data[3 + p] == 0xff + && data[4 + p] == 0x96) { + if (data[5 + p] == 0x64 + || data[5 + p] == 0x65 + || data[5 + p] == 0x66 + || data[5 + p] == 0x67) { + PDEBUG(D_PACK, "sof offset: %d leng: %d", + p, len); + frame = gspca_frame_add(gspca_dev, LAST_PACKET, + frame, data, 0); + + /* put the JPEG header */ + jpeg_put_header(gspca_dev, frame, + sd->qindex, 0x21); + data += 16; + len -= 16; + break; + } + } + } + gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len); +} + +/* sub-driver description */ +static const struct sd_desc sd_desc = { + .name = MODULE_NAME, + .ctrls = sd_ctrls, + .nctrls = ARRAY_SIZE(sd_ctrls), + .config = sd_config, + .open = sd_open, + .start = sd_start, + .stopN = sd_stopN, + .stop0 = sd_stop0, + .close = sd_close, + .pkt_scan = sd_pkt_scan, +}; + +/* -- module initialisation -- */ +#define DVNM(name) .driver_info = (kernel_ulong_t) name +static const __devinitdata struct usb_device_id device_table[] = { + {USB_DEVICE(0x093a, 0x050f), DVNM("Mars-Semi Pc-Camera")}, + {} +}; +MODULE_DEVICE_TABLE(usb, device_table); + +/* -- device connect -- */ +static int sd_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd), + THIS_MODULE); +} + +static struct usb_driver sd_driver = { + .name = MODULE_NAME, + .id_table = device_table, + .probe = sd_probe, + .disconnect = gspca_disconnect, +}; + +/* -- module insert / remove -- */ +static int __init sd_mod_init(void) +{ + if (usb_register(&sd_driver) < 0) + return -1; + PDEBUG(D_PROBE, "v%s registered", version); + return 0; +} +static void __exit sd_mod_exit(void) +{ + usb_deregister(&sd_driver); + PDEBUG(D_PROBE, "deregistered"); +} + +module_init(sd_mod_init); +module_exit(sd_mod_exit); diff --git a/drivers/media/video/gspca/ov519.c b/drivers/media/video/gspca/ov519.c new file mode 100644 index 000000000000..08d99c3b78e2 --- /dev/null +++ b/drivers/media/video/gspca/ov519.c @@ -0,0 +1,2186 @@ +/** + * OV519 driver + * + * Copyright (C) 2008 Jean-Francois Moine (http://moinejf.free.fr) + * + * (This module is adapted from the ov51x-jpeg package) + * + * 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 + * 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 + * + */ +#define MODULE_NAME "ov519" + +#include "gspca.h" + +#define DRIVER_VERSION_NUMBER KERNEL_VERSION(2, 1, 7) +static const char version[] = "2.1.7"; + +MODULE_AUTHOR("Jean-Francois Moine <http://moinejf.free.fr>"); +MODULE_DESCRIPTION("OV519 USB Camera Driver"); +MODULE_LICENSE("GPL"); + +/* global parameters */ +static int frame_rate; + +/* Number of times to retry a failed I2C transaction. Increase this if you + * are getting "Failed to read sensor ID..." */ +static int i2c_detect_tries = 10; + +/* ov519 device descriptor */ +struct sd { + struct gspca_dev gspca_dev; /* !! must be the first item */ + + /* Determined by sensor type */ + short maxwidth; + short maxheight; + + unsigned char primary_i2c_slave; /* I2C write id of sensor */ + + unsigned char brightness; + unsigned char contrast; + unsigned char colors; + + char compress; /* Should the next frame be compressed? */ + char compress_inited; /* Are compression params uploaded? */ + char stopped; /* Streaming is temporarily paused */ + + char frame_rate; /* current Framerate (OV519 only) */ + char clockdiv; /* clockdiv override for OV519 only */ + + char sensor; /* Type of image sensor chip (SEN_*) */ +#define SEN_UNKNOWN 0 +#define SEN_OV6620 1 +#define SEN_OV6630 2 +#define SEN_OV7610 3 +#define SEN_OV7620 4 +#define SEN_OV7630 5 +#define SEN_OV7640 6 +#define SEN_OV7670 7 +#define SEN_OV76BE 8 +#define SEN_OV8610 9 + +}; + +/* V4L2 controls supported by the driver */ +static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val); +static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val); +static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val); +static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val); +static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val); +static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val); + +static struct ctrl sd_ctrls[] = { +#define SD_BRIGHTNESS 0 + { + { + .id = V4L2_CID_BRIGHTNESS, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Brightness", + .minimum = 0, + .maximum = 255, + .step = 1, + .default_value = 127, + }, + .set = sd_setbrightness, + .get = sd_getbrightness, + }, +#define SD_CONTRAST 1 + { + { + .id = V4L2_CID_CONTRAST, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Contrast", + .minimum = 0, + .maximum = 255, + .step = 1, + .default_value = 127, + }, + .set = sd_setcontrast, + .get = sd_getcontrast, + }, +#define SD_COLOR 2 + { + { + .id = V4L2_CID_SATURATION, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Saturation", + .minimum = 0, + .maximum = 255, + .step = 1, + .default_value = 127, + }, + .set = sd_setcolors, + .get = sd_getcolors, + }, +}; + +static struct v4l2_pix_format vga_mode[] = { + {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, + .bytesperline = 320, + .sizeimage = 320 * 240 * 3 / 8 + 589, + .colorspace = V4L2_COLORSPACE_JPEG, + .priv = 1}, + {640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, + .bytesperline = 640, + .sizeimage = 640 * 480 * 3 / 8 + 590, + .colorspace = V4L2_COLORSPACE_JPEG, + .priv = 0}, +}; +static struct v4l2_pix_format sif_mode[] = { + {176, 144, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, + .bytesperline = 176, + .sizeimage = 176 * 144 * 3 / 8 + 589, + .colorspace = V4L2_COLORSPACE_JPEG, + .priv = 1}, + {352, 288, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, + .bytesperline = 352, + .sizeimage = 352 * 288 * 3 / 8 + 589, + .colorspace = V4L2_COLORSPACE_JPEG, + .priv = 0}, +}; + +/* OV519 Camera interface register numbers */ +#define OV519_CAM_H_SIZE 0x10 +#define OV519_CAM_V_SIZE 0x11 +#define OV519_CAM_X_OFFSETL 0x12 +#define OV519_CAM_X_OFFSETH 0x13 +#define OV519_CAM_Y_OFFSETL 0x14 +#define OV519_CAM_Y_OFFSETH 0x15 +#define OV519_CAM_DIVIDER 0x16 +#define OV519_CAM_DFR 0x20 +#define OV519_CAM_FORMAT 0x25 + +/* OV519 System Controller register numbers */ +#define OV519_SYS_RESET1 0x51 +#define OV519_SYS_EN_CLK1 0x54 + +#define OV519_GPIO_DATA_OUT0 0x71 +#define OV519_GPIO_IO_CTRL0 0x72 + +#define OV511_ENDPOINT_ADDRESS 1 /* Isoc endpoint number */ + +/* I2C registers */ +#define R51x_I2C_W_SID 0x41 +#define R51x_I2C_SADDR_3 0x42 +#define R51x_I2C_SADDR_2 0x43 +#define R51x_I2C_R_SID 0x44 +#define R51x_I2C_DATA 0x45 +#define R518_I2C_CTL 0x47 /* OV518(+) only */ + +/* I2C ADDRESSES */ +#define OV7xx0_SID 0x42 +#define OV8xx0_SID 0xa0 +#define OV6xx0_SID 0xc0 + +/* OV7610 registers */ +#define OV7610_REG_GAIN 0x00 /* gain setting (5:0) */ +#define OV7610_REG_SAT 0x03 /* saturation */ +#define OV8610_REG_HUE 0x04 /* 04 reserved */ +#define OV7610_REG_CNT 0x05 /* Y contrast */ +#define OV7610_REG_BRT 0x06 /* Y brightness */ +#define OV7610_REG_COM_C 0x14 /* misc common regs */ +#define OV7610_REG_ID_HIGH 0x1c /* manufacturer ID MSB */ +#define OV7610_REG_ID_LOW 0x1d /* manufacturer ID LSB */ +#define OV7610_REG_COM_I 0x29 /* misc settings */ + +/* OV7670 registers */ +#define OV7670_REG_GAIN 0x00 /* Gain lower 8 bits (rest in vref) */ +#define OV7670_REG_BLUE 0x01 /* blue gain */ +#define OV7670_REG_RED 0x02 /* red gain */ +#define OV7670_REG_VREF 0x03 /* Pieces of GAIN, VSTART, VSTOP */ +#define OV7670_REG_COM1 0x04 /* Control 1 */ +#define OV7670_REG_AECHH 0x07 /* AEC MS 5 bits */ +#define OV7670_REG_COM3 0x0c /* Control 3 */ +#define OV7670_REG_COM4 0x0d /* Control 4 */ +#define OV7670_REG_COM5 0x0e /* All "reserved" */ +#define OV7670_REG_COM6 0x0f /* Control 6 */ +#define OV7670_REG_AECH 0x10 /* More bits of AEC value */ +#define OV7670_REG_CLKRC 0x11 /* Clock control */ +#define OV7670_REG_COM7 0x12 /* Control 7 */ +#define OV7670_COM7_FMT_VGA 0x00 +#define OV7670_COM7_YUV 0x00 /* YUV */ +#define OV7670_COM7_FMT_QVGA 0x10 /* QVGA format */ +#define OV7670_COM7_FMT_MASK 0x38 +#define OV7670_COM7_RESET 0x80 /* Register reset */ +#define OV7670_REG_COM8 0x13 /* Control 8 */ +#define OV7670_COM8_AEC 0x01 /* Auto exposure enable */ +#define OV7670_COM8_AWB 0x02 /* White balance enable */ +#define OV7670_COM8_AGC 0x04 /* Auto gain enable */ +#define OV7670_COM8_BFILT 0x20 /* Band filter enable */ +#define OV7670_COM8_AECSTEP 0x40 /* Unlimited AEC step size */ +#define OV7670_COM8_FASTAEC 0x80 /* Enable fast AGC/AEC */ +#define OV7670_REG_COM9 0x14 /* Control 9 - gain ceiling */ +#define OV7670_REG_COM10 0x15 /* Control 10 */ +#define OV7670_REG_HSTART 0x17 /* Horiz start high bits */ +#define OV7670_REG_HSTOP 0x18 /* Horiz stop high bits */ +#define OV7670_REG_VSTART 0x19 /* Vert start high bits */ +#define OV7670_REG_VSTOP 0x1a /* Vert stop high bits */ +#define OV7670_REG_MVFP 0x1e /* Mirror / vflip */ +#define OV7670_MVFP_MIRROR 0x20 /* Mirror image */ +#define OV7670_REG_AEW 0x24 /* AGC upper limit */ +#define OV7670_REG_AEB 0x25 /* AGC lower limit */ +#define OV7670_REG_VPT 0x26 /* AGC/AEC fast mode op region */ +#define OV7670_REG_HREF 0x32 /* HREF pieces */ +#define OV7670_REG_TSLB 0x3a /* lots of stuff */ +#define OV7670_REG_COM11 0x3b /* Control 11 */ +#define OV7670_COM11_EXP 0x02 +#define OV7670_COM11_HZAUTO 0x10 /* Auto detect 50/60 Hz */ +#define OV7670_REG_COM12 0x3c /* Control 12 */ +#define OV7670_REG_COM13 0x3d /* Control 13 */ +#define OV7670_COM13_GAMMA 0x80 /* Gamma enable */ +#define OV7670_COM13_UVSAT 0x40 /* UV saturation auto adjustment */ +#define OV7670_REG_COM14 0x3e /* Control 14 */ +#define OV7670_REG_EDGE 0x3f /* Edge enhancement factor */ +#define OV7670_REG_COM15 0x40 /* Control 15 */ +#define OV7670_COM15_R00FF 0xc0 /* 00 to FF */ +#define OV7670_REG_COM16 0x41 /* Control 16 */ +#define OV7670_COM16_AWBGAIN 0x08 /* AWB gain enable */ +#define OV7670_REG_BRIGHT 0x55 /* Brightness */ +#define OV7670_REG_CONTRAS 0x56 /* Contrast control */ +#define OV7670_REG_GFIX 0x69 /* Fix gain control */ +#define OV7670_REG_RGB444 0x8c /* RGB 444 control */ +#define OV7670_REG_HAECC1 0x9f /* Hist AEC/AGC control 1 */ +#define OV7670_REG_HAECC2 0xa0 /* Hist AEC/AGC control 2 */ +#define OV7670_REG_BD50MAX 0xa5 /* 50hz banding step limit */ +#define OV7670_REG_HAECC3 0xa6 /* Hist AEC/AGC control 3 */ +#define OV7670_REG_HAECC4 0xa7 /* Hist AEC/AGC control 4 */ +#define OV7670_REG_HAECC5 0xa8 /* Hist AEC/AGC control 5 */ +#define OV7670_REG_HAECC6 0xa9 /* Hist AEC/AGC control 6 */ +#define OV7670_REG_HAECC7 0xaa /* Hist AEC/AGC control 7 */ +#define OV7670_REG_BD60MAX 0xab /* 60hz banding step limit */ + +struct ovsensor_window { + short x; + short y; + short width; + short height; +/* int format; */ + short quarter; /* Scale width and height down 2x */ + short clockdiv; /* Clock divisor setting */ +}; + +static unsigned char ov7670_abs_to_sm(unsigned char v) +{ + if (v > 127) + return v & 0x7f; + return (128 - v) | 0x80; +} + +/* Write a OV519 register */ +static int reg_w(struct sd *sd, __u16 index, __u8 value) +{ + int ret; + + sd->gspca_dev.usb_buf[0] = value; + ret = usb_control_msg(sd->gspca_dev.dev, + usb_sndctrlpipe(sd->gspca_dev.dev, 0), + 1, /* REQ_IO (ov518/519) */ + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + 0, index, + sd->gspca_dev.usb_buf, 1, 500); + if (ret < 0) + PDEBUG(D_ERR, "Write reg [%02x] %02x failed", index, value); + return ret; +} + +/* Read from a OV519 register */ +/* returns: negative is error, pos or zero is data */ +static int reg_r(struct sd *sd, __u16 index) +{ + int ret; + + ret = usb_control_msg(sd->gspca_dev.dev, + usb_rcvctrlpipe(sd->gspca_dev.dev, 0), + 1, /* REQ_IO */ + USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + 0, index, sd->gspca_dev.usb_buf, 1, 500); + + if (ret >= 0) + ret = sd->gspca_dev.usb_buf[0]; + else + PDEBUG(D_ERR, "Read reg [0x%02x] failed", index); + return ret; +} + +/* Read 8 values from a OV519 register */ +static int reg_r8(struct sd *sd, + __u16 index) +{ + int ret; + + ret = usb_control_msg(sd->gspca_dev.dev, + usb_rcvctrlpipe(sd->gspca_dev.dev, 0), + 1, /* REQ_IO */ + USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + 0, index, sd->gspca_dev.usb_buf, 8, 500); + + if (ret >= 0) + ret = sd->gspca_dev.usb_buf[0]; + else + PDEBUG(D_ERR, "Read reg 8 [0x%02x] failed", index); + return ret; +} + +/* + * Writes bits at positions specified by mask to an OV51x reg. Bits that are in + * the same position as 1's in "mask" are cleared and set to "value". Bits + * that are in the same position as 0's in "mask" are preserved, regardless + * of their respective state in "value". + */ +static int reg_w_mask(struct sd *sd, + __u16 index, + __u8 value, + __u8 mask) +{ + int ret; + __u8 oldval; + + if (mask != 0xff) { + value &= mask; /* Enforce mask on value */ + ret = reg_r(sd, index); + if (ret < 0) + return ret; + + oldval = ret & ~mask; /* Clear the masked bits */ + value |= oldval; /* Set the desired bits */ + } + return reg_w(sd, index, value); +} + +/* + * The OV518 I2C I/O procedure is different, hence, this function. + * This is normally only called from i2c_w(). Note that this function + * always succeeds regardless of whether the sensor is present and working. + */ +static int i2c_w(struct sd *sd, + __u8 reg, + __u8 value) +{ + int rc; + + PDEBUG(D_USBO, "i2c 0x%02x -> [0x%02x]", value, reg); + + /* Select camera register */ + rc = reg_w(sd, R51x_I2C_SADDR_3, reg); + if (rc < 0) + return rc; + + /* Write "value" to I2C data port of OV511 */ + rc = reg_w(sd, R51x_I2C_DATA, value); + if (rc < 0) + return rc; + + /* Initiate 3-byte write cycle */ + rc = reg_w(sd, R518_I2C_CTL, 0x01); + + /* wait for write complete */ + msleep(4); + if (rc < 0) + return rc; + return reg_r8(sd, R518_I2C_CTL); +} + +/* + * returns: negative is error, pos or zero is data + * + * The OV518 I2C I/O procedure is different, hence, this function. + * This is normally only called from i2c_r(). Note that this function + * always succeeds regardless of whether the sensor is present and working. + */ +static int i2c_r(struct sd *sd, __u8 reg) +{ + int rc, value; + + /* Select camera register */ + rc = reg_w(sd, R51x_I2C_SADDR_2, reg); + if (rc < 0) + return rc; + + /* Initiate 2-byte write cycle */ + rc = reg_w(sd, R518_I2C_CTL, 0x03); + if (rc < 0) + return rc; + + /* Initiate 2-byte read cycle */ + rc = reg_w(sd, R518_I2C_CTL, 0x05); + if (rc < 0) + return rc; + value = reg_r(sd, R51x_I2C_DATA); + PDEBUG(D_USBI, "i2c [0x%02X] -> 0x%02X", reg, value); + return value; +} + +/* Writes bits at positions specified by mask to an I2C reg. Bits that are in + * the same position as 1's in "mask" are cleared and set to "value". Bits + * that are in the same position as 0's in "mask" are preserved, regardless + * of their respective state in "value". + */ +static int i2c_w_mask(struct sd *sd, + __u8 reg, + __u8 value, + __u8 mask) +{ + int rc; + __u8 oldval; + + value &= mask; /* Enforce mask on value */ + rc = i2c_r(sd, reg); + if (rc < 0) + return rc; + oldval = rc & ~mask; /* Clear the masked bits */ + value |= oldval; /* Set the desired bits */ + return i2c_w(sd, reg, value); +} + +/* Temporarily stops OV511 from functioning. Must do this before changing + * registers while the camera is streaming */ +static inline int ov51x_stop(struct sd *sd) +{ + PDEBUG(D_STREAM, "stopping"); + sd->stopped = 1; + return reg_w(sd, OV519_SYS_RESET1, 0x0f); +} + +/* Restarts OV511 after ov511_stop() is called. Has no effect if it is not + * actually stopped (for performance). */ +static inline int ov51x_restart(struct sd *sd) +{ + PDEBUG(D_STREAM, "restarting"); + if (!sd->stopped) + return 0; + sd->stopped = 0; + + /* Reinitialize the stream */ + return reg_w(sd, OV519_SYS_RESET1, 0x00); +} + +/* This does an initial reset of an OmniVision sensor and ensures that I2C + * is synchronized. Returns <0 on failure. + */ +static int init_ov_sensor(struct sd *sd) +{ + int i, success; + + /* Reset the sensor */ + if (i2c_w(sd, 0x12, 0x80) < 0) + return -EIO; + + /* Wait for it to initialize */ + msleep(150); + + for (i = 0, success = 0; i < i2c_detect_tries && !success; i++) { + if (i2c_r(sd, OV7610_REG_ID_HIGH) == 0x7f && + i2c_r(sd, OV7610_REG_ID_LOW) == 0xa2) { + success = 1; + continue; + } + + /* Reset the sensor */ + if (i2c_w(sd, 0x12, 0x80) < 0) + return -EIO; + /* Wait for it to initialize */ + msleep(150); + /* Dummy read to sync I2C */ + if (i2c_r(sd, 0x00) < 0) + return -EIO; + } + if (!success) + return -EIO; + PDEBUG(D_PROBE, "I2C synced in %d attempt(s)", i); + return 0; +} + +/* Switch on standard JPEG compression. Returns 0 for success. */ +static int ov519_init_compression(struct sd *sd) +{ + if (!sd->compress_inited) { + if (reg_w_mask(sd, OV519_SYS_EN_CLK1, 1 << 2, 1 << 2) < 0) { + PDEBUG(D_ERR, "Error switching to compressed mode"); + return -EIO; + } + sd->compress_inited = 1; + } + return 0; +} + +/* Set the read and write slave IDs. The "slave" argument is the write slave, + * and the read slave will be set to (slave + 1). + * This should not be called from outside the i2c I/O functions. + * Sets I2C read and write slave IDs. Returns <0 for error + */ +static int ov51x_set_slave_ids(struct sd *sd, + __u8 slave) +{ + int rc; + + rc = reg_w(sd, R51x_I2C_W_SID, slave); + if (rc < 0) + return rc; + return reg_w(sd, R51x_I2C_R_SID, slave + 1); +} + +struct ov_regvals { + __u8 reg; + __u8 val; +}; +struct ov_i2c_regvals { + __u8 reg; + __u8 val; +}; + +static int write_regvals(struct sd *sd, + const struct ov_regvals *regvals, + int n) +{ + int rc; + + while (--n >= 0) { + rc = reg_w(sd, regvals->reg, regvals->val); + if (rc < 0) + return rc; + regvals++; + } + return 0; +} + +static int write_i2c_regvals(struct sd *sd, + const struct ov_i2c_regvals *regvals, + int n) +{ + int rc; + + while (--n >= 0) { + rc = i2c_w(sd, regvals->reg, regvals->val); + if (rc < 0) + return rc; + regvals++; + } + return 0; +} + +/**************************************************************************** + * + * OV511 and sensor configuration + * + ***************************************************************************/ + +/* This initializes the OV8110, OV8610 sensor. The OV8110 uses + * the same register settings as the OV8610, since they are very similar. + */ +static int ov8xx0_configure(struct sd *sd) +{ + int rc; + static const struct ov_i2c_regvals norm_8610[] = { + { 0x12, 0x80 }, + { 0x00, 0x00 }, + { 0x01, 0x80 }, + { 0x02, 0x80 }, + { 0x03, 0xc0 }, + { 0x04, 0x30 }, + { 0x05, 0x30 }, /* was 0x10, new from windrv 090403 */ + { 0x06, 0x70 }, /* was 0x80, new from windrv 090403 */ + { 0x0a, 0x86 }, + { 0x0b, 0xb0 }, + { 0x0c, 0x20 }, + { 0x0d, 0x20 }, + { 0x11, 0x01 }, + { 0x12, 0x25 }, + { 0x13, 0x01 }, + { 0x14, 0x04 }, + { 0x15, 0x01 }, /* Lin and Win think different about UV order */ + { 0x16, 0x03 }, + { 0x17, 0x38 }, /* was 0x2f, new from windrv 090403 */ + { 0x18, 0xea }, /* was 0xcf, new from windrv 090403 */ + { 0x19, 0x02 }, /* was 0x06, new from windrv 090403 */ + { 0x1a, 0xf5 }, + { 0x1b, 0x00 }, + { 0x20, 0xd0 }, /* was 0x90, new from windrv 090403 */ + { 0x23, 0xc0 }, /* was 0x00, new from windrv 090403 */ + { 0x24, 0x30 }, /* was 0x1d, new from windrv 090403 */ + { 0x25, 0x50 }, /* was 0x57, new from windrv 090403 */ + { 0x26, 0xa2 }, + { 0x27, 0xea }, + { 0x28, 0x00 }, + { 0x29, 0x00 }, + { 0x2a, 0x80 }, + { 0x2b, 0xc8 }, /* was 0xcc, new from windrv 090403 */ + { 0x2c, 0xac }, + { 0x2d, 0x45 }, /* was 0xd5, new from windrv 090403 */ + { 0x2e, 0x80 }, + { 0x2f, 0x14 }, /* was 0x01, new from windrv 090403 */ + { 0x4c, 0x00 }, + { 0x4d, 0x30 }, /* was 0x10, new from windrv 090403 */ + { 0x60, 0x02 }, /* was 0x01, new from windrv 090403 */ + { 0x61, 0x00 }, /* was 0x09, new from windrv 090403 */ + { 0x62, 0x5f }, /* was 0xd7, new from windrv 090403 */ + { 0x63, 0xff }, + { 0x64, 0x53 }, /* new windrv 090403 says 0x57, + * maybe thats wrong */ + { 0x65, 0x00 }, + { 0x66, 0x55 }, + { 0x67, 0xb0 }, + { 0x68, 0xc0 }, /* was 0xaf, new from windrv 090403 */ + { 0x69, 0x02 }, + { 0x6a, 0x22 }, + { 0x6b, 0x00 }, + { 0x6c, 0x99 }, /* was 0x80, old windrv says 0x00, but + deleting bit7 colors the first images red */ + { 0x6d, 0x11 }, /* was 0x00, new from windrv 090403 */ + { 0x6e, 0x11 }, /* was 0x00, new from windrv 090403 */ + { 0x6f, 0x01 }, + { 0x70, 0x8b }, + { 0x71, 0x00 }, + { 0x72, 0x14 }, + { 0x73, 0x54 }, + { 0x74, 0x00 },/* 0x60? - was 0x00, new from windrv 090403 */ + { 0x75, 0x0e }, + { 0x76, 0x02 }, /* was 0x02, new from windrv 090403 */ + { 0x77, 0xff }, + { 0x78, 0x80 }, + { 0x79, 0x80 }, + { 0x7a, 0x80 }, + { 0x7b, 0x10 }, /* was 0x13, new from windrv 090403 */ + { 0x7c, 0x00 }, + { 0x7d, 0x08 }, /* was 0x09, new from windrv 090403 */ + { 0x7e, 0x08 }, /* was 0xc0, new from windrv 090403 */ + { 0x7f, 0xfb }, + { 0x80, 0x28 }, + { 0x81, 0x00 }, + { 0x82, 0x23 }, + { 0x83, 0x0b }, + { 0x84, 0x00 }, + { 0x85, 0x62 }, /* was 0x61, new from windrv 090403 */ + { 0x86, 0xc9 }, + { 0x87, 0x00 }, + { 0x88, 0x00 }, + { 0x89, 0x01 }, + { 0x12, 0x20 }, + { 0x12, 0x25 }, /* was 0x24, new from windrv 090403 */ + }; + + PDEBUG(D_PROBE, "starting ov8xx0 configuration"); + + if (init_ov_sensor(sd) < 0) + PDEBUG(D_ERR|D_PROBE, "Failed to read sensor ID"); + else + PDEBUG(D_PROBE, "OV86x0 initialized"); + + /* Detect sensor (sub)type */ + rc = i2c_r(sd, OV7610_REG_COM_I); + if (rc < 0) { + PDEBUG(D_ERR, "Error detecting sensor type"); + return -1; + } + if ((rc & 3) == 1) { + PDEBUG(D_PROBE, "Sensor is an OV8610"); + sd->sensor = SEN_OV8610; + } else { + PDEBUG(D_ERR, "Unknown image sensor version: %d", rc & 3); + return -1; + } + PDEBUG(D_PROBE, "Writing 8610 registers"); + if (write_i2c_regvals(sd, + norm_8610, + sizeof norm_8610 / sizeof norm_8610[0])) + return -1; + + /* Set sensor-specific vars */ + sd->maxwidth = 640; + sd->maxheight = 480; + return 0; +} + +/* This initializes the OV7610, OV7620, or OV76BE sensor. The OV76BE uses + * the same register settings as the OV7610, since they are very similar. + */ +static int ov7xx0_configure(struct sd *sd) +{ + int rc, high, low; + + /* Lawrence Glaister <lg@jfm.bc.ca> reports: + * + * Register 0x0f in the 7610 has the following effects: + * + * 0x85 (AEC method 1): Best overall, good contrast range + * 0x45 (AEC method 2): Very overexposed + * 0xa5 (spec sheet default): Ok, but the black level is + * shifted resulting in loss of contrast + * 0x05 (old driver setting): very overexposed, too much + * contrast + */ + static const struct ov_i2c_regvals norm_7610[] = { + { 0x10, 0xff }, + { 0x16, 0x06 }, + { 0x28, 0x24 }, + { 0x2b, 0xac }, + { 0x12, 0x00 }, + { 0x38, 0x81 }, + { 0x28, 0x24 }, /* 0c */ + { 0x0f, 0x85 }, /* lg's setting */ + { 0x15, 0x01 }, + { 0x20, 0x1c }, + { 0x23, 0x2a }, + { 0x24, 0x10 }, + { 0x25, 0x8a }, + { 0x26, 0xa2 }, + { 0x27, 0xc2 }, + { 0x2a, 0x04 }, + { 0x2c, 0xfe }, + { 0x2d, 0x93 }, + { 0x30, 0x71 }, + { 0x31, 0x60 }, + { 0x32, 0x26 }, + { 0x33, 0x20 }, + { 0x34, 0x48 }, + { 0x12, 0x24 }, + { 0x11, 0x01 }, + { 0x0c, 0x24 }, + { 0x0d, 0x24 }, + }; + + static const struct ov_i2c_regvals norm_7620[] = { + { 0x00, 0x00 }, /* gain */ + { 0x01, 0x80 }, /* blue gain */ + { 0x02, 0x80 }, /* red gain */ + { 0x03, 0xc0 }, /* OV7670_REG_VREF */ + { 0x06, 0x60 }, + { 0x07, 0x00 }, + { 0x0c, 0x24 }, + { 0x0c, 0x24 }, + { 0x0d, 0x24 }, + { 0x11, 0x01 }, + { 0x12, 0x24 }, + { 0x13, 0x01 }, + { 0x14, 0x84 }, + { 0x15, 0x01 }, + { 0x16, 0x03 }, + { 0x17, 0x2f }, + { 0x18, 0xcf }, + { 0x19, 0x06 }, + { 0x1a, 0xf5 }, + { 0x1b, 0x00 }, + { 0x20, 0x18 }, + { 0x21, 0x80 }, + { 0x22, 0x80 }, + { 0x23, 0x00 }, + { 0x26, 0xa2 }, + { 0x27, 0xea }, + { 0x28, 0x20 }, + { 0x29, 0x00 }, + { 0x2a, 0x10 }, + { 0x2b, 0x00 }, + { 0x2c, 0x88 }, + { 0x2d, 0x91 }, + { 0x2e, 0x80 }, + { 0x2f, 0x44 }, + { 0x60, 0x27 }, + { 0x61, 0x02 }, + { 0x62, 0x5f }, + { 0x63, 0xd5 }, + { 0x64, 0x57 }, + { 0x65, 0x83 }, + { 0x66, 0x55 }, + { 0x67, 0x92 }, + { 0x68, 0xcf }, + { 0x69, 0x76 }, + { 0x6a, 0x22 }, + { 0x6b, 0x00 }, + { 0x6c, 0x02 }, + { 0x6d, 0x44 }, + { 0x6e, 0x80 }, + { 0x6f, 0x1d }, + { 0x70, 0x8b }, + { 0x71, 0x00 }, + { 0x72, 0x14 }, + { 0x73, 0x54 }, + { 0x74, 0x00 }, + { 0x75, 0x8e }, + { 0x76, 0x00 }, + { 0x77, 0xff }, + { 0x78, 0x80 }, + { 0x79, 0x80 }, + { 0x7a, 0x80 }, + { 0x7b, 0xe2 }, + { 0x7c, 0x00 }, + }; + + /* 7640 and 7648. The defaults should be OK for most registers. */ + static const struct ov_i2c_regvals norm_7640[] = { + { 0x12, 0x80 }, + { 0x12, 0x14 }, + }; + + /* 7670. Defaults taken from OmniVision provided data, + * as provided by Jonathan Corbet of OLPC */ + static const struct ov_i2c_regvals norm_7670[] = { + { OV7670_REG_COM7, OV7670_COM7_RESET }, + { OV7670_REG_TSLB, 0x04 }, /* OV */ + { OV7670_REG_COM7, OV7670_COM7_FMT_VGA }, /* VGA */ + { OV7670_REG_CLKRC, 0x1 }, + /* + * Set the hardware window. These values from OV don't entirely + * make sense - hstop is less than hstart. But they work... + */ + { OV7670_REG_HSTART, 0x13 }, { OV7670_REG_HSTOP, 0x01 }, + { OV7670_REG_HREF, 0xb6 }, { OV7670_REG_VSTART, 0x02 }, + { OV7670_REG_VSTOP, 0x7a }, { OV7670_REG_VREF, 0x0a }, + + { OV7670_REG_COM3, 0 }, { OV7670_REG_COM14, 0 }, + /* Mystery scaling numbers */ + { 0x70, 0x3a }, { 0x71, 0x35 }, + { 0x72, 0x11 }, { 0x73, 0xf0 }, + { 0xa2, 0x02 }, +/* jfm */ +/* { OV7670_REG_COM10, 0x0 }, */ + + /* Gamma curve values */ + { 0x7a, 0x20 }, +/* jfm:win 7b=1c */ + { 0x7b, 0x10 }, +/* jfm:win 7c=28 */ + { 0x7c, 0x1e }, +/* jfm:win 7d=3c */ + { 0x7d, 0x35 }, + { 0x7e, 0x5a }, { 0x7f, 0x69 }, + { 0x80, 0x76 }, { 0x81, 0x80 }, + { 0x82, 0x88 }, { 0x83, 0x8f }, + { 0x84, 0x96 }, { 0x85, 0xa3 }, + { 0x86, 0xaf }, { 0x87, 0xc4 }, + { 0x88, 0xd7 }, { 0x89, 0xe8 }, + + /* AGC and AEC parameters. Note we start by disabling those features, + then turn them only after tweaking the values. */ + { OV7670_REG_COM8, OV7670_COM8_FASTAEC + | OV7670_COM8_AECSTEP + | OV7670_COM8_BFILT }, + { OV7670_REG_GAIN, 0 }, { OV7670_REG_AECH, 0 }, + { OV7670_REG_COM4, 0x40 }, /* magic reserved bit */ +/* jfm:win 14=38 */ + { OV7670_REG_COM9, 0x18 }, /* 4x gain + magic rsvd bit */ + { OV7670_REG_BD50MAX, 0x05 }, { OV7670_REG_BD60MAX, 0x07 }, + { OV7670_REG_AEW, 0x95 }, { OV7670_REG_AEB, 0x33 }, + { OV7670_REG_VPT, 0xe3 }, { OV7670_REG_HAECC1, 0x78 }, + { OV7670_REG_HAECC2, 0x68 }, +/* jfm:win a1=0b */ + { 0xa1, 0x03 }, /* magic */ + { OV7670_REG_HAECC3, 0xd8 }, { OV7670_REG_HAECC4, 0xd8 }, + { OV7670_REG_HAECC5, 0xf0 }, { OV7670_REG_HAECC6, 0x90 }, + { OV7670_REG_HAECC7, 0x94 }, + { OV7670_REG_COM8, OV7670_COM8_FASTAEC + | OV7670_COM8_AECSTEP + | OV7670_COM8_BFILT + | OV7670_COM8_AGC + | OV7670_COM8_AEC }, + + /* Almost all of these are magic "reserved" values. */ + { OV7670_REG_COM5, 0x61 }, { OV7670_REG_COM6, 0x4b }, + { 0x16, 0x02 }, +/* jfm */ +/* { OV7670_REG_MVFP, 0x07|OV7670_MVFP_MIRROR }, */ + { OV7670_REG_MVFP, 0x07 }, + { 0x21, 0x02 }, { 0x22, 0x91 }, + { 0x29, 0x07 }, { 0x33, 0x0b }, + { 0x35, 0x0b }, { 0x37, 0x1d }, + { 0x38, 0x71 }, { 0x39, 0x2a }, + { OV7670_REG_COM12, 0x78 }, { 0x4d, 0x40 }, + { 0x4e, 0x20 }, { OV7670_REG_GFIX, 0 }, + { 0x6b, 0x4a }, { 0x74, 0x10 }, + { 0x8d, 0x4f }, { 0x8e, 0 }, + { 0x8f, 0 }, { 0x90, 0 }, + { 0x91, 0 }, { 0x96, 0 }, + { 0x9a, 0 }, { 0xb0, 0x84 }, + { 0xb1, 0x0c }, { 0xb2, 0x0e }, + { 0xb3, 0x82 }, { 0xb8, 0x0a }, + + /* More reserved magic, some of which tweaks white balance */ + { 0x43, 0x0a }, { 0x44, 0xf0 }, + { 0x45, 0x34 }, { 0x46, 0x58 }, + { 0x47, 0x28 }, { 0x48, 0x3a }, + { 0x59, 0x88 }, { 0x5a, 0x88 }, + { 0x5b, 0x44 }, { 0x5c, 0x67 }, + { 0x5d, 0x49 }, { 0x5e, 0x0e }, + { 0x6c, 0x0a }, { 0x6d, 0x55 }, + { 0x6e, 0x11 }, { 0x6f, 0x9f }, + /* "9e for advance AWB" */ + { 0x6a, 0x40 }, { OV7670_REG_BLUE, 0x40 }, + { OV7670_REG_RED, 0x60 }, + { OV7670_REG_COM8, OV7670_COM8_FASTAEC + | OV7670_COM8_AECSTEP + | OV7670_COM8_BFILT + | OV7670_COM8_AGC + | OV7670_COM8_AEC + | OV7670_COM8_AWB }, + + /* Matrix coefficients */ + { 0x4f, 0x80 }, { 0x50, 0x80 }, + { 0x51, 0 }, { 0x52, 0x22 }, + { 0x53, 0x5e }, { 0x54, 0x80 }, + { 0x58, 0x9e }, + + { OV7670_REG_COM16, OV7670_COM16_AWBGAIN }, + { OV7670_REG_EDGE, 0 }, + { 0x75, 0x05 }, { 0x76, 0xe1 }, + { 0x4c, 0 }, { 0x77, 0x01 }, + { OV7670_REG_COM13, 0xc3 }, { 0x4b, 0x09 }, + { 0xc9, 0x60 }, { OV7670_REG_COM16, 0x38 }, + { 0x56, 0x40 }, + + { 0x34, 0x11 }, + { OV7670_REG_COM11, OV7670_COM11_EXP|OV7670_COM11_HZAUTO }, + { 0xa4, 0x88 }, { 0x96, 0 }, + { 0x97, 0x30 }, { 0x98, 0x20 }, + { 0x99, 0x30 }, { 0x9a, 0x84 }, + { 0x9b, 0x29 }, { 0x9c, 0x03 }, + { 0x9d, 0x4c }, { 0x9e, 0x3f }, + { 0x78, 0x04 }, + + /* Extra-weird stuff. Some sort of multiplexor register */ + { 0x79, 0x01 }, { 0xc8, 0xf0 }, + { 0x79, 0x0f }, { 0xc8, 0x00 }, + { 0x79, 0x10 }, { 0xc8, 0x7e }, + { 0x79, 0x0a }, { 0xc8, 0x80 }, + { 0x79, 0x0b }, { 0xc8, 0x01 }, + { 0x79, 0x0c }, { 0xc8, 0x0f }, + { 0x79, 0x0d }, { 0xc8, 0x20 }, + { 0x79, 0x09 }, { 0xc8, 0x80 }, + { 0x79, 0x02 }, { 0xc8, 0xc0 }, + { 0x79, 0x03 }, { 0xc8, 0x40 }, + { 0x79, 0x05 }, { 0xc8, 0x30 }, + { 0x79, 0x26 }, + + /* Format YUV422 */ + { OV7670_REG_COM7, OV7670_COM7_YUV }, /* Selects YUV mode */ + { OV7670_REG_RGB444, 0 }, /* No RGB444 please */ + { OV7670_REG_COM1, 0 }, + { OV7670_REG_COM15, OV7670_COM15_R00FF }, + { OV7670_REG_COM9, 0x18 }, + /* 4x gain ceiling; 0x8 is reserved bit */ + { 0x4f, 0x80 }, /* "matrix coefficient 1" */ + { 0x50, 0x80 }, /* "matrix coefficient 2" */ + { 0x52, 0x22 }, /* "matrix coefficient 4" */ + { 0x53, 0x5e }, /* "matrix coefficient 5" */ + { 0x54, 0x80 }, /* "matrix coefficient 6" */ + { OV7670_REG_COM13, OV7670_COM13_GAMMA|OV7670_COM13_UVSAT }, +}; + + PDEBUG(D_PROBE, "starting OV7xx0 configuration"); + +/* jfm:already done? */ + if (init_ov_sensor(sd) < 0) + PDEBUG(D_ERR, "Failed to read sensor ID"); + else + PDEBUG(D_PROBE, "OV7xx0 initialized"); + + /* Detect sensor (sub)type */ + rc = i2c_r(sd, OV7610_REG_COM_I); + + /* add OV7670 here + * it appears to be wrongly detected as a 7610 by default */ + if (rc < 0) { + PDEBUG(D_ERR, "Error detecting sensor type"); + return -1; + } + if ((rc & 3) == 3) { + /* quick hack to make OV7670s work */ + high = i2c_r(sd, 0x0a); + low = i2c_r(sd, 0x0b); + /* info("%x, %x", high, low); */ + if (high == 0x76 && low == 0x73) { + PDEBUG(D_PROBE, "Sensor is an OV7670"); + sd->sensor = SEN_OV7670; + } else { + PDEBUG(D_PROBE, "Sensor is an OV7610"); + sd->sensor = SEN_OV7610; + } + } else if ((rc & 3) == 1) { + /* I don't know what's different about the 76BE yet. */ + if (i2c_r(sd, 0x15) & 1) + PDEBUG(D_PROBE, "Sensor is an OV7620AE"); + else + PDEBUG(D_PROBE, "Sensor is an OV76BE"); + + /* OV511+ will return all zero isoc data unless we + * configure the sensor as a 7620. Someone needs to + * find the exact reg. setting that causes this. */ + sd->sensor = SEN_OV76BE; + } else if ((rc & 3) == 0) { + /* try to read product id registers */ + high = i2c_r(sd, 0x0a); + if (high < 0) { + PDEBUG(D_ERR, "Error detecting camera chip PID"); + return high; + } + low = i2c_r(sd, 0x0b); + if (low < 0) { + PDEBUG(D_ERR, "Error detecting camera chip VER"); + return low; + } + if (high == 0x76) { + if (low == 0x30) { + PDEBUG(D_PROBE, "Sensor is an OV7630/OV7635"); + sd->sensor = SEN_OV7630; + } else if (low == 0x40) { + PDEBUG(D_PROBE, "Sensor is an OV7645"); + sd->sensor = SEN_OV7640; /* FIXME */ + } else if (low == 0x45) { + PDEBUG(D_PROBE, "Sensor is an OV7645B"); + sd->sensor = SEN_OV7640; /* FIXME */ + } else if (low == 0x48) { + PDEBUG(D_PROBE, "Sensor is an OV7648"); + sd->sensor = SEN_OV7640; /* FIXME */ + } else { + PDEBUG(D_PROBE, "Unknown sensor: 0x76%X", low); + return -1; + } + } else { + PDEBUG(D_PROBE, "Sensor is an OV7620"); + sd->sensor = SEN_OV7620; + } + } else { + PDEBUG(D_ERR, "Unknown image sensor version: %d", rc & 3); + return -1; + } + + if (sd->sensor == SEN_OV7620) { + PDEBUG(D_PROBE, "Writing 7620 registers"); + if (write_i2c_regvals(sd, norm_7620, + sizeof norm_7620 / sizeof norm_7620[0])) + return -1; + } else if (sd->sensor == SEN_OV7630) { + PDEBUG(D_ERR, "7630 is not supported by this driver version"); + return -1; + } else if (sd->sensor == SEN_OV7640) { + PDEBUG(D_PROBE, "Writing 7640 registers"); + if (write_i2c_regvals(sd, norm_7640, + sizeof norm_7640 / sizeof norm_7640[0])) + return -1; + } else if (sd->sensor == SEN_OV7670) { + PDEBUG(D_PROBE, "Writing 7670 registers"); + if (write_i2c_regvals(sd, norm_7670, + sizeof norm_7670 / sizeof norm_7670[0])) + return -1; + } else { + PDEBUG(D_PROBE, "Writing 7610 registers"); + if (write_i2c_regvals(sd, norm_7610, + sizeof norm_7610 / sizeof norm_7610[0])) + return -1; + } + + /* Set sensor-specific vars */ + sd->maxwidth = 640; + sd->maxheight = 480; + return 0; +} + +/* This initializes the OV6620, OV6630, OV6630AE, or OV6630AF sensor. */ +static int ov6xx0_configure(struct sd *sd) +{ + int rc; + static const struct ov_i2c_regvals norm_6x20[] = { + { 0x12, 0x80 }, /* reset */ + { 0x11, 0x01 }, + { 0x03, 0x60 }, + { 0x05, 0x7f }, /* For when autoadjust is off */ + { 0x07, 0xa8 }, + /* The ratio of 0x0c and 0x0d controls the white point */ + { 0x0c, 0x24 }, + { 0x0d, 0x24 }, + { 0x0f, 0x15 }, /* COMS */ + { 0x10, 0x75 }, /* AEC Exposure time */ + { 0x12, 0x24 }, /* Enable AGC */ + { 0x14, 0x04 }, + /* 0x16: 0x06 helps frame stability with moving objects */ + { 0x16, 0x06 }, +/* { 0x20, 0x30 }, * Aperture correction enable */ + { 0x26, 0xb2 }, /* BLC enable */ + /* 0x28: 0x05 Selects RGB format if RGB on */ + { 0x28, 0x05 }, + { 0x2a, 0x04 }, /* Disable framerate adjust */ +/* { 0x2b, 0xac }, * Framerate; Set 2a[7] first */ + { 0x2d, 0x99 }, + { 0x33, 0xa0 }, /* Color Processing Parameter */ + { 0x34, 0xd2 }, /* Max A/D range */ + { 0x38, 0x8b }, + { 0x39, 0x40 }, + + { 0x3c, 0x39 }, /* Enable AEC mode changing */ + { 0x3c, 0x3c }, /* Change AEC mode */ + { 0x3c, 0x24 }, /* Disable AEC mode changing */ + + { 0x3d, 0x80 }, + /* These next two registers (0x4a, 0x4b) are undocumented. + * They control the color balance */ + { 0x4a, 0x80 }, + { 0x4b, 0x80 }, + { 0x4d, 0xd2 }, /* This reduces noise a bit */ + { 0x4e, 0xc1 }, + { 0x4f, 0x04 }, +/* Do 50-53 have any effect? */ +/* Toggle 0x12[2] off and on here? */ + }; + + static const struct ov_i2c_regvals norm_6x30[] = { + { 0x12, 0x80 }, /* Reset */ + { 0x00, 0x1f }, /* Gain */ + { 0x01, 0x99 }, /* Blue gain */ + { 0x02, 0x7c }, /* Red gain */ + { 0x03, 0xc0 }, /* Saturation */ + { 0x05, 0x0a }, /* Contrast */ + { 0x06, 0x95 }, /* Brightness */ + { 0x07, 0x2d }, /* Sharpness */ + { 0x0c, 0x20 }, + { 0x0d, 0x20 }, + { 0x0e, 0x20 }, + { 0x0f, 0x05 }, + { 0x10, 0x9a }, + { 0x11, 0x00 }, /* Pixel clock = fastest */ + { 0x12, 0x24 }, /* Enable AGC and AWB */ + { 0x13, 0x21 }, + { 0x14, 0x80 }, + { 0x15, 0x01 }, + { 0x16, 0x03 }, + { 0x17, 0x38 }, + { 0x18, 0xea }, + { 0x19, 0x04 }, + { 0x1a, 0x93 }, + { 0x1b, 0x00 }, + { 0x1e, 0xc4 }, + { 0x1f, 0x04 }, + { 0x20, 0x20 }, + { 0x21, 0x10 }, + { 0x22, 0x88 }, + { 0x23, 0xc0 }, /* Crystal circuit power level */ + { 0x25, 0x9a }, /* Increase AEC black ratio */ + { 0x26, 0xb2 }, /* BLC enable */ + { 0x27, 0xa2 }, + { 0x28, 0x00 }, + { 0x29, 0x00 }, + { 0x2a, 0x84 }, /* 60 Hz power */ + { 0x2b, 0xa8 }, /* 60 Hz power */ + { 0x2c, 0xa0 }, + { 0x2d, 0x95 }, /* Enable auto-brightness */ + { 0x2e, 0x88 }, + { 0x33, 0x26 }, + { 0x34, 0x03 }, + { 0x36, 0x8f }, + { 0x37, 0x80 }, + { 0x38, 0x83 }, + { 0x39, 0x80 }, + { 0x3a, 0x0f }, + { 0x3b, 0x3c }, + { 0x3c, 0x1a }, + { 0x3d, 0x80 }, + { 0x3e, 0x80 }, + { 0x3f, 0x0e }, + { 0x40, 0x00 }, /* White bal */ + { 0x41, 0x00 }, /* White bal */ + { 0x42, 0x80 }, + { 0x43, 0x3f }, /* White bal */ + { 0x44, 0x80 }, + { 0x45, 0x20 }, + { 0x46, 0x20 }, + { 0x47, 0x80 }, + { 0x48, 0x7f }, + { 0x49, 0x00 }, + { 0x4a, 0x00 }, + { 0x4b, 0x80 }, + { 0x4c, 0xd0 }, + { 0x4d, 0x10 }, /* U = 0.563u, V = 0.714v */ + { 0x4e, 0x40 }, + { 0x4f, 0x07 }, /* UV avg., col. killer: max */ + { 0x50, 0xff }, + { 0x54, 0x23 }, /* Max AGC gain: 18dB */ + { 0x55, 0xff }, + { 0x56, 0x12 }, + { 0x57, 0x81 }, + { 0x58, 0x75 }, + { 0x59, 0x01 }, /* AGC dark current comp.: +1 */ + { 0x5a, 0x2c }, + { 0x5b, 0x0f }, /* AWB chrominance levels */ + { 0x5c, 0x10 }, + { 0x3d, 0x80 }, + { 0x27, 0xa6 }, + { 0x12, 0x20 }, /* Toggle AWB */ + { 0x12, 0x24 }, + }; + + PDEBUG(D_PROBE, "starting sensor configuration"); + + if (init_ov_sensor(sd) < 0) { + PDEBUG(D_ERR, "Failed to read sensor ID."); + return -1; + } + PDEBUG(D_PROBE, "OV6xx0 sensor detected"); + + /* Detect sensor (sub)type */ + rc = i2c_r(sd, OV7610_REG_COM_I); + if (rc < 0) { + PDEBUG(D_ERR, "Error detecting sensor type"); + return -1; + } + + /* Ugh. The first two bits are the version bits, but + * the entire register value must be used. I guess OVT + * underestimated how many variants they would make. */ + if (rc == 0x00) { + sd->sensor = SEN_OV6630; + PDEBUG(D_ERR, + "WARNING: Sensor is an OV66308. Your camera may have"); + PDEBUG(D_ERR, "been misdetected in previous driver versions."); + } else if (rc == 0x01) { + sd->sensor = SEN_OV6620; + PDEBUG(D_PROBE, "Sensor is an OV6620"); + } else if (rc == 0x02) { + sd->sensor = SEN_OV6630; + PDEBUG(D_PROBE, "Sensor is an OV66308AE"); + } else if (rc == 0x03) { + sd->sensor = SEN_OV6630; + PDEBUG(D_PROBE, "Sensor is an OV66308AF"); + } else if (rc == 0x90) { + sd->sensor = SEN_OV6630; + PDEBUG(D_ERR, + "WARNING: Sensor is an OV66307. Your camera may have"); + PDEBUG(D_ERR, "been misdetected in previous driver versions."); + } else { + PDEBUG(D_ERR, "FATAL: Unknown sensor version: 0x%02x", rc); + return -1; + } + + /* Set sensor-specific vars */ + sd->maxwidth = 352; + sd->maxheight = 288; + + if (sd->sensor == SEN_OV6620) { + PDEBUG(D_PROBE, "Writing 6x20 registers"); + if (write_i2c_regvals(sd, norm_6x20, + sizeof norm_6x20 / sizeof norm_6x20[0])) + return -1; + } else { + PDEBUG(D_PROBE, "Writing 6x30 registers"); + if (write_i2c_regvals(sd, norm_6x30, + sizeof norm_6x30 / sizeof norm_6x30[0])) + return -1; + } + return 0; +} + +/* Turns on or off the LED. Only has an effect with OV511+/OV518(+)/OV519 */ +static void ov51x_led_control(struct sd *sd, int on) +{ + PDEBUG(D_STREAM, "LED (%s)", on ? "on" : "off"); + +/* if (sd->bridge == BRG_OV511PLUS) */ +/* reg_w(sd, R511_SYS_LED_CTL, on ? 1 : 0); */ +/* else if (sd->bridge == BRG_OV519) */ + reg_w_mask(sd, OV519_GPIO_DATA_OUT0, !on, 1); /* 0 / 1 */ +/* else if (sd->bclass == BCL_OV518) */ +/* reg_w_mask(sd, R518_GPIO_OUT, on ? 0x02 : 0x00, 0x02); */ +} + +/* this function is called at probe time */ +static int sd_config(struct gspca_dev *gspca_dev, + const struct usb_device_id *id) +{ + struct sd *sd = (struct sd *) gspca_dev; + struct cam *cam; + +/* (from ov519_configure) */ + static const struct ov_regvals init_519[] = { + { 0x5a, 0x6d }, /* EnableSystem */ +/* jfm trace usbsnoop3-1.txt */ +/* jfm 53 = fb */ + { 0x53, 0x9b }, + { 0x54, 0xff }, /* set bit2 to enable jpeg */ + { 0x5d, 0x03 }, + { 0x49, 0x01 }, + { 0x48, 0x00 }, + /* Set LED pin to output mode. Bit 4 must be cleared or sensor + * detection will fail. This deserves further investigation. */ + { OV519_GPIO_IO_CTRL0, 0xee }, + { 0x51, 0x0f }, /* SetUsbInit */ + { 0x51, 0x00 }, + { 0x22, 0x00 }, + /* windows reads 0x55 at this point*/ + }; + + if (write_regvals(sd, init_519, ARRAY_SIZE(init_519))) + goto error; +/* jfm: not seen in windows trace */ + if (ov519_init_compression(sd)) + goto error; + ov51x_led_control(sd, 0); /* turn LED off */ + + /* Test for 76xx */ + sd->primary_i2c_slave = OV7xx0_SID; + if (ov51x_set_slave_ids(sd, OV7xx0_SID) < 0) + goto error; + + /* The OV519 must be more aggressive about sensor detection since + * I2C write will never fail if the sensor is not present. We have + * to try to initialize the sensor to detect its presence */ + if (init_ov_sensor(sd) < 0) { + /* Test for 6xx0 */ + sd->primary_i2c_slave = OV6xx0_SID; + if (ov51x_set_slave_ids(sd, OV6xx0_SID) < 0) + goto error; + + if (init_ov_sensor(sd) < 0) { + /* Test for 8xx0 */ + sd->primary_i2c_slave = OV8xx0_SID; + if (ov51x_set_slave_ids(sd, OV8xx0_SID) < 0) + goto error; + + if (init_ov_sensor(sd) < 0) { + PDEBUG(D_ERR, + "Can't determine sensor slave IDs"); + goto error; + } else { + if (ov8xx0_configure(sd) < 0) { + PDEBUG(D_ERR, + "Failed to configure OV8xx0 sensor"); + goto error; + } + } + } else { + if (ov6xx0_configure(sd) < 0) { + PDEBUG(D_ERR, "Failed to configure OV6xx0"); + goto error; + } + } + } else { + if (ov7xx0_configure(sd) < 0) { + PDEBUG(D_ERR, "Failed to configure OV7xx0"); + goto error; + } + } + + cam = &gspca_dev->cam; + cam->epaddr = OV511_ENDPOINT_ADDRESS; + if (sd->maxwidth == 640) { + cam->cam_mode = vga_mode; + cam->nmodes = sizeof vga_mode / sizeof vga_mode[0]; + } else { + cam->cam_mode = sif_mode; + cam->nmodes = sizeof sif_mode / sizeof sif_mode[0]; + } + cam->dev_name = (char *) id->driver_info; + sd->brightness = sd_ctrls[SD_BRIGHTNESS].qctrl.default_value; + sd->contrast = sd_ctrls[SD_CONTRAST].qctrl.default_value; + sd->colors = sd_ctrls[SD_COLOR].qctrl.default_value; + return 0; +error: + PDEBUG(D_ERR, "OV519 Config failed"); + return -EBUSY; +} + +/* this function is called at open time */ +static int sd_open(struct gspca_dev *gspca_dev) +{ + return 0; +} + +/* Sets up the OV519 with the given image parameters + * + * OV519 needs a completely different approach, until we can figure out what + * the individual registers do. + * + * Do not put any sensor-specific code in here (including I2C I/O functions) + */ +static int ov519_mode_init_regs(struct sd *sd, + int width, int height) +{ + static const struct ov_regvals mode_init_519_ov7670[] = { + { 0x5d, 0x03 }, /* Turn off suspend mode */ + { 0x53, 0x9f }, /* was 9b in 1.65-1.08 */ + { 0x54, 0x0f }, /* bit2 (jpeg enable) */ + { 0xa2, 0x20 }, /* a2-a5 are undocumented */ + { 0xa3, 0x18 }, + { 0xa4, 0x04 }, + { 0xa5, 0x28 }, + { 0x37, 0x00 }, /* SetUsbInit */ + { 0x55, 0x02 }, /* 4.096 Mhz audio clock */ + /* Enable both fields, YUV Input, disable defect comp (why?) */ + { 0x20, 0x0c }, + { 0x21, 0x38 }, + { 0x22, 0x1d }, + { 0x17, 0x50 }, /* undocumented */ + { 0x37, 0x00 }, /* undocumented */ + { 0x40, 0xff }, /* I2C timeout counter */ + { 0x46, 0x00 }, /* I2C clock prescaler */ + { 0x59, 0x04 }, /* new from windrv 090403 */ + { 0xff, 0x00 }, /* undocumented */ + /* windows reads 0x55 at this point, why? */ + }; + + static const struct ov_regvals mode_init_519[] = { + { 0x5d, 0x03 }, /* Turn off suspend mode */ + { 0x53, 0x9f }, /* was 9b in 1.65-1.08 */ + { 0x54, 0x0f }, /* bit2 (jpeg enable) */ + { 0xa2, 0x20 }, /* a2-a5 are undocumented */ + { 0xa3, 0x18 }, + { 0xa4, 0x04 }, + { 0xa5, 0x28 }, + { 0x37, 0x00 }, /* SetUsbInit */ + { 0x55, 0x02 }, /* 4.096 Mhz audio clock */ + /* Enable both fields, YUV Input, disable defect comp (why?) */ + { 0x22, 0x1d }, + { 0x17, 0x50 }, /* undocumented */ + { 0x37, 0x00 }, /* undocumented */ + { 0x40, 0xff }, /* I2C timeout counter */ + { 0x46, 0x00 }, /* I2C clock prescaler */ + { 0x59, 0x04 }, /* new from windrv 090403 */ + { 0xff, 0x00 }, /* undocumented */ + /* windows reads 0x55 at this point, why? */ + }; + +/* int hi_res; */ + + PDEBUG(D_CONF, "mode init %dx%d", width, height); + +/* if (width >= 800 && height >= 600) + hi_res = 1; + else + hi_res = 0; */ + +/* if (ov51x_stop(sd) < 0) + return -EIO; */ + + /******** Set the mode ********/ + if (sd->sensor != SEN_OV7670) { + if (write_regvals(sd, mode_init_519, + ARRAY_SIZE(mode_init_519))) + return -EIO; + } else { + if (write_regvals(sd, mode_init_519_ov7670, + ARRAY_SIZE(mode_init_519_ov7670))) + return -EIO; + } + + if (sd->sensor == SEN_OV7640) { + /* Select 8-bit input mode */ + reg_w_mask(sd, OV519_CAM_DFR, 0x10, 0x10); + } + + reg_w(sd, OV519_CAM_H_SIZE, width >> 4); + reg_w(sd, OV519_CAM_V_SIZE, height >> 3); + reg_w(sd, OV519_CAM_X_OFFSETL, 0x00); + reg_w(sd, OV519_CAM_X_OFFSETH, 0x00); + reg_w(sd, OV519_CAM_Y_OFFSETL, 0x00); + reg_w(sd, OV519_CAM_Y_OFFSETH, 0x00); + reg_w(sd, OV519_CAM_DIVIDER, 0x00); + reg_w(sd, OV519_CAM_FORMAT, 0x03); /* YUV422 */ + reg_w(sd, 0x26, 0x00); /* Undocumented */ + + /******** Set the framerate ********/ + if (frame_rate > 0) + sd->frame_rate = frame_rate; + +/* FIXME: These are only valid at the max resolution. */ + sd->clockdiv = 0; + if (sd->sensor == SEN_OV7640) { + switch (sd->frame_rate) { +/*jfm: default was 30 fps */ + case 30: + reg_w(sd, 0xa4, 0x0c); + reg_w(sd, 0x23, 0xff); + break; + case 25: + reg_w(sd, 0xa4, 0x0c); + reg_w(sd, 0x23, 0x1f); + break; + case 20: + reg_w(sd, 0xa4, 0x0c); + reg_w(sd, 0x23, 0x1b); + break; + default: +/* case 15: */ + reg_w(sd, 0xa4, 0x04); + reg_w(sd, 0x23, 0xff); + sd->clockdiv = 1; + break; + case 10: + reg_w(sd, 0xa4, 0x04); + reg_w(sd, 0x23, 0x1f); + sd->clockdiv = 1; + break; + case 5: + reg_w(sd, 0xa4, 0x04); + reg_w(sd, 0x23, 0x1b); + sd->clockdiv = 1; + break; + } + } else if (sd->sensor == SEN_OV8610) { + switch (sd->frame_rate) { + default: /* 15 fps */ +/* case 15: */ + reg_w(sd, 0xa4, 0x06); + reg_w(sd, 0x23, 0xff); + break; + case 10: + reg_w(sd, 0xa4, 0x06); + reg_w(sd, 0x23, 0x1f); + break; + case 5: + reg_w(sd, 0xa4, 0x06); + reg_w(sd, 0x23, 0x1b); + break; + } + sd->clockdiv = 0; + } else if (sd->sensor == SEN_OV7670) { /* guesses, based on 7640 */ + PDEBUG(D_STREAM, "Setting framerate to %d fps", + (sd->frame_rate == 0) ? 15 : sd->frame_rate); + switch (sd->frame_rate) { + case 30: + reg_w(sd, 0xa4, 0x10); + reg_w(sd, 0x23, 0xff); + break; + case 20: + reg_w(sd, 0xa4, 0x10); + reg_w(sd, 0x23, 0x1b); + break; + default: /* 15 fps */ +/* case 15: */ + reg_w(sd, 0xa4, 0x10); + reg_w(sd, 0x23, 0xff); + sd->clockdiv = 1; + break; + } + } + +/* if (ov51x_restart(sd) < 0) + return -EIO; */ + + /* Reset it just for good measure */ +/* if (ov51x_reset(sd, OV511_RESET_NOREGS) < 0) + return -EIO; */ + return 0; +} + +static int mode_init_ov_sensor_regs(struct sd *sd, + struct ovsensor_window *win) +{ + int qvga = win->quarter; + + /******** Mode (VGA/QVGA) and sensor specific regs ********/ + switch (sd->sensor) { + case SEN_OV8610: + /* For OV8610 qvga means qsvga */ + i2c_w_mask(sd, OV7610_REG_COM_C, qvga ? (1 << 5) : 0, 1 << 5); + break; + case SEN_OV7610: + i2c_w_mask(sd, 0x14, qvga ? 0x20 : 0x00, 0x20); + break; + case SEN_OV7620: +/* i2c_w(sd, 0x2b, 0x00); */ + i2c_w_mask(sd, 0x14, qvga ? 0x20 : 0x00, 0x20); + i2c_w_mask(sd, 0x28, qvga ? 0x00 : 0x20, 0x20); + i2c_w(sd, 0x24, qvga ? 0x20 : 0x3a); + i2c_w(sd, 0x25, qvga ? 0x30 : 0x60); + i2c_w_mask(sd, 0x2d, qvga ? 0x40 : 0x00, 0x40); + i2c_w_mask(sd, 0x67, qvga ? 0xf0 : 0x90, 0xf0); + i2c_w_mask(sd, 0x74, qvga ? 0x20 : 0x00, 0x20); + break; + case SEN_OV76BE: +/* i2c_w(sd, 0x2b, 0x00); */ + i2c_w_mask(sd, 0x14, qvga ? 0x20 : 0x00, 0x20); + break; + case SEN_OV7640: +/* i2c_w(sd, 0x2b, 0x00); */ + i2c_w_mask(sd, 0x14, qvga ? 0x20 : 0x00, 0x20); + i2c_w_mask(sd, 0x28, qvga ? 0x00 : 0x20, 0x20); +/* i2c_w(sd, 0x24, qvga ? 0x20 : 0x3a); */ +/* i2c_w(sd, 0x25, qvga ? 0x30 : 0x60); */ +/* i2c_w_mask(sd, 0x2d, qvga ? 0x40 : 0x00, 0x40); */ +/* i2c_w_mask(sd, 0x67, qvga ? 0xf0 : 0x90, 0xf0); */ +/* i2c_w_mask(sd, 0x74, qvga ? 0x20 : 0x00, 0x20); */ + break; + case SEN_OV7670: + /* set COM7_FMT_VGA or COM7_FMT_QVGA + * do we need to set anything else? + * HSTART etc are set in set_ov_sensor_window itself */ + i2c_w_mask(sd, OV7670_REG_COM7, + qvga ? OV7670_COM7_FMT_QVGA : OV7670_COM7_FMT_VGA, + OV7670_COM7_FMT_MASK); + break; + case SEN_OV6620: + i2c_w_mask(sd, 0x14, qvga ? 0x20 : 0x00, 0x20); + break; + case SEN_OV6630: + i2c_w_mask(sd, 0x14, qvga ? 0x20 : 0x00, 0x20); + break; + default: + return -EINVAL; + } + + /******** Palette-specific regs ********/ +/* Need to do work here for the OV7670 */ + + if (sd->sensor == SEN_OV7610 || sd->sensor == SEN_OV76BE) { + /* not valid on the OV6620/OV7620/6630? */ + i2c_w_mask(sd, 0x0e, 0x00, 0x40); + } + + /* The OV518 needs special treatment. Although both the OV518 + * and the OV6630 support a 16-bit video bus, only the 8 bit Y + * bus is actually used. The UV bus is tied to ground. + * Therefore, the OV6630 needs to be in 8-bit multiplexed + * output mode */ + + /* OV7640 is 8-bit only */ + + if (sd->sensor != SEN_OV6630 && sd->sensor != SEN_OV7640) + i2c_w_mask(sd, 0x13, 0x00, 0x20); +/* } */ + + /******** Clock programming ********/ + /* The OV6620 needs special handling. This prevents the + * severe banding that normally occurs */ + if (sd->sensor == SEN_OV6620) { + + /* Clock down */ + i2c_w(sd, 0x2a, 0x04); + i2c_w(sd, 0x11, win->clockdiv); + i2c_w(sd, 0x2a, 0x84); + /* This next setting is critical. It seems to improve + * the gain or the contrast. The "reserved" bits seem + * to have some effect in this case. */ + i2c_w(sd, 0x2d, 0x85); + } else if (win->clockdiv >= 0) { + i2c_w(sd, 0x11, win->clockdiv); + } + + /******** Special Features ********/ +/* no evidence this is possible with OV7670, either */ + /* Test Pattern */ + if (sd->sensor != SEN_OV7640 && sd->sensor != SEN_OV7670) + i2c_w_mask(sd, 0x12, 0x00, 0x02); + + /* Enable auto white balance */ + if (sd->sensor == SEN_OV7670) + i2c_w_mask(sd, OV7670_REG_COM8, OV7670_COM8_AWB, + OV7670_COM8_AWB); + else + i2c_w_mask(sd, 0x12, 0x04, 0x04); + + /* This will go away as soon as ov51x_mode_init_sensor_regs() */ + /* is fully tested. */ + /* 7620/6620/6630? don't have register 0x35, so play it safe */ + if (sd->sensor == SEN_OV7610 || sd->sensor == SEN_OV76BE) { + if (win->width == 640 /*&& win->height == 480*/) + i2c_w(sd, 0x35, 0x9e); + else + i2c_w(sd, 0x35, 0x1e); + } + return 0; +} + +static int set_ov_sensor_window(struct sd *sd, + struct ovsensor_window *win) +{ + int hwsbase, hwebase, vwsbase, vwebase, hwscale, vwscale; + int ret, hstart, hstop, vstop, vstart; + __u8 v; + + /* The different sensor ICs handle setting up of window differently. + * IF YOU SET IT WRONG, YOU WILL GET ALL ZERO ISOC DATA FROM OV51x!! */ + switch (sd->sensor) { + case SEN_OV8610: + hwsbase = 0x1e; + hwebase = 0x1e; + vwsbase = 0x02; + vwebase = 0x02; + break; + case SEN_OV7610: + case SEN_OV76BE: + hwsbase = 0x38; + hwebase = 0x3a; + vwsbase = vwebase = 0x05; + break; + case SEN_OV6620: + case SEN_OV6630: + hwsbase = 0x38; + hwebase = 0x3a; + vwsbase = 0x05; + vwebase = 0x06; + break; + case SEN_OV7620: + hwsbase = 0x2f; /* From 7620.SET (spec is wrong) */ + hwebase = 0x2f; + vwsbase = vwebase = 0x05; + break; + case SEN_OV7640: + hwsbase = 0x1a; + hwebase = 0x1a; + vwsbase = vwebase = 0x03; + break; + case SEN_OV7670: + /*handling of OV7670 hardware sensor start and stop values + * is very odd, compared to the other OV sensors */ + vwsbase = vwebase = hwebase = hwsbase = 0x00; + break; + default: + return -EINVAL; + } + + switch (sd->sensor) { + case SEN_OV6620: + case SEN_OV6630: + if (win->quarter) { /* QCIF */ + hwscale = 0; + vwscale = 0; + } else { /* CIF */ + hwscale = 1; + vwscale = 1; /* The datasheet says 0; + * it's wrong */ + } + break; + case SEN_OV8610: + if (win->quarter) { /* QSVGA */ + hwscale = 1; + vwscale = 1; + } else { /* SVGA */ + hwscale = 2; + vwscale = 2; + } + break; + default: /* SEN_OV7xx0 */ + if (win->quarter) { /* QVGA */ + hwscale = 1; + vwscale = 0; + } else { /* VGA */ + hwscale = 2; + vwscale = 1; + } + } + + ret = mode_init_ov_sensor_regs(sd, win); + if (ret < 0) + return ret; + + if (sd->sensor == SEN_OV8610) { + i2c_w_mask(sd, 0x2d, 0x05, 0x40); + /* old 0x95, new 0x05 from windrv 090403 */ + /* bits 5-7: reserved */ + i2c_w_mask(sd, 0x28, 0x20, 0x20); + /* bit 5: progressive mode on */ + } + + /* The below is wrong for OV7670s because their window registers + * only store the high bits in 0x17 to 0x1a */ + + /* SRH Use sd->max values instead of requested win values */ + /* SCS Since we're sticking with only the max hardware widths + * for a given mode */ + /* I can hard code this for OV7670s */ + /* Yes, these numbers do look odd, but they're tested and work! */ + if (sd->sensor == SEN_OV7670) { + if (win->quarter) { /* QVGA from ov7670.c by + * Jonathan Corbet */ + hstart = 164; + hstop = 20; + vstart = 14; + vstop = 494; + } else { /* VGA */ + hstart = 158; + hstop = 14; + vstart = 10; + vstop = 490; + } + /* OV7670 hardware window registers are split across + * multiple locations */ + i2c_w(sd, OV7670_REG_HSTART, (hstart >> 3) & 0xff); + i2c_w(sd, OV7670_REG_HSTOP, (hstop >> 3) & 0xff); + v = i2c_r(sd, OV7670_REG_HREF); + v = (v & 0xc0) | ((hstop & 0x7) << 3) | (hstart & 0x07); + msleep(10); /* need to sleep between read and write to + * same reg! */ + i2c_w(sd, OV7670_REG_HREF, v); + + i2c_w(sd, OV7670_REG_VSTART, (vstart >> 2) & 0xff); + i2c_w(sd, OV7670_REG_VSTOP, (vstop >> 2) & 0xff); + v = i2c_r(sd, OV7670_REG_VREF); + v = (v & 0xc0) | ((vstop & 0x3) << 2) | (vstart & 0x03); + msleep(10); /* need to sleep between read and write to + * same reg! */ + i2c_w(sd, OV7670_REG_VREF, v); + + } else { + i2c_w(sd, 0x17, hwsbase + (win->x >> hwscale)); + i2c_w(sd, 0x18, hwebase + ((win->x + win->width) >> hwscale)); + i2c_w(sd, 0x19, vwsbase + (win->y >> vwscale)); + i2c_w(sd, 0x1a, vwebase + ((win->y + win->height) >> vwscale)); + } + return 0; +} + +static int ov_sensor_mode_setup(struct sd *sd, + int width, int height) +{ + struct ovsensor_window win; + +/* win.format = mode; */ + + /* Unless subcapture is enabled, + * center the image window and downsample + * if possible to increase the field of view */ + /* NOTE: OV518(+) and OV519 does downsampling on its own */ + win.width = width; + win.height = height; + if (width == sd->maxwidth) + win.quarter = 0; + else + win.quarter = 1; + + /* Center it */ + win.x = (win.width - width) / 2; + win.y = (win.height - height) / 2; + + /* Clock is determined by OV519 frame rate code */ + win.clockdiv = sd->clockdiv; + + PDEBUG(D_CONF, "Setting clock divider to %d", win.clockdiv); + return set_ov_sensor_window(sd, &win); +} + +/* -- start the camera -- */ +static void sd_start(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + int ret; + + + ret = ov519_mode_init_regs(sd, gspca_dev->width, gspca_dev->height); + if (ret < 0) + goto out; + ret = ov_sensor_mode_setup(sd, gspca_dev->width, gspca_dev->height); + if (ret < 0) + goto out; + + ret = ov51x_restart((struct sd *) gspca_dev); + if (ret < 0) + goto out; + PDEBUG(D_STREAM, "camera started alt: 0x%02x", gspca_dev->alt); + ov51x_led_control(sd, 1); + return; +out: + PDEBUG(D_ERR, "camera start error:%d", ret); +} + +static void sd_stopN(struct gspca_dev *gspca_dev) +{ + ov51x_stop((struct sd *) gspca_dev); + ov51x_led_control((struct sd *) gspca_dev, 0); +} + +static void sd_stop0(struct gspca_dev *gspca_dev) +{ +} + +static void sd_close(struct gspca_dev *gspca_dev) +{ +} + +static void sd_pkt_scan(struct gspca_dev *gspca_dev, + struct gspca_frame *frame, /* target */ + __u8 *data, /* isoc packet */ + int len) /* iso packet length */ +{ + /* Header of ov519 is 16 bytes: + * Byte Value Description + * 0 0xff magic + * 1 0xff magic + * 2 0xff magic + * 3 0xXX 0x50 = SOF, 0x51 = EOF + * 9 0xXX 0x01 initial frame without data, + * 0x00 standard frame with image + * 14 Lo in EOF: length of image data / 8 + * 15 Hi + */ + + if (data[0] == 0xff && data[1] == 0xff && data[2] == 0xff) { + switch (data[3]) { + case 0x50: /* start of frame */ +#define HDRSZ 16 + data += HDRSZ; + len -= HDRSZ; +#undef HDRSZ + if (data[0] == 0xff || data[1] == 0xd8) + gspca_frame_add(gspca_dev, FIRST_PACKET, frame, + data, len); + else + gspca_dev->last_packet_type = DISCARD_PACKET; + return; + case 0x51: /* end of frame */ + if (data[9] != 0) + gspca_dev->last_packet_type = DISCARD_PACKET; + gspca_frame_add(gspca_dev, LAST_PACKET, frame, + data, 0); + return; + } + } + + /* intermediate packet */ + gspca_frame_add(gspca_dev, INTER_PACKET, frame, + data, len); +} + +/* -- management routines -- */ + +static void setbrightness(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + int val; +/* int was_streaming; */ + + val = sd->brightness; + PDEBUG(D_CONF, "brightness:%d", val); +/* was_streaming = gspca_dev->streaming; + * if (was_streaming) + * ov51x_stop(sd); */ + switch (sd->sensor) { + case SEN_OV8610: + case SEN_OV7610: + case SEN_OV76BE: + case SEN_OV6620: + case SEN_OV6630: + case SEN_OV7640: + i2c_w(sd, OV7610_REG_BRT, val); + break; + case SEN_OV7620: + /* 7620 doesn't like manual changes when in auto mode */ +/*fixme + * if (!sd->auto_brt) */ + i2c_w(sd, OV7610_REG_BRT, val); + break; + case SEN_OV7670: +/*jfm - from windblows + * i2c_w_mask(sd, OV7670_REG_COM8, 0, OV7670_COM8_AEC); */ + i2c_w(sd, OV7670_REG_BRIGHT, ov7670_abs_to_sm(val)); + break; + } +/* if (was_streaming) + * ov51x_restart(sd); */ +} + +static void setcontrast(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + int val; +/* int was_streaming; */ + + val = sd->contrast; + PDEBUG(D_CONF, "contrast:%d", val); +/* was_streaming = gspca_dev->streaming; + if (was_streaming) + ov51x_stop(sd); */ + switch (sd->sensor) { + case SEN_OV7610: + case SEN_OV6620: + i2c_w(sd, OV7610_REG_CNT, val); + break; + case SEN_OV6630: + i2c_w_mask(sd, OV7610_REG_CNT, val >> 4, 0x0f); + case SEN_OV8610: { + static const __u8 ctab[] = { + 0x03, 0x09, 0x0b, 0x0f, 0x53, 0x6f, 0x35, 0x7f + }; + + /* Use Y gamma control instead. Bit 0 enables it. */ + i2c_w(sd, 0x64, ctab[val >> 5]); + break; + } + case SEN_OV7620: { + static const __u8 ctab[] = { + 0x01, 0x05, 0x09, 0x11, 0x15, 0x35, 0x37, 0x57, + 0x5b, 0xa5, 0xa7, 0xc7, 0xc9, 0xcf, 0xef, 0xff + }; + + /* Use Y gamma control instead. Bit 0 enables it. */ + i2c_w(sd, 0x64, ctab[val >> 4]); + break; + } + case SEN_OV7640: + /* Use gain control instead. */ + i2c_w(sd, OV7610_REG_GAIN, val >> 2); + break; + case SEN_OV7670: + /* check that this isn't just the same as ov7610 */ + i2c_w(sd, OV7670_REG_CONTRAS, val >> 1); + break; + } +/* if (was_streaming) + ov51x_restart(sd); */ +} + +static void setcolors(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + int val; +/* int was_streaming; */ + + val = sd->colors; + PDEBUG(D_CONF, "saturation:%d", val); +/* was_streaming = gspca_dev->streaming; + if (was_streaming) + ov51x_stop(sd); */ + switch (sd->sensor) { + case SEN_OV8610: + case SEN_OV7610: + case SEN_OV76BE: + case SEN_OV6620: + case SEN_OV6630: + i2c_w(sd, OV7610_REG_SAT, val); + break; + case SEN_OV7620: + /* Use UV gamma control instead. Bits 0 & 7 are reserved. */ +/* rc = ov_i2c_write(sd->dev, 0x62, (val >> 9) & 0x7e); + if (rc < 0) + goto out; */ + i2c_w(sd, OV7610_REG_SAT, val); + break; + case SEN_OV7640: + i2c_w(sd, OV7610_REG_SAT, val & 0xf0); + break; + case SEN_OV7670: + /* supported later once I work out how to do it + * transparently fail now! */ + /* set REG_COM13 values for UV sat auto mode */ + break; + } +/* if (was_streaming) + ov51x_restart(sd); */ +} + +static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->brightness = val; + setbrightness(gspca_dev); + return 0; +} + +static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + *val = sd->brightness; + return 0; +} + +static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->contrast = val; + setcontrast(gspca_dev); + return 0; +} + +static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + *val = sd->contrast; + return 0; +} + +static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->colors = val; + setcolors(gspca_dev); + return 0; +} + +static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + *val = sd->colors; + return 0; +} + +/* sub-driver description */ +static const struct sd_desc sd_desc = { + .name = MODULE_NAME, + .ctrls = sd_ctrls, + .nctrls = ARRAY_SIZE(sd_ctrls), + .config = sd_config, + .open = sd_open, + .start = sd_start, + .stopN = sd_stopN, + .stop0 = sd_stop0, + .close = sd_close, + .pkt_scan = sd_pkt_scan, +}; + +/* -- module initialisation -- */ +#define DVNM(name) .driver_info = (kernel_ulong_t) name +static const __devinitdata struct usb_device_id device_table[] = { + {USB_DEVICE(0x041e, 0x4052), DVNM("Creative Live! VISTA IM")}, + {USB_DEVICE(0x041e, 0x405f), DVNM("Creative Live! VISTA VF0330")}, + {USB_DEVICE(0x041e, 0x4060), DVNM("Creative Live! VISTA VF0350")}, + {USB_DEVICE(0x041e, 0x4061), DVNM("Creative Live! VISTA VF0400")}, + {USB_DEVICE(0x041e, 0x4064), DVNM("Creative Live! VISTA VF0420")}, + {USB_DEVICE(0x041e, 0x4068), DVNM("Creative Live! VISTA VF0470")}, + {USB_DEVICE(0x045e, 0x028c), DVNM("Microsoft xbox cam")}, + {USB_DEVICE(0x054c, 0x0154), DVNM("Sonny toy4")}, + {USB_DEVICE(0x054c, 0x0155), DVNM("Sonny toy5")}, + {USB_DEVICE(0x05a9, 0x0519), DVNM("OmniVision")}, + {USB_DEVICE(0x05a9, 0x0530), DVNM("OmniVision")}, + {USB_DEVICE(0x05a9, 0x4519), DVNM("OmniVision")}, + {USB_DEVICE(0x05a9, 0x8519), DVNM("OmniVision")}, + {} +}; +#undef DVNAME +MODULE_DEVICE_TABLE(usb, device_table); + +/* -- device connect -- */ +static int sd_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd), + THIS_MODULE); +} + +static struct usb_driver sd_driver = { + .name = MODULE_NAME, + .id_table = device_table, + .probe = sd_probe, + .disconnect = gspca_disconnect, +}; + +/* -- module insert / remove -- */ +static int __init sd_mod_init(void) +{ + if (usb_register(&sd_driver) < 0) + return -1; + PDEBUG(D_PROBE, "v%s registered", version); + return 0; +} +static void __exit sd_mod_exit(void) +{ + usb_deregister(&sd_driver); + PDEBUG(D_PROBE, "deregistered"); +} + +module_init(sd_mod_init); +module_exit(sd_mod_exit); + +module_param(frame_rate, int, 0644); +MODULE_PARM_DESC(frame_rate, "Frame rate (5, 10, 15, 20 or 30 fps)"); + diff --git a/drivers/media/video/gspca/pac207.c b/drivers/media/video/gspca/pac207.c new file mode 100644 index 000000000000..fa7abc411090 --- /dev/null +++ b/drivers/media/video/gspca/pac207.c @@ -0,0 +1,622 @@ +/* + * Pixart PAC207BCA library + * + * Copyright (C) 2008 Hans de Goede <j.w.r.degoede@hhs.nl> + * Copyright (C) 2005 Thomas Kaiser thomas@kaiser-linux.li + * Copyleft (C) 2005 Michel Xhaard mxhaard@magic.fr + * + * V4L2 by Jean-Francois Moine <http://moinejf.free.fr> + * + * 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 + * + */ + +#define MODULE_NAME "pac207" + +#include "gspca.h" + +#define DRIVER_VERSION_NUMBER KERNEL_VERSION(2, 1, 7) +static const char version[] = "2.1.7"; + +MODULE_AUTHOR("Hans de Goede <j.w.r.degoede@hhs.nl>"); +MODULE_DESCRIPTION("Pixart PAC207"); +MODULE_LICENSE("GPL"); + +#define PAC207_CTRL_TIMEOUT 100 /* ms */ + +#define PAC207_BRIGHTNESS_MIN 0 +#define PAC207_BRIGHTNESS_MAX 255 +#define PAC207_BRIGHTNESS_DEFAULT 4 /* power on default: 4 */ + +/* An exposure value of 4 also works (3 does not) but then we need to lower + the compression balance setting when in 352x288 mode, otherwise the usb + bandwidth is not enough and packets get dropped resulting in corrupt + frames. The problem with this is that when the compression balance gets + lowered below 0x80, the pac207 starts using a different compression + algorithm for some lines, these lines get prefixed with a 0x2dd2 prefix + and currently we do not know how to decompress these lines, so for now + we use a minimum exposure value of 5 */ +#define PAC207_EXPOSURE_MIN 5 +#define PAC207_EXPOSURE_MAX 26 +#define PAC207_EXPOSURE_DEFAULT 5 /* power on default: 3 ?? */ +#define PAC207_EXPOSURE_KNEE 11 /* 4 = 30 fps, 11 = 8, 15 = 6 */ + +#define PAC207_GAIN_MIN 0 +#define PAC207_GAIN_MAX 31 +#define PAC207_GAIN_DEFAULT 9 /* power on default: 9 */ +#define PAC207_GAIN_KNEE 20 + +#define PAC207_AUTOGAIN_DEADZONE 30 +/* We calculating the autogain at the end of the transfer of a frame, at this + moment a frame with the old settings is being transmitted, and a frame is + being captured with the old settings. So if we adjust the autogain we must + ignore atleast the 2 next frames for the new settings to come into effect + before doing any other adjustments */ +#define PAC207_AUTOGAIN_IGNORE_FRAMES 3 + +/* specific webcam descriptor */ +struct sd { + struct gspca_dev gspca_dev; /* !! must be the first item */ + + u8 mode; + + u8 brightness; + u8 exposure; + u8 autogain; + u8 gain; + + u8 sof_read; + u8 header_read; + u8 autogain_ignore_frames; + + atomic_t avg_lum; +}; + +/* V4L2 controls supported by the driver */ +static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val); +static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val); +static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val); +static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val); +static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val); +static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val); +static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val); +static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val); + +static struct ctrl sd_ctrls[] = { +#define SD_BRIGHTNESS 0 + { + { + .id = V4L2_CID_BRIGHTNESS, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Brightness", + .minimum = PAC207_BRIGHTNESS_MIN, + .maximum = PAC207_BRIGHTNESS_MAX, + .step = 1, + .default_value = PAC207_BRIGHTNESS_DEFAULT, + .flags = 0, + }, + .set = sd_setbrightness, + .get = sd_getbrightness, + }, +#define SD_EXPOSURE 1 + { + { + .id = V4L2_CID_EXPOSURE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "exposure", + .minimum = PAC207_EXPOSURE_MIN, + .maximum = PAC207_EXPOSURE_MAX, + .step = 1, + .default_value = PAC207_EXPOSURE_DEFAULT, + .flags = 0, + }, + .set = sd_setexposure, + .get = sd_getexposure, + }, +#define SD_AUTOGAIN 2 + { + { + .id = V4L2_CID_AUTOGAIN, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Auto Gain", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 1, + .flags = 0, + }, + .set = sd_setautogain, + .get = sd_getautogain, + }, +#define SD_GAIN 3 + { + { + .id = V4L2_CID_GAIN, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "gain", + .minimum = PAC207_GAIN_MIN, + .maximum = PAC207_GAIN_MAX, + .step = 1, + .default_value = PAC207_GAIN_DEFAULT, + .flags = 0, + }, + .set = sd_setgain, + .get = sd_getgain, + }, +}; + +static struct v4l2_pix_format sif_mode[] = { + {176, 144, V4L2_PIX_FMT_PAC207, V4L2_FIELD_NONE, + .bytesperline = 176, + .sizeimage = (176 + 2) * 144, + /* uncompressed, add 2 bytes / line for line header */ + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = 1}, + {352, 288, V4L2_PIX_FMT_PAC207, V4L2_FIELD_NONE, + .bytesperline = 352, + /* compressed, but only when needed (not compressed + when the framerate is low) */ + .sizeimage = (352 + 2) * 288, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = 0}, +}; + +static const __u8 pac207_sensor_init[][8] = { + {0x10, 0x12, 0x0d, 0x12, 0x0c, 0x01, 0x29, 0xf0}, + {0x00, 0x64, 0x64, 0x64, 0x04, 0x10, 0xf0, 0x30}, + {0x00, 0x00, 0x00, 0x70, 0xa0, 0xf8, 0x00, 0x00}, + {0x00, 0x00, 0x32, 0x00, 0x96, 0x00, 0xa2, 0x02}, + {0x32, 0x00, 0x96, 0x00, 0xA2, 0x02, 0xaf, 0x00}, +}; + + /* 48 reg_72 Rate Control end BalSize_4a =0x36 */ +static const __u8 PacReg72[] = { 0x00, 0x00, 0x36, 0x00 }; + +static const unsigned char pac207_sof_marker[5] = + { 0xff, 0xff, 0x00, 0xff, 0x96 }; + +static int pac207_write_regs(struct gspca_dev *gspca_dev, u16 index, + const u8 *buffer, u16 length) +{ + struct usb_device *udev = gspca_dev->dev; + int err; + + memcpy(gspca_dev->usb_buf, buffer, length); + + err = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x01, + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE, + 0x00, index, + gspca_dev->usb_buf, length, PAC207_CTRL_TIMEOUT); + if (err < 0) + PDEBUG(D_ERR, + "Failed to write registers to index 0x%04X, error %d)", + index, err); + + return err; +} + + +int pac207_write_reg(struct gspca_dev *gspca_dev, u16 index, u16 value) +{ + struct usb_device *udev = gspca_dev->dev; + int err; + + err = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x00, + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE, + value, index, NULL, 0, PAC207_CTRL_TIMEOUT); + if (err) + PDEBUG(D_ERR, "Failed to write a register (index 0x%04X," + " value 0x%02X, error %d)", index, value, err); + + return err; +} + + +int pac207_read_reg(struct gspca_dev *gspca_dev, u16 index) +{ + struct usb_device *udev = gspca_dev->dev; + int res; + + res = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), 0x00, + USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_INTERFACE, + 0x00, index, + gspca_dev->usb_buf, 1, PAC207_CTRL_TIMEOUT); + if (res < 0) { + PDEBUG(D_ERR, + "Failed to read a register (index 0x%04X, error %d)", + index, res); + return res; + } + + return gspca_dev->usb_buf[0]; +} + +/* this function is called at probe time */ +static int sd_config(struct gspca_dev *gspca_dev, + const struct usb_device_id *id) +{ + struct sd *sd = (struct sd *) gspca_dev; + struct cam *cam; + u8 idreg[2]; + + idreg[0] = pac207_read_reg(gspca_dev, 0x0000); + idreg[1] = pac207_read_reg(gspca_dev, 0x0001); + idreg[0] = ((idreg[0] & 0x0F) << 4) | ((idreg[1] & 0xf0) >> 4); + idreg[1] = idreg[1] & 0x0f; + PDEBUG(D_PROBE, "Pixart Sensor ID 0x%02X Chips ID 0x%02X", + idreg[0], idreg[1]); + + if (idreg[0] != 0x27) { + PDEBUG(D_PROBE, "Error invalid sensor ID!"); + return -ENODEV; + } + + pac207_write_reg(gspca_dev, 0x41, 0x00); + /* Bit_0=Image Format, + * Bit_1=LED, + * Bit_2=Compression test mode enable */ + pac207_write_reg(gspca_dev, 0x0f, 0x00); /* Power Control */ + pac207_write_reg(gspca_dev, 0x11, 0x30); /* Analog Bias */ + + PDEBUG(D_PROBE, + "Pixart PAC207BCA Image Processor and Control Chip detected" + " (vid/pid 0x%04X:0x%04X)", id->idVendor, id->idProduct); + + cam = &gspca_dev->cam; + cam->dev_name = (char *) id->driver_info; + cam->epaddr = 0x05; + cam->cam_mode = sif_mode; + cam->nmodes = ARRAY_SIZE(sif_mode); + sd->brightness = PAC207_BRIGHTNESS_DEFAULT; + sd->exposure = PAC207_EXPOSURE_DEFAULT; + sd->gain = PAC207_GAIN_DEFAULT; + + return 0; +} + +/* this function is called at open time */ +static int sd_open(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->autogain = 1; + return 0; +} + +/* -- start the camera -- */ +static void sd_start(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + __u8 mode; + + pac207_write_reg(gspca_dev, 0x0f, 0x10); /* Power control (Bit 6-0) */ + pac207_write_regs(gspca_dev, 0x0002, pac207_sensor_init[0], 8); + pac207_write_regs(gspca_dev, 0x000a, pac207_sensor_init[1], 8); + pac207_write_regs(gspca_dev, 0x0012, pac207_sensor_init[2], 8); + pac207_write_regs(gspca_dev, 0x0040, pac207_sensor_init[3], 8); + pac207_write_regs(gspca_dev, 0x0042, pac207_sensor_init[4], 8); + pac207_write_regs(gspca_dev, 0x0048, PacReg72, 4); + + /* Compression Balance */ + if (gspca_dev->width == 176) + pac207_write_reg(gspca_dev, 0x4a, 0xff); + else + pac207_write_reg(gspca_dev, 0x4a, 0x88); + pac207_write_reg(gspca_dev, 0x4b, 0x00); /* Sram test value */ + pac207_write_reg(gspca_dev, 0x08, sd->brightness); + + /* PGA global gain (Bit 4-0) */ + pac207_write_reg(gspca_dev, 0x0e, sd->gain); + pac207_write_reg(gspca_dev, 0x02, sd->exposure); /* PXCK = 12MHz /n */ + + mode = 0x02; /* Image Format (Bit 0), LED (1), Compr. test mode (2) */ + if (gspca_dev->width == 176) { /* 176x144 */ + mode |= 0x01; + PDEBUG(D_STREAM, "pac207_start mode 176x144"); + } else { /* 352x288 */ + PDEBUG(D_STREAM, "pac207_start mode 352x288"); + } + pac207_write_reg(gspca_dev, 0x41, mode); + + pac207_write_reg(gspca_dev, 0x13, 0x01); /* Bit 0, auto clear */ + pac207_write_reg(gspca_dev, 0x1c, 0x01); /* not documented */ + msleep(10); + pac207_write_reg(gspca_dev, 0x40, 0x01); /* Start ISO pipe */ + + sd->sof_read = 0; + sd->autogain_ignore_frames = 0; + atomic_set(&sd->avg_lum, -1); +} + +static void sd_stopN(struct gspca_dev *gspca_dev) +{ + pac207_write_reg(gspca_dev, 0x40, 0x00); /* Stop ISO pipe */ + pac207_write_reg(gspca_dev, 0x41, 0x00); /* Turn of LED */ + pac207_write_reg(gspca_dev, 0x0f, 0x00); /* Power Control */ +} + +static void sd_stop0(struct gspca_dev *gspca_dev) +{ +} + +/* this function is called at close time */ +static void sd_close(struct gspca_dev *gspca_dev) +{ +} + +static void pac207_do_auto_gain(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + int avg_lum = atomic_read(&sd->avg_lum); + + if (avg_lum == -1) + return; + + if (sd->autogain_ignore_frames > 0) + sd->autogain_ignore_frames--; + else if (gspca_auto_gain_n_exposure(gspca_dev, avg_lum, + 100 + sd->brightness / 2, PAC207_AUTOGAIN_DEADZONE, + PAC207_GAIN_KNEE, PAC207_EXPOSURE_KNEE)) + sd->autogain_ignore_frames = PAC207_AUTOGAIN_IGNORE_FRAMES; +} + +static unsigned char *pac207_find_sof(struct gspca_dev *gspca_dev, + unsigned char *m, int len) +{ + struct sd *sd = (struct sd *) gspca_dev; + int i; + + /* Search for the SOF marker (fixed part) in the header */ + for (i = 0; i < len; i++) { + if (m[i] == pac207_sof_marker[sd->sof_read]) { + sd->sof_read++; + if (sd->sof_read == sizeof(pac207_sof_marker)) { + PDEBUG(D_STREAM, + "SOF found, bytes to analyze: %u." + " Frame starts at byte #%u", + len, i + 1); + sd->sof_read = 0; + return m + i + 1; + } + } else { + sd->sof_read = 0; + } + } + + return NULL; +} + +static void sd_pkt_scan(struct gspca_dev *gspca_dev, + struct gspca_frame *frame, + __u8 *data, + int len) +{ + struct sd *sd = (struct sd *) gspca_dev; + unsigned char *sof; + + sof = pac207_find_sof(gspca_dev, data, len); + if (sof) { + int n; + + /* finish decoding current frame */ + n = sof - data; + if (n > sizeof pac207_sof_marker) + n -= sizeof pac207_sof_marker; + else + n = 0; + frame = gspca_frame_add(gspca_dev, LAST_PACKET, frame, + data, n); + sd->header_read = 0; + gspca_frame_add(gspca_dev, FIRST_PACKET, frame, NULL, 0); + len -= sof - data; + data = sof; + } + if (sd->header_read < 11) { + int needed; + + /* get average lumination from frame header (byte 5) */ + if (sd->header_read < 5) { + needed = 5 - sd->header_read; + if (len >= needed) + atomic_set(&sd->avg_lum, data[needed - 1]); + } + /* skip the rest of the header */ + needed = 11 - sd->header_read; + if (len <= needed) { + sd->header_read += len; + return; + } + data += needed; + len -= needed; + sd->header_read = 11; + } + + gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len); +} + +static void setbrightness(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + + pac207_write_reg(gspca_dev, 0x08, sd->brightness); + pac207_write_reg(gspca_dev, 0x13, 0x01); /* Bit 0, auto clear */ + pac207_write_reg(gspca_dev, 0x1c, 0x01); /* not documented */ +} + +static void setexposure(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + + pac207_write_reg(gspca_dev, 0x02, sd->exposure); + pac207_write_reg(gspca_dev, 0x13, 0x01); /* Bit 0, auto clear */ + pac207_write_reg(gspca_dev, 0x1c, 0x01); /* not documented */ +} + +static void setgain(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + + pac207_write_reg(gspca_dev, 0x0e, sd->gain); + pac207_write_reg(gspca_dev, 0x13, 0x01); /* Bit 0, auto clear */ + pac207_write_reg(gspca_dev, 0x1c, 0x01); /* not documented */ +} + +static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->brightness = val; + if (gspca_dev->streaming) + setbrightness(gspca_dev); + return 0; +} + +static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + *val = sd->brightness; + return 0; +} + +static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->exposure = val; + if (gspca_dev->streaming) + setexposure(gspca_dev); + return 0; +} + +static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + *val = sd->exposure; + return 0; +} + +static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->gain = val; + if (gspca_dev->streaming) + setgain(gspca_dev); + return 0; +} + +static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + *val = sd->gain; + return 0; +} + +static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->autogain = val; + /* when switching to autogain set defaults to make sure + we are on a valid point of the autogain gain / + exposure knee graph, and give this change time to + take effect before doing autogain. */ + if (sd->autogain) { + sd->exposure = PAC207_EXPOSURE_DEFAULT; + sd->gain = PAC207_GAIN_DEFAULT; + if (gspca_dev->streaming) { + sd->autogain_ignore_frames = + PAC207_AUTOGAIN_IGNORE_FRAMES; + setexposure(gspca_dev); + setgain(gspca_dev); + } + } + + return 0; +} + +static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + *val = sd->autogain; + return 0; +} + +/* sub-driver description */ +static const struct sd_desc sd_desc = { + .name = MODULE_NAME, + .ctrls = sd_ctrls, + .nctrls = ARRAY_SIZE(sd_ctrls), + .config = sd_config, + .open = sd_open, + .start = sd_start, + .stopN = sd_stopN, + .stop0 = sd_stop0, + .close = sd_close, + .dq_callback = pac207_do_auto_gain, + .pkt_scan = sd_pkt_scan, +}; + +/* -- module initialisation -- */ +#define DVNM(name) .driver_info = (kernel_ulong_t) name +static const __devinitdata struct usb_device_id device_table[] = { + {USB_DEVICE(0x041e, 0x4028), DVNM("Creative Webcam Vista Plus")}, + {USB_DEVICE(0x093a, 0x2460), DVNM("Q-Tec Webcam 100")}, + {USB_DEVICE(0x093a, 0x2463), DVNM("Philips spc200nc pac207")}, + {USB_DEVICE(0x093a, 0x2464), DVNM("Labtec Webcam 1200")}, + {USB_DEVICE(0x093a, 0x2468), DVNM("PAC207")}, + {USB_DEVICE(0x093a, 0x2470), DVNM("Genius GF112")}, + {USB_DEVICE(0x093a, 0x2471), DVNM("Genius VideoCam GE111")}, + {USB_DEVICE(0x093a, 0x2472), DVNM("Genius VideoCam GE110")}, + {USB_DEVICE(0x2001, 0xf115), DVNM("D-Link DSB-C120")}, + {} +}; +MODULE_DEVICE_TABLE(usb, device_table); + +/* -- device connect -- */ +static int sd_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd), + THIS_MODULE); +} + +static struct usb_driver sd_driver = { + .name = MODULE_NAME, + .id_table = device_table, + .probe = sd_probe, + .disconnect = gspca_disconnect, +}; + +/* -- module insert / remove -- */ +static int __init sd_mod_init(void) +{ + if (usb_register(&sd_driver) < 0) + return -1; + PDEBUG(D_PROBE, "v%s registered", version); + return 0; +} +static void __exit sd_mod_exit(void) +{ + usb_deregister(&sd_driver); + PDEBUG(D_PROBE, "deregistered"); +} + +module_init(sd_mod_init); +module_exit(sd_mod_exit); diff --git a/drivers/media/video/gspca/pac7311.c b/drivers/media/video/gspca/pac7311.c new file mode 100644 index 000000000000..5c052e31be4a --- /dev/null +++ b/drivers/media/video/gspca/pac7311.c @@ -0,0 +1,760 @@ +/* + * Pixart PAC7311 library + * Copyright (C) 2005 Thomas Kaiser thomas@kaiser-linux.li + * + * V4L2 by Jean-Francois Moine <http://moinejf.free.fr> + * + * 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 + * 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 + */ + +#define MODULE_NAME "pac7311" + +#include "gspca.h" + +#define DRIVER_VERSION_NUMBER KERNEL_VERSION(2, 1, 7) +static const char version[] = "2.1.7"; + +MODULE_AUTHOR("Thomas Kaiser thomas@kaiser-linux.li"); +MODULE_DESCRIPTION("Pixart PAC7311"); +MODULE_LICENSE("GPL"); + +/* specific webcam descriptor */ +struct sd { + struct gspca_dev gspca_dev; /* !! must be the first item */ + + int avg_lum; + + unsigned char brightness; + unsigned char contrast; + unsigned char colors; + unsigned char autogain; + + char ffseq; + signed char ag_cnt; +#define AG_CNT_START 13 +}; + +/* V4L2 controls supported by the driver */ +static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val); +static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val); +static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val); +static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val); +static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val); +static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val); +static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val); +static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val); + +static struct ctrl sd_ctrls[] = { + { + { + .id = V4L2_CID_BRIGHTNESS, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Brightness", + .minimum = 0, +#define BRIGHTNESS_MAX 0x20 + .maximum = BRIGHTNESS_MAX, + .step = 1, +#define BRIGHTNESS_DEF 0x10 + .default_value = BRIGHTNESS_DEF, + }, + .set = sd_setbrightness, + .get = sd_getbrightness, + }, + { + { + .id = V4L2_CID_CONTRAST, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Contrast", + .minimum = 0, + .maximum = 255, + .step = 1, +#define CONTRAST_DEF 127 + .default_value = CONTRAST_DEF, + }, + .set = sd_setcontrast, + .get = sd_getcontrast, + }, + { + { + .id = V4L2_CID_SATURATION, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Color", + .minimum = 0, + .maximum = 255, + .step = 1, +#define COLOR_DEF 127 + .default_value = COLOR_DEF, + }, + .set = sd_setcolors, + .get = sd_getcolors, + }, + { + { + .id = V4L2_CID_AUTOGAIN, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Auto Gain", + .minimum = 0, + .maximum = 1, + .step = 1, +#define AUTOGAIN_DEF 1 + .default_value = AUTOGAIN_DEF, + }, + .set = sd_setautogain, + .get = sd_getautogain, + }, +}; + +static struct v4l2_pix_format vga_mode[] = { + {160, 120, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, + .bytesperline = 160, + .sizeimage = 160 * 120 * 3 / 8 + 590, + .colorspace = V4L2_COLORSPACE_JPEG, + .priv = 2}, + {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, + .bytesperline = 320, + .sizeimage = 320 * 240 * 3 / 8 + 590, + .colorspace = V4L2_COLORSPACE_JPEG, + .priv = 1}, + {640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, + .bytesperline = 640, + .sizeimage = 640 * 480 * 3 / 8 + 590, + .colorspace = V4L2_COLORSPACE_JPEG, + .priv = 0}, +}; + +#define PAC7311_JPEG_HEADER_SIZE (sizeof pac7311_jpeg_header) /* (594) */ + +static const __u8 pac7311_jpeg_header[] = { + 0xff, 0xd8, + 0xff, 0xe0, 0x00, 0x03, 0x20, + 0xff, 0xc0, 0x00, 0x11, 0x08, + 0x01, 0xe0, /* 12: height */ + 0x02, 0x80, /* 14: width */ + 0x03, /* 16 */ + 0x01, 0x21, 0x00, + 0x02, 0x11, 0x01, + 0x03, 0x11, 0x01, + 0xff, 0xdb, 0x00, 0x84, + 0x00, 0x10, 0x0b, 0x0c, 0x0e, 0x0c, 0x0a, 0x10, 0x0e, 0x0d, + 0x0e, 0x12, 0x11, 0x10, 0x13, 0x18, 0x28, 0x1a, 0x18, 0x16, + 0x16, 0x18, 0x31, 0x23, 0x25, 0x1d, 0x28, 0x3a, 0x33, 0x3d, + 0x3c, 0x39, 0x33, 0x38, 0x37, 0x40, 0x48, 0x5c, 0x4e, 0x40, + 0x44, 0x57, 0x45, 0x37, 0x38, 0x50, 0x6d, 0x51, 0x57, 0x5f, + 0x62, 0x67, 0x68, 0x67, 0x3e, 0x4d, 0x71, 0x79, 0x70, 0x64, + 0x78, 0x5c, 0x65, 0x67, 0x63, 0x01, 0x11, 0x12, 0x12, 0x18, + 0x15, 0x18, 0x2f, 0x1a, 0x1a, 0x2f, 0x63, 0x42, 0x38, 0x42, + 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, + 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, + 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, + 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, + 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, + 0xff, 0xc4, 0x01, 0xa2, 0x00, 0x00, 0x01, 0x05, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, + 0x09, 0x0a, 0x0b, 0x10, 0x00, 0x02, 0x01, 0x03, 0x03, 0x02, + 0x04, 0x03, 0x05, 0x05, 0x04, 0x04, 0x00, 0x00, 0x01, 0x7d, + 0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12, 0x21, 0x31, + 0x41, 0x06, 0x13, 0x51, 0x61, 0x07, 0x22, 0x71, 0x14, 0x32, + 0x81, 0x91, 0xa1, 0x08, 0x23, 0x42, 0xb1, 0xc1, 0x15, 0x52, + 0xd1, 0xf0, 0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0a, 0x16, + 0x17, 0x18, 0x19, 0x1a, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, + 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x43, 0x44, 0x45, + 0x46, 0x47, 0x48, 0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, + 0x58, 0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, + 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x83, + 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x92, 0x93, 0x94, + 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, + 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, + 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, + 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, + 0xd9, 0xda, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, + 0xe9, 0xea, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, + 0xf9, 0xfa, 0x01, 0x00, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, + 0x0b, 0x11, 0x00, 0x02, 0x01, 0x02, 0x04, 0x04, 0x03, 0x04, + 0x07, 0x05, 0x04, 0x04, 0x00, 0x01, 0x02, 0x77, 0x00, 0x01, + 0x02, 0x03, 0x11, 0x04, 0x05, 0x21, 0x31, 0x06, 0x12, 0x41, + 0x51, 0x07, 0x61, 0x71, 0x13, 0x22, 0x32, 0x81, 0x08, 0x14, + 0x42, 0x91, 0xa1, 0xb1, 0xc1, 0x09, 0x23, 0x33, 0x52, 0xf0, + 0x15, 0x62, 0x72, 0xd1, 0x0a, 0x16, 0x24, 0x34, 0xe1, 0x25, + 0xf1, 0x17, 0x18, 0x19, 0x1a, 0x26, 0x27, 0x28, 0x29, 0x2a, + 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, + 0x47, 0x48, 0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, + 0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, + 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x82, 0x83, + 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x92, 0x93, 0x94, + 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, + 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, + 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, + 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, + 0xd9, 0xda, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, + 0xea, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, + 0xff, 0xda, 0x00, 0x0c, 0x03, 0x01, 0x00, 0x02, 0x11, 0x03, + 0x11, 0x00, 0x3f, 0x00 +}; + +static void reg_w_buf(struct gspca_dev *gspca_dev, + __u16 index, + const char *buffer, __u16 len) +{ + memcpy(gspca_dev->usb_buf, buffer, len); + usb_control_msg(gspca_dev->dev, + usb_sndctrlpipe(gspca_dev->dev, 0), + 1, /* request */ + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + 0, /* value */ + index, gspca_dev->usb_buf, len, + 500); +} + +static __u8 reg_r(struct gspca_dev *gspca_dev, + __u16 index) +{ + usb_control_msg(gspca_dev->dev, + usb_rcvctrlpipe(gspca_dev->dev, 0), + 0, /* request */ + USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + 0, /* value */ + index, gspca_dev->usb_buf, 1, + 500); + return gspca_dev->usb_buf[0]; +} + +static void reg_w(struct gspca_dev *gspca_dev, + __u16 index, + __u8 value) +{ + gspca_dev->usb_buf[0] = value; + usb_control_msg(gspca_dev->dev, + usb_sndctrlpipe(gspca_dev->dev, 0), + 0, /* request */ + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + value, index, gspca_dev->usb_buf, 1, + 500); +} + +/* this function is called at probe time */ +static int sd_config(struct gspca_dev *gspca_dev, + const struct usb_device_id *id) +{ + struct sd *sd = (struct sd *) gspca_dev; + struct cam *cam; + + PDEBUG(D_CONF, "Find Sensor PAC7311"); + reg_w(gspca_dev, 0x78, 0x40); /* Bit_0=start stream, Bit_7=LED */ + reg_w(gspca_dev, 0x78, 0x40); /* Bit_0=start stream, Bit_7=LED */ + reg_w(gspca_dev, 0x78, 0x44); /* Bit_0=start stream, Bit_7=LED */ + reg_w(gspca_dev, 0xff, 0x04); + reg_w(gspca_dev, 0x27, 0x80); + reg_w(gspca_dev, 0x28, 0xca); + reg_w(gspca_dev, 0x29, 0x53); + reg_w(gspca_dev, 0x2a, 0x0e); + reg_w(gspca_dev, 0xff, 0x01); + reg_w(gspca_dev, 0x3e, 0x20); + + cam = &gspca_dev->cam; + cam->dev_name = (char *) id->driver_info; + cam->epaddr = 0x05; + cam->cam_mode = vga_mode; + cam->nmodes = ARRAY_SIZE(vga_mode); + + sd->brightness = BRIGHTNESS_DEF; + sd->contrast = CONTRAST_DEF; + sd->colors = COLOR_DEF; + sd->autogain = AUTOGAIN_DEF; + return 0; +} + +static void setbrightness(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + int brightness; + +/*jfm: inverted?*/ + brightness = BRIGHTNESS_MAX - sd->brightness; + reg_w(gspca_dev, 0xff, 0x04); +/* reg_w(gspca_dev, 0x0e, 0x00); */ + reg_w(gspca_dev, 0x0f, brightness); + /* load registers to sensor (Bit 0, auto clear) */ + reg_w(gspca_dev, 0x11, 0x01); + PDEBUG(D_CONF|D_STREAM, "brightness: %i", brightness); +} + +static void setcontrast(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + + reg_w(gspca_dev, 0xff, 0x01); + reg_w(gspca_dev, 0x80, sd->contrast); + /* load registers to sensor (Bit 0, auto clear) */ + reg_w(gspca_dev, 0x11, 0x01); + PDEBUG(D_CONF|D_STREAM, "contrast: %i", sd->contrast); +} + +static void setcolors(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + + reg_w(gspca_dev, 0xff, 0x01); + reg_w(gspca_dev, 0x10, sd->colors); + /* load registers to sensor (Bit 0, auto clear) */ + reg_w(gspca_dev, 0x11, 0x01); + PDEBUG(D_CONF|D_STREAM, "color: %i", sd->colors); +} + +/* this function is called at open time */ +static int sd_open(struct gspca_dev *gspca_dev) +{ + reg_w(gspca_dev, 0x78, 0x00); /* Turn on LED */ + return 0; +} + +static void sd_start(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + + reg_w(gspca_dev, 0xff, 0x01); + reg_w_buf(gspca_dev, 0x0002, "\x48\x0a\x40\x08\x00\x00\x08\x00", 8); + reg_w_buf(gspca_dev, 0x000a, "\x06\xff\x11\xff\x5a\x30\x90\x4c", 8); + reg_w_buf(gspca_dev, 0x0012, "\x00\x07\x00\x0a\x10\x00\xa0\x10", 8); + reg_w_buf(gspca_dev, 0x001a, "\x02\x00\x00\x00\x00\x0b\x01\x00", 8); + reg_w_buf(gspca_dev, 0x0022, "\x00\x00\x00\x00\x00\x00\x00\x00", 8); + reg_w_buf(gspca_dev, 0x002a, "\x00\x00\x00", 3); + reg_w_buf(gspca_dev, 0x003e, "\x00\x00\x78\x52\x4a\x52\x78\x6e", 8); + reg_w_buf(gspca_dev, 0x0046, "\x48\x46\x48\x6e\x5f\x49\x42\x49", 8); + reg_w_buf(gspca_dev, 0x004e, "\x5f\x5f\x49\x42\x49\x5f\x6e\x48", 8); + reg_w_buf(gspca_dev, 0x0056, "\x46\x48\x6e\x78\x52\x4a\x52\x78", 8); + reg_w_buf(gspca_dev, 0x005e, "\x00\x00\x09\x1b\x34\x49\x5c\x9b", 8); + reg_w_buf(gspca_dev, 0x0066, "\xd0\xff", 2); + reg_w_buf(gspca_dev, 0x0078, "\x44\x00\xf2\x01\x01\x80", 6); + reg_w_buf(gspca_dev, 0x007f, "\x2a\x1c\x00\xc8\x02\x58\x03\x84", 8); + reg_w_buf(gspca_dev, 0x0087, "\x12\x00\x1a\x04\x08\x0c\x10\x14", 8); + reg_w_buf(gspca_dev, 0x008f, "\x18\x20", 2); + reg_w_buf(gspca_dev, 0x0096, "\x01\x08\x04", 3); + reg_w_buf(gspca_dev, 0x00a0, "\x44\x44\x44\x04", 4); + reg_w_buf(gspca_dev, 0x00f0, "\x01\x00\x00\x00\x22\x00\x20\x00", 8); + reg_w_buf(gspca_dev, 0x00f8, "\x3f\x00\x0a\x01\x00", 5); + + reg_w(gspca_dev, 0xff, 0x04); + reg_w(gspca_dev, 0x02, 0x04); + reg_w(gspca_dev, 0x03, 0x54); + reg_w(gspca_dev, 0x04, 0x07); + reg_w(gspca_dev, 0x05, 0x2b); + reg_w(gspca_dev, 0x06, 0x09); + reg_w(gspca_dev, 0x07, 0x0f); + reg_w(gspca_dev, 0x08, 0x09); + reg_w(gspca_dev, 0x09, 0x00); + reg_w(gspca_dev, 0x0c, 0x07); + reg_w(gspca_dev, 0x0d, 0x00); + reg_w(gspca_dev, 0x0e, 0x00); + reg_w(gspca_dev, 0x0f, 0x62); + reg_w(gspca_dev, 0x10, 0x08); + reg_w(gspca_dev, 0x12, 0x07); + reg_w(gspca_dev, 0x13, 0x00); + reg_w(gspca_dev, 0x14, 0x00); + reg_w(gspca_dev, 0x15, 0x00); + reg_w(gspca_dev, 0x16, 0x00); + reg_w(gspca_dev, 0x17, 0x00); + reg_w(gspca_dev, 0x18, 0x00); + reg_w(gspca_dev, 0x19, 0x00); + reg_w(gspca_dev, 0x1a, 0x00); + reg_w(gspca_dev, 0x1b, 0x03); + reg_w(gspca_dev, 0x1c, 0xa0); + reg_w(gspca_dev, 0x1d, 0x01); + reg_w(gspca_dev, 0x1e, 0xf4); + reg_w(gspca_dev, 0x21, 0x00); + reg_w(gspca_dev, 0x22, 0x08); + reg_w(gspca_dev, 0x24, 0x03); + reg_w(gspca_dev, 0x26, 0x00); + reg_w(gspca_dev, 0x27, 0x01); + reg_w(gspca_dev, 0x28, 0xca); + reg_w(gspca_dev, 0x29, 0x10); + reg_w(gspca_dev, 0x2a, 0x06); + reg_w(gspca_dev, 0x2b, 0x78); + reg_w(gspca_dev, 0x2c, 0x00); + reg_w(gspca_dev, 0x2d, 0x00); + reg_w(gspca_dev, 0x2e, 0x00); + reg_w(gspca_dev, 0x2f, 0x00); + reg_w(gspca_dev, 0x30, 0x23); + reg_w(gspca_dev, 0x31, 0x28); + reg_w(gspca_dev, 0x32, 0x04); + reg_w(gspca_dev, 0x33, 0x11); + reg_w(gspca_dev, 0x34, 0x00); + reg_w(gspca_dev, 0x35, 0x00); + reg_w(gspca_dev, 0x11, 0x01); + setcontrast(gspca_dev); + setbrightness(gspca_dev); + setcolors(gspca_dev); + + /* set correct resolution */ + switch (gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv) { + case 2: /* 160x120 */ + reg_w(gspca_dev, 0xff, 0x04); + reg_w(gspca_dev, 0x02, 0x03); + reg_w(gspca_dev, 0xff, 0x01); + reg_w(gspca_dev, 0x08, 0x09); + reg_w(gspca_dev, 0x17, 0x20); + reg_w(gspca_dev, 0x1b, 0x00); +/* reg_w(gspca_dev, 0x80, 0x69); */ + reg_w(gspca_dev, 0x87, 0x10); + break; + case 1: /* 320x240 */ + reg_w(gspca_dev, 0xff, 0x04); + reg_w(gspca_dev, 0x02, 0x03); + reg_w(gspca_dev, 0xff, 0x01); + reg_w(gspca_dev, 0x08, 0x09); + reg_w(gspca_dev, 0x17, 0x30); +/* reg_w(gspca_dev, 0x80, 0x3f); */ + reg_w(gspca_dev, 0x87, 0x11); + break; + case 0: /* 640x480 */ + reg_w(gspca_dev, 0xff, 0x04); + reg_w(gspca_dev, 0x02, 0x03); + reg_w(gspca_dev, 0xff, 0x01); + reg_w(gspca_dev, 0x08, 0x08); + reg_w(gspca_dev, 0x17, 0x00); +/* reg_w(gspca_dev, 0x80, 0x1c); */ + reg_w(gspca_dev, 0x87, 0x12); + break; + } + + /* start stream */ + reg_w(gspca_dev, 0xff, 0x01); + reg_w(gspca_dev, 0x78, 0x04); + reg_w(gspca_dev, 0x78, 0x05); + + if (sd->autogain) { + sd->ag_cnt = AG_CNT_START; + sd->avg_lum = 0; + } else { + sd->ag_cnt = -1; + } +} + +static void sd_stopN(struct gspca_dev *gspca_dev) +{ + reg_w(gspca_dev, 0xff, 0x04); + reg_w(gspca_dev, 0x27, 0x80); + reg_w(gspca_dev, 0x28, 0xca); + reg_w(gspca_dev, 0x29, 0x53); + reg_w(gspca_dev, 0x2a, 0x0e); + reg_w(gspca_dev, 0xff, 0x01); + reg_w(gspca_dev, 0x3e, 0x20); + reg_w(gspca_dev, 0x78, 0x04); /* Bit_0=start stream, Bit_7=LED */ + reg_w(gspca_dev, 0x78, 0x44); /* Bit_0=start stream, Bit_7=LED */ + reg_w(gspca_dev, 0x78, 0x44); /* Bit_0=start stream, Bit_7=LED */ +} + +static void sd_stop0(struct gspca_dev *gspca_dev) +{ +} + +/* this function is called at close time */ +static void sd_close(struct gspca_dev *gspca_dev) +{ + reg_w(gspca_dev, 0xff, 0x04); + reg_w(gspca_dev, 0x27, 0x80); + reg_w(gspca_dev, 0x28, 0xca); + reg_w(gspca_dev, 0x29, 0x53); + reg_w(gspca_dev, 0x2a, 0x0e); + reg_w(gspca_dev, 0xff, 0x01); + reg_w(gspca_dev, 0x3e, 0x20); + reg_w(gspca_dev, 0x78, 0x04); /* Bit_0=start stream, Bit_7=LED */ + reg_w(gspca_dev, 0x78, 0x44); /* Bit_0=start stream, Bit_7=LED */ + reg_w(gspca_dev, 0x78, 0x44); /* Bit_0=start stream, Bit_7=LED */ +} + +static void setautogain(struct gspca_dev *gspca_dev, int luma) +{ + int luma_mean = 128; + int luma_delta = 20; + __u8 spring = 5; + int Gbright; + + Gbright = reg_r(gspca_dev, 0x02); + PDEBUG(D_FRAM, "luma mean %d", luma); + if (luma < luma_mean - luma_delta || + luma > luma_mean + luma_delta) { + Gbright += (luma_mean - luma) >> spring; + if (Gbright > 0x1a) + Gbright = 0x1a; + else if (Gbright < 4) + Gbright = 4; + PDEBUG(D_FRAM, "gbright %d", Gbright); + reg_w(gspca_dev, 0xff, 0x04); + reg_w(gspca_dev, 0x0f, Gbright); + /* load registers to sensor (Bit 0, auto clear) */ + reg_w(gspca_dev, 0x11, 0x01); + } +} + +static void sd_pkt_scan(struct gspca_dev *gspca_dev, + struct gspca_frame *frame, /* target */ + __u8 *data, /* isoc packet */ + int len) /* iso packet length */ +{ + struct sd *sd = (struct sd *) gspca_dev; + unsigned char tmpbuf[4]; + int i, p, ffseq; + +/* if (len < 5) { */ + if (len < 6) { +/* gspca_dev->last_packet_type = DISCARD_PACKET; */ + return; + } + + ffseq = sd->ffseq; + + for (p = 0; p < len - 6; p++) { + if ((data[0 + p] == 0xff) + && (data[1 + p] == 0xff) + && (data[2 + p] == 0x00) + && (data[3 + p] == 0xff) + && (data[4 + p] == 0x96)) { + + /* start of frame */ + if (sd->ag_cnt >= 0 && p > 28) { + sd->avg_lum += data[p - 23]; + if (--sd->ag_cnt < 0) { + sd->ag_cnt = AG_CNT_START; + setautogain(gspca_dev, + sd->avg_lum / AG_CNT_START); + sd->avg_lum = 0; + } + } + + /* copy the end of data to the current frame */ + frame = gspca_frame_add(gspca_dev, LAST_PACKET, frame, + data, p); + + /* put the JPEG header in the new frame */ + gspca_frame_add(gspca_dev, FIRST_PACKET, frame, + (unsigned char *) pac7311_jpeg_header, + 12); + tmpbuf[0] = gspca_dev->height >> 8; + tmpbuf[1] = gspca_dev->height & 0xff; + tmpbuf[2] = gspca_dev->width >> 8; + tmpbuf[3] = gspca_dev->width & 0xff; + gspca_frame_add(gspca_dev, INTER_PACKET, frame, + tmpbuf, 4); + gspca_frame_add(gspca_dev, INTER_PACKET, frame, + (unsigned char *) &pac7311_jpeg_header[16], + PAC7311_JPEG_HEADER_SIZE - 16); + + data += p + 7; + len -= p + 7; + ffseq = 0; + break; + } + } + + /* remove the 'ff ff ff xx' sequences */ + switch (ffseq) { + case 3: + data += 1; + len -= 1; + break; + case 2: + if (data[0] == 0xff) { + data += 2; + len -= 2; + frame->data_end -= 2; + } + break; + case 1: + if (data[0] == 0xff + && data[1] == 0xff) { + data += 3; + len -= 3; + frame->data_end -= 1; + } + break; + } + for (i = 0; i < len - 4; i++) { + if (data[i] == 0xff + && data[i + 1] == 0xff + && data[i + 2] == 0xff) { + memmove(&data[i], &data[i + 4], len - i - 4); + len -= 4; + } + } + ffseq = 0; + if (data[len - 4] == 0xff) { + if (data[len - 3] == 0xff + && data[len - 2] == 0xff) { + len -= 4; + } + } else if (data[len - 3] == 0xff) { + if (data[len - 2] == 0xff + && data[len - 1] == 0xff) + ffseq = 3; + } else if (data[len - 2] == 0xff) { + if (data[len - 1] == 0xff) + ffseq = 2; + } else if (data[len - 1] == 0xff) + ffseq = 1; + sd->ffseq = ffseq; + gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len); +} + +static void getbrightness(struct gspca_dev *gspca_dev) +{ +/* sd->brightness = reg_r(gspca_dev, 0x08); + return sd->brightness; */ +/* PDEBUG(D_CONF, "Called pac7311_getbrightness: Not implemented yet"); */ +} + + + +static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->brightness = val; + if (gspca_dev->streaming) + setbrightness(gspca_dev); + return 0; +} + +static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + getbrightness(gspca_dev); + *val = sd->brightness; + return 0; +} + +static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->contrast = val; + if (gspca_dev->streaming) + setcontrast(gspca_dev); + return 0; +} + +static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + +/* getcontrast(gspca_dev); */ + *val = sd->contrast; + return 0; +} + +static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->colors = val; + if (gspca_dev->streaming) + setcolors(gspca_dev); + return 0; +} + +static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + +/* getcolors(gspca_dev); */ + *val = sd->colors; + return 0; +} + +static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->autogain = val; + if (val) { + sd->ag_cnt = AG_CNT_START; + sd->avg_lum = 0; + } else { + sd->ag_cnt = -1; + } + return 0; +} + +static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + *val = sd->autogain; + return 0; +} + +/* sub-driver description */ +static struct sd_desc sd_desc = { + .name = MODULE_NAME, + .ctrls = sd_ctrls, + .nctrls = ARRAY_SIZE(sd_ctrls), + .config = sd_config, + .open = sd_open, + .start = sd_start, + .stopN = sd_stopN, + .stop0 = sd_stop0, + .close = sd_close, + .pkt_scan = sd_pkt_scan, +}; + +/* -- module initialisation -- */ +#define DVNM(name) .driver_info = (kernel_ulong_t) name +static __devinitdata struct usb_device_id device_table[] = { + {USB_DEVICE(0x093a, 0x2600), DVNM("Typhoon")}, + {USB_DEVICE(0x093a, 0x2601), DVNM("Philips SPC610NC")}, + {USB_DEVICE(0x093a, 0x2603), DVNM("PAC7312")}, + {USB_DEVICE(0x093a, 0x2608), DVNM("Trust WB-3300p")}, + {USB_DEVICE(0x093a, 0x260e), DVNM("Gigaware VGA PC Camera")}, + /* and also ', Trust WB-3350p, SIGMA cam 2350' */ + {USB_DEVICE(0x093a, 0x260f), DVNM("SnakeCam")}, + {USB_DEVICE(0x093a, 0x2621), DVNM("PAC731x")}, + {} +}; +MODULE_DEVICE_TABLE(usb, device_table); + +/* -- device connect -- */ +static int sd_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd), + THIS_MODULE); +} + +static struct usb_driver sd_driver = { + .name = MODULE_NAME, + .id_table = device_table, + .probe = sd_probe, + .disconnect = gspca_disconnect, +}; + +/* -- module insert / remove -- */ +static int __init sd_mod_init(void) +{ + if (usb_register(&sd_driver) < 0) + return -1; + PDEBUG(D_PROBE, "v%s registered", version); + return 0; +} +static void __exit sd_mod_exit(void) +{ + usb_deregister(&sd_driver); + PDEBUG(D_PROBE, "deregistered"); +} + +module_init(sd_mod_init); +module_exit(sd_mod_exit); diff --git a/drivers/media/video/gspca/sonixb.c b/drivers/media/video/gspca/sonixb.c new file mode 100644 index 000000000000..dbeebe8625c5 --- /dev/null +++ b/drivers/media/video/gspca/sonixb.c @@ -0,0 +1,1477 @@ +/* + * sonix sn9c102 (bayer) library + * Copyright (C) 2003 2004 Michel Xhaard mxhaard@magic.fr + * Add Pas106 Stefano Mozzi (C) 2004 + * + * V4L2 by Jean-Francois Moine <http://moinejf.free.fr> + * + * 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 + * 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 + */ + +#define MODULE_NAME "sonixb" + +#include "gspca.h" + +#define DRIVER_VERSION_NUMBER KERNEL_VERSION(2, 1, 8) +static const char version[] = "2.1.8"; + +MODULE_AUTHOR("Michel Xhaard <mxhaard@users.sourceforge.net>"); +MODULE_DESCRIPTION("GSPCA/SN9C102 USB Camera Driver"); +MODULE_LICENSE("GPL"); + +/* specific webcam descriptor */ +struct sd { + struct gspca_dev gspca_dev; /* !! must be the first item */ + + struct sd_desc sd_desc; /* our nctrls differ dependend upon the + sensor, so we use a per cam copy */ + atomic_t avg_lum; + + unsigned char gain; + unsigned char exposure; + unsigned char brightness; + unsigned char autogain; + unsigned char autogain_ignore_frames; + unsigned char freq; /* light freq filter setting */ + unsigned char saturation; + unsigned char hue; + unsigned char contrast; + + unsigned char fr_h_sz; /* size of frame header */ + char sensor; /* Type of image sensor chip */ +#define SENSOR_HV7131R 0 +#define SENSOR_OV6650 1 +#define SENSOR_OV7630 2 +#define SENSOR_OV7630_3 3 +#define SENSOR_PAS106 4 +#define SENSOR_PAS202 5 +#define SENSOR_TAS5110 6 +#define SENSOR_TAS5130CXX 7 + char sensor_has_gain; + __u8 sensor_addr; +}; + +#define COMP2 0x8f +#define COMP 0xc7 /* 0x87 //0x07 */ +#define COMP1 0xc9 /* 0x89 //0x09 */ + +#define MCK_INIT 0x63 +#define MCK_INIT1 0x20 /*fixme: Bayer - 0x50 for JPEG ??*/ + +#define SYS_CLK 0x04 + +/* We calculate the autogain at the end of the transfer of a frame, at this + moment a frame with the old settings is being transmitted, and a frame is + being captured with the old settings. So if we adjust the autogain we must + ignore atleast the 2 next frames for the new settings to come into effect + before doing any other adjustments */ +#define AUTOGAIN_IGNORE_FRAMES 3 +#define AUTOGAIN_DEADZONE 1000 +#define DESIRED_AVG_LUM 7000 + +/* V4L2 controls supported by the driver */ +static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val); +static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val); +static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val); +static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val); +static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val); +static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val); +static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val); +static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val); +static int sd_setfreq(struct gspca_dev *gspca_dev, __s32 val); +static int sd_getfreq(struct gspca_dev *gspca_dev, __s32 *val); +static int sd_setsaturation(struct gspca_dev *gspca_dev, __s32 val); +static int sd_getsaturation(struct gspca_dev *gspca_dev, __s32 *val); +static int sd_sethue(struct gspca_dev *gspca_dev, __s32 val); +static int sd_gethue(struct gspca_dev *gspca_dev, __s32 *val); +static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val); +static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val); + +static struct ctrl sd_ctrls[] = { + { + { + .id = V4L2_CID_BRIGHTNESS, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Brightness", + .minimum = 0, + .maximum = 255, + .step = 1, +#define BRIGHTNESS_DEF 127 + .default_value = BRIGHTNESS_DEF, + }, + .set = sd_setbrightness, + .get = sd_getbrightness, + }, + { + { + .id = V4L2_CID_GAIN, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Gain", + .minimum = 0, + .maximum = 255, + .step = 1, +#define GAIN_DEF 127 +#define GAIN_KNEE 200 + .default_value = GAIN_DEF, + }, + .set = sd_setgain, + .get = sd_getgain, + }, + { + { + .id = V4L2_CID_EXPOSURE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Exposure", +#define EXPOSURE_DEF 16 /* 32 ms / 30 fps */ +#define EXPOSURE_KNEE 50 /* 100 ms / 10 fps */ + .minimum = 0, + .maximum = 255, + .step = 1, + .default_value = EXPOSURE_DEF, + .flags = 0, + }, + .set = sd_setexposure, + .get = sd_getexposure, + }, + { + { + .id = V4L2_CID_AUTOGAIN, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Automatic Gain (and Exposure)", + .minimum = 0, + .maximum = 1, + .step = 1, +#define AUTOGAIN_DEF 1 + .default_value = AUTOGAIN_DEF, + .flags = 0, + }, + .set = sd_setautogain, + .get = sd_getautogain, + }, + { + { + .id = V4L2_CID_POWER_LINE_FREQUENCY, + .type = V4L2_CTRL_TYPE_MENU, + .name = "Light frequency filter", + .minimum = 0, + .maximum = 2, /* 0: 0, 1: 50Hz, 2:60Hz */ + .step = 1, +#define FREQ_DEF 1 + .default_value = FREQ_DEF, + }, + .set = sd_setfreq, + .get = sd_getfreq, + }, + { + { + .id = V4L2_CID_SATURATION, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Saturation", + .minimum = 0, + .maximum = 255, + .step = 1, +#define SATURATION_DEF 127 + .default_value = SATURATION_DEF, + }, + .set = sd_setsaturation, + .get = sd_getsaturation, + }, + { + { + .id = V4L2_CID_HUE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Hue", + .minimum = 0, + .maximum = 255, + .step = 1, +#define HUE_DEF 127 + .default_value = HUE_DEF, + }, + .set = sd_sethue, + .get = sd_gethue, + }, + { + { + .id = V4L2_CID_CONTRAST, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Contrast", + .minimum = 0, + .maximum = 255, + .step = 1, +#define CONTRAST_DEF 127 + .default_value = CONTRAST_DEF, + }, + .set = sd_setcontrast, + .get = sd_getcontrast, + }, +}; + +static struct v4l2_pix_format vga_mode[] = { + {160, 120, V4L2_PIX_FMT_SN9C10X, V4L2_FIELD_NONE, + .bytesperline = 160, + .sizeimage = 160 * 120, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = 2}, + {320, 240, V4L2_PIX_FMT_SN9C10X, V4L2_FIELD_NONE, + .bytesperline = 320, + .sizeimage = 320 * 240, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = 1}, + {640, 480, V4L2_PIX_FMT_SN9C10X, V4L2_FIELD_NONE, + .bytesperline = 640, + .sizeimage = 640 * 480, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = 0}, +}; +static struct v4l2_pix_format sif_mode[] = { + {176, 144, V4L2_PIX_FMT_SN9C10X, V4L2_FIELD_NONE, + .bytesperline = 176, + .sizeimage = 176 * 144, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = 1}, + {352, 288, V4L2_PIX_FMT_SN9C10X, V4L2_FIELD_NONE, + .bytesperline = 352, + .sizeimage = 352 * 288, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = 0}, +}; + +static const __u8 probe_ov7630[] = {0x08, 0x44}; + +static const __u8 initHv7131[] = { + 0x46, 0x77, 0x00, 0x04, 0x00, 0x00, 0x00, 0x80, 0x11, 0x00, 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, 0x00, 0x03, 0x01, 0x00, /* shift from 0x02 0x01 0x00 */ + 0x28, 0x1e, 0x60, 0x8a, 0x20, + 0x1d, 0x10, 0x02, 0x03, 0x0f, 0x0c +}; +static const __u8 hv7131_sensor_init[][8] = { + {0xc0, 0x11, 0x31, 0x38, 0x2a, 0x2e, 0x00, 0x10}, + {0xa0, 0x11, 0x01, 0x08, 0x2a, 0x2e, 0x00, 0x10}, + {0xb0, 0x11, 0x20, 0x00, 0xd0, 0x2e, 0x00, 0x10}, + {0xc0, 0x11, 0x25, 0x03, 0x0e, 0x28, 0x00, 0x16}, + {0xa0, 0x11, 0x30, 0x10, 0x0e, 0x28, 0x00, 0x15}, +}; +static const __u8 initOv6650[] = { + 0x44, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, + 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x02, 0x01, 0x0a, 0x16, 0x12, 0x68, 0x0b, + 0x10, 0x1d, 0x10, 0x00, 0x06, 0x1f, 0x00 +}; +static const __u8 ov6650_sensor_init[][8] = +{ + /* Bright, contrast, etc are set througth SCBB interface. + * AVCAP on win2 do not send any data on this controls. */ + /* Anyway, some registers appears to alter bright and constrat */ + + /* Reset sensor */ + {0xa0, 0x60, 0x12, 0x80, 0x00, 0x00, 0x00, 0x10}, + /* Set clock register 0x11 low nibble is clock divider */ + {0xd0, 0x60, 0x11, 0xc0, 0x1b, 0x18, 0xc1, 0x10}, + /* Next some unknown stuff */ + {0xb0, 0x60, 0x15, 0x00, 0x02, 0x18, 0xc1, 0x10}, +/* {0xa0, 0x60, 0x1b, 0x01, 0x02, 0x18, 0xc1, 0x10}, + * THIS SET GREEN SCREEN + * (pixels could be innverted in decode kind of "brg", + * but blue wont be there. Avoid this data ... */ + {0xd0, 0x60, 0x26, 0x01, 0x14, 0xd8, 0xa4, 0x10}, /* format out? */ + {0xd0, 0x60, 0x26, 0x01, 0x14, 0xd8, 0xa4, 0x10}, + {0xa0, 0x60, 0x30, 0x3d, 0x0A, 0xd8, 0xa4, 0x10}, + /* Enable rgb brightness control */ + {0xa0, 0x60, 0x61, 0x08, 0x00, 0x00, 0x00, 0x10}, + /* HDG: Note windows uses the line below, which sets both register 0x60 + and 0x61 I believe these registers of the ov6650 are identical as + those of the ov7630, because if this is true the windows settings + add a bit additional red gain and a lot additional blue gain, which + matches my findings that the windows settings make blue much too + blue and red a little too red. + {0xb0, 0x60, 0x60, 0x66, 0x68, 0xd8, 0xa4, 0x10}, */ + /* Some more unknown stuff */ + {0xa0, 0x60, 0x68, 0x04, 0x68, 0xd8, 0xa4, 0x10}, + {0xd0, 0x60, 0x17, 0x24, 0xd6, 0x04, 0x94, 0x10}, /* Clipreg */ +}; + +static const __u8 initOv7630[] = { + 0x04, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, /* r01 .. r08 */ + 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* r09 .. r10 */ + 0x00, 0x02, 0x01, 0x0a, /* r11 .. r14 */ + 0x28, 0x1e, /* H & V sizes r15 .. r16 */ + 0x68, COMP1, MCK_INIT1, /* r17 .. r19 */ + 0x1d, 0x10, 0x02, 0x03, 0x0f, 0x0c /* r1a .. r1f */ +}; +static const __u8 initOv7630_3[] = { + 0x44, 0x44, 0x00, 0x1a, 0x20, 0x20, 0x20, 0x80, /* r01 .. r08 */ + 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, /* r09 .. r10 */ + 0x00, 0x01, 0x01, 0x0a, /* r11 .. r14 */ + 0x28, 0x1e, /* H & V sizes r15 .. r16 */ + 0x68, 0x8f, MCK_INIT1, /* r17 .. r19 */ + 0x1d, 0x10, 0x02, 0x03, 0x0f, 0x0c, 0x00, /* r1a .. r20 */ + 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x80, /* r21 .. r28 */ + 0x90, 0xa0, 0xb0, 0xc0, 0xd0, 0xe0, 0xf0, 0xff /* r29 .. r30 */ +}; +static const __u8 ov7630_sensor_init_com[][8] = { + {0xa0, 0x21, 0x12, 0x80, 0x00, 0x00, 0x00, 0x10}, + {0xb0, 0x21, 0x01, 0x77, 0x3a, 0x00, 0x00, 0x10}, +/* {0xd0, 0x21, 0x12, 0x7c, 0x01, 0x80, 0x34, 0x10}, jfm */ + {0xd0, 0x21, 0x12, 0x1c, 0x00, 0x80, 0x34, 0x10}, /* jfm */ + {0xa0, 0x21, 0x1b, 0x04, 0x00, 0x80, 0x34, 0x10}, + {0xa0, 0x21, 0x20, 0x44, 0x00, 0x80, 0x34, 0x10}, + {0xa0, 0x21, 0x23, 0xee, 0x00, 0x80, 0x34, 0x10}, + {0xd0, 0x21, 0x26, 0xa0, 0x9a, 0xa0, 0x30, 0x10}, + {0xb0, 0x21, 0x2a, 0x80, 0x00, 0xa0, 0x30, 0x10}, + {0xb0, 0x21, 0x2f, 0x3d, 0x24, 0xa0, 0x30, 0x10}, + {0xa0, 0x21, 0x32, 0x86, 0x24, 0xa0, 0x30, 0x10}, + {0xb0, 0x21, 0x60, 0xa9, 0x4a, 0xa0, 0x30, 0x10}, +/* {0xb0, 0x21, 0x60, 0xa9, 0x42, 0xa0, 0x30, 0x10}, * jfm */ + {0xa0, 0x21, 0x65, 0x00, 0x42, 0xa0, 0x30, 0x10}, + {0xa0, 0x21, 0x69, 0x38, 0x42, 0xa0, 0x30, 0x10}, + {0xc0, 0x21, 0x6f, 0x88, 0x0b, 0x00, 0x30, 0x10}, + {0xc0, 0x21, 0x74, 0x21, 0x8e, 0x00, 0x30, 0x10}, + {0xa0, 0x21, 0x7d, 0xf7, 0x8e, 0x00, 0x30, 0x10}, + {0xd0, 0x21, 0x17, 0x1c, 0xbd, 0x06, 0xf6, 0x10}, +}; +static const __u8 ov7630_sensor_init[][8] = { + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* delay 200ms */ + {0xa0, 0x21, 0x11, 0x01, 0xbd, 0x06, 0xf6, 0x10}, /* jfm */ + {0xa0, 0x21, 0x10, 0x57, 0xbd, 0x06, 0xf6, 0x16}, + {0xa0, 0x21, 0x76, 0x02, 0xbd, 0x06, 0xf6, 0x16}, + {0xa0, 0x21, 0x00, 0x10, 0xbd, 0x06, 0xf6, 0x15}, /* gain */ +}; +static const __u8 ov7630_sensor_init_3[][8] = { + {0xa0, 0x21, 0x2a, 0xa0, 0x00, 0x00, 0x00, 0x10}, + {0xa0, 0x21, 0x2a, 0x80, 0x00, 0x00, 0x00, 0x10}, +}; + +static const __u8 initPas106[] = { + 0x04, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x81, 0x40, 0x00, 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, 0x00, 0x05, 0x01, 0x00, + 0x16, 0x12, 0x28, COMP1, MCK_INIT1, + 0x18, 0x10, 0x04, 0x03, 0x11, 0x0c +}; +/* compression 0x86 mckinit1 0x2b */ +static const __u8 pas106_data[][2] = { + {0x02, 0x04}, /* Pixel Clock Divider 6 */ + {0x03, 0x13}, /* Frame Time MSB */ +/* {0x03, 0x12}, * Frame Time MSB */ + {0x04, 0x06}, /* Frame Time LSB */ +/* {0x04, 0x05}, * Frame Time LSB */ + {0x05, 0x65}, /* Shutter Time Line Offset */ +/* {0x05, 0x6d}, * Shutter Time Line Offset */ +/* {0x06, 0xb1}, * Shutter Time Pixel Offset */ + {0x06, 0xcd}, /* Shutter Time Pixel Offset */ + {0x07, 0xc1}, /* Black Level Subtract Sign */ +/* {0x07, 0x00}, * Black Level Subtract Sign */ + {0x08, 0x06}, /* Black Level Subtract Level */ + {0x08, 0x06}, /* Black Level Subtract Level */ +/* {0x08, 0x01}, * Black Level Subtract Level */ + {0x09, 0x05}, /* Color Gain B Pixel 5 a */ + {0x0a, 0x04}, /* Color Gain G1 Pixel 1 5 */ + {0x0b, 0x04}, /* Color Gain G2 Pixel 1 0 5 */ + {0x0c, 0x05}, /* Color Gain R Pixel 3 1 */ + {0x0d, 0x00}, /* Color GainH Pixel */ + {0x0e, 0x0e}, /* Global Gain */ + {0x0f, 0x00}, /* Contrast */ + {0x10, 0x06}, /* H&V synchro polarity */ + {0x11, 0x06}, /* ?default */ + {0x12, 0x06}, /* DAC scale */ + {0x14, 0x02}, /* ?default */ + {0x13, 0x01}, /* Validate Settings */ +}; +static const __u8 initPas202[] = { + 0x44, 0x44, 0x21, 0x30, 0x00, 0x00, 0x00, 0x80, 0x40, 0x00, 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, 0x00, 0x07, 0x03, 0x0a, /* 6 */ + 0x28, 0x1e, 0x28, 0x89, 0x30, + 0x00, 0x00, 0x02, 0x03, 0x0f, 0x0c +}; +static const __u8 pas202_sensor_init[][8] = { + {0xa0, 0x40, 0x02, 0x03, 0x00, 0x00, 0x00, 0x10}, + {0xd0, 0x40, 0x04, 0x07, 0x34, 0x00, 0x09, 0x10}, + {0xd0, 0x40, 0x08, 0x01, 0x00, 0x00, 0x01, 0x10}, + {0xd0, 0x40, 0x0C, 0x00, 0x0C, 0x00, 0x32, 0x10}, + {0xd0, 0x40, 0x10, 0x00, 0x01, 0x00, 0x63, 0x10}, + {0xa0, 0x40, 0x15, 0x70, 0x01, 0x00, 0x63, 0x10}, + {0xa0, 0x40, 0x18, 0x00, 0x01, 0x00, 0x63, 0x10}, + {0xa0, 0x40, 0x11, 0x01, 0x01, 0x00, 0x63, 0x10}, + {0xa0, 0x40, 0x03, 0x56, 0x01, 0x00, 0x63, 0x10}, + {0xa0, 0x40, 0x11, 0x01, 0x01, 0x00, 0x63, 0x10}, + {0xb0, 0x40, 0x04, 0x07, 0x2a, 0x00, 0x63, 0x10}, + {0xb0, 0x40, 0x0e, 0x00, 0x3d, 0x00, 0x63, 0x10}, + + {0xa0, 0x40, 0x11, 0x01, 0x3d, 0x00, 0x63, 0x16}, + {0xa0, 0x40, 0x10, 0x08, 0x3d, 0x00, 0x63, 0x15}, + {0xa0, 0x40, 0x02, 0x04, 0x3d, 0x00, 0x63, 0x16}, + {0xa0, 0x40, 0x11, 0x01, 0x3d, 0x00, 0x63, 0x16}, + {0xb0, 0x40, 0x0e, 0x00, 0x31, 0x00, 0x63, 0x16}, + {0xa0, 0x40, 0x11, 0x01, 0x31, 0x00, 0x63, 0x16}, + {0xa0, 0x40, 0x10, 0x0e, 0x31, 0x00, 0x63, 0x15}, + {0xa0, 0x40, 0x11, 0x01, 0x31, 0x00, 0x63, 0x16}, +}; + +static const __u8 initTas5110[] = { + 0x44, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x11, 0x00, 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x01, 0x00, 0x46, 0x09, 0x0a, /* shift from 0x45 0x09 0x0a */ + 0x16, 0x12, 0x60, 0x86, 0x2b, + 0x14, 0x0a, 0x02, 0x02, 0x09, 0x07 +}; +static const __u8 tas5110_sensor_init[][8] = { + {0x30, 0x11, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x10}, + {0x30, 0x11, 0x02, 0x20, 0xa9, 0x00, 0x00, 0x10}, + {0xa0, 0x61, 0x9a, 0xca, 0x00, 0x00, 0x00, 0x17}, +}; + +static const __u8 initTas5130[] = { + 0x04, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x11, 0x00, 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x01, 0x00, 0x69, 0x0c, 0x0a, + 0x28, 0x1e, 0x60, COMP, MCK_INIT, + 0x18, 0x10, 0x04, 0x03, 0x11, 0x0c +}; +static const __u8 tas5130_sensor_init[][8] = { +/* {0x30, 0x11, 0x00, 0x40, 0x47, 0x00, 0x00, 0x10}, + * shutter 0x47 short exposure? */ + {0x30, 0x11, 0x00, 0x40, 0x01, 0x00, 0x00, 0x10}, + /* shutter 0x01 long exposure */ + {0x30, 0x11, 0x02, 0x20, 0x70, 0x00, 0x00, 0x10}, +}; + +/* get one byte in gspca_dev->usb_buf */ +static void reg_r(struct gspca_dev *gspca_dev, + __u16 value) +{ + usb_control_msg(gspca_dev->dev, + usb_rcvctrlpipe(gspca_dev->dev, 0), + 0, /* request */ + USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_INTERFACE, + value, + 0, /* index */ + gspca_dev->usb_buf, 1, + 500); +} + +static void reg_w(struct gspca_dev *gspca_dev, + __u16 value, + const __u8 *buffer, + int len) +{ +#ifdef CONFIG_VIDEO_ADV_DEBUG + if (len > sizeof gspca_dev->usb_buf) { + PDEBUG(D_ERR|D_PACK, "reg_w: buffer overflow"); + return; + } +#endif + memcpy(gspca_dev->usb_buf, buffer, len); + usb_control_msg(gspca_dev->dev, + usb_sndctrlpipe(gspca_dev->dev, 0), + 0x08, /* request */ + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE, + value, + 0, /* index */ + gspca_dev->usb_buf, len, + 500); +} + +static void reg_w_big(struct gspca_dev *gspca_dev, + __u16 value, + const __u8 *buffer, + int len) +{ + __u8 *tmpbuf; + + tmpbuf = kmalloc(len, GFP_KERNEL); + memcpy(tmpbuf, buffer, len); + usb_control_msg(gspca_dev->dev, + usb_sndctrlpipe(gspca_dev->dev, 0), + 0x08, /* request */ + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE, + value, + 0, /* index */ + tmpbuf, len, + 500); + kfree(tmpbuf); +} + +static int i2c_w(struct gspca_dev *gspca_dev, const __u8 *buffer) +{ + int retry = 60; + + /* is i2c ready */ + reg_w(gspca_dev, 0x08, buffer, 8); + while (retry--) { + msleep(10); + reg_r(gspca_dev, 0x08); + if (gspca_dev->usb_buf[0] & 0x04) { + if (gspca_dev->usb_buf[0] & 0x08) + return -1; + return 0; + } + } + return -1; +} + +static void i2c_w_vector(struct gspca_dev *gspca_dev, + const __u8 buffer[][8], int len) +{ + for (;;) { + reg_w(gspca_dev, 0x08, *buffer, 8); + len -= 8; + if (len <= 0) + break; + buffer++; + } +} + +static void setbrightness(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + __u8 value; + + switch (sd->sensor) { + case SENSOR_OV6650: + case SENSOR_OV7630_3: + case SENSOR_OV7630: { + __u8 i2cOV[] = + {0xa0, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x10}; + + /* change reg 0x06 */ + i2cOV[1] = sd->sensor_addr; + i2cOV[3] = sd->brightness; + if (i2c_w(gspca_dev, i2cOV) < 0) + goto err; + break; + } + case SENSOR_PAS106: { + __u8 i2c1[] = + {0xa1, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14}; + + i2c1[3] = sd->brightness >> 3; + i2c1[2] = 0x0e; + if (i2c_w(gspca_dev, i2c1) < 0) + goto err; + i2c1[3] = 0x01; + i2c1[2] = 0x13; + if (i2c_w(gspca_dev, i2c1) < 0) + goto err; + break; + } + case SENSOR_PAS202: { + /* __u8 i2cpexpo1[] = + {0xb0, 0x40, 0x04, 0x07, 0x2a, 0x00, 0x63, 0x16}; */ + __u8 i2cpexpo[] = + {0xb0, 0x40, 0x0e, 0x01, 0xab, 0x00, 0x63, 0x16}; + __u8 i2cp202[] = + {0xa0, 0x40, 0x10, 0x0e, 0x31, 0x00, 0x63, 0x15}; + static __u8 i2cpdoit[] = + {0xa0, 0x40, 0x11, 0x01, 0x31, 0x00, 0x63, 0x16}; + + /* change reg 0x10 */ + i2cpexpo[4] = 0xff - sd->brightness; +/* if(i2c_w(gspca_dev,i2cpexpo1) < 0) + goto err; */ +/* if(i2c_w(gspca_dev,i2cpdoit) < 0) + goto err; */ + if (i2c_w(gspca_dev, i2cpexpo) < 0) + goto err; + if (i2c_w(gspca_dev, i2cpdoit) < 0) + goto err; + i2cp202[3] = sd->brightness >> 3; + if (i2c_w(gspca_dev, i2cp202) < 0) + goto err; + if (i2c_w(gspca_dev, i2cpdoit) < 0) + goto err; + break; + } + case SENSOR_TAS5130CXX: { + __u8 i2c[] = + {0x30, 0x11, 0x02, 0x20, 0x70, 0x00, 0x00, 0x10}; + + value = 0xff - sd->brightness; + i2c[4] = value; + PDEBUG(D_CONF, "brightness %d : %d", value, i2c[4]); + if (i2c_w(gspca_dev, i2c) < 0) + goto err; + break; + } + case SENSOR_TAS5110: + /* FIXME figure out howto control brightness on TAS5110 */ + break; + } + return; +err: + PDEBUG(D_ERR, "i2c error brightness"); +} + +static void setsensorgain(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + unsigned char gain = sd->gain; + + switch (sd->sensor) { + + case SENSOR_TAS5110: { + __u8 i2c[] = + {0x30, 0x11, 0x02, 0x20, 0x70, 0x00, 0x00, 0x10}; + + i2c[4] = 255 - gain; + if (i2c_w(gspca_dev, i2c) < 0) + goto err; + break; + } + + case SENSOR_OV6650: + gain >>= 1; + /* fall thru */ + case SENSOR_OV7630_3: { + __u8 i2c[] = {0xa0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10}; + + i2c[1] = sd->sensor_addr; + i2c[3] = gain >> 2; + if (i2c_w(gspca_dev, i2c) < 0) + goto err; + break; + } + } + return; +err: + PDEBUG(D_ERR, "i2c error gain"); +} + +static void setgain(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + __u8 gain; + __u8 rgb_value; + + gain = sd->gain >> 4; + + /* red and blue gain */ + rgb_value = gain << 4 | gain; + reg_w(gspca_dev, 0x10, &rgb_value, 1); + /* green gain */ + rgb_value = gain; + reg_w(gspca_dev, 0x11, &rgb_value, 1); + + if (sd->sensor_has_gain) + setsensorgain(gspca_dev); +} + +static void setexposure(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + + switch (sd->sensor) { + case SENSOR_TAS5110: { + __u8 reg; + + /* register 19's high nibble contains the sn9c10x clock divider + The high nibble configures the no fps according to the + formula: 60 / high_nibble. With a maximum of 30 fps */ + reg = 120 * sd->exposure / 1000; + if (reg < 2) + reg = 2; + else if (reg > 15) + reg = 15; + reg = (reg << 4) | 0x0b; + reg_w(gspca_dev, 0x19, ®, 1); + break; + } + case SENSOR_OV6650: + case SENSOR_OV7630_3: { + /* The ov6650 / ov7630 have 2 registers which both influence + exposure, register 11, whose low nibble sets the nr off fps + according to: fps = 30 / (low_nibble + 1) + + The fps configures the maximum exposure setting, but it is + possible to use less exposure then what the fps maximum + allows by setting register 10. register 10 configures the + actual exposure as quotient of the full exposure, with 0 + being no exposure at all (not very usefull) and reg10_max + being max exposure possible at that framerate. + + The code maps our 0 - 510 ms exposure ctrl to these 2 + registers, trying to keep fps as high as possible. + */ + __u8 i2c[] = {0xb0, 0x00, 0x10, 0x00, 0xc0, 0x00, 0x00, 0x10}; + int reg10, reg11; + /* ov6645 datasheet says reg10_max is 9a, but that uses + tline * 2 * reg10 as formula for calculating texpo, the + ov6650 probably uses the same formula as the 7730 which uses + tline * 4 * reg10, which explains why the reg10max we've + found experimentally for the ov6650 is exactly half that of + the ov6645. The ov7630 datasheet says the max is 0x41. */ + const int reg10_max = (sd->sensor == SENSOR_OV6650) + ? 0x4d : 0x41; + + reg11 = (60 * sd->exposure + 999) / 1000; + if (reg11 < 1) + reg11 = 1; + else if (reg11 > 16) + reg11 = 16; + + /* frame exposure time in ms = 1000 * reg11 / 30 -> + reg10 = sd->exposure * 2 * reg10_max / (1000 * reg11 / 30) */ + reg10 = (sd->exposure * 60 * reg10_max) / (1000 * reg11); + + /* Don't allow this to get below 10 when using autogain, the + steps become very large (relatively) when below 10 causing + the image to oscilate from much too dark, to much too bright + and back again. */ + if (sd->autogain && reg10 < 10) + reg10 = 10; + else if (reg10 > reg10_max) + reg10 = reg10_max; + + /* Write reg 10 and reg11 low nibble */ + i2c[1] = sd->sensor_addr; + i2c[3] = reg10; + i2c[4] |= reg11 - 1; + if (sd->sensor == SENSOR_OV7630_3) { + __u8 reg76 = reg10 & 0x03; + __u8 i2c_reg76[] = {0xa0, 0x21, 0x76, 0x00, + 0x00, 0x00, 0x00, 0x10}; + reg10 >>= 2; + i2c_reg76[3] = reg76; + if (i2c_w(gspca_dev, i2c_reg76) < 0) + PDEBUG(D_ERR, "i2c error exposure"); + } + if (i2c_w(gspca_dev, i2c) < 0) + PDEBUG(D_ERR, "i2c error exposure"); + break; + } + } +} + +static void setfreq(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + + switch (sd->sensor) { + case SENSOR_OV6650: + case SENSOR_OV7630_3: { + /* Framerate adjust register for artificial light 50 hz flicker + compensation, identical to ov6630 0x2b register, see ov6630 + datasheet. + 0x4f -> (30 fps -> 25 fps), 0x00 -> no adjustment */ + __u8 i2c[] = {0xa0, 0x00, 0x2b, 0x00, 0x00, 0x00, 0x00, 0x10}; + switch (sd->freq) { + default: +/* case 0: * no filter*/ +/* case 2: * 60 hz */ + i2c[3] = 0; + break; + case 1: /* 50 hz */ + i2c[3] = (sd->sensor == SENSOR_OV6650) + ? 0x4f : 0x8a; + break; + } + i2c[1] = sd->sensor_addr; + if (i2c_w(gspca_dev, i2c) < 0) + PDEBUG(D_ERR, "i2c error setfreq"); + break; + } + } +} + +static void setsaturation(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + + switch (sd->sensor) { +/* case SENSOR_OV6650: */ + case SENSOR_OV7630_3: + case SENSOR_OV7630: { + __u8 i2c[] = {0xa0, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x10}; + i2c[1] = sd->sensor_addr; + i2c[3] = sd->saturation & 0xf0; + if (i2c_w(gspca_dev, i2c) < 0) + PDEBUG(D_ERR, "i2c error setsaturation"); + else + PDEBUG(D_CONF, "saturation set to: %d", + (int)sd->saturation); + break; + } + } +} + +static void sethue(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + + switch (sd->sensor) { +/* case SENSOR_OV6650: */ + case SENSOR_OV7630_3: + case SENSOR_OV7630: { + __u8 i2c[] = {0xa0, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x10}; + i2c[1] = sd->sensor_addr; + i2c[3] = 0x20 | (sd->hue >> 3); + if (i2c_w(gspca_dev, i2c) < 0) + PDEBUG(D_ERR, "i2c error setsaturation"); + else + PDEBUG(D_CONF, "hue set to: %d", (int)sd->hue); + break; + } + } +} + +static void setcontrast(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + + switch (sd->sensor) { +/* case SENSOR_OV6650: */ + case SENSOR_OV7630_3: + case SENSOR_OV7630: { + __u8 i2c[] = {0xa0, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x10}; + i2c[1] = sd->sensor_addr; + i2c[3] = 0x20 | (sd->contrast >> 3); + if (i2c_w(gspca_dev, i2c) < 0) + PDEBUG(D_ERR, "i2c error setcontrast"); + else + PDEBUG(D_CONF, "contrast set to: %d", + (int)sd->contrast); + break; + } + } +} + + +static void do_autogain(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + int avg_lum = atomic_read(&sd->avg_lum); + + if (avg_lum == -1) + return; + + if (sd->autogain_ignore_frames > 0) + sd->autogain_ignore_frames--; + else if (gspca_auto_gain_n_exposure(gspca_dev, avg_lum, + sd->brightness * DESIRED_AVG_LUM / 127, + AUTOGAIN_DEADZONE, GAIN_KNEE, EXPOSURE_KNEE)) { + PDEBUG(D_FRAM, "autogain: gain changed: gain: %d expo: %d\n", + (int)sd->gain, (int)sd->exposure); + sd->autogain_ignore_frames = AUTOGAIN_IGNORE_FRAMES; + } +} + +/* this function is called at probe time */ +static int sd_config(struct gspca_dev *gspca_dev, + const struct usb_device_id *id) +{ + struct sd *sd = (struct sd *) gspca_dev; + struct cam *cam; + __u16 product; + int sif = 0; + + /* nctrls depends upon the sensor, so we use a per cam copy */ + memcpy(&sd->sd_desc, gspca_dev->sd_desc, sizeof(struct sd_desc)); + gspca_dev->sd_desc = &sd->sd_desc; + + sd->fr_h_sz = 12; /* default size of the frame header */ + sd->sd_desc.nctrls = 2; /* default nb of ctrls */ + sd->autogain = AUTOGAIN_DEF; /* default is autogain active */ + + product = id->idProduct; +/* switch (id->idVendor) { */ +/* case 0x0c45: * Sonix */ + switch (product) { + case 0x6001: /* SN9C102 */ + case 0x6005: /* SN9C101 */ + case 0x6007: /* SN9C101 */ + sd->sensor = SENSOR_TAS5110; + sd->sensor_has_gain = 1; + sd->sd_desc.nctrls = 4; + sd->sd_desc.dq_callback = do_autogain; + sif = 1; + break; + case 0x6009: /* SN9C101 */ + case 0x600d: /* SN9C101 */ + case 0x6029: /* SN9C101 */ + sd->sensor = SENSOR_PAS106; + sif = 1; + break; + case 0x6011: /* SN9C101 - SN9C101G */ + sd->sensor = SENSOR_OV6650; + sd->sensor_has_gain = 1; + sd->sensor_addr = 0x60; + sd->sd_desc.nctrls = 5; + sd->sd_desc.dq_callback = do_autogain; + sif = 1; + break; + case 0x6019: /* SN9C101 */ + case 0x602c: /* SN9C102 */ + case 0x602e: /* SN9C102 */ + sd->sensor = SENSOR_OV7630; + sd->sensor_addr = 0x21; + break; + case 0x60b0: /* SN9C103 */ + sd->sensor = SENSOR_OV7630_3; + sd->sensor_addr = 0x21; + sd->fr_h_sz = 18; /* size of frame header */ + sd->sensor_has_gain = 1; + sd->sd_desc.nctrls = 8; + sd->sd_desc.dq_callback = do_autogain; + sd->autogain = 0; + break; + case 0x6024: /* SN9C102 */ + case 0x6025: /* SN9C102 */ + sd->sensor = SENSOR_TAS5130CXX; + break; + case 0x6028: /* SN9C102 */ + sd->sensor = SENSOR_PAS202; + break; + case 0x602d: /* SN9C102 */ + sd->sensor = SENSOR_HV7131R; + break; + case 0x60af: /* SN9C103 */ + sd->sensor = SENSOR_PAS202; + sd->fr_h_sz = 18; /* size of frame header (?) */ + break; + } +/* break; */ +/* } */ + + cam = &gspca_dev->cam; + cam->dev_name = (char *) id->driver_info; + cam->epaddr = 0x01; + if (!sif) { + cam->cam_mode = vga_mode; + cam->nmodes = ARRAY_SIZE(vga_mode); + if (sd->sensor == SENSOR_OV7630_3) { + /* We only have 320x240 & 640x480 */ + cam->cam_mode++; + cam->nmodes--; + } + } else { + cam->cam_mode = sif_mode; + cam->nmodes = ARRAY_SIZE(sif_mode); + } + sd->brightness = BRIGHTNESS_DEF; + sd->gain = GAIN_DEF; + sd->exposure = EXPOSURE_DEF; + sd->freq = FREQ_DEF; + sd->contrast = CONTRAST_DEF; + sd->saturation = SATURATION_DEF; + sd->hue = HUE_DEF; + if (sd->sensor == SENSOR_OV7630_3) /* jfm: from win trace */ + reg_w(gspca_dev, 0x01, probe_ov7630, sizeof probe_ov7630); + return 0; +} + +/* this function is called at open time */ +static int sd_open(struct gspca_dev *gspca_dev) +{ + reg_r(gspca_dev, 0x00); + if (gspca_dev->usb_buf[0] != 0x10) + return -ENODEV; + return 0; +} + +static void pas106_i2cinit(struct gspca_dev *gspca_dev) +{ + int i; + const __u8 *data; + __u8 i2c1[] = { 0xa1, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14 }; + + i = ARRAY_SIZE(pas106_data); + data = pas106_data[0]; + while (--i >= 0) { + memcpy(&i2c1[2], data, 2); + /* copy 2 bytes from the template */ + if (i2c_w(gspca_dev, i2c1) < 0) + PDEBUG(D_ERR, "i2c error pas106"); + data += 2; + } +} + +/* -- start the camera -- */ +static void sd_start(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + int mode, l; + const __u8 *sn9c10x; + __u8 reg01, reg17; + __u8 reg17_19[3]; + + mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv; + switch (sd->sensor) { + case SENSOR_HV7131R: + sn9c10x = initHv7131; + reg17_19[0] = 0x60; + reg17_19[1] = (mode << 4) | 0x8a; + reg17_19[2] = 0x20; + break; + case SENSOR_OV6650: + sn9c10x = initOv6650; + reg17_19[0] = 0x68; + reg17_19[1] = (mode << 4) | 0x8b; + reg17_19[2] = 0x20; + break; + case SENSOR_OV7630: + sn9c10x = initOv7630; + reg17_19[0] = 0x68; + reg17_19[1] = (mode << 4) | COMP2; + reg17_19[2] = MCK_INIT1; + break; + case SENSOR_OV7630_3: + sn9c10x = initOv7630_3; + reg17_19[0] = 0x68; + reg17_19[1] = (mode << 4) | COMP2; + reg17_19[2] = MCK_INIT1; + break; + case SENSOR_PAS106: + sn9c10x = initPas106; + reg17_19[0] = 0x24; /* 0x28 */ + reg17_19[1] = (mode << 4) | COMP1; + reg17_19[2] = MCK_INIT1; + break; + case SENSOR_PAS202: + sn9c10x = initPas202; + reg17_19[0] = mode ? 0x24 : 0x20; + reg17_19[1] = (mode << 4) | 0x89; + reg17_19[2] = 0x20; + break; + case SENSOR_TAS5110: + sn9c10x = initTas5110; + reg17_19[0] = 0x60; + reg17_19[1] = (mode << 4) | 0x86; + reg17_19[2] = 0x2b; /* 0xf3; */ + break; + default: +/* case SENSOR_TAS5130CXX: */ + sn9c10x = initTas5130; + reg17_19[0] = 0x60; + reg17_19[1] = (mode << 4) | COMP; + reg17_19[2] = mode ? 0x23 : 0x43; + break; + } + switch (sd->sensor) { + case SENSOR_OV7630: + reg01 = 0x06; + reg17 = 0x29; + l = sizeof initOv7630; + break; + case SENSOR_OV7630_3: + reg01 = 0x44; + reg17 = 0x68; + l = sizeof initOv7630_3; + break; + default: + reg01 = sn9c10x[0]; + reg17 = sn9c10x[0x17 - 1]; + l = 0x1f; + break; + } + + /* reg 0x01 bit 2 video transfert on */ + reg_w(gspca_dev, 0x01, ®01, 1); + /* reg 0x17 SensorClk enable inv Clk 0x60 */ + reg_w(gspca_dev, 0x17, ®17, 1); +/*fixme: for ov7630 102 + reg_w(gspca_dev, 0x01, {0x06, sn9c10x[1]}, 2); */ + /* Set the registers from the template */ + reg_w_big(gspca_dev, 0x01, sn9c10x, l); + switch (sd->sensor) { + case SENSOR_HV7131R: + i2c_w_vector(gspca_dev, hv7131_sensor_init, + sizeof hv7131_sensor_init); + break; + case SENSOR_OV6650: + i2c_w_vector(gspca_dev, ov6650_sensor_init, + sizeof ov6650_sensor_init); + break; + case SENSOR_OV7630: + i2c_w_vector(gspca_dev, ov7630_sensor_init_com, + sizeof ov7630_sensor_init_com); + msleep(200); + i2c_w_vector(gspca_dev, ov7630_sensor_init, + sizeof ov7630_sensor_init); + break; + case SENSOR_OV7630_3: + i2c_w_vector(gspca_dev, ov7630_sensor_init_com, + sizeof ov7630_sensor_init_com); + msleep(200); + i2c_w(gspca_dev, ov7630_sensor_init_3[mode]); + break; + case SENSOR_PAS106: + pas106_i2cinit(gspca_dev); + break; + case SENSOR_PAS202: + i2c_w_vector(gspca_dev, pas202_sensor_init, + sizeof pas202_sensor_init); + break; + case SENSOR_TAS5110: + i2c_w_vector(gspca_dev, tas5110_sensor_init, + sizeof tas5110_sensor_init); + break; + default: +/* case SENSOR_TAS5130CXX: */ + i2c_w_vector(gspca_dev, tas5130_sensor_init, + sizeof tas5130_sensor_init); + break; + } + /* H_size V_size 0x28, 0x1e -> 640x480. 0x16, 0x12 -> 352x288 */ + reg_w(gspca_dev, 0x15, &sn9c10x[0x15 - 1], 2); + /* compression register */ + reg_w(gspca_dev, 0x18, ®17_19[1], 1); + /* H_start */ + reg_w(gspca_dev, 0x12, &sn9c10x[0x12 - 1], 1); + /* V_START */ + reg_w(gspca_dev, 0x13, &sn9c10x[0x13 - 1], 1); + /* reset 0x17 SensorClk enable inv Clk 0x60 */ + /*fixme: ov7630 [17]=68 8f (+20 if 102)*/ + reg_w(gspca_dev, 0x17, ®17_19[0], 1); + /*MCKSIZE ->3 */ /*fixme: not ov7630*/ + reg_w(gspca_dev, 0x19, ®17_19[2], 1); + /* AE_STRX AE_STRY AE_ENDX AE_ENDY */ + reg_w(gspca_dev, 0x1c, &sn9c10x[0x1c - 1], 4); + /* Enable video transfert */ + reg_w(gspca_dev, 0x01, &sn9c10x[0], 1); + /* Compression */ + reg_w(gspca_dev, 0x18, ®17_19[1], 2); + msleep(20); + + setgain(gspca_dev); + setbrightness(gspca_dev); + setexposure(gspca_dev); + setfreq(gspca_dev); + setsaturation(gspca_dev); + sethue(gspca_dev); + setcontrast(gspca_dev); + + sd->autogain_ignore_frames = 0; + atomic_set(&sd->avg_lum, -1); +} + +static void sd_stopN(struct gspca_dev *gspca_dev) +{ + __u8 ByteSend; + + ByteSend = 0x09; /* 0X00 */ + reg_w(gspca_dev, 0x01, &ByteSend, 1); +} + +static void sd_stop0(struct gspca_dev *gspca_dev) +{ +} + +static void sd_close(struct gspca_dev *gspca_dev) +{ +} + +static void sd_pkt_scan(struct gspca_dev *gspca_dev, + struct gspca_frame *frame, /* target */ + unsigned char *data, /* isoc packet */ + int len) /* iso packet length */ +{ + int i; + struct sd *sd = (struct sd *) gspca_dev; + + /* frames start with: + * ff ff 00 c4 c4 96 synchro + * 00 (unknown) + * xx (frame sequence / size / compression) + * (xx) (idem - extra byte for sn9c103) + * ll mm brightness sum inside auto exposure + * ll mm brightness sum outside auto exposure + * (xx xx xx xx xx) audio values for snc103 + */ + if (len > 6 && len < 24) { + for (i = 0; i < len - 6; i++) { + if (data[0 + i] == 0xff + && data[1 + i] == 0xff + && data[2 + i] == 0x00 + && data[3 + i] == 0xc4 + && data[4 + i] == 0xc4 + && data[5 + i] == 0x96) { /* start of frame */ + frame = gspca_frame_add(gspca_dev, LAST_PACKET, + frame, data, 0); + if (len - i < sd->fr_h_sz) { + atomic_set(&sd->avg_lum, -1); + PDEBUG(D_STREAM, "packet too short to" + " get avg brightness"); + } else if (sd->fr_h_sz == 12) { + atomic_set(&sd->avg_lum, + data[i + 8] + + (data[i + 9] << 8)); + } else { + atomic_set(&sd->avg_lum, + data[i + 9] + + (data[i + 10] << 8)); + } + data += i + sd->fr_h_sz; + len -= i + sd->fr_h_sz; + gspca_frame_add(gspca_dev, FIRST_PACKET, + frame, data, len); + return; + } + } + } + gspca_frame_add(gspca_dev, INTER_PACKET, + frame, data, len); +} + +static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->brightness = val; + if (gspca_dev->streaming) + setbrightness(gspca_dev); + return 0; +} + +static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + *val = sd->brightness; + return 0; +} + +static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->gain = val; + if (gspca_dev->streaming) + setgain(gspca_dev); + return 0; +} + +static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + *val = sd->gain; + return 0; +} + +static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->exposure = val; + if (gspca_dev->streaming) + setexposure(gspca_dev); + return 0; +} + +static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + *val = sd->exposure; + return 0; +} + +static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->autogain = val; + /* when switching to autogain set defaults to make sure + we are on a valid point of the autogain gain / + exposure knee graph, and give this change time to + take effect before doing autogain. */ + if (sd->autogain) { + sd->exposure = EXPOSURE_DEF; + sd->gain = GAIN_DEF; + if (gspca_dev->streaming) { + sd->autogain_ignore_frames = AUTOGAIN_IGNORE_FRAMES; + setexposure(gspca_dev); + setgain(gspca_dev); + } + } + + return 0; +} + +static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + *val = sd->autogain; + return 0; +} + +static int sd_setfreq(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->freq = val; + if (gspca_dev->streaming) + setfreq(gspca_dev); + return 0; +} + +static int sd_getfreq(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + *val = sd->freq; + return 0; +} + +static int sd_setsaturation(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->saturation = val; + if (gspca_dev->streaming) + setsaturation(gspca_dev); + return 0; +} + +static int sd_getsaturation(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + *val = sd->saturation; + return 0; +} + +static int sd_sethue(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->hue = val; + if (gspca_dev->streaming) + sethue(gspca_dev); + return 0; +} + +static int sd_gethue(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + *val = sd->hue; + return 0; +} + +static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->contrast = val; + if (gspca_dev->streaming) + setcontrast(gspca_dev); + return 0; +} + +static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + *val = sd->contrast; + return 0; +} + +static int sd_querymenu(struct gspca_dev *gspca_dev, + struct v4l2_querymenu *menu) +{ + switch (menu->id) { + case V4L2_CID_POWER_LINE_FREQUENCY: + switch (menu->index) { + case 0: /* V4L2_CID_POWER_LINE_FREQUENCY_DISABLED */ + strcpy((char *) menu->name, "NoFliker"); + return 0; + case 1: /* V4L2_CID_POWER_LINE_FREQUENCY_50HZ */ + strcpy((char *) menu->name, "50 Hz"); + return 0; + case 2: /* V4L2_CID_POWER_LINE_FREQUENCY_60HZ */ + strcpy((char *) menu->name, "60 Hz"); + return 0; + } + break; + } + return -EINVAL; +} + +/* sub-driver description */ +static const struct sd_desc sd_desc = { + .name = MODULE_NAME, + .ctrls = sd_ctrls, + .nctrls = ARRAY_SIZE(sd_ctrls), + .config = sd_config, + .open = sd_open, + .start = sd_start, + .stopN = sd_stopN, + .stop0 = sd_stop0, + .close = sd_close, + .pkt_scan = sd_pkt_scan, + .querymenu = sd_querymenu, +}; + +/* -- module initialisation -- */ +#define DVNM(name) .driver_info = (kernel_ulong_t) name +static __devinitdata struct usb_device_id device_table[] = { +#ifndef CONFIG_USB_SN9C102 + {USB_DEVICE(0x0c45, 0x6001), DVNM("Genius VideoCAM NB")}, + {USB_DEVICE(0x0c45, 0x6005), DVNM("Sweex Tas5110")}, + {USB_DEVICE(0x0c45, 0x6007), DVNM("Sonix sn9c101 + Tas5110D")}, + {USB_DEVICE(0x0c45, 0x6009), DVNM("spcaCam@120")}, + {USB_DEVICE(0x0c45, 0x600d), DVNM("spcaCam@120")}, +#endif + {USB_DEVICE(0x0c45, 0x6011), DVNM("MAX Webcam Microdia")}, +#ifndef CONFIG_USB_SN9C102 + {USB_DEVICE(0x0c45, 0x6019), DVNM("Generic Sonix OV7630")}, + {USB_DEVICE(0x0c45, 0x6024), DVNM("Generic Sonix Tas5130c")}, + {USB_DEVICE(0x0c45, 0x6025), DVNM("Xcam Shanga")}, + {USB_DEVICE(0x0c45, 0x6028), DVNM("Sonix Btc Pc380")}, + {USB_DEVICE(0x0c45, 0x6029), DVNM("spcaCam@150")}, + {USB_DEVICE(0x0c45, 0x602c), DVNM("Generic Sonix OV7630")}, + {USB_DEVICE(0x0c45, 0x602d), DVNM("LIC-200 LG")}, + {USB_DEVICE(0x0c45, 0x602e), DVNM("Genius VideoCam Messenger")}, + {USB_DEVICE(0x0c45, 0x60af), DVNM("Trust WB3100P")}, + {USB_DEVICE(0x0c45, 0x60b0), DVNM("Genius VideoCam Look")}, +#endif + {} +}; +MODULE_DEVICE_TABLE(usb, device_table); + +/* -- device connect -- */ +static int sd_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd), + THIS_MODULE); +} + +static struct usb_driver sd_driver = { + .name = MODULE_NAME, + .id_table = device_table, + .probe = sd_probe, + .disconnect = gspca_disconnect, +}; + +/* -- module insert / remove -- */ +static int __init sd_mod_init(void) +{ + if (usb_register(&sd_driver) < 0) + return -1; + PDEBUG(D_PROBE, "v%s registered", version); + return 0; +} +static void __exit sd_mod_exit(void) +{ + usb_deregister(&sd_driver); + PDEBUG(D_PROBE, "deregistered"); +} + +module_init(sd_mod_init); +module_exit(sd_mod_exit); diff --git a/drivers/media/video/gspca/sonixj.c b/drivers/media/video/gspca/sonixj.c new file mode 100644 index 000000000000..3e68b9926956 --- /dev/null +++ b/drivers/media/video/gspca/sonixj.c @@ -0,0 +1,1671 @@ +/* + * Sonix sn9c102p sn9c105 sn9c120 (jpeg) library + * Copyright (C) 2005 Michel Xhaard mxhaard@magic.fr + * + * V4L2 by Jean-Francois Moine <http://moinejf.free.fr> + * + * 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 + * 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 + */ + +#define MODULE_NAME "sonixj" + +#include "gspca.h" +#include "jpeg.h" + +#define DRIVER_VERSION_NUMBER KERNEL_VERSION(2, 1, 7) +static const char version[] = "2.1.7"; + +MODULE_AUTHOR("Michel Xhaard <mxhaard@users.sourceforge.net>"); +MODULE_DESCRIPTION("GSPCA/SONIX JPEG USB Camera Driver"); +MODULE_LICENSE("GPL"); + +/* specific webcam descriptor */ +struct sd { + struct gspca_dev gspca_dev; /* !! must be the first item */ + + int avg_lum; + unsigned int exposure; + + unsigned short brightness; + unsigned char contrast; + unsigned char colors; + unsigned char autogain; + + signed char ag_cnt; +#define AG_CNT_START 13 + + char qindex; + unsigned char bridge; +#define BRIDGE_SN9C102P 0 +#define BRIDGE_SN9C105 1 +#define BRIDGE_SN9C110 2 +#define BRIDGE_SN9C120 3 +#define BRIDGE_SN9C325 4 + char sensor; /* Type of image sensor chip */ +#define SENSOR_HV7131R 0 +#define SENSOR_MI0360 1 +#define SENSOR_MO4000 2 +#define SENSOR_OV7648 3 +#define SENSOR_OV7660 4 + unsigned char i2c_base; +}; + +/* V4L2 controls supported by the driver */ +static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val); +static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val); +static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val); +static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val); +static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val); +static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val); +static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val); +static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val); + +static struct ctrl sd_ctrls[] = { + { + { + .id = V4L2_CID_BRIGHTNESS, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Brightness", + .minimum = 0, + .maximum = 0xffff, + .step = 1, +#define BRIGHTNESS_DEF 0x7fff + .default_value = BRIGHTNESS_DEF, + }, + .set = sd_setbrightness, + .get = sd_getbrightness, + }, + { + { + .id = V4L2_CID_CONTRAST, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Contrast", + .minimum = 0, + .maximum = 127, + .step = 1, +#define CONTRAST_DEF 63 + .default_value = CONTRAST_DEF, + }, + .set = sd_setcontrast, + .get = sd_getcontrast, + }, + { + { + .id = V4L2_CID_SATURATION, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Color", + .minimum = 0, + .maximum = 255, + .step = 1, +#define COLOR_DEF 127 + .default_value = COLOR_DEF, + }, + .set = sd_setcolors, + .get = sd_getcolors, + }, + { + { + .id = V4L2_CID_AUTOGAIN, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Auto Gain", + .minimum = 0, + .maximum = 1, + .step = 1, +#define AUTOGAIN_DEF 1 + .default_value = AUTOGAIN_DEF, + }, + .set = sd_setautogain, + .get = sd_getautogain, + }, +}; + +static struct v4l2_pix_format vga_mode[] = { + {160, 120, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, + .bytesperline = 160, + .sizeimage = 160 * 120 * 3 / 8 + 590, + .colorspace = V4L2_COLORSPACE_JPEG, + .priv = 2}, + {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, + .bytesperline = 320, + .sizeimage = 320 * 240 * 3 / 8 + 590, + .colorspace = V4L2_COLORSPACE_JPEG, + .priv = 1}, + {640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, + .bytesperline = 640, + .sizeimage = 640 * 480 * 3 / 8 + 590, + .colorspace = V4L2_COLORSPACE_JPEG, + .priv = 0}, +}; + +/*Data from sn9c102p+hv71331r */ +static const __u8 sn_hv7131[] = { +/* reg0 reg1 reg2 reg3 reg4 reg5 reg6 reg7 reg8 reg9 */ + 0x00, 0x03, 0x64, 0x00, 0x1A, 0x20, 0x20, 0x20, 0xA1, 0x11, +/* rega regb regc regd rege regf reg10 reg11 */ + 0x02, 0x09, 0x00, 0x00, 0x00, 0x10, 0x03, 0x00, /* 00 */ +/* reg12 reg13 reg14 reg15 reg16 reg17 reg18 reg19 reg1a reg1b */ + 0x00, 0x01, 0x03, 0x28, 0x1e, 0x41, 0x0a, 0x00, 0x00, 0x00, +/* reg1c reg1d reg1e reg1f reg20 reg21 reg22 reg23 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +static const __u8 sn_mi0360[] = { +/* reg0 reg1 reg2 reg3 reg4 reg5 reg6 reg7 reg8 reg9 */ + 0x00, 0x61, 0x44, 0x00, 0x1a, 0x20, 0x20, 0x20, 0xb1, 0x5d, +/* rega regb regc regd rege regf reg10 reg11 */ + 0x07, 0x00, 0x00, 0x00, 0x00, 0x10, 0x03, 0x00, +/* reg12 reg13 reg14 reg15 reg16 reg17 reg18 reg19 reg1a reg1b */ + 0x00, 0x02, 0x0a, 0x28, 0x1e, 0x61, 0x06, 0x00, 0x00, 0x00, +/* reg1c reg1d reg1e reg1f reg20 reg21 reg22 reg23 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +static const __u8 sn_mo4000[] = { +/* reg0 reg1 reg2 reg3 reg4 reg5 reg6 reg7 reg8 */ + 0x12, 0x23, 0x60, 0x00, 0x1A, 0x00, 0x20, 0x18, 0x81, +/* reg9 rega regb regc regd rege regf reg10 reg11*/ + 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, +/* reg12 reg13 reg14 reg15 reg16 reg17 reg18 reg19 reg1a*/ + 0x0b, 0x0f, 0x14, 0x28, 0x1e, 0x40, 0x08, 0x00, 0x00, +/* reg1b reg1c reg1d reg1e reg1f reg20 reg21 reg22 reg23*/ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x25, 0x39, 0x4b, + 0x5c, 0x6b, 0x79, 0x87, 0x95, 0xa2, 0xaf, 0xbb, 0xc7, + 0xd3, 0xdf, 0xea, 0xf5 +}; + +static const __u8 sn_ov7648[] = { + 0x00, 0x21, 0x62, 0x00, 0x1a, 0x20, 0x20, 0x20, 0xA1, 0x6E, 0x18, 0x65, + 0x00, 0x00, 0x00, 0x10, 0x03, 0x00, 0x00, 0x06, 0x06, 0x28, 0x1E, 0x82, + 0x07, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +static const __u8 sn_ov7660[] = { +/* reg0 reg1 reg2 reg3 reg4 reg5 reg6 reg7 reg8 */ + 0x00, 0x61, 0x40, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x81, +/* reg9 rega regb regc regd rege regf reg10 reg11*/ + 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, +/* reg12 reg13 reg14 reg15 reg16 reg17 reg18 reg19 reg1a*/ + 0x01, 0x01, 0x14, 0x28, 0x1e, 0x00, 0x07, 0x00, 0x00, +/* reg1b reg1c reg1d reg1e reg1f reg20 reg21 reg22 reg23*/ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +/* sequence specific to the sensors - !! index = SENSOR_xxx */ +static const __u8 *sn_tb[] = { + sn_hv7131, + sn_mi0360, + sn_mo4000, + sn_ov7648, + sn_ov7660 +}; + +static const __u8 regsn20[] = { + 0x00, 0x2d, 0x46, 0x5a, 0x6c, 0x7c, 0x8b, 0x99, + 0xa6, 0xb2, 0xbf, 0xca, 0xd5, 0xe0, 0xeb, 0xf5, 0xff +}; +static const __u8 regsn20_sn9c120[] = { + 0x00, 0x25, 0x3c, 0x50, 0x62, 0x72, 0x81, 0x90, + 0x9e, 0xab, 0xb8, 0xc5, 0xd1, 0xdd, 0xe9, 0xf4, 0xff +}; +static const __u8 regsn20_sn9c325[] = { + 0x0a, 0x3a, 0x56, 0x6c, 0x7e, 0x8d, 0x9a, 0xa4, + 0xaf, 0xbb, 0xc5, 0xcd, 0xd5, 0xde, 0xe8, 0xed, 0xf5 +}; + +static const __u8 reg84[] = { + 0x14, 0x00, 0x27, 0x00, 0x07, 0x00, 0xe5, 0x0f, + 0xe4, 0x0f, 0x38, 0x00, 0x3e, 0x00, 0xc3, 0x0f, +/* 0x00, 0x00, 0x00, 0x00, 0x00 */ + 0xf7, 0x0f, 0x0a, 0x00, 0x00 +}; +static const __u8 reg84_sn9c120_1[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0c, 0x00, 0x00 +}; +static const __u8 reg84_sn9c120_2[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0c, 0x02, 0x3b +}; +static const __u8 reg84_sn9c120_3[] = { + 0x14, 0x00, 0x27, 0x00, 0x08, 0x00, 0xeb, 0x0f, + 0xd5, 0x0f, 0x42, 0x00, 0x41, 0x00, 0xca, 0x0f, + 0xf5, 0x0f, 0x0c, 0x02, 0x3b +}; +static const __u8 reg84_sn9c325[] = { + 0x14, 0x00, 0x27, 0x00, 0x07, 0x00, 0xe4, 0x0f, + 0xd3, 0x0f, 0x4b, 0x00, 0x48, 0x00, 0xc0, 0x0f, + 0xf8, 0x0f, 0x00, 0x00, 0x00 +}; + +static const __u8 hv7131r_sensor_init[][8] = { + {0xC1, 0x11, 0x01, 0x08, 0x01, 0x00, 0x00, 0x10}, + {0xB1, 0x11, 0x34, 0x17, 0x7F, 0x00, 0x00, 0x10}, + {0xD1, 0x11, 0x40, 0xFF, 0x7F, 0x7F, 0x7F, 0x10}, + {0x91, 0x11, 0x44, 0x00, 0x00, 0x00, 0x00, 0x10}, + {0xD1, 0x11, 0x10, 0x00, 0x00, 0x00, 0x00, 0x10}, + {0xD1, 0x11, 0x14, 0x01, 0xE2, 0x02, 0x82, 0x10}, + {0x91, 0x11, 0x18, 0x00, 0x00, 0x00, 0x00, 0x10}, + + {0xA1, 0x11, 0x01, 0x08, 0x00, 0x00, 0x00, 0x10}, + {0xA1, 0x11, 0x01, 0x08, 0x00, 0x00, 0x00, 0x10}, + {0xC1, 0x11, 0x25, 0x00, 0x61, 0xA8, 0x00, 0x10}, + {0xA1, 0x11, 0x30, 0x22, 0x00, 0x00, 0x00, 0x10}, + {0xC1, 0x11, 0x31, 0x20, 0x2E, 0x20, 0x00, 0x10}, + {0xC1, 0x11, 0x25, 0x00, 0xC3, 0x50, 0x00, 0x10}, + {0xA1, 0x11, 0x30, 0x07, 0x00, 0x00, 0x00, 0x10}, /* gain14 */ + {0xC1, 0x11, 0x31, 0x10, 0x10, 0x10, 0x00, 0x10}, /* r g b 101a10 */ + + {0xA1, 0x11, 0x01, 0x08, 0x00, 0x00, 0x00, 0x10}, + {0xA1, 0x11, 0x20, 0x00, 0x00, 0x00, 0x00, 0x10}, + {0xA1, 0x11, 0x21, 0xD0, 0x00, 0x00, 0x00, 0x10}, + {0xA1, 0x11, 0x22, 0x00, 0x00, 0x00, 0x00, 0x10}, + {0xA1, 0x11, 0x23, 0x09, 0x00, 0x00, 0x00, 0x10}, + + {0xA1, 0x11, 0x01, 0x08, 0x00, 0x00, 0x00, 0x10}, + {0xA1, 0x11, 0x20, 0x00, 0x00, 0x00, 0x00, 0x10}, + {0xA1, 0x11, 0x21, 0xD0, 0x00, 0x00, 0x00, 0x10}, + {0xA1, 0x11, 0x22, 0x00, 0x00, 0x00, 0x00, 0x10}, + {0xA1, 0x11, 0x23, 0x10, 0x00, 0x00, 0x00, 0x10}, + {} +}; +static const __u8 mi0360_sensor_init[][8] = { + {0xB1, 0x5D, 0x07, 0x00, 0x02, 0x00, 0x00, 0x10}, + {0xB1, 0x5D, 0x0D, 0x00, 0x01, 0x00, 0x00, 0x10}, + {0xB1, 0x5D, 0x0D, 0x00, 0x00, 0x00, 0x00, 0x10}, + {0xD1, 0x5D, 0x01, 0x00, 0x08, 0x00, 0x16, 0x10}, + {0xD1, 0x5D, 0x03, 0x01, 0xE2, 0x02, 0x82, 0x10}, + {0xD1, 0x5D, 0x05, 0x00, 0x09, 0x00, 0x53, 0x10}, + {0xB1, 0x5D, 0x0D, 0x00, 0x02, 0x00, 0x00, 0x10}, + {0xD1, 0x5D, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x10}, + {0xD1, 0x5D, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x10}, + {0xD1, 0x5D, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x10}, + {0xD1, 0x5D, 0x10, 0x00, 0x00, 0x00, 0x00, 0x10}, + {0xD1, 0x5D, 0x12, 0x00, 0x00, 0x00, 0x00, 0x10}, + {0xD1, 0x5D, 0x14, 0x00, 0x00, 0x00, 0x00, 0x10}, + {0xD1, 0x5D, 0x16, 0x00, 0x00, 0x00, 0x00, 0x10}, + {0xD1, 0x5D, 0x18, 0x00, 0x00, 0x00, 0x00, 0x10}, + {0xD1, 0x5D, 0x1A, 0x00, 0x00, 0x00, 0x00, 0x10}, + {0xD1, 0x5D, 0x1C, 0x00, 0x00, 0x00, 0x00, 0x10}, + {0xB1, 0x5D, 0x32, 0x00, 0x00, 0x00, 0x00, 0x10}, + {0xD1, 0x5D, 0x20, 0x91, 0x01, 0x00, 0x00, 0x10}, + {0xD1, 0x5D, 0x22, 0x00, 0x00, 0x00, 0x00, 0x10}, + {0xD1, 0x5D, 0x24, 0x00, 0x00, 0x00, 0x00, 0x10}, + {0xD1, 0x5D, 0x26, 0x00, 0x00, 0x00, 0x24, 0x10}, + {0xD1, 0x5D, 0x2F, 0xF7, 0xB0, 0x00, 0x04, 0x10}, + {0xD1, 0x5D, 0x31, 0x00, 0x00, 0x00, 0x00, 0x10}, + {0xD1, 0x5D, 0x33, 0x00, 0x00, 0x01, 0x00, 0x10}, + {0xB1, 0x5D, 0x3D, 0x06, 0x8F, 0x00, 0x00, 0x10}, + {0xD1, 0x5D, 0x40, 0x01, 0xE0, 0x00, 0xD1, 0x10}, + {0xB1, 0x5D, 0x44, 0x00, 0x82, 0x00, 0x00, 0x10}, + {0xD1, 0x5D, 0x58, 0x00, 0x78, 0x00, 0x43, 0x10}, + {0xD1, 0x5D, 0x5A, 0x00, 0x00, 0x00, 0x00, 0x10}, + {0xD1, 0x5D, 0x5C, 0x00, 0x00, 0x00, 0x00, 0x10}, + {0xD1, 0x5D, 0x5E, 0x00, 0x00, 0xA3, 0x1D, 0x10}, + {0xB1, 0x5D, 0x62, 0x04, 0x11, 0x00, 0x00, 0x10}, + + {0xB1, 0x5D, 0x20, 0x91, 0x01, 0x00, 0x00, 0x10}, + {0xB1, 0x5D, 0x20, 0x11, 0x01, 0x00, 0x00, 0x10}, + {0xB1, 0x5D, 0x09, 0x00, 0x64, 0x00, 0x00, 0x10}, + {0xD1, 0x5D, 0x2B, 0x00, 0xA0, 0x00, 0xB0, 0x10}, + {0xD1, 0x5D, 0x2D, 0x00, 0xA0, 0x00, 0xA0, 0x10}, + + {0xB1, 0x5D, 0x0A, 0x00, 0x02, 0x00, 0x00, 0x10}, /* sensor clck ?2 */ + {0xB1, 0x5D, 0x06, 0x00, 0x30, 0x00, 0x00, 0x10}, + {0xB1, 0x5D, 0x05, 0x00, 0x0A, 0x00, 0x00, 0x10}, + {0xB1, 0x5D, 0x09, 0x02, 0x35, 0x00, 0x00, 0x10}, /* exposure 2 */ + + {0xD1, 0x5D, 0x2B, 0x00, 0xB9, 0x00, 0xE3, 0x10}, + {0xD1, 0x5D, 0x2D, 0x00, 0x5f, 0x00, 0xB9, 0x10}, /* 42 */ +/* {0xB1, 0x5D, 0x35, 0x00, 0x67, 0x00, 0x00, 0x10}, * gain orig */ +/* {0xB1, 0x5D, 0x35, 0x00, 0x20, 0x00, 0x00, 0x10}, * gain */ + {0xB1, 0x5D, 0x07, 0x00, 0x03, 0x00, 0x00, 0x10}, /* update */ + {0xB1, 0x5D, 0x07, 0x00, 0x02, 0x00, 0x00, 0x10}, /* sensor on */ + {} +}; +static const __u8 mo4000_sensor_init[][8] = { + {0xa1, 0x21, 0x01, 0x02, 0x00, 0x00, 0x00, 0x10}, + {0xa1, 0x21, 0x02, 0x00, 0x00, 0x00, 0x00, 0x10}, + {0xa1, 0x21, 0x03, 0x00, 0x00, 0x00, 0x00, 0x10}, + {0xa1, 0x21, 0x04, 0x00, 0x00, 0x00, 0x00, 0x10}, + {0xa1, 0x21, 0x05, 0x00, 0x00, 0x00, 0x00, 0x10}, + {0xa1, 0x21, 0x05, 0x04, 0x00, 0x00, 0x00, 0x10}, + {0xa1, 0x21, 0x06, 0x80, 0x00, 0x00, 0x00, 0x10}, + {0xa1, 0x21, 0x06, 0x81, 0x00, 0x00, 0x00, 0x10}, + {0xa1, 0x21, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x10}, + {0xa1, 0x21, 0x11, 0x00, 0x00, 0x00, 0x00, 0x10}, + {0xa1, 0x21, 0x11, 0x20, 0x00, 0x00, 0x00, 0x10}, + {0xa1, 0x21, 0x11, 0x30, 0x00, 0x00, 0x00, 0x10}, + {0xa1, 0x21, 0x11, 0x38, 0x00, 0x00, 0x00, 0x10}, + {0xa1, 0x21, 0x11, 0x38, 0x00, 0x00, 0x00, 0x10}, + {0xa1, 0x21, 0x12, 0x00, 0x00, 0x00, 0x00, 0x10}, + {0xa1, 0x21, 0x10, 0x00, 0x00, 0x00, 0x00, 0x10}, + {0xa1, 0x21, 0x0f, 0x20, 0x00, 0x00, 0x00, 0x10}, + {0xa1, 0x21, 0x10, 0x20, 0x00, 0x00, 0x00, 0x10}, + {0xa1, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10}, + {0xa1, 0x21, 0x11, 0x38, 0x00, 0x00, 0x00, 0x10}, + {} +}; +static const __u8 ov7660_sensor_init[][8] = { + {0xa1, 0x21, 0x12, 0x80, 0x00, 0x00, 0x00, 0x10}, /* reset SCCB */ + {0xa1, 0x21, 0x12, 0x05, 0x00, 0x00, 0x00, 0x10}, + /* Outformat ?? rawRGB */ + {0xa1, 0x21, 0x13, 0xb8, 0x00, 0x00, 0x00, 0x10}, /* init COM8 */ + {0xd1, 0x21, 0x00, 0x01, 0x74, 0x92, 0x00, 0x10}, +/* {0xd1, 0x21, 0x00, 0x01, 0x74, 0x74, 0x00, 0x10}, */ + /* GAIN BLUE RED VREF */ + {0xd1, 0x21, 0x04, 0x00, 0x7d, 0x62, 0x00, 0x10}, + /* COM 1 BAVE GEAVE AECHH */ + {0xb1, 0x21, 0x08, 0x83, 0x01, 0x00, 0x00, 0x10}, /* RAVE COM2 */ + {0xd1, 0x21, 0x0c, 0x00, 0x08, 0x04, 0x4f, 0x10}, /* COM 3 4 5 6 */ + {0xd1, 0x21, 0x10, 0x7f, 0x40, 0x05, 0xf8, 0x10}, +/* {0xd1, 0x21, 0x10, 0x7f, 0x40, 0x05, 0xff, 0x10}, */ + /* AECH CLKRC COM7 COM8 */ + {0xc1, 0x21, 0x14, 0x2c, 0x00, 0x02, 0x00, 0x10}, /* COM9 COM10 */ + {0xd1, 0x21, 0x17, 0x10, 0x60, 0x02, 0x7b, 0x10}, + /* HSTART HSTOP VSTRT VSTOP */ + {0xa1, 0x21, 0x1b, 0x02, 0x00, 0x00, 0x00, 0x10}, /* PSHFT */ + {0xb1, 0x21, 0x1e, 0x01, 0x0e, 0x00, 0x00, 0x10}, /* MVFP LAEC */ + {0xd1, 0x21, 0x20, 0x07, 0x07, 0x07, 0x07, 0x10}, + /* BOS GBOS GROS ROS (BGGR offset) */ + {0xd1, 0x21, 0x24, 0x68, 0x58, 0xd4, 0x80, 0x10}, +/* {0xd1, 0x21, 0x24, 0x78, 0x68, 0xd4, 0x80, 0x10}, */ + /* AEW AEB VPT BBIAS */ + {0xd1, 0x21, 0x28, 0x80, 0x30, 0x00, 0x00, 0x10}, + /* GbBIAS RSVD EXHCH EXHCL */ + {0xd1, 0x21, 0x2c, 0x80, 0x00, 0x00, 0x62, 0x10}, + /* RBIAS ADVFL ASDVFH YAVE */ + {0xc1, 0x21, 0x30, 0x08, 0x30, 0xb4, 0x00, 0x10}, + /* HSYST HSYEN HREF */ + {0xd1, 0x21, 0x33, 0x00, 0x07, 0x84, 0x00, 0x10}, /* reserved */ + {0xd1, 0x21, 0x37, 0x0c, 0x02, 0x43, 0x00, 0x10}, + /* ADC ACOM OFON TSLB */ + {0xd1, 0x21, 0x3b, 0x02, 0x6c, 0x19, 0x0e, 0x10}, + /* COM11 COM12 COM13 COM14 */ + {0xd1, 0x21, 0x3f, 0x41, 0xc1, 0x22, 0x08, 0x10}, + /* EDGE COM15 COM16 COM17 */ + {0xd1, 0x21, 0x43, 0xf0, 0x10, 0x78, 0xa8, 0x10}, /* reserved */ + {0xd1, 0x21, 0x47, 0x60, 0x80, 0x00, 0x00, 0x10}, /* reserved */ + {0xd1, 0x21, 0x4b, 0x00, 0x00, 0x00, 0x00, 0x10}, /* reserved */ + {0xd1, 0x21, 0x4f, 0x46, 0x36, 0x0f, 0x17, 0x10}, /* MTX 1 2 3 4 */ + {0xd1, 0x21, 0x53, 0x7f, 0x96, 0x40, 0x40, 0x10}, /* MTX 5 6 7 8 */ + {0xb1, 0x21, 0x57, 0x40, 0x0f, 0x00, 0x00, 0x10}, /* MTX9 MTXS */ + {0xd1, 0x21, 0x59, 0xba, 0x9a, 0x22, 0xb9, 0x10}, /* reserved */ + {0xd1, 0x21, 0x5d, 0x9b, 0x10, 0xf0, 0x05, 0x10}, /* reserved */ + {0xa1, 0x21, 0x61, 0x60, 0x00, 0x00, 0x00, 0x10}, /* reserved */ + {0xd1, 0x21, 0x62, 0x00, 0x00, 0x50, 0x30, 0x10}, + /* LCC1 LCC2 LCC3 LCC4 */ + {0xa1, 0x21, 0x66, 0x00, 0x00, 0x00, 0x00, 0x10}, /* LCC5 */ + {0xd1, 0x21, 0x67, 0x80, 0x7a, 0x90, 0x80, 0x10}, + {0xa1, 0x21, 0x6b, 0x0a, 0x00, 0x00, 0x00, 0x10}, + /* band gap reference [0..3] DBLV */ + {0xd1, 0x21, 0x6c, 0x30, 0x48, 0x80, 0x74, 0x10}, /* gamma curve */ + {0xd1, 0x21, 0x70, 0x64, 0x60, 0x5c, 0x58, 0x10}, /* gamma curve */ + {0xd1, 0x21, 0x74, 0x54, 0x4c, 0x40, 0x38, 0x10}, /* gamma curve */ + {0xd1, 0x21, 0x78, 0x34, 0x30, 0x2f, 0x2b, 0x10}, /* gamma curve */ + {0xd1, 0x21, 0x7c, 0x03, 0x07, 0x17, 0x34, 0x10}, /* gamma curve */ + {0xd1, 0x21, 0x80, 0x41, 0x4d, 0x58, 0x63, 0x10}, /* gamma curve */ + {0xd1, 0x21, 0x84, 0x6e, 0x77, 0x87, 0x95, 0x10}, /* gamma curve */ + {0xc1, 0x21, 0x88, 0xaf, 0xc7, 0xdf, 0x00, 0x10}, /* gamma curve */ + {0xc1, 0x21, 0x8b, 0x99, 0x99, 0xcf, 0x00, 0x10}, /* reserved */ + {0xb1, 0x21, 0x92, 0x00, 0x00, 0x00, 0x00, 0x10}, +/****** (some exchanges in the win trace) ******/ + {0xa1, 0x21, 0x1e, 0x01, 0x00, 0x00, 0x00, 0x10}, + /* bits[3..0]reserved */ + {0xa1, 0x21, 0x1e, 0x01, 0x00, 0x00, 0x00, 0x10}, + {0xa1, 0x21, 0x03, 0x00, 0x00, 0x00, 0x00, 0x10}, + /* VREF vertical frame ctrl */ + {0xa1, 0x21, 0x03, 0x00, 0x00, 0x00, 0x00, 0x10}, + {0xa1, 0x21, 0x10, 0x20, 0x00, 0x00, 0x00, 0x10}, /* 0x20 */ + {0xa1, 0x21, 0x2d, 0x00, 0x00, 0x00, 0x00, 0x10}, + {0xa1, 0x21, 0x2e, 0x00, 0x00, 0x00, 0x00, 0x10}, +/* {0xa1, 0x21, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x10}, */ + {0xa1, 0x21, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x10}, + {0xb1, 0x21, 0x01, 0x78, 0x78, 0x00, 0x00, 0x10}, +/****** (some exchanges in the win trace) ******/ + {0xa1, 0x21, 0x93, 0x00, 0x00, 0x00, 0x00, 0x10},/* dummy line hight */ + {0xa1, 0x21, 0x92, 0x25, 0x00, 0x00, 0x00, 0x10},/* dummy line low */ + {0xa1, 0x21, 0x2a, 0x00, 0x00, 0x00, 0x00, 0x10}, + {0xa1, 0x21, 0x2b, 0x00, 0x00, 0x00, 0x00, 0x10}, + {0xa1, 0x21, 0x02, 0x90, 0x00, 0x00, 0x00, 0x10}, +/****** (some exchanges in the win trace) ******/ +/**********startsensor KO if changed !!****/ + {0xa1, 0x21, 0x93, 0x01, 0x00, 0x00, 0x00, 0x10}, + {0xa1, 0x21, 0x92, 0xff, 0x00, 0x00, 0x00, 0x10}, + {0xa1, 0x21, 0x2a, 0x00, 0x00, 0x00, 0x00, 0x10}, + {0xa1, 0x21, 0x2b, 0xc3, 0x00, 0x00, 0x00, 0x10}, +/* here may start the isoc exchanges */ + {} +}; +/* reg0x04 reg0x07 reg 0x10 */ +/* expo = (COM1 & 0x02) | (AECHH & 0x2f <<10) [ (AECh << 2) */ + +static const __u8 ov7648_sensor_init[][8] = { + {0xC1, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00}, + {0xC1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00}, + {0xC1, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00}, + {0xA1, 0x6E, 0x3F, 0x20, 0x00, 0x00, 0x00, 0x10}, + {0xA1, 0x6E, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x10}, + {0xA1, 0x6E, 0x3E, 0x00, 0x00, 0x00, 0x00, 0x10}, + {0xD1, 0x6E, 0x04, 0x02, 0xB1, 0x02, 0x39, 0x10}, + {0xD1, 0x6E, 0x08, 0x00, 0x01, 0x00, 0x00, 0x10}, + {0xD1, 0x6E, 0x0C, 0x02, 0x7F, 0x01, 0xE0, 0x10}, + {0xD1, 0x6E, 0x12, 0x03, 0x02, 0x00, 0x03, 0x10}, + {0xD1, 0x6E, 0x16, 0x85, 0x40, 0x4A, 0x40, 0x10}, + {0xC1, 0x6E, 0x1A, 0x00, 0x80, 0x00, 0x00, 0x10}, + {0xD1, 0x6E, 0x1D, 0x08, 0x03, 0x00, 0x00, 0x10}, + {0xD1, 0x6E, 0x23, 0x00, 0xB0, 0x00, 0x94, 0x10}, + {0xD1, 0x6E, 0x27, 0x58, 0x00, 0x00, 0x00, 0x10}, + {0xD1, 0x6E, 0x2D, 0x14, 0x35, 0x61, 0x84, 0x10}, + {0xD1, 0x6E, 0x31, 0xA2, 0xBD, 0xD8, 0xFF, 0x10}, + {0xD1, 0x6E, 0x35, 0x06, 0x1E, 0x12, 0x02, 0x10}, + {0xD1, 0x6E, 0x39, 0xAA, 0x53, 0x37, 0xD5, 0x10}, + {0xA1, 0x6E, 0x3D, 0xF2, 0x00, 0x00, 0x00, 0x10}, + {0xD1, 0x6E, 0x3E, 0x00, 0x00, 0x80, 0x03, 0x10}, + {0xD1, 0x6E, 0x42, 0x03, 0x00, 0x00, 0x00, 0x10}, + {0xC1, 0x6E, 0x46, 0x00, 0x80, 0x80, 0x00, 0x10}, + {0xD1, 0x6E, 0x4B, 0x02, 0xEF, 0x08, 0xCD, 0x10}, + {0xD1, 0x6E, 0x4F, 0x00, 0xD0, 0x00, 0xA0, 0x10}, + {0xD1, 0x6E, 0x53, 0x01, 0xAA, 0x01, 0x40, 0x10}, + {0xD1, 0x6E, 0x5A, 0x50, 0x04, 0x30, 0x03, 0x10}, + {0xA1, 0x6E, 0x5E, 0x00, 0x00, 0x00, 0x00, 0x10}, + {0xD1, 0x6E, 0x5F, 0x10, 0x40, 0xFF, 0x00, 0x10}, + /* {0xD1, 0x6E, 0x63, 0x40, 0x40, 0x00, 0x00, 0x10}, + {0xD1, 0x6E, 0x67, 0x00, 0x00, 0x00, 0x00, 0x10}, + * This is currently setting a + * blue tint, and some things more , i leave it here for future test if + * somene is having problems with color on this sensor + {0xD1, 0x6E, 0x6B, 0x00, 0x00, 0x00, 0x00, 0x10}, + {0xD1, 0x6E, 0x6F, 0x00, 0x00, 0x00, 0x00, 0x10}, + {0xC1, 0x6E, 0x73, 0x10, 0x80, 0xEB, 0x00, 0x10}, + {0xA1, 0x6E, 0x1E, 0x03, 0x00, 0x00, 0x00, 0x10}, + {0xA1, 0x6E, 0x15, 0x01, 0x00, 0x00, 0x00, 0x10}, + {0xC1, 0x6E, 0x16, 0x40, 0x40, 0x40, 0x00, 0x10}, + {0xA1, 0x6E, 0x1D, 0x08, 0x00, 0x00, 0x00, 0x10}, + {0xA1, 0x6E, 0x06, 0x02, 0x00, 0x00, 0x00, 0x10}, + {0xA1, 0x6E, 0x07, 0xB5, 0x00, 0x00, 0x00, 0x10}, + {0xA1, 0x6E, 0x18, 0x6B, 0x00, 0x00, 0x00, 0x10}, + {0xA1, 0x6E, 0x1D, 0x08, 0x00, 0x00, 0x00, 0x10}, + {0xA1, 0x6E, 0x06, 0x02, 0x00, 0x00, 0x00, 0x10}, + {0xA1, 0x6E, 0x07, 0xB8, 0x00, 0x00, 0x00, 0x10}, */ + {0xC1, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00}, + {0xA1, 0x6E, 0x06, 0x03, 0x00, 0x00, 0x00, 0x10}, /* Bright... */ + {0xA1, 0x6E, 0x07, 0x66, 0x00, 0x00, 0x00, 0x10}, /* B.. */ + {0xC1, 0x6E, 0x1A, 0x03, 0x65, 0x90, 0x00, 0x10}, /* Bright/Witen....*/ +/* {0xC1, 0x6E, 0x16, 0x45, 0x40, 0x60, 0x00, 0x10}, * Bright/Witene */ + {} +}; + +static const __u8 qtable4[] = { + 0x06, 0x04, 0x04, 0x06, 0x04, 0x04, 0x06, 0x06, 0x06, 0x06, 0x08, 0x06, + 0x06, 0x08, 0x0A, 0x11, + 0x0A, 0x0A, 0x08, 0x08, 0x0A, 0x15, 0x0F, 0x0F, 0x0C, 0x11, 0x19, 0x15, + 0x19, 0x19, 0x17, 0x15, + 0x17, 0x17, 0x1B, 0x1D, 0x25, 0x21, 0x1B, 0x1D, 0x23, 0x1D, 0x17, 0x17, + 0x21, 0x2E, 0x21, 0x23, + 0x27, 0x29, 0x2C, 0x2C, 0x2C, 0x19, 0x1F, 0x30, 0x32, 0x2E, 0x29, 0x32, + 0x25, 0x29, 0x2C, 0x29, + 0x06, 0x08, 0x08, 0x0A, 0x08, 0x0A, 0x13, 0x0A, 0x0A, 0x13, 0x29, 0x1B, + 0x17, 0x1B, 0x29, 0x29, + 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0x29, 0x29, 0x29, 0x29, + 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0x29, 0x29, 0x29, 0x29, + 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0x29, 0x29, 0x29, 0x29 +}; + +/* read <len> bytes (len < sizeof gspca_dev->usb_buf) to gspca_dev->usb_buf */ +static void reg_r(struct gspca_dev *gspca_dev, + __u16 value, int len) +{ + usb_control_msg(gspca_dev->dev, + usb_rcvctrlpipe(gspca_dev->dev, 0), + 0, + USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_INTERFACE, + value, 0, + gspca_dev->usb_buf, len, + 500); +} + +static void reg_w(struct gspca_dev *gspca_dev, + __u16 value, + const __u8 *buffer, + int len) +{ + if (len <= sizeof gspca_dev->usb_buf) { + memcpy(gspca_dev->usb_buf, buffer, len); + usb_control_msg(gspca_dev->dev, + usb_sndctrlpipe(gspca_dev->dev, 0), + 0x08, + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE, + value, 0, + gspca_dev->usb_buf, len, + 500); + } else { + __u8 *tmpbuf; + + tmpbuf = kmalloc(len, GFP_KERNEL); + memcpy(tmpbuf, buffer, len); + usb_control_msg(gspca_dev->dev, + usb_sndctrlpipe(gspca_dev->dev, 0), + 0x08, + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE, + value, 0, + tmpbuf, len, + 500); + kfree(tmpbuf); + } +} + +/* I2C write 2 bytes */ +static void i2c_w2(struct gspca_dev *gspca_dev, + const __u8 *buffer) +{ + struct sd *sd = (struct sd *) gspca_dev; + __u8 mode[8]; + + /* is i2c ready */ + mode[0] = 0x81 | (2 << 4); + mode[1] = sd->i2c_base; + mode[2] = buffer[0]; + mode[3] = buffer[1]; + mode[4] = 0; + mode[5] = 0; + mode[6] = 0; + mode[7] = 0x10; + reg_w(gspca_dev, 0x08, mode, 8); +} + +/* I2C write 8 bytes */ +static void i2c_w8(struct gspca_dev *gspca_dev, + const __u8 *buffer) +{ + reg_w(gspca_dev, 0x08, buffer, 8); + msleep(1); +} + +/* read 5 bytes in gspca_dev->usb_buf */ +static void i2c_r5(struct gspca_dev *gspca_dev, __u8 reg) +{ + struct sd *sd = (struct sd *) gspca_dev; + __u8 mode[8]; + + mode[0] = 0x81 | 0x10; + mode[1] = sd->i2c_base; + mode[2] = reg; + mode[3] = 0; + mode[4] = 0; + mode[5] = 0; + mode[6] = 0; + mode[7] = 0x10; + i2c_w8(gspca_dev, mode); + mode[0] = 0x81 | (5 << 4) | 0x02; + mode[2] = 0; + i2c_w8(gspca_dev, mode); + reg_r(gspca_dev, 0x0a, 5); +} + +static int probesensor(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + __u8 reg02; + static const __u8 datasend[] = { 2, 0 }; + /* reg val1 val2 val3 val4 */ + + i2c_w2(gspca_dev, datasend); +/* should write 0xa1 0x11 0x02 0x00 0x00 0x00 0x00 the 0x10 is add by i2cw */ + msleep(10); + reg02 = 0x66; + reg_w(gspca_dev, 0x02, ®02, 1); /* Gpio on */ + msleep(10); + i2c_r5(gspca_dev, 0); /* read sensor id */ + if (gspca_dev->usb_buf[0] == 0x02 + && gspca_dev->usb_buf[1] == 0x09 + && gspca_dev->usb_buf[2] == 0x01 + && gspca_dev->usb_buf[3] == 0x00 + && gspca_dev->usb_buf[4] == 0x00) { + PDEBUG(D_PROBE, "Find Sensor sn9c102P HV7131R"); + sd->sensor = SENSOR_HV7131R; + return SENSOR_HV7131R; + } + PDEBUG(D_PROBE, "Find Sensor %d %d %d", + gspca_dev->usb_buf[0], gspca_dev->usb_buf[1], + gspca_dev->usb_buf[2]); + PDEBUG(D_PROBE, "Sensor sn9c102P Not found"); + return -ENODEV; +} + +static int configure_gpio(struct gspca_dev *gspca_dev, + const __u8 *sn9c1xx) +{ + struct sd *sd = (struct sd *) gspca_dev; + __u8 data; + __u8 regF1; + const __u8 *reg9a; + static const __u8 reg9a_def[] = + {0x08, 0x40, 0x20, 0x10, 0x00, 0x04}; + static const __u8 reg9a_sn9c120[] = /* from win trace */ + {0x00, 0x40, 0x38, 0x30, 0x00, 0x20}; + static const __u8 reg9a_sn9c325[] = + {0x0a, 0x40, 0x38, 0x30, 0x00, 0x20}; + + + regF1 = 0x00; + reg_w(gspca_dev, 0xf1, ®F1, 1); + reg_w(gspca_dev, 0x01, &sn9c1xx[0], 1); /*fixme:jfm was [1] en v1*/ + + /* configure gpio */ + reg_w(gspca_dev, 0x01, &sn9c1xx[1], 2); + reg_w(gspca_dev, 0x08, &sn9c1xx[8], 2); + reg_w(gspca_dev, 0x17, &sn9c1xx[0x17], 5); /* jfm was 3 */ + switch (sd->bridge) { + case BRIDGE_SN9C325: + reg9a = reg9a_sn9c325; + break; + case BRIDGE_SN9C120: + reg9a = reg9a_sn9c120; + break; + default: + reg9a = reg9a_def; + break; + } + reg_w(gspca_dev, 0x9a, reg9a, 6); + + data = 0x60; /*fixme:jfm 60 00 00 (3) */ + reg_w(gspca_dev, 0xd4, &data, 1); + + reg_w(gspca_dev, 0x03, &sn9c1xx[3], 0x0f); + + switch (sd->bridge) { + case BRIDGE_SN9C120: /* from win trace */ + data = 0x61; + reg_w(gspca_dev, 0x01, &data, 1); + data = 0x20; + reg_w(gspca_dev, 0x17, &data, 1); + data = 0x60; + reg_w(gspca_dev, 0x01, &data, 1); + break; + case BRIDGE_SN9C325: + data = 0x43; + reg_w(gspca_dev, 0x01, &data, 1); + data = 0xae; + reg_w(gspca_dev, 0x17, &data, 1); + data = 0x42; + reg_w(gspca_dev, 0x01, &data, 1); + break; + default: + data = 0x43; + reg_w(gspca_dev, 0x01, &data, 1); + data = 0x61; + reg_w(gspca_dev, 0x17, &data, 1); + data = 0x42; + reg_w(gspca_dev, 0x01, &data, 1); + } + + if (sd->sensor == SENSOR_HV7131R) { + if (probesensor(gspca_dev) < 0) + return -ENODEV; + } + return 0; +} + +static void hv7131R_InitSensor(struct gspca_dev *gspca_dev) +{ + int i = 0; + static const __u8 SetSensorClk[] = /* 0x08 Mclk */ + { 0xa1, 0x11, 0x01, 0x18, 0x00, 0x00, 0x00, 0x10 }; + + while (hv7131r_sensor_init[i][0]) { + i2c_w8(gspca_dev, hv7131r_sensor_init[i]); + i++; + } + i2c_w8(gspca_dev, SetSensorClk); +} + +static void mi0360_InitSensor(struct gspca_dev *gspca_dev) +{ + int i = 0; + + while (mi0360_sensor_init[i][0]) { + i2c_w8(gspca_dev, mi0360_sensor_init[i]); + i++; + } +} + +static void mo4000_InitSensor(struct gspca_dev *gspca_dev) +{ + int i = 0; + + while (mo4000_sensor_init[i][0]) { + i2c_w8(gspca_dev, mo4000_sensor_init[i]); + i++; + } +} + +static void ov7648_InitSensor(struct gspca_dev *gspca_dev) +{ + int i = 0; + + while (ov7648_sensor_init[i][0]) { + i2c_w8(gspca_dev, ov7648_sensor_init[i]); + i++; + } +} + +static void ov7660_InitSensor(struct gspca_dev *gspca_dev) +{ + int i = 0; + + while (ov7660_sensor_init[i][0]) { + i2c_w8(gspca_dev, ov7660_sensor_init[i]); + i++; + } +} + +/* this function is called at probe time */ +static int sd_config(struct gspca_dev *gspca_dev, + const struct usb_device_id *id) +{ + struct sd *sd = (struct sd *) gspca_dev; + struct cam *cam; + __u16 vendor; + __u16 product; + + vendor = id->idVendor; + product = id->idProduct; + sd->sensor = -1; + switch (vendor) { + case 0x0458: /* Genius */ +/* switch (product) { + case 0x7025: */ + sd->bridge = BRIDGE_SN9C120; + sd->sensor = SENSOR_MI0360; + sd->i2c_base = 0x5d; +/* break; + } */ + break; + case 0x045e: +/* switch (product) { + case 0x00f5: + case 0x00f7: */ + sd->bridge = BRIDGE_SN9C105; + sd->sensor = SENSOR_OV7660; + sd->i2c_base = 0x21; +/* break; + } */ + break; + case 0x0471: /* Philips */ +/* switch (product) { + case 0x0327: + case 0x0328: + case 0x0330: */ + sd->bridge = BRIDGE_SN9C105; + sd->sensor = SENSOR_MI0360; + sd->i2c_base = 0x5d; +/* break; + } */ + break; + case 0x0c45: /* Sonix */ + switch (product) { + case 0x6040: + sd->bridge = BRIDGE_SN9C102P; +/* sd->sensor = SENSOR_MI0360; * from BW600.inf */ +/*fixme: MI0360 base=5d ? */ + sd->sensor = SENSOR_HV7131R; /* gspcav1 value */ + sd->i2c_base = 0x11; + break; +/* case 0x607a: * from BW600.inf + sd->bridge = BRIDGE_SN9C102P; + sd->sensor = SENSOR_OV7648; + sd->i2c_base = 0x??; + break; */ + case 0x607c: + sd->bridge = BRIDGE_SN9C102P; + sd->sensor = SENSOR_HV7131R; + sd->i2c_base = 0x11; + break; +/* case 0x607e: * from BW600.inf + sd->bridge = BRIDGE_SN9C102P; + sd->sensor = SENSOR_OV7630; + sd->i2c_base = 0x??; + break; */ + case 0x60c0: + sd->bridge = BRIDGE_SN9C105; + sd->sensor = SENSOR_MI0360; + sd->i2c_base = 0x5d; + break; +/* case 0x60c8: * from BW600.inf + sd->bridge = BRIDGE_SN9C105; + sd->sensor = SENSOR_OM6801; + sd->i2c_base = 0x??; + break; */ +/* case 0x60cc: * from BW600.inf + sd->bridge = BRIDGE_SN9C105; + sd->sensor = SENSOR_HV7131GP; + sd->i2c_base = 0x??; + break; */ + case 0x60ec: + sd->bridge = BRIDGE_SN9C105; + sd->sensor = SENSOR_MO4000; + sd->i2c_base = 0x21; + break; +/* case 0x60ef: * from BW600.inf + sd->bridge = BRIDGE_SN9C105; + sd->sensor = SENSOR_ICM105C; + sd->i2c_base = 0x??; + break; */ +/* case 0x60fa: * from BW600.inf + sd->bridge = BRIDGE_SN9C105; + sd->sensor = SENSOR_OV7648; + sd->i2c_base = 0x??; + break; */ + case 0x60fb: + sd->bridge = BRIDGE_SN9C105; + sd->sensor = SENSOR_OV7660; + sd->i2c_base = 0x21; + break; + case 0x60fc: + sd->bridge = BRIDGE_SN9C105; + sd->sensor = SENSOR_HV7131R; + sd->i2c_base = 0x11; + break; +/* case 0x60fe: * from BW600.inf + sd->bridge = BRIDGE_SN9C105; + sd->sensor = SENSOR_OV7630; + sd->i2c_base = 0x??; + break; */ +/* case 0x6108: * from BW600.inf + sd->bridge = BRIDGE_SN9C120; + sd->sensor = SENSOR_OM6801; + sd->i2c_base = 0x??; + break; */ +/* case 0x6122: * from BW600.inf + sd->bridge = BRIDGE_SN9C110; + sd->sensor = SENSOR_ICM105C; + sd->i2c_base = 0x??; + break; */ + case 0x612a: +/* sd->bridge = BRIDGE_SN9C110; * in BW600.inf */ + sd->bridge = BRIDGE_SN9C325; + sd->sensor = SENSOR_OV7648; + sd->i2c_base = 0x21; +/*fixme: sensor_init has base = 00 et 6e!*/ + break; +/* case 0x6123: * from BW600.inf + sd->bridge = BRIDGE_SN9C110; + sd->sensor = SENSOR_SanyoCCD; + sd->i2c_base = 0x??; + break; */ + case 0x612c: + sd->bridge = BRIDGE_SN9C110; + sd->sensor = SENSOR_MO4000; + sd->i2c_base = 0x21; + break; +/* case 0x612e: * from BW600.inf + sd->bridge = BRIDGE_SN9C110; + sd->sensor = SENSOR_OV7630; + sd->i2c_base = 0x??; + break; */ +/* case 0x612f: * from BW600.inf + sd->bridge = BRIDGE_SN9C110; + sd->sensor = SENSOR_ICM105C; + sd->i2c_base = 0x??; + break; */ + case 0x6130: + sd->bridge = BRIDGE_SN9C120; + sd->sensor = SENSOR_MI0360; + sd->i2c_base = 0x5d; + break; + case 0x6138: + sd->bridge = BRIDGE_SN9C120; + sd->sensor = SENSOR_MO4000; + sd->i2c_base = 0x21; + break; +/* case 0x613a: * from BW600.inf + sd->bridge = BRIDGE_SN9C120; + sd->sensor = SENSOR_OV7648; + sd->i2c_base = 0x??; + break; */ + case 0x613b: + sd->bridge = BRIDGE_SN9C120; + sd->sensor = SENSOR_OV7660; + sd->i2c_base = 0x21; + break; + case 0x613c: + sd->bridge = BRIDGE_SN9C120; + sd->sensor = SENSOR_HV7131R; + sd->i2c_base = 0x11; + break; +/* case 0x613e: * from BW600.inf + sd->bridge = BRIDGE_SN9C120; + sd->sensor = SENSOR_OV7630; + sd->i2c_base = 0x??; + break; */ + } + break; + } + if (sd->sensor < 0) { + PDEBUG(D_ERR, "Invalid vendor/product %04x:%04x", + vendor, product); + return -EINVAL; + } + + cam = &gspca_dev->cam; + cam->dev_name = (char *) id->driver_info; + cam->epaddr = 0x01; + cam->cam_mode = vga_mode; + cam->nmodes = ARRAY_SIZE(vga_mode); + + sd->qindex = 4; /* set the quantization table */ + sd->brightness = BRIGHTNESS_DEF; + sd->contrast = CONTRAST_DEF; + sd->colors = COLOR_DEF; + sd->autogain = AUTOGAIN_DEF; + return 0; +} + +/* this function is called at open time */ +static int sd_open(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; +/* const __u8 *sn9c1xx; */ + __u8 regF1; + __u8 regGpio[] = { 0x29, 0x74 }; + + /* setup a selector by bridge */ + regF1 = 0x01; + reg_w(gspca_dev, 0xf1, ®F1, 1); + reg_r(gspca_dev, 0x00, 1); /* -> regF1 = 0x00 */ + regF1 = gspca_dev->usb_buf[0]; + reg_w(gspca_dev, 0xf1, ®F1, 1); + reg_r(gspca_dev, 0x00, 1); + regF1 = gspca_dev->usb_buf[0]; + switch (sd->bridge) { + case BRIDGE_SN9C102P: + if (regF1 != 0x11) + return -ENODEV; + reg_w(gspca_dev, 0x02, ®Gpio[1], 1); + break; + case BRIDGE_SN9C105: + if (regF1 != 0x11) + return -ENODEV; + reg_w(gspca_dev, 0x02, regGpio, 2); + break; + case BRIDGE_SN9C110: + if (regF1 != 0x12) + return -ENODEV; + regGpio[1] = 0x62; + reg_w(gspca_dev, 0x02, ®Gpio[1], 1); + break; + case BRIDGE_SN9C120: + if (regF1 != 0x12) + return -ENODEV; + regGpio[1] = 0x70; + reg_w(gspca_dev, 0x02, regGpio, 2); + break; + default: +/* case BRIDGE_SN9C325: */ + if (regF1 != 0x12) + return -ENODEV; + regGpio[1] = 0x62; + reg_w(gspca_dev, 0x02, ®Gpio[1], 1); + break; + } + + regF1 = 0x01; + reg_w(gspca_dev, 0xf1, ®F1, 1); + + return 0; +} + +static unsigned int setexposure(struct gspca_dev *gspca_dev, + unsigned int expo) +{ + struct sd *sd = (struct sd *) gspca_dev; + static const __u8 doit[] = /* update sensor */ + { 0xb1, 0x5d, 0x07, 0x00, 0x03, 0x00, 0x00, 0x10 }; + static const __u8 sensorgo[] = /* sensor on */ + { 0xb1, 0x5d, 0x07, 0x00, 0x02, 0x00, 0x00, 0x10 }; + static const __u8 gainMo[] = + { 0xa1, 0x21, 0x00, 0x10, 0x00, 0x00, 0x00, 0x1d }; + + switch (sd->sensor) { + case SENSOR_HV7131R: { + __u8 Expodoit[] = + { 0xc1, 0x11, 0x25, 0x07, 0x27, 0xc0, 0x00, 0x16 }; + + Expodoit[3] = expo >> 16; + Expodoit[4] = expo >> 8; + Expodoit[5] = expo; + i2c_w8(gspca_dev, Expodoit); + break; + } + case SENSOR_MI0360: { + __u8 expoMi[] = /* exposure 0x0635 -> 4 fp/s 0x10 */ + { 0xb1, 0x5d, 0x09, 0x06, 0x35, 0x00, 0x00, 0x16 }; + + if (expo > 0x0635) + expo = 0x0635; + else if (expo < 0x0001) + expo = 0x0001; + expoMi[3] = expo >> 8; + expoMi[4] = expo; + i2c_w8(gspca_dev, expoMi); + i2c_w8(gspca_dev, doit); + i2c_w8(gspca_dev, sensorgo); + break; + } + case SENSOR_MO4000: { + __u8 expoMof[] = + { 0xa1, 0x21, 0x0f, 0x20, 0x00, 0x00, 0x00, 0x10 }; + __u8 expoMo10[] = + { 0xa1, 0x21, 0x10, 0x20, 0x00, 0x00, 0x00, 0x10 }; + + if (expo > 0x1fff) + expo = 0x1fff; + else if (expo < 0x0001) + expo = 0x0001; + expoMof[3] = (expo & 0x03fc) >> 2; + i2c_w8(gspca_dev, expoMof); + expoMo10[3] = ((expo & 0x1c00) >> 10) + | ((expo & 0x0003) << 4); + i2c_w8(gspca_dev, expoMo10); + i2c_w8(gspca_dev, gainMo); + PDEBUG(D_CONF, "set exposure %d", + ((expoMo10[3] & 0x07) << 10) + | (expoMof[3] << 2) + | ((expoMo10[3] & 0x30) >> 4)); + break; + } + } + return expo; +} + +static void setbrightness(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + unsigned int expo; + __u8 k2; + + switch (sd->sensor) { + case SENSOR_HV7131R: + expo = sd->brightness << 4; + if (expo > 0x002dc6c0) + expo = 0x002dc6c0; + else if (expo < 0x02a0) + expo = 0x02a0; + sd->exposure = setexposure(gspca_dev, expo); + break; + case SENSOR_MI0360: + expo = sd->brightness >> 4; + sd->exposure = setexposure(gspca_dev, expo); + break; + case SENSOR_MO4000: + expo = sd->brightness >> 4; + sd->exposure = setexposure(gspca_dev, expo); + break; + case SENSOR_OV7660: + return; /*jfm??*/ + } + + k2 = sd->brightness >> 10; + reg_w(gspca_dev, 0x96, &k2, 1); +} + +static void setcontrast(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + __u8 k2; + __u8 contrast[] = { 0x00, 0x00, 0x28, 0x00, 0x07, 0x00 }; + + if (sd->sensor == SENSOR_OV7660) + return; /*jfm??*/ + k2 = sd->contrast; + contrast[2] = k2; + contrast[0] = (k2 + 1) >> 1; + contrast[4] = (k2 + 1) / 5; + reg_w(gspca_dev, 0x84, contrast, 6); +} + +static void setcolors(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + __u8 data; + int colour; + + colour = sd->colors - 128; + if (colour > 0) + data = (colour + 32) & 0x7f; /* blue */ + else + data = (-colour + 32) & 0x7f; /* red */ + reg_w(gspca_dev, 0x05, &data, 1); +} + +/* -- start the camera -- */ +static void sd_start(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + int i; + __u8 data; + __u8 reg1; + __u8 reg17; + const __u8 *sn9c1xx; + int mode; + static const __u8 DC29[] = { 0x6a, 0x50, 0x00, 0x00, 0x50, 0x3c }; + static const __u8 C0[] = { 0x2d, 0x2d, 0x3a, 0x05, 0x04, 0x3f }; + static const __u8 CA[] = { 0x28, 0xd8, 0x14, 0xec }; + static const __u8 CA_sn9c120[] = + { 0x14, 0xec, 0x0a, 0xf6 }; /* SN9C120 */ + static const __u8 CE[] = { 0x32, 0xdd, 0x2d, 0xdd }; /* MI0360 */ + static const __u8 CE_sn9c325[] = + { 0x32, 0xdd, 0x32, 0xdd }; /* OV7648 - SN9C325 */ + + sn9c1xx = sn_tb[(int) sd->sensor]; + configure_gpio(gspca_dev, sn9c1xx); + +/*fixme:jfm this sequence should appear at end of sd_start */ +/* with + data = 0x44; + reg_w(gspca_dev, 0x01, &data, 1); */ + reg_w(gspca_dev, 0x15, &sn9c1xx[0x15], 1); + reg_w(gspca_dev, 0x16, &sn9c1xx[0x16], 1); + reg_w(gspca_dev, 0x12, &sn9c1xx[0x12], 1); + reg_w(gspca_dev, 0x13, &sn9c1xx[0x13], 1); + reg_w(gspca_dev, 0x18, &sn9c1xx[0x18], 1); + reg_w(gspca_dev, 0xd2, &DC29[0], 1); + reg_w(gspca_dev, 0xd3, &DC29[1], 1); + reg_w(gspca_dev, 0xc6, &DC29[2], 1); + reg_w(gspca_dev, 0xc7, &DC29[3], 1); + reg_w(gspca_dev, 0xc8, &DC29[4], 1); + reg_w(gspca_dev, 0xc9, &DC29[5], 1); +/*fixme:jfm end of ending sequence */ + reg_w(gspca_dev, 0x18, &sn9c1xx[0x18], 1); + switch (sd->bridge) { + case BRIDGE_SN9C325: + data = 0xae; + break; + case BRIDGE_SN9C120: + data = 0xa0; + break; + default: + data = 0x60; + break; + } + reg_w(gspca_dev, 0x17, &data, 1); + reg_w(gspca_dev, 0x05, &sn9c1xx[5], 1); + reg_w(gspca_dev, 0x07, &sn9c1xx[7], 1); + reg_w(gspca_dev, 0x06, &sn9c1xx[6], 1); + reg_w(gspca_dev, 0x14, &sn9c1xx[0x14], 1); + switch (sd->bridge) { + case BRIDGE_SN9C325: + reg_w(gspca_dev, 0x20, regsn20_sn9c325, + sizeof regsn20_sn9c325); + for (i = 0; i < 8; i++) + reg_w(gspca_dev, 0x84, reg84_sn9c325, + sizeof reg84_sn9c325); + data = 0x0a; + reg_w(gspca_dev, 0x9a, &data, 1); + data = 0x60; + reg_w(gspca_dev, 0x99, &data, 1); + break; + case BRIDGE_SN9C120: + reg_w(gspca_dev, 0x20, regsn20_sn9c120, + sizeof regsn20_sn9c120); + for (i = 0; i < 2; i++) + reg_w(gspca_dev, 0x84, reg84_sn9c120_1, + sizeof reg84_sn9c120_1); + for (i = 0; i < 6; i++) + reg_w(gspca_dev, 0x84, reg84_sn9c120_2, + sizeof reg84_sn9c120_2); + reg_w(gspca_dev, 0x84, reg84_sn9c120_3, + sizeof reg84_sn9c120_3); + data = 0x05; + reg_w(gspca_dev, 0x9a, &data, 1); + data = 0x5b; + reg_w(gspca_dev, 0x99, &data, 1); + break; + default: + reg_w(gspca_dev, 0x20, regsn20, sizeof regsn20); + for (i = 0; i < 8; i++) + reg_w(gspca_dev, 0x84, reg84, sizeof reg84); + data = 0x08; + reg_w(gspca_dev, 0x9a, &data, 1); + data = 0x59; + reg_w(gspca_dev, 0x99, &data, 1); + break; + } + + mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv; + reg1 = 0x02; + reg17 = 0x61; + switch (sd->sensor) { + case SENSOR_HV7131R: + hv7131R_InitSensor(gspca_dev); + if (mode) + reg1 = 0x46; /* 320 clk 48Mhz */ + else + reg1 = 0x06; /* 640 clk 24Mz */ + break; + case SENSOR_MI0360: + mi0360_InitSensor(gspca_dev); + if (mode) + reg1 = 0x46; /* 320 clk 48Mhz */ + else + reg1 = 0x06; /* 640 clk 24Mz */ + break; + case SENSOR_MO4000: + mo4000_InitSensor(gspca_dev); + if (mode) { +/* reg1 = 0x46; * 320 clk 48Mhz 60fp/s */ + reg1 = 0x06; /* clk 24Mz */ + } else { + reg17 = 0x22; /* 640 MCKSIZE */ + reg1 = 0x06; /* 640 clk 24Mz */ + } + break; + case SENSOR_OV7648: + reg17 = 0xa2; + reg1 = 0x44; + ov7648_InitSensor(gspca_dev); +/* if (mode) + ; * 320x2... + else + ; * 640x... */ + break; + default: +/* case SENSOR_OV7660: */ + ov7660_InitSensor(gspca_dev); + if (mode) { +/* reg17 = 0x21; * 320 */ +/* reg1 = 0x44; */ + reg1 = 0x46; + } else { + reg17 = 0xa2; /* 640 */ + reg1 = 0x40; + } + break; + } + reg_w(gspca_dev, 0xc0, C0, 6); + switch (sd->bridge) { + case BRIDGE_SN9C120: /*jfm ?? */ + reg_w(gspca_dev, 0xca, CA_sn9c120, 4); + break; + default: + reg_w(gspca_dev, 0xca, CA, 4); + break; + } + switch (sd->bridge) { + case BRIDGE_SN9C120: /*jfm ?? */ + case BRIDGE_SN9C325: + reg_w(gspca_dev, 0xce, CE_sn9c325, 4); + break; + default: + reg_w(gspca_dev, 0xce, CE, 4); + /* ?? {0x1e, 0xdd, 0x2d, 0xe7} */ + break; + } + + /* here change size mode 0 -> VGA; 1 -> CIF */ + data = 0x40 | sn9c1xx[0x18] | (mode << 4); + reg_w(gspca_dev, 0x18, &data, 1); + + reg_w(gspca_dev, 0x100, qtable4, 0x40); + reg_w(gspca_dev, 0x140, qtable4 + 0x40, 0x40); + + data = sn9c1xx[0x18] | (mode << 4); + reg_w(gspca_dev, 0x18, &data, 1); + + reg_w(gspca_dev, 0x17, ®17, 1); + reg_w(gspca_dev, 0x01, ®1, 1); + setbrightness(gspca_dev); + setcontrast(gspca_dev); +} + +static void sd_stopN(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + static const __u8 stophv7131[] = + { 0xa1, 0x11, 0x02, 0x09, 0x00, 0x00, 0x00, 0x10 }; + static const __u8 stopmi0360[] = + { 0xb1, 0x5d, 0x07, 0x00, 0x00, 0x00, 0x00, 0x10 }; + __u8 regF1; + __u8 data; + const __u8 *sn9c1xx; + + data = 0x0b; + switch (sd->sensor) { + case SENSOR_HV7131R: + i2c_w8(gspca_dev, stophv7131); + data = 0x2b; + break; + case SENSOR_MI0360: + i2c_w8(gspca_dev, stopmi0360); + data = 0x29; + break; + case SENSOR_MO4000: + break; + case SENSOR_OV7648: + data = 0x29; + break; + default: +/* case SENSOR_OV7660: */ + break; + } + sn9c1xx = sn_tb[(int) sd->sensor]; + reg_w(gspca_dev, 0x01, &sn9c1xx[1], 1); + reg_w(gspca_dev, 0x17, &sn9c1xx[0x17], 1); + reg_w(gspca_dev, 0x01, &sn9c1xx[1], 1); + reg_w(gspca_dev, 0x01, &data, 1); + regF1 = 0x01; + reg_w(gspca_dev, 0xf1, ®F1, 1); +} + +static void sd_stop0(struct gspca_dev *gspca_dev) +{ +} + +static void sd_close(struct gspca_dev *gspca_dev) +{ +} + +static void setautogain(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + /* Thanks S., without your advice, autobright should not work :) */ + int delta; + int expotimes = 0; + __u8 luma_mean = 130; + __u8 luma_delta = 20; + + delta = sd->avg_lum; + if (delta < luma_mean - luma_delta || + delta > luma_mean + luma_delta) { + switch (sd->sensor) { + case SENSOR_HV7131R: + expotimes = sd->exposure >> 8; + expotimes += (luma_mean - delta) >> 4; + if (expotimes < 0) + expotimes = 0; + sd->exposure = setexposure(gspca_dev, + (unsigned int) (expotimes << 8)); + break; + case SENSOR_MO4000: + case SENSOR_MI0360: + expotimes = sd->exposure; + expotimes += (luma_mean - delta) >> 6; + if (expotimes < 0) + expotimes = 0; + sd->exposure = setexposure(gspca_dev, + (unsigned int) expotimes); + setcolors(gspca_dev); + break; + } + } +} + +static void sd_pkt_scan(struct gspca_dev *gspca_dev, + struct gspca_frame *frame, /* target */ + __u8 *data, /* isoc packet */ + int len) /* iso packet length */ +{ + struct sd *sd = (struct sd *) gspca_dev; + int sof, avg_lum; + + sof = len - 64; + if (sof >= 0 && data[sof] == 0xff && data[sof + 1] == 0xd9) { + + /* end of frame */ + gspca_frame_add(gspca_dev, LAST_PACKET, + frame, data, sof + 2); + if (sd->ag_cnt < 0) + return; + if (--sd->ag_cnt >= 0) + return; + sd->ag_cnt = AG_CNT_START; +/* w1 w2 w3 */ +/* w4 w5 w6 */ +/* w7 w8 */ +/* w4 */ + avg_lum = ((data[sof + 29] << 8) | data[sof + 30]) >> 6; +/* w6 */ + avg_lum += ((data[sof + 33] << 8) | data[sof + 34]) >> 6; +/* w2 */ + avg_lum += ((data[sof + 25] << 8) | data[sof + 26]) >> 6; +/* w8 */ + avg_lum += ((data[sof + 37] << 8) | data[sof + 38]) >> 6; +/* w5 */ + avg_lum += ((data[sof + 31] << 8) | data[sof + 32]) >> 4; + avg_lum >>= 4; + sd->avg_lum = avg_lum; + PDEBUG(D_PACK, "mean lum %d", avg_lum); + setautogain(gspca_dev); + return; + } + if (gspca_dev->last_packet_type == LAST_PACKET) { + + /* put the JPEG 422 header */ + jpeg_put_header(gspca_dev, frame, sd->qindex, 0x21); + } + gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len); +} + +static unsigned int getexposure(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + __u8 hexpo, mexpo, lexpo; + + switch (sd->sensor) { + case SENSOR_HV7131R: + /* read sensor exposure */ + i2c_r5(gspca_dev, 0x25); + return (gspca_dev->usb_buf[0] << 16) + | (gspca_dev->usb_buf[1] << 8) + | gspca_dev->usb_buf[2]; + case SENSOR_MI0360: + /* read sensor exposure */ + i2c_r5(gspca_dev, 0x09); + return (gspca_dev->usb_buf[0] << 8) + | gspca_dev->usb_buf[1]; + case SENSOR_MO4000: + i2c_r5(gspca_dev, 0x0e); + hexpo = 0; /* gspca_dev->usb_buf[1] & 0x07; */ + mexpo = 0x40; /* gspca_dev->usb_buf[2] & 0xff; */ + lexpo = (gspca_dev->usb_buf[1] & 0x30) >> 4; + PDEBUG(D_CONF, "exposure %d", + (hexpo << 10) | (mexpo << 2) | lexpo); + return (hexpo << 10) | (mexpo << 2) | lexpo; + default: +/* case SENSOR_OV7660: */ + /* read sensor exposure */ + i2c_r5(gspca_dev, 0x04); + hexpo = gspca_dev->usb_buf[3] & 0x2f; + lexpo = gspca_dev->usb_buf[0] & 0x02; + i2c_r5(gspca_dev, 0x08); + mexpo = gspca_dev->usb_buf[2]; + return (hexpo << 10) | (mexpo << 2) | lexpo; + } +} + +static void getbrightness(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + + /* hardcoded registers seem not readable */ + switch (sd->sensor) { + case SENSOR_HV7131R: +/* sd->brightness = 0x7fff; */ + sd->brightness = getexposure(gspca_dev) >> 4; + break; + case SENSOR_MI0360: + sd->brightness = getexposure(gspca_dev) << 4; + break; + case SENSOR_MO4000: +/* sd->brightness = 0x1fff; */ + sd->brightness = getexposure(gspca_dev) << 4; + break; + } +} + +static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->brightness = val; + if (gspca_dev->streaming) + setbrightness(gspca_dev); + return 0; +} + +static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + getbrightness(gspca_dev); + *val = sd->brightness; + return 0; +} + +static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->contrast = val; + if (gspca_dev->streaming) + setcontrast(gspca_dev); + return 0; +} + +static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + *val = sd->contrast; + return 0; +} + +static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->colors = val; + if (gspca_dev->streaming) + setcolors(gspca_dev); + return 0; +} + +static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + *val = sd->colors; + return 0; +} + +static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->autogain = val; + if (val) + sd->ag_cnt = AG_CNT_START; + else + sd->ag_cnt = -1; + return 0; +} + +static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + *val = sd->autogain; + return 0; +} + +/* sub-driver description */ +static const struct sd_desc sd_desc = { + .name = MODULE_NAME, + .ctrls = sd_ctrls, + .nctrls = ARRAY_SIZE(sd_ctrls), + .config = sd_config, + .open = sd_open, + .start = sd_start, + .stopN = sd_stopN, + .stop0 = sd_stop0, + .close = sd_close, + .pkt_scan = sd_pkt_scan, +}; + +/* -- module initialisation -- */ +#define DVNM(name) .driver_info = (kernel_ulong_t) name +static const __devinitdata struct usb_device_id device_table[] = { +#ifndef CONFIG_USB_SN9C102 + {USB_DEVICE(0x0458, 0x7025), DVNM("Genius Eye 311Q")}, + {USB_DEVICE(0x045e, 0x00f5), DVNM("MicroSoft VX3000")}, + {USB_DEVICE(0x045e, 0x00f7), DVNM("MicroSoft VX1000")}, + {USB_DEVICE(0x0471, 0x0327), DVNM("Philips SPC 600 NC")}, + {USB_DEVICE(0x0471, 0x0328), DVNM("Philips SPC 700 NC")}, +#endif + {USB_DEVICE(0x0471, 0x0330), DVNM("Philips SPC 710NC")}, + {USB_DEVICE(0x0c45, 0x6040), DVNM("Speed NVC 350K")}, + {USB_DEVICE(0x0c45, 0x607c), DVNM("Sonix sn9c102p Hv7131R")}, + {USB_DEVICE(0x0c45, 0x60c0), DVNM("Sangha Sn535")}, + {USB_DEVICE(0x0c45, 0x60ec), DVNM("SN9C105+MO4000")}, + {USB_DEVICE(0x0c45, 0x60fb), DVNM("Surfer NoName")}, + {USB_DEVICE(0x0c45, 0x60fc), DVNM("LG-LIC300")}, + {USB_DEVICE(0x0c45, 0x612a), DVNM("Avant Camera")}, + {USB_DEVICE(0x0c45, 0x612c), DVNM("Typhoon Rasy Cam 1.3MPix")}, +#ifndef CONFIG_USB_SN9C102 + {USB_DEVICE(0x0c45, 0x6130), DVNM("Sonix Pccam")}, + {USB_DEVICE(0x0c45, 0x6138), DVNM("Sn9c120 Mo4000")}, + {USB_DEVICE(0x0c45, 0x613b), DVNM("Surfer SN-206")}, + {USB_DEVICE(0x0c45, 0x613c), DVNM("Sonix Pccam168")}, +#endif + {} +}; +MODULE_DEVICE_TABLE(usb, device_table); + +/* -- device connect -- */ +static int sd_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd), + THIS_MODULE); +} + +static struct usb_driver sd_driver = { + .name = MODULE_NAME, + .id_table = device_table, + .probe = sd_probe, + .disconnect = gspca_disconnect, +}; + +/* -- module insert / remove -- */ +static int __init sd_mod_init(void) +{ + if (usb_register(&sd_driver) < 0) + return -1; + info("v%s registered", version); + return 0; +} +static void __exit sd_mod_exit(void) +{ + usb_deregister(&sd_driver); + info("deregistered"); +} + +module_init(sd_mod_init); +module_exit(sd_mod_exit); diff --git a/drivers/media/video/gspca/spca500.c b/drivers/media/video/gspca/spca500.c new file mode 100644 index 000000000000..156206118795 --- /dev/null +++ b/drivers/media/video/gspca/spca500.c @@ -0,0 +1,1216 @@ +/* + * SPCA500 chip based cameras initialization data + * + * V4L2 by Jean-Francois Moine <http://moinejf.free.fr> + * + * 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 + * 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 + * + */ + +#define MODULE_NAME "spca500" + +#include "gspca.h" +#include "jpeg.h" + +#define DRIVER_VERSION_NUMBER KERNEL_VERSION(2, 1, 7) +static const char version[] = "2.1.7"; + +MODULE_AUTHOR("Michel Xhaard <mxhaard@users.sourceforge.net>"); +MODULE_DESCRIPTION("GSPCA/SPCA500 USB Camera Driver"); +MODULE_LICENSE("GPL"); + +/* specific webcam descriptor */ +struct sd { + struct gspca_dev gspca_dev; /* !! must be the first item */ + + __u8 packet[ISO_MAX_SIZE + 128]; + /* !! no more than 128 ff in an ISO packet */ + + unsigned char brightness; + unsigned char contrast; + unsigned char colors; + + char qindex; + char subtype; +#define AgfaCl20 0 +#define AiptekPocketDV 1 +#define BenqDC1016 2 +#define CreativePCCam300 3 +#define DLinkDSC350 4 +#define Gsmartmini 5 +#define IntelPocketPCCamera 6 +#define KodakEZ200 7 +#define LogitechClickSmart310 8 +#define LogitechClickSmart510 9 +#define LogitechTraveler 10 +#define MustekGsmart300 11 +#define Optimedia 12 +#define PalmPixDC85 13 +#define ToptroIndus 14 +}; + +/* V4L2 controls supported by the driver */ +static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val); +static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val); +static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val); +static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val); +static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val); +static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val); + +static struct ctrl sd_ctrls[] = { + { + { + .id = V4L2_CID_BRIGHTNESS, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Brightness", + .minimum = 0, + .maximum = 255, + .step = 1, +#define BRIGHTNESS_DEF 127 + .default_value = BRIGHTNESS_DEF, + }, + .set = sd_setbrightness, + .get = sd_getbrightness, + }, + { + { + .id = V4L2_CID_CONTRAST, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Contrast", + .minimum = 0, + .maximum = 63, + .step = 1, +#define CONTRAST_DEF 31 + .default_value = CONTRAST_DEF, + }, + .set = sd_setcontrast, + .get = sd_getcontrast, + }, + { + { + .id = V4L2_CID_SATURATION, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Color", + .minimum = 0, + .maximum = 63, + .step = 1, +#define COLOR_DEF 31 + .default_value = COLOR_DEF, + }, + .set = sd_setcolors, + .get = sd_getcolors, + }, +}; + +static struct v4l2_pix_format vga_mode[] = { + {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, + .bytesperline = 320, + .sizeimage = 320 * 240 * 3 / 8 + 590, + .colorspace = V4L2_COLORSPACE_JPEG, + .priv = 1}, + {640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, + .bytesperline = 640, + .sizeimage = 640 * 480 * 3 / 8 + 590, + .colorspace = V4L2_COLORSPACE_JPEG, + .priv = 0}, +}; + +static struct v4l2_pix_format sif_mode[] = { + {176, 144, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, + .bytesperline = 176, + .sizeimage = 176 * 144 * 3 / 8 + 590, + .colorspace = V4L2_COLORSPACE_JPEG, + .priv = 1}, + {352, 288, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, + .bytesperline = 352, + .sizeimage = 352 * 288 * 3 / 8 + 590, + .colorspace = V4L2_COLORSPACE_JPEG, + .priv = 0}, +}; + +/* Frame packet header offsets for the spca500 */ +#define SPCA500_OFFSET_PADDINGLB 2 +#define SPCA500_OFFSET_PADDINGHB 3 +#define SPCA500_OFFSET_MODE 4 +#define SPCA500_OFFSET_IMGWIDTH 5 +#define SPCA500_OFFSET_IMGHEIGHT 6 +#define SPCA500_OFFSET_IMGMODE 7 +#define SPCA500_OFFSET_QTBLINDEX 8 +#define SPCA500_OFFSET_FRAMSEQ 9 +#define SPCA500_OFFSET_CDSPINFO 10 +#define SPCA500_OFFSET_GPIO 11 +#define SPCA500_OFFSET_AUGPIO 12 +#define SPCA500_OFFSET_DATA 16 + + +static const __u16 spca500_visual_defaults[][3] = { + {0x00, 0x0003, 0x816b}, /* SSI not active sync with vsync, + * hue (H byte) = 0, + * saturation/hue enable, + * brightness/contrast enable. + */ + {0x00, 0x0000, 0x8167}, /* brightness = 0 */ + {0x00, 0x0020, 0x8168}, /* contrast = 0 */ + {0x00, 0x0003, 0x816b}, /* SSI not active sync with vsync, + * hue (H byte) = 0, saturation/hue enable, + * brightness/contrast enable. + * was 0x0003, now 0x0000. + */ + {0x00, 0x0000, 0x816a}, /* hue (L byte) = 0 */ + {0x00, 0x0020, 0x8169}, /* saturation = 0x20 */ + {0x00, 0x0050, 0x8157}, /* edge gain high threshold */ + {0x00, 0x0030, 0x8158}, /* edge gain low threshold */ + {0x00, 0x0028, 0x8159}, /* edge bandwidth high threshold */ + {0x00, 0x000a, 0x815a}, /* edge bandwidth low threshold */ + {0x00, 0x0001, 0x8202}, /* clock rate compensation = 1/25 sec/frame */ + {0x0c, 0x0004, 0x0000}, + /* set interface */ + {} +}; +static const __u16 Clicksmart510_defaults[][3] = { + {0x00, 0x00, 0x8211}, + {0x00, 0x01, 0x82c0}, + {0x00, 0x10, 0x82cb}, + {0x00, 0x0f, 0x800d}, + {0x00, 0x82, 0x8225}, + {0x00, 0x21, 0x8228}, + {0x00, 0x00, 0x8203}, + {0x00, 0x00, 0x8204}, + {0x00, 0x08, 0x8205}, + {0x00, 0xf8, 0x8206}, + {0x00, 0x28, 0x8207}, + {0x00, 0xa0, 0x8208}, + {0x00, 0x08, 0x824a}, + {0x00, 0x08, 0x8214}, + {0x00, 0x80, 0x82c1}, + {0x00, 0x00, 0x82c2}, + {0x00, 0x00, 0x82ca}, + {0x00, 0x80, 0x82c1}, + {0x00, 0x04, 0x82c2}, + {0x00, 0x00, 0x82ca}, + {0x00, 0xfc, 0x8100}, + {0x00, 0xfc, 0x8105}, + {0x00, 0x30, 0x8101}, + {0x00, 0x00, 0x8102}, + {0x00, 0x00, 0x8103}, + {0x00, 0x66, 0x8107}, + {0x00, 0x00, 0x816b}, + {0x00, 0x00, 0x8155}, + {0x00, 0x01, 0x8156}, + {0x00, 0x60, 0x8157}, + {0x00, 0x40, 0x8158}, + {0x00, 0x0a, 0x8159}, + {0x00, 0x06, 0x815a}, + {0x00, 0x00, 0x813f}, + {0x00, 0x00, 0x8200}, + {0x00, 0x19, 0x8201}, + {0x00, 0x00, 0x82c1}, + {0x00, 0xa0, 0x82c2}, + {0x00, 0x00, 0x82ca}, + {0x00, 0x00, 0x8117}, + {0x00, 0x00, 0x8118}, + {0x00, 0x65, 0x8119}, + {0x00, 0x00, 0x811a}, + {0x00, 0x00, 0x811b}, + {0x00, 0x55, 0x811c}, + {0x00, 0x65, 0x811d}, + {0x00, 0x55, 0x811e}, + {0x00, 0x16, 0x811f}, + {0x00, 0x19, 0x8120}, + {0x00, 0x80, 0x8103}, + {0x00, 0x83, 0x816b}, + {0x00, 0x25, 0x8168}, + {0x00, 0x01, 0x820f}, + {0x00, 0xff, 0x8115}, + {0x00, 0x48, 0x8116}, + {0x00, 0x50, 0x8151}, + {0x00, 0x40, 0x8152}, + {0x00, 0x78, 0x8153}, + {0x00, 0x40, 0x8154}, + {0x00, 0x00, 0x8167}, + {0x00, 0x20, 0x8168}, + {0x00, 0x00, 0x816a}, + {0x00, 0x03, 0x816b}, + {0x00, 0x20, 0x8169}, + {0x00, 0x60, 0x8157}, + {0x00, 0x00, 0x8190}, + {0x00, 0x00, 0x81a1}, + {0x00, 0x00, 0x81b2}, + {0x00, 0x27, 0x8191}, + {0x00, 0x27, 0x81a2}, + {0x00, 0x27, 0x81b3}, + {0x00, 0x4b, 0x8192}, + {0x00, 0x4b, 0x81a3}, + {0x00, 0x4b, 0x81b4}, + {0x00, 0x66, 0x8193}, + {0x00, 0x66, 0x81a4}, + {0x00, 0x66, 0x81b5}, + {0x00, 0x79, 0x8194}, + {0x00, 0x79, 0x81a5}, + {0x00, 0x79, 0x81b6}, + {0x00, 0x8a, 0x8195}, + {0x00, 0x8a, 0x81a6}, + {0x00, 0x8a, 0x81b7}, + {0x00, 0x9b, 0x8196}, + {0x00, 0x9b, 0x81a7}, + {0x00, 0x9b, 0x81b8}, + {0x00, 0xa6, 0x8197}, + {0x00, 0xa6, 0x81a8}, + {0x00, 0xa6, 0x81b9}, + {0x00, 0xb2, 0x8198}, + {0x00, 0xb2, 0x81a9}, + {0x00, 0xb2, 0x81ba}, + {0x00, 0xbe, 0x8199}, + {0x00, 0xbe, 0x81aa}, + {0x00, 0xbe, 0x81bb}, + {0x00, 0xc8, 0x819a}, + {0x00, 0xc8, 0x81ab}, + {0x00, 0xc8, 0x81bc}, + {0x00, 0xd2, 0x819b}, + {0x00, 0xd2, 0x81ac}, + {0x00, 0xd2, 0x81bd}, + {0x00, 0xdb, 0x819c}, + {0x00, 0xdb, 0x81ad}, + {0x00, 0xdb, 0x81be}, + {0x00, 0xe4, 0x819d}, + {0x00, 0xe4, 0x81ae}, + {0x00, 0xe4, 0x81bf}, + {0x00, 0xed, 0x819e}, + {0x00, 0xed, 0x81af}, + {0x00, 0xed, 0x81c0}, + {0x00, 0xf7, 0x819f}, + {0x00, 0xf7, 0x81b0}, + {0x00, 0xf7, 0x81c1}, + {0x00, 0xff, 0x81a0}, + {0x00, 0xff, 0x81b1}, + {0x00, 0xff, 0x81c2}, + {0x00, 0x03, 0x8156}, + {0x00, 0x00, 0x8211}, + {0x00, 0x20, 0x8168}, + {0x00, 0x01, 0x8202}, + {0x00, 0x30, 0x8101}, + {0x00, 0x00, 0x8111}, + {0x00, 0x00, 0x8112}, + {0x00, 0x00, 0x8113}, + {0x00, 0x00, 0x8114}, + {} +}; + +static const __u8 qtable_creative_pccam[2][64] = { + { /* Q-table Y-components */ + 0x05, 0x03, 0x03, 0x05, 0x07, 0x0c, 0x0f, 0x12, + 0x04, 0x04, 0x04, 0x06, 0x08, 0x11, 0x12, 0x11, + 0x04, 0x04, 0x05, 0x07, 0x0c, 0x11, 0x15, 0x11, + 0x04, 0x05, 0x07, 0x09, 0x0f, 0x1a, 0x18, 0x13, + 0x05, 0x07, 0x0b, 0x11, 0x14, 0x21, 0x1f, 0x17, + 0x07, 0x0b, 0x11, 0x13, 0x18, 0x1f, 0x22, 0x1c, + 0x0f, 0x13, 0x17, 0x1a, 0x1f, 0x24, 0x24, 0x1e, + 0x16, 0x1c, 0x1d, 0x1d, 0x22, 0x1e, 0x1f, 0x1e}, + { /* Q-table C-components */ + 0x05, 0x05, 0x07, 0x0e, 0x1e, 0x1e, 0x1e, 0x1e, + 0x05, 0x06, 0x08, 0x14, 0x1e, 0x1e, 0x1e, 0x1e, + 0x07, 0x08, 0x11, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, + 0x0e, 0x14, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, + 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, + 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, + 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, + 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e} +}; + +static const __u8 qtable_kodak_ez200[2][64] = { + { /* Q-table Y-components */ + 0x02, 0x01, 0x01, 0x02, 0x02, 0x04, 0x05, 0x06, + 0x01, 0x01, 0x01, 0x02, 0x03, 0x06, 0x06, 0x06, + 0x01, 0x01, 0x02, 0x02, 0x04, 0x06, 0x07, 0x06, + 0x01, 0x02, 0x02, 0x03, 0x05, 0x09, 0x08, 0x06, + 0x02, 0x02, 0x04, 0x06, 0x07, 0x0b, 0x0a, 0x08, + 0x02, 0x04, 0x06, 0x06, 0x08, 0x0a, 0x0b, 0x09, + 0x05, 0x06, 0x08, 0x09, 0x0a, 0x0c, 0x0c, 0x0a, + 0x07, 0x09, 0x0a, 0x0a, 0x0b, 0x0a, 0x0a, 0x0a}, + { /* Q-table C-components */ + 0x02, 0x02, 0x02, 0x05, 0x0a, 0x0a, 0x0a, 0x0a, + 0x02, 0x02, 0x03, 0x07, 0x0a, 0x0a, 0x0a, 0x0a, + 0x02, 0x03, 0x06, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, + 0x05, 0x07, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, + 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, + 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, + 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, + 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a} +}; + +static const __u8 qtable_pocketdv[2][64] = { + { /* Q-table Y-components start registers 0x8800 */ + 0x06, 0x04, 0x04, 0x06, 0x0a, 0x10, 0x14, 0x18, + 0x05, 0x05, 0x06, 0x08, 0x0a, 0x17, 0x18, 0x16, + 0x06, 0x05, 0x06, 0x0a, 0x10, 0x17, 0x1c, 0x16, + 0x06, 0x07, 0x09, 0x0c, 0x14, 0x23, 0x20, 0x19, + 0x07, 0x09, 0x0f, 0x16, 0x1b, 0x2c, 0x29, 0x1f, + 0x0a, 0x0e, 0x16, 0x1a, 0x20, 0x2a, 0x2d, 0x25, + 0x14, 0x1a, 0x1f, 0x23, 0x29, 0x30, 0x30, 0x28, + 0x1d, 0x25, 0x26, 0x27, 0x2d, 0x28, 0x29, 0x28, + }, + { /* Q-table C-components start registers 0x8840 */ + 0x07, 0x07, 0x0a, 0x13, 0x28, 0x28, 0x28, 0x28, + 0x07, 0x08, 0x0a, 0x1a, 0x28, 0x28, 0x28, 0x28, + 0x0a, 0x0a, 0x16, 0x28, 0x28, 0x28, 0x28, 0x28, + 0x13, 0x1a, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, + 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, + 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, + 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, + 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28} +}; + +/* read 'len' bytes to gspca_dev->usb_buf */ +static void reg_r(struct gspca_dev *gspca_dev, + __u16 index, + __u16 length) +{ + usb_control_msg(gspca_dev->dev, + usb_rcvctrlpipe(gspca_dev->dev, 0), + 0, + USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + 0, /* value */ + index, gspca_dev->usb_buf, length, 500); +} + +static int reg_w(struct gspca_dev *gspca_dev, + __u16 req, __u16 index, __u16 value) +{ + int ret; + + PDEBUG(D_USBO, "reg write: [0x%02x] = 0x%02x", index, value); + ret = usb_control_msg(gspca_dev->dev, + usb_sndctrlpipe(gspca_dev->dev, 0), + req, + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + value, index, NULL, 0, 500); + if (ret < 0) + PDEBUG(D_ERR, "reg write: error %d", ret); + return ret; +} + +/* returns: negative is error, pos or zero is data */ +static int reg_r_12(struct gspca_dev *gspca_dev, + __u16 req, /* bRequest */ + __u16 index, /* wIndex */ + __u16 length) /* wLength (1 or 2 only) */ +{ + int ret; + + gspca_dev->usb_buf[1] = 0; + ret = usb_control_msg(gspca_dev->dev, + usb_rcvctrlpipe(gspca_dev->dev, 0), + req, + USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + 0, /* value */ + index, + gspca_dev->usb_buf, length, + 500); /* timeout */ + if (ret < 0) { + PDEBUG(D_ERR, "reg_r_12 err %d", ret); + return -1; + } + return (gspca_dev->usb_buf[1] << 8) + gspca_dev->usb_buf[0]; +} + +/* + * Simple function to wait for a given 8-bit value to be returned from + * a reg_read call. + * Returns: negative is error or timeout, zero is success. + */ +static int reg_r_wait(struct gspca_dev *gspca_dev, + __u16 reg, __u16 index, __u16 value) +{ + int ret, cnt = 20; + + while (--cnt > 0) { + ret = reg_r_12(gspca_dev, reg, index, 1); + if (ret == value) + return 0; + msleep(50); + } + return -EIO; +} + +static int write_vector(struct gspca_dev *gspca_dev, + const __u16 data[][3]) +{ + int ret, i = 0; + + while (data[i][0] != 0 || data[i][1] != 0 || data[i][2] != 0) { + ret = reg_w(gspca_dev, data[i][0], data[i][2], data[i][1]); + if (ret < 0) + return ret; + i++; + } + return 0; +} + +static int spca50x_setup_qtable(struct gspca_dev *gspca_dev, + unsigned int request, + unsigned int ybase, + unsigned int cbase, + const __u8 qtable[2][64]) +{ + int i, err; + + /* loop over y components */ + for (i = 0; i < 64; i++) { + err = reg_w(gspca_dev, request, ybase + i, qtable[0][i]); + if (err < 0) + return err; + } + + /* loop over c components */ + for (i = 0; i < 64; i++) { + err = reg_w(gspca_dev, request, cbase + i, qtable[1][i]); + if (err < 0) + return err; + } + return 0; +} + +static void spca500_ping310(struct gspca_dev *gspca_dev) +{ + reg_r(gspca_dev, 0x0d04, 2); + PDEBUG(D_STREAM, "ClickSmart310 ping 0x0d04 0x%02x 0x%02x", + gspca_dev->usb_buf[0], gspca_dev->usb_buf[1]); +} + +static void spca500_clksmart310_init(struct gspca_dev *gspca_dev) +{ + reg_r(gspca_dev, 0x0d05, 2); + PDEBUG(D_STREAM, "ClickSmart310 init 0x0d05 0x%02x 0x%02x", + gspca_dev->usb_buf[0], gspca_dev->usb_buf[1]); + reg_w(gspca_dev, 0x00, 0x8167, 0x5a); + spca500_ping310(gspca_dev); + + reg_w(gspca_dev, 0x00, 0x8168, 0x22); + reg_w(gspca_dev, 0x00, 0x816a, 0xc0); + reg_w(gspca_dev, 0x00, 0x816b, 0x0b); + reg_w(gspca_dev, 0x00, 0x8169, 0x25); + reg_w(gspca_dev, 0x00, 0x8157, 0x5b); + reg_w(gspca_dev, 0x00, 0x8158, 0x5b); + reg_w(gspca_dev, 0x00, 0x813f, 0x03); + reg_w(gspca_dev, 0x00, 0x8151, 0x4a); + reg_w(gspca_dev, 0x00, 0x8153, 0x78); + reg_w(gspca_dev, 0x00, 0x0d01, 0x04); + /* 00 for adjust shutter */ + reg_w(gspca_dev, 0x00, 0x0d02, 0x01); + reg_w(gspca_dev, 0x00, 0x8169, 0x25); + reg_w(gspca_dev, 0x00, 0x0d01, 0x02); +} + +static void spca500_setmode(struct gspca_dev *gspca_dev, + __u8 xmult, __u8 ymult) +{ + int mode; + + /* set x multiplier */ + reg_w(gspca_dev, 0, 0x8001, xmult); + + /* set y multiplier */ + reg_w(gspca_dev, 0, 0x8002, ymult); + + /* use compressed mode, VGA, with mode specific subsample */ + mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv; + reg_w(gspca_dev, 0, 0x8003, mode << 4); +} + +static int spca500_full_reset(struct gspca_dev *gspca_dev) +{ + int err; + + /* send the reset command */ + err = reg_w(gspca_dev, 0xe0, 0x0001, 0x0000); + if (err < 0) + return err; + + /* wait for the reset to complete */ + err = reg_r_wait(gspca_dev, 0x06, 0x0000, 0x0000); + if (err < 0) + return err; + err = reg_w(gspca_dev, 0xe0, 0x0000, 0x0000); + if (err < 0) + return err; + err = reg_r_wait(gspca_dev, 0x06, 0, 0); + if (err < 0) { + PDEBUG(D_ERR, "reg_r_wait() failed"); + return err; + } + /* all ok */ + return 0; +} + +/* Synchro the Bridge with sensor */ +/* Maybe that will work on all spca500 chip */ +/* because i only own a clicksmart310 try for that chip */ +/* using spca50x_set_packet_size() cause an Ooops here */ +/* usb_set_interface from kernel 2.6.x clear all the urb stuff */ +/* up-port the same feature as in 2.4.x kernel */ +static int spca500_synch310(struct gspca_dev *gspca_dev) +{ + if (usb_set_interface(gspca_dev->dev, gspca_dev->iface, 0) < 0) { + PDEBUG(D_ERR, "Set packet size: set interface error"); + goto error; + } + spca500_ping310(gspca_dev); + + reg_r(gspca_dev, 0x0d00, 1); + + /* need alt setting here */ + PDEBUG(D_PACK, "ClickSmart310 sync alt: %d", gspca_dev->alt); + + /* Windoze use pipe with altsetting 6 why 7 here */ + if (usb_set_interface(gspca_dev->dev, + gspca_dev->iface, + gspca_dev->alt) < 0) { + PDEBUG(D_ERR, "Set packet size: set interface error"); + goto error; + } + return 0; +error: + return -EBUSY; +} + +static void spca500_reinit(struct gspca_dev *gspca_dev) +{ + int err; + __u8 Data; + + /* some unknow command from Aiptek pocket dv and family300 */ + + reg_w(gspca_dev, 0x00, 0x0d01, 0x01); + reg_w(gspca_dev, 0x00, 0x0d03, 0x00); + reg_w(gspca_dev, 0x00, 0x0d02, 0x01); + + /* enable drop packet */ + reg_w(gspca_dev, 0x00, 0x850a, 0x0001); + + err = spca50x_setup_qtable(gspca_dev, 0x00, 0x8800, 0x8840, + qtable_pocketdv); + if (err < 0) + PDEBUG(D_ERR|D_STREAM, "spca50x_setup_qtable failed on init"); + + /* set qtable index */ + reg_w(gspca_dev, 0x00, 0x8880, 2); + /* family cam Quicksmart stuff */ + reg_w(gspca_dev, 0x00, 0x800a, 0x00); + /* Set agc transfer: synced inbetween frames */ + reg_w(gspca_dev, 0x00, 0x820f, 0x01); + /* Init SDRAM - needed for SDRAM access */ + reg_w(gspca_dev, 0x00, 0x870a, 0x04); + /*Start init sequence or stream */ + reg_w(gspca_dev, 0, 0x8003, 0x00); + /* switch to video camera mode */ + reg_w(gspca_dev, 0x00, 0x8000, 0x0004); + msleep(2000); + if (reg_r_wait(gspca_dev, 0, 0x8000, 0x44) != 0) { + reg_r(gspca_dev, 0x816b, 1); + Data = gspca_dev->usb_buf[0]; + reg_w(gspca_dev, 0x00, 0x816b, Data); + } +} + +/* this function is called at probe time */ +static int sd_config(struct gspca_dev *gspca_dev, + const struct usb_device_id *id) +{ + struct sd *sd = (struct sd *) gspca_dev; + struct cam *cam; + __u16 vendor; + __u16 product; + + vendor = id->idVendor; + product = id->idProduct; + switch (vendor) { + case 0x040a: /* Kodak cameras */ +/* switch (product) { */ +/* case 0x0300: */ + sd->subtype = KodakEZ200; +/* break; */ +/* } */ + break; + case 0x041e: /* Creative cameras */ +/* switch (product) { */ +/* case 0x400a: */ + sd->subtype = CreativePCCam300; +/* break; */ +/* } */ + break; + case 0x046d: /* Logitech Labtec */ + switch (product) { + case 0x0890: + sd->subtype = LogitechTraveler; + break; + case 0x0900: + sd->subtype = LogitechClickSmart310; + break; + case 0x0901: + sd->subtype = LogitechClickSmart510; + break; + } + break; + case 0x04a5: /* Benq */ +/* switch (product) { */ +/* case 0x300c: */ + sd->subtype = BenqDC1016; +/* break; */ +/* } */ + break; + case 0x04fc: /* SunPlus */ +/* switch (product) { */ +/* case 0x7333: */ + sd->subtype = PalmPixDC85; +/* break; */ +/* } */ + break; + case 0x055f: /* Mustek cameras */ + switch (product) { + case 0xc200: + sd->subtype = MustekGsmart300; + break; + case 0xc220: + sd->subtype = Gsmartmini; + break; + } + break; + case 0x06bd: /* Agfa Cl20 */ +/* switch (product) { */ +/* case 0x0404: */ + sd->subtype = AgfaCl20; +/* break; */ +/* } */ + break; + case 0x06be: /* Optimedia */ +/* switch (product) { */ +/* case 0x0800: */ + sd->subtype = Optimedia; +/* break; */ +/* } */ + break; + case 0x084d: /* D-Link / Minton */ +/* switch (product) { */ +/* case 0x0003: * DSC-350 / S-Cam F5 */ + sd->subtype = DLinkDSC350; +/* break; */ +/* } */ + break; + case 0x08ca: /* Aiptek */ +/* switch (product) { */ +/* case 0x0103: */ + sd->subtype = AiptekPocketDV; +/* break; */ +/* } */ + break; + case 0x2899: /* ToptroIndustrial */ +/* switch (product) { */ +/* case 0x012c: */ + sd->subtype = ToptroIndus; +/* break; */ +/* } */ + break; + case 0x8086: /* Intel */ +/* switch (product) { */ +/* case 0x0630: * Pocket PC Camera */ + sd->subtype = IntelPocketPCCamera; +/* break; */ +/* } */ + break; + } + cam = &gspca_dev->cam; + cam->dev_name = (char *) id->driver_info; + cam->epaddr = 0x01; + if (sd->subtype != LogitechClickSmart310) { + cam->cam_mode = vga_mode; + cam->nmodes = sizeof vga_mode / sizeof vga_mode[0]; + } else { + cam->cam_mode = sif_mode; + cam->nmodes = sizeof sif_mode / sizeof sif_mode[0]; + } + sd->qindex = 5; + sd->brightness = BRIGHTNESS_DEF; + sd->contrast = CONTRAST_DEF; + sd->colors = COLOR_DEF; + return 0; +} + +/* this function is called at open time */ +static int sd_open(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + + /* initialisation of spca500 based cameras is deferred */ + PDEBUG(D_STREAM, "SPCA500 init"); + if (sd->subtype == LogitechClickSmart310) + spca500_clksmart310_init(gspca_dev); +/* else + spca500_initialise(gspca_dev); */ + PDEBUG(D_STREAM, "SPCA500 init done"); + return 0; +} + +static void sd_start(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + int err; + __u8 Data; + __u8 xmult, ymult; + + if (sd->subtype == LogitechClickSmart310) { + xmult = 0x16; + ymult = 0x12; + } else { + xmult = 0x28; + ymult = 0x1e; + } + + /* is there a sensor here ? */ + reg_r(gspca_dev, 0x8a04, 1); + PDEBUG(D_STREAM, "Spca500 Sensor Address 0x%02x", + gspca_dev->usb_buf[0]); + PDEBUG(D_STREAM, "Spca500 curr_mode: %d Xmult: 0x%02x, Ymult: 0x%02x", + gspca_dev->curr_mode, xmult, ymult); + + /* setup qtable */ + switch (sd->subtype) { + case LogitechClickSmart310: + spca500_setmode(gspca_dev, xmult, ymult); + + /* enable drop packet */ + reg_w(gspca_dev, 0x00, 0x850a, 0x0001); + reg_w(gspca_dev, 0x00, 0x8880, 3); + err = spca50x_setup_qtable(gspca_dev, + 0x00, 0x8800, 0x8840, + qtable_creative_pccam); + if (err < 0) + PDEBUG(D_ERR, "spca50x_setup_qtable failed"); + /* Init SDRAM - needed for SDRAM access */ + reg_w(gspca_dev, 0x00, 0x870a, 0x04); + + /* switch to video camera mode */ + reg_w(gspca_dev, 0x00, 0x8000, 0x0004); + msleep(500); + if (reg_r_wait(gspca_dev, 0, 0x8000, 0x44) != 0) + PDEBUG(D_ERR, "reg_r_wait() failed"); + + reg_r(gspca_dev, 0x816b, 1); + Data = gspca_dev->usb_buf[0]; + reg_w(gspca_dev, 0x00, 0x816b, Data); + + spca500_synch310(gspca_dev); + + write_vector(gspca_dev, spca500_visual_defaults); + spca500_setmode(gspca_dev, xmult, ymult); + /* enable drop packet */ + reg_w(gspca_dev, 0x00, 0x850a, 0x0001); + PDEBUG(D_ERR, "failed to enable drop packet"); + reg_w(gspca_dev, 0x00, 0x8880, 3); + err = spca50x_setup_qtable(gspca_dev, + 0x00, 0x8800, 0x8840, + qtable_creative_pccam); + if (err < 0) + PDEBUG(D_ERR, "spca50x_setup_qtable failed"); + + /* Init SDRAM - needed for SDRAM access */ + reg_w(gspca_dev, 0x00, 0x870a, 0x04); + + /* switch to video camera mode */ + reg_w(gspca_dev, 0x00, 0x8000, 0x0004); + + if (reg_r_wait(gspca_dev, 0, 0x8000, 0x44) != 0) + PDEBUG(D_ERR, "reg_r_wait() failed"); + + reg_r(gspca_dev, 0x816b, 1); + Data = gspca_dev->usb_buf[0]; + reg_w(gspca_dev, 0x00, 0x816b, Data); + break; + case CreativePCCam300: /* Creative PC-CAM 300 640x480 CCD */ + case IntelPocketPCCamera: /* FIXME: Temporary fix for + * Intel Pocket PC Camera + * - NWG (Sat 29th March 2003) */ + + /* do a full reset */ + err = spca500_full_reset(gspca_dev); + if (err < 0) + PDEBUG(D_ERR, "spca500_full_reset failed"); + + /* enable drop packet */ + err = reg_w(gspca_dev, 0x00, 0x850a, 0x0001); + if (err < 0) + PDEBUG(D_ERR, "failed to enable drop packet"); + reg_w(gspca_dev, 0x00, 0x8880, 3); + err = spca50x_setup_qtable(gspca_dev, + 0x00, 0x8800, 0x8840, + qtable_creative_pccam); + if (err < 0) + PDEBUG(D_ERR, "spca50x_setup_qtable failed"); + + spca500_setmode(gspca_dev, xmult, ymult); + reg_w(gspca_dev, 0x20, 0x0001, 0x0004); + + /* switch to video camera mode */ + reg_w(gspca_dev, 0x00, 0x8000, 0x0004); + + if (reg_r_wait(gspca_dev, 0, 0x8000, 0x44) != 0) + PDEBUG(D_ERR, "reg_r_wait() failed"); + + reg_r(gspca_dev, 0x816b, 1); + Data = gspca_dev->usb_buf[0]; + reg_w(gspca_dev, 0x00, 0x816b, Data); + +/* write_vector(gspca_dev, spca500_visual_defaults); */ + break; + case KodakEZ200: /* Kodak EZ200 */ + + /* do a full reset */ + err = spca500_full_reset(gspca_dev); + if (err < 0) + PDEBUG(D_ERR, "spca500_full_reset failed"); + /* enable drop packet */ + reg_w(gspca_dev, 0x00, 0x850a, 0x0001); + reg_w(gspca_dev, 0x00, 0x8880, 0); + err = spca50x_setup_qtable(gspca_dev, + 0x00, 0x8800, 0x8840, + qtable_kodak_ez200); + if (err < 0) + PDEBUG(D_ERR, "spca50x_setup_qtable failed"); + spca500_setmode(gspca_dev, xmult, ymult); + + reg_w(gspca_dev, 0x20, 0x0001, 0x0004); + + /* switch to video camera mode */ + reg_w(gspca_dev, 0x00, 0x8000, 0x0004); + + if (reg_r_wait(gspca_dev, 0, 0x8000, 0x44) != 0) + PDEBUG(D_ERR, "reg_r_wait() failed"); + + reg_r(gspca_dev, 0x816b, 1); + Data = gspca_dev->usb_buf[0]; + reg_w(gspca_dev, 0x00, 0x816b, Data); + +/* write_vector(gspca_dev, spca500_visual_defaults); */ + break; + + case BenqDC1016: + case DLinkDSC350: /* FamilyCam 300 */ + case AiptekPocketDV: /* Aiptek PocketDV */ + case Gsmartmini: /*Mustek Gsmart Mini */ + case MustekGsmart300: /* Mustek Gsmart 300 */ + case PalmPixDC85: + case Optimedia: + case ToptroIndus: + case AgfaCl20: + spca500_reinit(gspca_dev); + reg_w(gspca_dev, 0x00, 0x0d01, 0x01); + /* enable drop packet */ + reg_w(gspca_dev, 0x00, 0x850a, 0x0001); + + err = spca50x_setup_qtable(gspca_dev, + 0x00, 0x8800, 0x8840, qtable_pocketdv); + if (err < 0) + PDEBUG(D_ERR, "spca50x_setup_qtable failed"); + reg_w(gspca_dev, 0x00, 0x8880, 2); + + /* familycam Quicksmart pocketDV stuff */ + reg_w(gspca_dev, 0x00, 0x800a, 0x00); + /* Set agc transfer: synced inbetween frames */ + reg_w(gspca_dev, 0x00, 0x820f, 0x01); + /* Init SDRAM - needed for SDRAM access */ + reg_w(gspca_dev, 0x00, 0x870a, 0x04); + + spca500_setmode(gspca_dev, xmult, ymult); + /* switch to video camera mode */ + reg_w(gspca_dev, 0x00, 0x8000, 0x0004); + + reg_r_wait(gspca_dev, 0, 0x8000, 0x44); + + reg_r(gspca_dev, 0x816b, 1); + Data = gspca_dev->usb_buf[0]; + reg_w(gspca_dev, 0x00, 0x816b, Data); + break; + case LogitechTraveler: + case LogitechClickSmart510: + reg_w(gspca_dev, 0x02, 0x00, 0x00); + /* enable drop packet */ + reg_w(gspca_dev, 0x00, 0x850a, 0x0001); + + err = spca50x_setup_qtable(gspca_dev, + 0x00, 0x8800, + 0x8840, qtable_creative_pccam); + if (err < 0) + PDEBUG(D_ERR, "spca50x_setup_qtable failed"); + reg_w(gspca_dev, 0x00, 0x8880, 3); + reg_w(gspca_dev, 0x00, 0x800a, 0x00); + /* Init SDRAM - needed for SDRAM access */ + reg_w(gspca_dev, 0x00, 0x870a, 0x04); + + spca500_setmode(gspca_dev, xmult, ymult); + + /* switch to video camera mode */ + reg_w(gspca_dev, 0x00, 0x8000, 0x0004); + reg_r_wait(gspca_dev, 0, 0x8000, 0x44); + + reg_r(gspca_dev, 0x816b, 1); + Data = gspca_dev->usb_buf[0]; + reg_w(gspca_dev, 0x00, 0x816b, Data); + write_vector(gspca_dev, Clicksmart510_defaults); + break; + } +} + +static void sd_stopN(struct gspca_dev *gspca_dev) +{ + reg_w(gspca_dev, 0, 0x8003, 0x00); + + /* switch to video camera mode */ + reg_w(gspca_dev, 0x00, 0x8000, 0x0004); + reg_r(gspca_dev, 0x8000, 1); + PDEBUG(D_STREAM, "stop SPCA500 done reg8000: 0x%2x", + gspca_dev->usb_buf[0]); +} + +static void sd_stop0(struct gspca_dev *gspca_dev) +{ +} + +static void sd_close(struct gspca_dev *gspca_dev) +{ +} + +static void sd_pkt_scan(struct gspca_dev *gspca_dev, + struct gspca_frame *frame, /* target */ + __u8 *data, /* isoc packet */ + int len) /* iso packet length */ +{ + struct sd *sd = (struct sd *) gspca_dev; + int i; + __u8 *s, *d; + static __u8 ffd9[] = {0xff, 0xd9}; + +/* frames are jpeg 4.1.1 without 0xff escape */ + if (data[0] == 0xff) { + if (data[1] != 0x01) { /* drop packet */ +/* gspca_dev->last_packet_type = DISCARD_PACKET; */ + return; + } + frame = gspca_frame_add(gspca_dev, LAST_PACKET, frame, + ffd9, 2); + + /* put the JPEG header in the new frame */ + jpeg_put_header(gspca_dev, frame, sd->qindex, 0x22); + + data += SPCA500_OFFSET_DATA; + len -= SPCA500_OFFSET_DATA; + } else { + data += 1; + len -= 1; + } + + /* add 0x00 after 0xff */ + for (i = len; --i >= 0; ) + if (data[i] == 0xff) + break; + if (i < 0) { /* no 0xff */ + gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len); + return; + } + s = data; + d = sd->packet; + for (i = 0; i < len; i++) { + *d++ = *s++; + if (s[-1] == 0xff) + *d++ = 0x00; + } + gspca_frame_add(gspca_dev, INTER_PACKET, frame, + sd->packet, d - sd->packet); +} + +static void setbrightness(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + + reg_w(gspca_dev, 0x00, 0x8167, + (__u8) (sd->brightness - 128)); +} + +static void getbrightness(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + int ret; + + ret = reg_r_12(gspca_dev, 0x00, 0x8167, 1); + if (ret >= 0) + sd->brightness = ret + 128; +} + +static void setcontrast(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + + reg_w(gspca_dev, 0x00, 0x8168, sd->contrast); +} + +static void getcontrast(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + int ret; + + ret = reg_r_12(gspca_dev, 0x0, 0x8168, 1); + if (ret >= 0) + sd->contrast = ret; +} + +static void setcolors(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + + reg_w(gspca_dev, 0x00, 0x8169, sd->colors); +} + +static void getcolors(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + int ret; + + ret = reg_r_12(gspca_dev, 0x0, 0x8169, 1); + if (ret >= 0) + sd->colors = ret; +} + +static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->brightness = val; + if (gspca_dev->streaming) + setbrightness(gspca_dev); + return 0; +} + +static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + getbrightness(gspca_dev); + *val = sd->brightness; + return 0; +} + +static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->contrast = val; + if (gspca_dev->streaming) + setcontrast(gspca_dev); + return 0; +} + +static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + getcontrast(gspca_dev); + *val = sd->contrast; + return 0; +} + +static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->colors = val; + if (gspca_dev->streaming) + setcolors(gspca_dev); + return 0; +} + +static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + getcolors(gspca_dev); + *val = sd->colors; + return 0; +} + +/* sub-driver description */ +static struct sd_desc sd_desc = { + .name = MODULE_NAME, + .ctrls = sd_ctrls, + .nctrls = ARRAY_SIZE(sd_ctrls), + .config = sd_config, + .open = sd_open, + .start = sd_start, + .stopN = sd_stopN, + .stop0 = sd_stop0, + .close = sd_close, + .pkt_scan = sd_pkt_scan, +}; + +/* -- module initialisation -- */ +#define DVNM(name) .driver_info = (kernel_ulong_t) name +static const __devinitdata struct usb_device_id device_table[] = { + {USB_DEVICE(0x040a, 0x0300), DVNM("Kodak EZ200")}, + {USB_DEVICE(0x041e, 0x400a), DVNM("Creative PC-CAM 300")}, + {USB_DEVICE(0x046d, 0x0890), DVNM("Logitech QuickCam traveler")}, + {USB_DEVICE(0x046d, 0x0900), DVNM("Logitech Inc. ClickSmart 310")}, + {USB_DEVICE(0x046d, 0x0901), DVNM("Logitech Inc. ClickSmart 510")}, + {USB_DEVICE(0x04a5, 0x300c), DVNM("Benq DC1016")}, + {USB_DEVICE(0x04fc, 0x7333), DVNM("PalmPixDC85")}, + {USB_DEVICE(0x055f, 0xc200), DVNM("Mustek Gsmart 300")}, + {USB_DEVICE(0x055f, 0xc220), DVNM("Gsmart Mini")}, + {USB_DEVICE(0x06bd, 0x0404), DVNM("Agfa CL20")}, + {USB_DEVICE(0x06be, 0x0800), DVNM("Optimedia")}, + {USB_DEVICE(0x084d, 0x0003), DVNM("D-Link DSC-350")}, + {USB_DEVICE(0x08ca, 0x0103), DVNM("Aiptek PocketDV")}, + {USB_DEVICE(0x2899, 0x012c), DVNM("Toptro Industrial")}, + {USB_DEVICE(0x8086, 0x0630), DVNM("Intel Pocket PC Camera")}, + {} +}; +MODULE_DEVICE_TABLE(usb, device_table); + +/* -- device connect -- */ +static int sd_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd), + THIS_MODULE); +} + +static struct usb_driver sd_driver = { + .name = MODULE_NAME, + .id_table = device_table, + .probe = sd_probe, + .disconnect = gspca_disconnect, +}; + +/* -- module insert / remove -- */ +static int __init sd_mod_init(void) +{ + if (usb_register(&sd_driver) < 0) + return -1; + PDEBUG(D_PROBE, "v%s registered", version); + return 0; +} +static void __exit sd_mod_exit(void) +{ + usb_deregister(&sd_driver); + PDEBUG(D_PROBE, "deregistered"); +} + +module_init(sd_mod_init); +module_exit(sd_mod_exit); diff --git a/drivers/media/video/gspca/spca501.c b/drivers/media/video/gspca/spca501.c new file mode 100644 index 000000000000..50e929de0203 --- /dev/null +++ b/drivers/media/video/gspca/spca501.c @@ -0,0 +1,2229 @@ +/* + * SPCA501 chip based cameras initialization data + * + * V4L2 by Jean-Francois Moine <http://moinejf.free.fr> + * + * 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 + * 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 + * + */ + +#define MODULE_NAME "spca501" + +#include "gspca.h" + +#define DRIVER_VERSION_NUMBER KERNEL_VERSION(2, 1, 7) +static const char version[] = "2.1.7"; + +MODULE_AUTHOR("Michel Xhaard <mxhaard@users.sourceforge.net>"); +MODULE_DESCRIPTION("GSPCA/SPCA501 USB Camera Driver"); +MODULE_LICENSE("GPL"); + +/* specific webcam descriptor */ +struct sd { + struct gspca_dev gspca_dev; /* !! must be the first item */ + + unsigned short contrast; + __u8 brightness; + __u8 colors; + + char subtype; +#define Arowana300KCMOSCamera 0 +#define IntelCreateAndShare 1 +#define KodakDVC325 2 +#define MystFromOriUnknownCamera 3 +#define SmileIntlCamera 4 +#define ThreeComHomeConnectLite 5 +#define ViewQuestM318B 6 +}; + +/* V4L2 controls supported by the driver */ +static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val); +static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val); +static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val); +static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val); +static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val); +static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val); + +static struct ctrl sd_ctrls[] = { +#define MY_BRIGHTNESS 0 + { + { + .id = V4L2_CID_BRIGHTNESS, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Brightness", + .minimum = 0, + .maximum = 127, + .step = 1, + .default_value = 63, + }, + .set = sd_setbrightness, + .get = sd_getbrightness, + }, +#define MY_CONTRAST 1 + { + { + .id = V4L2_CID_CONTRAST, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Contrast", + .minimum = 0, + .maximum = 0xffff, + .step = 1, + .default_value = 0xaa00, + }, + .set = sd_setcontrast, + .get = sd_getcontrast, + }, +#define MY_COLOR 2 + { + { + .id = V4L2_CID_SATURATION, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Color", + .minimum = 0, + .maximum = 63, + .step = 1, + .default_value = 31, + }, + .set = sd_setcolors, + .get = sd_getcolors, + }, +}; + +static struct v4l2_pix_format vga_mode[] = { + {160, 120, V4L2_PIX_FMT_SPCA501, V4L2_FIELD_NONE, + .bytesperline = 160, + .sizeimage = 160 * 120 * 3 / 2, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = 2}, + {320, 240, V4L2_PIX_FMT_SPCA501, V4L2_FIELD_NONE, + .bytesperline = 320, + .sizeimage = 320 * 240 * 3 / 2, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = 1}, + {640, 480, V4L2_PIX_FMT_SPCA501, V4L2_FIELD_NONE, + .bytesperline = 640, + .sizeimage = 640 * 480 * 3 / 2, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = 0}, +}; + +#define SPCA50X_REG_USB 0x2 /* spca505 501 */ +/* + * Data to initialize a SPCA501. From a capture file provided by Bill Roehl + * With SPCA501 chip description + */ +#define CCDSP_SET /* set CCDSP parameters */ +#define TG_SET /* set time generator set */ +#undef DSPWIN_SET /* set DSP windows parameters */ +#undef ALTER_GAMA /* Set alternate set to YUV transform coeffs. */ +#define SPCA501_SNAPBIT 0x80 +#define SPCA501_SNAPCTRL 0x10 +/* Frame packet header offsets for the spca501 */ +#define SPCA501_OFFSET_GPIO 1 +#define SPCA501_OFFSET_TYPE 2 +#define SPCA501_OFFSET_TURN3A 3 +#define SPCA501_OFFSET_FRAMSEQ 4 +#define SPCA501_OFFSET_COMPRESS 5 +#define SPCA501_OFFSET_QUANT 6 +#define SPCA501_OFFSET_QUANT2 7 +#define SPCA501_OFFSET_DATA 8 + +#define SPCA501_PROP_COMP_ENABLE(d) ((d) & 1) +#define SPCA501_PROP_SNAP(d) ((d) & 0x40) +#define SPCA501_PROP_SNAP_CTRL(d) ((d) & 0x10) +#define SPCA501_PROP_COMP_THRESH(d) (((d) & 0x0e) >> 1) +#define SPCA501_PROP_COMP_QUANT(d) (((d) & 0x70) >> 4) + +/* SPCA501 CCDSP control */ +#define SPCA501_REG_CCDSP 0x01 +/* SPCA501 control/status registers */ +#define SPCA501_REG_CTLRL 0x02 + +/* registers for color correction and YUV transformation */ +#define SPCA501_A11 0x08 +#define SPCA501_A12 0x09 +#define SPCA501_A13 0x0A +#define SPCA501_A21 0x0B +#define SPCA501_A22 0x0C +#define SPCA501_A23 0x0D +#define SPCA501_A31 0x0E +#define SPCA501_A32 0x0F +#define SPCA501_A33 0x10 + +/* Data for video camera initialization before capturing */ +static const __u16 spca501_open_data[][3] = { + /* bmRequest,value,index */ + + {0x2, 0x50, 0x00}, /* C/S enable soft reset */ + {0x2, 0x40, 0x00}, /* C/S disable soft reset */ + {0x2, 0x02, 0x05}, /* C/S general purpose I/O data */ + {0x2, 0x03, 0x05}, /* C/S general purpose I/O data */ + +#ifdef CCDSP_SET + {0x1, 0x38, 0x01}, /* CCDSP options */ + {0x1, 0x05, 0x02}, /* CCDSP Optical black level for user settings */ + {0x1, 0xC0, 0x03}, /* CCDSP Optical black settings */ + + {0x1, 0x67, 0x07}, + {0x1, 0x63, 0x3f}, /* CCDSP CCD gamma enable */ + {0x1, 0x03, 0x56}, /* Add gamma correction */ + + {0x1, 0xFF, 0x15}, /* CCDSP High luminance for white balance */ + {0x1, 0x01, 0x16}, /* CCDSP Low luminance for white balance */ + +/* Color correction and RGB-to-YUV transformation coefficients changing */ +#ifdef ALTER_GAMA + {0x0, 0x00, 0x08}, /* A11 */ + {0x0, 0x00, 0x09}, /* A12 */ + {0x0, 0x90, 0x0A}, /* A13 */ + {0x0, 0x12, 0x0B}, /* A21 */ + {0x0, 0x00, 0x0C}, /* A22 */ + {0x0, 0x00, 0x0D}, /* A23 */ + {0x0, 0x00, 0x0E}, /* A31 */ + {0x0, 0x02, 0x0F}, /* A32 */ + {0x0, 0x00, 0x10}, /* A33 */ +#else + {0x1, 0x2a, 0x08}, /* A11 0x31 */ + {0x1, 0xf8, 0x09}, /* A12 f8 */ + {0x1, 0xf8, 0x0A}, /* A13 f8 */ + {0x1, 0xf8, 0x0B}, /* A21 f8 */ + {0x1, 0x14, 0x0C}, /* A22 0x14 */ + {0x1, 0xf8, 0x0D}, /* A23 f8 */ + {0x1, 0xf8, 0x0E}, /* A31 f8 */ + {0x1, 0xf8, 0x0F}, /* A32 f8 */ + {0x1, 0x20, 0x10}, /* A33 0x20 */ +#endif + {0x1, 0x00, 0x11}, /* R offset */ + {0x1, 0x00, 0x12}, /* G offset */ + {0x1, 0x00, 0x13}, /* B offset */ + {0x1, 0x00, 0x14}, /* GB offset */ + +#endif + +#ifdef TG_SET + /* Time generator manipulations */ + {0x0, 0xfc, 0x0}, /* Set up high bits of shutter speed */ + {0x0, 0x01, 0x1}, /* Set up low bits of shutter speed */ + + {0x0, 0xe4, 0x04}, /* DCLK*2 clock phase adjustment */ + {0x0, 0x08, 0x05}, /* ADCK phase adjustment, inv. ext. VB */ + {0x0, 0x03, 0x06}, /* FR phase adjustment */ + {0x0, 0x01, 0x07}, /* FCDS phase adjustment */ + {0x0, 0x39, 0x08}, /* FS phase adjustment */ + {0x0, 0x88, 0x0a}, /* FH1 phase and delay adjustment */ + {0x0, 0x03, 0x0f}, /* pixel identification */ + {0x0, 0x00, 0x11}, /* clock source selection (default) */ + + /*VERY strange manipulations with + * select DMCLP or OBPX to be ADCLP output (0x0C) + * OPB always toggle or not (0x0D) but they allow + * us to set up brightness + */ + {0x0, 0x01, 0x0c}, + {0x0, 0xe0, 0x0d}, + /* Done */ +#endif + +#ifdef DSPWIN_SET + {0x1, 0xa0, 0x01}, /* Setting image processing parameters */ + {0x1, 0x1c, 0x17}, /* Changing Windows positions X1 */ + {0x1, 0xe2, 0x19}, /* X2 */ + {0x1, 0x1c, 0x1b}, /* X3 */ + {0x1, 0xe2, 0x1d}, /* X4 */ + {0x1, 0x5f, 0x1f}, /* X5 */ + {0x1, 0x32, 0x20}, /* Y5 */ + {0x1, 0x01, 0x10}, /* Changing A33 */ +#endif + + {0x2, 0x204a, 0x07},/* Setting video compression & resolution 160x120 */ + {0x2, 0x94, 0x06}, /* Setting video no compression */ + {} +}; + +/* + The SPCAxxx docs from Sunplus document these values + in tables, one table per register number. In the data + below, dmRequest is the register number, index is the Addr, + and value is a combination of Bit values. + Bit Value (hex) + 0 01 + 1 02 + 2 04 + 3 08 + 4 10 + 5 20 + 6 40 + 7 80 + */ + +/* Data for chip initialization (set default values) */ +static const __u16 spca501_init_data[][3] = { + /* Set all the values to powerup defaults */ + /* bmRequest,value,index */ + {0x0, 0xAA, 0x00}, + {0x0, 0x02, 0x01}, + {0x0, 0x01, 0x02}, + {0x0, 0x02, 0x03}, + {0x0, 0xCE, 0x04}, + {0x0, 0x00, 0x05}, + {0x0, 0x00, 0x06}, + {0x0, 0x00, 0x07}, + {0x0, 0x00, 0x08}, + {0x0, 0x00, 0x09}, + {0x0, 0x90, 0x0A}, + {0x0, 0x12, 0x0B}, + {0x0, 0x00, 0x0C}, + {0x0, 0x00, 0x0D}, + {0x0, 0x00, 0x0E}, + {0x0, 0x02, 0x0F}, + {0x0, 0x00, 0x10}, + {0x0, 0x00, 0x11}, + {0x0, 0x00, 0x12}, + {0x0, 0x00, 0x13}, + {0x0, 0x00, 0x14}, + {0x0, 0x00, 0x15}, + {0x0, 0x00, 0x16}, + {0x0, 0x00, 0x17}, + {0x0, 0x00, 0x18}, + {0x0, 0x00, 0x19}, + {0x0, 0x00, 0x1A}, + {0x0, 0x00, 0x1B}, + {0x0, 0x00, 0x1C}, + {0x0, 0x00, 0x1D}, + {0x0, 0x00, 0x1E}, + {0x0, 0x00, 0x1F}, + {0x0, 0x00, 0x20}, + {0x0, 0x00, 0x21}, + {0x0, 0x00, 0x22}, + {0x0, 0x00, 0x23}, + {0x0, 0x00, 0x24}, + {0x0, 0x00, 0x25}, + {0x0, 0x00, 0x26}, + {0x0, 0x00, 0x27}, + {0x0, 0x00, 0x28}, + {0x0, 0x00, 0x29}, + {0x0, 0x00, 0x2A}, + {0x0, 0x00, 0x2B}, + {0x0, 0x00, 0x2C}, + {0x0, 0x00, 0x2D}, + {0x0, 0x00, 0x2E}, + {0x0, 0x00, 0x2F}, + {0x0, 0x00, 0x30}, + {0x0, 0x00, 0x31}, + {0x0, 0x00, 0x32}, + {0x0, 0x00, 0x33}, + {0x0, 0x00, 0x34}, + {0x0, 0x00, 0x35}, + {0x0, 0x00, 0x36}, + {0x0, 0x00, 0x37}, + {0x0, 0x00, 0x38}, + {0x0, 0x00, 0x39}, + {0x0, 0x00, 0x3A}, + {0x0, 0x00, 0x3B}, + {0x0, 0x00, 0x3C}, + {0x0, 0x00, 0x3D}, + {0x0, 0x00, 0x3E}, + {0x0, 0x00, 0x3F}, + {0x0, 0x00, 0x40}, + {0x0, 0x00, 0x41}, + {0x0, 0x00, 0x42}, + {0x0, 0x00, 0x43}, + {0x0, 0x00, 0x44}, + {0x0, 0x00, 0x45}, + {0x0, 0x00, 0x46}, + {0x0, 0x00, 0x47}, + {0x0, 0x00, 0x48}, + {0x0, 0x00, 0x49}, + {0x0, 0x00, 0x4A}, + {0x0, 0x00, 0x4B}, + {0x0, 0x00, 0x4C}, + {0x0, 0x00, 0x4D}, + {0x0, 0x00, 0x4E}, + {0x0, 0x00, 0x4F}, + {0x0, 0x00, 0x50}, + {0x0, 0x00, 0x51}, + {0x0, 0x00, 0x52}, + {0x0, 0x00, 0x53}, + {0x0, 0x00, 0x54}, + {0x0, 0x00, 0x55}, + {0x0, 0x00, 0x56}, + {0x0, 0x00, 0x57}, + {0x0, 0x00, 0x58}, + {0x0, 0x00, 0x59}, + {0x0, 0x00, 0x5A}, + {0x0, 0x00, 0x5B}, + {0x0, 0x00, 0x5C}, + {0x0, 0x00, 0x5D}, + {0x0, 0x00, 0x5E}, + {0x0, 0x00, 0x5F}, + {0x0, 0x00, 0x60}, + {0x0, 0x00, 0x61}, + {0x0, 0x00, 0x62}, + {0x0, 0x00, 0x63}, + {0x0, 0x00, 0x64}, + {0x0, 0x00, 0x65}, + {0x0, 0x00, 0x66}, + {0x0, 0x00, 0x67}, + {0x0, 0x00, 0x68}, + {0x0, 0x00, 0x69}, + {0x0, 0x00, 0x6A}, + {0x0, 0x00, 0x6B}, + {0x0, 0x00, 0x6C}, + {0x0, 0x00, 0x6D}, + {0x0, 0x00, 0x6E}, + {0x0, 0x00, 0x6F}, + {0x0, 0x00, 0x70}, + {0x0, 0x00, 0x71}, + {0x0, 0x00, 0x72}, + {0x0, 0x00, 0x73}, + {0x0, 0x00, 0x74}, + {0x0, 0x00, 0x75}, + {0x0, 0x00, 0x76}, + {0x0, 0x00, 0x77}, + {0x0, 0x00, 0x78}, + {0x0, 0x00, 0x79}, + {0x0, 0x00, 0x7A}, + {0x0, 0x00, 0x7B}, + {0x0, 0x00, 0x7C}, + {0x0, 0x00, 0x7D}, + {0x0, 0x00, 0x7E}, + {0x0, 0x00, 0x7F}, + {0x0, 0x00, 0x80}, + {0x0, 0x00, 0x81}, + {0x0, 0x00, 0x82}, + {0x0, 0x00, 0x83}, + {0x0, 0x00, 0x84}, + {0x0, 0x00, 0x85}, + {0x0, 0x00, 0x86}, + {0x0, 0x00, 0x87}, + {0x0, 0x00, 0x88}, + {0x0, 0x00, 0x89}, + {0x0, 0x00, 0x8A}, + {0x0, 0x00, 0x8B}, + {0x0, 0x00, 0x8C}, + {0x0, 0x00, 0x8D}, + {0x0, 0x00, 0x8E}, + {0x0, 0x00, 0x8F}, + {0x0, 0x00, 0x90}, + {0x0, 0x00, 0x91}, + {0x0, 0x00, 0x92}, + {0x0, 0x00, 0x93}, + {0x0, 0x00, 0x94}, + {0x0, 0x00, 0x95}, + {0x0, 0x00, 0x96}, + {0x0, 0x00, 0x97}, + {0x0, 0x00, 0x98}, + {0x0, 0x00, 0x99}, + {0x0, 0x00, 0x9A}, + {0x0, 0x00, 0x9B}, + {0x0, 0x00, 0x9C}, + {0x0, 0x00, 0x9D}, + {0x0, 0x00, 0x9E}, + {0x0, 0x00, 0x9F}, + {0x0, 0x00, 0xA0}, + {0x0, 0x00, 0xA1}, + {0x0, 0x00, 0xA2}, + {0x0, 0x00, 0xA3}, + {0x0, 0x00, 0xA4}, + {0x0, 0x00, 0xA5}, + {0x0, 0x00, 0xA6}, + {0x0, 0x00, 0xA7}, + {0x0, 0x00, 0xA8}, + {0x0, 0x00, 0xA9}, + {0x0, 0x00, 0xAA}, + {0x0, 0x00, 0xAB}, + {0x0, 0x00, 0xAC}, + {0x0, 0x00, 0xAD}, + {0x0, 0x00, 0xAE}, + {0x0, 0x00, 0xAF}, + {0x0, 0x00, 0xB0}, + {0x0, 0x00, 0xB1}, + {0x0, 0x00, 0xB2}, + {0x0, 0x00, 0xB3}, + {0x0, 0x00, 0xB4}, + {0x0, 0x00, 0xB5}, + {0x0, 0x00, 0xB6}, + {0x0, 0x00, 0xB7}, + {0x0, 0x00, 0xB8}, + {0x0, 0x00, 0xB9}, + {0x0, 0x00, 0xBA}, + {0x0, 0x00, 0xBB}, + {0x0, 0x00, 0xBC}, + {0x0, 0x00, 0xBD}, + {0x0, 0x00, 0xBE}, + {0x0, 0x00, 0xBF}, + {0x0, 0x00, 0xC0}, + {0x0, 0x00, 0xC1}, + {0x0, 0x00, 0xC2}, + {0x0, 0x00, 0xC3}, + {0x0, 0x00, 0xC4}, + {0x0, 0x00, 0xC5}, + {0x0, 0x00, 0xC6}, + {0x0, 0x00, 0xC7}, + {0x0, 0x00, 0xC8}, + {0x0, 0x00, 0xC9}, + {0x0, 0x00, 0xCA}, + {0x0, 0x00, 0xCB}, + {0x0, 0x00, 0xCC}, + {0x1, 0xF4, 0x00}, + {0x1, 0x38, 0x01}, + {0x1, 0x40, 0x02}, + {0x1, 0x0A, 0x03}, + {0x1, 0x40, 0x04}, + {0x1, 0x40, 0x05}, + {0x1, 0x40, 0x06}, + {0x1, 0x67, 0x07}, + {0x1, 0x31, 0x08}, + {0x1, 0x00, 0x09}, + {0x1, 0x00, 0x0A}, + {0x1, 0x00, 0x0B}, + {0x1, 0x14, 0x0C}, + {0x1, 0x00, 0x0D}, + {0x1, 0x00, 0x0E}, + {0x1, 0x00, 0x0F}, + {0x1, 0x1E, 0x10}, + {0x1, 0x00, 0x11}, + {0x1, 0x00, 0x12}, + {0x1, 0x00, 0x13}, + {0x1, 0x00, 0x14}, + {0x1, 0xFF, 0x15}, + {0x1, 0x01, 0x16}, + {0x1, 0x32, 0x17}, + {0x1, 0x23, 0x18}, + {0x1, 0xCE, 0x19}, + {0x1, 0x23, 0x1A}, + {0x1, 0x32, 0x1B}, + {0x1, 0x8D, 0x1C}, + {0x1, 0xCE, 0x1D}, + {0x1, 0x8D, 0x1E}, + {0x1, 0x00, 0x1F}, + {0x1, 0x00, 0x20}, + {0x1, 0xFF, 0x3E}, + {0x1, 0x02, 0x3F}, + {0x1, 0x00, 0x40}, + {0x1, 0x00, 0x41}, + {0x1, 0x00, 0x42}, + {0x1, 0x00, 0x43}, + {0x1, 0x00, 0x44}, + {0x1, 0x00, 0x45}, + {0x1, 0x00, 0x46}, + {0x1, 0x00, 0x47}, + {0x1, 0x00, 0x48}, + {0x1, 0x00, 0x49}, + {0x1, 0x00, 0x4A}, + {0x1, 0x00, 0x4B}, + {0x1, 0x00, 0x4C}, + {0x1, 0x00, 0x4D}, + {0x1, 0x00, 0x4E}, + {0x1, 0x00, 0x4F}, + {0x1, 0x00, 0x50}, + {0x1, 0x00, 0x51}, + {0x1, 0x00, 0x52}, + {0x1, 0x00, 0x53}, + {0x1, 0x00, 0x54}, + {0x1, 0x00, 0x55}, + {0x1, 0x00, 0x56}, + {0x1, 0x00, 0x57}, + {0x1, 0x00, 0x58}, + {0x1, 0x00, 0x59}, + {0x1, 0x00, 0x5A}, + {0x2, 0x03, 0x00}, + {0x2, 0x00, 0x01}, + {0x2, 0x00, 0x05}, + {0x2, 0x00, 0x06}, + {0x2, 0x00, 0x07}, + {0x2, 0x00, 0x10}, + {0x2, 0x00, 0x11}, + /* Strange - looks like the 501 driver doesn't do anything + * at insert time except read the EEPROM + */ + {} +}; + +/* Data for video camera init before capture. + * Capture and decoding by Colin Peart. + * This is is for the 3com HomeConnect Lite which is spca501a based. + */ +static const __u16 spca501_3com_open_data[][3] = { + /* bmRequest,value,index */ + {0x2, 0x0050, 0x0000}, /* C/S Enable TG soft reset, timing mode=010 */ + {0x2, 0x0043, 0x0000}, /* C/S Disable TG soft reset, timing mode=010 */ + {0x2, 0x0002, 0x0005}, /* C/S GPIO */ + {0x2, 0x0003, 0x0005}, /* C/S GPIO */ + +#ifdef CCDSP_SET + {0x1, 0x0020, 0x0001}, /* CCDSP Options */ + + {0x1, 0x0020, 0x0002}, /* CCDSP Black Level */ + {0x1, 0x006e, 0x0007}, /* CCDSP Gamma options */ + {0x1, 0x0090, 0x0015}, /* CCDSP Luminance Low */ + {0x1, 0x00ff, 0x0016}, /* CCDSP Luminance High */ + {0x1, 0x0003, 0x003F}, /* CCDSP Gamma correction toggle */ + +#ifdef ALTER_GAMMA + {0x1, 0x0010, 0x0008}, /* CCDSP YUV A11 */ + {0x1, 0x0000, 0x0009}, /* CCDSP YUV A12 */ + {0x1, 0x0000, 0x000a}, /* CCDSP YUV A13 */ + {0x1, 0x0000, 0x000b}, /* CCDSP YUV A21 */ + {0x1, 0x0010, 0x000c}, /* CCDSP YUV A22 */ + {0x1, 0x0000, 0x000d}, /* CCDSP YUV A23 */ + {0x1, 0x0000, 0x000e}, /* CCDSP YUV A31 */ + {0x1, 0x0000, 0x000f}, /* CCDSP YUV A32 */ + {0x1, 0x0010, 0x0010}, /* CCDSP YUV A33 */ + {0x1, 0x0000, 0x0011}, /* CCDSP R Offset */ + {0x1, 0x0000, 0x0012}, /* CCDSP G Offset */ + {0x1, 0x0001, 0x0013}, /* CCDSP B Offset */ + {0x1, 0x0001, 0x0014}, /* CCDSP BG Offset */ + {0x1, 0x003f, 0x00C1}, /* CCDSP Gamma Correction Enable */ +#endif +#endif + +#ifdef TG_SET + {0x0, 0x00fc, 0x0000}, /* TG Shutter Speed High Bits */ + {0x0, 0x0000, 0x0001}, /* TG Shutter Speed Low Bits */ + {0x0, 0x00e4, 0x0004}, /* TG DCLK*2 Adjust */ + {0x0, 0x0008, 0x0005}, /* TG ADCK Adjust */ + {0x0, 0x0003, 0x0006}, /* TG FR Phase Adjust */ + {0x0, 0x0001, 0x0007}, /* TG FCDS Phase Adjust */ + {0x0, 0x0039, 0x0008}, /* TG FS Phase Adjust */ + {0x0, 0x0088, 0x000a}, /* TG MH1 */ + {0x0, 0x0003, 0x000f}, /* TG Pixel ID */ + + /* Like below, unexplained toglleing */ + {0x0, 0x0080, 0x000c}, + {0x0, 0x0000, 0x000d}, + {0x0, 0x0080, 0x000c}, + {0x0, 0x0004, 0x000d}, + {0x0, 0x0000, 0x000c}, + {0x0, 0x0000, 0x000d}, + {0x0, 0x0040, 0x000c}, + {0x0, 0x0017, 0x000d}, + {0x0, 0x00c0, 0x000c}, + {0x0, 0x0000, 0x000d}, + {0x0, 0x0080, 0x000c}, + {0x0, 0x0006, 0x000d}, + {0x0, 0x0080, 0x000c}, + {0x0, 0x0004, 0x000d}, + {0x0, 0x0002, 0x0003}, +#endif + +#ifdef DSPWIN_SET + {0x1, 0x001c, 0x0017}, /* CCDSP W1 Start X */ + {0x1, 0x00e2, 0x0019}, /* CCDSP W2 Start X */ + {0x1, 0x001c, 0x001b}, /* CCDSP W3 Start X */ + {0x1, 0x00e2, 0x001d}, /* CCDSP W4 Start X */ + {0x1, 0x00aa, 0x001f}, /* CCDSP W5 Start X */ + {0x1, 0x0070, 0x0020}, /* CCDSP W5 Start Y */ +#endif + {0x0, 0x0001, 0x0010}, /* TG Start Clock */ + +/* {0x2, 0x006a, 0x0001}, * C/S Enable ISOSYNCH Packet Engine */ + {0x2, 0x0068, 0x0001}, /* C/S Diable ISOSYNCH Packet Engine */ + {0x2, 0x0000, 0x0005}, + {0x2, 0x0043, 0x0000}, /* C/S Set Timing Mode, Disable TG soft reset */ + {0x2, 0x0043, 0x0000}, /* C/S Set Timing Mode, Disable TG soft reset */ + {0x2, 0x0002, 0x0005}, /* C/S GPIO */ + {0x2, 0x0003, 0x0005}, /* C/S GPIO */ + + {0x2, 0x006a, 0x0001}, /* C/S Enable ISOSYNCH Packet Engine */ + {} +}; + +/* + * Data used to initialize a SPCA501C with HV7131B sensor. + * From a capture file taken with USBSnoop v 1.5 + * I have a "SPCA501C pc camera chipset" manual by sunplus, but some + * of the value meanings are obscure or simply "reserved". + * to do list: + * 1) Understand what every value means + * 2) Understand why some values seem to appear more than once + * 3) Write a small comment for each line of the following arrays. + */ +static const __u16 spca501c_arowana_open_data[][3] = { + /* bmRequest,value,index */ + {0x02, 0x0007, 0x0005}, + {0x02, 0xa048, 0x0000}, + {0x05, 0x0022, 0x0004}, + {0x01, 0x0006, 0x0011}, + {0x01, 0x00ff, 0x0012}, + {0x01, 0x0014, 0x0013}, + {0x01, 0x0000, 0x0014}, + {0x01, 0x0042, 0x0051}, + {0x01, 0x0040, 0x0052}, + {0x01, 0x0051, 0x0053}, + {0x01, 0x0040, 0x0054}, + {0x01, 0x0000, 0x0055}, + {0x00, 0x0025, 0x0000}, + {0x00, 0x0026, 0x0000}, + {0x00, 0x0001, 0x0000}, + {0x00, 0x0027, 0x0000}, + {0x00, 0x008a, 0x0000}, + {} +}; + +static const __u16 spca501c_arowana_init_data[][3] = { + /* bmRequest,value,index */ + {0x02, 0x0007, 0x0005}, + {0x02, 0xa048, 0x0000}, + {0x05, 0x0022, 0x0004}, + {0x01, 0x0006, 0x0011}, + {0x01, 0x00ff, 0x0012}, + {0x01, 0x0014, 0x0013}, + {0x01, 0x0000, 0x0014}, + {0x01, 0x0042, 0x0051}, + {0x01, 0x0040, 0x0052}, + {0x01, 0x0051, 0x0053}, + {0x01, 0x0040, 0x0054}, + {0x01, 0x0000, 0x0055}, + {0x00, 0x0025, 0x0000}, + {0x00, 0x0026, 0x0000}, + {0x00, 0x0001, 0x0000}, + {0x00, 0x0027, 0x0000}, + {0x00, 0x008a, 0x0000}, + {0x02, 0x0000, 0x0005}, + {0x02, 0x0007, 0x0005}, + {0x02, 0x2000, 0x0000}, + {0x05, 0x0022, 0x0004}, + {0x05, 0x0015, 0x0001}, + {0x05, 0x00ea, 0x0000}, + {0x05, 0x0021, 0x0001}, + {0x05, 0x00d2, 0x0000}, + {0x05, 0x0023, 0x0001}, + {0x05, 0x0003, 0x0000}, + {0x05, 0x0030, 0x0001}, + {0x05, 0x002b, 0x0000}, + {0x05, 0x0031, 0x0001}, + {0x05, 0x0023, 0x0000}, + {0x05, 0x0032, 0x0001}, + {0x05, 0x0023, 0x0000}, + {0x05, 0x0033, 0x0001}, + {0x05, 0x0023, 0x0000}, + {0x05, 0x0034, 0x0001}, + {0x05, 0x0002, 0x0000}, + {0x05, 0x0050, 0x0001}, + {0x05, 0x0000, 0x0000}, + {0x05, 0x0051, 0x0001}, + {0x05, 0x0000, 0x0000}, + {0x05, 0x0052, 0x0001}, + {0x05, 0x0000, 0x0000}, + {0x05, 0x0054, 0x0001}, + {0x05, 0x0001, 0x0000}, + {0x00, 0x0000, 0x0001}, + {0x00, 0x0000, 0x0002}, + {0x00, 0x000c, 0x0003}, + {0x00, 0x0000, 0x0004}, + {0x00, 0x0090, 0x0005}, + {0x00, 0x0000, 0x0006}, + {0x00, 0x0040, 0x0007}, + {0x00, 0x00c0, 0x0008}, + {0x00, 0x004a, 0x0009}, + {0x00, 0x0000, 0x000a}, + {0x00, 0x0000, 0x000b}, + {0x00, 0x0001, 0x000c}, + {0x00, 0x0001, 0x000d}, + {0x00, 0x0000, 0x000e}, + {0x00, 0x0002, 0x000f}, + {0x00, 0x0001, 0x0010}, + {0x00, 0x0000, 0x0011}, + {0x00, 0x0000, 0x0012}, + {0x00, 0x0002, 0x0020}, + {0x00, 0x0080, 0x0021}, + {0x00, 0x0001, 0x0022}, + {0x00, 0x00e0, 0x0023}, + {0x00, 0x0000, 0x0024}, + {0x00, 0x00d5, 0x0025}, + {0x00, 0x0000, 0x0026}, + {0x00, 0x000b, 0x0027}, + {0x00, 0x0000, 0x0046}, + {0x00, 0x0000, 0x0047}, + {0x00, 0x0000, 0x0048}, + {0x00, 0x0000, 0x0049}, + {0x00, 0x0008, 0x004a}, + {0xff, 0x0000, 0x00d0}, + {0xff, 0x00d8, 0x00d1}, + {0xff, 0x0000, 0x00d4}, + {0xff, 0x0000, 0x00d5}, + {0x01, 0x00a6, 0x0000}, + {0x01, 0x0028, 0x0001}, + {0x01, 0x0000, 0x0002}, + {0x01, 0x000a, 0x0003}, + {0x01, 0x0040, 0x0004}, + {0x01, 0x0066, 0x0007}, + {0x01, 0x0011, 0x0008}, + {0x01, 0x0032, 0x0009}, + {0x01, 0x00fd, 0x000a}, + {0x01, 0x0038, 0x000b}, + {0x01, 0x00d1, 0x000c}, + {0x01, 0x00f7, 0x000d}, + {0x01, 0x00ed, 0x000e}, + {0x01, 0x00d8, 0x000f}, + {0x01, 0x0038, 0x0010}, + {0x01, 0x00ff, 0x0015}, + {0x01, 0x0001, 0x0016}, + {0x01, 0x0032, 0x0017}, + {0x01, 0x0023, 0x0018}, + {0x01, 0x00ce, 0x0019}, + {0x01, 0x0023, 0x001a}, + {0x01, 0x0032, 0x001b}, + {0x01, 0x008d, 0x001c}, + {0x01, 0x00ce, 0x001d}, + {0x01, 0x008d, 0x001e}, + {0x01, 0x0000, 0x001f}, + {0x01, 0x0000, 0x0020}, + {0x01, 0x00ff, 0x003e}, + {0x01, 0x0003, 0x003f}, + {0x01, 0x0000, 0x0040}, + {0x01, 0x0035, 0x0041}, + {0x01, 0x0053, 0x0042}, + {0x01, 0x0069, 0x0043}, + {0x01, 0x007c, 0x0044}, + {0x01, 0x008c, 0x0045}, + {0x01, 0x009a, 0x0046}, + {0x01, 0x00a8, 0x0047}, + {0x01, 0x00b4, 0x0048}, + {0x01, 0x00bf, 0x0049}, + {0x01, 0x00ca, 0x004a}, + {0x01, 0x00d4, 0x004b}, + {0x01, 0x00dd, 0x004c}, + {0x01, 0x00e7, 0x004d}, + {0x01, 0x00ef, 0x004e}, + {0x01, 0x00f8, 0x004f}, + {0x01, 0x00ff, 0x0050}, + {0x01, 0x0001, 0x0056}, + {0x01, 0x0060, 0x0057}, + {0x01, 0x0040, 0x0058}, + {0x01, 0x0011, 0x0059}, + {0x01, 0x0001, 0x005a}, + {0x02, 0x0007, 0x0005}, + {0x02, 0xa048, 0x0000}, + {0x02, 0x0007, 0x0005}, + {0x02, 0x0015, 0x0006}, + {0x02, 0x100a, 0x0007}, + {0x02, 0xa048, 0x0000}, + {0x02, 0xc002, 0x0001}, + {0x02, 0x000f, 0x0005}, + {0x02, 0xa048, 0x0000}, + {0x05, 0x0022, 0x0004}, + {0x05, 0x0025, 0x0001}, + {0x05, 0x0000, 0x0000}, + {0x05, 0x0026, 0x0001}, + {0x05, 0x0001, 0x0000}, + {0x05, 0x0027, 0x0001}, + {0x05, 0x0000, 0x0000}, + {0x05, 0x0001, 0x0001}, + {0x05, 0x0000, 0x0000}, + {0x05, 0x0021, 0x0001}, + {0x05, 0x00d2, 0x0000}, + {0x05, 0x0020, 0x0001}, + {0x05, 0x0000, 0x0000}, + {0x00, 0x0090, 0x0005}, + {0x01, 0x00a6, 0x0000}, + {0x02, 0x0007, 0x0005}, + {0x02, 0x2000, 0x0000}, + {0x05, 0x0022, 0x0004}, + {0x05, 0x0015, 0x0001}, + {0x05, 0x00ea, 0x0000}, + {0x05, 0x0021, 0x0001}, + {0x05, 0x00d2, 0x0000}, + {0x05, 0x0023, 0x0001}, + {0x05, 0x0003, 0x0000}, + {0x05, 0x0030, 0x0001}, + {0x05, 0x002b, 0x0000}, + {0x05, 0x0031, 0x0001}, + {0x05, 0x0023, 0x0000}, + {0x05, 0x0032, 0x0001}, + {0x05, 0x0023, 0x0000}, + {0x05, 0x0033, 0x0001}, + {0x05, 0x0023, 0x0000}, + {0x05, 0x0034, 0x0001}, + {0x05, 0x0002, 0x0000}, + {0x05, 0x0050, 0x0001}, + {0x05, 0x0000, 0x0000}, + {0x05, 0x0051, 0x0001}, + {0x05, 0x0000, 0x0000}, + {0x05, 0x0052, 0x0001}, + {0x05, 0x0000, 0x0000}, + {0x05, 0x0054, 0x0001}, + {0x05, 0x0001, 0x0000}, + {0x00, 0x0000, 0x0001}, + {0x00, 0x0000, 0x0002}, + {0x00, 0x000c, 0x0003}, + {0x00, 0x0000, 0x0004}, + {0x00, 0x0090, 0x0005}, + {0x00, 0x0000, 0x0006}, + {0x00, 0x0040, 0x0007}, + {0x00, 0x00c0, 0x0008}, + {0x00, 0x004a, 0x0009}, + {0x00, 0x0000, 0x000a}, + {0x00, 0x0000, 0x000b}, + {0x00, 0x0001, 0x000c}, + {0x00, 0x0001, 0x000d}, + {0x00, 0x0000, 0x000e}, + {0x00, 0x0002, 0x000f}, + {0x00, 0x0001, 0x0010}, + {0x00, 0x0000, 0x0011}, + {0x00, 0x0000, 0x0012}, + {0x00, 0x0002, 0x0020}, + {0x00, 0x0080, 0x0021}, + {0x00, 0x0001, 0x0022}, + {0x00, 0x00e0, 0x0023}, + {0x00, 0x0000, 0x0024}, + {0x00, 0x00d5, 0x0025}, + {0x00, 0x0000, 0x0026}, + {0x00, 0x000b, 0x0027}, + {0x00, 0x0000, 0x0046}, + {0x00, 0x0000, 0x0047}, + {0x00, 0x0000, 0x0048}, + {0x00, 0x0000, 0x0049}, + {0x00, 0x0008, 0x004a}, + {0xff, 0x0000, 0x00d0}, + {0xff, 0x00d8, 0x00d1}, + {0xff, 0x0000, 0x00d4}, + {0xff, 0x0000, 0x00d5}, + {0x01, 0x00a6, 0x0000}, + {0x01, 0x0028, 0x0001}, + {0x01, 0x0000, 0x0002}, + {0x01, 0x000a, 0x0003}, + {0x01, 0x0040, 0x0004}, + {0x01, 0x0066, 0x0007}, + {0x01, 0x0011, 0x0008}, + {0x01, 0x0032, 0x0009}, + {0x01, 0x00fd, 0x000a}, + {0x01, 0x0038, 0x000b}, + {0x01, 0x00d1, 0x000c}, + {0x01, 0x00f7, 0x000d}, + {0x01, 0x00ed, 0x000e}, + {0x01, 0x00d8, 0x000f}, + {0x01, 0x0038, 0x0010}, + {0x01, 0x00ff, 0x0015}, + {0x01, 0x0001, 0x0016}, + {0x01, 0x0032, 0x0017}, + {0x01, 0x0023, 0x0018}, + {0x01, 0x00ce, 0x0019}, + {0x01, 0x0023, 0x001a}, + {0x01, 0x0032, 0x001b}, + {0x01, 0x008d, 0x001c}, + {0x01, 0x00ce, 0x001d}, + {0x01, 0x008d, 0x001e}, + {0x01, 0x0000, 0x001f}, + {0x01, 0x0000, 0x0020}, + {0x01, 0x00ff, 0x003e}, + {0x01, 0x0003, 0x003f}, + {0x01, 0x0000, 0x0040}, + {0x01, 0x0035, 0x0041}, + {0x01, 0x0053, 0x0042}, + {0x01, 0x0069, 0x0043}, + {0x01, 0x007c, 0x0044}, + {0x01, 0x008c, 0x0045}, + {0x01, 0x009a, 0x0046}, + {0x01, 0x00a8, 0x0047}, + {0x01, 0x00b4, 0x0048}, + {0x01, 0x00bf, 0x0049}, + {0x01, 0x00ca, 0x004a}, + {0x01, 0x00d4, 0x004b}, + {0x01, 0x00dd, 0x004c}, + {0x01, 0x00e7, 0x004d}, + {0x01, 0x00ef, 0x004e}, + {0x01, 0x00f8, 0x004f}, + {0x01, 0x00ff, 0x0050}, + {0x01, 0x0001, 0x0056}, + {0x01, 0x0060, 0x0057}, + {0x01, 0x0040, 0x0058}, + {0x01, 0x0011, 0x0059}, + {0x01, 0x0001, 0x005a}, + {0x02, 0x0007, 0x0005}, + {0x02, 0xa048, 0x0000}, + {0x02, 0x0007, 0x0005}, + {0x02, 0x0015, 0x0006}, + {0x02, 0x100a, 0x0007}, + {0x02, 0xa048, 0x0000}, + {0x02, 0xc002, 0x0001}, + {0x02, 0x000f, 0x0005}, + {0x02, 0xa048, 0x0000}, + {0x05, 0x0022, 0x0004}, + {0x05, 0x0025, 0x0001}, + {0x05, 0x0000, 0x0000}, + {0x05, 0x0026, 0x0001}, + {0x05, 0x0001, 0x0000}, + {0x05, 0x0027, 0x0001}, + {0x05, 0x0000, 0x0000}, + {0x05, 0x0001, 0x0001}, + {0x05, 0x0000, 0x0000}, + {0x05, 0x0021, 0x0001}, + {0x05, 0x00d2, 0x0000}, + {0x05, 0x0020, 0x0001}, + {0x05, 0x0000, 0x0000}, + {0x00, 0x0090, 0x0005}, + {0x01, 0x00a6, 0x0000}, + {0x01, 0x0003, 0x003f}, + {0x01, 0x0001, 0x0056}, + {0x01, 0x0011, 0x0008}, + {0x01, 0x0032, 0x0009}, + {0x01, 0xfffd, 0x000a}, + {0x01, 0x0023, 0x000b}, + {0x01, 0xffea, 0x000c}, + {0x01, 0xfff4, 0x000d}, + {0x01, 0xfffc, 0x000e}, + {0x01, 0xffe3, 0x000f}, + {0x01, 0x001f, 0x0010}, + {0x01, 0x00a8, 0x0001}, + {0x01, 0x0067, 0x0007}, + {0x01, 0x0032, 0x0017}, + {0x01, 0x0023, 0x0018}, + {0x01, 0x00ce, 0x0019}, + {0x01, 0x0023, 0x001a}, + {0x01, 0x0032, 0x001b}, + {0x01, 0x008d, 0x001c}, + {0x01, 0x00ce, 0x001d}, + {0x01, 0x008d, 0x001e}, + {0x01, 0x00c8, 0x0015}, + {0x01, 0x0032, 0x0016}, + {0x01, 0x0000, 0x0011}, + {0x01, 0x0000, 0x0012}, + {0x01, 0x0000, 0x0013}, + {0x01, 0x000a, 0x0003}, + {0x02, 0xc002, 0x0001}, + {0x02, 0x0007, 0x0005}, + {0x02, 0xc000, 0x0001}, + {0x02, 0x0000, 0x0005}, + {0x02, 0x0007, 0x0005}, + {0x02, 0x2000, 0x0000}, + {0x05, 0x0022, 0x0004}, + {0x05, 0x0015, 0x0001}, + {0x05, 0x00ea, 0x0000}, + {0x05, 0x0021, 0x0001}, + {0x05, 0x00d2, 0x0000}, + {0x05, 0x0023, 0x0001}, + {0x05, 0x0003, 0x0000}, + {0x05, 0x0030, 0x0001}, + {0x05, 0x002b, 0x0000}, + {0x05, 0x0031, 0x0001}, + {0x05, 0x0023, 0x0000}, + {0x05, 0x0032, 0x0001}, + {0x05, 0x0023, 0x0000}, + {0x05, 0x0033, 0x0001}, + {0x05, 0x0023, 0x0000}, + {0x05, 0x0034, 0x0001}, + {0x05, 0x0002, 0x0000}, + {0x05, 0x0050, 0x0001}, + {0x05, 0x0000, 0x0000}, + {0x05, 0x0051, 0x0001}, + {0x05, 0x0000, 0x0000}, + {0x05, 0x0052, 0x0001}, + {0x05, 0x0000, 0x0000}, + {0x05, 0x0054, 0x0001}, + {0x05, 0x0001, 0x0000}, + {0x00, 0x0000, 0x0001}, + {0x00, 0x0000, 0x0002}, + {0x00, 0x000c, 0x0003}, + {0x00, 0x0000, 0x0004}, + {0x00, 0x0090, 0x0005}, + {0x00, 0x0000, 0x0006}, + {0x00, 0x0040, 0x0007}, + {0x00, 0x00c0, 0x0008}, + {0x00, 0x004a, 0x0009}, + {0x00, 0x0000, 0x000a}, + {0x00, 0x0000, 0x000b}, + {0x00, 0x0001, 0x000c}, + {0x00, 0x0001, 0x000d}, + {0x00, 0x0000, 0x000e}, + {0x00, 0x0002, 0x000f}, + {0x00, 0x0001, 0x0010}, + {0x00, 0x0000, 0x0011}, + {0x00, 0x0000, 0x0012}, + {0x00, 0x0002, 0x0020}, + {0x00, 0x0080, 0x0021}, + {0x00, 0x0001, 0x0022}, + {0x00, 0x00e0, 0x0023}, + {0x00, 0x0000, 0x0024}, + {0x00, 0x00d5, 0x0025}, + {0x00, 0x0000, 0x0026}, + {0x00, 0x000b, 0x0027}, + {0x00, 0x0000, 0x0046}, + {0x00, 0x0000, 0x0047}, + {0x00, 0x0000, 0x0048}, + {0x00, 0x0000, 0x0049}, + {0x00, 0x0008, 0x004a}, + {0xff, 0x0000, 0x00d0}, + {0xff, 0x00d8, 0x00d1}, + {0xff, 0x0000, 0x00d4}, + {0xff, 0x0000, 0x00d5}, + {0x01, 0x00a6, 0x0000}, + {0x01, 0x0028, 0x0001}, + {0x01, 0x0000, 0x0002}, + {0x01, 0x000a, 0x0003}, + {0x01, 0x0040, 0x0004}, + {0x01, 0x0066, 0x0007}, + {0x01, 0x0011, 0x0008}, + {0x01, 0x0032, 0x0009}, + {0x01, 0x00fd, 0x000a}, + {0x01, 0x0038, 0x000b}, + {0x01, 0x00d1, 0x000c}, + {0x01, 0x00f7, 0x000d}, + {0x01, 0x00ed, 0x000e}, + {0x01, 0x00d8, 0x000f}, + {0x01, 0x0038, 0x0010}, + {0x01, 0x00ff, 0x0015}, + {0x01, 0x0001, 0x0016}, + {0x01, 0x0032, 0x0017}, + {0x01, 0x0023, 0x0018}, + {0x01, 0x00ce, 0x0019}, + {0x01, 0x0023, 0x001a}, + {0x01, 0x0032, 0x001b}, + {0x01, 0x008d, 0x001c}, + {0x01, 0x00ce, 0x001d}, + {0x01, 0x008d, 0x001e}, + {0x01, 0x0000, 0x001f}, + {0x01, 0x0000, 0x0020}, + {0x01, 0x00ff, 0x003e}, + {0x01, 0x0003, 0x003f}, + {0x01, 0x0000, 0x0040}, + {0x01, 0x0035, 0x0041}, + {0x01, 0x0053, 0x0042}, + {0x01, 0x0069, 0x0043}, + {0x01, 0x007c, 0x0044}, + {0x01, 0x008c, 0x0045}, + {0x01, 0x009a, 0x0046}, + {0x01, 0x00a8, 0x0047}, + {0x01, 0x00b4, 0x0048}, + {0x01, 0x00bf, 0x0049}, + {0x01, 0x00ca, 0x004a}, + {0x01, 0x00d4, 0x004b}, + {0x01, 0x00dd, 0x004c}, + {0x01, 0x00e7, 0x004d}, + {0x01, 0x00ef, 0x004e}, + {0x01, 0x00f8, 0x004f}, + {0x01, 0x00ff, 0x0050}, + {0x01, 0x0001, 0x0056}, + {0x01, 0x0060, 0x0057}, + {0x01, 0x0040, 0x0058}, + {0x01, 0x0011, 0x0059}, + {0x01, 0x0001, 0x005a}, + {0x02, 0x0007, 0x0005}, + {0x02, 0xa048, 0x0000}, + {0x02, 0x0007, 0x0005}, + {0x02, 0x0015, 0x0006}, + {0x02, 0x100a, 0x0007}, + {0x02, 0xa048, 0x0000}, + {0x02, 0xc002, 0x0001}, + {0x02, 0x000f, 0x0005}, + {0x02, 0xa048, 0x0000}, + {0x05, 0x0022, 0x0004}, + {0x05, 0x0025, 0x0001}, + {0x05, 0x0000, 0x0000}, + {0x05, 0x0026, 0x0001}, + {0x05, 0x0001, 0x0000}, + {0x05, 0x0027, 0x0001}, + {0x05, 0x0000, 0x0000}, + {0x05, 0x0001, 0x0001}, + {0x05, 0x0000, 0x0000}, + {0x05, 0x0021, 0x0001}, + {0x05, 0x00d2, 0x0000}, + {0x05, 0x0020, 0x0001}, + {0x05, 0x0000, 0x0000}, + {0x00, 0x0090, 0x0005}, + {0x01, 0x00a6, 0x0000}, + {0x02, 0x0007, 0x0005}, + {0x02, 0x2000, 0x0000}, + {0x05, 0x0022, 0x0004}, + {0x05, 0x0015, 0x0001}, + {0x05, 0x00ea, 0x0000}, + {0x05, 0x0021, 0x0001}, + {0x05, 0x00d2, 0x0000}, + {0x05, 0x0023, 0x0001}, + {0x05, 0x0003, 0x0000}, + {0x05, 0x0030, 0x0001}, + {0x05, 0x002b, 0x0000}, + {0x05, 0x0031, 0x0001}, + {0x05, 0x0023, 0x0000}, + {0x05, 0x0032, 0x0001}, + {0x05, 0x0023, 0x0000}, + {0x05, 0x0033, 0x0001}, + {0x05, 0x0023, 0x0000}, + {0x05, 0x0034, 0x0001}, + {0x05, 0x0002, 0x0000}, + {0x05, 0x0050, 0x0001}, + {0x05, 0x0000, 0x0000}, + {0x05, 0x0051, 0x0001}, + {0x05, 0x0000, 0x0000}, + {0x05, 0x0052, 0x0001}, + {0x05, 0x0000, 0x0000}, + {0x05, 0x0054, 0x0001}, + {0x05, 0x0001, 0x0000}, + {0x00, 0x0000, 0x0001}, + {0x00, 0x0000, 0x0002}, + {0x00, 0x000c, 0x0003}, + {0x00, 0x0000, 0x0004}, + {0x00, 0x0090, 0x0005}, + {0x00, 0x0000, 0x0006}, + {0x00, 0x0040, 0x0007}, + {0x00, 0x00c0, 0x0008}, + {0x00, 0x004a, 0x0009}, + {0x00, 0x0000, 0x000a}, + {0x00, 0x0000, 0x000b}, + {0x00, 0x0001, 0x000c}, + {0x00, 0x0001, 0x000d}, + {0x00, 0x0000, 0x000e}, + {0x00, 0x0002, 0x000f}, + {0x00, 0x0001, 0x0010}, + {0x00, 0x0000, 0x0011}, + {0x00, 0x0000, 0x0012}, + {0x00, 0x0002, 0x0020}, + {0x00, 0x0080, 0x0021}, + {0x00, 0x0001, 0x0022}, + {0x00, 0x00e0, 0x0023}, + {0x00, 0x0000, 0x0024}, + {0x00, 0x00d5, 0x0025}, + {0x00, 0x0000, 0x0026}, + {0x00, 0x000b, 0x0027}, + {0x00, 0x0000, 0x0046}, + {0x00, 0x0000, 0x0047}, + {0x00, 0x0000, 0x0048}, + {0x00, 0x0000, 0x0049}, + {0x00, 0x0008, 0x004a}, + {0xff, 0x0000, 0x00d0}, + {0xff, 0x00d8, 0x00d1}, + {0xff, 0x0000, 0x00d4}, + {0xff, 0x0000, 0x00d5}, + {0x01, 0x00a6, 0x0000}, + {0x01, 0x0028, 0x0001}, + {0x01, 0x0000, 0x0002}, + {0x01, 0x000a, 0x0003}, + {0x01, 0x0040, 0x0004}, + {0x01, 0x0066, 0x0007}, + {0x01, 0x0011, 0x0008}, + {0x01, 0x0032, 0x0009}, + {0x01, 0x00fd, 0x000a}, + {0x01, 0x0038, 0x000b}, + {0x01, 0x00d1, 0x000c}, + {0x01, 0x00f7, 0x000d}, + {0x01, 0x00ed, 0x000e}, + {0x01, 0x00d8, 0x000f}, + {0x01, 0x0038, 0x0010}, + {0x01, 0x00ff, 0x0015}, + {0x01, 0x0001, 0x0016}, + {0x01, 0x0032, 0x0017}, + {0x01, 0x0023, 0x0018}, + {0x01, 0x00ce, 0x0019}, + {0x01, 0x0023, 0x001a}, + {0x01, 0x0032, 0x001b}, + {0x01, 0x008d, 0x001c}, + {0x01, 0x00ce, 0x001d}, + {0x01, 0x008d, 0x001e}, + {0x01, 0x0000, 0x001f}, + {0x01, 0x0000, 0x0020}, + {0x01, 0x00ff, 0x003e}, + {0x01, 0x0003, 0x003f}, + {0x01, 0x0000, 0x0040}, + {0x01, 0x0035, 0x0041}, + {0x01, 0x0053, 0x0042}, + {0x01, 0x0069, 0x0043}, + {0x01, 0x007c, 0x0044}, + {0x01, 0x008c, 0x0045}, + {0x01, 0x009a, 0x0046}, + {0x01, 0x00a8, 0x0047}, + {0x01, 0x00b4, 0x0048}, + {0x01, 0x00bf, 0x0049}, + {0x01, 0x00ca, 0x004a}, + {0x01, 0x00d4, 0x004b}, + {0x01, 0x00dd, 0x004c}, + {0x01, 0x00e7, 0x004d}, + {0x01, 0x00ef, 0x004e}, + {0x01, 0x00f8, 0x004f}, + {0x01, 0x00ff, 0x0050}, + {0x01, 0x0001, 0x0056}, + {0x01, 0x0060, 0x0057}, + {0x01, 0x0040, 0x0058}, + {0x01, 0x0011, 0x0059}, + {0x01, 0x0001, 0x005a}, + {0x02, 0x0007, 0x0005}, + {0x02, 0xa048, 0x0000}, + {0x02, 0x0007, 0x0005}, + {0x02, 0x0015, 0x0006}, + {0x02, 0x100a, 0x0007}, + {0x02, 0xa048, 0x0000}, + {0x02, 0xc002, 0x0001}, + {0x02, 0x000f, 0x0005}, + {0x02, 0xa048, 0x0000}, + {0x05, 0x0022, 0x0004}, + {0x05, 0x0025, 0x0001}, + {0x05, 0x0000, 0x0000}, + {0x05, 0x0026, 0x0001}, + {0x05, 0x0001, 0x0000}, + {0x05, 0x0027, 0x0001}, + {0x05, 0x0000, 0x0000}, + {0x05, 0x0001, 0x0001}, + {0x05, 0x0000, 0x0000}, + {0x05, 0x0021, 0x0001}, + {0x05, 0x00d2, 0x0000}, + {0x05, 0x0020, 0x0001}, + {0x05, 0x0000, 0x0000}, + {0x00, 0x0090, 0x0005}, + {0x01, 0x00a6, 0x0000}, + {0x05, 0x0026, 0x0001}, + {0x05, 0x0001, 0x0000}, + {0x05, 0x0027, 0x0001}, + {0x05, 0x000f, 0x0000}, + {0x01, 0x0003, 0x003f}, + {0x01, 0x0001, 0x0056}, + {0x01, 0x0011, 0x0008}, + {0x01, 0x0032, 0x0009}, + {0x01, 0xfffd, 0x000a}, + {0x01, 0x0023, 0x000b}, + {0x01, 0xffea, 0x000c}, + {0x01, 0xfff4, 0x000d}, + {0x01, 0xfffc, 0x000e}, + {0x01, 0xffe3, 0x000f}, + {0x01, 0x001f, 0x0010}, + {0x01, 0x00a8, 0x0001}, + {0x01, 0x0067, 0x0007}, + {0x01, 0x0042, 0x0051}, + {0x01, 0x0051, 0x0053}, + {0x01, 0x000a, 0x0003}, + {0x02, 0xc002, 0x0001}, + {0x02, 0x0007, 0x0005}, + {0x02, 0xc000, 0x0001}, + {0x02, 0x0000, 0x0005}, + {0x02, 0x0007, 0x0005}, + {0x02, 0x2000, 0x0000}, + {0x05, 0x0022, 0x0004}, + {0x05, 0x0015, 0x0001}, + {0x05, 0x00ea, 0x0000}, + {0x05, 0x0021, 0x0001}, + {0x05, 0x00d2, 0x0000}, + {0x05, 0x0023, 0x0001}, + {0x05, 0x0003, 0x0000}, + {0x05, 0x0030, 0x0001}, + {0x05, 0x002b, 0x0000}, + {0x05, 0x0031, 0x0001}, + {0x05, 0x0023, 0x0000}, + {0x05, 0x0032, 0x0001}, + {0x05, 0x0023, 0x0000}, + {0x05, 0x0033, 0x0001}, + {0x05, 0x0023, 0x0000}, + {0x05, 0x0034, 0x0001}, + {0x05, 0x0002, 0x0000}, + {0x05, 0x0050, 0x0001}, + {0x05, 0x0000, 0x0000}, + {0x05, 0x0051, 0x0001}, + {0x05, 0x0000, 0x0000}, + {0x05, 0x0052, 0x0001}, + {0x05, 0x0000, 0x0000}, + {0x05, 0x0054, 0x0001}, + {0x05, 0x0001, 0x0000}, + {0x00, 0x0000, 0x0001}, + {0x00, 0x0000, 0x0002}, + {0x00, 0x000c, 0x0003}, + {0x00, 0x0000, 0x0004}, + {0x00, 0x0090, 0x0005}, + {0x00, 0x0000, 0x0006}, + {0x00, 0x0040, 0x0007}, + {0x00, 0x00c0, 0x0008}, + {0x00, 0x004a, 0x0009}, + {0x00, 0x0000, 0x000a}, + {0x00, 0x0000, 0x000b}, + {0x00, 0x0001, 0x000c}, + {0x00, 0x0001, 0x000d}, + {0x00, 0x0000, 0x000e}, + {0x00, 0x0002, 0x000f}, + {0x00, 0x0001, 0x0010}, + {0x00, 0x0000, 0x0011}, + {0x00, 0x0000, 0x0012}, + {0x00, 0x0002, 0x0020}, + {0x00, 0x0080, 0x0021}, + {0x00, 0x0001, 0x0022}, + {0x00, 0x00e0, 0x0023}, + {0x00, 0x0000, 0x0024}, + {0x00, 0x00d5, 0x0025}, + {0x00, 0x0000, 0x0026}, + {0x00, 0x000b, 0x0027}, + {0x00, 0x0000, 0x0046}, + {0x00, 0x0000, 0x0047}, + {0x00, 0x0000, 0x0048}, + {0x00, 0x0000, 0x0049}, + {0x00, 0x0008, 0x004a}, + {0xff, 0x0000, 0x00d0}, + {0xff, 0x00d8, 0x00d1}, + {0xff, 0x0000, 0x00d4}, + {0xff, 0x0000, 0x00d5}, + {0x01, 0x00a6, 0x0000}, + {0x01, 0x0028, 0x0001}, + {0x01, 0x0000, 0x0002}, + {0x01, 0x000a, 0x0003}, + {0x01, 0x0040, 0x0004}, + {0x01, 0x0066, 0x0007}, + {0x01, 0x0011, 0x0008}, + {0x01, 0x0032, 0x0009}, + {0x01, 0x00fd, 0x000a}, + {0x01, 0x0038, 0x000b}, + {0x01, 0x00d1, 0x000c}, + {0x01, 0x00f7, 0x000d}, + {0x01, 0x00ed, 0x000e}, + {0x01, 0x00d8, 0x000f}, + {0x01, 0x0038, 0x0010}, + {0x01, 0x00ff, 0x0015}, + {0x01, 0x0001, 0x0016}, + {0x01, 0x0032, 0x0017}, + {0x01, 0x0023, 0x0018}, + {0x01, 0x00ce, 0x0019}, + {0x01, 0x0023, 0x001a}, + {0x01, 0x0032, 0x001b}, + {0x01, 0x008d, 0x001c}, + {0x01, 0x00ce, 0x001d}, + {0x01, 0x008d, 0x001e}, + {0x01, 0x0000, 0x001f}, + {0x01, 0x0000, 0x0020}, + {0x01, 0x00ff, 0x003e}, + {0x01, 0x0003, 0x003f}, + {0x01, 0x0000, 0x0040}, + {0x01, 0x0035, 0x0041}, + {0x01, 0x0053, 0x0042}, + {0x01, 0x0069, 0x0043}, + {0x01, 0x007c, 0x0044}, + {0x01, 0x008c, 0x0045}, + {0x01, 0x009a, 0x0046}, + {0x01, 0x00a8, 0x0047}, + {0x01, 0x00b4, 0x0048}, + {0x01, 0x00bf, 0x0049}, + {0x01, 0x00ca, 0x004a}, + {0x01, 0x00d4, 0x004b}, + {0x01, 0x00dd, 0x004c}, + {0x01, 0x00e7, 0x004d}, + {0x01, 0x00ef, 0x004e}, + {0x01, 0x00f8, 0x004f}, + {0x01, 0x00ff, 0x0050}, + {0x01, 0x0001, 0x0056}, + {0x01, 0x0060, 0x0057}, + {0x01, 0x0040, 0x0058}, + {0x01, 0x0011, 0x0059}, + {0x01, 0x0001, 0x005a}, + {0x02, 0x0007, 0x0005}, + {0x02, 0xa048, 0x0000}, + {0x02, 0x0007, 0x0005}, + {0x02, 0x0015, 0x0006}, + {0x02, 0x100a, 0x0007}, + {0x02, 0xa048, 0x0000}, + {0x02, 0xc002, 0x0001}, + {0x02, 0x000f, 0x0005}, + {0x02, 0xa048, 0x0000}, + {0x05, 0x0022, 0x0004}, + {0x05, 0x0025, 0x0001}, + {0x05, 0x0000, 0x0000}, + {0x05, 0x0026, 0x0001}, + {0x05, 0x0001, 0x0000}, + {0x05, 0x0027, 0x0001}, + {0x05, 0x0000, 0x0000}, + {0x05, 0x0001, 0x0001}, + {0x05, 0x0000, 0x0000}, + {0x05, 0x0021, 0x0001}, + {0x05, 0x00d2, 0x0000}, + {0x05, 0x0020, 0x0001}, + {0x05, 0x0000, 0x0000}, + {0x00, 0x0090, 0x0005}, + {0x01, 0x00a6, 0x0000}, + {0x02, 0x0007, 0x0005}, + {0x02, 0x2000, 0x0000}, + {0x05, 0x0022, 0x0004}, + {0x05, 0x0015, 0x0001}, + {0x05, 0x00ea, 0x0000}, + {0x05, 0x0021, 0x0001}, + {0x05, 0x00d2, 0x0000}, + {0x05, 0x0023, 0x0001}, + {0x05, 0x0003, 0x0000}, + {0x05, 0x0030, 0x0001}, + {0x05, 0x002b, 0x0000}, + {0x05, 0x0031, 0x0001}, + {0x05, 0x0023, 0x0000}, + {0x05, 0x0032, 0x0001}, + {0x05, 0x0023, 0x0000}, + {0x05, 0x0033, 0x0001}, + {0x05, 0x0023, 0x0000}, + {0x05, 0x0034, 0x0001}, + {0x05, 0x0002, 0x0000}, + {0x05, 0x0050, 0x0001}, + {0x05, 0x0000, 0x0000}, + {0x05, 0x0051, 0x0001}, + {0x05, 0x0000, 0x0000}, + {0x05, 0x0052, 0x0001}, + {0x05, 0x0000, 0x0000}, + {0x05, 0x0054, 0x0001}, + {0x05, 0x0001, 0x0000}, + {0x00, 0x0000, 0x0001}, + {0x00, 0x0000, 0x0002}, + {0x00, 0x000c, 0x0003}, + {0x00, 0x0000, 0x0004}, + {0x00, 0x0090, 0x0005}, + {0x00, 0x0000, 0x0006}, + {0x00, 0x0040, 0x0007}, + {0x00, 0x00c0, 0x0008}, + {0x00, 0x004a, 0x0009}, + {0x00, 0x0000, 0x000a}, + {0x00, 0x0000, 0x000b}, + {0x00, 0x0001, 0x000c}, + {0x00, 0x0001, 0x000d}, + {0x00, 0x0000, 0x000e}, + {0x00, 0x0002, 0x000f}, + {0x00, 0x0001, 0x0010}, + {0x00, 0x0000, 0x0011}, + {0x00, 0x0000, 0x0012}, + {0x00, 0x0002, 0x0020}, + {0x00, 0x0080, 0x0021}, + {0x00, 0x0001, 0x0022}, + {0x00, 0x00e0, 0x0023}, + {0x00, 0x0000, 0x0024}, + {0x00, 0x00d5, 0x0025}, + {0x00, 0x0000, 0x0026}, + {0x00, 0x000b, 0x0027}, + {0x00, 0x0000, 0x0046}, + {0x00, 0x0000, 0x0047}, + {0x00, 0x0000, 0x0048}, + {0x00, 0x0000, 0x0049}, + {0x00, 0x0008, 0x004a}, + {0xff, 0x0000, 0x00d0}, + {0xff, 0x00d8, 0x00d1}, + {0xff, 0x0000, 0x00d4}, + {0xff, 0x0000, 0x00d5}, + {0x01, 0x00a6, 0x0000}, + {0x01, 0x0028, 0x0001}, + {0x01, 0x0000, 0x0002}, + {0x01, 0x000a, 0x0003}, + {0x01, 0x0040, 0x0004}, + {0x01, 0x0066, 0x0007}, + {0x01, 0x0011, 0x0008}, + {0x01, 0x0032, 0x0009}, + {0x01, 0x00fd, 0x000a}, + {0x01, 0x0038, 0x000b}, + {0x01, 0x00d1, 0x000c}, + {0x01, 0x00f7, 0x000d}, + {0x01, 0x00ed, 0x000e}, + {0x01, 0x00d8, 0x000f}, + {0x01, 0x0038, 0x0010}, + {0x01, 0x00ff, 0x0015}, + {0x01, 0x0001, 0x0016}, + {0x01, 0x0032, 0x0017}, + {0x01, 0x0023, 0x0018}, + {0x01, 0x00ce, 0x0019}, + {0x01, 0x0023, 0x001a}, + {0x01, 0x0032, 0x001b}, + {0x01, 0x008d, 0x001c}, + {0x01, 0x00ce, 0x001d}, + {0x01, 0x008d, 0x001e}, + {0x01, 0x0000, 0x001f}, + {0x01, 0x0000, 0x0020}, + {0x01, 0x00ff, 0x003e}, + {0x01, 0x0003, 0x003f}, + {0x01, 0x0000, 0x0040}, + {0x01, 0x0035, 0x0041}, + {0x01, 0x0053, 0x0042}, + {0x01, 0x0069, 0x0043}, + {0x01, 0x007c, 0x0044}, + {0x01, 0x008c, 0x0045}, + {0x01, 0x009a, 0x0046}, + {0x01, 0x00a8, 0x0047}, + {0x01, 0x00b4, 0x0048}, + {0x01, 0x00bf, 0x0049}, + {0x01, 0x00ca, 0x004a}, + {0x01, 0x00d4, 0x004b}, + {0x01, 0x00dd, 0x004c}, + {0x01, 0x00e7, 0x004d}, + {0x01, 0x00ef, 0x004e}, + {0x01, 0x00f8, 0x004f}, + {0x01, 0x00ff, 0x0050}, + {0x01, 0x0001, 0x0056}, + {0x01, 0x0060, 0x0057}, + {0x01, 0x0040, 0x0058}, + {0x01, 0x0011, 0x0059}, + {0x01, 0x0001, 0x005a}, + {0x02, 0x0007, 0x0005}, + {0x02, 0xa048, 0x0000}, + {0x02, 0x0007, 0x0005}, + {0x02, 0x0015, 0x0006}, + {0x02, 0x100a, 0x0007}, + {0x02, 0xa048, 0x0000}, + {0x02, 0xc002, 0x0001}, + {0x02, 0x000f, 0x0005}, + {0x02, 0xa048, 0x0000}, + {0x05, 0x0022, 0x0004}, + {0x05, 0x0025, 0x0001}, + {0x05, 0x0000, 0x0000}, + {0x05, 0x0026, 0x0001}, + {0x05, 0x0001, 0x0000}, + {0x05, 0x0027, 0x0001}, + {0x05, 0x0000, 0x0000}, + {0x05, 0x0001, 0x0001}, + {0x05, 0x0000, 0x0000}, + {0x05, 0x0021, 0x0001}, + {0x05, 0x00d2, 0x0000}, + {0x05, 0x0020, 0x0001}, + {0x05, 0x0000, 0x0000}, + {0x00, 0x0090, 0x0005}, + {0x01, 0x00a6, 0x0000}, + {0x05, 0x0026, 0x0001}, + {0x05, 0x0001, 0x0000}, + {0x05, 0x0027, 0x0001}, + {0x05, 0x001e, 0x0000}, + {0x01, 0x0003, 0x003f}, + {0x01, 0x0001, 0x0056}, + {0x01, 0x0011, 0x0008}, + {0x01, 0x0032, 0x0009}, + {0x01, 0xfffd, 0x000a}, + {0x01, 0x0023, 0x000b}, + {0x01, 0xffea, 0x000c}, + {0x01, 0xfff4, 0x000d}, + {0x01, 0xfffc, 0x000e}, + {0x01, 0xffe3, 0x000f}, + {0x01, 0x001f, 0x0010}, + {0x01, 0x00a8, 0x0001}, + {0x01, 0x0067, 0x0007}, + {0x01, 0x0042, 0x0051}, + {0x01, 0x0051, 0x0053}, + {0x01, 0x000a, 0x0003}, + {0x02, 0xc002, 0x0001}, + {0x02, 0x0007, 0x0005}, + {0x01, 0x0042, 0x0051}, + {0x01, 0x0051, 0x0053}, + {0x05, 0x0026, 0x0001}, + {0x05, 0x0001, 0x0000}, + {0x05, 0x0027, 0x0001}, + {0x05, 0x002d, 0x0000}, + {0x01, 0x0003, 0x003f}, + {0x01, 0x0001, 0x0056}, + {0x02, 0xc000, 0x0001}, + {0x02, 0x0000, 0x0005}, + {} +}; + +/* Unknow camera from Ori Usbid 0x0000:0x0000 */ +/* Based on snoops from Ori Cohen */ +static const __u16 spca501c_mysterious_open_data[][3] = { + {0x02, 0x000f, 0x0005}, + {0x02, 0xa048, 0x0000}, + {0x05, 0x0022, 0x0004}, +/* DSP Registers */ + {0x01, 0x0016, 0x0011}, /* RGB offset */ + {0x01, 0x0000, 0x0012}, + {0x01, 0x0006, 0x0013}, + {0x01, 0x0078, 0x0051}, + {0x01, 0x0040, 0x0052}, + {0x01, 0x0046, 0x0053}, + {0x01, 0x0040, 0x0054}, + {0x00, 0x0025, 0x0000}, +/* {0x00, 0x0000, 0x0000 }, */ +/* Part 2 */ +/* TG Registers */ + {0x00, 0x0026, 0x0000}, + {0x00, 0x0001, 0x0000}, + {0x00, 0x0027, 0x0000}, + {0x00, 0x008a, 0x0000}, + {0x02, 0x0007, 0x0005}, + {0x02, 0x2000, 0x0000}, + {0x05, 0x0022, 0x0004}, + {0x05, 0x0015, 0x0001}, + {0x05, 0x00ea, 0x0000}, + {0x05, 0x0021, 0x0001}, + {0x05, 0x00d2, 0x0000}, + {0x05, 0x0023, 0x0001}, + {0x05, 0x0003, 0x0000}, + {0x05, 0x0030, 0x0001}, + {0x05, 0x002b, 0x0000}, + {0x05, 0x0031, 0x0001}, + {0x05, 0x0023, 0x0000}, + {0x05, 0x0032, 0x0001}, + {0x05, 0x0023, 0x0000}, + {0x05, 0x0033, 0x0001}, + {0x05, 0x0023, 0x0000}, + {0x05, 0x0034, 0x0001}, + {0x05, 0x0002, 0x0000}, + {0x05, 0x0050, 0x0001}, + {0x05, 0x0000, 0x0000}, + {0x05, 0x0051, 0x0001}, + {0x05, 0x0000, 0x0000}, + {0x05, 0x0052, 0x0001}, + {0x05, 0x0000, 0x0000}, + {0x05, 0x0054, 0x0001}, + {0x05, 0x0001, 0x0000}, + {} +}; + +/* Based on snoops from Ori Cohen */ +static const __u16 spca501c_mysterious_init_data[][3] = { +/* Part 3 */ +/* TG registers */ +/* {0x00, 0x0000, 0x0000}, */ + {0x00, 0x0000, 0x0001}, + {0x00, 0x0000, 0x0002}, + {0x00, 0x0006, 0x0003}, + {0x00, 0x0000, 0x0004}, + {0x00, 0x0090, 0x0005}, + {0x00, 0x0000, 0x0006}, + {0x00, 0x0040, 0x0007}, + {0x00, 0x00c0, 0x0008}, + {0x00, 0x004a, 0x0009}, + {0x00, 0x0000, 0x000a}, + {0x00, 0x0000, 0x000b}, + {0x00, 0x0001, 0x000c}, + {0x00, 0x0001, 0x000d}, + {0x00, 0x0000, 0x000e}, + {0x00, 0x0002, 0x000f}, + {0x00, 0x0001, 0x0010}, + {0x00, 0x0000, 0x0011}, + {0x00, 0x0001, 0x0012}, + {0x00, 0x0002, 0x0020}, + {0x00, 0x0080, 0x0021}, /* 640 */ + {0x00, 0x0001, 0x0022}, + {0x00, 0x00e0, 0x0023}, /* 480 */ + {0x00, 0x0000, 0x0024}, /* Offset H hight */ + {0x00, 0x00d3, 0x0025}, /* low */ + {0x00, 0x0000, 0x0026}, /* Offset V */ + {0x00, 0x000d, 0x0027}, /* low */ + {0x00, 0x0000, 0x0046}, + {0x00, 0x0000, 0x0047}, + {0x00, 0x0000, 0x0048}, + {0x00, 0x0000, 0x0049}, + {0x00, 0x0008, 0x004a}, +/* DSP Registers */ + {0x01, 0x00a6, 0x0000}, + {0x01, 0x0028, 0x0001}, + {0x01, 0x0000, 0x0002}, + {0x01, 0x000a, 0x0003}, /* Level Calc bit7 ->1 Auto */ + {0x01, 0x0040, 0x0004}, + {0x01, 0x0066, 0x0007}, + {0x01, 0x000f, 0x0008}, /* A11 Color correction coeff */ + {0x01, 0x002d, 0x0009}, /* A12 */ + {0x01, 0x0005, 0x000a}, /* A13 */ + {0x01, 0x0023, 0x000b}, /* A21 */ + {0x01, 0x00e0, 0x000c}, /* A22 */ + {0x01, 0x00fd, 0x000d}, /* A23 */ + {0x01, 0x00f4, 0x000e}, /* A31 */ + {0x01, 0x00e4, 0x000f}, /* A32 */ + {0x01, 0x0028, 0x0010}, /* A33 */ + {0x01, 0x00ff, 0x0015}, /* Reserved */ + {0x01, 0x0001, 0x0016}, /* Reserved */ + {0x01, 0x0032, 0x0017}, /* Win1 Start begin */ + {0x01, 0x0023, 0x0018}, + {0x01, 0x00ce, 0x0019}, + {0x01, 0x0023, 0x001a}, + {0x01, 0x0032, 0x001b}, + {0x01, 0x008d, 0x001c}, + {0x01, 0x00ce, 0x001d}, + {0x01, 0x008d, 0x001e}, + {0x01, 0x0000, 0x001f}, + {0x01, 0x0000, 0x0020}, /* Win1 Start end */ + {0x01, 0x00ff, 0x003e}, /* Reserved begin */ + {0x01, 0x0002, 0x003f}, + {0x01, 0x0000, 0x0040}, + {0x01, 0x0035, 0x0041}, + {0x01, 0x0053, 0x0042}, + {0x01, 0x0069, 0x0043}, + {0x01, 0x007c, 0x0044}, + {0x01, 0x008c, 0x0045}, + {0x01, 0x009a, 0x0046}, + {0x01, 0x00a8, 0x0047}, + {0x01, 0x00b4, 0x0048}, + {0x01, 0x00bf, 0x0049}, + {0x01, 0x00ca, 0x004a}, + {0x01, 0x00d4, 0x004b}, + {0x01, 0x00dd, 0x004c}, + {0x01, 0x00e7, 0x004d}, + {0x01, 0x00ef, 0x004e}, + {0x01, 0x00f8, 0x004f}, + {0x01, 0x00ff, 0x0050}, + {0x01, 0x0003, 0x0056}, /* Reserved end */ + {0x01, 0x0060, 0x0057}, /* Edge Gain */ + {0x01, 0x0040, 0x0058}, + {0x01, 0x0011, 0x0059}, /* Edge Bandwidth */ + {0x01, 0x0001, 0x005a}, + {0x02, 0x0007, 0x0005}, + {0x02, 0xa048, 0x0000}, + {0x02, 0x0007, 0x0005}, + {0x02, 0x0015, 0x0006}, + {0x02, 0x200a, 0x0007}, + {0x02, 0xa048, 0x0000}, + {0x02, 0xc000, 0x0001}, + {0x02, 0x000f, 0x0005}, + {0x02, 0xa048, 0x0000}, + {0x05, 0x0022, 0x0004}, + {0x05, 0x0025, 0x0001}, + {0x05, 0x0000, 0x0000}, +/* Part 4 */ + {0x05, 0x0026, 0x0001}, + {0x05, 0x0001, 0x0000}, + {0x05, 0x0027, 0x0001}, + {0x05, 0x0000, 0x0000}, + {0x05, 0x0001, 0x0001}, + {0x05, 0x0000, 0x0000}, + {0x05, 0x0021, 0x0001}, + {0x05, 0x00d2, 0x0000}, + {0x05, 0x0020, 0x0001}, + {0x05, 0x0000, 0x0000}, + {0x00, 0x0090, 0x0005}, + {0x01, 0x00a6, 0x0000}, + {0x02, 0x0000, 0x0005}, + {0x05, 0x0026, 0x0001}, + {0x05, 0x0001, 0x0000}, + {0x05, 0x0027, 0x0001}, + {0x05, 0x004e, 0x0000}, +/* Part 5 */ + {0x01, 0x0003, 0x003f}, + {0x01, 0x0001, 0x0056}, + {0x01, 0x000f, 0x0008}, + {0x01, 0x002d, 0x0009}, + {0x01, 0x0005, 0x000a}, + {0x01, 0x0023, 0x000b}, + {0x01, 0xffe0, 0x000c}, + {0x01, 0xfffd, 0x000d}, + {0x01, 0xfff4, 0x000e}, + {0x01, 0xffe4, 0x000f}, + {0x01, 0x0028, 0x0010}, + {0x01, 0x00a8, 0x0001}, + {0x01, 0x0066, 0x0007}, + {0x01, 0x0032, 0x0017}, + {0x01, 0x0023, 0x0018}, + {0x01, 0x00ce, 0x0019}, + {0x01, 0x0023, 0x001a}, + {0x01, 0x0032, 0x001b}, + {0x01, 0x008d, 0x001c}, + {0x01, 0x00ce, 0x001d}, + {0x01, 0x008d, 0x001e}, + {0x01, 0x00c8, 0x0015}, /* c8 Poids fort Luma */ + {0x01, 0x0032, 0x0016}, /* 32 */ + {0x01, 0x0016, 0x0011}, /* R 00 */ + {0x01, 0x0016, 0x0012}, /* G 00 */ + {0x01, 0x0016, 0x0013}, /* B 00 */ + {0x01, 0x000a, 0x0003}, + {0x02, 0xc002, 0x0001}, + {0x02, 0x0007, 0x0005}, + {} +}; + +static int reg_write(struct usb_device *dev, + __u16 req, __u16 index, __u16 value) +{ + int ret; + + ret = usb_control_msg(dev, + usb_sndctrlpipe(dev, 0), + req, + USB_TYPE_VENDOR | USB_RECIP_DEVICE, + value, index, NULL, 0, 500); + PDEBUG(D_USBO, "reg write: 0x%02x 0x%02x 0x%02x", + req, index, value); + if (ret < 0) + PDEBUG(D_ERR, "reg write: error %d", ret); + return ret; +} + +/* returns: negative is error, pos or zero is data */ +static int reg_read(struct gspca_dev *gspca_dev, + __u16 req, /* bRequest */ + __u16 index, /* wIndex */ + __u16 length) /* wLength (1 or 2 only) */ +{ + int ret; + + gspca_dev->usb_buf[1] = 0; + ret = usb_control_msg(gspca_dev->dev, + usb_rcvctrlpipe(gspca_dev->dev, 0), + req, + USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + 0, /* value */ + index, + gspca_dev->usb_buf, length, + 500); /* timeout */ + if (ret < 0) { + PDEBUG(D_ERR, "reg_read err %d", ret); + return -1; + } + return (gspca_dev->usb_buf[1] << 8) + gspca_dev->usb_buf[0]; +} + +static int write_vector(struct gspca_dev *gspca_dev, + const __u16 data[][3]) +{ + struct usb_device *dev = gspca_dev->dev; + int ret, i = 0; + + while (data[i][0] != 0 || data[i][1] != 0 || data[i][2] != 0) { + ret = reg_write(dev, data[i][0], data[i][2], data[i][1]); + if (ret < 0) { + PDEBUG(D_ERR, + "Reg write failed for 0x%02x,0x%02x,0x%02x", + data[i][0], data[i][1], data[i][2]); + return ret; + } + i++; + } + return 0; +} + +static void setbrightness(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + + reg_write(gspca_dev->dev, SPCA501_REG_CCDSP, 0x11, sd->brightness); + reg_write(gspca_dev->dev, SPCA501_REG_CCDSP, 0x12, sd->brightness); + reg_write(gspca_dev->dev, SPCA501_REG_CCDSP, 0x13, sd->brightness); +} + +static void getbrightness(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + __u16 brightness; + + brightness = reg_read(gspca_dev, SPCA501_REG_CCDSP, 0x11, 2); + sd->brightness = brightness << 1; +} + +static void setcontrast(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + + reg_write(gspca_dev->dev, 0x00, 0x00, + (sd->contrast >> 8) & 0xff); + reg_write(gspca_dev->dev, 0x00, 0x01, + sd->contrast & 0xff); +} + +static void getcontrast(struct gspca_dev *gspca_dev) +{ +/* spca50x->contrast = 0xaa01; */ +} + +static void setcolors(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + + reg_write(gspca_dev->dev, SPCA501_REG_CCDSP, 0x0c, sd->colors); +} + +static void getcolors(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->colors = reg_read(gspca_dev, SPCA501_REG_CCDSP, 0x0c, 2); +/* sd->hue = (reg_read(gspca_dev, SPCA501_REG_CCDSP, 0x13, */ +/* 2) & 0xFF) << 8; */ +} + +/* this function is called at probe time */ +static int sd_config(struct gspca_dev *gspca_dev, + const struct usb_device_id *id) +{ + struct sd *sd = (struct sd *) gspca_dev; + struct cam *cam; + __u16 vendor; + __u16 product; + + vendor = id->idVendor; + product = id->idProduct; + switch (vendor) { + case 0x0000: /* Unknow Camera */ +/* switch (product) { */ +/* case 0x0000: */ + sd->subtype = MystFromOriUnknownCamera; +/* break; */ +/* } */ + break; + case 0x040a: /* Kodak cameras */ +/* switch (product) { */ +/* case 0x0002: */ + sd->subtype = KodakDVC325; +/* break; */ +/* } */ + break; + case 0x0497: /* Smile International */ +/* switch (product) { */ +/* case 0xc001: */ + sd->subtype = SmileIntlCamera; +/* break; */ +/* } */ + break; + case 0x0506: /* 3COM cameras */ +/* switch (product) { */ +/* case 0x00df: */ + sd->subtype = ThreeComHomeConnectLite; +/* break; */ +/* } */ + break; + case 0x0733: /* Rebadged ViewQuest (Intel) and ViewQuest cameras */ + switch (product) { + case 0x0401: + sd->subtype = IntelCreateAndShare; + break; + case 0x0402: + sd->subtype = ViewQuestM318B; + break; + } + break; + case 0x1776: /* Arowana */ +/* switch (product) { */ +/* case 0x501c: */ + sd->subtype = Arowana300KCMOSCamera; +/* break; */ +/* } */ + break; + } + cam = &gspca_dev->cam; + cam->dev_name = (char *) id->driver_info; + cam->epaddr = 0x01; + cam->cam_mode = vga_mode; + cam->nmodes = sizeof vga_mode / sizeof vga_mode[0]; + sd->brightness = sd_ctrls[MY_BRIGHTNESS].qctrl.default_value; + sd->contrast = sd_ctrls[MY_CONTRAST].qctrl.default_value; + sd->colors = sd_ctrls[MY_COLOR].qctrl.default_value; + + switch (sd->subtype) { + case Arowana300KCMOSCamera: + case SmileIntlCamera: + /* Arowana 300k CMOS Camera data */ + if (write_vector(gspca_dev, spca501c_arowana_init_data)) + goto error; + break; + case MystFromOriUnknownCamera: + /* UnKnow Ori CMOS Camera data */ + if (write_vector(gspca_dev, spca501c_mysterious_open_data)) + goto error; + break; + default: + /* generic spca501 init data */ + if (write_vector(gspca_dev, spca501_init_data)) + goto error; + break; + } + return 0; +error: + return -EINVAL; +} + +/* this function is called at open time */ +static int sd_open(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + + switch (sd->subtype) { + case ThreeComHomeConnectLite: + /* Special handling for 3com data */ + write_vector(gspca_dev, spca501_3com_open_data); + break; + case Arowana300KCMOSCamera: + case SmileIntlCamera: + /* Arowana 300k CMOS Camera data */ + write_vector(gspca_dev, spca501c_arowana_open_data); + break; + case MystFromOriUnknownCamera: + /* UnKnow CMOS Camera data */ + write_vector(gspca_dev, spca501c_mysterious_init_data); + break; + default: + /* Generic 501 open data */ + write_vector(gspca_dev, spca501_open_data); + } + PDEBUG(D_STREAM, "Initializing SPCA501 finished"); + return 0; +} + +static void sd_start(struct gspca_dev *gspca_dev) +{ + struct usb_device *dev = gspca_dev->dev; + int mode; + + /* memorize the wanted pixel format */ + mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv; + + /* Enable ISO packet machine CTRL reg=2, + * index=1 bitmask=0x2 (bit ordinal 1) */ + reg_write(dev, SPCA50X_REG_USB, 0x6, 0x94); + switch (mode) { + case 0: /* 640x480 */ + reg_write(dev, SPCA50X_REG_USB, 0x07, 0x004a); + break; + case 1: /* 320x240 */ + reg_write(dev, SPCA50X_REG_USB, 0x07, 0x104a); + break; + default: +/* case 2: * 160x120 */ + reg_write(dev, SPCA50X_REG_USB, 0x07, 0x204a); + break; + } + reg_write(dev, SPCA501_REG_CTLRL, 0x01, 0x02); + + /* HDG atleast the Intel CreateAndShare needs to have one of its + * brightness / contrast / color set otherwise it assumes what seems + * max contrast. Note that strange enough setting any of these is + * enough to fix the max contrast problem, to be sure we set all 3 */ + setbrightness(gspca_dev); + setcontrast(gspca_dev); + setcolors(gspca_dev); +} + +static void sd_stopN(struct gspca_dev *gspca_dev) +{ + /* Disable ISO packet + * machine CTRL reg=2, index=1 bitmask=0x0 (bit ordinal 1) */ + reg_write(gspca_dev->dev, SPCA501_REG_CTLRL, 0x01, 0x00); +} + +static void sd_stop0(struct gspca_dev *gspca_dev) +{ +} + +/* this function is called at close time */ +static void sd_close(struct gspca_dev *gspca_dev) +{ + reg_write(gspca_dev->dev, SPCA501_REG_CTLRL, 0x05, 0x00); +} + +static void sd_pkt_scan(struct gspca_dev *gspca_dev, + struct gspca_frame *frame, /* target */ + __u8 *data, /* isoc packet */ + int len) /* iso packet length */ +{ + switch (data[0]) { + case 0: /* start of frame */ + frame = gspca_frame_add(gspca_dev, + LAST_PACKET, + frame, + data, 0); + data += SPCA501_OFFSET_DATA; + len -= SPCA501_OFFSET_DATA; + gspca_frame_add(gspca_dev, FIRST_PACKET, frame, + data, len); + return; + case 0xff: /* drop */ +/* gspca_dev->last_packet_type = DISCARD_PACKET; */ + return; + } + data++; + len--; + gspca_frame_add(gspca_dev, INTER_PACKET, frame, + data, len); +} + +static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->brightness = val; + if (gspca_dev->streaming) + setbrightness(gspca_dev); + return 0; +} + +static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + getbrightness(gspca_dev); + *val = sd->brightness; + return 0; +} + +static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->contrast = val; + if (gspca_dev->streaming) + setcontrast(gspca_dev); + return 0; +} + +static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + getcontrast(gspca_dev); + *val = sd->contrast; + return 0; +} + +static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->colors = val; + if (gspca_dev->streaming) + setcolors(gspca_dev); + return 0; +} + +static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + getcolors(gspca_dev); + *val = sd->colors; + return 0; +} + +/* sub-driver description */ +static const struct sd_desc sd_desc = { + .name = MODULE_NAME, + .ctrls = sd_ctrls, + .nctrls = ARRAY_SIZE(sd_ctrls), + .config = sd_config, + .open = sd_open, + .start = sd_start, + .stopN = sd_stopN, + .stop0 = sd_stop0, + .close = sd_close, + .pkt_scan = sd_pkt_scan, +}; + +/* -- module initialisation -- */ +#define DVNM(name) .driver_info = (kernel_ulong_t) name +static const __devinitdata struct usb_device_id device_table[] = { + {USB_DEVICE(0x040a, 0x0002), DVNM("Kodak DVC-325")}, + {USB_DEVICE(0x0497, 0xc001), DVNM("Smile International")}, + {USB_DEVICE(0x0506, 0x00df), DVNM("3Com HomeConnect Lite")}, + {USB_DEVICE(0x0733, 0x0401), DVNM("Intel Create and Share")}, + {USB_DEVICE(0x0733, 0x0402), DVNM("ViewQuest M318B")}, + {USB_DEVICE(0x1776, 0x501c), DVNM("Arowana 300K CMOS Camera")}, + {USB_DEVICE(0x0000, 0x0000), DVNM("MystFromOri Unknow Camera")}, + {} +}; +MODULE_DEVICE_TABLE(usb, device_table); + +/* -- device connect -- */ +static int sd_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd), + THIS_MODULE); +} + +static struct usb_driver sd_driver = { + .name = MODULE_NAME, + .id_table = device_table, + .probe = sd_probe, + .disconnect = gspca_disconnect, +}; + +/* -- module insert / remove -- */ +static int __init sd_mod_init(void) +{ + if (usb_register(&sd_driver) < 0) + return -1; + PDEBUG(D_PROBE, "v%s registered", version); + return 0; +} +static void __exit sd_mod_exit(void) +{ + usb_deregister(&sd_driver); + PDEBUG(D_PROBE, "deregistered"); +} + +module_init(sd_mod_init); +module_exit(sd_mod_exit); diff --git a/drivers/media/video/gspca/spca505.c b/drivers/media/video/gspca/spca505.c new file mode 100644 index 000000000000..ddea6e140aa8 --- /dev/null +++ b/drivers/media/video/gspca/spca505.c @@ -0,0 +1,951 @@ +/* + * SPCA505 chip based cameras initialization data + * + * V4L2 by Jean-Francis Moine <http://moinejf.free.fr> + * + * 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 + * 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 + * + */ + +#define MODULE_NAME "spca505" + +#include "gspca.h" + +#define DRIVER_VERSION_NUMBER KERNEL_VERSION(2, 1, 7) +static const char version[] = "2.1.7"; + +MODULE_AUTHOR("Michel Xhaard <mxhaard@users.sourceforge.net>"); +MODULE_DESCRIPTION("GSPCA/SPCA505 USB Camera Driver"); +MODULE_LICENSE("GPL"); + +/* specific webcam descriptor */ +struct sd { + struct gspca_dev gspca_dev; /* !! must be the first item */ + + int buflen; + unsigned char tmpbuf[640 * 480 * 3 / 2]; /* YYUV per line */ + unsigned char tmpbuf2[640 * 480 * 2]; /* YUYV */ + + unsigned char brightness; + + char subtype; +#define IntelPCCameraPro 0 +#define Nxultra 1 +}; + +/* V4L2 controls supported by the driver */ +static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val); +static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val); + +static struct ctrl sd_ctrls[] = { +#define SD_BRIGHTNESS 0 + { + { + .id = V4L2_CID_BRIGHTNESS, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Brightness", + .minimum = 0, + .maximum = 255, + .step = 1, + .default_value = 127, + }, + .set = sd_setbrightness, + .get = sd_getbrightness, + }, +}; + +static struct v4l2_pix_format vga_mode[] = { + {160, 120, V4L2_PIX_FMT_YUYV, V4L2_FIELD_NONE, + .bytesperline = 160 * 2, + .sizeimage = 160 * 120 * 2, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = 5}, + {176, 144, V4L2_PIX_FMT_YUYV, V4L2_FIELD_NONE, + .bytesperline = 176 * 2, + .sizeimage = 176 * 144 * 2, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = 4}, + {320, 240, V4L2_PIX_FMT_YUYV, V4L2_FIELD_NONE, + .bytesperline = 320 * 2, + .sizeimage = 320 * 240 * 2, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = 2}, + {352, 288, V4L2_PIX_FMT_YUYV, V4L2_FIELD_NONE, + .bytesperline = 352 * 2, + .sizeimage = 352 * 288 * 2, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = 1}, + {640, 480, V4L2_PIX_FMT_YUYV, V4L2_FIELD_NONE, + .bytesperline = 640 * 2, + .sizeimage = 640 * 480 * 2, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = 0}, +}; + +#define SPCA50X_OFFSET_DATA 10 + +#define SPCA50X_REG_USB 0x02 /* spca505 501 */ + +#define SPCA50X_USB_CTRL 0x00 /* spca505 */ +#define SPCA50X_CUSB_ENABLE 0x01 /* spca505 */ +#define SPCA50X_REG_GLOBAL 0x03 /* spca505 */ +#define SPCA50X_GMISC0_IDSEL 0x01 /* Global control device ID select spca505 */ +#define SPCA50X_GLOBAL_MISC0 0x00 /* Global control miscellaneous 0 spca505 */ + +#define SPCA50X_GLOBAL_MISC1 0x01 /* 505 */ +#define SPCA50X_GLOBAL_MISC3 0x03 /* 505 */ +#define SPCA50X_GMISC3_SAA7113RST 0x20 /* Not sure about this one spca505 */ + +/* + * Data to initialize a SPCA505. Common to the CCD and external modes + */ +static const __u16 spca505_init_data[][3] = { + /* line bmRequest,value,index */ + /* 1819 */ + {SPCA50X_REG_GLOBAL, SPCA50X_GMISC3_SAA7113RST, SPCA50X_GLOBAL_MISC3}, + /* Sensor reset */ + /* 1822 */ {SPCA50X_REG_GLOBAL, 0x00, SPCA50X_GLOBAL_MISC3}, + /* 1825 */ {SPCA50X_REG_GLOBAL, 0x00, SPCA50X_GLOBAL_MISC1}, + /* Block USB reset */ + /* 1828 */ {SPCA50X_REG_GLOBAL, SPCA50X_GMISC0_IDSEL, + SPCA50X_GLOBAL_MISC0}, + + /* 1831 */ {0x5, 0x01, 0x10}, + /* Maybe power down some stuff */ + /* 1834 */ {0x5, 0x0f, 0x11}, + + /* Setup internal CCD ? */ + /* 1837 */ {0x6, 0x10, 0x08}, + /* 1840 */ {0x6, 0x00, 0x09}, + /* 1843 */ {0x6, 0x00, 0x0a}, + /* 1846 */ {0x6, 0x00, 0x0b}, + /* 1849 */ {0x6, 0x10, 0x0c}, + /* 1852 */ {0x6, 0x00, 0x0d}, + /* 1855 */ {0x6, 0x00, 0x0e}, + /* 1858 */ {0x6, 0x00, 0x0f}, + /* 1861 */ {0x6, 0x10, 0x10}, + /* 1864 */ {0x6, 0x02, 0x11}, + /* 1867 */ {0x6, 0x00, 0x12}, + /* 1870 */ {0x6, 0x04, 0x13}, + /* 1873 */ {0x6, 0x02, 0x14}, + /* 1876 */ {0x6, 0x8a, 0x51}, + /* 1879 */ {0x6, 0x40, 0x52}, + /* 1882 */ {0x6, 0xb6, 0x53}, + /* 1885 */ {0x6, 0x3d, 0x54}, + {} +}; + +/* + * Data to initialize the camera using the internal CCD + */ +static const __u16 spca505_open_data_ccd[][3] = { + /* line bmRequest,value,index */ + /* Internal CCD data set */ + /* 1891 */ {0x3, 0x04, 0x01}, + /* This could be a reset */ + /* 1894 */ {0x3, 0x00, 0x01}, + + /* Setup compression and image registers. 0x6 and 0x7 seem to be + related to H&V hold, and are resolution mode specific */ + /* 1897 */ {0x4, 0x10, 0x01}, + /* DIFF(0x50), was (0x10) */ + /* 1900 */ {0x4, 0x00, 0x04}, + /* 1903 */ {0x4, 0x00, 0x05}, + /* 1906 */ {0x4, 0x20, 0x06}, + /* 1909 */ {0x4, 0x20, 0x07}, + + /* 1912 */ {0x8, 0x0a, 0x00}, + /* DIFF (0x4a), was (0xa) */ + + /* 1915 */ {0x5, 0x00, 0x10}, + /* 1918 */ {0x5, 0x00, 0x11}, + /* 1921 */ {0x5, 0x00, 0x00}, + /* DIFF not written */ + /* 1924 */ {0x5, 0x00, 0x01}, + /* DIFF not written */ + /* 1927 */ {0x5, 0x00, 0x02}, + /* DIFF not written */ + /* 1930 */ {0x5, 0x00, 0x03}, + /* DIFF not written */ + /* 1933 */ {0x5, 0x00, 0x04}, + /* DIFF not written */ + /* 1936 */ {0x5, 0x80, 0x05}, + /* DIFF not written */ + /* 1939 */ {0x5, 0xe0, 0x06}, + /* DIFF not written */ + /* 1942 */ {0x5, 0x20, 0x07}, + /* DIFF not written */ + /* 1945 */ {0x5, 0xa0, 0x08}, + /* DIFF not written */ + /* 1948 */ {0x5, 0x0, 0x12}, + /* DIFF not written */ + /* 1951 */ {0x5, 0x02, 0x0f}, + /* DIFF not written */ + /* 1954 */ {0x5, 0x10, 0x46}, + /* DIFF not written */ + /* 1957 */ {0x5, 0x8, 0x4a}, + /* DIFF not written */ + + /* 1960 */ {0x3, 0x08, 0x03}, + /* DIFF (0x3,0x28,0x3) */ + /* 1963 */ {0x3, 0x08, 0x01}, + /* 1966 */ {0x3, 0x0c, 0x03}, + /* DIFF not written */ + /* 1969 */ {0x3, 0x21, 0x00}, + /* DIFF (0x39) */ + +/* Extra block copied from init to hopefully ensure CCD is in a sane state */ + /* 1837 */ {0x6, 0x10, 0x08}, + /* 1840 */ {0x6, 0x00, 0x09}, + /* 1843 */ {0x6, 0x00, 0x0a}, + /* 1846 */ {0x6, 0x00, 0x0b}, + /* 1849 */ {0x6, 0x10, 0x0c}, + /* 1852 */ {0x6, 0x00, 0x0d}, + /* 1855 */ {0x6, 0x00, 0x0e}, + /* 1858 */ {0x6, 0x00, 0x0f}, + /* 1861 */ {0x6, 0x10, 0x10}, + /* 1864 */ {0x6, 0x02, 0x11}, + /* 1867 */ {0x6, 0x00, 0x12}, + /* 1870 */ {0x6, 0x04, 0x13}, + /* 1873 */ {0x6, 0x02, 0x14}, + /* 1876 */ {0x6, 0x8a, 0x51}, + /* 1879 */ {0x6, 0x40, 0x52}, + /* 1882 */ {0x6, 0xb6, 0x53}, + /* 1885 */ {0x6, 0x3d, 0x54}, + /* End of extra block */ + + /* 1972 */ {0x6, 0x3f, 0x1}, + /* Block skipped */ + /* 1975 */ {0x6, 0x10, 0x02}, + /* 1978 */ {0x6, 0x64, 0x07}, + /* 1981 */ {0x6, 0x10, 0x08}, + /* 1984 */ {0x6, 0x00, 0x09}, + /* 1987 */ {0x6, 0x00, 0x0a}, + /* 1990 */ {0x6, 0x00, 0x0b}, + /* 1993 */ {0x6, 0x10, 0x0c}, + /* 1996 */ {0x6, 0x00, 0x0d}, + /* 1999 */ {0x6, 0x00, 0x0e}, + /* 2002 */ {0x6, 0x00, 0x0f}, + /* 2005 */ {0x6, 0x10, 0x10}, + /* 2008 */ {0x6, 0x02, 0x11}, + /* 2011 */ {0x6, 0x00, 0x12}, + /* 2014 */ {0x6, 0x04, 0x13}, + /* 2017 */ {0x6, 0x02, 0x14}, + /* 2020 */ {0x6, 0x8a, 0x51}, + /* 2023 */ {0x6, 0x40, 0x52}, + /* 2026 */ {0x6, 0xb6, 0x53}, + /* 2029 */ {0x6, 0x3d, 0x54}, + /* 2032 */ {0x6, 0x60, 0x57}, + /* 2035 */ {0x6, 0x20, 0x58}, + /* 2038 */ {0x6, 0x15, 0x59}, + /* 2041 */ {0x6, 0x05, 0x5a}, + + /* 2044 */ {0x5, 0x01, 0xc0}, + /* 2047 */ {0x5, 0x10, 0xcb}, + /* 2050 */ {0x5, 0x80, 0xc1}, + /* */ + /* 2053 */ {0x5, 0x0, 0xc2}, + /* 4 was 0 */ + /* 2056 */ {0x5, 0x00, 0xca}, + /* 2059 */ {0x5, 0x80, 0xc1}, + /* */ + /* 2062 */ {0x5, 0x04, 0xc2}, + /* 2065 */ {0x5, 0x00, 0xca}, + /* 2068 */ {0x5, 0x0, 0xc1}, + /* */ + /* 2071 */ {0x5, 0x00, 0xc2}, + /* 2074 */ {0x5, 0x00, 0xca}, + /* 2077 */ {0x5, 0x40, 0xc1}, + /* */ + /* 2080 */ {0x5, 0x17, 0xc2}, + /* 2083 */ {0x5, 0x00, 0xca}, + /* 2086 */ {0x5, 0x80, 0xc1}, + /* */ + /* 2089 */ {0x5, 0x06, 0xc2}, + /* 2092 */ {0x5, 0x00, 0xca}, + /* 2095 */ {0x5, 0x80, 0xc1}, + /* */ + /* 2098 */ {0x5, 0x04, 0xc2}, + /* 2101 */ {0x5, 0x00, 0xca}, + + /* 2104 */ {0x3, 0x4c, 0x3}, + /* 2107 */ {0x3, 0x18, 0x1}, + + /* 2110 */ {0x6, 0x70, 0x51}, + /* 2113 */ {0x6, 0xbe, 0x53}, + /* 2116 */ {0x6, 0x71, 0x57}, + /* 2119 */ {0x6, 0x20, 0x58}, + /* 2122 */ {0x6, 0x05, 0x59}, + /* 2125 */ {0x6, 0x15, 0x5a}, + + /* 2128 */ {0x4, 0x00, 0x08}, + /* Compress = OFF (0x1 to turn on) */ + /* 2131 */ {0x4, 0x12, 0x09}, + /* 2134 */ {0x4, 0x21, 0x0a}, + /* 2137 */ {0x4, 0x10, 0x0b}, + /* 2140 */ {0x4, 0x21, 0x0c}, + /* 2143 */ {0x4, 0x05, 0x00}, + /* was 5 (Image Type ? ) */ + /* 2146 */ {0x4, 0x00, 0x01}, + + /* 2149 */ {0x6, 0x3f, 0x01}, + + /* 2152 */ {0x4, 0x00, 0x04}, + /* 2155 */ {0x4, 0x00, 0x05}, + /* 2158 */ {0x4, 0x40, 0x06}, + /* 2161 */ {0x4, 0x40, 0x07}, + + /* 2164 */ {0x6, 0x1c, 0x17}, + /* 2167 */ {0x6, 0xe2, 0x19}, + /* 2170 */ {0x6, 0x1c, 0x1b}, + /* 2173 */ {0x6, 0xe2, 0x1d}, + /* 2176 */ {0x6, 0xaa, 0x1f}, + /* 2179 */ {0x6, 0x70, 0x20}, + + /* 2182 */ {0x5, 0x01, 0x10}, + /* 2185 */ {0x5, 0x00, 0x11}, + /* 2188 */ {0x5, 0x01, 0x00}, + /* 2191 */ {0x5, 0x05, 0x01}, + /* 2194 */ {0x5, 0x00, 0xc1}, + /* */ + /* 2197 */ {0x5, 0x00, 0xc2}, + /* 2200 */ {0x5, 0x00, 0xca}, + + /* 2203 */ {0x6, 0x70, 0x51}, + /* 2206 */ {0x6, 0xbe, 0x53}, + {} +}; + +/* + Made by Tomasz Zablocki (skalamandra@poczta.onet.pl) + * SPCA505b chip based cameras initialization data + * + */ +/* jfm */ +#define initial_brightness 0x7f /* 0x0(white)-0xff(black) */ +/* #define initial_brightness 0x0 //0x0(white)-0xff(black) */ +/* + * Data to initialize a SPCA505. Common to the CCD and external modes + */ +static const __u16 spca505b_init_data[][3] = { +/* start */ + {0x02, 0x00, 0x00}, /* init */ + {0x02, 0x00, 0x01}, + {0x02, 0x00, 0x02}, + {0x02, 0x00, 0x03}, + {0x02, 0x00, 0x04}, + {0x02, 0x00, 0x05}, + {0x02, 0x00, 0x06}, + {0x02, 0x00, 0x07}, + {0x02, 0x00, 0x08}, + {0x02, 0x00, 0x09}, + {0x03, 0x00, 0x00}, + {0x03, 0x00, 0x01}, + {0x03, 0x00, 0x02}, + {0x03, 0x00, 0x03}, + {0x03, 0x00, 0x04}, + {0x03, 0x00, 0x05}, + {0x03, 0x00, 0x06}, + {0x04, 0x00, 0x00}, + {0x04, 0x00, 0x02}, + {0x04, 0x00, 0x04}, + {0x04, 0x00, 0x05}, + {0x04, 0x00, 0x06}, + {0x04, 0x00, 0x07}, + {0x04, 0x00, 0x08}, + {0x04, 0x00, 0x09}, + {0x04, 0x00, 0x0a}, + {0x04, 0x00, 0x0b}, + {0x04, 0x00, 0x0c}, + {0x07, 0x00, 0x00}, + {0x07, 0x00, 0x03}, + {0x08, 0x00, 0x00}, + {0x08, 0x00, 0x01}, + {0x08, 0x00, 0x02}, + {0x00, 0x01, 0x00}, + {0x00, 0x01, 0x01}, + {0x00, 0x01, 0x34}, + {0x00, 0x01, 0x35}, + {0x06, 0x18, 0x08}, + {0x06, 0xfc, 0x09}, + {0x06, 0xfc, 0x0a}, + {0x06, 0xfc, 0x0b}, + {0x06, 0x18, 0x0c}, + {0x06, 0xfc, 0x0d}, + {0x06, 0xfc, 0x0e}, + {0x06, 0xfc, 0x0f}, + {0x06, 0x18, 0x10}, + {0x06, 0xfe, 0x12}, + {0x06, 0x00, 0x11}, + {0x06, 0x00, 0x14}, + {0x06, 0x00, 0x13}, + {0x06, 0x28, 0x51}, + {0x06, 0xff, 0x53}, + {0x02, 0x00, 0x08}, + + {0x03, 0x00, 0x03}, + {0x03, 0x10, 0x03}, + {} +}; + +/* + * Data to initialize the camera using the internal CCD + */ +static const __u16 spca505b_open_data_ccd[][3] = { + +/* {0x02,0x00,0x00}, */ + {0x03, 0x04, 0x01}, /* rst */ + {0x03, 0x00, 0x01}, + {0x03, 0x00, 0x00}, + {0x03, 0x21, 0x00}, + {0x03, 0x00, 0x04}, + {0x03, 0x00, 0x03}, + {0x03, 0x18, 0x03}, + {0x03, 0x08, 0x01}, + {0x03, 0x1c, 0x03}, + {0x03, 0x5c, 0x03}, + {0x03, 0x5c, 0x03}, + {0x03, 0x18, 0x01}, + +/* same as 505 */ + {0x04, 0x10, 0x01}, + {0x04, 0x00, 0x04}, + {0x04, 0x00, 0x05}, + {0x04, 0x20, 0x06}, + {0x04, 0x20, 0x07}, + + {0x08, 0x0a, 0x00}, + + {0x05, 0x00, 0x10}, + {0x05, 0x00, 0x11}, + {0x05, 0x00, 0x12}, + {0x05, 0x6f, 0x00}, + {0x05, initial_brightness >> 6, 0x00}, + {0x05, initial_brightness << 2, 0x01}, + {0x05, 0x00, 0x02}, + {0x05, 0x01, 0x03}, + {0x05, 0x00, 0x04}, + {0x05, 0x03, 0x05}, + {0x05, 0xe0, 0x06}, + {0x05, 0x20, 0x07}, + {0x05, 0xa0, 0x08}, + {0x05, 0x00, 0x12}, + {0x05, 0x02, 0x0f}, + {0x05, 128, 0x14}, /* max exposure off (0=on) */ + {0x05, 0x01, 0xb0}, + {0x05, 0x01, 0xbf}, + {0x03, 0x02, 0x06}, + {0x05, 0x10, 0x46}, + {0x05, 0x08, 0x4a}, + + {0x06, 0x00, 0x01}, + {0x06, 0x10, 0x02}, + {0x06, 0x64, 0x07}, + {0x06, 0x18, 0x08}, + {0x06, 0xfc, 0x09}, + {0x06, 0xfc, 0x0a}, + {0x06, 0xfc, 0x0b}, + {0x04, 0x00, 0x01}, + {0x06, 0x18, 0x0c}, + {0x06, 0xfc, 0x0d}, + {0x06, 0xfc, 0x0e}, + {0x06, 0xfc, 0x0f}, + {0x06, 0x11, 0x10}, /* contrast */ + {0x06, 0x00, 0x11}, + {0x06, 0xfe, 0x12}, + {0x06, 0x00, 0x13}, + {0x06, 0x00, 0x14}, + {0x06, 0x9d, 0x51}, + {0x06, 0x40, 0x52}, + {0x06, 0x7c, 0x53}, + {0x06, 0x40, 0x54}, + {0x06, 0x02, 0x57}, + {0x06, 0x03, 0x58}, + {0x06, 0x15, 0x59}, + {0x06, 0x05, 0x5a}, + {0x06, 0x03, 0x56}, + {0x06, 0x02, 0x3f}, + {0x06, 0x00, 0x40}, + {0x06, 0x39, 0x41}, + {0x06, 0x69, 0x42}, + {0x06, 0x87, 0x43}, + {0x06, 0x9e, 0x44}, + {0x06, 0xb1, 0x45}, + {0x06, 0xbf, 0x46}, + {0x06, 0xcc, 0x47}, + {0x06, 0xd5, 0x48}, + {0x06, 0xdd, 0x49}, + {0x06, 0xe3, 0x4a}, + {0x06, 0xe8, 0x4b}, + {0x06, 0xed, 0x4c}, + {0x06, 0xf2, 0x4d}, + {0x06, 0xf7, 0x4e}, + {0x06, 0xfc, 0x4f}, + {0x06, 0xff, 0x50}, + + {0x05, 0x01, 0xc0}, + {0x05, 0x10, 0xcb}, + {0x05, 0x40, 0xc1}, + {0x05, 0x04, 0xc2}, + {0x05, 0x00, 0xca}, + {0x05, 0x40, 0xc1}, + {0x05, 0x09, 0xc2}, + {0x05, 0x00, 0xca}, + {0x05, 0xc0, 0xc1}, + {0x05, 0x09, 0xc2}, + {0x05, 0x00, 0xca}, + {0x05, 0x40, 0xc1}, + {0x05, 0x59, 0xc2}, + {0x05, 0x00, 0xca}, + {0x04, 0x00, 0x01}, + {0x05, 0x80, 0xc1}, + {0x05, 0xec, 0xc2}, + {0x05, 0x0, 0xca}, + + {0x06, 0x02, 0x57}, + {0x06, 0x01, 0x58}, + {0x06, 0x15, 0x59}, + {0x06, 0x0a, 0x5a}, + {0x06, 0x01, 0x57}, + {0x06, 0x8a, 0x03}, + {0x06, 0x0a, 0x6c}, + {0x06, 0x30, 0x01}, + {0x06, 0x20, 0x02}, + {0x06, 0x00, 0x03}, + + {0x05, 0x8c, 0x25}, + + {0x06, 0x4d, 0x51}, /* maybe saturation (4d) */ + {0x06, 0x84, 0x53}, /* making green (84) */ + {0x06, 0x00, 0x57}, /* sharpness (1) */ + {0x06, 0x18, 0x08}, + {0x06, 0xfc, 0x09}, + {0x06, 0xfc, 0x0a}, + {0x06, 0xfc, 0x0b}, + {0x06, 0x18, 0x0c}, /* maybe hue (18) */ + {0x06, 0xfc, 0x0d}, + {0x06, 0xfc, 0x0e}, + {0x06, 0xfc, 0x0f}, + {0x06, 0x18, 0x10}, /* maybe contrast (18) */ + + {0x05, 0x01, 0x02}, + + {0x04, 0x00, 0x08}, /* compression */ + {0x04, 0x12, 0x09}, + {0x04, 0x21, 0x0a}, + {0x04, 0x10, 0x0b}, + {0x04, 0x21, 0x0c}, + {0x04, 0x1d, 0x00}, /* imagetype (1d) */ + {0x04, 0x41, 0x01}, /* hardware snapcontrol */ + + {0x04, 0x00, 0x04}, + {0x04, 0x00, 0x05}, + {0x04, 0x10, 0x06}, + {0x04, 0x10, 0x07}, + {0x04, 0x40, 0x06}, + {0x04, 0x40, 0x07}, + {0x04, 0x00, 0x04}, + {0x04, 0x00, 0x05}, + + {0x06, 0x1c, 0x17}, + {0x06, 0xe2, 0x19}, + {0x06, 0x1c, 0x1b}, + {0x06, 0xe2, 0x1d}, + {0x06, 0x5f, 0x1f}, + {0x06, 0x32, 0x20}, + + {0x05, initial_brightness >> 6, 0x00}, + {0x05, initial_brightness << 2, 0x01}, + {0x05, 0x06, 0xc1}, + {0x05, 0x58, 0xc2}, + {0x05, 0x0, 0xca}, + {0x05, 0x0, 0x11}, + {} +}; + +static int reg_write(struct usb_device *dev, + __u16 reg, __u16 index, __u16 value) +{ + int ret; + + ret = usb_control_msg(dev, + usb_sndctrlpipe(dev, 0), + reg, + USB_TYPE_VENDOR | USB_RECIP_DEVICE, + value, index, NULL, 0, 500); + PDEBUG(D_PACK, "reg write: 0x%02x,0x%02x:0x%02x, 0x%x", + reg, index, value, ret); + if (ret < 0) + PDEBUG(D_ERR, "reg write: error %d", ret); + return ret; +} + +/* returns: negative is error, pos or zero is data */ +static int reg_read(struct gspca_dev *gspca_dev, + __u16 reg, /* bRequest */ + __u16 index, /* wIndex */ + __u16 length) /* wLength (1 or 2 only) */ +{ + int ret; + + gspca_dev->usb_buf[1] = 0; + ret = usb_control_msg(gspca_dev->dev, + usb_rcvctrlpipe(gspca_dev->dev, 0), + reg, + USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + (__u16) 0, /* value */ + (__u16) index, + gspca_dev->usb_buf, length, + 500); /* timeout */ + if (ret < 0) { + PDEBUG(D_ERR, "reg_read err %d", ret); + return -1; + } + return (gspca_dev->usb_buf[1] << 8) + gspca_dev->usb_buf[0]; +} + +static int write_vector(struct gspca_dev *gspca_dev, + const __u16 data[][3]) +{ + struct usb_device *dev = gspca_dev->dev; + int ret, i = 0; + + while (data[i][0] != 0 || data[i][1] != 0 || data[i][2] != 0) { + ret = reg_write(dev, data[i][0], data[i][2], data[i][1]); + if (ret < 0) { + PDEBUG(D_ERR, + "Register write failed for 0x%x,0x%x,0x%x", + data[i][0], data[i][1], data[i][2]); + return ret; + } + i++; + } + return 0; +} + +/* this function is called at probe time */ +static int sd_config(struct gspca_dev *gspca_dev, + const struct usb_device_id *id) +{ + struct sd *sd = (struct sd *) gspca_dev; + struct cam *cam; + __u16 vendor; + __u16 product; + + vendor = id->idVendor; + product = id->idProduct; + switch (vendor) { + case 0x041e: /* Creative cameras */ +/* switch (product) { */ +/* case 0x401d: * here505b */ + sd->subtype = Nxultra; +/* break; */ +/* } */ + break; + case 0x0733: /* Rebadged ViewQuest (Intel) and ViewQuest cameras */ +/* switch (product) { */ +/* case 0x0430: */ +/* fixme: may be UsbGrabberPV321 BRIDGE_SPCA506 SENSOR_SAA7113 */ + sd->subtype = IntelPCCameraPro; +/* break; */ +/* } */ + break; + } + + cam = &gspca_dev->cam; + cam->dev_name = (char *) id->driver_info; + cam->epaddr = 0x01; + cam->cam_mode = vga_mode; + if (sd->subtype != IntelPCCameraPro) + cam->nmodes = sizeof vga_mode / sizeof vga_mode[0]; + else /* no 640x480 for IntelPCCameraPro */ + cam->nmodes = sizeof vga_mode / sizeof vga_mode[0] - 1; + sd->brightness = sd_ctrls[SD_BRIGHTNESS].qctrl.default_value; + + if (sd->subtype == Nxultra) { + if (write_vector(gspca_dev, spca505b_init_data)) + return -EIO; + } else { + if (write_vector(gspca_dev, spca505_init_data)) + return -EIO; + } + return 0; +} + +/* this function is called at open time */ +static int sd_open(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + int ret; + + PDEBUG(D_STREAM, "Initializing SPCA505"); + if (sd->subtype == Nxultra) + write_vector(gspca_dev, spca505b_open_data_ccd); + else + write_vector(gspca_dev, spca505_open_data_ccd); + ret = reg_read(gspca_dev, 6, 0x16, 2); + + if (ret < 0) { + PDEBUG(D_ERR|D_STREAM, + "register read failed for after vector read err = %d", + ret); + return -EIO; + } + PDEBUG(D_STREAM, + "After vector read returns : 0x%x should be 0x0101", + ret & 0xffff); + + ret = reg_write(gspca_dev->dev, 6, 0x16, 0x0a); + if (ret < 0) { + PDEBUG(D_ERR, "register write failed for (6,0xa,0x16) err=%d", + ret); + return -EIO; + } + reg_write(gspca_dev->dev, 5, 0xc2, 18); + return 0; +} + +static void sd_start(struct gspca_dev *gspca_dev) +{ + struct usb_device *dev = gspca_dev->dev; + int ret; + + /* necessary because without it we can see stream + * only once after loading module */ + /* stopping usb registers Tomasz change */ + reg_write(dev, 0x02, 0x0, 0x0); + switch (gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv) { + case 0: + reg_write(dev, 0x04, 0x00, 0x00); + reg_write(dev, 0x04, 0x06, 0x10); + reg_write(dev, 0x04, 0x07, 0x10); + break; + case 1: + reg_write(dev, 0x04, 0x00, 0x01); + reg_write(dev, 0x04, 0x06, 0x1a); + reg_write(dev, 0x04, 0x07, 0x1a); + break; + case 2: + reg_write(dev, 0x04, 0x00, 0x02); + reg_write(dev, 0x04, 0x06, 0x1c); + reg_write(dev, 0x04, 0x07, 0x1d); + break; + case 4: + reg_write(dev, 0x04, 0x00, 0x04); + reg_write(dev, 0x04, 0x06, 0x34); + reg_write(dev, 0x04, 0x07, 0x34); + break; + default: +/* case 5: */ + reg_write(dev, 0x04, 0x00, 0x05); + reg_write(dev, 0x04, 0x06, 0x40); + reg_write(dev, 0x04, 0x07, 0x40); + break; + } +/* Enable ISO packet machine - should we do this here or in ISOC init ? */ + ret = reg_write(dev, SPCA50X_REG_USB, + SPCA50X_USB_CTRL, + SPCA50X_CUSB_ENABLE); + +/* reg_write(dev, 0x5, 0x0, 0x0); */ +/* reg_write(dev, 0x5, 0x0, 0x1); */ +/* reg_write(dev, 0x5, 0x11, 0x2); */ +} + +static void sd_stopN(struct gspca_dev *gspca_dev) +{ + /* Disable ISO packet machine */ + reg_write(gspca_dev->dev, 0x02, 0x00, 0x00); +} + +static void sd_stop0(struct gspca_dev *gspca_dev) +{ +} + +/* this function is called at close time */ +static void sd_close(struct gspca_dev *gspca_dev) +{ + /* This maybe reset or power control */ + reg_write(gspca_dev->dev, 0x03, 0x03, 0x20); + reg_write(gspca_dev->dev, 0x03, 0x01, 0x0); + reg_write(gspca_dev->dev, 0x03, 0x00, 0x1); + reg_write(gspca_dev->dev, 0x05, 0x10, 0x1); + reg_write(gspca_dev->dev, 0x05, 0x11, 0xf); +} + +/* convert YYUV per line to YUYV (YUV 4:2:2) */ +static void yyuv_decode(unsigned char *out, + unsigned char *in, + int width, + int height) +{ + unsigned char *Ui, *Vi, *yi, *yi1; + unsigned char *out1; + int i, j; + + yi = in; + for (i = height / 2; --i >= 0; ) { + out1 = out + width * 2; /* next line */ + yi1 = yi + width; + Ui = yi1 + width; + Vi = Ui + width / 2; + for (j = width / 2; --j >= 0; ) { + *out++ = 128 + *yi++; + *out++ = 128 + *Ui; + *out++ = 128 + *yi++; + *out++ = 128 + *Vi; + + *out1++ = 128 + *yi1++; + *out1++ = 128 + *Ui++; + *out1++ = 128 + *yi1++; + *out1++ = 128 + *Vi++; + } + yi += width * 2; + out = out1; + } +} + +static void sd_pkt_scan(struct gspca_dev *gspca_dev, + struct gspca_frame *frame, /* target */ + __u8 *data, /* isoc packet */ + int len) /* iso packet length */ +{ + struct sd *sd = (struct sd *) gspca_dev; + + switch (data[0]) { + case 0: /* start of frame */ + if (gspca_dev->last_packet_type == FIRST_PACKET) { + yyuv_decode(sd->tmpbuf2, sd->tmpbuf, + gspca_dev->width, + gspca_dev->height); + frame = gspca_frame_add(gspca_dev, + LAST_PACKET, + frame, + sd->tmpbuf2, + gspca_dev->width + * gspca_dev->height + * 2); + } + gspca_frame_add(gspca_dev, FIRST_PACKET, frame, + data, 0); + data += SPCA50X_OFFSET_DATA; + len -= SPCA50X_OFFSET_DATA; + if (len > 0) + memcpy(sd->tmpbuf, data, len); + else + len = 0; + sd->buflen = len; + return; + case 0xff: /* drop */ +/* gspca_dev->last_packet_type = DISCARD_PACKET; */ + return; + } + data += 1; + len -= 1; + memcpy(&sd->tmpbuf[sd->buflen], data, len); + sd->buflen += len; +} + +static void setbrightness(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + + __u8 brightness = sd->brightness; + reg_write(gspca_dev->dev, 5, 0x00, (255 - brightness) >> 6); + reg_write(gspca_dev->dev, 5, 0x01, (255 - brightness) << 2); + +} +static void getbrightness(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->brightness = 255 + - ((reg_read(gspca_dev, 5, 0x01, 1) >> 2) + + (reg_read(gspca_dev, 5, 0x0, 1) << 6)); +} + +static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->brightness = val; + if (gspca_dev->streaming) + setbrightness(gspca_dev); + return 0; +} + +static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + getbrightness(gspca_dev); + *val = sd->brightness; + return 0; +} + +/* sub-driver description */ +static const struct sd_desc sd_desc = { + .name = MODULE_NAME, + .ctrls = sd_ctrls, + .nctrls = ARRAY_SIZE(sd_ctrls), + .config = sd_config, + .open = sd_open, + .start = sd_start, + .stopN = sd_stopN, + .stop0 = sd_stop0, + .close = sd_close, + .pkt_scan = sd_pkt_scan, +}; + +/* -- module initialisation -- */ +#define DVNM(name) .driver_info = (kernel_ulong_t) name +static const __devinitdata struct usb_device_id device_table[] = { + {USB_DEVICE(0x041e, 0x401d), DVNM("Creative Webcam NX ULTRA")}, + {USB_DEVICE(0x0733, 0x0430), DVNM("Intel PC Camera Pro")}, + {} +}; +MODULE_DEVICE_TABLE(usb, device_table); + +/* -- device connect -- */ +static int sd_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd), + THIS_MODULE); +} + +static struct usb_driver sd_driver = { + .name = MODULE_NAME, + .id_table = device_table, + .probe = sd_probe, + .disconnect = gspca_disconnect, +}; + +/* -- module insert / remove -- */ +static int __init sd_mod_init(void) +{ + if (usb_register(&sd_driver) < 0) + return -1; + PDEBUG(D_PROBE, "v%s registered", version); + return 0; +} +static void __exit sd_mod_exit(void) +{ + usb_deregister(&sd_driver); + PDEBUG(D_PROBE, "deregistered"); +} + +module_init(sd_mod_init); +module_exit(sd_mod_exit); diff --git a/drivers/media/video/gspca/spca506.c b/drivers/media/video/gspca/spca506.c new file mode 100644 index 000000000000..143203c1fd9f --- /dev/null +++ b/drivers/media/video/gspca/spca506.c @@ -0,0 +1,847 @@ +/* + * SPCA506 chip based cameras function + * M Xhaard 15/04/2004 based on different work Mark Taylor and others + * and my own snoopy file on a pv-321c donate by a german compagny + * "Firma Frank Gmbh" from Saarbruecken + * + * V4L2 by Jean-Francois Moine <http://moinejf.free.fr> + * + * 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 + * 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 + */ + +#define MODULE_NAME "spca506" + +#include "gspca.h" + +#define DRIVER_VERSION_NUMBER KERNEL_VERSION(2, 1, 7) +static const char version[] = "2.1.7"; + +MODULE_AUTHOR("Michel Xhaard <mxhaard@users.sourceforge.net>"); +MODULE_DESCRIPTION("GSPCA/SPCA506 USB Camera Driver"); +MODULE_LICENSE("GPL"); + +/* specific webcam descriptor */ +struct sd { + struct gspca_dev gspca_dev; /* !! must be the first item */ + + int buflen; + __u8 tmpbuf[640 * 480 * 3]; /* YYUV per line */ + __u8 tmpbuf2[640 * 480 * 2]; /* YUYV */ + + unsigned char brightness; + unsigned char contrast; + unsigned char colors; + unsigned char hue; + char norme; + char channel; +}; + +/* V4L2 controls supported by the driver */ +static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val); +static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val); +static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val); +static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val); +static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val); +static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val); +static int sd_sethue(struct gspca_dev *gspca_dev, __s32 val); +static int sd_gethue(struct gspca_dev *gspca_dev, __s32 *val); + +static struct ctrl sd_ctrls[] = { +#define SD_BRIGHTNESS 0 + { + { + .id = V4L2_CID_BRIGHTNESS, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Brightness", + .minimum = 0, + .maximum = 0xff, + .step = 1, + .default_value = 0x80, + }, + .set = sd_setbrightness, + .get = sd_getbrightness, + }, +#define SD_CONTRAST 1 + { + { + .id = V4L2_CID_CONTRAST, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Contrast", + .minimum = 0, + .maximum = 0xff, + .step = 1, + .default_value = 0x47, + }, + .set = sd_setcontrast, + .get = sd_getcontrast, + }, +#define SD_COLOR 2 + { + { + .id = V4L2_CID_SATURATION, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Saturation", + .minimum = 0, + .maximum = 0xff, + .step = 1, + .default_value = 0x40, + }, + .set = sd_setcolors, + .get = sd_getcolors, + }, +#define SD_HUE 3 + { + { + .id = V4L2_CID_HUE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Hue", + .minimum = 0, + .maximum = 0xff, + .step = 1, + .default_value = 0, + }, + .set = sd_sethue, + .get = sd_gethue, + }, +}; + +static struct v4l2_pix_format vga_mode[] = { + {160, 120, V4L2_PIX_FMT_YUYV, V4L2_FIELD_NONE, + .bytesperline = 160 * 2, + .sizeimage = 160 * 120 * 2, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = 5}, + {176, 144, V4L2_PIX_FMT_YUYV, V4L2_FIELD_NONE, + .bytesperline = 176 * 2, + .sizeimage = 176 * 144 * 2, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = 4}, + {320, 240, V4L2_PIX_FMT_YUYV, V4L2_FIELD_NONE, + .bytesperline = 320 * 2, + .sizeimage = 320 * 240 * 2, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = 2}, + {352, 288, V4L2_PIX_FMT_YUYV, V4L2_FIELD_NONE, + .bytesperline = 352 * 2, + .sizeimage = 352 * 288 * 2, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = 1}, + {640, 480, V4L2_PIX_FMT_YUYV, V4L2_FIELD_NONE, + .bytesperline = 640 * 2, + .sizeimage = 640 * 480 * 2, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = 0}, +}; + +#define SPCA50X_OFFSET_DATA 10 + +#define SAA7113_bright 0x0a /* defaults 0x80 */ +#define SAA7113_contrast 0x0b /* defaults 0x47 */ +#define SAA7113_saturation 0x0c /* defaults 0x40 */ +#define SAA7113_hue 0x0d /* defaults 0x00 */ +#define SAA7113_I2C_BASE_WRITE 0x4a + +/* read 'len' bytes to gspca_dev->usb_buf */ +static void reg_r(struct gspca_dev *gspca_dev, + __u16 req, + __u16 index, + __u16 length) +{ + usb_control_msg(gspca_dev->dev, + usb_rcvctrlpipe(gspca_dev->dev, 0), + req, + USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + 0, /* value */ + index, gspca_dev->usb_buf, length, + 500); +} + +static void reg_w(struct usb_device *dev, + __u16 req, + __u16 value, + __u16 index) +{ + usb_control_msg(dev, + usb_sndctrlpipe(dev, 0), + req, + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + value, index, + NULL, 0, 500); +} + +static void spca506_Initi2c(struct gspca_dev *gspca_dev) +{ + reg_w(gspca_dev->dev, 0x07, SAA7113_I2C_BASE_WRITE, 0x0004); +} + +static void spca506_WriteI2c(struct gspca_dev *gspca_dev, __u16 valeur, + __u16 reg) +{ + int retry = 60; + + reg_w(gspca_dev->dev, 0x07, reg, 0x0001); + reg_w(gspca_dev->dev, 0x07, valeur, 0x0000); + while (retry--) { + reg_r(gspca_dev, 0x07, 0x0003, 2); + if ((gspca_dev->usb_buf[0] | gspca_dev->usb_buf[1]) == 0x00) + break; + } +} + +static int spca506_ReadI2c(struct gspca_dev *gspca_dev, __u16 reg) +{ + int retry = 60; + + reg_w(gspca_dev->dev, 0x07, SAA7113_I2C_BASE_WRITE, 0x0004); + reg_w(gspca_dev->dev, 0x07, reg, 0x0001); + reg_w(gspca_dev->dev, 0x07, 0x01, 0x0002); + while (--retry) { + reg_r(gspca_dev, 0x07, 0x0003, 2); + if ((gspca_dev->usb_buf[0] | gspca_dev->usb_buf[1]) == 0x00) + break; + } + if (retry == 0) + return -1; + reg_r(gspca_dev, 0x07, 0x0000, 1); + return gspca_dev->usb_buf[0]; +} + +static void spca506_SetNormeInput(struct gspca_dev *gspca_dev, + __u16 norme, + __u16 channel) +{ + struct sd *sd = (struct sd *) gspca_dev; +/* fixme: check if channel == 0..3 and 6..9 (8 values) */ + __u8 setbit0 = 0x00; + __u8 setbit1 = 0x00; + __u8 videomask = 0x00; + + PDEBUG(D_STREAM, "** Open Set Norme **"); + spca506_Initi2c(gspca_dev); + /* NTSC bit0 -> 1(525 l) PAL SECAM bit0 -> 0 (625 l) */ + /* Composite channel bit1 -> 1 S-video bit 1 -> 0 */ + /* and exclude SAA7113 reserved channel set default 0 otherwise */ + if (norme & V4L2_STD_NTSC) + setbit0 = 0x01; + if (channel == 4 || channel == 5 || channel > 9) + channel = 0; + if (channel < 4) + setbit1 = 0x02; + videomask = (0x48 | setbit0 | setbit1); + reg_w(gspca_dev->dev, 0x08, videomask, 0x0000); + spca506_WriteI2c(gspca_dev, (0xc0 | (channel & 0x0F)), 0x02); + + if (norme & V4L2_STD_NTSC) + spca506_WriteI2c(gspca_dev, 0x33, 0x0e); + /* Chrominance Control NTSC N */ + else if (norme & V4L2_STD_SECAM) + spca506_WriteI2c(gspca_dev, 0x53, 0x0e); + /* Chrominance Control SECAM */ + else + spca506_WriteI2c(gspca_dev, 0x03, 0x0e); + /* Chrominance Control PAL BGHIV */ + + sd->norme = norme; + sd->channel = channel; + PDEBUG(D_STREAM, "Set Video Byte to 0x%2x", videomask); + PDEBUG(D_STREAM, "Set Norme: %08x Channel %d", norme, channel); +} + +static void spca506_GetNormeInput(struct gspca_dev *gspca_dev, + __u16 *norme, __u16 *channel) +{ + struct sd *sd = (struct sd *) gspca_dev; + + /* Read the register is not so good value change so + we use your own copy in spca50x struct */ + *norme = sd->norme; + *channel = sd->channel; + PDEBUG(D_STREAM, "Get Norme: %d Channel %d", *norme, *channel); +} + +static void spca506_Setsize(struct gspca_dev *gspca_dev, __u16 code, + __u16 xmult, __u16 ymult) +{ + struct usb_device *dev = gspca_dev->dev; + + PDEBUG(D_STREAM, "** SetSize **"); + reg_w(dev, 0x04, (0x18 | (code & 0x07)), 0x0000); + /* Soft snap 0x40 Hard 0x41 */ + reg_w(dev, 0x04, 0x41, 0x0001); + reg_w(dev, 0x04, 0x00, 0x0002); + /* reserved */ + reg_w(dev, 0x04, 0x00, 0x0003); + + /* reserved */ + reg_w(dev, 0x04, 0x00, 0x0004); + /* reserved */ + reg_w(dev, 0x04, 0x01, 0x0005); + /* reserced */ + reg_w(dev, 0x04, xmult, 0x0006); + /* reserved */ + reg_w(dev, 0x04, ymult, 0x0007); + /* compression 1 */ + reg_w(dev, 0x04, 0x00, 0x0008); + /* T=64 -> 2 */ + reg_w(dev, 0x04, 0x00, 0x0009); + /* threshold2D */ + reg_w(dev, 0x04, 0x21, 0x000a); + /* quantization */ + reg_w(dev, 0x04, 0x00, 0x000b); +} + +/* this function is called at probe time */ +static int sd_config(struct gspca_dev *gspca_dev, + const struct usb_device_id *id) +{ + struct sd *sd = (struct sd *) gspca_dev; + struct cam *cam; + + cam = &gspca_dev->cam; + cam->dev_name = (char *) id->driver_info; + cam->epaddr = 0x01; + cam->cam_mode = vga_mode; + cam->nmodes = sizeof vga_mode / sizeof vga_mode[0]; + sd->brightness = sd_ctrls[SD_BRIGHTNESS].qctrl.default_value; + sd->contrast = sd_ctrls[SD_CONTRAST].qctrl.default_value; + sd->colors = sd_ctrls[SD_COLOR].qctrl.default_value; + sd->hue = sd_ctrls[SD_HUE].qctrl.default_value; + return 0; +} + +/* this function is called at open time */ +static int sd_open(struct gspca_dev *gspca_dev) +{ + struct usb_device *dev = gspca_dev->dev; + + reg_w(dev, 0x03, 0x00, 0x0004); + reg_w(dev, 0x03, 0xFF, 0x0003); + reg_w(dev, 0x03, 0x00, 0x0000); + reg_w(dev, 0x03, 0x1c, 0x0001); + reg_w(dev, 0x03, 0x18, 0x0001); + /* Init on PAL and composite input0 */ + spca506_SetNormeInput(gspca_dev, 0, 0); + reg_w(dev, 0x03, 0x1c, 0x0001); + reg_w(dev, 0x03, 0x18, 0x0001); + reg_w(dev, 0x05, 0x00, 0x0000); + reg_w(dev, 0x05, 0xef, 0x0001); + reg_w(dev, 0x05, 0x00, 0x00c1); + reg_w(dev, 0x05, 0x00, 0x00c2); + reg_w(dev, 0x06, 0x18, 0x0002); + reg_w(dev, 0x06, 0xf5, 0x0011); + reg_w(dev, 0x06, 0x02, 0x0012); + reg_w(dev, 0x06, 0xfb, 0x0013); + reg_w(dev, 0x06, 0x00, 0x0014); + reg_w(dev, 0x06, 0xa4, 0x0051); + reg_w(dev, 0x06, 0x40, 0x0052); + reg_w(dev, 0x06, 0x71, 0x0053); + reg_w(dev, 0x06, 0x40, 0x0054); + /************************************************/ + reg_w(dev, 0x03, 0x00, 0x0004); + reg_w(dev, 0x03, 0x00, 0x0003); + reg_w(dev, 0x03, 0x00, 0x0004); + reg_w(dev, 0x03, 0xFF, 0x0003); + reg_w(dev, 0x02, 0x00, 0x0000); + reg_w(dev, 0x03, 0x60, 0x0000); + reg_w(dev, 0x03, 0x18, 0x0001); + /* for a better reading mx :) */ + /*sdca506_WriteI2c(value,register) */ + spca506_Initi2c(gspca_dev); + spca506_WriteI2c(gspca_dev, 0x08, 0x01); + spca506_WriteI2c(gspca_dev, 0xc0, 0x02); + /* input composite video */ + spca506_WriteI2c(gspca_dev, 0x33, 0x03); + spca506_WriteI2c(gspca_dev, 0x00, 0x04); + spca506_WriteI2c(gspca_dev, 0x00, 0x05); + spca506_WriteI2c(gspca_dev, 0x0d, 0x06); + spca506_WriteI2c(gspca_dev, 0xf0, 0x07); + spca506_WriteI2c(gspca_dev, 0x98, 0x08); + spca506_WriteI2c(gspca_dev, 0x03, 0x09); + spca506_WriteI2c(gspca_dev, 0x80, 0x0a); + spca506_WriteI2c(gspca_dev, 0x47, 0x0b); + spca506_WriteI2c(gspca_dev, 0x48, 0x0c); + spca506_WriteI2c(gspca_dev, 0x00, 0x0d); + spca506_WriteI2c(gspca_dev, 0x03, 0x0e); /* Chroma Pal adjust */ + spca506_WriteI2c(gspca_dev, 0x2a, 0x0f); + spca506_WriteI2c(gspca_dev, 0x00, 0x10); + spca506_WriteI2c(gspca_dev, 0x0c, 0x11); + spca506_WriteI2c(gspca_dev, 0xb8, 0x12); + spca506_WriteI2c(gspca_dev, 0x01, 0x13); + spca506_WriteI2c(gspca_dev, 0x00, 0x14); + spca506_WriteI2c(gspca_dev, 0x00, 0x15); + spca506_WriteI2c(gspca_dev, 0x00, 0x16); + spca506_WriteI2c(gspca_dev, 0x00, 0x17); + spca506_WriteI2c(gspca_dev, 0x00, 0x18); + spca506_WriteI2c(gspca_dev, 0x00, 0x19); + spca506_WriteI2c(gspca_dev, 0x00, 0x1a); + spca506_WriteI2c(gspca_dev, 0x00, 0x1b); + spca506_WriteI2c(gspca_dev, 0x00, 0x1c); + spca506_WriteI2c(gspca_dev, 0x00, 0x1d); + spca506_WriteI2c(gspca_dev, 0x00, 0x1e); + spca506_WriteI2c(gspca_dev, 0xa1, 0x1f); + spca506_WriteI2c(gspca_dev, 0x02, 0x40); + spca506_WriteI2c(gspca_dev, 0xff, 0x41); + spca506_WriteI2c(gspca_dev, 0xff, 0x42); + spca506_WriteI2c(gspca_dev, 0xff, 0x43); + spca506_WriteI2c(gspca_dev, 0xff, 0x44); + spca506_WriteI2c(gspca_dev, 0xff, 0x45); + spca506_WriteI2c(gspca_dev, 0xff, 0x46); + spca506_WriteI2c(gspca_dev, 0xff, 0x47); + spca506_WriteI2c(gspca_dev, 0xff, 0x48); + spca506_WriteI2c(gspca_dev, 0xff, 0x49); + spca506_WriteI2c(gspca_dev, 0xff, 0x4a); + spca506_WriteI2c(gspca_dev, 0xff, 0x4b); + spca506_WriteI2c(gspca_dev, 0xff, 0x4c); + spca506_WriteI2c(gspca_dev, 0xff, 0x4d); + spca506_WriteI2c(gspca_dev, 0xff, 0x4e); + spca506_WriteI2c(gspca_dev, 0xff, 0x4f); + spca506_WriteI2c(gspca_dev, 0xff, 0x50); + spca506_WriteI2c(gspca_dev, 0xff, 0x51); + spca506_WriteI2c(gspca_dev, 0xff, 0x52); + spca506_WriteI2c(gspca_dev, 0xff, 0x53); + spca506_WriteI2c(gspca_dev, 0xff, 0x54); + spca506_WriteI2c(gspca_dev, 0xff, 0x55); + spca506_WriteI2c(gspca_dev, 0xff, 0x56); + spca506_WriteI2c(gspca_dev, 0xff, 0x57); + spca506_WriteI2c(gspca_dev, 0x00, 0x58); + spca506_WriteI2c(gspca_dev, 0x54, 0x59); + spca506_WriteI2c(gspca_dev, 0x07, 0x5a); + spca506_WriteI2c(gspca_dev, 0x83, 0x5b); + spca506_WriteI2c(gspca_dev, 0x00, 0x5c); + spca506_WriteI2c(gspca_dev, 0x00, 0x5d); + spca506_WriteI2c(gspca_dev, 0x00, 0x5e); + spca506_WriteI2c(gspca_dev, 0x00, 0x5f); + spca506_WriteI2c(gspca_dev, 0x00, 0x60); + spca506_WriteI2c(gspca_dev, 0x05, 0x61); + spca506_WriteI2c(gspca_dev, 0x9f, 0x62); + PDEBUG(D_STREAM, "** Close Init *"); + return 0; +} + +static void sd_start(struct gspca_dev *gspca_dev) +{ + struct usb_device *dev = gspca_dev->dev; + __u16 norme; + __u16 channel; + + /**************************************/ + reg_w(dev, 0x03, 0x00, 0x0004); + reg_w(dev, 0x03, 0x00, 0x0003); + reg_w(dev, 0x03, 0x00, 0x0004); + reg_w(dev, 0x03, 0xFF, 0x0003); + reg_w(dev, 0x02, 0x00, 0x0000); + reg_w(dev, 0x03, 0x60, 0x0000); + reg_w(dev, 0x03, 0x18, 0x0001); + + /*sdca506_WriteI2c(value,register) */ + spca506_Initi2c(gspca_dev); + spca506_WriteI2c(gspca_dev, 0x08, 0x01); /* Increment Delay */ +/* spca506_WriteI2c(gspca_dev, 0xc0, 0x02); * Analog Input Control 1 */ + spca506_WriteI2c(gspca_dev, 0x33, 0x03); + /* Analog Input Control 2 */ + spca506_WriteI2c(gspca_dev, 0x00, 0x04); + /* Analog Input Control 3 */ + spca506_WriteI2c(gspca_dev, 0x00, 0x05); + /* Analog Input Control 4 */ + spca506_WriteI2c(gspca_dev, 0x0d, 0x06); + /* Horizontal Sync Start 0xe9-0x0d */ + spca506_WriteI2c(gspca_dev, 0xf0, 0x07); + /* Horizontal Sync Stop 0x0d-0xf0 */ + + spca506_WriteI2c(gspca_dev, 0x98, 0x08); /* Sync Control */ +/* Defaults value */ + spca506_WriteI2c(gspca_dev, 0x03, 0x09); /* Luminance Control */ + spca506_WriteI2c(gspca_dev, 0x80, 0x0a); + /* Luminance Brightness */ + spca506_WriteI2c(gspca_dev, 0x47, 0x0b); /* Luminance Contrast */ + spca506_WriteI2c(gspca_dev, 0x48, 0x0c); + /* Chrominance Saturation */ + spca506_WriteI2c(gspca_dev, 0x00, 0x0d); + /* Chrominance Hue Control */ + spca506_WriteI2c(gspca_dev, 0x2a, 0x0f); + /* Chrominance Gain Control */ + /**************************************/ + spca506_WriteI2c(gspca_dev, 0x00, 0x10); + /* Format/Delay Control */ + spca506_WriteI2c(gspca_dev, 0x0c, 0x11); /* Output Control 1 */ + spca506_WriteI2c(gspca_dev, 0xb8, 0x12); /* Output Control 2 */ + spca506_WriteI2c(gspca_dev, 0x01, 0x13); /* Output Control 3 */ + spca506_WriteI2c(gspca_dev, 0x00, 0x14); /* reserved */ + spca506_WriteI2c(gspca_dev, 0x00, 0x15); /* VGATE START */ + spca506_WriteI2c(gspca_dev, 0x00, 0x16); /* VGATE STOP */ + spca506_WriteI2c(gspca_dev, 0x00, 0x17); /* VGATE Control (MSB) */ + spca506_WriteI2c(gspca_dev, 0x00, 0x18); + spca506_WriteI2c(gspca_dev, 0x00, 0x19); + spca506_WriteI2c(gspca_dev, 0x00, 0x1a); + spca506_WriteI2c(gspca_dev, 0x00, 0x1b); + spca506_WriteI2c(gspca_dev, 0x00, 0x1c); + spca506_WriteI2c(gspca_dev, 0x00, 0x1d); + spca506_WriteI2c(gspca_dev, 0x00, 0x1e); + spca506_WriteI2c(gspca_dev, 0xa1, 0x1f); + spca506_WriteI2c(gspca_dev, 0x02, 0x40); + spca506_WriteI2c(gspca_dev, 0xff, 0x41); + spca506_WriteI2c(gspca_dev, 0xff, 0x42); + spca506_WriteI2c(gspca_dev, 0xff, 0x43); + spca506_WriteI2c(gspca_dev, 0xff, 0x44); + spca506_WriteI2c(gspca_dev, 0xff, 0x45); + spca506_WriteI2c(gspca_dev, 0xff, 0x46); + spca506_WriteI2c(gspca_dev, 0xff, 0x47); + spca506_WriteI2c(gspca_dev, 0xff, 0x48); + spca506_WriteI2c(gspca_dev, 0xff, 0x49); + spca506_WriteI2c(gspca_dev, 0xff, 0x4a); + spca506_WriteI2c(gspca_dev, 0xff, 0x4b); + spca506_WriteI2c(gspca_dev, 0xff, 0x4c); + spca506_WriteI2c(gspca_dev, 0xff, 0x4d); + spca506_WriteI2c(gspca_dev, 0xff, 0x4e); + spca506_WriteI2c(gspca_dev, 0xff, 0x4f); + spca506_WriteI2c(gspca_dev, 0xff, 0x50); + spca506_WriteI2c(gspca_dev, 0xff, 0x51); + spca506_WriteI2c(gspca_dev, 0xff, 0x52); + spca506_WriteI2c(gspca_dev, 0xff, 0x53); + spca506_WriteI2c(gspca_dev, 0xff, 0x54); + spca506_WriteI2c(gspca_dev, 0xff, 0x55); + spca506_WriteI2c(gspca_dev, 0xff, 0x56); + spca506_WriteI2c(gspca_dev, 0xff, 0x57); + spca506_WriteI2c(gspca_dev, 0x00, 0x58); + spca506_WriteI2c(gspca_dev, 0x54, 0x59); + spca506_WriteI2c(gspca_dev, 0x07, 0x5a); + spca506_WriteI2c(gspca_dev, 0x83, 0x5b); + spca506_WriteI2c(gspca_dev, 0x00, 0x5c); + spca506_WriteI2c(gspca_dev, 0x00, 0x5d); + spca506_WriteI2c(gspca_dev, 0x00, 0x5e); + spca506_WriteI2c(gspca_dev, 0x00, 0x5f); + spca506_WriteI2c(gspca_dev, 0x00, 0x60); + spca506_WriteI2c(gspca_dev, 0x05, 0x61); + spca506_WriteI2c(gspca_dev, 0x9f, 0x62); + /**************************************/ + reg_w(dev, 0x05, 0x00, 0x0003); + reg_w(dev, 0x05, 0x00, 0x0004); + reg_w(dev, 0x03, 0x10, 0x0001); + reg_w(dev, 0x03, 0x78, 0x0000); + switch (gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv) { + case 0: + spca506_Setsize(gspca_dev, 0, 0x10, 0x10); + break; + case 1: + spca506_Setsize(gspca_dev, 1, 0x1a, 0x1a); + break; + case 2: + spca506_Setsize(gspca_dev, 2, 0x1c, 0x1c); + break; + case 4: + spca506_Setsize(gspca_dev, 4, 0x34, 0x34); + break; + default: +/* case 5: */ + spca506_Setsize(gspca_dev, 5, 0x40, 0x40); + break; + } + + /* compress setting and size */ + /* set i2c luma */ + reg_w(dev, 0x02, 0x01, 0x0000); + reg_w(dev, 0x03, 0x12, 0x0000); + reg_r(gspca_dev, 0x04, 0x0001, 2); + PDEBUG(D_STREAM, "webcam started"); + spca506_GetNormeInput(gspca_dev, &norme, &channel); + spca506_SetNormeInput(gspca_dev, norme, channel); +} + +static void sd_stopN(struct gspca_dev *gspca_dev) +{ + struct usb_device *dev = gspca_dev->dev; + + reg_w(dev, 0x02, 0x00, 0x0000); + reg_w(dev, 0x03, 0x00, 0x0004); + reg_w(dev, 0x03, 0x00, 0x0003); +} + +static void sd_stop0(struct gspca_dev *gspca_dev) +{ +} + +static void sd_close(struct gspca_dev *gspca_dev) +{ +} + +/* convert YYUV per line to YUYV (YUV 4:2:2) */ +static void yyuv_decode(unsigned char *out, + unsigned char *in, + int width, + int height) +{ + unsigned char *Ui, *Vi, *yi, *yi1; + unsigned char *out1; + int i, j; + + yi = in; + for (i = height / 2; --i >= 0; ) { + out1 = out + width * 2; /* next line */ + yi1 = yi + width; + Ui = yi1 + width; + Vi = Ui + width / 2; + for (j = width / 2; --j >= 0; ) { + *out++ = 128 + *yi++; + *out++ = 128 + *Ui; + *out++ = 128 + *yi++; + *out++ = 128 + *Vi; + + *out1++ = 128 + *yi1++; + *out1++ = 128 + *Ui++; + *out1++ = 128 + *yi1++; + *out1++ = 128 + *Vi++; + } + yi += width * 2; + out = out1; + } +} + +static void sd_pkt_scan(struct gspca_dev *gspca_dev, + struct gspca_frame *frame, /* target */ + __u8 *data, /* isoc packet */ + int len) /* iso packet length */ +{ + struct sd *sd = (struct sd *) gspca_dev; + + switch (data[0]) { + case 0: /* start of frame */ + if (gspca_dev->last_packet_type == FIRST_PACKET) { + yyuv_decode(sd->tmpbuf2, sd->tmpbuf, + gspca_dev->width, + gspca_dev->height); + frame = gspca_frame_add(gspca_dev, + LAST_PACKET, + frame, + sd->tmpbuf2, + gspca_dev->width + * gspca_dev->height + * 2); + } + gspca_frame_add(gspca_dev, FIRST_PACKET, frame, + data, 0); + data += SPCA50X_OFFSET_DATA; + len -= SPCA50X_OFFSET_DATA; + if (len > 0) + memcpy(sd->tmpbuf, data, len); + else + len = 0; + sd->buflen = len; + return; + case 0xff: /* drop */ +/* gspca_dev->last_packet_type = DISCARD_PACKET; */ + return; + } + data += 1; + len -= 1; + memcpy(&sd->tmpbuf[sd->buflen], data, len); + sd->buflen += len; +} + +static void setbrightness(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + + spca506_Initi2c(gspca_dev); + spca506_WriteI2c(gspca_dev, sd->brightness, SAA7113_bright); + spca506_WriteI2c(gspca_dev, 0x01, 0x09); +} + +static void getbrightness(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->brightness = spca506_ReadI2c(gspca_dev, SAA7113_bright); +} + +static void setcontrast(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + + spca506_Initi2c(gspca_dev); + spca506_WriteI2c(gspca_dev, sd->contrast, SAA7113_contrast); + spca506_WriteI2c(gspca_dev, 0x01, 0x09); +} + +static void getcontrast(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->contrast = spca506_ReadI2c(gspca_dev, SAA7113_contrast); +} + +static void setcolors(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + + spca506_Initi2c(gspca_dev); + spca506_WriteI2c(gspca_dev, sd->colors, SAA7113_saturation); + spca506_WriteI2c(gspca_dev, 0x01, 0x09); +} + +static void getcolors(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->colors = spca506_ReadI2c(gspca_dev, SAA7113_saturation); +} + +static void sethue(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + + spca506_Initi2c(gspca_dev); + spca506_WriteI2c(gspca_dev, sd->hue, SAA7113_hue); + spca506_WriteI2c(gspca_dev, 0x01, 0x09); +} + +static void gethue(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->hue = spca506_ReadI2c(gspca_dev, SAA7113_hue); +} + +static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->brightness = val; + if (gspca_dev->streaming) + setbrightness(gspca_dev); + return 0; +} + +static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + getbrightness(gspca_dev); + *val = sd->brightness; + return 0; +} + +static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->contrast = val; + if (gspca_dev->streaming) + setcontrast(gspca_dev); + return 0; +} + +static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + getcontrast(gspca_dev); + *val = sd->contrast; + return 0; +} + +static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->colors = val; + if (gspca_dev->streaming) + setcolors(gspca_dev); + return 0; +} + +static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + getcolors(gspca_dev); + *val = sd->colors; + return 0; +} + +static int sd_sethue(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->hue = val; + if (gspca_dev->streaming) + sethue(gspca_dev); + return 0; +} + +static int sd_gethue(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + gethue(gspca_dev); + *val = sd->hue; + return 0; +} + +/* sub-driver description */ +static struct sd_desc sd_desc = { + .name = MODULE_NAME, + .ctrls = sd_ctrls, + .nctrls = ARRAY_SIZE(sd_ctrls), + .config = sd_config, + .open = sd_open, + .start = sd_start, + .stopN = sd_stopN, + .stop0 = sd_stop0, + .close = sd_close, + .pkt_scan = sd_pkt_scan, +}; + +/* -- module initialisation -- */ +#define DVNM(name) .driver_info = (kernel_ulong_t) name +static __devinitdata struct usb_device_id device_table[] = { + {USB_DEVICE(0x06e1, 0xa190), DVNM("ADS Instant VCD")}, +/* {USB_DEVICE(0x0733, 0x0430), DVNM("UsbGrabber PV321c")}, */ + {USB_DEVICE(0x0734, 0x043b), DVNM("3DeMon USB Capture aka")}, + {USB_DEVICE(0x99fa, 0x8988), DVNM("Grandtec V.cap")}, + {} +}; +MODULE_DEVICE_TABLE(usb, device_table); + +/* -- device connect -- */ +static int sd_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd), + THIS_MODULE); +} + +static struct usb_driver sd_driver = { + .name = MODULE_NAME, + .id_table = device_table, + .probe = sd_probe, + .disconnect = gspca_disconnect, +}; + +/* -- module insert / remove -- */ +static int __init sd_mod_init(void) +{ + if (usb_register(&sd_driver) < 0) + return -1; + PDEBUG(D_PROBE, "v%s registered", version); + return 0; +} +static void __exit sd_mod_exit(void) +{ + usb_deregister(&sd_driver); + PDEBUG(D_PROBE, "deregistered"); +} + +module_init(sd_mod_init); +module_exit(sd_mod_exit); diff --git a/drivers/media/video/gspca/spca508.c b/drivers/media/video/gspca/spca508.c new file mode 100644 index 000000000000..d8cd93866a4a --- /dev/null +++ b/drivers/media/video/gspca/spca508.c @@ -0,0 +1,1791 @@ +/* + * SPCA508 chip based cameras subdriver + * + * V4L2 by Jean-Francois Moine <http://moinejf.free.fr> + * + * 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 + * 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 + */ + +#define MODULE_NAME "spca508" + +#include "gspca.h" + +#define DRIVER_VERSION_NUMBER KERNEL_VERSION(2, 1, 7) +static const char version[] = "2.1.7"; + +MODULE_AUTHOR("Michel Xhaard <mxhaard@users.sourceforge.net>"); +MODULE_DESCRIPTION("GSPCA/SPCA508 USB Camera Driver"); +MODULE_LICENSE("GPL"); + +/* specific webcam descriptor */ +struct sd { + struct gspca_dev gspca_dev; /* !! must be the first item */ + + int buflen; + unsigned char tmpbuf[352 * 288 * 3 / 2]; /* YUVY per line */ + unsigned char tmpbuf2[352 * 288 * 2]; /* YUYV */ + + unsigned char brightness; + + char subtype; +#define CreativeVista 0 +#define HamaUSBSightcam 1 +#define HamaUSBSightcam2 2 +#define IntelEasyPCCamera 3 +#define MicroInnovationIC200 4 +#define ViewQuestVQ110 5 +}; + +/* V4L2 controls supported by the driver */ +static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val); +static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val); + +static struct ctrl sd_ctrls[] = { + { + { + .id = V4L2_CID_BRIGHTNESS, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Brightness", + .minimum = 0, + .maximum = 255, + .step = 1, +#define BRIGHTNESS_DEF 128 + .default_value = BRIGHTNESS_DEF, + }, + .set = sd_setbrightness, + .get = sd_getbrightness, + }, +}; + +static struct v4l2_pix_format sif_mode[] = { + {160, 120, V4L2_PIX_FMT_YUYV, V4L2_FIELD_NONE, + .bytesperline = 160 * 2, + .sizeimage = 160 * 120 * 2, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = 3}, + {176, 144, V4L2_PIX_FMT_YUYV, V4L2_FIELD_NONE, + .bytesperline = 176 * 2, + .sizeimage = 176 * 144 * 2, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = 2}, + {320, 240, V4L2_PIX_FMT_YUYV, V4L2_FIELD_NONE, + .bytesperline = 320 * 2, + .sizeimage = 320 * 240 * 2, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = 1}, + {352, 288, V4L2_PIX_FMT_YUYV, V4L2_FIELD_NONE, + .bytesperline = 352 * 2, + .sizeimage = 352 * 288 * 2, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = 0}, +}; + +/* Frame packet header offsets for the spca508 */ +#define SPCA508_OFFSET_TYPE 1 +#define SPCA508_OFFSET_COMPRESS 2 +#define SPCA508_OFFSET_FRAMSEQ 8 +#define SPCA508_OFFSET_WIN1LUM 11 +#define SPCA508_OFFSET_DATA 37 + +#define SPCA508_SNAPBIT 0x20 +#define SPCA508_SNAPCTRL 0x40 +/*************** I2c ****************/ +#define SPCA508_INDEX_I2C_BASE 0x8800 + +/* + * Initialization data: this is the first set-up data written to the + * device (before the open data). + */ +static const __u16 spca508_init_data[][3] = +#define IGN(x) /* nothing */ +{ + /* line URB value, index */ + /* 44274 1804 */ {0x0000, 0x870b}, + + /* 44299 1805 */ {0x0020, 0x8112}, + /* Video drop enable, ISO streaming disable */ + /* 44324 1806 */ {0x0003, 0x8111}, + /* Reset compression & memory */ + /* 44349 1807 */ {0x0000, 0x8110}, + /* Disable all outputs */ + /* 44372 1808 */ /* READ {0x0000, 0x8114} -> 0000: 00 */ + /* 44398 1809 */ {0x0000, 0x8114}, + /* SW GPIO data */ + /* 44423 1810 */ {0x0008, 0x8110}, + /* Enable charge pump output */ + /* 44527 1811 */ {0x0002, 0x8116}, + /* 200 kHz pump clock */ + /* 44555 1812 */ + /* UNKNOWN DIRECTION (URB_FUNCTION_SELECT_INTERFACE:) */ + /* 44590 1813 */ {0x0003, 0x8111}, + /* Reset compression & memory */ + /* 44615 1814 */ {0x0000, 0x8111}, + /* Normal mode (not reset) */ + /* 44640 1815 */ {0x0098, 0x8110}, + /* Enable charge pump output, sync.serial,external 2x clock */ + /* 44665 1816 */ {0x000d, 0x8114}, + /* SW GPIO data */ + /* 44690 1817 */ {0x0002, 0x8116}, + /* 200 kHz pump clock */ + /* 44715 1818 */ {0x0020, 0x8112}, + /* Video drop enable, ISO streaming disable */ +/* --------------------------------------- */ + /* 44740 1819 */ {0x000f, 0x8402}, + /* memory bank */ + /* 44765 1820 */ {0x0000, 0x8403}, + /* ... address */ +/* --------------------------------------- */ +/* 0x88__ is Synchronous Serial Interface. */ +/* TBD: This table could be expressed more compactly */ +/* using spca508_write_i2c_vector(). */ +/* TBD: Should see if the values in spca50x_i2c_data */ +/* would work with the VQ110 instead of the values */ +/* below. */ + /* 44790 1821 */ {0x00c0, 0x8804}, + /* SSI slave addr */ + /* 44815 1822 */ {0x0008, 0x8802}, + /* 375 Khz SSI clock */ + /* 44838 1823 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */ + /* 44862 1824 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08 */ + /* 44888 1825 */ {0x0008, 0x8802}, + /* 375 Khz SSI clock */ + /* 44913 1826 */ {0x0012, 0x8801}, + /* SSI reg addr */ + /* 44938 1827 */ {0x0080, 0x8800}, + /* SSI data to write */ + /* 44961 1828 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */ + /* 44985 1829 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */ + /* 45009 1830 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08 */ + /* 45035 1831 */ {0x0008, 0x8802}, + /* 375 Khz SSI clock */ + /* 45060 1832 */ {0x0012, 0x8801}, + /* SSI reg addr */ + /* 45085 1833 */ {0x0000, 0x8800}, + /* SSI data to write */ + /* 45108 1834 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */ + /* 45132 1835 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */ + /* 45156 1836 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08 */ + /* 45182 1837 */ {0x0008, 0x8802}, + /* 375 Khz SSI clock */ + /* 45207 1838 */ {0x0011, 0x8801}, + /* SSI reg addr */ + /* 45232 1839 */ {0x0040, 0x8800}, + /* SSI data to write */ + /* 45255 1840 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */ + /* 45279 1841 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */ + /* 45303 1842 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08 */ + /* 45329 1843 */ {0x0008, 0x8802}, + /* 45354 1844 */ {0x0013, 0x8801}, + /* 45379 1845 */ {0x0000, 0x8800}, + /* 45402 1846 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */ + /* 45426 1847 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */ + /* 45450 1848 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08 */ + /* 45476 1849 */ {0x0008, 0x8802}, + /* 45501 1850 */ {0x0014, 0x8801}, + /* 45526 1851 */ {0x0000, 0x8800}, + /* 45549 1852 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */ + /* 45573 1853 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */ + /* 45597 1854 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08 */ + /* 45623 1855 */ {0x0008, 0x8802}, + /* 45648 1856 */ {0x0015, 0x8801}, + /* 45673 1857 */ {0x0001, 0x8800}, + /* 45696 1858 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */ + /* 45720 1859 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */ + /* 45744 1860 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08 */ + /* 45770 1861 */ {0x0008, 0x8802}, + /* 45795 1862 */ {0x0016, 0x8801}, + /* 45820 1863 */ {0x0003, 0x8800}, + /* 45843 1864 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */ + /* 45867 1865 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */ + /* 45891 1866 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08 */ + /* 45917 1867 */ {0x0008, 0x8802}, + /* 45942 1868 */ {0x0017, 0x8801}, + /* 45967 1869 */ {0x0036, 0x8800}, + /* 45990 1870 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */ + /* 46014 1871 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */ + /* 46038 1872 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08 */ + /* 46064 1873 */ {0x0008, 0x8802}, + /* 46089 1874 */ {0x0018, 0x8801}, + /* 46114 1875 */ {0x00ec, 0x8800}, + /* 46137 1876 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */ + /* 46161 1877 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */ + /* 46185 1878 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08 */ + /* 46211 1879 */ {0x0008, 0x8802}, + /* 46236 1880 */ {0x001a, 0x8801}, + /* 46261 1881 */ {0x0094, 0x8800}, + /* 46284 1882 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */ + /* 46308 1883 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */ + /* 46332 1884 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08 */ + /* 46358 1885 */ {0x0008, 0x8802}, + /* 46383 1886 */ {0x001b, 0x8801}, + /* 46408 1887 */ {0x0000, 0x8800}, + /* 46431 1888 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */ + /* 46455 1889 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */ + /* 46479 1890 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08 */ + /* 46505 1891 */ {0x0008, 0x8802}, + /* 46530 1892 */ {0x0027, 0x8801}, + /* 46555 1893 */ {0x00a2, 0x8800}, + /* 46578 1894 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */ + /* 46602 1895 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */ + /* 46626 1896 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08 */ + /* 46652 1897 */ {0x0008, 0x8802}, + /* 46677 1898 */ {0x0028, 0x8801}, + /* 46702 1899 */ {0x0040, 0x8800}, + /* 46725 1900 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */ + /* 46749 1901 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */ + /* 46773 1902 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08 */ + /* 46799 1903 */ {0x0008, 0x8802}, + /* 46824 1904 */ {0x002a, 0x8801}, + /* 46849 1905 */ {0x0084, 0x8800}, + /* 46872 1906 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */ + /* 46896 1907 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */ + /* 46920 1908 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08 */ + /* 46946 1909 */ {0x0008, 0x8802}, + /* 46971 1910 */ {0x002b, 0x8801}, + /* 46996 1911 */ {0x00a8, 0x8800}, + /* 47019 1912 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */ + /* 47043 1913 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */ + /* 47067 1914 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08 */ + /* 47093 1915 */ {0x0008, 0x8802}, + /* 47118 1916 */ {0x002c, 0x8801}, + /* 47143 1917 */ {0x00fe, 0x8800}, + /* 47166 1918 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */ + /* 47190 1919 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */ + /* 47214 1920 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08 */ + /* 47240 1921 */ {0x0008, 0x8802}, + /* 47265 1922 */ {0x002d, 0x8801}, + /* 47290 1923 */ {0x0003, 0x8800}, + /* 47313 1924 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */ + /* 47337 1925 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */ + /* 47361 1926 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08 */ + /* 47387 1927 */ {0x0008, 0x8802}, + /* 47412 1928 */ {0x0038, 0x8801}, + /* 47437 1929 */ {0x0083, 0x8800}, + /* 47460 1930 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */ + /* 47484 1931 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */ + /* 47508 1932 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08 */ + /* 47534 1933 */ {0x0008, 0x8802}, + /* 47559 1934 */ {0x0033, 0x8801}, + /* 47584 1935 */ {0x0081, 0x8800}, + /* 47607 1936 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */ + /* 47631 1937 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */ + /* 47655 1938 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08 */ + /* 47681 1939 */ {0x0008, 0x8802}, + /* 47706 1940 */ {0x0034, 0x8801}, + /* 47731 1941 */ {0x004a, 0x8800}, + /* 47754 1942 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */ + /* 47778 1943 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */ + /* 47802 1944 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08 */ + /* 47828 1945 */ {0x0008, 0x8802}, + /* 47853 1946 */ {0x0039, 0x8801}, + /* 47878 1947 */ {0x0000, 0x8800}, + /* 47901 1948 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */ + /* 47925 1949 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */ + /* 47949 1950 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08 */ + /* 47975 1951 */ {0x0008, 0x8802}, + /* 48000 1952 */ {0x0010, 0x8801}, + /* 48025 1953 */ {0x00a8, 0x8800}, + /* 48048 1954 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */ + /* 48072 1955 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */ + /* 48096 1956 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08 */ + /* 48122 1957 */ {0x0008, 0x8802}, + /* 48147 1958 */ {0x0006, 0x8801}, + /* 48172 1959 */ {0x0058, 0x8800}, + /* 48195 1960 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */ + /* 48219 1961 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */ + /* 48243 1962 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08 */ + /* 48269 1963 */ {0x0008, 0x8802}, + /* 48294 1964 */ {0x0000, 0x8801}, + /* 48319 1965 */ {0x0004, 0x8800}, + /* 48342 1966 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */ + /* 48366 1967 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */ + /* 48390 1968 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08 */ + /* 48416 1969 */ {0x0008, 0x8802}, + /* 48441 1970 */ {0x0040, 0x8801}, + /* 48466 1971 */ {0x0080, 0x8800}, + /* 48489 1972 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */ + /* 48513 1973 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */ + /* 48537 1974 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08 */ + /* 48563 1975 */ {0x0008, 0x8802}, + /* 48588 1976 */ {0x0041, 0x8801}, + /* 48613 1977 */ {0x000c, 0x8800}, + /* 48636 1978 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */ + /* 48660 1979 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */ + /* 48684 1980 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08 */ + /* 48710 1981 */ {0x0008, 0x8802}, + /* 48735 1982 */ {0x0042, 0x8801}, + /* 48760 1983 */ {0x000c, 0x8800}, + /* 48783 1984 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */ + /* 48807 1985 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */ + /* 48831 1986 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08 */ + /* 48857 1987 */ {0x0008, 0x8802}, + /* 48882 1988 */ {0x0043, 0x8801}, + /* 48907 1989 */ {0x0028, 0x8800}, + /* 48930 1990 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */ + /* 48954 1991 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */ + /* 48978 1992 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08 */ + /* 49004 1993 */ {0x0008, 0x8802}, + /* 49029 1994 */ {0x0044, 0x8801}, + /* 49054 1995 */ {0x0080, 0x8800}, + /* 49077 1996 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */ + /* 49101 1997 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */ + /* 49125 1998 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08 */ + /* 49151 1999 */ {0x0008, 0x8802}, + /* 49176 2000 */ {0x0045, 0x8801}, + /* 49201 2001 */ {0x0020, 0x8800}, + /* 49224 2002 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */ + /* 49248 2003 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */ + /* 49272 2004 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08 */ + /* 49298 2005 */ {0x0008, 0x8802}, + /* 49323 2006 */ {0x0046, 0x8801}, + /* 49348 2007 */ {0x0020, 0x8800}, + /* 49371 2008 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */ + /* 49395 2009 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */ + /* 49419 2010 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08 */ + /* 49445 2011 */ {0x0008, 0x8802}, + /* 49470 2012 */ {0x0047, 0x8801}, + /* 49495 2013 */ {0x0080, 0x8800}, + /* 49518 2014 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */ + /* 49542 2015 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */ + /* 49566 2016 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08 */ + /* 49592 2017 */ {0x0008, 0x8802}, + /* 49617 2018 */ {0x0048, 0x8801}, + /* 49642 2019 */ {0x004c, 0x8800}, + /* 49665 2020 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */ + /* 49689 2021 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */ + /* 49713 2022 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08 */ + /* 49739 2023 */ {0x0008, 0x8802}, + /* 49764 2024 */ {0x0049, 0x8801}, + /* 49789 2025 */ {0x0084, 0x8800}, + /* 49812 2026 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */ + /* 49836 2027 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */ + /* 49860 2028 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08 */ + /* 49886 2029 */ {0x0008, 0x8802}, + /* 49911 2030 */ {0x004a, 0x8801}, + /* 49936 2031 */ {0x0084, 0x8800}, + /* 49959 2032 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */ + /* 49983 2033 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */ + /* 50007 2034 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08 */ + /* 50033 2035 */ {0x0008, 0x8802}, + /* 50058 2036 */ {0x004b, 0x8801}, + /* 50083 2037 */ {0x0084, 0x8800}, + /* 50106 2038 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */ + /* --------------------------------------- */ + /* 50132 2039 */ {0x0012, 0x8700}, + /* Clock speed 48Mhz/(2+2)/2= 6 Mhz */ + /* 50157 2040 */ {0x0000, 0x8701}, + /* CKx1 clock delay adj */ + /* 50182 2041 */ {0x0000, 0x8701}, + /* CKx1 clock delay adj */ + /* 50207 2042 */ {0x0001, 0x870c}, + /* CKOx2 output */ + /* --------------------------------------- */ + /* 50232 2043 */ {0x0080, 0x8600}, + /* Line memory read counter (L) */ + /* 50257 2044 */ {0x0001, 0x8606}, + /* reserved */ + /* 50282 2045 */ {0x0064, 0x8607}, + /* Line memory read counter (H) 0x6480=25,728 */ + /* 50307 2046 */ {0x002a, 0x8601}, + /* CDSP sharp interpolation mode, + * line sel for color sep, edge enhance enab */ + /* 50332 2047 */ {0x0000, 0x8602}, + /* optical black level for user settng = 0 */ + /* 50357 2048 */ {0x0080, 0x8600}, + /* Line memory read counter (L) */ + /* 50382 2049 */ {0x000a, 0x8603}, + /* optical black level calc mode: auto; optical black offset = 10 */ + /* 50407 2050 */ {0x00df, 0x865b}, + /* Horiz offset for valid pixels (L)=0xdf */ + /* 50432 2051 */ {0x0012, 0x865c}, + /* Vert offset for valid lines (L)=0x12 */ + +/* The following two lines seem to be the "wrong" resolution. */ +/* But perhaps these indicate the actual size of the sensor */ +/* rather than the size of the current video mode. */ + /* 50457 2052 */ {0x0058, 0x865d}, + /* Horiz valid pixels (*4) (L) = 352 */ + /* 50482 2053 */ {0x0048, 0x865e}, + /* Vert valid lines (*4) (L) = 288 */ + + /* 50507 2054 */ {0x0015, 0x8608}, + /* A11 Coef ... */ + /* 50532 2055 */ {0x0030, 0x8609}, + /* 50557 2056 */ {0x00fb, 0x860a}, + /* 50582 2057 */ {0x003e, 0x860b}, + /* 50607 2058 */ {0x00ce, 0x860c}, + /* 50632 2059 */ {0x00f4, 0x860d}, + /* 50657 2060 */ {0x00eb, 0x860e}, + /* 50682 2061 */ {0x00dc, 0x860f}, + /* 50707 2062 */ {0x0039, 0x8610}, + /* 50732 2063 */ {0x0001, 0x8611}, + /* R offset for white balance ... */ + /* 50757 2064 */ {0x0000, 0x8612}, + /* 50782 2065 */ {0x0001, 0x8613}, + /* 50807 2066 */ {0x0000, 0x8614}, + /* 50832 2067 */ {0x005b, 0x8651}, + /* R gain for white balance ... */ + /* 50857 2068 */ {0x0040, 0x8652}, + /* 50882 2069 */ {0x0060, 0x8653}, + /* 50907 2070 */ {0x0040, 0x8654}, + /* 50932 2071 */ {0x0000, 0x8655}, + /* 50957 2072 */ {0x0001, 0x863f}, + /* Fixed gamma correction enable, USB control, + * lum filter disable, lum noise clip disable */ + /* 50982 2073 */ {0x00a1, 0x8656}, + /* Window1 size 256x256, Windows2 size 64x64, + * gamma look-up disable, new edge enhancement enable */ + /* 51007 2074 */ {0x0018, 0x8657}, + /* Edge gain high thresh */ + /* 51032 2075 */ {0x0020, 0x8658}, + /* Edge gain low thresh */ + /* 51057 2076 */ {0x000a, 0x8659}, + /* Edge bandwidth high threshold */ + /* 51082 2077 */ {0x0005, 0x865a}, + /* Edge bandwidth low threshold */ + /* -------------------------------- */ + /* 51107 2078 */ {0x0030, 0x8112}, + /* Video drop enable, ISO streaming enable */ + /* 51130 2079 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */ + /* 51154 2080 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08 */ + /* 51180 2081 */ {0xa908, 0x8802}, + /* 51205 2082 */ {0x0034, 0x8801}, + /* SSI reg addr */ + /* 51230 2083 */ {0x00ca, 0x8800}, + /* SSI data to write */ + /* 51253 2084 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */ + /* 51277 2085 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */ + /* 51301 2086 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08 */ + /* 51327 2087 */ {0x1f08, 0x8802}, + /* 51352 2088 */ {0x0006, 0x8801}, + /* 51377 2089 */ {0x0080, 0x8800}, + /* 51400 2090 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */ + +/* ----- Read back coefs we wrote earlier. */ + /* 51424 2091 */ /* READ { 0, 0x0000, 0x8608 } -> 0000: 15 */ + /* 51448 2092 */ /* READ { 0, 0x0000, 0x8609 } -> 0000: 30 */ + /* 51472 2093 */ /* READ { 0, 0x0000, 0x860a } -> 0000: fb */ + /* 51496 2094 */ /* READ { 0, 0x0000, 0x860b } -> 0000: 3e */ + /* 51520 2095 */ /* READ { 0, 0x0000, 0x860c } -> 0000: ce */ + /* 51544 2096 */ /* READ { 0, 0x0000, 0x860d } -> 0000: f4 */ + /* 51568 2097 */ /* READ { 0, 0x0000, 0x860e } -> 0000: eb */ + /* 51592 2098 */ /* READ { 0, 0x0000, 0x860f } -> 0000: dc */ + /* 51616 2099 */ /* READ { 0, 0x0000, 0x8610 } -> 0000: 39 */ + /* 51640 2100 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */ + /* 51664 2101 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08 */ + /* 51690 2102 */ {0xb008, 0x8802}, + /* 51715 2103 */ {0x0006, 0x8801}, + /* 51740 2104 */ {0x007d, 0x8800}, + /* 51763 2105 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */ + + + /* This chunk is seemingly redundant with */ + /* earlier commands (A11 Coef...), but if I disable it, */ + /* the image appears too dark. Maybe there was some kind of */ + /* reset since the earlier commands, so this is necessary again. */ + /* 51789 2106 */ {0x0015, 0x8608}, + /* 51814 2107 */ {0x0030, 0x8609}, + /* 51839 2108 */ {0xfffb, 0x860a}, + /* 51864 2109 */ {0x003e, 0x860b}, + /* 51889 2110 */ {0xffce, 0x860c}, + /* 51914 2111 */ {0xfff4, 0x860d}, + /* 51939 2112 */ {0xffeb, 0x860e}, + /* 51964 2113 */ {0xffdc, 0x860f}, + /* 51989 2114 */ {0x0039, 0x8610}, + /* 52014 2115 */ {0x0018, 0x8657}, + + /* 52039 2116 */ {0x0000, 0x8508}, + /* Disable compression. */ + /* Previous line was: + * 52039 2116 * { 0, 0x0021, 0x8508 }, * Enable compression. */ + /* 52064 2117 */ {0x0032, 0x850b}, + /* compression stuff */ + /* 52089 2118 */ {0x0003, 0x8509}, + /* compression stuff */ + /* 52114 2119 */ {0x0011, 0x850a}, + /* compression stuff */ + /* 52139 2120 */ {0x0021, 0x850d}, + /* compression stuff */ + /* 52164 2121 */ {0x0010, 0x850c}, + /* compression stuff */ + /* 52189 2122 */ {0x0003, 0x8500}, + /* *** Video mode: 160x120 */ + /* 52214 2123 */ {0x0001, 0x8501}, + /* Hardware-dominated snap control */ + /* 52239 2124 */ {0x0061, 0x8656}, + /* Window1 size 128x128, Windows2 size 128x128, + * gamma look-up disable, new edge enhancement enable */ + /* 52264 2125 */ {0x0018, 0x8617}, + /* Window1 start X (*2) */ + /* 52289 2126 */ {0x0008, 0x8618}, + /* Window1 start Y (*2) */ + /* 52314 2127 */ {0x0061, 0x8656}, + /* Window1 size 128x128, Windows2 size 128x128, + * gamma look-up disable, new edge enhancement enable */ + /* 52339 2128 */ {0x0058, 0x8619}, + /* Window2 start X (*2) */ + /* 52364 2129 */ {0x0008, 0x861a}, + /* Window2 start Y (*2) */ + /* 52389 2130 */ {0x00ff, 0x8615}, + /* High lum thresh for white balance */ + /* 52414 2131 */ {0x0000, 0x8616}, + /* Low lum thresh for white balance */ + /* 52439 2132 */ {0x0012, 0x8700}, + /* Clock speed 48Mhz/(2+2)/2= 6 Mhz */ + /* 52464 2133 */ {0x0012, 0x8700}, + /* Clock speed 48Mhz/(2+2)/2= 6 Mhz */ + /* 52487 2134 */ /* READ { 0, 0x0000, 0x8656 } -> 0000: 61 */ + /* 52513 2135 */ {0x0028, 0x8802}, + /* 375 Khz SSI clock, SSI r/w sync with VSYNC */ + /* 52536 2136 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */ + /* 52560 2137 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 28 */ + /* 52586 2138 */ {0x1f28, 0x8802}, + /* 375 Khz SSI clock, SSI r/w sync with VSYNC */ + /* 52611 2139 */ {0x0010, 0x8801}, + /* SSI reg addr */ + /* 52636 2140 */ {0x003e, 0x8800}, + /* SSI data to write */ + /* 52659 2141 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */ + /* 52685 2142 */ {0x0028, 0x8802}, + /* 52708 2143 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */ + /* 52732 2144 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 28 */ + /* 52758 2145 */ {0x1f28, 0x8802}, + /* 52783 2146 */ {0x0000, 0x8801}, + /* 52808 2147 */ {0x001f, 0x8800}, + /* 52831 2148 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */ + /* 52857 2149 */ {0x0001, 0x8602}, + /* optical black level for user settning = 1 */ + + /* Original: */ + /* 52882 2150 */ {0x0023, 0x8700}, + /* Clock speed 48Mhz/(3+2)/4= 2.4 Mhz */ + /* 52907 2151 */ {0x000f, 0x8602}, + /* optical black level for user settning = 15 */ + + /* 52932 2152 */ {0x0028, 0x8802}, + /* 52955 2153 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */ + /* 52979 2154 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 28 */ + /* 53005 2155 */ {0x1f28, 0x8802}, + /* 53030 2156 */ {0x0010, 0x8801}, + /* 53055 2157 */ {0x007b, 0x8800}, + /* 53078 2158 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */ + /* 53104 2159 */ {0x002f, 0x8651}, + /* R gain for white balance ... */ + /* 53129 2160 */ {0x0080, 0x8653}, + /* 53152 2161 */ /* READ { 0, 0x0000, 0x8655 } -> 0000: 00 */ + /* 53178 2162 */ {0x0000, 0x8655}, + + /* 53203 2163 */ {0x0030, 0x8112}, + /* Video drop enable, ISO streaming enable */ + /* 53228 2164 */ {0x0020, 0x8112}, + /* Video drop enable, ISO streaming disable */ + /* 53252 2165 */ + /* UNKNOWN DIRECTION (URB_FUNCTION_SELECT_INTERFACE: (ALT=0) ) */ + {} +}; + + +/* + * Initialization data for Intel EasyPC Camera CS110 + */ +static const __u16 spca508cs110_init_data[][3] = { + {0x0000, 0x870b}, /* Reset CTL3 */ + {0x0003, 0x8111}, /* Soft Reset compression, memory, TG & CDSP */ + {0x0000, 0x8111}, /* Normal operation on reset */ + {0x0090, 0x8110}, + /* External Clock 2x & Synchronous Serial Interface Output */ + {0x0020, 0x8112}, /* Video Drop packet enable */ + {0x0000, 0x8114}, /* Software GPIO output data */ + {0x0001, 0x8114}, + {0x0001, 0x8114}, + {0x0001, 0x8114}, + {0x0003, 0x8114}, + + /* Initial sequence Synchronous Serial Interface */ + {0x000f, 0x8402}, /* Memory bank Address */ + {0x0000, 0x8403}, /* Memory bank Address */ + {0x00ba, 0x8804}, /* SSI Slave address */ + {0x0010, 0x8802}, /* 93.75kHz SSI Clock Two DataByte */ + {0x0010, 0x8802}, /* 93.75kHz SSI Clock two DataByte */ + + {0x0001, 0x8801}, + {0x000a, 0x8805},/* a - NWG: Dunno what this is about */ + {0x0000, 0x8800}, + {0x0010, 0x8802}, + + {0x0002, 0x8801}, + {0x0000, 0x8805}, + {0x0000, 0x8800}, + {0x0010, 0x8802}, + + {0x0003, 0x8801}, + {0x0027, 0x8805}, + {0x0001, 0x8800}, + {0x0010, 0x8802}, + + {0x0004, 0x8801}, + {0x0065, 0x8805}, + {0x0001, 0x8800}, + {0x0010, 0x8802}, + + {0x0005, 0x8801}, + {0x0003, 0x8805}, + {0x0000, 0x8800}, + {0x0010, 0x8802}, + + {0x0006, 0x8801}, + {0x001c, 0x8805}, + {0x0000, 0x8800}, + {0x0010, 0x8802}, + + {0x0007, 0x8801}, + {0x002a, 0x8805}, + {0x0000, 0x8800}, + {0x0010, 0x8802}, + + {0x0002, 0x8704}, /* External input CKIx1 */ + {0x0001, 0x8606}, /* 1 Line memory Read Counter (H) Result: (d)410 */ + {0x009a, 0x8600}, /* Line memory Read Counter (L) */ + {0x0001, 0x865b}, /* 1 Horizontal Offset for Valid Pixel(L) */ + {0x0003, 0x865c}, /* 3 Vertical Offset for Valid Lines(L) */ + {0x0058, 0x865d}, /* 58 Horizontal Valid Pixel Window(L) */ + + {0x0006, 0x8660}, /* Nibble data + input order */ + + {0x000a, 0x8602}, /* Optical black level set to 0x0a */ +/* 1945 */ {0x0000, 0x8603}, /* Optical black level Offset */ + +/* 1962 * {0, 0x0000, 0x8611}, * 0 R Offset for white Balance */ +/* 1963 * {0, 0x0000, 0x8612}, * 1 Gr Offset for white Balance */ +/* 1964 * {0, 0x0000, 0x8613}, * 1f B Offset for white Balance */ +/* 1965 * {0, 0x0000, 0x8614}, * f0 Gb Offset for white Balance */ + + {0x0040, 0x8651}, /* 2b BLUE gain for white balance good at all 60 */ + {0x0030, 0x8652}, /* 41 Gr Gain for white Balance (L) */ + {0x0035, 0x8653}, /* 26 RED gain for white balance */ + {0x0035, 0x8654}, /* 40Gb Gain for white Balance (L) */ + {0x0041, 0x863f}, + /* Fixed Gamma correction enabled (makes colours look better) */ + +/* 2422 */ {0x0000, 0x8655}, + /* High bits for white balance*****brightness control*** */ + {} +}; + +static const __u16 spca508_sightcam_init_data[][3] = { +/* This line seems to setup the frame/canvas */ + /*368 */ {0x000f, 0x8402}, + +/* Theese 6 lines are needed to startup the webcam */ + /*398 */ {0x0090, 0x8110}, + /*399 */ {0x0001, 0x8114}, + /*400 */ {0x0001, 0x8114}, + /*401 */ {0x0001, 0x8114}, + /*402 */ {0x0003, 0x8114}, + /*403 */ {0x0080, 0x8804}, + +/* This part seems to make the pictures darker? (autobrightness?) */ + /*436 */ {0x0001, 0x8801}, + /*437 */ {0x0004, 0x8800}, + /*439 */ {0x0003, 0x8801}, + /*440 */ {0x00e0, 0x8800}, + /*442 */ {0x0004, 0x8801}, + /*443 */ {0x00b4, 0x8800}, + /*445 */ {0x0005, 0x8801}, + /*446 */ {0x0000, 0x8800}, + + /*448 */ {0x0006, 0x8801}, + /*449 */ {0x00e0, 0x8800}, + /*451 */ {0x0007, 0x8801}, + /*452 */ {0x000c, 0x8800}, + +/* This section is just needed, it probably + * does something like the previous section, + * but the cam won't start if it's not included. + */ + /*484 */ {0x0014, 0x8801}, + /*485 */ {0x0008, 0x8800}, + /*487 */ {0x0015, 0x8801}, + /*488 */ {0x0067, 0x8800}, + /*490 */ {0x0016, 0x8801}, + /*491 */ {0x0000, 0x8800}, + /*493 */ {0x0017, 0x8801}, + /*494 */ {0x0020, 0x8800}, + /*496 */ {0x0018, 0x8801}, + /*497 */ {0x0044, 0x8800}, + +/* Makes the picture darker - and the + * cam won't start if not included + */ + /*505 */ {0x001e, 0x8801}, + /*506 */ {0x00ea, 0x8800}, + /*508 */ {0x001f, 0x8801}, + /*509 */ {0x0001, 0x8800}, + /*511 */ {0x0003, 0x8801}, + /*512 */ {0x00e0, 0x8800}, + +/* seems to place the colors ontop of each other #1 */ + /*517 */ {0x0006, 0x8704}, + /*518 */ {0x0001, 0x870c}, + /*519 */ {0x0016, 0x8600}, + /*520 */ {0x0002, 0x8606}, + +/* if not included the pictures becomes _very_ dark */ + /*521 */ {0x0064, 0x8607}, + /*522 */ {0x003a, 0x8601}, + /*523 */ {0x0000, 0x8602}, + +/* seems to place the colors ontop of each other #2 */ + /*524 */ {0x0016, 0x8600}, + /*525 */ {0x0018, 0x8617}, + /*526 */ {0x0008, 0x8618}, + /*527 */ {0x00a1, 0x8656}, + +/* webcam won't start if not included */ + /*528 */ {0x0007, 0x865b}, + /*529 */ {0x0001, 0x865c}, + /*530 */ {0x0058, 0x865d}, + /*531 */ {0x0048, 0x865e}, + +/* adjusts the colors */ + /*541 */ {0x0049, 0x8651}, + /*542 */ {0x0040, 0x8652}, + /*543 */ {0x004c, 0x8653}, + /*544 */ {0x0040, 0x8654}, + {} +}; + +static const __u16 spca508_sightcam2_init_data[][3] = { +/* 35 */ {0x0020, 0x8112}, + +/* 36 */ {0x000f, 0x8402}, +/* 37 */ {0x0000, 0x8403}, + +/* 38 */ {0x0008, 0x8201}, +/* 39 */ {0x0008, 0x8200}, +/* 40 */ {0x0001, 0x8200}, +/* 43 */ {0x0009, 0x8201}, +/* 44 */ {0x0008, 0x8200}, +/* 45 */ {0x0001, 0x8200}, +/* 48 */ {0x000a, 0x8201}, +/* 49 */ {0x0008, 0x8200}, +/* 50 */ {0x0001, 0x8200}, +/* 53 */ {0x000b, 0x8201}, +/* 54 */ {0x0008, 0x8200}, +/* 55 */ {0x0001, 0x8200}, +/* 58 */ {0x000c, 0x8201}, +/* 59 */ {0x0008, 0x8200}, +/* 60 */ {0x0001, 0x8200}, +/* 63 */ {0x000d, 0x8201}, +/* 64 */ {0x0008, 0x8200}, +/* 65 */ {0x0001, 0x8200}, +/* 68 */ {0x000e, 0x8201}, +/* 69 */ {0x0008, 0x8200}, +/* 70 */ {0x0001, 0x8200}, +/* 73 */ {0x0007, 0x8201}, +/* 74 */ {0x0008, 0x8200}, +/* 75 */ {0x0001, 0x8200}, +/* 78 */ {0x000f, 0x8201}, +/* 79 */ {0x0008, 0x8200}, +/* 80 */ {0x0001, 0x8200}, + +/* 84 */ {0x0018, 0x8660}, +/* 85 */ {0x0010, 0x8201}, + +/* 86 */ {0x0008, 0x8200}, +/* 87 */ {0x0001, 0x8200}, +/* 90 */ {0x0011, 0x8201}, +/* 91 */ {0x0008, 0x8200}, +/* 92 */ {0x0001, 0x8200}, + +/* 95 */ {0x0000, 0x86b0}, +/* 96 */ {0x0034, 0x86b1}, +/* 97 */ {0x0000, 0x86b2}, +/* 98 */ {0x0049, 0x86b3}, +/* 99 */ {0x0000, 0x86b4}, +/* 100 */ {0x0000, 0x86b4}, + +/* 101 */ {0x0012, 0x8201}, +/* 102 */ {0x0008, 0x8200}, +/* 103 */ {0x0001, 0x8200}, +/* 106 */ {0x0013, 0x8201}, +/* 107 */ {0x0008, 0x8200}, +/* 108 */ {0x0001, 0x8200}, + +/* 111 */ {0x0001, 0x86b0}, +/* 112 */ {0x00aa, 0x86b1}, +/* 113 */ {0x0000, 0x86b2}, +/* 114 */ {0x00e4, 0x86b3}, +/* 115 */ {0x0000, 0x86b4}, +/* 116 */ {0x0000, 0x86b4}, + +/* 118 */ {0x0018, 0x8660}, + +/* 119 */ {0x0090, 0x8110}, +/* 120 */ {0x0001, 0x8114}, +/* 121 */ {0x0001, 0x8114}, +/* 122 */ {0x0001, 0x8114}, +/* 123 */ {0x0003, 0x8114}, + +/* 124 */ {0x0080, 0x8804}, +/* 157 */ {0x0003, 0x8801}, +/* 158 */ {0x0012, 0x8800}, +/* 160 */ {0x0004, 0x8801}, +/* 161 */ {0x0005, 0x8800}, +/* 163 */ {0x0005, 0x8801}, +/* 164 */ {0x0000, 0x8800}, +/* 166 */ {0x0006, 0x8801}, +/* 167 */ {0x0000, 0x8800}, +/* 169 */ {0x0007, 0x8801}, +/* 170 */ {0x0000, 0x8800}, +/* 172 */ {0x0008, 0x8801}, +/* 173 */ {0x0005, 0x8800}, +/* 175 */ {0x000a, 0x8700}, +/* 176 */ {0x000e, 0x8801}, +/* 177 */ {0x0004, 0x8800}, +/* 179 */ {0x0005, 0x8801}, +/* 180 */ {0x0047, 0x8800}, +/* 182 */ {0x0006, 0x8801}, +/* 183 */ {0x0000, 0x8800}, +/* 185 */ {0x0007, 0x8801}, +/* 186 */ {0x00c0, 0x8800}, +/* 188 */ {0x0008, 0x8801}, +/* 189 */ {0x0003, 0x8800}, +/* 191 */ {0x0013, 0x8801}, +/* 192 */ {0x0001, 0x8800}, +/* 194 */ {0x0009, 0x8801}, +/* 195 */ {0x0000, 0x8800}, +/* 197 */ {0x000a, 0x8801}, +/* 198 */ {0x0000, 0x8800}, +/* 200 */ {0x000b, 0x8801}, +/* 201 */ {0x0000, 0x8800}, +/* 203 */ {0x000c, 0x8801}, +/* 204 */ {0x0000, 0x8800}, +/* 206 */ {0x000e, 0x8801}, +/* 207 */ {0x0004, 0x8800}, +/* 209 */ {0x000f, 0x8801}, +/* 210 */ {0x0000, 0x8800}, +/* 212 */ {0x0010, 0x8801}, +/* 213 */ {0x0006, 0x8800}, +/* 215 */ {0x0011, 0x8801}, +/* 216 */ {0x0006, 0x8800}, +/* 218 */ {0x0012, 0x8801}, +/* 219 */ {0x0000, 0x8800}, +/* 221 */ {0x0013, 0x8801}, +/* 222 */ {0x0001, 0x8800}, + +/* 224 */ {0x000a, 0x8700}, +/* 225 */ {0x0000, 0x8702}, +/* 226 */ {0x0000, 0x8703}, +/* 227 */ {0x00c2, 0x8704}, +/* 228 */ {0x0001, 0x870c}, + +/* 229 */ {0x0044, 0x8600}, +/* 230 */ {0x0002, 0x8606}, +/* 231 */ {0x0064, 0x8607}, +/* 232 */ {0x003a, 0x8601}, +/* 233 */ {0x0008, 0x8602}, +/* 234 */ {0x0044, 0x8600}, +/* 235 */ {0x0018, 0x8617}, +/* 236 */ {0x0008, 0x8618}, +/* 237 */ {0x00a1, 0x8656}, +/* 238 */ {0x0004, 0x865b}, +/* 239 */ {0x0002, 0x865c}, +/* 240 */ {0x0058, 0x865d}, +/* 241 */ {0x0048, 0x865e}, +/* 242 */ {0x0012, 0x8608}, +/* 243 */ {0x002c, 0x8609}, +/* 244 */ {0x0002, 0x860a}, +/* 245 */ {0x002c, 0x860b}, +/* 246 */ {0x00db, 0x860c}, +/* 247 */ {0x00f9, 0x860d}, +/* 248 */ {0x00f1, 0x860e}, +/* 249 */ {0x00e3, 0x860f}, +/* 250 */ {0x002c, 0x8610}, +/* 251 */ {0x006c, 0x8651}, +/* 252 */ {0x0041, 0x8652}, +/* 253 */ {0x0059, 0x8653}, +/* 254 */ {0x0040, 0x8654}, +/* 255 */ {0x00fa, 0x8611}, +/* 256 */ {0x00ff, 0x8612}, +/* 257 */ {0x00f8, 0x8613}, +/* 258 */ {0x0000, 0x8614}, +/* 259 */ {0x0001, 0x863f}, +/* 260 */ {0x0000, 0x8640}, +/* 261 */ {0x0026, 0x8641}, +/* 262 */ {0x0045, 0x8642}, +/* 263 */ {0x0060, 0x8643}, +/* 264 */ {0x0075, 0x8644}, +/* 265 */ {0x0088, 0x8645}, +/* 266 */ {0x009b, 0x8646}, +/* 267 */ {0x00b0, 0x8647}, +/* 268 */ {0x00c5, 0x8648}, +/* 269 */ {0x00d2, 0x8649}, +/* 270 */ {0x00dc, 0x864a}, +/* 271 */ {0x00e5, 0x864b}, +/* 272 */ {0x00eb, 0x864c}, +/* 273 */ {0x00f0, 0x864d}, +/* 274 */ {0x00f6, 0x864e}, +/* 275 */ {0x00fa, 0x864f}, +/* 276 */ {0x00ff, 0x8650}, +/* 277 */ {0x0060, 0x8657}, +/* 278 */ {0x0010, 0x8658}, +/* 279 */ {0x0018, 0x8659}, +/* 280 */ {0x0005, 0x865a}, +/* 281 */ {0x0018, 0x8660}, +/* 282 */ {0x0003, 0x8509}, +/* 283 */ {0x0011, 0x850a}, +/* 284 */ {0x0032, 0x850b}, +/* 285 */ {0x0010, 0x850c}, +/* 286 */ {0x0021, 0x850d}, +/* 287 */ {0x0001, 0x8500}, +/* 288 */ {0x0000, 0x8508}, +/* 289 */ {0x0012, 0x8608}, +/* 290 */ {0x002c, 0x8609}, +/* 291 */ {0x0002, 0x860a}, +/* 292 */ {0x0039, 0x860b}, +/* 293 */ {0x00d0, 0x860c}, +/* 294 */ {0x00f7, 0x860d}, +/* 295 */ {0x00ed, 0x860e}, +/* 296 */ {0x00db, 0x860f}, +/* 297 */ {0x0039, 0x8610}, +/* 298 */ {0x0012, 0x8657}, +/* 299 */ {0x000c, 0x8619}, +/* 300 */ {0x0004, 0x861a}, +/* 301 */ {0x00a1, 0x8656}, +/* 302 */ {0x00c8, 0x8615}, +/* 303 */ {0x0032, 0x8616}, + +/* 306 */ {0x0030, 0x8112}, +/* 313 */ {0x0020, 0x8112}, +/* 314 */ {0x0020, 0x8112}, +/* 315 */ {0x000f, 0x8402}, +/* 316 */ {0x0000, 0x8403}, + +/* 317 */ {0x0090, 0x8110}, +/* 318 */ {0x0001, 0x8114}, +/* 319 */ {0x0001, 0x8114}, +/* 320 */ {0x0001, 0x8114}, +/* 321 */ {0x0003, 0x8114}, +/* 322 */ {0x0080, 0x8804}, + +/* 355 */ {0x0003, 0x8801}, +/* 356 */ {0x0012, 0x8800}, +/* 358 */ {0x0004, 0x8801}, +/* 359 */ {0x0005, 0x8800}, +/* 361 */ {0x0005, 0x8801}, +/* 362 */ {0x0047, 0x8800}, +/* 364 */ {0x0006, 0x8801}, +/* 365 */ {0x0000, 0x8800}, +/* 367 */ {0x0007, 0x8801}, +/* 368 */ {0x00c0, 0x8800}, +/* 370 */ {0x0008, 0x8801}, +/* 371 */ {0x0003, 0x8800}, +/* 373 */ {0x000a, 0x8700}, +/* 374 */ {0x000e, 0x8801}, +/* 375 */ {0x0004, 0x8800}, +/* 377 */ {0x0005, 0x8801}, +/* 378 */ {0x0047, 0x8800}, +/* 380 */ {0x0006, 0x8801}, +/* 381 */ {0x0000, 0x8800}, +/* 383 */ {0x0007, 0x8801}, +/* 384 */ {0x00c0, 0x8800}, +/* 386 */ {0x0008, 0x8801}, +/* 387 */ {0x0003, 0x8800}, +/* 389 */ {0x0013, 0x8801}, +/* 390 */ {0x0001, 0x8800}, +/* 392 */ {0x0009, 0x8801}, +/* 393 */ {0x0000, 0x8800}, +/* 395 */ {0x000a, 0x8801}, +/* 396 */ {0x0000, 0x8800}, +/* 398 */ {0x000b, 0x8801}, +/* 399 */ {0x0000, 0x8800}, +/* 401 */ {0x000c, 0x8801}, +/* 402 */ {0x0000, 0x8800}, +/* 404 */ {0x000e, 0x8801}, +/* 405 */ {0x0004, 0x8800}, +/* 407 */ {0x000f, 0x8801}, +/* 408 */ {0x0000, 0x8800}, +/* 410 */ {0x0010, 0x8801}, +/* 411 */ {0x0006, 0x8800}, +/* 413 */ {0x0011, 0x8801}, +/* 414 */ {0x0006, 0x8800}, +/* 416 */ {0x0012, 0x8801}, +/* 417 */ {0x0000, 0x8800}, +/* 419 */ {0x0013, 0x8801}, +/* 420 */ {0x0001, 0x8800}, +/* 422 */ {0x000a, 0x8700}, +/* 423 */ {0x0000, 0x8702}, +/* 424 */ {0x0000, 0x8703}, +/* 425 */ {0x00c2, 0x8704}, +/* 426 */ {0x0001, 0x870c}, +/* 427 */ {0x0044, 0x8600}, +/* 428 */ {0x0002, 0x8606}, +/* 429 */ {0x0064, 0x8607}, +/* 430 */ {0x003a, 0x8601}, +/* 431 */ {0x0008, 0x8602}, +/* 432 */ {0x0044, 0x8600}, +/* 433 */ {0x0018, 0x8617}, +/* 434 */ {0x0008, 0x8618}, +/* 435 */ {0x00a1, 0x8656}, +/* 436 */ {0x0004, 0x865b}, +/* 437 */ {0x0002, 0x865c}, +/* 438 */ {0x0058, 0x865d}, +/* 439 */ {0x0048, 0x865e}, +/* 440 */ {0x0012, 0x8608}, +/* 441 */ {0x002c, 0x8609}, +/* 442 */ {0x0002, 0x860a}, +/* 443 */ {0x002c, 0x860b}, +/* 444 */ {0x00db, 0x860c}, +/* 445 */ {0x00f9, 0x860d}, +/* 446 */ {0x00f1, 0x860e}, +/* 447 */ {0x00e3, 0x860f}, +/* 448 */ {0x002c, 0x8610}, +/* 449 */ {0x006c, 0x8651}, +/* 450 */ {0x0041, 0x8652}, +/* 451 */ {0x0059, 0x8653}, +/* 452 */ {0x0040, 0x8654}, +/* 453 */ {0x00fa, 0x8611}, +/* 454 */ {0x00ff, 0x8612}, +/* 455 */ {0x00f8, 0x8613}, +/* 456 */ {0x0000, 0x8614}, +/* 457 */ {0x0001, 0x863f}, +/* 458 */ {0x0000, 0x8640}, +/* 459 */ {0x0026, 0x8641}, +/* 460 */ {0x0045, 0x8642}, +/* 461 */ {0x0060, 0x8643}, +/* 462 */ {0x0075, 0x8644}, +/* 463 */ {0x0088, 0x8645}, +/* 464 */ {0x009b, 0x8646}, +/* 465 */ {0x00b0, 0x8647}, +/* 466 */ {0x00c5, 0x8648}, +/* 467 */ {0x00d2, 0x8649}, +/* 468 */ {0x00dc, 0x864a}, +/* 469 */ {0x00e5, 0x864b}, +/* 470 */ {0x00eb, 0x864c}, +/* 471 */ {0x00f0, 0x864d}, +/* 472 */ {0x00f6, 0x864e}, +/* 473 */ {0x00fa, 0x864f}, +/* 474 */ {0x00ff, 0x8650}, +/* 475 */ {0x0060, 0x8657}, +/* 476 */ {0x0010, 0x8658}, +/* 477 */ {0x0018, 0x8659}, +/* 478 */ {0x0005, 0x865a}, +/* 479 */ {0x0018, 0x8660}, +/* 480 */ {0x0003, 0x8509}, +/* 481 */ {0x0011, 0x850a}, +/* 482 */ {0x0032, 0x850b}, +/* 483 */ {0x0010, 0x850c}, +/* 484 */ {0x0021, 0x850d}, +/* 485 */ {0x0001, 0x8500}, +/* 486 */ {0x0000, 0x8508}, + +/* 487 */ {0x0012, 0x8608}, +/* 488 */ {0x002c, 0x8609}, +/* 489 */ {0x0002, 0x860a}, +/* 490 */ {0x0039, 0x860b}, +/* 491 */ {0x00d0, 0x860c}, +/* 492 */ {0x00f7, 0x860d}, +/* 493 */ {0x00ed, 0x860e}, +/* 494 */ {0x00db, 0x860f}, +/* 495 */ {0x0039, 0x8610}, +/* 496 */ {0x0012, 0x8657}, +/* 497 */ {0x0064, 0x8619}, + +/* This line starts it all, it is not needed here */ +/* since it has been build into the driver */ +/* jfm: don't start now */ +/* 590 * {0x0030, 0x8112}, */ + {} +}; + +/* + * Initialization data for Creative Webcam Vista + */ +static const __u16 spca508_vista_init_data[][3] = { + {0x0008, 0x8200}, /* Clear register */ + {0x0000, 0x870b}, /* Reset CTL3 */ + {0x0020, 0x8112}, /* Video Drop packet enable */ + {0x0003, 0x8111}, /* Soft Reset compression, memory, TG & CDSP */ + {0x0000, 0x8110}, /* Disable everything */ + {0x0000, 0x8114}, /* Software GPIO output data */ + {0x0000, 0x8114}, + + {0x0003, 0x8111}, + {0x0000, 0x8111}, + {0x0090, 0x8110}, /* Enable: SSI output, External 2X clock output */ + {0x0020, 0x8112}, + {0x0000, 0x8114}, + {0x0001, 0x8114}, + {0x0001, 0x8114}, + {0x0001, 0x8114}, + {0x0003, 0x8114}, + + {0x000f, 0x8402}, /* Memory bank Address */ + {0x0000, 0x8403}, /* Memory bank Address */ + {0x00ba, 0x8804}, /* SSI Slave address */ + {0x0010, 0x8802}, /* 93.75kHz SSI Clock Two DataByte */ + + /* READ { 0, 0x0001, 0x8803 } -> + 0000: 00 */ + /* READ { 0, 0x0001, 0x8802 } -> + 0000: 10 */ + {0x0010, 0x8802}, /* Will write 2 bytes (DATA1+DATA2) */ + {0x0020, 0x8801}, /* Register address for SSI read/write */ + {0x0044, 0x8805}, /* DATA2 */ + {0x0004, 0x8800}, /* DATA1 -> write triggered */ + /* READ { 0, 0x0001, 0x8803 } -> + 0000: 00 */ + + /* READ { 0, 0x0001, 0x8803 } -> + 0000: 00 */ + /* READ { 0, 0x0001, 0x8802 } -> + 0000: 10 */ + {0x0010, 0x8802}, + {0x0009, 0x8801}, + {0x0042, 0x8805}, + {0x0001, 0x8800}, + /* READ { 0, 0x0001, 0x8803 } -> + 0000: 00 */ + + /* READ { 0, 0x0001, 0x8803 } -> + 0000: 00 */ + /* READ { 0, 0x0001, 0x8802 } -> + 0000: 10 */ + {0x0010, 0x8802}, + {0x003c, 0x8801}, + {0x0001, 0x8805}, + {0x0000, 0x8800}, + /* READ { 0, 0x0001, 0x8803 } -> + 0000: 00 */ + + /* READ { 0, 0x0001, 0x8803 } -> + 0000: 00 */ + /* READ { 0, 0x0001, 0x8802 } -> + 0000: 10 */ + {0x0010, 0x8802}, + {0x0001, 0x8801}, + {0x000a, 0x8805}, + {0x0000, 0x8800}, + /* READ { 0, 0x0001, 0x8803 } -> + 0000: 00 */ + + /* READ { 0, 0x0001, 0x8803 } -> + 0000: 00 */ + /* READ { 0, 0x0001, 0x8802 } -> + 0000: 10 */ + {0x0010, 0x8802}, + {0x0002, 0x8801}, + {0x0000, 0x8805}, + {0x0000, 0x8800}, + /* READ { 0, 0x0001, 0x8803 } -> + 0000: 00 */ + + /* READ { 0, 0x0001, 0x8803 } -> + 0000: 00 */ + /* READ { 0, 0x0001, 0x8802 } -> + 0000: 10 */ + {0x0010, 0x8802}, + {0x0003, 0x8801}, + {0x0027, 0x8805}, + {0x0001, 0x8800}, + /* READ { 0, 0x0001, 0x8803 } -> + 0000: 00 */ + + /* READ { 0, 0x0001, 0x8803 } -> + 0000: 00 */ + /* READ { 0, 0x0001, 0x8802 } -> + 0000: 10 */ + {0x0010, 0x8802}, + {0x0004, 0x8801}, + {0x0065, 0x8805}, + {0x0001, 0x8800}, + /* READ { 0, 0x0001, 0x8803 } -> + 0000: 00 */ + + /* READ { 0, 0x0001, 0x8803 } -> + 0000: 00 */ + /* READ { 0, 0x0001, 0x8802 } -> + 0000: 10 */ + {0x0010, 0x8802}, + {0x0005, 0x8801}, + {0x0003, 0x8805}, + {0x0000, 0x8800}, + /* READ { 0, 0x0001, 0x8803 } -> + 0000: 00 */ + + /* READ { 0, 0x0001, 0x8803 } -> + 0000: 00 */ + /* READ { 0, 0x0001, 0x8802 } -> + 0000: 10 */ + {0x0010, 0x8802}, + {0x0006, 0x8801}, + {0x001c, 0x8805}, + {0x0000, 0x8800}, + /* READ { 0, 0x0001, 0x8803 } -> + 0000: 00 */ + + /* READ { 0, 0x0001, 0x8803 } -> + 0000: 00 */ + /* READ { 0, 0x0001, 0x8802 } -> + 0000: 10 */ + {0x0010, 0x8802}, + {0x0007, 0x8801}, + {0x002a, 0x8805}, + {0x0000, 0x8800}, + /* READ { 0, 0x0001, 0x8803 } -> + 0000: 00 */ + + /* READ { 0, 0x0001, 0x8803 } -> + 0000: 00 */ + /* READ { 0, 0x0001, 0x8802 } -> + 0000: 10 */ + {0x0010, 0x8802}, + {0x000e, 0x8801}, + {0x0000, 0x8805}, + {0x0000, 0x8800}, + /* READ { 0, 0x0001, 0x8803 } -> + 0000: 00 */ + + /* READ { 0, 0x0001, 0x8803 } -> + 0000: 00 */ + /* READ { 0, 0x0001, 0x8802 } -> + 0000: 10 */ + {0x0010, 0x8802}, + {0x0028, 0x8801}, + {0x002e, 0x8805}, + {0x0000, 0x8800}, + /* READ { 0, 0x0001, 0x8803 } -> + 0000: 00 */ + + /* READ { 0, 0x0001, 0x8803 } -> + 0000: 00 */ + /* READ { 0, 0x0001, 0x8802 } -> + 0000: 10 */ + {0x0010, 0x8802}, + {0x0039, 0x8801}, + {0x0013, 0x8805}, + {0x0000, 0x8800}, + /* READ { 0, 0x0001, 0x8803 } -> + 0000: 00 */ + + /* READ { 0, 0x0001, 0x8803 } -> + 0000: 00 */ + /* READ { 0, 0x0001, 0x8802 } -> + 0000: 10 */ + {0x0010, 0x8802}, + {0x003b, 0x8801}, + {0x000c, 0x8805}, + {0x0000, 0x8800}, + /* READ { 0, 0x0001, 0x8803 } -> + 0000: 00 */ + + /* READ { 0, 0x0001, 0x8803 } -> + 0000: 00 */ + /* READ { 0, 0x0001, 0x8802 } -> + 0000: 10 */ + {0x0010, 0x8802}, + {0x0035, 0x8801}, + {0x0028, 0x8805}, + {0x0000, 0x8800}, + /* READ { 0, 0x0001, 0x8803 } -> + 0000: 00 */ + + /* READ { 0, 0x0001, 0x8803 } -> + 0000: 00 */ + /* READ { 0, 0x0001, 0x8802 } -> + 0000: 10 */ + {0x0010, 0x8802}, + {0x0009, 0x8801}, + {0x0042, 0x8805}, + {0x0001, 0x8800}, + /* READ { 0, 0x0001, 0x8803 } -> + 0000: 00 */ + + {0x0050, 0x8703}, + {0x0002, 0x8704}, /* External input CKIx1 */ + {0x0001, 0x870C}, /* Select CKOx2 output */ + {0x009A, 0x8600}, /* Line memory Read Counter (L) */ + {0x0001, 0x8606}, /* 1 Line memory Read Counter (H) Result: (d)410 */ + {0x0023, 0x8601}, + {0x0010, 0x8602}, + {0x000A, 0x8603}, + {0x009A, 0x8600}, + {0x0001, 0x865B}, /* 1 Horizontal Offset for Valid Pixel(L) */ + {0x0003, 0x865C}, /* Vertical offset for valid lines (L) */ + {0x0058, 0x865D}, /* Horizontal valid pixels window (L) */ + {0x0048, 0x865E}, /* Vertical valid lines window (L) */ + {0x0000, 0x865F}, + + {0x0006, 0x8660}, + /* Enable nibble data input, select nibble input order */ + + {0x0013, 0x8608}, /* A11 Coeficients for color correction */ + {0x0028, 0x8609}, + /* Note: these values are confirmed at the end of array */ + {0x0005, 0x860A}, /* ... */ + {0x0025, 0x860B}, + {0x00E1, 0x860C}, + {0x00FA, 0x860D}, + {0x00F4, 0x860E}, + {0x00E8, 0x860F}, + {0x0025, 0x8610}, /* A33 Coef. */ + {0x00FC, 0x8611}, /* White balance offset: R */ + {0x0001, 0x8612}, /* White balance offset: Gr */ + {0x00FE, 0x8613}, /* White balance offset: B */ + {0x0000, 0x8614}, /* White balance offset: Gb */ + + {0x0064, 0x8651}, /* R gain for white balance (L) */ + {0x0040, 0x8652}, /* Gr gain for white balance (L) */ + {0x0066, 0x8653}, /* B gain for white balance (L) */ + {0x0040, 0x8654}, /* Gb gain for white balance (L) */ + {0x0001, 0x863F}, /* Enable fixed gamma correction */ + + {0x00A1, 0x8656}, /* Size - Window1: 256x256, Window2: 128x128 */ + /* UV division: UV no change, Enable New edge enhancement */ + {0x0018, 0x8657}, /* Edge gain high threshold */ + {0x0020, 0x8658}, /* Edge gain low threshold */ + {0x000A, 0x8659}, /* Edge bandwidth high threshold */ + {0x0005, 0x865A}, /* Edge bandwidth low threshold */ + {0x0064, 0x8607}, /* UV filter enable */ + + {0x0016, 0x8660}, + {0x0000, 0x86B0}, /* Bad pixels compensation address */ + {0x00DC, 0x86B1}, /* X coord for bad pixels compensation (L) */ + {0x0000, 0x86B2}, + {0x0009, 0x86B3}, /* Y coord for bad pixels compensation (L) */ + {0x0000, 0x86B4}, + + {0x0001, 0x86B0}, + {0x00F5, 0x86B1}, + {0x0000, 0x86B2}, + {0x00C6, 0x86B3}, + {0x0000, 0x86B4}, + + {0x0002, 0x86B0}, + {0x001C, 0x86B1}, + {0x0001, 0x86B2}, + {0x00D7, 0x86B3}, + {0x0000, 0x86B4}, + + {0x0003, 0x86B0}, + {0x001C, 0x86B1}, + {0x0001, 0x86B2}, + {0x00D8, 0x86B3}, + {0x0000, 0x86B4}, + + {0x0004, 0x86B0}, + {0x001D, 0x86B1}, + {0x0001, 0x86B2}, + {0x00D8, 0x86B3}, + {0x0000, 0x86B4}, + {0x001E, 0x8660}, + + /* READ { 0, 0x0000, 0x8608 } -> + 0000: 13 */ + /* READ { 0, 0x0000, 0x8609 } -> + 0000: 28 */ + /* READ { 0, 0x0000, 0x8610 } -> + 0000: 05 */ + /* READ { 0, 0x0000, 0x8611 } -> + 0000: 25 */ + /* READ { 0, 0x0000, 0x8612 } -> + 0000: e1 */ + /* READ { 0, 0x0000, 0x8613 } -> + 0000: fa */ + /* READ { 0, 0x0000, 0x8614 } -> + 0000: f4 */ + /* READ { 0, 0x0000, 0x8615 } -> + 0000: e8 */ + /* READ { 0, 0x0000, 0x8616 } -> + 0000: 25 */ + {} +}; + +static int reg_write(struct usb_device *dev, + __u16 index, __u16 value) +{ + int ret; + + ret = usb_control_msg(dev, + usb_sndctrlpipe(dev, 0), + 0, /* request */ + USB_TYPE_VENDOR | USB_RECIP_DEVICE, + value, index, NULL, 0, 500); + PDEBUG(D_USBO, "reg write i:0x%04x = 0x%02x", + index, value); + if (ret < 0) + PDEBUG(D_ERR|D_USBO, "reg write: error %d", ret); + return ret; +} + +/* read 1 byte */ +/* returns: negative is error, pos or zero is data */ +static int reg_read(struct gspca_dev *gspca_dev, + __u16 index) /* wIndex */ +{ + int ret; + + ret = usb_control_msg(gspca_dev->dev, + usb_rcvctrlpipe(gspca_dev->dev, 0), + 0, /* register */ + USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + 0, /* value */ + index, + gspca_dev->usb_buf, 1, + 500); /* timeout */ + PDEBUG(D_USBI, "reg read i:%04x --> %02x", + index, gspca_dev->usb_buf[0]); + if (ret < 0) { + PDEBUG(D_ERR|D_USBI, "reg_read err %d", ret); + return ret; + } + return gspca_dev->usb_buf[0]; +} + +static int write_vector(struct gspca_dev *gspca_dev, + const __u16 data[][3]) +{ + struct usb_device *dev = gspca_dev->dev; + int ret, i = 0; + + while (data[i][1] != 0) { + ret = reg_write(dev, data[i][1], data[i][0]); + if (ret < 0) + return ret; + i++; + } + return 0; +} + +/* this function is called at probe time */ +static int sd_config(struct gspca_dev *gspca_dev, + const struct usb_device_id *id) +{ + struct sd *sd = (struct sd *) gspca_dev; + struct cam *cam; + __u16 product; + int data1, data2; + + product = id->idProduct; + switch (id->idVendor) { + case 0x0130: /* Clone webcam */ +/* switch (product) { */ +/* case 0x0130: */ + sd->subtype = HamaUSBSightcam; /* same as Hama 0010 */ +/* break; */ +/* } */ + break; + case 0x041e: /* Creative cameras */ +/* switch (product) { */ +/* case 0x4018: */ + sd->subtype = CreativeVista; +/* break; */ +/* } */ + break; + case 0x0461: /* MicroInnovation */ +/* switch (product) { */ +/* case 0x0815: */ + sd->subtype = MicroInnovationIC200; +/* break; */ +/* } */ + break; + case 0x0733: /* Rebadged ViewQuest (Intel) and ViewQuest cameras */ +/* switch (product) { */ +/* case 0x110: */ + sd->subtype = ViewQuestVQ110; +/* break; */ +/* } */ + break; + case 0x0af9: /* Hama cameras */ + switch (product) { + case 0x0010: + sd->subtype = HamaUSBSightcam; + break; + case 0x0011: + sd->subtype = HamaUSBSightcam2; + break; + } + break; + case 0x8086: /* Intel */ +/* switch (product) { */ +/* case 0x0110: */ + sd->subtype = IntelEasyPCCamera; +/* break; */ +/* } */ + break; + } + + /* Read from global register the USB product and vendor IDs, just to + * prove that we can communicate with the device. This works, which + * confirms at we are communicating properly and that the device + * is a 508. */ + data1 = reg_read(gspca_dev, 0x8104); + data2 = reg_read(gspca_dev, 0x8105); + PDEBUG(D_PROBE, "Webcam Vendor ID: 0x%02x%02x", data2, data1); + + data1 = reg_read(gspca_dev, 0x8106); + data2 = reg_read(gspca_dev, 0x8107); + PDEBUG(D_PROBE, "Webcam Product ID: 0x%02x%02x", data2, data1); + + data1 = reg_read(gspca_dev, 0x8621); + PDEBUG(D_PROBE, "Window 1 average luminance: %d", data1); + + cam = &gspca_dev->cam; + cam->dev_name = (char *) id->driver_info; + cam->epaddr = 0x01; + cam->cam_mode = sif_mode; + cam->nmodes = ARRAY_SIZE(sif_mode); + sd->brightness = BRIGHTNESS_DEF; + + switch (sd->subtype) { + case ViewQuestVQ110: + if (write_vector(gspca_dev, spca508_init_data)) + return -1; + break; + default: +/* case MicroInnovationIC200: */ +/* case IntelEasyPCCamera: */ + if (write_vector(gspca_dev, spca508cs110_init_data)) + return -1; + break; + case HamaUSBSightcam: + if (write_vector(gspca_dev, spca508_sightcam_init_data)) + return -1; + break; + case HamaUSBSightcam2: + if (write_vector(gspca_dev, spca508_sightcam2_init_data)) + return -1; + break; + case CreativeVista: + if (write_vector(gspca_dev, spca508_vista_init_data)) + return -1; + break; + } + return 0; /* success */ +} + +/* this function is called at open time */ +static int sd_open(struct gspca_dev *gspca_dev) +{ +/* write_vector(gspca_dev, spca508_open_data); */ + return 0; +} + +static void sd_start(struct gspca_dev *gspca_dev) +{ + int mode; + + mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv; + reg_write(gspca_dev->dev, 0x8500, mode); + switch (mode) { + case 0: + case 1: + reg_write(gspca_dev->dev, 0x8700, 0x28); /* clock */ + break; + default: +/* case 2: */ +/* case 3: */ + reg_write(gspca_dev->dev, 0x8700, 0x23); /* clock */ + break; + } + reg_write(gspca_dev->dev, 0x8112, 0x10 | 0x20); +} + +static void sd_stopN(struct gspca_dev *gspca_dev) +{ + /* Video ISO disable, Video Drop Packet enable: */ + reg_write(gspca_dev->dev, 0x8112, 0x20); +} + +static void sd_stop0(struct gspca_dev *gspca_dev) +{ +} + +/* this function is called at close time */ +static void sd_close(struct gspca_dev *gspca_dev) +{ +} + +/* convert YUVY per line to YUYV (YUV 4:2:2) */ +static void yuvy_decode(unsigned char *out, + unsigned char *in, + int width, + int height) +{ + unsigned char *Ui, *Vi, *yi, *yi1; + unsigned char *out1; + int i, j; + + yi = in; + for (i = height / 2; --i >= 0; ) { + out1 = out + width * 2; /* next line */ + Ui = yi + width; + Vi = Ui + width / 2; + yi1 = Vi + width / 2; + for (j = width / 2; --j >= 0; ) { + *out++ = 128 + *yi++; + *out++ = 128 + *Ui; + *out++ = 128 + *yi++; + *out++ = 128 + *Vi; + + *out1++ = 128 + *yi1++; + *out1++ = 128 + *Ui++; + *out1++ = 128 + *yi1++; + *out1++ = 128 + *Vi++; + } + yi += width * 2; + out = out1; + } +} + +static void sd_pkt_scan(struct gspca_dev *gspca_dev, + struct gspca_frame *frame, /* target */ + __u8 *data, /* isoc packet */ + int len) /* iso packet length */ +{ + struct sd *sd = (struct sd *) gspca_dev; + + switch (data[0]) { + case 0: /* start of frame */ + if (gspca_dev->last_packet_type == FIRST_PACKET) { + yuvy_decode(sd->tmpbuf2, sd->tmpbuf, + gspca_dev->width, + gspca_dev->height); + frame = gspca_frame_add(gspca_dev, + LAST_PACKET, + frame, + sd->tmpbuf2, + gspca_dev->width + * gspca_dev->height + * 2); + } + gspca_frame_add(gspca_dev, FIRST_PACKET, frame, + data, 0); + data += SPCA508_OFFSET_DATA; + len -= SPCA508_OFFSET_DATA; + if (len > 0) + memcpy(sd->tmpbuf, data, len); + else + len = 0; + sd->buflen = len; + return; + case 0xff: /* drop */ +/* gspca_dev->last_packet_type = DISCARD_PACKET; */ + return; + } + data += 1; + len -= 1; + memcpy(&sd->tmpbuf[sd->buflen], data, len); + sd->buflen += len; +} + +static void setbrightness(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + __u8 brightness = sd->brightness; + + /* MX seem contrast */ + reg_write(gspca_dev->dev, 0x8651, brightness); + reg_write(gspca_dev->dev, 0x8652, brightness); + reg_write(gspca_dev->dev, 0x8653, brightness); + reg_write(gspca_dev->dev, 0x8654, brightness); +} + +static void getbrightness(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->brightness = reg_read(gspca_dev, 0x8651); +} + +static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->brightness = val; + if (gspca_dev->streaming) + setbrightness(gspca_dev); + return 0; +} + +static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + getbrightness(gspca_dev); + *val = sd->brightness; + return 0; +} + +/* sub-driver description */ +static const struct sd_desc sd_desc = { + .name = MODULE_NAME, + .ctrls = sd_ctrls, + .nctrls = ARRAY_SIZE(sd_ctrls), + .config = sd_config, + .open = sd_open, + .start = sd_start, + .stopN = sd_stopN, + .stop0 = sd_stop0, + .close = sd_close, + .pkt_scan = sd_pkt_scan, +}; + +/* -- module initialisation -- */ +#define DVNM(name) .driver_info = (kernel_ulong_t) name +static const __devinitdata struct usb_device_id device_table[] = { + {USB_DEVICE(0x0130, 0x0130), DVNM("Clone Digital Webcam 11043")}, + {USB_DEVICE(0x041e, 0x4018), DVNM("Creative Webcam Vista (PD1100)")}, + {USB_DEVICE(0x0461, 0x0815), DVNM("Micro Innovation IC200")}, + {USB_DEVICE(0x0733, 0x0110), DVNM("ViewQuest VQ110")}, + {USB_DEVICE(0x0af9, 0x0010), DVNM("Hama USB Sightcam 100")}, + {USB_DEVICE(0x0af9, 0x0011), DVNM("Hama USB Sightcam 100")}, + {USB_DEVICE(0x8086, 0x0110), DVNM("Intel Easy PC Camera")}, + {} +}; +MODULE_DEVICE_TABLE(usb, device_table); + +/* -- device connect -- */ +static int sd_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd), + THIS_MODULE); +} + +static struct usb_driver sd_driver = { + .name = MODULE_NAME, + .id_table = device_table, + .probe = sd_probe, + .disconnect = gspca_disconnect, +}; + +/* -- module insert / remove -- */ +static int __init sd_mod_init(void) +{ + if (usb_register(&sd_driver) < 0) + return -1; + PDEBUG(D_PROBE, "v%s registered", version); + return 0; +} +static void __exit sd_mod_exit(void) +{ + usb_deregister(&sd_driver); + PDEBUG(D_PROBE, "deregistered"); +} + +module_init(sd_mod_init); +module_exit(sd_mod_exit); diff --git a/drivers/media/video/gspca/spca561.c b/drivers/media/video/gspca/spca561.c new file mode 100644 index 000000000000..b659bd0f788d --- /dev/null +++ b/drivers/media/video/gspca/spca561.c @@ -0,0 +1,1052 @@ +/* + * Sunplus spca561 subdriver + * + * Copyright (C) 2004 Michel Xhaard mxhaard@magic.fr + * + * V4L2 by Jean-Francois Moine <http://moinejf.free.fr> + * + * 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 + * 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 + */ + +#define MODULE_NAME "spca561" + +#include "gspca.h" + +#define DRIVER_VERSION_NUMBER KERNEL_VERSION(2, 1, 7) +static const char version[] = "2.1.7"; + +MODULE_AUTHOR("Michel Xhaard <mxhaard@users.sourceforge.net>"); +MODULE_DESCRIPTION("GSPCA/SPCA561 USB Camera Driver"); +MODULE_LICENSE("GPL"); + +/* specific webcam descriptor */ +struct sd { + struct gspca_dev gspca_dev; /* !! must be the first item */ + + unsigned short contrast; + __u8 brightness; + __u8 autogain; + + __u8 chip_revision; + signed char ag_cnt; +#define AG_CNT_START 13 +}; + +/* V4L2 controls supported by the driver */ +static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val); +static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val); +static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val); +static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val); +static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val); +static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val); + +static struct ctrl sd_ctrls[] = { +#define SD_BRIGHTNESS 0 + { + { + .id = V4L2_CID_BRIGHTNESS, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Brightness", + .minimum = 0, + .maximum = 63, + .step = 1, + .default_value = 32, + }, + .set = sd_setbrightness, + .get = sd_getbrightness, + }, +#define SD_CONTRAST 1 + { + { + .id = V4L2_CID_CONTRAST, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Contrast", + .minimum = 0, + .maximum = 0x3fff, + .step = 1, + .default_value = 0x2000, + }, + .set = sd_setcontrast, + .get = sd_getcontrast, + }, +#define SD_AUTOGAIN 2 + { + { + .id = V4L2_CID_AUTOGAIN, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Auto Gain", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 1, + }, + .set = sd_setautogain, + .get = sd_getautogain, + }, +}; + +static struct v4l2_pix_format sif_mode[] = { + {160, 120, V4L2_PIX_FMT_SGBRG8, V4L2_FIELD_NONE, + .bytesperline = 160, + .sizeimage = 160 * 120, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = 3}, + {176, 144, V4L2_PIX_FMT_SGBRG8, V4L2_FIELD_NONE, + .bytesperline = 176, + .sizeimage = 176 * 144, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = 2}, + {320, 240, V4L2_PIX_FMT_SPCA561, V4L2_FIELD_NONE, + .bytesperline = 320, + .sizeimage = 320 * 240 * 4 / 8, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = 1}, + {352, 288, V4L2_PIX_FMT_SPCA561, V4L2_FIELD_NONE, + .bytesperline = 352, + .sizeimage = 352 * 288 * 4 / 8, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = 0}, +}; + +/* + * Initialization data + * I'm not very sure how to split initialization from open data + * chunks. For now, we'll consider everything as initialization + */ +/* Frame packet header offsets for the spca561 */ +#define SPCA561_OFFSET_SNAP 1 +#define SPCA561_OFFSET_TYPE 2 +#define SPCA561_OFFSET_COMPRESS 3 +#define SPCA561_OFFSET_FRAMSEQ 4 +#define SPCA561_OFFSET_GPIO 5 +#define SPCA561_OFFSET_USBBUFF 6 +#define SPCA561_OFFSET_WIN2GRAVE 7 +#define SPCA561_OFFSET_WIN2RAVE 8 +#define SPCA561_OFFSET_WIN2BAVE 9 +#define SPCA561_OFFSET_WIN2GBAVE 10 +#define SPCA561_OFFSET_WIN1GRAVE 11 +#define SPCA561_OFFSET_WIN1RAVE 12 +#define SPCA561_OFFSET_WIN1BAVE 13 +#define SPCA561_OFFSET_WIN1GBAVE 14 +#define SPCA561_OFFSET_FREQ 15 +#define SPCA561_OFFSET_VSYNC 16 +#define SPCA561_OFFSET_DATA 1 +#define SPCA561_INDEX_I2C_BASE 0x8800 +#define SPCA561_SNAPBIT 0x20 +#define SPCA561_SNAPCTRL 0x40 +enum { + Rev072A = 0, + Rev012A, +}; + +static void reg_w_val(struct usb_device *dev, __u16 index, __u16 value) +{ + int ret; + + ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), + 0, /* request */ + USB_TYPE_VENDOR | USB_RECIP_DEVICE, + value, index, NULL, 0, 500); + PDEBUG(D_USBO, "reg write: 0x%02x:0x%02x", index, value); + if (ret < 0) + PDEBUG(D_ERR, "reg write: error %d", ret); +} + +static void write_vector(struct gspca_dev *gspca_dev, + const __u16 data[][2]) +{ + struct usb_device *dev = gspca_dev->dev; + int i; + + i = 0; + while (data[i][1] != 0) { + reg_w_val(dev, data[i][1], data[i][0]); + i++; + } +} + +/* read 'len' bytes to gspca_dev->usb_buf */ +static void reg_r(struct gspca_dev *gspca_dev, + __u16 index, __u16 length) +{ + usb_control_msg(gspca_dev->dev, + usb_rcvctrlpipe(gspca_dev->dev, 0), + 0, /* request */ + USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + 0, /* value */ + index, gspca_dev->usb_buf, length, 500); +} + +static void reg_w_buf(struct gspca_dev *gspca_dev, + __u16 index, const __u8 *buffer, __u16 len) +{ + memcpy(gspca_dev->usb_buf, buffer, len); + usb_control_msg(gspca_dev->dev, + usb_sndctrlpipe(gspca_dev->dev, 0), + 0, /* request */ + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + 0, /* value */ + index, gspca_dev->usb_buf, len, 500); +} + +static void i2c_init(struct gspca_dev *gspca_dev, __u8 mode) +{ + reg_w_val(gspca_dev->dev, 0x92, 0x8804); + reg_w_val(gspca_dev->dev, mode, 0x8802); +} + +static void i2c_write(struct gspca_dev *gspca_dev, __u16 valeur, __u16 reg) +{ + int retry = 60; + __u8 DataLow; + __u8 DataHight; + + DataLow = valeur; + DataHight = valeur >> 8; + reg_w_val(gspca_dev->dev, reg, 0x8801); + reg_w_val(gspca_dev->dev, DataLow, 0x8805); + reg_w_val(gspca_dev->dev, DataHight, 0x8800); + while (retry--) { + reg_r(gspca_dev, 0x8803, 1); + if (!gspca_dev->usb_buf[0]) + break; + } +} + +static int i2c_read(struct gspca_dev *gspca_dev, __u16 reg, __u8 mode) +{ + int retry = 60; + __u8 value; + __u8 vallsb; + + reg_w_val(gspca_dev->dev, 0x92, 0x8804); + reg_w_val(gspca_dev->dev, reg, 0x8801); + reg_w_val(gspca_dev->dev, (mode | 0x01), 0x8802); + while (retry--) { + reg_r(gspca_dev, 0x8803, 1); + if (!gspca_dev->usb_buf) + break; + } + if (retry == 0) + return -1; + reg_r(gspca_dev, 0x8800, 1); + value = gspca_dev->usb_buf[0]; + reg_r(gspca_dev, 0x8805, 1); + vallsb = gspca_dev->usb_buf[0]; + return ((int) value << 8) | vallsb; +} + +static const __u16 spca561_init_data[][2] = { + {0x0000, 0x8114}, /* Software GPIO output data */ + {0x0001, 0x8114}, /* Software GPIO output data */ + {0x0000, 0x8112}, /* Some kind of reset */ + {0x0003, 0x8701}, /* PCLK clock delay adjustment */ + {0x0001, 0x8703}, /* HSYNC from cmos inverted */ + {0x0011, 0x8118}, /* Enable and conf sensor */ + {0x0001, 0x8118}, /* Conf sensor */ + {0x0092, 0x8804}, /* I know nothing about these */ + {0x0010, 0x8802}, /* 0x88xx registers, so I won't */ + /***************/ + {0x000d, 0x8805}, /* sensor default setting */ + {0x0001, 0x8801}, /* 1 <- 0x0d */ + {0x0000, 0x8800}, + {0x0018, 0x8805}, + {0x0002, 0x8801}, /* 2 <- 0x18 */ + {0x0000, 0x8800}, + {0x0065, 0x8805}, + {0x0004, 0x8801}, /* 4 <- 0x01 0x65 */ + {0x0001, 0x8800}, + {0x0021, 0x8805}, + {0x0005, 0x8801}, /* 5 <- 0x21 */ + {0x0000, 0x8800}, + {0x00aa, 0x8805}, + {0x0007, 0x8801}, /* 7 <- 0xaa */ + {0x0000, 0x8800}, + {0x0004, 0x8805}, + {0x0020, 0x8801}, /* 0x20 <- 0x15 0x04 */ + {0x0015, 0x8800}, + {0x0002, 0x8805}, + {0x0039, 0x8801}, /* 0x39 <- 0x02 */ + {0x0000, 0x8800}, + {0x0010, 0x8805}, + {0x0035, 0x8801}, /* 0x35 <- 0x10 */ + {0x0000, 0x8800}, + {0x0049, 0x8805}, + {0x0009, 0x8801}, /* 0x09 <- 0x10 0x49 */ + {0x0010, 0x8800}, + {0x000b, 0x8805}, + {0x0028, 0x8801}, /* 0x28 <- 0x0b */ + {0x0000, 0x8800}, + {0x000f, 0x8805}, + {0x003b, 0x8801}, /* 0x3b <- 0x0f */ + {0x0000, 0x8800}, + {0x0000, 0x8805}, + {0x003c, 0x8801}, /* 0x3c <- 0x00 */ + {0x0000, 0x8800}, + /***************/ + {0x0018, 0x8601}, /* Pixel/line selection for color separation */ + {0x0000, 0x8602}, /* Optical black level for user setting */ + {0x0060, 0x8604}, /* Optical black horizontal offset */ + {0x0002, 0x8605}, /* Optical black vertical offset */ + {0x0000, 0x8603}, /* Non-automatic optical black level */ + {0x0002, 0x865b}, /* Horizontal offset for valid pixels */ + {0x0000, 0x865f}, /* Vertical valid pixels window (x2) */ + {0x00b0, 0x865d}, /* Horizontal valid pixels window (x2) */ + {0x0090, 0x865e}, /* Vertical valid lines window (x2) */ + {0x00e0, 0x8406}, /* Memory buffer threshold */ + {0x0000, 0x8660}, /* Compensation memory stuff */ + {0x0002, 0x8201}, /* Output address for r/w serial EEPROM */ + {0x0008, 0x8200}, /* Clear valid bit for serial EEPROM */ + {0x0001, 0x8200}, /* OprMode to be executed by hardware */ + {0x0007, 0x8201}, /* Output address for r/w serial EEPROM */ + {0x0008, 0x8200}, /* Clear valid bit for serial EEPROM */ + {0x0001, 0x8200}, /* OprMode to be executed by hardware */ + {0x0010, 0x8660}, /* Compensation memory stuff */ + {0x0018, 0x8660}, /* Compensation memory stuff */ + + {0x0004, 0x8611}, /* R offset for white balance */ + {0x0004, 0x8612}, /* Gr offset for white balance */ + {0x0007, 0x8613}, /* B offset for white balance */ + {0x0000, 0x8614}, /* Gb offset for white balance */ + {0x008c, 0x8651}, /* R gain for white balance */ + {0x008c, 0x8652}, /* Gr gain for white balance */ + {0x00b5, 0x8653}, /* B gain for white balance */ + {0x008c, 0x8654}, /* Gb gain for white balance */ + {0x0002, 0x8502}, /* Maximum average bit rate stuff */ + + {0x0011, 0x8802}, + {0x0087, 0x8700}, /* Set master clock (96Mhz????) */ + {0x0081, 0x8702}, /* Master clock output enable */ + + {0x0000, 0x8500}, /* Set image type (352x288 no compression) */ + /* Originally was 0x0010 (352x288 compression) */ + + {0x0002, 0x865b}, /* Horizontal offset for valid pixels */ + {0x0003, 0x865c}, /* Vertical offset for valid lines */ + /***************//* sensor active */ + {0x0003, 0x8801}, /* 0x03 <- 0x01 0x21 //289 */ + {0x0021, 0x8805}, + {0x0001, 0x8800}, + {0x0004, 0x8801}, /* 0x04 <- 0x01 0x65 //357 */ + {0x0065, 0x8805}, + {0x0001, 0x8800}, + {0x0005, 0x8801}, /* 0x05 <- 0x2f */ + {0x002f, 0x8805}, + {0x0000, 0x8800}, + {0x0006, 0x8801}, /* 0x06 <- 0 */ + {0x0000, 0x8805}, + {0x0000, 0x8800}, + {0x000a, 0x8801}, /* 0x0a <- 2 */ + {0x0002, 0x8805}, + {0x0000, 0x8800}, + {0x0009, 0x8801}, /* 0x09 <- 0x1061 */ + {0x0061, 0x8805}, + {0x0010, 0x8800}, + {0x0035, 0x8801}, /* 0x35 <-0x14 */ + {0x0014, 0x8805}, + {0x0000, 0x8800}, + {0x0030, 0x8112}, /* ISO and drop packet enable */ + {0x0000, 0x8112}, /* Some kind of reset ???? */ + {0x0009, 0x8118}, /* Enable sensor and set standby */ + {0x0000, 0x8114}, /* Software GPIO output data */ + {0x0000, 0x8114}, /* Software GPIO output data */ + {0x0001, 0x8114}, /* Software GPIO output data */ + {0x0000, 0x8112}, /* Some kind of reset ??? */ + {0x0003, 0x8701}, + {0x0001, 0x8703}, + {0x0011, 0x8118}, + {0x0001, 0x8118}, + /***************/ + {0x0092, 0x8804}, + {0x0010, 0x8802}, + {0x000d, 0x8805}, + {0x0001, 0x8801}, + {0x0000, 0x8800}, + {0x0018, 0x8805}, + {0x0002, 0x8801}, + {0x0000, 0x8800}, + {0x0065, 0x8805}, + {0x0004, 0x8801}, + {0x0001, 0x8800}, + {0x0021, 0x8805}, + {0x0005, 0x8801}, + {0x0000, 0x8800}, + {0x00aa, 0x8805}, + {0x0007, 0x8801}, /* mode 0xaa */ + {0x0000, 0x8800}, + {0x0004, 0x8805}, + {0x0020, 0x8801}, + {0x0015, 0x8800}, /* mode 0x0415 */ + {0x0002, 0x8805}, + {0x0039, 0x8801}, + {0x0000, 0x8800}, + {0x0010, 0x8805}, + {0x0035, 0x8801}, + {0x0000, 0x8800}, + {0x0049, 0x8805}, + {0x0009, 0x8801}, + {0x0010, 0x8800}, + {0x000b, 0x8805}, + {0x0028, 0x8801}, + {0x0000, 0x8800}, + {0x000f, 0x8805}, + {0x003b, 0x8801}, + {0x0000, 0x8800}, + {0x0000, 0x8805}, + {0x003c, 0x8801}, + {0x0000, 0x8800}, + {0x0002, 0x8502}, + {0x0039, 0x8801}, + {0x0000, 0x8805}, + {0x0000, 0x8800}, + + {0x0087, 0x8700}, /* overwrite by start */ + {0x0081, 0x8702}, + {0x0000, 0x8500}, +/* {0x0010, 0x8500}, -- Previous line was this */ + {0x0002, 0x865b}, + {0x0003, 0x865c}, + /***************/ + {0x0003, 0x8801}, /* 0x121-> 289 */ + {0x0021, 0x8805}, + {0x0001, 0x8800}, + {0x0004, 0x8801}, /* 0x165 -> 357 */ + {0x0065, 0x8805}, + {0x0001, 0x8800}, + {0x0005, 0x8801}, /* 0x2f //blanking control colonne */ + {0x002f, 0x8805}, + {0x0000, 0x8800}, + {0x0006, 0x8801}, /* 0x00 //blanking mode row */ + {0x0000, 0x8805}, + {0x0000, 0x8800}, + {0x000a, 0x8801}, /* 0x01 //0x02 */ + {0x0001, 0x8805}, + {0x0000, 0x8800}, + {0x0009, 0x8801}, /* 0x1061 - setexposure times && pixel clock + * 0001 0 | 000 0110 0001 */ + {0x0061, 0x8805}, /* 61 31 */ + {0x0008, 0x8800}, /* 08 */ + {0x0035, 0x8801}, /* 0x14 - set gain general */ + {0x001f, 0x8805}, /* 0x14 */ + {0x0000, 0x8800}, + {0x0030, 0x8112}, + {} +}; + +static void sensor_reset(struct gspca_dev *gspca_dev) +{ + reg_w_val(gspca_dev->dev, 0x8631, 0xc8); + reg_w_val(gspca_dev->dev, 0x8634, 0xc8); + reg_w_val(gspca_dev->dev, 0x8112, 0x00); + reg_w_val(gspca_dev->dev, 0x8114, 0x00); + reg_w_val(gspca_dev->dev, 0x8118, 0x21); + i2c_init(gspca_dev, 0x14); + i2c_write(gspca_dev, 1, 0x0d); + i2c_write(gspca_dev, 0, 0x0d); +} + +/******************** QC Express etch2 stuff ********************/ +static const __u16 Pb100_1map8300[][2] = { + /* reg, value */ + {0x8320, 0x3304}, + + {0x8303, 0x0125}, /* image area */ + {0x8304, 0x0169}, + {0x8328, 0x000b}, + {0x833c, 0x0001}, + + {0x832f, 0x0419}, + {0x8307, 0x00aa}, + {0x8301, 0x0003}, + {0x8302, 0x000e}, + {} +}; +static const __u16 Pb100_2map8300[][2] = { + /* reg, value */ + {0x8339, 0x0000}, + {0x8307, 0x00aa}, + {} +}; + +static const __u16 spca561_161rev12A_data1[][2] = { + {0x21, 0x8118}, + {0x01, 0x8114}, + {0x00, 0x8112}, + {0x92, 0x8804}, + {0x04, 0x8802}, /* windows uses 08 */ + {} +}; +static const __u16 spca561_161rev12A_data2[][2] = { + {0x21, 0x8118}, + {0x10, 0x8500}, + {0x07, 0x8601}, + {0x07, 0x8602}, + {0x04, 0x8501}, + {0x21, 0x8118}, + + {0x07, 0x8201}, /* windows uses 02 */ + {0x08, 0x8200}, + {0x01, 0x8200}, + + {0x00, 0x8114}, + {0x01, 0x8114}, /* windows uses 00 */ + + {0x90, 0x8604}, + {0x00, 0x8605}, + {0xb0, 0x8603}, + + /* sensor gains */ + {0x00, 0x8610}, /* *red */ + {0x00, 0x8611}, /* 3f *green */ + {0x00, 0x8612}, /* green *blue */ + {0x00, 0x8613}, /* blue *green */ + {0x35, 0x8614}, /* green *red */ + {0x35, 0x8615}, /* 40 *green */ + {0x35, 0x8616}, /* 7a *blue */ + {0x35, 0x8617}, /* 40 *green */ + + {0x0c, 0x8620}, /* 0c */ + {0xc8, 0x8631}, /* c8 */ + {0xc8, 0x8634}, /* c8 */ + {0x23, 0x8635}, /* 23 */ + {0x1f, 0x8636}, /* 1f */ + {0xdd, 0x8637}, /* dd */ + {0xe1, 0x8638}, /* e1 */ + {0x1d, 0x8639}, /* 1d */ + {0x21, 0x863a}, /* 21 */ + {0xe3, 0x863b}, /* e3 */ + {0xdf, 0x863c}, /* df */ + {0xf0, 0x8505}, + {0x32, 0x850a}, + {} +}; + +static void sensor_mapwrite(struct gspca_dev *gspca_dev, + const __u16 sensormap[][2]) +{ + int i = 0; + __u8 usbval[2]; + + while (sensormap[i][0]) { + usbval[0] = sensormap[i][1]; + usbval[1] = sensormap[i][1] >> 8; + reg_w_buf(gspca_dev, sensormap[i][0], usbval, 2); + i++; + } +} +static void init_161rev12A(struct gspca_dev *gspca_dev) +{ + sensor_reset(gspca_dev); + write_vector(gspca_dev, spca561_161rev12A_data1); + sensor_mapwrite(gspca_dev, Pb100_1map8300); + write_vector(gspca_dev, spca561_161rev12A_data2); + sensor_mapwrite(gspca_dev, Pb100_2map8300); +} + +/* this function is called at probe time */ +static int sd_config(struct gspca_dev *gspca_dev, + const struct usb_device_id *id) +{ + struct sd *sd = (struct sd *) gspca_dev; + struct cam *cam; + __u16 vendor, product; + __u8 data1, data2; + + /* Read frm global register the USB product and vendor IDs, just to + * prove that we can communicate with the device. This works, which + * confirms at we are communicating properly and that the device + * is a 561. */ + reg_r(gspca_dev, 0x8104, 1); + data1 = gspca_dev->usb_buf[0]; + reg_r(gspca_dev, 0x8105, 1); + data2 = gspca_dev->usb_buf[0]; + vendor = (data2 << 8) | data1; + reg_r(gspca_dev, 0x8106, 1); + data1 = gspca_dev->usb_buf[0]; + reg_r(gspca_dev, 0x8107, 1); + data2 = gspca_dev->usb_buf[0]; + product = (data2 << 8) | data1; + if (vendor != id->idVendor || product != id->idProduct) { + PDEBUG(D_PROBE, "Bad vendor / product from device"); + return -EINVAL; + } + switch (product) { + case 0x0928: + case 0x0929: + case 0x092a: + case 0x092b: + case 0x092c: + case 0x092d: + case 0x092e: + case 0x092f: + case 0x403b: + sd->chip_revision = Rev012A; + break; + default: +/* case 0x0561: + case 0x0815: * ?? in spca508.c + case 0x401a: + case 0x7004: + case 0x7e50: + case 0xa001: + case 0xcdee: */ + sd->chip_revision = Rev072A; + break; + } + cam = &gspca_dev->cam; + cam->dev_name = (char *) id->driver_info; + cam->epaddr = 0x01; + gspca_dev->nbalt = 7 + 1; /* choose alternate 7 first */ + cam->cam_mode = sif_mode; + cam->nmodes = sizeof sif_mode / sizeof sif_mode[0]; + sd->brightness = sd_ctrls[SD_BRIGHTNESS].qctrl.default_value; + sd->contrast = sd_ctrls[SD_CONTRAST].qctrl.default_value; + sd->autogain = sd_ctrls[SD_AUTOGAIN].qctrl.default_value; + return 0; +} + +/* this function is called at open time */ +static int sd_open(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + + switch (sd->chip_revision) { + case Rev072A: + PDEBUG(D_STREAM, "Chip revision id: 072a"); + write_vector(gspca_dev, spca561_init_data); + break; + default: +/* case Rev012A: */ + PDEBUG(D_STREAM, "Chip revision id: 012a"); + init_161rev12A(gspca_dev); + break; + } + return 0; +} + +static void setcontrast(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + struct usb_device *dev = gspca_dev->dev; + __u8 lowb; + int expotimes; + + switch (sd->chip_revision) { + case Rev072A: + lowb = sd->contrast >> 8; + reg_w_val(dev, lowb, 0x8651); + reg_w_val(dev, lowb, 0x8652); + reg_w_val(dev, lowb, 0x8653); + reg_w_val(dev, lowb, 0x8654); + break; + case Rev012A: { + __u8 Reg8391[] = + { 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00 }; + + /* Write camera sensor settings */ + expotimes = (sd->contrast >> 5) & 0x07ff; + Reg8391[0] = expotimes & 0xff; /* exposure */ + Reg8391[1] = 0x18 | (expotimes >> 8); + Reg8391[2] = sd->brightness; /* gain */ + reg_w_buf(gspca_dev, 0x8391, Reg8391, 8); + reg_w_buf(gspca_dev, 0x8390, Reg8391, 8); + break; + } + } +} + +static void sd_start(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + struct usb_device *dev = gspca_dev->dev; + int Clck; + __u8 Reg8307[] = { 0xaa, 0x00 }; + int mode; + + mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv; + switch (sd->chip_revision) { + case Rev072A: + switch (mode) { + default: +/* case 0: + case 1: */ + Clck = 0x25; + break; + case 2: + Clck = 0x22; + break; + case 3: + Clck = 0x21; + break; + } + reg_w_val(dev, 0x8500, mode); /* mode */ + reg_w_val(dev, 0x8700, Clck); /* 0x27 clock */ + reg_w_val(dev, 0x8112, 0x10 | 0x20); + break; + default: +/* case Rev012A: */ + switch (mode) { + case 0: + case 1: + Clck = 0x8a; + break; + case 2: + Clck = 0x85; + break; + default: + Clck = 0x83; + break; + } + if (mode <= 1) { + /* Use compression on 320x240 and above */ + reg_w_val(dev, 0x8500, 0x10 | mode); + } else { + /* I couldn't get the compression to work below 320x240 + * Fortunately at these resolutions the bandwidth + * is sufficient to push raw frames at ~20fps */ + reg_w_val(dev, 0x8500, mode); + } /* -- qq@kuku.eu.org */ + reg_w_buf(gspca_dev, 0x8307, Reg8307, 2); + reg_w_val(gspca_dev->dev, 0x8700, Clck); + /* 0x8f 0x85 0x27 clock */ + reg_w_val(gspca_dev->dev, 0x8112, 0x1e | 0x20); + reg_w_val(gspca_dev->dev, 0x850b, 0x03); + setcontrast(gspca_dev); + break; + } +} + +static void sd_stopN(struct gspca_dev *gspca_dev) +{ + reg_w_val(gspca_dev->dev, 0x8112, 0x20); +} + +static void sd_stop0(struct gspca_dev *gspca_dev) +{ +} + +/* this function is called at close time */ +static void sd_close(struct gspca_dev *gspca_dev) +{ + reg_w_val(gspca_dev->dev, 0x8114, 0); +} + +static void setautogain(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + int expotimes = 0; + int pixelclk = 0; + int gainG = 0; + __u8 R, Gr, Gb, B; + int y; + __u8 luma_mean = 110; + __u8 luma_delta = 20; + __u8 spring = 4; + + switch (sd->chip_revision) { + case Rev072A: + reg_r(gspca_dev, 0x8621, 1); + Gr = gspca_dev->usb_buf[0]; + reg_r(gspca_dev, 0x8622, 1); + R = gspca_dev->usb_buf[0]; + reg_r(gspca_dev, 0x8623, 1); + B = gspca_dev->usb_buf[0]; + reg_r(gspca_dev, 0x8624, 1); + Gb = gspca_dev->usb_buf[0]; + y = (77 * R + 75 * (Gr + Gb) + 29 * B) >> 8; + /* u= (128*B-(43*(Gr+Gb+R))) >> 8; */ + /* v= (128*R-(53*(Gr+Gb))-21*B) >> 8; */ + /* PDEBUG(D_CONF,"reading Y %d U %d V %d ",y,u,v); */ + + if (y < luma_mean - luma_delta || + y > luma_mean + luma_delta) { + expotimes = i2c_read(gspca_dev, 0x09, 0x10); + pixelclk = 0x0800; + expotimes = expotimes & 0x07ff; + /* PDEBUG(D_PACK, + "Exposition Times 0x%03X Clock 0x%04X ", + expotimes,pixelclk); */ + gainG = i2c_read(gspca_dev, 0x35, 0x10); + /* PDEBUG(D_PACK, + "reading Gain register %d", gainG); */ + + expotimes += (luma_mean - y) >> spring; + gainG += (luma_mean - y) / 50; + /* PDEBUG(D_PACK, + "compute expotimes %d gain %d", + expotimes,gainG); */ + + if (gainG > 0x3f) + gainG = 0x3f; + else if (gainG < 4) + gainG = 3; + i2c_write(gspca_dev, gainG, 0x35); + + if (expotimes >= 0x0256) + expotimes = 0x0256; + else if (expotimes < 4) + expotimes = 3; + i2c_write(gspca_dev, expotimes | pixelclk, 0x09); + } + break; + case Rev012A: + /* sensor registers is access and memory mapped to 0x8300 */ + /* readind all 0x83xx block the sensor */ + /* + * The data from the header seem wrong where is the luma + * and chroma mean value + * at the moment set exposure in contrast set + */ + break; + } +} + +static void sd_pkt_scan(struct gspca_dev *gspca_dev, + struct gspca_frame *frame, /* target */ + __u8 *data, /* isoc packet */ + int len) /* iso packet length */ +{ + struct sd *sd = (struct sd *) gspca_dev; + + switch (data[0]) { + case 0: /* start of frame */ + frame = gspca_frame_add(gspca_dev, LAST_PACKET, frame, + data, 0); + if (sd->ag_cnt >= 0) { + if (--sd->ag_cnt < 0) { + sd->ag_cnt = AG_CNT_START; + setautogain(gspca_dev); + } + } + data += SPCA561_OFFSET_DATA; + len -= SPCA561_OFFSET_DATA; + if (data[1] & 0x10) { + /* compressed bayer */ + gspca_frame_add(gspca_dev, FIRST_PACKET, + frame, data, len); + } else { + /* raw bayer (with a header, which we skip) */ + data += 20; + len -= 20; + gspca_frame_add(gspca_dev, FIRST_PACKET, + frame, data, len); + } + return; + case 0xff: /* drop */ +/* gspca_dev->last_packet_type = DISCARD_PACKET; */ + return; + } + data++; + len--; + gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len); +} + +static void setbrightness(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + __u8 value; + + switch (sd->chip_revision) { + case Rev072A: + value = sd->brightness; + reg_w_val(gspca_dev->dev, value, 0x8611); + reg_w_val(gspca_dev->dev, value, 0x8612); + reg_w_val(gspca_dev->dev, value, 0x8613); + reg_w_val(gspca_dev->dev, value, 0x8614); + break; + default: +/* case Rev012A: */ + setcontrast(gspca_dev); + break; + } +} + +static void getbrightness(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + __u16 tot; + + switch (sd->chip_revision) { + case Rev072A: + tot = 0; + reg_r(gspca_dev, 0x8611, 1); + tot += gspca_dev->usb_buf[0]; + reg_r(gspca_dev, 0x8612, 1); + tot += gspca_dev->usb_buf[0]; + reg_r(gspca_dev, 0x8613, 1); + tot += gspca_dev->usb_buf[0]; + reg_r(gspca_dev, 0x8614, 1); + tot += gspca_dev->usb_buf[0]; + sd->brightness = tot >> 2; + break; + default: +/* case Rev012A: */ + /* no way to read sensor settings */ + break; + } +} + +static void getcontrast(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + __u16 tot; + + switch (sd->chip_revision) { + case Rev072A: + tot = 0; + reg_r(gspca_dev, 0x8651, 1); + tot += gspca_dev->usb_buf[0]; + reg_r(gspca_dev, 0x8652, 1); + tot += gspca_dev->usb_buf[0]; + reg_r(gspca_dev, 0x8653, 1); + tot += gspca_dev->usb_buf[0]; + reg_r(gspca_dev, 0x8654, 1); + tot += gspca_dev->usb_buf[0]; + sd->contrast = tot << 6; + break; + default: +/* case Rev012A: */ + /* no way to read sensor settings */ + break; + } + PDEBUG(D_CONF, "get contrast %d", sd->contrast); +} + +static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->brightness = val; + if (gspca_dev->streaming) + setbrightness(gspca_dev); + return 0; +} + +static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + getbrightness(gspca_dev); + *val = sd->brightness; + return 0; +} + +static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->contrast = val; + if (gspca_dev->streaming) + setcontrast(gspca_dev); + return 0; +} + +static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + getcontrast(gspca_dev); + *val = sd->contrast; + return 0; +} + +static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->autogain = val; + if (val) + sd->ag_cnt = AG_CNT_START; + else + sd->ag_cnt = -1; + return 0; +} + +static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + *val = sd->autogain; + return 0; +} + +/* sub-driver description */ +static const struct sd_desc sd_desc = { + .name = MODULE_NAME, + .ctrls = sd_ctrls, + .nctrls = ARRAY_SIZE(sd_ctrls), + .config = sd_config, + .open = sd_open, + .start = sd_start, + .stopN = sd_stopN, + .stop0 = sd_stop0, + .close = sd_close, + .pkt_scan = sd_pkt_scan, +}; + +/* -- module initialisation -- */ +#define DVNM(name) .driver_info = (kernel_ulong_t) name +static const __devinitdata struct usb_device_id device_table[] = { + {USB_DEVICE(0x041e, 0x401a), DVNM("Creative Webcam Vista (PD1100)")}, + {USB_DEVICE(0x041e, 0x403b), DVNM("Creative Webcam Vista (VF0010)")}, + {USB_DEVICE(0x0458, 0x7004), DVNM("Genius VideoCAM Express V2")}, + {USB_DEVICE(0x046d, 0x0928), DVNM("Logitech QC Express Etch2")}, + {USB_DEVICE(0x046d, 0x0929), DVNM("Labtec Webcam Elch2")}, + {USB_DEVICE(0x046d, 0x092a), DVNM("Logitech QC for Notebook")}, + {USB_DEVICE(0x046d, 0x092b), DVNM("Labtec Webcam Plus")}, + {USB_DEVICE(0x046d, 0x092c), DVNM("Logitech QC chat Elch2")}, + {USB_DEVICE(0x046d, 0x092d), DVNM("Logitech QC Elch2")}, + {USB_DEVICE(0x046d, 0x092e), DVNM("Logitech QC Elch2")}, + {USB_DEVICE(0x046d, 0x092f), DVNM("Logitech QC Elch2")}, + {USB_DEVICE(0x04fc, 0x0561), DVNM("Flexcam 100")}, + {USB_DEVICE(0x060b, 0xa001), DVNM("Maxell Compact Pc PM3")}, + {USB_DEVICE(0x10fd, 0x7e50), DVNM("FlyCam Usb 100")}, + {USB_DEVICE(0xabcd, 0xcdee), DVNM("Petcam")}, + {} +}; + +MODULE_DEVICE_TABLE(usb, device_table); + +/* -- device connect -- */ +static int sd_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd), + THIS_MODULE); +} + +static struct usb_driver sd_driver = { + .name = MODULE_NAME, + .id_table = device_table, + .probe = sd_probe, + .disconnect = gspca_disconnect, +}; + +/* -- module insert / remove -- */ +static int __init sd_mod_init(void) +{ + if (usb_register(&sd_driver) < 0) + return -1; + PDEBUG(D_PROBE, "v%s registered", version); + return 0; +} +static void __exit sd_mod_exit(void) +{ + usb_deregister(&sd_driver); + PDEBUG(D_PROBE, "deregistered"); +} + +module_init(sd_mod_init); +module_exit(sd_mod_exit); diff --git a/drivers/media/video/gspca/stk014.c b/drivers/media/video/gspca/stk014.c new file mode 100644 index 000000000000..c78ee0d3e59b --- /dev/null +++ b/drivers/media/video/gspca/stk014.c @@ -0,0 +1,592 @@ +/* + * Syntek DV4000 (STK014) subdriver + * + * Copyright (C) 2008 Jean-Francois Moine (http://moinejf.free.fr) + * + * 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 + * 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 + */ + +#define MODULE_NAME "stk014" + +#include "gspca.h" +#include "jpeg.h" + +#define DRIVER_VERSION_NUMBER KERNEL_VERSION(2, 1, 7) +static const char version[] = "2.1.7"; + +MODULE_AUTHOR("Jean-Francois Moine <http://moinejf.free.fr>"); +MODULE_DESCRIPTION("Syntek DV4000 (STK014) USB Camera Driver"); +MODULE_LICENSE("GPL"); + +/* specific webcam descriptor */ +struct sd { + struct gspca_dev gspca_dev; /* !! must be the first item */ + + unsigned char brightness; + unsigned char contrast; + unsigned char colors; + unsigned char lightfreq; +}; + +/* global parameters */ +static int sd_quant = 7; /* <= 4 KO - 7: good (enough!) */ + +/* V4L2 controls supported by the driver */ +static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val); +static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val); +static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val); +static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val); +static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val); +static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val); +static int sd_setfreq(struct gspca_dev *gspca_dev, __s32 val); +static int sd_getfreq(struct gspca_dev *gspca_dev, __s32 *val); + +static struct ctrl sd_ctrls[] = { + { + { + .id = V4L2_CID_BRIGHTNESS, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Brightness", + .minimum = 0, + .maximum = 255, + .step = 1, +#define BRIGHTNESS_DEF 127 + .default_value = BRIGHTNESS_DEF, + }, + .set = sd_setbrightness, + .get = sd_getbrightness, + }, + { + { + .id = V4L2_CID_CONTRAST, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Contrast", + .minimum = 0, + .maximum = 255, + .step = 1, +#define CONTRAST_DEF 127 + .default_value = CONTRAST_DEF, + }, + .set = sd_setcontrast, + .get = sd_getcontrast, + }, + { + { + .id = V4L2_CID_SATURATION, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Color", + .minimum = 0, + .maximum = 255, + .step = 1, +#define COLOR_DEF 127 + .default_value = COLOR_DEF, + }, + .set = sd_setcolors, + .get = sd_getcolors, + }, + { + { + .id = V4L2_CID_POWER_LINE_FREQUENCY, + .type = V4L2_CTRL_TYPE_MENU, + .name = "Light frequency filter", + .minimum = 1, + .maximum = 2, /* 0: 0, 1: 50Hz, 2:60Hz */ + .step = 1, +#define FREQ_DEF 1 + .default_value = FREQ_DEF, + }, + .set = sd_setfreq, + .get = sd_getfreq, + }, +}; + +static struct v4l2_pix_format vga_mode[] = { + {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, + .bytesperline = 320, + .sizeimage = 320 * 240 * 3 / 8 + 590, + .colorspace = V4L2_COLORSPACE_JPEG, + .priv = 1}, + {640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, + .bytesperline = 640, + .sizeimage = 640 * 480 * 3 / 8 + 590, + .colorspace = V4L2_COLORSPACE_JPEG, + .priv = 0}, +}; + +/* -- read a register -- */ +static int reg_r(struct gspca_dev *gspca_dev, + __u16 index) +{ + struct usb_device *dev = gspca_dev->dev; + int ret; + + ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), + 0x00, + USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + 0x00, + index, + gspca_dev->usb_buf, 1, + 500); + if (ret < 0) { + PDEBUG(D_ERR, "reg_r err %d", ret); + return ret; + } + return gspca_dev->usb_buf[0]; +} + +/* -- write a register -- */ +static int reg_w(struct gspca_dev *gspca_dev, + __u16 index, __u16 value) +{ + struct usb_device *dev = gspca_dev->dev; + int ret; + + ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), + 0x01, + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + value, + index, + NULL, + 0, + 500); + if (ret < 0) + PDEBUG(D_ERR, "reg_w err %d", ret); + return ret; +} + +/* -- get a bulk value (4 bytes) -- */ +static int rcv_val(struct gspca_dev *gspca_dev, + int ads) +{ + struct usb_device *dev = gspca_dev->dev; + int alen, ret; + + reg_w(gspca_dev, 0x634, (ads >> 16) & 0xff); + reg_w(gspca_dev, 0x635, (ads >> 8) & 0xff); + reg_w(gspca_dev, 0x636, ads & 0xff); + reg_w(gspca_dev, 0x637, 0); + reg_w(gspca_dev, 0x638, 4); /* len & 0xff */ + reg_w(gspca_dev, 0x639, 0); /* len >> 8 */ + reg_w(gspca_dev, 0x63a, 0); + reg_w(gspca_dev, 0x63b, 0); + reg_w(gspca_dev, 0x630, 5); + ret = usb_bulk_msg(dev, + usb_rcvbulkpipe(dev, 5), + gspca_dev->usb_buf, + 4, /* length */ + &alen, + 500); /* timeout in milliseconds */ + return ret; +} + +/* -- send a bulk value -- */ +static int snd_val(struct gspca_dev *gspca_dev, + int ads, + unsigned int val) +{ + struct usb_device *dev = gspca_dev->dev; + int alen, ret; + __u8 seq = 0; + + if (ads == 0x003f08) { + ret = reg_r(gspca_dev, 0x0704); + if (ret < 0) + goto ko; + ret = reg_r(gspca_dev, 0x0705); + if (ret < 0) + goto ko; + seq = ret; /* keep the sequence number */ + ret = reg_r(gspca_dev, 0x0650); + if (ret < 0) + goto ko; + reg_w(gspca_dev, 0x654, seq); + } else { + reg_w(gspca_dev, 0x654, (ads >> 16) & 0xff); + } + reg_w(gspca_dev, 0x655, (ads >> 8) & 0xff); + reg_w(gspca_dev, 0x656, ads & 0xff); + reg_w(gspca_dev, 0x657, 0); + reg_w(gspca_dev, 0x658, 0x04); /* size */ + reg_w(gspca_dev, 0x659, 0); + reg_w(gspca_dev, 0x65a, 0); + reg_w(gspca_dev, 0x65b, 0); + reg_w(gspca_dev, 0x650, 5); + gspca_dev->usb_buf[0] = val >> 24; + gspca_dev->usb_buf[1] = val >> 16; + gspca_dev->usb_buf[2] = val >> 8; + gspca_dev->usb_buf[3] = val; + ret = usb_bulk_msg(dev, + usb_sndbulkpipe(dev, 6), + gspca_dev->usb_buf, + 4, + &alen, + 500); /* timeout in milliseconds */ + if (ret < 0) + goto ko; + if (ads == 0x003f08) { + seq += 4; + seq &= 0x3f; + reg_w(gspca_dev, 0x705, seq); + } + return ret; +ko: + PDEBUG(D_ERR, "snd_val err %d", ret); + return ret; +} + +/* set a camera parameter */ +static int set_par(struct gspca_dev *gspca_dev, + int parval) +{ + return snd_val(gspca_dev, 0x003f08, parval); +} + +static void setbrightness(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + int parval; + + parval = 0x06000000 /* whiteness */ + + (sd->brightness << 16); + set_par(gspca_dev, parval); +} + +static void setcontrast(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + int parval; + + parval = 0x07000000 /* contrast */ + + (sd->contrast << 16); + set_par(gspca_dev, parval); +} + +static void setcolors(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + int parval; + + parval = 0x08000000 /* saturation */ + + (sd->colors << 16); + set_par(gspca_dev, parval); +} + +static void setfreq(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + + set_par(gspca_dev, sd->lightfreq == 1 + ? 0x33640000 /* 50 Hz */ + : 0x33780000); /* 60 Hz */ +} + +/* this function is called at probe time */ +static int sd_config(struct gspca_dev *gspca_dev, + const struct usb_device_id *id) +{ + struct sd *sd = (struct sd *) gspca_dev; + struct cam *cam = &gspca_dev->cam; + + cam->dev_name = (char *) id->driver_info; + cam->epaddr = 0x02; + gspca_dev->cam.cam_mode = vga_mode; + gspca_dev->cam.nmodes = ARRAY_SIZE(vga_mode); + sd->brightness = BRIGHTNESS_DEF; + sd->contrast = CONTRAST_DEF; + sd->colors = COLOR_DEF; + sd->lightfreq = FREQ_DEF; + return 0; +} + +/* this function is called at open time */ +static int sd_open(struct gspca_dev *gspca_dev) +{ + int ret; + + /* check if the device responds */ + usb_set_interface(gspca_dev->dev, gspca_dev->iface, 1); + ret = reg_r(gspca_dev, 0x0740); + if (ret < 0) + return ret; + if (ret != 0xff) { + PDEBUG(D_ERR|D_STREAM, "init reg: 0x%02x", ret); + return -1; + } + return 0; +} + +/* -- start the camera -- */ +static void sd_start(struct gspca_dev *gspca_dev) +{ + int ret, value; + + /* work on alternate 1 */ + usb_set_interface(gspca_dev->dev, gspca_dev->iface, 1); + + set_par(gspca_dev, 0x10000000); + set_par(gspca_dev, 0x00000000); + set_par(gspca_dev, 0x8002e001); + set_par(gspca_dev, 0x14000000); + if (gspca_dev->width > 320) + value = 0x8002e001; /* 640x480 */ + else + value = 0x4001f000; /* 320x240 */ + set_par(gspca_dev, value); + ret = usb_set_interface(gspca_dev->dev, + gspca_dev->iface, + gspca_dev->alt); + if (ret < 0) { + PDEBUG(D_ERR|D_STREAM, "set intf %d %d failed", + gspca_dev->iface, gspca_dev->alt); + goto out; + } + ret = reg_r(gspca_dev, 0x0630); + if (ret < 0) + goto out; + rcv_val(gspca_dev, 0x000020); /* << (value ff ff ff ff) */ + ret = reg_r(gspca_dev, 0x0650); + if (ret < 0) + goto out; + snd_val(gspca_dev, 0x000020, 0xffffffff); + reg_w(gspca_dev, 0x0620, 0); + reg_w(gspca_dev, 0x0630, 0); + reg_w(gspca_dev, 0x0640, 0); + reg_w(gspca_dev, 0x0650, 0); + reg_w(gspca_dev, 0x0660, 0); + setbrightness(gspca_dev); /* whiteness */ + setcontrast(gspca_dev); /* contrast */ + setcolors(gspca_dev); /* saturation */ + set_par(gspca_dev, 0x09800000); /* Red ? */ + set_par(gspca_dev, 0x0a800000); /* Green ? */ + set_par(gspca_dev, 0x0b800000); /* Blue ? */ + set_par(gspca_dev, 0x0d030000); /* Gamma ? */ + setfreq(gspca_dev); /* light frequency */ + + /* start the video flow */ + set_par(gspca_dev, 0x01000000); + set_par(gspca_dev, 0x01000000); + PDEBUG(D_STREAM, "camera started alt: 0x%02x", gspca_dev->alt); + return; +out: + PDEBUG(D_ERR|D_STREAM, "camera start err %d", ret); +} + +static void sd_stopN(struct gspca_dev *gspca_dev) +{ + struct usb_device *dev = gspca_dev->dev; + + set_par(gspca_dev, 0x02000000); + set_par(gspca_dev, 0x02000000); + usb_set_interface(dev, gspca_dev->iface, 1); + reg_r(gspca_dev, 0x0630); + rcv_val(gspca_dev, 0x000020); /* << (value ff ff ff ff) */ + reg_r(gspca_dev, 0x0650); + snd_val(gspca_dev, 0x000020, 0xffffffff); + reg_w(gspca_dev, 0x0620, 0); + reg_w(gspca_dev, 0x0630, 0); + reg_w(gspca_dev, 0x0640, 0); + reg_w(gspca_dev, 0x0650, 0); + reg_w(gspca_dev, 0x0660, 0); + PDEBUG(D_STREAM, "camera stopped"); +} + +static void sd_stop0(struct gspca_dev *gspca_dev) +{ +} + +static void sd_close(struct gspca_dev *gspca_dev) +{ +} + +static void sd_pkt_scan(struct gspca_dev *gspca_dev, + struct gspca_frame *frame, /* target */ + __u8 *data, /* isoc packet */ + int len) /* iso packet length */ +{ + static unsigned char ffd9[] = {0xff, 0xd9}; + + /* a frame starts with: + * - 0xff 0xfe + * - 0x08 0x00 - length (little endian ?!) + * - 4 bytes = size of whole frame (BE - including header) + * - 0x00 0x0c + * - 0xff 0xd8 + * - .. JPEG image with escape sequences (ff 00) + * (without ending - ff d9) + */ + if (data[0] == 0xff && data[1] == 0xfe) { + frame = gspca_frame_add(gspca_dev, LAST_PACKET, frame, + ffd9, 2); + + /* put the JPEG 411 header */ + jpeg_put_header(gspca_dev, frame, sd_quant, 0x22); + + /* beginning of the frame */ +#define STKHDRSZ 12 + gspca_frame_add(gspca_dev, INTER_PACKET, frame, + data + STKHDRSZ, len - STKHDRSZ); +#undef STKHDRSZ + return; + } + gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len); +} + +static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->brightness = val; + if (gspca_dev->streaming) + setbrightness(gspca_dev); + return 0; +} + +static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + *val = sd->brightness; + return 0; +} + +static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->contrast = val; + if (gspca_dev->streaming) + setcontrast(gspca_dev); + return 0; +} + +static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + *val = sd->contrast; + return 0; +} + +static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->colors = val; + if (gspca_dev->streaming) + setcolors(gspca_dev); + return 0; +} + +static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + *val = sd->colors; + return 0; +} + +static int sd_setfreq(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->lightfreq = val; + if (gspca_dev->streaming) + setfreq(gspca_dev); + return 0; +} + +static int sd_getfreq(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + *val = sd->lightfreq; + return 0; +} + +static int sd_querymenu(struct gspca_dev *gspca_dev, + struct v4l2_querymenu *menu) +{ + switch (menu->id) { + case V4L2_CID_POWER_LINE_FREQUENCY: + switch (menu->index) { + case 1: /* V4L2_CID_POWER_LINE_FREQUENCY_50HZ */ + strcpy((char *) menu->name, "50 Hz"); + return 0; + case 2: /* V4L2_CID_POWER_LINE_FREQUENCY_60HZ */ + strcpy((char *) menu->name, "60 Hz"); + return 0; + } + break; + } + return -EINVAL; +} + +/* sub-driver description */ +static const struct sd_desc sd_desc = { + .name = MODULE_NAME, + .ctrls = sd_ctrls, + .nctrls = ARRAY_SIZE(sd_ctrls), + .config = sd_config, + .open = sd_open, + .start = sd_start, + .stopN = sd_stopN, + .stop0 = sd_stop0, + .close = sd_close, + .pkt_scan = sd_pkt_scan, + .querymenu = sd_querymenu, +}; + +/* -- module initialisation -- */ +#define DVNM(name) .driver_info = (kernel_ulong_t) name +static const __devinitdata struct usb_device_id device_table[] = { + {USB_DEVICE(0x05e1, 0x0893), DVNM("Syntek DV4000")}, + {} +}; +MODULE_DEVICE_TABLE(usb, device_table); + +/* -- device connect -- */ +static int sd_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd), + THIS_MODULE); +} + +static struct usb_driver sd_driver = { + .name = MODULE_NAME, + .id_table = device_table, + .probe = sd_probe, + .disconnect = gspca_disconnect, +}; + +/* -- module insert / remove -- */ +static int __init sd_mod_init(void) +{ + if (usb_register(&sd_driver) < 0) + return -1; + info("v%s registered", version); + return 0; +} +static void __exit sd_mod_exit(void) +{ + usb_deregister(&sd_driver); + info("deregistered"); +} + +module_init(sd_mod_init); +module_exit(sd_mod_exit); + +module_param_named(quant, sd_quant, int, 0644); +MODULE_PARM_DESC(quant, "Quantization index (0..8)"); diff --git a/drivers/media/video/gspca/sunplus.c b/drivers/media/video/gspca/sunplus.c new file mode 100644 index 000000000000..abd7bef9b3d1 --- /dev/null +++ b/drivers/media/video/gspca/sunplus.c @@ -0,0 +1,1677 @@ +/* + * Sunplus spca504(abc) spca533 spca536 library + * Copyright (C) 2005 Michel Xhaard mxhaard@magic.fr + * + * V4L2 by Jean-Francois Moine <http://moinejf.free.fr> + * + * 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 + * 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 + */ + +#define MODULE_NAME "sunplus" + +#include "gspca.h" +#include "jpeg.h" + +#define DRIVER_VERSION_NUMBER KERNEL_VERSION(2, 1, 8) +static const char version[] = "2.1.8"; + +MODULE_AUTHOR("Michel Xhaard <mxhaard@users.sourceforge.net>"); +MODULE_DESCRIPTION("GSPCA/SPCA5xx USB Camera Driver"); +MODULE_LICENSE("GPL"); + +/* specific webcam descriptor */ +struct sd { + struct gspca_dev gspca_dev; /* !! must be the first item */ + + __u8 packet[ISO_MAX_SIZE + 128]; + /* !! no more than 128 ff in an ISO packet */ + + unsigned char brightness; + unsigned char contrast; + unsigned char colors; + unsigned char autogain; + + char qindex; + char bridge; +#define BRIDGE_SPCA504 0 +#define BRIDGE_SPCA504B 1 +#define BRIDGE_SPCA504C 2 +#define BRIDGE_SPCA533 3 +#define BRIDGE_SPCA536 4 + char subtype; +#define AiptekMiniPenCam13 1 +#define LogitechClickSmart420 2 +#define LogitechClickSmart820 3 +#define MegapixV4 4 +}; + +/* V4L2 controls supported by the driver */ +static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val); +static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val); +static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val); +static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val); +static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val); +static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val); +static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val); +static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val); + +static struct ctrl sd_ctrls[] = { +#define SD_BRIGHTNESS 0 + { + { + .id = V4L2_CID_BRIGHTNESS, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Brightness", + .minimum = 0, + .maximum = 0xff, + .step = 1, + .default_value = 0, + }, + .set = sd_setbrightness, + .get = sd_getbrightness, + }, +#define SD_CONTRAST 1 + { + { + .id = V4L2_CID_CONTRAST, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Contrast", + .minimum = 0, + .maximum = 0xff, + .step = 1, + .default_value = 0x20, + }, + .set = sd_setcontrast, + .get = sd_getcontrast, + }, +#define SD_COLOR 2 + { + { + .id = V4L2_CID_SATURATION, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Color", + .minimum = 0, + .maximum = 0xff, + .step = 1, + .default_value = 0x1a, + }, + .set = sd_setcolors, + .get = sd_getcolors, + }, +#define SD_AUTOGAIN 3 + { + { + .id = V4L2_CID_AUTOGAIN, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Auto Gain", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 1, + }, + .set = sd_setautogain, + .get = sd_getautogain, + }, +}; + +static struct v4l2_pix_format vga_mode[] = { + {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, + .bytesperline = 320, + .sizeimage = 320 * 240 * 3 / 8 + 590, + .colorspace = V4L2_COLORSPACE_JPEG, + .priv = 2}, + {640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, + .bytesperline = 640, + .sizeimage = 640 * 480 * 3 / 8 + 590, + .colorspace = V4L2_COLORSPACE_JPEG, + .priv = 1}, +}; + +static struct v4l2_pix_format custom_mode[] = { + {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, + .bytesperline = 320, + .sizeimage = 320 * 240 * 3 / 8 + 590, + .colorspace = V4L2_COLORSPACE_JPEG, + .priv = 2}, + {464, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, + .bytesperline = 464, + .sizeimage = 464 * 480 * 3 / 8 + 590, + .colorspace = V4L2_COLORSPACE_JPEG, + .priv = 1}, +}; + +static struct v4l2_pix_format vga_mode2[] = { + {176, 144, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, + .bytesperline = 176, + .sizeimage = 176 * 144 * 3 / 8 + 590, + .colorspace = V4L2_COLORSPACE_JPEG, + .priv = 4}, + {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, + .bytesperline = 320, + .sizeimage = 320 * 240 * 3 / 8 + 590, + .colorspace = V4L2_COLORSPACE_JPEG, + .priv = 3}, + {352, 288, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, + .bytesperline = 352, + .sizeimage = 352 * 288 * 3 / 8 + 590, + .colorspace = V4L2_COLORSPACE_JPEG, + .priv = 2}, + {640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, + .bytesperline = 640, + .sizeimage = 640 * 480 * 3 / 8 + 590, + .colorspace = V4L2_COLORSPACE_JPEG, + .priv = 1}, +}; + +#define SPCA50X_OFFSET_DATA 10 +#define SPCA504_PCCAM600_OFFSET_SNAPSHOT 3 +#define SPCA504_PCCAM600_OFFSET_COMPRESS 4 +#define SPCA504_PCCAM600_OFFSET_MODE 5 +#define SPCA504_PCCAM600_OFFSET_DATA 14 + /* Frame packet header offsets for the spca533 */ +#define SPCA533_OFFSET_DATA 16 +#define SPCA533_OFFSET_FRAMSEQ 15 +/* Frame packet header offsets for the spca536 */ +#define SPCA536_OFFSET_DATA 4 +#define SPCA536_OFFSET_FRAMSEQ 1 + +/* Initialisation data for the Creative PC-CAM 600 */ +static const __u16 spca504_pccam600_init_data[][3] = { +/* {0xa0, 0x0000, 0x0503}, * capture mode */ + {0x00, 0x0000, 0x2000}, + {0x00, 0x0013, 0x2301}, + {0x00, 0x0003, 0x2000}, + {0x00, 0x0001, 0x21ac}, + {0x00, 0x0001, 0x21a6}, + {0x00, 0x0000, 0x21a7}, /* brightness */ + {0x00, 0x0020, 0x21a8}, /* contrast */ + {0x00, 0x0001, 0x21ac}, /* sat/hue */ + {0x00, 0x0000, 0x21ad}, /* hue */ + {0x00, 0x001a, 0x21ae}, /* saturation */ + {0x00, 0x0002, 0x21a3}, /* gamma */ + {0x30, 0x0154, 0x0008}, + {0x30, 0x0004, 0x0006}, + {0x30, 0x0258, 0x0009}, + {0x30, 0x0004, 0x0000}, + {0x30, 0x0093, 0x0004}, + {0x30, 0x0066, 0x0005}, + {0x00, 0x0000, 0x2000}, + {0x00, 0x0013, 0x2301}, + {0x00, 0x0003, 0x2000}, + {0x00, 0x0013, 0x2301}, + {0x00, 0x0003, 0x2000}, + {} +}; + +/* Creative PC-CAM 600 specific open data, sent before using the + * generic initialisation data from spca504_open_data. + */ +static const __u16 spca504_pccam600_open_data[][3] = { + {0x00, 0x0001, 0x2501}, + {0x20, 0x0500, 0x0001}, /* snapshot mode */ + {0x00, 0x0003, 0x2880}, + {0x00, 0x0001, 0x2881}, + {} +}; + +/* Initialisation data for the logitech clicksmart 420 */ +static const __u16 spca504A_clicksmart420_init_data[][3] = { +/* {0xa0, 0x0000, 0x0503}, * capture mode */ + {0x00, 0x0000, 0x2000}, + {0x00, 0x0013, 0x2301}, + {0x00, 0x0003, 0x2000}, + {0x00, 0x0001, 0x21ac}, + {0x00, 0x0001, 0x21a6}, + {0x00, 0x0000, 0x21a7}, /* brightness */ + {0x00, 0x0020, 0x21a8}, /* contrast */ + {0x00, 0x0001, 0x21ac}, /* sat/hue */ + {0x00, 0x0000, 0x21ad}, /* hue */ + {0x00, 0x001a, 0x21ae}, /* saturation */ + {0x00, 0x0002, 0x21a3}, /* gamma */ + {0x30, 0x0004, 0x000a}, + {0xb0, 0x0001, 0x0000}, + + + {0x0a1, 0x0080, 0x0001}, + {0x30, 0x0049, 0x0000}, + {0x30, 0x0060, 0x0005}, + {0x0c, 0x0004, 0x0000}, + {0x00, 0x0000, 0x0000}, + {0x00, 0x0000, 0x2000}, + {0x00, 0x0013, 0x2301}, + {0x00, 0x0003, 0x2000}, + {0x00, 0x0000, 0x2000}, + + {} +}; + +/* clicksmart 420 open data ? */ +static const __u16 spca504A_clicksmart420_open_data[][3] = { + {0x00, 0x0001, 0x2501}, + {0x20, 0x0502, 0x0000}, + {0x06, 0x0000, 0x0000}, + {0x00, 0x0004, 0x2880}, + {0x00, 0x0001, 0x2881}, +/* look like setting a qTable */ + {0x00, 0x0006, 0x2800}, + {0x00, 0x0004, 0x2801}, + {0x00, 0x0004, 0x2802}, + {0x00, 0x0006, 0x2803}, + {0x00, 0x000a, 0x2804}, + {0x00, 0x0010, 0x2805}, + {0x00, 0x0014, 0x2806}, + {0x00, 0x0018, 0x2807}, + {0x00, 0x0005, 0x2808}, + {0x00, 0x0005, 0x2809}, + {0x00, 0x0006, 0x280a}, + {0x00, 0x0008, 0x280b}, + {0x00, 0x000a, 0x280c}, + {0x00, 0x0017, 0x280d}, + {0x00, 0x0018, 0x280e}, + {0x00, 0x0016, 0x280f}, + + {0x00, 0x0006, 0x2810}, + {0x00, 0x0005, 0x2811}, + {0x00, 0x0006, 0x2812}, + {0x00, 0x000a, 0x2813}, + {0x00, 0x0010, 0x2814}, + {0x00, 0x0017, 0x2815}, + {0x00, 0x001c, 0x2816}, + {0x00, 0x0016, 0x2817}, + {0x00, 0x0006, 0x2818}, + {0x00, 0x0007, 0x2819}, + {0x00, 0x0009, 0x281a}, + {0x00, 0x000c, 0x281b}, + {0x00, 0x0014, 0x281c}, + {0x00, 0x0023, 0x281d}, + {0x00, 0x0020, 0x281e}, + {0x00, 0x0019, 0x281f}, + + {0x00, 0x0007, 0x2820}, + {0x00, 0x0009, 0x2821}, + {0x00, 0x000f, 0x2822}, + {0x00, 0x0016, 0x2823}, + {0x00, 0x001b, 0x2824}, + {0x00, 0x002c, 0x2825}, + {0x00, 0x0029, 0x2826}, + {0x00, 0x001f, 0x2827}, + {0x00, 0x000a, 0x2828}, + {0x00, 0x000e, 0x2829}, + {0x00, 0x0016, 0x282a}, + {0x00, 0x001a, 0x282b}, + {0x00, 0x0020, 0x282c}, + {0x00, 0x002a, 0x282d}, + {0x00, 0x002d, 0x282e}, + {0x00, 0x0025, 0x282f}, + + {0x00, 0x0014, 0x2830}, + {0x00, 0x001a, 0x2831}, + {0x00, 0x001f, 0x2832}, + {0x00, 0x0023, 0x2833}, + {0x00, 0x0029, 0x2834}, + {0x00, 0x0030, 0x2835}, + {0x00, 0x0030, 0x2836}, + {0x00, 0x0028, 0x2837}, + {0x00, 0x001d, 0x2838}, + {0x00, 0x0025, 0x2839}, + {0x00, 0x0026, 0x283a}, + {0x00, 0x0027, 0x283b}, + {0x00, 0x002d, 0x283c}, + {0x00, 0x0028, 0x283d}, + {0x00, 0x0029, 0x283e}, + {0x00, 0x0028, 0x283f}, + + {0x00, 0x0007, 0x2840}, + {0x00, 0x0007, 0x2841}, + {0x00, 0x000a, 0x2842}, + {0x00, 0x0013, 0x2843}, + {0x00, 0x0028, 0x2844}, + {0x00, 0x0028, 0x2845}, + {0x00, 0x0028, 0x2846}, + {0x00, 0x0028, 0x2847}, + {0x00, 0x0007, 0x2848}, + {0x00, 0x0008, 0x2849}, + {0x00, 0x000a, 0x284a}, + {0x00, 0x001a, 0x284b}, + {0x00, 0x0028, 0x284c}, + {0x00, 0x0028, 0x284d}, + {0x00, 0x0028, 0x284e}, + {0x00, 0x0028, 0x284f}, + + {0x00, 0x000a, 0x2850}, + {0x00, 0x000a, 0x2851}, + {0x00, 0x0016, 0x2852}, + {0x00, 0x0028, 0x2853}, + {0x00, 0x0028, 0x2854}, + {0x00, 0x0028, 0x2855}, + {0x00, 0x0028, 0x2856}, + {0x00, 0x0028, 0x2857}, + {0x00, 0x0013, 0x2858}, + {0x00, 0x001a, 0x2859}, + {0x00, 0x0028, 0x285a}, + {0x00, 0x0028, 0x285b}, + {0x00, 0x0028, 0x285c}, + {0x00, 0x0028, 0x285d}, + {0x00, 0x0028, 0x285e}, + {0x00, 0x0028, 0x285f}, + + {0x00, 0x0028, 0x2860}, + {0x00, 0x0028, 0x2861}, + {0x00, 0x0028, 0x2862}, + {0x00, 0x0028, 0x2863}, + {0x00, 0x0028, 0x2864}, + {0x00, 0x0028, 0x2865}, + {0x00, 0x0028, 0x2866}, + {0x00, 0x0028, 0x2867}, + {0x00, 0x0028, 0x2868}, + {0x00, 0x0028, 0x2869}, + {0x00, 0x0028, 0x286a}, + {0x00, 0x0028, 0x286b}, + {0x00, 0x0028, 0x286c}, + {0x00, 0x0028, 0x286d}, + {0x00, 0x0028, 0x286e}, + {0x00, 0x0028, 0x286f}, + + {0x00, 0x0028, 0x2870}, + {0x00, 0x0028, 0x2871}, + {0x00, 0x0028, 0x2872}, + {0x00, 0x0028, 0x2873}, + {0x00, 0x0028, 0x2874}, + {0x00, 0x0028, 0x2875}, + {0x00, 0x0028, 0x2876}, + {0x00, 0x0028, 0x2877}, + {0x00, 0x0028, 0x2878}, + {0x00, 0x0028, 0x2879}, + {0x00, 0x0028, 0x287a}, + {0x00, 0x0028, 0x287b}, + {0x00, 0x0028, 0x287c}, + {0x00, 0x0028, 0x287d}, + {0x00, 0x0028, 0x287e}, + {0x00, 0x0028, 0x287f}, + + {0xa0, 0x0000, 0x0503}, + {} +}; + +static const __u8 qtable_creative_pccam[2][64] = { + { /* Q-table Y-components */ + 0x05, 0x03, 0x03, 0x05, 0x07, 0x0c, 0x0f, 0x12, + 0x04, 0x04, 0x04, 0x06, 0x08, 0x11, 0x12, 0x11, + 0x04, 0x04, 0x05, 0x07, 0x0c, 0x11, 0x15, 0x11, + 0x04, 0x05, 0x07, 0x09, 0x0f, 0x1a, 0x18, 0x13, + 0x05, 0x07, 0x0b, 0x11, 0x14, 0x21, 0x1f, 0x17, + 0x07, 0x0b, 0x11, 0x13, 0x18, 0x1f, 0x22, 0x1c, + 0x0f, 0x13, 0x17, 0x1a, 0x1f, 0x24, 0x24, 0x1e, + 0x16, 0x1c, 0x1d, 0x1d, 0x22, 0x1e, 0x1f, 0x1e}, + { /* Q-table C-components */ + 0x05, 0x05, 0x07, 0x0e, 0x1e, 0x1e, 0x1e, 0x1e, + 0x05, 0x06, 0x08, 0x14, 0x1e, 0x1e, 0x1e, 0x1e, + 0x07, 0x08, 0x11, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, + 0x0e, 0x14, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, + 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, + 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, + 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, + 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e} +}; + +/* FIXME: This Q-table is identical to the Creative PC-CAM one, + * except for one byte. Possibly a typo? + * NWG: 18/05/2003. + */ +static const __u8 qtable_spca504_default[2][64] = { + { /* Q-table Y-components */ + 0x05, 0x03, 0x03, 0x05, 0x07, 0x0c, 0x0f, 0x12, + 0x04, 0x04, 0x04, 0x06, 0x08, 0x11, 0x12, 0x11, + 0x04, 0x04, 0x05, 0x07, 0x0c, 0x11, 0x15, 0x11, + 0x04, 0x05, 0x07, 0x09, 0x0f, 0x1a, 0x18, 0x13, + 0x05, 0x07, 0x0b, 0x11, 0x14, 0x21, 0x1f, 0x17, + 0x07, 0x0b, 0x11, 0x13, 0x18, 0x1f, 0x22, 0x1c, + 0x0f, 0x13, 0x17, 0x1a, 0x1f, 0x24, 0x24, 0x1e, + 0x16, 0x1c, 0x1d, 0x1d, 0x1d /* 0x22 */ , 0x1e, 0x1f, 0x1e, + }, + { /* Q-table C-components */ + 0x05, 0x05, 0x07, 0x0e, 0x1e, 0x1e, 0x1e, 0x1e, + 0x05, 0x06, 0x08, 0x14, 0x1e, 0x1e, 0x1e, 0x1e, + 0x07, 0x08, 0x11, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, + 0x0e, 0x14, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, + 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, + 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, + 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, + 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e} +}; + +static void reg_r(struct usb_device *dev, + __u16 req, + __u16 index, + __u8 *buffer, __u16 length) +{ + usb_control_msg(dev, + usb_rcvctrlpipe(dev, 0), + req, + USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + 0, /* value */ + index, buffer, length, + 500); +} + +static void reg_w(struct usb_device *dev, + __u16 req, + __u16 value, + __u16 index, + __u8 *buffer, __u16 length) +{ + usb_control_msg(dev, + usb_sndctrlpipe(dev, 0), + req, + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + value, index, buffer, length, + 500); +} + +/* write req / index / value */ +static int reg_w_riv(struct usb_device *dev, + __u16 req, __u16 index, __u16 value) +{ + int ret; + + ret = usb_control_msg(dev, + usb_sndctrlpipe(dev, 0), + req, + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + value, index, NULL, 0, 500); + PDEBUG(D_USBO, "reg write: 0x%02x,0x%02x:0x%02x, %d", + req, index, value, ret); + if (ret < 0) + PDEBUG(D_ERR, "reg write: error %d", ret); + return ret; +} + +/* read 1 byte */ +static int reg_r_1(struct gspca_dev *gspca_dev, + __u16 value) /* wValue */ +{ + int ret; + + ret = usb_control_msg(gspca_dev->dev, + usb_rcvctrlpipe(gspca_dev->dev, 0), + 0x20, /* request */ + USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + value, + 0, /* index */ + gspca_dev->usb_buf, 1, + 500); /* timeout */ + if (ret < 0) { + PDEBUG(D_ERR, "reg_r_1 err %d", ret); + return 0; + } + return gspca_dev->usb_buf[0]; +} + +/* read 1 or 2 bytes - returns < 0 if error */ +static int reg_r_12(struct gspca_dev *gspca_dev, + __u16 req, /* bRequest */ + __u16 index, /* wIndex */ + __u16 length) /* wLength (1 or 2 only) */ +{ + int ret; + + gspca_dev->usb_buf[1] = 0; + ret = usb_control_msg(gspca_dev->dev, + usb_rcvctrlpipe(gspca_dev->dev, 0), + req, + USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + 0, /* value */ + index, + gspca_dev->usb_buf, length, + 500); + if (ret < 0) { + PDEBUG(D_ERR, "reg_read err %d", ret); + return -1; + } + return (gspca_dev->usb_buf[1] << 8) + gspca_dev->usb_buf[0]; +} + +static int write_vector(struct gspca_dev *gspca_dev, + const __u16 data[][3]) +{ + struct usb_device *dev = gspca_dev->dev; + int ret, i = 0; + + while (data[i][0] != 0 || data[i][1] != 0 || data[i][2] != 0) { + ret = reg_w_riv(dev, data[i][0], data[i][2], data[i][1]); + if (ret < 0) { + PDEBUG(D_ERR, + "Register write failed for 0x%x,0x%x,0x%x", + data[i][0], data[i][1], data[i][2]); + return ret; + } + i++; + } + return 0; +} + +static int spca50x_setup_qtable(struct gspca_dev *gspca_dev, + unsigned int request, + unsigned int ybase, + unsigned int cbase, + const __u8 qtable[2][64]) +{ + struct usb_device *dev = gspca_dev->dev; + int i, err; + + /* loop over y components */ + for (i = 0; i < 64; i++) { + err = reg_w_riv(dev, request, ybase + i, qtable[0][i]); + if (err < 0) + return err; + } + + /* loop over c components */ + for (i = 0; i < 64; i++) { + err = reg_w_riv(dev, request, cbase + i, qtable[1][i]); + if (err < 0) + return err; + } + return 0; +} + +static void spca504_acknowledged_command(struct gspca_dev *gspca_dev, + __u16 req, __u16 idx, __u16 val) +{ + struct usb_device *dev = gspca_dev->dev; + __u8 notdone; + + reg_w_riv(dev, req, idx, val); + notdone = reg_r_12(gspca_dev, 0x01, 0x0001, 1); + reg_w_riv(dev, req, idx, val); + + PDEBUG(D_FRAM, "before wait 0x%x", notdone); + + msleep(200); + notdone = reg_r_12(gspca_dev, 0x01, 0x0001, 1); + PDEBUG(D_FRAM, "after wait 0x%x", notdone); +} + +static void spca504A_acknowledged_command(struct gspca_dev *gspca_dev, + __u16 req, + __u16 idx, __u16 val, __u8 stat, __u8 count) +{ + struct usb_device *dev = gspca_dev->dev; + __u8 status; + __u8 endcode; + + reg_w_riv(dev, req, idx, val); + status = reg_r_12(gspca_dev, 0x01, 0x0001, 1); + endcode = stat; + PDEBUG(D_FRAM, "Status 0x%x Need 0x%x", status, stat); + if (!count) + return; + count = 200; + while (--count > 0) { + msleep(10); + /* gsmart mini2 write a each wait setting 1 ms is enought */ +/* reg_w_riv(dev, req, idx, val); */ + status = reg_r_12(gspca_dev, 0x01, 0x0001, 1); + if (status == endcode) { + PDEBUG(D_FRAM, "status 0x%x after wait 0x%x", + status, 200 - count); + break; + } + } +} + +static int spca504B_PollingDataReady(struct gspca_dev *gspca_dev) +{ + int count = 10; + + while (--count > 0) { + reg_r(gspca_dev->dev, 0x21, 0, gspca_dev->usb_buf, 1); + if ((gspca_dev->usb_buf[0] & 0x01) == 0) + break; + msleep(10); + } + return gspca_dev->usb_buf[0]; +} + +static void spca504B_WaitCmdStatus(struct gspca_dev *gspca_dev) +{ + struct usb_device *dev = gspca_dev->dev; + int count = 50; + + while (--count > 0) { + reg_r(dev, 0x21, 1, gspca_dev->usb_buf, 1); + if (gspca_dev->usb_buf[0] != 0) { + gspca_dev->usb_buf[0] = 0; + reg_w(dev, 0x21, 0, 1, gspca_dev->usb_buf, 1); + reg_r(dev, 0x21, 1, gspca_dev->usb_buf, 1); + spca504B_PollingDataReady(gspca_dev); + break; + } + msleep(10); + } +} + +static void spca50x_GetFirmware(struct gspca_dev *gspca_dev) +{ + struct usb_device *dev = gspca_dev->dev; + __u8 *data; + + data = kmalloc(64, GFP_KERNEL); + reg_r(dev, 0x20, 0, data, 5); + PDEBUG(D_STREAM, "FirmWare : %d %d %d %d %d ", + data[0], data[1], data[2], data[3], data[4]); + reg_r(dev, 0x23, 0, data, 64); + reg_r(dev, 0x23, 1, data, 64); + kfree(data); +} + +static void spca504B_SetSizeType(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + struct usb_device *dev = gspca_dev->dev; + __u8 Size; + __u8 Type; + int rc; + + Size = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv; + Type = 0; + switch (sd->bridge) { + case BRIDGE_SPCA533: + reg_w(dev, 0x31, 0, 0, NULL, 0); + spca504B_WaitCmdStatus(gspca_dev); + rc = spca504B_PollingDataReady(gspca_dev); + spca50x_GetFirmware(gspca_dev); + gspca_dev->usb_buf[0] = 2; /* type */ + reg_w(dev, 0x24, 0, 8, gspca_dev->usb_buf, 1); + reg_r(dev, 0x24, 8, gspca_dev->usb_buf, 1); + + gspca_dev->usb_buf[0] = Size; + reg_w(dev, 0x25, 0, 4, gspca_dev->usb_buf, 1); + reg_r(dev, 0x25, 4, gspca_dev->usb_buf, 1); /* size */ + rc = spca504B_PollingDataReady(gspca_dev); + + /* Init the cam width height with some values get on init ? */ + reg_w(dev, 0x31, 0, 4, NULL, 0); + spca504B_WaitCmdStatus(gspca_dev); + rc = spca504B_PollingDataReady(gspca_dev); + break; + default: +/* case BRIDGE_SPCA504B: */ +/* case BRIDGE_SPCA536: */ + gspca_dev->usb_buf[0] = Size; + reg_w(dev, 0x25, 0, 4, gspca_dev->usb_buf, 1); + reg_r(dev, 0x25, 4, gspca_dev->usb_buf, 1); /* size */ + Type = 6; + gspca_dev->usb_buf[0] = Type; + reg_w(dev, 0x27, 0, 0, gspca_dev->usb_buf, 1); + reg_r(dev, 0x27, 0, gspca_dev->usb_buf, 1); /* type */ + rc = spca504B_PollingDataReady(gspca_dev); + break; + case BRIDGE_SPCA504: + Size += 3; + if (sd->subtype == AiptekMiniPenCam13) { + /* spca504a aiptek */ + spca504A_acknowledged_command(gspca_dev, + 0x08, Size, 0, + 0x80 | (Size & 0x0f), 1); + spca504A_acknowledged_command(gspca_dev, + 1, 3, 0, 0x9f, 0); + } else { + spca504_acknowledged_command(gspca_dev, 0x08, Size, 0); + } + break; + case BRIDGE_SPCA504C: + /* capture mode */ + reg_w_riv(dev, 0xa0, (0x0500 | (Size & 0x0f)), 0x00); + reg_w_riv(dev, 0x20, 0x01, 0x0500 | (Size & 0x0f)); + break; + } +} + +static void spca504_wait_status(struct gspca_dev *gspca_dev) +{ + int cnt; + + cnt = 256; + while (--cnt > 0) { + /* With this we get the status, when return 0 it's all ok */ + if (reg_r_12(gspca_dev, 0x06, 0x00, 1) == 0) + return; + msleep(10); + } +} + +static void spca504B_setQtable(struct gspca_dev *gspca_dev) +{ + struct usb_device *dev = gspca_dev->dev; + + gspca_dev->usb_buf[0] = 3; + reg_w(dev, 0x26, 0, 0, gspca_dev->usb_buf, 1); + reg_r(dev, 0x26, 0, gspca_dev->usb_buf, 1); + spca504B_PollingDataReady(gspca_dev); +} + +static void sp5xx_initContBrigHueRegisters(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + struct usb_device *dev = gspca_dev->dev; + int pollreg = 1; + + switch (sd->bridge) { + case BRIDGE_SPCA504: + case BRIDGE_SPCA504C: + pollreg = 0; + /* fall thru */ + default: +/* case BRIDGE_SPCA533: */ +/* case BRIDGE_SPCA504B: */ + reg_w(dev, 0, 0, 0x21a7, NULL, 0); /* brightness */ + reg_w(dev, 0, 0x20, 0x21a8, NULL, 0); /* contrast */ + reg_w(dev, 0, 0, 0x21ad, NULL, 0); /* hue */ + reg_w(dev, 0, 1, 0x21ac, NULL, 0); /* sat/hue */ + reg_w(dev, 0, 0x20, 0x21ae, NULL, 0); /* saturation */ + reg_w(dev, 0, 0, 0x21a3, NULL, 0); /* gamma */ + break; + case BRIDGE_SPCA536: + reg_w(dev, 0, 0, 0x20f0, NULL, 0); + reg_w(dev, 0, 0x21, 0x20f1, NULL, 0); + reg_w(dev, 0, 0x40, 0x20f5, NULL, 0); + reg_w(dev, 0, 1, 0x20f4, NULL, 0); + reg_w(dev, 0, 0x40, 0x20f6, NULL, 0); + reg_w(dev, 0, 0, 0x2089, NULL, 0); + break; + } + if (pollreg) + spca504B_PollingDataReady(gspca_dev); +} + +/* this function is called at probe time */ +static int sd_config(struct gspca_dev *gspca_dev, + const struct usb_device_id *id) +{ + struct sd *sd = (struct sd *) gspca_dev; + struct usb_device *dev = gspca_dev->dev; + struct cam *cam; + __u16 vendor; + __u16 product; + __u8 fw; + + vendor = id->idVendor; + product = id->idProduct; + switch (vendor) { + case 0x041e: /* Creative cameras */ +/* switch (product) { */ +/* case 0x400b: */ +/* case 0x4012: */ +/* case 0x4013: */ +/* sd->bridge = BRIDGE_SPCA504C; */ +/* break; */ +/* } */ + break; + case 0x0458: /* Genius KYE cameras */ +/* switch (product) { */ +/* case 0x7006: */ + sd->bridge = BRIDGE_SPCA504B; +/* break; */ +/* } */ + break; + case 0x0461: /* MicroInnovation */ +/* switch (product) { */ +/* case 0x0821: */ + sd->bridge = BRIDGE_SPCA533; +/* break; */ +/* } */ + break; + case 0x046d: /* Logitech Labtec */ + switch (product) { + case 0x0905: + sd->subtype = LogitechClickSmart820; + sd->bridge = BRIDGE_SPCA533; + break; + case 0x0960: + sd->subtype = LogitechClickSmart420; + sd->bridge = BRIDGE_SPCA504C; + break; + } + break; + case 0x0471: /* Philips */ +/* switch (product) { */ +/* case 0x0322: */ + sd->bridge = BRIDGE_SPCA504B; +/* break; */ +/* } */ + break; + case 0x04a5: /* Benq */ + switch (product) { + case 0x3003: + sd->bridge = BRIDGE_SPCA504B; + break; + case 0x3008: + case 0x300a: + sd->bridge = BRIDGE_SPCA533; + break; + } + break; + case 0x04f1: /* JVC */ +/* switch (product) { */ +/* case 0x1001: */ + sd->bridge = BRIDGE_SPCA504B; +/* break; */ +/* } */ + break; + case 0x04fc: /* SunPlus */ + switch (product) { + case 0x500c: + sd->bridge = BRIDGE_SPCA504B; + break; + case 0x504a: +/* try to get the firmware as some cam answer 2.0.1.2.2 + * and should be a spca504b then overwrite that setting */ + reg_r(dev, 0x20, 0, gspca_dev->usb_buf, 1); + fw = gspca_dev->usb_buf[0]; + if (fw == 1) { + sd->subtype = AiptekMiniPenCam13; + sd->bridge = BRIDGE_SPCA504; + } else if (fw == 2) { + sd->bridge = BRIDGE_SPCA504B; + } else + return -ENODEV; + break; + case 0x504b: + sd->bridge = BRIDGE_SPCA504B; + break; + case 0x5330: + sd->bridge = BRIDGE_SPCA533; + break; + case 0x5360: + sd->bridge = BRIDGE_SPCA536; + break; + case 0xffff: + sd->bridge = BRIDGE_SPCA504B; + break; + } + break; + case 0x052b: /* ?? Megapix */ +/* switch (product) { */ +/* case 0x1513: */ + sd->subtype = MegapixV4; + sd->bridge = BRIDGE_SPCA533; +/* break; */ +/* } */ + break; + case 0x0546: /* Polaroid */ + switch (product) { + case 0x3155: + sd->bridge = BRIDGE_SPCA533; + break; + case 0x3191: + case 0x3273: + sd->bridge = BRIDGE_SPCA504B; + break; + } + break; + case 0x055f: /* Mustek cameras */ + switch (product) { + case 0xc211: + sd->bridge = BRIDGE_SPCA536; + break; + case 0xc230: + case 0xc232: + sd->bridge = BRIDGE_SPCA533; + break; + case 0xc360: + sd->bridge = BRIDGE_SPCA536; + break; + case 0xc420: + sd->bridge = BRIDGE_SPCA504; + break; + case 0xc430: + case 0xc440: + sd->bridge = BRIDGE_SPCA533; + break; + case 0xc520: + sd->bridge = BRIDGE_SPCA504; + break; + case 0xc530: + case 0xc540: + case 0xc630: + case 0xc650: + sd->bridge = BRIDGE_SPCA533; + break; + } + break; + case 0x05da: /* Digital Dream cameras */ +/* switch (product) { */ +/* case 0x1018: */ + sd->bridge = BRIDGE_SPCA504B; +/* break; */ +/* } */ + break; + case 0x06d6: /* Trust */ +/* switch (product) { */ +/* case 0x0031: */ + sd->bridge = BRIDGE_SPCA533; /* SPCA533A */ +/* break; */ +/* } */ + break; + case 0x0733: /* Rebadged ViewQuest (Intel) and ViewQuest cameras */ + switch (product) { + case 0x1311: + case 0x1314: + case 0x2211: + case 0x2221: + sd->bridge = BRIDGE_SPCA533; + break; + case 0x3261: + case 0x3281: + sd->bridge = BRIDGE_SPCA536; + break; + } + break; + case 0x08ca: /* Aiptek */ + switch (product) { + case 0x0104: + case 0x0106: + sd->bridge = BRIDGE_SPCA533; + break; + case 0x2008: + sd->bridge = BRIDGE_SPCA504B; + break; + case 0x2010: + sd->bridge = BRIDGE_SPCA533; + break; + case 0x2016: + case 0x2018: + sd->bridge = BRIDGE_SPCA504B; + break; + case 0x2020: + case 0x2022: + sd->bridge = BRIDGE_SPCA533; + break; + case 0x2024: + sd->bridge = BRIDGE_SPCA536; + break; + case 0x2028: + sd->bridge = BRIDGE_SPCA533; + break; + case 0x2040: + case 0x2042: + case 0x2050: + case 0x2060: + sd->bridge = BRIDGE_SPCA536; + break; + } + break; + case 0x0d64: /* SunPlus */ +/* switch (product) { */ +/* case 0x0303: */ + sd->bridge = BRIDGE_SPCA536; +/* break; */ +/* } */ + break; + } + + cam = &gspca_dev->cam; + cam->dev_name = (char *) id->driver_info; + cam->epaddr = 0x01; + + switch (sd->bridge) { + default: +/* case BRIDGE_SPCA504B: */ +/* case BRIDGE_SPCA504: */ +/* case BRIDGE_SPCA536: */ + cam->cam_mode = vga_mode; + cam->nmodes = sizeof vga_mode / sizeof vga_mode[0]; + break; + case BRIDGE_SPCA533: + cam->cam_mode = custom_mode; + cam->nmodes = sizeof custom_mode / sizeof custom_mode[0]; + break; + case BRIDGE_SPCA504C: + cam->cam_mode = vga_mode2; + cam->nmodes = sizeof vga_mode2 / sizeof vga_mode2[0]; + break; + } + sd->qindex = 5; /* set the quantization table */ + sd->brightness = sd_ctrls[SD_BRIGHTNESS].qctrl.default_value; + sd->contrast = sd_ctrls[SD_CONTRAST].qctrl.default_value; + sd->colors = sd_ctrls[SD_COLOR].qctrl.default_value; + return 0; +} + +/* this function is called at open time */ +static int sd_open(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + struct usb_device *dev = gspca_dev->dev; + int rc; + __u8 i; + __u8 info[6]; + int err_code; + + switch (sd->bridge) { + case BRIDGE_SPCA504B: + reg_w(dev, 0x1d, 0, 0, NULL, 0); + reg_w(dev, 0, 1, 0x2306, NULL, 0); + reg_w(dev, 0, 0, 0x0d04, NULL, 0); + reg_w(dev, 0, 0, 0x2000, NULL, 0); + reg_w(dev, 0, 0x13, 0x2301, NULL, 0); + reg_w(dev, 0, 0, 0x2306, NULL, 0); + /* fall thru */ + case BRIDGE_SPCA533: + rc = spca504B_PollingDataReady(gspca_dev); + spca50x_GetFirmware(gspca_dev); + break; + case BRIDGE_SPCA536: + spca50x_GetFirmware(gspca_dev); + reg_r(dev, 0x00, 0x5002, gspca_dev->usb_buf, 1); + gspca_dev->usb_buf[0] = 0; + reg_w(dev, 0x24, 0, 0, gspca_dev->usb_buf, 1); + reg_r(dev, 0x24, 0, gspca_dev->usb_buf, 1); + rc = spca504B_PollingDataReady(gspca_dev); + reg_w(dev, 0x34, 0, 0, NULL, 0); + spca504B_WaitCmdStatus(gspca_dev); + break; + case BRIDGE_SPCA504C: /* pccam600 */ + PDEBUG(D_STREAM, "Opening SPCA504 (PC-CAM 600)"); + reg_w_riv(dev, 0xe0, 0x0000, 0x0000); + reg_w_riv(dev, 0xe0, 0x0000, 0x0001); /* reset */ + spca504_wait_status(gspca_dev); + if (sd->subtype == LogitechClickSmart420) + write_vector(gspca_dev, + spca504A_clicksmart420_open_data); + else + write_vector(gspca_dev, spca504_pccam600_open_data); + err_code = spca50x_setup_qtable(gspca_dev, + 0x00, 0x2800, + 0x2840, qtable_creative_pccam); + if (err_code < 0) { + PDEBUG(D_ERR|D_STREAM, "spca50x_setup_qtable failed"); + return err_code; + } + break; + default: +/* case BRIDGE_SPCA504: */ + PDEBUG(D_STREAM, "Opening SPCA504"); + if (sd->subtype == AiptekMiniPenCam13) { + /*****************************/ + for (i = 0; i < 6; i++) + info[i] = reg_r_1(gspca_dev, i); + PDEBUG(D_STREAM, + "Read info: %d %d %d %d %d %d." + " Should be 1,0,2,2,0,0", + info[0], info[1], info[2], + info[3], info[4], info[5]); + /* spca504a aiptek */ + /* Set AE AWB Banding Type 3-> 50Hz 2-> 60Hz */ + spca504A_acknowledged_command(gspca_dev, 0x24, + 8, 3, 0x9e, 1); + /* Twice sequencial need status 0xff->0x9e->0x9d */ + spca504A_acknowledged_command(gspca_dev, 0x24, + 8, 3, 0x9e, 0); + + spca504A_acknowledged_command(gspca_dev, 0x24, + 0, 0, 0x9d, 1); + /******************************/ + /* spca504a aiptek */ + spca504A_acknowledged_command(gspca_dev, 0x08, + 6, 0, 0x86, 1); +/* reg_write (dev, 0, 0x2000, 0); */ +/* reg_write (dev, 0, 0x2883, 1); */ +/* spca504A_acknowledged_command (gspca_dev, 0x08, + 6, 0, 0x86, 1); */ +/* spca504A_acknowledged_command (gspca_dev, 0x24, + 0, 0, 0x9D, 1); */ + reg_w_riv(dev, 0x0, 0x270c, 0x05); /* L92 sno1t.txt */ + reg_w_riv(dev, 0x0, 0x2310, 0x05); + spca504A_acknowledged_command(gspca_dev, 0x01, + 0x0f, 0, 0xff, 0); + } + /* setup qtable */ + reg_w_riv(dev, 0, 0x2000, 0); + reg_w_riv(dev, 0, 0x2883, 1); + err_code = spca50x_setup_qtable(gspca_dev, + 0x00, 0x2800, + 0x2840, + qtable_spca504_default); + if (err_code < 0) { + PDEBUG(D_ERR, "spca50x_setup_qtable failed"); + return err_code; + } + break; + } + return 0; +} + +static void sd_start(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + struct usb_device *dev = gspca_dev->dev; + int rc; + int enable; + __u8 i; + __u8 info[6]; + + if (sd->bridge == BRIDGE_SPCA504B) + spca504B_setQtable(gspca_dev); + spca504B_SetSizeType(gspca_dev); + switch (sd->bridge) { + default: +/* case BRIDGE_SPCA504B: */ +/* case BRIDGE_SPCA533: */ +/* case BRIDGE_SPCA536: */ + if (sd->subtype == MegapixV4 || + sd->subtype == LogitechClickSmart820) { + reg_w(dev, 0xf0, 0, 0, NULL, 0); + spca504B_WaitCmdStatus(gspca_dev); + reg_r(dev, 0xf0, 4, NULL, 0); + spca504B_WaitCmdStatus(gspca_dev); + } else { + reg_w(dev, 0x31, 0, 4, NULL, 0); + spca504B_WaitCmdStatus(gspca_dev); + rc = spca504B_PollingDataReady(gspca_dev); + } + break; + case BRIDGE_SPCA504: + if (sd->subtype == AiptekMiniPenCam13) { + for (i = 0; i < 6; i++) + info[i] = reg_r_1(gspca_dev, i); + PDEBUG(D_STREAM, + "Read info: %d %d %d %d %d %d." + " Should be 1,0,2,2,0,0", + info[0], info[1], info[2], + info[3], info[4], info[5]); + /* spca504a aiptek */ + /* Set AE AWB Banding Type 3-> 50Hz 2-> 60Hz */ + spca504A_acknowledged_command(gspca_dev, 0x24, + 8, 3, 0x9e, 1); + /* Twice sequencial need status 0xff->0x9e->0x9d */ + spca504A_acknowledged_command(gspca_dev, 0x24, + 8, 3, 0x9e, 0); + spca504A_acknowledged_command(gspca_dev, 0x24, + 0, 0, 0x9d, 1); + } else { + spca504_acknowledged_command(gspca_dev, 0x24, 8, 3); + for (i = 0; i < 6; i++) + info[i] = reg_r_1(gspca_dev, i); + PDEBUG(D_STREAM, + "Read info: %d %d %d %d %d %d." + " Should be 1,0,2,2,0,0", + info[0], info[1], info[2], + info[3], info[4], info[5]); + spca504_acknowledged_command(gspca_dev, 0x24, 8, 3); + spca504_acknowledged_command(gspca_dev, 0x24, 0, 0); + } + spca504B_SetSizeType(gspca_dev); + reg_w_riv(dev, 0x0, 0x270c, 0x05); /* L92 sno1t.txt */ + reg_w_riv(dev, 0x0, 0x2310, 0x05); + break; + case BRIDGE_SPCA504C: + if (sd->subtype == LogitechClickSmart420) { + write_vector(gspca_dev, + spca504A_clicksmart420_init_data); + } else { + write_vector(gspca_dev, spca504_pccam600_init_data); + } + enable = (sd->autogain ? 0x04 : 0x01); + reg_w_riv(dev, 0x0c, 0x0000, enable); /* auto exposure */ + reg_w_riv(dev, 0xb0, 0x0000, enable); /* auto whiteness */ + + /* set default exposure compensation and whiteness balance */ + reg_w_riv(dev, 0x30, 0x0001, 800); /* ~ 20 fps */ + reg_w_riv(dev, 0x30, 0x0002, 1600); + spca504B_SetSizeType(gspca_dev); + break; + } + sp5xx_initContBrigHueRegisters(gspca_dev); +} + +static void sd_stopN(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + struct usb_device *dev = gspca_dev->dev; + + switch (sd->bridge) { + default: +/* case BRIDGE_SPCA533: */ +/* case BRIDGE_SPCA536: */ +/* case BRIDGE_SPCA504B: */ + reg_w(dev, 0x31, 0, 0, NULL, 0); + spca504B_WaitCmdStatus(gspca_dev); + spca504B_PollingDataReady(gspca_dev); + break; + case BRIDGE_SPCA504: + case BRIDGE_SPCA504C: + reg_w_riv(dev, 0x00, 0x2000, 0x0000); + + if (sd->subtype == AiptekMiniPenCam13) { + /* spca504a aiptek */ +/* spca504A_acknowledged_command(gspca_dev, 0x08, + 6, 0, 0x86, 1); */ + spca504A_acknowledged_command(gspca_dev, 0x24, + 0x00, 0x00, 0x9d, 1); + spca504A_acknowledged_command(gspca_dev, 0x01, + 0x0f, 0x00, 0xff, 1); + } else { + spca504_acknowledged_command(gspca_dev, 0x24, 0, 0); + reg_w_riv(dev, 0x01, 0x000f, 0x00); + } + break; + } +} + +static void sd_stop0(struct gspca_dev *gspca_dev) +{ +} + +static void sd_close(struct gspca_dev *gspca_dev) +{ +} + +static void sd_pkt_scan(struct gspca_dev *gspca_dev, + struct gspca_frame *frame, /* target */ + __u8 *data, /* isoc packet */ + int len) /* iso packet length */ +{ + struct sd *sd = (struct sd *) gspca_dev; + int i, sof = 0; + unsigned char *s, *d; + static unsigned char ffd9[] = {0xff, 0xd9}; + +/* frames are jpeg 4.1.1 without 0xff escape */ + switch (sd->bridge) { + case BRIDGE_SPCA533: + if (data[0] == 0xff) { + if (data[1] != 0x01) { /* drop packet */ +/* gspca_dev->last_packet_type = DISCARD_PACKET; */ + return; + } + sof = 1; + data += SPCA533_OFFSET_DATA; + len -= SPCA533_OFFSET_DATA; + } else { + data += 1; + len -= 1; + } + break; + case BRIDGE_SPCA536: + if (data[0] == 0xff) { + sof = 1; + data += SPCA536_OFFSET_DATA; + len -= SPCA536_OFFSET_DATA; + } else { + data += 2; + len -= 2; + } + break; + default: +/* case BRIDGE_SPCA504: */ +/* case BRIDGE_SPCA504B: */ + switch (data[0]) { + case 0xfe: /* start of frame */ + sof = 1; + data += SPCA50X_OFFSET_DATA; + len -= SPCA50X_OFFSET_DATA; + break; + case 0xff: /* drop packet */ +/* gspca_dev->last_packet_type = DISCARD_PACKET; */ + return; + default: + data += 1; + len -= 1; + break; + } + break; + case BRIDGE_SPCA504C: + switch (data[0]) { + case 0xfe: /* start of frame */ + sof = 1; + data += SPCA504_PCCAM600_OFFSET_DATA; + len -= SPCA504_PCCAM600_OFFSET_DATA; + break; + case 0xff: /* drop packet */ +/* gspca_dev->last_packet_type = DISCARD_PACKET; */ + return; + default: + data += 1; + len -= 1; + break; + } + break; + } + if (sof) { /* start of frame */ + frame = gspca_frame_add(gspca_dev, LAST_PACKET, frame, + ffd9, 2); + + /* put the JPEG header in the new frame */ + jpeg_put_header(gspca_dev, frame, + ((struct sd *) gspca_dev)->qindex, + 0x22); + } + + /* add 0x00 after 0xff */ + for (i = len; --i >= 0; ) + if (data[i] == 0xff) + break; + if (i < 0) { /* no 0xff */ + gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len); + return; + } + s = data; + d = sd->packet; + for (i = 0; i < len; i++) { + *d++ = *s++; + if (s[-1] == 0xff) + *d++ = 0x00; + } + gspca_frame_add(gspca_dev, INTER_PACKET, frame, + sd->packet, d - sd->packet); +} + +static void setbrightness(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + struct usb_device *dev = gspca_dev->dev; + + switch (sd->bridge) { + default: +/* case BRIDGE_SPCA533: */ +/* case BRIDGE_SPCA504B: */ +/* case BRIDGE_SPCA504: */ +/* case BRIDGE_SPCA504C: */ + reg_w_riv(dev, 0x0, 0x21a7, sd->brightness); + break; + case BRIDGE_SPCA536: + reg_w_riv(dev, 0x0, 0x20f0, sd->brightness); + break; + } +} + +static void getbrightness(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + __u16 brightness = 0; + + switch (sd->bridge) { + default: +/* case BRIDGE_SPCA533: */ +/* case BRIDGE_SPCA504B: */ +/* case BRIDGE_SPCA504: */ +/* case BRIDGE_SPCA504C: */ + brightness = reg_r_12(gspca_dev, 0x00, 0x21a7, 2); + break; + case BRIDGE_SPCA536: + brightness = reg_r_12(gspca_dev, 0x00, 0x20f0, 2); + break; + } + sd->brightness = ((brightness & 0xff) - 128) % 255; +} + +static void setcontrast(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + struct usb_device *dev = gspca_dev->dev; + + switch (sd->bridge) { + default: +/* case BRIDGE_SPCA533: */ +/* case BRIDGE_SPCA504B: */ +/* case BRIDGE_SPCA504: */ +/* case BRIDGE_SPCA504C: */ + reg_w_riv(dev, 0x0, 0x21a8, sd->contrast); + break; + case BRIDGE_SPCA536: + reg_w_riv(dev, 0x0, 0x20f1, sd->contrast); + break; + } +} + +static void getcontrast(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + + switch (sd->bridge) { + default: +/* case BRIDGE_SPCA533: */ +/* case BRIDGE_SPCA504B: */ +/* case BRIDGE_SPCA504: */ +/* case BRIDGE_SPCA504C: */ + sd->contrast = reg_r_12(gspca_dev, 0x00, 0x21a8, 2); + break; + case BRIDGE_SPCA536: + sd->contrast = reg_r_12(gspca_dev, 0x00, 0x20f1, 2); + break; + } +} + +static void setcolors(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + struct usb_device *dev = gspca_dev->dev; + + switch (sd->bridge) { + default: +/* case BRIDGE_SPCA533: */ +/* case BRIDGE_SPCA504B: */ +/* case BRIDGE_SPCA504: */ +/* case BRIDGE_SPCA504C: */ + reg_w_riv(dev, 0x0, 0x21ae, sd->colors); + break; + case BRIDGE_SPCA536: + reg_w_riv(dev, 0x0, 0x20f6, sd->colors); + break; + } +} + +static void getcolors(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + + switch (sd->bridge) { + default: +/* case BRIDGE_SPCA533: */ +/* case BRIDGE_SPCA504B: */ +/* case BRIDGE_SPCA504: */ +/* case BRIDGE_SPCA504C: */ + sd->colors = reg_r_12(gspca_dev, 0x00, 0x21ae, 2) >> 1; + break; + case BRIDGE_SPCA536: + sd->colors = reg_r_12(gspca_dev, 0x00, 0x20f6, 2) >> 1; + break; + } +} + +static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->brightness = val; + if (gspca_dev->streaming) + setbrightness(gspca_dev); + return 0; +} + +static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + getbrightness(gspca_dev); + *val = sd->brightness; + return 0; +} + +static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->contrast = val; + if (gspca_dev->streaming) + setcontrast(gspca_dev); + return 0; +} + +static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + getcontrast(gspca_dev); + *val = sd->contrast; + return 0; +} + +static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->colors = val; + if (gspca_dev->streaming) + setcolors(gspca_dev); + return 0; +} + +static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + getcolors(gspca_dev); + *val = sd->colors; + return 0; +} + +static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->autogain = val; + return 0; +} + +static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + *val = sd->autogain; + return 0; +} + +/* sub-driver description */ +static const struct sd_desc sd_desc = { + .name = MODULE_NAME, + .ctrls = sd_ctrls, + .nctrls = ARRAY_SIZE(sd_ctrls), + .config = sd_config, + .open = sd_open, + .start = sd_start, + .stopN = sd_stopN, + .stop0 = sd_stop0, + .close = sd_close, + .pkt_scan = sd_pkt_scan, +}; + +/* -- module initialisation -- */ +#define DVNM(name) .driver_info = (kernel_ulong_t) name +static const __devinitdata struct usb_device_id device_table[] = { + {USB_DEVICE(0x041e, 0x400b), DVNM("Creative PC-CAM 600")}, + {USB_DEVICE(0x041e, 0x4012), DVNM("PC-Cam350")}, + {USB_DEVICE(0x041e, 0x4013), DVNM("Creative Pccam750")}, + {USB_DEVICE(0x0458, 0x7006), DVNM("Genius Dsc 1.3 Smart")}, + {USB_DEVICE(0x0461, 0x0821), DVNM("Fujifilm MV-1")}, + {USB_DEVICE(0x046d, 0x0905), DVNM("Logitech ClickSmart 820")}, + {USB_DEVICE(0x046d, 0x0960), DVNM("Logitech ClickSmart 420")}, + {USB_DEVICE(0x0471, 0x0322), DVNM("Philips DMVC1300K")}, + {USB_DEVICE(0x04a5, 0x3003), DVNM("Benq DC 1300")}, + {USB_DEVICE(0x04a5, 0x3008), DVNM("Benq DC 1500")}, + {USB_DEVICE(0x04a5, 0x300a), DVNM("Benq DC3410")}, + {USB_DEVICE(0x04f1, 0x1001), DVNM("JVC GC A50")}, + {USB_DEVICE(0x04fc, 0x500c), DVNM("Sunplus CA500C")}, + {USB_DEVICE(0x04fc, 0x504a), DVNM("Aiptek Mini PenCam 1.3")}, + {USB_DEVICE(0x04fc, 0x504b), DVNM("Maxell MaxPocket LE 1.3")}, + {USB_DEVICE(0x04fc, 0x5330), DVNM("Digitrex 2110")}, + {USB_DEVICE(0x04fc, 0x5360), DVNM("Sunplus Generic")}, + {USB_DEVICE(0x04fc, 0xffff), DVNM("Pure DigitalDakota")}, + {USB_DEVICE(0x052b, 0x1513), DVNM("Megapix V4")}, + {USB_DEVICE(0x0546, 0x3155), DVNM("Polaroid PDC3070")}, + {USB_DEVICE(0x0546, 0x3191), DVNM("Polaroid Ion 80")}, + {USB_DEVICE(0x0546, 0x3273), DVNM("Polaroid PDC2030")}, + {USB_DEVICE(0x055f, 0xc211), DVNM("Kowa Bs888e Microcamera")}, + {USB_DEVICE(0x055f, 0xc230), DVNM("Mustek Digicam 330K")}, + {USB_DEVICE(0x055f, 0xc232), DVNM("Mustek MDC3500")}, + {USB_DEVICE(0x055f, 0xc360), DVNM("Mustek DV4000 Mpeg4 ")}, + {USB_DEVICE(0x055f, 0xc420), DVNM("Mustek gSmart Mini 2")}, + {USB_DEVICE(0x055f, 0xc430), DVNM("Mustek Gsmart LCD 2")}, + {USB_DEVICE(0x055f, 0xc440), DVNM("Mustek DV 3000")}, + {USB_DEVICE(0x055f, 0xc520), DVNM("Mustek gSmart Mini 3")}, + {USB_DEVICE(0x055f, 0xc530), DVNM("Mustek Gsmart LCD 3")}, + {USB_DEVICE(0x055f, 0xc540), DVNM("Gsmart D30")}, + {USB_DEVICE(0x055f, 0xc630), DVNM("Mustek MDC4000")}, + {USB_DEVICE(0x055f, 0xc650), DVNM("Mustek MDC5500Z")}, + {USB_DEVICE(0x05da, 0x1018), DVNM("Digital Dream Enigma 1.3")}, + {USB_DEVICE(0x06d6, 0x0031), DVNM("Trust 610 LCD PowerC@m Zoom")}, + {USB_DEVICE(0x0733, 0x1311), DVNM("Digital Dream Epsilon 1.3")}, + {USB_DEVICE(0x0733, 0x1314), DVNM("Mercury 2.1MEG Deluxe Classic Cam")}, + {USB_DEVICE(0x0733, 0x2211), DVNM("Jenoptik jdc 21 LCD")}, + {USB_DEVICE(0x0733, 0x2221), DVNM("Mercury Digital Pro 3.1p")}, + {USB_DEVICE(0x0733, 0x3261), DVNM("Concord 3045 spca536a")}, + {USB_DEVICE(0x0733, 0x3281), DVNM("Cyberpix S550V")}, + {USB_DEVICE(0x08ca, 0x0104), DVNM("Aiptek PocketDVII 1.3")}, + {USB_DEVICE(0x08ca, 0x0106), DVNM("Aiptek Pocket DV3100+")}, + {USB_DEVICE(0x08ca, 0x2008), DVNM("Aiptek Mini PenCam 2 M")}, + {USB_DEVICE(0x08ca, 0x2010), DVNM("Aiptek PocketCam 3M")}, + {USB_DEVICE(0x08ca, 0x2016), DVNM("Aiptek PocketCam 2 Mega")}, + {USB_DEVICE(0x08ca, 0x2018), DVNM("Aiptek Pencam SD 2M")}, + {USB_DEVICE(0x08ca, 0x2020), DVNM("Aiptek Slim 3000F")}, + {USB_DEVICE(0x08ca, 0x2022), DVNM("Aiptek Slim 3200")}, + {USB_DEVICE(0x08ca, 0x2024), DVNM("Aiptek DV3500 Mpeg4 ")}, + {USB_DEVICE(0x08ca, 0x2028), DVNM("Aiptek PocketCam4M")}, + {USB_DEVICE(0x08ca, 0x2040), DVNM("Aiptek PocketDV4100M")}, + {USB_DEVICE(0x08ca, 0x2042), DVNM("Aiptek PocketDV5100")}, + {USB_DEVICE(0x08ca, 0x2050), DVNM("Medion MD 41437")}, + {USB_DEVICE(0x08ca, 0x2060), DVNM("Aiptek PocketDV5300")}, + {USB_DEVICE(0x0d64, 0x0303), DVNM("Sunplus FashionCam DXG")}, + {} +}; +MODULE_DEVICE_TABLE(usb, device_table); + +/* -- device connect -- */ +static int sd_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd), + THIS_MODULE); +} + +static struct usb_driver sd_driver = { + .name = MODULE_NAME, + .id_table = device_table, + .probe = sd_probe, + .disconnect = gspca_disconnect, +}; + +/* -- module insert / remove -- */ +static int __init sd_mod_init(void) +{ + if (usb_register(&sd_driver) < 0) + return -1; + PDEBUG(D_PROBE, "v%s registered", version); + return 0; +} +static void __exit sd_mod_exit(void) +{ + usb_deregister(&sd_driver); + PDEBUG(D_PROBE, "deregistered"); +} + +module_init(sd_mod_init); +module_exit(sd_mod_exit); diff --git a/drivers/media/video/gspca/t613.c b/drivers/media/video/gspca/t613.c new file mode 100644 index 000000000000..00f47e463a05 --- /dev/null +++ b/drivers/media/video/gspca/t613.c @@ -0,0 +1,1038 @@ +/* + *Notes: * t613 + tas5130A + * * Focus to light do not balance well as in win. + * Quality in win is not good, but its kinda better. + * * Fix some "extraneous bytes", most of apps will show the image anyway + * * Gamma table, is there, but its really doing something? + * * 7~8 Fps, its ok, max on win its 10. + * Costantino Leandro + * + * V4L2 by Jean-Francois Moine <http://moinejf.free.fr> + * + * 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 + * 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 + */ + +#define MODULE_NAME "t613" +#include "gspca.h" +#define DRIVER_VERSION_NUMBER KERNEL_VERSION(2, 1, 7) +static const char version[] = "2.1.7"; + +#define MAX_GAMMA 0x10 /* 0 to 15 */ + +/* From LUVCVIEW */ +#define V4L2_CID_EFFECTS (V4L2_CID_PRIVATE_BASE + 3) + +MODULE_AUTHOR("Leandro Costantino <le_costantino@pixartargentina.com.ar>"); +MODULE_DESCRIPTION("GSPCA/T613 (JPEG Compliance) USB Camera Driver"); +MODULE_LICENSE("GPL"); + +struct sd { + struct gspca_dev gspca_dev; /* !! must be the first item */ + + unsigned char brightness; + unsigned char contrast; + unsigned char colors; + unsigned char autogain; + unsigned char gamma; + unsigned char sharpness; + unsigned char freq; + unsigned char whitebalance; + unsigned char mirror; + unsigned char effect; +}; + +/* V4L2 controls supported by the driver */ +static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val); +static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val); +static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val); +static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val); +static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val); +static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val); +static int sd_setlowlight(struct gspca_dev *gspca_dev, __s32 val); +static int sd_getlowlight(struct gspca_dev *gspca_dev, __s32 *val); +static int sd_setgamma(struct gspca_dev *gspca_dev, __s32 val); +static int sd_getgamma(struct gspca_dev *gspca_dev, __s32 *val); +static int sd_setsharpness(struct gspca_dev *gspca_dev, __s32 val); +static int sd_getsharpness(struct gspca_dev *gspca_dev, __s32 *val); +static int sd_setfreq(struct gspca_dev *gspca_dev, __s32 val); +static int sd_getfreq(struct gspca_dev *gspca_dev, __s32 *val); +static int sd_setwhitebalance(struct gspca_dev *gspca_dev, __s32 val); +static int sd_getwhitebalance(struct gspca_dev *gspca_dev, __s32 *val); +static int sd_setflip(struct gspca_dev *gspca_dev, __s32 val); +static int sd_getflip(struct gspca_dev *gspca_dev, __s32 *val); +static int sd_seteffect(struct gspca_dev *gspca_dev, __s32 val); +static int sd_geteffect(struct gspca_dev *gspca_dev, __s32 *val); +static int sd_querymenu(struct gspca_dev *gspca_dev, + struct v4l2_querymenu *menu); + +static struct ctrl sd_ctrls[] = { +#define SD_BRIGHTNESS 0 + { + { + .id = V4L2_CID_BRIGHTNESS, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Brightness", + .minimum = 0, + .maximum = 0x0f, + .step = 1, + .default_value = 0x09, + }, + .set = sd_setbrightness, + .get = sd_getbrightness, + }, +#define SD_CONTRAST 1 + { + { + .id = V4L2_CID_CONTRAST, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Contrast", + .minimum = 0, + .maximum = 0x0d, + .step = 1, + .default_value = 0x07, + }, + .set = sd_setcontrast, + .get = sd_getcontrast, + }, +#define SD_COLOR 2 + { + { + .id = V4L2_CID_SATURATION, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Color", + .minimum = 0, + .maximum = 0x0f, + .step = 1, + .default_value = 0x05, + }, + .set = sd_setcolors, + .get = sd_getcolors, + }, +#define SD_GAMMA 3 + { + { + .id = V4L2_CID_GAMMA, /* (gamma on win) */ + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Gamma (Untested)", + .minimum = 0, + .maximum = MAX_GAMMA, + .step = 1, + .default_value = 0x09, + }, + .set = sd_setgamma, + .get = sd_getgamma, + }, +#define SD_AUTOGAIN 4 + { + { + .id = V4L2_CID_GAIN, /* here, i activate only the lowlight, + * some apps dont bring up the + * backligth_compensation control) */ + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Low Light", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0x01, + }, + .set = sd_setlowlight, + .get = sd_getlowlight, + }, +#define SD_MIRROR 5 + { + { + .id = V4L2_CID_HFLIP, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Mirror Image", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0, + }, + .set = sd_setflip, + .get = sd_getflip + }, +#define SD_LIGHTFREQ 6 + { + { + .id = V4L2_CID_POWER_LINE_FREQUENCY, + .type = V4L2_CTRL_TYPE_MENU, + .name = "Light Frequency Filter", + .minimum = 1, /* 1 -> 0x50, 2->0x60 */ + .maximum = 2, + .step = 1, + .default_value = 1, + }, + .set = sd_setfreq, + .get = sd_getfreq}, + +#define SD_WHITE_BALANCE 7 + { + { + .id = V4L2_CID_WHITE_BALANCE_TEMPERATURE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "White Balance", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 1, + }, + .set = sd_setwhitebalance, + .get = sd_getwhitebalance + }, +#define SD_SHARPNESS 8 /* (aka definition on win) */ + { + { + .id = V4L2_CID_SHARPNESS, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Sharpness", + .minimum = 0, + .maximum = MAX_GAMMA, /* 0 to 16 */ + .step = 1, + .default_value = 0x06, + }, + .set = sd_setsharpness, + .get = sd_getsharpness, + }, +#define SD_EFFECTS 9 + { + { + .id = V4L2_CID_EFFECTS, + .type = V4L2_CTRL_TYPE_MENU, + .name = "Webcam Effects", + .minimum = 0, + .maximum = 4, + .step = 1, + .default_value = 0, + }, + .set = sd_seteffect, + .get = sd_geteffect + }, +}; + +static char *effects_control[] = { + "Normal", + "Emboss", /* disabled */ + "Monochrome", + "Sepia", + "Sketch", + "Sun Effect", /* disabled */ + "Negative", +}; + +static struct v4l2_pix_format vga_mode_t16[] = { + {160, 120, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, + .bytesperline = 160, + .sizeimage = 160 * 120 * 3 / 8 + 590, + .colorspace = V4L2_COLORSPACE_JPEG, + .priv = 4}, + {176, 144, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, + .bytesperline = 176, + .sizeimage = 176 * 144 * 3 / 8 + 590, + .colorspace = V4L2_COLORSPACE_JPEG, + .priv = 3}, + {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, + .bytesperline = 320, + .sizeimage = 320 * 240 * 3 / 8 + 590, + .colorspace = V4L2_COLORSPACE_JPEG, + .priv = 2}, + {352, 288, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, + .bytesperline = 352, + .sizeimage = 352 * 288 * 3 / 8 + 590, + .colorspace = V4L2_COLORSPACE_JPEG, + .priv = 1}, + {640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, + .bytesperline = 640, + .sizeimage = 640 * 480 * 3 / 8 + 590, + .colorspace = V4L2_COLORSPACE_JPEG, + .priv = 0}, +}; + +#define T16_OFFSET_DATA 631 +#define MAX_EFFECTS 7 +/* easily done by soft, this table could be removed, + * i keep it here just in case */ +static const __u8 effects_table[MAX_EFFECTS][6] = { + {0xa8, 0xe8, 0xc6, 0xd2, 0xc0, 0x00}, /* Normal */ + {0xa8, 0xc8, 0xc6, 0x52, 0xc0, 0x04}, /* Repujar */ + {0xa8, 0xe8, 0xc6, 0xd2, 0xc0, 0x20}, /* Monochrome */ + {0xa8, 0xe8, 0xc6, 0xd2, 0xc0, 0x80}, /* Sepia */ + {0xa8, 0xc8, 0xc6, 0x52, 0xc0, 0x02}, /* Croquis */ + {0xa8, 0xc8, 0xc6, 0xd2, 0xc0, 0x10}, /* Sun Effect */ + {0xa8, 0xc8, 0xc6, 0xd2, 0xc0, 0x40}, /* Negative */ +}; + +static const __u8 gamma_table[MAX_GAMMA][34] = { + {0x90, 0x00, 0x91, 0x3e, 0x92, 0x69, 0x93, 0x85, + 0x94, 0x95, 0x95, 0xa1, 0x96, 0xae, 0x97, 0xb9, + 0x98, 0xc2, 0x99, 0xcb, 0x9a, 0xd4, 0x9b, 0xdb, + 0x9c, 0xe3, 0x9d, 0xea, 0x9e, 0xf1, 0x9f, 0xf8, + 0xa0, 0xff}, + {0x90, 0x00, 0x91, 0x33, 0x92, 0x5A, 0x93, 0x75, + 0x94, 0x85, 0x95, 0x93, 0x96, 0xA1, 0x97, 0xAD, + 0x98, 0xB7, 0x99, 0xC2, 0x9A, 0xCB, 0x9B, 0xD4, + 0x9C, 0xDE, 0x9D, 0xE7, 0x9E, 0xF0, 0x9F, 0xF7, + 0xa0, 0xff}, + {0x90, 0x00, 0x91, 0x2F, 0x92, 0x51, 0x93, 0x6B, + 0x94, 0x7C, 0x95, 0x8A, 0x96, 0x99, 0x97, 0xA6, + 0x98, 0xB1, 0x99, 0xBC, 0x9A, 0xC6, 0x9B, 0xD0, + 0x9C, 0xDB, 0x9D, 0xE4, 0x9E, 0xED, 0x9F, 0xF6, + 0xa0, 0xff}, + {0x90, 0x00, 0x91, 0x29, 0x92, 0x48, 0x93, 0x60, + 0x94, 0x72, 0x95, 0x81, 0x96, 0x90, 0x97, 0x9E, + 0x98, 0xAA, 0x99, 0xB5, 0x9A, 0xBF, 0x9B, 0xCB, + 0x9C, 0xD6, 0x9D, 0xE1, 0x9E, 0xEB, 0x9F, 0xF5, + 0xa0, 0xff}, + {0x90, 0x00, 0x91, 0x23, 0x92, 0x3F, 0x93, 0x55, + 0x94, 0x68, 0x95, 0x77, 0x96, 0x86, 0x97, 0x95, + 0x98, 0xA2, 0x99, 0xAD, 0x9A, 0xB9, 0x9B, 0xC6, + 0x9C, 0xD2, 0x9D, 0xDE, 0x9E, 0xE9, 0x9F, 0xF4, + 0xa0, 0xff}, + {0x90, 0x00, 0x91, 0x1B, 0x92, 0x33, 0x93, 0x48, + 0x94, 0x59, 0x95, 0x69, 0x96, 0x79, 0x97, 0x87, + 0x98, 0x96, 0x99, 0xA3, 0x9A, 0xB1, 0x9B, 0xBE, + 0x9C, 0xCC, 0x9D, 0xDA, 0x9E, 0xE7, 0x9F, 0xF3, + 0xa0, 0xff}, + {0x90, 0x00, 0x91, 0x02, 0x92, 0x10, 0x93, 0x20, + 0x94, 0x32, 0x95, 0x40, 0x96, 0x57, 0x97, 0x67, + 0x98, 0x77, 0x99, 0x88, 0x9a, 0x99, 0x9b, 0xaa, + 0x9c, 0xbb, 0x9d, 0xcc, 0x9e, 0xdd, 0x9f, 0xee, + 0xa0, 0xff}, + {0x90, 0x00, 0x91, 0x02, 0x92, 0x14, 0x93, 0x26, + 0x94, 0x38, 0x95, 0x4A, 0x96, 0x60, 0x97, 0x70, + 0x98, 0x80, 0x99, 0x90, 0x9A, 0xA0, 0x9B, 0xB0, + 0x9C, 0xC0, 0x9D, 0xD0, 0x9E, 0xE0, 0x9F, 0xF0, + 0xa0, 0xff}, + {0x90, 0x00, 0x91, 0x10, 0x92, 0x22, 0x93, 0x35, + 0x94, 0x47, 0x95, 0x5A, 0x96, 0x69, 0x97, 0x79, + 0x98, 0x88, 0x99, 0x97, 0x9A, 0xA7, 0x9B, 0xB6, + 0x9C, 0xC4, 0x9D, 0xD3, 0x9E, 0xE0, 0x9F, 0xF0, + 0xa0, 0xff}, + {0x90, 0x00, 0x91, 0x10, 0x92, 0x26, 0x93, 0x40, + 0x94, 0x54, 0x95, 0x65, 0x96, 0x75, 0x97, 0x84, + 0x98, 0x93, 0x99, 0xa1, 0x9a, 0xb0, 0x9b, 0xbd, + 0x9c, 0xca, 0x9d, 0xd6, 0x9e, 0xe0, 0x9f, 0xf0, + 0xa0, 0xff}, + {0x90, 0x00, 0x91, 0x18, 0x92, 0x2B, 0x93, 0x44, + 0x94, 0x60, 0x95, 0x70, 0x96, 0x80, 0x97, 0x8E, + 0x98, 0x9C, 0x99, 0xAA, 0x9A, 0xB7, 0x9B, 0xC4, + 0x9C, 0xD0, 0x9D, 0xD8, 0x9E, 0xE2, 0x9F, 0xF0, + 0xa0, 0xff}, + {0x90, 0x00, 0x91, 0x1A, 0x92, 0x34, 0x93, 0x52, + 0x94, 0x66, 0x95, 0x7E, 0x96, 0x8D, 0x97, 0x9B, + 0x98, 0xA8, 0x99, 0xB4, 0x9A, 0xC0, 0x9B, 0xCB, + 0x9C, 0xD6, 0x9D, 0xE1, 0x9E, 0xEB, 0x9F, 0xF5, + 0xa0, 0xff}, + {0x90, 0x00, 0x91, 0x3F, 0x92, 0x5A, 0x93, 0x6E, + 0x94, 0x7F, 0x95, 0x8E, 0x96, 0x9C, 0x97, 0xA8, + 0x98, 0xB4, 0x99, 0xBF, 0x9A, 0xC9, 0x9B, 0xD3, + 0x9C, 0xDC, 0x9D, 0xE5, 0x9E, 0xEE, 0x9F, 0xF6, + 0xA0, 0xFF}, + {0x90, 0x00, 0x91, 0x54, 0x92, 0x6F, 0x93, 0x83, + 0x94, 0x93, 0x95, 0xA0, 0x96, 0xAD, 0x97, 0xB7, + 0x98, 0xC2, 0x99, 0xCB, 0x9A, 0xD4, 0x9B, 0xDC, + 0x9C, 0xE4, 0x9D, 0xEB, 0x9E, 0xF2, 0x9F, 0xF9, + 0xa0, 0xff}, + {0x90, 0x00, 0x91, 0x6E, 0x92, 0x88, 0x93, 0x9A, + 0x94, 0xA8, 0x95, 0xB3, 0x96, 0xBD, 0x97, 0xC6, + 0x98, 0xCF, 0x99, 0xD6, 0x9A, 0xDD, 0x9B, 0xE3, + 0x9C, 0xE9, 0x9D, 0xEF, 0x9E, 0xF4, 0x9F, 0xFA, + 0xa0, 0xff}, + {0x90, 0x00, 0x91, 0x93, 0x92, 0xA8, 0x93, 0xB7, + 0x94, 0xC1, 0x95, 0xCA, 0x96, 0xD2, 0x97, 0xD8, + 0x98, 0xDE, 0x99, 0xE3, 0x9A, 0xE8, 0x9B, 0xED, + 0x9C, 0xF1, 0x9D, 0xF5, 0x9E, 0xF8, 0x9F, 0xFC, + 0xA0, 0xFF} +}; + +static const __u8 tas5130a_sensor_init[][8] = { + {0x62, 0x08, 0x63, 0x70, 0x64, 0x1d, 0x60, 0x09}, + {0x62, 0x20, 0x63, 0x01, 0x64, 0x02, 0x60, 0x09}, + {0x62, 0x07, 0x63, 0x03, 0x64, 0x00, 0x60, 0x09}, + {0x62, 0x07, 0x63, 0x03, 0x64, 0x00, 0x60, 0x09}, + {}, +}; + +/* read 1 byte */ +static int reg_r_1(struct gspca_dev *gspca_dev, + __u16 index) +{ + usb_control_msg(gspca_dev->dev, + usb_rcvctrlpipe(gspca_dev->dev, 0), + 0, /* request */ + USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + 0, /* value */ + index, + gspca_dev->usb_buf, 1, 500); + return gspca_dev->usb_buf[0]; +} + +static void reg_w(struct gspca_dev *gspca_dev, + __u16 value, + __u16 index, + const __u8 *buffer, __u16 len) +{ + if (buffer == NULL) { + usb_control_msg(gspca_dev->dev, + usb_sndctrlpipe(gspca_dev->dev, 0), + 0, + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE, + value, index, + NULL, 0, 500); + return; + } + if (len <= sizeof gspca_dev->usb_buf) { + memcpy(gspca_dev->usb_buf, buffer, len); + usb_control_msg(gspca_dev->dev, + usb_sndctrlpipe(gspca_dev->dev, 0), + 0, + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE, + value, index, + gspca_dev->usb_buf, len, 500); + } else { + __u8 *tmpbuf; + + tmpbuf = kmalloc(len, GFP_KERNEL); + memcpy(tmpbuf, buffer, len); + usb_control_msg(gspca_dev->dev, + usb_sndctrlpipe(gspca_dev->dev, 0), + 0, + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE, + value, index, + tmpbuf, len, 500); + kfree(tmpbuf); + } +} + +/* this function is called at probe time */ +static int sd_config(struct gspca_dev *gspca_dev, + const struct usb_device_id *id) +{ + struct sd *sd = (struct sd *) gspca_dev; + struct cam *cam; + + cam = &gspca_dev->cam; + cam->dev_name = (char *) id->driver_info; + cam->epaddr = 0x01; + + cam->cam_mode = vga_mode_t16; + cam->nmodes = ARRAY_SIZE(vga_mode_t16); + + sd->brightness = sd_ctrls[SD_BRIGHTNESS].qctrl.default_value; + sd->contrast = sd_ctrls[SD_CONTRAST].qctrl.default_value; + sd->colors = sd_ctrls[SD_COLOR].qctrl.default_value; + sd->gamma = sd_ctrls[SD_GAMMA].qctrl.default_value; + sd->mirror = sd_ctrls[SD_MIRROR].qctrl.default_value; + sd->freq = sd_ctrls[SD_LIGHTFREQ].qctrl.default_value; + sd->whitebalance = sd_ctrls[SD_WHITE_BALANCE].qctrl.default_value; + sd->sharpness = sd_ctrls[SD_SHARPNESS].qctrl.default_value; + sd->effect = sd_ctrls[SD_EFFECTS].qctrl.default_value; + return 0; +} + +static int init_default_parameters(struct gspca_dev *gspca_dev) +{ + /* some of this registers are not really neded, because + * they are overriden by setbrigthness, setcontrast, etc, + * but wont hurt anyway, and can help someone with similar webcam + * to see the initial parameters.*/ + int i = 0; + __u8 test_byte; + + static const __u8 read_indexs[] = + { 0x06, 0x07, 0x0a, 0x0b, 0x66, 0x80, 0x81, 0x8e, 0x8f, 0xa5, + 0xa6, 0xa8, 0xbb, 0xbc, 0xc6, 0x00, 0x00 }; + static const __u8 n1[6] = + {0x08, 0x03, 0x09, 0x03, 0x12, 0x04}; + static const __u8 n2[2] = + {0x08, 0x00}; + static const __u8 nset[6] = + { 0x61, 0x68, 0x62, 0xff, 0x60, 0x07 }; + static const __u8 n3[6] = + {0x61, 0x68, 0x65, 0x0a, 0x60, 0x04}; + static const __u8 n4[0x46] = + {0x09, 0x01, 0x12, 0x04, 0x66, 0x8a, 0x80, 0x3c, + 0x81, 0x22, 0x84, 0x50, 0x8a, 0x78, 0x8b, 0x68, + 0x8c, 0x88, 0x8e, 0x33, 0x8f, 0x24, 0xaa, 0xb1, + 0xa2, 0x60, 0xa5, 0x30, 0xa6, 0x3a, 0xa8, 0xe8, + 0xae, 0x05, 0xb1, 0x00, 0xbb, 0x04, 0xbc, 0x48, + 0xbe, 0x36, 0xc6, 0x88, 0xe9, 0x00, 0xc5, 0xc0, + 0x65, 0x0a, 0xbb, 0x86, 0xaf, 0x58, 0xb0, 0x68, + 0x87, 0x40, 0x89, 0x2b, 0x8d, 0xff, 0x83, 0x40, + 0xac, 0x84, 0xad, 0x86, 0xaf, 0x46}; + static const __u8 nset4[18] = { + 0xe0, 0x60, 0xe1, 0xa8, 0xe2, 0xe0, 0xe3, 0x60, 0xe4, 0xa8, + 0xe5, 0xe0, 0xe6, 0x60, 0xe7, 0xa8, + 0xe8, 0xe0 + }; + /* ojo puede ser 0xe6 en vez de 0xe9 */ + static const __u8 nset2[20] = { + 0xd0, 0xbb, 0xd1, 0x28, 0xd2, 0x10, 0xd3, 0x10, 0xd4, 0xbb, + 0xd5, 0x28, 0xd6, 0x1e, 0xd7, 0x27, + 0xd8, 0xc8, 0xd9, 0xfc + }; + static const __u8 missing[8] = + { 0x87, 0x20, 0x88, 0x20, 0x89, 0x20, 0x80, 0x38 }; + static const __u8 nset3[18] = { + 0xc7, 0x60, 0xc8, 0xa8, 0xc9, 0xe0, 0xca, 0x60, 0xcb, 0xa8, + 0xcc, 0xe0, 0xcd, 0x60, 0xce, 0xa8, + 0xcf, 0xe0 + }; + static const __u8 nset5[4] = + { 0x8f, 0x24, 0xc3, 0x00 }; /* bright */ + static const __u8 nset6[34] = { + 0x90, 0x00, 0x91, 0x1c, 0x92, 0x30, 0x93, 0x43, 0x94, 0x54, + 0x95, 0x65, 0x96, 0x75, 0x97, 0x84, + 0x98, 0x93, 0x99, 0xa1, 0x9a, 0xb0, 0x9b, 0xbd, 0x9c, 0xca, + 0x9d, 0xd8, 0x9e, 0xe5, 0x9f, 0xf2, + 0xa0, 0xff + }; /* Gamma */ + static const __u8 nset7[4] = + { 0x66, 0xca, 0xa8, 0xf8 }; /* 50/60 Hz */ + static const __u8 nset9[4] = + { 0x0b, 0x04, 0x0a, 0x78 }; + static const __u8 nset8[6] = + { 0xa8, 0xf0, 0xc6, 0x88, 0xc0, 0x00 }; + static const __u8 nset10[6] = + { 0x0c, 0x03, 0xab, 0x10, 0x81, 0x20 }; + + reg_w(gspca_dev, 0x01, 0x0000, n1, 0x06); + reg_w(gspca_dev, 0x01, 0x0000, nset, 0x06); + reg_r_1(gspca_dev, 0x0063); + reg_w(gspca_dev, 0x01, 0x0000, n2, 0x02); + + while (read_indexs[i] != 0x00) { + test_byte = reg_r_1(gspca_dev, read_indexs[i]); + PDEBUG(D_CONF, "Reg 0x%02x => 0x%02x", read_indexs[i], + test_byte); + i++; + } + + reg_w(gspca_dev, 0x01, 0x0000, n3, 0x06); + reg_w(gspca_dev, 0x01, 0x0000, n4, 0x46); + reg_r_1(gspca_dev, 0x0080); + reg_w(gspca_dev, 0x00, 0x2c80, NULL, 0); + reg_w(gspca_dev, 0x01, 0x0000, nset2, 0x14); + reg_w(gspca_dev, 0x01, 0x0000, nset3, 0x12); + reg_w(gspca_dev, 0x01, 0x0000, nset4, 0x12); + reg_w(gspca_dev, 0x00, 0x3880, NULL, 0); + reg_w(gspca_dev, 0x00, 0x3880, NULL, 0); + reg_w(gspca_dev, 0x00, 0x338e, NULL, 0); + reg_w(gspca_dev, 0x01, 0x0000, nset5, 0x04); + reg_w(gspca_dev, 0x00, 0x00a9, NULL, 0); + reg_w(gspca_dev, 0x01, 0x0000, nset6, 0x22); + reg_w(gspca_dev, 0x00, 0x86bb, NULL, 0); + reg_w(gspca_dev, 0x00, 0x4aa6, NULL, 0); + + reg_w(gspca_dev, 0x01, 0x0000, missing, 0x08); + + reg_w(gspca_dev, 0x00, 0x2087, NULL, 0); + reg_w(gspca_dev, 0x00, 0x2088, NULL, 0); + reg_w(gspca_dev, 0x00, 0x2089, NULL, 0); + + reg_w(gspca_dev, 0x01, 0x0000, nset7, 0x04); + reg_w(gspca_dev, 0x01, 0x0000, nset10, 0x06); + reg_w(gspca_dev, 0x01, 0x0000, nset8, 0x06); + reg_w(gspca_dev, 0x01, 0x0000, nset9, 0x04); + + reg_w(gspca_dev, 0x00, 0x2880, NULL, 0); + reg_w(gspca_dev, 0x01, 0x0000, nset2, 0x14); + reg_w(gspca_dev, 0x01, 0x0000, nset3, 0x12); + reg_w(gspca_dev, 0x01, 0x0000, nset4, 0x12); + + return 0; +} + +static void setbrightness(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + unsigned int brightness; + __u8 set6[4] = { 0x8f, 0x26, 0xc3, 0x80 }; + brightness = sd->brightness; + + if (brightness < 7) { + set6[3] = 0x70 - (brightness * 0xa); + } else { + set6[1] = 0x24; + set6[3] = 0x00 + ((brightness - 7) * 0xa); + } + + reg_w(gspca_dev, 0x01, 0x0000, set6, 4); +} + +static void setflip(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + + __u8 flipcmd[8] = + { 0x62, 0x07, 0x63, 0x03, 0x64, 0x00, 0x60, 0x09 }; + + if (sd->mirror == 1) + flipcmd[3] = 0x01; + + reg_w(gspca_dev, 0x01, 0x0000, flipcmd, 8); +} + +static void seteffect(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + + reg_w(gspca_dev, 0x01, 0x0000, effects_table[sd->effect], 0x06); + if (sd->effect == 1 || sd->effect == 5) { + PDEBUG(D_CONF, + "This effect have been disabled for webcam \"safety\""); + return; + } + + if (sd->effect == 1 || sd->effect == 4) + reg_w(gspca_dev, 0x00, 0x4aa6, NULL, 0); + else + reg_w(gspca_dev, 0x00, 0xfaa6, NULL, 0); +} + +static void setwhitebalance(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + + __u8 white_balance[8] = + { 0x87, 0x20, 0x88, 0x20, 0x89, 0x20, 0x80, 0x38 }; + + if (sd->whitebalance == 1) + white_balance[7] = 0x3c; + + reg_w(gspca_dev, 0x01, 0x0000, white_balance, 8); +} + +static void setlightfreq(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + __u8 freq[4] = { 0x66, 0x40, 0xa8, 0xe8 }; + + if (sd->freq == 2) /* 60hz */ + freq[1] = 0x00; + + reg_w(gspca_dev, 0x1, 0x0000, freq, 0x4); +} + +static void setcontrast(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + unsigned int contrast = sd->contrast; + __u16 reg_to_write = 0x00; + + if (contrast < 7) + reg_to_write = 0x8ea9 - (0x200 * contrast); + else + reg_to_write = (0x00a9 + ((contrast - 7) * 0x200)); + + reg_w(gspca_dev, 0x00, reg_to_write, NULL, 0); +} + +static void setcolors(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + __u16 reg_to_write; + + reg_to_write = 0xc0bb + sd->colors * 0x100; + reg_w(gspca_dev, 0x00, reg_to_write, NULL, 0); +} + +static void setgamma(struct gspca_dev *gspca_dev) +{ +} + +static void setsharpness(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + __u16 reg_to_write; + + reg_to_write = 0x0aa6 + 0x1000 * sd->sharpness; + + reg_w(gspca_dev, 0x00, reg_to_write, NULL, 0); +} + +static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->brightness = val; + if (gspca_dev->streaming) + setbrightness(gspca_dev); + return 0; +} + +static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + *val = sd->brightness; + return *val; +} + +static int sd_setwhitebalance(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->whitebalance = val; + if (gspca_dev->streaming) + setwhitebalance(gspca_dev); + return 0; +} + +static int sd_getwhitebalance(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + *val = sd->whitebalance; + return *val; +} + +static int sd_setflip(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->mirror = val; + if (gspca_dev->streaming) + setflip(gspca_dev); + return 0; +} + +static int sd_getflip(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + *val = sd->mirror; + return *val; +} + +static int sd_seteffect(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->effect = val; + if (gspca_dev->streaming) + seteffect(gspca_dev); + return 0; +} + +static int sd_geteffect(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + *val = sd->effect; + return *val; +} + +static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->contrast = val; + if (gspca_dev->streaming) + setcontrast(gspca_dev); + return 0; +} + +static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + *val = sd->contrast; + return *val; +} + +static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->colors = val; + if (gspca_dev->streaming) + setcolors(gspca_dev); + return 0; +} + +static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + *val = sd->colors; + return 0; +} + +static int sd_setgamma(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->gamma = val; + if (gspca_dev->streaming) + setgamma(gspca_dev); + return 0; +} + +static int sd_getgamma(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + *val = sd->gamma; + return 0; +} + +static int sd_setfreq(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->freq = val; + if (gspca_dev->streaming) + setlightfreq(gspca_dev); + return 0; +} + +static int sd_getfreq(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + *val = sd->freq; + return 0; +} + +static int sd_setsharpness(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->sharpness = val; + if (gspca_dev->streaming) + setsharpness(gspca_dev); + return 0; +} + +static int sd_getsharpness(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + *val = sd->sharpness; + return 0; +} + +/* Low Light set here......*/ +static int sd_setlowlight(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->autogain = val; + if (val != 0) + reg_w(gspca_dev, 0x00, 0xf48e, NULL, 0); + else + reg_w(gspca_dev, 0x00, 0xb48e, NULL, 0); + return 0; +} + +static int sd_getlowlight(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + *val = sd->autogain; + return 0; +} + +static void sd_start(struct gspca_dev *gspca_dev) +{ + int mode; + + static const __u8 t1[] = { 0x66, 0x00, 0xa8, 0xe8 }; + __u8 t2[] = { 0x07, 0x00, 0x0d, 0x60, 0x0e, 0x80 }; + static const __u8 t3[] = + { 0xb3, 0x07, 0xb4, 0x00, 0xb5, 0x88, 0xb6, 0x02, 0xb7, 0x06, + 0xb8, 0x00, 0xb9, 0xe7, 0xba, 0x01 }; + static const __u8 t4[] = { 0x0b, 0x04, 0x0a, 0x40 }; + + mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode]. priv; + switch (mode) { + case 1: /* 352x288 */ + t2[1] = 0x40; + break; + case 2: /* 320x240 */ + t2[1] = 0x10; + break; + case 3: /* 176x144 */ + t2[1] = 0x50; + break; + case 4: /* 160x120 */ + t2[1] = 0x20; + break; + default: /* 640x480 (0x00) */ + break; + } + + reg_w(gspca_dev, 0x01, 0x0000, tas5130a_sensor_init[0], 0x8); + reg_w(gspca_dev, 0x01, 0x0000, tas5130a_sensor_init[1], 0x8); + reg_w(gspca_dev, 0x01, 0x0000, tas5130a_sensor_init[2], 0x8); + reg_w(gspca_dev, 0x01, 0x0000, tas5130a_sensor_init[3], 0x8); + reg_w(gspca_dev, 0x00, 0x3c80, NULL, 0); + /* just in case and to keep sync with logs (for mine) */ + reg_w(gspca_dev, 0x01, 0x0000, tas5130a_sensor_init[3], 0x8); + reg_w(gspca_dev, 0x00, 0x3c80, NULL, 0); + /* just in case and to keep sync with logs (for mine) */ + reg_w(gspca_dev, 0x01, 0x0000, t1, 4); + reg_w(gspca_dev, 0x01, 0x0000, t2, 6); + reg_r_1(gspca_dev, 0x0012); + reg_w(gspca_dev, 0x01, 0x0000, t3, 0x10); + reg_w(gspca_dev, 0x00, 0x0013, NULL, 0); + reg_w(gspca_dev, 0x01, 0x0000, t4, 0x4); + /* restart on each start, just in case, sometimes regs goes wrong + * when using controls from app */ + setbrightness(gspca_dev); + setcontrast(gspca_dev); + setcolors(gspca_dev); +} + +static void sd_stopN(struct gspca_dev *gspca_dev) +{ +} + +static void sd_stop0(struct gspca_dev *gspca_dev) +{ +} + +static void sd_close(struct gspca_dev *gspca_dev) +{ +} + +static void sd_pkt_scan(struct gspca_dev *gspca_dev, + struct gspca_frame *frame, /* target */ + __u8 *data, /* isoc packet */ + int len) /* iso packet length */ +{ + int sof = 0; + static __u8 ffd9[] = { 0xff, 0xd9 }; + + if (data[0] == 0x5a) { + /* Control Packet, after this came the header again, + * but extra bytes came in the packet before this, + * sometimes an EOF arrives, sometimes not... */ + return; + } + + if (data[len - 1] == 0xff && data[len] == 0xd9) { + /* Just in case, i have seen packets with the marker, + * other's do not include it... */ + data += 2; + len -= 4; + } else if (data[2] == 0xff && data[3] == 0xd8) { + sof = 1; + data += 2; + len -= 2; + } else { + data += 2; + len -= 2; + } + + if (sof) { + /* extra bytes....., could be processed too but would be + * a waste of time, right now leave the application and + * libjpeg do it for ourserlves.. */ + frame = gspca_frame_add(gspca_dev, LAST_PACKET, frame, + ffd9, 2); + gspca_frame_add(gspca_dev, FIRST_PACKET, frame, data, len); + return; + } + + gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len); +} + +static int sd_querymenu(struct gspca_dev *gspca_dev, + struct v4l2_querymenu *menu) +{ + switch (menu->id) { + case V4L2_CID_POWER_LINE_FREQUENCY: + switch (menu->index) { + case 1: /* V4L2_CID_POWER_LINE_FREQUENCY_50HZ */ + strcpy((char *) menu->name, "50 Hz"); + return 0; + case 2: /* V4L2_CID_POWER_LINE_FREQUENCY_60HZ */ + strcpy((char *) menu->name, "60 Hz"); + return 0; + } + break; + case V4L2_CID_EFFECTS: + if ((unsigned) menu->index < ARRAY_SIZE(effects_control)) { + strncpy((char *) menu->name, + effects_control[menu->index], 32); + return 0; + } + break; + } + return -EINVAL; +} + +/* this function is called at open time */ +static int sd_open(struct gspca_dev *gspca_dev) +{ + init_default_parameters(gspca_dev); + return 0; +} + +/* sub-driver description */ +static const struct sd_desc sd_desc = { + .name = MODULE_NAME, + .ctrls = sd_ctrls, + .nctrls = ARRAY_SIZE(sd_ctrls), + .config = sd_config, + .open = sd_open, + .start = sd_start, + .stopN = sd_stopN, + .stop0 = sd_stop0, + .close = sd_close, + .pkt_scan = sd_pkt_scan, + .querymenu = sd_querymenu, +}; + +/* -- module initialisation -- */ +#define DVNM(name) .driver_info = (kernel_ulong_t) name +static const __devinitdata struct usb_device_id device_table[] = { + {USB_DEVICE(0x17a1, 0x0128), DVNM("XPX Webcam")}, + {} +}; +MODULE_DEVICE_TABLE(usb, device_table); + +/* -- device connect -- */ +static int sd_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd), + THIS_MODULE); +} + +static struct usb_driver sd_driver = { + .name = MODULE_NAME, + .id_table = device_table, + .probe = sd_probe, + .disconnect = gspca_disconnect, +}; + +/* -- module insert / remove -- */ +static int __init sd_mod_init(void) +{ + if (usb_register(&sd_driver) < 0) + return -1; + PDEBUG(D_PROBE, "v%s registered", version); + return 0; +} +static void __exit sd_mod_exit(void) +{ + usb_deregister(&sd_driver); + PDEBUG(D_PROBE, "deregistered"); +} + +module_init(sd_mod_init); +module_exit(sd_mod_exit); diff --git a/drivers/media/video/gspca/tv8532.c b/drivers/media/video/gspca/tv8532.c new file mode 100644 index 000000000000..0b793899095f --- /dev/null +++ b/drivers/media/video/gspca/tv8532.c @@ -0,0 +1,670 @@ +/* + * Quickcam cameras initialization data + * + * V4L2 by Jean-Francois Moine <http://moinejf.free.fr> + * + * 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 + * 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 + * + */ +#define MODULE_NAME "tv8532" + +#include "gspca.h" + +#define DRIVER_VERSION_NUMBER KERNEL_VERSION(2, 1, 7) +static const char version[] = "2.1.7"; + +MODULE_AUTHOR("Michel Xhaard <mxhaard@users.sourceforge.net>"); +MODULE_DESCRIPTION("TV8532 USB Camera Driver"); +MODULE_LICENSE("GPL"); + +/* specific webcam descriptor */ +struct sd { + struct gspca_dev gspca_dev; /* !! must be the first item */ + + int buflen; /* current length of tmpbuf */ + __u8 tmpbuf[352 * 288 + 10 * 288]; /* no protection... */ + __u8 tmpbuf2[352 * 288]; /* no protection... */ + + unsigned short brightness; + unsigned short contrast; + + char packet; + char synchro; +}; + +/* V4L2 controls supported by the driver */ +static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val); +static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val); +static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val); +static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val); + +static struct ctrl sd_ctrls[] = { +#define SD_BRIGHTNESS 0 + { + { + .id = V4L2_CID_BRIGHTNESS, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Brightness", + .minimum = 1, + .maximum = 0x2ff, + .step = 1, + .default_value = 0x18f, + }, + .set = sd_setbrightness, + .get = sd_getbrightness, + }, +#define SD_CONTRAST 1 + { + { + .id = V4L2_CID_CONTRAST, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Contrast", + .minimum = 0, + .maximum = 0xffff, + .step = 1, + .default_value = 0x7fff, + }, + .set = sd_setcontrast, + .get = sd_getcontrast, + }, +}; + +static struct v4l2_pix_format sif_mode[] = { + {176, 144, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE, + .bytesperline = 176, + .sizeimage = 176 * 144, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = 1}, + {352, 288, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE, + .bytesperline = 352, + .sizeimage = 352 * 288, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = 0}, +}; + +/* + * Initialization data: this is the first set-up data written to the + * device (before the open data). + */ +#define TESTCLK 0x10 /* reg 0x2c -> 0x12 //10 */ +#define TESTCOMP 0x90 /* reg 0x28 -> 0x80 */ +#define TESTLINE 0x81 /* reg 0x29 -> 0x81 */ +#define QCIFLINE 0x41 /* reg 0x29 -> 0x81 */ +#define TESTPTL 0x14 /* reg 0x2D -> 0x14 */ +#define TESTPTH 0x01 /* reg 0x2E -> 0x01 */ +#define TESTPTBL 0x12 /* reg 0x2F -> 0x0a */ +#define TESTPTBH 0x01 /* reg 0x30 -> 0x01 */ +#define ADWIDTHL 0xe8 /* reg 0x0c -> 0xe8 */ +#define ADWIDTHH 0x03 /* reg 0x0d -> 0x03 */ +#define ADHEIGHL 0x90 /* reg 0x0e -> 0x91 //93 */ +#define ADHEIGHH 0x01 /* reg 0x0f -> 0x01 */ +#define EXPOL 0x8f /* reg 0x1c -> 0x8f */ +#define EXPOH 0x01 /* reg 0x1d -> 0x01 */ +#define ADCBEGINL 0x44 /* reg 0x10 -> 0x46 //47 */ +#define ADCBEGINH 0x00 /* reg 0x11 -> 0x00 */ +#define ADRBEGINL 0x0a /* reg 0x14 -> 0x0b //0x0c */ +#define ADRBEGINH 0x00 /* reg 0x15 -> 0x00 */ +#define TV8532_CMD_UPDATE 0x84 + +#define TV8532_EEprom_Add 0x03 +#define TV8532_EEprom_DataL 0x04 +#define TV8532_EEprom_DataM 0x05 +#define TV8532_EEprom_DataH 0x06 +#define TV8532_EEprom_TableLength 0x07 +#define TV8532_EEprom_Write 0x08 +#define TV8532_PART_CTRL 0x00 +#define TV8532_CTRL 0x01 +#define TV8532_CMD_EEprom_Open 0x30 +#define TV8532_CMD_EEprom_Close 0x29 +#define TV8532_UDP_UPDATE 0x31 +#define TV8532_GPIO 0x39 +#define TV8532_GPIO_OE 0x3B +#define TV8532_REQ_RegWrite 0x02 +#define TV8532_REQ_RegRead 0x03 + +#define TV8532_ADWIDTH_L 0x0C +#define TV8532_ADWIDTH_H 0x0D +#define TV8532_ADHEIGHT_L 0x0E +#define TV8532_ADHEIGHT_H 0x0F +#define TV8532_EXPOSURE 0x1C +#define TV8532_QUANT_COMP 0x28 +#define TV8532_MODE_PACKET 0x29 +#define TV8532_SETCLK 0x2C +#define TV8532_POINT_L 0x2D +#define TV8532_POINT_H 0x2E +#define TV8532_POINTB_L 0x2F +#define TV8532_POINTB_H 0x30 +#define TV8532_BUDGET_L 0x2A +#define TV8532_BUDGET_H 0x2B +#define TV8532_VID_L 0x34 +#define TV8532_VID_H 0x35 +#define TV8532_PID_L 0x36 +#define TV8532_PID_H 0x37 +#define TV8532_DeviceID 0x83 +#define TV8532_AD_SLOPE 0x91 +#define TV8532_AD_BITCTRL 0x94 +#define TV8532_AD_COLBEGIN_L 0x10 +#define TV8532_AD_COLBEGIN_H 0x11 +#define TV8532_AD_ROWBEGIN_L 0x14 +#define TV8532_AD_ROWBEGIN_H 0x15 + +static const __u32 tv_8532_eeprom_data[] = { +/* add dataL dataM dataH */ + 0x00010001, 0x01018011, 0x02050014, 0x0305001c, + 0x040d001e, 0x0505001f, 0x06050519, 0x0705011b, + 0x0805091e, 0x090d892e, 0x0a05892f, 0x0b050dd9, + 0x0c0509f1, 0 +}; + +static int reg_r(struct gspca_dev *gspca_dev, + __u16 index) +{ + usb_control_msg(gspca_dev->dev, + usb_rcvctrlpipe(gspca_dev->dev, 0), + TV8532_REQ_RegRead, + USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + 0, /* value */ + index, gspca_dev->usb_buf, 1, + 500); + return gspca_dev->usb_buf[0]; +} + +/* write 1 byte */ +static void reg_w_1(struct gspca_dev *gspca_dev, + __u16 index, __u8 value) +{ + gspca_dev->usb_buf[0] = value; + usb_control_msg(gspca_dev->dev, + usb_sndctrlpipe(gspca_dev->dev, 0), + TV8532_REQ_RegWrite, + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + 0, /* value */ + index, gspca_dev->usb_buf, 1, 500); +} + +/* write 2 bytes */ +static void reg_w_2(struct gspca_dev *gspca_dev, + __u16 index, __u8 val1, __u8 val2) +{ + gspca_dev->usb_buf[0] = val1; + gspca_dev->usb_buf[1] = val2; + usb_control_msg(gspca_dev->dev, + usb_sndctrlpipe(gspca_dev->dev, 0), + TV8532_REQ_RegWrite, + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + 0, /* value */ + index, gspca_dev->usb_buf, 2, 500); +} + +static void tv_8532WriteEEprom(struct gspca_dev *gspca_dev) +{ + int i = 0; + __u8 reg, data0, data1, data2; + + reg_w_1(gspca_dev, TV8532_GPIO, 0xb0); + reg_w_1(gspca_dev, TV8532_CTRL, TV8532_CMD_EEprom_Open); +/* msleep(1); */ + while (tv_8532_eeprom_data[i]) { + reg = (tv_8532_eeprom_data[i] & 0xff000000) >> 24; + reg_w_1(gspca_dev, TV8532_EEprom_Add, reg); + /* msleep(1); */ + data0 = (tv_8532_eeprom_data[i] & 0x000000ff); + reg_w_1(gspca_dev, TV8532_EEprom_DataL, data0); + /* msleep(1); */ + data1 = (tv_8532_eeprom_data[i] & 0x0000ff00) >> 8; + reg_w_1(gspca_dev, TV8532_EEprom_DataM, data1); + /* msleep(1); */ + data2 = (tv_8532_eeprom_data[i] & 0x00ff0000) >> 16; + reg_w_1(gspca_dev, TV8532_EEprom_DataH, data2); + /* msleep(1); */ + reg_w_1(gspca_dev, TV8532_EEprom_Write, 0); + /* msleep(10); */ + i++; + } + reg_w_1(gspca_dev, TV8532_EEprom_TableLength, i); +/* msleep(1); */ + reg_w_1(gspca_dev, TV8532_CTRL, TV8532_CMD_EEprom_Close); + msleep(10); +} + +/* this function is called at probe time */ +static int sd_config(struct gspca_dev *gspca_dev, + const struct usb_device_id *id) +{ + struct sd *sd = (struct sd *) gspca_dev; + struct cam *cam; + + tv_8532WriteEEprom(gspca_dev); + + cam = &gspca_dev->cam; + cam->dev_name = (char *) id->driver_info; + cam->epaddr = 1; + cam->cam_mode = sif_mode; + cam->nmodes = sizeof sif_mode / sizeof sif_mode[0]; + + sd->brightness = sd_ctrls[SD_BRIGHTNESS].qctrl.default_value; + sd->contrast = sd_ctrls[SD_CONTRAST].qctrl.default_value; + return 0; +} + +static void tv_8532ReadRegisters(struct gspca_dev *gspca_dev) +{ + __u8 data; + + data = reg_r(gspca_dev, 0x0001); + PDEBUG(D_USBI, "register 0x01-> %x", data); + data = reg_r(gspca_dev, 0x0002); + PDEBUG(D_USBI, "register 0x02-> %x", data); + reg_r(gspca_dev, TV8532_ADWIDTH_L); + reg_r(gspca_dev, TV8532_ADWIDTH_H); + reg_r(gspca_dev, TV8532_QUANT_COMP); + reg_r(gspca_dev, TV8532_MODE_PACKET); + reg_r(gspca_dev, TV8532_SETCLK); + reg_r(gspca_dev, TV8532_POINT_L); + reg_r(gspca_dev, TV8532_POINT_H); + reg_r(gspca_dev, TV8532_POINTB_L); + reg_r(gspca_dev, TV8532_POINTB_H); + reg_r(gspca_dev, TV8532_BUDGET_L); + reg_r(gspca_dev, TV8532_BUDGET_H); + reg_r(gspca_dev, TV8532_VID_L); + reg_r(gspca_dev, TV8532_VID_H); + reg_r(gspca_dev, TV8532_PID_L); + reg_r(gspca_dev, TV8532_PID_H); + reg_r(gspca_dev, TV8532_DeviceID); + reg_r(gspca_dev, TV8532_AD_COLBEGIN_L); + reg_r(gspca_dev, TV8532_AD_COLBEGIN_H); + reg_r(gspca_dev, TV8532_AD_ROWBEGIN_L); + reg_r(gspca_dev, TV8532_AD_ROWBEGIN_H); +} + +static void tv_8532_setReg(struct gspca_dev *gspca_dev) +{ + reg_w_1(gspca_dev, TV8532_AD_COLBEGIN_L, + ADCBEGINL); /* 0x10 */ + reg_w_1(gspca_dev, TV8532_AD_COLBEGIN_H, + ADCBEGINH); /* also digital gain */ + reg_w_1(gspca_dev, TV8532_PART_CTRL, + TV8532_CMD_UPDATE); /* 0x00<-0x84 */ + + reg_w_1(gspca_dev, TV8532_GPIO_OE, 0x0a); + /******************************************************/ + reg_w_1(gspca_dev, TV8532_ADHEIGHT_L, ADHEIGHL); /* 0e */ + reg_w_1(gspca_dev, TV8532_ADHEIGHT_H, ADHEIGHH); /* 0f */ + reg_w_2(gspca_dev, TV8532_EXPOSURE, + EXPOL, EXPOH); /* 350d 0x014c; 1c */ + reg_w_1(gspca_dev, TV8532_AD_COLBEGIN_L, + ADCBEGINL); /* 0x10 */ + reg_w_1(gspca_dev, TV8532_AD_COLBEGIN_H, + ADCBEGINH); /* also digital gain */ + reg_w_1(gspca_dev, TV8532_AD_ROWBEGIN_L, + ADRBEGINL); /* 0x14 */ + + reg_w_1(gspca_dev, TV8532_AD_SLOPE, 0x00); /* 0x91 */ + reg_w_1(gspca_dev, TV8532_AD_BITCTRL, 0x02); /* 0x94 */ + + reg_w_1(gspca_dev, TV8532_CTRL, + TV8532_CMD_EEprom_Close); /* 0x01 */ + + reg_w_1(gspca_dev, TV8532_AD_SLOPE, 0x00); /* 0x91 */ + reg_w_1(gspca_dev, TV8532_PART_CTRL, + TV8532_CMD_UPDATE); /* 0x00<-0x84 */ +} + +static void tv_8532_PollReg(struct gspca_dev *gspca_dev) +{ + int i; + + /* strange polling from tgc */ + for (i = 0; i < 10; i++) { + reg_w_1(gspca_dev, TV8532_SETCLK, + TESTCLK); /* 0x48; //0x08; 0x2c */ + reg_w_1(gspca_dev, TV8532_PART_CTRL, TV8532_CMD_UPDATE); + reg_w_1(gspca_dev, TV8532_UDP_UPDATE, 0x01); /* 0x31 */ + } +} + +/* this function is called at open time */ +static int sd_open(struct gspca_dev *gspca_dev) +{ + reg_w_1(gspca_dev, TV8532_AD_SLOPE, 0x32); + reg_w_1(gspca_dev, TV8532_AD_BITCTRL, 0x00); + tv_8532ReadRegisters(gspca_dev); + reg_w_1(gspca_dev, TV8532_GPIO_OE, 0x0b); + reg_w_2(gspca_dev, TV8532_ADHEIGHT_L, ADHEIGHL, + ADHEIGHH); /* 401d 0x0169; 0e */ + reg_w_2(gspca_dev, TV8532_EXPOSURE, EXPOL, + EXPOH); /* 350d 0x014c; 1c */ + reg_w_1(gspca_dev, TV8532_ADWIDTH_L, ADWIDTHL); /* 0x20; 0x0c */ + reg_w_1(gspca_dev, TV8532_ADWIDTH_H, ADWIDTHH); /* 0x0d */ + + /*******************************************************************/ + reg_w_1(gspca_dev, TV8532_QUANT_COMP, + TESTCOMP); /* 0x72 compressed mode 0x28 */ + reg_w_1(gspca_dev, TV8532_MODE_PACKET, + TESTLINE); /* 0x84; // CIF | 4 packet 0x29 */ + + /************************************************/ + reg_w_1(gspca_dev, TV8532_SETCLK, + TESTCLK); /* 0x48; //0x08; 0x2c */ + reg_w_1(gspca_dev, TV8532_POINT_L, + TESTPTL); /* 0x38; 0x2d */ + reg_w_1(gspca_dev, TV8532_POINT_H, + TESTPTH); /* 0x04; 0x2e */ + reg_w_1(gspca_dev, TV8532_POINTB_L, + TESTPTBL); /* 0x04; 0x2f */ + reg_w_1(gspca_dev, TV8532_POINTB_H, + TESTPTBH); /* 0x04; 0x30 */ + reg_w_1(gspca_dev, TV8532_PART_CTRL, + TV8532_CMD_UPDATE); /* 0x00<-0x84 */ + /*************************************************/ + reg_w_1(gspca_dev, TV8532_UDP_UPDATE, 0x01); /* 0x31 */ + msleep(200); + reg_w_1(gspca_dev, TV8532_UDP_UPDATE, 0x00); /* 0x31 */ + /*************************************************/ + tv_8532_setReg(gspca_dev); + /*************************************************/ + reg_w_1(gspca_dev, TV8532_GPIO_OE, 0x0b); + /*************************************************/ + tv_8532_setReg(gspca_dev); + /*************************************************/ + tv_8532_PollReg(gspca_dev); + return 0; +} + +static void setbrightness(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + int brightness = sd->brightness; + + reg_w_2(gspca_dev, TV8532_EXPOSURE, + brightness >> 8, brightness); /* 1c */ + reg_w_1(gspca_dev, TV8532_PART_CTRL, TV8532_CMD_UPDATE); +} + +/* -- start the camera -- */ +static void sd_start(struct gspca_dev *gspca_dev) +{ + reg_w_1(gspca_dev, TV8532_AD_SLOPE, 0x32); + reg_w_1(gspca_dev, TV8532_AD_BITCTRL, 0x00); + tv_8532ReadRegisters(gspca_dev); + reg_w_1(gspca_dev, TV8532_GPIO_OE, 0x0b); + reg_w_2(gspca_dev, TV8532_ADHEIGHT_L, + ADHEIGHL, ADHEIGHH); /* 401d 0x0169; 0e */ +/* reg_w_2(gspca_dev, TV8532_EXPOSURE, + EXPOL, EXPOH); * 350d 0x014c; 1c */ + setbrightness(gspca_dev); + + reg_w_1(gspca_dev, TV8532_ADWIDTH_L, ADWIDTHL); /* 0x20; 0x0c */ + reg_w_1(gspca_dev, TV8532_ADWIDTH_H, ADWIDTHH); /* 0x0d */ + + /************************************************/ + reg_w_1(gspca_dev, TV8532_QUANT_COMP, + TESTCOMP); /* 0x72 compressed mode 0x28 */ + if (gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv) { + /* 176x144 */ + reg_w_1(gspca_dev, TV8532_MODE_PACKET, + QCIFLINE); /* 0x84; // CIF | 4 packet 0x29 */ + } else { + /* 352x288 */ + reg_w_1(gspca_dev, TV8532_MODE_PACKET, + TESTLINE); /* 0x84; // CIF | 4 packet 0x29 */ + } + /************************************************/ + reg_w_1(gspca_dev, TV8532_SETCLK, + TESTCLK); /* 0x48; //0x08; 0x2c */ + reg_w_1(gspca_dev, TV8532_POINT_L, + TESTPTL); /* 0x38; 0x2d */ + reg_w_1(gspca_dev, TV8532_POINT_H, + TESTPTH); /* 0x04; 0x2e */ + reg_w_1(gspca_dev, TV8532_POINTB_L, + TESTPTBL); /* 0x04; 0x2f */ + reg_w_1(gspca_dev, TV8532_POINTB_H, + TESTPTBH); /* 0x04; 0x30 */ + reg_w_1(gspca_dev, TV8532_PART_CTRL, + TV8532_CMD_UPDATE); /* 0x00<-0x84 */ + /************************************************/ + reg_w_1(gspca_dev, TV8532_UDP_UPDATE, 0x01); /* 0x31 */ + msleep(200); + reg_w_1(gspca_dev, TV8532_UDP_UPDATE, 0x00); /* 0x31 */ + /************************************************/ + tv_8532_setReg(gspca_dev); + /************************************************/ + reg_w_1(gspca_dev, TV8532_GPIO_OE, 0x0b); + /************************************************/ + tv_8532_setReg(gspca_dev); + /************************************************/ + tv_8532_PollReg(gspca_dev); + reg_w_1(gspca_dev, TV8532_UDP_UPDATE, 0x00); /* 0x31 */ +} + +static void sd_stopN(struct gspca_dev *gspca_dev) +{ + reg_w_1(gspca_dev, TV8532_GPIO_OE, 0x0b); +} + +static void sd_stop0(struct gspca_dev *gspca_dev) +{ +} + +static void sd_close(struct gspca_dev *gspca_dev) +{ +} + +static void tv8532_preprocess(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; +/* we should received a whole frame with header and EOL marker + * in gspca_dev->tmpbuf and return a GBRG pattern in gspca_dev->tmpbuf2 + * sequence 2bytes header the Alternate pixels bayer GB 4 bytes + * Alternate pixels bayer RG 4 bytes EOL */ + int width = gspca_dev->width; + int height = gspca_dev->height; + unsigned char *dst = sd->tmpbuf2; + unsigned char *data = sd->tmpbuf; + int i; + + /* precompute where is the good bayer line */ + if (((data[3] + data[width + 7]) >> 1) + + (data[4] >> 2) + + (data[width + 6] >> 1) >= ((data[2] + data[width + 6]) >> 1) + + (data[3] >> 2) + + (data[width + 5] >> 1)) + data += 3; + else + data += 2; + for (i = 0; i < height / 2; i++) { + memcpy(dst, data, width); + data += width + 3; + dst += width; + memcpy(dst, data, width); + data += width + 7; + dst += width; + } +} + +static void sd_pkt_scan(struct gspca_dev *gspca_dev, + struct gspca_frame *frame, /* target */ + __u8 *data, /* isoc packet */ + int len) /* iso packet length */ +{ + struct sd *sd = (struct sd *) gspca_dev; + + if (data[0] != 0x80) { + sd->packet++; + if (sd->buflen + len > sizeof sd->tmpbuf) { + if (gspca_dev->last_packet_type != DISCARD_PACKET) { + PDEBUG(D_PACK, "buffer overflow"); + gspca_dev->last_packet_type = DISCARD_PACKET; + } + return; + } + memcpy(&sd->tmpbuf[sd->buflen], data, len); + sd->buflen += len; + return; + } + + /* here we detect 0x80 */ + /* counter is limited so we need few header for a frame :) */ + + /* header 0x80 0x80 0x80 0x80 0x80 */ + /* packet 00 63 127 145 00 */ + /* sof 0 1 1 0 0 */ + + /* update sequence */ + if (sd->packet == 63 || sd->packet == 127) + sd->synchro = 1; + + /* is there a frame start ? */ + if (sd->packet >= (gspca_dev->height >> 1) - 1) { + PDEBUG(D_PACK, "SOF > %d packet %d", sd->synchro, + sd->packet); + if (!sd->synchro) { /* start of frame */ + if (gspca_dev->last_packet_type == FIRST_PACKET) { + tv8532_preprocess(gspca_dev); + frame = gspca_frame_add(gspca_dev, + LAST_PACKET, + frame, sd->tmpbuf2, + gspca_dev->width * + gspca_dev->width); + } + gspca_frame_add(gspca_dev, FIRST_PACKET, + frame, data, 0); + memcpy(sd->tmpbuf, data, len); + sd->buflen = len; + sd->packet = 0; + return; + } + if (gspca_dev->last_packet_type != DISCARD_PACKET) { + PDEBUG(D_PACK, + "Warning wrong TV8532 frame detection %d", + sd->packet); + gspca_dev->last_packet_type = DISCARD_PACKET; + } + return; + } + + if (!sd->synchro) { + /* Drop packet frame corrupt */ + PDEBUG(D_PACK, "DROP SOF %d packet %d", + sd->synchro, sd->packet); + sd->packet = 0; + gspca_dev->last_packet_type = DISCARD_PACKET; + return; + } + sd->synchro = 1; + sd->packet++; + memcpy(&sd->tmpbuf[sd->buflen], data, len); + sd->buflen += len; +} + +static void setcontrast(struct gspca_dev *gspca_dev) +{ +} + +static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->brightness = val; + if (gspca_dev->streaming) + setbrightness(gspca_dev); + return 0; +} + +static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + *val = sd->brightness; + return 0; +} + +static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->contrast = val; + if (gspca_dev->streaming) + setcontrast(gspca_dev); + return 0; +} + +static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + *val = sd->contrast; + return 0; +} + +/* sub-driver description */ +static const struct sd_desc sd_desc = { + .name = MODULE_NAME, + .ctrls = sd_ctrls, + .nctrls = ARRAY_SIZE(sd_ctrls), + .config = sd_config, + .open = sd_open, + .start = sd_start, + .stopN = sd_stopN, + .stop0 = sd_stop0, + .close = sd_close, + .pkt_scan = sd_pkt_scan, +}; + +/* -- module initialisation -- */ +#define DVNM(name) .driver_info = (kernel_ulong_t) name +static const __devinitdata struct usb_device_id device_table[] = { + {USB_DEVICE(0x046d, 0x0920), DVNM("QC Express")}, + {USB_DEVICE(0x046d, 0x0921), DVNM("Labtec Webcam")}, + {USB_DEVICE(0x0545, 0x808b), DVNM("Veo Stingray")}, + {USB_DEVICE(0x0545, 0x8333), DVNM("Veo Stingray")}, + {USB_DEVICE(0x0923, 0x010f), DVNM("ICM532 cams")}, + {} +}; + +MODULE_DEVICE_TABLE(usb, device_table); + +/* -- device connect -- */ +static int sd_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd), + THIS_MODULE); +} + +static struct usb_driver sd_driver = { + .name = MODULE_NAME, + .id_table = device_table, + .probe = sd_probe, + .disconnect = gspca_disconnect, +}; + +/* -- module insert / remove -- */ +static int __init sd_mod_init(void) +{ + if (usb_register(&sd_driver) < 0) + return -1; + PDEBUG(D_PROBE, "v%s registered", version); + return 0; +} + +static void __exit sd_mod_exit(void) +{ + usb_deregister(&sd_driver); + PDEBUG(D_PROBE, "deregistered"); +} + +module_init(sd_mod_init); +module_exit(sd_mod_exit); diff --git a/drivers/media/video/gspca/vc032x.c b/drivers/media/video/gspca/vc032x.c new file mode 100644 index 000000000000..fcf2c9e32573 --- /dev/null +++ b/drivers/media/video/gspca/vc032x.c @@ -0,0 +1,1818 @@ +/* + * Z-star vc0321 library + * Copyright (C) 2006 Koninski Artur takeshi87@o2.pl + * Copyright (C) 2006 Michel Xhaard + * + * V4L2 by Jean-Francois Moine <http://moinejf.free.fr> + * + * 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 + * 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 + */ + +#define MODULE_NAME "vc032x" + +#include "gspca.h" + +#define DRIVER_VERSION_NUMBER KERNEL_VERSION(2, 1, 7) +static const char version[] = "2.1.7"; + +MODULE_AUTHOR("Michel Xhaard <mxhaard@users.sourceforge.net>"); +MODULE_DESCRIPTION("GSPCA/VC032X USB Camera Driver"); +MODULE_LICENSE("GPL"); + +/* specific webcam descriptor */ +struct sd { + struct gspca_dev gspca_dev; /* !! must be the first item */ + + unsigned char autogain; + unsigned char lightfreq; + + char qindex; + char bridge; +#define BRIDGE_VC0321 0 +#define BRIDGE_VC0323 1 + char sensor; +#define SENSOR_HV7131R 0 +#define SENSOR_MI1320 1 +#define SENSOR_MI1310_SOC 2 +#define SENSOR_OV7660 3 +#define SENSOR_OV7670 4 +#define SENSOR_PO3130NC 5 +}; + +/* V4L2 controls supported by the driver */ +static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val); +static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val); +static int sd_setfreq(struct gspca_dev *gspca_dev, __s32 val); +static int sd_getfreq(struct gspca_dev *gspca_dev, __s32 *val); + +static struct ctrl sd_ctrls[] = { + { + { + .id = V4L2_CID_AUTOGAIN, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Auto Gain", + .minimum = 0, + .maximum = 1, + .step = 1, +#define AUTOGAIN_DEF 1 + .default_value = AUTOGAIN_DEF, + }, + .set = sd_setautogain, + .get = sd_getautogain, + }, + { + { + .id = V4L2_CID_POWER_LINE_FREQUENCY, + .type = V4L2_CTRL_TYPE_MENU, + .name = "Light frequency filter", + .minimum = 0, + .maximum = 2, /* 0: No, 1: 50Hz, 2:60Hz */ + .step = 1, +#define FREQ_DEF 1 + .default_value = FREQ_DEF, + .default_value = 1, + }, + .set = sd_setfreq, + .get = sd_getfreq, + }, +}; + +static struct v4l2_pix_format vc0321_mode[] = { + {320, 240, V4L2_PIX_FMT_YUV420, V4L2_FIELD_NONE, + .bytesperline = 320 * 2, + .sizeimage = 320 * 240 * 2, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = 1}, + {640, 480, V4L2_PIX_FMT_YUV420, V4L2_FIELD_NONE, + .bytesperline = 640 * 2, + .sizeimage = 640 * 480 * 2, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = 0}, +}; +static struct v4l2_pix_format vc0323_mode[] = { + {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, + .bytesperline = 320, + .sizeimage = 320 * 240 * 3 / 8 + 590, + .colorspace = V4L2_COLORSPACE_JPEG, + .priv = 1}, + {640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, + .bytesperline = 640, + .sizeimage = 640 * 480 * 3 / 8 + 590, + .colorspace = V4L2_COLORSPACE_JPEG, + .priv = 0}, +}; + +static const __u8 mi1310_socinitVGA_JPG[][4] = { + {0xb0, 0x03, 0x19, 0xcc}, + {0xb0, 0x04, 0x02, 0xcc}, + {0xb3, 0x00, 0x64, 0xcc}, + {0xb3, 0x00, 0x65, 0xcc}, + {0xb3, 0x05, 0x00, 0xcc}, + {0xb3, 0x06, 0x00, 0xcc}, + {0xb3, 0x08, 0x01, 0xcc}, + {0xb3, 0x09, 0x0c, 0xcc}, + {0xb3, 0x34, 0x02, 0xcc}, + {0xb3, 0x35, 0xdd, 0xcc}, + {0xb3, 0x02, 0x00, 0xcc}, + {0xb3, 0x03, 0x0a, 0xcc}, + {0xb3, 0x04, 0x05, 0xcc}, + {0xb3, 0x20, 0x00, 0xcc}, + {0xb3, 0x21, 0x00, 0xcc}, + {0xb3, 0x22, 0x03, 0xcc}, + {0xb3, 0x23, 0xc0, 0xcc}, + {0xb3, 0x14, 0x00, 0xcc}, + {0xb3, 0x15, 0x00, 0xcc}, + {0xb3, 0x16, 0x04, 0xcc}, + {0xb3, 0x17, 0xff, 0xcc}, + {0xb3, 0x00, 0x65, 0xcc}, + {0xb8, 0x00, 0x00, 0xcc}, + {0xbc, 0x00, 0xd0, 0xcc}, + {0xbc, 0x01, 0x01, 0xcc}, + {0xf0, 0x00, 0x02, 0xbb}, + {0xc8, 0x9f, 0x0b, 0xbb}, + {0x5b, 0x00, 0x01, 0xbb}, + {0x2f, 0xde, 0x20, 0xbb}, + {0xf0, 0x00, 0x00, 0xbb}, + {0x20, 0x03, 0x02, 0xbb}, + {0xf0, 0x00, 0x01, 0xbb}, + {0x05, 0x00, 0x07, 0xbb}, + {0x34, 0x00, 0x00, 0xbb}, + {0x35, 0xff, 0x00, 0xbb}, + {0xdc, 0x07, 0x02, 0xbb}, + {0xdd, 0x3c, 0x18, 0xbb}, + {0xde, 0x92, 0x6d, 0xbb}, + {0xdf, 0xcd, 0xb1, 0xbb}, + {0xe0, 0xff, 0xe7, 0xbb}, + {0x06, 0xf0, 0x0d, 0xbb}, + {0x06, 0x70, 0x0e, 0xbb}, + {0x4c, 0x00, 0x01, 0xbb}, + {0x4d, 0x00, 0x01, 0xbb}, + {0xf0, 0x00, 0x02, 0xbb}, + {0x2e, 0x0c, 0x55, 0xbb}, + {0x21, 0xb6, 0x6e, 0xbb}, + {0x36, 0x30, 0x10, 0xbb}, + {0x37, 0x00, 0xc1, 0xbb}, + {0xf0, 0x00, 0x00, 0xbb}, + {0x07, 0x00, 0x84, 0xbb}, + {0x08, 0x02, 0x4a, 0xbb}, + {0x05, 0x01, 0x10, 0xbb}, + {0x06, 0x00, 0x39, 0xbb}, + {0xf0, 0x00, 0x02, 0xbb}, + {0x58, 0x02, 0x67, 0xbb}, + {0x57, 0x02, 0x00, 0xbb}, + {0x5a, 0x02, 0x67, 0xbb}, + {0x59, 0x02, 0x00, 0xbb}, + {0x5c, 0x12, 0x0d, 0xbb}, + {0x5d, 0x16, 0x11, 0xbb}, + {0x39, 0x06, 0x18, 0xbb}, + {0x3a, 0x06, 0x18, 0xbb}, + {0x3b, 0x06, 0x18, 0xbb}, + {0x3c, 0x06, 0x18, 0xbb}, + {0x64, 0x7b, 0x5b, 0xbb}, + {0xf0, 0x00, 0x02, 0xbb}, + {0x36, 0x30, 0x10, 0xbb}, + {0x37, 0x00, 0xc0, 0xbb}, + {0xbc, 0x0e, 0x00, 0xcc}, + {0xbc, 0x0f, 0x05, 0xcc}, + {0xbc, 0x10, 0xc0, 0xcc}, + {0xbc, 0x11, 0x03, 0xcc}, + {0xb6, 0x00, 0x00, 0xcc}, + {0xb6, 0x03, 0x02, 0xcc}, + {0xb6, 0x02, 0x80, 0xcc}, + {0xb6, 0x05, 0x01, 0xcc}, + {0xb6, 0x04, 0xe0, 0xcc}, + {0xb6, 0x12, 0xf8, 0xcc}, + {0xb6, 0x13, 0x25, 0xcc}, + {0xb6, 0x18, 0x02, 0xcc}, + {0xb6, 0x17, 0x58, 0xcc}, + {0xb6, 0x16, 0x00, 0xcc}, + {0xb6, 0x22, 0x12, 0xcc}, + {0xb6, 0x23, 0x0b, 0xcc}, + {0xbf, 0xc0, 0x39, 0xcc}, + {0xbf, 0xc1, 0x04, 0xcc}, + {0xbf, 0xcc, 0x00, 0xcc}, + {0xbc, 0x02, 0x18, 0xcc}, + {0xbc, 0x03, 0x50, 0xcc}, + {0xbc, 0x04, 0x18, 0xcc}, + {0xbc, 0x05, 0x00, 0xcc}, + {0xbc, 0x06, 0x00, 0xcc}, + {0xbc, 0x08, 0x30, 0xcc}, + {0xbc, 0x09, 0x40, 0xcc}, + {0xbc, 0x0a, 0x10, 0xcc}, + {0xbc, 0x0b, 0x00, 0xcc}, + {0xbc, 0x0c, 0x00, 0xcc}, + {0xb3, 0x5c, 0x01, 0xcc}, + {0xf0, 0x00, 0x01, 0xbb}, + {0x80, 0x00, 0x03, 0xbb}, + {0x81, 0xc7, 0x14, 0xbb}, + {0x82, 0xeb, 0xe8, 0xbb}, + {0x83, 0xfe, 0xf4, 0xbb}, + {0x84, 0xcd, 0x10, 0xbb}, + {0x85, 0xf3, 0xee, 0xbb}, + {0x86, 0xff, 0xf1, 0xbb}, + {0x87, 0xcd, 0x10, 0xbb}, + {0x88, 0xf3, 0xee, 0xbb}, + {0x89, 0x01, 0xf1, 0xbb}, + {0x8a, 0xe5, 0x17, 0xbb}, + {0x8b, 0xe8, 0xe2, 0xbb}, + {0x8c, 0xf7, 0xed, 0xbb}, + {0x8d, 0x00, 0xff, 0xbb}, + {0x8e, 0xec, 0x10, 0xbb}, + {0x8f, 0xf0, 0xed, 0xbb}, + {0x90, 0xf9, 0xf2, 0xbb}, + {0x91, 0x00, 0x00, 0xbb}, + {0x92, 0xe9, 0x0d, 0xbb}, + {0x93, 0xf4, 0xf2, 0xbb}, + {0x94, 0xfb, 0xf5, 0xbb}, + {0x95, 0x00, 0xff, 0xbb}, + {0xb6, 0x0f, 0x08, 0xbb}, + {0xb7, 0x3d, 0x16, 0xbb}, + {0xb8, 0x0c, 0x04, 0xbb}, + {0xb9, 0x1c, 0x07, 0xbb}, + {0xba, 0x0a, 0x03, 0xbb}, + {0xbb, 0x1b, 0x09, 0xbb}, + {0xbc, 0x17, 0x0d, 0xbb}, + {0xbd, 0x23, 0x1d, 0xbb}, + {0xbe, 0x00, 0x28, 0xbb}, + {0xbf, 0x11, 0x09, 0xbb}, + {0xc0, 0x16, 0x15, 0xbb}, + {0xc1, 0x00, 0x1b, 0xbb}, + {0xc2, 0x0e, 0x07, 0xbb}, + {0xc3, 0x14, 0x10, 0xbb}, + {0xc4, 0x00, 0x17, 0xbb}, + {0x06, 0x74, 0x8e, 0xbb}, + {0xf0, 0x00, 0x01, 0xbb}, + {0x06, 0xf4, 0x8e, 0xbb}, + {0x00, 0x00, 0x50, 0xdd}, + {0x06, 0x74, 0x8e, 0xbb}, + {0xf0, 0x00, 0x02, 0xbb}, + {0x24, 0x50, 0x20, 0xbb}, + {0xf0, 0x00, 0x02, 0xbb}, + {0x34, 0x0c, 0x50, 0xbb}, + {0xb3, 0x01, 0x41, 0xcc}, + {0xf0, 0x00, 0x00, 0xbb}, + {0x03, 0x03, 0xc0, 0xbb}, + {}, +}; +static const __u8 mi1310_socinitQVGA_JPG[][4] = { + {0xb0, 0x03, 0x19, 0xcc}, {0xb0, 0x04, 0x02, 0xcc}, + {0xb3, 0x00, 0x64, 0xcc}, {0xb3, 0x00, 0x65, 0xcc}, + {0xb3, 0x05, 0x00, 0xcc}, {0xb3, 0x06, 0x00, 0xcc}, + {0xb3, 0x08, 0x01, 0xcc}, {0xb3, 0x09, 0x0c, 0xcc}, + {0xb3, 0x34, 0x02, 0xcc}, {0xb3, 0x35, 0xdd, 0xcc}, + {0xb3, 0x02, 0x00, 0xcc}, {0xb3, 0x03, 0x0a, 0xcc}, + {0xb3, 0x04, 0x05, 0xcc}, {0xb3, 0x20, 0x00, 0xcc}, + {0xb3, 0x21, 0x00, 0xcc}, {0xb3, 0x22, 0x03, 0xcc}, + {0xb3, 0x23, 0xc0, 0xcc}, {0xb3, 0x14, 0x00, 0xcc}, + {0xb3, 0x15, 0x00, 0xcc}, {0xb3, 0x16, 0x04, 0xcc}, + {0xb3, 0x17, 0xff, 0xcc}, {0xb3, 0x00, 0x65, 0xcc}, + {0xb8, 0x00, 0x00, 0xcc}, {0xbc, 0x00, 0xf0, 0xcc}, + {0xbc, 0x01, 0x01, 0xcc}, {0xf0, 0x00, 0x02, 0xbb}, + {0xc8, 0x9f, 0x0b, 0xbb}, {0x5b, 0x00, 0x01, 0xbb}, + {0x2f, 0xde, 0x20, 0xbb}, {0xf0, 0x00, 0x00, 0xbb}, + {0x20, 0x03, 0x02, 0xbb}, {0xf0, 0x00, 0x01, 0xbb}, + {0x05, 0x00, 0x07, 0xbb}, {0x34, 0x00, 0x00, 0xbb}, + {0x35, 0xff, 0x00, 0xbb}, {0xdc, 0x07, 0x02, 0xbb}, + {0xdd, 0x3c, 0x18, 0xbb}, {0xde, 0x92, 0x6d, 0xbb}, + {0xdf, 0xcd, 0xb1, 0xbb}, {0xe0, 0xff, 0xe7, 0xbb}, + {0x06, 0xf0, 0x0d, 0xbb}, {0x06, 0x70, 0x0e, 0xbb}, + {0x4c, 0x00, 0x01, 0xbb}, {0x4d, 0x00, 0x01, 0xbb}, + {0xf0, 0x00, 0x02, 0xbb}, {0x2e, 0x0c, 0x55, 0xbb}, + {0x21, 0xb6, 0x6e, 0xbb}, {0x36, 0x30, 0x10, 0xbb}, + {0x37, 0x00, 0xc1, 0xbb}, {0xf0, 0x00, 0x00, 0xbb}, + {0x07, 0x00, 0x84, 0xbb}, {0x08, 0x02, 0x4a, 0xbb}, + {0x05, 0x01, 0x10, 0xbb}, {0x06, 0x00, 0x39, 0xbb}, + {0xf0, 0x00, 0x02, 0xbb}, {0x58, 0x02, 0x67, 0xbb}, + {0x57, 0x02, 0x00, 0xbb}, {0x5a, 0x02, 0x67, 0xbb}, + {0x59, 0x02, 0x00, 0xbb}, {0x5c, 0x12, 0x0d, 0xbb}, + {0x5d, 0x16, 0x11, 0xbb}, {0x39, 0x06, 0x18, 0xbb}, + {0x3a, 0x06, 0x18, 0xbb}, {0x3b, 0x06, 0x18, 0xbb}, + {0x3c, 0x06, 0x18, 0xbb}, {0x64, 0x7b, 0x5b, 0xbb}, + {0xf0, 0x00, 0x02, 0xbb}, {0x36, 0x30, 0x10, 0xbb}, + {0x37, 0x00, 0xc0, 0xbb}, {0xbc, 0x0e, 0x00, 0xcc}, + {0xbc, 0x0f, 0x05, 0xcc}, {0xbc, 0x10, 0xc0, 0xcc}, + {0xbc, 0x11, 0x03, 0xcc}, {0xb6, 0x00, 0x00, 0xcc}, + {0xb6, 0x03, 0x01, 0xcc}, {0xb6, 0x02, 0x40, 0xcc}, + {0xb6, 0x05, 0x00, 0xcc}, {0xb6, 0x04, 0xf0, 0xcc}, + {0xb6, 0x12, 0xf8, 0xcc}, {0xb6, 0x13, 0x25, 0xcc}, + {0xb6, 0x18, 0x00, 0xcc}, {0xb6, 0x17, 0x96, 0xcc}, + {0xb6, 0x16, 0x00, 0xcc}, {0xb6, 0x22, 0x12, 0xcc}, + {0xb6, 0x23, 0x0b, 0xcc}, {0xbf, 0xc0, 0x39, 0xcc}, + {0xbf, 0xc1, 0x04, 0xcc}, {0xbf, 0xcc, 0x00, 0xcc}, + {0xb3, 0x5c, 0x01, 0xcc}, {0xf0, 0x00, 0x01, 0xbb}, + {0x80, 0x00, 0x03, 0xbb}, {0x81, 0xc7, 0x14, 0xbb}, + {0x82, 0xeb, 0xe8, 0xbb}, {0x83, 0xfe, 0xf4, 0xbb}, + {0x84, 0xcd, 0x10, 0xbb}, {0x85, 0xf3, 0xee, 0xbb}, + {0x86, 0xff, 0xf1, 0xbb}, {0x87, 0xcd, 0x10, 0xbb}, + {0x88, 0xf3, 0xee, 0xbb}, {0x89, 0x01, 0xf1, 0xbb}, + {0x8a, 0xe5, 0x17, 0xbb}, {0x8b, 0xe8, 0xe2, 0xbb}, + {0x8c, 0xf7, 0xed, 0xbb}, {0x8d, 0x00, 0xff, 0xbb}, + {0x8e, 0xec, 0x10, 0xbb}, {0x8f, 0xf0, 0xed, 0xbb}, + {0x90, 0xf9, 0xf2, 0xbb}, {0x91, 0x00, 0x00, 0xbb}, + {0x92, 0xe9, 0x0d, 0xbb}, {0x93, 0xf4, 0xf2, 0xbb}, + {0x94, 0xfb, 0xf5, 0xbb}, {0x95, 0x00, 0xff, 0xbb}, + {0xb6, 0x0f, 0x08, 0xbb}, {0xb7, 0x3d, 0x16, 0xbb}, + {0xb8, 0x0c, 0x04, 0xbb}, {0xb9, 0x1c, 0x07, 0xbb}, + {0xba, 0x0a, 0x03, 0xbb}, {0xbb, 0x1b, 0x09, 0xbb}, + {0xbc, 0x17, 0x0d, 0xbb}, {0xbd, 0x23, 0x1d, 0xbb}, + {0xbe, 0x00, 0x28, 0xbb}, {0xbf, 0x11, 0x09, 0xbb}, + {0xc0, 0x16, 0x15, 0xbb}, {0xc1, 0x00, 0x1b, 0xbb}, + {0xc2, 0x0e, 0x07, 0xbb}, {0xc3, 0x14, 0x10, 0xbb}, + {0xc4, 0x00, 0x17, 0xbb}, {0x06, 0x74, 0x8e, 0xbb}, + {0xf0, 0x00, 0x01, 0xbb}, {0x06, 0xf4, 0x8e, 0xbb}, + {0x00, 0x00, 0x50, 0xdd}, {0x06, 0x74, 0x8e, 0xbb}, + {0xf0, 0x00, 0x02, 0xbb}, {0x24, 0x50, 0x20, 0xbb}, + {0xf0, 0x00, 0x02, 0xbb}, {0x34, 0x0c, 0x50, 0xbb}, + {0xb3, 0x01, 0x41, 0xcc}, {0xf0, 0x00, 0x00, 0xbb}, + {0x03, 0x03, 0xc0, 0xbb}, + {}, +}; + +static const __u8 mi1320_gamma[17] = { + 0x00, 0x13, 0x38, 0x59, 0x79, 0x92, 0xa7, 0xb9, 0xc8, + 0xd4, 0xdf, 0xe7, 0xee, 0xf4, 0xf9, 0xfc, 0xff +}; +static const __u8 mi1320_matrix[9] = { + 0x54, 0xda, 0x06, 0xf1, 0x50, 0xf4, 0xf7, 0xea, 0x52 +}; +static const __u8 mi1320_initVGA_data[][4] = { + {0xb3, 0x01, 0x01, 0xcc}, {0x00, 0x00, 0x33, 0xdd}, + {0xb0, 0x03, 0x19, 0xcc}, {0x00, 0x00, 0x33, 0xdd}, + {0xb0, 0x04, 0x02, 0xcc}, {0x00, 0x00, 0x33, 0xdd}, + {0xb3, 0x00, 0x64, 0xcc}, {0xb3, 0x00, 0x65, 0xcc}, + {0xb0, 0x16, 0x03, 0xcc}, {0xb3, 0x05, 0x00, 0xcc}, + {0xb3, 0x06, 0x00, 0xcc}, {0xb3, 0x08, 0x01, 0xcc}, + {0xb3, 0x09, 0x0c, 0xcc}, {0xb3, 0x34, 0x02, 0xcc}, + {0xb3, 0x35, 0xc8, 0xcc}, {0xb3, 0x02, 0x00, 0xcc}, + {0xb3, 0x03, 0x0a, 0xcc}, {0xb3, 0x04, 0x05, 0xcc}, + {0xb3, 0x20, 0x00, 0xcc}, {0xb3, 0x21, 0x00, 0xcc}, + {0xb3, 0x22, 0x03, 0xcc}, {0xb3, 0x23, 0xc0, 0xcc}, + {0xb3, 0x14, 0x00, 0xcc}, {0xb3, 0x15, 0x00, 0xcc}, + {0xb3, 0x16, 0x04, 0xcc}, {0xb3, 0x17, 0xff, 0xcc}, + {0xb3, 0x00, 0x67, 0xcc}, {0xbc, 0x00, 0xd0, 0xcc}, + {0xbc, 0x01, 0x01, 0xcc}, {0xf0, 0x00, 0x00, 0xbb}, + {0x0d, 0x00, 0x09, 0xbb}, {0x00, 0x01, 0x00, 0xdd}, + {0x0d, 0x00, 0x08, 0xbb}, {0xf0, 0x00, 0x01, 0xbb}, + {0xa1, 0x05, 0x00, 0xbb}, {0xa4, 0x03, 0xc0, 0xbb}, + {0xf0, 0x00, 0x02, 0xbb}, {0x00, 0x00, 0x10, 0xdd}, + {0xc8, 0x9f, 0x0b, 0xbb}, {0x00, 0x00, 0x10, 0xdd}, + {0xf0, 0x00, 0x00, 0xbb}, {0x00, 0x00, 0x10, 0xdd}, + {0x20, 0x01, 0x00, 0xbb}, {0x00, 0x00, 0x10, 0xdd}, + {0xf0, 0x00, 0x01, 0xbb}, {0x9d, 0x3c, 0xa0, 0xbb}, + {0x47, 0x30, 0x30, 0xbb}, {0xf0, 0x00, 0x00, 0xbb}, + {0x0a, 0x80, 0x11, 0xbb}, {0x35, 0x00, 0x22, 0xbb}, + {0xf0, 0x00, 0x02, 0xbb}, {0x9d, 0xc5, 0x05, 0xbb}, + {0xdc, 0x0f, 0xfc, 0xbb}, {0xf0, 0x00, 0x01, 0xbb}, + {0x06, 0x74, 0x0e, 0xbb}, {0x80, 0x00, 0x06, 0xbb}, + {0x81, 0x04, 0x00, 0xbb}, {0x82, 0x01, 0x02, 0xbb}, + {0x83, 0x03, 0x02, 0xbb}, {0x84, 0x05, 0x00, 0xbb}, + {0x85, 0x01, 0x00, 0xbb}, {0x86, 0x03, 0x02, 0xbb}, + {0x87, 0x05, 0x00, 0xbb}, {0x88, 0x01, 0x00, 0xbb}, + {0x89, 0x02, 0x02, 0xbb}, {0x8a, 0xfd, 0x04, 0xbb}, + {0x8b, 0xfc, 0xfd, 0xbb}, {0x8c, 0xff, 0xfd, 0xbb}, + {0x8d, 0x00, 0x00, 0xbb}, {0x8e, 0xfe, 0x05, 0xbb}, + {0x8f, 0xfc, 0xfd, 0xbb}, {0x90, 0xfe, 0xfd, 0xbb}, + {0x91, 0x00, 0x00, 0xbb}, {0x92, 0xfe, 0x03, 0xbb}, + {0x93, 0xfd, 0xfe, 0xbb}, {0x94, 0xff, 0xfd, 0xbb}, + {0x95, 0x00, 0x00, 0xbb}, {0xb6, 0x07, 0x05, 0xbb}, + {0xb7, 0x13, 0x06, 0xbb}, {0xb8, 0x08, 0x06, 0xbb}, + {0xb9, 0x14, 0x08, 0xbb}, {0xba, 0x06, 0x05, 0xbb}, + {0xbb, 0x13, 0x06, 0xbb}, {0xbc, 0x03, 0x01, 0xbb}, + {0xbd, 0x03, 0x04, 0xbb}, {0xbe, 0x00, 0x02, 0xbb}, + {0xbf, 0x03, 0x01, 0xbb}, {0xc0, 0x02, 0x04, 0xbb}, + {0xc1, 0x00, 0x04, 0xbb}, {0xc2, 0x02, 0x01, 0xbb}, + {0xc3, 0x01, 0x03, 0xbb}, {0xc4, 0x00, 0x04, 0xbb}, + {0xf0, 0x00, 0x00, 0xbb}, {0x05, 0x01, 0x13, 0xbb}, + {0x06, 0x00, 0x11, 0xbb}, {0x07, 0x00, 0x85, 0xbb}, + {0x08, 0x00, 0x27, 0xbb}, {0x20, 0x01, 0x03, 0xbb}, + {0x21, 0x80, 0x00, 0xbb}, {0x22, 0x0d, 0x0f, 0xbb}, + {0x24, 0x80, 0x00, 0xbb}, {0x59, 0x00, 0xff, 0xbb}, + {0xf0, 0x00, 0x02, 0xbb}, {0x39, 0x03, 0x0d, 0xbb}, + {0x3a, 0x06, 0x1b, 0xbb}, {0x3b, 0x00, 0x95, 0xbb}, + {0x3c, 0x04, 0xdb, 0xbb}, {0x57, 0x02, 0x00, 0xbb}, + {0x58, 0x02, 0x66, 0xbb}, {0x59, 0x00, 0xff, 0xbb}, + {0x5a, 0x01, 0x33, 0xbb}, {0x5c, 0x12, 0x0d, 0xbb}, + {0x5d, 0x16, 0x11, 0xbb}, {0x64, 0x5e, 0x1c, 0xbb}, + {0xf0, 0x00, 0x02, 0xbb}, {0x2f, 0xd1, 0x00, 0xbb}, + {0x5b, 0x00, 0x01, 0xbb}, {0xf0, 0x00, 0x02, 0xbb}, + {0x36, 0x68, 0x10, 0xbb}, {0x00, 0x00, 0x30, 0xdd}, + {0x37, 0x82, 0x00, 0xbb}, {0xbc, 0x0e, 0x00, 0xcc}, + {0xbc, 0x0f, 0x05, 0xcc}, {0xbc, 0x10, 0xc0, 0xcc}, + {0xbc, 0x11, 0x03, 0xcc}, {0xb6, 0x00, 0x00, 0xcc}, + {0xb6, 0x03, 0x05, 0xcc}, {0xb6, 0x02, 0x00, 0xcc}, + {0xb6, 0x05, 0x04, 0xcc}, {0xb6, 0x04, 0x00, 0xcc}, + {0xb6, 0x12, 0xf8, 0xcc}, {0xb6, 0x13, 0x29, 0xcc}, + {0xb6, 0x18, 0x0a, 0xcc}, {0xb6, 0x17, 0x00, 0xcc}, + {0xb6, 0x16, 0x00, 0xcc}, {0xb6, 0x22, 0x12, 0xcc}, + {0xb6, 0x23, 0x0b, 0xcc}, {0xbf, 0xc0, 0x26, 0xcc}, + {0xbf, 0xc1, 0x02, 0xcc}, {0xbf, 0xcc, 0x04, 0xcc}, + {0xbc, 0x02, 0x18, 0xcc}, {0xbc, 0x03, 0x50, 0xcc}, + {0xbc, 0x04, 0x18, 0xcc}, {0xbc, 0x05, 0x00, 0xcc}, + {0xbc, 0x06, 0x00, 0xcc}, {0xbc, 0x08, 0x30, 0xcc}, + {0xbc, 0x09, 0x40, 0xcc}, {0xbc, 0x0a, 0x10, 0xcc}, + {0xbc, 0x0b, 0x00, 0xcc}, {0xbc, 0x0c, 0x00, 0xcc}, + {0xb3, 0x5c, 0x01, 0xcc}, {0xb3, 0x01, 0x41, 0xcc}, + {} +}; +static const __u8 mi1320_initQVGA_data[][4] = { + {0xb3, 0x01, 0x01, 0xcc}, {0x00, 0x00, 0x33, 0xdd}, + {0xb0, 0x03, 0x19, 0xcc}, {0x00, 0x00, 0x33, 0xdd}, + {0xb0, 0x04, 0x02, 0xcc}, {0x00, 0x00, 0x33, 0xdd}, + {0xb3, 0x00, 0x64, 0xcc}, {0xb3, 0x00, 0x65, 0xcc}, + {0xb0, 0x16, 0x03, 0xcc}, {0xb3, 0x05, 0x01, 0xcc}, + {0xb3, 0x06, 0x01, 0xcc}, {0xb3, 0x08, 0x01, 0xcc}, + {0xb3, 0x09, 0x0c, 0xcc}, {0xb3, 0x34, 0x02, 0xcc}, + {0xb3, 0x35, 0xc8, 0xcc}, {0xb3, 0x02, 0x00, 0xcc}, + {0xb3, 0x03, 0x0a, 0xcc}, {0xb3, 0x04, 0x05, 0xcc}, + {0xb3, 0x20, 0x00, 0xcc}, {0xb3, 0x21, 0x00, 0xcc}, + {0xb3, 0x22, 0x01, 0xcc}, {0xb3, 0x23, 0xe0, 0xcc}, + {0xb3, 0x14, 0x00, 0xcc}, {0xb3, 0x15, 0x00, 0xcc}, + {0xb3, 0x16, 0x02, 0xcc}, {0xb3, 0x17, 0x7f, 0xcc}, + {0xb3, 0x00, 0x65, 0xcc}, {0xb8, 0x00, 0x00, 0xcc}, + {0xbc, 0x00, 0xd0, 0xcc}, {0xbc, 0x01, 0x01, 0xcc}, + {0xf0, 0x00, 0x00, 0xbb}, {0x0d, 0x00, 0x09, 0xbb}, + {0x00, 0x01, 0x00, 0xdd}, {0x0d, 0x00, 0x08, 0xbb}, + {0xf0, 0x00, 0x00, 0xbb}, {0x02, 0x00, 0x64, 0xbb}, + {0x05, 0x01, 0x78, 0xbb}, {0x06, 0x00, 0x11, 0xbb}, + {0x07, 0x01, 0x42, 0xbb}, {0x08, 0x00, 0x11, 0xbb}, + {0x20, 0x01, 0x00, 0xbb}, {0x21, 0x80, 0x00, 0xbb}, + {0x22, 0x0d, 0x0f, 0xbb}, {0x24, 0x80, 0x00, 0xbb}, + {0x59, 0x00, 0xff, 0xbb}, {0xf0, 0x00, 0x01, 0xbb}, + {0x9d, 0x3c, 0xa0, 0xbb}, {0x47, 0x30, 0x30, 0xbb}, + {0xf0, 0x00, 0x00, 0xbb}, {0x0a, 0x80, 0x11, 0xbb}, + {0x35, 0x00, 0x22, 0xbb}, {0xf0, 0x00, 0x02, 0xbb}, + {0x9d, 0xc5, 0x05, 0xbb}, {0xdc, 0x0f, 0xfc, 0xbb}, + {0xf0, 0x00, 0x01, 0xbb}, {0x06, 0x74, 0x0e, 0xbb}, + {0x80, 0x00, 0x06, 0xbb}, {0x81, 0x04, 0x00, 0xbb}, + {0x82, 0x01, 0x02, 0xbb}, {0x83, 0x03, 0x02, 0xbb}, + {0x84, 0x05, 0x00, 0xbb}, {0x85, 0x01, 0x00, 0xbb}, + {0x86, 0x03, 0x02, 0xbb}, {0x87, 0x05, 0x00, 0xbb}, + {0x88, 0x01, 0x00, 0xbb}, {0x89, 0x02, 0x02, 0xbb}, + {0x8a, 0xfd, 0x04, 0xbb}, {0x8b, 0xfc, 0xfd, 0xbb}, + {0x8c, 0xff, 0xfd, 0xbb}, {0x8d, 0x00, 0x00, 0xbb}, + {0x8e, 0xfe, 0x05, 0xbb}, {0x8f, 0xfc, 0xfd, 0xbb}, + {0x90, 0xfe, 0xfd, 0xbb}, {0x91, 0x00, 0x00, 0xbb}, + {0x92, 0xfe, 0x03, 0xbb}, {0x93, 0xfd, 0xfe, 0xbb}, + {0x94, 0xff, 0xfd, 0xbb}, {0x95, 0x00, 0x00, 0xbb}, + {0xb6, 0x07, 0x05, 0xbb}, {0xb7, 0x13, 0x06, 0xbb}, + {0xb8, 0x08, 0x06, 0xbb}, {0xb9, 0x14, 0x08, 0xbb}, + {0xba, 0x06, 0x05, 0xbb}, {0xbb, 0x13, 0x06, 0xbb}, + {0xbc, 0x03, 0x01, 0xbb}, {0xbd, 0x03, 0x04, 0xbb}, + {0xbe, 0x00, 0x02, 0xbb}, {0xbf, 0x03, 0x01, 0xbb}, + {0xc0, 0x02, 0x04, 0xbb}, {0xc1, 0x00, 0x04, 0xbb}, + {0xc2, 0x02, 0x01, 0xbb}, {0xc3, 0x01, 0x03, 0xbb}, + {0xc4, 0x00, 0x04, 0xbb}, {0xf0, 0x00, 0x02, 0xbb}, + {0xc8, 0x00, 0x00, 0xbb}, {0x2e, 0x00, 0x00, 0xbb}, + {0x2e, 0x0c, 0x5b, 0xbb}, {0x2f, 0xd1, 0x00, 0xbb}, + {0x39, 0x03, 0xca, 0xbb}, {0x3a, 0x06, 0x80, 0xbb}, + {0x3b, 0x01, 0x52, 0xbb}, {0x3c, 0x05, 0x40, 0xbb}, + {0x57, 0x01, 0x9c, 0xbb}, {0x58, 0x01, 0xee, 0xbb}, + {0x59, 0x00, 0xf0, 0xbb}, {0x5a, 0x01, 0x20, 0xbb}, + {0x5c, 0x1d, 0x17, 0xbb}, {0x5d, 0x22, 0x1c, 0xbb}, + {0x64, 0x1e, 0x1c, 0xbb}, {0x5b, 0x00, 0x01, 0xbb}, + {0xf0, 0x00, 0x02, 0xbb}, {0x36, 0x68, 0x10, 0xbb}, + {0x00, 0x00, 0x30, 0xdd}, {0x37, 0x81, 0x00, 0xbb}, + {0xbc, 0x02, 0x18, 0xcc}, {0xbc, 0x03, 0x50, 0xcc}, + {0xbc, 0x04, 0x18, 0xcc}, {0xbc, 0x05, 0x00, 0xcc}, + {0xbc, 0x06, 0x00, 0xcc}, {0xbc, 0x08, 0x30, 0xcc}, + {0xbc, 0x09, 0x40, 0xcc}, {0xbc, 0x0a, 0x10, 0xcc}, + {0xbc, 0x0b, 0x00, 0xcc}, {0xbc, 0x0c, 0x00, 0xcc}, + {0xbf, 0xc0, 0x26, 0xcc}, {0xbf, 0xc1, 0x02, 0xcc}, + {0xbf, 0xcc, 0x04, 0xcc}, {0xb3, 0x5c, 0x01, 0xcc}, + {0xb3, 0x01, 0x41, 0xcc}, + {} +}; + +static const __u8 po3130_gamma[17] = { + 0x00, 0x13, 0x38, 0x59, 0x79, 0x92, 0xa7, 0xb9, 0xc8, + 0xd4, 0xdf, 0xe7, 0xee, 0xf4, 0xf9, 0xfc, 0xff +}; +static const __u8 po3130_matrix[9] = { + 0x5f, 0xec, 0xf5, 0xf1, 0x5a, 0xf5, 0xf1, 0xec, 0x63 +}; + +static const __u8 po3130_initVGA_data[][4] = { + {0xb0, 0x4d, 0x00, 0xcc}, {0xb3, 0x01, 0x01, 0xcc}, + {0x00, 0x00, 0x50, 0xdd}, {0xb0, 0x03, 0x01, 0xcc}, + {0xb3, 0x00, 0x04, 0xcc}, {0xb3, 0x00, 0x24, 0xcc}, + {0xb3, 0x00, 0x25, 0xcc}, {0xb3, 0x08, 0x01, 0xcc}, + {0xb3, 0x09, 0x0c, 0xcc}, {0xb3, 0x05, 0x00, 0xcc}, + {0xb3, 0x06, 0x01, 0xcc}, {0xb3, 0x03, 0x1a, 0xcc}, + {0xb3, 0x04, 0x15, 0xcc}, {0xb3, 0x20, 0x00, 0xcc}, + {0xb3, 0x21, 0x00, 0xcc}, {0xb3, 0x22, 0x01, 0xcc}, + {0xb3, 0x23, 0xe8, 0xcc}, {0xb8, 0x08, 0xe8, 0xcc}, + {0xb3, 0x14, 0x00, 0xcc}, {0xb3, 0x15, 0x00, 0xcc}, + {0xb3, 0x16, 0x02, 0xcc}, {0xb3, 0x17, 0x7f, 0xcc}, + {0xb3, 0x34, 0x01, 0xcc}, {0xb3, 0x35, 0xf6, 0xcc}, + {0xb3, 0x00, 0x27, 0xcc}, {0xbc, 0x00, 0x71, 0xcc}, + {0xb8, 0x00, 0x21, 0xcc}, {0xb8, 0x27, 0x20, 0xcc}, + {0xb8, 0x01, 0x79, 0xcc}, {0xb8, 0x81, 0x09, 0xcc}, + {0xb8, 0x2c, 0x50, 0xcc}, {0xb8, 0x2d, 0xf8, 0xcc}, + {0xb8, 0x2e, 0xf8, 0xcc}, {0xb8, 0x2f, 0xf8, 0xcc}, + {0xb8, 0x30, 0x50, 0xcc}, {0xb8, 0x31, 0xf8, 0xcc}, + {0xb8, 0x32, 0xf8, 0xcc}, {0xb8, 0x33, 0xf8, 0xcc}, + {0xb8, 0x34, 0x50, 0xcc}, {0xb8, 0x35, 0x00, 0xcc}, + {0xb8, 0x36, 0x00, 0xcc}, {0xb8, 0x37, 0x00, 0xcc}, + {0x00, 0x1e, 0xc6, 0xaa}, {0x00, 0x20, 0x44, 0xaa}, + {0x00, 0xad, 0x02, 0xaa}, {0x00, 0xae, 0x2c, 0xaa}, + {0x00, 0x12, 0x08, 0xaa}, {0x00, 0x17, 0x41, 0xaa}, + {0x00, 0x19, 0x41, 0xaa}, {0x00, 0x1e, 0x06, 0xaa}, + {0x00, 0x21, 0x00, 0xaa}, {0x00, 0x36, 0xc0, 0xaa}, + {0x00, 0x37, 0xc8, 0xaa}, {0x00, 0x3b, 0x36, 0xaa}, + {0x00, 0x4b, 0xfe, 0xaa}, {0x00, 0x51, 0x1c, 0xaa}, + {0x00, 0x52, 0x01, 0xaa}, {0x00, 0x55, 0x0a, 0xaa}, + {0x00, 0x59, 0x02, 0xaa}, {0x00, 0x5a, 0x04, 0xaa}, + {0x00, 0x5c, 0x10, 0xaa}, {0x00, 0x5d, 0x10, 0xaa}, + {0x00, 0x5e, 0x10, 0xaa}, {0x00, 0x5f, 0x10, 0xaa}, + {0x00, 0x61, 0x00, 0xaa}, {0x00, 0x62, 0x18, 0xaa}, + {0x00, 0x63, 0x30, 0xaa}, {0x00, 0x70, 0x68, 0xaa}, + {0x00, 0x80, 0x71, 0xaa}, {0x00, 0x81, 0x08, 0xaa}, + {0x00, 0x82, 0x00, 0xaa}, {0x00, 0x83, 0x55, 0xaa}, + {0x00, 0x84, 0x06, 0xaa}, {0x00, 0x85, 0x06, 0xaa}, + {0x00, 0x86, 0x13, 0xaa}, {0x00, 0x87, 0x18, 0xaa}, + {0x00, 0xaa, 0x3f, 0xaa}, {0x00, 0xab, 0x44, 0xaa}, + {0x00, 0xb0, 0x68, 0xaa}, {0x00, 0xb5, 0x10, 0xaa}, + {0x00, 0xb8, 0x20, 0xaa}, {0x00, 0xb9, 0xa0, 0xaa}, + {0x00, 0xbc, 0x04, 0xaa}, {0x00, 0x8b, 0x40, 0xaa}, + {0x00, 0x8c, 0x91, 0xaa}, {0x00, 0x8d, 0x8f, 0xaa}, + {0x00, 0x8e, 0x91, 0xaa}, {0x00, 0x8f, 0x43, 0xaa}, + {0x00, 0x90, 0x92, 0xaa}, {0x00, 0x91, 0x89, 0xaa}, + {0x00, 0x92, 0x9d, 0xaa}, {0x00, 0x93, 0x46, 0xaa}, + {0x00, 0xd6, 0x22, 0xaa}, {0x00, 0x73, 0x00, 0xaa}, + {0x00, 0x74, 0x10, 0xaa}, {0x00, 0x75, 0x20, 0xaa}, + {0x00, 0x76, 0x2b, 0xaa}, {0x00, 0x77, 0x36, 0xaa}, + {0x00, 0x78, 0x49, 0xaa}, {0x00, 0x79, 0x5a, 0xaa}, + {0x00, 0x7a, 0x7f, 0xaa}, {0x00, 0x7b, 0x9b, 0xaa}, + {0x00, 0x7c, 0xba, 0xaa}, {0x00, 0x7d, 0xd4, 0xaa}, + {0x00, 0x7e, 0xea, 0xaa}, {0x00, 0xd6, 0x62, 0xaa}, + {0x00, 0x73, 0x00, 0xaa}, {0x00, 0x74, 0x10, 0xaa}, + {0x00, 0x75, 0x20, 0xaa}, {0x00, 0x76, 0x2b, 0xaa}, + {0x00, 0x77, 0x36, 0xaa}, {0x00, 0x78, 0x49, 0xaa}, + {0x00, 0x79, 0x5a, 0xaa}, {0x00, 0x7a, 0x7f, 0xaa}, + {0x00, 0x7b, 0x9b, 0xaa}, {0x00, 0x7c, 0xba, 0xaa}, + {0x00, 0x7d, 0xd4, 0xaa}, {0x00, 0x7e, 0xea, 0xaa}, + {0x00, 0xd6, 0xa2, 0xaa}, {0x00, 0x73, 0x00, 0xaa}, + {0x00, 0x74, 0x10, 0xaa}, {0x00, 0x75, 0x20, 0xaa}, + {0x00, 0x76, 0x2b, 0xaa}, {0x00, 0x77, 0x36, 0xaa}, + {0x00, 0x78, 0x49, 0xaa}, {0x00, 0x79, 0x5a, 0xaa}, + {0x00, 0x7a, 0x7f, 0xaa}, {0x00, 0x7b, 0x9b, 0xaa}, + {0x00, 0x7c, 0xba, 0xaa}, {0x00, 0x7d, 0xd4, 0xaa}, + {0x00, 0x7e, 0xea, 0xaa}, + {0x00, 0x4c, 0x07, 0xaa}, + {0x00, 0x4b, 0xe0, 0xaa}, {0x00, 0x4e, 0x77, 0xaa}, + {0x00, 0x59, 0x02, 0xaa}, {0x00, 0x4d, 0x0a, 0xaa}, +/* {0x00, 0xd1, 0x00, 0xaa}, {0x00, 0x20, 0xc4, 0xaa}, + {0xb8, 0x8e, 0x00, 0xcc}, {0xb8, 0x8f, 0xff, 0xcc}, */ + {0x00, 0xd1, 0x3c, 0xaa}, {0x00, 0x20, 0xc4, 0xaa}, + {0xb8, 0x8e, 0x00, 0xcc}, {0xb8, 0x8f, 0xff, 0xcc}, + {0xb8, 0xfe, 0x00, 0xcc}, {0xb8, 0xff, 0x28, 0xcc}, + {0xb9, 0x00, 0x28, 0xcc}, {0xb9, 0x01, 0x28, 0xcc}, + {0xb9, 0x02, 0x28, 0xcc}, {0xb9, 0x03, 0x00, 0xcc}, + {0xb9, 0x04, 0x00, 0xcc}, {0xb9, 0x05, 0x3c, 0xcc}, + {0xb9, 0x06, 0x3c, 0xcc}, {0xb9, 0x07, 0x3c, 0xcc}, + {0xb9, 0x08, 0x3c, 0xcc}, {0x00, 0x05, 0x00, 0xaa}, + {0xb3, 0x5c, 0x00, 0xcc}, {0xb3, 0x01, 0x41, 0xcc}, + {} +}; +static const __u8 po3130_rundata[][4] = { + {0x00, 0x47, 0x45, 0xaa}, {0x00, 0x48, 0x9b, 0xaa}, + {0x00, 0x49, 0x3a, 0xaa}, {0x00, 0x4a, 0x01, 0xaa}, + {0x00, 0x44, 0x40, 0xaa}, +/* {0x00, 0xd5, 0x7c, 0xaa}, */ + {0x00, 0xad, 0x04, 0xaa}, {0x00, 0xae, 0x00, 0xaa}, + {0x00, 0xb0, 0x78, 0xaa}, {0x00, 0x98, 0x02, 0xaa}, + {0x00, 0x94, 0x25, 0xaa}, {0x00, 0x95, 0x25, 0xaa}, + {0x00, 0x59, 0x68, 0xaa}, {0x00, 0x44, 0x20, 0xaa}, + {0x00, 0x17, 0x50, 0xaa}, {0x00, 0x19, 0x50, 0xaa}, + {0x00, 0xd1, 0x3c, 0xaa}, {0x00, 0xd1, 0x3c, 0xaa}, + {0x00, 0x1e, 0x06, 0xaa}, {0x00, 0x1e, 0x06, 0xaa}, + {} +}; + +static const __u8 po3130_initQVGA_data[][4] = { + {0xb0, 0x4d, 0x00, 0xcc}, {0xb3, 0x01, 0x01, 0xcc}, + {0x00, 0x00, 0x50, 0xdd}, {0xb0, 0x03, 0x09, 0xcc}, + {0xb3, 0x00, 0x04, 0xcc}, {0xb3, 0x00, 0x24, 0xcc}, + {0xb3, 0x00, 0x25, 0xcc}, {0xb3, 0x08, 0x01, 0xcc}, + {0xb3, 0x09, 0x0c, 0xcc}, {0xb3, 0x05, 0x00, 0xcc}, + {0xb3, 0x06, 0x01, 0xcc}, {0xb3, 0x03, 0x1a, 0xcc}, + {0xb3, 0x04, 0x15, 0xcc}, {0xb3, 0x20, 0x00, 0xcc}, + {0xb3, 0x21, 0x00, 0xcc}, {0xb3, 0x22, 0x01, 0xcc}, + {0xb3, 0x23, 0xe0, 0xcc}, {0xb8, 0x08, 0xe0, 0xcc}, + {0xb3, 0x14, 0x00, 0xcc}, {0xb3, 0x15, 0x00, 0xcc}, + {0xb3, 0x16, 0x02, 0xcc}, {0xb3, 0x17, 0x7f, 0xcc}, + {0xb3, 0x34, 0x01, 0xcc}, {0xb3, 0x35, 0xf6, 0xcc}, + {0xb3, 0x00, 0x27, 0xcc}, {0xbc, 0x00, 0xd1, 0xcc}, + {0xb8, 0x00, 0x21, 0xcc}, {0xb8, 0x27, 0x20, 0xcc}, + {0xb8, 0x01, 0x79, 0xcc}, {0xb8, 0x81, 0x09, 0xcc}, + {0xb8, 0x2c, 0x50, 0xcc}, {0xb8, 0x2d, 0xf8, 0xcc}, + {0xb8, 0x2e, 0xf8, 0xcc}, {0xb8, 0x2f, 0xf8, 0xcc}, + {0xb8, 0x30, 0x50, 0xcc}, {0xb8, 0x31, 0xf8, 0xcc}, + {0xb8, 0x32, 0xf8, 0xcc}, {0xb8, 0x33, 0xf8, 0xcc}, + {0xb8, 0x34, 0x50, 0xcc}, {0xb8, 0x35, 0x00, 0xcc}, + {0xb8, 0x36, 0x00, 0xcc}, {0xb8, 0x37, 0x00, 0xcc}, + {0x00, 0x1e, 0xc6, 0xaa}, {0x00, 0x20, 0x44, 0xaa}, + {0x00, 0xad, 0x02, 0xaa}, {0x00, 0xae, 0x2c, 0xaa}, + {0x00, 0x12, 0x08, 0xaa}, {0x00, 0x17, 0x41, 0xaa}, + {0x00, 0x19, 0x41, 0xaa}, {0x00, 0x1e, 0x06, 0xaa}, + {0x00, 0x21, 0x00, 0xaa}, {0x00, 0x36, 0xc0, 0xaa}, + {0x00, 0x37, 0xc8, 0xaa}, {0x00, 0x3b, 0x36, 0xaa}, + {0x00, 0x4b, 0xfe, 0xaa}, {0x00, 0x51, 0x1c, 0xaa}, + {0x00, 0x52, 0x01, 0xaa}, {0x00, 0x55, 0x0a, 0xaa}, + {0x00, 0x59, 0x6f, 0xaa}, {0x00, 0x5a, 0x04, 0xaa}, + {0x00, 0x5c, 0x10, 0xaa}, {0x00, 0x5d, 0x10, 0xaa}, + {0x00, 0x5e, 0x10, 0xaa}, {0x00, 0x5f, 0x10, 0xaa}, + {0x00, 0x61, 0x00, 0xaa}, {0x00, 0x62, 0x18, 0xaa}, + {0x00, 0x63, 0x30, 0xaa}, {0x00, 0x70, 0x68, 0xaa}, + {0x00, 0x80, 0x71, 0xaa}, {0x00, 0x81, 0x08, 0xaa}, + {0x00, 0x82, 0x00, 0xaa}, {0x00, 0x83, 0x55, 0xaa}, + {0x00, 0x84, 0x06, 0xaa}, {0x00, 0x85, 0x06, 0xaa}, + {0x00, 0x86, 0x13, 0xaa}, {0x00, 0x87, 0x18, 0xaa}, + {0x00, 0xaa, 0x3f, 0xaa}, {0x00, 0xab, 0x44, 0xaa}, + {0x00, 0xb0, 0x68, 0xaa}, {0x00, 0xb5, 0x10, 0xaa}, + {0x00, 0xb8, 0x20, 0xaa}, {0x00, 0xb9, 0xa0, 0xaa}, + {0x00, 0xbc, 0x04, 0xaa}, {0x00, 0x8b, 0x40, 0xaa}, + {0x00, 0x8c, 0x91, 0xaa}, {0x00, 0x8d, 0x8f, 0xaa}, + {0x00, 0x8e, 0x91, 0xaa}, {0x00, 0x8f, 0x43, 0xaa}, + {0x00, 0x90, 0x92, 0xaa}, {0x00, 0x91, 0x89, 0xaa}, + {0x00, 0x92, 0x9d, 0xaa}, {0x00, 0x93, 0x46, 0xaa}, + {0x00, 0xd6, 0x22, 0xaa}, {0x00, 0x73, 0x00, 0xaa}, + {0x00, 0x74, 0x10, 0xaa}, {0x00, 0x75, 0x20, 0xaa}, + {0x00, 0x76, 0x2b, 0xaa}, {0x00, 0x77, 0x36, 0xaa}, + {0x00, 0x78, 0x49, 0xaa}, {0x00, 0x79, 0x5a, 0xaa}, + {0x00, 0x7a, 0x7f, 0xaa}, {0x00, 0x7b, 0x9b, 0xaa}, + {0x00, 0x7c, 0xba, 0xaa}, {0x00, 0x7d, 0xd4, 0xaa}, + {0x00, 0x7e, 0xea, 0xaa}, {0x00, 0xd6, 0x62, 0xaa}, + {0x00, 0x73, 0x00, 0xaa}, {0x00, 0x74, 0x10, 0xaa}, + {0x00, 0x75, 0x20, 0xaa}, {0x00, 0x76, 0x2b, 0xaa}, + {0x00, 0x77, 0x36, 0xaa}, {0x00, 0x78, 0x49, 0xaa}, + {0x00, 0x79, 0x5a, 0xaa}, {0x00, 0x7a, 0x7f, 0xaa}, + {0x00, 0x7b, 0x9b, 0xaa}, {0x00, 0x7c, 0xba, 0xaa}, + {0x00, 0x7d, 0xd4, 0xaa}, {0x00, 0x7e, 0xea, 0xaa}, + {0x00, 0xd6, 0xa2, 0xaa}, {0x00, 0x73, 0x00, 0xaa}, + {0x00, 0x74, 0x10, 0xaa}, {0x00, 0x75, 0x20, 0xaa}, + {0x00, 0x76, 0x2b, 0xaa}, {0x00, 0x77, 0x36, 0xaa}, + {0x00, 0x78, 0x49, 0xaa}, {0x00, 0x79, 0x5a, 0xaa}, + {0x00, 0x7a, 0x7f, 0xaa}, {0x00, 0x7b, 0x9b, 0xaa}, + {0x00, 0x7c, 0xba, 0xaa}, {0x00, 0x7d, 0xd4, 0xaa}, + {0x00, 0x7e, 0xea, 0xaa}, {0x00, 0x4c, 0x07, 0xaa}, + {0x00, 0x4b, 0xe0, 0xaa}, {0x00, 0x4e, 0x77, 0xaa}, + {0x00, 0x59, 0x66, 0xaa}, {0x00, 0x4d, 0x0a, 0xaa}, + {0x00, 0xd1, 0x00, 0xaa}, {0x00, 0x20, 0xc4, 0xaa}, + {0xb8, 0x8e, 0x00, 0xcc}, {0xb8, 0x8f, 0xff, 0xcc}, + {0xb8, 0xfe, 0x00, 0xcc}, {0xb8, 0xff, 0x28, 0xcc}, + {0xb9, 0x00, 0x28, 0xcc}, {0xb9, 0x01, 0x28, 0xcc}, + {0xb9, 0x02, 0x28, 0xcc}, {0xb9, 0x03, 0x00, 0xcc}, + {0xb9, 0x04, 0x00, 0xcc}, {0xb9, 0x05, 0x3c, 0xcc}, + {0xb9, 0x06, 0x3c, 0xcc}, {0xb9, 0x07, 0x3c, 0xcc}, + {0xb9, 0x08, 0x3c, 0xcc}, {0xbc, 0x02, 0x18, 0xcc}, + {0xbc, 0x03, 0x50, 0xcc}, {0xbc, 0x04, 0x18, 0xcc}, + {0xbc, 0x05, 0x00, 0xcc}, {0xbc, 0x06, 0x00, 0xcc}, + {0xbc, 0x08, 0x30, 0xcc}, {0xbc, 0x09, 0x40, 0xcc}, + {0xbc, 0x0a, 0x10, 0xcc}, {0xbc, 0x0b, 0x00, 0xcc}, + {0xbc, 0x0c, 0x00, 0xcc}, {0x00, 0x05, 0x00, 0xaa}, + {0xb3, 0x5c, 0x00, 0xcc}, {0xb3, 0x01, 0x41, 0xcc}, + {} +}; + +static const __u8 hv7131r_gamma[17] = { +/* 0x00, 0x13, 0x38, 0x59, 0x79, 0x92, 0xa7, 0xb9, 0xc8, + * 0xd4, 0xdf, 0xe7, 0xee, 0xf4, 0xf9, 0xfc, 0xff */ + 0x04, 0x1a, 0x36, 0x55, 0x6f, 0x87, 0x9d, 0xb0, 0xc1, + 0xcf, 0xda, 0xe4, 0xec, 0xf3, 0xf8, 0xfd, 0xff +}; +static const __u8 hv7131r_matrix[9] = { + 0x5f, 0xec, 0xf5, 0xf1, 0x5a, 0xf5, 0xf1, 0xec, 0x63 +}; +static const __u8 hv7131r_initVGA_data[][4] = { + {0xb0, 0x4d, 0x00, 0xcc}, {0xb3, 0x01, 0x01, 0xcc}, + {0x00, 0x00, 0x50, 0xdd}, {0xb0, 0x03, 0x01, 0xcc}, + {0xb3, 0x00, 0x24, 0xcc}, + {0xb3, 0x00, 0x25, 0xcc}, {0xb3, 0x08, 0x01, 0xcc}, + {0xb3, 0x09, 0x0c, 0xcc}, {0xb3, 0x05, 0x00, 0xcc}, + {0xb3, 0x06, 0x01, 0xcc}, + {0xb3, 0x01, 0x45, 0xcc}, {0xb3, 0x03, 0x0b, 0xcc}, + {0xb3, 0x04, 0x05, 0xcc}, {0xb3, 0x20, 0x00, 0xcc}, + {0xb3, 0x21, 0x00, 0xcc}, + {0xb3, 0x22, 0x01, 0xcc}, {0xb3, 0x23, 0xe0, 0xcc}, + {0xb3, 0x14, 0x00, 0xcc}, {0xb3, 0x15, 0x00, 0xcc}, + {0xb3, 0x16, 0x02, 0xcc}, + {0xb3, 0x17, 0x7f, 0xcc}, {0xb3, 0x34, 0x01, 0xcc}, + {0xb3, 0x35, 0x91, 0xcc}, {0xb3, 0x00, 0x27, 0xcc}, + {0xbc, 0x00, 0x73, 0xcc}, + {0xb8, 0x00, 0x23, 0xcc}, {0x00, 0x01, 0x0c, 0xaa}, + {0x00, 0x14, 0x01, 0xaa}, {0x00, 0x15, 0xe6, 0xaa}, + {0x00, 0x16, 0x02, 0xaa}, + {0x00, 0x17, 0x86, 0xaa}, {0x00, 0x23, 0x00, 0xaa}, + {0x00, 0x25, 0x09, 0xaa}, {0x00, 0x26, 0x27, 0xaa}, + {0x00, 0x27, 0xc0, 0xaa}, + {0xb8, 0x2c, 0x60, 0xcc}, {0xb8, 0x2d, 0xf8, 0xcc}, + {0xb8, 0x2e, 0xf8, 0xcc}, {0xb8, 0x2f, 0xf8, 0xcc}, + {0xb8, 0x30, 0x50, 0xcc}, + {0xb8, 0x31, 0xf8, 0xcc}, {0xb8, 0x32, 0xf8, 0xcc}, + {0xb8, 0x33, 0xf8, 0xcc}, {0xb8, 0x34, 0x65, 0xcc}, + {0xb8, 0x35, 0x00, 0xcc}, + {0xb8, 0x36, 0x00, 0xcc}, {0xb8, 0x37, 0x00, 0xcc}, + {0xb8, 0x27, 0x20, 0xcc}, {0xb8, 0x01, 0x7d, 0xcc}, + {0xb8, 0x81, 0x09, 0xcc}, + {0xb3, 0x01, 0x41, 0xcc}, {0xb8, 0xfe, 0x00, 0xcc}, + {0xb8, 0xff, 0x28, 0xcc}, {0xb9, 0x00, 0x28, 0xcc}, + {0xb9, 0x01, 0x28, 0xcc}, + {0xb9, 0x02, 0x28, 0xcc}, {0xb9, 0x03, 0x00, 0xcc}, + {0xb9, 0x04, 0x00, 0xcc}, {0xb9, 0x05, 0x3c, 0xcc}, + {0xb9, 0x06, 0x3c, 0xcc}, + {0xb9, 0x07, 0x3c, 0xcc}, {0xb9, 0x08, 0x3c, 0xcc}, + {0xb8, 0x8e, 0x00, 0xcc}, {0xb8, 0x8f, 0xff, 0xcc}, + {0x00, 0x30, 0x18, 0xaa}, + {} +}; + +static const __u8 hv7131r_initQVGA_data[][4] = { + {0xb0, 0x4d, 0x00, 0xcc}, {0xb3, 0x01, 0x01, 0xcc}, + {0x00, 0x00, 0x50, 0xdd}, {0xb0, 0x03, 0x01, 0xcc}, + {0xb3, 0x00, 0x24, 0xcc}, + {0xb3, 0x00, 0x25, 0xcc}, {0xb3, 0x08, 0x01, 0xcc}, + {0xb3, 0x09, 0x0c, 0xcc}, {0xb3, 0x05, 0x00, 0xcc}, + {0xb3, 0x06, 0x01, 0xcc}, + {0xb3, 0x03, 0x0b, 0xcc}, {0xb3, 0x04, 0x05, 0xcc}, + {0xb3, 0x20, 0x00, 0xcc}, {0xb3, 0x21, 0x00, 0xcc}, + {0xb3, 0x22, 0x01, 0xcc}, + {0xb3, 0x23, 0xe0, 0xcc}, {0xb3, 0x14, 0x00, 0xcc}, + {0xb3, 0x15, 0x00, 0xcc}, {0xb3, 0x16, 0x02, 0xcc}, + {0xb3, 0x17, 0x7f, 0xcc}, + {0xb3, 0x34, 0x01, 0xcc}, {0xb3, 0x35, 0x91, 0xcc}, + {0xb3, 0x00, 0x27, 0xcc}, {0xbc, 0x00, 0xd1, 0xcc}, + {0xb8, 0x00, 0x21, 0xcc}, + {0x00, 0x01, 0x0c, 0xaa}, {0x00, 0x14, 0x01, 0xaa}, + {0x00, 0x15, 0xe6, 0xaa}, {0x00, 0x16, 0x02, 0xaa}, + {0x00, 0x17, 0x86, 0xaa}, + {0x00, 0x23, 0x00, 0xaa}, {0x00, 0x25, 0x01, 0xaa}, + {0x00, 0x26, 0xd4, 0xaa}, {0x00, 0x27, 0xc0, 0xaa}, + {0xbc, 0x02, 0x08, 0xcc}, + {0xbc, 0x03, 0x70, 0xcc}, {0xbc, 0x04, 0x08, 0xcc}, + {0xbc, 0x05, 0x00, 0xcc}, {0xbc, 0x06, 0x00, 0xcc}, + {0xbc, 0x08, 0x3c, 0xcc}, + {0xbc, 0x09, 0x40, 0xcc}, {0xbc, 0x0a, 0x04, 0xcc}, + {0xbc, 0x0b, 0x00, 0xcc}, {0xbc, 0x0c, 0x00, 0xcc}, + {0xb8, 0xfe, 0x02, 0xcc}, + {0xb8, 0xff, 0x07, 0xcc}, {0xb9, 0x00, 0x14, 0xcc}, + {0xb9, 0x01, 0x14, 0xcc}, {0xb9, 0x02, 0x14, 0xcc}, + {0xb9, 0x03, 0x00, 0xcc}, + {0xb9, 0x04, 0x02, 0xcc}, {0xb9, 0x05, 0x05, 0xcc}, + {0xb9, 0x06, 0x0f, 0xcc}, {0xb9, 0x07, 0x0f, 0xcc}, + {0xb9, 0x08, 0x0f, 0xcc}, + {0xb8, 0x2c, 0x60, 0xcc}, {0xb8, 0x2d, 0xf8, 0xcc}, + {0xb8, 0x2e, 0xf8, 0xcc}, {0xb8, 0x2f, 0xf8, 0xcc}, + {0xb8, 0x30, 0x50, 0xcc}, + {0xb8, 0x31, 0xf8, 0xcc}, {0xb8, 0x32, 0xf8, 0xcc}, + {0xb8, 0x33, 0xf8, 0xcc}, + {0xb8, 0x34, 0x65, 0xcc}, {0xb8, 0x35, 0x00, 0xcc}, + {0xb8, 0x36, 0x00, 0xcc}, {0xb8, 0x37, 0x00, 0xcc}, + {0xb8, 0x27, 0x20, 0xcc}, + {0xb8, 0x01, 0x7d, 0xcc}, {0xb8, 0x81, 0x09, 0xcc}, + {0xb3, 0x01, 0x41, 0xcc}, {0xb8, 0xfe, 0x00, 0xcc}, + {0xb8, 0xff, 0x28, 0xcc}, + {0xb9, 0x00, 0x28, 0xcc}, {0xb9, 0x01, 0x28, 0xcc}, + {0xb9, 0x02, 0x28, 0xcc}, {0xb9, 0x03, 0x00, 0xcc}, + {0xb9, 0x04, 0x00, 0xcc}, + {0xb9, 0x05, 0x3c, 0xcc}, {0xb9, 0x06, 0x3c, 0xcc}, + {0xb9, 0x07, 0x3c, 0xcc}, {0xb9, 0x08, 0x3c, 0xcc}, + {0xb8, 0x8e, 0x00, 0xcc}, + {0xb8, 0x8f, 0xff, 0xcc}, {0x00, 0x30, 0x18, 0xaa}, + {} +}; + +static const __u8 ov7660_gamma[17] = { + 0x00, 0x13, 0x38, 0x59, 0x79, 0x92, 0xa7, 0xb9, 0xc8, + 0xd4, 0xdf, 0xe7, 0xee, 0xf4, 0xf9, 0xfc, 0xff +}; +static const __u8 ov7660_matrix[9] = { + 0x5a, 0xf0, 0xf6, 0xf3, 0x57, 0xf6, 0xf3, 0xef, 0x62 +}; +static const __u8 ov7660_initVGA_data[][4] = { + {0xb0, 0x4d, 0x00, 0xcc}, {0xb3, 0x01, 0x01, 0xcc}, + {0x00, 0x00, 0x50, 0xdd}, + {0xb0, 0x03, 0x01, 0xcc}, + {0xb3, 0x00, 0x21, 0xcc}, {0xb3, 0x00, 0x26, 0xcc}, + {0xb3, 0x05, 0x01, 0xcc}, + {0xb3, 0x06, 0x03, 0xcc}, + {0xb3, 0x03, 0x1f, 0xcc}, {0xb3, 0x04, 0x05, 0xcc}, + {0xb3, 0x05, 0x00, 0xcc}, + {0xb3, 0x06, 0x01, 0xcc}, + {0xb3, 0x15, 0x00, 0xcc},/* 0xb315 <-0 href startl */ + {0xb3, 0x16, 0x02, 0xcc}, {0xb3, 0x17, 0x7f, 0xcc}, + {0xb3, 0x21, 0x00, 0xcc}, + {0xb3, 0x23, 0xe0, 0xcc}, {0xb3, 0x1d, 0x01, 0xcc}, + {0xb3, 0x1f, 0x02, 0xcc}, + {0xb3, 0x34, 0x01, 0xcc}, + {0xb3, 0x35, 0xa1, 0xcc}, {0xb3, 0x00, 0x26, 0xcc}, + {0xb8, 0x00, 0x33, 0xcc}, /* 13 */ + {0xb8, 0x01, 0x7d, 0xcc}, + {0xbc, 0x00, 0x73, 0xcc}, {0xb8, 0x81, 0x09, 0xcc}, + {0xb8, 0x27, 0x20, 0xcc}, + {0xb8, 0x8f, 0x50, 0xcc}, + {0x00, 0x01, 0x80, 0xaa}, {0x00, 0x02, 0x80, 0xaa}, + {0x00, 0x12, 0x80, 0xaa}, + {0x00, 0x12, 0x05, 0xaa}, + {0x00, 0x1e, 0x01, 0xaa}, + {0x00, 0x3d, 0x40, 0xaa}, /* 0x3d <-40 gamma 01 */ + {0x00, 0x41, 0x00, 0xaa}, /* edge 00 */ + {0x00, 0x0d, 0x48, 0xaa}, {0x00, 0x0e, 0x04, 0xaa}, + {0x00, 0x13, 0xa7, 0xaa}, + {0x00, 0x40, 0xc1, 0xaa}, {0x00, 0x35, 0x00, 0xaa}, + {0x00, 0x36, 0x00, 0xaa}, + {0x00, 0x3c, 0x68, 0xaa}, {0x00, 0x1b, 0x05, 0xaa}, + {0x00, 0x39, 0x43, 0xaa}, + {0x00, 0x8d, 0xcf, 0xaa}, + {0x00, 0x8b, 0xcc, 0xaa}, {0x00, 0x8c, 0xcc, 0xaa}, + {0x00, 0x0f, 0x62, 0xaa}, + {0x00, 0x35, 0x84, 0xaa}, + {0x00, 0x3b, 0x08, 0xaa}, /* 0 * Nightframe 1/4 + 50Hz -> 0xC8 */ + {0x00, 0x3a, 0x00, 0xaa}, /* mx change yuyv format 00, 04, 01; 08, 0c*/ + {0x00, 0x14, 0x2a, 0xaa}, /* agc ampli */ + {0x00, 0x9e, 0x40, 0xaa}, {0xb8, 0x8f, 0x50, 0xcc}, + {0x00, 0x01, 0x80, 0xaa}, + {0x00, 0x02, 0x80, 0xaa}, + {0xb8, 0xfe, 0x00, 0xcc}, {0xb8, 0xff, 0x28, 0xcc}, + {0xb9, 0x00, 0x28, 0xcc}, + {0xb9, 0x01, 0x28, 0xcc}, {0xb9, 0x02, 0x28, 0xcc}, + {0xb9, 0x03, 0x00, 0xcc}, + {0xb9, 0x04, 0x00, 0xcc}, + {0xb9, 0x05, 0x3c, 0xcc}, {0xb9, 0x06, 0x3c, 0xcc}, + {0xb9, 0x07, 0x3c, 0xcc}, + {0xb9, 0x08, 0x3c, 0xcc}, + + {0xb8, 0x8e, 0x00, 0xcc}, {0xb8, 0x8f, 0xff, 0xcc}, + + {0x00, 0x29, 0x3c, 0xaa}, {0xb3, 0x01, 0x45, 0xcc}, + {} +}; +static const __u8 ov7660_initQVGA_data[][4] = { + {0xb0, 0x4d, 0x00, 0xcc}, {0xb3, 0x01, 0x01, 0xcc}, + {0x00, 0x00, 0x50, 0xdd}, {0xb0, 0x03, 0x01, 0xcc}, + {0xb3, 0x00, 0x21, 0xcc}, {0xb3, 0x00, 0x26, 0xcc}, + {0xb3, 0x05, 0x01, 0xcc}, {0xb3, 0x06, 0x03, 0xcc}, + {0xb3, 0x03, 0x1f, 0xcc}, {0xb3, 0x04, 0x05, 0xcc}, + {0xb3, 0x05, 0x00, 0xcc}, {0xb3, 0x06, 0x01, 0xcc}, + {0xb3, 0x15, 0x00, 0xcc},/* 0xb315 <-0 href startl */ + {0xb3, 0x16, 0x02, 0xcc}, {0xb3, 0x17, 0x7f, 0xcc}, + {0xb3, 0x21, 0x00, 0xcc}, + {0xb3, 0x23, 0xe0, 0xcc}, {0xb3, 0x1d, 0x01, 0xcc}, + {0xb3, 0x1f, 0x02, 0xcc}, {0xb3, 0x34, 0x01, 0xcc}, + {0xb3, 0x35, 0xa1, 0xcc}, {0xb3, 0x00, 0x26, 0xcc}, + {0xb8, 0x00, 0x33, 0xcc}, /* 13 */ + {0xb8, 0x01, 0x7d, 0xcc}, +/* sizer */ + {0xbc, 0x00, 0xd3, 0xcc}, + {0xb8, 0x81, 0x09, 0xcc}, {0xb8, 0x81, 0x09, 0xcc}, + {0xb8, 0x27, 0x20, 0xcc}, {0xb8, 0x8f, 0x50, 0xcc}, + {0x00, 0x01, 0x80, 0xaa}, {0x00, 0x02, 0x80, 0xaa}, + {0x00, 0x12, 0x80, 0xaa}, {0x00, 0x12, 0x05, 0xaa}, + {0x00, 0x1e, 0x01, 0xaa}, + {0x00, 0x3d, 0x40, 0xaa}, /* 0x3d <-40 gamma 01 */ + {0x00, 0x41, 0x00, 0xaa}, /* edge 00 */ + {0x00, 0x0d, 0x48, 0xaa}, {0x00, 0x0e, 0x04, 0xaa}, + {0x00, 0x13, 0xa7, 0xaa}, + {0x00, 0x40, 0xc1, 0xaa}, {0x00, 0x35, 0x00, 0xaa}, + {0x00, 0x36, 0x00, 0xaa}, + {0x00, 0x3c, 0x68, 0xaa}, {0x00, 0x1b, 0x05, 0xaa}, + {0x00, 0x39, 0x43, 0xaa}, {0x00, 0x8d, 0xcf, 0xaa}, + {0x00, 0x8b, 0xcc, 0xaa}, {0x00, 0x8c, 0xcc, 0xaa}, + {0x00, 0x0f, 0x62, 0xaa}, {0x00, 0x35, 0x84, 0xaa}, + {0x00, 0x3b, 0x08, 0xaa}, /* 0 * Nightframe 1/4 + 50Hz -> 0xC8 */ + {0x00, 0x3a, 0x00, 0xaa}, /* mx change yuyv format 00, 04, 01; 08, 0c*/ + {0x00, 0x14, 0x2a, 0xaa}, /* agc ampli */ + {0x00, 0x9e, 0x40, 0xaa}, {0xb8, 0x8f, 0x50, 0xcc}, + {0x00, 0x01, 0x80, 0xaa}, + {0x00, 0x02, 0x80, 0xaa}, +/* sizer filters */ + {0xbc, 0x02, 0x08, 0xcc}, + {0xbc, 0x03, 0x70, 0xcc}, + {0xb8, 0x35, 0x00, 0xcc}, + {0xb8, 0x36, 0x00, 0xcc}, + {0xb8, 0x37, 0x00, 0xcc}, + {0xbc, 0x04, 0x08, 0xcc}, + {0xbc, 0x05, 0x00, 0xcc}, + {0xbc, 0x06, 0x00, 0xcc}, + {0xbc, 0x08, 0x3c, 0xcc}, + {0xbc, 0x09, 0x40, 0xcc}, + {0xbc, 0x0a, 0x04, 0xcc}, + {0xbc, 0x0b, 0x00, 0xcc}, + {0xbc, 0x0c, 0x00, 0xcc}, +/* */ + {0xb8, 0xfe, 0x00, 0xcc}, + {0xb8, 0xff, 0x28, 0xcc}, +/* */ + {0xb9, 0x00, 0x28, 0xcc}, {0xb9, 0x01, 0x28, 0xcc}, + {0xb9, 0x02, 0x28, 0xcc}, {0xb9, 0x03, 0x00, 0xcc}, + {0xb9, 0x04, 0x00, 0xcc}, {0xb9, 0x05, 0x3c, 0xcc}, + {0xb9, 0x06, 0x3c, 0xcc}, {0xb9, 0x07, 0x3c, 0xcc}, + {0xb9, 0x08, 0x3c, 0xcc}, +/* */ + {0xb8, 0x8e, 0x00, 0xcc}, + {0xb8, 0x8f, 0xff, 0xcc}, /* ff */ + {0x00, 0x29, 0x3c, 0xaa}, + {0xb3, 0x01, 0x45, 0xcc}, /* 45 */ + {} +}; + +static const __u8 ov7660_50HZ[][4] = { + {0x00, 0x3b, 0x08, 0xaa}, + {0x00, 0x9d, 0x40, 0xaa}, + {0x00, 0x13, 0xa7, 0xaa}, + {} +}; + +static const __u8 ov7660_60HZ[][4] = { + {0x00, 0x3b, 0x00, 0xaa}, + {0x00, 0x9e, 0x40, 0xaa}, + {0x00, 0x13, 0xa7, 0xaa}, + {} +}; + +static const __u8 ov7660_NoFliker[][4] = { + {0x00, 0x13, 0x87, 0xaa}, + {} +}; + +static const __u8 ov7670_initVGA_JPG[][4] = { + {0xb3, 0x01, 0x05, 0xcc}, + {0x00, 0x00, 0x30, 0xdd}, {0xb0, 0x03, 0x19, 0xcc}, + {0x00, 0x00, 0x10, 0xdd}, + {0xb0, 0x04, 0x02, 0xcc}, {0x00, 0x00, 0x10, 0xdd}, + {0xb3, 0x00, 0x66, 0xcc}, {0xb3, 0x00, 0x67, 0xcc}, + {0xb3, 0x35, 0xa1, 0xcc}, {0xb3, 0x34, 0x01, 0xcc}, + {0xb3, 0x05, 0x01, 0xcc}, {0xb3, 0x06, 0x01, 0xcc}, + {0xb3, 0x08, 0x01, 0xcc}, {0xb3, 0x09, 0x0c, 0xcc}, + {0xb3, 0x02, 0x02, 0xcc}, {0xb3, 0x03, 0x1f, 0xcc}, + {0xb3, 0x14, 0x00, 0xcc}, {0xb3, 0x15, 0x00, 0xcc}, + {0xb3, 0x16, 0x02, 0xcc}, {0xb3, 0x17, 0x7f, 0xcc}, + {0xb3, 0x04, 0x05, 0xcc}, {0xb3, 0x20, 0x00, 0xcc}, + {0xb3, 0x21, 0x00, 0xcc}, {0xb3, 0x22, 0x01, 0xcc}, + {0xb3, 0x23, 0xe0, 0xcc}, {0xbc, 0x00, 0x41, 0xcc}, + {0xbc, 0x01, 0x01, 0xcc}, {0x00, 0x12, 0x80, 0xaa}, + {0x00, 0x00, 0x20, 0xdd}, {0x00, 0x12, 0x00, 0xaa}, + {0x00, 0x11, 0x40, 0xaa}, {0x00, 0x6b, 0x0a, 0xaa}, + {0x00, 0x3a, 0x04, 0xaa}, {0x00, 0x40, 0xc0, 0xaa}, + {0x00, 0x8c, 0x00, 0xaa}, {0x00, 0x7a, 0x29, 0xaa}, + {0x00, 0x7b, 0x0e, 0xaa}, {0x00, 0x7c, 0x1a, 0xaa}, + {0x00, 0x7d, 0x31, 0xaa}, {0x00, 0x7e, 0x53, 0xaa}, + {0x00, 0x7f, 0x60, 0xaa}, {0x00, 0x80, 0x6b, 0xaa}, + {0x00, 0x81, 0x73, 0xaa}, {0x00, 0x82, 0x7b, 0xaa}, + {0x00, 0x83, 0x82, 0xaa}, {0x00, 0x84, 0x89, 0xaa}, + {0x00, 0x85, 0x96, 0xaa}, {0x00, 0x86, 0xa1, 0xaa}, + {0x00, 0x87, 0xb7, 0xaa}, {0x00, 0x88, 0xcc, 0xaa}, + {0x00, 0x89, 0xe1, 0xaa}, {0x00, 0x13, 0xe0, 0xaa}, + {0x00, 0x00, 0x00, 0xaa}, {0x00, 0x10, 0x00, 0xaa}, + {0x00, 0x0d, 0x40, 0xaa}, {0x00, 0x14, 0x28, 0xaa}, + {0x00, 0xa5, 0x05, 0xaa}, {0x00, 0xab, 0x07, 0xaa}, + {0x00, 0x24, 0x95, 0xaa}, {0x00, 0x25, 0x33, 0xaa}, + {0x00, 0x26, 0xe3, 0xaa}, {0x00, 0x9f, 0x88, 0xaa}, + {0x00, 0xa0, 0x78, 0xaa}, {0x00, 0x55, 0x90, 0xaa}, + {0x00, 0xa1, 0x03, 0xaa}, {0x00, 0xa6, 0xe0, 0xaa}, + {0x00, 0xa7, 0xd8, 0xaa}, {0x00, 0xa8, 0xf0, 0xaa}, + {0x00, 0xa9, 0x90, 0xaa}, {0x00, 0xaa, 0x14, 0xaa}, + {0x00, 0x13, 0xe5, 0xaa}, {0x00, 0x0e, 0x61, 0xaa}, + {0x00, 0x0f, 0x4b, 0xaa}, {0x00, 0x16, 0x02, 0xaa}, + {0x00, 0x1e, 0x07, 0xaa}, {0x00, 0x21, 0x02, 0xaa}, + {0x00, 0x22, 0x91, 0xaa}, {0x00, 0x29, 0x07, 0xaa}, + {0x00, 0x33, 0x0b, 0xaa}, {0x00, 0x35, 0x0b, 0xaa}, + {0x00, 0x37, 0x1d, 0xaa}, {0x00, 0x38, 0x71, 0xaa}, + {0x00, 0x39, 0x2a, 0xaa}, {0x00, 0x3c, 0x78, 0xaa}, + {0x00, 0x4d, 0x40, 0xaa}, {0x00, 0x4e, 0x20, 0xaa}, + {0x00, 0x74, 0x19, 0xaa}, {0x00, 0x8d, 0x4f, 0xaa}, + {0x00, 0x8e, 0x00, 0xaa}, {0x00, 0x8f, 0x00, 0xaa}, + {0x00, 0x90, 0x00, 0xaa}, {0x00, 0x91, 0x00, 0xaa}, + {0x00, 0x96, 0x00, 0xaa}, {0x00, 0x9a, 0x80, 0xaa}, + {0x00, 0xb0, 0x84, 0xaa}, {0x00, 0xb1, 0x0c, 0xaa}, + {0x00, 0xb2, 0x0e, 0xaa}, {0x00, 0xb3, 0x82, 0xaa}, + {0x00, 0xb8, 0x0a, 0xaa}, {0x00, 0x43, 0x14, 0xaa}, + {0x00, 0x44, 0xf0, 0xaa}, {0x00, 0x45, 0x45, 0xaa}, + {0x00, 0x46, 0x63, 0xaa}, {0x00, 0x47, 0x2d, 0xaa}, + {0x00, 0x48, 0x46, 0xaa}, {0x00, 0x59, 0x88, 0xaa}, + {0x00, 0x5a, 0xa0, 0xaa}, {0x00, 0x5b, 0xc6, 0xaa}, + {0x00, 0x5c, 0x7d, 0xaa}, {0x00, 0x5d, 0x5f, 0xaa}, + {0x00, 0x5e, 0x19, 0xaa}, {0x00, 0x6c, 0x0a, 0xaa}, + {0x00, 0x6d, 0x55, 0xaa}, {0x00, 0x6e, 0x11, 0xaa}, + {0x00, 0x6f, 0x9e, 0xaa}, {0x00, 0x69, 0x00, 0xaa}, + {0x00, 0x6a, 0x40, 0xaa}, {0x00, 0x01, 0x40, 0xaa}, + {0x00, 0x02, 0x40, 0xaa}, {0x00, 0x13, 0xe7, 0xaa}, + {0x00, 0x5f, 0xf0, 0xaa}, {0x00, 0x60, 0xf0, 0xaa}, + {0x00, 0x61, 0xf0, 0xaa}, {0x00, 0x27, 0xa0, 0xaa}, + {0x00, 0x28, 0x80, 0xaa}, {0x00, 0x2c, 0x90, 0xaa}, + {0x00, 0x4f, 0x66, 0xaa}, {0x00, 0x50, 0x66, 0xaa}, + {0x00, 0x51, 0x00, 0xaa}, {0x00, 0x52, 0x22, 0xaa}, + {0x00, 0x53, 0x5e, 0xaa}, {0x00, 0x54, 0x80, 0xaa}, + {0x00, 0x58, 0x9e, 0xaa}, {0x00, 0x41, 0x08, 0xaa}, + {0x00, 0x3f, 0x00, 0xaa}, {0x00, 0x75, 0x85, 0xaa}, + {0x00, 0x76, 0xe1, 0xaa}, {0x00, 0x4c, 0x00, 0xaa}, + {0x00, 0x77, 0x0a, 0xaa}, {0x00, 0x3d, 0x88, 0xaa}, + {0x00, 0x4b, 0x09, 0xaa}, {0x00, 0xc9, 0x60, 0xaa}, + {0x00, 0x41, 0x38, 0xaa}, {0x00, 0x62, 0x30, 0xaa}, + {0x00, 0x63, 0x30, 0xaa}, {0x00, 0x64, 0x08, 0xaa}, + {0x00, 0x94, 0x07, 0xaa}, {0x00, 0x95, 0x0b, 0xaa}, + {0x00, 0x65, 0x00, 0xaa}, {0x00, 0x66, 0x05, 0xaa}, + {0x00, 0x56, 0x50, 0xaa}, {0x00, 0x34, 0x11, 0xaa}, + {0x00, 0xa4, 0x88, 0xaa}, {0x00, 0x96, 0x00, 0xaa}, + {0x00, 0x97, 0x30, 0xaa}, {0x00, 0x98, 0x20, 0xaa}, + {0x00, 0x99, 0x30, 0xaa}, {0x00, 0x9a, 0x84, 0xaa}, + {0x00, 0x9b, 0x29, 0xaa}, {0x00, 0x9c, 0x03, 0xaa}, + {0x00, 0x78, 0x04, 0xaa}, {0x00, 0x79, 0x01, 0xaa}, + {0x00, 0xc8, 0xf0, 0xaa}, {0x00, 0x79, 0x0f, 0xaa}, + {0x00, 0xc8, 0x00, 0xaa}, {0x00, 0x79, 0x10, 0xaa}, + {0x00, 0xc8, 0x7e, 0xaa}, {0x00, 0x79, 0x0a, 0xaa}, + {0x00, 0xc8, 0x80, 0xaa}, {0x00, 0x79, 0x0b, 0xaa}, + {0x00, 0xc8, 0x01, 0xaa}, {0x00, 0x79, 0x0c, 0xaa}, + {0x00, 0xc8, 0x0f, 0xaa}, {0x00, 0x79, 0x0d, 0xaa}, + {0x00, 0xc8, 0x20, 0xaa}, {0x00, 0x79, 0x09, 0xaa}, + {0x00, 0xc8, 0x80, 0xaa}, {0x00, 0x79, 0x02, 0xaa}, + {0x00, 0xc8, 0xc0, 0xaa}, {0x00, 0x79, 0x03, 0xaa}, + {0x00, 0xc8, 0x40, 0xaa}, {0x00, 0x79, 0x05, 0xaa}, + {0x00, 0xc8, 0x30, 0xaa}, {0x00, 0x79, 0x26, 0xaa}, + {0x00, 0x11, 0x40, 0xaa}, {0x00, 0x3a, 0x04, 0xaa}, + {0x00, 0x12, 0x00, 0xaa}, {0x00, 0x40, 0xc0, 0xaa}, + {0x00, 0x8c, 0x00, 0xaa}, {0x00, 0x17, 0x14, 0xaa}, + {0x00, 0x18, 0x02, 0xaa}, {0x00, 0x32, 0x92, 0xaa}, + {0x00, 0x19, 0x02, 0xaa}, {0x00, 0x1a, 0x7a, 0xaa}, + {0x00, 0x03, 0x0a, 0xaa}, {0x00, 0x0c, 0x00, 0xaa}, + {0x00, 0x3e, 0x00, 0xaa}, {0x00, 0x70, 0x3a, 0xaa}, + {0x00, 0x71, 0x35, 0xaa}, {0x00, 0x72, 0x11, 0xaa}, + {0x00, 0x73, 0xf0, 0xaa}, {0x00, 0xa2, 0x02, 0xaa}, + {0x00, 0xb1, 0x00, 0xaa}, {0x00, 0xb1, 0x0c, 0xaa}, + {0x00, 0x1e, 0x37, 0xaa}, {0x00, 0xaa, 0x14, 0xaa}, + {0x00, 0x24, 0x80, 0xaa}, {0x00, 0x25, 0x74, 0xaa}, + {0x00, 0x26, 0xd3, 0xaa}, {0x00, 0x0d, 0x00, 0xaa}, + {0x00, 0x14, 0x18, 0xaa}, {0x00, 0x9d, 0x99, 0xaa}, + {0x00, 0x9e, 0x7f, 0xaa}, {0x00, 0x64, 0x08, 0xaa}, + {0x00, 0x94, 0x07, 0xaa}, {0x00, 0x95, 0x06, 0xaa}, + {0x00, 0x66, 0x05, 0xaa}, {0x00, 0x41, 0x08, 0xaa}, + {0x00, 0x3f, 0x00, 0xaa}, {0x00, 0x75, 0x07, 0xaa}, + {0x00, 0x76, 0xe1, 0xaa}, {0x00, 0x4c, 0x00, 0xaa}, + {0x00, 0x77, 0x00, 0xaa}, {0x00, 0x3d, 0xc2, 0xaa}, + {0x00, 0x4b, 0x09, 0xaa}, {0x00, 0xc9, 0x60, 0xaa}, + {0x00, 0x41, 0x38, 0xaa}, {0xb6, 0x00, 0x00, 0xcc}, + {0xb6, 0x03, 0x02, 0xcc}, {0xb6, 0x02, 0x80, 0xcc}, + {0xb6, 0x05, 0x01, 0xcc}, {0xb6, 0x04, 0xe0, 0xcc}, + {0xb6, 0x12, 0xf8, 0xcc}, {0xb6, 0x13, 0x13, 0xcc}, + {0xb6, 0x18, 0x02, 0xcc}, {0xb6, 0x17, 0x58, 0xcc}, + {0xb6, 0x16, 0x00, 0xcc}, {0xb6, 0x22, 0x12, 0xcc}, + {0xb6, 0x23, 0x0b, 0xcc}, {0xbf, 0xc0, 0x39, 0xcc}, + {0xbf, 0xc1, 0x04, 0xcc}, {0xbf, 0xcc, 0x00, 0xcc}, + {0xb3, 0x5c, 0x01, 0xcc}, {0xb3, 0x01, 0x45, 0xcc}, + {0x00, 0x77, 0x05, 0xaa}, + {}, +}; + +static const __u8 ov7670_initQVGA_JPG[][4] = { + {0xb3, 0x01, 0x05, 0xcc}, {0x00, 0x00, 0x30, 0xdd}, + {0xb0, 0x03, 0x19, 0xcc}, {0x00, 0x00, 0x10, 0xdd}, + {0xb0, 0x04, 0x02, 0xcc}, {0x00, 0x00, 0x10, 0xdd}, + {0xb3, 0x00, 0x66, 0xcc}, {0xb3, 0x00, 0x67, 0xcc}, + {0xb3, 0x35, 0xa1, 0xcc}, {0xb3, 0x34, 0x01, 0xcc}, + {0xb3, 0x05, 0x01, 0xcc}, {0xb3, 0x06, 0x01, 0xcc}, + {0xb3, 0x08, 0x01, 0xcc}, {0xb3, 0x09, 0x0c, 0xcc}, + {0xb3, 0x02, 0x02, 0xcc}, {0xb3, 0x03, 0x1f, 0xcc}, + {0xb3, 0x14, 0x00, 0xcc}, {0xb3, 0x15, 0x00, 0xcc}, + {0xb3, 0x16, 0x02, 0xcc}, {0xb3, 0x17, 0x7f, 0xcc}, + {0xb3, 0x04, 0x05, 0xcc}, {0xb3, 0x20, 0x00, 0xcc}, + {0xb3, 0x21, 0x00, 0xcc}, {0xb3, 0x22, 0x01, 0xcc}, + {0xb3, 0x23, 0xe0, 0xcc}, {0xbc, 0x00, 0xd1, 0xcc}, + {0xbc, 0x01, 0x01, 0xcc}, {0x00, 0x12, 0x80, 0xaa}, + {0x00, 0x00, 0x20, 0xdd}, {0x00, 0x12, 0x00, 0xaa}, + {0x00, 0x11, 0x40, 0xaa}, {0x00, 0x6b, 0x0a, 0xaa}, + {0x00, 0x3a, 0x04, 0xaa}, {0x00, 0x40, 0xc0, 0xaa}, + {0x00, 0x8c, 0x00, 0xaa}, {0x00, 0x7a, 0x29, 0xaa}, + {0x00, 0x7b, 0x0e, 0xaa}, {0x00, 0x7c, 0x1a, 0xaa}, + {0x00, 0x7d, 0x31, 0xaa}, {0x00, 0x7e, 0x53, 0xaa}, + {0x00, 0x7f, 0x60, 0xaa}, {0x00, 0x80, 0x6b, 0xaa}, + {0x00, 0x81, 0x73, 0xaa}, {0x00, 0x82, 0x7b, 0xaa}, + {0x00, 0x83, 0x82, 0xaa}, {0x00, 0x84, 0x89, 0xaa}, + {0x00, 0x85, 0x96, 0xaa}, {0x00, 0x86, 0xa1, 0xaa}, + {0x00, 0x87, 0xb7, 0xaa}, {0x00, 0x88, 0xcc, 0xaa}, + {0x00, 0x89, 0xe1, 0xaa}, {0x00, 0x13, 0xe0, 0xaa}, + {0x00, 0x00, 0x00, 0xaa}, {0x00, 0x10, 0x00, 0xaa}, + {0x00, 0x0d, 0x40, 0xaa}, {0x00, 0x14, 0x28, 0xaa}, + {0x00, 0xa5, 0x05, 0xaa}, {0x00, 0xab, 0x07, 0xaa}, + {0x00, 0x24, 0x95, 0xaa}, {0x00, 0x25, 0x33, 0xaa}, + {0x00, 0x26, 0xe3, 0xaa}, {0x00, 0x9f, 0x88, 0xaa}, + {0x00, 0xa0, 0x78, 0xaa}, {0x00, 0x55, 0x90, 0xaa}, + {0x00, 0xa1, 0x03, 0xaa}, {0x00, 0xa6, 0xe0, 0xaa}, + {0x00, 0xa7, 0xd8, 0xaa}, {0x00, 0xa8, 0xf0, 0xaa}, + {0x00, 0xa9, 0x90, 0xaa}, {0x00, 0xaa, 0x14, 0xaa}, + {0x00, 0x13, 0xe5, 0xaa}, {0x00, 0x0e, 0x61, 0xaa}, + {0x00, 0x0f, 0x4b, 0xaa}, {0x00, 0x16, 0x02, 0xaa}, + {0x00, 0x1e, 0x07, 0xaa}, {0x00, 0x21, 0x02, 0xaa}, + {0x00, 0x22, 0x91, 0xaa}, {0x00, 0x29, 0x07, 0xaa}, + {0x00, 0x33, 0x0b, 0xaa}, {0x00, 0x35, 0x0b, 0xaa}, + {0x00, 0x37, 0x1d, 0xaa}, {0x00, 0x38, 0x71, 0xaa}, + {0x00, 0x39, 0x2a, 0xaa}, {0x00, 0x3c, 0x78, 0xaa}, + {0x00, 0x4d, 0x40, 0xaa}, {0x00, 0x4e, 0x20, 0xaa}, + {0x00, 0x74, 0x19, 0xaa}, {0x00, 0x8d, 0x4f, 0xaa}, + {0x00, 0x8e, 0x00, 0xaa}, {0x00, 0x8f, 0x00, 0xaa}, + {0x00, 0x90, 0x00, 0xaa}, {0x00, 0x91, 0x00, 0xaa}, + {0x00, 0x96, 0x00, 0xaa}, {0x00, 0x9a, 0x80, 0xaa}, + {0x00, 0xb0, 0x84, 0xaa}, {0x00, 0xb1, 0x0c, 0xaa}, + {0x00, 0xb2, 0x0e, 0xaa}, {0x00, 0xb3, 0x82, 0xaa}, + {0x00, 0xb8, 0x0a, 0xaa}, {0x00, 0x43, 0x14, 0xaa}, + {0x00, 0x44, 0xf0, 0xaa}, {0x00, 0x45, 0x45, 0xaa}, + {0x00, 0x46, 0x63, 0xaa}, {0x00, 0x47, 0x2d, 0xaa}, + {0x00, 0x48, 0x46, 0xaa}, {0x00, 0x59, 0x88, 0xaa}, + {0x00, 0x5a, 0xa0, 0xaa}, {0x00, 0x5b, 0xc6, 0xaa}, + {0x00, 0x5c, 0x7d, 0xaa}, {0x00, 0x5d, 0x5f, 0xaa}, + {0x00, 0x5e, 0x19, 0xaa}, {0x00, 0x6c, 0x0a, 0xaa}, + {0x00, 0x6d, 0x55, 0xaa}, {0x00, 0x6e, 0x11, 0xaa}, + {0x00, 0x6f, 0x9e, 0xaa}, {0x00, 0x69, 0x00, 0xaa}, + {0x00, 0x6a, 0x40, 0xaa}, {0x00, 0x01, 0x40, 0xaa}, + {0x00, 0x02, 0x40, 0xaa}, {0x00, 0x13, 0xe7, 0xaa}, + {0x00, 0x5f, 0xf0, 0xaa}, {0x00, 0x60, 0xf0, 0xaa}, + {0x00, 0x61, 0xf0, 0xaa}, {0x00, 0x27, 0xa0, 0xaa}, + {0x00, 0x28, 0x80, 0xaa}, {0x00, 0x2c, 0x90, 0xaa}, + {0x00, 0x4f, 0x66, 0xaa}, {0x00, 0x50, 0x66, 0xaa}, + {0x00, 0x51, 0x00, 0xaa}, {0x00, 0x52, 0x22, 0xaa}, + {0x00, 0x53, 0x5e, 0xaa}, {0x00, 0x54, 0x80, 0xaa}, + {0x00, 0x58, 0x9e, 0xaa}, {0x00, 0x41, 0x08, 0xaa}, + {0x00, 0x3f, 0x00, 0xaa}, {0x00, 0x75, 0x85, 0xaa}, + {0x00, 0x76, 0xe1, 0xaa}, {0x00, 0x4c, 0x00, 0xaa}, + {0x00, 0x77, 0x0a, 0xaa}, {0x00, 0x3d, 0x88, 0xaa}, + {0x00, 0x4b, 0x09, 0xaa}, {0x00, 0xc9, 0x60, 0xaa}, + {0x00, 0x41, 0x38, 0xaa}, {0x00, 0x62, 0x30, 0xaa}, + {0x00, 0x63, 0x30, 0xaa}, {0x00, 0x64, 0x08, 0xaa}, + {0x00, 0x94, 0x07, 0xaa}, {0x00, 0x95, 0x0b, 0xaa}, + {0x00, 0x65, 0x00, 0xaa}, {0x00, 0x66, 0x05, 0xaa}, + {0x00, 0x56, 0x50, 0xaa}, {0x00, 0x34, 0x11, 0xaa}, + {0x00, 0xa4, 0x88, 0xaa}, {0x00, 0x96, 0x00, 0xaa}, + {0x00, 0x97, 0x30, 0xaa}, {0x00, 0x98, 0x20, 0xaa}, + {0x00, 0x99, 0x30, 0xaa}, {0x00, 0x9a, 0x84, 0xaa}, + {0x00, 0x9b, 0x29, 0xaa}, {0x00, 0x9c, 0x03, 0xaa}, + {0x00, 0x78, 0x04, 0xaa}, {0x00, 0x79, 0x01, 0xaa}, + {0x00, 0xc8, 0xf0, 0xaa}, {0x00, 0x79, 0x0f, 0xaa}, + {0x00, 0xc8, 0x00, 0xaa}, {0x00, 0x79, 0x10, 0xaa}, + {0x00, 0xc8, 0x7e, 0xaa}, {0x00, 0x79, 0x0a, 0xaa}, + {0x00, 0xc8, 0x80, 0xaa}, {0x00, 0x79, 0x0b, 0xaa}, + {0x00, 0xc8, 0x01, 0xaa}, {0x00, 0x79, 0x0c, 0xaa}, + {0x00, 0xc8, 0x0f, 0xaa}, {0x00, 0x79, 0x0d, 0xaa}, + {0x00, 0xc8, 0x20, 0xaa}, {0x00, 0x79, 0x09, 0xaa}, + {0x00, 0xc8, 0x80, 0xaa}, {0x00, 0x79, 0x02, 0xaa}, + {0x00, 0xc8, 0xc0, 0xaa}, {0x00, 0x79, 0x03, 0xaa}, + {0x00, 0xc8, 0x40, 0xaa}, {0x00, 0x79, 0x05, 0xaa}, + {0x00, 0xc8, 0x30, 0xaa}, {0x00, 0x79, 0x26, 0xaa}, + {0x00, 0x11, 0x40, 0xaa}, {0x00, 0x3a, 0x04, 0xaa}, + {0x00, 0x12, 0x00, 0xaa}, {0x00, 0x40, 0xc0, 0xaa}, + {0x00, 0x8c, 0x00, 0xaa}, {0x00, 0x17, 0x14, 0xaa}, + {0x00, 0x18, 0x02, 0xaa}, {0x00, 0x32, 0x92, 0xaa}, + {0x00, 0x19, 0x02, 0xaa}, {0x00, 0x1a, 0x7a, 0xaa}, + {0x00, 0x03, 0x0a, 0xaa}, {0x00, 0x0c, 0x00, 0xaa}, + {0x00, 0x3e, 0x00, 0xaa}, {0x00, 0x70, 0x3a, 0xaa}, + {0x00, 0x71, 0x35, 0xaa}, {0x00, 0x72, 0x11, 0xaa}, + {0x00, 0x73, 0xf0, 0xaa}, {0x00, 0xa2, 0x02, 0xaa}, + {0x00, 0xb1, 0x00, 0xaa}, {0x00, 0xb1, 0x0c, 0xaa}, + {0x00, 0x1e, 0x37, 0xaa}, {0x00, 0xaa, 0x14, 0xaa}, + {0x00, 0x24, 0x80, 0xaa}, {0x00, 0x25, 0x74, 0xaa}, + {0x00, 0x26, 0xd3, 0xaa}, {0x00, 0x0d, 0x00, 0xaa}, + {0x00, 0x14, 0x18, 0xaa}, {0x00, 0x9d, 0x99, 0xaa}, + {0x00, 0x9e, 0x7f, 0xaa}, {0x00, 0x64, 0x08, 0xaa}, + {0x00, 0x94, 0x07, 0xaa}, {0x00, 0x95, 0x06, 0xaa}, + {0x00, 0x66, 0x05, 0xaa}, {0x00, 0x41, 0x08, 0xaa}, + {0x00, 0x3f, 0x00, 0xaa}, {0x00, 0x75, 0x07, 0xaa}, + {0x00, 0x76, 0xe1, 0xaa}, {0x00, 0x4c, 0x00, 0xaa}, + {0x00, 0x77, 0x00, 0xaa}, {0x00, 0x3d, 0xc2, 0xaa}, + {0x00, 0x4b, 0x09, 0xaa}, {0x00, 0xc9, 0x60, 0xaa}, + {0x00, 0x41, 0x38, 0xaa}, {0xb6, 0x00, 0x00, 0xcc}, + {0xb6, 0x03, 0x01, 0xcc}, {0xb6, 0x02, 0x40, 0xcc}, + {0xb6, 0x05, 0x00, 0xcc}, {0xb6, 0x04, 0xf0, 0xcc}, + {0xb6, 0x12, 0xf8, 0xcc}, {0xb6, 0x13, 0x21, 0xcc}, + {0xb6, 0x18, 0x00, 0xcc}, {0xb6, 0x17, 0x96, 0xcc}, + {0xb6, 0x16, 0x00, 0xcc}, {0xb6, 0x22, 0x12, 0xcc}, + {0xb6, 0x23, 0x0b, 0xcc}, {0xbf, 0xc0, 0x39, 0xcc}, + {0xbf, 0xc1, 0x04, 0xcc}, {0xbf, 0xcc, 0x00, 0xcc}, + {0xbc, 0x02, 0x18, 0xcc}, {0xbc, 0x03, 0x50, 0xcc}, + {0xbc, 0x04, 0x18, 0xcc}, {0xbc, 0x05, 0x00, 0xcc}, + {0xbc, 0x06, 0x00, 0xcc}, {0xbc, 0x08, 0x30, 0xcc}, + {0xbc, 0x09, 0x40, 0xcc}, {0xbc, 0x0a, 0x10, 0xcc}, + {0xbc, 0x0b, 0x00, 0xcc}, {0xbc, 0x0c, 0x00, 0xcc}, + {0xb3, 0x5c, 0x01, 0xcc}, {0xb3, 0x01, 0x45, 0xcc}, + {0x00, 0x77, 0x05, 0xaa }, + {}, +}; + +struct sensor_info { + int sensorId; + __u8 I2cAdd; + __u8 IdAdd; + __u16 VpId; + __u8 m1; + __u8 m2; + __u8 op; + }; + +static const struct sensor_info sensor_info_data[] = { +/* sensorId, I2cAdd, IdAdd, VpId, m1, m2, op */ + {SENSOR_HV7131R, 0x80 | 0x11, 0x00, 0x0209, 0x24, 0x25, 0x01}, + {SENSOR_OV7660, 0x80 | 0x21, 0x0a, 0x7660, 0x26, 0x26, 0x05}, + {SENSOR_PO3130NC, 0x80 | 0x76, 0x00, 0x3130, 0x24, 0x25, 0x01}, + {SENSOR_MI1320, 0x80 | 0xc8, 0x00, 0x148c, 0x64, 0x65, 0x01}, + {SENSOR_OV7670, 0x80 | 0x21, 0x0a, 0x7673, 0x66, 0x67, 0x05}, + {SENSOR_MI1310_SOC, 0x80 | 0x5d, 0x00, 0x143a, 0x24, 0x25, 0x01}, +}; + +/* read 'len' bytes in gspca_dev->usb_buf */ +static void reg_r(struct gspca_dev *gspca_dev, + __u16 req, + __u16 index, + __u16 len) +{ + usb_control_msg(gspca_dev->dev, + usb_rcvctrlpipe(gspca_dev->dev, 0), + req, + USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + 1, /* value */ + index, gspca_dev->usb_buf, len, + 500); +} + +static void reg_w(struct usb_device *dev, + __u16 req, + __u16 value, + __u16 index) +{ + usb_control_msg(dev, + usb_sndctrlpipe(dev, 0), + req, + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + value, index, NULL, 0, + 500); +} + +static void read_sensor_register(struct gspca_dev *gspca_dev, + __u16 address, __u16 *value) +{ + struct usb_device *dev = gspca_dev->dev; + __u8 ldata, mdata, hdata; + int retry = 50; + + *value = 0; + + reg_r(gspca_dev, 0xa1, 0xb33f, 1); + /*PDEBUG(D_PROBE, " I2c Bus Busy Wait 0x%02X ", tmpvalue); */ + if (!(gspca_dev->usb_buf[0] & 0x02)) { + PDEBUG(D_ERR, "I2c Bus Busy Wait %d", + gspca_dev->usb_buf[0] & 0x02); + return; + } + reg_w(dev, 0xa0, address, 0xb33a); + reg_w(dev, 0xa0, 0x02, 0xb339); + + reg_r(gspca_dev, 0xa1, 0xb33b, 1); + while (retry-- && gspca_dev->usb_buf[0]) { + reg_r(gspca_dev, 0xa1, 0xb33b, 1); +/* PDEBUG(D_PROBE, "Read again 0xb33b %d", tmpvalue); */ + msleep(1); + } + reg_r(gspca_dev, 0xa1, 0xb33e, 1); + hdata = gspca_dev->usb_buf[0]; + reg_r(gspca_dev, 0xa1, 0xb33d, 1); + mdata = gspca_dev->usb_buf[0]; + reg_r(gspca_dev, 0xa1, 0xb33c, 1); + ldata = gspca_dev->usb_buf[0]; + PDEBUG(D_PROBE, "Read Sensor h (0x%02X) m (0x%02X) l (0x%02X)", + hdata, mdata, ldata); + reg_r(gspca_dev, 0xa1, 0xb334, 1); + if (gspca_dev->usb_buf[0] == 0x02) + *value = (ldata << 8) + mdata; + else + *value = ldata; +} + +static int vc032x_probe_sensor(struct gspca_dev *gspca_dev) +{ + struct usb_device *dev = gspca_dev->dev; + int i; + __u16 value; + const struct sensor_info *ptsensor_info; + + reg_r(gspca_dev, 0xa1, 0xbfcf, 1); + PDEBUG(D_PROBE, "check sensor header %d", gspca_dev->usb_buf[0]); + for (i = 0; i < ARRAY_SIZE(sensor_info_data); i++) { + ptsensor_info = &sensor_info_data[i]; + reg_w(dev, 0xa0, 0x02, 0xb334); + reg_w(dev, 0xa0, ptsensor_info->m1, 0xb300); + reg_w(dev, 0xa0, ptsensor_info->m2, 0xb300); + reg_w(dev, 0xa0, 0x01, 0xb308); + reg_w(dev, 0xa0, 0x0c, 0xb309); + reg_w(dev, 0xa0, ptsensor_info->I2cAdd, 0xb335); +/* PDEBUG(D_PROBE, + "check sensor VC032X -> %d Add -> ox%02X!", + i, ptsensor_info->I2cAdd); */ + reg_w(dev, 0xa0, ptsensor_info->op, 0xb301); + read_sensor_register(gspca_dev, ptsensor_info->IdAdd, &value); + if (value == ptsensor_info->VpId) { +/* PDEBUG(D_PROBE, "find sensor VC032X -> ox%04X!", + ptsensor_info->VpId); */ + return ptsensor_info->sensorId; + } + } + return -1; +} + +static __u8 i2c_write(struct gspca_dev *gspca_dev, + __u8 reg, const __u8 *val, __u8 size) +{ + struct usb_device *dev = gspca_dev->dev; + + if (size > 3 || size < 1) + return -EINVAL; + reg_r(gspca_dev, 0xa1, 0xb33f, 1); + reg_w(dev, 0xa0, size, 0xb334); + reg_w(dev, 0xa0, reg, 0xb33a); + switch (size) { + case 1: + reg_w(dev, 0xa0, val[0], 0xb336); + break; + case 2: + reg_w(dev, 0xa0, val[0], 0xb336); + reg_w(dev, 0xa0, val[1], 0xb337); + break; + case 3: + reg_w(dev, 0xa0, val[0], 0xb336); + reg_w(dev, 0xa0, val[1], 0xb337); + reg_w(dev, 0xa0, val[2], 0xb338); + break; + default: + reg_w(dev, 0xa0, 0x01, 0xb334); + return -EINVAL; + } + reg_w(dev, 0xa0, 0x01, 0xb339); + reg_r(gspca_dev, 0xa1, 0xb33b, 1); + return gspca_dev->usb_buf[0] == 0; +} + +static void put_tab_to_reg(struct gspca_dev *gspca_dev, + const __u8 *tab, __u8 tabsize, __u16 addr) +{ + int j; + __u16 ad = addr; + + for (j = 0; j < tabsize; j++) + reg_w(gspca_dev->dev, 0xa0, tab[j], ad++); +} + +static void usb_exchange(struct gspca_dev *gspca_dev, + const __u8 data[][4]) +{ + struct usb_device *dev = gspca_dev->dev; + int i = 0; + + for (;;) { + switch (data[i][3]) { + default: + return; + case 0xcc: /* normal write */ + reg_w(dev, 0xa0, data[i][2], + ((data[i][0])<<8) | data[i][1]); + break; + case 0xaa: /* i2c op */ + i2c_write(gspca_dev, data[i][1], &data[i][2], 1); + break; + case 0xbb: /* i2c op */ + i2c_write(gspca_dev, data[i][0], &data[i][1], 2); + break; + case 0xdd: + msleep(data[i][2] + 10); + break; + } + i++; + } + /*not reached*/ +} + +/* + "GammaT"=hex:04,17,31,4f,6a,83,99,ad,bf,ce,da,e5,ee,f5,fb,ff,ff + "MatrixT"=hex:60,f9,e5,e7,50,05,f3,e6,66 + */ + +static void vc0321_reset(struct gspca_dev *gspca_dev) +{ + reg_w(gspca_dev->dev, 0xa0, 0x00, 0xb04d); + reg_w(gspca_dev->dev, 0xa0, 0x01, 0xb301); + msleep(100); + reg_w(gspca_dev->dev, 0xa0, 0x01, 0xb003); + msleep(100); +} + +/* this function is called at probe time */ +static int sd_config(struct gspca_dev *gspca_dev, + const struct usb_device_id *id) +{ + struct sd *sd = (struct sd *) gspca_dev; + struct usb_device *dev = gspca_dev->dev; + struct cam *cam; + int sensor; + __u16 product; + + product = id->idProduct; + sd->bridge = BRIDGE_VC0321; + switch (id->idVendor) { + case 0x0ac8: /* Vimicro z-star */ + switch (product) { + case 0x0323: + sd->bridge = BRIDGE_VC0323; + break; + } + break; + case 0x17ef: /* Lenovo */ +/* switch (product) { */ +/* case 0x4802: * Lenovo MI1310_SOC */ + sd->bridge = BRIDGE_VC0323; +/* break; */ +/* } */ + break; + } + + cam = &gspca_dev->cam; + cam->dev_name = (char *) id->driver_info; + cam->epaddr = 0x02; + if (sd->bridge == BRIDGE_VC0321) { + cam->cam_mode = vc0321_mode; + cam->nmodes = ARRAY_SIZE(vc0321_mode); + } else { + cam->cam_mode = vc0323_mode; + cam->nmodes = ARRAY_SIZE(vc0323_mode); + } + + vc0321_reset(gspca_dev); + sensor = vc032x_probe_sensor(gspca_dev); + switch (sensor) { + case -1: + PDEBUG(D_PROBE, "Unknown sensor..."); + return -EINVAL; + case SENSOR_HV7131R: + PDEBUG(D_PROBE, "Find Sensor HV7131R"); + sd->sensor = SENSOR_HV7131R; + break; + case SENSOR_MI1310_SOC: + PDEBUG(D_PROBE, "Find Sensor MI1310_SOC"); + sd->sensor = SENSOR_MI1310_SOC; + break; + case SENSOR_MI1320: + PDEBUG(D_PROBE, "Find Sensor MI1320"); + sd->sensor = SENSOR_MI1320; + break; + case SENSOR_OV7660: + PDEBUG(D_PROBE, "Find Sensor OV7660"); + sd->sensor = SENSOR_OV7660; + break; + case SENSOR_OV7670: + PDEBUG(D_PROBE, "Find Sensor OV7670"); + sd->sensor = SENSOR_OV7670; + break; + case SENSOR_PO3130NC: + PDEBUG(D_PROBE, "Find Sensor PO3130NC"); + sd->sensor = SENSOR_PO3130NC; + break; + } + + sd->qindex = 7; + sd->autogain = AUTOGAIN_DEF; + sd->lightfreq = FREQ_DEF; + + if (sd->bridge == BRIDGE_VC0321) { + reg_r(gspca_dev, 0x8a, 0, 3); + reg_w(dev, 0x87, 0x00, 0x0f0f); + + reg_r(gspca_dev, 0x8b, 0, 3); + reg_w(dev, 0x88, 0x00, 0x0202); + } + return 0; +} + +/* this function is called at open time */ +static int sd_open(struct gspca_dev *gspca_dev) +{ + return 0; +} + +static void setquality(struct gspca_dev *gspca_dev) +{ +} + +static void setautogain(struct gspca_dev *gspca_dev) +{ +} + +static void setlightfreq(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + static const __u8 (*ov7660_freq_tb[3])[4] = + {ov7660_NoFliker, ov7660_50HZ, ov7660_60HZ}; + + if (sd->sensor != SENSOR_OV7660) + return; + usb_exchange(gspca_dev, ov7660_freq_tb[sd->lightfreq]); +} + +static void sd_start(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + const __u8 *GammaT = NULL; + const __u8 *MatrixT = NULL; + int mode; + + /* Assume start use the good resolution from gspca_dev->mode */ + if (sd->bridge == BRIDGE_VC0321) { + reg_w(gspca_dev->dev, 0xa0, 0xff, 0xbfec); + reg_w(gspca_dev->dev, 0xa0, 0xff, 0xbfed); + reg_w(gspca_dev->dev, 0xa0, 0xff, 0xbfee); + reg_w(gspca_dev->dev, 0xa0, 0xff, 0xbfef); + } + + mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv; + switch (sd->sensor) { + case SENSOR_HV7131R: + GammaT = hv7131r_gamma; + MatrixT = hv7131r_matrix; + if (mode) { + /* 320x240 */ + usb_exchange(gspca_dev, hv7131r_initQVGA_data); + } else { + /* 640x480 */ + usb_exchange(gspca_dev, hv7131r_initVGA_data); + } + break; + case SENSOR_OV7660: + GammaT = ov7660_gamma; + MatrixT = ov7660_matrix; + if (mode) { + /* 320x240 */ + usb_exchange(gspca_dev, ov7660_initQVGA_data); + } else { + /* 640x480 */ + usb_exchange(gspca_dev, ov7660_initVGA_data); + } + break; + case SENSOR_OV7670: + /*GammaT = ov7660_gamma; */ + /*MatrixT = ov7660_matrix; */ + if (mode) { + /* 320x240 */ + usb_exchange(gspca_dev, ov7670_initQVGA_JPG); + } else { + /* 640x480 */ + usb_exchange(gspca_dev, ov7670_initVGA_JPG); + } + break; + case SENSOR_MI1310_SOC: + if (mode) { + /* 320x240 */ + usb_exchange(gspca_dev, mi1310_socinitQVGA_JPG); + } else { + /* 640x480 */ + usb_exchange(gspca_dev, mi1310_socinitVGA_JPG); + } + break; + case SENSOR_MI1320: + GammaT = mi1320_gamma; + MatrixT = mi1320_matrix; + if (mode) { + /* 320x240 */ + usb_exchange(gspca_dev, mi1320_initQVGA_data); + } else { + /* 640x480 */ + usb_exchange(gspca_dev, mi1320_initVGA_data); + } + break; + case SENSOR_PO3130NC: + GammaT = po3130_gamma; + MatrixT = po3130_matrix; + if (mode) { + /* 320x240 */ + usb_exchange(gspca_dev, po3130_initQVGA_data); + } else { + /* 640x480 */ + usb_exchange(gspca_dev, po3130_initVGA_data); + } + usb_exchange(gspca_dev, po3130_rundata); + break; + default: + PDEBUG(D_PROBE, "Damned !! no sensor found Bye"); + return; + } + if (GammaT && MatrixT) { + put_tab_to_reg(gspca_dev, GammaT, 17, 0xb84a); + put_tab_to_reg(gspca_dev, GammaT, 17, 0xb85b); + put_tab_to_reg(gspca_dev, GammaT, 17, 0xb86c); + put_tab_to_reg(gspca_dev, MatrixT, 9, 0xb82c); + + /* Seem SHARPNESS */ + /* + reg_w(gspca_dev->dev, 0xa0, 0x80, 0xb80a); + reg_w(gspca_dev->dev, 0xa0, 0xff, 0xb80b); + reg_w(gspca_dev->dev, 0xa0, 0xff, 0xb80e); + */ + /* all 0x40 ??? do nothing + reg_w(gspca_dev->dev, 0xa0, 0x40, 0xb822); + reg_w(gspca_dev->dev, 0xa0, 0x40, 0xb823); + reg_w(gspca_dev->dev, 0xa0, 0x40, 0xb824); + */ + /* Only works for HV7131R ?? + reg_r (gspca_dev, 0xa1, 0xb881, 1); + reg_w(gspca_dev->dev, 0xa0, 0xfe01, 0xb881); + reg_w(gspca_dev->dev, 0xa0, 0x79, 0xb801); + */ + /* only hv7131r et ov7660 + reg_w(gspca_dev->dev, 0xa0, 0x20, 0xb827); + reg_w(gspca_dev->dev, 0xa0, 0xff, 0xb826); * ISP_GAIN 80 + reg_w(gspca_dev->dev, 0xa0, 0x23, 0xb800); * ISP CTRL_BAS + */ + /* set the led on 0x0892 0x0896 */ + reg_w(gspca_dev->dev, 0x89, 0xffff, 0xfdff); + msleep(100); + setquality(gspca_dev); + setautogain(gspca_dev); + setlightfreq(gspca_dev); + } +} + +static void sd_stopN(struct gspca_dev *gspca_dev) +{ + struct usb_device *dev = gspca_dev->dev; + + reg_w(dev, 0x89, 0xffff, 0xffff); + reg_w(dev, 0xa0, 0x01, 0xb301); + reg_w(dev, 0xa0, 0x09, 0xb003); +} + +static void sd_stop0(struct gspca_dev *gspca_dev) +{ + struct usb_device *dev = gspca_dev->dev; + + reg_w(dev, 0x89, 0xffff, 0xffff); +} + +/* this function is called at close time */ +static void sd_close(struct gspca_dev *gspca_dev) +{ +/* struct usb_device *dev = gspca_dev->dev; + __u8 buffread; + + reg_w(dev, 0x89, 0xffff, 0xffff); + reg_w(dev, 0xa0, 0x01, 0xb301); + reg_w(dev, 0xa0, 0x09, 0xb303); + reg_w(dev, 0x89, 0xffff, 0xffff); +*/ +} + +static void sd_pkt_scan(struct gspca_dev *gspca_dev, + struct gspca_frame *frame, /* target */ + __u8 *data, /* isoc packet */ + int len) /* iso pkt length */ +{ + struct sd *sd = (struct sd *) gspca_dev; + + if (data[0] == 0xff && data[1] == 0xd8) { + PDEBUG(D_PACK, + "vc032x header packet found len %d", len); + frame = gspca_frame_add(gspca_dev, LAST_PACKET, frame, + data, 0); + if (sd->bridge == BRIDGE_VC0321) { +#define VCHDRSZ 46 + data += VCHDRSZ; + len -= VCHDRSZ; +#undef VCHDRSZ + } + gspca_frame_add(gspca_dev, FIRST_PACKET, frame, + data, len); + return; + } + gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len); +} + +static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->autogain = val; + if (gspca_dev->streaming) + setautogain(gspca_dev); + return 0; +} + +static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + *val = sd->autogain; + return 0; +} + +static int sd_setfreq(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->lightfreq = val; + if (gspca_dev->streaming) + setlightfreq(gspca_dev); + return 0; +} + +static int sd_getfreq(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + *val = sd->lightfreq; + return 0; +} + +static int sd_querymenu(struct gspca_dev *gspca_dev, + struct v4l2_querymenu *menu) +{ + switch (menu->id) { + case V4L2_CID_POWER_LINE_FREQUENCY: + switch (menu->index) { + case 0: /* V4L2_CID_POWER_LINE_FREQUENCY_DISABLED */ + strcpy((char *) menu->name, "NoFliker"); + return 0; + case 1: /* V4L2_CID_POWER_LINE_FREQUENCY_50HZ */ + strcpy((char *) menu->name, "50 Hz"); + return 0; + case 2: /* V4L2_CID_POWER_LINE_FREQUENCY_60HZ */ + strcpy((char *) menu->name, "60 Hz"); + return 0; + } + break; + } + return -EINVAL; +} + +/* sub-driver description */ +static const struct sd_desc sd_desc = { + .name = MODULE_NAME, + .ctrls = sd_ctrls, + .nctrls = ARRAY_SIZE(sd_ctrls), + .config = sd_config, + .open = sd_open, + .start = sd_start, + .stopN = sd_stopN, + .stop0 = sd_stop0, + .close = sd_close, + .pkt_scan = sd_pkt_scan, + .querymenu = sd_querymenu, +}; + +/* -- module initialisation -- */ +#define DVNM(name) .driver_info = (kernel_ulong_t) name +static const __devinitdata struct usb_device_id device_table[] = { + {USB_DEVICE(0x046d, 0x0892), DVNM("Logitech Orbicam")}, + {USB_DEVICE(0x046d, 0x0896), DVNM("Logitech Orbicam")}, + {USB_DEVICE(0x0ac8, 0x0321), DVNM("Vimicro generic vc0321")}, + {USB_DEVICE(0x0ac8, 0x0323), DVNM("Vimicro Vc0323")}, + {USB_DEVICE(0x0ac8, 0x0328), DVNM("A4Tech PK-130MG")}, + {USB_DEVICE(0x0ac8, 0xc001), DVNM("Sony embedded vimicro")}, + {USB_DEVICE(0x0ac8, 0xc002), DVNM("Sony embedded vimicro")}, + {USB_DEVICE(0x17ef, 0x4802), DVNM("Lenovo Vc0323+MI1310_SOC")}, + {} +}; +MODULE_DEVICE_TABLE(usb, device_table); + +/* -- device connect -- */ +static int sd_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd), + THIS_MODULE); +} + +static struct usb_driver sd_driver = { + .name = MODULE_NAME, + .id_table = device_table, + .probe = sd_probe, + .disconnect = gspca_disconnect, +}; + +/* -- module insert / remove -- */ +static int __init sd_mod_init(void) +{ + if (usb_register(&sd_driver) < 0) + return -1; + PDEBUG(D_PROBE, "v%s registered", version); + return 0; +} +static void __exit sd_mod_exit(void) +{ + usb_deregister(&sd_driver); + PDEBUG(D_PROBE, "deregistered"); +} + +module_init(sd_mod_init); +module_exit(sd_mod_exit); diff --git a/drivers/media/video/gspca/zc3xx-reg.h b/drivers/media/video/gspca/zc3xx-reg.h new file mode 100644 index 000000000000..f52e09c2cc19 --- /dev/null +++ b/drivers/media/video/gspca/zc3xx-reg.h @@ -0,0 +1,261 @@ +/* + * zc030x registers + * + * Copyright (c) 2008 Mauro Carvalho Chehab <mchehab@infradead.org> + * + * The register aliases used here came from this driver: + * http://zc0302.sourceforge.net/zc0302.php + * + * This code is placed under the terms of the GNU General Public License v2 + */ + +/* Define the register map */ +#define ZC3XX_R000_SYSTEMCONTROL 0x0000 +#define ZC3XX_R001_SYSTEMOPERATING 0x0001 + +/* Picture size */ +#define ZC3XX_R002_CLOCKSELECT 0x0002 +#define ZC3XX_R003_FRAMEWIDTHHIGH 0x0003 +#define ZC3XX_R004_FRAMEWIDTHLOW 0x0004 +#define ZC3XX_R005_FRAMEHEIGHTHIGH 0x0005 +#define ZC3XX_R006_FRAMEHEIGHTLOW 0x0006 + +/* JPEG control */ +#define ZC3XX_R008_CLOCKSETTING 0x0008 + +/* Test mode */ +#define ZC3XX_R00B_TESTMODECONTROL 0x000b + +/* Frame retreiving */ +#define ZC3XX_R00C_LASTACQTIME 0x000c +#define ZC3XX_R00D_MONITORRES 0x000d +#define ZC3XX_R00E_TIMESTAMPHIGH 0x000e +#define ZC3XX_R00F_TIMESTAMPLOW 0x000f +#define ZC3XX_R018_FRAMELOST 0x0018 +#define ZC3XX_R019_AUTOADJUSTFPS 0x0019 +#define ZC3XX_R01A_LASTFRAMESTATE 0x001a +#define ZC3XX_R025_DATACOUNTER 0x0025 + +/* Stream and sensor specific */ +#define ZC3XX_R010_CMOSSENSORSELECT 0x0010 +#define ZC3XX_R011_VIDEOSTATUS 0x0011 +#define ZC3XX_R012_VIDEOCONTROLFUNC 0x0012 + +/* Horizontal and vertical synchros */ +#define ZC3XX_R01D_HSYNC_0 0x001d +#define ZC3XX_R01E_HSYNC_1 0x001e +#define ZC3XX_R01F_HSYNC_2 0x001f +#define ZC3XX_R020_HSYNC_3 0x0020 + +/* Target picture size in byte */ +#define ZC3XX_R022_TARGETPICTSIZE_0 0x0022 +#define ZC3XX_R023_TARGETPICTSIZE_1 0x0023 +#define ZC3XX_R024_TARGETPICTSIZE_2 0x0024 + +/* Audio registers */ +#define ZC3XX_R030_AUDIOADC 0x0030 +#define ZC3XX_R031_AUDIOSTREAMSTATUS 0x0031 +#define ZC3XX_R032_AUDIOSTATUS 0x0032 + +/* Sensor interface */ +#define ZC3XX_R080_HBLANKHIGH 0x0080 +#define ZC3XX_R081_HBLANKLOW 0x0081 +#define ZC3XX_R082_RESETLEVELADDR 0x0082 +#define ZC3XX_R083_RGAINADDR 0x0083 +#define ZC3XX_R084_GGAINADDR 0x0084 +#define ZC3XX_R085_BGAINADDR 0x0085 +#define ZC3XX_R086_EXPTIMEHIGH 0x0086 +#define ZC3XX_R087_EXPTIMEMID 0x0087 +#define ZC3XX_R088_EXPTIMELOW 0x0088 +#define ZC3XX_R089_RESETBLACKHIGH 0x0089 +#define ZC3XX_R08A_RESETWHITEHIGH 0x008a +#define ZC3XX_R08B_I2CDEVICEADDR 0x008b +#define ZC3XX_R08C_I2CIDLEANDNACK 0x008c +#define ZC3XX_R08D_COMPABILITYMODE 0x008d +#define ZC3XX_R08E_COMPABILITYMODE2 0x008e + +/* I2C control */ +#define ZC3XX_R090_I2CCOMMAND 0x0090 +#define ZC3XX_R091_I2CSTATUS 0x0091 +#define ZC3XX_R092_I2CADDRESSSELECT 0x0092 +#define ZC3XX_R093_I2CSETVALUE 0x0093 +#define ZC3XX_R094_I2CWRITEACK 0x0094 +#define ZC3XX_R095_I2CREAD 0x0095 +#define ZC3XX_R096_I2CREADACK 0x0096 + +/* Window inside the sensor array */ +#define ZC3XX_R097_WINYSTARTHIGH 0x0097 +#define ZC3XX_R098_WINYSTARTLOW 0x0098 +#define ZC3XX_R099_WINXSTARTHIGH 0x0099 +#define ZC3XX_R09A_WINXSTARTLOW 0x009a +#define ZC3XX_R09B_WINHEIGHTHIGH 0x009b +#define ZC3XX_R09C_WINHEIGHTLOW 0x009c +#define ZC3XX_R09D_WINWIDTHHIGH 0x009d +#define ZC3XX_R09E_WINWIDTHLOW 0x009e +#define ZC3XX_R119_FIRSTYHIGH 0x0119 +#define ZC3XX_R11A_FIRSTYLOW 0x011a +#define ZC3XX_R11B_FIRSTXHIGH 0x011b +#define ZC3XX_R11C_FIRSTXLOW 0x011c + +/* Max sensor array size */ +#define ZC3XX_R09F_MAXXHIGH 0x009f +#define ZC3XX_R0A0_MAXXLOW 0x00a0 +#define ZC3XX_R0A1_MAXYHIGH 0x00a1 +#define ZC3XX_R0A2_MAXYLOW 0x00a2 +#define ZC3XX_R0A3_EXPOSURETIMEHIGH 0x00a3 +#define ZC3XX_R0A4_EXPOSURETIMELOW 0x00a4 +#define ZC3XX_R0A5_EXPOSUREGAIN 0x00a5 +#define ZC3XX_R0A6_EXPOSUREBLACKLVL 0x00a6 + +/* Other registers */ +#define ZC3XX_R100_OPERATIONMODE 0x0100 +#define ZC3XX_R101_SENSORCORRECTION 0x0101 + +/* Gains */ +#define ZC3XX_R116_RGAIN 0x0116 +#define ZC3XX_R117_GGAIN 0x0117 +#define ZC3XX_R118_BGAIN 0x0118 +#define ZC3XX_R11D_GLOBALGAIN 0x011d +#define ZC3XX_R1A8_DIGITALGAIN 0x01a8 +#define ZC3XX_R1A9_DIGITALLIMITDIFF 0x01a9 +#define ZC3XX_R1AA_DIGITALGAINSTEP 0x01aa + +/* Auto correction */ +#define ZC3XX_R180_AUTOCORRECTENABLE 0x0180 +#define ZC3XX_R181_WINXSTART 0x0181 +#define ZC3XX_R182_WINXWIDTH 0x0182 +#define ZC3XX_R183_WINXCENTER 0x0183 +#define ZC3XX_R184_WINYSTART 0x0184 +#define ZC3XX_R185_WINYWIDTH 0x0185 +#define ZC3XX_R186_WINYCENTER 0x0186 + +/* Gain range */ +#define ZC3XX_R187_MAXGAIN 0x0187 +#define ZC3XX_R188_MINGAIN 0x0188 + +/* Auto exposure and white balance */ +#define ZC3XX_R189_AWBSTATUS 0x0189 +#define ZC3XX_R18A_AWBFREEZE 0x018a +#define ZC3XX_R18B_AESTATUS 0x018b +#define ZC3XX_R18C_AEFREEZE 0x018c +#define ZC3XX_R18F_AEUNFREEZE 0x018f +#define ZC3XX_R190_EXPOSURELIMITHIGH 0x0190 +#define ZC3XX_R191_EXPOSURELIMITMID 0x0191 +#define ZC3XX_R192_EXPOSURELIMITLOW 0x0192 +#define ZC3XX_R195_ANTIFLICKERHIGH 0x0195 +#define ZC3XX_R196_ANTIFLICKERMID 0x0196 +#define ZC3XX_R197_ANTIFLICKERLOW 0x0197 + +/* What is this ? */ +#define ZC3XX_R18D_YTARGET 0x018d +#define ZC3XX_R18E_RESETLVL 0x018e + +/* Color */ +#define ZC3XX_R1A0_REDMEANAFTERAGC 0x01a0 +#define ZC3XX_R1A1_GREENMEANAFTERAGC 0x01a1 +#define ZC3XX_R1A2_BLUEMEANAFTERAGC 0x01a2 +#define ZC3XX_R1A3_REDMEANAFTERAWB 0x01a3 +#define ZC3XX_R1A4_GREENMEANAFTERAWB 0x01a4 +#define ZC3XX_R1A5_BLUEMEANAFTERAWB 0x01a5 +#define ZC3XX_R1A6_YMEANAFTERAE 0x01a6 +#define ZC3XX_R1A7_CALCGLOBALMEAN 0x01a7 + +#define ZC3XX_R1A2_BLUEMEANAFTERAGC 0x01a2 + +/* Matrixes */ + +/* Color matrix is like : + R' = R * RGB00 + G * RGB01 + B * RGB02 + RGB03 + G' = R * RGB10 + G * RGB11 + B * RGB22 + RGB13 + B' = R * RGB20 + G * RGB21 + B * RGB12 + RGB23 + */ +#define ZC3XX_R10A_RGB00 0x010a +#define ZC3XX_R10B_RGB01 0x010b +#define ZC3XX_R10C_RGB02 0x010c +#define ZC3XX_R113_RGB03 0x0113 +#define ZC3XX_R10D_RGB10 0x010d +#define ZC3XX_R10E_RGB11 0x010e +#define ZC3XX_R10F_RGB12 0x010f +#define ZC3XX_R114_RGB13 0x0114 +#define ZC3XX_R110_RGB20 0x0110 +#define ZC3XX_R111_RGB21 0x0111 +#define ZC3XX_R112_RGB22 0x0112 +#define ZC3XX_R115_RGB23 0x0115 + +/* Gamma matrix */ +#define ZC3XX_R120_GAMMA00 0x0120 +#define ZC3XX_R121_GAMMA01 0x0121 +#define ZC3XX_R122_GAMMA02 0x0122 +#define ZC3XX_R123_GAMMA03 0x0123 +#define ZC3XX_R124_GAMMA04 0x0124 +#define ZC3XX_R125_GAMMA05 0x0125 +#define ZC3XX_R126_GAMMA06 0x0126 +#define ZC3XX_R127_GAMMA07 0x0127 +#define ZC3XX_R128_GAMMA08 0x0128 +#define ZC3XX_R129_GAMMA09 0x0129 +#define ZC3XX_R12A_GAMMA0A 0x012a +#define ZC3XX_R12B_GAMMA0B 0x012b +#define ZC3XX_R12C_GAMMA0C 0x012c +#define ZC3XX_R12D_GAMMA0D 0x012d +#define ZC3XX_R12E_GAMMA0E 0x012e +#define ZC3XX_R12F_GAMMA0F 0x012f +#define ZC3XX_R130_GAMMA10 0x0130 +#define ZC3XX_R131_GAMMA11 0x0131 +#define ZC3XX_R132_GAMMA12 0x0132 +#define ZC3XX_R133_GAMMA13 0x0133 +#define ZC3XX_R134_GAMMA14 0x0134 +#define ZC3XX_R135_GAMMA15 0x0135 +#define ZC3XX_R136_GAMMA16 0x0136 +#define ZC3XX_R137_GAMMA17 0x0137 +#define ZC3XX_R138_GAMMA18 0x0138 +#define ZC3XX_R139_GAMMA19 0x0139 +#define ZC3XX_R13A_GAMMA1A 0x013a +#define ZC3XX_R13B_GAMMA1B 0x013b +#define ZC3XX_R13C_GAMMA1C 0x013c +#define ZC3XX_R13D_GAMMA1D 0x013d +#define ZC3XX_R13E_GAMMA1E 0x013e +#define ZC3XX_R13F_GAMMA1F 0x013f + +/* Luminance gamma */ +#define ZC3XX_R140_YGAMMA00 0x0140 +#define ZC3XX_R141_YGAMMA01 0x0141 +#define ZC3XX_R142_YGAMMA02 0x0142 +#define ZC3XX_R143_YGAMMA03 0x0143 +#define ZC3XX_R144_YGAMMA04 0x0144 +#define ZC3XX_R145_YGAMMA05 0x0145 +#define ZC3XX_R146_YGAMMA06 0x0146 +#define ZC3XX_R147_YGAMMA07 0x0147 +#define ZC3XX_R148_YGAMMA08 0x0148 +#define ZC3XX_R149_YGAMMA09 0x0149 +#define ZC3XX_R14A_YGAMMA0A 0x014a +#define ZC3XX_R14B_YGAMMA0B 0x014b +#define ZC3XX_R14C_YGAMMA0C 0x014c +#define ZC3XX_R14D_YGAMMA0D 0x014d +#define ZC3XX_R14E_YGAMMA0E 0x014e +#define ZC3XX_R14F_YGAMMA0F 0x014f +#define ZC3XX_R150_YGAMMA10 0x0150 +#define ZC3XX_R151_YGAMMA11 0x0151 + +#define ZC3XX_R1C5_SHARPNESSMODE 0x01c5 +#define ZC3XX_R1C6_SHARPNESS00 0x01c6 +#define ZC3XX_R1C7_SHARPNESS01 0x01c7 +#define ZC3XX_R1C8_SHARPNESS02 0x01c8 +#define ZC3XX_R1C9_SHARPNESS03 0x01c9 +#define ZC3XX_R1CA_SHARPNESS04 0x01ca +#define ZC3XX_R1CB_SHARPNESS05 0x01cb + +/* Synchronization */ +#define ZC3XX_R190_SYNC00LOW 0x0190 +#define ZC3XX_R191_SYNC00MID 0x0191 +#define ZC3XX_R192_SYNC00HIGH 0x0192 +#define ZC3XX_R195_SYNC01LOW 0x0195 +#define ZC3XX_R196_SYNC01MID 0x0196 +#define ZC3XX_R197_SYNC01HIGH 0x0197 + +/* Dead pixels */ +#define ZC3XX_R250_DEADPIXELSMODE 0x0250 + +/* EEPROM */ +#define ZC3XX_R300_EEPROMCONFIG 0x0300 +#define ZC3XX_R301_EEPROMACCESS 0x0301 +#define ZC3XX_R302_EEPROMSTATUS 0x0302 diff --git a/drivers/media/video/gspca/zc3xx.c b/drivers/media/video/gspca/zc3xx.c new file mode 100644 index 000000000000..b761b11c5c6a --- /dev/null +++ b/drivers/media/video/gspca/zc3xx.c @@ -0,0 +1,7623 @@ +/* + * Z-Star/Vimicro zc301/zc302p/vc30x library + * Copyright (C) 2004 2005 2006 Michel Xhaard + * mxhaard@magic.fr + * + * V4L2 by Jean-Francois Moine <http://moinejf.free.fr> + * + * 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. + */ + +#define MODULE_NAME "zc3xx" + +#include "gspca.h" + +#define DRIVER_VERSION_NUMBER KERNEL_VERSION(2, 1, 7) +static const char version[] = "2.1.7"; + +MODULE_AUTHOR("Michel Xhaard <mxhaard@users.sourceforge.net>, " + "Serge A. Suchkov <Serge.A.S@tochka.ru>"); +MODULE_DESCRIPTION("GSPCA ZC03xx/VC3xx USB Camera Driver"); +MODULE_LICENSE("GPL"); + +static int force_sensor = -1; + +#include "jpeg.h" +#include "zc3xx-reg.h" + +/* specific webcam descriptor */ +struct sd { + struct gspca_dev gspca_dev; /* !! must be the first item */ + + __u8 brightness; + __u8 contrast; + __u8 gamma; + __u8 autogain; + __u8 lightfreq; + __u8 sharpness; + + char qindex; + char sensor; /* Type of image sensor chip */ +/* !! values used in different tables */ +#define SENSOR_CS2102 0 +#define SENSOR_CS2102K 1 +#define SENSOR_GC0305 2 +#define SENSOR_HDCS2020 3 +#define SENSOR_HDCS2020b 4 +#define SENSOR_HV7131B 5 +#define SENSOR_HV7131C 6 +#define SENSOR_ICM105A 7 +#define SENSOR_MC501CB 8 +#define SENSOR_OV7620 9 +/*#define SENSOR_OV7648 9 - same values */ +#define SENSOR_OV7630C 10 +#define SENSOR_PAS106 11 +#define SENSOR_PB0330 12 +#define SENSOR_PO2030 13 +#define SENSOR_TAS5130CK 14 +#define SENSOR_TAS5130CXX 15 +#define SENSOR_TAS5130C_VF0250 16 +#define SENSOR_MAX 17 + unsigned short chip_revision; +}; + +/* V4L2 controls supported by the driver */ +static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val); +static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val); +static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val); +static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val); +static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val); +static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val); +static int sd_setgamma(struct gspca_dev *gspca_dev, __s32 val); +static int sd_getgamma(struct gspca_dev *gspca_dev, __s32 *val); +static int sd_setfreq(struct gspca_dev *gspca_dev, __s32 val); +static int sd_getfreq(struct gspca_dev *gspca_dev, __s32 *val); +static int sd_setsharpness(struct gspca_dev *gspca_dev, __s32 val); +static int sd_getsharpness(struct gspca_dev *gspca_dev, __s32 *val); + +static struct ctrl sd_ctrls[] = { +#define SD_BRIGHTNESS 0 + { + { + .id = V4L2_CID_BRIGHTNESS, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Brightness", + .minimum = 0, + .maximum = 255, + .step = 1, + .default_value = 128, + }, + .set = sd_setbrightness, + .get = sd_getbrightness, + }, +#define SD_CONTRAST 1 + { + { + .id = V4L2_CID_CONTRAST, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Contrast", + .minimum = 0, + .maximum = 256, + .step = 1, + .default_value = 128, + }, + .set = sd_setcontrast, + .get = sd_getcontrast, + }, +#define SD_GAMMA 2 + { + { + .id = V4L2_CID_GAMMA, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Gamma", + .minimum = 1, + .maximum = 6, + .step = 1, + .default_value = 4, + }, + .set = sd_setgamma, + .get = sd_getgamma, + }, +#define SD_AUTOGAIN 3 + { + { + .id = V4L2_CID_AUTOGAIN, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Auto Gain", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 1, + }, + .set = sd_setautogain, + .get = sd_getautogain, + }, +#define SD_FREQ 4 + { + { + .id = V4L2_CID_POWER_LINE_FREQUENCY, + .type = V4L2_CTRL_TYPE_MENU, + .name = "Light frequency filter", + .minimum = 0, + .maximum = 2, /* 0: 0, 1: 50Hz, 2:60Hz */ + .step = 1, + .default_value = 1, + }, + .set = sd_setfreq, + .get = sd_getfreq, + }, +#define SD_SHARPNESS 5 + { + { + .id = V4L2_CID_SHARPNESS, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Sharpness", + .minimum = 0, + .maximum = 3, + .step = 1, + .default_value = 2, + }, + .set = sd_setsharpness, + .get = sd_getsharpness, + }, +}; + +static struct v4l2_pix_format vga_mode[] = { + {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, + .bytesperline = 320, + .sizeimage = 320 * 240 * 3 / 8 + 590, + .colorspace = V4L2_COLORSPACE_JPEG, + .priv = 1}, + {640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, + .bytesperline = 640, + .sizeimage = 640 * 480 * 3 / 8 + 590, + .colorspace = V4L2_COLORSPACE_JPEG, + .priv = 0}, +}; + +static struct v4l2_pix_format sif_mode[] = { + {176, 144, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, + .bytesperline = 176, + .sizeimage = 176 * 144 * 3 / 8 + 590, + .colorspace = V4L2_COLORSPACE_JPEG, + .priv = 1}, + {352, 288, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, + .bytesperline = 352, + .sizeimage = 352 * 288 * 3 / 8 + 590, + .colorspace = V4L2_COLORSPACE_JPEG, + .priv = 0}, +}; + +/* usb exchanges */ +struct usb_action { + __u8 req; + __u8 val; + __u16 idx; +}; + +static const struct usb_action cs2102_Initial[] = { + {0xa1, 0x01, 0x0008}, + {0xa1, 0x01, 0x0008}, + {0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL}, + {0xa0, 0x10, ZC3XX_R002_CLOCKSELECT}, + {0xa0, 0x00, ZC3XX_R010_CMOSSENSORSELECT}, + {0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING}, + {0xa0, 0x20, ZC3XX_R080_HBLANKHIGH}, + {0xa0, 0x21, ZC3XX_R081_HBLANKLOW}, + {0xa0, 0x30, ZC3XX_R083_RGAINADDR}, + {0xa0, 0x31, ZC3XX_R084_GGAINADDR}, + {0xa0, 0x32, ZC3XX_R085_BGAINADDR}, + {0xa0, 0x23, ZC3XX_R086_EXPTIMEHIGH}, + {0xa0, 0x24, ZC3XX_R087_EXPTIMEMID}, + {0xa0, 0x25, ZC3XX_R088_EXPTIMELOW}, + {0xa0, 0xb3, ZC3XX_R08B_I2CDEVICEADDR}, + {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, /* 00 */ + {0xa0, 0x03, ZC3XX_R012_VIDEOCONTROLFUNC}, + {0xa0, 0x01, ZC3XX_R012_VIDEOCONTROLFUNC}, + {0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH}, + {0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW}, + {0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH}, + {0xa0, 0xe0, ZC3XX_R006_FRAMEHEIGHTLOW}, + {0xa0, 0x00, ZC3XX_R098_WINYSTARTLOW}, + {0xa0, 0x00, ZC3XX_R09A_WINXSTARTLOW}, + {0xa0, 0x00, ZC3XX_R11A_FIRSTYLOW}, + {0xa0, 0x00, ZC3XX_R11C_FIRSTXLOW}, + {0xaa, 0x02, 0x0008}, + {0xaa, 0x03, 0x0000}, + {0xaa, 0x11, 0x0000}, + {0xaa, 0x12, 0x0089}, + {0xaa, 0x13, 0x0000}, + {0xaa, 0x14, 0x00e9}, + {0xaa, 0x20, 0x0000}, + {0xaa, 0x22, 0x0000}, + {0xaa, 0x0b, 0x0004}, + {0xaa, 0x30, 0x0030}, + {0xaa, 0x31, 0x0030}, + {0xaa, 0x32, 0x0030}, + {0xa0, 0x37, ZC3XX_R101_SENSORCORRECTION}, + {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, + {0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC}, + {0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE}, + {0xa0, 0x06, ZC3XX_R189_AWBSTATUS}, + {0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE}, + {0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05}, + {0xa0, 0x10, 0x01ae}, + {0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE}, + {0xa0, 0x08, ZC3XX_R301_EEPROMACCESS}, + {0xa0, 0x68, ZC3XX_R18D_YTARGET}, + {0xa0, 0x00, 0x01ad}, + {0xa1, 0x01, 0x0002}, + {0xa1, 0x01, 0x0008}, + {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, /* 00 */ + {0xa0, 0x08, ZC3XX_R1C6_SHARPNESS00}, /* sharpness+ */ + {0xa1, 0x01, 0x01c8}, + {0xa1, 0x01, 0x01c9}, + {0xa1, 0x01, 0x01ca}, + {0xa0, 0x0f, ZC3XX_R1CB_SHARPNESS05}, /* sharpness- */ + {0xa0, 0x24, ZC3XX_R120_GAMMA00}, /* gamma 5 */ + {0xa0, 0x44, ZC3XX_R121_GAMMA01}, + {0xa0, 0x64, ZC3XX_R122_GAMMA02}, + {0xa0, 0x84, ZC3XX_R123_GAMMA03}, + {0xa0, 0x9d, ZC3XX_R124_GAMMA04}, + {0xa0, 0xb2, ZC3XX_R125_GAMMA05}, + {0xa0, 0xc4, ZC3XX_R126_GAMMA06}, + {0xa0, 0xd3, ZC3XX_R127_GAMMA07}, + {0xa0, 0xe0, ZC3XX_R128_GAMMA08}, + {0xa0, 0xeb, ZC3XX_R129_GAMMA09}, + {0xa0, 0xf4, ZC3XX_R12A_GAMMA0A}, + {0xa0, 0xfb, ZC3XX_R12B_GAMMA0B}, + {0xa0, 0xff, ZC3XX_R12C_GAMMA0C}, + {0xa0, 0xff, ZC3XX_R12D_GAMMA0D}, + {0xa0, 0xff, ZC3XX_R12E_GAMMA0E}, + {0xa0, 0xff, ZC3XX_R12F_GAMMA0F}, + {0xa0, 0x18, ZC3XX_R130_GAMMA10}, + {0xa0, 0x20, ZC3XX_R131_GAMMA11}, + {0xa0, 0x20, ZC3XX_R132_GAMMA12}, + {0xa0, 0x1c, ZC3XX_R133_GAMMA13}, + {0xa0, 0x16, ZC3XX_R134_GAMMA14}, + {0xa0, 0x13, ZC3XX_R135_GAMMA15}, + {0xa0, 0x10, ZC3XX_R136_GAMMA16}, + {0xa0, 0x0e, ZC3XX_R137_GAMMA17}, + {0xa0, 0x0b, ZC3XX_R138_GAMMA18}, + {0xa0, 0x09, ZC3XX_R139_GAMMA19}, + {0xa0, 0x07, ZC3XX_R13A_GAMMA1A}, + {0xa0, 0x06, ZC3XX_R13B_GAMMA1B}, + {0xa0, 0x00, ZC3XX_R13C_GAMMA1C}, + {0xa0, 0x00, ZC3XX_R13D_GAMMA1D}, + {0xa0, 0x00, ZC3XX_R13E_GAMMA1E}, + {0xa0, 0x01, ZC3XX_R13F_GAMMA1F}, + {0xa0, 0x58, ZC3XX_R10A_RGB00}, /* matrix */ + {0xa0, 0xf4, ZC3XX_R10B_RGB01}, + {0xa0, 0xf4, ZC3XX_R10C_RGB02}, + {0xa0, 0xf4, ZC3XX_R10D_RGB10}, + {0xa0, 0x58, ZC3XX_R10E_RGB11}, + {0xa0, 0xf4, ZC3XX_R10F_RGB12}, + {0xa0, 0xf4, ZC3XX_R110_RGB20}, + {0xa0, 0xf4, ZC3XX_R111_RGB21}, + {0xa0, 0x58, ZC3XX_R112_RGB22}, + {0xa1, 0x01, 0x0180}, + {0xa0, 0x00, ZC3XX_R180_AUTOCORRECTENABLE}, + {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, + {0xaa, 0x23, 0x0001}, + {0xaa, 0x24, 0x0055}, + {0xaa, 0x25, 0x00cc}, + {0xaa, 0x21, 0x003f}, + {0xa0, 0x02, ZC3XX_R190_EXPOSURELIMITHIGH}, + {0xa0, 0xab, ZC3XX_R191_EXPOSURELIMITMID}, + {0xa0, 0x98, ZC3XX_R192_EXPOSURELIMITLOW}, + {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, + {0xa0, 0x30, ZC3XX_R196_ANTIFLICKERMID}, + {0xa0, 0xd4, ZC3XX_R197_ANTIFLICKERLOW}, + {0xa0, 0x10, ZC3XX_R18C_AEFREEZE}, + {0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE}, + {0xa0, 0x10, ZC3XX_R1A9_DIGITALLIMITDIFF}, + {0xa0, 0x24, ZC3XX_R1AA_DIGITALGAINSTEP}, + {0xa0, 0x39, ZC3XX_R01D_HSYNC_0}, + {0xa0, 0x70, ZC3XX_R01E_HSYNC_1}, + {0xa0, 0xb0, ZC3XX_R01F_HSYNC_2}, + {0xa0, 0xff, ZC3XX_R020_HSYNC_3}, + {0xa0, 0x40, ZC3XX_R180_AUTOCORRECTENABLE}, + {0xa1, 0x01, 0x0180}, + {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE}, + {0xa0, 0x40, ZC3XX_R116_RGAIN}, + {0xa0, 0x40, ZC3XX_R117_GGAIN}, + {0xa0, 0x40, ZC3XX_R118_BGAIN}, + {} +}; + +static const struct usb_action cs2102_InitialScale[] = { + {0xa1, 0x01, 0x0008}, + {0xa1, 0x01, 0x0008}, + {0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL}, + {0xa0, 0x00, ZC3XX_R002_CLOCKSELECT}, + {0xa0, 0x00, ZC3XX_R010_CMOSSENSORSELECT}, + {0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING}, + {0xa0, 0x20, ZC3XX_R080_HBLANKHIGH}, + {0xa0, 0x21, ZC3XX_R081_HBLANKLOW}, + {0xa0, 0x30, ZC3XX_R083_RGAINADDR}, + {0xa0, 0x31, ZC3XX_R084_GGAINADDR}, + {0xa0, 0x32, ZC3XX_R085_BGAINADDR}, + {0xa0, 0x23, ZC3XX_R086_EXPTIMEHIGH}, + {0xa0, 0x24, ZC3XX_R087_EXPTIMEMID}, + {0xa0, 0x25, ZC3XX_R088_EXPTIMELOW}, + {0xa0, 0xb3, ZC3XX_R08B_I2CDEVICEADDR}, + {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, /* 00 */ + {0xa0, 0x03, ZC3XX_R012_VIDEOCONTROLFUNC}, + {0xa0, 0x01, ZC3XX_R012_VIDEOCONTROLFUNC}, + {0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH}, + {0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW}, + {0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH}, + {0xa0, 0xe0, ZC3XX_R006_FRAMEHEIGHTLOW}, + {0xa0, 0x00, ZC3XX_R098_WINYSTARTLOW}, + {0xa0, 0x00, ZC3XX_R09A_WINXSTARTLOW}, + {0xa0, 0x00, ZC3XX_R11A_FIRSTYLOW}, + {0xa0, 0x00, ZC3XX_R11C_FIRSTXLOW}, + {0xaa, 0x02, 0x0008}, + {0xaa, 0x03, 0x0000}, + {0xaa, 0x11, 0x0001}, + {0xaa, 0x12, 0x0087}, + {0xaa, 0x13, 0x0001}, + {0xaa, 0x14, 0x00e7}, + {0xaa, 0x20, 0x0000}, + {0xaa, 0x22, 0x0000}, + {0xaa, 0x0b, 0x0004}, + {0xaa, 0x30, 0x0030}, + {0xaa, 0x31, 0x0030}, + {0xaa, 0x32, 0x0030}, + {0xa0, 0x77, ZC3XX_R101_SENSORCORRECTION}, + {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, + {0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC}, + {0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE}, + {0xa0, 0x06, ZC3XX_R189_AWBSTATUS}, + {0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE}, + {0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05}, + {0xa0, 0x15, 0x01ae}, + {0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE}, + {0xa0, 0x08, ZC3XX_R301_EEPROMACCESS}, + {0xa0, 0x68, ZC3XX_R18D_YTARGET}, + {0xa0, 0x00, 0x01ad}, + {0xa1, 0x01, 0x0002}, + {0xa1, 0x01, 0x0008}, + {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, /* 00 */ + {0xa0, 0x08, ZC3XX_R1C6_SHARPNESS00}, /* sharpness+ */ + {0xa1, 0x01, 0x01c8}, + {0xa1, 0x01, 0x01c9}, + {0xa1, 0x01, 0x01ca}, + {0xa0, 0x0f, ZC3XX_R1CB_SHARPNESS05}, /* sharpness- */ + {0xa0, 0x24, ZC3XX_R120_GAMMA00}, /* gamma 5 */ + {0xa0, 0x44, ZC3XX_R121_GAMMA01}, + {0xa0, 0x64, ZC3XX_R122_GAMMA02}, + {0xa0, 0x84, ZC3XX_R123_GAMMA03}, + {0xa0, 0x9d, ZC3XX_R124_GAMMA04}, + {0xa0, 0xb2, ZC3XX_R125_GAMMA05}, + {0xa0, 0xc4, ZC3XX_R126_GAMMA06}, + {0xa0, 0xd3, ZC3XX_R127_GAMMA07}, + {0xa0, 0xe0, ZC3XX_R128_GAMMA08}, + {0xa0, 0xeb, ZC3XX_R129_GAMMA09}, + {0xa0, 0xf4, ZC3XX_R12A_GAMMA0A}, + {0xa0, 0xfb, ZC3XX_R12B_GAMMA0B}, + {0xa0, 0xff, ZC3XX_R12C_GAMMA0C}, + {0xa0, 0xff, ZC3XX_R12D_GAMMA0D}, + {0xa0, 0xff, ZC3XX_R12E_GAMMA0E}, + {0xa0, 0xff, ZC3XX_R12F_GAMMA0F}, + {0xa0, 0x18, ZC3XX_R130_GAMMA10}, + {0xa0, 0x20, ZC3XX_R131_GAMMA11}, + {0xa0, 0x20, ZC3XX_R132_GAMMA12}, + {0xa0, 0x1c, ZC3XX_R133_GAMMA13}, + {0xa0, 0x16, ZC3XX_R134_GAMMA14}, + {0xa0, 0x13, ZC3XX_R135_GAMMA15}, + {0xa0, 0x10, ZC3XX_R136_GAMMA16}, + {0xa0, 0x0e, ZC3XX_R137_GAMMA17}, + {0xa0, 0x0b, ZC3XX_R138_GAMMA18}, + {0xa0, 0x09, ZC3XX_R139_GAMMA19}, + {0xa0, 0x07, ZC3XX_R13A_GAMMA1A}, + {0xa0, 0x06, ZC3XX_R13B_GAMMA1B}, + {0xa0, 0x00, ZC3XX_R13C_GAMMA1C}, + {0xa0, 0x00, ZC3XX_R13D_GAMMA1D}, + {0xa0, 0x00, ZC3XX_R13E_GAMMA1E}, + {0xa0, 0x01, ZC3XX_R13F_GAMMA1F}, + {0xa0, 0x58, ZC3XX_R10A_RGB00}, /* matrix */ + {0xa0, 0xf4, ZC3XX_R10B_RGB01}, + {0xa0, 0xf4, ZC3XX_R10C_RGB02}, + {0xa0, 0xf4, ZC3XX_R10D_RGB10}, + {0xa0, 0x58, ZC3XX_R10E_RGB11}, + {0xa0, 0xf4, ZC3XX_R10F_RGB12}, + {0xa0, 0xf4, ZC3XX_R110_RGB20}, + {0xa0, 0xf4, ZC3XX_R111_RGB21}, + {0xa0, 0x58, ZC3XX_R112_RGB22}, + {0xa1, 0x01, 0x0180}, + {0xa0, 0x00, ZC3XX_R180_AUTOCORRECTENABLE}, + {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, + {0xaa, 0x23, 0x0000}, + {0xaa, 0x24, 0x00aa}, + {0xaa, 0x25, 0x00e6}, + {0xaa, 0x21, 0x003f}, + {0xa0, 0x01, ZC3XX_R190_EXPOSURELIMITHIGH}, + {0xa0, 0x55, ZC3XX_R191_EXPOSURELIMITMID}, + {0xa0, 0xcc, ZC3XX_R192_EXPOSURELIMITLOW}, + {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, + {0xa0, 0x18, ZC3XX_R196_ANTIFLICKERMID}, + {0xa0, 0x6a, ZC3XX_R197_ANTIFLICKERLOW}, + {0xa0, 0x10, ZC3XX_R18C_AEFREEZE}, + {0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE}, + {0xa0, 0x10, ZC3XX_R1A9_DIGITALLIMITDIFF}, + {0xa0, 0x24, ZC3XX_R1AA_DIGITALGAINSTEP}, + {0xa0, 0x3f, ZC3XX_R01D_HSYNC_0}, + {0xa0, 0xa5, ZC3XX_R01E_HSYNC_1}, + {0xa0, 0xf0, ZC3XX_R01F_HSYNC_2}, + {0xa0, 0xff, ZC3XX_R020_HSYNC_3}, + {0xa0, 0x40, ZC3XX_R180_AUTOCORRECTENABLE}, + {0xa1, 0x01, 0x0180}, + {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE}, + {0xa0, 0x40, ZC3XX_R116_RGAIN}, + {0xa0, 0x40, ZC3XX_R117_GGAIN}, + {0xa0, 0x40, ZC3XX_R118_BGAIN}, + {} +}; +static const struct usb_action cs2102_50HZ[] = { + {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */ + {0xaa, 0x0f, 0x008c}, /* 00,0f,8c,aa */ + {0xaa, 0x03, 0x0005}, /* 00,03,05,aa */ + {0xaa, 0x04, 0x00ac}, /* 00,04,ac,aa */ + {0xaa, 0x10, 0x0005}, /* 00,10,05,aa */ + {0xaa, 0x11, 0x00ac}, /* 00,11,ac,aa */ + {0xaa, 0x1b, 0x0000}, /* 00,1b,00,aa */ + {0xaa, 0x1c, 0x0005}, /* 00,1c,05,aa */ + {0xaa, 0x1d, 0x00ac}, /* 00,1d,ac,aa */ + {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc */ + {0xa0, 0x3f, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,3f,cc */ + {0xa0, 0xf0, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,f0,cc */ + {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */ + {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc */ + {0xa0, 0x42, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,42,cc */ + {0xa0, 0x10, ZC3XX_R18C_AEFREEZE}, /* 01,8c,10,cc */ + {0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,20,cc */ + {0xa0, 0x10, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,10,cc */ + {0xa0, 0x24, ZC3XX_R1AA_DIGITALGAINSTEP}, /* 01,aa,24,cc */ + {0xa0, 0x8c, ZC3XX_R01D_HSYNC_0}, /* 00,1d,8c,cc */ + {0xa0, 0xb0, ZC3XX_R01E_HSYNC_1}, /* 00,1e,b0,cc */ + {0xa0, 0xd0, ZC3XX_R01F_HSYNC_2}, /* 00,1f,d0,cc */ + {} +}; +static const struct usb_action cs2102_50HZScale[] = { + {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */ + {0xaa, 0x0f, 0x0093}, /* 00,0f,93,aa */ + {0xaa, 0x03, 0x0005}, /* 00,03,05,aa */ + {0xaa, 0x04, 0x00a1}, /* 00,04,a1,aa */ + {0xaa, 0x10, 0x0005}, /* 00,10,05,aa */ + {0xaa, 0x11, 0x00a1}, /* 00,11,a1,aa */ + {0xaa, 0x1b, 0x0000}, /* 00,1b,00,aa */ + {0xaa, 0x1c, 0x0005}, /* 00,1c,05,aa */ + {0xaa, 0x1d, 0x00a1}, /* 00,1d,a1,aa */ + {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc */ + {0xa0, 0x3f, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,3f,cc */ + {0xa0, 0xf7, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,f7,cc */ + {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */ + {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc */ + {0xa0, 0x83, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,83,cc */ + {0xa0, 0x10, ZC3XX_R18C_AEFREEZE}, /* 01,8c,10,cc */ + {0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,20,cc */ + {0xa0, 0x10, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,10,cc */ + {0xa0, 0x24, ZC3XX_R1AA_DIGITALGAINSTEP}, /* 01,aa,24,cc */ + {0xa0, 0x93, ZC3XX_R01D_HSYNC_0}, /* 00,1d,93,cc */ + {0xa0, 0xb0, ZC3XX_R01E_HSYNC_1}, /* 00,1e,b0,cc */ + {0xa0, 0xd0, ZC3XX_R01F_HSYNC_2}, /* 00,1f,d0,cc */ + {} +}; +static const struct usb_action cs2102_60HZ[] = { + {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */ + {0xaa, 0x0f, 0x005d}, /* 00,0f,5d,aa */ + {0xaa, 0x03, 0x0005}, /* 00,03,05,aa */ + {0xaa, 0x04, 0x00aa}, /* 00,04,aa,aa */ + {0xaa, 0x10, 0x0005}, /* 00,10,05,aa */ + {0xaa, 0x11, 0x00aa}, /* 00,11,aa,aa */ + {0xaa, 0x1b, 0x0000}, /* 00,1b,00,aa */ + {0xaa, 0x1c, 0x0005}, /* 00,1c,05,aa */ + {0xaa, 0x1d, 0x00aa}, /* 00,1d,aa,aa */ + {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc */ + {0xa0, 0x3f, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,3f,cc */ + {0xa0, 0xe4, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,e4,cc */ + {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */ + {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc */ + {0xa0, 0x3a, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,3a,cc */ + {0xa0, 0x10, ZC3XX_R18C_AEFREEZE}, /* 01,8c,10,cc */ + {0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,20,cc */ + {0xa0, 0x10, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,10,cc */ + {0xa0, 0x24, ZC3XX_R1AA_DIGITALGAINSTEP}, /* 01,aa,24,cc */ + {0xa0, 0x5d, ZC3XX_R01D_HSYNC_0}, /* 00,1d,5d,cc */ + {0xa0, 0x90, ZC3XX_R01E_HSYNC_1}, /* 00,1e,90,cc */ + {0xa0, 0xd0, 0x00c8}, /* 00,c8,d0,cc */ + {} +}; +static const struct usb_action cs2102_60HZScale[] = { + {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */ + {0xaa, 0x0f, 0x00b7}, /* 00,0f,b7,aa */ + {0xaa, 0x03, 0x0005}, /* 00,03,05,aa */ + {0xaa, 0x04, 0x00be}, /* 00,04,be,aa */ + {0xaa, 0x10, 0x0005}, /* 00,10,05,aa */ + {0xaa, 0x11, 0x00be}, /* 00,11,be,aa */ + {0xaa, 0x1b, 0x0000}, /* 00,1b,00,aa */ + {0xaa, 0x1c, 0x0005}, /* 00,1c,05,aa */ + {0xaa, 0x1d, 0x00be}, /* 00,1d,be,aa */ + {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc */ + {0xa0, 0x3f, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,3f,cc */ + {0xa0, 0xfc, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,fc,cc */ + {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */ + {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc */ + {0xa0, 0x69, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,69,cc */ + {0xa0, 0x10, ZC3XX_R18C_AEFREEZE}, /* 01,8c,10,cc */ + {0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,20,cc */ + {0xa0, 0x10, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,10,cc */ + {0xa0, 0x24, ZC3XX_R1AA_DIGITALGAINSTEP}, /* 01,aa,24,cc */ + {0xa0, 0xb7, ZC3XX_R01D_HSYNC_0}, /* 00,1d,b7,cc */ + {0xa0, 0xd0, ZC3XX_R01E_HSYNC_1}, /* 00,1e,d0,cc */ + {0xa0, 0xe8, ZC3XX_R01F_HSYNC_2}, /* 00,1f,e8,cc */ + {} +}; +static const struct usb_action cs2102_NoFliker[] = { + {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */ + {0xaa, 0x0f, 0x0059}, /* 00,0f,59,aa */ + {0xaa, 0x03, 0x0005}, /* 00,03,05,aa */ + {0xaa, 0x04, 0x0080}, /* 00,04,80,aa */ + {0xaa, 0x10, 0x0005}, /* 00,10,05,aa */ + {0xaa, 0x11, 0x0080}, /* 00,11,80,aa */ + {0xaa, 0x1b, 0x0000}, /* 00,1b,00,aa */ + {0xaa, 0x1c, 0x0005}, /* 00,1c,05,aa */ + {0xaa, 0x1d, 0x0080}, /* 00,1d,80,aa */ + {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc */ + {0xa0, 0x3f, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,3f,cc */ + {0xa0, 0xf0, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,f0,cc */ + {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */ + {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc */ + {0xa0, 0x10, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,10,cc */ + {0xa0, 0x10, ZC3XX_R18C_AEFREEZE}, /* 01,8c,10,cc */ + {0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,20,cc */ + {0xa0, 0x00, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,00,cc */ + {0xa0, 0x00, ZC3XX_R1AA_DIGITALGAINSTEP}, /* 01,aa,00,cc */ + {0xa0, 0x59, ZC3XX_R01D_HSYNC_0}, /* 00,1d,59,cc */ + {0xa0, 0x90, ZC3XX_R01E_HSYNC_1}, /* 00,1e,90,cc */ + {0xa0, 0xc8, ZC3XX_R01F_HSYNC_2}, /* 00,1f,c8,cc */ + {} +}; +static const struct usb_action cs2102_NoFlikerScale[] = { + {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */ + {0xaa, 0x0f, 0x0059}, /* 00,0f,59,aa */ + {0xaa, 0x03, 0x0005}, /* 00,03,05,aa */ + {0xaa, 0x04, 0x0080}, /* 00,04,80,aa */ + {0xaa, 0x10, 0x0005}, /* 00,10,05,aa */ + {0xaa, 0x11, 0x0080}, /* 00,11,80,aa */ + {0xaa, 0x1b, 0x0000}, /* 00,1b,00,aa */ + {0xaa, 0x1c, 0x0005}, /* 00,1c,05,aa */ + {0xaa, 0x1d, 0x0080}, /* 00,1d,80,aa */ + {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc */ + {0xa0, 0x3f, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,3f,cc */ + {0xa0, 0xf0, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,f0,cc */ + {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */ + {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc */ + {0xa0, 0x10, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,10,cc */ + {0xa0, 0x10, ZC3XX_R18C_AEFREEZE}, /* 01,8c,10,cc */ + {0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,20,cc */ + {0xa0, 0x00, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,00,cc */ + {0xa0, 0x00, ZC3XX_R1AA_DIGITALGAINSTEP}, /* 01,aa,00,cc */ + {0xa0, 0x59, ZC3XX_R01D_HSYNC_0}, /* 00,1d,59,cc */ + {0xa0, 0x90, ZC3XX_R01E_HSYNC_1}, /* 00,1e,90,cc */ + {0xa0, 0xc8, ZC3XX_R01F_HSYNC_2}, /* 00,1f,c8,cc */ + {} +}; + +/* CS2102_KOCOM */ +static const struct usb_action cs2102K_Initial[] = { + {0xa0, 0x11, ZC3XX_R002_CLOCKSELECT}, + {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, + {0xa0, 0x08, ZC3XX_R010_CMOSSENSORSELECT}, + {0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH}, + {0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW}, + {0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH}, + {0xa0, 0xe0, ZC3XX_R006_FRAMEHEIGHTLOW}, + {0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING}, + {0xa0, 0x03, ZC3XX_R012_VIDEOCONTROLFUNC}, + {0xa0, 0x01, ZC3XX_R012_VIDEOCONTROLFUNC}, + {0xa0, 0x00, ZC3XX_R098_WINYSTARTLOW}, + {0xa0, 0x00, ZC3XX_R09A_WINXSTARTLOW}, + {0xa0, 0x00, ZC3XX_R11A_FIRSTYLOW}, + {0xa0, 0x00, ZC3XX_R11C_FIRSTXLOW}, + {0xa0, 0xe8, ZC3XX_R09C_WINHEIGHTLOW}, + {0xa0, 0x88, ZC3XX_R09E_WINWIDTHLOW}, + {0xa0, 0x55, ZC3XX_R08B_I2CDEVICEADDR}, + {0xa0, 0x18, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x00, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x0a, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x02, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x0b, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x02, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x0c, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x7c, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x0d, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0xa3, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x03, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0xfb, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x05, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x00, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x06, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x03, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x09, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x08, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x0e, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x04, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x0f, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x18, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x10, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x18, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x11, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x18, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x12, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x18, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x15, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x00, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x16, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x0c, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x17, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x0c, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x18, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x04, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0xb7, ZC3XX_R101_SENSORCORRECTION}, + {0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC}, + {0xa0, 0x78, ZC3XX_R18D_YTARGET}, + {0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE}, + {0xa0, 0x06, ZC3XX_R189_AWBSTATUS}, + {0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE}, + {0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05}, + {0xa0, 0x20, ZC3XX_R087_EXPTIMEMID}, + {0xa0, 0x21, ZC3XX_R088_EXPTIMELOW}, + {0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE}, + {0xa0, 0x08, ZC3XX_R301_EEPROMACCESS}, + {0xa0, 0x00, 0x01ad}, + {0xa0, 0x01, 0x01b1}, + {0xa0, 0x02, ZC3XX_R180_AUTOCORRECTENABLE}, + {0xa0, 0x60, ZC3XX_R116_RGAIN}, + {0xa0, 0x40, ZC3XX_R117_GGAIN}, + {0xa0, 0x4c, ZC3XX_R118_BGAIN}, + {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, /* clock ? */ + {0xa0, 0x08, ZC3XX_R1C6_SHARPNESS00}, /* sharpness+ */ + {0xa0, 0x0f, ZC3XX_R1CB_SHARPNESS05}, /* sharpness- */ + {0xa0, 0x13, ZC3XX_R120_GAMMA00}, /* gamma 4 */ + {0xa0, 0x38, ZC3XX_R121_GAMMA01}, + {0xa0, 0x59, ZC3XX_R122_GAMMA02}, + {0xa0, 0x79, ZC3XX_R123_GAMMA03}, + {0xa0, 0x92, ZC3XX_R124_GAMMA04}, + {0xa0, 0xa7, ZC3XX_R125_GAMMA05}, + {0xa0, 0xb9, ZC3XX_R126_GAMMA06}, + {0xa0, 0xc8, ZC3XX_R127_GAMMA07}, + {0xa0, 0xd4, ZC3XX_R128_GAMMA08}, + {0xa0, 0xdf, ZC3XX_R129_GAMMA09}, + {0xa0, 0xe7, ZC3XX_R12A_GAMMA0A}, + {0xa0, 0xee, ZC3XX_R12B_GAMMA0B}, + {0xa0, 0xf4, ZC3XX_R12C_GAMMA0C}, + {0xa0, 0xf9, ZC3XX_R12D_GAMMA0D}, + {0xa0, 0xfc, ZC3XX_R12E_GAMMA0E}, + {0xa0, 0xff, ZC3XX_R12F_GAMMA0F}, + {0xa0, 0x26, ZC3XX_R130_GAMMA10}, + {0xa0, 0x22, ZC3XX_R131_GAMMA11}, + {0xa0, 0x20, ZC3XX_R132_GAMMA12}, + {0xa0, 0x1c, ZC3XX_R133_GAMMA13}, + {0xa0, 0x16, ZC3XX_R134_GAMMA14}, + {0xa0, 0x13, ZC3XX_R135_GAMMA15}, + {0xa0, 0x10, ZC3XX_R136_GAMMA16}, + {0xa0, 0x0d, ZC3XX_R137_GAMMA17}, + {0xa0, 0x0b, ZC3XX_R138_GAMMA18}, + {0xa0, 0x09, ZC3XX_R139_GAMMA19}, + {0xa0, 0x07, ZC3XX_R13A_GAMMA1A}, + {0xa0, 0x06, ZC3XX_R13B_GAMMA1B}, + {0xa0, 0x05, ZC3XX_R13C_GAMMA1C}, + {0xa0, 0x04, ZC3XX_R13D_GAMMA1D}, + {0xa0, 0x03, ZC3XX_R13E_GAMMA1E}, + {0xa0, 0x02, ZC3XX_R13F_GAMMA1F}, + {0xa0, 0x58, ZC3XX_R10A_RGB00}, /* matrix */ + {0xa0, 0xf4, ZC3XX_R10B_RGB01}, + {0xa0, 0xf4, ZC3XX_R10C_RGB02}, + {0xa0, 0xf4, ZC3XX_R10D_RGB10}, + {0xa0, 0x58, ZC3XX_R10E_RGB11}, + {0xa0, 0xf4, ZC3XX_R10F_RGB12}, + {0xa0, 0xf4, ZC3XX_R110_RGB20}, + {0xa0, 0xf4, ZC3XX_R111_RGB21}, + {0xa0, 0x58, ZC3XX_R112_RGB22}, + {0xa0, 0x00, ZC3XX_R180_AUTOCORRECTENABLE}, + {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, + {0xa0, 0x18, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x00, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x13, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x22, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x14, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x01, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x20, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x01, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x21, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x22, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x18, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x04, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x01, ZC3XX_R0A3_EXPOSURETIMEHIGH}, + {0xa0, 0x22, ZC3XX_R0A4_EXPOSURETIMELOW}, + {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, + {0xa0, 0x07, ZC3XX_R191_EXPOSURELIMITMID}, + {0xa0, 0xee, ZC3XX_R192_EXPOSURELIMITLOW}, + {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, + {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, + {0xa0, 0x3a, ZC3XX_R197_ANTIFLICKERLOW}, + {0xa0, 0x10, ZC3XX_R18C_AEFREEZE}, + {0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE}, + {0xa0, 0x0c, ZC3XX_R1A9_DIGITALLIMITDIFF}, + {0xa0, 0x28, ZC3XX_R1AA_DIGITALGAINSTEP}, + {0xa0, 0x04, ZC3XX_R01D_HSYNC_0}, + {0xa0, 0x0f, ZC3XX_R01E_HSYNC_1}, + {0xa0, 0x19, ZC3XX_R01F_HSYNC_2}, + {0xa0, 0x1f, ZC3XX_R020_HSYNC_3}, + {0xa0, 0x60, ZC3XX_R11D_GLOBALGAIN}, + {0xa0, 0x60, ZC3XX_R11D_GLOBALGAIN}, + {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE}, + {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE}, + {0xa0, 0x60, ZC3XX_R116_RGAIN}, + {0xa0, 0x40, ZC3XX_R117_GGAIN}, + {0xa0, 0x4c, ZC3XX_R118_BGAIN}, + {0xa0, 0x04, ZC3XX_R1A7_CALCGLOBALMEAN}, + {0xa0, 0x20, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x01, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x21, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x5c, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x18, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x00, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x13, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x5c, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x14, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x01, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x18, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x04, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x00, ZC3XX_R1A7_CALCGLOBALMEAN}, + {0xa0, 0x04, ZC3XX_R1A7_CALCGLOBALMEAN}, + {0xa0, 0x00, ZC3XX_R1A7_CALCGLOBALMEAN}, + {0xa0, 0x04, ZC3XX_R1A7_CALCGLOBALMEAN}, + {0xa0, 0x20, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x01, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x21, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x96, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x18, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x00, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x13, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x96, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x14, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x01, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x18, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x04, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x00, ZC3XX_R1A7_CALCGLOBALMEAN}, + {0xa0, 0x04, ZC3XX_R1A7_CALCGLOBALMEAN}, + {0xa0, 0x00, ZC3XX_R1A7_CALCGLOBALMEAN}, + {} +}; + +static const struct usb_action cs2102K_InitialScale[] = { + {0xa0, 0x11, ZC3XX_R002_CLOCKSELECT}, + {0xa0, 0x00, ZC3XX_R002_CLOCKSELECT}, + {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, + {0xa0, 0x08, ZC3XX_R010_CMOSSENSORSELECT}, + {0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH}, + {0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW}, + {0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH}, + {0xa0, 0xe0, ZC3XX_R006_FRAMEHEIGHTLOW}, + {0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING}, + {0xa0, 0x03, ZC3XX_R012_VIDEOCONTROLFUNC}, + {0xa0, 0x01, ZC3XX_R012_VIDEOCONTROLFUNC}, + {0xa0, 0x00, ZC3XX_R098_WINYSTARTLOW}, + {0xa0, 0x00, ZC3XX_R09A_WINXSTARTLOW}, + {0xa0, 0x00, ZC3XX_R11A_FIRSTYLOW}, + {0xa0, 0x00, ZC3XX_R11C_FIRSTXLOW}, + {0xa0, 0xe8, ZC3XX_R09C_WINHEIGHTLOW}, + {0xa0, 0x88, ZC3XX_R09E_WINWIDTHLOW}, + {0xa0, 0x55, ZC3XX_R08B_I2CDEVICEADDR}, + {0xa0, 0x18, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x00, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x0a, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x02, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x0b, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x02, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x0c, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x7b, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x0d, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0xa3, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x03, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0xfb, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x05, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x00, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x06, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x03, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x09, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x08, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x0e, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x04, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x0f, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x18, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x10, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x18, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x11, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x18, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x12, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x18, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x15, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x00, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x16, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x0c, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x17, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x0c, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x18, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x04, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0xf7, ZC3XX_R101_SENSORCORRECTION}, + {0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC}, + {0xa0, 0x78, ZC3XX_R18D_YTARGET}, + {0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE}, + {0xa0, 0x06, ZC3XX_R189_AWBSTATUS}, + {0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE}, + {0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05}, + {0xa0, 0x20, ZC3XX_R087_EXPTIMEMID}, + {0xa0, 0x21, ZC3XX_R088_EXPTIMELOW}, + {0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE}, + {0xa0, 0x08, ZC3XX_R301_EEPROMACCESS}, + {0xa0, 0x00, 0x01ad}, + {0xa0, 0x01, 0x01b1}, + {0xa0, 0x02, ZC3XX_R180_AUTOCORRECTENABLE}, + {0xa0, 0x60, ZC3XX_R116_RGAIN}, + {0xa0, 0x40, ZC3XX_R117_GGAIN}, + {0xa0, 0x4c, ZC3XX_R118_BGAIN}, + {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, /* clock ? */ + {0xa0, 0x08, ZC3XX_R1C6_SHARPNESS00}, /* sharpness+ */ + {0xa0, 0x0f, ZC3XX_R1CB_SHARPNESS05}, /* sharpness- */ + {0xa0, 0x13, ZC3XX_R120_GAMMA00}, /* gamma 4 */ + {0xa0, 0x38, ZC3XX_R121_GAMMA01}, + {0xa0, 0x59, ZC3XX_R122_GAMMA02}, + {0xa0, 0x79, ZC3XX_R123_GAMMA03}, + {0xa0, 0x92, ZC3XX_R124_GAMMA04}, + {0xa0, 0xa7, ZC3XX_R125_GAMMA05}, + {0xa0, 0xb9, ZC3XX_R126_GAMMA06}, + {0xa0, 0xc8, ZC3XX_R127_GAMMA07}, + {0xa0, 0xd4, ZC3XX_R128_GAMMA08}, + {0xa0, 0xdf, ZC3XX_R129_GAMMA09}, + {0xa0, 0xe7, ZC3XX_R12A_GAMMA0A}, + {0xa0, 0xee, ZC3XX_R12B_GAMMA0B}, + {0xa0, 0xf4, ZC3XX_R12C_GAMMA0C}, + {0xa0, 0xf9, ZC3XX_R12D_GAMMA0D}, + {0xa0, 0xfc, ZC3XX_R12E_GAMMA0E}, + {0xa0, 0xff, ZC3XX_R12F_GAMMA0F}, + {0xa0, 0x26, ZC3XX_R130_GAMMA10}, + {0xa0, 0x22, ZC3XX_R131_GAMMA11}, + {0xa0, 0x20, ZC3XX_R132_GAMMA12}, + {0xa0, 0x1c, ZC3XX_R133_GAMMA13}, + {0xa0, 0x16, ZC3XX_R134_GAMMA14}, + {0xa0, 0x13, ZC3XX_R135_GAMMA15}, + {0xa0, 0x10, ZC3XX_R136_GAMMA16}, + {0xa0, 0x0d, ZC3XX_R137_GAMMA17}, + {0xa0, 0x0b, ZC3XX_R138_GAMMA18}, + {0xa0, 0x09, ZC3XX_R139_GAMMA19}, + {0xa0, 0x07, ZC3XX_R13A_GAMMA1A}, + {0xa0, 0x06, ZC3XX_R13B_GAMMA1B}, + {0xa0, 0x05, ZC3XX_R13C_GAMMA1C}, + {0xa0, 0x04, ZC3XX_R13D_GAMMA1D}, + {0xa0, 0x03, ZC3XX_R13E_GAMMA1E}, + {0xa0, 0x02, ZC3XX_R13F_GAMMA1F}, + {0xa0, 0x58, ZC3XX_R10A_RGB00}, /* matrix */ + {0xa0, 0xf4, ZC3XX_R10B_RGB01}, + {0xa0, 0xf4, ZC3XX_R10C_RGB02}, + {0xa0, 0xf4, ZC3XX_R10D_RGB10}, + {0xa0, 0x58, ZC3XX_R10E_RGB11}, + {0xa0, 0xf4, ZC3XX_R10F_RGB12}, + {0xa0, 0xf4, ZC3XX_R110_RGB20}, + {0xa0, 0xf4, ZC3XX_R111_RGB21}, + {0xa0, 0x58, ZC3XX_R112_RGB22}, + {0xa0, 0x00, ZC3XX_R180_AUTOCORRECTENABLE}, + {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, + {0xa0, 0x18, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x00, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x13, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x22, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x14, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x01, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x20, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x01, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x21, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x22, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x18, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x04, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x01, ZC3XX_R0A3_EXPOSURETIMEHIGH}, + {0xa0, 0x22, ZC3XX_R0A4_EXPOSURETIMELOW}, + {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, + {0xa0, 0x07, ZC3XX_R191_EXPOSURELIMITMID}, + {0xa0, 0xee, ZC3XX_R192_EXPOSURELIMITLOW}, + {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, + {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, + {0xa0, 0x3a, ZC3XX_R197_ANTIFLICKERLOW}, + {0xa0, 0x10, ZC3XX_R18C_AEFREEZE}, + {0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE}, + {0xa0, 0x0c, ZC3XX_R1A9_DIGITALLIMITDIFF}, + {0xa0, 0x28, ZC3XX_R1AA_DIGITALGAINSTEP}, + {0xa0, 0x04, ZC3XX_R01D_HSYNC_0}, + {0xa0, 0x0f, ZC3XX_R01E_HSYNC_1}, + {0xa0, 0x19, ZC3XX_R01F_HSYNC_2}, + {0xa0, 0x1f, ZC3XX_R020_HSYNC_3}, + {0xa0, 0x60, ZC3XX_R11D_GLOBALGAIN}, + {0xa0, 0x60, ZC3XX_R11D_GLOBALGAIN}, + {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE}, + {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE}, + {0xa0, 0x60, ZC3XX_R116_RGAIN}, + {0xa0, 0x40, ZC3XX_R117_GGAIN}, + {0xa0, 0x4c, ZC3XX_R118_BGAIN}, + {0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL}, + {0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL}, + {0xa0, 0x00, ZC3XX_R002_CLOCKSELECT}, + {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, + {0xa0, 0x08, ZC3XX_R010_CMOSSENSORSELECT}, + {0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH}, + {0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW}, + {0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH}, + {0xa0, 0xe0, ZC3XX_R006_FRAMEHEIGHTLOW}, + {0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING}, + {0xa0, 0x03, ZC3XX_R012_VIDEOCONTROLFUNC}, + {0xa0, 0x01, ZC3XX_R012_VIDEOCONTROLFUNC}, + {0xa0, 0x00, ZC3XX_R098_WINYSTARTLOW}, + {0xa0, 0x00, ZC3XX_R09A_WINXSTARTLOW}, + {0xa0, 0x00, ZC3XX_R11A_FIRSTYLOW}, + {0xa0, 0x00, ZC3XX_R11C_FIRSTXLOW}, + {0xa0, 0xe8, ZC3XX_R09C_WINHEIGHTLOW}, + {0xa0, 0x88, ZC3XX_R09E_WINWIDTHLOW}, + {0xa0, 0x55, ZC3XX_R08B_I2CDEVICEADDR}, + {0xa0, 0x18, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x00, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x0A, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x02, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x0B, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x02, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x0C, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x7b, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x0D, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0xA3, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x03, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0xfb, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x05, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x00, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x06, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x03, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x09, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x08, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x0E, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x04, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x0f, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x18, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x10, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x18, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x11, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x18, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x12, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x18, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x15, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x00, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x16, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x0c, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x17, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x0C, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x18, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x04, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0xf7, ZC3XX_R101_SENSORCORRECTION}, + {0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC}, + {0xa0, 0x78, ZC3XX_R18D_YTARGET}, + {0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE}, + {0xa0, 0x06, ZC3XX_R189_AWBSTATUS}, + {0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE}, + {0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05}, + {0xa0, 0x20, ZC3XX_R087_EXPTIMEMID}, + {0xa0, 0x21, ZC3XX_R088_EXPTIMELOW}, + {0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE}, + {0xa0, 0x08, ZC3XX_R301_EEPROMACCESS}, + {0xa0, 0x00, 0x01ad}, + {0xa0, 0x01, 0x01b1}, + {0xa0, 0x02, ZC3XX_R180_AUTOCORRECTENABLE}, + {0xa0, 0x60, ZC3XX_R116_RGAIN}, + {0xa0, 0x40, ZC3XX_R117_GGAIN}, + {0xa0, 0x4c, ZC3XX_R118_BGAIN}, + {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, /* clock ? */ + {0xa0, 0x08, ZC3XX_R1C6_SHARPNESS00}, /* sharpness+ */ + {0xa0, 0x0f, ZC3XX_R1CB_SHARPNESS05}, /* sharpness- */ + {0xa0, 0x13, ZC3XX_R120_GAMMA00}, /* gamma 4 */ + {0xa0, 0x38, ZC3XX_R121_GAMMA01}, + {0xa0, 0x59, ZC3XX_R122_GAMMA02}, + {0xa0, 0x79, ZC3XX_R123_GAMMA03}, + {0xa0, 0x92, ZC3XX_R124_GAMMA04}, + {0xa0, 0xa7, ZC3XX_R125_GAMMA05}, + {0xa0, 0xb9, ZC3XX_R126_GAMMA06}, + {0xa0, 0xc8, ZC3XX_R127_GAMMA07}, + {0xa0, 0xd4, ZC3XX_R128_GAMMA08}, + {0xa0, 0xdf, ZC3XX_R129_GAMMA09}, + {0xa0, 0xe7, ZC3XX_R12A_GAMMA0A}, + {0xa0, 0xee, ZC3XX_R12B_GAMMA0B}, + {0xa0, 0xf4, ZC3XX_R12C_GAMMA0C}, + {0xa0, 0xf9, ZC3XX_R12D_GAMMA0D}, + {0xa0, 0xfc, ZC3XX_R12E_GAMMA0E}, + {0xa0, 0xff, ZC3XX_R12F_GAMMA0F}, + {0xa0, 0x26, ZC3XX_R130_GAMMA10}, + {0xa0, 0x22, ZC3XX_R131_GAMMA11}, + {0xa0, 0x20, ZC3XX_R132_GAMMA12}, + {0xa0, 0x1c, ZC3XX_R133_GAMMA13}, + {0xa0, 0x16, ZC3XX_R134_GAMMA14}, + {0xa0, 0x13, ZC3XX_R135_GAMMA15}, + {0xa0, 0x10, ZC3XX_R136_GAMMA16}, + {0xa0, 0x0d, ZC3XX_R137_GAMMA17}, + {0xa0, 0x0b, ZC3XX_R138_GAMMA18}, + {0xa0, 0x09, ZC3XX_R139_GAMMA19}, + {0xa0, 0x07, ZC3XX_R13A_GAMMA1A}, + {0xa0, 0x06, ZC3XX_R13B_GAMMA1B}, + {0xa0, 0x05, ZC3XX_R13C_GAMMA1C}, + {0xa0, 0x04, ZC3XX_R13D_GAMMA1D}, + {0xa0, 0x03, ZC3XX_R13E_GAMMA1E}, + {0xa0, 0x02, ZC3XX_R13F_GAMMA1F}, + {0xa0, 0x58, ZC3XX_R10A_RGB00}, /* matrix */ + {0xa0, 0xf4, ZC3XX_R10B_RGB01}, + {0xa0, 0xf4, ZC3XX_R10C_RGB02}, + {0xa0, 0xf4, ZC3XX_R10D_RGB10}, + {0xa0, 0x58, ZC3XX_R10E_RGB11}, + {0xa0, 0xf4, ZC3XX_R10F_RGB12}, + {0xa0, 0xf4, ZC3XX_R110_RGB20}, + {0xa0, 0xf4, ZC3XX_R111_RGB21}, + {0xa0, 0x58, ZC3XX_R112_RGB22}, + {0xa0, 0x00, ZC3XX_R180_AUTOCORRECTENABLE}, + {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, + {0xa0, 0x18, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x00, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x13, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x22, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x14, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x01, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x20, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x01, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x21, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x22, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x18, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x04, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x01, ZC3XX_R0A3_EXPOSURETIMEHIGH}, + {0xa0, 0x22, ZC3XX_R0A4_EXPOSURETIMELOW}, + {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, + {0xa0, 0x07, ZC3XX_R191_EXPOSURELIMITMID}, + {0xa0, 0xee, ZC3XX_R192_EXPOSURELIMITLOW}, + {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, + {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, + {0xa0, 0x3a, ZC3XX_R197_ANTIFLICKERLOW}, + {0xa0, 0x10, ZC3XX_R18C_AEFREEZE}, + {0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE}, + {0xa0, 0x0c, ZC3XX_R1A9_DIGITALLIMITDIFF}, + {0xa0, 0x28, ZC3XX_R1AA_DIGITALGAINSTEP}, + {0xa0, 0x04, ZC3XX_R01D_HSYNC_0}, + {0xa0, 0x0f, ZC3XX_R01E_HSYNC_1}, + {0xa0, 0x19, ZC3XX_R01F_HSYNC_2}, + {0xa0, 0x1f, ZC3XX_R020_HSYNC_3}, + {0xa0, 0x60, ZC3XX_R11D_GLOBALGAIN}, + {0xa0, 0x60, ZC3XX_R11D_GLOBALGAIN}, + {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE}, + {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE}, + {0xa0, 0x60, ZC3XX_R116_RGAIN}, + {0xa0, 0x40, ZC3XX_R117_GGAIN}, + {0xa0, 0x4c, ZC3XX_R118_BGAIN}, + {0xa0, 0x04, ZC3XX_R1A7_CALCGLOBALMEAN}, + {0xa0, 0x20, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x01, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x21, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x5c, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x18, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x00, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x13, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x5c, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x14, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x01, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x18, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x04, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x00, ZC3XX_R1A7_CALCGLOBALMEAN}, + {0xa0, 0x04, ZC3XX_R1A7_CALCGLOBALMEAN}, + {0xa0, 0x00, ZC3XX_R1A7_CALCGLOBALMEAN}, + {0xa0, 0x04, ZC3XX_R1A7_CALCGLOBALMEAN}, + {0xa0, 0x20, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x01, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x21, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x96, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x18, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x00, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x13, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x96, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x14, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x01, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x18, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x04, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x00, ZC3XX_R1A7_CALCGLOBALMEAN}, + {0xa0, 0x04, ZC3XX_R1A7_CALCGLOBALMEAN}, + {0xa0, 0x00, ZC3XX_R1A7_CALCGLOBALMEAN}, + {0xa0, 0x04, ZC3XX_R1A7_CALCGLOBALMEAN}, + {0xa0, 0x00, ZC3XX_R1A7_CALCGLOBALMEAN}, + {0xa0, 0x04, ZC3XX_R1A7_CALCGLOBALMEAN}, + {0xa0, 0x20, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x01, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x21, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0xd0, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x18, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x00, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x13, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0xd0, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x14, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x01, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x18, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x04, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x00, ZC3XX_R1A7_CALCGLOBALMEAN}, + {0xa0, 0x02, ZC3XX_R008_CLOCKSETTING}, + {0xa0, 0x04, ZC3XX_R1A7_CALCGLOBALMEAN}, + {0xa0, 0x00, ZC3XX_R1A7_CALCGLOBALMEAN}, + {0xa0, 0x04, ZC3XX_R1A7_CALCGLOBALMEAN}, + {0xa0, 0x20, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x02, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x21, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x0a, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x18, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x00, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x13, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x0a, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x14, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x02, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x18, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x04, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x00, ZC3XX_R1A7_CALCGLOBALMEAN}, + {0xa0, 0x04, ZC3XX_R1A7_CALCGLOBALMEAN}, + {0xa0, 0x00, ZC3XX_R1A7_CALCGLOBALMEAN}, + {0xa0, 0x04, ZC3XX_R1A7_CALCGLOBALMEAN}, + {0xa0, 0x20, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x02, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x21, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x44, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x18, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x00, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x13, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x44, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x14, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x02, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x18, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x04, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x00, ZC3XX_R1A7_CALCGLOBALMEAN}, + {0xa0, 0x04, ZC3XX_R1A7_CALCGLOBALMEAN}, + {0xa0, 0x00, ZC3XX_R1A7_CALCGLOBALMEAN}, + {0xa0, 0x04, ZC3XX_R1A7_CALCGLOBALMEAN}, + {0xa0, 0x20, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x02, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x21, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x7e, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x18, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x00, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x13, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x7e, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x14, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x02, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x18, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x04, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x00, ZC3XX_R1A7_CALCGLOBALMEAN}, + {0xa0, 0x04, ZC3XX_R1A7_CALCGLOBALMEAN}, + {0xa0, 0x00, ZC3XX_R1A7_CALCGLOBALMEAN}, + {0xa0, 0x04, ZC3XX_R1A7_CALCGLOBALMEAN}, + {} +}; + +static const struct usb_action gc0305_Initial[] = { /* 640x480 */ + {0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL}, /* 00,00,01,cc */ + {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, /* 00,08,03,cc */ + {0xa0, 0x01, ZC3XX_R010_CMOSSENSORSELECT}, /* 00,10,01,cc */ + {0xa0, 0x04, ZC3XX_R002_CLOCKSELECT}, /* 00,02,04,cc */ + {0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH}, /* 00,03,02,cc */ + {0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW}, /* 00,04,80,cc */ + {0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH}, /* 00,05,01,cc */ + {0xa0, 0xe0, ZC3XX_R006_FRAMEHEIGHTLOW}, /* 00,06,e0,cc */ + {0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING}, /* 00,01,01,cc */ + {0xa0, 0x03, ZC3XX_R012_VIDEOCONTROLFUNC}, /* 00,12,03,cc */ + {0xa0, 0x01, ZC3XX_R012_VIDEOCONTROLFUNC}, /* 00,12,01,cc */ + {0xa0, 0x00, ZC3XX_R098_WINYSTARTLOW}, /* 00,98,00,cc */ + {0xa0, 0x00, ZC3XX_R09A_WINXSTARTLOW}, /* 00,9a,00,cc */ + {0xa0, 0x00, ZC3XX_R11A_FIRSTYLOW}, /* 01,1a,00,cc */ + {0xa0, 0x00, ZC3XX_R11C_FIRSTXLOW}, /* 01,1c,00,cc */ + {0xa0, 0xe6, ZC3XX_R09C_WINHEIGHTLOW}, /* 00,9c,e6,cc */ + {0xa0, 0x86, ZC3XX_R09E_WINWIDTHLOW}, /* 00,9e,86,cc */ + {0xa0, 0x98, ZC3XX_R08B_I2CDEVICEADDR}, /* 00,8b,98,cc */ + {0xaa, 0x13, 0x0002}, /* 00,13,02,aa */ + {0xaa, 0x15, 0x0003}, /* 00,15,03,aa */ + {0xaa, 0x01, 0x0000}, /* 00,01,00,aa */ + {0xaa, 0x02, 0x0000}, /* 00,02,00,aa */ + {0xaa, 0x1a, 0x0000}, /* 00,1a,00,aa */ + {0xaa, 0x1c, 0x0017}, /* 00,1c,17,aa */ + {0xaa, 0x1d, 0x0080}, /* 00,1d,80,aa */ + {0xaa, 0x1f, 0x0008}, /* 00,1f,08,aa */ + {0xaa, 0x21, 0x0012}, /* 00,21,12,aa */ + {0xa0, 0x82, ZC3XX_R086_EXPTIMEHIGH}, /* 00,86,82,cc */ + {0xa0, 0x83, ZC3XX_R087_EXPTIMEMID}, /* 00,87,83,cc */ + {0xa0, 0x84, ZC3XX_R088_EXPTIMELOW}, /* 00,88,84,cc */ + {0xaa, 0x05, 0x0000}, /* 00,05,00,aa */ + {0xaa, 0x0a, 0x0000}, /* 00,0a,00,aa */ + {0xaa, 0x0b, 0x00b0}, /* 00,0b,b0,aa */ + {0xaa, 0x0c, 0x0000}, /* 00,0c,00,aa */ + {0xaa, 0x0d, 0x00b0}, /* 00,0d,b0,aa */ + {0xaa, 0x0e, 0x0000}, /* 00,0e,00,aa */ + {0xaa, 0x0f, 0x00b0}, /* 00,0f,b0,aa */ + {0xaa, 0x10, 0x0000}, /* 00,10,00,aa */ + {0xaa, 0x11, 0x00b0}, /* 00,11,b0,aa */ + {0xaa, 0x16, 0x0001}, /* 00,16,01,aa */ + {0xaa, 0x17, 0x00e6}, /* 00,17,e6,aa */ + {0xaa, 0x18, 0x0002}, /* 00,18,02,aa */ + {0xaa, 0x19, 0x0086}, /* 00,19,86,aa */ + {0xaa, 0x20, 0x0000}, /* 00,20,00,aa */ + {0xaa, 0x1b, 0x0020}, /* 00,1b,20,aa */ + {0xa0, 0xb7, ZC3XX_R101_SENSORCORRECTION}, /* 01,01,b7,cc */ + {0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC}, /* 00,12,05,cc */ + {0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE}, /* 01,00,0d,cc */ + {0xa0, 0x76, ZC3XX_R189_AWBSTATUS}, /* 01,89,76,cc */ + {0xa0, 0x09, 0x01ad}, /* 01,ad,09,cc */ + {0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE}, /* 01,c5,03,cc */ + {0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05}, /* 01,cb,13,cc */ + {0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE}, /* 02,50,08,cc */ + {0xa0, 0x08, ZC3XX_R301_EEPROMACCESS}, /* 03,01,08,cc */ + {0xa0, 0x60, ZC3XX_R1A8_DIGITALGAIN}, /* 01,a8,60,cc */ + {0xa0, 0x85, ZC3XX_R18D_YTARGET}, /* 01,8d,85,cc */ + {0xa0, 0x00, 0x011e}, /* 01,1e,00,cc */ + {0xa0, 0x52, ZC3XX_R116_RGAIN}, /* 01,16,52,cc */ + {0xa0, 0x40, ZC3XX_R117_GGAIN}, /* 01,17,40,cc */ + {0xa0, 0x52, ZC3XX_R118_BGAIN}, /* 01,18,52,cc */ + {0xa0, 0x03, ZC3XX_R113_RGB03}, /* 01,13,03,cc */ + {} +}; +static const struct usb_action gc0305_InitialScale[] = { /* 320x240 */ + {0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL}, /* 00,00,01,cc */ + {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, /* 00,08,03,cc */ + {0xa0, 0x01, ZC3XX_R010_CMOSSENSORSELECT}, /* 00,10,01,cc */ + {0xa0, 0x10, ZC3XX_R002_CLOCKSELECT}, /* 00,02,10,cc */ + {0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH}, /* 00,03,02,cc */ + {0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW}, /* 00,04,80,cc */ + {0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH}, /* 00,05,01,cc */ + {0xa0, 0xe0, ZC3XX_R006_FRAMEHEIGHTLOW}, /* 00,06,e0,cc */ + {0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING}, /* 00,01,01,cc */ + {0xa0, 0x03, ZC3XX_R012_VIDEOCONTROLFUNC}, /* 00,12,03,cc */ + {0xa0, 0x01, ZC3XX_R012_VIDEOCONTROLFUNC}, /* 00,12,01,cc */ + {0xa0, 0x00, ZC3XX_R098_WINYSTARTLOW}, /* 00,98,00,cc */ + {0xa0, 0x00, ZC3XX_R09A_WINXSTARTLOW}, /* 00,9a,00,cc */ + {0xa0, 0x00, ZC3XX_R11A_FIRSTYLOW}, /* 01,1a,00,cc */ + {0xa0, 0x00, ZC3XX_R11C_FIRSTXLOW}, /* 01,1c,00,cc */ + {0xa0, 0xe8, ZC3XX_R09C_WINHEIGHTLOW}, /* 00,9c,e8,cc */ + {0xa0, 0x88, ZC3XX_R09E_WINWIDTHLOW}, /* 00,9e,88,cc */ + {0xa0, 0x98, ZC3XX_R08B_I2CDEVICEADDR}, /* 00,8b,98,cc */ + {0xaa, 0x13, 0x0000}, /* 00,13,00,aa */ + {0xaa, 0x15, 0x0001}, /* 00,15,01,aa */ + {0xaa, 0x01, 0x0000}, /* 00,01,00,aa */ + {0xaa, 0x02, 0x0000}, /* 00,02,00,aa */ + {0xaa, 0x1a, 0x0000}, /* 00,1a,00,aa */ + {0xaa, 0x1c, 0x0017}, /* 00,1c,17,aa */ + {0xaa, 0x1d, 0x0080}, /* 00,1d,80,aa */ + {0xaa, 0x1f, 0x0008}, /* 00,1f,08,aa */ + {0xaa, 0x21, 0x0012}, /* 00,21,12,aa */ + {0xa0, 0x82, ZC3XX_R086_EXPTIMEHIGH}, /* 00,86,82,cc */ + {0xa0, 0x83, ZC3XX_R087_EXPTIMEMID}, /* 00,87,83,cc */ + {0xa0, 0x84, ZC3XX_R088_EXPTIMELOW}, /* 00,88,84,cc */ + {0xaa, 0x05, 0x0000}, /* 00,05,00,aa */ + {0xaa, 0x0a, 0x0000}, /* 00,0a,00,aa */ + {0xaa, 0x0b, 0x00b0}, /* 00,0b,b0,aa */ + {0xaa, 0x0c, 0x0000}, /* 00,0c,00,aa */ + {0xaa, 0x0d, 0x00b0}, /* 00,0d,b0,aa */ + {0xaa, 0x0e, 0x0000}, /* 00,0e,00,aa */ + {0xaa, 0x0f, 0x00b0}, /* 00,0f,b0,aa */ + {0xaa, 0x10, 0x0000}, /* 00,10,00,aa */ + {0xaa, 0x11, 0x00b0}, /* 00,11,b0,aa */ + {0xaa, 0x16, 0x0001}, /* 00,16,01,aa */ + {0xaa, 0x17, 0x00e8}, /* 00,17,e8,aa */ + {0xaa, 0x18, 0x0002}, /* 00,18,02,aa */ + {0xaa, 0x19, 0x0088}, /* 00,19,88,aa */ + {0xaa, 0x20, 0x0000}, /* 00,20,00,aa */ + {0xaa, 0x1b, 0x0020}, /* 00,1b,20,aa */ + {0xa0, 0xb7, ZC3XX_R101_SENSORCORRECTION}, /* 01,01,b7,cc */ + {0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC}, /* 00,12,05,cc */ + {0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE}, /* 01,00,0d,cc */ + {0xa0, 0x76, ZC3XX_R189_AWBSTATUS}, /* 01,89,76,cc */ + {0xa0, 0x09, 0x01ad}, /* 01,ad,09,cc */ + {0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE}, /* 01,c5,03,cc */ + {0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05}, /* 01,cb,13,cc */ + {0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE}, /* 02,50,08,cc */ + {0xa0, 0x08, ZC3XX_R301_EEPROMACCESS}, /* 03,01,08,cc */ + {0xa0, 0x60, ZC3XX_R1A8_DIGITALGAIN}, /* 01,a8,60,cc */ + {0xa0, 0x00, 0x011e}, /* 01,1e,00,cc */ + {0xa0, 0x52, ZC3XX_R116_RGAIN}, /* 01,16,52,cc */ + {0xa0, 0x40, ZC3XX_R117_GGAIN}, /* 01,17,40,cc */ + {0xa0, 0x52, ZC3XX_R118_BGAIN}, /* 01,18,52,cc */ + {0xa0, 0x03, ZC3XX_R113_RGB03}, /* 01,13,03,cc */ + {} +}; +static const struct usb_action gc0305_50HZ[] = { + {0xaa, 0x82, 0x0000}, /* 00,82,00,aa */ + {0xaa, 0x83, 0x0002}, /* 00,83,02,aa */ + {0xaa, 0x84, 0x0038}, /* 00,84,38,aa */ /* win: 00,84,ec */ + {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc */ + {0xa0, 0x0b, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,0b,cc */ + {0xa0, 0x18, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,18,cc */ + /* win: 01,92,10 */ + {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */ + {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc */ + {0xa0, 0x8e, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,8e,cc */ + /* win: 01,97,ec */ + {0xa0, 0x0e, ZC3XX_R18C_AEFREEZE}, /* 01,8c,0e,cc */ + {0xa0, 0x15, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,15,cc */ + {0xa0, 0x10, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,10,cc */ + {0xa0, 0x24, ZC3XX_R1AA_DIGITALGAINSTEP}, /* 01,aa,24,cc */ + {0xa0, 0x62, ZC3XX_R01D_HSYNC_0}, /* 00,1d,62,cc */ + {0xa0, 0x90, ZC3XX_R01E_HSYNC_1}, /* 00,1e,90,cc */ + {0xa0, 0xc8, ZC3XX_R01F_HSYNC_2}, /* 00,1f,c8,cc */ + {0xa0, 0xff, ZC3XX_R020_HSYNC_3}, /* 00,20,ff,cc */ + {0xa0, 0x60, ZC3XX_R11D_GLOBALGAIN}, /* 01,1d,60,cc */ + {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE}, /* 01,80,42,cc */ +/* {0xa0, 0x85, ZC3XX_R18D_YTARGET}, * 01,8d,85,cc * + * if 640x480 */ + {} +}; +static const struct usb_action gc0305_60HZ[] = { + {0xaa, 0x82, 0x0000}, /* 00,82,00,aa */ + {0xaa, 0x83, 0x0000}, /* 00,83,00,aa */ + {0xaa, 0x84, 0x00ec}, /* 00,84,ec,aa */ + {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc */ + {0xa0, 0x0b, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,0b,cc */ + {0xa0, 0x10, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,10,cc */ + {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */ + {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc */ + {0xa0, 0xec, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,ec,cc */ + {0xa0, 0x0e, ZC3XX_R18C_AEFREEZE}, /* 01,8c,0e,cc */ + {0xa0, 0x15, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,15,cc */ + {0xa0, 0x10, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,10,cc */ + {0xa0, 0x24, ZC3XX_R1AA_DIGITALGAINSTEP}, /* 01,aa,24,cc */ + {0xa0, 0x62, ZC3XX_R01D_HSYNC_0}, /* 00,1d,62,cc */ + {0xa0, 0x90, ZC3XX_R01E_HSYNC_1}, /* 00,1e,90,cc */ + {0xa0, 0xc8, ZC3XX_R01F_HSYNC_2}, /* 00,1f,c8,cc */ + {0xa0, 0xff, ZC3XX_R020_HSYNC_3}, /* 00,20,ff,cc */ + {0xa0, 0x60, ZC3XX_R11D_GLOBALGAIN}, /* 01,1d,60,cc */ + {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE}, /* 01,80,42,cc */ + {0xa0, 0x80, ZC3XX_R18D_YTARGET}, /* 01,8d,80,cc */ + {} +}; + +static const struct usb_action gc0305_NoFliker[] = { + {0xa0, 0x0c, ZC3XX_R100_OPERATIONMODE}, /* 01,00,0c,cc */ + {0xaa, 0x82, 0x0000}, /* 00,82,00,aa */ + {0xaa, 0x83, 0x0000}, /* 00,83,00,aa */ + {0xaa, 0x84, 0x0020}, /* 00,84,20,aa */ + {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc */ + {0xa0, 0x00, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,00,cc */ + {0xa0, 0x48, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,48,cc */ + {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */ + {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc */ + {0xa0, 0x10, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,10,cc */ + {0xa0, 0x0e, ZC3XX_R18C_AEFREEZE}, /* 01,8c,0e,cc */ + {0xa0, 0x15, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,15,cc */ + {0xa0, 0x62, ZC3XX_R01D_HSYNC_0}, /* 00,1d,62,cc */ + {0xa0, 0x90, ZC3XX_R01E_HSYNC_1}, /* 00,1e,90,cc */ + {0xa0, 0xc8, ZC3XX_R01F_HSYNC_2}, /* 00,1f,c8,cc */ + {0xa0, 0xff, ZC3XX_R020_HSYNC_3}, /* 00,20,ff,cc */ + {0xa0, 0x60, ZC3XX_R11D_GLOBALGAIN}, /* 01,1d,60,cc */ + {0xa0, 0x03, ZC3XX_R180_AUTOCORRECTENABLE}, /* 01,80,03,cc */ + {0xa0, 0x80, ZC3XX_R18D_YTARGET}, /* 01,8d,80,cc */ + {} +}; + +/* play poker with registers at your own risk !! */ +static const struct usb_action hdcs2020xx_Initial[] = { + {0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL}, + {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, + {0xa0, 0x0e, ZC3XX_R010_CMOSSENSORSELECT}, + {0xa0, 0x10, ZC3XX_R002_CLOCKSELECT}, + {0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH}, + {0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW}, + {0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH}, + {0xa0, 0xd0, ZC3XX_R006_FRAMEHEIGHTLOW}, + /* D0 ?? E0 did not start */ + {0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING}, + {0xa0, 0x03, ZC3XX_R012_VIDEOCONTROLFUNC}, + {0xa0, 0x01, ZC3XX_R012_VIDEOCONTROLFUNC}, + {0xa0, 0x08, ZC3XX_R08D_COMPABILITYMODE}, + {0xa0, 0x08, ZC3XX_R098_WINYSTARTLOW}, + {0xa0, 0x02, ZC3XX_R09A_WINXSTARTLOW}, + {0xa0, 0x08, ZC3XX_R11A_FIRSTYLOW}, + {0xa0, 0x02, ZC3XX_R11C_FIRSTXLOW}, + {0xa0, 0x01, ZC3XX_R09B_WINHEIGHTHIGH}, + {0xa0, 0xd8, ZC3XX_R09C_WINHEIGHTLOW}, + {0xa0, 0x02, ZC3XX_R09D_WINWIDTHHIGH}, + {0xa0, 0x88, ZC3XX_R09E_WINWIDTHLOW}, + {0xaa, 0x02, 0x0002}, + {0xaa, 0x07, 0x0006}, + {0xaa, 0x08, 0x0002}, + {0xaa, 0x09, 0x0006}, + {0xaa, 0x0a, 0x0001}, + {0xaa, 0x0b, 0x0001}, + {0xaa, 0x0c, 0x0008}, + {0xaa, 0x0d, 0x0000}, + {0xaa, 0x10, 0x0000}, + {0xaa, 0x12, 0x0005}, + {0xaa, 0x13, 0x0063}, + {0xaa, 0x15, 0x0070}, + {0xa0, 0x37, ZC3XX_R101_SENSORCORRECTION}, + {0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE}, + {0xa0, 0x06, ZC3XX_R189_AWBSTATUS}, + {0xa0, 0x00, 0x01ad}, + {0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE}, + {0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05}, + {0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE}, + {0xa0, 0x08, ZC3XX_R301_EEPROMACCESS}, + {0xa0, 0x70, ZC3XX_R18D_YTARGET}, + {0xa1, 0x01, 0x0002}, + {0xa1, 0x01, 0x0008}, + {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, /* clock ? */ + {0xa0, 0x04, ZC3XX_R1C6_SHARPNESS00}, /* sharpness+ */ + {0xa1, 0x01, 0x01c8}, + {0xa1, 0x01, 0x01c9}, + {0xa1, 0x01, 0x01ca}, + {0xa0, 0x07, ZC3XX_R1CB_SHARPNESS05}, /* sharpness- */ + {0xa0, 0x11, ZC3XX_R120_GAMMA00}, /* gamma ~4 */ + {0xa0, 0x37, ZC3XX_R121_GAMMA01}, + {0xa0, 0x58, ZC3XX_R122_GAMMA02}, + {0xa0, 0x79, ZC3XX_R123_GAMMA03}, + {0xa0, 0x91, ZC3XX_R124_GAMMA04}, + {0xa0, 0xa6, ZC3XX_R125_GAMMA05}, + {0xa0, 0xb8, ZC3XX_R126_GAMMA06}, + {0xa0, 0xc7, ZC3XX_R127_GAMMA07}, + {0xa0, 0xd3, ZC3XX_R128_GAMMA08}, + {0xa0, 0xde, ZC3XX_R129_GAMMA09}, + {0xa0, 0xe6, ZC3XX_R12A_GAMMA0A}, + {0xa0, 0xed, ZC3XX_R12B_GAMMA0B}, + {0xa0, 0xf3, ZC3XX_R12C_GAMMA0C}, + {0xa0, 0xf8, ZC3XX_R12D_GAMMA0D}, + {0xa0, 0xfb, ZC3XX_R12E_GAMMA0E}, + {0xa0, 0xff, ZC3XX_R12F_GAMMA0F}, + {0xa0, 0x26, ZC3XX_R130_GAMMA10}, + {0xa0, 0x23, ZC3XX_R131_GAMMA11}, + {0xa0, 0x20, ZC3XX_R132_GAMMA12}, + {0xa0, 0x1c, ZC3XX_R133_GAMMA13}, + {0xa0, 0x16, ZC3XX_R134_GAMMA14}, + {0xa0, 0x13, ZC3XX_R135_GAMMA15}, + {0xa0, 0x10, ZC3XX_R136_GAMMA16}, + {0xa0, 0x0d, ZC3XX_R137_GAMMA17}, + {0xa0, 0x0b, ZC3XX_R138_GAMMA18}, + {0xa0, 0x09, ZC3XX_R139_GAMMA19}, + {0xa0, 0x07, ZC3XX_R13A_GAMMA1A}, + {0xa0, 0x06, ZC3XX_R13B_GAMMA1B}, + {0xa0, 0x05, ZC3XX_R13C_GAMMA1C}, + {0xa0, 0x04, ZC3XX_R13D_GAMMA1D}, + {0xa0, 0x03, ZC3XX_R13E_GAMMA1E}, + {0xa0, 0x02, ZC3XX_R13F_GAMMA1F}, + + {0xa0, 0x4c, ZC3XX_R10A_RGB00}, /* matrix */ + {0xa0, 0xf5, ZC3XX_R10B_RGB01}, + {0xa0, 0xff, ZC3XX_R10C_RGB02}, + {0xa0, 0xf9, ZC3XX_R10D_RGB10}, + {0xa0, 0x51, ZC3XX_R10E_RGB11}, + {0xa0, 0xf5, ZC3XX_R10F_RGB12}, + {0xa0, 0xfb, ZC3XX_R110_RGB20}, + {0xa0, 0xed, ZC3XX_R111_RGB21}, + {0xa0, 0x5f, ZC3XX_R112_RGB22}, + + {0xa1, 0x01, 0x0180}, + {0xa0, 0x00, ZC3XX_R180_AUTOCORRECTENABLE}, + {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, + {0xa0, 0x20, ZC3XX_R087_EXPTIMEMID}, + {0xa0, 0x21, ZC3XX_R088_EXPTIMELOW}, + {0xaa, 0x20, 0x0004}, + {0xaa, 0x21, 0x003d}, + {0xaa, 0x03, 0x0041}, + {0xaa, 0x04, 0x0010}, + {0xaa, 0x05, 0x003d}, + {0xaa, 0x0e, 0x0001}, + {0xaa, 0x0f, 0x0000}, + {0xa0, 0x14, ZC3XX_R1A9_DIGITALLIMITDIFF}, + {0xa0, 0x24, ZC3XX_R1AA_DIGITALGAINSTEP}, + {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, + {0xa0, 0x04, ZC3XX_R191_EXPOSURELIMITMID}, + {0xa0, 0x3d, ZC3XX_R192_EXPOSURELIMITLOW}, + {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, + {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, + {0xa0, 0x9b, ZC3XX_R197_ANTIFLICKERLOW}, + {0xa0, 0x10, ZC3XX_R18C_AEFREEZE}, + {0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE}, + {0xa0, 0x41, ZC3XX_R01D_HSYNC_0}, + {0xa0, 0x6f, ZC3XX_R01E_HSYNC_1}, + {0xa0, 0xad, ZC3XX_R01F_HSYNC_2}, + {0xa0, 0xff, ZC3XX_R020_HSYNC_3}, + {0xa0, 0x0f, ZC3XX_R087_EXPTIMEMID}, + {0xa0, 0x0e, ZC3XX_R088_EXPTIMELOW}, + {0xa0, 0x40, ZC3XX_R180_AUTOCORRECTENABLE}, + {0xa1, 0x01, 0x0195}, + {0xa1, 0x01, 0x0196}, + {0xa1, 0x01, 0x0197}, + {0xa0, 0x3d, ZC3XX_R192_EXPOSURELIMITLOW}, + {0xa0, 0x04, ZC3XX_R191_EXPOSURELIMITMID}, + {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, + {0xa0, 0x1d, ZC3XX_R116_RGAIN}, + {0xa0, 0x40, ZC3XX_R117_GGAIN}, + {0xa0, 0x85, ZC3XX_R118_BGAIN}, + {0xa1, 0x01, 0x0116}, + {0xa1, 0x01, 0x0118}, + {0xa1, 0x01, 0x0180}, + {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE}, + {0xa0, 0x1d, ZC3XX_R116_RGAIN}, + {0xa0, 0x40, ZC3XX_R117_GGAIN}, + {0xa0, 0x85, ZC3XX_R118_BGAIN}, + {0xa1, 0x01, 0x0116}, + {0xa1, 0x01, 0x0118}, +/* {0xa0, 0x02, ZC3XX_R008_CLOCKSETTING}, */ + {0xa0, 0x00, 0x0007}, + {} +}; + +static const struct usb_action hdcs2020xx_InitialScale[] = { + {0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL}, + {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, + {0xa0, 0x0e, ZC3XX_R010_CMOSSENSORSELECT}, + {0xa0, 0x00, ZC3XX_R002_CLOCKSELECT}, + {0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH}, + {0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW}, + {0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH}, + {0xa0, 0xe0, ZC3XX_R006_FRAMEHEIGHTLOW}, + {0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING}, + {0xa0, 0x03, ZC3XX_R012_VIDEOCONTROLFUNC}, + {0xa0, 0x01, ZC3XX_R012_VIDEOCONTROLFUNC}, + {0xa0, 0x08, ZC3XX_R08D_COMPABILITYMODE}, + {0xa0, 0x00, ZC3XX_R098_WINYSTARTLOW}, + {0xa0, 0x03, ZC3XX_R09A_WINXSTARTLOW}, + {0xa0, 0x00, ZC3XX_R11A_FIRSTYLOW}, + {0xa0, 0x03, ZC3XX_R11C_FIRSTXLOW}, + {0xa0, 0x01, ZC3XX_R09B_WINHEIGHTHIGH}, + {0xa0, 0xe6, ZC3XX_R09C_WINHEIGHTLOW}, + {0xa0, 0x02, ZC3XX_R09D_WINWIDTHHIGH}, + {0xa0, 0x86, ZC3XX_R09E_WINWIDTHLOW}, + {0xaa, 0x02, 0x0002}, + {0xaa, 0x07, 0x0006}, + {0xaa, 0x08, 0x0002}, + {0xaa, 0x09, 0x0006}, + {0xaa, 0x0a, 0x0001}, + {0xaa, 0x0b, 0x0001}, + {0xaa, 0x0c, 0x0008}, + {0xaa, 0x0d, 0x0000}, + {0xaa, 0x10, 0x0000}, + {0xaa, 0x12, 0x0005}, + {0xaa, 0x13, 0x0063}, + {0xaa, 0x15, 0x0070}, + {0xa0, 0xb7, ZC3XX_R101_SENSORCORRECTION}, + {0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE}, + {0xa0, 0x06, ZC3XX_R189_AWBSTATUS}, + {0xa0, 0x00, 0x01ad}, + {0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE}, + {0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05}, + {0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE}, + {0xa0, 0x08, ZC3XX_R301_EEPROMACCESS}, + {0xa0, 0x70, ZC3XX_R18D_YTARGET}, + {0xa1, 0x01, 0x0002}, + {0xa1, 0x01, 0x0008}, + {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, /* clock ? */ + {0xa0, 0x04, ZC3XX_R1C6_SHARPNESS00}, /* sharpness+ */ + {0xa1, 0x01, 0x01c8}, + {0xa1, 0x01, 0x01c9}, + {0xa1, 0x01, 0x01ca}, + {0xa0, 0x07, ZC3XX_R1CB_SHARPNESS05}, /* sharpness- */ + {0xa0, 0x11, ZC3XX_R120_GAMMA00}, /* gamma ~4*/ + {0xa0, 0x37, ZC3XX_R121_GAMMA01}, + {0xa0, 0x58, ZC3XX_R122_GAMMA02}, + {0xa0, 0x79, ZC3XX_R123_GAMMA03}, + {0xa0, 0x91, ZC3XX_R124_GAMMA04}, + {0xa0, 0xa6, ZC3XX_R125_GAMMA05}, + {0xa0, 0xb8, ZC3XX_R126_GAMMA06}, + {0xa0, 0xc7, ZC3XX_R127_GAMMA07}, + {0xa0, 0xd3, ZC3XX_R128_GAMMA08}, + {0xa0, 0xde, ZC3XX_R129_GAMMA09}, + {0xa0, 0xe6, ZC3XX_R12A_GAMMA0A}, + {0xa0, 0xed, ZC3XX_R12B_GAMMA0B}, + {0xa0, 0xf3, ZC3XX_R12C_GAMMA0C}, + {0xa0, 0xf8, ZC3XX_R12D_GAMMA0D}, + {0xa0, 0xfb, ZC3XX_R12E_GAMMA0E}, + {0xa0, 0xff, ZC3XX_R12F_GAMMA0F}, + {0xa0, 0x26, ZC3XX_R130_GAMMA10}, + {0xa0, 0x23, ZC3XX_R131_GAMMA11}, + {0xa0, 0x20, ZC3XX_R132_GAMMA12}, + {0xa0, 0x1c, ZC3XX_R133_GAMMA13}, + {0xa0, 0x16, ZC3XX_R134_GAMMA14}, + {0xa0, 0x13, ZC3XX_R135_GAMMA15}, + {0xa0, 0x10, ZC3XX_R136_GAMMA16}, + {0xa0, 0x0d, ZC3XX_R137_GAMMA17}, + {0xa0, 0x0b, ZC3XX_R138_GAMMA18}, + {0xa0, 0x09, ZC3XX_R139_GAMMA19}, + {0xa0, 0x07, ZC3XX_R13A_GAMMA1A}, + {0xa0, 0x06, ZC3XX_R13B_GAMMA1B}, + {0xa0, 0x05, ZC3XX_R13C_GAMMA1C}, + {0xa0, 0x04, ZC3XX_R13D_GAMMA1D}, + {0xa0, 0x03, ZC3XX_R13E_GAMMA1E}, + {0xa0, 0x02, ZC3XX_R13F_GAMMA1F}, + {0xa0, 0x60, ZC3XX_R10A_RGB00}, /* matrix */ + {0xa0, 0xff, ZC3XX_R10B_RGB01}, + {0xa0, 0xff, ZC3XX_R10C_RGB02}, + {0xa0, 0xff, ZC3XX_R10D_RGB10}, + {0xa0, 0x60, ZC3XX_R10E_RGB11}, + {0xa0, 0xff, ZC3XX_R10F_RGB12}, + {0xa0, 0xff, ZC3XX_R110_RGB20}, + {0xa0, 0xff, ZC3XX_R111_RGB21}, + {0xa0, 0x60, ZC3XX_R112_RGB22}, + + {0xa1, 0x01, 0x0180}, + {0xa0, 0x00, ZC3XX_R180_AUTOCORRECTENABLE}, + {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, + {0xa0, 0x20, ZC3XX_R087_EXPTIMEMID}, + {0xa0, 0x21, ZC3XX_R088_EXPTIMELOW}, + {0xaa, 0x20, 0x0002}, + {0xaa, 0x21, 0x001b}, + {0xaa, 0x03, 0x0044}, + {0xaa, 0x04, 0x0008}, + {0xaa, 0x05, 0x001b}, + {0xaa, 0x0e, 0x0001}, + {0xaa, 0x0f, 0x0000}, + {0xa0, 0x14, ZC3XX_R1A9_DIGITALLIMITDIFF}, + {0xa0, 0x24, ZC3XX_R1AA_DIGITALGAINSTEP}, + {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, + {0xa0, 0x02, ZC3XX_R191_EXPOSURELIMITMID}, + {0xa0, 0x1b, ZC3XX_R192_EXPOSURELIMITLOW}, + {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, + {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, + {0xa0, 0x4d, ZC3XX_R197_ANTIFLICKERLOW}, + {0xa0, 0x10, ZC3XX_R18C_AEFREEZE}, + {0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE}, + {0xa0, 0x44, ZC3XX_R01D_HSYNC_0}, + {0xa0, 0x6f, ZC3XX_R01E_HSYNC_1}, + {0xa0, 0xad, ZC3XX_R01F_HSYNC_2}, + {0xa0, 0xeb, ZC3XX_R020_HSYNC_3}, + {0xa0, 0x0f, ZC3XX_R087_EXPTIMEMID}, + {0xa0, 0x0e, ZC3XX_R088_EXPTIMELOW}, + {0xa0, 0x40, ZC3XX_R180_AUTOCORRECTENABLE}, + {0xa1, 0x01, 0x0195}, + {0xa1, 0x01, 0x0196}, + {0xa1, 0x01, 0x0197}, + {0xa0, 0x1b, ZC3XX_R192_EXPOSURELIMITLOW}, + {0xa0, 0x02, ZC3XX_R191_EXPOSURELIMITMID}, + {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, + {0xa0, 0x1d, ZC3XX_R116_RGAIN}, + {0xa0, 0x40, ZC3XX_R117_GGAIN}, + {0xa0, 0x99, ZC3XX_R118_BGAIN}, + {0xa1, 0x01, 0x0116}, + {0xa1, 0x01, 0x0118}, + {0xa1, 0x01, 0x0180}, + {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE}, + {0xa0, 0x1d, ZC3XX_R116_RGAIN}, + {0xa0, 0x40, ZC3XX_R117_GGAIN}, + {0xa0, 0x99, ZC3XX_R118_BGAIN}, +/* {0xa0, 0x02, ZC3XX_R008_CLOCKSETTING}, */ + {0xa0, 0x00, 0x0007}, +/* {0xa0, 0x18, 0x00fe}, */ + {} +}; +static const struct usb_action hdcs2020xb_Initial[] = { + {0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL}, + {0xa0, 0x11, ZC3XX_R002_CLOCKSELECT}, + {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, /* qtable 0x05 */ + {0xa0, 0x08, ZC3XX_R010_CMOSSENSORSELECT}, + {0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH}, + {0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW}, + {0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH}, + {0xa0, 0xe0, ZC3XX_R006_FRAMEHEIGHTLOW}, + {0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING}, + {0xa0, 0x03, ZC3XX_R012_VIDEOCONTROLFUNC}, + {0xa0, 0x01, ZC3XX_R012_VIDEOCONTROLFUNC}, + {0xa0, 0x00, ZC3XX_R098_WINYSTARTLOW}, + {0xa0, 0x00, ZC3XX_R09A_WINXSTARTLOW}, + {0xa0, 0x00, ZC3XX_R11A_FIRSTYLOW}, + {0xa0, 0x00, ZC3XX_R11C_FIRSTXLOW}, + {0xa0, 0xe8, ZC3XX_R09C_WINHEIGHTLOW}, + {0xa0, 0x88, ZC3XX_R09E_WINWIDTHLOW}, + {0xaa, 0x1c, 0x0000}, + {0xaa, 0x0a, 0x0001}, + {0xaa, 0x0b, 0x0006}, + {0xaa, 0x0c, 0x007b}, + {0xaa, 0x0d, 0x00a7}, + {0xaa, 0x03, 0x00fb}, + {0xaa, 0x05, 0x0000}, + {0xaa, 0x06, 0x0003}, + {0xaa, 0x09, 0x0008}, + + {0xaa, 0x0f, 0x0018}, /* set sensor gain */ + {0xaa, 0x10, 0x0018}, + {0xaa, 0x11, 0x0018}, + {0xaa, 0x12, 0x0018}, + + {0xaa, 0x15, 0x004e}, + {0xaa, 0x1c, 0x0004}, + {0xa0, 0xb7, ZC3XX_R101_SENSORCORRECTION}, + {0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC}, + {0xa0, 0x70, ZC3XX_R18D_YTARGET}, + {0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE}, + {0xa0, 0x06, ZC3XX_R189_AWBSTATUS}, + {0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE}, + {0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05}, + {0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE}, + {0xa0, 0x08, ZC3XX_R301_EEPROMACCESS}, + {0xa1, 0x01, 0x0002}, + {0xa1, 0x01, 0x0008}, + {0xa1, 0x01, 0x0180}, + {0xa0, 0x02, ZC3XX_R180_AUTOCORRECTENABLE}, + {0xa0, 0x40, ZC3XX_R116_RGAIN}, + {0xa0, 0x40, ZC3XX_R117_GGAIN}, + {0xa0, 0x40, ZC3XX_R118_BGAIN}, + {0xa1, 0x01, 0x0008}, + {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, /* clock ? */ + {0xa0, 0x08, ZC3XX_R1C6_SHARPNESS00}, /* sharpness+ */ + {0xa1, 0x01, 0x01c8}, + {0xa1, 0x01, 0x01c9}, + {0xa1, 0x01, 0x01ca}, + {0xa0, 0x0f, ZC3XX_R1CB_SHARPNESS05}, /* sharpness- */ + {0xa0, 0x13, ZC3XX_R120_GAMMA00}, /* gamma 4 */ + {0xa0, 0x38, ZC3XX_R121_GAMMA01}, + {0xa0, 0x59, ZC3XX_R122_GAMMA02}, + {0xa0, 0x79, ZC3XX_R123_GAMMA03}, + {0xa0, 0x92, ZC3XX_R124_GAMMA04}, + {0xa0, 0xa7, ZC3XX_R125_GAMMA05}, + {0xa0, 0xb9, ZC3XX_R126_GAMMA06}, + {0xa0, 0xc8, ZC3XX_R127_GAMMA07}, + {0xa0, 0xd4, ZC3XX_R128_GAMMA08}, + {0xa0, 0xdf, ZC3XX_R129_GAMMA09}, + {0xa0, 0xe7, ZC3XX_R12A_GAMMA0A}, + {0xa0, 0xee, ZC3XX_R12B_GAMMA0B}, + {0xa0, 0xf4, ZC3XX_R12C_GAMMA0C}, + {0xa0, 0xf9, ZC3XX_R12D_GAMMA0D}, + {0xa0, 0xfc, ZC3XX_R12E_GAMMA0E}, + {0xa0, 0xff, ZC3XX_R12F_GAMMA0F}, + {0xa0, 0x26, ZC3XX_R130_GAMMA10}, + {0xa0, 0x22, ZC3XX_R131_GAMMA11}, + {0xa0, 0x20, ZC3XX_R132_GAMMA12}, + {0xa0, 0x1c, ZC3XX_R133_GAMMA13}, + {0xa0, 0x16, ZC3XX_R134_GAMMA14}, + {0xa0, 0x13, ZC3XX_R135_GAMMA15}, + {0xa0, 0x10, ZC3XX_R136_GAMMA16}, + {0xa0, 0x0d, ZC3XX_R137_GAMMA17}, + {0xa0, 0x0b, ZC3XX_R138_GAMMA18}, + {0xa0, 0x09, ZC3XX_R139_GAMMA19}, + {0xa0, 0x07, ZC3XX_R13A_GAMMA1A}, + {0xa0, 0x06, ZC3XX_R13B_GAMMA1B}, + {0xa0, 0x05, ZC3XX_R13C_GAMMA1C}, + {0xa0, 0x04, ZC3XX_R13D_GAMMA1D}, + {0xa0, 0x03, ZC3XX_R13E_GAMMA1E}, + {0xa0, 0x02, ZC3XX_R13F_GAMMA1F}, + + {0xa0, 0x66, ZC3XX_R10A_RGB00}, /* matrix */ + {0xa0, 0xed, ZC3XX_R10B_RGB01}, + {0xa0, 0xed, ZC3XX_R10C_RGB02}, + {0xa0, 0xed, ZC3XX_R10D_RGB10}, + {0xa0, 0x66, ZC3XX_R10E_RGB11}, + {0xa0, 0xed, ZC3XX_R10F_RGB12}, + {0xa0, 0xed, ZC3XX_R110_RGB20}, + {0xa0, 0xed, ZC3XX_R111_RGB21}, + {0xa0, 0x66, ZC3XX_R112_RGB22}, + + {0xa1, 0x01, 0x0180}, + {0xa0, 0x00, ZC3XX_R180_AUTOCORRECTENABLE}, + {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, + {0xaa, 0x13, 0x0031}, + {0xaa, 0x14, 0x0001}, + {0xaa, 0x0e, 0x0004}, + {0xaa, 0x19, 0x00cd}, + {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, + {0xa0, 0x02, ZC3XX_R191_EXPOSURELIMITMID}, + {0xa0, 0x62, ZC3XX_R192_EXPOSURELIMITLOW}, + {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, + {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, + {0xa0, 0x3d, ZC3XX_R197_ANTIFLICKERLOW}, + {0xa0, 0x10, ZC3XX_R18C_AEFREEZE}, + {0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE}, + + {0xa0, 0x0c, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 0x14 */ + {0xa0, 0x28, ZC3XX_R1AA_DIGITALGAINSTEP}, + {0xa0, 0x04, ZC3XX_R01D_HSYNC_0}, + {0xa0, 0x18, ZC3XX_R01E_HSYNC_1}, + {0xa0, 0x2c, ZC3XX_R01F_HSYNC_2}, + {0xa0, 0x41, ZC3XX_R020_HSYNC_3}, + {0xa0, 0x60, ZC3XX_R11D_GLOBALGAIN}, + {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE}, + {0xa1, 0x01, 0x0180}, + {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE}, + {0xa0, 0x40, ZC3XX_R116_RGAIN}, + {0xa0, 0x40, ZC3XX_R117_GGAIN}, + {0xa0, 0x40, ZC3XX_R118_BGAIN}, + {} +}; +static const struct usb_action hdcs2020xb_InitialScale[] = { + {0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL}, + {0xa0, 0x00, ZC3XX_R002_CLOCKSELECT}, + {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, + {0xa0, 0x08, ZC3XX_R010_CMOSSENSORSELECT}, + {0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH}, + {0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW}, + {0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH}, + {0xa0, 0xe0, ZC3XX_R006_FRAMEHEIGHTLOW}, + {0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING}, + {0xa0, 0x03, ZC3XX_R012_VIDEOCONTROLFUNC}, + {0xa0, 0x01, ZC3XX_R012_VIDEOCONTROLFUNC}, + {0xa0, 0x00, ZC3XX_R098_WINYSTARTLOW}, + {0xa0, 0x00, ZC3XX_R09A_WINXSTARTLOW}, + {0xa0, 0x00, ZC3XX_R11A_FIRSTYLOW}, + {0xa0, 0x00, ZC3XX_R11C_FIRSTXLOW}, + {0xa0, 0xe8, ZC3XX_R09C_WINHEIGHTLOW}, + {0xa0, 0x88, ZC3XX_R09E_WINWIDTHLOW}, + {0xaa, 0x1c, 0x0000}, + {0xaa, 0x0a, 0x0001}, + {0xaa, 0x0b, 0x0006}, + {0xaa, 0x0c, 0x007a}, + {0xaa, 0x0d, 0x00a7}, + {0xaa, 0x03, 0x00fb}, + {0xaa, 0x05, 0x0000}, + {0xaa, 0x06, 0x0003}, + {0xaa, 0x09, 0x0008}, + {0xaa, 0x0f, 0x0018}, /* original setting */ + {0xaa, 0x10, 0x0018}, + {0xaa, 0x11, 0x0018}, + {0xaa, 0x12, 0x0018}, + {0xaa, 0x15, 0x004e}, + {0xaa, 0x1c, 0x0004}, + {0xa0, 0xf7, ZC3XX_R101_SENSORCORRECTION}, + {0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC}, + {0xa0, 0x70, ZC3XX_R18D_YTARGET}, + {0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE}, + {0xa0, 0x06, ZC3XX_R189_AWBSTATUS}, + {0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE}, + {0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05}, + {0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE}, + {0xa0, 0x08, ZC3XX_R301_EEPROMACCESS}, + {0xa1, 0x01, 0x0002}, + {0xa1, 0x01, 0x0008}, + {0xa1, 0x01, 0x0180}, + {0xa0, 0x02, ZC3XX_R180_AUTOCORRECTENABLE}, + {0xa0, 0x40, ZC3XX_R116_RGAIN}, + {0xa0, 0x40, ZC3XX_R117_GGAIN}, + {0xa0, 0x40, ZC3XX_R118_BGAIN}, + {0xa1, 0x01, 0x0008}, + {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, /* clock ? */ + {0xa0, 0x08, ZC3XX_R1C6_SHARPNESS00}, /* sharpness+ */ + {0xa1, 0x01, 0x01c8}, + {0xa1, 0x01, 0x01c9}, + {0xa1, 0x01, 0x01ca}, + {0xa0, 0x0f, ZC3XX_R1CB_SHARPNESS05}, /* sharpness- */ + {0xa0, 0x13, ZC3XX_R120_GAMMA00}, /* gamma 4 */ + {0xa0, 0x38, ZC3XX_R121_GAMMA01}, + {0xa0, 0x59, ZC3XX_R122_GAMMA02}, + {0xa0, 0x79, ZC3XX_R123_GAMMA03}, + {0xa0, 0x92, ZC3XX_R124_GAMMA04}, + {0xa0, 0xa7, ZC3XX_R125_GAMMA05}, + {0xa0, 0xb9, ZC3XX_R126_GAMMA06}, + {0xa0, 0xc8, ZC3XX_R127_GAMMA07}, + {0xa0, 0xd4, ZC3XX_R128_GAMMA08}, + {0xa0, 0xdf, ZC3XX_R129_GAMMA09}, + {0xa0, 0xe7, ZC3XX_R12A_GAMMA0A}, + {0xa0, 0xee, ZC3XX_R12B_GAMMA0B}, + {0xa0, 0xf4, ZC3XX_R12C_GAMMA0C}, + {0xa0, 0xf9, ZC3XX_R12D_GAMMA0D}, + {0xa0, 0xfc, ZC3XX_R12E_GAMMA0E}, + {0xa0, 0xff, ZC3XX_R12F_GAMMA0F}, + {0xa0, 0x26, ZC3XX_R130_GAMMA10}, + {0xa0, 0x22, ZC3XX_R131_GAMMA11}, + {0xa0, 0x20, ZC3XX_R132_GAMMA12}, + {0xa0, 0x1c, ZC3XX_R133_GAMMA13}, + {0xa0, 0x16, ZC3XX_R134_GAMMA14}, + {0xa0, 0x13, ZC3XX_R135_GAMMA15}, + {0xa0, 0x10, ZC3XX_R136_GAMMA16}, + {0xa0, 0x0d, ZC3XX_R137_GAMMA17}, + {0xa0, 0x0b, ZC3XX_R138_GAMMA18}, + {0xa0, 0x09, ZC3XX_R139_GAMMA19}, + {0xa0, 0x07, ZC3XX_R13A_GAMMA1A}, + {0xa0, 0x06, ZC3XX_R13B_GAMMA1B}, + {0xa0, 0x05, ZC3XX_R13C_GAMMA1C}, + {0xa0, 0x04, ZC3XX_R13D_GAMMA1D}, + {0xa0, 0x03, ZC3XX_R13E_GAMMA1E}, + {0xa0, 0x02, ZC3XX_R13F_GAMMA1F}, + {0xa0, 0x66, ZC3XX_R10A_RGB00}, /* matrix */ + {0xa0, 0xed, ZC3XX_R10B_RGB01}, + {0xa0, 0xed, ZC3XX_R10C_RGB02}, + {0xa0, 0xed, ZC3XX_R10D_RGB10}, + {0xa0, 0x66, ZC3XX_R10E_RGB11}, + {0xa0, 0xed, ZC3XX_R10F_RGB12}, + {0xa0, 0xed, ZC3XX_R110_RGB20}, + {0xa0, 0xed, ZC3XX_R111_RGB21}, + {0xa0, 0x66, ZC3XX_R112_RGB22}, + {0xa1, 0x01, 0x0180}, + {0xa0, 0x00, ZC3XX_R180_AUTOCORRECTENABLE}, + {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, + /**** set exposure ***/ + {0xaa, 0x13, 0x0031}, + {0xaa, 0x14, 0x0001}, + {0xaa, 0x0e, 0x0004}, + {0xaa, 0x19, 0x00cd}, + {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, + {0xa0, 0x02, ZC3XX_R191_EXPOSURELIMITMID}, + {0xa0, 0x62, ZC3XX_R192_EXPOSURELIMITLOW}, + {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, + {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, + {0xa0, 0x3d, ZC3XX_R197_ANTIFLICKERLOW}, + {0xa0, 0x10, ZC3XX_R18C_AEFREEZE}, + {0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE}, + {0xa0, 0x0c, ZC3XX_R1A9_DIGITALLIMITDIFF}, + {0xa0, 0x28, ZC3XX_R1AA_DIGITALGAINSTEP}, + {0xa0, 0x04, ZC3XX_R01D_HSYNC_0}, + {0xa0, 0x18, ZC3XX_R01E_HSYNC_1}, + {0xa0, 0x2c, ZC3XX_R01F_HSYNC_2}, + {0xa0, 0x41, ZC3XX_R020_HSYNC_3}, + {0xa0, 0x60, ZC3XX_R11D_GLOBALGAIN}, + {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE}, + {0xa1, 0x01, 0x0180}, + {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE}, + {0xa0, 0x40, ZC3XX_R116_RGAIN}, + {0xa0, 0x40, ZC3XX_R117_GGAIN}, + {0xa0, 0x40, ZC3XX_R118_BGAIN}, + {} +}; +static const struct usb_action hdcs2020b_50HZ[] = { + {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */ + {0xaa, 0x13, 0x0018}, /* 00,13,18,aa */ + {0xaa, 0x14, 0x0001}, /* 00,14,01,aa */ + {0xaa, 0x0e, 0x0005}, /* 00,0e,05,aa */ + {0xaa, 0x19, 0x001f}, /* 00,19,1f,aa */ + {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc */ + {0xa0, 0x02, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,02,cc */ + {0xa0, 0x76, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,76,cc */ + {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */ + {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc */ + {0xa0, 0x46, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,46,cc */ + {0xa0, 0x10, ZC3XX_R18C_AEFREEZE}, /* 01,8c,10,cc */ + {0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,20,cc */ + {0xa0, 0x0c, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,0c,cc */ + {0xa0, 0x28, ZC3XX_R1AA_DIGITALGAINSTEP}, /* 01,aa,28,cc */ + {0xa0, 0x05, ZC3XX_R01D_HSYNC_0}, /* 00,1d,05,cc */ + {0xa0, 0x1a, ZC3XX_R01E_HSYNC_1}, /* 00,1e,1a,cc */ + {0xa0, 0x2f, ZC3XX_R01F_HSYNC_2}, /* 00,1f,2f,cc */ + {} +}; +static const struct usb_action hdcs2020b_60HZ[] = { + {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */ + {0xaa, 0x13, 0x0031}, /* 00,13,31,aa */ + {0xaa, 0x14, 0x0001}, /* 00,14,01,aa */ + {0xaa, 0x0e, 0x0004}, /* 00,0e,04,aa */ + {0xaa, 0x19, 0x00cd}, /* 00,19,cd,aa */ + {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc */ + {0xa0, 0x02, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,02,cc */ + {0xa0, 0x62, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,62,cc */ + {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */ + {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc */ + {0xa0, 0x3d, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,3d,cc */ + {0xa0, 0x10, ZC3XX_R18C_AEFREEZE}, /* 01,8c,10,cc */ + {0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,20,cc */ + {0xa0, 0x0c, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,0c,cc */ + {0xa0, 0x28, ZC3XX_R1AA_DIGITALGAINSTEP}, /* 01,aa,28,cc */ + {0xa0, 0x04, ZC3XX_R01D_HSYNC_0}, /* 00,1d,04,cc */ + {0xa0, 0x18, ZC3XX_R01E_HSYNC_1}, /* 00,1e,18,cc */ + {0xa0, 0x2c, ZC3XX_R01F_HSYNC_2}, /* 00,1f,2c,cc */ + {} +}; +static const struct usb_action hdcs2020b_NoFliker[] = { + {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */ + {0xaa, 0x13, 0x0010}, /* 00,13,10,aa */ + {0xaa, 0x14, 0x0001}, /* 00,14,01,aa */ + {0xaa, 0x0e, 0x0004}, /* 00,0e,04,aa */ + {0xaa, 0x19, 0x0000}, /* 00,19,00,aa */ + {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc */ + {0xa0, 0x02, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,02,cc */ + {0xa0, 0x70, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,70,cc */ + {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */ + {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc */ + {0xa0, 0x10, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,10,cc */ + {0xa0, 0x10, ZC3XX_R18C_AEFREEZE}, /* 01,8c,10,cc */ + {0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,20,cc */ + {0xa0, 0x00, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,00,cc */ + {0xa0, 0x00, ZC3XX_R1AA_DIGITALGAINSTEP}, /* 01,aa,00,cc */ + {0xa0, 0x04, ZC3XX_R01D_HSYNC_0}, /* 00,1d,04,cc */ + {0xa0, 0x17, ZC3XX_R01E_HSYNC_1}, /* 00,1e,17,cc */ + {0xa0, 0x2a, ZC3XX_R01F_HSYNC_2}, /* 00,1f,2a,cc */ + {} +}; + +static const struct usb_action hv7131bxx_Initial[] = { + {0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL}, + {0xa0, 0x10, ZC3XX_R002_CLOCKSELECT}, + {0xa0, 0x00, ZC3XX_R010_CMOSSENSORSELECT}, + {0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING}, + {0xa0, 0x77, ZC3XX_R101_SENSORCORRECTION}, + {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, /* 00 */ + {0xa0, 0x03, ZC3XX_R012_VIDEOCONTROLFUNC}, + {0xa0, 0x01, ZC3XX_R012_VIDEOCONTROLFUNC}, + {0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH}, + {0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW}, + {0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH}, + {0xa0, 0xe0, ZC3XX_R006_FRAMEHEIGHTLOW}, + {0xa0, 0x00, ZC3XX_R098_WINYSTARTLOW}, + {0xa0, 0x00, ZC3XX_R09A_WINXSTARTLOW}, + {0xa0, 0x00, ZC3XX_R11A_FIRSTYLOW}, + {0xa0, 0x00, ZC3XX_R11C_FIRSTXLOW}, + {0xaa, 0x30, 0x002d}, + {0xaa, 0x01, 0x0005}, + {0xaa, 0x11, 0x0000}, + {0xaa, 0x13, 0x0001}, /* {0xaa, 0x13, 0x0000}, */ + {0xaa, 0x14, 0x0001}, + {0xaa, 0x15, 0x00e8}, + {0xaa, 0x16, 0x0002}, + {0xaa, 0x17, 0x0086}, + {0xaa, 0x31, 0x0038}, + {0xaa, 0x32, 0x0038}, + {0xaa, 0x33, 0x0038}, + {0xaa, 0x5b, 0x0001}, + {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, + {0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC}, + {0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE}, + {0xa0, 0x68, ZC3XX_R18D_YTARGET}, + {0xa0, 0x60, ZC3XX_R1A8_DIGITALGAIN}, + {0xa0, 0x00, 0x01ad}, + {0xa0, 0xc0, 0x019b}, + {0xa0, 0xa0, 0x019c}, + {0xa0, 0x02, ZC3XX_R188_MINGAIN}, + {0xa0, 0x06, ZC3XX_R189_AWBSTATUS}, + {0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE}, + {0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05}, + {0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE}, + {0xa0, 0x08, ZC3XX_R301_EEPROMACCESS}, + {0xaa, 0x02, 0x0080}, /* {0xaa, 0x02, 0x0090}; */ + {0xa1, 0x01, 0x0002}, + {0xa0, 0x00, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x02, ZC3XX_R090_I2CCOMMAND}, + {0xa1, 0x01, 0x0091}, + {0xa1, 0x01, 0x0095}, + {0xa1, 0x01, 0x0096}, + + {0xa1, 0x01, 0x0008}, + {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, /* clock ? */ + {0xa0, 0x08, ZC3XX_R1C6_SHARPNESS00}, /* sharpness+ */ + {0xa1, 0x01, 0x01c8}, + {0xa1, 0x01, 0x01c9}, + {0xa1, 0x01, 0x01ca}, + {0xa0, 0x0f, ZC3XX_R1CB_SHARPNESS05}, /* sharpness- */ + + {0xa0, 0x50, ZC3XX_R10A_RGB00}, /* matrix */ + {0xa0, 0xf8, ZC3XX_R10B_RGB01}, + {0xa0, 0xf8, ZC3XX_R10C_RGB02}, + {0xa0, 0xf8, ZC3XX_R10D_RGB10}, + {0xa0, 0x50, ZC3XX_R10E_RGB11}, + {0xa0, 0xf8, ZC3XX_R10F_RGB12}, + {0xa0, 0xf8, ZC3XX_R110_RGB20}, + {0xa0, 0xf8, ZC3XX_R111_RGB21}, + {0xa0, 0x50, ZC3XX_R112_RGB22}, + {0xa1, 0x01, 0x0180}, + {0xa0, 0x10, ZC3XX_R180_AUTOCORRECTENABLE}, + {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, + {0xaa, 0x25, 0x0007}, + {0xaa, 0x26, 0x00a1}, + {0xaa, 0x27, 0x0020}, + {0xaa, 0x20, 0x0000}, + {0xaa, 0x21, 0x00a0}, + {0xaa, 0x22, 0x0016}, + {0xaa, 0x23, 0x0040}, + + {0xa0, 0x10, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 2F */ + {0xa0, 0x04, ZC3XX_R191_EXPOSURELIMITMID}, /* 4d */ + {0xa0, 0x60, ZC3XX_R192_EXPOSURELIMITLOW}, + {0xa0, 0x01, ZC3XX_R195_ANTIFLICKERHIGH}, + {0xa0, 0x86, ZC3XX_R196_ANTIFLICKERMID}, + {0xa0, 0xa0, ZC3XX_R197_ANTIFLICKERLOW}, + {0xa0, 0x07, ZC3XX_R18C_AEFREEZE}, + {0xa0, 0x0f, ZC3XX_R18F_AEUNFREEZE}, + {0xa0, 0x18, ZC3XX_R1A9_DIGITALLIMITDIFF}, + {0xa0, 0x24, ZC3XX_R1AA_DIGITALGAINSTEP}, + {0xa0, 0x00, ZC3XX_R01D_HSYNC_0}, + {0xa0, 0xa0, ZC3XX_R01E_HSYNC_1}, + {0xa0, 0x16, ZC3XX_R01F_HSYNC_2}, + {0xa0, 0x40, ZC3XX_R020_HSYNC_3}, + {0xa0, 0x60, ZC3XX_R11D_GLOBALGAIN}, + {0xa1, 0x01, 0x001d}, + {0xa1, 0x01, 0x001e}, + {0xa1, 0x01, 0x001f}, + {0xa1, 0x01, 0x0020}, + {0xa0, 0x40, ZC3XX_R180_AUTOCORRECTENABLE}, + {0xa1, 0x01, 0x0180}, + {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE}, + {0xa0, 0x40, ZC3XX_R116_RGAIN}, + {0xa0, 0x40, ZC3XX_R117_GGAIN}, + {0xa0, 0x40, ZC3XX_R118_BGAIN}, +/* {0xa0, 0x02, ZC3XX_R008_CLOCKSETTING}, */ + {} +}; + +static const struct usb_action hv7131bxx_InitialScale[] = { + {0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL}, + {0xa0, 0x00, ZC3XX_R002_CLOCKSELECT}, + {0xa0, 0x00, ZC3XX_R010_CMOSSENSORSELECT}, + {0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING}, + {0xa0, 0x37, ZC3XX_R101_SENSORCORRECTION}, + {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, /* 00 */ + {0xa0, 0x03, ZC3XX_R012_VIDEOCONTROLFUNC}, + {0xa0, 0x01, ZC3XX_R012_VIDEOCONTROLFUNC}, + {0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH}, + {0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW}, + {0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH}, + {0xa0, 0xe0, ZC3XX_R006_FRAMEHEIGHTLOW}, + {0xa0, 0x00, ZC3XX_R098_WINYSTARTLOW}, + {0xa0, 0x00, ZC3XX_R09A_WINXSTARTLOW}, + {0xa0, 0x00, ZC3XX_R11A_FIRSTYLOW}, + {0xa0, 0x00, ZC3XX_R11C_FIRSTXLOW}, + {0xaa, 0x30, 0x002d}, + {0xaa, 0x01, 0x0005}, + {0xaa, 0x11, 0x0001}, + {0xaa, 0x13, 0x0000}, /* {0xaa, 0x13, 0x0001}; */ + {0xaa, 0x14, 0x0001}, + {0xaa, 0x15, 0x00e6}, + {0xaa, 0x16, 0x0002}, + {0xaa, 0x17, 0x0086}, + {0xaa, 0x31, 0x0038}, + {0xaa, 0x32, 0x0038}, + {0xaa, 0x33, 0x0038}, + {0xaa, 0x5b, 0x0001}, + {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, + {0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC}, + {0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE}, + {0xa0, 0x70, ZC3XX_R18D_YTARGET}, + {0xa0, 0x60, ZC3XX_R1A8_DIGITALGAIN}, + {0xa0, 0x00, 0x01ad}, + {0xa0, 0xc0, 0x019b}, + {0xa0, 0xa0, 0x019c}, + {0xa0, 0x02, ZC3XX_R188_MINGAIN}, + {0xa0, 0x06, ZC3XX_R189_AWBSTATUS}, + {0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE}, + {0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05}, + {0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE}, + {0xa0, 0x08, ZC3XX_R301_EEPROMACCESS}, + {0xaa, 0x02, 0x0090}, /* {0xaa, 0x02, 0x0080}, */ + {0xa1, 0x01, 0x0002}, + {0xa0, 0x00, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x02, ZC3XX_R090_I2CCOMMAND}, + {0xa1, 0x01, 0x0091}, + {0xa1, 0x01, 0x0095}, + {0xa1, 0x01, 0x0096}, + {0xa1, 0x01, 0x0008}, + {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, /* clock ? */ + {0xa0, 0x08, ZC3XX_R1C6_SHARPNESS00}, /* sharpness+ */ + {0xa1, 0x01, 0x01c8}, + {0xa1, 0x01, 0x01c9}, + {0xa1, 0x01, 0x01ca}, + {0xa0, 0x0f, ZC3XX_R1CB_SHARPNESS05}, /* sharpness- */ + + {0xa0, 0x50, ZC3XX_R10A_RGB00}, /* matrix */ + {0xa0, 0xf8, ZC3XX_R10B_RGB01}, + {0xa0, 0xf8, ZC3XX_R10C_RGB02}, + {0xa0, 0xf8, ZC3XX_R10D_RGB10}, + {0xa0, 0x50, ZC3XX_R10E_RGB11}, + {0xa0, 0xf8, ZC3XX_R10F_RGB12}, + {0xa0, 0xf8, ZC3XX_R110_RGB20}, + {0xa0, 0xf8, ZC3XX_R111_RGB21}, + {0xa0, 0x50, ZC3XX_R112_RGB22}, + {0xa1, 0x01, 0x0180}, + {0xa0, 0x10, ZC3XX_R180_AUTOCORRECTENABLE}, + {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, + {0xaa, 0x25, 0x0007}, + {0xaa, 0x26, 0x00a1}, + {0xaa, 0x27, 0x0020}, + {0xaa, 0x20, 0x0000}, + {0xaa, 0x21, 0x0040}, + {0xaa, 0x22, 0x0013}, + {0xaa, 0x23, 0x004c}, + {0xa0, 0x10, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 2f */ + {0xa0, 0x04, ZC3XX_R191_EXPOSURELIMITMID}, /* 4d */ + {0xa0, 0x60, ZC3XX_R192_EXPOSURELIMITLOW}, /* 60 */ + {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, + {0xa0, 0xc3, ZC3XX_R196_ANTIFLICKERMID}, + {0xa0, 0x50, ZC3XX_R197_ANTIFLICKERLOW}, + {0xa0, 0x0c, ZC3XX_R18C_AEFREEZE}, + {0xa0, 0x18, ZC3XX_R18F_AEUNFREEZE}, + {0xa0, 0x18, ZC3XX_R1A9_DIGITALLIMITDIFF}, + {0xa0, 0x24, ZC3XX_R1AA_DIGITALGAINSTEP}, + {0xa0, 0x00, ZC3XX_R01D_HSYNC_0}, + {0xa0, 0x40, ZC3XX_R01E_HSYNC_1}, + {0xa0, 0x13, ZC3XX_R01F_HSYNC_2}, + {0xa0, 0x4c, ZC3XX_R020_HSYNC_3}, + {0xa0, 0x60, ZC3XX_R11D_GLOBALGAIN}, + {0xa1, 0x01, 0x001d}, + {0xa1, 0x01, 0x001e}, + {0xa1, 0x01, 0x001f}, + {0xa1, 0x01, 0x0020}, + {0xa0, 0x40, ZC3XX_R180_AUTOCORRECTENABLE}, + {0xa1, 0x01, 0x0180}, + {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE}, + {0xa0, 0x40, ZC3XX_R116_RGAIN}, + {0xa0, 0x40, ZC3XX_R117_GGAIN}, + {0xa0, 0x40, ZC3XX_R118_BGAIN}, +/* {0xa0, 0x02, ZC3XX_R008_CLOCKSETTING}, */ + {} +}; + +static const struct usb_action hv7131cxx_Initial[] = { + {0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL}, + {0xa0, 0x10, ZC3XX_R002_CLOCKSELECT}, + {0xa0, 0x01, ZC3XX_R010_CMOSSENSORSELECT}, + {0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING}, + {0xa0, 0x77, ZC3XX_R101_SENSORCORRECTION}, + {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, + {0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC}, + {0xa0, 0x07, ZC3XX_R012_VIDEOCONTROLFUNC}, + {0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH}, + {0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW}, + {0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH}, + {0xa0, 0xe0, ZC3XX_R006_FRAMEHEIGHTLOW}, + {0xa0, 0x00, ZC3XX_R098_WINYSTARTLOW}, + {0xa0, 0x00, ZC3XX_R09A_WINXSTARTLOW}, + {0xa0, 0x01, ZC3XX_R09B_WINHEIGHTHIGH}, + {0xa0, 0xe8, ZC3XX_R09C_WINHEIGHTLOW}, + {0xa0, 0x02, ZC3XX_R09D_WINWIDTHHIGH}, + {0xa0, 0x88, ZC3XX_R09E_WINWIDTHLOW}, + {0xa0, 0x00, ZC3XX_R11A_FIRSTYLOW}, + {0xa0, 0x00, ZC3XX_R11C_FIRSTXLOW}, + {0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC}, + {0xaa, 0x01, 0x000c}, + {0xaa, 0x11, 0x0000}, + {0xaa, 0x13, 0x0000}, + {0xaa, 0x14, 0x0001}, + {0xaa, 0x15, 0x00e8}, + {0xaa, 0x16, 0x0002}, + {0xaa, 0x17, 0x0088}, + + {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, + {0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE}, + {0xa0, 0x89, ZC3XX_R18D_YTARGET}, + {0xa0, 0x50, ZC3XX_R1A8_DIGITALGAIN}, + {0xa0, 0x00, 0x01ad}, + {0xa0, 0xc0, 0x019b}, + {0xa0, 0xa0, 0x019c}, + {0xa0, 0x06, ZC3XX_R189_AWBSTATUS}, + {0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE}, + {0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05}, + {0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE}, + {0xa0, 0x08, ZC3XX_R301_EEPROMACCESS}, + {0xa1, 0x01, 0x0002}, + {0xa0, 0x00, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x02, ZC3XX_R090_I2CCOMMAND}, + {0xa1, 0x01, 0x0091}, + {0xa1, 0x01, 0x0095}, + {0xa1, 0x01, 0x0096}, + + {0xa1, 0x01, 0x0008}, + {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, /* clock ? */ + {0xa0, 0x08, ZC3XX_R1C6_SHARPNESS00}, /* sharpness+ */ + {0xa1, 0x01, 0x01c8}, + {0xa1, 0x01, 0x01c9}, + {0xa1, 0x01, 0x01ca}, + {0xa0, 0x0f, ZC3XX_R1CB_SHARPNESS05}, /* sharpness- */ + + {0xa0, 0x60, ZC3XX_R10A_RGB00}, /* matrix */ + {0xa0, 0xf0, ZC3XX_R10B_RGB01}, + {0xa0, 0xf0, ZC3XX_R10C_RGB02}, + {0xa0, 0xf0, ZC3XX_R10D_RGB10}, + {0xa0, 0x60, ZC3XX_R10E_RGB11}, + {0xa0, 0xf0, ZC3XX_R10F_RGB12}, + {0xa0, 0xf0, ZC3XX_R110_RGB20}, + {0xa0, 0xf0, ZC3XX_R111_RGB21}, + {0xa0, 0x60, ZC3XX_R112_RGB22}, + {0xa1, 0x01, 0x0180}, + {0xa0, 0x10, ZC3XX_R180_AUTOCORRECTENABLE}, + {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, + {0xaa, 0x25, 0x0007}, + {0xaa, 0x26, 0x0053}, + {0xaa, 0x27, 0x0000}, + + {0xa0, 0x10, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 2f */ + {0xa0, 0x04, ZC3XX_R191_EXPOSURELIMITMID}, /* 9b */ + {0xa0, 0x60, ZC3XX_R192_EXPOSURELIMITLOW}, /* 80 */ + {0xa0, 0x01, ZC3XX_R195_ANTIFLICKERHIGH}, + {0xa0, 0xd4, ZC3XX_R196_ANTIFLICKERMID}, + {0xa0, 0xc0, ZC3XX_R197_ANTIFLICKERLOW}, + {0xa0, 0x10, ZC3XX_R18C_AEFREEZE}, + {0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE}, + {0xa0, 0x60, ZC3XX_R1A8_DIGITALGAIN}, + {0xa0, 0x10, ZC3XX_R1A9_DIGITALLIMITDIFF}, + {0xa0, 0x13, ZC3XX_R1AA_DIGITALGAINSTEP}, + {0xa1, 0x01, 0x001d}, + {0xa1, 0x01, 0x001e}, + {0xa1, 0x01, 0x001f}, + {0xa1, 0x01, 0x0020}, + {0xa0, 0x40, ZC3XX_R180_AUTOCORRECTENABLE}, + {0xa1, 0x01, 0x0180}, + {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE}, + {} +}; + +static const struct usb_action hv7131cxx_InitialScale[] = { + {0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL}, + + {0xa0, 0x00, ZC3XX_R002_CLOCKSELECT}, /* diff */ + {0xa0, 0x01, ZC3XX_R010_CMOSSENSORSELECT}, + {0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING}, + {0xa0, 0x77, ZC3XX_R101_SENSORCORRECTION}, + {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, + + {0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC}, + {0xa0, 0x07, ZC3XX_R012_VIDEOCONTROLFUNC}, + + {0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH}, + {0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW}, + {0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH}, + {0xa0, 0xe0, ZC3XX_R006_FRAMEHEIGHTLOW}, /* 1e0 */ + + {0xa0, 0x00, ZC3XX_R098_WINYSTARTLOW}, + {0xa0, 0x00, ZC3XX_R09A_WINXSTARTLOW}, + {0xa0, 0x01, ZC3XX_R09B_WINHEIGHTHIGH}, + {0xa0, 0xe8, ZC3XX_R09C_WINHEIGHTLOW}, + {0xa0, 0x02, ZC3XX_R09D_WINWIDTHHIGH}, + {0xa0, 0x88, ZC3XX_R09E_WINWIDTHLOW}, + {0xa0, 0x00, ZC3XX_R11A_FIRSTYLOW}, + {0xa0, 0x00, ZC3XX_R11C_FIRSTXLOW}, + {0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC}, + {0xaa, 0x01, 0x000c}, + {0xaa, 0x11, 0x0000}, + {0xaa, 0x13, 0x0000}, + {0xaa, 0x14, 0x0001}, + {0xaa, 0x15, 0x00e8}, + {0xaa, 0x16, 0x0002}, + {0xaa, 0x17, 0x0088}, + + {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00 */ + + {0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE}, + {0xa0, 0x89, ZC3XX_R18D_YTARGET}, + {0xa0, 0x50, ZC3XX_R1A8_DIGITALGAIN}, + {0xa0, 0x00, 0x01ad}, + {0xa0, 0xc0, 0x019b}, + {0xa0, 0xa0, 0x019c}, + {0xa0, 0x06, ZC3XX_R189_AWBSTATUS}, + {0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE}, + {0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05}, + {0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE}, + {0xa0, 0x08, ZC3XX_R301_EEPROMACCESS}, + {0xa1, 0x01, 0x0002}, + {0xa0, 0x00, ZC3XX_R092_I2CADDRESSSELECT}, + /* read the i2c chips ident */ + {0xa0, 0x02, ZC3XX_R090_I2CCOMMAND}, + {0xa1, 0x01, 0x0091}, + {0xa1, 0x01, 0x0095}, + {0xa1, 0x01, 0x0096}, + + {0xa1, 0x01, 0x0008}, + {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, /* clock ? */ + {0xa0, 0x08, ZC3XX_R1C6_SHARPNESS00}, /* sharpness+ */ + {0xa1, 0x01, 0x01c8}, + {0xa1, 0x01, 0x01c9}, + {0xa1, 0x01, 0x01ca}, + {0xa0, 0x0f, ZC3XX_R1CB_SHARPNESS05}, /* sharpness- */ + + {0xa0, 0x60, ZC3XX_R10A_RGB00}, /* matrix */ + {0xa0, 0xf0, ZC3XX_R10B_RGB01}, + {0xa0, 0xf0, ZC3XX_R10C_RGB02}, + {0xa0, 0xf0, ZC3XX_R10D_RGB10}, + {0xa0, 0x60, ZC3XX_R10E_RGB11}, + {0xa0, 0xf0, ZC3XX_R10F_RGB12}, + {0xa0, 0xf0, ZC3XX_R110_RGB20}, + {0xa0, 0xf0, ZC3XX_R111_RGB21}, + {0xa0, 0x60, ZC3XX_R112_RGB22}, + {0xa1, 0x01, 0x0180}, + {0xa0, 0x10, ZC3XX_R180_AUTOCORRECTENABLE}, + {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, + {0xaa, 0x25, 0x0007}, + {0xaa, 0x26, 0x0053}, + {0xaa, 0x27, 0x0000}, + + {0xa0, 0x10, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 2f */ + {0xa0, 0x04, ZC3XX_R191_EXPOSURELIMITMID}, /* 9b */ + {0xa0, 0x60, ZC3XX_R192_EXPOSURELIMITLOW}, /* 80 */ + + {0xa0, 0x01, ZC3XX_R195_ANTIFLICKERHIGH}, + {0xa0, 0xd4, ZC3XX_R196_ANTIFLICKERMID}, + {0xa0, 0xc0, ZC3XX_R197_ANTIFLICKERLOW}, + + {0xa0, 0x10, ZC3XX_R18C_AEFREEZE}, + {0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE}, + {0xa0, 0x60, ZC3XX_R1A8_DIGITALGAIN}, + {0xa0, 0x10, ZC3XX_R1A9_DIGITALLIMITDIFF}, + {0xa0, 0x13, ZC3XX_R1AA_DIGITALGAINSTEP}, + {0xa1, 0x01, 0x001d}, + {0xa1, 0x01, 0x001e}, + {0xa1, 0x01, 0x001f}, + {0xa1, 0x01, 0x0020}, + {0xa0, 0x40, ZC3XX_R180_AUTOCORRECTENABLE}, + {0xa1, 0x01, 0x0180}, + {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE}, + {} +}; + +static const struct usb_action icm105axx_Initial[] = { + {0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL}, + {0xa0, 0x10, ZC3XX_R002_CLOCKSELECT}, + {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, + {0xa0, 0x0c, ZC3XX_R010_CMOSSENSORSELECT}, + {0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH}, + {0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW}, + {0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH}, + {0xa0, 0xe0, ZC3XX_R006_FRAMEHEIGHTLOW}, + {0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING}, + {0xa0, 0x03, ZC3XX_R012_VIDEOCONTROLFUNC}, + {0xa0, 0x01, ZC3XX_R012_VIDEOCONTROLFUNC}, + {0xa0, 0xa1, ZC3XX_R08B_I2CDEVICEADDR}, + {0xa0, 0x00, ZC3XX_R097_WINYSTARTHIGH}, + {0xa0, 0x01, ZC3XX_R098_WINYSTARTLOW}, + {0xa0, 0x00, ZC3XX_R099_WINXSTARTHIGH}, + {0xa0, 0x01, ZC3XX_R09A_WINXSTARTLOW}, + {0xa0, 0x01, ZC3XX_R11A_FIRSTYLOW}, + {0xa0, 0x01, ZC3XX_R11C_FIRSTXLOW}, + {0xa0, 0x01, ZC3XX_R09B_WINHEIGHTHIGH}, + {0xa0, 0xe8, ZC3XX_R09C_WINHEIGHTLOW}, + {0xa0, 0x02, ZC3XX_R09D_WINWIDTHHIGH}, + {0xa0, 0x88, ZC3XX_R09E_WINWIDTHLOW}, + {0xa0, 0x37, ZC3XX_R101_SENSORCORRECTION}, + {0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE}, + {0xa0, 0x06, ZC3XX_R189_AWBSTATUS}, + {0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE}, + {0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05}, + {0xaa, 0x01, 0x0010}, + {0xaa, 0x03, 0x0000}, + {0xaa, 0x04, 0x0001}, + {0xaa, 0x05, 0x0020}, + {0xaa, 0x06, 0x0001}, + {0xaa, 0x08, 0x0000}, + {0xaa, 0x03, 0x0001}, + {0xaa, 0x04, 0x0011}, + {0xaa, 0x05, 0x00a0}, + {0xaa, 0x06, 0x0001}, + {0xaa, 0x08, 0x0000}, + {0xaa, 0x03, 0x0002}, + {0xaa, 0x04, 0x0013}, + {0xaa, 0x05, 0x0020}, + {0xaa, 0x06, 0x0001}, + {0xaa, 0x08, 0x0000}, + {0xaa, 0x03, 0x0003}, + {0xaa, 0x04, 0x0015}, + {0xaa, 0x05, 0x0020}, + {0xaa, 0x06, 0x0005}, + {0xaa, 0x08, 0x0000}, + {0xaa, 0x03, 0x0004}, + {0xaa, 0x04, 0x0017}, + {0xaa, 0x05, 0x0020}, + {0xaa, 0x06, 0x000d}, + {0xaa, 0x08, 0x0000}, + {0xaa, 0x03, 0x0005}, + {0xaa, 0x04, 0x0019}, + {0xaa, 0x05, 0x0020}, + {0xaa, 0x06, 0x0005}, + {0xaa, 0x08, 0x0000}, + {0xaa, 0x03, 0x0006}, + {0xaa, 0x04, 0x0017}, + {0xaa, 0x05, 0x0026}, + {0xaa, 0x06, 0x0005}, + {0xaa, 0x08, 0x0000}, + {0xaa, 0x03, 0x0007}, + {0xaa, 0x04, 0x0019}, + {0xaa, 0x05, 0x0022}, + {0xaa, 0x06, 0x0005}, + {0xaa, 0x08, 0x0000}, + {0xaa, 0x03, 0x0008}, + {0xaa, 0x04, 0x0021}, + {0xaa, 0x05, 0x00aa}, + {0xaa, 0x06, 0x0005}, + {0xaa, 0x08, 0x0000}, + {0xaa, 0x03, 0x0009}, + {0xaa, 0x04, 0x0023}, + {0xaa, 0x05, 0x00aa}, + {0xaa, 0x06, 0x000d}, + {0xaa, 0x08, 0x0000}, + {0xaa, 0x03, 0x000a}, + {0xaa, 0x04, 0x0025}, + {0xaa, 0x05, 0x00aa}, + {0xaa, 0x06, 0x0005}, + {0xaa, 0x08, 0x0000}, + {0xaa, 0x03, 0x000b}, + {0xaa, 0x04, 0x00ec}, + {0xaa, 0x05, 0x002e}, + {0xaa, 0x06, 0x0005}, + {0xaa, 0x08, 0x0000}, + {0xaa, 0x03, 0x000c}, + {0xaa, 0x04, 0x00fa}, + {0xaa, 0x05, 0x002a}, + {0xaa, 0x06, 0x0005}, + {0xaa, 0x08, 0x0000}, + {0xaa, 0x07, 0x000d}, + {0xaa, 0x01, 0x0005}, + {0xaa, 0x94, 0x0002}, + {0xaa, 0x90, 0x0000}, + {0xaa, 0x91, 0x001f}, + {0xaa, 0x10, 0x0064}, + {0xaa, 0x9b, 0x00f0}, + {0xaa, 0x9c, 0x0002}, + {0xaa, 0x14, 0x001a}, + {0xaa, 0x20, 0x0080}, + {0xaa, 0x22, 0x0080}, + {0xaa, 0x24, 0x0080}, + {0xaa, 0x26, 0x0080}, + {0xaa, 0x00, 0x0084}, + {0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE}, + {0xa0, 0x08, ZC3XX_R301_EEPROMACCESS}, + {0xaa, 0xa8, 0x00c0}, + {0xa1, 0x01, 0x0002}, + {0xa1, 0x01, 0x0008}, + {0xa1, 0x01, 0x0180}, + {0xa0, 0x02, ZC3XX_R180_AUTOCORRECTENABLE}, + {0xa0, 0x40, ZC3XX_R116_RGAIN}, + {0xa0, 0x40, ZC3XX_R117_GGAIN}, + {0xa0, 0x40, ZC3XX_R118_BGAIN}, + {0xa1, 0x01, 0x0008}, + + {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, /* clock ? */ + {0xa0, 0x08, ZC3XX_R1C6_SHARPNESS00}, /* sharpness+ */ + {0xa1, 0x01, 0x01c8}, + {0xa1, 0x01, 0x01c9}, + {0xa1, 0x01, 0x01ca}, + {0xa0, 0x0f, ZC3XX_R1CB_SHARPNESS05}, /* sharpness- */ + {0xa0, 0x52, ZC3XX_R10A_RGB00}, /* matrix */ + {0xa0, 0xf7, ZC3XX_R10B_RGB01}, + {0xa0, 0xf7, ZC3XX_R10C_RGB02}, + {0xa0, 0xf7, ZC3XX_R10D_RGB10}, + {0xa0, 0x52, ZC3XX_R10E_RGB11}, + {0xa0, 0xf7, ZC3XX_R10F_RGB12}, + {0xa0, 0xf7, ZC3XX_R110_RGB20}, + {0xa0, 0xf7, ZC3XX_R111_RGB21}, + {0xa0, 0x52, ZC3XX_R112_RGB22}, + {0xa1, 0x01, 0x0180}, + {0xa0, 0x00, ZC3XX_R180_AUTOCORRECTENABLE}, + {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, + {0xaa, 0x0d, 0x0003}, + {0xaa, 0x0c, 0x008c}, + {0xaa, 0x0e, 0x0095}, + {0xaa, 0x0f, 0x0002}, + {0xaa, 0x1c, 0x0094}, + {0xaa, 0x1d, 0x0002}, + {0xaa, 0x20, 0x0080}, + {0xaa, 0x22, 0x0080}, + {0xaa, 0x24, 0x0080}, + {0xaa, 0x26, 0x0080}, + {0xaa, 0x00, 0x0084}, + {0xa0, 0x02, ZC3XX_R0A3_EXPOSURETIMEHIGH}, + {0xa0, 0x94, ZC3XX_R0A4_EXPOSURETIMELOW}, + {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, + {0xa0, 0x04, ZC3XX_R191_EXPOSURELIMITMID}, + {0xa0, 0x20, ZC3XX_R192_EXPOSURELIMITLOW}, + {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, + {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, + {0xa0, 0x84, ZC3XX_R197_ANTIFLICKERLOW}, + {0xa0, 0x10, ZC3XX_R18C_AEFREEZE}, + {0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE}, + {0xa0, 0x10, ZC3XX_R1A9_DIGITALLIMITDIFF}, + {0xa0, 0x12, ZC3XX_R1AA_DIGITALGAINSTEP}, + {0xa0, 0xe3, ZC3XX_R01D_HSYNC_0}, + {0xa0, 0xec, ZC3XX_R01E_HSYNC_1}, + {0xa0, 0xf5, ZC3XX_R01F_HSYNC_2}, + {0xa0, 0xff, ZC3XX_R020_HSYNC_3}, + {0xa0, 0x00, ZC3XX_R1A7_CALCGLOBALMEAN}, + {0xa0, 0xc0, ZC3XX_R1A8_DIGITALGAIN}, + {0xa0, 0xc0, ZC3XX_R11D_GLOBALGAIN}, + {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE}, + {0xa1, 0x01, 0x0180}, + {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE}, + {0xa0, 0x40, ZC3XX_R116_RGAIN}, + {0xa0, 0x40, ZC3XX_R117_GGAIN}, + {0xa0, 0x40, ZC3XX_R118_BGAIN}, + {} +}; + +static const struct usb_action icm105axx_InitialScale[] = { + {0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL}, + {0xa0, 0x00, ZC3XX_R002_CLOCKSELECT}, + {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, + {0xa0, 0x0c, ZC3XX_R010_CMOSSENSORSELECT}, + {0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH}, + {0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW}, + {0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH}, + {0xa0, 0xe0, ZC3XX_R006_FRAMEHEIGHTLOW}, + {0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING}, + {0xa0, 0x03, ZC3XX_R012_VIDEOCONTROLFUNC}, + {0xa0, 0x01, ZC3XX_R012_VIDEOCONTROLFUNC}, + {0xa0, 0xa1, ZC3XX_R08B_I2CDEVICEADDR}, + {0xa0, 0x00, ZC3XX_R097_WINYSTARTHIGH}, + {0xa0, 0x02, ZC3XX_R098_WINYSTARTLOW}, + {0xa0, 0x00, ZC3XX_R099_WINXSTARTHIGH}, + {0xa0, 0x02, ZC3XX_R09A_WINXSTARTLOW}, + {0xa0, 0x02, ZC3XX_R11A_FIRSTYLOW}, + {0xa0, 0x02, ZC3XX_R11C_FIRSTXLOW}, + {0xa0, 0x01, ZC3XX_R09B_WINHEIGHTHIGH}, + {0xa0, 0xe6, ZC3XX_R09C_WINHEIGHTLOW}, + {0xa0, 0x02, ZC3XX_R09D_WINWIDTHHIGH}, + {0xa0, 0x86, ZC3XX_R09E_WINWIDTHLOW}, + {0xa0, 0x77, ZC3XX_R101_SENSORCORRECTION}, + {0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE}, + {0xa0, 0x06, ZC3XX_R189_AWBSTATUS}, + {0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE}, + {0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05}, + {0xaa, 0x01, 0x0010}, + {0xaa, 0x03, 0x0000}, + {0xaa, 0x04, 0x0001}, + {0xaa, 0x05, 0x0020}, + {0xaa, 0x06, 0x0001}, + {0xaa, 0x08, 0x0000}, + {0xaa, 0x03, 0x0001}, + {0xaa, 0x04, 0x0011}, + {0xaa, 0x05, 0x00a0}, + {0xaa, 0x06, 0x0001}, + {0xaa, 0x08, 0x0000}, + {0xaa, 0x03, 0x0002}, + {0xaa, 0x04, 0x0013}, + {0xaa, 0x05, 0x0020}, + {0xaa, 0x06, 0x0001}, + {0xaa, 0x08, 0x0000}, + {0xaa, 0x03, 0x0003}, + {0xaa, 0x04, 0x0015}, + {0xaa, 0x05, 0x0020}, + {0xaa, 0x06, 0x0005}, + {0xaa, 0x08, 0x0000}, + {0xaa, 0x03, 0x0004}, + {0xaa, 0x04, 0x0017}, + {0xaa, 0x05, 0x0020}, + {0xaa, 0x06, 0x000d}, + {0xaa, 0x08, 0x0000}, + {0xaa, 0x03, 0x0005}, + {0xa0, 0x04, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x19, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa1, 0x01, 0x0091}, + {0xaa, 0x05, 0x0020}, + {0xaa, 0x06, 0x0005}, + {0xaa, 0x08, 0x0000}, + {0xaa, 0x03, 0x0006}, + {0xaa, 0x04, 0x0017}, + {0xaa, 0x05, 0x0026}, + {0xaa, 0x06, 0x0005}, + {0xaa, 0x08, 0x0000}, + {0xaa, 0x03, 0x0007}, + {0xaa, 0x04, 0x0019}, + {0xaa, 0x05, 0x0022}, + {0xaa, 0x06, 0x0005}, + {0xaa, 0x08, 0x0000}, + {0xaa, 0x03, 0x0008}, + {0xaa, 0x04, 0x0021}, + {0xaa, 0x05, 0x00aa}, + {0xaa, 0x06, 0x0005}, + {0xaa, 0x08, 0x0000}, + {0xaa, 0x03, 0x0009}, + {0xaa, 0x04, 0x0023}, + {0xaa, 0x05, 0x00aa}, + {0xaa, 0x06, 0x000d}, + {0xaa, 0x08, 0x0000}, + {0xaa, 0x03, 0x000a}, + {0xaa, 0x04, 0x0025}, + {0xaa, 0x05, 0x00aa}, + {0xaa, 0x06, 0x0005}, + {0xaa, 0x08, 0x0000}, + {0xaa, 0x03, 0x000b}, + {0xaa, 0x04, 0x00ec}, + {0xaa, 0x05, 0x002e}, + {0xaa, 0x06, 0x0005}, + {0xaa, 0x08, 0x0000}, + {0xaa, 0x03, 0x000c}, + {0xaa, 0x04, 0x00fa}, + {0xaa, 0x05, 0x002a}, + {0xaa, 0x06, 0x0005}, + {0xaa, 0x08, 0x0000}, + {0xaa, 0x07, 0x000d}, + {0xaa, 0x01, 0x0005}, + {0xaa, 0x94, 0x0002}, + {0xaa, 0x90, 0x0000}, + {0xaa, 0x91, 0x0010}, + {0xaa, 0x10, 0x0064}, + {0xaa, 0x9b, 0x00f0}, + {0xaa, 0x9c, 0x0002}, + {0xaa, 0x14, 0x001a}, + {0xaa, 0x20, 0x0080}, + {0xaa, 0x22, 0x0080}, + {0xaa, 0x24, 0x0080}, + {0xaa, 0x26, 0x0080}, + {0xaa, 0x00, 0x0084}, + {0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE}, + {0xa0, 0x08, ZC3XX_R301_EEPROMACCESS}, + {0xaa, 0xa8, 0x0080}, + {0xa0, 0x78, ZC3XX_R18D_YTARGET}, + {0xa1, 0x01, 0x0002}, + {0xa1, 0x01, 0x0008}, + {0xa1, 0x01, 0x0180}, + {0xa0, 0x02, ZC3XX_R180_AUTOCORRECTENABLE}, + {0xa0, 0x40, ZC3XX_R116_RGAIN}, + {0xa0, 0x40, ZC3XX_R117_GGAIN}, + {0xa0, 0x40, ZC3XX_R118_BGAIN}, + {0xa1, 0x01, 0x0008}, + + {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, /* clock ? */ + {0xa0, 0x08, ZC3XX_R1C6_SHARPNESS00}, /* sharpness+ */ + {0xa1, 0x01, 0x01c8}, + {0xa1, 0x01, 0x01c9}, + {0xa1, 0x01, 0x01ca}, + {0xa0, 0x0f, ZC3XX_R1CB_SHARPNESS05}, /* sharpness- */ + + {0xa0, 0x52, ZC3XX_R10A_RGB00}, /* matrix */ + {0xa0, 0xf7, ZC3XX_R10B_RGB01}, + {0xa0, 0xf7, ZC3XX_R10C_RGB02}, + {0xa0, 0xf7, ZC3XX_R10D_RGB10}, + {0xa0, 0x52, ZC3XX_R10E_RGB11}, + {0xa0, 0xf7, ZC3XX_R10F_RGB12}, + {0xa0, 0xf7, ZC3XX_R110_RGB20}, + {0xa0, 0xf7, ZC3XX_R111_RGB21}, + {0xa0, 0x52, ZC3XX_R112_RGB22}, + {0xa1, 0x01, 0x0180}, + {0xa0, 0x00, ZC3XX_R180_AUTOCORRECTENABLE}, + {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, + {0xaa, 0x0d, 0x0003}, + {0xaa, 0x0c, 0x0020}, + {0xaa, 0x0e, 0x000e}, + {0xaa, 0x0f, 0x0002}, + {0xaa, 0x1c, 0x000d}, + {0xaa, 0x1d, 0x0002}, + {0xaa, 0x20, 0x0080}, + {0xaa, 0x22, 0x0080}, + {0xaa, 0x24, 0x0080}, + {0xaa, 0x26, 0x0080}, + {0xaa, 0x00, 0x0084}, + {0xa0, 0x02, ZC3XX_R0A3_EXPOSURETIMEHIGH}, + {0xa0, 0x0d, ZC3XX_R0A4_EXPOSURETIMELOW}, + {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, + {0xa0, 0x04, ZC3XX_R191_EXPOSURELIMITMID}, + {0xa0, 0x1a, ZC3XX_R192_EXPOSURELIMITLOW}, + {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, + {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, + {0xa0, 0x4b, ZC3XX_R197_ANTIFLICKERLOW}, + {0xa0, 0x10, ZC3XX_R18C_AEFREEZE}, + {0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE}, + {0xa0, 0x10, ZC3XX_R1A9_DIGITALLIMITDIFF}, + {0xa0, 0x12, ZC3XX_R1AA_DIGITALGAINSTEP}, + {0xa0, 0xc8, ZC3XX_R01D_HSYNC_0}, + {0xa0, 0xd8, ZC3XX_R01E_HSYNC_1}, + {0xa0, 0xea, ZC3XX_R01F_HSYNC_2}, + {0xa0, 0xff, ZC3XX_R020_HSYNC_3}, + {0xa0, 0x00, ZC3XX_R1A7_CALCGLOBALMEAN}, + {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE}, + {0xa1, 0x01, 0x0180}, + {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE}, + {0xa0, 0x40, ZC3XX_R116_RGAIN}, + {0xa0, 0x40, ZC3XX_R117_GGAIN}, + {0xa0, 0x40, ZC3XX_R118_BGAIN}, + {} +}; +static const struct usb_action icm105a_50HZ[] = { + {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */ + {0xaa, 0x0d, 0x0003}, /* 00,0d,03,aa */ + {0xaa, 0x0c, 0x0020}, /* 00,0c,20,aa */ + {0xaa, 0x0e, 0x000e}, /* 00,0e,0e,aa */ + {0xaa, 0x0f, 0x0002}, /* 00,0f,02,aa */ + {0xaa, 0x1c, 0x000d}, /* 00,1c,0d,aa */ + {0xaa, 0x1d, 0x0002}, /* 00,1d,02,aa */ + {0xaa, 0x20, 0x0080}, /* 00,20,80,aa */ + {0xaa, 0x22, 0x0080}, /* 00,22,80,aa */ + {0xaa, 0x24, 0x0080}, /* 00,24,80,aa */ + {0xaa, 0x26, 0x0080}, /* 00,26,80,aa */ + {0xaa, 0x00, 0x0084}, /* 00,00,84,aa */ + {0xa0, 0x02, ZC3XX_R0A3_EXPOSURETIMEHIGH}, /* 00,a3,02,cc */ + {0xa0, 0x0d, ZC3XX_R0A4_EXPOSURETIMELOW}, /* 00,a4,0d,cc */ + {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc */ + {0xa0, 0x04, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,04,cc */ + {0xa0, 0x1a, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,1a,cc */ + {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */ + {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc */ + {0xa0, 0x4b, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,4b,cc */ + {0xa0, 0x10, ZC3XX_R18C_AEFREEZE}, /* 01,8c,10,cc */ + {0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,20,cc */ + {0xa0, 0x10, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,10,cc */ + {0xa0, 0x12, ZC3XX_R1AA_DIGITALGAINSTEP}, /* 01,aa,12,cc */ + {0xa0, 0xc8, ZC3XX_R01D_HSYNC_0}, /* 00,1d,c8,cc */ + {0xa0, 0xd8, ZC3XX_R01E_HSYNC_1}, /* 00,1e,d8,cc */ + {0xa0, 0xea, ZC3XX_R01F_HSYNC_2}, /* 00,1f,ea,cc */ + {0xa0, 0xff, ZC3XX_R020_HSYNC_3}, /* 00,20,ff,cc */ + {} +}; +static const struct usb_action icm105a_50HZScale[] = { + {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */ + {0xaa, 0x0d, 0x0003}, /* 00,0d,03,aa */ + {0xaa, 0x0c, 0x008c}, /* 00,0c,8c,aa */ + {0xaa, 0x0e, 0x0095}, /* 00,0e,95,aa */ + {0xaa, 0x0f, 0x0002}, /* 00,0f,02,aa */ + {0xaa, 0x1c, 0x0094}, /* 00,1c,94,aa */ + {0xaa, 0x1d, 0x0002}, /* 00,1d,02,aa */ + {0xaa, 0x20, 0x0080}, /* 00,20,80,aa */ + {0xaa, 0x22, 0x0080}, /* 00,22,80,aa */ + {0xaa, 0x24, 0x0080}, /* 00,24,80,aa */ + {0xaa, 0x26, 0x0080}, /* 00,26,80,aa */ + {0xaa, 0x00, 0x0084}, /* 00,00,84,aa */ + {0xa0, 0x02, ZC3XX_R0A3_EXPOSURETIMEHIGH}, /* 00,a3,02,cc */ + {0xa0, 0x94, ZC3XX_R0A4_EXPOSURETIMELOW}, /* 00,a4,94,cc */ + {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc */ + {0xa0, 0x04, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,04,cc */ + {0xa0, 0x20, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,20,cc */ + {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */ + {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc */ + {0xa0, 0x84, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,84,cc */ + {0xa0, 0x10, ZC3XX_R18C_AEFREEZE}, /* 01,8c,10,cc */ + {0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,20,cc */ + {0xa0, 0x10, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,10,cc */ + {0xa0, 0x12, ZC3XX_R1AA_DIGITALGAINSTEP}, /* 01,aa,12,cc */ + {0xa0, 0xe3, ZC3XX_R01D_HSYNC_0}, /* 00,1d,e3,cc */ + {0xa0, 0xec, ZC3XX_R01E_HSYNC_1}, /* 00,1e,ec,cc */ + {0xa0, 0xf5, ZC3XX_R01F_HSYNC_2}, /* 00,1f,f5,cc */ + {0xa0, 0xff, ZC3XX_R020_HSYNC_3}, /* 00,20,ff,cc */ + {0xa0, 0x00, ZC3XX_R1A7_CALCGLOBALMEAN}, /* 01,a7,00,cc */ + {0xa0, 0xc0, ZC3XX_R1A8_DIGITALGAIN}, /* 01,a8,c0,cc */ + {} +}; +static const struct usb_action icm105a_60HZ[] = { + {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */ + {0xaa, 0x0d, 0x0003}, /* 00,0d,03,aa */ + {0xaa, 0x0c, 0x0004}, /* 00,0c,04,aa */ + {0xaa, 0x0e, 0x000d}, /* 00,0e,0d,aa */ + {0xaa, 0x0f, 0x0002}, /* 00,0f,02,aa */ + {0xaa, 0x1c, 0x0008}, /* 00,1c,08,aa */ + {0xaa, 0x1d, 0x0002}, /* 00,1d,02,aa */ + {0xaa, 0x20, 0x0080}, /* 00,20,80,aa */ + {0xaa, 0x22, 0x0080}, /* 00,22,80,aa */ + {0xaa, 0x24, 0x0080}, /* 00,24,80,aa */ + {0xaa, 0x26, 0x0080}, /* 00,26,80,aa */ + {0xaa, 0x00, 0x0084}, /* 00,00,84,aa */ + {0xa0, 0x02, ZC3XX_R0A3_EXPOSURETIMEHIGH}, /* 00,a3,02,cc */ + {0xa0, 0x08, ZC3XX_R0A4_EXPOSURETIMELOW}, /* 00,a4,08,cc */ + {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc */ + {0xa0, 0x04, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,04,cc */ + {0xa0, 0x10, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,10,cc */ + {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */ + {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc */ + {0xa0, 0x41, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,41,cc */ + {0xa0, 0x10, ZC3XX_R18C_AEFREEZE}, /* 01,8c,10,cc */ + {0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,20,cc */ + {0xa0, 0x10, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,10,cc */ + {0xa0, 0x12, ZC3XX_R1AA_DIGITALGAINSTEP}, /* 01,aa,12,cc */ + {0xa0, 0xc1, ZC3XX_R01D_HSYNC_0}, /* 00,1d,c1,cc */ + {0xa0, 0xd4, ZC3XX_R01E_HSYNC_1}, /* 00,1e,d4,cc */ + {0xa0, 0xe8, ZC3XX_R01F_HSYNC_2}, /* 00,1f,e8,cc */ + {0xa0, 0xff, ZC3XX_R020_HSYNC_3}, /* 00,20,ff,cc */ + {} +}; +static const struct usb_action icm105a_60HZScale[] = { + {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */ + {0xaa, 0x0d, 0x0003}, /* 00,0d,03,aa */ + {0xaa, 0x0c, 0x0008}, /* 00,0c,08,aa */ + {0xaa, 0x0e, 0x0086}, /* 00,0e,86,aa */ + {0xaa, 0x0f, 0x0002}, /* 00,0f,02,aa */ + {0xaa, 0x1c, 0x0085}, /* 00,1c,85,aa */ + {0xaa, 0x1d, 0x0002}, /* 00,1d,02,aa */ + {0xaa, 0x20, 0x0080}, /* 00,20,80,aa */ + {0xaa, 0x22, 0x0080}, /* 00,22,80,aa */ + {0xaa, 0x24, 0x0080}, /* 00,24,80,aa */ + {0xaa, 0x26, 0x0080}, /* 00,26,80,aa */ + {0xaa, 0x00, 0x0084}, /* 00,00,84,aa */ + {0xa0, 0x02, ZC3XX_R0A3_EXPOSURETIMEHIGH}, /* 00,a3,02,cc */ + {0xa0, 0x85, ZC3XX_R0A4_EXPOSURETIMELOW}, /* 00,a4,85,cc */ + {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc */ + {0xa0, 0x04, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,04,cc */ + {0xa0, 0x08, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,08,cc */ + {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */ + {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc */ + {0xa0, 0x81, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,81,cc */ + {0xa0, 0x10, ZC3XX_R18C_AEFREEZE}, /* 01,8c,10,cc */ + {0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,20,cc */ + {0xa0, 0x10, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,10,cc */ + {0xa0, 0x12, ZC3XX_R1AA_DIGITALGAINSTEP}, /* 01,aa,12,cc */ + {0xa0, 0xc2, ZC3XX_R01D_HSYNC_0}, /* 00,1d,c2,cc */ + {0xa0, 0xd6, ZC3XX_R01E_HSYNC_1}, /* 00,1e,d6,cc */ + {0xa0, 0xea, ZC3XX_R01F_HSYNC_2}, /* 00,1f,ea,cc */ + {0xa0, 0xff, ZC3XX_R020_HSYNC_3}, /* 00,20,ff,cc */ + {0xa0, 0x00, ZC3XX_R1A7_CALCGLOBALMEAN}, /* 01,a7,00,cc */ + {0xa0, 0xc0, ZC3XX_R1A8_DIGITALGAIN}, /* 01,a8,c0,cc */ + {} +}; +static const struct usb_action icm105a_NoFliker[] = { + {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */ + {0xaa, 0x0d, 0x0003}, /* 00,0d,03,aa */ + {0xaa, 0x0c, 0x0004}, /* 00,0c,04,aa */ + {0xaa, 0x0e, 0x000d}, /* 00,0e,0d,aa */ + {0xaa, 0x0f, 0x0002}, /* 00,0f,02,aa */ + {0xaa, 0x1c, 0x0000}, /* 00,1c,00,aa */ + {0xaa, 0x1d, 0x0002}, /* 00,1d,02,aa */ + {0xaa, 0x20, 0x0080}, /* 00,20,80,aa */ + {0xaa, 0x22, 0x0080}, /* 00,22,80,aa */ + {0xaa, 0x24, 0x0080}, /* 00,24,80,aa */ + {0xaa, 0x26, 0x0080}, /* 00,26,80,aa */ + {0xaa, 0x00, 0x0084}, /* 00,00,84,aa */ + {0xa0, 0x02, ZC3XX_R0A3_EXPOSURETIMEHIGH}, /* 00,a3,02,cc */ + {0xa0, 0x00, ZC3XX_R0A4_EXPOSURETIMELOW}, /* 00,a4,00,cc */ + {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc */ + {0xa0, 0x04, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,04,cc */ + {0xa0, 0x20, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,20,cc */ + {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */ + {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc */ + {0xa0, 0x10, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,10,cc */ + {0xa0, 0x10, ZC3XX_R18C_AEFREEZE}, /* 01,8c,10,cc */ + {0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,20,cc */ + {0xa0, 0x00, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,00,cc */ + {0xa0, 0x00, ZC3XX_R1AA_DIGITALGAINSTEP}, /* 01,aa,00,cc */ + {0xa0, 0xc1, ZC3XX_R01D_HSYNC_0}, /* 00,1d,c1,cc */ + {0xa0, 0xd4, ZC3XX_R01E_HSYNC_1}, /* 00,1e,d4,cc */ + {0xa0, 0xe8, ZC3XX_R01F_HSYNC_2}, /* 00,1f,e8,cc */ + {0xa0, 0xff, ZC3XX_R020_HSYNC_3}, /* 00,20,ff,cc */ + {} +}; +static const struct usb_action icm105a_NoFlikerScale[] = { + {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */ + {0xaa, 0x0d, 0x0003}, /* 00,0d,03,aa */ + {0xaa, 0x0c, 0x0004}, /* 00,0c,04,aa */ + {0xaa, 0x0e, 0x0081}, /* 00,0e,81,aa */ + {0xaa, 0x0f, 0x0002}, /* 00,0f,02,aa */ + {0xaa, 0x1c, 0x0080}, /* 00,1c,80,aa */ + {0xaa, 0x1d, 0x0002}, /* 00,1d,02,aa */ + {0xaa, 0x20, 0x0080}, /* 00,20,80,aa */ + {0xaa, 0x22, 0x0080}, /* 00,22,80,aa */ + {0xaa, 0x24, 0x0080}, /* 00,24,80,aa */ + {0xaa, 0x26, 0x0080}, /* 00,26,80,aa */ + {0xaa, 0x00, 0x0084}, /* 00,00,84,aa */ + {0xa0, 0x02, ZC3XX_R0A3_EXPOSURETIMEHIGH}, /* 00,a3,02,cc */ + {0xa0, 0x80, ZC3XX_R0A4_EXPOSURETIMELOW}, /* 00,a4,80,cc */ + {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc */ + {0xa0, 0x04, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,04,cc */ + {0xa0, 0x20, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,20,cc */ + {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */ + {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc */ + {0xa0, 0x10, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,10,cc */ + {0xa0, 0x10, ZC3XX_R18C_AEFREEZE}, /* 01,8c,10,cc */ + {0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,20,cc */ + {0xa0, 0x00, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,00,cc */ + {0xa0, 0x00, ZC3XX_R1AA_DIGITALGAINSTEP}, /* 01,aa,00,cc */ + {0xa0, 0xc1, ZC3XX_R01D_HSYNC_0}, /* 00,1d,c1,cc */ + {0xa0, 0xd4, ZC3XX_R01E_HSYNC_1}, /* 00,1e,d4,cc */ + {0xa0, 0xe8, ZC3XX_R01F_HSYNC_2}, /* 00,1f,e8,cc */ + {0xa0, 0xff, ZC3XX_R020_HSYNC_3}, /* 00,20,ff,cc */ + {0xa0, 0x00, ZC3XX_R1A7_CALCGLOBALMEAN}, /* 01,a7,00,cc */ + {0xa0, 0xc0, ZC3XX_R1A8_DIGITALGAIN}, /* 01,a8,c0,cc */ + {} +}; + +static const struct usb_action MC501CB_InitialScale[] = { + {0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL}, /* 00,00,01,cc */ + {0xa0, 0x00, ZC3XX_R002_CLOCKSELECT}, /* 00,02,00,cc */ + {0xa0, 0x01, ZC3XX_R010_CMOSSENSORSELECT}, /* 00,10,01,cc */ + {0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING}, /* 00,01,01,cc */ + {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, /* 00,08,03,cc */ + {0xa0, 0x01, ZC3XX_R012_VIDEOCONTROLFUNC}, /* 00,12,01,cc */ + {0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC}, /* 00,12,05,cc */ + {0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH}, /* 00,03,02,cc */ + {0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW}, /* 00,04,80,cc */ + {0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH}, /* 00,05,01,cc */ + {0xa0, 0xd8, ZC3XX_R006_FRAMEHEIGHTLOW}, /* 00,06,d8,cc */ + {0xa0, 0x00, ZC3XX_R098_WINYSTARTLOW}, /* 00,98,00,cc */ + {0xa0, 0x00, ZC3XX_R09A_WINXSTARTLOW}, /* 00,9a,00,cc */ + {0xa0, 0x00, ZC3XX_R11A_FIRSTYLOW}, /* 01,1a,00,cc */ + {0xa0, 0x00, ZC3XX_R11C_FIRSTXLOW}, /* 01,1c,00,cc */ + {0xa0, 0x01, ZC3XX_R09B_WINHEIGHTHIGH}, /* 00,9b,01,cc */ + {0xa0, 0xde, ZC3XX_R09C_WINHEIGHTLOW}, /* 00,9c,de,cc */ + {0xa0, 0x02, ZC3XX_R09D_WINWIDTHHIGH}, /* 00,9d,02,cc */ + {0xa0, 0x86, ZC3XX_R09E_WINWIDTHLOW}, /* 00,9e,86,cc */ + {0xa0, 0x33, ZC3XX_R086_EXPTIMEHIGH}, /* 00,86,33,cc */ + {0xa0, 0x34, ZC3XX_R087_EXPTIMEMID}, /* 00,87,34,cc */ + {0xa0, 0x35, ZC3XX_R088_EXPTIMELOW}, /* 00,88,35,cc */ + {0xa0, 0xb0, ZC3XX_R08B_I2CDEVICEADDR}, /* 00,8b,b0,cc */ + {0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC}, /* 00,12,05,cc */ + {0xaa, 0x01, 0x0001}, /* 00,01,01,aa */ + {0xaa, 0x01, 0x0003}, /* 00,01,03,aa */ + {0xaa, 0x01, 0x0001}, /* 00,01,01,aa */ + {0xaa, 0x03, 0x0000}, /* 00,03,00,aa */ + {0xaa, 0x10, 0x0000}, /* 00,10,00,aa */ + {0xaa, 0x11, 0x0080}, /* 00,11,80,aa */ + {0xaa, 0x12, 0x0000}, /* 00,12,00,aa */ + {0xaa, 0x13, 0x0000}, /* 00,13,00,aa */ + {0xaa, 0x14, 0x0000}, /* 00,14,00,aa */ + {0xaa, 0x15, 0x0000}, /* 00,15,00,aa */ + {0xaa, 0x16, 0x0000}, /* 00,16,00,aa */ + {0xaa, 0x17, 0x0001}, /* 00,17,01,aa */ + {0xaa, 0x18, 0x00de}, /* 00,18,de,aa */ + {0xaa, 0x19, 0x0002}, /* 00,19,02,aa */ + {0xaa, 0x1a, 0x0086}, /* 00,1a,86,aa */ + {0xaa, 0x20, 0x00a8}, /* 00,20,a8,aa */ + {0xaa, 0x22, 0x0000}, /* 00,22,00,aa */ + {0xaa, 0x23, 0x0000}, /* 00,23,00,aa */ + {0xaa, 0x24, 0x0000}, /* 00,24,00,aa */ + {0xaa, 0x40, 0x0033}, /* 00,40,33,aa */ + {0xaa, 0x41, 0x0077}, /* 00,41,77,aa */ + {0xaa, 0x42, 0x0053}, /* 00,42,53,aa */ + {0xaa, 0x43, 0x00b0}, /* 00,43,b0,aa */ + {0xaa, 0x4b, 0x0001}, /* 00,4b,01,aa */ + {0xaa, 0x72, 0x0020}, /* 00,72,20,aa */ + {0xaa, 0x73, 0x0000}, /* 00,73,00,aa */ + {0xaa, 0x80, 0x0000}, /* 00,80,00,aa */ + {0xaa, 0x85, 0x0050}, /* 00,85,50,aa */ + {0xaa, 0x91, 0x0070}, /* 00,91,70,aa */ + {0xaa, 0x92, 0x0072}, /* 00,92,72,aa */ + {0xaa, 0x03, 0x0001}, /* 00,03,01,aa */ + {0xaa, 0x10, 0x00a0}, /* 00,10,a0,aa */ + {0xaa, 0x11, 0x0001}, /* 00,11,01,aa */ + {0xaa, 0x30, 0x0000}, /* 00,30,00,aa */ + {0xaa, 0x60, 0x0000}, /* 00,60,00,aa */ + {0xaa, 0xa0, ZC3XX_R01A_LASTFRAMESTATE}, /* 00,a0,1a,aa */ + {0xaa, 0xa1, 0x0000}, /* 00,a1,00,aa */ + {0xaa, 0xa2, 0x003f}, /* 00,a2,3f,aa */ + {0xaa, 0xa3, 0x0028}, /* 00,a3,28,aa */ + {0xaa, 0xa4, 0x0010}, /* 00,a4,10,aa */ + {0xaa, 0xa5, 0x0020}, /* 00,a5,20,aa */ + {0xaa, 0xb1, 0x0044}, /* 00,b1,44,aa */ + {0xaa, 0xd0, 0x0001}, /* 00,d0,01,aa */ + {0xaa, 0xd1, 0x0085}, /* 00,d1,85,aa */ + {0xaa, 0xd2, 0x0080}, /* 00,d2,80,aa */ + {0xaa, 0xd3, 0x0080}, /* 00,d3,80,aa */ + {0xaa, 0xd4, 0x0080}, /* 00,d4,80,aa */ + {0xaa, 0xd5, 0x0080}, /* 00,d5,80,aa */ + {0xaa, 0xc0, 0x00c3}, /* 00,c0,c3,aa */ + {0xaa, 0xc2, 0x0044}, /* 00,c2,44,aa */ + {0xaa, 0xc4, 0x0040}, /* 00,c4,40,aa */ + {0xaa, 0xc5, 0x0020}, /* 00,c5,20,aa */ + {0xaa, 0xc6, 0x0008}, /* 00,c6,08,aa */ + {0xaa, 0x03, 0x0004}, /* 00,03,04,aa */ + {0xaa, 0x10, 0x0000}, /* 00,10,00,aa */ + {0xaa, 0x40, 0x0030}, /* 00,40,30,aa */ + {0xaa, 0x41, 0x0020}, /* 00,41,20,aa */ + {0xaa, 0x42, 0x002d}, /* 00,42,2d,aa */ + {0xaa, 0x03, 0x0003}, /* 00,03,03,aa */ + {0xaa, 0x1c, 0x0050}, /* 00,1C,50,aa */ + {0xaa, 0x11, 0x0081}, /* 00,11,81,aa */ + {0xaa, 0x3b, 0x001d}, /* 00,3b,1D,aa */ + {0xaa, 0x3c, 0x004c}, /* 00,3c,4C,aa */ + {0xaa, 0x3d, 0x0018}, /* 00,3d,18,aa */ + {0xaa, 0x3e, 0x006a}, /* 00,3e,6A,aa */ + {0xaa, 0x01, 0x0000}, /* 00,01,00,aa */ + {0xaa, 0x52, 0x00ff}, /* 00,52,FF,aa */ + {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */ + {0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE}, /* 01,00,0d,cc */ + {0xa0, 0x37, ZC3XX_R101_SENSORCORRECTION}, /* 01,01,37,cc */ + {0xa0, 0x06, ZC3XX_R189_AWBSTATUS}, /* 01,89,06,cc */ + {0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE}, /* 01,c5,03,cc */ + {0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05}, /* 01,cb,13,cc */ + {0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE}, /* 02,50,08,cc */ + {0xa0, 0x08, ZC3XX_R301_EEPROMACCESS}, /* 03,01,08,cc */ + {0xa0, 0x02, ZC3XX_R180_AUTOCORRECTENABLE}, /* 01,80,02,cc */ + {0xaa, 0x03, 0x0002}, /* 00,03,02,aa */ + {0xaa, 0x51, 0x0027}, /* 00,51,27,aa */ + {0xaa, 0x52, 0x0020}, /* 00,52,20,aa */ + {0xaa, 0x03, 0x0003}, /* 00,03,03,aa */ + {0xaa, 0x50, 0x0010}, /* 00,50,10,aa */ + {0xaa, 0x51, 0x0010}, /* 00,51,10,aa */ + {0xaa, 0x54, 0x0010}, /* 00,54,10,aa */ + {0xaa, 0x55, 0x0010}, /* 00,55,10,aa */ + {0xa0, 0xf0, 0x0199}, /* 01,99,F0,cc */ + {0xa0, 0x80, 0x019a}, /* 01,9A,80,cc */ + + {0xaa, 0x03, 0x0003}, /* 00,03,03,aa */ + {0xaa, 0x10, 0x00fc}, /* 00,10,fc,aa */ + {0xaa, 0x36, 0x001d}, /* 00,36,1D,aa */ + {0xaa, 0x37, 0x004c}, /* 00,37,4C,aa */ + {0xaa, 0x3b, 0x001d}, /* 00,3B,1D,aa */ + {} +}; + +static const struct usb_action MC501CB_Initial[] = { /* 320x240 */ + {0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL}, /* 00,00,01,cc */ + {0xa0, 0x10, ZC3XX_R002_CLOCKSELECT}, /* 00,02,10,cc */ + {0xa0, 0x01, ZC3XX_R010_CMOSSENSORSELECT}, /* 00,10,01,cc */ + {0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING}, /* 00,01,01,cc */ + {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, /* 00,08,03,cc */ + {0xa0, 0x01, ZC3XX_R012_VIDEOCONTROLFUNC}, /* 00,12,01,cc */ + {0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC}, /* 00,12,05,cc */ + {0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH}, /* 00,03,02,cc */ + {0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW}, /* 00,04,80,cc */ + {0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH}, /* 00,05,01,cc */ + {0xa0, 0xd0, ZC3XX_R006_FRAMEHEIGHTLOW}, /* 00,06,d0,cc */ + {0xa0, 0x00, ZC3XX_R098_WINYSTARTLOW}, /* 00,98,00,cc */ + {0xa0, 0x00, ZC3XX_R09A_WINXSTARTLOW}, /* 00,9a,00,cc */ + {0xa0, 0x00, ZC3XX_R11A_FIRSTYLOW}, /* 01,1a,00,cc */ + {0xa0, 0x00, ZC3XX_R11C_FIRSTXLOW}, /* 01,1c,00,cc */ + {0xa0, 0x01, ZC3XX_R09B_WINHEIGHTHIGH}, /* 00,9b,01,cc */ + {0xa0, 0xd8, ZC3XX_R09C_WINHEIGHTLOW}, /* 00,9c,d8,cc */ + {0xa0, 0x02, ZC3XX_R09D_WINWIDTHHIGH}, /* 00,9d,02,cc */ + {0xa0, 0x88, ZC3XX_R09E_WINWIDTHLOW}, /* 00,9e,88,cc */ + {0xa0, 0x33, ZC3XX_R086_EXPTIMEHIGH}, /* 00,86,33,cc */ + {0xa0, 0x34, ZC3XX_R087_EXPTIMEMID}, /* 00,87,34,cc */ + {0xa0, 0x35, ZC3XX_R088_EXPTIMELOW}, /* 00,88,35,cc */ + {0xa0, 0xb0, ZC3XX_R08B_I2CDEVICEADDR}, /* 00,8b,b0,cc */ + {0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC}, /* 00,12,05,cc */ + {0xaa, 0x01, 0x0001}, /* 00,01,01,aa */ + {0xaa, 0x01, 0x0003}, /* 00,01,03,aa */ + {0xaa, 0x01, 0x0001}, /* 00,01,01,aa */ + {0xaa, 0x03, 0x0000}, /* 00,03,00,aa */ + {0xaa, 0x10, 0x0000}, /* 00,10,00,aa */ + {0xaa, 0x11, 0x0080}, /* 00,11,80,aa */ + {0xaa, 0x12, 0x0000}, /* 00,12,00,aa */ + {0xaa, 0x13, 0x0000}, /* 00,13,00,aa */ + {0xaa, 0x14, 0x0000}, /* 00,14,00,aa */ + {0xaa, 0x15, 0x0000}, /* 00,15,00,aa */ + {0xaa, 0x16, 0x0000}, /* 00,16,00,aa */ + {0xaa, 0x17, 0x0001}, /* 00,17,01,aa */ + {0xaa, 0x18, 0x00d8}, /* 00,18,d8,aa */ + {0xaa, 0x19, 0x0002}, /* 00,19,02,aa */ + {0xaa, 0x1a, 0x0088}, /* 00,1a,88,aa */ + {0xaa, 0x20, 0x00a8}, /* 00,20,a8,aa */ + {0xaa, 0x22, 0x0000}, /* 00,22,00,aa */ + {0xaa, 0x23, 0x0000}, /* 00,23,00,aa */ + {0xaa, 0x24, 0x0000}, /* 00,24,00,aa */ + {0xaa, 0x40, 0x0033}, /* 00,40,33,aa */ + {0xaa, 0x41, 0x0077}, /* 00,41,77,aa */ + {0xaa, 0x42, 0x0053}, /* 00,42,53,aa */ + {0xaa, 0x43, 0x00b0}, /* 00,43,b0,aa */ + {0xaa, 0x4b, 0x0001}, /* 00,4b,01,aa */ + {0xaa, 0x72, 0x0020}, /* 00,72,20,aa */ + {0xaa, 0x73, 0x0000}, /* 00,73,00,aa */ + {0xaa, 0x80, 0x0000}, /* 00,80,00,aa */ + {0xaa, 0x85, 0x0050}, /* 00,85,50,aa */ + {0xaa, 0x91, 0x0070}, /* 00,91,70,aa */ + {0xaa, 0x92, 0x0072}, /* 00,92,72,aa */ + {0xaa, 0x03, 0x0001}, /* 00,03,01,aa */ + {0xaa, 0x10, 0x00a0}, /* 00,10,a0,aa */ + {0xaa, 0x11, 0x0001}, /* 00,11,01,aa */ + {0xaa, 0x30, 0x0000}, /* 00,30,00,aa */ + {0xaa, 0x60, 0x0000}, /* 00,60,00,aa */ + {0xaa, 0xa0, ZC3XX_R01A_LASTFRAMESTATE}, /* 00,a0,1a,aa */ + {0xaa, 0xa1, 0x0000}, /* 00,a1,00,aa */ + {0xaa, 0xa2, 0x003f}, /* 00,a2,3f,aa */ + {0xaa, 0xa3, 0x0028}, /* 00,a3,28,aa */ + {0xaa, 0xa4, 0x0010}, /* 00,a4,10,aa */ + {0xaa, 0xa5, 0x0020}, /* 00,a5,20,aa */ + {0xaa, 0xb1, 0x0044}, /* 00,b1,44,aa */ + {0xaa, 0xd0, 0x0001}, /* 00,d0,01,aa */ + {0xaa, 0xd1, 0x0085}, /* 00,d1,85,aa */ + {0xaa, 0xd2, 0x0080}, /* 00,d2,80,aa */ + {0xaa, 0xd3, 0x0080}, /* 00,d3,80,aa */ + {0xaa, 0xd4, 0x0080}, /* 00,d4,80,aa */ + {0xaa, 0xd5, 0x0080}, /* 00,d5,80,aa */ + {0xaa, 0xc0, 0x00c3}, /* 00,c0,c3,aa */ + {0xaa, 0xc2, 0x0044}, /* 00,c2,44,aa */ + {0xaa, 0xc4, 0x0040}, /* 00,c4,40,aa */ + {0xaa, 0xc5, 0x0020}, /* 00,c5,20,aa */ + {0xaa, 0xc6, 0x0008}, /* 00,c6,08,aa */ + {0xaa, 0x03, 0x0004}, /* 00,03,04,aa */ + {0xaa, 0x10, 0x0000}, /* 00,10,00,aa */ + {0xaa, 0x40, 0x0030}, /* 00,40,30,aa */ + {0xaa, 0x41, 0x0020}, /* 00,41,20,aa */ + {0xaa, 0x42, 0x002d}, /* 00,42,2d,aa */ + {0xaa, 0x03, 0x0003}, /* 00,03,03,aa */ + {0xaa, 0x1c, 0x0050}, /* 00,1c,50,aa */ + {0xaa, 0x11, 0x0081}, /* 00,11,81,aa */ + {0xaa, 0x3b, 0x003a}, /* 00,3b,3A,aa */ + {0xaa, 0x3c, 0x0098}, /* 00,3c,98,aa */ + {0xaa, 0x3d, 0x0030}, /* 00,3d,30,aa */ + {0xaa, 0x3e, 0x00d4}, /* 00,3E,D4,aa */ + {0xaa, 0x01, 0x0000}, /* 00,01,00,aa */ + {0xaa, 0x52, 0x00ff}, /* 00,52,FF,aa */ + {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */ + {0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE}, /* 01,00,0d,cc */ + {0xa0, 0x37, ZC3XX_R101_SENSORCORRECTION}, /* 01,01,37,cc */ + {0xa0, 0x06, ZC3XX_R189_AWBSTATUS}, /* 01,89,06,cc */ + {0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE}, /* 01,c5,03,cc */ + {0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05}, /* 01,cb,13,cc */ + {0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE}, /* 02,50,08,cc */ + {0xa0, 0x08, ZC3XX_R301_EEPROMACCESS}, /* 03,01,08,cc */ + {0xa0, 0x02, ZC3XX_R180_AUTOCORRECTENABLE}, /* 01,80,02,cc */ + {0xaa, 0x03, 0x0002}, /* 00,03,02,aa */ + {0xaa, 0x51, 0x004e}, /* 00,51,4E,aa */ + {0xaa, 0x52, 0x0041}, /* 00,52,41,aa */ + {0xaa, 0x03, 0x0003}, /* 00,03,03,aa */ + {0xaa, 0x50, 0x0010}, /* 00,50,10,aa */ + {0xaa, 0x51, 0x0010}, /* 00,51,10,aa */ + {0xaa, 0x54, 0x0010}, /* 00,54,10,aa */ + {0xaa, 0x55, 0x0010}, /* 00,55,10,aa */ + {0xa0, 0xf0, 0x0199}, /* 01,99,F0,cc */ + {0xa0, 0x80, 0x019a}, /* 01,9A,80,cc */ + {0xaa, 0x03, 0x0003}, /* 00,03,03,aa */ + {0xaa, 0x10, 0x00fc}, /* 00,10,fc,aa */ + {0xaa, 0x36, 0x001d}, /* 00,36,1D,aa */ + {0xaa, 0x37, 0x004c}, /* 00,37,4C,aa */ + {0xaa, 0x3b, 0x001d}, /* 00,3B,1D,aa */ + {} +}; + +static const struct usb_action MC501CB_50HZ[] = { + {0xaa, 0x03, 0x0003}, /* 00,03,03,aa */ + {0xaa, 0x10, 0x00fc}, /* 00,10,fc,aa */ + {0xaa, 0x36, 0x001d}, /* 00,36,1D,aa */ + {0xaa, 0x37, 0x004c}, /* 00,37,4C,aa */ + {0xaa, 0x3b, 0x001d}, /* 00,3B,1D,aa */ + {0xaa, 0x3c, 0x004c}, /* 00,3C,4C,aa */ + {0xaa, 0x3d, 0x001d}, /* 00,3D,1D,aa */ + {0xaa, 0x3e, 0x004c}, /* 00,3E,4C,aa */ + {0xaa, 0x03, 0x0003}, /* 00,03,03,aa */ + {0xaa, 0x10, 0x00fc}, /* 00,10,fc,aa */ + {0xaa, 0x36, 0x003a}, /* 00,36,3A,aa */ + {0xaa, 0x37, 0x0098}, /* 00,37,98,aa */ + {0xaa, 0x3b, 0x003a}, /* 00,3B,3A,aa */ + {} +}; + +static const struct usb_action MC501CB_50HZScale[] = { + {0xaa, 0x03, 0x0003}, /* 00,03,03,aa */ + {0xaa, 0x10, 0x00fc}, /* 00,10,fc,aa */ + {0xaa, 0x36, 0x003a}, /* 00,36,3A,aa */ + {0xaa, 0x37, 0x0098}, /* 00,37,98,aa */ + {0xaa, 0x3b, 0x003a}, /* 00,3B,3A,aa */ + {0xaa, 0x3c, 0x0098}, /* 00,3C,98,aa */ + {0xaa, 0x3d, 0x003a}, /* 00,3D,3A,aa */ + {0xaa, 0x3e, 0x0098}, /* 00,3E,98,aa */ + {0xaa, 0x03, 0x0003}, /* 00,03,03,aa */ + {0xaa, 0x10, 0x00fc}, /* 00,10,fc,aa */ + {0xaa, 0x36, 0x0018}, /* 00,36,18,aa */ + {0xaa, 0x37, 0x006a}, /* 00,37,6A,aa */ + {0xaa, 0x3d, 0x0018}, /* 00,3D,18,aa */ + {} +}; + +static const struct usb_action MC501CB_60HZ[] = { + {0xaa, 0x03, 0x0003}, /* 00,03,03,aa */ + {0xaa, 0x10, 0x00fc}, /* 00,10,fc,aa */ + {0xaa, 0x36, 0x0018}, /* 00,36,18,aa */ + {0xaa, 0x37, 0x006a}, /* 00,37,6A,aa */ + {0xaa, 0x3d, 0x0018}, /* 00,3D,18,aa */ + {0xaa, 0x3e, 0x006a}, /* 00,3E,6A,aa */ + {0xaa, 0x3b, 0x0018}, /* 00,3B,18,aa */ + {0xaa, 0x3c, 0x006a}, /* 00,3C,6A,aa */ + {0xaa, 0x03, 0x0003}, /* 00,03,03,aa */ + {0xaa, 0x10, 0x00fc}, /* 00,10,fc,aa */ + {0xaa, 0x36, 0x0030}, /* 00,36,30,aa */ + {0xaa, 0x37, 0x00d4}, /* 00,37,D4,aa */ + {0xaa, 0x3d, 0x0030}, /* 00,3D,30,aa */ + {} +}; + +static const struct usb_action MC501CB_60HZScale[] = { + {0xaa, 0x03, 0x0003}, /* 00,03,03,aa */ + {0xaa, 0x10, 0x00fc}, /* 00,10,fc,aa */ + {0xaa, 0x36, 0x0030}, /* 00,36,30,aa */ + {0xaa, 0x37, 0x00d4}, /* 00,37,D4,aa */ + {0xaa, 0x3d, 0x0030}, /* 00,3D,30,aa */ + {0xaa, 0x3e, 0x00d4}, /* 00,3E,D4,aa */ + {0xaa, 0x3b, 0x0030}, /* 00,3B,30,aa */ + {0xaa, 0x3c, 0x00d4}, /* 00,3C,D4,aa */ + {0xaa, 0x03, 0x0003}, /* 00,03,03,aa */ + {0xaa, 0x10, 0x00fc}, /* 00,10,fc,aa */ + {0xaa, 0x36, 0x0018}, /* 00,36,18,aa */ + {0xaa, 0x37, 0x006a}, /* 00,37,6A,aa */ + {0xaa, 0x3d, 0x0018}, /* 00,3D,18,aa */ + {} +}; + +static const struct usb_action MC501CB_NoFliker[] = { + {0xaa, 0x03, 0x0003}, /* 00,03,03,aa */ + {0xaa, 0x10, 0x00fc}, /* 00,10,fc,aa */ + {0xaa, 0x36, 0x0018}, /* 00,36,18,aa */ + {0xaa, 0x37, 0x006a}, /* 00,37,6A,aa */ + {0xaa, 0x3d, 0x0018}, /* 00,3D,18,aa */ + {0xaa, 0x3e, 0x006a}, /* 00,3E,6A,aa */ + {0xaa, 0x3b, 0x0018}, /* 00,3B,18,aa */ + {0xaa, 0x3c, 0x006a}, /* 00,3C,6A,aa */ + {0xaa, 0x03, 0x0003}, /* 00,03,03,aa */ + {0xaa, 0x10, 0x00fc}, /* 00,10,fc,aa */ + {0xaa, 0x36, 0x0030}, /* 00,36,30,aa */ + {0xaa, 0x37, 0x00d4}, /* 00,37,D4,aa */ + {0xaa, 0x3d, 0x0030}, /* 00,3D,30,aa */ + {} +}; + +static const struct usb_action MC501CB_NoFlikerScale[] = { + {0xaa, 0x03, 0x0003}, /* 00,03,03,aa */ + {0xaa, 0x10, 0x00fc}, /* 00,10,fc,aa */ + {0xaa, 0x36, 0x0030}, /* 00,36,30,aa */ + {0xaa, 0x37, 0x00d4}, /* 00,37,D4,aa */ + {0xaa, 0x3d, 0x0030}, /* 00,3D,30,aa */ + {0xaa, 0x3e, 0x00d4}, /* 00,3E,D4,aa */ + {0xaa, 0x3b, 0x0030}, /* 00,3B,30,aa */ + {0xaa, 0x3c, 0x00d4}, /* 00,3C,D4,aa */ + {} +}; + +/* from zs211.inf - HKR,%OV7620%,Initial - 640x480 */ +static const struct usb_action OV7620_mode0[] = { + {0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL}, /* 00,00,01,cc */ + {0xa0, 0x40, ZC3XX_R002_CLOCKSELECT}, /* 00,02,40,cc */ + {0xa0, 0x00, ZC3XX_R008_CLOCKSETTING}, /* 00,08,00,cc */ + {0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING}, /* 00,01,01,cc */ + {0xa0, 0x06, ZC3XX_R010_CMOSSENSORSELECT}, /* 00,10,06,cc */ + {0xa0, 0x02, ZC3XX_R083_RGAINADDR}, /* 00,83,02,cc */ + {0xa0, 0x01, ZC3XX_R085_BGAINADDR}, /* 00,85,01,cc */ + {0xa0, 0x80, ZC3XX_R086_EXPTIMEHIGH}, /* 00,86,80,cc */ + {0xa0, 0x81, ZC3XX_R087_EXPTIMEMID}, /* 00,87,81,cc */ + {0xa0, 0x10, ZC3XX_R088_EXPTIMELOW}, /* 00,88,10,cc */ + {0xa0, 0xa1, ZC3XX_R08B_I2CDEVICEADDR}, /* 00,8b,a1,cc */ + {0xa0, 0x08, ZC3XX_R08D_COMPABILITYMODE}, /* 00,8d,08,cc */ + {0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH}, /* 00,03,02,cc */ + {0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW}, /* 00,04,80,cc */ + {0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH}, /* 00,05,01,cc */ + {0xa0, 0xd8, ZC3XX_R006_FRAMEHEIGHTLOW}, /* 00,06,d8,cc */ + {0xa0, 0x03, ZC3XX_R012_VIDEOCONTROLFUNC}, /* 00,12,03,cc */ + {0xa0, 0x01, ZC3XX_R012_VIDEOCONTROLFUNC}, /* 00,12,01,cc */ + {0xa0, 0x00, ZC3XX_R098_WINYSTARTLOW}, /* 00,98,00,cc */ + {0xa0, 0x00, ZC3XX_R09A_WINXSTARTLOW}, /* 00,9a,00,cc */ + {0xa0, 0x00, ZC3XX_R11A_FIRSTYLOW}, /* 01,1a,00,cc */ + {0xa0, 0x00, ZC3XX_R11C_FIRSTXLOW}, /* 01,1c,00,cc */ + {0xa0, 0xde, ZC3XX_R09C_WINHEIGHTLOW}, /* 00,9c,de,cc */ + {0xa0, 0x86, ZC3XX_R09E_WINWIDTHLOW}, /* 00,9e,86,cc */ + {0xaa, 0x12, 0x0088}, /* 00,12,88,aa */ + {0xaa, 0x12, 0x0048}, /* 00,12,48,aa */ + {0xaa, 0x75, 0x008a}, /* 00,75,8a,aa */ + {0xaa, 0x13, 0x00a3}, /* 00,13,a3,aa */ + {0xaa, 0x04, 0x0000}, /* 00,04,00,aa */ + {0xaa, 0x05, 0x0000}, /* 00,05,00,aa */ + {0xaa, 0x14, 0x0000}, /* 00,14,00,aa */ + {0xaa, 0x15, 0x0004}, /* 00,15,04,aa */ + {0xaa, 0x17, 0x0018}, /* 00,17,18,aa */ + {0xaa, 0x18, 0x00ba}, /* 00,18,ba,aa */ + {0xaa, 0x19, 0x0002}, /* 00,19,02,aa */ + {0xaa, 0x1a, 0x00f1}, /* 00,1a,f1,aa */ + {0xaa, 0x20, 0x0040}, /* 00,20,40,aa */ + {0xaa, 0x24, 0x0088}, /* 00,24,88,aa */ + {0xaa, 0x25, 0x0078}, /* 00,25,78,aa */ + {0xaa, 0x27, 0x00f6}, /* 00,27,f6,aa */ + {0xaa, 0x28, 0x00a0}, /* 00,28,a0,aa */ + {0xaa, 0x21, 0x0000}, /* 00,21,00,aa */ + {0xaa, 0x2a, 0x0083}, /* 00,2a,83,aa */ + {0xaa, 0x2b, 0x0096}, /* 00,2b,96,aa */ + {0xaa, 0x2d, 0x0005}, /* 00,2d,05,aa */ + {0xaa, 0x74, 0x0020}, /* 00,74,20,aa */ + {0xaa, 0x61, 0x0068}, /* 00,61,68,aa */ + {0xaa, 0x64, 0x0088}, /* 00,64,88,aa */ + {0xaa, 0x00, 0x0000}, /* 00,00,00,aa */ + {0xaa, 0x06, 0x0080}, /* 00,06,80,aa */ + {0xaa, 0x01, 0x0090}, /* 00,01,90,aa */ + {0xaa, 0x02, 0x0030}, /* 00,02,30,aa */ + {0xa0, 0x77, ZC3XX_R101_SENSORCORRECTION}, /* 01,01,77,cc */ + {0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC}, /* 00,12,05,cc */ + {0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE}, /* 01,00,0d,cc */ + {0xa0, 0x06, ZC3XX_R189_AWBSTATUS}, /* 01,89,06,cc */ + {0xa0, 0x00, 0x01ad}, /* 01,ad,00,cc */ + {0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE}, /* 01,c5,03,cc */ + {0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05}, /* 01,cb,13,cc */ + {0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE}, /* 02,50,08,cc */ + {0xa0, 0x08, ZC3XX_R301_EEPROMACCESS}, /* 03,01,08,cc */ + {0xa0, 0x68, ZC3XX_R116_RGAIN}, /* 01,16,68,cc */ + {0xa0, 0x52, ZC3XX_R118_BGAIN}, /* 01,18,52,cc */ + {0xa0, 0x40, ZC3XX_R11D_GLOBALGAIN}, /* 01,1d,40,cc */ + {0xa0, 0x02, ZC3XX_R180_AUTOCORRECTENABLE}, /* 01,80,02,cc */ + {0xa0, 0x50, ZC3XX_R1A8_DIGITALGAIN}, /* 01,a8,50,cc */ + {} +}; + +/* from zs211.inf - HKR,%OV7620%,InitialScale - 320x240 */ +static const struct usb_action OV7620_mode1[] = { + {0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL}, /* 00,00,01,cc */ + {0xa0, 0x50, ZC3XX_R002_CLOCKSELECT}, /* 00,02,50,cc */ + {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, /* 00,08,00,cc */ + /* mx change? */ + {0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING}, /* 00,01,01,cc */ + {0xa0, 0x06, ZC3XX_R010_CMOSSENSORSELECT}, /* 00,10,06,cc */ + {0xa0, 0x02, ZC3XX_R083_RGAINADDR}, /* 00,83,02,cc */ + {0xa0, 0x01, ZC3XX_R085_BGAINADDR}, /* 00,85,01,cc */ + {0xa0, 0x80, ZC3XX_R086_EXPTIMEHIGH}, /* 00,86,80,cc */ + {0xa0, 0x81, ZC3XX_R087_EXPTIMEMID}, /* 00,87,81,cc */ + {0xa0, 0x10, ZC3XX_R088_EXPTIMELOW}, /* 00,88,10,cc */ + {0xa0, 0xa1, ZC3XX_R08B_I2CDEVICEADDR}, /* 00,8b,a1,cc */ + {0xa0, 0x08, ZC3XX_R08D_COMPABILITYMODE}, /* 00,8d,08,cc */ + {0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH}, /* 00,03,02,cc */ + {0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW}, /* 00,04,80,cc */ + {0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH}, /* 00,05,01,cc */ + {0xa0, 0xd0, ZC3XX_R006_FRAMEHEIGHTLOW}, /* 00,06,d0,cc */ + {0xa0, 0x03, ZC3XX_R012_VIDEOCONTROLFUNC}, /* 00,12,03,cc */ + {0xa0, 0x01, ZC3XX_R012_VIDEOCONTROLFUNC}, /* 00,12,01,cc */ + {0xa0, 0x00, ZC3XX_R098_WINYSTARTLOW}, /* 00,98,00,cc */ + {0xa0, 0x00, ZC3XX_R09A_WINXSTARTLOW}, /* 00,9a,00,cc */ + {0xa0, 0x00, ZC3XX_R11A_FIRSTYLOW}, /* 01,1a,00,cc */ + {0xa0, 0x00, ZC3XX_R11C_FIRSTXLOW}, /* 01,1c,00,cc */ + {0xa0, 0xd6, ZC3XX_R09C_WINHEIGHTLOW}, /* 00,9c,d6,cc */ + /* OV7648 00,9c,d8,cc */ + {0xa0, 0x88, ZC3XX_R09E_WINWIDTHLOW}, /* 00,9e,88,cc */ + {0xaa, 0x12, 0x0088}, /* 00,12,88,aa */ + {0xaa, 0x12, 0x0048}, /* 00,12,48,aa */ + {0xaa, 0x75, 0x008a}, /* 00,75,8a,aa */ + {0xaa, 0x13, 0x00a3}, /* 00,13,a3,aa */ + {0xaa, 0x04, 0x0000}, /* 00,04,00,aa */ + {0xaa, 0x05, 0x0000}, /* 00,05,00,aa */ + {0xaa, 0x14, 0x0000}, /* 00,14,00,aa */ + {0xaa, 0x15, 0x0004}, /* 00,15,04,aa */ + {0xaa, 0x24, 0x0088}, /* 00,24,88,aa */ + {0xaa, 0x25, 0x0078}, /* 00,25,78,aa */ + {0xaa, 0x17, 0x0018}, /* 00,17,18,aa */ + {0xaa, 0x18, 0x00ba}, /* 00,18,ba,aa */ + {0xaa, 0x19, 0x0002}, /* 00,19,02,aa */ + {0xaa, 0x1a, 0x00f2}, /* 00,1a,f2,aa */ + {0xaa, 0x20, 0x0040}, /* 00,20,40,aa */ + {0xaa, 0x27, 0x00f6}, /* 00,27,f6,aa */ + {0xaa, 0x28, 0x00a0}, /* 00,28,a0,aa */ + {0xaa, 0x21, 0x0000}, /* 00,21,00,aa */ + {0xaa, 0x2a, 0x0083}, /* 00,2a,83,aa */ + {0xaa, 0x2b, 0x0096}, /* 00,2b,96,aa */ + {0xaa, 0x2d, 0x0005}, /* 00,2d,05,aa */ + {0xaa, 0x74, 0x0020}, /* 00,74,20,aa */ + {0xaa, 0x61, 0x0068}, /* 00,61,68,aa */ + {0xaa, 0x64, 0x0088}, /* 00,64,88,aa */ + {0xaa, 0x00, 0x0000}, /* 00,00,00,aa */ + {0xaa, 0x06, 0x0080}, /* 00,06,80,aa */ + {0xaa, 0x01, 0x0090}, /* 00,01,90,aa */ + {0xaa, 0x02, 0x0030}, /* 00,02,30,aa */ + {0xa0, 0x77, ZC3XX_R101_SENSORCORRECTION}, /* 01,01,77,cc */ + {0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC}, /* 00,12,05,cc */ + {0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE}, /* 01,00,0d,cc */ + {0xa0, 0x06, ZC3XX_R189_AWBSTATUS}, /* 01,89,06,cc */ + {0xa0, 0x00, 0x01ad}, /* 01,ad,00,cc */ + {0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE}, /* 01,c5,03,cc */ + {0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05}, /* 01,cb,13,cc */ + {0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE}, /* 02,50,08,cc */ + {0xa0, 0x08, ZC3XX_R301_EEPROMACCESS}, /* 03,01,08,cc */ + {0xa0, 0x68, ZC3XX_R116_RGAIN}, /* 01,16,68,cc */ + {0xa0, 0x52, ZC3XX_R118_BGAIN}, /* 01,18,52,cc */ + {0xa0, 0x50, ZC3XX_R11D_GLOBALGAIN}, /* 01,1d,50,cc */ + {0xa0, 0x02, ZC3XX_R180_AUTOCORRECTENABLE}, /* 01,80,02,cc */ + {0xa0, 0x50, ZC3XX_R1A8_DIGITALGAIN}, /* 01,a8,50,cc */ + {} +}; + +/* from zs211.inf - HKR,%OV7620%\AE,50HZ */ +static const struct usb_action OV7620_50HZ[] = { + {0xaa, 0x13, 0x00a3}, /* 00,13,a3,aa */ + {0xdd, 0x00, 0x0100}, /* 00,01,00,dd */ + {0xaa, 0x2b, 0x0096}, /* 00,2b,96,aa */ + {0xaa, 0x75, 0x008a}, /* 00,75,8a,aa */ + {0xaa, 0x2d, 0x0005}, /* 00,2d,05,aa */ + {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc */ + {0xa0, 0x04, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,04,cc */ + {0xa0, 0x18, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,18,cc */ + {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */ + {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc */ + {0xa0, 0x83, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,83,cc */ + {0xaa, 0x10, 0x0082}, /* 00,10,82,aa */ + {0xaa, 0x76, 0x0003}, /* 00,76,03,aa */ +/* {0xa0, 0x40, ZC3XX_R002_CLOCKSELECT}, * 00,02,40,cc + if mode0 (640x480) */ + {} +}; + +/* from zs211.inf - HKR,%OV7620%\AE,60HZ */ +static const struct usb_action OV7620_60HZ[] = { + {0xaa, 0x13, 0x00a3}, /* 00,13,a3,aa */ + /* (bug in zs211.inf) */ + {0xdd, 0x00, 0x0100}, /* 00,01,00,dd */ + {0xaa, 0x2b, 0x0000}, /* 00,2b,00,aa */ + {0xaa, 0x75, 0x008a}, /* 00,75,8a,aa */ + {0xaa, 0x2d, 0x0005}, /* 00,2d,05,aa */ + {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc */ + {0xa0, 0x04, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,04,cc */ + {0xa0, 0x18, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,18,cc */ + {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */ + {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc */ + {0xa0, 0x83, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,83,cc */ + {0xaa, 0x10, 0x0020}, /* 00,10,20,aa */ + {0xaa, 0x76, 0x0003}, /* 00,76,03,aa */ +/* {0xa0, 0x40, ZC3XX_R002_CLOCKSELECT}, * 00,02,40,cc + * if mode0 (640x480) */ +/* ?? in gspca v1, it was + {0xa0, 0x00, 0x0039}, * 00,00,00,dd * + {0xa1, 0x01, 0x0037}, */ + {} +}; + +/* from zs211.inf - HKR,%OV7620%\AE,NoFliker */ +static const struct usb_action OV7620_NoFliker[] = { + {0xaa, 0x13, 0x00a3}, /* 00,13,a3,aa */ + /* (bug in zs211.inf) */ + {0xdd, 0x00, 0x0100}, /* 00,01,00,dd */ + {0xaa, 0x2b, 0x0000}, /* 00,2b,00,aa */ + {0xaa, 0x75, 0x008e}, /* 00,75,8e,aa */ + {0xaa, 0x2d, 0x0001}, /* 00,2d,01,aa */ + {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc */ + {0xa0, 0x04, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,04,cc */ + {0xa0, 0x18, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,18,cc */ + {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */ + {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc */ + {0xa0, 0x01, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,01,cc */ +/* {0xa0, 0x44, ZC3XX_R002_CLOCKSELECT}, * 00,02,44,cc + - if mode1 (320x240) */ +/* ?? was + {0xa0, 0x00, 0x0039}, * 00,00,00,dd * + {0xa1, 0x01, 0x0037}, */ + {} +}; + +static const struct usb_action ov7630c_Initial[] = { + {0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL}, + {0xa0, 0x10, ZC3XX_R002_CLOCKSELECT}, + {0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL}, + {0xa0, 0x10, ZC3XX_R002_CLOCKSELECT}, + {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, + {0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING}, + {0xa0, 0x06, ZC3XX_R010_CMOSSENSORSELECT}, + {0xa0, 0xa1, ZC3XX_R08B_I2CDEVICEADDR}, + {0xa0, 0x08, ZC3XX_R08D_COMPABILITYMODE}, + {0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH}, + {0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW}, + {0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH}, + {0xa0, 0xe0, ZC3XX_R006_FRAMEHEIGHTLOW}, + {0xa0, 0x01, ZC3XX_R012_VIDEOCONTROLFUNC}, + {0xaa, 0x12, 0x0080}, + {0xa0, 0x02, ZC3XX_R083_RGAINADDR}, + {0xa0, 0x01, ZC3XX_R085_BGAINADDR}, + {0xa0, 0x90, ZC3XX_R086_EXPTIMEHIGH}, + {0xa0, 0x91, ZC3XX_R087_EXPTIMEMID}, + {0xa0, 0x10, ZC3XX_R088_EXPTIMELOW}, + {0xa0, 0x00, ZC3XX_R098_WINYSTARTLOW}, + {0xa0, 0x00, ZC3XX_R09A_WINXSTARTLOW}, + {0xa0, 0x00, ZC3XX_R11A_FIRSTYLOW}, + {0xa0, 0x00, ZC3XX_R11C_FIRSTXLOW}, + {0xa0, 0xd8, ZC3XX_R09C_WINHEIGHTLOW}, + {0xa0, 0x88, ZC3XX_R09E_WINWIDTHLOW}, + {0xaa, 0x12, 0x0069}, + {0xaa, 0x04, 0x0020}, + {0xaa, 0x06, 0x0050}, + {0xaa, 0x13, 0x0083}, + {0xaa, 0x14, 0x0000}, + {0xaa, 0x15, 0x0024}, + {0xaa, 0x17, 0x0018}, + {0xaa, 0x18, 0x00ba}, + {0xaa, 0x19, 0x0002}, + {0xaa, 0x1a, 0x00f6}, + {0xaa, 0x1b, 0x0002}, + {0xaa, 0x20, 0x00c2}, + {0xaa, 0x24, 0x0060}, + {0xaa, 0x25, 0x0040}, + {0xaa, 0x26, 0x0030}, + {0xaa, 0x27, 0x00ea}, + {0xaa, 0x28, 0x00a0}, + {0xaa, 0x21, 0x0000}, + {0xaa, 0x2a, 0x0081}, + {0xaa, 0x2b, 0x0096}, + {0xaa, 0x2d, 0x0094}, + {0xaa, 0x2f, 0x003d}, + {0xaa, 0x30, 0x0024}, + {0xaa, 0x60, 0x0000}, + {0xaa, 0x61, 0x0040}, + {0xaa, 0x68, 0x007c}, + {0xaa, 0x6f, 0x0015}, + {0xaa, 0x75, 0x0088}, + {0xaa, 0x77, 0x00b5}, + {0xaa, 0x01, 0x0060}, + {0xaa, 0x02, 0x0060}, + {0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC}, + {0xa0, 0x77, ZC3XX_R101_SENSORCORRECTION}, + {0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE}, + {0xa0, 0x06, ZC3XX_R189_AWBSTATUS}, + {0xa0, 0x04, ZC3XX_R1A7_CALCGLOBALMEAN}, + {0xa0, 0x00, 0x01ad}, + {0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE}, + {0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05}, + {0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE}, + {0xa0, 0x08, ZC3XX_R301_EEPROMACCESS}, + {0xa0, 0x60, ZC3XX_R116_RGAIN}, + {0xa0, 0x46, ZC3XX_R118_BGAIN}, + {0xa0, 0x04, ZC3XX_R113_RGB03}, +/* 0x10, */ + {0xa1, 0x01, 0x0002}, + {0xa0, 0x50, ZC3XX_R10A_RGB00}, /* matrix */ + {0xa0, 0xf8, ZC3XX_R10B_RGB01}, + {0xa0, 0xf8, ZC3XX_R10C_RGB02}, + {0xa0, 0xf8, ZC3XX_R10D_RGB10}, + {0xa0, 0x50, ZC3XX_R10E_RGB11}, + {0xa0, 0xf8, ZC3XX_R10F_RGB12}, + {0xa0, 0xf8, ZC3XX_R110_RGB20}, + {0xa0, 0xf8, ZC3XX_R111_RGB21}, + {0xa0, 0x50, ZC3XX_R112_RGB22}, +/* 0x03, */ + {0xa1, 0x01, 0x0008}, + {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, /* clock ? */ + {0xa0, 0x08, ZC3XX_R1C6_SHARPNESS00}, /* sharpness+ */ + {0xa1, 0x01, 0x01c8}, + {0xa1, 0x01, 0x01c9}, + {0xa1, 0x01, 0x01ca}, + {0xa0, 0x0f, ZC3XX_R1CB_SHARPNESS05}, /* sharpness- */ + {0xa0, 0x01, ZC3XX_R120_GAMMA00}, /* gamma 2 ?*/ + {0xa0, 0x0c, ZC3XX_R121_GAMMA01}, + {0xa0, 0x1f, ZC3XX_R122_GAMMA02}, + {0xa0, 0x3a, ZC3XX_R123_GAMMA03}, + {0xa0, 0x53, ZC3XX_R124_GAMMA04}, + {0xa0, 0x6d, ZC3XX_R125_GAMMA05}, + {0xa0, 0x85, ZC3XX_R126_GAMMA06}, + {0xa0, 0x9c, ZC3XX_R127_GAMMA07}, + {0xa0, 0xb0, ZC3XX_R128_GAMMA08}, + {0xa0, 0xc2, ZC3XX_R129_GAMMA09}, + {0xa0, 0xd1, ZC3XX_R12A_GAMMA0A}, + {0xa0, 0xde, ZC3XX_R12B_GAMMA0B}, + {0xa0, 0xe9, ZC3XX_R12C_GAMMA0C}, + {0xa0, 0xf2, ZC3XX_R12D_GAMMA0D}, + {0xa0, 0xf9, ZC3XX_R12E_GAMMA0E}, + {0xa0, 0xff, ZC3XX_R12F_GAMMA0F}, + {0xa0, 0x05, ZC3XX_R130_GAMMA10}, + {0xa0, 0x0f, ZC3XX_R131_GAMMA11}, + {0xa0, 0x16, ZC3XX_R132_GAMMA12}, + {0xa0, 0x1a, ZC3XX_R133_GAMMA13}, + {0xa0, 0x19, ZC3XX_R134_GAMMA14}, + {0xa0, 0x19, ZC3XX_R135_GAMMA15}, + {0xa0, 0x17, ZC3XX_R136_GAMMA16}, + {0xa0, 0x15, ZC3XX_R137_GAMMA17}, + {0xa0, 0x12, ZC3XX_R138_GAMMA18}, + {0xa0, 0x10, ZC3XX_R139_GAMMA19}, + {0xa0, 0x0e, ZC3XX_R13A_GAMMA1A}, + {0xa0, 0x0b, ZC3XX_R13B_GAMMA1B}, + {0xa0, 0x09, ZC3XX_R13C_GAMMA1C}, + {0xa0, 0x08, ZC3XX_R13D_GAMMA1D}, + {0xa0, 0x06, ZC3XX_R13E_GAMMA1E}, + {0xa0, 0x03, ZC3XX_R13F_GAMMA1F}, + {0xa0, 0x50, ZC3XX_R10A_RGB00}, /* matrix */ + {0xa0, 0xf8, ZC3XX_R10B_RGB01}, + {0xa0, 0xf8, ZC3XX_R10C_RGB02}, + {0xa0, 0xf8, ZC3XX_R10D_RGB10}, + {0xa0, 0x50, ZC3XX_R10E_RGB11}, + {0xa0, 0xf8, ZC3XX_R10F_RGB12}, + {0xa0, 0xf8, ZC3XX_R110_RGB20}, + {0xa0, 0xf8, ZC3XX_R111_RGB21}, + {0xa0, 0x50, ZC3XX_R112_RGB22}, + + {0xa1, 0x01, 0x0180}, + {0xa0, 0x00, ZC3XX_R180_AUTOCORRECTENABLE}, + {0xaa, 0x10, 0x001b}, + {0xaa, 0x76, 0x0002}, + {0xaa, 0x2a, 0x0081}, + {0xaa, 0x2b, 0x0000}, + {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, + {0xa0, 0x01, ZC3XX_R191_EXPOSURELIMITMID}, + {0xa0, 0xb8, ZC3XX_R192_EXPOSURELIMITLOW}, + {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, + {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, + {0xa0, 0x37, ZC3XX_R197_ANTIFLICKERLOW}, + {0xa0, 0x10, ZC3XX_R18C_AEFREEZE}, + {0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE}, + {0xa0, 0x10, ZC3XX_R1A9_DIGITALLIMITDIFF}, + {0xa0, 0x26, ZC3XX_R1AA_DIGITALGAINSTEP}, + {0xa0, 0x50, ZC3XX_R11D_GLOBALGAIN}, + {0xa0, 0x02, ZC3XX_R180_AUTOCORRECTENABLE}, + {0xa0, 0x40, ZC3XX_R180_AUTOCORRECTENABLE}, + {0xaa, 0x13, 0x0083}, /* 40 */ + {0xa1, 0x01, 0x0180}, + {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE}, + {} +}; + +static const struct usb_action ov7630c_InitialScale[] = { + {0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL}, + {0xa0, 0x00, ZC3XX_R002_CLOCKSELECT}, + {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, + {0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING}, + {0xa0, 0x06, ZC3XX_R010_CMOSSENSORSELECT}, + {0xa0, 0xa1, ZC3XX_R08B_I2CDEVICEADDR}, + {0xa0, 0x08, ZC3XX_R08D_COMPABILITYMODE}, + {0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH}, + {0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW}, + {0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH}, + {0xa0, 0xe0, ZC3XX_R006_FRAMEHEIGHTLOW}, + {0xa0, 0x01, ZC3XX_R012_VIDEOCONTROLFUNC}, + + {0xaa, 0x12, 0x0080}, + {0xa0, 0x02, ZC3XX_R083_RGAINADDR}, + {0xa0, 0x01, ZC3XX_R085_BGAINADDR}, + {0xa0, 0x90, ZC3XX_R086_EXPTIMEHIGH}, + {0xa0, 0x91, ZC3XX_R087_EXPTIMEMID}, + {0xa0, 0x10, ZC3XX_R088_EXPTIMELOW}, + {0xa0, 0x00, ZC3XX_R098_WINYSTARTLOW}, + {0xa0, 0x00, ZC3XX_R09A_WINXSTARTLOW}, + {0xa0, 0x00, ZC3XX_R11A_FIRSTYLOW}, + {0xa0, 0x00, ZC3XX_R11C_FIRSTXLOW}, + {0xa0, 0xe6, ZC3XX_R09C_WINHEIGHTLOW}, + {0xa0, 0x86, ZC3XX_R09E_WINWIDTHLOW}, + {0xaa, 0x12, 0x0069}, /* i2c */ + {0xaa, 0x04, 0x0020}, + {0xaa, 0x06, 0x0050}, + {0xaa, 0x13, 0x00c3}, + {0xaa, 0x14, 0x0000}, + {0xaa, 0x15, 0x0024}, + {0xaa, 0x19, 0x0003}, + {0xaa, 0x1a, 0x00f6}, + {0xaa, 0x1b, 0x0002}, + {0xaa, 0x20, 0x00c2}, + {0xaa, 0x24, 0x0060}, + {0xaa, 0x25, 0x0040}, + {0xaa, 0x26, 0x0030}, + {0xaa, 0x27, 0x00ea}, + {0xaa, 0x28, 0x00a0}, + {0xaa, 0x21, 0x0000}, + {0xaa, 0x2a, 0x0081}, + {0xaa, 0x2b, 0x0096}, + {0xaa, 0x2d, 0x0084}, + {0xaa, 0x2f, 0x003d}, + {0xaa, 0x30, 0x0024}, + {0xaa, 0x60, 0x0000}, + {0xaa, 0x61, 0x0040}, + {0xaa, 0x68, 0x007c}, + {0xaa, 0x6f, 0x0015}, + {0xaa, 0x75, 0x0088}, + {0xaa, 0x77, 0x00b5}, + {0xaa, 0x01, 0x0060}, + {0xaa, 0x02, 0x0060}, + {0xaa, 0x17, 0x0018}, + {0xaa, 0x18, 0x00ba}, + {0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC}, + {0xa0, 0x77, ZC3XX_R101_SENSORCORRECTION}, + {0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE}, + {0xa0, 0x06, ZC3XX_R189_AWBSTATUS}, + {0xa0, 0x04, ZC3XX_R1A7_CALCGLOBALMEAN}, + {0xa0, 0x00, 0x01ad}, + {0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE}, + {0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05}, + {0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE}, + {0xa0, 0x08, ZC3XX_R301_EEPROMACCESS}, + {0xa0, 0x60, ZC3XX_R116_RGAIN}, + {0xa0, 0x46, ZC3XX_R118_BGAIN}, + {0xa0, 0x04, ZC3XX_R113_RGB03}, + + {0xa1, 0x01, 0x0002}, + {0xa0, 0x4e, ZC3XX_R10A_RGB00}, /* matrix */ + {0xa0, 0xfe, ZC3XX_R10B_RGB01}, + {0xa0, 0xf4, ZC3XX_R10C_RGB02}, + {0xa0, 0xf7, ZC3XX_R10D_RGB10}, + {0xa0, 0x4d, ZC3XX_R10E_RGB11}, + {0xa0, 0xfc, ZC3XX_R10F_RGB12}, + {0xa0, 0x00, ZC3XX_R110_RGB20}, + {0xa0, 0xf6, ZC3XX_R111_RGB21}, + {0xa0, 0x4a, ZC3XX_R112_RGB22}, + + {0xa1, 0x01, 0x0008}, + {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, /* clock ? */ + {0xa0, 0x08, ZC3XX_R1C6_SHARPNESS00}, /* sharpness+ */ + {0xa1, 0x01, 0x01c8}, + {0xa1, 0x01, 0x01c9}, + {0xa1, 0x01, 0x01ca}, + {0xa0, 0x0f, ZC3XX_R1CB_SHARPNESS05}, /* sharpness- */ + {0xa0, 0x16, ZC3XX_R120_GAMMA00}, /* gamma ~4 */ + {0xa0, 0x3a, ZC3XX_R121_GAMMA01}, + {0xa0, 0x5b, ZC3XX_R122_GAMMA02}, + {0xa0, 0x7c, ZC3XX_R123_GAMMA03}, + {0xa0, 0x94, ZC3XX_R124_GAMMA04}, + {0xa0, 0xa9, ZC3XX_R125_GAMMA05}, + {0xa0, 0xbb, ZC3XX_R126_GAMMA06}, + {0xa0, 0xca, ZC3XX_R127_GAMMA07}, + {0xa0, 0xd7, ZC3XX_R128_GAMMA08}, + {0xa0, 0xe1, ZC3XX_R129_GAMMA09}, + {0xa0, 0xea, ZC3XX_R12A_GAMMA0A}, + {0xa0, 0xf1, ZC3XX_R12B_GAMMA0B}, + {0xa0, 0xf7, ZC3XX_R12C_GAMMA0C}, + {0xa0, 0xfc, ZC3XX_R12D_GAMMA0D}, + {0xa0, 0xff, ZC3XX_R12E_GAMMA0E}, + {0xa0, 0xff, ZC3XX_R12F_GAMMA0F}, + {0xa0, 0x20, ZC3XX_R130_GAMMA10}, + {0xa0, 0x22, ZC3XX_R131_GAMMA11}, + {0xa0, 0x20, ZC3XX_R132_GAMMA12}, + {0xa0, 0x1c, ZC3XX_R133_GAMMA13}, + {0xa0, 0x16, ZC3XX_R134_GAMMA14}, + {0xa0, 0x13, ZC3XX_R135_GAMMA15}, + {0xa0, 0x10, ZC3XX_R136_GAMMA16}, + {0xa0, 0x0d, ZC3XX_R137_GAMMA17}, + {0xa0, 0x0b, ZC3XX_R138_GAMMA18}, + {0xa0, 0x09, ZC3XX_R139_GAMMA19}, + {0xa0, 0x07, ZC3XX_R13A_GAMMA1A}, + {0xa0, 0x06, ZC3XX_R13B_GAMMA1B}, + {0xa0, 0x05, ZC3XX_R13C_GAMMA1C}, + {0xa0, 0x04, ZC3XX_R13D_GAMMA1D}, + {0xa0, 0x00, ZC3XX_R13E_GAMMA1E}, + {0xa0, 0x01, ZC3XX_R13F_GAMMA1F}, + {0xa0, 0x4e, ZC3XX_R10A_RGB00}, /* matrix */ + {0xa0, 0xfe, ZC3XX_R10B_RGB01}, + {0xa0, 0xf4, ZC3XX_R10C_RGB02}, + {0xa0, 0xf7, ZC3XX_R10D_RGB10}, + {0xa0, 0x4d, ZC3XX_R10E_RGB11}, + {0xa0, 0xfc, ZC3XX_R10F_RGB12}, + {0xa0, 0x00, ZC3XX_R110_RGB20}, + {0xa0, 0xf6, ZC3XX_R111_RGB21}, + {0xa0, 0x4a, ZC3XX_R112_RGB22}, + + {0xa1, 0x01, 0x0180}, + {0xa0, 0x00, ZC3XX_R180_AUTOCORRECTENABLE}, + {0xaa, 0x10, 0x000d}, + {0xaa, 0x76, 0x0002}, + {0xaa, 0x2a, 0x0081}, + {0xaa, 0x2b, 0x0000}, + {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, + {0xa0, 0x00, ZC3XX_R191_EXPOSURELIMITMID}, + {0xa0, 0xd8, ZC3XX_R192_EXPOSURELIMITLOW}, + {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, + {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, + {0xa0, 0x1b, ZC3XX_R197_ANTIFLICKERLOW}, + {0xa0, 0x10, ZC3XX_R18C_AEFREEZE}, + {0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE}, + {0xa0, 0x10, ZC3XX_R1A9_DIGITALLIMITDIFF}, + {0xa0, 0x26, ZC3XX_R1AA_DIGITALGAINSTEP}, + {0xa0, 0x50, ZC3XX_R11D_GLOBALGAIN}, + {0xa0, 0x02, ZC3XX_R180_AUTOCORRECTENABLE}, + {0xa0, 0x40, ZC3XX_R180_AUTOCORRECTENABLE}, + {0xaa, 0x13, 0x00c3}, + + {0xa1, 0x01, 0x0180}, + {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE}, + {} +}; + +static const struct usb_action pas106b_Initial_com[] = { +/* Sream and Sensor specific */ + {0xa1, 0x01, 0x0010}, /* CMOSSensorSelect */ +/* System */ + {0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL}, /* SystemControl */ + {0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL}, /* SystemControl */ +/* Picture size */ + {0xa0, 0x00, ZC3XX_R002_CLOCKSELECT}, /* ClockSelect */ + {0xa0, 0x03, 0x003a}, + {0xa0, 0x0c, 0x003b}, + {0xa0, 0x04, 0x0038}, + {} +}; + +static const struct usb_action pas106b_Initial[] = { /* 176x144 */ +/* JPEG control */ + {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, /* ClockSetting */ +/* Sream and Sensor specific */ + {0xa0, 0x0f, ZC3XX_R010_CMOSSENSORSELECT}, /* CMOSSensorSelect */ +/* Picture size */ + {0xa0, 0x00, ZC3XX_R003_FRAMEWIDTHHIGH}, /* FrameWidthHigh 00 */ + {0xa0, 0xb0, ZC3XX_R004_FRAMEWIDTHLOW}, /* FrameWidthLow B0 */ + {0xa0, 0x00, ZC3XX_R005_FRAMEHEIGHTHIGH}, /* FrameHeightHigh 00 */ + {0xa0, 0x90, ZC3XX_R006_FRAMEHEIGHTLOW}, /* FrameHightLow 90 */ +/* System */ + {0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING}, /* SystemOperating */ +/* Sream and Sensor specific */ + {0xa0, 0x03, ZC3XX_R012_VIDEOCONTROLFUNC}, /* VideoControlFunction */ + {0xa0, 0x01, ZC3XX_R012_VIDEOCONTROLFUNC}, /* VideoControlFunction */ +/* Sensor Interface */ + {0xa0, 0x08, ZC3XX_R08D_COMPABILITYMODE}, /* Compatibily Mode */ +/* Window inside sensor array */ + {0xa0, 0x03, ZC3XX_R09A_WINXSTARTLOW}, /* WinXStartLow */ + {0xa0, 0x00, ZC3XX_R11A_FIRSTYLOW}, /* FirstYLow */ + {0xa0, 0x03, ZC3XX_R11C_FIRSTXLOW}, /* FirstxLow */ + {0xa0, 0x28, ZC3XX_R09C_WINHEIGHTLOW}, /* WinHeightLow */ + {0xa0, 0x68, ZC3XX_R09E_WINWIDTHLOW}, /* WinWidthLow */ +/* Init the sensor */ + {0xaa, 0x02, 0x0004}, + {0xaa, 0x08, 0x0000}, + {0xaa, 0x09, 0x0005}, + {0xaa, 0x0a, 0x0002}, + {0xaa, 0x0b, 0x0002}, + {0xaa, 0x0c, 0x0005}, + {0xaa, 0x0d, 0x0000}, + {0xaa, 0x0e, 0x0002}, + {0xaa, 0x14, 0x0081}, + +/* Other registors */ + {0xa0, 0x37, ZC3XX_R101_SENSORCORRECTION}, /* SensorCorrection */ +/* Frame retreiving */ + {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* AutoAdjustFPS */ +/* Gains */ + {0xa0, 0xa0, ZC3XX_R1A8_DIGITALGAIN}, /* DigitalGain */ +/* Unknown */ + {0xa0, 0x00, 0x01ad}, +/* Sharpness */ + {0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE}, /* SharpnessMode */ + {0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05}, /* Sharpness05 */ +/* Other registors */ + {0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE}, /* OperationMode */ +/* Auto exposure and white balance */ + {0xa0, 0x06, ZC3XX_R189_AWBSTATUS}, /* AWBStatus */ +/*Dead pixels */ + {0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE}, /* DeadPixelsMode */ +/* EEPROM */ + {0xa0, 0x08, ZC3XX_R301_EEPROMACCESS}, /* EEPROMAccess */ +/* JPEG control */ + {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, /* ClockSetting */ + {0xa0, 0x08, ZC3XX_R1C6_SHARPNESS00}, /* sharpness+ */ + {0xa0, 0x0f, ZC3XX_R1CB_SHARPNESS05}, /* sharpness- */ +/* Other registers */ + {0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE}, /* OperationMode */ +/* Auto exposure and white balance */ + {0xa0, 0x06, ZC3XX_R189_AWBSTATUS}, /* AWBStatus */ +/*Dead pixels */ + {0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE}, /* DeadPixelsMode */ +/* EEPROM */ + {0xa0, 0x08, ZC3XX_R301_EEPROMACCESS}, /* EEPROMAccess */ +/* JPEG control */ + {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, /* ClockSetting */ + {0xa0, 0x08, ZC3XX_R1C6_SHARPNESS00}, /* sharpness+ */ + {0xa0, 0x0f, ZC3XX_R1CB_SHARPNESS05}, /* sharpness- */ + + {0xa0, 0x58, ZC3XX_R10A_RGB00}, /* matrix */ + {0xa0, 0xf4, ZC3XX_R10B_RGB01}, + {0xa0, 0xf4, ZC3XX_R10C_RGB02}, + {0xa0, 0xf4, ZC3XX_R10D_RGB10}, + {0xa0, 0x58, ZC3XX_R10E_RGB11}, + {0xa0, 0xf4, ZC3XX_R10F_RGB12}, + {0xa0, 0xf4, ZC3XX_R110_RGB20}, + {0xa0, 0xf4, ZC3XX_R111_RGB21}, + {0xa0, 0x58, ZC3XX_R112_RGB22}, +/* Auto correction */ + {0xa0, 0x03, ZC3XX_R181_WINXSTART}, /* WinXstart */ + {0xa0, 0x08, ZC3XX_R182_WINXWIDTH}, /* WinXWidth */ + {0xa0, 0x16, ZC3XX_R183_WINXCENTER}, /* WinXCenter */ + {0xa0, 0x03, ZC3XX_R184_WINYSTART}, /* WinYStart */ + {0xa0, 0x05, ZC3XX_R185_WINYWIDTH}, /* WinYWidth */ + {0xa0, 0x14, ZC3XX_R186_WINYCENTER}, /* WinYCenter */ + {0xa0, 0x00, ZC3XX_R180_AUTOCORRECTENABLE}, /* AutoCorrectEnable */ + +/* Auto exposure and white balance */ + {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* ExposureLimitHigh */ + {0xa0, 0x03, ZC3XX_R191_EXPOSURELIMITMID}, /* ExposureLimitMid */ + {0xa0, 0xb1, ZC3XX_R192_EXPOSURELIMITLOW}, /* ExposureLimitLow */ + {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* AntiFlickerHigh */ + {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* AntiFlickerLow */ + {0xa0, 0x87, ZC3XX_R197_ANTIFLICKERLOW}, /* AntiFlickerLow */ + {0xa0, 0x0c, ZC3XX_R18C_AEFREEZE}, /* AEBFreeze */ + {0xa0, 0x18, ZC3XX_R18F_AEUNFREEZE}, /* AEBUnfreeze */ +/* sensor on */ + {0xaa, 0x07, 0x00b1}, + {0xaa, 0x05, 0x0003}, + {0xaa, 0x04, 0x0001}, + {0xaa, 0x03, 0x003b}, +/* Gains */ + {0xa0, 0x20, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* DigitalLimitDiff */ + {0xa0, 0x26, ZC3XX_R1AA_DIGITALGAINSTEP}, /* DigitalGainStep */ + {0xa0, 0xa0, ZC3XX_R11D_GLOBALGAIN}, /* GlobalGain */ + {0xa0, 0x60, ZC3XX_R11D_GLOBALGAIN}, /* GlobalGain */ +/* Auto correction */ + {0xa0, 0x40, ZC3XX_R180_AUTOCORRECTENABLE}, /* AutoCorrectEnable */ + {0xa1, 0x01, 0x0180}, /* AutoCorrectEnable */ + {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE}, /* AutoCorrectEnable */ +/* Gains */ + {0xa0, 0x40, ZC3XX_R116_RGAIN}, /* RGain */ + {0xa0, 0x40, ZC3XX_R117_GGAIN}, /* GGain */ + {0xa0, 0x40, ZC3XX_R118_BGAIN}, /* BGain */ + {} +}; + +static const struct usb_action pas106b_InitialScale[] = { /* 352x288 */ +/* JPEG control */ + {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, /* ClockSetting */ +/* Sream and Sensor specific */ + {0xa0, 0x0f, ZC3XX_R010_CMOSSENSORSELECT}, /* CMOSSensorSelect */ +/* Picture size */ + {0xa0, 0x01, ZC3XX_R003_FRAMEWIDTHHIGH}, /* FrameWidthHigh */ + {0xa0, 0x60, ZC3XX_R004_FRAMEWIDTHLOW}, /* FrameWidthLow */ + {0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH}, /* FrameHeightHigh */ + {0xa0, 0x20, ZC3XX_R006_FRAMEHEIGHTLOW}, /* FrameHightLow */ +/* System */ + {0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING}, /* SystemOperating */ +/* Sream and Sensor specific */ + {0xa0, 0x03, ZC3XX_R012_VIDEOCONTROLFUNC}, /* VideoControlFunction */ + {0xa0, 0x01, ZC3XX_R012_VIDEOCONTROLFUNC}, /* VideoControlFunction */ +/* Sensor Interface */ + {0xa0, 0x08, ZC3XX_R08D_COMPABILITYMODE}, /* Compatibily Mode */ +/* Window inside sensor array */ + {0xa0, 0x03, ZC3XX_R09A_WINXSTARTLOW}, /* WinXStartLow */ + {0xa0, 0x00, ZC3XX_R11A_FIRSTYLOW}, /* FirstYLow */ + {0xa0, 0x03, ZC3XX_R11C_FIRSTXLOW}, /* FirstxLow */ + {0xa0, 0x28, ZC3XX_R09C_WINHEIGHTLOW}, /* WinHeightLow */ + {0xa0, 0x68, ZC3XX_R09E_WINWIDTHLOW}, /* WinWidthLow */ +/* Init the sensor */ + {0xaa, 0x02, 0x0004}, + {0xaa, 0x08, 0x0000}, + {0xaa, 0x09, 0x0005}, + {0xaa, 0x0a, 0x0002}, + {0xaa, 0x0b, 0x0002}, + {0xaa, 0x0c, 0x0005}, + {0xaa, 0x0d, 0x0000}, + {0xaa, 0x0e, 0x0002}, + {0xaa, 0x14, 0x0081}, + +/* Other registors */ + {0xa0, 0x37, ZC3XX_R101_SENSORCORRECTION}, /* SensorCorrection */ +/* Frame retreiving */ + {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* AutoAdjustFPS */ +/* Gains */ + {0xa0, 0xa0, ZC3XX_R1A8_DIGITALGAIN}, /* DigitalGain */ +/* Unknown */ + {0xa0, 0x00, 0x01ad}, +/* Sharpness */ + {0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE}, /* SharpnessMode */ + {0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05}, /* Sharpness05 */ +/* Other registors */ + {0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE}, /* OperationMode */ +/* Auto exposure and white balance */ + {0xa0, 0x06, ZC3XX_R189_AWBSTATUS}, /* AWBStatus */ + {0xa0, 0x80, ZC3XX_R18D_YTARGET}, /* ????????? */ +/*Dead pixels */ + {0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE}, /* DeadPixelsMode */ +/* EEPROM */ + {0xa0, 0x08, ZC3XX_R301_EEPROMACCESS}, /* EEPROMAccess */ +/* JPEG control */ + {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, /* ClockSetting */ + {0xa0, 0x08, ZC3XX_R1C6_SHARPNESS00}, /* sharpness+ */ + {0xa0, 0x0f, ZC3XX_R1CB_SHARPNESS05}, /* sharpness- */ +/* Other registers */ + {0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE}, /* OperationMode */ +/* Auto exposure and white balance */ + {0xa0, 0x06, ZC3XX_R189_AWBSTATUS}, /* AWBStatus */ +/*Dead pixels */ + {0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE}, /* DeadPixelsMode */ +/* EEPROM */ + {0xa0, 0x08, ZC3XX_R301_EEPROMACCESS}, /* EEPROMAccess */ +/* JPEG control */ + {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, /* ClockSetting */ + {0xa0, 0x08, ZC3XX_R1C6_SHARPNESS00}, /* sharpness+ */ + {0xa0, 0x0f, ZC3XX_R1CB_SHARPNESS05}, /* sharpness- */ + + {0xa0, 0x58, ZC3XX_R10A_RGB00}, /* matrix */ + {0xa0, 0xf4, ZC3XX_R10B_RGB01}, + {0xa0, 0xf4, ZC3XX_R10C_RGB02}, + {0xa0, 0xf4, ZC3XX_R10D_RGB10}, + {0xa0, 0x58, ZC3XX_R10E_RGB11}, + {0xa0, 0xf4, ZC3XX_R10F_RGB12}, + {0xa0, 0xf4, ZC3XX_R110_RGB20}, + {0xa0, 0xf4, ZC3XX_R111_RGB21}, + {0xa0, 0x58, ZC3XX_R112_RGB22}, +/* Auto correction */ + {0xa0, 0x03, ZC3XX_R181_WINXSTART}, /* WinXstart */ + {0xa0, 0x08, ZC3XX_R182_WINXWIDTH}, /* WinXWidth */ + {0xa0, 0x16, ZC3XX_R183_WINXCENTER}, /* WinXCenter */ + {0xa0, 0x03, ZC3XX_R184_WINYSTART}, /* WinYStart */ + {0xa0, 0x05, ZC3XX_R185_WINYWIDTH}, /* WinYWidth */ + {0xa0, 0x14, ZC3XX_R186_WINYCENTER}, /* WinYCenter */ + {0xa0, 0x00, ZC3XX_R180_AUTOCORRECTENABLE}, /* AutoCorrectEnable */ + +/* Auto exposure and white balance */ + {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* ExposureLimitHigh 0 */ + {0xa0, 0x03, ZC3XX_R191_EXPOSURELIMITMID}, /* ExposureLimitMid */ + {0xa0, 0xb1, ZC3XX_R192_EXPOSURELIMITLOW}, /* ExposureLimitLow 0xb1 */ + + {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* AntiFlickerHigh 0x00 */ + {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* AntiFlickerLow 0x00 */ + {0xa0, 0x87, ZC3XX_R197_ANTIFLICKERLOW}, /* AntiFlickerLow 0x87 */ + + {0xa0, 0x10, ZC3XX_R18C_AEFREEZE}, /* AEBFreeze 0x10 0x0c */ + {0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE}, /* AEBUnfreeze 0x30 0x18 */ +/* sensor on */ + {0xaa, 0x07, 0x00b1}, + {0xaa, 0x05, 0x0003}, + {0xaa, 0x04, 0x0001}, + {0xaa, 0x03, 0x003b}, +/* Gains */ + {0xa0, 0x20, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* DigitalLimitDiff */ + {0xa0, 0x26, ZC3XX_R1AA_DIGITALGAINSTEP}, /* DigitalGainStep */ + {0xa0, 0xa0, ZC3XX_R11D_GLOBALGAIN}, /* GlobalGain */ + {0xa0, 0x60, ZC3XX_R11D_GLOBALGAIN}, /* GlobalGain */ +/* Auto correction */ + {0xa0, 0x40, ZC3XX_R180_AUTOCORRECTENABLE}, /* AutoCorrectEnable */ + {0xa1, 0x01, 0x0180}, /* AutoCorrectEnable */ + {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE}, /* AutoCorrectEnable */ +/* Gains */ + {0xa0, 0x40, ZC3XX_R116_RGAIN}, /* RGain */ + {0xa0, 0x40, ZC3XX_R117_GGAIN}, /* GGain */ + {0xa0, 0x40, ZC3XX_R118_BGAIN}, /* BGain */ + + {0xa0, 0x00, 0x0007}, /* AutoCorrectEnable */ + {0xa0, 0xff, ZC3XX_R018_FRAMELOST}, /* Frame adjust */ + {} +}; +static const struct usb_action pas106b_50HZ[] = { + {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc */ + {0xa0, 0x06, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,06,cc */ + {0xa0, 0x54, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,54,cc */ + {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */ + {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc */ + {0xa0, 0x87, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,87,cc */ + {0xa0, 0x10, ZC3XX_R18C_AEFREEZE}, /* 01,8c,10,cc */ + {0xa0, 0x30, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,30,cc */ + {0xaa, 0x03, 0x0021}, /* 00,03,21,aa */ + {0xaa, 0x04, 0x000c}, /* 00,04,0c,aa */ + {0xaa, 0x05, 0x0002}, /* 00,05,02,aa */ + {0xaa, 0x07, 0x001c}, /* 00,07,1c,aa */ + {0xa0, 0x04, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,04,cc */ + {} +}; +static const struct usb_action pas106b_60HZ[] = { + {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc */ + {0xa0, 0x06, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,06,cc */ + {0xa0, 0x2e, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,2e,cc */ + {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */ + {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc */ + {0xa0, 0x71, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,71,cc */ + {0xa0, 0x10, ZC3XX_R18C_AEFREEZE}, /* 01,8c,10,cc */ + {0xa0, 0x30, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,30,cc */ + {0xaa, 0x03, 0x001c}, /* 00,03,1c,aa */ + {0xaa, 0x04, 0x0004}, /* 00,04,04,aa */ + {0xaa, 0x05, 0x0001}, /* 00,05,01,aa */ + {0xaa, 0x07, 0x00c4}, /* 00,07,c4,aa */ + {0xa0, 0x04, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,04,cc */ + {} +}; +static const struct usb_action pas106b_NoFliker[] = { + {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc */ + {0xa0, 0x06, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,06,cc */ + {0xa0, 0x50, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,50,cc */ + {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */ + {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc */ + {0xa0, 0x10, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,10,cc */ + {0xa0, 0x10, ZC3XX_R18C_AEFREEZE}, /* 01,8c,10,cc */ + {0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,20,cc */ + {0xaa, 0x03, 0x0013}, /* 00,03,13,aa */ + {0xaa, 0x04, 0x0000}, /* 00,04,00,aa */ + {0xaa, 0x05, 0x0001}, /* 00,05,01,aa */ + {0xaa, 0x07, 0x0030}, /* 00,07,30,aa */ + {0xa0, 0x00, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,00,cc */ + {} +}; + +static const struct usb_action pb03303x_Initial[] = { + {0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL}, + {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, + {0xa0, 0x0a, ZC3XX_R010_CMOSSENSORSELECT}, + {0xa0, 0x10, ZC3XX_R002_CLOCKSELECT}, + {0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH}, + {0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW}, + {0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH}, + {0xa0, 0xe0, ZC3XX_R006_FRAMEHEIGHTLOW}, + {0xa0, 0xdc, ZC3XX_R08B_I2CDEVICEADDR}, /* 8b -> dc */ + {0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING}, + {0xa0, 0x03, ZC3XX_R012_VIDEOCONTROLFUNC}, + {0xa0, 0x01, ZC3XX_R012_VIDEOCONTROLFUNC}, + {0xa0, 0x00, ZC3XX_R098_WINYSTARTLOW}, + {0xa0, 0x00, ZC3XX_R09A_WINXSTARTLOW}, + {0xa0, 0x00, ZC3XX_R11A_FIRSTYLOW}, + {0xa0, 0x00, ZC3XX_R11C_FIRSTXLOW}, + {0xa0, 0xdc, ZC3XX_R08B_I2CDEVICEADDR}, + {0xaa, 0x01, 0x0001}, + {0xaa, 0x06, 0x0000}, + {0xaa, 0x08, 0x0483}, + {0xaa, 0x01, 0x0004}, + {0xaa, 0x08, 0x0006}, + {0xaa, 0x02, 0x0011}, + {0xaa, 0x03, 0x01e7}, + {0xaa, 0x04, 0x0287}, + {0xaa, 0x07, 0x3002}, + {0xaa, 0x20, 0x1100}, + {0xaa, 0x35, 0x0050}, + {0xaa, 0x30, 0x0005}, + {0xaa, 0x31, 0x0000}, + {0xaa, 0x58, 0x0078}, + {0xaa, 0x62, 0x0411}, + {0xaa, 0x2b, 0x0028}, + {0xaa, 0x2c, 0x0030}, + {0xaa, 0x2d, 0x0030}, + {0xaa, 0x2e, 0x0028}, + {0xa0, 0x10, ZC3XX_R087_EXPTIMEMID}, + {0xa0, 0x37, ZC3XX_R101_SENSORCORRECTION}, + {0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC}, + {0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE}, + {0xa0, 0x06, ZC3XX_R189_AWBSTATUS}, + {0xa0, 0x00, 0x01ad}, + {0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE}, + {0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05}, + {0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE}, + {0xa0, 0x08, ZC3XX_R301_EEPROMACCESS}, + {0xa0, 0x60, ZC3XX_R1A8_DIGITALGAIN}, + {0xa0, 0x78, ZC3XX_R18D_YTARGET}, + {0xa0, 0x61, ZC3XX_R116_RGAIN}, + {0xa0, 0x65, ZC3XX_R118_BGAIN}, + + {0xa1, 0x01, 0x0002}, + {0xa0, 0x09, 0x01ad}, + {0xa0, 0x15, 0x01ae}, + {0xa0, 0x0d, 0x003a}, + {0xa0, 0x02, 0x003b}, + {0xa0, 0x00, 0x0038}, + {0xa0, 0x50, ZC3XX_R10A_RGB00}, /* matrix */ + {0xa0, 0xf8, ZC3XX_R10B_RGB01}, + {0xa0, 0xf8, ZC3XX_R10C_RGB02}, + {0xa0, 0xf8, ZC3XX_R10D_RGB10}, + {0xa0, 0x50, ZC3XX_R10E_RGB11}, + {0xa0, 0xf8, ZC3XX_R10F_RGB12}, + {0xa0, 0xf8, ZC3XX_R110_RGB20}, + {0xa0, 0xf8, ZC3XX_R111_RGB21}, + {0xa0, 0x50, ZC3XX_R112_RGB22}, + + {0xa1, 0x01, 0x0008}, + {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, /* clock ? */ + {0xa0, 0x08, ZC3XX_R1C6_SHARPNESS00}, /* sharpness+ */ + {0xa1, 0x01, 0x01c8}, + {0xa1, 0x01, 0x01c9}, + {0xa1, 0x01, 0x01ca}, + {0xa0, 0x0f, ZC3XX_R1CB_SHARPNESS05}, /* sharpness- */ + {0xa0, 0x13, ZC3XX_R120_GAMMA00}, /* gamma 4 */ + {0xa0, 0x38, ZC3XX_R121_GAMMA01}, + {0xa0, 0x59, ZC3XX_R122_GAMMA02}, + {0xa0, 0x79, ZC3XX_R123_GAMMA03}, + {0xa0, 0x92, ZC3XX_R124_GAMMA04}, + {0xa0, 0xa7, ZC3XX_R125_GAMMA05}, + {0xa0, 0xb9, ZC3XX_R126_GAMMA06}, + {0xa0, 0xc8, ZC3XX_R127_GAMMA07}, + {0xa0, 0xd4, ZC3XX_R128_GAMMA08}, + {0xa0, 0xdf, ZC3XX_R129_GAMMA09}, + {0xa0, 0xe7, ZC3XX_R12A_GAMMA0A}, + {0xa0, 0xee, ZC3XX_R12B_GAMMA0B}, + {0xa0, 0xf4, ZC3XX_R12C_GAMMA0C}, + {0xa0, 0xf9, ZC3XX_R12D_GAMMA0D}, + {0xa0, 0xfc, ZC3XX_R12E_GAMMA0E}, + {0xa0, 0xff, ZC3XX_R12F_GAMMA0F}, + {0xa0, 0x26, ZC3XX_R130_GAMMA10}, + {0xa0, 0x22, ZC3XX_R131_GAMMA11}, + {0xa0, 0x20, ZC3XX_R132_GAMMA12}, + {0xa0, 0x1c, ZC3XX_R133_GAMMA13}, + {0xa0, 0x16, ZC3XX_R134_GAMMA14}, + {0xa0, 0x13, ZC3XX_R135_GAMMA15}, + {0xa0, 0x10, ZC3XX_R136_GAMMA16}, + {0xa0, 0x0d, ZC3XX_R137_GAMMA17}, + {0xa0, 0x0b, ZC3XX_R138_GAMMA18}, + {0xa0, 0x09, ZC3XX_R139_GAMMA19}, + {0xa0, 0x07, ZC3XX_R13A_GAMMA1A}, + {0xa0, 0x06, ZC3XX_R13B_GAMMA1B}, + {0xa0, 0x05, ZC3XX_R13C_GAMMA1C}, + {0xa0, 0x04, ZC3XX_R13D_GAMMA1D}, + {0xa0, 0x03, ZC3XX_R13E_GAMMA1E}, + {0xa0, 0x02, ZC3XX_R13F_GAMMA1F}, + {0xa0, 0x50, ZC3XX_R10A_RGB00}, /* matrix */ + {0xa0, 0xf8, ZC3XX_R10B_RGB01}, + {0xa0, 0xf8, ZC3XX_R10C_RGB02}, + {0xa0, 0xf8, ZC3XX_R10D_RGB10}, + {0xa0, 0x50, ZC3XX_R10E_RGB11}, + {0xa0, 0xf8, ZC3XX_R10F_RGB12}, + {0xa0, 0xf8, ZC3XX_R110_RGB20}, + {0xa0, 0xf8, ZC3XX_R111_RGB21}, + {0xa0, 0x50, ZC3XX_R112_RGB22}, + + {0xa1, 0x01, 0x0180}, + {0xa0, 0x00, ZC3XX_R180_AUTOCORRECTENABLE}, + {0xa0, 0x00, ZC3XX_R180_AUTOCORRECTENABLE}, + {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, + {0xaa, 0x05, 0x0009}, + {0xaa, 0x09, 0x0134}, + {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, + {0xa0, 0x07, ZC3XX_R191_EXPOSURELIMITMID}, + {0xa0, 0xec, ZC3XX_R192_EXPOSURELIMITLOW}, + {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, + {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, + {0xa0, 0x9c, ZC3XX_R197_ANTIFLICKERLOW}, + {0xa0, 0x0e, ZC3XX_R18C_AEFREEZE}, + {0xa0, 0x1c, ZC3XX_R18F_AEUNFREEZE}, + {0xa0, 0x14, ZC3XX_R1A9_DIGITALLIMITDIFF}, + {0xa0, 0x24, ZC3XX_R1AA_DIGITALGAINSTEP}, + {0xa0, 0xd7, ZC3XX_R01D_HSYNC_0}, + {0xa0, 0xf4, ZC3XX_R01E_HSYNC_1}, + {0xa0, 0xf9, ZC3XX_R01F_HSYNC_2}, + {0xa0, 0xff, ZC3XX_R020_HSYNC_3}, + {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE}, + {0xa0, 0x09, 0x01ad}, + {0xa0, 0x15, 0x01ae}, + {0xa0, 0x40, ZC3XX_R180_AUTOCORRECTENABLE}, + {0xa1, 0x01, 0x0180}, + {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE}, + {} +}; + +static const struct usb_action pb03303x_InitialScale[] = { + {0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL}, + {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, + {0xa0, 0x0a, ZC3XX_R010_CMOSSENSORSELECT}, + {0xa0, 0x00, ZC3XX_R002_CLOCKSELECT}, + {0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH}, + {0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW}, + {0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH}, + {0xa0, 0xe0, ZC3XX_R006_FRAMEHEIGHTLOW}, + {0xa0, 0xdc, ZC3XX_R08B_I2CDEVICEADDR}, /* 8b -> dc */ + {0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING}, + {0xa0, 0x03, ZC3XX_R012_VIDEOCONTROLFUNC}, + {0xa0, 0x01, ZC3XX_R012_VIDEOCONTROLFUNC}, + {0xa0, 0x00, ZC3XX_R098_WINYSTARTLOW}, + {0xa0, 0x00, ZC3XX_R09A_WINXSTARTLOW}, + {0xa0, 0x00, ZC3XX_R11A_FIRSTYLOW}, + {0xa0, 0x00, ZC3XX_R11C_FIRSTXLOW}, + {0xa0, 0xdc, ZC3XX_R08B_I2CDEVICEADDR}, + {0xaa, 0x01, 0x0001}, + {0xaa, 0x06, 0x0000}, + {0xaa, 0x08, 0x0483}, + {0xaa, 0x01, 0x0004}, + {0xaa, 0x08, 0x0006}, + {0xaa, 0x02, 0x0011}, + {0xaa, 0x03, 0x01e7}, + {0xaa, 0x04, 0x0287}, + {0xaa, 0x07, 0x3002}, + {0xaa, 0x20, 0x1100}, + {0xaa, 0x35, 0x0050}, + {0xaa, 0x30, 0x0005}, + {0xaa, 0x31, 0x0000}, + {0xaa, 0x58, 0x0078}, + {0xaa, 0x62, 0x0411}, + {0xaa, 0x2b, 0x0028}, + {0xaa, 0x2c, 0x0030}, + {0xaa, 0x2d, 0x0030}, + {0xaa, 0x2e, 0x0028}, + {0xa0, 0x10, ZC3XX_R087_EXPTIMEMID}, + {0xa0, 0x37, ZC3XX_R101_SENSORCORRECTION}, + {0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC}, + {0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE}, + {0xa0, 0x06, ZC3XX_R189_AWBSTATUS}, + {0xa0, 0x00, 0x01ad}, + {0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE}, + {0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05}, + {0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE}, + {0xa0, 0x08, ZC3XX_R301_EEPROMACCESS}, + {0xa0, 0x60, ZC3XX_R1A8_DIGITALGAIN}, + {0xa0, 0x78, ZC3XX_R18D_YTARGET}, + {0xa0, 0x61, ZC3XX_R116_RGAIN}, + {0xa0, 0x65, ZC3XX_R118_BGAIN}, + + {0xa1, 0x01, 0x0002}, + + {0xa0, 0x09, 0x01ad}, + {0xa0, 0x15, 0x01ae}, + + {0xa0, 0x0d, 0x003a}, + {0xa0, 0x02, 0x003b}, + {0xa0, 0x00, 0x0038}, + {0xa0, 0x50, ZC3XX_R10A_RGB00}, /* matrix */ + {0xa0, 0xf8, ZC3XX_R10B_RGB01}, + {0xa0, 0xf8, ZC3XX_R10C_RGB02}, + {0xa0, 0xf8, ZC3XX_R10D_RGB10}, + {0xa0, 0x50, ZC3XX_R10E_RGB11}, + {0xa0, 0xf8, ZC3XX_R10F_RGB12}, + {0xa0, 0xf8, ZC3XX_R110_RGB20}, + {0xa0, 0xf8, ZC3XX_R111_RGB21}, + {0xa0, 0x50, ZC3XX_R112_RGB22}, + + {0xa1, 0x01, 0x0008}, + {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, /* clock ? */ + {0xa0, 0x08, ZC3XX_R1C6_SHARPNESS00}, /* sharpness+ */ + {0xa1, 0x01, 0x01c8}, + {0xa1, 0x01, 0x01c9}, + {0xa1, 0x01, 0x01ca}, + {0xa0, 0x0f, ZC3XX_R1CB_SHARPNESS05}, /* sharpness- */ + + {0xa0, 0x13, ZC3XX_R120_GAMMA00}, /* gamma 4 */ + {0xa0, 0x38, ZC3XX_R121_GAMMA01}, + {0xa0, 0x59, ZC3XX_R122_GAMMA02}, + {0xa0, 0x79, ZC3XX_R123_GAMMA03}, + {0xa0, 0x92, ZC3XX_R124_GAMMA04}, + {0xa0, 0xa7, ZC3XX_R125_GAMMA05}, + {0xa0, 0xb9, ZC3XX_R126_GAMMA06}, + {0xa0, 0xc8, ZC3XX_R127_GAMMA07}, + {0xa0, 0xd4, ZC3XX_R128_GAMMA08}, + {0xa0, 0xdf, ZC3XX_R129_GAMMA09}, + {0xa0, 0xe7, ZC3XX_R12A_GAMMA0A}, + {0xa0, 0xee, ZC3XX_R12B_GAMMA0B}, + {0xa0, 0xf4, ZC3XX_R12C_GAMMA0C}, + {0xa0, 0xf9, ZC3XX_R12D_GAMMA0D}, + {0xa0, 0xfc, ZC3XX_R12E_GAMMA0E}, + {0xa0, 0xff, ZC3XX_R12F_GAMMA0F}, + {0xa0, 0x26, ZC3XX_R130_GAMMA10}, + {0xa0, 0x22, ZC3XX_R131_GAMMA11}, + {0xa0, 0x20, ZC3XX_R132_GAMMA12}, + {0xa0, 0x1c, ZC3XX_R133_GAMMA13}, + {0xa0, 0x16, ZC3XX_R134_GAMMA14}, + {0xa0, 0x13, ZC3XX_R135_GAMMA15}, + {0xa0, 0x10, ZC3XX_R136_GAMMA16}, + {0xa0, 0x0d, ZC3XX_R137_GAMMA17}, + {0xa0, 0x0b, ZC3XX_R138_GAMMA18}, + {0xa0, 0x09, ZC3XX_R139_GAMMA19}, + {0xa0, 0x07, ZC3XX_R13A_GAMMA1A}, + {0xa0, 0x06, ZC3XX_R13B_GAMMA1B}, + {0xa0, 0x05, ZC3XX_R13C_GAMMA1C}, + {0xa0, 0x04, ZC3XX_R13D_GAMMA1D}, + {0xa0, 0x03, ZC3XX_R13E_GAMMA1E}, + {0xa0, 0x02, ZC3XX_R13F_GAMMA1F}, + {0xa0, 0x50, ZC3XX_R10A_RGB00}, /* matrix */ + {0xa0, 0xf8, ZC3XX_R10B_RGB01}, + {0xa0, 0xf8, ZC3XX_R10C_RGB02}, + {0xa0, 0xf8, ZC3XX_R10D_RGB10}, + {0xa0, 0x50, ZC3XX_R10E_RGB11}, + {0xa0, 0xf8, ZC3XX_R10F_RGB12}, + {0xa0, 0xf8, ZC3XX_R110_RGB20}, + {0xa0, 0xf8, ZC3XX_R111_RGB21}, + {0xa0, 0x50, ZC3XX_R112_RGB22}, + + {0xa1, 0x01, 0x0180}, + {0xa0, 0x00, ZC3XX_R180_AUTOCORRECTENABLE}, + {0xa0, 0x00, ZC3XX_R180_AUTOCORRECTENABLE}, + {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, + {0xaa, 0x05, 0x0009}, + {0xaa, 0x09, 0x0134}, + {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, + {0xa0, 0x07, ZC3XX_R191_EXPOSURELIMITMID}, + {0xa0, 0xec, ZC3XX_R192_EXPOSURELIMITLOW}, + {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, + {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, + {0xa0, 0x9c, ZC3XX_R197_ANTIFLICKERLOW}, + {0xa0, 0x0e, ZC3XX_R18C_AEFREEZE}, + {0xa0, 0x1c, ZC3XX_R18F_AEUNFREEZE}, + {0xa0, 0x14, ZC3XX_R1A9_DIGITALLIMITDIFF}, + {0xa0, 0x24, ZC3XX_R1AA_DIGITALGAINSTEP}, + {0xa0, 0xd7, ZC3XX_R01D_HSYNC_0}, + {0xa0, 0xf4, ZC3XX_R01E_HSYNC_1}, + {0xa0, 0xf9, ZC3XX_R01F_HSYNC_2}, + {0xa0, 0xff, ZC3XX_R020_HSYNC_3}, + {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE}, + {0xa0, 0x09, 0x01ad}, + {0xa0, 0x15, 0x01ae}, + {0xa0, 0x40, ZC3XX_R180_AUTOCORRECTENABLE}, + {0xa1, 0x01, 0x0180}, + {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE}, + {} +}; +static const struct usb_action pb0330xx_Initial[] = { + {0xa1, 0x01, 0x0008}, + {0xa1, 0x01, 0x0008}, + {0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL}, + {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, /* 00 */ + {0xa0, 0x0a, ZC3XX_R010_CMOSSENSORSELECT}, + {0xa0, 0x10, ZC3XX_R002_CLOCKSELECT}, + {0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH}, + {0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW}, + {0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH}, + {0xa0, 0xe0, ZC3XX_R006_FRAMEHEIGHTLOW}, + {0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING}, + {0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC}, + {0xa0, 0x07, ZC3XX_R012_VIDEOCONTROLFUNC}, + {0xa0, 0x00, ZC3XX_R098_WINYSTARTLOW}, + {0xa0, 0x00, ZC3XX_R09A_WINXSTARTLOW}, + {0xa0, 0x00, ZC3XX_R11A_FIRSTYLOW}, + {0xa0, 0x00, ZC3XX_R11C_FIRSTXLOW}, + {0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC}, + {0xaa, 0x01, 0x0006}, + {0xaa, 0x02, 0x0011}, + {0xaa, 0x03, 0x01e7}, + {0xaa, 0x04, 0x0287}, + {0xaa, 0x06, 0x0003}, + {0xaa, 0x07, 0x3002}, + {0xaa, 0x20, 0x1100}, + {0xaa, 0x2f, 0xf7b0}, + {0xaa, 0x30, 0x0005}, + {0xaa, 0x31, 0x0000}, + {0xaa, 0x34, 0x0100}, + {0xaa, 0x35, 0x0060}, + {0xaa, 0x3d, 0x068f}, + {0xaa, 0x40, 0x01e0}, + {0xaa, 0x58, 0x0078}, + {0xaa, 0x62, 0x0411}, + {0xa0, 0x10, ZC3XX_R087_EXPTIMEMID}, + {0xa0, 0x37, ZC3XX_R101_SENSORCORRECTION}, + {0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC}, + {0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE}, + {0xa0, 0x06, ZC3XX_R189_AWBSTATUS}, + {0xa0, 0x00, 0x01ad}, + {0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE}, + {0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05}, + {0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE}, + {0xa0, 0x08, ZC3XX_R301_EEPROMACCESS}, + {0xa0, 0x60, ZC3XX_R1A8_DIGITALGAIN}, + {0xa0, 0x6c, ZC3XX_R18D_YTARGET}, + {0xa1, 0x01, 0x0002}, + {0xa0, 0x09, 0x01ad}, + {0xa0, 0x15, 0x01ae}, + {0xa0, 0x00, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x02, ZC3XX_R090_I2CCOMMAND}, + {0xa1, 0x01, 0x0091}, + {0xa1, 0x01, 0x0095}, + {0xa1, 0x01, 0x0096}, + {0xa0, 0x50, ZC3XX_R10A_RGB00}, /* matrix */ + {0xa0, 0xf8, ZC3XX_R10B_RGB01}, + {0xa0, 0xf8, ZC3XX_R10C_RGB02}, + {0xa0, 0xf8, ZC3XX_R10D_RGB10}, + {0xa0, 0x50, ZC3XX_R10E_RGB11}, + {0xa0, 0xf8, ZC3XX_R10F_RGB12}, + {0xa0, 0xf8, ZC3XX_R110_RGB20}, + {0xa0, 0xf8, ZC3XX_R111_RGB21}, + {0xa0, 0x50, ZC3XX_R112_RGB22}, + {0xa1, 0x01, 0x0008}, + {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, /* clock ? */ + {0xa0, 0x08, ZC3XX_R1C6_SHARPNESS00}, /* sharpness+ */ + {0xa1, 0x01, 0x01c8}, + {0xa1, 0x01, 0x01c9}, + {0xa1, 0x01, 0x01ca}, + {0xa0, 0x0f, ZC3XX_R1CB_SHARPNESS05}, /* sharpness- */ + + {0xa0, 0x50, ZC3XX_R10A_RGB00}, /* matrix */ + {0xa0, 0xf8, ZC3XX_R10B_RGB01}, + {0xa0, 0xf8, ZC3XX_R10C_RGB02}, + {0xa0, 0xf8, ZC3XX_R10D_RGB10}, + {0xa0, 0x50, ZC3XX_R10E_RGB11}, + {0xa0, 0xf8, ZC3XX_R10F_RGB12}, + {0xa0, 0xf8, ZC3XX_R110_RGB20}, + {0xa0, 0xf8, ZC3XX_R111_RGB21}, + {0xa0, 0x50, ZC3XX_R112_RGB22}, + {0xa1, 0x01, 0x0180}, + {0xa0, 0x00, ZC3XX_R180_AUTOCORRECTENABLE}, + {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, + {0xaa, 0x05, 0x0066}, + {0xaa, 0x09, 0x02b2}, + {0xaa, 0x10, 0x0002}, + + {0xa0, 0x60, ZC3XX_R11D_GLOBALGAIN}, + {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, + {0xa0, 0x07, ZC3XX_R191_EXPOSURELIMITMID}, + {0xa0, 0x8c, ZC3XX_R192_EXPOSURELIMITLOW}, + {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, + {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, + {0xa0, 0x8a, ZC3XX_R197_ANTIFLICKERLOW}, + {0xa0, 0x10, ZC3XX_R18C_AEFREEZE}, + {0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE}, + {0xa0, 0x14, ZC3XX_R1A9_DIGITALLIMITDIFF}, + {0xa0, 0x24, ZC3XX_R1AA_DIGITALGAINSTEP}, + {0xa0, 0xd7, ZC3XX_R01D_HSYNC_0}, + {0xa0, 0xf0, ZC3XX_R01E_HSYNC_1}, + {0xa0, 0xf8, ZC3XX_R01F_HSYNC_2}, + {0xa0, 0xff, ZC3XX_R020_HSYNC_3}, + {0xa0, 0x09, 0x01ad}, + {0xa0, 0x15, 0x01ae}, + {0xa0, 0x40, ZC3XX_R180_AUTOCORRECTENABLE}, + {0xa1, 0x01, 0x0180}, + {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE}, + {0xa1, 0x01, 0x0008}, + {0xa1, 0x01, 0x0007}, +/* {0xa0, 0x30, 0x0007}, */ +/* {0xa0, 0x00, 0x0007}, */ + {} +}; + +static const struct usb_action pb0330xx_InitialScale[] = { + {0xa1, 0x01, 0x0008}, + {0xa1, 0x01, 0x0008}, + {0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL}, + {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, /* 00 */ + {0xa0, 0x0a, ZC3XX_R010_CMOSSENSORSELECT}, + {0xa0, 0x00, ZC3XX_R002_CLOCKSELECT}, /* 10 */ + {0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH}, + {0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW}, + {0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH}, + {0xa0, 0xe0, ZC3XX_R006_FRAMEHEIGHTLOW}, + {0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING}, + {0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC}, + {0xa0, 0x07, ZC3XX_R012_VIDEOCONTROLFUNC}, + {0xa0, 0x00, ZC3XX_R098_WINYSTARTLOW}, + {0xa0, 0x00, ZC3XX_R09A_WINXSTARTLOW}, + {0xa0, 0x00, ZC3XX_R11A_FIRSTYLOW}, + {0xa0, 0x00, ZC3XX_R11C_FIRSTXLOW}, + {0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC}, + {0xaa, 0x01, 0x0006}, + {0xaa, 0x02, 0x0011}, + {0xaa, 0x03, 0x01e7}, + {0xaa, 0x04, 0x0287}, + {0xaa, 0x06, 0x0003}, + {0xaa, 0x07, 0x3002}, + {0xaa, 0x20, 0x1100}, + {0xaa, 0x2f, 0xf7b0}, + {0xaa, 0x30, 0x0005}, + {0xaa, 0x31, 0x0000}, + {0xaa, 0x34, 0x0100}, + {0xaa, 0x35, 0x0060}, + {0xaa, 0x3d, 0x068f}, + {0xaa, 0x40, 0x01e0}, + {0xaa, 0x58, 0x0078}, + {0xaa, 0x62, 0x0411}, + {0xa0, 0x10, ZC3XX_R087_EXPTIMEMID}, + {0xa0, 0x37, ZC3XX_R101_SENSORCORRECTION}, + {0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC}, + {0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE}, + {0xa0, 0x06, ZC3XX_R189_AWBSTATUS}, + {0xa0, 0x00, 0x01ad}, + {0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE}, + {0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05}, + {0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE}, + {0xa0, 0x08, ZC3XX_R301_EEPROMACCESS}, + {0xa0, 0x60, ZC3XX_R1A8_DIGITALGAIN}, + {0xa0, 0x6c, ZC3XX_R18D_YTARGET}, + {0xa1, 0x01, 0x0002}, + {0xa0, 0x09, 0x01ad}, + {0xa0, 0x15, 0x01ae}, + {0xa0, 0x00, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x02, ZC3XX_R090_I2CCOMMAND}, + {0xa1, 0x01, 0x0091}, + {0xa1, 0x01, 0x0095}, + {0xa1, 0x01, 0x0096}, + {0xa0, 0x50, ZC3XX_R10A_RGB00}, /* matrix */ + {0xa0, 0xf8, ZC3XX_R10B_RGB01}, + {0xa0, 0xf8, ZC3XX_R10C_RGB02}, + {0xa0, 0xf8, ZC3XX_R10D_RGB10}, + {0xa0, 0x50, ZC3XX_R10E_RGB11}, + {0xa0, 0xf8, ZC3XX_R10F_RGB12}, + {0xa0, 0xf8, ZC3XX_R110_RGB20}, + {0xa0, 0xf8, ZC3XX_R111_RGB21}, + {0xa0, 0x50, ZC3XX_R112_RGB22}, + {0xa1, 0x01, 0x0008}, + {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, /* clock ? */ + {0xa0, 0x08, ZC3XX_R1C6_SHARPNESS00}, /* sharpness+ */ + {0xa1, 0x01, 0x01c8}, + {0xa1, 0x01, 0x01c9}, + {0xa1, 0x01, 0x01ca}, + {0xa0, 0x0f, ZC3XX_R1CB_SHARPNESS05}, /* sharpness- */ + + {0xa0, 0x50, ZC3XX_R10A_RGB00}, /* matrix */ + {0xa0, 0xf8, ZC3XX_R10B_RGB01}, + {0xa0, 0xf8, ZC3XX_R10C_RGB02}, + {0xa0, 0xf8, ZC3XX_R10D_RGB10}, + {0xa0, 0x50, ZC3XX_R10E_RGB11}, + {0xa0, 0xf8, ZC3XX_R10F_RGB12}, + {0xa0, 0xf8, ZC3XX_R110_RGB20}, + {0xa0, 0xf8, ZC3XX_R111_RGB21}, + {0xa0, 0x50, ZC3XX_R112_RGB22}, + {0xa1, 0x01, 0x0180}, + {0xa0, 0x00, ZC3XX_R180_AUTOCORRECTENABLE}, + {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, + {0xaa, 0x05, 0x0066}, + {0xaa, 0x09, 0x02b2}, + {0xaa, 0x10, 0x0002}, + {0xa0, 0x60, ZC3XX_R11D_GLOBALGAIN}, + {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, + {0xa0, 0x07, ZC3XX_R191_EXPOSURELIMITMID}, + {0xa0, 0x8c, ZC3XX_R192_EXPOSURELIMITLOW}, + {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, + {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, + {0xa0, 0x8a, ZC3XX_R197_ANTIFLICKERLOW}, + {0xa0, 0x10, ZC3XX_R18C_AEFREEZE}, + {0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE}, + {0xa0, 0x14, ZC3XX_R1A9_DIGITALLIMITDIFF}, + {0xa0, 0x24, ZC3XX_R1AA_DIGITALGAINSTEP}, + {0xa0, 0xd7, ZC3XX_R01D_HSYNC_0}, + {0xa0, 0xf0, ZC3XX_R01E_HSYNC_1}, + {0xa0, 0xf8, ZC3XX_R01F_HSYNC_2}, + {0xa0, 0xff, ZC3XX_R020_HSYNC_3}, + {0xa0, 0x09, 0x01ad}, + {0xa0, 0x15, 0x01ae}, + {0xa0, 0x40, ZC3XX_R180_AUTOCORRECTENABLE}, + {0xa1, 0x01, 0x0180}, + {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE}, + {0xa1, 0x01, 0x0008}, + {0xa1, 0x01, 0x0007}, +/* {0xa0, 0x30, 0x0007}, */ +/* {0xa0, 0x00, 0x0007}, */ + {} +}; +static const struct usb_action pb0330_50HZ[] = { + {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc */ + {0xa0, 0x07, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,07,cc */ + {0xa0, 0xee, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,ee,cc */ + {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */ + {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc */ + {0xa0, 0x46, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,46,cc */ + {0xa0, 0x10, ZC3XX_R18C_AEFREEZE}, /* 01,8c,10,cc */ + {0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,20,cc */ + {0xa0, 0x0c, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,0c,cc */ + {0xa0, 0x26, ZC3XX_R1AA_DIGITALGAINSTEP}, /* 01,aa,26,cc */ + {0xa0, 0x68, ZC3XX_R01D_HSYNC_0}, /* 00,1d,68,cc */ + {0xa0, 0x90, ZC3XX_R01E_HSYNC_1}, /* 00,1e,90,cc */ + {0xa0, 0xc8, ZC3XX_R01F_HSYNC_2}, /* 00,1f,c8,cc */ + {} +}; +static const struct usb_action pb0330_50HZScale[] = { + {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */ + {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc */ + {0xa0, 0x07, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,07,cc */ + {0xa0, 0xa0, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,a0,cc */ + {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */ + {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc */ + {0xa0, 0x7a, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,7a,cc */ + {0xa0, 0x10, ZC3XX_R18C_AEFREEZE}, /* 01,8c,10,cc */ + {0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,20,cc */ + {0xa0, 0x0c, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,0c,cc */ + {0xa0, 0x26, ZC3XX_R1AA_DIGITALGAINSTEP}, /* 01,aa,26,cc */ + {0xa0, 0xe5, ZC3XX_R01D_HSYNC_0}, /* 00,1d,e5,cc */ + {0xa0, 0xf0, ZC3XX_R01E_HSYNC_1}, /* 00,1e,f0,cc */ + {0xa0, 0xf8, ZC3XX_R01F_HSYNC_2}, /* 00,1f,f8,cc */ + {} +}; +static const struct usb_action pb0330_60HZ[] = { + {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */ + {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc */ + {0xa0, 0x07, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,07,cc */ + {0xa0, 0xdd, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,dd,cc */ + {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */ + {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc */ + {0xa0, 0x3d, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,3d,cc */ + {0xa0, 0x10, ZC3XX_R18C_AEFREEZE}, /* 01,8c,10,cc */ + {0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,20,cc */ + {0xa0, 0x0c, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,0c,cc */ + {0xa0, 0x26, ZC3XX_R1AA_DIGITALGAINSTEP}, /* 01,aa,26,cc */ + {0xa0, 0x43, ZC3XX_R01D_HSYNC_0}, /* 00,1d,43,cc */ + {0xa0, 0x50, ZC3XX_R01E_HSYNC_1}, /* 00,1e,50,cc */ + {0xa0, 0x90, ZC3XX_R01F_HSYNC_2}, /* 00,1f,90,cc */ + {} +}; +static const struct usb_action pb0330_60HZScale[] = { + {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */ + {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc */ + {0xa0, 0x07, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,07,cc */ + {0xa0, 0xa0, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,a0,cc */ + {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */ + {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc */ + {0xa0, 0x7a, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,7a,cc */ + {0xa0, 0x10, ZC3XX_R18C_AEFREEZE}, /* 01,8c,10,cc */ + {0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,20,cc */ + {0xa0, 0x0c, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,0c,cc */ + {0xa0, 0x26, ZC3XX_R1AA_DIGITALGAINSTEP}, /* 01,aa,26,cc */ + {0xa0, 0x41, ZC3XX_R01D_HSYNC_0}, /* 00,1d,41,cc */ + {0xa0, 0x50, ZC3XX_R01E_HSYNC_1}, /* 00,1e,50,cc */ + {0xa0, 0x90, ZC3XX_R01F_HSYNC_2}, /* 00,1f,90,cc */ + {} +}; +static const struct usb_action pb0330_NoFliker[] = { + {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */ + {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc */ + {0xa0, 0x07, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,07,cc */ + {0xa0, 0xf0, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,f0,cc */ + {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */ + {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc */ + {0xa0, 0x10, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,10,cc */ + {0xa0, 0x10, ZC3XX_R18C_AEFREEZE}, /* 01,8c,10,cc */ + {0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,20,cc */ + {0xa0, 0x00, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,00,cc */ + {0xa0, 0x00, ZC3XX_R1AA_DIGITALGAINSTEP}, /* 01,aa,00,cc */ + {0xa0, 0x09, ZC3XX_R01D_HSYNC_0}, /* 00,1d,09,cc */ + {0xa0, 0x40, ZC3XX_R01E_HSYNC_1}, /* 00,1e,40,cc */ + {0xa0, 0x90, ZC3XX_R01F_HSYNC_2}, /* 00,1f,90,cc */ + {} +}; +static const struct usb_action pb0330_NoFlikerScale[] = { + {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */ + {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc */ + {0xa0, 0x07, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,07,cc */ + {0xa0, 0xf0, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,f0,cc */ + {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */ + {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc */ + {0xa0, 0x10, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,10,cc */ + {0xa0, 0x10, ZC3XX_R18C_AEFREEZE}, /* 01,8c,10,cc */ + {0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,20,cc */ + {0xa0, 0x00, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,00,cc */ + {0xa0, 0x00, ZC3XX_R1AA_DIGITALGAINSTEP}, /* 01,aa,00,cc */ + {0xa0, 0x09, ZC3XX_R01D_HSYNC_0}, /* 00,1d,09,cc */ + {0xa0, 0x40, ZC3XX_R01E_HSYNC_1}, /* 00,1e,40,cc */ + {0xa0, 0x90, ZC3XX_R01F_HSYNC_2}, /* 00,1f,90,cc */ + {} +}; + +/* from oem9.inf - HKR,%PO2030%,Initial - 640x480 - (close to CS2102) */ +static const struct usb_action PO2030_mode0[] = { + {0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL}, /* 00,00,01,cc */ + {0xa0, 0x04, ZC3XX_R002_CLOCKSELECT}, /* 00,02,04,cc */ + {0xa0, 0x01, ZC3XX_R010_CMOSSENSORSELECT}, /* 00,10,01,cc */ + {0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING}, /* 00,01,01,cc */ + {0xa0, 0x04, ZC3XX_R080_HBLANKHIGH}, /* 00,80,04,cc */ + {0xa0, 0x05, ZC3XX_R081_HBLANKLOW}, /* 00,81,05,cc */ + {0xa0, 0x16, ZC3XX_R083_RGAINADDR}, /* 00,83,16,cc */ + {0xa0, 0x18, ZC3XX_R085_BGAINADDR}, /* 00,85,18,cc */ + {0xa0, 0x1a, ZC3XX_R086_EXPTIMEHIGH}, /* 00,86,1a,cc */ + {0xa0, 0x1b, ZC3XX_R087_EXPTIMEMID}, /* 00,87,1b,cc */ + {0xa0, 0x1c, ZC3XX_R088_EXPTIMELOW}, /* 00,88,1c,cc */ + {0xa0, 0xee, ZC3XX_R08B_I2CDEVICEADDR}, /* 00,8b,ee,cc */ + {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, /* 00,08,03,cc */ + {0xa0, 0x03, ZC3XX_R012_VIDEOCONTROLFUNC}, /* 00,12,03,cc */ + {0xa0, 0x01, ZC3XX_R012_VIDEOCONTROLFUNC}, /* 00,12,01,cc */ + {0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH}, /* 00,03,02,cc */ + {0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW}, /* 00,04,80,cc */ + {0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH}, /* 00,05,01,cc */ + {0xa0, 0xe0, ZC3XX_R006_FRAMEHEIGHTLOW}, /* 00,06,e0,cc */ + {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE}, /* 01,80,42,cc */ + {0xaa, 0x8d, 0x0008}, /* 00,8d,08,aa */ + {0xa0, 0x00, ZC3XX_R098_WINYSTARTLOW}, /* 00,98,00,cc */ + {0xa0, 0x00, ZC3XX_R09A_WINXSTARTLOW}, /* 00,9a,00,cc */ + {0xa0, 0x00, ZC3XX_R11A_FIRSTYLOW}, /* 01,1a,00,cc */ + {0xa0, 0x00, ZC3XX_R11C_FIRSTXLOW}, /* 01,1c,00,cc */ + {0xa0, 0xe6, ZC3XX_R09C_WINHEIGHTLOW}, /* 00,9c,e6,cc */ + {0xa0, 0x86, ZC3XX_R09E_WINWIDTHLOW}, /* 00,9e,86,cc */ + {0xaa, 0x09, 0x00ce}, /* 00,09,ce,aa */ + {0xaa, 0x0b, 0x0005}, /* 00,0b,05,aa */ + {0xaa, 0x0d, 0x0054}, /* 00,0d,54,aa */ + {0xaa, 0x0f, 0x00eb}, /* 00,0f,eb,aa */ + {0xaa, 0x87, 0x0000}, /* 00,87,00,aa */ + {0xaa, 0x88, 0x0004}, /* 00,88,04,aa */ + {0xaa, 0x89, 0x0000}, /* 00,89,00,aa */ + {0xaa, 0x8a, 0x0005}, /* 00,8a,05,aa */ + {0xaa, 0x13, 0x0003}, /* 00,13,03,aa */ + {0xaa, 0x16, 0x0040}, /* 00,16,40,aa */ + {0xaa, 0x18, 0x0040}, /* 00,18,40,aa */ + {0xaa, 0x1d, 0x0002}, /* 00,1d,02,aa */ + {0xaa, 0x29, 0x00e8}, /* 00,29,e8,aa */ + {0xaa, 0x45, 0x0045}, /* 00,45,45,aa */ + {0xaa, 0x50, 0x00ed}, /* 00,50,ed,aa */ + {0xaa, 0x51, 0x0025}, /* 00,51,25,aa */ + {0xaa, 0x52, 0x0042}, /* 00,52,42,aa */ + {0xaa, 0x53, 0x002f}, /* 00,53,2f,aa */ + {0xaa, 0x79, 0x0025}, /* 00,79,25,aa */ + {0xaa, 0x7b, 0x0000}, /* 00,7b,00,aa */ + {0xaa, 0x7e, 0x0025}, /* 00,7e,25,aa */ + {0xaa, 0x7f, 0x0025}, /* 00,7f,25,aa */ + {0xaa, 0x21, 0x0000}, /* 00,21,00,aa */ + {0xaa, 0x33, 0x0036}, /* 00,33,36,aa */ + {0xaa, 0x36, 0x0060}, /* 00,36,60,aa */ + {0xaa, 0x37, 0x0008}, /* 00,37,08,aa */ + {0xaa, 0x3b, 0x0031}, /* 00,3b,31,aa */ + {0xaa, 0x44, 0x000f}, /* 00,44,0f,aa */ + {0xaa, 0x58, 0x0002}, /* 00,58,02,aa */ + {0xaa, 0x66, 0x00c0}, /* 00,66,c0,aa */ + {0xaa, 0x67, 0x0044}, /* 00,67,44,aa */ + {0xaa, 0x6b, 0x00a0}, /* 00,6b,a0,aa */ + {0xaa, 0x6c, 0x0054}, /* 00,6c,54,aa */ + {0xaa, 0xd6, 0x0007}, /* 00,d6,07,aa */ + {0xa0, 0xf7, ZC3XX_R101_SENSORCORRECTION}, /* 01,01,f7,cc */ + {0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC}, /* 00,12,05,cc */ + {0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE}, /* 01,00,0d,cc */ + {0xa0, 0x06, ZC3XX_R189_AWBSTATUS}, /* 01,89,06,cc */ + {0xa0, 0x00, 0x01ad}, /* 01,ad,00,cc */ + {0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE}, /* 01,c5,03,cc */ + {0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05}, /* 01,cb,13,cc */ + {0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE}, /* 02,50,08,cc */ + {0xa0, 0x08, ZC3XX_R301_EEPROMACCESS}, /* 03,01,08,cc */ + {0xa0, 0x7a, ZC3XX_R116_RGAIN}, /* 01,16,7a,cc */ + {0xa0, 0x4a, ZC3XX_R118_BGAIN}, /* 01,18,4a,cc */ + {} +}; + +/* from oem9.inf - HKR,%PO2030%,InitialScale - 320x240 */ +static const struct usb_action PO2030_mode1[] = { + {0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL}, /* 00,00,01,cc */ + {0xa0, 0x10, ZC3XX_R002_CLOCKSELECT}, /* 00,02,10,cc */ + {0xa0, 0x01, ZC3XX_R010_CMOSSENSORSELECT}, /* 00,10,01,cc */ + {0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING}, /* 00,01,01,cc */ + {0xa0, 0x04, ZC3XX_R080_HBLANKHIGH}, /* 00,80,04,cc */ + {0xa0, 0x05, ZC3XX_R081_HBLANKLOW}, /* 00,81,05,cc */ + {0xa0, 0x16, ZC3XX_R083_RGAINADDR}, /* 00,83,16,cc */ + {0xa0, 0x18, ZC3XX_R085_BGAINADDR}, /* 00,85,18,cc */ + {0xa0, 0x1a, ZC3XX_R086_EXPTIMEHIGH}, /* 00,86,1a,cc */ + {0xa0, 0x1b, ZC3XX_R087_EXPTIMEMID}, /* 00,87,1b,cc */ + {0xa0, 0x1c, ZC3XX_R088_EXPTIMELOW}, /* 00,88,1c,cc */ + {0xa0, 0xee, ZC3XX_R08B_I2CDEVICEADDR}, /* 00,8b,ee,cc */ + {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, /* 00,08,03,cc */ + {0xa0, 0x03, ZC3XX_R012_VIDEOCONTROLFUNC}, /* 00,12,03,cc */ + {0xa0, 0x01, ZC3XX_R012_VIDEOCONTROLFUNC}, /* 00,12,01,cc */ + {0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH}, /* 00,03,02,cc */ + {0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW}, /* 00,04,80,cc */ + {0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH}, /* 00,05,01,cc */ + {0xa0, 0xe0, ZC3XX_R006_FRAMEHEIGHTLOW}, /* 00,06,e0,cc */ + {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE}, /* 01,80,42,cc */ + {0xaa, 0x8d, 0x0008}, /* 00,8d,08,aa */ + {0xa0, 0x00, ZC3XX_R098_WINYSTARTLOW}, /* 00,98,00,cc */ + {0xa0, 0x00, ZC3XX_R09A_WINXSTARTLOW}, /* 00,9a,00,cc */ + {0xa0, 0x00, ZC3XX_R11A_FIRSTYLOW}, /* 01,1a,00,cc */ + {0xa0, 0x00, ZC3XX_R11C_FIRSTXLOW}, /* 01,1c,00,cc */ + {0xa0, 0xe8, ZC3XX_R09C_WINHEIGHTLOW}, /* 00,9c,e8,cc */ + {0xa0, 0x88, ZC3XX_R09E_WINWIDTHLOW}, /* 00,9e,88,cc */ + {0xaa, 0x09, 0x00cc}, /* 00,09,cc,aa */ + {0xaa, 0x0b, 0x0005}, /* 00,0b,05,aa */ + {0xaa, 0x0d, 0x0058}, /* 00,0d,58,aa */ + {0xaa, 0x0f, 0x00ed}, /* 00,0f,ed,aa */ + {0xaa, 0x87, 0x0000}, /* 00,87,00,aa */ + {0xaa, 0x88, 0x0004}, /* 00,88,04,aa */ + {0xaa, 0x89, 0x0000}, /* 00,89,00,aa */ + {0xaa, 0x8a, 0x0005}, /* 00,8a,05,aa */ + {0xaa, 0x13, 0x0003}, /* 00,13,03,aa */ + {0xaa, 0x16, 0x0040}, /* 00,16,40,aa */ + {0xaa, 0x18, 0x0040}, /* 00,18,40,aa */ + {0xaa, 0x1d, 0x0002}, /* 00,1d,02,aa */ + {0xaa, 0x29, 0x00e8}, /* 00,29,e8,aa */ + {0xaa, 0x45, 0x0045}, /* 00,45,45,aa */ + {0xaa, 0x50, 0x00ed}, /* 00,50,ed,aa */ + {0xaa, 0x51, 0x0025}, /* 00,51,25,aa */ + {0xaa, 0x52, 0x0042}, /* 00,52,42,aa */ + {0xaa, 0x53, 0x002f}, /* 00,53,2f,aa */ + {0xaa, 0x79, 0x0025}, /* 00,79,25,aa */ + {0xaa, 0x7b, 0x0000}, /* 00,7b,00,aa */ + {0xaa, 0x7e, 0x0025}, /* 00,7e,25,aa */ + {0xaa, 0x7f, 0x0025}, /* 00,7f,25,aa */ + {0xaa, 0x21, 0x0000}, /* 00,21,00,aa */ + {0xaa, 0x33, 0x0036}, /* 00,33,36,aa */ + {0xaa, 0x36, 0x0060}, /* 00,36,60,aa */ + {0xaa, 0x37, 0x0008}, /* 00,37,08,aa */ + {0xaa, 0x3b, 0x0031}, /* 00,3b,31,aa */ + {0xaa, 0x44, 0x000f}, /* 00,44,0f,aa */ + {0xaa, 0x58, 0x0002}, /* 00,58,02,aa */ + {0xaa, 0x66, 0x00c0}, /* 00,66,c0,aa */ + {0xaa, 0x67, 0x0044}, /* 00,67,44,aa */ + {0xaa, 0x6b, 0x00a0}, /* 00,6b,a0,aa */ + {0xaa, 0x6c, 0x0054}, /* 00,6c,54,aa */ + {0xaa, 0xd6, 0x0007}, /* 00,d6,07,aa */ + {0xa0, 0xf7, ZC3XX_R101_SENSORCORRECTION}, /* 01,01,f7,cc */ + {0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC}, /* 00,12,05,cc */ + {0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE}, /* 01,00,0d,cc */ + {0xa0, 0x06, ZC3XX_R189_AWBSTATUS}, /* 01,89,06,cc */ + {0xa0, 0x00, 0x01ad}, /* 01,ad,00,cc */ + {0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE}, /* 01,c5,03,cc */ + {0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05}, /* 01,cb,13,cc */ + {0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE}, /* 02,50,08,cc */ + {0xa0, 0x08, ZC3XX_R301_EEPROMACCESS}, /* 03,01,08,cc */ + {0xa0, 0x7a, ZC3XX_R116_RGAIN}, /* 01,16,7a,cc */ + {0xa0, 0x4a, ZC3XX_R118_BGAIN}, /* 01,18,4a,cc */ + {} +}; + +static const struct usb_action PO2030_50HZ[] = { + {0xaa, 0x8d, 0x0008}, /* 00,8d,08,aa */ + {0xaa, 0x1a, 0x0001}, /* 00,1a,01,aa */ + {0xaa, 0x1b, 0x000a}, /* 00,1b,0a,aa */ + {0xaa, 0x1c, 0x00b0}, /* 00,1c,b0,aa */ + {0xa0, 0x05, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,05,cc */ + {0xa0, 0x35, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,35,cc */ + {0xa0, 0x70, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,70,cc */ + {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */ + {0xa0, 0x85, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,85,cc */ + {0xa0, 0x58, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,58,cc */ + {0xa0, 0x0c, ZC3XX_R18C_AEFREEZE}, /* 01,8c,0c,cc */ + {0xa0, 0x18, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,18,cc */ + {0xa0, 0x60, ZC3XX_R1A8_DIGITALGAIN}, /* 01,a8,60,cc */ + {0xa0, 0x10, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,10,cc */ + {0xa0, 0x22, ZC3XX_R1AA_DIGITALGAINSTEP}, /* 01,aa,22,cc */ + {0xa0, 0x88, ZC3XX_R18D_YTARGET}, /* 01,8d,88,cc */ + {0xa0, 0x58, ZC3XX_R11D_GLOBALGAIN}, /* 01,1d,58,cc */ + {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE}, /* 01,80,42,cc */ + {} +}; + +static const struct usb_action PO2030_60HZ[] = { + {0xaa, 0x8d, 0x0008}, /* 00,8d,08,aa */ + {0xaa, 0x1a, 0x0000}, /* 00,1a,00,aa */ + {0xaa, 0x1b, 0x00de}, /* 00,1b,de,aa */ + {0xaa, 0x1c, 0x0040}, /* 00,1c,40,aa */ + {0xa0, 0x08, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,08,cc */ + {0xa0, 0xae, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,ae,cc */ + {0xa0, 0x80, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,80,cc */ + {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */ + {0xa0, 0x6f, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,6f,cc */ + {0xa0, 0x20, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,20,cc */ + {0xa0, 0x0c, ZC3XX_R18C_AEFREEZE}, /* 01,8c,0c,cc */ + {0xa0, 0x18, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,18,cc */ + {0xa0, 0x60, ZC3XX_R1A8_DIGITALGAIN}, /* 01,a8,60,cc */ + {0xa0, 0x10, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,10,cc */ + {0xa0, 0x22, ZC3XX_R1AA_DIGITALGAINSTEP}, /* 01,aa,22,cc */ + {0xa0, 0x88, ZC3XX_R18D_YTARGET}, /* 01,8d,88,cc */ + /* win: 01,8d,80 */ + {0xa0, 0x58, ZC3XX_R11D_GLOBALGAIN}, /* 01,1d,58,cc */ + {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE}, /* 01,80,42,cc */ + {} +}; + +static const struct usb_action PO2030_NoFliker[] = { + {0xa0, 0x02, ZC3XX_R180_AUTOCORRECTENABLE}, /* 01,80,02,cc */ + {0xaa, 0x8d, 0x000d}, /* 00,8d,0d,aa */ + {0xaa, 0x1a, 0x0000}, /* 00,1a,00,aa */ + {0xaa, 0x1b, 0x0002}, /* 00,1b,02,aa */ + {0xaa, 0x1c, 0x0078}, /* 00,1c,78,aa */ + {0xaa, 0x46, 0x0000}, /* 00,46,00,aa */ + {0xaa, 0x15, 0x0000}, /* 00,15,00,aa */ + {} +}; + +/* TEST */ +static const struct usb_action tas5130CK_Initial[] = { + {0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL}, + {0xa0, 0x01, 0x003b}, + {0xa0, 0x0e, 0x003a}, + {0xa0, 0x01, 0x0038}, + {0xa0, 0x0b, 0x0039}, + {0xa0, 0x00, 0x0038}, + {0xa0, 0x0b, 0x0039}, + {0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL}, + {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, + {0xa0, 0x0a, ZC3XX_R010_CMOSSENSORSELECT}, + {0xa0, 0x10, ZC3XX_R002_CLOCKSELECT}, + {0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH}, + {0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW}, + {0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH}, + {0xa0, 0xe0, ZC3XX_R006_FRAMEHEIGHTLOW}, + {0xa0, 0xdc, ZC3XX_R08B_I2CDEVICEADDR}, + {0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING}, + {0xa0, 0x07, ZC3XX_R012_VIDEOCONTROLFUNC}, + {0xa0, 0x00, ZC3XX_R098_WINYSTARTLOW}, + {0xa0, 0x00, ZC3XX_R09A_WINXSTARTLOW}, + {0xa0, 0x00, ZC3XX_R11A_FIRSTYLOW}, + {0xa0, 0x00, ZC3XX_R11C_FIRSTXLOW}, + {0xa0, 0xdc, ZC3XX_R08B_I2CDEVICEADDR}, + {0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC}, + {0xa0, 0x01, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x01, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x06, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x00, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x08, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x83, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x04, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x01, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x04, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x08, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x06, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x02, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x11, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x03, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0xE7, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x01, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x04, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x87, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x02, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x07, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x02, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x30, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x20, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x00, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x51, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x35, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x7F, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x30, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x05, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x31, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x00, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x58, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x78, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x62, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x11, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x04, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x2B, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x7f, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x2c, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x7f, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x2D, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x7f, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x2e, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x7f, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x10, ZC3XX_R087_EXPTIMEMID}, + {0xa0, 0xb7, ZC3XX_R101_SENSORCORRECTION}, + {0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC}, + {0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE}, + {0xa0, 0x06, ZC3XX_R189_AWBSTATUS}, + {0xa0, 0x09, 0x01ad}, + {0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE}, + {0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05}, + {0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE}, + {0xa0, 0x08, ZC3XX_R301_EEPROMACCESS}, + {0xa0, 0x60, ZC3XX_R1A8_DIGITALGAIN}, + {0xa0, 0x6c, ZC3XX_R18D_YTARGET}, + {0xa0, 0x61, ZC3XX_R116_RGAIN}, + {0xa0, 0x65, ZC3XX_R118_BGAIN}, + {0xa0, 0x09, 0x01ad}, + {0xa0, 0x15, 0x01ae}, + {0xa0, 0x4c, ZC3XX_R10A_RGB00}, /* matrix */ + {0xa0, 0xf1, ZC3XX_R10B_RGB01}, + {0xa0, 0x03, ZC3XX_R10C_RGB02}, + {0xa0, 0xfe, ZC3XX_R10D_RGB10}, + {0xa0, 0x51, ZC3XX_R10E_RGB11}, + {0xa0, 0xf1, ZC3XX_R10F_RGB12}, + {0xa0, 0xec, ZC3XX_R110_RGB20}, + {0xa0, 0x03, ZC3XX_R111_RGB21}, + {0xa0, 0x51, ZC3XX_R112_RGB22}, + {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, + {0xa0, 0x08, ZC3XX_R1C6_SHARPNESS00}, /* sharpness+ */ + {0xa0, 0x0f, ZC3XX_R1CB_SHARPNESS05}, /* sharpness- */ + {0xa0, 0x38, ZC3XX_R120_GAMMA00}, /* gamma > 5 */ + {0xa0, 0x51, ZC3XX_R121_GAMMA01}, + {0xa0, 0x6e, ZC3XX_R122_GAMMA02}, + {0xa0, 0x8c, ZC3XX_R123_GAMMA03}, + {0xa0, 0xa2, ZC3XX_R124_GAMMA04}, + {0xa0, 0xb6, ZC3XX_R125_GAMMA05}, + {0xa0, 0xc8, ZC3XX_R126_GAMMA06}, + {0xa0, 0xd6, ZC3XX_R127_GAMMA07}, + {0xa0, 0xe2, ZC3XX_R128_GAMMA08}, + {0xa0, 0xed, ZC3XX_R129_GAMMA09}, + {0xa0, 0xf5, ZC3XX_R12A_GAMMA0A}, + {0xa0, 0xfc, ZC3XX_R12B_GAMMA0B}, + {0xa0, 0xff, ZC3XX_R12C_GAMMA0C}, + {0xa0, 0xff, ZC3XX_R12D_GAMMA0D}, + {0xa0, 0xff, ZC3XX_R12E_GAMMA0E}, + {0xa0, 0xff, ZC3XX_R12F_GAMMA0F}, + {0xa0, 0x12, ZC3XX_R130_GAMMA10}, + {0xa0, 0x1b, ZC3XX_R131_GAMMA11}, + {0xa0, 0x1d, ZC3XX_R132_GAMMA12}, + {0xa0, 0x1a, ZC3XX_R133_GAMMA13}, + {0xa0, 0x15, ZC3XX_R134_GAMMA14}, + {0xa0, 0x12, ZC3XX_R135_GAMMA15}, + {0xa0, 0x0f, ZC3XX_R136_GAMMA16}, + {0xa0, 0x0d, ZC3XX_R137_GAMMA17}, + {0xa0, 0x0b, ZC3XX_R138_GAMMA18}, + {0xa0, 0x09, ZC3XX_R139_GAMMA19}, + {0xa0, 0x07, ZC3XX_R13A_GAMMA1A}, + {0xa0, 0x05, ZC3XX_R13B_GAMMA1B}, + {0xa0, 0x00, ZC3XX_R13C_GAMMA1C}, + {0xa0, 0x00, ZC3XX_R13D_GAMMA1D}, + {0xa0, 0x00, ZC3XX_R13E_GAMMA1E}, + {0xa0, 0x01, ZC3XX_R13F_GAMMA1F}, + {0xa0, 0x4c, ZC3XX_R10A_RGB00}, /* matrix */ + {0xa0, 0xf1, ZC3XX_R10B_RGB01}, + {0xa0, 0x03, ZC3XX_R10C_RGB02}, + {0xa0, 0xfe, ZC3XX_R10D_RGB10}, + {0xa0, 0x51, ZC3XX_R10E_RGB11}, + {0xa0, 0xf1, ZC3XX_R10F_RGB12}, + {0xa0, 0xec, ZC3XX_R110_RGB20}, + {0xa0, 0x03, ZC3XX_R111_RGB21}, + {0xa0, 0x51, ZC3XX_R112_RGB22}, + {0xa0, 0x10, ZC3XX_R180_AUTOCORRECTENABLE}, + {0xa0, 0x00, ZC3XX_R180_AUTOCORRECTENABLE}, + {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, + {0xa0, 0x05, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x09, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x09, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x34, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x01, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, + {0xa0, 0x07, ZC3XX_R191_EXPOSURELIMITMID}, + {0xa0, 0xd2, ZC3XX_R192_EXPOSURELIMITLOW}, + {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, + {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, + {0xa0, 0x9a, ZC3XX_R197_ANTIFLICKERLOW}, + {0xa0, 0x0e, ZC3XX_R18C_AEFREEZE}, + {0xa0, 0x1c, ZC3XX_R18F_AEUNFREEZE}, + {0xa0, 0x14, ZC3XX_R1A9_DIGITALLIMITDIFF}, + {0xa0, 0x66, ZC3XX_R1AA_DIGITALGAINSTEP}, + {0xa0, 0xd7, ZC3XX_R01D_HSYNC_0}, + {0xa0, 0xf4, ZC3XX_R01E_HSYNC_1}, + {0xa0, 0xf9, ZC3XX_R01F_HSYNC_2}, + {0xa0, 0xff, ZC3XX_R020_HSYNC_3}, + {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE}, + {0xa0, 0x09, 0x01ad}, + {0xa0, 0x15, 0x01ae}, + {0xa0, 0x40, ZC3XX_R180_AUTOCORRECTENABLE}, + {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE}, + {} +}; + +static const struct usb_action tas5130CK_InitialScale[] = { + {0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL}, + {0xa0, 0x01, 0x003b}, + {0xa0, 0x0e, 0x003a}, + {0xa0, 0x01, 0x0038}, + {0xa0, 0x0b, 0x0039}, + {0xa0, 0x00, 0x0038}, + {0xa0, 0x0b, 0x0039}, + {0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL}, + {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, + {0xa0, 0x0a, ZC3XX_R010_CMOSSENSORSELECT}, + {0xa0, 0x00, ZC3XX_R002_CLOCKSELECT}, + {0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH}, + {0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW}, + {0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH}, + {0xa0, 0xe0, ZC3XX_R006_FRAMEHEIGHTLOW}, + {0xa0, 0xdc, ZC3XX_R08B_I2CDEVICEADDR}, + {0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING}, + {0xa0, 0x07, ZC3XX_R012_VIDEOCONTROLFUNC}, + {0xa0, 0x00, ZC3XX_R098_WINYSTARTLOW}, + {0xa0, 0x00, ZC3XX_R09A_WINXSTARTLOW}, + {0xa0, 0x00, ZC3XX_R11A_FIRSTYLOW}, + {0xa0, 0x00, ZC3XX_R11C_FIRSTXLOW}, + {0xa0, 0xdc, ZC3XX_R08B_I2CDEVICEADDR}, + {0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC}, + {0xa0, 0x01, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x01, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x06, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x00, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x08, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x83, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x04, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x01, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x04, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x08, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x06, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x02, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x11, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x03, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0xe5, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x01, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x04, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x85, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x02, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x07, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x02, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x30, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x20, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x00, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x51, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x35, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x7F, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x50, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x30, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x05, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x31, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x00, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x58, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x78, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x62, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x11, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x04, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x2B, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x7f, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x2C, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x7F, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x2D, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x7f, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x2e, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x7f, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x10, ZC3XX_R087_EXPTIMEMID}, + {0xa0, 0xb7, ZC3XX_R101_SENSORCORRECTION}, + {0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC}, + {0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE}, + {0xa0, 0x06, ZC3XX_R189_AWBSTATUS}, + {0xa0, 0x09, 0x01ad}, + {0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE}, + {0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05}, + {0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE}, + {0xa0, 0x08, ZC3XX_R301_EEPROMACCESS}, + {0xa0, 0x60, ZC3XX_R1A8_DIGITALGAIN}, + {0xa0, 0x6c, ZC3XX_R18D_YTARGET}, + {0xa0, 0x61, ZC3XX_R116_RGAIN}, + {0xa0, 0x65, ZC3XX_R118_BGAIN}, + {0xa0, 0x09, 0x01ad}, + {0xa0, 0x15, 0x01ae}, + {0xa0, 0x4c, ZC3XX_R10A_RGB00}, /* matrix */ + {0xa0, 0xf1, ZC3XX_R10B_RGB01}, + {0xa0, 0x03, ZC3XX_R10C_RGB02}, + {0xa0, 0xfe, ZC3XX_R10D_RGB10}, + {0xa0, 0x51, ZC3XX_R10E_RGB11}, + {0xa0, 0xf1, ZC3XX_R10F_RGB12}, + {0xa0, 0xec, ZC3XX_R110_RGB20}, + {0xa0, 0x03, ZC3XX_R111_RGB21}, + {0xa0, 0x51, ZC3XX_R112_RGB22}, + {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, + {0xa0, 0x08, ZC3XX_R1C6_SHARPNESS00}, /* sharpness+ */ + {0xa0, 0x0f, ZC3XX_R1CB_SHARPNESS05}, /* sharpness- */ + {0xa0, 0x38, ZC3XX_R120_GAMMA00}, /* gamma > 5 */ + {0xa0, 0x51, ZC3XX_R121_GAMMA01}, + {0xa0, 0x6e, ZC3XX_R122_GAMMA02}, + {0xa0, 0x8c, ZC3XX_R123_GAMMA03}, + {0xa0, 0xa2, ZC3XX_R124_GAMMA04}, + {0xa0, 0xb6, ZC3XX_R125_GAMMA05}, + {0xa0, 0xc8, ZC3XX_R126_GAMMA06}, + {0xa0, 0xd6, ZC3XX_R127_GAMMA07}, + {0xa0, 0xe2, ZC3XX_R128_GAMMA08}, + {0xa0, 0xed, ZC3XX_R129_GAMMA09}, + {0xa0, 0xf5, ZC3XX_R12A_GAMMA0A}, + {0xa0, 0xfc, ZC3XX_R12B_GAMMA0B}, + {0xa0, 0xff, ZC3XX_R12C_GAMMA0C}, + {0xa0, 0xff, ZC3XX_R12D_GAMMA0D}, + {0xa0, 0xff, ZC3XX_R12E_GAMMA0E}, + {0xa0, 0xff, ZC3XX_R12F_GAMMA0F}, + {0xa0, 0x12, ZC3XX_R130_GAMMA10}, + {0xa0, 0x1b, ZC3XX_R131_GAMMA11}, + {0xa0, 0x1d, ZC3XX_R132_GAMMA12}, + {0xa0, 0x1a, ZC3XX_R133_GAMMA13}, + {0xa0, 0x15, ZC3XX_R134_GAMMA14}, + {0xa0, 0x12, ZC3XX_R135_GAMMA15}, + {0xa0, 0x0f, ZC3XX_R136_GAMMA16}, + {0xa0, 0x0d, ZC3XX_R137_GAMMA17}, + {0xa0, 0x0b, ZC3XX_R138_GAMMA18}, + {0xa0, 0x09, ZC3XX_R139_GAMMA19}, + {0xa0, 0x07, ZC3XX_R13A_GAMMA1A}, + {0xa0, 0x05, ZC3XX_R13B_GAMMA1B}, + {0xa0, 0x00, ZC3XX_R13C_GAMMA1C}, + {0xa0, 0x00, ZC3XX_R13D_GAMMA1D}, + {0xa0, 0x00, ZC3XX_R13E_GAMMA1E}, + {0xa0, 0x01, ZC3XX_R13F_GAMMA1F}, + {0xa0, 0x4c, ZC3XX_R10A_RGB00}, /* matrix */ + {0xa0, 0xf1, ZC3XX_R10B_RGB01}, + {0xa0, 0x03, ZC3XX_R10C_RGB02}, + {0xa0, 0xfe, ZC3XX_R10D_RGB10}, + {0xa0, 0x51, ZC3XX_R10E_RGB11}, + {0xa0, 0xf1, ZC3XX_R10F_RGB12}, + {0xa0, 0xec, ZC3XX_R110_RGB20}, + {0xa0, 0x03, ZC3XX_R111_RGB21}, + {0xa0, 0x51, ZC3XX_R112_RGB22}, + {0xa0, 0x10, ZC3XX_R180_AUTOCORRECTENABLE}, + {0xa0, 0x00, ZC3XX_R180_AUTOCORRECTENABLE}, + {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, + {0xa0, 0x05, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x62, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x09, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0xaa, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x01, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, + {0xa0, 0x03, ZC3XX_R191_EXPOSURELIMITMID}, + {0xa0, 0x9b, ZC3XX_R192_EXPOSURELIMITLOW}, + {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, + {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, + {0xa0, 0x47, ZC3XX_R197_ANTIFLICKERLOW}, + {0xa0, 0x0e, ZC3XX_R18C_AEFREEZE}, + {0xa0, 0x1c, ZC3XX_R18F_AEUNFREEZE}, + {0xa0, 0x14, ZC3XX_R1A9_DIGITALLIMITDIFF}, + {0xa0, 0x66, ZC3XX_R1AA_DIGITALGAINSTEP}, + {0xa0, 0x62, ZC3XX_R01D_HSYNC_0}, + {0xa0, 0x90, ZC3XX_R01E_HSYNC_1}, + {0xa0, 0xc8, ZC3XX_R01F_HSYNC_2}, + {0xa0, 0xff, ZC3XX_R020_HSYNC_3}, + {0xa0, 0x60, ZC3XX_R11D_GLOBALGAIN}, + {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE}, + {0xa0, 0x09, 0x01ad}, + {0xa0, 0x15, 0x01ae}, + {0xa0, 0x40, ZC3XX_R180_AUTOCORRECTENABLE}, + {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE}, + {0xa0, 0x30, 0x0007}, + {0xa0, 0x02, ZC3XX_R008_CLOCKSETTING}, + {0xa0, 0x00, 0x0007}, + {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, + {} +}; + +static const struct usb_action tas5130cxx_Initial[] = { + {0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL}, + {0xa0, 0x50, ZC3XX_R002_CLOCKSELECT}, + {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, + {0xa0, 0x02, ZC3XX_R010_CMOSSENSORSELECT}, + {0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING}, + {0xa0, 0x00, ZC3XX_R001_SYSTEMOPERATING}, + {0xa0, 0x01, ZC3XX_R012_VIDEOCONTROLFUNC}, + {0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING}, + {0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC}, + {0xa0, 0x07, ZC3XX_R0A5_EXPOSUREGAIN}, + {0xa0, 0x02, ZC3XX_R0A6_EXPOSUREBLACKLVL}, + + {0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH}, + {0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW}, + {0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH}, + {0xa0, 0xe0, ZC3XX_R006_FRAMEHEIGHTLOW}, + + {0xa0, 0x04, ZC3XX_R098_WINYSTARTLOW}, + {0xa0, 0x0f, ZC3XX_R09A_WINXSTARTLOW}, + {0xa0, 0x04, ZC3XX_R11A_FIRSTYLOW}, + {0xa0, 0x0f, ZC3XX_R11C_FIRSTXLOW}, + {0xa0, 0xe8, ZC3XX_R09C_WINHEIGHTLOW}, + {0xa0, 0x02, ZC3XX_R09D_WINWIDTHHIGH}, + {0xa0, 0x88, ZC3XX_R09E_WINWIDTHLOW}, + {0xa0, 0x06, ZC3XX_R08D_COMPABILITYMODE}, + {0xa0, 0xf7, ZC3XX_R101_SENSORCORRECTION}, + {0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE}, + {0xa0, 0x06, ZC3XX_R189_AWBSTATUS}, + {0xa0, 0x68, ZC3XX_R18D_YTARGET}, + {0xa0, 0x60, ZC3XX_R1A8_DIGITALGAIN}, + {0xa0, 0x00, 0x01ad}, + {0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE}, + {0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05}, + {0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE}, + {0xa0, 0x08, ZC3XX_R301_EEPROMACCESS}, + {0xa1, 0x01, 0x0002}, + {0xa1, 0x01, 0x0008}, + {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, /* clock ? */ + {0xa0, 0x08, ZC3XX_R1C6_SHARPNESS00}, /* sharpness+ */ + {0xa1, 0x01, 0x01c8}, + {0xa1, 0x01, 0x01c9}, + {0xa1, 0x01, 0x01ca}, + {0xa0, 0x0f, ZC3XX_R1CB_SHARPNESS05}, /* sharpness- */ + + {0xa0, 0x68, ZC3XX_R10A_RGB00}, /* matrix */ + {0xa0, 0xec, ZC3XX_R10B_RGB01}, + {0xa0, 0xec, ZC3XX_R10C_RGB02}, + {0xa0, 0xec, ZC3XX_R10D_RGB10}, + {0xa0, 0x68, ZC3XX_R10E_RGB11}, + {0xa0, 0xec, ZC3XX_R10F_RGB12}, + {0xa0, 0xec, ZC3XX_R110_RGB20}, + {0xa0, 0xec, ZC3XX_R111_RGB21}, + {0xa0, 0x68, ZC3XX_R112_RGB22}, + + {0xa1, 0x01, 0x018d}, + {0xa0, 0x90, ZC3XX_R18D_YTARGET}, /* 90 */ + {0xa1, 0x01, 0x0180}, + {0xa0, 0x00, ZC3XX_R180_AUTOCORRECTENABLE}, + {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, + + {0xaa, 0xa3, 0x0001}, + {0xaa, 0xa4, 0x0077}, + {0xa0, 0x01, ZC3XX_R0A3_EXPOSURETIMEHIGH}, + {0xa0, 0x77, ZC3XX_R0A4_EXPOSURETIMELOW}, + + {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 00 */ + {0xa0, 0x03, ZC3XX_R191_EXPOSURELIMITMID}, /* 03 */ + {0xa0, 0xe8, ZC3XX_R192_EXPOSURELIMITLOW}, /* e8 */ + {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 0 */ + {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 0 */ + {0xa0, 0x7d, ZC3XX_R197_ANTIFLICKERLOW}, /* 7d */ + + {0xa0, 0x0c, ZC3XX_R18C_AEFREEZE}, + {0xa0, 0x18, ZC3XX_R18F_AEUNFREEZE}, + {0xa0, 0x08, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 08 */ + {0xa0, 0x24, ZC3XX_R1AA_DIGITALGAINSTEP}, /* 24 */ + {0xa0, 0xf0, ZC3XX_R01D_HSYNC_0}, + {0xa0, 0xf4, ZC3XX_R01E_HSYNC_1}, + {0xa0, 0xf8, ZC3XX_R01F_HSYNC_2}, + {0xa0, 0xff, ZC3XX_R020_HSYNC_3}, + {0xa0, 0x03, ZC3XX_R09F_MAXXHIGH}, + {0xa0, 0xc0, ZC3XX_R0A0_MAXXLOW}, + {0xa0, 0x50, ZC3XX_R11D_GLOBALGAIN}, /* 50 */ + {0xa0, 0x40, ZC3XX_R180_AUTOCORRECTENABLE}, + {0xa1, 0x01, 0x0180}, + {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE}, + {} +}; +static const struct usb_action tas5130cxx_InitialScale[] = { + {0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL}, + {0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL}, + {0xa0, 0x40, ZC3XX_R002_CLOCKSELECT}, + + {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, + {0xa1, 0x01, 0x0008}, + + {0xa0, 0x02, ZC3XX_R010_CMOSSENSORSELECT}, + {0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING}, + {0xa0, 0x00, ZC3XX_R001_SYSTEMOPERATING}, + {0xa0, 0x01, ZC3XX_R012_VIDEOCONTROLFUNC}, + {0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING}, + {0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC}, + {0xa0, 0x07, ZC3XX_R0A5_EXPOSUREGAIN}, + {0xa0, 0x02, ZC3XX_R0A6_EXPOSUREBLACKLVL}, + {0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH}, + {0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW}, + {0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH}, + {0xa0, 0xe0, ZC3XX_R006_FRAMEHEIGHTLOW}, + {0xa0, 0x05, ZC3XX_R098_WINYSTARTLOW}, + {0xa0, 0x0f, ZC3XX_R09A_WINXSTARTLOW}, + {0xa0, 0x05, ZC3XX_R11A_FIRSTYLOW}, + {0xa0, 0x0f, ZC3XX_R11C_FIRSTXLOW}, + {0xa0, 0xe6, ZC3XX_R09C_WINHEIGHTLOW}, + {0xa0, 0x02, ZC3XX_R09D_WINWIDTHHIGH}, + {0xa0, 0x86, ZC3XX_R09E_WINWIDTHLOW}, + {0xa0, 0x06, ZC3XX_R08D_COMPABILITYMODE}, + {0xa0, 0x37, ZC3XX_R101_SENSORCORRECTION}, + {0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE}, + {0xa0, 0x06, ZC3XX_R189_AWBSTATUS}, + {0xa0, 0x68, ZC3XX_R18D_YTARGET}, + {0xa0, 0x60, ZC3XX_R1A8_DIGITALGAIN}, + {0xa0, 0x00, 0x01ad}, + {0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE}, + {0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05}, + {0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE}, + {0xa0, 0x08, ZC3XX_R301_EEPROMACCESS}, + {0xa1, 0x01, 0x0002}, + {0xa1, 0x01, 0x0008}, + + {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, + {0xa1, 0x01, 0x0008}, /* clock ? */ + {0xa0, 0x08, ZC3XX_R1C6_SHARPNESS00}, /* sharpness+ */ + {0xa1, 0x01, 0x01c8}, + {0xa1, 0x01, 0x01c9}, + {0xa1, 0x01, 0x01ca}, + {0xa0, 0x0f, ZC3XX_R1CB_SHARPNESS05}, /* sharpness- */ + + {0xa0, 0x68, ZC3XX_R10A_RGB00}, /* matrix */ + {0xa0, 0xec, ZC3XX_R10B_RGB01}, + {0xa0, 0xec, ZC3XX_R10C_RGB02}, + {0xa0, 0xec, ZC3XX_R10D_RGB10}, + {0xa0, 0x68, ZC3XX_R10E_RGB11}, + {0xa0, 0xec, ZC3XX_R10F_RGB12}, + {0xa0, 0xec, ZC3XX_R110_RGB20}, + {0xa0, 0xec, ZC3XX_R111_RGB21}, + {0xa0, 0x68, ZC3XX_R112_RGB22}, + + {0xa1, 0x01, 0x018d}, + {0xa0, 0x90, ZC3XX_R18D_YTARGET}, + {0xa1, 0x01, 0x0180}, + {0xa0, 0x00, ZC3XX_R180_AUTOCORRECTENABLE}, + {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, + {0xaa, 0xa3, 0x0001}, + {0xaa, 0xa4, 0x0063}, + {0xa0, 0x01, ZC3XX_R0A3_EXPOSURETIMEHIGH}, + {0xa0, 0x63, ZC3XX_R0A4_EXPOSURETIMELOW}, + {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, + {0xa0, 0x02, ZC3XX_R191_EXPOSURELIMITMID}, + {0xa0, 0x38, ZC3XX_R192_EXPOSURELIMITLOW}, + {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, + {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, + {0xa0, 0x47, ZC3XX_R197_ANTIFLICKERLOW}, + {0xa0, 0x0c, ZC3XX_R18C_AEFREEZE}, + {0xa0, 0x18, ZC3XX_R18F_AEUNFREEZE}, + {0xa0, 0x08, ZC3XX_R1A9_DIGITALLIMITDIFF}, + {0xa0, 0x24, ZC3XX_R1AA_DIGITALGAINSTEP}, + {0xa0, 0xd3, ZC3XX_R01D_HSYNC_0}, + {0xa0, 0xda, ZC3XX_R01E_HSYNC_1}, + {0xa0, 0xea, ZC3XX_R01F_HSYNC_2}, + {0xa0, 0xff, ZC3XX_R020_HSYNC_3}, + {0xa0, 0x03, ZC3XX_R09F_MAXXHIGH}, + {0xa0, 0x4c, ZC3XX_R0A0_MAXXLOW}, + {0xa0, 0x50, ZC3XX_R11D_GLOBALGAIN}, + {0xa0, 0x40, ZC3XX_R180_AUTOCORRECTENABLE}, + {0xa1, 0x01, 0x0180}, + {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE}, + {} +}; +static const struct usb_action tas5130cxx_50HZ[] = { + {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */ + {0xaa, 0xa3, 0x0001}, /* 00,a3,01,aa */ + {0xaa, 0xa4, 0x0063}, /* 00,a4,63,aa */ + {0xa0, 0x01, ZC3XX_R0A3_EXPOSURETIMEHIGH}, /* 00,a3,01,cc */ + {0xa0, 0x63, ZC3XX_R0A4_EXPOSURETIMELOW}, /* 00,a4,63,cc */ + {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc */ + {0xa0, 0x02, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,02,cc */ + {0xa0, 0x38, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,38,cc */ + {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */ + {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc */ + {0xa0, 0x47, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,47,cc */ + {0xa0, 0x10, ZC3XX_R18C_AEFREEZE}, /* 01,8c,10,cc */ + {0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,20,cc */ + {0xa0, 0x0c, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,0c,cc */ + {0xa0, 0x26, ZC3XX_R1AA_DIGITALGAINSTEP}, /* 01,aa,26,cc */ + {0xa0, 0xd3, ZC3XX_R01D_HSYNC_0}, /* 00,1d,d3,cc */ + {0xa0, 0xda, ZC3XX_R01E_HSYNC_1}, /* 00,1e,da,cc */ + {0xa0, 0xea, ZC3XX_R01F_HSYNC_2}, /* 00,1f,ea,cc */ + {0xa0, 0xff, ZC3XX_R020_HSYNC_3}, /* 00,20,ff,cc */ + {0xa0, 0x03, ZC3XX_R09F_MAXXHIGH}, /* 00,9f,03,cc */ + {} +}; +static const struct usb_action tas5130cxx_50HZScale[] = { + {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */ + {0xaa, 0xa3, 0x0001}, /* 00,a3,01,aa */ + {0xaa, 0xa4, 0x0077}, /* 00,a4,77,aa */ + {0xa0, 0x01, ZC3XX_R0A3_EXPOSURETIMEHIGH}, /* 00,a3,01,cc */ + {0xa0, 0x77, ZC3XX_R0A4_EXPOSURETIMELOW}, /* 00,a4,77,cc */ + {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc */ + {0xa0, 0x03, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,03,cc */ + {0xa0, 0xe8, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,e8,cc */ + {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */ + {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc */ + {0xa0, 0x7d, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,7d,cc */ + {0xa0, 0x14, ZC3XX_R18C_AEFREEZE}, /* 01,8c,14,cc */ + {0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,20,cc */ + {0xa0, 0x0c, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,0c,cc */ + {0xa0, 0x26, ZC3XX_R1AA_DIGITALGAINSTEP}, /* 01,aa,26,cc */ + {0xa0, 0xf0, ZC3XX_R01D_HSYNC_0}, /* 00,1d,f0,cc */ + {0xa0, 0xf4, ZC3XX_R01E_HSYNC_1}, /* 00,1e,f4,cc */ + {0xa0, 0xf8, ZC3XX_R01F_HSYNC_2}, /* 00,1f,f8,cc */ + {0xa0, 0xff, ZC3XX_R020_HSYNC_3}, /* 00,20,ff,cc */ + {0xa0, 0x03, ZC3XX_R09F_MAXXHIGH}, /* 00,9f,03,cc */ + {} +}; +static const struct usb_action tas5130cxx_60HZ[] = { + {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */ + {0xaa, 0xa3, 0x0001}, /* 00,a3,01,aa */ + {0xaa, 0xa4, 0x0036}, /* 00,a4,36,aa */ + {0xa0, 0x01, ZC3XX_R0A3_EXPOSURETIMEHIGH}, /* 00,a3,01,cc */ + {0xa0, 0x36, ZC3XX_R0A4_EXPOSURETIMELOW}, /* 00,a4,36,cc */ + {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc */ + {0xa0, 0x01, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,01,cc */ + {0xa0, 0xf0, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,f0,cc */ + {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */ + {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc */ + {0xa0, 0x3e, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,3e,cc */ + {0xa0, 0x10, ZC3XX_R18C_AEFREEZE}, /* 01,8c,10,cc */ + {0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,20,cc */ + {0xa0, 0x0c, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,0c,cc */ + {0xa0, 0x26, ZC3XX_R1AA_DIGITALGAINSTEP}, /* 01,aa,26,cc */ + {0xa0, 0xca, ZC3XX_R01D_HSYNC_0}, /* 00,1d,ca,cc */ + {0xa0, 0xd0, ZC3XX_R01E_HSYNC_1}, /* 00,1e,d0,cc */ + {0xa0, 0xe0, ZC3XX_R01F_HSYNC_2}, /* 00,1f,e0,cc */ + {0xa0, 0xff, ZC3XX_R020_HSYNC_3}, /* 00,20,ff,cc */ + {0xa0, 0x03, ZC3XX_R09F_MAXXHIGH}, /* 00,9f,03,cc */ + {} +}; +static const struct usb_action tas5130cxx_60HZScale[] = { + {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */ + {0xaa, 0xa3, 0x0001}, /* 00,a3,01,aa */ + {0xaa, 0xa4, 0x0077}, /* 00,a4,77,aa */ + {0xa0, 0x01, ZC3XX_R0A3_EXPOSURETIMEHIGH}, /* 00,a3,01,cc */ + {0xa0, 0x77, ZC3XX_R0A4_EXPOSURETIMELOW}, /* 00,a4,77,cc */ + {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc */ + {0xa0, 0x03, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,03,cc */ + {0xa0, 0xe8, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,e8,cc */ + {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */ + {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc */ + {0xa0, 0x7d, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,7d,cc */ + {0xa0, 0x14, ZC3XX_R18C_AEFREEZE}, /* 01,8c,14,cc */ + {0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,20,cc */ + {0xa0, 0x0c, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,0c,cc */ + {0xa0, 0x26, ZC3XX_R1AA_DIGITALGAINSTEP}, /* 01,aa,26,cc */ + {0xa0, 0xc8, ZC3XX_R01D_HSYNC_0}, /* 00,1d,c8,cc */ + {0xa0, 0xd0, ZC3XX_R01E_HSYNC_1}, /* 00,1e,d0,cc */ + {0xa0, 0xe0, ZC3XX_R01F_HSYNC_2}, /* 00,1f,e0,cc */ + {0xa0, 0xff, ZC3XX_R020_HSYNC_3}, /* 00,20,ff,cc */ + {0xa0, 0x03, ZC3XX_R09F_MAXXHIGH}, /* 00,9f,03,cc */ + {} +}; +static const struct usb_action tas5130cxx_NoFliker[] = { + {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */ + {0xaa, 0xa3, 0x0001}, /* 00,a3,01,aa */ + {0xaa, 0xa4, 0x0040}, /* 00,a4,40,aa */ + {0xa0, 0x01, ZC3XX_R0A3_EXPOSURETIMEHIGH}, /* 00,a3,01,cc */ + {0xa0, 0x40, ZC3XX_R0A4_EXPOSURETIMELOW}, /* 00,a4,40,cc */ + {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc */ + {0xa0, 0x01, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,01,cc */ + {0xa0, 0xf0, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,f0,cc */ + {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */ + {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc */ + {0xa0, 0x10, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,10,cc */ + {0xa0, 0x10, ZC3XX_R18C_AEFREEZE}, /* 01,8c,10,cc */ + {0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,20,cc */ + {0xa0, 0x00, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,00,cc */ + {0xa0, 0x00, ZC3XX_R1AA_DIGITALGAINSTEP}, /* 01,aa,00,cc */ + {0xa0, 0xbc, ZC3XX_R01D_HSYNC_0}, /* 00,1d,bc,cc */ + {0xa0, 0xd0, ZC3XX_R01E_HSYNC_1}, /* 00,1e,d0,cc */ + {0xa0, 0xe0, ZC3XX_R01F_HSYNC_2}, /* 00,1f,e0,cc */ + {0xa0, 0xff, ZC3XX_R020_HSYNC_3}, /* 00,20,ff,cc */ + {0xa0, 0x02, ZC3XX_R09F_MAXXHIGH}, /* 00,9f,02,cc */ + {} +}; + +static const struct usb_action tas5130cxx_NoFlikerScale[] = { + {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */ + {0xaa, 0xa3, 0x0001}, /* 00,a3,01,aa */ + {0xaa, 0xa4, 0x0090}, /* 00,a4,90,aa */ + {0xa0, 0x01, ZC3XX_R0A3_EXPOSURETIMEHIGH}, /* 00,a3,01,cc */ + {0xa0, 0x90, ZC3XX_R0A4_EXPOSURETIMELOW}, /* 00,a4,90,cc */ + {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc */ + {0xa0, 0x03, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,03,cc */ + {0xa0, 0xf0, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,f0,cc */ + {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */ + {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc */ + {0xa0, 0x10, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,10,cc */ + {0xa0, 0x10, ZC3XX_R18C_AEFREEZE}, /* 01,8c,10,cc */ + {0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,20,cc */ + {0xa0, 0x00, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,00,cc */ + {0xa0, 0x00, ZC3XX_R1AA_DIGITALGAINSTEP}, /* 01,aa,00,cc */ + {0xa0, 0xbc, ZC3XX_R01D_HSYNC_0}, /* 00,1d,bc,cc */ + {0xa0, 0xd0, ZC3XX_R01E_HSYNC_1}, /* 00,1e,d0,cc */ + {0xa0, 0xe0, ZC3XX_R01F_HSYNC_2}, /* 00,1f,e0,cc */ + {0xa0, 0xff, ZC3XX_R020_HSYNC_3}, /* 00,20,ff,cc */ + {0xa0, 0x02, ZC3XX_R09F_MAXXHIGH}, /* 00,9f,02,cc */ + {} +}; + +static const struct usb_action tas5130c_vf0250_Initial[] = { + {0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL}, /* 00,00,01,cc, */ + {0xa0, 0x02, ZC3XX_R008_CLOCKSETTING}, /* 00,08,02,cc, */ + {0xa0, 0x01, ZC3XX_R010_CMOSSENSORSELECT}, /* 00,10,01,cc, */ + {0xa0, 0x10, ZC3XX_R002_CLOCKSELECT}, /* 00,02,00,cc, + * 0<->10 */ + {0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH}, /* 00,03,02,cc, */ + {0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW}, /* 00,04,80,cc, */ + {0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH}, /* 00,05,01,cc, */ + {0xa0, 0xe0, ZC3XX_R006_FRAMEHEIGHTLOW}, /* 00,06,e0,cc, */ + {0xa0, 0x98, ZC3XX_R08B_I2CDEVICEADDR}, /* 00,8b,98,cc, */ + {0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING}, /* 00,01,01,cc, */ + {0xa0, 0x03, ZC3XX_R012_VIDEOCONTROLFUNC}, /* 00,12,03,cc, */ + {0xa0, 0x01, ZC3XX_R012_VIDEOCONTROLFUNC}, /* 00,12,01,cc, */ + {0xa0, 0x00, ZC3XX_R098_WINYSTARTLOW}, /* 00,98,00,cc, */ + {0xa0, 0x00, ZC3XX_R09A_WINXSTARTLOW}, /* 00,9a,00,cc, */ + {0xa0, 0x00, ZC3XX_R11A_FIRSTYLOW}, /* 01,1a,00,cc, */ + {0xa0, 0x00, ZC3XX_R11C_FIRSTXLOW}, /* 01,1c,00,cc, */ + {0xa0, 0xe8, ZC3XX_R09C_WINHEIGHTLOW}, /* 00,9c,e6,cc, + * 6<->8 */ + {0xa0, 0x88, ZC3XX_R09E_WINWIDTHLOW}, /* 00,9e,86,cc, + * 6<->8 */ + {0xa0, 0x10, ZC3XX_R087_EXPTIMEMID}, /* 00,87,10,cc, */ + {0xa0, 0x98, ZC3XX_R08B_I2CDEVICEADDR}, /* 00,8b,98,cc, */ + {0xaa, 0x1b, 0x0024}, /* 00,1b,24,aa, */ + {0xdd, 0x00, 0x0080}, /* 00,00,80,dd, */ + {0xaa, 0x1b, 0x0000}, /* 00,1b,00,aa, */ + {0xaa, 0x13, 0x0002}, /* 00,13,02,aa, */ + {0xaa, 0x15, 0x0004}, /* 00,15,04,aa */ + {0xaa, 0x01, 0x0000}, + {0xaa, 0x01, 0x0000}, + {0xaa, 0x1a, 0x0000}, /* 00,1a,00,aa, */ + {0xaa, 0x1c, 0x0017}, /* 00,1c,17,aa, */ + {0xa0, 0x82, ZC3XX_R086_EXPTIMEHIGH}, /* 00,86,82,cc, */ + {0xa0, 0x83, ZC3XX_R087_EXPTIMEMID}, /* 00,87,83,cc, */ + {0xa0, 0x84, ZC3XX_R088_EXPTIMELOW}, /* 00,88,84,cc, */ + {0xaa, 0x05, 0x0010}, /* 00,05,10,aa, */ + {0xaa, 0x0a, 0x0000}, /* 00,0a,00,aa, */ + {0xaa, 0x0b, 0x00a0}, /* 00,0b,a0,aa, */ + {0xaa, 0x0c, 0x0000}, /* 00,0c,00,aa, */ + {0xaa, 0x0d, 0x00a0}, /* 00,0d,a0,aa, */ + {0xaa, 0x0e, 0x0000}, /* 00,0e,00,aa, */ + {0xaa, 0x0f, 0x00a0}, /* 00,0f,a0,aa, */ + {0xaa, 0x10, 0x0000}, /* 00,10,00,aa, */ + {0xaa, 0x11, 0x00a0}, /* 00,11,a0,aa, */ + {0xa0, 0x00, 0x0039}, + {0xa1, 0x01, 0x0037}, + {0xaa, 0x16, 0x0001}, /* 00,16,01,aa, */ + {0xaa, 0x17, 0x00e8}, /* 00,17,e6,aa, (e6 -> e8) */ + {0xaa, 0x18, 0x0002}, /* 00,18,02,aa, */ + {0xaa, 0x19, 0x0088}, /* 00,19,86,aa, */ + {0xaa, 0x20, 0x0020}, /* 00,20,20,aa, */ + {0xa0, 0xb7, ZC3XX_R101_SENSORCORRECTION}, /* 01,01,b7,cc, */ + {0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC}, /* 00,12,05,cc, */ + {0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE}, /* 01,00,0d,cc, */ + {0xa0, 0x76, ZC3XX_R189_AWBSTATUS}, /* 01,89,76,cc, */ + {0xa0, 0x09, 0x01ad}, /* 01,ad,09,cc, */ + {0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE}, /* 01,c5,03,cc, */ + {0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05}, /* 01,cb,13,cc, */ + {0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE}, /* 02,50,08,cc, */ + {0xa0, 0x08, ZC3XX_R301_EEPROMACCESS}, /* 03,01,08,cc, */ + {0xa0, 0x60, ZC3XX_R1A8_DIGITALGAIN}, /* 01,a8,60,cc, */ + {0xa0, 0x61, ZC3XX_R116_RGAIN}, /* 01,16,61,cc, */ + {0xa0, 0x65, ZC3XX_R118_BGAIN}, /* 01,18,65,cc */ + {} +}; + +static const struct usb_action tas5130c_vf0250_InitialScale[] = { + {0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL}, /* 00,00,01,cc, */ + {0xa0, 0x02, ZC3XX_R008_CLOCKSETTING}, /* 00,08,02,cc, */ + {0xa0, 0x01, ZC3XX_R010_CMOSSENSORSELECT}, /* 00,10,01,cc, */ + {0xa0, 0x00, ZC3XX_R002_CLOCKSELECT}, /* 00,02,10,cc, */ + {0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH}, /* 00,03,02,cc, */ + {0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW}, /* 00,04,80,cc, */ + {0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH}, /* 00,05,01,cc, */ + {0xa0, 0xe0, ZC3XX_R006_FRAMEHEIGHTLOW}, /* 00,06,e0,cc, */ + {0xa0, 0x98, ZC3XX_R08B_I2CDEVICEADDR}, /* 00,8b,98,cc, */ + {0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING}, /* 00,01,01,cc, */ + {0xa0, 0x03, ZC3XX_R012_VIDEOCONTROLFUNC}, /* 00,12,03,cc, */ + {0xa0, 0x01, ZC3XX_R012_VIDEOCONTROLFUNC}, /* 00,12,01,cc, */ + {0xa0, 0x00, ZC3XX_R098_WINYSTARTLOW}, /* 00,98,00,cc, */ + {0xa0, 0x00, ZC3XX_R09A_WINXSTARTLOW}, /* 00,9a,00,cc, */ + {0xa0, 0x00, ZC3XX_R11A_FIRSTYLOW}, /* 01,1a,00,cc, */ + {0xa0, 0x00, ZC3XX_R11C_FIRSTXLOW}, /* 01,1c,00,cc, */ + {0xa0, 0xe8, ZC3XX_R09C_WINHEIGHTLOW}, /* 00,9c,e8,cc, + * 8<->6 */ + {0xa0, 0x88, ZC3XX_R09E_WINWIDTHLOW}, /* 00,9e,88,cc, + * 8<->6 */ + {0xa0, 0x10, ZC3XX_R087_EXPTIMEMID}, /* 00,87,10,cc, */ + {0xa0, 0x98, ZC3XX_R08B_I2CDEVICEADDR}, /* 00,8b,98,cc, */ + {0xaa, 0x1b, 0x0024}, /* 00,1b,24,aa, */ + {0xdd, 0x00, 0x0080}, /* 00,00,80,dd, */ + {0xaa, 0x1b, 0x0000}, /* 00,1b,00,aa, */ + {0xaa, 0x13, 0x0002}, /* 00,13,02,aa, */ + {0xaa, 0x15, 0x0004}, /* 00,15,04,aa */ + {0xaa, 0x01, 0x0000}, + {0xaa, 0x01, 0x0000}, + {0xaa, 0x1a, 0x0000}, /* 00,1a,00,aa, */ + {0xaa, 0x1c, 0x0017}, /* 00,1c,17,aa, */ + {0xa0, 0x82, ZC3XX_R086_EXPTIMEHIGH}, /* 00,86,82,cc, */ + {0xa0, 0x83, ZC3XX_R087_EXPTIMEMID}, /* 00,87,83,cc, */ + {0xa0, 0x84, ZC3XX_R088_EXPTIMELOW}, /* 00,88,84,cc, */ + {0xaa, 0x05, 0x0010}, /* 00,05,10,aa, */ + {0xaa, 0x0a, 0x0000}, /* 00,0a,00,aa, */ + {0xaa, 0x0b, 0x00a0}, /* 00,0b,a0,aa, */ + {0xaa, 0x0c, 0x0000}, /* 00,0c,00,aa, */ + {0xaa, 0x0d, 0x00a0}, /* 00,0d,a0,aa, */ + {0xaa, 0x0e, 0x0000}, /* 00,0e,00,aa, */ + {0xaa, 0x0f, 0x00a0}, /* 00,0f,a0,aa, */ + {0xaa, 0x10, 0x0000}, /* 00,10,00,aa, */ + {0xaa, 0x11, 0x00a0}, /* 00,11,a0,aa, */ + {0xa0, 0x00, 0x0039}, + {0xa1, 0x01, 0x0037}, + {0xaa, 0x16, 0x0001}, /* 00,16,01,aa, */ + {0xaa, 0x17, 0x00e8}, /* 00,17,e6,aa (e6 -> e8) */ + {0xaa, 0x18, 0x0002}, /* 00,18,02,aa, */ + {0xaa, 0x19, 0x0088}, /* 00,19,88,aa, */ + {0xaa, 0x20, 0x0020}, /* 00,20,20,aa, */ + {0xa0, 0xb7, ZC3XX_R101_SENSORCORRECTION}, /* 01,01,b7,cc, */ + {0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC}, /* 00,12,05,cc, */ + {0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE}, /* 01,00,0d,cc, */ + {0xa0, 0x76, ZC3XX_R189_AWBSTATUS}, /* 01,89,76,cc, */ + {0xa0, 0x09, 0x01ad}, /* 01,ad,09,cc, */ + {0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE}, /* 01,c5,03,cc, */ + {0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05}, /* 01,cb,13,cc, */ + {0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE}, /* 02,50,08,cc, */ + {0xa0, 0x08, ZC3XX_R301_EEPROMACCESS}, /* 03,01,08,cc, */ + {0xa0, 0x60, ZC3XX_R1A8_DIGITALGAIN}, /* 01,a8,60,cc, */ + {0xa0, 0x61, ZC3XX_R116_RGAIN}, /* 01,16,61,cc, */ + {0xa0, 0x65, ZC3XX_R118_BGAIN}, /* 01,18,65,cc */ + {} +}; +/* "50HZ" light frequency banding filter */ +static const struct usb_action tas5130c_vf0250_50HZ[] = { + {0xaa, 0x82, 0x0000}, /* 00,82,00,aa */ + {0xaa, 0x83, 0x0001}, /* 00,83,01,aa */ + {0xaa, 0x84, 0x00aa}, /* 00,84,aa,aa */ + {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc, */ + {0xa0, 0x06, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,0d,cc, */ + {0xa0, 0xa8, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,50,cc, */ + {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc, */ + {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc, */ + {0xa0, 0x8e, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,47,cc, */ + {0xa0, 0x0e, ZC3XX_R18C_AEFREEZE}, /* 01,8c,0e,cc, */ + {0xa0, 0x15, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,15,cc, */ + {0xa0, 0x10, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,10,cc, */ + {0xa0, 0x24, ZC3XX_R1AA_DIGITALGAINSTEP}, /* 01,aa,24,cc, */ + {0xa0, 0x62, ZC3XX_R01D_HSYNC_0}, /* 00,1d,62,cc, */ + {0xa0, 0x90, ZC3XX_R01E_HSYNC_1}, /* 00,1e,90,cc, */ + {0xa0, 0xc8, ZC3XX_R01F_HSYNC_2}, /* 00,1f,c8,cc, */ + {0xa0, 0xff, ZC3XX_R020_HSYNC_3}, /* 00,20,ff,cc, */ + {0xa0, 0x58, ZC3XX_R11D_GLOBALGAIN}, /* 01,1d,58,cc, */ + {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE}, /* 01,80,42,cc, */ + {0xa0, 0x78, ZC3XX_R18D_YTARGET}, /* 01,8d,78,cc */ + {} +}; + +/* "50HZScale" light frequency banding filter */ +static const struct usb_action tas5130c_vf0250_50HZScale[] = { + {0xaa, 0x82, 0x0000}, /* 00,82,00,aa */ + {0xaa, 0x83, 0x0003}, /* 00,83,03,aa */ + {0xaa, 0x84, 0x0054}, /* 00,84,54,aa */ + {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc, */ + {0xa0, 0x0d, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,0d,cc, */ + {0xa0, 0x50, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,50,cc, */ + {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc, */ + {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc, */ + {0xa0, 0x8e, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,8e,cc, */ + {0xa0, 0x0e, ZC3XX_R18C_AEFREEZE}, /* 01,8c,0e,cc, */ + {0xa0, 0x15, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,15,cc, */ + {0xa0, 0x10, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,10,cc, */ + {0xa0, 0x24, ZC3XX_R1AA_DIGITALGAINSTEP}, /* 01,aa,24,cc, */ + {0xa0, 0x62, ZC3XX_R01D_HSYNC_0}, /* 00,1d,62,cc, */ + {0xa0, 0x90, ZC3XX_R01E_HSYNC_1}, /* 00,1e,90,cc, */ + {0xa0, 0xc8, ZC3XX_R01F_HSYNC_2}, /* 00,1f,c8,cc, */ + {0xa0, 0xff, ZC3XX_R020_HSYNC_3}, /* 00,20,ff,cc, */ + {0xa0, 0x58, ZC3XX_R11D_GLOBALGAIN}, /* 01,1d,58,cc, */ + {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE}, /* 01,80,42,cc, */ + {0xa0, 0x78, ZC3XX_R18D_YTARGET}, /* 01,8d,78,cc */ + {} +}; + +/* "60HZ" light frequency banding filter */ +static const struct usb_action tas5130c_vf0250_60HZ[] = { + {0xaa, 0x82, 0x0000}, /* 00,82,00,aa */ + {0xaa, 0x83, 0x0001}, /* 00,83,01,aa */ + {0xaa, 0x84, 0x0062}, /* 00,84,62,aa */ + {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc, */ + {0xa0, 0x05, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,05,cc, */ + {0xa0, 0x88, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,88,cc, */ + {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc, */ + {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc, */ + {0xa0, 0x3b, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,3b,cc, */ + {0xa0, 0x0e, ZC3XX_R18C_AEFREEZE}, /* 01,8c,0e,cc, */ + {0xa0, 0x15, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,15,cc, */ + {0xa0, 0x10, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,10,cc, */ + {0xa0, 0x24, ZC3XX_R1AA_DIGITALGAINSTEP}, /* 01,aa,24,cc, */ + {0xa0, 0x62, ZC3XX_R01D_HSYNC_0}, /* 00,1d,62,cc, */ + {0xa0, 0x90, ZC3XX_R01E_HSYNC_1}, /* 00,1e,90,cc, */ + {0xa0, 0xc8, ZC3XX_R01F_HSYNC_2}, /* 00,1f,c8,cc, */ + {0xa0, 0xff, ZC3XX_R020_HSYNC_3}, /* 00,20,ff,cc, */ + {0xa0, 0x58, ZC3XX_R11D_GLOBALGAIN}, /* 01,1d,58,cc, */ + {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE}, /* 01,80,42,cc, */ + {0xa0, 0x78, ZC3XX_R18D_YTARGET}, /* 01,8d,78,cc */ + {} +}; + +/* "60HZScale" light frequency banding ilter */ +static const struct usb_action tas5130c_vf0250_60HZScale[] = { + {0xaa, 0x82, 0x0000}, /* 00,82,00,aa */ + {0xaa, 0x83, 0x0002}, /* 00,83,02,aa */ + {0xaa, 0x84, 0x00c4}, /* 00,84,c4,aa */ + {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc, */ + {0xa0, 0x0b, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,1,0b,cc, */ + {0xa0, 0x10, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,2,10,cc, */ + {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,5,00,cc, */ + {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,6,00,cc, */ + {0xa0, 0x76, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,7,76,cc, */ + {0xa0, 0x0e, ZC3XX_R18C_AEFREEZE}, /* 01,c,0e,cc, */ + {0xa0, 0x15, ZC3XX_R18F_AEUNFREEZE}, /* 01,f,15,cc, */ + {0xa0, 0x10, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,9,10,cc, */ + {0xa0, 0x24, ZC3XX_R1AA_DIGITALGAINSTEP}, /* 01,a,24,cc, */ + {0xa0, 0x62, ZC3XX_R01D_HSYNC_0}, /* 00,d,62,cc, */ + {0xa0, 0x90, ZC3XX_R01E_HSYNC_1}, /* 00,e,90,cc, */ + {0xa0, 0xc8, ZC3XX_R01F_HSYNC_2}, /* 00,f,c8,cc, */ + {0xa0, 0xff, ZC3XX_R020_HSYNC_3}, /* 00,0,ff,cc, */ + {0xa0, 0x58, ZC3XX_R11D_GLOBALGAIN}, /* 01,d,58,cc, */ + {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE}, /* 01,80,42,cc, */ + {0xa0, 0x78, ZC3XX_R18D_YTARGET}, /* 01,d,78,cc */ + {} +}; + +/* "NoFliker" light frequency banding flter */ +static const struct usb_action tas5130c_vf0250_NoFliker[] = { + {0xa0, 0x0c, ZC3XX_R100_OPERATIONMODE}, /* 01,00,0c,cc, */ + {0xaa, 0x82, 0x0000}, /* 00,82,00,aa */ + {0xaa, 0x83, 0x0000}, /* 00,83,00,aa */ + {0xaa, 0x84, 0x0020}, /* 00,84,20,aa */ + {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,0,00,cc, */ + {0xa0, 0x05, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,05,cc, */ + {0xa0, 0x88, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,88,cc, */ + {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc, */ + {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc, */ + {0xa0, 0x10, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,10,cc, */ + {0xa0, 0x0e, ZC3XX_R18C_AEFREEZE}, /* 01,8c,0e,cc, */ + {0xa0, 0x15, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,15,cc, */ + {0xa0, 0x62, ZC3XX_R01D_HSYNC_0}, /* 00,1d,62,cc, */ + {0xa0, 0x90, ZC3XX_R01E_HSYNC_1}, /* 00,1e,90,cc, */ + {0xa0, 0xc8, ZC3XX_R01F_HSYNC_2}, /* 00,1f,c8,cc, */ + {0xa0, 0xff, ZC3XX_R020_HSYNC_3}, /* 00,20,ff,cc, */ + {0xa0, 0x58, ZC3XX_R11D_GLOBALGAIN}, /* 01,1d,58,cc, */ + {0xa0, 0x03, ZC3XX_R180_AUTOCORRECTENABLE}, /* 01,80,03,cc */ + {} +}; + +/* "NoFlikerScale" light frequency banding filter */ +static const struct usb_action tas5130c_vf0250_NoFlikerScale[] = { + {0xa0, 0x0c, ZC3XX_R100_OPERATIONMODE}, /* 01,00,0c,cc, */ + {0xaa, 0x82, 0x0000}, /* 00,82,00,aa */ + {0xaa, 0x83, 0x0000}, /* 00,83,00,aa */ + {0xaa, 0x84, 0x0020}, /* 00,84,20,aa */ + {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc, */ + {0xa0, 0x0b, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,0b,cc, */ + {0xa0, 0x10, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,10,cc, */ + {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc, */ + {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc, */ + {0xa0, 0x10, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,10,cc, */ + {0xa0, 0x0e, ZC3XX_R18C_AEFREEZE}, /* 01,8c,0e,cc, */ + {0xa0, 0x15, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,15,cc, */ + {0xa0, 0x62, ZC3XX_R01D_HSYNC_0}, /* 00,1d,62,cc, */ + {0xa0, 0x90, ZC3XX_R01E_HSYNC_1}, /* 00,1e,90,cc, */ + {0xa0, 0xc8, ZC3XX_R01F_HSYNC_2}, /* 00,1f,c8,cc, */ + {0xa0, 0xff, ZC3XX_R020_HSYNC_3}, /* 00,20,ff,cc, */ + {0xa0, 0x58, ZC3XX_R11D_GLOBALGAIN}, /* 01,1d,58,cc, */ + {0xa0, 0x03, ZC3XX_R180_AUTOCORRECTENABLE}, /* 01,80,03,cc */ + {} +}; + +static int reg_r_i(struct gspca_dev *gspca_dev, + __u16 index) +{ + usb_control_msg(gspca_dev->dev, + usb_rcvctrlpipe(gspca_dev->dev, 0), + 0xa1, + USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + 0x01, /* value */ + index, gspca_dev->usb_buf, 1, + 500); + return gspca_dev->usb_buf[0]; +} + +static int reg_r(struct gspca_dev *gspca_dev, + __u16 index) +{ + int ret; + + ret = reg_r_i(gspca_dev, index); + PDEBUG(D_USBI, "reg r [%04x] -> %02x", index, ret); + return ret; +} + +static void reg_w_i(struct usb_device *dev, + __u8 value, + __u16 index) +{ + usb_control_msg(dev, + usb_sndctrlpipe(dev, 0), + 0xa0, + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + value, index, NULL, 0, + 500); +} + +static void reg_w(struct usb_device *dev, + __u8 value, + __u16 index) +{ + PDEBUG(D_USBO, "reg w %02x -> [%04x]", value, index); + reg_w_i(dev, value, index); +} + +static __u16 i2c_read(struct gspca_dev *gspca_dev, + __u8 reg) +{ + __u8 retbyte; + __u8 retval[2]; + + reg_w_i(gspca_dev->dev, reg, 0x92); + reg_w_i(gspca_dev->dev, 0x02, 0x90); /* <- read command */ + msleep(25); + retbyte = reg_r_i(gspca_dev, 0x0091); /* read status */ + retval[0] = reg_r_i(gspca_dev, 0x0095); /* read Lowbyte */ + retval[1] = reg_r_i(gspca_dev, 0x0096); /* read Hightbyte */ + PDEBUG(D_USBO, "i2c r [%02x] -> (%02x) %02x%02x", + reg, retbyte, retval[1], retval[0]); + return (retval[1] << 8) | retval[0]; +} + +static __u8 i2c_write(struct gspca_dev *gspca_dev, + __u8 reg, + __u8 valL, + __u8 valH) +{ + __u8 retbyte; + + reg_w_i(gspca_dev->dev, reg, 0x92); + reg_w_i(gspca_dev->dev, valL, 0x93); + reg_w_i(gspca_dev->dev, valH, 0x94); + reg_w_i(gspca_dev->dev, 0x01, 0x90); /* <- write command */ + msleep(5); + retbyte = reg_r_i(gspca_dev, 0x0091); /* read status */ + PDEBUG(D_USBO, "i2c w [%02x] %02x%02x (%02x)", + reg, valH, valL, retbyte); + return retbyte; +} + +static void usb_exchange(struct gspca_dev *gspca_dev, + const struct usb_action *action) +{ + while (action->req) { + switch (action->req) { + case 0xa0: /* write register */ + reg_w(gspca_dev->dev, action->val, action->idx); + break; + case 0xa1: /* read status */ + reg_r(gspca_dev, action->idx); + break; + case 0xaa: + i2c_write(gspca_dev, + action->val, /* reg */ + action->idx & 0xff, /* valL */ + action->idx >> 8); /* valH */ + break; + default: +/* case 0xdd: * delay */ + msleep(action->val / 64 + 10); + break; + } + action++; +/* msleep(1); */ + } +} + +static void setmatrix(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + int i; + const __u8 *matrix; + static const __u8 gc0305_matrix[9] = + {0x50, 0xf8, 0xf8, 0xf8, 0x50, 0xf8, 0xf8, 0xf8, 0x50}; + static const __u8 ov7620_matrix[9] = + {0x58, 0xf4, 0xf4, 0xf4, 0x58, 0xf4, 0xf4, 0xf4, 0x58}; + static const __u8 po2030_matrix[9] = + {0x60, 0xf0, 0xf0, 0xf0, 0x60, 0xf0, 0xf0, 0xf0, 0x60}; + + switch (sd->sensor) { + case SENSOR_GC0305: + matrix = gc0305_matrix; + break; + case SENSOR_MC501CB: + return; /* no matrix? */ + case SENSOR_OV7620: +/* case SENSOR_OV7648: */ + matrix = ov7620_matrix; + break; + case SENSOR_PO2030: + matrix = po2030_matrix; + break; + case SENSOR_TAS5130C_VF0250: /* no matrix? */ + return; + default: /* matrix already loaded */ + return; + } + for (i = 0; i < ARRAY_SIZE(ov7620_matrix); i++) + reg_w(gspca_dev->dev, matrix[i], 0x010a + i); +} + +static void setbrightness(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + __u8 brightness; + + switch (sd->sensor) { + case SENSOR_GC0305: + case SENSOR_OV7620: + case SENSOR_PO2030: + return; + } +/*fixme: is it really write to 011d and 018d for all other sensors? */ + brightness = sd->brightness; + reg_w(gspca_dev->dev, brightness, 0x011d); + if (brightness < 0x70) + brightness += 0x10; + else + brightness = 0x80; + reg_w(gspca_dev->dev, brightness, 0x018d); +} + +static void setsharpness(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + struct usb_device *dev = gspca_dev->dev; + int sharpness; + static const __u8 sharpness_tb[][2] = { + {0x02, 0x03}, + {0x04, 0x07}, + {0x08, 0x0f}, + {0x10, 0x1e} + }; + + sharpness = sd->sharpness; + reg_w(dev, sharpness_tb[sharpness][0], 0x01c6); + reg_r(gspca_dev, 0x01c8); + reg_r(gspca_dev, 0x01c9); + reg_r(gspca_dev, 0x01ca); + reg_w(dev, sharpness_tb[sharpness][1], 0x01cb); +} + +static void setcontrast(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + struct usb_device *dev = gspca_dev->dev; + const __u8 *Tgamma, *Tgradient; + int g, i, k; + static const __u8 kgamma_tb[16] = /* delta for contrast */ + {0x15, 0x0d, 0x0a, 0x09, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08}; + static const __u8 kgrad_tb[16] = + {0x1b, 0x06, 0x03, 0x02, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x06, 0x04}; + static const __u8 Tgamma_1[16] = + {0x00, 0x00, 0x03, 0x0d, 0x1b, 0x2e, 0x45, 0x5f, + 0x79, 0x93, 0xab, 0xc1, 0xd4, 0xe5, 0xf3, 0xff}; + static const __u8 Tgradient_1[16] = + {0x00, 0x01, 0x05, 0x0b, 0x10, 0x15, 0x18, 0x1a, + 0x1a, 0x18, 0x16, 0x14, 0x12, 0x0f, 0x0d, 0x06}; + static const __u8 Tgamma_2[16] = + {0x01, 0x0c, 0x1f, 0x3a, 0x53, 0x6d, 0x85, 0x9c, + 0xb0, 0xc2, 0xd1, 0xde, 0xe9, 0xf2, 0xf9, 0xff}; + static const __u8 Tgradient_2[16] = + {0x05, 0x0f, 0x16, 0x1a, 0x19, 0x19, 0x17, 0x15, + 0x12, 0x10, 0x0e, 0x0b, 0x09, 0x08, 0x06, 0x03}; + static const __u8 Tgamma_3[16] = + {0x04, 0x16, 0x30, 0x4e, 0x68, 0x81, 0x98, 0xac, + 0xbe, 0xcd, 0xda, 0xe4, 0xed, 0xf5, 0xfb, 0xff}; + static const __u8 Tgradient_3[16] = + {0x0c, 0x16, 0x1b, 0x1c, 0x19, 0x18, 0x15, 0x12, + 0x10, 0x0d, 0x0b, 0x09, 0x08, 0x06, 0x05, 0x03}; + static const __u8 Tgamma_4[16] = + {0x13, 0x38, 0x59, 0x79, 0x92, 0xa7, 0xb9, 0xc8, + 0xd4, 0xdf, 0xe7, 0xee, 0xf4, 0xf9, 0xfc, 0xff}; + static const __u8 Tgradient_4[16] = + {0x26, 0x22, 0x20, 0x1c, 0x16, 0x13, 0x10, 0x0d, + 0x0b, 0x09, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02}; + static const __u8 Tgamma_5[16] = + {0x20, 0x4b, 0x6e, 0x8d, 0xa3, 0xb5, 0xc5, 0xd2, + 0xdc, 0xe5, 0xec, 0xf2, 0xf6, 0xfa, 0xfd, 0xff}; + static const __u8 Tgradient_5[16] = + {0x37, 0x26, 0x20, 0x1a, 0x14, 0x10, 0x0e, 0x0b, + 0x09, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x02}; + static const __u8 Tgamma_6[16] = /* ?? was gamma 5 */ + {0x24, 0x44, 0x64, 0x84, 0x9d, 0xb2, 0xc4, 0xd3, + 0xe0, 0xeb, 0xf4, 0xff, 0xff, 0xff, 0xff, 0xff}; + static const __u8 Tgradient_6[16] = + {0x18, 0x20, 0x20, 0x1c, 0x16, 0x13, 0x10, 0x0e, + 0x0b, 0x09, 0x07, 0x00, 0x00, 0x00, 0x00, 0x01}; + static const __u8 *gamma_tb[] = { + NULL, Tgamma_1, Tgamma_2, + Tgamma_3, Tgamma_4, Tgamma_5, Tgamma_6 + }; + static const __u8 *gradient_tb[] = { + NULL, Tgradient_1, Tgradient_2, + Tgradient_3, Tgradient_4, Tgradient_5, Tgradient_6 + }; +#ifdef CONFIG_VIDEO_ADV_DEBUG + __u8 v[16]; +#endif + + Tgamma = gamma_tb[sd->gamma]; + Tgradient = gradient_tb[sd->gamma]; + + k = (sd->contrast - 128) /* -128 / 128 */ + * Tgamma[0]; + PDEBUG(D_CONF, "gamma:%d contrast:%d gamma coeff: %d/128", + sd->gamma, sd->contrast, k); + for (i = 0; i < 16; i++) { + g = Tgamma[i] + kgamma_tb[i] * k / 128; + if (g > 0xff) + g = 0xff; + else if (g <= 0) + g = 1; + reg_w(dev, g, 0x0120 + i); /* gamma */ +#ifdef CONFIG_VIDEO_ADV_DEBUG + if (gspca_debug & D_CONF) + v[i] = g; +#endif + } + PDEBUG(D_CONF, "tb: %02x %02x %02x %02x %02x %02x %02x %02x", + v[0], v[1], v[2], v[3], v[4], v[5], v[6], v[7]); + PDEBUG(D_CONF, " %02x %02x %02x %02x %02x %02x %02x %02x", + v[8], v[9], v[10], v[11], v[12], v[13], v[14], v[15]); + for (i = 0; i < 16; i++) { + g = Tgradient[i] - kgrad_tb[i] * k / 128; + if (g > 0xff) + g = 0xff; + else if (g <= 0) { + if (i != 15) + g = 0; + else + g = 1; + } + reg_w(dev, g, 0x0130 + i); /* gradient */ +#ifdef CONFIG_VIDEO_ADV_DEBUG + if (gspca_debug & D_CONF) + v[i] = g; +#endif + } + PDEBUG(D_CONF, " %02x %02x %02x %02x %02x %02x %02x %02x", + v[0], v[1], v[2], v[3], v[4], v[5], v[6], v[7]); + PDEBUG(D_CONF, " %02x %02x %02x %02x %02x %02x %02x %02x", + v[8], v[9], v[10], v[11], v[12], v[13], v[14], v[15]); +} + +static void setquality(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + struct usb_device *dev = gspca_dev->dev; + __u8 quality; + __u8 frxt; + + switch (sd->sensor) { + case SENSOR_GC0305: + case SENSOR_OV7620: + case SENSOR_PO2030: + return; + } +/*fixme: is it really 0008 0007 0018 for all other sensors? */ + quality = sd->qindex; + reg_w(dev, quality, 0x0008); + frxt = 0x30; + reg_w(dev, frxt, 0x0007); + switch (quality) { + case 0: + case 1: + case 2: + frxt = 0xff; + break; + case 3: + frxt = 0xf0; + break; + case 4: + frxt = 0xe0; + break; + case 5: + frxt = 0x20; + break; + } + reg_w(dev, frxt, 0x0018); +} + +/* Matches the sensor's internal frame rate to the lighting frequency. + * Valid frequencies are: + * 50Hz, for European and Asian lighting (default) + * 60Hz, for American lighting + * 0 = No Fliker (for outdoore usage) + * Returns: 0 for success + */ +static int setlightfreq(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + int i, mode; + const struct usb_action *zc3_freq; + static const struct usb_action *freq_tb[SENSOR_MAX][6] = { +/* SENSOR_CS2102 0 */ + {cs2102_NoFliker, cs2102_NoFlikerScale, + cs2102_50HZ, cs2102_50HZScale, + cs2102_60HZ, cs2102_60HZScale}, +/* SENSOR_CS2102K 1 */ + {cs2102_NoFliker, cs2102_NoFlikerScale, + cs2102_50HZ, cs2102_50HZScale, + cs2102_60HZ, cs2102_60HZScale}, +/* SENSOR_GC0305 2 */ + {gc0305_NoFliker, gc0305_NoFliker, + gc0305_50HZ, gc0305_50HZ, + gc0305_60HZ, gc0305_60HZ}, +/* SENSOR_HDCS2020 3 */ + {NULL, NULL, + NULL, NULL, + NULL, NULL}, +/* SENSOR_HDCS2020b 4 */ + {hdcs2020b_NoFliker, hdcs2020b_NoFliker, + hdcs2020b_50HZ, hdcs2020b_50HZ, + hdcs2020b_60HZ, hdcs2020b_60HZ}, +/* SENSOR_HV7131B 5 */ + {NULL, NULL, + NULL, NULL, + NULL, NULL}, +/* SENSOR_HV7131C 6 */ + {NULL, NULL, + NULL, NULL, + NULL, NULL}, +/* SENSOR_ICM105A 7 */ + {icm105a_NoFliker, icm105a_NoFlikerScale, + icm105a_50HZ, icm105a_50HZScale, + icm105a_60HZ, icm105a_60HZScale}, +/* SENSOR_MC501CB 8 */ + {MC501CB_NoFliker, MC501CB_NoFlikerScale, + MC501CB_50HZ, MC501CB_50HZScale, + MC501CB_60HZ, MC501CB_60HZScale}, +/* SENSOR_OV7620 9 */ + {OV7620_NoFliker, OV7620_NoFliker, + OV7620_50HZ, OV7620_50HZ, + OV7620_60HZ, OV7620_60HZ}, +/* SENSOR_OV7630C 10 */ + {NULL, NULL, + NULL, NULL, + NULL, NULL}, +/* SENSOR_PAS106 11 */ + {pas106b_NoFliker, pas106b_NoFliker, + pas106b_50HZ, pas106b_50HZ, + pas106b_60HZ, pas106b_60HZ}, +/* SENSOR_PB0330 12 */ + {pb0330_NoFliker, pb0330_NoFlikerScale, + pb0330_50HZ, pb0330_50HZScale, + pb0330_60HZ, pb0330_60HZScale}, +/* SENSOR_PO2030 13 */ + {PO2030_NoFliker, PO2030_NoFliker, + PO2030_50HZ, PO2030_50HZ, + PO2030_60HZ, PO2030_60HZ}, +/* SENSOR_TAS5130CK 14 */ + {tas5130cxx_NoFliker, tas5130cxx_NoFlikerScale, + tas5130cxx_50HZ, tas5130cxx_50HZScale, + tas5130cxx_60HZ, tas5130cxx_60HZScale}, +/* SENSOR_TAS5130CXX 15 */ + {tas5130cxx_NoFliker, tas5130cxx_NoFlikerScale, + tas5130cxx_50HZ, tas5130cxx_50HZScale, + tas5130cxx_60HZ, tas5130cxx_60HZScale}, +/* SENSOR_TAS5130C_VF0250 16 */ + {tas5130c_vf0250_NoFliker, tas5130c_vf0250_NoFlikerScale, + tas5130c_vf0250_50HZ, tas5130c_vf0250_50HZScale, + tas5130c_vf0250_60HZ, tas5130c_vf0250_60HZScale}, + }; + + i = sd->lightfreq * 2; + mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv; + if (!mode) + i++; /* 640x480 */ + zc3_freq = freq_tb[(int) sd->sensor][i]; + if (zc3_freq != NULL) { + usb_exchange(gspca_dev, zc3_freq); + switch (sd->sensor) { + case SENSOR_GC0305: + if (mode /* if 320x240 */ + && sd->lightfreq == 1) /* and 50Hz */ + reg_w(gspca_dev->dev, 0x85, 0x018d); + /* win: 0x80, 0x018d */ + break; + case SENSOR_OV7620: + if (!mode) { /* if 640x480 */ + if (sd->lightfreq != 0) /* and 50 or 60 Hz */ + reg_w(gspca_dev->dev, 0x40, 0x0002); + else + reg_w(gspca_dev->dev, 0x44, 0x0002); + } + break; + } + } + return 0; +} + +static void setautogain(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + __u8 autoval; + + if (sd->autogain) + autoval = 0x42; + else + autoval = 0x02; + reg_w(gspca_dev->dev, autoval, 0x0180); +} + +static void send_unknown(struct usb_device *dev, int sensor) +{ + reg_w(dev, 0x01, 0x0000); /* led off */ + switch (sensor) { + case SENSOR_PAS106: + reg_w(dev, 0x03, 0x003a); + reg_w(dev, 0x0c, 0x003b); + reg_w(dev, 0x08, 0x0038); + break; + case SENSOR_GC0305: + case SENSOR_OV7620: + case SENSOR_PB0330: + case SENSOR_PO2030: + reg_w(dev, 0x0d, 0x003a); + reg_w(dev, 0x02, 0x003b); + reg_w(dev, 0x00, 0x0038); + break; + } +} + +/* start probe 2 wires */ +static void start_2wr_probe(struct usb_device *dev, int sensor) +{ + reg_w(dev, 0x01, 0x0000); + reg_w(dev, sensor, 0x0010); + reg_w(dev, 0x01, 0x0001); + reg_w(dev, 0x03, 0x0012); + reg_w(dev, 0x01, 0x0012); +/* msleep(2); */ +} + +static int sif_probe(struct gspca_dev *gspca_dev) +{ + __u16 checkword; + + start_2wr_probe(gspca_dev->dev, 0x0f); /* PAS106 */ + reg_w(gspca_dev->dev, 0x08, 0x008d); + msleep(150); + checkword = ((i2c_read(gspca_dev, 0x00) & 0x0f) << 4) + | ((i2c_read(gspca_dev, 0x01) & 0xf0) >> 4); + PDEBUG(D_PROBE, "probe sif 0x%04x", checkword); + if (checkword == 0x0007) { + send_unknown(gspca_dev->dev, SENSOR_PAS106); + return 0x0f; /* PAS106 */ + } + return -1; +} + +static int vga_2wr_probe(struct gspca_dev *gspca_dev) +{ + struct usb_device *dev = gspca_dev->dev; + __u8 retbyte; + __u16 checkword; + + start_2wr_probe(dev, 0x00); /* HV7131B */ + i2c_write(gspca_dev, 0x01, 0xaa, 0x00); + retbyte = i2c_read(gspca_dev, 0x01); + if (retbyte != 0) + return 0x00; /* HV7131B */ + + start_2wr_probe(dev, 0x04); /* CS2102 */ + i2c_write(gspca_dev, 0x01, 0xaa, 0x00); + retbyte = i2c_read(gspca_dev, 0x01); + if (retbyte != 0) + return 0x04; /* CS2102 */ + + start_2wr_probe(dev, 0x06); /* OmniVision */ + reg_w(dev, 0x08, 0x8d); + i2c_write(gspca_dev, 0x11, 0xaa, 0x00); + retbyte = i2c_read(gspca_dev, 0x11); + if (retbyte != 0) { + /* (should have returned 0xaa) --> Omnivision? */ + /* reg_r 0x10 -> 0x06 --> */ + goto ov_check; + } + + start_2wr_probe(dev, 0x08); /* HDCS2020 */ + i2c_write(gspca_dev, 0x15, 0xaa, 0x00); + retbyte = i2c_read(gspca_dev, 0x15); + if (retbyte != 0) + return 0x08; /* HDCS2020 */ + + start_2wr_probe(dev, 0x0a); /* PB0330 */ + i2c_write(gspca_dev, 0x07, 0xaa, 0xaa); + retbyte = i2c_read(gspca_dev, 0x07); + if (retbyte != 0) + return 0x0a; /* PB0330 */ + retbyte = i2c_read(gspca_dev, 0x03); + if (retbyte != 0) + return 0x0a; /* PB0330 ?? */ + retbyte = i2c_read(gspca_dev, 0x04); + if (retbyte != 0) + return 0x0a; /* PB0330 ?? */ + + start_2wr_probe(dev, 0x0c); /* ICM105A */ + i2c_write(gspca_dev, 0x01, 0x11, 0x00); + retbyte = i2c_read(gspca_dev, 0x01); + if (retbyte != 0) + return 0x0c; /* ICM105A */ + + start_2wr_probe(dev, 0x0e); /* PAS202BCB */ + reg_w(dev, 0x08, 0x8d); + i2c_write(gspca_dev, 0x03, 0xaa, 0x00); + msleep(500); + retbyte = i2c_read(gspca_dev, 0x03); + if (retbyte != 0) + return 0x0e; /* PAS202BCB */ + + start_2wr_probe(dev, 0x02); /* ?? */ + i2c_write(gspca_dev, 0x01, 0xaa, 0x00); + retbyte = i2c_read(gspca_dev, 0x01); + if (retbyte != 0) + return 0x02; /* ?? */ +ov_check: + reg_r(gspca_dev, 0x0010); /* ?? */ + reg_r(gspca_dev, 0x0010); + + reg_w(dev, 0x01, 0x0000); + reg_w(dev, 0x01, 0x0001); + reg_w(dev, 0x06, 0x0010); /* OmniVision */ + reg_w(dev, 0xa1, 0x008b); + reg_w(dev, 0x08, 0x008d); + msleep(500); + reg_w(dev, 0x01, 0x0012); + i2c_write(gspca_dev, 0x12, 0x80, 0x00); /* sensor reset */ + retbyte = i2c_read(gspca_dev, 0x0a); + checkword = retbyte << 8; + retbyte = i2c_read(gspca_dev, 0x0b); + checkword |= retbyte; + PDEBUG(D_PROBE, "probe 2wr ov vga 0x%04x", checkword); + switch (checkword) { + case 0x7631: /* OV7630C */ + reg_w(dev, 0x06, 0x0010); + break; + case 0x7620: /* OV7620 */ + case 0x7648: /* OV7648 */ + break; + default: + return -1; /* not OmniVision */ + } + return checkword; +} + +struct sensor_by_chipset_revision { + __u16 revision; + __u8 internal_sensor_id; +}; +static const struct sensor_by_chipset_revision chipset_revision_sensor[] = { + {0xc001, 0x13}, /* MI0360 */ + {0xe001, 0x13}, + {0x8001, 0x13}, + {0x8000, 0x14}, /* CS2102K */ + {0x8400, 0x15}, /* TAS5130K */ + {0, 0} +}; + +static int vga_3wr_probe(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + struct usb_device *dev = gspca_dev->dev; + int i; + __u8 retbyte; + __u16 checkword; + +/*fixme: lack of 8b=b3 (11,12)-> 10, 8b=e0 (14,15,16)-> 12 found in gspcav1*/ + reg_w(dev, 0x02, 0x0010); + reg_r(gspca_dev, 0x10); + reg_w(dev, 0x01, 0x0000); + reg_w(dev, 0x00, 0x0010); + reg_w(dev, 0x01, 0x0001); + reg_w(dev, 0x91, 0x008b); + reg_w(dev, 0x03, 0x0012); + reg_w(dev, 0x01, 0x0012); + reg_w(dev, 0x05, 0x0012); + retbyte = i2c_read(gspca_dev, 0x14); + if (retbyte != 0) + return 0x11; /* HV7131R */ + retbyte = i2c_read(gspca_dev, 0x15); + if (retbyte != 0) + return 0x11; /* HV7131R */ + retbyte = i2c_read(gspca_dev, 0x16); + if (retbyte != 0) + return 0x11; /* HV7131R */ + + reg_w(dev, 0x02, 0x0010); + retbyte = reg_r(gspca_dev, 0x000b); + checkword = retbyte << 8; + retbyte = reg_r(gspca_dev, 0x000a); + checkword |= retbyte; + PDEBUG(D_PROBE, "probe 3wr vga 1 0x%04x", checkword); + reg_r(gspca_dev, 0x0010); + /* this is tested only once anyway */ + i = 0; + while (chipset_revision_sensor[i].revision) { + if (chipset_revision_sensor[i].revision == checkword) { + sd->chip_revision = checkword; + send_unknown(dev, SENSOR_PB0330); + return chipset_revision_sensor[i].internal_sensor_id; + } + i++; + } + + reg_w(dev, 0x01, 0x0000); + reg_w(dev, 0x01, 0x0001); + reg_w(dev, 0xdd, 0x008b); + reg_w(dev, 0x0a, 0x0010); + reg_w(dev, 0x03, 0x0012); + reg_w(dev, 0x01, 0x0012); + retbyte = i2c_read(gspca_dev, 0x00); + if (retbyte != 0) { + PDEBUG(D_PROBE, "probe 3wr vga type 0a ?"); + return 0x0a; /* ?? */ + } + + reg_w(dev, 0x01, 0x0000); + reg_w(dev, 0x01, 0x0001); + reg_w(dev, 0x98, 0x008b); + reg_w(dev, 0x01, 0x0010); + reg_w(dev, 0x03, 0x0012); + msleep(2); + reg_w(dev, 0x01, 0x0012); + retbyte = i2c_read(gspca_dev, 0x00); + if (retbyte != 0) { + PDEBUG(D_PROBE, "probe 3wr vga type %02x", retbyte); + send_unknown(dev, SENSOR_GC0305); + return retbyte; /* 0x29 = gc0305 - should continue? */ + } + + reg_w(dev, 0x01, 0x0000); /* check OmniVision */ + reg_w(dev, 0x01, 0x0001); + reg_w(dev, 0xa1, 0x008b); + reg_w(dev, 0x08, 0x008d); + reg_w(dev, 0x06, 0x0010); + reg_w(dev, 0x01, 0x0012); + reg_w(dev, 0x05, 0x0012); + if (i2c_read(gspca_dev, 0x1c) == 0x7f /* OV7610 - manufacturer ID */ + && i2c_read(gspca_dev, 0x1d) == 0xa2) { + send_unknown(dev, SENSOR_OV7620); + return 0x06; /* OmniVision confirm ? */ + } + + reg_w(dev, 0x01, 0x00); + reg_w(dev, 0x00, 0x02); + reg_w(dev, 0x01, 0x10); + reg_w(dev, 0x01, 0x01); + reg_w(dev, 0xee, 0x8b); + reg_w(dev, 0x03, 0x12); +/* msleep(150); */ + reg_w(dev, 0x01, 0x12); + reg_w(dev, 0x05, 0x12); + retbyte = i2c_read(gspca_dev, 0x00); /* ID 0 */ + checkword = retbyte << 8; + retbyte = i2c_read(gspca_dev, 0x01); /* ID 1 */ + checkword |= retbyte; + PDEBUG(D_PROBE, "probe 3wr vga 2 0x%04x", checkword); + if (checkword == 0x2030) { + retbyte = i2c_read(gspca_dev, 0x02); /* revision number */ + PDEBUG(D_PROBE, "sensor PO2030 rev 0x%02x", retbyte); + send_unknown(dev, SENSOR_PO2030); + return checkword; + } + + reg_w(dev, 0x01, 0x00); + reg_w(dev, 0x0a, 0x10); + reg_w(dev, 0xd3, 0x8b); + reg_w(dev, 0x01, 0x01); + reg_w(dev, 0x03, 0x12); + reg_w(dev, 0x01, 0x12); + reg_w(dev, 0x05, 0x01); + reg_w(dev, 0xd3, 0x8b); + retbyte = i2c_read(gspca_dev, 0x01); + if (retbyte != 0) { + PDEBUG(D_PROBE, "probe 3wr vga type 0a ?"); + return 0x0a; /* ?? */ + } + return -1; +} + +static int zcxx_probeSensor(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + int sensor, sensor2; + + switch (sd->sensor) { + case SENSOR_MC501CB: + case SENSOR_TAS5130C_VF0250: + return -1; /* don't probe */ + } + sensor = vga_2wr_probe(gspca_dev); + if (sensor >= 0) { + if (sensor < 0x7600) + return sensor; + /* next probe is needed for OmniVision ? */ + } + sensor2 = vga_3wr_probe(gspca_dev); + if (sensor2 >= 0) { + if (sensor >= 0) + return sensor; + return sensor2; + } + return sif_probe(gspca_dev); +} + +/* this function is called at probe time */ +static int sd_config(struct gspca_dev *gspca_dev, + const struct usb_device_id *id) +{ + struct sd *sd = (struct sd *) gspca_dev; + struct cam *cam; + int sensor; + int vga = 1; /* 1: vga, 0: sif */ + static const __u8 gamma[SENSOR_MAX] = { + 5, /* SENSOR_CS2102 0 */ + 5, /* SENSOR_CS2102K 1 */ + 4, /* SENSOR_GC0305 2 */ + 4, /* SENSOR_HDCS2020 3 */ + 4, /* SENSOR_HDCS2020b 4 */ + 4, /* SENSOR_HV7131B 5 */ + 4, /* SENSOR_HV7131C 6 */ + 4, /* SENSOR_ICM105A 7 */ + 4, /* SENSOR_MC501CB 8 */ + 3, /* SENSOR_OV7620 9 */ + 4, /* SENSOR_OV7630C 10 */ + 4, /* SENSOR_PAS106 11 */ + 4, /* SENSOR_PB0330 12 */ + 4, /* SENSOR_PO2030 13 */ + 4, /* SENSOR_TAS5130CK 14 */ + 4, /* SENSOR_TAS5130CXX 15 */ + 3, /* SENSOR_TAS5130C_VF0250 16 */ + }; + + /* define some sensors from the vendor/product */ + sd->sharpness = 2; + switch (id->idVendor) { + case 0x041e: /* Creative */ + switch (id->idProduct) { + case 0x4051: /* zc301 chips */ + case 0x4053: + sd->sensor = SENSOR_TAS5130C_VF0250; + break; + } + break; + case 0x046d: /* Logitech Labtec */ + switch (id->idProduct) { + case 0x08dd: + sd->sensor = SENSOR_MC501CB; + break; + } + break; + case 0x0ac8: /* Vimicro z-star */ + switch (id->idProduct) { + case 0x305b: + sd->sensor = SENSOR_TAS5130C_VF0250; + break; + } + break; + } + sensor = zcxx_probeSensor(gspca_dev); + if (sensor >= 0) + PDEBUG(D_PROBE, "probe sensor -> %02x", sensor); + if ((unsigned) force_sensor < SENSOR_MAX) { + sd->sensor = force_sensor; + PDEBUG(D_PROBE, "sensor forced to %d", force_sensor); + } else { + switch (sensor) { + case -1: + switch (sd->sensor) { + case SENSOR_MC501CB: + PDEBUG(D_PROBE, "Sensor MC501CB"); + break; + case SENSOR_TAS5130C_VF0250: + PDEBUG(D_PROBE, "Sensor Tas5130 (VF0250)"); + break; + default: + PDEBUG(D_PROBE, + "Sensor UNKNOW_0 force Tas5130"); + sd->sensor = SENSOR_TAS5130CXX; + } + break; + case 0: + PDEBUG(D_PROBE, "Find Sensor HV7131B"); + sd->sensor = SENSOR_HV7131B; + break; + case 0x04: + PDEBUG(D_PROBE, "Find Sensor CS2102"); + sd->sensor = SENSOR_CS2102; + break; + case 0x08: + PDEBUG(D_PROBE, "Find Sensor HDCS2020(b)"); + sd->sensor = SENSOR_HDCS2020b; + break; + case 0x0a: + PDEBUG(D_PROBE, + "Find Sensor PB0330. Chip revision %x", + sd->chip_revision); + sd->sensor = SENSOR_PB0330; + break; + case 0x0c: + PDEBUG(D_PROBE, "Find Sensor ICM105A"); + sd->sensor = SENSOR_ICM105A; + break; + case 0x0e: + PDEBUG(D_PROBE, "Find Sensor HDCS2020"); + sd->sensor = SENSOR_HDCS2020; + sd->sharpness = 1; + break; + case 0x0f: + PDEBUG(D_PROBE, "Find Sensor PAS106"); + sd->sensor = SENSOR_PAS106; + vga = 0; /* SIF */ + break; + case 0x10: + case 0x12: + PDEBUG(D_PROBE, "Find Sensor TAS5130"); + sd->sensor = SENSOR_TAS5130CXX; + break; + case 0x11: + PDEBUG(D_PROBE, "Find Sensor HV7131R(c)"); + sd->sensor = SENSOR_HV7131C; + break; + case 0x13: + PDEBUG(D_PROBE, + "Find Sensor MI0360. Chip revision %x", + sd->chip_revision); + sd->sensor = SENSOR_PB0330; + break; + case 0x14: + PDEBUG(D_PROBE, + "Find Sensor CS2102K?. Chip revision %x", + sd->chip_revision); + sd->sensor = SENSOR_CS2102K; + break; + case 0x15: + PDEBUG(D_PROBE, + "Find Sensor TAS5130CK?. Chip revision %x", + sd->chip_revision); + sd->sensor = SENSOR_TAS5130CK; + break; + case 0x29: + PDEBUG(D_PROBE, "Find Sensor GC0305"); + sd->sensor = SENSOR_GC0305; + break; + case 0x2030: + PDEBUG(D_PROBE, "Find Sensor PO2030"); + sd->sensor = SENSOR_PO2030; + sd->sharpness = 0; /* from win traces */ + break; + case 0x7620: + PDEBUG(D_PROBE, "Find Sensor OV7620"); + sd->sensor = SENSOR_OV7620; + break; + case 0x7648: + PDEBUG(D_PROBE, "Find Sensor OV7648"); + sd->sensor = SENSOR_OV7620; /* same sensor (?) */ + break; + default: + PDEBUG(D_ERR|D_PROBE, "Unknown sensor %02x", sensor); + return -EINVAL; + } + } + if (sensor < 0x20) { + if (sensor == -1 || sensor == 0x10 || sensor == 0x12) + reg_w(gspca_dev->dev, 0x02, 0x0010); + else + reg_w(gspca_dev->dev, sensor & 0x0f, 0x0010); + reg_r(gspca_dev, 0x0010); + } + + cam = &gspca_dev->cam; + cam->dev_name = (char *) id->driver_info; + cam->epaddr = 0x01; +/*fixme:test*/ + gspca_dev->nbalt--; + if (vga) { + cam->cam_mode = vga_mode; + cam->nmodes = ARRAY_SIZE(vga_mode); + } else { + cam->cam_mode = sif_mode; + cam->nmodes = ARRAY_SIZE(sif_mode); + } + sd->qindex = 1; + sd->brightness = sd_ctrls[SD_BRIGHTNESS].qctrl.default_value; + sd->contrast = sd_ctrls[SD_CONTRAST].qctrl.default_value; + sd->gamma = gamma[(int) sd->sensor]; + sd->autogain = sd_ctrls[SD_AUTOGAIN].qctrl.default_value; + sd->lightfreq = sd_ctrls[SD_FREQ].qctrl.default_value; + sd->sharpness = sd_ctrls[SD_SHARPNESS].qctrl.default_value; + + /* switch the led off */ + reg_w(gspca_dev->dev, 0x01, 0x0000); + return 0; +} + +/* this function is called at open time */ +static int sd_open(struct gspca_dev *gspca_dev) +{ + reg_w(gspca_dev->dev, 0x01, 0x0000); + return 0; +} + +static void sd_start(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + struct usb_device *dev = gspca_dev->dev; + const struct usb_action *zc3_init; + int mode; + static const struct usb_action *init_tb[SENSOR_MAX][2] = { + {cs2102_InitialScale, cs2102_Initial}, /* 0 */ + {cs2102K_InitialScale, cs2102K_Initial}, /* 1 */ + {gc0305_Initial, gc0305_InitialScale}, /* 2 */ + {hdcs2020xx_InitialScale, hdcs2020xx_Initial}, /* 3 */ + {hdcs2020xb_InitialScale, hdcs2020xb_Initial}, /* 4 */ + {hv7131bxx_InitialScale, hv7131bxx_Initial}, /* 5 */ + {hv7131cxx_InitialScale, hv7131cxx_Initial}, /* 6 */ + {icm105axx_InitialScale, icm105axx_Initial}, /* 7 */ + {MC501CB_InitialScale, MC501CB_Initial}, /* 9 */ + {OV7620_mode0, OV7620_mode1}, /* 9 */ + {ov7630c_InitialScale, ov7630c_Initial}, /* 10 */ + {pas106b_InitialScale, pas106b_Initial}, /* 11 */ + {pb0330xx_InitialScale, pb0330xx_Initial}, /* 12 */ +/* or {pb03303x_InitialScale, pb03303x_Initial}, */ + {PO2030_mode0, PO2030_mode1}, /* 13 */ + {tas5130CK_InitialScale, tas5130CK_Initial}, /* 14 */ + {tas5130cxx_InitialScale, tas5130cxx_Initial}, /* 15 */ + {tas5130c_vf0250_InitialScale, tas5130c_vf0250_Initial}, + /* 16 */ + }; + + mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv; + zc3_init = init_tb[(int) sd->sensor][mode]; + switch (sd->sensor) { + case SENSOR_HV7131B: + case SENSOR_HV7131C: + zcxx_probeSensor(gspca_dev); + break; + case SENSOR_PAS106: + usb_exchange(gspca_dev, pas106b_Initial_com); + break; + case SENSOR_PB0330: + if (mode) { + if (sd->chip_revision == 0xc001 + || sd->chip_revision == 0xe001 + || sd->chip_revision == 0x8001) + zc3_init = pb03303x_Initial; + } else { + if (sd->chip_revision == 0xc001 + || sd->chip_revision == 0xe001 + || sd->chip_revision == 0x8001) + zc3_init = pb03303x_InitialScale; + } + break; + } + usb_exchange(gspca_dev, zc3_init); + + switch (sd->sensor) { + case SENSOR_GC0305: + case SENSOR_OV7620: + case SENSOR_PO2030: + msleep(100); /* ?? */ + reg_r(gspca_dev, 0x0002); /* --> 0x40 */ + reg_w(dev, 0x09, 0x01ad); /* (from win traces) */ + reg_w(dev, 0x15, 0x01ae); + reg_w(dev, 0x0d, 0x003a); + reg_w(dev, 0x02, 0x003b); + reg_w(dev, 0x00, 0x0038); + break; + } + + setmatrix(gspca_dev); + setbrightness(gspca_dev); + switch (sd->sensor) { + case SENSOR_OV7620: + reg_r(gspca_dev, 0x0008); + reg_w(dev, 0x00, 0x0008); + break; + case SENSOR_GC0305: + reg_r(gspca_dev, 0x0008); + /* fall thru */ + case SENSOR_PO2030: + reg_w(dev, 0x03, 0x0008); + break; + } + setsharpness(gspca_dev); + + /* set the gamma tables when not set */ + switch (sd->sensor) { + case SENSOR_CS2102: /* gamma set in xxx_Initial */ + case SENSOR_CS2102K: + case SENSOR_HDCS2020: + case SENSOR_HDCS2020b: + case SENSOR_PB0330: /* pb with chip_revision - see above */ + case SENSOR_OV7630C: + case SENSOR_TAS5130CK: + break; + default: + setcontrast(gspca_dev); + break; + } + setmatrix(gspca_dev); /* one more time? */ + switch (sd->sensor) { + case SENSOR_OV7620: + reg_r(gspca_dev, 0x0180); /* from win */ + reg_w(dev, 0x00, 0x0180); + break; + default: + setquality(gspca_dev); + break; + } + setlightfreq(gspca_dev); + + switch (sd->sensor) { + case SENSOR_GC0305: + case SENSOR_OV7620: + reg_w(dev, 0x09, 0x01ad); /* (from win traces) */ + reg_w(dev, 0x15, 0x01ae); + sd->autogain = 0; + break; + case SENSOR_PO2030: + reg_w(dev, 0x40, 0x0117); /* (from win traces) */ + reg_r(gspca_dev, 0x0180); + break; + } + + setautogain(gspca_dev); + switch (sd->sensor) { + case SENSOR_GC0305: +/* setlightfreq(gspca_dev); ?? (end: 80 -> [18d]) */ + reg_w(dev, 0x09, 0x01ad); /* (from win traces) */ + reg_w(dev, 0x15, 0x01ae); + reg_w(dev, 0x40, 0x0180); + reg_w(dev, 0x40, 0x0117); + reg_r(gspca_dev, 0x0180); + sd->autogain = 1; + setautogain(gspca_dev); + break; + case SENSOR_OV7620: + i2c_read(gspca_dev, 0x13); /*fixme: returns 0xa3 */ + i2c_write(gspca_dev, 0x13, 0xa3, 0x00); + /*fixme: returned value to send? */ + reg_w(dev, 0x40, 0x0117); /* (from win traces) */ + reg_r(gspca_dev, 0x0180); + setautogain(gspca_dev); + msleep(500); + break; + case SENSOR_PO2030: + msleep(500); + reg_r(gspca_dev, 0x0008); + reg_r(gspca_dev, 0x0007); + reg_w(dev, 0x00, 0x0007); /* (from win traces) */ + reg_w(dev, 0x02, 0x0008); + break; + } +} + +static void sd_stopN(struct gspca_dev *gspca_dev) +{ +} + +static void sd_stop0(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + + send_unknown(gspca_dev->dev, sd->sensor); +} + +/* this function is called at close time */ +static void sd_close(struct gspca_dev *gspca_dev) +{ +} + +static void sd_pkt_scan(struct gspca_dev *gspca_dev, + struct gspca_frame *frame, + __u8 *data, + int len) +{ + + if (data[0] == 0xff && data[1] == 0xd8) { /* start of frame */ + frame = gspca_frame_add(gspca_dev, LAST_PACKET, frame, + data, 0); + /* put the JPEG header in the new frame */ + jpeg_put_header(gspca_dev, frame, + ((struct sd *) gspca_dev)->qindex, + 0x21); + /* remove the webcam's header: + * ff d8 ff fe 00 0e 00 00 ss ss 00 01 ww ww hh hh pp pp + * - 'ss ss' is the frame sequence number (BE) + * - 'ww ww' and 'hh hh' are the window dimensions (BE) + * - 'pp pp' is the packet sequence number (BE) + */ + data += 18; + len -= 18; + } + gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len); +} + +static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->brightness = val; + if (gspca_dev->streaming) + setbrightness(gspca_dev); + return 0; +} + +static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + *val = sd->brightness; + return 0; +} + +static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->contrast = val; + if (gspca_dev->streaming) + setcontrast(gspca_dev); + return 0; +} + +static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + *val = sd->contrast; + return 0; +} + +static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->autogain = val; + if (gspca_dev->streaming) + setautogain(gspca_dev); + return 0; +} + +static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + *val = sd->autogain; + return 0; +} + +static int sd_setgamma(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->gamma = val; + if (gspca_dev->streaming) + setcontrast(gspca_dev); + return 0; +} + +static int sd_getgamma(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + *val = sd->gamma; + return 0; +} + +static int sd_setfreq(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->lightfreq = val; + if (gspca_dev->streaming) + setlightfreq(gspca_dev); + return 0; +} + +static int sd_getfreq(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + *val = sd->lightfreq; + return 0; +} + +static int sd_setsharpness(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->sharpness = val; + if (gspca_dev->streaming) + setsharpness(gspca_dev); + return 0; +} + +static int sd_getsharpness(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + *val = sd->sharpness; + return 0; +} + +static int sd_querymenu(struct gspca_dev *gspca_dev, + struct v4l2_querymenu *menu) +{ + switch (menu->id) { + case V4L2_CID_POWER_LINE_FREQUENCY: + switch (menu->index) { + case 0: /* V4L2_CID_POWER_LINE_FREQUENCY_DISABLED */ + strcpy((char *) menu->name, "NoFliker"); + return 0; + case 1: /* V4L2_CID_POWER_LINE_FREQUENCY_50HZ */ + strcpy((char *) menu->name, "50 Hz"); + return 0; + case 2: /* V4L2_CID_POWER_LINE_FREQUENCY_60HZ */ + strcpy((char *) menu->name, "60 Hz"); + return 0; + } + break; + } + return -EINVAL; +} + +static const struct sd_desc sd_desc = { + .name = MODULE_NAME, + .ctrls = sd_ctrls, + .nctrls = sizeof sd_ctrls / sizeof sd_ctrls[0], + .config = sd_config, + .open = sd_open, + .start = sd_start, + .stopN = sd_stopN, + .stop0 = sd_stop0, + .close = sd_close, + .pkt_scan = sd_pkt_scan, + .querymenu = sd_querymenu, +}; + +#define DVNM(name) .driver_info = (kernel_ulong_t) name +static const __devinitdata struct usb_device_id device_table[] = { + {USB_DEVICE(0x041e, 0x041e), DVNM("Creative WebCam Live!")}, +#ifndef CONFIG_USB_ZC0301 + {USB_DEVICE(0x041e, 0x4017), DVNM("Creative Webcam Mobile PD1090")}, + {USB_DEVICE(0x041e, 0x401c), DVNM("Creative NX")}, + {USB_DEVICE(0x041e, 0x401e), DVNM("Creative Nx Pro")}, + {USB_DEVICE(0x041e, 0x401f), DVNM("Creative Webcam Notebook PD1171")}, +#endif + {USB_DEVICE(0x041e, 0x4029), DVNM("Creative WebCam Vista Pro")}, +#ifndef CONFIG_USB_ZC0301 + {USB_DEVICE(0x041e, 0x4034), DVNM("Creative Instant P0620")}, + {USB_DEVICE(0x041e, 0x4035), DVNM("Creative Instant P0620D")}, + {USB_DEVICE(0x041e, 0x4036), DVNM("Creative Live !")}, + {USB_DEVICE(0x041e, 0x403a), DVNM("Creative Nx Pro 2")}, +#endif + {USB_DEVICE(0x041e, 0x4051), DVNM("Creative Notebook Pro (VF0250)")}, + {USB_DEVICE(0x041e, 0x4053), DVNM("Creative Live!Cam Video IM")}, +#ifndef CONFIG_USB_ZC0301 + {USB_DEVICE(0x0458, 0x7007), DVNM("Genius VideoCam V2")}, + {USB_DEVICE(0x0458, 0x700c), DVNM("Genius VideoCam V3")}, + {USB_DEVICE(0x0458, 0x700f), DVNM("Genius VideoCam Web V2")}, +#endif + {USB_DEVICE(0x0461, 0x0a00), DVNM("MicroInnovation WebCam320")}, + {USB_DEVICE(0x046d, 0x08a0), DVNM("Logitech QC IM")}, + {USB_DEVICE(0x046d, 0x08a1), DVNM("Logitech QC IM 0x08A1 +sound")}, + {USB_DEVICE(0x046d, 0x08a2), DVNM("Labtec Webcam Pro")}, + {USB_DEVICE(0x046d, 0x08a3), DVNM("Logitech QC Chat")}, + {USB_DEVICE(0x046d, 0x08a6), DVNM("Logitech QCim")}, + {USB_DEVICE(0x046d, 0x08a7), DVNM("Logitech QuickCam Image")}, + {USB_DEVICE(0x046d, 0x08a9), DVNM("Logitech Notebook Deluxe")}, + {USB_DEVICE(0x046d, 0x08aa), DVNM("Labtec Webcam Notebook")}, + {USB_DEVICE(0x046d, 0x08ac), DVNM("Logitech QuickCam Cool")}, + {USB_DEVICE(0x046d, 0x08ad), DVNM("Logitech QCCommunicate STX")}, +#ifndef CONFIG_USB_ZC0301 + {USB_DEVICE(0x046d, 0x08ae), DVNM("Logitech QuickCam for Notebooks")}, +#endif + {USB_DEVICE(0x046d, 0x08af), DVNM("Logitech QuickCam Cool")}, + {USB_DEVICE(0x046d, 0x08b9), DVNM("Logitech QC IM ???")}, + {USB_DEVICE(0x046d, 0x08d7), DVNM("Logitech QCam STX")}, + {USB_DEVICE(0x046d, 0x08d9), DVNM("Logitech QuickCam IM/Connect")}, + {USB_DEVICE(0x046d, 0x08d8), DVNM("Logitech Notebook Deluxe")}, + {USB_DEVICE(0x046d, 0x08da), DVNM("Logitech QuickCam Messenger")}, + {USB_DEVICE(0x046d, 0x08dd), DVNM("Logitech QuickCam for Notebooks")}, + {USB_DEVICE(0x0471, 0x0325), DVNM("Philips SPC 200 NC")}, + {USB_DEVICE(0x0471, 0x0326), DVNM("Philips SPC 300 NC")}, + {USB_DEVICE(0x0471, 0x032d), DVNM("Philips spc210nc")}, + {USB_DEVICE(0x0471, 0x032e), DVNM("Philips spc315nc")}, + {USB_DEVICE(0x055f, 0xc005), DVNM("Mustek Wcam300A")}, +#ifndef CONFIG_USB_ZC0301 + {USB_DEVICE(0x055f, 0xd003), DVNM("Mustek WCam300A")}, + {USB_DEVICE(0x055f, 0xd004), DVNM("Mustek WCam300 AN")}, +#endif + {USB_DEVICE(0x0698, 0x2003), DVNM("CTX M730V built in")}, + {USB_DEVICE(0x0ac8, 0x0302), DVNM("Z-star Vimicro zc0302")}, +#ifndef CONFIG_USB_ZC0301 + {USB_DEVICE(0x0ac8, 0x301b), DVNM("Z-Star zc301b")}, + {USB_DEVICE(0x0ac8, 0x303b), DVNM("Vimicro 0x303b")}, +#endif + {USB_DEVICE(0x0ac8, 0x305b), DVNM("Z-star Vimicro zc0305b")}, +#ifndef CONFIG_USB_ZC0301 + {USB_DEVICE(0x0ac8, 0x307b), DVNM("Z-Star 307b")}, + {USB_DEVICE(0x10fd, 0x0128), DVNM("Typhoon Webshot II 300k 0x0128")}, + {USB_DEVICE(0x10fd, 0x8050), DVNM("Typhoon Webshot II USB 300k")}, +#endif + {} /* end of entry */ +}; +#undef DVNAME +MODULE_DEVICE_TABLE(usb, device_table); + +/* -- device connect -- */ +static int sd_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd), + THIS_MODULE); +} + +/* USB driver */ +static struct usb_driver sd_driver = { + .name = MODULE_NAME, + .id_table = device_table, + .probe = sd_probe, + .disconnect = gspca_disconnect, +}; + +static int __init sd_mod_init(void) +{ + if (usb_register(&sd_driver) < 0) + return -1; + PDEBUG(D_PROBE, "v%s registered", version); + return 0; +} + +static void __exit sd_mod_exit(void) +{ + usb_deregister(&sd_driver); + PDEBUG(D_PROBE, "deregistered"); +} + +module_init(sd_mod_init); +module_exit(sd_mod_exit); + +module_param(force_sensor, int, 0644); +MODULE_PARM_DESC(force_sensor, + "Force sensor. Only for experts!!!"); diff --git a/drivers/media/video/ir-kbd-i2c.c b/drivers/media/video/ir-kbd-i2c.c index 7b65f5e537f8..a30254bed311 100644 --- a/drivers/media/video/ir-kbd-i2c.c +++ b/drivers/media/video/ir-kbd-i2c.c @@ -194,88 +194,6 @@ static int get_key_knc1(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw) return 1; } -/* Common (grey or coloured) pinnacle PCTV remote handling - * - */ -static int get_key_pinnacle(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw, - int parity_offset, int marker, int code_modulo) -{ - unsigned char b[4]; - unsigned int start = 0,parity = 0,code = 0; - - /* poll IR chip */ - if (4 != i2c_master_recv(&ir->c,b,4)) { - dprintk(2,"read error\n"); - return -EIO; - } - - for (start = 0; start < ARRAY_SIZE(b); start++) { - if (b[start] == marker) { - code=b[(start+parity_offset+1)%4]; - parity=b[(start+parity_offset)%4]; - } - } - - /* Empty Request */ - if (parity==0) - return 0; - - /* Repeating... */ - if (ir->old == parity) - return 0; - - ir->old = parity; - - /* drop special codes when a key is held down a long time for the grey controller - In this case, the second bit of the code is asserted */ - if (marker == 0xfe && (code & 0x40)) - return 0; - - code %= code_modulo; - - *ir_raw = code; - *ir_key = code; - - dprintk(1,"Pinnacle PCTV key %02x\n", code); - - return 1; -} - -/* The grey pinnacle PCTV remote - * - * There are one issue with this remote: - * - I2c packet does not change when the same key is pressed quickly. The workaround - * is to hold down each key for about half a second, so that another code is generated - * in the i2c packet, and the function can distinguish key presses. - * - * Sylvain Pasche <sylvain.pasche@gmail.com> - */ -int get_key_pinnacle_grey(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw) -{ - - return get_key_pinnacle(ir, ir_key, ir_raw, 1, 0xfe, 0xff); -} - -EXPORT_SYMBOL_GPL(get_key_pinnacle_grey); - - -/* The new pinnacle PCTV remote (with the colored buttons) - * - * Ricardo Cerqueira <v4l@cerqueira.org> - */ -int get_key_pinnacle_color(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw) -{ - /* code_modulo parameter (0x88) is used to reduce code value to fit inside IR_KEYTAB_SIZE - * - * this is the only value that results in 42 unique - * codes < 128 - */ - - return get_key_pinnacle(ir, ir_key, ir_raw, 2, 0x80, 0x88); -} - -EXPORT_SYMBOL_GPL(get_key_pinnacle_color); - /* ----------------------------------------------------------------------- */ static void ir_key_poll(struct IR_i2c *ir) diff --git a/drivers/media/video/ivtv/ivtv-cards.c b/drivers/media/video/ivtv/ivtv-cards.c index 4fb8faefe2ce..4e05f91a9100 100644 --- a/drivers/media/video/ivtv/ivtv-cards.c +++ b/drivers/media/video/ivtv/ivtv-cards.c @@ -40,7 +40,7 @@ #define MSP_MONO MSP_INPUT(MSP_IN_MONO, MSP_IN_TUNER1, \ MSP_DSP_IN_SCART, MSP_DSP_IN_SCART) -#define V4L2_STD_NOT_MN (V4L2_STD_PAL|V4L2_STD_SECAM) +#define V4L2_STD_PAL_SECAM (V4L2_STD_PAL|V4L2_STD_SECAM) /* usual i2c tuner addresses to probe */ static struct ivtv_card_tuner_i2c ivtv_i2c_std = { @@ -300,7 +300,7 @@ static const struct ivtv_card ivtv_card_mpg600 = { .gpio_audio_detect = { .mask = 0x0900, .stereo = 0x0100 }, .tuners = { /* The PAL tuner is confirmed */ - { .std = V4L2_STD_NOT_MN, .tuner = TUNER_PHILIPS_FQ1216ME }, + { .std = V4L2_STD_PAL_SECAM, .tuner = TUNER_PHILIPS_FQ1216ME }, { .std = V4L2_STD_ALL, .tuner = TUNER_PHILIPS_FQ1286 }, }, .pci_list = ivtv_pci_mpg600, @@ -341,7 +341,7 @@ static const struct ivtv_card ivtv_card_mpg160 = { .lang1 = 0x0004, .lang2 = 0x0000, .both = 0x0008 }, .gpio_audio_detect = { .mask = 0x0900, .stereo = 0x0100 }, .tuners = { - { .std = V4L2_STD_NOT_MN, .tuner = TUNER_PHILIPS_FQ1216ME }, + { .std = V4L2_STD_PAL_SECAM, .tuner = TUNER_PHILIPS_FQ1216ME }, { .std = V4L2_STD_ALL, .tuner = TUNER_PHILIPS_FQ1286 }, }, .pci_list = ivtv_pci_mpg160, @@ -377,7 +377,7 @@ static const struct ivtv_card ivtv_card_pg600 = { { IVTV_CARD_INPUT_LINE_IN1, CX25840_AUDIO_SERIAL }, }, .tuners = { - { .std = V4L2_STD_NOT_MN, .tuner = TUNER_PHILIPS_FQ1216ME }, + { .std = V4L2_STD_PAL_SECAM, .tuner = TUNER_PHILIPS_FQ1216ME }, { .std = V4L2_STD_ALL, .tuner = TUNER_PHILIPS_FQ1286 }, }, .pci_list = ivtv_pci_pg600, @@ -418,7 +418,7 @@ static const struct ivtv_card ivtv_card_avc2410 = { on the country/region setting of the user to decide which tuner is available. */ .tuners = { - { .std = V4L2_STD_NOT_MN, .tuner = TUNER_PHILIPS_FM1216ME_MK3 }, + { .std = V4L2_STD_PAL_SECAM, .tuner = TUNER_PHILIPS_FM1216ME_MK3 }, { .std = V4L2_STD_ALL - V4L2_STD_NTSC_M_JP, .tuner = TUNER_PHILIPS_FM1236_MK3 }, { .std = V4L2_STD_NTSC_M_JP, .tuner = TUNER_PHILIPS_FQ1286 }, @@ -492,7 +492,7 @@ static const struct ivtv_card ivtv_card_tg5000tv = { .gpio_video_input = { .mask = 0x0030, .tuner = 0x0000, .composite = 0x0010, .svideo = 0x0020 }, .tuners = { - { .std = V4L2_STD_525_60|V4L2_STD_MN, .tuner = TUNER_PHILIPS_FQ1286 }, + { .std = V4L2_STD_MN, .tuner = TUNER_PHILIPS_FQ1286 }, }, .pci_list = ivtv_pci_tg5000tv, .i2c = &ivtv_i2c_std, @@ -523,7 +523,7 @@ static const struct ivtv_card ivtv_card_va2000 = { { IVTV_CARD_INPUT_AUD_TUNER, MSP_TUNER }, }, .tuners = { - { .std = V4L2_STD_525_60|V4L2_STD_MN, .tuner = TUNER_PHILIPS_FQ1286 }, + { .std = V4L2_STD_MN, .tuner = TUNER_PHILIPS_FQ1286 }, }, .pci_list = ivtv_pci_va2000, .i2c = &ivtv_i2c_std, @@ -567,7 +567,7 @@ static const struct ivtv_card ivtv_card_cx23416gyc = { .gpio_audio_freq = { .mask = 0xc000, .f32000 = 0x0000, .f44100 = 0x4000, .f48000 = 0x8000 }, .tuners = { - { .std = V4L2_STD_NOT_MN, .tuner = TUNER_PHILIPS_FM1216ME_MK3 }, + { .std = V4L2_STD_PAL_SECAM, .tuner = TUNER_PHILIPS_FM1216ME_MK3 }, { .std = V4L2_STD_ALL, .tuner = TUNER_PHILIPS_FM1236_MK3 }, }, .pci_list = ivtv_pci_cx23416gyc, @@ -599,7 +599,7 @@ static const struct ivtv_card ivtv_card_cx23416gyc_nogr = { .gpio_audio_freq = { .mask = 0xc000, .f32000 = 0x0000, .f44100 = 0x4000, .f48000 = 0x8000 }, .tuners = { - { .std = V4L2_STD_NOT_MN, .tuner = TUNER_PHILIPS_FM1216ME_MK3 }, + { .std = V4L2_STD_PAL_SECAM, .tuner = TUNER_PHILIPS_FM1216ME_MK3 }, { .std = V4L2_STD_ALL, .tuner = TUNER_PHILIPS_FM1236_MK3 }, }, .i2c = &ivtv_i2c_std, @@ -629,7 +629,7 @@ static const struct ivtv_card ivtv_card_cx23416gyc_nogrycs = { .gpio_audio_freq = { .mask = 0xc000, .f32000 = 0x0000, .f44100 = 0x4000, .f48000 = 0x8000 }, .tuners = { - { .std = V4L2_STD_NOT_MN, .tuner = TUNER_PHILIPS_FM1216ME_MK3 }, + { .std = V4L2_STD_PAL_SECAM, .tuner = TUNER_PHILIPS_FM1216ME_MK3 }, { .std = V4L2_STD_ALL, .tuner = TUNER_PHILIPS_FM1236_MK3 }, }, .i2c = &ivtv_i2c_std, @@ -669,7 +669,7 @@ static const struct ivtv_card ivtv_card_gv_mvprx = { .gpio_audio_input = { .mask = 0xffff, .tuner = 0x0200, .linein = 0x0300 }, .tuners = { /* This card has the Panasonic VP27 tuner */ - { .std = V4L2_STD_525_60|V4L2_STD_MN, .tuner = TUNER_PANASONIC_VP27 }, + { .std = V4L2_STD_MN, .tuner = TUNER_PANASONIC_VP27 }, }, .pci_list = ivtv_pci_gv_mvprx, .i2c = &ivtv_i2c_std, @@ -706,7 +706,7 @@ static const struct ivtv_card ivtv_card_gv_mvprx2e = { .gpio_audio_input = { .mask = 0xffff, .tuner = 0x0200, .linein = 0x0300 }, .tuners = { /* This card has the Panasonic VP27 tuner */ - { .std = V4L2_STD_525_60|V4L2_STD_MN, .tuner = TUNER_PANASONIC_VP27 }, + { .std = V4L2_STD_MN, .tuner = TUNER_PANASONIC_VP27 }, }, .pci_list = ivtv_pci_gv_mvprx2e, .i2c = &ivtv_i2c_std, @@ -741,7 +741,7 @@ static const struct ivtv_card ivtv_card_gotview_pci_dvd = { .gpio_init = { .direction = 0xf000, .initial_value = 0xA000 }, .tuners = { /* This card has a Philips FQ1216ME MK3 tuner */ - { .std = V4L2_STD_NOT_MN, .tuner = TUNER_PHILIPS_FM1216ME_MK3 }, + { .std = V4L2_STD_PAL_SECAM, .tuner = TUNER_PHILIPS_FM1216ME_MK3 }, }, .pci_list = ivtv_pci_gotview_pci_dvd, .i2c = &ivtv_i2c_std, @@ -780,7 +780,7 @@ static const struct ivtv_card ivtv_card_gotview_pci_dvd2 = { .gpio_audio_input = { .mask = 0x0800, .tuner = 0, .linein = 0, .radio = 0x0800 }, .tuners = { /* This card has a Philips FQ1216ME MK5 tuner */ - { .std = V4L2_STD_NOT_MN, .tuner = TUNER_PHILIPS_FM1216ME_MK3 }, + { .std = V4L2_STD_PAL_SECAM, .tuner = TUNER_PHILIPS_FM1216ME_MK3 }, }, .pci_list = ivtv_pci_gotview_pci_dvd2, .i2c = &ivtv_i2c_std, @@ -858,7 +858,7 @@ static const struct ivtv_card ivtv_card_dctmvtvp1 = { .gpio_video_input = { .mask = 0x0030, .tuner = 0x0000, .composite = 0x0010, .svideo = 0x0020}, .tuners = { - { .std = V4L2_STD_525_60|V4L2_STD_MN, .tuner = TUNER_PHILIPS_FQ1286 }, + { .std = V4L2_STD_MN, .tuner = TUNER_PHILIPS_FQ1286 }, }, .pci_list = ivtv_pci_dctmvtvp1, .i2c = &ivtv_i2c_std, @@ -923,7 +923,6 @@ static const struct ivtv_card ivtv_card_club3d = { { IVTV_CARD_INPUT_LINE_IN1, CX25840_AUDIO_SERIAL }, }, .radio_input = { IVTV_CARD_INPUT_AUD_TUNER, CX25840_AUDIO5 }, - .gpio_init = { .direction = 0x1000, .initial_value = 0x1000 }, /* tuner reset */ .xceive_pin = 12, .tuners = { { .std = V4L2_STD_ALL, .tuner = TUNER_XC2028 }, @@ -959,7 +958,7 @@ static const struct ivtv_card ivtv_card_avertv_mce116 = { { IVTV_CARD_INPUT_LINE_IN1, CX25840_AUDIO_SERIAL, 1 }, }, /* enable line-in */ - .gpio_init = { .direction = 0xe400, .initial_value = 0x4400 }, + .gpio_init = { .direction = 0xe000, .initial_value = 0x4000 }, .xceive_pin = 10, .tuners = { { .std = V4L2_STD_ALL, .tuner = TUNER_XC2028 }, @@ -1001,7 +1000,7 @@ static const struct ivtv_card ivtv_card_aver_pvr150 = { .gpio_audio_input = { .mask = 0x0800, .tuner = 0, .linein = 0, .radio = 0x0800 }, .tuners = { /* This card has a Partsnic PTI-5NF05 tuner */ - { .std = V4L2_STD_525_60|V4L2_STD_MN, .tuner = TUNER_TCL_2002N }, + { .std = V4L2_STD_MN, .tuner = TUNER_TCL_2002N }, }, .pci_list = ivtv_pci_aver_pvr150, .i2c = &ivtv_i2c_radio, @@ -1069,7 +1068,7 @@ static const struct ivtv_card ivtv_card_asus_falcon2 = { }, .radio_input = { IVTV_CARD_INPUT_AUD_TUNER, CX25840_AUDIO_SERIAL, M52790_IN_TUNER }, .tuners = { - { .std = V4L2_STD_525_60|V4L2_STD_MN, .tuner = TUNER_PHILIPS_FM1236_MK3 }, + { .std = V4L2_STD_MN, .tuner = TUNER_PHILIPS_FM1236_MK3 }, }, .pci_list = ivtv_pci_asus_falcon2, .i2c = &ivtv_i2c_std, @@ -1102,7 +1101,7 @@ static const struct ivtv_card ivtv_card_aver_m104 = { }, .radio_input = { IVTV_CARD_INPUT_AUD_TUNER, CX25840_AUDIO_SERIAL, 2 }, /* enable line-in + reset tuner */ - .gpio_init = { .direction = 0xe400, .initial_value = 0x4000 }, + .gpio_init = { .direction = 0xe000, .initial_value = 0x4000 }, .xceive_pin = 10, .tuners = { { .std = V4L2_STD_ALL, .tuner = TUNER_XC2028 }, @@ -1111,6 +1110,41 @@ static const struct ivtv_card ivtv_card_aver_m104 = { .i2c = &ivtv_i2c_std, }; +/* ------------------------------------------------------------------------- */ + +/* Buffalo PC-MV5L/PCI cards */ + +static const struct ivtv_card_pci_info ivtv_pci_buffalo[] = { + { PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_MELCO, 0x052b }, + { 0, 0, 0 } +}; + +static const struct ivtv_card ivtv_card_buffalo = { + .type = IVTV_CARD_BUFFALO_MV5L, + .name = "Buffalo PC-MV5L/PCI", + .v4l2_capabilities = IVTV_CAP_ENCODER, + .hw_video = IVTV_HW_CX25840, + .hw_audio = IVTV_HW_CX25840, + .hw_audio_ctrl = IVTV_HW_CX25840, + .hw_all = IVTV_HW_CX25840 | IVTV_HW_TUNER, + .video_inputs = { + { IVTV_CARD_INPUT_VID_TUNER, 0, CX25840_COMPOSITE2 }, + { IVTV_CARD_INPUT_SVIDEO1, 1, + CX25840_SVIDEO_LUMA3 | CX25840_SVIDEO_CHROMA4 }, + { IVTV_CARD_INPUT_COMPOSITE1, 1, CX25840_COMPOSITE1 }, + }, + .audio_inputs = { + { IVTV_CARD_INPUT_AUD_TUNER, CX25840_AUDIO5 }, + { IVTV_CARD_INPUT_LINE_IN1, CX25840_AUDIO_SERIAL }, + }, + .xceive_pin = 12, + .tuners = { + { .std = V4L2_STD_ALL, .tuner = TUNER_XC2028 }, + }, + .pci_list = ivtv_pci_buffalo, + .i2c = &ivtv_i2c_std, +}; + static const struct ivtv_card *ivtv_card_list[] = { &ivtv_card_pvr250, &ivtv_card_pvr350, @@ -1137,6 +1171,7 @@ static const struct ivtv_card *ivtv_card_list[] = { &ivtv_card_aver_pvr150, &ivtv_card_aver_ezmaker, &ivtv_card_aver_m104, + &ivtv_card_buffalo, /* Variations of standard cards but with the same PCI IDs. These cards must come last in this list. */ diff --git a/drivers/media/video/ivtv/ivtv-cards.h b/drivers/media/video/ivtv/ivtv-cards.h index 748485dcebbd..381af1bceef8 100644 --- a/drivers/media/video/ivtv/ivtv-cards.h +++ b/drivers/media/video/ivtv/ivtv-cards.h @@ -49,7 +49,8 @@ #define IVTV_CARD_AVER_PVR150PLUS 22 /* AVerMedia PVR-150 Plus */ #define IVTV_CARD_AVER_EZMAKER 23 /* AVerMedia EZMaker PCI Deluxe */ #define IVTV_CARD_AVER_M104 24 /* AverMedia M104 miniPCI card */ -#define IVTV_CARD_LAST 24 +#define IVTV_CARD_BUFFALO_MV5L 25 /* Buffalo PC-MV5L/PCI card */ +#define IVTV_CARD_LAST 25 /* Variants of existing cards but with the same PCI IDs. The driver detects these based on other device information. diff --git a/drivers/media/video/ivtv/ivtv-controls.c b/drivers/media/video/ivtv/ivtv-controls.c index c7e449f6397b..48e103be7183 100644 --- a/drivers/media/video/ivtv/ivtv-controls.c +++ b/drivers/media/video/ivtv/ivtv-controls.c @@ -47,12 +47,12 @@ static const u32 *ctrl_classes[] = { NULL }; -static int ivtv_queryctrl(struct ivtv *itv, struct v4l2_queryctrl *qctrl) + +int ivtv_queryctrl(struct file *file, void *fh, struct v4l2_queryctrl *qctrl) { + struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv; const char *name; - IVTV_DEBUG_IOCTL("VIDIOC_QUERYCTRL(%08x)\n", qctrl->id); - qctrl->id = v4l2_ctrl_next(ctrl_classes, qctrl->id); if (qctrl->id == 0) return -EINVAL; @@ -87,21 +87,35 @@ static int ivtv_queryctrl(struct ivtv *itv, struct v4l2_queryctrl *qctrl) return 0; } -static int ivtv_querymenu(struct ivtv *itv, struct v4l2_querymenu *qmenu) +int ivtv_querymenu(struct file *file, void *fh, struct v4l2_querymenu *qmenu) { + struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv; struct v4l2_queryctrl qctrl; qctrl.id = qmenu->id; - ivtv_queryctrl(itv, &qctrl); - return v4l2_ctrl_query_menu(qmenu, &qctrl, cx2341x_ctrl_get_menu(qmenu->id)); + ivtv_queryctrl(file, fh, &qctrl); + return v4l2_ctrl_query_menu(qmenu, &qctrl, + cx2341x_ctrl_get_menu(&itv->params, qmenu->id)); } -static int ivtv_s_ctrl(struct ivtv *itv, struct v4l2_control *vctrl) +static int ivtv_try_ctrl(struct file *file, void *fh, + struct v4l2_ext_control *vctrl) { - s32 v = vctrl->value; - - IVTV_DEBUG_IOCTL("VIDIOC_S_CTRL(%08x, %x)\n", vctrl->id, v); + struct v4l2_queryctrl qctrl; + const char **menu_items = NULL; + int err; + + qctrl.id = vctrl->id; + err = ivtv_queryctrl(file, fh, &qctrl); + if (err) + return err; + if (qctrl.type == V4L2_CTRL_TYPE_MENU) + menu_items = v4l2_ctrl_get_menu(qctrl.id); + return v4l2_ctrl_check(vctrl, &qctrl, menu_items); +} +static int ivtv_s_ctrl(struct ivtv *itv, struct v4l2_control *vctrl) +{ switch (vctrl->id) { /* Standard V4L2 controls */ case V4L2_CID_BRIGHTNESS: @@ -119,7 +133,7 @@ static int ivtv_s_ctrl(struct ivtv *itv, struct v4l2_control *vctrl) return ivtv_i2c_hw(itv, itv->card->hw_audio_ctrl, VIDIOC_S_CTRL, vctrl); default: - IVTV_DEBUG_IOCTL("invalid control %x\n", vctrl->id); + IVTV_DEBUG_IOCTL("invalid control 0x%x\n", vctrl->id); return -EINVAL; } return 0; @@ -127,8 +141,6 @@ static int ivtv_s_ctrl(struct ivtv *itv, struct v4l2_control *vctrl) static int ivtv_g_ctrl(struct ivtv *itv, struct v4l2_control *vctrl) { - IVTV_DEBUG_IOCTL("VIDIOC_G_CTRL(%08x)\n", vctrl->id); - switch (vctrl->id) { /* Standard V4L2 controls */ case V4L2_CID_BRIGHTNESS: @@ -145,7 +157,7 @@ static int ivtv_g_ctrl(struct ivtv *itv, struct v4l2_control *vctrl) case V4L2_CID_AUDIO_LOUDNESS: return ivtv_i2c_hw(itv, itv->card->hw_audio_ctrl, VIDIOC_G_CTRL, vctrl); default: - IVTV_DEBUG_IOCTL("invalid control %x\n", vctrl->id); + IVTV_DEBUG_IOCTL("invalid control 0x%x\n", vctrl->id); return -EINVAL; } return 0; @@ -191,119 +203,106 @@ static int ivtv_setup_vbi_fmt(struct ivtv *itv, enum v4l2_mpeg_stream_vbi_fmt fm return 0; } -int ivtv_control_ioctls(struct ivtv *itv, unsigned int cmd, void *arg) +int ivtv_g_ext_ctrls(struct file *file, void *fh, struct v4l2_ext_controls *c) { + struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv; struct v4l2_control ctrl; - switch (cmd) { - case VIDIOC_QUERYMENU: - IVTV_DEBUG_IOCTL("VIDIOC_QUERYMENU\n"); - return ivtv_querymenu(itv, arg); - - case VIDIOC_QUERYCTRL: - return ivtv_queryctrl(itv, arg); - - case VIDIOC_S_CTRL: - return ivtv_s_ctrl(itv, arg); - - case VIDIOC_G_CTRL: - return ivtv_g_ctrl(itv, arg); - - case VIDIOC_S_EXT_CTRLS: - { - struct v4l2_ext_controls *c = arg; - - if (c->ctrl_class == V4L2_CTRL_CLASS_USER) { - int i; - int err = 0; - - for (i = 0; i < c->count; i++) { - ctrl.id = c->controls[i].id; - ctrl.value = c->controls[i].value; - err = ivtv_s_ctrl(itv, &ctrl); - c->controls[i].value = ctrl.value; - if (err) { - c->error_idx = i; - break; - } + if (c->ctrl_class == V4L2_CTRL_CLASS_USER) { + int i; + int err = 0; + + for (i = 0; i < c->count; i++) { + ctrl.id = c->controls[i].id; + ctrl.value = c->controls[i].value; + err = ivtv_g_ctrl(itv, &ctrl); + c->controls[i].value = ctrl.value; + if (err) { + c->error_idx = i; + break; } - return err; } - IVTV_DEBUG_IOCTL("VIDIOC_S_EXT_CTRLS\n"); - if (c->ctrl_class == V4L2_CTRL_CLASS_MPEG) { - static u32 freqs[3] = { 44100, 48000, 32000 }; - struct cx2341x_mpeg_params p = itv->params; - int err = cx2341x_ext_ctrls(&p, atomic_read(&itv->capturing), arg, cmd); - unsigned idx; - - if (err) - return err; - - if (p.video_encoding != itv->params.video_encoding) { - int is_mpeg1 = p.video_encoding == - V4L2_MPEG_VIDEO_ENCODING_MPEG_1; - struct v4l2_format fmt; - - /* fix videodecoder resolution */ - fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - fmt.fmt.pix.width = itv->params.width / (is_mpeg1 ? 2 : 1); - fmt.fmt.pix.height = itv->params.height; - itv->video_dec_func(itv, VIDIOC_S_FMT, &fmt); - } - err = cx2341x_update(itv, ivtv_api_func, &itv->params, &p); - if (!err && itv->params.stream_vbi_fmt != p.stream_vbi_fmt) { - err = ivtv_setup_vbi_fmt(itv, p.stream_vbi_fmt); + return err; + } + if (c->ctrl_class == V4L2_CTRL_CLASS_MPEG) + return cx2341x_ext_ctrls(&itv->params, 0, c, VIDIOC_G_EXT_CTRLS); + return -EINVAL; +} + +int ivtv_s_ext_ctrls(struct file *file, void *fh, struct v4l2_ext_controls *c) +{ + struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv; + struct v4l2_control ctrl; + + if (c->ctrl_class == V4L2_CTRL_CLASS_USER) { + int i; + int err = 0; + + for (i = 0; i < c->count; i++) { + ctrl.id = c->controls[i].id; + ctrl.value = c->controls[i].value; + err = ivtv_s_ctrl(itv, &ctrl); + c->controls[i].value = ctrl.value; + if (err) { + c->error_idx = i; + break; } - itv->params = p; - itv->dualwatch_stereo_mode = p.audio_properties & 0x0300; - idx = p.audio_properties & 0x03; - /* The audio clock of the digitizer must match the codec sample - rate otherwise you get some very strange effects. */ - if (idx < sizeof(freqs)) - ivtv_call_i2c_clients(itv, VIDIOC_INT_AUDIO_CLOCK_FREQ, &freqs[idx]); - return err; } - return -EINVAL; + return err; } + if (c->ctrl_class == V4L2_CTRL_CLASS_MPEG) { + static u32 freqs[3] = { 44100, 48000, 32000 }; + struct cx2341x_mpeg_params p = itv->params; + int err = cx2341x_ext_ctrls(&p, atomic_read(&itv->capturing), c, VIDIOC_S_EXT_CTRLS); + unsigned idx; - case VIDIOC_G_EXT_CTRLS: - { - struct v4l2_ext_controls *c = arg; - - if (c->ctrl_class == V4L2_CTRL_CLASS_USER) { - int i; - int err = 0; - - for (i = 0; i < c->count; i++) { - ctrl.id = c->controls[i].id; - ctrl.value = c->controls[i].value; - err = ivtv_g_ctrl(itv, &ctrl); - c->controls[i].value = ctrl.value; - if (err) { - c->error_idx = i; - break; - } - } + if (err) return err; + + if (p.video_encoding != itv->params.video_encoding) { + int is_mpeg1 = p.video_encoding == + V4L2_MPEG_VIDEO_ENCODING_MPEG_1; + struct v4l2_format fmt; + + /* fix videodecoder resolution */ + fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + fmt.fmt.pix.width = itv->params.width / (is_mpeg1 ? 2 : 1); + fmt.fmt.pix.height = itv->params.height; + itv->video_dec_func(itv, VIDIOC_S_FMT, &fmt); } - IVTV_DEBUG_IOCTL("VIDIOC_G_EXT_CTRLS\n"); - if (c->ctrl_class == V4L2_CTRL_CLASS_MPEG) - return cx2341x_ext_ctrls(&itv->params, 0, arg, cmd); - return -EINVAL; + err = cx2341x_update(itv, ivtv_api_func, &itv->params, &p); + if (!err && itv->params.stream_vbi_fmt != p.stream_vbi_fmt) + err = ivtv_setup_vbi_fmt(itv, p.stream_vbi_fmt); + itv->params = p; + itv->dualwatch_stereo_mode = p.audio_properties & 0x0300; + idx = p.audio_properties & 0x03; + /* The audio clock of the digitizer must match the codec sample + rate otherwise you get some very strange effects. */ + if (idx < sizeof(freqs)) + ivtv_call_i2c_clients(itv, VIDIOC_INT_AUDIO_CLOCK_FREQ, &freqs[idx]); + return err; } + return -EINVAL; +} - case VIDIOC_TRY_EXT_CTRLS: - { - struct v4l2_ext_controls *c = arg; +int ivtv_try_ext_ctrls(struct file *file, void *fh, struct v4l2_ext_controls *c) +{ + struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv; - IVTV_DEBUG_IOCTL("VIDIOC_TRY_EXT_CTRLS\n"); - if (c->ctrl_class == V4L2_CTRL_CLASS_MPEG) - return cx2341x_ext_ctrls(&itv->params, atomic_read(&itv->capturing), arg, cmd); - return -EINVAL; - } + if (c->ctrl_class == V4L2_CTRL_CLASS_USER) { + int i; + int err = 0; - default: - return -EINVAL; + for (i = 0; i < c->count; i++) { + err = ivtv_try_ctrl(file, fh, &c->controls[i]); + if (err) { + c->error_idx = i; + break; + } + } + return err; } - return 0; + if (c->ctrl_class == V4L2_CTRL_CLASS_MPEG) + return cx2341x_ext_ctrls(&itv->params, atomic_read(&itv->capturing), c, VIDIOC_TRY_EXT_CTRLS); + return -EINVAL; } diff --git a/drivers/media/video/ivtv/ivtv-controls.h b/drivers/media/video/ivtv/ivtv-controls.h index bb8a6a5ed2bc..1c7721e23c9b 100644 --- a/drivers/media/video/ivtv/ivtv-controls.h +++ b/drivers/media/video/ivtv/ivtv-controls.h @@ -21,6 +21,10 @@ #ifndef IVTV_CONTROLS_H #define IVTV_CONTROLS_H -int ivtv_control_ioctls(struct ivtv *itv, unsigned int cmd, void *arg); +int ivtv_queryctrl(struct file *file, void *fh, struct v4l2_queryctrl *a); +int ivtv_g_ext_ctrls(struct file *file, void *fh, struct v4l2_ext_controls *a); +int ivtv_s_ext_ctrls(struct file *file, void *fh, struct v4l2_ext_controls *a); +int ivtv_try_ext_ctrls(struct file *file, void *fh, struct v4l2_ext_controls *a); +int ivtv_querymenu(struct file *file, void *fh, struct v4l2_querymenu *a); #endif diff --git a/drivers/media/video/ivtv/ivtv-driver.c b/drivers/media/video/ivtv/ivtv-driver.c index 797e636771da..41fd79279bb5 100644 --- a/drivers/media/video/ivtv/ivtv-driver.c +++ b/drivers/media/video/ivtv/ivtv-driver.c @@ -191,6 +191,7 @@ MODULE_PARM_DESC(cardtype, "\t\t\t23 = AverMedia PVR-150 Plus\n" "\t\t\t24 = AverMedia EZMaker PCI Deluxe\n" "\t\t\t25 = AverMedia M104 (not yet working)\n" + "\t\t\t26 = Buffalo PC-MV5L/PCI\n" "\t\t\t 0 = Autodetect (default)\n" "\t\t\t-1 = Ignore this card\n\t\t"); MODULE_PARM_DESC(pal, "Set PAL standard: BGH, DK, I, M, N, Nc, 60"); @@ -1019,7 +1020,7 @@ static int __devinit ivtv_probe(struct pci_dev *dev, ivtv_cards[ivtv_cards_active] = itv; itv->dev = dev; itv->num = ivtv_cards_active++; - snprintf(itv->name, sizeof(itv->name) - 1, "ivtv%d", itv->num); + snprintf(itv->name, sizeof(itv->name), "ivtv%d", itv->num); IVTV_INFO("Initializing card #%d\n", itv->num); spin_unlock(&ivtv_cards_lock); @@ -1127,6 +1128,12 @@ static int __devinit ivtv_probe(struct pci_dev *dev, /* if no tuner was found, then pick the first tuner in the card list */ if (itv->options.tuner == -1 && itv->card->tuners[0].std) { itv->std = itv->card->tuners[0].std; + if (itv->std & V4L2_STD_PAL) + itv->std = V4L2_STD_PAL_BG | V4L2_STD_PAL_H; + else if (itv->std & V4L2_STD_NTSC) + itv->std = V4L2_STD_NTSC_M; + else if (itv->std & V4L2_STD_SECAM) + itv->std = V4L2_STD_SECAM_L; itv->options.tuner = itv->card->tuners[0].tuner; } if (itv->options.radio == -1) @@ -1261,9 +1268,13 @@ err: int ivtv_init_on_first_open(struct ivtv *itv) { struct v4l2_frequency vf; + /* Needed to call ioctls later */ + struct ivtv_open_id fh; int fw_retry_count = 3; int video_input; + fh.itv = itv; + if (test_bit(IVTV_F_I_FAILED, &itv->i_flags)) return -ENXIO; @@ -1311,18 +1322,18 @@ int ivtv_init_on_first_open(struct ivtv *itv) video_input = itv->active_input; itv->active_input++; /* Force update of input */ - ivtv_v4l2_ioctls(itv, NULL, VIDIOC_S_INPUT, &video_input); + ivtv_s_input(NULL, &fh, video_input); /* Let the VIDIOC_S_STD ioctl do all the work, keeps the code in one place. */ itv->std++; /* Force full standard initialization */ itv->std_out = itv->std; - ivtv_v4l2_ioctls(itv, NULL, VIDIOC_S_FREQUENCY, &vf); + ivtv_s_frequency(NULL, &fh, &vf); if (itv->card->v4l2_capabilities & V4L2_CAP_VIDEO_OUTPUT) { ivtv_init_mpeg_decoder(itv); } - ivtv_v4l2_ioctls(itv, NULL, VIDIOC_S_STD, &itv->tuner_std); + ivtv_s_std(NULL, &fh, &itv->tuner_std); /* On a cx23416 this seems to be able to enable DMA to the chip? */ if (!itv->has_cx23415) diff --git a/drivers/media/video/ivtv/ivtv-driver.h b/drivers/media/video/ivtv/ivtv-driver.h index 9d23b1efd36d..a08bb3331cfb 100644 --- a/drivers/media/video/ivtv/ivtv-driver.h +++ b/drivers/media/video/ivtv/ivtv-driver.h @@ -635,7 +635,6 @@ struct ivtv { spinlock_t lock; /* lock access to this struct */ struct mutex serialize_lock; /* mutex used to serialize open/close/start/stop/ioctl operations */ - /* Streams */ int stream_buf_size[IVTV_MAX_STREAMS]; /* stream buffer size */ struct ivtv_stream streams[IVTV_MAX_STREAMS]; /* stream data */ diff --git a/drivers/media/video/ivtv/ivtv-fileops.c b/drivers/media/video/ivtv/ivtv-fileops.c index db813e071ce6..7ec5c99f9ad1 100644 --- a/drivers/media/video/ivtv/ivtv-fileops.c +++ b/drivers/media/video/ivtv/ivtv-fileops.c @@ -582,6 +582,19 @@ ssize_t ivtv_v4l2_write(struct file *filp, const char __user *user_buf, size_t c ivtv_queue_init(&q); set_bit(IVTV_F_S_APPL_IO, &s->s_flags); + /* Start decoder (returns 0 if already started) */ + mutex_lock(&itv->serialize_lock); + rc = ivtv_start_decoding(id, itv->speed); + mutex_unlock(&itv->serialize_lock); + if (rc) { + IVTV_DEBUG_WARN("Failed start decode stream %s\n", s->name); + + /* failure, clean up */ + clear_bit(IVTV_F_S_STREAMING, &s->s_flags); + clear_bit(IVTV_F_S_APPL_IO, &s->s_flags); + return rc; + } + retry: /* If possible, just DMA the entire frame - Check the data transfer size since we may get here before the stream has been fully set-up */ @@ -664,18 +677,6 @@ retry: ivtv_enqueue(s, buf, &s->q_full); } - /* Start decoder (returns 0 if already started) */ - mutex_lock(&itv->serialize_lock); - rc = ivtv_start_decoding(id, itv->speed); - mutex_unlock(&itv->serialize_lock); - if (rc) { - IVTV_DEBUG_WARN("Failed start decode stream %s\n", s->name); - - /* failure, clean up */ - clear_bit(IVTV_F_S_STREAMING, &s->s_flags); - clear_bit(IVTV_F_S_APPL_IO, &s->s_flags); - return rc; - } if (test_bit(IVTV_F_S_NEEDS_DATA, &s->s_flags)) { if (s->q_full.length >= itv->dma_data_req_size) { int got_sig; diff --git a/drivers/media/video/ivtv/ivtv-gpio.c b/drivers/media/video/ivtv/ivtv-gpio.c index d8ac09f3cce6..bc22905ea20f 100644 --- a/drivers/media/video/ivtv/ivtv-gpio.c +++ b/drivers/media/video/ivtv/ivtv-gpio.c @@ -146,15 +146,20 @@ int ivtv_reset_tuner_gpio(void *dev, int cmd, int value) void ivtv_gpio_init(struct ivtv *itv) { - if (itv->card->gpio_init.direction == 0) + u16 pin = 0; + + if (itv->card->xceive_pin) + pin = 1 << itv->card->xceive_pin; + + if ((itv->card->gpio_init.direction | pin) == 0) return; IVTV_DEBUG_INFO("GPIO initial dir: %08x out: %08x\n", read_reg(IVTV_REG_GPIO_DIR), read_reg(IVTV_REG_GPIO_OUT)); /* init output data then direction */ - write_reg(itv->card->gpio_init.initial_value, IVTV_REG_GPIO_OUT); - write_reg(itv->card->gpio_init.direction, IVTV_REG_GPIO_DIR); + write_reg(itv->card->gpio_init.initial_value | pin, IVTV_REG_GPIO_OUT); + write_reg(itv->card->gpio_init.direction | pin, IVTV_REG_GPIO_DIR); } static struct v4l2_queryctrl gpio_ctrl_mute = { diff --git a/drivers/media/video/ivtv/ivtv-i2c.c b/drivers/media/video/ivtv/ivtv-i2c.c index 32129f3ea836..af154238fb9a 100644 --- a/drivers/media/video/ivtv/ivtv-i2c.c +++ b/drivers/media/video/ivtv/ivtv-i2c.c @@ -75,10 +75,6 @@ #define IVTV_REG_I2C_GETSCL_OFFSET 0x7008 #define IVTV_REG_I2C_GETSDA_OFFSET 0x700c -#ifndef I2C_ADAP_CLASS_TV_ANALOG -#define I2C_ADAP_CLASS_TV_ANALOG I2C_CLASS_TV_ANALOG -#endif /* I2C_ADAP_CLASS_TV_ANALOG */ - #define IVTV_CS53L32A_I2C_ADDR 0x11 #define IVTV_M52790_I2C_ADDR 0x48 #define IVTV_CX25840_I2C_ADDR 0x44 @@ -139,7 +135,7 @@ static const u8 hw_addrs[] = { static const char * const hw_devicenames[] = { "cx25840", "saa7115", - "saa7127", + "saa7127_auto", /* saa7127 or saa7129 */ "msp3400", "tuner", "wm8775", diff --git a/drivers/media/video/ivtv/ivtv-ioctl.c b/drivers/media/video/ivtv/ivtv-ioctl.c index 26cc0f6699fd..52e00a7f3110 100644 --- a/drivers/media/video/ivtv/ivtv-ioctl.c +++ b/drivers/media/video/ivtv/ivtv-ioctl.c @@ -128,37 +128,6 @@ u16 ivtv_get_service_set(struct v4l2_sliced_vbi_format *fmt) return set; } -static const struct { - v4l2_std_id std; - char *name; -} enum_stds[] = { - { V4L2_STD_PAL_BG | V4L2_STD_PAL_H, "PAL-BGH" }, - { V4L2_STD_PAL_DK, "PAL-DK" }, - { V4L2_STD_PAL_I, "PAL-I" }, - { V4L2_STD_PAL_M, "PAL-M" }, - { V4L2_STD_PAL_N, "PAL-N" }, - { V4L2_STD_PAL_Nc, "PAL-Nc" }, - { V4L2_STD_SECAM_B | V4L2_STD_SECAM_G | V4L2_STD_SECAM_H, "SECAM-BGH" }, - { V4L2_STD_SECAM_DK, "SECAM-DK" }, - { V4L2_STD_SECAM_L, "SECAM-L" }, - { V4L2_STD_SECAM_LC, "SECAM-L'" }, - { V4L2_STD_NTSC_M, "NTSC-M" }, - { V4L2_STD_NTSC_M_JP, "NTSC-J" }, - { V4L2_STD_NTSC_M_KR, "NTSC-K" }, -}; - -static const struct v4l2_standard ivtv_std_60hz = -{ - .frameperiod = {.numerator = 1001, .denominator = 30000}, - .framelines = 525, -}; - -static const struct v4l2_standard ivtv_std_50hz = -{ - .frameperiod = {.numerator = 1, .denominator = 25}, - .framelines = 625, -}; - void ivtv_set_osd_alpha(struct ivtv *itv) { ivtv_vapi(itv, CX2341X_OSD_SET_GLOBAL_ALPHA, 3, @@ -345,1073 +314,1219 @@ static int ivtv_video_command(struct ivtv *itv, struct ivtv_open_id *id, return 0; } -static int ivtv_itvc(struct ivtv *itv, unsigned int cmd, void *arg) +static int ivtv_g_fmt_sliced_vbi_out(struct file *file, void *fh, struct v4l2_format *fmt) { - struct v4l2_register *regs = arg; - unsigned long flags; - volatile u8 __iomem *reg_start; + struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv; + struct v4l2_sliced_vbi_format *vbifmt = &fmt->fmt.sliced; - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - if (regs->reg >= IVTV_REG_OFFSET && regs->reg < IVTV_REG_OFFSET + IVTV_REG_SIZE) - reg_start = itv->reg_mem - IVTV_REG_OFFSET; - else if (itv->has_cx23415 && regs->reg >= IVTV_DECODER_OFFSET && - regs->reg < IVTV_DECODER_OFFSET + IVTV_DECODER_SIZE) - reg_start = itv->dec_mem - IVTV_DECODER_OFFSET; - else if (regs->reg >= 0 && regs->reg < IVTV_ENCODER_SIZE) - reg_start = itv->enc_mem; - else + vbifmt->reserved[0] = 0; + vbifmt->reserved[1] = 0; + if (!(itv->v4l2_cap & V4L2_CAP_SLICED_VBI_OUTPUT)) return -EINVAL; - - spin_lock_irqsave(&ivtv_cards_lock, flags); - if (cmd == VIDIOC_DBG_G_REGISTER) { - regs->val = readl(regs->reg + reg_start); + vbifmt->io_size = sizeof(struct v4l2_sliced_vbi_data) * 36; + if (itv->is_60hz) { + vbifmt->service_lines[0][21] = V4L2_SLICED_CAPTION_525; + vbifmt->service_lines[1][21] = V4L2_SLICED_CAPTION_525; } else { - writel(regs->val, regs->reg + reg_start); + vbifmt->service_lines[0][23] = V4L2_SLICED_WSS_625; + vbifmt->service_lines[0][16] = V4L2_SLICED_VPS; } - spin_unlock_irqrestore(&ivtv_cards_lock, flags); + vbifmt->service_set = ivtv_get_service_set(vbifmt); return 0; } -static int ivtv_get_fmt(struct ivtv *itv, int streamtype, struct v4l2_format *fmt) +static int ivtv_g_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *fmt) { - switch (fmt->type) { - case V4L2_BUF_TYPE_VIDEO_OUTPUT: - if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) - return -EINVAL; - fmt->fmt.pix.width = itv->main_rect.width; - fmt->fmt.pix.height = itv->main_rect.height; - fmt->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; - fmt->fmt.pix.field = V4L2_FIELD_INTERLACED; - if (streamtype == IVTV_DEC_STREAM_TYPE_YUV) { - switch (itv->yuv_info.lace_mode & IVTV_YUV_MODE_MASK) { - case IVTV_YUV_MODE_INTERLACED: - fmt->fmt.pix.field = (itv->yuv_info.lace_mode & IVTV_YUV_SYNC_MASK) ? - V4L2_FIELD_INTERLACED_BT : V4L2_FIELD_INTERLACED_TB; - break; - case IVTV_YUV_MODE_PROGRESSIVE: - fmt->fmt.pix.field = V4L2_FIELD_NONE; - break; - default: - fmt->fmt.pix.field = V4L2_FIELD_ANY; - break; - } - fmt->fmt.pix.pixelformat = V4L2_PIX_FMT_HM12; - fmt->fmt.pix.bytesperline = 720; - fmt->fmt.pix.width = itv->yuv_info.v4l2_src_w; - fmt->fmt.pix.height = itv->yuv_info.v4l2_src_h; - /* YUV size is (Y=(h*w) + UV=(h*(w/2))) */ - fmt->fmt.pix.sizeimage = - 1080 * ((fmt->fmt.pix.height + 31) & ~31); - } else if (streamtype == IVTV_ENC_STREAM_TYPE_YUV) { - fmt->fmt.pix.pixelformat = V4L2_PIX_FMT_HM12; - /* YUV size is (Y=(h*w) + UV=(h*(w/2))) */ - fmt->fmt.pix.sizeimage = - fmt->fmt.pix.height * fmt->fmt.pix.width + - fmt->fmt.pix.height * (fmt->fmt.pix.width / 2); - } else { - fmt->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG; - fmt->fmt.pix.sizeimage = 128 * 1024; - } - break; - - case V4L2_BUF_TYPE_VIDEO_CAPTURE: - fmt->fmt.pix.width = itv->params.width; - fmt->fmt.pix.height = itv->params.height; - fmt->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; - fmt->fmt.pix.field = V4L2_FIELD_INTERLACED; - if (streamtype == IVTV_ENC_STREAM_TYPE_YUV || - streamtype == IVTV_DEC_STREAM_TYPE_YUV) { - fmt->fmt.pix.pixelformat = V4L2_PIX_FMT_HM12; - /* YUV size is (Y=(h*w) + UV=(h*(w/2))) */ - fmt->fmt.pix.sizeimage = - fmt->fmt.pix.height * fmt->fmt.pix.width + - fmt->fmt.pix.height * (fmt->fmt.pix.width / 2); - } else { - fmt->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG; - fmt->fmt.pix.sizeimage = 128 * 1024; - } - break; + struct ivtv_open_id *id = fh; + struct ivtv *itv = id->itv; + struct v4l2_pix_format *pixfmt = &fmt->fmt.pix; + + pixfmt->width = itv->params.width; + pixfmt->height = itv->params.height; + pixfmt->colorspace = V4L2_COLORSPACE_SMPTE170M; + pixfmt->field = V4L2_FIELD_INTERLACED; + pixfmt->priv = 0; + if (id->type == IVTV_ENC_STREAM_TYPE_YUV) { + pixfmt->pixelformat = V4L2_PIX_FMT_HM12; + /* YUV size is (Y=(h*w) + UV=(h*(w/2))) */ + pixfmt->sizeimage = + pixfmt->height * pixfmt->width + + pixfmt->height * (pixfmt->width / 2); + pixfmt->bytesperline = 720; + } else { + pixfmt->pixelformat = V4L2_PIX_FMT_MPEG; + pixfmt->sizeimage = 128 * 1024; + pixfmt->bytesperline = 0; + } + return 0; +} - case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY: - if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) - return -EINVAL; - fmt->fmt.win.chromakey = itv->osd_chroma_key; - fmt->fmt.win.global_alpha = itv->osd_global_alpha; - break; +static int ivtv_g_fmt_vbi_cap(struct file *file, void *fh, struct v4l2_format *fmt) +{ + struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv; + struct v4l2_vbi_format *vbifmt = &fmt->fmt.vbi; + + vbifmt->sampling_rate = 27000000; + vbifmt->offset = 248; + vbifmt->samples_per_line = itv->vbi.raw_decoder_line_size - 4; + vbifmt->sample_format = V4L2_PIX_FMT_GREY; + vbifmt->start[0] = itv->vbi.start[0]; + vbifmt->start[1] = itv->vbi.start[1]; + vbifmt->count[0] = vbifmt->count[1] = itv->vbi.count; + vbifmt->flags = 0; + vbifmt->reserved[0] = 0; + vbifmt->reserved[1] = 0; + return 0; +} - case V4L2_BUF_TYPE_VBI_CAPTURE: - fmt->fmt.vbi.sampling_rate = 27000000; - fmt->fmt.vbi.offset = 248; - fmt->fmt.vbi.samples_per_line = itv->vbi.raw_decoder_line_size - 4; - fmt->fmt.vbi.sample_format = V4L2_PIX_FMT_GREY; - fmt->fmt.vbi.start[0] = itv->vbi.start[0]; - fmt->fmt.vbi.start[1] = itv->vbi.start[1]; - fmt->fmt.vbi.count[0] = fmt->fmt.vbi.count[1] = itv->vbi.count; - break; +static int ivtv_g_fmt_sliced_vbi_cap(struct file *file, void *fh, struct v4l2_format *fmt) +{ + struct v4l2_sliced_vbi_format *vbifmt = &fmt->fmt.sliced; + struct ivtv_open_id *id = fh; + struct ivtv *itv = id->itv; - case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT: - { - struct v4l2_sliced_vbi_format *vbifmt = &fmt->fmt.sliced; + vbifmt->reserved[0] = 0; + vbifmt->reserved[1] = 0; + vbifmt->io_size = sizeof(struct v4l2_sliced_vbi_data) * 36; - if (!(itv->v4l2_cap & V4L2_CAP_SLICED_VBI_OUTPUT)) - return -EINVAL; - vbifmt->io_size = sizeof(struct v4l2_sliced_vbi_data) * 36; - memset(vbifmt->reserved, 0, sizeof(vbifmt->reserved)); - memset(vbifmt->service_lines, 0, sizeof(vbifmt->service_lines)); - if (itv->is_60hz) { - vbifmt->service_lines[0][21] = V4L2_SLICED_CAPTION_525; - vbifmt->service_lines[1][21] = V4L2_SLICED_CAPTION_525; - } else { - vbifmt->service_lines[0][23] = V4L2_SLICED_WSS_625; - vbifmt->service_lines[0][16] = V4L2_SLICED_VPS; - } - vbifmt->service_set = ivtv_get_service_set(vbifmt); - break; + if (id->type == IVTV_DEC_STREAM_TYPE_VBI) { + vbifmt->service_set = itv->is_50hz ? V4L2_SLICED_VBI_625 : + V4L2_SLICED_VBI_525; + ivtv_expand_service_set(vbifmt, itv->is_50hz); + return 0; } - case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE: - { - struct v4l2_sliced_vbi_format *vbifmt = &fmt->fmt.sliced; + itv->video_dec_func(itv, VIDIOC_G_FMT, fmt); + vbifmt->service_set = ivtv_get_service_set(vbifmt); + return 0; +} - vbifmt->io_size = sizeof(struct v4l2_sliced_vbi_data) * 36; - memset(vbifmt->reserved, 0, sizeof(vbifmt->reserved)); - memset(vbifmt->service_lines, 0, sizeof(vbifmt->service_lines)); +static int ivtv_g_fmt_vid_out(struct file *file, void *fh, struct v4l2_format *fmt) +{ + struct ivtv_open_id *id = fh; + struct ivtv *itv = id->itv; + struct v4l2_pix_format *pixfmt = &fmt->fmt.pix; - if (streamtype == IVTV_DEC_STREAM_TYPE_VBI) { - vbifmt->service_set = itv->is_50hz ? V4L2_SLICED_VBI_625 : - V4L2_SLICED_VBI_525; - ivtv_expand_service_set(vbifmt, itv->is_50hz); + if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) + return -EINVAL; + pixfmt->width = itv->main_rect.width; + pixfmt->height = itv->main_rect.height; + pixfmt->colorspace = V4L2_COLORSPACE_SMPTE170M; + pixfmt->field = V4L2_FIELD_INTERLACED; + pixfmt->priv = 0; + if (id->type == IVTV_DEC_STREAM_TYPE_YUV) { + switch (itv->yuv_info.lace_mode & IVTV_YUV_MODE_MASK) { + case IVTV_YUV_MODE_INTERLACED: + pixfmt->field = (itv->yuv_info.lace_mode & IVTV_YUV_SYNC_MASK) ? + V4L2_FIELD_INTERLACED_BT : V4L2_FIELD_INTERLACED_TB; + break; + case IVTV_YUV_MODE_PROGRESSIVE: + pixfmt->field = V4L2_FIELD_NONE; + break; + default: + pixfmt->field = V4L2_FIELD_ANY; break; } - - itv->video_dec_func(itv, VIDIOC_G_FMT, fmt); - vbifmt->service_set = ivtv_get_service_set(vbifmt); - break; - } - case V4L2_BUF_TYPE_VBI_OUTPUT: - case V4L2_BUF_TYPE_VIDEO_OVERLAY: - default: - return -EINVAL; + pixfmt->pixelformat = V4L2_PIX_FMT_HM12; + pixfmt->bytesperline = 720; + pixfmt->width = itv->yuv_info.v4l2_src_w; + pixfmt->height = itv->yuv_info.v4l2_src_h; + /* YUV size is (Y=(h*w) + UV=(h*(w/2))) */ + pixfmt->sizeimage = + 1080 * ((pixfmt->height + 31) & ~31); + } else { + pixfmt->pixelformat = V4L2_PIX_FMT_MPEG; + pixfmt->sizeimage = 128 * 1024; + pixfmt->bytesperline = 0; } return 0; } -static int ivtv_try_or_set_fmt(struct ivtv *itv, int streamtype, - struct v4l2_format *fmt, int set_fmt) +static int ivtv_g_fmt_vid_out_overlay(struct file *file, void *fh, struct v4l2_format *fmt) { - struct yuv_playback_info *yi = &itv->yuv_info; - struct v4l2_sliced_vbi_format *vbifmt = &fmt->fmt.sliced; - u16 set; + struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv; + struct v4l2_window *winfmt = &fmt->fmt.win; - if (fmt->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) { - struct v4l2_rect r; - int field; + if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) + return -EINVAL; + winfmt->chromakey = itv->osd_chroma_key; + winfmt->global_alpha = itv->osd_global_alpha; + winfmt->field = V4L2_FIELD_INTERLACED; + winfmt->clips = NULL; + winfmt->clipcount = 0; + winfmt->bitmap = NULL; + winfmt->w.top = winfmt->w.left = 0; + winfmt->w.width = itv->osd_rect.width; + winfmt->w.height = itv->osd_rect.height; + return 0; +} - if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) - return -EINVAL; - field = fmt->fmt.pix.field; - r.top = 0; - r.left = 0; - r.width = fmt->fmt.pix.width; - r.height = fmt->fmt.pix.height; - ivtv_get_fmt(itv, streamtype, fmt); - fmt->fmt.pix.width = r.width; - fmt->fmt.pix.height = r.height; - if (streamtype == IVTV_DEC_STREAM_TYPE_YUV) { - fmt->fmt.pix.field = field; - if (fmt->fmt.pix.width < 2) - fmt->fmt.pix.width = 2; - if (fmt->fmt.pix.width > 720) - fmt->fmt.pix.width = 720; - if (fmt->fmt.pix.height < 2) - fmt->fmt.pix.height = 2; - if (fmt->fmt.pix.height > 576) - fmt->fmt.pix.height = 576; - } - if (set_fmt && streamtype == IVTV_DEC_STREAM_TYPE_YUV) { - /* Return now if we already have some frame data */ - if (yi->stream_size) - return -EBUSY; +static int ivtv_try_fmt_sliced_vbi_out(struct file *file, void *fh, struct v4l2_format *fmt) +{ + return ivtv_g_fmt_sliced_vbi_out(file, fh, fmt); +} - yi->v4l2_src_w = r.width; - yi->v4l2_src_h = r.height; +static int ivtv_try_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *fmt) +{ + struct ivtv_open_id *id = fh; + struct ivtv *itv = id->itv; + int w = fmt->fmt.pix.width; + int h = fmt->fmt.pix.height; + + w = min(w, 720); + w = max(w, 1); + h = min(h, itv->is_50hz ? 576 : 480); + h = max(h, 2); + ivtv_g_fmt_vid_cap(file, fh, fmt); + fmt->fmt.pix.width = w; + fmt->fmt.pix.height = h; + return 0; +} - switch (field) { - case V4L2_FIELD_NONE: - yi->lace_mode = IVTV_YUV_MODE_PROGRESSIVE; - break; - case V4L2_FIELD_ANY: - yi->lace_mode = IVTV_YUV_MODE_AUTO; - break; - case V4L2_FIELD_INTERLACED_BT: - yi->lace_mode = - IVTV_YUV_MODE_INTERLACED|IVTV_YUV_SYNC_ODD; - break; - case V4L2_FIELD_INTERLACED_TB: - default: - yi->lace_mode = IVTV_YUV_MODE_INTERLACED; - break; - } - yi->lace_sync_field = (yi->lace_mode & IVTV_YUV_SYNC_MASK) == IVTV_YUV_SYNC_EVEN ? 0 : 1; +static int ivtv_try_fmt_vbi_cap(struct file *file, void *fh, struct v4l2_format *fmt) +{ + return ivtv_g_fmt_vbi_cap(file, fh, fmt); +} - if (test_bit(IVTV_F_I_DEC_YUV, &itv->i_flags)) - itv->dma_data_req_size = - 1080 * ((yi->v4l2_src_h + 31) & ~31); +static int ivtv_try_fmt_sliced_vbi_cap(struct file *file, void *fh, struct v4l2_format *fmt) +{ + struct v4l2_sliced_vbi_format *vbifmt = &fmt->fmt.sliced; + struct ivtv_open_id *id = fh; + struct ivtv *itv = id->itv; - /* Force update of yuv registers */ - yi->yuv_forced_update = 1; - return 0; - } - return 0; - } + if (id->type == IVTV_DEC_STREAM_TYPE_VBI) + return ivtv_g_fmt_sliced_vbi_cap(file, fh, fmt); - if (fmt->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY) { - if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) - return -EINVAL; - if (set_fmt) { - itv->osd_chroma_key = fmt->fmt.win.chromakey; - itv->osd_global_alpha = fmt->fmt.win.global_alpha; - ivtv_set_osd_alpha(itv); - } - return 0; - } + /* set sliced VBI capture format */ + vbifmt->io_size = sizeof(struct v4l2_sliced_vbi_data) * 36; + vbifmt->reserved[0] = 0; + vbifmt->reserved[1] = 0; - /* set window size */ - if (fmt->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { - struct cx2341x_mpeg_params *p = &itv->params; - int w = fmt->fmt.pix.width; - int h = fmt->fmt.pix.height; - - if (w > 720) w = 720; - else if (w < 1) w = 1; - if (h > (itv->is_50hz ? 576 : 480)) h = (itv->is_50hz ? 576 : 480); - else if (h < 2) h = 2; - ivtv_get_fmt(itv, streamtype, fmt); - fmt->fmt.pix.width = w; - fmt->fmt.pix.height = h; - - if (!set_fmt || (p->width == w && p->height == h)) - return 0; - if (atomic_read(&itv->capturing) > 0) - return -EBUSY; + if (vbifmt->service_set) + ivtv_expand_service_set(vbifmt, itv->is_50hz); + check_service_set(vbifmt, itv->is_50hz); + vbifmt->service_set = ivtv_get_service_set(vbifmt); + return 0; +} - p->width = w; - p->height = h; - if (w != 720 || h != (itv->is_50hz ? 576 : 480)) - p->video_temporal_filter = 0; - else - p->video_temporal_filter = 8; - if (p->video_encoding == V4L2_MPEG_VIDEO_ENCODING_MPEG_1) - fmt->fmt.pix.width /= 2; - itv->video_dec_func(itv, VIDIOC_S_FMT, fmt); - return ivtv_get_fmt(itv, streamtype, fmt); - } +static int ivtv_try_fmt_vid_out(struct file *file, void *fh, struct v4l2_format *fmt) +{ + struct ivtv_open_id *id = fh; + s32 w, h; + int field; + int ret; - /* set raw VBI format */ - if (fmt->type == V4L2_BUF_TYPE_VBI_CAPTURE) { - if (set_fmt && atomic_read(&itv->capturing) > 0) { - return -EBUSY; - } - if (set_fmt) { - itv->vbi.sliced_in->service_set = 0; - itv->video_dec_func(itv, VIDIOC_S_FMT, &itv->vbi.in); - } - return ivtv_get_fmt(itv, streamtype, fmt); - } + w = fmt->fmt.pix.width; + h = fmt->fmt.pix.height; + field = fmt->fmt.pix.field; + ret = ivtv_g_fmt_vid_out(file, fh, fmt); + fmt->fmt.pix.width = w; + fmt->fmt.pix.height = h; + if (!ret && id->type == IVTV_DEC_STREAM_TYPE_YUV) { + fmt->fmt.pix.field = field; + if (fmt->fmt.pix.width < 2) + fmt->fmt.pix.width = 2; + if (fmt->fmt.pix.width > 720) + fmt->fmt.pix.width = 720; + if (fmt->fmt.pix.height < 2) + fmt->fmt.pix.height = 2; + if (fmt->fmt.pix.height > 576) + fmt->fmt.pix.height = 576; + } + return ret; +} - /* set sliced VBI output - In principle the user could request that only certain - VBI types are output and that the others are ignored. - I.e., suppress CC in the even fields or only output - WSS and no VPS. Currently though there is no choice. */ - if (fmt->type == V4L2_BUF_TYPE_SLICED_VBI_OUTPUT) - return ivtv_get_fmt(itv, streamtype, fmt); +static int ivtv_try_fmt_vid_out_overlay(struct file *file, void *fh, struct v4l2_format *fmt) +{ + struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv; + u32 chromakey = fmt->fmt.win.chromakey; + u8 global_alpha = fmt->fmt.win.global_alpha; - /* any else but sliced VBI capture is an error */ - if (fmt->type != V4L2_BUF_TYPE_SLICED_VBI_CAPTURE) + if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) return -EINVAL; + ivtv_g_fmt_vid_out_overlay(file, fh, fmt); + fmt->fmt.win.chromakey = chromakey; + fmt->fmt.win.global_alpha = global_alpha; + return 0; +} - if (streamtype == IVTV_DEC_STREAM_TYPE_VBI) - return ivtv_get_fmt(itv, streamtype, fmt); +static int ivtv_s_fmt_sliced_vbi_out(struct file *file, void *fh, struct v4l2_format *fmt) +{ + return ivtv_g_fmt_sliced_vbi_out(file, fh, fmt); +} - /* set sliced VBI capture format */ - vbifmt->io_size = sizeof(struct v4l2_sliced_vbi_data) * 36; - memset(vbifmt->reserved, 0, sizeof(vbifmt->reserved)); +static int ivtv_s_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *fmt) +{ + struct ivtv_open_id *id = fh; + struct ivtv *itv = id->itv; + struct cx2341x_mpeg_params *p = &itv->params; + int w = fmt->fmt.pix.width; + int h = fmt->fmt.pix.height; + int ret = ivtv_try_fmt_vid_cap(file, fh, fmt); - if (vbifmt->service_set) - ivtv_expand_service_set(vbifmt, itv->is_50hz); - set = check_service_set(vbifmt, itv->is_50hz); - vbifmt->service_set = ivtv_get_service_set(vbifmt); + if (ret) + return ret; - if (!set_fmt) + if (p->width == w && p->height == h) return 0; - if (set == 0) + + if (atomic_read(&itv->capturing) > 0) + return -EBUSY; + + p->width = w; + p->height = h; + if (p->video_encoding == V4L2_MPEG_VIDEO_ENCODING_MPEG_1) + fmt->fmt.pix.width /= 2; + itv->video_dec_func(itv, VIDIOC_S_FMT, fmt); + return ivtv_g_fmt_vid_cap(file, fh, fmt); +} + +static int ivtv_s_fmt_vbi_cap(struct file *file, void *fh, struct v4l2_format *fmt) +{ + struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv; + + itv->vbi.sliced_in->service_set = 0; + itv->video_dec_func(itv, VIDIOC_S_FMT, &itv->vbi.in); + return ivtv_g_fmt_vbi_cap(file, fh, fmt); +} + +static int ivtv_s_fmt_sliced_vbi_cap(struct file *file, void *fh, struct v4l2_format *fmt) +{ + struct v4l2_sliced_vbi_format *vbifmt = &fmt->fmt.sliced; + struct ivtv_open_id *id = fh; + struct ivtv *itv = id->itv; + int ret = ivtv_try_fmt_sliced_vbi_cap(file, fh, fmt); + + if (ret || id->type == IVTV_DEC_STREAM_TYPE_VBI) + return ret; + + if (check_service_set(vbifmt, itv->is_50hz) == 0) return -EINVAL; - if (atomic_read(&itv->capturing) > 0) { + if (atomic_read(&itv->capturing) > 0) return -EBUSY; - } itv->video_dec_func(itv, VIDIOC_S_FMT, fmt); memcpy(itv->vbi.sliced_in, vbifmt, sizeof(*itv->vbi.sliced_in)); return 0; } -static int ivtv_debug_ioctls(struct file *filp, unsigned int cmd, void *arg) +static int ivtv_s_fmt_vid_out(struct file *file, void *fh, struct v4l2_format *fmt) { - struct ivtv_open_id *id = (struct ivtv_open_id *)filp->private_data; + struct ivtv_open_id *id = fh; struct ivtv *itv = id->itv; - struct v4l2_register *reg = arg; + struct yuv_playback_info *yi = &itv->yuv_info; + int ret = ivtv_try_fmt_vid_out(file, fh, fmt); - switch (cmd) { - /* ioctls to allow direct access to the encoder registers for testing */ - case VIDIOC_DBG_G_REGISTER: - if (v4l2_chip_match_host(reg->match_type, reg->match_chip)) - return ivtv_itvc(itv, cmd, arg); - if (reg->match_type == V4L2_CHIP_MATCH_I2C_DRIVER) - return ivtv_i2c_id(itv, reg->match_chip, cmd, arg); - return ivtv_call_i2c_client(itv, reg->match_chip, cmd, arg); - - case VIDIOC_DBG_S_REGISTER: - if (v4l2_chip_match_host(reg->match_type, reg->match_chip)) - return ivtv_itvc(itv, cmd, arg); - if (reg->match_type == V4L2_CHIP_MATCH_I2C_DRIVER) - return ivtv_i2c_id(itv, reg->match_chip, cmd, arg); - return ivtv_call_i2c_client(itv, reg->match_chip, cmd, arg); - - case VIDIOC_G_CHIP_IDENT: { - struct v4l2_chip_ident *chip = arg; - - chip->ident = V4L2_IDENT_NONE; - chip->revision = 0; - if (reg->match_type == V4L2_CHIP_MATCH_HOST) { - if (v4l2_chip_match_host(reg->match_type, reg->match_chip)) - chip->ident = itv->has_cx23415 ? V4L2_IDENT_CX23415 : V4L2_IDENT_CX23416; - return 0; - } - if (reg->match_type == V4L2_CHIP_MATCH_I2C_DRIVER) - return ivtv_i2c_id(itv, reg->match_chip, cmd, arg); - if (reg->match_type == V4L2_CHIP_MATCH_I2C_ADDR) - return ivtv_call_i2c_client(itv, reg->match_chip, cmd, arg); - return -EINVAL; - } + if (ret) + return ret; - case VIDIOC_INT_S_AUDIO_ROUTING: { - struct v4l2_routing *route = arg; + if (id->type != IVTV_DEC_STREAM_TYPE_YUV) + return 0; - ivtv_i2c_hw(itv, itv->card->hw_audio, VIDIOC_INT_S_AUDIO_ROUTING, route); - break; - } + /* Return now if we already have some frame data */ + if (yi->stream_size) + return -EBUSY; - case VIDIOC_INT_RESET: { - u32 val = *(u32 *)arg; + yi->v4l2_src_w = fmt->fmt.pix.width; + yi->v4l2_src_h = fmt->fmt.pix.height; - if ((val == 0 && itv->options.newi2c) || (val & 0x01)) { - ivtv_reset_ir_gpio(itv); - } - if (val & 0x02) { - itv->video_dec_func(itv, cmd, NULL); - } + switch (fmt->fmt.pix.field) { + case V4L2_FIELD_NONE: + yi->lace_mode = IVTV_YUV_MODE_PROGRESSIVE; break; - } - + case V4L2_FIELD_ANY: + yi->lace_mode = IVTV_YUV_MODE_AUTO; + break; + case V4L2_FIELD_INTERLACED_BT: + yi->lace_mode = + IVTV_YUV_MODE_INTERLACED|IVTV_YUV_SYNC_ODD; + break; + case V4L2_FIELD_INTERLACED_TB: default: - return -EINVAL; + yi->lace_mode = IVTV_YUV_MODE_INTERLACED; + break; } + yi->lace_sync_field = (yi->lace_mode & IVTV_YUV_SYNC_MASK) == IVTV_YUV_SYNC_EVEN ? 0 : 1; + + if (test_bit(IVTV_F_I_DEC_YUV, &itv->i_flags)) + itv->dma_data_req_size = + 1080 * ((yi->v4l2_src_h + 31) & ~31); + + /* Force update of yuv registers */ + yi->yuv_forced_update = 1; return 0; } -int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void *arg) +static int ivtv_s_fmt_vid_out_overlay(struct file *file, void *fh, struct v4l2_format *fmt) { - struct ivtv_open_id *id = NULL; - struct yuv_playback_info *yi = &itv->yuv_info; - u32 data[CX2341X_MBOX_MAX_DATA]; - int streamtype = 0; + struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv; + int ret = ivtv_try_fmt_vid_out_overlay(file, fh, fmt); - if (filp) { - id = (struct ivtv_open_id *)filp->private_data; - streamtype = id->type; + if (ret == 0) { + itv->osd_chroma_key = fmt->fmt.win.chromakey; + itv->osd_global_alpha = fmt->fmt.win.global_alpha; + ivtv_set_osd_alpha(itv); } + return ret; +} - switch (cmd) { - case VIDIOC_G_PRIORITY: - { - enum v4l2_priority *p = arg; +static int ivtv_g_chip_ident(struct file *file, void *fh, struct v4l2_chip_ident *chip) +{ + struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv; - *p = v4l2_prio_max(&itv->prio); - break; + chip->ident = V4L2_IDENT_NONE; + chip->revision = 0; + if (chip->match_type == V4L2_CHIP_MATCH_HOST) { + if (v4l2_chip_match_host(chip->match_type, chip->match_chip)) + chip->ident = itv->has_cx23415 ? V4L2_IDENT_CX23415 : V4L2_IDENT_CX23416; + return 0; } + if (chip->match_type == V4L2_CHIP_MATCH_I2C_DRIVER) + return ivtv_i2c_id(itv, chip->match_chip, VIDIOC_G_CHIP_IDENT, chip); + if (chip->match_type == V4L2_CHIP_MATCH_I2C_ADDR) + return ivtv_call_i2c_client(itv, chip->match_chip, VIDIOC_G_CHIP_IDENT, chip); + return -EINVAL; +} - case VIDIOC_S_PRIORITY: - { - enum v4l2_priority *prio = arg; +#ifdef CONFIG_VIDEO_ADV_DEBUG +static int ivtv_itvc(struct ivtv *itv, unsigned int cmd, void *arg) +{ + struct v4l2_register *regs = arg; + unsigned long flags; + volatile u8 __iomem *reg_start; - return v4l2_prio_change(&itv->prio, &id->prio, *prio); - } + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + if (regs->reg >= IVTV_REG_OFFSET && regs->reg < IVTV_REG_OFFSET + IVTV_REG_SIZE) + reg_start = itv->reg_mem - IVTV_REG_OFFSET; + else if (itv->has_cx23415 && regs->reg >= IVTV_DECODER_OFFSET && + regs->reg < IVTV_DECODER_OFFSET + IVTV_DECODER_SIZE) + reg_start = itv->dec_mem - IVTV_DECODER_OFFSET; + else if (regs->reg >= 0 && regs->reg < IVTV_ENCODER_SIZE) + reg_start = itv->enc_mem; + else + return -EINVAL; - case VIDIOC_QUERYCAP:{ - struct v4l2_capability *vcap = arg; + spin_lock_irqsave(&ivtv_cards_lock, flags); + if (cmd == VIDIOC_DBG_G_REGISTER) + regs->val = readl(regs->reg + reg_start); + else + writel(regs->val, regs->reg + reg_start); + spin_unlock_irqrestore(&ivtv_cards_lock, flags); + return 0; +} - memset(vcap, 0, sizeof(*vcap)); - strlcpy(vcap->driver, IVTV_DRIVER_NAME, sizeof(vcap->driver)); - strlcpy(vcap->card, itv->card_name, sizeof(vcap->card)); - strlcpy(vcap->bus_info, pci_name(itv->dev), sizeof(vcap->bus_info)); - vcap->version = IVTV_DRIVER_VERSION; /* version */ - vcap->capabilities = itv->v4l2_cap; /* capabilities */ +static int ivtv_g_register(struct file *file, void *fh, struct v4l2_register *reg) +{ + struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv; - /* reserved.. must set to 0! */ - vcap->reserved[0] = vcap->reserved[1] = - vcap->reserved[2] = vcap->reserved[3] = 0; - break; - } + if (v4l2_chip_match_host(reg->match_type, reg->match_chip)) + return ivtv_itvc(itv, VIDIOC_DBG_G_REGISTER, reg); + if (reg->match_type == V4L2_CHIP_MATCH_I2C_DRIVER) + return ivtv_i2c_id(itv, reg->match_chip, VIDIOC_DBG_G_REGISTER, reg); + return ivtv_call_i2c_client(itv, reg->match_chip, VIDIOC_DBG_G_REGISTER, reg); +} - case VIDIOC_ENUMAUDIO:{ - struct v4l2_audio *vin = arg; +static int ivtv_s_register(struct file *file, void *fh, struct v4l2_register *reg) +{ + struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv; - return ivtv_get_audio_input(itv, vin->index, vin); - } + if (v4l2_chip_match_host(reg->match_type, reg->match_chip)) + return ivtv_itvc(itv, VIDIOC_DBG_S_REGISTER, reg); + if (reg->match_type == V4L2_CHIP_MATCH_I2C_DRIVER) + return ivtv_i2c_id(itv, reg->match_chip, VIDIOC_DBG_S_REGISTER, reg); + return ivtv_call_i2c_client(itv, reg->match_chip, VIDIOC_DBG_S_REGISTER, reg); +} +#endif - case VIDIOC_G_AUDIO:{ - struct v4l2_audio *vin = arg; +static int ivtv_g_priority(struct file *file, void *fh, enum v4l2_priority *p) +{ + struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv; - vin->index = itv->audio_input; - return ivtv_get_audio_input(itv, vin->index, vin); - } + *p = v4l2_prio_max(&itv->prio); - case VIDIOC_S_AUDIO:{ - struct v4l2_audio *vout = arg; + return 0; +} - if (vout->index >= itv->nof_audio_inputs) - return -EINVAL; - itv->audio_input = vout->index; - ivtv_audio_set_io(itv); - break; - } +static int ivtv_s_priority(struct file *file, void *fh, enum v4l2_priority prio) +{ + struct ivtv_open_id *id = fh; + struct ivtv *itv = id->itv; - case VIDIOC_ENUMAUDOUT:{ - struct v4l2_audioout *vin = arg; + return v4l2_prio_change(&itv->prio, &id->prio, prio); +} - /* set it to defaults from our table */ - return ivtv_get_audio_output(itv, vin->index, vin); - } +static int ivtv_querycap(struct file *file, void *fh, struct v4l2_capability *vcap) +{ + struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv; - case VIDIOC_G_AUDOUT:{ - struct v4l2_audioout *vin = arg; + strlcpy(vcap->driver, IVTV_DRIVER_NAME, sizeof(vcap->driver)); + strlcpy(vcap->card, itv->card_name, sizeof(vcap->card)); + strlcpy(vcap->bus_info, pci_name(itv->dev), sizeof(vcap->bus_info)); + vcap->version = IVTV_DRIVER_VERSION; /* version */ + vcap->capabilities = itv->v4l2_cap; /* capabilities */ + return 0; +} - vin->index = 0; - return ivtv_get_audio_output(itv, vin->index, vin); - } +static int ivtv_enumaudio(struct file *file, void *fh, struct v4l2_audio *vin) +{ + struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv; - case VIDIOC_S_AUDOUT:{ - struct v4l2_audioout *vout = arg; + return ivtv_get_audio_input(itv, vin->index, vin); +} - return ivtv_get_audio_output(itv, vout->index, vout); - } +static int ivtv_g_audio(struct file *file, void *fh, struct v4l2_audio *vin) +{ + struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv; - case VIDIOC_ENUMINPUT:{ - struct v4l2_input *vin = arg; + vin->index = itv->audio_input; + return ivtv_get_audio_input(itv, vin->index, vin); +} - /* set it to defaults from our table */ - return ivtv_get_input(itv, vin->index, vin); - } +static int ivtv_s_audio(struct file *file, void *fh, struct v4l2_audio *vout) +{ + struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv; - case VIDIOC_ENUMOUTPUT:{ - struct v4l2_output *vout = arg; + if (vout->index >= itv->nof_audio_inputs) + return -EINVAL; - return ivtv_get_output(itv, vout->index, vout); - } + itv->audio_input = vout->index; + ivtv_audio_set_io(itv); - case VIDIOC_TRY_FMT: - case VIDIOC_S_FMT: { - struct v4l2_format *fmt = arg; + return 0; +} - return ivtv_try_or_set_fmt(itv, id->type, fmt, cmd == VIDIOC_S_FMT); - } +static int ivtv_enumaudout(struct file *file, void *fh, struct v4l2_audioout *vin) +{ + struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv; - case VIDIOC_G_FMT: { - struct v4l2_format *fmt = arg; - int type = fmt->type; + /* set it to defaults from our table */ + return ivtv_get_audio_output(itv, vin->index, vin); +} - memset(fmt, 0, sizeof(*fmt)); - fmt->type = type; - return ivtv_get_fmt(itv, id->type, fmt); - } +static int ivtv_g_audout(struct file *file, void *fh, struct v4l2_audioout *vin) +{ + struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv; - case VIDIOC_CROPCAP: { - struct v4l2_cropcap *cropcap = arg; + vin->index = 0; + return ivtv_get_audio_output(itv, vin->index, vin); +} - if (cropcap->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) - return -EINVAL; - cropcap->bounds.top = cropcap->bounds.left = 0; - cropcap->bounds.width = 720; - if (cropcap->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { - cropcap->bounds.height = itv->is_50hz ? 576 : 480; - cropcap->pixelaspect.numerator = itv->is_50hz ? 59 : 10; - cropcap->pixelaspect.denominator = itv->is_50hz ? 54 : 11; - } else if (streamtype == IVTV_DEC_STREAM_TYPE_YUV) { - if (yi->track_osd) { - cropcap->bounds.width = yi->osd_full_w; - cropcap->bounds.height = yi->osd_full_h; - } else { - cropcap->bounds.width = 720; - cropcap->bounds.height = - itv->is_out_50hz ? 576 : 480; - } - cropcap->pixelaspect.numerator = itv->is_out_50hz ? 59 : 10; - cropcap->pixelaspect.denominator = itv->is_out_50hz ? 54 : 11; +static int ivtv_s_audout(struct file *file, void *fh, struct v4l2_audioout *vout) +{ + struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv; + + return ivtv_get_audio_output(itv, vout->index, vout); +} + +static int ivtv_enum_input(struct file *file, void *fh, struct v4l2_input *vin) +{ + struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv; + + /* set it to defaults from our table */ + return ivtv_get_input(itv, vin->index, vin); +} + +static int ivtv_enum_output(struct file *file, void *fh, struct v4l2_output *vout) +{ + struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv; + + return ivtv_get_output(itv, vout->index, vout); +} + +static int ivtv_cropcap(struct file *file, void *fh, struct v4l2_cropcap *cropcap) +{ + struct ivtv_open_id *id = fh; + struct ivtv *itv = id->itv; + struct yuv_playback_info *yi = &itv->yuv_info; + int streamtype; + + streamtype = id->type; + + if (cropcap->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) + return -EINVAL; + cropcap->bounds.top = cropcap->bounds.left = 0; + cropcap->bounds.width = 720; + if (cropcap->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { + cropcap->bounds.height = itv->is_50hz ? 576 : 480; + cropcap->pixelaspect.numerator = itv->is_50hz ? 59 : 10; + cropcap->pixelaspect.denominator = itv->is_50hz ? 54 : 11; + } else if (streamtype == IVTV_DEC_STREAM_TYPE_YUV) { + if (yi->track_osd) { + cropcap->bounds.width = yi->osd_full_w; + cropcap->bounds.height = yi->osd_full_h; } else { - cropcap->bounds.height = itv->is_out_50hz ? 576 : 480; - cropcap->pixelaspect.numerator = itv->is_out_50hz ? 59 : 10; - cropcap->pixelaspect.denominator = itv->is_out_50hz ? 54 : 11; + cropcap->bounds.width = 720; + cropcap->bounds.height = + itv->is_out_50hz ? 576 : 480; } - cropcap->defrect = cropcap->bounds; - return 0; + cropcap->pixelaspect.numerator = itv->is_out_50hz ? 59 : 10; + cropcap->pixelaspect.denominator = itv->is_out_50hz ? 54 : 11; + } else { + cropcap->bounds.height = itv->is_out_50hz ? 576 : 480; + cropcap->pixelaspect.numerator = itv->is_out_50hz ? 59 : 10; + cropcap->pixelaspect.denominator = itv->is_out_50hz ? 54 : 11; } + cropcap->defrect = cropcap->bounds; + return 0; +} + +static int ivtv_s_crop(struct file *file, void *fh, struct v4l2_crop *crop) +{ + struct ivtv_open_id *id = fh; + struct ivtv *itv = id->itv; + struct yuv_playback_info *yi = &itv->yuv_info; + int streamtype; - case VIDIOC_S_CROP: { - struct v4l2_crop *crop = arg; + streamtype = id->type; - if (crop->type == V4L2_BUF_TYPE_VIDEO_OUTPUT && - (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) { - if (streamtype == IVTV_DEC_STREAM_TYPE_YUV) { - yi->main_rect = crop->c; + if (ivtv_debug & IVTV_DBGFLG_IOCTL) { + printk(KERN_INFO "ivtv%d ioctl: ", itv->num); + /* Should be replaced */ + /* v4l_printk_ioctl(VIDIOC_S_CROP); */ + } + + if (crop->type == V4L2_BUF_TYPE_VIDEO_OUTPUT && + (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) { + if (streamtype == IVTV_DEC_STREAM_TYPE_YUV) { + yi->main_rect = crop->c; + return 0; + } else { + if (!ivtv_vapi(itv, CX2341X_OSD_SET_FRAMEBUFFER_WINDOW, 4, + crop->c.width, crop->c.height, crop->c.left, crop->c.top)) { + itv->main_rect = crop->c; return 0; - } else { - if (!ivtv_vapi(itv, CX2341X_OSD_SET_FRAMEBUFFER_WINDOW, 4, - crop->c.width, crop->c.height, crop->c.left, crop->c.top)) { - itv->main_rect = crop->c; - return 0; - } } - return -EINVAL; } return -EINVAL; } + return -EINVAL; +} - case VIDIOC_G_CROP: { - struct v4l2_crop *crop = arg; +static int ivtv_g_crop(struct file *file, void *fh, struct v4l2_crop *crop) +{ + struct ivtv_open_id *id = fh; + struct ivtv *itv = id->itv; + struct yuv_playback_info *yi = &itv->yuv_info; + int streamtype; - if (crop->type == V4L2_BUF_TYPE_VIDEO_OUTPUT && - (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) { - if (streamtype == IVTV_DEC_STREAM_TYPE_YUV) - crop->c = yi->main_rect; - else - crop->c = itv->main_rect; - return 0; + streamtype = id->type; + + if (crop->type == V4L2_BUF_TYPE_VIDEO_OUTPUT && + (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) { + if (streamtype == IVTV_DEC_STREAM_TYPE_YUV) + crop->c = yi->main_rect; + else + crop->c = itv->main_rect; + return 0; + } + return -EINVAL; +} + +static int ivtv_enum_fmt_vid_cap(struct file *file, void *fh, struct v4l2_fmtdesc *fmt) +{ + static struct v4l2_fmtdesc formats[] = { + { 0, 0, 0, + "HM12 (YUV 4:2:0)", V4L2_PIX_FMT_HM12, + { 0, 0, 0, 0 } + }, + { 1, 0, V4L2_FMT_FLAG_COMPRESSED, + "MPEG", V4L2_PIX_FMT_MPEG, + { 0, 0, 0, 0 } } + }; + enum v4l2_buf_type type = fmt->type; + + if (fmt->index > 1) return -EINVAL; - } - case VIDIOC_ENUM_FMT: { - static struct v4l2_fmtdesc formats[] = { - { 0, 0, 0, - "HM12 (YUV 4:2:0)", V4L2_PIX_FMT_HM12, - { 0, 0, 0, 0 } - }, - { 1, 0, V4L2_FMT_FLAG_COMPRESSED, - "MPEG", V4L2_PIX_FMT_MPEG, - { 0, 0, 0, 0 } - } - }; - struct v4l2_fmtdesc *fmt = arg; - enum v4l2_buf_type type = fmt->type; + *fmt = formats[fmt->index]; + fmt->type = type; + return 0; +} - switch (type) { - case V4L2_BUF_TYPE_VIDEO_CAPTURE: - break; - case V4L2_BUF_TYPE_VIDEO_OUTPUT: - if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) - return -EINVAL; - break; - default: - return -EINVAL; +static int ivtv_enum_fmt_vid_out(struct file *file, void *fh, struct v4l2_fmtdesc *fmt) +{ + struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv; + + static struct v4l2_fmtdesc formats[] = { + { 0, 0, 0, + "HM12 (YUV 4:2:0)", V4L2_PIX_FMT_HM12, + { 0, 0, 0, 0 } + }, + { 1, 0, V4L2_FMT_FLAG_COMPRESSED, + "MPEG", V4L2_PIX_FMT_MPEG, + { 0, 0, 0, 0 } } - if (fmt->index > 1) - return -EINVAL; - *fmt = formats[fmt->index]; - fmt->type = type; + }; + enum v4l2_buf_type type = fmt->type; + + if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) + return -EINVAL; + + if (fmt->index > 1) + return -EINVAL; + + *fmt = formats[fmt->index]; + fmt->type = type; + + return 0; +} + +static int ivtv_g_input(struct file *file, void *fh, unsigned int *i) +{ + struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv; + + *i = itv->active_input; + + return 0; +} + +int ivtv_s_input(struct file *file, void *fh, unsigned int inp) +{ + struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv; + + if (inp < 0 || inp >= itv->nof_inputs) + return -EINVAL; + + if (inp == itv->active_input) { + IVTV_DEBUG_INFO("Input unchanged\n"); return 0; } - case VIDIOC_G_INPUT:{ - *(int *)arg = itv->active_input; - break; + if (atomic_read(&itv->capturing) > 0) { + return -EBUSY; } - case VIDIOC_S_INPUT:{ - int inp = *(int *)arg; + IVTV_DEBUG_INFO("Changing input from %d to %d\n", + itv->active_input, inp); - if (inp < 0 || inp >= itv->nof_inputs) - return -EINVAL; + itv->active_input = inp; + /* Set the audio input to whatever is appropriate for the + input type. */ + itv->audio_input = itv->card->video_inputs[inp].audio_index; - if (inp == itv->active_input) { - IVTV_DEBUG_INFO("Input unchanged\n"); - break; - } - if (atomic_read(&itv->capturing) > 0) { - return -EBUSY; - } - IVTV_DEBUG_INFO("Changing input from %d to %d\n", - itv->active_input, inp); + /* prevent others from messing with the streams until + we're finished changing inputs. */ + ivtv_mute(itv); + ivtv_video_set_io(itv); + ivtv_audio_set_io(itv); + ivtv_unmute(itv); - itv->active_input = inp; - /* Set the audio input to whatever is appropriate for the - input type. */ - itv->audio_input = itv->card->video_inputs[inp].audio_index; + return 0; +} - /* prevent others from messing with the streams until - we're finished changing inputs. */ - ivtv_mute(itv); - ivtv_video_set_io(itv); - ivtv_audio_set_io(itv); - ivtv_unmute(itv); - break; - } +static int ivtv_g_output(struct file *file, void *fh, unsigned int *i) +{ + struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv; - case VIDIOC_G_OUTPUT:{ - if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) - return -EINVAL; - *(int *)arg = itv->active_output; - break; - } + if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) + return -EINVAL; - case VIDIOC_S_OUTPUT:{ - int outp = *(int *)arg; - struct v4l2_routing route; + *i = itv->active_output; - if (outp >= itv->card->nof_outputs) - return -EINVAL; + return 0; +} - if (outp == itv->active_output) { - IVTV_DEBUG_INFO("Output unchanged\n"); - break; - } - IVTV_DEBUG_INFO("Changing output from %d to %d\n", - itv->active_output, outp); +static int ivtv_s_output(struct file *file, void *fh, unsigned int outp) +{ + struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv; + struct v4l2_routing route; - itv->active_output = outp; - route.input = SAA7127_INPUT_TYPE_NORMAL; - route.output = itv->card->video_outputs[outp].video_output; - ivtv_saa7127(itv, VIDIOC_INT_S_VIDEO_ROUTING, &route); - break; + if (outp >= itv->card->nof_outputs) + return -EINVAL; + + if (outp == itv->active_output) { + IVTV_DEBUG_INFO("Output unchanged\n"); + return 0; } + IVTV_DEBUG_INFO("Changing output from %d to %d\n", + itv->active_output, outp); - case VIDIOC_G_FREQUENCY:{ - struct v4l2_frequency *vf = arg; + itv->active_output = outp; + route.input = SAA7127_INPUT_TYPE_NORMAL; + route.output = itv->card->video_outputs[outp].video_output; + ivtv_saa7127(itv, VIDIOC_INT_S_VIDEO_ROUTING, &route); - if (vf->tuner != 0) - return -EINVAL; - ivtv_call_i2c_clients(itv, cmd, arg); - break; - } + return 0; +} - case VIDIOC_S_FREQUENCY:{ - struct v4l2_frequency vf = *(struct v4l2_frequency *)arg; +static int ivtv_g_frequency(struct file *file, void *fh, struct v4l2_frequency *vf) +{ + struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv; - if (vf.tuner != 0) - return -EINVAL; + if (vf->tuner != 0) + return -EINVAL; - ivtv_mute(itv); - IVTV_DEBUG_INFO("v4l2 ioctl: set frequency %d\n", vf.frequency); - ivtv_call_i2c_clients(itv, cmd, &vf); - ivtv_unmute(itv); - break; - } + ivtv_call_i2c_clients(itv, VIDIOC_G_FREQUENCY, vf); + return 0; +} - case VIDIOC_ENUMSTD:{ - struct v4l2_standard *vs = arg; - int idx = vs->index; +int ivtv_s_frequency(struct file *file, void *fh, struct v4l2_frequency *vf) +{ + struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv; - if (idx < 0 || idx >= ARRAY_SIZE(enum_stds)) - return -EINVAL; + if (vf->tuner != 0) + return -EINVAL; - *vs = (enum_stds[idx].std & V4L2_STD_525_60) ? - ivtv_std_60hz : ivtv_std_50hz; - vs->index = idx; - vs->id = enum_stds[idx].std; - strlcpy(vs->name, enum_stds[idx].name, sizeof(vs->name)); - break; - } + ivtv_mute(itv); + IVTV_DEBUG_INFO("v4l2 ioctl: set frequency %d\n", vf->frequency); + ivtv_call_i2c_clients(itv, VIDIOC_S_FREQUENCY, vf); + ivtv_unmute(itv); + return 0; +} - case VIDIOC_G_STD:{ - *(v4l2_std_id *) arg = itv->std; - break; - } +static int ivtv_g_std(struct file *file, void *fh, v4l2_std_id *std) +{ + struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv; - case VIDIOC_S_STD: { - v4l2_std_id std = *(v4l2_std_id *) arg; + *std = itv->std; + return 0; +} - if ((std & V4L2_STD_ALL) == 0) - return -EINVAL; +int ivtv_s_std(struct file *file, void *fh, v4l2_std_id *std) +{ + struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv; + struct yuv_playback_info *yi = &itv->yuv_info; - if (std == itv->std) - break; + if ((*std & V4L2_STD_ALL) == 0) + return -EINVAL; - if (test_bit(IVTV_F_I_RADIO_USER, &itv->i_flags) || - atomic_read(&itv->capturing) > 0 || - atomic_read(&itv->decoding) > 0) { - /* Switching standard would turn off the radio or mess - with already running streams, prevent that by - returning EBUSY. */ - return -EBUSY; - } + if (*std == itv->std) + return 0; - itv->std = std; - itv->is_60hz = (std & V4L2_STD_525_60) ? 1 : 0; - itv->params.is_50hz = itv->is_50hz = !itv->is_60hz; - itv->params.width = 720; - itv->params.height = itv->is_50hz ? 576 : 480; - itv->vbi.count = itv->is_50hz ? 18 : 12; - itv->vbi.start[0] = itv->is_50hz ? 6 : 10; - itv->vbi.start[1] = itv->is_50hz ? 318 : 273; - if (itv->hw_flags & IVTV_HW_CX25840) { - itv->vbi.sliced_decoder_line_size = itv->is_60hz ? 272 : 284; - } - IVTV_DEBUG_INFO("Switching standard to %llx.\n", (unsigned long long)itv->std); - - /* Tuner */ - ivtv_call_i2c_clients(itv, VIDIOC_S_STD, &itv->std); - - if (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT) { - /* set display standard */ - itv->std_out = std; - itv->is_out_60hz = itv->is_60hz; - itv->is_out_50hz = itv->is_50hz; - ivtv_call_i2c_clients(itv, VIDIOC_INT_S_STD_OUTPUT, &itv->std_out); - ivtv_vapi(itv, CX2341X_DEC_SET_STANDARD, 1, itv->is_out_50hz); - itv->main_rect.left = itv->main_rect.top = 0; - itv->main_rect.width = 720; - itv->main_rect.height = itv->params.height; - ivtv_vapi(itv, CX2341X_OSD_SET_FRAMEBUFFER_WINDOW, 4, - 720, itv->main_rect.height, 0, 0); - yi->main_rect = itv->main_rect; - if (!itv->osd_info) { - yi->osd_full_w = 720; - yi->osd_full_h = itv->is_out_50hz ? 576 : 480; - } + if (test_bit(IVTV_F_I_RADIO_USER, &itv->i_flags) || + atomic_read(&itv->capturing) > 0 || + atomic_read(&itv->decoding) > 0) { + /* Switching standard would turn off the radio or mess + with already running streams, prevent that by + returning EBUSY. */ + return -EBUSY; + } + + itv->std = *std; + itv->is_60hz = (*std & V4L2_STD_525_60) ? 1 : 0; + itv->params.is_50hz = itv->is_50hz = !itv->is_60hz; + itv->params.width = 720; + itv->params.height = itv->is_50hz ? 576 : 480; + itv->vbi.count = itv->is_50hz ? 18 : 12; + itv->vbi.start[0] = itv->is_50hz ? 6 : 10; + itv->vbi.start[1] = itv->is_50hz ? 318 : 273; + + if (itv->hw_flags & IVTV_HW_CX25840) + itv->vbi.sliced_decoder_line_size = itv->is_60hz ? 272 : 284; + + IVTV_DEBUG_INFO("Switching standard to %llx.\n", (unsigned long long)itv->std); + + /* Tuner */ + ivtv_call_i2c_clients(itv, VIDIOC_S_STD, &itv->std); + + if (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT) { + /* set display standard */ + itv->std_out = *std; + itv->is_out_60hz = itv->is_60hz; + itv->is_out_50hz = itv->is_50hz; + ivtv_call_i2c_clients(itv, VIDIOC_INT_S_STD_OUTPUT, &itv->std_out); + ivtv_vapi(itv, CX2341X_DEC_SET_STANDARD, 1, itv->is_out_50hz); + itv->main_rect.left = itv->main_rect.top = 0; + itv->main_rect.width = 720; + itv->main_rect.height = itv->params.height; + ivtv_vapi(itv, CX2341X_OSD_SET_FRAMEBUFFER_WINDOW, 4, + 720, itv->main_rect.height, 0, 0); + yi->main_rect = itv->main_rect; + if (!itv->osd_info) { + yi->osd_full_w = 720; + yi->osd_full_h = itv->is_out_50hz ? 576 : 480; } - break; } + return 0; +} - case VIDIOC_S_TUNER: { /* Setting tuner can only set audio mode */ - struct v4l2_tuner *vt = arg; +static int ivtv_s_tuner(struct file *file, void *fh, struct v4l2_tuner *vt) +{ + struct ivtv_open_id *id = fh; + struct ivtv *itv = id->itv; - if (vt->index != 0) - return -EINVAL; + if (vt->index != 0) + return -EINVAL; - ivtv_call_i2c_clients(itv, VIDIOC_S_TUNER, vt); - break; - } + ivtv_call_i2c_clients(itv, VIDIOC_S_TUNER, vt); - case VIDIOC_G_TUNER: { - struct v4l2_tuner *vt = arg; + return 0; +} - if (vt->index != 0) - return -EINVAL; +static int ivtv_g_tuner(struct file *file, void *fh, struct v4l2_tuner *vt) +{ + struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv; - memset(vt, 0, sizeof(*vt)); - ivtv_call_i2c_clients(itv, VIDIOC_G_TUNER, vt); + if (vt->index != 0) + return -EINVAL; - if (test_bit(IVTV_F_I_RADIO_USER, &itv->i_flags)) { - strlcpy(vt->name, "ivtv Radio Tuner", sizeof(vt->name)); - vt->type = V4L2_TUNER_RADIO; - } else { - strlcpy(vt->name, "ivtv TV Tuner", sizeof(vt->name)); - vt->type = V4L2_TUNER_ANALOG_TV; - } - break; + ivtv_call_i2c_clients(itv, VIDIOC_G_TUNER, vt); + + if (test_bit(IVTV_F_I_RADIO_USER, &itv->i_flags)) { + strlcpy(vt->name, "ivtv Radio Tuner", sizeof(vt->name)); + vt->type = V4L2_TUNER_RADIO; + } else { + strlcpy(vt->name, "ivtv TV Tuner", sizeof(vt->name)); + vt->type = V4L2_TUNER_ANALOG_TV; } - case VIDIOC_G_SLICED_VBI_CAP: { - struct v4l2_sliced_vbi_cap *cap = arg; - int set = itv->is_50hz ? V4L2_SLICED_VBI_625 : V4L2_SLICED_VBI_525; - int f, l; - enum v4l2_buf_type type = cap->type; - - memset(cap, 0, sizeof(*cap)); - cap->type = type; - if (type == V4L2_BUF_TYPE_SLICED_VBI_CAPTURE) { - for (f = 0; f < 2; f++) { - for (l = 0; l < 24; l++) { - if (valid_service_line(f, l, itv->is_50hz)) { - cap->service_lines[f][l] = set; - } - } + return 0; +} + +static int ivtv_g_sliced_vbi_cap(struct file *file, void *fh, struct v4l2_sliced_vbi_cap *cap) +{ + struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv; + int set = itv->is_50hz ? V4L2_SLICED_VBI_625 : V4L2_SLICED_VBI_525; + int f, l; + + if (cap->type == V4L2_BUF_TYPE_SLICED_VBI_CAPTURE) { + for (f = 0; f < 2; f++) { + for (l = 0; l < 24; l++) { + if (valid_service_line(f, l, itv->is_50hz)) + cap->service_lines[f][l] = set; } - return 0; } - if (type == V4L2_BUF_TYPE_SLICED_VBI_OUTPUT) { - if (!(itv->v4l2_cap & V4L2_CAP_SLICED_VBI_OUTPUT)) - return -EINVAL; - if (itv->is_60hz) { - cap->service_lines[0][21] = V4L2_SLICED_CAPTION_525; - cap->service_lines[1][21] = V4L2_SLICED_CAPTION_525; - } else { - cap->service_lines[0][23] = V4L2_SLICED_WSS_625; - cap->service_lines[0][16] = V4L2_SLICED_VPS; - } - return 0; + return 0; + } + if (cap->type == V4L2_BUF_TYPE_SLICED_VBI_OUTPUT) { + if (!(itv->v4l2_cap & V4L2_CAP_SLICED_VBI_OUTPUT)) + return -EINVAL; + if (itv->is_60hz) { + cap->service_lines[0][21] = V4L2_SLICED_CAPTION_525; + cap->service_lines[1][21] = V4L2_SLICED_CAPTION_525; + } else { + cap->service_lines[0][23] = V4L2_SLICED_WSS_625; + cap->service_lines[0][16] = V4L2_SLICED_VPS; } - return -EINVAL; + return 0; } + return -EINVAL; +} - case VIDIOC_G_ENC_INDEX: { - struct v4l2_enc_idx *idx = arg; - struct v4l2_enc_idx_entry *e = idx->entry; - int entries; - int i; - - entries = (itv->pgm_info_write_idx + IVTV_MAX_PGM_INDEX - itv->pgm_info_read_idx) % - IVTV_MAX_PGM_INDEX; - if (entries > V4L2_ENC_IDX_ENTRIES) - entries = V4L2_ENC_IDX_ENTRIES; - idx->entries = 0; - for (i = 0; i < entries; i++) { - *e = itv->pgm_info[(itv->pgm_info_read_idx + i) % IVTV_MAX_PGM_INDEX]; - if ((e->flags & V4L2_ENC_IDX_FRAME_MASK) <= V4L2_ENC_IDX_FRAME_B) { - idx->entries++; - e++; - } +static int ivtv_g_enc_index(struct file *file, void *fh, struct v4l2_enc_idx *idx) +{ + struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv; + struct v4l2_enc_idx_entry *e = idx->entry; + int entries; + int i; + + entries = (itv->pgm_info_write_idx + IVTV_MAX_PGM_INDEX - itv->pgm_info_read_idx) % + IVTV_MAX_PGM_INDEX; + if (entries > V4L2_ENC_IDX_ENTRIES) + entries = V4L2_ENC_IDX_ENTRIES; + idx->entries = 0; + for (i = 0; i < entries; i++) { + *e = itv->pgm_info[(itv->pgm_info_read_idx + i) % IVTV_MAX_PGM_INDEX]; + if ((e->flags & V4L2_ENC_IDX_FRAME_MASK) <= V4L2_ENC_IDX_FRAME_B) { + idx->entries++; + e++; } - itv->pgm_info_read_idx = (itv->pgm_info_read_idx + idx->entries) % IVTV_MAX_PGM_INDEX; - break; } + itv->pgm_info_read_idx = (itv->pgm_info_read_idx + idx->entries) % IVTV_MAX_PGM_INDEX; + return 0; +} - case VIDIOC_ENCODER_CMD: - case VIDIOC_TRY_ENCODER_CMD: { - struct v4l2_encoder_cmd *enc = arg; - int try = cmd == VIDIOC_TRY_ENCODER_CMD; - - memset(&enc->raw, 0, sizeof(enc->raw)); - switch (enc->cmd) { - case V4L2_ENC_CMD_START: - IVTV_DEBUG_IOCTL("V4L2_ENC_CMD_START\n"); - enc->flags = 0; - if (try) - return 0; - return ivtv_start_capture(id); +static int ivtv_encoder_cmd(struct file *file, void *fh, struct v4l2_encoder_cmd *enc) +{ + struct ivtv_open_id *id = fh; + struct ivtv *itv = id->itv; - case V4L2_ENC_CMD_STOP: - IVTV_DEBUG_IOCTL("V4L2_ENC_CMD_STOP\n"); - enc->flags &= V4L2_ENC_CMD_STOP_AT_GOP_END; - if (try) - return 0; - ivtv_stop_capture(id, enc->flags & V4L2_ENC_CMD_STOP_AT_GOP_END); + + switch (enc->cmd) { + case V4L2_ENC_CMD_START: + IVTV_DEBUG_IOCTL("V4L2_ENC_CMD_START\n"); + enc->flags = 0; + return ivtv_start_capture(id); + + case V4L2_ENC_CMD_STOP: + IVTV_DEBUG_IOCTL("V4L2_ENC_CMD_STOP\n"); + enc->flags &= V4L2_ENC_CMD_STOP_AT_GOP_END; + ivtv_stop_capture(id, enc->flags & V4L2_ENC_CMD_STOP_AT_GOP_END); + return 0; + + case V4L2_ENC_CMD_PAUSE: + IVTV_DEBUG_IOCTL("V4L2_ENC_CMD_PAUSE\n"); + enc->flags = 0; + + if (!atomic_read(&itv->capturing)) + return -EPERM; + if (test_and_set_bit(IVTV_F_I_ENC_PAUSED, &itv->i_flags)) return 0; - case V4L2_ENC_CMD_PAUSE: - IVTV_DEBUG_IOCTL("V4L2_ENC_CMD_PAUSE\n"); - enc->flags = 0; - if (try) - return 0; - if (!atomic_read(&itv->capturing)) - return -EPERM; - if (test_and_set_bit(IVTV_F_I_ENC_PAUSED, &itv->i_flags)) - return 0; - ivtv_mute(itv); - ivtv_vapi(itv, CX2341X_ENC_PAUSE_ENCODER, 1, 0); - break; + ivtv_mute(itv); + ivtv_vapi(itv, CX2341X_ENC_PAUSE_ENCODER, 1, 0); + break; - case V4L2_ENC_CMD_RESUME: - IVTV_DEBUG_IOCTL("V4L2_ENC_CMD_RESUME\n"); - enc->flags = 0; - if (try) - return 0; - if (!atomic_read(&itv->capturing)) - return -EPERM; - if (!test_and_clear_bit(IVTV_F_I_ENC_PAUSED, &itv->i_flags)) - return 0; - ivtv_vapi(itv, CX2341X_ENC_PAUSE_ENCODER, 1, 1); - ivtv_unmute(itv); - break; - default: - IVTV_DEBUG_IOCTL("Unknown cmd %d\n", enc->cmd); - return -EINVAL; - } + case V4L2_ENC_CMD_RESUME: + IVTV_DEBUG_IOCTL("V4L2_ENC_CMD_RESUME\n"); + enc->flags = 0; + + if (!atomic_read(&itv->capturing)) + return -EPERM; + + if (!test_and_clear_bit(IVTV_F_I_ENC_PAUSED, &itv->i_flags)) + return 0; + + ivtv_vapi(itv, CX2341X_ENC_PAUSE_ENCODER, 1, 1); + ivtv_unmute(itv); break; + default: + IVTV_DEBUG_IOCTL("Unknown cmd %d\n", enc->cmd); + return -EINVAL; } - case VIDIOC_G_FBUF: { - struct v4l2_framebuffer *fb = arg; - int pixfmt; - static u32 pixel_format[16] = { - V4L2_PIX_FMT_PAL8, /* Uses a 256-entry RGB colormap */ - V4L2_PIX_FMT_RGB565, - V4L2_PIX_FMT_RGB555, - V4L2_PIX_FMT_RGB444, - V4L2_PIX_FMT_RGB32, - 0, - 0, - 0, - V4L2_PIX_FMT_PAL8, /* Uses a 256-entry YUV colormap */ - V4L2_PIX_FMT_YUV565, - V4L2_PIX_FMT_YUV555, - V4L2_PIX_FMT_YUV444, - V4L2_PIX_FMT_YUV32, - 0, - 0, - 0, - }; + return 0; +} - memset(fb, 0, sizeof(*fb)); - if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT_OVERLAY)) - return -EINVAL; - fb->capability = V4L2_FBUF_CAP_EXTERNOVERLAY | V4L2_FBUF_CAP_CHROMAKEY | - V4L2_FBUF_CAP_GLOBAL_ALPHA; - ivtv_vapi_result(itv, data, CX2341X_OSD_GET_STATE, 0); - data[0] |= (read_reg(0x2a00) >> 7) & 0x40; - pixfmt = (data[0] >> 3) & 0xf; - fb->fmt.pixelformat = pixel_format[pixfmt]; - fb->fmt.width = itv->osd_rect.width; - fb->fmt.height = itv->osd_rect.height; - fb->base = (void *)itv->osd_video_pbase; - if (itv->osd_chroma_key_state) - fb->flags |= V4L2_FBUF_FLAG_CHROMAKEY; - if (itv->osd_global_alpha_state) - fb->flags |= V4L2_FBUF_FLAG_GLOBAL_ALPHA; - pixfmt &= 7; - /* no local alpha for RGB565 or unknown formats */ - if (pixfmt == 1 || pixfmt > 4) - break; +static int ivtv_try_encoder_cmd(struct file *file, void *fh, struct v4l2_encoder_cmd *enc) +{ + struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv; + + switch (enc->cmd) { + case V4L2_ENC_CMD_START: + IVTV_DEBUG_IOCTL("V4L2_ENC_CMD_START\n"); + enc->flags = 0; + return 0; + + case V4L2_ENC_CMD_STOP: + IVTV_DEBUG_IOCTL("V4L2_ENC_CMD_STOP\n"); + enc->flags &= V4L2_ENC_CMD_STOP_AT_GOP_END; + return 0; + + case V4L2_ENC_CMD_PAUSE: + IVTV_DEBUG_IOCTL("V4L2_ENC_CMD_PAUSE\n"); + enc->flags = 0; + return 0; + + case V4L2_ENC_CMD_RESUME: + IVTV_DEBUG_IOCTL("V4L2_ENC_CMD_RESUME\n"); + enc->flags = 0; + return 0; + default: + IVTV_DEBUG_IOCTL("Unknown cmd %d\n", enc->cmd); + return -EINVAL; + } +} + +static int ivtv_g_fbuf(struct file *file, void *fh, struct v4l2_framebuffer *fb) +{ + struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv; + u32 data[CX2341X_MBOX_MAX_DATA]; + struct yuv_playback_info *yi = &itv->yuv_info; + + int pixfmt; + static u32 pixel_format[16] = { + V4L2_PIX_FMT_PAL8, /* Uses a 256-entry RGB colormap */ + V4L2_PIX_FMT_RGB565, + V4L2_PIX_FMT_RGB555, + V4L2_PIX_FMT_RGB444, + V4L2_PIX_FMT_RGB32, + 0, + 0, + 0, + V4L2_PIX_FMT_PAL8, /* Uses a 256-entry YUV colormap */ + V4L2_PIX_FMT_YUV565, + V4L2_PIX_FMT_YUV555, + V4L2_PIX_FMT_YUV444, + V4L2_PIX_FMT_YUV32, + 0, + 0, + 0, + }; + + if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT_OVERLAY)) + return -EINVAL; + if (!itv->osd_video_pbase) + return -EINVAL; + + fb->capability = V4L2_FBUF_CAP_EXTERNOVERLAY | V4L2_FBUF_CAP_CHROMAKEY | + V4L2_FBUF_CAP_GLOBAL_ALPHA; + + ivtv_vapi_result(itv, data, CX2341X_OSD_GET_STATE, 0); + data[0] |= (read_reg(0x2a00) >> 7) & 0x40; + pixfmt = (data[0] >> 3) & 0xf; + + fb->fmt.pixelformat = pixel_format[pixfmt]; + fb->fmt.width = itv->osd_rect.width; + fb->fmt.height = itv->osd_rect.height; + fb->fmt.field = V4L2_FIELD_INTERLACED; + fb->fmt.bytesperline = fb->fmt.width; + fb->fmt.colorspace = V4L2_COLORSPACE_SMPTE170M; + fb->fmt.field = V4L2_FIELD_INTERLACED; + fb->fmt.priv = 0; + if (fb->fmt.pixelformat != V4L2_PIX_FMT_PAL8) + fb->fmt.bytesperline *= 2; + if (fb->fmt.pixelformat == V4L2_PIX_FMT_RGB32 || + fb->fmt.pixelformat == V4L2_PIX_FMT_YUV32) + fb->fmt.bytesperline *= 2; + fb->fmt.sizeimage = fb->fmt.bytesperline * fb->fmt.height; + fb->base = (void *)itv->osd_video_pbase; + fb->flags = 0; + + if (itv->osd_chroma_key_state) + fb->flags |= V4L2_FBUF_FLAG_CHROMAKEY; + + if (itv->osd_global_alpha_state) + fb->flags |= V4L2_FBUF_FLAG_GLOBAL_ALPHA; + + pixfmt &= 7; + + /* no local alpha for RGB565 or unknown formats */ + if (pixfmt == 1 || pixfmt > 4) + return 0; + + /* 16-bit formats have inverted local alpha */ + if (pixfmt == 2 || pixfmt == 3) + fb->capability |= V4L2_FBUF_CAP_LOCAL_INV_ALPHA; + else + fb->capability |= V4L2_FBUF_CAP_LOCAL_ALPHA; + + if (itv->osd_local_alpha_state) { /* 16-bit formats have inverted local alpha */ if (pixfmt == 2 || pixfmt == 3) - fb->capability |= V4L2_FBUF_CAP_LOCAL_INV_ALPHA; + fb->flags |= V4L2_FBUF_FLAG_LOCAL_INV_ALPHA; else - fb->capability |= V4L2_FBUF_CAP_LOCAL_ALPHA; - if (itv->osd_local_alpha_state) { - /* 16-bit formats have inverted local alpha */ - if (pixfmt == 2 || pixfmt == 3) - fb->flags |= V4L2_FBUF_FLAG_LOCAL_INV_ALPHA; - else - fb->flags |= V4L2_FBUF_FLAG_LOCAL_ALPHA; - } - if (yi->track_osd) - fb->flags |= V4L2_FBUF_FLAG_OVERLAY; - break; + fb->flags |= V4L2_FBUF_FLAG_LOCAL_ALPHA; } + if (yi->track_osd) + fb->flags |= V4L2_FBUF_FLAG_OVERLAY; - case VIDIOC_S_FBUF: { - struct v4l2_framebuffer *fb = arg; + return 0; +} - if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT_OVERLAY)) - return -EINVAL; - itv->osd_global_alpha_state = (fb->flags & V4L2_FBUF_FLAG_GLOBAL_ALPHA) != 0; - itv->osd_local_alpha_state = - (fb->flags & (V4L2_FBUF_FLAG_LOCAL_ALPHA|V4L2_FBUF_FLAG_LOCAL_INV_ALPHA)) != 0; - itv->osd_chroma_key_state = (fb->flags & V4L2_FBUF_FLAG_CHROMAKEY) != 0; - ivtv_set_osd_alpha(itv); - yi->track_osd = (fb->flags & V4L2_FBUF_FLAG_OVERLAY) != 0; - break; - } +static int ivtv_s_fbuf(struct file *file, void *fh, struct v4l2_framebuffer *fb) +{ + struct ivtv_open_id *id = fh; + struct ivtv *itv = id->itv; + struct yuv_playback_info *yi = &itv->yuv_info; - case VIDIOC_OVERLAY: { - int *on = arg; + if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT_OVERLAY)) + return -EINVAL; + if (!itv->osd_video_pbase) + return -EINVAL; - if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT_OVERLAY)) - return -EINVAL; - ivtv_vapi(itv, CX2341X_OSD_SET_STATE, 1, *on != 0); - break; - } + itv->osd_global_alpha_state = (fb->flags & V4L2_FBUF_FLAG_GLOBAL_ALPHA) != 0; + itv->osd_local_alpha_state = + (fb->flags & (V4L2_FBUF_FLAG_LOCAL_ALPHA|V4L2_FBUF_FLAG_LOCAL_INV_ALPHA)) != 0; + itv->osd_chroma_key_state = (fb->flags & V4L2_FBUF_FLAG_CHROMAKEY) != 0; + ivtv_set_osd_alpha(itv); + yi->track_osd = (fb->flags & V4L2_FBUF_FLAG_OVERLAY) != 0; + return ivtv_g_fbuf(file, fh, fb); +} - case VIDIOC_LOG_STATUS: - { - int has_output = itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT; - struct v4l2_input vidin; - struct v4l2_audio audin; - int i; +static int ivtv_overlay(struct file *file, void *fh, unsigned int on) +{ + struct ivtv_open_id *id = fh; + struct ivtv *itv = id->itv; - IVTV_INFO("================= START STATUS CARD #%d =================\n", itv->num); - IVTV_INFO("Version: %s Card: %s\n", IVTV_VERSION, itv->card_name); - if (itv->hw_flags & IVTV_HW_TVEEPROM) { - struct tveeprom tv; + if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT_OVERLAY)) + return -EINVAL; - ivtv_read_eeprom(itv, &tv); - } - ivtv_call_i2c_clients(itv, VIDIOC_LOG_STATUS, NULL); - ivtv_get_input(itv, itv->active_input, &vidin); - ivtv_get_audio_input(itv, itv->audio_input, &audin); - IVTV_INFO("Video Input: %s\n", vidin.name); - IVTV_INFO("Audio Input: %s%s\n", audin.name, - (itv->dualwatch_stereo_mode & ~0x300) == 0x200 ? " (Bilingual)" : ""); - if (has_output) { - struct v4l2_output vidout; - struct v4l2_audioout audout; - int mode = itv->output_mode; - static const char * const output_modes[5] = { - "None", - "MPEG Streaming", - "YUV Streaming", - "YUV Frames", - "Passthrough", - }; - static const char * const audio_modes[5] = { - "Stereo", - "Left", - "Right", - "Mono", - "Swapped" - }; - static const char * const alpha_mode[4] = { - "None", - "Global", - "Local", - "Global and Local" - }; - static const char * const pixel_format[16] = { - "ARGB Indexed", - "RGB 5:6:5", - "ARGB 1:5:5:5", - "ARGB 1:4:4:4", - "ARGB 8:8:8:8", - "5", - "6", - "7", - "AYUV Indexed", - "YUV 5:6:5", - "AYUV 1:5:5:5", - "AYUV 1:4:4:4", - "AYUV 8:8:8:8", - "13", - "14", - "15", - }; - - ivtv_get_output(itv, itv->active_output, &vidout); - ivtv_get_audio_output(itv, 0, &audout); - IVTV_INFO("Video Output: %s\n", vidout.name); - IVTV_INFO("Audio Output: %s (Stereo/Bilingual: %s/%s)\n", audout.name, - audio_modes[itv->audio_stereo_mode], - audio_modes[itv->audio_bilingual_mode]); - if (mode < 0 || mode > OUT_PASSTHROUGH) - mode = OUT_NONE; - IVTV_INFO("Output Mode: %s\n", output_modes[mode]); - ivtv_vapi_result(itv, data, CX2341X_OSD_GET_STATE, 0); - data[0] |= (read_reg(0x2a00) >> 7) & 0x40; - IVTV_INFO("Overlay: %s, Alpha: %s, Pixel Format: %s\n", - data[0] & 1 ? "On" : "Off", - alpha_mode[(data[0] >> 1) & 0x3], - pixel_format[(data[0] >> 3) & 0xf]); - } - IVTV_INFO("Tuner: %s\n", - test_bit(IVTV_F_I_RADIO_USER, &itv->i_flags) ? "Radio" : "TV"); - cx2341x_log_status(&itv->params, itv->name); - IVTV_INFO("Status flags: 0x%08lx\n", itv->i_flags); - for (i = 0; i < IVTV_MAX_STREAMS; i++) { - struct ivtv_stream *s = &itv->streams[i]; - - if (s->v4l2dev == NULL || s->buffers == 0) - continue; - IVTV_INFO("Stream %s: status 0x%04lx, %d%% of %d KiB (%d buffers) in use\n", s->name, s->s_flags, - (s->buffers - s->q_free.buffers) * 100 / s->buffers, - (s->buffers * s->buf_size) / 1024, s->buffers); - } - IVTV_INFO("Read MPG/VBI: %lld/%lld bytes\n", (long long)itv->mpg_data_received, (long long)itv->vbi_data_inserted); - IVTV_INFO("================== END STATUS CARD #%d ==================\n", itv->num); - break; + ivtv_vapi(itv, CX2341X_OSD_SET_STATE, 1, on != 0); + + return 0; +} + +static int ivtv_log_status(struct file *file, void *fh) +{ + struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv; + u32 data[CX2341X_MBOX_MAX_DATA]; + + int has_output = itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT; + struct v4l2_input vidin; + struct v4l2_audio audin; + int i; + + IVTV_INFO("================= START STATUS CARD #%d =================\n", itv->num); + IVTV_INFO("Version: %s Card: %s\n", IVTV_VERSION, itv->card_name); + if (itv->hw_flags & IVTV_HW_TVEEPROM) { + struct tveeprom tv; + + ivtv_read_eeprom(itv, &tv); + } + ivtv_call_i2c_clients(itv, VIDIOC_LOG_STATUS, NULL); + ivtv_get_input(itv, itv->active_input, &vidin); + ivtv_get_audio_input(itv, itv->audio_input, &audin); + IVTV_INFO("Video Input: %s\n", vidin.name); + IVTV_INFO("Audio Input: %s%s\n", audin.name, + (itv->dualwatch_stereo_mode & ~0x300) == 0x200 ? " (Bilingual)" : ""); + if (has_output) { + struct v4l2_output vidout; + struct v4l2_audioout audout; + int mode = itv->output_mode; + static const char * const output_modes[5] = { + "None", + "MPEG Streaming", + "YUV Streaming", + "YUV Frames", + "Passthrough", + }; + static const char * const audio_modes[5] = { + "Stereo", + "Left", + "Right", + "Mono", + "Swapped" + }; + static const char * const alpha_mode[4] = { + "None", + "Global", + "Local", + "Global and Local" + }; + static const char * const pixel_format[16] = { + "ARGB Indexed", + "RGB 5:6:5", + "ARGB 1:5:5:5", + "ARGB 1:4:4:4", + "ARGB 8:8:8:8", + "5", + "6", + "7", + "AYUV Indexed", + "YUV 5:6:5", + "AYUV 1:5:5:5", + "AYUV 1:4:4:4", + "AYUV 8:8:8:8", + "13", + "14", + "15", + }; + + ivtv_get_output(itv, itv->active_output, &vidout); + ivtv_get_audio_output(itv, 0, &audout); + IVTV_INFO("Video Output: %s\n", vidout.name); + IVTV_INFO("Audio Output: %s (Stereo/Bilingual: %s/%s)\n", audout.name, + audio_modes[itv->audio_stereo_mode], + audio_modes[itv->audio_bilingual_mode]); + if (mode < 0 || mode > OUT_PASSTHROUGH) + mode = OUT_NONE; + IVTV_INFO("Output Mode: %s\n", output_modes[mode]); + ivtv_vapi_result(itv, data, CX2341X_OSD_GET_STATE, 0); + data[0] |= (read_reg(0x2a00) >> 7) & 0x40; + IVTV_INFO("Overlay: %s, Alpha: %s, Pixel Format: %s\n", + data[0] & 1 ? "On" : "Off", + alpha_mode[(data[0] >> 1) & 0x3], + pixel_format[(data[0] >> 3) & 0xf]); } + IVTV_INFO("Tuner: %s\n", + test_bit(IVTV_F_I_RADIO_USER, &itv->i_flags) ? "Radio" : "TV"); + cx2341x_log_status(&itv->params, itv->name); + IVTV_INFO("Status flags: 0x%08lx\n", itv->i_flags); + for (i = 0; i < IVTV_MAX_STREAMS; i++) { + struct ivtv_stream *s = &itv->streams[i]; - default: - return -EINVAL; + if (s->v4l2dev == NULL || s->buffers == 0) + continue; + IVTV_INFO("Stream %s: status 0x%04lx, %d%% of %d KiB (%d buffers) in use\n", s->name, s->s_flags, + (s->buffers - s->q_free.buffers) * 100 / s->buffers, + (s->buffers * s->buf_size) / 1024, s->buffers); } + + IVTV_INFO("Read MPG/VBI: %lld/%lld bytes\n", (long long)itv->mpg_data_received, (long long)itv->vbi_data_inserted); + IVTV_INFO("================== END STATUS CARD #%d ==================\n", itv->num); + return 0; } @@ -1433,7 +1548,7 @@ static int ivtv_decoder_ioctls(struct file *filp, unsigned int cmd, void *arg) return -EINVAL; if (itv->output_mode == OUT_UDMA_YUV && args->y_source == NULL) return 0; - if (ivtv_claim_stream(id, id->type)) { + if (ivtv_start_decoding(id, id->type)) { return -EBUSY; } if (ivtv_set_output_mode(itv, OUT_UDMA_YUV) != OUT_UDMA_YUV) { @@ -1607,121 +1722,30 @@ static int ivtv_decoder_ioctls(struct file *filp, unsigned int cmd, void *arg) return 0; } -static int ivtv_v4l2_do_ioctl(struct inode *inode, struct file *filp, - unsigned int cmd, void *arg) +static int ivtv_default(struct file *file, void *fh, int cmd, void *arg) { - struct ivtv_open_id *id = (struct ivtv_open_id *)filp->private_data; - struct ivtv *itv = id->itv; - int ret; - - /* check priority */ - switch (cmd) { - case VIDIOC_S_CTRL: - case VIDIOC_S_STD: - case VIDIOC_S_INPUT: - case VIDIOC_S_OUTPUT: - case VIDIOC_S_TUNER: - case VIDIOC_S_FREQUENCY: - case VIDIOC_S_FMT: - case VIDIOC_S_CROP: - case VIDIOC_S_AUDIO: - case VIDIOC_S_AUDOUT: - case VIDIOC_S_EXT_CTRLS: - case VIDIOC_S_FBUF: - case VIDIOC_OVERLAY: - ret = v4l2_prio_check(&itv->prio, &id->prio); - if (ret) - return ret; - } + struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv; switch (cmd) { - case VIDIOC_DBG_G_REGISTER: - case VIDIOC_DBG_S_REGISTER: - case VIDIOC_G_CHIP_IDENT: - case VIDIOC_INT_S_AUDIO_ROUTING: - case VIDIOC_INT_RESET: - if (ivtv_debug & IVTV_DBGFLG_IOCTL) { - printk(KERN_INFO "ivtv%d ioctl: ", itv->num); - v4l_printk_ioctl(cmd); - printk("\n"); - } - return ivtv_debug_ioctls(filp, cmd, arg); + case VIDIOC_INT_S_AUDIO_ROUTING: { + struct v4l2_routing *route = arg; - case VIDIOC_G_PRIORITY: - case VIDIOC_S_PRIORITY: - case VIDIOC_QUERYCAP: - case VIDIOC_ENUMINPUT: - case VIDIOC_G_INPUT: - case VIDIOC_S_INPUT: - case VIDIOC_ENUMOUTPUT: - case VIDIOC_G_OUTPUT: - case VIDIOC_S_OUTPUT: - case VIDIOC_G_FMT: - case VIDIOC_S_FMT: - case VIDIOC_TRY_FMT: - case VIDIOC_ENUM_FMT: - case VIDIOC_CROPCAP: - case VIDIOC_G_CROP: - case VIDIOC_S_CROP: - case VIDIOC_G_FREQUENCY: - case VIDIOC_S_FREQUENCY: - case VIDIOC_ENUMSTD: - case VIDIOC_G_STD: - case VIDIOC_S_STD: - case VIDIOC_S_TUNER: - case VIDIOC_G_TUNER: - case VIDIOC_ENUMAUDIO: - case VIDIOC_S_AUDIO: - case VIDIOC_G_AUDIO: - case VIDIOC_ENUMAUDOUT: - case VIDIOC_S_AUDOUT: - case VIDIOC_G_AUDOUT: - case VIDIOC_G_SLICED_VBI_CAP: - case VIDIOC_LOG_STATUS: - case VIDIOC_G_ENC_INDEX: - case VIDIOC_ENCODER_CMD: - case VIDIOC_TRY_ENCODER_CMD: - case VIDIOC_G_FBUF: - case VIDIOC_S_FBUF: - case VIDIOC_OVERLAY: - if (ivtv_debug & IVTV_DBGFLG_IOCTL) { - printk(KERN_INFO "ivtv%d ioctl: ", itv->num); - v4l_printk_ioctl(cmd); - printk("\n"); - } - return ivtv_v4l2_ioctls(itv, filp, cmd, arg); + ivtv_i2c_hw(itv, itv->card->hw_audio, VIDIOC_INT_S_AUDIO_ROUTING, route); + break; + } - case VIDIOC_QUERYMENU: - case VIDIOC_QUERYCTRL: - case VIDIOC_S_CTRL: - case VIDIOC_G_CTRL: - case VIDIOC_S_EXT_CTRLS: - case VIDIOC_G_EXT_CTRLS: - case VIDIOC_TRY_EXT_CTRLS: - if (ivtv_debug & IVTV_DBGFLG_IOCTL) { - printk(KERN_INFO "ivtv%d ioctl: ", itv->num); - v4l_printk_ioctl(cmd); - printk("\n"); - } - return ivtv_control_ioctls(itv, cmd, arg); + case VIDIOC_INT_RESET: { + u32 val = *(u32 *)arg; - case IVTV_IOC_DMA_FRAME: - case VIDEO_GET_PTS: - case VIDEO_GET_FRAME_COUNT: - case VIDEO_GET_EVENT: - case VIDEO_PLAY: - case VIDEO_STOP: - case VIDEO_FREEZE: - case VIDEO_CONTINUE: - case VIDEO_COMMAND: - case VIDEO_TRY_COMMAND: - return ivtv_decoder_ioctls(filp, cmd, arg); + if ((val == 0 && itv->options.newi2c) || (val & 0x01)) + ivtv_reset_ir_gpio(itv); + if (val & 0x02) + itv->video_dec_func(itv, cmd, NULL); + break; + } - case 0x00005401: /* Handle isatty() calls */ - return -EINVAL; default: - return v4l_compat_translate_ioctl(inode, filp, cmd, arg, - ivtv_v4l2_do_ioctl); + return -EINVAL; } return 0; } @@ -1729,7 +1753,11 @@ static int ivtv_v4l2_do_ioctl(struct inode *inode, struct file *filp, static int ivtv_serialized_ioctl(struct ivtv *itv, struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg) { - /* Filter dvb ioctls that cannot be handled by video_usercopy */ + struct video_device *vfd = video_devdata(filp); + struct ivtv_open_id *id = (struct ivtv_open_id *)filp->private_data; + int ret; + + /* Filter dvb ioctls that cannot be handled by the v4l ioctl framework */ switch (cmd) { case VIDEO_SELECT_SOURCE: IVTV_DEBUG_IOCTL("VIDEO_SELECT_SOURCE\n"); @@ -1758,10 +1786,47 @@ static int ivtv_serialized_ioctl(struct ivtv *itv, struct inode *inode, struct f ivtv_vapi(itv, CX2341X_DEC_SET_AUDIO_MODE, 2, itv->audio_bilingual_mode, itv->audio_stereo_mode); return 0; + case IVTV_IOC_DMA_FRAME: + case VIDEO_GET_PTS: + case VIDEO_GET_FRAME_COUNT: + case VIDEO_GET_EVENT: + case VIDEO_PLAY: + case VIDEO_STOP: + case VIDEO_FREEZE: + case VIDEO_CONTINUE: + case VIDEO_COMMAND: + case VIDEO_TRY_COMMAND: + return ivtv_decoder_ioctls(filp, cmd, (void *)arg); + default: break; } - return video_usercopy(inode, filp, cmd, arg, ivtv_v4l2_do_ioctl); + + /* check priority */ + switch (cmd) { + case VIDIOC_S_CTRL: + case VIDIOC_S_STD: + case VIDIOC_S_INPUT: + case VIDIOC_S_OUTPUT: + case VIDIOC_S_TUNER: + case VIDIOC_S_FREQUENCY: + case VIDIOC_S_FMT: + case VIDIOC_S_CROP: + case VIDIOC_S_AUDIO: + case VIDIOC_S_AUDOUT: + case VIDIOC_S_EXT_CTRLS: + case VIDIOC_S_FBUF: + case VIDIOC_OVERLAY: + ret = v4l2_prio_check(&itv->prio, &id->prio); + if (ret) + return ret; + } + + if (ivtv_debug & IVTV_DBGFLG_IOCTL) + vfd->debug = V4L2_DEBUG_IOCTL | V4L2_DEBUG_IOCTL_ARG; + ret = video_ioctl2(inode, filp, cmd, arg); + vfd->debug = 0; + return ret; } int ivtv_v4l2_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, @@ -1776,3 +1841,70 @@ int ivtv_v4l2_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, mutex_unlock(&itv->serialize_lock); return res; } + +void ivtv_set_funcs(struct video_device *vdev) +{ + vdev->vidioc_querycap = ivtv_querycap; + vdev->vidioc_g_priority = ivtv_g_priority; + vdev->vidioc_s_priority = ivtv_s_priority; + vdev->vidioc_s_audio = ivtv_s_audio; + vdev->vidioc_g_audio = ivtv_g_audio; + vdev->vidioc_enumaudio = ivtv_enumaudio; + vdev->vidioc_s_audout = ivtv_s_audout; + vdev->vidioc_g_audout = ivtv_g_audout; + vdev->vidioc_enum_input = ivtv_enum_input; + vdev->vidioc_enum_output = ivtv_enum_output; + vdev->vidioc_enumaudout = ivtv_enumaudout; + vdev->vidioc_cropcap = ivtv_cropcap; + vdev->vidioc_s_crop = ivtv_s_crop; + vdev->vidioc_g_crop = ivtv_g_crop; + vdev->vidioc_g_input = ivtv_g_input; + vdev->vidioc_s_input = ivtv_s_input; + vdev->vidioc_g_output = ivtv_g_output; + vdev->vidioc_s_output = ivtv_s_output; + vdev->vidioc_g_frequency = ivtv_g_frequency; + vdev->vidioc_s_frequency = ivtv_s_frequency; + vdev->vidioc_s_tuner = ivtv_s_tuner; + vdev->vidioc_g_tuner = ivtv_g_tuner; + vdev->vidioc_g_enc_index = ivtv_g_enc_index; + vdev->vidioc_g_fbuf = ivtv_g_fbuf; + vdev->vidioc_s_fbuf = ivtv_s_fbuf; + vdev->vidioc_g_std = ivtv_g_std; + vdev->vidioc_s_std = ivtv_s_std; + vdev->vidioc_overlay = ivtv_overlay; + vdev->vidioc_log_status = ivtv_log_status; + vdev->vidioc_enum_fmt_vid_cap = ivtv_enum_fmt_vid_cap; + vdev->vidioc_encoder_cmd = ivtv_encoder_cmd; + vdev->vidioc_try_encoder_cmd = ivtv_try_encoder_cmd; + vdev->vidioc_enum_fmt_vid_out = ivtv_enum_fmt_vid_out; + vdev->vidioc_g_fmt_vid_cap = ivtv_g_fmt_vid_cap; + vdev->vidioc_g_fmt_vbi_cap = ivtv_g_fmt_vbi_cap; + vdev->vidioc_g_fmt_sliced_vbi_cap = ivtv_g_fmt_sliced_vbi_cap; + vdev->vidioc_g_fmt_vid_out = ivtv_g_fmt_vid_out; + vdev->vidioc_g_fmt_vid_out_overlay = ivtv_g_fmt_vid_out_overlay; + vdev->vidioc_g_fmt_sliced_vbi_out = ivtv_g_fmt_sliced_vbi_out; + vdev->vidioc_s_fmt_vid_cap = ivtv_s_fmt_vid_cap; + vdev->vidioc_s_fmt_vbi_cap = ivtv_s_fmt_vbi_cap; + vdev->vidioc_s_fmt_sliced_vbi_cap = ivtv_s_fmt_sliced_vbi_cap; + vdev->vidioc_s_fmt_vid_out = ivtv_s_fmt_vid_out; + vdev->vidioc_s_fmt_vid_out_overlay = ivtv_s_fmt_vid_out_overlay; + vdev->vidioc_s_fmt_sliced_vbi_out = ivtv_s_fmt_sliced_vbi_out; + vdev->vidioc_try_fmt_vid_cap = ivtv_try_fmt_vid_cap; + vdev->vidioc_try_fmt_vbi_cap = ivtv_try_fmt_vbi_cap; + vdev->vidioc_try_fmt_sliced_vbi_cap = ivtv_try_fmt_sliced_vbi_cap; + vdev->vidioc_try_fmt_vid_out = ivtv_try_fmt_vid_out; + vdev->vidioc_try_fmt_vid_out_overlay = ivtv_try_fmt_vid_out_overlay; + vdev->vidioc_try_fmt_sliced_vbi_out = ivtv_try_fmt_sliced_vbi_out; + vdev->vidioc_g_sliced_vbi_cap = ivtv_g_sliced_vbi_cap; + vdev->vidioc_g_chip_ident = ivtv_g_chip_ident; +#ifdef CONFIG_VIDEO_ADV_DEBUG + vdev->vidioc_g_register = ivtv_g_register; + vdev->vidioc_s_register = ivtv_s_register; +#endif + vdev->vidioc_default = ivtv_default; + vdev->vidioc_queryctrl = ivtv_queryctrl; + vdev->vidioc_querymenu = ivtv_querymenu; + vdev->vidioc_g_ext_ctrls = ivtv_g_ext_ctrls; + vdev->vidioc_s_ext_ctrls = ivtv_s_ext_ctrls; + vdev->vidioc_try_ext_ctrls = ivtv_try_ext_ctrls; +} diff --git a/drivers/media/video/ivtv/ivtv-ioctl.h b/drivers/media/video/ivtv/ivtv-ioctl.h index 4e67f0ed1fc0..70188588b4f4 100644 --- a/drivers/media/video/ivtv/ivtv-ioctl.h +++ b/drivers/media/video/ivtv/ivtv-ioctl.h @@ -24,10 +24,13 @@ u16 ivtv_service2vbi(int type); void ivtv_expand_service_set(struct v4l2_sliced_vbi_format *fmt, int is_pal); u16 ivtv_get_service_set(struct v4l2_sliced_vbi_format *fmt); -int ivtv_v4l2_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, - unsigned long arg); -int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void *arg); void ivtv_set_osd_alpha(struct ivtv *itv); int ivtv_set_speed(struct ivtv *itv, int speed); +void ivtv_set_funcs(struct video_device *vdev); +int ivtv_s_std(struct file *file, void *fh, v4l2_std_id *std); +int ivtv_s_frequency(struct file *file, void *fh, struct v4l2_frequency *vf); +int ivtv_s_input(struct file *file, void *fh, unsigned int inp); +int ivtv_v4l2_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, + unsigned long arg); #endif diff --git a/drivers/media/video/ivtv/ivtv-streams.c b/drivers/media/video/ivtv/ivtv-streams.c index c854285a4371..f8883b487f4a 100644 --- a/drivers/media/video/ivtv/ivtv-streams.c +++ b/drivers/media/video/ivtv/ivtv-streams.c @@ -220,7 +220,8 @@ static int ivtv_prep_dev(struct ivtv *itv, int type) s->v4l2dev->dev = &itv->dev->dev; s->v4l2dev->fops = ivtv_stream_info[type].fops; s->v4l2dev->release = video_device_release; - + s->v4l2dev->tvnorms = V4L2_STD_ALL; + ivtv_set_funcs(s->v4l2dev); return 0; } diff --git a/drivers/media/video/ivtv/ivtvfb.c b/drivers/media/video/ivtv/ivtvfb.c index 73be154f7f05..bdfda48e56bf 100644 --- a/drivers/media/video/ivtv/ivtvfb.c +++ b/drivers/media/video/ivtv/ivtvfb.c @@ -367,6 +367,88 @@ static int ivtvfb_prep_frame(struct ivtv *itv, int cmd, void __user *source, return ivtvfb_prep_dec_dma_to_device(itv, dest_offset, source, count); } +static ssize_t ivtvfb_write(struct fb_info *info, const char __user *buf, + size_t count, loff_t *ppos) +{ + unsigned long p = *ppos; + void *dst; + int err = 0; + unsigned long total_size; + struct ivtv *itv = (struct ivtv *) info->par; + unsigned long dma_offset = + IVTV_DECODER_OFFSET + itv->osd_info->video_rbase; + unsigned long dma_size; + u16 lead = 0, tail = 0; + + if (info->state != FBINFO_STATE_RUNNING) + return -EPERM; + + total_size = info->screen_size; + + if (total_size == 0) + total_size = info->fix.smem_len; + + if (p > total_size) + return -EFBIG; + + if (count > total_size) { + err = -EFBIG; + count = total_size; + } + + if (count + p > total_size) { + if (!err) + err = -ENOSPC; + + count = total_size - p; + } + + dst = (void __force *) (info->screen_base + p); + + if (info->fbops->fb_sync) + info->fbops->fb_sync(info); + + if (!access_ok(VERIFY_READ, buf, count)) { + IVTVFB_WARN("Invalid userspace pointer 0x%08lx\n", + (unsigned long)buf); + err = -EFAULT; + } + + if (!err) { + /* If transfer size > threshold and both src/dst + addresses are aligned, use DMA */ + if (count >= 4096 && + ((unsigned long)buf & 3) == ((unsigned long)dst & 3)) { + /* Odd address = can't DMA. Align */ + if ((unsigned long)dst & 3) { + lead = 4 - ((unsigned long)dst & 3); + memcpy(dst, buf, lead); + buf += lead; + dst += lead; + } + /* DMA resolution is 32 bits */ + if ((count - lead) & 3) + tail = (count - lead) & 3; + /* DMA the data */ + dma_size = count - lead - tail; + err = ivtvfb_prep_dec_dma_to_device(itv, + p + lead + dma_offset, (void *)buf, dma_size); + dst += dma_size; + buf += dma_size; + /* Copy any leftover data */ + if (tail) + memcpy(dst, buf, tail); + } else { + memcpy(dst, buf, count); + } + } + + if (!err) + *ppos += count; + + return (err) ? err : count; +} + static int ivtvfb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg) { DEFINE_WAIT(wait); @@ -708,6 +790,9 @@ static int _ivtvfb_check_var(struct fb_var_screeninfo *var, struct ivtv *itv) else var->pixclock = pixclock; + itv->osd_rect.width = var->xres; + itv->osd_rect.height = var->yres; + IVTVFB_DEBUG_INFO("Display size: %dx%d (virtual %dx%d) @ %dbpp\n", var->xres, var->yres, var->xres_virtual, var->yres_virtual, @@ -824,6 +909,7 @@ static int ivtvfb_blank(int blank_mode, struct fb_info *info) static struct fb_ops ivtvfb_ops = { .owner = THIS_MODULE, + .fb_write = ivtvfb_write, .fb_check_var = ivtvfb_check_var, .fb_set_par = ivtvfb_set_par, .fb_setcolreg = ivtvfb_setcolreg, diff --git a/drivers/media/video/m52790.c b/drivers/media/video/m52790.c index 8e0160d275ca..39bf6b114d50 100644 --- a/drivers/media/video/m52790.c +++ b/drivers/media/video/m52790.c @@ -171,4 +171,3 @@ static struct v4l2_i2c_driver_data v4l2_i2c_data = { .remove = m52790_remove, .id_table = m52790_id, }; - diff --git a/drivers/media/video/meye.c b/drivers/media/video/meye.c index e7ccbc895d7a..2fb5854cf6f0 100644 --- a/drivers/media/video/meye.c +++ b/drivers/media/video/meye.c @@ -1253,7 +1253,7 @@ static int vidioc_g_ctrl(struct file *file, void *fh, struct v4l2_control *c) return 0; } -static int vidioc_enum_fmt_cap(struct file *file, void *fh, +static int vidioc_enum_fmt_vid_cap(struct file *file, void *fh, struct v4l2_fmtdesc *f) { if (f->index > 1) @@ -1283,7 +1283,7 @@ static int vidioc_enum_fmt_cap(struct file *file, void *fh, return 0; } -static int vidioc_try_fmt_cap(struct file *file, void *fh, +static int vidioc_try_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *f) { if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) @@ -1316,7 +1316,8 @@ static int vidioc_try_fmt_cap(struct file *file, void *fh, return 0; } -static int vidioc_g_fmt_cap(struct file *file, void *fh, struct v4l2_format *f) +static int vidioc_g_fmt_vid_cap(struct file *file, void *fh, + struct v4l2_format *f) { if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) return -EINVAL; @@ -1346,7 +1347,8 @@ static int vidioc_g_fmt_cap(struct file *file, void *fh, struct v4l2_format *f) return 0; } -static int vidioc_s_fmt_cap(struct file *file, void *fh, struct v4l2_format *f) +static int vidioc_s_fmt_vid_cap(struct file *file, void *fh, + struct v4l2_format *f) { if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) return -EINVAL; @@ -1709,10 +1711,10 @@ static struct video_device meye_template = { .vidioc_queryctrl = vidioc_queryctrl, .vidioc_s_ctrl = vidioc_s_ctrl, .vidioc_g_ctrl = vidioc_g_ctrl, - .vidioc_enum_fmt_cap = vidioc_enum_fmt_cap, - .vidioc_try_fmt_cap = vidioc_try_fmt_cap, - .vidioc_g_fmt_cap = vidioc_g_fmt_cap, - .vidioc_s_fmt_cap = vidioc_s_fmt_cap, + .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap, + .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap, + .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap, + .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap, .vidioc_reqbufs = vidioc_reqbufs, .vidioc_querybuf = vidioc_querybuf, .vidioc_qbuf = vidioc_qbuf, diff --git a/drivers/media/video/msp3400-driver.c b/drivers/media/video/msp3400-driver.c index 310dbaba55ff..5691e019d195 100644 --- a/drivers/media/video/msp3400-driver.c +++ b/drivers/media/video/msp3400-driver.c @@ -110,6 +110,7 @@ MODULE_PARM_DESC(dolby, "Activates Dolby processsing"); /* Addresses to scan */ static unsigned short normal_i2c[] = { 0x80 >> 1, 0x88 >> 1, I2C_CLIENT_END }; + I2C_CLIENT_INSMOD; /* ----------------------------------------------------------------------- */ @@ -333,7 +334,6 @@ void msp_set_audio(struct i2c_client *client) /* ------------------------------------------------------------------------ */ - static void msp_wake_thread(struct i2c_client *client) { struct msp_state *state = i2c_get_clientdata(client); @@ -1004,7 +1004,6 @@ static struct v4l2_i2c_driver_data v4l2_i2c_data = { .id_table = msp_id, }; - /* * Overrides for Emacs so that we follow Linus's tabbing style. * --------------------------------------------------------------------------- diff --git a/drivers/media/video/msp3400-kthreads.c b/drivers/media/video/msp3400-kthreads.c index 7f5568592793..1622f70e4dd0 100644 --- a/drivers/media/video/msp3400-kthreads.c +++ b/drivers/media/video/msp3400-kthreads.c @@ -480,7 +480,6 @@ int msp3400c_thread(void *data) struct msp3400c_carrier_detect *cd; int count, max1, max2, val1, val2, val, i; - v4l_dbg(1, msp_debug, client, "msp3400 daemon started\n"); set_freezable(); for (;;) { diff --git a/drivers/media/video/mt9v022.c b/drivers/media/video/mt9v022.c index 1658fe590392..b31ba4e09327 100644 --- a/drivers/media/video/mt9v022.c +++ b/drivers/media/video/mt9v022.c @@ -815,7 +815,6 @@ static int mt9v022_remove(struct i2c_client *client) return 0; } - static const struct i2c_device_id mt9v022_id[] = { { "mt9v022", 0 }, { } diff --git a/drivers/media/video/ov7670.c b/drivers/media/video/ov7670.c index d7bfd30f74a9..ea032f5f2f41 100644 --- a/drivers/media/video/ov7670.c +++ b/drivers/media/video/ov7670.c @@ -682,17 +682,17 @@ static int ov7670_try_fmt(struct i2c_client *c, struct v4l2_format *fmt, for (index = 0; index < N_OV7670_FMTS; index++) if (ov7670_formats[index].pixelformat == pix->pixelformat) break; - if (index >= N_OV7670_FMTS) - return -EINVAL; + if (index >= N_OV7670_FMTS) { + /* default to first format */ + index = 0; + pix->pixelformat = ov7670_formats[0].pixelformat; + } if (ret_fmt != NULL) *ret_fmt = ov7670_formats + index; /* * Fields: the OV devices claim to be progressive. */ - if (pix->field == V4L2_FIELD_ANY) - pix->field = V4L2_FIELD_NONE; - else if (pix->field != V4L2_FIELD_NONE) - return -EINVAL; + pix->field = V4L2_FIELD_NONE; /* * Round requested image size down to the nearest * we support, but not below the smallest. @@ -833,7 +833,7 @@ static int ov7670_store_cmatrix(struct i2c_client *client, int matrix[CMATRIX_LEN]) { int i, ret; - unsigned char signbits; + unsigned char signbits = 0; /* * Weird crap seems to exist in the upper part of @@ -1009,7 +1009,7 @@ static unsigned char ov7670_abs_to_sm(unsigned char v) static int ov7670_t_brightness(struct i2c_client *client, int value) { - unsigned char com8, v; + unsigned char com8 = 0, v; int ret; ov7670_read(client, REG_COM8, &com8); @@ -1022,7 +1022,7 @@ static int ov7670_t_brightness(struct i2c_client *client, int value) static int ov7670_q_brightness(struct i2c_client *client, __s32 *value) { - unsigned char v; + unsigned char v = 0; int ret = ov7670_read(client, REG_BRIGHT, &v); *value = ov7670_sm_to_abs(v); @@ -1036,7 +1036,7 @@ static int ov7670_t_contrast(struct i2c_client *client, int value) static int ov7670_q_contrast(struct i2c_client *client, __s32 *value) { - unsigned char v; + unsigned char v = 0; int ret = ov7670_read(client, REG_CONTRAS, &v); *value = v; @@ -1046,7 +1046,7 @@ static int ov7670_q_contrast(struct i2c_client *client, __s32 *value) static int ov7670_q_hflip(struct i2c_client *client, __s32 *value) { int ret; - unsigned char v; + unsigned char v = 0; ret = ov7670_read(client, REG_MVFP, &v); *value = (v & MVFP_MIRROR) == MVFP_MIRROR; @@ -1056,7 +1056,7 @@ static int ov7670_q_hflip(struct i2c_client *client, __s32 *value) static int ov7670_t_hflip(struct i2c_client *client, int value) { - unsigned char v; + unsigned char v = 0; int ret; ret = ov7670_read(client, REG_MVFP, &v); @@ -1074,7 +1074,7 @@ static int ov7670_t_hflip(struct i2c_client *client, int value) static int ov7670_q_vflip(struct i2c_client *client, __s32 *value) { int ret; - unsigned char v; + unsigned char v = 0; ret = ov7670_read(client, REG_MVFP, &v); *value = (v & MVFP_FLIP) == MVFP_FLIP; @@ -1084,7 +1084,7 @@ static int ov7670_q_vflip(struct i2c_client *client, __s32 *value) static int ov7670_t_vflip(struct i2c_client *client, int value) { - unsigned char v; + unsigned char v = 0; int ret; ret = ov7670_read(client, REG_MVFP, &v); diff --git a/drivers/media/video/ovcamchip/ovcamchip_core.c b/drivers/media/video/ovcamchip/ovcamchip_core.c index 8063e33f1c85..065c2454113e 100644 --- a/drivers/media/video/ovcamchip/ovcamchip_core.c +++ b/drivers/media/video/ovcamchip/ovcamchip_core.c @@ -297,7 +297,6 @@ static int ovcamchip_attach(struct i2c_adapter *adap) switch (adap->id) { case I2C_HW_SMBUS_OV511: case I2C_HW_SMBUS_OV518: - case I2C_HW_SMBUS_OVFX2: case I2C_HW_SMBUS_W9968CF: PDEBUG(1, "Adapter ID 0x%06x accepted", adap->id); break; diff --git a/drivers/media/video/pvrusb2/pvrusb2-audio.c b/drivers/media/video/pvrusb2/pvrusb2-audio.c index 8d859ccd48ec..cdedaa55f152 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-audio.c +++ b/drivers/media/video/pvrusb2/pvrusb2-audio.c @@ -1,6 +1,5 @@ /* * - * $Id$ * * Copyright (C) 2005 Mike Isely <isely@pobox.com> * Copyright (C) 2004 Aurelien Alleaume <slts@free.fr> diff --git a/drivers/media/video/pvrusb2/pvrusb2-audio.h b/drivers/media/video/pvrusb2/pvrusb2-audio.h index 536339b68843..ac54eed3721b 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-audio.h +++ b/drivers/media/video/pvrusb2/pvrusb2-audio.h @@ -1,6 +1,5 @@ /* * - * $Id$ * * Copyright (C) 2005 Mike Isely <isely@pobox.com> * Copyright (C) 2004 Aurelien Alleaume <slts@free.fr> diff --git a/drivers/media/video/pvrusb2/pvrusb2-context.c b/drivers/media/video/pvrusb2/pvrusb2-context.c index 73dcb1c57ae6..7c19ff72e6b3 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-context.c +++ b/drivers/media/video/pvrusb2/pvrusb2-context.c @@ -1,5 +1,4 @@ /* - * $Id$ * * Copyright (C) 2005 Mike Isely <isely@pobox.com> * diff --git a/drivers/media/video/pvrusb2/pvrusb2-context.h b/drivers/media/video/pvrusb2/pvrusb2-context.h index 745e270233c2..61801291c2af 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-context.h +++ b/drivers/media/video/pvrusb2/pvrusb2-context.h @@ -1,5 +1,4 @@ /* - * $Id$ * * Copyright (C) 2005 Mike Isely <isely@pobox.com> * diff --git a/drivers/media/video/pvrusb2/pvrusb2-ctrl.c b/drivers/media/video/pvrusb2/pvrusb2-ctrl.c index 91a42f2473a7..0764fbfffb73 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-ctrl.c +++ b/drivers/media/video/pvrusb2/pvrusb2-ctrl.c @@ -1,6 +1,5 @@ /* * - * $Id$ * * Copyright (C) 2005 Mike Isely <isely@pobox.com> * diff --git a/drivers/media/video/pvrusb2/pvrusb2-ctrl.h b/drivers/media/video/pvrusb2/pvrusb2-ctrl.h index c1680053cd64..0371ae6e6e4e 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-ctrl.h +++ b/drivers/media/video/pvrusb2/pvrusb2-ctrl.h @@ -1,6 +1,5 @@ /* * - * $Id$ * * Copyright (C) 2005 Mike Isely <isely@pobox.com> * diff --git a/drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.c b/drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.c index 29d50597c88a..895859ec495a 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.c +++ b/drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.c @@ -1,6 +1,5 @@ /* * - * $Id$ * * Copyright (C) 2005 Mike Isely <isely@pobox.com> * Copyright (C) 2004 Aurelien Alleaume <slts@free.fr> diff --git a/drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.h b/drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.h index 54b2844e7a71..66abf77f51fd 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.h +++ b/drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.h @@ -1,6 +1,5 @@ /* * - * $Id$ * * Copyright (C) 2005 Mike Isely <isely@pobox.com> * Copyright (C) 2004 Aurelien Alleaume <slts@free.fr> diff --git a/drivers/media/video/pvrusb2/pvrusb2-debug.h b/drivers/media/video/pvrusb2/pvrusb2-debug.h index 707d2d9635d7..be79249f8628 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-debug.h +++ b/drivers/media/video/pvrusb2/pvrusb2-debug.h @@ -1,5 +1,4 @@ /* - * $Id$ * * Copyright (C) 2005 Mike Isely <isely@pobox.com> * diff --git a/drivers/media/video/pvrusb2/pvrusb2-debugifc.c b/drivers/media/video/pvrusb2/pvrusb2-debugifc.c index b53121c78ff9..ca892fb78a5b 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-debugifc.c +++ b/drivers/media/video/pvrusb2/pvrusb2-debugifc.c @@ -1,6 +1,5 @@ /* * - * $Id$ * * Copyright (C) 2005 Mike Isely <isely@pobox.com> * diff --git a/drivers/media/video/pvrusb2/pvrusb2-debugifc.h b/drivers/media/video/pvrusb2/pvrusb2-debugifc.h index 990b02d35d36..e24ff59f8605 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-debugifc.h +++ b/drivers/media/video/pvrusb2/pvrusb2-debugifc.h @@ -1,6 +1,5 @@ /* * - * $Id$ * * Copyright (C) 2005 Mike Isely <isely@pobox.com> * diff --git a/drivers/media/video/pvrusb2/pvrusb2-devattr.c b/drivers/media/video/pvrusb2/pvrusb2-devattr.c index 5bf6d8fda1f9..5d036e7e3f07 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-devattr.c +++ b/drivers/media/video/pvrusb2/pvrusb2-devattr.c @@ -1,6 +1,5 @@ /* * - * $Id$ * * Copyright (C) 2007 Mike Isely <isely@pobox.com> * @@ -182,7 +181,7 @@ static int pvr2_lgh06xf_attach(struct pvr2_dvb_adapter *adap) return 0; } -struct pvr2_dvb_props pvr2_onair_creator_fe_props = { +static struct pvr2_dvb_props pvr2_onair_creator_fe_props = { .frontend_attach = pvr2_lgdt3303_attach, .tuner_attach = pvr2_lgh06xf_attach, }; @@ -242,7 +241,7 @@ static int pvr2_fcv1236d_attach(struct pvr2_dvb_adapter *adap) return 0; } -struct pvr2_dvb_props pvr2_onair_usb2_fe_props = { +static struct pvr2_dvb_props pvr2_onair_usb2_fe_props = { .frontend_attach = pvr2_lgdt3302_attach, .tuner_attach = pvr2_fcv1236d_attach, }; @@ -315,7 +314,7 @@ static int pvr2_73xxx_tda18271_8295_attach(struct pvr2_dvb_adapter *adap) return 0; } -struct pvr2_dvb_props pvr2_73xxx_dvb_props = { +static struct pvr2_dvb_props pvr2_73xxx_dvb_props = { .frontend_attach = pvr2_tda10048_attach, .tuner_attach = pvr2_73xxx_tda18271_8295_attach, }; @@ -418,12 +417,12 @@ static int pvr2_tda18271_8295_attach(struct pvr2_dvb_adapter *adap) return 0; } -struct pvr2_dvb_props pvr2_750xx_dvb_props = { +static struct pvr2_dvb_props pvr2_750xx_dvb_props = { .frontend_attach = pvr2_s5h1409_attach, .tuner_attach = pvr2_tda18271_8295_attach, }; -struct pvr2_dvb_props pvr2_751xx_dvb_props = { +static struct pvr2_dvb_props pvr2_751xx_dvb_props = { .frontend_attach = pvr2_s5h1411_attach, .tuner_attach = pvr2_tda18271_8295_attach, }; diff --git a/drivers/media/video/pvrusb2/pvrusb2-devattr.h b/drivers/media/video/pvrusb2/pvrusb2-devattr.h index d016f8b6c70b..e23ce1d2edd7 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-devattr.h +++ b/drivers/media/video/pvrusb2/pvrusb2-devattr.h @@ -1,6 +1,5 @@ /* * - * $Id$ * * Copyright (C) 2005 Mike Isely <isely@pobox.com> * diff --git a/drivers/media/video/pvrusb2/pvrusb2-eeprom.c b/drivers/media/video/pvrusb2/pvrusb2-eeprom.c index 5ef005947b04..299afa4fa969 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-eeprom.c +++ b/drivers/media/video/pvrusb2/pvrusb2-eeprom.c @@ -1,6 +1,5 @@ /* * - * $Id$ * * Copyright (C) 2005 Mike Isely <isely@pobox.com> * Copyright (C) 2004 Aurelien Alleaume <slts@free.fr> diff --git a/drivers/media/video/pvrusb2/pvrusb2-eeprom.h b/drivers/media/video/pvrusb2/pvrusb2-eeprom.h index 84242975dea7..cca3216f94cc 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-eeprom.h +++ b/drivers/media/video/pvrusb2/pvrusb2-eeprom.h @@ -1,6 +1,5 @@ /* * - * $Id$ * * Copyright (C) 2005 Mike Isely <isely@pobox.com> * Copyright (C) 2004 Aurelien Alleaume <slts@free.fr> diff --git a/drivers/media/video/pvrusb2/pvrusb2-encoder.c b/drivers/media/video/pvrusb2/pvrusb2-encoder.c index c46d367f7472..a1252d673b41 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-encoder.c +++ b/drivers/media/video/pvrusb2/pvrusb2-encoder.c @@ -1,6 +1,5 @@ /* * - * $Id$ * * Copyright (C) 2005 Mike Isely <isely@pobox.com> * Copyright (C) 2004 Aurelien Alleaume <slts@free.fr> diff --git a/drivers/media/video/pvrusb2/pvrusb2-encoder.h b/drivers/media/video/pvrusb2/pvrusb2-encoder.h index 54caf2e3c428..232fefbcd1ac 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-encoder.h +++ b/drivers/media/video/pvrusb2/pvrusb2-encoder.h @@ -1,6 +1,5 @@ /* * - * $Id$ * * Copyright (C) 2005 Mike Isely <isely@pobox.com> * Copyright (C) 2004 Aurelien Alleaume <slts@free.fr> diff --git a/drivers/media/video/pvrusb2/pvrusb2-fx2-cmd.h b/drivers/media/video/pvrusb2/pvrusb2-fx2-cmd.h index abaada31e66e..b58369e7f30b 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-fx2-cmd.h +++ b/drivers/media/video/pvrusb2/pvrusb2-fx2-cmd.h @@ -1,6 +1,5 @@ /* * - * $Id$ * * Copyright (C) 2007 Michael Krufky <mkrufky@linuxtv.org> * diff --git a/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h b/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h index a3fe251d6fd9..657f861593b3 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h +++ b/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h @@ -1,6 +1,5 @@ /* * - * $Id$ * * Copyright (C) 2005 Mike Isely <isely@pobox.com> * diff --git a/drivers/media/video/pvrusb2/pvrusb2-hdw.c b/drivers/media/video/pvrusb2/pvrusb2-hdw.c index 0a868888f389..a5217a2cf4c0 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-hdw.c +++ b/drivers/media/video/pvrusb2/pvrusb2-hdw.c @@ -1,6 +1,5 @@ /* * - * $Id$ * * Copyright (C) 2005 Mike Isely <isely@pobox.com> * @@ -40,6 +39,23 @@ #define TV_MIN_FREQ 55250000L #define TV_MAX_FREQ 850000000L +/* This defines a minimum interval that the decoder must remain quiet + before we are allowed to start it running. */ +#define TIME_MSEC_DECODER_WAIT 50 + +/* This defines a minimum interval that the encoder must remain quiet + before we are allowed to configure it. I had this originally set to + 50msec, but Martin Dauskardt <martin.dauskardt@gmx.de> reports that + things work better when it's set to 100msec. */ +#define TIME_MSEC_ENCODER_WAIT 100 + +/* This defines the minimum interval that the encoder must successfully run + before we consider that the encoder has run at least once since its + firmware has been loaded. This measurement is in important for cases + where we can't do something until we know that the encoder has been run + at least once. */ +#define TIME_MSEC_ENCODER_OK 250 + static struct pvr2_hdw *unit_pointers[PVR_NUM] = {[ 0 ... PVR_NUM-1 ] = NULL}; static DEFINE_MUTEX(pvr2_unit_mtx); @@ -67,6 +83,16 @@ MODULE_PARM_DESC(video_std,"specify initial video standard"); module_param_array(tolerance, int, NULL, 0444); MODULE_PARM_DESC(tolerance,"specify stream error tolerance"); +/* US Broadcast channel 7 (175.25 MHz) */ +static int default_tv_freq = 175250000L; +/* 104.3 MHz, a usable FM station for my area */ +static int default_radio_freq = 104300000L; + +module_param_named(tv_freq, default_tv_freq, int, 0444); +MODULE_PARM_DESC(tv_freq, "specify initial television frequency"); +module_param_named(radio_freq, default_radio_freq, int, 0444); +MODULE_PARM_DESC(radio_freq, "specify initial radio frequency"); + #define PVR2_CTL_WRITE_ENDPOINT 0x01 #define PVR2_CTL_READ_ENDPOINT 0x81 @@ -1701,10 +1727,8 @@ static void pvr2_hdw_setup_low(struct pvr2_hdw *hdw) are, but I set them to something usable in the Chicago area just to make driver testing a little easier. */ - /* US Broadcast channel 7 (175.25 MHz) */ - hdw->freqValTelevision = 175250000L; - /* 104.3 MHz, a usable FM station for my area */ - hdw->freqValRadio = 104300000L; + hdw->freqValTelevision = default_tv_freq; + hdw->freqValRadio = default_radio_freq; // Do not use pvr2_reset_ctl_endpoints() here. It is not // thread-safe against the normal pvr2_send_request() mechanism. @@ -1989,7 +2013,8 @@ struct pvr2_hdw *pvr2_hdw_create(struct usb_interface *intf, case V4L2_CTRL_TYPE_MENU: ciptr->type = pvr2_ctl_enum; ciptr->def.type_enum.value_names = - cx2341x_ctrl_get_menu(ciptr->v4l_id); + cx2341x_ctrl_get_menu(&hdw->enc_ctl_state, + ciptr->v4l_id); for (cnt1 = 0; ciptr->def.type_enum.value_names[cnt1] != NULL; cnt1++) { } @@ -2428,22 +2453,38 @@ static int pvr2_hdw_commit_execute(struct pvr2_hdw *hdw) struct pvr2_ctrl *cptr; int disruptive_change; - /* When video standard changes, reset the hres and vres values - - but if the user has pending changes there, then let the changes - take priority. */ + /* Handle some required side effects when the video standard is + changed.... */ if (hdw->std_dirty) { - /* Rewrite the vertical resolution to be appropriate to the - video standard that has been selected. */ int nvres; + int gop_size; if (hdw->std_mask_cur & V4L2_STD_525_60) { nvres = 480; + gop_size = 15; } else { nvres = 576; + gop_size = 12; } + /* Rewrite the vertical resolution to be appropriate to the + video standard that has been selected. */ if (nvres != hdw->res_ver_val) { hdw->res_ver_val = nvres; hdw->res_ver_dirty = !0; } + /* Rewrite the GOP size to be appropriate to the video + standard that has been selected. */ + if (gop_size != hdw->enc_ctl_state.video_gop_size) { + struct v4l2_ext_controls cs; + struct v4l2_ext_control c1; + memset(&cs, 0, sizeof(cs)); + memset(&c1, 0, sizeof(c1)); + cs.controls = &c1; + cs.count = 1; + c1.id = V4L2_CID_MPEG_VIDEO_GOP_SIZE; + c1.value = gop_size; + cx2341x_ext_ctrls(&hdw->enc_ctl_state, 0, &cs, + VIDIOC_S_EXT_CTRLS); + } } if (hdw->input_dirty && hdw->state_pathway_ok && @@ -3421,7 +3462,7 @@ static void pvr2_hdw_cmd_modeswitch(struct pvr2_hdw *hdw,int digitalFl) } -void pvr2_led_ctrl_hauppauge(struct pvr2_hdw *hdw, int onoff) +static void pvr2_led_ctrl_hauppauge(struct pvr2_hdw *hdw, int onoff) { /* change some GPIO data * @@ -3601,7 +3642,9 @@ static int state_eval_encoder_config(struct pvr2_hdw *hdw) the encoder. */ if (!hdw->state_encoder_waitok) { hdw->encoder_wait_timer.expires = - jiffies + (HZ*50/1000); + jiffies + + (HZ * TIME_MSEC_ENCODER_WAIT + / 1000); add_timer(&hdw->encoder_wait_timer); } } @@ -3725,7 +3768,7 @@ static int state_eval_encoder_run(struct pvr2_hdw *hdw) hdw->state_encoder_run = !0; if (!hdw->state_encoder_runok) { hdw->encoder_run_timer.expires = - jiffies + (HZ*250/1000); + jiffies + (HZ * TIME_MSEC_ENCODER_OK / 1000); add_timer(&hdw->encoder_run_timer); } } @@ -3800,7 +3843,9 @@ static int state_eval_decoder_run(struct pvr2_hdw *hdw) but before we did the pending check. */ if (!hdw->state_decoder_quiescent) { hdw->quiescent_timer.expires = - jiffies + (HZ*50/1000); + jiffies + + (HZ * TIME_MSEC_DECODER_WAIT + / 1000); add_timer(&hdw->quiescent_timer); } } diff --git a/drivers/media/video/pvrusb2/pvrusb2-hdw.h b/drivers/media/video/pvrusb2/pvrusb2-hdw.h index 20295e0c1995..c04956d304a7 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-hdw.h +++ b/drivers/media/video/pvrusb2/pvrusb2-hdw.h @@ -1,6 +1,5 @@ /* * - * $Id$ * * Copyright (C) 2005 Mike Isely <isely@pobox.com> * diff --git a/drivers/media/video/pvrusb2/pvrusb2-i2c-chips-v4l2.c b/drivers/media/video/pvrusb2/pvrusb2-i2c-chips-v4l2.c index 49773764383b..ccdb429fc7af 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-i2c-chips-v4l2.c +++ b/drivers/media/video/pvrusb2/pvrusb2-i2c-chips-v4l2.c @@ -1,6 +1,5 @@ /* * - * $Id$ * * Copyright (C) 2005 Mike Isely <isely@pobox.com> * diff --git a/drivers/media/video/pvrusb2/pvrusb2-i2c-cmd-v4l2.c b/drivers/media/video/pvrusb2/pvrusb2-i2c-cmd-v4l2.c index c650e02ccd00..55f04a0b2047 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-i2c-cmd-v4l2.c +++ b/drivers/media/video/pvrusb2/pvrusb2-i2c-cmd-v4l2.c @@ -1,6 +1,5 @@ /* * - * $Id$ * * Copyright (C) 2005 Mike Isely <isely@pobox.com> * Copyright (C) 2004 Aurelien Alleaume <slts@free.fr> diff --git a/drivers/media/video/pvrusb2/pvrusb2-i2c-cmd-v4l2.h b/drivers/media/video/pvrusb2/pvrusb2-i2c-cmd-v4l2.h index c838df6167f9..7fa38683b3b1 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-i2c-cmd-v4l2.h +++ b/drivers/media/video/pvrusb2/pvrusb2-i2c-cmd-v4l2.h @@ -1,6 +1,5 @@ /* * - * $Id$ * * Copyright (C) 2005 Mike Isely <isely@pobox.com> * Copyright (C) 2004 Aurelien Alleaume <slts@free.fr> diff --git a/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c b/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c index 793c89a8d672..9d3c18b24744 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c +++ b/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c @@ -1,6 +1,5 @@ /* * - * $Id$ * * Copyright (C) 2005 Mike Isely <isely@pobox.com> * diff --git a/drivers/media/video/pvrusb2/pvrusb2-i2c-core.h b/drivers/media/video/pvrusb2/pvrusb2-i2c-core.h index bd0807b905bb..6ef7a1c0e935 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-i2c-core.h +++ b/drivers/media/video/pvrusb2/pvrusb2-i2c-core.h @@ -1,6 +1,5 @@ /* * - * $Id$ * * Copyright (C) 2005 Mike Isely <isely@pobox.com> * diff --git a/drivers/media/video/pvrusb2/pvrusb2-io.c b/drivers/media/video/pvrusb2/pvrusb2-io.c index 7aff8b720064..20b6ae0bb40d 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-io.c +++ b/drivers/media/video/pvrusb2/pvrusb2-io.c @@ -1,6 +1,5 @@ /* * - * $Id$ * * Copyright (C) 2005 Mike Isely <isely@pobox.com> * diff --git a/drivers/media/video/pvrusb2/pvrusb2-io.h b/drivers/media/video/pvrusb2/pvrusb2-io.h index 42fcf8281a87..afb7e87c0394 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-io.h +++ b/drivers/media/video/pvrusb2/pvrusb2-io.h @@ -1,6 +1,5 @@ /* * - * $Id$ * * Copyright (C) 2005 Mike Isely <isely@pobox.com> * diff --git a/drivers/media/video/pvrusb2/pvrusb2-ioread.c b/drivers/media/video/pvrusb2/pvrusb2-ioread.c index c572212c9f15..05a1376405e7 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-ioread.c +++ b/drivers/media/video/pvrusb2/pvrusb2-ioread.c @@ -1,6 +1,5 @@ /* * - * $Id$ * * Copyright (C) 2005 Mike Isely <isely@pobox.com> * diff --git a/drivers/media/video/pvrusb2/pvrusb2-ioread.h b/drivers/media/video/pvrusb2/pvrusb2-ioread.h index 1d362f833588..100e0780e1aa 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-ioread.h +++ b/drivers/media/video/pvrusb2/pvrusb2-ioread.h @@ -1,6 +1,5 @@ /* * - * $Id$ * * Copyright (C) 2005 Mike Isely <isely@pobox.com> * diff --git a/drivers/media/video/pvrusb2/pvrusb2-main.c b/drivers/media/video/pvrusb2/pvrusb2-main.c index 332aced8a5a1..ad0d98c2ebb4 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-main.c +++ b/drivers/media/video/pvrusb2/pvrusb2-main.c @@ -1,6 +1,5 @@ /* * - * $Id$ * * Copyright (C) 2005 Mike Isely <isely@pobox.com> * Copyright (C) 2004 Aurelien Alleaume <slts@free.fr> diff --git a/drivers/media/video/pvrusb2/pvrusb2-std.c b/drivers/media/video/pvrusb2/pvrusb2-std.c index fdc5a2b49ca8..ca9f83a85ca5 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-std.c +++ b/drivers/media/video/pvrusb2/pvrusb2-std.c @@ -1,6 +1,5 @@ /* * - * $Id$ * * Copyright (C) 2005 Mike Isely <isely@pobox.com> * diff --git a/drivers/media/video/pvrusb2/pvrusb2-std.h b/drivers/media/video/pvrusb2/pvrusb2-std.h index 07c399375341..a35c53d0b320 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-std.h +++ b/drivers/media/video/pvrusb2/pvrusb2-std.h @@ -1,6 +1,5 @@ /* * - * $Id$ * * Copyright (C) 2005 Mike Isely <isely@pobox.com> * diff --git a/drivers/media/video/pvrusb2/pvrusb2-sysfs.c b/drivers/media/video/pvrusb2/pvrusb2-sysfs.c index 0ff7a836a8a2..46a8c39ba030 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-sysfs.c +++ b/drivers/media/video/pvrusb2/pvrusb2-sysfs.c @@ -1,6 +1,5 @@ /* * - * $Id$ * * Copyright (C) 2005 Mike Isely <isely@pobox.com> * @@ -71,6 +70,7 @@ struct pvr2_sysfs_ctl_item { struct device_attribute attr_val; struct device_attribute attr_custom; struct pvr2_ctrl *cptr; + int ctl_id; struct pvr2_sysfs *chptr; struct pvr2_sysfs_ctl_item *item_next; struct attribute *attr_gen[7]; @@ -83,38 +83,29 @@ struct pvr2_sysfs_class { struct class class; }; -static ssize_t show_name(int id,struct device *class_dev,char *buf) +static ssize_t show_name(struct device *class_dev, + struct device_attribute *attr, + char *buf) { - struct pvr2_ctrl *cptr; - struct pvr2_sysfs *sfp; + struct pvr2_sysfs_ctl_item *cip; const char *name; - - sfp = (struct pvr2_sysfs *)class_dev->driver_data; - if (!sfp) return -EINVAL; - cptr = pvr2_hdw_get_ctrl_by_index(sfp->channel.hdw,id); - if (!cptr) return -EINVAL; - - name = pvr2_ctrl_get_desc(cptr); - pvr2_sysfs_trace("pvr2_sysfs(%p) show_name(cid=%d) is %s",sfp,id,name); - + cip = container_of(attr, struct pvr2_sysfs_ctl_item, attr_name); + name = pvr2_ctrl_get_desc(cip->cptr); + pvr2_sysfs_trace("pvr2_sysfs(%p) show_name(cid=%d) is %s", + cip->chptr, cip->ctl_id, name); if (!name) return -EINVAL; - - return scnprintf(buf,PAGE_SIZE,"%s\n",name); + return scnprintf(buf, PAGE_SIZE, "%s\n", name); } -static ssize_t show_type(int id,struct device *class_dev,char *buf) +static ssize_t show_type(struct device *class_dev, + struct device_attribute *attr, + char *buf) { - struct pvr2_ctrl *cptr; - struct pvr2_sysfs *sfp; + struct pvr2_sysfs_ctl_item *cip; const char *name; enum pvr2_ctl_type tp; - - sfp = (struct pvr2_sysfs *)class_dev->driver_data; - if (!sfp) return -EINVAL; - cptr = pvr2_hdw_get_ctrl_by_index(sfp->channel.hdw,id); - if (!cptr) return -EINVAL; - - tp = pvr2_ctrl_get_type(cptr); + cip = container_of(attr, struct pvr2_sysfs_ctl_item, attr_type); + tp = pvr2_ctrl_get_type(cip->cptr); switch (tp) { case pvr2_ctl_int: name = "integer"; break; case pvr2_ctl_enum: name = "enum"; break; @@ -122,403 +113,178 @@ static ssize_t show_type(int id,struct device *class_dev,char *buf) case pvr2_ctl_bool: name = "boolean"; break; default: name = "?"; break; } - pvr2_sysfs_trace("pvr2_sysfs(%p) show_type(cid=%d) is %s",sfp,id,name); - + pvr2_sysfs_trace("pvr2_sysfs(%p) show_type(cid=%d) is %s", + cip->chptr, cip->ctl_id, name); if (!name) return -EINVAL; - - return scnprintf(buf,PAGE_SIZE,"%s\n",name); + return scnprintf(buf, PAGE_SIZE, "%s\n", name); } -static ssize_t show_min(int id,struct device *class_dev,char *buf) +static ssize_t show_min(struct device *class_dev, + struct device_attribute *attr, + char *buf) { - struct pvr2_ctrl *cptr; - struct pvr2_sysfs *sfp; + struct pvr2_sysfs_ctl_item *cip; long val; - - sfp = (struct pvr2_sysfs *)class_dev->driver_data; - if (!sfp) return -EINVAL; - cptr = pvr2_hdw_get_ctrl_by_index(sfp->channel.hdw,id); - if (!cptr) return -EINVAL; - val = pvr2_ctrl_get_min(cptr); - - pvr2_sysfs_trace("pvr2_sysfs(%p) show_min(cid=%d) is %ld",sfp,id,val); - - return scnprintf(buf,PAGE_SIZE,"%ld\n",val); + cip = container_of(attr, struct pvr2_sysfs_ctl_item, attr_min); + val = pvr2_ctrl_get_min(cip->cptr); + pvr2_sysfs_trace("pvr2_sysfs(%p) show_min(cid=%d) is %ld", + cip->chptr, cip->ctl_id, val); + return scnprintf(buf, PAGE_SIZE, "%ld\n", val); } -static ssize_t show_max(int id,struct device *class_dev,char *buf) +static ssize_t show_max(struct device *class_dev, + struct device_attribute *attr, + char *buf) { - struct pvr2_ctrl *cptr; - struct pvr2_sysfs *sfp; + struct pvr2_sysfs_ctl_item *cip; long val; - - sfp = (struct pvr2_sysfs *)class_dev->driver_data; - if (!sfp) return -EINVAL; - cptr = pvr2_hdw_get_ctrl_by_index(sfp->channel.hdw,id); - if (!cptr) return -EINVAL; - val = pvr2_ctrl_get_max(cptr); - - pvr2_sysfs_trace("pvr2_sysfs(%p) show_max(cid=%d) is %ld",sfp,id,val); - - return scnprintf(buf,PAGE_SIZE,"%ld\n",val); + cip = container_of(attr, struct pvr2_sysfs_ctl_item, attr_max); + val = pvr2_ctrl_get_max(cip->cptr); + pvr2_sysfs_trace("pvr2_sysfs(%p) show_max(cid=%d) is %ld", + cip->chptr, cip->ctl_id, val); + return scnprintf(buf, PAGE_SIZE, "%ld\n", val); } -static ssize_t show_val_norm(int id,struct device *class_dev,char *buf) +static ssize_t show_val_norm(struct device *class_dev, + struct device_attribute *attr, + char *buf) { - struct pvr2_ctrl *cptr; - struct pvr2_sysfs *sfp; - int val,ret; + struct pvr2_sysfs_ctl_item *cip; + int val; + int ret; unsigned int cnt = 0; - - sfp = (struct pvr2_sysfs *)class_dev->driver_data; - if (!sfp) return -EINVAL; - cptr = pvr2_hdw_get_ctrl_by_index(sfp->channel.hdw,id); - if (!cptr) return -EINVAL; - - ret = pvr2_ctrl_get_value(cptr,&val); + cip = container_of(attr, struct pvr2_sysfs_ctl_item, attr_val); + ret = pvr2_ctrl_get_value(cip->cptr, &val); if (ret < 0) return ret; - - ret = pvr2_ctrl_value_to_sym(cptr,~0,val, - buf,PAGE_SIZE-1,&cnt); - + ret = pvr2_ctrl_value_to_sym(cip->cptr, ~0, val, + buf, PAGE_SIZE - 1, &cnt); pvr2_sysfs_trace("pvr2_sysfs(%p) show_val_norm(cid=%d) is %.*s (%d)", - sfp,id,cnt,buf,val); + cip->chptr, cip->ctl_id, cnt, buf, val); buf[cnt] = '\n'; return cnt+1; } -static ssize_t show_val_custom(int id,struct device *class_dev,char *buf) +static ssize_t show_val_custom(struct device *class_dev, + struct device_attribute *attr, + char *buf) { - struct pvr2_ctrl *cptr; - struct pvr2_sysfs *sfp; - int val,ret; + struct pvr2_sysfs_ctl_item *cip; + int val; + int ret; unsigned int cnt = 0; - - sfp = (struct pvr2_sysfs *)class_dev->driver_data; - if (!sfp) return -EINVAL; - cptr = pvr2_hdw_get_ctrl_by_index(sfp->channel.hdw,id); - if (!cptr) return -EINVAL; - - ret = pvr2_ctrl_get_value(cptr,&val); + cip = container_of(attr, struct pvr2_sysfs_ctl_item, attr_custom); + ret = pvr2_ctrl_get_value(cip->cptr, &val); if (ret < 0) return ret; - - ret = pvr2_ctrl_custom_value_to_sym(cptr,~0,val, - buf,PAGE_SIZE-1,&cnt); - + ret = pvr2_ctrl_custom_value_to_sym(cip->cptr, ~0, val, + buf, PAGE_SIZE - 1, &cnt); pvr2_sysfs_trace("pvr2_sysfs(%p) show_val_custom(cid=%d) is %.*s (%d)", - sfp,id,cnt,buf,val); + cip->chptr, cip->ctl_id, cnt, buf, val); buf[cnt] = '\n'; return cnt+1; } -static ssize_t show_enum(int id,struct device *class_dev,char *buf) +static ssize_t show_enum(struct device *class_dev, + struct device_attribute *attr, + char *buf) { - struct pvr2_ctrl *cptr; - struct pvr2_sysfs *sfp; + struct pvr2_sysfs_ctl_item *cip; long val; - unsigned int bcnt,ccnt,ecnt; - - sfp = (struct pvr2_sysfs *)class_dev->driver_data; - if (!sfp) return -EINVAL; - cptr = pvr2_hdw_get_ctrl_by_index(sfp->channel.hdw,id); - if (!cptr) return -EINVAL; - ecnt = pvr2_ctrl_get_cnt(cptr); + unsigned int bcnt, ccnt, ecnt; + cip = container_of(attr, struct pvr2_sysfs_ctl_item, attr_enum); + ecnt = pvr2_ctrl_get_cnt(cip->cptr); bcnt = 0; for (val = 0; val < ecnt; val++) { - pvr2_ctrl_get_valname(cptr,val,buf+bcnt,PAGE_SIZE-bcnt,&ccnt); + pvr2_ctrl_get_valname(cip->cptr, val, buf + bcnt, + PAGE_SIZE - bcnt, &ccnt); if (!ccnt) continue; bcnt += ccnt; if (bcnt >= PAGE_SIZE) break; buf[bcnt] = '\n'; bcnt++; } - pvr2_sysfs_trace("pvr2_sysfs(%p) show_enum(cid=%d)",sfp,id); + pvr2_sysfs_trace("pvr2_sysfs(%p) show_enum(cid=%d)", + cip->chptr, cip->ctl_id); return bcnt; } -static ssize_t show_bits(int id,struct device *class_dev,char *buf) +static ssize_t show_bits(struct device *class_dev, + struct device_attribute *attr, + char *buf) { - struct pvr2_ctrl *cptr; - struct pvr2_sysfs *sfp; - int valid_bits,msk; - unsigned int bcnt,ccnt; - - sfp = (struct pvr2_sysfs *)class_dev->driver_data; - if (!sfp) return -EINVAL; - cptr = pvr2_hdw_get_ctrl_by_index(sfp->channel.hdw,id); - if (!cptr) return -EINVAL; - valid_bits = pvr2_ctrl_get_mask(cptr); + struct pvr2_sysfs_ctl_item *cip; + int valid_bits, msk; + unsigned int bcnt, ccnt; + cip = container_of(attr, struct pvr2_sysfs_ctl_item, attr_bits); + valid_bits = pvr2_ctrl_get_mask(cip->cptr); bcnt = 0; for (msk = 1; valid_bits; msk <<= 1) { if (!(msk & valid_bits)) continue; valid_bits &= ~msk; - pvr2_ctrl_get_valname(cptr,msk,buf+bcnt,PAGE_SIZE-bcnt,&ccnt); + pvr2_ctrl_get_valname(cip->cptr, msk, buf + bcnt, + PAGE_SIZE - bcnt, &ccnt); bcnt += ccnt; if (bcnt >= PAGE_SIZE) break; buf[bcnt] = '\n'; bcnt++; } - pvr2_sysfs_trace("pvr2_sysfs(%p) show_bits(cid=%d)",sfp,id); + pvr2_sysfs_trace("pvr2_sysfs(%p) show_bits(cid=%d)", + cip->chptr, cip->ctl_id); return bcnt; } -static int store_val_any(int id,int customfl,struct pvr2_sysfs *sfp, +static int store_val_any(struct pvr2_sysfs_ctl_item *cip, int customfl, const char *buf,unsigned int count) { - struct pvr2_ctrl *cptr; int ret; int mask,val; - - cptr = pvr2_hdw_get_ctrl_by_index(sfp->channel.hdw,id); if (customfl) { - ret = pvr2_ctrl_custom_sym_to_value(cptr,buf,count,&mask,&val); + ret = pvr2_ctrl_custom_sym_to_value(cip->cptr, buf, count, + &mask, &val); } else { - ret = pvr2_ctrl_sym_to_value(cptr,buf,count,&mask,&val); + ret = pvr2_ctrl_sym_to_value(cip->cptr, buf, count, + &mask, &val); } if (ret < 0) return ret; - ret = pvr2_ctrl_set_mask_value(cptr,mask,val); - pvr2_hdw_commit_ctl(sfp->channel.hdw); + ret = pvr2_ctrl_set_mask_value(cip->cptr, mask, val); + pvr2_hdw_commit_ctl(cip->chptr->channel.hdw); return ret; } -static ssize_t store_val_norm(int id,struct device *class_dev, - const char *buf,size_t count) +static ssize_t store_val_norm(struct device *class_dev, + struct device_attribute *attr, + const char *buf, size_t count) { - struct pvr2_sysfs *sfp; + struct pvr2_sysfs_ctl_item *cip; int ret; - sfp = (struct pvr2_sysfs *)class_dev->driver_data; + cip = container_of(attr, struct pvr2_sysfs_ctl_item, attr_val); pvr2_sysfs_trace("pvr2_sysfs(%p) store_val_norm(cid=%d) \"%.*s\"", - sfp,id,(int)count,buf); - ret = store_val_any(id,0,sfp,buf,count); + cip->chptr, cip->ctl_id, (int)count, buf); + ret = store_val_any(cip, 0, buf, count); if (!ret) ret = count; return ret; } -static ssize_t store_val_custom(int id,struct device *class_dev, - const char *buf,size_t count) +static ssize_t store_val_custom(struct device *class_dev, + struct device_attribute *attr, + const char *buf, size_t count) { - struct pvr2_sysfs *sfp; + struct pvr2_sysfs_ctl_item *cip; int ret; - sfp = (struct pvr2_sysfs *)class_dev->driver_data; + cip = container_of(attr, struct pvr2_sysfs_ctl_item, attr_custom); pvr2_sysfs_trace("pvr2_sysfs(%p) store_val_custom(cid=%d) \"%.*s\"", - sfp,id,(int)count,buf); - ret = store_val_any(id,1,sfp,buf,count); + cip->chptr, cip->ctl_id, (int)count, buf); + ret = store_val_any(cip, 1, buf, count); if (!ret) ret = count; return ret; } -/* - Mike Isely <isely@pobox.com> 30-April-2005 - - This next batch of horrible preprocessor hackery is needed because the - kernel's device_attribute mechanism fails to pass the actual - attribute through to the show / store functions, which means we have no - way to package up any attribute-specific parameters, like for example the - control id. So we work around this brain-damage by encoding the control - id into the show / store functions themselves and pick the function based - on the control id we're setting up. These macros try to ease the pain. - Yuck. -*/ - -#define CREATE_SHOW_INSTANCE(sf_name,ctl_id) \ -static ssize_t sf_name##_##ctl_id(struct device *class_dev, \ -struct device_attribute *attr, char *buf) \ -{ return sf_name(ctl_id,class_dev,buf); } - -#define CREATE_STORE_INSTANCE(sf_name,ctl_id) \ -static ssize_t sf_name##_##ctl_id(struct device *class_dev, \ -struct device_attribute *attr, const char *buf, size_t count) \ -{ return sf_name(ctl_id,class_dev,buf,count); } - -#define CREATE_BATCH(ctl_id) \ -CREATE_SHOW_INSTANCE(show_name,ctl_id) \ -CREATE_SHOW_INSTANCE(show_type,ctl_id) \ -CREATE_SHOW_INSTANCE(show_min,ctl_id) \ -CREATE_SHOW_INSTANCE(show_max,ctl_id) \ -CREATE_SHOW_INSTANCE(show_val_norm,ctl_id) \ -CREATE_SHOW_INSTANCE(show_val_custom,ctl_id) \ -CREATE_SHOW_INSTANCE(show_enum,ctl_id) \ -CREATE_SHOW_INSTANCE(show_bits,ctl_id) \ -CREATE_STORE_INSTANCE(store_val_norm,ctl_id) \ -CREATE_STORE_INSTANCE(store_val_custom,ctl_id) \ - -CREATE_BATCH(0) -CREATE_BATCH(1) -CREATE_BATCH(2) -CREATE_BATCH(3) -CREATE_BATCH(4) -CREATE_BATCH(5) -CREATE_BATCH(6) -CREATE_BATCH(7) -CREATE_BATCH(8) -CREATE_BATCH(9) -CREATE_BATCH(10) -CREATE_BATCH(11) -CREATE_BATCH(12) -CREATE_BATCH(13) -CREATE_BATCH(14) -CREATE_BATCH(15) -CREATE_BATCH(16) -CREATE_BATCH(17) -CREATE_BATCH(18) -CREATE_BATCH(19) -CREATE_BATCH(20) -CREATE_BATCH(21) -CREATE_BATCH(22) -CREATE_BATCH(23) -CREATE_BATCH(24) -CREATE_BATCH(25) -CREATE_BATCH(26) -CREATE_BATCH(27) -CREATE_BATCH(28) -CREATE_BATCH(29) -CREATE_BATCH(30) -CREATE_BATCH(31) -CREATE_BATCH(32) -CREATE_BATCH(33) -CREATE_BATCH(34) -CREATE_BATCH(35) -CREATE_BATCH(36) -CREATE_BATCH(37) -CREATE_BATCH(38) -CREATE_BATCH(39) -CREATE_BATCH(40) -CREATE_BATCH(41) -CREATE_BATCH(42) -CREATE_BATCH(43) -CREATE_BATCH(44) -CREATE_BATCH(45) -CREATE_BATCH(46) -CREATE_BATCH(47) -CREATE_BATCH(48) -CREATE_BATCH(49) -CREATE_BATCH(50) -CREATE_BATCH(51) -CREATE_BATCH(52) -CREATE_BATCH(53) -CREATE_BATCH(54) -CREATE_BATCH(55) -CREATE_BATCH(56) -CREATE_BATCH(57) -CREATE_BATCH(58) -CREATE_BATCH(59) - -struct pvr2_sysfs_func_set { - ssize_t (*show_name)(struct device *, - struct device_attribute *attr, char *); - ssize_t (*show_type)(struct device *, - struct device_attribute *attr, char *); - ssize_t (*show_min)(struct device *, - struct device_attribute *attr, char *); - ssize_t (*show_max)(struct device *, - struct device_attribute *attr, char *); - ssize_t (*show_enum)(struct device *, - struct device_attribute *attr, char *); - ssize_t (*show_bits)(struct device *, - struct device_attribute *attr, char *); - ssize_t (*show_val_norm)(struct device *, - struct device_attribute *attr, char *); - ssize_t (*store_val_norm)(struct device *, - struct device_attribute *attr, - const char *,size_t); - ssize_t (*show_val_custom)(struct device *, - struct device_attribute *attr, char *); - ssize_t (*store_val_custom)(struct device *, - struct device_attribute *attr, - const char *,size_t); -}; - -#define INIT_BATCH(ctl_id) \ -[ctl_id] = { \ - .show_name = show_name_##ctl_id, \ - .show_type = show_type_##ctl_id, \ - .show_min = show_min_##ctl_id, \ - .show_max = show_max_##ctl_id, \ - .show_enum = show_enum_##ctl_id, \ - .show_bits = show_bits_##ctl_id, \ - .show_val_norm = show_val_norm_##ctl_id, \ - .store_val_norm = store_val_norm_##ctl_id, \ - .show_val_custom = show_val_custom_##ctl_id, \ - .store_val_custom = store_val_custom_##ctl_id, \ -} \ - -static struct pvr2_sysfs_func_set funcs[] = { - INIT_BATCH(0), - INIT_BATCH(1), - INIT_BATCH(2), - INIT_BATCH(3), - INIT_BATCH(4), - INIT_BATCH(5), - INIT_BATCH(6), - INIT_BATCH(7), - INIT_BATCH(8), - INIT_BATCH(9), - INIT_BATCH(10), - INIT_BATCH(11), - INIT_BATCH(12), - INIT_BATCH(13), - INIT_BATCH(14), - INIT_BATCH(15), - INIT_BATCH(16), - INIT_BATCH(17), - INIT_BATCH(18), - INIT_BATCH(19), - INIT_BATCH(20), - INIT_BATCH(21), - INIT_BATCH(22), - INIT_BATCH(23), - INIT_BATCH(24), - INIT_BATCH(25), - INIT_BATCH(26), - INIT_BATCH(27), - INIT_BATCH(28), - INIT_BATCH(29), - INIT_BATCH(30), - INIT_BATCH(31), - INIT_BATCH(32), - INIT_BATCH(33), - INIT_BATCH(34), - INIT_BATCH(35), - INIT_BATCH(36), - INIT_BATCH(37), - INIT_BATCH(38), - INIT_BATCH(39), - INIT_BATCH(40), - INIT_BATCH(41), - INIT_BATCH(42), - INIT_BATCH(43), - INIT_BATCH(44), - INIT_BATCH(45), - INIT_BATCH(46), - INIT_BATCH(47), - INIT_BATCH(48), - INIT_BATCH(49), - INIT_BATCH(50), - INIT_BATCH(51), - INIT_BATCH(52), - INIT_BATCH(53), - INIT_BATCH(54), - INIT_BATCH(55), - INIT_BATCH(56), - INIT_BATCH(57), - INIT_BATCH(58), - INIT_BATCH(59), -}; - - static void pvr2_sysfs_add_control(struct pvr2_sysfs *sfp,int ctl_id) { struct pvr2_sysfs_ctl_item *cip; - struct pvr2_sysfs_func_set *fp; struct pvr2_ctrl *cptr; unsigned int cnt,acnt; int ret; - if ((ctl_id < 0) || (ctl_id >= ARRAY_SIZE(funcs))) { - return; - } - - fp = funcs + ctl_id; cptr = pvr2_hdw_get_ctrl_by_index(sfp->channel.hdw,ctl_id); if (!cptr) return; @@ -527,6 +293,7 @@ static void pvr2_sysfs_add_control(struct pvr2_sysfs *sfp,int ctl_id) pvr2_sysfs_trace("Creating pvr2_sysfs_ctl_item id=%p",cip); cip->cptr = cptr; + cip->ctl_id = ctl_id; cip->chptr = sfp; cip->item_next = NULL; @@ -539,19 +306,19 @@ static void pvr2_sysfs_add_control(struct pvr2_sysfs *sfp,int ctl_id) cip->attr_name.attr.name = "name"; cip->attr_name.attr.mode = S_IRUGO; - cip->attr_name.show = fp->show_name; + cip->attr_name.show = show_name; cip->attr_type.attr.name = "type"; cip->attr_type.attr.mode = S_IRUGO; - cip->attr_type.show = fp->show_type; + cip->attr_type.show = show_type; cip->attr_min.attr.name = "min_val"; cip->attr_min.attr.mode = S_IRUGO; - cip->attr_min.show = fp->show_min; + cip->attr_min.show = show_min; cip->attr_max.attr.name = "max_val"; cip->attr_max.attr.mode = S_IRUGO; - cip->attr_max.show = fp->show_max; + cip->attr_max.show = show_max; cip->attr_val.attr.name = "cur_val"; cip->attr_val.attr.mode = S_IRUGO; @@ -561,11 +328,11 @@ static void pvr2_sysfs_add_control(struct pvr2_sysfs *sfp,int ctl_id) cip->attr_enum.attr.name = "enum_val"; cip->attr_enum.attr.mode = S_IRUGO; - cip->attr_enum.show = fp->show_enum; + cip->attr_enum.show = show_enum; cip->attr_bits.attr.name = "bit_val"; cip->attr_bits.attr.mode = S_IRUGO; - cip->attr_bits.show = fp->show_bits; + cip->attr_bits.show = show_bits; if (pvr2_ctrl_is_writable(cptr)) { cip->attr_val.attr.mode |= S_IWUSR|S_IWGRP; @@ -576,12 +343,12 @@ static void pvr2_sysfs_add_control(struct pvr2_sysfs *sfp,int ctl_id) cip->attr_gen[acnt++] = &cip->attr_name.attr; cip->attr_gen[acnt++] = &cip->attr_type.attr; cip->attr_gen[acnt++] = &cip->attr_val.attr; - cip->attr_val.show = fp->show_val_norm; - cip->attr_val.store = fp->store_val_norm; + cip->attr_val.show = show_val_norm; + cip->attr_val.store = store_val_norm; if (pvr2_ctrl_has_custom_symbols(cptr)) { cip->attr_gen[acnt++] = &cip->attr_custom.attr; - cip->attr_custom.show = fp->show_val_custom; - cip->attr_custom.store = fp->store_val_custom; + cip->attr_custom.show = show_val_custom; + cip->attr_custom.store = store_val_custom; } switch (pvr2_ctrl_get_type(cptr)) { case pvr2_ctl_enum: diff --git a/drivers/media/video/pvrusb2/pvrusb2-sysfs.h b/drivers/media/video/pvrusb2/pvrusb2-sysfs.h index ff9373b47f8f..6d875bfe7991 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-sysfs.h +++ b/drivers/media/video/pvrusb2/pvrusb2-sysfs.h @@ -1,6 +1,5 @@ /* * - * $Id$ * * Copyright (C) 2005 Mike Isely <isely@pobox.com> * diff --git a/drivers/media/video/pvrusb2/pvrusb2-tuner.c b/drivers/media/video/pvrusb2/pvrusb2-tuner.c index 05e65ce2e3a9..07775d1aad4e 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-tuner.c +++ b/drivers/media/video/pvrusb2/pvrusb2-tuner.c @@ -1,6 +1,5 @@ /* * - * $Id$ * * Copyright (C) 2005 Mike Isely <isely@pobox.com> * Copyright (C) 2004 Aurelien Alleaume <slts@free.fr> diff --git a/drivers/media/video/pvrusb2/pvrusb2-tuner.h b/drivers/media/video/pvrusb2/pvrusb2-tuner.h index 556f12aa9160..ef4afaf37b0a 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-tuner.h +++ b/drivers/media/video/pvrusb2/pvrusb2-tuner.h @@ -1,6 +1,5 @@ /* * - * $Id$ * * Copyright (C) 2005 Mike Isely <isely@pobox.com> * diff --git a/drivers/media/video/pvrusb2/pvrusb2-util.h b/drivers/media/video/pvrusb2/pvrusb2-util.h index e53aee416f56..92b75544ee2e 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-util.h +++ b/drivers/media/video/pvrusb2/pvrusb2-util.h @@ -1,6 +1,5 @@ /* * - * $Id$ * * Copyright (C) 2005 Mike Isely <isely@pobox.com> * diff --git a/drivers/media/video/pvrusb2/pvrusb2-v4l2.c b/drivers/media/video/pvrusb2/pvrusb2-v4l2.c index e9b5d4e91327..0d72dc470fef 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-v4l2.c +++ b/drivers/media/video/pvrusb2/pvrusb2-v4l2.c @@ -1,6 +1,5 @@ /* * - * $Id$ * * Copyright (C) 2005 Mike Isely <isely@pobox.com> * Copyright (C) 2004 Aurelien Alleaume <slts@free.fr> diff --git a/drivers/media/video/pvrusb2/pvrusb2-v4l2.h b/drivers/media/video/pvrusb2/pvrusb2-v4l2.h index 9a995e2d2256..34c011a7b107 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-v4l2.h +++ b/drivers/media/video/pvrusb2/pvrusb2-v4l2.h @@ -1,6 +1,5 @@ /* * - * $Id$ * * Copyright (C) 2005 Mike Isely <isely@pobox.com> * diff --git a/drivers/media/video/pvrusb2/pvrusb2-video-v4l.c b/drivers/media/video/pvrusb2/pvrusb2-video-v4l.c index 2433a3160041..4059648c7056 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-video-v4l.c +++ b/drivers/media/video/pvrusb2/pvrusb2-video-v4l.c @@ -1,6 +1,5 @@ /* * - * $Id$ * * Copyright (C) 2005 Mike Isely <isely@pobox.com> * Copyright (C) 2004 Aurelien Alleaume <slts@free.fr> diff --git a/drivers/media/video/pvrusb2/pvrusb2-video-v4l.h b/drivers/media/video/pvrusb2/pvrusb2-video-v4l.h index 2b917fda02e4..4ff5b892b303 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-video-v4l.h +++ b/drivers/media/video/pvrusb2/pvrusb2-video-v4l.h @@ -1,6 +1,5 @@ /* * - * $Id$ * * Copyright (C) 2005 Mike Isely <isely@pobox.com> * Copyright (C) 2004 Aurelien Alleaume <slts@free.fr> diff --git a/drivers/media/video/pvrusb2/pvrusb2-wm8775.c b/drivers/media/video/pvrusb2/pvrusb2-wm8775.c index 66b4d36ef765..f6fcf0ac6118 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-wm8775.c +++ b/drivers/media/video/pvrusb2/pvrusb2-wm8775.c @@ -1,6 +1,5 @@ /* * - * $Id$ * * Copyright (C) 2005 Mike Isely <isely@pobox.com> * Copyright (C) 2004 Aurelien Alleaume <slts@free.fr> diff --git a/drivers/media/video/pvrusb2/pvrusb2-wm8775.h b/drivers/media/video/pvrusb2/pvrusb2-wm8775.h index 8aaeff4e1e20..807090961255 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-wm8775.h +++ b/drivers/media/video/pvrusb2/pvrusb2-wm8775.h @@ -1,6 +1,5 @@ /* * - * $Id$ * * Copyright (C) 2005 Mike Isely <isely@pobox.com> * Copyright (C) 2004 Aurelien Alleaume <slts@free.fr> diff --git a/drivers/media/video/pvrusb2/pvrusb2.h b/drivers/media/video/pvrusb2/pvrusb2.h index 1a9a4baf12b8..240de9b35661 100644 --- a/drivers/media/video/pvrusb2/pvrusb2.h +++ b/drivers/media/video/pvrusb2/pvrusb2.h @@ -1,6 +1,5 @@ /* * - * $Id$ * * Copyright (C) 2005 Mike Isely <isely@pobox.com> * Copyright (C) 2004 Aurelien Alleaume <slts@free.fr> diff --git a/drivers/media/video/pwc/pwc-ctrl.c b/drivers/media/video/pwc/pwc-ctrl.c index ea53316d2111..1cccd5c77048 100644 --- a/drivers/media/video/pwc/pwc-ctrl.c +++ b/drivers/media/video/pwc/pwc-ctrl.c @@ -1255,7 +1255,6 @@ int pwc_get_cmos_sensor(struct pwc_device *pdev, int *sensor) exactly the same otherwise. */ - /* define local variable for arg */ #define ARG_DEF(ARG_type, ARG_name)\ ARG_type *ARG_name = arg; @@ -1268,7 +1267,6 @@ int pwc_get_cmos_sensor(struct pwc_device *pdev, int *sensor) /* copy local variable to arg */ #define ARG_OUT(ARG_name) /* nothing */ - int pwc_ioctl(struct pwc_device *pdev, unsigned int cmd, void *arg) { int ret = 0; diff --git a/drivers/media/video/pwc/pwc-ioctl.h b/drivers/media/video/pwc/pwc-ioctl.h index cec660299768..8c0cae7b3daf 100644 --- a/drivers/media/video/pwc/pwc-ioctl.h +++ b/drivers/media/video/pwc/pwc-ioctl.h @@ -54,7 +54,6 @@ #include <linux/types.h> #include <linux/version.h> - /* Enumeration of image sizes */ #define PSZ_SQCIF 0x00 #define PSZ_QSIF 0x01 diff --git a/drivers/media/video/pxa_camera.c b/drivers/media/video/pxa_camera.c index 5ec5bb9a94d2..b15f82c49766 100644 --- a/drivers/media/video/pxa_camera.c +++ b/drivers/media/video/pxa_camera.c @@ -30,6 +30,7 @@ #include <media/v4l2-common.h> #include <media/v4l2-dev.h> +#include <media/videobuf-dma-sg.h> #include <media/soc_camera.h> #include <linux/videodev2.h> @@ -582,6 +583,19 @@ static struct videobuf_queue_ops pxa_videobuf_ops = { .buf_release = pxa_videobuf_release, }; +static void pxa_camera_init_videobuf(struct videobuf_queue *q, + struct soc_camera_device *icd) +{ + struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); + struct pxa_camera_dev *pcdev = ici->priv; + + /* We must pass NULL as dev pointer, then all pci_* dma operations + * transform to normal dma_* ones. */ + videobuf_queue_sg_init(q, &pxa_videobuf_ops, NULL, &pcdev->lock, + V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_FIELD_NONE, + sizeof(struct pxa_buffer), icd); +} + static int mclk_get_divisor(struct pxa_camera_dev *pcdev) { unsigned int mclk_10khz = pcdev->platform_mclk_10khz; @@ -983,34 +997,23 @@ static int pxa_camera_querycap(struct soc_camera_host *ici, return 0; } -static spinlock_t *pxa_camera_spinlock_alloc(struct soc_camera_file *icf) -{ - struct soc_camera_host *ici = - to_soc_camera_host(icf->icd->dev.parent); - struct pxa_camera_dev *pcdev = ici->priv; - - return &pcdev->lock; -} - static struct soc_camera_host_ops pxa_soc_camera_host_ops = { .owner = THIS_MODULE, .add = pxa_camera_add_device, .remove = pxa_camera_remove_device, .set_fmt_cap = pxa_camera_set_fmt_cap, .try_fmt_cap = pxa_camera_try_fmt_cap, + .init_videobuf = pxa_camera_init_videobuf, .reqbufs = pxa_camera_reqbufs, .poll = pxa_camera_poll, .querycap = pxa_camera_querycap, .try_bus_param = pxa_camera_try_bus_param, .set_bus_param = pxa_camera_set_bus_param, - .spinlock_alloc = pxa_camera_spinlock_alloc, }; /* Should be allocated dynamically too, but we have only one. */ static struct soc_camera_host pxa_soc_camera_host = { .drv_name = PXA_CAM_DRV_NAME, - .vbq_ops = &pxa_videobuf_ops, - .msize = sizeof(struct pxa_buffer), .ops = &pxa_soc_camera_host_ops, }; diff --git a/drivers/media/video/s2255drv.c b/drivers/media/video/s2255drv.c new file mode 100644 index 000000000000..04eb2c3fabd8 --- /dev/null +++ b/drivers/media/video/s2255drv.c @@ -0,0 +1,2495 @@ +/* + * s2255drv.c - a driver for the Sensoray 2255 USB video capture device + * + * Copyright (C) 2007-2008 by Sensoray Company Inc. + * Dean Anderson + * + * Some video buffer code based on vivi driver: + * + * Sensoray 2255 device supports 4 simultaneous channels. + * The channels are not "crossbar" inputs, they are physically + * attached to separate video decoders. + * + * Because of USB2.0 bandwidth limitations. There is only a + * certain amount of data which may be transferred at one time. + * + * Example maximum bandwidth utilization: + * + * -full size, color mode YUYV or YUV422P: 2 channels at once + * + * -full or half size Grey scale: all 4 channels at once + * + * -half size, color mode YUYV or YUV422P: all 4 channels at once + * + * -full size, color mode YUYV or YUV422P 1/2 frame rate: all 4 channels + * at once. + * (TODO: Incorporate videodev2 frame rate(FR) enumeration, + * which is currently experimental.) + * + * 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. + */ + +#include <linux/module.h> +#include <linux/firmware.h> +#include <linux/kernel.h> +#include <linux/mutex.h> +#include <linux/videodev2.h> +#include <linux/version.h> +#include <media/videobuf-vmalloc.h> +#include <media/v4l2-common.h> +#include <linux/vmalloc.h> +#include <linux/usb.h> + +#define FIRMWARE_FILE_NAME "f2255usb.bin" + + + +/* vendor request in */ +#define S2255_VR_IN 0 +/* vendor request out */ +#define S2255_VR_OUT 1 +/* firmware query */ +#define S2255_VR_FW 0x30 +/* USB endpoint number for configuring the device */ +#define S2255_CONFIG_EP 2 +/* maximum time for DSP to start responding after last FW word loaded(ms) */ +#define S2255_DSP_BOOTTIME 400 +/* maximum time to wait for firmware to load (ms) */ +#define S2255_LOAD_TIMEOUT (5000 + S2255_DSP_BOOTTIME) +#define S2255_DEF_BUFS 16 +#define MAX_CHANNELS 4 +#define FRAME_MARKER 0x2255DA4AL +#define MAX_PIPE_USBBLOCK (40 * 1024) +#define DEFAULT_PIPE_USBBLOCK (16 * 1024) +#define MAX_CHANNELS 4 +#define MAX_PIPE_BUFFERS 1 +#define SYS_FRAMES 4 +/* maximum size is PAL full size plus room for the marker header(s) */ +#define SYS_FRAMES_MAXSIZE (720 * 288 * 2 * 2 + 4096) +#define DEF_USB_BLOCK (4096) +#define LINE_SZ_4CIFS_NTSC 640 +#define LINE_SZ_2CIFS_NTSC 640 +#define LINE_SZ_1CIFS_NTSC 320 +#define LINE_SZ_4CIFS_PAL 704 +#define LINE_SZ_2CIFS_PAL 704 +#define LINE_SZ_1CIFS_PAL 352 +#define NUM_LINES_4CIFS_NTSC 240 +#define NUM_LINES_2CIFS_NTSC 240 +#define NUM_LINES_1CIFS_NTSC 240 +#define NUM_LINES_4CIFS_PAL 288 +#define NUM_LINES_2CIFS_PAL 288 +#define NUM_LINES_1CIFS_PAL 288 +#define LINE_SZ_DEF 640 +#define NUM_LINES_DEF 240 + + +/* predefined settings */ +#define FORMAT_NTSC 1 +#define FORMAT_PAL 2 + +#define SCALE_4CIFS 1 /* 640x480(NTSC) or 704x576(PAL) */ +#define SCALE_2CIFS 2 /* 640x240(NTSC) or 704x288(PAL) */ +#define SCALE_1CIFS 3 /* 320x240(NTSC) or 352x288(PAL) */ + +#define COLOR_YUVPL 1 /* YUV planar */ +#define COLOR_YUVPK 2 /* YUV packed */ +#define COLOR_Y8 4 /* monochrome */ + +/* frame decimation. Not implemented by V4L yet(experimental in V4L) */ +#define FDEC_1 1 /* capture every frame. default */ +#define FDEC_2 2 /* capture every 2nd frame */ +#define FDEC_3 3 /* capture every 3rd frame */ +#define FDEC_5 5 /* capture every 5th frame */ + +/*------------------------------------------------------- + * Default mode parameters. + *-------------------------------------------------------*/ +#define DEF_SCALE SCALE_4CIFS +#define DEF_COLOR COLOR_YUVPL +#define DEF_FDEC FDEC_1 +#define DEF_BRIGHT 0 +#define DEF_CONTRAST 0x5c +#define DEF_SATURATION 0x80 +#define DEF_HUE 0 + +/* usb config commands */ +#define IN_DATA_TOKEN 0x2255c0de +#define CMD_2255 0xc2255000 +#define CMD_SET_MODE (CMD_2255 | 0x10) +#define CMD_START (CMD_2255 | 0x20) +#define CMD_STOP (CMD_2255 | 0x30) +#define CMD_STATUS (CMD_2255 | 0x40) + +struct s2255_mode { + u32 format; /* input video format (NTSC, PAL) */ + u32 scale; /* output video scale */ + u32 color; /* output video color format */ + u32 fdec; /* frame decimation */ + u32 bright; /* brightness */ + u32 contrast; /* contrast */ + u32 saturation; /* saturation */ + u32 hue; /* hue (NTSC only)*/ + u32 single; /* capture 1 frame at a time (!=0), continuously (==0)*/ + u32 usb_block; /* block size. should be 4096 of DEF_USB_BLOCK */ + u32 restart; /* if DSP requires restart */ +}; + +/* frame structure */ +#define FRAME_STATE_UNUSED 0 +#define FRAME_STATE_FILLING 1 +#define FRAME_STATE_FULL 2 + + +struct s2255_framei { + unsigned long size; + + unsigned long ulState; /* ulState ==0 unused, 1 being filled, 2 full */ + void *lpvbits; /* image data */ + unsigned long cur_size; /* current data copied to it */ +}; + +/* image buffer structure */ +struct s2255_bufferi { + unsigned long dwFrames; /* number of frames in buffer */ + struct s2255_framei frame[SYS_FRAMES]; /* array of FRAME structures */ +}; + +#define DEF_MODEI_NTSC_CONT {FORMAT_NTSC, DEF_SCALE, DEF_COLOR, \ + DEF_FDEC, DEF_BRIGHT, DEF_CONTRAST, DEF_SATURATION, \ + DEF_HUE, 0, DEF_USB_BLOCK, 0} + +struct s2255_dmaqueue { + struct list_head active; + /* thread for acquisition */ + struct task_struct *kthread; + int frame; + struct s2255_dev *dev; + int channel; +}; + +/* for firmware loading, fw_state */ +#define S2255_FW_NOTLOADED 0 +#define S2255_FW_LOADED_DSPWAIT 1 +#define S2255_FW_SUCCESS 2 +#define S2255_FW_FAILED 3 + +struct s2255_fw { + int fw_loaded; + int fw_size; + struct urb *fw_urb; + atomic_t fw_state; + void *pfw_data; + wait_queue_head_t wait_fw; + struct timer_list dsp_wait; + const struct firmware *fw; +}; + +struct s2255_pipeinfo { + u32 max_transfer_size; + u32 cur_transfer_size; + u8 *transfer_buffer; + u32 transfer_flags;; + u32 state; + u32 prev_state; + u32 urb_size; + void *stream_urb; + void *dev; /* back pointer to s2255_dev struct*/ + u32 err_count; + u32 buf_index; + u32 idx; + u32 priority_set; +}; + +struct s2255_fmt; /*forward declaration */ + +struct s2255_dev { + int frames; + int users[MAX_CHANNELS]; + struct mutex lock; + struct mutex open_lock; + int resources[MAX_CHANNELS]; + struct usb_device *udev; + struct usb_interface *interface; + u8 read_endpoint; + + struct s2255_dmaqueue vidq[MAX_CHANNELS]; + struct video_device *vdev[MAX_CHANNELS]; + struct list_head s2255_devlist; + struct timer_list timer; + struct s2255_fw *fw_data; + int board_num; + int is_open; + struct s2255_pipeinfo pipes[MAX_PIPE_BUFFERS]; + struct s2255_bufferi buffer[MAX_CHANNELS]; + struct s2255_mode mode[MAX_CHANNELS]; + const struct s2255_fmt *cur_fmt[MAX_CHANNELS]; + int cur_frame[MAX_CHANNELS]; + int last_frame[MAX_CHANNELS]; + u32 cc; /* current channel */ + int b_acquire[MAX_CHANNELS]; + unsigned long req_image_size[MAX_CHANNELS]; + int bad_payload[MAX_CHANNELS]; + unsigned long frame_count[MAX_CHANNELS]; + int frame_ready; + struct kref kref; + spinlock_t slock; +}; +#define to_s2255_dev(d) container_of(d, struct s2255_dev, kref) + +struct s2255_fmt { + char *name; + u32 fourcc; + int depth; +}; + +/* buffer for one video frame */ +struct s2255_buffer { + /* common v4l buffer stuff -- must be first */ + struct videobuf_buffer vb; + const struct s2255_fmt *fmt; +}; + +struct s2255_fh { + struct s2255_dev *dev; + unsigned int resources; + const struct s2255_fmt *fmt; + unsigned int width; + unsigned int height; + struct videobuf_queue vb_vidq; + enum v4l2_buf_type type; + int channel; + /* mode below is the desired mode. + mode in s2255_dev is the current mode that was last set */ + struct s2255_mode mode; +}; + +/* + * TODO: fixme S2255_MAX_USERS. Do not limit open driver handles. + * Limit V4L to one stream at a time. + */ +#define S2255_MAX_USERS 1 + +#define CUR_USB_FWVER 774 /* current cypress EEPROM firmware version */ +#define S2255_MAJOR_VERSION 1 +#define S2255_MINOR_VERSION 13 +#define S2255_RELEASE 0 +#define S2255_VERSION KERNEL_VERSION(S2255_MAJOR_VERSION, \ + S2255_MINOR_VERSION, \ + S2255_RELEASE) + +/* vendor ids */ +#define USB_S2255_VENDOR_ID 0x1943 +#define USB_S2255_PRODUCT_ID 0x2255 +#define S2255_NORMS (V4L2_STD_PAL | V4L2_STD_NTSC) +/* frame prefix size (sent once every frame) */ +#define PREFIX_SIZE 512 + +/* Channels on box are in reverse order */ +static unsigned long G_chnmap[MAX_CHANNELS] = {3, 2, 1, 0}; + +static LIST_HEAD(s2255_devlist); + +static int debug; +static int *s2255_debug = &debug; + +static int s2255_start_readpipe(struct s2255_dev *dev); +static void s2255_stop_readpipe(struct s2255_dev *dev); +static int s2255_start_acquire(struct s2255_dev *dev, unsigned long chn); +static int s2255_stop_acquire(struct s2255_dev *dev, unsigned long chn); +static void s2255_fillbuff(struct s2255_dev *dev, struct s2255_buffer *buf, + int chn); +static int s2255_set_mode(struct s2255_dev *dev, unsigned long chn, + struct s2255_mode *mode); +static int s2255_board_shutdown(struct s2255_dev *dev); +static void s2255_exit_v4l(struct s2255_dev *dev); +static void s2255_fwload_start(struct s2255_dev *dev); + +#define dprintk(level, fmt, arg...) \ + do { \ + if (*s2255_debug >= (level)) { \ + printk(KERN_DEBUG "s2255: " fmt, ##arg); \ + } \ + } while (0) + + +static struct usb_driver s2255_driver; + + +/* Declare static vars that will be used as parameters */ +static unsigned int vid_limit = 16; /* Video memory limit, in Mb */ + +/* start video number */ +static int video_nr = -1; /* /dev/videoN, -1 for autodetect */ + +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "Debug level(0-100) default 0"); +module_param(vid_limit, int, 0644); +MODULE_PARM_DESC(vid_limit, "video memory limit(Mb)"); +module_param(video_nr, int, 0644); +MODULE_PARM_DESC(video_nr, "start video minor(-1 default autodetect)"); + +/* USB device table */ +static struct usb_device_id s2255_table[] = { + {USB_DEVICE(USB_S2255_VENDOR_ID, USB_S2255_PRODUCT_ID)}, + { } /* Terminating entry */ +}; +MODULE_DEVICE_TABLE(usb, s2255_table); + + +#define BUFFER_TIMEOUT msecs_to_jiffies(400) + +/* supported controls */ +static struct v4l2_queryctrl s2255_qctrl[] = { + { + .id = V4L2_CID_BRIGHTNESS, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Brightness", + .minimum = -127, + .maximum = 128, + .step = 1, + .default_value = 0, + .flags = 0, + }, { + .id = V4L2_CID_CONTRAST, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Contrast", + .minimum = 0, + .maximum = 255, + .step = 0x1, + .default_value = DEF_CONTRAST, + .flags = 0, + }, { + .id = V4L2_CID_SATURATION, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Saturation", + .minimum = 0, + .maximum = 255, + .step = 0x1, + .default_value = DEF_SATURATION, + .flags = 0, + }, { + .id = V4L2_CID_HUE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Hue", + .minimum = 0, + .maximum = 255, + .step = 0x1, + .default_value = DEF_HUE, + .flags = 0, + } +}; + +static int qctl_regs[ARRAY_SIZE(s2255_qctrl)]; + +/* image formats. */ +static const struct s2255_fmt formats[] = { + { + .name = "4:2:2, planar, YUV422P", + .fourcc = V4L2_PIX_FMT_YUV422P, + .depth = 16 + + }, { + .name = "4:2:2, packed, YUYV", + .fourcc = V4L2_PIX_FMT_YUYV, + .depth = 16 + + }, { + .name = "4:2:2, packed, UYVY", + .fourcc = V4L2_PIX_FMT_UYVY, + .depth = 16 + }, { + .name = "8bpp GREY", + .fourcc = V4L2_PIX_FMT_GREY, + .depth = 8 + } +}; + +static int norm_maxw(struct video_device *vdev) +{ + return (vdev->current_norm & V4L2_STD_NTSC) ? + LINE_SZ_4CIFS_NTSC : LINE_SZ_4CIFS_PAL; +} + +static int norm_maxh(struct video_device *vdev) +{ + return (vdev->current_norm & V4L2_STD_NTSC) ? + (NUM_LINES_1CIFS_NTSC * 2) : (NUM_LINES_1CIFS_PAL * 2); +} + +static int norm_minw(struct video_device *vdev) +{ + return (vdev->current_norm & V4L2_STD_NTSC) ? + LINE_SZ_1CIFS_NTSC : LINE_SZ_1CIFS_PAL; +} + +static int norm_minh(struct video_device *vdev) +{ + return (vdev->current_norm & V4L2_STD_NTSC) ? + (NUM_LINES_1CIFS_NTSC) : (NUM_LINES_1CIFS_PAL); +} + + +/* + * TODO: fixme: move YUV reordering to hardware + * converts 2255 planar format to yuyv or uyvy + */ +static void planar422p_to_yuv_packed(const unsigned char *in, + unsigned char *out, + int width, int height, + int fmt) +{ + unsigned char *pY; + unsigned char *pCb; + unsigned char *pCr; + unsigned long size = height * width; + unsigned int i; + pY = (unsigned char *)in; + pCr = (unsigned char *)in + height * width; + pCb = (unsigned char *)in + height * width + (height * width / 2); + for (i = 0; i < size * 2; i += 4) { + out[i] = (fmt == V4L2_PIX_FMT_YUYV) ? *pY++ : *pCr++; + out[i + 1] = (fmt == V4L2_PIX_FMT_YUYV) ? *pCr++ : *pY++; + out[i + 2] = (fmt == V4L2_PIX_FMT_YUYV) ? *pY++ : *pCb++; + out[i + 3] = (fmt == V4L2_PIX_FMT_YUYV) ? *pCb++ : *pY++; + } + return; +} + + +/* kickstarts the firmware loading. from probe + */ +static void s2255_timer(unsigned long user_data) +{ + struct s2255_fw *data = (struct s2255_fw *)user_data; + dprintk(100, "s2255 timer\n"); + if (usb_submit_urb(data->fw_urb, GFP_ATOMIC) < 0) { + printk(KERN_ERR "s2255: can't submit urb\n"); + if (data->fw) { + release_firmware(data->fw); + data->fw = NULL; + } + return; + } +} + +/* called when DSP is up and running. DSP is guaranteed to + be running after S2255_DSP_BOOTTIME */ +static void s2255_dsp_running(unsigned long user_data) +{ + struct s2255_fw *data = (struct s2255_fw *)user_data; + dprintk(1, "dsp running\n"); + atomic_set(&data->fw_state, S2255_FW_SUCCESS); + wake_up(&data->wait_fw); + printk(KERN_INFO "s2255: firmware loaded successfully\n"); + return; +} + + +/* this loads the firmware asynchronously. + Originally this was done synchroously in probe. + But it is better to load it asynchronously here than block + inside the probe function. Blocking inside probe affects boot time. + FW loading is triggered by the timer in the probe function +*/ +static void s2255_fwchunk_complete(struct urb *urb) +{ + struct s2255_fw *data = urb->context; + struct usb_device *udev = urb->dev; + int len; + dprintk(100, "udev %p urb %p", udev, urb); + /* TODO: fixme. reflect change in status */ + if (urb->status) { + dev_err(&udev->dev, "URB failed with status %d", urb->status); + return; + } + if (data->fw_urb == NULL) { + dev_err(&udev->dev, "early disconncect\n"); + return; + } +#define CHUNK_SIZE 512 + /* all USB transfers must be done with continuous kernel memory. + can't allocate more than 128k in current linux kernel, so + upload the firmware in chunks + */ + if (data->fw_loaded < data->fw_size) { + len = (data->fw_loaded + CHUNK_SIZE) > data->fw_size ? + data->fw_size % CHUNK_SIZE : CHUNK_SIZE; + + if (len < CHUNK_SIZE) + memset(data->pfw_data, 0, CHUNK_SIZE); + + dprintk(100, "completed len %d, loaded %d \n", len, + data->fw_loaded); + + memcpy(data->pfw_data, + (char *) data->fw->data + data->fw_loaded, len); + + usb_fill_bulk_urb(data->fw_urb, udev, usb_sndbulkpipe(udev, 2), + data->pfw_data, CHUNK_SIZE, + s2255_fwchunk_complete, data); + if (usb_submit_urb(data->fw_urb, GFP_ATOMIC) < 0) { + dev_err(&udev->dev, "failed submit URB\n"); + atomic_set(&data->fw_state, S2255_FW_FAILED); + /* wake up anything waiting for the firmware */ + wake_up(&data->wait_fw); + return; + } + data->fw_loaded += len; + } else { + init_timer(&data->dsp_wait); + data->dsp_wait.function = s2255_dsp_running; + data->dsp_wait.data = (unsigned long)data; + atomic_set(&data->fw_state, S2255_FW_LOADED_DSPWAIT); + mod_timer(&data->dsp_wait, msecs_to_jiffies(S2255_DSP_BOOTTIME) + + jiffies); + } + dprintk(100, "2255 complete done\n"); + return; + +} + +static int s2255_got_frame(struct s2255_dev *dev, int chn) +{ + struct s2255_dmaqueue *dma_q = &dev->vidq[chn]; + struct s2255_buffer *buf; + unsigned long flags = 0; + int rc = 0; + dprintk(2, "wakeup: %p channel: %d\n", &dma_q, chn); + spin_lock_irqsave(&dev->slock, flags); + + if (list_empty(&dma_q->active)) { + dprintk(1, "No active queue to serve\n"); + rc = -1; + goto unlock; + } + buf = list_entry(dma_q->active.next, + struct s2255_buffer, vb.queue); + + if (!waitqueue_active(&buf->vb.done)) { + /* no one active */ + rc = -1; + goto unlock; + } + list_del(&buf->vb.queue); + do_gettimeofday(&buf->vb.ts); + dprintk(100, "[%p/%d] wakeup\n", buf, buf->vb.i); + + s2255_fillbuff(dev, buf, dma_q->channel); + wake_up(&buf->vb.done); + dprintk(2, "wakeup [buf/i] [%p/%d]\n", buf, buf->vb.i); +unlock: + spin_unlock_irqrestore(&dev->slock, flags); + return 0; +} + + +static const struct s2255_fmt *format_by_fourcc(int fourcc) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(formats); i++) { + if (-1 == formats[i].fourcc) + continue; + if (formats[i].fourcc == fourcc) + return formats + i; + } + return NULL; +} + + + + +/* video buffer vmalloc implementation based partly on VIVI driver which is + * Copyright (c) 2006 by + * Mauro Carvalho Chehab <mchehab--a.t--infradead.org> + * Ted Walther <ted--a.t--enumera.com> + * John Sokol <sokol--a.t--videotechnology.com> + * http://v4l.videotechnology.com/ + * + */ +static void s2255_fillbuff(struct s2255_dev *dev, struct s2255_buffer *buf, + int chn) +{ + int pos = 0; + struct timeval ts; + const char *tmpbuf; + char *vbuf = videobuf_to_vmalloc(&buf->vb); + unsigned long last_frame; + struct s2255_framei *frm; + + if (!vbuf) + return; + + last_frame = dev->last_frame[chn]; + if (last_frame != -1) { + frm = &dev->buffer[chn].frame[last_frame]; + tmpbuf = + (const char *)dev->buffer[chn].frame[last_frame].lpvbits; + switch (buf->fmt->fourcc) { + case V4L2_PIX_FMT_YUYV: + case V4L2_PIX_FMT_UYVY: + planar422p_to_yuv_packed((const unsigned char *)tmpbuf, + vbuf, buf->vb.width, + buf->vb.height, + buf->fmt->fourcc); + break; + case V4L2_PIX_FMT_GREY: + memcpy(vbuf, tmpbuf, buf->vb.width * buf->vb.height); + break; + case V4L2_PIX_FMT_YUV422P: + memcpy(vbuf, tmpbuf, + buf->vb.width * buf->vb.height * 2); + break; + default: + printk(KERN_DEBUG "s2255: unknown format?\n"); + } + dev->last_frame[chn] = -1; + /* done with the frame, free it */ + frm->ulState = 0; + dprintk(4, "freeing buffer\n"); + } else { + printk(KERN_ERR "s2255: =======no frame\n"); + return; + + } + dprintk(2, "s2255fill at : Buffer 0x%08lx size= %d\n", + (unsigned long)vbuf, pos); + /* tell v4l buffer was filled */ + + buf->vb.field_count++; + do_gettimeofday(&ts); + buf->vb.ts = ts; + buf->vb.state = VIDEOBUF_DONE; +} + + +/* ------------------------------------------------------------------ + Videobuf operations + ------------------------------------------------------------------*/ + +static int buffer_setup(struct videobuf_queue *vq, unsigned int *count, + unsigned int *size) +{ + struct s2255_fh *fh = vq->priv_data; + + *size = fh->width * fh->height * (fh->fmt->depth >> 3); + + if (0 == *count) + *count = S2255_DEF_BUFS; + + while (*size * (*count) > vid_limit * 1024 * 1024) + (*count)--; + + return 0; +} + +static void free_buffer(struct videobuf_queue *vq, struct s2255_buffer *buf) +{ + dprintk(4, "%s\n", __func__); + + videobuf_waiton(&buf->vb, 0, 0); + videobuf_vmalloc_free(&buf->vb); + buf->vb.state = VIDEOBUF_NEEDS_INIT; +} + +static int buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb, + enum v4l2_field field) +{ + struct s2255_fh *fh = vq->priv_data; + struct s2255_buffer *buf = container_of(vb, struct s2255_buffer, vb); + int rc; + dprintk(4, "%s, field=%d\n", __func__, field); + if (fh->fmt == NULL) + return -EINVAL; + + if ((fh->width < norm_minw(fh->dev->vdev[fh->channel])) || + (fh->width > norm_maxw(fh->dev->vdev[fh->channel])) || + (fh->height < norm_minh(fh->dev->vdev[fh->channel])) || + (fh->height > norm_maxh(fh->dev->vdev[fh->channel]))) { + dprintk(4, "invalid buffer prepare\n"); + return -EINVAL; + } + + buf->vb.size = fh->width * fh->height * (fh->fmt->depth >> 3); + + if (0 != buf->vb.baddr && buf->vb.bsize < buf->vb.size) { + dprintk(4, "invalid buffer prepare\n"); + return -EINVAL; + } + + buf->fmt = fh->fmt; + buf->vb.width = fh->width; + buf->vb.height = fh->height; + buf->vb.field = field; + + + if (VIDEOBUF_NEEDS_INIT == buf->vb.state) { + rc = videobuf_iolock(vq, &buf->vb, NULL); + if (rc < 0) + goto fail; + } + + buf->vb.state = VIDEOBUF_PREPARED; + return 0; +fail: + free_buffer(vq, buf); + return rc; +} + +static void buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb) +{ + struct s2255_buffer *buf = container_of(vb, struct s2255_buffer, vb); + struct s2255_fh *fh = vq->priv_data; + struct s2255_dev *dev = fh->dev; + struct s2255_dmaqueue *vidq = &dev->vidq[fh->channel]; + + dprintk(1, "%s\n", __func__); + + buf->vb.state = VIDEOBUF_QUEUED; + list_add_tail(&buf->vb.queue, &vidq->active); +} + +static void buffer_release(struct videobuf_queue *vq, + struct videobuf_buffer *vb) +{ + struct s2255_buffer *buf = container_of(vb, struct s2255_buffer, vb); + struct s2255_fh *fh = vq->priv_data; + dprintk(4, "%s %d\n", __func__, fh->channel); + free_buffer(vq, buf); +} + +static struct videobuf_queue_ops s2255_video_qops = { + .buf_setup = buffer_setup, + .buf_prepare = buffer_prepare, + .buf_queue = buffer_queue, + .buf_release = buffer_release, +}; + + +static int res_get(struct s2255_dev *dev, struct s2255_fh *fh) +{ + /* is it free? */ + mutex_lock(&dev->lock); + if (dev->resources[fh->channel]) { + /* no, someone else uses it */ + mutex_unlock(&dev->lock); + return 0; + } + /* it's free, grab it */ + dev->resources[fh->channel] = 1; + dprintk(1, "res: get\n"); + mutex_unlock(&dev->lock); + return 1; +} + +static int res_locked(struct s2255_dev *dev, struct s2255_fh *fh) +{ + return dev->resources[fh->channel]; +} + +static void res_free(struct s2255_dev *dev, struct s2255_fh *fh) +{ + dev->resources[fh->channel] = 0; + dprintk(1, "res: put\n"); +} + + +static int vidioc_querycap(struct file *file, void *priv, + struct v4l2_capability *cap) +{ + struct s2255_fh *fh = file->private_data; + struct s2255_dev *dev = fh->dev; + strlcpy(cap->driver, "s2255", sizeof(cap->driver)); + strlcpy(cap->card, "s2255", sizeof(cap->card)); + strlcpy(cap->bus_info, dev_name(&dev->udev->dev), + sizeof(cap->bus_info)); + cap->version = S2255_VERSION; + cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING; + return 0; +} + +static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_fmtdesc *f) +{ + int index = 0; + if (f) + index = f->index; + + if (index >= ARRAY_SIZE(formats)) + return -EINVAL; + + dprintk(4, "name %s\n", formats[index].name); + strlcpy(f->description, formats[index].name, sizeof(f->description)); + f->pixelformat = formats[index].fourcc; + return 0; +} + +static int vidioc_g_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct s2255_fh *fh = priv; + + f->fmt.pix.width = fh->width; + f->fmt.pix.height = fh->height; + f->fmt.pix.field = fh->vb_vidq.field; + f->fmt.pix.pixelformat = fh->fmt->fourcc; + f->fmt.pix.bytesperline = f->fmt.pix.width * (fh->fmt->depth >> 3); + f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline; + return 0; +} + +static int vidioc_try_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + const struct s2255_fmt *fmt; + enum v4l2_field field; + int b_any_field = 0; + struct s2255_fh *fh = priv; + struct s2255_dev *dev = fh->dev; + int is_ntsc; + + is_ntsc = + (dev->vdev[fh->channel]->current_norm & V4L2_STD_NTSC) ? 1 : 0; + + fmt = format_by_fourcc(f->fmt.pix.pixelformat); + + if (fmt == NULL) + return -EINVAL; + + field = f->fmt.pix.field; + if (field == V4L2_FIELD_ANY) + b_any_field = 1; + + dprintk(4, "try format %d \n", is_ntsc); + /* supports 3 sizes. see s2255drv.h */ + dprintk(50, "width test %d, height %d\n", + f->fmt.pix.width, f->fmt.pix.height); + if (is_ntsc) { + /* NTSC */ + if (f->fmt.pix.height >= NUM_LINES_1CIFS_NTSC * 2) { + f->fmt.pix.height = NUM_LINES_1CIFS_NTSC * 2; + if (b_any_field) { + field = V4L2_FIELD_SEQ_TB; + } else if (!((field == V4L2_FIELD_INTERLACED) || + (field == V4L2_FIELD_SEQ_TB) || + (field == V4L2_FIELD_INTERLACED_TB))) { + dprintk(1, "unsupported field setting\n"); + return -EINVAL; + } + } else { + f->fmt.pix.height = NUM_LINES_1CIFS_NTSC; + if (b_any_field) { + field = V4L2_FIELD_TOP; + } else if (!((field == V4L2_FIELD_TOP) || + (field == V4L2_FIELD_BOTTOM))) { + dprintk(1, "unsupported field setting\n"); + return -EINVAL; + } + + } + if (f->fmt.pix.width >= LINE_SZ_4CIFS_NTSC) + f->fmt.pix.width = LINE_SZ_4CIFS_NTSC; + else if (f->fmt.pix.width >= LINE_SZ_2CIFS_NTSC) + f->fmt.pix.width = LINE_SZ_2CIFS_NTSC; + else if (f->fmt.pix.width >= LINE_SZ_1CIFS_NTSC) + f->fmt.pix.width = LINE_SZ_1CIFS_NTSC; + else + f->fmt.pix.width = LINE_SZ_1CIFS_NTSC; + } else { + /* PAL */ + if (f->fmt.pix.height >= NUM_LINES_1CIFS_PAL * 2) { + f->fmt.pix.height = NUM_LINES_1CIFS_PAL * 2; + if (b_any_field) { + field = V4L2_FIELD_SEQ_TB; + } else if (!((field == V4L2_FIELD_INTERLACED) || + (field == V4L2_FIELD_SEQ_TB) || + (field == V4L2_FIELD_INTERLACED_TB))) { + dprintk(1, "unsupported field setting\n"); + return -EINVAL; + } + } else { + f->fmt.pix.height = NUM_LINES_1CIFS_PAL; + if (b_any_field) { + field = V4L2_FIELD_TOP; + } else if (!((field == V4L2_FIELD_TOP) || + (field == V4L2_FIELD_BOTTOM))) { + dprintk(1, "unsupported field setting\n"); + return -EINVAL; + } + } + if (f->fmt.pix.width >= LINE_SZ_4CIFS_PAL) { + dprintk(50, "pal 704\n"); + f->fmt.pix.width = LINE_SZ_4CIFS_PAL; + field = V4L2_FIELD_SEQ_TB; + } else if (f->fmt.pix.width >= LINE_SZ_2CIFS_PAL) { + dprintk(50, "pal 352A\n"); + f->fmt.pix.width = LINE_SZ_2CIFS_PAL; + field = V4L2_FIELD_TOP; + } else if (f->fmt.pix.width >= LINE_SZ_1CIFS_PAL) { + dprintk(50, "pal 352B\n"); + f->fmt.pix.width = LINE_SZ_1CIFS_PAL; + field = V4L2_FIELD_TOP; + } else { + dprintk(50, "pal 352C\n"); + f->fmt.pix.width = LINE_SZ_1CIFS_PAL; + field = V4L2_FIELD_TOP; + } + } + + dprintk(50, "width %d height %d field %d \n", f->fmt.pix.width, + f->fmt.pix.height, f->fmt.pix.field); + f->fmt.pix.field = field; + f->fmt.pix.bytesperline = (f->fmt.pix.width * fmt->depth) >> 3; + f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline; + return 0; +} + +static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct s2255_fh *fh = priv; + const struct s2255_fmt *fmt; + struct videobuf_queue *q = &fh->vb_vidq; + int ret; + int norm; + + ret = vidioc_try_fmt_vid_cap(file, fh, f); + + if (ret < 0) + return ret; + + fmt = format_by_fourcc(f->fmt.pix.pixelformat); + + if (fmt == NULL) + return -EINVAL; + + mutex_lock(&q->vb_lock); + + if (videobuf_queue_is_busy(&fh->vb_vidq)) { + dprintk(1, "queue busy\n"); + ret = -EBUSY; + goto out_s_fmt; + } + + if (res_locked(fh->dev, fh)) { + dprintk(1, "can't change format after started\n"); + ret = -EBUSY; + goto out_s_fmt; + } + + fh->fmt = fmt; + fh->width = f->fmt.pix.width; + fh->height = f->fmt.pix.height; + fh->vb_vidq.field = f->fmt.pix.field; + fh->type = f->type; + norm = norm_minw(fh->dev->vdev[fh->channel]); + if (fh->width > norm_minw(fh->dev->vdev[fh->channel])) { + if (fh->height > norm_minh(fh->dev->vdev[fh->channel])) + fh->mode.scale = SCALE_4CIFS; + else + fh->mode.scale = SCALE_2CIFS; + + } else { + fh->mode.scale = SCALE_1CIFS; + } + + /* color mode */ + switch (fh->fmt->fourcc) { + case V4L2_PIX_FMT_GREY: + fh->mode.color = COLOR_Y8; + break; + case V4L2_PIX_FMT_YUV422P: + fh->mode.color = COLOR_YUVPL; + break; + case V4L2_PIX_FMT_YUYV: + case V4L2_PIX_FMT_UYVY: + default: + fh->mode.color = COLOR_YUVPK; + break; + } + ret = 0; +out_s_fmt: + mutex_unlock(&q->vb_lock); + return ret; +} + +static int vidioc_reqbufs(struct file *file, void *priv, + struct v4l2_requestbuffers *p) +{ + int rc; + struct s2255_fh *fh = priv; + rc = videobuf_reqbufs(&fh->vb_vidq, p); + return rc; +} + +static int vidioc_querybuf(struct file *file, void *priv, struct v4l2_buffer *p) +{ + int rc; + struct s2255_fh *fh = priv; + rc = videobuf_querybuf(&fh->vb_vidq, p); + return rc; +} + +static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *p) +{ + int rc; + struct s2255_fh *fh = priv; + rc = videobuf_qbuf(&fh->vb_vidq, p); + return rc; +} + +static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p) +{ + int rc; + struct s2255_fh *fh = priv; + rc = videobuf_dqbuf(&fh->vb_vidq, p, file->f_flags & O_NONBLOCK); + return rc; +} + +#ifdef CONFIG_VIDEO_V4L1_COMPAT +static int vidioc_cgmbuf(struct file *file, void *priv, struct video_mbuf *mbuf) +{ + struct s2255_fh *fh = priv; + + return videobuf_cgmbuf(&fh->vb_vidq, mbuf, 8); +} +#endif + +/* write to the configuration pipe, synchronously */ +static int s2255_write_config(struct usb_device *udev, unsigned char *pbuf, + int size) +{ + int pipe; + int done; + long retval = -1; + if (udev) { + pipe = usb_sndbulkpipe(udev, S2255_CONFIG_EP); + retval = usb_bulk_msg(udev, pipe, pbuf, size, &done, 500); + } + return retval; +} + +static u32 get_transfer_size(struct s2255_mode *mode) +{ + int linesPerFrame = LINE_SZ_DEF; + int pixelsPerLine = NUM_LINES_DEF; + u32 outImageSize; + u32 usbInSize; + unsigned int mask_mult; + + if (mode == NULL) + return 0; + + if (mode->format == FORMAT_NTSC) { + switch (mode->scale) { + case SCALE_4CIFS: + linesPerFrame = NUM_LINES_4CIFS_NTSC * 2; + pixelsPerLine = LINE_SZ_4CIFS_NTSC; + break; + case SCALE_2CIFS: + linesPerFrame = NUM_LINES_2CIFS_NTSC; + pixelsPerLine = LINE_SZ_2CIFS_NTSC; + break; + case SCALE_1CIFS: + linesPerFrame = NUM_LINES_1CIFS_NTSC; + pixelsPerLine = LINE_SZ_1CIFS_NTSC; + break; + default: + break; + } + } else if (mode->format == FORMAT_PAL) { + switch (mode->scale) { + case SCALE_4CIFS: + linesPerFrame = NUM_LINES_4CIFS_PAL * 2; + pixelsPerLine = LINE_SZ_4CIFS_PAL; + break; + case SCALE_2CIFS: + linesPerFrame = NUM_LINES_2CIFS_PAL; + pixelsPerLine = LINE_SZ_2CIFS_PAL; + break; + case SCALE_1CIFS: + linesPerFrame = NUM_LINES_1CIFS_PAL; + pixelsPerLine = LINE_SZ_1CIFS_PAL; + break; + default: + break; + } + } + outImageSize = linesPerFrame * pixelsPerLine; + if (mode->color != COLOR_Y8) { + /* 2 bytes/pixel if not monochrome */ + outImageSize *= 2; + } + + /* total bytes to send including prefix and 4K padding; + must be a multiple of USB_READ_SIZE */ + usbInSize = outImageSize + PREFIX_SIZE; /* always send prefix */ + mask_mult = 0xffffffffUL - DEF_USB_BLOCK + 1; + /* if size not a multiple of USB_READ_SIZE */ + if (usbInSize & ~mask_mult) + usbInSize = (usbInSize & mask_mult) + (DEF_USB_BLOCK); + return usbInSize; +} + +static void dump_verify_mode(struct s2255_dev *sdev, struct s2255_mode *mode) +{ + struct device *dev = &sdev->udev->dev; + dev_info(dev, "------------------------------------------------\n"); + dev_info(dev, "verify mode\n"); + dev_info(dev, "format: %d\n", mode->format); + dev_info(dev, "scale: %d\n", mode->scale); + dev_info(dev, "fdec: %d\n", mode->fdec); + dev_info(dev, "color: %d\n", mode->color); + dev_info(dev, "bright: 0x%x\n", mode->bright); + dev_info(dev, "restart: 0x%x\n", mode->restart); + dev_info(dev, "usb_block: 0x%x\n", mode->usb_block); + dev_info(dev, "single: 0x%x\n", mode->single); + dev_info(dev, "------------------------------------------------\n"); +} + +/* + * set mode is the function which controls the DSP. + * the restart parameter in struct s2255_mode should be set whenever + * the image size could change via color format, video system or image + * size. + * When the restart parameter is set, we sleep for ONE frame to allow the + * DSP time to get the new frame + */ +static int s2255_set_mode(struct s2255_dev *dev, unsigned long chn, + struct s2255_mode *mode) +{ + int res; + u32 *buffer; + unsigned long chn_rev; + + chn_rev = G_chnmap[chn]; + dprintk(3, "mode scale [%ld] %p %d\n", chn, mode, mode->scale); + dprintk(3, "mode scale [%ld] %p %d\n", chn, &dev->mode[chn], + dev->mode[chn].scale); + dprintk(2, "mode contrast %x\n", mode->contrast); + + /* save the mode */ + dev->mode[chn] = *mode; + dev->req_image_size[chn] = get_transfer_size(mode); + dprintk(1, "transfer size %ld\n", dev->req_image_size[chn]); + + buffer = kzalloc(512, GFP_KERNEL); + if (buffer == NULL) { + dev_err(&dev->udev->dev, "out of mem\n"); + return -ENOMEM; + } + + /* set the mode */ + buffer[0] = IN_DATA_TOKEN; + buffer[1] = (u32) chn_rev; + buffer[2] = CMD_SET_MODE; + memcpy(&buffer[3], &dev->mode[chn], sizeof(struct s2255_mode)); + res = s2255_write_config(dev->udev, (unsigned char *)buffer, 512); + if (debug) + dump_verify_mode(dev, mode); + kfree(buffer); + dprintk(1, "set mode done chn %lu, %d\n", chn, res); + + /* wait at least 3 frames before continuing */ + if (mode->restart) + msleep(125); + + /* clear the restart flag */ + dev->mode[chn].restart = 0; + + return res; +} + +static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i) +{ + int res; + struct s2255_fh *fh = priv; + struct s2255_dev *dev = fh->dev; + struct s2255_mode *new_mode; + struct s2255_mode *old_mode; + int chn; + int j; + dprintk(4, "%s\n", __func__); + if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) { + dev_err(&dev->udev->dev, "invalid fh type0\n"); + return -EINVAL; + } + if (i != fh->type) { + dev_err(&dev->udev->dev, "invalid fh type1\n"); + return -EINVAL; + } + + if (!res_get(dev, fh)) { + dev_err(&dev->udev->dev, "res get busy\n"); + return -EBUSY; + } + + /* send a set mode command everytime with restart. + in case we switch resolutions or other parameters */ + chn = fh->channel; + new_mode = &fh->mode; + old_mode = &fh->dev->mode[chn]; + + if (new_mode->color != old_mode->color) + new_mode->restart = 1; + else if (new_mode->scale != old_mode->scale) + new_mode->restart = 1; + else if (new_mode->format != old_mode->format) + new_mode->restart = 1; + + s2255_set_mode(dev, chn, new_mode); + new_mode->restart = 0; + *old_mode = *new_mode; + dev->cur_fmt[chn] = fh->fmt; + dprintk(1, "%s[%d]\n", __func__, chn); + dev->last_frame[chn] = -1; + dev->bad_payload[chn] = 0; + dev->cur_frame[chn] = 0; + for (j = 0; j < SYS_FRAMES; j++) { + dev->buffer[chn].frame[j].ulState = 0; + dev->buffer[chn].frame[j].cur_size = 0; + } + res = videobuf_streamon(&fh->vb_vidq); + if (res == 0) { + s2255_start_acquire(dev, chn); + dev->b_acquire[chn] = 1; + } else { + res_free(dev, fh); + } + return res; +} + +static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i) +{ + int res; + struct s2255_fh *fh = priv; + struct s2255_dev *dev = fh->dev; + + dprintk(4, "%s\n, channel: %d", __func__, fh->channel); + if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) { + printk(KERN_ERR "invalid fh type0\n"); + return -EINVAL; + } + if (i != fh->type) { + printk(KERN_ERR "invalid type i\n"); + return -EINVAL; + } + s2255_stop_acquire(dev, fh->channel); + res = videobuf_streamoff(&fh->vb_vidq); + res_free(dev, fh); + return res; +} + +static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *i) +{ + struct s2255_fh *fh = priv; + struct s2255_mode *mode; + struct videobuf_queue *q = &fh->vb_vidq; + int ret = 0; + + mutex_lock(&q->vb_lock); + if (videobuf_queue_is_busy(q)) { + dprintk(1, "queue busy\n"); + ret = -EBUSY; + goto out_s_std; + } + + if (res_locked(fh->dev, fh)) { + dprintk(1, "can't change standard after started\n"); + ret = -EBUSY; + goto out_s_std; + } + mode = &fh->mode; + + if (*i & V4L2_STD_NTSC) { + dprintk(4, "vidioc_s_std NTSC\n"); + mode->format = FORMAT_NTSC; + } else if (*i & V4L2_STD_PAL) { + dprintk(4, "vidioc_s_std PAL\n"); + mode->format = FORMAT_PAL; + } else { + ret = -EINVAL; + } +out_s_std: + mutex_unlock(&q->vb_lock); + return ret; +} + +/* Sensoray 2255 is a multiple channel capture device. + It does not have a "crossbar" of inputs. + We use one V4L device per channel. The user must + be aware that certain combinations are not allowed. + For instance, you cannot do full FPS on more than 2 channels(2 videodevs) + at once in color(you can do full fps on 4 channels with greyscale. +*/ +static int vidioc_enum_input(struct file *file, void *priv, + struct v4l2_input *inp) +{ + if (inp->index != 0) + return -EINVAL; + + inp->type = V4L2_INPUT_TYPE_CAMERA; + inp->std = S2255_NORMS; + strlcpy(inp->name, "Camera", sizeof(inp->name)); + return 0; +} + +static int vidioc_g_input(struct file *file, void *priv, unsigned int *i) +{ + *i = 0; + return 0; +} +static int vidioc_s_input(struct file *file, void *priv, unsigned int i) +{ + if (i > 0) + return -EINVAL; + return 0; +} + +/* --- controls ---------------------------------------------- */ +static int vidioc_queryctrl(struct file *file, void *priv, + struct v4l2_queryctrl *qc) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(s2255_qctrl); i++) + if (qc->id && qc->id == s2255_qctrl[i].id) { + memcpy(qc, &(s2255_qctrl[i]), sizeof(*qc)); + return 0; + } + + dprintk(4, "query_ctrl -EINVAL %d\n", qc->id); + return -EINVAL; +} + +static int vidioc_g_ctrl(struct file *file, void *priv, + struct v4l2_control *ctrl) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(s2255_qctrl); i++) + if (ctrl->id == s2255_qctrl[i].id) { + ctrl->value = qctl_regs[i]; + return 0; + } + dprintk(4, "g_ctrl -EINVAL\n"); + + return -EINVAL; +} + +static int vidioc_s_ctrl(struct file *file, void *priv, + struct v4l2_control *ctrl) +{ + int i; + struct s2255_fh *fh = priv; + struct s2255_dev *dev = fh->dev; + struct s2255_mode *mode; + mode = &fh->mode; + dprintk(4, "vidioc_s_ctrl\n"); + for (i = 0; i < ARRAY_SIZE(s2255_qctrl); i++) { + if (ctrl->id == s2255_qctrl[i].id) { + if (ctrl->value < s2255_qctrl[i].minimum || + ctrl->value > s2255_qctrl[i].maximum) + return -ERANGE; + + qctl_regs[i] = ctrl->value; + /* update the mode to the corresponding value */ + switch (ctrl->id) { + case V4L2_CID_BRIGHTNESS: + mode->bright = ctrl->value; + break; + case V4L2_CID_CONTRAST: + mode->contrast = ctrl->value; + break; + case V4L2_CID_HUE: + mode->hue = ctrl->value; + break; + case V4L2_CID_SATURATION: + mode->saturation = ctrl->value; + break; + } + mode->restart = 0; + /* set mode here. Note: stream does not need restarted. + some V4L programs restart stream unnecessarily + after a s_crtl. + */ + s2255_set_mode(dev, fh->channel, mode); + return 0; + } + } + return -EINVAL; +} + +static int s2255_open(struct inode *inode, struct file *file) +{ + int minor = iminor(inode); + struct s2255_dev *h, *dev = NULL; + struct s2255_fh *fh; + struct list_head *list; + enum v4l2_buf_type type = 0; + int i = 0; + int cur_channel = -1; + dprintk(1, "s2255: open called (minor=%d)\n", minor); + + list_for_each(list, &s2255_devlist) { + h = list_entry(list, struct s2255_dev, s2255_devlist); + for (i = 0; i < MAX_CHANNELS; i++) { + if (h->vdev[i]->minor == minor) { + cur_channel = i; + dev = h; + type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + } + } + } + + if ((NULL == dev) || (cur_channel == -1)) { + dprintk(1, "s2255: openv4l no dev\n"); + return -ENODEV; + } + + mutex_lock(&dev->open_lock); + + dev->users[cur_channel]++; + if (dev->users[cur_channel] > S2255_MAX_USERS) { + dev->users[cur_channel]--; + mutex_unlock(&dev->open_lock); + printk(KERN_INFO "s2255drv: too many open handles!\n"); + return -EBUSY; + } + + if (atomic_read(&dev->fw_data->fw_state) == S2255_FW_FAILED) { + err("2255 firmware load failed. retrying.\n"); + s2255_fwload_start(dev); + wait_event_timeout(dev->fw_data->wait_fw, + (atomic_read(&dev->fw_data->fw_state) + != S2255_FW_NOTLOADED), + msecs_to_jiffies(S2255_LOAD_TIMEOUT)); + if (atomic_read(&dev->fw_data->fw_state) + != S2255_FW_SUCCESS) { + printk(KERN_INFO "2255 FW load failed after 2 tries\n"); + mutex_unlock(&dev->open_lock); + return -EFAULT; + } + } else if (atomic_read(&dev->fw_data->fw_state) == S2255_FW_NOTLOADED) { + /* give S2255_LOAD_TIMEOUT time for firmware to load in case + driver loaded and then device immediately opened */ + printk(KERN_INFO "%s waiting for firmware load\n", __func__); + wait_event_timeout(dev->fw_data->wait_fw, + (atomic_read(&dev->fw_data->fw_state) + != S2255_FW_NOTLOADED), + msecs_to_jiffies(S2255_LOAD_TIMEOUT)); + if (atomic_read(&dev->fw_data->fw_state) + != S2255_FW_SUCCESS) { + printk(KERN_INFO "2255 firmware not loaded" + "try again\n"); + mutex_unlock(&dev->open_lock); + return -EBUSY; + } + } + + /* allocate + initialize per filehandle data */ + fh = kzalloc(sizeof(*fh), GFP_KERNEL); + if (NULL == fh) { + mutex_unlock(&dev->open_lock); + return -ENOMEM; + } + + file->private_data = fh; + fh->dev = dev; + fh->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + fh->mode = dev->mode[cur_channel]; + fh->fmt = dev->cur_fmt[cur_channel]; + /* default 4CIF NTSC */ + fh->width = LINE_SZ_4CIFS_NTSC; + fh->height = NUM_LINES_4CIFS_NTSC * 2; + fh->channel = cur_channel; + + /* Put all controls at a sane state */ + for (i = 0; i < ARRAY_SIZE(s2255_qctrl); i++) + qctl_regs[i] = s2255_qctrl[i].default_value; + + dprintk(1, "s2255drv: open minor=%d type=%s users=%d\n", + minor, v4l2_type_names[type], dev->users[cur_channel]); + dprintk(2, "s2255drv: open: fh=0x%08lx, dev=0x%08lx, vidq=0x%08lx\n", + (unsigned long)fh, (unsigned long)dev, + (unsigned long)&dev->vidq[cur_channel]); + dprintk(4, "s2255drv: open: list_empty active=%d\n", + list_empty(&dev->vidq[cur_channel].active)); + + videobuf_queue_vmalloc_init(&fh->vb_vidq, &s2255_video_qops, + NULL, &dev->slock, + fh->type, + V4L2_FIELD_INTERLACED, + sizeof(struct s2255_buffer), fh); + + kref_get(&dev->kref); + mutex_unlock(&dev->open_lock); + return 0; +} + + +static unsigned int s2255_poll(struct file *file, + struct poll_table_struct *wait) +{ + struct s2255_fh *fh = file->private_data; + int rc; + dprintk(100, "%s\n", __func__); + + if (V4L2_BUF_TYPE_VIDEO_CAPTURE != fh->type) + return POLLERR; + + rc = videobuf_poll_stream(file, &fh->vb_vidq, wait); + return rc; +} + +static void s2255_destroy(struct kref *kref) +{ + struct s2255_dev *dev = to_s2255_dev(kref); + if (!dev) { + printk(KERN_ERR "s2255drv: kref problem\n"); + return; + } + /* prevent s2255_disconnect from racing s2255_open */ + mutex_lock(&dev->open_lock); + s2255_exit_v4l(dev); + /* device unregistered so no longer possible to open. open_mutex + can be unlocked */ + mutex_unlock(&dev->open_lock); + + /* board shutdown stops the read pipe if it is running */ + s2255_board_shutdown(dev); + + /* make sure firmware still not trying to load */ + if (dev->fw_data->fw_urb) { + dprintk(2, "kill fw_urb\n"); + usb_kill_urb(dev->fw_data->fw_urb); + usb_free_urb(dev->fw_data->fw_urb); + dev->fw_data->fw_urb = NULL; + } + /* + * TODO: fixme(above, below): potentially leaving timers alive. + * do not ignore timeout below if + * it occurs. + */ + + /* make sure we aren't waiting for the DSP */ + if (atomic_read(&dev->fw_data->fw_state) == S2255_FW_LOADED_DSPWAIT) { + /* if we are, wait for the wakeup for fw_success or timeout */ + wait_event_timeout(dev->fw_data->wait_fw, + (atomic_read(&dev->fw_data->fw_state) + == S2255_FW_SUCCESS), + msecs_to_jiffies(S2255_LOAD_TIMEOUT)); + } + + if (dev->fw_data) { + if (dev->fw_data->fw) + release_firmware(dev->fw_data->fw); + kfree(dev->fw_data->pfw_data); + kfree(dev->fw_data); + } + + usb_put_dev(dev->udev); + dprintk(1, "%s", __func__); + kfree(dev); +} + +static int s2255_close(struct inode *inode, struct file *file) +{ + struct s2255_fh *fh = file->private_data; + struct s2255_dev *dev = fh->dev; + int minor = iminor(inode); + if (!dev) + return -ENODEV; + + mutex_lock(&dev->open_lock); + + if (dev->b_acquire[fh->channel]) + s2255_stop_acquire(dev, fh->channel); + res_free(dev, fh); + videobuf_mmap_free(&fh->vb_vidq); + kfree(fh); + dev->users[fh->channel]--; + mutex_unlock(&dev->open_lock); + + kref_put(&dev->kref, s2255_destroy); + dprintk(1, "s2255: close called (minor=%d, users=%d)\n", + minor, dev->users[fh->channel]); + return 0; +} + +static int s2255_mmap_v4l(struct file *file, struct vm_area_struct *vma) +{ + struct s2255_fh *fh = file->private_data; + int ret; + + if (!fh) + return -ENODEV; + dprintk(4, "mmap called, vma=0x%08lx\n", (unsigned long)vma); + + ret = videobuf_mmap_mapper(&fh->vb_vidq, vma); + + dprintk(4, "vma start=0x%08lx, size=%ld, ret=%d\n", + (unsigned long)vma->vm_start, + (unsigned long)vma->vm_end - (unsigned long)vma->vm_start, ret); + + return ret; +} + +static const struct file_operations s2255_fops_v4l = { + .owner = THIS_MODULE, + .open = s2255_open, + .release = s2255_close, + .poll = s2255_poll, + .ioctl = video_ioctl2, /* V4L2 ioctl handler */ + .compat_ioctl = v4l_compat_ioctl32, + .mmap = s2255_mmap_v4l, + .llseek = no_llseek, +}; + +static struct video_device template = { + .name = "s2255v", + .type = VID_TYPE_CAPTURE, + .fops = &s2255_fops_v4l, + .minor = -1, + .release = video_device_release, + .vidioc_querycap = vidioc_querycap, + .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap, + .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap, + .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap, + .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap, + .vidioc_reqbufs = vidioc_reqbufs, + .vidioc_querybuf = vidioc_querybuf, + .vidioc_qbuf = vidioc_qbuf, + .vidioc_dqbuf = vidioc_dqbuf, + .vidioc_s_std = vidioc_s_std, + .vidioc_enum_input = vidioc_enum_input, + .vidioc_g_input = vidioc_g_input, + .vidioc_s_input = vidioc_s_input, + .vidioc_queryctrl = vidioc_queryctrl, + .vidioc_g_ctrl = vidioc_g_ctrl, + .vidioc_s_ctrl = vidioc_s_ctrl, + .vidioc_streamon = vidioc_streamon, + .vidioc_streamoff = vidioc_streamoff, +#ifdef CONFIG_VIDEO_V4L1_COMPAT + .vidiocgmbuf = vidioc_cgmbuf, +#endif + .tvnorms = S2255_NORMS, + .current_norm = V4L2_STD_NTSC_M, +}; + +static int s2255_probe_v4l(struct s2255_dev *dev) +{ + int ret; + int i; + int cur_nr = video_nr; + + /* initialize all video 4 linux */ + list_add_tail(&dev->s2255_devlist, &s2255_devlist); + /* register 4 video devices */ + for (i = 0; i < MAX_CHANNELS; i++) { + INIT_LIST_HEAD(&dev->vidq[i].active); + dev->vidq[i].dev = dev; + dev->vidq[i].channel = i; + dev->vidq[i].kthread = NULL; + /* register 4 video devices */ + dev->vdev[i] = video_device_alloc(); + memcpy(dev->vdev[i], &template, sizeof(struct video_device)); + dev->vdev[i]->dev = &dev->interface->dev; + if (video_nr == -1) + ret = video_register_device(dev->vdev[i], + VFL_TYPE_GRABBER, + video_nr); + else + ret = video_register_device(dev->vdev[i], + VFL_TYPE_GRABBER, + cur_nr + i); + dev->vdev[i]->priv = dev; + + if (ret != 0) { + dev_err(&dev->udev->dev, + "failed to register video device!\n"); + return ret; + } + } + printk(KERN_INFO "Sensoray 2255 V4L driver\n"); + return ret; +} + +static void s2255_exit_v4l(struct s2255_dev *dev) +{ + struct list_head *list; + int i; + /* unregister the video devices */ + while (!list_empty(&s2255_devlist)) { + list = s2255_devlist.next; + list_del(list); + } + for (i = 0; i < MAX_CHANNELS; i++) { + if (-1 != dev->vdev[i]->minor) + video_unregister_device(dev->vdev[i]); + else + video_device_release(dev->vdev[i]); + } +} + +/* this function moves the usb stream read pipe data + * into the system buffers. + * returns 0 on success, EAGAIN if more data to process( call this + * function again). + * + * Received frame structure: + * bytes 0-3: marker : 0x2255DA4AL (FRAME_MARKER) + * bytes 4-7: channel: 0-3 + * bytes 8-11: payload size: size of the frame + * bytes 12-payloadsize+12: frame data + */ +static int save_frame(struct s2255_dev *dev, struct s2255_pipeinfo *pipe_info) +{ + static int dbgsync; /* = 0; */ + char *pdest; + u32 offset = 0; + int bsync = 0; + int btrunc = 0; + char *psrc; + unsigned long copy_size; + unsigned long size; + s32 idx = -1; + struct s2255_framei *frm; + unsigned char *pdata; + unsigned long cur_size; + int bsearch = 0; + struct s2255_bufferi *buf; + dprintk(100, "buffer to user\n"); + + idx = dev->cur_frame[dev->cc]; + buf = &dev->buffer[dev->cc]; + frm = &buf->frame[idx]; + + if (frm->ulState == 0) { + frm->ulState = 1; + frm->cur_size = 0; + bsearch = 1; + } else if (frm->ulState == 2) { + /* system frame was not freed */ + dprintk(2, "sys frame not free. overrun ringbuf\n"); + bsearch = 1; + frm->ulState = 1; + frm->cur_size = 0; + } + + if (bsearch) { + if (*(s32 *) pipe_info->transfer_buffer != FRAME_MARKER) { + u32 jj; + if (dbgsync == 0) { + dprintk(3, "not synched, discarding all packets" + "until marker\n"); + + dbgsync++; + } + pdata = (unsigned char *)pipe_info->transfer_buffer; + for (jj = 0; jj < (pipe_info->cur_transfer_size - 12); + jj++) { + if (*(s32 *) pdata == FRAME_MARKER) { + int cc; + dprintk(3, + "found frame marker at offset:" + " %d [%x %x]\n", jj, pdata[0], + pdata[1]); + offset = jj; + bsync = 1; + cc = *(u32 *) (pdata + sizeof(u32)); + if (cc >= MAX_CHANNELS) { + printk(KERN_ERR + "bad channel\n"); + return -EINVAL; + } + /* reverse it */ + dev->cc = G_chnmap[cc]; + break; + } + pdata++; + } + if (bsync == 0) + return -EINVAL; + } else { + u32 *pword; + u32 payload; + int cc; + dbgsync = 0; + bsync = 1; + pword = (u32 *) pipe_info->transfer_buffer; + cc = pword[1]; + + if (cc >= MAX_CHANNELS) { + printk("invalid channel found. " + "throwing out data!\n"); + return -EINVAL; + } + dev->cc = G_chnmap[cc]; + payload = pword[2]; + if (payload != dev->req_image_size[dev->cc]) { + dprintk(1, "[%d][%d]unexpected payload: %d" + "required: %lu \n", cc, dev->cc, + payload, dev->req_image_size[dev->cc]); + dev->bad_payload[dev->cc]++; + /* discard the bad frame */ + return -EINVAL; + } + + } + } + /* search done. now find out if should be acquiring + on this channel */ + if (!dev->b_acquire[dev->cc]) { + frm->ulState = 0; + return -EINVAL; + } + + idx = dev->cur_frame[dev->cc]; + frm = &dev->buffer[dev->cc].frame[idx]; + + if (frm->ulState == 0) { + frm->ulState = 1; + frm->cur_size = 0; + } else if (frm->ulState == 2) { + /* system frame ring buffer overrun */ + dprintk(2, "sys frame overrun. overwriting frame %d %d\n", + dev->cc, idx); + frm->ulState = 1; + frm->cur_size = 0; + } + + if (bsync) { + /* skip the marker 512 bytes (and offset if out of sync) */ + psrc = (u8 *)pipe_info->transfer_buffer + offset + PREFIX_SIZE; + } else { + psrc = (u8 *)pipe_info->transfer_buffer; + } + + if (frm->lpvbits == NULL) { + dprintk(1, "s2255 frame buffer == NULL.%p %p %d %d", + frm, dev, dev->cc, idx); + return -ENOMEM; + } + + pdest = frm->lpvbits + frm->cur_size; + + if (bsync) { + copy_size = + (pipe_info->cur_transfer_size - offset) - PREFIX_SIZE; + if (copy_size > pipe_info->cur_transfer_size) { + printk("invalid copy size, overflow!\n"); + return -ENOMEM; + } + } else { + copy_size = pipe_info->cur_transfer_size; + } + + cur_size = frm->cur_size; + size = dev->req_image_size[dev->cc]; + + if ((copy_size + cur_size) > size) { + copy_size = size - cur_size; + btrunc = 1; + } + + memcpy(pdest, psrc, copy_size); + cur_size += copy_size; + frm->cur_size += copy_size; + dprintk(50, "cur_size size %lu size %lu \n", cur_size, size); + + if (cur_size >= (size - PREFIX_SIZE)) { + u32 cc = dev->cc; + frm->ulState = 2; + dprintk(2, "****************[%d]Buffer[%d]full*************\n", + cc, idx); + dev->last_frame[cc] = dev->cur_frame[cc]; + dev->cur_frame[cc]++; + /* end of system frame ring buffer, start at zero */ + if ((dev->cur_frame[cc] == SYS_FRAMES) || + (dev->cur_frame[cc] == dev->buffer[cc].dwFrames)) + dev->cur_frame[cc] = 0; + + /* signal the semaphore for this channel */ + if (dev->b_acquire[cc]) + s2255_got_frame(dev, cc); + dev->frame_count[cc]++; + } + /* frame was truncated */ + if (btrunc) { + /* return more data to process */ + return EAGAIN; + } + /* done successfully */ + return 0; +} + +static void s2255_read_video_callback(struct s2255_dev *dev, + struct s2255_pipeinfo *pipe_info) +{ + int res; + dprintk(50, "callback read video \n"); + + if (dev->cc >= MAX_CHANNELS) { + dev->cc = 0; + dev_err(&dev->udev->dev, "invalid channel\n"); + return; + } + /* otherwise copy to the system buffers */ + res = save_frame(dev, pipe_info); + if (res == EAGAIN) + save_frame(dev, pipe_info); + + dprintk(50, "callback read video done\n"); + return; +} + +static long s2255_vendor_req(struct s2255_dev *dev, unsigned char Request, + u16 Index, u16 Value, void *TransferBuffer, + s32 TransferBufferLength, int bOut) +{ + int r; + if (!bOut) { + r = usb_control_msg(dev->udev, usb_rcvctrlpipe(dev->udev, 0), + Request, + USB_TYPE_VENDOR | USB_RECIP_DEVICE | + USB_DIR_IN, + Value, Index, TransferBuffer, + TransferBufferLength, HZ * 5); + } else { + r = usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, 0), + Request, USB_TYPE_VENDOR | USB_RECIP_DEVICE, + Value, Index, TransferBuffer, + TransferBufferLength, HZ * 5); + } + return r; +} + +/* + * retrieve FX2 firmware version. future use. + * @param dev pointer to device extension + * @return -1 for fail, else returns firmware version as an int(16 bits) + */ +static int s2255_get_fx2fw(struct s2255_dev *dev) +{ + int fw; + int ret; + unsigned char transBuffer[64]; + ret = s2255_vendor_req(dev, S2255_VR_FW, 0, 0, transBuffer, 2, + S2255_VR_IN); + if (ret < 0) + dprintk(2, "get fw error: %x\n", ret); + fw = transBuffer[0] + (transBuffer[1] << 8); + dprintk(2, "Get FW %x %x\n", transBuffer[0], transBuffer[1]); + return fw; +} + +/* + * Create the system ring buffer to copy frames into from the + * usb read pipe. + */ +static int s2255_create_sys_buffers(struct s2255_dev *dev, unsigned long chn) +{ + unsigned long i; + unsigned long reqsize; + dprintk(1, "create sys buffers\n"); + if (chn >= MAX_CHANNELS) + return -1; + + dev->buffer[chn].dwFrames = SYS_FRAMES; + + /* always allocate maximum size(PAL) for system buffers */ + reqsize = SYS_FRAMES_MAXSIZE; + + if (reqsize > SYS_FRAMES_MAXSIZE) + reqsize = SYS_FRAMES_MAXSIZE; + + for (i = 0; i < SYS_FRAMES; i++) { + /* allocate the frames */ + dev->buffer[chn].frame[i].lpvbits = vmalloc(reqsize); + + dprintk(1, "valloc %p chan %lu, idx %lu, pdata %p\n", + &dev->buffer[chn].frame[i], chn, i, + dev->buffer[chn].frame[i].lpvbits); + dev->buffer[chn].frame[i].size = reqsize; + if (dev->buffer[chn].frame[i].lpvbits == NULL) { + printk(KERN_INFO "out of memory. using less frames\n"); + dev->buffer[chn].dwFrames = i; + break; + } + } + + /* make sure internal states are set */ + for (i = 0; i < SYS_FRAMES; i++) { + dev->buffer[chn].frame[i].ulState = 0; + dev->buffer[chn].frame[i].cur_size = 0; + } + + dev->cur_frame[chn] = 0; + dev->last_frame[chn] = -1; + return 0; +} + +static int s2255_release_sys_buffers(struct s2255_dev *dev, + unsigned long channel) +{ + unsigned long i; + dprintk(1, "release sys buffers\n"); + for (i = 0; i < SYS_FRAMES; i++) { + if (dev->buffer[channel].frame[i].lpvbits) { + dprintk(1, "vfree %p\n", + dev->buffer[channel].frame[i].lpvbits); + vfree(dev->buffer[channel].frame[i].lpvbits); + } + dev->buffer[channel].frame[i].lpvbits = NULL; + } + return 0; +} + +static int s2255_board_init(struct s2255_dev *dev) +{ + int j; + struct s2255_mode mode_def = DEF_MODEI_NTSC_CONT; + int fw_ver; + dprintk(4, "board init: %p", dev); + + for (j = 0; j < MAX_PIPE_BUFFERS; j++) { + struct s2255_pipeinfo *pipe = &dev->pipes[j]; + + memset(pipe, 0, sizeof(*pipe)); + pipe->dev = dev; + pipe->cur_transfer_size = DEFAULT_PIPE_USBBLOCK; + pipe->max_transfer_size = MAX_PIPE_USBBLOCK; + + if (pipe->cur_transfer_size > pipe->max_transfer_size) + pipe->cur_transfer_size = pipe->max_transfer_size; + pipe->transfer_buffer = kzalloc(pipe->max_transfer_size, + GFP_KERNEL); + if (pipe->transfer_buffer == NULL) { + dprintk(1, "out of memory!\n"); + return -ENOMEM; + } + + } + + /* query the firmware */ + fw_ver = s2255_get_fx2fw(dev); + + printk(KERN_INFO "2255 usb firmware version %d \n", fw_ver); + if (fw_ver < CUR_USB_FWVER) + err("usb firmware not up to date %d\n", fw_ver); + + for (j = 0; j < MAX_CHANNELS; j++) { + dev->b_acquire[j] = 0; + dev->mode[j] = mode_def; + dev->cur_fmt[j] = &formats[0]; + dev->mode[j].restart = 1; + dev->req_image_size[j] = get_transfer_size(&mode_def); + dev->frame_count[j] = 0; + /* create the system buffers */ + s2255_create_sys_buffers(dev, j); + } + /* start read pipe */ + s2255_start_readpipe(dev); + + dprintk(1, "S2255: board initialized\n"); + return 0; +} + +static int s2255_board_shutdown(struct s2255_dev *dev) +{ + u32 i; + + dprintk(1, "S2255: board shutdown: %p", dev); + + for (i = 0; i < MAX_CHANNELS; i++) { + if (dev->b_acquire[i]) + s2255_stop_acquire(dev, i); + } + + s2255_stop_readpipe(dev); + + for (i = 0; i < MAX_CHANNELS; i++) + s2255_release_sys_buffers(dev, i); + + /* release transfer buffers */ + for (i = 0; i < MAX_PIPE_BUFFERS; i++) { + struct s2255_pipeinfo *pipe = &dev->pipes[i]; + kfree(pipe->transfer_buffer); + } + return 0; +} + +static void read_pipe_completion(struct urb *purb) +{ + struct s2255_pipeinfo *pipe_info; + struct s2255_dev *dev; + int status; + int pipe; + + pipe_info = purb->context; + dprintk(100, "read pipe completion %p, status %d\n", purb, + purb->status); + if (pipe_info == NULL) { + err("no context !"); + return; + } + + dev = pipe_info->dev; + if (dev == NULL) { + err("no context !"); + return; + } + status = purb->status; + if (status != 0) { + dprintk(2, "read_pipe_completion: err\n"); + return; + } + + if (pipe_info->state == 0) { + dprintk(2, "exiting USB pipe"); + return; + } + + s2255_read_video_callback(dev, pipe_info); + + pipe_info->err_count = 0; + pipe = usb_rcvbulkpipe(dev->udev, dev->read_endpoint); + /* reuse urb */ + usb_fill_bulk_urb(pipe_info->stream_urb, dev->udev, + pipe, + pipe_info->transfer_buffer, + pipe_info->cur_transfer_size, + read_pipe_completion, pipe_info); + + if (pipe_info->state != 0) { + if (usb_submit_urb(pipe_info->stream_urb, GFP_KERNEL)) { + dev_err(&dev->udev->dev, "error submitting urb\n"); + usb_free_urb(pipe_info->stream_urb); + } + } else { + dprintk(2, "read pipe complete state 0\n"); + } + return; +} + +static int s2255_start_readpipe(struct s2255_dev *dev) +{ + int pipe; + int retval; + int i; + struct s2255_pipeinfo *pipe_info = dev->pipes; + pipe = usb_rcvbulkpipe(dev->udev, dev->read_endpoint); + dprintk(2, "start pipe IN %d\n", dev->read_endpoint); + + for (i = 0; i < MAX_PIPE_BUFFERS; i++) { + pipe_info->state = 1; + pipe_info->buf_index = (u32) i; + pipe_info->priority_set = 0; + pipe_info->stream_urb = usb_alloc_urb(0, GFP_KERNEL); + if (!pipe_info->stream_urb) { + dev_err(&dev->udev->dev, + "ReadStream: Unable to alloc URB"); + return -ENOMEM; + } + /* transfer buffer allocated in board_init */ + usb_fill_bulk_urb(pipe_info->stream_urb, dev->udev, + pipe, + pipe_info->transfer_buffer, + pipe_info->cur_transfer_size, + read_pipe_completion, pipe_info); + + pipe_info->urb_size = sizeof(pipe_info->stream_urb); + dprintk(4, "submitting URB %p\n", pipe_info->stream_urb); + retval = usb_submit_urb(pipe_info->stream_urb, GFP_KERNEL); + if (retval) { + printk(KERN_ERR "s2255: start read pipe failed\n"); + return retval; + } + } + + return 0; +} + +/* starts acquisition process */ +static int s2255_start_acquire(struct s2255_dev *dev, unsigned long chn) +{ + unsigned char *buffer; + int res; + unsigned long chn_rev; + int j; + if (chn >= MAX_CHANNELS) { + dprintk(2, "start acquire failed, bad channel %lu\n", chn); + return -1; + } + + chn_rev = G_chnmap[chn]; + dprintk(1, "S2255: start acquire %lu \n", chn); + + buffer = kzalloc(512, GFP_KERNEL); + if (buffer == NULL) { + dev_err(&dev->udev->dev, "out of mem\n"); + return -ENOMEM; + } + + dev->last_frame[chn] = -1; + dev->bad_payload[chn] = 0; + dev->cur_frame[chn] = 0; + for (j = 0; j < SYS_FRAMES; j++) { + dev->buffer[chn].frame[j].ulState = 0; + dev->buffer[chn].frame[j].cur_size = 0; + } + + /* send the start command */ + *(u32 *) buffer = IN_DATA_TOKEN; + *((u32 *) buffer + 1) = (u32) chn_rev; + *((u32 *) buffer + 2) = (u32) CMD_START; + res = s2255_write_config(dev->udev, (unsigned char *)buffer, 512); + if (res != 0) + dev_err(&dev->udev->dev, "CMD_START error\n"); + + dprintk(2, "start acquire exit[%lu] %d \n", chn, res); + kfree(buffer); + return 0; +} + +static int s2255_stop_acquire(struct s2255_dev *dev, unsigned long chn) +{ + unsigned char *buffer; + int res; + unsigned long chn_rev; + + if (chn >= MAX_CHANNELS) { + dprintk(2, "stop acquire failed, bad channel %lu\n", chn); + return -1; + } + chn_rev = G_chnmap[chn]; + + buffer = kzalloc(512, GFP_KERNEL); + if (buffer == NULL) { + dev_err(&dev->udev->dev, "out of mem\n"); + return -ENOMEM; + } + + /* send the stop command */ + dprintk(4, "stop acquire %lu\n", chn); + *(u32 *) buffer = IN_DATA_TOKEN; + *((u32 *) buffer + 1) = (u32) chn_rev; + *((u32 *) buffer + 2) = CMD_STOP; + res = s2255_write_config(dev->udev, (unsigned char *)buffer, 512); + + if (res != 0) + dev_err(&dev->udev->dev, "CMD_STOP error\n"); + + dprintk(4, "stop acquire: releasing states \n"); + + kfree(buffer); + dev->b_acquire[chn] = 0; + + return 0; +} + +static void s2255_stop_readpipe(struct s2255_dev *dev) +{ + int j; + + if (dev == NULL) { + err("s2255: invalid device"); + return; + } + dprintk(4, "stop read pipe\n"); + for (j = 0; j < MAX_PIPE_BUFFERS; j++) { + struct s2255_pipeinfo *pipe_info = &dev->pipes[j]; + if (pipe_info) { + if (pipe_info->state == 0) + continue; + pipe_info->state = 0; + pipe_info->prev_state = 1; + + } + } + + for (j = 0; j < MAX_PIPE_BUFFERS; j++) { + struct s2255_pipeinfo *pipe_info = &dev->pipes[j]; + if (pipe_info->stream_urb) { + /* cancel urb */ + usb_kill_urb(pipe_info->stream_urb); + usb_free_urb(pipe_info->stream_urb); + pipe_info->stream_urb = NULL; + } + } + dprintk(2, "s2255 stop read pipe: %d\n", j); + return; +} + +static void s2255_fwload_start(struct s2255_dev *dev) +{ + dev->fw_data->fw_size = dev->fw_data->fw->size; + atomic_set(&dev->fw_data->fw_state, S2255_FW_NOTLOADED); + memcpy(dev->fw_data->pfw_data, + dev->fw_data->fw->data, CHUNK_SIZE); + dev->fw_data->fw_loaded = CHUNK_SIZE; + usb_fill_bulk_urb(dev->fw_data->fw_urb, dev->udev, + usb_sndbulkpipe(dev->udev, 2), + dev->fw_data->pfw_data, + CHUNK_SIZE, s2255_fwchunk_complete, + dev->fw_data); + mod_timer(&dev->timer, jiffies + HZ); +} + +/* standard usb probe function */ +static int s2255_probe(struct usb_interface *interface, + const struct usb_device_id *id) +{ + struct s2255_dev *dev = NULL; + struct usb_host_interface *iface_desc; + struct usb_endpoint_descriptor *endpoint; + int i; + int retval = -ENOMEM; + + dprintk(2, "s2255: probe\n"); + + /* allocate memory for our device state and initialize it to zero */ + dev = kzalloc(sizeof(struct s2255_dev), GFP_KERNEL); + if (dev == NULL) { + err("s2255: out of memory"); + goto error; + } + + dev->fw_data = kzalloc(sizeof(struct s2255_fw), GFP_KERNEL); + if (!dev->fw_data) + goto error; + + mutex_init(&dev->lock); + mutex_init(&dev->open_lock); + + /* grab usb_device and save it */ + dev->udev = usb_get_dev(interface_to_usbdev(interface)); + if (dev->udev == NULL) { + dev_err(&interface->dev, "null usb device\n"); + retval = -ENODEV; + goto error; + } + kref_init(&dev->kref); + dprintk(1, "dev: %p, kref: %p udev %p interface %p\n", dev, &dev->kref, + dev->udev, interface); + dev->interface = interface; + /* set up the endpoint information */ + iface_desc = interface->cur_altsetting; + dprintk(1, "num endpoints %d\n", iface_desc->desc.bNumEndpoints); + for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) { + endpoint = &iface_desc->endpoint[i].desc; + if (!dev->read_endpoint && usb_endpoint_is_bulk_in(endpoint)) { + /* we found the bulk in endpoint */ + dev->read_endpoint = endpoint->bEndpointAddress; + } + } + + if (!dev->read_endpoint) { + dev_err(&interface->dev, "Could not find bulk-in endpoint"); + goto error; + } + + /* set intfdata */ + usb_set_intfdata(interface, dev); + + dprintk(100, "after intfdata %p\n", dev); + + init_timer(&dev->timer); + dev->timer.function = s2255_timer; + dev->timer.data = (unsigned long)dev->fw_data; + + init_waitqueue_head(&dev->fw_data->wait_fw); + + + dev->fw_data->fw_urb = usb_alloc_urb(0, GFP_KERNEL); + + if (!dev->fw_data->fw_urb) { + dev_err(&interface->dev, "out of memory!\n"); + goto error; + } + dev->fw_data->pfw_data = kzalloc(CHUNK_SIZE, GFP_KERNEL); + if (!dev->fw_data->pfw_data) { + dev_err(&interface->dev, "out of memory!\n"); + goto error; + } + /* load the first chunk */ + if (request_firmware(&dev->fw_data->fw, + FIRMWARE_FILE_NAME, &dev->udev->dev)) { + printk(KERN_ERR "sensoray 2255 failed to get firmware\n"); + goto error; + } + + /* loads v4l specific */ + s2255_probe_v4l(dev); + /* load 2255 board specific */ + s2255_board_init(dev); + + dprintk(4, "before probe done %p\n", dev); + spin_lock_init(&dev->slock); + + s2255_fwload_start(dev); + dev_info(&interface->dev, "Sensoray 2255 detected\n"); + return 0; +error: + return retval; +} + +/* disconnect routine. when board is removed physically or with rmmod */ +static void s2255_disconnect(struct usb_interface *interface) +{ + struct s2255_dev *dev = NULL; + dprintk(1, "s2255: disconnect interface %p\n", interface); + dev = usb_get_intfdata(interface); + if (dev) { + kref_put(&dev->kref, s2255_destroy); + dprintk(1, "s2255drv: disconnect\n"); + dev_info(&interface->dev, "s2255usb now disconnected\n"); + } + usb_set_intfdata(interface, NULL); +} + +static struct usb_driver s2255_driver = { + .name = "s2255", + .probe = s2255_probe, + .disconnect = s2255_disconnect, + .id_table = s2255_table, +}; + +static int __init usb_s2255_init(void) +{ + int result; + + /* register this driver with the USB subsystem */ + result = usb_register(&s2255_driver); + + if (result) + err("usb_register failed. Error number %d", result); + + dprintk(2, "s2255_init: done\n"); + return result; +} + +static void __exit usb_s2255_exit(void) +{ + usb_deregister(&s2255_driver); +} + +module_init(usb_s2255_init); +module_exit(usb_s2255_exit); + +MODULE_DESCRIPTION("Sensoray 2255 Video for Linux driver"); +MODULE_AUTHOR("Dean Anderson (Sensoray Company Inc.)"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/video/saa5246a.c b/drivers/media/video/saa5246a.c index 996b49491f5a..03e772130b55 100644 --- a/drivers/media/video/saa5246a.c +++ b/drivers/media/video/saa5246a.c @@ -66,6 +66,7 @@ static struct video_device saa_template; /* Declared near bottom */ /* Addresses to scan */ static unsigned short normal_i2c[] = { I2C_ADDRESS, I2C_CLIENT_END }; + I2C_CLIENT_INSMOD; static struct i2c_client client_template; diff --git a/drivers/media/video/saa5249.c b/drivers/media/video/saa5249.c index ec8c65dc8408..fde99d9ee71f 100644 --- a/drivers/media/video/saa5249.c +++ b/drivers/media/video/saa5249.c @@ -130,6 +130,7 @@ static struct video_device saa_template; /* Declared near bottom */ /* Addresses to scan */ static unsigned short normal_i2c[] = {34>>1,I2C_CLIENT_END}; + I2C_CLIENT_INSMOD; static struct i2c_client client_template; diff --git a/drivers/media/video/saa6588.c b/drivers/media/video/saa6588.c index 716ee7f64df3..f05024259f01 100644 --- a/drivers/media/video/saa6588.c +++ b/drivers/media/video/saa6588.c @@ -31,7 +31,6 @@ #include <linux/wait.h> #include <asm/uaccess.h> - #include <media/rds.h> /* Addresses to scan */ diff --git a/drivers/media/video/saa7115.c b/drivers/media/video/saa7115.c index 435c083cc542..bcd1c8f6cf6b 100644 --- a/drivers/media/video/saa7115.c +++ b/drivers/media/video/saa7115.c @@ -67,7 +67,6 @@ static unsigned short normal_i2c[] = { 0x42 >> 1, 0x40 >> 1, /* SAA7114, SAA7115 and SAA7118 */ I2C_CLIENT_END }; - I2C_CLIENT_INSMOD; struct saa711x_state { @@ -1558,7 +1557,7 @@ static int saa7115_remove(struct i2c_client *client) } static const struct i2c_device_id saa7115_id[] = { - { "saa711x", 1 }, /* autodetect */ + { "saa7115_auto", 1 }, /* autodetect */ { "saa7111", 0 }, { "saa7113", 0 }, { "saa7114", 0 }, @@ -1577,4 +1576,3 @@ static struct v4l2_i2c_driver_data v4l2_i2c_data = { .legacy_class = I2C_CLASS_TV_ANALOG | I2C_CLASS_TV_DIGITAL, .id_table = saa7115_id, }; - diff --git a/drivers/media/video/saa711x.c b/drivers/media/video/saa711x.c deleted file mode 100644 index cedb988574bd..000000000000 --- a/drivers/media/video/saa711x.c +++ /dev/null @@ -1,584 +0,0 @@ -/* - * saa711x - Philips SAA711x video decoder driver version 0.0.1 - * - * To do: Now, it handles only saa7113/7114. Should be improved to - * handle all Philips saa711x devices. - * - * Based on saa7113 driver from Dave Perks <dperks@ibm.net> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include <linux/module.h> -#include <linux/init.h> -#include <linux/delay.h> -#include <linux/errno.h> -#include <linux/fs.h> -#include <linux/kernel.h> -#include <linux/major.h> -#include <linux/slab.h> -#include <linux/mm.h> -#include <linux/signal.h> -#include <asm/io.h> -#include <asm/pgtable.h> -#include <asm/page.h> -#include <linux/types.h> -#include <asm/uaccess.h> -#include <linux/videodev.h> - -MODULE_DESCRIPTION("Philips SAA711x video decoder driver"); -MODULE_AUTHOR("Dave Perks, Jose Ignacio Gijon, Joerg Heckenbach, Mark McClelland, Dwaine Garden"); -MODULE_LICENSE("GPL"); - -#include <linux/i2c.h> - -#define I2C_NAME(s) (s)->name - -#include <linux/video_decoder.h> - -static int debug; -module_param(debug, int, 0644); -MODULE_PARM_DESC(debug, " Set the default Debug level. Default: 0 (Off) - (0-1)"); - - -#define dprintk(num, format, args...) \ - do { \ - if (debug >= num) \ - printk(format, ##args); \ - } while (0) - -/* ----------------------------------------------------------------------- */ - -struct saa711x { - unsigned char reg[32]; - - int norm; - int input; - int enable; - int bright; - int contrast; - int hue; - int sat; -}; - -#define I2C_SAA7113 0x4A -#define I2C_SAA7114 0x42 - -/* ----------------------------------------------------------------------- */ - -static inline int -saa711x_write (struct i2c_client *client, - u8 reg, - u8 value) -{ - struct saa711x *decoder = i2c_get_clientdata(client); - - decoder->reg[reg] = value; - return i2c_smbus_write_byte_data(client, reg, value); -} - -static int -saa711x_write_block (struct i2c_client *client, - const u8 *data, - unsigned int len) -{ - int ret = -1; - u8 reg; - - /* the saa711x has an autoincrement function, use it if - * the adapter understands raw I2C */ - if (i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { - /* do raw I2C, not smbus compatible */ - struct saa711x *decoder = i2c_get_clientdata(client); - struct i2c_msg msg; - u8 block_data[32]; - - msg.addr = client->addr; - msg.flags = 0; - while (len >= 2) { - msg.buf = (char *) block_data; - msg.len = 0; - block_data[msg.len++] = reg = data[0]; - do { - block_data[msg.len++] = - decoder->reg[reg++] = data[1]; - len -= 2; - data += 2; - } while (len >= 2 && data[0] == reg && - msg.len < 32); - if ((ret = i2c_transfer(client->adapter, - &msg, 1)) < 0) - break; - } - } else { - /* do some slow I2C emulation kind of thing */ - while (len >= 2) { - reg = *data++; - if ((ret = saa711x_write(client, reg, - *data++)) < 0) - break; - len -= 2; - } - } - - return ret; -} - -static int -saa711x_init_decoder (struct i2c_client *client, - struct video_decoder_init *init) -{ - return saa711x_write_block(client, init->data, init->len); -} - -static inline int -saa711x_read (struct i2c_client *client, - u8 reg) -{ - return i2c_smbus_read_byte_data(client, reg); -} - -/* ----------------------------------------------------------------------- */ - -static const unsigned char saa711x_i2c_init[] = { - 0x00, 0x00, /* PH711x_CHIP_VERSION 00 - ID byte */ - 0x01, 0x08, /* PH711x_INCREMENT_DELAY - (1) (1) (1) (1) IDEL3 IDEL2 IDELL1 IDEL0 */ - 0x02, 0xc0, /* PH711x_ANALOG_INPUT_CONTR_1 - FUSE1 FUSE0 GUDL1 GUDL0 MODE3 MODE2 MODE1 MODE0 */ - 0x03, 0x23, /* PH711x_ANALOG_INPUT_CONTR_2 - (1) HLNRS VBSL WPOFF HOLDG GAFIX GAI28 GAI18 */ - 0x04, 0x00, /* PH711x_ANALOG_INPUT_CONTR_3 - GAI17 GAI16 GAI15 GAI14 GAI13 GAI12 GAI11 GAI10 */ - 0x05, 0x00, /* PH711x_ANALOG_INPUT_CONTR_4 - GAI27 GAI26 GAI25 GAI24 GAI23 GAI22 GAI21 GAI20 */ - 0x06, 0xeb, /* PH711x_HORIZONTAL_SYNC_START - HSB7 HSB6 HSB5 HSB4 HSB3 HSB2 HSB1 HSB0 */ - 0x07, 0xe0, /* PH711x_HORIZONTAL_SYNC_STOP - HSS7 HSS6 HSS5 HSS4 HSS3 HSS2 HSS1 HSS0 */ - 0x08, 0x88, /* PH711x_SYNC_CONTROL - AUFD FSEL FOET HTC1 HTC0 HPLL VNOI1 VNOI0 */ - 0x09, 0x00, /* PH711x_LUMINANCE_CONTROL - BYPS PREF BPSS1 BPSS0 VBLB UPTCV APER1 APER0 */ - 0x0a, 0x80, /* PH711x_LUMINANCE_BRIGHTNESS - BRIG7 BRIG6 BRIG5 BRIG4 BRIG3 BRIG2 BRIG1 BRIG0 */ - 0x0b, 0x47, /* PH711x_LUMINANCE_CONTRAST - CONT7 CONT6 CONT5 CONT4 CONT3 CONT2 CONT1 CONT0 */ - 0x0c, 0x40, /* PH711x_CHROMA_SATURATION - SATN7 SATN6 SATN5 SATN4 SATN3 SATN2 SATN1 SATN0 */ - 0x0d, 0x00, /* PH711x_CHROMA_HUE_CONTROL - HUEC7 HUEC6 HUEC5 HUEC4 HUEC3 HUEC2 HUEC1 HUEC0 */ - 0x0e, 0x01, /* PH711x_CHROMA_CONTROL - CDTO CSTD2 CSTD1 CSTD0 DCCF FCTC CHBW1 CHBW0 */ - 0x0f, 0xaa, /* PH711x_CHROMA_GAIN_CONTROL - ACGC CGAIN6 CGAIN5 CGAIN4 CGAIN3 CGAIN2 CGAIN1 CGAIN0 */ - 0x10, 0x00, /* PH711x_FORMAT_DELAY_CONTROL - OFTS1 OFTS0 HDEL1 HDEL0 VRLN YDEL2 YDEL1 YDEL0 */ - 0x11, 0x1C, /* PH711x_OUTPUT_CONTROL_1 - GPSW1 CM99 GPSW0 HLSEL OEYC OERT VIPB COLO */ - 0x12, 0x01, /* PH711x_OUTPUT_CONTROL_2 - RTSE13 RTSE12 RTSE11 RTSE10 RTSE03 RTSE02 RTSE01 RTSE00 */ - 0x13, 0x00, /* PH711x_OUTPUT_CONTROL_3 - ADLSB (1) (1) OLDSB FIDP (1) AOSL1 AOSL0 */ - 0x14, 0x00, /* RESERVED 14 - (1) (1) (1) (1) (1) (1) (1) (1) */ - 0x15, 0x00, /* PH711x_V_GATE1_START - VSTA7 VSTA6 VSTA5 VSTA4 VSTA3 VSTA2 VSTA1 VSTA0 */ - 0x16, 0x00, /* PH711x_V_GATE1_STOP - VSTO7 VSTO6 VSTO5 VSTO4 VSTO3 VSTO2 VSTO1 VSTO0 */ - 0x17, 0x00, /* PH711x_V_GATE1_MSB - (1) (1) (1) (1) (1) (1) VSTO8 VSTA8 */ -}; - -static int -saa711x_command (struct i2c_client *client, - unsigned int cmd, - void *arg) -{ - struct saa711x *decoder = i2c_get_clientdata(client); - - switch (cmd) { - - case 0: - case DECODER_INIT: - { - struct video_decoder_init *init = arg; - if (NULL != init) - return saa711x_init_decoder(client, init); - else { - struct video_decoder_init vdi; - vdi.data = saa711x_i2c_init; - vdi.len = sizeof(saa711x_i2c_init); - return saa711x_init_decoder(client, &vdi); - } - } - - case DECODER_DUMP: - { - int i; - - for (i = 0; i < 32; i += 16) { - int j; - - printk(KERN_DEBUG "%s: %03x", I2C_NAME(client), i); - for (j = 0; j < 16; ++j) { - printk(" %02x", - saa711x_read(client, i + j)); - } - printk("\n"); - } - } - break; - - case DECODER_GET_CAPABILITIES: - { - struct video_decoder_capability *cap = arg; - - cap->flags = VIDEO_DECODER_PAL | - VIDEO_DECODER_NTSC | - VIDEO_DECODER_SECAM | - VIDEO_DECODER_AUTO | - VIDEO_DECODER_CCIR; - cap->inputs = 8; - cap->outputs = 1; - } - break; - - case DECODER_GET_STATUS: - { - int *iarg = arg; - int status; - int res; - - status = saa711x_read(client, 0x1f); - dprintk(1, KERN_DEBUG "%s status: 0x%02x\n", I2C_NAME(client), - status); - res = 0; - if ((status & (1 << 6)) == 0) { - res |= DECODER_STATUS_GOOD; - } - switch (decoder->norm) { - case VIDEO_MODE_NTSC: - res |= DECODER_STATUS_NTSC; - break; - case VIDEO_MODE_PAL: - res |= DECODER_STATUS_PAL; - break; - case VIDEO_MODE_SECAM: - res |= DECODER_STATUS_SECAM; - break; - default: - case VIDEO_MODE_AUTO: - if ((status & (1 << 5)) != 0) { - res |= DECODER_STATUS_NTSC; - } else { - res |= DECODER_STATUS_PAL; - } - break; - } - if ((status & (1 << 0)) != 0) { - res |= DECODER_STATUS_COLOR; - } - *iarg = res; - } - break; - - case DECODER_SET_GPIO: - { - int *iarg = arg; - if (0 != *iarg) { - saa711x_write(client, 0x11, - (decoder->reg[0x11] | 0x80)); - } else { - saa711x_write(client, 0x11, - (decoder->reg[0x11] & 0x7f)); - } - break; - } - - case DECODER_SET_VBI_BYPASS: - { - int *iarg = arg; - if (0 != *iarg) { - saa711x_write(client, 0x13, - (decoder->reg[0x13] & 0xf0) | 0x0a); - } else { - saa711x_write(client, 0x13, - (decoder->reg[0x13] & 0xf0)); - } - break; - } - - case DECODER_SET_NORM: - { - int *iarg = arg; - - switch (*iarg) { - - case VIDEO_MODE_NTSC: - saa711x_write(client, 0x08, - (decoder->reg[0x08] & 0x3f) | 0x40); - saa711x_write(client, 0x0e, - (decoder->reg[0x0e] & 0x8f)); - break; - - case VIDEO_MODE_PAL: - saa711x_write(client, 0x08, - (decoder->reg[0x08] & 0x3f) | 0x00); - saa711x_write(client, 0x0e, - (decoder->reg[0x0e] & 0x8f)); - break; - - case VIDEO_MODE_SECAM: - saa711x_write(client, 0x08, - (decoder->reg[0x08] & 0x3f) | 0x00); - saa711x_write(client, 0x0e, - (decoder->reg[0x0e] & 0x8f) | 0x50); - break; - - case VIDEO_MODE_AUTO: - saa711x_write(client, 0x08, - (decoder->reg[0x08] & 0x3f) | 0x80); - saa711x_write(client, 0x0e, - (decoder->reg[0x0e] & 0x8f)); - break; - - default: - return -EINVAL; - - } - decoder->norm = *iarg; - } - break; - - case DECODER_SET_INPUT: - { - int *iarg = arg; - if (*iarg < 0 || *iarg > 9) { - return -EINVAL; - } - if (decoder->input != *iarg) { - decoder->input = *iarg; - /* select mode */ - saa711x_write(client, 0x02, - (decoder->reg[0x02] & 0xf0) | decoder->input); - /* bypass chrominance trap for modes 4..7 */ - saa711x_write(client, 0x09, - (decoder->reg[0x09] & 0x7f) | ((decoder->input > 3) ? 0x80 : 0)); - } - } - break; - - case DECODER_SET_OUTPUT: - { - int *iarg = arg; - - /* not much choice of outputs */ - if (*iarg != 0) { - return -EINVAL; - } - } - break; - - case DECODER_ENABLE_OUTPUT: - { - int *iarg = arg; - int enable = (*iarg != 0); - - if (decoder->enable != enable) { - decoder->enable = enable; - - /* RJ: If output should be disabled (for - * playing videos), we also need a open PLL. - * The input is set to 0 (where no input - * source is connected), although this - * is not necessary. - * - * If output should be enabled, we have to - * reverse the above. - */ - - if (decoder->enable) { - saa711x_write(client, 0x02, - (decoder-> - reg[0x02] & 0xf8) | - decoder->input); - saa711x_write(client, 0x08, - (decoder->reg[0x08] & 0xfb)); - saa711x_write(client, 0x11, - (decoder-> - reg[0x11] & 0xf3) | 0x0c); - } else { - saa711x_write(client, 0x02, - (decoder->reg[0x02] & 0xf8)); - saa711x_write(client, 0x08, - (decoder-> - reg[0x08] & 0xfb) | 0x04); - saa711x_write(client, 0x11, - (decoder->reg[0x11] & 0xf3)); - } - } - } - break; - - case DECODER_SET_PICTURE: - { - struct video_picture *pic = arg; - - if (decoder->bright != pic->brightness) { - /* We want 0 to 255 we get 0-65535 */ - decoder->bright = pic->brightness; - saa711x_write(client, 0x0a, decoder->bright >> 8); - } - if (decoder->contrast != pic->contrast) { - /* We want 0 to 127 we get 0-65535 */ - decoder->contrast = pic->contrast; - saa711x_write(client, 0x0b, - decoder->contrast >> 9); - } - if (decoder->sat != pic->colour) { - /* We want 0 to 127 we get 0-65535 */ - decoder->sat = pic->colour; - saa711x_write(client, 0x0c, decoder->sat >> 9); - } - if (decoder->hue != pic->hue) { - /* We want -128 to 127 we get 0-65535 */ - decoder->hue = pic->hue; - saa711x_write(client, 0x0d, - (decoder->hue - 32768) >> 8); - } - } - break; - - default: - return -EINVAL; - } - - return 0; -} - -/* ----------------------------------------------------------------------- */ - -/* - * Generic i2c probe - * concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1' - */ - -/* standard i2c insmod options */ -static unsigned short normal_i2c[] = { - I2C_SAA7113>>1, /* saa7113 */ - I2C_SAA7114>>1, /* saa7114 */ - I2C_CLIENT_END -}; - -I2C_CLIENT_INSMOD; - - -static struct i2c_driver i2c_driver_saa711x; - -static int -saa711x_detect_client (struct i2c_adapter *adapter, - int address, - int kind) -{ - int i; - struct i2c_client *client; - struct saa711x *decoder; - struct video_decoder_init vdi; - - dprintk(1, - KERN_INFO - "saa711x.c: detecting saa711x client on address 0x%x\n", - address << 1); - - /* Check if the adapter supports the needed features */ - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) - return 0; - - client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL); - if (client == 0) - return -ENOMEM; - client->addr = address; - client->adapter = adapter; - client->driver = &i2c_driver_saa711x; - strlcpy(I2C_NAME(client), "saa711x", sizeof(I2C_NAME(client))); - decoder = kzalloc(sizeof(struct saa711x), GFP_KERNEL); - if (decoder == NULL) { - kfree(client); - return -ENOMEM; - } - decoder->norm = VIDEO_MODE_NTSC; - decoder->input = 0; - decoder->enable = 1; - decoder->bright = 32768; - decoder->contrast = 32768; - decoder->hue = 32768; - decoder->sat = 32768; - i2c_set_clientdata(client, decoder); - - i = i2c_attach_client(client); - if (i) { - kfree(client); - kfree(decoder); - return i; - } - - vdi.data = saa711x_i2c_init; - vdi.len = sizeof(saa711x_i2c_init); - i = saa711x_init_decoder(client, &vdi); - if (i < 0) { - dprintk(1, KERN_ERR "%s_attach error: init status %d\n", - I2C_NAME(client), i); - } else { - dprintk(1, - KERN_INFO - "%s_attach: chip version %x at address 0x%x\n", - I2C_NAME(client), saa711x_read(client, 0x00) >> 4, - client->addr << 1); - } - - return 0; -} - -static int -saa711x_attach_adapter (struct i2c_adapter *adapter) -{ - dprintk(1, - KERN_INFO - "saa711x.c: starting probe for adapter %s (0x%x)\n", - I2C_NAME(adapter), adapter->id); - return i2c_probe(adapter, &addr_data, &saa711x_detect_client); -} - -static int -saa711x_detach_client (struct i2c_client *client) -{ - struct saa711x *decoder = i2c_get_clientdata(client); - int err; - - err = i2c_detach_client(client); - if (err) { - return err; - } - - kfree(decoder); - kfree(client); - - return 0; -} - -/* ----------------------------------------------------------------------- */ - -static struct i2c_driver i2c_driver_saa711x = { - .driver = { - .name = "saa711x", - }, - .id = I2C_DRIVERID_SAA711X, - .attach_adapter = saa711x_attach_adapter, - .detach_client = saa711x_detach_client, - .command = saa711x_command, -}; - -static int __init -saa711x_init (void) -{ - return i2c_add_driver(&i2c_driver_saa711x); -} - -static void __exit -saa711x_exit (void) -{ - i2c_del_driver(&i2c_driver_saa711x); -} - -module_init(saa711x_init); -module_exit(saa711x_exit); diff --git a/drivers/media/video/saa7127.c b/drivers/media/video/saa7127.c index 79d11a658bdf..d0e83fe0ff51 100644 --- a/drivers/media/video/saa7127.c +++ b/drivers/media/video/saa7127.c @@ -666,7 +666,6 @@ static int saa7127_probe(struct i2c_client *client, { struct saa7127_state *state; struct v4l2_sliced_vbi_data vbi = { 0, 0, 0, 0 }; /* set to disabled */ - int read_result = 0; /* Check if the adapter supports the needed features */ if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) @@ -710,20 +709,29 @@ static int saa7127_probe(struct i2c_client *client, saa7127_set_input_type(client, SAA7127_INPUT_TYPE_NORMAL); saa7127_set_video_enable(client, 1); - /* Detect if it's an saa7129 */ - read_result = saa7127_read(client, SAA7129_REG_FADE_KEY_COL2); - saa7127_write(client, SAA7129_REG_FADE_KEY_COL2, 0xaa); - if (saa7127_read(client, SAA7129_REG_FADE_KEY_COL2) == 0xaa) { - v4l_info(client, "saa7129 found @ 0x%x (%s)\n", - client->addr << 1, client->adapter->name); - saa7127_write(client, SAA7129_REG_FADE_KEY_COL2, read_result); - saa7127_write_inittab(client, saa7129_init_config_extra); - state->ident = V4L2_IDENT_SAA7129; - } else { - v4l_info(client, "saa7127 found @ 0x%x (%s)\n", - client->addr << 1, client->adapter->name); - state->ident = V4L2_IDENT_SAA7127; + if (id->driver_data) { /* Chip type is already known */ + state->ident = id->driver_data; + } else { /* Needs detection */ + int read_result; + + /* Detect if it's an saa7129 */ + read_result = saa7127_read(client, SAA7129_REG_FADE_KEY_COL2); + saa7127_write(client, SAA7129_REG_FADE_KEY_COL2, 0xaa); + if (saa7127_read(client, SAA7129_REG_FADE_KEY_COL2) == 0xaa) { + saa7127_write(client, SAA7129_REG_FADE_KEY_COL2, + read_result); + state->ident = V4L2_IDENT_SAA7129; + strlcpy(client->name, "saa7129", I2C_NAME_SIZE); + } else { + state->ident = V4L2_IDENT_SAA7127; + strlcpy(client->name, "saa7127", I2C_NAME_SIZE); + } } + + v4l_info(client, "%s found @ 0x%x (%s)\n", client->name, + client->addr << 1, client->adapter->name); + if (state->ident == V4L2_IDENT_SAA7129) + saa7127_write_inittab(client, saa7129_init_config_extra); return 0; } @@ -740,7 +748,11 @@ static int saa7127_remove(struct i2c_client *client) /* ----------------------------------------------------------------------- */ static struct i2c_device_id saa7127_id[] = { - { "saa7127", 0 }, + { "saa7127_auto", 0 }, /* auto-detection */ + { "saa7126", V4L2_IDENT_SAA7127 }, + { "saa7127", V4L2_IDENT_SAA7127 }, + { "saa7128", V4L2_IDENT_SAA7129 }, + { "saa7129", V4L2_IDENT_SAA7129 }, { } }; MODULE_DEVICE_TABLE(i2c, saa7127_id); @@ -753,4 +765,3 @@ static struct v4l2_i2c_driver_data v4l2_i2c_data = { .remove = saa7127_remove, .id_table = saa7127_id, }; - diff --git a/drivers/media/video/saa7134/saa6752hs.c b/drivers/media/video/saa7134/saa6752hs.c index 002e70a33a4f..707be175509d 100644 --- a/drivers/media/video/saa7134/saa6752hs.c +++ b/drivers/media/video/saa7134/saa6752hs.c @@ -13,7 +13,6 @@ #include <linux/init.h> #include <linux/crc32.h> - #define MPEG_VIDEO_TARGET_BITRATE_MAX 27000 #define MPEG_VIDEO_MAX_BITRATE_MAX 27000 #define MPEG_TOTAL_TARGET_BITRATE_MAX 27000 @@ -21,6 +20,7 @@ /* Addresses to scan */ static unsigned short normal_i2c[] = {0x20, I2C_CLIENT_END}; + I2C_CLIENT_INSMOD; MODULE_DESCRIPTION("device driver for saa6752hs MPEG2 encoder"); @@ -448,6 +448,104 @@ static int handle_ctrl(struct saa6752hs_mpeg_params *params, return 0; } +static int saa6752hs_qctrl(struct saa6752hs_mpeg_params *params, + struct v4l2_queryctrl *qctrl) +{ + int err; + + switch (qctrl->id) { + case V4L2_CID_MPEG_AUDIO_ENCODING: + return v4l2_ctrl_query_fill(qctrl, + V4L2_MPEG_AUDIO_ENCODING_LAYER_2, + V4L2_MPEG_AUDIO_ENCODING_LAYER_2, 1, + V4L2_MPEG_AUDIO_ENCODING_LAYER_2); + + case V4L2_CID_MPEG_AUDIO_L2_BITRATE: + return v4l2_ctrl_query_fill(qctrl, + V4L2_MPEG_AUDIO_L2_BITRATE_256K, + V4L2_MPEG_AUDIO_L2_BITRATE_384K, 1, + V4L2_MPEG_AUDIO_L2_BITRATE_256K); + + case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ: + return v4l2_ctrl_query_fill(qctrl, + V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000, + V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000, 1, + V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000); + + case V4L2_CID_MPEG_VIDEO_ENCODING: + return v4l2_ctrl_query_fill(qctrl, + V4L2_MPEG_VIDEO_ENCODING_MPEG_2, + V4L2_MPEG_VIDEO_ENCODING_MPEG_2, 1, + V4L2_MPEG_VIDEO_ENCODING_MPEG_2); + + case V4L2_CID_MPEG_VIDEO_ASPECT: + return v4l2_ctrl_query_fill(qctrl, + V4L2_MPEG_VIDEO_ASPECT_4x3, + V4L2_MPEG_VIDEO_ASPECT_16x9, 1, + V4L2_MPEG_VIDEO_ASPECT_4x3); + + case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK: + err = v4l2_ctrl_query_fill_std(qctrl); + if (err == 0 && + params->vi_bitrate_mode == + V4L2_MPEG_VIDEO_BITRATE_MODE_CBR) + qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE; + return err; + + case V4L2_CID_MPEG_STREAM_TYPE: + return v4l2_ctrl_query_fill(qctrl, + V4L2_MPEG_STREAM_TYPE_MPEG2_TS, + V4L2_MPEG_STREAM_TYPE_MPEG2_TS, 1, + V4L2_MPEG_STREAM_TYPE_MPEG2_TS); + + case V4L2_CID_MPEG_VIDEO_BITRATE_MODE: + case V4L2_CID_MPEG_VIDEO_BITRATE: + case V4L2_CID_MPEG_STREAM_PID_PMT: + case V4L2_CID_MPEG_STREAM_PID_AUDIO: + case V4L2_CID_MPEG_STREAM_PID_VIDEO: + case V4L2_CID_MPEG_STREAM_PID_PCR: + return v4l2_ctrl_query_fill_std(qctrl); + + default: + break; + } + return -EINVAL; +} + +static int saa6752hs_qmenu(struct saa6752hs_mpeg_params *params, + struct v4l2_querymenu *qmenu) +{ + static const char *mpeg_audio_l2_bitrate[] = { + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "256 kbps", + "", + "384 kbps", + NULL + }; + struct v4l2_queryctrl qctrl; + int err; + + qctrl.id = qmenu->id; + err = saa6752hs_qctrl(params, &qctrl); + if (err) + return err; + if (qmenu->id == V4L2_CID_MPEG_AUDIO_L2_BITRATE) + return v4l2_ctrl_query_menu(qmenu, &qctrl, + mpeg_audio_l2_bitrate); + return v4l2_ctrl_query_menu(qmenu, &qctrl, + v4l2_ctrl_get_menu(qmenu->id)); +} + static int saa6752hs_init(struct i2c_client* client) { unsigned char buf[9], buf2[4]; @@ -609,7 +707,6 @@ static int saa6752hs_attach(struct i2c_adapter *adap, int addr, int kind) i2c_attach_client(&h->client); v4l_info(&h->client,"saa6752hs: chip found @ 0x%x\n", addr<<1); - return 0; } @@ -662,6 +759,10 @@ saa6752hs_command(struct i2c_client *client, unsigned int cmd, void *arg) } h->params = params; break; + case VIDIOC_QUERYCTRL: + return saa6752hs_qctrl(&h->params, arg); + case VIDIOC_QUERYMENU: + return saa6752hs_qmenu(&h->params, arg); case VIDIOC_G_FMT: { struct v4l2_format *f = arg; diff --git a/drivers/media/video/saa7134/saa7134-alsa.c b/drivers/media/video/saa7134/saa7134-alsa.c index f118de6e3672..9929d20320b4 100644 --- a/drivers/media/video/saa7134/saa7134-alsa.c +++ b/drivers/media/video/saa7134/saa7134-alsa.c @@ -80,7 +80,6 @@ typedef struct snd_card_saa7134 { } snd_card_saa7134_t; - /* * PCM structure */ @@ -1121,6 +1120,3 @@ late_initcall(saa7134_alsa_init); module_exit(saa7134_alsa_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Ricardo Cerqueira"); - - - diff --git a/drivers/media/video/saa7134/saa7134-cards.c b/drivers/media/video/saa7134/saa7134-cards.c index 2618cfa592e7..6893f998d292 100644 --- a/drivers/media/video/saa7134/saa7134-cards.c +++ b/drivers/media/video/saa7134/saa7134-cards.c @@ -1287,6 +1287,22 @@ struct saa7134_board saa7134_boards[] = { .vmux = 8, }}, }, + [SAA7134_BOARD_AVERMEDIA_M103] = { + /* Massimo Piccioni <dafastidio@libero.it> */ + .name = "AVerMedia MiniPCI DVB-T Hybrid M103", + .audio_clock = 0x187de7, + .tuner_type = TUNER_XC2028, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .mpeg = SAA7134_MPEG_DVB, + .inputs = {{ + .name = name_tv, + .vmux = 1, + .amux = TV, + .tv = 1, + } }, + }, [SAA7134_BOARD_NOVAC_PRIMETV7133] = { /* toshii@netbsd.org */ .name = "Noval Prime TV 7133", @@ -3503,6 +3519,39 @@ struct saa7134_board saa7134_boards[] = { .amux = TV, .gpio = 0x0200000, }, + }, + [SAA7134_BOARD_ASUSTeK_P7131_ANALOG] = { + .name = "ASUSTeK P7131 Analog", + .audio_clock = 0x00187de7, + .tuner_type = TUNER_PHILIPS_TDA8290, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .gpiomask = 1 << 21, + .inputs = {{ + .name = name_tv, + .vmux = 1, + .amux = TV, + .tv = 1, + .gpio = 0x0000000, + }, { + .name = name_comp1, + .vmux = 3, + .amux = LINE2, + }, { + .name = name_comp2, + .vmux = 0, + .amux = LINE2, + }, { + .name = name_svideo, + .vmux = 8, + .amux = LINE2, + } }, + .radio = { + .name = name_radio, + .amux = TV, + .gpio = 0x0200000, + }, }, [SAA7134_BOARD_SABRENT_TV_PCB05] = { .name = "Sabrent PCMCIA TV-PCB05", @@ -3940,32 +3989,111 @@ struct saa7134_board saa7134_boards[] = { [SAA7134_BOARD_BEHOLD_M6] = { /* Igor Kuznetsov <igk@igk.ru> */ /* Andrey Melnikoff <temnota@kmv.ru> */ - .name = "Beholder BeholdTV M6 / BeholdTV M6 Extra", + /* Beholder Intl. Ltd. Dmitry Belimov <d.belimov@gmail.com> */ + .name = "Beholder BeholdTV M6", .audio_clock = 0x00187de7, .tuner_type = TUNER_PHILIPS_FM1216ME_MK3, .radio_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, .tda9887_conf = TDA9887_PRESENT, - .inputs = {{ + .inputs = { { .name = name_tv, .vmux = 3, .amux = TV, .tv = 1, - },{ + }, { .name = name_comp1, .vmux = 1, .amux = LINE1, - },{ + }, { .name = name_svideo, .vmux = 8, .amux = LINE1, - }}, + } }, .radio = { .name = name_radio, .amux = LINE2, }, .mpeg = SAA7134_MPEG_EMPRESS, + .video_out = CCIR656, + .vid_port_opts = (SET_T_CODE_POLARITY_NON_INVERTED | + SET_CLOCK_NOT_DELAYED | + SET_CLOCK_INVERTED | + SET_VSYNC_OFF), + }, + [SAA7134_BOARD_BEHOLD_M63] = { + /* Igor Kuznetsov <igk@igk.ru> */ + /* Andrey Melnikoff <temnota@kmv.ru> */ + /* Beholder Intl. Ltd. Dmitry Belimov <d.belimov@gmail.com> */ + .name = "Beholder BeholdTV M63", + .audio_clock = 0x00187de7, + .tuner_type = TUNER_PHILIPS_FM1216ME_MK3, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .tda9887_conf = TDA9887_PRESENT, + .inputs = { { + .name = name_tv, + .vmux = 3, + .amux = TV, + .tv = 1, + }, { + .name = name_comp1, + .vmux = 1, + .amux = LINE1, + }, { + .name = name_svideo, + .vmux = 8, + .amux = LINE1, + } }, + .radio = { + .name = name_radio, + .amux = LINE2, + }, + .mpeg = SAA7134_MPEG_EMPRESS, + .video_out = CCIR656, + .vid_port_opts = (SET_T_CODE_POLARITY_NON_INVERTED | + SET_CLOCK_NOT_DELAYED | + SET_CLOCK_INVERTED | + SET_VSYNC_OFF), + }, + [SAA7134_BOARD_BEHOLD_M6_EXTRA] = { + /* Igor Kuznetsov <igk@igk.ru> */ + /* Andrey Melnikoff <temnota@kmv.ru> */ + /* Beholder Intl. Ltd. Dmitry Belimov <d.belimov@gmail.com> */ + .name = "Beholder BeholdTV M6 Extra", + .audio_clock = 0x00187de7, + /* FIXME: Must be PHILIPS_FM1216ME_MK5*/ + .tuner_type = TUNER_PHILIPS_FM1216ME_MK3, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .tda9887_conf = TDA9887_PRESENT, + .inputs = { { + .name = name_tv, + .vmux = 3, + .amux = TV, + .tv = 1, + }, { + .name = name_comp1, + .vmux = 1, + .amux = LINE1, + }, { + .name = name_svideo, + .vmux = 8, + .amux = LINE1, + } }, + .radio = { + .name = name_radio, + .amux = LINE2, + }, + .mpeg = SAA7134_MPEG_EMPRESS, + .video_out = CCIR656, + .vid_port_opts = (SET_T_CODE_POLARITY_NON_INVERTED | + SET_CLOCK_NOT_DELAYED | + SET_CLOCK_INVERTED | + SET_VSYNC_OFF), }, [SAA7134_BOARD_TWINHAN_DTV_DVB_3056] = { .name = "Twinhan Hybrid DTV-DVB 3056 PCI", @@ -4121,9 +4249,9 @@ struct saa7134_board saa7134_boards[] = { .amux = TV, .tv = 1, }, { - .name = name_comp1, - .vmux = 3, - .amux = LINE2, + .name = name_comp, + .vmux = 0, + .amux = LINE1, }, { .name = name_svideo, .vmux = 8, @@ -4141,6 +4269,7 @@ struct saa7134_board saa7134_boards[] = { .radio_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, + .mpeg = SAA7134_MPEG_DVB, .inputs = {{ .name = name_tv, .vmux = 1, @@ -4150,6 +4279,10 @@ struct saa7134_board saa7134_boards[] = { .name = name_svideo, .vmux = 8, .amux = LINE1, + }, { + .name = name_comp, + .vmux = 0, + .amux = LINE1, } }, .radio = { .name = name_radio, @@ -4163,7 +4296,6 @@ struct saa7134_board saa7134_boards[] = { .radio_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .mpeg = SAA7134_MPEG_DVB, .inputs = {{ .name = name_tv, .vmux = 1, @@ -5226,13 +5358,13 @@ struct pci_device_id saa7134_pci_tbl[] = { .device = PCI_DEVICE_ID_PHILIPS_SAA7133, .subvendor = 0x5ace, .subdevice = 0x6193, - .driver_data = SAA7134_BOARD_BEHOLD_M6, + .driver_data = SAA7134_BOARD_BEHOLD_M6_EXTRA, }, { .vendor = PCI_VENDOR_ID_PHILIPS, .device = PCI_DEVICE_ID_PHILIPS_SAA7133, .subvendor = 0x5ace, .subdevice = 0x6191, - .driver_data = SAA7134_BOARD_BEHOLD_M6, + .driver_data = SAA7134_BOARD_BEHOLD_M63, },{ .vendor = PCI_VENDOR_ID_PHILIPS, .device = PCI_DEVICE_ID_PHILIPS_SAA7133, @@ -5284,10 +5416,22 @@ struct pci_device_id saa7134_pci_tbl[] = { }, { .vendor = PCI_VENDOR_ID_PHILIPS, .device = PCI_DEVICE_ID_PHILIPS_SAA7133, + .subvendor = 0x5169, + .subdevice = 0x1502, + .driver_data = SAA7134_BOARD_FLYTVPLATINUM_MINI, + }, { + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7133, .subvendor = 0x5ace, .subdevice = 0x6290, .driver_data = SAA7134_BOARD_BEHOLD_H6, }, { + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7133, + .subvendor = 0x1461, /* Avermedia Technologies Inc */ + .subdevice = 0xf636, + .driver_data = SAA7134_BOARD_AVERMEDIA_M103, + }, { /* --- boards without eeprom + subsystem ID --- */ .vendor = PCI_VENDOR_ID_PHILIPS, .device = PCI_DEVICE_ID_PHILIPS_SAA7134, @@ -5352,6 +5496,7 @@ static int saa7134_xc2028_callback(struct saa7134_dev *dev, saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, 0x00008000, 0x00008000); switch (dev->board) { case SAA7134_BOARD_AVERMEDIA_CARDBUS_506: + case SAA7134_BOARD_AVERMEDIA_M103: saa7134_set_gpio(dev, 23, 0); msleep(10); saa7134_set_gpio(dev, 23, 1); @@ -5493,6 +5638,7 @@ int saa7134_board_init1(struct saa7134_dev *dev) case SAA7134_BOARD_FLYDVBT_LR301: case SAA7134_BOARD_ASUSTeK_P7131_DUAL: case SAA7134_BOARD_ASUSTeK_P7131_HYBRID_LNA: + case SAA7134_BOARD_ASUSTeK_P7131_ANALOG: case SAA7134_BOARD_FLYDVBTDUO: case SAA7134_BOARD_PROTEUS_2309: case SAA7134_BOARD_AVERMEDIA_A16AR: @@ -5560,6 +5706,7 @@ int saa7134_board_init1(struct saa7134_dev *dev) msleep(10); break; case SAA7134_BOARD_AVERMEDIA_CARDBUS_506: + case SAA7134_BOARD_AVERMEDIA_M103: saa7134_set_gpio(dev, 23, 0); msleep(10); saa7134_set_gpio(dev, 23, 1); @@ -5601,6 +5748,8 @@ int saa7134_board_init1(struct saa7134_dev *dev) case SAA7134_BOARD_HAUPPAUGE_HVR1110: case SAA7134_BOARD_BEHOLD_607_9FM: case SAA7134_BOARD_BEHOLD_M6: + case SAA7134_BOARD_BEHOLD_M63: + case SAA7134_BOARD_BEHOLD_M6_EXTRA: dev->has_remote = SAA7134_REMOTE_I2C; break; case SAA7134_BOARD_AVERMEDIA_A169_B: @@ -5683,6 +5832,7 @@ static void saa7134_tuner_setup(struct saa7134_dev *dev) switch (dev->board) { case SAA7134_BOARD_AVERMEDIA_A16D: case SAA7134_BOARD_AVERMEDIA_CARDBUS_506: + case SAA7134_BOARD_AVERMEDIA_M103: ctl.demod = XC3028_FE_ZARLINK456; break; default: @@ -5825,6 +5975,15 @@ int saa7134_board_init2(struct saa7134_dev *dev) i2c_transfer(&dev->i2c_adap, &msg, 1); break; } + case SAA7134_BOARD_ASUSTeK_TVFM7135: + /* The card below is detected as card=53, but is different */ + if (dev->autodetected && (dev->eedata[0x27] == 0x03)) { + dev->board = SAA7134_BOARD_ASUSTeK_P7131_ANALOG; + printk(KERN_INFO "%s: P7131 analog only, using " + "entry of %s\n", + dev->name, saa7134_boards[dev->board].name); + } + break; case SAA7134_BOARD_HAUPPAUGE_HVR1110: hauppauge_eeprom(dev, dev->eedata+0x80); /* break intentionally omitted */ diff --git a/drivers/media/video/saa7134/saa7134-core.c b/drivers/media/video/saa7134/saa7134-core.c index 2c19cd0113c8..cfee84ee7a88 100644 --- a/drivers/media/video/saa7134/saa7134-core.c +++ b/drivers/media/video/saa7134/saa7134-core.c @@ -150,7 +150,6 @@ void saa7134_set_gpio(struct saa7134_dev *dev, int bit_no, int value) #if defined(CONFIG_MODULES) && defined(MODULE) - static void request_module_async(struct work_struct *work){ struct saa7134_dev* dev = container_of(work, struct saa7134_dev, request_module_wk); if (card_is_empress(dev)) diff --git a/drivers/media/video/saa7134/saa7134-dvb.c b/drivers/media/video/saa7134/saa7134-dvb.c index 341b101b0357..be48b9b66a67 100644 --- a/drivers/media/video/saa7134/saa7134-dvb.c +++ b/drivers/media/video/saa7134/saa7134-dvb.c @@ -1263,6 +1263,7 @@ static int dvb_init(struct saa7134_dev *dev) &avermedia_xc3028_mt352_dev, &dev->i2c_adap); attach_xc3028 = 1; + break; case SAA7134_BOARD_MD7134_BRIDGE_2: dev->dvb.frontend = dvb_attach(tda10086_attach, &sd1878_4m, &dev->i2c_adap); @@ -1290,6 +1291,15 @@ static int dvb_init(struct saa7134_dev *dev) fe->ops.enable_high_lnb_voltage = md8800_set_high_voltage; } break; + case SAA7134_BOARD_AVERMEDIA_M103: + saa7134_set_gpio(dev, 25, 0); + msleep(10); + saa7134_set_gpio(dev, 25, 1); + dev->dvb.frontend = dvb_attach(mt352_attach, + &avermedia_xc3028_mt352_dev, + &dev->i2c_adap); + attach_xc3028 = 1; + break; default: wprintk("Huh? unknown DVB card?\n"); break; diff --git a/drivers/media/video/saa7134/saa7134-empress.c b/drivers/media/video/saa7134/saa7134-empress.c index 3ae71a340822..2a5ab957542d 100644 --- a/drivers/media/video/saa7134/saa7134-empress.c +++ b/drivers/media/video/saa7134/saa7134-empress.c @@ -208,7 +208,7 @@ static int empress_s_input(struct file *file, void *priv, unsigned int i) return 0; } -static int empress_enum_fmt_cap(struct file *file, void *priv, +static int empress_enum_fmt_vid_cap(struct file *file, void *priv, struct v4l2_fmtdesc *f) { if (f->index != 0) @@ -220,7 +220,7 @@ static int empress_enum_fmt_cap(struct file *file, void *priv, return 0; } -static int empress_g_fmt_cap(struct file *file, void *priv, +static int empress_g_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f) { struct saa7134_dev *dev = file->private_data; @@ -233,7 +233,7 @@ static int empress_g_fmt_cap(struct file *file, void *priv, return 0; } -static int empress_s_fmt_cap(struct file *file, void *priv, +static int empress_s_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f) { struct saa7134_dev *dev = file->private_data; @@ -294,10 +294,20 @@ static int empress_streamoff(struct file *file, void *priv, return videobuf_streamoff(&dev->empress_tsq); } +static int saa7134_i2c_call_saa6752(struct saa7134_dev *dev, + unsigned int cmd, void *arg) +{ + if (dev->mpeg_i2c_client == NULL) + return -EINVAL; + return dev->mpeg_i2c_client->driver->command(dev->mpeg_i2c_client, + cmd, arg); +} + static int empress_s_ext_ctrls(struct file *file, void *priv, struct v4l2_ext_controls *ctrls) { struct saa7134_dev *dev = file->private_data; + int err; /* count == 0 is abused in saa6752hs.c, so that special case is handled here explicitly. */ @@ -307,10 +317,10 @@ static int empress_s_ext_ctrls(struct file *file, void *priv, if (ctrls->ctrl_class != V4L2_CTRL_CLASS_MPEG) return -EINVAL; - saa7134_i2c_call_clients(dev, VIDIOC_S_EXT_CTRLS, ctrls); + err = saa7134_i2c_call_saa6752(dev, VIDIOC_S_EXT_CTRLS, ctrls); ts_init_encoder(dev); - return 0; + return err; } static int empress_g_ext_ctrls(struct file *file, void *priv, @@ -320,9 +330,62 @@ static int empress_g_ext_ctrls(struct file *file, void *priv, if (ctrls->ctrl_class != V4L2_CTRL_CLASS_MPEG) return -EINVAL; - saa7134_i2c_call_clients(dev, VIDIOC_G_EXT_CTRLS, ctrls); + return saa7134_i2c_call_saa6752(dev, VIDIOC_G_EXT_CTRLS, ctrls); +} - return 0; +static int empress_queryctrl(struct file *file, void *priv, + struct v4l2_queryctrl *c) +{ + static const u32 user_ctrls[] = { + V4L2_CID_USER_CLASS, + V4L2_CID_BRIGHTNESS, + V4L2_CID_CONTRAST, + V4L2_CID_SATURATION, + V4L2_CID_HUE, + V4L2_CID_AUDIO_VOLUME, + V4L2_CID_AUDIO_MUTE, + V4L2_CID_HFLIP, + 0 + }; + + static const u32 mpeg_ctrls[] = { + V4L2_CID_MPEG_CLASS, + V4L2_CID_MPEG_STREAM_TYPE, + V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ, + V4L2_CID_MPEG_AUDIO_ENCODING, + V4L2_CID_MPEG_AUDIO_L2_BITRATE, + V4L2_CID_MPEG_VIDEO_ENCODING, + V4L2_CID_MPEG_VIDEO_ASPECT, + V4L2_CID_MPEG_VIDEO_BITRATE_MODE, + V4L2_CID_MPEG_VIDEO_BITRATE, + V4L2_CID_MPEG_VIDEO_BITRATE_PEAK, + 0 + }; + static const u32 *ctrl_classes[] = { + user_ctrls, + mpeg_ctrls, + NULL + }; + struct saa7134_dev *dev = file->private_data; + + c->id = v4l2_ctrl_next(ctrl_classes, c->id); + if (c->id == 0) + return -EINVAL; + if (c->id == V4L2_CID_USER_CLASS || c->id == V4L2_CID_MPEG_CLASS) + return v4l2_ctrl_query_fill_std(c); + if (V4L2_CTRL_ID2CLASS(c->id) != V4L2_CTRL_CLASS_MPEG) + return saa7134_queryctrl(file, priv, c); + return saa7134_i2c_call_saa6752(dev, VIDIOC_QUERYCTRL, c); +} + +static int empress_querymenu(struct file *file, void *priv, + struct v4l2_querymenu *c) +{ + struct saa7134_dev *dev = file->private_data; + + if (V4L2_CTRL_ID2CLASS(c->id) != V4L2_CTRL_CLASS_MPEG) + return -EINVAL; + return saa7134_i2c_call_saa6752(dev, VIDIOC_QUERYMENU, c); } static const struct file_operations ts_fops = @@ -348,9 +411,9 @@ static struct video_device saa7134_empress_template = .minor = -1, .vidioc_querycap = empress_querycap, - .vidioc_enum_fmt_cap = empress_enum_fmt_cap, - .vidioc_s_fmt_cap = empress_s_fmt_cap, - .vidioc_g_fmt_cap = empress_g_fmt_cap, + .vidioc_enum_fmt_vid_cap = empress_enum_fmt_vid_cap, + .vidioc_s_fmt_vid_cap = empress_s_fmt_vid_cap, + .vidioc_g_fmt_vid_cap = empress_g_fmt_vid_cap, .vidioc_reqbufs = empress_reqbufs, .vidioc_querybuf = empress_querybuf, .vidioc_qbuf = empress_qbuf, @@ -363,7 +426,8 @@ static struct video_device saa7134_empress_template = .vidioc_g_input = empress_g_input, .vidioc_s_input = empress_s_input, - .vidioc_queryctrl = saa7134_queryctrl, + .vidioc_queryctrl = empress_queryctrl, + .vidioc_querymenu = empress_querymenu, .vidioc_g_ctrl = saa7134_g_ctrl, .vidioc_s_ctrl = saa7134_s_ctrl, diff --git a/drivers/media/video/saa7134/saa7134-i2c.c b/drivers/media/video/saa7134/saa7134-i2c.c index d8af3863f2d3..5f713e637683 100644 --- a/drivers/media/video/saa7134/saa7134-i2c.c +++ b/drivers/media/video/saa7134/saa7134-i2c.c @@ -327,6 +327,8 @@ static int attach_inform(struct i2c_client *client) d1printk( "%s i2c attach [addr=0x%x,client=%s]\n", client->driver->driver.name, client->addr, client->name); + if (client->addr == 0x20 && client->driver && client->driver->command) + dev->mpeg_i2c_client = client; /* Am I an i2c remote control? */ diff --git a/drivers/media/video/saa7134/saa7134-input.c b/drivers/media/video/saa7134/saa7134-input.c index 76e6501d238d..ad08d13dffdd 100644 --- a/drivers/media/video/saa7134/saa7134-input.c +++ b/drivers/media/video/saa7134/saa7134-input.c @@ -198,6 +198,84 @@ static int get_key_beholdm6xx(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw) return 1; } +/* Common (grey or coloured) pinnacle PCTV remote handling + * + */ +static int get_key_pinnacle(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw, + int parity_offset, int marker, int code_modulo) +{ + unsigned char b[4]; + unsigned int start = 0,parity = 0,code = 0; + + /* poll IR chip */ + if (4 != i2c_master_recv(&ir->c, b, 4)) { + i2cdprintk("read error\n"); + return -EIO; + } + + for (start = 0; start < ARRAY_SIZE(b); start++) { + if (b[start] == marker) { + code=b[(start+parity_offset + 1) % 4]; + parity=b[(start+parity_offset) % 4]; + } + } + + /* Empty Request */ + if (parity == 0) + return 0; + + /* Repeating... */ + if (ir->old == parity) + return 0; + + ir->old = parity; + + /* drop special codes when a key is held down a long time for the grey controller + In this case, the second bit of the code is asserted */ + if (marker == 0xfe && (code & 0x40)) + return 0; + + code %= code_modulo; + + *ir_raw = code; + *ir_key = code; + + i2cdprintk("Pinnacle PCTV key %02x\n", code); + + return 1; +} + +/* The grey pinnacle PCTV remote + * + * There are one issue with this remote: + * - I2c packet does not change when the same key is pressed quickly. The workaround + * is to hold down each key for about half a second, so that another code is generated + * in the i2c packet, and the function can distinguish key presses. + * + * Sylvain Pasche <sylvain.pasche@gmail.com> + */ +static int get_key_pinnacle_grey(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw) +{ + + return get_key_pinnacle(ir, ir_key, ir_raw, 1, 0xfe, 0xff); +} + + +/* The new pinnacle PCTV remote (with the colored buttons) + * + * Ricardo Cerqueira <v4l@cerqueira.org> + */ +static int get_key_pinnacle_color(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw) +{ + /* code_modulo parameter (0x88) is used to reduce code value to fit inside IR_KEYTAB_SIZE + * + * this is the only value that results in 42 unique + * codes < 128 + */ + + return get_key_pinnacle(ir, ir_key, ir_raw, 2, 0x80, 0x88); +} + void saa7134_input_irq(struct saa7134_dev *dev) { struct card_ir *ir = dev->remote; @@ -409,6 +487,7 @@ int saa7134_input_init1(struct saa7134_dev *dev) break; case SAA7134_BOARD_ASUSTeK_P7131_DUAL: case SAA7134_BOARD_ASUSTeK_P7131_HYBRID_LNA: + case SAA7134_BOARD_ASUSTeK_P7131_ANALOG: ir_codes = ir_codes_asus_pc39; mask_keydown = 0x0040000; rc5_gpio = 1; @@ -540,6 +619,8 @@ void saa7134_set_i2c_ir(struct saa7134_dev *dev, struct IR_i2c *ir) break; case SAA7134_BOARD_BEHOLD_607_9FM: case SAA7134_BOARD_BEHOLD_M6: + case SAA7134_BOARD_BEHOLD_M63: + case SAA7134_BOARD_BEHOLD_M6_EXTRA: case SAA7134_BOARD_BEHOLD_H6: snprintf(ir->c.name, sizeof(ir->c.name), "BeholdTV"); ir->get_key = get_key_beholdm6xx; diff --git a/drivers/media/video/saa7134/saa7134-reg.h b/drivers/media/video/saa7134/saa7134-reg.h index 86f5eefdb0f6..cf89d96d7295 100644 --- a/drivers/media/video/saa7134/saa7134-reg.h +++ b/drivers/media/video/saa7134/saa7134-reg.h @@ -368,6 +368,7 @@ #define SAA7135_DSP_RWCLEAR 0x586 #define SAA7135_DSP_RWCLEAR_RERR 1 +#define SAA7133_I2S_AUDIO_CONTROL 0x591 /* ------------------------------------------------------------------ */ /* * Local variables: diff --git a/drivers/media/video/saa7134/saa7134-tvaudio.c b/drivers/media/video/saa7134/saa7134-tvaudio.c index 232af598d947..c5d0b44c179e 100644 --- a/drivers/media/video/saa7134/saa7134-tvaudio.c +++ b/drivers/media/video/saa7134/saa7134-tvaudio.c @@ -477,7 +477,6 @@ static int tvaudio_thread(void *data) unsigned int i, audio, nscan; int max1,max2,carrier,rx,mode,lastmode,default_carrier; - set_freezable(); for (;;) { @@ -775,7 +774,6 @@ static int tvaudio_thread_ddep(void *data) struct saa7134_dev *dev = data; u32 value, norms; - set_freezable(); for (;;) { tvaudio_sleep(dev,-1); @@ -873,13 +871,34 @@ void saa7134_enable_i2s(struct saa7134_dev *dev) if (!card_is_empress(dev)) return; - i2s_format = (dev->input->amux == TV) ? 0x00 : 0x01; - /* enable I2S audio output for the mpeg encoder */ - saa_writeb(SAA7134_I2S_OUTPUT_SELECT, 0x80); - saa_writeb(SAA7134_I2S_OUTPUT_FORMAT, i2s_format); - saa_writeb(SAA7134_I2S_OUTPUT_LEVEL, 0x0F); - saa_writeb(SAA7134_I2S_AUDIO_OUTPUT, 0x01); + if (dev->pci->device == PCI_DEVICE_ID_PHILIPS_SAA7130) + return; + + /* configure GPIO for out */ + saa_andorl(SAA7134_GPIO_GPMODE0 >> 2, 0x0E000000, 0x00000000); + + switch (dev->pci->device) { + case PCI_DEVICE_ID_PHILIPS_SAA7133: + case PCI_DEVICE_ID_PHILIPS_SAA7135: + /* Set I2S format (SONY) Â */ + saa_writeb(SAA7133_I2S_AUDIO_CONTROL, 0x00); + /* Start I2S */ + saa_writeb(SAA7134_I2S_AUDIO_OUTPUT, 0x11); + break; + + case PCI_DEVICE_ID_PHILIPS_SAA7134: + i2s_format = (dev->input->amux == TV) ? 0x00 : 0x01; + + /* enable I2S audio output for the mpeg encoder */ + saa_writeb(SAA7134_I2S_OUTPUT_SELECT, 0x80); + saa_writeb(SAA7134_I2S_OUTPUT_FORMAT, i2s_format); + saa_writeb(SAA7134_I2S_OUTPUT_LEVEL, 0x0F); + saa_writeb(SAA7134_I2S_AUDIO_OUTPUT, 0x01); + + default: + break; + } } int saa7134_tvaudio_rx2mode(u32 rx) diff --git a/drivers/media/video/saa7134/saa7134-video.c b/drivers/media/video/saa7134/saa7134-video.c index 48e1a01718ec..1a5137550e7a 100644 --- a/drivers/media/video/saa7134/saa7134-video.c +++ b/drivers/media/video/saa7134/saa7134-video.c @@ -1496,7 +1496,7 @@ static int video_mmap(struct file *file, struct vm_area_struct * vma) /* ------------------------------------------------------------------ */ -static int saa7134_try_get_set_fmt_vbi(struct file *file, void *priv, +static int saa7134_try_get_set_fmt_vbi_cap(struct file *file, void *priv, struct v4l2_format *f) { struct saa7134_fh *fh = priv; @@ -1516,7 +1516,7 @@ static int saa7134_try_get_set_fmt_vbi(struct file *file, void *priv, return 0; } -static int saa7134_g_fmt_cap(struct file *file, void *priv, +static int saa7134_g_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f) { struct saa7134_fh *fh = priv; @@ -1532,7 +1532,7 @@ static int saa7134_g_fmt_cap(struct file *file, void *priv, return 0; } -static int saa7134_g_fmt_overlay(struct file *file, void *priv, +static int saa7134_g_fmt_vid_overlay(struct file *file, void *priv, struct v4l2_format *f) { struct saa7134_fh *fh = priv; @@ -1546,7 +1546,7 @@ static int saa7134_g_fmt_overlay(struct file *file, void *priv, return 0; } -static int saa7134_try_fmt_cap(struct file *file, void *priv, +static int saa7134_try_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f) { struct saa7134_fh *fh = priv; @@ -1597,7 +1597,7 @@ static int saa7134_try_fmt_cap(struct file *file, void *priv, return 0; } -static int saa7134_try_fmt_overlay(struct file *file, void *priv, +static int saa7134_try_fmt_vid_overlay(struct file *file, void *priv, struct v4l2_format *f) { struct saa7134_fh *fh = priv; @@ -1611,13 +1611,13 @@ static int saa7134_try_fmt_overlay(struct file *file, void *priv, return verify_preview(dev, &f->fmt.win); } -static int saa7134_s_fmt_cap(struct file *file, void *priv, +static int saa7134_s_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f) { struct saa7134_fh *fh = priv; int err; - err = saa7134_try_fmt_cap(file, priv, f); + err = saa7134_try_fmt_vid_cap(file, priv, f); if (0 != err) return err; @@ -1628,7 +1628,7 @@ static int saa7134_s_fmt_cap(struct file *file, void *priv, return 0; } -static int saa7134_s_fmt_overlay(struct file *file, void *priv, +static int saa7134_s_fmt_vid_overlay(struct file *file, void *priv, struct v4l2_format *f) { struct saa7134_fh *fh = priv; @@ -2028,7 +2028,7 @@ static int saa7134_s_priority(struct file *file, void *f, return v4l2_prio_change(&dev->prio, &fh->prio, prio); } -static int saa7134_enum_fmt_cap(struct file *file, void *priv, +static int saa7134_enum_fmt_vid_cap(struct file *file, void *priv, struct v4l2_fmtdesc *f) { if (f->index >= FORMATS) @@ -2042,7 +2042,7 @@ static int saa7134_enum_fmt_cap(struct file *file, void *priv, return 0; } -static int saa7134_enum_fmt_overlay(struct file *file, void *priv, +static int saa7134_enum_fmt_vid_overlay(struct file *file, void *priv, struct v4l2_fmtdesc *f) { if (saa7134_no_overlay > 0) { @@ -2061,7 +2061,7 @@ static int saa7134_enum_fmt_overlay(struct file *file, void *priv, return 0; } -static int saa7134_enum_fmt_vbi(struct file *file, void *priv, +static int saa7134_enum_fmt_vbi_cap(struct file *file, void *priv, struct v4l2_fmtdesc *f) { if (0 != f->index) @@ -2208,6 +2208,32 @@ static int saa7134_g_parm(struct file *file, void *fh, return 0; } +#ifdef CONFIG_VIDEO_ADV_DEBUG +static int vidioc_g_register (struct file *file, void *priv, + struct v4l2_register *reg) +{ + struct saa7134_fh *fh = priv; + struct saa7134_dev *dev = fh->dev; + + if (!v4l2_chip_match_host(reg->match_type, reg->match_chip)) + return -EINVAL; + reg->val = saa_readb(reg->reg); + return 0; +} + +static int vidioc_s_register (struct file *file, void *priv, + struct v4l2_register *reg) +{ + struct saa7134_fh *fh = priv; + struct saa7134_dev *dev = fh->dev; + + if (!v4l2_chip_match_host(reg->match_type, reg->match_chip)) + return -EINVAL; + saa_writeb(reg->reg&0xffffff, reg->val); + return 0; +} +#endif + static int radio_querycap(struct file *file, void *priv, struct v4l2_capability *cap) { @@ -2348,18 +2374,18 @@ struct video_device saa7134_video_template = .fops = &video_fops, .minor = -1, .vidioc_querycap = saa7134_querycap, - .vidioc_enum_fmt_cap = saa7134_enum_fmt_cap, - .vidioc_g_fmt_cap = saa7134_g_fmt_cap, - .vidioc_try_fmt_cap = saa7134_try_fmt_cap, - .vidioc_s_fmt_cap = saa7134_s_fmt_cap, - .vidioc_enum_fmt_overlay = saa7134_enum_fmt_overlay, - .vidioc_g_fmt_overlay = saa7134_g_fmt_overlay, - .vidioc_try_fmt_overlay = saa7134_try_fmt_overlay, - .vidioc_s_fmt_overlay = saa7134_s_fmt_overlay, - .vidioc_enum_fmt_vbi = saa7134_enum_fmt_vbi, - .vidioc_g_fmt_vbi = saa7134_try_get_set_fmt_vbi, - .vidioc_try_fmt_vbi = saa7134_try_get_set_fmt_vbi, - .vidioc_s_fmt_vbi = saa7134_try_get_set_fmt_vbi, + .vidioc_enum_fmt_vid_cap = saa7134_enum_fmt_vid_cap, + .vidioc_g_fmt_vid_cap = saa7134_g_fmt_vid_cap, + .vidioc_try_fmt_vid_cap = saa7134_try_fmt_vid_cap, + .vidioc_s_fmt_vid_cap = saa7134_s_fmt_vid_cap, + .vidioc_enum_fmt_vid_overlay = saa7134_enum_fmt_vid_overlay, + .vidioc_g_fmt_vid_overlay = saa7134_g_fmt_vid_overlay, + .vidioc_try_fmt_vid_overlay = saa7134_try_fmt_vid_overlay, + .vidioc_s_fmt_vid_overlay = saa7134_s_fmt_vid_overlay, + .vidioc_enum_fmt_vbi_cap = saa7134_enum_fmt_vbi_cap, + .vidioc_g_fmt_vbi_cap = saa7134_try_get_set_fmt_vbi_cap, + .vidioc_try_fmt_vbi_cap = saa7134_try_get_set_fmt_vbi_cap, + .vidioc_s_fmt_vbi_cap = saa7134_try_get_set_fmt_vbi_cap, .vidioc_g_audio = saa7134_g_audio, .vidioc_s_audio = saa7134_s_audio, .vidioc_cropcap = saa7134_cropcap, @@ -2391,6 +2417,10 @@ struct video_device saa7134_video_template = .vidioc_g_parm = saa7134_g_parm, .vidioc_g_frequency = saa7134_g_frequency, .vidioc_s_frequency = saa7134_s_frequency, +#ifdef CONFIG_VIDEO_ADV_DEBUG + .vidioc_g_register = vidioc_g_register, + .vidioc_s_register = vidioc_s_register, +#endif .tvnorms = SAA7134_NORMS, .current_norm = V4L2_STD_PAL, }; @@ -2458,13 +2488,14 @@ int saa7134_videoport_init(struct saa7134_dev *dev) int vo = saa7134_boards[dev->board].video_out; int video_reg; unsigned int vid_port_opts = saa7134_boards[dev->board].vid_port_opts; + + /* Configure videoport */ saa_writeb(SAA7134_VIDEO_PORT_CTRL0, video_out[vo][0]); video_reg = video_out[vo][1]; if (vid_port_opts & SET_T_CODE_POLARITY_NON_INVERTED) video_reg &= ~VP_T_CODE_P_INVERTED; saa_writeb(SAA7134_VIDEO_PORT_CTRL1, video_reg); saa_writeb(SAA7134_VIDEO_PORT_CTRL2, video_out[vo][2]); - saa_writeb(SAA7134_VIDEO_PORT_CTRL3, video_out[vo][3]); saa_writeb(SAA7134_VIDEO_PORT_CTRL4, video_out[vo][4]); video_reg = video_out[vo][5]; if (vid_port_opts & SET_CLOCK_NOT_DELAYED) @@ -2481,6 +2512,9 @@ int saa7134_videoport_init(struct saa7134_dev *dev) saa_writeb(SAA7134_VIDEO_PORT_CTRL7, video_out[vo][7]); saa_writeb(SAA7134_VIDEO_PORT_CTRL8, video_out[vo][8]); + /* Start videoport */ + saa_writeb(SAA7134_VIDEO_PORT_CTRL3, video_out[vo][3]); + return 0; } diff --git a/drivers/media/video/saa7134/saa7134.h b/drivers/media/video/saa7134/saa7134.h index 34ff0d4998f3..6927cbea8624 100644 --- a/drivers/media/video/saa7134/saa7134.h +++ b/drivers/media/video/saa7134/saa7134.h @@ -264,7 +264,10 @@ struct saa7134_format { #define SAA7134_BOARD_AVERMEDIA_A700_PRO 140 #define SAA7134_BOARD_AVERMEDIA_A700_HYBRID 141 #define SAA7134_BOARD_BEHOLD_H6 142 - +#define SAA7134_BOARD_BEHOLD_M63 143 +#define SAA7134_BOARD_BEHOLD_M6_EXTRA 144 +#define SAA7134_BOARD_AVERMEDIA_M103 145 +#define SAA7134_BOARD_ASUSTeK_P7131_ANALOG 146 #define SAA7134_MAXBOARDS 8 #define SAA7134_INPUT_MAX 8 @@ -552,6 +555,7 @@ struct saa7134_dev { struct saa7134_ts ts; struct saa7134_dmaqueue ts_q; struct saa7134_mpeg_ops *mops; + struct i2c_client *mpeg_i2c_client; /* SAA7134_MPEG_EMPRESS only */ struct video_device *empress_dev; diff --git a/drivers/media/video/sh_mobile_ceu_camera.c b/drivers/media/video/sh_mobile_ceu_camera.c new file mode 100644 index 000000000000..012005e1a77b --- /dev/null +++ b/drivers/media/video/sh_mobile_ceu_camera.c @@ -0,0 +1,657 @@ +/* + * V4L2 Driver for SuperH Mobile CEU interface + * + * Copyright (C) 2008 Magnus Damm + * + * Based on V4L2 Driver for PXA camera host - "pxa_camera.c", + * + * Copyright (C) 2006, Sascha Hauer, Pengutronix + * Copyright (C) 2008, Guennadi Liakhovetski <kernel@pengutronix.de> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include <linux/init.h> +#include <linux/module.h> +#include <linux/io.h> +#include <linux/delay.h> +#include <linux/dma-mapping.h> +#include <linux/errno.h> +#include <linux/fs.h> +#include <linux/interrupt.h> +#include <linux/kernel.h> +#include <linux/mm.h> +#include <linux/moduleparam.h> +#include <linux/time.h> +#include <linux/version.h> +#include <linux/device.h> +#include <linux/platform_device.h> +#include <linux/mutex.h> +#include <linux/videodev2.h> + +#include <media/v4l2-common.h> +#include <media/v4l2-dev.h> +#include <media/soc_camera.h> +#include <media/sh_mobile_ceu.h> +#include <media/videobuf-dma-contig.h> + +/* register offsets for sh7722 / sh7723 */ + +#define CAPSR 0x00 +#define CAPCR 0x04 +#define CAMCR 0x08 +#define CMCYR 0x0c +#define CAMOR 0x10 +#define CAPWR 0x14 +#define CAIFR 0x18 +#define CSTCR 0x20 /* not on sh7723 */ +#define CSECR 0x24 /* not on sh7723 */ +#define CRCNTR 0x28 +#define CRCMPR 0x2c +#define CFLCR 0x30 +#define CFSZR 0x34 +#define CDWDR 0x38 +#define CDAYR 0x3c +#define CDACR 0x40 +#define CDBYR 0x44 +#define CDBCR 0x48 +#define CBDSR 0x4c +#define CFWCR 0x5c +#define CLFCR 0x60 +#define CDOCR 0x64 +#define CDDCR 0x68 +#define CDDAR 0x6c +#define CEIER 0x70 +#define CETCR 0x74 +#define CSTSR 0x7c +#define CSRTR 0x80 +#define CDSSR 0x84 +#define CDAYR2 0x90 +#define CDACR2 0x94 +#define CDBYR2 0x98 +#define CDBCR2 0x9c + +static DEFINE_MUTEX(camera_lock); + +/* per video frame buffer */ +struct sh_mobile_ceu_buffer { + struct videobuf_buffer vb; /* v4l buffer must be first */ + const struct soc_camera_data_format *fmt; +}; + +struct sh_mobile_ceu_dev { + struct device *dev; + struct soc_camera_host ici; + struct soc_camera_device *icd; + + unsigned int irq; + void __iomem *base; + unsigned long video_limit; + + spinlock_t lock; + struct list_head capture; + struct videobuf_buffer *active; + + struct sh_mobile_ceu_info *pdata; +}; + +static void ceu_write(struct sh_mobile_ceu_dev *priv, + unsigned long reg_offs, unsigned long data) +{ + iowrite32(data, priv->base + reg_offs); +} + +static unsigned long ceu_read(struct sh_mobile_ceu_dev *priv, + unsigned long reg_offs) +{ + return ioread32(priv->base + reg_offs); +} + +/* + * Videobuf operations + */ +static int sh_mobile_ceu_videobuf_setup(struct videobuf_queue *vq, + unsigned int *count, + unsigned int *size) +{ + struct soc_camera_device *icd = vq->priv_data; + struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); + struct sh_mobile_ceu_dev *pcdev = ici->priv; + int bytes_per_pixel = (icd->current_fmt->depth + 7) >> 3; + + *size = PAGE_ALIGN(icd->width * icd->height * bytes_per_pixel); + + if (0 == *count) + *count = 2; + + if (pcdev->video_limit) { + while (*size * *count > pcdev->video_limit) + (*count)--; + } + + dev_dbg(&icd->dev, "count=%d, size=%d\n", *count, *size); + + return 0; +} + +static void free_buffer(struct videobuf_queue *vq, + struct sh_mobile_ceu_buffer *buf) +{ + struct soc_camera_device *icd = vq->priv_data; + + dev_dbg(&icd->dev, "%s (vb=0x%p) 0x%08lx %zd\n", __func__, + &buf->vb, buf->vb.baddr, buf->vb.bsize); + + if (in_interrupt()) + BUG(); + + videobuf_dma_contig_free(vq, &buf->vb); + dev_dbg(&icd->dev, "%s freed\n", __func__); + buf->vb.state = VIDEOBUF_NEEDS_INIT; +} + +static void sh_mobile_ceu_capture(struct sh_mobile_ceu_dev *pcdev) +{ + ceu_write(pcdev, CEIER, ceu_read(pcdev, CEIER) & ~1); + ceu_write(pcdev, CETCR, ~ceu_read(pcdev, CETCR) & 0x0317f313); + ceu_write(pcdev, CEIER, ceu_read(pcdev, CEIER) | 1); + + ceu_write(pcdev, CAPCR, ceu_read(pcdev, CAPCR) & ~0x10000); + + ceu_write(pcdev, CETCR, 0x0317f313 ^ 0x10); + + if (pcdev->active) { + ceu_write(pcdev, CDAYR, videobuf_to_dma_contig(pcdev->active)); + ceu_write(pcdev, CAPSR, 0x1); /* start capture */ + } +} + +static int sh_mobile_ceu_videobuf_prepare(struct videobuf_queue *vq, + struct videobuf_buffer *vb, + enum v4l2_field field) +{ + struct soc_camera_device *icd = vq->priv_data; + struct sh_mobile_ceu_buffer *buf; + int ret; + + buf = container_of(vb, struct sh_mobile_ceu_buffer, vb); + + dev_dbg(&icd->dev, "%s (vb=0x%p) 0x%08lx %zd\n", __func__, + vb, vb->baddr, vb->bsize); + + /* Added list head initialization on alloc */ + WARN_ON(!list_empty(&vb->queue)); + +#ifdef DEBUG + /* This can be useful if you want to see if we actually fill + * the buffer with something */ + memset((void *)vb->baddr, 0xaa, vb->bsize); +#endif + + BUG_ON(NULL == icd->current_fmt); + + if (buf->fmt != icd->current_fmt || + vb->width != icd->width || + vb->height != icd->height || + vb->field != field) { + buf->fmt = icd->current_fmt; + vb->width = icd->width; + vb->height = icd->height; + vb->field = field; + vb->state = VIDEOBUF_NEEDS_INIT; + } + + vb->size = vb->width * vb->height * ((buf->fmt->depth + 7) >> 3); + if (0 != vb->baddr && vb->bsize < vb->size) { + ret = -EINVAL; + goto out; + } + + if (vb->state == VIDEOBUF_NEEDS_INIT) { + ret = videobuf_iolock(vq, vb, NULL); + if (ret) + goto fail; + vb->state = VIDEOBUF_PREPARED; + } + + return 0; +fail: + free_buffer(vq, buf); +out: + return ret; +} + +static void sh_mobile_ceu_videobuf_queue(struct videobuf_queue *vq, + struct videobuf_buffer *vb) +{ + struct soc_camera_device *icd = vq->priv_data; + struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); + struct sh_mobile_ceu_dev *pcdev = ici->priv; + unsigned long flags; + + dev_dbg(&icd->dev, "%s (vb=0x%p) 0x%08lx %zd\n", __func__, + vb, vb->baddr, vb->bsize); + + vb->state = VIDEOBUF_ACTIVE; + spin_lock_irqsave(&pcdev->lock, flags); + list_add_tail(&vb->queue, &pcdev->capture); + + if (!pcdev->active) { + pcdev->active = vb; + sh_mobile_ceu_capture(pcdev); + } + + spin_unlock_irqrestore(&pcdev->lock, flags); +} + +static void sh_mobile_ceu_videobuf_release(struct videobuf_queue *vq, + struct videobuf_buffer *vb) +{ + free_buffer(vq, container_of(vb, struct sh_mobile_ceu_buffer, vb)); +} + +static struct videobuf_queue_ops sh_mobile_ceu_videobuf_ops = { + .buf_setup = sh_mobile_ceu_videobuf_setup, + .buf_prepare = sh_mobile_ceu_videobuf_prepare, + .buf_queue = sh_mobile_ceu_videobuf_queue, + .buf_release = sh_mobile_ceu_videobuf_release, +}; + +static irqreturn_t sh_mobile_ceu_irq(int irq, void *data) +{ + struct sh_mobile_ceu_dev *pcdev = data; + struct videobuf_buffer *vb; + unsigned long flags; + + spin_lock_irqsave(&pcdev->lock, flags); + + vb = pcdev->active; + list_del_init(&vb->queue); + + if (!list_empty(&pcdev->capture)) + pcdev->active = list_entry(pcdev->capture.next, + struct videobuf_buffer, queue); + else + pcdev->active = NULL; + + sh_mobile_ceu_capture(pcdev); + + vb->state = VIDEOBUF_DONE; + do_gettimeofday(&vb->ts); + vb->field_count++; + wake_up(&vb->done); + spin_unlock_irqrestore(&pcdev->lock, flags); + + return IRQ_HANDLED; +} + +static int sh_mobile_ceu_add_device(struct soc_camera_device *icd) +{ + struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); + struct sh_mobile_ceu_dev *pcdev = ici->priv; + int ret = -EBUSY; + + mutex_lock(&camera_lock); + + if (pcdev->icd) + goto err; + + dev_info(&icd->dev, + "SuperH Mobile CEU driver attached to camera %d\n", + icd->devnum); + + if (pcdev->pdata->enable_camera) + pcdev->pdata->enable_camera(); + + ret = icd->ops->init(icd); + if (ret) + goto err; + + ceu_write(pcdev, CAPSR, 1 << 16); /* reset */ + while (ceu_read(pcdev, CSTSR) & 1) + msleep(1); + + pcdev->icd = icd; +err: + mutex_unlock(&camera_lock); + + return ret; +} + +static void sh_mobile_ceu_remove_device(struct soc_camera_device *icd) +{ + struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); + struct sh_mobile_ceu_dev *pcdev = ici->priv; + + BUG_ON(icd != pcdev->icd); + + /* disable capture, disable interrupts */ + ceu_write(pcdev, CEIER, 0); + ceu_write(pcdev, CAPSR, 1 << 16); /* reset */ + icd->ops->release(icd); + if (pcdev->pdata->disable_camera) + pcdev->pdata->disable_camera(); + + dev_info(&icd->dev, + "SuperH Mobile CEU driver detached from camera %d\n", + icd->devnum); + + pcdev->icd = NULL; +} + +static int sh_mobile_ceu_set_bus_param(struct soc_camera_device *icd, + __u32 pixfmt) +{ + struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); + struct sh_mobile_ceu_dev *pcdev = ici->priv; + int ret, buswidth, width, cfszr_width, cdwdr_width; + unsigned long camera_flags, common_flags, value; + + camera_flags = icd->ops->query_bus_param(icd); + common_flags = soc_camera_bus_param_compatible(camera_flags, + pcdev->pdata->flags); + if (!common_flags) + return -EINVAL; + + ret = icd->ops->set_bus_param(icd, common_flags); + if (ret < 0) + return ret; + + switch (common_flags & SOCAM_DATAWIDTH_MASK) { + case SOCAM_DATAWIDTH_8: + buswidth = 8; + break; + case SOCAM_DATAWIDTH_16: + buswidth = 16; + break; + default: + return -EINVAL; + } + + ceu_write(pcdev, CRCNTR, 0); + ceu_write(pcdev, CRCMPR, 0); + + value = 0x00000010; + value |= (common_flags & SOCAM_VSYNC_ACTIVE_LOW) ? (1 << 1) : 0; + value |= (common_flags & SOCAM_HSYNC_ACTIVE_LOW) ? (1 << 0) : 0; + value |= (buswidth == 16) ? (1 << 12) : 0; + ceu_write(pcdev, CAMCR, value); + + ceu_write(pcdev, CAPCR, 0x00300000); + ceu_write(pcdev, CAIFR, 0); + + mdelay(1); + + width = icd->width * (icd->current_fmt->depth / 8); + width = (buswidth == 16) ? width / 2 : width; + cfszr_width = (buswidth == 8) ? width / 2 : width; + cdwdr_width = (buswidth == 16) ? width * 2 : width; + + ceu_write(pcdev, CAMOR, 0); + ceu_write(pcdev, CAPWR, (icd->height << 16) | width); + ceu_write(pcdev, CFLCR, 0); /* data fetch mode - no scaling */ + ceu_write(pcdev, CFSZR, (icd->height << 16) | cfszr_width); + ceu_write(pcdev, CLFCR, 0); /* data fetch mode - no lowpass filter */ + ceu_write(pcdev, CDOCR, 0x00000016); + + ceu_write(pcdev, CDWDR, cdwdr_width); + ceu_write(pcdev, CFWCR, 0); /* keep "datafetch firewall" disabled */ + + /* not in bundle mode: skip CBDSR, CDAYR2, CDACR2, CDBYR2, CDBCR2 */ + /* in data fetch mode: no need for CDACR, CDBYR, CDBCR */ + + return 0; +} + +static int sh_mobile_ceu_try_bus_param(struct soc_camera_device *icd, + __u32 pixfmt) +{ + struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); + struct sh_mobile_ceu_dev *pcdev = ici->priv; + unsigned long camera_flags, common_flags; + + camera_flags = icd->ops->query_bus_param(icd); + common_flags = soc_camera_bus_param_compatible(camera_flags, + pcdev->pdata->flags); + if (!common_flags) + return -EINVAL; + + return 0; +} + +static int sh_mobile_ceu_set_fmt_cap(struct soc_camera_device *icd, + __u32 pixfmt, struct v4l2_rect *rect) +{ + return icd->ops->set_fmt_cap(icd, pixfmt, rect); +} + +static int sh_mobile_ceu_try_fmt_cap(struct soc_camera_device *icd, + struct v4l2_format *f) +{ + /* FIXME: calculate using depth and bus width */ + + if (f->fmt.pix.height < 4) + f->fmt.pix.height = 4; + if (f->fmt.pix.height > 1920) + f->fmt.pix.height = 1920; + if (f->fmt.pix.width < 2) + f->fmt.pix.width = 2; + if (f->fmt.pix.width > 2560) + f->fmt.pix.width = 2560; + f->fmt.pix.width &= ~0x01; + f->fmt.pix.height &= ~0x03; + + /* limit to sensor capabilities */ + return icd->ops->try_fmt_cap(icd, f); +} + +static int sh_mobile_ceu_reqbufs(struct soc_camera_file *icf, + struct v4l2_requestbuffers *p) +{ + int i; + + /* This is for locking debugging only. I removed spinlocks and now I + * check whether .prepare is ever called on a linked buffer, or whether + * a dma IRQ can occur for an in-work or unlinked buffer. Until now + * it hadn't triggered */ + for (i = 0; i < p->count; i++) { + struct sh_mobile_ceu_buffer *buf; + + buf = container_of(icf->vb_vidq.bufs[i], + struct sh_mobile_ceu_buffer, vb); + INIT_LIST_HEAD(&buf->vb.queue); + } + + return 0; +} + +static unsigned int sh_mobile_ceu_poll(struct file *file, poll_table *pt) +{ + struct soc_camera_file *icf = file->private_data; + struct sh_mobile_ceu_buffer *buf; + + buf = list_entry(icf->vb_vidq.stream.next, + struct sh_mobile_ceu_buffer, vb.stream); + + poll_wait(file, &buf->vb.done, pt); + + if (buf->vb.state == VIDEOBUF_DONE || + buf->vb.state == VIDEOBUF_ERROR) + return POLLIN|POLLRDNORM; + + return 0; +} + +static int sh_mobile_ceu_querycap(struct soc_camera_host *ici, + struct v4l2_capability *cap) +{ + strlcpy(cap->card, "SuperH_Mobile_CEU", sizeof(cap->card)); + cap->version = KERNEL_VERSION(0, 0, 5); + cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING; + return 0; +} + +static void sh_mobile_ceu_init_videobuf(struct videobuf_queue *q, + struct soc_camera_device *icd) +{ + struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); + struct sh_mobile_ceu_dev *pcdev = ici->priv; + + videobuf_queue_dma_contig_init(q, + &sh_mobile_ceu_videobuf_ops, + &ici->dev, &pcdev->lock, + V4L2_BUF_TYPE_VIDEO_CAPTURE, + V4L2_FIELD_NONE, + sizeof(struct sh_mobile_ceu_buffer), + icd); +} + +static struct soc_camera_host_ops sh_mobile_ceu_host_ops = { + .owner = THIS_MODULE, + .add = sh_mobile_ceu_add_device, + .remove = sh_mobile_ceu_remove_device, + .set_fmt_cap = sh_mobile_ceu_set_fmt_cap, + .try_fmt_cap = sh_mobile_ceu_try_fmt_cap, + .reqbufs = sh_mobile_ceu_reqbufs, + .poll = sh_mobile_ceu_poll, + .querycap = sh_mobile_ceu_querycap, + .try_bus_param = sh_mobile_ceu_try_bus_param, + .set_bus_param = sh_mobile_ceu_set_bus_param, + .init_videobuf = sh_mobile_ceu_init_videobuf, +}; + +static int sh_mobile_ceu_probe(struct platform_device *pdev) +{ + struct sh_mobile_ceu_dev *pcdev; + struct resource *res; + void __iomem *base; + unsigned int irq; + int err = 0; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + irq = platform_get_irq(pdev, 0); + if (!res || !irq) { + dev_err(&pdev->dev, "Not enough CEU platform resources.\n"); + err = -ENODEV; + goto exit; + } + + pcdev = kzalloc(sizeof(*pcdev), GFP_KERNEL); + if (!pcdev) { + dev_err(&pdev->dev, "Could not allocate pcdev\n"); + err = -ENOMEM; + goto exit; + } + + platform_set_drvdata(pdev, pcdev); + INIT_LIST_HEAD(&pcdev->capture); + spin_lock_init(&pcdev->lock); + + pcdev->pdata = pdev->dev.platform_data; + if (!pcdev->pdata) { + err = -EINVAL; + dev_err(&pdev->dev, "CEU platform data not set.\n"); + goto exit_kfree; + } + + base = ioremap_nocache(res->start, res->end - res->start + 1); + if (!base) { + err = -ENXIO; + dev_err(&pdev->dev, "Unable to ioremap CEU registers.\n"); + goto exit_kfree; + } + + pcdev->irq = irq; + pcdev->base = base; + pcdev->video_limit = 0; /* only enabled if second resource exists */ + pcdev->dev = &pdev->dev; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 1); + if (res) { + err = dma_declare_coherent_memory(&pdev->dev, res->start, + res->start, + (res->end - res->start) + 1, + DMA_MEMORY_MAP | + DMA_MEMORY_EXCLUSIVE); + if (!err) { + dev_err(&pdev->dev, "Unable to declare CEU memory.\n"); + err = -ENXIO; + goto exit_iounmap; + } + + pcdev->video_limit = (res->end - res->start) + 1; + } + + /* request irq */ + err = request_irq(pcdev->irq, sh_mobile_ceu_irq, IRQF_DISABLED, + pdev->dev.bus_id, pcdev); + if (err) { + dev_err(&pdev->dev, "Unable to register CEU interrupt.\n"); + goto exit_release_mem; + } + + pcdev->ici.priv = pcdev; + pcdev->ici.dev.parent = &pdev->dev; + pcdev->ici.nr = pdev->id; + pcdev->ici.drv_name = pdev->dev.bus_id, + pcdev->ici.ops = &sh_mobile_ceu_host_ops, + + err = soc_camera_host_register(&pcdev->ici); + if (err) + goto exit_free_irq; + + return 0; + +exit_free_irq: + free_irq(pcdev->irq, pcdev); +exit_release_mem: + if (platform_get_resource(pdev, IORESOURCE_MEM, 1)) + dma_release_declared_memory(&pdev->dev); +exit_iounmap: + iounmap(base); +exit_kfree: + kfree(pcdev); +exit: + return err; +} + +static int sh_mobile_ceu_remove(struct platform_device *pdev) +{ + struct sh_mobile_ceu_dev *pcdev = platform_get_drvdata(pdev); + + soc_camera_host_unregister(&pcdev->ici); + free_irq(pcdev->irq, pcdev); + if (platform_get_resource(pdev, IORESOURCE_MEM, 1)) + dma_release_declared_memory(&pdev->dev); + iounmap(pcdev->base); + kfree(pcdev); + return 0; +} + +static struct platform_driver sh_mobile_ceu_driver = { + .driver = { + .name = "sh_mobile_ceu", + }, + .probe = sh_mobile_ceu_probe, + .remove = sh_mobile_ceu_remove, +}; + +static int __init sh_mobile_ceu_init(void) +{ + return platform_driver_register(&sh_mobile_ceu_driver); +} + +static void __exit sh_mobile_ceu_exit(void) +{ + return platform_driver_unregister(&sh_mobile_ceu_driver); +} + +module_init(sh_mobile_ceu_init); +module_exit(sh_mobile_ceu_exit); + +MODULE_DESCRIPTION("SuperH Mobile CEU driver"); +MODULE_AUTHOR("Magnus Damm"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/video/sn9c102/sn9c102_devtable.h b/drivers/media/video/sn9c102/sn9c102_devtable.h index 35223e0d7e49..6ff489baacf3 100644 --- a/drivers/media/video/sn9c102/sn9c102_devtable.h +++ b/drivers/media/video/sn9c102/sn9c102_devtable.h @@ -44,7 +44,6 @@ static const struct usb_device_id sn9c102_id_table[] = { { SN9C102_USB_DEVICE(0x0c45, 0x6005, BRIDGE_SN9C102), }, { SN9C102_USB_DEVICE(0x0c45, 0x6007, BRIDGE_SN9C102), }, { SN9C102_USB_DEVICE(0x0c45, 0x6009, BRIDGE_SN9C102), }, - { SN9C102_USB_DEVICE(0x0c45, 0x6011, BRIDGE_SN9C102), }, { SN9C102_USB_DEVICE(0x0c45, 0x600d, BRIDGE_SN9C102), }, { SN9C102_USB_DEVICE(0x0c45, 0x6019, BRIDGE_SN9C102), }, { SN9C102_USB_DEVICE(0x0c45, 0x6024, BRIDGE_SN9C102), }, @@ -57,7 +56,6 @@ static const struct usb_device_id sn9c102_id_table[] = { { SN9C102_USB_DEVICE(0x0c45, 0x602d, BRIDGE_SN9C102), }, { SN9C102_USB_DEVICE(0x0c45, 0x602e, BRIDGE_SN9C102), }, { SN9C102_USB_DEVICE(0x0c45, 0x6030, BRIDGE_SN9C102), }, - { SN9C102_USB_DEVICE(0x0c45, 0x603f, BRIDGE_SN9C102), }, /* SN9C103 */ { SN9C102_USB_DEVICE(0x0c45, 0x6080, BRIDGE_SN9C103), }, { SN9C102_USB_DEVICE(0x0c45, 0x6082, BRIDGE_SN9C103), }, diff --git a/drivers/media/video/soc_camera.c b/drivers/media/video/soc_camera.c index d015bfe00950..e39b98f1eca4 100644 --- a/drivers/media/video/soc_camera.c +++ b/drivers/media/video/soc_camera.c @@ -26,6 +26,7 @@ #include <media/v4l2-common.h> #include <media/v4l2-dev.h> +#include <media/videobuf-core.h> #include <media/soc_camera.h> static LIST_HEAD(hosts); @@ -44,7 +45,7 @@ format_by_fourcc(struct soc_camera_device *icd, unsigned int fourcc) return NULL; } -static int soc_camera_try_fmt_cap(struct file *file, void *priv, +static int soc_camera_try_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f) { struct soc_camera_file *icf = file->private_data; @@ -182,7 +183,6 @@ static int soc_camera_open(struct inode *inode, struct file *file) struct soc_camera_device *icd; struct soc_camera_host *ici; struct soc_camera_file *icf; - spinlock_t *lock; int ret; icf = vmalloc(sizeof(*icf)); @@ -209,13 +209,6 @@ static int soc_camera_open(struct inode *inode, struct file *file) } icf->icd = icd; - - icf->lock = ici->ops->spinlock_alloc(icf); - if (!icf->lock) { - ret = -ENOMEM; - goto esla; - } - icd->use_count++; /* Now we really have to activate the camera */ @@ -233,21 +226,12 @@ static int soc_camera_open(struct inode *inode, struct file *file) file->private_data = icf; dev_dbg(&icd->dev, "camera device open\n"); - /* We must pass NULL as dev pointer, then all pci_* dma operations - * transform to normal dma_* ones. */ - videobuf_queue_sg_init(&icf->vb_vidq, ici->vbq_ops, NULL, icf->lock, - V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_FIELD_NONE, - ici->msize, icd); + ici->ops->init_videobuf(&icf->vb_vidq, icd); return 0; /* All errors are entered with the video_lock held */ eiciadd: - lock = icf->lock; - icf->lock = NULL; - if (ici->ops->spinlock_free) - ici->ops->spinlock_free(lock); -esla: module_put(ici->ops->owner); emgi: module_put(icd->ops->owner); @@ -263,15 +247,11 @@ static int soc_camera_close(struct inode *inode, struct file *file) struct soc_camera_device *icd = icf->icd; struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); struct video_device *vdev = icd->vdev; - spinlock_t *lock = icf->lock; mutex_lock(&video_lock); icd->use_count--; if (!icd->use_count) ici->ops->remove(icd); - icf->lock = NULL; - if (ici->ops->spinlock_free) - ici->ops->spinlock_free(lock); module_put(icd->ops->owner); module_put(ici->ops->owner); mutex_unlock(&video_lock); @@ -342,7 +322,7 @@ static struct file_operations soc_camera_fops = { }; -static int soc_camera_s_fmt_cap(struct file *file, void *priv, +static int soc_camera_s_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f) { struct soc_camera_file *icf = file->private_data; @@ -362,7 +342,7 @@ static int soc_camera_s_fmt_cap(struct file *file, void *priv, /* buswidth may be further adjusted by the ici */ icd->buswidth = data_fmt->depth; - ret = soc_camera_try_fmt_cap(file, icf, f); + ret = soc_camera_try_fmt_vid_cap(file, icf, f); if (ret < 0) return ret; @@ -389,7 +369,7 @@ static int soc_camera_s_fmt_cap(struct file *file, void *priv, return ici->ops->set_bus_param(icd, f->fmt.pix.pixelformat); } -static int soc_camera_enum_fmt_cap(struct file *file, void *priv, +static int soc_camera_enum_fmt_vid_cap(struct file *file, void *priv, struct v4l2_fmtdesc *f) { struct soc_camera_file *icf = file->private_data; @@ -408,7 +388,7 @@ static int soc_camera_enum_fmt_cap(struct file *file, void *priv, return 0; } -static int soc_camera_g_fmt_cap(struct file *file, void *priv, +static int soc_camera_g_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f) { struct soc_camera_file *icf = file->private_data; @@ -767,27 +747,12 @@ static void dummy_release(struct device *dev) { } -static spinlock_t *spinlock_alloc(struct soc_camera_file *icf) -{ - spinlock_t *lock = kmalloc(sizeof(spinlock_t), GFP_KERNEL); - - if (lock) - spin_lock_init(lock); - - return lock; -} - -static void spinlock_free(spinlock_t *lock) -{ - kfree(lock); -} - int soc_camera_host_register(struct soc_camera_host *ici) { int ret; struct soc_camera_host *ix; - if (!ici->vbq_ops || !ici->ops->add || !ici->ops->remove) + if (!ici->ops->init_videobuf || !ici->ops->add || !ici->ops->remove) return -EINVAL; /* Number might be equal to the platform device ID */ @@ -811,11 +776,6 @@ int soc_camera_host_register(struct soc_camera_host *ici) if (ret) goto edevr; - if (!ici->ops->spinlock_alloc) { - ici->ops->spinlock_alloc = spinlock_alloc; - ici->ops->spinlock_free = spinlock_free; - } - scan_add_host(ici); return 0; @@ -925,15 +885,15 @@ int soc_camera_video_start(struct soc_camera_device *icd) vdev->minor = -1; vdev->tvnorms = V4L2_STD_UNKNOWN, vdev->vidioc_querycap = soc_camera_querycap; - vdev->vidioc_g_fmt_cap = soc_camera_g_fmt_cap; - vdev->vidioc_enum_fmt_cap = soc_camera_enum_fmt_cap; - vdev->vidioc_s_fmt_cap = soc_camera_s_fmt_cap; + vdev->vidioc_g_fmt_vid_cap = soc_camera_g_fmt_vid_cap; + vdev->vidioc_enum_fmt_vid_cap = soc_camera_enum_fmt_vid_cap; + vdev->vidioc_s_fmt_vid_cap = soc_camera_s_fmt_vid_cap; vdev->vidioc_enum_input = soc_camera_enum_input; vdev->vidioc_g_input = soc_camera_g_input; vdev->vidioc_s_input = soc_camera_s_input; vdev->vidioc_s_std = soc_camera_s_std; vdev->vidioc_reqbufs = soc_camera_reqbufs; - vdev->vidioc_try_fmt_cap = soc_camera_try_fmt_cap; + vdev->vidioc_try_fmt_vid_cap = soc_camera_try_fmt_vid_cap; vdev->vidioc_querybuf = soc_camera_querybuf; vdev->vidioc_qbuf = soc_camera_qbuf; vdev->vidioc_dqbuf = soc_camera_dqbuf; diff --git a/drivers/media/video/soc_camera_platform.c b/drivers/media/video/soc_camera_platform.c new file mode 100644 index 000000000000..eefb0327ebb6 --- /dev/null +++ b/drivers/media/video/soc_camera_platform.c @@ -0,0 +1,198 @@ +/* + * Generic Platform Camera Driver + * + * Copyright (C) 2008 Magnus Damm + * Based on mt9m001 driver, + * Copyright (C) 2008, Guennadi Liakhovetski <kernel@pengutronix.de> + * + * 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 <linux/init.h> +#include <linux/module.h> +#include <linux/slab.h> +#include <linux/delay.h> +#include <linux/platform_device.h> +#include <linux/videodev2.h> +#include <media/v4l2-common.h> +#include <media/soc_camera.h> + +struct soc_camera_platform_info { + int iface; + char *format_name; + unsigned long format_depth; + struct v4l2_pix_format format; + unsigned long bus_param; + int (*set_capture)(struct soc_camera_platform_info *info, int enable); +}; + +struct soc_camera_platform_priv { + struct soc_camera_platform_info *info; + struct soc_camera_device icd; + struct soc_camera_data_format format; +}; + +static struct soc_camera_platform_info * +soc_camera_platform_get_info(struct soc_camera_device *icd) +{ + struct soc_camera_platform_priv *priv; + priv = container_of(icd, struct soc_camera_platform_priv, icd); + return priv->info; +} + +static int soc_camera_platform_init(struct soc_camera_device *icd) +{ + return 0; +} + +static int soc_camera_platform_release(struct soc_camera_device *icd) +{ + return 0; +} + +static int soc_camera_platform_start_capture(struct soc_camera_device *icd) +{ + struct soc_camera_platform_info *p = soc_camera_platform_get_info(icd); + return p->set_capture(p, 1); +} + +static int soc_camera_platform_stop_capture(struct soc_camera_device *icd) +{ + struct soc_camera_platform_info *p = soc_camera_platform_get_info(icd); + return p->set_capture(p, 0); +} + +static int soc_camera_platform_set_bus_param(struct soc_camera_device *icd, + unsigned long flags) +{ + return 0; +} + +static unsigned long +soc_camera_platform_query_bus_param(struct soc_camera_device *icd) +{ + struct soc_camera_platform_info *p = soc_camera_platform_get_info(icd); + return p->bus_param; +} + +static int soc_camera_platform_set_fmt_cap(struct soc_camera_device *icd, + __u32 pixfmt, struct v4l2_rect *rect) +{ + return 0; +} + +static int soc_camera_platform_try_fmt_cap(struct soc_camera_device *icd, + struct v4l2_format *f) +{ + struct soc_camera_platform_info *p = soc_camera_platform_get_info(icd); + + f->fmt.pix.width = p->format.width; + f->fmt.pix.height = p->format.height; + return 0; +} + +static int soc_camera_platform_video_probe(struct soc_camera_device *icd) +{ + struct soc_camera_platform_priv *priv; + priv = container_of(icd, struct soc_camera_platform_priv, icd); + + priv->format.name = priv->info->format_name; + priv->format.depth = priv->info->format_depth; + priv->format.fourcc = priv->info->format.pixelformat; + priv->format.colorspace = priv->info->format.colorspace; + + icd->formats = &priv->format; + icd->num_formats = 1; + + return soc_camera_video_start(icd); +} + +static void soc_camera_platform_video_remove(struct soc_camera_device *icd) +{ + soc_camera_video_stop(icd); +} + +static struct soc_camera_ops soc_camera_platform_ops = { + .owner = THIS_MODULE, + .probe = soc_camera_platform_video_probe, + .remove = soc_camera_platform_video_remove, + .init = soc_camera_platform_init, + .release = soc_camera_platform_release, + .start_capture = soc_camera_platform_start_capture, + .stop_capture = soc_camera_platform_stop_capture, + .set_fmt_cap = soc_camera_platform_set_fmt_cap, + .try_fmt_cap = soc_camera_platform_try_fmt_cap, + .set_bus_param = soc_camera_platform_set_bus_param, + .query_bus_param = soc_camera_platform_query_bus_param, +}; + +static int soc_camera_platform_probe(struct platform_device *pdev) +{ + struct soc_camera_platform_priv *priv; + struct soc_camera_platform_info *p; + struct soc_camera_device *icd; + int ret; + + p = pdev->dev.platform_data; + if (!p) + return -EINVAL; + + priv = kzalloc(sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->info = p; + platform_set_drvdata(pdev, priv); + + icd = &priv->icd; + icd->ops = &soc_camera_platform_ops; + icd->control = &pdev->dev; + icd->width_min = 0; + icd->width_max = priv->info->format.width; + icd->height_min = 0; + icd->height_max = priv->info->format.height; + icd->y_skip_top = 0; + icd->iface = priv->info->iface; + + ret = soc_camera_device_register(icd); + if (ret) + kfree(priv); + + return ret; +} + +static int soc_camera_platform_remove(struct platform_device *pdev) +{ + struct soc_camera_platform_priv *priv = platform_get_drvdata(pdev); + + soc_camera_device_unregister(&priv->icd); + kfree(priv); + return 0; +} + +static struct platform_driver soc_camera_platform_driver = { + .driver = { + .name = "soc_camera_platform", + }, + .probe = soc_camera_platform_probe, + .remove = soc_camera_platform_remove, +}; + +static int __init soc_camera_platform_module_init(void) +{ + return platform_driver_register(&soc_camera_platform_driver); +} + +static void __exit soc_camera_platform_module_exit(void) +{ + return platform_driver_unregister(&soc_camera_platform_driver); +} + +module_init(soc_camera_platform_module_init); +module_exit(soc_camera_platform_module_exit); + +MODULE_DESCRIPTION("SoC Camera Platform driver"); +MODULE_AUTHOR("Magnus Damm"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/video/stk-webcam.c b/drivers/media/video/stk-webcam.c index b12c60cf5a09..f308c38d744f 100644 --- a/drivers/media/video/stk-webcam.c +++ b/drivers/media/video/stk-webcam.c @@ -981,7 +981,7 @@ static int stk_vidioc_s_ctrl(struct file *filp, } -static int stk_vidioc_enum_fmt_cap(struct file *filp, +static int stk_vidioc_enum_fmt_vid_cap(struct file *filp, void *priv, struct v4l2_fmtdesc *fmtd) { fmtd->flags = 0; @@ -1025,7 +1025,7 @@ static struct stk_size { { .w = 176, .h = 144, .m = MODE_QCIF, }, }; -static int stk_vidioc_g_fmt_cap(struct file *filp, +static int stk_vidioc_g_fmt_vid_cap(struct file *filp, void *priv, struct v4l2_format *f) { struct v4l2_pix_format *pix_format = &f->fmt.pix; @@ -1054,7 +1054,7 @@ static int stk_vidioc_g_fmt_cap(struct file *filp, return 0; } -static int stk_vidioc_try_fmt_cap(struct file *filp, +static int stk_vidioc_try_fmt_vid_cap(struct file *filp, void *priv, struct v4l2_format *fmtd) { int i; @@ -1131,7 +1131,7 @@ static int stk_setup_format(struct stk_camera *dev) return stk_sensor_configure(dev); } -static int stk_vidioc_s_fmt_cap(struct file *filp, +static int stk_vidioc_s_fmt_vid_cap(struct file *filp, void *priv, struct v4l2_format *fmtd) { int ret; @@ -1145,7 +1145,7 @@ static int stk_vidioc_s_fmt_cap(struct file *filp, return -EBUSY; if (dev->owner && dev->owner != filp) return -EBUSY; - ret = stk_vidioc_try_fmt_cap(filp, priv, fmtd); + ret = stk_vidioc_try_fmt_vid_cap(filp, priv, fmtd); if (ret) return ret; dev->owner = filp; @@ -1342,10 +1342,10 @@ static struct video_device stk_v4l_data = { .release = stk_v4l_dev_release, .vidioc_querycap = stk_vidioc_querycap, - .vidioc_enum_fmt_cap = stk_vidioc_enum_fmt_cap, - .vidioc_try_fmt_cap = stk_vidioc_try_fmt_cap, - .vidioc_s_fmt_cap = stk_vidioc_s_fmt_cap, - .vidioc_g_fmt_cap = stk_vidioc_g_fmt_cap, + .vidioc_enum_fmt_vid_cap = stk_vidioc_enum_fmt_vid_cap, + .vidioc_try_fmt_vid_cap = stk_vidioc_try_fmt_vid_cap, + .vidioc_s_fmt_vid_cap = stk_vidioc_s_fmt_vid_cap, + .vidioc_g_fmt_vid_cap = stk_vidioc_g_fmt_vid_cap, .vidioc_enum_input = stk_vidioc_enum_input, .vidioc_s_input = stk_vidioc_s_input, .vidioc_g_input = stk_vidioc_g_input, diff --git a/drivers/media/video/tcm825x.c b/drivers/media/video/tcm825x.c index 8f0100f67a91..29991d1cf13e 100644 --- a/drivers/media/video/tcm825x.c +++ b/drivers/media/video/tcm825x.c @@ -523,6 +523,9 @@ static int ioctl_g_ctrl(struct v4l2_int_device *s, if (val < 0) return val; + if (vc->id == V4L2_CID_HFLIP || vc->id == V4L2_CID_VFLIP) + val ^= sensor->platform_data->is_upside_down(); + vc->value = val; return 0; } @@ -556,6 +559,9 @@ static int ioctl_s_ctrl(struct v4l2_int_device *s, if (lvc == NULL) return -EINVAL; + if (vc->id == V4L2_CID_HFLIP || vc->id == V4L2_CID_VFLIP) + val ^= sensor->platform_data->is_upside_down(); + val = val << lvc->start_bit; if (tcm825x_write_reg_mask(client, lvc->reg, val)) return -EIO; diff --git a/drivers/media/video/tcm825x.h b/drivers/media/video/tcm825x.h index 966765b66b3a..770ebacfa344 100644 --- a/drivers/media/video/tcm825x.h +++ b/drivers/media/video/tcm825x.h @@ -182,6 +182,7 @@ struct tcm825x_platform_data { int (*needs_reset)(struct v4l2_int_device *s, void *buf, struct v4l2_pix_format *fmt); int (*ifparm)(struct v4l2_ifparm *p); + int (*is_upside_down)(void); }; /* Array of image sizes supported by TCM825X. These must be ordered from diff --git a/drivers/media/video/tda7432.c b/drivers/media/video/tda7432.c index b4d10f7a4e57..ae75c187da79 100644 --- a/drivers/media/video/tda7432.c +++ b/drivers/media/video/tda7432.c @@ -72,6 +72,7 @@ static unsigned short normal_i2c[] = { I2C_ADDR_TDA7432 >> 1, I2C_CLIENT_END, }; + I2C_CLIENT_INSMOD; /* Structure of address and subaddresses for the tda7432 */ diff --git a/drivers/media/video/tda9840.c b/drivers/media/video/tda9840.c index 0cee00242782..2437c1a269c5 100644 --- a/drivers/media/video/tda9840.c +++ b/drivers/media/video/tda9840.c @@ -34,6 +34,7 @@ static int debug; /* insmod parameter */ module_param(debug, int, 0644); MODULE_PARM_DESC(debug, "Turn on/off device debugging (default:off)."); + #define dprintk(args...) \ do { if (debug) { printk("%s: %s()[%d]: ", KBUILD_MODNAME, __func__, __LINE__); printk(args); } } while (0) diff --git a/drivers/media/video/tda9875.c b/drivers/media/video/tda9875.c index 3c0557130a70..7a8ce8fb46dc 100644 --- a/drivers/media/video/tda9875.c +++ b/drivers/media/video/tda9875.c @@ -30,7 +30,6 @@ #include <linux/i2c.h> #include <linux/init.h> - #include <media/i2c-addr.h> static int debug; /* insmod parameter */ @@ -42,6 +41,7 @@ static unsigned short normal_i2c[] = { I2C_ADDR_TDA9875 >> 1, I2C_CLIENT_END }; + I2C_CLIENT_INSMOD; /* This is a superset of the TDA9875 */ diff --git a/drivers/media/video/tea6415c.c b/drivers/media/video/tea6415c.c index 9513d8611e87..421c1445e96c 100644 --- a/drivers/media/video/tea6415c.c +++ b/drivers/media/video/tea6415c.c @@ -36,6 +36,7 @@ static int debug; /* insmod parameter */ module_param(debug, int, 0644); MODULE_PARM_DESC(debug, "Turn on/off device debugging (default:off)."); + #define dprintk(args...) \ do { if (debug) { printk("%s: %s()[%d]: ", KBUILD_MODNAME, __func__, __LINE__); printk(args); } } while (0) diff --git a/drivers/media/video/tea6420.c b/drivers/media/video/tea6420.c index 7fd53367c07c..b5c8957d130e 100644 --- a/drivers/media/video/tea6420.c +++ b/drivers/media/video/tea6420.c @@ -36,6 +36,7 @@ static int debug; /* insmod parameter */ module_param(debug, int, 0644); MODULE_PARM_DESC(debug, "Turn on/off device debugging (default:off)."); + #define dprintk(args...) \ do { if (debug) { printk("%s: %s()[%d]: ", KBUILD_MODNAME, __func__, __LINE__); printk(args); } } while (0) diff --git a/drivers/media/video/tlv320aic23b.c b/drivers/media/video/tlv320aic23b.c index 28ab9f9d760a..9220378a5637 100644 --- a/drivers/media/video/tlv320aic23b.c +++ b/drivers/media/video/tlv320aic23b.c @@ -39,7 +39,6 @@ MODULE_LICENSE("GPL"); static unsigned short normal_i2c[] = { 0x34 >> 1, I2C_CLIENT_END }; - I2C_CLIENT_INSMOD; /* ----------------------------------------------------------------------- */ diff --git a/drivers/media/video/tuner-core.c b/drivers/media/video/tuner-core.c index 0d12ace61665..93d879dc510f 100644 --- a/drivers/media/video/tuner-core.c +++ b/drivers/media/video/tuner-core.c @@ -1298,7 +1298,6 @@ static struct v4l2_i2c_driver_data v4l2_i2c_data = { .id_table = tuner_id, }; - /* * Overrides for Emacs so that we follow Linus's tabbing style. * --------------------------------------------------------------------------- diff --git a/drivers/media/video/tvaudio.c b/drivers/media/video/tvaudio.c index c77914d99d15..463680b13289 100644 --- a/drivers/media/video/tvaudio.c +++ b/drivers/media/video/tvaudio.c @@ -69,7 +69,6 @@ typedef struct AUDIOCMD { /* chip description */ struct CHIPDESC { char *name; /* chip name */ - int id; /* ID */ int addr_lo, addr_hi; /* i2c address range */ int registers; /* # of registers */ @@ -1256,7 +1255,6 @@ module_param(ta8874z, int, 0444); static struct CHIPDESC chiplist[] = { { .name = "tda9840", - .id = I2C_DRIVERID_TDA9840, .insmodopt = &tda9840, .addr_lo = I2C_ADDR_TDA9840 >> 1, .addr_hi = I2C_ADDR_TDA9840 >> 1, @@ -1272,7 +1270,6 @@ static struct CHIPDESC chiplist[] = { }, { .name = "tda9873h", - .id = I2C_DRIVERID_TDA9873, .checkit = tda9873_checkit, .insmodopt = &tda9873, .addr_lo = I2C_ADDR_TDA985x_L >> 1, @@ -1293,7 +1290,6 @@ static struct CHIPDESC chiplist[] = { }, { .name = "tda9874h/a", - .id = I2C_DRIVERID_TDA9874, .checkit = tda9874a_checkit, .initialize = tda9874a_initialize, .insmodopt = &tda9874a, @@ -1306,7 +1302,6 @@ static struct CHIPDESC chiplist[] = { }, { .name = "tda9850", - .id = I2C_DRIVERID_TDA9850, .insmodopt = &tda9850, .addr_lo = I2C_ADDR_TDA985x_L >> 1, .addr_hi = I2C_ADDR_TDA985x_H >> 1, @@ -1319,7 +1314,6 @@ static struct CHIPDESC chiplist[] = { }, { .name = "tda9855", - .id = I2C_DRIVERID_TDA9855, .insmodopt = &tda9855, .addr_lo = I2C_ADDR_TDA985x_L >> 1, .addr_hi = I2C_ADDR_TDA985x_H >> 1, @@ -1344,7 +1338,6 @@ static struct CHIPDESC chiplist[] = { }, { .name = "tea6300", - .id = I2C_DRIVERID_TEA6300, .insmodopt = &tea6300, .addr_lo = I2C_ADDR_TEA6300 >> 1, .addr_hi = I2C_ADDR_TEA6300 >> 1, @@ -1365,7 +1358,6 @@ static struct CHIPDESC chiplist[] = { }, { .name = "tea6320", - .id = I2C_DRIVERID_TEA6300, .initialize = tea6320_initialize, .insmodopt = &tea6320, .addr_lo = I2C_ADDR_TEA6300 >> 1, @@ -1387,7 +1379,6 @@ static struct CHIPDESC chiplist[] = { }, { .name = "tea6420", - .id = I2C_DRIVERID_TEA6420, .insmodopt = &tea6420, .addr_lo = I2C_ADDR_TEA6420 >> 1, .addr_hi = I2C_ADDR_TEA6420 >> 1, @@ -1400,7 +1391,6 @@ static struct CHIPDESC chiplist[] = { }, { .name = "tda8425", - .id = I2C_DRIVERID_TDA8425, .insmodopt = &tda8425, .addr_lo = I2C_ADDR_TDA8425 >> 1, .addr_hi = I2C_ADDR_TDA8425 >> 1, @@ -1424,7 +1414,6 @@ static struct CHIPDESC chiplist[] = { }, { .name = "pic16c54 (PV951)", - .id = I2C_DRIVERID_PIC16C54_PV9, .insmodopt = &pic16c54, .addr_lo = I2C_ADDR_PIC16C54 >> 1, .addr_hi = I2C_ADDR_PIC16C54>> 1, @@ -1440,8 +1429,6 @@ static struct CHIPDESC chiplist[] = { }, { .name = "ta8874z", - .id = -1, - /*.id = I2C_DRIVERID_TA8874Z, */ .checkit = ta8874z_checkit, .insmodopt = &ta8874z, .addr_lo = I2C_ADDR_TDA9840 >> 1, diff --git a/drivers/media/video/usbvision/usbvision-core.c b/drivers/media/video/usbvision/usbvision-core.c index a9c5e5adba3a..abf685464b7c 100644 --- a/drivers/media/video/usbvision/usbvision-core.c +++ b/drivers/media/video/usbvision/usbvision-core.c @@ -169,7 +169,6 @@ static void usbvision_rvfree(void *mem, unsigned long size) } - #if ENABLE_HEXDUMP static void usbvision_hexdump(const unsigned char *data, int len) { @@ -2317,7 +2316,6 @@ static void usbvision_powerOffTimer(unsigned long data) del_timer(&usbvision->powerOffTimer); INIT_WORK(&usbvision->powerOffWork, call_usbvision_power_off); (void) schedule_work(&usbvision->powerOffWork); - } void usbvision_init_powerOffTimer(struct usb_usbvision *usbvision) @@ -2518,7 +2516,6 @@ int usbvision_init_isoc(struct usb_usbvision *usbvision) } } - /* Submit all URBs */ for (bufIdx = 0; bufIdx < USBVISION_NUMSBUF; bufIdx++) { errCode = usb_submit_urb(usbvision->sbuf[bufIdx].urb, @@ -2564,7 +2561,6 @@ void usbvision_stop_isoc(struct usb_usbvision *usbvision) usbvision->sbuf[bufIdx].urb = NULL; } - PDEBUG(DBG_ISOC, "%s: streaming=Stream_Off\n", __func__); usbvision->streaming = Stream_Off; diff --git a/drivers/media/video/usbvision/usbvision-i2c.c b/drivers/media/video/usbvision/usbvision-i2c.c index e2274d77ea29..a6d00858b07e 100644 --- a/drivers/media/video/usbvision/usbvision-i2c.c +++ b/drivers/media/video/usbvision/usbvision-i2c.c @@ -190,7 +190,6 @@ static u32 functionality(struct i2c_adapter *adap) return I2C_FUNC_SMBUS_EMUL | I2C_FUNC_10BIT_ADDR; } - /* -----exported algorithm data: ------------------------------------- */ static struct i2c_algorithm usbvision_algo = { @@ -514,11 +513,7 @@ static struct i2c_adapter i2c_adap_template = { .id = I2C_HW_B_BT848, /* FIXME */ .client_register = attach_inform, .client_unregister = detach_inform, -#ifdef I2C_ADAP_CLASS_TV_ANALOG - .class = I2C_ADAP_CLASS_TV_ANALOG, -#else .class = I2C_CLASS_TV_ANALOG, -#endif }; static struct i2c_client i2c_client_template = { diff --git a/drivers/media/video/usbvision/usbvision-video.c b/drivers/media/video/usbvision/usbvision-video.c index d97261ab430f..cd6c41d67899 100644 --- a/drivers/media/video/usbvision/usbvision-video.c +++ b/drivers/media/video/usbvision/usbvision-video.c @@ -179,7 +179,6 @@ MODULE_ALIAS(DRIVER_ALIAS); /* /sys/bus/usb/drivers/USBVision Video Grabber */ /*****************************************************************************/ - #define YES_NO(x) ((x) ? "Yes" : "No") static inline struct usb_usbvision *cd_to_usbvision(struct device *cd) @@ -370,7 +369,6 @@ static void usbvision_remove_sysfs(struct video_device *vdev) } } - /* * usbvision_open() * @@ -388,7 +386,6 @@ static int usbvision_v4l2_open(struct inode *inode, struct file *file) PDEBUG(DBG_IO, "open"); - usbvision_reset_powerOffTimer(usbvision); if (usbvision->user) @@ -442,9 +439,6 @@ static int usbvision_v4l2_open(struct inode *inode, struct file *file) mutex_unlock(&usbvision->lock); } - if (errCode) { - } - /* prepare queues */ usbvision_empty_framequeues(usbvision); @@ -495,8 +489,6 @@ static int usbvision_v4l2_close(struct inode *inode, struct file *file) } PDEBUG(DBG_IO, "success"); - - return 0; } @@ -998,7 +990,7 @@ static int vidioc_streamoff(struct file *file, return 0; } -static int vidioc_enum_fmt_cap (struct file *file, void *priv, +static int vidioc_enum_fmt_vid_cap (struct file *file, void *priv, struct v4l2_fmtdesc *vfd) { if(vfd->index>=USBVISION_SUPPORTED_PALETTES-1) { @@ -1012,7 +1004,7 @@ static int vidioc_enum_fmt_cap (struct file *file, void *priv, return 0; } -static int vidioc_g_fmt_cap (struct file *file, void *priv, +static int vidioc_g_fmt_vid_cap (struct file *file, void *priv, struct v4l2_format *vf) { struct video_device *dev = video_devdata(file); @@ -1030,7 +1022,7 @@ static int vidioc_g_fmt_cap (struct file *file, void *priv, return 0; } -static int vidioc_try_fmt_cap (struct file *file, void *priv, +static int vidioc_try_fmt_vid_cap (struct file *file, void *priv, struct v4l2_format *vf) { struct video_device *dev = video_devdata(file); @@ -1060,7 +1052,7 @@ static int vidioc_try_fmt_cap (struct file *file, void *priv, return 0; } -static int vidioc_s_fmt_cap(struct file *file, void *priv, +static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *vf) { struct video_device *dev = video_devdata(file); @@ -1068,7 +1060,7 @@ static int vidioc_s_fmt_cap(struct file *file, void *priv, (struct usb_usbvision *) video_get_drvdata(dev); int ret; - if( 0 != (ret=vidioc_try_fmt_cap (file, priv, vf)) ) { + if( 0 != (ret=vidioc_try_fmt_vid_cap (file, priv, vf)) ) { return ret; } @@ -1346,9 +1338,7 @@ static int usbvision_radio_close(struct inode *inode, struct file *file) usbvision_release(usbvision); } - PDEBUG(DBG_IO, "success"); - return errCode; } @@ -1360,7 +1350,6 @@ static int usbvision_vbi_open(struct inode *inode, struct file *file) { /* TODO */ return -ENODEV; - } static int usbvision_vbi_close(struct inode *inode, struct file *file) @@ -1407,10 +1396,10 @@ static struct video_device usbvision_video_template = { .release = video_device_release, .minor = -1, .vidioc_querycap = vidioc_querycap, - .vidioc_enum_fmt_cap = vidioc_enum_fmt_cap, - .vidioc_g_fmt_cap = vidioc_g_fmt_cap, - .vidioc_try_fmt_cap = vidioc_try_fmt_cap, - .vidioc_s_fmt_cap = vidioc_s_fmt_cap, + .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap, + .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap, + .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap, + .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap, .vidioc_reqbufs = vidioc_reqbufs, .vidioc_querybuf = vidioc_querybuf, .vidioc_qbuf = vidioc_qbuf, @@ -1899,7 +1888,6 @@ static void __devexit usbvision_disconnect(struct usb_interface *intf) } PDEBUG(DBG_PROBE, "success"); - } static struct usb_driver usbvision_driver = { diff --git a/drivers/media/video/uvc/Kconfig b/drivers/media/video/uvc/Kconfig new file mode 100644 index 000000000000..c2d9760de832 --- /dev/null +++ b/drivers/media/video/uvc/Kconfig @@ -0,0 +1,17 @@ +config USB_VIDEO_CLASS + tristate "USB Video Class (UVC)" + ---help--- + Support for the USB Video Class (UVC). Currently only video + input devices, such as webcams, are supported. + + For more information see: <http://linux-uvc.berlios.de/> + +config USB_VIDEO_CLASS_INPUT_EVDEV + bool "UVC input events device support" + default y + depends on USB_VIDEO_CLASS && INPUT + ---help--- + This option makes USB Video Class devices register an input device + to report button events. + + If you are in doubt, say Y. diff --git a/drivers/media/video/uvc/uvc_ctrl.c b/drivers/media/video/uvc/uvc_ctrl.c index f0ee46d15540..3ae95512666f 100644 --- a/drivers/media/video/uvc/uvc_ctrl.c +++ b/drivers/media/video/uvc/uvc_ctrl.c @@ -1254,3 +1254,4 @@ void uvc_ctrl_init(void) for (; mapping < mend; ++mapping) uvc_ctrl_add_mapping(mapping); } + diff --git a/drivers/media/video/uvc/uvc_driver.c b/drivers/media/video/uvc/uvc_driver.c index 60ced589f898..f2b2983fe062 100644 --- a/drivers/media/video/uvc/uvc_driver.c +++ b/drivers/media/video/uvc/uvc_driver.c @@ -298,7 +298,8 @@ static int uvc_parse_format(struct uvc_device *dev, switch (buffer[2]) { case VS_FORMAT_UNCOMPRESSED: case VS_FORMAT_FRAME_BASED: - if (buflen < 27) { + n = buffer[2] == VS_FORMAT_UNCOMPRESSED ? 27 : 28; + if (buflen < n) { uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming" "interface %d FORMAT error\n", dev->udev->devnum, @@ -1632,13 +1633,16 @@ static void uvc_disconnect(struct usb_interface *intf) * reference to the uvc_device instance after uvc_v4l2_open() received * the pointer to the device (video_devdata) but before it got the * chance to increase the reference count (kref_get). + * + * Note that the reference can't be released with the lock held, + * otherwise a AB-BA deadlock can occur with videodev_lock that + * videodev acquires in videodev_open() and video_unregister_device(). */ mutex_lock(&uvc_driver.open_mutex); - dev->state |= UVC_DEV_DISCONNECTED; - kref_put(&dev->kref, uvc_delete); - mutex_unlock(&uvc_driver.open_mutex); + + kref_put(&dev->kref, uvc_delete); } static int uvc_suspend(struct usb_interface *intf, pm_message_t message) @@ -1825,6 +1829,15 @@ static struct usb_device_id uvc_ids[] = { .bInterfaceSubClass = 1, .bInterfaceProtocol = 0, .driver_info = UVC_QUIRK_STREAM_NO_FID }, + /* Asus F9SG */ + { .match_flags = USB_DEVICE_ID_MATCH_DEVICE + | USB_DEVICE_ID_MATCH_INT_INFO, + .idVendor = 0x174f, + .idProduct = 0x8a31, + .bInterfaceClass = USB_CLASS_VIDEO, + .bInterfaceSubClass = 1, + .bInterfaceProtocol = 0, + .driver_info = UVC_QUIRK_STREAM_NO_FID }, /* Syntek (Asus U3S) */ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_INT_INFO, @@ -1891,6 +1904,15 @@ static struct usb_device_id uvc_ids[] = { .bInterfaceSubClass = 1, .bInterfaceProtocol = 0, .driver_info = UVC_QUIRK_PROBE_MINMAX }, + /* Medion Akoya Mini E1210 */ + { .match_flags = USB_DEVICE_ID_MATCH_DEVICE + | USB_DEVICE_ID_MATCH_INT_INFO, + .idVendor = 0x5986, + .idProduct = 0x0141, + .bInterfaceClass = USB_CLASS_VIDEO, + .bInterfaceSubClass = 1, + .bInterfaceProtocol = 0, + .driver_info = UVC_QUIRK_PROBE_MINMAX }, /* Acer OrbiCam - Unknown vendor */ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_INT_INFO, @@ -1953,3 +1975,4 @@ MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); MODULE_VERSION(DRIVER_VERSION); + diff --git a/drivers/media/video/uvc/uvc_queue.c b/drivers/media/video/uvc/uvc_queue.c index 0923f0e3b3d4..7388d0cee3d4 100644 --- a/drivers/media/video/uvc/uvc_queue.c +++ b/drivers/media/video/uvc/uvc_queue.c @@ -475,3 +475,4 @@ struct uvc_buffer *uvc_queue_next_buffer(struct uvc_video_queue *queue, wake_up(&buf->wait); return nextbuf; } + diff --git a/drivers/media/video/uvc/uvc_status.c b/drivers/media/video/uvc/uvc_status.c index be9084e5eace..75e678ac54eb 100644 --- a/drivers/media/video/uvc/uvc_status.c +++ b/drivers/media/video/uvc/uvc_status.c @@ -22,6 +22,7 @@ /* -------------------------------------------------------------------------- * Input device */ +#ifdef CONFIG_USB_VIDEO_CLASS_INPUT_EVDEV static int uvc_input_init(struct uvc_device *dev) { struct usb_device *udev = dev->udev; @@ -67,6 +68,19 @@ static void uvc_input_cleanup(struct uvc_device *dev) input_unregister_device(dev->input); } +static void uvc_input_report_key(struct uvc_device *dev, unsigned int code, + int value) +{ + if (dev->input) + input_report_key(dev->input, code, value); +} + +#else +#define uvc_input_init(dev) +#define uvc_input_cleanup(dev) +#define uvc_input_report_key(dev, code, value) +#endif /* CONFIG_USB_VIDEO_CLASS_INPUT_EVDEV */ + /* -------------------------------------------------------------------------- * Status interrupt endpoint */ @@ -83,8 +97,7 @@ static void uvc_event_streaming(struct uvc_device *dev, __u8 *data, int len) return; uvc_trace(UVC_TRACE_STATUS, "Button (intf %u) %s len %d\n", data[1], data[3] ? "pressed" : "released", len); - if (dev->input) - input_report_key(dev->input, BTN_0, data[3]); + uvc_input_report_key(dev, BTN_0, data[3]); } else { uvc_trace(UVC_TRACE_STATUS, "Stream %u error event %02x %02x " "len %d.\n", data[1], data[2], data[3], len); @@ -203,5 +216,6 @@ int uvc_status_resume(struct uvc_device *dev) if (dev->int_urb == NULL) return 0; - return usb_submit_urb(dev->int_urb, GFP_KERNEL); + return usb_submit_urb(dev->int_urb, GFP_NOIO); } + diff --git a/drivers/media/video/uvc/uvc_v4l2.c b/drivers/media/video/uvc/uvc_v4l2.c index 2e0a66575bb4..b5a11eb8f9fa 100644 --- a/drivers/media/video/uvc/uvc_v4l2.c +++ b/drivers/media/video/uvc/uvc_v4l2.c @@ -1032,7 +1032,7 @@ static int uvc_v4l2_mmap(struct file *file, struct vm_area_struct *vma) { struct video_device *vdev = video_devdata(file); struct uvc_video_device *video = video_get_drvdata(vdev); - struct uvc_buffer *buffer; + struct uvc_buffer *uninitialized_var(buffer); struct page *page; unsigned long addr, start, size; unsigned int i; @@ -1103,3 +1103,4 @@ struct file_operations uvc_fops = { .mmap = uvc_v4l2_mmap, .poll = uvc_v4l2_poll, }; + diff --git a/drivers/media/video/uvc/uvc_video.c b/drivers/media/video/uvc/uvc_video.c index 6faf1fb21614..ad63794fda77 100644 --- a/drivers/media/video/uvc/uvc_video.c +++ b/drivers/media/video/uvc/uvc_video.c @@ -554,9 +554,56 @@ static void uvc_video_complete(struct urb *urb) } /* + * Free transfer buffers. + */ +static void uvc_free_urb_buffers(struct uvc_video_device *video) +{ + unsigned int i; + + for (i = 0; i < UVC_URBS; ++i) { + if (video->urb_buffer[i]) { + usb_buffer_free(video->dev->udev, video->urb_size, + video->urb_buffer[i], video->urb_dma[i]); + video->urb_buffer[i] = NULL; + } + } + + video->urb_size = 0; +} + +/* + * Allocate transfer buffers. This function can be called with buffers + * already allocated when resuming from suspend, in which case it will + * return without touching the buffers. + * + * Return 0 on success or -ENOMEM when out of memory. + */ +static int uvc_alloc_urb_buffers(struct uvc_video_device *video, + unsigned int size) +{ + unsigned int i; + + /* Buffers are already allocated, bail out. */ + if (video->urb_size) + return 0; + + for (i = 0; i < UVC_URBS; ++i) { + video->urb_buffer[i] = usb_buffer_alloc(video->dev->udev, + size, GFP_KERNEL, &video->urb_dma[i]); + if (video->urb_buffer[i] == NULL) { + uvc_free_urb_buffers(video); + return -ENOMEM; + } + } + + video->urb_size = size; + return 0; +} + +/* * Uninitialize isochronous/bulk URBs and free transfer buffers. */ -static void uvc_uninit_video(struct uvc_video_device *video) +static void uvc_uninit_video(struct uvc_video_device *video, int free_buffers) { struct urb *urb; unsigned int i; @@ -566,19 +613,12 @@ static void uvc_uninit_video(struct uvc_video_device *video) continue; usb_kill_urb(urb); - /* urb->transfer_buffer_length is not touched by USB core, so - * we can use it here as the buffer length. - */ - if (video->urb_buffer[i]) { - usb_buffer_free(video->dev->udev, - urb->transfer_buffer_length, - video->urb_buffer[i], urb->transfer_dma); - video->urb_buffer[i] = NULL; - } - usb_free_urb(urb); video->urb[i] = NULL; } + + if (free_buffers) + uvc_free_urb_buffers(video); } /* @@ -586,7 +626,7 @@ static void uvc_uninit_video(struct uvc_video_device *video) * is given by the endpoint. */ static int uvc_init_video_isoc(struct uvc_video_device *video, - struct usb_host_endpoint *ep) + struct usb_host_endpoint *ep, gfp_t gfp_flags) { struct urb *urb; unsigned int npackets, i, j; @@ -610,18 +650,13 @@ static int uvc_init_video_isoc(struct uvc_video_device *video, size = npackets * psize; + if (uvc_alloc_urb_buffers(video, size) < 0) + return -ENOMEM; + for (i = 0; i < UVC_URBS; ++i) { - urb = usb_alloc_urb(npackets, GFP_KERNEL); + urb = usb_alloc_urb(npackets, gfp_flags); if (urb == NULL) { - uvc_uninit_video(video); - return -ENOMEM; - } - - video->urb_buffer[i] = usb_buffer_alloc(video->dev->udev, - size, GFP_KERNEL, &urb->transfer_dma); - if (video->urb_buffer[i] == NULL) { - usb_free_urb(urb); - uvc_uninit_video(video); + uvc_uninit_video(video, 1); return -ENOMEM; } @@ -632,6 +667,7 @@ static int uvc_init_video_isoc(struct uvc_video_device *video, urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP; urb->interval = ep->desc.bInterval; urb->transfer_buffer = video->urb_buffer[i]; + urb->transfer_dma = video->urb_dma[i]; urb->complete = uvc_video_complete; urb->number_of_packets = npackets; urb->transfer_buffer_length = size; @@ -652,7 +688,7 @@ static int uvc_init_video_isoc(struct uvc_video_device *video, * given by the endpoint. */ static int uvc_init_video_bulk(struct uvc_video_device *video, - struct usb_host_endpoint *ep) + struct usb_host_endpoint *ep, gfp_t gfp_flags) { struct urb *urb; unsigned int pipe, i; @@ -671,20 +707,15 @@ static int uvc_init_video_bulk(struct uvc_video_device *video, if (size > psize * UVC_MAX_ISO_PACKETS) size = psize * UVC_MAX_ISO_PACKETS; + if (uvc_alloc_urb_buffers(video, size) < 0) + return -ENOMEM; + pipe = usb_rcvbulkpipe(video->dev->udev, ep->desc.bEndpointAddress); for (i = 0; i < UVC_URBS; ++i) { - urb = usb_alloc_urb(0, GFP_KERNEL); + urb = usb_alloc_urb(0, gfp_flags); if (urb == NULL) { - uvc_uninit_video(video); - return -ENOMEM; - } - - video->urb_buffer[i] = usb_buffer_alloc(video->dev->udev, - size, GFP_KERNEL, &urb->transfer_dma); - if (video->urb_buffer[i] == NULL) { - usb_free_urb(urb); - uvc_uninit_video(video); + uvc_uninit_video(video, 1); return -ENOMEM; } @@ -692,6 +723,7 @@ static int uvc_init_video_bulk(struct uvc_video_device *video, video->urb_buffer[i], size, uvc_video_complete, video); urb->transfer_flags = URB_NO_TRANSFER_DMA_MAP; + urb->transfer_dma = video->urb_dma[i]; video->urb[i] = urb; } @@ -702,7 +734,7 @@ static int uvc_init_video_bulk(struct uvc_video_device *video, /* * Initialize isochronous/bulk URBs and allocate transfer buffers. */ -static int uvc_init_video(struct uvc_video_device *video) +static int uvc_init_video(struct uvc_video_device *video, gfp_t gfp_flags) { struct usb_interface *intf = video->streaming->intf; struct usb_host_interface *alts; @@ -747,7 +779,7 @@ static int uvc_init_video(struct uvc_video_device *video) if ((ret = usb_set_interface(video->dev->udev, intfnum, i)) < 0) return ret; - ret = uvc_init_video_isoc(video, ep); + ret = uvc_init_video_isoc(video, ep, gfp_flags); } else { /* Bulk endpoint, proceed to URB initialization. */ ep = uvc_find_endpoint(&intf->altsetting[0], @@ -755,7 +787,7 @@ static int uvc_init_video(struct uvc_video_device *video) if (ep == NULL) return -EIO; - ret = uvc_init_video_bulk(video, ep); + ret = uvc_init_video_bulk(video, ep, gfp_flags); } if (ret < 0) @@ -763,10 +795,10 @@ static int uvc_init_video(struct uvc_video_device *video) /* Submit the URBs. */ for (i = 0; i < UVC_URBS; ++i) { - if ((ret = usb_submit_urb(video->urb[i], GFP_KERNEL)) < 0) { + if ((ret = usb_submit_urb(video->urb[i], gfp_flags)) < 0) { uvc_printk(KERN_ERR, "Failed to submit URB %u " "(%d).\n", i, ret); - uvc_uninit_video(video); + uvc_uninit_video(video, 1); return ret; } } @@ -791,7 +823,7 @@ int uvc_video_suspend(struct uvc_video_device *video) return 0; video->frozen = 1; - uvc_uninit_video(video); + uvc_uninit_video(video, 0); usb_set_interface(video->dev->udev, video->streaming->intfnum, 0); return 0; } @@ -818,7 +850,7 @@ int uvc_video_resume(struct uvc_video_device *video) if (!uvc_queue_streaming(&video->queue)) return 0; - if ((ret = uvc_init_video(video)) < 0) + if ((ret = uvc_init_video(video, GFP_NOIO)) < 0) uvc_queue_enable(&video->queue, 0); return ret; @@ -920,7 +952,7 @@ int uvc_video_enable(struct uvc_video_device *video, int enable) int ret; if (!enable) { - uvc_uninit_video(video); + uvc_uninit_video(video, 1); usb_set_interface(video->dev->udev, video->streaming->intfnum, 0); uvc_queue_enable(&video->queue, 0); @@ -930,5 +962,6 @@ int uvc_video_enable(struct uvc_video_device *video, int enable) if ((ret = uvc_queue_enable(&video->queue, 1)) < 0) return ret; - return uvc_init_video(video); + return uvc_init_video(video, GFP_KERNEL); } + diff --git a/drivers/media/video/uvc/uvcvideo.h b/drivers/media/video/uvc/uvcvideo.h index a995a780db1c..bafe3406e305 100644 --- a/drivers/media/video/uvc/uvcvideo.h +++ b/drivers/media/video/uvc/uvcvideo.h @@ -602,6 +602,8 @@ struct uvc_video_device { struct urb *urb[UVC_URBS]; char *urb_buffer[UVC_URBS]; + dma_addr_t urb_dma[UVC_URBS]; + unsigned int urb_size; __u8 last_fid; }; @@ -794,3 +796,4 @@ void uvc_video_decode_isight(struct urb *urb, struct uvc_video_device *video, #endif /* __KERNEL__ */ #endif + diff --git a/drivers/media/video/videobuf-dma-contig.c b/drivers/media/video/videobuf-dma-contig.c new file mode 100644 index 000000000000..03f20acb668c --- /dev/null +++ b/drivers/media/video/videobuf-dma-contig.c @@ -0,0 +1,418 @@ +/* + * helper functions for physically contiguous capture buffers + * + * The functions support hardware lacking scatter gather support + * (i.e. the buffers must be linear in physical memory) + * + * Copyright (c) 2008 Magnus Damm + * + * Based on videobuf-vmalloc.c, + * (c) 2007 Mauro Carvalho Chehab, <mchehab@infradead.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 + */ + +#include <linux/init.h> +#include <linux/module.h> +#include <linux/mm.h> +#include <linux/dma-mapping.h> +#include <media/videobuf-dma-contig.h> + +struct videobuf_dma_contig_memory { + u32 magic; + void *vaddr; + dma_addr_t dma_handle; + unsigned long size; +}; + +#define MAGIC_DC_MEM 0x0733ac61 +#define MAGIC_CHECK(is, should) \ + if (unlikely((is) != (should))) { \ + pr_err("magic mismatch: %x expected %x\n", is, should); \ + BUG(); \ + } + +static void +videobuf_vm_open(struct vm_area_struct *vma) +{ + struct videobuf_mapping *map = vma->vm_private_data; + + dev_dbg(map->q->dev, "vm_open %p [count=%u,vma=%08lx-%08lx]\n", + map, map->count, vma->vm_start, vma->vm_end); + + map->count++; +} + +static void videobuf_vm_close(struct vm_area_struct *vma) +{ + struct videobuf_mapping *map = vma->vm_private_data; + struct videobuf_queue *q = map->q; + int i; + + dev_dbg(map->q->dev, "vm_close %p [count=%u,vma=%08lx-%08lx]\n", + map, map->count, vma->vm_start, vma->vm_end); + + map->count--; + if (0 == map->count) { + struct videobuf_dma_contig_memory *mem; + + dev_dbg(map->q->dev, "munmap %p q=%p\n", map, q); + mutex_lock(&q->vb_lock); + + /* We need first to cancel streams, before unmapping */ + if (q->streaming) + videobuf_queue_cancel(q); + + for (i = 0; i < VIDEO_MAX_FRAME; i++) { + if (NULL == q->bufs[i]) + continue; + + if (q->bufs[i]->map != map) + continue; + + mem = q->bufs[i]->priv; + if (mem) { + /* This callback is called only if kernel has + allocated memory and this memory is mmapped. + In this case, memory should be freed, + in order to do memory unmap. + */ + + MAGIC_CHECK(mem->magic, MAGIC_DC_MEM); + + /* vfree is not atomic - can't be + called with IRQ's disabled + */ + dev_dbg(map->q->dev, "buf[%d] freeing %p\n", + i, mem->vaddr); + + dma_free_coherent(q->dev, mem->size, + mem->vaddr, mem->dma_handle); + mem->vaddr = NULL; + } + + q->bufs[i]->map = NULL; + q->bufs[i]->baddr = 0; + } + + kfree(map); + + mutex_unlock(&q->vb_lock); + } +} + +static struct vm_operations_struct videobuf_vm_ops = { + .open = videobuf_vm_open, + .close = videobuf_vm_close, +}; + +static void *__videobuf_alloc(size_t size) +{ + struct videobuf_dma_contig_memory *mem; + struct videobuf_buffer *vb; + + vb = kzalloc(size + sizeof(*mem), GFP_KERNEL); + if (vb) { + mem = vb->priv = ((char *)vb) + size; + mem->magic = MAGIC_DC_MEM; + } + + return vb; +} + +static void *__videobuf_to_vmalloc(struct videobuf_buffer *buf) +{ + struct videobuf_dma_contig_memory *mem = buf->priv; + + BUG_ON(!mem); + MAGIC_CHECK(mem->magic, MAGIC_DC_MEM); + + return mem->vaddr; +} + +static int __videobuf_iolock(struct videobuf_queue *q, + struct videobuf_buffer *vb, + struct v4l2_framebuffer *fbuf) +{ + struct videobuf_dma_contig_memory *mem = vb->priv; + + BUG_ON(!mem); + MAGIC_CHECK(mem->magic, MAGIC_DC_MEM); + + switch (vb->memory) { + case V4L2_MEMORY_MMAP: + dev_dbg(q->dev, "%s memory method MMAP\n", __func__); + + /* All handling should be done by __videobuf_mmap_mapper() */ + if (!mem->vaddr) { + dev_err(q->dev, "memory is not alloced/mmapped.\n"); + return -EINVAL; + } + break; + case V4L2_MEMORY_USERPTR: + dev_dbg(q->dev, "%s memory method USERPTR\n", __func__); + + /* The only USERPTR currently supported is the one needed for + read() method. + */ + if (vb->baddr) + return -EINVAL; + + mem->size = PAGE_ALIGN(vb->size); + mem->vaddr = dma_alloc_coherent(q->dev, mem->size, + &mem->dma_handle, GFP_KERNEL); + if (!mem->vaddr) { + dev_err(q->dev, "dma_alloc_coherent %ld failed\n", + mem->size); + return -ENOMEM; + } + + dev_dbg(q->dev, "dma_alloc_coherent data is at %p (%ld)\n", + mem->vaddr, mem->size); + break; + case V4L2_MEMORY_OVERLAY: + default: + dev_dbg(q->dev, "%s memory method OVERLAY/unknown\n", + __func__); + return -EINVAL; + } + + return 0; +} + +static int __videobuf_sync(struct videobuf_queue *q, + struct videobuf_buffer *buf) +{ + struct videobuf_dma_contig_memory *mem = buf->priv; + + BUG_ON(!mem); + MAGIC_CHECK(mem->magic, MAGIC_DC_MEM); + + dma_sync_single_for_cpu(q->dev, mem->dma_handle, mem->size, + DMA_FROM_DEVICE); + return 0; +} + +static int __videobuf_mmap_free(struct videobuf_queue *q) +{ + unsigned int i; + + dev_dbg(q->dev, "%s\n", __func__); + for (i = 0; i < VIDEO_MAX_FRAME; i++) { + if (q->bufs[i] && q->bufs[i]->map) + return -EBUSY; + } + + return 0; +} + +static int __videobuf_mmap_mapper(struct videobuf_queue *q, + struct vm_area_struct *vma) +{ + struct videobuf_dma_contig_memory *mem; + struct videobuf_mapping *map; + unsigned int first; + int retval; + unsigned long size, offset = vma->vm_pgoff << PAGE_SHIFT; + + dev_dbg(q->dev, "%s\n", __func__); + if (!(vma->vm_flags & VM_WRITE) || !(vma->vm_flags & VM_SHARED)) + return -EINVAL; + + /* look for first buffer to map */ + for (first = 0; first < VIDEO_MAX_FRAME; first++) { + if (!q->bufs[first]) + continue; + + if (V4L2_MEMORY_MMAP != q->bufs[first]->memory) + continue; + if (q->bufs[first]->boff == offset) + break; + } + if (VIDEO_MAX_FRAME == first) { + dev_dbg(q->dev, "invalid user space offset [offset=0x%lx]\n", + offset); + return -EINVAL; + } + + /* create mapping + update buffer list */ + map = kzalloc(sizeof(struct videobuf_mapping), GFP_KERNEL); + if (!map) + return -ENOMEM; + + q->bufs[first]->map = map; + map->start = vma->vm_start; + map->end = vma->vm_end; + map->q = q; + + q->bufs[first]->baddr = vma->vm_start; + + mem = q->bufs[first]->priv; + BUG_ON(!mem); + MAGIC_CHECK(mem->magic, MAGIC_DC_MEM); + + mem->size = PAGE_ALIGN(q->bufs[first]->bsize); + mem->vaddr = dma_alloc_coherent(q->dev, mem->size, + &mem->dma_handle, GFP_KERNEL); + if (!mem->vaddr) { + dev_err(q->dev, "dma_alloc_coherent size %ld failed\n", + mem->size); + goto error; + } + dev_dbg(q->dev, "dma_alloc_coherent data is at addr %p (size %ld)\n", + mem->vaddr, mem->size); + + /* Try to remap memory */ + + size = vma->vm_end - vma->vm_start; + size = (size < mem->size) ? size : mem->size; + + vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); + retval = remap_pfn_range(vma, vma->vm_start, + mem->dma_handle >> PAGE_SHIFT, + size, vma->vm_page_prot); + if (retval) { + dev_err(q->dev, "mmap: remap failed with error %d. ", retval); + dma_free_coherent(q->dev, mem->size, + mem->vaddr, mem->dma_handle); + goto error; + } + + vma->vm_ops = &videobuf_vm_ops; + vma->vm_flags |= VM_DONTEXPAND; + vma->vm_private_data = map; + + dev_dbg(q->dev, "mmap %p: q=%p %08lx-%08lx (%lx) pgoff %08lx buf %d\n", + map, q, vma->vm_start, vma->vm_end, + (long int) q->bufs[first]->bsize, + vma->vm_pgoff, first); + + videobuf_vm_open(vma); + + return 0; + +error: + kfree(map); + return -ENOMEM; +} + +static int __videobuf_copy_to_user(struct videobuf_queue *q, + char __user *data, size_t count, + int nonblocking) +{ + struct videobuf_dma_contig_memory *mem = q->read_buf->priv; + void *vaddr; + + BUG_ON(!mem); + MAGIC_CHECK(mem->magic, MAGIC_DC_MEM); + BUG_ON(!mem->vaddr); + + /* copy to userspace */ + if (count > q->read_buf->size - q->read_off) + count = q->read_buf->size - q->read_off; + + vaddr = mem->vaddr; + + if (copy_to_user(data, vaddr + q->read_off, count)) + return -EFAULT; + + return count; +} + +static int __videobuf_copy_stream(struct videobuf_queue *q, + char __user *data, size_t count, size_t pos, + int vbihack, int nonblocking) +{ + unsigned int *fc; + struct videobuf_dma_contig_memory *mem = q->read_buf->priv; + + BUG_ON(!mem); + MAGIC_CHECK(mem->magic, MAGIC_DC_MEM); + + if (vbihack) { + /* dirty, undocumented hack -- pass the frame counter + * within the last four bytes of each vbi data block. + * We need that one to maintain backward compatibility + * to all vbi decoding software out there ... */ + fc = (unsigned int *)mem->vaddr; + fc += (q->read_buf->size >> 2) - 1; + *fc = q->read_buf->field_count >> 1; + dev_dbg(q->dev, "vbihack: %d\n", *fc); + } + + /* copy stuff using the common method */ + count = __videobuf_copy_to_user(q, data, count, nonblocking); + + if ((count == -EFAULT) && (pos == 0)) + return -EFAULT; + + return count; +} + +static struct videobuf_qtype_ops qops = { + .magic = MAGIC_QTYPE_OPS, + + .alloc = __videobuf_alloc, + .iolock = __videobuf_iolock, + .sync = __videobuf_sync, + .mmap_free = __videobuf_mmap_free, + .mmap_mapper = __videobuf_mmap_mapper, + .video_copy_to_user = __videobuf_copy_to_user, + .copy_stream = __videobuf_copy_stream, + .vmalloc = __videobuf_to_vmalloc, +}; + +void videobuf_queue_dma_contig_init(struct videobuf_queue *q, + struct videobuf_queue_ops *ops, + struct device *dev, + spinlock_t *irqlock, + enum v4l2_buf_type type, + enum v4l2_field field, + unsigned int msize, + void *priv) +{ + videobuf_queue_core_init(q, ops, dev, irqlock, type, field, msize, + priv, &qops); +} +EXPORT_SYMBOL_GPL(videobuf_queue_dma_contig_init); + +dma_addr_t videobuf_to_dma_contig(struct videobuf_buffer *buf) +{ + struct videobuf_dma_contig_memory *mem = buf->priv; + + BUG_ON(!mem); + MAGIC_CHECK(mem->magic, MAGIC_DC_MEM); + + return mem->dma_handle; +} +EXPORT_SYMBOL_GPL(videobuf_to_dma_contig); + +void videobuf_dma_contig_free(struct videobuf_queue *q, + struct videobuf_buffer *buf) +{ + struct videobuf_dma_contig_memory *mem = buf->priv; + + /* mmapped memory can't be freed here, otherwise mmapped region + would be released, while still needed. In this case, the memory + release should happen inside videobuf_vm_close(). + So, it should free memory only if the memory were allocated for + read() operation. + */ + if ((buf->memory != V4L2_MEMORY_USERPTR) || !buf->baddr) + return; + + if (!mem) + return; + + MAGIC_CHECK(mem->magic, MAGIC_DC_MEM); + + dma_free_coherent(q->dev, mem->size, mem->vaddr, mem->dma_handle); + mem->vaddr = NULL; +} +EXPORT_SYMBOL_GPL(videobuf_dma_contig_free); + +MODULE_DESCRIPTION("helper module to manage video4linux dma contig buffers"); +MODULE_AUTHOR("Magnus Damm"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/video/videobuf-dma-sg.c b/drivers/media/video/videobuf-dma-sg.c index 03a7b946bd54..bc6d5aba0fe6 100644 --- a/drivers/media/video/videobuf-dma-sg.c +++ b/drivers/media/video/videobuf-dma-sg.c @@ -1,7 +1,7 @@ /* * helper functions for SG DMA video4linux capture buffers * - * The functions expect the hardware being able to scatter gatter + * The functions expect the hardware being able to scatter gather * (i.e. the buffers are not linear in physical memory, but fragmented * into PAGE_SIZE chunks). They also assume the driver does not need * to touch the video data. @@ -80,17 +80,15 @@ struct scatterlist* videobuf_pages_to_sg(struct page **pages, int nr_pages, int offset) { struct scatterlist *sglist; - int i = 0; + int i; if (NULL == pages[0]) return NULL; - sglist = kcalloc(nr_pages, sizeof(*sglist), GFP_KERNEL); + sglist = kmalloc(nr_pages * sizeof(*sglist), GFP_KERNEL); if (NULL == sglist) return NULL; sg_init_table(sglist, nr_pages); - if (NULL == pages[0]) - goto nopage; if (PageHighMem(pages[0])) /* DMA to highmem pages might not work */ goto highmem; diff --git a/drivers/media/video/videobuf-dvb.c b/drivers/media/video/videobuf-dvb.c index 6e4d73ec6855..b56cffcbfd45 100644 --- a/drivers/media/video/videobuf-dvb.c +++ b/drivers/media/video/videobuf-dvb.c @@ -13,7 +13,6 @@ * (at your option) any later version. */ - #include <linux/module.h> #include <linux/init.h> #include <linux/device.h> @@ -257,4 +256,3 @@ EXPORT_SYMBOL(videobuf_dvb_unregister); * compile-command: "make DVB=1" * End: */ - diff --git a/drivers/media/video/videobuf-vmalloc.c b/drivers/media/video/videobuf-vmalloc.c index c91e1d8e3802..a868b7ed75ff 100644 --- a/drivers/media/video/videobuf-vmalloc.c +++ b/drivers/media/video/videobuf-vmalloc.c @@ -1,7 +1,7 @@ /* * helper functions for vmalloc video4linux capture buffers * - * The functions expect the hardware being able to scatter gatter + * The functions expect the hardware being able to scatter gather * (i.e. the buffers are not linear in physical memory, but fragmented * into PAGE_SIZE chunks). They also assume the driver does not need * to touch the video data. diff --git a/drivers/media/video/videodev.c b/drivers/media/video/videodev.c index 7649860a388d..6616e6570557 100644 --- a/drivers/media/video/videodev.c +++ b/drivers/media/video/videodev.c @@ -17,15 +17,19 @@ */ #define dbgarg(cmd, fmt, arg...) \ - if (vfd->debug & V4L2_DEBUG_IOCTL_ARG) { \ + do { \ + if (vfd->debug & V4L2_DEBUG_IOCTL_ARG) { \ printk(KERN_DEBUG "%s: ", vfd->name); \ v4l_printk_ioctl(cmd); \ printk(" " fmt, ## arg); \ - } + } \ + } while (0) #define dbgarg2(fmt, arg...) \ - if (vfd->debug & V4L2_DEBUG_IOCTL_ARG) \ - printk(KERN_DEBUG "%s: " fmt, vfd->name, ## arg); + do { \ + if (vfd->debug & V4L2_DEBUG_IOCTL_ARG) \ + printk(KERN_DEBUG "%s: " fmt, vfd->name, ## arg);\ + } while (0) #include <linux/module.h> #include <linux/types.h> @@ -138,7 +142,7 @@ EXPORT_SYMBOL(v4l2_video_std_construct); /* ----------------------------------------------------------------- */ /* some arrays for pretty-printing debug messages of enum types */ -char *v4l2_field_names[] = { +const char *v4l2_field_names[] = { [V4L2_FIELD_ANY] = "any", [V4L2_FIELD_NONE] = "none", [V4L2_FIELD_TOP] = "top", @@ -152,19 +156,19 @@ char *v4l2_field_names[] = { }; EXPORT_SYMBOL(v4l2_field_names); -char *v4l2_type_names[] = { - [V4L2_BUF_TYPE_VIDEO_CAPTURE] = "video-cap", - [V4L2_BUF_TYPE_VIDEO_OVERLAY] = "video-over", - [V4L2_BUF_TYPE_VIDEO_OUTPUT] = "video-out", +const char *v4l2_type_names[] = { + [V4L2_BUF_TYPE_VIDEO_CAPTURE] = "vid-cap", + [V4L2_BUF_TYPE_VIDEO_OVERLAY] = "vid-overlay", + [V4L2_BUF_TYPE_VIDEO_OUTPUT] = "vid-out", [V4L2_BUF_TYPE_VBI_CAPTURE] = "vbi-cap", [V4L2_BUF_TYPE_VBI_OUTPUT] = "vbi-out", [V4L2_BUF_TYPE_SLICED_VBI_CAPTURE] = "sliced-vbi-cap", [V4L2_BUF_TYPE_SLICED_VBI_OUTPUT] = "sliced-vbi-out", - [V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY] = "video-out-over", + [V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY] = "vid-out-overlay", }; EXPORT_SYMBOL(v4l2_type_names); -static char *v4l2_memory_names[] = { +static const char *v4l2_memory_names[] = { [V4L2_MEMORY_MMAP] = "mmap", [V4L2_MEMORY_USERPTR] = "userptr", [V4L2_MEMORY_OVERLAY] = "overlay", @@ -278,6 +282,7 @@ static const char *v4l2_ioctls[] = { [_IOC_NR(VIDIOC_DBG_G_REGISTER)] = "VIDIOC_DBG_G_REGISTER", [_IOC_NR(VIDIOC_G_CHIP_IDENT)] = "VIDIOC_G_CHIP_IDENT", + [_IOC_NR(VIDIOC_S_HW_FREQ_SEEK)] = "VIDIOC_S_HW_FREQ_SEEK", #endif }; #define V4L2_IOCTLS ARRAY_SIZE(v4l2_ioctls) @@ -371,6 +376,14 @@ EXPORT_SYMBOL(v4l_printk_ioctl); * sysfs stuff */ +static ssize_t show_index(struct device *cd, + struct device_attribute *attr, char *buf) +{ + struct video_device *vfd = container_of(cd, struct video_device, + class_dev); + return sprintf(buf, "%i\n", vfd->index); +} + static ssize_t show_name(struct device *cd, struct device_attribute *attr, char *buf) { @@ -379,6 +392,12 @@ static ssize_t show_name(struct device *cd, return sprintf(buf, "%.*s\n", (int)sizeof(vfd->name), vfd->name); } +static struct device_attribute video_device_attrs[] = { + __ATTR(name, S_IRUGO, show_name, NULL), + __ATTR(index, S_IRUGO, show_index, NULL), + __ATTR_NULL +}; + struct video_device *video_device_alloc(void) { struct video_device *vfd; @@ -407,11 +426,6 @@ static void video_release(struct device *cd) vfd->release(vfd); } -static struct device_attribute video_device_attrs[] = { - __ATTR(name, S_IRUGO, show_name, NULL), - __ATTR_NULL -}; - static struct class video_class = { .name = VIDEO_NAME, .dev_attrs = video_device_attrs, @@ -650,7 +664,7 @@ static void dbgbuf(unsigned int cmd, struct video_device *vfd, p->field, p->sequence, prt_names(p->memory, v4l2_memory_names), p->m.userptr, p->length); - dbgarg2 ("timecode= %02d:%02d:%02d type=%d, " + dbgarg2("timecode=%02d:%02d:%02d type=%d, " "flags=0x%08d, frames=%d, userbits=0x%08x\n", tc->hours,tc->minutes,tc->seconds, tc->type, tc->flags, tc->frames, *(__u32 *) tc->userbits); @@ -659,7 +673,7 @@ static void dbgbuf(unsigned int cmd, struct video_device *vfd, static inline void dbgrect(struct video_device *vfd, char *s, struct v4l2_rect *r) { - dbgarg2 ("%sRect start at %dx%d, size= %dx%d\n", s, r->left, r->top, + dbgarg2("%sRect start at %dx%d, size=%dx%d\n", s, r->left, r->top, r->width, r->height); }; @@ -677,40 +691,85 @@ static inline void v4l_print_pix_fmt (struct video_device *vfd, fmt->bytesperline, fmt->sizeimage, fmt->colorspace); }; +static inline void v4l_print_ext_ctrls(unsigned int cmd, + struct video_device *vfd, struct v4l2_ext_controls *c, int show_vals) +{ + __u32 i; + + if (!(vfd->debug & V4L2_DEBUG_IOCTL_ARG)) + return; + dbgarg(cmd, ""); + printk(KERN_CONT "class=0x%x", c->ctrl_class); + for (i = 0; i < c->count; i++) { + if (show_vals) + printk(KERN_CONT " id/val=0x%x/0x%x", + c->controls[i].id, c->controls[i].value); + else + printk(KERN_CONT " id=0x%x", c->controls[i].id); + } + printk(KERN_CONT "\n"); +}; + +static inline int check_ext_ctrls(struct v4l2_ext_controls *c, int allow_priv) +{ + __u32 i; + + /* zero the reserved fields */ + c->reserved[0] = c->reserved[1] = 0; + for (i = 0; i < c->count; i++) { + c->controls[i].reserved2[0] = 0; + c->controls[i].reserved2[1] = 0; + } + /* V4L2_CID_PRIVATE_BASE cannot be used as control class + when using extended controls. + Only when passed in through VIDIOC_G_CTRL and VIDIOC_S_CTRL + is it allowed for backwards compatibility. + */ + if (!allow_priv && c->ctrl_class == V4L2_CID_PRIVATE_BASE) + return 0; + /* Check that all controls are from the same control class. */ + for (i = 0; i < c->count; i++) { + if (V4L2_CTRL_ID2CLASS(c->controls[i].id) != c->ctrl_class) { + c->error_idx = i; + return 0; + } + } + return 1; +} static int check_fmt (struct video_device *vfd, enum v4l2_buf_type type) { switch (type) { case V4L2_BUF_TYPE_VIDEO_CAPTURE: - if (vfd->vidioc_try_fmt_cap) + if (vfd->vidioc_try_fmt_vid_cap) return (0); break; case V4L2_BUF_TYPE_VIDEO_OVERLAY: - if (vfd->vidioc_try_fmt_overlay) + if (vfd->vidioc_try_fmt_vid_overlay) return (0); break; - case V4L2_BUF_TYPE_VBI_CAPTURE: - if (vfd->vidioc_try_fmt_vbi) + case V4L2_BUF_TYPE_VIDEO_OUTPUT: + if (vfd->vidioc_try_fmt_vid_out) return (0); break; - case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT: - if (vfd->vidioc_try_fmt_vbi_output) + case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY: + if (vfd->vidioc_try_fmt_vid_out_overlay) return (0); break; - case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE: - if (vfd->vidioc_try_fmt_vbi_capture) + case V4L2_BUF_TYPE_VBI_CAPTURE: + if (vfd->vidioc_try_fmt_vbi_cap) return (0); break; - case V4L2_BUF_TYPE_VIDEO_OUTPUT: - if (vfd->vidioc_try_fmt_video_output) + case V4L2_BUF_TYPE_VBI_OUTPUT: + if (vfd->vidioc_try_fmt_vbi_out) return (0); break; - case V4L2_BUF_TYPE_VBI_OUTPUT: - if (vfd->vidioc_try_fmt_vbi_output) + case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE: + if (vfd->vidioc_try_fmt_sliced_vbi_cap) return (0); break; - case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY: - if (vfd->vidioc_try_fmt_output_overlay) + case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT: + if (vfd->vidioc_try_fmt_sliced_vbi_out) return (0); break; case V4L2_BUF_TYPE_PRIVATE: @@ -827,46 +886,37 @@ static int __video_do_ioctl(struct inode *inode, struct file *file, switch (type) { case V4L2_BUF_TYPE_VIDEO_CAPTURE: - if (vfd->vidioc_enum_fmt_cap) - ret=vfd->vidioc_enum_fmt_cap(file, fh, f); + if (vfd->vidioc_enum_fmt_vid_cap) + ret = vfd->vidioc_enum_fmt_vid_cap(file, fh, f); break; case V4L2_BUF_TYPE_VIDEO_OVERLAY: - if (vfd->vidioc_enum_fmt_overlay) - ret=vfd->vidioc_enum_fmt_overlay(file, fh, f); + if (vfd->vidioc_enum_fmt_vid_overlay) + ret = vfd->vidioc_enum_fmt_vid_overlay(file, + fh, f); break; +#if 1 + /* V4L2_BUF_TYPE_VBI_CAPTURE should not support VIDIOC_ENUM_FMT + * according to the spec. The bttv and saa7134 drivers support + * it though, so just warn that this is deprecated and will be + * removed in the near future. */ case V4L2_BUF_TYPE_VBI_CAPTURE: - if (vfd->vidioc_enum_fmt_vbi) - ret=vfd->vidioc_enum_fmt_vbi(file, fh, f); - break; - case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT: - if (vfd->vidioc_enum_fmt_vbi_output) - ret=vfd->vidioc_enum_fmt_vbi_output(file, - fh, f); - break; - case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE: - if (vfd->vidioc_enum_fmt_vbi_capture) - ret=vfd->vidioc_enum_fmt_vbi_capture(file, - fh, f); + if (vfd->vidioc_enum_fmt_vbi_cap) { + printk(KERN_WARNING "vidioc_enum_fmt_vbi_cap will be removed in 2.6.28!\n"); + ret = vfd->vidioc_enum_fmt_vbi_cap(file, fh, f); + } break; +#endif case V4L2_BUF_TYPE_VIDEO_OUTPUT: - if (vfd->vidioc_enum_fmt_video_output) - ret=vfd->vidioc_enum_fmt_video_output(file, - fh, f); - break; - case V4L2_BUF_TYPE_VBI_OUTPUT: - if (vfd->vidioc_enum_fmt_vbi_output) - ret=vfd->vidioc_enum_fmt_vbi_output(file, - fh, f); - break; - case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY: - if (vfd->vidioc_enum_fmt_output_overlay) - ret=vfd->vidioc_enum_fmt_output_overlay(file, fh, f); + if (vfd->vidioc_enum_fmt_vid_out) + ret = vfd->vidioc_enum_fmt_vid_out(file, fh, f); break; case V4L2_BUF_TYPE_PRIVATE: if (vfd->vidioc_enum_fmt_type_private) - ret=vfd->vidioc_enum_fmt_type_private(file, + ret = vfd->vidioc_enum_fmt_type_private(file, fh, f); break; + default: + break; } if (!ret) dbgarg (cmd, "index=%d, type=%d, flags=%d, " @@ -882,54 +932,56 @@ static int __video_do_ioctl(struct inode *inode, struct file *file, case VIDIOC_G_FMT: { struct v4l2_format *f = (struct v4l2_format *)arg; - enum v4l2_buf_type type=f->type; - memset(&f->fmt.pix,0,sizeof(f->fmt.pix)); - f->type=type; + memset(f->fmt.raw_data, 0, sizeof(f->fmt.raw_data)); /* FIXME: Should be one dump per type */ - dbgarg (cmd, "type=%s\n", prt_names(type, - v4l2_type_names)); + dbgarg(cmd, "type=%s\n", prt_names(f->type, v4l2_type_names)); - switch (type) { + switch (f->type) { case V4L2_BUF_TYPE_VIDEO_CAPTURE: - if (vfd->vidioc_g_fmt_cap) - ret=vfd->vidioc_g_fmt_cap(file, fh, f); + if (vfd->vidioc_g_fmt_vid_cap) + ret = vfd->vidioc_g_fmt_vid_cap(file, fh, f); if (!ret) - v4l_print_pix_fmt(vfd,&f->fmt.pix); + v4l_print_pix_fmt(vfd, &f->fmt.pix); break; case V4L2_BUF_TYPE_VIDEO_OVERLAY: - if (vfd->vidioc_g_fmt_overlay) - ret=vfd->vidioc_g_fmt_overlay(file, fh, f); - break; - case V4L2_BUF_TYPE_VBI_CAPTURE: - if (vfd->vidioc_g_fmt_vbi) - ret=vfd->vidioc_g_fmt_vbi(file, fh, f); - break; - case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT: - if (vfd->vidioc_g_fmt_vbi_output) - ret=vfd->vidioc_g_fmt_vbi_output(file, fh, f); - break; - case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE: - if (vfd->vidioc_g_fmt_vbi_capture) - ret=vfd->vidioc_g_fmt_vbi_capture(file, fh, f); + if (vfd->vidioc_g_fmt_vid_overlay) + ret = vfd->vidioc_g_fmt_vid_overlay(file, + fh, f); break; case V4L2_BUF_TYPE_VIDEO_OUTPUT: - if (vfd->vidioc_g_fmt_video_output) - ret=vfd->vidioc_g_fmt_video_output(file, - fh, f); + if (vfd->vidioc_g_fmt_vid_out) + ret = vfd->vidioc_g_fmt_vid_out(file, fh, f); + if (!ret) + v4l_print_pix_fmt(vfd, &f->fmt.pix); break; case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY: - if (vfd->vidioc_g_fmt_output_overlay) - ret=vfd->vidioc_g_fmt_output_overlay(file, fh, f); + if (vfd->vidioc_g_fmt_vid_out_overlay) + ret = vfd->vidioc_g_fmt_vid_out_overlay(file, + fh, f); + break; + case V4L2_BUF_TYPE_VBI_CAPTURE: + if (vfd->vidioc_g_fmt_vbi_cap) + ret = vfd->vidioc_g_fmt_vbi_cap(file, fh, f); break; case V4L2_BUF_TYPE_VBI_OUTPUT: - if (vfd->vidioc_g_fmt_vbi_output) - ret=vfd->vidioc_g_fmt_vbi_output(file, fh, f); + if (vfd->vidioc_g_fmt_vbi_out) + ret = vfd->vidioc_g_fmt_vbi_out(file, fh, f); + break; + case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE: + if (vfd->vidioc_g_fmt_sliced_vbi_cap) + ret = vfd->vidioc_g_fmt_sliced_vbi_cap(file, + fh, f); + break; + case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT: + if (vfd->vidioc_g_fmt_sliced_vbi_out) + ret = vfd->vidioc_g_fmt_sliced_vbi_out(file, + fh, f); break; case V4L2_BUF_TYPE_PRIVATE: if (vfd->vidioc_g_fmt_type_private) - ret=vfd->vidioc_g_fmt_type_private(file, + ret = vfd->vidioc_g_fmt_type_private(file, fh, f); break; } @@ -941,48 +993,50 @@ static int __video_do_ioctl(struct inode *inode, struct file *file, struct v4l2_format *f = (struct v4l2_format *)arg; /* FIXME: Should be one dump per type */ - dbgarg (cmd, "type=%s\n", prt_names(f->type, - v4l2_type_names)); + dbgarg(cmd, "type=%s\n", prt_names(f->type, v4l2_type_names)); switch (f->type) { case V4L2_BUF_TYPE_VIDEO_CAPTURE: - v4l_print_pix_fmt(vfd,&f->fmt.pix); - if (vfd->vidioc_s_fmt_cap) - ret=vfd->vidioc_s_fmt_cap(file, fh, f); + v4l_print_pix_fmt(vfd, &f->fmt.pix); + if (vfd->vidioc_s_fmt_vid_cap) + ret = vfd->vidioc_s_fmt_vid_cap(file, fh, f); break; case V4L2_BUF_TYPE_VIDEO_OVERLAY: - if (vfd->vidioc_s_fmt_overlay) - ret=vfd->vidioc_s_fmt_overlay(file, fh, f); - break; - case V4L2_BUF_TYPE_VBI_CAPTURE: - if (vfd->vidioc_s_fmt_vbi) - ret=vfd->vidioc_s_fmt_vbi(file, fh, f); - break; - case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT: - if (vfd->vidioc_s_fmt_vbi_output) - ret=vfd->vidioc_s_fmt_vbi_output(file, fh, f); - break; - case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE: - if (vfd->vidioc_s_fmt_vbi_capture) - ret=vfd->vidioc_s_fmt_vbi_capture(file, fh, f); + if (vfd->vidioc_s_fmt_vid_overlay) + ret = vfd->vidioc_s_fmt_vid_overlay(file, + fh, f); break; case V4L2_BUF_TYPE_VIDEO_OUTPUT: - if (vfd->vidioc_s_fmt_video_output) - ret=vfd->vidioc_s_fmt_video_output(file, - fh, f); + v4l_print_pix_fmt(vfd, &f->fmt.pix); + if (vfd->vidioc_s_fmt_vid_out) + ret = vfd->vidioc_s_fmt_vid_out(file, fh, f); break; case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY: - if (vfd->vidioc_s_fmt_output_overlay) - ret=vfd->vidioc_s_fmt_output_overlay(file, fh, f); + if (vfd->vidioc_s_fmt_vid_out_overlay) + ret = vfd->vidioc_s_fmt_vid_out_overlay(file, + fh, f); + break; + case V4L2_BUF_TYPE_VBI_CAPTURE: + if (vfd->vidioc_s_fmt_vbi_cap) + ret = vfd->vidioc_s_fmt_vbi_cap(file, fh, f); break; case V4L2_BUF_TYPE_VBI_OUTPUT: - if (vfd->vidioc_s_fmt_vbi_output) - ret=vfd->vidioc_s_fmt_vbi_output(file, - fh, f); + if (vfd->vidioc_s_fmt_vbi_out) + ret = vfd->vidioc_s_fmt_vbi_out(file, fh, f); + break; + case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE: + if (vfd->vidioc_s_fmt_sliced_vbi_cap) + ret = vfd->vidioc_s_fmt_sliced_vbi_cap(file, + fh, f); + break; + case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT: + if (vfd->vidioc_s_fmt_sliced_vbi_out) + ret = vfd->vidioc_s_fmt_sliced_vbi_out(file, + fh, f); break; case V4L2_BUF_TYPE_PRIVATE: if (vfd->vidioc_s_fmt_type_private) - ret=vfd->vidioc_s_fmt_type_private(file, + ret = vfd->vidioc_s_fmt_type_private(file, fh, f); break; } @@ -997,46 +1051,48 @@ static int __video_do_ioctl(struct inode *inode, struct file *file, v4l2_type_names)); switch (f->type) { case V4L2_BUF_TYPE_VIDEO_CAPTURE: - if (vfd->vidioc_try_fmt_cap) - ret=vfd->vidioc_try_fmt_cap(file, fh, f); + if (vfd->vidioc_try_fmt_vid_cap) + ret = vfd->vidioc_try_fmt_vid_cap(file, fh, f); if (!ret) - v4l_print_pix_fmt(vfd,&f->fmt.pix); + v4l_print_pix_fmt(vfd, &f->fmt.pix); break; case V4L2_BUF_TYPE_VIDEO_OVERLAY: - if (vfd->vidioc_try_fmt_overlay) - ret=vfd->vidioc_try_fmt_overlay(file, fh, f); + if (vfd->vidioc_try_fmt_vid_overlay) + ret = vfd->vidioc_try_fmt_vid_overlay(file, + fh, f); + break; + case V4L2_BUF_TYPE_VIDEO_OUTPUT: + if (vfd->vidioc_try_fmt_vid_out) + ret = vfd->vidioc_try_fmt_vid_out(file, fh, f); + if (!ret) + v4l_print_pix_fmt(vfd, &f->fmt.pix); + break; + case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY: + if (vfd->vidioc_try_fmt_vid_out_overlay) + ret = vfd->vidioc_try_fmt_vid_out_overlay(file, + fh, f); break; case V4L2_BUF_TYPE_VBI_CAPTURE: - if (vfd->vidioc_try_fmt_vbi) - ret=vfd->vidioc_try_fmt_vbi(file, fh, f); + if (vfd->vidioc_try_fmt_vbi_cap) + ret = vfd->vidioc_try_fmt_vbi_cap(file, fh, f); break; - case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT: - if (vfd->vidioc_try_fmt_vbi_output) - ret=vfd->vidioc_try_fmt_vbi_output(file, - fh, f); + case V4L2_BUF_TYPE_VBI_OUTPUT: + if (vfd->vidioc_try_fmt_vbi_out) + ret = vfd->vidioc_try_fmt_vbi_out(file, fh, f); break; case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE: - if (vfd->vidioc_try_fmt_vbi_capture) - ret=vfd->vidioc_try_fmt_vbi_capture(file, - fh, f); - break; - case V4L2_BUF_TYPE_VIDEO_OUTPUT: - if (vfd->vidioc_try_fmt_video_output) - ret=vfd->vidioc_try_fmt_video_output(file, + if (vfd->vidioc_try_fmt_sliced_vbi_cap) + ret = vfd->vidioc_try_fmt_sliced_vbi_cap(file, fh, f); break; - case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY: - if (vfd->vidioc_try_fmt_output_overlay) - ret=vfd->vidioc_try_fmt_output_overlay(file, fh, f); - break; - case V4L2_BUF_TYPE_VBI_OUTPUT: - if (vfd->vidioc_try_fmt_vbi_output) - ret=vfd->vidioc_try_fmt_vbi_output(file, + case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT: + if (vfd->vidioc_try_fmt_sliced_vbi_out) + ret = vfd->vidioc_try_fmt_sliced_vbi_out(file, fh, f); break; case V4L2_BUF_TYPE_PRIVATE: if (vfd->vidioc_try_fmt_type_private) - ret=vfd->vidioc_try_fmt_type_private(file, + ret = vfd->vidioc_try_fmt_type_private(file, fh, f); break; } @@ -1120,29 +1176,29 @@ static int __video_do_ioctl(struct inode *inode, struct file *file, } case VIDIOC_G_FBUF: { - struct v4l2_framebuffer *p=arg; + struct v4l2_framebuffer *p = arg; + if (!vfd->vidioc_g_fbuf) break; - ret=vfd->vidioc_g_fbuf(file, fh, arg); + ret = vfd->vidioc_g_fbuf(file, fh, arg); if (!ret) { - dbgarg (cmd, "capability=%d, flags=%d, base=0x%08lx\n", - p->capability,p->flags, + dbgarg(cmd, "capability=0x%x, flags=%d, base=0x%08lx\n", + p->capability, p->flags, (unsigned long)p->base); - v4l_print_pix_fmt (vfd, &p->fmt); + v4l_print_pix_fmt(vfd, &p->fmt); } break; } case VIDIOC_S_FBUF: { - struct v4l2_framebuffer *p=arg; + struct v4l2_framebuffer *p = arg; + if (!vfd->vidioc_s_fbuf) break; - - dbgarg (cmd, "capability=%d, flags=%d, base=0x%08lx\n", - p->capability,p->flags,(unsigned long)p->base); - v4l_print_pix_fmt (vfd, &p->fmt); - ret=vfd->vidioc_s_fbuf(file, fh, arg); - + dbgarg(cmd, "capability=0x%x, flags=%d, base=0x%08lx\n", + p->capability, p->flags, (unsigned long)p->base); + v4l_print_pix_fmt(vfd, &p->fmt); + ret = vfd->vidioc_s_fbuf(file, fh, arg); break; } case VIDIOC_STREAMON: @@ -1194,7 +1250,7 @@ static int __video_do_ioctl(struct inode *inode, struct file *file, v4l2_video_std_construct(p, curr_id, descr); p->index = index; - dbgarg(cmd, "index=%d, id=%Ld, name=%s, fps=%d/%d, " + dbgarg(cmd, "index=%d, id=0x%Lx, name=%s, fps=%d/%d, " "framelines=%d\n", p->index, (unsigned long long)p->id, p->name, p->frameperiod.numerator, @@ -1208,18 +1264,22 @@ static int __video_do_ioctl(struct inode *inode, struct file *file, { v4l2_std_id *id = arg; - *id = vfd->current_norm; - - dbgarg (cmd, "value=%08Lx\n", (long long unsigned) *id); + ret = 0; + /* Calls the specific handler */ + if (vfd->vidioc_g_std) + ret = vfd->vidioc_g_std(file, fh, id); + else + *id = vfd->current_norm; - ret=0; + if (!ret) + dbgarg(cmd, "std=0x%08Lx\n", (long long unsigned)*id); break; } case VIDIOC_S_STD: { v4l2_std_id *id = arg,norm; - dbgarg (cmd, "value=%08Lx\n", (long long unsigned) *id); + dbgarg(cmd, "std=%08Lx\n", (long long unsigned)*id); norm = (*id) & vfd->tvnorms; if ( vfd->tvnorms && !norm) /* Check if std is supported */ @@ -1295,6 +1355,25 @@ static int __video_do_ioctl(struct inode *inode, struct file *file, } /* ------ output switching ---------- */ + case VIDIOC_ENUMOUTPUT: + { + struct v4l2_output *p = arg; + int i = p->index; + + if (!vfd->vidioc_enum_output) + break; + memset(p, 0, sizeof(*p)); + p->index = i; + + ret = vfd->vidioc_enum_output(file, fh, p); + if (!ret) + dbgarg(cmd, "index=%d, name=%s, type=%d, " + "audioset=0x%x, " + "modulator=%d, std=0x%08Lx\n", + p->index, p->name, p->type, p->audioset, + p->modulator, (unsigned long long)p->std); + break; + } case VIDIOC_G_OUTPUT: { unsigned int *i = arg; @@ -1320,132 +1399,172 @@ static int __video_do_ioctl(struct inode *inode, struct file *file, /* --- controls ---------------------------------------------- */ case VIDIOC_QUERYCTRL: { - struct v4l2_queryctrl *p=arg; + struct v4l2_queryctrl *p = arg; if (!vfd->vidioc_queryctrl) break; - ret=vfd->vidioc_queryctrl(file, fh, p); - + ret = vfd->vidioc_queryctrl(file, fh, p); if (!ret) - dbgarg (cmd, "id=%d, type=%d, name=%s, " - "min/max=%d/%d," - " step=%d, default=%d, flags=0x%08x\n", - p->id,p->type,p->name,p->minimum, - p->maximum,p->step,p->default_value, - p->flags); + dbgarg(cmd, "id=0x%x, type=%d, name=%s, min/max=%d/%d, " + "step=%d, default=%d, flags=0x%08x\n", + p->id, p->type, p->name, + p->minimum, p->maximum, + p->step, p->default_value, p->flags); + else + dbgarg(cmd, "id=0x%x\n", p->id); break; } case VIDIOC_G_CTRL: { struct v4l2_control *p = arg; - if (!vfd->vidioc_g_ctrl) + if (vfd->vidioc_g_ctrl) + ret = vfd->vidioc_g_ctrl(file, fh, p); + else if (vfd->vidioc_g_ext_ctrls) { + struct v4l2_ext_controls ctrls; + struct v4l2_ext_control ctrl; + + ctrls.ctrl_class = V4L2_CTRL_ID2CLASS(p->id); + ctrls.count = 1; + ctrls.controls = &ctrl; + ctrl.id = p->id; + ctrl.value = p->value; + if (check_ext_ctrls(&ctrls, 1)) { + ret = vfd->vidioc_g_ext_ctrls(file, fh, &ctrls); + if (ret == 0) + p->value = ctrl.value; + } + } else break; - dbgarg(cmd, "Enum for index=%d\n", p->id); - - ret=vfd->vidioc_g_ctrl(file, fh, p); if (!ret) - dbgarg2 ( "id=%d, value=%d\n", p->id, p->value); + dbgarg(cmd, "id=0x%x, value=%d\n", p->id, p->value); + else + dbgarg(cmd, "id=0x%x\n", p->id); break; } case VIDIOC_S_CTRL: { struct v4l2_control *p = arg; + struct v4l2_ext_controls ctrls; + struct v4l2_ext_control ctrl; + + if (!vfd->vidioc_s_ctrl && !vfd->vidioc_s_ext_ctrls) + break; - if (!vfd->vidioc_s_ctrl) + dbgarg(cmd, "id=0x%x, value=%d\n", p->id, p->value); + + if (vfd->vidioc_s_ctrl) { + ret = vfd->vidioc_s_ctrl(file, fh, p); + break; + } + if (!vfd->vidioc_s_ext_ctrls) break; - dbgarg (cmd, "id=%d, value=%d\n", p->id, p->value); - ret=vfd->vidioc_s_ctrl(file, fh, p); + ctrls.ctrl_class = V4L2_CTRL_ID2CLASS(p->id); + ctrls.count = 1; + ctrls.controls = &ctrl; + ctrl.id = p->id; + ctrl.value = p->value; + if (check_ext_ctrls(&ctrls, 1)) + ret = vfd->vidioc_s_ext_ctrls(file, fh, &ctrls); break; } case VIDIOC_G_EXT_CTRLS: { struct v4l2_ext_controls *p = arg; - if (vfd->vidioc_g_ext_ctrls) { - dbgarg(cmd, "count=%d\n", p->count); - - ret=vfd->vidioc_g_ext_ctrls(file, fh, p); - } + p->error_idx = p->count; + if (!vfd->vidioc_g_ext_ctrls) + break; + if (check_ext_ctrls(p, 0)) + ret = vfd->vidioc_g_ext_ctrls(file, fh, p); + v4l_print_ext_ctrls(cmd, vfd, p, !ret); break; } case VIDIOC_S_EXT_CTRLS: { struct v4l2_ext_controls *p = arg; - if (vfd->vidioc_s_ext_ctrls) { - dbgarg(cmd, "count=%d\n", p->count); - - ret=vfd->vidioc_s_ext_ctrls(file, fh, p); - } + p->error_idx = p->count; + if (!vfd->vidioc_s_ext_ctrls) + break; + v4l_print_ext_ctrls(cmd, vfd, p, 1); + if (check_ext_ctrls(p, 0)) + ret = vfd->vidioc_s_ext_ctrls(file, fh, p); break; } case VIDIOC_TRY_EXT_CTRLS: { struct v4l2_ext_controls *p = arg; - if (vfd->vidioc_try_ext_ctrls) { - dbgarg(cmd, "count=%d\n", p->count); - - ret=vfd->vidioc_try_ext_ctrls(file, fh, p); - } + p->error_idx = p->count; + if (!vfd->vidioc_try_ext_ctrls) + break; + v4l_print_ext_ctrls(cmd, vfd, p, 1); + if (check_ext_ctrls(p, 0)) + ret = vfd->vidioc_try_ext_ctrls(file, fh, p); break; } case VIDIOC_QUERYMENU: { - struct v4l2_querymenu *p=arg; + struct v4l2_querymenu *p = arg; + if (!vfd->vidioc_querymenu) break; - ret=vfd->vidioc_querymenu(file, fh, p); + ret = vfd->vidioc_querymenu(file, fh, p); if (!ret) - dbgarg (cmd, "id=%d, index=%d, name=%s\n", - p->id,p->index,p->name); + dbgarg(cmd, "id=0x%x, index=%d, name=%s\n", + p->id, p->index, p->name); + else + dbgarg(cmd, "id=0x%x, index=%d\n", + p->id, p->index); break; } /* --- audio ---------------------------------------------- */ case VIDIOC_ENUMAUDIO: { - struct v4l2_audio *p=arg; + struct v4l2_audio *p = arg; if (!vfd->vidioc_enumaudio) break; - dbgarg(cmd, "Enum for index=%d\n", p->index); - ret=vfd->vidioc_enumaudio(file, fh, p); + ret = vfd->vidioc_enumaudio(file, fh, p); if (!ret) - dbgarg2("index=%d, name=%s, capability=%d, " - "mode=%d\n",p->index,p->name, + dbgarg(cmd, "index=%d, name=%s, capability=0x%x, " + "mode=0x%x\n", p->index, p->name, p->capability, p->mode); + else + dbgarg(cmd, "index=%d\n", p->index); break; } case VIDIOC_G_AUDIO: { - struct v4l2_audio *p=arg; - __u32 index=p->index; + struct v4l2_audio *p = arg; + __u32 index = p->index; if (!vfd->vidioc_g_audio) break; - memset(p,0,sizeof(*p)); - p->index=index; - dbgarg(cmd, "Get for index=%d\n", p->index); - ret=vfd->vidioc_g_audio(file, fh, p); + memset(p, 0, sizeof(*p)); + p->index = index; + ret = vfd->vidioc_g_audio(file, fh, p); if (!ret) - dbgarg2("index=%d, name=%s, capability=%d, " - "mode=%d\n",p->index, - p->name,p->capability, p->mode); + dbgarg(cmd, "index=%d, name=%s, capability=0x%x, " + "mode=0x%x\n", p->index, + p->name, p->capability, p->mode); + else + dbgarg(cmd, "index=%d\n", p->index); break; } case VIDIOC_S_AUDIO: { - struct v4l2_audio *p=arg; + struct v4l2_audio *p = arg; if (!vfd->vidioc_s_audio) break; - dbgarg(cmd, "index=%d, name=%s, capability=%d, " - "mode=%d\n", p->index, p->name, + dbgarg(cmd, "index=%d, name=%s, capability=0x%x, " + "mode=0x%x\n", p->index, p->name, p->capability, p->mode); - ret=vfd->vidioc_s_audio(file, fh, p); + ret = vfd->vidioc_s_audio(file, fh, p); break; } case VIDIOC_ENUMAUDOUT: @@ -1521,9 +1640,9 @@ static int __video_do_ioctl(struct inode *inode, struct file *file, struct v4l2_crop *p=arg; if (!vfd->vidioc_g_crop) break; + dbgarg(cmd, "type=%s\n", prt_names(p->type, v4l2_type_names)); ret=vfd->vidioc_g_crop(file, fh, p); if (!ret) { - dbgarg(cmd, "type=%d\n", p->type); dbgrect(vfd, "", &p->c); } break; @@ -1533,21 +1652,24 @@ static int __video_do_ioctl(struct inode *inode, struct file *file, struct v4l2_crop *p=arg; if (!vfd->vidioc_s_crop) break; - dbgarg(cmd, "type=%d\n", p->type); + dbgarg(cmd, "type=%s\n", prt_names(p->type, v4l2_type_names)); dbgrect(vfd, "", &p->c); ret=vfd->vidioc_s_crop(file, fh, p); break; } case VIDIOC_CROPCAP: { - struct v4l2_cropcap *p=arg; + struct v4l2_cropcap *p = arg; + /*FIXME: Should also show v4l2_fract pixelaspect */ if (!vfd->vidioc_cropcap) break; - dbgarg(cmd, "type=%d\n", p->type); - dbgrect(vfd, "bounds ", &p->bounds); - dbgrect(vfd, "defrect ", &p->defrect); - ret=vfd->vidioc_cropcap(file, fh, p); + dbgarg(cmd, "type=%s\n", prt_names(p->type, v4l2_type_names)); + ret = vfd->vidioc_cropcap(file, fh, p); + if (!ret) { + dbgrect(vfd, "bounds ", &p->bounds); + dbgrect(vfd, "defrect ", &p->defrect); + } break; } case VIDIOC_G_JPEGCOMP: @@ -1590,26 +1712,26 @@ static int __video_do_ioctl(struct inode *inode, struct file *file, } case VIDIOC_ENCODER_CMD: { - struct v4l2_encoder_cmd *p=arg; + struct v4l2_encoder_cmd *p = arg; if (!vfd->vidioc_encoder_cmd) break; - ret=vfd->vidioc_encoder_cmd(file, fh, p); + memset(&p->raw, 0, sizeof(p->raw)); + ret = vfd->vidioc_encoder_cmd(file, fh, p); if (!ret) - dbgarg (cmd, "cmd=%d, flags=%d\n", - p->cmd,p->flags); + dbgarg(cmd, "cmd=%d, flags=%x\n", p->cmd, p->flags); break; } case VIDIOC_TRY_ENCODER_CMD: { - struct v4l2_encoder_cmd *p=arg; + struct v4l2_encoder_cmd *p = arg; if (!vfd->vidioc_try_encoder_cmd) break; - ret=vfd->vidioc_try_encoder_cmd(file, fh, p); + memset(&p->raw, 0, sizeof(p->raw)); + ret = vfd->vidioc_try_encoder_cmd(file, fh, p); if (!ret) - dbgarg (cmd, "cmd=%d, flags=%d\n", - p->cmd,p->flags); + dbgarg(cmd, "cmd=%d, flags=%x\n", p->cmd, p->flags); break; } case VIDIOC_G_PARM: @@ -1649,54 +1771,57 @@ static int __video_do_ioctl(struct inode *inode, struct file *file, } case VIDIOC_G_TUNER: { - struct v4l2_tuner *p=arg; - __u32 index=p->index; + struct v4l2_tuner *p = arg; + __u32 index = p->index; if (!vfd->vidioc_g_tuner) break; - memset(p,0,sizeof(*p)); - p->index=index; + memset(p, 0, sizeof(*p)); + p->index = index; - ret=vfd->vidioc_g_tuner(file, fh, p); + ret = vfd->vidioc_g_tuner(file, fh, p); if (!ret) - dbgarg (cmd, "index=%d, name=%s, type=%d, " - "capability=%d, rangelow=%d, " + dbgarg(cmd, "index=%d, name=%s, type=%d, " + "capability=0x%x, rangelow=%d, " "rangehigh=%d, signal=%d, afc=%d, " - "rxsubchans=%d, audmode=%d\n", + "rxsubchans=0x%x, audmode=%d\n", p->index, p->name, p->type, p->capability, p->rangelow, - p->rangehigh, p->rxsubchans, - p->audmode, p->signal, p->afc); + p->rangehigh, p->signal, p->afc, + p->rxsubchans, p->audmode); break; } case VIDIOC_S_TUNER: { - struct v4l2_tuner *p=arg; + struct v4l2_tuner *p = arg; + if (!vfd->vidioc_s_tuner) break; - dbgarg (cmd, "index=%d, name=%s, type=%d, " - "capability=%d, rangelow=%d, rangehigh=%d, " - "signal=%d, afc=%d, rxsubchans=%d, " - "audmode=%d\n",p->index, p->name, p->type, - p->capability, p->rangelow,p->rangehigh, - p->rxsubchans, p->audmode, p->signal, - p->afc); - ret=vfd->vidioc_s_tuner(file, fh, p); + dbgarg(cmd, "index=%d, name=%s, type=%d, " + "capability=0x%x, rangelow=%d, " + "rangehigh=%d, signal=%d, afc=%d, " + "rxsubchans=0x%x, audmode=%d\n", + p->index, p->name, p->type, + p->capability, p->rangelow, + p->rangehigh, p->signal, p->afc, + p->rxsubchans, p->audmode); + ret = vfd->vidioc_s_tuner(file, fh, p); break; } case VIDIOC_G_FREQUENCY: { - struct v4l2_frequency *p=arg; + struct v4l2_frequency *p = arg; + if (!vfd->vidioc_g_frequency) break; - memset(p,0,sizeof(*p)); + memset(p->reserved, 0, sizeof(p->reserved)); - ret=vfd->vidioc_g_frequency(file, fh, p); + ret = vfd->vidioc_g_frequency(file, fh, p); if (!ret) - dbgarg (cmd, "tuner=%d, type=%d, frequency=%d\n", - p->tuner,p->type,p->frequency); + dbgarg(cmd, "tuner=%d, type=%d, frequency=%d\n", + p->tuner, p->type, p->frequency); break; } case VIDIOC_S_FREQUENCY: @@ -1711,12 +1836,17 @@ static int __video_do_ioctl(struct inode *inode, struct file *file, } case VIDIOC_G_SLICED_VBI_CAP: { - struct v4l2_sliced_vbi_cap *p=arg; + struct v4l2_sliced_vbi_cap *p = arg; + __u32 type = p->type; + if (!vfd->vidioc_g_sliced_vbi_cap) break; - ret=vfd->vidioc_g_sliced_vbi_cap(file, fh, p); + memset(p, 0, sizeof(*p)); + p->type = type; + dbgarg(cmd, "type=%s\n", prt_names(p->type, v4l2_type_names)); + ret = vfd->vidioc_g_sliced_vbi_cap(file, fh, p); if (!ret) - dbgarg (cmd, "service_set=%d\n", p->service_set); + dbgarg2("service_set=%d\n", p->service_set); break; } case VIDIOC_LOG_STATUS: @@ -1763,13 +1893,23 @@ static int __video_do_ioctl(struct inode *inode, struct file *file, ret = vfd->vidioc_default(file, fh, cmd, arg); break; } + case VIDIOC_S_HW_FREQ_SEEK: + { + struct v4l2_hw_freq_seek *p = arg; + if (!vfd->vidioc_s_hw_freq_seek) + break; + dbgarg(cmd, + "tuner=%d, type=%d, seek_upward=%d, wrap_around=%d\n", + p->tuner, p->type, p->seek_upward, p->wrap_around); + ret = vfd->vidioc_s_hw_freq_seek(file, fh, p); + break; + } } /* switch */ if (vfd->debug & V4L2_DEBUG_IOCTL_ARG) { - if (ret<0) { - printk("%s: err: on ", vfd->name); + if (ret < 0) { v4l_print_ioctl(vfd->name, cmd); - printk("\n"); + printk(KERN_CONT " error %d\n", ret); } } @@ -1871,8 +2011,55 @@ out: } EXPORT_SYMBOL(video_ioctl2); +/** + * get_index - assign stream number based on parent device + * @vdev: video_device to assign index number to, vdev->dev should be assigned + * @num: -1 if auto assign, requested number otherwise + * + * + * returns -ENFILE if num is already in use, a free index number if + * successful. + */ +static int get_index(struct video_device *vdev, int num) +{ + u32 used = 0; + const int max_index = sizeof(used) * 8 - 1; + int i; + + /* Currently a single v4l driver instance cannot create more than + 32 devices. + Increase to u64 or an array of u32 if more are needed. */ + if (num > max_index) { + printk(KERN_ERR "videodev: %s num is too large\n", __func__); + return -EINVAL; + } + + for (i = 0; i < VIDEO_NUM_DEVICES; i++) { + if (video_device[i] != NULL && + video_device[i] != vdev && + video_device[i]->dev == vdev->dev) { + used |= 1 << video_device[i]->index; + } + } + + if (num >= 0) { + if (used & (1 << num)) + return -ENFILE; + return num; + } + + i = ffz(used); + return i > max_index ? -ENFILE : i; +} + static const struct file_operations video_fops; +int video_register_device(struct video_device *vfd, int type, int nr) +{ + return video_register_device_index(vfd, type, nr, -1); +} +EXPORT_SYMBOL(video_register_device); + /** * video_register_device - register video4linux devices * @vfd: video device structure we want to register @@ -1898,7 +2085,8 @@ static const struct file_operations video_fops; * %VFL_TYPE_RADIO - A radio card */ -int video_register_device(struct video_device *vfd, int type, int nr) +int video_register_device_index(struct video_device *vfd, int type, int nr, + int index) { int i=0; int base; @@ -1955,20 +2143,29 @@ int video_register_device(struct video_device *vfd, int type, int nr) } video_device[i]=vfd; vfd->minor=i; + + ret = get_index(vfd, index); + vfd->index = ret; + mutex_unlock(&videodev_lock); + + if (ret < 0) { + printk(KERN_ERR "%s: get_index failed\n", __func__); + goto fail_minor; + } + mutex_init(&vfd->lock); /* sysfs class */ memset(&vfd->class_dev, 0x00, sizeof(vfd->class_dev)); - if (vfd->dev) - vfd->class_dev.parent = vfd->dev; vfd->class_dev.class = &video_class; vfd->class_dev.devt = MKDEV(VIDEO_MAJOR, vfd->minor); + if (vfd->dev) + vfd->class_dev.parent = vfd->dev; sprintf(vfd->class_dev.bus_id, "%s%d", name_base, i - base); ret = device_register(&vfd->class_dev); if (ret < 0) { - printk(KERN_ERR "%s: device_register failed\n", - __func__); + printk(KERN_ERR "%s: device_register failed\n", __func__); goto fail_minor; } @@ -1988,7 +2185,7 @@ fail_minor: mutex_unlock(&videodev_lock); return ret; } -EXPORT_SYMBOL(video_register_device); +EXPORT_SYMBOL(video_register_device_index); /** * video_unregister_device - unregister a video4linux device diff --git a/drivers/media/video/vivi.c b/drivers/media/video/vivi.c index 5ff9a58b6135..059b01c11dc1 100644 --- a/drivers/media/video/vivi.c +++ b/drivers/media/video/vivi.c @@ -39,6 +39,8 @@ #include <linux/highmem.h> #include <linux/freezer.h> +#define VIVI_MODULE_NAME "vivi" + /* Wake up at about 30 fps */ #define WAKE_NUMERATOR 30 #define WAKE_DENOMINATOR 1001 @@ -47,7 +49,7 @@ #include "font.h" #define VIVI_MAJOR_VERSION 0 -#define VIVI_MINOR_VERSION 4 +#define VIVI_MINOR_VERSION 5 #define VIVI_RELEASE 0 #define VIVI_VERSION \ KERNEL_VERSION(VIVI_MAJOR_VERSION, VIVI_MINOR_VERSION, VIVI_RELEASE) @@ -630,7 +632,7 @@ static int vidioc_querycap(struct file *file, void *priv, return 0; } -static int vidioc_enum_fmt_cap(struct file *file, void *priv, +static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv, struct v4l2_fmtdesc *f) { if (f->index > 0) @@ -641,7 +643,7 @@ static int vidioc_enum_fmt_cap(struct file *file, void *priv, return 0; } -static int vidioc_g_fmt_cap(struct file *file, void *priv, +static int vidioc_g_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f) { struct vivi_fh *fh = priv; @@ -658,7 +660,7 @@ static int vidioc_g_fmt_cap(struct file *file, void *priv, return (0); } -static int vidioc_try_fmt_cap(struct file *file, void *priv, +static int vidioc_try_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f) { struct vivi_fh *fh = priv; @@ -706,13 +708,13 @@ static int vidioc_try_fmt_cap(struct file *file, void *priv, } /*FIXME: This seems to be generic enough to be at videodev2 */ -static int vidioc_s_fmt_cap(struct file *file, void *priv, +static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f) { struct vivi_fh *fh = priv; struct videobuf_queue *q = &fh->vb_vidq; - int ret = vidioc_try_fmt_cap(file, fh, f); + int ret = vidioc_try_fmt_vid_cap(file, fh, f); if (ret < 0) return (ret); @@ -1017,10 +1019,15 @@ static int vivi_release(void) list_del(list); dev = list_entry(list, struct vivi_dev, vivi_devlist); - if (-1 != dev->vfd->minor) + if (-1 != dev->vfd->minor) { video_unregister_device(dev->vfd); - else + printk(KERN_INFO "%s: /dev/video%d unregistered.\n", + VIVI_MODULE_NAME, dev->vfd->minor); + } else { video_device_release(dev->vfd); + printk(KERN_INFO "%s: /dev/video%d released.\n", + VIVI_MODULE_NAME, dev->vfd->minor); + } kfree(dev); } @@ -1066,10 +1073,10 @@ static struct video_device vivi_template = { .release = video_device_release, .vidioc_querycap = vidioc_querycap, - .vidioc_enum_fmt_cap = vidioc_enum_fmt_cap, - .vidioc_g_fmt_cap = vidioc_g_fmt_cap, - .vidioc_try_fmt_cap = vidioc_try_fmt_cap, - .vidioc_s_fmt_cap = vidioc_s_fmt_cap, + .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap, + .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap, + .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap, + .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap, .vidioc_reqbufs = vidioc_reqbufs, .vidioc_querybuf = vidioc_querybuf, .vidioc_qbuf = vidioc_qbuf, @@ -1131,6 +1138,8 @@ static int __init vivi_init(void) video_nr++; dev->vfd = vfd; + printk(KERN_INFO "%s: V4L2 device registered as /dev/video%d\n", + VIVI_MODULE_NAME, vfd->minor); } if (ret < 0) { @@ -1138,7 +1147,9 @@ static int __init vivi_init(void) printk(KERN_INFO "Error %d while loading vivi driver\n", ret); } else printk(KERN_INFO "Video Technology Magazine Virtual Video " - "Capture Board successfully loaded.\n"); + "Capture Board ver %u.%u.%u successfully loaded.\n", + (VIVI_VERSION >> 16) & 0xFF, (VIVI_VERSION >> 8) & 0xFF, + VIVI_VERSION & 0xFF); return ret; } diff --git a/drivers/media/video/vp27smpx.c b/drivers/media/video/vp27smpx.c index a1f76ee032e7..cbecb3cbbbaa 100644 --- a/drivers/media/video/vp27smpx.c +++ b/drivers/media/video/vp27smpx.c @@ -166,4 +166,3 @@ static struct v4l2_i2c_driver_data v4l2_i2c_data = { .remove = vp27smpx_remove, .id_table = vp27smpx_id, }; - diff --git a/drivers/media/video/wm8739.c b/drivers/media/video/wm8739.c index fc50299caa36..7be47a255853 100644 --- a/drivers/media/video/wm8739.c +++ b/drivers/media/video/wm8739.c @@ -327,4 +327,3 @@ static struct v4l2_i2c_driver_data v4l2_i2c_data = { .remove = wm8739_remove, .id_table = wm8739_id, }; - diff --git a/drivers/media/video/wm8775.c b/drivers/media/video/wm8775.c index 506378a508b9..c2ab70a04a74 100644 --- a/drivers/media/video/wm8775.c +++ b/drivers/media/video/wm8775.c @@ -42,7 +42,6 @@ MODULE_LICENSE("GPL"); static unsigned short normal_i2c[] = { 0x36 >> 1, I2C_CLIENT_END }; - I2C_CLIENT_INSMOD; @@ -230,4 +229,3 @@ static struct v4l2_i2c_driver_data v4l2_i2c_data = { .remove = wm8775_remove, .id_table = wm8775_id, }; - diff --git a/drivers/media/video/zoran_card.c b/drivers/media/video/zoran_card.c index 006d48847e24..0929edb2d4f1 100644 --- a/drivers/media/video/zoran_card.c +++ b/drivers/media/video/zoran_card.c @@ -59,8 +59,6 @@ #include "zoran_device.h" #include "zoran_procfs.h" -#define I2C_NAME(x) (x)->name - extern const struct zoran_format zoran_formats[]; static int card[BUZ_MAX] = { -1, -1, -1, -1 }; @@ -360,14 +358,6 @@ i2cid_to_modulename (u16 i2c_id) case I2C_DRIVERID_VPX3220: name = "vpx3220"; break; -/* case I2C_DRIVERID_VPX3224: - name = "vpx3224"; - break; - case I2C_DRIVERID_MSE3000: - name = "mse3000"; - break;*/ - default: - break; } return name; @@ -388,8 +378,6 @@ codecid_to_modulename (u16 codecid) case CODEC_TYPE_ZR36016: name = "zr36016"; break; - default: - break; } return name; @@ -430,7 +418,6 @@ static struct card_info zoran_cards[NUM_CARDS] __devinitdata = { .type = DC10_old, .name = "DC10(old)", .i2c_decoder = I2C_DRIVERID_VPX3220, - /*.i2c_encoder = I2C_DRIVERID_MSE3000,*/ .video_codec = CODEC_TYPE_ZR36050, .video_vfe = CODEC_TYPE_ZR36016, @@ -809,7 +796,7 @@ clientunreg_unlock_and_return: return res; } -static struct i2c_algo_bit_data zoran_i2c_bit_data_template = { +static const struct i2c_algo_bit_data zoran_i2c_bit_data_template = { .setsda = zoran_i2c_setsda, .setscl = zoran_i2c_setscl, .getsda = zoran_i2c_getsda, @@ -818,24 +805,17 @@ static struct i2c_algo_bit_data zoran_i2c_bit_data_template = { .timeout = 100, }; -static struct i2c_adapter zoran_i2c_adapter_template = { - .name = "zr36057", - .id = I2C_HW_B_ZR36067, - .algo = NULL, - .client_register = zoran_i2c_client_register, - .client_unregister = zoran_i2c_client_unregister, -}; - static int zoran_register_i2c (struct zoran *zr) { memcpy(&zr->i2c_algo, &zoran_i2c_bit_data_template, sizeof(struct i2c_algo_bit_data)); zr->i2c_algo.data = zr; - memcpy(&zr->i2c_adapter, &zoran_i2c_adapter_template, - sizeof(struct i2c_adapter)); - strncpy(I2C_NAME(&zr->i2c_adapter), ZR_DEVNAME(zr), - sizeof(I2C_NAME(&zr->i2c_adapter)) - 1); + zr->i2c_adapter.id = I2C_HW_B_ZR36067; + zr->i2c_adapter.client_register = zoran_i2c_client_register; + zr->i2c_adapter.client_unregister = zoran_i2c_client_unregister; + strlcpy(zr->i2c_adapter.name, ZR_DEVNAME(zr), + sizeof(zr->i2c_adapter.name)); i2c_set_adapdata(&zr->i2c_adapter, zr); zr->i2c_adapter.algo_data = &zr->i2c_algo; zr->i2c_adapter.dev.parent = &zr->pci_dev->dev; @@ -1147,7 +1127,7 @@ zr36057_init (struct zoran *zr) goto exit_free; } for (j = 0; j < BUZ_NUM_STAT_COM; j++) { - zr->stat_com[j] = 1; /* mark as unavailable to zr36057 */ + zr->stat_com[j] = cpu_to_le32(1); /* mark as unavailable to zr36057 */ } /* diff --git a/drivers/media/video/zoran_driver.c b/drivers/media/video/zoran_driver.c index 5394d7a5cfee..c0675921fe20 100644 --- a/drivers/media/video/zoran_driver.c +++ b/drivers/media/video/zoran_driver.c @@ -94,7 +94,6 @@ V4L2_CAP_VIDEO_OVERLAY \ ) -#include <asm/byteorder.h> #if defined(CONFIG_VIDEO_V4L1_COMPAT) #define ZFMT(pal, fcc, cs) \ @@ -2795,7 +2794,7 @@ zoran_do_ioctl (struct inode *inode, { struct v4l2_format *fmt = arg; int i, res = 0; - __u32 printformat; + __le32 printformat; dprintk(3, KERN_DEBUG "%s: VIDIOC_S_FMT - type=%d, ", ZR_DEVNAME(zr), fmt->type); @@ -3040,7 +3039,7 @@ zoran_do_ioctl (struct inode *inode, { int i, res = 0; struct v4l2_framebuffer *fb = arg; - __u32 printformat = __cpu_to_le32(fb->fmt.pixelformat); + __le32 printformat = __cpu_to_le32(fb->fmt.pixelformat); dprintk(3, KERN_DEBUG diff --git a/drivers/media/video/zr364xx.c b/drivers/media/video/zr364xx.c index a0e49dc66301..485df2e36132 100644 --- a/drivers/media/video/zr364xx.c +++ b/drivers/media/video/zr364xx.c @@ -521,7 +521,7 @@ static int zr364xx_vidioc_g_ctrl(struct file *file, void *priv, return 0; } -static int zr364xx_vidioc_enum_fmt_cap(struct file *file, +static int zr364xx_vidioc_enum_fmt_vid_cap(struct file *file, void *priv, struct v4l2_fmtdesc *f) { if (f->index > 0) @@ -537,7 +537,7 @@ static int zr364xx_vidioc_enum_fmt_cap(struct file *file, return 0; } -static int zr364xx_vidioc_try_fmt_cap(struct file *file, void *priv, +static int zr364xx_vidioc_try_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f) { struct video_device *vdev = video_devdata(file); @@ -564,7 +564,7 @@ static int zr364xx_vidioc_try_fmt_cap(struct file *file, void *priv, return 0; } -static int zr364xx_vidioc_g_fmt_cap(struct file *file, void *priv, +static int zr364xx_vidioc_g_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f) { struct video_device *vdev = video_devdata(file); @@ -589,7 +589,7 @@ static int zr364xx_vidioc_g_fmt_cap(struct file *file, void *priv, return 0; } -static int zr364xx_vidioc_s_fmt_cap(struct file *file, void *priv, +static int zr364xx_vidioc_s_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f) { struct video_device *vdev = video_devdata(file); @@ -770,10 +770,10 @@ static struct video_device zr364xx_template = { .minor = -1, .vidioc_querycap = zr364xx_vidioc_querycap, - .vidioc_enum_fmt_cap = zr364xx_vidioc_enum_fmt_cap, - .vidioc_try_fmt_cap = zr364xx_vidioc_try_fmt_cap, - .vidioc_s_fmt_cap = zr364xx_vidioc_s_fmt_cap, - .vidioc_g_fmt_cap = zr364xx_vidioc_g_fmt_cap, + .vidioc_enum_fmt_vid_cap = zr364xx_vidioc_enum_fmt_vid_cap, + .vidioc_try_fmt_vid_cap = zr364xx_vidioc_try_fmt_vid_cap, + .vidioc_s_fmt_vid_cap = zr364xx_vidioc_s_fmt_vid_cap, + .vidioc_g_fmt_vid_cap = zr364xx_vidioc_g_fmt_vid_cap, .vidioc_enum_input = zr364xx_vidioc_enum_input, .vidioc_g_input = zr364xx_vidioc_g_input, .vidioc_s_input = zr364xx_vidioc_s_input, diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index ae96bd6242f2..260bade0a5ec 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -17,7 +17,7 @@ config MFD_SM501 config MFD_ASIC3 bool "Support for Compaq ASIC3" - depends on GENERIC_HARDIRQS && ARM + depends on GENERIC_HARDIRQS && HAVE_GPIO_LIB && ARM ---help--- This driver supports the ASIC3 multifunction chip found on many PDAs (mainly iPAQ and HTC based ones) diff --git a/drivers/mfd/asic3.c b/drivers/mfd/asic3.c index ef8a492766a7..3b870e7fb3e1 100644 --- a/drivers/mfd/asic3.c +++ b/drivers/mfd/asic3.c @@ -9,7 +9,7 @@ * * Copyright 2001 Compaq Computer Corporation. * Copyright 2004-2005 Phil Blundell - * Copyright 2007 OpenedHand Ltd. + * Copyright 2007-2008 OpenedHand Ltd. * * Authors: Phil Blundell <pb@handhelds.org>, * Samuel Ortiz <sameo@openedhand.com> @@ -19,12 +19,26 @@ #include <linux/version.h> #include <linux/kernel.h> #include <linux/irq.h> +#include <linux/gpio.h> #include <linux/io.h> #include <linux/spinlock.h> #include <linux/platform_device.h> #include <linux/mfd/asic3.h> +struct asic3 { + void __iomem *mapping; + unsigned int bus_shift; + unsigned int irq_nr; + unsigned int irq_base; + spinlock_t lock; + u16 irq_bothedge[4]; + struct gpio_chip gpio; + struct device *dev; +}; + +static int asic3_gpio_get(struct gpio_chip *chip, unsigned offset); + static inline void asic3_write_register(struct asic3 *asic, unsigned int reg, u32 value) { @@ -41,8 +55,8 @@ static inline u32 asic3_read_register(struct asic3 *asic, /* IRQs */ #define MAX_ASIC_ISR_LOOPS 20 -#define ASIC3_GPIO_Base_INCR \ - (ASIC3_GPIO_B_Base - ASIC3_GPIO_A_Base) +#define ASIC3_GPIO_BASE_INCR \ + (ASIC3_GPIO_B_BASE - ASIC3_GPIO_A_BASE) static void asic3_irq_flip_edge(struct asic3 *asic, u32 base, int bit) @@ -52,10 +66,10 @@ static void asic3_irq_flip_edge(struct asic3 *asic, spin_lock_irqsave(&asic->lock, flags); edge = asic3_read_register(asic, - base + ASIC3_GPIO_EdgeTrigger); + base + ASIC3_GPIO_EDGE_TRIGGER); edge ^= bit; asic3_write_register(asic, - base + ASIC3_GPIO_EdgeTrigger, edge); + base + ASIC3_GPIO_EDGE_TRIGGER, edge); spin_unlock_irqrestore(&asic->lock, flags); } @@ -75,7 +89,7 @@ static void asic3_irq_demux(unsigned int irq, struct irq_desc *desc) spin_lock_irqsave(&asic->lock, flags); status = asic3_read_register(asic, - ASIC3_OFFSET(INTR, PIntStat)); + ASIC3_OFFSET(INTR, P_INT_STAT)); spin_unlock_irqrestore(&asic->lock, flags); /* Check all ten register bits */ @@ -87,17 +101,17 @@ static void asic3_irq_demux(unsigned int irq, struct irq_desc *desc) if (status & (1 << bank)) { unsigned long base, istat; - base = ASIC3_GPIO_A_Base - + bank * ASIC3_GPIO_Base_INCR; + base = ASIC3_GPIO_A_BASE + + bank * ASIC3_GPIO_BASE_INCR; spin_lock_irqsave(&asic->lock, flags); istat = asic3_read_register(asic, base + - ASIC3_GPIO_IntStatus); + ASIC3_GPIO_INT_STATUS); /* Clearing IntStatus */ asic3_write_register(asic, base + - ASIC3_GPIO_IntStatus, 0); + ASIC3_GPIO_INT_STATUS, 0); spin_unlock_irqrestore(&asic->lock, flags); for (i = 0; i < ASIC3_GPIOS_PER_BANK; i++) { @@ -123,7 +137,7 @@ static void asic3_irq_demux(unsigned int irq, struct irq_desc *desc) for (i = ASIC3_NUM_GPIOS; i < ASIC3_NR_IRQS; i++) { /* They start at bit 4 and go up */ if (status & (1 << (i - ASIC3_NUM_GPIOS + 4))) { - desc = irq_desc + + i; + desc = irq_desc + asic->irq_base + i; desc->handle_irq(asic->irq_base + i, desc); } @@ -131,8 +145,7 @@ static void asic3_irq_demux(unsigned int irq, struct irq_desc *desc) } if (iter >= MAX_ASIC_ISR_LOOPS) - printk(KERN_ERR "%s: interrupt processing overrun\n", - __func__); + dev_err(asic->dev, "interrupt processing overrun\n"); } static inline int asic3_irq_to_bank(struct asic3 *asic, int irq) @@ -141,7 +154,7 @@ static inline int asic3_irq_to_bank(struct asic3 *asic, int irq) n = (irq - asic->irq_base) >> 4; - return (n * (ASIC3_GPIO_B_Base - ASIC3_GPIO_A_Base)); + return (n * (ASIC3_GPIO_B_BASE - ASIC3_GPIO_A_BASE)); } static inline int asic3_irq_to_index(struct asic3 *asic, int irq) @@ -159,9 +172,9 @@ static void asic3_mask_gpio_irq(unsigned int irq) index = asic3_irq_to_index(asic, irq); spin_lock_irqsave(&asic->lock, flags); - val = asic3_read_register(asic, bank + ASIC3_GPIO_Mask); + val = asic3_read_register(asic, bank + ASIC3_GPIO_MASK); val |= 1 << index; - asic3_write_register(asic, bank + ASIC3_GPIO_Mask, val); + asic3_write_register(asic, bank + ASIC3_GPIO_MASK, val); spin_unlock_irqrestore(&asic->lock, flags); } @@ -173,15 +186,15 @@ static void asic3_mask_irq(unsigned int irq) spin_lock_irqsave(&asic->lock, flags); regval = asic3_read_register(asic, - ASIC3_INTR_Base + - ASIC3_INTR_IntMask); + ASIC3_INTR_BASE + + ASIC3_INTR_INT_MASK); regval &= ~(ASIC3_INTMASK_MASK0 << (irq - (asic->irq_base + ASIC3_NUM_GPIOS))); asic3_write_register(asic, - ASIC3_INTR_Base + - ASIC3_INTR_IntMask, + ASIC3_INTR_BASE + + ASIC3_INTR_INT_MASK, regval); spin_unlock_irqrestore(&asic->lock, flags); } @@ -196,9 +209,9 @@ static void asic3_unmask_gpio_irq(unsigned int irq) index = asic3_irq_to_index(asic, irq); spin_lock_irqsave(&asic->lock, flags); - val = asic3_read_register(asic, bank + ASIC3_GPIO_Mask); + val = asic3_read_register(asic, bank + ASIC3_GPIO_MASK); val &= ~(1 << index); - asic3_write_register(asic, bank + ASIC3_GPIO_Mask, val); + asic3_write_register(asic, bank + ASIC3_GPIO_MASK, val); spin_unlock_irqrestore(&asic->lock, flags); } @@ -210,15 +223,15 @@ static void asic3_unmask_irq(unsigned int irq) spin_lock_irqsave(&asic->lock, flags); regval = asic3_read_register(asic, - ASIC3_INTR_Base + - ASIC3_INTR_IntMask); + ASIC3_INTR_BASE + + ASIC3_INTR_INT_MASK); regval |= (ASIC3_INTMASK_MASK0 << (irq - (asic->irq_base + ASIC3_NUM_GPIOS))); asic3_write_register(asic, - ASIC3_INTR_Base + - ASIC3_INTR_IntMask, + ASIC3_INTR_BASE + + ASIC3_INTR_INT_MASK, regval); spin_unlock_irqrestore(&asic->lock, flags); } @@ -236,11 +249,11 @@ static int asic3_gpio_irq_type(unsigned int irq, unsigned int type) spin_lock_irqsave(&asic->lock, flags); level = asic3_read_register(asic, - bank + ASIC3_GPIO_LevelTrigger); + bank + ASIC3_GPIO_LEVEL_TRIGGER); edge = asic3_read_register(asic, - bank + ASIC3_GPIO_EdgeTrigger); + bank + ASIC3_GPIO_EDGE_TRIGGER); trigger = asic3_read_register(asic, - bank + ASIC3_GPIO_TriggerType); + bank + ASIC3_GPIO_TRIGGER_TYPE); asic->irq_bothedge[(irq - asic->irq_base) >> 4] &= ~bit; if (type == IRQT_RISING) { @@ -251,7 +264,7 @@ static int asic3_gpio_irq_type(unsigned int irq, unsigned int type) edge &= ~bit; } else if (type == IRQT_BOTHEDGE) { trigger |= bit; - if (asic3_gpio_get_value(asic, irq - asic->irq_base)) + if (asic3_gpio_get(&asic->gpio, irq - asic->irq_base)) edge &= ~bit; else edge |= bit; @@ -268,13 +281,13 @@ static int asic3_gpio_irq_type(unsigned int irq, unsigned int type) * be careful to not unmask them if mask was also called. * Probably need internal state for mask. */ - printk(KERN_NOTICE "asic3: irq type not changed.\n"); + dev_notice(asic->dev, "irq type not changed\n"); } - asic3_write_register(asic, bank + ASIC3_GPIO_LevelTrigger, + asic3_write_register(asic, bank + ASIC3_GPIO_LEVEL_TRIGGER, level); - asic3_write_register(asic, bank + ASIC3_GPIO_EdgeTrigger, + asic3_write_register(asic, bank + ASIC3_GPIO_EDGE_TRIGGER, edge); - asic3_write_register(asic, bank + ASIC3_GPIO_TriggerType, + asic3_write_register(asic, bank + ASIC3_GPIO_TRIGGER_TYPE, trigger); spin_unlock_irqrestore(&asic->lock, flags); return 0; @@ -295,11 +308,12 @@ static struct irq_chip asic3_irq_chip = { .unmask = asic3_unmask_irq, }; -static int asic3_irq_probe(struct platform_device *pdev) +static int __init asic3_irq_probe(struct platform_device *pdev) { struct asic3 *asic = platform_get_drvdata(pdev); unsigned long clksel = 0; unsigned int irq, irq_base; + int map_size; asic->irq_nr = platform_get_irq(pdev, 0); if (asic->irq_nr < 0) @@ -323,7 +337,7 @@ static int asic3_irq_probe(struct platform_device *pdev) set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); } - asic3_write_register(asic, ASIC3_OFFSET(INTR, IntMask), + asic3_write_register(asic, ASIC3_OFFSET(INTR, INT_MASK), ASIC3_INTMASK_GINTMASK); set_irq_chained_handler(asic->irq_nr, asic3_irq_demux); @@ -350,149 +364,182 @@ static void asic3_irq_remove(struct platform_device *pdev) } /* GPIOs */ -static inline u32 asic3_get_gpio(struct asic3 *asic, unsigned int base, - unsigned int function) -{ - return asic3_read_register(asic, base + function); -} - -static void asic3_set_gpio(struct asic3 *asic, unsigned int base, - unsigned int function, u32 bits, u32 val) +static int asic3_gpio_direction(struct gpio_chip *chip, + unsigned offset, int out) { + u32 mask = ASIC3_GPIO_TO_MASK(offset), out_reg; + unsigned int gpio_base; unsigned long flags; + struct asic3 *asic; + + asic = container_of(chip, struct asic3, gpio); + gpio_base = ASIC3_GPIO_TO_BASE(offset); + + if (gpio_base > ASIC3_GPIO_D_BASE) { + dev_err(asic->dev, "Invalid base (0x%x) for gpio %d\n", + gpio_base, offset); + return -EINVAL; + } spin_lock_irqsave(&asic->lock, flags); - val |= (asic3_read_register(asic, base + function) & ~bits); - asic3_write_register(asic, base + function, val); + out_reg = asic3_read_register(asic, gpio_base + ASIC3_GPIO_DIRECTION); + + /* Input is 0, Output is 1 */ + if (out) + out_reg |= mask; + else + out_reg &= ~mask; + + asic3_write_register(asic, gpio_base + ASIC3_GPIO_DIRECTION, out_reg); + spin_unlock_irqrestore(&asic->lock, flags); + + return 0; + +} + +static int asic3_gpio_direction_input(struct gpio_chip *chip, + unsigned offset) +{ + return asic3_gpio_direction(chip, offset, 0); +} + +static int asic3_gpio_direction_output(struct gpio_chip *chip, + unsigned offset, int value) +{ + return asic3_gpio_direction(chip, offset, 1); } -#define asic3_get_gpio_a(asic, fn) \ - asic3_get_gpio(asic, ASIC3_GPIO_A_Base, ASIC3_GPIO_##fn) -#define asic3_get_gpio_b(asic, fn) \ - asic3_get_gpio(asic, ASIC3_GPIO_B_Base, ASIC3_GPIO_##fn) -#define asic3_get_gpio_c(asic, fn) \ - asic3_get_gpio(asic, ASIC3_GPIO_C_Base, ASIC3_GPIO_##fn) -#define asic3_get_gpio_d(asic, fn) \ - asic3_get_gpio(asic, ASIC3_GPIO_D_Base, ASIC3_GPIO_##fn) - -#define asic3_set_gpio_a(asic, fn, bits, val) \ - asic3_set_gpio(asic, ASIC3_GPIO_A_Base, ASIC3_GPIO_##fn, bits, val) -#define asic3_set_gpio_b(asic, fn, bits, val) \ - asic3_set_gpio(asic, ASIC3_GPIO_B_Base, ASIC3_GPIO_##fn, bits, val) -#define asic3_set_gpio_c(asic, fn, bits, val) \ - asic3_set_gpio(asic, ASIC3_GPIO_C_Base, ASIC3_GPIO_##fn, bits, val) -#define asic3_set_gpio_d(asic, fn, bits, val) \ - asic3_set_gpio(asic, ASIC3_GPIO_D_Base, ASIC3_GPIO_##fn, bits, val) - -#define asic3_set_gpio_banks(asic, fn, bits, pdata, field) \ - do { \ - asic3_set_gpio_a((asic), fn, (bits), (pdata)->gpio_a.field); \ - asic3_set_gpio_b((asic), fn, (bits), (pdata)->gpio_b.field); \ - asic3_set_gpio_c((asic), fn, (bits), (pdata)->gpio_c.field); \ - asic3_set_gpio_d((asic), fn, (bits), (pdata)->gpio_d.field); \ - } while (0) - -int asic3_gpio_get_value(struct asic3 *asic, unsigned gpio) +static int asic3_gpio_get(struct gpio_chip *chip, + unsigned offset) { - u32 mask = ASIC3_GPIO_bit(gpio); - - switch (gpio >> 4) { - case ASIC3_GPIO_BANK_A: - return asic3_get_gpio_a(asic, Status) & mask; - case ASIC3_GPIO_BANK_B: - return asic3_get_gpio_b(asic, Status) & mask; - case ASIC3_GPIO_BANK_C: - return asic3_get_gpio_c(asic, Status) & mask; - case ASIC3_GPIO_BANK_D: - return asic3_get_gpio_d(asic, Status) & mask; - default: - printk(KERN_ERR "%s: invalid GPIO value 0x%x", - __func__, gpio); + unsigned int gpio_base; + u32 mask = ASIC3_GPIO_TO_MASK(offset); + struct asic3 *asic; + + asic = container_of(chip, struct asic3, gpio); + gpio_base = ASIC3_GPIO_TO_BASE(offset); + + if (gpio_base > ASIC3_GPIO_D_BASE) { + dev_err(asic->dev, "Invalid base (0x%x) for gpio %d\n", + gpio_base, offset); return -EINVAL; } + + return asic3_read_register(asic, gpio_base + ASIC3_GPIO_STATUS) & mask; } -EXPORT_SYMBOL(asic3_gpio_get_value); -void asic3_gpio_set_value(struct asic3 *asic, unsigned gpio, int val) +static void asic3_gpio_set(struct gpio_chip *chip, + unsigned offset, int value) { - u32 mask = ASIC3_GPIO_bit(gpio); - u32 bitval = 0; - if (val) - bitval = mask; - - switch (gpio >> 4) { - case ASIC3_GPIO_BANK_A: - asic3_set_gpio_a(asic, Out, mask, bitval); - return; - case ASIC3_GPIO_BANK_B: - asic3_set_gpio_b(asic, Out, mask, bitval); - return; - case ASIC3_GPIO_BANK_C: - asic3_set_gpio_c(asic, Out, mask, bitval); - return; - case ASIC3_GPIO_BANK_D: - asic3_set_gpio_d(asic, Out, mask, bitval); - return; - default: - printk(KERN_ERR "%s: invalid GPIO value 0x%x", - __func__, gpio); + u32 mask, out_reg; + unsigned int gpio_base; + unsigned long flags; + struct asic3 *asic; + + asic = container_of(chip, struct asic3, gpio); + gpio_base = ASIC3_GPIO_TO_BASE(offset); + + if (gpio_base > ASIC3_GPIO_D_BASE) { + dev_err(asic->dev, "Invalid base (0x%x) for gpio %d\n", + gpio_base, offset); return; } + + mask = ASIC3_GPIO_TO_MASK(offset); + + spin_lock_irqsave(&asic->lock, flags); + + out_reg = asic3_read_register(asic, gpio_base + ASIC3_GPIO_OUT); + + if (value) + out_reg |= mask; + else + out_reg &= ~mask; + + asic3_write_register(asic, gpio_base + ASIC3_GPIO_OUT, out_reg); + + spin_unlock_irqrestore(&asic->lock, flags); + + return; } -EXPORT_SYMBOL(asic3_gpio_set_value); -static int asic3_gpio_probe(struct platform_device *pdev) +static __init int asic3_gpio_probe(struct platform_device *pdev, + u16 *gpio_config, int num) { - struct asic3_platform_data *pdata = pdev->dev.platform_data; struct asic3 *asic = platform_get_drvdata(pdev); + u16 alt_reg[ASIC3_NUM_GPIO_BANKS]; + u16 out_reg[ASIC3_NUM_GPIO_BANKS]; + u16 dir_reg[ASIC3_NUM_GPIO_BANKS]; + int i; + + memzero(alt_reg, ASIC3_NUM_GPIO_BANKS * sizeof(u16)); + memzero(out_reg, ASIC3_NUM_GPIO_BANKS * sizeof(u16)); + memzero(dir_reg, ASIC3_NUM_GPIO_BANKS * sizeof(u16)); + + /* Enable all GPIOs */ + asic3_write_register(asic, ASIC3_GPIO_OFFSET(A, MASK), 0xffff); + asic3_write_register(asic, ASIC3_GPIO_OFFSET(B, MASK), 0xffff); + asic3_write_register(asic, ASIC3_GPIO_OFFSET(C, MASK), 0xffff); + asic3_write_register(asic, ASIC3_GPIO_OFFSET(D, MASK), 0xffff); + + for (i = 0; i < num; i++) { + u8 alt, pin, dir, init, bank_num, bit_num; + u16 config = gpio_config[i]; + + pin = ASIC3_CONFIG_GPIO_PIN(config); + alt = ASIC3_CONFIG_GPIO_ALT(config); + dir = ASIC3_CONFIG_GPIO_DIR(config); + init = ASIC3_CONFIG_GPIO_INIT(config); + + bank_num = ASIC3_GPIO_TO_BANK(pin); + bit_num = ASIC3_GPIO_TO_BIT(pin); + + alt_reg[bank_num] |= (alt << bit_num); + out_reg[bank_num] |= (init << bit_num); + dir_reg[bank_num] |= (dir << bit_num); + } - asic3_write_register(asic, ASIC3_GPIO_OFFSET(A, Mask), 0xffff); - asic3_write_register(asic, ASIC3_GPIO_OFFSET(B, Mask), 0xffff); - asic3_write_register(asic, ASIC3_GPIO_OFFSET(C, Mask), 0xffff); - asic3_write_register(asic, ASIC3_GPIO_OFFSET(D, Mask), 0xffff); - - asic3_set_gpio_a(asic, SleepMask, 0xffff, 0xffff); - asic3_set_gpio_b(asic, SleepMask, 0xffff, 0xffff); - asic3_set_gpio_c(asic, SleepMask, 0xffff, 0xffff); - asic3_set_gpio_d(asic, SleepMask, 0xffff, 0xffff); - - if (pdata) { - asic3_set_gpio_banks(asic, Out, 0xffff, pdata, init); - asic3_set_gpio_banks(asic, Direction, 0xffff, pdata, dir); - asic3_set_gpio_banks(asic, SleepMask, 0xffff, pdata, - sleep_mask); - asic3_set_gpio_banks(asic, SleepOut, 0xffff, pdata, sleep_out); - asic3_set_gpio_banks(asic, BattFaultOut, 0xffff, pdata, - batt_fault_out); - asic3_set_gpio_banks(asic, SleepConf, 0xffff, pdata, - sleep_conf); - asic3_set_gpio_banks(asic, AltFunction, 0xffff, pdata, - alt_function); + for (i = 0; i < ASIC3_NUM_GPIO_BANKS; i++) { + asic3_write_register(asic, + ASIC3_BANK_TO_BASE(i) + + ASIC3_GPIO_DIRECTION, + dir_reg[i]); + asic3_write_register(asic, + ASIC3_BANK_TO_BASE(i) + ASIC3_GPIO_OUT, + out_reg[i]); + asic3_write_register(asic, + ASIC3_BANK_TO_BASE(i) + + ASIC3_GPIO_ALT_FUNCTION, + alt_reg[i]); } - return 0; + return gpiochip_add(&asic->gpio); } -static void asic3_gpio_remove(struct platform_device *pdev) +static int asic3_gpio_remove(struct platform_device *pdev) { - return; + struct asic3 *asic = platform_get_drvdata(pdev); + + return gpiochip_remove(&asic->gpio); } /* Core */ -static int asic3_probe(struct platform_device *pdev) +static int __init asic3_probe(struct platform_device *pdev) { struct asic3_platform_data *pdata = pdev->dev.platform_data; struct asic3 *asic; struct resource *mem; unsigned long clksel; - int ret; + int ret = 0; asic = kzalloc(sizeof(struct asic3), GFP_KERNEL); - if (!asic) + if (asic == NULL) { + printk(KERN_ERR "kzalloc failed\n"); return -ENOMEM; + } spin_lock_init(&asic->lock); platform_set_drvdata(pdev, asic); @@ -501,49 +548,58 @@ static int asic3_probe(struct platform_device *pdev) mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!mem) { ret = -ENOMEM; - printk(KERN_ERR "asic3: no MEM resource\n"); - goto err_out_1; + dev_err(asic->dev, "no MEM resource\n"); + goto out_free; } - asic->mapping = ioremap(mem->start, PAGE_SIZE); + map_size = mem->end - mem->start + 1; + asic->mapping = ioremap(mem->start, map_size); if (!asic->mapping) { ret = -ENOMEM; - printk(KERN_ERR "asic3: couldn't ioremap\n"); - goto err_out_1; + dev_err(asic->dev, "Couldn't ioremap\n"); + goto out_free; } asic->irq_base = pdata->irq_base; - if (pdata && pdata->bus_shift) - asic->bus_shift = 2 - pdata->bus_shift; - else - asic->bus_shift = 0; + /* calculate bus shift from mem resource */ + asic->bus_shift = 2 - (map_size >> 12); clksel = 0; asic3_write_register(asic, ASIC3_OFFSET(CLOCK, SEL), clksel); ret = asic3_irq_probe(pdev); if (ret < 0) { - printk(KERN_ERR "asic3: couldn't probe IRQs\n"); - goto err_out_2; + dev_err(asic->dev, "Couldn't probe IRQs\n"); + goto out_unmap; } - asic3_gpio_probe(pdev); - if (pdata->children) { - int i; - for (i = 0; i < pdata->n_children; i++) { - pdata->children[i]->dev.parent = &pdev->dev; - platform_device_register(pdata->children[i]); - } + asic->gpio.base = pdata->gpio_base; + asic->gpio.ngpio = ASIC3_NUM_GPIOS; + asic->gpio.get = asic3_gpio_get; + asic->gpio.set = asic3_gpio_set; + asic->gpio.direction_input = asic3_gpio_direction_input; + asic->gpio.direction_output = asic3_gpio_direction_output; + + ret = asic3_gpio_probe(pdev, + pdata->gpio_config, + pdata->gpio_config_num); + if (ret < 0) { + dev_err(asic->dev, "GPIO probe failed\n"); + goto out_irq; } - printk(KERN_INFO "ASIC3 Core driver\n"); + dev_info(asic->dev, "ASIC3 Core driver\n"); return 0; - err_out_2: + out_irq: + asic3_irq_remove(pdev); + + out_unmap: iounmap(asic->mapping); - err_out_1: + + out_free: kfree(asic); return ret; @@ -551,9 +607,12 @@ static int asic3_probe(struct platform_device *pdev) static int asic3_remove(struct platform_device *pdev) { + int ret; struct asic3 *asic = platform_get_drvdata(pdev); - asic3_gpio_remove(pdev); + ret = asic3_gpio_remove(pdev); + if (ret < 0) + return ret; asic3_irq_remove(pdev); asic3_write_register(asic, ASIC3_OFFSET(CLOCK, SEL), 0); @@ -573,7 +632,6 @@ static struct platform_driver asic3_device_driver = { .driver = { .name = "asic3", }, - .probe = asic3_probe, .remove = __devexit_p(asic3_remove), .shutdown = asic3_shutdown, }; @@ -581,7 +639,7 @@ static struct platform_driver asic3_device_driver = { static int __init asic3_init(void) { int retval = 0; - retval = platform_driver_register(&asic3_device_driver); + retval = platform_driver_probe(&asic3_device_driver, asic3_probe); return retval; } diff --git a/drivers/net/3c503.c b/drivers/net/3c503.c index 9c23336750e2..900b0ffdcc68 100644 --- a/drivers/net/3c503.c +++ b/drivers/net/3c503.c @@ -149,7 +149,7 @@ el2_pio_probe(struct net_device *dev) #ifndef MODULE struct net_device * __init el2_probe(int unit) { - struct net_device *dev = alloc_ei_netdev(); + struct net_device *dev = alloc_eip_netdev(); int err; if (!dev) @@ -340,7 +340,7 @@ el2_probe1(struct net_device *dev, int ioaddr) dev->stop = &el2_close; dev->ethtool_ops = &netdev_ethtool_ops; #ifdef CONFIG_NET_POLL_CONTROLLER - dev->poll_controller = ei_poll; + dev->poll_controller = eip_poll; #endif retval = register_netdev(dev); @@ -386,7 +386,7 @@ el2_open(struct net_device *dev) outb_p(0x00, E33G_IDCFR); if (*irqp == probe_irq_off(cookie) /* It's a good IRQ line! */ && ((retval = request_irq(dev->irq = *irqp, - ei_interrupt, 0, dev->name, dev)) == 0)) + eip_interrupt, 0, dev->name, dev)) == 0)) break; } } while (*++irqp); @@ -395,13 +395,13 @@ el2_open(struct net_device *dev) return retval; } } else { - if ((retval = request_irq(dev->irq, ei_interrupt, 0, dev->name, dev))) { + if ((retval = request_irq(dev->irq, eip_interrupt, 0, dev->name, dev))) { return retval; } } el2_init_card(dev); - ei_open(dev); + eip_open(dev); return 0; } @@ -412,7 +412,7 @@ el2_close(struct net_device *dev) dev->irq = ei_status.saved_irq; outb(EGACFR_IRQOFF, E33G_GACFR); /* disable interrupts. */ - ei_close(dev); + eip_close(dev); return 0; } @@ -698,7 +698,7 @@ init_module(void) if (this_dev != 0) break; /* only autoprobe 1st one */ printk(KERN_NOTICE "3c503.c: Presently autoprobing (not recommended) for a single card.\n"); } - dev = alloc_ei_netdev(); + dev = alloc_eip_netdev(); if (!dev) break; dev->irq = irq[this_dev]; diff --git a/drivers/net/3c515.c b/drivers/net/3c515.c index 105a8c7ca7e9..e4e3241628d6 100644 --- a/drivers/net/3c515.c +++ b/drivers/net/3c515.c @@ -572,12 +572,16 @@ static int corkscrew_setup(struct net_device *dev, int ioaddr, int irq; DECLARE_MAC_BUF(mac); +#ifdef __ISAPNP__ if (idev) { irq = pnp_irq(idev, 0); vp->dev = &idev->dev; } else { irq = inw(ioaddr + 0x2002) & 15; } +#else + irq = inw(ioaddr + 0x2002) & 15; +#endif dev->base_addr = ioaddr; dev->irq = irq; diff --git a/drivers/net/3c523.c b/drivers/net/3c523.c index 239fc42fb8df..dc6e474229b1 100644 --- a/drivers/net/3c523.c +++ b/drivers/net/3c523.c @@ -202,7 +202,6 @@ static void elmc_xmt_int(struct net_device *dev); static void elmc_rnr_int(struct net_device *dev); struct priv { - struct net_device_stats stats; unsigned long base; char *memtop; unsigned long mapped_start; /* Start of ioremap */ @@ -989,18 +988,18 @@ static void elmc_rcv_int(struct net_device *dev) skb->protocol = eth_type_trans(skb, dev); netif_rx(skb); dev->last_rx = jiffies; - p->stats.rx_packets++; - p->stats.rx_bytes += totlen; + dev->stats.rx_packets++; + dev->stats.rx_bytes += totlen; } else { - p->stats.rx_dropped++; + dev->stats.rx_dropped++; } } else { printk(KERN_WARNING "%s: received oversized frame.\n", dev->name); - p->stats.rx_dropped++; + 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); - p->stats.rx_errors++; + dev->stats.rx_errors++; } p->rfd_top->status = 0; p->rfd_top->last = RFD_SUSP; @@ -1018,7 +1017,7 @@ static void elmc_rnr_int(struct net_device *dev) { struct priv *p = (struct priv *) dev->priv; - p->stats.rx_errors++; + dev->stats.rx_errors++; WAIT_4_SCB_CMD(); /* wait for the last cmd */ p->scb->cmd = RUC_ABORT; /* usually the RU is in the 'no resource'-state .. abort it now. */ @@ -1046,24 +1045,24 @@ static void elmc_xmt_int(struct net_device *dev) printk(KERN_WARNING "%s: strange .. xmit-int without a 'COMPLETE'\n", dev->name); } if (status & STAT_OK) { - p->stats.tx_packets++; - p->stats.collisions += (status & TCMD_MAXCOLLMASK); + dev->stats.tx_packets++; + dev->stats.collisions += (status & TCMD_MAXCOLLMASK); } else { - p->stats.tx_errors++; + dev->stats.tx_errors++; if (status & TCMD_LATECOLL) { printk(KERN_WARNING "%s: late collision detected.\n", dev->name); - p->stats.collisions++; + dev->stats.collisions++; } else if (status & TCMD_NOCARRIER) { - p->stats.tx_carrier_errors++; + dev->stats.tx_carrier_errors++; printk(KERN_WARNING "%s: no carrier detected.\n", dev->name); } else if (status & TCMD_LOSTCTS) { printk(KERN_WARNING "%s: loss of CTS detected.\n", dev->name); } else if (status & TCMD_UNDERRUN) { - p->stats.tx_fifo_errors++; + dev->stats.tx_fifo_errors++; printk(KERN_WARNING "%s: DMA underrun detected.\n", dev->name); } else if (status & TCMD_MAXCOLL) { printk(KERN_WARNING "%s: Max. collisions exceeded.\n", dev->name); - p->stats.collisions += 16; + dev->stats.collisions += 16; } } @@ -1215,12 +1214,12 @@ static struct net_device_stats *elmc_get_stats(struct net_device *dev) ovrn = p->scb->ovrn_errs; p->scb->ovrn_errs -= ovrn; - p->stats.rx_crc_errors += crc; - p->stats.rx_fifo_errors += ovrn; - p->stats.rx_frame_errors += aln; - p->stats.rx_dropped += rsc; + dev->stats.rx_crc_errors += crc; + dev->stats.rx_fifo_errors += ovrn; + dev->stats.rx_frame_errors += aln; + dev->stats.rx_dropped += rsc; - return &p->stats; + return &dev->stats; } /******************************************************** diff --git a/drivers/net/3c527.c b/drivers/net/3c527.c index fae295b6809c..6aca0c640f13 100644 --- a/drivers/net/3c527.c +++ b/drivers/net/3c527.c @@ -158,7 +158,6 @@ struct mc32_local int slot; u32 base; - struct net_device_stats net_stats; volatile struct mc32_mailbox *rx_box; volatile struct mc32_mailbox *tx_box; volatile struct mc32_mailbox *exec_box; @@ -1093,24 +1092,24 @@ static void mc32_update_stats(struct net_device *dev) u32 rx_errors=0; - rx_errors+=lp->net_stats.rx_crc_errors +=st->rx_crc_errors; + rx_errors+=dev->stats.rx_crc_errors +=st->rx_crc_errors; st->rx_crc_errors=0; - rx_errors+=lp->net_stats.rx_fifo_errors +=st->rx_overrun_errors; + rx_errors+=dev->stats.rx_fifo_errors +=st->rx_overrun_errors; st->rx_overrun_errors=0; - rx_errors+=lp->net_stats.rx_frame_errors +=st->rx_alignment_errors; + rx_errors+=dev->stats.rx_frame_errors +=st->rx_alignment_errors; st->rx_alignment_errors=0; - rx_errors+=lp->net_stats.rx_length_errors+=st->rx_tooshort_errors; + rx_errors+=dev->stats.rx_length_errors+=st->rx_tooshort_errors; st->rx_tooshort_errors=0; - rx_errors+=lp->net_stats.rx_missed_errors+=st->rx_outofresource_errors; + rx_errors+=dev->stats.rx_missed_errors+=st->rx_outofresource_errors; st->rx_outofresource_errors=0; - lp->net_stats.rx_errors=rx_errors; + dev->stats.rx_errors=rx_errors; /* Number of packets which saw one collision */ - lp->net_stats.collisions+=st->dataC[10]; + dev->stats.collisions+=st->dataC[10]; st->dataC[10]=0; /* Number of packets which saw 2--15 collisions */ - lp->net_stats.collisions+=st->dataC[11]; + dev->stats.collisions+=st->dataC[11]; st->dataC[11]=0; } @@ -1178,7 +1177,7 @@ static void mc32_rx_ring(struct net_device *dev) skb=dev_alloc_skb(length+2); if(skb==NULL) { - lp->net_stats.rx_dropped++; + dev->stats.rx_dropped++; goto dropped; } @@ -1189,8 +1188,8 @@ static void mc32_rx_ring(struct net_device *dev) skb->protocol=eth_type_trans(skb,dev); dev->last_rx = jiffies; - lp->net_stats.rx_packets++; - lp->net_stats.rx_bytes += length; + dev->stats.rx_packets++; + dev->stats.rx_bytes += length; netif_rx(skb); } @@ -1253,34 +1252,34 @@ static void mc32_tx_ring(struct net_device *dev) /* Not COMPLETED */ break; } - lp->net_stats.tx_packets++; + dev->stats.tx_packets++; if(!(np->status & (1<<6))) /* Not COMPLETED_OK */ { - lp->net_stats.tx_errors++; + dev->stats.tx_errors++; switch(np->status&0x0F) { case 1: - lp->net_stats.tx_aborted_errors++; + dev->stats.tx_aborted_errors++; break; /* Max collisions */ case 2: - lp->net_stats.tx_fifo_errors++; + dev->stats.tx_fifo_errors++; break; case 3: - lp->net_stats.tx_carrier_errors++; + dev->stats.tx_carrier_errors++; break; case 4: - lp->net_stats.tx_window_errors++; + dev->stats.tx_window_errors++; break; /* CTS Lost */ case 5: - lp->net_stats.tx_aborted_errors++; + dev->stats.tx_aborted_errors++; break; /* Transmit timeout */ } } /* Packets are sent in order - this is basically a FIFO queue of buffers matching the card ring */ - lp->net_stats.tx_bytes+=lp->tx_ring[t].skb->len; + dev->stats.tx_bytes+=lp->tx_ring[t].skb->len; dev_kfree_skb_irq(lp->tx_ring[t].skb); lp->tx_ring[t].skb=NULL; atomic_inc(&lp->tx_count); @@ -1367,7 +1366,7 @@ static irqreturn_t mc32_interrupt(int irq, void *dev_id) case 6: /* Out of RX buffers stat */ /* Must restart rx */ - lp->net_stats.rx_dropped++; + dev->stats.rx_dropped++; mc32_rx_ring(dev); mc32_start_transceiver(dev); break; @@ -1489,10 +1488,8 @@ static int mc32_close(struct net_device *dev) static struct net_device_stats *mc32_get_stats(struct net_device *dev) { - struct mc32_local *lp = netdev_priv(dev); - mc32_update_stats(dev); - return &lp->net_stats; + return &dev->stats; } diff --git a/drivers/net/8139cp.c b/drivers/net/8139cp.c index a453eda834d5..6011d6fabef0 100644 --- a/drivers/net/8139cp.c +++ b/drivers/net/8139cp.c @@ -340,7 +340,6 @@ struct cp_private { u32 rx_config; u16 cpcmd; - struct net_device_stats net_stats; struct cp_extra_stats cp_stats; unsigned rx_head ____cacheline_aligned; @@ -457,8 +456,8 @@ static inline void cp_rx_skb (struct cp_private *cp, struct sk_buff *skb, { skb->protocol = eth_type_trans (skb, cp->dev); - cp->net_stats.rx_packets++; - cp->net_stats.rx_bytes += skb->len; + cp->dev->stats.rx_packets++; + cp->dev->stats.rx_bytes += skb->len; cp->dev->last_rx = jiffies; #if CP_VLAN_TAG_USED @@ -477,17 +476,17 @@ static void cp_rx_err_acct (struct cp_private *cp, unsigned rx_tail, printk (KERN_DEBUG "%s: rx err, slot %d status 0x%x len %d\n", cp->dev->name, rx_tail, status, len); - cp->net_stats.rx_errors++; + cp->dev->stats.rx_errors++; if (status & RxErrFrame) - cp->net_stats.rx_frame_errors++; + cp->dev->stats.rx_frame_errors++; if (status & RxErrCRC) - cp->net_stats.rx_crc_errors++; + cp->dev->stats.rx_crc_errors++; if ((status & RxErrRunt) || (status & RxErrLong)) - cp->net_stats.rx_length_errors++; + cp->dev->stats.rx_length_errors++; if ((status & (FirstFrag | LastFrag)) != (FirstFrag | LastFrag)) - cp->net_stats.rx_length_errors++; + cp->dev->stats.rx_length_errors++; if (status & RxErrFIFO) - cp->net_stats.rx_fifo_errors++; + cp->dev->stats.rx_fifo_errors++; } static inline unsigned int cp_rx_csum_ok (u32 status) @@ -539,7 +538,7 @@ rx_status_loop: * that RX fragments are never encountered */ cp_rx_err_acct(cp, rx_tail, status, len); - cp->net_stats.rx_dropped++; + dev->stats.rx_dropped++; cp->cp_stats.rx_frags++; goto rx_next; } @@ -556,7 +555,7 @@ rx_status_loop: buflen = cp->rx_buf_sz + RX_OFFSET; new_skb = dev_alloc_skb (buflen); if (!new_skb) { - cp->net_stats.rx_dropped++; + dev->stats.rx_dropped++; goto rx_next; } @@ -710,20 +709,20 @@ static void cp_tx (struct cp_private *cp) if (netif_msg_tx_err(cp)) printk(KERN_DEBUG "%s: tx err, status 0x%x\n", cp->dev->name, status); - cp->net_stats.tx_errors++; + cp->dev->stats.tx_errors++; if (status & TxOWC) - cp->net_stats.tx_window_errors++; + cp->dev->stats.tx_window_errors++; if (status & TxMaxCol) - cp->net_stats.tx_aborted_errors++; + cp->dev->stats.tx_aborted_errors++; if (status & TxLinkFail) - cp->net_stats.tx_carrier_errors++; + cp->dev->stats.tx_carrier_errors++; if (status & TxFIFOUnder) - cp->net_stats.tx_fifo_errors++; + cp->dev->stats.tx_fifo_errors++; } else { - cp->net_stats.collisions += + cp->dev->stats.collisions += ((status >> TxColCntShift) & TxColCntMask); - cp->net_stats.tx_packets++; - cp->net_stats.tx_bytes += skb->len; + 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); } @@ -956,7 +955,7 @@ static void cp_set_rx_mode (struct net_device *dev) static void __cp_get_stats(struct cp_private *cp) { /* only lower 24 bits valid; write any value to clear */ - cp->net_stats.rx_missed_errors += (cpr32 (RxMissed) & 0xffffff); + cp->dev->stats.rx_missed_errors += (cpr32 (RxMissed) & 0xffffff); cpw32 (RxMissed, 0); } @@ -971,7 +970,7 @@ static struct net_device_stats *cp_get_stats(struct net_device *dev) __cp_get_stats(cp); spin_unlock_irqrestore(&cp->lock, flags); - return &cp->net_stats; + return &dev->stats; } static void cp_stop_hw (struct cp_private *cp) @@ -1142,7 +1141,7 @@ static void cp_clean_rings (struct cp_private *cp) PCI_DMA_TODEVICE); if (le32_to_cpu(desc->opts1) & LastFrag) dev_kfree_skb(skb); - cp->net_stats.tx_dropped++; + cp->dev->stats.tx_dropped++; } } @@ -1214,7 +1213,6 @@ static int cp_close (struct net_device *dev) spin_unlock_irqrestore(&cp->lock, flags); - synchronize_irq(dev->irq); free_irq(dev->irq, dev); cp_free_rings(cp); diff --git a/drivers/net/8139too.c b/drivers/net/8139too.c index 53bd903d2321..75317a14ad1c 100644 --- a/drivers/net/8139too.c +++ b/drivers/net/8139too.c @@ -107,8 +107,8 @@ #include <linux/mii.h> #include <linux/completion.h> #include <linux/crc32.h> -#include <asm/io.h> -#include <asm/uaccess.h> +#include <linux/io.h> +#include <linux/uaccess.h> #include <asm/irq.h> #define RTL8139_DRIVER_NAME DRV_NAME " Fast Ethernet driver " DRV_VERSION @@ -134,7 +134,7 @@ #if RTL8139_DEBUG /* note: prints function name for you */ -# define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __FUNCTION__ , ## args) +# define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __func__ , ## args) #else # define DPRINTK(fmt, args...) #endif @@ -145,7 +145,7 @@ # define assert(expr) \ if(unlikely(!(expr))) { \ printk(KERN_ERR "Assertion failed! %s,%s,%s,line=%d\n", \ - #expr,__FILE__,__FUNCTION__,__LINE__); \ + #expr, __FILE__, __func__, __LINE__); \ } #endif @@ -219,7 +219,7 @@ enum { #define RTL8139B_IO_SIZE 256 #define RTL8129_CAPS HAS_MII_XCVR -#define RTL8139_CAPS HAS_CHIP_XCVR|HAS_LNK_CHNG +#define RTL8139_CAPS (HAS_CHIP_XCVR|HAS_LNK_CHNG) typedef enum { RTL8139 = 0, @@ -574,7 +574,6 @@ struct rtl8139_private { u32 msg_enable; struct napi_struct napi; struct net_device *dev; - struct net_device_stats stats; unsigned char *rx_ring; unsigned int cur_rx; /* RX buf index of next pkt */ @@ -1711,7 +1710,7 @@ static int rtl8139_start_xmit (struct sk_buff *skb, struct net_device *dev) dev_kfree_skb(skb); } else { dev_kfree_skb(skb); - tp->stats.tx_dropped++; + dev->stats.tx_dropped++; return 0; } @@ -1762,27 +1761,27 @@ static void rtl8139_tx_interrupt (struct net_device *dev, if (netif_msg_tx_err(tp)) printk(KERN_DEBUG "%s: Transmit error, Tx status %8.8x.\n", dev->name, txstatus); - tp->stats.tx_errors++; + dev->stats.tx_errors++; if (txstatus & TxAborted) { - tp->stats.tx_aborted_errors++; + dev->stats.tx_aborted_errors++; RTL_W32 (TxConfig, TxClearAbt); RTL_W16 (IntrStatus, TxErr); wmb(); } if (txstatus & TxCarrierLost) - tp->stats.tx_carrier_errors++; + dev->stats.tx_carrier_errors++; if (txstatus & TxOutOfWindow) - tp->stats.tx_window_errors++; + dev->stats.tx_window_errors++; } else { if (txstatus & TxUnderrun) { /* Add 64 to the Tx FIFO threshold. */ if (tp->tx_flag < 0x00300000) tp->tx_flag += 0x00020000; - tp->stats.tx_fifo_errors++; + dev->stats.tx_fifo_errors++; } - tp->stats.collisions += (txstatus >> 24) & 15; - tp->stats.tx_bytes += txstatus & 0x7ff; - tp->stats.tx_packets++; + dev->stats.collisions += (txstatus >> 24) & 15; + dev->stats.tx_bytes += txstatus & 0x7ff; + dev->stats.tx_packets++; } dirty_tx++; @@ -1818,7 +1817,7 @@ static void rtl8139_rx_err (u32 rx_status, struct net_device *dev, if (netif_msg_rx_err (tp)) printk(KERN_DEBUG "%s: Ethernet frame had errors, status %8.8x.\n", dev->name, rx_status); - tp->stats.rx_errors++; + dev->stats.rx_errors++; if (!(rx_status & RxStatusOK)) { if (rx_status & RxTooLong) { DPRINTK ("%s: Oversized Ethernet frame, status %4.4x!\n", @@ -1826,11 +1825,11 @@ static void rtl8139_rx_err (u32 rx_status, struct net_device *dev, /* A.C.: The chip hangs here. */ } if (rx_status & (RxBadSymbol | RxBadAlign)) - tp->stats.rx_frame_errors++; + dev->stats.rx_frame_errors++; if (rx_status & (RxRunt | RxTooLong)) - tp->stats.rx_length_errors++; + dev->stats.rx_length_errors++; if (rx_status & RxCRCErr) - tp->stats.rx_crc_errors++; + dev->stats.rx_crc_errors++; } else { tp->xstats.rx_lost_in_ring++; } @@ -1890,7 +1889,7 @@ static void rtl8139_rx_err (u32 rx_status, struct net_device *dev, } #if RX_BUF_IDX == 3 -static __inline__ void wrap_copy(struct sk_buff *skb, const unsigned char *ring, +static inline void wrap_copy(struct sk_buff *skb, const unsigned char *ring, u32 offset, unsigned int size) { u32 left = RX_BUF_LEN - offset; @@ -1913,9 +1912,9 @@ static void rtl8139_isr_ack(struct rtl8139_private *tp) /* Clear out errors and receive interrupts */ if (likely(status != 0)) { if (unlikely(status & (RxFIFOOver | RxOverflow))) { - tp->stats.rx_errors++; + tp->dev->stats.rx_errors++; if (status & RxFIFOOver) - tp->stats.rx_fifo_errors++; + tp->dev->stats.rx_fifo_errors++; } RTL_W16_F (IntrStatus, RxAckBits); } @@ -2016,8 +2015,8 @@ no_early_rx: skb->protocol = eth_type_trans (skb, dev); dev->last_rx = jiffies; - tp->stats.rx_bytes += pkt_size; - tp->stats.rx_packets++; + dev->stats.rx_bytes += pkt_size; + dev->stats.rx_packets++; netif_receive_skb (skb); } else { @@ -2025,7 +2024,7 @@ no_early_rx: printk (KERN_WARNING "%s: Memory squeeze, dropping packet.\n", dev->name); - tp->stats.rx_dropped++; + dev->stats.rx_dropped++; } received++; @@ -2072,7 +2071,7 @@ static void rtl8139_weird_interrupt (struct net_device *dev, assert (ioaddr != NULL); /* Update the error count. */ - tp->stats.rx_missed_errors += RTL_R32 (RxMissed); + dev->stats.rx_missed_errors += RTL_R32 (RxMissed); RTL_W32 (RxMissed, 0); if ((status & RxUnderrun) && link_changed && @@ -2082,12 +2081,12 @@ static void rtl8139_weird_interrupt (struct net_device *dev, } if (status & (RxUnderrun | RxErr)) - tp->stats.rx_errors++; + dev->stats.rx_errors++; if (status & PCSTimeout) - tp->stats.rx_length_errors++; + dev->stats.rx_length_errors++; if (status & RxUnderrun) - tp->stats.rx_fifo_errors++; + dev->stats.rx_fifo_errors++; if (status & PCIErr) { u16 pci_cmd_status; pci_read_config_word (tp->pci_dev, PCI_STATUS, &pci_cmd_status); @@ -2227,12 +2226,11 @@ static int rtl8139_close (struct net_device *dev) RTL_W16 (IntrMask, 0); /* Update the error counts. */ - tp->stats.rx_missed_errors += RTL_R32 (RxMissed); + dev->stats.rx_missed_errors += RTL_R32 (RxMissed); RTL_W32 (RxMissed, 0); spin_unlock_irqrestore (&tp->lock, flags); - synchronize_irq (dev->irq); /* racy, but that's ok here */ free_irq (dev->irq, dev); rtl8139_tx_clear (tp); @@ -2472,12 +2470,12 @@ static struct net_device_stats *rtl8139_get_stats (struct net_device *dev) if (netif_running(dev)) { spin_lock_irqsave (&tp->lock, flags); - tp->stats.rx_missed_errors += RTL_R32 (RxMissed); + dev->stats.rx_missed_errors += RTL_R32 (RxMissed); RTL_W32 (RxMissed, 0); spin_unlock_irqrestore (&tp->lock, flags); } - return &tp->stats; + return &dev->stats; } /* Set or clear the multicast filter for this adaptor. @@ -2561,7 +2559,7 @@ static int rtl8139_suspend (struct pci_dev *pdev, pm_message_t state) RTL_W8 (ChipCmd, 0); /* Update the error counts. */ - tp->stats.rx_missed_errors += RTL_R32 (RxMissed); + dev->stats.rx_missed_errors += RTL_R32 (RxMissed); RTL_W32 (RxMissed, 0); spin_unlock_irqrestore (&tp->lock, flags); diff --git a/drivers/net/8390.h b/drivers/net/8390.h index 04ddec0f4c61..8e209f5e7c11 100644 --- a/drivers/net/8390.h +++ b/drivers/net/8390.h @@ -30,8 +30,10 @@ extern int ei_debug; #ifdef CONFIG_NET_POLL_CONTROLLER extern void ei_poll(struct net_device *dev); +extern void eip_poll(struct net_device *dev); #endif +/* Without I/O delay - non ISA or later chips */ extern void NS8390_init(struct net_device *dev, int startp); extern int ei_open(struct net_device *dev); extern int ei_close(struct net_device *dev); @@ -42,6 +44,17 @@ static inline struct net_device *alloc_ei_netdev(void) return __alloc_ei_netdev(0); } +/* With I/O delay form */ +extern void NS8390p_init(struct net_device *dev, int startp); +extern int eip_open(struct net_device *dev); +extern int eip_close(struct net_device *dev); +extern irqreturn_t eip_interrupt(int irq, void *dev_id); +extern struct net_device *__alloc_eip_netdev(int size); +static inline struct net_device *alloc_eip_netdev(void) +{ + return __alloc_eip_netdev(0); +} + /* You have one of these per-board */ struct ei_device { const char *name; @@ -69,7 +82,6 @@ struct ei_device { unsigned char reg0; /* Register '0' in a WD8013 */ unsigned char reg5; /* Register '5' in a WD8013 */ unsigned char saved_irq; /* Original dev->irq value. */ - struct net_device_stats stat; /* The new statistics table. */ u32 *reg_offset; /* Register mapping table */ spinlock_t page_lock; /* Page register locks */ unsigned long priv; /* Private field to store bus IDs etc. */ @@ -116,13 +128,14 @@ struct ei_device { /* * Only generate indirect loads given a machine that needs them. * - removed AMIGA_PCMCIA from this list, handled as ISA io now + * - the _p for generates no delay by default 8390p.c overrides this. */ #ifndef ei_inb #define ei_inb(_p) inb(_p) #define ei_outb(_v,_p) outb(_v,_p) -#define ei_inb_p(_p) inb_p(_p) -#define ei_outb_p(_v,_p) outb_p(_v,_p) +#define ei_inb_p(_p) inb(_p) +#define ei_outb_p(_v,_p) outb(_v,_p) #endif #ifndef EI_SHIFT diff --git a/drivers/net/8390p.c b/drivers/net/8390p.c new file mode 100644 index 000000000000..71f19884c4b1 --- /dev/null +++ b/drivers/net/8390p.c @@ -0,0 +1,66 @@ +/* 8390 core for ISA devices needing bus delays */ + +static const char version[] = + "8390p.c:v1.10cvs 9/23/94 Donald Becker (becker@cesdis.gsfc.nasa.gov)\n"; + +#define ei_inb(_p) inb(_p) +#define ei_outb(_v,_p) outb(_v,_p) +#define ei_inb_p(_p) inb_p(_p) +#define ei_outb_p(_v,_p) outb_p(_v,_p) + +#include "lib8390.c" + +int eip_open(struct net_device *dev) +{ + return __ei_open(dev); +} + +int eip_close(struct net_device *dev) +{ + return __ei_close(dev); +} + +irqreturn_t eip_interrupt(int irq, void *dev_id) +{ + return __ei_interrupt(irq, dev_id); +} + +#ifdef CONFIG_NET_POLL_CONTROLLER +void eip_poll(struct net_device *dev) +{ + __ei_poll(dev); +} +#endif + +struct net_device *__alloc_eip_netdev(int size) +{ + return ____alloc_ei_netdev(size); +} + +void NS8390p_init(struct net_device *dev, int startp) +{ + return __NS8390_init(dev, startp); +} + +EXPORT_SYMBOL(eip_open); +EXPORT_SYMBOL(eip_close); +EXPORT_SYMBOL(eip_interrupt); +#ifdef CONFIG_NET_POLL_CONTROLLER +EXPORT_SYMBOL(eip_poll); +#endif +EXPORT_SYMBOL(NS8390p_init); +EXPORT_SYMBOL(__alloc_eip_netdev); + +#if defined(MODULE) + +int init_module(void) +{ + return 0; +} + +void cleanup_module(void) +{ +} + +#endif /* MODULE */ +MODULE_LICENSE("GPL"); diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 2683ee32fc11..3e5e64c33e18 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -26,14 +26,6 @@ menuconfig NETDEVICES # that for each of the symbols. if NETDEVICES -config NETDEVICES_MULTIQUEUE - bool "Netdevice multiple hardware queue support" - ---help--- - Say Y here if you want to allow the network stack to use multiple - hardware TX queues on an ethernet device. - - Most people will say N here. - config IFB tristate "Intermediate Functional Block support" depends on NET_CLS_ACT @@ -333,15 +325,6 @@ config APNE To compile this driver as a module, choose M here: the module will be called apne. -config APOLLO_ELPLUS - tristate "Apollo 3c505 support" - depends on APOLLO - help - Say Y or M here if your Apollo has a 3Com 3c505 ISA Ethernet card. - If you don't have one made for Apollos, you can use one from a PC, - except that your Apollo won't be able to boot from it (because the - code in the ROM will be for a PC). - config MAC8390 bool "Macintosh NS 8390 based ethernet cards" depends on MAC @@ -524,6 +507,18 @@ config STNIC If unsure, say N. +config SH_ETH + tristate "Renesas SuperH Ethernet support" + depends on SUPERH && \ + (CPU_SUBTYPE_SH7710 || CPU_SUBTYPE_SH7712) + select CRC32 + select MII + select MDIO_BITBANG + select PHYLIB + help + Renesas SuperH Ethernet device driver. + This driver support SH7710 and SH7712. + config SUNLANCE tristate "Sun LANCE support" depends on SBUS @@ -926,6 +921,23 @@ config DM9000 To compile this driver as a module, choose M here. The module will be called dm9000. +config DM9000_DEBUGLEVEL + int "DM9000 maximum debug level" + depends on DM9000 + default 4 + help + The maximum level of debugging code compiled into the DM9000 + driver. + +config DM9000_FORCE_SIMPLE_PHY_POLL + bool "Force simple NSR based PHY polling" + depends on DM9000 + ---help--- + This configuration forces the DM9000 to use the NSR's LinkStatus + bit to determine if the link is up or down instead of the more + costly MII PHY reads. Note, this will not work if the chip is + operating with an external PHY. + config ENC28J60 tristate "ENC28J60 support" depends on EXPERIMENTAL && SPI && NET_ETHERNET @@ -943,19 +955,11 @@ config ENC28J60_WRITEVERIFY Enable the verify after the buffer write useful for debugging purpose. If unsure, say N. -config DM9000_DEBUGLEVEL - int "DM9000 maximum debug level" - depends on DM9000 - default 4 - help - The maximum level of debugging code compiled into the DM9000 - driver. - config SMC911X tristate "SMSC LAN911[5678] support" select CRC32 select MII - depends on ARCH_PXA || SH_MAGIC_PANEL_R2 + depends on ARCH_PXA || SUPERH help This is a driver for SMSC's LAN911x series of Ethernet chipsets including the new LAN9115, LAN9116, LAN9117, and LAN9118. @@ -1243,7 +1247,6 @@ config IBMVETH To compile this driver as a module, choose M here. The module will be called ibmveth. -source "drivers/net/ibm_emac/Kconfig" source "drivers/net/ibm_newemac/Kconfig" config NET_PCI @@ -1286,20 +1289,6 @@ config AMD8111_ETH To compile this driver as a module, choose M here. The module will be called amd8111e. -config AMD8111E_NAPI - bool "Use RX polling (NAPI)" - depends on AMD8111_ETH - help - NAPI is a new driver API designed to reduce CPU and interrupt load - when the driver is receiving lots of packets from the card. It is - still somewhat experimental and thus not yet enabled by default. - - If your estimated Rx load is 10kpps or more, or if the card will be - deployed on potentially unfriendly networks (e.g. in a firewall), - then say Y here. - - If in doubt, say N. - config ADAPTEC_STARFIRE tristate "Adaptec Starfire/DuraLAN support" depends on NET_PCI && PCI @@ -1314,20 +1303,6 @@ config ADAPTEC_STARFIRE To compile this driver as a module, choose M here: the module will be called starfire. This is recommended. -config ADAPTEC_STARFIRE_NAPI - bool "Use Rx Polling (NAPI) (EXPERIMENTAL)" - depends on ADAPTEC_STARFIRE && EXPERIMENTAL - help - NAPI is a new driver API designed to reduce CPU and interrupt load - when the driver is receiving lots of packets from the card. It is - still somewhat experimental and thus not yet enabled by default. - - If your estimated Rx load is 10kpps or more, or if the card will be - deployed on potentially unfriendly networks (e.g. in a firewall), - then say Y here. - - If in doubt, say N. - config AC3200 tristate "Ansel Communications EISA 3200 support (EXPERIMENTAL)" depends on NET_PCI && (ISA || EISA) && EXPERIMENTAL @@ -1670,7 +1645,7 @@ config SUNDANCE_MMIO config TLAN tristate "TI ThunderLAN support" - depends on NET_PCI && (PCI || EISA) && !64BIT + depends on NET_PCI && (PCI || EISA) ---help--- If you have a PCI Ethernet network card based on the ThunderLAN chip which is supported by this driver, say Y and read the @@ -1710,26 +1685,6 @@ config VIA_RHINE_MMIO If unsure, say Y. -config VIA_RHINE_NAPI - bool "Use Rx Polling (NAPI)" - depends on VIA_RHINE - help - NAPI is a new driver API designed to reduce CPU and interrupt load - when the driver is receiving lots of packets from the card. - - If your estimated Rx load is 10kpps or more, or if the card will be - deployed on potentially unfriendly networks (e.g. in a firewall), - then say Y here. - -config LAN_SAA9730 - bool "Philips SAA9730 Ethernet support" - depends on NET_PCI && PCI && MIPS_ATLAS - help - The SAA9730 is a combined multimedia and peripheral controller used - in thin clients, Internet access terminals, and diskless - workstations. - See <http://www.semiconductors.philips.com/pip/SAA9730_flyer_1>. - config SC92031 tristate "Silan SC92031 PCI Fast Ethernet Adapter driver (EXPERIMENTAL)" depends on NET_PCI && PCI && EXPERIMENTAL @@ -2013,9 +1968,6 @@ config E1000E To compile this driver as a module, choose M here. The module will be called e1000e. -config E1000E_ENABLED - def_bool E1000E != n - config IP1000 tristate "IP1000 Gigabit Ethernet support" depends on PCI && EXPERIMENTAL @@ -2047,6 +1999,15 @@ config IGB To compile this driver as a module, choose M here. The module will be called igb. +config IGB_LRO + bool "Use software LRO" + depends on IGB && INET + select INET_LRO + ---help--- + Say Y here if you want to use large receive offload. + + If in doubt, say N. + source "drivers/net/ixp2000/Kconfig" config MYRI_SBUS @@ -2104,27 +2065,13 @@ config R8169 To compile this driver as a module, choose M here: the module will be called r8169. This is recommended. -config R8169_NAPI - bool "Use Rx Polling (NAPI) (EXPERIMENTAL)" - depends on R8169 && EXPERIMENTAL - help - NAPI is a new driver API designed to reduce CPU and interrupt load - when the driver is receiving lots of packets from the card. It is - still somewhat experimental and thus not yet enabled by default. - - If your estimated Rx load is 10kpps or more, or if the card will be - deployed on potentially unfriendly networks (e.g. in a firewall), - then say Y here. - - If in doubt, say N. - config R8169_VLAN bool "VLAN support" depends on R8169 && VLAN_8021Q ---help--- Say Y here for the r8169 driver to support the functions required by the kernel 802.1Q code. - + If in doubt, say Y. config SB1250_MAC @@ -2227,6 +2174,7 @@ config VIA_VELOCITY config TIGON3 tristate "Broadcom Tigon3 support" depends on PCI + select PHYLIB help This driver supports Broadcom Tigon3 based gigabit Ethernet cards. @@ -2282,6 +2230,19 @@ config GELIC_WIRELESS the driver automatically distinguishes the models, you can safely enable this option even if you have a wireless-less model. +config GELIC_WIRELESS_OLD_PSK_INTERFACE + bool "PS3 Wireless private PSK interface (OBSOLETE)" + depends on GELIC_WIRELESS + help + This option retains the obsolete private interface to pass + the PSK from user space programs to the driver. The PSK + stands for 'Pre Shared Key' and is used for WPA[2]-PSK + (WPA-Personal) environment. + If WPA[2]-PSK is used and you need to use old programs that + support only this old interface, say Y. Otherwise N. + + If unsure, say N. + config GIANFAR tristate "Gianfar Ethernet" depends on FSL_SOC @@ -2291,10 +2252,6 @@ config GIANFAR This driver supports the Gigabit TSEC on the MPC83xx, MPC85xx, and MPC86xx family of chips, and the FEC on the 8540. -config GFAR_NAPI - bool "Use Rx Polling (NAPI)" - depends on GIANFAR - config UCC_GETH tristate "Freescale QE Gigabit Ethernet" depends on QUICC_ENGINE @@ -2303,10 +2260,6 @@ config UCC_GETH This driver supports the Gigabit Ethernet mode of the QUICC Engine, which is available on some Freescale SOCs. -config UGETH_NAPI - bool "Use Rx Polling (NAPI)" - depends on UCC_GETH - config UGETH_MAGIC_PACKET bool "Magic Packet detection support" depends on UCC_GETH @@ -2396,18 +2349,11 @@ config CHELSIO_T1_1G Enables support for Chelsio's gigabit Ethernet PCI cards. If you are using only 10G cards say 'N' here. -config CHELSIO_T1_NAPI - bool "Use Rx Polling (NAPI)" - depends on CHELSIO_T1 - default y - help - NAPI is a driver API designed to reduce CPU and interrupt load - when the driver is receiving lots of packets from the card. - config CHELSIO_T3 tristate "Chelsio Communications T3 10Gb Ethernet support" - depends on PCI + depends on PCI && INET select FW_LOADER + select INET_LRO help This driver supports Chelsio T3-based gigabit and 10Gb Ethernet adapters. @@ -2435,7 +2381,8 @@ config EHEA config IXGBE tristate "Intel(R) 10GbE PCI Express adapters support" - depends on PCI + depends on PCI && INET + select INET_LRO ---help--- This driver supports Intel(R) 10GbE PCI Express family of adapters. For more information on how to identify your adapter, go @@ -2473,20 +2420,6 @@ config IXGB To compile this driver as a module, choose M here. The module will be called ixgb. -config IXGB_NAPI - bool "Use Rx Polling (NAPI) (EXPERIMENTAL)" - depends on IXGB && EXPERIMENTAL - help - NAPI is a new driver API designed to reduce CPU and interrupt load - when the driver is receiving lots of packets from the card. It is - still somewhat experimental and thus not yet enabled by default. - - If your estimated Rx load is 10kpps or more, or if the card will be - deployed on potentially unfriendly networks (e.g. in a firewall), - then say Y here. - - If in doubt, say N. - config S2IO tristate "S2IO 10Gbe XFrame NIC" depends on PCI @@ -2495,20 +2428,6 @@ config S2IO More specific information on configuring the driver is in <file:Documentation/networking/s2io.txt>. -config S2IO_NAPI - bool "Use Rx Polling (NAPI) (EXPERIMENTAL)" - depends on S2IO && EXPERIMENTAL - help - NAPI is a new driver API designed to reduce CPU and interrupt load - when the driver is receiving lots of packets from the card. It is - still somewhat experimental and thus not yet enabled by default. - - If your estimated Rx load is 10kpps or more, or if the card will be - deployed on potentially unfriendly networks (e.g. in a firewall), - then say Y here. - - If in doubt, say N. - config MYRI10GE tristate "Myricom Myri-10G Ethernet support" depends on PCI && INET @@ -2573,6 +2492,7 @@ config BNX2X tristate "Broadcom NetXtremeII 10Gb support" depends on PCI select ZLIB_INFLATE + select LIBCRC32C help This driver supports Broadcom NetXtremeII 10 gigabit Ethernet cards. To compile this driver as a module, choose M here: the module diff --git a/drivers/net/Makefile b/drivers/net/Makefile index 9010e58da0f2..4b17a9ab7861 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -4,7 +4,6 @@ obj-$(CONFIG_E1000) += e1000/ obj-$(CONFIG_E1000E) += e1000e/ -obj-$(CONFIG_IBM_EMAC) += ibm_emac/ obj-$(CONFIG_IBM_NEW_EMAC) += ibm_newemac/ obj-$(CONFIG_IGB) += igb/ obj-$(CONFIG_IXGBE) += ixgbe/ @@ -67,6 +66,7 @@ obj-$(CONFIG_FEALNX) += fealnx.o obj-$(CONFIG_TIGON3) += tg3.o obj-$(CONFIG_BNX2) += bnx2.o obj-$(CONFIG_BNX2X) += bnx2x.o +bnx2x-objs := bnx2x_main.o bnx2x_link.o spidernet-y += spider_net.o spider_net_ethtool.o obj-$(CONFIG_SPIDER_NET) += spidernet.o sungem_phy.o obj-$(CONFIG_GELIC_NET) += ps3_gelic.o @@ -80,6 +80,7 @@ obj-$(CONFIG_VIA_RHINE) += via-rhine.o obj-$(CONFIG_VIA_VELOCITY) += via-velocity.o obj-$(CONFIG_ADAPTEC_STARFIRE) += starfire.o obj-$(CONFIG_RIONET) += rionet.o +obj-$(CONFIG_SH_ETH) += sh_eth.o # # end link order section @@ -105,11 +106,11 @@ ifeq ($(CONFIG_FEC_MPC52xx_MDIO),y) endif obj-$(CONFIG_68360_ENET) += 68360enet.o obj-$(CONFIG_WD80x3) += wd.o 8390.o -obj-$(CONFIG_EL2) += 3c503.o 8390.o -obj-$(CONFIG_NE2000) += ne.o 8390.o -obj-$(CONFIG_NE2_MCA) += ne2.o 8390.o -obj-$(CONFIG_HPLAN) += hp.o 8390.o -obj-$(CONFIG_HPLAN_PLUS) += hp-plus.o 8390.o +obj-$(CONFIG_EL2) += 3c503.o 8390p.o +obj-$(CONFIG_NE2000) += ne.o 8390p.o +obj-$(CONFIG_NE2_MCA) += ne2.o 8390p.o +obj-$(CONFIG_HPLAN) += hp.o 8390p.o +obj-$(CONFIG_HPLAN_PLUS) += hp-plus.o 8390p.o obj-$(CONFIG_ULTRA) += smc-ultra.o 8390.o obj-$(CONFIG_ULTRAMCA) += smc-mca.o 8390.o obj-$(CONFIG_ULTRA32) += smc-ultra32.o 8390.o @@ -165,7 +166,6 @@ obj-$(CONFIG_EEXPRESS_PRO) += eepro.o obj-$(CONFIG_8139CP) += 8139cp.o obj-$(CONFIG_8139TOO) += 8139too.o obj-$(CONFIG_ZNET) += znet.o -obj-$(CONFIG_LAN_SAA9730) += saa9730.o obj-$(CONFIG_CPMAC) += cpmac.o obj-$(CONFIG_DEPCA) += depca.o obj-$(CONFIG_EWRK3) += ewrk3.o @@ -235,6 +235,7 @@ obj-$(CONFIG_USB_CATC) += usb/ obj-$(CONFIG_USB_KAWETH) += usb/ obj-$(CONFIG_USB_PEGASUS) += usb/ obj-$(CONFIG_USB_RTL8150) += usb/ +obj-$(CONFIG_USB_HSO) += usb/ obj-$(CONFIG_USB_USBNET) += usb/ obj-$(CONFIG_USB_ZD1201) += usb/ diff --git a/drivers/net/a2065.c b/drivers/net/a2065.c index 6c5719ae8cca..9c0837435b68 100644 --- a/drivers/net/a2065.c +++ b/drivers/net/a2065.c @@ -475,16 +475,12 @@ static irqreturn_t lance_interrupt (int irq, void *dev_id) return IRQ_HANDLED; } -struct net_device *last_dev; - static int lance_open (struct net_device *dev) { struct lance_private *lp = netdev_priv(dev); volatile struct lance_regs *ll = lp->ll; int ret; - last_dev = dev; - /* Stop the Lance */ ll->rap = LE_CSR0; ll->rdp = LE_C0_STOP; diff --git a/drivers/net/acenic.c b/drivers/net/acenic.c index 6c192650d349..e4483de84e7f 100644 --- a/drivers/net/acenic.c +++ b/drivers/net/acenic.c @@ -1457,11 +1457,6 @@ static int __devinit ace_init(struct net_device *dev) ace_set_txprd(regs, ap, 0); writel(0, ®s->RxRetCsm); - /* - * Zero the stats before starting the interface - */ - memset(&ap->stats, 0, sizeof(ap->stats)); - /* * Enable DMA engine now. * If we do this sooner, Mckinley box pukes. @@ -2041,8 +2036,8 @@ static void ace_rx_int(struct net_device *dev, u32 rxretprd, u32 rxretcsm) netif_rx(skb); dev->last_rx = jiffies; - ap->stats.rx_packets++; - ap->stats.rx_bytes += retdesc->size; + dev->stats.rx_packets++; + dev->stats.rx_bytes += retdesc->size; idx = (idx + 1) % RX_RETURN_RING_ENTRIES; } @@ -2090,8 +2085,8 @@ static inline void ace_tx_int(struct net_device *dev, } if (skb) { - ap->stats.tx_packets++; - ap->stats.tx_bytes += skb->len; + dev->stats.tx_packets++; + dev->stats.tx_bytes += skb->len; dev_kfree_skb_irq(skb); info->skb = NULL; } @@ -2863,11 +2858,11 @@ static struct net_device_stats *ace_get_stats(struct net_device *dev) struct ace_mac_stats __iomem *mac_stats = (struct ace_mac_stats __iomem *)ap->regs->Stats; - ap->stats.rx_missed_errors = readl(&mac_stats->drop_space); - ap->stats.multicast = readl(&mac_stats->kept_mc); - ap->stats.collisions = readl(&mac_stats->coll); + dev->stats.rx_missed_errors = readl(&mac_stats->drop_space); + dev->stats.multicast = readl(&mac_stats->kept_mc); + dev->stats.collisions = readl(&mac_stats->coll); - return &ap->stats; + return &dev->stats; } diff --git a/drivers/net/acenic.h b/drivers/net/acenic.h index 60ed1837fa8f..4487f32759a4 100644 --- a/drivers/net/acenic.h +++ b/drivers/net/acenic.h @@ -693,7 +693,6 @@ struct ace_private __attribute__ ((aligned (SMP_CACHE_BYTES))); u32 last_tx, last_std_rx, last_mini_rx; #endif - struct net_device_stats stats; int pci_using_dac; }; diff --git a/drivers/net/amd8111e.c b/drivers/net/amd8111e.c index 85f7276aaba5..c54967f7942a 100644 --- a/drivers/net/amd8111e.c +++ b/drivers/net/amd8111e.c @@ -101,9 +101,9 @@ Revision History: #include "amd8111e.h" #define MODULE_NAME "amd8111e" -#define MODULE_VERS "3.0.6" +#define MODULE_VERS "3.0.7" MODULE_AUTHOR("Advanced Micro Devices, Inc."); -MODULE_DESCRIPTION ("AMD8111 based 10/100 Ethernet Controller. Driver Version 3.0.6"); +MODULE_DESCRIPTION ("AMD8111 based 10/100 Ethernet Controller. Driver Version "MODULE_VERS); MODULE_LICENSE("GPL"); MODULE_DEVICE_TABLE(pci, amd8111e_pci_tbl); module_param_array(speed_duplex, int, NULL, 0); @@ -671,11 +671,7 @@ This is the receive indication function for packets with vlan tag. */ static int amd8111e_vlan_rx(struct amd8111e_priv *lp, struct sk_buff *skb, u16 vlan_tag) { -#ifdef CONFIG_AMD8111E_NAPI return vlan_hwaccel_receive_skb(skb, lp->vlgrp,vlan_tag); -#else - return vlan_hwaccel_rx(skb, lp->vlgrp, vlan_tag); -#endif /* CONFIG_AMD8111E_NAPI */ } #endif @@ -722,7 +718,6 @@ static int amd8111e_tx(struct net_device *dev) return 0; } -#ifdef CONFIG_AMD8111E_NAPI /* This function handles the driver receive operation in polling mode */ static int amd8111e_rx_poll(struct napi_struct *napi, int budget) { @@ -734,7 +729,6 @@ static int amd8111e_rx_poll(struct napi_struct *napi, int budget) int min_pkt_len, status; unsigned int intr0; int num_rx_pkt = 0; - /*int max_rx_pkt = NUM_RX_BUFFERS;*/ short pkt_len; #if AMD8111E_VLAN_TAG_USED short vtag; @@ -850,108 +844,6 @@ rx_not_empty: return num_rx_pkt; } -#else -/* -This function will check the ownership of receive buffers and descriptors. It will indicate to kernel up to half the number of maximum receive buffers in the descriptor ring, in a single receive interrupt. It will also replenish the descriptors with new skbs. -*/ -static int amd8111e_rx(struct net_device *dev) -{ - struct amd8111e_priv *lp = netdev_priv(dev); - struct sk_buff *skb,*new_skb; - int rx_index = lp->rx_idx & RX_RING_DR_MOD_MASK; - int min_pkt_len, status; - int num_rx_pkt = 0; - int max_rx_pkt = NUM_RX_BUFFERS; - short pkt_len; -#if AMD8111E_VLAN_TAG_USED - short vtag; -#endif - - /* If we own the next entry, it's a new packet. Send it up. */ - while(++num_rx_pkt <= max_rx_pkt){ - status = le16_to_cpu(lp->rx_ring[rx_index].rx_flags); - if(status & OWN_BIT) - return 0; - - /* check if err summary bit is set */ - if(status & ERR_BIT){ - /* - * There is a tricky error noted by John Murphy, - * <murf@perftech.com> to Russ Nelson: Even with full-sized - * buffers it's possible for a jabber packet to use two - * buffers, with only the last correctly noting the error. */ - /* reseting flags */ - lp->rx_ring[rx_index].rx_flags &= RESET_RX_FLAGS; - goto err_next_pkt; - } - /* check for STP and ENP */ - if(!((status & STP_BIT) && (status & ENP_BIT))){ - /* reseting flags */ - lp->rx_ring[rx_index].rx_flags &= RESET_RX_FLAGS; - goto err_next_pkt; - } - pkt_len = le16_to_cpu(lp->rx_ring[rx_index].msg_count) - 4; - -#if AMD8111E_VLAN_TAG_USED - vtag = status & TT_MASK; - /*MAC will strip vlan tag*/ - if(lp->vlgrp != NULL && vtag !=0) - min_pkt_len =MIN_PKT_LEN - 4; - else -#endif - min_pkt_len =MIN_PKT_LEN; - - if (pkt_len < min_pkt_len) { - lp->rx_ring[rx_index].rx_flags &= RESET_RX_FLAGS; - lp->drv_rx_errors++; - goto err_next_pkt; - } - if(!(new_skb = dev_alloc_skb(lp->rx_buff_len))){ - /* if allocation fail, - ignore that pkt and go to next one */ - lp->rx_ring[rx_index].rx_flags &= RESET_RX_FLAGS; - lp->drv_rx_errors++; - goto err_next_pkt; - } - - skb_reserve(new_skb, 2); - skb = lp->rx_skbuff[rx_index]; - pci_unmap_single(lp->pci_dev,lp->rx_dma_addr[rx_index], - lp->rx_buff_len-2, PCI_DMA_FROMDEVICE); - skb_put(skb, pkt_len); - lp->rx_skbuff[rx_index] = new_skb; - lp->rx_dma_addr[rx_index] = pci_map_single(lp->pci_dev, - new_skb->data, lp->rx_buff_len-2,PCI_DMA_FROMDEVICE); - - skb->protocol = eth_type_trans(skb, dev); - -#if AMD8111E_VLAN_TAG_USED - if(lp->vlgrp != NULL && (vtag == TT_VLAN_TAGGED)){ - amd8111e_vlan_rx(lp, skb, - le16_to_cpu(lp->rx_ring[rx_index].tag_ctrl_info)); - } else -#endif - - netif_rx (skb); - /*COAL update rx coalescing parameters*/ - lp->coal_conf.rx_packets++; - lp->coal_conf.rx_bytes += pkt_len; - - dev->last_rx = jiffies; - -err_next_pkt: - lp->rx_ring[rx_index].buff_phy_addr - = cpu_to_le32(lp->rx_dma_addr[rx_index]); - lp->rx_ring[rx_index].buff_count = - cpu_to_le16(lp->rx_buff_len-2); - wmb(); - lp->rx_ring[rx_index].rx_flags |= cpu_to_le16(OWN_BIT); - rx_index = (++lp->rx_idx) & RX_RING_DR_MOD_MASK; - } - - return 0; -} -#endif /* CONFIG_AMD8111E_NAPI */ /* This function will indicate the link status to the kernel. */ @@ -1280,29 +1172,22 @@ static irqreturn_t amd8111e_interrupt(int irq, void *dev_id) writel(intr0, mmio + INT0); /* Check if Receive Interrupt has occurred. */ -#ifdef CONFIG_AMD8111E_NAPI - if(intr0 & RINT0){ - if(netif_rx_schedule_prep(dev, &lp->napi)){ + if (intr0 & RINT0) { + if (netif_rx_schedule_prep(dev, &lp->napi)) { /* Disable receive interupts */ writel(RINTEN0, mmio + INTEN0); /* Schedule a polling routine */ __netif_rx_schedule(dev, &lp->napi); - } - else if (intren0 & RINTEN0) { + } else if (intren0 & RINTEN0) { printk("************Driver bug! \ interrupt while in poll\n"); /* Fix by disable receive interrupts */ writel(RINTEN0, mmio + INTEN0); } } -#else - if(intr0 & RINT0){ - amd8111e_rx(dev); - writel(VAL2 | RDMD0, mmio + CMD0); - } -#endif /* CONFIG_AMD8111E_NAPI */ + /* Check if Transmit Interrupt has occurred. */ - if(intr0 & TINT0) + if (intr0 & TINT0) amd8111e_tx(dev); /* Check if Link Change Interrupt has occurred. */ @@ -1340,9 +1225,7 @@ static int amd8111e_close(struct net_device * dev) struct amd8111e_priv *lp = netdev_priv(dev); netif_stop_queue(dev); -#ifdef CONFIG_AMD8111E_NAPI napi_disable(&lp->napi); -#endif spin_lock_irq(&lp->lock); @@ -1374,9 +1257,7 @@ static int amd8111e_open(struct net_device * dev ) dev->name, dev)) return -EAGAIN; -#ifdef CONFIG_AMD8111E_NAPI napi_enable(&lp->napi); -#endif spin_lock_irq(&lp->lock); @@ -1384,9 +1265,7 @@ static int amd8111e_open(struct net_device * dev ) if(amd8111e_restart(dev)){ spin_unlock_irq(&lp->lock); -#ifdef CONFIG_AMD8111E_NAPI napi_disable(&lp->napi); -#endif if (dev->irq) free_irq(dev->irq, dev); return -ENOMEM; @@ -2036,9 +1915,7 @@ static int __devinit amd8111e_probe_one(struct pci_dev *pdev, dev->irq =pdev->irq; dev->tx_timeout = amd8111e_tx_timeout; dev->watchdog_timeo = AMD8111E_TX_TIMEOUT; -#ifdef CONFIG_AMD8111E_NAPI netif_napi_add(dev, &lp->napi, amd8111e_rx_poll, 32); -#endif #ifdef CONFIG_NET_POLL_CONTROLLER dev->poll_controller = amd8111e_poll; #endif diff --git a/drivers/net/ariadne.c b/drivers/net/ariadne.c index 10f3a196be32..29e53eb71c74 100644 --- a/drivers/net/ariadne.c +++ b/drivers/net/ariadne.c @@ -98,7 +98,6 @@ struct ariadne_private { volatile u_short *rx_buff[RX_RING_SIZE]; int cur_tx, cur_rx; /* The next free ring entry */ int dirty_tx; /* The ring entries to be free()ed. */ - struct net_device_stats stats; char tx_full; }; @@ -378,20 +377,19 @@ static void ariadne_init_ring(struct net_device *dev) static int ariadne_close(struct net_device *dev) { - struct ariadne_private *priv = netdev_priv(dev); volatile struct Am79C960 *lance = (struct Am79C960*)dev->base_addr; netif_stop_queue(dev); lance->RAP = CSR112; /* Missed Frame Count */ - priv->stats.rx_missed_errors = swapw(lance->RDP); + dev->stats.rx_missed_errors = swapw(lance->RDP); lance->RAP = CSR0; /* PCnet-ISA Controller Status */ if (ariadne_debug > 1) { printk(KERN_DEBUG "%s: Shutting down ethercard, status was %2.2x.\n", dev->name, lance->RDP); printk(KERN_DEBUG "%s: %lu packets missed\n", dev->name, - priv->stats.rx_missed_errors); + dev->stats.rx_missed_errors); } /* We stop the LANCE here -- it occasionally polls memory if we don't. */ @@ -502,16 +500,16 @@ static irqreturn_t ariadne_interrupt(int irq, void *data) if (status & TF_ERR) { /* There was an major error, log it. */ int err_status = priv->tx_ring[entry]->TMD3; - priv->stats.tx_errors++; + dev->stats.tx_errors++; if (err_status & EF_RTRY) - priv->stats.tx_aborted_errors++; + dev->stats.tx_aborted_errors++; if (err_status & EF_LCAR) - priv->stats.tx_carrier_errors++; + dev->stats.tx_carrier_errors++; if (err_status & EF_LCOL) - priv->stats.tx_window_errors++; + dev->stats.tx_window_errors++; if (err_status & EF_UFLO) { /* Ackk! On FIFO errors the Tx unit is turned off! */ - priv->stats.tx_fifo_errors++; + dev->stats.tx_fifo_errors++; /* Remove this verbosity later! */ printk(KERN_ERR "%s: Tx FIFO error! Status %4.4x.\n", dev->name, csr0); @@ -520,8 +518,8 @@ static irqreturn_t ariadne_interrupt(int irq, void *data) } } else { if (status & (TF_MORE|TF_ONE)) - priv->stats.collisions++; - priv->stats.tx_packets++; + dev->stats.collisions++; + dev->stats.tx_packets++; } dirty_tx++; } @@ -547,11 +545,11 @@ static irqreturn_t ariadne_interrupt(int irq, void *data) /* Log misc errors. */ if (csr0 & BABL) { handled = 1; - priv->stats.tx_errors++; /* Tx babble. */ + dev->stats.tx_errors++; /* Tx babble. */ } if (csr0 & MISS) { handled = 1; - priv->stats.rx_errors++; /* Missed a Rx frame. */ + dev->stats.rx_errors++; /* Missed a Rx frame. */ } if (csr0 & MERR) { handled = 1; @@ -672,7 +670,7 @@ static int ariadne_start_xmit(struct sk_buff *skb, struct net_device *dev) priv->cur_tx -= TX_RING_SIZE; priv->dirty_tx -= TX_RING_SIZE; } - priv->stats.tx_bytes += len; + dev->stats.tx_bytes += len; /* Trigger an immediate send poll. */ lance->RAP = CSR0; /* PCnet-ISA Controller Status */ @@ -707,15 +705,15 @@ static int ariadne_rx(struct net_device *dev) buffers, with only the last correctly noting the error. */ if (status & RF_ENP) /* Only count a general error at the end of a packet.*/ - priv->stats.rx_errors++; + dev->stats.rx_errors++; if (status & RF_FRAM) - priv->stats.rx_frame_errors++; + dev->stats.rx_frame_errors++; if (status & RF_OFLO) - priv->stats.rx_over_errors++; + dev->stats.rx_over_errors++; if (status & RF_CRC) - priv->stats.rx_crc_errors++; + dev->stats.rx_crc_errors++; if (status & RF_BUFF) - priv->stats.rx_fifo_errors++; + dev->stats.rx_fifo_errors++; priv->rx_ring[entry]->RMD1 &= 0xff00|RF_STP|RF_ENP; } else { /* Malloc up new buffer, compatible with net-3. */ @@ -731,7 +729,7 @@ static int ariadne_rx(struct net_device *dev) break; if (i > RX_RING_SIZE-2) { - priv->stats.rx_dropped++; + dev->stats.rx_dropped++; priv->rx_ring[entry]->RMD1 |= RF_OWN; priv->cur_rx++; } @@ -764,8 +762,8 @@ static int ariadne_rx(struct net_device *dev) netif_rx(skb); dev->last_rx = jiffies; - priv->stats.rx_packets++; - priv->stats.rx_bytes += pkt_len; + dev->stats.rx_packets++; + dev->stats.rx_bytes += pkt_len; } priv->rx_ring[entry]->RMD1 |= RF_OWN; @@ -783,7 +781,6 @@ static int ariadne_rx(struct net_device *dev) static struct net_device_stats *ariadne_get_stats(struct net_device *dev) { - struct ariadne_private *priv = netdev_priv(dev); volatile struct Am79C960 *lance = (struct Am79C960*)dev->base_addr; short saved_addr; unsigned long flags; @@ -791,11 +788,11 @@ static struct net_device_stats *ariadne_get_stats(struct net_device *dev) local_irq_save(flags); saved_addr = lance->RAP; lance->RAP = CSR112; /* Missed Frame Count */ - priv->stats.rx_missed_errors = swapw(lance->RDP); + dev->stats.rx_missed_errors = swapw(lance->RDP); lance->RAP = saved_addr; local_irq_restore(flags); - return &priv->stats; + return &dev->stats; } diff --git a/drivers/net/arm/ixp4xx_eth.c b/drivers/net/arm/ixp4xx_eth.c index c617b64c288e..9b777d9433cd 100644 --- a/drivers/net/arm/ixp4xx_eth.c +++ b/drivers/net/arm/ixp4xx_eth.c @@ -522,7 +522,6 @@ static int eth_poll(struct napi_struct *napi, int budget) #endif if ((n = queue_get_desc(rxq, port, 0)) < 0) { - received = 0; /* No packet received */ #if DEBUG_RX printk(KERN_DEBUG "%s: eth_poll netif_rx_complete\n", dev->name); @@ -543,7 +542,7 @@ static int eth_poll(struct napi_struct *napi, int budget) printk(KERN_DEBUG "%s: eth_poll all done\n", dev->name); #endif - return 0; /* all work done */ + return received; /* all work done */ } desc = rx_desc_ptr(port, n); diff --git a/drivers/net/atarilance.c b/drivers/net/atarilance.c index 4cceaac8863a..0860cc280b01 100644 --- a/drivers/net/atarilance.c +++ b/drivers/net/atarilance.c @@ -243,7 +243,7 @@ struct lance_private { /* Possible memory/IO addresses for probing */ -struct lance_addr { +static struct lance_addr { unsigned long memaddr; unsigned long ioaddr; int slow_flag; diff --git a/drivers/net/atlx/atl1.c b/drivers/net/atlx/atl1.c index 3c798ae5c343..3e22e7817bc3 100644 --- a/drivers/net/atlx/atl1.c +++ b/drivers/net/atlx/atl1.c @@ -1859,7 +1859,8 @@ static u16 atl1_alloc_rx_buffers(struct atl1_adapter *adapter) rfd_desc = ATL1_RFD_DESC(rfd_ring, rfd_next_to_use); - skb = dev_alloc_skb(adapter->rx_buffer_len + NET_IP_ALIGN); + skb = netdev_alloc_skb(adapter->netdev, + adapter->rx_buffer_len + NET_IP_ALIGN); if (unlikely(!skb)) { /* Better luck next round */ adapter->net_stats.rx_dropped++; diff --git a/drivers/net/au1000_eth.c b/drivers/net/au1000_eth.c index 7023d77bf380..3ab61e40e86a 100644 --- a/drivers/net/au1000_eth.c +++ b/drivers/net/au1000_eth.c @@ -912,7 +912,7 @@ au1000_adjust_link(struct net_device *dev) // link state changed if (phydev->link) // link went up - netif_schedule(dev); + netif_tx_schedule_all(dev); else { // link went down aup->old_speed = 0; aup->old_duplex = -1; diff --git a/drivers/net/b44.c b/drivers/net/b44.c index 59dce6aa0865..c3bda5ce67c4 100644 --- a/drivers/net/b44.c +++ b/drivers/net/b44.c @@ -148,9 +148,9 @@ static inline void b44_sync_dma_desc_for_device(struct ssb_device *sdev, unsigned long offset, enum dma_data_direction dir) { - dma_sync_single_range_for_device(sdev->dma_dev, dma_base, - offset & dma_desc_align_mask, - dma_desc_sync_size, dir); + ssb_dma_sync_single_range_for_device(sdev, dma_base, + offset & dma_desc_align_mask, + dma_desc_sync_size, dir); } static inline void b44_sync_dma_desc_for_cpu(struct ssb_device *sdev, @@ -158,9 +158,9 @@ static inline void b44_sync_dma_desc_for_cpu(struct ssb_device *sdev, unsigned long offset, enum dma_data_direction dir) { - dma_sync_single_range_for_cpu(sdev->dma_dev, dma_base, - offset & dma_desc_align_mask, - dma_desc_sync_size, dir); + ssb_dma_sync_single_range_for_cpu(sdev, dma_base, + offset & dma_desc_align_mask, + dma_desc_sync_size, dir); } static inline unsigned long br32(const struct b44 *bp, unsigned long reg) @@ -613,10 +613,10 @@ static void b44_tx(struct b44 *bp) BUG_ON(skb == NULL); - dma_unmap_single(bp->sdev->dma_dev, - rp->mapping, - skb->len, - DMA_TO_DEVICE); + ssb_dma_unmap_single(bp->sdev, + rp->mapping, + skb->len, + DMA_TO_DEVICE); rp->skb = NULL; dev_kfree_skb_irq(skb); } @@ -653,29 +653,29 @@ static int b44_alloc_rx_skb(struct b44 *bp, int src_idx, u32 dest_idx_unmasked) if (skb == NULL) return -ENOMEM; - mapping = dma_map_single(bp->sdev->dma_dev, skb->data, - RX_PKT_BUF_SZ, - DMA_FROM_DEVICE); + mapping = ssb_dma_map_single(bp->sdev, skb->data, + RX_PKT_BUF_SZ, + DMA_FROM_DEVICE); /* Hardware bug work-around, the chip is unable to do PCI DMA to/from anything above 1GB :-( */ - if (dma_mapping_error(mapping) || + if (ssb_dma_mapping_error(bp->sdev, mapping) || mapping + RX_PKT_BUF_SZ > DMA_30BIT_MASK) { /* Sigh... */ - if (!dma_mapping_error(mapping)) - dma_unmap_single(bp->sdev->dma_dev, mapping, - RX_PKT_BUF_SZ, DMA_FROM_DEVICE); + if (!ssb_dma_mapping_error(bp->sdev, mapping)) + ssb_dma_unmap_single(bp->sdev, mapping, + RX_PKT_BUF_SZ, DMA_FROM_DEVICE); dev_kfree_skb_any(skb); skb = __netdev_alloc_skb(bp->dev, RX_PKT_BUF_SZ, GFP_ATOMIC|GFP_DMA); if (skb == NULL) return -ENOMEM; - mapping = dma_map_single(bp->sdev->dma_dev, skb->data, - RX_PKT_BUF_SZ, - DMA_FROM_DEVICE); - if (dma_mapping_error(mapping) || + mapping = ssb_dma_map_single(bp->sdev, skb->data, + RX_PKT_BUF_SZ, + DMA_FROM_DEVICE); + if (ssb_dma_mapping_error(bp->sdev, mapping) || mapping + RX_PKT_BUF_SZ > DMA_30BIT_MASK) { - if (!dma_mapping_error(mapping)) - dma_unmap_single(bp->sdev->dma_dev, mapping, RX_PKT_BUF_SZ,DMA_FROM_DEVICE); + if (!ssb_dma_mapping_error(bp->sdev, mapping)) + ssb_dma_unmap_single(bp->sdev, mapping, RX_PKT_BUF_SZ,DMA_FROM_DEVICE); dev_kfree_skb_any(skb); return -ENOMEM; } @@ -750,9 +750,9 @@ static void b44_recycle_rx(struct b44 *bp, int src_idx, u32 dest_idx_unmasked) dest_idx * sizeof(dest_desc), DMA_BIDIRECTIONAL); - dma_sync_single_for_device(bp->sdev->dma_dev, le32_to_cpu(src_desc->addr), - RX_PKT_BUF_SZ, - DMA_FROM_DEVICE); + ssb_dma_sync_single_for_device(bp->sdev, le32_to_cpu(src_desc->addr), + RX_PKT_BUF_SZ, + DMA_FROM_DEVICE); } static int b44_rx(struct b44 *bp, int budget) @@ -772,7 +772,7 @@ static int b44_rx(struct b44 *bp, int budget) struct rx_header *rh; u16 len; - dma_sync_single_for_cpu(bp->sdev->dma_dev, map, + ssb_dma_sync_single_for_cpu(bp->sdev, map, RX_PKT_BUF_SZ, DMA_FROM_DEVICE); rh = (struct rx_header *) skb->data; @@ -806,8 +806,8 @@ static int b44_rx(struct b44 *bp, int budget) skb_size = b44_alloc_rx_skb(bp, cons, bp->rx_prod); if (skb_size < 0) goto drop_it; - dma_unmap_single(bp->sdev->dma_dev, map, - skb_size, DMA_FROM_DEVICE); + ssb_dma_unmap_single(bp->sdev, map, + skb_size, DMA_FROM_DEVICE); /* Leave out rx_header */ skb_put(skb, len + RX_PKT_OFFSET); skb_pull(skb, RX_PKT_OFFSET); @@ -966,25 +966,25 @@ static int b44_start_xmit(struct sk_buff *skb, struct net_device *dev) goto err_out; } - mapping = dma_map_single(bp->sdev->dma_dev, skb->data, len, DMA_TO_DEVICE); - if (dma_mapping_error(mapping) || mapping + len > DMA_30BIT_MASK) { + mapping = ssb_dma_map_single(bp->sdev, skb->data, len, DMA_TO_DEVICE); + if (ssb_dma_mapping_error(bp->sdev, mapping) || mapping + len > DMA_30BIT_MASK) { struct sk_buff *bounce_skb; /* Chip can't handle DMA to/from >1GB, use bounce buffer */ - if (!dma_mapping_error(mapping)) - dma_unmap_single(bp->sdev->dma_dev, mapping, len, - DMA_TO_DEVICE); + if (!ssb_dma_mapping_error(bp->sdev, mapping)) + ssb_dma_unmap_single(bp->sdev, mapping, len, + DMA_TO_DEVICE); bounce_skb = __dev_alloc_skb(len, GFP_ATOMIC | GFP_DMA); if (!bounce_skb) goto err_out; - mapping = dma_map_single(bp->sdev->dma_dev, bounce_skb->data, - len, DMA_TO_DEVICE); - if (dma_mapping_error(mapping) || mapping + len > DMA_30BIT_MASK) { - if (!dma_mapping_error(mapping)) - dma_unmap_single(bp->sdev->dma_dev, mapping, - len, DMA_TO_DEVICE); + mapping = ssb_dma_map_single(bp->sdev, bounce_skb->data, + len, DMA_TO_DEVICE); + if (ssb_dma_mapping_error(bp->sdev, mapping) || mapping + len > DMA_30BIT_MASK) { + if (!ssb_dma_mapping_error(bp->sdev, mapping)) + ssb_dma_unmap_single(bp->sdev, mapping, + len, DMA_TO_DEVICE); dev_kfree_skb_any(bounce_skb); goto err_out; } @@ -1082,8 +1082,8 @@ static void b44_free_rings(struct b44 *bp) if (rp->skb == NULL) continue; - dma_unmap_single(bp->sdev->dma_dev, rp->mapping, RX_PKT_BUF_SZ, - DMA_FROM_DEVICE); + ssb_dma_unmap_single(bp->sdev, rp->mapping, RX_PKT_BUF_SZ, + DMA_FROM_DEVICE); dev_kfree_skb_any(rp->skb); rp->skb = NULL; } @@ -1094,8 +1094,8 @@ static void b44_free_rings(struct b44 *bp) if (rp->skb == NULL) continue; - dma_unmap_single(bp->sdev->dma_dev, rp->mapping, rp->skb->len, - DMA_TO_DEVICE); + ssb_dma_unmap_single(bp->sdev, rp->mapping, rp->skb->len, + DMA_TO_DEVICE); dev_kfree_skb_any(rp->skb); rp->skb = NULL; } @@ -1117,14 +1117,14 @@ static void b44_init_rings(struct b44 *bp) memset(bp->tx_ring, 0, B44_TX_RING_BYTES); if (bp->flags & B44_FLAG_RX_RING_HACK) - dma_sync_single_for_device(bp->sdev->dma_dev, bp->rx_ring_dma, - DMA_TABLE_BYTES, - DMA_BIDIRECTIONAL); + ssb_dma_sync_single_for_device(bp->sdev, bp->rx_ring_dma, + DMA_TABLE_BYTES, + DMA_BIDIRECTIONAL); if (bp->flags & B44_FLAG_TX_RING_HACK) - dma_sync_single_for_device(bp->sdev->dma_dev, bp->tx_ring_dma, - DMA_TABLE_BYTES, - DMA_TO_DEVICE); + ssb_dma_sync_single_for_device(bp->sdev, bp->tx_ring_dma, + DMA_TABLE_BYTES, + DMA_TO_DEVICE); for (i = 0; i < bp->rx_pending; i++) { if (b44_alloc_rx_skb(bp, -1, i) < 0) @@ -1144,25 +1144,27 @@ static void b44_free_consistent(struct b44 *bp) bp->tx_buffers = NULL; if (bp->rx_ring) { if (bp->flags & B44_FLAG_RX_RING_HACK) { - dma_unmap_single(bp->sdev->dma_dev, bp->rx_ring_dma, - DMA_TABLE_BYTES, - DMA_BIDIRECTIONAL); + ssb_dma_unmap_single(bp->sdev, bp->rx_ring_dma, + DMA_TABLE_BYTES, + DMA_BIDIRECTIONAL); kfree(bp->rx_ring); } else - dma_free_coherent(bp->sdev->dma_dev, DMA_TABLE_BYTES, - bp->rx_ring, bp->rx_ring_dma); + ssb_dma_free_consistent(bp->sdev, DMA_TABLE_BYTES, + bp->rx_ring, bp->rx_ring_dma, + GFP_KERNEL); bp->rx_ring = NULL; bp->flags &= ~B44_FLAG_RX_RING_HACK; } if (bp->tx_ring) { if (bp->flags & B44_FLAG_TX_RING_HACK) { - dma_unmap_single(bp->sdev->dma_dev, bp->tx_ring_dma, - DMA_TABLE_BYTES, - DMA_TO_DEVICE); + ssb_dma_unmap_single(bp->sdev, bp->tx_ring_dma, + DMA_TABLE_BYTES, + DMA_TO_DEVICE); kfree(bp->tx_ring); } else - dma_free_coherent(bp->sdev->dma_dev, DMA_TABLE_BYTES, - bp->tx_ring, bp->tx_ring_dma); + ssb_dma_free_consistent(bp->sdev, DMA_TABLE_BYTES, + bp->tx_ring, bp->tx_ring_dma, + GFP_KERNEL); bp->tx_ring = NULL; bp->flags &= ~B44_FLAG_TX_RING_HACK; } @@ -1187,7 +1189,7 @@ static int b44_alloc_consistent(struct b44 *bp, gfp_t gfp) goto out_err; size = DMA_TABLE_BYTES; - bp->rx_ring = dma_alloc_coherent(bp->sdev->dma_dev, size, &bp->rx_ring_dma, gfp); + bp->rx_ring = ssb_dma_alloc_consistent(bp->sdev, size, &bp->rx_ring_dma, gfp); if (!bp->rx_ring) { /* Allocation may have failed due to pci_alloc_consistent insisting on use of GFP_DMA, which is more restrictive @@ -1199,11 +1201,11 @@ static int b44_alloc_consistent(struct b44 *bp, gfp_t gfp) if (!rx_ring) goto out_err; - rx_ring_dma = dma_map_single(bp->sdev->dma_dev, rx_ring, - DMA_TABLE_BYTES, - DMA_BIDIRECTIONAL); + rx_ring_dma = ssb_dma_map_single(bp->sdev, rx_ring, + DMA_TABLE_BYTES, + DMA_BIDIRECTIONAL); - if (dma_mapping_error(rx_ring_dma) || + if (ssb_dma_mapping_error(bp->sdev, rx_ring_dma) || rx_ring_dma + size > DMA_30BIT_MASK) { kfree(rx_ring); goto out_err; @@ -1214,9 +1216,9 @@ static int b44_alloc_consistent(struct b44 *bp, gfp_t gfp) bp->flags |= B44_FLAG_RX_RING_HACK; } - bp->tx_ring = dma_alloc_coherent(bp->sdev->dma_dev, size, &bp->tx_ring_dma, gfp); + bp->tx_ring = ssb_dma_alloc_consistent(bp->sdev, size, &bp->tx_ring_dma, gfp); if (!bp->tx_ring) { - /* Allocation may have failed due to dma_alloc_coherent + /* Allocation may have failed due to ssb_dma_alloc_consistent insisting on use of GFP_DMA, which is more restrictive than necessary... */ struct dma_desc *tx_ring; @@ -1226,11 +1228,11 @@ static int b44_alloc_consistent(struct b44 *bp, gfp_t gfp) if (!tx_ring) goto out_err; - tx_ring_dma = dma_map_single(bp->sdev->dma_dev, tx_ring, + tx_ring_dma = ssb_dma_map_single(bp->sdev, tx_ring, DMA_TABLE_BYTES, DMA_TO_DEVICE); - if (dma_mapping_error(tx_ring_dma) || + if (ssb_dma_mapping_error(bp->sdev, tx_ring_dma) || tx_ring_dma + size > DMA_30BIT_MASK) { kfree(tx_ring); goto out_err; diff --git a/drivers/net/bfin_mac.c b/drivers/net/bfin_mac.c index 41443435ab1c..a6a3da89f590 100644 --- a/drivers/net/bfin_mac.c +++ b/drivers/net/bfin_mac.c @@ -357,7 +357,7 @@ static void bfin_mac_adjust_link(struct net_device *dev) if (!lp->old_link) { new_state = 1; lp->old_link = 1; - netif_schedule(dev); + netif_tx_schedule_all(dev); } } else if (lp->old_link) { new_state = 1; diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c index 367b6d462708..5ebde67d4297 100644 --- a/drivers/net/bnx2.c +++ b/drivers/net/bnx2.c @@ -47,6 +47,7 @@ #include <linux/prefetch.h> #include <linux/cache.h> #include <linux/zlib.h> +#include <linux/log2.h> #include "bnx2.h" #include "bnx2_fw.h" @@ -56,8 +57,8 @@ #define DRV_MODULE_NAME "bnx2" #define PFX DRV_MODULE_NAME ": " -#define DRV_MODULE_VERSION "1.7.5" -#define DRV_MODULE_RELDATE "April 29, 2008" +#define DRV_MODULE_VERSION "1.7.9" +#define DRV_MODULE_RELDATE "July 18, 2008" #define RUN_AT(x) (jiffies + (x)) @@ -68,7 +69,7 @@ static char version[] __devinitdata = "Broadcom NetXtreme II Gigabit Ethernet Driver " DRV_MODULE_NAME " v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n"; MODULE_AUTHOR("Michael Chan <mchan@broadcom.com>"); -MODULE_DESCRIPTION("Broadcom NetXtreme II BCM5706/5708 Driver"); +MODULE_DESCRIPTION("Broadcom NetXtreme II BCM5706/5708/5709 Driver"); MODULE_LICENSE("GPL"); MODULE_VERSION(DRV_MODULE_VERSION); @@ -87,6 +88,7 @@ typedef enum { BCM5708S, BCM5709, BCM5709S, + BCM5716, } board_t; /* indexed by board_t, above */ @@ -102,9 +104,10 @@ static struct { { "Broadcom NetXtreme II BCM5708 1000Base-SX" }, { "Broadcom NetXtreme II BCM5709 1000Base-T" }, { "Broadcom NetXtreme II BCM5709 1000Base-SX" }, + { "Broadcom NetXtreme II BCM5716 1000Base-T" }, }; -static struct pci_device_id bnx2_pci_tbl[] = { +static DEFINE_PCI_DEVICE_TABLE(bnx2_pci_tbl) = { { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_5706, PCI_VENDOR_ID_HP, 0x3101, 0, 0, NC370T }, { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_5706, @@ -123,6 +126,8 @@ static struct pci_device_id bnx2_pci_tbl[] = { PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5709 }, { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_5709S, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5709S }, + { PCI_VENDOR_ID_BROADCOM, 0x163b, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5716 }, { 0, } }; @@ -226,7 +231,7 @@ static struct flash_spec flash_5709 = { MODULE_DEVICE_TABLE(pci, bnx2_pci_tbl); -static inline u32 bnx2_tx_avail(struct bnx2 *bp, struct bnx2_napi *bnapi) +static inline u32 bnx2_tx_avail(struct bnx2 *bp, struct bnx2_tx_ring_info *txr) { u32 diff; @@ -235,7 +240,7 @@ static inline u32 bnx2_tx_avail(struct bnx2 *bp, struct bnx2_napi *bnapi) /* The ring uses 256 indices for 255 entries, one of them * needs to be skipped. */ - diff = bp->tx_prod - bnapi->tx_cons; + diff = txr->tx_prod - txr->tx_cons; if (unlikely(diff >= TX_DESC_CNT)) { diff &= 0xffff; if (diff == TX_DESC_CNT) @@ -289,7 +294,6 @@ bnx2_ctx_wr(struct bnx2 *bp, u32 cid_addr, u32 offset, u32 val) REG_WR(bp, BNX2_CTX_CTX_CTRL, offset | BNX2_CTX_CTX_CTRL_WRITE_REQ); for (i = 0; i < 5; i++) { - u32 val; val = REG_RD(bp, BNX2_CTX_CTX_CTRL); if ((val & BNX2_CTX_CTX_CTRL_WRITE_REQ) == 0) break; @@ -488,7 +492,7 @@ bnx2_netif_start(struct bnx2 *bp) { if (atomic_dec_and_test(&bp->intr_sem)) { if (netif_running(bp->dev)) { - netif_wake_queue(bp->dev); + netif_tx_wake_all_queues(bp->dev); bnx2_napi_enable(bp); bnx2_enable_int(bp); } @@ -496,99 +500,162 @@ bnx2_netif_start(struct bnx2 *bp) } static void -bnx2_free_mem(struct bnx2 *bp) +bnx2_free_tx_mem(struct bnx2 *bp) { int i; - for (i = 0; i < bp->ctx_pages; i++) { - if (bp->ctx_blk[i]) { - pci_free_consistent(bp->pdev, BCM_PAGE_SIZE, - bp->ctx_blk[i], - bp->ctx_blk_mapping[i]); - bp->ctx_blk[i] = NULL; + for (i = 0; i < bp->num_tx_rings; i++) { + struct bnx2_napi *bnapi = &bp->bnx2_napi[i]; + struct bnx2_tx_ring_info *txr = &bnapi->tx_ring; + + if (txr->tx_desc_ring) { + pci_free_consistent(bp->pdev, TXBD_RING_SIZE, + txr->tx_desc_ring, + txr->tx_desc_mapping); + txr->tx_desc_ring = NULL; } + kfree(txr->tx_buf_ring); + txr->tx_buf_ring = NULL; } - if (bp->status_blk) { - pci_free_consistent(bp->pdev, bp->status_stats_size, - bp->status_blk, bp->status_blk_mapping); - bp->status_blk = NULL; - bp->stats_blk = NULL; +} + +static void +bnx2_free_rx_mem(struct bnx2 *bp) +{ + int i; + + for (i = 0; i < bp->num_rx_rings; i++) { + struct bnx2_napi *bnapi = &bp->bnx2_napi[i]; + struct bnx2_rx_ring_info *rxr = &bnapi->rx_ring; + int j; + + for (j = 0; j < bp->rx_max_ring; j++) { + if (rxr->rx_desc_ring[j]) + pci_free_consistent(bp->pdev, RXBD_RING_SIZE, + rxr->rx_desc_ring[j], + rxr->rx_desc_mapping[j]); + rxr->rx_desc_ring[j] = NULL; + } + if (rxr->rx_buf_ring) + vfree(rxr->rx_buf_ring); + rxr->rx_buf_ring = NULL; + + for (j = 0; j < bp->rx_max_pg_ring; j++) { + if (rxr->rx_pg_desc_ring[j]) + pci_free_consistent(bp->pdev, RXBD_RING_SIZE, + rxr->rx_pg_desc_ring[i], + rxr->rx_pg_desc_mapping[i]); + rxr->rx_pg_desc_ring[i] = NULL; + } + if (rxr->rx_pg_ring) + vfree(rxr->rx_pg_ring); + rxr->rx_pg_ring = NULL; } - if (bp->tx_desc_ring) { - pci_free_consistent(bp->pdev, TXBD_RING_SIZE, - bp->tx_desc_ring, bp->tx_desc_mapping); - bp->tx_desc_ring = NULL; - } - kfree(bp->tx_buf_ring); - bp->tx_buf_ring = NULL; - for (i = 0; i < bp->rx_max_ring; i++) { - if (bp->rx_desc_ring[i]) - pci_free_consistent(bp->pdev, RXBD_RING_SIZE, - bp->rx_desc_ring[i], - bp->rx_desc_mapping[i]); - bp->rx_desc_ring[i] = NULL; - } - vfree(bp->rx_buf_ring); - bp->rx_buf_ring = NULL; - for (i = 0; i < bp->rx_max_pg_ring; i++) { - if (bp->rx_pg_desc_ring[i]) - pci_free_consistent(bp->pdev, RXBD_RING_SIZE, - bp->rx_pg_desc_ring[i], - bp->rx_pg_desc_mapping[i]); - bp->rx_pg_desc_ring[i] = NULL; - } - if (bp->rx_pg_ring) - vfree(bp->rx_pg_ring); - bp->rx_pg_ring = NULL; } static int -bnx2_alloc_mem(struct bnx2 *bp) +bnx2_alloc_tx_mem(struct bnx2 *bp) { - int i, status_blk_size; + int i; - bp->tx_buf_ring = kzalloc(SW_TXBD_RING_SIZE, GFP_KERNEL); - if (bp->tx_buf_ring == NULL) - return -ENOMEM; + for (i = 0; i < bp->num_tx_rings; i++) { + struct bnx2_napi *bnapi = &bp->bnx2_napi[i]; + struct bnx2_tx_ring_info *txr = &bnapi->tx_ring; - bp->tx_desc_ring = pci_alloc_consistent(bp->pdev, TXBD_RING_SIZE, - &bp->tx_desc_mapping); - if (bp->tx_desc_ring == NULL) - goto alloc_mem_err; + txr->tx_buf_ring = kzalloc(SW_TXBD_RING_SIZE, GFP_KERNEL); + if (txr->tx_buf_ring == NULL) + return -ENOMEM; - bp->rx_buf_ring = vmalloc(SW_RXBD_RING_SIZE * bp->rx_max_ring); - if (bp->rx_buf_ring == NULL) - goto alloc_mem_err; + txr->tx_desc_ring = + pci_alloc_consistent(bp->pdev, TXBD_RING_SIZE, + &txr->tx_desc_mapping); + if (txr->tx_desc_ring == NULL) + return -ENOMEM; + } + return 0; +} + +static int +bnx2_alloc_rx_mem(struct bnx2 *bp) +{ + int i; + + for (i = 0; i < bp->num_rx_rings; i++) { + struct bnx2_napi *bnapi = &bp->bnx2_napi[i]; + struct bnx2_rx_ring_info *rxr = &bnapi->rx_ring; + int j; - memset(bp->rx_buf_ring, 0, SW_RXBD_RING_SIZE * bp->rx_max_ring); + rxr->rx_buf_ring = + vmalloc(SW_RXBD_RING_SIZE * bp->rx_max_ring); + if (rxr->rx_buf_ring == NULL) + return -ENOMEM; - for (i = 0; i < bp->rx_max_ring; i++) { - bp->rx_desc_ring[i] = - pci_alloc_consistent(bp->pdev, RXBD_RING_SIZE, - &bp->rx_desc_mapping[i]); - if (bp->rx_desc_ring[i] == NULL) - goto alloc_mem_err; + memset(rxr->rx_buf_ring, 0, + SW_RXBD_RING_SIZE * bp->rx_max_ring); - } + for (j = 0; j < bp->rx_max_ring; j++) { + rxr->rx_desc_ring[j] = + pci_alloc_consistent(bp->pdev, RXBD_RING_SIZE, + &rxr->rx_desc_mapping[j]); + if (rxr->rx_desc_ring[j] == NULL) + return -ENOMEM; - if (bp->rx_pg_ring_size) { - bp->rx_pg_ring = vmalloc(SW_RXPG_RING_SIZE * - bp->rx_max_pg_ring); - if (bp->rx_pg_ring == NULL) - goto alloc_mem_err; + } + + if (bp->rx_pg_ring_size) { + rxr->rx_pg_ring = vmalloc(SW_RXPG_RING_SIZE * + bp->rx_max_pg_ring); + if (rxr->rx_pg_ring == NULL) + return -ENOMEM; + + memset(rxr->rx_pg_ring, 0, SW_RXPG_RING_SIZE * + bp->rx_max_pg_ring); + } + + for (j = 0; j < bp->rx_max_pg_ring; j++) { + rxr->rx_pg_desc_ring[j] = + pci_alloc_consistent(bp->pdev, RXBD_RING_SIZE, + &rxr->rx_pg_desc_mapping[j]); + if (rxr->rx_pg_desc_ring[j] == NULL) + return -ENOMEM; - memset(bp->rx_pg_ring, 0, SW_RXPG_RING_SIZE * - bp->rx_max_pg_ring); + } } + return 0; +} - for (i = 0; i < bp->rx_max_pg_ring; i++) { - bp->rx_pg_desc_ring[i] = - pci_alloc_consistent(bp->pdev, RXBD_RING_SIZE, - &bp->rx_pg_desc_mapping[i]); - if (bp->rx_pg_desc_ring[i] == NULL) - goto alloc_mem_err; +static void +bnx2_free_mem(struct bnx2 *bp) +{ + int i; + struct bnx2_napi *bnapi = &bp->bnx2_napi[0]; + + bnx2_free_tx_mem(bp); + bnx2_free_rx_mem(bp); + for (i = 0; i < bp->ctx_pages; i++) { + if (bp->ctx_blk[i]) { + pci_free_consistent(bp->pdev, BCM_PAGE_SIZE, + bp->ctx_blk[i], + bp->ctx_blk_mapping[i]); + bp->ctx_blk[i] = NULL; + } } + if (bnapi->status_blk.msi) { + pci_free_consistent(bp->pdev, bp->status_stats_size, + bnapi->status_blk.msi, + bp->status_blk_mapping); + bnapi->status_blk.msi = NULL; + bp->stats_blk = NULL; + } +} + +static int +bnx2_alloc_mem(struct bnx2 *bp) +{ + int i, status_blk_size, err; + struct bnx2_napi *bnapi; + void *status_blk; /* Combine status and statistics blocks into one allocation. */ status_blk_size = L1_CACHE_ALIGN(sizeof(struct status_block)); @@ -598,27 +665,37 @@ bnx2_alloc_mem(struct bnx2 *bp) bp->status_stats_size = status_blk_size + sizeof(struct statistics_block); - bp->status_blk = pci_alloc_consistent(bp->pdev, bp->status_stats_size, - &bp->status_blk_mapping); - if (bp->status_blk == NULL) + status_blk = pci_alloc_consistent(bp->pdev, bp->status_stats_size, + &bp->status_blk_mapping); + if (status_blk == NULL) goto alloc_mem_err; - memset(bp->status_blk, 0, bp->status_stats_size); + memset(status_blk, 0, bp->status_stats_size); - bp->bnx2_napi[0].status_blk = bp->status_blk; + bnapi = &bp->bnx2_napi[0]; + bnapi->status_blk.msi = status_blk; + bnapi->hw_tx_cons_ptr = + &bnapi->status_blk.msi->status_tx_quick_consumer_index0; + bnapi->hw_rx_cons_ptr = + &bnapi->status_blk.msi->status_rx_quick_consumer_index0; if (bp->flags & BNX2_FLAG_MSIX_CAP) { for (i = 1; i < BNX2_MAX_MSIX_VEC; i++) { - struct bnx2_napi *bnapi = &bp->bnx2_napi[i]; + struct status_block_msix *sblk; - bnapi->status_blk_msix = (void *) - ((unsigned long) bp->status_blk + - BNX2_SBLK_MSIX_ALIGN_SIZE * i); + bnapi = &bp->bnx2_napi[i]; + + sblk = (void *) (status_blk + + BNX2_SBLK_MSIX_ALIGN_SIZE * i); + bnapi->status_blk.msix = sblk; + bnapi->hw_tx_cons_ptr = + &sblk->status_tx_quick_consumer_index; + bnapi->hw_rx_cons_ptr = + &sblk->status_rx_quick_consumer_index; bnapi->int_num = i << 24; } } - bp->stats_blk = (void *) ((unsigned long) bp->status_blk + - status_blk_size); + bp->stats_blk = status_blk + status_blk_size; bp->stats_blk_mapping = bp->status_blk_mapping + status_blk_size; @@ -634,6 +711,15 @@ bnx2_alloc_mem(struct bnx2 *bp) goto alloc_mem_err; } } + + err = bnx2_alloc_rx_mem(bp); + if (err) + goto alloc_mem_err; + + err = bnx2_alloc_tx_mem(bp); + if (err) + goto alloc_mem_err; + return 0; alloc_mem_err: @@ -993,9 +1079,9 @@ bnx2_copper_linkup(struct bnx2 *bp) } static void -bnx2_init_rx_context0(struct bnx2 *bp) +bnx2_init_rx_context(struct bnx2 *bp, u32 cid) { - u32 val, rx_cid_addr = GET_CID_ADDR(RX_CID); + u32 val, rx_cid_addr = GET_CID_ADDR(cid); val = BNX2_L2CTX_CTX_TYPE_CTX_BD_CHN_TYPE_VALUE; val |= BNX2_L2CTX_CTX_TYPE_SIZE_L2; @@ -1028,6 +1114,19 @@ bnx2_init_rx_context0(struct bnx2 *bp) bnx2_ctx_wr(bp, rx_cid_addr, BNX2_L2CTX_CTX_TYPE, val); } +static void +bnx2_init_all_rx_contexts(struct bnx2 *bp) +{ + int i; + u32 cid; + + for (i = 0, cid = RX_CID; i < bp->num_rx_rings; i++, cid++) { + if (i == 1) + cid = RX_RSS_CID; + bnx2_init_rx_context(bp, cid); + } +} + static int bnx2_set_mac_link(struct bnx2 *bp) { @@ -1093,7 +1192,7 @@ bnx2_set_mac_link(struct bnx2 *bp) REG_WR(bp, BNX2_EMAC_STATUS, BNX2_EMAC_STATUS_LINK_CHANGE); if (CHIP_NUM(bp) == CHIP_NUM_5709) - bnx2_init_rx_context0(bp); + bnx2_init_all_rx_contexts(bp); return 0; } @@ -1392,7 +1491,7 @@ bnx2_phy_get_pause_adv(struct bnx2 *bp) return adv; } -static int bnx2_fw_sync(struct bnx2 *, u32, int); +static int bnx2_fw_sync(struct bnx2 *, u32, int, int); static int bnx2_setup_remote_phy(struct bnx2 *bp, u8 port) @@ -1445,7 +1544,7 @@ bnx2_setup_remote_phy(struct bnx2 *bp, u8 port) bnx2_shmem_wr(bp, BNX2_DRV_MB_ARG0, speed_arg); spin_unlock_bh(&bp->phy_lock); - bnx2_fw_sync(bp, BNX2_DRV_MSG_CODE_CMD_SET_LINK, 0); + bnx2_fw_sync(bp, BNX2_DRV_MSG_CODE_CMD_SET_LINK, 1, 0); spin_lock_bh(&bp->phy_lock); return 0; @@ -1875,7 +1974,7 @@ bnx2_setup_phy(struct bnx2 *bp, u8 port) } static int -bnx2_init_5709s_phy(struct bnx2 *bp) +bnx2_init_5709s_phy(struct bnx2 *bp, int reset_phy) { u32 val; @@ -1890,7 +1989,8 @@ bnx2_init_5709s_phy(struct bnx2 *bp) bnx2_write_phy(bp, MII_BNX2_AER_AER, MII_BNX2_AER_AER_AN_MMD); bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_COMBO_IEEEB0); - bnx2_reset_phy(bp); + if (reset_phy) + bnx2_reset_phy(bp); bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_SERDES_DIG); @@ -1924,11 +2024,12 @@ bnx2_init_5709s_phy(struct bnx2 *bp) } static int -bnx2_init_5708s_phy(struct bnx2 *bp) +bnx2_init_5708s_phy(struct bnx2 *bp, int reset_phy) { u32 val; - bnx2_reset_phy(bp); + if (reset_phy) + bnx2_reset_phy(bp); bp->mii_up1 = BCM5708S_UP1; @@ -1981,9 +2082,10 @@ bnx2_init_5708s_phy(struct bnx2 *bp) } static int -bnx2_init_5706s_phy(struct bnx2 *bp) +bnx2_init_5706s_phy(struct bnx2 *bp, int reset_phy) { - bnx2_reset_phy(bp); + if (reset_phy) + bnx2_reset_phy(bp); bp->phy_flags &= ~BNX2_PHY_FLAG_PARALLEL_DETECT; @@ -2018,11 +2120,12 @@ bnx2_init_5706s_phy(struct bnx2 *bp) } static int -bnx2_init_copper_phy(struct bnx2 *bp) +bnx2_init_copper_phy(struct bnx2 *bp, int reset_phy) { u32 val; - bnx2_reset_phy(bp); + if (reset_phy) + bnx2_reset_phy(bp); if (bp->phy_flags & BNX2_PHY_FLAG_CRC_FIX) { bnx2_write_phy(bp, 0x18, 0x0c00); @@ -2070,7 +2173,7 @@ bnx2_init_copper_phy(struct bnx2 *bp) static int -bnx2_init_phy(struct bnx2 *bp) +bnx2_init_phy(struct bnx2 *bp, int reset_phy) { u32 val; int rc = 0; @@ -2096,14 +2199,14 @@ bnx2_init_phy(struct bnx2 *bp) if (bp->phy_flags & BNX2_PHY_FLAG_SERDES) { if (CHIP_NUM(bp) == CHIP_NUM_5706) - rc = bnx2_init_5706s_phy(bp); + rc = bnx2_init_5706s_phy(bp, reset_phy); else if (CHIP_NUM(bp) == CHIP_NUM_5708) - rc = bnx2_init_5708s_phy(bp); + rc = bnx2_init_5708s_phy(bp, reset_phy); else if (CHIP_NUM(bp) == CHIP_NUM_5709) - rc = bnx2_init_5709s_phy(bp); + rc = bnx2_init_5709s_phy(bp, reset_phy); } else { - rc = bnx2_init_copper_phy(bp); + rc = bnx2_init_copper_phy(bp, reset_phy); } setup_phy: @@ -2159,7 +2262,7 @@ bnx2_set_phy_loopback(struct bnx2 *bp) } static int -bnx2_fw_sync(struct bnx2 *bp, u32 msg_data, int silent) +bnx2_fw_sync(struct bnx2 *bp, u32 msg_data, int ack, int silent) { int i; u32 val; @@ -2169,6 +2272,9 @@ bnx2_fw_sync(struct bnx2 *bp, u32 msg_data, int silent) bnx2_shmem_wr(bp, BNX2_DRV_MB, msg_data); + if (!ack) + return 0; + /* wait for an acknowledgement. */ for (i = 0; i < (FW_ACK_TIME_OUT_MS / 10); i++) { msleep(10); @@ -2345,28 +2451,27 @@ bnx2_alloc_bad_rbuf(struct bnx2 *bp) } static void -bnx2_set_mac_addr(struct bnx2 *bp) +bnx2_set_mac_addr(struct bnx2 *bp, u8 *mac_addr, u32 pos) { u32 val; - u8 *mac_addr = bp->dev->dev_addr; val = (mac_addr[0] << 8) | mac_addr[1]; - REG_WR(bp, BNX2_EMAC_MAC_MATCH0, val); + REG_WR(bp, BNX2_EMAC_MAC_MATCH0 + (pos * 8), val); val = (mac_addr[2] << 24) | (mac_addr[3] << 16) | (mac_addr[4] << 8) | mac_addr[5]; - REG_WR(bp, BNX2_EMAC_MAC_MATCH1, val); + REG_WR(bp, BNX2_EMAC_MAC_MATCH1 + (pos * 8), val); } static inline int -bnx2_alloc_rx_page(struct bnx2 *bp, u16 index) +bnx2_alloc_rx_page(struct bnx2 *bp, struct bnx2_rx_ring_info *rxr, u16 index) { dma_addr_t mapping; - struct sw_pg *rx_pg = &bp->rx_pg_ring[index]; + struct sw_pg *rx_pg = &rxr->rx_pg_ring[index]; struct rx_bd *rxbd = - &bp->rx_pg_desc_ring[RX_RING(index)][RX_IDX(index)]; + &rxr->rx_pg_desc_ring[RX_RING(index)][RX_IDX(index)]; struct page *page = alloc_page(GFP_ATOMIC); if (!page) @@ -2381,9 +2486,9 @@ bnx2_alloc_rx_page(struct bnx2 *bp, u16 index) } static void -bnx2_free_rx_page(struct bnx2 *bp, u16 index) +bnx2_free_rx_page(struct bnx2 *bp, struct bnx2_rx_ring_info *rxr, u16 index) { - struct sw_pg *rx_pg = &bp->rx_pg_ring[index]; + struct sw_pg *rx_pg = &rxr->rx_pg_ring[index]; struct page *page = rx_pg->page; if (!page) @@ -2397,12 +2502,12 @@ bnx2_free_rx_page(struct bnx2 *bp, u16 index) } static inline int -bnx2_alloc_rx_skb(struct bnx2 *bp, struct bnx2_napi *bnapi, u16 index) +bnx2_alloc_rx_skb(struct bnx2 *bp, struct bnx2_rx_ring_info *rxr, u16 index) { struct sk_buff *skb; - struct sw_bd *rx_buf = &bp->rx_buf_ring[index]; + struct sw_bd *rx_buf = &rxr->rx_buf_ring[index]; dma_addr_t mapping; - struct rx_bd *rxbd = &bp->rx_desc_ring[RX_RING(index)][RX_IDX(index)]; + struct rx_bd *rxbd = &rxr->rx_desc_ring[RX_RING(index)][RX_IDX(index)]; unsigned long align; skb = netdev_alloc_skb(bp->dev, bp->rx_buf_size); @@ -2422,7 +2527,7 @@ bnx2_alloc_rx_skb(struct bnx2 *bp, struct bnx2_napi *bnapi, u16 index) rxbd->rx_bd_haddr_hi = (u64) mapping >> 32; rxbd->rx_bd_haddr_lo = (u64) mapping & 0xffffffff; - bnapi->rx_prod_bseq += bp->rx_buf_use_size; + rxr->rx_prod_bseq += bp->rx_buf_use_size; return 0; } @@ -2430,7 +2535,7 @@ bnx2_alloc_rx_skb(struct bnx2 *bp, struct bnx2_napi *bnapi, u16 index) static int bnx2_phy_event_is_set(struct bnx2 *bp, struct bnx2_napi *bnapi, u32 event) { - struct status_block *sblk = bnapi->status_blk; + struct status_block *sblk = bnapi->status_blk.msi; u32 new_link_state, old_link_state; int is_set = 1; @@ -2466,11 +2571,9 @@ bnx2_get_hw_tx_cons(struct bnx2_napi *bnapi) { u16 cons; - if (bnapi->int_num == 0) - cons = bnapi->status_blk->status_tx_quick_consumer_index0; - else - cons = bnapi->status_blk_msix->status_tx_quick_consumer_index; - + /* Tell compiler that status block fields can change. */ + barrier(); + cons = *bnapi->hw_tx_cons_ptr; if (unlikely((cons & MAX_TX_DESC_CNT) == MAX_TX_DESC_CNT)) cons++; return cons; @@ -2479,11 +2582,16 @@ bnx2_get_hw_tx_cons(struct bnx2_napi *bnapi) static int bnx2_tx_int(struct bnx2 *bp, struct bnx2_napi *bnapi, int budget) { + struct bnx2_tx_ring_info *txr = &bnapi->tx_ring; u16 hw_cons, sw_cons, sw_ring_cons; - int tx_pkt = 0; + int tx_pkt = 0, index; + struct netdev_queue *txq; + + index = (bnapi - bp->bnx2_napi); + txq = netdev_get_tx_queue(bp->dev, index); hw_cons = bnx2_get_hw_tx_cons(bnapi); - sw_cons = bnapi->tx_cons; + sw_cons = txr->tx_cons; while (sw_cons != hw_cons) { struct sw_bd *tx_buf; @@ -2492,7 +2600,7 @@ bnx2_tx_int(struct bnx2 *bp, struct bnx2_napi *bnapi, int budget) sw_ring_cons = TX_RING_IDX(sw_cons); - tx_buf = &bp->tx_buf_ring[sw_ring_cons]; + tx_buf = &txr->tx_buf_ring[sw_ring_cons]; skb = tx_buf->skb; /* partial BD completions possible with TSO packets */ @@ -2522,7 +2630,7 @@ bnx2_tx_int(struct bnx2 *bp, struct bnx2_napi *bnapi, int budget) pci_unmap_page(bp->pdev, pci_unmap_addr( - &bp->tx_buf_ring[TX_RING_IDX(sw_cons)], + &txr->tx_buf_ring[TX_RING_IDX(sw_cons)], mapping), skb_shinfo(skb)->frags[i].size, PCI_DMA_TODEVICE); @@ -2538,44 +2646,46 @@ bnx2_tx_int(struct bnx2 *bp, struct bnx2_napi *bnapi, int budget) hw_cons = bnx2_get_hw_tx_cons(bnapi); } - bnapi->hw_tx_cons = hw_cons; - bnapi->tx_cons = sw_cons; + txr->hw_tx_cons = hw_cons; + txr->tx_cons = sw_cons; + /* Need to make the tx_cons update visible to bnx2_start_xmit() - * before checking for netif_queue_stopped(). Without the + * before checking for netif_tx_queue_stopped(). Without the * memory barrier, there is a small possibility that bnx2_start_xmit() * will miss it and cause the queue to be stopped forever. */ smp_mb(); - if (unlikely(netif_queue_stopped(bp->dev)) && - (bnx2_tx_avail(bp, bnapi) > bp->tx_wake_thresh)) { - netif_tx_lock(bp->dev); - if ((netif_queue_stopped(bp->dev)) && - (bnx2_tx_avail(bp, bnapi) > bp->tx_wake_thresh)) - netif_wake_queue(bp->dev); - netif_tx_unlock(bp->dev); + if (unlikely(netif_tx_queue_stopped(txq)) && + (bnx2_tx_avail(bp, txr) > bp->tx_wake_thresh)) { + __netif_tx_lock(txq, smp_processor_id()); + if ((netif_tx_queue_stopped(txq)) && + (bnx2_tx_avail(bp, txr) > bp->tx_wake_thresh)) + netif_tx_wake_queue(txq); + __netif_tx_unlock(txq); } + return tx_pkt; } static void -bnx2_reuse_rx_skb_pages(struct bnx2 *bp, struct bnx2_napi *bnapi, +bnx2_reuse_rx_skb_pages(struct bnx2 *bp, struct bnx2_rx_ring_info *rxr, struct sk_buff *skb, int count) { struct sw_pg *cons_rx_pg, *prod_rx_pg; struct rx_bd *cons_bd, *prod_bd; dma_addr_t mapping; int i; - u16 hw_prod = bnapi->rx_pg_prod, prod; - u16 cons = bnapi->rx_pg_cons; + u16 hw_prod = rxr->rx_pg_prod, prod; + u16 cons = rxr->rx_pg_cons; for (i = 0; i < count; i++) { prod = RX_PG_RING_IDX(hw_prod); - prod_rx_pg = &bp->rx_pg_ring[prod]; - cons_rx_pg = &bp->rx_pg_ring[cons]; - cons_bd = &bp->rx_pg_desc_ring[RX_RING(cons)][RX_IDX(cons)]; - prod_bd = &bp->rx_pg_desc_ring[RX_RING(prod)][RX_IDX(prod)]; + prod_rx_pg = &rxr->rx_pg_ring[prod]; + cons_rx_pg = &rxr->rx_pg_ring[cons]; + cons_bd = &rxr->rx_pg_desc_ring[RX_RING(cons)][RX_IDX(cons)]; + prod_bd = &rxr->rx_pg_desc_ring[RX_RING(prod)][RX_IDX(prod)]; if (i == 0 && skb) { struct page *page; @@ -2604,25 +2714,25 @@ bnx2_reuse_rx_skb_pages(struct bnx2 *bp, struct bnx2_napi *bnapi, cons = RX_PG_RING_IDX(NEXT_RX_BD(cons)); hw_prod = NEXT_RX_BD(hw_prod); } - bnapi->rx_pg_prod = hw_prod; - bnapi->rx_pg_cons = cons; + rxr->rx_pg_prod = hw_prod; + rxr->rx_pg_cons = cons; } static inline void -bnx2_reuse_rx_skb(struct bnx2 *bp, struct bnx2_napi *bnapi, struct sk_buff *skb, - u16 cons, u16 prod) +bnx2_reuse_rx_skb(struct bnx2 *bp, struct bnx2_rx_ring_info *rxr, + struct sk_buff *skb, u16 cons, u16 prod) { struct sw_bd *cons_rx_buf, *prod_rx_buf; struct rx_bd *cons_bd, *prod_bd; - cons_rx_buf = &bp->rx_buf_ring[cons]; - prod_rx_buf = &bp->rx_buf_ring[prod]; + cons_rx_buf = &rxr->rx_buf_ring[cons]; + prod_rx_buf = &rxr->rx_buf_ring[prod]; pci_dma_sync_single_for_device(bp->pdev, pci_unmap_addr(cons_rx_buf, mapping), - bp->rx_offset + RX_COPY_THRESH, PCI_DMA_FROMDEVICE); + BNX2_RX_OFFSET + BNX2_RX_COPY_THRESH, PCI_DMA_FROMDEVICE); - bnapi->rx_prod_bseq += bp->rx_buf_use_size; + rxr->rx_prod_bseq += bp->rx_buf_use_size; prod_rx_buf->skb = skb; @@ -2632,33 +2742,33 @@ bnx2_reuse_rx_skb(struct bnx2 *bp, struct bnx2_napi *bnapi, struct sk_buff *skb, pci_unmap_addr_set(prod_rx_buf, mapping, pci_unmap_addr(cons_rx_buf, mapping)); - cons_bd = &bp->rx_desc_ring[RX_RING(cons)][RX_IDX(cons)]; - prod_bd = &bp->rx_desc_ring[RX_RING(prod)][RX_IDX(prod)]; + cons_bd = &rxr->rx_desc_ring[RX_RING(cons)][RX_IDX(cons)]; + prod_bd = &rxr->rx_desc_ring[RX_RING(prod)][RX_IDX(prod)]; prod_bd->rx_bd_haddr_hi = cons_bd->rx_bd_haddr_hi; prod_bd->rx_bd_haddr_lo = cons_bd->rx_bd_haddr_lo; } static int -bnx2_rx_skb(struct bnx2 *bp, struct bnx2_napi *bnapi, struct sk_buff *skb, +bnx2_rx_skb(struct bnx2 *bp, struct bnx2_rx_ring_info *rxr, struct sk_buff *skb, unsigned int len, unsigned int hdr_len, dma_addr_t dma_addr, u32 ring_idx) { int err; u16 prod = ring_idx & 0xffff; - err = bnx2_alloc_rx_skb(bp, bnapi, prod); + err = bnx2_alloc_rx_skb(bp, rxr, prod); if (unlikely(err)) { - bnx2_reuse_rx_skb(bp, bnapi, skb, (u16) (ring_idx >> 16), prod); + bnx2_reuse_rx_skb(bp, rxr, skb, (u16) (ring_idx >> 16), prod); if (hdr_len) { unsigned int raw_len = len + 4; int pages = PAGE_ALIGN(raw_len - hdr_len) >> PAGE_SHIFT; - bnx2_reuse_rx_skb_pages(bp, bnapi, NULL, pages); + bnx2_reuse_rx_skb_pages(bp, rxr, NULL, pages); } return err; } - skb_reserve(skb, bp->rx_offset); + skb_reserve(skb, BNX2_RX_OFFSET); pci_unmap_single(bp->pdev, dma_addr, bp->rx_buf_use_size, PCI_DMA_FROMDEVICE); @@ -2668,8 +2778,8 @@ bnx2_rx_skb(struct bnx2 *bp, struct bnx2_napi *bnapi, struct sk_buff *skb, } else { unsigned int i, frag_len, frag_size, pages; struct sw_pg *rx_pg; - u16 pg_cons = bnapi->rx_pg_cons; - u16 pg_prod = bnapi->rx_pg_prod; + u16 pg_cons = rxr->rx_pg_cons; + u16 pg_prod = rxr->rx_pg_prod; frag_size = len + 4 - hdr_len; pages = PAGE_ALIGN(frag_size) >> PAGE_SHIFT; @@ -2680,9 +2790,9 @@ bnx2_rx_skb(struct bnx2 *bp, struct bnx2_napi *bnapi, struct sk_buff *skb, if (unlikely(frag_len <= 4)) { unsigned int tail = 4 - frag_len; - bnapi->rx_pg_cons = pg_cons; - bnapi->rx_pg_prod = pg_prod; - bnx2_reuse_rx_skb_pages(bp, bnapi, NULL, + rxr->rx_pg_cons = pg_cons; + rxr->rx_pg_prod = pg_prod; + bnx2_reuse_rx_skb_pages(bp, rxr, NULL, pages - i); skb->len -= tail; if (i == 0) { @@ -2696,7 +2806,7 @@ bnx2_rx_skb(struct bnx2 *bp, struct bnx2_napi *bnapi, struct sk_buff *skb, } return 0; } - rx_pg = &bp->rx_pg_ring[pg_cons]; + rx_pg = &rxr->rx_pg_ring[pg_cons]; pci_unmap_page(bp->pdev, pci_unmap_addr(rx_pg, mapping), PAGE_SIZE, PCI_DMA_FROMDEVICE); @@ -2707,11 +2817,12 @@ bnx2_rx_skb(struct bnx2 *bp, struct bnx2_napi *bnapi, struct sk_buff *skb, skb_fill_page_desc(skb, i, rx_pg->page, 0, frag_len); rx_pg->page = NULL; - err = bnx2_alloc_rx_page(bp, RX_PG_RING_IDX(pg_prod)); + err = bnx2_alloc_rx_page(bp, rxr, + RX_PG_RING_IDX(pg_prod)); if (unlikely(err)) { - bnapi->rx_pg_cons = pg_cons; - bnapi->rx_pg_prod = pg_prod; - bnx2_reuse_rx_skb_pages(bp, bnapi, skb, + rxr->rx_pg_cons = pg_cons; + rxr->rx_pg_prod = pg_prod; + bnx2_reuse_rx_skb_pages(bp, rxr, skb, pages - i); return err; } @@ -2724,8 +2835,8 @@ bnx2_rx_skb(struct bnx2 *bp, struct bnx2_napi *bnapi, struct sk_buff *skb, pg_prod = NEXT_RX_BD(pg_prod); pg_cons = RX_PG_RING_IDX(NEXT_RX_BD(pg_cons)); } - bnapi->rx_pg_prod = pg_prod; - bnapi->rx_pg_cons = pg_cons; + rxr->rx_pg_prod = pg_prod; + rxr->rx_pg_cons = pg_cons; } return 0; } @@ -2733,8 +2844,11 @@ bnx2_rx_skb(struct bnx2 *bp, struct bnx2_napi *bnapi, struct sk_buff *skb, static inline u16 bnx2_get_hw_rx_cons(struct bnx2_napi *bnapi) { - u16 cons = bnapi->status_blk->status_rx_quick_consumer_index0; + u16 cons; + /* Tell compiler that status block fields can change. */ + barrier(); + cons = *bnapi->hw_rx_cons_ptr; if (unlikely((cons & MAX_RX_DESC_CNT) == MAX_RX_DESC_CNT)) cons++; return cons; @@ -2743,13 +2857,14 @@ bnx2_get_hw_rx_cons(struct bnx2_napi *bnapi) static int bnx2_rx_int(struct bnx2 *bp, struct bnx2_napi *bnapi, int budget) { + struct bnx2_rx_ring_info *rxr = &bnapi->rx_ring; u16 hw_cons, sw_cons, sw_ring_cons, sw_prod, sw_ring_prod; struct l2_fhdr *rx_hdr; int rx_pkt = 0, pg_ring_used = 0; hw_cons = bnx2_get_hw_rx_cons(bnapi); - sw_cons = bnapi->rx_cons; - sw_prod = bnapi->rx_prod; + sw_cons = rxr->rx_cons; + sw_prod = rxr->rx_prod; /* Memory barrier necessary as speculative reads of the rx * buffer can be ahead of the index in the status block @@ -2765,7 +2880,7 @@ bnx2_rx_int(struct bnx2 *bp, struct bnx2_napi *bnapi, int budget) sw_ring_cons = RX_RING_IDX(sw_cons); sw_ring_prod = RX_RING_IDX(sw_prod); - rx_buf = &bp->rx_buf_ring[sw_ring_cons]; + rx_buf = &rxr->rx_buf_ring[sw_ring_cons]; skb = rx_buf->skb; rx_buf->skb = NULL; @@ -2773,7 +2888,8 @@ bnx2_rx_int(struct bnx2 *bp, struct bnx2_napi *bnapi, int budget) dma_addr = pci_unmap_addr(rx_buf, mapping); pci_dma_sync_single_for_cpu(bp->pdev, dma_addr, - bp->rx_offset + RX_COPY_THRESH, PCI_DMA_FROMDEVICE); + BNX2_RX_OFFSET + BNX2_RX_COPY_THRESH, + PCI_DMA_FROMDEVICE); rx_hdr = (struct l2_fhdr *) skb->data; len = rx_hdr->l2_fhdr_pkt_len; @@ -2785,7 +2901,7 @@ bnx2_rx_int(struct bnx2 *bp, struct bnx2_napi *bnapi, int budget) L2_FHDR_ERRORS_TOO_SHORT | L2_FHDR_ERRORS_GIANT_FRAME)) { - bnx2_reuse_rx_skb(bp, bnapi, skb, sw_ring_cons, + bnx2_reuse_rx_skb(bp, rxr, skb, sw_ring_cons, sw_ring_prod); goto next_rx; } @@ -2805,22 +2921,23 @@ bnx2_rx_int(struct bnx2 *bp, struct bnx2_napi *bnapi, int budget) new_skb = netdev_alloc_skb(bp->dev, len + 2); if (new_skb == NULL) { - bnx2_reuse_rx_skb(bp, bnapi, skb, sw_ring_cons, + bnx2_reuse_rx_skb(bp, rxr, skb, sw_ring_cons, sw_ring_prod); goto next_rx; } /* aligned copy */ - skb_copy_from_linear_data_offset(skb, bp->rx_offset - 2, + skb_copy_from_linear_data_offset(skb, + BNX2_RX_OFFSET - 2, new_skb->data, len + 2); skb_reserve(new_skb, 2); skb_put(new_skb, len); - bnx2_reuse_rx_skb(bp, bnapi, skb, + bnx2_reuse_rx_skb(bp, rxr, skb, sw_ring_cons, sw_ring_prod); skb = new_skb; - } else if (unlikely(bnx2_rx_skb(bp, bnapi, skb, len, hdr_len, + } else if (unlikely(bnx2_rx_skb(bp, rxr, skb, len, hdr_len, dma_addr, (sw_ring_cons << 16) | sw_ring_prod))) goto next_rx; @@ -2869,16 +2986,15 @@ next_rx: rmb(); } } - bnapi->rx_cons = sw_cons; - bnapi->rx_prod = sw_prod; + rxr->rx_cons = sw_cons; + rxr->rx_prod = sw_prod; if (pg_ring_used) - REG_WR16(bp, MB_RX_CID_ADDR + BNX2_L2CTX_HOST_PG_BDIDX, - bnapi->rx_pg_prod); + REG_WR16(bp, rxr->rx_pg_bidx_addr, rxr->rx_pg_prod); - REG_WR16(bp, MB_RX_CID_ADDR + BNX2_L2CTX_HOST_BDIDX, sw_prod); + REG_WR16(bp, rxr->rx_bidx_addr, sw_prod); - REG_WR(bp, MB_RX_CID_ADDR + BNX2_L2CTX_HOST_BSEQ, bnapi->rx_prod_bseq); + REG_WR(bp, rxr->rx_bseq_addr, rxr->rx_prod_bseq); mmiowb(); @@ -2892,11 +3008,11 @@ next_rx: static irqreturn_t bnx2_msi(int irq, void *dev_instance) { - struct net_device *dev = dev_instance; - struct bnx2 *bp = netdev_priv(dev); - struct bnx2_napi *bnapi = &bp->bnx2_napi[0]; + struct bnx2_napi *bnapi = dev_instance; + struct bnx2 *bp = bnapi->bp; + struct net_device *dev = bp->dev; - prefetch(bnapi->status_blk); + prefetch(bnapi->status_blk.msi); REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD, BNX2_PCICFG_INT_ACK_CMD_USE_INT_HC_PARAM | BNX2_PCICFG_INT_ACK_CMD_MASK_INT); @@ -2913,11 +3029,11 @@ bnx2_msi(int irq, void *dev_instance) static irqreturn_t bnx2_msi_1shot(int irq, void *dev_instance) { - struct net_device *dev = dev_instance; - struct bnx2 *bp = netdev_priv(dev); - struct bnx2_napi *bnapi = &bp->bnx2_napi[0]; + struct bnx2_napi *bnapi = dev_instance; + struct bnx2 *bp = bnapi->bp; + struct net_device *dev = bp->dev; - prefetch(bnapi->status_blk); + prefetch(bnapi->status_blk.msi); /* Return here if interrupt is disabled. */ if (unlikely(atomic_read(&bp->intr_sem) != 0)) @@ -2931,10 +3047,10 @@ bnx2_msi_1shot(int irq, void *dev_instance) static irqreturn_t bnx2_interrupt(int irq, void *dev_instance) { - struct net_device *dev = dev_instance; - struct bnx2 *bp = netdev_priv(dev); - struct bnx2_napi *bnapi = &bp->bnx2_napi[0]; - struct status_block *sblk = bnapi->status_blk; + struct bnx2_napi *bnapi = dev_instance; + struct bnx2 *bp = bnapi->bp; + struct net_device *dev = bp->dev; + struct status_block *sblk = bnapi->status_blk.msi; /* When using INTx, it is possible for the interrupt to arrive * at the CPU before the status block posted prior to the @@ -2968,21 +3084,16 @@ bnx2_interrupt(int irq, void *dev_instance) return IRQ_HANDLED; } -static irqreturn_t -bnx2_tx_msix(int irq, void *dev_instance) +static inline int +bnx2_has_fast_work(struct bnx2_napi *bnapi) { - struct net_device *dev = dev_instance; - struct bnx2 *bp = netdev_priv(dev); - struct bnx2_napi *bnapi = &bp->bnx2_napi[BNX2_TX_VEC]; - - prefetch(bnapi->status_blk_msix); + struct bnx2_tx_ring_info *txr = &bnapi->tx_ring; + struct bnx2_rx_ring_info *rxr = &bnapi->rx_ring; - /* Return here if interrupt is disabled. */ - if (unlikely(atomic_read(&bp->intr_sem) != 0)) - return IRQ_HANDLED; - - netif_rx_schedule(dev, &bnapi->napi); - return IRQ_HANDLED; + if ((bnx2_get_hw_rx_cons(bnapi) != rxr->rx_cons) || + (bnx2_get_hw_tx_cons(bnapi) != txr->hw_tx_cons)) + return 1; + return 0; } #define STATUS_ATTN_EVENTS (STATUS_ATTN_BITS_LINK_STATE | \ @@ -2991,10 +3102,9 @@ bnx2_tx_msix(int irq, void *dev_instance) static inline int bnx2_has_work(struct bnx2_napi *bnapi) { - struct status_block *sblk = bnapi->status_blk; + struct status_block *sblk = bnapi->status_blk.msi; - if ((bnx2_get_hw_rx_cons(bnapi) != bnapi->rx_cons) || - (bnx2_get_hw_tx_cons(bnapi) != bnapi->hw_tx_cons)) + if (bnx2_has_fast_work(bnapi)) return 1; if ((sblk->status_attn_bits & STATUS_ATTN_EVENTS) != @@ -3004,33 +3114,9 @@ bnx2_has_work(struct bnx2_napi *bnapi) return 0; } -static int bnx2_tx_poll(struct napi_struct *napi, int budget) -{ - struct bnx2_napi *bnapi = container_of(napi, struct bnx2_napi, napi); - struct bnx2 *bp = bnapi->bp; - int work_done = 0; - struct status_block_msix *sblk = bnapi->status_blk_msix; - - do { - work_done += bnx2_tx_int(bp, bnapi, budget - work_done); - if (unlikely(work_done >= budget)) - return work_done; - - bnapi->last_status_idx = sblk->status_idx; - rmb(); - } while (bnx2_get_hw_tx_cons(bnapi) != bnapi->hw_tx_cons); - - netif_rx_complete(bp->dev, napi); - REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD, bnapi->int_num | - BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID | - bnapi->last_status_idx); - return work_done; -} - -static int bnx2_poll_work(struct bnx2 *bp, struct bnx2_napi *bnapi, - int work_done, int budget) +static void bnx2_poll_link(struct bnx2 *bp, struct bnx2_napi *bnapi) { - struct status_block *sblk = bnapi->status_blk; + struct status_block *sblk = bnapi->status_blk.msi; u32 status_attn_bits = sblk->status_attn_bits; u32 status_attn_bits_ack = sblk->status_attn_bits_ack; @@ -3046,24 +3132,60 @@ static int bnx2_poll_work(struct bnx2 *bp, struct bnx2_napi *bnapi, bp->hc_cmd | BNX2_HC_COMMAND_COAL_NOW_WO_INT); REG_RD(bp, BNX2_HC_COMMAND); } +} - if (bnx2_get_hw_tx_cons(bnapi) != bnapi->hw_tx_cons) +static int bnx2_poll_work(struct bnx2 *bp, struct bnx2_napi *bnapi, + int work_done, int budget) +{ + struct bnx2_tx_ring_info *txr = &bnapi->tx_ring; + struct bnx2_rx_ring_info *rxr = &bnapi->rx_ring; + + if (bnx2_get_hw_tx_cons(bnapi) != txr->hw_tx_cons) bnx2_tx_int(bp, bnapi, 0); - if (bnx2_get_hw_rx_cons(bnapi) != bnapi->rx_cons) + if (bnx2_get_hw_rx_cons(bnapi) != rxr->rx_cons) work_done += bnx2_rx_int(bp, bnapi, budget - work_done); return work_done; } +static int bnx2_poll_msix(struct napi_struct *napi, int budget) +{ + struct bnx2_napi *bnapi = container_of(napi, struct bnx2_napi, napi); + struct bnx2 *bp = bnapi->bp; + int work_done = 0; + struct status_block_msix *sblk = bnapi->status_blk.msix; + + while (1) { + work_done = bnx2_poll_work(bp, bnapi, work_done, budget); + if (unlikely(work_done >= budget)) + break; + + bnapi->last_status_idx = sblk->status_idx; + /* status idx must be read before checking for more work. */ + rmb(); + if (likely(!bnx2_has_fast_work(bnapi))) { + + netif_rx_complete(bp->dev, napi); + REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD, bnapi->int_num | + BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID | + bnapi->last_status_idx); + break; + } + } + return work_done; +} + static int bnx2_poll(struct napi_struct *napi, int budget) { struct bnx2_napi *bnapi = container_of(napi, struct bnx2_napi, napi); struct bnx2 *bp = bnapi->bp; int work_done = 0; - struct status_block *sblk = bnapi->status_blk; + struct status_block *sblk = bnapi->status_blk.msi; while (1) { + bnx2_poll_link(bp, bnapi); + work_done = bnx2_poll_work(bp, bnapi, work_done, budget); if (unlikely(work_done >= budget)) @@ -3106,6 +3228,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; int i; spin_lock_bh(&bp->phy_lock); @@ -3161,6 +3284,25 @@ 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 + BNX2_START_UNICAST_ADDRESS_INDEX); + sort_mode |= (1 << + (i + BNX2_START_UNICAST_ADDRESS_INDEX)); + uc_ptr = uc_ptr->next; + } + + } + if (rx_mode != bp->rx_mode) { bp->rx_mode = rx_mode; REG_WR(bp, BNX2_EMAC_RX_MODE, rx_mode); @@ -3213,7 +3355,7 @@ load_rv2p_fw(struct bnx2 *bp, __le32 *rv2p_code, u32 rv2p_code_len, } static int -load_cpu_fw(struct bnx2 *bp, struct cpu_reg *cpu_reg, struct fw_info *fw) +load_cpu_fw(struct bnx2 *bp, const struct cpu_reg *cpu_reg, struct fw_info *fw) { u32 offset; u32 val; @@ -3297,7 +3439,6 @@ load_cpu_fw(struct bnx2 *bp, struct cpu_reg *cpu_reg, struct fw_info *fw) static int bnx2_init_cpus(struct bnx2 *bp) { - struct cpu_reg cpu_reg; struct fw_info *fw; int rc, rv2p_len; void *text, *rv2p; @@ -3333,122 +3474,57 @@ bnx2_init_cpus(struct bnx2 *bp) load_rv2p_fw(bp, text, rc /* == len */, RV2P_PROC2); /* Initialize the RX Processor. */ - cpu_reg.mode = BNX2_RXP_CPU_MODE; - cpu_reg.mode_value_halt = BNX2_RXP_CPU_MODE_SOFT_HALT; - cpu_reg.mode_value_sstep = BNX2_RXP_CPU_MODE_STEP_ENA; - cpu_reg.state = BNX2_RXP_CPU_STATE; - cpu_reg.state_value_clear = 0xffffff; - cpu_reg.gpr0 = BNX2_RXP_CPU_REG_FILE; - cpu_reg.evmask = BNX2_RXP_CPU_EVENT_MASK; - cpu_reg.pc = BNX2_RXP_CPU_PROGRAM_COUNTER; - cpu_reg.inst = BNX2_RXP_CPU_INSTRUCTION; - cpu_reg.bp = BNX2_RXP_CPU_HW_BREAKPOINT; - cpu_reg.spad_base = BNX2_RXP_SCRATCH; - cpu_reg.mips_view_base = 0x8000000; - if (CHIP_NUM(bp) == CHIP_NUM_5709) fw = &bnx2_rxp_fw_09; else fw = &bnx2_rxp_fw_06; fw->text = text; - rc = load_cpu_fw(bp, &cpu_reg, fw); + rc = load_cpu_fw(bp, &cpu_reg_rxp, fw); if (rc) goto init_cpu_err; /* Initialize the TX Processor. */ - cpu_reg.mode = BNX2_TXP_CPU_MODE; - cpu_reg.mode_value_halt = BNX2_TXP_CPU_MODE_SOFT_HALT; - cpu_reg.mode_value_sstep = BNX2_TXP_CPU_MODE_STEP_ENA; - cpu_reg.state = BNX2_TXP_CPU_STATE; - cpu_reg.state_value_clear = 0xffffff; - cpu_reg.gpr0 = BNX2_TXP_CPU_REG_FILE; - cpu_reg.evmask = BNX2_TXP_CPU_EVENT_MASK; - cpu_reg.pc = BNX2_TXP_CPU_PROGRAM_COUNTER; - cpu_reg.inst = BNX2_TXP_CPU_INSTRUCTION; - cpu_reg.bp = BNX2_TXP_CPU_HW_BREAKPOINT; - cpu_reg.spad_base = BNX2_TXP_SCRATCH; - cpu_reg.mips_view_base = 0x8000000; - if (CHIP_NUM(bp) == CHIP_NUM_5709) fw = &bnx2_txp_fw_09; else fw = &bnx2_txp_fw_06; fw->text = text; - rc = load_cpu_fw(bp, &cpu_reg, fw); + rc = load_cpu_fw(bp, &cpu_reg_txp, fw); if (rc) goto init_cpu_err; /* Initialize the TX Patch-up Processor. */ - cpu_reg.mode = BNX2_TPAT_CPU_MODE; - cpu_reg.mode_value_halt = BNX2_TPAT_CPU_MODE_SOFT_HALT; - cpu_reg.mode_value_sstep = BNX2_TPAT_CPU_MODE_STEP_ENA; - cpu_reg.state = BNX2_TPAT_CPU_STATE; - cpu_reg.state_value_clear = 0xffffff; - cpu_reg.gpr0 = BNX2_TPAT_CPU_REG_FILE; - cpu_reg.evmask = BNX2_TPAT_CPU_EVENT_MASK; - cpu_reg.pc = BNX2_TPAT_CPU_PROGRAM_COUNTER; - cpu_reg.inst = BNX2_TPAT_CPU_INSTRUCTION; - cpu_reg.bp = BNX2_TPAT_CPU_HW_BREAKPOINT; - cpu_reg.spad_base = BNX2_TPAT_SCRATCH; - cpu_reg.mips_view_base = 0x8000000; - if (CHIP_NUM(bp) == CHIP_NUM_5709) fw = &bnx2_tpat_fw_09; else fw = &bnx2_tpat_fw_06; fw->text = text; - rc = load_cpu_fw(bp, &cpu_reg, fw); + rc = load_cpu_fw(bp, &cpu_reg_tpat, fw); if (rc) goto init_cpu_err; /* Initialize the Completion Processor. */ - cpu_reg.mode = BNX2_COM_CPU_MODE; - cpu_reg.mode_value_halt = BNX2_COM_CPU_MODE_SOFT_HALT; - cpu_reg.mode_value_sstep = BNX2_COM_CPU_MODE_STEP_ENA; - cpu_reg.state = BNX2_COM_CPU_STATE; - cpu_reg.state_value_clear = 0xffffff; - cpu_reg.gpr0 = BNX2_COM_CPU_REG_FILE; - cpu_reg.evmask = BNX2_COM_CPU_EVENT_MASK; - cpu_reg.pc = BNX2_COM_CPU_PROGRAM_COUNTER; - cpu_reg.inst = BNX2_COM_CPU_INSTRUCTION; - cpu_reg.bp = BNX2_COM_CPU_HW_BREAKPOINT; - cpu_reg.spad_base = BNX2_COM_SCRATCH; - cpu_reg.mips_view_base = 0x8000000; - if (CHIP_NUM(bp) == CHIP_NUM_5709) fw = &bnx2_com_fw_09; else fw = &bnx2_com_fw_06; fw->text = text; - rc = load_cpu_fw(bp, &cpu_reg, fw); + rc = load_cpu_fw(bp, &cpu_reg_com, fw); if (rc) goto init_cpu_err; /* Initialize the Command Processor. */ - cpu_reg.mode = BNX2_CP_CPU_MODE; - cpu_reg.mode_value_halt = BNX2_CP_CPU_MODE_SOFT_HALT; - cpu_reg.mode_value_sstep = BNX2_CP_CPU_MODE_STEP_ENA; - cpu_reg.state = BNX2_CP_CPU_STATE; - cpu_reg.state_value_clear = 0xffffff; - cpu_reg.gpr0 = BNX2_CP_CPU_REG_FILE; - cpu_reg.evmask = BNX2_CP_CPU_EVENT_MASK; - cpu_reg.pc = BNX2_CP_CPU_PROGRAM_COUNTER; - cpu_reg.inst = BNX2_CP_CPU_INSTRUCTION; - cpu_reg.bp = BNX2_CP_CPU_HW_BREAKPOINT; - cpu_reg.spad_base = BNX2_CP_SCRATCH; - cpu_reg.mips_view_base = 0x8000000; - if (CHIP_NUM(bp) == CHIP_NUM_5709) fw = &bnx2_cp_fw_09; else fw = &bnx2_cp_fw_06; fw->text = text; - rc = load_cpu_fw(bp, &cpu_reg, fw); + rc = load_cpu_fw(bp, &cpu_reg_cp, fw); init_cpu_err: vfree(text); @@ -3511,7 +3587,7 @@ bnx2_set_power_state(struct bnx2 *bp, pci_power_t state) bp->autoneg = autoneg; bp->advertising = advertising; - bnx2_set_mac_addr(bp); + bnx2_set_mac_addr(bp, bp->dev->dev_addr, 0); val = REG_RD(bp, BNX2_EMAC_MODE); @@ -3562,7 +3638,8 @@ bnx2_set_power_state(struct bnx2 *bp, pci_power_t state) } if (!(bp->flags & BNX2_FLAG_NO_WOL)) - bnx2_fw_sync(bp, BNX2_DRV_MSG_DATA_WAIT3 | wol_msg, 0); + bnx2_fw_sync(bp, BNX2_DRV_MSG_DATA_WAIT3 | wol_msg, + 1, 0); pmcsr &= ~PCI_PM_CTRL_STATE_MASK; if ((CHIP_ID(bp) == CHIP_ID_5706_A0) || @@ -4203,35 +4280,43 @@ nvram_write_end: } static void -bnx2_init_remote_phy(struct bnx2 *bp) +bnx2_init_fw_cap(struct bnx2 *bp) { - u32 val; + u32 val, sig = 0; bp->phy_flags &= ~BNX2_PHY_FLAG_REMOTE_PHY_CAP; - if (!(bp->phy_flags & BNX2_PHY_FLAG_SERDES)) - return; + bp->flags &= ~BNX2_FLAG_CAN_KEEP_VLAN; + + if (!(bp->flags & BNX2_FLAG_ASF_ENABLE)) + bp->flags |= BNX2_FLAG_CAN_KEEP_VLAN; val = bnx2_shmem_rd(bp, BNX2_FW_CAP_MB); if ((val & BNX2_FW_CAP_SIGNATURE_MASK) != BNX2_FW_CAP_SIGNATURE) return; - if (val & BNX2_FW_CAP_REMOTE_PHY_CAPABLE) { + if ((val & BNX2_FW_CAP_CAN_KEEP_VLAN) == BNX2_FW_CAP_CAN_KEEP_VLAN) { + bp->flags |= BNX2_FLAG_CAN_KEEP_VLAN; + sig |= BNX2_DRV_ACK_CAP_SIGNATURE | BNX2_FW_CAP_CAN_KEEP_VLAN; + } + + if ((bp->phy_flags & BNX2_PHY_FLAG_SERDES) && + (val & BNX2_FW_CAP_REMOTE_PHY_CAPABLE)) { + u32 link; + bp->phy_flags |= BNX2_PHY_FLAG_REMOTE_PHY_CAP; - val = bnx2_shmem_rd(bp, BNX2_LINK_STATUS); - if (val & BNX2_LINK_STATUS_SERDES_LINK) + link = bnx2_shmem_rd(bp, BNX2_LINK_STATUS); + if (link & BNX2_LINK_STATUS_SERDES_LINK) bp->phy_port = PORT_FIBRE; else bp->phy_port = PORT_TP; - if (netif_running(bp->dev)) { - u32 sig; - - sig = BNX2_DRV_ACK_CAP_SIGNATURE | - BNX2_FW_CAP_REMOTE_PHY_CAPABLE; - bnx2_shmem_wr(bp, BNX2_DRV_ACK_CAP_MB, sig); - } + sig |= BNX2_DRV_ACK_CAP_SIGNATURE | + BNX2_FW_CAP_REMOTE_PHY_CAPABLE; } + + if (netif_running(bp->dev) && sig) + bnx2_shmem_wr(bp, BNX2_DRV_ACK_CAP_MB, sig); } static void @@ -4261,7 +4346,7 @@ bnx2_reset_chip(struct bnx2 *bp, u32 reset_code) udelay(5); /* Wait for the firmware to tell us it is ok to issue a reset. */ - bnx2_fw_sync(bp, BNX2_DRV_MSG_DATA_WAIT0 | reset_code, 1); + bnx2_fw_sync(bp, BNX2_DRV_MSG_DATA_WAIT0 | reset_code, 1, 1); /* Deposit a driver reset signature so the firmware knows that * this is a soft reset. */ @@ -4322,13 +4407,13 @@ bnx2_reset_chip(struct bnx2 *bp, u32 reset_code) } /* Wait for the firmware to finish its initialization. */ - rc = bnx2_fw_sync(bp, BNX2_DRV_MSG_DATA_WAIT1 | reset_code, 0); + rc = bnx2_fw_sync(bp, BNX2_DRV_MSG_DATA_WAIT1 | reset_code, 1, 0); if (rc) return rc; spin_lock_bh(&bp->phy_lock); old_port = bp->phy_port; - bnx2_init_remote_phy(bp); + bnx2_init_fw_cap(bp); if ((bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP) && old_port != bp->phy_port) bnx2_set_default_remote_link(bp); @@ -4412,7 +4497,7 @@ bnx2_init_chip(struct bnx2 *bp) bnx2_init_nvram(bp); - bnx2_set_mac_addr(bp); + bnx2_set_mac_addr(bp, bp->dev->dev_addr, 0); val = REG_RD(bp, BNX2_MQ_CONFIG); val &= ~BNX2_MQ_CONFIG_KNL_BYP_BLK_SIZE; @@ -4498,15 +4583,25 @@ bnx2_init_chip(struct bnx2 *bp) BNX2_HC_CONFIG_COLLECT_STATS; } - if (bp->flags & BNX2_FLAG_USING_MSIX) { - u32 base = ((BNX2_TX_VEC - 1) * BNX2_HC_SB_CONFIG_SIZE) + - BNX2_HC_SB_CONFIG_1; - + if (bp->irq_nvecs > 1) { REG_WR(bp, BNX2_HC_MSIX_BIT_VECTOR, BNX2_HC_MSIX_BIT_VECTOR_VAL); + val |= BNX2_HC_CONFIG_SB_ADDR_INC_128B; + } + + if (bp->flags & BNX2_FLAG_ONE_SHOT_MSI) + val |= BNX2_HC_CONFIG_ONE_SHOT; + + REG_WR(bp, BNX2_HC_CONFIG, val); + + for (i = 1; i < bp->irq_nvecs; i++) { + u32 base = ((i - 1) * BNX2_HC_SB_CONFIG_SIZE) + + BNX2_HC_SB_CONFIG_1; + REG_WR(bp, base, BNX2_HC_SB_CONFIG_1_TX_TMR_MODE | + BNX2_HC_SB_CONFIG_1_RX_TMR_MODE | BNX2_HC_SB_CONFIG_1_ONE_SHOT); REG_WR(bp, base + BNX2_HC_TX_QUICK_CONS_TRIP_OFF, @@ -4516,13 +4611,13 @@ bnx2_init_chip(struct bnx2 *bp) REG_WR(bp, base + BNX2_HC_TX_TICKS_OFF, (bp->tx_ticks_int << 16) | bp->tx_ticks); - val |= BNX2_HC_CONFIG_SB_ADDR_INC_128B; - } + REG_WR(bp, base + BNX2_HC_RX_QUICK_CONS_TRIP_OFF, + (bp->rx_quick_cons_trip_int << 16) | + bp->rx_quick_cons_trip); - if (bp->flags & BNX2_FLAG_ONE_SHOT_MSI) - val |= BNX2_HC_CONFIG_ONE_SHOT; - - REG_WR(bp, BNX2_HC_CONFIG, val); + REG_WR(bp, base + BNX2_HC_RX_TICKS_OFF, + (bp->rx_ticks_int << 16) | bp->rx_ticks); + } /* Clear internal stats counters. */ REG_WR(bp, BNX2_HC_COMMAND, BNX2_HC_COMMAND_CLR_STAT_NOW); @@ -4538,7 +4633,7 @@ bnx2_init_chip(struct bnx2 *bp) REG_WR(bp, BNX2_MISC_NEW_CORE_CTL, val); } rc = bnx2_fw_sync(bp, BNX2_DRV_MSG_DATA_WAIT2 | BNX2_DRV_MSG_CODE_RESET, - 0); + 1, 0); REG_WR(bp, BNX2_MISC_ENABLE_SET_BITS, BNX2_MISC_ENABLE_DEFAULT); REG_RD(bp, BNX2_MISC_ENABLE_SET_BITS); @@ -4554,23 +4649,27 @@ static void bnx2_clear_ring_states(struct bnx2 *bp) { struct bnx2_napi *bnapi; + struct bnx2_tx_ring_info *txr; + struct bnx2_rx_ring_info *rxr; int i; for (i = 0; i < BNX2_MAX_MSIX_VEC; i++) { bnapi = &bp->bnx2_napi[i]; + txr = &bnapi->tx_ring; + rxr = &bnapi->rx_ring; - bnapi->tx_cons = 0; - bnapi->hw_tx_cons = 0; - bnapi->rx_prod_bseq = 0; - bnapi->rx_prod = 0; - bnapi->rx_cons = 0; - bnapi->rx_pg_prod = 0; - bnapi->rx_pg_cons = 0; + txr->tx_cons = 0; + txr->hw_tx_cons = 0; + rxr->rx_prod_bseq = 0; + rxr->rx_prod = 0; + rxr->rx_cons = 0; + rxr->rx_pg_prod = 0; + rxr->rx_pg_cons = 0; } } static void -bnx2_init_tx_context(struct bnx2 *bp, u32 cid) +bnx2_init_tx_context(struct bnx2 *bp, u32 cid, struct bnx2_tx_ring_info *txr) { u32 val, offset0, offset1, offset2, offset3; u32 cid_addr = GET_CID_ADDR(cid); @@ -4592,43 +4691,43 @@ bnx2_init_tx_context(struct bnx2 *bp, u32 cid) val = BNX2_L2CTX_CMD_TYPE_TYPE_L2 | (8 << 16); bnx2_ctx_wr(bp, cid_addr, offset1, val); - val = (u64) bp->tx_desc_mapping >> 32; + val = (u64) txr->tx_desc_mapping >> 32; bnx2_ctx_wr(bp, cid_addr, offset2, val); - val = (u64) bp->tx_desc_mapping & 0xffffffff; + val = (u64) txr->tx_desc_mapping & 0xffffffff; bnx2_ctx_wr(bp, cid_addr, offset3, val); } static void -bnx2_init_tx_ring(struct bnx2 *bp) +bnx2_init_tx_ring(struct bnx2 *bp, int ring_num) { struct tx_bd *txbd; u32 cid = TX_CID; struct bnx2_napi *bnapi; + struct bnx2_tx_ring_info *txr; - bp->tx_vec = 0; - if (bp->flags & BNX2_FLAG_USING_MSIX) { - cid = TX_TSS_CID; - bp->tx_vec = BNX2_TX_VEC; - REG_WR(bp, BNX2_TSCH_TSS_CFG, BNX2_TX_INT_NUM | - (TX_TSS_CID << 7)); - } - bnapi = &bp->bnx2_napi[bp->tx_vec]; + bnapi = &bp->bnx2_napi[ring_num]; + txr = &bnapi->tx_ring; + + if (ring_num == 0) + cid = TX_CID; + else + cid = TX_TSS_CID + ring_num - 1; bp->tx_wake_thresh = bp->tx_ring_size / 2; - txbd = &bp->tx_desc_ring[MAX_TX_DESC_CNT]; + txbd = &txr->tx_desc_ring[MAX_TX_DESC_CNT]; - txbd->tx_bd_haddr_hi = (u64) bp->tx_desc_mapping >> 32; - txbd->tx_bd_haddr_lo = (u64) bp->tx_desc_mapping & 0xffffffff; + txbd->tx_bd_haddr_hi = (u64) txr->tx_desc_mapping >> 32; + txbd->tx_bd_haddr_lo = (u64) txr->tx_desc_mapping & 0xffffffff; - bp->tx_prod = 0; - bp->tx_prod_bseq = 0; + txr->tx_prod = 0; + txr->tx_prod_bseq = 0; - bp->tx_bidx_addr = MB_GET_CID_ADDR(cid) + BNX2_L2CTX_TX_HOST_BIDX; - bp->tx_bseq_addr = MB_GET_CID_ADDR(cid) + BNX2_L2CTX_TX_HOST_BSEQ; + txr->tx_bidx_addr = MB_GET_CID_ADDR(cid) + BNX2_L2CTX_TX_HOST_BIDX; + txr->tx_bseq_addr = MB_GET_CID_ADDR(cid) + BNX2_L2CTX_TX_HOST_BSEQ; - bnx2_init_tx_context(bp, cid); + bnx2_init_tx_context(bp, cid, txr); } static void @@ -4656,17 +4755,25 @@ bnx2_init_rxbd_rings(struct rx_bd *rx_ring[], dma_addr_t dma[], u32 buf_size, } static void -bnx2_init_rx_ring(struct bnx2 *bp) +bnx2_init_rx_ring(struct bnx2 *bp, int ring_num) { int i; u16 prod, ring_prod; - u32 val, rx_cid_addr = GET_CID_ADDR(RX_CID); - struct bnx2_napi *bnapi = &bp->bnx2_napi[0]; + u32 cid, rx_cid_addr, val; + struct bnx2_napi *bnapi = &bp->bnx2_napi[ring_num]; + struct bnx2_rx_ring_info *rxr = &bnapi->rx_ring; - bnx2_init_rxbd_rings(bp->rx_desc_ring, bp->rx_desc_mapping, + if (ring_num == 0) + cid = RX_CID; + else + cid = RX_RSS_CID + ring_num - 1; + + rx_cid_addr = GET_CID_ADDR(cid); + + bnx2_init_rxbd_rings(rxr->rx_desc_ring, rxr->rx_desc_mapping, bp->rx_buf_use_size, bp->rx_max_ring); - bnx2_init_rx_context0(bp); + bnx2_init_rx_context(bp, cid); if (CHIP_NUM(bp) == CHIP_NUM_5709) { val = REG_RD(bp, BNX2_MQ_MAP_L2_5); @@ -4675,54 +4782,101 @@ bnx2_init_rx_ring(struct bnx2 *bp) bnx2_ctx_wr(bp, rx_cid_addr, BNX2_L2CTX_PG_BUF_SIZE, 0); if (bp->rx_pg_ring_size) { - bnx2_init_rxbd_rings(bp->rx_pg_desc_ring, - bp->rx_pg_desc_mapping, + bnx2_init_rxbd_rings(rxr->rx_pg_desc_ring, + rxr->rx_pg_desc_mapping, PAGE_SIZE, bp->rx_max_pg_ring); val = (bp->rx_buf_use_size << 16) | PAGE_SIZE; bnx2_ctx_wr(bp, rx_cid_addr, BNX2_L2CTX_PG_BUF_SIZE, val); bnx2_ctx_wr(bp, rx_cid_addr, BNX2_L2CTX_RBDC_KEY, - BNX2_L2CTX_RBDC_JUMBO_KEY); + BNX2_L2CTX_RBDC_JUMBO_KEY - ring_num); - val = (u64) bp->rx_pg_desc_mapping[0] >> 32; + val = (u64) rxr->rx_pg_desc_mapping[0] >> 32; bnx2_ctx_wr(bp, rx_cid_addr, BNX2_L2CTX_NX_PG_BDHADDR_HI, val); - val = (u64) bp->rx_pg_desc_mapping[0] & 0xffffffff; + val = (u64) rxr->rx_pg_desc_mapping[0] & 0xffffffff; bnx2_ctx_wr(bp, rx_cid_addr, BNX2_L2CTX_NX_PG_BDHADDR_LO, val); if (CHIP_NUM(bp) == CHIP_NUM_5709) REG_WR(bp, BNX2_MQ_MAP_L2_3, BNX2_MQ_MAP_L2_3_DEFAULT); } - val = (u64) bp->rx_desc_mapping[0] >> 32; + val = (u64) rxr->rx_desc_mapping[0] >> 32; bnx2_ctx_wr(bp, rx_cid_addr, BNX2_L2CTX_NX_BDHADDR_HI, val); - val = (u64) bp->rx_desc_mapping[0] & 0xffffffff; + val = (u64) rxr->rx_desc_mapping[0] & 0xffffffff; bnx2_ctx_wr(bp, rx_cid_addr, BNX2_L2CTX_NX_BDHADDR_LO, val); - ring_prod = prod = bnapi->rx_pg_prod; + ring_prod = prod = rxr->rx_pg_prod; for (i = 0; i < bp->rx_pg_ring_size; i++) { - if (bnx2_alloc_rx_page(bp, ring_prod) < 0) + if (bnx2_alloc_rx_page(bp, rxr, ring_prod) < 0) break; prod = NEXT_RX_BD(prod); ring_prod = RX_PG_RING_IDX(prod); } - bnapi->rx_pg_prod = prod; + rxr->rx_pg_prod = prod; - ring_prod = prod = bnapi->rx_prod; + ring_prod = prod = rxr->rx_prod; for (i = 0; i < bp->rx_ring_size; i++) { - if (bnx2_alloc_rx_skb(bp, bnapi, ring_prod) < 0) { + if (bnx2_alloc_rx_skb(bp, rxr, ring_prod) < 0) break; - } prod = NEXT_RX_BD(prod); ring_prod = RX_RING_IDX(prod); } - bnapi->rx_prod = prod; + rxr->rx_prod = prod; + + rxr->rx_bidx_addr = MB_GET_CID_ADDR(cid) + BNX2_L2CTX_HOST_BDIDX; + rxr->rx_bseq_addr = MB_GET_CID_ADDR(cid) + BNX2_L2CTX_HOST_BSEQ; + rxr->rx_pg_bidx_addr = MB_GET_CID_ADDR(cid) + BNX2_L2CTX_HOST_PG_BDIDX; - REG_WR16(bp, MB_RX_CID_ADDR + BNX2_L2CTX_HOST_PG_BDIDX, - bnapi->rx_pg_prod); - REG_WR16(bp, MB_RX_CID_ADDR + BNX2_L2CTX_HOST_BDIDX, prod); + REG_WR16(bp, rxr->rx_pg_bidx_addr, rxr->rx_pg_prod); + REG_WR16(bp, rxr->rx_bidx_addr, prod); - REG_WR(bp, MB_RX_CID_ADDR + BNX2_L2CTX_HOST_BSEQ, bnapi->rx_prod_bseq); + REG_WR(bp, rxr->rx_bseq_addr, rxr->rx_prod_bseq); +} + +static void +bnx2_init_all_rings(struct bnx2 *bp) +{ + int i; + u32 val; + + bnx2_clear_ring_states(bp); + + REG_WR(bp, BNX2_TSCH_TSS_CFG, 0); + for (i = 0; i < bp->num_tx_rings; i++) + bnx2_init_tx_ring(bp, i); + + if (bp->num_tx_rings > 1) + REG_WR(bp, BNX2_TSCH_TSS_CFG, ((bp->num_tx_rings - 1) << 24) | + (TX_TSS_CID << 7)); + + REG_WR(bp, BNX2_RLUP_RSS_CONFIG, 0); + bnx2_reg_wr_ind(bp, BNX2_RXP_SCRATCH_RSS_TBL_SZ, 0); + + for (i = 0; i < bp->num_rx_rings; i++) + bnx2_init_rx_ring(bp, i); + + if (bp->num_rx_rings > 1) { + u32 tbl_32; + u8 *tbl = (u8 *) &tbl_32; + + bnx2_reg_wr_ind(bp, BNX2_RXP_SCRATCH_RSS_TBL_SZ, + BNX2_RXP_SCRATCH_RSS_TBL_MAX_ENTRIES); + + for (i = 0; i < BNX2_RXP_SCRATCH_RSS_TBL_MAX_ENTRIES; i++) { + tbl[i % 4] = i % (bp->num_rx_rings - 1); + if ((i % 4) == 3) + bnx2_reg_wr_ind(bp, + BNX2_RXP_SCRATCH_RSS_TBL + i, + cpu_to_be32(tbl_32)); + } + + val = BNX2_RLUP_RSS_CONFIG_IPV4_RSS_TYPE_ALL_XI | + BNX2_RLUP_RSS_CONFIG_IPV6_RSS_TYPE_ALL_XI; + + REG_WR(bp, BNX2_RLUP_RSS_CONFIG, val); + + } } static u32 bnx2_find_max_ring(u32 ring_size, u32 max_size) @@ -4750,12 +4904,12 @@ bnx2_set_rx_ring_size(struct bnx2 *bp, u32 size) u32 rx_size, rx_space, jumbo_size; /* 8 for CRC and VLAN */ - rx_size = bp->dev->mtu + ETH_HLEN + bp->rx_offset + 8; + rx_size = bp->dev->mtu + ETH_HLEN + BNX2_RX_OFFSET + 8; rx_space = SKB_DATA_ALIGN(rx_size + BNX2_RX_ALIGN) + NET_SKB_PAD + sizeof(struct skb_shared_info); - bp->rx_copy_thresh = RX_COPY_THRESH; + bp->rx_copy_thresh = BNX2_RX_COPY_THRESH; bp->rx_pg_ring_size = 0; bp->rx_max_pg_ring = 0; bp->rx_max_pg_ring_idx = 0; @@ -4770,14 +4924,14 @@ bnx2_set_rx_ring_size(struct bnx2 *bp, u32 size) bp->rx_max_pg_ring = bnx2_find_max_ring(jumbo_size, MAX_RX_PG_RINGS); bp->rx_max_pg_ring_idx = (bp->rx_max_pg_ring * RX_DESC_CNT) - 1; - rx_size = RX_COPY_THRESH + bp->rx_offset; + rx_size = BNX2_RX_COPY_THRESH + BNX2_RX_OFFSET; bp->rx_copy_thresh = 0; } bp->rx_buf_use_size = rx_size; /* hw alignment */ bp->rx_buf_size = bp->rx_buf_use_size + BNX2_RX_ALIGN; - bp->rx_jumbo_thresh = rx_size - bp->rx_offset; + bp->rx_jumbo_thresh = rx_size - BNX2_RX_OFFSET; bp->rx_ring_size = size; bp->rx_max_ring = bnx2_find_max_ring(size, MAX_RX_RINGS); bp->rx_max_ring_idx = (bp->rx_max_ring * RX_DESC_CNT) - 1; @@ -4788,36 +4942,42 @@ bnx2_free_tx_skbs(struct bnx2 *bp) { int i; - if (bp->tx_buf_ring == NULL) - return; - - for (i = 0; i < TX_DESC_CNT; ) { - struct sw_bd *tx_buf = &bp->tx_buf_ring[i]; - struct sk_buff *skb = tx_buf->skb; - int j, last; + for (i = 0; i < bp->num_tx_rings; i++) { + struct bnx2_napi *bnapi = &bp->bnx2_napi[i]; + struct bnx2_tx_ring_info *txr = &bnapi->tx_ring; + int j; - if (skb == NULL) { - i++; + if (txr->tx_buf_ring == NULL) continue; - } - pci_unmap_single(bp->pdev, pci_unmap_addr(tx_buf, mapping), + for (j = 0; j < TX_DESC_CNT; ) { + struct sw_bd *tx_buf = &txr->tx_buf_ring[j]; + struct sk_buff *skb = tx_buf->skb; + int k, last; + + if (skb == NULL) { + j++; + continue; + } + + pci_unmap_single(bp->pdev, + pci_unmap_addr(tx_buf, mapping), skb_headlen(skb), PCI_DMA_TODEVICE); - tx_buf->skb = NULL; + tx_buf->skb = NULL; - last = skb_shinfo(skb)->nr_frags; - for (j = 0; j < last; j++) { - tx_buf = &bp->tx_buf_ring[i + j + 1]; - pci_unmap_page(bp->pdev, - pci_unmap_addr(tx_buf, mapping), - skb_shinfo(skb)->frags[j].size, - PCI_DMA_TODEVICE); + last = skb_shinfo(skb)->nr_frags; + for (k = 0; k < last; k++) { + tx_buf = &txr->tx_buf_ring[j + k + 1]; + pci_unmap_page(bp->pdev, + pci_unmap_addr(tx_buf, mapping), + skb_shinfo(skb)->frags[j].size, + PCI_DMA_TODEVICE); + } + dev_kfree_skb(skb); + j += k + 1; } - dev_kfree_skb(skb); - i += j + 1; } - } static void @@ -4825,25 +4985,33 @@ bnx2_free_rx_skbs(struct bnx2 *bp) { int i; - if (bp->rx_buf_ring == NULL) - return; + for (i = 0; i < bp->num_rx_rings; i++) { + struct bnx2_napi *bnapi = &bp->bnx2_napi[i]; + struct bnx2_rx_ring_info *rxr = &bnapi->rx_ring; + int j; - for (i = 0; i < bp->rx_max_ring_idx; i++) { - struct sw_bd *rx_buf = &bp->rx_buf_ring[i]; - struct sk_buff *skb = rx_buf->skb; + if (rxr->rx_buf_ring == NULL) + return; - if (skb == NULL) - continue; + for (j = 0; j < bp->rx_max_ring_idx; j++) { + struct sw_bd *rx_buf = &rxr->rx_buf_ring[j]; + struct sk_buff *skb = rx_buf->skb; - pci_unmap_single(bp->pdev, pci_unmap_addr(rx_buf, mapping), - bp->rx_buf_use_size, PCI_DMA_FROMDEVICE); + if (skb == NULL) + continue; - rx_buf->skb = NULL; + pci_unmap_single(bp->pdev, + pci_unmap_addr(rx_buf, mapping), + bp->rx_buf_use_size, + PCI_DMA_FROMDEVICE); - dev_kfree_skb(skb); + rx_buf->skb = NULL; + + dev_kfree_skb(skb); + } + for (j = 0; j < bp->rx_max_pg_ring_idx; j++) + bnx2_free_rx_page(bp, rxr, j); } - for (i = 0; i < bp->rx_max_pg_ring_idx; i++) - bnx2_free_rx_page(bp, i); } static void @@ -4866,14 +5034,12 @@ bnx2_reset_nic(struct bnx2 *bp, u32 reset_code) if ((rc = bnx2_init_chip(bp)) != 0) return rc; - bnx2_clear_ring_states(bp); - bnx2_init_tx_ring(bp); - bnx2_init_rx_ring(bp); + bnx2_init_all_rings(bp); return 0; } static int -bnx2_init_nic(struct bnx2 *bp) +bnx2_init_nic(struct bnx2 *bp, int reset_phy) { int rc; @@ -4881,7 +5047,7 @@ bnx2_init_nic(struct bnx2 *bp) return rc; spin_lock_bh(&bp->phy_lock); - bnx2_init_phy(bp); + bnx2_init_phy(bp, reset_phy); bnx2_set_link(bp); if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP) bnx2_remote_phy_event(bp); @@ -5141,11 +5307,13 @@ bnx2_run_loopback(struct bnx2 *bp, int loopback_mode) struct l2_fhdr *rx_hdr; int ret = -ENODEV; struct bnx2_napi *bnapi = &bp->bnx2_napi[0], *tx_napi; + struct bnx2_tx_ring_info *txr = &bnapi->tx_ring; + struct bnx2_rx_ring_info *rxr = &bnapi->rx_ring; tx_napi = bnapi; - if (bp->flags & BNX2_FLAG_USING_MSIX) - tx_napi = &bp->bnx2_napi[BNX2_TX_VEC]; + txr = &tx_napi->tx_ring; + rxr = &bnapi->rx_ring; if (loopback_mode == BNX2_MAC_LOOPBACK) { bp->loopback = MAC_LOOPBACK; bnx2_set_mac_loopback(bp); @@ -5183,7 +5351,7 @@ bnx2_run_loopback(struct bnx2 *bp, int loopback_mode) num_pkts = 0; - txbd = &bp->tx_desc_ring[TX_RING_IDX(bp->tx_prod)]; + txbd = &txr->tx_desc_ring[TX_RING_IDX(txr->tx_prod)]; txbd->tx_bd_haddr_hi = (u64) map >> 32; txbd->tx_bd_haddr_lo = (u64) map & 0xffffffff; @@ -5191,11 +5359,11 @@ bnx2_run_loopback(struct bnx2 *bp, int loopback_mode) txbd->tx_bd_vlan_tag_flags = TX_BD_FLAGS_START | TX_BD_FLAGS_END; num_pkts++; - bp->tx_prod = NEXT_TX_BD(bp->tx_prod); - bp->tx_prod_bseq += pkt_size; + txr->tx_prod = NEXT_TX_BD(txr->tx_prod); + txr->tx_prod_bseq += pkt_size; - REG_WR16(bp, bp->tx_bidx_addr, bp->tx_prod); - REG_WR(bp, bp->tx_bseq_addr, bp->tx_prod_bseq); + REG_WR16(bp, txr->tx_bidx_addr, txr->tx_prod); + REG_WR(bp, txr->tx_bseq_addr, txr->tx_prod_bseq); udelay(100); @@ -5209,7 +5377,7 @@ bnx2_run_loopback(struct bnx2 *bp, int loopback_mode) pci_unmap_single(bp->pdev, map, pkt_size, PCI_DMA_TODEVICE); dev_kfree_skb(skb); - if (bnx2_get_hw_tx_cons(tx_napi) != bp->tx_prod) + if (bnx2_get_hw_tx_cons(tx_napi) != txr->tx_prod) goto loopback_test_done; rx_idx = bnx2_get_hw_rx_cons(bnapi); @@ -5217,11 +5385,11 @@ bnx2_run_loopback(struct bnx2 *bp, int loopback_mode) goto loopback_test_done; } - rx_buf = &bp->rx_buf_ring[rx_start_idx]; + rx_buf = &rxr->rx_buf_ring[rx_start_idx]; rx_skb = rx_buf->skb; rx_hdr = (struct l2_fhdr *) rx_skb->data; - skb_reserve(rx_skb, bp->rx_offset); + skb_reserve(rx_skb, BNX2_RX_OFFSET); pci_dma_sync_single_for_cpu(bp->pdev, pci_unmap_addr(rx_buf, mapping), @@ -5269,7 +5437,7 @@ bnx2_test_loopback(struct bnx2 *bp) bnx2_reset_nic(bp, BNX2_DRV_MSG_CODE_RESET); spin_lock_bh(&bp->phy_lock); - bnx2_init_phy(bp); + bnx2_init_phy(bp, 1); spin_unlock_bh(&bp->phy_lock); if (bnx2_run_loopback(bp, BNX2_MAC_LOOPBACK)) rc |= BNX2_MAC_LOOPBACK_FAILED; @@ -5531,7 +5699,6 @@ bnx2_restart_timer: static int bnx2_request_irq(struct bnx2 *bp) { - struct net_device *dev = bp->dev; unsigned long flags; struct bnx2_irq *irq; int rc = 0, i; @@ -5544,7 +5711,7 @@ bnx2_request_irq(struct bnx2 *bp) for (i = 0; i < bp->irq_nvecs; i++) { irq = &bp->irq_tbl[i]; rc = request_irq(irq->vector, irq->handler, flags, irq->name, - dev); + &bp->bnx2_napi[i]); if (rc) break; irq->requested = 1; @@ -5555,14 +5722,13 @@ bnx2_request_irq(struct bnx2 *bp) static void bnx2_free_irq(struct bnx2 *bp) { - struct net_device *dev = bp->dev; struct bnx2_irq *irq; int i; for (i = 0; i < bp->irq_nvecs; i++) { irq = &bp->irq_tbl[i]; if (irq->requested) - free_irq(irq->vector, dev); + free_irq(irq->vector, &bp->bnx2_napi[i]); irq->requested = 0; } if (bp->flags & BNX2_FLAG_USING_MSI) @@ -5574,7 +5740,7 @@ bnx2_free_irq(struct bnx2 *bp) } static void -bnx2_enable_msix(struct bnx2 *bp) +bnx2_enable_msix(struct bnx2 *bp, int msix_vecs) { int i, rc; struct msix_entry msix_ent[BNX2_MAX_MSIX_VEC]; @@ -5587,21 +5753,16 @@ bnx2_enable_msix(struct bnx2 *bp) for (i = 0; i < BNX2_MAX_MSIX_VEC; i++) { msix_ent[i].entry = i; msix_ent[i].vector = 0; + + strcpy(bp->irq_tbl[i].name, bp->dev->name); + bp->irq_tbl[i].handler = bnx2_msi_1shot; } rc = pci_enable_msix(bp->pdev, msix_ent, BNX2_MAX_MSIX_VEC); if (rc != 0) return; - bp->irq_tbl[BNX2_BASE_VEC].handler = bnx2_msi_1shot; - bp->irq_tbl[BNX2_TX_VEC].handler = bnx2_tx_msix; - - strcpy(bp->irq_tbl[BNX2_BASE_VEC].name, bp->dev->name); - strcat(bp->irq_tbl[BNX2_BASE_VEC].name, "-base"); - strcpy(bp->irq_tbl[BNX2_TX_VEC].name, bp->dev->name); - strcat(bp->irq_tbl[BNX2_TX_VEC].name, "-tx"); - - bp->irq_nvecs = BNX2_MAX_MSIX_VEC; + bp->irq_nvecs = msix_vecs; bp->flags |= BNX2_FLAG_USING_MSIX | BNX2_FLAG_ONE_SHOT_MSI; for (i = 0; i < BNX2_MAX_MSIX_VEC; i++) bp->irq_tbl[i].vector = msix_ent[i].vector; @@ -5610,13 +5771,16 @@ bnx2_enable_msix(struct bnx2 *bp) static void bnx2_setup_int_mode(struct bnx2 *bp, int dis_msi) { + int cpus = num_online_cpus(); + int msix_vecs = min(cpus + 1, RX_MAX_RINGS); + bp->irq_tbl[0].handler = bnx2_interrupt; strcpy(bp->irq_tbl[0].name, bp->dev->name); bp->irq_nvecs = 1; bp->irq_tbl[0].vector = bp->pdev->irq; - if ((bp->flags & BNX2_FLAG_MSIX_CAP) && !dis_msi) - bnx2_enable_msix(bp); + if ((bp->flags & BNX2_FLAG_MSIX_CAP) && !dis_msi && cpus > 1) + bnx2_enable_msix(bp, msix_vecs); if ((bp->flags & BNX2_FLAG_MSI_CAP) && !dis_msi && !(bp->flags & BNX2_FLAG_USING_MSIX)) { @@ -5631,6 +5795,11 @@ bnx2_setup_int_mode(struct bnx2 *bp, int dis_msi) bp->irq_tbl[0].vector = bp->pdev->irq; } } + + bp->num_tx_rings = rounddown_pow_of_two(bp->irq_nvecs); + bp->dev->real_num_tx_queues = bp->num_tx_rings; + + bp->num_rx_rings = bp->irq_nvecs; } /* Called with rtnl_lock */ @@ -5645,29 +5814,19 @@ bnx2_open(struct net_device *dev) bnx2_set_power_state(bp, PCI_D0); bnx2_disable_int(bp); + bnx2_setup_int_mode(bp, disable_msi); + bnx2_napi_enable(bp); rc = bnx2_alloc_mem(bp); if (rc) - return rc; + goto open_err; - bnx2_setup_int_mode(bp, disable_msi); - bnx2_napi_enable(bp); rc = bnx2_request_irq(bp); + if (rc) + goto open_err; - if (rc) { - bnx2_napi_disable(bp); - bnx2_free_mem(bp); - return rc; - } - - rc = bnx2_init_nic(bp); - - if (rc) { - bnx2_napi_disable(bp); - bnx2_free_irq(bp); - bnx2_free_skbs(bp); - bnx2_free_mem(bp); - return rc; - } + rc = bnx2_init_nic(bp, 1); + if (rc) + goto open_err; mod_timer(&bp->timer, jiffies + bp->current_interval); @@ -5691,17 +5850,14 @@ bnx2_open(struct net_device *dev) bnx2_setup_int_mode(bp, 1); - rc = bnx2_init_nic(bp); + rc = bnx2_init_nic(bp, 0); if (!rc) rc = bnx2_request_irq(bp); if (rc) { - bnx2_napi_disable(bp); - bnx2_free_skbs(bp); - bnx2_free_mem(bp); del_timer_sync(&bp->timer); - return rc; + goto open_err; } bnx2_enable_int(bp); } @@ -5711,9 +5867,16 @@ bnx2_open(struct net_device *dev) else if (bp->flags & BNX2_FLAG_USING_MSIX) printk(KERN_INFO PFX "%s: using MSIX\n", dev->name); - netif_start_queue(dev); + netif_tx_start_all_queues(dev); return 0; + +open_err: + bnx2_napi_disable(bp); + bnx2_free_skbs(bp); + bnx2_free_irq(bp); + bnx2_free_mem(bp); + return rc; } static void @@ -5726,7 +5889,7 @@ bnx2_reset_task(struct work_struct *work) bnx2_netif_stop(bp); - bnx2_init_nic(bp); + bnx2_init_nic(bp, 1); atomic_set(&bp->intr_sem, 1); bnx2_netif_start(bp); @@ -5752,6 +5915,8 @@ bnx2_vlan_rx_register(struct net_device *dev, struct vlan_group *vlgrp) bp->vlgrp = vlgrp; bnx2_set_rx_mode(dev); + if (bp->flags & BNX2_FLAG_CAN_KEEP_VLAN) + bnx2_fw_sync(bp, BNX2_DRV_MSG_CODE_KEEP_VLAN_UPDATE, 0, 1); bnx2_netif_start(bp); } @@ -5771,18 +5936,26 @@ bnx2_start_xmit(struct sk_buff *skb, struct net_device *dev) u32 len, vlan_tag_flags, last_frag, mss; u16 prod, ring_prod; int i; - struct bnx2_napi *bnapi = &bp->bnx2_napi[bp->tx_vec]; + struct bnx2_napi *bnapi; + struct bnx2_tx_ring_info *txr; + struct netdev_queue *txq; - if (unlikely(bnx2_tx_avail(bp, bnapi) < + /* Determine which tx ring we will be placed on */ + i = skb_get_queue_mapping(skb); + bnapi = &bp->bnx2_napi[i]; + txr = &bnapi->tx_ring; + txq = netdev_get_tx_queue(dev, i); + + if (unlikely(bnx2_tx_avail(bp, txr) < (skb_shinfo(skb)->nr_frags + 1))) { - netif_stop_queue(dev); + netif_tx_stop_queue(txq); printk(KERN_ERR PFX "%s: BUG! Tx ring full when queue awake!\n", dev->name); return NETDEV_TX_BUSY; } len = skb_headlen(skb); - prod = bp->tx_prod; + prod = txr->tx_prod; ring_prod = TX_RING_IDX(prod); vlan_tag_flags = 0; @@ -5844,11 +6017,11 @@ bnx2_start_xmit(struct sk_buff *skb, struct net_device *dev) mapping = pci_map_single(bp->pdev, skb->data, len, PCI_DMA_TODEVICE); - tx_buf = &bp->tx_buf_ring[ring_prod]; + tx_buf = &txr->tx_buf_ring[ring_prod]; tx_buf->skb = skb; pci_unmap_addr_set(tx_buf, mapping, mapping); - txbd = &bp->tx_desc_ring[ring_prod]; + txbd = &txr->tx_desc_ring[ring_prod]; txbd->tx_bd_haddr_hi = (u64) mapping >> 32; txbd->tx_bd_haddr_lo = (u64) mapping & 0xffffffff; @@ -5862,12 +6035,12 @@ bnx2_start_xmit(struct sk_buff *skb, struct net_device *dev) prod = NEXT_TX_BD(prod); ring_prod = TX_RING_IDX(prod); - txbd = &bp->tx_desc_ring[ring_prod]; + txbd = &txr->tx_desc_ring[ring_prod]; len = frag->size; mapping = pci_map_page(bp->pdev, frag->page, frag->page_offset, len, PCI_DMA_TODEVICE); - pci_unmap_addr_set(&bp->tx_buf_ring[ring_prod], + pci_unmap_addr_set(&txr->tx_buf_ring[ring_prod], mapping, mapping); txbd->tx_bd_haddr_hi = (u64) mapping >> 32; @@ -5879,20 +6052,20 @@ bnx2_start_xmit(struct sk_buff *skb, struct net_device *dev) txbd->tx_bd_vlan_tag_flags |= TX_BD_FLAGS_END; prod = NEXT_TX_BD(prod); - bp->tx_prod_bseq += skb->len; + txr->tx_prod_bseq += skb->len; - REG_WR16(bp, bp->tx_bidx_addr, prod); - REG_WR(bp, bp->tx_bseq_addr, bp->tx_prod_bseq); + REG_WR16(bp, txr->tx_bidx_addr, prod); + REG_WR(bp, txr->tx_bseq_addr, txr->tx_prod_bseq); mmiowb(); - bp->tx_prod = prod; + txr->tx_prod = prod; dev->trans_start = jiffies; - if (unlikely(bnx2_tx_avail(bp, bnapi) <= MAX_SKB_FRAGS)) { - netif_stop_queue(dev); - if (bnx2_tx_avail(bp, bnapi) > bp->tx_wake_thresh) - netif_wake_queue(dev); + if (unlikely(bnx2_tx_avail(bp, txr) <= MAX_SKB_FRAGS)) { + netif_tx_stop_queue(txq); + if (bnx2_tx_avail(bp, txr) > bp->tx_wake_thresh) + netif_tx_wake_queue(txq); } return NETDEV_TX_OK; @@ -6095,6 +6268,12 @@ bnx2_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) !(bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP)) goto err_out_unlock; + /* If device is down, we can store the settings only if the user + * is setting the currently active port. + */ + if (!netif_running(dev) && cmd->port != bp->phy_port) + goto err_out_unlock; + if (cmd->autoneg == AUTONEG_ENABLE) { autoneg |= AUTONEG_SPEED; @@ -6152,7 +6331,12 @@ bnx2_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) bp->req_line_speed = req_line_speed; bp->req_duplex = req_duplex; - err = bnx2_setup_phy(bp, cmd->port); + err = 0; + /* If device is down, the new settings will be picked up when it is + * brought up. + */ + if (netif_running(dev)) + err = bnx2_setup_phy(bp, cmd->port); err_out_unlock: spin_unlock_bh(&bp->phy_lock); @@ -6414,7 +6598,7 @@ bnx2_set_coalesce(struct net_device *dev, struct ethtool_coalesce *coal) if (netif_running(bp->dev)) { bnx2_netif_stop(bp); - bnx2_init_nic(bp); + bnx2_init_nic(bp, 0); bnx2_netif_start(bp); } @@ -6457,7 +6641,7 @@ bnx2_change_ring_size(struct bnx2 *bp, u32 rx, u32 tx) rc = bnx2_alloc_mem(bp); if (rc) return rc; - bnx2_init_nic(bp); + bnx2_init_nic(bp, 0); bnx2_netif_start(bp); } return 0; @@ -6725,7 +6909,7 @@ bnx2_self_test(struct net_device *dev, struct ethtool_test *etest, u64 *buf) bnx2_reset_chip(bp, BNX2_DRV_MSG_CODE_RESET); } else { - bnx2_init_nic(bp); + bnx2_init_nic(bp, 1); bnx2_netif_start(bp); } @@ -6951,7 +7135,7 @@ bnx2_change_mac_addr(struct net_device *dev, void *p) memcpy(dev->dev_addr, addr->sa_data, dev->addr_len); if (netif_running(dev)) - bnx2_set_mac_addr(bp); + bnx2_set_mac_addr(bp, bp->dev->dev_addr, 0); return 0; } @@ -7108,6 +7292,7 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev) } pci_set_master(pdev); + pci_save_state(pdev); bp->pm_cap = pci_find_capability(pdev, PCI_CAP_ID_PM); if (bp->pm_cap == 0) { @@ -7125,7 +7310,7 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev) INIT_WORK(&bp->reset_task, bnx2_reset_task); dev->base_addr = dev->mem_start = pci_resource_start(pdev, 0); - mem_len = MB_GET_CID_ADDR(TX_TSS_CID + 1); + mem_len = MB_GET_CID_ADDR(TX_TSS_CID + TX_MAX_TSS_RINGS); dev->mem_end = dev->mem_start + mem_len; dev->irq = pdev->irq; @@ -7272,7 +7457,6 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev) reg &= BNX2_CONDITION_MFW_RUN_MASK; if (reg != BNX2_CONDITION_MFW_RUN_UNKNOWN && reg != BNX2_CONDITION_MFW_RUN_NONE) { - int i; u32 addr = bnx2_shmem_rd(bp, BNX2_MFW_VER_PTR); bp->fw_version[j++] = ' '; @@ -7294,8 +7478,6 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev) bp->mac_addr[4] = (u8) (reg >> 8); bp->mac_addr[5] = (u8) reg; - bp->rx_offset = sizeof(struct l2_fhdr) + 2; - bp->tx_ring_size = MAX_TX_DESC_CNT; bnx2_set_rx_ring_size(bp, 255); @@ -7345,8 +7527,6 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev) if (reg & BNX2_SHARED_HW_CFG_PHY_2_5G) bp->phy_flags |= BNX2_PHY_FLAG_2_5G_CAPABLE; } - bnx2_init_remote_phy(bp); - } else if (CHIP_NUM(bp) == CHIP_NUM_5706 || CHIP_NUM(bp) == CHIP_NUM_5708) bp->phy_flags |= BNX2_PHY_FLAG_CRC_FIX; @@ -7355,6 +7535,8 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev) CHIP_REV(bp) == CHIP_REV_Bx)) bp->phy_flags |= BNX2_PHY_FLAG_DIS_EARLY_DAC; + bnx2_init_fw_cap(bp); + if ((CHIP_ID(bp) == CHIP_ID_5708_A0) || (CHIP_ID(bp) == CHIP_ID_5708_B0) || (CHIP_ID(bp) == CHIP_ID_5708_B1)) { @@ -7451,15 +7633,19 @@ static void __devinit bnx2_init_napi(struct bnx2 *bp) { int i; - struct bnx2_napi *bnapi; for (i = 0; i < BNX2_MAX_MSIX_VEC; i++) { - bnapi = &bp->bnx2_napi[i]; + struct bnx2_napi *bnapi = &bp->bnx2_napi[i]; + int (*poll)(struct napi_struct *, int); + + if (i == 0) + poll = bnx2_poll; + else + poll = bnx2_poll_msix; + + netif_napi_add(bp->dev, &bp->bnx2_napi[i].napi, poll, 64); bnapi->bp = bp; } - netif_napi_add(bp->dev, &bp->bnx2_napi[0].napi, bnx2_poll, 64); - netif_napi_add(bp->dev, &bp->bnx2_napi[BNX2_TX_VEC].napi, bnx2_tx_poll, - 64); } static int __devinit @@ -7476,7 +7662,7 @@ bnx2_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) printk(KERN_INFO "%s", version); /* dev zeroed in init_etherdev */ - dev = alloc_etherdev(sizeof(*bp)); + dev = alloc_etherdev_mq(sizeof(*bp), TX_MAX_RINGS); if (!dev) return -ENOMEM; @@ -7491,7 +7677,7 @@ bnx2_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) dev->hard_start_xmit = bnx2_start_xmit; dev->stop = bnx2_close; dev->get_stats = bnx2_get_stats; - dev->set_multicast_list = bnx2_set_rx_mode; + dev->set_rx_mode = bnx2_set_rx_mode; dev->do_ioctl = bnx2_ioctl; dev->set_mac_address = bnx2_change_mac_addr; dev->change_mtu = bnx2_change_mtu; @@ -7612,11 +7798,97 @@ bnx2_resume(struct pci_dev *pdev) bnx2_set_power_state(bp, PCI_D0); netif_device_attach(dev); - bnx2_init_nic(bp); + bnx2_init_nic(bp, 1); bnx2_netif_start(bp); return 0; } +/** + * bnx2_io_error_detected - called when PCI error is detected + * @pdev: Pointer to PCI device + * @state: The current pci connection state + * + * This function is called after a PCI bus error affecting + * this device has been detected. + */ +static pci_ers_result_t bnx2_io_error_detected(struct pci_dev *pdev, + pci_channel_state_t state) +{ + struct net_device *dev = pci_get_drvdata(pdev); + struct bnx2 *bp = netdev_priv(dev); + + rtnl_lock(); + netif_device_detach(dev); + + if (netif_running(dev)) { + bnx2_netif_stop(bp); + del_timer_sync(&bp->timer); + bnx2_reset_nic(bp, BNX2_DRV_MSG_CODE_RESET); + } + + pci_disable_device(pdev); + rtnl_unlock(); + + /* Request a slot slot reset. */ + return PCI_ERS_RESULT_NEED_RESET; +} + +/** + * bnx2_io_slot_reset - called after the pci bus has been reset. + * @pdev: Pointer to PCI device + * + * Restart the card from scratch, as if from a cold-boot. + */ +static pci_ers_result_t bnx2_io_slot_reset(struct pci_dev *pdev) +{ + struct net_device *dev = pci_get_drvdata(pdev); + struct bnx2 *bp = netdev_priv(dev); + + rtnl_lock(); + if (pci_enable_device(pdev)) { + dev_err(&pdev->dev, + "Cannot re-enable PCI device after reset.\n"); + rtnl_unlock(); + return PCI_ERS_RESULT_DISCONNECT; + } + pci_set_master(pdev); + pci_restore_state(pdev); + + if (netif_running(dev)) { + bnx2_set_power_state(bp, PCI_D0); + bnx2_init_nic(bp, 1); + } + + rtnl_unlock(); + return PCI_ERS_RESULT_RECOVERED; +} + +/** + * bnx2_io_resume - called when traffic can start flowing again. + * @pdev: Pointer to PCI device + * + * This callback is called when the error recovery driver tells us that + * its OK to resume normal operation. + */ +static void bnx2_io_resume(struct pci_dev *pdev) +{ + struct net_device *dev = pci_get_drvdata(pdev); + struct bnx2 *bp = netdev_priv(dev); + + rtnl_lock(); + if (netif_running(dev)) + bnx2_netif_start(bp); + + netif_device_attach(dev); + rtnl_unlock(); +} + +static struct pci_error_handlers bnx2_err_handler = { + .error_detected = bnx2_io_error_detected, + .slot_reset = bnx2_io_slot_reset, + .resume = bnx2_io_resume, +}; + static struct pci_driver bnx2_pci_driver = { .name = DRV_MODULE_NAME, .id_table = bnx2_pci_tbl, @@ -7624,6 +7896,7 @@ static struct pci_driver bnx2_pci_driver = { .remove = __devexit_p(bnx2_remove_one), .suspend = bnx2_suspend, .resume = bnx2_resume, + .err_handler = &bnx2_err_handler, }; static int __init bnx2_init(void) diff --git a/drivers/net/bnx2.h b/drivers/net/bnx2.h index 2377cc13bf61..c3c579f98ed0 100644 --- a/drivers/net/bnx2.h +++ b/drivers/net/bnx2.h @@ -309,6 +309,7 @@ struct l2_fhdr { #endif }; +#define BNX2_RX_OFFSET (sizeof(struct l2_fhdr) + 2) /* * l2_context definition @@ -4157,6 +4158,23 @@ struct l2_fhdr { /* + * rlup_reg definition + * offset: 0x2000 + */ +#define BNX2_RLUP_RSS_CONFIG 0x0000201c +#define BNX2_RLUP_RSS_CONFIG_IPV4_RSS_TYPE_XI (0x3L<<0) +#define BNX2_RLUP_RSS_CONFIG_IPV4_RSS_TYPE_OFF_XI (0L<<0) +#define BNX2_RLUP_RSS_CONFIG_IPV4_RSS_TYPE_ALL_XI (1L<<0) +#define BNX2_RLUP_RSS_CONFIG_IPV4_RSS_TYPE_IP_ONLY_XI (2L<<0) +#define BNX2_RLUP_RSS_CONFIG_IPV4_RSS_TYPE_RES_XI (3L<<0) +#define BNX2_RLUP_RSS_CONFIG_IPV6_RSS_TYPE_XI (0x3L<<2) +#define BNX2_RLUP_RSS_CONFIG_IPV6_RSS_TYPE_OFF_XI (0L<<2) +#define BNX2_RLUP_RSS_CONFIG_IPV6_RSS_TYPE_ALL_XI (1L<<2) +#define BNX2_RLUP_RSS_CONFIG_IPV6_RSS_TYPE_IP_ONLY_XI (2L<<2) +#define BNX2_RLUP_RSS_CONFIG_IPV6_RSS_TYPE_RES_XI (3L<<2) + + +/* * rbuf_reg definition * offset: 0x200000 */ @@ -5527,6 +5545,9 @@ struct l2_fhdr { #define BNX2_HC_TX_QUICK_CONS_TRIP_OFF (BNX2_HC_TX_QUICK_CONS_TRIP_1 - \ BNX2_HC_SB_CONFIG_1) #define BNX2_HC_TX_TICKS_OFF (BNX2_HC_TX_TICKS_1 - BNX2_HC_SB_CONFIG_1) +#define BNX2_HC_RX_QUICK_CONS_TRIP_OFF (BNX2_HC_RX_QUICK_CONS_TRIP_1 - \ + BNX2_HC_SB_CONFIG_1) +#define BNX2_HC_RX_TICKS_OFF (BNX2_HC_RX_TICKS_1 - BNX2_HC_SB_CONFIG_1) /* @@ -5855,6 +5876,9 @@ struct l2_fhdr { #define BNX2_RXP_FTQ_CTL_CUR_DEPTH (0x3ffL<<22) #define BNX2_RXP_SCRATCH 0x000e0000 +#define BNX2_RXP_SCRATCH_RSS_TBL_SZ 0x000e0038 +#define BNX2_RXP_SCRATCH_RSS_TBL 0x000e003c +#define BNX2_RXP_SCRATCH_RSS_TBL_MAX_ENTRIES 128 /* @@ -6412,10 +6436,15 @@ struct l2_fhdr { #define MAX_ETHERNET_PACKET_SIZE 1514 #define MAX_ETHERNET_JUMBO_PACKET_SIZE 9014 -#define RX_COPY_THRESH 128 +#define BNX2_RX_COPY_THRESH 128 #define BNX2_MISC_ENABLE_DEFAULT 0x17ffffff +#define BNX2_START_UNICAST_ADDRESS_INDEX 4 +#define BNX2_END_UNICAST_ADDRESS_INDEX 7 +#define BNX2_MAX_UNICAST_ADDRESSES (BNX2_END_UNICAST_ADDRESS_INDEX - \ + BNX2_START_UNICAST_ADDRESS_INDEX + 1) + #define DMA_READ_CHANS 5 #define DMA_WRITE_CHANS 3 @@ -6478,6 +6507,11 @@ struct l2_fhdr { #define TX_CID 16 #define TX_TSS_CID 32 #define RX_CID 0 +#define RX_RSS_CID 4 +#define RX_MAX_RSS_RINGS 7 +#define RX_MAX_RINGS (RX_MAX_RSS_RINGS + 1) +#define TX_MAX_TSS_RINGS 7 +#define TX_MAX_RINGS (TX_MAX_TSS_RINGS + 1) #define MB_TX_CID_ADDR MB_GET_CID_ADDR(TX_CID) #define MB_RX_CID_ADDR MB_GET_CID_ADDR(RX_CID) @@ -6556,7 +6590,7 @@ struct flash_spec { }; #define BNX2_MAX_MSIX_HW_VEC 9 -#define BNX2_MAX_MSIX_VEC 2 +#define BNX2_MAX_MSIX_VEC 9 #define BNX2_BASE_VEC 0 #define BNX2_TX_VEC 1 #define BNX2_TX_INT_NUM (BNX2_TX_VEC << BNX2_PCICFG_INT_ACK_CMD_INT_NUM_SHIFT) @@ -6568,24 +6602,56 @@ struct bnx2_irq { char name[16]; }; -struct bnx2_napi { - struct napi_struct napi ____cacheline_aligned; - struct bnx2 *bp; - struct status_block *status_blk; - struct status_block_msix *status_blk_msix; - u32 last_status_idx; - u32 int_num; +struct bnx2_tx_ring_info { + u32 tx_prod_bseq; + u16 tx_prod; + u32 tx_bidx_addr; + u32 tx_bseq_addr; + + struct tx_bd *tx_desc_ring; + struct sw_bd *tx_buf_ring; u16 tx_cons; u16 hw_tx_cons; + dma_addr_t tx_desc_mapping; +}; + +struct bnx2_rx_ring_info { u32 rx_prod_bseq; u16 rx_prod; u16 rx_cons; + u32 rx_bidx_addr; + u32 rx_bseq_addr; + u32 rx_pg_bidx_addr; + u16 rx_pg_prod; u16 rx_pg_cons; + struct sw_bd *rx_buf_ring; + struct rx_bd *rx_desc_ring[MAX_RX_RINGS]; + struct sw_pg *rx_pg_ring; + struct rx_bd *rx_pg_desc_ring[MAX_RX_PG_RINGS]; + + dma_addr_t rx_desc_mapping[MAX_RX_RINGS]; + dma_addr_t rx_pg_desc_mapping[MAX_RX_PG_RINGS]; +}; + +struct bnx2_napi { + struct napi_struct napi ____cacheline_aligned; + struct bnx2 *bp; + union { + struct status_block *msi; + struct status_block_msix *msix; + } status_blk; + u16 *hw_tx_cons_ptr; + u16 *hw_rx_cons_ptr; + u32 last_status_idx; + u32 int_num; + + struct bnx2_rx_ring_info rx_ring; + struct bnx2_tx_ring_info tx_ring; }; struct bnx2 { @@ -6612,14 +6678,7 @@ struct bnx2 { #define BNX2_FLAG_USING_MSI_OR_MSIX (BNX2_FLAG_USING_MSI | \ BNX2_FLAG_USING_MSIX) #define BNX2_FLAG_JUMBO_BROKEN 0x00000800 - - /* Put tx producer and consumer fields in separate cache lines. */ - - u32 tx_prod_bseq __attribute__((aligned(L1_CACHE_BYTES))); - u16 tx_prod; - u8 tx_vec; - u32 tx_bidx_addr; - u32 tx_bseq_addr; +#define BNX2_FLAG_CAN_KEEP_VLAN 0x00001000 struct bnx2_napi bnx2_napi[BNX2_MAX_MSIX_VEC]; @@ -6627,7 +6686,6 @@ struct bnx2 { struct vlan_group *vlgrp; #endif - u32 rx_offset; u32 rx_buf_use_size; /* useable size */ u32 rx_buf_size; /* with alignment */ u32 rx_copy_thresh; @@ -6637,14 +6695,7 @@ struct bnx2 { u32 rx_csum; - struct sw_bd *rx_buf_ring; - struct rx_bd *rx_desc_ring[MAX_RX_RINGS]; - struct sw_pg *rx_pg_ring; - struct rx_bd *rx_pg_desc_ring[MAX_RX_PG_RINGS]; - /* TX constants */ - struct tx_bd *tx_desc_ring; - struct sw_bd *tx_buf_ring; int tx_ring_size; u32 tx_wake_thresh; @@ -6722,16 +6773,11 @@ struct bnx2 { u16 fw_wr_seq; u16 fw_drv_pulse_wr_seq; - dma_addr_t tx_desc_mapping; - - int rx_max_ring; int rx_ring_size; - dma_addr_t rx_desc_mapping[MAX_RX_RINGS]; int rx_max_pg_ring; int rx_pg_ring_size; - dma_addr_t rx_pg_desc_mapping[MAX_RX_PG_RINGS]; u16 tx_quick_cons_trip; u16 tx_quick_cons_trip_int; @@ -6750,7 +6796,6 @@ struct bnx2 { u32 stats_ticks; - struct status_block *status_blk; dma_addr_t status_blk_mapping; struct statistics_block *stats_blk; @@ -6812,6 +6857,9 @@ struct bnx2 { struct bnx2_irq irq_tbl[BNX2_MAX_MSIX_VEC]; int irq_nvecs; + + u8 num_tx_rings; + u8 num_rx_rings; }; #define REG_RD(bp, offset) \ @@ -6912,6 +6960,7 @@ struct fw_info { #define BNX2_DRV_MSG_CODE_DIAG 0x07000000 #define BNX2_DRV_MSG_CODE_SUSPEND_NO_WOL 0x09000000 #define BNX2_DRV_MSG_CODE_UNLOAD_LNK_DN 0x0b000000 +#define BNX2_DRV_MSG_CODE_KEEP_VLAN_UPDATE 0x0d000000 #define BNX2_DRV_MSG_CODE_CMD_SET_LINK 0x10000000 #define BNX2_DRV_MSG_DATA 0x00ff0000 @@ -7240,6 +7289,10 @@ struct fw_info { #define BNX2_FW_CAP_SIGNATURE_MASK 0xffff0000 #define BNX2_FW_CAP_REMOTE_PHY_CAPABLE 0x00000001 #define BNX2_FW_CAP_REMOTE_PHY_PRESENT 0x00000002 +#define BNX2_FW_CAP_MFW_CAN_KEEP_VLAN 0x00000008 +#define BNX2_FW_CAP_BC_CAN_KEEP_VLAN 0x00000010 +#define BNX2_FW_CAP_CAN_KEEP_VLAN (BNX2_FW_CAP_BC_CAN_KEEP_VLAN | \ + BNX2_FW_CAP_MFW_CAN_KEEP_VLAN) #define BNX2_RPHY_SIGNATURE 0x36c #define BNX2_RPHY_LOAD_SIGNATURE 0x5a5a5a5a diff --git a/drivers/net/bnx2_fw.h b/drivers/net/bnx2_fw.h index 3b839d4626fe..e4b1de435567 100644 --- a/drivers/net/bnx2_fw.h +++ b/drivers/net/bnx2_fw.h @@ -886,6 +886,23 @@ static struct fw_info bnx2_com_fw_06 = { .rodata = bnx2_COM_b06FwRodata, }; +/* Initialized Values for the Completion Processor. */ +static const struct cpu_reg cpu_reg_com = { + .mode = BNX2_COM_CPU_MODE, + .mode_value_halt = BNX2_COM_CPU_MODE_SOFT_HALT, + .mode_value_sstep = BNX2_COM_CPU_MODE_STEP_ENA, + .state = BNX2_COM_CPU_STATE, + .state_value_clear = 0xffffff, + .gpr0 = BNX2_COM_CPU_REG_FILE, + .evmask = BNX2_COM_CPU_EVENT_MASK, + .pc = BNX2_COM_CPU_PROGRAM_COUNTER, + .inst = BNX2_COM_CPU_INSTRUCTION, + .bp = BNX2_COM_CPU_HW_BREAKPOINT, + .spad_base = BNX2_COM_SCRATCH, + .mips_view_base = 0x8000000, +}; + + static u8 bnx2_CP_b06FwText[] = { 0x9d, 0xbc, 0x0d, 0x78, 0x13, 0xe7, 0x99, 0x2e, 0x7c, 0xcf, 0x48, 0xb2, 0x65, 0x5b, 0xb6, 0xc7, 0xb6, 0x0c, 0x22, 0x65, 0x41, 0x83, 0x47, 0x20, @@ -2167,6 +2184,22 @@ static struct fw_info bnx2_cp_fw_06 = { .rodata = bnx2_CP_b06FwRodata, }; +/* Initialized Values the Command Processor. */ +static const struct cpu_reg cpu_reg_cp = { + .mode = BNX2_CP_CPU_MODE, + .mode_value_halt = BNX2_CP_CPU_MODE_SOFT_HALT, + .mode_value_sstep = BNX2_CP_CPU_MODE_STEP_ENA, + .state = BNX2_CP_CPU_STATE, + .state_value_clear = 0xffffff, + .gpr0 = BNX2_CP_CPU_REG_FILE, + .evmask = BNX2_CP_CPU_EVENT_MASK, + .pc = BNX2_CP_CPU_PROGRAM_COUNTER, + .inst = BNX2_CP_CPU_INSTRUCTION, + .bp = BNX2_CP_CPU_HW_BREAKPOINT, + .spad_base = BNX2_CP_SCRATCH, + .mips_view_base = 0x8000000, +}; + static u8 bnx2_RXP_b06FwText[] = { 0xec, 0x5b, 0x5d, 0x70, 0x5c, 0xd7, 0x5d, 0xff, 0xdf, 0xb3, 0x2b, 0x69, 0x2d, 0x4b, 0xf2, 0x95, 0xbc, 0x71, 0x56, 0xa9, 0x92, 0xec, 0x5a, 0x57, @@ -2946,6 +2979,22 @@ static struct fw_info bnx2_rxp_fw_06 = { .rodata = bnx2_RXP_b06FwRodata, }; +/* Initialized Values for the RX Processor. */ +static const struct cpu_reg cpu_reg_rxp = { + .mode = BNX2_RXP_CPU_MODE, + .mode_value_halt = BNX2_RXP_CPU_MODE_SOFT_HALT, + .mode_value_sstep = BNX2_RXP_CPU_MODE_STEP_ENA, + .state = BNX2_RXP_CPU_STATE, + .state_value_clear = 0xffffff, + .gpr0 = BNX2_RXP_CPU_REG_FILE, + .evmask = BNX2_RXP_CPU_EVENT_MASK, + .pc = BNX2_RXP_CPU_PROGRAM_COUNTER, + .inst = BNX2_RXP_CPU_INSTRUCTION, + .bp = BNX2_RXP_CPU_HW_BREAKPOINT, + .spad_base = BNX2_RXP_SCRATCH, + .mips_view_base = 0x8000000, +}; + static u8 bnx2_rv2p_proc1[] = { /* Date: 12/07/2007 15:02 */ 0xd5, 0x56, 0x41, 0x6b, 0x13, 0x51, 0x10, 0x9e, 0xdd, 0x6c, 0xbb, 0xdb, @@ -3651,6 +3700,22 @@ static struct fw_info bnx2_tpat_fw_06 = { .rodata = bnx2_TPAT_b06FwRodata, }; +/* Initialized Values for the TX Patch-up Processor. */ +static const struct cpu_reg cpu_reg_tpat = { + .mode = BNX2_TPAT_CPU_MODE, + .mode_value_halt = BNX2_TPAT_CPU_MODE_SOFT_HALT, + .mode_value_sstep = BNX2_TPAT_CPU_MODE_STEP_ENA, + .state = BNX2_TPAT_CPU_STATE, + .state_value_clear = 0xffffff, + .gpr0 = BNX2_TPAT_CPU_REG_FILE, + .evmask = BNX2_TPAT_CPU_EVENT_MASK, + .pc = BNX2_TPAT_CPU_PROGRAM_COUNTER, + .inst = BNX2_TPAT_CPU_INSTRUCTION, + .bp = BNX2_TPAT_CPU_HW_BREAKPOINT, + .spad_base = BNX2_TPAT_SCRATCH, + .mips_view_base = 0x8000000, +}; + static u8 bnx2_TXP_b06FwText[] = { 0xad, 0x7b, 0x7f, 0x70, 0x9b, 0x75, 0x7a, 0xe7, 0xe7, 0xd5, 0x0f, 0x5b, 0xb2, 0x65, 0x59, 0x0e, 0x4a, 0x90, 0x77, 0xbd, 0x8d, 0x5e, 0xf4, 0xca, @@ -4531,3 +4596,18 @@ static struct fw_info bnx2_txp_fw_06 = { .rodata = bnx2_TXP_b06FwRodata, }; +/* Initialized Values for the TX Processor. */ +static const struct cpu_reg cpu_reg_txp = { + .mode = BNX2_TXP_CPU_MODE, + .mode_value_halt = BNX2_TXP_CPU_MODE_SOFT_HALT, + .mode_value_sstep = BNX2_TXP_CPU_MODE_STEP_ENA, + .state = BNX2_TXP_CPU_STATE, + .state_value_clear = 0xffffff, + .gpr0 = BNX2_TXP_CPU_REG_FILE, + .evmask = BNX2_TXP_CPU_EVENT_MASK, + .pc = BNX2_TXP_CPU_PROGRAM_COUNTER, + .inst = BNX2_TXP_CPU_INSTRUCTION, + .bp = BNX2_TXP_CPU_HW_BREAKPOINT, + .spad_base = BNX2_TXP_SCRATCH, + .mips_view_base = 0x8000000, +}; diff --git a/drivers/net/bnx2_fw2.h b/drivers/net/bnx2_fw2.h index ed0514cba0ee..fe753b6bcb41 100644 --- a/drivers/net/bnx2_fw2.h +++ b/drivers/net/bnx2_fw2.h @@ -15,842 +15,848 @@ */ static u8 bnx2_COM_b09FwText[] = { - 0xcd, 0x7c, 0x7f, 0x6c, 0x5c, 0xd7, 0x95, 0xde, 0x79, 0x6f, 0x1e, 0xc9, - 0xe1, 0x88, 0xa2, 0x1e, 0xe9, 0x31, 0x3d, 0x8e, 0xb9, 0xc9, 0x0c, 0xe7, - 0x91, 0xa2, 0x4d, 0x26, 0xfb, 0xcc, 0x8e, 0x6d, 0x3a, 0x99, 0xb5, 0xc6, - 0x33, 0x94, 0xad, 0xc4, 0x8c, 0x41, 0x3b, 0xca, 0xd6, 0x28, 0xdc, 0x80, - 0x1d, 0x52, 0x8e, 0xb3, 0x75, 0xbb, 0x8e, 0x1b, 0xa4, 0x89, 0x11, 0x44, - 0x93, 0x21, 0xa5, 0x55, 0x82, 0x21, 0x67, 0x22, 0xd3, 0xdc, 0xfc, 0xb1, - 0x68, 0xc6, 0x43, 0x52, 0x71, 0xb6, 0x23, 0xd1, 0x4e, 0xb2, 0x41, 0x16, - 0xd8, 0xc0, 0x2c, 0x25, 0xcb, 0xc2, 0x22, 0x2d, 0xdc, 0x34, 0x28, 0x82, - 0xec, 0xfe, 0x21, 0xc8, 0xce, 0xc6, 0x29, 0xd2, 0xc2, 0xed, 0x06, 0x8d, - 0x37, 0x48, 0xf2, 0xfa, 0x7d, 0xf7, 0xde, 0x37, 0x1a, 0x8d, 0x68, 0x27, - 0xdd, 0xfe, 0x53, 0x02, 0x83, 0xfb, 0xde, 0xfd, 0x79, 0xee, 0xb9, 0xe7, - 0x9e, 0xf3, 0x9d, 0x73, 0xef, 0xe3, 0x3d, 0x22, 0x31, 0x31, 0x7f, 0xfb, - 0xf1, 0xcb, 0xfc, 0xab, 0x3f, 0x5e, 0xb8, 0xe3, 0x7d, 0xfe, 0xfb, 0xf8, - 0x6e, 0x77, 0x89, 0xc3, 0x34, 0x82, 0x5f, 0x1c, 0xbf, 0x29, 0xf3, 0xbc, - 0xd7, 0x9f, 0x8b, 0xdf, 0x9d, 0x96, 0xc8, 0xfc, 0x7f, 0x13, 0xb1, 0x3a, - 0xca, 0xa2, 0x7b, 0xd4, 0x0f, 0x82, 0xb7, 0xe9, 0xc8, 0xfc, 0xd9, 0xf8, - 0x25, 0xdf, 0xb9, 0xca, 0xff, 0xf3, 0x5f, 0x44, 0x93, 0xad, 0xe6, 0xcd, - 0x9f, 0x44, 0xed, 0x6c, 0xfd, 0x81, 0xbc, 0x27, 0xd1, 0x48, 0x76, 0x6d, - 0x76, 0xc1, 0x13, 0xc9, 0x35, 0x27, 0x92, 0x05, 0xf9, 0x75, 0x50, 0x8a, - 0x3b, 0xc2, 0xfc, 0xdf, 0xcb, 0xfe, 0xea, 0xab, 0xdf, 0xbd, 0x2b, 0xf5, - 0x66, 0x3d, 0x22, 0x51, 0x37, 0xfb, 0x96, 0xb8, 0x63, 0x12, 0x1d, 0x46, - 0x9b, 0x3f, 0x3b, 0x78, 0xc9, 0x96, 0xfe, 0xb0, 0x2f, 0x77, 0x3e, 0x92, - 0x95, 0xb9, 0x63, 0x95, 0xe3, 0x81, 0xed, 0x49, 0xc9, 0xc9, 0x7a, 0xe3, - 0x0d, 0xe9, 0x9b, 0xde, 0xca, 0xdc, 0x25, 0x78, 0x9f, 0x3b, 0xd6, 0x8c, - 0x4a, 0xb9, 0x59, 0xea, 0xb3, 0x3d, 0x0f, 0xa9, 0x44, 0xbb, 0xb3, 0x8b, - 0xd1, 0x8b, 0x1e, 0xc7, 0xfe, 0x21, 0xc6, 0xbe, 0x45, 0xba, 0xbc, 0x20, - 0xd8, 0xc2, 0xd8, 0xf7, 0x35, 0x7f, 0x1d, 0x3c, 0xe7, 0xe8, 0x71, 0xed, - 0xec, 0x93, 0x11, 0xa6, 0x56, 0xf6, 0xf2, 0x03, 0x23, 0x4d, 0xbe, 0x7b, - 0x3d, 0x9a, 0x4e, 0x37, 0x06, 0x3a, 0xa3, 0x4e, 0x76, 0x2e, 0xb6, 0x8c, - 0xb4, 0x2b, 0xfb, 0xe8, 0xed, 0x5b, 0xaa, 0xde, 0xeb, 0xa6, 0xde, 0x13, - 0x5d, 0xba, 0xdd, 0xf8, 0xec, 0x58, 0x93, 0x69, 0x66, 0x76, 0x54, 0xa5, - 0xd9, 0xd9, 0xb4, 0x4a, 0x73, 0xb3, 0x23, 0x2a, 0x9d, 0x99, 0xf5, 0x54, - 0xfa, 0xb7, 0x0f, 0xe8, 0xfc, 0x37, 0x1e, 0x48, 0xaa, 0xf4, 0x67, 0x26, - 0x7d, 0xd3, 0xa4, 0x3f, 0x37, 0xe9, 0x5b, 0x26, 0xfd, 0x95, 0x49, 0x65, - 0x56, 0xa7, 0x8e, 0xe9, 0x27, 0x6a, 0xde, 0xfb, 0x4c, 0xea, 0x9a, 0x34, - 0x6e, 0xd2, 0x84, 0x49, 0x87, 0x0d, 0x5d, 0x49, 0x93, 0x7a, 0x26, 0x9d, - 0x34, 0xe5, 0xbe, 0xa1, 0x77, 0x1a, 0xf4, 0x7e, 0xa1, 0xcb, 0xc8, 0x2a, - 0xe6, 0x9d, 0x94, 0x85, 0x8a, 0x23, 0xe5, 0x6a, 0x44, 0x0a, 0x6a, 0x0d, - 0x1f, 0xd9, 0x2f, 0x31, 0x47, 0x96, 0xb6, 0xa3, 0x72, 0x59, 0x89, 0xe8, - 0x1b, 0xc1, 0x77, 0x0f, 0x4a, 0xc9, 0xce, 0xba, 0xf2, 0xc2, 0x76, 0x5c, - 0x5e, 0xda, 0x16, 0x6b, 0x2e, 0xd3, 0x2b, 0xf6, 0xe9, 0x77, 0x49, 0xce, - 0xb5, 0x24, 0xa2, 0x78, 0x9a, 0x94, 0x7c, 0x65, 0x08, 0xef, 0xa9, 0x84, - 0xc8, 0xe9, 0xfd, 0x7a, 0xfd, 0xa2, 0x12, 0x59, 0xe7, 0x9a, 0x3c, 0x3d, - 0x7b, 0x71, 0x2d, 0x21, 0xce, 0xea, 0x24, 0xc6, 0xe8, 0x93, 0xae, 0x75, - 0x19, 0x8e, 0xc8, 0x68, 0xe2, 0x31, 0xd4, 0x98, 0x69, 0x3a, 0x72, 0xb8, - 0x69, 0x89, 0xe3, 0x45, 0x21, 0x1f, 0x7d, 0xf8, 0xb9, 0xf8, 0xc5, 0xf1, - 0x4b, 0xe0, 0xf7, 0x97, 0xe8, 0x67, 0x58, 0x0a, 0x4d, 0xf6, 0x89, 0x71, - 0xab, 0x18, 0xbf, 0x9a, 0x72, 0xe7, 0x85, 0x74, 0x25, 0xe4, 0xbb, 0x07, - 0x49, 0x97, 0x4b, 0x7a, 0x40, 0x5b, 0xd4, 0xca, 0xaf, 0xc9, 0x93, 0x05, - 0x5f, 0x92, 0xb6, 0x17, 0x93, 0xa2, 0x6b, 0x25, 0x17, 0xc7, 0x07, 0xa5, - 0x74, 0x14, 0xe5, 0x55, 0xc9, 0xd9, 0xe8, 0xbf, 0xe8, 0xca, 0xbc, 0x2e, - 0x63, 0xde, 0x5b, 0xd8, 0xab, 0x29, 0x97, 0x42, 0xfb, 0x52, 0xf5, 0xdb, - 0x78, 0x66, 0x7f, 0xff, 0xe0, 0x68, 0xba, 0x7f, 0x81, 0x77, 0xe6, 0xff, - 0x7d, 0x9f, 0x7e, 0xe7, 0x33, 0xeb, 0x86, 0xe3, 0x86, 0xf3, 0xe5, 0xf8, - 0xe3, 0x98, 0x33, 0x69, 0x08, 0xe7, 0x2c, 0xa5, 0x2e, 0xd0, 0xd2, 0x58, - 0xeb, 0xb3, 0x36, 0xd6, 0x26, 0xe5, 0x64, 0xf5, 0x1e, 0xc9, 0xfb, 0x41, - 0xb0, 0xe0, 0x4b, 0xdc, 0x96, 0x51, 0xb7, 0x80, 0x0a, 0xbb, 0x4d, 0xb1, - 0x1a, 0x15, 0x89, 0xf6, 0x80, 0x2f, 0x3f, 0x59, 0x63, 0xdf, 0x0e, 0xf2, - 0x86, 0x50, 0xbf, 0xdf, 0xda, 0x5c, 0x03, 0xfd, 0x59, 0xf2, 0x27, 0x08, - 0x96, 0xfd, 0xd1, 0xc4, 0x22, 0xc6, 0x3c, 0xdf, 0x1c, 0x9d, 0xbe, 0x22, - 0x2e, 0xfa, 0x1c, 0x44, 0x1d, 0xf2, 0x8a, 0x7d, 0xb1, 0x4f, 0xf6, 0xd7, - 0x87, 0xb6, 0x71, 0x94, 0x91, 0xae, 0x20, 0xc8, 0xfb, 0x2e, 0xdf, 0x65, - 0x07, 0xfc, 0xdb, 0x21, 0xff, 0x62, 0xc3, 0xf2, 0x4a, 0x93, 0x63, 0xec, - 0x45, 0xfb, 0xc4, 0xff, 0x87, 0xb4, 0x27, 0xd0, 0x7f, 0x1c, 0xe9, 0x3e, - 0xab, 0x51, 0x0b, 0x30, 0x7e, 0x02, 0xcf, 0x7b, 0xcd, 0xe3, 0xb2, 0x5a, - 0xfb, 0x17, 0xb0, 0xf6, 0x6e, 0x36, 0x2e, 0x2f, 0x6e, 0x0f, 0x63, 0x1e, - 0x09, 0xf9, 0x06, 0x64, 0x73, 0xe0, 0xce, 0x7d, 0x92, 0x86, 0x6c, 0x72, - 0xcd, 0xa7, 0xd6, 0x1f, 0x95, 0x62, 0x3c, 0x35, 0x4e, 0x3d, 0x9a, 0x9f, - 0xea, 0xc1, 0x7c, 0xb5, 0xb6, 0x1a, 0x59, 0x8d, 0x4b, 0x7a, 0x3d, 0x77, - 0x83, 0x9e, 0x57, 0xdd, 0x92, 0x58, 0x49, 0xec, 0x73, 0x21, 0x6f, 0xc6, - 0x4d, 0xbd, 0x96, 0x1c, 0x5b, 0xf6, 0x7a, 0x9f, 0x15, 0x59, 0x9f, 0x94, - 0x13, 0x7b, 0xf0, 0xa4, 0x01, 0x9e, 0xd8, 0xab, 0xa1, 0x9c, 0x3b, 0x78, - 0x1f, 0x42, 0xdd, 0x7e, 0xcb, 0x59, 0xbf, 0x9e, 0x1f, 0x1b, 0xcd, 0x51, - 0x7f, 0x17, 0xfc, 0xb0, 0xd7, 0x07, 0x51, 0xe7, 0x7a, 0x7e, 0x34, 0xc0, - 0x0f, 0x7b, 0x5d, 0xf3, 0xa2, 0x01, 0x5e, 0xd8, 0xa0, 0xb3, 0x01, 0x5e, - 0xd8, 0xa7, 0x35, 0x2f, 0x1a, 0x66, 0x4f, 0x9c, 0x51, 0xfa, 0x28, 0x07, - 0x5a, 0x2d, 0xd1, 0x3a, 0x29, 0x27, 0xd4, 0x3d, 0x91, 0xec, 0x0c, 0xf6, - 0xb2, 0x8d, 0xb9, 0x3a, 0x32, 0x33, 0x65, 0xc9, 0x82, 0x2a, 0x9b, 0x91, - 0x74, 0xf3, 0x5d, 0x60, 0xd4, 0xc4, 0x38, 0x2c, 0x41, 0xa9, 0x3b, 0xfb, - 0x1d, 0x7b, 0xb7, 0x12, 0x95, 0x82, 0x93, 0x14, 0x6f, 0x95, 0xfd, 0xcc, - 0xb7, 0xf5, 0x33, 0x8f, 0x7e, 0x76, 0xc1, 0x0f, 0x0b, 0xba, 0x93, 0x65, - 0x8f, 0xaa, 0x7d, 0x9d, 0x5e, 0x77, 0x64, 0x74, 0x95, 0x75, 0x4a, 0xf6, - 0x85, 0xe6, 0xaf, 0x02, 0xdd, 0xef, 0xa3, 0x1c, 0xd3, 0xb5, 0xb3, 0xcb, - 0xf6, 0xf9, 0xcd, 0x53, 0xf6, 0xcb, 0x4d, 0xf4, 0xdb, 0x24, 0xaf, 0xb1, - 0x16, 0x55, 0xac, 0x45, 0x15, 0xeb, 0x62, 0xf6, 0x6c, 0x5d, 0xed, 0x9d, - 0xa4, 0x59, 0x37, 0xd2, 0xc0, 0xb5, 0x4b, 0x60, 0xcd, 0xb8, 0x76, 0x62, - 0xbd, 0x9a, 0xd9, 0x27, 0x91, 0xd3, 0x11, 0xb5, 0x66, 0x03, 0xeb, 0x1f, - 0x68, 0xad, 0xd9, 0xc8, 0xd4, 0x81, 0xd6, 0x9a, 0xd9, 0xab, 0xb9, 0x5b, - 0x6c, 0x39, 0x24, 0x76, 0x16, 0xfc, 0xc9, 0x4c, 0x80, 0x5f, 0x11, 0x94, - 0xc5, 0xc5, 0x59, 0xcf, 0x21, 0x2f, 0x95, 0x28, 0x82, 0x8f, 0x65, 0xf0, - 0xb1, 0x28, 0x25, 0xc8, 0xcc, 0xcf, 0x2c, 0xad, 0xdf, 0x7e, 0x29, 0x46, - 0xb6, 0xdf, 0x91, 0x5f, 0x23, 0xe0, 0x97, 0xf7, 0x3b, 0xf0, 0xcb, 0xd9, - 0x93, 0x5f, 0xfd, 0x76, 0x27, 0xbf, 0x22, 0xe0, 0x57, 0xd7, 0xef, 0xcc, - 0x2f, 0xf0, 0x61, 0x4f, 0x5e, 0x45, 0xa1, 0xd7, 0x4a, 0x92, 0xcf, 0x88, - 0xe4, 0x6b, 0x5a, 0x17, 0x97, 0x94, 0x4e, 0xa6, 0x2e, 0x0a, 0x75, 0x32, - 0xf5, 0xb1, 0xda, 0x07, 0x56, 0xa1, 0x92, 0x84, 0xae, 0x74, 0x90, 0x3e, - 0x8f, 0x74, 0x9f, 0x35, 0x57, 0x83, 0x68, 0xf5, 0x07, 0xe2, 0x4e, 0x85, - 0xf6, 0xb0, 0x94, 0x70, 0xb1, 0x36, 0xee, 0xfb, 0xba, 0x44, 0x86, 0x52, - 0xe0, 0xd3, 0xcd, 0x28, 0x4f, 0x25, 0x72, 0x92, 0xb1, 0x43, 0xdc, 0x92, - 0xaf, 0xf4, 0xbe, 0x95, 0x53, 0x4f, 0xcc, 0x67, 0xbb, 0x0c, 0xf2, 0xba, - 0x64, 0x1e, 0x7a, 0x7e, 0xc6, 0xe3, 0x78, 0xec, 0x3f, 0x39, 0xcf, 0x71, - 0x0b, 0xcd, 0x50, 0x27, 0x4b, 0x0e, 0x36, 0x1a, 0x65, 0xdc, 0x97, 0xd3, - 0x56, 0x41, 0xdb, 0x46, 0xf1, 0x9a, 0xed, 0xf6, 0xa3, 0x45, 0x27, 0xf6, - 0x6b, 0x8e, 0x72, 0x8d, 0xb1, 0x93, 0xd8, 0x73, 0xe5, 0x48, 0xb8, 0x3e, - 0x4e, 0x76, 0x5a, 0x60, 0x77, 0xa5, 0x5c, 0x61, 0x7f, 0x9f, 0xb1, 0x22, - 0xe7, 0xc2, 0xfe, 0xc9, 0x47, 0xf6, 0xad, 0xfb, 0x2b, 0x37, 0xdf, 0x30, - 0x7b, 0x5f, 0xd9, 0x22, 0xf4, 0x57, 0x6a, 0xeb, 0xaf, 0x64, 0x45, 0x56, - 0xe5, 0x80, 0xd2, 0xf7, 0x47, 0xc9, 0xbf, 0x53, 0x28, 0xbb, 0x2c, 0x11, - 0xca, 0x8c, 0xda, 0x63, 0xdc, 0xe7, 0x9f, 0xe5, 0x7c, 0xdb, 0x78, 0x3b, - 0x07, 0x1b, 0xc6, 0xfd, 0x85, 0x35, 0x8e, 0x33, 0xff, 0x2e, 0x43, 0x93, - 0x23, 0x39, 0xf5, 0xfe, 0xb5, 0x7d, 0xa1, 0x7e, 0xc4, 0x7e, 0x06, 0x6d, - 0xdf, 0x51, 0x73, 0xb4, 0xb3, 0x59, 0xf0, 0xa6, 0x9d, 0x46, 0x85, 0x05, - 0xb0, 0xc6, 0xa1, 0x8e, 0x0a, 0xd7, 0x8a, 0xb8, 0xc5, 0xb1, 0x96, 0x2a, - 0x7d, 0xb0, 0x7f, 0x51, 0x63, 0x63, 0xd9, 0x7e, 0x19, 0xed, 0x99, 0xcf, - 0xb6, 0x7d, 0xb0, 0xb7, 0x6c, 0xbf, 0x6c, 0xda, 0x5f, 0xb5, 0xbb, 0xdc, - 0x2b, 0xb4, 0xb9, 0x17, 0x32, 0xc0, 0x3a, 0x6b, 0xb6, 0x14, 0x7c, 0xe0, - 0x18, 0x7f, 0xd8, 0xec, 0x0b, 0x2d, 0x9b, 0xf7, 0x3a, 0x96, 0xf4, 0x78, - 0x7b, 0xc9, 0xe6, 0xcb, 0xb6, 0xb6, 0x65, 0x57, 0x65, 0x73, 0x09, 0x3a, - 0xea, 0x04, 0x64, 0x65, 0xb9, 0x55, 0x8f, 0x72, 0xa9, 0x64, 0x14, 0xb2, - 0x99, 0x9a, 0xe6, 0x34, 0x2f, 0x34, 0xdb, 0x65, 0x34, 0xec, 0x23, 0xaa, - 0xe4, 0x40, 0x8f, 0xb3, 0xdc, 0x36, 0xce, 0x72, 0xdb, 0x38, 0x27, 0x0d, - 0x76, 0x63, 0x3f, 0xda, 0x6e, 0x5e, 0xbe, 0xc6, 0x5e, 0x73, 0xcd, 0x3e, - 0x8a, 0x3d, 0xa9, 0x65, 0x01, 0x58, 0x4c, 0xaf, 0x41, 0xc5, 0x95, 0xf2, - 0xf6, 0xd9, 0x70, 0xaf, 0x96, 0x7a, 0x90, 0xff, 0x53, 0xe4, 0x8f, 0xaf, - 0xb8, 0xb0, 0x43, 0xc4, 0x62, 0x7f, 0x25, 0x5b, 0x15, 0xca, 0xc8, 0x77, - 0x40, 0x77, 0xda, 0xef, 0xb6, 0xc8, 0xd7, 0xd4, 0xf8, 0x19, 0x49, 0x25, - 0xcb, 0x32, 0xe1, 0x33, 0x3d, 0x49, 0x45, 0x8d, 0x7a, 0x1a, 0xe3, 0x7c, - 0x07, 0xf2, 0x27, 0xf2, 0x66, 0xa5, 0x47, 0xec, 0xa9, 0x9f, 0x06, 0xb4, - 0x73, 0xa7, 0xb6, 0x3b, 0xfb, 0x11, 0x19, 0x5b, 0x51, 0xfd, 0xa0, 0x8f, - 0xb4, 0x7f, 0x49, 0xf5, 0x17, 0xf6, 0x85, 0x79, 0x4e, 0x75, 0xf6, 0xe7, - 0xc8, 0x65, 0xd7, 0x46, 0x7f, 0xb7, 0x98, 0x39, 0xf2, 0x19, 0x32, 0xe2, - 0x3a, 0x48, 0xef, 0xb3, 0x43, 0x99, 0xb1, 0xa7, 0xfe, 0x3a, 0xc8, 0xcd, - 0x71, 0x6e, 0xff, 0xcc, 0xe4, 0xfd, 0x47, 0x23, 0x6f, 0x52, 0xb3, 0xb3, - 0xe0, 0x59, 0x66, 0x14, 0xe3, 0xf1, 0x3d, 0x09, 0xfc, 0x23, 0x25, 0xe2, - 0xaf, 0x62, 0xe5, 0x37, 0x41, 0xce, 0xd1, 0x98, 0x49, 0xaf, 0x3d, 0xcb, - 0x2d, 0x29, 0xa0, 0xee, 0x92, 0xd1, 0x07, 0x33, 0xcd, 0xcb, 0x8a, 0x7f, - 0x2f, 0xaa, 0x7d, 0x94, 0x3a, 0x55, 0xa2, 0xde, 0xd8, 0x8e, 0x46, 0xb8, - 0xc7, 0x5f, 0xf0, 0x37, 0x83, 0xa5, 0x6a, 0x2a, 0x99, 0xb4, 0x47, 0xa5, - 0x58, 0x1b, 0x2d, 0xd9, 0x48, 0x9f, 0xac, 0x27, 0xe4, 0xc9, 0x0a, 0xfb, - 0xb9, 0x01, 0x75, 0xa0, 0x88, 0x6c, 0x6c, 0xf2, 0x21, 0xea, 0x1a, 0x8e, - 0xf9, 0x96, 0xa5, 0xc7, 0xc4, 0x1c, 0xbc, 0x1d, 0xeb, 0x93, 0xcd, 0x0b, - 0x56, 0xb1, 0xce, 0xf5, 0x47, 0x7e, 0xb3, 0x5d, 0x1f, 0xb5, 0xeb, 0xed, - 0x50, 0x5f, 0xeb, 0xb5, 0x73, 0xb0, 0xef, 0x6a, 0x95, 0x65, 0xab, 0xbc, - 0x26, 0x76, 0xde, 0xef, 0x32, 0xf2, 0x68, 0xb9, 0x7a, 0xce, 0x4f, 0x46, - 0xa8, 0x13, 0x23, 0xde, 0x29, 0xab, 0x5c, 0xb9, 0x55, 0x72, 0x0e, 0x31, - 0x1c, 0x9f, 0x25, 0x88, 0x64, 0x3d, 0xda, 0x4d, 0x27, 0x92, 0x4d, 0x63, - 0xbf, 0xb1, 0xce, 0x66, 0xf0, 0x65, 0x8c, 0x33, 0x72, 0x1a, 0xfa, 0xd9, - 0x7f, 0x0f, 0xfa, 0xe1, 0xf8, 0xbd, 0x78, 0x77, 0xcc, 0xbe, 0xec, 0x42, - 0xbd, 0x14, 0x36, 0xf7, 0xc5, 0x7e, 0xe9, 0x7f, 0x06, 0x7a, 0x36, 0xec, - 0x9b, 0x75, 0x12, 0xa6, 0x4e, 0x9f, 0xa9, 0x73, 0x37, 0xca, 0x3f, 0x86, - 0x7a, 0x29, 0x9f, 0xd0, 0x16, 0x29, 0xf2, 0x06, 0x31, 0x47, 0xd4, 0x6d, - 0xdc, 0x60, 0xde, 0xc3, 0xf6, 0x77, 0xb6, 0xd5, 0xe5, 0xfb, 0xb5, 0x7a, - 0x78, 0xbe, 0xa5, 0x87, 0xc9, 0xc3, 0x1c, 0xf4, 0x9e, 0xd8, 0xd8, 0xf7, - 0x6e, 0x24, 0xcb, 0xfc, 0x69, 0x3c, 0x3f, 0x1f, 0x94, 0xab, 0xd4, 0xfb, - 0xc0, 0xc1, 0x75, 0xa5, 0xff, 0xd0, 0x6f, 0xce, 0x9a, 0xa9, 0x84, 0xeb, - 0xc4, 0x79, 0x85, 0xb8, 0x44, 0xf1, 0x0c, 0xf4, 0x26, 0xaf, 0xd2, 0xeb, - 0x2a, 0x99, 0x40, 0x9e, 0x6f, 0xf2, 0x7a, 0xda, 0xf2, 0x42, 0x9d, 0xf4, - 0x05, 0xcc, 0x6b, 0x58, 0xad, 0x99, 0x9d, 0x3d, 0x62, 0xe5, 0x15, 0x26, - 0x0a, 0x82, 0x82, 0xd7, 0x25, 0xc5, 0xc9, 0xa7, 0xc1, 0x2b, 0x96, 0x95, - 0xdc, 0x88, 0xc2, 0xf1, 0x73, 0x0f, 0x2c, 0x78, 0x29, 0x85, 0x49, 0xf2, - 0xd0, 0x09, 0x5a, 0x8f, 0x4b, 0x69, 0x00, 0xb4, 0x7b, 0xab, 0xe4, 0xc5, - 0x66, 0x70, 0x1a, 0xf8, 0x7b, 0x6e, 0x75, 0xc6, 0x1a, 0x59, 0xc5, 0xba, - 0x0f, 0x59, 0xe0, 0x4b, 0x9f, 0xe4, 0xcf, 0x91, 0x2f, 0xac, 0xc3, 0xfc, - 0x6e, 0x99, 0x8b, 0x77, 0xda, 0xef, 0x3f, 0x3e, 0x20, 0x31, 0xf2, 0x01, - 0x75, 0x57, 0x21, 0xec, 0x31, 0x8d, 0x89, 0x47, 0xd6, 0x29, 0x47, 0x33, - 0xd6, 0x42, 0x85, 0xba, 0xb5, 0x17, 0x36, 0x5b, 0xad, 0x3f, 0xfa, 0x44, - 0xd9, 0x99, 0xce, 0x3e, 0x3e, 0x1d, 0xd1, 0x7d, 0xb0, 0x5d, 0xd8, 0x47, - 0x3b, 0x3f, 0xf6, 0x29, 0xdd, 0x3b, 0x98, 0x1d, 0xec, 0xe8, 0x37, 0xd1, - 0xd6, 0x2f, 0xca, 0xce, 0xfc, 0x34, 0x42, 0x2c, 0xf8, 0x52, 0x15, 0x7c, - 0x56, 0x73, 0x62, 0x19, 0xdb, 0xcc, 0x58, 0x85, 0xd5, 0x20, 0x98, 0xf3, - 0x6d, 0x89, 0x0c, 0x85, 0x75, 0xf5, 0xbc, 0x66, 0x30, 0xaf, 0x3c, 0xe6, - 0x65, 0x0f, 0x75, 0xd2, 0xf4, 0x39, 0x43, 0xd3, 0x60, 0x1b, 0x4d, 0xf1, - 0x77, 0x98, 0x57, 0x7c, 0x8f, 0x79, 0x9d, 0x1c, 0xd4, 0x7d, 0xc4, 0xdb, - 0xfa, 0x18, 0xea, 0xe8, 0x03, 0xb6, 0x28, 0xce, 0xf6, 0x43, 0x7b, 0xb4, - 0xff, 0x49, 0xaf, 0x6e, 0xcf, 0x36, 0xdd, 0xb0, 0x37, 0xc3, 0x46, 0x57, - 0x3f, 0xd9, 0xa6, 0x5f, 0x9f, 0x84, 0x7e, 0x6d, 0x6f, 0x13, 0xca, 0x65, - 0xbb, 0x5f, 0x46, 0x9f, 0x2c, 0xc4, 0xaf, 0xef, 0x52, 0xb8, 0xe8, 0x2a, - 0xae, 0x8f, 0x02, 0x23, 0xf5, 0x01, 0x93, 0xf4, 0xd3, 0xf7, 0x32, 0x38, - 0x95, 0xbe, 0x18, 0xb1, 0xa9, 0x78, 0x40, 0x76, 0xd0, 0x77, 0xa3, 0x89, - 0x63, 0x22, 0xca, 0xf7, 0x22, 0xa6, 0xa7, 0x1f, 0xc6, 0x71, 0xe8, 0x87, - 0x71, 0xdd, 0xf9, 0x5e, 0x68, 0xf9, 0x65, 0xc3, 0xd0, 0x45, 0xc4, 0xe4, - 0xc4, 0xaf, 0xa1, 0xfd, 0x6b, 0xd7, 0xf1, 0x7b, 0xd1, 0x34, 0xdc, 0x41, - 0x13, 0xf4, 0x24, 0xfc, 0xc1, 0x25, 0xc8, 0x23, 0x70, 0x32, 0xf4, 0xf2, - 0xd3, 0xb3, 0x5b, 0x6b, 0x22, 0xc5, 0x26, 0x6d, 0xf6, 0xa4, 0xc0, 0x97, - 0x03, 0x5d, 0xec, 0x5b, 0xd9, 0x6d, 0xe8, 0xcb, 0xfe, 0x9c, 0x9d, 0x1d, - 0x85, 0xef, 0xef, 0xc8, 0xa2, 0xa1, 0x6d, 0x5e, 0xf9, 0x8d, 0x7d, 0x48, - 0x13, 0x4a, 0xae, 0xe6, 0x41, 0x1f, 0x9f, 0xe7, 0x8d, 0xbf, 0x70, 0xac, - 0xd9, 0x49, 0xdb, 0x0f, 0x41, 0x9b, 0x07, 0x1a, 0x92, 0xf2, 0x2d, 0xf8, - 0x0b, 0xdf, 0x54, 0xfb, 0x32, 0xd4, 0x67, 0x4a, 0x57, 0xd4, 0x4a, 0xf2, - 0x7c, 0xb0, 0x56, 0xe5, 0xbe, 0x25, 0xae, 0xe8, 0x93, 0x12, 0xd6, 0x6b, - 0x64, 0x35, 0x95, 0xcc, 0xd9, 0x62, 0xdd, 0x70, 0x27, 0xe5, 0xe9, 0x09, - 0x19, 0x39, 0x27, 0x96, 0xb3, 0x8a, 0xbd, 0xde, 0x1f, 0x62, 0x3e, 0xce, - 0xef, 0xdd, 0x98, 0x1f, 0xfa, 0xae, 0x86, 0xf3, 0xeb, 0x93, 0xe2, 0x3a, - 0xe7, 0xd7, 0x9a, 0x5b, 0x9c, 0x51, 0x98, 0xa7, 0x60, 0x43, 0x30, 0x47, - 0xd0, 0x38, 0x0d, 0xec, 0xfd, 0x1e, 0x33, 0xa7, 0x3e, 0xcc, 0x09, 0xb8, - 0x61, 0x95, 0xed, 0x41, 0x17, 0x68, 0x2e, 0xa2, 0x5e, 0x79, 0x95, 0x6b, - 0x0e, 0x5a, 0xb1, 0xee, 0xc5, 0x26, 0xd7, 0x9e, 0x73, 0xd3, 0x58, 0xc3, - 0xf1, 0x38, 0x3f, 0xce, 0x73, 0x1c, 0xf3, 0x62, 0x1d, 0xb6, 0xeb, 0x94, - 0x91, 0xf1, 0x77, 0x58, 0x8f, 0x77, 0x77, 0xac, 0x87, 0x98, 0xf5, 0x88, - 0x4a, 0xf7, 0xba, 0xf2, 0xd1, 0x15, 0x0d, 0xf4, 0x6b, 0x1c, 0xd0, 0xbf, - 0xbc, 0x26, 0x93, 0x0c, 0x60, 0xd1, 0x36, 0x20, 0x2f, 0xd3, 0x2d, 0xa3, - 0xfe, 0x05, 0xc8, 0x55, 0x11, 0xb2, 0x40, 0x1f, 0xe5, 0xa5, 0xaa, 0x5e, - 0x8b, 0x62, 0x33, 0x26, 0xf6, 0x69, 0x8e, 0x4f, 0x7e, 0x73, 0x6e, 0xae, - 0x5a, 0x87, 0xf6, 0x75, 0x79, 0xec, 0xba, 0x75, 0xd9, 0x84, 0x1e, 0xa5, - 0x1e, 0x20, 0x16, 0xa3, 0x2e, 0x08, 0xe3, 0x10, 0x7f, 0xe4, 0xea, 0xfd, - 0x14, 0xda, 0xc4, 0xcb, 0x2d, 0xcc, 0xfb, 0xa2, 0xf2, 0x1d, 0xf4, 0x9c, - 0xf2, 0x19, 0xe8, 0xa5, 0xb5, 0x1b, 0xb0, 0x77, 0x68, 0x13, 0x37, 0x83, - 0x5a, 0xb5, 0x4b, 0xd1, 0x90, 0xf7, 0xfb, 0x89, 0xdf, 0x44, 0xdb, 0x01, - 0xa6, 0xcc, 0xa7, 0x8d, 0x44, 0x59, 0x86, 0x6b, 0x89, 0xf7, 0x06, 0xdf, - 0xdb, 0xf5, 0xfe, 0x7f, 0x72, 0xf4, 0x7e, 0x64, 0xec, 0x69, 0x2f, 0x3b, - 0x78, 0x35, 0xe6, 0xe0, 0xc0, 0x57, 0x2e, 0xaf, 0x05, 0xc0, 0x63, 0xef, - 0xc1, 0xde, 0xce, 0x49, 0xd1, 0x85, 0x1d, 0x1f, 0xbf, 0x19, 0x7c, 0x9d, - 0x16, 0x15, 0x67, 0x18, 0xdf, 0x8f, 0xe7, 0x7d, 0xca, 0xa7, 0x29, 0x8e, - 0xbf, 0x57, 0x72, 0x73, 0xc4, 0x43, 0x8f, 0xcb, 0x3c, 0x6c, 0x6e, 0x71, - 0x1c, 0x36, 0x31, 0xce, 0x77, 0xe8, 0x25, 0x6f, 0x8c, 0xb1, 0x09, 0xfc, - 0xfd, 0x1b, 0x13, 0x93, 0x39, 0x88, 0xf7, 0x7d, 0xa8, 0xf3, 0x31, 0x53, - 0xa7, 0x7f, 0x8f, 0x3a, 0x79, 0xbc, 0xdf, 0x8d, 0x3a, 0x31, 0x8c, 0x01, - 0x4c, 0x0b, 0x5b, 0x66, 0x7b, 0x1f, 0x46, 0xde, 0x5d, 0xc8, 0xbb, 0x0b, - 0x79, 0x77, 0xe0, 0xbd, 0x60, 0x62, 0x1d, 0x61, 0x9b, 0x7e, 0xbc, 0x7f, - 0x01, 0xe5, 0xd0, 0x33, 0xee, 0x25, 0x94, 0xdf, 0xad, 0xda, 0x5d, 0x5b, - 0x67, 0xb0, 0xe3, 0x7d, 0xcb, 0xd1, 0xb1, 0x11, 0xe6, 0x0d, 0x9b, 0x67, - 0xb1, 0x96, 0x2b, 0x7c, 0xff, 0xa1, 0x79, 0xbf, 0xb7, 0x23, 0xff, 0x71, - 0xf3, 0xde, 0xb9, 0xae, 0xb7, 0x61, 0x5d, 0x59, 0xfe, 0xd1, 0x03, 0x7a, - 0x3d, 0xc6, 0x74, 0xfc, 0xe1, 0x1a, 0x3c, 0xa2, 0x44, 0x11, 0xcf, 0x3b, - 0xc0, 0x21, 0xc4, 0x26, 0xed, 0xb8, 0x84, 0x34, 0xa9, 0xfa, 0x66, 0x9c, - 0xe7, 0xfa, 0xc3, 0x71, 0xcb, 0x90, 0x81, 0xc3, 0x6b, 0x61, 0xfe, 0xc5, - 0xfe, 0x6b, 0xe9, 0xf9, 0x9f, 0x6d, 0xf5, 0xf6, 0xcb, 0xe1, 0x5a, 0x98, - 0x7f, 0xe8, 0xc0, 0xb5, 0xf5, 0x6e, 0x3e, 0x70, 0x75, 0xae, 0xad, 0x78, - 0x09, 0x68, 0xfb, 0x8c, 0x7d, 0x15, 0x2b, 0xe5, 0xec, 0xc5, 0xe6, 0x8c, - 0xad, 0x69, 0x62, 0x1d, 0x94, 0x35, 0x77, 0x06, 0x1c, 0x25, 0xa3, 0x39, - 0x9b, 0x7e, 0x4a, 0x69, 0x83, 0xcf, 0x37, 0x23, 0x6d, 0x6f, 0x3b, 0x0c, - 0x7d, 0x9b, 0xb3, 0xf5, 0x9c, 0x3a, 0xdb, 0x87, 0xf2, 0xed, 0xcb, 0x52, - 0x0d, 0x32, 0xe9, 0xa5, 0xc6, 0x4b, 0xf0, 0x73, 0x17, 0xfc, 0xd4, 0x1c, - 0x65, 0x16, 0xbe, 0xf0, 0x23, 0x22, 0xb3, 0x52, 0xae, 0x3d, 0x08, 0xec, - 0x1e, 0xc8, 0x87, 0x60, 0xff, 0xff, 0x25, 0xf0, 0x43, 0x1d, 0xba, 0xa0, - 0xde, 0xf4, 0xf0, 0x1b, 0x96, 0xaf, 0x57, 0x12, 0xf2, 0x3c, 0x7c, 0x91, - 0xc6, 0x1a, 0xf5, 0x65, 0xda, 0xfd, 0x90, 0xc8, 0x80, 0x2d, 0xe7, 0xef, - 0xb2, 0x65, 0x22, 0x39, 0x62, 0xa5, 0x13, 0xf8, 0xb9, 0xdd, 0xf8, 0xcd, - 0xc0, 0xff, 0xdb, 0x68, 0x32, 0x8e, 0x10, 0x97, 0x3f, 0xdf, 0x4c, 0xe2, - 0x37, 0x24, 0xff, 0x7e, 0x93, 0xe3, 0x8f, 0x98, 0x34, 0xf4, 0x4d, 0xbe, - 0x05, 0x1d, 0x71, 0x29, 0x58, 0xae, 0x32, 0x26, 0x14, 0xda, 0xa1, 0x6f, - 0x29, 0x3b, 0xb4, 0x54, 0x09, 0x8e, 0x6b, 0x1f, 0xdc, 0x83, 0xcf, 0x8d, - 0xf7, 0xe6, 0x5b, 0x56, 0xa3, 0x35, 0xc7, 0x1d, 0xab, 0x61, 0xd6, 0xad, - 0xd1, 0x9a, 0x23, 0xca, 0x9b, 0x17, 0x20, 0x0b, 0xd4, 0xbf, 0xa1, 0xee, - 0xf5, 0x0c, 0x2e, 0x0a, 0xf5, 0x2f, 0xf6, 0x70, 0x4d, 0xa2, 0xf1, 0xec, - 0x2f, 0x64, 0xed, 0x34, 0xf7, 0x14, 0xed, 0xe5, 0x34, 0x64, 0x31, 0xf5, - 0x95, 0x12, 0x71, 0xb6, 0xc7, 0x98, 0xc0, 0x25, 0xf4, 0x31, 0x3f, 0xa8, - 0x65, 0xe7, 0x12, 0xf6, 0xf9, 0xac, 0x38, 0xa7, 0x3f, 0xdf, 0x25, 0xfd, - 0xc7, 0x65, 0xd9, 0x87, 0x3f, 0x6b, 0x97, 0x82, 0x88, 0xe7, 0x25, 0x0a, - 0xca, 0xdf, 0x5a, 0x03, 0x5d, 0xdf, 0x03, 0x26, 0x3e, 0xae, 0xfc, 0xba, - 0x63, 0x35, 0xd6, 0xed, 0xc6, 0x7a, 0xa4, 0x4a, 0x05, 0xac, 0xd5, 0x89, - 0xf8, 0x05, 0x94, 0x05, 0x81, 0xed, 0x0d, 0x48, 0xb1, 0x1e, 0x3e, 0x43, - 0xf6, 0x37, 0xff, 0x01, 0x32, 0xc6, 0x67, 0xc0, 0xc4, 0x75, 0x96, 0x8d, - 0x20, 0x65, 0x39, 0xcb, 0x3c, 0xa5, 0xeb, 0x8a, 0x4d, 0xd2, 0x31, 0x2b, - 0x85, 0x1a, 0xe7, 0x04, 0xbb, 0x58, 0xbf, 0x14, 0x9c, 0xa8, 0x5e, 0x00, - 0xaf, 0x38, 0x5e, 0x56, 0x1a, 0x58, 0x8b, 0x72, 0xf3, 0x71, 0x60, 0xfa, - 0xd7, 0x91, 0x2e, 0x22, 0xbd, 0x8c, 0xf4, 0x09, 0xa4, 0x6f, 0x20, 0xe5, - 0xbc, 0x1e, 0x97, 0x46, 0x3d, 0xd1, 0x2d, 0x31, 0xf6, 0xf3, 0xd9, 0xd6, - 0x7c, 0xca, 0xd0, 0x0d, 0xb9, 0x56, 0x3e, 0x9f, 0x99, 0x7e, 0x02, 0xe9, - 0x47, 0x91, 0xf7, 0x3d, 0x3c, 0x4f, 0x4b, 0xa1, 0xf2, 0x04, 0xec, 0x30, - 0xb1, 0xea, 0x27, 0x30, 0x2e, 0xc7, 0x7f, 0x19, 0x74, 0xb0, 0x2c, 0x90, - 0x4f, 0x62, 0x9e, 0xf9, 0xda, 0x71, 0x79, 0xd8, 0xbf, 0x45, 0xa6, 0x1e, - 0x26, 0x3d, 0xe4, 0x0d, 0xf5, 0xdb, 0x5e, 0xbc, 0x21, 0x5f, 0x42, 0x7e, - 0xf4, 0x61, 0x5e, 0xd4, 0x55, 0xc4, 0xc6, 0x10, 0xc0, 0x7e, 0x8d, 0x77, - 0x46, 0xc6, 0x02, 0x79, 0xc8, 0xcf, 0x4a, 0xe4, 0xf4, 0x98, 0x9b, 0xb1, - 0x27, 0xe0, 0xf9, 0xa4, 0xf1, 0x3b, 0x0e, 0xb9, 0xf4, 0x4e, 0x8d, 0xd8, - 0x23, 0xa0, 0x09, 0x65, 0x0d, 0x8e, 0x73, 0x29, 0xf8, 0x93, 0xea, 0xab, - 0xf0, 0xdb, 0xb3, 0x72, 0xa5, 0xf9, 0x2a, 0xe4, 0x83, 0xf4, 0x08, 0xe8, - 0x9c, 0x95, 0x1f, 0xd7, 0x5e, 0x96, 0x93, 0xe0, 0xfd, 0x6b, 0x48, 0x97, - 0x6b, 0x25, 0xf0, 0x95, 0xf1, 0x7b, 0xf6, 0x11, 0x60, 0xcd, 0x46, 0xe1, - 0x6f, 0xdd, 0x96, 0x58, 0xc4, 0xfa, 0xce, 0xbb, 0x81, 0x6c, 0xf9, 0x25, - 0xd9, 0x9a, 0x46, 0x9b, 0x3a, 0xdb, 0xf7, 0xca, 0x61, 0x95, 0x52, 0xfe, - 0xfa, 0x31, 0xc7, 0x98, 0xe2, 0xf3, 0x72, 0x35, 0x94, 0x3d, 0xca, 0x61, - 0xa7, 0xfc, 0x91, 0xee, 0x1d, 0xeb, 0x9b, 0x4d, 0xda, 0xd1, 0xbd, 0x6c, - 0x62, 0x28, 0x97, 0xb4, 0x8b, 0xed, 0xb2, 0x29, 0xd2, 0xa8, 0x69, 0xff, - 0xe6, 0x1b, 0xdb, 0x4a, 0xd6, 0xb1, 0x3e, 0xc4, 0xd3, 0x3f, 0x17, 0xe0, - 0x37, 0xf0, 0x29, 0x8c, 0x2f, 0x6a, 0xbf, 0xab, 0x0e, 0x7a, 0xe1, 0x6b, - 0x00, 0x2b, 0x88, 0xd4, 0xeb, 0x9f, 0x57, 0xfc, 0xf2, 0x4e, 0x0f, 0x4b, - 0xad, 0x4a, 0x1e, 0xa7, 0x5c, 0xdb, 0x56, 0xfe, 0x0d, 0x78, 0xeb, 0x41, - 0x56, 0xc2, 0xf2, 0x14, 0xfc, 0xaf, 0xe3, 0xe2, 0x4e, 0xc5, 0x60, 0xbf, - 0xf8, 0x2c, 0x32, 0x77, 0xae, 0x13, 0x0b, 0x86, 0x36, 0xa6, 0x1b, 0x7e, - 0x7e, 0x17, 0x74, 0x41, 0x1f, 0xfc, 0x74, 0xf8, 0xbf, 0x90, 0xa7, 0x3f, - 0x01, 0x7e, 0x3a, 0xa5, 0x7c, 0x76, 0xee, 0xc3, 0x07, 0x67, 0x47, 0x36, - 0x99, 0x7e, 0x78, 0x36, 0x5d, 0x67, 0x7a, 0xd4, 0xc4, 0xf5, 0x1f, 0x31, - 0xf1, 0xfe, 0xf9, 0xd9, 0x83, 0x2a, 0x5d, 0x9c, 0x1d, 0x57, 0xe9, 0xe3, - 0xb3, 0x57, 0x63, 0x31, 0x17, 0x20, 0xab, 0xa4, 0x4d, 0x9c, 0x62, 0x26, - 0x23, 0x9b, 0x15, 0x1f, 0x7e, 0xf7, 0x34, 0xf0, 0xc7, 0x34, 0xe4, 0x36, - 0x0b, 0x7a, 0xa1, 0x7f, 0xb2, 0x3e, 0x52, 0x31, 0x7f, 0x61, 0xbb, 0x6e, - 0xc6, 0xdd, 0xb8, 0x66, 0xc6, 0x77, 0xf5, 0xe9, 0xbb, 0xb6, 0xff, 0xb1, - 0x4f, 0xc8, 0x38, 0xed, 0xee, 0xaf, 0xe1, 0x6f, 0xb3, 0x7f, 0xb6, 0x65, - 0xff, 0x22, 0xbb, 0x6b, 0x12, 0x8d, 0x66, 0xff, 0x5a, 0xa2, 0xcf, 0x06, - 0xc1, 0x4f, 0xfc, 0xd4, 0x91, 0x92, 0x80, 0x4f, 0x16, 0xf2, 0x37, 0x59, - 0x46, 0x9d, 0x35, 0xe1, 0x5e, 0x81, 0xcc, 0xe5, 0x8e, 0x8a, 0xbc, 0x82, - 0xbc, 0xc6, 0x1a, 0xf9, 0xff, 0x3d, 0xf0, 0xdf, 0xac, 0x87, 0xca, 0x63, - 0x3d, 0xf8, 0x48, 0x71, 0xca, 0xdc, 0x84, 0xdb, 0x83, 0xf6, 0xf5, 0x4d, - 0xb6, 0x49, 0x4d, 0xf3, 0x98, 0xec, 0x95, 0xcd, 0x0b, 0x4a, 0x5f, 0x75, - 0x67, 0xc7, 0x19, 0x43, 0x92, 0x8d, 0xb5, 0xdf, 0x04, 0x0b, 0xfe, 0x0e, - 0x80, 0x5a, 0x0a, 0x72, 0x9f, 0x95, 0xf3, 0xc0, 0x58, 0xe7, 0x2b, 0x69, - 0xac, 0x0d, 0xf0, 0x6d, 0x82, 0x24, 0x7b, 0xa8, 0xf7, 0x66, 0x37, 0x71, - 0x6c, 0x9e, 0xe7, 0x47, 0x95, 0x69, 0xd9, 0x6d, 0xce, 0x09, 0xb1, 0x52, - 0x3e, 0xc3, 0xf9, 0xb4, 0xf3, 0x41, 0xff, 0x15, 0xb1, 0x06, 0x66, 0x7e, - 0xea, 0x0f, 0x74, 0x62, 0x3f, 0xa1, 0xbd, 0xbf, 0x83, 0xbd, 0x91, 0x82, - 0x7e, 0x15, 0x07, 0x7e, 0xa2, 0xa4, 0xcf, 0x3a, 0x4e, 0xbe, 0xe2, 0xc8, - 0xc8, 0x59, 0x6c, 0xa9, 0xac, 0xe1, 0x43, 0x33, 0x94, 0xb1, 0x50, 0xe7, - 0x51, 0xa6, 0x38, 0xff, 0x54, 0x69, 0x07, 0x8c, 0x1e, 0xcc, 0x5e, 0x94, - 0x87, 0xd7, 0xf5, 0x7c, 0xed, 0x33, 0xc2, 0xb3, 0x13, 0xb9, 0xb2, 0x96, - 0xf2, 0x2f, 0x0b, 0xfd, 0x5f, 0x1f, 0x32, 0x72, 0xb1, 0x1b, 0xfb, 0x79, - 0x3a, 0x67, 0x1f, 0xec, 0xd1, 0xb6, 0xd9, 0xc1, 0x1e, 0x00, 0x4e, 0xac, - 0xc0, 0x6f, 0xf6, 0x7a, 0xe4, 0x5f, 0x38, 0x78, 0x26, 0x6e, 0x44, 0x9e, - 0xb1, 0xa3, 0x78, 0xd6, 0xfd, 0x95, 0x31, 0x0f, 0x1d, 0x57, 0xb6, 0xe4, - 0x61, 0x58, 0x15, 0x41, 0xff, 0x23, 0x66, 0xac, 0x91, 0x33, 0x17, 0xd4, - 0x7e, 0x4d, 0xaf, 0x67, 0x81, 0xa3, 0x1c, 0xe3, 0x6f, 0x52, 0x4f, 0xc9, - 0x1e, 0xfe, 0x4a, 0x28, 0xa3, 0x17, 0x82, 0x2f, 0x56, 0xc3, 0x98, 0x40, - 0x46, 0x46, 0x56, 0xb4, 0x4c, 0x3d, 0x9e, 0x81, 0xce, 0x86, 0x2c, 0x8d, - 0xac, 0x04, 0xf2, 0x13, 0xdf, 0x97, 0x53, 0xdb, 0x7b, 0xc9, 0x54, 0xe7, - 0x5f, 0x1f, 0xe8, 0xe4, 0x6f, 0x48, 0x96, 0xfe, 0x14, 0x74, 0x9e, 0x75, - 0xf1, 0x9c, 0x9a, 0x9b, 0xa7, 0x8f, 0x70, 0x16, 0xba, 0x14, 0xbe, 0xac, - 0x7d, 0x76, 0x58, 0xd5, 0xb1, 0xcf, 0xc2, 0xc6, 0x41, 0xc6, 0x6c, 0xf0, - 0xb5, 0x0c, 0x7b, 0x67, 0x9f, 0xed, 0x82, 0x5d, 0xe4, 0x1e, 0x95, 0x41, - 0x1b, 0xba, 0x80, 0xf5, 0x1b, 0xd8, 0x2b, 0xf6, 0xd9, 0x3e, 0xa4, 0x49, - 0xd5, 0x57, 0xa3, 0xe2, 0xa9, 0xf6, 0x8d, 0xca, 0xb8, 0x6a, 0xd7, 0xa8, - 0x4c, 0x22, 0x85, 0x8e, 0xcf, 0xf8, 0xd2, 0x7d, 0x36, 0x23, 0x72, 0xd6, - 0x92, 0xe2, 0x5c, 0x10, 0xc4, 0x40, 0x7b, 0xec, 0xec, 0x01, 0xb9, 0xac, - 0xd6, 0x76, 0x4e, 0x46, 0x9e, 0x25, 0xbf, 0xb2, 0xa8, 0x3b, 0x23, 0xe9, - 0x67, 0x67, 0xc4, 0x7b, 0x96, 0x3c, 0x61, 0xac, 0x7e, 0x57, 0xc9, 0xd4, - 0x27, 0xe4, 0x28, 0xec, 0x4a, 0x0f, 0xf6, 0x84, 0xe3, 0x96, 0x65, 0x05, - 0x6b, 0x32, 0xea, 0x1e, 0x86, 0x9c, 0xc9, 0xdb, 0xd6, 0x67, 0x5d, 0xb6, - 0x61, 0xfd, 0x83, 0x90, 0x17, 0x0f, 0xf5, 0x8f, 0xc2, 0xc6, 0xb4, 0xf3, - 0x82, 0xfb, 0x2c, 0xf7, 0x0e, 0xf2, 0x17, 0xee, 0xaf, 0x0b, 0xc1, 0xc9, - 0x2a, 0xf7, 0x18, 0xf7, 0xd7, 0x87, 0xe4, 0x15, 0x6f, 0x4e, 0x76, 0xbd, - 0x8c, 0x5c, 0x00, 0x0e, 0x7d, 0xd9, 0x9b, 0x91, 0x8b, 0x5e, 0xb4, 0x87, - 0x31, 0xb6, 0x06, 0x71, 0x72, 0x6b, 0xcd, 0xe2, 0xc6, 0x1f, 0x79, 0x43, - 0xb6, 0x2a, 0xb4, 0xd5, 0xc1, 0xa1, 0x05, 0xbf, 0x74, 0x33, 0x68, 0x03, - 0x1d, 0x8c, 0x1b, 0x5c, 0xb5, 0x11, 0x5d, 0xd8, 0x43, 0x1b, 0xca, 0x46, - 0xf4, 0xd1, 0x46, 0xf8, 0x05, 0xd9, 0x2f, 0xbb, 0x35, 0x1d, 0xd3, 0xcb, - 0x03, 0x43, 0xed, 0xd6, 0xb9, 0xfe, 0x71, 0xf9, 0x52, 0x95, 0x73, 0x2d, - 0xdf, 0x10, 0x93, 0x88, 0x1c, 0x51, 0x36, 0xbb, 0x5f, 0xce, 0x6f, 0x02, - 0xf3, 0x02, 0x7d, 0xd8, 0xb7, 0x32, 0x26, 0x64, 0xab, 0x18, 0x83, 0x0c, - 0xd0, 0x66, 0xfd, 0x17, 0xf0, 0x88, 0x71, 0x20, 0xcc, 0x71, 0x80, 0xb3, - 0x09, 0xdf, 0x27, 0x65, 0xb7, 0xc2, 0x67, 0x4b, 0x0a, 0xf0, 0x27, 0x77, - 0x2b, 0x4c, 0x13, 0x48, 0x4d, 0x8c, 0x5f, 0x61, 0xf8, 0xbf, 0x55, 0xe5, - 0x3d, 0xde, 0x2c, 0xd6, 0x85, 0x72, 0x8b, 0x74, 0x4b, 0x8f, 0x5b, 0x80, - 0xcf, 0x5f, 0x9c, 0xec, 0xa5, 0xfd, 0x02, 0x6e, 0x72, 0x64, 0x5e, 0xd5, - 0xcf, 0xc8, 0xc5, 0xca, 0xcf, 0xcc, 0x3e, 0x99, 0x36, 0xcf, 0x2c, 0x67, - 0xac, 0x87, 0x3e, 0xcd, 0x91, 0xd9, 0x65, 0xef, 0x03, 0xa6, 0x5c, 0xc5, - 0x5c, 0xac, 0x0f, 0x02, 0x43, 0x8e, 0xac, 0x74, 0x63, 0x3e, 0xf6, 0x90, - 0x3e, 0x93, 0x39, 0x24, 0x33, 0xfe, 0x41, 0xd0, 0x7f, 0x40, 0xca, 0xf0, - 0x95, 0x96, 0xb6, 0xa1, 0x57, 0xc6, 0xe1, 0x13, 0xbb, 0xb7, 0x13, 0xa3, - 0xa9, 0x98, 0x52, 0xd9, 0x1d, 0x45, 0xda, 0x83, 0xf4, 0x66, 0x29, 0x3f, - 0x73, 0x43, 0x54, 0xf7, 0xd7, 0xd5, 0xf1, 0xfe, 0x3c, 0xc7, 0x4e, 0x26, - 0xad, 0xdf, 0x86, 0x07, 0xdb, 0xb1, 0x20, 0xe9, 0xe8, 0x12, 0xef, 0xcb, - 0x7d, 0x32, 0xba, 0xe2, 0xca, 0xd8, 0x4a, 0x42, 0x0e, 0xae, 0x0c, 0xcb, - 0xf8, 0x4a, 0x52, 0x6e, 0x5d, 0x09, 0xf1, 0xd8, 0x83, 0xb3, 0x69, 0x63, - 0x07, 0xbc, 0xdf, 0xd1, 0x0e, 0xdc, 0xda, 0xd4, 0xd8, 0xb4, 0xbc, 0x71, - 0x01, 0x36, 0x7b, 0x07, 0xfb, 0x37, 0x03, 0x2c, 0xe6, 0x43, 0x27, 0x4d, - 0x42, 0x27, 0x8d, 0x43, 0x27, 0x4d, 0x53, 0x27, 0x01, 0xff, 0xbd, 0x0a, - 0xfc, 0x77, 0x8f, 0xbc, 0x06, 0x9d, 0xfb, 0x82, 0xdf, 0xe3, 0xce, 0x81, - 0x1f, 0x87, 0xd5, 0xb9, 0x57, 0xea, 0x2b, 0x3b, 0x90, 0x81, 0xc6, 0xd7, - 0x24, 0x3a, 0x00, 0x7d, 0x75, 0xfb, 0x7a, 0x8f, 0x6c, 0xc4, 0x83, 0xe0, - 0x34, 0xf6, 0xfa, 0x95, 0x8a, 0x96, 0xd9, 0xbc, 0xc7, 0x3d, 0xff, 0x20, - 0xe6, 0x3e, 0x89, 0xbc, 0x1c, 0x74, 0x98, 0x8e, 0xa3, 0x34, 0x8e, 0x26, - 0x64, 0xf3, 0xe0, 0x74, 0x47, 0xbd, 0x0c, 0xde, 0xa9, 0x33, 0xfe, 0x39, - 0xea, 0x53, 0x7f, 0xbb, 0xb2, 0x05, 0x8c, 0x78, 0xe6, 0x60, 0x6a, 0x3a, - 0x69, 0x53, 0xdf, 0x25, 0xa5, 0xfe, 0xb5, 0x84, 0x6c, 0x54, 0xb5, 0xcd, - 0x59, 0x00, 0x26, 0x2c, 0x00, 0xef, 0x6e, 0x00, 0x67, 0x15, 0x9a, 0x5a, - 0xdf, 0xdb, 0xd9, 0x2e, 0x61, 0x7f, 0x85, 0x66, 0x1e, 0xf8, 0x58, 0x9c, - 0x7c, 0x86, 0x74, 0x4e, 0x24, 0x22, 0x76, 0x0f, 0x64, 0x81, 0xfb, 0xe3, - 0x41, 0xd8, 0x53, 0x96, 0xd1, 0x36, 0x53, 0xff, 0x3f, 0x15, 0x25, 0xc6, - 0x2b, 0xf8, 0xc4, 0xd3, 0x79, 0x94, 0xa5, 0x12, 0x69, 0xe4, 0xcf, 0x49, - 0x5a, 0x9d, 0x21, 0x2d, 0x60, 0xcf, 0x97, 0x15, 0xcd, 0x11, 0xc6, 0xa4, - 0x28, 0x1e, 0x51, 0x1d, 0x2f, 0x0c, 0xf3, 0x27, 0xdc, 0x22, 0xd6, 0x38, - 0xc7, 0xbe, 0xab, 0xcc, 0x4b, 0xbb, 0x6c, 0x57, 0xf0, 0xf9, 0x2e, 0xf2, - 0x91, 0x26, 0xe3, 0x27, 0x51, 0x79, 0xb8, 0xd9, 0x07, 0x9a, 0xba, 0x7f, - 0x8b, 0x3d, 0x71, 0xdb, 0xec, 0xc9, 0x6e, 0xc2, 0x85, 0x9e, 0x58, 0x34, - 0x7a, 0xc5, 0x99, 0xd2, 0x18, 0xf8, 0xa5, 0x2a, 0xd6, 0xa8, 0x8a, 0x35, - 0xaa, 0x62, 0x8d, 0xaa, 0x58, 0xa3, 0x2a, 0xf5, 0x07, 0x75, 0x4d, 0xce, - 0x9c, 0x31, 0x50, 0x87, 0x3c, 0x8f, 0xb5, 0x9c, 0x93, 0x6f, 0x6f, 0xcf, - 0xca, 0x5f, 0x6c, 0x1f, 0x01, 0xc6, 0x9e, 0xc1, 0xba, 0xe6, 0xb0, 0xae, - 0xd3, 0x58, 0xd3, 0xa3, 0x58, 0xd3, 0x2c, 0xcf, 0xd9, 0xe4, 0xcb, 0x95, - 0xd4, 0x0b, 0x25, 0x85, 0xef, 0xdf, 0xc0, 0xfa, 0x4e, 0x89, 0xb7, 0x3e, - 0x0c, 0x9d, 0x50, 0x0a, 0xe2, 0x5e, 0x70, 0x08, 0x18, 0x1a, 0xf3, 0x2f, - 0xa5, 0x1c, 0x45, 0x83, 0xe7, 0x7e, 0x0a, 0x13, 0xbf, 0x21, 0x9b, 0xaa, - 0x51, 0x3d, 0x6d, 0xd5, 0xc6, 0xa5, 0x78, 0x0e, 0xf5, 0x4f, 0xf7, 0x81, - 0xdf, 0xc4, 0x6f, 0xa9, 0x52, 0x51, 0x76, 0xa0, 0xcf, 0x72, 0xa0, 0xf1, - 0xbd, 0x52, 0x8e, 0xa7, 0x9e, 0xe7, 0x3e, 0xbb, 0x71, 0x95, 0xf1, 0x01, - 0x1b, 0xbc, 0x21, 0xed, 0x78, 0x3e, 0x97, 0x55, 0x31, 0xbe, 0xbc, 0x7f, - 0xc0, 0xec, 0x63, 0x8d, 0x49, 0xeb, 0xc2, 0x71, 0x39, 0xde, 0x67, 0x64, - 0x11, 0xb8, 0xcf, 0xce, 0x12, 0x57, 0x78, 0x09, 0x8c, 0x19, 0x5d, 0x38, - 0xe7, 0x46, 0x17, 0xcf, 0xb1, 0x9f, 0xa8, 0xa4, 0x57, 0xa9, 0x97, 0xd8, - 0x0f, 0x74, 0x36, 0xfa, 0x8e, 0xa8, 0x33, 0xb5, 0x09, 0xb4, 0xfb, 0x03, - 0x60, 0x46, 0xcd, 0xc3, 0xfc, 0x69, 0x6d, 0xc7, 0xf2, 0x8d, 0x76, 0xcc, - 0x06, 0x1d, 0x02, 0x3b, 0x97, 0x6b, 0x68, 0xfc, 0x35, 0xa3, 0xf0, 0x99, - 0xc6, 0x66, 0x47, 0xe5, 0x50, 0xaf, 0xc4, 0x3c, 0x35, 0x9f, 0xf4, 0xe9, - 0x1d, 0x62, 0x52, 0x8c, 0xa1, 0xe3, 0xcc, 0x57, 0xe9, 0xce, 0x60, 0x2e, - 0x37, 0xf7, 0x86, 0x31, 0x41, 0x7b, 0x55, 0x9f, 0x41, 0xd9, 0xe7, 0x7c, - 0xcc, 0x47, 0x86, 0x18, 0x65, 0xb4, 0x31, 0x87, 0x7b, 0x95, 0x9d, 0x9d, - 0x62, 0xec, 0x0f, 0xb2, 0x4d, 0xfd, 0x32, 0x84, 0xbd, 0xc1, 0x77, 0x1d, - 0x53, 0xee, 0xf1, 0x28, 0x2f, 0x71, 0xc8, 0x20, 0x74, 0x4d, 0xff, 0xb0, - 0xd4, 0xb7, 0x59, 0x36, 0xac, 0xf4, 0xb0, 0x83, 0x35, 0x58, 0xae, 0x04, - 0x87, 0xf2, 0x7e, 0x09, 0xda, 0x92, 0x3c, 0x27, 0x3f, 0xc8, 0xf7, 0x49, - 0xd0, 0x46, 0x1e, 0xf7, 0x97, 0xf4, 0xb9, 0xe6, 0x7e, 0x29, 0xd6, 0xa8, - 0x8b, 0x91, 0xd6, 0xf7, 0x9b, 0xd8, 0x46, 0x5c, 0x72, 0x73, 0x9c, 0x3b, - 0x7d, 0x13, 0xa0, 0xba, 0xd5, 0x94, 0x5f, 0xb7, 0x67, 0xa5, 0x48, 0xf9, - 0x84, 0x6e, 0x2c, 0x6e, 0x4e, 0xc9, 0xf2, 0x1a, 0xe3, 0x7d, 0x3c, 0x7b, - 0x9e, 0x88, 0x4a, 0x7f, 0x10, 0x6c, 0xf9, 0xb4, 0xf3, 0x79, 0x29, 0x20, - 0xdf, 0x5e, 0x87, 0x9d, 0x3f, 0xaa, 0x79, 0xc7, 0xf9, 0x96, 0x37, 0xfe, - 0x6f, 0xf8, 0xf8, 0xf6, 0x38, 0x77, 0x66, 0x0f, 0x9c, 0xfb, 0xea, 0x39, - 0xc8, 0x5f, 0x15, 0xb2, 0x09, 0x9f, 0xe9, 0x2f, 0xaa, 0x90, 0x4d, 0xd8, - 0x8c, 0x6f, 0x56, 0x21, 0x9b, 0xd8, 0x3b, 0x2f, 0xc2, 0xa7, 0xd1, 0x98, - 0xe2, 0x11, 0x85, 0x29, 0x4e, 0x54, 0x89, 0xf9, 0x2f, 0x41, 0x96, 0x27, - 0x21, 0xc7, 0x49, 0xc8, 0xaf, 0x0f, 0xd9, 0x1d, 0x87, 0x3c, 0x7b, 0x90, - 0xe7, 0x61, 0x15, 0xf7, 0x79, 0x61, 0x3b, 0x2a, 0xf7, 0xc3, 0x9f, 0x38, - 0x53, 0x23, 0x1f, 0x8f, 0xcb, 0xff, 0x82, 0x2f, 0xb1, 0xeb, 0xef, 0x80, - 0x87, 0x39, 0x59, 0xf4, 0xc8, 0xaf, 0x9c, 0xbd, 0xe0, 0xd1, 0xd7, 0x70, - 0xe5, 0xcc, 0x06, 0x7d, 0x04, 0xea, 0x88, 0x57, 0xe5, 0x9b, 0x95, 0x1f, - 0xc8, 0xb7, 0x80, 0x05, 0x0a, 0xf0, 0x9b, 0x37, 0x9e, 0xa1, 0xcf, 0xa8, - 0x68, 0x84, 0xdc, 0xc5, 0x65, 0x73, 0xfb, 0x76, 0x79, 0xca, 0xa5, 0x0c, - 0xc7, 0xa1, 0x5b, 0xf0, 0x7e, 0x90, 0x7a, 0x28, 0x83, 0xfd, 0x09, 0x39, - 0x87, 0x6e, 0xa8, 0xd9, 0x3c, 0xc3, 0x28, 0x05, 0x03, 0xd4, 0x59, 0x35, - 0xcf, 0x1d, 0xb1, 0xc9, 0x9b, 0x5b, 0x18, 0x73, 0xfa, 0x0a, 0x84, 0x17, - 0x79, 0xb4, 0xd9, 0x48, 0xeb, 0xd0, 0x8d, 0xcf, 0x90, 0x8f, 0xf4, 0x61, - 0xf1, 0xbc, 0xc1, 0xbd, 0xf6, 0x73, 0x15, 0xcb, 0x2d, 0xce, 0xc1, 0x5f, - 0xdf, 0x20, 0x9f, 0x20, 0x2b, 0xcf, 0x90, 0x8f, 0xe4, 0x9d, 0xe6, 0xe3, - 0x43, 0x12, 0xf2, 0x90, 0x65, 0x9d, 0x3c, 0xfc, 0x77, 0x90, 0xc3, 0x38, - 0xe6, 0xfd, 0xd5, 0x28, 0x63, 0x8e, 0x37, 0x7a, 0x5c, 0xf3, 0x57, 0xe5, - 0xc9, 0x26, 0xc7, 0x7a, 0xd9, 0x8c, 0xf9, 0xfd, 0xe0, 0xe1, 0x38, 0x69, - 0xe7, 0x7a, 0xee, 0x93, 0xc6, 0x90, 0x6f, 0xe2, 0x2a, 0xbf, 0xcd, 0xde, - 0xb0, 0x1e, 0x78, 0x0d, 0xbd, 0xf2, 0xad, 0x2a, 0x78, 0x0c, 0xbf, 0xe9, - 0x1b, 0xf0, 0x9b, 0x18, 0x6b, 0xd4, 0xeb, 0x32, 0x6d, 0xe2, 0xa6, 0x9d, - 0xf1, 0xd2, 0x24, 0xd6, 0x85, 0xbe, 0x79, 0xaa, 0x74, 0x19, 0xba, 0xef, - 0x45, 0x9f, 0x71, 0xc4, 0x40, 0xbe, 0xef, 0xb7, 0x6b, 0x37, 0x15, 0x63, - 0x96, 0x87, 0xa0, 0x0f, 0x1f, 0x86, 0x3e, 0xfc, 0xc8, 0x75, 0xf7, 0x7b, - 0x28, 0x67, 0x4f, 0xcf, 0x2e, 0xac, 0x8d, 0x96, 0x22, 0xf6, 0xb0, 0xcc, - 0x5d, 0xa3, 0x1b, 0x19, 0x4f, 0x4c, 0x9a, 0x78, 0x68, 0x3b, 0xfe, 0x0c, - 0x63, 0x9e, 0x94, 0xe7, 0x40, 0x2e, 0xfa, 0xa5, 0xbe, 0x88, 0x3a, 0x97, - 0xe6, 0xba, 0xee, 0x85, 0x2d, 0xbf, 0x6d, 0xf6, 0x30, 0x65, 0xab, 0xf3, - 0xdc, 0x98, 0xe7, 0xd0, 0xfd, 0xf0, 0x13, 0xb8, 0x57, 0x53, 0xc9, 0x1c, - 0xf6, 0x73, 0x79, 0x9b, 0xfa, 0x9f, 0xd8, 0xb0, 0x9b, 0xf1, 0xbc, 0xf9, - 0x9e, 0x2c, 0x63, 0x01, 0xfd, 0xf0, 0x3f, 0x7e, 0x24, 0x5b, 0x6b, 0x7f, - 0xd3, 0xab, 0xf7, 0x91, 0xbe, 0x6f, 0x66, 0x9f, 0xeb, 0x8c, 0x63, 0xd2, - 0xa6, 0x4a, 0xb4, 0x17, 0x76, 0xf1, 0xd6, 0x67, 0xfb, 0x95, 0xdd, 0xbb, - 0xcf, 0x77, 0x64, 0x27, 0xce, 0xfe, 0x7e, 0x24, 0x3f, 0x5e, 0x1b, 0x89, - 0x31, 0xfe, 0xb9, 0x0c, 0x3e, 0xef, 0x2a, 0xdd, 0xf5, 0x20, 0xea, 0x64, - 0xe5, 0xf5, 0x35, 0xda, 0xd6, 0xb4, 0x7b, 0x46, 0x26, 0x12, 0x67, 0xc0, - 0xcb, 0x53, 0x68, 0x03, 0x7f, 0x38, 0x98, 0x41, 0xde, 0xcb, 0xf4, 0xb9, - 0x2d, 0x3e, 0x4f, 0xb8, 0x5f, 0x04, 0x4e, 0xce, 0xb9, 0x69, 0xb7, 0xd7, - 0xba, 0xa4, 0xce, 0x9d, 0x22, 0x1e, 0xfb, 0x1a, 0x92, 0xc2, 0xa6, 0xa6, - 0xf1, 0xca, 0x26, 0xc7, 0xe0, 0x5c, 0x48, 0xe3, 0xdf, 0xf0, 0x5c, 0x01, - 0xf4, 0xdf, 0x06, 0x9f, 0x84, 0x98, 0xe5, 0x12, 0x64, 0x66, 0x08, 0xfa, - 0x81, 0xbe, 0x0a, 0xcf, 0x2c, 0xc9, 0xb3, 0xcf, 0x03, 0xef, 0xc7, 0x21, - 0xab, 0xc8, 0xdf, 0xbc, 0xea, 0x1f, 0x2e, 0xb7, 0x70, 0x3d, 0x6d, 0xe3, - 0x2c, 0x6c, 0xe4, 0xbb, 0x14, 0x3d, 0x47, 0x7c, 0xf8, 0xda, 0xcf, 0x50, - 0xbe, 0x0e, 0x4a, 0x31, 0x4e, 0x5c, 0x49, 0x7d, 0xb2, 0x9b, 0x88, 0x02, - 0xd7, 0x46, 0x6f, 0xe7, 0xbe, 0x3b, 0x22, 0xf7, 0x7b, 0x0f, 0xca, 0x07, - 0xbd, 0x49, 0x99, 0xf1, 0xee, 0x91, 0xc3, 0x5e, 0x5e, 0xee, 0xf3, 0x60, - 0x9b, 0x14, 0x3e, 0xef, 0xc1, 0x3c, 0x38, 0xf6, 0x90, 0x39, 0xdf, 0xd3, - 0xf8, 0xf4, 0xeb, 0xdb, 0x5a, 0x27, 0xe5, 0xd7, 0xb2, 0x31, 0xda, 0xe4, - 0x23, 0xfe, 0x8c, 0xb1, 0xc9, 0xf0, 0xf9, 0x55, 0xbd, 0x19, 0x65, 0xbb, - 0xcb, 0x9b, 0x73, 0x48, 0x61, 0xc7, 0x37, 0xa7, 0x81, 0xfb, 0xe9, 0x4b, - 0xe5, 0xf0, 0x7e, 0x0f, 0xde, 0x3f, 0x84, 0xf4, 0x08, 0x52, 0x75, 0xae, - 0x19, 0xd3, 0xb1, 0xdb, 0xd6, 0xb9, 0x1d, 0xe4, 0xeb, 0xe8, 0xec, 0x42, - 0x2d, 0x8c, 0x81, 0x1f, 0x92, 0xc7, 0x7d, 0x7d, 0x96, 0x7e, 0x18, 0x7e, - 0x74, 0x0c, 0xf8, 0xe9, 0x43, 0xcf, 0x4e, 0x49, 0xe4, 0xee, 0x43, 0x62, - 0xdf, 0x6d, 0xc9, 0xc2, 0x24, 0xe8, 0x9b, 0x1c, 0xc5, 0x3c, 0x86, 0xe5, - 0xc4, 0xb6, 0xf2, 0x51, 0x0d, 0x5e, 0xa4, 0x1e, 0x07, 0xd6, 0xdd, 0x0e, - 0x71, 0x63, 0x37, 0x70, 0x05, 0xe3, 0x7b, 0x49, 0x85, 0x77, 0xed, 0x1b, - 0xb9, 0xbe, 0x7d, 0x92, 0xbf, 0x91, 0xfc, 0x63, 0x1e, 0xfc, 0x9d, 0x1b, - 0xb5, 0xdd, 0x48, 0xaf, 0x70, 0x6d, 0x7a, 0x4c, 0xec, 0x96, 0x36, 0x80, - 0xe9, 0x6a, 0xac, 0x85, 0x0b, 0x19, 0x9f, 0xb1, 0x6e, 0x8f, 0x5d, 0xbd, - 0x67, 0x16, 0xca, 0x73, 0x78, 0x7f, 0xc0, 0x53, 0x38, 0xe7, 0x44, 0xf5, - 0x05, 0xcc, 0x81, 0x36, 0x3d, 0x22, 0xdd, 0xd0, 0x6b, 0x5b, 0x1e, 0xf7, - 0x1e, 0x6d, 0xce, 0x11, 0xcc, 0x87, 0x36, 0x9e, 0xb6, 0xfe, 0xde, 0x7e, - 0xe9, 0xa7, 0x9d, 0x67, 0xfd, 0x24, 0xca, 0x58, 0x97, 0x79, 0x97, 0x51, - 0x9f, 0xb1, 0x29, 0xf8, 0x3e, 0xd5, 0x45, 0xe8, 0x19, 0x0f, 0xe9, 0xe3, - 0x48, 0xc7, 0x91, 0x3e, 0x81, 0x54, 0xc7, 0xb1, 0x36, 0x9f, 0x61, 0x2c, - 0x49, 0xc5, 0x68, 0x14, 0xbe, 0xa0, 0x4d, 0x9c, 0xf3, 0xa9, 0x27, 0x8f, - 0x8b, 0x3d, 0x75, 0x1b, 0xf2, 0xe8, 0x6b, 0x63, 0xd4, 0xf7, 0x7f, 0xde, - 0xc4, 0x88, 0x5a, 0x71, 0x25, 0x63, 0x07, 0xd6, 0xd0, 0x17, 0xfb, 0xa1, - 0x2f, 0xfb, 0x0b, 0x79, 0xf8, 0x9a, 0xd8, 0x5c, 0x2b, 0xde, 0x34, 0x5d, - 0x50, 0x3a, 0x96, 0x7c, 0x81, 0x7e, 0x75, 0x33, 0xf2, 0xb5, 0xed, 0x01, - 0xe8, 0xaf, 0x38, 0xb1, 0x26, 0xf0, 0xb6, 0xc6, 0x6e, 0x8b, 0x98, 0x9b, - 0xb6, 0xef, 0x71, 0xf9, 0xbb, 0xb5, 0x61, 0xf9, 0x71, 0x25, 0x21, 0xaf, - 0x57, 0x82, 0xe0, 0xa2, 0x9f, 0xf6, 0xef, 0x13, 0xb9, 0xbd, 0x5b, 0x9f, - 0xfd, 0xa3, 0x86, 0x3e, 0xaf, 0x2f, 0xab, 0x33, 0x7b, 0xd4, 0x83, 0x5e, - 0x79, 0xbd, 0xf9, 0xf7, 0xe0, 0xaf, 0xee, 0xb3, 0xb3, 0xed, 0xae, 0x6e, - 0xcb, 0x33, 0xff, 0xc4, 0x8e, 0xa4, 0xcd, 0xdd, 0x81, 0x34, 0xda, 0xa6, - 0xc7, 0x37, 0x5a, 0xed, 0xd9, 0x36, 0xa3, 0xec, 0x40, 0x71, 0x73, 0x50, - 0x1a, 0x7f, 0xca, 0xfd, 0x01, 0xbf, 0x53, 0x9d, 0xcb, 0x30, 0xe5, 0x39, - 0x07, 0xeb, 0x24, 0x4d, 0xf9, 0x88, 0x29, 0xf7, 0x54, 0x6c, 0x70, 0xb9, - 0x4a, 0x19, 0x85, 0x1f, 0x4a, 0x6c, 0xd8, 0x24, 0x76, 0x0d, 0xe3, 0x61, - 0xd4, 0xd3, 0xb3, 0x52, 0x56, 0x71, 0x2d, 0xda, 0xa0, 0x5e, 0x15, 0xd3, - 0xd2, 0xb1, 0x3e, 0x96, 0x3d, 0x2c, 0x73, 0xee, 0x71, 0x19, 0x98, 0xba, - 0x36, 0x6e, 0xd7, 0xeb, 0x1d, 0x87, 0x6f, 0xa5, 0xec, 0xac, 0xfb, 0x41, - 0x21, 0x8f, 0xbb, 0x69, 0x17, 0x72, 0xb6, 0x05, 0xdf, 0xf4, 0xcb, 0x19, - 0x79, 0x7e, 0x3b, 0x95, 0x14, 0xac, 0xd7, 0x07, 0xe1, 0x7b, 0xda, 0xcf, - 0xe1, 0x9d, 0x71, 0xae, 0x67, 0xe3, 0x12, 0x79, 0x76, 0x58, 0x7a, 0x56, - 0x88, 0x3f, 0xc8, 0xd3, 0x84, 0x74, 0xaf, 0x10, 0xfb, 0x32, 0x2e, 0x9c, - 0x9a, 0xbe, 0x22, 0x8c, 0xb7, 0xa4, 0xfc, 0x0b, 0xf8, 0xed, 0x62, 0xde, - 0x3d, 0xf0, 0x9b, 0xbb, 0xcf, 0xea, 0x76, 0xf6, 0xd6, 0x10, 0x00, 0x1f, - 0x7c, 0xee, 0x15, 0xfa, 0xd9, 0x4c, 0xe9, 0x77, 0xb3, 0x0c, 0xb2, 0xbd, - 0x35, 0x62, 0xca, 0xe8, 0x53, 0x73, 0x7c, 0x9e, 0xd9, 0xeb, 0x7b, 0xa0, - 0xf6, 0x18, 0x7d, 0x52, 0x5f, 0x5e, 0xdc, 0x60, 0x0c, 0xfc, 0x55, 0xf8, - 0x6f, 0x19, 0x89, 0xac, 0x64, 0x20, 0x87, 0x3e, 0x6c, 0x29, 0x71, 0x1c, - 0xed, 0x17, 0xf2, 0x61, 0x73, 0x36, 0x9e, 0x51, 0x31, 0x87, 0x92, 0x93, - 0x85, 0xcc, 0xd5, 0x3f, 0x63, 0x97, 0xdb, 0x6c, 0x54, 0xd9, 0xd8, 0xa8, - 0xb2, 0xb1, 0x51, 0xe5, 0x66, 0xb8, 0x3f, 0x38, 0xc6, 0x71, 0xd8, 0xd5, - 0x2e, 0x79, 0x2a, 0x4e, 0x59, 0xd1, 0xb2, 0x17, 0xb1, 0xc7, 0x94, 0xac, - 0xce, 0xd0, 0xde, 0x3e, 0xe3, 0xee, 0x83, 0xaf, 0x55, 0x52, 0x7b, 0xe3, - 0x99, 0x50, 0xce, 0x78, 0xe7, 0x33, 0x90, 0x1a, 0xb0, 0x4c, 0xd9, 0xb3, - 0x64, 0xc9, 0x3b, 0xae, 0xb0, 0xde, 0xc3, 0xe8, 0xe3, 0x49, 0xd3, 0xc7, - 0x92, 0x8c, 0x19, 0x79, 0xe7, 0xda, 0x44, 0xd5, 0x79, 0xc5, 0x43, 0xfe, - 0xef, 0xc9, 0xc0, 0x20, 0xd7, 0x93, 0xf2, 0x4f, 0x7c, 0xc1, 0xf5, 0x60, - 0x8c, 0xff, 0x6d, 0x63, 0xa9, 0xea, 0x0e, 0x5f, 0xa1, 0x42, 0x5b, 0xb2, - 0x1f, 0xf2, 0x9b, 0x81, 0xff, 0x1d, 0xc6, 0x53, 0xd5, 0xbe, 0x4a, 0xd8, - 0x36, 0xec, 0xda, 0xd8, 0xd8, 0x78, 0x51, 0x8e, 0x4b, 0x19, 0x7e, 0x2b, - 0x69, 0x58, 0x82, 0x1d, 0xdb, 0xf0, 0xff, 0x2e, 0xf8, 0x64, 0x3c, 0x55, - 0x9a, 0x97, 0xce, 0x18, 0x27, 0x7d, 0xf1, 0xb7, 0x8b, 0x73, 0x1e, 0x51, - 0xfa, 0xf1, 0x5a, 0x2c, 0x15, 0xc6, 0x38, 0xe7, 0x3a, 0x62, 0x9c, 0xfa, - 0xec, 0xac, 0x27, 0x4b, 0xbd, 0x7e, 0xca, 0xfa, 0x71, 0x26, 0x22, 0x0d, - 0x60, 0xca, 0xfb, 0x7c, 0x62, 0xa4, 0x92, 0xf5, 0x7a, 0x45, 0xd4, 0x7b, - 0xc1, 0x8f, 0xe8, 0x58, 0xbb, 0x0b, 0xdb, 0xb2, 0xed, 0x98, 0xb3, 0x22, - 0x07, 0x79, 0xb6, 0xf2, 0x77, 0x8b, 0x4a, 0x27, 0x27, 0xfa, 0x24, 0x46, - 0x3d, 0x75, 0x2f, 0xde, 0x79, 0x5e, 0x71, 0xa4, 0x23, 0x7f, 0x67, 0x80, - 0x7b, 0xac, 0x0c, 0x3c, 0xb6, 0xe4, 0x69, 0x7e, 0x39, 0xe0, 0xf1, 0x0c, - 0x30, 0xce, 0x95, 0x26, 0x71, 0x6d, 0xcc, 0xe0, 0x5a, 0xe2, 0x26, 0xac, - 0xd1, 0xf6, 0x28, 0xca, 0x88, 0x9d, 0xe2, 0xca, 0xaf, 0x53, 0x58, 0xca, - 0x2f, 0x18, 0x3b, 0x41, 0x99, 0xa2, 0x3c, 0x11, 0x93, 0x69, 0x99, 0x5a, - 0xa8, 0xb8, 0x1d, 0xf2, 0xe4, 0xfe, 0x23, 0xe5, 0xe9, 0xa6, 0x3e, 0x9e, - 0xf7, 0xbc, 0x84, 0xfd, 0x79, 0x12, 0xf6, 0x74, 0xa3, 0xb6, 0x4f, 0x76, - 0x6b, 0xa3, 0xc0, 0xc5, 0xcc, 0xe3, 0xbe, 0x4c, 0xc8, 0xfd, 0x95, 0x59, - 0x39, 0x5c, 0x8b, 0xca, 0xc5, 0x9a, 0x7d, 0x4f, 0x8f, 0x30, 0x46, 0x4d, - 0xcc, 0xf1, 0x0d, 0xa5, 0xd7, 0x7e, 0xe2, 0x5f, 0x6d, 0xbf, 0x84, 0xf6, - 0x0d, 0xb4, 0x5f, 0xa8, 0xdd, 0x28, 0x45, 0xd5, 0x7e, 0xfd, 0xba, 0x31, - 0xae, 0xd6, 0xe9, 0x33, 0xf6, 0x33, 0x3c, 0x97, 0xa4, 0x6d, 0xee, 0xc2, - 0xbc, 0xe1, 0x27, 0x65, 0x90, 0xd6, 0x79, 0x36, 0x49, 0xdb, 0xfe, 0x47, - 0xae, 0x4e, 0x13, 0x6d, 0x76, 0x21, 0xd9, 0x66, 0x17, 0xde, 0x68, 0xbb, - 0x4b, 0xa9, 0xef, 0x65, 0xbf, 0x9c, 0x01, 0xf6, 0xab, 0x0d, 0xb5, 0xdd, - 0xa9, 0x48, 0x95, 0x68, 0x93, 0x18, 0x0b, 0xdb, 0xac, 0x84, 0xba, 0x3a, - 0x37, 0xc0, 0x38, 0xfe, 0xb2, 0x4f, 0xbe, 0x4b, 0x32, 0x92, 0xa5, 0xae, - 0xf7, 0xa3, 0xbb, 0xc0, 0x68, 0x0d, 0x75, 0x4e, 0x1d, 0xc1, 0x0f, 0xb6, - 0xd0, 0xb1, 0xc4, 0xf5, 0x98, 0x57, 0xd2, 0x58, 0xd7, 0x85, 0xde, 0xb4, - 0x55, 0x9d, 0x64, 0xde, 0xbf, 0xc9, 0xbc, 0x43, 0xbf, 0x55, 0xde, 0x3b, - 0x6c, 0x67, 0xff, 0xfb, 0xcd, 0xf9, 0x0c, 0xcf, 0x0e, 0x99, 0x47, 0xcc, - 0xfb, 0x03, 0x60, 0x5e, 0xde, 0xb7, 0xe5, 0xba, 0xbc, 0x89, 0xf5, 0xbf, - 0x08, 0xdb, 0xe2, 0x41, 0xaf, 0x3b, 0xb2, 0x90, 0xb9, 0x68, 0xce, 0x2e, - 0x38, 0xb7, 0x6e, 0xd8, 0xa8, 0x1f, 0xc9, 0xe1, 0xb5, 0x14, 0xb0, 0x4a, - 0x88, 0xaf, 0xd8, 0xc7, 0xf5, 0xd8, 0xea, 0x44, 0xb5, 0xfd, 0xfc, 0x37, - 0xbc, 0x3f, 0x4a, 0xd9, 0x50, 0xe7, 0xda, 0x56, 0x81, 0xf1, 0xc0, 0xd5, - 0x1f, 0x60, 0x9e, 0xa9, 0x53, 0x22, 0x3c, 0xeb, 0x62, 0x9c, 0x17, 0x3e, - 0xc2, 0x36, 0xf3, 0xe7, 0xd0, 0xf7, 0x0f, 0x78, 0x97, 0x16, 0xfe, 0x93, - 0x6d, 0xf8, 0xf3, 0xfb, 0xc6, 0xbf, 0x8f, 0x32, 0x36, 0x0a, 0xd9, 0x2f, - 0x2b, 0xdb, 0x5d, 0x8c, 0x2f, 0x23, 0xfd, 0x1f, 0xc6, 0x56, 0x7f, 0xbd, - 0x4f, 0xdb, 0x6a, 0xde, 0x03, 0xf9, 0x02, 0xf7, 0x96, 0xa1, 0x9b, 0xf4, - 0x92, 0xee, 0x2e, 0xe9, 0x3e, 0x4d, 0x9a, 0xbf, 0x82, 0x7a, 0x94, 0x8d, - 0x83, 0xe6, 0xbe, 0x08, 0xcf, 0xc1, 0xd9, 0x27, 0x6c, 0x84, 0xc2, 0x5b, - 0x39, 0xa4, 0x6c, 0xb7, 0x86, 0x7a, 0x39, 0xcc, 0x59, 0x61, 0xb0, 0xa1, - 0x88, 0x84, 0x79, 0xf7, 0x22, 0x8f, 0x3e, 0xe5, 0x4d, 0xf0, 0x29, 0x99, - 0x97, 0xc7, 0x3b, 0xc7, 0xba, 0xd9, 0x8c, 0x63, 0x30, 0xdd, 0x35, 0x34, - 0x71, 0x2e, 0xe1, 0x5a, 0x77, 0x9b, 0x33, 0x73, 0xe6, 0xdd, 0x64, 0xf2, - 0x1c, 0x33, 0xbf, 0x61, 0x73, 0x8f, 0x3d, 0x75, 0x2a, 0x27, 0xa1, 0xec, - 0x93, 0xbe, 0x68, 0x1b, 0x16, 0xfc, 0x83, 0xc1, 0xab, 0x77, 0x1c, 0x29, - 0x6b, 0x94, 0xaf, 0x84, 0xba, 0xbf, 0xc7, 0xf3, 0xf2, 0x17, 0x14, 0xfe, - 0x0e, 0x71, 0x95, 0xd2, 0x65, 0x3c, 0x07, 0xa8, 0xd9, 0xd9, 0x9e, 0xdf, - 0xf9, 0x3e, 0x5b, 0x24, 0x1b, 0xb6, 0x03, 0x1e, 0x52, 0x6d, 0x92, 0xb2, - 0xd8, 0x7c, 0xbb, 0xbb, 0x6f, 0xc0, 0x68, 0xd7, 0xdc, 0x67, 0x49, 0x28, - 0xfd, 0xb3, 0x51, 0x8b, 0x80, 0xbf, 0x43, 0x78, 0xbe, 0x0c, 0x1e, 0x44, - 0x31, 0x4f, 0xe0, 0xf4, 0xf8, 0x4d, 0xea, 0xbe, 0x4f, 0xc4, 0xbb, 0xa4, - 0xce, 0x8d, 0x0a, 0xf5, 0x9f, 0xa9, 0xb2, 0xaf, 0xad, 0xf5, 0xf0, 0x0e, - 0x28, 0x52, 0x9e, 0x43, 0xff, 0x06, 0x32, 0xd8, 0x65, 0x64, 0x10, 0x69, - 0x9d, 0xf9, 0xb7, 0xc0, 0x87, 0x14, 0xc8, 0x4b, 0x37, 0xb0, 0xbd, 0xf2, - 0x13, 0x30, 0x9b, 0xab, 0x34, 0x74, 0x67, 0xc3, 0x3b, 0x97, 0x81, 0x1c, - 0x86, 0x6c, 0x6c, 0x4c, 0x2f, 0x4b, 0x63, 0xba, 0x1d, 0x27, 0x02, 0x07, - 0xba, 0xa5, 0xa0, 0xe1, 0x31, 0xd6, 0xd7, 0x6f, 0xee, 0xbf, 0x2d, 0x1a, - 0x6c, 0x47, 0xfe, 0xdb, 0x52, 0x98, 0x5c, 0x52, 0x32, 0xd5, 0x50, 0xeb, - 0xe0, 0x58, 0xe7, 0xd5, 0xdd, 0x59, 0x8e, 0xc1, 0xfb, 0xb3, 0x11, 0x83, - 0x71, 0xfe, 0xa9, 0x59, 0xcf, 0xef, 0xf7, 0x85, 0xdf, 0x64, 0x74, 0x65, - 0x4f, 0xf2, 0xce, 0x08, 0xf0, 0x6b, 0x6d, 0x76, 0xa1, 0x42, 0xbd, 0x16, - 0x04, 0x0d, 0x7f, 0x07, 0x3d, 0xbe, 0xa9, 0xf0, 0xd9, 0xae, 0x68, 0xfd, - 0xb9, 0xa4, 0xee, 0xa1, 0x56, 0x66, 0xf3, 0x2a, 0xa6, 0x06, 0xdc, 0xd1, - 0x3a, 0xbf, 0x78, 0xa7, 0xb3, 0x8b, 0x28, 0xfc, 0xe5, 0x5e, 0xb3, 0xee, - 0x51, 0xa7, 0x58, 0xe9, 0x73, 0x16, 0xd4, 0xb9, 0xd2, 0xe7, 0xcc, 0xf7, - 0x2b, 0xa5, 0xd9, 0x74, 0x33, 0xbb, 0x9f, 0x58, 0x9a, 0x31, 0xfd, 0x42, - 0x85, 0x67, 0x19, 0xba, 0x3c, 0x6d, 0xca, 0x47, 0x9a, 0xaa, 0x4c, 0xc5, - 0xe4, 0xe0, 0x77, 0xc1, 0xae, 0x30, 0xfe, 0x47, 0xdd, 0x82, 0xfe, 0xe3, - 0x7a, 0x0e, 0x91, 0xec, 0x32, 0x7c, 0x3b, 0xd2, 0x77, 0x6a, 0x36, 0xbf, - 0xc6, 0x7b, 0x47, 0x5f, 0x9a, 0xbd, 0x08, 0xff, 0x63, 0xcb, 0xd3, 0x77, - 0xb5, 0x37, 0x19, 0x3b, 0x62, 0x3b, 0xd5, 0xe7, 0xb2, 0x89, 0x65, 0x9e, - 0x9c, 0x1d, 0xdd, 0x8c, 0xc8, 0x49, 0xd3, 0x07, 0xdf, 0x93, 0x2d, 0xdf, - 0x44, 0xe9, 0x3b, 0x60, 0xf0, 0x27, 0x80, 0xc1, 0x63, 0xb0, 0x8b, 0xc4, - 0xf2, 0xc4, 0xb7, 0x31, 0xec, 0x15, 0x8e, 0xf3, 0xaf, 0xd5, 0x38, 0x11, - 0x8c, 0xb3, 0xb0, 0x76, 0x40, 0xdd, 0x23, 0xc9, 0x7b, 0x0e, 0xec, 0x34, - 0xec, 0xa9, 0xc7, 0x58, 0xb2, 0x8d, 0x39, 0x8f, 0x43, 0x1f, 0xf0, 0x6e, - 0xc7, 0x60, 0x78, 0xef, 0x85, 0x77, 0xad, 0x4c, 0xbb, 0x4f, 0xa3, 0x1d, - 0x31, 0x38, 0xdb, 0xca, 0x8d, 0xb6, 0x8c, 0x2a, 0xbb, 0xab, 0x75, 0x0e, - 0x69, 0xa8, 0x63, 0xae, 0xb4, 0x5d, 0xd8, 0x6b, 0x6a, 0x5e, 0x9f, 0x56, - 0xed, 0xac, 0xec, 0x53, 0xa0, 0x9d, 0xd8, 0x0a, 0x7d, 0x57, 0x75, 0x7c, - 0xb0, 0xa0, 0xe4, 0x08, 0x72, 0x32, 0x1d, 0xde, 0x17, 0xd1, 0xed, 0xc2, - 0xfa, 0x23, 0x9b, 0x9f, 0x35, 0xe3, 0xff, 0x32, 0xc8, 0x1d, 0x8d, 0xa9, - 0xfb, 0x39, 0x2f, 0x5d, 0x73, 0x87, 0x8a, 0x6d, 0xc2, 0x3a, 0x11, 0x23, - 0x5b, 0x27, 0xda, 0x68, 0xfe, 0x9c, 0x59, 0x73, 0xb6, 0x63, 0xfc, 0x94, - 0x79, 0x25, 0xe6, 0x39, 0x8b, 0x19, 0xf6, 0xd1, 0x7e, 0xee, 0x32, 0x09, - 0x5b, 0xae, 0x6d, 0x46, 0x69, 0xdb, 0x83, 0x4d, 0xec, 0xc6, 0xda, 0xd1, - 0x06, 0x8c, 0x1a, 0xdc, 0xfe, 0x8e, 0x71, 0x49, 0xa7, 0x98, 0x81, 0x1f, - 0xdf, 0x6a, 0xcf, 0x75, 0x2c, 0xcd, 0x5e, 0xac, 0x78, 0x72, 0xa2, 0xaa, - 0xef, 0x37, 0x69, 0x3e, 0x50, 0x37, 0x73, 0x6d, 0x93, 0xb2, 0xe0, 0x31, - 0xfe, 0x91, 0x94, 0x57, 0xbc, 0x76, 0x3d, 0x8d, 0xfa, 0xdb, 0x93, 0xe6, - 0x8e, 0xf3, 0xa7, 0x31, 0x7f, 0xe2, 0x31, 0x2d, 0x4b, 0x07, 0x61, 0x77, - 0xfe, 0x83, 0x43, 0x9d, 0xdd, 0x2d, 0x97, 0x9d, 0xf6, 0xf9, 0x85, 0x71, - 0x6e, 0x2d, 0x97, 0x0e, 0x64, 0x64, 0xb9, 0xc5, 0x77, 0xf8, 0xbf, 0xef, - 0x1b, 0x83, 0x8e, 0xb7, 0x64, 0x66, 0xd2, 0x4b, 0x2c, 0x31, 0xee, 0xef, - 0x4e, 0xb8, 0xae, 0xba, 0xa7, 0x97, 0x04, 0xbd, 0x7c, 0x1e, 0x05, 0x06, - 0xe1, 0x9d, 0x3a, 0xbc, 0xf3, 0x4e, 0x5b, 0xdc, 0x03, 0xbd, 0xae, 0x8a, - 0xe7, 0x6b, 0x1d, 0xfd, 0xf5, 0xfd, 0x8c, 0xa7, 0x0c, 0x78, 0xe1, 0xda, - 0xab, 0x7b, 0xcd, 0xe8, 0x3b, 0x62, 0xca, 0x07, 0x5b, 0xfc, 0x97, 0x21, - 0xa6, 0xad, 0xbb, 0x52, 0x26, 0x6e, 0xc1, 0xfa, 0x9f, 0x51, 0xb4, 0x2c, - 0x78, 0x41, 0xb0, 0xa8, 0xe6, 0xf3, 0x34, 0x64, 0x21, 0x22, 0xe5, 0x96, - 0xfc, 0x3e, 0x0d, 0xf9, 0xdd, 0xc7, 0x6b, 0x35, 0x7b, 0xc8, 0x5a, 0x28, - 0x63, 0x94, 0x2f, 0xca, 0x56, 0xa2, 0x9f, 0x7b, 0xae, 0xd4, 0x5a, 0x77, - 0x47, 0xd9, 0xd8, 0xa4, 0x1d, 0xae, 0x3b, 0x9f, 0xf7, 0xba, 0x93, 0x14, - 0xee, 0x8f, 0xcc, 0x3f, 0x62, 0x6d, 0x7d, 0xb3, 0xb6, 0x99, 0xb6, 0x6f, - 0x0b, 0xc2, 0xfe, 0x18, 0x3b, 0x54, 0xf6, 0x38, 0x21, 0xd0, 0xd9, 0x25, - 0x7d, 0xbf, 0x57, 0xe1, 0xd6, 0x9c, 0x9b, 0x4f, 0x32, 0x4e, 0x7c, 0x4c, - 0xee, 0x02, 0xcd, 0xb9, 0xf1, 0x2e, 0xd1, 0x6d, 0xe7, 0xc1, 0xef, 0x1d, - 0x17, 0xbe, 0x16, 0xcf, 0x6c, 0x2b, 0x8e, 0x6c, 0xa9, 0xb3, 0x47, 0xec, - 0xd1, 0x98, 0x23, 0xcb, 0x5e, 0xd8, 0x6f, 0x54, 0xea, 0xa8, 0xb3, 0x81, - 0xb2, 0x93, 0x2d, 0xda, 0x88, 0xd3, 0xe1, 0xa7, 0x78, 0xbf, 0x0c, 0x8a, - 0xf1, 0x6b, 0xea, 0x9a, 0x7b, 0xfa, 0x8c, 0x77, 0xf4, 0x29, 0x1f, 0xaa, - 0x00, 0x9f, 0xab, 0x00, 0x7f, 0xab, 0xa0, 0xf4, 0x02, 0xe3, 0x1f, 0x8c, - 0x4f, 0x95, 0x80, 0xed, 0x4b, 0x41, 0x8f, 0x77, 0x5c, 0xc5, 0xdd, 0x5e, - 0xd8, 0xa6, 0x0f, 0xe0, 0x25, 0xef, 0x97, 0xd0, 0x86, 0xf4, 0x97, 0xa2, - 0xd9, 0xf6, 0x18, 0x56, 0x52, 0xc5, 0x80, 0x7a, 0x81, 0x43, 0x1f, 0x87, - 0xae, 0x7e, 0xd1, 0x67, 0xec, 0xea, 0x56, 0xf2, 0xfb, 0x2b, 0x9c, 0xa4, - 0x3d, 0x36, 0x29, 0xde, 0x59, 0x6f, 0xfc, 0x7e, 0x21, 0xb6, 0x4f, 0x25, - 0x8f, 0x90, 0x6f, 0xad, 0xef, 0x04, 0x42, 0xbb, 0x3a, 0x29, 0xa3, 0x67, - 0x7f, 0xa4, 0xce, 0x04, 0x3e, 0xe2, 0x77, 0xca, 0x86, 0x8a, 0x7d, 0x4d, - 0x0e, 0xc8, 0x28, 0xfc, 0x4a, 0x81, 0x75, 0xe2, 0x77, 0x03, 0x96, 0x2c, - 0x67, 0xd4, 0xbb, 0xcc, 0x35, 0x93, 0xe6, 0x9e, 0x25, 0x63, 0x5b, 0x8c, - 0x8d, 0x71, 0x4d, 0xfb, 0xd4, 0xdd, 0x4a, 0xde, 0xff, 0x9b, 0x69, 0x6a, - 0x9b, 0x9b, 0x53, 0x77, 0x1c, 0x19, 0x2b, 0x63, 0xcc, 0x4b, 0xdf, 0x9f, - 0x3b, 0xdc, 0xdc, 0x2b, 0x2e, 0x16, 0xde, 0xf7, 0xd3, 0x76, 0x6b, 0x37, - 0x73, 0x00, 0xb6, 0xce, 0x55, 0xf1, 0x89, 0xa2, 0x3b, 0x20, 0xc7, 0xc6, - 0x7b, 0xc0, 0xf3, 0x41, 0x75, 0x17, 0xcd, 0xf6, 0xde, 0x2f, 0x5d, 0xb4, - 0x9b, 0xae, 0xba, 0x23, 0x6d, 0xf8, 0x7c, 0x07, 0xf2, 0x7e, 0x05, 0xde, - 0x33, 0xef, 0x63, 0xfd, 0xda, 0x0e, 0x7d, 0x0a, 0x78, 0x9b, 0xf7, 0xca, - 0xeb, 0x07, 0xf2, 0x6a, 0x3d, 0xe8, 0xf7, 0x86, 0xba, 0x29, 0xbc, 0xff, - 0x18, 0x85, 0x6d, 0x72, 0xcd, 0x79, 0x71, 0x49, 0x96, 0x88, 0x01, 0x37, - 0xa9, 0x7f, 0x2c, 0x35, 0xd6, 0xe5, 0xc8, 0xbb, 0xa4, 0x54, 0xdf, 0xeb, - 0xdc, 0x3b, 0x08, 0xbe, 0xe1, 0xab, 0x3b, 0x97, 0xa7, 0x4a, 0x66, 0x8d, - 0xf5, 0x37, 0x85, 0x4e, 0xdb, 0x7d, 0xee, 0xa8, 0xd2, 0xbb, 0xb9, 0x41, - 0x60, 0x15, 0xef, 0xa3, 0xfd, 0x57, 0xef, 0xf0, 0xfd, 0xc6, 0xe0, 0x58, - 0xde, 0xdf, 0xd3, 0x77, 0xbb, 0xed, 0x46, 0x28, 0x27, 0xf4, 0x9b, 0x89, - 0x9f, 0x0f, 0xc2, 0xa7, 0x86, 0xde, 0x1c, 0xe2, 0xfb, 0x5f, 0x9a, 0xb6, - 0x7c, 0x0e, 0xe4, 0xbe, 0xa9, 0xce, 0x33, 0xed, 0x69, 0x7d, 0x0f, 0x3c, - 0x16, 0xde, 0x73, 0x1f, 0xee, 0xb8, 0x9b, 0xa4, 0xe8, 0x84, 0x3c, 0x85, - 0x34, 0xe8, 0xb1, 0x0e, 0x83, 0xde, 0x46, 0x2d, 0x21, 0x83, 0x1e, 0x7d, - 0xc5, 0x88, 0x4c, 0x0d, 0xa6, 0x5a, 0x77, 0xcd, 0x1b, 0x75, 0xd8, 0xfc, - 0x5a, 0x48, 0xa7, 0xbe, 0x6b, 0xd8, 0xa8, 0xb3, 0x3c, 0x89, 0xb1, 0x7a, - 0x64, 0x6a, 0x88, 0x7c, 0xee, 0xa4, 0x23, 0x61, 0xee, 0x23, 0x77, 0xe6, - 0xdf, 0xdd, 0x46, 0xdf, 0xf5, 0xdf, 0x62, 0xea, 0xfb, 0x8f, 0xbc, 0xcb, - 0x4e, 0x1a, 0x79, 0xce, 0x82, 0x39, 0xfa, 0xa1, 0x6f, 0x11, 0xf2, 0x65, - 0x50, 0xdd, 0x97, 0x2f, 0xd4, 0xbb, 0x94, 0x5c, 0x2c, 0x64, 0x38, 0x17, - 0xe2, 0xa0, 0xf0, 0x4e, 0xfc, 0x3f, 0x39, 0xa0, 0xd7, 0xfc, 0x63, 0xe1, - 0x1c, 0x4d, 0x3e, 0xdb, 0xdf, 0x82, 0x36, 0x5f, 0x0d, 0xd0, 0x3f, 0x83, - 0x5b, 0xd8, 0xf3, 0x21, 0x36, 0xbf, 0x45, 0xb7, 0x8f, 0x85, 0xdf, 0xe3, - 0xb5, 0x7f, 0x1f, 0xc0, 0x3d, 0x15, 0xf2, 0x8d, 0x7d, 0x70, 0x7c, 0xd2, - 0xc1, 0x71, 0x7b, 0xdb, 0xc6, 0x55, 0x3f, 0xff, 0x5a, 0xbd, 0x76, 0x47, - 0xdb, 0x7c, 0x29, 0x5f, 0xfd, 0xb2, 0x54, 0x8b, 0x49, 0xb9, 0xa6, 0xfc, - 0x99, 0x71, 0x20, 0x36, 0xe0, 0x39, 0xee, 0x45, 0x75, 0xff, 0xd6, 0xdc, - 0x2d, 0x0c, 0xf7, 0x64, 0x3f, 0xea, 0xd1, 0x6e, 0x20, 0xad, 0x6b, 0x9d, - 0x54, 0x97, 0xeb, 0xbf, 0x77, 0x58, 0x6c, 0x7d, 0xef, 0xa0, 0xfd, 0xe3, - 0x62, 0xeb, 0x6e, 0x46, 0xb4, 0x34, 0x98, 0x6d, 0xbf, 0xef, 0x53, 0x92, - 0x87, 0xee, 0xe4, 0x77, 0x06, 0x31, 0x23, 0x97, 0xef, 0x37, 0xe3, 0x60, - 0xbc, 0xd5, 0x69, 0x19, 0x59, 0xfd, 0xbc, 0x14, 0xe7, 0xd4, 0x9d, 0xed, - 0xb6, 0x3b, 0xfb, 0xa3, 0xe6, 0x3b, 0xa2, 0x9c, 0xc5, 0x3b, 0x20, 0x85, - 0x55, 0xac, 0xd1, 0x9d, 0xa9, 0xf1, 0xa4, 0xcd, 0x6f, 0x59, 0x1f, 0x95, - 0x91, 0xf5, 0x69, 0x49, 0xaf, 0x12, 0x27, 0xf0, 0x74, 0x3c, 0xa5, 0xe2, - 0x8d, 0xe9, 0x73, 0xba, 0x3f, 0x6f, 0x95, 0xe5, 0x69, 0x60, 0x54, 0x96, - 0x17, 0x12, 0x11, 0x75, 0x82, 0x7e, 0x1b, 0x64, 0xa8, 0xdb, 0x60, 0x00, - 0x47, 0xf2, 0xab, 0x6c, 0x4f, 0xbc, 0xf1, 0x1c, 0xd6, 0xac, 0x90, 0xb4, - 0x85, 0x6d, 0x54, 0x7f, 0x78, 0x8e, 0x2a, 0xec, 0x5c, 0xc8, 0x90, 0xd7, - 0x93, 0xb2, 0xd9, 0xf4, 0xb0, 0x0f, 0xf4, 0x3d, 0xff, 0x62, 0x3d, 0xbc, - 0x77, 0xf9, 0x90, 0xf9, 0x6e, 0x40, 0xd3, 0x38, 0x53, 0xe9, 0x94, 0xb7, - 0xc7, 0xcc, 0x7d, 0x7f, 0xce, 0xdb, 0x6d, 0xd7, 0x79, 0xa6, 0xfe, 0x6b, - 0x07, 0x78, 0x96, 0x4e, 0x9f, 0x68, 0xa4, 0xdd, 0xff, 0x88, 0xc7, 0xcd, - 0x77, 0x16, 0x61, 0xbd, 0xff, 0x7d, 0x40, 0xdf, 0xd5, 0x27, 0x9f, 0xb2, - 0x86, 0xe6, 0x29, 0xe5, 0xdf, 0xbc, 0x54, 0x3d, 0x88, 0xb6, 0x5c, 0x27, - 0xa4, 0x0d, 0x3e, 0x53, 0x6f, 0x1e, 0x31, 0x67, 0x4e, 0x43, 0x6a, 0x2c, - 0x37, 0xdb, 0xfe, 0x0d, 0x48, 0x6f, 0xdb, 0xf8, 0x9d, 0xf4, 0xf2, 0x9b, - 0x90, 0x8b, 0x46, 0x5e, 0x58, 0xce, 0xf7, 0xce, 0x3a, 0x87, 0x0e, 0x84, - 0xe5, 0x4e, 0xeb, 0xbb, 0x01, 0xf2, 0x92, 0xe7, 0x65, 0x48, 0x79, 0x4e, - 0xa9, 0x9e, 0x91, 0x9a, 0xef, 0x21, 0x9c, 0x55, 0xfe, 0x3a, 0xfb, 0x71, - 0xd0, 0x77, 0xb8, 0x4f, 0xf7, 0xba, 0x17, 0x43, 0xfd, 0x7b, 0xca, 0xda, - 0xad, 0x44, 0xe9, 0xef, 0xc8, 0xb1, 0x4c, 0x3f, 0xfc, 0x7d, 0x9b, 0xdf, - 0x78, 0x32, 0xb6, 0xc9, 0x33, 0x3d, 0x59, 0x54, 0x7a, 0x6d, 0x4c, 0xf4, - 0xf7, 0xad, 0xbd, 0x32, 0xe3, 0x52, 0x9e, 0xc7, 0x64, 0xb3, 0x3e, 0xd7, - 0x76, 0x57, 0xb6, 0xdb, 0xc8, 0xd9, 0x2b, 0x5d, 0x12, 0x2b, 0x59, 0x17, - 0x2a, 0xe1, 0x3e, 0x1e, 0x93, 0x99, 0x7a, 0xfb, 0x7d, 0x68, 0xde, 0xb3, - 0xa1, 0xdc, 0x0e, 0xb7, 0xed, 0x3d, 0xde, 0x4d, 0x03, 0x96, 0x8a, 0xd3, - 0x1f, 0x65, 0xbd, 0xfd, 0xc6, 0xc6, 0x7e, 0xd4, 0x95, 0x98, 0x6b, 0x89, - 0x47, 0xda, 0xfa, 0x4d, 0x5c, 0x3e, 0x2d, 0xf7, 0xc5, 0x4b, 0xf0, 0xc7, - 0xc6, 0xcc, 0xb8, 0xef, 0xc1, 0x3b, 0xeb, 0x1e, 0x30, 0xe5, 0xb7, 0x98, - 0xf7, 0x98, 0x79, 0x8f, 0xe0, 0x9d, 0x77, 0xac, 0xd9, 0x27, 0xd3, 0xe7, - 0x55, 0xdc, 0x65, 0x20, 0x9b, 0x95, 0xae, 0x73, 0x02, 0xdb, 0x14, 0x93, - 0xc7, 0xea, 0x8a, 0xbf, 0x96, 0xb7, 0x4a, 0x10, 0x70, 0x83, 0x79, 0xbe, - 0x7e, 0x0f, 0x3e, 0x75, 0xcd, 0x37, 0x47, 0x7f, 0xe8, 0x6a, 0x59, 0x69, - 0xa7, 0xf7, 0x6e, 0xd0, 0xfa, 0x76, 0xf7, 0x8f, 0x68, 0x97, 0xb4, 0x9f, - 0x38, 0x53, 0xa1, 0x0e, 0xcc, 0xca, 0xb1, 0x0a, 0x68, 0xad, 0x0d, 0xbb, - 0xfa, 0x9e, 0x08, 0xf9, 0xa5, 0xef, 0x0d, 0xe6, 0x6b, 0x63, 0xe6, 0x7c, - 0x97, 0x6d, 0x79, 0x8f, 0x91, 0x7c, 0x8b, 0x76, 0xc4, 0x11, 0x68, 0x7f, - 0x68, 0x5b, 0xf8, 0x2d, 0x8e, 0x8f, 0xba, 0xcb, 0xd4, 0x35, 0xb0, 0x4d, - 0x21, 0x7e, 0xf8, 0x82, 0x89, 0x47, 0x85, 0x76, 0x9e, 0xdf, 0x47, 0x8b, - 0xfc, 0x67, 0x60, 0x57, 0xfb, 0x74, 0xaf, 0x44, 0x4e, 0x87, 0x77, 0x90, - 0xb8, 0xc6, 0xa3, 0xea, 0x8e, 0xd9, 0x6e, 0xf3, 0xc3, 0x28, 0x0b, 0xcf, - 0x8a, 0xbb, 0xcc, 0x59, 0x71, 0x28, 0xe7, 0x70, 0x34, 0x62, 0x51, 0xc8, - 0x38, 0xdb, 0xe7, 0x14, 0x5f, 0x73, 0x71, 0xe2, 0xac, 0x83, 0x26, 0x6e, - 0xc0, 0xb2, 0x92, 0x0c, 0xdc, 0xf9, 0x61, 0xee, 0x8d, 0x77, 0x47, 0x24, - 0xfc, 0x8e, 0x40, 0x8d, 0x13, 0xd7, 0xb8, 0x91, 0xdf, 0x57, 0xfb, 0xd8, - 0x57, 0xfb, 0x76, 0xc2, 0xef, 0x08, 0xce, 0x37, 0x33, 0xea, 0x7b, 0x05, - 0x9e, 0x25, 0xec, 0xf2, 0x1e, 0xd6, 0x2a, 0xbf, 0xa5, 0xa6, 0x6c, 0x9b, - 0xef, 0xa8, 0xfb, 0x87, 0xe5, 0xe5, 0xa6, 0xfe, 0xf6, 0x42, 0xdf, 0xed, - 0x25, 0x3e, 0x4b, 0xa2, 0x9c, 0x77, 0xc7, 0xf8, 0xad, 0x03, 0xff, 0x9f, - 0xc2, 0x23, 0x48, 0x3f, 0x25, 0x1b, 0x15, 0x1d, 0xcf, 0x2c, 0xc3, 0x7f, - 0x18, 0x59, 0x75, 0xd5, 0x99, 0xcb, 0xc8, 0xea, 0x0c, 0xc6, 0x0b, 0xbf, - 0x7d, 0x8e, 0x23, 0x8f, 0xf4, 0x95, 0xcc, 0x1e, 0x0d, 0xef, 0x4b, 0xfc, - 0x57, 0x97, 0x36, 0xa1, 0xd4, 0xec, 0x43, 0x5d, 0xcb, 0x60, 0x10, 0xe2, - 0xbb, 0xf0, 0x1b, 0xaf, 0x18, 0x6d, 0x54, 0x40, 0x9d, 0x94, 0xc6, 0x38, - 0x8d, 0x0a, 0xef, 0x5d, 0xa8, 0xff, 0xc3, 0xe0, 0x16, 0xe9, 0xa3, 0x29, - 0x1d, 0x9f, 0x1a, 0x9f, 0x97, 0x82, 0xdb, 0x25, 0x09, 0xf5, 0x7f, 0x1d, - 0x6c, 0xcc, 0x3d, 0xbf, 0xd6, 0xb7, 0x13, 0xc9, 0x72, 0x6e, 0x1c, 0x9b, - 0xbe, 0x87, 0x9e, 0x0f, 0xbf, 0x19, 0x71, 0xb2, 0xbc, 0xdb, 0xcd, 0xef, - 0x9e, 0x98, 0x5f, 0x02, 0xce, 0x0a, 0xbf, 0x73, 0xd1, 0xdf, 0x31, 0xcc, - 0x37, 0x8f, 0xc8, 0x89, 0xca, 0x7e, 0x7e, 0x6f, 0xe1, 0xef, 0x82, 0x6f, - 0xc7, 0x9a, 0x7d, 0xea, 0x5b, 0x8a, 0xf9, 0x26, 0xef, 0x8f, 0x85, 0xb6, - 0x87, 0x6b, 0x15, 0x57, 0x67, 0x18, 0x2f, 0xa8, 0x6f, 0x2d, 0xf4, 0x77, - 0x16, 0x8f, 0xa9, 0xef, 0x16, 0xf4, 0x7e, 0xbf, 0x1e, 0x7b, 0x53, 0x06, - 0x3f, 0x07, 0x7f, 0x50, 0xeb, 0xdd, 0xfb, 0x32, 0xbc, 0x23, 0x19, 0x04, - 0xc7, 0x7c, 0xc6, 0x45, 0x73, 0xd3, 0x1b, 0x98, 0xe3, 0x85, 0x3a, 0x78, - 0x78, 0x94, 0x79, 0xbc, 0x43, 0xd5, 0x23, 0xf9, 0x49, 0xf5, 0x1d, 0xba, - 0xb5, 0xe1, 0xed, 0x97, 0xf3, 0x35, 0xee, 0x05, 0x07, 0xf3, 0x4e, 0xb9, - 0x0d, 0xb9, 0x61, 0x80, 0x67, 0x60, 0x87, 0x55, 0xfb, 0x70, 0xbf, 0xeb, - 0x58, 0xc1, 0xe1, 0x4d, 0xad, 0x4f, 0x78, 0xbf, 0xae, 0xeb, 0xac, 0x58, - 0x1f, 0xcf, 0x0c, 0xc3, 0xdf, 0xe6, 0x58, 0x69, 0xb4, 0x83, 0xec, 0x24, - 0xb8, 0xd7, 0x7f, 0x15, 0x34, 0x40, 0xef, 0x95, 0x26, 0x31, 0x3a, 0x70, - 0xd3, 0x1c, 0xdb, 0x64, 0xc5, 0x5e, 0x61, 0x9d, 0x41, 0xc8, 0x5f, 0x17, - 0xe6, 0xe3, 0x00, 0xff, 0x1f, 0x90, 0x86, 0xcb, 0x32, 0x3e, 0x27, 0x4c, - 0x6c, 0x42, 0x7d, 0x23, 0x0c, 0xfe, 0x25, 0x95, 0x4e, 0xca, 0xb9, 0x7a, - 0x7c, 0xde, 0xe1, 0x5c, 0xa8, 0xcd, 0x62, 0x0f, 0x39, 0x06, 0x8f, 0x39, - 0xe8, 0xe3, 0xd7, 0xe6, 0xbb, 0x8c, 0x92, 0x14, 0x32, 0x1a, 0x7f, 0x68, - 0x1b, 0xc3, 0xf3, 0x12, 0x07, 0xf8, 0x3f, 0xdc, 0x97, 0x8f, 0x1d, 0xb8, - 0xf6, 0xfb, 0x0d, 0x62, 0x97, 0x74, 0xe2, 0x0c, 0xcf, 0xb9, 0xb6, 0x1f, - 0x94, 0x79, 0xd0, 0x7c, 0xca, 0xcc, 0xf3, 0xfe, 0x8c, 0x27, 0x97, 0xeb, - 0x68, 0x93, 0x39, 0x88, 0x94, 0x77, 0xfd, 0x48, 0xf3, 0x84, 0xb9, 0xc7, - 0x98, 0xc5, 0x5c, 0x1f, 0x95, 0xd7, 0x80, 0xa9, 0x5f, 0xaf, 0xa4, 0xfd, - 0xc3, 0xea, 0x8e, 0x4e, 0x2a, 0x71, 0x5e, 0x26, 0x92, 0xf4, 0xfb, 0x4a, - 0x6e, 0x2a, 0x71, 0x59, 0x78, 0xd7, 0xe8, 0xb1, 0x01, 0xfe, 0x4f, 0x87, - 0x06, 0xec, 0xa1, 0xbe, 0x73, 0x94, 0x62, 0x9c, 0x04, 0xef, 0xc3, 0xe6, - 0xbb, 0x22, 0x8e, 0xc3, 0xb2, 0x61, 0x79, 0xad, 0xd2, 0xb2, 0xbf, 0x1c, - 0xc7, 0x7c, 0x4b, 0xce, 0xb1, 0xfe, 0xed, 0x00, 0xf5, 0x10, 0xc7, 0xd3, - 0x7d, 0x84, 0x75, 0xc8, 0x57, 0xbd, 0xc6, 0xf9, 0x8c, 0xfa, 0xae, 0x35, - 0x29, 0x96, 0x25, 0xdd, 0x1e, 0xe7, 0x7e, 0xd3, 0x80, 0xc6, 0x40, 0x6c, - 0x97, 0x76, 0xef, 0x53, 0xfd, 0xf1, 0xac, 0x8c, 0xe7, 0x49, 0x61, 0x3f, - 0xbc, 0x33, 0x84, 0x75, 0x8f, 0x73, 0xbd, 0xdb, 0x69, 0xd0, 0xf6, 0xff, - 0x35, 0x15, 0xa3, 0x9e, 0x46, 0x7d, 0xda, 0x68, 0xc8, 0x4b, 0x3d, 0xd1, - 0xfa, 0x36, 0x42, 0xf3, 0x92, 0xcf, 0x8f, 0xb5, 0xbe, 0x4f, 0xb0, 0x6f, - 0x77, 0x4d, 0x79, 0x88, 0x45, 0x87, 0xb1, 0x5f, 0x1f, 0x95, 0xc6, 0x5a, - 0x3a, 0xf1, 0x98, 0x84, 0xfd, 0x06, 0x87, 0x78, 0x8e, 0x30, 0x93, 0x99, - 0x70, 0x97, 0x14, 0x3d, 0xa9, 0x04, 0xef, 0xdd, 0x9e, 0xc7, 0x78, 0x8d, - 0x66, 0x67, 0xbc, 0x21, 0x95, 0xdb, 0x91, 0xb4, 0xaf, 0xd7, 0x66, 0x4c, - 0x76, 0xb0, 0x36, 0x5f, 0x32, 0x6b, 0xf3, 0x41, 0xf4, 0xed, 0xad, 0x4c, - 0x4a, 0x7a, 0x25, 0x9d, 0x3c, 0x25, 0x3c, 0x9b, 0x3b, 0xc0, 0xb8, 0x95, - 0x75, 0x7f, 0x26, 0x89, 0xf9, 0xa6, 0x30, 0x5f, 0xa4, 0x4d, 0x3e, 0x4f, - 0xc0, 0x1f, 0xdf, 0xc7, 0xbd, 0x7d, 0x88, 0x3a, 0x93, 0xbc, 0x98, 0x51, - 0x65, 0x8f, 0x9a, 0xbb, 0x94, 0xdf, 0xe3, 0xfa, 0xa8, 0xb8, 0xdf, 0xe5, - 0x26, 0xcf, 0xeb, 0x34, 0x7d, 0x05, 0xd0, 0xb7, 0xa8, 0xe9, 0x4b, 0xce, - 0xb7, 0xf0, 0x6a, 0x2a, 0x71, 0x42, 0x88, 0x97, 0x88, 0x5f, 0x88, 0xe5, - 0x6f, 0x19, 0xd4, 0xdf, 0x7e, 0xc0, 0x77, 0xbd, 0x3d, 0xd7, 0x9a, 0x7b, - 0x37, 0xea, 0x5e, 0x80, 0xee, 0xa7, 0xbc, 0x1c, 0x91, 0x0f, 0x48, 0xee, - 0x91, 0x54, 0x32, 0x67, 0x79, 0x06, 0x03, 0x22, 0xad, 0xf3, 0x99, 0x3a, - 0xd7, 0x33, 0xd8, 0x82, 0x6b, 0x93, 0xc1, 0x58, 0xfa, 0x3b, 0x92, 0x5d, - 0xcc, 0x2d, 0xaf, 0x64, 0xed, 0xf7, 0xb1, 0x87, 0xf4, 0xff, 0xb3, 0x38, - 0x0f, 0x3e, 0x96, 0xc1, 0xc7, 0xc7, 0xaf, 0xc3, 0x60, 0x5d, 0x2d, 0x0c, - 0xb6, 0xab, 0xc6, 0xb3, 0x40, 0x53, 0xc1, 0x25, 0xfe, 0x2a, 0xb7, 0x64, - 0x85, 0x34, 0x4d, 0xf2, 0x7f, 0xd2, 0xc8, 0xcb, 0x19, 0xae, 0x07, 0x30, - 0x18, 0xfa, 0xdb, 0xb8, 0x2a, 0x4b, 0x98, 0xbf, 0x92, 0x5f, 0xc8, 0x6e, - 0xca, 0x75, 0x2c, 0xae, 0x05, 0xfb, 0x13, 0xeb, 0x22, 0x68, 0xd9, 0x55, - 0x72, 0xa0, 0x65, 0x60, 0xb7, 0x1e, 0x7b, 0x07, 0x19, 0xe0, 0x3c, 0x29, - 0x7f, 0xa1, 0xec, 0xb5, 0xbe, 0x39, 0x87, 0x4f, 0x5b, 0x92, 0xdb, 0xee, - 0xc8, 0x4a, 0x7e, 0x85, 0x67, 0x4b, 0x62, 0x4d, 0xdc, 0x41, 0x99, 0x24, - 0x4e, 0x00, 0x86, 0x4c, 0x90, 0xc7, 0x1a, 0x0f, 0xce, 0x3f, 0xb7, 0x1f, - 0xbf, 0x73, 0x03, 0xbc, 0x5b, 0x92, 0xdf, 0xa2, 0xbe, 0x12, 0xeb, 0xd6, - 0x3b, 0xb4, 0x4f, 0x78, 0x25, 0x0e, 0x9e, 0xa3, 0x7c, 0xe4, 0xcb, 0xdd, - 0xd0, 0x57, 0x8e, 0x99, 0x37, 0xdf, 0xc9, 0x57, 0xa4, 0xcf, 0x71, 0x5c, - 0xed, 0x5f, 0xe8, 0x38, 0x20, 0xf7, 0x45, 0x49, 0x16, 0xa1, 0x0f, 0x16, - 0x32, 0x31, 0x39, 0x5c, 0x8b, 0xcb, 0x91, 0xca, 0xb4, 0x7c, 0xb1, 0xd2, - 0xa7, 0x70, 0xc3, 0x9f, 0xfb, 0xe9, 0xc4, 0xb8, 0x15, 0xc8, 0xfd, 0xc0, - 0x3f, 0xf3, 0xc3, 0xdd, 0xf2, 0xfa, 0xa4, 0xa5, 0xf4, 0xde, 0x15, 0x7e, - 0x18, 0xed, 0xf2, 0x0e, 0x27, 0xe7, 0x03, 0xbd, 0x6f, 0xc1, 0x17, 0xb0, - 0x78, 0x6f, 0xaf, 0x4f, 0x1e, 0xf0, 0x91, 0xde, 0xe8, 0xab, 0xef, 0x62, - 0xcd, 0x77, 0x5c, 0x46, 0x8f, 0x9c, 0x33, 0x63, 0x1f, 0x31, 0x69, 0x6a, - 0xb0, 0x8d, 0x16, 0x6b, 0x31, 0x13, 0x51, 0xf3, 0x2b, 0xd7, 0xa9, 0xdf, - 0xd8, 0x06, 0xfa, 0x04, 0x7b, 0xb7, 0x0b, 0x7c, 0xd9, 0x80, 0x7e, 0x29, - 0xd6, 0xc4, 0xda, 0xca, 0x00, 0x51, 0x7b, 0x1a, 0x7f, 0x16, 0x21, 0x5f, - 0x0b, 0x35, 0xea, 0xbf, 0x23, 0x90, 0x05, 0xda, 0x6f, 0x87, 0xdf, 0xdc, - 0x00, 0x43, 0x98, 0x3b, 0x1f, 0x31, 0xc6, 0x40, 0xda, 0x75, 0x58, 0xf8, - 0x3f, 0x67, 0x3e, 0x3e, 0x28, 0xfd, 0x25, 0xac, 0x4b, 0x88, 0xb9, 0xc1, - 0x53, 0x8c, 0x99, 0x57, 0xeb, 0x14, 0xae, 0x09, 0x75, 0x4f, 0x88, 0x37, - 0xda, 0xfd, 0x23, 0xee, 0x59, 0xda, 0x0b, 0x29, 0x45, 0x81, 0x69, 0x7b, - 0x57, 0x60, 0xbb, 0x6b, 0x59, 0xc8, 0x0a, 0xef, 0xe1, 0x4f, 0x4b, 0x19, - 0xd8, 0xed, 0xe3, 0xfe, 0xe7, 0xc4, 0x7e, 0xf6, 0xa0, 0x6c, 0xd4, 0x7a, - 0xc1, 0x0f, 0xda, 0x85, 0x2e, 0xe5, 0x53, 0x5f, 0x39, 0x4a, 0x7b, 0x47, - 0x5b, 0xa2, 0xd7, 0x62, 0xb7, 0x0e, 0x27, 0x38, 0xa6, 0xf3, 0x76, 0xea, - 0xa1, 0x2d, 0xe4, 0xf7, 0x34, 0x5d, 0xc6, 0x2e, 0xc7, 0xa0, 0xbb, 0xd7, - 0xa5, 0xa1, 0xfc, 0x73, 0xce, 0x9f, 0x36, 0xa8, 0x8b, 0xf7, 0xc7, 0xac, - 0x86, 0xc7, 0xb9, 0xb7, 0xdb, 0x20, 0x8d, 0x3b, 0xdc, 0x3b, 0x39, 0x1e, - 0xef, 0x26, 0x70, 0x8e, 0x71, 0xe9, 0x3a, 0xf3, 0xa8, 0xd8, 0xf0, 0x5b, - 0x22, 0xab, 0xc4, 0x7a, 0xd7, 0xfa, 0x2e, 0x91, 0x73, 0x51, 0xf3, 0xfd, - 0xf0, 0xa8, 0xc6, 0x32, 0x19, 0xa4, 0x8d, 0xf0, 0x9b, 0x62, 0xfe, 0xda, - 0xed, 0x66, 0xe8, 0x5b, 0xec, 0x69, 0x4b, 0xf1, 0xf7, 0x7f, 0x00, 0xb6, - 0x9d, 0x3c, 0x32, 0x44, 0x4b, 0x00, 0x00, 0x00 }; + 0xcd, 0x7c, 0x7f, 0x6c, 0x5c, 0xd7, 0x75, 0xe6, 0x79, 0x6f, 0xde, 0x90, + 0x43, 0x8a, 0xa2, 0x1e, 0x99, 0x31, 0x33, 0x8e, 0xd8, 0x7a, 0x86, 0xf3, + 0x48, 0xd1, 0x21, 0xe3, 0x3e, 0x33, 0x63, 0x99, 0x76, 0xa6, 0xd6, 0x64, + 0x66, 0x28, 0x2b, 0x0e, 0x69, 0xd0, 0x8e, 0x82, 0x4d, 0x01, 0x03, 0xe5, + 0x0e, 0xa9, 0x54, 0xd9, 0xf5, 0x22, 0xda, 0x34, 0x45, 0x8a, 0xa2, 0x88, + 0x26, 0x24, 0xe5, 0x2a, 0xcd, 0x88, 0x1c, 0xcb, 0x34, 0x1b, 0x14, 0x5e, + 0x64, 0x3c, 0xa4, 0x14, 0xb7, 0x1d, 0x89, 0x72, 0xe2, 0x2d, 0xbc, 0x58, + 0x07, 0x66, 0xa9, 0x1f, 0x4e, 0x83, 0x14, 0xf0, 0x2e, 0xbc, 0x68, 0x60, + 0xa4, 0x80, 0x20, 0xbb, 0x8d, 0xb3, 0xc8, 0x62, 0x83, 0xdd, 0x00, 0x71, + 0x02, 0x27, 0x6f, 0xbf, 0xef, 0xde, 0xfb, 0xc8, 0xd1, 0x88, 0x76, 0xd2, + 0xfc, 0xb5, 0x04, 0x06, 0xf7, 0xfd, 0xb8, 0x3f, 0xce, 0x3d, 0xf7, 0xdc, + 0x73, 0xbe, 0x73, 0xee, 0x79, 0x7c, 0x40, 0xa4, 0x53, 0xcc, 0xdf, 0x5e, + 0xfc, 0x32, 0xff, 0xe1, 0xb3, 0xb3, 0x63, 0x77, 0x65, 0xee, 0xc2, 0xe5, + 0x87, 0xed, 0xf7, 0x3b, 0x0e, 0x9f, 0x47, 0xf0, 0x8b, 0xe3, 0x37, 0x66, + 0xae, 0x77, 0xfb, 0x73, 0xf1, 0x3b, 0x68, 0x89, 0xcc, 0xfc, 0x4f, 0x11, + 0xab, 0xe5, 0x5d, 0xec, 0x5d, 0xda, 0xbc, 0xd7, 0x9f, 0xfd, 0x1b, 0xb4, + 0xf9, 0xd7, 0xfe, 0x45, 0x34, 0xd9, 0x6a, 0xde, 0xfc, 0x49, 0xcc, 0xce, + 0xce, 0x4c, 0xe6, 0x3d, 0x89, 0x45, 0xb2, 0x47, 0xa7, 0x66, 0x3d, 0x91, + 0x5c, 0x63, 0x24, 0x59, 0x90, 0x5f, 0x04, 0xe5, 0xb8, 0x23, 0x7c, 0xfe, + 0x5b, 0xd9, 0x77, 0xbe, 0xf6, 0xad, 0x7b, 0x53, 0x3f, 0xae, 0x45, 0x24, + 0xe6, 0x66, 0xdf, 0x16, 0x77, 0x48, 0x62, 0xfd, 0x68, 0xf3, 0xcc, 0x81, + 0x57, 0x6d, 0xe9, 0x0e, 0xfb, 0x72, 0x67, 0x22, 0x59, 0x99, 0x3e, 0x56, + 0x39, 0x19, 0xd8, 0x9e, 0x94, 0x9d, 0xac, 0x37, 0x5c, 0x97, 0xae, 0xf1, + 0x73, 0x99, 0x7b, 0x05, 0xf7, 0xd3, 0xc7, 0x1a, 0x31, 0x99, 0x6f, 0x94, + 0xbb, 0x6c, 0xcf, 0x43, 0x29, 0xb1, 0xb6, 0xec, 0x62, 0xec, 0x9a, 0xc7, + 0xb1, 0xbf, 0x8a, 0xb1, 0xf7, 0x4b, 0xd4, 0x0b, 0x82, 0x73, 0x18, 0xfb, + 0x70, 0xe3, 0x17, 0xc1, 0xb3, 0x8e, 0x1e, 0xd7, 0xce, 0x9e, 0x88, 0xb0, + 0xb4, 0xb2, 0xb5, 0xc9, 0x81, 0x06, 0xef, 0x8b, 0xed, 0x9a, 0x4e, 0xbf, + 0x13, 0x74, 0xc6, 0x9c, 0xec, 0x89, 0xce, 0x45, 0x94, 0xd1, 0x6c, 0x7c, + 0xec, 0x9c, 0xaa, 0xb7, 0x6e, 0xea, 0x3d, 0x1e, 0xd5, 0xed, 0xde, 0x9a, + 0x1c, 0x6a, 0xb0, 0xfc, 0xc9, 0xe4, 0xa0, 0x2a, 0xdf, 0x99, 0x4c, 0xab, + 0x52, 0xa6, 0x06, 0x54, 0xe9, 0x4c, 0x79, 0xaa, 0x7c, 0xc6, 0x3c, 0x7f, + 0x6e, 0x32, 0xa9, 0xca, 0x86, 0x29, 0x2f, 0x99, 0xf2, 0x05, 0x53, 0xbe, + 0x68, 0xca, 0x97, 0x4c, 0xb9, 0x69, 0xca, 0x2b, 0x93, 0xba, 0x9f, 0x6f, + 0x9b, 0xfb, 0xef, 0x9a, 0xf2, 0x55, 0x53, 0xbe, 0x66, 0xca, 0xef, 0x99, + 0xf2, 0xfb, 0x86, 0xae, 0xeb, 0xa6, 0x7c, 0xd3, 0x94, 0x3f, 0x32, 0xef, + 0x7f, 0x6c, 0xe8, 0x7d, 0x1b, 0x74, 0xfd, 0x49, 0xd4, 0xc8, 0x2a, 0xe6, + 0x9d, 0x94, 0xd9, 0x8a, 0x23, 0xf3, 0xcb, 0x11, 0x29, 0xa8, 0x35, 0xfc, + 0xca, 0x5e, 0xe9, 0x74, 0x64, 0x61, 0x23, 0x26, 0xd7, 0x95, 0x88, 0xbe, + 0x15, 0x7c, 0xeb, 0x80, 0x94, 0xed, 0xac, 0x2b, 0x97, 0x36, 0xe2, 0xf2, + 0xf2, 0x86, 0x58, 0xd3, 0x99, 0x0e, 0xb1, 0xcf, 0x7e, 0x40, 0x72, 0xae, + 0x25, 0x11, 0xc5, 0xd3, 0xa4, 0xe4, 0x2b, 0x7d, 0xb8, 0x4f, 0x25, 0x44, + 0xae, 0xee, 0xd5, 0xeb, 0x17, 0x93, 0xc8, 0x2a, 0xd7, 0xe4, 0xfe, 0xa9, + 0x6b, 0x2b, 0x09, 0x71, 0x96, 0x46, 0x31, 0x46, 0x97, 0x44, 0x57, 0xa5, + 0x3f, 0x22, 0x83, 0x89, 0x4f, 0xa3, 0x46, 0xb1, 0xe1, 0xc8, 0x44, 0xc3, + 0x12, 0xc7, 0x8b, 0x41, 0x3e, 0xba, 0xf0, 0x73, 0xf1, 0x8b, 0xe3, 0x97, + 0xc0, 0xef, 0x47, 0xe8, 0xa7, 0x5f, 0x0a, 0x0d, 0xf6, 0x89, 0x71, 0x97, + 0x31, 0xfe, 0x72, 0xca, 0x9d, 0x11, 0xd2, 0x95, 0x90, 0x6f, 0x1d, 0x20, + 0x5d, 0x2e, 0xe9, 0x01, 0x6d, 0x31, 0x2b, 0xbf, 0x22, 0x27, 0x0a, 0xbe, + 0x24, 0x6d, 0xaf, 0x53, 0x4a, 0xae, 0x95, 0x9c, 0x1b, 0xee, 0x95, 0xf2, + 0x51, 0xbc, 0x5f, 0x96, 0x9c, 0x8d, 0xfe, 0x4b, 0xae, 0xcc, 0xe8, 0x77, + 0x7c, 0xf6, 0x36, 0xf6, 0x6a, 0xca, 0xa5, 0xd0, 0xbe, 0xbc, 0xfc, 0xb7, + 0xb8, 0x66, 0x7f, 0x3f, 0x77, 0x34, 0xdd, 0x3f, 0xc5, 0x3d, 0x9f, 0x0f, + 0x99, 0x79, 0xf0, 0x9a, 0x75, 0xc3, 0x71, 0xc3, 0xf9, 0x72, 0xfc, 0x61, + 0xcc, 0x99, 0x34, 0x84, 0x73, 0x96, 0x72, 0x14, 0xb4, 0xd4, 0x57, 0xba, + 0xac, 0xb5, 0x95, 0x51, 0x79, 0x62, 0xf9, 0x01, 0xc9, 0xfb, 0x41, 0x30, + 0xeb, 0x4b, 0xdc, 0x96, 0x41, 0xb7, 0x80, 0x0a, 0x5b, 0x0d, 0xb1, 0xea, + 0x15, 0x89, 0xb5, 0x83, 0x2f, 0x3f, 0x58, 0x61, 0xdf, 0x0e, 0x9e, 0xf5, + 0xa1, 0x7e, 0xb7, 0xb5, 0xbe, 0x02, 0xfa, 0xb3, 0xe4, 0x4f, 0x10, 0x2c, + 0xfa, 0x83, 0x89, 0x39, 0x8c, 0x79, 0xb9, 0x31, 0x38, 0x7e, 0x43, 0x5c, + 0xf4, 0xd9, 0x8b, 0x3a, 0xe4, 0x15, 0xfb, 0x62, 0x9f, 0xec, 0xaf, 0x0b, + 0x6d, 0xe3, 0x78, 0x47, 0xba, 0x82, 0x20, 0xef, 0xbb, 0xbc, 0x97, 0x4d, + 0xf0, 0x6f, 0x93, 0xfc, 0xeb, 0xec, 0x97, 0x57, 0x1a, 0x1c, 0x63, 0x37, + 0xda, 0x47, 0xfe, 0x3f, 0xa4, 0x3d, 0x81, 0xfe, 0xe3, 0x28, 0xf7, 0x58, + 0xf5, 0x6a, 0x80, 0xf1, 0x13, 0xb8, 0xde, 0x6d, 0x1e, 0xd7, 0xd5, 0xda, + 0x5f, 0xc2, 0xda, 0xbb, 0xd9, 0xb8, 0x3c, 0xbf, 0xd1, 0x8f, 0x79, 0x24, + 0xe4, 0x1b, 0x90, 0xcd, 0x9e, 0x83, 0x7b, 0x24, 0x0d, 0xd9, 0xe4, 0x9a, + 0x8f, 0xad, 0xce, 0x49, 0x29, 0x9e, 0x1a, 0xa6, 0x1e, 0xcd, 0x8f, 0xed, + 0xc3, 0x7c, 0xb5, 0xb6, 0x1a, 0x58, 0xca, 0xed, 0xb7, 0xe5, 0x90, 0xd8, + 0x59, 0x8c, 0x9b, 0x19, 0x01, 0x2d, 0x11, 0xbc, 0x8b, 0x8b, 0xb7, 0x9a, + 0xc3, 0xb3, 0x54, 0xa2, 0x04, 0x1a, 0xe7, 0x41, 0x63, 0x49, 0xca, 0x62, + 0x5f, 0x7c, 0xce, 0x0a, 0xf7, 0x8a, 0xe6, 0xdd, 0xb0, 0xe9, 0x67, 0x5b, + 0xce, 0x2d, 0x7b, 0xb5, 0xcb, 0x8a, 0xac, 0x8e, 0xca, 0xa9, 0x5d, 0x78, + 0x56, 0x07, 0xcf, 0xec, 0xa5, 0x70, 0x1f, 0x38, 0xb8, 0xef, 0x43, 0xdd, + 0x6e, 0xcb, 0x59, 0xbd, 0x95, 0x5f, 0x6b, 0x8d, 0x41, 0x7f, 0x0b, 0xfc, + 0xb2, 0x57, 0x7b, 0x51, 0xe7, 0x56, 0x7e, 0xd5, 0xc1, 0x2f, 0x7b, 0x55, + 0xf3, 0xaa, 0x0e, 0x5e, 0xd9, 0x4b, 0x71, 0x94, 0x7b, 0x2c, 0xfb, 0xac, + 0xe6, 0x55, 0xdd, 0xec, 0x99, 0xf3, 0x4a, 0x5f, 0xe5, 0x40, 0xab, 0x25, + 0x5a, 0x67, 0xe5, 0x84, 0xba, 0x29, 0x92, 0x2d, 0x62, 0xaf, 0xdb, 0xe0, + 0x85, 0x23, 0xc5, 0x31, 0x4b, 0x66, 0xd5, 0xbb, 0xa2, 0xa4, 0x1b, 0x1f, + 0x00, 0x23, 0x47, 0x86, 0x61, 0x29, 0xca, 0x6d, 0xd9, 0x17, 0xed, 0xad, + 0x4a, 0x4c, 0x0a, 0x4e, 0x52, 0xbc, 0x25, 0xa5, 0xc7, 0x9b, 0xfa, 0x99, + 0x41, 0x3f, 0xdf, 0x01, 0x3f, 0x2c, 0xe8, 0x56, 0xbe, 0x7b, 0x4c, 0xed, + 0xfb, 0xf4, 0xaa, 0x23, 0x83, 0x4b, 0xac, 0x53, 0xb6, 0xaf, 0x34, 0xde, + 0x09, 0x74, 0xbf, 0x8f, 0x71, 0x4c, 0xd7, 0xce, 0x2e, 0xda, 0x97, 0xd7, + 0x4f, 0xdb, 0x57, 0x1b, 0xe8, 0xb7, 0xc1, 0xb5, 0xc0, 0x5a, 0x2d, 0x63, + 0xad, 0x96, 0xb1, 0x6e, 0x66, 0x4f, 0xd7, 0xd4, 0xde, 0x4a, 0x9a, 0x75, + 0x25, 0x0d, 0x5c, 0xdb, 0x04, 0xd6, 0x94, 0x6b, 0x2b, 0xd6, 0xab, 0x99, + 0x3d, 0x12, 0x39, 0x1b, 0x51, 0x6b, 0xda, 0xb3, 0xfa, 0x91, 0xed, 0x35, + 0x1d, 0x68, 0x5a, 0x53, 0xfb, 0x5d, 0xd6, 0xd4, 0xd9, 0x65, 0x4d, 0xb7, + 0x1a, 0x3f, 0x31, 0x6b, 0xfa, 0x73, 0x31, 0xb2, 0xff, 0x9e, 0xfc, 0x1a, + 0x00, 0xbf, 0xbc, 0x5f, 0x83, 0x5f, 0xce, 0xae, 0xfc, 0xea, 0xb3, 0x5b, + 0xf9, 0x15, 0x01, 0xbf, 0xa2, 0xbf, 0x36, 0xbf, 0xc0, 0x87, 0x5d, 0x79, + 0x15, 0x83, 0xde, 0x2b, 0x4b, 0x3e, 0x23, 0x92, 0xaf, 0x6a, 0x5d, 0x5d, + 0x56, 0x3a, 0x9b, 0xba, 0x2a, 0xd4, 0xd9, 0xd4, 0xd7, 0x6a, 0x9f, 0x58, + 0x85, 0x4a, 0x12, 0xba, 0xd4, 0x41, 0xf9, 0x1c, 0xca, 0x3d, 0xd6, 0x74, + 0xb5, 0x1f, 0x76, 0x36, 0x10, 0x77, 0x2c, 0xb4, 0x97, 0xe5, 0x84, 0x8b, + 0xb5, 0x71, 0xef, 0x8a, 0x8a, 0xf4, 0xa5, 0xc0, 0xa7, 0x14, 0xde, 0xa7, + 0x12, 0x39, 0xc9, 0xda, 0x21, 0xae, 0xc9, 0x57, 0x3a, 0xde, 0xce, 0xa9, + 0x2b, 0x3e, 0x67, 0xbb, 0x0c, 0x9e, 0x45, 0x65, 0x06, 0x76, 0xa0, 0xe8, + 0x71, 0x3c, 0xf6, 0x9f, 0x9c, 0xe1, 0xb8, 0x85, 0x46, 0xa8, 0xb3, 0x25, + 0x07, 0x1b, 0x8e, 0x77, 0xdc, 0xb7, 0xe3, 0x56, 0x41, 0xd9, 0xa0, 0x8c, + 0x78, 0x8d, 0x66, 0xfb, 0xb2, 0x4d, 0x27, 0xf6, 0x73, 0x0e, 0x72, 0x4d, + 0xda, 0x92, 0xd8, 0x7b, 0xc7, 0x22, 0xe1, 0xfa, 0x38, 0xd9, 0x71, 0x81, + 0x5d, 0x96, 0xf9, 0x0a, 0xfb, 0xfb, 0x63, 0x2b, 0x72, 0x31, 0xec, 0x9f, + 0x7c, 0x64, 0xdf, 0xba, 0xbf, 0xf9, 0xc6, 0x5b, 0x46, 0x37, 0x28, 0x5b, + 0x85, 0xfe, 0xca, 0x4d, 0xfd, 0x95, 0xad, 0xc8, 0x92, 0xec, 0x53, 0xf6, + 0xe0, 0x28, 0xf9, 0x77, 0x1a, 0xef, 0xae, 0x4b, 0x84, 0x32, 0xa3, 0xf6, + 0x18, 0xf7, 0xfb, 0x97, 0x38, 0xdf, 0x26, 0xde, 0x4e, 0xc3, 0xc6, 0x71, + 0x7f, 0x61, 0x8d, 0xe3, 0x7c, 0x7e, 0xc8, 0xd0, 0xe4, 0x48, 0x4e, 0xdd, + 0x7f, 0x63, 0x4f, 0xa8, 0x3f, 0xb1, 0x9f, 0x41, 0xdb, 0x8b, 0x6a, 0x8e, + 0x76, 0x36, 0x0b, 0xde, 0x34, 0xd3, 0xc8, 0x79, 0x67, 0xb1, 0xc6, 0xa1, + 0x0e, 0x0b, 0xd7, 0x8a, 0xb8, 0xc6, 0xb1, 0x16, 0x2a, 0x5d, 0xb0, 0x8f, + 0x31, 0x63, 0x83, 0xd9, 0x7e, 0x11, 0xed, 0xf9, 0x9c, 0x6d, 0xbb, 0x60, + 0x8f, 0xd9, 0x7e, 0xd1, 0xb4, 0xdf, 0xb1, 0xcb, 0xdc, 0x2b, 0xb4, 0xc9, + 0x57, 0x32, 0xc0, 0x42, 0x2b, 0xb6, 0x14, 0x7c, 0xe0, 0x1c, 0xbf, 0xdf, + 0xec, 0x0b, 0x2d, 0x9b, 0x1f, 0x75, 0x2c, 0x69, 0xf7, 0x76, 0x93, 0xcd, + 0x7f, 0xb0, 0xb5, 0xad, 0xdb, 0x91, 0xcd, 0x05, 0xe8, 0xa8, 0x53, 0x90, + 0x95, 0xc5, 0xed, 0x7a, 0x94, 0x4b, 0x25, 0xa3, 0x90, 0xcd, 0xd4, 0x38, + 0xa7, 0x79, 0xa5, 0xd1, 0x2c, 0xa3, 0x61, 0x1f, 0x31, 0x25, 0x07, 0x7a, + 0x9c, 0xc5, 0xa6, 0x71, 0x16, 0x9b, 0xc6, 0x59, 0x32, 0xd8, 0x8e, 0xfd, + 0x68, 0xbb, 0x7a, 0xfd, 0x26, 0x7b, 0xce, 0x35, 0xfb, 0x24, 0xf6, 0xa4, + 0x96, 0x05, 0x60, 0x35, 0xbd, 0x06, 0x15, 0x57, 0xe6, 0x37, 0x2e, 0x84, + 0x7b, 0xb5, 0xdc, 0x8e, 0xe7, 0x3f, 0xc4, 0xf3, 0xe1, 0x33, 0x2e, 0xec, + 0x14, 0xb1, 0xda, 0x4b, 0x72, 0xae, 0x42, 0x19, 0x79, 0x11, 0x74, 0xa7, + 0xfd, 0x36, 0x8b, 0x7c, 0x4d, 0x0d, 0x9f, 0x97, 0x54, 0x72, 0x5e, 0x46, + 0x7c, 0x96, 0x4f, 0x88, 0xc2, 0x58, 0xa2, 0x31, 0xd0, 0x8b, 0x90, 0x3f, + 0x91, 0x1f, 0x57, 0xda, 0xc5, 0x1e, 0xfb, 0x61, 0x40, 0x3b, 0x78, 0x7a, + 0xa3, 0xb5, 0x1f, 0x91, 0xa1, 0x33, 0xaa, 0x1f, 0xf4, 0x91, 0xf6, 0xbf, + 0xad, 0xfa, 0x0b, 0xfb, 0xc2, 0x3c, 0xc7, 0x5a, 0xfb, 0x73, 0xe4, 0xba, + 0x6b, 0xa3, 0xbf, 0xb4, 0x99, 0x23, 0xaf, 0x21, 0x23, 0xae, 0x83, 0xf2, + 0x61, 0x3b, 0x94, 0x19, 0x7b, 0xec, 0x3b, 0x41, 0x6e, 0x9a, 0x73, 0x2b, + 0x99, 0x67, 0xff, 0xc3, 0xc8, 0x9b, 0x54, 0xed, 0x2c, 0x78, 0x96, 0x19, + 0xc4, 0x78, 0xbc, 0x4f, 0x02, 0x1f, 0x49, 0x99, 0xf8, 0xac, 0x54, 0xf9, + 0x65, 0x90, 0x73, 0x34, 0xa6, 0xd2, 0x6b, 0xcf, 0xf7, 0x96, 0x14, 0x50, + 0x77, 0xc1, 0xe8, 0x83, 0x62, 0xe3, 0xba, 0xe2, 0xdf, 0xf3, 0x6a, 0x1f, + 0xa5, 0x4e, 0x97, 0xa9, 0x37, 0x36, 0xdc, 0x08, 0xf7, 0xf8, 0x25, 0xff, + 0xa5, 0x60, 0x61, 0x39, 0x95, 0x4c, 0xda, 0x83, 0x52, 0xaa, 0x0e, 0x96, + 0x6d, 0x94, 0x27, 0x6a, 0x09, 0x39, 0x51, 0x61, 0x3f, 0xfb, 0x51, 0x07, + 0x8a, 0xc8, 0xc6, 0x26, 0xef, 0xa3, 0xae, 0xe1, 0x98, 0x6f, 0x5b, 0x7a, + 0x4c, 0xcc, 0xc1, 0xdb, 0xb4, 0xfe, 0x63, 0xe3, 0x8a, 0x55, 0xaa, 0x71, + 0xfd, 0xf1, 0xbc, 0xd1, 0xac, 0x8f, 0x42, 0x5d, 0xb4, 0x83, 0xc5, 0x22, + 0xd9, 0x45, 0xab, 0xb4, 0x22, 0x76, 0xde, 0x8f, 0x12, 0x0f, 0x26, 0x45, + 0xee, 0x75, 0xf5, 0x3c, 0x3f, 0x19, 0xa1, 0x1e, 0x74, 0xbc, 0xd3, 0xe8, + 0xbb, 0x53, 0x72, 0x0e, 0xd7, 0x9f, 0xd7, 0x12, 0x44, 0xb2, 0x1e, 0x6d, + 0xa5, 0x13, 0xc9, 0x3a, 0xd8, 0x63, 0xac, 0xf3, 0x52, 0xc0, 0xbd, 0x90, + 0xaf, 0x6a, 0x19, 0x29, 0xef, 0x60, 0x2f, 0xd0, 0x9b, 0x83, 0x8e, 0x11, + 0x1b, 0x7b, 0xcc, 0x8d, 0x64, 0xf9, 0x7c, 0x1c, 0xd7, 0x9b, 0xa8, 0x4f, + 0x1d, 0x0b, 0x4c, 0x5a, 0x53, 0xbc, 0xc3, 0x58, 0x39, 0xab, 0x58, 0x09, + 0x79, 0xf2, 0x52, 0xf0, 0xe4, 0x72, 0x88, 0x11, 0x94, 0x6c, 0xc9, 0xc0, + 0xd9, 0xa4, 0xd9, 0xd7, 0x5d, 0xdc, 0x73, 0xe4, 0x3f, 0x9e, 0xf9, 0xe6, + 0x59, 0x7b, 0xd3, 0xb3, 0x70, 0xff, 0x7f, 0x09, 0xb4, 0xf5, 0x2b, 0xfe, + 0xd8, 0xd9, 0x23, 0x56, 0x5e, 0xe1, 0x93, 0x20, 0x28, 0x78, 0x51, 0x29, + 0x8d, 0xfe, 0x09, 0xe6, 0xca, 0x77, 0x65, 0x30, 0x9c, 0x76, 0x63, 0x78, + 0x72, 0xd6, 0x4b, 0x29, 0xfb, 0x9f, 0xc7, 0xfe, 0xd3, 0x3a, 0x53, 0xca, + 0x3d, 0xa0, 0xdd, 0x5b, 0xe2, 0x9a, 0xbc, 0x14, 0x9c, 0x05, 0x16, 0x9e, + 0x5e, 0x2a, 0x5a, 0x03, 0xd8, 0x12, 0x76, 0x9f, 0x05, 0x3e, 0x77, 0x49, + 0xfe, 0x22, 0xd7, 0x82, 0x75, 0xf8, 0xbc, 0x4d, 0xa6, 0xe3, 0xad, 0xb6, + 0xf2, 0xdc, 0x3e, 0xe9, 0x24, 0xbf, 0x51, 0x77, 0xe9, 0xff, 0x46, 0xb4, + 0x5e, 0x76, 0x65, 0x60, 0x95, 0x7c, 0x2f, 0x5a, 0xb3, 0x15, 0xea, 0xb1, + 0x0e, 0xd8, 0x47, 0x3e, 0x67, 0x9f, 0x78, 0x77, 0xbe, 0xb5, 0x8f, 0xdf, + 0x8b, 0xe8, 0x3e, 0xd8, 0x2e, 0xec, 0xa3, 0x99, 0x1f, 0x7b, 0x94, 0x9e, + 0xeb, 0xcd, 0xf6, 0xb6, 0xf4, 0x9b, 0x68, 0xea, 0x17, 0xef, 0xce, 0x7f, + 0x37, 0x42, 0x5c, 0xf6, 0xf2, 0x32, 0xf8, 0xac, 0xe6, 0xc4, 0x77, 0x6c, + 0x53, 0xb4, 0x0a, 0x4b, 0x41, 0x30, 0xed, 0xdb, 0x12, 0xe9, 0x0b, 0xeb, + 0xea, 0x79, 0x15, 0x31, 0xaf, 0x3c, 0xe6, 0x65, 0xf7, 0xb5, 0xd2, 0xf4, + 0xfb, 0x86, 0xa6, 0xde, 0x26, 0x9a, 0xe2, 0xef, 0x31, 0xaf, 0xf8, 0x2e, + 0xf3, 0x7a, 0xa9, 0x57, 0xf7, 0x11, 0x6f, 0xea, 0xa3, 0xaf, 0xa5, 0x0f, + 0xe8, 0xfd, 0x38, 0xdb, 0xf7, 0xed, 0xd2, 0xfe, 0x87, 0x1d, 0xba, 0x3d, + 0xdb, 0xb4, 0x41, 0xb7, 0xf7, 0x1b, 0xbd, 0x78, 0xa2, 0x49, 0x97, 0x9d, + 0x80, 0x2e, 0x6b, 0x6e, 0xd3, 0x2c, 0xff, 0xa1, 0x8f, 0x44, 0xff, 0x28, + 0xc4, 0x8a, 0x1f, 0x50, 0x18, 0x64, 0x07, 0x63, 0xc7, 0x80, 0x47, 0xba, + 0x60, 0xff, 0xbb, 0xe9, 0x07, 0x19, 0x4c, 0x48, 0xbf, 0x88, 0x38, 0x50, + 0x3c, 0xa0, 0x28, 0xe8, 0x96, 0xc1, 0xc4, 0x31, 0x11, 0xe5, 0x07, 0x11, + 0x5f, 0xd3, 0x27, 0xe2, 0x38, 0xf4, 0x89, 0xb8, 0xee, 0xbc, 0x2f, 0x6c, + 0xfb, 0x48, 0xfd, 0xd8, 0xf7, 0xc4, 0xc7, 0xdc, 0x33, 0xa1, 0xad, 0x69, + 0xd6, 0xa7, 0xbb, 0xd1, 0xd4, 0xdf, 0x42, 0x13, 0x74, 0x12, 0x7c, 0xb3, + 0x05, 0xc8, 0x23, 0x30, 0x29, 0x74, 0xe0, 0xfd, 0x53, 0xe7, 0x56, 0x44, + 0x4a, 0x0d, 0xda, 0xc7, 0x51, 0x81, 0x5f, 0x05, 0xba, 0xd8, 0xb7, 0xb2, + 0x91, 0xd0, 0x4d, 0xdd, 0x39, 0x3b, 0x3b, 0x08, 0x3f, 0xdc, 0x91, 0x39, + 0x43, 0xdb, 0x8c, 0xf2, 0xe1, 0xba, 0x50, 0x26, 0x94, 0x5c, 0xcd, 0x80, + 0x3e, 0x5e, 0xcf, 0x18, 0xec, 0x7e, 0xac, 0xd1, 0x4a, 0xdb, 0xf7, 0x40, + 0x9b, 0x07, 0x1a, 0x92, 0xf2, 0x02, 0xb0, 0xfb, 0x37, 0xd5, 0xbe, 0x0c, + 0x75, 0x17, 0x65, 0x29, 0x55, 0x2d, 0xcb, 0x66, 0xb0, 0xb2, 0xcc, 0x7d, + 0x4b, 0x1b, 0xde, 0x25, 0x65, 0xac, 0xd7, 0xc0, 0x52, 0x2a, 0x99, 0xb3, + 0xc5, 0x7a, 0xdf, 0x41, 0xca, 0xd3, 0xe3, 0x32, 0x70, 0x51, 0x2c, 0x67, + 0x09, 0x7b, 0xbd, 0x3b, 0xc4, 0x57, 0x9c, 0xdf, 0x6f, 0x63, 0x7e, 0xe8, + 0x7b, 0x39, 0x9c, 0x5f, 0x97, 0x94, 0x56, 0x39, 0xbf, 0xed, 0xb9, 0xc5, + 0x19, 0x11, 0xf9, 0x1c, 0xf4, 0x35, 0xe6, 0x08, 0x1a, 0xc7, 0x81, 0x73, + 0xef, 0x30, 0x73, 0xea, 0xc2, 0x9c, 0x60, 0xa3, 0x97, 0xd8, 0x1e, 0x74, + 0x81, 0xe6, 0x12, 0xea, 0xcd, 0x2f, 0x71, 0xcd, 0x41, 0x2b, 0xd6, 0xbd, + 0xd4, 0xe0, 0xda, 0x73, 0x6e, 0xda, 0xae, 0x3b, 0x1e, 0xe7, 0xc7, 0x79, + 0x0e, 0x63, 0x5e, 0xac, 0xc3, 0x76, 0xad, 0x32, 0x32, 0xfc, 0x1e, 0xeb, + 0xf1, 0xdb, 0x2d, 0xeb, 0x21, 0x66, 0x3d, 0x62, 0xd2, 0xb6, 0xaa, 0xfc, + 0x65, 0x45, 0x03, 0x7d, 0x08, 0x07, 0xf4, 0x2f, 0xae, 0xc8, 0x68, 0x54, + 0x48, 0x7b, 0x82, 0xcf, 0x32, 0x6d, 0x32, 0xe8, 0x5f, 0x81, 0x5c, 0x95, + 0x20, 0x0b, 0xf4, 0x07, 0x5e, 0x5e, 0xd6, 0x6b, 0x51, 0x6a, 0x74, 0xc2, + 0x47, 0xe7, 0xf8, 0xe4, 0x37, 0xe7, 0xe6, 0xaa, 0x75, 0x68, 0x5e, 0x97, + 0x4f, 0xdf, 0xb2, 0x2e, 0xd4, 0xbb, 0xd4, 0x03, 0xc4, 0x3d, 0xd4, 0x05, + 0x61, 0x4c, 0xa0, 0xe6, 0xea, 0xfd, 0x14, 0xda, 0x9f, 0xeb, 0xdb, 0xf8, + 0x52, 0xaf, 0x59, 0xc2, 0xc4, 0x05, 0xba, 0xc4, 0x5e, 0xbd, 0x83, 0x7a, + 0x1f, 0xf6, 0x27, 0x9c, 0xdf, 0xef, 0xe0, 0x3e, 0x71, 0xd3, 0x7a, 0xd8, + 0x98, 0x93, 0xa3, 0xe6, 0xa8, 0xd6, 0x62, 0x5b, 0xe6, 0xe6, 0x1a, 0x7a, + 0x5e, 0xce, 0xd2, 0x1e, 0xb3, 0x1e, 0x31, 0x3c, 0xe3, 0xbc, 0x42, 0x9b, + 0xc3, 0x79, 0x91, 0x5e, 0xd7, 0xc8, 0x1c, 0xe7, 0xc3, 0xfd, 0xd7, 0x2c, + 0x6b, 0x2f, 0x05, 0xd5, 0xe5, 0xa8, 0x9a, 0x7b, 0xde, 0xef, 0x26, 0x46, + 0xa3, 0x8e, 0x34, 0xfa, 0x89, 0xcf, 0x69, 0x07, 0xf1, 0x2e, 0x43, 0x19, + 0xc2, 0x7d, 0x9d, 0xf7, 0xcd, 0x36, 0xed, 0x79, 0x47, 0xeb, 0x01, 0xc6, + 0x9f, 0xde, 0xdb, 0xd6, 0x45, 0xb3, 0x62, 0xad, 0x57, 0xe8, 0x33, 0x07, + 0xc0, 0x5d, 0x77, 0x40, 0xaf, 0x1c, 0x92, 0x92, 0x0b, 0x7b, 0x3d, 0x7c, + 0x3b, 0xe6, 0x3c, 0x2e, 0x2a, 0xde, 0x30, 0xbc, 0x17, 0xd7, 0x7b, 0x94, + 0xef, 0x52, 0x1a, 0xfe, 0x90, 0xe4, 0xa6, 0x69, 0xd3, 0x7e, 0x5f, 0x66, + 0x60, 0x5b, 0x4b, 0xc3, 0x77, 0x82, 0x3e, 0xde, 0x43, 0x27, 0x7a, 0x43, + 0x8c, 0x51, 0xe0, 0xef, 0x71, 0x13, 0x9b, 0x39, 0x80, 0xfb, 0x3d, 0xa8, + 0xf3, 0x49, 0x53, 0xa7, 0x1b, 0x75, 0x06, 0x5b, 0xea, 0x70, 0xbc, 0xfb, + 0x50, 0x07, 0xf6, 0x14, 0x56, 0xd2, 0xf6, 0x0e, 0xe2, 0x37, 0x81, 0x67, + 0xf7, 0xe2, 0xd9, 0x3d, 0x78, 0x76, 0x0f, 0xee, 0x7f, 0xd7, 0xc4, 0x3c, + 0xc2, 0x36, 0xdd, 0xb8, 0xff, 0x12, 0xde, 0x43, 0xc7, 0xb9, 0xdf, 0xc6, + 0xfb, 0xfb, 0xf0, 0x1b, 0x6b, 0xa9, 0xe3, 0xb6, 0xdc, 0x9f, 0x76, 0x74, + 0x8c, 0x84, 0xcf, 0x82, 0xc8, 0xce, 0xf5, 0x7f, 0x35, 0xcf, 0xbd, 0xa6, + 0xf7, 0x1f, 0x37, 0xd7, 0xad, 0xb2, 0x94, 0x86, 0x2c, 0xf1, 0xfd, 0x57, + 0xf6, 0xe9, 0xb5, 0xb8, 0x43, 0xc7, 0x1f, 0x6e, 0xc2, 0x1b, 0x4a, 0xfc, + 0x71, 0xbd, 0x09, 0x9c, 0x41, 0xec, 0xd1, 0x8c, 0x3b, 0x48, 0x8b, 0xab, + 0xe4, 0xf5, 0xe5, 0xe5, 0xd7, 0xba, 0xf5, 0x18, 0x62, 0xd5, 0x21, 0x73, + 0x13, 0x2a, 0x16, 0xf1, 0x33, 0xf3, 0xcc, 0xdb, 0xb7, 0xf3, 0x6e, 0xaf, + 0x4c, 0x54, 0xff, 0x68, 0xdf, 0x0e, 0x6d, 0x93, 0x4d, 0xd7, 0x3b, 0x98, + 0x02, 0xfe, 0x84, 0xbd, 0x83, 0x77, 0x72, 0xf6, 0x5c, 0xa3, 0x68, 0xeb, + 0x71, 0x59, 0x07, 0xef, 0x1a, 0x9b, 0x3d, 0x8e, 0x92, 0xfd, 0x9c, 0x4d, + 0x5f, 0xa3, 0xbc, 0xc6, 0xeb, 0xdb, 0x51, 0x36, 0xb7, 0xed, 0x87, 0x1e, + 0xcf, 0xd9, 0x9a, 0xee, 0xd6, 0xf6, 0xe1, 0xbe, 0xf1, 0x65, 0xa1, 0x0a, + 0x99, 0xf3, 0x52, 0xc3, 0x65, 0xac, 0xdd, 0xac, 0x9f, 0x9a, 0xa6, 0x4c, + 0xc2, 0x9f, 0xfd, 0x94, 0xc8, 0xa4, 0xcc, 0x57, 0x1f, 0x06, 0xfe, 0x0e, + 0xe4, 0x21, 0xe0, 0x8a, 0x7f, 0x0f, 0x5c, 0x52, 0x83, 0xac, 0xd7, 0x1a, + 0x1e, 0x7e, 0xfd, 0xf2, 0x57, 0x95, 0x84, 0x3c, 0x07, 0x7f, 0x02, 0xb2, + 0x06, 0x3d, 0x9c, 0x76, 0x1f, 0x12, 0xe9, 0xb1, 0xe5, 0xf2, 0xbd, 0xb6, + 0x8c, 0x24, 0x07, 0xac, 0x74, 0x02, 0x3f, 0xb7, 0x0d, 0xbf, 0x22, 0x7c, + 0xb8, 0xb5, 0x06, 0x63, 0x01, 0x71, 0xf9, 0xeb, 0xf5, 0x24, 0x7e, 0x7d, + 0xf2, 0x37, 0xeb, 0x1c, 0x7f, 0xc0, 0x94, 0x6a, 0x1f, 0xc3, 0xe7, 0x28, + 0xcb, 0x62, 0x26, 0x21, 0x0b, 0x95, 0xe0, 0xa4, 0xf6, 0x99, 0x3d, 0xf8, + 0xc8, 0xdc, 0xb3, 0x2f, 0x60, 0xcf, 0xe2, 0xb9, 0xc2, 0x9e, 0xa1, 0xdd, + 0x7b, 0x01, 0x76, 0x2f, 0x5c, 0x23, 0xce, 0xb3, 0x75, 0x7d, 0xd8, 0x2f, + 0xd7, 0x88, 0x7a, 0x9d, 0xba, 0x3c, 0x06, 0xfc, 0x10, 0xea, 0x76, 0xea, + 0x08, 0x6f, 0xdb, 0x0f, 0x7d, 0xe4, 0x60, 0x17, 0xb0, 0x86, 0xc4, 0xe2, + 0xd9, 0x9f, 0xca, 0xca, 0x59, 0xee, 0x1b, 0xda, 0xe3, 0xbb, 0x21, 0x6f, + 0xa9, 0xaf, 0x96, 0x89, 0x99, 0xbd, 0x0c, 0xf8, 0x51, 0x96, 0xe9, 0x83, + 0xab, 0xbd, 0x5a, 0x4e, 0x26, 0xc5, 0x39, 0xfb, 0x85, 0xa8, 0x74, 0x9f, + 0x94, 0x45, 0x1f, 0x7e, 0xa9, 0x5d, 0x0e, 0x22, 0x9e, 0x97, 0x28, 0x28, + 0xbf, 0x69, 0x05, 0x74, 0xc6, 0x64, 0xe2, 0x2c, 0xeb, 0x9c, 0x84, 0x8c, + 0xb5, 0x81, 0xe6, 0x76, 0x39, 0x15, 0x4f, 0x95, 0x0b, 0xf0, 0xf7, 0x6d, + 0xaf, 0x47, 0x06, 0xea, 0x2c, 0x89, 0x41, 0xfe, 0x37, 0xe4, 0x87, 0xd7, + 0xf0, 0x03, 0x57, 0xf9, 0x7c, 0x00, 0x25, 0x9f, 0x7b, 0xd0, 0x2f, 0xe4, + 0x07, 0x70, 0xc3, 0xc5, 0xb2, 0x9c, 0xca, 0x4c, 0x4a, 0xbd, 0x2a, 0xd6, + 0x42, 0x06, 0x7b, 0xa0, 0x96, 0x95, 0x3a, 0x78, 0x51, 0x6a, 0x1c, 0x87, + 0xdf, 0xf9, 0x26, 0xca, 0x39, 0x94, 0xd7, 0x51, 0x3e, 0x8e, 0xf2, 0x2d, + 0x94, 0xa4, 0xfd, 0xb8, 0xd4, 0x6b, 0x7b, 0xda, 0xa4, 0x93, 0x7d, 0x6c, + 0x18, 0x9a, 0xe1, 0x3b, 0x1e, 0x3c, 0x0e, 0x2c, 0x1a, 0x3e, 0x3f, 0x2e, + 0x52, 0xff, 0x0c, 0x7e, 0x0f, 0xaa, 0x7b, 0xfa, 0x96, 0x0b, 0x99, 0x71, + 0xe0, 0x7a, 0xb1, 0x4e, 0x65, 0x1e, 0x37, 0xfd, 0x7c, 0x06, 0xe3, 0x5d, + 0xc5, 0xd8, 0x31, 0xc8, 0x48, 0x20, 0x8f, 0xf8, 0x27, 0xe5, 0x73, 0xfe, + 0x7e, 0x19, 0xeb, 0x8d, 0x95, 0x63, 0x59, 0xce, 0x9f, 0x7a, 0x6a, 0xb7, + 0xf9, 0x87, 0xf3, 0xe6, 0x9c, 0xa1, 0x5b, 0x97, 0xf6, 0x6a, 0xdc, 0x6d, + 0x7f, 0x39, 0xaa, 0x69, 0xb1, 0x64, 0x60, 0x88, 0xfd, 0x65, 0x25, 0x72, + 0x76, 0xc8, 0xcd, 0xd8, 0x23, 0xf0, 0x52, 0xd2, 0xf8, 0x9d, 0x84, 0xfc, + 0x79, 0xa7, 0x07, 0xec, 0xdb, 0x40, 0x13, 0xde, 0xd5, 0x39, 0x0e, 0xec, + 0xe9, 0x3d, 0xaf, 0x62, 0x6e, 0x65, 0x69, 0xbf, 0x27, 0x2b, 0x37, 0x1a, + 0xbc, 0x86, 0x3d, 0xba, 0x30, 0x29, 0xff, 0x5c, 0xbd, 0x2a, 0x4f, 0x54, + 0x27, 0xe5, 0x0d, 0x94, 0x8b, 0xd5, 0x32, 0xf8, 0xc8, 0x58, 0x3c, 0xfb, + 0x08, 0xb0, 0x2e, 0x83, 0xf0, 0x8d, 0x3e, 0x98, 0x98, 0xc3, 0xfa, 0xcd, + 0xb8, 0x81, 0x9c, 0xf3, 0xcb, 0x72, 0x6e, 0x1c, 0x6d, 0x6a, 0x1d, 0x12, + 0x7d, 0x96, 0xf3, 0xed, 0x96, 0x02, 0x2c, 0x7a, 0x31, 0x43, 0x9d, 0xd9, + 0x29, 0x85, 0x5a, 0xab, 0xdc, 0x51, 0xde, 0xde, 0xb6, 0xea, 0xdb, 0x3a, + 0x60, 0xd3, 0xfa, 0x66, 0x83, 0x36, 0x78, 0x37, 0x7b, 0xaa, 0xe5, 0xae, + 0x5e, 0xa3, 0x4d, 0xdd, 0x91, 0xbd, 0x3a, 0xfc, 0xb9, 0x7a, 0xf5, 0xba, + 0x91, 0x3f, 0x25, 0xb7, 0x58, 0x17, 0x62, 0xf1, 0x9f, 0x08, 0xb0, 0x1f, + 0x78, 0x14, 0xc6, 0x09, 0xb5, 0x7f, 0x54, 0x03, 0xad, 0x85, 0x38, 0x71, + 0x06, 0xac, 0x5b, 0xed, 0x0b, 0x8a, 0x57, 0xde, 0xd9, 0x7e, 0xa9, 0x2e, + 0x93, 0xbf, 0x29, 0xd7, 0xb6, 0x95, 0x4f, 0x02, 0xbe, 0x7a, 0x58, 0x9f, + 0xf0, 0x7d, 0x0a, 0x7e, 0xd2, 0x49, 0x71, 0xc7, 0x3a, 0x31, 0x27, 0x5e, + 0x8b, 0x4c, 0x5f, 0x6c, 0xc5, 0x91, 0xa1, 0x9d, 0x68, 0x83, 0x3f, 0x1e, + 0xc5, 0x5a, 0x76, 0xc1, 0x9f, 0x86, 0x9f, 0x0a, 0x39, 0xfa, 0x33, 0x60, + 0xaf, 0xd3, 0xca, 0xb7, 0xe6, 0x9e, 0xea, 0x9e, 0x1a, 0x58, 0x67, 0xb9, + 0x77, 0x2a, 0x5d, 0x63, 0x19, 0x9f, 0xd2, 0xbe, 0x64, 0x62, 0x4a, 0xc7, + 0xed, 0x93, 0x53, 0x07, 0x54, 0xe9, 0x4d, 0x0d, 0xab, 0x72, 0x78, 0x6a, + 0x27, 0x66, 0x42, 0x9e, 0x8a, 0x95, 0xcf, 0x64, 0xa4, 0x58, 0x21, 0x8d, + 0xe2, 0x1c, 0x83, 0x3c, 0xcd, 0x01, 0xcb, 0xe4, 0x2b, 0xbe, 0x9c, 0xda, + 0xc8, 0x82, 0x66, 0xe8, 0x99, 0xac, 0x8f, 0x52, 0xcc, 0x5f, 0xd8, 0xb6, + 0x8d, 0x31, 0x32, 0xae, 0x99, 0xf1, 0x33, 0x7d, 0xfa, 0x99, 0xcd, 0x7f, + 0xec, 0x0f, 0xb2, 0x49, 0xfb, 0xf9, 0x0b, 0xf8, 0xc6, 0xe2, 0x94, 0x32, + 0x6c, 0xeb, 0xc3, 0x07, 0x17, 0xd9, 0x5a, 0x91, 0x58, 0x2c, 0xfb, 0x1d, + 0x89, 0x3d, 0x1d, 0x04, 0x3f, 0xf0, 0x53, 0x47, 0xca, 0x02, 0x5e, 0x59, + 0x78, 0xbe, 0xce, 0x77, 0xd4, 0x4d, 0x23, 0xee, 0x0d, 0xc8, 0x5c, 0xee, + 0xa8, 0xc8, 0x2b, 0x78, 0x56, 0x5f, 0xe1, 0x1a, 0x7c, 0x17, 0x6b, 0x60, + 0xd6, 0x44, 0x3d, 0x63, 0x3d, 0xf8, 0x58, 0x71, 0xce, 0x63, 0xc4, 0x6d, + 0x47, 0xfb, 0xda, 0x3a, 0xdb, 0xa4, 0xc6, 0x79, 0xe4, 0xf5, 0xca, 0xba, + 0x9e, 0xdf, 0xe1, 0xcc, 0xb0, 0x5c, 0xae, 0xa8, 0x3e, 0x20, 0xeb, 0xbf, + 0x44, 0x9b, 0x4d, 0xc8, 0x2d, 0x63, 0x53, 0x59, 0x99, 0x07, 0x4e, 0x9b, + 0xaf, 0xa4, 0x21, 0x3b, 0x8e, 0xcc, 0x24, 0x48, 0xb6, 0x27, 0x5b, 0x95, + 0x37, 0xdb, 0x88, 0x85, 0xf3, 0x1e, 0xaf, 0xc7, 0x51, 0x67, 0x5a, 0x88, + 0xb7, 0xf2, 0x19, 0xce, 0xa9, 0x99, 0x17, 0xfa, 0xaf, 0x84, 0xb5, 0x30, + 0x73, 0x54, 0x7f, 0x7a, 0x1c, 0xb4, 0x37, 0xe3, 0x14, 0x01, 0x53, 0xe0, + 0x6b, 0x4a, 0xfa, 0x82, 0xe3, 0xe4, 0x2b, 0x8e, 0x0c, 0x5c, 0xc0, 0xb6, + 0xca, 0x1a, 0x5e, 0x34, 0x42, 0x59, 0x0b, 0x31, 0x10, 0x65, 0x8b, 0x3c, + 0x48, 0x95, 0x37, 0xc1, 0xec, 0xde, 0xec, 0x35, 0x79, 0x74, 0x55, 0xcf, + 0xd9, 0x3e, 0x2f, 0x3c, 0x0b, 0x91, 0x1b, 0x2b, 0x29, 0xff, 0x3a, 0xf4, + 0x7d, 0x21, 0xee, 0x43, 0x56, 0xfe, 0x4b, 0x1b, 0xf6, 0xf4, 0x78, 0xce, + 0xde, 0xdf, 0xae, 0x6d, 0xac, 0x83, 0x3d, 0x01, 0xac, 0x59, 0xc9, 0xa1, + 0x4d, 0xbb, 0xfc, 0x5b, 0x07, 0xd7, 0xc4, 0x9e, 0x78, 0x66, 0xec, 0x22, + 0xae, 0x75, 0x7f, 0xf3, 0x98, 0x87, 0x8e, 0x03, 0x5b, 0xf2, 0x28, 0x2c, + 0x88, 0xa0, 0xff, 0x01, 0x33, 0xd6, 0xc0, 0xf9, 0x50, 0x36, 0x40, 0xf7, + 0x6a, 0x16, 0xf8, 0xdd, 0x31, 0x7e, 0x2b, 0x75, 0x8c, 0xec, 0xe2, 0xf7, + 0x34, 0xc7, 0x5e, 0x63, 0x2a, 0x4e, 0x47, 0x2c, 0x47, 0xd9, 0x3a, 0x62, + 0x64, 0xeb, 0x33, 0x90, 0xad, 0xe3, 0x4a, 0xb6, 0x02, 0xf9, 0x81, 0xef, + 0xcb, 0x97, 0x77, 0x95, 0xaf, 0xd6, 0xbf, 0x2e, 0xd0, 0xcb, 0x5f, 0x9f, + 0x2c, 0xfc, 0x05, 0xc6, 0xbd, 0xe0, 0xe2, 0x3a, 0x95, 0x9b, 0x11, 0xf2, + 0x31, 0x81, 0xeb, 0x18, 0xca, 0x7e, 0x55, 0x67, 0xe0, 0x02, 0xec, 0x1a, + 0xe4, 0x8d, 0xfc, 0x9d, 0x87, 0x8d, 0x1b, 0xb8, 0x10, 0x85, 0x2d, 0xe4, + 0x9e, 0x95, 0x5e, 0x1b, 0xba, 0x81, 0xf5, 0xeb, 0xd8, 0x3b, 0x03, 0x17, + 0xba, 0x50, 0x26, 0x55, 0x5f, 0xf5, 0x8a, 0xa7, 0xda, 0xd7, 0x2b, 0xc3, + 0xaa, 0x5d, 0xbd, 0x32, 0x8a, 0x12, 0xfa, 0x3d, 0xe3, 0xcb, 0xd0, 0x85, + 0x8c, 0x24, 0x2f, 0x58, 0x52, 0x9a, 0x0e, 0x82, 0x18, 0x68, 0x1f, 0xbe, + 0xd0, 0x23, 0xd7, 0xa7, 0x39, 0x37, 0xea, 0x62, 0xb1, 0x16, 0x33, 0xd3, + 0xd8, 0x9b, 0xe4, 0x1f, 0xb0, 0xfe, 0x85, 0x22, 0x6c, 0x6e, 0x51, 0x4e, + 0xad, 0x90, 0x3f, 0x8c, 0xb5, 0x6f, 0x25, 0x22, 0x92, 0x82, 0x2e, 0x3b, + 0x2a, 0x73, 0xd5, 0x76, 0xe8, 0x32, 0xc7, 0xad, 0xcb, 0x13, 0x58, 0xa3, + 0x41, 0xca, 0x03, 0xf8, 0x92, 0x45, 0xdf, 0x45, 0x29, 0xa0, 0x4d, 0x71, + 0x65, 0xa7, 0x7e, 0x49, 0xda, 0xb1, 0xa7, 0x8e, 0xca, 0xb1, 0x2a, 0xfb, + 0x71, 0xdc, 0x79, 0x39, 0x00, 0x19, 0xf2, 0xdc, 0x09, 0xf4, 0x03, 0x1b, + 0xd9, 0xf4, 0xc7, 0xfd, 0x97, 0x7b, 0x0f, 0x99, 0x0c, 0xf7, 0x5d, 0xac, + 0xdc, 0x96, 0x9d, 0xb6, 0xb6, 0x32, 0xe2, 0xcc, 0x66, 0x1e, 0xb2, 0x5e, + 0xc9, 0x64, 0xac, 0x2b, 0x99, 0x9c, 0x75, 0x35, 0x53, 0xb4, 0xae, 0xc1, + 0x36, 0xd5, 0x37, 0xde, 0x81, 0xfc, 0x00, 0x4f, 0x10, 0x7b, 0x6f, 0xaf, + 0x61, 0xdc, 0xf8, 0x39, 0x6f, 0xc9, 0xb9, 0x0a, 0xed, 0x74, 0x70, 0x68, + 0xd6, 0x2f, 0xdf, 0x0e, 0xfa, 0x40, 0x07, 0xe3, 0x11, 0x3b, 0xb6, 0x23, + 0x9a, 0x1d, 0x06, 0x4e, 0xa0, 0xed, 0xe8, 0xa2, 0xed, 0xf0, 0x0b, 0xb2, + 0x57, 0xb6, 0xaa, 0x3a, 0x2e, 0x97, 0x07, 0x6e, 0xda, 0xaa, 0xc5, 0xe5, + 0xcb, 0xcb, 0xa1, 0x2c, 0x71, 0xbe, 0xf3, 0xef, 0xeb, 0x90, 0x88, 0x1c, + 0x51, 0xf6, 0xba, 0x5b, 0x2e, 0xaf, 0x03, 0xd3, 0x02, 0x81, 0xd8, 0x77, + 0x32, 0xce, 0x63, 0xab, 0xf8, 0x85, 0xf4, 0xf0, 0x3c, 0xf0, 0x1f, 0xc0, + 0x2b, 0x9e, 0xd9, 0x61, 0x9e, 0x3d, 0x9c, 0x51, 0x78, 0x3f, 0x8a, 0x3d, + 0xc9, 0x6b, 0x4b, 0x0a, 0xc0, 0xed, 0x5b, 0x15, 0x96, 0x09, 0x94, 0x26, + 0x56, 0x0f, 0x5d, 0x10, 0xc9, 0xfe, 0xa3, 0x7a, 0xdf, 0xee, 0x89, 0x35, + 0x0b, 0x3b, 0x5c, 0x5a, 0xa1, 0x4c, 0xa3, 0x5c, 0xd7, 0x63, 0x17, 0x7c, + 0x60, 0xe6, 0xd1, 0x0e, 0xda, 0x37, 0xe0, 0x27, 0xec, 0x7b, 0x85, 0xed, + 0x33, 0xd8, 0x73, 0x3f, 0x68, 0xa7, 0x6d, 0x3f, 0xec, 0x8f, 0xcb, 0xb5, + 0x0a, 0xaf, 0xf9, 0x3e, 0xe5, 0x8b, 0x8a, 0x1b, 0xc7, 0xa6, 0x16, 0x3d, + 0xdf, 0xec, 0x31, 0x15, 0xd3, 0xb1, 0x3e, 0x06, 0xcc, 0x38, 0x70, 0xa6, + 0x4d, 0xd2, 0x4f, 0xdb, 0x7d, 0xfa, 0x7c, 0xe5, 0x90, 0x14, 0xfd, 0x03, + 0x98, 0xc3, 0x3e, 0x99, 0x87, 0x2f, 0xb6, 0xb0, 0x31, 0x2c, 0xf3, 0xc3, + 0xf0, 0xb9, 0xdd, 0xbb, 0x89, 0xd5, 0xf0, 0xeb, 0xc0, 0xf3, 0x41, 0x94, + 0xed, 0x28, 0x6f, 0x97, 0xf9, 0xa7, 0xba, 0x63, 0xba, 0xbf, 0x68, 0xcb, + 0xfd, 0xb3, 0x1c, 0x3b, 0x99, 0xb4, 0x7e, 0x15, 0x2e, 0x6c, 0xc6, 0x84, + 0xa4, 0x23, 0x2a, 0xde, 0x93, 0x5d, 0x32, 0x78, 0xc6, 0x95, 0xa1, 0x33, + 0x09, 0x39, 0x70, 0xa6, 0x5f, 0x86, 0xcf, 0x24, 0xe5, 0xce, 0x33, 0x21, + 0xfe, 0xea, 0x9e, 0x4a, 0x1b, 0x5b, 0xe1, 0xfd, 0x9a, 0xb6, 0xe2, 0xce, + 0x86, 0xc6, 0xa8, 0xf3, 0x6b, 0xc4, 0x74, 0xaf, 0x62, 0xef, 0x6e, 0xaa, + 0xf3, 0xca, 0x4b, 0x1b, 0x41, 0x70, 0xc9, 0x6f, 0x77, 0xa7, 0x85, 0xfc, + 0xce, 0x00, 0x9f, 0xf9, 0xd0, 0x61, 0xa3, 0xd0, 0x61, 0xe3, 0xca, 0x36, + 0xd6, 0xbf, 0x2e, 0xd6, 0xb1, 0xcc, 0x03, 0xb2, 0x06, 0xd9, 0x7e, 0xd0, + 0x4f, 0x7d, 0x75, 0x53, 0xf1, 0x47, 0x62, 0x3d, 0xd0, 0x67, 0x77, 0xaf, + 0xb6, 0xcb, 0x1b, 0xf1, 0x20, 0x38, 0x0b, 0x1d, 0x50, 0xaf, 0x68, 0xf9, + 0xcd, 0x7b, 0xd4, 0x05, 0x0f, 0x61, 0xfe, 0xa3, 0x78, 0x96, 0x33, 0xba, + 0xbd, 0x43, 0x6e, 0xc4, 0x13, 0xb2, 0x7e, 0x60, 0xbc, 0xa5, 0x5e, 0x06, + 0xf7, 0xc0, 0x3d, 0x8d, 0xdf, 0x23, 0xbf, 0xf0, 0xdc, 0x95, 0x73, 0xf0, + 0x99, 0xcf, 0x1f, 0x48, 0x8d, 0x27, 0x6d, 0xea, 0xc3, 0xa4, 0xd4, 0xbe, + 0x9e, 0x90, 0xb5, 0x65, 0x6d, 0x97, 0x66, 0xbd, 0x71, 0x29, 0x00, 0xfb, + 0xae, 0x2d, 0x67, 0x51, 0xb2, 0x7e, 0xa8, 0x73, 0xb4, 0x5c, 0x16, 0x33, + 0x79, 0xec, 0x63, 0xee, 0x0f, 0x6d, 0x77, 0x6c, 0xbb, 0x1d, 0x72, 0xc4, + 0x3d, 0xf1, 0x30, 0x9e, 0xe7, 0xb1, 0xaf, 0x69, 0xc7, 0xd3, 0x90, 0xaf, + 0xcf, 0xc6, 0x28, 0x1f, 0x05, 0x9f, 0xf8, 0x9a, 0x6d, 0x52, 0x89, 0x34, + 0x9e, 0x4f, 0x4b, 0x5a, 0x9d, 0x0b, 0xcd, 0xfa, 0x61, 0x7f, 0x59, 0xa3, + 0x17, 0x22, 0x8c, 0x81, 0xe1, 0xef, 0x64, 0x8c, 0xf2, 0x18, 0xf1, 0xc2, + 0xe7, 0x23, 0xb0, 0x3d, 0x51, 0x35, 0xc6, 0xfc, 0x32, 0x9f, 0xa5, 0x5d, + 0xb6, 0x2f, 0xf8, 0xbc, 0x17, 0xf9, 0x44, 0x83, 0xf1, 0x9a, 0x98, 0x3c, + 0xda, 0xe8, 0x02, 0xbd, 0x6d, 0xbf, 0xc2, 0xf6, 0xec, 0xec, 0x73, 0x3b, + 0xbb, 0x95, 0x70, 0x95, 0x6e, 0xa1, 0x1e, 0xa1, 0x0e, 0x69, 0x17, 0x67, + 0x8c, 0xfb, 0x0c, 0x6b, 0xb2, 0x8c, 0x35, 0x5a, 0xc6, 0x1a, 0x2d, 0x63, + 0x8d, 0x96, 0xb1, 0x7e, 0xcb, 0xd4, 0x2d, 0x83, 0xd8, 0xcf, 0x39, 0x73, + 0x86, 0x40, 0xfd, 0xf2, 0x1c, 0xd6, 0x76, 0x5a, 0xfe, 0x76, 0x63, 0x52, + 0xfe, 0xf3, 0xc6, 0x11, 0xe0, 0xee, 0x22, 0xd6, 0x35, 0x87, 0x75, 0xcd, + 0x62, 0x5d, 0x8f, 0x62, 0x5d, 0xc7, 0x55, 0xcc, 0xb3, 0x5a, 0x49, 0x5d, + 0x2a, 0x2b, 0x8c, 0xff, 0x16, 0xe4, 0x61, 0x4c, 0x9c, 0xd5, 0x7e, 0xe8, + 0x8b, 0x72, 0x10, 0xf7, 0x82, 0x43, 0xc0, 0xd6, 0x18, 0xbb, 0x9c, 0x72, + 0x94, 0xee, 0xf3, 0xdc, 0xcf, 0x63, 0xaf, 0xbc, 0x2f, 0x9b, 0xaa, 0x52, + 0x75, 0x9d, 0xab, 0x0e, 0x4b, 0xe9, 0x22, 0xea, 0x9f, 0xed, 0x02, 0xad, + 0xc4, 0x7c, 0xa9, 0xd3, 0x25, 0xd9, 0x84, 0xbe, 0xcb, 0x81, 0xc6, 0x0f, + 0xc9, 0x7c, 0x3c, 0xf5, 0x9c, 0xc8, 0xb8, 0xdc, 0x03, 0x3f, 0x9d, 0xf1, + 0xcc, 0x9c, 0x8a, 0xb1, 0xe1, 0xfa, 0x62, 0x16, 0xfe, 0x36, 0x6d, 0xec, + 0x3e, 0xe3, 0x87, 0x6b, 0x1c, 0x5b, 0x13, 0x8e, 0xcb, 0xf1, 0xfe, 0x58, + 0xe6, 0x80, 0x15, 0xe1, 0xeb, 0x03, 0x8b, 0x78, 0x09, 0x8c, 0x19, 0x9b, + 0xbd, 0xe8, 0xc6, 0xe6, 0x2e, 0xb2, 0x9f, 0x98, 0x44, 0x96, 0xa8, 0xb3, + 0xd8, 0x0f, 0x74, 0x3b, 0xfa, 0x4e, 0xab, 0x33, 0xb3, 0x11, 0xb4, 0xfb, + 0x5d, 0xe0, 0x4c, 0xcd, 0xc7, 0xfc, 0x59, 0x6d, 0xf7, 0xf2, 0xf5, 0x66, + 0xac, 0x07, 0xdd, 0x02, 0xbb, 0x98, 0xab, 0x6b, 0xdc, 0x56, 0x54, 0xb8, + 0x4e, 0x63, 0xba, 0xa3, 0x72, 0xa8, 0x43, 0x3a, 0x3d, 0x35, 0x9f, 0xc8, + 0xd9, 0x4d, 0xe2, 0x58, 0x8c, 0xc1, 0x36, 0xd1, 0x26, 0xba, 0x33, 0xb0, + 0xa7, 0xb7, 0x77, 0x50, 0x66, 0x3e, 0x09, 0xdc, 0x38, 0xb0, 0xa4, 0xcf, + 0x98, 0x06, 0x2e, 0xfa, 0x98, 0x8f, 0xf4, 0x31, 0xb2, 0x69, 0x63, 0x0e, + 0x1f, 0x55, 0x76, 0x79, 0x0c, 0xb6, 0xd8, 0x85, 0xac, 0x53, 0xe7, 0xf4, + 0x61, 0xff, 0xf0, 0x9e, 0xba, 0x87, 0x7a, 0x8c, 0x32, 0x13, 0x07, 0x6e, + 0x82, 0xfe, 0xe9, 0xee, 0x97, 0xda, 0x06, 0xdf, 0xf5, 0x2b, 0x1d, 0xed, + 0x60, 0x0d, 0x16, 0x2b, 0xc1, 0xa1, 0xbc, 0x5f, 0x86, 0x16, 0x25, 0xcf, + 0xc9, 0x0f, 0xf2, 0x7d, 0x14, 0xb4, 0x91, 0xc7, 0xdd, 0x65, 0x7d, 0x6e, + 0xb9, 0x57, 0x4a, 0x55, 0xea, 0x69, 0x94, 0xb5, 0xbd, 0xf0, 0x9d, 0x5c, + 0x85, 0x65, 0x73, 0xd3, 0x9c, 0x7b, 0xac, 0xec, 0x42, 0x6e, 0xdd, 0x83, + 0x93, 0x2a, 0xa6, 0x72, 0x79, 0x29, 0xe5, 0xd7, 0x6c, 0x8c, 0x09, 0x9d, + 0x69, 0x9f, 0x1f, 0x93, 0xb9, 0x95, 0x6e, 0x19, 0x5c, 0xe5, 0xf9, 0xf2, + 0x50, 0x4c, 0xba, 0x83, 0xe0, 0x9c, 0x9f, 0x57, 0xb1, 0xc7, 0x81, 0x55, + 0x60, 0x82, 0xa3, 0x9a, 0x77, 0x9c, 0x2f, 0x74, 0xc4, 0xbf, 0x82, 0x8f, + 0xef, 0x8e, 0x8f, 0x8b, 0xbb, 0xe0, 0xe3, 0x57, 0x2f, 0x42, 0xfe, 0x96, + 0x21, 0x9b, 0xcb, 0x90, 0xcd, 0x65, 0xc8, 0xe6, 0x32, 0x64, 0x73, 0x19, + 0xb2, 0x89, 0xfd, 0xf3, 0xfc, 0xf2, 0xb8, 0xc1, 0x1f, 0x9f, 0x82, 0x2c, + 0x7f, 0xdb, 0xe0, 0x8f, 0x51, 0xc8, 0x70, 0x12, 0xb2, 0xeb, 0x43, 0x6e, + 0x87, 0x21, 0xcb, 0x1e, 0x64, 0xb9, 0x1f, 0x72, 0x9c, 0x50, 0xfe, 0xe3, + 0x04, 0xb0, 0xe8, 0x83, 0xf0, 0x41, 0xce, 0x57, 0xfb, 0x65, 0x51, 0xd1, + 0x12, 0xc8, 0x96, 0xbf, 0x49, 0x1e, 0x62, 0x5f, 0xd0, 0x3f, 0x77, 0xe5, + 0xfc, 0x5a, 0x48, 0xdb, 0xab, 0xf2, 0xcd, 0xca, 0x6b, 0xf2, 0x42, 0x85, + 0x34, 0xe6, 0x64, 0x11, 0xef, 0xd6, 0x9e, 0xa2, 0x1f, 0xa9, 0xe8, 0x83, + 0xcc, 0x9d, 0x94, 0xff, 0x03, 0x5e, 0xae, 0x6f, 0x7c, 0x58, 0x3e, 0xe7, + 0x52, 0x86, 0xe3, 0xd0, 0x35, 0xb8, 0x3f, 0x40, 0xbd, 0x04, 0x3f, 0xb4, + 0x92, 0x2a, 0x97, 0xa0, 0x27, 0xaa, 0xf6, 0x08, 0x30, 0x58, 0x39, 0xe8, + 0xa1, 0x0e, 0xab, 0x7a, 0xee, 0x80, 0x4d, 0xde, 0xec, 0x87, 0xbc, 0xa4, + 0xbe, 0x0a, 0xe1, 0xc5, 0x33, 0xda, 0x73, 0x94, 0x35, 0xe8, 0xcf, 0xa7, + 0xc8, 0x47, 0xfa, 0xb5, 0xb8, 0x56, 0xba, 0xf7, 0x27, 0x2a, 0x7e, 0x5c, + 0x9a, 0x86, 0x2f, 0xbf, 0x46, 0x3e, 0x41, 0x56, 0x9e, 0x22, 0x1f, 0x49, + 0x9f, 0xe6, 0xe3, 0x23, 0x12, 0xf2, 0x90, 0xef, 0x5a, 0x79, 0x08, 0x27, + 0xaa, 0x33, 0x8e, 0xb9, 0x7f, 0x2d, 0x66, 0x62, 0xc8, 0xc6, 0x26, 0xbf, + 0x2a, 0xd3, 0x0d, 0xce, 0xc7, 0x92, 0xdb, 0xbc, 0xab, 0xf0, 0xa9, 0x38, + 0xf6, 0xab, 0xc1, 0xa3, 0x71, 0xce, 0x81, 0xeb, 0xba, 0x47, 0xea, 0x7d, + 0xbe, 0x89, 0xaf, 0xfc, 0x2a, 0x5b, 0xc4, 0x7a, 0xe0, 0x3b, 0xf4, 0xcb, + 0x0b, 0xcb, 0xe0, 0x37, 0xfc, 0xae, 0x6f, 0xc0, 0xef, 0x62, 0x9c, 0x53, + 0xaf, 0xcf, 0xb8, 0x89, 0xd9, 0xb6, 0xc6, 0x6a, 0x93, 0x58, 0x23, 0xfa, + 0xed, 0xa9, 0xf2, 0x75, 0xe8, 0xc1, 0xe7, 0x7d, 0xc6, 0xf8, 0x02, 0xf9, + 0xef, 0x7e, 0xb3, 0xa6, 0x53, 0xf1, 0x6d, 0x79, 0x04, 0xba, 0xf1, 0x51, + 0xe8, 0xc6, 0x4f, 0xdc, 0x92, 0xe7, 0x43, 0x79, 0xbb, 0x7f, 0x6a, 0x76, + 0x65, 0xb0, 0x1c, 0xb1, 0xfb, 0x31, 0xa7, 0xe6, 0xb6, 0x8c, 0xf1, 0x25, + 0x4d, 0x2c, 0xb6, 0x19, 0xb3, 0x86, 0xf1, 0x56, 0xca, 0x74, 0x20, 0xd7, + 0xfc, 0x72, 0x57, 0x44, 0x9d, 0x3f, 0x7b, 0xb4, 0x13, 0xbb, 0xfc, 0xbd, + 0xd8, 0xa1, 0xed, 0xf3, 0x5b, 0x46, 0xc6, 0x76, 0x72, 0x99, 0x26, 0x32, + 0xe1, 0x99, 0x73, 0x37, 0x6c, 0x1e, 0xf7, 0x6d, 0x2a, 0x99, 0xc3, 0xde, + 0x9e, 0xdf, 0xa0, 0x5d, 0x20, 0x9e, 0x6c, 0x63, 0x4c, 0x6f, 0xa6, 0x3d, + 0xcb, 0xd8, 0x41, 0x37, 0xfc, 0x97, 0xd7, 0xe5, 0xdc, 0xca, 0x3f, 0x75, + 0xe8, 0xfd, 0xa4, 0x73, 0xcf, 0xec, 0x8b, 0xad, 0x71, 0x54, 0xbd, 0x46, + 0x85, 0x4c, 0x37, 0x30, 0x0c, 0xfd, 0xa5, 0x6b, 0xca, 0x5f, 0x3a, 0xec, + 0x3b, 0xb2, 0x19, 0x67, 0x9f, 0xaf, 0xcb, 0xb1, 0x95, 0xe1, 0x4e, 0xc6, + 0x2b, 0x17, 0x97, 0x0f, 0xc8, 0x96, 0xd2, 0x65, 0x0f, 0xa3, 0x6e, 0x16, + 0x7b, 0x36, 0x08, 0x26, 0xfc, 0xb4, 0x7b, 0x5e, 0x46, 0x12, 0xe7, 0xc1, + 0xd3, 0x3f, 0x43, 0x1b, 0xf8, 0xd4, 0x41, 0x11, 0xcf, 0xae, 0xc2, 0x6f, + 0xbf, 0x21, 0xbc, 0x1e, 0x71, 0x4f, 0x43, 0x18, 0x72, 0x6e, 0xda, 0x7d, + 0x4b, 0x42, 0xdb, 0x45, 0x3b, 0xc5, 0x33, 0xeb, 0x3e, 0x29, 0xac, 0x6b, + 0x5a, 0xe7, 0x41, 0xeb, 0xa9, 0x15, 0x8e, 0xc1, 0x79, 0x91, 0xde, 0x7f, + 0xe2, 0x19, 0x07, 0xe6, 0xf2, 0x41, 0x60, 0x59, 0xe2, 0x28, 0x1d, 0x8b, + 0x28, 0xa0, 0x8d, 0xc2, 0x5a, 0x3e, 0xcf, 0x2b, 0xc9, 0xc7, 0x2f, 0xc2, + 0x6f, 0x88, 0x43, 0x8e, 0xf1, 0x7c, 0xbd, 0x39, 0xe6, 0xcb, 0xfa, 0xfa, + 0x1c, 0xed, 0x92, 0xf2, 0x11, 0xf2, 0xc0, 0x85, 0x93, 0xa8, 0xcb, 0x78, + 0x67, 0x10, 0x1c, 0xf7, 0xe1, 0xc7, 0x3f, 0x45, 0xd9, 0xbb, 0x53, 0x4a, + 0xca, 0xe7, 0x20, 0x86, 0x65, 0xfe, 0xc6, 0x96, 0x1b, 0xc3, 0xfe, 0x9c, + 0x86, 0x6d, 0xcb, 0xc3, 0xb6, 0x45, 0xee, 0x3e, 0x02, 0x3c, 0xab, 0xce, + 0xd9, 0x60, 0x3f, 0x39, 0xee, 0xc3, 0xd6, 0xdf, 0x67, 0x46, 0x81, 0x6f, + 0x1f, 0x00, 0xbe, 0x65, 0x1e, 0x59, 0x1e, 0x18, 0x97, 0xf8, 0xd6, 0x95, + 0xbf, 0xda, 0xc8, 0x43, 0xb7, 0x4d, 0x74, 0x52, 0x17, 0x1f, 0xd9, 0xb6, + 0xd3, 0x45, 0x63, 0xc7, 0xf7, 0x49, 0x41, 0x9d, 0xbb, 0x15, 0x95, 0xbd, + 0x9f, 0x5f, 0x27, 0xae, 0x87, 0xed, 0x5f, 0x87, 0xef, 0x57, 0xa1, 0x8f, + 0x96, 0xc3, 0xfd, 0x03, 0xb8, 0x7f, 0x08, 0xe5, 0x11, 0x94, 0xda, 0xf7, + 0xb9, 0xb4, 0x1c, 0xe9, 0xd4, 0x31, 0xde, 0x44, 0x93, 0xff, 0x43, 0x39, + 0x8c, 0x4f, 0xcd, 0x56, 0xc3, 0x38, 0xfd, 0x21, 0x39, 0xee, 0xeb, 0xb3, + 0xf5, 0x09, 0xf8, 0xeb, 0x9d, 0xc0, 0x60, 0x0f, 0x3d, 0x0d, 0x9b, 0x71, + 0xdf, 0x21, 0xb1, 0xef, 0xb3, 0x64, 0x76, 0x14, 0x74, 0x8f, 0x0e, 0x42, + 0x3f, 0xf7, 0xc3, 0xdf, 0x56, 0x7e, 0xb0, 0xc1, 0x9c, 0xd4, 0xfb, 0x71, + 0xf9, 0xf3, 0x8d, 0x10, 0x7b, 0xb6, 0x01, 0xa7, 0x32, 0x56, 0x98, 0x54, + 0xb8, 0xd9, 0xbe, 0x8d, 0xeb, 0xdf, 0x25, 0xf9, 0xdb, 0xc8, 0x53, 0x3e, + 0x03, 0xa6, 0x51, 0xd7, 0x71, 0x49, 0x9f, 0xe1, 0xba, 0xb5, 0x9b, 0x18, + 0x2f, 0x6d, 0x06, 0xcb, 0xbf, 0xec, 0xdc, 0xc6, 0x96, 0x8c, 0x01, 0x59, + 0xe3, 0x9d, 0x3b, 0x79, 0x69, 0xa1, 0xdc, 0x87, 0xf9, 0x04, 0x94, 0xff, + 0x4b, 0xa0, 0x9f, 0xf6, 0x9e, 0xb6, 0xc1, 0xb5, 0xa2, 0x07, 0x89, 0x05, + 0x22, 0xd2, 0xe6, 0x71, 0x9f, 0xd2, 0x4e, 0x1d, 0xc1, 0x9c, 0x88, 0x0d, + 0x3e, 0xdf, 0x2d, 0xdd, 0xc4, 0x07, 0x49, 0x3c, 0xbb, 0x8e, 0x7a, 0xbc, + 0x67, 0x3d, 0xf8, 0x52, 0xcb, 0x62, 0x45, 0x0e, 0xce, 0x41, 0xae, 0x3d, + 0x5c, 0x1f, 0x47, 0x39, 0x8c, 0xf2, 0x71, 0x94, 0xd4, 0x4f, 0x57, 0x65, + 0x56, 0xc7, 0x7f, 0x14, 0x0e, 0xa1, 0xed, 0x9c, 0xf6, 0xa9, 0x53, 0x4f, + 0x8a, 0x3d, 0xf6, 0x41, 0x3c, 0xa3, 0x1f, 0x8f, 0x91, 0xee, 0xff, 0x82, + 0x89, 0x3f, 0x6d, 0xc7, 0xac, 0x8c, 0x4e, 0x5e, 0x51, 0x31, 0xfc, 0xf5, + 0xa7, 0xe8, 0x23, 0xff, 0x54, 0x1e, 0xbd, 0x29, 0xb6, 0xb7, 0x1d, 0xcb, + 0x1a, 0x2f, 0x28, 0x5d, 0x4c, 0x7e, 0x40, 0x0f, 0xbb, 0x19, 0xf9, 0xfa, + 0x46, 0x0f, 0xf4, 0x5b, 0x5c, 0xde, 0x58, 0x09, 0x80, 0xd5, 0xb9, 0x37, + 0x47, 0x60, 0x33, 0x5d, 0x83, 0x03, 0xe2, 0xf2, 0x2f, 0x90, 0xf3, 0x7f, + 0xae, 0x24, 0xe4, 0xcd, 0x4a, 0x10, 0x5c, 0xf3, 0xd3, 0xfe, 0x61, 0x91, + 0xbb, 0xdb, 0x74, 0x0e, 0x00, 0x6a, 0xe8, 0x73, 0xfb, 0x79, 0x75, 0x76, + 0x8f, 0x7a, 0xd0, 0x3b, 0x6f, 0x36, 0x7e, 0x01, 0xbe, 0xea, 0x3e, 0x5b, + 0xdb, 0x6e, 0xe9, 0xb6, 0x3c, 0xfb, 0x4f, 0x6c, 0x4a, 0xda, 0xe4, 0x10, + 0xa4, 0xd1, 0x36, 0x3d, 0xbc, 0xb6, 0xdd, 0x9e, 0x6d, 0x33, 0xca, 0x5e, + 0x94, 0xd6, 0x7b, 0xa5, 0xfe, 0x17, 0xdc, 0x2b, 0xf0, 0x63, 0xd5, 0x99, + 0x11, 0x4b, 0x9e, 0x55, 0xb0, 0x4e, 0xd2, 0xbc, 0x1f, 0x30, 0xef, 0x3d, + 0x85, 0x5f, 0x9d, 0xed, 0x18, 0x20, 0x7c, 0xdb, 0xe5, 0xd4, 0x69, 0x65, + 0x47, 0x18, 0xb7, 0x5d, 0xa6, 0x7f, 0x4f, 0x5d, 0x3e, 0x69, 0xec, 0x09, + 0x7c, 0x8f, 0xda, 0x71, 0x99, 0x51, 0xd7, 0x9f, 0x90, 0x47, 0x5c, 0xf2, + 0xee, 0xa4, 0xf8, 0x63, 0x1a, 0x4b, 0x89, 0x89, 0x09, 0x76, 0x78, 0x27, + 0xe1, 0x9b, 0x29, 0x7b, 0xec, 0x7e, 0x4c, 0xc8, 0xe3, 0x36, 0xda, 0x8f, + 0x9c, 0x6d, 0x01, 0x83, 0x3d, 0x99, 0x91, 0xe7, 0x36, 0x50, 0x17, 0xeb, + 0xf5, 0x31, 0xc1, 0xfd, 0xb3, 0xb8, 0x67, 0x1c, 0xed, 0xe9, 0xb8, 0x44, + 0x9e, 0xee, 0x97, 0xf6, 0x33, 0xc4, 0x29, 0xe4, 0x69, 0x42, 0xda, 0xce, + 0x10, 0x2f, 0x33, 0xb6, 0x9c, 0x1a, 0xbf, 0x21, 0x8c, 0xe5, 0xa4, 0xfc, + 0x2b, 0xf8, 0x6d, 0x61, 0xde, 0xed, 0xf0, 0xc3, 0xdb, 0x2e, 0xe8, 0x76, + 0xf6, 0xb9, 0x3e, 0x00, 0xc3, 0x98, 0xd8, 0xf0, 0x59, 0xec, 0x0b, 0x2c, + 0xbb, 0x50, 0xf2, 0x1d, 0x48, 0x3a, 0x37, 0x60, 0xde, 0x41, 0x37, 0x5e, + 0xe0, 0xf8, 0xb0, 0x8f, 0xbe, 0xce, 0x17, 0x1d, 0x18, 0xf2, 0xe5, 0xd2, + 0x1a, 0x65, 0x93, 0x71, 0x74, 0x62, 0x97, 0x57, 0xc5, 0x5e, 0xca, 0x48, + 0xe4, 0x4c, 0x06, 0x72, 0xe8, 0xc3, 0xee, 0x12, 0xf3, 0xd1, 0xd6, 0xe1, + 0x39, 0xf0, 0x56, 0xfd, 0x29, 0xce, 0xe9, 0xaa, 0xd8, 0xf5, 0x5f, 0x65, + 0xc3, 0xc2, 0x7d, 0xc1, 0x31, 0x4e, 0xc2, 0xfe, 0x46, 0xe5, 0x73, 0x71, + 0xca, 0x8a, 0x96, 0xbd, 0xb4, 0x3d, 0xa4, 0x64, 0xb5, 0x48, 0xbb, 0xfc, + 0xd4, 0xed, 0x7b, 0xe0, 0xa7, 0x9d, 0x2e, 0x6f, 0xcb, 0x18, 0xf3, 0x42, + 0x03, 0xa9, 0x02, 0xef, 0xcc, 0x7b, 0x96, 0x2c, 0x78, 0x27, 0x15, 0x1e, + 0x7c, 0x14, 0xed, 0x4f, 0x98, 0xf6, 0x0b, 0x32, 0x64, 0x64, 0x5d, 0xc5, + 0x11, 0xa0, 0xc7, 0xb8, 0x66, 0xbc, 0xff, 0x2d, 0xf1, 0x7b, 0xb9, 0x9e, + 0x27, 0x65, 0x60, 0x4c, 0xe3, 0x90, 0x92, 0x4d, 0x1c, 0xf2, 0xae, 0x71, + 0x5a, 0x95, 0xcb, 0x57, 0xa8, 0xd0, 0xce, 0xec, 0x85, 0xfc, 0xc2, 0x27, + 0xda, 0x08, 0x63, 0xb5, 0x6a, 0x5f, 0x25, 0x06, 0x6c, 0x4b, 0xbc, 0xa1, + 0xa1, 0xe1, 0x12, 0xf0, 0xc9, 0x3c, 0x7c, 0x5e, 0xd2, 0xb1, 0x00, 0x3b, + 0xb7, 0xe6, 0xff, 0x4b, 0x70, 0x22, 0x9e, 0x3a, 0x3d, 0xf3, 0xae, 0xf1, + 0xfb, 0x30, 0x6e, 0xdf, 0x7c, 0x9e, 0xb2, 0x69, 0xfd, 0x61, 0xe3, 0x88, + 0xd2, 0x91, 0x37, 0xe3, 0xae, 0x30, 0x7e, 0x3f, 0x7d, 0x53, 0x1c, 0xb5, + 0xd4, 0x08, 0x73, 0xf0, 0x42, 0x3d, 0x7f, 0x1a, 0xba, 0x3a, 0x22, 0x37, + 0x80, 0x41, 0x27, 0xc0, 0xbb, 0x73, 0x6b, 0x65, 0xeb, 0x4a, 0x45, 0xd4, + 0x7d, 0xc1, 0x67, 0x4e, 0xde, 0x47, 0xc0, 0x3b, 0xd8, 0x98, 0x0d, 0xc7, + 0x9c, 0x29, 0x39, 0x78, 0x66, 0x2b, 0x9f, 0xb9, 0xa4, 0x74, 0xf3, 0xe1, + 0x2e, 0x9e, 0xb9, 0x5c, 0x5a, 0xfe, 0x28, 0xee, 0x79, 0xf6, 0x71, 0xa4, + 0xe5, 0xf9, 0x66, 0x4f, 0x54, 0x63, 0x37, 0xf0, 0x5d, 0xf3, 0xcd, 0x01, + 0xbf, 0x8b, 0x8c, 0xe7, 0x35, 0x88, 0x83, 0x3b, 0x0d, 0x0e, 0x26, 0xce, + 0xc2, 0x7a, 0x6d, 0x30, 0x0e, 0x43, 0xac, 0x15, 0x57, 0x7e, 0xa1, 0xc2, + 0x5e, 0xfe, 0x31, 0x93, 0x7f, 0x71, 0xab, 0x5c, 0xcd, 0x56, 0x42, 0x3c, + 0xd7, 0x2c, 0x57, 0xee, 0x6f, 0x20, 0x57, 0x13, 0x5d, 0x3a, 0xdf, 0x81, + 0x36, 0xcd, 0x92, 0x37, 0xaa, 0x7b, 0x64, 0xab, 0xfa, 0x20, 0x70, 0xb4, + 0xca, 0xfb, 0x90, 0x2d, 0xac, 0xc5, 0x83, 0x95, 0x49, 0x99, 0xa8, 0xc6, + 0xe4, 0x5a, 0xd5, 0x7e, 0xa0, 0x5d, 0x18, 0x07, 0x27, 0x36, 0xf9, 0x1b, + 0xa5, 0xdf, 0x7e, 0xe0, 0xef, 0xb4, 0xe7, 0xb9, 0xca, 0x0d, 0xb4, 0x9f, + 0xad, 0xde, 0x2b, 0x25, 0xd5, 0xbe, 0x7e, 0xcb, 0x18, 0x51, 0x33, 0x46, + 0xbd, 0x7a, 0x97, 0x89, 0xdf, 0x95, 0xe5, 0x12, 0xb0, 0xaf, 0x7d, 0x96, + 0xf3, 0xbd, 0xc3, 0xe4, 0x77, 0xc5, 0x9a, 0xfc, 0x91, 0xa8, 0xf1, 0x47, + 0x7e, 0x06, 0x3d, 0xfe, 0x94, 0x44, 0xbd, 0xb0, 0x2f, 0xe6, 0x6a, 0x27, + 0x4c, 0x6e, 0xc7, 0x5e, 0xf4, 0x75, 0x10, 0xef, 0xee, 0xc3, 0xef, 0x49, + 0xd4, 0xa3, 0xbd, 0xe2, 0xd9, 0x28, 0x31, 0x02, 0xcf, 0xeb, 0x7a, 0x51, + 0xaf, 0x03, 0x58, 0x72, 0xbf, 0x79, 0x16, 0xf6, 0x11, 0xd6, 0x0d, 0xef, + 0x9b, 0xcf, 0x53, 0x59, 0x2f, 0xd9, 0x74, 0x9e, 0x0a, 0x45, 0xa5, 0xda, + 0x86, 0xb6, 0x36, 0xb4, 0x51, 0xc9, 0x26, 0x1b, 0xf5, 0x56, 0x53, 0x9e, + 0xa7, 0xc6, 0x61, 0x57, 0x33, 0x9c, 0x6b, 0x5f, 0x53, 0x0e, 0x4a, 0xaa, + 0x4c, 0xfb, 0xc8, 0x78, 0xdf, 0x7a, 0x25, 0xb4, 0x1f, 0xb9, 0x1e, 0x9e, + 0x5b, 0x2c, 0xfa, 0x2a, 0x16, 0x97, 0x8c, 0x64, 0x69, 0x7f, 0xfc, 0xd8, + 0x16, 0x70, 0x65, 0x5d, 0x9d, 0xeb, 0x47, 0xf0, 0x83, 0x5d, 0x76, 0x2c, + 0x71, 0x3d, 0x3e, 0x2b, 0x1b, 0xbd, 0x03, 0x5d, 0x6e, 0xab, 0x3a, 0xc9, + 0xbc, 0xdf, 0x67, 0xee, 0x13, 0xb2, 0x56, 0xf9, 0x50, 0xbf, 0x9d, 0xfd, + 0x5f, 0xb7, 0xe7, 0x33, 0x3d, 0x3c, 0x7f, 0xc2, 0x33, 0xe2, 0xf5, 0xd7, + 0x54, 0x4e, 0xa3, 0xc6, 0x46, 0x0e, 0xcf, 0x2f, 0x81, 0x73, 0x7e, 0x04, + 0x9e, 0x84, 0xb8, 0xfb, 0x75, 0x99, 0x50, 0x98, 0xaa, 0x0d, 0xb6, 0xd2, + 0x60, 0xaa, 0xee, 0x14, 0x30, 0x15, 0xdb, 0xb7, 0xe2, 0x40, 0xbd, 0x97, + 0x22, 0x59, 0x1d, 0x57, 0x6d, 0x89, 0x15, 0x5b, 0x8f, 0x64, 0xc4, 0x3a, + 0x81, 0x1f, 0x65, 0xd4, 0x5e, 0x7a, 0x4d, 0xbc, 0xa5, 0x54, 0x95, 0xf9, + 0xb1, 0x0b, 0x1b, 0x3c, 0xc7, 0x03, 0x16, 0x4b, 0x50, 0x96, 0xf9, 0x6e, + 0x1a, 0x63, 0xbc, 0x06, 0xff, 0x73, 0x0f, 0xf8, 0x6d, 0x1b, 0x1e, 0xf9, + 0x26, 0x46, 0x11, 0x63, 0x2c, 0x18, 0x7b, 0x71, 0x5e, 0x61, 0x89, 0x52, + 0x7c, 0x11, 0xe5, 0x0f, 0x0d, 0x76, 0x78, 0xbd, 0x2b, 0x3c, 0xb7, 0x2f, + 0xc5, 0xbf, 0x84, 0xe7, 0xaf, 0xc3, 0x1f, 0x8c, 0x4a, 0x9b, 0x5a, 0xb3, + 0x10, 0x3b, 0xff, 0x3d, 0xea, 0x90, 0xfe, 0x3b, 0x4d, 0x7e, 0x0d, 0xf3, + 0x06, 0xd8, 0x1f, 0xec, 0x96, 0xca, 0xe1, 0xca, 0xa1, 0x64, 0x3b, 0xb6, + 0x79, 0x05, 0x75, 0x73, 0x98, 0x37, 0x9f, 0x4b, 0x5f, 0x44, 0x9a, 0x9f, + 0x7f, 0x14, 0xcf, 0x29, 0x87, 0xef, 0x37, 0x72, 0x18, 0xbe, 0xcb, 0x1b, + 0x3e, 0xdd, 0x8e, 0x31, 0xc8, 0xab, 0x66, 0xba, 0x38, 0x9f, 0x70, 0xcd, + 0xdb, 0x4c, 0xae, 0x01, 0x9f, 0xbd, 0xdf, 0x3c, 0x73, 0xcc, 0x1c, 0x3f, + 0xde, 0x65, 0xb0, 0x04, 0x76, 0x7b, 0xb8, 0x1f, 0x49, 0x67, 0xac, 0x09, + 0xb3, 0xfe, 0x61, 0xef, 0x4e, 0x1e, 0x26, 0x65, 0xce, 0x53, 0xb1, 0x23, + 0xe6, 0x8f, 0xe5, 0x6c, 0x9d, 0xb3, 0xf1, 0x8d, 0x9b, 0xe2, 0xdd, 0x4a, + 0xd7, 0xf2, 0x0c, 0xa4, 0x6a, 0x67, 0xdb, 0x7f, 0xed, 0xbc, 0xbb, 0x48, + 0x36, 0x6c, 0x07, 0x9c, 0xa6, 0xda, 0x24, 0x65, 0xae, 0xf1, 0x6e, 0x39, + 0x7a, 0xca, 0xbf, 0x30, 0x79, 0x10, 0xfb, 0x55, 0x1e, 0x04, 0xf5, 0xe2, + 0x5a, 0x35, 0x02, 0x5e, 0xf7, 0x31, 0x37, 0x0a, 0x7e, 0x4c, 0x0c, 0x73, + 0x45, 0x5f, 0xf1, 0xf7, 0xab, 0x5c, 0xa9, 0x88, 0x17, 0xe6, 0xf5, 0x72, + 0x1f, 0xde, 0xa1, 0xde, 0x7f, 0x7d, 0xa5, 0x9d, 0xf9, 0xaa, 0x28, 0xb9, + 0x47, 0x7f, 0x09, 0xfd, 0x18, 0x95, 0x42, 0xd5, 0x03, 0xfe, 0x89, 0x52, + 0x2e, 0xf1, 0x7c, 0x3f, 0xfc, 0x61, 0xc1, 0x3e, 0x69, 0x83, 0x6f, 0xa2, + 0x7c, 0x1d, 0xcc, 0x68, 0x87, 0x0e, 0x62, 0x70, 0x9d, 0x1f, 0x1a, 0x40, + 0x87, 0xcf, 0xcb, 0xda, 0xf8, 0xa2, 0xd4, 0xc7, 0x9b, 0x31, 0x2c, 0x30, + 0xaa, 0x5b, 0x0e, 0xea, 0x9e, 0x8a, 0x65, 0x1a, 0xdd, 0x72, 0xc2, 0xe0, + 0x4e, 0xae, 0x83, 0x2d, 0x85, 0xd1, 0x05, 0x25, 0x5f, 0x75, 0xb5, 0x1e, + 0x8e, 0x75, 0x59, 0xe5, 0xf9, 0x72, 0x0c, 0xe6, 0xfa, 0x46, 0x0c, 0x0e, + 0x3b, 0x65, 0xd6, 0xd5, 0xd9, 0x1b, 0xe6, 0xcc, 0x47, 0xb3, 0x87, 0x99, + 0xdb, 0x01, 0x6c, 0x3d, 0x3d, 0x35, 0x5b, 0xa1, 0x2d, 0x0c, 0x82, 0xba, + 0xbf, 0x89, 0x1e, 0x7f, 0xac, 0x30, 0xe4, 0x96, 0x68, 0xdd, 0xbe, 0xa0, + 0x72, 0x66, 0x27, 0xa7, 0xf2, 0x2a, 0x5e, 0xd8, 0x7c, 0x76, 0xf3, 0x5e, + 0xe7, 0x36, 0x31, 0xf8, 0xfe, 0x1d, 0x66, 0xfd, 0x63, 0x4e, 0xa9, 0xd2, + 0xe5, 0xcc, 0xaa, 0xb3, 0xb5, 0xac, 0xf9, 0x16, 0x27, 0x37, 0x95, 0x6e, + 0x7c, 0x76, 0x2f, 0xb1, 0x3e, 0xcf, 0x31, 0x0a, 0x15, 0x9e, 0xe3, 0xe8, + 0xf7, 0x69, 0xf3, 0x7e, 0xa0, 0xa1, 0xde, 0xa9, 0x78, 0x23, 0x63, 0x8c, + 0xed, 0x28, 0x6f, 0x54, 0xa8, 0x6b, 0xd0, 0x7f, 0x5c, 0xcf, 0x21, 0x92, + 0x2d, 0xc2, 0x3f, 0x25, 0x7d, 0x47, 0xa6, 0xf2, 0x2b, 0xcc, 0xdb, 0x7a, + 0x68, 0xea, 0x1a, 0xfc, 0xa5, 0x73, 0x9e, 0xce, 0x2b, 0x5f, 0x67, 0x1c, + 0x8c, 0xed, 0x54, 0x9f, 0x45, 0x13, 0xab, 0x3d, 0x3c, 0x35, 0xb8, 0x1e, + 0x91, 0x27, 0x4c, 0x1f, 0xbc, 0x4f, 0x6e, 0xfb, 0x52, 0x4a, 0xff, 0xc1, + 0x3f, 0x18, 0x85, 0x7f, 0xd0, 0x09, 0x5d, 0x4f, 0x3f, 0x83, 0xf8, 0xbb, + 0x13, 0x7b, 0x85, 0xe3, 0xdc, 0xa5, 0xc6, 0x89, 0x60, 0x9c, 0x59, 0xf8, + 0x38, 0x8c, 0x47, 0xe6, 0x3d, 0x07, 0x58, 0x02, 0xb6, 0xde, 0x63, 0xbc, + 0xdc, 0xc6, 0x9c, 0x87, 0xa1, 0x27, 0x98, 0xa3, 0x32, 0x11, 0xe6, 0x0d, + 0xa1, 0x9d, 0x6f, 0xda, 0x1d, 0x44, 0x3b, 0xfa, 0x07, 0x6c, 0x2b, 0xb7, + 0xd9, 0x32, 0xa8, 0xb0, 0x81, 0xf6, 0x6b, 0x48, 0x43, 0x0d, 0x73, 0xa5, + 0x5d, 0xc5, 0x9e, 0x53, 0xf3, 0x3a, 0xa8, 0xda, 0x59, 0xd9, 0x31, 0xd0, + 0x4e, 0xfc, 0x87, 0xbe, 0x97, 0x75, 0xbc, 0xb3, 0xa0, 0xe4, 0x08, 0x72, + 0x32, 0x1e, 0xe6, 0xbd, 0xe8, 0x76, 0x61, 0xfd, 0x81, 0xf5, 0x86, 0x19, + 0xff, 0xe7, 0x41, 0xee, 0x68, 0xa7, 0xf2, 0xad, 0x5f, 0xbe, 0x29, 0x07, + 0x8d, 0x6d, 0xc2, 0x3a, 0x91, 0x30, 0x2f, 0xb9, 0x89, 0xe6, 0xac, 0x59, + 0x73, 0xb6, 0x63, 0x6c, 0x58, 0xe5, 0xe2, 0xf3, 0x99, 0x33, 0x97, 0x61, + 0x1f, 0xcd, 0x67, 0x4d, 0xa3, 0xc0, 0x19, 0xda, 0x86, 0x94, 0x37, 0x3c, + 0xd8, 0xeb, 0x36, 0xac, 0x1d, 0x6d, 0xc2, 0xa0, 0xf1, 0x2d, 0xde, 0x2b, + 0xce, 0xca, 0x73, 0xcc, 0x51, 0xf8, 0xf5, 0x61, 0x7b, 0xae, 0x63, 0x6e, + 0xea, 0x5a, 0xc5, 0x93, 0x53, 0xcb, 0x3a, 0x3f, 0x4c, 0xf3, 0x81, 0x3a, + 0x9b, 0x6b, 0x9b, 0x94, 0x59, 0x8f, 0xb1, 0x9c, 0xa4, 0xbc, 0xe2, 0x35, + 0xe7, 0x39, 0xa1, 0xfe, 0xc6, 0xa8, 0xc9, 0xc7, 0x3e, 0x88, 0xf9, 0x13, + 0x37, 0x6a, 0x59, 0x3a, 0x00, 0x3b, 0xf4, 0x77, 0x0e, 0x70, 0x21, 0xf6, + 0xd3, 0x75, 0xa7, 0x79, 0x7e, 0xdb, 0xf9, 0xdf, 0x4a, 0x2e, 0x1d, 0xc8, + 0xc8, 0xe2, 0x36, 0xdf, 0xe1, 0xb7, 0xdf, 0x35, 0x04, 0x7d, 0x6f, 0x49, + 0x71, 0xd4, 0x4b, 0x2c, 0xf0, 0x5c, 0xc3, 0x1d, 0x01, 0xca, 0xa7, 0x1f, + 0x9d, 0x04, 0xbd, 0xbc, 0x1e, 0x04, 0x3e, 0x62, 0x4e, 0x22, 0xee, 0x99, + 0x13, 0x18, 0xf7, 0x40, 0xaf, 0xab, 0xce, 0x2b, 0xb4, 0xce, 0xfe, 0xfe, + 0x5e, 0xe6, 0xc0, 0xf5, 0x78, 0xe1, 0xda, 0xab, 0xef, 0xda, 0xd0, 0x77, + 0xc4, 0xbc, 0x9f, 0xd8, 0xe6, 0xbf, 0xf4, 0xb1, 0xdc, 0xce, 0x35, 0x33, + 0xb1, 0x17, 0xd6, 0x1f, 0x57, 0xb4, 0xcc, 0x42, 0x57, 0xcf, 0xa9, 0xf9, + 0xdc, 0x0f, 0x59, 0x88, 0xc8, 0xfc, 0xb6, 0xfc, 0xde, 0x0f, 0xf9, 0xdd, + 0xc3, 0x14, 0xcf, 0x5d, 0x64, 0x2d, 0x94, 0x31, 0xca, 0x17, 0x65, 0xeb, + 0xe3, 0xdd, 0xdc, 0x73, 0xe5, 0xed, 0x75, 0x77, 0x94, 0xcd, 0x4d, 0xda, + 0xe1, 0xba, 0xf3, 0x7a, 0xb7, 0xdc, 0xaa, 0x70, 0x7f, 0x64, 0x7e, 0x83, + 0xb5, 0xf5, 0xcd, 0xda, 0x66, 0x9a, 0xbe, 0x83, 0x08, 0xfb, 0x63, 0x0c, + 0x94, 0x36, 0x88, 0xe7, 0x50, 0xed, 0x52, 0x56, 0x32, 0x68, 0x29, 0x6c, + 0x9d, 0x73, 0xf3, 0x49, 0xc6, 0xbc, 0x8f, 0xc9, 0xbf, 0x03, 0xcd, 0xb9, + 0xe1, 0xa8, 0xe8, 0xb6, 0x33, 0xe0, 0xf7, 0xa6, 0x0b, 0x7f, 0x90, 0x67, + 0xd6, 0x15, 0x47, 0xce, 0xa9, 0x73, 0x57, 0xec, 0xd1, 0x4e, 0x47, 0x16, + 0xbd, 0xed, 0x73, 0x78, 0xa9, 0xa1, 0xce, 0x1a, 0xde, 0x3d, 0xb1, 0x4d, + 0x1b, 0xfd, 0x09, 0xf8, 0x52, 0xde, 0xcf, 0x83, 0x52, 0xfc, 0xa6, 0xba, + 0x46, 0xaf, 0x33, 0x4e, 0xc3, 0xf3, 0x01, 0x57, 0x0a, 0xf0, 0x0b, 0x0b, + 0xf0, 0x09, 0x0b, 0x4a, 0x2f, 0x30, 0x6e, 0xc3, 0x18, 0x5b, 0x19, 0x3e, + 0x48, 0x39, 0x68, 0xf7, 0x4e, 0xaa, 0x18, 0xe2, 0xa5, 0x8d, 0x54, 0xb9, + 0x2c, 0x5e, 0xf2, 0xc1, 0xed, 0x7c, 0xba, 0xee, 0x72, 0x2c, 0xdb, 0x1c, + 0x87, 0x4b, 0xaa, 0x5c, 0xb4, 0x0e, 0x60, 0xe4, 0xe3, 0xd0, 0xd5, 0xcf, + 0xfb, 0x8c, 0xbf, 0xdd, 0x49, 0x7e, 0x7f, 0x95, 0x93, 0xb4, 0x87, 0x46, + 0xc5, 0xbb, 0xe0, 0x0d, 0x3f, 0x28, 0xf4, 0x3f, 0x52, 0xc9, 0x23, 0xe4, + 0xdb, 0xf6, 0x37, 0x0d, 0xa1, 0x7d, 0x1d, 0x95, 0xc1, 0x0b, 0xaf, 0xab, + 0x33, 0x8e, 0x4f, 0xf8, 0xad, 0xb2, 0xa1, 0xe2, 0x77, 0xa3, 0x3d, 0x32, + 0x08, 0xdf, 0x57, 0x60, 0xa1, 0xf8, 0x8d, 0x83, 0x05, 0xdf, 0x43, 0xdd, + 0xcb, 0x74, 0x23, 0x69, 0xf2, 0x54, 0x69, 0x5f, 0x19, 0xdf, 0xd3, 0x79, + 0x7a, 0xcc, 0x4d, 0x65, 0xfe, 0x64, 0x51, 0xe5, 0xeb, 0x31, 0xd6, 0xc7, + 0x58, 0x1e, 0xe3, 0x7d, 0x8c, 0xdb, 0xe9, 0x5c, 0xbd, 0x89, 0xc6, 0x6e, + 0xb1, 0xbd, 0x30, 0x5f, 0x52, 0xdb, 0xad, 0xad, 0xcc, 0x3e, 0xd8, 0x3a, + 0x57, 0xc5, 0x4e, 0x4a, 0x6e, 0x8f, 0x1c, 0x1b, 0x6e, 0x07, 0xcf, 0x7b, + 0x55, 0x3e, 0x9d, 0xed, 0xdd, 0x0f, 0x1c, 0xcb, 0xf8, 0x1c, 0xb1, 0x69, + 0xc8, 0xe7, 0x7b, 0xf0, 0xec, 0x1d, 0xf0, 0x9e, 0xcf, 0x80, 0x5b, 0x95, + 0x1d, 0xfa, 0xbc, 0x6c, 0x55, 0x98, 0x03, 0x5f, 0xdb, 0x97, 0x57, 0xeb, + 0x41, 0xdf, 0x3c, 0xd4, 0x4d, 0x61, 0xfe, 0x28, 0x7d, 0x2a, 0xd7, 0x9c, + 0x93, 0xd3, 0x37, 0xef, 0x85, 0xbf, 0x4e, 0xfd, 0x63, 0xa9, 0xb1, 0xae, + 0x47, 0x3e, 0x20, 0xe5, 0xda, 0x6e, 0x67, 0xfe, 0x41, 0xf0, 0x0d, 0x5f, + 0xe5, 0xac, 0xc2, 0x9f, 0xd4, 0x6b, 0xac, 0xbf, 0x8f, 0x74, 0x76, 0xf2, + 0xcb, 0xe3, 0xda, 0x67, 0xcc, 0xf5, 0x02, 0xb3, 0x78, 0xa7, 0xbb, 0x77, + 0xb0, 0xf3, 0x2f, 0x0d, 0xae, 0x25, 0x6e, 0xee, 0x55, 0xd8, 0xc0, 0xae, + 0x87, 0x72, 0xc2, 0x7c, 0x1f, 0x62, 0xea, 0x03, 0x92, 0xab, 0x41, 0x6f, + 0xf6, 0xf1, 0xfe, 0x47, 0xa6, 0x2d, 0xaf, 0x03, 0x39, 0x3c, 0xd6, 0x7a, + 0x96, 0x3f, 0xae, 0x71, 0x7d, 0x67, 0x78, 0x9e, 0x1f, 0xe6, 0xbc, 0xdf, + 0x94, 0x5b, 0x0b, 0x79, 0x0a, 0x69, 0xd0, 0x63, 0x4d, 0x80, 0xde, 0x7a, + 0x35, 0x21, 0xbd, 0x1e, 0xf3, 0x84, 0x22, 0x32, 0xd6, 0x9b, 0x82, 0x13, + 0xaf, 0xe9, 0xa9, 0xd7, 0x60, 0xf3, 0xab, 0x21, 0x9d, 0x1a, 0xe3, 0xd7, + 0x6b, 0x7c, 0x9f, 0xc4, 0x58, 0xed, 0x32, 0xd6, 0x47, 0x3e, 0xb7, 0xd2, + 0x91, 0x34, 0xf9, 0xdc, 0xad, 0xcf, 0xef, 0x6b, 0xa2, 0xef, 0xd6, 0xef, + 0x4a, 0xf3, 0x8c, 0x8b, 0xad, 0xd0, 0x3f, 0x21, 0x8d, 0xbd, 0xd0, 0x73, + 0x98, 0xa3, 0x1f, 0xfa, 0x1a, 0x21, 0x5f, 0x42, 0x1f, 0x25, 0xaa, 0xe4, + 0x62, 0x36, 0xc3, 0xb9, 0x44, 0x8d, 0xcf, 0x42, 0xba, 0x14, 0x6d, 0x11, + 0x9e, 0x25, 0x46, 0xbd, 0xcf, 0xec, 0xd3, 0xeb, 0xff, 0xa4, 0x99, 0xaf, + 0x6b, 0xea, 0xb0, 0xaf, 0xfd, 0x68, 0xff, 0xb5, 0x00, 0x63, 0x31, 0x08, + 0x87, 0xfd, 0x1f, 0x62, 0xf7, 0xfd, 0xba, 0xaf, 0xce, 0x10, 0xbf, 0x87, + 0xdf, 0xa1, 0x91, 0x4e, 0xee, 0xaf, 0x90, 0x87, 0xec, 0xa3, 0xd7, 0xc4, + 0x5c, 0x49, 0x43, 0x47, 0x0b, 0x0d, 0x29, 0xff, 0x66, 0x1d, 0x77, 0x4f, + 0xd3, 0xdc, 0x29, 0x6b, 0xdd, 0xb2, 0x50, 0xed, 0x94, 0xf9, 0xaa, 0xf2, + 0x75, 0x86, 0x45, 0x88, 0xed, 0xb8, 0x2f, 0x55, 0x2e, 0xb3, 0xc9, 0x99, + 0x0c, 0xf7, 0x67, 0x37, 0xea, 0xd1, 0x86, 0xa0, 0xac, 0x69, 0xfd, 0x54, + 0x93, 0x5b, 0xbf, 0xd3, 0x98, 0x6b, 0xb4, 0xe6, 0xe3, 0x5d, 0x6f, 0xca, + 0xc7, 0x6b, 0xce, 0x7f, 0x2a, 0xcb, 0x23, 0x07, 0x3b, 0x64, 0xe0, 0x6c, + 0xa7, 0x91, 0xd1, 0xfb, 0xcd, 0x38, 0x18, 0x6f, 0x69, 0x5c, 0x06, 0x96, + 0xbe, 0x28, 0xa5, 0x69, 0x95, 0xff, 0xde, 0xf4, 0xfd, 0xc3, 0xa0, 0xf9, + 0xfe, 0x29, 0x67, 0x31, 0x17, 0xa6, 0xb0, 0x84, 0xf5, 0x3a, 0x98, 0x1a, + 0x4e, 0xda, 0xfc, 0x46, 0xf7, 0x31, 0x19, 0x58, 0x1d, 0x97, 0xf4, 0x12, + 0x31, 0x03, 0xb3, 0x01, 0x52, 0x2a, 0x2e, 0x9a, 0xbe, 0xa8, 0xfb, 0xf3, + 0x96, 0xf8, 0x3e, 0x0d, 0xbc, 0xca, 0xf7, 0x85, 0x44, 0x44, 0x65, 0x0c, + 0x7c, 0x10, 0xf2, 0xd4, 0x66, 0xf0, 0x80, 0x23, 0xf9, 0x25, 0xb6, 0x27, + 0xf6, 0xf8, 0x47, 0xac, 0x59, 0x21, 0x69, 0x0b, 0xdb, 0xa8, 0xfe, 0x70, + 0x1d, 0xc6, 0xd3, 0xc9, 0xeb, 0x51, 0x59, 0x6f, 0x78, 0xd8, 0x13, 0xfa, + 0x9b, 0x89, 0x52, 0x2d, 0xcc, 0x27, 0x7d, 0xc4, 0xc4, 0x00, 0x34, 0x8d, + 0xc5, 0x4a, 0xab, 0xec, 0x3d, 0x63, 0xbe, 0x9d, 0xe8, 0x50, 0x67, 0x68, + 0x4d, 0xfa, 0xcf, 0xd4, 0xbf, 0xdd, 0x65, 0xde, 0x80, 0x08, 0xdf, 0x37, + 0xf9, 0x24, 0xf1, 0xb8, 0xda, 0x07, 0x03, 0xf5, 0xb0, 0xde, 0xa8, 0xab, + 0x7d, 0x60, 0xf2, 0x29, 0x6b, 0x68, 0x1e, 0x83, 0xcf, 0xc3, 0x67, 0x07, + 0xd0, 0x96, 0xeb, 0x84, 0xb2, 0x7e, 0x40, 0xe5, 0x39, 0x46, 0xb2, 0x47, + 0xcc, 0x59, 0x5a, 0x9f, 0x1a, 0xcb, 0xcd, 0xb2, 0xff, 0x50, 0x37, 0x74, + 0x34, 0x8d, 0xdf, 0x4a, 0x2f, 0x7d, 0xf8, 0x9f, 0x19, 0x79, 0xe1, 0x7b, + 0xde, 0xb7, 0xd6, 0xf9, 0xa3, 0x7d, 0xe1, 0x7b, 0x67, 0xfb, 0x1b, 0x0c, + 0xf2, 0x92, 0x67, 0x80, 0x28, 0x2f, 0x32, 0x97, 0x9d, 0xd7, 0x28, 0xcd, + 0xb7, 0x25, 0xce, 0x12, 0x7f, 0xad, 0xfd, 0x38, 0xe8, 0x3b, 0xdc, 0xb3, + 0xbb, 0xe5, 0x06, 0x51, 0x17, 0x9f, 0xb6, 0xb6, 0x2a, 0x8c, 0x5d, 0x94, + 0xe5, 0x58, 0xa6, 0x5b, 0x66, 0xab, 0x36, 0xbf, 0x4d, 0x65, 0x2c, 0x96, + 0x67, 0x95, 0x32, 0xa7, 0x74, 0xdc, 0x90, 0xe8, 0xef, 0x76, 0x3b, 0xa4, + 0xe8, 0x52, 0x9e, 0x87, 0x64, 0xbd, 0x36, 0xdd, 0x94, 0x03, 0xdc, 0x66, + 0xe4, 0xec, 0xef, 0xa2, 0xd2, 0xc9, 0x38, 0x52, 0xb8, 0xa7, 0x87, 0xa4, + 0x58, 0x6b, 0x3e, 0x67, 0x60, 0x9e, 0x11, 0xe5, 0xb6, 0xbf, 0x69, 0xef, + 0x31, 0x57, 0x0f, 0xb8, 0x2a, 0x4e, 0x9f, 0x95, 0xf5, 0xf6, 0x1a, 0x7b, + 0xfb, 0x15, 0xac, 0xc7, 0xfb, 0x2d, 0xf1, 0x48, 0x1b, 0x6c, 0x84, 0xc9, + 0x35, 0x3e, 0x1c, 0x2f, 0xc3, 0x3f, 0x1b, 0x32, 0xe3, 0xde, 0x81, 0x7b, + 0xd6, 0xdd, 0x67, 0xde, 0xef, 0x37, 0xf7, 0x9d, 0xe6, 0x3e, 0x82, 0x7b, + 0xe6, 0x8d, 0xb3, 0x4f, 0x96, 0xfc, 0x9e, 0x88, 0xdf, 0xeb, 0x64, 0x25, + 0x7a, 0x11, 0xe8, 0xa9, 0xd1, 0x29, 0x9f, 0xae, 0x29, 0xfe, 0x5a, 0xde, + 0x12, 0x01, 0xc1, 0x7e, 0x73, 0x7d, 0xeb, 0x1e, 0xfc, 0xdc, 0x4d, 0xdf, + 0x4a, 0x55, 0x8c, 0xac, 0x34, 0xd3, 0x9b, 0x03, 0xad, 0xef, 0x96, 0x83, + 0x45, 0x1b, 0xa5, 0xfd, 0xc6, 0x62, 0x45, 0xe7, 0x1a, 0x1d, 0x83, 0xdf, + 0x78, 0xb8, 0xfa, 0xa8, 0xab, 0xf3, 0x62, 0xc2, 0x5c, 0xca, 0x4e, 0xcc, + 0x6b, 0xc8, 0x9c, 0x5b, 0xb3, 0x2d, 0x73, 0x3a, 0xc3, 0xf3, 0x99, 0x66, + 0xac, 0x4a, 0x5b, 0x44, 0x3b, 0xc3, 0xef, 0x9a, 0x7c, 0xd4, 0x5d, 0xa4, + 0xae, 0x69, 0xca, 0xcd, 0xff, 0x52, 0x4b, 0x6e, 0x3e, 0xbf, 0xfb, 0x16, + 0xf9, 0x6f, 0x0d, 0xc6, 0x95, 0x3a, 0x24, 0x72, 0x36, 0xcc, 0xc1, 0xe2, + 0x1a, 0x13, 0x87, 0xf1, 0x7b, 0xef, 0xa9, 0x5d, 0x62, 0x4e, 0xa1, 0x9c, + 0x7f, 0xc7, 0x65, 0x7e, 0xab, 0x9b, 0x0d, 0xe3, 0x54, 0xcc, 0xeb, 0x21, + 0xe6, 0x3a, 0x60, 0x62, 0x0a, 0x7c, 0x57, 0x96, 0x9e, 0x83, 0x53, 0xdc, + 0x1b, 0xbf, 0x1d, 0xd9, 0xce, 0xfd, 0x57, 0xe3, 0xc4, 0x35, 0x86, 0xe4, + 0x77, 0xe3, 0x3e, 0xf6, 0xd5, 0x9e, 0xcd, 0xf0, 0x9b, 0x8c, 0xcb, 0x8d, + 0x8c, 0xfa, 0xf6, 0x83, 0x67, 0x1e, 0x5b, 0x0d, 0xee, 0x3b, 0x7e, 0x23, + 0x9e, 0x55, 0x39, 0x01, 0x5b, 0xe6, 0x9b, 0xe7, 0xab, 0x0d, 0xfd, 0x1d, + 0xcb, 0xe2, 0xb2, 0xca, 0xcb, 0x07, 0x56, 0x4b, 0xe2, 0x3d, 0x73, 0xe8, + 0xfa, 0x55, 0x2e, 0xc1, 0x7c, 0xe3, 0x53, 0x28, 0x3f, 0x2f, 0x6b, 0x15, + 0x1d, 0x7f, 0x9d, 0x6f, 0x30, 0xa7, 0xc0, 0x55, 0x67, 0x44, 0x03, 0x4b, + 0x45, 0x8c, 0x17, 0x7e, 0xb3, 0x1d, 0xc7, 0x33, 0xd2, 0x57, 0x36, 0x7b, + 0x34, 0xcc, 0x05, 0xe9, 0xea, 0xa1, 0x4d, 0x28, 0x37, 0xba, 0x54, 0x1e, + 0x82, 0xc6, 0x23, 0xc4, 0x7a, 0x31, 0xd4, 0xe5, 0x5c, 0x3b, 0x69, 0xaf, + 0x02, 0xea, 0xa4, 0x34, 0xc6, 0xa9, 0xab, 0xdc, 0x44, 0xf2, 0xd9, 0x73, + 0x4b, 0xf4, 0xd7, 0x94, 0x8e, 0x4f, 0x0d, 0xcf, 0x48, 0xc1, 0x8d, 0xc2, + 0x17, 0x9b, 0x57, 0x7e, 0xce, 0xfd, 0xc0, 0xd0, 0x5d, 0x9b, 0x91, 0x2c, + 0xe7, 0xc6, 0xb1, 0xe9, 0x87, 0xe8, 0xf9, 0xe8, 0x33, 0x02, 0xb1, 0xe6, + 0xd5, 0xf7, 0x8f, 0x7c, 0xce, 0x78, 0x6f, 0xf8, 0xcd, 0x90, 0xfe, 0x26, + 0x64, 0xa6, 0x71, 0x44, 0x4e, 0x55, 0xf6, 0xf2, 0x5b, 0x09, 0x7f, 0x0b, + 0x7c, 0x3b, 0xd6, 0xe8, 0x52, 0xdf, 0xa5, 0xcc, 0x34, 0x98, 0x3f, 0x17, + 0xda, 0x1e, 0xae, 0x55, 0xdc, 0x7c, 0x37, 0x91, 0x30, 0xdf, 0x4d, 0xf0, + 0xdb, 0x8f, 0x1f, 0xed, 0x0d, 0xf7, 0xfb, 0xad, 0x38, 0x9c, 0x32, 0xf8, + 0xa7, 0xf0, 0x0d, 0xc3, 0x3c, 0x4c, 0xe6, 0x8b, 0x06, 0xc1, 0x31, 0x9f, + 0xf1, 0xdb, 0xe9, 0xc3, 0x6b, 0x98, 0xe3, 0x95, 0x1a, 0x78, 0x78, 0x94, + 0xcf, 0x98, 0x37, 0xd6, 0x2e, 0xf9, 0xd1, 0x76, 0xea, 0xf2, 0xce, 0x35, + 0x6f, 0xaf, 0x5c, 0xae, 0xc6, 0x55, 0x0e, 0x5c, 0x09, 0x38, 0xbf, 0x2e, + 0x1f, 0xeb, 0xe1, 0xd9, 0xdd, 0x84, 0x6a, 0x1f, 0xee, 0x77, 0x1d, 0x37, + 0x98, 0x58, 0xd7, 0xfa, 0xe4, 0x78, 0x06, 0xb8, 0xe5, 0x82, 0x58, 0x7f, + 0x90, 0xe9, 0x87, 0xef, 0xcd, 0xb1, 0xd2, 0x68, 0x07, 0xd9, 0x49, 0x70, + 0xaf, 0xbf, 0x13, 0xd4, 0x41, 0xef, 0x8d, 0x06, 0xf1, 0x3a, 0x30, 0xd4, + 0x34, 0xdb, 0x64, 0xc5, 0x3e, 0xc3, 0x3a, 0xbd, 0x90, 0xbf, 0x28, 0xe6, + 0xe3, 0xc0, 0x17, 0xd8, 0x27, 0x75, 0x97, 0xef, 0x1c, 0x7d, 0xa6, 0x12, + 0x0f, 0xfd, 0x94, 0xef, 0x81, 0x7f, 0x49, 0xa5, 0x93, 0xc2, 0xf3, 0x4e, + 0xe6, 0xb3, 0xce, 0x56, 0x27, 0xb1, 0x87, 0x1c, 0x83, 0xcd, 0x1c, 0xf4, + 0xf1, 0xe1, 0x1e, 0x8d, 0x15, 0x78, 0x1e, 0xaa, 0xb1, 0x88, 0xb6, 0x31, + 0x3c, 0xdf, 0x71, 0xe0, 0x0b, 0x84, 0xfb, 0xf2, 0x99, 0x7d, 0x37, 0x7f, + 0x0b, 0x43, 0x1c, 0x93, 0x4e, 0x9c, 0xe7, 0x79, 0xdc, 0xc6, 0xc3, 0x32, + 0x03, 0x9a, 0x4f, 0x9b, 0x79, 0x3e, 0x98, 0xf1, 0xe4, 0x7a, 0x8d, 0xe7, + 0x95, 0x07, 0x50, 0x32, 0xd7, 0x91, 0x34, 0x8f, 0x98, 0x7c, 0xce, 0x2c, + 0xe6, 0xfa, 0x98, 0xbc, 0x01, 0x7c, 0xfd, 0x66, 0x25, 0xed, 0x4f, 0xa8, + 0x3c, 0xa4, 0x54, 0xe2, 0xb2, 0x8c, 0x24, 0xe9, 0x03, 0x96, 0xdd, 0x54, + 0xe2, 0x3a, 0xe4, 0xe1, 0x46, 0xe5, 0x99, 0x1e, 0xfe, 0xaf, 0x8a, 0x3a, + 0xec, 0xe1, 0x0d, 0x95, 0x83, 0x94, 0x62, 0xcc, 0x04, 0xf7, 0xfd, 0x26, + 0x0f, 0x8a, 0xe3, 0xf0, 0x5d, 0xbf, 0xbc, 0x51, 0xd9, 0xb6, 0xbf, 0x1c, + 0xc7, 0x7c, 0x03, 0xcf, 0xb1, 0x2e, 0xf4, 0x50, 0x0f, 0x71, 0x3c, 0xdd, + 0x47, 0x58, 0x87, 0x7c, 0x0d, 0xe3, 0x9a, 0xea, 0x5b, 0xcb, 0xa4, 0x58, + 0x96, 0xb4, 0x79, 0x9c, 0xfb, 0x54, 0x8f, 0xc6, 0x40, 0x6c, 0x97, 0x76, + 0x0f, 0xab, 0xfe, 0x78, 0xb6, 0xc7, 0xf3, 0xaf, 0xb0, 0x1f, 0xe6, 0x43, + 0x31, 0xe7, 0x8a, 0xba, 0xaf, 0x99, 0x06, 0x6d, 0xff, 0xdf, 0x50, 0xb1, + 0xf4, 0x71, 0xd4, 0xa7, 0x8d, 0x86, 0xbc, 0xd4, 0x12, 0xdb, 0xdf, 0x7c, + 0x68, 0x5e, 0xf2, 0xfa, 0x99, 0xed, 0x6f, 0x32, 0xec, 0xbb, 0x5d, 0xf3, + 0x3e, 0xc4, 0xa5, 0xfd, 0xd8, 0xaf, 0x8f, 0x49, 0x7d, 0x25, 0x9d, 0xf8, + 0xb4, 0x84, 0xfd, 0x06, 0x87, 0x78, 0xde, 0x51, 0xcc, 0x8c, 0xb8, 0x0b, + 0x8a, 0x9e, 0x54, 0x82, 0x39, 0xc8, 0x97, 0x31, 0x5e, 0xbd, 0xd1, 0x1a, + 0x7b, 0x48, 0xe5, 0x36, 0x25, 0xed, 0xeb, 0xb5, 0x19, 0x92, 0x4d, 0xac, + 0xcd, 0x9f, 0x9b, 0xb5, 0xf9, 0x18, 0xfa, 0xf6, 0xce, 0x8c, 0x4a, 0xfa, + 0x4c, 0x3a, 0x79, 0x5a, 0x78, 0x96, 0xb8, 0x8f, 0x31, 0x2c, 0xeb, 0xc1, + 0x4c, 0x12, 0xf3, 0x4d, 0x61, 0xbe, 0x28, 0x1b, 0xbc, 0x1e, 0x81, 0x6f, + 0xbe, 0x87, 0x7b, 0xfb, 0x10, 0x75, 0x26, 0x79, 0x51, 0x54, 0xef, 0x80, + 0x4f, 0x9e, 0x26, 0x4d, 0x00, 0xca, 0x9d, 0x29, 0x15, 0x07, 0xbc, 0xde, + 0xe0, 0xf9, 0xa2, 0xa6, 0xaf, 0x00, 0xfa, 0xe6, 0x34, 0x7d, 0xc9, 0x99, + 0x6d, 0xec, 0x9a, 0x4a, 0x9c, 0x12, 0xe2, 0x25, 0xe2, 0x17, 0xe2, 0xfa, + 0x47, 0x7a, 0xc3, 0x6f, 0x5a, 0xf2, 0x77, 0xe7, 0xb6, 0xe7, 0xde, 0x86, + 0xba, 0x57, 0x32, 0x2a, 0xbf, 0xd9, 0x3d, 0x22, 0x1f, 0x91, 0xdc, 0xa7, + 0x52, 0xc9, 0x9c, 0xe5, 0x19, 0x0c, 0x88, 0xb2, 0xc6, 0x6b, 0xea, 0x5c, + 0xcf, 0x60, 0x0b, 0xae, 0x4d, 0x06, 0x63, 0x29, 0xde, 0xc2, 0x67, 0xea, + 0x87, 0xcc, 0x53, 0xd6, 0x7e, 0x07, 0x7b, 0x48, 0xff, 0x9f, 0x8e, 0xcb, + 0xe0, 0xe3, 0x3c, 0xf8, 0x78, 0xfc, 0x16, 0x0c, 0x16, 0xdd, 0xc6, 0x60, + 0x5b, 0x6a, 0xbc, 0x7b, 0x41, 0x53, 0xc1, 0x25, 0xfe, 0x9a, 0xdf, 0x96, + 0x15, 0xd2, 0x34, 0xca, 0xff, 0xb5, 0x23, 0x57, 0x33, 0x5c, 0x0f, 0x60, + 0x30, 0xf4, 0xb7, 0xb6, 0x23, 0x4b, 0x98, 0xbf, 0x92, 0x5f, 0xc8, 0x6e, + 0xca, 0x75, 0x2c, 0xae, 0x05, 0xfb, 0x13, 0xeb, 0x1a, 0x68, 0xd9, 0x52, + 0x72, 0xa0, 0x65, 0x60, 0xab, 0xd6, 0xf9, 0x1e, 0x32, 0xc0, 0x79, 0x52, + 0xfe, 0x42, 0xd9, 0xdb, 0xc9, 0xa7, 0xe8, 0x00, 0x4f, 0x3e, 0x78, 0x4f, + 0x56, 0xf2, 0x67, 0x78, 0x16, 0x26, 0xd6, 0xc8, 0x3d, 0x94, 0x49, 0xe2, + 0x04, 0x60, 0xc8, 0x04, 0x79, 0xac, 0xf1, 0xe0, 0xcc, 0xb3, 0x7b, 0xf1, + 0x7b, 0xb3, 0x87, 0x39, 0x33, 0xf9, 0x73, 0xd4, 0x57, 0x62, 0xdd, 0x79, + 0x8f, 0xf6, 0x0f, 0x6f, 0xc4, 0xc1, 0x73, 0xbc, 0x1f, 0x78, 0xb2, 0x0d, + 0xfa, 0xca, 0x31, 0xf3, 0xe6, 0x3d, 0xf9, 0x8a, 0xf2, 0xd9, 0x29, 0xa3, + 0x03, 0xa8, 0x47, 0xc4, 0xec, 0x8b, 0xb2, 0xcc, 0x31, 0x46, 0x9f, 0xe9, + 0x94, 0x09, 0xe8, 0xb5, 0x23, 0x95, 0x71, 0xf9, 0x72, 0xa5, 0x4b, 0xe1, + 0x86, 0xbf, 0xf6, 0xd3, 0x89, 0x61, 0x2b, 0x90, 0x07, 0x81, 0x7f, 0x66, + 0xfa, 0xdb, 0xe4, 0xcd, 0x51, 0x9d, 0xfb, 0x7b, 0x83, 0xc9, 0x8d, 0x2e, + 0xf3, 0x55, 0x39, 0x1f, 0xe8, 0x7d, 0x0b, 0xbe, 0x80, 0xd5, 0x2e, 0x33, + 0xf1, 0x2e, 0xf9, 0xb8, 0x8f, 0xf2, 0x36, 0x5f, 0x7d, 0x63, 0x9c, 0x8b, + 0x37, 0xeb, 0x91, 0x37, 0xcd, 0xd8, 0x5f, 0x34, 0xe5, 0xbf, 0xe9, 0x6d, + 0xa2, 0xc5, 0x9a, 0xcb, 0x44, 0xd4, 0xfc, 0xe6, 0x6b, 0xd4, 0x6f, 0x6c, + 0x03, 0x7d, 0xd2, 0xe0, 0x39, 0x51, 0x59, 0xd6, 0xa0, 0x5f, 0x4a, 0x55, + 0xb1, 0xce, 0x65, 0x80, 0xa8, 0x3d, 0x8d, 0x3f, 0x4b, 0x90, 0xaf, 0xd9, + 0xaa, 0x8a, 0x59, 0xaa, 0xbc, 0xed, 0x59, 0x60, 0x5d, 0xf8, 0xc4, 0xc0, + 0x10, 0x26, 0x7f, 0xa5, 0x93, 0xf1, 0x90, 0x66, 0x1d, 0x16, 0xfe, 0x2f, + 0x9d, 0xff, 0xd4, 0x2b, 0xdd, 0x65, 0xac, 0x4b, 0x88, 0xb9, 0xc1, 0x53, + 0x8c, 0x99, 0x57, 0xeb, 0x14, 0xae, 0x09, 0x75, 0x4f, 0x73, 0xbe, 0x78, + 0x88, 0x39, 0xb8, 0x67, 0x69, 0x2f, 0xa4, 0x1c, 0x03, 0xa6, 0xed, 0x38, + 0x03, 0xdb, 0x5d, 0xcd, 0x42, 0x56, 0xc6, 0x55, 0xde, 0xe7, 0x3c, 0xb0, + 0xdb, 0x1f, 0xf8, 0x7f, 0x2a, 0xf6, 0xd3, 0x07, 0x64, 0xad, 0xda, 0x01, + 0x7e, 0xd0, 0x2e, 0x44, 0x95, 0x7f, 0x7d, 0xe3, 0x28, 0xed, 0x1d, 0x6d, + 0x89, 0x5e, 0x8b, 0xad, 0xda, 0xf7, 0x7a, 0xf5, 0xb7, 0x33, 0x7b, 0x65, + 0xb3, 0x16, 0xda, 0x42, 0xf8, 0x87, 0xd5, 0xa8, 0xb1, 0xcb, 0x9d, 0xd0, + 0xdd, 0xdf, 0x8f, 0xd6, 0x95, 0xaf, 0xce, 0xf9, 0xd3, 0x06, 0x45, 0x99, + 0x17, 0xd7, 0x59, 0xf7, 0x38, 0xf7, 0x66, 0x1b, 0xa4, 0x71, 0x87, 0x7b, + 0x90, 0xe3, 0x31, 0x87, 0x82, 0x73, 0x8c, 0x4b, 0xf4, 0xfc, 0x63, 0x62, + 0xc3, 0x6f, 0x89, 0x2c, 0x11, 0xeb, 0xdd, 0xec, 0xbb, 0x44, 0x2e, 0xba, + 0xe6, 0x5b, 0xec, 0x41, 0x8d, 0x65, 0x32, 0x28, 0xeb, 0xe1, 0xf7, 0xd9, + 0xfc, 0x35, 0xdb, 0xcd, 0xd0, 0xb7, 0xd8, 0xd5, 0x96, 0xe2, 0xef, 0xff, + 0x01, 0x37, 0x64, 0x26, 0x2b, 0x1c, 0x4c, 0x00, 0x00, 0x00 }; static const u32 bnx2_COM_b09FwData[(0x0/4) + 1] = { 0x0 }; static const u32 bnx2_COM_b09FwRodata[(0x30/4) + 1] = { - 0x80080100, 0x80080080, 0x80080000, 0x80080240, 0x08000e94, 0x08000eec, - 0x08000f30, 0x08000fc4, 0x08001008, 0x80080100, 0x80080080, 0x80080000, + 0x80080100, 0x80080080, 0x80080000, 0x80080240, 0x08000e20, 0x08000e78, + 0x08000ebc, 0x08000f50, 0x08000f94, 0x80080100, 0x80080080, 0x80080000, 0x00000000 }; static struct fw_info bnx2_com_fw_09 = { - /* Firmware version: 4.0.5 */ + /* Firmware version: 4.4.23 */ .ver_major = 0x4, - .ver_minor = 0x0, - .ver_fix = 0x5, + .ver_minor = 0x4, + .ver_fix = 0x17, .start_addr = 0x080000f8, .text_addr = 0x08000000, - .text_len = 0x4b40, + .text_len = 0x4c18, .text_index = 0x0, .gz_text = bnx2_COM_b09FwText, .gz_text_len = sizeof(bnx2_COM_b09FwText), @@ -860,1202 +866,1210 @@ static struct fw_info bnx2_com_fw_09 = { .data_index = 0x0, .data = bnx2_COM_b09FwData, - .sbss_addr = 0x08004ba0, + .sbss_addr = 0x08004c60, .sbss_len = 0x38, .sbss_index = 0x0, - .bss_addr = 0x08004bd8, + .bss_addr = 0x08004c98, .bss_len = 0xbc, .bss_index = 0x0, - .rodata_addr = 0x08004b40, + .rodata_addr = 0x08004c18, .rodata_len = 0x30, .rodata_index = 0x0, .rodata = bnx2_COM_b09FwRodata, }; static u8 bnx2_CP_b09FwText[] = { - 0xad, 0xbc, 0x0f, 0x74, 0x53, 0xd7, 0x95, 0x2e, 0xfe, 0xdd, 0x2b, 0xc9, - 0x96, 0x6d, 0xd9, 0x96, 0x8d, 0x70, 0xe4, 0xc4, 0x0d, 0x52, 0x7c, 0x05, - 0x0a, 0x36, 0xe9, 0x95, 0x11, 0x89, 0xd3, 0x77, 0x13, 0x54, 0x70, 0x82, - 0x49, 0x68, 0xe2, 0x10, 0xa6, 0x75, 0x67, 0x98, 0xa9, 0x1e, 0x21, 0x09, - 0x49, 0x99, 0x3c, 0xb7, 0xaf, 0xed, 0x23, 0xf9, 0xd1, 0xf1, 0xad, 0xcd, - 0x1f, 0x03, 0x92, 0x25, 0x1b, 0xf3, 0x27, 0x6f, 0xba, 0x5e, 0x84, 0x31, - 0x18, 0x12, 0xd9, 0x4e, 0xda, 0x4c, 0x87, 0xbc, 0xd5, 0x79, 0x78, 0x0c, - 0x24, 0x90, 0x34, 0x7f, 0x9a, 0xb4, 0xab, 0x69, 0xa7, 0x6f, 0xe2, 0x12, - 0x92, 0x92, 0x7f, 0x94, 0x34, 0x9d, 0x0e, 0x74, 0x86, 0xde, 0xdf, 0xb7, - 0xaf, 0x24, 0x30, 0x94, 0xa4, 0xed, 0x5a, 0xcf, 0x6b, 0x69, 0x49, 0xf7, - 0xde, 0x73, 0xf6, 0x39, 0x67, 0x9f, 0xbd, 0xbf, 0xfd, 0xed, 0x73, 0xce, - 0xf5, 0xa7, 0x80, 0x52, 0xe4, 0xff, 0xca, 0xf9, 0xb9, 0x2e, 0xda, 0x71, - 0x0f, 0xe6, 0x5d, 0xa7, 0xcb, 0xb5, 0xd3, 0x05, 0x27, 0xfe, 0xc4, 0xbf, - 0xc0, 0x9f, 0x5a, 0x30, 0xff, 0xe7, 0x00, 0xbc, 0x85, 0x36, 0xe5, 0x03, - 0xb7, 0x6a, 0xac, 0xfb, 0xe2, 0x02, 0x0d, 0x6e, 0x87, 0x11, 0x5d, 0x7e, - 0x8f, 0x06, 0xc4, 0xb2, 0x0d, 0x81, 0x85, 0x38, 0x67, 0x99, 0x3e, 0x27, - 0xe4, 0xfe, 0xa7, 0x8c, 0xff, 0x7c, 0xec, 0x9f, 0x6e, 0x08, 0x9e, 0xce, - 0x38, 0xe0, 0xf6, 0x1a, 0x5f, 0x83, 0x77, 0x26, 0xdc, 0x75, 0xac, 0xf3, - 0xed, 0x59, 0xb3, 0x55, 0x54, 0x14, 0x64, 0x05, 0xfd, 0x19, 0x04, 0xbd, - 0x26, 0x82, 0x61, 0x13, 0x88, 0x3b, 0x0d, 0xc4, 0x8b, 0x0d, 0x37, 0x8a, - 0xb4, 0x22, 0xc4, 0xbd, 0x6b, 0x02, 0xeb, 0xa2, 0xc0, 0x82, 0x84, 0x3b, - 0x70, 0x3c, 0x0b, 0xdc, 0x93, 0x70, 0x63, 0xd2, 0xe1, 0x09, 0xbc, 0x99, - 0xbd, 0xb9, 0x32, 0xa7, 0x83, 0x18, 0x1c, 0x1a, 0xe2, 0xaa, 0x21, 0xf7, - 0x11, 0x58, 0x98, 0x8d, 0x62, 0x7d, 0xca, 0xb2, 0x9c, 0x1a, 0x9c, 0x83, - 0x8d, 0x0e, 0xc4, 0xbc, 0x0a, 0x76, 0x6b, 0x51, 0x74, 0x8f, 0x05, 0x39, - 0x58, 0x29, 0x23, 0xed, 0xfc, 0xe6, 0xdc, 0xc6, 0xd4, 0x49, 0xeb, 0x9f, - 0x66, 0x79, 0xf1, 0xe4, 0x98, 0x0f, 0x07, 0xc7, 0x82, 0xa6, 0x89, 0x2a, - 0x9c, 0x48, 0x37, 0xe2, 0xa4, 0x56, 0x87, 0x37, 0x35, 0x0b, 0xeb, 0xf5, - 0x30, 0x54, 0x2d, 0xa8, 0x43, 0xf1, 0x63, 0xd0, 0x1b, 0x0c, 0xc4, 0xc1, - 0x4e, 0x54, 0x04, 0xc3, 0xe3, 0xac, 0x9b, 0x4a, 0x21, 0x5e, 0x64, 0x38, - 0x51, 0xa2, 0xdd, 0x8c, 0x53, 0xdb, 0x0c, 0x7c, 0xb0, 0x0d, 0xcb, 0x2b, - 0x60, 0x59, 0xd9, 0x48, 0xa8, 0x6d, 0xb5, 0xe2, 0x0d, 0x3c, 0x9f, 0x45, - 0xe0, 0x58, 0x76, 0xaa, 0xde, 0x38, 0x21, 0xd5, 0x6c, 0x27, 0x15, 0xc5, - 0x4e, 0xf6, 0xcd, 0x3b, 0x2b, 0x8a, 0xf4, 0x18, 0xdb, 0x4e, 0x49, 0x7f, - 0xfc, 0xf8, 0xa7, 0x59, 0x7f, 0xcd, 0xf9, 0x64, 0x5b, 0x94, 0xbd, 0x21, - 0xf5, 0x3a, 0xfb, 0x55, 0x87, 0xef, 0x8e, 0xf9, 0xf1, 0x1d, 0xf6, 0xed, - 0x29, 0x29, 0x37, 0x16, 0x60, 0x1f, 0xab, 0x70, 0x84, 0xfd, 0xfb, 0x21, - 0xfb, 0xf7, 0x0a, 0xfb, 0xb7, 0x9b, 0xfd, 0x5b, 0xd1, 0x1c, 0xdc, 0x69, - 0x42, 0xc1, 0xd2, 0xc6, 0x36, 0xe9, 0x1b, 0xc7, 0xc7, 0x8f, 0xaa, 0x22, - 0x56, 0x1d, 0x0c, 0x07, 0xd4, 0x60, 0x18, 0x76, 0x9f, 0xa5, 0xfd, 0xdf, - 0x9c, 0x4b, 0xa6, 0x60, 0xba, 0xa9, 0x57, 0x97, 0x71, 0x33, 0xb2, 0xec, - 0xf3, 0x13, 0xdb, 0x42, 0xcd, 0xab, 0x54, 0x2c, 0xf1, 0xb0, 0xdf, 0x0f, - 0x46, 0x42, 0x81, 0xd9, 0xec, 0xf7, 0x50, 0x56, 0x55, 0x55, 0xcd, 0x17, - 0x18, 0xce, 0x2a, 0x88, 0x2d, 0x55, 0x39, 0x7e, 0xb6, 0x9b, 0x62, 0x5f, - 0x52, 0xec, 0x4b, 0x8a, 0x7d, 0x49, 0x49, 0x9f, 0xc3, 0xec, 0x6f, 0x4e, - 0xd7, 0x83, 0xd9, 0xcb, 0xf5, 0x35, 0xd8, 0xc3, 0xb9, 0xa4, 0x3e, 0xa5, - 0xcf, 0x96, 0xf5, 0xaa, 0xbe, 0x88, 0x7d, 0xb0, 0xac, 0x8f, 0x74, 0xe9, - 0x9b, 0xf4, 0xab, 0x1c, 0x31, 0x5f, 0x8a, 0x73, 0x56, 0xe8, 0x1b, 0x8c, - 0x6a, 0xcc, 0x30, 0x5d, 0x86, 0xcc, 0xbb, 0xca, 0xfb, 0x21, 0xfd, 0x23, - 0xc0, 0x1a, 0x8c, 0x7a, 0x03, 0x1b, 0xb2, 0xbe, 0x40, 0x17, 0x75, 0xd9, - 0x9d, 0x0d, 0xfa, 0xc5, 0x56, 0xff, 0xb0, 0x2f, 0x41, 0x6f, 0xdc, 0x9e, - 0x53, 0xe9, 0xd3, 0x64, 0x7e, 0x3e, 0x2d, 0xeb, 0x15, 0xdd, 0xcf, 0xb6, - 0xa5, 0x3f, 0x51, 0xbb, 0xed, 0x0f, 0x75, 0x44, 0xbd, 0x10, 0xbb, 0x08, - 0x99, 0x3f, 0xb4, 0xed, 0xcb, 0x1b, 0x48, 0x67, 0x59, 0xe6, 0xbc, 0x1c, - 0x27, 0xc7, 0x0a, 0xb6, 0x65, 0x59, 0xbb, 0xb5, 0xa0, 0x57, 0xda, 0xca, - 0x8d, 0x51, 0xec, 0x46, 0xec, 0xc4, 0x1f, 0xf7, 0x18, 0x5e, 0xca, 0x44, - 0xdb, 0xce, 0x64, 0xa7, 0x55, 0xab, 0x89, 0x2e, 0xb5, 0x35, 0xb5, 0x0e, - 0x4f, 0xf3, 0xa9, 0x79, 0x5f, 0x31, 0xcb, 0xa3, 0x11, 0x94, 0x6a, 0xf0, - 0x94, 0x68, 0x68, 0xeb, 0x1d, 0x29, 0x35, 0xcb, 0x8c, 0xef, 0xdf, 0x9d, - 0x1c, 0x71, 0xa3, 0x74, 0x44, 0x43, 0xc9, 0x48, 0xc8, 0x89, 0x0a, 0x03, - 0x5b, 0xc6, 0xde, 0x71, 0xe4, 0xc6, 0xbb, 0xb0, 0x30, 0x6e, 0xb1, 0x71, - 0xf7, 0x5b, 0x89, 0xd3, 0x56, 0x91, 0x56, 0xf2, 0x05, 0x87, 0xa1, 0x05, - 0xf6, 0x02, 0xa7, 0x57, 0x44, 0xfd, 0xe8, 0xa2, 0xcd, 0xce, 0xd0, 0x7e, - 0xe2, 0x41, 0x45, 0x2b, 0xcc, 0xb1, 0x1a, 0xf1, 0x07, 0xac, 0x4f, 0x58, - 0x56, 0x91, 0x71, 0xf7, 0xdd, 0x2c, 0xe7, 0xdd, 0x8b, 0x5a, 0x2c, 0xf4, - 0x62, 0xed, 0xfa, 0xe8, 0xaf, 0x95, 0x7d, 0x03, 0xcb, 0x61, 0x0e, 0xaf, - 0xe6, 0x47, 0x05, 0xaa, 0xae, 0xbe, 0xda, 0x71, 0xe3, 0x72, 0x74, 0x0f, - 0xb3, 0xaf, 0xa9, 0x18, 0xed, 0x53, 0x6c, 0x6b, 0x35, 0x36, 0x0d, 0x3f, - 0x04, 0x73, 0xf7, 0x4a, 0x96, 0x91, 0x31, 0x75, 0xf1, 0xbb, 0x15, 0x8f, - 0x8d, 0x89, 0x7c, 0xe9, 0xc6, 0xe5, 0xe4, 0xbf, 0x63, 0x2d, 0xf4, 0x89, - 0x7c, 0x27, 0x36, 0x26, 0xec, 0x79, 0x51, 0x68, 0x9f, 0xe1, 0x13, 0xb4, - 0x95, 0x6e, 0xdd, 0x40, 0x4f, 0xaa, 0x19, 0x1b, 0x53, 0xb1, 0x20, 0xd1, - 0x80, 0xf3, 0xd6, 0x06, 0xd5, 0x08, 0xb5, 0x76, 0x41, 0x7c, 0x02, 0x4a, - 0xa9, 0x01, 0x67, 0x36, 0x3a, 0xe9, 0x7e, 0x31, 0xa1, 0xb5, 0x3f, 0xae, - 0xb8, 0x10, 0xaf, 0x92, 0x36, 0x26, 0xdd, 0x2f, 0x27, 0x14, 0xfc, 0x52, - 0x0b, 0x75, 0xbc, 0xab, 0x4c, 0xba, 0x5f, 0xca, 0x7a, 0x51, 0x9b, 0x0c, - 0xb6, 0x9b, 0x4a, 0x33, 0x9e, 0xc9, 0xfa, 0xe0, 0x4f, 0x1a, 0x38, 0x90, - 0xd5, 0xb1, 0xff, 0x22, 0x9f, 0xb9, 0xec, 0x9f, 0xe9, 0x60, 0x5f, 0x57, - 0x26, 0x02, 0xe8, 0xd2, 0xcf, 0x59, 0x31, 0x2f, 0xe2, 0x95, 0xc6, 0xa4, - 0xfb, 0x83, 0x24, 0x94, 0x0a, 0x43, 0xf3, 0x8f, 0x2a, 0xbf, 0xb0, 0xe2, - 0x3e, 0x29, 0xc6, 0xfe, 0x8d, 0xc9, 0x58, 0x97, 0x50, 0xef, 0x06, 0xe7, - 0xfd, 0xb4, 0x55, 0xc6, 0x39, 0x2b, 0x32, 0xae, 0xc4, 0xf0, 0x80, 0x86, - 0xfd, 0x1c, 0xeb, 0xfb, 0xfa, 0x78, 0xb3, 0x07, 0x5a, 0xdb, 0x7b, 0x08, - 0xc6, 0x66, 0x2b, 0x06, 0x8e, 0x66, 0x35, 0x0c, 0x25, 0x0c, 0x1c, 0x4a, - 0xd4, 0x7b, 0xbb, 0x31, 0x17, 0x31, 0x7f, 0x0e, 0x1f, 0x47, 0xd8, 0xef, - 0xc1, 0x50, 0x1b, 0x2a, 0x8d, 0x66, 0x4c, 0xb0, 0xdf, 0xa7, 0xe6, 0x89, - 0x1c, 0x1d, 0x2f, 0xfd, 0x09, 0x7d, 0x15, 0xbd, 0x3e, 0xca, 0xbe, 0x36, - 0xcf, 0x3d, 0x67, 0x61, 0x9a, 0x1b, 0xc7, 0xf5, 0x2b, 0x88, 0x47, 0x30, - 0x4b, 0x0c, 0xb7, 0xb3, 0x27, 0xe1, 0xc5, 0xbe, 0xac, 0xc7, 0xd9, 0x9d, - 0xf0, 0x61, 0x77, 0x36, 0x80, 0x5a, 0x03, 0xa6, 0x9f, 0x72, 0x6b, 0xe9, - 0x4b, 0xa3, 0x03, 0x75, 0x18, 0x1b, 0x08, 0xea, 0x2f, 0x13, 0x7b, 0xf6, - 0x0e, 0x5d, 0x89, 0x91, 0x01, 0x05, 0xc3, 0x21, 0xf6, 0x9d, 0xbf, 0x9f, - 0x18, 0xb8, 0x1a, 0xd9, 0x01, 0x07, 0xb6, 0xd8, 0x7a, 0xb5, 0xfd, 0x30, - 0xff, 0x7d, 0x25, 0x32, 0x43, 0x70, 0xce, 0x4e, 0x7a, 0xf1, 0x78, 0xd6, - 0xe9, 0xd4, 0x92, 0x3e, 0x0c, 0x65, 0xbf, 0xce, 0x79, 0x13, 0xd9, 0x01, - 0x0c, 0x26, 0xfe, 0x9a, 0xbf, 0x65, 0x1c, 0xb7, 0x2b, 0xf9, 0xd8, 0x41, - 0xcc, 0x0e, 0x10, 0x4f, 0x5b, 0xd0, 0x95, 0x72, 0x60, 0x85, 0x8d, 0xeb, - 0x29, 0x3e, 0x6b, 0xa1, 0xcd, 0x17, 0xe4, 0x0a, 0xbe, 0x07, 0x88, 0xbd, - 0x47, 0xe9, 0x03, 0x51, 0xda, 0xbf, 0x8e, 0xff, 0x33, 0xd6, 0x88, 0x7f, - 0x1c, 0x0b, 0xe3, 0x7b, 0x63, 0x1a, 0xfe, 0x81, 0xb8, 0xf4, 0xf4, 0xd8, - 0x54, 0xff, 0xbf, 0x9b, 0xe3, 0x13, 0x1f, 0x34, 0xb0, 0x2e, 0x55, 0x84, - 0x0d, 0x03, 0xa5, 0xe8, 0x1e, 0xa8, 0x0f, 0x1f, 0xa2, 0xdd, 0x7c, 0x4f, - 0xff, 0x1c, 0xc6, 0xab, 0x29, 0x83, 0xfe, 0xbb, 0x89, 0xf7, 0x37, 0x0f, - 0xd4, 0x53, 0xef, 0x96, 0xa5, 0x46, 0x1a, 0x9a, 0x27, 0x88, 0x59, 0x93, - 0xbe, 0x60, 0x60, 0x5c, 0x0d, 0x06, 0x62, 0x70, 0x21, 0xd1, 0xa8, 0xc2, - 0x9c, 0x1e, 0xcc, 0x98, 0xc4, 0x4d, 0x9f, 0x76, 0xb5, 0x22, 0xd8, 0x66, - 0xaa, 0x06, 0x6d, 0x8e, 0x78, 0xa7, 0xc6, 0xe8, 0x13, 0xa5, 0xf8, 0x60, - 0x20, 0xd8, 0x63, 0xaa, 0x77, 0xc1, 0xac, 0xb6, 0xac, 0xef, 0x44, 0xd0, - 0x71, 0x85, 0x81, 0xd8, 0x74, 0x62, 0xc8, 0xd5, 0xc6, 0x12, 0x10, 0x9f, - 0x71, 0x2a, 0xa9, 0xf9, 0x7f, 0xa2, 0xdc, 0x8d, 0xaf, 0xb7, 0x05, 0x03, - 0x01, 0xb5, 0xc1, 0xdc, 0xad, 0x36, 0xd3, 0xd4, 0x11, 0xf0, 0x1b, 0xb7, - 0x61, 0x8d, 0x3d, 0x56, 0x05, 0x5e, 0x2d, 0x86, 0xee, 0x14, 0x2b, 0xf9, - 0xea, 0xdb, 0xfb, 0xd4, 0xfa, 0x33, 0xba, 0x1a, 0x3c, 0xda, 0xa6, 0x12, - 0x2f, 0xe6, 0x9e, 0xb2, 0x02, 0x35, 0x96, 0xd5, 0x34, 0x57, 0xda, 0x0c, - 0xa0, 0x9a, 0x73, 0x53, 0xc5, 0xb9, 0x69, 0x1a, 0x2d, 0xc5, 0xbb, 0x03, - 0x30, 0xaf, 0x30, 0x82, 0xad, 0x0f, 0xaa, 0xa5, 0x78, 0x67, 0xa8, 0x14, - 0x6f, 0x0e, 0x38, 0x71, 0x72, 0xc0, 0xb2, 0xee, 0xd5, 0x2b, 0x51, 0x14, - 0xc1, 0xf4, 0x22, 0x84, 0x4e, 0x0f, 0xc2, 0xc4, 0xef, 0x59, 0xf6, 0x37, - 0x03, 0x7e, 0xfc, 0xdb, 0xc0, 0x67, 0xf0, 0x74, 0x75, 0xec, 0xd8, 0x34, - 0xf8, 0x70, 0x86, 0x73, 0x7e, 0x2a, 0x11, 0x6c, 0xaf, 0x75, 0x04, 0xd7, - 0x00, 0x0d, 0xab, 0x1e, 0x56, 0x82, 0xf1, 0x97, 0x95, 0x60, 0x20, 0xa9, - 0xf8, 0xf0, 0x1e, 0x6d, 0xeb, 0x44, 0xb6, 0xbe, 0xf9, 0x35, 0xb6, 0xff, - 0x5b, 0xfd, 0x7b, 0xd6, 0x78, 0x8d, 0xe8, 0x50, 0xf4, 0x45, 0x9d, 0xa7, - 0xa8, 0x73, 0xe2, 0xee, 0xf7, 0x52, 0xd4, 0x39, 0xfb, 0xf3, 0xf4, 0x1f, - 0xe0, 0xa0, 0xcc, 0x57, 0x33, 0x7d, 0xfd, 0x2a, 0xfc, 0x9d, 0x3d, 0xb6, - 0x63, 0xd6, 0xff, 0xf0, 0xc9, 0xf8, 0x7e, 0x34, 0x3d, 0xe7, 0xe3, 0x32, - 0xce, 0xa3, 0x56, 0xdc, 0x2b, 0x63, 0x94, 0xb1, 0xda, 0xba, 0x0c, 0x74, - 0x28, 0xd3, 0x55, 0x94, 0x5a, 0xd6, 0x56, 0x3d, 0xff, 0xdc, 0x57, 0x18, - 0xeb, 0xbf, 0xd2, 0x0e, 0x64, 0xbc, 0x6b, 0x1d, 0xa2, 0xfb, 0x80, 0xfa, - 0xaa, 0xf8, 0xbf, 0x19, 0x43, 0xb9, 0x47, 0x62, 0x60, 0xec, 0xfc, 0xf5, - 0x53, 0x15, 0x17, 0x3f, 0xa7, 0x6d, 0xd9, 0xed, 0xfd, 0x3b, 0xaf, 0x65, - 0x2c, 0xaf, 0xd0, 0x6e, 0xc4, 0x4e, 0x38, 0x9d, 0x86, 0xd8, 0xcc, 0xa5, - 0xf6, 0x22, 0xb6, 0xd2, 0x48, 0xbb, 0xfa, 0x17, 0x62, 0x62, 0x07, 0x9e, - 0xbc, 0xde, 0x2d, 0xd3, 0x1c, 0x70, 0x18, 0x26, 0x3e, 0x1f, 0x75, 0xe0, - 0xab, 0x51, 0x05, 0xd3, 0xb4, 0x60, 0x06, 0xaa, 0x69, 0x55, 0x91, 0x5b, - 0x6c, 0xe8, 0x4d, 0x63, 0xc3, 0x18, 0x50, 0xd9, 0x0b, 0x77, 0x85, 0x61, - 0xe0, 0xa5, 0x24, 0xdc, 0x65, 0xf4, 0xcb, 0x2f, 0x27, 0xeb, 0xc7, 0xdf, - 0x56, 0x82, 0xb1, 0xd7, 0xa9, 0x4f, 0xea, 0xb5, 0xcd, 0xaf, 0x04, 0x5b, - 0x57, 0x2b, 0xc1, 0xe6, 0xd9, 0x0a, 0xdc, 0x0a, 0xcb, 0x85, 0xb3, 0x69, - 0xa4, 0xc6, 0xe4, 0x77, 0x33, 0x66, 0x65, 0xfb, 0xf2, 0x7d, 0x14, 0x3f, - 0x06, 0x8e, 0xd0, 0xbf, 0x87, 0x9a, 0x15, 0xe2, 0xc9, 0x3b, 0x56, 0xcc, - 0x47, 0xf9, 0x29, 0xb8, 0x4b, 0x59, 0xe7, 0xb6, 0x64, 0x1a, 0x8c, 0x99, - 0xee, 0x12, 0xd6, 0xb9, 0x36, 0x09, 0x78, 0x7a, 0x05, 0xf3, 0x83, 0x81, - 0x6b, 0x94, 0xfa, 0xf6, 0xa4, 0x12, 0x0c, 0xdf, 0xae, 0x34, 0xe8, 0x4f, - 0x90, 0xb7, 0x6c, 0x40, 0xae, 0x8d, 0x50, 0x36, 0x27, 0xbf, 0x3e, 0x0b, - 0x65, 0x46, 0x12, 0x9e, 0x5a, 0x6d, 0x26, 0xce, 0x4e, 0xb3, 0xdb, 0x51, - 0x2a, 0x93, 0x01, 0x3b, 0x96, 0x56, 0x8e, 0x00, 0x2f, 0xf5, 0x5b, 0x38, - 0x14, 0xa9, 0xa7, 0xbf, 0xb5, 0xc1, 0xcf, 0x32, 0x39, 0x5b, 0xb4, 0xb1, - 0x42, 0xe9, 0x49, 0xd0, 0xe9, 0xa6, 0xcb, 0xa5, 0x0f, 0xf1, 0xcf, 0x23, - 0x26, 0xf7, 0x76, 0x26, 0xa0, 0xf4, 0x26, 0x82, 0x3b, 0x01, 0x6d, 0x4d, - 0x95, 0x23, 0xf6, 0x40, 0x25, 0x3a, 0x31, 0x11, 0x09, 0xc5, 0x07, 0x95, - 0x50, 0x7b, 0xbf, 0xa2, 0xbb, 0xb7, 0xb0, 0xbd, 0xcd, 0x2c, 0xb3, 0x81, - 0x9f, 0x45, 0x21, 0xad, 0xf5, 0x43, 0xc4, 0xae, 0x2d, 0x61, 0x99, 0x43, - 0x7a, 0xe8, 0xcc, 0x6e, 0x84, 0x8e, 0xfe, 0xda, 0xa1, 0xbb, 0x1f, 0xcd, - 0x8a, 0xac, 0x66, 0x65, 0x68, 0xf4, 0x26, 0x35, 0xe7, 0xfb, 0xff, 0x33, - 0xaf, 0x83, 0xaf, 0xcb, 0xb5, 0xdd, 0xb6, 0x33, 0x79, 0xb4, 0xf4, 0x0f, - 0xef, 0x71, 0x92, 0x2e, 0xba, 0xd7, 0xe0, 0x1d, 0xa2, 0xdf, 0x38, 0xb4, - 0x12, 0xfa, 0xb9, 0xf0, 0x95, 0x58, 0xd8, 0x05, 0xb9, 0xe7, 0x40, 0xc6, - 0x19, 0xf3, 0x3b, 0xf0, 0x9f, 0x56, 0x6c, 0x99, 0xdc, 0x2b, 0x45, 0xbc, - 0xad, 0xc1, 0xef, 0x44, 0x43, 0xf3, 0x7a, 0xfa, 0xf0, 0xe4, 0xb2, 0x05, - 0x7c, 0x16, 0xd2, 0x0f, 0xa1, 0x3e, 0xb0, 0x1e, 0xf2, 0xfb, 0x2c, 0x6d, - 0x6d, 0x81, 0xd4, 0x65, 0x99, 0x1c, 0x27, 0x13, 0x8c, 0x58, 0xa7, 0x5b, - 0x78, 0x56, 0x87, 0x59, 0x6c, 0x1c, 0x50, 0x8e, 0x27, 0x7e, 0x6f, 0xc5, - 0x9c, 0x58, 0x42, 0x7f, 0xd2, 0x35, 0x05, 0x01, 0xb7, 0x11, 0x0a, 0x1c, - 0x25, 0xfb, 0xa4, 0x6d, 0x28, 0x93, 0xd9, 0x75, 0xca, 0x5b, 0xd9, 0x1e, - 0xe5, 0x44, 0x56, 0xea, 0x1e, 0x50, 0xde, 0xcc, 0x4a, 0xec, 0xa9, 0x0b, - 0x1c, 0x61, 0x2c, 0x65, 0x1c, 0x57, 0xbb, 0xc9, 0xda, 0x36, 0xe8, 0x15, - 0xe4, 0x8e, 0x5a, 0x78, 0x90, 0xfd, 0xdd, 0x13, 0x85, 0xbe, 0x51, 0x77, - 0x61, 0xd2, 0x0b, 0x4f, 0xb7, 0xee, 0x94, 0x6b, 0xc6, 0x34, 0xa9, 0x5b, - 0x17, 0x58, 0x9f, 0x3d, 0x47, 0xbf, 0xc8, 0x5d, 0xef, 0x89, 0x16, 0xee, - 0x7d, 0x64, 0x8d, 0x2f, 0x53, 0x79, 0xfd, 0xa2, 0x8c, 0x9b, 0x75, 0xa7, - 0x72, 0x45, 0x89, 0xdb, 0x2a, 0xb9, 0x69, 0x15, 0x4c, 0x6f, 0xd0, 0xcc, - 0x60, 0x09, 0x7d, 0xe7, 0x30, 0xb9, 0xac, 0x9f, 0x71, 0x69, 0x09, 0xb1, - 0x54, 0x78, 0x98, 0xc2, 0xe7, 0x1e, 0xdc, 0x92, 0xf8, 0x87, 0x3c, 0xc7, - 0x65, 0x6c, 0xae, 0x71, 0x08, 0x9f, 0xf4, 0xca, 0xdc, 0x1e, 0x4c, 0x4d, - 0xe5, 0x7e, 0x75, 0x81, 0x93, 0xec, 0x77, 0x89, 0xa6, 0x85, 0x4b, 0x94, - 0xba, 0xc0, 0x5b, 0xd9, 0x25, 0xf4, 0xcd, 0x77, 0xd9, 0xae, 0x07, 0x6f, - 0x25, 0x2a, 0xc8, 0x6b, 0x83, 0x31, 0x93, 0x02, 0x6f, 0x25, 0x2f, 0x20, - 0xbf, 0x98, 0xf2, 0xd7, 0x06, 0xc6, 0x5a, 0x89, 0x87, 0xea, 0xa2, 0x79, - 0xcd, 0x58, 0x95, 0x85, 0x73, 0x65, 0xd4, 0xc0, 0xbd, 0x8c, 0xa3, 0xf7, - 0x33, 0x36, 0xad, 0x66, 0xdc, 0xd9, 0x12, 0xe1, 0xd8, 0xaa, 0x2c, 0xab, - 0x58, 0xeb, 0x14, 0x8e, 0x8c, 0x24, 0xe3, 0xde, 0x3d, 0x9a, 0x13, 0xeb, - 0xf8, 0xfb, 0xc5, 0xec, 0x7f, 0x58, 0xf7, 0x93, 0xa3, 0x3f, 0x7b, 0x91, - 0x4c, 0xa8, 0x43, 0x5a, 0x43, 0x78, 0x3d, 0xe3, 0x1e, 0xe5, 0x9a, 0x15, - 0x86, 0x65, 0x5d, 0x1b, 0x0a, 0xc6, 0x5c, 0x8a, 0x8e, 0x43, 0x23, 0x93, - 0x56, 0x60, 0xba, 0xf0, 0xf3, 0x42, 0x6c, 0x90, 0xb1, 0x16, 0xf8, 0x9f, - 0x70, 0xbd, 0xa9, 0x3e, 0xad, 0xe2, 0xd6, 0x01, 0xe1, 0xa6, 0x7e, 0x2c, - 0x4d, 0x7c, 0x0b, 0x87, 0x1a, 0x9d, 0x68, 0x25, 0x6f, 0x5f, 0x94, 0xf0, - 0xe0, 0x2e, 0x62, 0xe0, 0xe2, 0x44, 0x31, 0xe7, 0xc6, 0x87, 0xdb, 0x12, - 0x4e, 0x1c, 0x6e, 0x9c, 0x06, 0xd3, 0x57, 0x8c, 0xf7, 0x74, 0x07, 0x8e, - 0xe8, 0x5e, 0x64, 0x6c, 0x7f, 0xd8, 0x42, 0xec, 0x0a, 0xe6, 0xf9, 0xa2, - 0xe8, 0xd0, 0x41, 0x7d, 0xaa, 0x88, 0x9f, 0xd7, 0xe1, 0xe5, 0xb8, 0x60, - 0x81, 0x07, 0x7e, 0x68, 0xc5, 0xa7, 0x4b, 0x7d, 0x98, 0x1e, 0x43, 0xc6, - 0x21, 0x5c, 0x4a, 0x47, 0xf7, 0x48, 0x8c, 0x9c, 0x67, 0xea, 0x50, 0x4f, - 0x93, 0xc7, 0x55, 0xe2, 0x75, 0x4d, 0x78, 0xdc, 0x2b, 0xf0, 0xd2, 0x77, - 0x7b, 0x46, 0x42, 0x1d, 0xa7, 0x15, 0x07, 0x5e, 0xd4, 0x2a, 0xe2, 0x6e, - 0xfa, 0xf4, 0xc6, 0x11, 0x38, 0xd7, 0xcf, 0xd3, 0xd1, 0x3b, 0xd2, 0xd5, - 0x5c, 0x0e, 0x12, 0x9b, 0x79, 0x39, 0xfe, 0xf1, 0x65, 0xea, 0x76, 0x45, - 0xc4, 0xe6, 0x1f, 0xb9, 0xd8, 0xeb, 0xb5, 0x2c, 0xe6, 0x0c, 0xd4, 0x33, - 0xb0, 0x2f, 0xaf, 0xe3, 0x3d, 0xfc, 0xdd, 0x93, 0xd7, 0xf1, 0x3a, 0xca, - 0xa3, 0xff, 0x61, 0xc3, 0x45, 0x9c, 0x21, 0x80, 0x62, 0x43, 0x30, 0x88, - 0xf8, 0x49, 0x3c, 0x89, 0x51, 0xc7, 0xcf, 0x65, 0x7f, 0xc7, 0xb1, 0x06, - 0x39, 0xdd, 0x62, 0x4f, 0x8c, 0x85, 0xea, 0x67, 0x1c, 0xc4, 0x55, 0xea, - 0x41, 0xf4, 0x2c, 0xfa, 0xb5, 0xac, 0x7e, 0x5d, 0x74, 0x2c, 0xfa, 0x16, - 0xbd, 0xe7, 0xf0, 0x93, 0x7c, 0xbf, 0x07, 0x48, 0xb3, 0xac, 0x83, 0x78, - 0x69, 0xe0, 0xbb, 0x6d, 0x62, 0x3b, 0xe5, 0x76, 0x8c, 0x9b, 0x33, 0xd3, - 0xb2, 0x9e, 0x8a, 0x04, 0xf0, 0xbe, 0xd6, 0xd0, 0xdc, 0xa4, 0x06, 0xd9, - 0xd7, 0x25, 0x48, 0x8c, 0xc5, 0x38, 0x77, 0x57, 0x93, 0x87, 0x8b, 0xad, - 0xa1, 0xa3, 0xc8, 0xc6, 0x5c, 0xe0, 0x44, 0x42, 0x0b, 0x6f, 0xe0, 0x9c, - 0xed, 0xf6, 0x2d, 0x23, 0x67, 0x52, 0x5b, 0x98, 0xb5, 0x90, 0xab, 0x68, - 0xe6, 0x26, 0xbc, 0x6b, 0x65, 0x7c, 0x16, 0xe3, 0x9b, 0x0a, 0xa7, 0x36, - 0x03, 0x87, 0xbd, 0x0e, 0x3c, 0x1f, 0xae, 0x41, 0xac, 0x4a, 0x41, 0x99, - 0xf6, 0x4b, 0xeb, 0x05, 0x9f, 0xb4, 0xc3, 0x7c, 0x43, 0xfd, 0x39, 0xfb, - 0xad, 0xb0, 0x8c, 0xc8, 0x5d, 0x86, 0xae, 0xb1, 0x4b, 0xdb, 0xff, 0x85, - 0x35, 0xe9, 0x93, 0xf6, 0x83, 0xde, 0x80, 0xfa, 0x49, 0x73, 0xf8, 0xaa, - 0xf5, 0x5a, 0x4e, 0xa6, 0x1d, 0x7f, 0xa0, 0x8a, 0xbc, 0xc7, 0x39, 0x3e, - 0x91, 0x59, 0x68, 0x47, 0xfc, 0x6c, 0x3f, 0xef, 0xc9, 0x33, 0xb1, 0x91, - 0x75, 0x6c, 0xf7, 0x90, 0x85, 0x1a, 0xb9, 0xde, 0x6c, 0x97, 0x35, 0xc7, - 0x26, 0x16, 0x3b, 0x31, 0x1f, 0xb3, 0x22, 0x0b, 0x16, 0xca, 0x58, 0x54, - 0x23, 0x16, 0x70, 0xc3, 0xac, 0x71, 0x10, 0x8b, 0xdf, 0x6e, 0x6c, 0xc4, - 0xc2, 0xec, 0xa4, 0xf5, 0x2e, 0xc1, 0xa5, 0x4b, 0x73, 0x60, 0x9c, 0xe3, - 0xdb, 0xaf, 0x4b, 0x6e, 0x68, 0x61, 0x51, 0xc4, 0x8c, 0xd3, 0x63, 0xcd, - 0x72, 0xda, 0x4e, 0xa9, 0x26, 0xf1, 0xb9, 0x02, 0x65, 0x86, 0x33, 0xfc, - 0x2e, 0x82, 0xfa, 0x16, 0xf2, 0x93, 0x40, 0xd5, 0xac, 0x66, 0x17, 0xb5, - 0xfb, 0x52, 0x22, 0xd4, 0x7c, 0x44, 0xc9, 0xf9, 0xc3, 0x73, 0x9c, 0xdb, - 0xd7, 0x13, 0xda, 0x9a, 0x62, 0x47, 0xee, 0xfa, 0xe5, 0xac, 0xe4, 0x23, - 0x05, 0x7f, 0xf0, 0xe7, 0x71, 0xc3, 0xed, 0x3e, 0x91, 0xc0, 0x69, 0x95, - 0xf8, 0x53, 0x65, 0xe0, 0x74, 0xb7, 0x9e, 0x51, 0x5c, 0x5a, 0x05, 0x71, - 0x55, 0xb0, 0xb4, 0x88, 0x31, 0x41, 0x62, 0xb6, 0xdb, 0xfd, 0x2e, 0xcb, - 0x2c, 0x8e, 0x60, 0x32, 0x7c, 0x63, 0x43, 0xb3, 0x1b, 0x31, 0xb3, 0x98, - 0x7e, 0x59, 0x6e, 0xf8, 0xdc, 0x73, 0x46, 0xcd, 0x1a, 0x0f, 0xed, 0xba, - 0xcc, 0x40, 0xcb, 0xac, 0xde, 0xd6, 0x4a, 0x54, 0x34, 0x62, 0xf5, 0x88, - 0xe4, 0x96, 0x7d, 0x35, 0x2a, 0xfb, 0xea, 0xd2, 0xca, 0xe1, 0xaa, 0x5e, - 0x3d, 0x5f, 0x35, 0x7e, 0x80, 0xb6, 0xa8, 0xbb, 0x45, 0x1f, 0x9d, 0x9a, - 0xe3, 0x08, 0x46, 0x9a, 0x35, 0x95, 0xc4, 0xc7, 0x0a, 0x43, 0xf2, 0x9b, - 0x40, 0xcb, 0xcb, 0x36, 0x7e, 0x7a, 0xc9, 0xc7, 0x7f, 0xe6, 0xff, 0xf3, - 0xeb, 0x3c, 0x4f, 0x1d, 0x4b, 0x9b, 0xf2, 0x2d, 0xb9, 0x26, 0x9c, 0xcc, - 0x1d, 0xd1, 0x35, 0xec, 0x61, 0x7e, 0x21, 0x73, 0x03, 0x77, 0x91, 0x11, - 0xfe, 0xcb, 0x67, 0xe9, 0x17, 0x2e, 0xea, 0x78, 0x93, 0x66, 0x12, 0xce, - 0x2d, 0x4b, 0x8b, 0x04, 0xfd, 0x45, 0x4a, 0x00, 0x1b, 0x1b, 0x7f, 0x47, - 0x5b, 0x00, 0xf1, 0x0a, 0x24, 0xab, 0x35, 0x58, 0x37, 0x5c, 0x31, 0xa5, - 0xde, 0xbe, 0xf3, 0xf5, 0x92, 0x9a, 0x19, 0x97, 0x7a, 0x43, 0x91, 0x60, - 0xfb, 0x06, 0xd6, 0xdb, 0xcc, 0x7a, 0x31, 0xc6, 0xc8, 0x7b, 0xe9, 0x9b, - 0x2e, 0xe6, 0x37, 0xeb, 0x99, 0xeb, 0x4c, 0x69, 0xef, 0xaf, 0x0a, 0xf5, - 0x1e, 0xd5, 0xcc, 0x71, 0xbb, 0xbd, 0xb9, 0xc1, 0x35, 0x45, 0x8e, 0x00, - 0x7a, 0x59, 0x6f, 0x9c, 0xf5, 0xde, 0x1a, 0xa9, 0xce, 0x97, 0x77, 0x62, - 0xc3, 0xac, 0x5c, 0xd9, 0x1e, 0xcd, 0xf4, 0x4b, 0x59, 0x67, 0x24, 0xd8, - 0x7c, 0x1f, 0xb1, 0xba, 0x4b, 0xda, 0x60, 0xdf, 0xde, 0xb2, 0xe3, 0x0a, - 0x6e, 0x7a, 0x21, 0x91, 0x9a, 0x74, 0x6a, 0x5a, 0xdb, 0x4a, 0x25, 0xa6, - 0x2c, 0x9e, 0x67, 0xcf, 0xef, 0x4d, 0xc7, 0xb2, 0x9d, 0xd8, 0xa8, 0x4d, - 0x44, 0x8a, 0x59, 0xef, 0x88, 0x36, 0xe1, 0x77, 0xd1, 0xd7, 0x56, 0xb2, - 0xed, 0x2e, 0xe6, 0x15, 0x2a, 0x7d, 0x7b, 0xdd, 0xb0, 0xf0, 0x01, 0x9d, - 0x7c, 0xa3, 0x8e, 0x76, 0x28, 0xfa, 0x91, 0x36, 0x65, 0x9e, 0x45, 0x17, - 0xc1, 0xf0, 0xb0, 0xad, 0x0b, 0xa5, 0x7a, 0x5f, 0x23, 0x8d, 0xa5, 0x8a, - 0xfc, 0xab, 0x51, 0x62, 0xa2, 0x42, 0x3c, 0xbe, 0x12, 0x1b, 0xec, 0x3c, - 0xad, 0x8e, 0x5c, 0xc7, 0xb2, 0xf6, 0xe8, 0x96, 0xf5, 0xac, 0x3e, 0x03, - 0xfb, 0xf4, 0x60, 0x5c, 0x6c, 0xf3, 0x97, 0xfa, 0x82, 0x6b, 0x5d, 0x08, - 0x32, 0xe1, 0xff, 0x14, 0xc6, 0x69, 0x2f, 0x25, 0x9a, 0xf8, 0xa0, 0x02, - 0x7f, 0xc8, 0x19, 0x28, 0x53, 0x2c, 0xb8, 0xe7, 0xce, 0x5c, 0x33, 0x93, - 0x7a, 0xaa, 0xb8, 0x51, 0xc1, 0x07, 0x73, 0x14, 0x4c, 0xcc, 0x09, 0xf9, - 0x07, 0x95, 0x72, 0xe2, 0x6d, 0xa8, 0xad, 0x45, 0x31, 0x8f, 0xb2, 0x6e, - 0xac, 0xd1, 0xc1, 0x7c, 0x5a, 0xa9, 0x24, 0x16, 0xcc, 0x0a, 0x08, 0x1d, - 0x70, 0x26, 0x43, 0xfe, 0xcd, 0xfc, 0x76, 0x8c, 0x28, 0x18, 0xd1, 0x82, - 0x31, 0xd8, 0xf2, 0xd9, 0x76, 0x44, 0xc1, 0x75, 0x21, 0xcb, 0x3a, 0x16, - 0x69, 0xf0, 0x1e, 0xc3, 0x2f, 0x2d, 0x59, 0x4b, 0xf1, 0x87, 0xce, 0xe7, - 0x06, 0x28, 0x4d, 0x6a, 0xb1, 0x16, 0x65, 0xbb, 0x53, 0x38, 0xc5, 0xaa, - 0xac, 0xc4, 0xc8, 0x42, 0x7f, 0x0b, 0xb1, 0xd2, 0xb2, 0x7e, 0xa9, 0xe7, - 0x64, 0x79, 0xa3, 0xc2, 0xcd, 0x66, 0x60, 0x4c, 0x0b, 0xb6, 0x8e, 0x53, - 0x07, 0x7e, 0xfa, 0x60, 0x2d, 0xe7, 0x7d, 0xd2, 0x15, 0xf4, 0x4e, 0x2a, - 0x0b, 0xcf, 0xaa, 0x98, 0xbd, 0xea, 0x31, 0xa5, 0xa1, 0xa3, 0x04, 0x5a, - 0x6c, 0x54, 0xb9, 0x82, 0x3a, 0x31, 0xfd, 0x1e, 0x04, 0xbd, 0x2b, 0x61, - 0xc7, 0x6d, 0xdc, 0x9e, 0x70, 0xc6, 0xce, 0xa0, 0x9e, 0xfe, 0xa0, 0xb5, - 0xdf, 0x4f, 0x6e, 0x07, 0x7c, 0x96, 0x84, 0x5f, 0xfa, 0x5a, 0x83, 0xf8, - 0x5f, 0x58, 0xd6, 0x03, 0xec, 0xeb, 0x16, 0xf6, 0x75, 0x75, 0xe4, 0x7d, - 0xeb, 0x17, 0xb6, 0xcc, 0x9b, 0x31, 0xa8, 0x5d, 0x2a, 0xf7, 0x3d, 0x0b, - 0xd3, 0x45, 0xae, 0x0b, 0xb7, 0x4e, 0x67, 0xee, 0x11, 0x15, 0x2c, 0x79, - 0x84, 0xf9, 0xb9, 0xc8, 0x63, 0x5c, 0x51, 0x2f, 0x8d, 0xcd, 0x0e, 0x30, - 0xe6, 0xf9, 0xe3, 0x8a, 0x5a, 0x57, 0x06, 0x2f, 0xdc, 0x9a, 0x85, 0x07, - 0xc9, 0x23, 0x62, 0xd3, 0x2b, 0xf1, 0x90, 0xee, 0x46, 0x79, 0x48, 0xbd, - 0xd2, 0xc1, 0x39, 0xd9, 0x17, 0x91, 0x6b, 0x17, 0xc6, 0xa7, 0x3b, 0xd0, - 0x49, 0x7e, 0xe1, 0x0d, 0xa9, 0xb5, 0x72, 0xdf, 0xdd, 0x24, 0xd7, 0xec, - 0xff, 0x15, 0x0a, 0x1e, 0xa0, 0x55, 0xa8, 0xa1, 0x2e, 0xbf, 0xdc, 0x6f, - 0xd5, 0xe5, 0x5a, 0x41, 0x7d, 0xc4, 0xc9, 0x79, 0xb1, 0xe0, 0x60, 0xdf, - 0x4b, 0x43, 0xbc, 0x1f, 0x91, 0xdf, 0xb1, 0x07, 0x38, 0xee, 0xd8, 0x6e, - 0x45, 0xb0, 0xe7, 0xc7, 0xd6, 0xf3, 0x8c, 0x2d, 0x5e, 0x3e, 0x7f, 0x88, - 0x6d, 0x1f, 0x8d, 0x3c, 0x6b, 0xd5, 0x12, 0x73, 0x8f, 0x35, 0x07, 0x30, - 0x63, 0x4e, 0x1d, 0x26, 0xef, 0x96, 0x31, 0x2b, 0x28, 0xd7, 0xca, 0x5d, - 0x92, 0xe7, 0x55, 0x68, 0x57, 0xe0, 0xd6, 0xbb, 0x72, 0xf7, 0x4a, 0x28, - 0x2f, 0x4c, 0xdc, 0x2d, 0x99, 0x53, 0x8d, 0x40, 0xfe, 0xde, 0xc2, 0x90, - 0xb3, 0xad, 0x5c, 0xd1, 0xbc, 0xb7, 0x2b, 0xf2, 0xfc, 0x37, 0xb4, 0x71, - 0xcb, 0x7a, 0x90, 0xf3, 0x35, 0x2b, 0xe2, 0xc1, 0x29, 0xb6, 0xd3, 0x45, - 0xfd, 0x2d, 0x39, 0x3f, 0x5f, 0x85, 0xfa, 0xbf, 0xb6, 0x02, 0x7f, 0x21, - 0x75, 0x45, 0xc6, 0xcc, 0xd6, 0x5b, 0x95, 0xe7, 0x9c, 0x92, 0x33, 0xac, - 0x8e, 0xd8, 0x3a, 0x63, 0xd9, 0x5a, 0x97, 0x5c, 0x7b, 0xa3, 0xaf, 0x9f, - 0x5f, 0x7f, 0x39, 0x6d, 0xc7, 0xa8, 0x05, 0x37, 0x7a, 0x31, 0x69, 0x55, - 0x35, 0x99, 0xde, 0x62, 0x48, 0xac, 0xaa, 0x0f, 0x3f, 0x45, 0xb9, 0xaf, - 0xe9, 0xb9, 0x38, 0xb6, 0x47, 0x0f, 0xa6, 0x4d, 0xfa, 0x43, 0x9c, 0x39, - 0x5f, 0x8b, 0xbd, 0x56, 0xb4, 0x87, 0xf3, 0x30, 0x03, 0xc5, 0x4d, 0xc1, - 0x9e, 0x6b, 0x98, 0x03, 0x39, 0xa2, 0x12, 0xff, 0x64, 0x7e, 0xec, 0x32, - 0x6c, 0xab, 0x04, 0x0b, 0xd9, 0xc7, 0x48, 0xd3, 0x1f, 0x8b, 0x1d, 0x22, - 0x47, 0xac, 0x33, 0xd8, 0x13, 0xc3, 0x1f, 0x2b, 0x0b, 0x46, 0x6a, 0xc4, - 0x1d, 0x86, 0xfb, 0xa6, 0x78, 0x56, 0x25, 0xf7, 0x28, 0xf2, 0x76, 0x45, - 0x6b, 0xf8, 0x91, 0xe7, 0xce, 0x9b, 0x56, 0x64, 0xcf, 0xaf, 0x29, 0x21, - 0xad, 0x17, 0x41, 0xbd, 0x4e, 0x70, 0x9c, 0x88, 0xec, 0x95, 0xf1, 0x99, - 0xcd, 0x5e, 0x3b, 0x87, 0x5e, 0xfb, 0x85, 0x7b, 0xb4, 0xa0, 0xfe, 0x26, - 0x5b, 0x3c, 0x4c, 0x8e, 0x63, 0xda, 0x9e, 0x21, 0xbe, 0x3e, 0x15, 0x47, - 0x25, 0xae, 0x88, 0x4c, 0xc1, 0xd0, 0x2b, 0xd1, 0xb7, 0xa3, 0x03, 0x81, - 0x9a, 0x1c, 0x66, 0xb9, 0x8c, 0xb9, 0xd8, 0x93, 0xde, 0xec, 0xca, 0xf1, - 0xf2, 0x4e, 0x3c, 0x45, 0x4c, 0xdb, 0xb8, 0x63, 0xa2, 0xb6, 0x8a, 0xba, - 0xea, 0xd0, 0x1b, 0xf4, 0xd3, 0xb8, 0x83, 0x7e, 0x2e, 0x65, 0x27, 0xbe, - 0x52, 0x05, 0x29, 0x67, 0xe1, 0x48, 0xa4, 0x06, 0xc9, 0x1d, 0x9f, 0x46, - 0x66, 0xba, 0xdc, 0x97, 0x7b, 0x6e, 0xe2, 0xb0, 0x0f, 0xeb, 0x77, 0xf8, - 0x91, 0xf1, 0xc9, 0x5a, 0x99, 0xac, 0x57, 0x0a, 0x36, 0xbf, 0x61, 0x99, - 0x5e, 0xe9, 0x87, 0xc4, 0xf7, 0x50, 0x73, 0x37, 0x63, 0x9a, 0xd7, 0x88, - 0x11, 0x3f, 0xc8, 0x3d, 0x46, 0x7f, 0x62, 0x65, 0x6c, 0x0e, 0xef, 0x36, - 0x85, 0x23, 0x3d, 0xab, 0x35, 0xc4, 0x8e, 0xb0, 0x07, 0xf1, 0xec, 0x7f, - 0xd2, 0x47, 0x9c, 0xb8, 0x47, 0xfb, 0xb8, 0xfe, 0x7b, 0xd8, 0x3f, 0xb8, - 0x9d, 0xc4, 0x76, 0xf2, 0x48, 0x62, 0x70, 0xc8, 0x25, 0x31, 0xbf, 0x88, - 0xed, 0x6f, 0xd9, 0xa1, 0xa0, 0x85, 0x18, 0xb8, 0x99, 0x36, 0xf5, 0x40, - 0x08, 0xce, 0xd6, 0x39, 0xe4, 0x35, 0xf8, 0x02, 0x73, 0x1a, 0x1f, 0x36, - 0x0d, 0x63, 0x6e, 0x56, 0x1b, 0xaf, 0xf5, 0xa0, 0xc7, 0x25, 0xdc, 0xd6, - 0x24, 0xde, 0xe7, 0xe4, 0xec, 0xbb, 0x44, 0x4e, 0x0d, 0x1e, 0xcd, 0xcb, - 0xd9, 0x49, 0x39, 0x9f, 0x9e, 0x05, 0x67, 0xc5, 0xa7, 0x65, 0x2e, 0x17, - 0xd2, 0xbf, 0x6a, 0x90, 0xb2, 0xe3, 0x04, 0x79, 0xe0, 0x67, 0xa0, 0x68, - 0x33, 0x25, 0x67, 0x58, 0x6a, 0xd7, 0xbb, 0xa5, 0x71, 0xfc, 0x4c, 0x15, - 0xc1, 0xf5, 0xf4, 0xac, 0x71, 0x3a, 0x72, 0x41, 0x27, 0xde, 0x42, 0x5f, - 0xff, 0xea, 0x42, 0x1b, 0x1c, 0x33, 0xed, 0xcb, 0x1d, 0x95, 0xbe, 0x3d, - 0x6e, 0xb5, 0x7a, 0x73, 0x73, 0x95, 0xd8, 0x11, 0x0c, 0xb4, 0x51, 0xe7, - 0x5b, 0xf4, 0xfa, 0xb6, 0x34, 0x29, 0xcc, 0x03, 0x73, 0x3e, 0x4d, 0xdf, - 0xf7, 0x63, 0xf3, 0x30, 0x6e, 0x18, 0xd1, 0x24, 0xc6, 0x8c, 0x07, 0xcb, - 0x2f, 0x9a, 0x83, 0xab, 0xa9, 0xef, 0x6a, 0xca, 0x27, 0xbf, 0x9b, 0x55, - 0xe8, 0x3b, 0xfb, 0x41, 0xfc, 0x7e, 0x74, 0x87, 0xe4, 0xc2, 0x75, 0xe4, - 0x58, 0x96, 0x75, 0x90, 0x63, 0x68, 0x9e, 0xd5, 0xb0, 0xe6, 0xb8, 0xa3, - 0x16, 0x93, 0xd3, 0xaf, 0xc4, 0xce, 0x61, 0x89, 0x3f, 0x01, 0xd6, 0x6d, - 0xaa, 0xcc, 0x71, 0x1b, 0xb8, 0x6e, 0xe5, 0x58, 0x0f, 0xe7, 0xc7, 0xe1, - 0xd2, 0xc4, 0x26, 0x9a, 0xb0, 0x67, 0xe0, 0xfc, 0xf3, 0xe0, 0x2d, 0xda, - 0x78, 0xd0, 0xf5, 0x07, 0xb6, 0x32, 0xce, 0xef, 0x0a, 0x89, 0x33, 0x17, - 0xe9, 0x75, 0xdd, 0xf0, 0x69, 0x7e, 0x57, 0x33, 0x2e, 0xe6, 0xfa, 0xbd, - 0x6e, 0xf8, 0x5f, 0x79, 0x2d, 0x7d, 0xb7, 0xb0, 0xce, 0xce, 0x63, 0x8a, - 0x18, 0xdf, 0x04, 0x9b, 0xc5, 0xae, 0x6b, 0x24, 0x8f, 0x6b, 0xce, 0x40, - 0x62, 0xb3, 0xd8, 0xf2, 0x80, 0xd8, 0x72, 0xd8, 0xa1, 0x00, 0x43, 0xe7, - 0x6d, 0xb9, 0x13, 0x3f, 0xd0, 0x26, 0xee, 0x2a, 0xc6, 0xc4, 0x17, 0x65, - 0xad, 0xb8, 0x23, 0x82, 0x63, 0x8b, 0x88, 0x13, 0x6f, 0xe9, 0x05, 0xbd, - 0x8a, 0x3e, 0x05, 0x43, 0x15, 0x14, 0xd3, 0x66, 0x36, 0x50, 0x8f, 0x45, - 0xaa, 0x9f, 0xed, 0x5e, 0x8a, 0xa5, 0xd2, 0x7f, 0x1d, 0x7b, 0x12, 0x13, - 0x0f, 0x17, 0xe3, 0x7f, 0x49, 0x5e, 0xf4, 0xc6, 0x09, 0xca, 0xb9, 0x45, - 0x17, 0xfd, 0x89, 0xee, 0x0a, 0x32, 0xae, 0x44, 0xef, 0x8e, 0x42, 0x5d, - 0x05, 0x2f, 0x86, 0xfc, 0xf9, 0xb5, 0xd8, 0x2b, 0x91, 0x1c, 0x9e, 0x38, - 0x46, 0x2e, 0x44, 0x7d, 0x4e, 0xac, 0xf1, 0xb3, 0x2f, 0xa7, 0x23, 0x05, - 0xfb, 0x11, 0x9c, 0x98, 0x2a, 0x43, 0xfc, 0x03, 0x4a, 0xc5, 0x4c, 0xac, - 0xab, 0xa0, 0x1f, 0x64, 0x43, 0x88, 0x97, 0x19, 0x35, 0x48, 0x0c, 0xd3, - 0xcf, 0x47, 0x8a, 0xe0, 0xbc, 0x5e, 0xec, 0x5e, 0xf8, 0x98, 0xf3, 0xa6, - 0xe3, 0x89, 0x22, 0x7c, 0x49, 0x3f, 0x67, 0x09, 0x46, 0x1f, 0xd3, 0x70, - 0x55, 0x11, 0xf5, 0x34, 0x33, 0x12, 0x8a, 0xad, 0x24, 0x3f, 0x38, 0xd2, - 0xe8, 0xbc, 0xe9, 0x64, 0xf6, 0xb7, 0xe4, 0xbe, 0x97, 0x8e, 0x45, 0xf4, - 0x81, 0x17, 0x17, 0x87, 0x72, 0x73, 0x4e, 0xde, 0x9f, 0xf7, 0x07, 0x69, - 0xdf, 0xb2, 0x42, 0x11, 0x1f, 0xed, 0xe2, 0xc2, 0x18, 0xde, 0xd6, 0x0a, - 0x63, 0xf0, 0x31, 0xb6, 0x2f, 0x21, 0xb7, 0x16, 0xde, 0xef, 0x66, 0x9e, - 0xeb, 0x64, 0xbe, 0xd0, 0x06, 0xe1, 0xa3, 0x47, 0xc9, 0xab, 0xf6, 0x27, - 0x80, 0x77, 0xd3, 0x16, 0x16, 0x44, 0xca, 0x89, 0x75, 0x3d, 0x94, 0x2d, - 0xeb, 0xab, 0x07, 0x94, 0x61, 0xe6, 0xc2, 0x93, 0xce, 0x92, 0x98, 0xca, - 0xdc, 0x77, 0x5f, 0x36, 0xe4, 0x9f, 0x60, 0x1e, 0xec, 0x66, 0x2e, 0x4e, - 0xcd, 0x29, 0xfb, 0x99, 0x07, 0xef, 0xce, 0xe7, 0xc1, 0xfb, 0xb2, 0x1e, - 0x64, 0x69, 0xbc, 0x5b, 0x22, 0xcc, 0xbf, 0xed, 0x75, 0x04, 0x0f, 0xc6, - 0xd2, 0x2a, 0x4e, 0x45, 0x3e, 0xb0, 0xc6, 0xab, 0x64, 0xcc, 0x3e, 0x3c, - 0x93, 0xa8, 0xc6, 0x81, 0x81, 0x3a, 0x9c, 0xcd, 0x3e, 0x52, 0x84, 0xd2, - 0x2b, 0x71, 0x66, 0xa8, 0x02, 0x23, 0x03, 0x9b, 0xf9, 0xbb, 0x11, 0x1f, - 0x0c, 0xd9, 0x39, 0x38, 0xb1, 0x59, 0xfa, 0x77, 0x40, 0x99, 0xb0, 0x73, - 0x70, 0x33, 0xc6, 0xdc, 0xbb, 0xb9, 0x27, 0x9f, 0x7b, 0x8f, 0x33, 0xf7, - 0x3e, 0xc2, 0x36, 0x9f, 0xcb, 0xb7, 0x79, 0xc8, 0xfe, 0x96, 0xbe, 0x48, - 0xdd, 0xa9, 0xf5, 0x9a, 0x59, 0x0f, 0x18, 0x4e, 0x84, 0xc2, 0x85, 0xba, - 0xcf, 0xb1, 0xde, 0x91, 0xf3, 0xf5, 0x72, 0x39, 0x35, 0x79, 0x31, 0x36, - 0x24, 0xec, 0x75, 0x1f, 0xea, 0x23, 0x4c, 0x5d, 0x48, 0x8e, 0x49, 0x7e, - 0x9e, 0xfd, 0x16, 0xf9, 0xfc, 0x9e, 0x22, 0x54, 0x54, 0x61, 0x61, 0x46, - 0xd6, 0xb3, 0x4b, 0x98, 0xfb, 0x15, 0xf4, 0x1f, 0x47, 0x32, 0xb5, 0x8a, - 0xfe, 0x05, 0xb7, 0xc7, 0xc8, 0xfe, 0x55, 0x82, 0xf3, 0xf0, 0x44, 0x68, - 0xbc, 0xad, 0x1c, 0x95, 0x58, 0x15, 0xb1, 0xf9, 0x23, 0x79, 0x60, 0xb0, - 0x79, 0x09, 0xe3, 0x9c, 0x23, 0x14, 0x64, 0xcc, 0x02, 0x42, 0x23, 0xcc, - 0x6f, 0xb2, 0x95, 0xb8, 0x87, 0x79, 0xa6, 0x5a, 0x15, 0x47, 0xcf, 0xf9, - 0x35, 0x4e, 0xf9, 0x5e, 0x85, 0xee, 0x31, 0x91, 0x17, 0x67, 0xee, 0x50, - 0x86, 0x45, 0xb9, 0x35, 0x19, 0xb7, 0x9b, 0xb2, 0xdd, 0xa1, 0xf1, 0x30, - 0x5d, 0x50, 0xdf, 0xc7, 0x1b, 0x87, 0x12, 0x0a, 0x16, 0x68, 0x2e, 0xac, - 0xf4, 0x56, 0x62, 0x81, 0xfe, 0x3b, 0x6b, 0xd1, 0x32, 0x79, 0x76, 0x61, - 0xad, 0xb4, 0x98, 0xed, 0xfe, 0x92, 0xf9, 0xc2, 0xb0, 0x78, 0x67, 0x36, - 0x77, 0xdf, 0xcc, 0x52, 0x36, 0xe5, 0x6e, 0xa0, 0xdc, 0xfb, 0xbc, 0x76, - 0x2e, 0x9f, 0x2f, 0x37, 0x1e, 0x76, 0x30, 0x3e, 0x49, 0xd9, 0x16, 0xca, - 0xbd, 0x87, 0x72, 0x7b, 0xbc, 0xd2, 0xbf, 0xdf, 0x59, 0xf7, 0x2d, 0x93, - 0x67, 0xb9, 0x75, 0x91, 0x9c, 0xdc, 0xac, 0xc8, 0xd5, 0x87, 0xf3, 0x6d, - 0x4d, 0x24, 0x98, 0xec, 0x11, 0xb3, 0x57, 0x44, 0x43, 0x81, 0x2e, 0x7b, - 0x4d, 0x3c, 0x80, 0x95, 0xd9, 0x00, 0xee, 0xa5, 0xde, 0x33, 0xce, 0xc2, - 0x98, 0xec, 0x3e, 0x99, 0x92, 0x17, 0x2c, 0x64, 0xb9, 0xee, 0x3c, 0x7e, - 0xb7, 0x64, 0xc5, 0xfe, 0x26, 0xf3, 0xf9, 0xa4, 0xc4, 0xb1, 0xba, 0x3c, - 0x16, 0x38, 0xf1, 0x64, 0xe2, 0x37, 0xe7, 0xfa, 0x52, 0x12, 0x97, 0x65, - 0xad, 0x27, 0x80, 0x74, 0xf6, 0x2a, 0xd4, 0xf7, 0x7b, 0xb1, 0x42, 0x9f, - 0x46, 0x9c, 0xf8, 0xd6, 0x79, 0x7b, 0xdc, 0xc7, 0x76, 0xe0, 0xb2, 0xc5, - 0x2b, 0x4f, 0x66, 0x1b, 0xbc, 0xd5, 0xc4, 0xba, 0x83, 0x17, 0xc5, 0xd7, - 0x19, 0xb1, 0x32, 0x23, 0xd4, 0xf6, 0x02, 0xe7, 0xbd, 0xc4, 0xce, 0x1b, - 0xd6, 0x29, 0x19, 0xce, 0xfd, 0xe3, 0xf9, 0xb9, 0xdf, 0x9f, 0x45, 0x71, - 0x0e, 0xdb, 0xae, 0xc2, 0xac, 0x7e, 0xf9, 0xf6, 0xe2, 0xed, 0x68, 0x29, - 0xef, 0x5d, 0x85, 0x99, 0x83, 0x57, 0x17, 0xe7, 0xf6, 0xc2, 0x64, 0x7d, - 0xe1, 0xd2, 0x1c, 0x2a, 0xd8, 0x63, 0xe2, 0x3d, 0xda, 0x44, 0x1d, 0x75, - 0x26, 0x18, 0x2b, 0xfd, 0xda, 0x74, 0xbe, 0x5f, 0x4f, 0xb0, 0x5f, 0x71, - 0x97, 0xac, 0xff, 0x4a, 0xbf, 0x94, 0x58, 0x85, 0x51, 0x87, 0x0f, 0x92, - 0xf0, 0x7a, 0x8d, 0x50, 0xfc, 0x25, 0xfa, 0xca, 0x08, 0xfb, 0x5a, 0x85, - 0x1e, 0x25, 0x6b, 0xef, 0xfd, 0x1c, 0x60, 0x99, 0xa9, 0x7c, 0x40, 0xfa, - 0xe9, 0xa4, 0xcd, 0xfd, 0x25, 0x71, 0x58, 0x27, 0x0e, 0x8b, 0xfc, 0x77, - 0xc8, 0x79, 0xbb, 0x29, 0x7f, 0x09, 0xe7, 0xcf, 0x2d, 0x7b, 0x54, 0x66, - 0xa9, 0xd1, 0x66, 0x73, 0x6e, 0x27, 0x7d, 0x76, 0x01, 0x6d, 0x6a, 0x7f, - 0x46, 0xc1, 0x10, 0x95, 0x7e, 0x34, 0x2d, 0x6b, 0xd7, 0x7e, 0xec, 0xcb, - 0xb8, 0xf0, 0x5c, 0xba, 0x16, 0xc3, 0x99, 0x22, 0x1c, 0x4a, 0x5f, 0x89, - 0xdd, 0x19, 0x22, 0x67, 0xfa, 0x2a, 0x0c, 0x66, 0xdc, 0x78, 0x23, 0x4d, - 0x3d, 0x65, 0x4a, 0xf0, 0xd3, 0xf4, 0xa7, 0xf0, 0x4c, 0xa6, 0x14, 0xaf, - 0xa7, 0xaf, 0xc6, 0x81, 0x4c, 0x19, 0x5e, 0x4e, 0x93, 0x17, 0x67, 0x3c, - 0x78, 0x29, 0x1d, 0xc0, 0x68, 0xa6, 0x1c, 0x2f, 0xa6, 0x83, 0x18, 0xc9, - 0x54, 0xe0, 0x07, 0xe9, 0x6b, 0x90, 0xcd, 0x54, 0xe2, 0x85, 0x74, 0x3d, - 0x9e, 0xa0, 0x0f, 0x3c, 0x9f, 0xd6, 0xf0, 0x78, 0xa6, 0x0a, 0xc7, 0xd2, - 0x21, 0xb6, 0xeb, 0xc3, 0xd1, 0x81, 0x30, 0xf6, 0x0d, 0xd5, 0xe0, 0xb9, - 0x81, 0xd9, 0x18, 0x1e, 0xf2, 0xe3, 0xd0, 0x40, 0x23, 0x76, 0x0f, 0x8d, - 0xdb, 0xfa, 0x39, 0x92, 0x68, 0x39, 0xaf, 0xc7, 0x0d, 0x1f, 0x33, 0xdf, - 0xaf, 0x24, 0x44, 0x6f, 0x6e, 0xb3, 0x8a, 0x73, 0xf4, 0x64, 0xd6, 0x9e, - 0x77, 0x68, 0xfd, 0x6d, 0xf4, 0x33, 0x0b, 0xdd, 0xfa, 0x95, 0xcc, 0x47, - 0x7b, 0x24, 0x1e, 0xd1, 0x16, 0x0e, 0x28, 0x1b, 0x6d, 0x0c, 0xaa, 0x88, - 0x95, 0x53, 0x97, 0x1c, 0xb6, 0xb7, 0x8c, 0xfe, 0x9c, 0x26, 0x16, 0x98, - 0x9c, 0xd7, 0x44, 0xf6, 0x80, 0xb2, 0x85, 0xf9, 0xef, 0xb5, 0xfd, 0xa6, - 0x55, 0x6a, 0x63, 0x71, 0x28, 0x36, 0x9b, 0x3e, 0x17, 0x1e, 0x14, 0x7d, - 0x96, 0x17, 0x89, 0x3e, 0x8b, 0xb4, 0xcb, 0xd9, 0x49, 0x41, 0xef, 0x3f, - 0x2e, 0xca, 0xd9, 0xc3, 0xdf, 0x17, 0xe7, 0x72, 0xc9, 0xc2, 0xbc, 0x5b, - 0x56, 0x9f, 0x5e, 0x98, 0x7b, 0xf2, 0xd8, 0x6a, 0x59, 0x6f, 0x03, 0x63, - 0x48, 0x15, 0x79, 0x8e, 0xac, 0x45, 0x4c, 0xc5, 0x1b, 0xc4, 0x8a, 0x8d, - 0x50, 0x60, 0x96, 0x7a, 0x51, 0xfe, 0xea, 0x75, 0xd8, 0xf6, 0x67, 0xda, - 0x98, 0x75, 0xf8, 0x3c, 0xf6, 0x4c, 0x14, 0x4b, 0x0c, 0xdd, 0x93, 0x90, - 0xbe, 0x41, 0x2d, 0x92, 0x3e, 0x23, 0x77, 0x0f, 0xa3, 0xb2, 0x9e, 0x77, - 0x39, 0xbb, 0x53, 0xb1, 0x72, 0xc0, 0x89, 0x2e, 0xfd, 0xbf, 0x48, 0xcc, - 0x64, 0x3f, 0xea, 0xe8, 0x6f, 0x2a, 0xfe, 0x76, 0x80, 0xf1, 0x25, 0x72, - 0x37, 0x4c, 0xe2, 0xad, 0x6b, 0xd4, 0x89, 0x15, 0x89, 0x65, 0x7c, 0xee, - 0x86, 0x3a, 0x4a, 0x56, 0xd1, 0xeb, 0x36, 0x2b, 0x68, 0x33, 0xb2, 0xff, - 0xd2, 0x3c, 0x66, 0xe2, 0xf0, 0x3c, 0x3f, 0x52, 0x09, 0x59, 0x3f, 0x5d, - 0x82, 0x9d, 0xa9, 0xd0, 0xaa, 0xb3, 0x8a, 0x1f, 0xc9, 0xac, 0x0b, 0x26, - 0xe7, 0xbe, 0x9b, 0x7d, 0xf3, 0xf4, 0x7a, 0xd1, 0x3d, 0x54, 0xcd, 0xcf, - 0xc4, 0x67, 0x3d, 0xc4, 0xea, 0x6e, 0xce, 0x6d, 0xf7, 0x90, 0x07, 0x47, - 0xf7, 0xb8, 0x51, 0x96, 0x82, 0xf2, 0xec, 0x3c, 0xa2, 0x8d, 0xd6, 0x88, - 0x17, 0x46, 0x3c, 0x28, 0x25, 0xa7, 0x7d, 0x7e, 0xc4, 0x8b, 0x92, 0xad, - 0xb4, 0x87, 0x5d, 0x55, 0x28, 0xde, 0xea, 0xc6, 0x73, 0x99, 0x6a, 0xb8, - 0xb6, 0xde, 0x81, 0xf5, 0x99, 0x69, 0x50, 0xb7, 0x56, 0x63, 0x62, 0x97, - 0x0f, 0x33, 0x76, 0x18, 0x78, 0x63, 0x4f, 0x0d, 0x6a, 0x77, 0xdc, 0x8c, - 0x9f, 0xee, 0xf1, 0xa3, 0x92, 0xba, 0x79, 0x79, 0xc4, 0x29, 0xfc, 0x93, - 0xf3, 0x74, 0xa0, 0x38, 0xbf, 0x6f, 0x1c, 0xbb, 0x94, 0xaf, 0x42, 0x29, - 0xcc, 0x0d, 0x90, 0xc9, 0xca, 0xfa, 0x68, 0x63, 0x4b, 0x77, 0x62, 0xe4, - 0x5f, 0x8b, 0x8d, 0x5f, 0xfd, 0x9f, 0xb7, 0xa3, 0x0d, 0xc4, 0x32, 0xf1, - 0xff, 0x15, 0xab, 0x4b, 0x8c, 0x8e, 0x87, 0xc3, 0xf3, 0x8a, 0xb1, 0xca, - 0x9e, 0x8f, 0x95, 0xe4, 0x80, 0xcb, 0xd1, 0xbd, 0xa3, 0xa1, 0xed, 0x1e, - 0xc5, 0x87, 0x58, 0x55, 0x3f, 0xef, 0xa9, 0x79, 0x9f, 0x82, 0x2a, 0xf9, - 0xba, 0xac, 0x99, 0xa9, 0xa3, 0x8b, 0xf2, 0x7b, 0xa0, 0x3e, 0x7b, 0x0d, - 0xaa, 0x3b, 0x55, 0xd0, 0xe3, 0x98, 0x65, 0xda, 0xfb, 0x5a, 0xe2, 0xe3, - 0x4e, 0xac, 0x4c, 0x8c, 0x32, 0x47, 0x11, 0x5d, 0x4a, 0x5f, 0x37, 0x52, - 0x8e, 0xf4, 0x57, 0x9e, 0x37, 0xc4, 0xaa, 0x3e, 0xb6, 0xbf, 0x85, 0x71, - 0x75, 0xb3, 0xfc, 0x67, 0xdd, 0x28, 0x95, 0xb2, 0xd2, 0xf7, 0x7a, 0xfe, - 0x96, 0xfe, 0x5a, 0xd6, 0xc6, 0x8b, 0xe2, 0x54, 0x51, 0xac, 0x94, 0x71, - 0x6a, 0x7f, 0x22, 0x14, 0x7b, 0x97, 0x78, 0x76, 0x2c, 0xeb, 0x24, 0xf7, - 0x11, 0xbb, 0x59, 0x47, 0x7b, 0xe9, 0x51, 0x8e, 0x9e, 0xb7, 0x99, 0x42, - 0x2e, 0xb0, 0x04, 0xe9, 0xd4, 0x54, 0x5f, 0x92, 0xfd, 0x6e, 0x27, 0x5c, - 0xbd, 0x05, 0xdc, 0x64, 0xac, 0x19, 0x25, 0xbf, 0xcb, 0x3a, 0xe0, 0xe8, - 0xa7, 0x3d, 0xe8, 0x2a, 0xc7, 0x58, 0xc4, 0x39, 0xaf, 0xe6, 0xc7, 0x6d, - 0x56, 0x1a, 0x26, 0x4e, 0xcd, 0x2b, 0xc1, 0xa1, 0x5d, 0x57, 0xa1, 0xbc, - 0x7f, 0xdc, 0xf2, 0xf0, 0x5e, 0xa9, 0x31, 0x1f, 0x4f, 0x44, 0x42, 0xad, - 0xab, 0x15, 0x13, 0xad, 0xf3, 0xdc, 0x28, 0xd9, 0xe5, 0x40, 0x71, 0x3f, - 0x79, 0x83, 0x7e, 0x03, 0xc6, 0x7d, 0x39, 0x3c, 0x57, 0x7b, 0x67, 0xdb, - 0x76, 0x75, 0xcd, 0xa8, 0xdb, 0xf4, 0x1b, 0x13, 0x37, 0xaa, 0x8c, 0xed, - 0xc5, 0xc3, 0x1e, 0x14, 0xf5, 0x9a, 0x98, 0x71, 0x83, 0xe0, 0x51, 0x23, - 0x8a, 0x68, 0xaf, 0xae, 0x5e, 0x1f, 0xf3, 0xea, 0x3a, 0xb8, 0xc8, 0xed, - 0x1c, 0xdb, 0x0d, 0x38, 0xc8, 0xc3, 0xd4, 0xed, 0x37, 0x43, 0x65, 0xd9, - 0x13, 0x7c, 0x7e, 0x82, 0xfc, 0xf3, 0x04, 0xef, 0x9d, 0x18, 0xae, 0xe1, - 0xa7, 0x0a, 0xb5, 0xbb, 0xcb, 0x10, 0x5b, 0x2a, 0xeb, 0xac, 0x0e, 0x54, - 0xf7, 0x8b, 0x7f, 0xaa, 0xb8, 0xab, 0x49, 0x81, 0x7e, 0x1d, 0xdb, 0x9c, - 0x79, 0x39, 0x5f, 0xbd, 0xd3, 0x8d, 0x8a, 0x2e, 0xb6, 0x77, 0xa9, 0x2f, - 0x4b, 0xac, 0xba, 0x30, 0x07, 0x01, 0x55, 0x62, 0xb7, 0xcc, 0xd9, 0x27, - 0xf9, 0xbd, 0x1b, 0xce, 0x5e, 0x99, 0x6b, 0x19, 0xe3, 0x37, 0xdd, 0x39, - 0x5e, 0x7b, 0xd1, 0x5a, 0x3b, 0xb2, 0x89, 0x25, 0xd8, 0x62, 0x9f, 0x5d, - 0x08, 0xc0, 0x33, 0x12, 0x6c, 0xcd, 0xe0, 0xf4, 0xb9, 0x9e, 0x94, 0x13, - 0xf7, 0x26, 0xe5, 0x0c, 0x87, 0x9c, 0x33, 0xe0, 0x58, 0x47, 0xdc, 0x78, - 0xb0, 0xcf, 0x2d, 0x6b, 0xdc, 0x01, 0x97, 0x56, 0x8b, 0x77, 0x33, 0x82, - 0x79, 0x25, 0x38, 0x9c, 0xf6, 0xe3, 0x84, 0xfd, 0xbb, 0x94, 0x18, 0x6c, - 0xa1, 0x45, 0x2f, 0x47, 0xb7, 0xb7, 0x04, 0xc9, 0xf0, 0xcd, 0xc8, 0xdc, - 0xc5, 0x1c, 0x9a, 0xb6, 0x59, 0x41, 0x4e, 0x41, 0xb7, 0x63, 0x6e, 0xe0, - 0x40, 0x2a, 0xfc, 0x39, 0x4c, 0x56, 0x39, 0xa9, 0x3f, 0x59, 0x9f, 0x50, - 0xb1, 0x93, 0x56, 0x45, 0xfc, 0x8b, 0x89, 0xdd, 0x96, 0x27, 0x61, 0x55, - 0x18, 0x5a, 0x7c, 0x54, 0x09, 0xb5, 0xaf, 0xa7, 0xdf, 0x96, 0x8d, 0x94, - 0x11, 0x8f, 0x67, 0xa1, 0x74, 0x97, 0xd8, 0xaf, 0x87, 0xd8, 0x70, 0xbd, - 0xec, 0x07, 0x84, 0x03, 0x8a, 0x07, 0xf7, 0x0d, 0x08, 0xae, 0x2e, 0x47, - 0xd1, 0x9e, 0x0a, 0x3c, 0x9c, 0x76, 0x12, 0xfb, 0xdc, 0xa8, 0xdd, 0x25, - 0x3e, 0x5f, 0x89, 0xca, 0xad, 0x07, 0x2d, 0xbf, 0x56, 0x82, 0x4a, 0x5e, - 0x3f, 0x46, 0x5d, 0x7c, 0x90, 0xfa, 0x1a, 0x46, 0x13, 0xf5, 0x94, 0xdb, - 0xce, 0xf1, 0xf9, 0xf0, 0x5e, 0xaa, 0x91, 0xb2, 0xfd, 0x78, 0x77, 0x87, - 0x65, 0xb5, 0x44, 0x62, 0x70, 0x8e, 0x5c, 0x89, 0x5f, 0xf2, 0xf7, 0x71, - 0xbd, 0x05, 0xea, 0x48, 0x1d, 0xde, 0x4c, 0xb5, 0xc2, 0x31, 0x52, 0x81, - 0xb3, 0x5b, 0x45, 0xa6, 0x1b, 0x95, 0x7d, 0x5a, 0xf8, 0x0c, 0x6d, 0xdf, - 0xb5, 0x8b, 0x81, 0xbf, 0x46, 0xda, 0x2f, 0xcc, 0x4f, 0x8e, 0xef, 0x1d, - 0xcc, 0xcf, 0xcd, 0x38, 0x0a, 0xdc, 0xe9, 0x07, 0xd6, 0x63, 0x4c, 0x67, - 0x5c, 0xd1, 0x20, 0xba, 0xc3, 0xc7, 0x64, 0xbf, 0x9c, 0xe3, 0x8b, 0x11, - 0xf3, 0x9f, 0xb5, 0xe4, 0xdc, 0x81, 0x8b, 0xf6, 0x59, 0xac, 0x1d, 0xb2, - 0x36, 0x2e, 0x93, 0xfb, 0x3f, 0xe7, 0x9c, 0x30, 0x41, 0x31, 0x44, 0xe6, - 0x16, 0x99, 0x4b, 0xa2, 0xf1, 0xe5, 0x64, 0xfe, 0xa3, 0xf5, 0xe8, 0xf9, - 0xf2, 0xf0, 0xba, 0xec, 0x75, 0x70, 0x59, 0x87, 0x95, 0xb9, 0x94, 0xf5, - 0xca, 0x00, 0x56, 0x8d, 0x78, 0xed, 0xdc, 0xf9, 0xdd, 0x84, 0xcc, 0x9f, - 0x9c, 0xa1, 0xf1, 0x90, 0x9b, 0xe8, 0x28, 0xe5, 0xdc, 0x7d, 0x90, 0x80, - 0x72, 0x5b, 0xb4, 0x0d, 0xe5, 0xc4, 0xb5, 0x77, 0x12, 0xc1, 0x55, 0x26, - 0x12, 0x6c, 0x2b, 0x8a, 0x12, 0xd6, 0x79, 0x33, 0xe1, 0x60, 0xbc, 0x6d, - 0xe6, 0x98, 0xbd, 0xb0, 0x6c, 0xae, 0xbc, 0x0c, 0x33, 0xa8, 0xa7, 0xb3, - 0x09, 0x03, 0xb5, 0xd4, 0xd3, 0x99, 0x84, 0x13, 0x67, 0xa8, 0x97, 0x53, - 0x89, 0x00, 0x2a, 0x18, 0x98, 0x8a, 0xfa, 0x2c, 0x4c, 0xe8, 0x95, 0x72, - 0x3e, 0x02, 0x72, 0xfe, 0xc5, 0x9f, 0xd4, 0x51, 0x9b, 0xac, 0x5f, 0x53, - 0xeb, 0x70, 0x60, 0xd2, 0xe6, 0x2c, 0x4e, 0xe6, 0xcd, 0xa2, 0x1f, 0x19, - 0x93, 0x9d, 0xab, 0xb7, 0xca, 0xa1, 0xa6, 0x83, 0x1c, 0x4f, 0x40, 0x29, - 0x8c, 0x67, 0x19, 0x40, 0x59, 0xa3, 0x89, 0x30, 0x1e, 0x62, 0x5b, 0x6f, - 0x27, 0x5e, 0xc1, 0xad, 0xfc, 0x7e, 0x3f, 0xf1, 0x23, 0x2c, 0x61, 0x3f, - 0xde, 0x23, 0x6e, 0xdc, 0x1f, 0xba, 0xad, 0x04, 0xa5, 0x75, 0x58, 0x34, - 0x72, 0xfa, 0x5c, 0xb7, 0x3d, 0xce, 0x42, 0x4e, 0xe5, 0xc6, 0xfd, 0xe9, - 0xc2, 0x59, 0xa6, 0x18, 0x7d, 0x58, 0xf0, 0xd5, 0xcd, 0x1c, 0x1e, 0x68, - 0x4b, 0x7c, 0x23, 0x77, 0x4e, 0x47, 0x95, 0xcf, 0x79, 0x3d, 0x3a, 0x51, - 0xea, 0xcf, 0xfb, 0x95, 0xf4, 0xe7, 0x93, 0xca, 0x5c, 0xe0, 0xcc, 0xa3, - 0xb6, 0x7e, 0x65, 0x7d, 0x3e, 0x80, 0xeb, 0x88, 0xe7, 0x27, 0xc9, 0xa1, - 0x19, 0x93, 0xb1, 0x7a, 0xde, 0x0a, 0xf4, 0xec, 0x11, 0x9d, 0x06, 0xdb, - 0xd9, 0x87, 0xb6, 0x0c, 0x56, 0x22, 0xb9, 0xc7, 0xc3, 0x31, 0x88, 0xde, - 0xc9, 0x43, 0xf7, 0xd0, 0xff, 0xd3, 0x7f, 0x83, 0x75, 0xbb, 0xa6, 0xe1, - 0xad, 0xf4, 0x97, 0xb0, 0x9e, 0x36, 0xe4, 0xa0, 0xef, 0xac, 0xd0, 0xaf, - 0x42, 0x6e, 0x3f, 0xc3, 0xc7, 0x39, 0x78, 0x9f, 0xbe, 0xb5, 0x0e, 0xef, - 0x64, 0x67, 0x61, 0x46, 0x9f, 0x8a, 0xc9, 0x69, 0x0a, 0xed, 0x43, 0xf6, - 0x5e, 0xdc, 0xc4, 0xb7, 0xaf, 0x40, 0xdd, 0x65, 0x62, 0x7d, 0xd4, 0x8d, - 0xdd, 0xcc, 0x2d, 0x56, 0xc8, 0x7a, 0x98, 0x5d, 0xaf, 0x19, 0x7b, 0x39, - 0x17, 0x89, 0x04, 0x79, 0x8b, 0x37, 0xa7, 0xe7, 0xf8, 0xf4, 0x62, 0xd6, - 0xb9, 0xa7, 0xc4, 0xde, 0xcb, 0x50, 0x04, 0x1f, 0x44, 0xcf, 0x05, 0x1d, - 0x7f, 0x0d, 0x37, 0x26, 0xdf, 0xa7, 0x1d, 0x84, 0xc6, 0xaf, 0x75, 0xfc, - 0x4f, 0xea, 0x72, 0x1d, 0xe7, 0xf1, 0x6f, 0x30, 0x94, 0xf6, 0xd0, 0x8f, - 0x64, 0xef, 0x69, 0x2d, 0x8e, 0x6e, 0x8b, 0x33, 0x37, 0x09, 0xea, 0x19, - 0xf2, 0xfa, 0x4c, 0x95, 0x65, 0x39, 0x22, 0x71, 0x0c, 0x0e, 0x58, 0xd6, - 0x62, 0x3d, 0xd6, 0x5c, 0x42, 0xfd, 0xde, 0x8f, 0xfd, 0xac, 0xe7, 0xc3, - 0x91, 0xa1, 0x15, 0xbc, 0x2f, 0x3c, 0x78, 0x2d, 0x1e, 0xe6, 0xf3, 0x2f, - 0xe9, 0xb1, 0xf1, 0x19, 0x08, 0x72, 0xce, 0x73, 0xcf, 0xc7, 0x86, 0x56, - 0x7e, 0x4c, 0xbd, 0x0b, 0xfa, 0x7c, 0x22, 0xaf, 0xcf, 0x52, 0xea, 0xf3, - 0xf6, 0x91, 0xf7, 0xcf, 0x6d, 0x48, 0x05, 0x63, 0x19, 0xc6, 0x98, 0xb7, - 0xa8, 0xb7, 0x8d, 0xb4, 0x57, 0xe6, 0x1a, 0x38, 0x92, 0x6d, 0xa6, 0x6e, - 0x5c, 0xe4, 0x44, 0x4e, 0x1c, 0xcb, 0x1a, 0xb4, 0x4d, 0x60, 0x21, 0xe3, - 0x85, 0xe9, 0xcd, 0xd9, 0x4f, 0xe6, 0xbc, 0x3f, 0x70, 0xee, 0x94, 0x66, - 0x1c, 0x4f, 0xc8, 0xd8, 0xa5, 0x9c, 0xfd, 0x5c, 0xd6, 0x80, 0xa7, 0x94, - 0xb9, 0xd0, 0xf6, 0xee, 0x84, 0xf0, 0xf4, 0x00, 0x65, 0x15, 0x53, 0xd6, - 0xe9, 0x73, 0x9b, 0x52, 0x6d, 0xf6, 0xd9, 0x37, 0xf2, 0x1b, 0x84, 0x69, - 0xcf, 0xc5, 0x91, 0x32, 0xbc, 0xed, 0x13, 0x19, 0x39, 0x5d, 0x0a, 0x06, - 0x6e, 0x61, 0x19, 0x79, 0xfe, 0x20, 0x9f, 0xdf, 0x12, 0x29, 0xc2, 0x90, - 0xb7, 0xb0, 0xee, 0x94, 0xeb, 0x8b, 0x79, 0xbe, 0x9d, 0x6b, 0x2b, 0x73, - 0x76, 0x55, 0x5c, 0x6a, 0xef, 0x25, 0xd9, 0xdc, 0xaa, 0xee, 0x92, 0xfd, - 0x3a, 0x89, 0x7f, 0x82, 0x93, 0x39, 0x9c, 0x2d, 0xa1, 0x3d, 0x3d, 0x97, - 0x90, 0x75, 0x21, 0x93, 0x39, 0x46, 0x18, 0x8b, 0xb2, 0xf6, 0x99, 0x2e, - 0xc6, 0x37, 0xea, 0x8c, 0xbc, 0x77, 0x65, 0x54, 0xf6, 0xe3, 0x6e, 0xae, - 0x14, 0x5e, 0xd7, 0x11, 0x95, 0x7c, 0x42, 0x6c, 0xb5, 0x70, 0xcf, 0x8d, - 0x3d, 0xf9, 0x39, 0x0f, 0xa8, 0x9f, 0x84, 0xfd, 0xaf, 0x5f, 0xc2, 0xf1, - 0x0a, 0x7b, 0x5a, 0xd2, 0xaf, 0xf3, 0x5c, 0xcf, 0xe6, 0xf5, 0x43, 0xf4, - 0x37, 0xd3, 0x59, 0x46, 0x7e, 0x27, 0xbc, 0x3e, 0xa4, 0xcf, 0x52, 0x85, - 0xd3, 0x4b, 0x4e, 0x21, 0x6b, 0x7b, 0x3d, 0xca, 0xde, 0xac, 0xac, 0xef, - 0x09, 0x9f, 0xbf, 0xdc, 0x1a, 0x9f, 0x9c, 0x8d, 0x93, 0xf8, 0x78, 0xfa, - 0x5c, 0x7f, 0xaa, 0xcd, 0xde, 0x07, 0x5d, 0xd0, 0x6f, 0xe1, 0x6e, 0xc6, - 0x82, 0x7b, 0xaa, 0xed, 0x1c, 0x29, 0x9f, 0x8b, 0x9c, 0x3e, 0xb7, 0x33, - 0xf5, 0x7b, 0x4b, 0xb5, 0xf7, 0x1d, 0x5d, 0x70, 0x6c, 0xd5, 0xce, 0xac, - 0x20, 0xe7, 0x3b, 0x7b, 0x83, 0xe4, 0x25, 0x2e, 0xc6, 0xc9, 0xff, 0x52, - 0x2a, 0x7b, 0xe0, 0xe4, 0xcb, 0xb8, 0xa5, 0x3f, 0x86, 0x21, 0xfd, 0x43, - 0xcb, 0xf4, 0x4d, 0xad, 0xef, 0xc2, 0x92, 0xfe, 0xdf, 0x5b, 0xe5, 0x76, - 0x7d, 0xad, 0x3d, 0xa9, 0xa8, 0x78, 0x70, 0x9e, 0x0b, 0xb7, 0x0d, 0x86, - 0xb0, 0xb8, 0x5f, 0x45, 0x78, 0x9e, 0xc8, 0x09, 0xa1, 0x75, 0xb0, 0xde, - 0x99, 0x5f, 0xd7, 0xc1, 0x22, 0xf6, 0xe3, 0x6d, 0xbd, 0x0c, 0xaf, 0x11, - 0x77, 0x2b, 0x6c, 0x9e, 0xbd, 0x46, 0x49, 0x09, 0xcf, 0x76, 0xa9, 0x98, - 0xa6, 0xc1, 0x5b, 0x6d, 0xc4, 0xc8, 0xb1, 0x5b, 0x94, 0xad, 0x99, 0x35, - 0x4a, 0x7f, 0xb6, 0xd0, 0xbe, 0x07, 0x77, 0x8c, 0x7a, 0x71, 0xc7, 0xde, - 0x6a, 0x7e, 0x7c, 0xfc, 0xd4, 0xf0, 0xf3, 0x8d, 0xd2, 0xdc, 0xfe, 0xfc, - 0x12, 0xac, 0x4b, 0x15, 0xec, 0xca, 0xc9, 0xbc, 0x5a, 0x6c, 0x57, 0xea, - 0x04, 0xb0, 0x97, 0xfc, 0xfc, 0x64, 0x5a, 0xb8, 0xfd, 0x06, 0xea, 0x42, - 0xd6, 0x99, 0x8b, 0xc9, 0xef, 0xe5, 0x3c, 0x63, 0x24, 0xbf, 0xef, 0x9f, - 0xb3, 0x1b, 0x9c, 0xb7, 0x1b, 0x17, 0xde, 0xa1, 0x7f, 0xcf, 0x8a, 0xfc, - 0xbb, 0x35, 0xe9, 0xbd, 0x60, 0x57, 0x17, 0x9e, 0x17, 0xf8, 0xd0, 0xe9, - 0x73, 0xe9, 0xd4, 0x54, 0x7b, 0x52, 0x50, 0xd4, 0x2f, 0x7c, 0x59, 0xf4, - 0xe2, 0xc4, 0xab, 0xc4, 0x07, 0x67, 0xff, 0xc4, 0xb5, 0x42, 0xeb, 0x5c, - 0x7b, 0x63, 0xe8, 0x8e, 0x52, 0xb7, 0x83, 0xa5, 0xc5, 0x39, 0xfb, 0xc8, - 0xe9, 0x22, 0xa0, 0x0a, 0xbe, 0x78, 0x6c, 0x9e, 0x17, 0x60, 0x2e, 0xa8, - 0xee, 0x15, 0xce, 0x58, 0xcd, 0x6f, 0xe1, 0xe6, 0xe4, 0x2f, 0x7b, 0x85, - 0xa7, 0xd7, 0xf0, 0x9b, 0x24, 0xbf, 0x46, 0xec, 0x69, 0x25, 0x7a, 0x18, - 0x13, 0x8b, 0x43, 0x2b, 0xb1, 0x71, 0xf8, 0x72, 0xb6, 0x95, 0xcb, 0x77, - 0x0e, 0x5e, 0xb0, 0x6f, 0x69, 0x8f, 0x7d, 0x3a, 0x7d, 0x4e, 0x6c, 0x35, - 0xc0, 0xb9, 0xda, 0x9d, 0x96, 0x3e, 0x58, 0xe8, 0xd0, 0xc9, 0x8d, 0xe8, - 0x6b, 0x6a, 0xb5, 0xdc, 0x9f, 0xca, 0x29, 0x0b, 0xb2, 0xa6, 0xde, 0xdb, - 0x55, 0x2a, 0xeb, 0xec, 0x17, 0xc6, 0x5e, 0x68, 0x43, 0xd6, 0x55, 0x03, - 0xa8, 0xea, 0x15, 0x3d, 0xca, 0x98, 0x02, 0x70, 0x92, 0x03, 0x56, 0x8d, - 0x5e, 0x4e, 0x1e, 0x6a, 0x4a, 0xec, 0xf3, 0x83, 0x61, 0xfa, 0x99, 0xc7, - 0x2c, 0x26, 0x5f, 0x7c, 0x3b, 0x21, 0xe7, 0x32, 0x5b, 0x5b, 0x76, 0x27, - 0x66, 0x7a, 0x0f, 0xe7, 0xf3, 0xfe, 0x15, 0x70, 0x93, 0xa3, 0x9a, 0x98, - 0x88, 0x2a, 0x36, 0xde, 0x38, 0xb4, 0x10, 0x16, 0x32, 0xb7, 0xbc, 0x25, - 0x23, 0xf3, 0xb9, 0x26, 0xbf, 0x26, 0x24, 0xed, 0xc5, 0x94, 0xa1, 0xac, - 0xe4, 0x05, 0xf0, 0x3a, 0x8d, 0x16, 0x65, 0x5f, 0x46, 0xea, 0xaf, 0xe1, - 0xbd, 0xc2, 0x9e, 0xf1, 0x12, 0xf4, 0xa7, 0x0a, 0xbe, 0x55, 0xd0, 0x47, - 0x05, 0x6d, 0x55, 0xf2, 0x3e, 0x13, 0xfa, 0xf5, 0xb5, 0x68, 0x1c, 0x2c, - 0xc7, 0xed, 0xfd, 0xb9, 0xfd, 0xfa, 0x86, 0xc1, 0x6a, 0xdc, 0xb6, 0x7d, - 0x39, 0x4a, 0xf7, 0x7a, 0xb1, 0x78, 0xbb, 0xec, 0x0d, 0x2c, 0x43, 0xf1, - 0xe8, 0xaf, 0x4a, 0xed, 0x9c, 0xbb, 0xb7, 0x99, 0x73, 0xd4, 0x4c, 0xce, - 0x19, 0x6c, 0x8e, 0x41, 0xd6, 0x3a, 0x0d, 0x14, 0x8d, 0x1a, 0xe4, 0xa6, - 0x56, 0xe7, 0x0c, 0x83, 0xf3, 0xcc, 0x7e, 0x5e, 0xc3, 0xbc, 0x67, 0x16, - 0xc7, 0xee, 0xe2, 0xc7, 0xd1, 0x6b, 0x59, 0x67, 0x6f, 0x40, 0x67, 0x19, - 0xf3, 0x70, 0xc7, 0xe8, 0x55, 0x08, 0x0c, 0x36, 0xa2, 0x76, 0xb4, 0x1a, - 0xda, 0xa0, 0x0f, 0xad, 0xbd, 0xe2, 0x8b, 0xc1, 0x40, 0x5c, 0x8d, 0xc2, - 0x3d, 0xca, 0x38, 0xdd, 0xfb, 0x7b, 0xeb, 0x24, 0xe7, 0xba, 0x99, 0x3a, - 0xbb, 0xb3, 0xb7, 0x15, 0x95, 0xa3, 0xb4, 0xf3, 0xfe, 0x3b, 0x50, 0x31, - 0xe8, 0x26, 0x4f, 0x0e, 0x20, 0x4b, 0x5e, 0xec, 0x19, 0xf4, 0xa3, 0xb4, - 0x57, 0x6b, 0xbd, 0x5d, 0x41, 0x6c, 0x26, 0x73, 0xa9, 0x22, 0xb6, 0xe5, - 0xa2, 0x0f, 0x0d, 0xd2, 0x97, 0x17, 0xd2, 0xcd, 0x3b, 0x7b, 0x05, 0x77, - 0x44, 0x27, 0x67, 0x6d, 0x9b, 0x5e, 0xd9, 0x7b, 0xf9, 0x33, 0xa3, 0x38, - 0x7f, 0x66, 0xd4, 0xb4, 0xcf, 0x72, 0x56, 0x1a, 0x50, 0xce, 0xcc, 0xd2, - 0x7a, 0x6a, 0x79, 0xef, 0x43, 0xc6, 0xfd, 0xaf, 0xf6, 0x7a, 0x18, 0x7f, - 0x3a, 0xf1, 0xb9, 0xa6, 0xa0, 0x39, 0xaa, 0xbc, 0xc2, 0xf1, 0xff, 0x88, - 0x01, 0xb7, 0x8e, 0xfd, 0xfc, 0x73, 0xe5, 0x5f, 0xba, 0x26, 0x36, 0xef, - 0xa2, 0xb5, 0xb4, 0x23, 0xcc, 0x9f, 0xc7, 0x2f, 0x5a, 0x4b, 0x13, 0x2c, - 0xbd, 0xf4, 0x4c, 0x6d, 0x60, 0xca, 0xfa, 0x8c, 0xcc, 0x99, 0xcc, 0x53, - 0x61, 0x7d, 0xc6, 0x44, 0xd3, 0xf5, 0x2e, 0x2c, 0xec, 0x97, 0x9c, 0x47, - 0x62, 0x71, 0x88, 0xb9, 0xc6, 0x66, 0xce, 0x83, 0xbd, 0xae, 0xc2, 0x7b, - 0x01, 0xe2, 0x4b, 0x80, 0x39, 0x44, 0x92, 0xf7, 0x4a, 0x70, 0x5b, 0x7f, - 0xb5, 0xbd, 0x87, 0xb5, 0x38, 0x72, 0x15, 0xc2, 0x55, 0xb2, 0xbe, 0x76, - 0x61, 0x1d, 0x66, 0x0e, 0x73, 0x95, 0x32, 0x1b, 0xbb, 0x16, 0x50, 0xd7, - 0x57, 0xd1, 0x26, 0x72, 0x78, 0x75, 0xfb, 0x60, 0x0e, 0x97, 0x7a, 0xd9, - 0xff, 0x71, 0x57, 0xce, 0xde, 0xd2, 0xb4, 0x37, 0xaf, 0xd6, 0xa2, 0xa4, - 0x33, 0x0d, 0xde, 0x69, 0x97, 0x3d, 0x8b, 0x01, 0x6f, 0xa5, 0x51, 0x38, - 0x27, 0x4c, 0x4c, 0xcb, 0x3e, 0x58, 0x96, 0xcf, 0xdb, 0x3e, 0xa6, 0xfc, - 0xc7, 0xe9, 0xeb, 0xfa, 0x3f, 0x51, 0x5f, 0x72, 0xae, 0xac, 0xa0, 0x2f, - 0x6d, 0xca, 0xd9, 0x88, 0x9c, 0xce, 0xaa, 0x0d, 0x39, 0x4b, 0x78, 0x41, - 0x67, 0x77, 0x51, 0x67, 0xf5, 0xe7, 0x75, 0x76, 0x5d, 0x5e, 0x67, 0x25, - 0xd4, 0x59, 0x35, 0x71, 0x57, 0x30, 0xf9, 0x5a, 0x62, 0xf2, 0xb7, 0xec, - 0x7b, 0xb3, 0xa9, 0x97, 0x9c, 0xce, 0x34, 0xea, 0x6c, 0x2a, 0xde, 0x5f, - 0x85, 0x76, 0xe2, 0x7d, 0x05, 0xe3, 0x61, 0x99, 0x9c, 0xed, 0xba, 0xe1, - 0x2a, 0xdc, 0x39, 0x58, 0x82, 0xb9, 0x83, 0x2e, 0xea, 0xd2, 0x8e, 0x01, - 0xe4, 0xf4, 0xae, 0xf3, 0x7a, 0x6c, 0x18, 0x94, 0x71, 0xad, 0x51, 0x7e, - 0xc8, 0x71, 0x05, 0x8a, 0x72, 0x7a, 0x7c, 0x25, 0x9b, 0xeb, 0x43, 0xb5, - 0x26, 0xf1, 0xac, 0x45, 0x79, 0x35, 0x23, 0x38, 0xfb, 0x3d, 0xea, 0x6a, - 0x0d, 0x9f, 0x35, 0x78, 0x7d, 0xe0, 0x58, 0x3e, 0xf6, 0xbc, 0x9f, 0xe8, - 0xeb, 0x7b, 0xe7, 0xf5, 0xfa, 0xc7, 0xcb, 0x16, 0xec, 0x4a, 0xce, 0xfb, - 0x15, 0xf4, 0xa5, 0x4d, 0xc1, 0x48, 0xcb, 0x7a, 0x5a, 0x9f, 0x85, 0x78, - 0x75, 0x30, 0x2d, 0x6b, 0x46, 0x69, 0xf2, 0x1d, 0x47, 0xaf, 0xf4, 0x59, - 0x72, 0x03, 0xf5, 0x66, 0xb2, 0xbf, 0x46, 0x07, 0x3a, 0x71, 0x42, 0xd7, - 0x7a, 0xee, 0xc3, 0xa7, 0xd0, 0xe5, 0xb3, 0xb0, 0x47, 0x6f, 0x67, 0xee, - 0x53, 0x8a, 0x55, 0x8d, 0x34, 0xf9, 0xbb, 0x62, 0xe8, 0x4b, 0x99, 0xed, - 0x0e, 0xc8, 0x9a, 0xec, 0xf7, 0xbf, 0x90, 0x08, 0x05, 0xdb, 0x56, 0x2b, - 0xc0, 0xe2, 0xa4, 0x1b, 0x01, 0xc5, 0xe6, 0x26, 0xe1, 0x7e, 0x55, 0xd6, - 0x96, 0xb7, 0x17, 0xe5, 0xce, 0x6a, 0xa8, 0x08, 0xd4, 0x48, 0x3b, 0xed, - 0x30, 0xc7, 0xa4, 0x2e, 0xf5, 0x38, 0x53, 0xc1, 0x6d, 0x33, 0x83, 0x66, - 0x5c, 0xb1, 0xac, 0xa5, 0x11, 0xa7, 0xfd, 0x7c, 0xcb, 0x58, 0x43, 0xfc, - 0x6e, 0xf5, 0xe7, 0x96, 0x69, 0xaf, 0x67, 0x07, 0xbd, 0x31, 0xf5, 0x8f, - 0x8d, 0x93, 0x79, 0x03, 0x73, 0x84, 0xfd, 0xf9, 0x35, 0x5c, 0x97, 0x11, - 0x5e, 0xbe, 0xc7, 0x5e, 0x47, 0xfe, 0x96, 0x7d, 0x2e, 0x25, 0x9d, 0x92, - 0x35, 0xc0, 0xa8, 0x07, 0xa5, 0xed, 0xe8, 0x1a, 0xbb, 0x01, 0x23, 0x8d, - 0xbf, 0xb0, 0x32, 0xb9, 0xbe, 0x8b, 0x79, 0xbb, 0x6b, 0x8d, 0x13, 0x5f, - 0xb8, 0x71, 0x96, 0x70, 0x47, 0x39, 0x43, 0x4a, 0xde, 0xae, 0xe4, 0xb8, - 0xec, 0x0c, 0xed, 0x16, 0x1c, 0xbc, 0x48, 0xa6, 0xac, 0x31, 0x14, 0x64, - 0xb6, 0x51, 0x9e, 0xc8, 0x75, 0x51, 0x57, 0xff, 0x6e, 0x0d, 0xfa, 0xa6, - 0x96, 0xfb, 0x47, 0x77, 0x2e, 0xc6, 0x49, 0xb9, 0x42, 0xbb, 0xc2, 0xed, - 0x3e, 0xb0, 0x86, 0x2e, 0x2a, 0xf7, 0x6a, 0x9e, 0x33, 0x3d, 0xe4, 0x91, - 0x33, 0x2d, 0xe9, 0x54, 0x31, 0xf9, 0xd4, 0x09, 0x6b, 0xef, 0x45, 0x65, - 0x3e, 0xbc, 0xa4, 0x4c, 0x3d, 0x73, 0xb5, 0x7f, 0xb1, 0x86, 0x2f, 0x2a, - 0x53, 0x59, 0x7a, 0x71, 0x99, 0x6b, 0x88, 0xb3, 0xaf, 0x5a, 0xbb, 0x2f, - 0x2a, 0xf3, 0x77, 0x97, 0xc8, 0x99, 0x4b, 0x1b, 0x7f, 0xda, 0xda, 0x97, - 0x2f, 0xe3, 0x64, 0x99, 0x75, 0xda, 0x53, 0xf9, 0xbc, 0xbc, 0x50, 0xa6, - 0x70, 0xbf, 0xa4, 0xec, 0xd2, 0xfb, 0x39, 0x99, 0xe1, 0x4b, 0x64, 0x06, - 0x4d, 0x99, 0x6f, 0x57, 0x53, 0x61, 0xbe, 0xa3, 0xf9, 0xfb, 0xdf, 0x28, - 0xbb, 0xb8, 0xdc, 0xc4, 0x25, 0xd7, 0x05, 0x79, 0x7f, 0xed, 0xbe, 0xf8, - 0x7e, 0x65, 0xf1, 0xc5, 0xd7, 0xbb, 0x8b, 0x72, 0xd7, 0x05, 0x9d, 0x6e, - 0xb9, 0xe4, 0xf9, 0x7f, 0x2b, 0xba, 0xf8, 0xfa, 0xc6, 0xe2, 0xcb, 0xb7, - 0xf3, 0x93, 0x4b, 0xee, 0x2b, 0x5d, 0xf2, 0xfe, 0x89, 0xc3, 0x50, 0x2b, - 0xba, 0xa2, 0xab, 0x6e, 0x8a, 0x67, 0x7b, 0x68, 0x9f, 0x62, 0x5b, 0xab, - 0x6f, 0x5a, 0x91, 0x3d, 0x79, 0x7e, 0x8f, 0x3b, 0xad, 0x2f, 0xf0, 0x7b, - 0xf1, 0x59, 0xac, 0xb0, 0xf7, 0xd2, 0x64, 0x8d, 0xc7, 0xe4, 0x18, 0xed, - 0x77, 0x51, 0xdc, 0x8a, 0x11, 0x87, 0x6e, 0x9f, 0x07, 0x5d, 0x89, 0xfa, - 0xac, 0xbd, 0x8f, 0x17, 0x8e, 0xe3, 0xa0, 0xda, 0xaa, 0x99, 0xf9, 0x73, - 0x7e, 0xe6, 0x8d, 0x5e, 0xc4, 0xa6, 0xe6, 0xd2, 0x81, 0x61, 0xfb, 0x2c, - 0x69, 0x07, 0xba, 0xed, 0x73, 0xaa, 0xed, 0xf9, 0xf3, 0xa4, 0xcb, 0xa1, - 0x65, 0x0b, 0x7c, 0x4b, 0xd6, 0x64, 0xe5, 0x6c, 0x85, 0x45, 0x1f, 0x14, - 0xfe, 0x70, 0x40, 0x51, 0x93, 0xf6, 0xba, 0xe7, 0x32, 0x07, 0x42, 0xcd, - 0x2d, 0x0a, 0xe2, 0x25, 0x46, 0x28, 0xf0, 0x4e, 0x1e, 0x2b, 0x5d, 0x23, - 0xeb, 0x94, 0xa2, 0x91, 0x1e, 0xc5, 0x39, 0x92, 0xc3, 0x4a, 0xc7, 0x88, - 0xf0, 0xfb, 0x6a, 0x96, 0xf1, 0x62, 0xd6, 0x3c, 0x27, 0x5e, 0x48, 0x54, - 0xd8, 0xef, 0x34, 0xac, 0x9f, 0x57, 0x84, 0x07, 0x23, 0x0a, 0x5a, 0xe7, - 0x1c, 0xc6, 0x49, 0xe6, 0x32, 0x87, 0x13, 0x66, 0x64, 0x88, 0x6d, 0x4e, - 0x24, 0x54, 0x1c, 0x1a, 0x58, 0x17, 0x19, 0xb4, 0xdb, 0x37, 0xd1, 0x6d, - 0xef, 0x5b, 0x2d, 0xb3, 0x36, 0xa6, 0x96, 0x5b, 0x1b, 0x52, 0x4e, 0xe6, - 0x9f, 0xd5, 0xf1, 0x4a, 0xd6, 0x3f, 0x39, 0x6f, 0x15, 0x4e, 0xb1, 0xcc, - 0x48, 0x62, 0x35, 0x3e, 0xc8, 0x7a, 0xed, 0xf5, 0x9a, 0x1f, 0x64, 0x3d, - 0xcc, 0xa7, 0x5a, 0xf1, 0x42, 0x76, 0x19, 0x9e, 0x1f, 0x90, 0x33, 0xe4, - 0x2d, 0x58, 0x90, 0x50, 0xb0, 0x38, 0xb4, 0x0c, 0xc7, 0x86, 0x96, 0xe1, - 0xf0, 0x80, 0xbc, 0x47, 0x70, 0x45, 0xfe, 0xcc, 0xb9, 0x3c, 0x8f, 0xf1, - 0xf9, 0x52, 0x4c, 0x0c, 0xf9, 0x99, 0x0b, 0xe9, 0x78, 0x33, 0xeb, 0xc3, - 0x60, 0xa2, 0x11, 0xc7, 0xc9, 0xe7, 0x9f, 0x49, 0x34, 0xe3, 0x2c, 0xaf, - 0x0f, 0x24, 0x84, 0x07, 0x45, 0x71, 0x26, 0xfb, 0x7d, 0x14, 0x25, 0x6b, - 0x71, 0xa4, 0xed, 0x69, 0xa8, 0xc9, 0x03, 0xfc, 0xb4, 0xe2, 0xf8, 0x50, - 0x2b, 0x4e, 0x0c, 0xdc, 0x86, 0x13, 0x43, 0x3f, 0xc3, 0xc9, 0x01, 0xe9, - 0xaf, 0x9c, 0x2b, 0x17, 0xb9, 0x1a, 0xe5, 0x2e, 0xc3, 0xf8, 0xd0, 0x9f, - 0x23, 0xfb, 0x3d, 0xeb, 0xc8, 0x32, 0x91, 0xfb, 0xf4, 0x27, 0xc8, 0xce, - 0xe5, 0x4a, 0x72, 0x66, 0xf4, 0x58, 0xc2, 0x8d, 0xa3, 0x89, 0xf1, 0x6b, - 0x4b, 0x30, 0x7e, 0x23, 0x91, 0x0e, 0x1b, 0x99, 0xc3, 0x1d, 0x4a, 0xcb, - 0xba, 0xdf, 0x67, 0x98, 0x17, 0xaf, 0xc3, 0xfa, 0xb1, 0x62, 0xbc, 0x90, - 0x76, 0x53, 0xc7, 0x37, 0x22, 0x56, 0xd5, 0x4e, 0xfd, 0x79, 0xf0, 0x62, - 0xc2, 0x87, 0x97, 0x12, 0x0d, 0x8c, 0x0f, 0x4d, 0xc8, 0xad, 0x77, 0x7a, - 0xa8, 0xef, 0x0e, 0xbb, 0x4f, 0x2f, 0x24, 0x96, 0x59, 0xeb, 0xa9, 0xe3, - 0x9e, 0xd4, 0xd7, 0xec, 0x33, 0xe1, 0xcf, 0x27, 0xce, 0x30, 0x27, 0x39, - 0x8a, 0xc7, 0xa9, 0xd3, 0x63, 0x89, 0x38, 0x39, 0x63, 0x1d, 0xe7, 0x68, - 0x1c, 0x43, 0xd9, 0xb5, 0x78, 0x33, 0xad, 0x1d, 0x5d, 0x81, 0xb5, 0x38, - 0x9b, 0x29, 0xc6, 0xeb, 0x6c, 0xa3, 0x72, 0xae, 0x13, 0x93, 0xb6, 0xbc, - 0xb5, 0xf8, 0x20, 0xad, 0x30, 0x8e, 0xaf, 0xc5, 0xfb, 0x7c, 0xf6, 0x32, - 0x7f, 0x9f, 0x8a, 0xb0, 0x87, 0xf9, 0x67, 0x27, 0xc8, 0xeb, 0x65, 0x7d, - 0xab, 0x2b, 0xba, 0x16, 0xc7, 0x33, 0xcf, 0x92, 0x0b, 0x57, 0xe2, 0x61, - 0x7d, 0x1a, 0x9a, 0xa7, 0x91, 0x8b, 0x69, 0xc5, 0x38, 0xc6, 0xe7, 0x33, - 0x89, 0xbf, 0xe3, 0xde, 0x5c, 0xf9, 0xf7, 0x38, 0x9e, 0x07, 0x29, 0xeb, - 0xdd, 0xcc, 0x37, 0x29, 0x77, 0x3e, 0xb2, 0x91, 0x6f, 0x52, 0xee, 0xcf, - 0x30, 0x9c, 0xd7, 0xc7, 0x71, 0x5d, 0xc6, 0xf5, 0xf5, 0x72, 0xc9, 0xa9, - 0x27, 0x12, 0xdf, 0xe0, 0x77, 0x07, 0x26, 0xb3, 0x3b, 0xf8, 0xfd, 0x03, - 0xec, 0x63, 0x8c, 0x4e, 0xa4, 0x2e, 0xe5, 0xe3, 0xd3, 0xb1, 0xa9, 0xaf, - 0x22, 0x5e, 0x45, 0xfb, 0x89, 0x5c, 0x5f, 0x89, 0xd9, 0x91, 0x04, 0x36, - 0xef, 0x76, 0x62, 0x13, 0xf1, 0x76, 0x73, 0xb2, 0x1a, 0x3b, 0xb7, 0x79, - 0x91, 0xda, 0x76, 0x25, 0x7a, 0xb7, 0x5d, 0x8d, 0xe4, 0xb6, 0x3a, 0x6c, - 0xdc, 0x46, 0x9d, 0xcf, 0xb5, 0xac, 0x93, 0x11, 0xcb, 0x3a, 0xcc, 0xcf, - 0x5e, 0x7e, 0xde, 0xd3, 0xc5, 0x3f, 0x62, 0x08, 0xdb, 0x7e, 0xd2, 0x42, - 0x3f, 0x91, 0x6f, 0x0d, 0xd7, 0x64, 0xd7, 0x44, 0x66, 0x8e, 0xae, 0x8d, - 0x34, 0x8c, 0x4e, 0x47, 0x77, 0x5f, 0x0d, 0xd6, 0x6f, 0xab, 0x8e, 0x7b, - 0xd9, 0x8e, 0xf7, 0x7a, 0x0b, 0x9d, 0xf4, 0x9f, 0x67, 0xf4, 0x9e, 0xc8, - 0xfc, 0xd1, 0xa7, 0xc9, 0x43, 0x7d, 0xd8, 0xd9, 0xe7, 0x67, 0x1b, 0x0a, - 0x2a, 0x35, 0xe7, 0xaa, 0x4a, 0x8e, 0xe3, 0x68, 0xe4, 0x00, 0xca, 0x47, - 0xbf, 0x4f, 0x9e, 0xe7, 0xc3, 0xc6, 0xbe, 0x22, 0x79, 0x4f, 0x08, 0xbd, - 0x51, 0x0b, 0xef, 0xe9, 0xe3, 0x28, 0xa3, 0xbc, 0xae, 0xbe, 0x0a, 0x74, - 0x6f, 0xf3, 0x50, 0x66, 0x05, 0x1e, 0xdb, 0x56, 0x1a, 0x2f, 0x32, 0x44, - 0xde, 0x12, 0xfc, 0x74, 0xe4, 0x6b, 0xd8, 0x34, 0xe6, 0x41, 0x0f, 0xef, - 0xaf, 0xdb, 0xe6, 0x75, 0xbf, 0xc0, 0x3a, 0xed, 0x6c, 0xeb, 0xbf, 0xf1, - 0xf3, 0x01, 0xfb, 0x5d, 0x1c, 0x59, 0x83, 0xcd, 0x63, 0xc2, 0x6d, 0x8e, - 0xc2, 0x3f, 0xda, 0x8a, 0x97, 0x47, 0xda, 0xf0, 0xb7, 0x23, 0xff, 0xea, - 0x41, 0xc5, 0x32, 0xdc, 0x3f, 0x22, 0xfb, 0xee, 0x71, 0xdc, 0x93, 0x10, - 0x3c, 0x5a, 0x89, 0x3d, 0x09, 0xd9, 0xbf, 0x6c, 0xc7, 0xb3, 0x09, 0xb1, - 0xdf, 0xe5, 0xb4, 0xdf, 0x0e, 0xe6, 0x74, 0x92, 0x47, 0x64, 0x22, 0xf5, - 0xa3, 0xdf, 0x8e, 0x5c, 0x33, 0xfa, 0x73, 0x72, 0xf0, 0xa1, 0x48, 0x68, - 0x74, 0x27, 0xc7, 0x39, 0x49, 0x5e, 0x7d, 0x82, 0x5c, 0xfb, 0x75, 0x72, - 0xe1, 0x42, 0x1c, 0xfc, 0xaf, 0xce, 0x5c, 0x8e, 0x52, 0xc8, 0x03, 0x0b, - 0x6b, 0xed, 0x96, 0xe5, 0x60, 0x9e, 0xb3, 0xd0, 0x2b, 0xb9, 0x42, 0x17, - 0xd6, 0xef, 0x58, 0x8d, 0x0d, 0x3b, 0x1a, 0xbc, 0x7b, 0x19, 0xb3, 0x62, - 0x3e, 0xe1, 0xee, 0xf9, 0xfc, 0xee, 0xfc, 0x1a, 0x98, 0xac, 0xd9, 0x77, - 0xd0, 0xe7, 0xd7, 0xd9, 0xe7, 0x38, 0x4b, 0x35, 0x04, 0x4a, 0xb4, 0xdf, - 0x5a, 0xb1, 0xf3, 0xf5, 0xdb, 0x2d, 0x59, 0x97, 0x2d, 0x36, 0x14, 0x8c, - 0x69, 0x6d, 0xf6, 0x7e, 0xd8, 0x71, 0x9b, 0x8f, 0x75, 0x21, 0x35, 0x4c, - 0x6e, 0xbc, 0x4b, 0xc6, 0xb1, 0x52, 0xc6, 0x61, 0xaa, 0xda, 0x32, 0x6b, - 0x5d, 0x0a, 0xb7, 0x16, 0x31, 0xbf, 0x58, 0x35, 0x52, 0x84, 0xf8, 0x9e, - 0x52, 0xdc, 0xb3, 0x6d, 0xb9, 0x95, 0x4a, 0x09, 0xff, 0x96, 0x3c, 0xbb, - 0x14, 0x9d, 0xbc, 0xb7, 0xa6, 0x4f, 0xf6, 0x21, 0x42, 0x1d, 0xb5, 0x8e, - 0x52, 0x3c, 0xb4, 0x8b, 0xfd, 0xd8, 0xb5, 0x04, 0xf1, 0x5d, 0x47, 0x60, - 0x66, 0x54, 0x8c, 0x0c, 0x38, 0xe1, 0x37, 0x4e, 0x93, 0x6f, 0xfd, 0x0c, - 0xc9, 0x21, 0x15, 0xd9, 0x01, 0x45, 0xdb, 0x18, 0x1a, 0xc5, 0xc6, 0x21, - 0x27, 0xf6, 0x26, 0x5a, 0xf0, 0x36, 0x71, 0x6e, 0x30, 0x11, 0xc3, 0x71, - 0xea, 0x76, 0x72, 0xcf, 0x32, 0x7e, 0x3c, 0xf4, 0xf7, 0x83, 0xf4, 0x9d, - 0x30, 0xba, 0xe9, 0x47, 0x07, 0x13, 0x1a, 0x1e, 0xcb, 0xde, 0x0c, 0x73, - 0xe8, 0x0e, 0x6c, 0x1e, 0x32, 0xf1, 0xe8, 0x8e, 0x36, 0x7e, 0x1b, 0x78, - 0x74, 0xe8, 0x6b, 0x58, 0x33, 0x72, 0x14, 0x9b, 0xb2, 0x71, 0xbc, 0x33, - 0xf2, 0x2c, 0x92, 0x69, 0x9d, 0xbe, 0x21, 0xdc, 0x4d, 0xc1, 0xe6, 0x79, - 0xcf, 0x62, 0x73, 0xe6, 0x30, 0x36, 0xa6, 0x3b, 0xc9, 0x09, 0x0f, 0x63, - 0x03, 0x7f, 0xaf, 0x4f, 0x6b, 0xfe, 0x41, 0x1c, 0x46, 0x77, 0x66, 0x2d, - 0x3a, 0xfb, 0x44, 0x5f, 0x0a, 0xce, 0xde, 0xb0, 0x16, 0x0f, 0xef, 0xea, - 0xc0, 0x03, 0x23, 0x3f, 0xc0, 0xce, 0xec, 0xb3, 0xe8, 0x4d, 0x27, 0x90, - 0xda, 0x2a, 0xfa, 0xac, 0xc4, 0x0f, 0x22, 0x78, 0xa0, 0x12, 0xa1, 0xb6, - 0xa4, 0x22, 0xb2, 0xd6, 0x60, 0x13, 0xfd, 0x7a, 0x63, 0x4a, 0xf4, 0xfb, - 0x34, 0xdb, 0x3c, 0x40, 0xbc, 0x58, 0x43, 0x7d, 0x3c, 0xc2, 0x4f, 0x61, - 0xcf, 0x76, 0xea, 0x3e, 0x83, 0xf8, 0x8b, 0xdf, 0xce, 0xe5, 0x4b, 0x7b, - 0x25, 0xaf, 0x1c, 0x0f, 0x96, 0x92, 0x8b, 0x94, 0xf4, 0x8a, 0x3e, 0xdb, - 0xad, 0xae, 0xd4, 0xf8, 0x67, 0x4b, 0x20, 0x73, 0x10, 0x20, 0x76, 0xff, - 0x0c, 0xeb, 0xe9, 0x8f, 0xb7, 0xca, 0xe1, 0x15, 0xc6, 0xa1, 0x43, 0xf4, - 0xe7, 0xb8, 0xcf, 0xb2, 0x9e, 0xd2, 0x59, 0xad, 0xb7, 0x83, 0x78, 0xe5, - 0xca, 0xef, 0xc5, 0x8d, 0x5f, 0x5b, 0x41, 0x19, 0xe5, 0xbd, 0x5d, 0x72, - 0xe6, 0x45, 0xcf, 0xe5, 0xbc, 0x96, 0xb5, 0x25, 0x54, 0xb0, 0x9f, 0xf1, - 0x6b, 0xcb, 0x31, 0x4d, 0xd6, 0x8f, 0x9b, 0x73, 0xef, 0xc1, 0x9d, 0x63, - 0x5c, 0xec, 0xc2, 0x96, 0xe1, 0xb6, 0xbc, 0x1d, 0xfd, 0xbf, 0x92, 0x77, - 0xb9, 0x3d, 0xbe, 0x6b, 0xec, 0x75, 0x1f, 0xd8, 0x67, 0xea, 0x81, 0x7b, - 0x13, 0xb2, 0x6f, 0xa2, 0xde, 0x40, 0x56, 0x45, 0x0b, 0x2d, 0xc6, 0x61, - 0xfd, 0x4a, 0x74, 0x93, 0x77, 0xde, 0xa2, 0x17, 0x61, 0xb8, 0xd1, 0xc0, - 0xa4, 0xd7, 0x6c, 0x13, 0xce, 0x56, 0x66, 0x8c, 0xb7, 0x7f, 0x39, 0x14, - 0x94, 0xbc, 0x10, 0x61, 0x62, 0x08, 0x6c, 0xce, 0xd6, 0x83, 0x64, 0x4a, - 0x81, 0x47, 0xbb, 0x03, 0xd9, 0x2a, 0x9f, 0xb4, 0x1f, 0x2e, 0x9c, 0xbf, - 0x2c, 0xd6, 0xce, 0xe5, 0xdf, 0x7d, 0x5b, 0xc2, 0xf9, 0xa0, 0x6d, 0xcf, - 0xb4, 0xac, 0xb6, 0x48, 0x00, 0xf5, 0xa1, 0x86, 0x40, 0x95, 0xfa, 0x0b, - 0xcb, 0x94, 0x3d, 0xa9, 0x31, 0x39, 0x0f, 0x78, 0xb9, 0xfc, 0xfd, 0x21, - 0x6c, 0xdc, 0x3a, 0x07, 0x93, 0x3e, 0x91, 0xf9, 0x44, 0x79, 0x4e, 0x8e, - 0xac, 0x5f, 0xbc, 0x5a, 0x81, 0xd2, 0x1e, 0xfa, 0x4a, 0x0f, 0x7a, 0x52, - 0x2a, 0xdb, 0x78, 0xd3, 0x2a, 0x9e, 0x2e, 0xe3, 0xfe, 0x1f, 0x15, 0xb9, - 0x32, 0xaf, 0x55, 0x08, 0xbf, 0xd8, 0x94, 0xea, 0xa1, 0xee, 0x54, 0xc6, - 0x9b, 0x7f, 0xb1, 0x8e, 0xf8, 0xaa, 0xf9, 0x3c, 0x9e, 0x97, 0xb1, 0x4e, - 0xd6, 0xd1, 0xf4, 0x18, 0xe4, 0xde, 0x2b, 0x2c, 0x2b, 0xfa, 0xea, 0xa1, - 0x1e, 0x1c, 0xe4, 0x9e, 0x3e, 0x74, 0x7a, 0x73, 0x6b, 0x34, 0x17, 0xc6, - 0x21, 0x65, 0x64, 0x2c, 0x3d, 0x48, 0xa5, 0x64, 0x1f, 0xe3, 0xac, 0x75, - 0x6a, 0xba, 0x3c, 0x2f, 0xc9, 0xb7, 0x57, 0x6b, 0xef, 0xad, 0x3d, 0x9a, - 0x72, 0x4c, 0xe9, 0x9b, 0xd4, 0xb5, 0x65, 0xb3, 0xfe, 0xa7, 0x2e, 0x69, - 0xd7, 0x6b, 0x73, 0x72, 0xd5, 0x9e, 0xa7, 0x57, 0xf2, 0xe5, 0xcb, 0xcb, - 0x0b, 0xef, 0x2f, 0xc8, 0xd9, 0xde, 0x0b, 0x6d, 0x4f, 0x2d, 0x23, 0x6b, - 0x01, 0xb9, 0xba, 0xcd, 0x3b, 0x0a, 0xf2, 0x2d, 0xab, 0x68, 0x6e, 0x3b, - 0x6d, 0xd4, 0xea, 0x2c, 0x26, 0x46, 0xbe, 0x1d, 0xf5, 0x63, 0x7d, 0x42, - 0x74, 0xa4, 0xf9, 0xf7, 0x12, 0x03, 0xba, 0x6d, 0x4e, 0xe1, 0x42, 0x57, - 0xa6, 0x70, 0xde, 0x44, 0xd6, 0x3d, 0xe5, 0xdc, 0x9a, 0xbc, 0x87, 0x43, - 0x2e, 0xe5, 0x5d, 0x10, 0x70, 0x92, 0x0f, 0xdd, 0x8b, 0xff, 0xe0, 0x5c, - 0xc8, 0xfb, 0x24, 0xb9, 0x35, 0x91, 0x38, 0x6d, 0x20, 0x17, 0x93, 0x40, - 0x5f, 0x27, 0x17, 0xca, 0x9f, 0xb3, 0xef, 0xca, 0xfe, 0x87, 0x35, 0x6e, - 0x9f, 0xb3, 0xbf, 0x70, 0xa6, 0x23, 0xe3, 0x95, 0x77, 0x39, 0x31, 0xe5, - 0xcc, 0x3d, 0x63, 0x88, 0x26, 0x67, 0xf3, 0x7f, 0x67, 0xad, 0xb8, 0xa8, - 0xec, 0x78, 0x55, 0xee, 0x1d, 0x94, 0x98, 0xba, 0x40, 0x2b, 0xf0, 0x3b, - 0xd9, 0x57, 0x12, 0x5e, 0x77, 0x77, 0x65, 0x6e, 0xbd, 0x35, 0xd8, 0xda, - 0x06, 0xd9, 0xdb, 0x2e, 0xf0, 0x35, 0x4d, 0x9f, 0xad, 0x74, 0x62, 0x56, - 0xa4, 0x54, 0xde, 0xa9, 0x0d, 0x3a, 0x8d, 0xa0, 0xf7, 0x24, 0x42, 0xe1, - 0xc3, 0xf6, 0x59, 0x0c, 0xf1, 0x6d, 0x0d, 0xf7, 0x66, 0x1b, 0xa9, 0x1b, - 0x79, 0x1f, 0x5a, 0x7e, 0xdb, 0xf2, 0xf9, 0x1b, 0xee, 0x72, 0x62, 0xfb, - 0x48, 0xd2, 0xfc, 0xaf, 0x2e, 0x5b, 0x5e, 0xb0, 0x7d, 0xc8, 0x7e, 0x57, - 0xa9, 0x20, 0xcf, 0x73, 0x19, 0x79, 0x61, 0xd6, 0x0f, 0x53, 0x96, 0xc8, - 0xd0, 0x28, 0xe3, 0xd2, 0xf3, 0x39, 0xd3, 0xe3, 0x92, 0x23, 0xef, 0xcb, - 0xf3, 0xbe, 0xc3, 0x7f, 0x90, 0x23, 0x5f, 0xb6, 0xcd, 0x18, 0xdb, 0x6c, - 0x2d, 0x55, 0x62, 0x11, 0x79, 0x57, 0xa8, 0x38, 0x12, 0x0a, 0x3f, 0x47, - 0xe7, 0x74, 0x1a, 0x21, 0xff, 0x90, 0x7d, 0x66, 0x44, 0x77, 0x2f, 0xcc, - 0xe6, 0xf2, 0x29, 0x73, 0xec, 0x93, 0x75, 0x52, 0xa6, 0x69, 0x6d, 0x0d, - 0x4a, 0xec, 0x46, 0x22, 0x38, 0xc2, 0x11, 0x04, 0x8a, 0x8c, 0x82, 0x8e, - 0x42, 0xe1, 0x93, 0x9c, 0xcf, 0x89, 0x68, 0x88, 0x78, 0x29, 0x5c, 0x49, - 0xf4, 0xa2, 0xbb, 0x73, 0x73, 0xdf, 0x28, 0x9c, 0xda, 0x74, 0x31, 0xee, - 0x0d, 0x27, 0x64, 0x9d, 0xab, 0xc1, 0xbb, 0x11, 0x55, 0xb4, 0x57, 0xc4, - 0xba, 0x1b, 0xe3, 0xd8, 0x97, 0x40, 0xcc, 0x31, 0xa7, 0x12, 0x71, 0x92, - 0x64, 0x87, 0x16, 0x27, 0xef, 0x69, 0x08, 0x6f, 0xa2, 0x0d, 0xca, 0xd9, - 0x46, 0x13, 0x71, 0x1c, 0x4a, 0x2c, 0xf8, 0x4b, 0x07, 0x4c, 0xbd, 0x0c, - 0xf2, 0xae, 0x16, 0xbe, 0x78, 0x5b, 0x28, 0x18, 0x78, 0x3e, 0x7f, 0xe6, - 0xa5, 0x2b, 0xf1, 0x91, 0xbd, 0xa7, 0xe5, 0xd0, 0x3e, 0xa9, 0x8c, 0xdb, - 0x5e, 0xc7, 0xdd, 0x9b, 0xfe, 0x36, 0xd6, 0x6d, 0x65, 0x1f, 0x99, 0xdf, - 0x2f, 0xd0, 0x3b, 0xb1, 0x50, 0xf7, 0x60, 0xa5, 0x77, 0x56, 0xb3, 0x9c, - 0xe9, 0x19, 0xcc, 0xe4, 0xd6, 0x3d, 0xd6, 0xdb, 0x67, 0x6a, 0x06, 0xb0, - 0x99, 0x3e, 0x56, 0xa2, 0xc9, 0xb9, 0xab, 0x98, 0xb2, 0x39, 0xdb, 0xa2, - 0x6c, 0xca, 0xaf, 0xb3, 0xf5, 0x64, 0x5f, 0xaf, 0x44, 0xa9, 0x89, 0xe3, - 0xba, 0xbc, 0x23, 0x29, 0x72, 0x4d, 0x0c, 0x45, 0xff, 0x94, 0x77, 0x25, - 0x45, 0xa7, 0x6b, 0xd0, 0x3d, 0xf0, 0x08, 0xba, 0x06, 0x5e, 0xb4, 0xcf, - 0xb6, 0xba, 0x34, 0xb7, 0x79, 0xb5, 0x11, 0x3c, 0x60, 0xe2, 0x69, 0xaf, - 0xac, 0xe7, 0xd6, 0x18, 0x47, 0xb1, 0xd9, 0x2b, 0xef, 0x00, 0x0e, 0x90, - 0x03, 0x08, 0xce, 0x2d, 0xc7, 0x97, 0x93, 0x32, 0x87, 0x15, 0xc4, 0xfc, - 0x60, 0x6c, 0xa5, 0x3d, 0x87, 0x8d, 0x38, 0x36, 0xfa, 0x08, 0xde, 0xde, - 0xde, 0x09, 0x35, 0x12, 0xf4, 0x2f, 0x82, 0xd5, 0x79, 0x44, 0x8f, 0x99, - 0x2e, 0x04, 0xf7, 0x39, 0x54, 0xe0, 0xe0, 0x76, 0xc9, 0x69, 0xdb, 0x71, - 0x23, 0x63, 0x6d, 0xa5, 0x66, 0xcd, 0xff, 0xb7, 0xb9, 0xc1, 0x1e, 0xcd, - 0x61, 0xfe, 0xf3, 0x74, 0x04, 0xd3, 0xcd, 0xaa, 0xd6, 0x7e, 0xa7, 0x0a, - 0xc5, 0x63, 0xc8, 0x7b, 0xeb, 0x9d, 0xb8, 0xa3, 0xc9, 0x63, 0x96, 0x1b, - 0xc1, 0xf4, 0x8b, 0x4a, 0x30, 0x6c, 0xaa, 0x9f, 0xe7, 0x3c, 0x87, 0xf1, - 0xfc, 0xa8, 0x17, 0xad, 0xbd, 0x3a, 0x16, 0xf7, 0x36, 0xda, 0xb8, 0xa5, - 0x6a, 0xf5, 0xcd, 0x25, 0x8a, 0x17, 0x8b, 0x46, 0x81, 0x89, 0xcc, 0x72, - 0xbc, 0xb9, 0x5d, 0x47, 0x0b, 0x9f, 0xf5, 0xa5, 0x9e, 0xaa, 0x94, 0xb3, - 0x6f, 0x1d, 0xba, 0xd9, 0xa0, 0x22, 0x74, 0xd4, 0xa5, 0x62, 0xc1, 0x0c, - 0x23, 0x34, 0x3e, 0xdf, 0xe1, 0x44, 0xf3, 0xa8, 0x13, 0x77, 0xb1, 0xcc, - 0x46, 0x62, 0xfa, 0x9d, 0xbd, 0x6e, 0xf2, 0x87, 0x3a, 0x7c, 0x48, 0xae, - 0xfb, 0x2b, 0x72, 0xda, 0x49, 0xc6, 0xe6, 0xc9, 0x6c, 0x29, 0xda, 0xfa, - 0x5d, 0x72, 0x8e, 0x67, 0xdc, 0xc5, 0xb9, 0xa8, 0x68, 0xf2, 0xe1, 0xd4, - 0x90, 0x1b, 0x9f, 0xdb, 0x1e, 0xdc, 0x39, 0xa9, 0xd6, 0xe0, 0x83, 0xa1, - 0x52, 0x7b, 0xbd, 0xb2, 0xdc, 0xb0, 0xb0, 0x85, 0x38, 0xfd, 0x1e, 0x9f, - 0xb5, 0x6c, 0x87, 0x92, 0x9d, 0x77, 0x0d, 0x79, 0xb9, 0xc6, 0xfa, 0x65, - 0xb8, 0xad, 0x5f, 0xd6, 0x68, 0x54, 0xbc, 0x33, 0xa4, 0xe0, 0x64, 0x46, - 0xc7, 0x02, 0xb6, 0xd7, 0x9d, 0x3a, 0x68, 0xb9, 0xe9, 0xe7, 0x2b, 0xb2, - 0x3a, 0xee, 0xcb, 0x34, 0xa2, 0x37, 0xf5, 0x06, 0x39, 0x50, 0x13, 0xde, - 0xd8, 0xa6, 0x1d, 0x7d, 0xcb, 0x11, 0x1a, 0x9f, 0xe7, 0x68, 0xc2, 0xeb, - 0x7b, 0x9a, 0xf0, 0xc3, 0xbe, 0xf9, 0xf8, 0x74, 0x53, 0x0c, 0xa7, 0xe7, - 0x35, 0xe1, 0x95, 0x5d, 0x8d, 0xc4, 0xe8, 0x28, 0x02, 0x23, 0xe3, 0xd8, - 0x92, 0x6c, 0x46, 0xc3, 0x88, 0x01, 0xad, 0xcf, 0xea, 0x2c, 0x33, 0x3a, - 0xb1, 0x59, 0x37, 0x30, 0x7b, 0x97, 0xe8, 0xc1, 0xb2, 0x56, 0xce, 0x33, - 0xf0, 0x5c, 0x5a, 0xa3, 0x9f, 0x1a, 0xd4, 0x43, 0x23, 0x71, 0xd6, 0x40, - 0x68, 0xab, 0x76, 0x66, 0x37, 0xaf, 0xe7, 0xef, 0x8e, 0xa2, 0x9d, 0xed, - 0x27, 0x52, 0x31, 0xec, 0x1c, 0x69, 0xe4, 0x98, 0x75, 0x8e, 0xbf, 0xde, - 0xfc, 0x50, 0x69, 0x41, 0x7a, 0xa4, 0x15, 0xbd, 0x7d, 0x9d, 0x78, 0x31, - 0xd2, 0x8a, 0x24, 0x65, 0xad, 0x4f, 0xe9, 0xb8, 0xad, 0xb7, 0x15, 0xfb, - 0x13, 0x72, 0x96, 0x5e, 0x6b, 0xbe, 0x5e, 0x09, 0xe9, 0x27, 0xd1, 0x8a, - 0xbd, 0xd4, 0xc9, 0x82, 0xfe, 0x25, 0xf6, 0xb9, 0xa1, 0x85, 0xdb, 0x1b, - 0xf1, 0x58, 0xea, 0x0e, 0xbc, 0x39, 0xac, 0xa3, 0xad, 0x57, 0xf4, 0x2d, - 0xe7, 0x27, 0xe3, 0x38, 0x92, 0x5a, 0x8b, 0x0f, 0xfb, 0x63, 0xff, 0xcc, - 0x69, 0x3e, 0xa6, 0xda, 0xfb, 0x5d, 0x2a, 0xae, 0x6b, 0x92, 0x73, 0xad, - 0x0e, 0xa2, 0x5a, 0xd0, 0xac, 0x54, 0xcd, 0x00, 0xef, 0x9b, 0x4e, 0x75, - 0x2d, 0xfe, 0xb6, 0xdf, 0x49, 0xde, 0xae, 0x32, 0xdf, 0x30, 0x3b, 0x68, - 0x1b, 0x66, 0x85, 0x9a, 0x9b, 0x37, 0x7b, 0x7f, 0x40, 0x73, 0x40, 0xce, - 0xbd, 0x96, 0xb1, 0xde, 0xe2, 0x48, 0x30, 0x56, 0xa2, 0x46, 0xc9, 0x27, - 0x1e, 0xc1, 0xca, 0xed, 0x8f, 0x60, 0x05, 0x3f, 0x1d, 0xdb, 0xad, 0xce, - 0x5b, 0x75, 0x05, 0x87, 0x34, 0xab, 0xb3, 0x53, 0xd7, 0x38, 0xb7, 0x32, - 0xaf, 0x8f, 0x60, 0xcd, 0xde, 0x47, 0xf0, 0x15, 0xda, 0x57, 0x35, 0xfd, - 0x78, 0x69, 0xaf, 0xd5, 0xf9, 0xe9, 0xa6, 0x30, 0x7e, 0x6d, 0xe7, 0x18, - 0x62, 0xaf, 0x5b, 0xec, 0xbc, 0x37, 0xa3, 0xca, 0xef, 0xbf, 0xb7, 0x7f, - 0x9b, 0xea, 0x2b, 0xf9, 0xbd, 0xa8, 0x35, 0xf8, 0x88, 0x72, 0x7f, 0xb3, - 0xbd, 0x12, 0x5b, 0xab, 0x25, 0x66, 0xb8, 0xcd, 0x12, 0x03, 0x8a, 0x36, - 0x8f, 0xb9, 0xd4, 0xd6, 0x23, 0x36, 0xdf, 0xf2, 0x45, 0x24, 0xcf, 0x6d, - 0xd0, 0xd7, 0xa9, 0x37, 0x13, 0xdb, 0xc9, 0xc5, 0x66, 0x7e, 0x1b, 0x49, - 0xfa, 0xea, 0x96, 0x99, 0xc1, 0x78, 0x12, 0x86, 0xb5, 0x65, 0xfa, 0xc0, - 0x9f, 0xf1, 0x7e, 0x6c, 0x61, 0xdf, 0x4d, 0xde, 0x91, 0x7d, 0x04, 0x9d, - 0xdb, 0x65, 0xfe, 0x1f, 0xc1, 0xc3, 0xec, 0xff, 0x9a, 0xfe, 0x47, 0xf0, - 0x10, 0x6d, 0xa7, 0x6a, 0xee, 0xc4, 0xc3, 0x55, 0x98, 0xc5, 0x4c, 0x68, - 0xfc, 0x81, 0x6a, 0x39, 0xf3, 0x4a, 0x4c, 0x4c, 0x2a, 0x8f, 0xe0, 0xde, - 0xc1, 0xfd, 0xf4, 0x45, 0xdb, 0xff, 0x88, 0xc5, 0x85, 0x78, 0xe5, 0xc7, - 0xca, 0x6c, 0x5d, 0x1e, 0xd7, 0x7d, 0x58, 0x91, 0x78, 0xd2, 0xf6, 0xfd, - 0x22, 0x63, 0x09, 0xfd, 0xbe, 0x95, 0x7e, 0xdf, 0x42, 0xbf, 0x8f, 0xd1, - 0xef, 0x0d, 0xfa, 0x7d, 0x33, 0xfd, 0x3e, 0x4a, 0xbf, 0xd7, 0xe9, 0xf7, - 0x8d, 0xf4, 0xfb, 0xb0, 0xec, 0x47, 0x28, 0x47, 0xa3, 0x47, 0xe0, 0xea, - 0x73, 0xd3, 0x86, 0x72, 0xef, 0x3d, 0xee, 0x21, 0xfe, 0x1c, 0xd7, 0x67, - 0xfb, 0x6f, 0x61, 0x2c, 0x1d, 0x22, 0x46, 0x64, 0x86, 0xbf, 0x6d, 0xbf, - 0x23, 0x97, 0x21, 0xee, 0x3f, 0x4f, 0x7d, 0x2c, 0x8e, 0xd4, 0xeb, 0xfb, - 0x19, 0xc3, 0x7e, 0xa4, 0x35, 0xf4, 0xf8, 0x58, 0xe6, 0xbb, 0xa9, 0x86, - 0xf4, 0x34, 0x68, 0x66, 0x93, 0xba, 0x1e, 0x58, 0xea, 0xe3, 0x98, 0x65, - 0xbf, 0x6e, 0x29, 0x1e, 0x1e, 0x68, 0xc3, 0xdf, 0x0d, 0x78, 0xa9, 0x8b, - 0xfa, 0xf1, 0x9b, 0x1d, 0xf8, 0xbe, 0x1f, 0x0e, 0xdf, 0x15, 0xc0, 0x7f, - 0xd6, 0x60, 0xf6, 0x3e, 0x79, 0xcf, 0x3a, 0x53, 0xe3, 0x68, 0x9c, 0x01, - 0xb1, 0x11, 0x10, 0xa9, 0x1d, 0xcc, 0xf6, 0x66, 0xdb, 0xef, 0x74, 0xc6, - 0x96, 0x09, 0xa6, 0x97, 0x60, 0x7d, 0xd8, 0xc6, 0xd9, 0x27, 0x65, 0xff, - 0xb0, 0x86, 0x78, 0xe4, 0x31, 0x5a, 0xb1, 0x21, 0x69, 0x7e, 0xb1, 0x86, - 0x5c, 0xa9, 0x27, 0x99, 0xd3, 0xc1, 0x03, 0x11, 0xaa, 0xc4, 0x90, 0xff, - 0x19, 0x01, 0x67, 0x47, 0xb4, 0x19, 0xf7, 0x65, 0x77, 0x22, 0xcd, 0xb1, - 0xae, 0xa2, 0x9f, 0xad, 0xfc, 0xe3, 0xef, 0xc5, 0xe3, 0xa1, 0x44, 0x80, - 0xf6, 0x7f, 0xce, 0xca, 0x54, 0xcd, 0x4e, 0xd7, 0x40, 0x5b, 0x73, 0x97, - 0x7a, 0x3d, 0xf3, 0xd6, 0xe0, 0x01, 0x3e, 0x32, 0xa7, 0xdb, 0xe7, 0xd1, - 0xdc, 0xb8, 0xa6, 0x1f, 0xca, 0x50, 0xaf, 0xbc, 0xd7, 0xd6, 0x89, 0xbf, - 0xd1, 0x3f, 0x6f, 0xdb, 0xcf, 0xb8, 0xc3, 0x8b, 0x19, 0xbd, 0x72, 0xdf, - 0x9a, 0x7f, 0x76, 0x6e, 0x30, 0x1c, 0x70, 0x3c, 0x54, 0x29, 0xfb, 0x12, - 0xcf, 0x30, 0xce, 0xfa, 0xfb, 0xe7, 0x43, 0x9d, 0xeb, 0xc6, 0xdd, 0x8d, - 0xe5, 0x88, 0x2f, 0x15, 0x0e, 0x69, 0xef, 0x9b, 0x50, 0x9f, 0x7f, 0x8d, - 0xfb, 0xf5, 0xa7, 0xc8, 0xd7, 0x76, 0xa2, 0x9f, 0xf8, 0xb5, 0x52, 0xff, - 0x9c, 0x62, 0xf2, 0xf7, 0x86, 0x94, 0x89, 0x55, 0xfa, 0x6d, 0xc0, 0x5f, - 0x54, 0xa3, 0x74, 0xbb, 0x94, 0x17, 0xb9, 0x5b, 0x6c, 0x79, 0x7b, 0x52, - 0xf2, 0xfb, 0xef, 0xf3, 0x6d, 0xde, 0x09, 0x54, 0xbb, 0xed, 0x3c, 0xe7, - 0x57, 0x33, 0x77, 0x62, 0x6b, 0x0a, 0xdf, 0xaf, 0x44, 0x7d, 0xa6, 0x4f, - 0x75, 0x7c, 0xff, 0x0a, 0xcc, 0x4e, 0xff, 0x56, 0x95, 0xf9, 0x88, 0xe1, - 0xbe, 0x99, 0x0a, 0x71, 0x4d, 0x3b, 0x7d, 0x97, 0x1a, 0x34, 0xc7, 0x41, - 0xf9, 0x63, 0x2f, 0x5a, 0xe3, 0x57, 0xf8, 0xb0, 0x6f, 0x4c, 0xea, 0xb6, - 0xc1, 0xe2, 0x9c, 0xec, 0xb7, 0xf7, 0xe2, 0x82, 0x47, 0x2d, 0x35, 0x00, - 0x27, 0xef, 0x9d, 0x1d, 0xd2, 0x99, 0xc7, 0xb7, 0xe1, 0xdf, 0x06, 0x96, - 0xe2, 0xb7, 0x03, 0xf5, 0x1d, 0x37, 0x28, 0x96, 0x75, 0x28, 0xf2, 0x59, - 0xfc, 0xb8, 0xda, 0x8b, 0xdd, 0xe4, 0xff, 0xbf, 0x4d, 0x98, 0xb5, 0x57, - 0x10, 0x0b, 0xfe, 0x3d, 0x11, 0x4c, 0x1f, 0x52, 0xed, 0x77, 0xc6, 0xf5, - 0x85, 0x6a, 0x70, 0xe7, 0xaf, 0xd8, 0xc6, 0x7d, 0xea, 0x12, 0xfc, 0x3a, - 0xdb, 0x8a, 0xd3, 0xd9, 0xa9, 0xb6, 0xd0, 0x69, 0xa1, 0x46, 0xec, 0x40, - 0xec, 0x81, 0xb6, 0x98, 0xa2, 0x2d, 0x92, 0xdf, 0x76, 0x7d, 0x86, 0xf6, - 0x48, 0x2c, 0xfa, 0x1e, 0x31, 0xea, 0x1f, 0x52, 0xb4, 0x47, 0xfa, 0xcd, - 0x77, 0xe9, 0x37, 0xdf, 0xa1, 0xdf, 0x3c, 0x45, 0xbf, 0xc9, 0x71, 0xdb, - 0x36, 0x7b, 0xbd, 0xfe, 0x65, 0xc6, 0xc4, 0xc4, 0xd6, 0x4e, 0x9c, 0x8a, - 0xd4, 0xaf, 0x1a, 0x45, 0xb0, 0x3d, 0xa9, 0x58, 0x5e, 0xe1, 0x73, 0x5f, - 0x0b, 0x89, 0x0f, 0xc8, 0xfb, 0x69, 0x7e, 0x3c, 0x3e, 0xdc, 0x59, 0x29, - 0xef, 0xbb, 0xee, 0xd9, 0xf1, 0x71, 0x3a, 0xfb, 0x07, 0xf6, 0x43, 0xf4, - 0xf5, 0xe7, 0x8e, 0x5d, 0x74, 0xf9, 0xcf, 0xd6, 0x8f, 0x6b, 0x64, 0xfc, - 0xcb, 0xf0, 0xfb, 0x81, 0x16, 0x9c, 0x66, 0xfc, 0x7d, 0x7e, 0xee, 0xb8, - 0xb7, 0x14, 0xc1, 0xb8, 0xaa, 0x1a, 0xc8, 0x66, 0x5b, 0x70, 0x26, 0x61, - 0xe0, 0x89, 0x44, 0xfd, 0xaa, 0x32, 0xc7, 0xcf, 0xd5, 0x4c, 0xad, 0x58, - 0x54, 0x0c, 0x27, 0x85, 0x5f, 0x86, 0xda, 0x50, 0x6c, 0x34, 0x63, 0x30, - 0x2b, 0x76, 0xea, 0xc5, 0x5b, 0x51, 0x5d, 0xde, 0x2f, 0xfb, 0xa3, 0x7f, - 0xf7, 0xd1, 0x1e, 0x5f, 0x95, 0xff, 0x27, 0xc1, 0x79, 0xf6, 0x1a, 0xcb, - 0xe0, 0xdc, 0x2e, 0xef, 0xf8, 0x8b, 0x3f, 0x2b, 0xd8, 0xa4, 0x8f, 0x77, - 0x94, 0x20, 0xf8, 0xe4, 0x4f, 0x68, 0xeb, 0x87, 0x7a, 0xe5, 0x2c, 0x6e, - 0x0b, 0x7e, 0xc9, 0xf2, 0x95, 0xf4, 0x8b, 0x43, 0x59, 0xa7, 0xf3, 0xc7, - 0xbd, 0xf2, 0x8e, 0xfa, 0x12, 0xfc, 0x38, 0x3b, 0xa1, 0x7e, 0xe4, 0xd5, - 0xf1, 0xab, 0xd1, 0xa5, 0xb4, 0x27, 0xc9, 0xe5, 0x63, 0xcc, 0xe5, 0x83, - 0xde, 0xc7, 0xb1, 0x14, 0xea, 0xde, 0x65, 0xf0, 0x6c, 0x97, 0xf7, 0x67, - 0x96, 0xa1, 0x8c, 0xbf, 0xfd, 0xdb, 0x2d, 0xcb, 0x39, 0xb7, 0xd2, 0xda, - 0xb8, 0x4c, 0xe6, 0x4e, 0xf0, 0xe4, 0xff, 0x7a, 0x65, 0x2d, 0x00, 0x7b, - 0x45, 0xbe, 0x46, 0xf9, 0x4b, 0xe1, 0xde, 0x5e, 0x1f, 0x5e, 0x84, 0xfa, - 0xd3, 0x2e, 0x65, 0x29, 0xae, 0xde, 0xab, 0x54, 0xa1, 0x54, 0xca, 0x86, - 0x69, 0x7f, 0x26, 0xe4, 0x9c, 0x74, 0x4b, 0xef, 0xaf, 0xac, 0x19, 0x86, - 0xbd, 0xbf, 0x86, 0x95, 0xa3, 0x1a, 0xe3, 0x5d, 0x29, 0xe2, 0x83, 0x8f, - 0x59, 0x95, 0x86, 0x13, 0x2b, 0x46, 0x1b, 0x71, 0x4b, 0xbf, 0x65, 0x9d, - 0x9a, 0x17, 0x83, 0xc7, 0xf0, 0x10, 0xc3, 0x3c, 0xf8, 0x4a, 0x6f, 0x19, - 0xbf, 0x2d, 0x14, 0x31, 0x26, 0xcf, 0x52, 0xb5, 0x55, 0xb5, 0x0e, 0xad, - 0x7d, 0x54, 0x91, 0xb8, 0xef, 0xc1, 0x83, 0x8c, 0xcf, 0x8b, 0x7b, 0xfd, - 0x88, 0x8f, 0x5a, 0xd6, 0x2b, 0x51, 0x1f, 0x1e, 0x60, 0xfd, 0xd6, 0xde, - 0x01, 0x74, 0xd1, 0x2e, 0xe2, 0x7b, 0xb5, 0x80, 0x97, 0xf1, 0x7e, 0xe5, - 0xa8, 0x9b, 0x31, 0xac, 0x1a, 0x8b, 0xb6, 0x07, 0xf0, 0x95, 0x51, 0x0f, - 0xe3, 0x9b, 0x35, 0xff, 0x4d, 0xdd, 0xbc, 0xd6, 0x01, 0x0d, 0x6b, 0x46, - 0x7d, 0x58, 0xd2, 0x1b, 0x3c, 0x23, 0xef, 0x5a, 0x9f, 0xd5, 0xc3, 0x58, - 0x3d, 0xea, 0xc7, 0xed, 0xbd, 0x13, 0x5f, 0x99, 0x01, 0xf3, 0xff, 0xab, - 0x45, 0x23, 0xbe, 0x3c, 0x5a, 0x47, 0xf9, 0xc1, 0x55, 0x2f, 0x2b, 0x75, - 0xf8, 0xdb, 0xbd, 0x3a, 0xe5, 0xab, 0xb8, 0x8d, 0x72, 0x6e, 0xed, 0xbd, - 0x1a, 0x0f, 0xee, 0x8d, 0xe2, 0xbe, 0xd1, 0xb9, 0x58, 0xc8, 0xf8, 0xd4, - 0xc1, 0xbc, 0x0e, 0x9f, 0x07, 0x6e, 0xef, 0x17, 0xdd, 0x43, 0x79, 0x25, - 0x3a, 0x0e, 0x37, 0xe3, 0x1d, 0x0d, 0x91, 0xf7, 0x1a, 0xc9, 0xc1, 0x74, - 0xdc, 0xbe, 0x6b, 0xae, 0xbd, 0x9f, 0x5e, 0x1f, 0x29, 0x46, 0xbc, 0x4d, - 0x41, 0x4b, 0xbf, 0xc4, 0x59, 0xe1, 0x36, 0x3a, 0xe3, 0x6a, 0x88, 0x6d, - 0xe8, 0x8c, 0xab, 0xb9, 0xfb, 0x5d, 0x29, 0x39, 0x6b, 0xf5, 0x06, 0xf9, - 0x52, 0x04, 0x2d, 0x76, 0x8c, 0x76, 0x93, 0x5f, 0x9b, 0x70, 0x32, 0x76, - 0x47, 0x68, 0xe3, 0xf3, 0x9b, 0x24, 0x56, 0x37, 0x32, 0x4f, 0x34, 0x30, - 0xd6, 0xa7, 0x75, 0x9c, 0x51, 0x0c, 0x8c, 0xee, 0x92, 0x98, 0xe8, 0xc3, - 0xea, 0x5e, 0x03, 0x6f, 0xca, 0x59, 0xfa, 0x39, 0xb1, 0xc5, 0x65, 0xd0, - 0xf4, 0x07, 0x11, 0x32, 0x8f, 0x31, 0xb6, 0x9f, 0xce, 0x54, 0xe3, 0x96, - 0xed, 0x52, 0xa6, 0x09, 0x6f, 0x0d, 0x39, 0x71, 0x4b, 0xef, 0x5a, 0x3c, - 0x96, 0x76, 0x60, 0x50, 0xaf, 0xef, 0x51, 0x19, 0x3f, 0x6f, 0x6c, 0x0a, - 0x7a, 0x9f, 0x21, 0x57, 0x3d, 0x33, 0x97, 0x51, 0xf9, 0x8a, 0x28, 0x5a, - 0xd8, 0xaf, 0x16, 0x2d, 0x77, 0x96, 0xe2, 0xbe, 0xe8, 0x5a, 0x1c, 0x4b, - 0x6b, 0xe6, 0x7e, 0xe6, 0xcb, 0xee, 0x26, 0x3e, 0x9f, 0xee, 0x44, 0xb7, - 0x26, 0x9c, 0xb6, 0x91, 0xbe, 0x25, 0xeb, 0x2a, 0x51, 0xbc, 0x49, 0x7b, - 0xed, 0xc9, 0xcc, 0x67, 0xec, 0x97, 0x98, 0x2f, 0x67, 0xfd, 0x4c, 0x54, - 0xde, 0xa0, 0xe0, 0xf8, 0x6e, 0xe1, 0x58, 0xf3, 0xf1, 0x45, 0xea, 0xa9, - 0xa5, 0x57, 0xc5, 0x8d, 0x7b, 0x97, 0xe3, 0xd4, 0xb6, 0x1c, 0xe7, 0x7a, - 0x25, 0x62, 0x7e, 0x99, 0x9c, 0xab, 0xbd, 0x9c, 0x9c, 0x8b, 0x5c, 0x2e, - 0xbc, 0x5a, 0x71, 0x22, 0x34, 0xda, 0x4c, 0x5e, 0x21, 0xfc, 0x82, 0xfe, - 0x9a, 0x8d, 0x62, 0x51, 0x6f, 0x1d, 0x86, 0xc9, 0xb7, 0x32, 0xc4, 0x8b, - 0x4c, 0x96, 0x71, 0x65, 0xa8, 0x86, 0x9f, 0x00, 0x3f, 0xd7, 0xf0, 0xa3, - 0xd9, 0xf7, 0x56, 0xd0, 0x96, 0x63, 0x6d, 0x8a, 0x7d, 0xce, 0x7e, 0x30, - 0x2b, 0xb1, 0x5a, 0x41, 0x95, 0xf6, 0x17, 0x55, 0x92, 0x67, 0x7a, 0x35, - 0x05, 0xaf, 0xa5, 0x03, 0xf8, 0x6a, 0xd3, 0x5a, 0x25, 0x56, 0x6d, 0xbf, - 0xa7, 0x6a, 0x96, 0xb2, 0x6f, 0x8b, 0xe6, 0xc9, 0x3a, 0x64, 0x98, 0x39, - 0xaf, 0xfc, 0x8f, 0x02, 0x05, 0x0f, 0x30, 0x97, 0x0f, 0x54, 0x05, 0xe4, - 0x1c, 0x14, 0xfd, 0xdd, 0x87, 0x17, 0x12, 0x71, 0x64, 0x13, 0x0d, 0x3d, - 0xab, 0x15, 0xd9, 0xef, 0x09, 0x36, 0xc7, 0x95, 0x1c, 0xe7, 0x2f, 0x67, - 0xdd, 0xdd, 0xf3, 0x3a, 0xd0, 0x41, 0x6e, 0x7f, 0x3a, 0xc7, 0xed, 0x03, - 0x93, 0xe8, 0xc0, 0xca, 0x84, 0xec, 0x6f, 0xc6, 0xad, 0x2e, 0xce, 0xc1, - 0xe1, 0x44, 0x07, 0xee, 0x4c, 0x34, 0x74, 0x10, 0x5a, 0x30, 0x7e, 0x57, - 0x07, 0x5a, 0x12, 0xf5, 0xe3, 0x5b, 0xe5, 0x7f, 0x50, 0x4d, 0xd3, 0x70, - 0x60, 0x4c, 0x45, 0xad, 0x16, 0x20, 0xf6, 0x07, 0x30, 0x98, 0x6a, 0x38, - 0xd3, 0xa5, 0xde, 0xa9, 0x4c, 0x5e, 0x21, 0x39, 0x64, 0x33, 0x9e, 0x4f, - 0x78, 0x50, 0x96, 0x34, 0x69, 0xfb, 0x40, 0xe9, 0x48, 0x94, 0xf9, 0xc3, - 0x63, 0x56, 0x95, 0x11, 0x4a, 0x8b, 0x5e, 0x4a, 0x46, 0xe6, 0xe3, 0x0d, - 0xc6, 0xdc, 0xfa, 0xeb, 0x35, 0xef, 0x42, 0x1b, 0x8b, 0x7e, 0x65, 0xd5, - 0x1a, 0x65, 0x98, 0xb1, 0x2b, 0xd4, 0xdc, 0xc2, 0xf8, 0xda, 0x7c, 0x03, - 0xed, 0x80, 0xb1, 0xaf, 0xd2, 0xd8, 0xc9, 0x39, 0x16, 0x7b, 0xf2, 0xa0, - 0x7c, 0xc4, 0x47, 0x1c, 0xa2, 0xe8, 0x11, 0x0d, 0x7b, 0xd9, 0x2f, 0xef, - 0x88, 0x9c, 0x0b, 0x0a, 0xb6, 0xdf, 0x27, 0xff, 0x53, 0x64, 0x4f, 0xee, - 0xfc, 0xe1, 0xfb, 0x89, 0xcf, 0x40, 0x92, 0x51, 0xcf, 0x88, 0x07, 0x1f, - 0x26, 0xe4, 0x0c, 0x1f, 0x69, 0xcd, 0x48, 0x00, 0x55, 0xac, 0xfb, 0x66, - 0xa2, 0x3e, 0xfd, 0xdf, 0x51, 0x1f, 0xb8, 0x55, 0xad, 0xb4, 0xcf, 0x0a, - 0x39, 0x47, 0x6e, 0xc2, 0x89, 0x74, 0x70, 0x9c, 0x79, 0xf4, 0xaa, 0x76, - 0xaa, 0x98, 0xb9, 0xae, 0x79, 0x8d, 0xd2, 0xd0, 0xa1, 0xaa, 0xc1, 0xf0, - 0xa8, 0x02, 0xca, 0x73, 0xb2, 0x8d, 0x9b, 0xf0, 0x76, 0xba, 0x14, 0x45, - 0xbb, 0x76, 0xd2, 0xee, 0x8b, 0xb0, 0x78, 0x9b, 0x1b, 0x25, 0x7b, 0xc4, - 0x56, 0x45, 0xaf, 0x92, 0xef, 0x83, 0xb6, 0x6a, 0x62, 0x6f, 0x74, 0x39, - 0x9e, 0x1f, 0x90, 0x7d, 0xf4, 0x0b, 0x1c, 0xbc, 0x2d, 0x62, 0xde, 0xae, - 0x32, 0x06, 0xad, 0x4f, 0x85, 0xe2, 0x25, 0xb4, 0x09, 0x87, 0x11, 0x6a, - 0xef, 0xe6, 0xd8, 0x1b, 0x46, 0xc5, 0xce, 0x9a, 0xf1, 0x1d, 0x8e, 0xa5, - 0x9f, 0x36, 0x31, 0x9c, 0xa8, 0xc3, 0x46, 0xda, 0x84, 0x49, 0x9b, 0x30, - 0x39, 0xff, 0x26, 0x6d, 0xc2, 0xa4, 0x4d, 0x98, 0xb4, 0x09, 0x93, 0x36, - 0x61, 0x66, 0xe7, 0x63, 0x5f, 0x5a, 0x45, 0xcf, 0x50, 0x19, 0xe2, 0xd5, - 0xf2, 0x1e, 0xbd, 0x86, 0xb1, 0x54, 0x97, 0x32, 0x79, 0xd7, 0x4d, 0x18, - 0x4c, 0xdf, 0xcc, 0x8f, 0x82, 0x76, 0xda, 0xc5, 0xce, 0x8c, 0xd8, 0x99, - 0x1b, 0xdf, 0xcd, 0xce, 0x99, 0x86, 0xd2, 0x5c, 0xac, 0x7c, 0xcc, 0xbe, - 0xa7, 0x70, 0x8e, 0xdc, 0x78, 0x26, 0x2b, 0xf7, 0x4c, 0x9c, 0xa0, 0xfd, - 0xf7, 0x50, 0x9e, 0x1a, 0x91, 0xfd, 0x92, 0x28, 0xf9, 0xbe, 0x9c, 0x0b, - 0xdf, 0xc9, 0x7e, 0x0b, 0xcf, 0x30, 0xb1, 0x65, 0x1e, 0xd0, 0xd4, 0xbf, - 0x16, 0x0f, 0xf5, 0x61, 0xbc, 0x9c, 0xcf, 0xbe, 0x93, 0xd9, 0x49, 0x1f, - 0x6e, 0xb4, 0xd7, 0x30, 0xee, 0x6f, 0x52, 0xf0, 0xa5, 0xb4, 0x9c, 0x27, - 0xaf, 0x8f, 0x6d, 0x44, 0xc4, 0xf6, 0xdb, 0xfe, 0xd4, 0x4e, 0xa4, 0xf8, - 0xcc, 0x1f, 0x69, 0xa2, 0x4f, 0x56, 0xe3, 0xdd, 0x6d, 0x41, 0xfd, 0x35, - 0x68, 0xad, 0x23, 0xb0, 0xe6, 0x2f, 0x8c, 0x84, 0xcc, 0x7a, 0xa5, 0x09, - 0x6d, 0x7b, 0x9b, 0x98, 0x3b, 0x04, 0xf5, 0xd7, 0xe9, 0x73, 0xcf, 0x45, - 0xe6, 0x33, 0x7f, 0x88, 0xe1, 0x2b, 0xe4, 0xf9, 0x77, 0x0d, 0xaa, 0x1c, - 0x53, 0xa3, 0xbd, 0xf6, 0xf1, 0x9c, 0xfd, 0x0e, 0x5c, 0x54, 0xce, 0xc8, - 0x28, 0x0f, 0x12, 0x73, 0x16, 0x27, 0x0f, 0x5a, 0xf2, 0x4e, 0xed, 0xca, - 0xeb, 0x9a, 0xb1, 0x3f, 0x6b, 0xe0, 0xc9, 0xf4, 0x1b, 0x96, 0xaa, 0xc5, - 0xce, 0x3a, 0xc9, 0x45, 0x3c, 0xc4, 0x8c, 0x6c, 0x46, 0xfc, 0x5f, 0xf6, - 0xc0, 0x0d, 0x7c, 0x98, 0xd6, 0xd2, 0x0d, 0x8c, 0x4b, 0xbf, 0xe6, 0xbd, - 0x9d, 0xc4, 0x11, 0xf7, 0x56, 0xed, 0xa8, 0x4a, 0x0e, 0x3f, 0xdf, 0x61, - 0xa0, 0x68, 0xb7, 0xcc, 0x81, 0xe0, 0x56, 0x00, 0x63, 0x89, 0x18, 0xee, - 0xa4, 0xfd, 0x8c, 0x26, 0x5a, 0x70, 0x07, 0x6d, 0x63, 0x24, 0xd1, 0x8a, - 0xcf, 0x31, 0x37, 0xd8, 0x9d, 0x10, 0x3f, 0x5b, 0x82, 0x85, 0xb4, 0x95, - 0xfd, 0xa9, 0xff, 0x05, 0x7d, 0x7a, 0x00, 0xbb, 0x6d, 0xae, 0x29, 0xfb, - 0xd6, 0x50, 0x56, 0x26, 0xdc, 0xcc, 0x6d, 0xe2, 0x56, 0x7f, 0x4a, 0x38, - 0x50, 0x27, 0x6e, 0x89, 0x34, 0x62, 0x0b, 0xe5, 0x65, 0xc9, 0x75, 0x87, - 0x98, 0x4f, 0xad, 0xde, 0xb5, 0x9c, 0x98, 0x7c, 0x61, 0xee, 0x4f, 0xeb, - 0xe6, 0x21, 0x62, 0x41, 0xd8, 0xcf, 0x79, 0x57, 0x69, 0xc3, 0x72, 0xce, - 0x7c, 0x90, 0x63, 0x9f, 0x43, 0x3c, 0x70, 0xa7, 0xc4, 0x7e, 0x82, 0x47, - 0x19, 0xf2, 0x1e, 0xae, 0x95, 0x77, 0x15, 0xe8, 0x1b, 0x33, 0x52, 0x56, - 0xa7, 0x93, 0x71, 0x64, 0x53, 0xb4, 0x0e, 0x07, 0x47, 0x6e, 0x86, 0x77, - 0x6b, 0x1d, 0x46, 0x93, 0x7e, 0x64, 0x93, 0xa8, 0xf5, 0x42, 0xbd, 0xc1, - 0x8b, 0x60, 0xf3, 0x21, 0xc6, 0x89, 0xb7, 0x95, 0x86, 0xf6, 0x37, 0x11, - 0xec, 0xd9, 0xac, 0x04, 0xbd, 0x0d, 0xaa, 0xb4, 0x4d, 0x3c, 0xa1, 0x1f, - 0x0c, 0xd2, 0xde, 0x33, 0x23, 0xc4, 0x14, 0xd6, 0x75, 0x6d, 0x75, 0xc9, - 0x3a, 0xf1, 0x78, 0x95, 0xe6, 0xc3, 0x9e, 0x3d, 0xc4, 0xb8, 0x1d, 0xf2, - 0xbf, 0x03, 0x6a, 0xb0, 0x6f, 0xcf, 0xcd, 0x98, 0xb1, 0x35, 0x80, 0x83, - 0xbc, 0x57, 0xbb, 0xe3, 0x1a, 0x3c, 0x43, 0x3f, 0xc9, 0xd0, 0x0f, 0x8b, - 0xb6, 0xaa, 0xd8, 0xbb, 0xe7, 0x26, 0x54, 0x92, 0xd7, 0x9f, 0x0a, 0x29, - 0x36, 0xf6, 0x26, 0x38, 0xae, 0xdd, 0x29, 0xfb, 0xdc, 0xbc, 0xf2, 0x22, - 0xf3, 0x81, 0xee, 0x11, 0x1d, 0x9b, 0x79, 0x3f, 0xc5, 0xb9, 0xde, 0x42, - 0xcc, 0x3d, 0xbe, 0xad, 0x1a, 0xf7, 0x6f, 0xd3, 0x62, 0xd7, 0xa8, 0xd6, - 0xfc, 0xb7, 0xf4, 0xd0, 0x19, 0x17, 0xe7, 0xd8, 0x62, 0x0e, 0x77, 0xb6, - 0xef, 0xa0, 0x55, 0x45, 0xac, 0x77, 0x69, 0xf3, 0x31, 0x73, 0x6e, 0x0c, - 0xaf, 0x47, 0x9b, 0x70, 0x66, 0x97, 0xe8, 0xca, 0x62, 0x0c, 0x90, 0xf8, - 0x10, 0x45, 0x9c, 0x39, 0xdd, 0x6e, 0xe6, 0x74, 0xf7, 0x30, 0xa7, 0x7b, - 0xb0, 0x4f, 0x74, 0xdc, 0x89, 0x25, 0x11, 0x83, 0x3a, 0x6c, 0x24, 0x7e, - 0x19, 0x50, 0xfb, 0xb4, 0xe6, 0xbb, 0x88, 0xf1, 0xc5, 0x76, 0x8e, 0x67, - 0x10, 0x27, 0x24, 0x4f, 0x30, 0xf0, 0xd3, 0x4c, 0xce, 0xef, 0x6a, 0x19, - 0xd3, 0x0f, 0x8c, 0xb4, 0xe0, 0xbb, 0xcc, 0xe1, 0x46, 0xfb, 0x42, 0x3b, - 0x5f, 0x56, 0x5a, 0xf1, 0x5d, 0x3b, 0x5e, 0x88, 0x0d, 0xb7, 0xe2, 0xdd, - 0x84, 0x16, 0x5f, 0xa8, 0x84, 0xda, 0xd3, 0xbc, 0xff, 0x5e, 0xf6, 0x66, - 0x72, 0xd8, 0x25, 0x38, 0x4e, 0x1b, 0xee, 0x49, 0x09, 0x96, 0x3b, 0xe1, - 0xda, 0x76, 0x07, 0xde, 0x1a, 0xce, 0xe5, 0x6e, 0x21, 0xe6, 0x6e, 0x77, - 0xf6, 0xd3, 0x1e, 0x52, 0x10, 0x6f, 0x60, 0x0e, 0x17, 0x5c, 0x55, 0xc4, - 0xfc, 0xed, 0xa3, 0x48, 0x2e, 0x7f, 0x8b, 0x57, 0x07, 0xf5, 0x17, 0x15, - 0x73, 0xa7, 0xbc, 0x7b, 0xf4, 0x1a, 0x72, 0xe7, 0xc6, 0x4f, 0x10, 0x6b, - 0x37, 0xd1, 0x07, 0xae, 0x8b, 0x48, 0x7e, 0xa7, 0x61, 0x38, 0x65, 0xbf, - 0xcf, 0xad, 0xff, 0x94, 0xf3, 0xeb, 0xd7, 0xc4, 0x06, 0x1c, 0x38, 0xad, - 0xd7, 0x7b, 0xbd, 0x0e, 0x07, 0x6e, 0xd1, 0x83, 0xab, 0x8e, 0x20, 0xca, - 0x79, 0x97, 0xbd, 0xc2, 0x5c, 0x3c, 0x75, 0x26, 0xe5, 0x1d, 0x94, 0x4e, - 0xbc, 0x35, 0xf7, 0xef, 0xf3, 0x79, 0x58, 0x21, 0x1f, 0x13, 0x9b, 0x6b, - 0x68, 0x76, 0xa0, 0xde, 0x2c, 0x86, 0x96, 0x49, 0x93, 0x5f, 0xc6, 0x39, - 0xd7, 0x71, 0x08, 0xf6, 0x37, 0x98, 0x5e, 0x84, 0xed, 0xff, 0xf9, 0xf5, - 0x7c, 0xc2, 0x3e, 0x03, 0x4a, 0x9c, 0xcb, 0xe1, 0xea, 0x73, 0x89, 0x52, - 0x80, 0xf8, 0x94, 0xe0, 0xd8, 0x8a, 0x47, 0x4c, 0xb8, 0x0c, 0xfa, 0x57, - 0x9f, 0x07, 0xea, 0x2e, 0x0f, 0xfc, 0xc9, 0xc7, 0xac, 0x72, 0xe2, 0x6a, - 0xd9, 0x2e, 0xce, 0x91, 0xc3, 0xb2, 0x9e, 0x9a, 0x27, 0x38, 0x2b, 0x65, - 0xb5, 0xd6, 0x0f, 0x79, 0xad, 0x11, 0x67, 0x35, 0x62, 0x6b, 0x05, 0xf1, - 0xb1, 0x3b, 0x59, 0x8d, 0xcd, 0xdb, 0x06, 0xa8, 0x73, 0x2f, 0x1c, 0xbc, - 0x4e, 0x25, 0xfd, 0x36, 0x76, 0x82, 0xbf, 0x2b, 0xe9, 0x33, 0xa0, 0x9d, - 0x6d, 0x4d, 0x5a, 0xf3, 0xef, 0x8c, 0x98, 0x7d, 0x95, 0xec, 0xcb, 0x34, - 0xe2, 0xed, 0xc6, 0x64, 0xd0, 0x7b, 0xab, 0xaa, 0xe0, 0xf6, 0x88, 0xce, - 0xb6, 0x3d, 0xe8, 0x4b, 0x0a, 0x4e, 0x4c, 0x50, 0x8f, 0x66, 0x43, 0x19, - 0x75, 0xe9, 0xa2, 0x2e, 0x67, 0xd8, 0xe7, 0x55, 0xeb, 0x50, 0xbe, 0x27, - 0xca, 0x3e, 0x37, 0x12, 0x8b, 0x4d, 0x6c, 0xe2, 0xcf, 0xf9, 0xbb, 0x97, - 0xe3, 0xba, 0x6d, 0x76, 0xee, 0xbb, 0x40, 0xf2, 0x99, 0xd7, 0x22, 0x21, - 0xfd, 0x1e, 0xd5, 0x89, 0xb7, 0xb3, 0x82, 0xb5, 0xf2, 0x3e, 0x3d, 0xc6, - 0x67, 0x68, 0xcd, 0x58, 0x9a, 0x14, 0x8c, 0xf2, 0x93, 0x67, 0x47, 0xb1, - 0x24, 0x29, 0xfe, 0x68, 0xe2, 0xb6, 0xeb, 0xeb, 0xf0, 0xfe, 0xf9, 0x75, - 0x0b, 0x1f, 0x26, 0x89, 0x99, 0x93, 0xc4, 0xcc, 0x49, 0x62, 0xe6, 0xa4, - 0xbd, 0x16, 0xa1, 0xe2, 0xf4, 0x90, 0x82, 0xf7, 0x6c, 0xfc, 0xdb, 0x69, - 0x73, 0xa8, 0x27, 0x19, 0xd3, 0xdb, 0xd3, 0x3a, 0x0e, 0xd0, 0x16, 0x92, - 0x29, 0xb1, 0x35, 0x05, 0x4f, 0xf5, 0x45, 0x50, 0x45, 0xdb, 0xd9, 0x4a, - 0x9b, 0x7e, 0x78, 0xbb, 0x16, 0x98, 0xef, 0x08, 0xb5, 0xa6, 0xd0, 0x84, - 0x07, 0x88, 0x57, 0x0f, 0x31, 0x97, 0x39, 0x44, 0x4c, 0xbb, 0x67, 0x70, - 0x2d, 0x96, 0xf4, 0xa9, 0xc4, 0x2c, 0x62, 0xd5, 0x74, 0xc1, 0x6e, 0xc1, - 0x4b, 0x79, 0x57, 0x2e, 0x2a, 0xeb, 0x9a, 0xca, 0x5d, 0xc4, 0xaa, 0xc6, - 0x5e, 0xe1, 0x38, 0xcc, 0x93, 0x18, 0x8b, 0x12, 0xc4, 0xaa, 0x2d, 0x69, - 0x99, 0xaf, 0x4e, 0xdc, 0x4b, 0xbb, 0x5e, 0x9f, 0x5f, 0x97, 0x98, 0xb3, - 0x55, 0x3b, 0x73, 0x40, 0xc9, 0x71, 0x9d, 0x5e, 0x5e, 0x1f, 0xee, 0x0b, - 0x50, 0x0f, 0x06, 0x8e, 0xed, 0x92, 0x3c, 0x48, 0xfa, 0x13, 0xc0, 0x21, - 0xe2, 0x93, 0x83, 0xba, 0x7e, 0x99, 0xf8, 0x54, 0x49, 0x7c, 0x7a, 0x8d, - 0xf8, 0x34, 0x8d, 0xf8, 0xf4, 0x6a, 0x1e, 0x9f, 0xaa, 0x47, 0xc4, 0x16, - 0x72, 0x5c, 0xfb, 0x78, 0xe2, 0xb9, 0x2a, 0xf9, 0x5f, 0x62, 0x82, 0xf3, - 0x97, 0xc7, 0xff, 0xa5, 0x78, 0x71, 0x00, 0xee, 0x19, 0xe4, 0xb2, 0x16, - 0xf1, 0xe6, 0x03, 0xc7, 0x52, 0xfc, 0x74, 0xa8, 0xc0, 0x61, 0x27, 0xed, - 0x5c, 0xb9, 0xdc, 0x90, 0x75, 0x30, 0x59, 0x03, 0xab, 0xcb, 0xef, 0x0b, - 0x9a, 0xf8, 0xce, 0x3c, 0xe1, 0x8d, 0xb2, 0xae, 0x53, 0x44, 0x7e, 0xd8, - 0x86, 0xe1, 0x6d, 0xcf, 0x62, 0x53, 0x9f, 0x7a, 0x6b, 0x19, 0xc8, 0x85, - 0x95, 0x4e, 0x38, 0x22, 0x95, 0x98, 0x19, 0x11, 0x1b, 0x64, 0x2e, 0x32, - 0xf6, 0x6d, 0x74, 0xef, 0x2e, 0xc3, 0x84, 0xd7, 0xb2, 0x9e, 0xd4, 0x6b, - 0xe5, 0xdf, 0x00, 0x08, 0x5e, 0x7a, 0x8a, 0x18, 0xa3, 0x6e, 0x1d, 0xfd, - 0xb8, 0x33, 0xa7, 0x6b, 0xf0, 0xc5, 0xed, 0x8f, 0xa0, 0x7d, 0xfb, 0x37, - 0xe9, 0x7b, 0x33, 0x7b, 0x6a, 0x69, 0x87, 0xd7, 0x35, 0x8d, 0xe3, 0x44, - 0x84, 0xb1, 0xcf, 0xa7, 0xe0, 0x87, 0x73, 0x66, 0x8a, 0x1c, 0xfe, 0x7d, - 0x60, 0x05, 0x6c, 0x79, 0x6f, 0xe5, 0xfd, 0xe3, 0x39, 0x1f, 0xc7, 0x4e, - 0xd9, 0x27, 0xbc, 0xf9, 0xb3, 0x9b, 0x7f, 0x42, 0x5b, 0x3f, 0x13, 0x19, - 0xfc, 0x2b, 0xc8, 0x78, 0xdd, 0x8a, 0x2d, 0x93, 0x7a, 0x45, 0xf9, 0x36, - 0xbe, 0x49, 0x8e, 0x47, 0x9e, 0xa7, 0xf3, 0x7b, 0xf0, 0x59, 0x91, 0xcf, - 0x67, 0x05, 0xf9, 0x2f, 0x5a, 0xb1, 0x36, 0xb9, 0x96, 0x32, 0x1f, 0xf1, - 0x99, 0x94, 0x2b, 0x3c, 0x7b, 0x36, 0x2f, 0xa7, 0x18, 0x81, 0xea, 0x9c, - 0x9c, 0x2f, 0x51, 0xce, 0x69, 0x62, 0x9e, 0x7a, 0xfd, 0x54, 0x59, 0x85, - 0x76, 0xff, 0xf7, 0x79, 0x59, 0xb9, 0x72, 0x45, 0xd3, 0x51, 0x2a, 0x65, - 0xa7, 0xae, 0x7b, 0x17, 0xd1, 0x77, 0x43, 0xde, 0xf5, 0xf6, 0x7a, 0xb3, - 0x8e, 0x15, 0x17, 0xe7, 0x4c, 0xf2, 0xde, 0x1b, 0xb9, 0x82, 0x17, 0x6f, - 0x33, 0x47, 0xca, 0xad, 0xbf, 0x4b, 0xfe, 0x65, 0xe0, 0xf1, 0x44, 0xb0, - 0x75, 0xa5, 0xd2, 0x10, 0x9b, 0x4d, 0x6e, 0x81, 0x2a, 0x59, 0x93, 0x6e, - 0xb6, 0xff, 0x5f, 0x5e, 0x36, 0xd4, 0xcc, 0x3c, 0xcd, 0xa0, 0x2d, 0x05, - 0x3b, 0x4e, 0xd8, 0xfb, 0x89, 0x06, 0x5e, 0xca, 0xbe, 0x92, 0x3f, 0x8f, - 0x28, 0x73, 0x1e, 0xe6, 0x9c, 0x4f, 0x5d, 0x13, 0x95, 0xf9, 0x0f, 0xa6, - 0x33, 0xa8, 0x16, 0x1e, 0x68, 0x9a, 0xd0, 0xe9, 0x37, 0x26, 0x43, 0xd8, - 0x0d, 0x88, 0xfb, 0x64, 0x6f, 0xc1, 0x97, 0xff, 0x3f, 0x66, 0xac, 0xf7, - 0x09, 0x6b, 0x3c, 0x60, 0xbd, 0xdc, 0x99, 0x33, 0x1d, 0xe6, 0xd8, 0xd5, - 0xc8, 0x78, 0x65, 0xfd, 0x00, 0xe6, 0x34, 0x23, 0x00, 0x9f, 0x76, 0x37, - 0xc7, 0xed, 0xc2, 0x74, 0xe6, 0x47, 0x91, 0x99, 0x0d, 0x6d, 0x4d, 0xea, - 0x15, 0x88, 0x55, 0xc9, 0x79, 0x22, 0x9d, 0xf6, 0x0f, 0x14, 0xf7, 0xca, - 0xf9, 0x0d, 0xb3, 0xd5, 0x8d, 0xa0, 0x7f, 0xae, 0xa2, 0xa0, 0x28, 0x04, - 0xe7, 0xfd, 0x59, 0xf2, 0xb0, 0x99, 0x1f, 0x59, 0x3f, 0xf2, 0xe9, 0xcc, - 0xe7, 0x0b, 0x7d, 0xd0, 0xf1, 0xf5, 0xd1, 0x4b, 0x33, 0xc8, 0x82, 0xcc, - 0xf7, 0xad, 0xd8, 0x74, 0x69, 0x5b, 0xe4, 0x7e, 0x52, 0x5f, 0x73, 0x7d, - 0xfc, 0xa7, 0x59, 0xf5, 0x01, 0x07, 0x2a, 0xb1, 0x5e, 0x37, 0xa6, 0xcb, - 0xd9, 0xec, 0x7b, 0x65, 0x8d, 0xc5, 0x3e, 0xcf, 0x36, 0xf5, 0x5c, 0xd6, - 0xd4, 0x75, 0x63, 0x2f, 0xaa, 0x89, 0xe1, 0x25, 0x49, 0xd1, 0xf5, 0x35, - 0x50, 0xa9, 0xef, 0x63, 0xc4, 0xa2, 0xe2, 0xa4, 0x87, 0x79, 0xab, 0x87, - 0x58, 0x67, 0xe0, 0xb9, 0x6c, 0x07, 0x5c, 0xe4, 0x4e, 0x13, 0xd9, 0x30, - 0x5e, 0xcd, 0xce, 0x99, 0x2e, 0xe7, 0x5e, 0xa9, 0x02, 0x38, 0x67, 0xca, - 0x6f, 0x53, 0xde, 0xe7, 0x53, 0x72, 0xbf, 0xdf, 0xb7, 0xdf, 0x35, 0x77, - 0x18, 0x2b, 0x71, 0x4f, 0xa2, 0x4a, 0xd6, 0xda, 0x4d, 0x9f, 0x61, 0x5a, - 0xd3, 0xb4, 0xaa, 0xe9, 0xb9, 0xf3, 0x30, 0xc1, 0xf6, 0xa5, 0xc4, 0x91, - 0xd5, 0x11, 0xad, 0xed, 0xbf, 0x2b, 0xc1, 0x40, 0x5a, 0x69, 0x63, 0xf9, - 0x30, 0x36, 0x8f, 0x4a, 0x5d, 0x85, 0xe3, 0x2d, 0xec, 0x57, 0x37, 0x04, - 0x42, 0xea, 0xaf, 0x0b, 0x67, 0xa1, 0xdd, 0x45, 0x46, 0x1c, 0xcf, 0x26, - 0xa6, 0xcb, 0xff, 0x2c, 0x90, 0x35, 0x95, 0xbc, 0x4c, 0x8f, 0x59, 0x65, - 0x48, 0x5b, 0xed, 0x6c, 0xcb, 0x3c, 0xeb, 0x25, 0x86, 0xb8, 0xb4, 0xe0, - 0xd1, 0xaf, 0x22, 0xb8, 0x66, 0xbe, 0xa3, 0x13, 0x67, 0x22, 0x5a, 0xc7, - 0x47, 0x6c, 0xa3, 0xca, 0x11, 0x46, 0x6f, 0x5e, 0xbe, 0xfc, 0x9f, 0xd8, - 0x9c, 0xac, 0x86, 0x55, 0x45, 0xea, 0x69, 0x2b, 0x33, 0x3d, 0x27, 0xbf, - 0xd8, 0x58, 0xce, 0xfc, 0xd8, 0x43, 0xb9, 0x72, 0xe6, 0x36, 0xb8, 0xf3, - 0xd7, 0x30, 0xad, 0x6a, 0x4d, 0xeb, 0xf9, 0xaa, 0xda, 0x89, 0x15, 0x4d, - 0xc1, 0xc0, 0x32, 0xda, 0x48, 0x95, 0x2d, 0x23, 0x16, 0x2e, 0xfa, 0xd8, - 0x33, 0x71, 0xf4, 0x23, 0xc8, 0xba, 0x23, 0xcb, 0x95, 0xca, 0x99, 0x31, - 0x79, 0xd7, 0xd4, 0x89, 0x85, 0x8c, 0x6f, 0xf1, 0xc2, 0xff, 0x74, 0xb2, - 0xf7, 0x86, 0xbe, 0x31, 0xfd, 0xc2, 0xff, 0xd9, 0xfd, 0xff, 0x01, 0x02, - 0x8b, 0x0c, 0x6e, 0x74, 0x57, 0x00, 0x00, 0x00 }; + 0xad, 0xbc, 0x0b, 0x74, 0x1c, 0xd5, 0x95, 0x2e, 0xfc, 0x55, 0x75, 0xb7, + 0xd4, 0x92, 0xda, 0x52, 0x4b, 0x6e, 0xcb, 0x6d, 0xd0, 0xe0, 0x6a, 0xab, + 0xda, 0x6a, 0x2c, 0x01, 0xd5, 0xb2, 0x0c, 0x4d, 0xa6, 0xc0, 0x1d, 0x5b, + 0x80, 0x0c, 0x26, 0x11, 0xc6, 0xb9, 0x23, 0xe6, 0x7a, 0xfe, 0xf4, 0x18, + 0x03, 0x86, 0x90, 0x5c, 0x33, 0x93, 0x9b, 0x71, 0xb8, 0x9e, 0xeb, 0x8a, + 0xe4, 0x87, 0xc0, 0xa5, 0xee, 0x96, 0x90, 0x1f, 0xac, 0x35, 0xeb, 0xa7, + 0x2d, 0xcb, 0x92, 0x21, 0xad, 0x16, 0x49, 0x98, 0x19, 0xe7, 0xe6, 0x81, + 0xc6, 0xd8, 0x60, 0x93, 0xf0, 0xc8, 0x6b, 0xfd, 0x4c, 0xfe, 0xb9, 0x7f, + 0x3c, 0xb6, 0x79, 0x83, 0xe3, 0x3c, 0x47, 0x9e, 0xc1, 0xa9, 0xff, 0xdb, + 0xd5, 0xdd, 0xb6, 0xec, 0x40, 0x1e, 0xeb, 0x8e, 0xd6, 0xaa, 0xa5, 0xee, + 0xaa, 0x73, 0xf6, 0x39, 0x67, 0x9f, 0xbd, 0xbf, 0xfd, 0xed, 0x73, 0x4e, + 0xb5, 0x06, 0x54, 0xa3, 0xf4, 0x37, 0x8b, 0xd7, 0xd5, 0x1d, 0x1b, 0xee, + 0x5e, 0xdc, 0x7e, 0x75, 0x87, 0x7c, 0xf7, 0xce, 0xf5, 0x7a, 0xf1, 0x61, + 0x7f, 0x26, 0x12, 0x97, 0xde, 0xd2, 0x3e, 0xb4, 0xe0, 0x47, 0xfc, 0x25, + 0x10, 0x91, 0x7f, 0xad, 0xa5, 0xaf, 0x1e, 0x20, 0x58, 0x6e, 0x5f, 0x2e, + 0xf8, 0x55, 0xb3, 0xf3, 0xbf, 0x2e, 0xd3, 0xe1, 0xf7, 0x98, 0x9f, 0xff, + 0x8b, 0xbb, 0x75, 0x20, 0x99, 0x6f, 0xd5, 0x96, 0xe3, 0x9c, 0x63, 0x85, + 0xbc, 0x90, 0xfb, 0x7f, 0x62, 0x7e, 0xf0, 0xc4, 0xb7, 0xae, 0x8b, 0x9c, + 0xc9, 0x79, 0xe0, 0x0f, 0x9a, 0x16, 0x82, 0x0b, 0xe1, 0x6f, 0x62, 0x9d, + 0xbf, 0x6b, 0xd9, 0xa6, 0xa2, 0xb6, 0x2c, 0x2b, 0x12, 0xce, 0x21, 0x12, + 0xb4, 0x10, 0x89, 0x59, 0x40, 0xca, 0x6b, 0x22, 0x55, 0x69, 0xfa, 0x51, + 0xa1, 0x57, 0x20, 0x15, 0xdc, 0xa8, 0x6d, 0xe1, 0x18, 0x97, 0xd9, 0x7e, + 0xed, 0x44, 0x1e, 0xb8, 0xdb, 0xf6, 0xe3, 0xb8, 0x27, 0xa0, 0x9d, 0xcc, + 0xef, 0xab, 0x2b, 0xea, 0x23, 0x09, 0x8f, 0x8e, 0x94, 0x6a, 0xca, 0x7d, + 0x68, 0xcb, 0xf3, 0x48, 0xf9, 0xcc, 0xcf, 0x6b, 0xe3, 0x36, 0xd0, 0x9b, + 0x69, 0x36, 0x4e, 0xa0, 0x35, 0x7c, 0x18, 0x95, 0x48, 0x85, 0x22, 0x31, + 0xe0, 0x83, 0x73, 0x8f, 0x66, 0x14, 0xf8, 0xf4, 0xd9, 0xe8, 0xdc, 0x0b, + 0x3c, 0x92, 0x89, 0x24, 0x75, 0x05, 0xe8, 0x9f, 0x94, 0xba, 0x91, 0x60, + 0x8e, 0xcf, 0xb7, 0x64, 0x80, 0xad, 0x99, 0xd9, 0xd8, 0x96, 0x75, 0xf0, + 0x9c, 0xd1, 0x1c, 0xdc, 0xc7, 0x16, 0x7a, 0xdd, 0xe7, 0xb3, 0x61, 0xe5, + 0xe4, 0xf9, 0x5b, 0xce, 0xb7, 0x5a, 0x82, 0x78, 0x7a, 0x32, 0x84, 0x67, + 0x27, 0xeb, 0xf1, 0x48, 0xb6, 0x1e, 0xdb, 0xb3, 0x31, 0xa8, 0xba, 0x83, + 0x58, 0x3c, 0x86, 0x8a, 0xeb, 0x1d, 0x9c, 0x34, 0xda, 0xb0, 0x95, 0x82, + 0x5f, 0x6d, 0x6b, 0xc4, 0xda, 0x60, 0x13, 0xb6, 0xe8, 0xd7, 0xa1, 0x38, + 0xd6, 0x0f, 0xce, 0x65, 0x32, 0xd2, 0x3f, 0xaf, 0xaa, 0xea, 0x37, 0xe2, + 0xf4, 0x4e, 0x13, 0xef, 0xef, 0xc4, 0x9a, 0x5a, 0x38, 0x4e, 0x3e, 0x1e, + 0xed, 0x7e, 0x50, 0x09, 0x6a, 0x4f, 0xe5, 0xd9, 0xa1, 0x55, 0x5e, 0xca, + 0x83, 0x36, 0x92, 0x9f, 0x39, 0x15, 0x6c, 0x2f, 0xc3, 0x76, 0x33, 0xd2, + 0x97, 0x30, 0xbe, 0xd5, 0xf2, 0xdf, 0x68, 0x0f, 0xc5, 0x31, 0x6d, 0xcd, + 0xbc, 0xc6, 0x3e, 0x69, 0xec, 0x4f, 0x13, 0xbe, 0x36, 0x19, 0xc6, 0x57, + 0xd9, 0xb7, 0xaf, 0x4c, 0x4a, 0x1f, 0x23, 0x7b, 0x2c, 0xd4, 0x63, 0x34, + 0xdb, 0x84, 0xa7, 0xf5, 0x36, 0x7c, 0x85, 0x7d, 0xec, 0x33, 0x62, 0x58, + 0x9b, 0xb8, 0x8b, 0xfd, 0x51, 0xb0, 0xaa, 0xed, 0x2f, 0x4b, 0xfd, 0x8a, + 0x68, 0x50, 0x55, 0x24, 0x1b, 0x22, 0x31, 0x4d, 0x15, 0x99, 0x17, 0xfa, + 0x3b, 0x90, 0x81, 0xe5, 0x37, 0xa5, 0xcf, 0x37, 0x22, 0xcf, 0xfe, 0x7e, + 0x79, 0x67, 0xd4, 0x58, 0xaf, 0x62, 0x65, 0x80, 0x7d, 0x7e, 0x20, 0x1e, + 0x4d, 0x2c, 0x62, 0x9f, 0xc7, 0xf3, 0x2a, 0xc7, 0x13, 0xd2, 0xc6, 0xd8, + 0xf7, 0xe4, 0x2a, 0x95, 0x7d, 0x67, 0x5f, 0x32, 0xec, 0x4b, 0x86, 0x7d, + 0xc9, 0xb0, 0x2f, 0x6e, 0xbf, 0x63, 0xec, 0x73, 0x71, 0x8e, 0x46, 0xf2, + 0xc7, 0xd9, 0xdf, 0x99, 0xfd, 0x6c, 0x62, 0xdf, 0x91, 0xaa, 0xe7, 0xbc, + 0x35, 0xa7, 0x65, 0xde, 0x1c, 0xe7, 0x55, 0xc3, 0x71, 0x7e, 0x6e, 0x04, + 0xa8, 0xbf, 0x0c, 0xed, 0xa0, 0xdc, 0x9f, 0xf9, 0x56, 0x85, 0x89, 0x4e, + 0x9a, 0xa0, 0x73, 0xa4, 0x23, 0x9a, 0x68, 0x50, 0x54, 0x78, 0xf5, 0xa0, + 0xd6, 0x52, 0x88, 0x18, 0xd4, 0x8f, 0x16, 0x2d, 0x40, 0xd3, 0x0b, 0x94, + 0x75, 0x51, 0xbb, 0x91, 0xe0, 0x14, 0xa4, 0x5d, 0x8d, 0xed, 0x1f, 0x2f, + 0xcd, 0x9d, 0xc8, 0x0f, 0xb3, 0x4d, 0x69, 0x5f, 0x64, 0x3b, 0xce, 0xcf, + 0x0c, 0xe8, 0x41, 0x44, 0xad, 0x41, 0xda, 0x9f, 0xc7, 0x0c, 0x6a, 0x1b, + 0xf2, 0x7c, 0x7e, 0x5e, 0x46, 0x71, 0x3e, 0xd6, 0xe6, 0xb5, 0xd2, 0x18, + 0x22, 0xec, 0x82, 0xd8, 0x41, 0x38, 0x15, 0x30, 0x83, 0xd2, 0xf7, 0xee, + 0x3d, 0x03, 0x9b, 0x9d, 0x79, 0xba, 0xe8, 0x4a, 0xdf, 0x38, 0xcf, 0x13, + 0x48, 0x9c, 0x5e, 0xf2, 0x90, 0x35, 0xab, 0x23, 0x8e, 0x6a, 0x1d, 0x81, + 0x2a, 0x1d, 0xdd, 0xe9, 0x89, 0x6a, 0xab, 0xc6, 0xfc, 0xe6, 0x9d, 0x03, + 0x13, 0x7e, 0x54, 0x4f, 0xe8, 0xa8, 0x9a, 0x78, 0xdc, 0x8b, 0x5a, 0x03, + 0x3b, 0x26, 0xff, 0xcc, 0x5b, 0x1c, 0xdb, 0xcd, 0xa5, 0x31, 0xba, 0xb6, + 0xef, 0x7f, 0xdd, 0x3e, 0xe3, 0x54, 0xe8, 0x55, 0x7f, 0xe6, 0x31, 0x75, + 0x6d, 0x0c, 0x38, 0xb3, 0xb6, 0x63, 0x39, 0x7a, 0x83, 0x0a, 0xe6, 0xeb, + 0x7f, 0x32, 0x0b, 0xb5, 0x26, 0xac, 0xc9, 0xc6, 0x54, 0x85, 0x19, 0x4a, + 0x71, 0x6e, 0xf0, 0x82, 0x9d, 0x83, 0x6f, 0xc0, 0x71, 0xa4, 0xec, 0x49, + 0xdc, 0x79, 0xa7, 0x6a, 0x1e, 0xba, 0xc6, 0x87, 0x4e, 0x96, 0xc7, 0xa6, + 0xa3, 0x1d, 0x3f, 0x57, 0xd4, 0x9d, 0xdd, 0xb0, 0xc6, 0x3d, 0x48, 0x06, + 0x53, 0xfc, 0x7f, 0xc5, 0x15, 0x2b, 0x13, 0xdd, 0xb0, 0xc7, 0xa7, 0x79, + 0xdf, 0xcb, 0x7b, 0x26, 0xd2, 0x99, 0x2b, 0xae, 0xb8, 0x3d, 0x91, 0xc2, + 0xc0, 0xb8, 0x7c, 0xf6, 0x62, 0xaa, 0x3e, 0x85, 0xed, 0xbb, 0x35, 0xd4, + 0xe9, 0xdd, 0xc8, 0x8c, 0xcb, 0x67, 0xc7, 0x39, 0x65, 0x7c, 0x09, 0x7b, + 0xda, 0xe8, 0xff, 0x73, 0xbb, 0xb1, 0x6d, 0xb7, 0x85, 0x4a, 0xdd, 0xa2, + 0xee, 0x15, 0xef, 0x3f, 0xb7, 0x29, 0xd0, 0xee, 0x84, 0xb7, 0x42, 0x17, + 0xbd, 0x25, 0xbc, 0xf7, 0xd8, 0x66, 0x70, 0xbe, 0xee, 0x38, 0x23, 0xc6, + 0x22, 0x7c, 0xba, 0x7b, 0x2d, 0xac, 0x7d, 0x01, 0x58, 0xab, 0xe5, 0x7f, + 0x37, 0x75, 0xb8, 0x16, 0xbd, 0xfb, 0xd6, 0xa2, 0xff, 0x31, 0x3a, 0x6e, + 0x7d, 0xd0, 0x9d, 0xa7, 0x6f, 0xb5, 0x48, 0x9f, 0xa4, 0x7f, 0x3d, 0xbc, + 0x44, 0xb7, 0x5f, 0xe0, 0x7f, 0x29, 0x33, 0xed, 0x60, 0xce, 0x85, 0x32, + 0xdb, 0x59, 0x66, 0xdb, 0x45, 0x65, 0x4c, 0x3c, 0x31, 0x29, 0xba, 0x10, + 0x95, 0xfd, 0x3e, 0x5d, 0x7c, 0xdb, 0xe9, 0x0d, 0x89, 0x2e, 0xac, 0x1e, + 0x1f, 0x22, 0xdd, 0xf7, 0x2a, 0x5e, 0xac, 0x18, 0x00, 0xeb, 0xd0, 0x09, + 0xaa, 0x23, 0xc9, 0x85, 0x8a, 0x89, 0xea, 0x01, 0x05, 0x2b, 0xe2, 0x55, + 0xd0, 0xea, 0x45, 0xde, 0x8f, 0x1c, 0x2b, 0x28, 0xfd, 0x3d, 0x8a, 0x1a, + 0xde, 0x5f, 0x17, 0xff, 0x01, 0xf1, 0x4c, 0xfa, 0x14, 0x67, 0xf9, 0x3b, + 0x78, 0xff, 0x95, 0x19, 0xdf, 0xa5, 0x9c, 0xe3, 0xf4, 0x19, 0x06, 0xfa, + 0x33, 0x6d, 0xd8, 0x9e, 0x49, 0x46, 0xa8, 0x25, 0xcb, 0x67, 0xf2, 0xbe, + 0x19, 0xed, 0xea, 0x85, 0xb4, 0x03, 0xa5, 0xda, 0x84, 0x37, 0xdf, 0x71, + 0xdc, 0xff, 0x92, 0xad, 0xf7, 0x3c, 0xa5, 0xf8, 0x68, 0xec, 0xd2, 0xce, + 0x71, 0xff, 0x2b, 0xb6, 0x82, 0x37, 0xf5, 0xe8, 0x86, 0x77, 0x94, 0xe3, + 0xfe, 0x97, 0xf3, 0x41, 0xcc, 0x1b, 0x88, 0xf4, 0x58, 0x4a, 0x02, 0x5f, + 0xcf, 0x87, 0x10, 0x1e, 0x30, 0x71, 0x30, 0x6f, 0xe0, 0xc9, 0x8b, 0x70, + 0xe0, 0x43, 0xff, 0x2c, 0x0f, 0xc7, 0xbe, 0xce, 0xd6, 0xd0, 0x6b, 0x9c, + 0x73, 0x92, 0x41, 0xa4, 0xea, 0xcc, 0xe3, 0xfe, 0xf7, 0x07, 0xa0, 0xd4, + 0x9a, 0x7a, 0xb8, 0xa0, 0xfc, 0xab, 0x93, 0x0a, 0x49, 0x31, 0xf6, 0xcf, + 0xc5, 0xb2, 0x24, 0xed, 0xce, 0x20, 0xce, 0x9d, 0x71, 0x6a, 0x68, 0xb3, + 0x15, 0xe6, 0x65, 0x18, 0x1f, 0xd6, 0xf1, 0xa4, 0xed, 0x38, 0xef, 0x19, + 0x53, 0x89, 0x00, 0xf4, 0xee, 0x77, 0x11, 0x49, 0x2e, 0xa2, 0x5e, 0x8e, + 0xe6, 0x75, 0x8c, 0xda, 0x26, 0x9e, 0xb3, 0x9b, 0x83, 0x7d, 0x58, 0x8c, + 0x64, 0xb8, 0x18, 0x43, 0x26, 0xd8, 0xef, 0x91, 0x68, 0x37, 0xea, 0xcc, + 0x04, 0x0e, 0xb1, 0xdf, 0xa7, 0x97, 0x88, 0x1c, 0x03, 0x2f, 0xff, 0x01, + 0x7d, 0x25, 0xbe, 0xe3, 0x71, 0xf6, 0x35, 0xb1, 0xf8, 0x9c, 0x83, 0xd9, + 0x7e, 0x9c, 0x30, 0xe6, 0xd2, 0x0e, 0x61, 0x55, 0x99, 0x7e, 0x6f, 0xbf, + 0x1d, 0xc4, 0x81, 0x7c, 0xc0, 0xdb, 0x67, 0x87, 0xb0, 0x8f, 0xfe, 0x36, + 0x8f, 0xa6, 0x1e, 0xa6, 0xdc, 0x79, 0xc4, 0xb5, 0xc2, 0x70, 0x13, 0x26, + 0x87, 0x23, 0xc6, 0x2b, 0x4a, 0x18, 0x63, 0xa3, 0x97, 0x61, 0x62, 0x58, + 0xc1, 0x78, 0x94, 0x7d, 0xe7, 0xe7, 0x2f, 0x0f, 0x5f, 0x81, 0xfc, 0xb0, + 0x07, 0x3b, 0x5c, 0xbd, 0xba, 0x38, 0x53, 0xfa, 0x7f, 0x19, 0x72, 0xa3, + 0xf0, 0x2e, 0x1a, 0x08, 0xe2, 0xa9, 0xbc, 0xd7, 0xab, 0x0f, 0x84, 0x30, + 0x9a, 0xff, 0x36, 0xe7, 0x4d, 0x64, 0x6b, 0x18, 0xb1, 0xc7, 0xdc, 0x39, + 0xac, 0x33, 0x29, 0xac, 0x18, 0x5f, 0x19, 0xcb, 0x34, 0xc6, 0x99, 0x04, + 0x71, 0x48, 0x7c, 0xdc, 0x4f, 0x0c, 0x12, 0x1f, 0x7f, 0x4d, 0x41, 0x6d, + 0x02, 0x7d, 0x93, 0xe5, 0xe7, 0x0a, 0xed, 0xdf, 0x8b, 0x75, 0x41, 0x03, + 0x76, 0x46, 0xec, 0xb4, 0x8c, 0xcb, 0xf2, 0x59, 0xe6, 0xbf, 0x1a, 0xd6, + 0xfe, 0x6a, 0xec, 0xa0, 0x8f, 0x3d, 0xba, 0x53, 0xee, 0x3b, 0xce, 0x7d, + 0xf1, 0x3a, 0xda, 0x18, 0x6e, 0xaa, 0x42, 0xd4, 0x78, 0xcb, 0xed, 0x9b, + 0x85, 0xb1, 0xbc, 0xc4, 0x50, 0x8d, 0xf1, 0xed, 0x28, 0xdb, 0xea, 0x60, + 0x3b, 0x06, 0xbe, 0x3d, 0xd9, 0x86, 0x7f, 0x9c, 0x8c, 0xe1, 0x1f, 0x26, + 0x75, 0xfc, 0xfd, 0xa4, 0x86, 0x67, 0x2e, 0xc2, 0xf5, 0x3b, 0xa9, 0x2b, + 0xc1, 0x30, 0x03, 0x5b, 0x32, 0x15, 0xd8, 0x36, 0x5c, 0x8d, 0xbe, 0xe1, + 0xe6, 0xd8, 0x73, 0xc4, 0xe3, 0x7f, 0x30, 0x6e, 0xc7, 0x54, 0x43, 0x87, + 0xeb, 0x33, 0x8f, 0xf0, 0xfe, 0xa3, 0xc3, 0xcd, 0x9c, 0x43, 0xc7, 0x51, + 0xe3, 0xad, 0x89, 0x43, 0xc4, 0xf7, 0xe3, 0xa1, 0x88, 0x36, 0xa5, 0x46, + 0xb4, 0x24, 0x7c, 0xb0, 0xdb, 0x54, 0x58, 0x73, 0x22, 0x39, 0x7a, 0x31, + 0x42, 0xfa, 0x7d, 0x1c, 0x5b, 0x44, 0xb3, 0x54, 0x83, 0xf6, 0xcb, 0x98, + 0xa1, 0x76, 0x10, 0x5f, 0xaa, 0xf1, 0xfe, 0x70, 0xa4, 0xdf, 0x52, 0xef, + 0x80, 0xd5, 0xe0, 0x38, 0x5f, 0x8d, 0x63, 0xc3, 0x5c, 0x13, 0xc9, 0x39, + 0x8c, 0x05, 0x57, 0x98, 0x49, 0x30, 0x8e, 0xe1, 0xf4, 0x80, 0x1e, 0xfe, + 0x7f, 0x94, 0x3b, 0xf1, 0xdf, 0xbb, 0x23, 0x9a, 0xa6, 0xb6, 0x5a, 0xfb, + 0x54, 0x92, 0x8d, 0x46, 0x68, 0x61, 0xf3, 0x56, 0x6c, 0x74, 0x79, 0x82, + 0x82, 0xa0, 0xde, 0x81, 0xbe, 0x0c, 0x2b, 0x85, 0x9a, 0x7b, 0x06, 0xd5, + 0xe6, 0x69, 0x43, 0x8d, 0x1c, 0xed, 0x56, 0x89, 0xb7, 0x8b, 0x4f, 0x3b, + 0x5a, 0xa3, 0xe3, 0xb4, 0x2f, 0x96, 0x36, 0x35, 0x34, 0x70, 0x9e, 0xeb, + 0x39, 0xcf, 0xed, 0x85, 0x6a, 0xbc, 0x33, 0x0c, 0x6b, 0xae, 0x19, 0xe9, + 0x7a, 0x40, 0xad, 0xc6, 0xdb, 0xa3, 0xd5, 0x38, 0x39, 0xec, 0xc5, 0x5b, + 0xc3, 0x8e, 0x73, 0x8f, 0x51, 0x87, 0x8a, 0x38, 0xe6, 0x54, 0x20, 0x7a, + 0x66, 0x04, 0x16, 0x7e, 0xc3, 0xb2, 0xbf, 0x1c, 0x0e, 0xe3, 0x57, 0xc3, + 0x1f, 0xc3, 0x33, 0x0d, 0xc9, 0x63, 0xb3, 0x19, 0x23, 0xa7, 0x69, 0x3f, + 0xa7, 0xed, 0x48, 0xcf, 0x3c, 0x4f, 0x64, 0x23, 0x79, 0xcb, 0xfa, 0x2f, + 0x2a, 0x91, 0xd4, 0x2b, 0x4a, 0x44, 0x1b, 0x50, 0x42, 0x78, 0x97, 0x76, + 0x7a, 0x2a, 0xdf, 0x9c, 0xf8, 0x01, 0xdb, 0xff, 0xb5, 0xf1, 0x0f, 0xce, + 0x54, 0xa3, 0xe8, 0x50, 0xf4, 0x45, 0x9d, 0xd3, 0x77, 0xff, 0x91, 0x31, + 0xea, 0x1f, 0x32, 0xd4, 0x39, 0xfb, 0xf3, 0xcc, 0x6f, 0xc5, 0x2f, 0x99, + 0xaf, 0x04, 0xe7, 0xf1, 0x72, 0xfc, 0x4f, 0x77, 0x6c, 0xc7, 0x9c, 0xbf, + 0x09, 0xc9, 0xf8, 0x3a, 0x1b, 0x8b, 0x18, 0x24, 0xe3, 0x3c, 0xea, 0xa4, + 0x82, 0x32, 0x46, 0x19, 0xab, 0xab, 0x4b, 0x6d, 0x83, 0xf2, 0x90, 0x8a, + 0x6a, 0xc7, 0x79, 0xcc, 0x28, 0x3d, 0x0f, 0x95, 0xc7, 0xfa, 0x31, 0xde, + 0x97, 0xf1, 0xbe, 0xe3, 0x11, 0xdd, 0x6b, 0xea, 0xd5, 0xfc, 0x1e, 0xb1, + 0x92, 0xb8, 0x33, 0xc0, 0xef, 0xb1, 0xe4, 0xf9, 0xef, 0xde, 0xba, 0x8b, + 0x9f, 0xd3, 0x4e, 0xdd, 0xf6, 0xee, 0xe4, 0x77, 0x19, 0xcb, 0xab, 0xb4, + 0x9b, 0x0f, 0xb3, 0x13, 0xb1, 0x91, 0x18, 0xed, 0xe9, 0x94, 0xc4, 0x15, + 0x2b, 0x64, 0xfa, 0x2d, 0xd5, 0x84, 0x46, 0x9c, 0xf0, 0x2b, 0xe6, 0x06, + 0x68, 0x79, 0x0b, 0x9f, 0xea, 0xf0, 0xe0, 0xaf, 0x3a, 0x14, 0xcc, 0xd6, + 0x37, 0x20, 0x7b, 0xad, 0xe5, 0xd4, 0xeb, 0x7b, 0x55, 0xf1, 0x81, 0x8a, + 0x34, 0x2c, 0xfa, 0x1d, 0x12, 0xe4, 0x4a, 0x75, 0x7f, 0xaa, 0xe0, 0x44, + 0x3c, 0x4a, 0x9b, 0xdb, 0x82, 0x6d, 0x9c, 0xf3, 0x59, 0x69, 0xf8, 0x03, + 0xa6, 0x09, 0x7b, 0x00, 0xfe, 0x2a, 0xfa, 0xfe, 0x95, 0x03, 0xcd, 0x1b, + 0xc6, 0x94, 0x48, 0x22, 0xad, 0x44, 0xba, 0xa9, 0x6f, 0xe3, 0xb4, 0x8b, + 0x1b, 0x11, 0xad, 0x42, 0x91, 0x76, 0x4c, 0xb4, 0xe4, 0xb7, 0x60, 0x60, + 0x52, 0x3e, 0x27, 0xa0, 0xe7, 0x7f, 0x5c, 0xea, 0x3b, 0xfc, 0x3e, 0xf6, + 0x61, 0xbf, 0xfd, 0xba, 0x93, 0x0b, 0x46, 0xb4, 0x9c, 0xfb, 0x7d, 0x3d, + 0xbf, 0xc3, 0x5f, 0x61, 0x3e, 0x88, 0xe7, 0xed, 0x37, 0xe7, 0x94, 0xcb, + 0x15, 0xfb, 0x7a, 0x69, 0x7f, 0xfe, 0xb7, 0x93, 0x0c, 0xb9, 0xfd, 0xf1, + 0xd7, 0xb0, 0x8d, 0xcf, 0x0c, 0xb0, 0x8d, 0x4c, 0xb9, 0x3f, 0x40, 0x20, + 0x2d, 0x71, 0x38, 0xa2, 0x2d, 0x50, 0x9a, 0x8d, 0x01, 0x25, 0x12, 0xbb, + 0x57, 0x69, 0x4d, 0x8c, 0x91, 0x5f, 0x6e, 0x47, 0xb1, 0x4f, 0xd1, 0x7c, + 0xb1, 0x3f, 0x0b, 0xf2, 0x50, 0x3c, 0x03, 0x08, 0xcc, 0xd7, 0x17, 0x62, + 0xb3, 0x3b, 0xa7, 0x50, 0xc2, 0x03, 0x1a, 0x6a, 0xc9, 0x5f, 0xc2, 0x13, + 0xc0, 0xe4, 0x10, 0xb9, 0x5c, 0xbc, 0x19, 0x9f, 0x63, 0x2c, 0x98, 0xc7, + 0x32, 0x5f, 0x0c, 0x9e, 0xc7, 0x2f, 0xa5, 0xdf, 0x26, 0xc0, 0xcc, 0x29, + 0xf2, 0xb2, 0xd4, 0x7f, 0x41, 0x52, 0xee, 0x3d, 0x6e, 0x43, 0xc9, 0xd8, + 0x91, 0x3d, 0x80, 0x3e, 0x15, 0xf7, 0x24, 0xef, 0x0f, 0x63, 0x33, 0x4e, + 0xc7, 0xa3, 0xa9, 0x82, 0x12, 0x35, 0x86, 0x14, 0xc3, 0xbf, 0x8d, 0xed, + 0xed, 0x60, 0x99, 0xed, 0xbc, 0x1e, 0x88, 0xea, 0x5d, 0x77, 0x28, 0xc9, + 0x2b, 0xab, 0x58, 0xe6, 0xa4, 0x11, 0x25, 0xcf, 0x8c, 0x4e, 0xaf, 0x82, + 0xe1, 0x7f, 0x22, 0x2f, 0xb2, 0x12, 0xca, 0x96, 0xc2, 0xe3, 0x6a, 0x11, + 0x8f, 0x7e, 0x5d, 0xd2, 0xd9, 0x49, 0xf9, 0xee, 0xb6, 0xed, 0x1d, 0x68, + 0xaa, 0xf9, 0xed, 0x7b, 0xda, 0x9c, 0x8b, 0xef, 0xb5, 0x06, 0x47, 0xe9, + 0x7f, 0x1e, 0xbd, 0x8a, 0x73, 0x27, 0xfc, 0x28, 0x19, 0xf3, 0x41, 0xee, + 0x79, 0x90, 0xf3, 0x26, 0xc3, 0x1e, 0x7c, 0xe0, 0x24, 0x57, 0xcb, 0xbd, + 0x6a, 0xa4, 0xba, 0x5b, 0xc3, 0x5e, 0xb4, 0x26, 0xb6, 0x12, 0x0b, 0x8e, + 0xaf, 0x5e, 0xc6, 0x67, 0x51, 0xe3, 0x39, 0x34, 0x6b, 0x5b, 0x21, 0x9f, + 0xcf, 0xd2, 0x66, 0x97, 0x49, 0x5d, 0x96, 0x29, 0x72, 0x1f, 0xc1, 0x9a, + 0x2d, 0x86, 0x83, 0xe7, 0x0d, 0x58, 0x95, 0xe6, 0x41, 0xe5, 0x84, 0xfd, + 0x1b, 0x27, 0xe9, 0xc5, 0x4a, 0xfa, 0xa5, 0x41, 0xda, 0xab, 0xf9, 0xcd, + 0xa8, 0x76, 0x94, 0x99, 0x82, 0xc7, 0xb4, 0x94, 0xe3, 0xf9, 0x2d, 0xca, + 0xeb, 0xf9, 0x7e, 0xe5, 0x54, 0x5e, 0xea, 0x1e, 0x54, 0x4e, 0xe6, 0x25, + 0x1e, 0x36, 0x69, 0x47, 0xc8, 0x6f, 0xc8, 0xa9, 0xd4, 0x3e, 0x03, 0xca, + 0x36, 0xa3, 0x96, 0x3c, 0x5f, 0x8f, 0x8d, 0xb0, 0xbf, 0xfb, 0x3b, 0x60, + 0x6c, 0x37, 0x7c, 0x38, 0x1e, 0x44, 0xa0, 0xcf, 0xf0, 0xca, 0x77, 0xe6, + 0x03, 0x52, 0xb7, 0x49, 0xdb, 0x9a, 0x3f, 0x47, 0xff, 0x2a, 0x7e, 0xdf, + 0xdf, 0x51, 0xbe, 0xf7, 0x0b, 0x67, 0x6a, 0xb5, 0xca, 0xef, 0x7f, 0xea, + 0xe1, 0x50, 0x58, 0x77, 0x26, 0x3f, 0x17, 0x2e, 0xa5, 0x92, 0x3f, 0xd6, + 0xc3, 0x0a, 0x46, 0xac, 0x1c, 0x73, 0x85, 0xbe, 0x4c, 0x3b, 0xfd, 0x2d, + 0xcc, 0x58, 0x99, 0x24, 0xbe, 0x93, 0xf7, 0xb2, 0xcd, 0x0a, 0x3d, 0x80, + 0x9b, 0xec, 0x66, 0x4f, 0x51, 0x7f, 0x2a, 0x31, 0xcc, 0xc3, 0x98, 0x2e, + 0x1c, 0xef, 0x52, 0xce, 0xdd, 0xa4, 0xbd, 0xc5, 0x7e, 0x57, 0xe9, 0x7a, + 0xac, 0x4a, 0x69, 0xd2, 0x5e, 0xcf, 0x27, 0xe9, 0xe3, 0x3d, 0x6c, 0x37, + 0x80, 0xd7, 0xed, 0x5a, 0xe6, 0x20, 0x91, 0xa4, 0x45, 0x81, 0x37, 0x77, + 0x84, 0x41, 0xce, 0x37, 0xe3, 0xaf, 0x1b, 0x8c, 0xff, 0x12, 0xa3, 0xd5, + 0x5b, 0x96, 0x24, 0xb0, 0x3e, 0x0f, 0xef, 0xba, 0x0e, 0x13, 0xf7, 0x30, + 0xb6, 0xdf, 0xc7, 0x78, 0xf9, 0x20, 0x63, 0xe1, 0x8e, 0x38, 0xc7, 0x56, + 0xef, 0x38, 0x95, 0xfa, 0x66, 0xc9, 0x67, 0x30, 0xc0, 0x58, 0x7c, 0x37, + 0xe3, 0xcb, 0x16, 0x7e, 0x7e, 0x29, 0xff, 0x1f, 0xce, 0x7d, 0xcc, 0xa7, + 0x9e, 0xbf, 0x48, 0x26, 0xd4, 0x51, 0xbd, 0x35, 0xb6, 0x95, 0xb1, 0x98, + 0x72, 0xad, 0x5a, 0xd3, 0x71, 0xae, 0x8c, 0x46, 0x92, 0x3e, 0xc5, 0xc0, + 0x73, 0x13, 0xc7, 0x1d, 0x6d, 0x8e, 0xe4, 0x52, 0xe5, 0x38, 0x28, 0x63, + 0x95, 0x1c, 0x41, 0xf0, 0x41, 0xf2, 0x84, 0x99, 0x18, 0xa1, 0xe2, 0xe6, + 0x61, 0xc9, 0x13, 0xc2, 0x58, 0x65, 0x7f, 0x09, 0xcf, 0xb5, 0x79, 0xd1, + 0xc5, 0x1c, 0xeb, 0x16, 0x3b, 0x80, 0x3b, 0x88, 0xa5, 0x2b, 0x6c, 0xe6, + 0x4e, 0xc1, 0x10, 0x6e, 0xb5, 0xbd, 0x38, 0xdc, 0xc6, 0x1c, 0x28, 0x54, + 0x89, 0x77, 0x0d, 0x0f, 0x8e, 0x18, 0x41, 0xe4, 0x5c, 0x7f, 0xd8, 0x41, + 0x0c, 0xa4, 0x1e, 0x55, 0xc9, 0x1d, 0x44, 0x87, 0x1e, 0xea, 0x53, 0x45, + 0xea, 0xbc, 0x0e, 0x3f, 0x2c, 0x17, 0x90, 0x7e, 0x49, 0x3e, 0xf0, 0x33, + 0x27, 0x35, 0x47, 0xea, 0xc3, 0x0a, 0x98, 0x32, 0x0e, 0xe1, 0xb7, 0x06, + 0xfa, 0x26, 0x3a, 0xc8, 0xed, 0x66, 0x0e, 0xf5, 0x0c, 0xb9, 0x75, 0x1d, + 0x5e, 0xd3, 0x85, 0x5b, 0xbf, 0x8a, 0x20, 0x7d, 0xb7, 0x7f, 0x22, 0xba, + 0xe1, 0x8c, 0xe2, 0xc1, 0x4b, 0x7a, 0x2d, 0x79, 0x9f, 0x89, 0xed, 0x13, + 0xf0, 0x6e, 0x5d, 0x62, 0x20, 0x3d, 0xd1, 0x9b, 0x98, 0xc5, 0xb4, 0xd7, + 0xbb, 0xa4, 0xc8, 0x89, 0x3e, 0x43, 0xdd, 0xae, 0x8d, 0xbb, 0x9c, 0xa8, + 0xc8, 0x07, 0x82, 0x8e, 0x73, 0x52, 0x17, 0x3d, 0x03, 0x07, 0x4a, 0x3a, + 0xde, 0xcf, 0xcf, 0xfd, 0x25, 0x1d, 0x6f, 0xa1, 0x3c, 0xfa, 0x1f, 0xb6, + 0x5d, 0xc4, 0x63, 0x34, 0x54, 0x9a, 0xc2, 0x6f, 0x88, 0xc3, 0xc4, 0x93, + 0x24, 0x75, 0xfc, 0x42, 0x7e, 0xbd, 0xe0, 0x36, 0xa7, 0xbb, 0xdd, 0xc5, + 0xef, 0xa4, 0x7a, 0x80, 0x76, 0x20, 0x7a, 0x78, 0xad, 0x94, 0xdb, 0x38, + 0xce, 0x90, 0x21, 0x3a, 0x2e, 0xe7, 0x65, 0xa2, 0xeb, 0x36, 0xc9, 0xb1, + 0xfa, 0x81, 0xdf, 0xb0, 0xac, 0x87, 0xb8, 0x6b, 0xe2, 0x6b, 0xdd, 0x62, + 0x3b, 0xb3, 0xdc, 0x58, 0x79, 0xd5, 0x42, 0xc7, 0xf9, 0x4a, 0x5c, 0xc3, + 0x7b, 0x7a, 0x6b, 0xa2, 0x5d, 0x8d, 0xb0, 0xaf, 0x49, 0xd8, 0x93, 0x1d, + 0x9c, 0xbb, 0x2b, 0x90, 0x0c, 0x89, 0xad, 0x61, 0x43, 0x45, 0x11, 0xc3, + 0x71, 0xca, 0xd6, 0x63, 0xdb, 0x38, 0x67, 0xfb, 0x42, 0x5d, 0xe4, 0x71, + 0x6a, 0x27, 0xd3, 0x7f, 0xf2, 0x27, 0xdd, 0x7a, 0x04, 0xef, 0x38, 0xb9, + 0x90, 0xc3, 0x38, 0x29, 0xb9, 0xd1, 0x7c, 0x1c, 0x0e, 0x7a, 0xf0, 0x62, + 0xac, 0x11, 0xc9, 0x7a, 0x05, 0x35, 0xfa, 0x9b, 0xce, 0x77, 0x42, 0xd2, + 0x0e, 0x73, 0x3c, 0xf5, 0x56, 0x8f, 0xe4, 0x80, 0x5e, 0x5d, 0xe4, 0x76, + 0x31, 0xc7, 0xbd, 0xb4, 0xfd, 0x7f, 0x75, 0x8e, 0x87, 0xa4, 0xfd, 0x48, + 0x50, 0x53, 0x7f, 0xd7, 0x1c, 0x7e, 0xdf, 0xf9, 0x81, 0x2b, 0x33, 0xe3, + 0xea, 0x01, 0xaa, 0xc8, 0x23, 0x54, 0x54, 0x8b, 0xcc, 0x72, 0x3b, 0xe2, + 0x67, 0x73, 0x79, 0x4f, 0x9e, 0x89, 0x8d, 0x6c, 0x61, 0xbb, 0xcf, 0x39, + 0x68, 0x94, 0xef, 0xd3, 0x1e, 0x29, 0x6b, 0x4d, 0x1e, 0x5a, 0xe1, 0xc5, + 0x52, 0xb4, 0xc4, 0x97, 0x2d, 0x97, 0xb1, 0xa8, 0x66, 0x52, 0xf3, 0xc3, + 0x6a, 0xf4, 0x10, 0x8b, 0xdf, 0x68, 0x6b, 0xc3, 0x72, 0xe6, 0x8c, 0xef, + 0x10, 0x5c, 0x7a, 0x75, 0x0f, 0xa6, 0x38, 0xbe, 0x27, 0x0d, 0x59, 0x2f, + 0x70, 0x70, 0x4b, 0xdc, 0x4a, 0xd1, 0x63, 0xad, 0x59, 0xb4, 0x9d, 0x6a, + 0x5d, 0xe2, 0x7c, 0x2d, 0x6a, 0x4c, 0x6f, 0xec, 0x1d, 0x44, 0x8c, 0x1d, + 0xe4, 0x39, 0x5a, 0x7d, 0x4b, 0xc2, 0x47, 0xed, 0xbe, 0x6c, 0x47, 0x13, + 0x47, 0x94, 0xa2, 0x3f, 0xbc, 0xc0, 0xb9, 0x7d, 0xcd, 0xd6, 0x37, 0x56, + 0x7a, 0x8a, 0xdf, 0x5f, 0x71, 0xf3, 0xd1, 0xb2, 0x3f, 0x84, 0x4b, 0xb8, + 0xe1, 0xf7, 0x9f, 0xb2, 0x71, 0x86, 0x54, 0x88, 0x79, 0x29, 0xce, 0xf4, + 0x19, 0x53, 0x8a, 0x4f, 0xaf, 0x25, 0xae, 0x0a, 0x96, 0x56, 0x90, 0x13, + 0x4a, 0xec, 0xf7, 0xfb, 0xdf, 0x61, 0x19, 0x72, 0xba, 0xe3, 0xb1, 0xeb, + 0x5b, 0x13, 0x7e, 0x24, 0xad, 0x4a, 0xfa, 0xe5, 0x2c, 0x33, 0xe4, 0xbf, + 0xaa, 0x60, 0x35, 0x06, 0x68, 0xd7, 0x35, 0xcc, 0x57, 0x5b, 0xd2, 0x13, + 0x8c, 0xe1, 0x6d, 0x78, 0x70, 0x82, 0x23, 0x6b, 0x18, 0x6c, 0x54, 0x4d, + 0x59, 0x83, 0x08, 0xc2, 0xd7, 0xf0, 0xe0, 0x0d, 0xaa, 0x79, 0x1c, 0x3d, + 0x1d, 0xfe, 0xce, 0x44, 0x01, 0xfe, 0x7a, 0x73, 0x13, 0xe2, 0x69, 0xc9, + 0x3b, 0x05, 0x23, 0x93, 0x5b, 0x89, 0x5a, 0x8d, 0x75, 0xd7, 0x96, 0xf5, + 0x0d, 0xb5, 0xd6, 0x94, 0xfc, 0x53, 0xeb, 0x7c, 0xc5, 0xc5, 0xd2, 0x20, + 0xf3, 0x85, 0x1f, 0x87, 0xff, 0xcf, 0xea, 0x27, 0x38, 0x27, 0xd2, 0x17, + 0xf9, 0x2f, 0x79, 0x3f, 0xbc, 0x2a, 0xb1, 0xb0, 0x77, 0xdc, 0xcb, 0xfc, + 0x4a, 0xe6, 0x4c, 0xe2, 0xf1, 0x6b, 0xff, 0xf5, 0x79, 0xfa, 0x8b, 0x8f, + 0xba, 0x7f, 0x44, 0xb7, 0x08, 0xf3, 0x8e, 0xa3, 0xc7, 0x23, 0xe1, 0x0a, + 0x45, 0xc3, 0xf6, 0xb6, 0x7f, 0xa7, 0x8d, 0x80, 0x38, 0x06, 0x12, 0xeb, + 0x5a, 0x6c, 0x19, 0xaf, 0x98, 0x51, 0xaf, 0x67, 0x4d, 0xb9, 0xde, 0x80, + 0x6e, 0xa5, 0xa4, 0xde, 0x68, 0x3c, 0xd2, 0xb3, 0x8d, 0xf5, 0x1e, 0x65, + 0xbd, 0x24, 0x63, 0xe7, 0x3d, 0x13, 0x41, 0x37, 0x9f, 0xb3, 0xc6, 0xab, + 0x67, 0xb6, 0x77, 0xbe, 0xde, 0xe3, 0xba, 0x35, 0xe5, 0xb6, 0xb7, 0x38, + 0xb2, 0xb1, 0xc2, 0xe3, 0x45, 0x9a, 0xf5, 0xa6, 0x58, 0xef, 0xf5, 0x09, + 0x59, 0x8f, 0xc0, 0x0d, 0xe3, 0x76, 0xe6, 0xb8, 0x47, 0xd7, 0x83, 0x27, + 0x91, 0x24, 0xe6, 0xba, 0x73, 0x79, 0xc3, 0x58, 0x7e, 0x33, 0xb6, 0xeb, + 0x87, 0xe2, 0x95, 0xac, 0x77, 0x44, 0x3f, 0x14, 0xf6, 0xd1, 0xaf, 0xd6, + 0x51, 0x5e, 0x2f, 0xf3, 0x1a, 0x95, 0xfe, 0xb2, 0x65, 0x5c, 0x62, 0xbf, + 0x41, 0x5e, 0x12, 0xa2, 0xcd, 0xc9, 0x98, 0xa5, 0x5d, 0x99, 0x53, 0x19, + 0x5f, 0x24, 0x36, 0xee, 0x8e, 0x4f, 0x99, 0x7b, 0x40, 0x72, 0xdd, 0x7a, + 0x0b, 0x7d, 0x6d, 0x12, 0xff, 0x14, 0x62, 0x6f, 0x03, 0xf3, 0x4f, 0x69, + 0x23, 0x84, 0x6d, 0xf4, 0xed, 0xfd, 0x86, 0xe3, 0x3c, 0x6f, 0xcc, 0xc7, + 0x01, 0x23, 0x92, 0x12, 0x3b, 0x7c, 0xd3, 0x58, 0x76, 0xa5, 0xe4, 0x96, + 0xc0, 0x9f, 0x60, 0x8a, 0xb6, 0x51, 0xa5, 0x8b, 0xbf, 0x29, 0x08, 0x47, + 0xbd, 0x5a, 0x8d, 0xe2, 0xc0, 0xbf, 0x78, 0xe1, 0xc6, 0x85, 0x1c, 0x7b, + 0xed, 0xf5, 0x0a, 0xde, 0xbf, 0x4a, 0xc1, 0xa1, 0xab, 0xa2, 0xe1, 0x11, + 0x65, 0x16, 0xb1, 0x35, 0xda, 0xdd, 0xa9, 0x58, 0x47, 0x59, 0x37, 0xd9, + 0xe6, 0x89, 0x84, 0xa1, 0xd4, 0xd1, 0xef, 0x5b, 0x34, 0x09, 0xfd, 0xde, + 0x81, 0x68, 0xf8, 0x51, 0xfe, 0xf7, 0x4c, 0x28, 0x98, 0xd0, 0x23, 0x49, + 0xb8, 0xf2, 0xd9, 0x36, 0xd3, 0xce, 0xab, 0xa3, 0x8e, 0x73, 0x2c, 0xde, + 0x1a, 0x3c, 0x86, 0x37, 0x89, 0x6d, 0xd2, 0x4e, 0x19, 0xeb, 0xc1, 0x5c, + 0x56, 0x4f, 0x76, 0x2a, 0x8e, 0x57, 0xf8, 0xc3, 0xfa, 0xbc, 0xc4, 0xc3, + 0x72, 0x7f, 0xcb, 0x71, 0xd1, 0x71, 0xde, 0x34, 0x8a, 0xb2, 0x82, 0x1d, + 0x91, 0x14, 0x30, 0x1f, 0x93, 0x7a, 0xa4, 0x6b, 0x8a, 0x3a, 0x08, 0xd3, + 0xdf, 0xe6, 0xe9, 0x8d, 0x38, 0xee, 0x8b, 0x04, 0x8f, 0x2b, 0xcb, 0xcf, + 0xaa, 0x58, 0xb4, 0xfe, 0x09, 0xa5, 0x75, 0x43, 0x15, 0xf4, 0x64, 0x41, + 0x99, 0x2b, 0x3a, 0x09, 0x07, 0xc8, 0xa5, 0xd6, 0xc1, 0x8d, 0xd1, 0xb8, + 0xcd, 0xf6, 0x26, 0xa7, 0xd1, 0x4c, 0xdb, 0xd7, 0x7b, 0xee, 0x23, 0x0f, + 0x04, 0x3e, 0xce, 0x24, 0x41, 0xfa, 0xda, 0x88, 0xd4, 0xa7, 0x1c, 0xe7, + 0x7e, 0xf6, 0x75, 0x07, 0xfb, 0xfa, 0x60, 0xfc, 0x3d, 0xe7, 0x5f, 0x5d, + 0x99, 0x37, 0x62, 0x44, 0xbf, 0x54, 0xee, 0xbb, 0xcc, 0xf5, 0x45, 0xae, + 0x0f, 0x37, 0xcf, 0x61, 0xbe, 0xd2, 0x21, 0xb8, 0x71, 0xd2, 0x4b, 0xdc, + 0xa0, 0x3c, 0xc6, 0x10, 0xf5, 0xd2, 0x38, 0xec, 0x01, 0xe3, 0x5b, 0x38, + 0xa5, 0xa8, 0x24, 0x42, 0x41, 0xf8, 0x75, 0x07, 0x0f, 0x90, 0x33, 0x24, + 0xe7, 0xd4, 0xe1, 0x73, 0x86, 0x1f, 0xb3, 0xa2, 0xea, 0x65, 0x1e, 0xce, + 0xc9, 0x81, 0xb8, 0x7c, 0xf7, 0x61, 0x6a, 0x8e, 0x07, 0x9b, 0xc9, 0x25, + 0x82, 0x51, 0x75, 0x9e, 0xdc, 0xf7, 0xb7, 0xcb, 0x77, 0xf6, 0x7f, 0xae, + 0x82, 0xfb, 0x69, 0x15, 0x6a, 0xb4, 0x37, 0x2c, 0xf7, 0xbb, 0x0c, 0xf9, + 0xae, 0xa0, 0x39, 0xee, 0xe5, 0xbc, 0x38, 0xf0, 0x48, 0x7a, 0x1f, 0xe5, + 0xfd, 0xb8, 0x7c, 0x4e, 0xde, 0xcf, 0x71, 0x27, 0xf7, 0x29, 0x82, 0x33, + 0x3f, 0x72, 0x5e, 0x64, 0x1c, 0x09, 0xf2, 0xf9, 0xe7, 0xd8, 0xf6, 0xd1, + 0xf8, 0xf3, 0xce, 0x3c, 0xe2, 0xeb, 0xb1, 0x84, 0x86, 0xf9, 0x57, 0x35, + 0xe1, 0xf8, 0x9d, 0x32, 0x66, 0x05, 0xb3, 0xf4, 0x2f, 0xf8, 0x24, 0xcf, + 0xac, 0xd5, 0xe7, 0xe2, 0xe6, 0x3b, 0x8a, 0xf7, 0xaa, 0xa2, 0xb2, 0x4e, + 0xa8, 0xa1, 0xea, 0xaa, 0x06, 0x68, 0xa5, 0x7b, 0xcb, 0xa3, 0xde, 0xee, + 0x59, 0x8a, 0x1e, 0xbc, 0x4d, 0x91, 0xe7, 0xbf, 0x24, 0xb7, 0x75, 0x9c, + 0x07, 0x38, 0x5f, 0x2d, 0xf1, 0x00, 0x4e, 0xb3, 0x9d, 0x5e, 0xea, 0x6f, + 0xe5, 0xf9, 0xf9, 0x2a, 0xd7, 0xff, 0xb9, 0xa3, 0x7d, 0x4a, 0xea, 0x8a, + 0x8c, 0x85, 0x5d, 0x37, 0x2b, 0x1c, 0x50, 0xb5, 0xe8, 0xd9, 0xd5, 0x19, + 0xcb, 0xf6, 0xba, 0xdf, 0x83, 0x1d, 0xaf, 0x9d, 0x5f, 0xf3, 0x3a, 0xe3, + 0xc6, 0xa3, 0x65, 0xd7, 0x07, 0x71, 0xdc, 0xa9, 0x6f, 0xb7, 0x82, 0x95, + 0x90, 0xb8, 0xd4, 0x1c, 0xfb, 0x0a, 0xe5, 0xfe, 0xc0, 0x28, 0xc6, 0xac, + 0xfd, 0x46, 0x24, 0x6b, 0xd1, 0x1f, 0x52, 0xcc, 0x13, 0x3b, 0x25, 0x76, + 0x4f, 0xd6, 0xfa, 0x50, 0x3b, 0x1f, 0x95, 0xed, 0x91, 0xfe, 0x05, 0xcc, + 0x9b, 0x3c, 0x1d, 0x12, 0xeb, 0x64, 0x7e, 0xdc, 0x32, 0x6c, 0xab, 0x0a, + 0xcb, 0xd9, 0xc7, 0x78, 0xfb, 0xef, 0x8b, 0x13, 0x22, 0x47, 0xac, 0x33, + 0xd2, 0x9f, 0xc4, 0xef, 0x2b, 0x0b, 0x46, 0x65, 0x59, 0x4f, 0xf2, 0xdf, + 0x90, 0xca, 0xab, 0xe4, 0x19, 0x15, 0xc1, 0xde, 0x8e, 0x46, 0x5e, 0xf2, + 0xdc, 0x7b, 0xc3, 0xda, 0xfc, 0xf9, 0x75, 0x3c, 0x64, 0x8d, 0x0a, 0xa8, + 0x57, 0x0b, 0x66, 0x13, 0x7d, 0x83, 0x32, 0x3e, 0x8b, 0x56, 0x2e, 0x39, + 0x7a, 0xe7, 0x5d, 0x77, 0xd3, 0x9f, 0x9f, 0x63, 0x8b, 0xa3, 0xe4, 0x33, + 0x96, 0xeb, 0x19, 0xe2, 0xeb, 0x33, 0xd7, 0xf5, 0x24, 0x86, 0x94, 0xd7, + 0x06, 0x1b, 0x30, 0xb8, 0xfb, 0x0e, 0x68, 0x8d, 0x45, 0x1c, 0x52, 0xcd, + 0xc5, 0x58, 0x96, 0x7d, 0xdb, 0x57, 0xe4, 0xe0, 0xb5, 0x18, 0xd8, 0x1d, + 0x47, 0x6e, 0x8e, 0x3c, 0x93, 0x7b, 0x7e, 0x08, 0x4e, 0x6e, 0xdf, 0x7d, + 0x99, 0xe4, 0xd4, 0x61, 0x91, 0x9b, 0xa2, 0xef, 0xa8, 0xfa, 0xdb, 0x8e, + 0x15, 0x14, 0xf9, 0x87, 0xae, 0xf4, 0x52, 0x87, 0x37, 0xa1, 0xb5, 0x67, + 0x0c, 0xa7, 0xc8, 0xeb, 0xdc, 0x35, 0x54, 0xad, 0xd2, 0x9c, 0xba, 0xdf, + 0x87, 0x68, 0x6a, 0x9c, 0x38, 0x10, 0x98, 0xf0, 0x93, 0x9f, 0xcc, 0x77, + 0xd7, 0x8e, 0x96, 0x91, 0x7f, 0xa4, 0xc8, 0x6d, 0x3f, 0xee, 0xf5, 0xe2, + 0x6e, 0x62, 0xc6, 0x7e, 0xbd, 0x75, 0xc3, 0x18, 0x7e, 0x45, 0xac, 0x93, + 0xf2, 0x3f, 0x60, 0x7b, 0x22, 0xd3, 0xcb, 0xf6, 0xe0, 0xf7, 0x12, 0x8f, + 0xc9, 0x09, 0xbd, 0x3e, 0x3d, 0xed, 0x93, 0xf8, 0x2d, 0xdc, 0x75, 0xc7, + 0x6e, 0x05, 0x9d, 0x94, 0xf3, 0x28, 0x6d, 0xe6, 0xfe, 0x28, 0xbc, 0x5d, + 0x57, 0x91, 0xa3, 0x90, 0xf3, 0x61, 0x4e, 0x00, 0x8f, 0x8c, 0x23, 0x91, + 0xd7, 0xa7, 0xe6, 0x05, 0xf0, 0x26, 0xe5, 0x08, 0xae, 0x57, 0x94, 0xe4, + 0xf4, 0xac, 0xb9, 0x58, 0x4e, 0x2d, 0x1e, 0x2f, 0xc9, 0xd9, 0x43, 0x39, + 0xd7, 0xb4, 0xc0, 0x5b, 0x7b, 0x8d, 0xcc, 0x55, 0x1b, 0xfd, 0xa7, 0x16, + 0x19, 0x17, 0xdb, 0xc9, 0xe9, 0x3e, 0x06, 0x45, 0x5f, 0x28, 0xfc, 0xff, + 0x1b, 0x6e, 0xbd, 0x9b, 0xda, 0xa6, 0xa6, 0xeb, 0x09, 0x9e, 0x67, 0x5a, + 0xa6, 0xe8, 0xa8, 0x65, 0xdd, 0x34, 0x62, 0xeb, 0xee, 0xea, 0x72, 0x7f, + 0xd9, 0x4e, 0xb9, 0x8d, 0x06, 0xde, 0x0b, 0xe1, 0x11, 0xe6, 0x71, 0x37, + 0xb1, 0x9d, 0x03, 0x86, 0x70, 0xb1, 0x56, 0xa3, 0x4a, 0x91, 0xbc, 0x36, + 0xcc, 0xb8, 0xde, 0x80, 0x3e, 0x37, 0x16, 0x84, 0x59, 0x7f, 0x77, 0x5d, + 0x91, 0x4f, 0xc0, 0x77, 0x2b, 0xcb, 0x76, 0xc6, 0x8b, 0xed, 0xf9, 0x74, + 0xc9, 0x15, 0xdb, 0xb1, 0x7f, 0xf8, 0xfc, 0xf3, 0xc8, 0x4d, 0xfa, 0xcc, + 0xf9, 0x9a, 0x8a, 0x10, 0x4b, 0x2b, 0x50, 0x5d, 0x21, 0x58, 0x7f, 0xd1, + 0xd8, 0xb7, 0x8c, 0xff, 0x29, 0xef, 0x57, 0x63, 0xeb, 0xb8, 0x83, 0x2d, + 0x6e, 0x9e, 0x50, 0x81, 0xde, 0x36, 0xc1, 0x43, 0xb1, 0xa5, 0x39, 0x92, + 0x27, 0x25, 0x72, 0x90, 0x18, 0x27, 0xf6, 0xb3, 0xc6, 0xb5, 0x1f, 0x8f, + 0x32, 0xd3, 0x7e, 0x36, 0xe3, 0xbb, 0xfa, 0xa1, 0x3b, 0x2a, 0x71, 0xe8, + 0x2e, 0x59, 0xff, 0xde, 0x10, 0xc7, 0xe1, 0x5b, 0xe8, 0x9b, 0xaf, 0x13, + 0x5b, 0xb6, 0xb4, 0x30, 0x86, 0xb8, 0x98, 0xa5, 0xa0, 0x92, 0xb1, 0x7d, + 0xdb, 0x6e, 0xe6, 0xc0, 0x6a, 0x90, 0x6d, 0x5e, 0x8a, 0x5d, 0xd2, 0x7f, + 0x83, 0xb9, 0xee, 0xa1, 0x2f, 0x56, 0x22, 0x20, 0x39, 0xc7, 0x4f, 0x4e, + 0x51, 0xc6, 0x4d, 0x46, 0x59, 0x57, 0xa2, 0xa7, 0xb2, 0x9c, 0x06, 0xa4, + 0x77, 0x97, 0xeb, 0x2b, 0x78, 0x29, 0x1a, 0x2e, 0xad, 0x3f, 0x37, 0x60, + 0x60, 0xfc, 0xd0, 0x31, 0x72, 0x0d, 0x27, 0xd1, 0x72, 0x68, 0x63, 0x98, + 0x7d, 0x39, 0x13, 0x2f, 0xcf, 0xa9, 0xf8, 0xe6, 0x4c, 0x19, 0x62, 0xbb, + 0x50, 0x6a, 0x17, 0x62, 0x4b, 0x2d, 0x6d, 0x34, 0x1f, 0x45, 0xaa, 0xc6, + 0xac, 0x85, 0x3d, 0x4e, 0xdf, 0x9a, 0xa8, 0x80, 0xf7, 0x5a, 0x89, 0x7d, + 0xc2, 0x77, 0xbc, 0x37, 0x9c, 0xb0, 0x2b, 0xf0, 0x69, 0xe3, 0x9c, 0x23, + 0xb8, 0x78, 0x4c, 0xc7, 0xe5, 0x15, 0xc4, 0xc4, 0x85, 0xf1, 0x68, 0x72, + 0x1d, 0xf3, 0xc2, 0x23, 0x6d, 0xde, 0x1b, 0xde, 0xca, 0xff, 0x9a, 0xdc, + 0xf2, 0xd2, 0xf1, 0x88, 0x3e, 0x70, 0x74, 0x45, 0x54, 0xda, 0x94, 0xf6, + 0xca, 0x36, 0x2a, 0xed, 0x3b, 0x4e, 0x34, 0x1e, 0x70, 0xe7, 0xbc, 0x3c, + 0x86, 0x37, 0xf4, 0xf2, 0x18, 0x02, 0x8c, 0xa7, 0x49, 0x72, 0x57, 0xe1, + 0xd5, 0x7e, 0xe6, 0x91, 0x5e, 0xf2, 0xf1, 0x6e, 0x08, 0xdf, 0x3b, 0x4a, + 0x7e, 0xf2, 0xa4, 0x0d, 0xbc, 0x93, 0x75, 0xb0, 0x2c, 0x3e, 0x8b, 0xf8, + 0xd2, 0x4f, 0xd9, 0xb2, 0xa6, 0x76, 0x50, 0x19, 0x67, 0xae, 0x79, 0xdc, + 0x5b, 0x95, 0x54, 0x99, 0x5b, 0x1e, 0xc8, 0x47, 0xc3, 0x87, 0x98, 0x67, + 0xfa, 0x99, 0xeb, 0x72, 0x06, 0x94, 0x27, 0x99, 0x67, 0xee, 0x2b, 0xe5, + 0x99, 0x07, 0xf2, 0x01, 0xe4, 0xb3, 0xc4, 0xc6, 0x38, 0xf3, 0x5b, 0x37, + 0x4f, 0x0f, 0x60, 0x32, 0xab, 0x32, 0x1f, 0x7f, 0xdf, 0x99, 0xaa, 0x77, + 0xf7, 0x0b, 0xf0, 0x75, 0xbb, 0x01, 0x07, 0x87, 0x9b, 0x70, 0x36, 0x3f, + 0x45, 0xbb, 0xb8, 0x0c, 0xd3, 0xa3, 0xb5, 0x98, 0x18, 0x7e, 0x95, 0x9f, + 0xdb, 0xf0, 0xfe, 0xa8, 0x9b, 0xe3, 0x12, 0x0f, 0xa5, 0x7f, 0x07, 0x95, + 0x43, 0x6e, 0x8e, 0x6b, 0x25, 0x99, 0xdb, 0x26, 0xfa, 0x4b, 0xb9, 0xed, + 0x14, 0x73, 0xdb, 0x23, 0x6c, 0xf3, 0x85, 0x52, 0x9b, 0xcf, 0xb9, 0xff, + 0xa5, 0x2f, 0x52, 0x77, 0x66, 0xbd, 0x44, 0x52, 0xd6, 0xa6, 0xc7, 0xed, + 0x68, 0xac, 0x5c, 0xf7, 0x05, 0xd6, 0x3b, 0x72, 0xbe, 0xde, 0x6a, 0x0c, + 0x64, 0xd6, 0x90, 0xe7, 0xcb, 0xda, 0xca, 0x7b, 0x6b, 0x6c, 0xea, 0xf2, + 0xcb, 0xd1, 0xa9, 0xee, 0x59, 0xa8, 0xc3, 0xfa, 0xb8, 0x70, 0xa2, 0xb7, + 0xc8, 0x89, 0x22, 0x89, 0x95, 0x8c, 0x0f, 0x9e, 0x68, 0x84, 0x58, 0x0f, + 0x44, 0x27, 0x98, 0x03, 0xe4, 0xeb, 0x70, 0x37, 0x73, 0x31, 0xb5, 0x7e, + 0x75, 0x69, 0x0f, 0xab, 0x94, 0xe3, 0x78, 0xd6, 0xa0, 0x6f, 0x52, 0xe4, + 0xad, 0x26, 0xbf, 0xae, 0xc1, 0x2d, 0xc5, 0x75, 0x0b, 0xbf, 0x9f, 0xb2, + 0xfd, 0xd1, 0xa9, 0x18, 0x5d, 0xc6, 0x38, 0xc0, 0x1b, 0xcf, 0xd9, 0x0a, + 0x96, 0xe9, 0x3e, 0xac, 0x0b, 0xd6, 0x61, 0x99, 0xf1, 0xef, 0xce, 0x2d, + 0xab, 0xe5, 0xd9, 0x79, 0x1e, 0xe1, 0xaf, 0x64, 0xbb, 0x6f, 0x92, 0x53, + 0x8f, 0xf3, 0xcb, 0x54, 0xbe, 0x78, 0xdf, 0xca, 0x53, 0x36, 0xe5, 0x6e, + 0xa3, 0xdc, 0x7b, 0x83, 0x6e, 0xbe, 0x5b, 0x2a, 0x37, 0x15, 0xf3, 0x10, + 0xd7, 0xa5, 0x6c, 0x27, 0xe5, 0xde, 0x4d, 0xb9, 0xfd, 0x41, 0xe9, 0xdf, + 0xbf, 0x3b, 0xf7, 0xae, 0x96, 0x67, 0xe5, 0x7d, 0x13, 0x29, 0xff, 0x9e, + 0xc8, 0x35, 0xc6, 0x4b, 0x6d, 0x1d, 0xb2, 0x91, 0x95, 0xdc, 0x6f, 0x6d, + 0x47, 0x54, 0xeb, 0x75, 0xd7, 0xb2, 0x35, 0xac, 0xcb, 0x6b, 0xb8, 0x87, + 0xba, 0xcb, 0x79, 0xcb, 0x63, 0x72, 0xfb, 0x64, 0x09, 0x77, 0x5e, 0xce, + 0x72, 0x7d, 0x25, 0xdc, 0xee, 0xcc, 0x8b, 0x0d, 0xcd, 0xdc, 0x4f, 0x6a, + 0x2a, 0xf9, 0xb3, 0x17, 0x4f, 0xdb, 0x1f, 0x9c, 0x1b, 0xcc, 0x48, 0x3c, + 0x93, 0xf5, 0x10, 0x0d, 0xd9, 0xfc, 0xe5, 0x68, 0x1e, 0x0a, 0x62, 0xad, + 0x31, 0x9b, 0xbe, 0xfe, 0xa5, 0xf3, 0x36, 0x75, 0x80, 0xed, 0xc0, 0xe7, + 0x8a, 0x57, 0x9e, 0xce, 0xb7, 0x06, 0x1b, 0x70, 0xe9, 0x1e, 0xd2, 0xfc, + 0x64, 0x8d, 0x19, 0xed, 0xfe, 0x0e, 0xe7, 0xae, 0xca, 0xe5, 0xd0, 0x5b, + 0x94, 0x1c, 0xe7, 0xef, 0xa9, 0xd2, 0xfc, 0x3d, 0x99, 0xbf, 0xae, 0xb2, + 0x88, 0x45, 0x97, 0xa3, 0x65, 0x48, 0xfe, 0x07, 0xf1, 0x46, 0xc7, 0xc7, + 0x79, 0xef, 0x72, 0x2c, 0x1c, 0xf9, 0x54, 0x25, 0xb9, 0xb5, 0x51, 0xcc, + 0xc1, 0x2f, 0xcd, 0x33, 0x22, 0xfd, 0x16, 0x16, 0xb0, 0x5c, 0x13, 0x75, + 0x26, 0x18, 0x28, 0xfd, 0x7a, 0xe4, 0x7c, 0xbf, 0xbe, 0xcc, 0x7e, 0xa5, + 0x7c, 0xb2, 0xd6, 0x2a, 0xfd, 0x52, 0x92, 0xb5, 0x66, 0x13, 0xde, 0x1f, + 0x40, 0x30, 0x68, 0x46, 0x53, 0x2f, 0xd3, 0xde, 0x27, 0xd8, 0xd7, 0x7a, + 0xf4, 0x2b, 0x79, 0x77, 0xaf, 0xea, 0x20, 0xcb, 0xcc, 0x8c, 0xa3, 0xd2, + 0x4f, 0xaf, 0xe4, 0x59, 0x3e, 0xd9, 0x67, 0xf2, 0xe9, 0x22, 0xff, 0x6d, + 0x72, 0xc5, 0x3e, 0xca, 0x4f, 0x72, 0xfe, 0xfc, 0x6c, 0x03, 0x56, 0xb5, + 0xd9, 0xed, 0x72, 0x55, 0x2f, 0xfd, 0x6e, 0x19, 0x6d, 0xea, 0xc9, 0x9c, + 0x82, 0x51, 0x2a, 0xfd, 0x68, 0x56, 0xd6, 0x89, 0xc3, 0x38, 0x90, 0xf3, + 0xe1, 0x85, 0xec, 0x3c, 0x8c, 0xe7, 0x2a, 0xf0, 0x5c, 0xf6, 0x32, 0xec, + 0xcb, 0x11, 0xfd, 0xb2, 0x97, 0x63, 0x24, 0xe7, 0xc7, 0x4f, 0xb2, 0xd4, + 0x53, 0xae, 0x0a, 0xff, 0x9c, 0xfd, 0x13, 0x7c, 0x3d, 0x57, 0x8d, 0xd7, + 0xb2, 0x57, 0xe0, 0x60, 0xae, 0x06, 0xaf, 0x64, 0xc9, 0x27, 0x73, 0x01, + 0xbc, 0x9c, 0xd5, 0x50, 0xc8, 0xcd, 0xc2, 0x4b, 0xd9, 0x08, 0x26, 0x72, + 0xb5, 0xf8, 0x6e, 0x76, 0x01, 0xf2, 0xb9, 0x3a, 0x7c, 0x27, 0xdb, 0x8c, + 0x2f, 0xe7, 0x82, 0x78, 0x31, 0xab, 0xe3, 0xa9, 0x5c, 0x3d, 0x8e, 0x65, + 0xa3, 0x6c, 0x37, 0x84, 0xa3, 0xc3, 0x31, 0x1c, 0x18, 0x6d, 0xc4, 0x0b, + 0xc3, 0x8b, 0x30, 0x3e, 0x1a, 0xc6, 0x73, 0xc3, 0x6d, 0xd8, 0x37, 0xfa, + 0x6f, 0x15, 0xa2, 0x9f, 0x23, 0xf6, 0xff, 0x38, 0xaf, 0xc7, 0x6d, 0x1f, + 0x31, 0xdf, 0xaf, 0xda, 0xa2, 0x37, 0xbf, 0x55, 0xcf, 0x39, 0x7a, 0x3a, + 0xef, 0xce, 0x3b, 0xf4, 0x21, 0x77, 0x7f, 0x06, 0x7d, 0xc6, 0x65, 0xcc, + 0xd9, 0xfa, 0x25, 0x7e, 0xd0, 0x16, 0x0e, 0x2a, 0xdb, 0x5d, 0x1c, 0xa9, + 0x4d, 0xce, 0xa2, 0x2e, 0x39, 0xec, 0x60, 0x0d, 0x7d, 0x32, 0x4b, 0x7f, + 0xb6, 0x38, 0xaf, 0x76, 0xfe, 0xa0, 0xb2, 0x83, 0x39, 0xe2, 0x95, 0x43, + 0x96, 0x53, 0xed, 0xe2, 0x69, 0x34, 0xb9, 0x88, 0x3e, 0x17, 0x1b, 0x11, + 0x7d, 0xde, 0x59, 0x21, 0xfa, 0xac, 0xd0, 0x3f, 0xcc, 0x4e, 0xca, 0x7a, + 0x0f, 0x94, 0xec, 0xe1, 0xfb, 0x95, 0xc5, 0xbc, 0xaa, 0x3c, 0xef, 0x8e, + 0x33, 0x68, 0x94, 0xe7, 0x9e, 0xfc, 0xaf, 0x41, 0xd6, 0xa4, 0xc0, 0x58, + 0x50, 0x8f, 0x5c, 0x48, 0xf2, 0xf5, 0x99, 0x98, 0x81, 0x64, 0xa5, 0x19, + 0xd5, 0x5a, 0xd4, 0x99, 0x7c, 0x45, 0xb0, 0x43, 0xe4, 0x5b, 0x2e, 0xee, + 0x1c, 0x3e, 0x8f, 0x1f, 0x67, 0x2b, 0x85, 0xa7, 0xec, 0xb7, 0xa5, 0x6f, + 0x50, 0x2b, 0xa4, 0xcf, 0x28, 0xde, 0x43, 0xa1, 0xac, 0xaf, 0x99, 0x76, + 0xa7, 0x52, 0xb7, 0x62, 0x7b, 0x5e, 0xfa, 0xc2, 0x72, 0x89, 0x7b, 0xec, + 0x47, 0x13, 0x5e, 0xb0, 0x8b, 0x7b, 0x33, 0xe3, 0x79, 0xd1, 0xb7, 0x86, + 0xad, 0xe4, 0x5e, 0x87, 0x87, 0x15, 0xea, 0xee, 0x2f, 0x51, 0xdc, 0x3f, + 0xf2, 0xd2, 0x57, 0xd7, 0xb2, 0x3c, 0x63, 0x7c, 0x61, 0xda, 0xdd, 0x1b, + 0xae, 0x73, 0xf3, 0xee, 0x30, 0x0a, 0x03, 0x1f, 0x9c, 0xdb, 0x96, 0xf9, + 0xe5, 0xb9, 0x3d, 0x99, 0x68, 0x4a, 0xf6, 0x67, 0xf2, 0x13, 0x3e, 0xe4, + 0xf6, 0x06, 0xf0, 0xd4, 0x84, 0x1f, 0x35, 0x69, 0xc9, 0xf3, 0x83, 0x78, + 0x6a, 0xff, 0xa1, 0x15, 0x35, 0x68, 0xe0, 0xff, 0x10, 0xaf, 0x46, 0x5e, + 0x01, 0x1c, 0x1b, 0xf5, 0xe3, 0x2d, 0x5b, 0x7c, 0x58, 0xfc, 0xa3, 0x8d, + 0xd8, 0x1f, 0x60, 0xbc, 0x55, 0x19, 0x47, 0x9a, 0x70, 0x38, 0x1f, 0xc4, + 0xf2, 0x6c, 0x3d, 0x9e, 0xcb, 0x25, 0xf1, 0x44, 0xa6, 0x1e, 0x67, 0x1f, + 0xf3, 0x63, 0xde, 0x3e, 0xf1, 0x87, 0x06, 0x9c, 0x1e, 0xfc, 0x04, 0x0a, + 0x7b, 0x93, 0xb0, 0x33, 0xb3, 0xb1, 0x63, 0xb0, 0x01, 0xdf, 0x61, 0x99, + 0x7e, 0xea, 0xa9, 0x7a, 0xa7, 0x89, 0x17, 0x69, 0x43, 0x55, 0x3b, 0x6f, + 0xa4, 0xec, 0x30, 0x7c, 0x03, 0x21, 0x1c, 0xc9, 0x7b, 0x85, 0xd7, 0x71, + 0x1e, 0x7f, 0x5a, 0x9c, 0x17, 0x08, 0x6f, 0xbd, 0x98, 0x07, 0x1e, 0x3f, + 0xcf, 0x03, 0x81, 0x5c, 0x5e, 0xd6, 0x18, 0xdb, 0x3a, 0xfb, 0xec, 0x89, + 0xff, 0xcf, 0x6f, 0xfe, 0xf4, 0xdb, 0x15, 0x4b, 0x0c, 0x62, 0x9d, 0x8c, + 0x7f, 0xed, 0x83, 0xd5, 0xe6, 0x86, 0x2f, 0xae, 0x58, 0x52, 0x89, 0xfb, + 0xdd, 0xf9, 0xea, 0x81, 0xbd, 0xbb, 0x9b, 0xf1, 0xb5, 0xb5, 0x67, 0x40, + 0xb9, 0x02, 0xa9, 0xfa, 0x21, 0xde, 0x53, 0x4b, 0x3e, 0x07, 0x55, 0x6c, + 0xad, 0x8e, 0xfa, 0x54, 0x0b, 0x1a, 0x4e, 0xd0, 0xc8, 0x6a, 0xd3, 0x11, + 0x4c, 0xd5, 0xcb, 0x38, 0x63, 0xcc, 0xb3, 0x3c, 0xb2, 0x77, 0x8d, 0x4f, + 0x33, 0xc6, 0x9d, 0x5d, 0xac, 0x20, 0xf1, 0x67, 0xe2, 0x83, 0xb7, 0x96, + 0xf6, 0x80, 0x65, 0x3f, 0x4c, 0xe6, 0xad, 0xac, 0xff, 0xbd, 0xb2, 0xee, + 0xc9, 0x3f, 0xc1, 0x0a, 0x2f, 0x0e, 0xdb, 0x39, 0xe6, 0x08, 0x32, 0x07, + 0x32, 0xa6, 0xed, 0xac, 0x27, 0xe3, 0x92, 0xe7, 0xad, 0x89, 0xfa, 0x8f, + 0x1c, 0x97, 0x8c, 0x67, 0xad, 0x1f, 0xd5, 0x32, 0x86, 0xb2, 0x2e, 0xfa, + 0x58, 0xf7, 0x51, 0xde, 0x93, 0x7a, 0x8e, 0xb3, 0xfd, 0xa2, 0x98, 0x55, + 0x91, 0xac, 0x66, 0xdf, 0x9f, 0xb4, 0xa3, 0xc9, 0x77, 0x88, 0x8b, 0xc7, + 0xa8, 0xc3, 0x51, 0x5b, 0xec, 0x6f, 0x0b, 0xed, 0xae, 0x5f, 0x39, 0x7a, + 0xde, 0xf6, 0x80, 0x83, 0xb6, 0xcc, 0xaf, 0xf0, 0x29, 0x19, 0xaf, 0x86, + 0xe9, 0x89, 0xa0, 0xcb, 0xc7, 0xdf, 0xb6, 0xc5, 0x26, 0x62, 0xcc, 0xcf, + 0xa6, 0xcf, 0xf5, 0x66, 0x0c, 0x1c, 0xe3, 0xdc, 0x9e, 0xb6, 0xab, 0x88, + 0x37, 0x1d, 0x90, 0xbd, 0xce, 0xf7, 0xed, 0x04, 0x5e, 0x22, 0x66, 0xbd, + 0x47, 0x5b, 0xfb, 0x2e, 0x31, 0xec, 0x5d, 0x5b, 0xc7, 0x77, 0x68, 0x7b, + 0xef, 0xd8, 0x31, 0xbc, 0x98, 0xaf, 0xc7, 0x51, 0xe2, 0xd0, 0x49, 0x7e, + 0x5e, 0x9e, 0xf7, 0xc1, 0x0a, 0xc9, 0xbe, 0xda, 0x1e, 0x3f, 0x6a, 0x7b, + 0xd9, 0xe7, 0x48, 0x97, 0x1c, 0x44, 0x79, 0x96, 0xe3, 0xd3, 0x94, 0x32, + 0x0f, 0x29, 0xe7, 0x04, 0x49, 0x64, 0x33, 0x33, 0xb1, 0x21, 0xd2, 0x9f, + 0xa3, 0xdd, 0xfa, 0xd2, 0xe5, 0x38, 0xc0, 0xd8, 0x59, 0x10, 0xdb, 0xf6, + 0xc0, 0x33, 0x24, 0xf6, 0x7f, 0x0d, 0x75, 0x3d, 0x7d, 0x4e, 0xf6, 0xd2, + 0x54, 0x7d, 0x8a, 0xfe, 0x5e, 0x85, 0xde, 0xdc, 0xe5, 0xa8, 0x19, 0x5a, + 0x8a, 0xfb, 0xe3, 0xe2, 0xf7, 0x7e, 0xf4, 0xe7, 0x3c, 0xa8, 0x1c, 0x22, + 0x77, 0x61, 0xd9, 0xa9, 0x50, 0x31, 0x1e, 0xa9, 0x69, 0xc3, 0xf5, 0x83, + 0x05, 0x85, 0x0f, 0xce, 0xd9, 0x99, 0x43, 0xf3, 0x54, 0x4c, 0x9f, 0x4b, + 0x67, 0x02, 0xe8, 0xa3, 0x4d, 0xab, 0x69, 0x05, 0x75, 0x7a, 0x88, 0xf9, + 0x5f, 0x1b, 0x7a, 0xa9, 0x8b, 0xf9, 0xe9, 0x26, 0x3c, 0x31, 0xd1, 0x88, + 0x79, 0xbb, 0x4c, 0x3c, 0x4e, 0xdb, 0x0f, 0xef, 0xba, 0x11, 0x7b, 0x58, + 0xee, 0x15, 0x3e, 0x7b, 0x65, 0x7f, 0x03, 0xaf, 0x10, 0xaf, 0x46, 0x5e, + 0xf5, 0x18, 0xd8, 0xab, 0x97, 0xce, 0x61, 0x78, 0xd0, 0x30, 0x24, 0xf8, + 0xa2, 0xe2, 0x8e, 0x76, 0x05, 0xc6, 0xd5, 0x6c, 0x73, 0xe1, 0x87, 0x61, + 0x4d, 0xc3, 0x1f, 0xd0, 0xef, 0x1f, 0x38, 0x53, 0xe7, 0xed, 0xc7, 0x0f, + 0x6f, 0xfa, 0xfb, 0xae, 0xfd, 0x2c, 0x28, 0x48, 0x3b, 0xef, 0x12, 0x33, + 0xc4, 0x86, 0x7e, 0x17, 0x9e, 0x95, 0xf5, 0xfe, 0xdb, 0x67, 0x2b, 0x70, + 0xde, 0xbe, 0x2e, 0x5a, 0x77, 0x47, 0x9e, 0x36, 0xb1, 0xc3, 0x3d, 0x3b, + 0x22, 0xb9, 0x4e, 0xa4, 0x2b, 0x47, 0xfd, 0xf4, 0x33, 0x87, 0xb9, 0x87, + 0x38, 0xb1, 0x3d, 0x13, 0xb1, 0x2c, 0xb6, 0xe5, 0x23, 0x36, 0x3c, 0x30, + 0xe8, 0x97, 0xf5, 0x6e, 0xcd, 0xa7, 0xcf, 0xc3, 0x3b, 0x39, 0xb1, 0xf9, + 0x2a, 0x1c, 0xce, 0x86, 0x71, 0xca, 0xfd, 0x5c, 0xcd, 0x58, 0xe3, 0xa0, + 0xd3, 0x98, 0x85, 0xbe, 0x60, 0x15, 0x06, 0x62, 0x37, 0x22, 0x77, 0x07, + 0x73, 0x6c, 0xfa, 0x58, 0xad, 0xee, 0x47, 0x3a, 0x28, 0xf9, 0x8b, 0x07, + 0x99, 0xd8, 0xed, 0x38, 0x5e, 0xef, 0xc5, 0x3c, 0x59, 0x6f, 0xe1, 0xb3, + 0x3d, 0x41, 0x28, 0xf4, 0xbd, 0xa4, 0x8f, 0xb8, 0x34, 0x6b, 0x00, 0x4e, + 0xad, 0xa9, 0xcb, 0x1e, 0x4c, 0xcf, 0x56, 0xe2, 0x52, 0xcd, 0x44, 0x0d, + 0xe3, 0x4e, 0x0b, 0xaa, 0xf7, 0xca, 0x5e, 0x40, 0x00, 0xeb, 0x86, 0xaf, + 0x95, 0xbd, 0x81, 0x98, 0xa6, 0x04, 0x70, 0xef, 0xb0, 0xc4, 0x8f, 0x35, + 0xa8, 0xd8, 0x5f, 0x8b, 0x2f, 0x66, 0xbd, 0xc4, 0x78, 0xe2, 0x0d, 0xcb, + 0xed, 0xc9, 0xd4, 0xa1, 0xee, 0xb1, 0x67, 0x9d, 0x30, 0x75, 0x5c, 0xb7, + 0x57, 0xb0, 0x88, 0xb6, 0x9b, 0xf9, 0x3c, 0x0a, 0x76, 0x33, 0xe5, 0xf6, + 0x70, 0x7c, 0x21, 0xbc, 0x4b, 0xec, 0xaa, 0x99, 0x08, 0xe3, 0x9d, 0xdd, + 0x92, 0xab, 0x24, 0xe1, 0x9d, 0xb8, 0x0c, 0x6f, 0xf2, 0xf3, 0x09, 0xa3, + 0x13, 0xea, 0x44, 0x13, 0x4e, 0x66, 0xba, 0xe0, 0x99, 0xa8, 0x2d, 0x62, + 0xd8, 0x5e, 0x3f, 0xea, 0x06, 0xf5, 0xd8, 0x34, 0xe7, 0xc8, 0xb7, 0x97, + 0x04, 0xa7, 0x51, 0xda, 0x3f, 0x6f, 0xdb, 0xc6, 0x85, 0x7d, 0x87, 0xf2, + 0xd9, 0x15, 0xb1, 0xef, 0xef, 0x3a, 0x4f, 0x04, 0xd9, 0xbf, 0x8e, 0x08, + 0xfa, 0x62, 0xc7, 0x64, 0x3f, 0x9f, 0xe3, 0x4b, 0x72, 0xee, 0x9f, 0x77, + 0xe4, 0x5c, 0x88, 0xcf, 0x94, 0x33, 0x19, 0xcf, 0x39, 0xdb, 0x57, 0xcb, + 0xfd, 0xdb, 0xab, 0x50, 0xcd, 0xc4, 0xc9, 0x14, 0x99, 0x3b, 0x64, 0x6e, + 0x19, 0x75, 0x3e, 0x4c, 0xe6, 0x3f, 0x3a, 0x8f, 0x9f, 0x2f, 0x8f, 0xa0, + 0xcf, 0x5d, 0x13, 0xbf, 0xe0, 0xcb, 0x35, 0x9c, 0xbb, 0xf5, 0x25, 0x5f, + 0x7e, 0xc7, 0x96, 0xf9, 0x93, 0xf3, 0x4b, 0x01, 0x72, 0x30, 0x03, 0xd5, + 0x9c, 0xbb, 0xf7, 0x6d, 0x28, 0xb7, 0x76, 0x74, 0x63, 0xd6, 0x44, 0x80, + 0xbe, 0x1e, 0x59, 0x6f, 0xc1, 0x66, 0x5b, 0x1d, 0xa8, 0x62, 0x9d, 0x93, + 0xb6, 0x87, 0x7e, 0x9e, 0xe0, 0x98, 0x83, 0x70, 0x5c, 0x5e, 0xbf, 0x1a, + 0xf3, 0xa9, 0xa7, 0xb3, 0xb6, 0x89, 0x79, 0xd4, 0xd3, 0xb4, 0xed, 0x25, + 0x4e, 0x34, 0x11, 0x0f, 0x34, 0xd4, 0x12, 0x1b, 0x2b, 0x06, 0x1d, 0x1c, + 0x32, 0xea, 0xc8, 0xf5, 0xc5, 0x4e, 0x3b, 0x10, 0x1e, 0x30, 0x30, 0x6f, + 0xa0, 0x79, 0xe3, 0x3c, 0x8f, 0x07, 0xc7, 0x7d, 0xc5, 0xd8, 0x93, 0x9b, + 0x23, 0xfa, 0x91, 0x31, 0xb9, 0xb9, 0xfc, 0x87, 0x60, 0xc0, 0x6a, 0x80, + 0xb2, 0x0a, 0xc4, 0x8c, 0xcf, 0xb1, 0xad, 0x37, 0xec, 0x57, 0x71, 0xf3, + 0x84, 0xe0, 0xcb, 0x0f, 0xb1, 0x92, 0xfd, 0x78, 0x97, 0xb8, 0x76, 0x5f, + 0xf4, 0x1b, 0x1c, 0x6b, 0x13, 0x6e, 0x99, 0x98, 0x3e, 0xd7, 0xe7, 0x8e, + 0xb3, 0x9c, 0xff, 0xf9, 0x71, 0x5f, 0xb6, 0x7c, 0x06, 0x2d, 0x49, 0x9f, + 0x91, 0x38, 0xe1, 0x87, 0xf8, 0x4d, 0xb7, 0xbd, 0x0d, 0xc5, 0x78, 0x2e, + 0x57, 0x59, 0x8f, 0x3b, 0xbd, 0x92, 0x97, 0x17, 0x7d, 0x43, 0xfa, 0xf3, + 0xbb, 0xca, 0x14, 0x7d, 0x43, 0xfc, 0xe2, 0xcb, 0xae, 0x7e, 0x85, 0x77, + 0x69, 0xb8, 0x6d, 0xe2, 0x97, 0xc4, 0xc7, 0x48, 0x32, 0x47, 0xcc, 0x7e, + 0x9d, 0xfa, 0xdd, 0x4e, 0xfd, 0x32, 0x07, 0x60, 0xbc, 0x4a, 0x50, 0x9f, + 0x3e, 0x72, 0x15, 0x2f, 0x31, 0xd3, 0xa4, 0x2e, 0x41, 0x0c, 0x64, 0xee, + 0x1e, 0x2c, 0x8e, 0x37, 0x77, 0x7e, 0xfe, 0xd8, 0x96, 0x92, 0xc0, 0x09, + 0xfb, 0x87, 0x55, 0x72, 0x26, 0xe8, 0xa4, 0xed, 0x3e, 0x97, 0x35, 0xcd, + 0x19, 0x65, 0x2e, 0xb4, 0xbd, 0xcf, 0x16, 0xfe, 0x5c, 0x49, 0xbb, 0xd6, + 0x28, 0xaf, 0xa6, 0x84, 0xa9, 0x52, 0x57, 0xf6, 0x60, 0xa5, 0xfd, 0x6e, + 0xe1, 0x20, 0x78, 0x83, 0x3e, 0x77, 0xc4, 0xa8, 0xc0, 0xa8, 0x3b, 0x17, + 0x62, 0x8f, 0xc5, 0x76, 0x2f, 0xd8, 0x4d, 0xba, 0xae, 0x74, 0x1e, 0xab, + 0xba, 0xc8, 0xc9, 0x2e, 0x6d, 0xa3, 0xe2, 0x3f, 0xb1, 0x8d, 0x44, 0xa9, + 0x8d, 0x8f, 0x3a, 0xe3, 0x06, 0x3c, 0x65, 0x4b, 0xec, 0x97, 0xfd, 0x0f, + 0x0d, 0x8b, 0x26, 0x04, 0x5f, 0xe8, 0xbb, 0x03, 0xd3, 0x2e, 0xf7, 0xcf, + 0x41, 0xf6, 0xb6, 0x42, 0xf0, 0x45, 0x35, 0x9c, 0xd2, 0x63, 0x58, 0x58, + 0x90, 0xfd, 0xa9, 0x7d, 0x75, 0xc2, 0xe1, 0xce, 0xe8, 0xc2, 0x3b, 0x64, + 0xbe, 0xca, 0xf7, 0xfc, 0xd8, 0xaf, 0x17, 0xfb, 0x9a, 0x54, 0x8b, 0xdc, + 0xd1, 0x43, 0xee, 0xd8, 0x6b, 0xf8, 0x69, 0x97, 0xad, 0xc1, 0xd9, 0xbf, + 0x73, 0x2f, 0xab, 0xdc, 0xdf, 0xdf, 0x57, 0xee, 0xc2, 0x7a, 0x5c, 0xf6, + 0xa2, 0xfd, 0x21, 0x19, 0xd3, 0x5c, 0xa0, 0x41, 0xe2, 0x55, 0x91, 0xa3, + 0x6e, 0x3d, 0x9f, 0xff, 0x58, 0xca, 0x60, 0xfe, 0x31, 0xd4, 0xeb, 0x0b, + 0x50, 0xdf, 0x50, 0xc3, 0xb8, 0x1c, 0xed, 0xa2, 0x7b, 0x4b, 0x2c, 0xb3, + 0x82, 0xa6, 0xe4, 0xbf, 0xc2, 0x5b, 0xa5, 0xcd, 0x7e, 0xa5, 0xaa, 0x20, + 0xed, 0x1e, 0x54, 0xfc, 0x85, 0x0f, 0x6b, 0x5b, 0xce, 0xfb, 0x4d, 0x9f, + 0x1b, 0xca, 0x74, 0xbb, 0x7b, 0x8c, 0xcb, 0x86, 0x1c, 0xdc, 0x69, 0x34, + 0xe1, 0xee, 0x06, 0x69, 0xa3, 0x98, 0xc3, 0x68, 0xea, 0x34, 0x39, 0xdc, + 0x6f, 0x1c, 0x55, 0x97, 0xcf, 0x3e, 0x78, 0x1e, 0xd3, 0xa7, 0xd7, 0x42, + 0xc5, 0xd9, 0xeb, 0x24, 0x9f, 0xf1, 0x91, 0x7f, 0x6d, 0xaa, 0x2e, 0xee, + 0x2f, 0x8b, 0x1d, 0x4b, 0x3f, 0xfc, 0xf4, 0xb3, 0x0b, 0xfd, 0xd8, 0xf6, + 0x07, 0xf5, 0xc3, 0x8f, 0x9b, 0x86, 0x92, 0x18, 0x35, 0x4e, 0x38, 0x56, + 0x68, 0x66, 0xdb, 0x3e, 0xac, 0x1c, 0xfa, 0x8d, 0x33, 0xcb, 0x6d, 0x5b, + 0x27, 0xa7, 0x52, 0xf1, 0xc0, 0x12, 0x1f, 0x6e, 0x1d, 0x89, 0x62, 0xc5, + 0x90, 0x8a, 0xd8, 0x12, 0xe9, 0x43, 0x14, 0x5d, 0x23, 0xbb, 0xbd, 0xc5, + 0xf2, 0xc0, 0x2d, 0x1c, 0xc3, 0x1b, 0x46, 0x0d, 0x7e, 0x40, 0x0c, 0xac, + 0x75, 0xb9, 0xfd, 0x46, 0x25, 0x23, 0xdc, 0xde, 0xa7, 0x62, 0xb6, 0x8e, + 0x60, 0x83, 0x99, 0xa4, 0xee, 0x3a, 0x95, 0xc7, 0x72, 0x1b, 0x95, 0xa1, + 0x7c, 0xb9, 0xef, 0x01, 0x7c, 0xa2, 0x10, 0xc4, 0x27, 0xc6, 0x1a, 0x78, + 0x85, 0x78, 0x35, 0xf2, 0x7a, 0xf1, 0xfc, 0xb8, 0xca, 0x67, 0x3c, 0x9f, + 0x65, 0x4e, 0xb1, 0xcd, 0xf5, 0x4b, 0x89, 0x0b, 0x9a, 0x9c, 0xd5, 0xc1, + 0x5b, 0x59, 0xc9, 0x27, 0xb6, 0xd1, 0x86, 0x65, 0x4d, 0xb8, 0x92, 0x39, + 0x45, 0x24, 0x36, 0x85, 0xbf, 0xaa, 0x2e, 0xce, 0x7d, 0xd1, 0x86, 0x71, + 0xde, 0x86, 0x7d, 0x78, 0x3b, 0xab, 0xa2, 0x25, 0xfe, 0x6f, 0xce, 0xf1, + 0xa0, 0xe0, 0xc9, 0xa5, 0xcf, 0xcb, 0x9c, 0x65, 0xfa, 0x5c, 0x36, 0xd3, + 0x34, 0x63, 0x5f, 0x56, 0x41, 0xc5, 0x90, 0xf0, 0xf3, 0xeb, 0x5c, 0xbe, + 0xf7, 0x7d, 0xc3, 0x07, 0xef, 0xd0, 0xa1, 0x2b, 0xe5, 0x68, 0x93, 0x6f, + 0x8c, 0x71, 0xab, 0x83, 0xf3, 0x32, 0xf2, 0xf1, 0x92, 0xce, 0xca, 0xba, + 0x50, 0xdc, 0x35, 0x49, 0xd5, 0x8d, 0xe9, 0x41, 0xa8, 0x63, 0xc2, 0x43, + 0xc9, 0x0d, 0xc6, 0x24, 0x1f, 0x08, 0xf1, 0xbf, 0xe4, 0x06, 0x8d, 0xfc, + 0xcf, 0xc4, 0xa2, 0x51, 0xe2, 0x78, 0x0f, 0xfa, 0x19, 0x9f, 0x2a, 0xa3, + 0x3d, 0xd8, 0x3e, 0xfe, 0x61, 0x31, 0xbf, 0x98, 0x63, 0x3d, 0x7b, 0xde, + 0xcf, 0xdc, 0x39, 0x62, 0x9f, 0xa6, 0xcf, 0x89, 0xcf, 0xc8, 0x5c, 0xed, + 0xcb, 0x4a, 0x1f, 0x1c, 0x6c, 0x30, 0x6e, 0x64, 0xdb, 0x3e, 0xa8, 0x0d, + 0x33, 0xb9, 0xe7, 0x79, 0x3e, 0x4d, 0xdd, 0x6d, 0x54, 0x46, 0x39, 0x27, + 0x96, 0xb7, 0x52, 0xd6, 0x87, 0x82, 0x15, 0x9c, 0x93, 0xaf, 0xe4, 0x45, + 0x46, 0xa7, 0x32, 0x9e, 0x9b, 0x59, 0x67, 0xa3, 0x32, 0x96, 0xff, 0x55, + 0xb5, 0xac, 0x99, 0x5f, 0xd0, 0x4d, 0xb9, 0x0f, 0x62, 0x63, 0x1a, 0xea, + 0xd3, 0xa2, 0x67, 0x19, 0xb3, 0x06, 0x2f, 0x79, 0x5c, 0x7d, 0xe1, 0x43, + 0xdb, 0x6c, 0xac, 0x72, 0xcf, 0x62, 0xc6, 0x18, 0x8b, 0x02, 0x56, 0x25, + 0x39, 0x1f, 0x6d, 0x34, 0xe5, 0x33, 0xbb, 0x3a, 0xf7, 0xd9, 0x0b, 0x83, + 0x87, 0x4b, 0x6b, 0x11, 0x6b, 0x21, 0xbc, 0x54, 0x71, 0x71, 0xd6, 0xa3, + 0x47, 0xb1, 0x9c, 0xb9, 0xee, 0x4d, 0xb9, 0x62, 0x7f, 0xc7, 0xd8, 0xdf, + 0x29, 0xd7, 0xf7, 0x92, 0xca, 0x68, 0x5e, 0x75, 0xfb, 0xed, 0x35, 0xa5, + 0xbf, 0x52, 0x97, 0xe3, 0xc9, 0xbf, 0x56, 0xca, 0xa9, 0x92, 0x18, 0xcc, + 0xcc, 0xf4, 0x61, 0xe9, 0x73, 0x2d, 0xda, 0x86, 0x3e, 0xa0, 0x9f, 0xc9, + 0xbc, 0x0a, 0xfe, 0xcc, 0xc3, 0xca, 0x91, 0x59, 0x68, 0x1d, 0x0a, 0xe3, + 0xb6, 0x91, 0x06, 0x2c, 0xda, 0xb5, 0x06, 0xd5, 0x63, 0x41, 0x5c, 0xb9, + 0x4b, 0xd6, 0xf8, 0x57, 0xa3, 0xb2, 0x70, 0x5b, 0x8d, 0xe4, 0xb8, 0x7a, + 0x3a, 0xc1, 0xf9, 0x4b, 0xa0, 0x22, 0x1d, 0x49, 0x24, 0x21, 0x6b, 0xa4, + 0x26, 0x2a, 0x0a, 0x26, 0xf9, 0xa4, 0xb3, 0x79, 0xbe, 0xe9, 0x73, 0xcf, + 0x9b, 0x2d, 0x2b, 0xd0, 0xe6, 0x39, 0x6e, 0x1f, 0x2f, 0x4f, 0xda, 0x71, + 0xce, 0x5e, 0x87, 0xcd, 0x35, 0x66, 0x13, 0x3c, 0x85, 0xcb, 0x91, 0x1c, + 0x69, 0xc3, 0xbc, 0x42, 0x03, 0x3a, 0x47, 0x42, 0x88, 0xa5, 0xc5, 0xc7, + 0x23, 0x5a, 0x4a, 0xed, 0x80, 0xbf, 0xc0, 0x78, 0x9a, 0xfe, 0x8d, 0xf3, + 0x16, 0xed, 0xa0, 0x87, 0xfa, 0xba, 0x26, 0xdd, 0x85, 0xba, 0x42, 0x00, + 0x57, 0x0f, 0x7d, 0x02, 0xb5, 0x23, 0x7e, 0xcc, 0x1a, 0xd2, 0x90, 0x5f, + 0xe2, 0x47, 0x60, 0x24, 0x8c, 0xea, 0xb4, 0xde, 0x75, 0x9b, 0x82, 0xe4, + 0xc2, 0x25, 0x61, 0xb6, 0x4d, 0x7b, 0xa3, 0x7f, 0x8d, 0x90, 0x7f, 0x2d, + 0xef, 0x06, 0x36, 0xa7, 0x05, 0x1b, 0x45, 0x27, 0x9f, 0x72, 0xcf, 0x9f, + 0xac, 0x4b, 0x7f, 0x18, 0xce, 0x95, 0xed, 0x5b, 0xfc, 0xdc, 0x72, 0xcf, + 0xc4, 0x32, 0x07, 0x52, 0xa6, 0x5b, 0xf4, 0xec, 0x3c, 0xde, 0xfb, 0x39, + 0xe3, 0xf3, 0x43, 0xe9, 0x80, 0x55, 0x6b, 0x6e, 0xc6, 0x55, 0xed, 0x11, + 0xab, 0xa0, 0xbc, 0xca, 0xf1, 0xff, 0x90, 0x41, 0xbb, 0x89, 0xfd, 0xfc, + 0x63, 0xe5, 0x5f, 0xba, 0xce, 0xb6, 0xe4, 0xa2, 0xf5, 0xb9, 0x23, 0xcc, + 0xe7, 0xa7, 0x2e, 0x5a, 0x9f, 0x13, 0xbc, 0x2f, 0x9f, 0x83, 0x90, 0xb9, + 0xd2, 0x66, 0xd8, 0xb7, 0xac, 0x17, 0x09, 0x36, 0xca, 0x7c, 0x95, 0xd7, + 0x8b, 0x7c, 0x58, 0x3e, 0x24, 0xb9, 0x92, 0xca, 0x3c, 0xa1, 0x05, 0xc9, + 0xd0, 0xa3, 0x9c, 0x03, 0x77, 0x4d, 0x89, 0xf7, 0x06, 0xf8, 0x59, 0xd6, + 0x7b, 0x34, 0xe2, 0x8f, 0x56, 0xca, 0x0b, 0xaa, 0x70, 0xeb, 0x50, 0x83, + 0xbb, 0x1f, 0xb5, 0x22, 0x7e, 0x39, 0x62, 0xf5, 0x5f, 0x62, 0x99, 0x0b, + 0x6b, 0x43, 0x57, 0x31, 0xdf, 0xa8, 0x71, 0xcf, 0x4a, 0x2c, 0xa3, 0xbe, + 0x2f, 0x47, 0xdb, 0x48, 0x11, 0xcf, 0x6e, 0x1b, 0x29, 0xe2, 0x56, 0x5a, + 0x6c, 0xce, 0x57, 0xb4, 0xb9, 0x2c, 0x6d, 0x2e, 0xa8, 0x77, 0x2a, 0xd9, + 0xdc, 0x47, 0xc5, 0x13, 0x04, 0xeb, 0xcc, 0xf2, 0x99, 0x6a, 0x62, 0x5e, + 0xfe, 0x48, 0xcd, 0x1f, 0x16, 0x7f, 0x2e, 0xd5, 0xd9, 0xb5, 0x7f, 0xa4, + 0xce, 0xca, 0x31, 0xeb, 0x82, 0xce, 0x06, 0x2f, 0xd1, 0xd9, 0x02, 0xea, + 0xa0, 0x41, 0x2f, 0xea, 0x6d, 0xb9, 0x71, 0x19, 0x52, 0xae, 0xde, 0xaa, + 0x64, 0x6d, 0x8c, 0xf7, 0x04, 0xaf, 0xe7, 0xe0, 0xfb, 0xc1, 0x2f, 0xb9, + 0xf7, 0x16, 0x51, 0x27, 0x45, 0x7d, 0x05, 0xa9, 0xaf, 0x0b, 0xb1, 0x00, + 0xea, 0x07, 0xcc, 0xa7, 0x8a, 0xb1, 0x40, 0x74, 0xf7, 0xda, 0xa0, 0x86, + 0xba, 0xeb, 0x2e, 0xc7, 0x2b, 0x7b, 0xab, 0xd0, 0x3e, 0xe2, 0xa3, 0x7f, + 0x49, 0x7c, 0x28, 0xc6, 0xa4, 0xd6, 0x11, 0x77, 0x3f, 0x8a, 0xf8, 0xda, + 0x10, 0xf8, 0xc3, 0x63, 0xb0, 0x8c, 0x47, 0xce, 0xe5, 0xc9, 0xb9, 0x39, + 0x19, 0x97, 0x3e, 0xc3, 0x16, 0x1c, 0xe7, 0x19, 0xce, 0x77, 0xaa, 0x21, + 0x92, 0x95, 0xf5, 0xa6, 0x2c, 0x39, 0x99, 0x27, 0x2d, 0x3a, 0x13, 0xbe, + 0xad, 0xde, 0xe8, 0x81, 0xda, 0xe6, 0xc1, 0x66, 0x9c, 0x32, 0xf4, 0xfe, + 0x7b, 0xf1, 0x27, 0xe8, 0x0d, 0x39, 0xd8, 0x6f, 0xac, 0x64, 0x3e, 0x51, + 0x8d, 0xf5, 0x6d, 0x34, 0xcf, 0x3b, 0x3a, 0x88, 0x09, 0x56, 0x8f, 0x07, + 0xb2, 0x9e, 0xbb, 0xf1, 0x2e, 0x3b, 0x1a, 0xe9, 0x7e, 0x50, 0x01, 0x56, + 0x0c, 0xf8, 0xa1, 0x29, 0x2e, 0xdf, 0x89, 0x0d, 0xa9, 0xb2, 0xb6, 0xfc, + 0x2f, 0x15, 0xc5, 0xb3, 0x10, 0x2a, 0xb4, 0x46, 0x69, 0x67, 0x25, 0xac, + 0xc9, 0x0e, 0x17, 0x4f, 0x6a, 0x16, 0x2a, 0xb8, 0x75, 0x61, 0xc4, 0x4a, + 0x29, 0x8e, 0xb3, 0x2a, 0xee, 0x75, 0x9f, 0xef, 0x98, 0x6c, 0x4d, 0xdd, + 0xa9, 0xfe, 0x8b, 0x63, 0xb9, 0xeb, 0xd9, 0x91, 0x60, 0x52, 0x65, 0x9f, + 0x3f, 0xf2, 0xac, 0xa2, 0x8c, 0x93, 0x5c, 0x9c, 0xbc, 0xfb, 0xc9, 0xd2, + 0xfa, 0xaf, 0xcf, 0x5c, 0xff, 0x17, 0xfb, 0x75, 0xc9, 0xf7, 0xbe, 0xe4, + 0x9e, 0xfb, 0xc8, 0x66, 0x64, 0xfd, 0xf0, 0xe1, 0x00, 0xaa, 0x57, 0xa2, + 0x77, 0xf2, 0x3a, 0x4c, 0xb4, 0xfd, 0xab, 0x93, 0x2b, 0xf6, 0x5d, 0xcc, + 0xd0, 0x3f, 0xcf, 0xcc, 0xdd, 0x75, 0x7d, 0x4b, 0x84, 0x1c, 0x5c, 0xce, + 0x7a, 0x92, 0x0b, 0x2b, 0x45, 0x1e, 0x3e, 0x5f, 0xbf, 0x09, 0xcf, 0x5e, + 0x24, 0x53, 0xd6, 0x12, 0xca, 0x32, 0x77, 0x51, 0x9e, 0xc8, 0x65, 0x3c, + 0xd0, 0xff, 0xcd, 0x19, 0x09, 0xcd, 0x2c, 0x17, 0xab, 0x2a, 0xc6, 0x2a, + 0x29, 0x57, 0x6e, 0xb7, 0x82, 0xf5, 0xde, 0x77, 0x46, 0x2f, 0x2a, 0xf7, + 0xd3, 0x52, 0xb9, 0x67, 0x02, 0x72, 0x66, 0x24, 0x9b, 0x11, 0xce, 0x7a, + 0xca, 0x19, 0xbb, 0xa8, 0x4c, 0x4b, 0xf5, 0xc5, 0x65, 0x9a, 0x89, 0xd1, + 0xff, 0xaf, 0x33, 0x7e, 0x51, 0x99, 0xe4, 0x25, 0x65, 0x16, 0x10, 0x13, + 0xbf, 0xef, 0xec, 0xbb, 0xa8, 0x4c, 0xed, 0x25, 0x65, 0x16, 0xd3, 0x1e, + 0x9f, 0x71, 0x0e, 0x5c, 0x54, 0x66, 0xcc, 0x7f, 0x71, 0x19, 0xd9, 0xe3, + 0x58, 0xff, 0x17, 0x5b, 0xf4, 0x75, 0x25, 0x9f, 0xbb, 0x70, 0xbf, 0x58, + 0xfe, 0xf1, 0x4b, 0xfa, 0x1f, 0xb1, 0x64, 0xbe, 0x7d, 0xed, 0xe5, 0xf9, + 0x7e, 0xb8, 0x74, 0xff, 0x7b, 0x35, 0x17, 0x97, 0xbb, 0x22, 0x70, 0x69, + 0x3b, 0x45, 0x79, 0x47, 0x2f, 0x69, 0xff, 0xe6, 0xca, 0x8b, 0xbf, 0xbf, + 0x5d, 0x51, 0xfc, 0x5e, 0xd6, 0xe9, 0xa1, 0x4b, 0x9e, 0xff, 0x7d, 0xc5, + 0xc5, 0xdf, 0x37, 0x54, 0x7e, 0x78, 0x3b, 0xb5, 0x97, 0xb4, 0xa3, 0xf4, + 0xca, 0xbb, 0x38, 0x1e, 0x53, 0xad, 0xed, 0xed, 0x58, 0x7f, 0x43, 0x2a, + 0xbf, 0x89, 0xf6, 0x29, 0xb6, 0xf5, 0xe0, 0x0d, 0x6b, 0xf3, 0x6f, 0xcd, + 0xe0, 0xb1, 0xcb, 0xc2, 0x41, 0x7c, 0x1c, 0x6b, 0xdd, 0xbd, 0x34, 0x95, + 0x38, 0x69, 0xb9, 0xb6, 0x40, 0x8e, 0xe9, 0x57, 0xcc, 0x14, 0x0c, 0xf7, + 0xbc, 0xe5, 0x3a, 0x34, 0xe7, 0xdd, 0x3d, 0xbb, 0x58, 0x0a, 0xcf, 0xaa, + 0x5d, 0xba, 0x55, 0x3a, 0x47, 0x67, 0x5d, 0x1f, 0x44, 0x72, 0x66, 0x7e, + 0xaa, 0x8d, 0x23, 0x12, 0xde, 0x86, 0x75, 0xee, 0x59, 0x6b, 0xc5, 0xec, + 0x29, 0x9d, 0xd7, 0x5c, 0x03, 0x3d, 0x5f, 0xe6, 0x4d, 0xb2, 0x9e, 0x2b, + 0xe7, 0x19, 0x1c, 0xfa, 0xa0, 0xc4, 0xf9, 0x83, 0x8a, 0x3a, 0xe0, 0xae, + 0x99, 0xae, 0xf6, 0x20, 0x9a, 0xe8, 0x54, 0x90, 0xaa, 0x32, 0xa3, 0xda, + 0xdb, 0x25, 0x4c, 0xf3, 0x4d, 0x6c, 0x51, 0x2a, 0x26, 0xfa, 0x15, 0xef, + 0x44, 0x11, 0xd3, 0x3c, 0x13, 0xb2, 0xb6, 0xd0, 0xc0, 0x32, 0x41, 0xb4, + 0x2c, 0xf1, 0xe2, 0x3b, 0x76, 0xad, 0xfb, 0x1e, 0xc7, 0xd6, 0x25, 0x15, + 0x78, 0x20, 0xae, 0xa0, 0xeb, 0xaa, 0xc3, 0x78, 0x2b, 0x2f, 0xeb, 0x6c, + 0x56, 0x7c, 0x94, 0x6d, 0x1e, 0xb2, 0x65, 0xbd, 0x74, 0x4b, 0x7c, 0xc4, + 0x6d, 0xff, 0xf3, 0xe8, 0x73, 0xf7, 0xad, 0xba, 0x9d, 0xed, 0x99, 0x1e, + 0x67, 0x1b, 0x73, 0x8d, 0x82, 0xdd, 0x90, 0xaa, 0x63, 0xfd, 0xb7, 0x96, + 0xac, 0xc7, 0x69, 0x96, 0x99, 0xb0, 0x1f, 0xc4, 0xfb, 0xf9, 0x20, 0xf2, + 0xf6, 0x4a, 0x7c, 0x37, 0x1f, 0x60, 0xce, 0xd7, 0x85, 0xef, 0xe4, 0x57, + 0xe3, 0xc5, 0x61, 0xf7, 0x7d, 0x29, 0x2c, 0xb3, 0x15, 0xac, 0x88, 0xae, + 0xc6, 0xb1, 0xd1, 0xd5, 0x38, 0x3c, 0x2c, 0xef, 0x0e, 0xcc, 0x25, 0x8f, + 0x2c, 0xda, 0x9b, 0x4a, 0x8c, 0x59, 0x66, 0xaf, 0xc2, 0xa1, 0xd1, 0x30, + 0x73, 0x29, 0x03, 0x27, 0xf3, 0x21, 0x8c, 0xd8, 0x6d, 0x38, 0x91, 0x0f, + 0xe3, 0xeb, 0x76, 0x02, 0x67, 0xf9, 0xfd, 0xa0, 0x2d, 0x9c, 0xa5, 0x03, + 0xd3, 0xf9, 0x6f, 0x32, 0xcf, 0x99, 0x87, 0x23, 0xdd, 0xcf, 0x30, 0x1c, + 0x1d, 0xe4, 0xd5, 0x85, 0x13, 0xa3, 0x5d, 0x38, 0x35, 0x7c, 0x2b, 0x4e, + 0x8d, 0xfe, 0x18, 0x6f, 0x0d, 0x4b, 0x7f, 0xe5, 0xfc, 0xb7, 0xc8, 0xd5, + 0x29, 0x77, 0x35, 0xa6, 0x46, 0xff, 0x18, 0xd9, 0xef, 0x3a, 0x47, 0x56, + 0x8b, 0xdc, 0x67, 0x7e, 0x87, 0x6c, 0xd1, 0xa5, 0x60, 0xbf, 0x1f, 0xc7, + 0x6c, 0x3f, 0x8e, 0xda, 0x53, 0x57, 0x56, 0x61, 0xea, 0x7a, 0x22, 0x1d, + 0xb6, 0xe7, 0x2b, 0xf1, 0x5c, 0x56, 0xd6, 0xd8, 0x3e, 0x86, 0x64, 0x70, + 0x23, 0xb6, 0x4e, 0x56, 0xe2, 0x3b, 0x59, 0x3f, 0x75, 0x7c, 0x3d, 0x92, + 0xf5, 0xab, 0xa9, 0xbf, 0x00, 0x5e, 0xb2, 0x43, 0x78, 0xd9, 0x6e, 0x4d, + 0x15, 0x94, 0x76, 0x58, 0x2e, 0xfe, 0x07, 0xa8, 0xef, 0x0d, 0x6e, 0x9f, + 0xbe, 0x63, 0x77, 0x3b, 0x5b, 0xa9, 0xe3, 0xfe, 0xcc, 0xe7, 0xdd, 0xb3, + 0xdb, 0x2f, 0xda, 0xd3, 0x8e, 0xbc, 0x93, 0xf1, 0x14, 0x75, 0x7a, 0xcc, + 0x4e, 0x91, 0xdb, 0x35, 0x71, 0x8e, 0xa6, 0x30, 0x4a, 0xbb, 0x3c, 0x99, + 0xd5, 0x8f, 0xae, 0xc5, 0x26, 0x9c, 0xcd, 0x55, 0xe2, 0x35, 0xb6, 0x51, + 0xb7, 0xd8, 0x8b, 0xe3, 0xae, 0xbc, 0x4d, 0x78, 0x3f, 0xab, 0x30, 0xde, + 0x6e, 0xc2, 0x7b, 0x7c, 0xf6, 0x0a, 0x3f, 0x9f, 0x8e, 0xb3, 0x87, 0xa5, + 0x67, 0xa7, 0xc8, 0xcf, 0x65, 0xcd, 0xa8, 0xb7, 0x63, 0x13, 0x4e, 0xe4, + 0xde, 0x23, 0xa7, 0x75, 0xf0, 0x45, 0x63, 0x36, 0x12, 0xb3, 0xc9, 0x9b, + 0xf4, 0x4a, 0x1c, 0xe3, 0xf3, 0x85, 0xc4, 0xdf, 0xe2, 0xfa, 0xd9, 0x26, + 0xbc, 0xcb, 0xf1, 0x3c, 0x40, 0x59, 0xef, 0xe4, 0xfe, 0x96, 0x72, 0x97, + 0x22, 0x1f, 0xff, 0x5b, 0xca, 0xfd, 0x31, 0xc6, 0x4b, 0xfa, 0x38, 0x61, + 0xc8, 0xb8, 0xbe, 0x31, 0x0b, 0xd5, 0x21, 0x8e, 0xe3, 0x9b, 0xfc, 0xbf, + 0x01, 0xc7, 0xf3, 0xff, 0x9b, 0xff, 0xbf, 0x8b, 0x03, 0x79, 0x59, 0xaf, + 0x9e, 0x19, 0x4b, 0xc5, 0x7f, 0xca, 0x1c, 0x64, 0x0e, 0x32, 0x83, 0xb5, + 0xa9, 0xd9, 0xb4, 0xa3, 0xbf, 0xbe, 0xb6, 0x0e, 0xef, 0xc6, 0x2d, 0xec, + 0xd8, 0xe7, 0x45, 0x86, 0xb8, 0xbb, 0x63, 0xa0, 0x01, 0x4f, 0xec, 0x0c, + 0xe2, 0xf1, 0x9d, 0x97, 0x61, 0xcb, 0xce, 0x2b, 0xb0, 0x67, 0x67, 0x13, + 0xd2, 0x3b, 0x1d, 0xe7, 0xfd, 0xc5, 0x8e, 0xb3, 0x88, 0xd7, 0x23, 0xf4, + 0x05, 0x3f, 0xff, 0xbf, 0x10, 0x17, 0x3f, 0xd1, 0x71, 0x95, 0xeb, 0x2f, + 0x9d, 0xb8, 0xd2, 0xfd, 0x9f, 0xc4, 0xa2, 0xfc, 0xc6, 0xf8, 0xfa, 0xc2, + 0xa6, 0xf8, 0x7d, 0x85, 0x39, 0xd8, 0x3a, 0xd8, 0x88, 0xc1, 0x9d, 0x0d, + 0xa9, 0x06, 0xb6, 0xb3, 0xea, 0x5a, 0xe1, 0x76, 0x8e, 0x63, 0xb4, 0xf7, + 0xc7, 0xd7, 0x16, 0x9e, 0x41, 0x77, 0x21, 0x84, 0xbe, 0xc1, 0x30, 0xdb, + 0x92, 0xbd, 0x5c, 0xef, 0xd1, 0x7b, 0xe1, 0x38, 0xd3, 0x8b, 0x0f, 0xe2, + 0xae, 0xc2, 0x37, 0xc9, 0x1b, 0x43, 0x48, 0x0f, 0xae, 0x47, 0x66, 0xb2, + 0x22, 0xe5, 0x37, 0x1d, 0xbc, 0x14, 0x9f, 0xc2, 0xed, 0x94, 0xf7, 0xe8, + 0x60, 0x2d, 0xfb, 0x54, 0x9d, 0xaa, 0x34, 0x25, 0x86, 0x3f, 0xc8, 0x18, + 0x25, 0xfc, 0xe2, 0x28, 0x56, 0x30, 0xbf, 0xaa, 0x5f, 0xa2, 0xcf, 0x42, + 0x6d, 0xd0, 0x7b, 0xa6, 0x43, 0xec, 0x2f, 0x45, 0xfb, 0x93, 0x7d, 0xf5, + 0x75, 0xb8, 0xdb, 0x3d, 0xe7, 0xdd, 0x83, 0xe7, 0x6d, 0xc1, 0x9d, 0x35, + 0xd8, 0x6f, 0xaf, 0x63, 0xce, 0x25, 0xf1, 0x7a, 0x25, 0x9a, 0x0b, 0x7f, + 0x17, 0xbf, 0xa7, 0xb0, 0x9a, 0x7c, 0xf6, 0x5f, 0x70, 0x53, 0x21, 0xc7, + 0x7e, 0x8d, 0xc6, 0xef, 0x2e, 0xec, 0x89, 0xdf, 0x5b, 0xe8, 0xc2, 0x02, + 0x37, 0xa7, 0x64, 0xfe, 0x55, 0x90, 0x38, 0x77, 0x9c, 0x5c, 0xf8, 0x14, + 0x96, 0x17, 0x5e, 0xc3, 0xcd, 0x05, 0xc1, 0x0d, 0x89, 0x7f, 0x2f, 0x7a, + 0x51, 0x2d, 0x71, 0xef, 0x0b, 0xd8, 0xba, 0x3b, 0x85, 0xbe, 0xdd, 0x65, + 0x8c, 0x6a, 0x0d, 0xee, 0x13, 0x7c, 0x99, 0xf4, 0x95, 0x62, 0xd4, 0xa7, + 0x68, 0x8f, 0x2a, 0x63, 0xa3, 0xac, 0xd3, 0xaf, 0xa3, 0x2f, 0x6f, 0x24, + 0x66, 0xca, 0x7a, 0xfc, 0x27, 0x4b, 0xf7, 0x25, 0xd6, 0xcb, 0x5a, 0xbc, + 0x86, 0x43, 0x79, 0x77, 0x4f, 0x5b, 0xf3, 0xeb, 0xb7, 0xf3, 0x99, 0xd4, + 0xff, 0x02, 0xd2, 0xbb, 0x57, 0x3b, 0x8f, 0x66, 0x8a, 0xfb, 0x66, 0x47, + 0xa2, 0x6c, 0x6b, 0x9c, 0xb1, 0x7d, 0x2f, 0xfc, 0xb3, 0x38, 0xb6, 0x89, + 0x01, 0x58, 0x1e, 0xbd, 0xdb, 0xd9, 0x92, 0xc1, 0xbd, 0xb3, 0x10, 0xc6, + 0xca, 0x89, 0x0a, 0x24, 0xf7, 0x57, 0xe3, 0xb6, 0x9d, 0x3d, 0xb4, 0x65, + 0x8b, 0xf6, 0xab, 0x1b, 0x77, 0x2b, 0xd5, 0xb8, 0x99, 0xf7, 0x3e, 0x3d, + 0x28, 0x6b, 0x58, 0xd1, 0xa3, 0x27, 0x3c, 0xd5, 0xb8, 0x6b, 0xaf, 0x1f, + 0xb9, 0xdc, 0x4a, 0x24, 0xf7, 0x1e, 0x81, 0x95, 0xa3, 0x4d, 0xee, 0x22, + 0xce, 0x30, 0xcd, 0x51, 0xcd, 0x1f, 0x63, 0xcf, 0xa8, 0x8a, 0xba, 0x5d, + 0xb2, 0xfe, 0xa8, 0xe8, 0xa7, 0xa3, 0x05, 0xa4, 0x47, 0xbd, 0x98, 0x95, + 0xee, 0xc4, 0x04, 0xb1, 0x26, 0x90, 0x4e, 0x22, 0x9f, 0xef, 0x46, 0x8e, + 0x58, 0x92, 0x1b, 0x0d, 0xa0, 0x26, 0x6d, 0x20, 0xa0, 0xc7, 0xb0, 0x83, + 0xfe, 0x52, 0x91, 0xd6, 0xb1, 0x2d, 0x7f, 0x23, 0xac, 0xd1, 0x4f, 0x60, + 0xfb, 0x68, 0x37, 0x2f, 0x13, 0x7d, 0xa3, 0x9f, 0xc7, 0xb2, 0x89, 0xa3, + 0xe8, 0xcf, 0xa7, 0x68, 0x8f, 0xef, 0x61, 0x7b, 0xee, 0x30, 0x9e, 0xc8, + 0x6e, 0xc6, 0xd9, 0xc5, 0x87, 0xf1, 0x38, 0x3f, 0x67, 0xb3, 0xfa, 0xc6, + 0xb0, 0x7a, 0x18, 0x99, 0xdc, 0x26, 0x7c, 0x62, 0x50, 0xc1, 0x4b, 0xb4, + 0xf5, 0xdb, 0xf7, 0xd2, 0x16, 0x1f, 0xdb, 0x80, 0xae, 0x89, 0xef, 0xc2, + 0xce, 0x3f, 0x8f, 0x1d, 0xb9, 0x07, 0xd1, 0x9f, 0x59, 0xcf, 0xfc, 0xff, + 0x19, 0xca, 0x39, 0x48, 0x3f, 0xdf, 0xc8, 0x31, 0x3e, 0xcc, 0xeb, 0xc2, + 0x1a, 0xe3, 0x85, 0x35, 0x39, 0xfa, 0x7d, 0x46, 0x72, 0xcf, 0x75, 0xc4, + 0x89, 0x27, 0x6b, 0x65, 0x5d, 0xb2, 0x4a, 0x9f, 0xb9, 0x56, 0x2f, 0xb6, + 0x1f, 0x76, 0x73, 0xed, 0xaa, 0xb4, 0xe4, 0x75, 0x53, 0x91, 0x2a, 0x72, + 0x0c, 0x7f, 0x5a, 0x74, 0xd8, 0xe3, 0xf4, 0x66, 0x04, 0x4b, 0x64, 0x3e, + 0x34, 0xbc, 0x90, 0xff, 0x31, 0xb6, 0x0e, 0xcf, 0xc6, 0xf2, 0x6c, 0x1b, + 0x39, 0xa5, 0xe3, 0x7c, 0x85, 0xbe, 0x66, 0x93, 0xeb, 0xec, 0x18, 0x4c, + 0x12, 0x53, 0x66, 0x23, 0x39, 0xa7, 0xc8, 0x4f, 0xc2, 0x69, 0x69, 0xcb, + 0x57, 0xda, 0xab, 0x9b, 0xba, 0x32, 0xcc, 0x7b, 0x75, 0x69, 0x99, 0xb7, + 0x88, 0xa1, 0xb9, 0xfb, 0x69, 0x8e, 0xf3, 0x52, 0xb4, 0xcc, 0x95, 0xa6, + 0xae, 0xac, 0xc3, 0x6c, 0x59, 0x77, 0x4d, 0xc8, 0x39, 0xdf, 0x6f, 0xb5, + 0x2c, 0xa7, 0xaf, 0x7e, 0x01, 0x03, 0xe3, 0xe5, 0x77, 0x23, 0xff, 0xb3, + 0xe4, 0xdd, 0xf5, 0x9f, 0x2c, 0xaf, 0xbc, 0x07, 0x2a, 0xe7, 0x8c, 0xcb, + 0xef, 0x50, 0x8a, 0x2e, 0xaf, 0x90, 0xfd, 0x03, 0xab, 0xb8, 0x4f, 0x0a, + 0x1c, 0xb1, 0x2b, 0x18, 0x87, 0xd5, 0xa5, 0x64, 0x63, 0x21, 0x1f, 0x2a, + 0x19, 0x2f, 0x1b, 0xd1, 0x47, 0xbe, 0x7a, 0x93, 0x51, 0x81, 0x03, 0x6d, + 0x49, 0x39, 0xcf, 0xd7, 0xe3, 0x73, 0x79, 0xea, 0xa6, 0x3f, 0xff, 0x6d, + 0x9e, 0xba, 0x09, 0xe9, 0x8c, 0x9c, 0x63, 0xeb, 0xc6, 0x4b, 0xf5, 0xf2, + 0x5e, 0xe7, 0x26, 0xf7, 0x9c, 0x70, 0xd5, 0x42, 0x62, 0x46, 0x5c, 0xc3, + 0x51, 0xbd, 0x55, 0x6b, 0x50, 0x23, 0x06, 0x94, 0xd7, 0x1d, 0x2b, 0x94, + 0x44, 0xff, 0xa4, 0x9c, 0xd5, 0xfb, 0xa8, 0x3d, 0x84, 0xb5, 0xd8, 0xfe, + 0x58, 0x07, 0x8e, 0xaf, 0x96, 0xb5, 0xbc, 0x9f, 0x95, 0xde, 0xdb, 0x93, + 0x3e, 0x46, 0xea, 0xe4, 0x0c, 0xaa, 0xc8, 0xde, 0x9e, 0x51, 0x19, 0x7b, + 0xe2, 0x78, 0x3d, 0xe8, 0x8e, 0x37, 0x56, 0x3e, 0x97, 0x59, 0xa9, 0x2f, + 0x2f, 0x95, 0x5f, 0x50, 0x27, 0xbc, 0x64, 0x5b, 0x66, 0x13, 0xb9, 0xb6, + 0xf4, 0xe7, 0xd7, 0xce, 0xda, 0x50, 0x03, 0xcb, 0x8e, 0x95, 0x9e, 0x8b, + 0xad, 0x45, 0x8c, 0x24, 0xe4, 0x9e, 0xd4, 0x11, 0x9d, 0xcd, 0xac, 0xe3, + 0x41, 0xbd, 0x7e, 0x25, 0x1e, 0xa2, 0x8f, 0xcf, 0xd7, 0x5f, 0x76, 0x36, + 0xcb, 0x39, 0xcd, 0x85, 0xc1, 0x19, 0x6d, 0x2d, 0x75, 0xfb, 0x52, 0xc9, + 0xbe, 0x0c, 0x66, 0xe4, 0xbd, 0x81, 0xb3, 0xce, 0xc2, 0x46, 0x79, 0x7e, + 0x5b, 0x6d, 0x51, 0x7e, 0xb3, 0x7b, 0x0e, 0x7b, 0x4f, 0xa6, 0xdc, 0x6f, + 0x39, 0xe3, 0x1e, 0x2a, 0xb7, 0x15, 0xbb, 0x30, 0x1e, 0xe9, 0xdb, 0xd7, + 0x6a, 0x2f, 0xee, 0xf3, 0x9d, 0xb3, 0xca, 0xef, 0x17, 0xcc, 0x73, 0xeb, + 0x94, 0xdb, 0x94, 0x3e, 0x6e, 0xc2, 0xe3, 0x93, 0x97, 0x8e, 0xf1, 0xee, + 0x19, 0x63, 0x92, 0x3a, 0x32, 0xae, 0x60, 0xc9, 0x0e, 0x36, 0xb2, 0x8c, + 0xd4, 0x91, 0x75, 0x82, 0xa0, 0x9b, 0x3f, 0xd4, 0xed, 0x16, 0x79, 0x22, + 0xc3, 0x71, 0xde, 0x70, 0x63, 0xf2, 0x02, 0xb7, 0xcc, 0xe0, 0xe4, 0x6a, + 0xfa, 0x91, 0xb3, 0x99, 0xf8, 0xec, 0xbc, 0xd1, 0x11, 0xc6, 0x56, 0x5b, + 0x74, 0xad, 0x87, 0xc7, 0x88, 0x4d, 0x7d, 0x2e, 0x9f, 0xf1, 0xa1, 0x37, + 0x57, 0x3e, 0xeb, 0x52, 0x29, 0x7b, 0x21, 0x61, 0xd1, 0x79, 0xaf, 0x41, + 0x1e, 0x17, 0x5c, 0xa6, 0x79, 0xc9, 0xc5, 0xee, 0xc1, 0x7f, 0xc8, 0xfc, + 0xc6, 0x7c, 0xa5, 0x75, 0x93, 0x14, 0xed, 0xa8, 0x18, 0x0f, 0x41, 0xfe, + 0x40, 0x1e, 0x56, 0x3a, 0x43, 0xdf, 0x9b, 0xff, 0x0f, 0x67, 0xca, 0x3d, + 0x43, 0x7f, 0xe1, 0x2c, 0x4a, 0x2e, 0xe8, 0x38, 0xfb, 0xf8, 0xec, 0xc2, + 0x79, 0x7a, 0x72, 0x06, 0x5d, 0xce, 0xdd, 0xff, 0x3b, 0xe7, 0x6e, 0x66, + 0xd9, 0xa9, 0xfa, 0xe2, 0xfb, 0x25, 0x49, 0x75, 0x99, 0x5e, 0xc6, 0x6d, + 0xd9, 0x27, 0x12, 0xdc, 0x3e, 0x58, 0x57, 0x5c, 0x3f, 0x8e, 0x74, 0x75, + 0x43, 0xf6, 0xe4, 0xcb, 0x38, 0xa3, 0x1b, 0x8b, 0x94, 0xcd, 0x68, 0x89, + 0x57, 0xcb, 0xf9, 0xba, 0x88, 0xd7, 0x8c, 0x04, 0xdf, 0x42, 0x34, 0x76, + 0xd8, 0x3d, 0x43, 0x22, 0xd8, 0xa3, 0xe3, 0x9e, 0xbc, 0x4e, 0x9b, 0x95, + 0xf7, 0xd2, 0xe5, 0x73, 0xf1, 0xdd, 0xc7, 0x64, 0x5e, 0xb0, 0xba, 0x87, + 0x58, 0x6d, 0xfd, 0xa5, 0xcf, 0x95, 0x17, 0xe9, 0x19, 0x55, 0x22, 0x5d, + 0x0f, 0x2a, 0x65, 0x79, 0x81, 0x0f, 0x91, 0x17, 0x63, 0x7d, 0xad, 0xf4, + 0x2e, 0xb8, 0x4e, 0x19, 0x97, 0x9e, 0x0d, 0x9a, 0x93, 0x92, 0x3c, 0xfa, + 0x40, 0x89, 0x73, 0x1e, 0xfe, 0xad, 0x3c, 0xfa, 0x43, 0xdb, 0x4c, 0xb2, + 0xcd, 0xae, 0x6a, 0x25, 0x19, 0x97, 0xf7, 0x80, 0x2a, 0xe3, 0xd1, 0xd8, + 0x0b, 0x74, 0x72, 0xaf, 0x19, 0x0d, 0x8f, 0xba, 0x67, 0x5d, 0x0c, 0xff, + 0xf2, 0x7c, 0xd1, 0x7f, 0xac, 0xc9, 0xdf, 0xad, 0x93, 0x1a, 0x5d, 0xef, + 0x6e, 0x55, 0x92, 0xd7, 0x57, 0x53, 0x4e, 0x2c, 0x0e, 0xad, 0xc2, 0x2c, + 0xeb, 0x28, 0x1a, 0x7b, 0x8b, 0xf3, 0x79, 0xa8, 0x23, 0x1a, 0x1e, 0x71, + 0x73, 0x74, 0xd1, 0x8b, 0xe1, 0x2f, 0xce, 0xbd, 0x2e, 0x7c, 0xde, 0xf2, + 0x31, 0x36, 0x8f, 0xdb, 0x7e, 0x8e, 0xa5, 0x35, 0xb8, 0x1d, 0xf5, 0xb4, + 0x71, 0x24, 0xfb, 0xda, 0x18, 0x1f, 0x6c, 0x24, 0x3d, 0x57, 0xd5, 0x21, + 0x45, 0x82, 0xee, 0xd1, 0x53, 0xe4, 0x5c, 0xad, 0xb1, 0x47, 0x68, 0xbf, + 0xb9, 0x50, 0x24, 0x6c, 0x21, 0x85, 0xe7, 0xec, 0x65, 0x7f, 0xee, 0x81, + 0x65, 0xd4, 0x70, 0xa2, 0xab, 0xcd, 0xa9, 0x3f, 0xbf, 0x35, 0x1a, 0xd1, + 0x5e, 0x2c, 0x9d, 0xd5, 0xe9, 0xb5, 0x7f, 0xe1, 0xee, 0x51, 0x79, 0xf4, + 0xdf, 0x55, 0x46, 0xda, 0xf6, 0x63, 0x2c, 0x9b, 0xc5, 0x96, 0xc7, 0xd8, + 0x47, 0xdd, 0xc1, 0x32, 0x63, 0x33, 0x96, 0x1b, 0x01, 0xac, 0x0b, 0xb6, + 0x24, 0xe4, 0x2c, 0xd2, 0x48, 0xae, 0xb8, 0x36, 0x52, 0x5c, 0x0b, 0xef, + 0xc7, 0xa3, 0x19, 0x37, 0x3e, 0x07, 0xfd, 0x66, 0x52, 0x79, 0x34, 0xdf, + 0xa9, 0x3c, 0x52, 0x5a, 0x8f, 0xeb, 0xcf, 0xdf, 0x10, 0x44, 0xb5, 0x85, + 0x13, 0x86, 0xbc, 0x47, 0x29, 0x72, 0x2d, 0x8c, 0x76, 0xfc, 0x21, 0xef, + 0x53, 0x8a, 0x4e, 0x37, 0xa2, 0x6f, 0xf8, 0x61, 0xf4, 0x0e, 0xbf, 0xe4, + 0x9e, 0x65, 0xf5, 0xe9, 0x7e, 0xeb, 0x0a, 0x33, 0x72, 0xd0, 0xc2, 0xbc, + 0x7a, 0x59, 0x13, 0x6e, 0x34, 0x8f, 0xe2, 0xd1, 0xa0, 0xbc, 0x27, 0xd8, + 0x4f, 0x9e, 0x22, 0xef, 0x9c, 0xad, 0xc1, 0x67, 0x06, 0x64, 0x0e, 0x6b, + 0xad, 0x4a, 0x33, 0x92, 0x5c, 0xe7, 0xce, 0x61, 0x1b, 0x8e, 0x15, 0x1e, + 0xc6, 0x1b, 0xbb, 0x36, 0x43, 0x8d, 0x47, 0xc2, 0xb7, 0xc0, 0xd9, 0x7c, + 0xc4, 0x48, 0x5a, 0x3e, 0x44, 0x0e, 0x78, 0x54, 0xe0, 0xd9, 0x5d, 0x92, + 0x4f, 0xf7, 0xe0, 0x7a, 0x72, 0x80, 0x3a, 0xdd, 0x59, 0xfa, 0xab, 0xc5, + 0x91, 0x7e, 0xdd, 0x63, 0xfd, 0xd3, 0x1c, 0x44, 0xb2, 0x09, 0x55, 0xef, + 0xf9, 0xa4, 0x0a, 0x25, 0x60, 0xca, 0x6f, 0x00, 0x6c, 0xc6, 0x27, 0xda, + 0x03, 0xd6, 0x2c, 0x33, 0x92, 0x7d, 0x49, 0x89, 0xc4, 0x2c, 0xf5, 0x1b, + 0x9c, 0xe7, 0x18, 0x5e, 0x24, 0xc7, 0xe9, 0x62, 0x6c, 0x5f, 0x21, 0x31, + 0xdd, 0xc5, 0xbe, 0xe6, 0x44, 0x95, 0x12, 0xc4, 0x2d, 0x05, 0xe0, 0x50, + 0x6e, 0x0d, 0x4e, 0xee, 0x32, 0xd0, 0xc9, 0x67, 0x83, 0x19, 0x02, 0x16, + 0x31, 0x60, 0x83, 0x61, 0xb5, 0xaa, 0xe4, 0x16, 0x3e, 0x15, 0xcb, 0xe6, + 0x9b, 0xd1, 0xa9, 0xa5, 0x1e, 0x2f, 0x12, 0x05, 0x2f, 0xee, 0x60, 0x99, + 0xed, 0x8c, 0x0b, 0x9f, 0x4c, 0xfb, 0xc9, 0x6f, 0x9b, 0xf0, 0x33, 0xf2, + 0xec, 0x9f, 0x92, 0x4f, 0x1f, 0x27, 0x5f, 0x38, 0x9e, 0xaf, 0x46, 0xf7, + 0x90, 0x4f, 0xce, 0x1f, 0x4d, 0xf9, 0x38, 0x17, 0xb5, 0xed, 0x21, 0x9c, + 0x1e, 0xf5, 0xe3, 0xf6, 0x5d, 0x91, 0x3d, 0xc7, 0xd5, 0x46, 0xbc, 0x3f, + 0x5a, 0x8d, 0x95, 0x43, 0x7e, 0xf6, 0xcd, 0xc1, 0x0e, 0xe2, 0xff, 0xbb, + 0x7c, 0xd6, 0xb9, 0x0b, 0x4a, 0x7e, 0xc9, 0x02, 0xe6, 0x04, 0x3a, 0xeb, + 0xd7, 0xe0, 0xd6, 0x21, 0xe1, 0x81, 0x2a, 0xde, 0x1e, 0x55, 0xf0, 0x56, + 0xce, 0xc0, 0x32, 0xb6, 0xd7, 0x97, 0x79, 0xd6, 0xf1, 0xd3, 0xcf, 0xd7, + 0xe6, 0x0d, 0xdc, 0x9b, 0xd3, 0x19, 0x53, 0x7e, 0xe2, 0x78, 0xf4, 0x76, + 0xfc, 0x64, 0xa7, 0x7e, 0xf4, 0x75, 0x4f, 0x74, 0x6a, 0x89, 0xa7, 0x1d, + 0xaf, 0xed, 0x6f, 0xc7, 0xf7, 0x06, 0x97, 0xe2, 0x9a, 0xf6, 0x24, 0xce, + 0x2c, 0x69, 0xc7, 0xab, 0x7b, 0x75, 0x3c, 0x92, 0xe9, 0x80, 0x36, 0x31, + 0x45, 0xfe, 0x9b, 0x40, 0xeb, 0x84, 0x09, 0x7d, 0xd0, 0xd9, 0x5c, 0x63, + 0x6e, 0xc6, 0xa3, 0x86, 0x89, 0x45, 0x7b, 0x45, 0x0f, 0x8e, 0xb3, 0x6e, + 0x89, 0x89, 0x17, 0xb2, 0x3a, 0xfd, 0xd4, 0xa4, 0x1e, 0x74, 0x3c, 0x9e, + 0x31, 0x11, 0x7d, 0x4c, 0x9f, 0xde, 0xc7, 0xef, 0x4b, 0xf7, 0x75, 0xa0, + 0x87, 0xed, 0xdb, 0xc4, 0xeb, 0x3d, 0x13, 0x6d, 0x1c, 0xb3, 0xc1, 0xf1, + 0x37, 0x5b, 0x3f, 0x53, 0x3a, 0x91, 0x9d, 0xe8, 0x22, 0x9f, 0xdd, 0x4c, + 0x1e, 0xdb, 0xe5, 0xee, 0xb9, 0x6f, 0xcd, 0x18, 0xb8, 0x35, 0xdd, 0x85, + 0x27, 0x6d, 0x39, 0x3b, 0xaf, 0x27, 0xae, 0x55, 0xe4, 0x1d, 0xdd, 0x2e, + 0x8c, 0x51, 0x27, 0xcb, 0x86, 0x56, 0xba, 0xe7, 0x9d, 0x96, 0xef, 0xd2, + 0xf1, 0x44, 0xe6, 0x13, 0x38, 0x39, 0x6e, 0xa0, 0x3b, 0x2d, 0xfa, 0x96, + 0xf3, 0x9b, 0x29, 0x1c, 0x61, 0x6c, 0xf9, 0xd9, 0x50, 0xf2, 0x9f, 0x38, + 0xcd, 0xc7, 0x54, 0xc8, 0x7a, 0x89, 0x8a, 0xab, 0xdb, 0xe5, 0x0c, 0xae, + 0x87, 0xa8, 0x16, 0xb1, 0xea, 0x54, 0x4b, 0xe3, 0x7d, 0xcb, 0xab, 0x6e, + 0xc2, 0x67, 0x87, 0xbc, 0xcc, 0x19, 0x54, 0xe6, 0x3a, 0xd6, 0x06, 0xda, + 0x86, 0x55, 0xab, 0x16, 0xe7, 0xcd, 0xdd, 0x63, 0xd0, 0x3d, 0xd8, 0x61, + 0x34, 0x77, 0xd7, 0xb0, 0xde, 0x8a, 0x78, 0x24, 0x59, 0xa5, 0x76, 0x30, + 0x0f, 0x7d, 0x18, 0xeb, 0x76, 0x3d, 0x8c, 0xb5, 0xbc, 0x36, 0xec, 0x72, + 0x36, 0xdf, 0x6c, 0x28, 0x78, 0x4e, 0x77, 0x36, 0x6f, 0x36, 0x74, 0xce, + 0xad, 0xcc, 0xeb, 0xc3, 0xd8, 0x38, 0xf6, 0x30, 0x1e, 0xa2, 0x7d, 0x35, + 0xd0, 0x8f, 0x57, 0xa5, 0x9d, 0xcd, 0xd7, 0xb4, 0xc7, 0xf0, 0x73, 0x37, + 0xbf, 0x11, 0x7b, 0x3d, 0xe3, 0xe6, 0xdc, 0x39, 0xd5, 0xb5, 0xdd, 0xa0, + 0x7c, 0xb6, 0xd4, 0x25, 0xc1, 0x72, 0x6c, 0xf9, 0x05, 0xe5, 0xfe, 0x72, + 0x57, 0x1d, 0x1e, 0x6b, 0x90, 0xf8, 0xe1, 0xb7, 0xaa, 0x4c, 0x28, 0xfa, + 0x12, 0xe6, 0x71, 0x8f, 0x1d, 0xc1, 0x76, 0xf2, 0xc2, 0x50, 0x5c, 0x72, + 0xec, 0x56, 0x63, 0x8b, 0x7a, 0x23, 0xb1, 0x5d, 0xc1, 0xa3, 0x0b, 0xb3, + 0x18, 0xa0, 0xaf, 0xee, 0x58, 0x18, 0x49, 0x0d, 0xc0, 0x74, 0x76, 0xcc, + 0xe9, 0xff, 0x23, 0xde, 0xa1, 0x2d, 0xef, 0x4b, 0xca, 0x7b, 0xb4, 0x0f, + 0x63, 0xf3, 0x2e, 0x99, 0xff, 0x87, 0xf1, 0x45, 0xf6, 0x7f, 0xe3, 0xd0, + 0xc3, 0xf8, 0x1c, 0x6d, 0xa7, 0x7e, 0xf1, 0xa1, 0x2f, 0xd6, 0xa3, 0x25, + 0x5b, 0x87, 0xa9, 0xfb, 0x1b, 0xe4, 0xbc, 0x2d, 0x31, 0x71, 0x40, 0x79, + 0x18, 0xf7, 0x8c, 0xd4, 0xd2, 0x17, 0xdd, 0x31, 0x10, 0x8b, 0xcb, 0xf1, + 0x2a, 0x8c, 0x75, 0xf9, 0xa6, 0x12, 0xae, 0x87, 0xb0, 0xd6, 0x3e, 0xe0, + 0xfa, 0x7e, 0x85, 0xb9, 0x9a, 0x7e, 0xdf, 0x4d, 0xbf, 0x5f, 0x49, 0xbf, + 0xef, 0xa2, 0xdf, 0x77, 0xd2, 0xef, 0x93, 0xf4, 0x7b, 0x93, 0x7e, 0x9f, + 0xa0, 0xdf, 0x77, 0xd0, 0xef, 0x0d, 0xd9, 0x3b, 0x54, 0x8e, 0x76, 0x1c, + 0x81, 0x6f, 0xd0, 0x4f, 0x1b, 0x2a, 0xbe, 0xd3, 0xb8, 0x9f, 0xf8, 0x73, + 0xc2, 0x58, 0x14, 0xbe, 0x89, 0xaa, 0x1a, 0x25, 0x46, 0xe4, 0xc6, 0xff, + 0xce, 0x7d, 0xff, 0x2d, 0x47, 0xdc, 0x7f, 0x91, 0xfa, 0x58, 0x11, 0x6f, + 0x36, 0x9e, 0x64, 0x0c, 0xfb, 0xa1, 0xde, 0xda, 0x1f, 0x62, 0x99, 0xaf, + 0x65, 0x5a, 0xb3, 0xb3, 0xa1, 0x5b, 0xed, 0xea, 0x56, 0x60, 0x55, 0x88, + 0x63, 0x96, 0x73, 0xdd, 0xab, 0xf0, 0xc5, 0xe1, 0x6e, 0xfc, 0xcf, 0xe1, + 0x20, 0x75, 0xd1, 0x3c, 0x75, 0xa3, 0x07, 0xdf, 0x0c, 0xc3, 0x13, 0x9a, + 0x0b, 0x7c, 0xd0, 0x88, 0x45, 0x07, 0xe4, 0x5d, 0xec, 0x5c, 0xa3, 0xa7, + 0x6d, 0x3e, 0xc4, 0x46, 0x40, 0xa4, 0xf6, 0x30, 0xd3, 0x5c, 0xe4, 0xbe, + 0xaf, 0x99, 0x5c, 0x2d, 0x98, 0x5e, 0x85, 0xad, 0x31, 0x17, 0x67, 0x9f, + 0x96, 0xf3, 0xe9, 0x8d, 0xc4, 0xa3, 0x80, 0xd9, 0x85, 0x6d, 0x03, 0xd6, + 0x5d, 0x8d, 0x58, 0x89, 0xfe, 0x81, 0xa2, 0x0e, 0xee, 0x8f, 0x13, 0xf2, + 0xcc, 0xa8, 0xb6, 0x48, 0x81, 0x77, 0x43, 0x47, 0x02, 0xf7, 0xe6, 0x6d, + 0x64, 0x39, 0xc6, 0xf5, 0xf4, 0xb3, 0x75, 0xbf, 0xff, 0x3d, 0x7c, 0x7c, + 0xce, 0xd6, 0x68, 0xff, 0xe7, 0x9c, 0x5c, 0xfd, 0xa2, 0x6c, 0x23, 0xf4, + 0x8d, 0x77, 0xa8, 0xd7, 0x32, 0x67, 0x8e, 0x1c, 0xe4, 0x23, 0x6b, 0x8e, + 0x7b, 0x8e, 0xce, 0x8f, 0x05, 0x43, 0x50, 0x46, 0xd3, 0xf2, 0xce, 0xda, + 0x66, 0xfc, 0x5f, 0xc6, 0x37, 0x5c, 0x5b, 0x9a, 0xf2, 0xc8, 0x99, 0x16, + 0xb9, 0xef, 0x2c, 0x3d, 0xbb, 0x38, 0x12, 0xd3, 0x3c, 0x3f, 0xa8, 0x93, + 0xfd, 0x8b, 0xaf, 0x33, 0xce, 0x86, 0x87, 0x96, 0x42, 0x5d, 0xec, 0xc7, + 0x9d, 0x6d, 0xb3, 0x90, 0x5a, 0x25, 0x3c, 0xd4, 0xdd, 0x5f, 0xa1, 0x3e, + 0xff, 0x02, 0xf7, 0x19, 0x5f, 0xc1, 0xf1, 0x90, 0x8d, 0x21, 0xe2, 0xd7, + 0x3a, 0xe3, 0x76, 0xc5, 0xe2, 0x67, 0xe6, 0x44, 0x58, 0x6f, 0x30, 0xd7, + 0xfa, 0x54, 0x03, 0x1a, 0x76, 0x49, 0x79, 0x91, 0x7b, 0xc6, 0x95, 0xb7, + 0x3f, 0x23, 0x9f, 0x8b, 0x36, 0x3b, 0xe5, 0xf9, 0x24, 0xd0, 0x20, 0xe7, + 0x84, 0x15, 0xbc, 0xbd, 0xd0, 0xc6, 0x63, 0x19, 0x7c, 0xb3, 0x0a, 0xcd, + 0xb9, 0x41, 0xd5, 0xf3, 0xcd, 0xb9, 0x58, 0x64, 0xfc, 0x5a, 0x95, 0xf9, + 0x48, 0xe2, 0xbe, 0x85, 0x72, 0x1e, 0x4d, 0x3f, 0xf3, 0x3d, 0xfa, 0xd6, + 0x71, 0xd8, 0xd8, 0x3e, 0xf9, 0x92, 0x33, 0x35, 0x37, 0x84, 0xa7, 0x26, + 0xa5, 0x6e, 0x37, 0x4e, 0x70, 0x4e, 0xbe, 0xec, 0xee, 0xe7, 0x45, 0x92, + 0x27, 0x54, 0x79, 0xe7, 0xb0, 0x1b, 0x6f, 0x8d, 0x1a, 0xd8, 0xc7, 0x1c, + 0xea, 0x57, 0xc3, 0xab, 0xf0, 0xeb, 0xe1, 0x66, 0xed, 0x6f, 0x14, 0x39, + 0x03, 0xff, 0x71, 0xfc, 0xa8, 0x21, 0x88, 0x83, 0xb4, 0xa1, 0x69, 0xbb, + 0x0b, 0x6f, 0xdb, 0x56, 0x64, 0x2e, 0x22, 0x7b, 0xbc, 0x9e, 0xc8, 0x01, + 0x79, 0xcf, 0x79, 0x9d, 0x1a, 0x39, 0xb8, 0x44, 0x89, 0x58, 0x6f, 0xa8, + 0x2b, 0xf1, 0x8b, 0x7c, 0x17, 0xce, 0xe4, 0x67, 0xda, 0xc2, 0x66, 0x07, + 0x8d, 0x62, 0x07, 0x62, 0x0f, 0xb4, 0x45, 0xe6, 0x8a, 0xdf, 0x26, 0x8f, + 0xee, 0xfd, 0x18, 0xed, 0x31, 0x43, 0x7b, 0xcc, 0xd0, 0x1e, 0x89, 0x49, + 0xcf, 0x10, 0xab, 0xbe, 0x96, 0xa1, 0x3d, 0xd2, 0x7f, 0xbe, 0x42, 0xff, + 0x29, 0x72, 0xe5, 0x1e, 0x77, 0x4d, 0xff, 0x15, 0xc6, 0x44, 0xfb, 0x31, + 0x79, 0x7f, 0xb8, 0x79, 0x7d, 0x01, 0x91, 0x9e, 0x01, 0x65, 0x5d, 0xbd, + 0xbc, 0xcf, 0xf1, 0xf9, 0xa8, 0xf8, 0x80, 0xbc, 0x7b, 0x46, 0xbf, 0x1a, + 0x3f, 0x55, 0x27, 0xef, 0xb2, 0xee, 0xdf, 0xfd, 0x51, 0x3a, 0xfb, 0x7b, + 0xf6, 0x43, 0xf4, 0xf5, 0xc7, 0x8e, 0x5d, 0x74, 0xf9, 0x4f, 0xce, 0x8f, + 0x1a, 0x65, 0xfc, 0xab, 0xf1, 0xf3, 0xe1, 0x4e, 0x9c, 0x65, 0xfc, 0xfd, + 0x74, 0xfb, 0x94, 0x45, 0x9b, 0xdd, 0x68, 0x78, 0x4c, 0x4c, 0xe6, 0x3b, + 0x71, 0xda, 0x36, 0x91, 0xb7, 0x9b, 0xd7, 0x7f, 0x57, 0x79, 0x53, 0xcd, + 0xcd, 0x2b, 0xf2, 0xf9, 0xdf, 0x90, 0x5f, 0x1e, 0x6a, 0x91, 0xf7, 0x5d, + 0x13, 0x18, 0xc9, 0x8b, 0x9d, 0x06, 0x71, 0xd3, 0x12, 0x43, 0xde, 0x11, + 0xfb, 0xbd, 0x7f, 0xf7, 0xd9, 0xb2, 0x97, 0x72, 0xce, 0x99, 0x0a, 0xfa, + 0xad, 0x20, 0x7d, 0xd8, 0xb3, 0x4b, 0x7e, 0x07, 0x40, 0xfc, 0x59, 0xc1, + 0x67, 0x8c, 0x29, 0xad, 0x06, 0x91, 0xa7, 0x77, 0x33, 0x81, 0x7a, 0x2d, + 0x2d, 0x67, 0x88, 0x3b, 0xf1, 0x26, 0xcb, 0x57, 0xd1, 0x2f, 0x5e, 0xcb, + 0x7b, 0xbd, 0x3f, 0x4a, 0xcb, 0x7b, 0xec, 0x2b, 0xf1, 0xa3, 0xfc, 0xcb, + 0xea, 0x2f, 0x82, 0x06, 0xde, 0x2e, 0xac, 0xc2, 0xfc, 0x5d, 0xb2, 0xbe, + 0x90, 0xc4, 0x7e, 0x3b, 0x72, 0xf4, 0x59, 0xac, 0xc2, 0xbc, 0xb1, 0xd5, + 0xcc, 0xa3, 0x15, 0xbc, 0x17, 0x5d, 0x8d, 0x00, 0x3f, 0xd7, 0xee, 0x72, + 0x9c, 0xc3, 0xf1, 0x3a, 0x67, 0xfb, 0x6a, 0x99, 0x3b, 0xc1, 0x93, 0x65, + 0xf5, 0xa8, 0x5d, 0x0d, 0x8c, 0x09, 0x57, 0xd1, 0x71, 0xeb, 0xc0, 0x2a, + 0x5c, 0xb1, 0xab, 0x39, 0x76, 0x2b, 0x9a, 0xb3, 0x47, 0x3c, 0xab, 0xd0, + 0x30, 0x76, 0x2f, 0xe7, 0x40, 0xca, 0x6a, 0xb4, 0x3f, 0x0b, 0x95, 0xe4, + 0x84, 0x9d, 0xe9, 0x9f, 0x3a, 0xf3, 0x4d, 0x77, 0x1f, 0x0e, 0xeb, 0x0a, + 0x3a, 0xe3, 0x5d, 0x35, 0x52, 0x23, 0x4f, 0x38, 0x75, 0xa6, 0x17, 0x6b, + 0x0b, 0x6d, 0xb8, 0x69, 0xc8, 0x71, 0x4e, 0x2f, 0x49, 0x22, 0x60, 0x06, + 0x88, 0x61, 0x01, 0x3c, 0x94, 0xae, 0xe1, 0x7f, 0x07, 0x15, 0x8c, 0xc9, + 0x2d, 0xaa, 0xbe, 0x7e, 0x9e, 0x47, 0xef, 0x29, 0x28, 0x12, 0xf7, 0x03, + 0x78, 0x80, 0xf1, 0x79, 0x45, 0x3a, 0x8c, 0x54, 0xc1, 0x71, 0x5e, 0xed, + 0x08, 0xe1, 0x7e, 0xd6, 0xef, 0x4a, 0xf7, 0xa3, 0x97, 0x76, 0x91, 0x1a, + 0xd3, 0xb5, 0x20, 0xe3, 0xfd, 0xba, 0x82, 0x9f, 0x31, 0xac, 0x01, 0xb7, + 0xec, 0xd2, 0xf0, 0x50, 0x21, 0xc0, 0xf8, 0xe6, 0x2c, 0x3d, 0x69, 0x58, + 0x57, 0x7a, 0xa0, 0x63, 0x63, 0x21, 0x84, 0x95, 0xe9, 0xc8, 0xb4, 0xbc, + 0x47, 0x7d, 0xd6, 0x88, 0xe1, 0xc1, 0x42, 0x18, 0xb7, 0xa5, 0x0f, 0x3d, + 0x34, 0x1f, 0xd6, 0xff, 0x98, 0x87, 0x36, 0x7c, 0xa6, 0xd0, 0x44, 0xf9, + 0x91, 0xf5, 0xaf, 0x28, 0x4d, 0xf8, 0xec, 0x98, 0x41, 0xf9, 0x2a, 0x6e, + 0xa5, 0x9c, 0x9b, 0xd3, 0x57, 0xe0, 0x81, 0xb1, 0x0e, 0xdc, 0x5b, 0x58, + 0x8c, 0xe5, 0x8c, 0x4f, 0x1b, 0x98, 0x1b, 0xe2, 0xbf, 0x00, 0xb7, 0x0d, + 0x89, 0xee, 0xa1, 0xbc, 0xda, 0x31, 0xc5, 0x7c, 0xdc, 0x00, 0x0d, 0x91, + 0xf7, 0x74, 0x72, 0x30, 0x03, 0xb7, 0xed, 0x5d, 0xec, 0xee, 0xc9, 0x37, + 0xc7, 0x2b, 0x91, 0xea, 0x56, 0xd0, 0x39, 0x24, 0x71, 0x56, 0xb8, 0x8d, + 0xc1, 0xb8, 0x1a, 0x65, 0x1b, 0x06, 0xe3, 0x6a, 0xf1, 0x7e, 0x6f, 0x46, + 0xd6, 0x2e, 0x7e, 0x42, 0xbe, 0x14, 0x47, 0xa7, 0x1b, 0xa3, 0xfd, 0xe4, + 0xd7, 0x16, 0xbc, 0x8c, 0xdd, 0x71, 0xda, 0xf8, 0xd2, 0x76, 0x89, 0xd5, + 0x3a, 0x06, 0xe8, 0x0f, 0x93, 0x83, 0xfa, 0x86, 0x69, 0xc5, 0x44, 0x61, + 0xaf, 0xc4, 0xc4, 0x10, 0x1e, 0x4c, 0x9b, 0x38, 0x29, 0xe7, 0xf8, 0xaf, + 0x4a, 0xae, 0xa8, 0x81, 0x6e, 0x3c, 0x80, 0xa8, 0x75, 0x8c, 0xb1, 0xfd, + 0x4c, 0xae, 0x01, 0x37, 0xed, 0x92, 0x32, 0xed, 0x78, 0x7d, 0xd4, 0x8b, + 0x9b, 0xd2, 0x9b, 0xf0, 0x44, 0xd6, 0x83, 0x11, 0xa3, 0xb9, 0x5f, 0x65, + 0xfc, 0xbc, 0xbe, 0x3d, 0x12, 0xfc, 0x3a, 0xb9, 0xea, 0xf4, 0x62, 0x46, + 0xe5, 0xb9, 0x1d, 0xe8, 0x64, 0xbf, 0x3a, 0x75, 0xf1, 0x49, 0x0b, 0xf7, + 0x76, 0x6c, 0xc2, 0xb1, 0xac, 0x6e, 0x3d, 0x29, 0xeb, 0x0c, 0xed, 0x7c, + 0x3e, 0xc7, 0x8b, 0x3e, 0x5d, 0x38, 0xad, 0x4e, 0xdf, 0x22, 0xeb, 0xd4, + 0x3b, 0x70, 0x92, 0xf6, 0xda, 0x9f, 0x5b, 0xca, 0xd8, 0x2f, 0x31, 0xdf, + 0x6f, 0x85, 0x59, 0xaf, 0xee, 0x3a, 0x05, 0x27, 0xf6, 0x09, 0xc7, 0x5a, + 0x8a, 0xbb, 0xa8, 0xa7, 0xce, 0xb4, 0x8a, 0xeb, 0xc7, 0xd6, 0xe0, 0xf4, + 0xce, 0x22, 0xe7, 0x7a, 0x35, 0x6e, 0x7d, 0x86, 0x9c, 0xab, 0x67, 0x16, + 0x39, 0x17, 0xb9, 0x5c, 0xec, 0x41, 0xc5, 0x8b, 0x68, 0x21, 0x41, 0x5e, + 0x21, 0xfc, 0x22, 0x8c, 0xa7, 0xf2, 0x1d, 0xb8, 0x25, 0xdd, 0x84, 0x71, + 0xf2, 0xad, 0x1c, 0xf1, 0x22, 0x97, 0x67, 0x5c, 0x19, 0x6d, 0xe4, 0xa5, + 0xf1, 0x5a, 0xc0, 0x4b, 0x77, 0xef, 0xad, 0xa5, 0x2d, 0x27, 0xbb, 0x25, + 0x4f, 0x23, 0xff, 0xcd, 0x4b, 0xac, 0x56, 0x98, 0xb7, 0xfe, 0xaf, 0x7a, + 0xc9, 0x4d, 0x83, 0xba, 0x82, 0xaf, 0x65, 0x35, 0xfc, 0x55, 0xfb, 0x76, + 0x25, 0xd9, 0xe0, 0xbe, 0x83, 0x4a, 0xdf, 0xb6, 0x70, 0x92, 0x63, 0xba, + 0x37, 0x2b, 0x76, 0x49, 0x19, 0xcc, 0xd1, 0x8f, 0x19, 0xf5, 0xd0, 0xea, + 0x35, 0x39, 0xd7, 0xc4, 0xd8, 0xc1, 0xf8, 0x6b, 0xa7, 0xc8, 0xa3, 0x5a, + 0xbb, 0x5b, 0x55, 0x8f, 0xbc, 0x9f, 0x67, 0x68, 0xaa, 0xf8, 0x58, 0x0a, + 0x15, 0x69, 0xbf, 0x55, 0x27, 0xf5, 0x97, 0x6c, 0x60, 0x3c, 0x68, 0x5d, + 0xff, 0xb2, 0xf0, 0xfb, 0x39, 0x11, 0x6d, 0x0a, 0x1b, 0xb0, 0xce, 0xd6, + 0x19, 0x03, 0xd7, 0x38, 0xbd, 0x9c, 0x87, 0x51, 0x7b, 0x03, 0xee, 0xb2, + 0x5b, 0xa7, 0x1e, 0xa7, 0x6d, 0xe1, 0xce, 0x0d, 0xe8, 0xe4, 0xb3, 0x91, + 0x4c, 0xf3, 0x74, 0x2f, 0x75, 0x7d, 0x7c, 0x76, 0xcc, 0x5d, 0xf7, 0x97, + 0x33, 0xe4, 0xa3, 0xe4, 0xd7, 0x5f, 0xcd, 0xb4, 0x26, 0x87, 0xd4, 0x1e, + 0x05, 0x73, 0x24, 0x97, 0x4c, 0x90, 0x53, 0x05, 0xf0, 0x99, 0xb4, 0x45, + 0x1f, 0x00, 0x6d, 0xae, 0x83, 0x79, 0xc5, 0x13, 0x4e, 0xbd, 0x19, 0x35, + 0x44, 0x3f, 0xeb, 0x0b, 0x4b, 0xf1, 0x14, 0x63, 0x6f, 0xf3, 0xb5, 0x7a, + 0xf0, 0x39, 0x68, 0xf0, 0x99, 0x3f, 0x75, 0x1a, 0xcc, 0x1a, 0x3c, 0x30, + 0x12, 0x4d, 0xdc, 0xc4, 0x38, 0xdb, 0x79, 0xad, 0x7e, 0xf4, 0x14, 0x63, + 0xe0, 0x7c, 0xd3, 0x96, 0xf3, 0x26, 0xe4, 0x3b, 0x01, 0xd7, 0xce, 0x4f, + 0xdb, 0xe2, 0x27, 0x3a, 0x71, 0x33, 0x84, 0xcf, 0xd1, 0xce, 0xdf, 0xb7, + 0x63, 0x98, 0x24, 0xdf, 0xf8, 0x2c, 0xfd, 0xe3, 0x8c, 0x1d, 0x49, 0x5d, + 0xa3, 0xea, 0xd8, 0x40, 0xff, 0x78, 0xd7, 0x4e, 0xd0, 0x77, 0x3e, 0xc6, + 0xab, 0x8d, 0xfe, 0x10, 0x63, 0x1d, 0x8d, 0x7e, 0x10, 0x72, 0xcf, 0x95, + 0x8e, 0x65, 0x9a, 0xbb, 0x1f, 0x42, 0x73, 0xec, 0x66, 0xa5, 0x8e, 0x79, + 0x6a, 0x10, 0xf7, 0x14, 0x6e, 0xc0, 0x89, 0x6c, 0x64, 0x9a, 0x39, 0xf9, + 0xc6, 0xa5, 0x0a, 0xee, 0x20, 0x67, 0x5b, 0x5f, 0xad, 0xb4, 0x4e, 0x3d, + 0xa5, 0x44, 0x68, 0x93, 0x8c, 0x97, 0xf4, 0xcf, 0xcf, 0xb2, 0xcc, 0x99, + 0x6c, 0x35, 0x36, 0x8c, 0xd8, 0xe8, 0xcf, 0x54, 0xa0, 0x6a, 0xa7, 0x1f, + 0xf7, 0x8f, 0xe9, 0xc8, 0x64, 0x64, 0x1d, 0xd9, 0x6f, 0xd5, 0x12, 0x37, + 0x46, 0x89, 0x0d, 0x2f, 0x2d, 0x01, 0xa6, 0xf7, 0xae, 0xc1, 0x81, 0x9d, + 0x3a, 0xe3, 0x5d, 0xd1, 0x3e, 0x82, 0x71, 0x97, 0x93, 0xa7, 0x84, 0x93, + 0x57, 0x99, 0x12, 0xfb, 0xa2, 0x3d, 0x8f, 0x50, 0x07, 0xb7, 0x15, 0xc4, + 0xee, 0x12, 0x9c, 0xa3, 0x30, 0x06, 0x69, 0x23, 0xfb, 0xec, 0x26, 0xe6, + 0xe6, 0x01, 0x58, 0xb4, 0x11, 0x4b, 0xde, 0x53, 0xa5, 0x8d, 0x58, 0xb4, + 0x11, 0x8b, 0x36, 0x62, 0xd1, 0x46, 0xac, 0xfc, 0x52, 0xe6, 0x4c, 0x3a, + 0xc6, 0xd9, 0xe6, 0xb6, 0x51, 0x72, 0xf7, 0xa0, 0xd8, 0x4a, 0x0c, 0x5f, + 0xcf, 0xf4, 0x2b, 0xda, 0x9d, 0x37, 0x60, 0x24, 0x7b, 0x23, 0x2f, 0x05, + 0xb7, 0xd2, 0x56, 0x1e, 0xcd, 0x89, 0xed, 0xe9, 0xee, 0xef, 0xd3, 0x3c, + 0x9b, 0xdf, 0x33, 0x1b, 0xd5, 0xe2, 0x03, 0x8c, 0x45, 0xee, 0x7d, 0x39, + 0x73, 0xec, 0xc7, 0x68, 0xfe, 0x82, 0x5f, 0x7c, 0x4f, 0xce, 0xab, 0xb4, + 0xcb, 0x6f, 0xc5, 0x74, 0x30, 0x0f, 0x90, 0x73, 0xee, 0x32, 0x4e, 0x19, + 0x57, 0x71, 0x4c, 0x55, 0x83, 0x9b, 0xf0, 0xf5, 0x41, 0x9d, 0xb1, 0xca, + 0xc0, 0x93, 0x39, 0x89, 0xe5, 0xe2, 0xdf, 0x32, 0x0f, 0xe2, 0xeb, 0x1e, + 0xd4, 0xb4, 0x7b, 0x11, 0x70, 0xfd, 0xbc, 0x39, 0xbc, 0x43, 0xb1, 0xe9, + 0x3b, 0xba, 0x9c, 0x03, 0x9d, 0x0a, 0xeb, 0x0d, 0x38, 0xbd, 0xbb, 0x1d, + 0xff, 0x6d, 0xa7, 0x87, 0x3c, 0xc0, 0x59, 0xfa, 0x52, 0x5c, 0x4f, 0x4e, + 0x2b, 0xd1, 0xd8, 0x2c, 0xa5, 0x1d, 0xf7, 0x90, 0xfb, 0x6f, 0x18, 0x8c, + 0x74, 0x33, 0x66, 0x1b, 0xb7, 0x28, 0x4b, 0x51, 0xc5, 0x1c, 0xa0, 0x8d, + 0x39, 0xc0, 0x83, 0xc4, 0x80, 0xaf, 0x66, 0xbc, 0x68, 0x59, 0x2c, 0xbf, + 0x4d, 0xa6, 0xbb, 0x6b, 0x3b, 0x2f, 0x90, 0xa3, 0xce, 0x37, 0x3b, 0xe4, + 0x2c, 0x8e, 0x72, 0xf6, 0xba, 0x29, 0x24, 0x28, 0x7f, 0xcc, 0xcd, 0x2f, + 0x12, 0x38, 0x98, 0x27, 0x6e, 0x70, 0xdc, 0xaf, 0xb4, 0xfd, 0x84, 0xf9, + 0xb0, 0x70, 0x7b, 0x13, 0x13, 0x39, 0x97, 0xff, 0x47, 0xea, 0x88, 0x19, + 0xd9, 0x41, 0xbd, 0xcb, 0xaf, 0x9a, 0x78, 0x64, 0xaf, 0xf8, 0xb0, 0x89, + 0xf6, 0x21, 0x3d, 0x7c, 0x9b, 0x1a, 0x0d, 0xae, 0xe3, 0xb3, 0x05, 0x9c, + 0xcf, 0xc7, 0x33, 0x32, 0x8f, 0x1a, 0x5a, 0x18, 0x9b, 0xdf, 0x9c, 0xd0, + 0xb1, 0x88, 0x71, 0xfa, 0x9d, 0x89, 0x18, 0x96, 0x32, 0x66, 0x3b, 0xcc, + 0x1f, 0x12, 0x19, 0xf1, 0x45, 0xf2, 0x81, 0x09, 0x8d, 0x71, 0x56, 0xd6, + 0x87, 0x9e, 0xc0, 0xd8, 0x6a, 0x0d, 0xfb, 0xdc, 0xf3, 0x7c, 0x7e, 0xab, + 0x81, 0x58, 0xd9, 0x39, 0xe0, 0xc7, 0xa7, 0x87, 0x36, 0xe3, 0xf5, 0xc5, + 0xc2, 0x95, 0xd6, 0x38, 0xa2, 0x9f, 0xc7, 0x29, 0x73, 0x8c, 0xbc, 0x78, + 0x94, 0x79, 0xd7, 0xc2, 0x7d, 0x6b, 0xf0, 0xc9, 0x5d, 0x17, 0xf2, 0xb4, + 0x33, 0x71, 0xeb, 0x6e, 0xda, 0xc4, 0xfa, 0x00, 0x6d, 0xa2, 0x96, 0x36, + 0x61, 0x67, 0xa2, 0xc9, 0x02, 0x6d, 0x22, 0x46, 0xdc, 0xc8, 0x0e, 0x48, + 0x39, 0xf7, 0x9d, 0x99, 0xbb, 0xe4, 0xdd, 0x65, 0x83, 0xbe, 0xb3, 0x75, + 0xc0, 0xd9, 0xec, 0x65, 0xbc, 0x79, 0xa4, 0xa3, 0x89, 0xd8, 0x72, 0x23, + 0xf6, 0x0c, 0x36, 0xa1, 0x85, 0x31, 0x63, 0x61, 0x1a, 0x77, 0x84, 0xa1, + 0xce, 0x0f, 0x23, 0xb2, 0xe1, 0x1d, 0x44, 0xa7, 0xef, 0x56, 0x5a, 0x8f, + 0xbe, 0xa8, 0x44, 0x36, 0xfe, 0x84, 0x36, 0x7c, 0x56, 0x91, 0xb6, 0x9b, + 0x70, 0x35, 0xfd, 0xe4, 0x2a, 0xfa, 0x84, 0xc6, 0x5c, 0x52, 0x63, 0xdd, + 0xfe, 0x41, 0x1f, 0xe6, 0x33, 0xd7, 0x93, 0xb3, 0xca, 0xb1, 0x31, 0x2f, + 0xb2, 0x3b, 0xf5, 0xa9, 0x47, 0xd0, 0x08, 0x63, 0xec, 0x46, 0x6c, 0x1d, + 0xd4, 0x10, 0xe5, 0xbd, 0xbe, 0x9d, 0x0b, 0xd0, 0x4c, 0xfb, 0xd6, 0xe8, + 0xa7, 0xbd, 0x83, 0x2a, 0x16, 0x8c, 0xdd, 0x80, 0x1d, 0x83, 0x0a, 0xee, + 0x8b, 0x2a, 0x68, 0x19, 0x91, 0x1c, 0x2c, 0x86, 0xa7, 0x32, 0xc2, 0x15, + 0xa1, 0xb4, 0x5c, 0x4b, 0x8e, 0x4c, 0xee, 0xf9, 0x93, 0x9c, 0xcc, 0xb9, + 0xe8, 0x53, 0x7e, 0x53, 0xa6, 0x1d, 0x9f, 0xdb, 0xd9, 0x80, 0xab, 0x76, + 0xeb, 0xd6, 0x69, 0xc5, 0x59, 0x7a, 0x80, 0x7c, 0xde, 0xaf, 0x16, 0xe7, + 0xfc, 0xc1, 0xc1, 0x67, 0x19, 0x2f, 0x7e, 0xe2, 0x04, 0xf5, 0xa5, 0xe8, + 0x8b, 0x27, 0xb1, 0xb6, 0xa3, 0x1d, 0x6b, 0xf7, 0x8a, 0xbe, 0x1c, 0xe6, + 0x87, 0xcc, 0xfd, 0x26, 0xa7, 0xf0, 0x0e, 0xfd, 0x77, 0x11, 0x39, 0xed, + 0x52, 0xc6, 0x89, 0x37, 0x16, 0x9b, 0xd4, 0x9f, 0xee, 0x9e, 0xf5, 0x9b, + 0x67, 0x9a, 0xa8, 0x1d, 0xd4, 0x19, 0x67, 0x4c, 0xcc, 0xda, 0x2b, 0xed, + 0x99, 0xb8, 0x67, 0x50, 0x4f, 0x3d, 0xcd, 0xb9, 0x14, 0xbb, 0x11, 0xcc, + 0xae, 0x61, 0xec, 0x3f, 0x39, 0x29, 0x38, 0xd5, 0x89, 0x13, 0xcc, 0x03, + 0xde, 0x7c, 0x2c, 0xda, 0xfd, 0x33, 0xe6, 0x74, 0xef, 0x50, 0x46, 0x96, + 0xfd, 0x1b, 0xe0, 0xbc, 0x56, 0xa4, 0xf5, 0x8d, 0xff, 0x8c, 0x28, 0xfd, + 0xbb, 0x0b, 0xb5, 0xd4, 0xc9, 0x81, 0xc1, 0x95, 0xf0, 0xd3, 0x16, 0x1e, + 0xc9, 0x88, 0xdd, 0x10, 0xbf, 0x77, 0x7e, 0x02, 0x5b, 0xf7, 0x17, 0xf3, + 0xbc, 0x7b, 0x06, 0x36, 0xd1, 0xc6, 0x85, 0xb3, 0xc7, 0x68, 0xef, 0x98, + 0xe7, 0x43, 0xb2, 0x9e, 0x18, 0x91, 0x58, 0x4e, 0xcc, 0x7c, 0xd4, 0x20, + 0xae, 0xd6, 0x47, 0xc2, 0x2d, 0xaa, 0x95, 0x60, 0x5e, 0x17, 0xbe, 0x0f, + 0xd2, 0xbe, 0x85, 0x75, 0x4b, 0x36, 0x61, 0x4f, 0xd6, 0x8b, 0xaa, 0xc5, + 0x1e, 0xe2, 0xb1, 0x60, 0x94, 0x15, 0x94, 0xe7, 0x6b, 0x21, 0x7e, 0x22, + 0xf3, 0xeb, 0xc1, 0x99, 0x78, 0xf3, 0x86, 0xac, 0xfc, 0x96, 0x05, 0x73, + 0xbe, 0xcf, 0xa2, 0x83, 0x73, 0x2f, 0xfe, 0x98, 0xc0, 0x3d, 0x63, 0xc2, + 0xd5, 0xc8, 0xe7, 0x6c, 0x3f, 0xfe, 0x3a, 0x2b, 0x9c, 0x6e, 0x33, 0xee, + 0x69, 0x2f, 0xe7, 0x6e, 0x62, 0x77, 0xad, 0xd3, 0x1e, 0x34, 0x93, 0x93, + 0xe9, 0xb9, 0xac, 0x1a, 0xb1, 0x52, 0x88, 0xf4, 0xa7, 0x20, 0x71, 0xa2, + 0xd5, 0xe2, 0x0c, 0x53, 0x36, 0xb9, 0xa5, 0xed, 0x41, 0x1d, 0x7d, 0x5c, + 0x7e, 0x44, 0xae, 0x9d, 0xf6, 0xf3, 0xac, 0x5d, 0x0d, 0xcd, 0xb5, 0x75, + 0x2f, 0x96, 0x16, 0x2c, 0xe2, 0xed, 0x52, 0xb4, 0x3d, 0x16, 0xc0, 0x35, + 0xe4, 0x26, 0x57, 0xa7, 0x9f, 0x70, 0x66, 0x11, 0x7b, 0xdb, 0x46, 0xa2, + 0xc1, 0x23, 0xe4, 0x81, 0x07, 0x96, 0xfc, 0xd4, 0xf1, 0x98, 0xae, 0x5f, + 0x68, 0xf4, 0x00, 0xe7, 0x33, 0x1d, 0xfa, 0xd4, 0x0e, 0x04, 0x90, 0x20, + 0x7e, 0x5e, 0x99, 0x69, 0x40, 0xfb, 0xee, 0x7e, 0xce, 0x7f, 0x10, 0x57, + 0xf2, 0xfb, 0x62, 0xc6, 0x37, 0x8d, 0xd8, 0xaa, 0xc9, 0xe7, 0x82, 0xd8, + 0x4b, 0x98, 0x7e, 0xe4, 0x2c, 0xbd, 0xb3, 0xdd, 0xba, 0x63, 0x36, 0xf5, + 0xd5, 0x42, 0x5c, 0x5e, 0x9a, 0x89, 0x6c, 0xbc, 0x59, 0x51, 0xb0, 0xb2, + 0xdd, 0x60, 0xdb, 0x01, 0xc4, 0x32, 0xb2, 0x36, 0x70, 0xe8, 0xa1, 0x3a, + 0x58, 0xad, 0x01, 0xda, 0xe9, 0x11, 0x45, 0xd6, 0x35, 0x44, 0x6f, 0x4d, + 0xb8, 0x8a, 0x7c, 0x44, 0x23, 0x66, 0xc7, 0x0a, 0xa2, 0x43, 0x60, 0x6d, + 0x6e, 0x0d, 0xf6, 0x0c, 0x8b, 0x7f, 0x0a, 0x76, 0x3a, 0x4e, 0xe5, 0xe2, + 0xa8, 0xf1, 0x36, 0x75, 0xf8, 0xc6, 0x84, 0x60, 0x90, 0x82, 0x79, 0xb4, + 0x63, 0x55, 0x97, 0x58, 0x2b, 0xb8, 0x15, 0xa6, 0xdf, 0x76, 0xe0, 0xd3, + 0x8c, 0x6d, 0xd5, 0x9c, 0x83, 0x55, 0x4b, 0x9a, 0xe8, 0xbf, 0xc4, 0xc9, + 0x89, 0x20, 0xaf, 0x10, 0x8e, 0xef, 0x6f, 0xe4, 0xa5, 0xf1, 0x5a, 0xc0, + 0x4b, 0xe7, 0x3d, 0x15, 0x67, 0xf6, 0x93, 0x33, 0xed, 0x15, 0x0e, 0x22, + 0x3e, 0xe8, 0xc7, 0xd3, 0x13, 0x20, 0x8f, 0x31, 0xc8, 0x43, 0x04, 0xff, + 0x64, 0x9e, 0x98, 0xc7, 0x0c, 0xc6, 0x11, 0x1d, 0x29, 0x72, 0x8e, 0x93, + 0xc3, 0x7a, 0xcf, 0x5a, 0x44, 0xb5, 0xbf, 0x26, 0x7e, 0x9d, 0x1a, 0x6d, + 0xc7, 0x74, 0x96, 0xb8, 0xb5, 0xb8, 0x1d, 0x6f, 0xe7, 0x36, 0xd1, 0xff, + 0x55, 0x9c, 0x25, 0x66, 0x69, 0x73, 0x05, 0xd7, 0x05, 0x43, 0xfd, 0xb4, + 0xd7, 0x0e, 0x59, 0x03, 0x55, 0xe2, 0xc4, 0xac, 0x6b, 0xd2, 0xcf, 0x3a, + 0xb5, 0x3a, 0x73, 0x2a, 0x35, 0x81, 0x0c, 0x31, 0xcb, 0xce, 0xca, 0x7c, + 0x6d, 0xc6, 0x56, 0xe2, 0xd5, 0xd6, 0x9c, 0xd8, 0x37, 0x6d, 0x7a, 0x50, + 0x0f, 0x16, 0x68, 0xdb, 0xea, 0x5e, 0x91, 0x61, 0xa2, 0x8f, 0xb1, 0xfd, + 0x33, 0x1d, 0x26, 0x76, 0xe4, 0x24, 0x0e, 0x0a, 0x07, 0xd3, 0x98, 0x97, + 0x24, 0xd1, 0x43, 0x9c, 0x7a, 0xdb, 0xee, 0xc4, 0x0a, 0xe2, 0xd4, 0x2f, + 0x98, 0xa7, 0xdc, 0x49, 0x9c, 0x7a, 0xc3, 0x2e, 0xe2, 0xd4, 0xcd, 0x13, + 0x62, 0x0b, 0x45, 0x5e, 0x7e, 0xc2, 0x6e, 0x6b, 0x90, 0xdf, 0x39, 0xab, + 0x36, 0x7f, 0x57, 0x5c, 0x58, 0x85, 0x97, 0x86, 0xcb, 0x7b, 0xc5, 0x91, + 0xe4, 0xed, 0xe4, 0xcc, 0x47, 0x47, 0xcb, 0x9c, 0xf7, 0xb8, 0x9b, 0x5b, + 0xcf, 0x32, 0xcb, 0xfb, 0x96, 0xe5, 0xfd, 0x06, 0x0b, 0x5f, 0x5d, 0x22, + 0x3c, 0x53, 0xd6, 0x81, 0x2a, 0xc8, 0x27, 0xbb, 0x31, 0xbe, 0xf3, 0x3d, + 0x3c, 0x32, 0xa8, 0xde, 0x5c, 0xc3, 0xd8, 0x7a, 0x8b, 0xb2, 0x19, 0x9e, + 0xb8, 0xbc, 0x47, 0x2a, 0x6b, 0xe5, 0xcc, 0x5d, 0x26, 0xb3, 0xe8, 0xdb, + 0x57, 0x83, 0x43, 0x41, 0xc7, 0x79, 0xda, 0x98, 0x27, 0x3f, 0x13, 0x20, + 0xb8, 0x19, 0xa8, 0xa0, 0x2f, 0xdc, 0xfc, 0x5b, 0xbf, 0xdd, 0x58, 0xde, + 0x3b, 0xd8, 0x88, 0xbb, 0x76, 0x3d, 0x8c, 0x9e, 0x5d, 0x7f, 0x8b, 0x4f, + 0x0e, 0x2d, 0xec, 0x9f, 0xe7, 0x71, 0x9c, 0xab, 0xdb, 0xa7, 0x70, 0x2a, + 0xce, 0xd8, 0x18, 0x52, 0xf0, 0xbd, 0xab, 0x16, 0x8a, 0x1c, 0xfe, 0xbd, + 0xef, 0x68, 0xae, 0xbc, 0x5b, 0x4b, 0x3e, 0x92, 0x98, 0xc3, 0xf1, 0x53, + 0xf6, 0x8a, 0xfa, 0xd2, 0xbb, 0xc2, 0x7f, 0x40, 0x5b, 0x3f, 0x16, 0x19, + 0xfc, 0x2b, 0xcb, 0x78, 0xcd, 0x49, 0xae, 0x96, 0x7a, 0x15, 0xa5, 0x36, + 0xfe, 0x96, 0x9c, 0x90, 0xbc, 0xd0, 0xe0, 0xff, 0x91, 0xeb, 0x44, 0x3e, + 0x9f, 0x95, 0xe5, 0xbf, 0xe4, 0x24, 0xbb, 0xe5, 0xbb, 0x94, 0x59, 0xc7, + 0x67, 0x52, 0xae, 0xfc, 0xec, 0xf9, 0x92, 0x9c, 0x4a, 0x68, 0x0d, 0x45, + 0x39, 0x9f, 0xa6, 0x9c, 0x33, 0x8b, 0x93, 0x50, 0xaf, 0x9d, 0x29, 0xab, + 0xdc, 0xee, 0xff, 0x3a, 0x2f, 0xab, 0x58, 0xee, 0x6f, 0xe6, 0xc8, 0xbe, + 0x80, 0x7a, 0xed, 0xcc, 0x75, 0xf2, 0x0a, 0xfa, 0x6f, 0x34, 0xb8, 0xd5, + 0x5d, 0x9f, 0x36, 0xb0, 0xf6, 0xe2, 0x1c, 0x4b, 0xb0, 0x03, 0xe3, 0x76, + 0xb0, 0x94, 0x53, 0xc9, 0x2d, 0x13, 0x5f, 0x66, 0xce, 0xf6, 0x94, 0x1d, + 0xe9, 0x5a, 0xa7, 0xb4, 0x26, 0x17, 0x31, 0xce, 0xa0, 0x5e, 0xd6, 0xb0, + 0x13, 0xee, 0xef, 0xf9, 0xe5, 0xa3, 0x09, 0xe4, 0x69, 0x8f, 0xaf, 0xd8, + 0x91, 0x0d, 0xa7, 0xdc, 0xfd, 0x3b, 0x13, 0x2f, 0xe7, 0x5f, 0x2d, 0xed, + 0x33, 0x95, 0x7f, 0x4f, 0x6c, 0xe6, 0x1a, 0xaa, 0xcc, 0xbf, 0x9c, 0xb1, + 0x6e, 0x90, 0xb5, 0x0a, 0xcb, 0xa2, 0x9f, 0xf7, 0x66, 0xac, 0xb0, 0x8a, + 0xeb, 0x90, 0x0a, 0xc9, 0xbe, 0xc4, 0xd6, 0xd2, 0x6f, 0x52, 0xb1, 0xde, + 0xef, 0x58, 0x13, 0x02, 0x8c, 0xd2, 0x39, 0xb6, 0x18, 0xac, 0xc9, 0x2b, + 0xc8, 0xc5, 0x64, 0xbd, 0x01, 0xd6, 0x6c, 0x53, 0x43, 0x48, 0x3f, 0xcc, + 0x71, 0xfb, 0x30, 0x87, 0xf9, 0x54, 0x7c, 0x61, 0x6b, 0x77, 0xbb, 0x3a, + 0x57, 0x70, 0x36, 0x98, 0x54, 0x63, 0x12, 0x07, 0x50, 0x99, 0x96, 0xb3, + 0x26, 0x56, 0x97, 0x9f, 0x98, 0xba, 0x98, 0xd8, 0x52, 0x11, 0x85, 0xf7, + 0xbe, 0xbc, 0x17, 0xc1, 0x85, 0xbf, 0x70, 0x7e, 0x18, 0x8a, 0x61, 0xdb, + 0x64, 0xb9, 0x0f, 0x06, 0xfe, 0x7b, 0xe1, 0xd2, 0x8c, 0xb3, 0x2c, 0xf3, + 0x3d, 0x27, 0x39, 0x47, 0xda, 0x2e, 0xca, 0xfd, 0xe8, 0xbe, 0x4a, 0x1f, + 0xa5, 0xaf, 0xcd, 0x1a, 0x51, 0x15, 0x5b, 0x8d, 0x89, 0x39, 0xf2, 0x9b, + 0x3f, 0xf7, 0xb8, 0x67, 0xd3, 0x65, 0x0e, 0xe4, 0xfd, 0xf1, 0x04, 0xee, + 0x93, 0xf7, 0x30, 0x19, 0xb3, 0xee, 0xcd, 0xbb, 0xef, 0x77, 0x42, 0x7e, + 0x17, 0xf1, 0xde, 0x7c, 0x51, 0x7f, 0x0f, 0xe5, 0x03, 0xe4, 0xdd, 0x01, + 0xcb, 0x6b, 0x6e, 0x80, 0x4f, 0x97, 0x33, 0x67, 0x65, 0x5d, 0xfe, 0xdf, + 0x73, 0x24, 0x97, 0xff, 0x2a, 0xfd, 0xc9, 0xbb, 0x50, 0x3e, 0x5b, 0xf2, + 0xae, 0xa2, 0x52, 0xfc, 0x7c, 0xc6, 0x7d, 0xef, 0x5d, 0x35, 0xd7, 0xd1, + 0x2f, 0x67, 0xbb, 0xef, 0xeb, 0x89, 0x7e, 0x42, 0xa6, 0xe5, 0xcc, 0xd6, + 0x03, 0xb4, 0x91, 0xde, 0x39, 0xa5, 0x77, 0x0f, 0xba, 0xee, 0x20, 0x8e, + 0x2c, 0x22, 0xb7, 0x5a, 0xac, 0x44, 0xb4, 0x55, 0x4a, 0x37, 0xeb, 0x51, + 0x4f, 0x05, 0x91, 0xa1, 0xb8, 0xbf, 0xbd, 0xeb, 0xa3, 0x8c, 0xfd, 0x76, + 0xab, 0xe6, 0x53, 0x7f, 0x5e, 0x3a, 0x7b, 0x2d, 0x7b, 0xf1, 0x29, 0x3c, + 0x6f, 0xcf, 0xc1, 0xd4, 0x6f, 0xc9, 0x3d, 0xbf, 0x66, 0xfd, 0x4f, 0x41, + 0x62, 0x88, 0x4f, 0x8f, 0x6c, 0x8c, 0x7b, 0x22, 0xeb, 0xa7, 0xe9, 0xd3, + 0x85, 0xb8, 0x9e, 0xfa, 0x1a, 0xdb, 0xf8, 0x3e, 0xb9, 0x85, 0x3d, 0x43, + 0x7e, 0x51, 0x56, 0x6b, 0x4f, 0x85, 0x7a, 0xc6, 0x29, 0xbe, 0x77, 0x2d, + 0xbf, 0xfb, 0xbb, 0x06, 0xc1, 0xb4, 0xe5, 0x84, 0x28, 0x73, 0xbe, 0x19, + 0xd9, 0x53, 0xaf, 0xea, 0xd9, 0xcf, 0xab, 0x9b, 0xb1, 0x56, 0x8e, 0x7c, + 0x98, 0x11, 0xed, 0xd3, 0xb4, 0x8f, 0x76, 0x57, 0x46, 0x32, 0x56, 0x81, + 0x8f, 0x3a, 0xd3, 0xc6, 0xf1, 0x41, 0xd6, 0x28, 0x59, 0xce, 0xdd, 0xe3, + 0x97, 0xf7, 0x77, 0x98, 0x63, 0xdb, 0xf2, 0xbb, 0xa6, 0x6e, 0x33, 0xa5, + 0x7d, 0x24, 0xe6, 0xc8, 0x8c, 0x97, 0xf7, 0xc8, 0x6f, 0xc8, 0x55, 0x07, + 0x70, 0xaf, 0x2d, 0xeb, 0x0e, 0xff, 0x3f, 0x45, 0x18, 0xff, 0x64, 0x3c, + 0x59, 0x00, 0x00, 0x00 }; static const u32 bnx2_CP_b09FwData[(0x84/4) + 1] = { 0x00000000, 0x0000001b, 0x0000000f, 0x0000000a, 0x00000008, 0x00000006, @@ -2064,1091 +2078,1077 @@ static const u32 bnx2_CP_b09FwData[(0x84/4) + 1] = { 0x00000002, 0x00000002, 0x00000002, 0x00000002, 0x00000002, 0x00000002, 0x00000002, 0x00000002, 0x00000002, 0x00000002, 0x00000002, 0x00000002, 0x00000001, 0x00000001, 0x00000001, 0x00000000 }; -static const u32 bnx2_CP_b09FwRodata[(0x178/4) + 1] = { - 0x80080100, 0x80080080, 0x80080000, 0x080015a0, 0x080015d8, 0x08001600, - 0x08001600, 0x08001614, 0x080015bc, 0x080018a4, 0x0800186c, 0x080018f8, - 0x080018f8, 0x08001980, 0x080018b4, 0x80080240, 0x80080100, 0x80080080, - 0x80080000, 0x08003148, 0x080030b4, 0x08003170, 0x08003198, 0x080031c0, - 0x080031e4, 0x0800322c, 0x08003208, 0x08003250, 0x0800311c, 0x08003344, - 0x08003334, 0x080030d0, 0x080030d0, 0x080030d0, 0x080032a4, 0x080032a4, - 0x080030d0, 0x080030d0, 0x08003324, 0x080030d0, 0x080030d0, 0x080030d0, - 0x080030d0, 0x08003314, 0x080030d0, 0x080030d0, 0x080030d0, 0x080030d0, - 0x080030d0, 0x080030d0, 0x080030d0, 0x080030d0, 0x080030d0, 0x080030d0, - 0x080030d0, 0x080030d0, 0x080030d0, 0x080030d0, 0x08003304, 0x080030d0, - 0x080030d0, 0x080032f4, 0x080030d0, 0x080030d0, 0x080030d0, 0x080030d0, - 0x080030d0, 0x080030d0, 0x080030d0, 0x080030d0, 0x080030d0, 0x080030d0, - 0x080030d0, 0x080030d0, 0x080030d0, 0x080030d0, 0x080030d0, 0x080030d0, - 0x080030d0, 0x080032dc, 0x080030d0, 0x080030d0, 0x080032cc, 0x080032bc, - 0x08003c0c, 0x08003be8, 0x08003bbc, 0x08003b9c, 0x08003b7c, 0x08003b24, - 0x80080100, 0x80080080, 0x80080000, 0x80080080, 0x00000000 }; +static const u32 bnx2_CP_b09FwRodata[(0x16c/4) + 1] = { + 0x80080100, 0x80080080, 0x80080000, 0x08001744, 0x08001744, 0x0800177c, + 0x0800177c, 0x08001790, 0x08001760, 0x080019b8, 0x08001984, 0x08001a10, + 0x08001a10, 0x08001a98, 0x080019c8, 0x80080240, 0x08003260, 0x080031cc, + 0x08003288, 0x080032b0, 0x080032d8, 0x080032fc, 0x08003344, 0x08003320, + 0x08003368, 0x08003234, 0x0800345c, 0x0800344c, 0x080031e8, 0x080031e8, + 0x080031e8, 0x080033bc, 0x080033bc, 0x080031e8, 0x080031e8, 0x0800343c, + 0x080031e8, 0x080031e8, 0x080031e8, 0x080031e8, 0x0800342c, 0x080031e8, + 0x080031e8, 0x080031e8, 0x080031e8, 0x080031e8, 0x080031e8, 0x080031e8, + 0x080031e8, 0x080031e8, 0x080031e8, 0x080031e8, 0x080031e8, 0x080031e8, + 0x080031e8, 0x0800341c, 0x080031e8, 0x080031e8, 0x0800340c, 0x080031e8, + 0x080031e8, 0x080031e8, 0x080031e8, 0x080031e8, 0x080031e8, 0x080031e8, + 0x080031e8, 0x080031e8, 0x080031e8, 0x080031e8, 0x080031e8, 0x080031e8, + 0x080031e8, 0x080031e8, 0x080031e8, 0x080031e8, 0x080033f4, 0x080031e8, + 0x080031e8, 0x080033e4, 0x080033d4, 0x08003d6c, 0x08003d40, 0x08003d0c, + 0x08003ce0, 0x08003cc0, 0x08003c74, 0x80080100, 0x80080080, 0x80080000, + 0x80080080, 0x00000000 }; static struct fw_info bnx2_cp_fw_09 = { - /* Firmware version: 4.0.5 */ + /* Firmware version: 4.4.23 */ .ver_major = 0x4, - .ver_minor = 0x0, - .ver_fix = 0x5, + .ver_minor = 0x4, + .ver_fix = 0x17, - .start_addr = 0x08000074, + .start_addr = 0x08000080, .text_addr = 0x08000000, - .text_len = 0x5770, + .text_len = 0x5938, .text_index = 0x0, .gz_text = bnx2_CP_b09FwText, .gz_text_len = sizeof(bnx2_CP_b09FwText), - .data_addr = 0x08005900, + .data_addr = 0x08005ac0, .data_len = 0x84, .data_index = 0x0, .data = bnx2_CP_b09FwData, - .sbss_addr = 0x08005988, - .sbss_len = 0x99, + .sbss_addr = 0x08005b44, + .sbss_len = 0x91, .sbss_index = 0x0, - .bss_addr = 0x08005a28, - .bss_len = 0x20c, + .bss_addr = 0x08005bd8, + .bss_len = 0x19c, .bss_index = 0x0, - .rodata_addr = 0x08005770, - .rodata_len = 0x178, + .rodata_addr = 0x08005938, + .rodata_len = 0x16c, .rodata_index = 0x0, .rodata = bnx2_CP_b09FwRodata, }; static u8 bnx2_RXP_b09FwText[] = { - 0xec, 0x5b, 0x7f, 0x70, 0x1c, 0xf5, 0x75, 0xff, 0x7c, 0xf7, 0xf6, 0xa4, - 0x95, 0x74, 0xba, 0x5b, 0x49, 0x27, 0xf9, 0x14, 0x8c, 0xb5, 0x8b, 0x56, - 0x27, 0x61, 0x19, 0x77, 0x4f, 0x3a, 0xd9, 0x4a, 0x66, 0x1b, 0x2e, 0xb6, - 0x63, 0xe4, 0x81, 0x82, 0xb0, 0x09, 0x31, 0x53, 0x26, 0xa8, 0xb6, 0x63, - 0xc4, 0x8f, 0x34, 0x26, 0x61, 0x06, 0x11, 0x68, 0xd8, 0x48, 0x36, 0xa6, - 0xf6, 0x9e, 0xd6, 0x36, 0x12, 0xe0, 0x99, 0x74, 0x22, 0x64, 0x59, 0x36, - 0xe4, 0xa4, 0x33, 0x90, 0x1f, 0x66, 0x5a, 0x6a, 0x81, 0xf9, 0x61, 0x88, - 0x0d, 0x84, 0x42, 0x02, 0x33, 0x99, 0x89, 0xf9, 0x11, 0xc7, 0x66, 0x68, - 0x50, 0x5a, 0x92, 0x8a, 0x89, 0xea, 0x6f, 0xdf, 0xbb, 0x93, 0xf8, 0x61, - 0x3a, 0x4d, 0x3b, 0xd3, 0x3f, 0xf7, 0xcd, 0xdc, 0x68, 0xf7, 0xfb, 0x7d, - 0xef, 0x7d, 0xdf, 0xef, 0xf7, 0xbe, 0x3b, 0xa3, 0x5b, 0x23, 0x28, 0xc7, - 0x1c, 0x54, 0xd2, 0x2f, 0xbd, 0xa5, 0xef, 0x5b, 0x1d, 0x4b, 0xed, 0xa5, - 0xfc, 0x1e, 0x0a, 0x43, 0xe5, 0xbf, 0x02, 0x01, 0x04, 0x10, 0x40, 0x00, - 0x01, 0x04, 0x10, 0x40, 0x00, 0x01, 0x04, 0x10, 0x40, 0x00, 0x01, 0x04, - 0x10, 0x40, 0x00, 0x01, 0x04, 0x10, 0x40, 0x00, 0x01, 0x04, 0x10, 0x40, - 0x00, 0x01, 0x04, 0x10, 0x40, 0x00, 0x01, 0x04, 0x10, 0x40, 0x00, 0x01, - 0x04, 0x10, 0x40, 0x00, 0x01, 0x04, 0x10, 0x40, 0x00, 0x01, 0x04, 0x10, - 0x40, 0x00, 0x01, 0x04, 0x10, 0x40, 0x00, 0x01, 0xfc, 0x7f, 0x42, 0x08, - 0xd0, 0xf9, 0x6f, 0xe5, 0xdc, 0x0f, 0x9a, 0xe2, 0x8c, 0x7c, 0x67, 0x85, - 0x05, 0x2d, 0xe4, 0xc4, 0xef, 0xd8, 0x68, 0x01, 0x99, 0x5c, 0xab, 0xb1, - 0x12, 0xff, 0x29, 0xdd, 0xb8, 0x0a, 0x5e, 0x3f, 0xdf, 0x99, 0xfd, 0xc1, - 0x13, 0xcb, 0xcd, 0xe9, 0x91, 0x10, 0x34, 0xdd, 0x79, 0x39, 0xa5, 0x27, - 0xa1, 0x2d, 0x24, 0x9a, 0xef, 0x37, 0x6f, 0xab, 0x46, 0x74, 0x9e, 0x17, - 0x5c, 0xc5, 0x91, 0x72, 0xbf, 0x2d, 0xf1, 0xac, 0xed, 0x8a, 0xae, 0x34, - 0xdc, 0x90, 0x73, 0x58, 0xdc, 0xe0, 0x9d, 0x95, 0x46, 0xb8, 0x78, 0xb2, - 0x3a, 0xa1, 0x21, 0xbc, 0x1f, 0xba, 0xea, 0x28, 0x08, 0x5b, 0xe5, 0x28, - 0x79, 0xb0, 0x02, 0xe1, 0x07, 0x13, 0x28, 0x9d, 0x38, 0x24, 0x7a, 0x46, - 0x34, 0x9c, 0x0c, 0x1d, 0x16, 0x9b, 0x72, 0xe8, 0x09, 0x3b, 0x33, 0x57, - 0x8c, 0x12, 0x5d, 0xa6, 0xf0, 0xff, 0x25, 0x53, 0x57, 0x8c, 0xe5, 0xa0, - 0x87, 0x1c, 0x28, 0xaa, 0xf3, 0x34, 0x3d, 0x33, 0xde, 0xcc, 0x15, 0xfb, - 0x72, 0xa7, 0xe5, 0x13, 0xcd, 0x71, 0x1c, 0xc9, 0xeb, 0x38, 0x94, 0xff, - 0x25, 0xc9, 0x61, 0xba, 0x2e, 0x34, 0x57, 0x75, 0x5c, 0x6c, 0x4b, 0x87, - 0x31, 0xbe, 0xeb, 0xac, 0x0c, 0x59, 0xa6, 0x01, 0xc5, 0xd2, 0x8f, 0x82, - 0xf0, 0x7c, 0xc2, 0xf3, 0xc3, 0x18, 0x1d, 0x79, 0xb3, 0x1a, 0xe5, 0x09, - 0x3c, 0xd1, 0xcc, 0xf4, 0x4c, 0xcb, 0x3c, 0x42, 0xb1, 0x79, 0xfa, 0x12, - 0xa2, 0x7f, 0x26, 0x0d, 0x8c, 0xed, 0xea, 0x26, 0x52, 0x89, 0x01, 0xbb, - 0x14, 0x1b, 0x74, 0xb8, 0x65, 0x0e, 0xf3, 0x9a, 0xe7, 0xe3, 0x0a, 0x63, - 0x22, 0xaa, 0x17, 0xf9, 0x40, 0x68, 0x16, 0xdc, 0xd2, 0x73, 0xf6, 0x4f, - 0xe7, 0xe6, 0xf7, 0xef, 0xa1, 0x73, 0x34, 0xda, 0xef, 0xc5, 0x4f, 0xf2, - 0x9b, 0xf0, 0xe3, 0xfc, 0xb5, 0x78, 0x2c, 0xdf, 0x4d, 0xe7, 0xde, 0x4a, - 0xe7, 0x6e, 0xc1, 0x3f, 0xe7, 0x6f, 0xc6, 0x4f, 0xf3, 0x3d, 0xf8, 0x51, - 0x7e, 0x3d, 0x1e, 0xcd, 0x5f, 0x85, 0x47, 0xf2, 0x28, 0xc8, 0x70, 0x3a, - 0xdd, 0x22, 0x7e, 0xee, 0x95, 0x41, 0xdd, 0xbd, 0x15, 0x53, 0xb9, 0x30, - 0xc2, 0xbb, 0x25, 0x76, 0xd9, 0xe6, 0x03, 0x40, 0xb3, 0x1e, 0x86, 0xc0, - 0x4a, 0xdb, 0x3c, 0x08, 0x7c, 0x01, 0x3d, 0x71, 0xf3, 0x10, 0x50, 0x27, - 0x5e, 0x19, 0xaa, 0x13, 0x27, 0x86, 0x54, 0xf1, 0xa2, 0x27, 0x10, 0x73, - 0x10, 0x79, 0x21, 0x2d, 0xe5, 0xa5, 0x6d, 0x52, 0xe6, 0x52, 0x56, 0xd7, - 0x4b, 0xc2, 0xb4, 0x77, 0x88, 0x45, 0x30, 0x6a, 0xcd, 0xcc, 0x8d, 0x42, - 0x73, 0xcb, 0x89, 0xff, 0x9a, 0x0e, 0xc0, 0xda, 0x6d, 0x90, 0x1f, 0x58, - 0xc7, 0x6d, 0xf8, 0x7a, 0x21, 0x26, 0xba, 0x51, 0x63, 0xad, 0xc4, 0xb7, - 0xbb, 0x6d, 0x8c, 0xe4, 0xa1, 0x55, 0x39, 0x1f, 0x20, 0x35, 0x28, 0x60, - 0x93, 0xbf, 0x05, 0x3d, 0xdb, 0xb9, 0x27, 0x6b, 0x8a, 0xfe, 0x26, 0xd9, - 0x7d, 0x92, 0xdd, 0x27, 0xd9, 0x7d, 0xd2, 0xcb, 0x27, 0xbd, 0x7c, 0xd2, - 0xc1, 0x27, 0xdd, 0x7c, 0xd2, 0xc3, 0x27, 0x3d, 0x7c, 0xd2, 0xd1, 0x67, - 0x5f, 0xf5, 0x91, 0x0d, 0x22, 0xf8, 0xa5, 0xb7, 0x10, 0x1f, 0x78, 0xe7, - 0xe3, 0x83, 0xb5, 0x3a, 0x5e, 0x27, 0x19, 0x15, 0xeb, 0xff, 0xca, 0xe3, - 0xa7, 0x11, 0xf2, 0x91, 0xf1, 0xbf, 0x3f, 0xdb, 0x24, 0x8d, 0xe6, 0x69, - 0x97, 0xe0, 0x94, 0xf7, 0xb6, 0x2c, 0x59, 0xc0, 0xe7, 0x7e, 0x11, 0x72, - 0x08, 0x58, 0x34, 0x2c, 0xe5, 0x87, 0xed, 0xbf, 0x96, 0x6f, 0x7c, 0x95, - 0xf9, 0x39, 0x78, 0x6b, 0x48, 0x41, 0x88, 0xd6, 0x2e, 0xb1, 0xdf, 0x90, - 0xd7, 0xc7, 0x19, 0xef, 0x8f, 0x11, 0x94, 0xb3, 0xad, 0xa0, 0xd5, 0x38, - 0xea, 0x1d, 0xdf, 0x4e, 0xc2, 0x8d, 0x3a, 0xaa, 0x78, 0x35, 0x6b, 0x60, - 0x81, 0x93, 0x41, 0xa5, 0x63, 0xed, 0xba, 0x5f, 0x69, 0xed, 0xab, 0x46, - 0xe6, 0xc2, 0x18, 0x6c, 0xec, 0xcf, 0xab, 0xe2, 0x78, 0xb6, 0x12, 0xd5, - 0xbb, 0xad, 0xf5, 0x59, 0xa1, 0xa0, 0xa7, 0x36, 0x83, 0xb1, 0xb4, 0x69, - 0x8c, 0xc0, 0xc0, 0xfa, 0x36, 0x05, 0x58, 0xe0, 0xe2, 0xee, 0xb4, 0x69, - 0xbb, 0xe8, 0xc7, 0x54, 0xdc, 0xc6, 0x78, 0x5e, 0xa3, 0xfc, 0x70, 0x71, - 0x7d, 0x5a, 0x83, 0xdc, 0x95, 0xc1, 0xa9, 0xf6, 0x52, 0x4c, 0x75, 0x73, - 0x9c, 0xa8, 0x74, 0xf6, 0x76, 0x28, 0xd5, 0xd5, 0xe4, 0x9b, 0xb4, 0x08, - 0x57, 0x17, 0x52, 0x94, 0xd6, 0x21, 0xfe, 0x35, 0xcd, 0x32, 0x7c, 0x4e, - 0x1c, 0x1f, 0x8e, 0xa2, 0x7c, 0x58, 0xc3, 0x0f, 0x77, 0xab, 0x58, 0x43, - 0x3e, 0xbe, 0x3f, 0xa5, 0x1a, 0x37, 0x0a, 0x07, 0x63, 0x79, 0x15, 0xf1, - 0x6c, 0x3d, 0x8c, 0x2a, 0x0d, 0x8b, 0xb2, 0x2e, 0xde, 0x26, 0xde, 0x7d, - 0xc4, 0x3b, 0xd6, 0xae, 0xe3, 0x64, 0x6d, 0xd1, 0xbf, 0xb7, 0x78, 0x8d, - 0xee, 0x6e, 0xa5, 0x04, 0x28, 0x81, 0xab, 0x39, 0x69, 0xdc, 0xe6, 0x35, - 0x92, 0x1e, 0xd7, 0x60, 0x45, 0x89, 0x86, 0x0d, 0x83, 0xbc, 0xb6, 0x0a, - 0x98, 0x58, 0x50, 0x89, 0x72, 0xb6, 0x01, 0xe7, 0xf5, 0x4a, 0x7a, 0xe6, - 0x78, 0xb8, 0x37, 0xce, 0xf6, 0x77, 0x95, 0xff, 0x90, 0x99, 0x38, 0xe3, - 0x15, 0x73, 0xe5, 0x68, 0x3a, 0x8d, 0xdb, 0xbd, 0xc6, 0xcc, 0x5e, 0xa5, - 0x06, 0x08, 0x9b, 0x86, 0xa1, 0x40, 0x8b, 0x3b, 0x48, 0x0d, 0x51, 0xdc, - 0xdc, 0x5b, 0x88, 0x1b, 0xa4, 0xda, 0x73, 0x9c, 0x9f, 0x9a, 0xab, 0x13, - 0x7e, 0xc3, 0xb2, 0x26, 0xfc, 0xf1, 0x5e, 0xc6, 0x53, 0xf1, 0x3c, 0x3d, - 0x9f, 0xd9, 0xf7, 0xe6, 0x5c, 0x0d, 0xf9, 0x87, 0x82, 0x7f, 0x0d, 0x65, - 0xfe, 0x6c, 0x1b, 0xd7, 0x7b, 0x8d, 0x33, 0xdb, 0x15, 0xf2, 0xe1, 0x79, - 0x11, 0x94, 0x51, 0x1d, 0x0a, 0x13, 0xaf, 0xfd, 0xde, 0x2c, 0xd6, 0xb6, - 0x99, 0x87, 0xf9, 0xff, 0xce, 0x46, 0xad, 0x22, 0xff, 0x0b, 0x72, 0x36, - 0x1e, 0xca, 0xdb, 0xd8, 0x48, 0x72, 0xdc, 0x8a, 0x37, 0x81, 0xfa, 0xc5, - 0xc6, 0x69, 0xe5, 0x2d, 0xe9, 0x5e, 0xc5, 0xfc, 0x16, 0xe2, 0x74, 0x75, - 0x63, 0xcf, 0x69, 0xc5, 0x1c, 0xb9, 0x47, 0x61, 0x5b, 0x29, 0xf8, 0xab, - 0xb6, 0x34, 0x46, 0xaa, 0x74, 0x5c, 0xd3, 0xa6, 0xb9, 0x8b, 0x48, 0xa6, - 0x97, 0x97, 0x6b, 0xa8, 0xdb, 0x93, 0xc1, 0x6b, 0x6d, 0xaf, 0x62, 0x64, - 0x2d, 0xdb, 0x81, 0xe9, 0x58, 0xe6, 0x04, 0xaa, 0xad, 0x32, 0x54, 0x8f, - 0x86, 0x11, 0xdb, 0x73, 0x56, 0x26, 0x2c, 0x5e, 0xb7, 0xb6, 0xcc, 0x08, - 0x96, 0x39, 0x8c, 0xe8, 0xe8, 0xe7, 0xa1, 0x5a, 0x66, 0x0b, 0xf0, 0x8d, - 0x38, 0xe3, 0x96, 0x58, 0xf3, 0xb2, 0x0b, 0x5c, 0xfa, 0x05, 0x81, 0x1b, - 0x53, 0x4f, 0xca, 0x4c, 0x2d, 0xd3, 0x3c, 0x46, 0xeb, 0x2c, 0x43, 0xd9, - 0x4c, 0x06, 0x75, 0x44, 0x33, 0x8f, 0x17, 0x41, 0xef, 0x9e, 0xa2, 0x0c, - 0x6f, 0x2c, 0xc7, 0x63, 0x1a, 0x3a, 0xd1, 0xec, 0x7f, 0x0f, 0xaf, 0x2d, - 0x63, 0x9a, 0xef, 0x4d, 0xef, 0x6f, 0xdb, 0x49, 0x36, 0xe1, 0x7a, 0x7a, - 0xae, 0x5f, 0x78, 0xbf, 0xbb, 0x96, 0xec, 0xd5, 0x02, 0x91, 0xa0, 0x35, - 0x8e, 0xe1, 0xdd, 0xd2, 0x58, 0x57, 0xf4, 0x4b, 0x29, 0xf1, 0x3b, 0x93, - 0xee, 0x44, 0x63, 0x56, 0x85, 0xf4, 0x1a, 0xed, 0x5f, 0x87, 0x76, 0xc8, - 0xa9, 0x6b, 0x79, 0xaf, 0x51, 0x3f, 0x1a, 0x12, 0x58, 0xa1, 0x9a, 0xd3, - 0x3d, 0x48, 0xe0, 0x20, 0xd5, 0x9a, 0x7a, 0x47, 0xa7, 0xda, 0x13, 0xa7, - 0x1a, 0x64, 0x88, 0xe6, 0xfb, 0x6d, 0x2c, 0xce, 0x5e, 0x8b, 0x8b, 0x87, - 0x1d, 0x1c, 0xf6, 0x6d, 0xfc, 0xd0, 0x97, 0xf2, 0x94, 0x2d, 0xe5, 0xfb, - 0xed, 0x66, 0xef, 0x31, 0x6a, 0x0b, 0x4b, 0x97, 0xb7, 0xf6, 0xc4, 0x42, - 0x2a, 0xd9, 0xa7, 0xc9, 0xb8, 0x59, 0x98, 0x89, 0x49, 0x61, 0x53, 0xcc, - 0x75, 0x91, 0xed, 0x0d, 0xec, 0xcb, 0xb7, 0xe0, 0xe1, 0xbc, 0x45, 0xbf, - 0x25, 0x14, 0x2b, 0x69, 0xaa, 0x6b, 0xac, 0xab, 0x8e, 0xb1, 0x66, 0xca, - 0x0d, 0x5f, 0xc1, 0x41, 0x9b, 0x72, 0xa0, 0x8a, 0x70, 0xfd, 0xb3, 0xe4, - 0x3f, 0x0d, 0x2d, 0xbb, 0x33, 0x28, 0x4b, 0xd5, 0xc0, 0xb8, 0xd2, 0xc2, - 0x98, 0xaf, 0xb9, 0x61, 0x8a, 0xfb, 0x51, 0xef, 0x61, 0x7c, 0x4d, 0x8f, - 0xa3, 0x9c, 0xec, 0xb7, 0xbe, 0x2d, 0x02, 0xac, 0xe3, 0xbd, 0x08, 0xea, - 0xad, 0xe7, 0x50, 0x5f, 0x5d, 0x89, 0x92, 0xc5, 0x4f, 0x62, 0x4a, 0x8f, - 0xa2, 0x94, 0x7a, 0x47, 0x03, 0xe1, 0x34, 0x90, 0xaf, 0x6a, 0x2d, 0x8b, - 0x78, 0x0a, 0x58, 0x4d, 0x84, 0x4b, 0x39, 0x95, 0x20, 0xdd, 0xc3, 0xcb, - 0xe3, 0xc8, 0x93, 0xfc, 0x93, 0x9e, 0x94, 0x91, 0xb4, 0xd9, 0xeb, 0x53, - 0x7e, 0x4e, 0xe4, 0x3a, 0x31, 0x99, 0xbf, 0x9c, 0xea, 0xba, 0x8d, 0x7d, - 0x9e, 0x83, 0x51, 0x5f, 0x5d, 0xef, 0xc1, 0xec, 0xbe, 0x09, 0x69, 0x3c, - 0x4c, 0xf1, 0x33, 0xee, 0x9b, 0xc6, 0x53, 0x21, 0x0d, 0xc7, 0xec, 0x0a, - 0x92, 0x93, 0x72, 0x97, 0x74, 0x7a, 0xdc, 0xbb, 0x0f, 0x56, 0x0d, 0xdb, - 0x9f, 0xfd, 0x94, 0xc6, 0x01, 0xbf, 0x10, 0xdf, 0x97, 0x6a, 0x70, 0x61, - 0x77, 0xb0, 0x6f, 0xdc, 0xe9, 0x70, 0x5b, 0xb1, 0x9e, 0x76, 0x77, 0xd8, - 0x28, 0x1d, 0xec, 0x24, 0xbe, 0x8d, 0xf6, 0x5b, 0xb8, 0x09, 0x53, 0x09, - 0x17, 0x4b, 0x29, 0xfe, 0x55, 0xe7, 0x81, 0xd4, 0x56, 0xcf, 0x95, 0x31, - 0xcb, 0xea, 0x7d, 0x49, 0xdc, 0x85, 0xe3, 0x29, 0xae, 0xef, 0x2a, 0xe5, - 0xbe, 0x8e, 0x9d, 0xf6, 0x2e, 0x9c, 0xc8, 0x7d, 0x09, 0x3d, 0x55, 0x66, - 0xcb, 0x80, 0xb8, 0x09, 0x87, 0x77, 0x5d, 0x0c, 0x7c, 0x95, 0xf3, 0x84, - 0x74, 0xb3, 0x6e, 0xc2, 0x91, 0x91, 0xef, 0xe0, 0x99, 0xa1, 0x72, 0x3c, - 0x6e, 0x55, 0xa3, 0x7e, 0xbc, 0x78, 0xce, 0x97, 0x3b, 0x34, 0x8c, 0x52, - 0x4e, 0x5f, 0x62, 0xab, 0x38, 0x19, 0xe7, 0x1a, 0x42, 0xb1, 0xd6, 0xf6, - 0x2d, 0xaa, 0x37, 0x85, 0x16, 0x8c, 0x4d, 0x69, 0x03, 0x9e, 0x97, 0xa1, - 0x3a, 0x58, 0x86, 0x3d, 0x55, 0x10, 0x1b, 0xa9, 0x97, 0xfd, 0xad, 0xd7, - 0xd8, 0x3b, 0xa8, 0x54, 0x63, 0xa4, 0x3e, 0x43, 0xbe, 0x10, 0xa8, 0xb3, - 0x0c, 0x6c, 0xcb, 0x51, 0x25, 0xcd, 0xa9, 0xf8, 0x6e, 0xae, 0x1d, 0x23, - 0x75, 0x4c, 0x7b, 0x11, 0xa6, 0x0a, 0x7f, 0xc3, 0x38, 0x59, 0x6d, 0x26, - 0x40, 0x36, 0x1b, 0xf3, 0x55, 0x0c, 0xdb, 0xc3, 0x67, 0x47, 0xd6, 0x9a, - 0x7a, 0x0f, 0xe5, 0x5b, 0xa8, 0x10, 0xb7, 0xfc, 0x0c, 0x7c, 0xd3, 0xfb, - 0xbd, 0xfc, 0xa0, 0x70, 0xa6, 0xca, 0xf9, 0x3f, 0xf5, 0x46, 0xe8, 0x8c, - 0x14, 0xa5, 0xcc, 0xff, 0xf6, 0x68, 0xf1, 0x7f, 0x46, 0x7f, 0xcc, 0xb8, - 0x19, 0x80, 0xe3, 0x60, 0xc1, 0x27, 0x62, 0x7e, 0xbe, 0x8e, 0x9f, 0x1b, - 0xd3, 0xc5, 0xfa, 0xa0, 0x2f, 0x63, 0xf9, 0xe6, 0xf3, 0xaf, 0x1a, 0x75, - 0xe3, 0x4d, 0x28, 0xdb, 0xc3, 0xef, 0xbc, 0x2e, 0x70, 0x41, 0x07, 0xe7, - 0x5e, 0x13, 0x94, 0xd1, 0x4d, 0xd1, 0x62, 0x7d, 0x9e, 0xaf, 0x1b, 0x7f, - 0x37, 0x77, 0x6e, 0x61, 0x16, 0xa0, 0xf7, 0x62, 0x7d, 0xfd, 0x6e, 0x9a, - 0x9f, 0x99, 0xa6, 0x0c, 0xaf, 0xed, 0x33, 0xed, 0x11, 0x65, 0x39, 0xc9, - 0xc2, 0xf9, 0xca, 0x79, 0x7b, 0xc7, 0x1c, 0x0d, 0xe5, 0x82, 0x7f, 0x50, - 0xe2, 0x1a, 0xe6, 0x37, 0x4f, 0xdf, 0x84, 0x92, 0x8f, 0xce, 0x55, 0xf1, - 0x54, 0xfa, 0xdc, 0x73, 0xaf, 0x96, 0xe5, 0x6b, 0xab, 0x29, 0xfe, 0x6a, - 0xa1, 0x2e, 0xa6, 0x01, 0x40, 0xaf, 0x43, 0x05, 0xe5, 0x73, 0xc8, 0xba, - 0x52, 0x86, 0xae, 0xe6, 0xf8, 0xd5, 0xdc, 0x88, 0x73, 0x1e, 0x06, 0x77, - 0x3f, 0x41, 0xbe, 0x8f, 0x72, 0x9c, 0x92, 0xff, 0xcf, 0x43, 0xf6, 0xc1, - 0x86, 0x28, 0xeb, 0xbb, 0xbe, 0x0d, 0x6e, 0x03, 0xd5, 0xf2, 0xdf, 0xdc, - 0xdf, 0x2b, 0x47, 0xba, 0x75, 0x3c, 0x9b, 0x5e, 0x49, 0xeb, 0x1c, 0x67, - 0x36, 0x7e, 0xe4, 0x69, 0xb8, 0x6d, 0x30, 0x41, 0x72, 0x72, 0x0d, 0x2d, - 0x9b, 0x39, 0xa9, 0xd8, 0x78, 0x8c, 0x62, 0xf4, 0x11, 0x9f, 0x6d, 0xa5, - 0xe2, 0x82, 0xb6, 0x95, 0xb2, 0xb4, 0x8e, 0xe3, 0x7e, 0x31, 0xd1, 0xe8, - 0xc4, 0x3b, 0x0a, 0xdd, 0xfa, 0x4b, 0x79, 0x68, 0x2d, 0x3f, 0x5f, 0x48, - 0x6b, 0x75, 0xf4, 0xf7, 0x2f, 0x64, 0xc5, 0x67, 0xe4, 0xd0, 0xff, 0x3b, - 0x39, 0x28, 0x1f, 0x4c, 0x7b, 0x33, 0x5a, 0x69, 0x4e, 0x52, 0x91, 0xa1, - 0xae, 0x39, 0x4e, 0xb1, 0xb1, 0x9d, 0x7a, 0xf4, 0x6f, 0x68, 0x16, 0xdc, - 0x56, 0x98, 0xb7, 0x0a, 0xe3, 0x5b, 0x61, 0x9e, 0xdb, 0x50, 0x9c, 0xcb, - 0x34, 0xd5, 0xe2, 0x59, 0x6d, 0x7e, 0x8f, 0x6d, 0xdd, 0x85, 0x0d, 0x43, - 0x52, 0x6e, 0xb5, 0xe3, 0xc4, 0xa3, 0x1a, 0x5b, 0xad, 0x2e, 0xf4, 0x0e, - 0x81, 0xf2, 0x5a, 0xca, 0xd2, 0xd4, 0xe2, 0xc4, 0x3b, 0x54, 0xe4, 0x7b, - 0x74, 0x57, 0x8c, 0xa7, 0x3f, 0x47, 0x76, 0xaa, 0xc0, 0xcf, 0x68, 0xde, - 0xdb, 0xe1, 0x23, 0xb3, 0x26, 0x55, 0x49, 0xfd, 0x4a, 0x87, 0xef, 0x1b, - 0x62, 0x72, 0x48, 0x47, 0xd6, 0x3f, 0x2b, 0x8f, 0x37, 0x09, 0xec, 0xef, - 0x88, 0xe3, 0xf8, 0x18, 0xf3, 0xd7, 0xb1, 0x2d, 0xcf, 0xb3, 0x65, 0x88, - 0xec, 0xe1, 0x8a, 0x6b, 0xd2, 0xbc, 0x56, 0x01, 0x6b, 0x1f, 0xd7, 0x63, - 0xcb, 0x9e, 0x11, 0x45, 0x9c, 0xbb, 0xf3, 0xaf, 0xd3, 0x9c, 0x65, 0x50, - 0x2d, 0x5b, 0x48, 0xf3, 0x55, 0x82, 0x66, 0xa9, 0x38, 0xcd, 0x52, 0xd6, - 0xdc, 0x7c, 0x68, 0x52, 0x36, 0x4a, 0xf9, 0x18, 0xd5, 0xb2, 0x57, 0xe8, - 0xf7, 0x01, 0xd5, 0xd3, 0x2a, 0xd2, 0xe5, 0x82, 0x41, 0xd6, 0xc5, 0x15, - 0x36, 0xd5, 0xdb, 0x8c, 0x52, 0x1e, 0xe3, 0x3e, 0x14, 0x9a, 0x24, 0x5e, - 0x34, 0x73, 0x6c, 0xf3, 0x81, 0x01, 0x1f, 0xee, 0xd3, 0x94, 0xfb, 0x35, - 0xe3, 0x51, 0x54, 0x8f, 0xeb, 0x08, 0x8f, 0xb7, 0xd0, 0xbe, 0x86, 0x38, - 0xbd, 0xbb, 0x34, 0x13, 0xc6, 0x9c, 0x3a, 0xb1, 0xe4, 0xbe, 0x59, 0xb9, - 0x33, 0xa5, 0xe2, 0xc6, 0x26, 0xb3, 0xeb, 0x4a, 0x81, 0x4c, 0x4b, 0x96, - 0xf5, 0x2d, 0xa5, 0xdc, 0x94, 0x47, 0xe2, 0x96, 0x94, 0x51, 0x47, 0xde, - 0x75, 0xa2, 0xc3, 0xb2, 0x4f, 0x80, 0x65, 0x64, 0x1a, 0x5e, 0x77, 0xc5, - 0xef, 0x3b, 0xac, 0x07, 0x5e, 0x45, 0x12, 0xed, 0xe3, 0xaa, 0xf8, 0xb7, - 0xec, 0x12, 0xb4, 0x4d, 0x42, 0x2f, 0x71, 0x0e, 0x89, 0x93, 0x0f, 0x1e, - 0x16, 0xa7, 0x26, 0x48, 0x6e, 0x9f, 0x74, 0xf1, 0x49, 0x17, 0x9f, 0x74, - 0xf1, 0x49, 0x97, 0xc2, 0x5c, 0xc9, 0xba, 0xb6, 0xd0, 0x3c, 0xf3, 0x7a, - 0x61, 0xf6, 0xe5, 0x59, 0xb1, 0xca, 0x31, 0x33, 0x2e, 0x58, 0x6f, 0xd6, - 0x53, 0xca, 0x57, 0xed, 0xa2, 0x3e, 0x2e, 0x95, 0x5b, 0x6d, 0x72, 0xde, - 0x16, 0x52, 0xfe, 0xbb, 0xcd, 0xb6, 0x60, 0x1d, 0xa5, 0x7c, 0xd4, 0x26, - 0x9b, 0x12, 0xaf, 0x01, 0x5f, 0x1e, 0x29, 0xb1, 0x2c, 0x63, 0x1c, 0x11, - 0xd2, 0x2f, 0x4a, 0x7a, 0x69, 0xa4, 0x6b, 0x12, 0x2a, 0xe9, 0x1a, 0x1a, - 0x87, 0xae, 0x90, 0x3c, 0xc6, 0x28, 0xd9, 0x69, 0xf2, 0xcf, 0xc9, 0xc3, - 0xfe, 0x71, 0xc5, 0x97, 0x69, 0x3e, 0x51, 0xc9, 0xae, 0x03, 0x14, 0x23, - 0x3d, 0x2a, 0x8c, 0x52, 0x4b, 0xa1, 0x9e, 0xa8, 0xe1, 0xc0, 0x58, 0x05, - 0xc6, 0x47, 0x74, 0x8c, 0x8c, 0x41, 0x0f, 0x13, 0x4f, 0x77, 0xe4, 0xb0, - 0xf8, 0x64, 0x5c, 0x95, 0x3a, 0x5b, 0xf0, 0x0e, 0xd5, 0xa9, 0x41, 0xaf, - 0x5a, 0x9c, 0xda, 0xa5, 0x61, 0xab, 0xcf, 0xb9, 0x29, 0x71, 0xd4, 0xee, - 0x4f, 0x10, 0x8a, 0xe8, 0xb7, 0xd7, 0x50, 0x4c, 0x85, 0xb0, 0xd9, 0x42, - 0x66, 0x9b, 0xdd, 0x05, 0x62, 0x65, 0xec, 0xa5, 0xfa, 0xd7, 0x67, 0xb9, - 0x7d, 0x34, 0xc6, 0xf4, 0x26, 0x60, 0xae, 0xff, 0xad, 0x30, 0x7b, 0x0e, - 0x90, 0xfd, 0x37, 0x67, 0x91, 0xd9, 0x99, 0xad, 0x13, 0xef, 0x0e, 0xcd, - 0xca, 0x35, 0x29, 0x33, 0xd3, 0x4c, 0x6b, 0x95, 0x59, 0x25, 0x59, 0x82, - 0xfe, 0x8d, 0x84, 0xdb, 0xa2, 0x62, 0x36, 0xb4, 0x3d, 0xd5, 0x5f, 0x45, - 0x13, 0x90, 0x16, 0xa1, 0x1a, 0xec, 0x35, 0x99, 0x89, 0x1c, 0xad, 0xad, - 0xa7, 0x7b, 0xcb, 0xf3, 0xb6, 0x79, 0xec, 0x3d, 0x4c, 0x63, 0x83, 0x37, - 0xad, 0x36, 0xfb, 0x66, 0x5f, 0x24, 0xe4, 0x76, 0x97, 0x41, 0x59, 0x5d, - 0x81, 0x69, 0xed, 0x4c, 0xd6, 0xb4, 0x2f, 0x13, 0x6e, 0x8b, 0x86, 0xfe, - 0x46, 0x7a, 0x8f, 0x1c, 0xf3, 0x8a, 0x74, 0x7b, 0xed, 0xfe, 0x27, 0x2b, - 0x90, 0xec, 0xbb, 0x84, 0x7a, 0xc9, 0x92, 0x90, 0xc4, 0xf5, 0xa9, 0x69, - 0x7d, 0xb3, 0x37, 0x1b, 0x0a, 0xb7, 0x27, 0xf5, 0x33, 0xc2, 0x4d, 0x94, - 0x62, 0x3a, 0x7e, 0x45, 0xd6, 0x34, 0x72, 0x48, 0x1e, 0xeb, 0xc2, 0x74, - 0x62, 0x87, 0x67, 0x4e, 0xdd, 0x8c, 0xe4, 0xfa, 0x64, 0x68, 0x7a, 0x61, - 0x99, 0x9f, 0xcc, 0x7c, 0x53, 0x24, 0x3b, 0xcb, 0x69, 0x36, 0x1f, 0xa9, - 0x4d, 0x66, 0xce, 0x14, 0x72, 0x8c, 0xe7, 0x1c, 0x95, 0xe6, 0x9c, 0x2d, - 0xb8, 0x9d, 0x6c, 0xd2, 0x49, 0x76, 0x9f, 0x58, 0x52, 0x4a, 0xf3, 0x4a, - 0xa3, 0x1d, 0x0d, 0xb9, 0x9d, 0x61, 0x98, 0xfa, 0x7b, 0x54, 0x8b, 0x27, - 0xad, 0x19, 0x7b, 0x75, 0x8e, 0xe7, 0x1f, 0x35, 0xb5, 0x94, 0xf2, 0xf5, - 0x9e, 0xbc, 0xa0, 0x79, 0x91, 0x6d, 0x6a, 0xea, 0x23, 0x74, 0x77, 0x33, - 0x6a, 0xd8, 0x86, 0x2a, 0xbe, 0x6e, 0xb9, 0x06, 0xe9, 0x6d, 0x33, 0xdd, - 0x73, 0x30, 0x13, 0xdb, 0xa9, 0x8f, 0x6f, 0xf6, 0x90, 0xb9, 0xd4, 0x7b, - 0x34, 0x46, 0xf5, 0xb9, 0x17, 0x50, 0x2e, 0xaf, 0x84, 0xdb, 0x57, 0x86, - 0xfe, 0x75, 0x95, 0x30, 0xed, 0xf7, 0xc4, 0x6c, 0xe8, 0xd2, 0x54, 0xff, - 0x85, 0x95, 0x98, 0x36, 0x5e, 0xf7, 0x4c, 0xea, 0xf3, 0x12, 0xa3, 0xa9, - 0xd9, 0xd0, 0x01, 0x7b, 0xda, 0xf2, 0x49, 0xe7, 0xf7, 0xe0, 0x1e, 0x53, - 0x30, 0xdd, 0xb2, 0xd9, 0x33, 0xbb, 0x96, 0x84, 0x92, 0xdd, 0x09, 0x31, - 0xbd, 0xe4, 0xa2, 0x6c, 0x32, 0x73, 0x85, 0x48, 0xae, 0x2f, 0x11, 0xbf, - 0x22, 0x9e, 0xc9, 0xcc, 0x37, 0x04, 0xe7, 0xcf, 0xc9, 0xb9, 0xfb, 0x15, - 0x32, 0xa3, 0x76, 0x82, 0x62, 0x8f, 0xe3, 0x55, 0x27, 0x3f, 0xf2, 0x3d, - 0xcb, 0x80, 0xea, 0x58, 0x89, 0x31, 0xba, 0x37, 0xf6, 0x50, 0x1e, 0x1d, - 0xb4, 0x39, 0xe7, 0xe4, 0x91, 0x52, 0xcb, 0x6a, 0x39, 0x40, 0xb7, 0xd3, - 0xa3, 0x94, 0xe3, 0x94, 0xf3, 0xc6, 0x24, 0xf5, 0xe2, 0xa9, 0x5a, 0x15, - 0x55, 0xce, 0x11, 0xca, 0x75, 0x42, 0x2a, 0xb7, 0xf4, 0x3e, 0x30, 0xfe, - 0x16, 0xa0, 0xd6, 0x00, 0xcd, 0xe6, 0x84, 0x33, 0x23, 0xa7, 0xa8, 0x7e, - 0x0c, 0xf8, 0x8c, 0x67, 0xf5, 0x3d, 0x82, 0x3f, 0xc8, 0x93, 0x55, 0x8c, - 0x9f, 0xc1, 0x86, 0x34, 0xc4, 0xe3, 0x76, 0x0c, 0x46, 0x8d, 0x8e, 0x7e, - 0xea, 0xe7, 0x8a, 0x63, 0xcd, 0x8c, 0x72, 0x7f, 0xab, 0x81, 0x5b, 0x41, - 0xf3, 0x46, 0x51, 0x86, 0xd3, 0x2c, 0x03, 0xc1, 0x22, 0x71, 0xe3, 0xf0, - 0x42, 0x71, 0x03, 0xdf, 0x01, 0x52, 0x58, 0x55, 0x86, 0x26, 0xfb, 0x34, - 0xad, 0x72, 0xce, 0x46, 0x9d, 0x88, 0x38, 0x31, 0x0c, 0x3d, 0x67, 0x53, - 0xe7, 0xaf, 0x92, 0xf2, 0x60, 0xca, 0x40, 0xde, 0x2e, 0xa1, 0x99, 0x3a, - 0x8c, 0x2a, 0x0b, 0x7a, 0xc2, 0xb1, 0xee, 0x39, 0x8c, 0xaf, 0xc0, 0xa8, - 0x43, 0x54, 0xa5, 0x7e, 0x4c, 0x6b, 0x62, 0xdc, 0x2e, 0xa3, 0x39, 0x5f, - 0x20, 0xe1, 0x24, 0xb0, 0xdd, 0xe7, 0x7a, 0x60, 0xf5, 0x1d, 0xa6, 0x1a, - 0x50, 0xac, 0x79, 0x3f, 0xa0, 0xb9, 0x47, 0x34, 0x54, 0x3a, 0xbc, 0xcf, - 0xeb, 0x97, 0xf3, 0x7c, 0x5e, 0x98, 0xc5, 0xb6, 0xd3, 0xbe, 0xe4, 0xde, - 0x5e, 0x83, 0x18, 0xc9, 0x9b, 0x18, 0xa5, 0xfb, 0x02, 0xdb, 0x28, 0xe2, - 0x90, 0xe6, 0x75, 0xd0, 0xcb, 0x1c, 0xcb, 0x7d, 0x08, 0x5d, 0x40, 0x35, - 0xcf, 0x11, 0xd0, 0x4a, 0x1c, 0x1b, 0xcf, 0x7a, 0xdf, 0xa7, 0xb3, 0x90, - 0x79, 0xd7, 0x86, 0x46, 0xfc, 0x90, 0xa0, 0xbc, 0x8c, 0xb5, 0x53, 0x2c, - 0x50, 0xff, 0x3f, 0x60, 0x23, 0xd6, 0xe0, 0x58, 0xc7, 0x8e, 0x50, 0x2c, - 0x18, 0x0b, 0xa0, 0x28, 0xa9, 0x57, 0xc0, 0xf3, 0xbb, 0xea, 0xf0, 0xde, - 0x04, 0x4e, 0xea, 0x88, 0x95, 0x38, 0x56, 0xd7, 0x38, 0x05, 0x82, 0xee, - 0x3c, 0x04, 0xbb, 0xaa, 0x90, 0x93, 0xc4, 0xa7, 0x93, 0xf8, 0x80, 0xeb, - 0xa0, 0x16, 0xa5, 0xe7, 0x17, 0x9b, 0xa4, 0x8c, 0x35, 0x5b, 0xbd, 0x79, - 0x98, 0x3d, 0x93, 0x42, 0xc5, 0xce, 0xdd, 0x5c, 0xf3, 0xa6, 0x4c, 0x6a, - 0x9f, 0xd4, 0xb7, 0xa3, 0xa2, 0xe4, 0x3e, 0x05, 0xcd, 0xcb, 0x54, 0xbc, - 0x48, 0x35, 0xef, 0xd9, 0x14, 0xdf, 0xef, 0x5b, 0x63, 0xc5, 0xb9, 0x9e, - 0x7c, 0xff, 0x51, 0xbd, 0x98, 0xbf, 0x93, 0x19, 0x54, 0x33, 0xac, 0xae, - 0x87, 0xb1, 0x4b, 0x1a, 0x55, 0xec, 0x43, 0x9a, 0x85, 0x68, 0xd6, 0xac, - 0xa4, 0x5a, 0x99, 0xeb, 0xb0, 0x5a, 0x28, 0x9c, 0xdd, 0x8d, 0x1d, 0x0d, - 0xe4, 0x6f, 0x8e, 0x03, 0x59, 0xa9, 0x14, 0xfc, 0x24, 0xe5, 0x75, 0xe9, - 0xd6, 0x63, 0x6f, 0x87, 0x0e, 0xd2, 0x9c, 0xcb, 0x36, 0xbe, 0x9c, 0xf6, - 0xd9, 0xfe, 0x51, 0x91, 0xba, 0xdf, 0xa5, 0xde, 0xc0, 0x67, 0x4a, 0x99, - 0x6c, 0xa3, 0x83, 0xca, 0x43, 0x34, 0x23, 0x22, 0xf3, 0xba, 0x07, 0x11, - 0x6b, 0xdf, 0x54, 0xb0, 0xc3, 0xe3, 0x76, 0x2d, 0xc5, 0x01, 0x62, 0x9a, - 0x63, 0xe9, 0x74, 0x71, 0x56, 0x1a, 0x9c, 0x2a, 0x5c, 0x47, 0xd2, 0x64, - 0x7d, 0xce, 0xb7, 0x4e, 0xec, 0xf7, 0xf8, 0xfb, 0x47, 0x27, 0x36, 0x12, - 0x8f, 0x49, 0xcb, 0x22, 0x1d, 0xcd, 0xf5, 0x03, 0x22, 0x2a, 0x9e, 0x1f, - 0x22, 0x3d, 0x77, 0x33, 0x6f, 0x15, 0xcd, 0x4d, 0x2a, 0x56, 0x35, 0xf1, - 0x4c, 0x3c, 0x65, 0xaa, 0x60, 0xfd, 0xfe, 0x24, 0x9b, 0xdb, 0x98, 0xce, - 0xa2, 0xbb, 0x87, 0xa0, 0x5a, 0x97, 0xc5, 0x66, 0x5d, 0xa0, 0xcf, 0xa6, - 0x28, 0x5e, 0xa0, 0xc2, 0x6e, 0x53, 0xd1, 0x6b, 0xef, 0x05, 0x85, 0x06, - 0xd5, 0x38, 0x0d, 0x9b, 0xec, 0x2c, 0xdc, 0x38, 0xfb, 0xf2, 0x1f, 0x25, - 0xae, 0x66, 0xbb, 0xec, 0x98, 0xb3, 0xd1, 0x9e, 0xc2, 0xb7, 0x82, 0x23, - 0x3e, 0xe3, 0x45, 0xc5, 0xa9, 0x21, 0x57, 0xb0, 0x3e, 0x1f, 0xdb, 0x93, - 0x75, 0x62, 0x19, 0xea, 0xc4, 0xce, 0x61, 0x64, 0x76, 0x74, 0x48, 0xb9, - 0x39, 0x65, 0x76, 0xbd, 0x00, 0x05, 0xc9, 0xe1, 0x30, 0x9e, 0x5e, 0xd2, - 0x27, 0x5d, 0x7d, 0x85, 0x49, 0x79, 0xae, 0x53, 0x54, 0x63, 0xa0, 0xd9, - 0x9c, 0x59, 0x49, 0x5c, 0x7f, 0xe7, 0x37, 0xe0, 0x0d, 0x9b, 0x62, 0xcc, - 0x52, 0xfb, 0x3a, 0x43, 0xdc, 0xf7, 0x37, 0x12, 0x9f, 0x26, 0xb7, 0x52, - 0xb1, 0x7a, 0x26, 0x28, 0xcf, 0x2a, 0x9c, 0x1e, 0xb9, 0xb3, 0x96, 0x63, - 0x10, 0x4a, 0x34, 0xf5, 0x35, 0x39, 0x55, 0xcb, 0xb1, 0xc8, 0x73, 0x59, - 0x54, 0xe8, 0xc3, 0x7c, 0x3e, 0xcf, 0x69, 0x2a, 0xc2, 0x49, 0x29, 0xc7, - 0xed, 0xcd, 0x24, 0x2b, 0xcb, 0x30, 0x2f, 0xeb, 0x26, 0x99, 0xa9, 0x42, - 0x2c, 0xea, 0x58, 0xbd, 0x93, 0x54, 0xa3, 0x23, 0x4e, 0x2b, 0xdd, 0x7b, - 0xaf, 0x93, 0xc5, 0x39, 0x94, 0xfb, 0x7e, 0x54, 0x8c, 0x0f, 0x31, 0x0f, - 0xf6, 0xcd, 0xb9, 0x7a, 0x40, 0xa3, 0xfb, 0x33, 0x26, 0xb2, 0x02, 0xfb, - 0x52, 0x7d, 0xb2, 0x47, 0x67, 0x7e, 0x51, 0xf1, 0xec, 0xd0, 0xc7, 0x67, - 0x7e, 0x1a, 0x7f, 0xef, 0x9c, 0x9d, 0xbe, 0x54, 0x8c, 0x09, 0xbf, 0x18, - 0xa3, 0x25, 0xce, 0xcb, 0x14, 0xfb, 0xca, 0x6a, 0xba, 0x9d, 0x41, 0x4f, - 0x09, 0x3c, 0xd5, 0x29, 0x70, 0xdd, 0x12, 0x9a, 0xc1, 0x96, 0x5a, 0x14, - 0x27, 0xd7, 0x48, 0x63, 0xc1, 0x14, 0x05, 0xdc, 0xac, 0x2c, 0x4d, 0xaa, - 0x78, 0x67, 0x09, 0x25, 0xd1, 0x55, 0x1c, 0xab, 0x0a, 0x5e, 0x20, 0xbc, - 0xd5, 0x17, 0x59, 0x5d, 0x47, 0x51, 0x01, 0xe3, 0x2b, 0xbc, 0xb6, 0x62, - 0x43, 0x18, 0xad, 0x09, 0x1d, 0x16, 0xf9, 0xbc, 0x86, 0x67, 0x69, 0x92, - 0x9f, 0x69, 0xe7, 0x63, 0xdb, 0x2b, 0xc8, 0xd1, 0xbc, 0x8c, 0x9f, 0x59, - 0xbe, 0x8f, 0xdf, 0x07, 0x86, 0x58, 0x3e, 0xf6, 0x17, 0xf9, 0x9a, 0x64, - 0x2e, 0x49, 0xcd, 0xc7, 0xc5, 0x6d, 0x73, 0xb2, 0x46, 0x69, 0xae, 0x61, - 0x9a, 0x62, 0x0c, 0x9d, 0xa0, 0xf8, 0x19, 0xff, 0x08, 0x87, 0x2c, 0x58, - 0xce, 0xe7, 0x70, 0xac, 0x08, 0x60, 0xad, 0x82, 0xd4, 0x32, 0x9e, 0x11, - 0x28, 0x06, 0x86, 0xcd, 0x4e, 0x43, 0x59, 0x44, 0xfb, 0x4c, 0x1b, 0x25, - 0xbf, 0xf3, 0x7b, 0xf1, 0x9c, 0x5b, 0x9a, 0x38, 0xce, 0x5b, 0xe7, 0xfc, - 0xf1, 0x0b, 0xbd, 0x38, 0xc3, 0x46, 0xa9, 0xe7, 0x81, 0xf6, 0x19, 0x4f, - 0xc5, 0x1a, 0xc6, 0x49, 0xcd, 0xe3, 0xcc, 0xc7, 0xe8, 0xbf, 0x10, 0xee, - 0x9f, 0x64, 0xaa, 0x8d, 0xfb, 0x75, 0x54, 0x5c, 0x37, 0xc4, 0xb8, 0x45, - 0x7b, 0x7f, 0xd8, 0x4c, 0xf8, 0xed, 0xe7, 0xe2, 0xbf, 0xfc, 0x09, 0xfc, - 0xcf, 0xf4, 0x77, 0x82, 0x2e, 0xb1, 0xc3, 0xa3, 0x0b, 0xbf, 0xa5, 0x5c, - 0x56, 0x4e, 0x79, 0xfd, 0x10, 0xf5, 0xf9, 0x83, 0x23, 0x5d, 0x62, 0x3b, - 0x99, 0xe7, 0xc0, 0xd8, 0x2a, 0x71, 0xb7, 0x67, 0xf1, 0x2c, 0x39, 0xd7, - 0xf3, 0x8b, 0xdf, 0xf7, 0xb6, 0x7d, 0xea, 0xbb, 0x5d, 0xa4, 0x47, 0x77, - 0xd0, 0x5d, 0x3f, 0x78, 0x97, 0x6c, 0xb0, 0xb8, 0x9e, 0x59, 0x53, 0x17, - 0x87, 0x22, 0x9d, 0xb1, 0xe5, 0x21, 0x44, 0x2d, 0x74, 0xc7, 0x68, 0xd6, - 0x7a, 0xb1, 0xd0, 0xe3, 0x0c, 0x18, 0xb9, 0x81, 0xda, 0x62, 0x0c, 0x48, - 0x49, 0x75, 0x5f, 0xad, 0x74, 0xd0, 0x53, 0xe2, 0x94, 0x68, 0x97, 0x74, - 0x44, 0x90, 0xeb, 0xe8, 0xaa, 0x3f, 0x9e, 0xbb, 0xac, 0xfe, 0xb9, 0x5c, - 0x5d, 0x0f, 0xdd, 0x7d, 0xeb, 0x7f, 0xe6, 0x01, 0x67, 0x48, 0x86, 0xb0, - 0x73, 0xa5, 0xbb, 0x2f, 0x0d, 0xa5, 0xb7, 0xc3, 0x32, 0x16, 0x8b, 0x75, - 0xeb, 0x48, 0x87, 0xfa, 0x63, 0xb9, 0x3b, 0xd7, 0x85, 0x26, 0xa9, 0xdb, - 0xe9, 0xb8, 0xf3, 0xed, 0xf4, 0x9d, 0xd8, 0xe2, 0xf5, 0x61, 0x93, 0x17, - 0x2f, 0xd4, 0xa8, 0x5d, 0x2c, 0x93, 0xcf, 0xdf, 0xec, 0x58, 0xd6, 0x08, - 0xb6, 0xe6, 0x55, 0xbc, 0x55, 0xd8, 0x33, 0x13, 0xab, 0xf1, 0x31, 0xee, - 0x67, 0xf1, 0x3e, 0xf9, 0x2d, 0x91, 0x63, 0x06, 0x99, 0xd0, 0xa0, 0x94, - 0x4a, 0x9a, 0xef, 0x7f, 0xd3, 0x34, 0x0b, 0x73, 0x8d, 0x79, 0x0f, 0xfb, - 0xad, 0x05, 0xfc, 0x2d, 0x91, 0x21, 0x53, 0x3a, 0xc8, 0x7b, 0xa7, 0xe7, - 0xf6, 0xde, 0xa1, 0x3d, 0x88, 0x53, 0xd4, 0xab, 0xa8, 0x8e, 0x17, 0xf6, - 0xcb, 0x07, 0x23, 0xf8, 0x7b, 0x9f, 0x71, 0x4e, 0xce, 0xe1, 0xfc, 0x8a, - 0x70, 0xe2, 0x58, 0x53, 0x05, 0xb7, 0x92, 0x73, 0x6b, 0x78, 0xfe, 0x5b, - 0x23, 0xe5, 0x89, 0xfd, 0x61, 0xb4, 0xf8, 0xad, 0x31, 0x2a, 0xb4, 0xfb, - 0xe8, 0x39, 0xca, 0x71, 0xc8, 0xb1, 0xca, 0xf4, 0xc7, 0x53, 0x45, 0xfa, - 0x63, 0x29, 0xa6, 0xff, 0x2c, 0x8d, 0x9a, 0x89, 0x0c, 0xc6, 0xa9, 0xfe, - 0xbe, 0x4b, 0xb5, 0xa0, 0xc8, 0xbb, 0x48, 0xf7, 0x4f, 0x73, 0x74, 0x87, - 0x89, 0xee, 0x0f, 0x14, 0x87, 0x4c, 0xcb, 0x7a, 0x72, 0x6e, 0xcc, 0xfb, - 0xaf, 0x45, 0x1c, 0xf2, 0x0c, 0x1c, 0xca, 0xa9, 0x62, 0x1f, 0xd5, 0xda, - 0x31, 0xba, 0xb7, 0x0c, 0x14, 0xbe, 0xa5, 0xea, 0x64, 0x93, 0x17, 0xaa, - 0x8a, 0xfe, 0xe2, 0xef, 0xcb, 0x53, 0x58, 0xe1, 0x25, 0xa9, 0xf7, 0x6b, - 0x05, 0x9d, 0x4a, 0x9d, 0xa7, 0xf1, 0x5b, 0xaa, 0x97, 0xa7, 0x0a, 0xdf, - 0x6f, 0x9e, 0x46, 0x32, 0xc7, 0x73, 0x8f, 0x25, 0x36, 0x79, 0x46, 0x8f, - 0x42, 0xbc, 0x57, 0xe5, 0x8a, 0x35, 0x84, 0xfa, 0x5b, 0x86, 0x6a, 0xb3, - 0x78, 0xa6, 0xf0, 0x5e, 0x43, 0x3d, 0x8f, 0x65, 0xc8, 0x88, 0x44, 0xd2, - 0x45, 0x43, 0xd2, 0x95, 0xaa, 0x65, 0x1d, 0x53, 0x43, 0x96, 0xfe, 0x4e, - 0x28, 0x73, 0x8b, 0x82, 0xbb, 0xf0, 0x7e, 0x7b, 0xe6, 0x6f, 0xea, 0xe9, - 0x6f, 0x65, 0x3b, 0x8c, 0x0a, 0xca, 0xf3, 0x1b, 0x3a, 0x9a, 0x32, 0x2f, - 0x89, 0xa6, 0xee, 0xac, 0x68, 0x72, 0xd7, 0x88, 0xa6, 0xce, 0x32, 0x61, - 0x6b, 0xcf, 0x51, 0x13, 0x7f, 0x39, 0x37, 0x6f, 0x07, 0xf6, 0x1f, 0xdb, - 0x80, 0xc2, 0xdc, 0xb1, 0x32, 0x8b, 0x45, 0x8c, 0xee, 0xfe, 0x9c, 0x0f, - 0x0d, 0xa0, 0x5e, 0x74, 0x36, 0xd7, 0xd1, 0xba, 0x7e, 0x97, 0x28, 0xa3, - 0x7a, 0xa0, 0x63, 0x2f, 0xcd, 0x27, 0x0d, 0x16, 0xc7, 0x27, 0x35, 0xc8, - 0x05, 0x2c, 0xcf, 0xcf, 0x23, 0x45, 0xfd, 0xd6, 0x55, 0x17, 0xf3, 0x4f, - 0x50, 0x9d, 0x83, 0x16, 0xa3, 0x58, 0x7d, 0x9f, 0xea, 0xda, 0xef, 0x9a, - 0x8a, 0x71, 0xbb, 0x94, 0xbf, 0x03, 0x17, 0xf0, 0x8e, 0x4b, 0xba, 0x5b, - 0x91, 0x4e, 0xe7, 0x31, 0x3e, 0xe9, 0x3b, 0x55, 0xfd, 0x69, 0xfa, 0xa2, - 0x6d, 0x15, 0x9a, 0x01, 0x8e, 0xe4, 0x33, 0x62, 0xb5, 0x87, 0x2d, 0xa1, - 0x82, 0xfe, 0x06, 0x56, 0xe7, 0xba, 0xc4, 0x2a, 0xcf, 0x32, 0x06, 0xc8, - 0x06, 0xdb, 0xf4, 0x56, 0x7d, 0x8c, 0xea, 0x16, 0xf1, 0x32, 0x4a, 0x29, - 0x07, 0x34, 0x67, 0x01, 0xee, 0x99, 0x8b, 0x29, 0xca, 0x0b, 0xb7, 0xcc, - 0xe9, 0x13, 0x8b, 0x27, 0xf8, 0x95, 0xf8, 0x7c, 0xa4, 0xdf, 0x87, 0x72, - 0xfb, 0x55, 0xbc, 0xdf, 0x3f, 0xe7, 0x93, 0x9b, 0xf9, 0x4c, 0x7a, 0x3f, - 0x35, 0x27, 0xc3, 0xff, 0x44, 0x3b, 0x71, 0xfe, 0xa7, 0x69, 0x78, 0xae, - 0xe3, 0x3b, 0x05, 0xdc, 0x6a, 0x87, 0x67, 0xba, 0x85, 0x73, 0xb1, 0x30, - 0x4c, 0xbc, 0xb7, 0xe0, 0xca, 0x65, 0x40, 0xf3, 0xe0, 0x42, 0x6c, 0xcf, - 0x03, 0x2d, 0x83, 0x3c, 0x63, 0xcf, 0xc2, 0xcb, 0x42, 0x2b, 0x73, 0x66, - 0x70, 0x61, 0xb6, 0xb1, 0xb7, 0x54, 0x98, 0x2d, 0x59, 0x61, 0x76, 0x03, - 0xad, 0x34, 0x7d, 0x98, 0x89, 0xc5, 0xc2, 0x34, 0x36, 0x83, 0x6d, 0x35, - 0x8b, 0xa6, 0x42, 0xae, 0xcf, 0xc0, 0x22, 0x7f, 0x77, 0x0f, 0x86, 0xa0, - 0xb4, 0xfd, 0x8e, 0x6c, 0x66, 0x76, 0x42, 0x2c, 0xa4, 0xf9, 0x96, 0x63, - 0x72, 0x16, 0x5b, 0xa9, 0x4f, 0xd7, 0x13, 0xce, 0xe7, 0xa9, 0x07, 0x34, - 0x0e, 0x9a, 0x33, 0x80, 0xd9, 0x77, 0x71, 0xa8, 0xb1, 0xa5, 0x17, 0xe6, - 0x96, 0x6d, 0x68, 0x9d, 0x7a, 0x46, 0x98, 0x99, 0x19, 0x21, 0x50, 0xda, - 0x56, 0xe4, 0xb9, 0x74, 0x8e, 0x67, 0x0b, 0xdf, 0x37, 0x0a, 0xb9, 0x45, - 0x77, 0x92, 0xb6, 0x5f, 0xc8, 0xa9, 0x82, 0xcd, 0xfe, 0x7a, 0x4e, 0xff, - 0xec, 0x9c, 0x0f, 0xd4, 0xb9, 0xf7, 0x9f, 0x54, 0x73, 0x7d, 0x2f, 0x69, - 0x2b, 0xcc, 0xe3, 0x14, 0x97, 0x5f, 0x44, 0x3f, 0xcd, 0x7e, 0x99, 0x02, - 0x7d, 0x17, 0x7a, 0x72, 0x10, 0x9b, 0xbd, 0xa9, 0xd2, 0x67, 0x68, 0xaa, - 0x1e, 0x29, 0xf0, 0xb9, 0x8c, 0xd6, 0xba, 0xe9, 0xc7, 0x36, 0xfb, 0xaf, - 0x4a, 0xbe, 0x3d, 0x38, 0xaa, 0xfb, 0x4a, 0xf3, 0xbb, 0xfd, 0x90, 0x5a, - 0xef, 0xab, 0x27, 0x2d, 0x03, 0x56, 0x37, 0x7d, 0x5b, 0x6a, 0x5b, 0xb2, - 0xb9, 0x0d, 0xcd, 0x22, 0x7b, 0xb5, 0x4b, 0x1b, 0x84, 0x2c, 0x82, 0xb1, - 0x65, 0x1b, 0xc7, 0xb8, 0xd6, 0xb5, 0x56, 0xb0, 0x31, 0x18, 0x3b, 0x89, - 0xec, 0xe1, 0x0f, 0x25, 0x9e, 0x1d, 0xf5, 0x48, 0x20, 0x04, 0xf4, 0x4b, - 0x12, 0x2c, 0xb0, 0x55, 0x53, 0x6e, 0xf4, 0x00, 0xe2, 0xb4, 0x24, 0xbc, - 0x99, 0xd4, 0x2a, 0xa9, 0x9a, 0xb1, 0x62, 0xc4, 0x2b, 0x36, 0xc6, 0x9e, - 0xc9, 0x6c, 0x91, 0x2d, 0xbb, 0xcc, 0x40, 0x00, 0x27, 0x7e, 0xe1, 0xcc, - 0x4c, 0x2c, 0xc6, 0x89, 0xef, 0x7e, 0xe7, 0xde, 0x6e, 0x10, 0x84, 0xc4, - 0x35, 0x54, 0xa9, 0xda, 0xdd, 0xf7, 0xf7, 0x3c, 0xbf, 0x73, 0xbe, 0xf3, - 0x9d, 0x73, 0x7e, 0xd7, 0x92, 0xcb, 0x58, 0xcb, 0xff, 0x0e, 0x9b, 0xed, - 0x36, 0x45, 0xd1, 0x98, 0x1b, 0xbc, 0x6a, 0x9c, 0x53, 0x2d, 0x1d, 0xb1, - 0x99, 0x1c, 0xbd, 0x59, 0x9e, 0x25, 0x25, 0x77, 0xb3, 0x3e, 0xe4, 0xf7, - 0x74, 0x9b, 0xbc, 0xdf, 0x83, 0x67, 0xd2, 0x1e, 0x6c, 0x20, 0xb6, 0xa6, - 0x4c, 0x6c, 0xbd, 0x1e, 0x1f, 0xd9, 0xd8, 0x6e, 0x05, 0xdb, 0xf5, 0x64, - 0xb8, 0x53, 0x73, 0xfa, 0xac, 0xa9, 0x2b, 0x8e, 0x26, 0x39, 0x07, 0x91, - 0xbd, 0xc4, 0x76, 0xd9, 0xd8, 0x57, 0xce, 0x24, 0xac, 0x0c, 0x46, 0x5b, - 0x95, 0xfe, 0x68, 0x31, 0xe7, 0x8b, 0x28, 0xc9, 0x90, 0x6d, 0x77, 0x29, - 0xe3, 0xa9, 0x15, 0x8b, 0x56, 0x12, 0x7f, 0xb4, 0x80, 0x66, 0x2b, 0xc1, - 0xb3, 0x81, 0x39, 0x98, 0x52, 0x97, 0x62, 0x73, 0x20, 0x87, 0x5c, 0x69, - 0x3f, 0x36, 0xaa, 0xb9, 0xd8, 0x14, 0xf8, 0x0b, 0xe0, 0xe1, 0x3c, 0xea, - 0xb1, 0xc5, 0x39, 0x73, 0x38, 0x6f, 0x1e, 0x31, 0xe3, 0x39, 0x73, 0xdf, - 0xe3, 0xb2, 0x57, 0xae, 0xb3, 0x59, 0x49, 0x12, 0xf3, 0x2b, 0x4c, 0xdb, - 0x9d, 0xf9, 0x7e, 0x28, 0x65, 0xe6, 0x60, 0x5f, 0x5e, 0x6c, 0xca, 0xf9, - 0xf7, 0xdf, 0xd7, 0xd3, 0xab, 0xcb, 0xc9, 0xd3, 0xa9, 0x3f, 0xcb, 0x11, - 0xae, 0x5c, 0x82, 0xe7, 0x03, 0x8d, 0x28, 0xd2, 0x9a, 0xf1, 0x6d, 0x35, - 0x42, 0x4c, 0x1f, 0xc2, 0x77, 0xcc, 0x31, 0x64, 0x3c, 0xb3, 0x66, 0xc4, - 0x7f, 0xbf, 0xb3, 0x43, 0xfb, 0xba, 0xf8, 0xd2, 0xca, 0xc9, 0xb4, 0xdb, - 0x9c, 0xe8, 0x19, 0x90, 0x4f, 0x07, 0xbe, 0x13, 0xb2, 0x72, 0xb0, 0xf1, - 0x21, 0x27, 0x62, 0x03, 0x0e, 0xa4, 0x83, 0x64, 0x3f, 0x95, 0x37, 0x8f, - 0x3d, 0xc4, 0xb1, 0xad, 0xbc, 0xc5, 0x77, 0x29, 0xd7, 0x73, 0x4e, 0x27, - 0xb9, 0x10, 0xd4, 0x0a, 0xb6, 0x29, 0x1f, 0x2f, 0x80, 0x7b, 0x48, 0xea, - 0x4e, 0x93, 0xca, 0x96, 0xb4, 0xd5, 0xe6, 0x7b, 0x52, 0xab, 0xca, 0xb5, - 0x81, 0xbe, 0x88, 0xdb, 0x75, 0xb0, 0x8d, 0x8b, 0x71, 0x71, 0x3e, 0x6a, - 0x86, 0x0a, 0xf8, 0xa7, 0xa2, 0xf4, 0x20, 0x1f, 0x8c, 0x37, 0x2b, 0x2f, - 0x46, 0x03, 0x28, 0x65, 0xbc, 0x5e, 0xd6, 0x64, 0xf5, 0x7f, 0x29, 0xfd, - 0x75, 0xeb, 0x77, 0xa2, 0xbd, 0x54, 0xce, 0xab, 0x06, 0x85, 0xda, 0x94, - 0xf1, 0x82, 0x85, 0xf1, 0xa6, 0x2f, 0xed, 0xbe, 0x56, 0xe7, 0x92, 0x35, - 0x29, 0xc2, 0x5b, 0xd5, 0xf2, 0x26, 0x89, 0x9b, 0xf9, 0xa3, 0x19, 0x77, - 0xcb, 0x1a, 0x64, 0xec, 0x7c, 0xe4, 0x0e, 0xc9, 0xd8, 0x05, 0xc8, 0xb9, - 0xb6, 0x16, 0x99, 0x87, 0x61, 0xde, 0xb8, 0xf8, 0x57, 0x99, 0x6f, 0x52, - 0x19, 0x4c, 0xcb, 0x1a, 0xb2, 0xf3, 0x9e, 0x32, 0x9e, 0x51, 0x0b, 0xe8, - 0xcf, 0x87, 0x8d, 0x0d, 0x15, 0x86, 0xe1, 0x5f, 0x74, 0xdc, 0x48, 0xad, - 0x35, 0xb1, 0xd6, 0xd8, 0x9d, 0x70, 0x62, 0x17, 0xe5, 0xb6, 0x39, 0x78, - 0x58, 0x78, 0x5c, 0xe6, 0x5f, 0x56, 0x6e, 0x47, 0x28, 0xb7, 0xb9, 0x99, - 0x73, 0x9c, 0x54, 0x8e, 0x5e, 0xf3, 0xf7, 0xb2, 0x46, 0x59, 0x97, 0x82, - 0x72, 0x4d, 0xd6, 0x65, 0x43, 0x99, 0x96, 0x8f, 0x72, 0xca, 0xa7, 0xcc, - 0x5c, 0x53, 0xb3, 0xf2, 0x6e, 0x14, 0x6a, 0x09, 0xb9, 0x43, 0xe9, 0xb8, - 0xb5, 0xae, 0x29, 0xca, 0xe7, 0xcc, 0x35, 0x9d, 0x98, 0x2d, 0x67, 0xa1, - 0x57, 0x62, 0xd3, 0x33, 0xdf, 0xdf, 0x9a, 0x94, 0x71, 0xed, 0x74, 0x9c, - 0x0a, 0xb6, 0x87, 0xc4, 0x5f, 0xe0, 0xe5, 0xe5, 0x51, 0x4b, 0x06, 0x36, - 0xf3, 0x0c, 0xc4, 0x06, 0x64, 0xff, 0xd9, 0xbd, 0x37, 0x2b, 0x4f, 0x45, - 0xa5, 0xbf, 0x86, 0x1a, 0xb3, 0x9f, 0x15, 0x37, 0xdb, 0xa8, 0x7f, 0xcb, - 0x79, 0x36, 0xb6, 0x71, 0x4b, 0x37, 0x3d, 0xa9, 0x56, 0xce, 0x2b, 0xe7, - 0x34, 0xa9, 0x74, 0x72, 0x4e, 0x98, 0x67, 0xfb, 0x5f, 0xcb, 0x2d, 0x5b, - 0x9f, 0xa4, 0x6d, 0xf2, 0x37, 0xa7, 0x8d, 0xfa, 0x5e, 0x00, 0xc7, 0x90, - 0xcb, 0xcc, 0xf1, 0xc8, 0xd8, 0xcf, 0x45, 0xcb, 0x90, 0x77, 0x30, 0xdb, - 0xd7, 0xf2, 0xed, 0x56, 0x8d, 0x30, 0x6b, 0x8f, 0x82, 0x8f, 0xe2, 0x27, - 0x22, 0x4a, 0xf8, 0x5a, 0x9d, 0x4f, 0x72, 0x5f, 0x52, 0xff, 0xcc, 0xe5, - 0x7a, 0x24, 0x7f, 0xaa, 0x10, 0x33, 0x6c, 0xc4, 0xe9, 0xe5, 0x1e, 0x07, - 0x71, 0x6e, 0x03, 0xbe, 0x34, 0x22, 0x15, 0xe1, 0x80, 0x13, 0x56, 0x8c, - 0xde, 0x8e, 0x5c, 0x58, 0x18, 0x44, 0x2d, 0x8d, 0xd2, 0x1f, 0x73, 0xaf, - 0xe4, 0x00, 0xe8, 0x4e, 0x7f, 0x69, 0x4c, 0x55, 0x38, 0xe8, 0xf3, 0xaf, - 0xe5, 0xd6, 0x68, 0x77, 0x86, 0x31, 0xcc, 0x67, 0xbd, 0xe9, 0xec, 0x39, - 0x91, 0x5b, 0x90, 0x6b, 0x3e, 0xad, 0xfd, 0xbb, 0xb1, 0xfe, 0x86, 0xb6, - 0x59, 0x6c, 0xb6, 0x62, 0xed, 0x23, 0x26, 0x36, 0x17, 0xa2, 0x77, 0xb7, - 0x37, 0x99, 0x02, 0x79, 0x8b, 0x66, 0x9b, 0x2b, 0x31, 0x82, 0x1d, 0xde, - 0xbe, 0x66, 0xc6, 0xfa, 0xc4, 0x4e, 0x4f, 0x0a, 0xff, 0x5c, 0x2e, 0x76, - 0xc4, 0x78, 0xcd, 0x53, 0x6a, 0x2b, 0x93, 0xb5, 0x9b, 0xab, 0xb2, 0x0f, - 0xe4, 0x61, 0x43, 0x43, 0x1e, 0x52, 0x6d, 0xc4, 0xac, 0x81, 0x48, 0x2b, - 0x87, 0x77, 0xe5, 0x37, 0xbd, 0xf5, 0xbd, 0x6f, 0xf8, 0xbd, 0xf4, 0x93, - 0x40, 0x6e, 0x8c, 0x73, 0x22, 0x83, 0x69, 0x03, 0xde, 0x88, 0xcd, 0x26, - 0xfd, 0x7f, 0x6b, 0x90, 0x63, 0xb3, 0xaf, 0x8c, 0xc1, 0xb9, 0xff, 0xc8, - 0x16, 0x24, 0xee, 0xfb, 0xb2, 0x5c, 0xf2, 0x8e, 0x6a, 0xad, 0x82, 0xc2, - 0x81, 0x42, 0x14, 0x30, 0x4e, 0xdf, 0x55, 0xe9, 0xeb, 0xd0, 0x6d, 0xf9, - 0x38, 0x7d, 0xd7, 0x7f, 0x41, 0xaa, 0x32, 0x07, 0xae, 0x5a, 0x60, 0x45, - 0xdc, 0x06, 0x5b, 0x2d, 0xb1, 0x37, 0x04, 0x34, 0x8f, 0xf3, 0xdc, 0x06, - 0x14, 0x3c, 0x91, 0xb4, 0xe1, 0xc1, 0xa4, 0x1d, 0xab, 0x93, 0xf8, 0xab, - 0x1a, 0x60, 0xba, 0x1a, 0xfe, 0xf6, 0x19, 0x05, 0x9b, 0x8b, 0x61, 0xfa, - 0xf8, 0xd6, 0xd5, 0x8c, 0x4b, 0x57, 0x8d, 0x13, 0xcf, 0xd8, 0xd6, 0xc9, - 0x98, 0xcd, 0xd1, 0x6f, 0x47, 0x75, 0x3f, 0x6e, 0xcf, 0x05, 0x42, 0x4e, - 0xf8, 0x67, 0xe8, 0x67, 0xca, 0x1c, 0xf0, 0x4f, 0x9d, 0xb7, 0xfb, 0x3b, - 0xab, 0xed, 0x3c, 0xdc, 0x5a, 0x59, 0x8b, 0x0b, 0x0f, 0x51, 0x9f, 0x6b, - 0x06, 0xd8, 0xbe, 0xd6, 0x06, 0x55, 0x53, 0x70, 0xe5, 0x71, 0xc9, 0xfb, - 0xca, 0x33, 0xc9, 0x55, 0x28, 0x28, 0x1e, 0xb0, 0x13, 0xc3, 0xde, 0x34, - 0x4e, 0x57, 0x0a, 0x7e, 0x03, 0x4f, 0x70, 0x6d, 0x6e, 0xfe, 0xa6, 0xd6, - 0xba, 0xb0, 0x70, 0xa9, 0x8a, 0x75, 0x43, 0x5f, 0x9a, 0x3a, 0x25, 0xe3, - 0x38, 0x69, 0x53, 0x39, 0xb4, 0xf1, 0x83, 0x66, 0x0d, 0xd1, 0xc6, 0x3d, - 0xda, 0x51, 0x30, 0x00, 0xac, 0x8a, 0xe3, 0x91, 0x42, 0xf8, 0xc3, 0xb2, - 0xc6, 0xba, 0x25, 0x0e, 0xf6, 0x2d, 0x44, 0xeb, 0xb8, 0xd5, 0xef, 0xfe, - 0xf1, 0x92, 0x0a, 0x2b, 0x07, 0xfe, 0xa7, 0x6b, 0xda, 0x3d, 0x21, 0x3f, - 0x36, 0x24, 0xa9, 0x73, 0x36, 0x0f, 0x86, 0x32, 0xb9, 0xe8, 0xf5, 0x29, - 0xef, 0xac, 0x9a, 0xf3, 0xdf, 0x14, 0x66, 0xea, 0xd1, 0xb4, 0x85, 0x19, - 0x8e, 0x13, 0x51, 0xd6, 0x53, 0x76, 0x43, 0x13, 0x06, 0xa2, 0xba, 0x81, - 0x31, 0xfe, 0xbd, 0xad, 0x4b, 0xde, 0x63, 0x52, 0x79, 0x26, 0xf6, 0x95, - 0x11, 0xc9, 0xd8, 0xf3, 0x0f, 0x12, 0x01, 0x65, 0x53, 0x0c, 0x78, 0x95, - 0xfe, 0xf4, 0x10, 0xff, 0x46, 0x12, 0x92, 0x47, 0xa2, 0xec, 0x69, 0xd7, - 0xdb, 0x52, 0xc0, 0x70, 0x02, 0xe1, 0xfd, 0x4b, 0x84, 0xc3, 0x17, 0x70, - 0x3e, 0x5a, 0x0d, 0xdb, 0xa4, 0xf9, 0x77, 0x90, 0x7f, 0x13, 0x3c, 0x53, - 0xce, 0x87, 0xc0, 0x98, 0x03, 0xe1, 0x31, 0x02, 0xed, 0x58, 0x00, 0x53, - 0xf4, 0x81, 0x57, 0x47, 0x54, 0x14, 0x1d, 0x2a, 0xc3, 0xa7, 0xa3, 0xc4, - 0xc7, 0x03, 0x16, 0xef, 0xdf, 0x30, 0x26, 0xf5, 0x42, 0xd9, 0x9f, 0xd4, - 0xd7, 0xc5, 0x9e, 0xf2, 0x70, 0x28, 0x59, 0x66, 0xd6, 0xd8, 0x2f, 0xe8, - 0x1c, 0x5b, 0x95, 0xda, 0x68, 0x1b, 0x0e, 0x47, 0x7d, 0x9e, 0x3e, 0xea, - 0x7c, 0xc4, 0x21, 0x36, 0x16, 0xc2, 0xab, 0xd1, 0x6c, 0x8d, 0xcd, 0xc7, - 0x78, 0xd7, 0x09, 0x8f, 0xb3, 0x8c, 0xf2, 0x95, 0x67, 0x59, 0x5f, 0x2a, - 0x7b, 0x96, 0x7c, 0x7e, 0x96, 0xb7, 0xcc, 0xfe, 0xfd, 0xa4, 0x21, 0xb5, - 0xdf, 0xd7, 0x26, 0xbc, 0x7d, 0x29, 0xe8, 0xa6, 0xaf, 0x1c, 0xad, 0xf3, - 0x26, 0x23, 0x90, 0xf3, 0x0d, 0x71, 0x0d, 0x1f, 0x53, 0xf7, 0x03, 0x94, - 0xf5, 0x5f, 0xd3, 0xb7, 0x4b, 0x9e, 0xbc, 0x14, 0xbb, 0xfa, 0xcb, 0xb0, - 0xb3, 0x3f, 0x82, 0xde, 0x25, 0x6b, 0x71, 0x32, 0x6a, 0x60, 0x43, 0xd0, - 0xc0, 0xaa, 0xa0, 0x37, 0xf0, 0x03, 0xd4, 0x37, 0x1e, 0xc6, 0x43, 0xe4, - 0x10, 0x2a, 0x65, 0xf2, 0x24, 0x3e, 0xd8, 0xed, 0xc0, 0xb3, 0xfa, 0x37, - 0x69, 0xc3, 0x86, 0xf1, 0xab, 0xc5, 0xf3, 0x30, 0x94, 0xa8, 0x57, 0xbb, - 0xb9, 0xbe, 0xf0, 0x5a, 0x9e, 0x55, 0x83, 0x03, 0x1b, 0xf5, 0xbf, 0x62, - 0x5b, 0xb7, 0xcd, 0xa1, 0xc9, 0x77, 0x1b, 0xfd, 0xa9, 0x9c, 0x65, 0x84, - 0xfa, 0x65, 0xf9, 0xb2, 0x70, 0xa6, 0x3e, 0xf1, 0x6c, 0x48, 0x30, 0xbf, - 0x10, 0x27, 0x28, 0xb7, 0x37, 0x92, 0x61, 0x49, 0x45, 0x29, 0x1b, 0x43, - 0x5d, 0x78, 0x8a, 0x7c, 0xe3, 0x03, 0x12, 0x81, 0x7b, 0xe2, 0x0a, 0x1a, - 0xeb, 0x74, 0x9c, 0x4d, 0x3f, 0x89, 0x77, 0x46, 0x9a, 0xf0, 0x36, 0x7d, - 0xfa, 0xc2, 0xff, 0xe9, 0x65, 0x2c, 0xef, 0xc1, 0xe9, 0x74, 0x13, 0xde, - 0x8c, 0x7a, 0xdb, 0x5e, 0x20, 0x3f, 0xfa, 0x79, 0xda, 0x81, 0x3b, 0xe2, - 0x8c, 0x7b, 0x38, 0x8e, 0x3f, 0xee, 0xc0, 0xc5, 0xb4, 0x8a, 0xc3, 0x3c, - 0x1f, 0x47, 0x70, 0x21, 0xe3, 0x5e, 0x0f, 0x0e, 0x0e, 0x3e, 0x88, 0xa9, - 0xd4, 0x83, 0x38, 0x96, 0xfc, 0xc0, 0x70, 0x69, 0x52, 0x27, 0x73, 0xe1, - 0x22, 0x63, 0xb2, 0x69, 0x4a, 0xa3, 0x70, 0x69, 0x1b, 0xfd, 0xbc, 0x16, - 0x11, 0xb9, 0xbf, 0xc3, 0xdf, 0xee, 0x89, 0x37, 0x62, 0xff, 0x18, 0x45, - 0x9a, 0xd0, 0x91, 0x88, 0xc9, 0x5c, 0x21, 0xc4, 0xc8, 0x0b, 0x77, 0xf5, - 0x1b, 0xf4, 0x17, 0x77, 0x48, 0x0c, 0xa2, 0xb4, 0xd6, 0xfe, 0x73, 0x66, - 0x1f, 0x8d, 0xb3, 0x6a, 0xa0, 0xf9, 0x3c, 0x1b, 0xca, 0x95, 0xfd, 0xfe, - 0x77, 0xa2, 0xc1, 0xf4, 0x4d, 0x47, 0xae, 0x9d, 0x47, 0x23, 0xcf, 0xe3, - 0x49, 0x9c, 0xdd, 0xbd, 0x16, 0xef, 0x10, 0xef, 0x8a, 0x17, 0xfb, 0x3a, - 0x9d, 0xb6, 0x7a, 0x8e, 0x9d, 0x36, 0x52, 0x95, 0x22, 0xd3, 0xb5, 0xf8, - 0x65, 0x54, 0x64, 0x9a, 0x26, 0xfe, 0xf9, 0x3c, 0x7e, 0xfb, 0x5b, 0xb4, - 0x09, 0xb7, 0xad, 0xbb, 0xc1, 0xaa, 0xe9, 0x15, 0x2e, 0x75, 0xe1, 0x92, - 0xb9, 0x36, 0x59, 0xeb, 0x9f, 0x5b, 0xdf, 0x2f, 0x8d, 0x55, 0x95, 0xb2, - 0xbe, 0x88, 0x91, 0xa3, 0x69, 0x81, 0x1c, 0x45, 0xfc, 0x6c, 0xc0, 0xac, - 0x63, 0xd4, 0xc5, 0xbb, 0x60, 0x0f, 0x16, 0x32, 0x3e, 0xf3, 0xce, 0x74, - 0xe0, 0x1d, 0x5c, 0x9e, 0x70, 0x61, 0x41, 0x3c, 0x80, 0x57, 0x26, 0x72, - 0x2b, 0x91, 0xff, 0x0b, 0x9c, 0xe7, 0x77, 0x5f, 0xdc, 0xb2, 0xb7, 0xee, - 0xd0, 0x5a, 0xac, 0x48, 0xcb, 0xfe, 0x9e, 0xe4, 0x44, 0x3a, 0xc2, 0x69, - 0xd9, 0x67, 0x8c, 0xb6, 0x21, 0xfb, 0x2c, 0xfb, 0x9a, 0x7d, 0xbe, 0xcb, - 0xb5, 0xcf, 0xa3, 0x2d, 0x65, 0x7d, 0x47, 0x11, 0x0e, 0x26, 0x55, 0x9c, - 0xd0, 0x8b, 0x70, 0x4e, 0x95, 0x7c, 0xbd, 0x8b, 0x3e, 0xc4, 0x81, 0x66, - 0xc6, 0x4b, 0xc3, 0xd1, 0x3c, 0x3c, 0xa3, 0x3a, 0x70, 0x4a, 0x77, 0xe0, - 0x98, 0x7e, 0x1b, 0xb1, 0x5e, 0xe2, 0x08, 0xd3, 0xbf, 0x90, 0x31, 0x65, - 0xf5, 0x58, 0x9e, 0x17, 0xc2, 0x53, 0x5a, 0x86, 0x37, 0x25, 0xef, 0x68, - 0xb6, 0x71, 0x49, 0xad, 0x17, 0x87, 0x28, 0xb3, 0x9c, 0x58, 0x39, 0x2e, - 0xb5, 0x35, 0xde, 0xa2, 0x1f, 0x69, 0xac, 0xf6, 0xb1, 0xb1, 0xb9, 0xf2, - 0xda, 0x98, 0x1e, 0x28, 0x47, 0x2a, 0x2c, 0x9c, 0xc8, 0xd6, 0xe1, 0xb2, - 0xbe, 0x6c, 0x76, 0xbf, 0xd9, 0xfb, 0x7c, 0xa1, 0x52, 0xb0, 0xc9, 0x61, - 0xc6, 0x82, 0x6d, 0xdf, 0xa4, 0x8f, 0xa2, 0xcf, 0x5e, 0xbb, 0x45, 0x62, - 0x43, 0x5b, 0xd3, 0xba, 0x6f, 0x2e, 0xd7, 0x72, 0x60, 0x37, 0xb9, 0xa0, - 0xe3, 0x65, 0x8b, 0xbf, 0xbb, 0x5e, 0xd6, 0xcc, 0xcf, 0xc2, 0x97, 0x17, - 0x98, 0x9f, 0xea, 0xcb, 0xbe, 0xd4, 0x75, 0x5f, 0x66, 0xf1, 0x63, 0xf3, - 0xae, 0x10, 0xfa, 0xf4, 0x88, 0x72, 0x7f, 0x48, 0x78, 0xe6, 0x6c, 0x8e, - 0x11, 0x50, 0x4e, 0x45, 0x23, 0x46, 0xb5, 0x96, 0x1f, 0x29, 0x26, 0xf7, - 0x6e, 0xf4, 0x6b, 0xc4, 0x6a, 0x89, 0xe9, 0x34, 0x9c, 0xe1, 0x79, 0x10, - 0x62, 0xa9, 0xe3, 0xff, 0x0f, 0xd1, 0xdd, 0x68, 0xcf, 0x37, 0x71, 0xc9, - 0x30, 0x76, 0x05, 0x25, 0x07, 0x21, 0xe3, 0x3a, 0xf0, 0x11, 0xcf, 0xf9, - 0x37, 0x23, 0x05, 0xf8, 0x30, 0xa5, 0xe1, 0x5c, 0x7a, 0x2d, 0x76, 0x4c, - 0x58, 0x1c, 0xe4, 0x58, 0xda, 0xe2, 0x44, 0x12, 0xd3, 0xef, 0x27, 0x47, - 0x88, 0x25, 0x5e, 0x37, 0xf2, 0x34, 0xdf, 0x94, 0xdf, 0xee, 0xc0, 0xbe, - 0xf4, 0x34, 0x26, 0xfa, 0x3f, 0x33, 0xec, 0x5a, 0x17, 0x3e, 0x0d, 0x4e, - 0x63, 0xfc, 0x80, 0xd4, 0x50, 0x43, 0xd8, 0x35, 0x18, 0x40, 0x6f, 0xc2, - 0x86, 0x9d, 0x4b, 0x5a, 0xb1, 0x6b, 0xa2, 0x05, 0x91, 0x43, 0x1e, 0xec, - 0x4c, 0xa7, 0x31, 0x35, 0x32, 0x8d, 0x93, 0x49, 0x8d, 0xf1, 0xe4, 0x34, - 0x4e, 0xa4, 0x38, 0x66, 0xe2, 0x3d, 0x44, 0x38, 0xc6, 0xb6, 0xa4, 0xa6, - 0x0e, 0x9b, 0x7b, 0x9c, 0x46, 0x77, 0xea, 0x56, 0x39, 0x13, 0xae, 0x27, - 0xd1, 0xd3, 0x6e, 0xd5, 0x45, 0x88, 0xbd, 0x69, 0x4d, 0xe9, 0xe3, 0xf9, - 0x1d, 0x4e, 0x67, 0x6b, 0x24, 0x37, 0xe7, 0x4a, 0x42, 0xe8, 0x1b, 0x6c, - 0x65, 0x9f, 0x00, 0xba, 0x13, 0x52, 0x87, 0xf6, 0x71, 0x4e, 0x03, 0xbf, - 0xd6, 0xbd, 0xee, 0x05, 0xfc, 0x1c, 0xd5, 0x3b, 0xb1, 0x89, 0x63, 0x4d, - 0x31, 0x46, 0xd2, 0x14, 0x6f, 0x63, 0x04, 0x76, 0xfc, 0x4a, 0x27, 0x1f, - 0xaa, 0xb0, 0xe3, 0x55, 0xea, 0x5a, 0xb8, 0xd4, 0x8e, 0xfa, 0x20, 0x7d, - 0x78, 0xc6, 0xa7, 0x7f, 0x92, 0x54, 0xf0, 0x20, 0xf1, 0xf6, 0x8d, 0x60, - 0x7d, 0xfb, 0x4a, 0x61, 0x7b, 0x07, 0x14, 0x5c, 0xd6, 0xae, 0x1a, 0x11, - 0xea, 0x87, 0xcb, 0x9f, 0x3d, 0xa3, 0x7f, 0xc9, 0xe4, 0xf0, 0xbe, 0x34, - 0xb2, 0xfd, 0x66, 0xb8, 0xc6, 0x27, 0xd8, 0x6f, 0xc1, 0xe2, 0xfa, 0x4e, - 0xe9, 0xe7, 0x26, 0xde, 0x4b, 0xbf, 0x73, 0x95, 0x8e, 0x59, 0xfd, 0x42, - 0xd8, 0x36, 0xd8, 0x6c, 0xae, 0x77, 0x7b, 0x02, 0x8b, 0x1c, 0x10, 0x5b, - 0xab, 0x57, 0x2f, 0x02, 0x5d, 0xd3, 0x7a, 0x09, 0x79, 0x90, 0x3f, 0xf0, - 0x0c, 0x44, 0x56, 0x12, 0x67, 0xbe, 0x87, 0x9d, 0xd1, 0x11, 0x30, 0xd6, - 0x24, 0x06, 0xfa, 0xd7, 0x0d, 0x23, 0x85, 0xe7, 0xd3, 0x29, 0xbc, 0x40, - 0x19, 0x45, 0xcc, 0xbb, 0x62, 0x69, 0x7c, 0x3b, 0xfa, 0x1e, 0x62, 0xe6, - 0x99, 0x1d, 0xc6, 0xfa, 0xa8, 0xbb, 0x0a, 0xf9, 0xd2, 0x77, 0x25, 0xc7, - 0x17, 0xb9, 0x7a, 0xdb, 0x22, 0xf8, 0x8a, 0xe3, 0xaf, 0x44, 0xcf, 0xb0, - 0x61, 0xfc, 0x90, 0xbe, 0xed, 0x2d, 0x72, 0xaf, 0xcb, 0x99, 0x7b, 0x67, - 0x79, 0x94, 0xb7, 0x66, 0xfa, 0xb8, 0xb5, 0x3c, 0xe7, 0x2a, 0xe1, 0xfc, - 0x28, 0x1a, 0xd3, 0x94, 0x05, 0x31, 0x39, 0x77, 0x72, 0xca, 0x31, 0x0f, - 0x9e, 0x20, 0x7f, 0xc9, 0x1d, 0xfd, 0x5b, 0x45, 0xfc, 0x5c, 0xf5, 0x01, - 0xc6, 0x02, 0x07, 0x3c, 0xca, 0xc2, 0x3d, 0x2e, 0x3c, 0x18, 0x73, 0xe0, - 0xfe, 0x58, 0x0b, 0x7a, 0xf6, 0x6a, 0x6c, 0xe3, 0xd5, 0xcf, 0x30, 0x5e, - 0x3d, 0x01, 0x9f, 0x67, 0x98, 0x9c, 0xcb, 0x4d, 0x9c, 0x76, 0x8c, 0x16, - 0xa3, 0x60, 0x54, 0x85, 0x6d, 0xb4, 0x0c, 0x85, 0xa3, 0x6e, 0x54, 0xd3, - 0xef, 0xb9, 0xc7, 0xce, 0x62, 0x62, 0x8f, 0xe4, 0x53, 0xbf, 0x30, 0x72, - 0xc9, 0xcb, 0x3e, 0x0d, 0x06, 0x50, 0x3c, 0xb6, 0x05, 0xe9, 0x58, 0x03, - 0x0a, 0xc7, 0x48, 0xb3, 0xc6, 0x26, 0x95, 0x7a, 0xce, 0xd9, 0x12, 0xd3, - 0x38, 0x96, 0xc5, 0x83, 0x56, 0xd2, 0x57, 0xf6, 0x25, 0xbc, 0xeb, 0xa4, - 0x2e, 0x79, 0x59, 0x3f, 0x8e, 0xbc, 0xfe, 0xec, 0xfd, 0x39, 0x78, 0xf3, - 0x80, 0x92, 0x1e, 0xdd, 0xdf, 0xb6, 0x11, 0xd6, 0x5d, 0xba, 0xfb, 0x33, - 0x7b, 0x6a, 0x90, 0x3d, 0x39, 0xd7, 0x52, 0x17, 0xe6, 0xa0, 0x84, 0x7b, - 0x3a, 0x4f, 0xfd, 0xb9, 0x87, 0xeb, 0xbd, 0xca, 0xb8, 0xb1, 0x33, 0x26, - 0x7a, 0xff, 0xb7, 0x0a, 0xed, 0x06, 0x33, 0xa9, 0x02, 0x7c, 0x96, 0xf2, - 0x28, 0x3e, 0xee, 0xe7, 0x3b, 0x7c, 0xfe, 0x6d, 0xee, 0x67, 0xeb, 0x5e, - 0x6f, 0xdb, 0x51, 0xc5, 0xdb, 0xbe, 0x46, 0xf1, 0xa9, 0x5b, 0x95, 0x42, - 0x9c, 0x1f, 0x29, 0xc6, 0x45, 0xfa, 0xe9, 0xab, 0x23, 0x65, 0xb8, 0x34, - 0x52, 0x41, 0x5b, 0xd1, 0x38, 0x86, 0x61, 0x14, 0x69, 0x6e, 0xcc, 0xa4, - 0x5f, 0x40, 0x49, 0x6c, 0x1e, 0x3e, 0x4b, 0x6f, 0x42, 0x71, 0x4c, 0xf8, - 0xbc, 0x07, 0x9f, 0xf2, 0xf9, 0x27, 0xe9, 0x71, 0xe4, 0xef, 0xf9, 0x82, - 0x6d, 0x0c, 0xa3, 0x85, 0x7b, 0xbc, 0x94, 0xee, 0x40, 0xe1, 0x9e, 0x97, - 0xe0, 0xd8, 0x63, 0x74, 0xf5, 0x04, 0xf1, 0x73, 0x3b, 0xf7, 0xd2, 0xad, - 0x7b, 0xa7, 0x16, 0xd8, 0x1b, 0x38, 0x86, 0xce, 0x31, 0x27, 0x95, 0x85, - 0x63, 0x2f, 0xa1, 0x78, 0x8f, 0x07, 0x9b, 0x29, 0xcb, 0x71, 0x68, 0x81, - 0x35, 0xca, 0x4b, 0xc8, 0x19, 0xb5, 0x64, 0xb0, 0x61, 0xcc, 0xb2, 0x91, - 0x96, 0x90, 0xe4, 0x94, 0x26, 0x95, 0x61, 0xd3, 0x46, 0xdc, 0x72, 0xd7, - 0x07, 0xd3, 0xe9, 0x02, 0x9c, 0x4a, 0x89, 0x8c, 0xe4, 0xbe, 0xe0, 0x38, - 0x72, 0xf7, 0x10, 0x3f, 0x47, 0x74, 0x93, 0x5f, 0x88, 0x6d, 0x8c, 0xa4, - 0x6f, 0x65, 0x5f, 0x3a, 0x76, 0x26, 0xaa, 0x69, 0x5b, 0xf3, 0xb0, 0x6a, - 0x8f, 0x61, 0x04, 0x82, 0x53, 0xf7, 0xb8, 0xa8, 0x4d, 0x87, 0xd2, 0xb7, - 0xb2, 0xad, 0x46, 0xea, 0xa9, 0xb7, 0x35, 0x62, 0xe6, 0xbb, 0x0d, 0x4c, - 0xeb, 0x93, 0x8a, 0x2d, 0x26, 0xb1, 0xd8, 0x5a, 0xda, 0x7c, 0x1b, 0x7a, - 0x06, 0xd1, 0xbe, 0x3f, 0x24, 0xb5, 0x70, 0x27, 0x86, 0x19, 0x5b, 0x9d, - 0x67, 0x3c, 0x42, 0x99, 0xab, 0x39, 0x4d, 0x39, 0x18, 0x1a, 0x71, 0xe1, - 0x27, 0x23, 0x1e, 0x34, 0xc6, 0xbe, 0x20, 0x66, 0xe4, 0x63, 0x92, 0xf2, - 0x9e, 0x20, 0x37, 0xfa, 0x34, 0xaa, 0x62, 0x9c, 0x7e, 0xf8, 0x93, 0x68, - 0x05, 0xc6, 0x18, 0x87, 0x7d, 0x1c, 0xd5, 0x90, 0xe6, 0xd9, 0x7c, 0x44, - 0xbc, 0xf9, 0x61, 0xba, 0x01, 0xbf, 0x89, 0x36, 0xe0, 0x55, 0xca, 0xb1, - 0x2e, 0xe6, 0xe6, 0x9a, 0x8e, 0x28, 0x38, 0x30, 0xa9, 0xe4, 0x50, 0x2f, - 0xfc, 0x31, 0xcd, 0x33, 0x9c, 0xd1, 0x0b, 0x6d, 0xac, 0x8d, 0x76, 0x24, - 0x77, 0x2d, 0xc4, 0x77, 0x38, 0xf4, 0x61, 0x90, 0xef, 0x35, 0x64, 0x73, - 0x8b, 0x5e, 0xf7, 0x14, 0xaa, 0x68, 0x4b, 0x5f, 0x19, 0xaa, 0x26, 0x79, - 0xb4, 0x64, 0xf0, 0x72, 0x54, 0x53, 0x2f, 0x99, 0x7b, 0x88, 0x28, 0xce, - 0x25, 0x92, 0xa3, 0xd8, 0xca, 0xfd, 0x07, 0x88, 0x19, 0x57, 0xcc, 0x73, - 0x52, 0xb5, 0xe3, 0x68, 0x30, 0xef, 0xa4, 0x31, 0xd6, 0x5b, 0x72, 0x1c, - 0x77, 0x1e, 0xf8, 0x3f, 0x55, 0x16, 0x57, 0xa2, 0x6d, 0xdb, 0x6e, 0xce, - 0x83, 0x49, 0x4e, 0x7d, 0x77, 0xf0, 0x78, 0xf4, 0x37, 0x55, 0x52, 0x6b, - 0x3b, 0x4a, 0xce, 0xb4, 0x3d, 0x71, 0xab, 0x98, 0xc2, 0xc0, 0x3b, 0xc4, - 0x97, 0x4b, 0x49, 0xe1, 0x55, 0xc2, 0xa7, 0xba, 0xe8, 0xbb, 0x8a, 0xc8, - 0x27, 0xe8, 0x67, 0xc9, 0xf9, 0x7d, 0xf1, 0x29, 0xc6, 0x34, 0x77, 0x93, - 0xd3, 0x15, 0x73, 0x98, 0xf7, 0x39, 0x5f, 0x1b, 0x76, 0xd2, 0x4e, 0xf3, - 0xb4, 0x05, 0x58, 0x45, 0xbe, 0xe4, 0xd0, 0xe8, 0x6e, 0x1e, 0x11, 0x9f, - 0x03, 0xd4, 0xc6, 0x55, 0x14, 0x36, 0x69, 0xeb, 0xde, 0xc2, 0x3d, 0x68, - 0xaf, 0x74, 0x41, 0xea, 0x09, 0x6f, 0x63, 0x19, 0x52, 0x8f, 0x89, 0xef, - 0xb5, 0x49, 0x7d, 0x2c, 0x72, 0x16, 0x35, 0x26, 0x73, 0xcf, 0x6f, 0x92, - 0xf5, 0x54, 0xf0, 0x2c, 0x54, 0x5c, 0xa0, 0x8c, 0x2f, 0x46, 0x7d, 0x33, - 0x2b, 0x50, 0x7f, 0xf2, 0xa2, 0x9d, 0xbc, 0xb0, 0x5c, 0xda, 0x37, 0x40, - 0xe3, 0x78, 0x9f, 0x47, 0x83, 0xe8, 0x57, 0xe5, 0xbb, 0xf0, 0xcb, 0x36, - 0x74, 0x0f, 0xcb, 0x1a, 0x0c, 0xa3, 0x8c, 0x58, 0xf9, 0x88, 0x39, 0xbf, - 0xcc, 0x7d, 0x73, 0x7c, 0x92, 0xf5, 0x7f, 0x12, 0xa3, 0x4c, 0xe3, 0x70, - 0xd2, 0x03, 0xc7, 0x92, 0xaa, 0x39, 0xc8, 0x9f, 0xc6, 0x48, 0x4a, 0x23, - 0xf7, 0x2c, 0x80, 0xa7, 0x52, 0xc7, 0x2e, 0xfa, 0xfc, 0x18, 0xdb, 0xa7, - 0x63, 0x05, 0x88, 0x54, 0x5a, 0x73, 0xde, 0x1d, 0xff, 0xd8, 0x98, 0x7a, - 0xd8, 0xf4, 0xa1, 0xfc, 0x1e, 0x64, 0x9f, 0x39, 0x72, 0xed, 0x14, 0xcf, - 0xc6, 0x2e, 0x19, 0x53, 0x6d, 0xb3, 0x7f, 0x2f, 0x35, 0xef, 0x6e, 0x85, - 0x6d, 0x95, 0xfc, 0xb4, 0xe4, 0xd2, 0x4d, 0xb9, 0x94, 0x68, 0xef, 0x19, - 0x0f, 0x59, 0x72, 0x99, 0x23, 0xf1, 0x40, 0x6d, 0xfc, 0xf1, 0x39, 0x92, - 0x6f, 0x15, 0x7f, 0xe6, 0x6a, 0xd2, 0x1a, 0x4f, 0xe2, 0x17, 0xc6, 0xb9, - 0x1b, 0xc6, 0x29, 0xe7, 0x33, 0xf1, 0x4d, 0xe7, 0x32, 0xf7, 0x00, 0xdc, - 0x99, 0x98, 0x61, 0x1a, 0x47, 0x93, 0xe2, 0x17, 0x3c, 0x58, 0x2f, 0xf9, - 0x2a, 0xd5, 0xdb, 0x17, 0xc1, 0x14, 0x39, 0xe2, 0x07, 0x94, 0xbd, 0x22, - 0xf5, 0x3a, 0xf2, 0xc4, 0xd9, 0xbe, 0x2b, 0x8c, 0x94, 0x59, 0x8f, 0x12, - 0x6c, 0x9d, 0xc6, 0xf6, 0xa4, 0xd4, 0x4d, 0x3f, 0x23, 0x6f, 0xea, 0x22, - 0x27, 0x9f, 0x46, 0x4f, 0xaa, 0x05, 0xaf, 0xec, 0x6d, 0x25, 0xde, 0x08, - 0x6e, 0xfa, 0x4e, 0x9e, 0xb7, 0xb7, 0x60, 0xff, 0xa1, 0x34, 0x52, 0xa3, - 0xe2, 0x2f, 0xe5, 0x1e, 0x9c, 0xf8, 0xca, 0x00, 0xa2, 0x89, 0x13, 0x88, - 0xf0, 0x73, 0x67, 0xe2, 0x25, 0x84, 0x47, 0xdf, 0x63, 0x2c, 0x30, 0x8d, - 0x95, 0xd4, 0xb9, 0x83, 0x98, 0xc6, 0xea, 0x03, 0x1a, 0x92, 0x89, 0x56, - 0x8e, 0xdf, 0x82, 0xde, 0xbd, 0xde, 0x80, 0xc3, 0x56, 0x42, 0x7f, 0xa5, - 0x61, 0xdb, 0x44, 0x33, 0x22, 0xc3, 0x56, 0x5d, 0xac, 0x21, 0xee, 0x51, - 0x3e, 0x21, 0x9f, 0xae, 0x8f, 0x7b, 0x19, 0xc7, 0x79, 0x23, 0xab, 0x15, - 0x9f, 0x27, 0xc7, 0x66, 0x18, 0xbd, 0xf4, 0x1b, 0x27, 0x75, 0x05, 0x79, - 0xf7, 0x28, 0x08, 0xd2, 0x8f, 0x79, 0xaa, 0xe8, 0x5f, 0x86, 0x43, 0xe8, - 0x1d, 0x9c, 0x5d, 0x53, 0x94, 0xf3, 0x7a, 0x80, 0xe3, 0xc9, 0xd9, 0xb5, - 0xa2, 0x77, 0xc2, 0xd7, 0x71, 0xd2, 0xac, 0x39, 0x4a, 0xbb, 0x6c, 0x1b, - 0x14, 0x7e, 0x16, 0xf2, 0x06, 0x4a, 0x14, 0x69, 0xbb, 0x95, 0x58, 0x36, - 0xbb, 0x7d, 0x44, 0x49, 0x2e, 0x21, 0x7f, 0xb5, 0x89, 0x5d, 0x74, 0x9b, - 0xb6, 0x23, 0xb2, 0xe8, 0x4d, 0x86, 0xa9, 0xd3, 0x3f, 0x35, 0x52, 0x6d, - 0x6d, 0x5c, 0x67, 0xa3, 0xd4, 0x9c, 0x4c, 0x9e, 0x72, 0x5a, 0xf2, 0x73, - 0x4e, 0xf1, 0xe3, 0xdd, 0xed, 0x2e, 0xea, 0x53, 0x2e, 0xb1, 0x2a, 0x6f, - 0xdc, 0x05, 0xd7, 0xc1, 0x02, 0xe4, 0x0e, 0x09, 0x9f, 0x83, 0x5a, 0xdc, - 0xa4, 0xc2, 0x3e, 0x5e, 0x48, 0x1b, 0xe0, 0x19, 0x8e, 0xd3, 0xc6, 0xa2, - 0x6e, 0xd4, 0x8c, 0xbb, 0xf1, 0x13, 0xe2, 0x41, 0xf5, 0xb8, 0x86, 0x49, - 0xe2, 0x81, 0x7b, 0x3c, 0x80, 0x09, 0xe2, 0x41, 0x49, 0x26, 0x47, 0xf2, - 0x76, 0xfa, 0x65, 0x9e, 0xab, 0xcc, 0x25, 0x72, 0xcc, 0x9e, 0xab, 0x9c, - 0x69, 0x2b, 0x31, 0x50, 0xce, 0xb7, 0x01, 0x3b, 0x06, 0xd3, 0x58, 0xbe, - 0xc7, 0xc0, 0xbb, 0x7a, 0xbd, 0x3b, 0x4f, 0x91, 0x78, 0xc2, 0x40, 0x5a, - 0x97, 0x3b, 0xab, 0xde, 0x75, 0x72, 0xaf, 0xbb, 0xbd, 0xc2, 0x40, 0x4e, - 0xd0, 0xab, 0x13, 0xf9, 0xd7, 0xe5, 0x29, 0xe2, 0xc3, 0xea, 0x3d, 0x9b, - 0x30, 0x57, 0x6a, 0x8e, 0xfc, 0xb7, 0x02, 0x9b, 0xc8, 0x1b, 0xf3, 0xb5, - 0x56, 0xec, 0x2c, 0x8d, 0xb8, 0x2e, 0x87, 0x0c, 0x63, 0x43, 0xf0, 0xf1, - 0x2a, 0x93, 0x03, 0xda, 0xf6, 0xf1, 0x73, 0x2d, 0xf7, 0x2d, 0x7b, 0xef, - 0x40, 0x6c, 0xb7, 0x82, 0xb4, 0xbf, 0x03, 0xd1, 0x91, 0x0e, 0xec, 0xda, - 0x2d, 0x98, 0xd0, 0x47, 0x4c, 0x30, 0xba, 0x36, 0x06, 0x1f, 0xc2, 0x25, - 0x93, 0x11, 0x48, 0x1f, 0x6f, 0xc0, 0x63, 0x9b, 0x7d, 0x0e, 0x1b, 0xb9, - 0x7e, 0xcb, 0x76, 0x9a, 0xfb, 0x85, 0x7b, 0xfb, 0xfb, 0x7a, 0x79, 0xfe, - 0x0f, 0x1f, 0x10, 0xdf, 0x63, 0x18, 0x7d, 0xfa, 0x3c, 0xa0, 0x54, 0xf6, - 0x10, 0x40, 0x3c, 0x61, 0x7c, 0x56, 0xad, 0xf9, 0x66, 0x76, 0xd1, 0xcf, - 0x9f, 0xdd, 0x53, 0xbf, 0x69, 0x93, 0x70, 0x9a, 0xc5, 0xc2, 0xf3, 0xd2, - 0x38, 0x33, 0x7a, 0x27, 0x52, 0x0f, 0x73, 0x3f, 0x3c, 0x2b, 0x67, 0xfc, - 0x4b, 0x43, 0x78, 0x9d, 0x5d, 0x93, 0x9a, 0x2d, 0xa7, 0x1c, 0xf7, 0xa3, - 0xa7, 0x14, 0x91, 0xcb, 0x21, 0x99, 0xff, 0xda, 0xfa, 0xb9, 0xdf, 0x16, - 0xec, 0xda, 0x2b, 0xbc, 0x43, 0x38, 0x9a, 0x2f, 0xf2, 0x11, 0x5a, 0x91, - 0x9c, 0xb0, 0xe6, 0x8a, 0x26, 0x6e, 0xd6, 0x15, 0x39, 0xf7, 0x13, 0xd8, - 0x41, 0x8e, 0xe7, 0xe2, 0xf8, 0xf4, 0x35, 0x1c, 0x4f, 0x0b, 0xe4, 0xc9, - 0x7c, 0xe3, 0x3f, 0x35, 0x76, 0x56, 0x8a, 0x6c, 0x64, 0x7c, 0xcd, 0xc4, - 0x8c, 0x0d, 0xc1, 0x3f, 0xb7, 0xd7, 0x1a, 0x37, 0xf2, 0xbd, 0xad, 0x96, - 0x3c, 0xa4, 0xad, 0xf6, 0x27, 0xd6, 0xb3, 0x90, 0xed, 0x64, 0x4d, 0x1d, - 0xd8, 0xb1, 0x1b, 0x91, 0x7c, 0x4d, 0x6a, 0x0d, 0x1d, 0xe8, 0xa3, 0x7c, - 0xb7, 0x25, 0x3b, 0xb0, 0x9f, 0x36, 0x3b, 0xa4, 0xbf, 0x51, 0x6d, 0x43, - 0xdd, 0x8c, 0x1d, 0x53, 0x3f, 0xab, 0x21, 0x9e, 0x2e, 0x5c, 0xec, 0xa7, - 0x7d, 0x75, 0x20, 0x9e, 0xca, 0x75, 0x9b, 0x35, 0x40, 0x9b, 0xf8, 0x42, - 0x91, 0x45, 0x27, 0xf2, 0xfb, 0x4f, 0xc0, 0xd9, 0xdf, 0x89, 0x3c, 0xff, - 0x32, 0xdc, 0x1f, 0x3c, 0x67, 0x5c, 0xd2, 0x1c, 0xee, 0xa3, 0x94, 0xcf, - 0x1b, 0x0d, 0xd5, 0x8c, 0x3b, 0x1b, 0xb0, 0x6d, 0xf8, 0x36, 0xda, 0x7e, - 0x23, 0xb9, 0x2f, 0xe7, 0x6a, 0xb2, 0x61, 0xf5, 0x12, 0x89, 0xe9, 0xa5, - 0x3e, 0x5d, 0x25, 0xf7, 0x10, 0xd4, 0xe7, 0x21, 0xf1, 0x1a, 0x39, 0x59, - 0x85, 0x07, 0x4f, 0xd3, 0xc6, 0xda, 0x55, 0x79, 0xbe, 0x85, 0x71, 0xc4, - 0x16, 0x54, 0xc7, 0x22, 0x86, 0xc8, 0xfb, 0x28, 0xc2, 0xdf, 0x93, 0x9a, - 0x4a, 0xe3, 0x62, 0xff, 0xa6, 0x19, 0x45, 0x74, 0xda, 0xdf, 0x3e, 0xae, - 0xe8, 0xae, 0x07, 0xc6, 0x14, 0x04, 0xfa, 0x39, 0x56, 0xf0, 0xfd, 0x39, - 0x56, 0x1e, 0x2d, 0xcb, 0xff, 0xb6, 0x90, 0x33, 0x6c, 0x41, 0x11, 0xfb, - 0xbb, 0x35, 0xc1, 0x86, 0xf0, 0x7d, 0xc5, 0xec, 0x9f, 0x0e, 0xfa, 0xdb, - 0x0a, 0x15, 0xe1, 0x46, 0xfe, 0xc6, 0xd5, 0x8a, 0xf0, 0x18, 0xe9, 0xa7, - 0xbb, 0xea, 0xc6, 0xce, 0x66, 0x6a, 0x66, 0x8d, 0xc4, 0x07, 0x8f, 0x79, - 0x07, 0xd5, 0xba, 0xaf, 0x95, 0xbd, 0xb3, 0xa4, 0xf2, 0xfc, 0x25, 0xc6, - 0x38, 0x12, 0x5c, 0x1e, 0x6d, 0x92, 0xfb, 0x21, 0xcb, 0x0e, 0x51, 0xef, - 0xcf, 0xa3, 0x02, 0xff, 0x10, 0x15, 0x5c, 0xf3, 0xe0, 0x1f, 0xa3, 0xb9, - 0x12, 0x57, 0xa7, 0x24, 0x6f, 0xf9, 0x66, 0x32, 0x62, 0x50, 0xae, 0xad, - 0xab, 0xa9, 0x4b, 0x81, 0x60, 0x21, 0x50, 0xd9, 0xfd, 0xb4, 0xd3, 0x8c, - 0xf3, 0x8b, 0x50, 0x4a, 0x1f, 0xd0, 0x3f, 0xfc, 0xa7, 0x72, 0xb4, 0xef, - 0x9b, 0xdc, 0xf2, 0xef, 0xea, 0xec, 0xd8, 0x16, 0xfc, 0x57, 0x23, 0x95, - 0xb9, 0x33, 0x7c, 0x66, 0xb7, 0xe8, 0x69, 0x00, 0xb9, 0xf1, 0xb3, 0xd4, - 0x49, 0x15, 0xa7, 0xa3, 0x3e, 0x7d, 0x8d, 0xed, 0x49, 0xea, 0x7f, 0xcd, - 0x0d, 0xd8, 0x5d, 0xa3, 0x3d, 0x88, 0xa7, 0x4c, 0xec, 0x0e, 0xa3, 0x87, - 0xbe, 0x81, 0x9c, 0x6e, 0xdf, 0xd3, 0x36, 0x15, 0x79, 0x31, 0x9f, 0xea, - 0xa3, 0x4e, 0xf5, 0x70, 0x0e, 0xe1, 0x9b, 0xe5, 0xe4, 0x83, 0x1b, 0xa3, - 0xf5, 0x9e, 0x7f, 0xc1, 0x7a, 0xda, 0xa3, 0xcc, 0x21, 0x7b, 0xd2, 0x50, - 0x18, 0xd7, 0x70, 0x8c, 0xfb, 0xd8, 0x56, 0x6a, 0xcd, 0x5b, 0x9c, 0x19, - 0x3b, 0x3e, 0x2c, 0x5c, 0x6c, 0x29, 0xd6, 0x98, 0x63, 0xeb, 0xb4, 0x4b, - 0x0d, 0xfb, 0xe4, 0x6e, 0x7f, 0x9d, 0x86, 0x44, 0xba, 0x19, 0x2f, 0x95, - 0x79, 0xb0, 0x3f, 0xb1, 0x05, 0x8b, 0x12, 0xf7, 0xe1, 0xd1, 0xb2, 0x88, - 0xdc, 0x85, 0x41, 0x5e, 0x5c, 0x53, 0xef, 0x54, 0xee, 0xcd, 0xd4, 0x29, - 0x2a, 0xe0, 0x88, 0x8b, 0xcf, 0xcb, 0xc1, 0x80, 0x3a, 0x17, 0x05, 0xe6, - 0x9d, 0x4a, 0x6b, 0xec, 0x5d, 0xc3, 0xde, 0x8c, 0x1f, 0x24, 0x6a, 0xc4, - 0x15, 0xf1, 0xbf, 0x81, 0x17, 0x50, 0xce, 0x38, 0x21, 0x82, 0x9c, 0x26, - 0x2d, 0xf5, 0x2c, 0xf2, 0x10, 0xa9, 0x12, 0x4c, 0x94, 0x3e, 0xb7, 0xdd, - 0xb4, 0xa6, 0xb2, 0xcc, 0x9a, 0xb2, 0xcf, 0x31, 0x07, 0xc5, 0xa2, 0x5b, - 0xc2, 0x35, 0xe4, 0xf7, 0x7c, 0xb4, 0x51, 0x9f, 0x2a, 0xb8, 0xe6, 0x84, - 0x79, 0x5f, 0xd6, 0xab, 0x47, 0x6c, 0x21, 0xfc, 0x76, 0x8f, 0xa5, 0x83, - 0xeb, 0x6a, 0x79, 0xfe, 0xc5, 0x21, 0xcc, 0x8c, 0x8a, 0x3f, 0xfb, 0x53, - 0x67, 0x92, 0xf5, 0xc5, 0x72, 0x2e, 0x22, 0x57, 0xef, 0xc9, 0x0b, 0xa8, - 0x9f, 0x7a, 0xc2, 0x76, 0xd8, 0x40, 0xb9, 0xc8, 0xf8, 0xb8, 0x5b, 0x62, - 0x58, 0x1b, 0x79, 0x44, 0x24, 0x7d, 0xc5, 0x2d, 0xbe, 0xd2, 0x11, 0x07, - 0x6a, 0xe2, 0x11, 0xe4, 0x36, 0x69, 0xfb, 0x2e, 0xdb, 0xaf, 0x1a, 0xed, - 0x55, 0xb7, 0x31, 0x26, 0xbc, 0xbe, 0xe7, 0x3e, 0xae, 0xdd, 0xae, 0xfd, - 0xd4, 0x58, 0x51, 0x21, 0x6b, 0xac, 0xae, 0xb6, 0xf2, 0xd1, 0xf3, 0x29, - 0x97, 0xac, 0x4c, 0x0c, 0xea, 0xcf, 0xff, 0x32, 0xbe, 0x71, 0xc3, 0x73, - 0xe1, 0x33, 0xa2, 0xa7, 0xb3, 0xef, 0x14, 0x8a, 0xce, 0x7a, 0xa8, 0xa7, - 0xd3, 0x38, 0x94, 0x6c, 0x44, 0x7f, 0x42, 0x64, 0x1c, 0xc6, 0x79, 0x72, - 0xc5, 0xda, 0x81, 0x69, 0x0c, 0x91, 0x2b, 0xfa, 0xe2, 0xde, 0x7d, 0x94, - 0x24, 0x5e, 0x52, 0x97, 0x99, 0x3c, 0xc9, 0xa5, 0x65, 0xd7, 0x70, 0xb7, - 0x29, 0x77, 0xf1, 0x31, 0x3b, 0xb9, 0xdf, 0x3b, 0xc8, 0x93, 0x9a, 0x63, - 0xb9, 0xd0, 0x4a, 0x8b, 0x51, 0xa8, 0x49, 0x5d, 0xc3, 0x6a, 0x17, 0xe5, - 0x5a, 0x0a, 0x34, 0x1f, 0x56, 0x9b, 0x6d, 0x3d, 0xe6, 0xfd, 0x09, 0x47, - 0x99, 0xf8, 0x60, 0xf1, 0xbb, 0xe4, 0xe2, 0x4b, 0xc4, 0xef, 0x86, 0xb9, - 0xb6, 0x05, 0x3c, 0xb3, 0x45, 0x70, 0xdf, 0xeb, 0x41, 0xf5, 0xbd, 0xf4, - 0x91, 0x0b, 0x15, 0x94, 0x2d, 0xf4, 0x47, 0x16, 0xd9, 0x9a, 0x81, 0xaa, - 0x00, 0xf1, 0x47, 0x33, 0x7a, 0x12, 0x7f, 0xe0, 0x18, 0x1d, 0x30, 0x76, - 0xe7, 0x63, 0xfd, 0xee, 0x12, 0xea, 0xaa, 0x47, 0xf2, 0xf0, 0x2e, 0x57, - 0x53, 0x34, 0xe8, 0x8a, 0xd5, 0xeb, 0x4e, 0x65, 0x01, 0xfd, 0xb1, 0x9c, - 0x9f, 0xcc, 0x7f, 0xd7, 0x0d, 0x7c, 0xa9, 0x9c, 0xfe, 0xed, 0x51, 0x73, - 0x0d, 0x92, 0x2b, 0x96, 0x7e, 0x7f, 0x7c, 0x4e, 0x53, 0xd7, 0xce, 0xe9, - 0x4e, 0x38, 0x1e, 0xa9, 0x20, 0xff, 0xba, 0xb5, 0x0f, 0xc9, 0xa3, 0x0f, - 0xb9, 0x23, 0x66, 0x74, 0x6d, 0x0e, 0x16, 0x48, 0xfe, 0xc8, 0xf4, 0x21, - 0xed, 0xb6, 0x8d, 0xa6, 0xee, 0x38, 0xb5, 0x1e, 0xca, 0xdb, 0xca, 0x47, - 0x53, 0x06, 0x73, 0xac, 0xbb, 0xb9, 0xd9, 0xdf, 0x3a, 0xb0, 0x9d, 0x98, - 0x29, 0x77, 0xea, 0x9d, 0x9a, 0x46, 0xfb, 0xef, 0x40, 0x0f, 0xc7, 0x7c, - 0x85, 0xb8, 0xd9, 0x4f, 0xdc, 0xbc, 0xba, 0xf8, 0x8d, 0x9f, 0x55, 0xa3, - 0x2e, 0xe9, 0xc6, 0xd4, 0x5f, 0x97, 0x09, 0x6e, 0x2e, 0xf2, 0x77, 0x5c, - 0x31, 0x71, 0x53, 0xc6, 0x96, 0xf1, 0x66, 0x8f, 0xfd, 0x3f, 0xf8, 0xdf, - 0xf9, 0x92, 0x73, 0x34, 0x9c, 0xda, 0xff, 0x35, 0xb6, 0x55, 0xc8, 0x5a, - 0x6f, 0xb5, 0x0e, 0xc1, 0xda, 0xd9, 0x35, 0xfd, 0x69, 0x62, 0xae, 0x19, - 0x2f, 0xd0, 0xe7, 0x86, 0xb1, 0x6a, 0x89, 0x8a, 0x4b, 0xd1, 0x69, 0xe4, - 0x1d, 0xc8, 0xe2, 0x93, 0xb1, 0xec, 0x18, 0xb1, 0x69, 0x08, 0x82, 0x47, - 0x4d, 0x3c, 0x97, 0x08, 0xed, 0xa4, 0x08, 0xe3, 0x49, 0xb9, 0x47, 0x64, - 0x60, 0x57, 0xd0, 0x45, 0x6e, 0xdb, 0x7d, 0x34, 0xc7, 0xf4, 0x13, 0x45, - 0x54, 0xad, 0x2c, 0xef, 0x16, 0xce, 0x2d, 0xf8, 0x23, 0xfc, 0xd8, 0x8e, - 0x92, 0xc5, 0x92, 0x17, 0xf8, 0xc2, 0xb8, 0xf4, 0x98, 0xb4, 0x9b, 0x87, - 0xa1, 0xdd, 0xa2, 0x7f, 0x3e, 0x54, 0x6b, 0x67, 0x19, 0x73, 0x80, 0x73, - 0xda, 0x6e, 0xcf, 0x21, 0x37, 0xee, 0xd2, 0x97, 0xe0, 0x6a, 0x79, 0x0f, - 0x0a, 0x9a, 0xdc, 0xf8, 0x30, 0x3a, 0x85, 0x43, 0xc4, 0x8f, 0x5c, 0xea, - 0x50, 0x5e, 0x46, 0xcf, 0x76, 0x0c, 0xcb, 0xfe, 0xaa, 0xb1, 0xd2, 0xb4, - 0x53, 0x19, 0x63, 0x1a, 0xaf, 0x92, 0xcf, 0x36, 0x2f, 0x11, 0x2e, 0xab, - 0x63, 0x5f, 0xa2, 0x08, 0x35, 0x83, 0x5d, 0x94, 0x5d, 0x11, 0xaa, 0x87, - 0xc5, 0xbe, 0xe6, 0x0b, 0x8e, 0xca, 0x05, 0x39, 0xca, 0x43, 0xc5, 0xf6, - 0x68, 0xbd, 0x7a, 0x81, 0x41, 0x42, 0xf8, 0x9a, 0xaf, 0x77, 0xd3, 0xef, - 0x30, 0x26, 0xca, 0xe8, 0x85, 0x4a, 0xbd, 0x68, 0xbb, 0xc6, 0xa3, 0xb3, - 0x7b, 0x99, 0x9d, 0x3f, 0x52, 0xb1, 0x23, 0x6a, 0x62, 0x21, 0xfb, 0xfa, - 0x02, 0x3e, 0x85, 0x58, 0x3e, 0x26, 0x3a, 0xf6, 0x7e, 0x46, 0xce, 0x79, - 0xb7, 0x59, 0xf7, 0x5a, 0x36, 0xde, 0xf4, 0x5d, 0x6b, 0x7f, 0x13, 0x67, - 0x8d, 0x5d, 0x8f, 0xc9, 0x1a, 0x8f, 0xe3, 0x60, 0xf2, 0x8a, 0xdc, 0x9b, - 0xef, 0x38, 0x03, 0x1b, 0x4e, 0x33, 0x76, 0x19, 0x4b, 0xfd, 0xae, 0x5a, - 0xde, 0x45, 0xd9, 0x97, 0x98, 0xed, 0x3b, 0xc4, 0x2e, 0x3d, 0x19, 0xbf, - 0x61, 0xd9, 0x67, 0x69, 0x5c, 0xee, 0xaf, 0x1c, 0x09, 0x3e, 0xcd, 0x73, - 0xf1, 0x2f, 0xaa, 0x37, 0x73, 0x32, 0xe4, 0xc2, 0x8c, 0x53, 0x04, 0x73, - 0x23, 0xf4, 0xf9, 0x45, 0xf8, 0x79, 0x52, 0x7c, 0xb0, 0x81, 0x5c, 0xea, - 0xe3, 0xb9, 0x8a, 0xee, 0xe7, 0x4b, 0x4d, 0x6e, 0x5d, 0x84, 0x32, 0xee, - 0x73, 0x60, 0xf8, 0x56, 0xba, 0x7e, 0xdd, 0x4f, 0xa4, 0x83, 0x0a, 0x71, - 0xe3, 0x5f, 0xb9, 0x4e, 0xab, 0xcf, 0x99, 0xa4, 0x0b, 0x9f, 0x06, 0xdb, - 0x31, 0x55, 0x1a, 0xc6, 0x60, 0x22, 0x0f, 0xed, 0x55, 0x75, 0xe6, 0xbb, - 0x1d, 0xd5, 0x71, 0x0f, 0xce, 0x46, 0x9d, 0x68, 0x9c, 0xe3, 0x31, 0x73, - 0x83, 0x36, 0x62, 0xfd, 0x07, 0xd1, 0xb0, 0x69, 0x83, 0xb3, 0x7d, 0x48, - 0x8e, 0xb6, 0x18, 0x2d, 0x19, 0x9c, 0xdf, 0x9f, 0xf8, 0x82, 0x38, 0x54, - 0x1c, 0x29, 0x6f, 0x2a, 0xc2, 0x1d, 0x83, 0x72, 0xc7, 0x41, 0xee, 0x64, - 0x68, 0x33, 0x77, 0x2a, 0x45, 0x58, 0x36, 0x2c, 0x98, 0x2f, 0xb6, 0x9b, - 0xa6, 0xed, 0xae, 0xe5, 0xb9, 0x75, 0x42, 0xde, 0xd9, 0x78, 0x85, 0xb2, - 0xb7, 0x2b, 0x46, 0xd7, 0x45, 0x3d, 0x2c, 0xf7, 0x3c, 0x3b, 0x5b, 0x68, - 0x07, 0x33, 0x41, 0x6f, 0x7b, 0xb9, 0x5d, 0xeb, 0xf8, 0x95, 0xd2, 0x80, - 0xf1, 0x31, 0xa0, 0x7f, 0x34, 0x80, 0x8f, 0x12, 0x12, 0x03, 0x04, 0xf0, - 0x1b, 0x72, 0xa3, 0x0b, 0x89, 0x06, 0xfa, 0x0b, 0x6f, 0xf8, 0x39, 0x34, - 0xe0, 0x43, 0x7e, 0xcf, 0x8d, 0xeb, 0xb8, 0x4c, 0xf9, 0x39, 0xe3, 0x21, - 0x5c, 0x9c, 0xb8, 0x17, 0x97, 0xf6, 0x2a, 0x78, 0x43, 0xbb, 0x17, 0xe7, - 0x0f, 0x75, 0x62, 0xf1, 0x5e, 0x79, 0xef, 0xef, 0x48, 0x50, 0xa5, 0xaf, - 0x78, 0xba, 0xd6, 0xe8, 0x7a, 0x51, 0xaf, 0x83, 0x5e, 0xe6, 0xd5, 0xdb, - 0x89, 0x09, 0x82, 0xf1, 0x61, 0x9b, 0x9c, 0xa1, 0x9c, 0x65, 0x27, 0x2e, - 0x99, 0xb8, 0x7e, 0x6b, 0xac, 0xb8, 0x8e, 0xe9, 0x32, 0x8f, 0xe0, 0xcb, - 0x7c, 0xfc, 0x48, 0x0d, 0x70, 0x1f, 0x6e, 0x72, 0xb1, 0x29, 0xfa, 0xc7, - 0x3c, 0xe4, 0x56, 0x4a, 0xcd, 0x5a, 0x43, 0x3e, 0x71, 0xe4, 0x14, 0x65, - 0xb7, 0xaa, 0xd2, 0x6b, 0xc6, 0x3a, 0xb9, 0xf1, 0x06, 0xc6, 0x31, 0xe5, - 0xf8, 0xe8, 0x06, 0xff, 0xfb, 0x23, 0xe3, 0x51, 0x13, 0xaf, 0x13, 0xb7, - 0x09, 0x1f, 0x7b, 0x3d, 0xf1, 0xf8, 0x6d, 0x82, 0xdb, 0x92, 0x5f, 0x2c, - 0xd6, 0xb4, 0x4d, 0xdf, 0x81, 0xbc, 0xff, 0xf6, 0xc6, 0x7f, 0x2b, 0x24, - 0x4f, 0x7e, 0x31, 0x58, 0x17, 0x29, 0x45, 0x1f, 0x9f, 0x4f, 0x2d, 0x56, - 0x71, 0x90, 0x9f, 0x7e, 0xb6, 0x6b, 0xe0, 0x3a, 0x3e, 0x36, 0x52, 0xaa, - 0xcf, 0xf4, 0x25, 0x71, 0xfa, 0xd3, 0xd3, 0xb1, 0xfa, 0xf6, 0x51, 0xe5, - 0xb2, 0x11, 0xa9, 0xac, 0xe5, 0x6f, 0x15, 0x38, 0x13, 0xf5, 0x4e, 0x1d, - 0x42, 0xbd, 0x67, 0x46, 0xd9, 0x6f, 0x44, 0x54, 0x39, 0x1f, 0xd9, 0xaf, - 0xf4, 0x5f, 0xc0, 0xe7, 0xe7, 0x66, 0xe9, 0xe1, 0xf5, 0x38, 0xcc, 0x79, - 0x4d, 0xff, 0x84, 0xa7, 0x18, 0xcb, 0x46, 0xf4, 0x7a, 0xb5, 0x87, 0xd8, - 0x10, 0x56, 0x6f, 0xa5, 0x7f, 0x79, 0xd4, 0xbf, 0x30, 0xe3, 0xca, 0x22, - 0xa8, 0xd6, 0x7b, 0x3d, 0x48, 0x0e, 0xcf, 0xe6, 0x9a, 0xa2, 0x77, 0x16, - 0x6f, 0x6d, 0x2f, 0xed, 0x3e, 0xea, 0x24, 0x36, 0x25, 0x88, 0xeb, 0x71, - 0xe2, 0x7a, 0x2e, 0x71, 0xfd, 0xe3, 0x3d, 0xf9, 0x38, 0xbd, 0xa7, 0x11, - 0xe9, 0x52, 0xe9, 0x63, 0x87, 0x93, 0xbb, 0x4b, 0x65, 0xee, 0x39, 0x54, - 0x0f, 0xdc, 0x27, 0x77, 0x1e, 0x21, 0x7e, 0x36, 0x27, 0xce, 0xb8, 0xab, - 0xcd, 0x0e, 0x87, 0xf9, 0x4e, 0x43, 0xc9, 0x0d, 0xfa, 0xe7, 0xd2, 0x72, - 0xd1, 0x4a, 0x39, 0xe6, 0x6a, 0xbe, 0xb9, 0xd6, 0xdd, 0xbe, 0x22, 0xc6, - 0x91, 0x72, 0x5f, 0x71, 0xa9, 0xd4, 0x03, 0xd9, 0x5e, 0xfa, 0x49, 0xac, - 0x63, 0x60, 0x07, 0x35, 0xac, 0xae, 0xd2, 0x40, 0x42, 0x0f, 0xd3, 0x87, - 0x05, 0x11, 0x26, 0xa7, 0x2f, 0xd4, 0xe4, 0xbb, 0x8a, 0x8b, 0x8c, 0xd3, - 0xc6, 0x1a, 0x14, 0x7c, 0x7a, 0x97, 0x70, 0x03, 0xbf, 0x7e, 0x5a, 0xc1, - 0x1c, 0xeb, 0x5d, 0x0a, 0xc1, 0x8c, 0x62, 0x13, 0x33, 0x72, 0x4d, 0x9e, - 0x34, 0xc7, 0xc4, 0x1b, 0x79, 0x57, 0xac, 0x9a, 0x7e, 0xe8, 0x9e, 0x44, - 0xfd, 0x94, 0xcf, 0x4e, 0xce, 0xf6, 0xf8, 0x5d, 0xe4, 0x6a, 0x26, 0x67, - 0x20, 0xfe, 0xbf, 0x9f, 0xe1, 0x15, 0xde, 0xc6, 0x9b, 0xef, 0x90, 0x9e, - 0xbb, 0x16, 0xa7, 0x5b, 0x7b, 0xe8, 0x1f, 0xfe, 0x9d, 0xd1, 0x76, 0xc3, - 0xfa, 0xb3, 0xb8, 0xb2, 0x80, 0xdf, 0xa5, 0xbf, 0xd8, 0x1d, 0xf5, 0x22, - 0xfe, 0x33, 0xe3, 0x29, 0x93, 0xdf, 0xd9, 0xe7, 0xca, 0x1d, 0x51, 0xc7, - 0xc0, 0x17, 0xb7, 0xc9, 0xfb, 0x13, 0xb6, 0x59, 0x3c, 0xc1, 0xf2, 0xbd, - 0x17, 0x8c, 0xd5, 0xe6, 0x5a, 0xf3, 0x33, 0xed, 0x24, 0xa6, 0x96, 0xb5, - 0x28, 0xf8, 0x81, 0x56, 0xaf, 0x9e, 0x42, 0xa1, 0xe0, 0x49, 0x58, 0x6a, - 0x9f, 0xf9, 0x9a, 0xcf, 0x7d, 0x90, 0x9f, 0xbb, 0xf8, 0xfc, 0xb8, 0xe6, - 0x68, 0xdc, 0x0c, 0xa9, 0xf7, 0xda, 0x78, 0x56, 0xf5, 0xee, 0x53, 0xf0, - 0x87, 0x73, 0x95, 0x19, 0xa3, 0xbd, 0x42, 0xda, 0x58, 0x75, 0x5f, 0x28, - 0x67, 0xcd, 0x7c, 0x8a, 0xa5, 0x33, 0xf3, 0xa8, 0x33, 0x82, 0x5d, 0xc2, - 0x4d, 0x16, 0x72, 0xef, 0x2a, 0x86, 0x27, 0x80, 0x9c, 0x01, 0x97, 0xc9, - 0x95, 0xd4, 0xda, 0x5a, 0xcf, 0xb3, 0x58, 0x3e, 0x57, 0xde, 0x01, 0xdb, - 0xaa, 0xe3, 0x76, 0x1b, 0xde, 0xbb, 0xdd, 0xd6, 0x74, 0xdf, 0x77, 0x5b, - 0x42, 0x9b, 0x65, 0x5f, 0x44, 0x67, 0x33, 0xb7, 0xeb, 0x96, 0x1a, 0xe5, - 0x4a, 0xfa, 0xb4, 0x21, 0xc6, 0xfc, 0x2b, 0x1b, 0xfe, 0xdd, 0xf8, 0x96, - 0x23, 0xec, 0xb1, 0xa3, 0xd6, 0xd3, 0x8b, 0xab, 0x46, 0xaa, 0x42, 0x9e, - 0xcb, 0x18, 0xf2, 0xae, 0xa7, 0xd4, 0x59, 0x0c, 0xe3, 0x8e, 0x5a, 0x83, - 0xf1, 0xb4, 0x6d, 0xb9, 0x9d, 0x76, 0x91, 0xab, 0x9d, 0x37, 0xea, 0xaa, - 0x6a, 0xdd, 0x36, 0xa5, 0x8e, 0xda, 0x51, 0x81, 0x57, 0xa9, 0xbf, 0xaf, - 0x4e, 0x88, 0x0f, 0x54, 0x71, 0x98, 0x76, 0x7a, 0xa8, 0xce, 0xd7, 0x79, - 0x89, 0xb1, 0xe5, 0x27, 0xe4, 0xfc, 0x6f, 0x6b, 0xde, 0xf6, 0x93, 0x92, - 0x93, 0x0c, 0x3a, 0xf0, 0x66, 0xc3, 0x55, 0x33, 0x4f, 0x1c, 0x3b, 0xa0, - 0x62, 0x28, 0x61, 0xd9, 0xfb, 0x6b, 0xb4, 0xe3, 0xeb, 0x77, 0x1e, 0x42, - 0xe8, 0x19, 0x14, 0xfb, 0x08, 0x99, 0x76, 0x74, 0x3d, 0x77, 0x24, 0x78, - 0x2d, 0x76, 0xb1, 0x5e, 0x6a, 0x7e, 0x91, 0x14, 0xc8, 0x6d, 0x06, 0x56, - 0x92, 0x13, 0x8b, 0xcf, 0x6d, 0x60, 0xfc, 0xeb, 0xa0, 0xfd, 0x9c, 0x64, - 0x2c, 0xc2, 0xb5, 0x35, 0x19, 0xc6, 0x05, 0xc6, 0x66, 0xc3, 0xa8, 0x57, - 0x8f, 0x61, 0x0d, 0x79, 0x2d, 0x39, 0xcf, 0x44, 0x0b, 0x76, 0x9a, 0xb1, - 0x95, 0x4f, 0xbd, 0x5f, 0x59, 0xc4, 0xfd, 0xb7, 0xa0, 0xfb, 0x90, 0x87, - 0x3e, 0xc1, 0x30, 0x1e, 0xd0, 0xff, 0x12, 0x65, 0x83, 0xdd, 0x9d, 0x65, - 0x94, 0xc7, 0xe7, 0xc1, 0x48, 0x07, 0x31, 0x7d, 0xd3, 0x31, 0x45, 0xee, - 0xa5, 0x7e, 0x8b, 0xe7, 0x11, 0x30, 0xf9, 0xf6, 0x8e, 0xc4, 0x03, 0xf4, - 0x71, 0xff, 0x1d, 0x3b, 0x54, 0x65, 0x19, 0xdd, 0x1d, 0x39, 0x23, 0xfc, - 0x6a, 0x93, 0x76, 0xf2, 0xbc, 0xfd, 0xfb, 0xd0, 0xe7, 0x34, 0xf2, 0x99, - 0xf8, 0x79, 0x69, 0x0b, 0x5c, 0x88, 0x76, 0xe2, 0x68, 0x9a, 0x7a, 0x1d, - 0xed, 0xc3, 0xb1, 0xb4, 0xcc, 0x29, 0x9c, 0xab, 0x01, 0xb1, 0x41, 0x3b, - 0xc6, 0x75, 0x5f, 0xb8, 0x98, 0x72, 0xc9, 0x0f, 0x7a, 0xc3, 0x6b, 0x88, - 0xb1, 0x7d, 0xc3, 0x69, 0xbc, 0xb9, 0xdb, 0xdb, 0x5e, 0xa7, 0x68, 0x88, - 0x4e, 0x40, 0x7d, 0x6e, 0x49, 0x1a, 0xa7, 0x46, 0x1e, 0x86, 0xa7, 0xca, - 0xeb, 0x59, 0xa9, 0xb4, 0x62, 0xeb, 0xc4, 0xd7, 0xe5, 0x9c, 0x34, 0xce, - 0xdd, 0x8a, 0x08, 0x65, 0xbf, 0x1d, 0xff, 0x38, 0x57, 0x70, 0xac, 0x77, - 0xa2, 0x10, 0x35, 0xf4, 0x47, 0xaf, 0x98, 0x7e, 0xd7, 0xb2, 0xa3, 0x6a, - 0xed, 0x53, 0xe3, 0x89, 0x8c, 0x5f, 0xff, 0xf3, 0xf2, 0xfa, 0xb1, 0x11, - 0x56, 0x45, 0x5e, 0xd2, 0xaf, 0x9a, 0xdc, 0x40, 0x78, 0x81, 0xe5, 0xbf, - 0x4b, 0xb5, 0xf7, 0x8d, 0x87, 0xcd, 0x31, 0x46, 0x39, 0x8f, 0xec, 0x29, - 0x90, 0xd9, 0xb7, 0x8e, 0xdf, 0x46, 0x25, 0xf7, 0xa1, 0xe2, 0x98, 0x2e, - 0x38, 0xd2, 0x4a, 0x5b, 0x75, 0x62, 0x53, 0x03, 0xcd, 0xd1, 0xac, 0x09, - 0x4c, 0x63, 0x67, 0xf2, 0xf7, 0xc6, 0xf3, 0xd4, 0xa3, 0x55, 0xe4, 0x34, - 0x1e, 0xe2, 0xc0, 0x33, 0xc1, 0x07, 0xc8, 0x4b, 0xb9, 0xe7, 0x84, 0x83, - 0x18, 0xa4, 0x20, 0xd1, 0x48, 0xfb, 0x0f, 0x2e, 0xc4, 0x94, 0xd9, 0xfe, - 0xb1, 0xb9, 0x56, 0xae, 0xb1, 0x61, 0x9e, 0x15, 0x2b, 0x8a, 0xfc, 0xff, - 0x23, 0xf2, 0x7b, 0xcd, 0xf0, 0x94, 0x89, 0xfc, 0x1c, 0x70, 0xfb, 0x1b, - 0xb0, 0x8f, 0x6d, 0xce, 0xec, 0x76, 0x60, 0x40, 0x6b, 0xc5, 0xc0, 0x04, - 0x3c, 0x9f, 0xb3, 0xcd, 0xbb, 0x23, 0xbf, 0x98, 0x6b, 0x71, 0x87, 0xf7, - 0xd0, 0x1d, 0x7d, 0xc1, 0x58, 0x5e, 0x26, 0xfb, 0x95, 0x7b, 0x3e, 0x6d, - 0x6c, 0x9f, 0xcd, 0xfb, 0x3d, 0x6b, 0x3c, 0x62, 0xfa, 0x89, 0x7f, 0x9a, - 0x2b, 0x75, 0xb9, 0xd7, 0x13, 0x06, 0x2e, 0xea, 0xe7, 0xe4, 0xfd, 0x49, - 0x93, 0xeb, 0xf5, 0x26, 0xe4, 0x6c, 0x65, 0x6d, 0xc7, 0x32, 0xf2, 0x28, - 0xa8, 0xba, 0x71, 0xdd, 0x67, 0x33, 0x39, 0x50, 0xe1, 0x10, 0x22, 0xab, - 0x2c, 0xd7, 0xf0, 0x64, 0xf2, 0x6e, 0xc7, 0xd1, 0x93, 0x94, 0x9a, 0xb9, - 0xbc, 0x9f, 0x5d, 0x82, 0x17, 0xf5, 0x87, 0xb0, 0xa0, 0xec, 0x0f, 0x9c, - 0x4f, 0x72, 0x30, 0xad, 0x1c, 0xcf, 0x30, 0x36, 0xea, 0xf5, 0xfa, 0x45, - 0x7c, 0x13, 0x53, 0x15, 0x21, 0xb3, 0x86, 0x91, 0xd7, 0xe4, 0x51, 0xb4, - 0x3d, 0x6b, 0xe0, 0x2c, 0xd5, 0x88, 0xfd, 0xa2, 0x93, 0x82, 0x31, 0xb2, - 0x26, 0xc1, 0x19, 0xc9, 0xf1, 0x4b, 0x4e, 0x3c, 0x12, 0xae, 0x69, 0xea, - 0x54, 0x1e, 0x64, 0xcc, 0xff, 0x4e, 0x50, 0xde, 0x21, 0xf4, 0xb7, 0xd7, - 0xd8, 0x90, 0x37, 0x19, 0xca, 0xc5, 0x2f, 0x83, 0x72, 0x9f, 0x1b, 0xae, - 0xb1, 0xb4, 0x37, 0xd2, 0x68, 0x57, 0x5d, 0x69, 0xb3, 0x56, 0x29, 0xb8, - 0x9b, 0xa0, 0xcc, 0x89, 0x2d, 0x26, 0xa6, 0xdc, 0x85, 0x15, 0xe6, 0x39, - 0xab, 0xf4, 0xa7, 0xc2, 0x1b, 0x8e, 0x90, 0x37, 0x00, 0xb9, 0x03, 0xc6, - 0xb2, 0xe6, 0x60, 0xbd, 0xde, 0x87, 0xdb, 0xc9, 0xfd, 0x97, 0xe1, 0x23, - 0x5d, 0xea, 0x24, 0x91, 0x6f, 0x39, 0xcc, 0xfb, 0x38, 0x87, 0x83, 0x5b, - 0xa3, 0x2b, 0xb1, 0x7f, 0x30, 0xa2, 0x38, 0x9b, 0xbc, 0xad, 0x31, 0xf2, - 0x22, 0x42, 0xba, 0x99, 0x23, 0xdc, 0x41, 0xfe, 0x70, 0x38, 0xd4, 0x89, - 0xed, 0x7a, 0x2e, 0x7a, 0xf5, 0x70, 0x5e, 0xcf, 0x92, 0x2e, 0xbc, 0xa2, - 0x17, 0x4a, 0x1e, 0x9e, 0xf8, 0xae, 0x6d, 0x4a, 0xc2, 0xdf, 0xf1, 0x21, - 0xbc, 0x53, 0x47, 0xc9, 0x41, 0xce, 0xdb, 0x15, 0xf8, 0x97, 0x3a, 0x5c, - 0xb1, 0xb1, 0x26, 0xec, 0x9b, 0xa8, 0x70, 0xc5, 0xc7, 0x18, 0x0f, 0x4e, - 0x30, 0x86, 0x61, 0x1c, 0xac, 0x8d, 0xad, 0xc4, 0xb6, 0x61, 0xb9, 0xe3, - 0x1b, 0xc0, 0xdd, 0x65, 0xe7, 0x8c, 0xa7, 0xfd, 0x82, 0xa3, 0xf3, 0x71, - 0x67, 0x99, 0xcf, 0xf4, 0x81, 0xed, 0xb6, 0xaf, 0xe3, 0x0f, 0x76, 0x6c, - 0x0e, 0xfe, 0xc8, 0x08, 0x3f, 0x26, 0x72, 0x7b, 0x9e, 0x67, 0xf4, 0x00, - 0xb1, 0xd4, 0x92, 0xe1, 0x86, 0x6b, 0x32, 0x0c, 0xa1, 0x7b, 0x30, 0x44, - 0xfb, 0x71, 0x93, 0x6f, 0x5d, 0x3f, 0x87, 0xf5, 0xba, 0x6f, 0x66, 0x08, - 0xad, 0x78, 0x65, 0xe2, 0x6f, 0xd8, 0x4f, 0xf2, 0x33, 0x4b, 0xd1, 0x91, - 0x89, 0x47, 0xc2, 0xb6, 0x02, 0xf2, 0x3f, 0xcb, 0x0f, 0x0c, 0x0c, 0xcb, - 0x73, 0xef, 0xbe, 0x30, 0xb9, 0xcc, 0x8b, 0x0d, 0x33, 0xd4, 0xc3, 0x48, - 0xa7, 0xdd, 0x7c, 0x2f, 0xe2, 0xca, 0xf7, 0xdc, 0x75, 0xde, 0x75, 0x33, - 0x0a, 0xf0, 0x17, 0x31, 0xfa, 0x64, 0x9b, 0xf4, 0x95, 0xb1, 0x9d, 0x38, - 0xd8, 0x30, 0x1f, 0x53, 0x6b, 0x65, 0x4c, 0x99, 0xcf, 0x30, 0x9e, 0xa3, - 0x8e, 0xff, 0x00, 0x4e, 0xe4, 0xde, 0x65, 0xc7, 0x39, 0x95, 0xb6, 0xa2, - 0xff, 0xde, 0x48, 0xd3, 0x57, 0x6e, 0xcd, 0xd8, 0xcc, 0x36, 0xda, 0xcc, - 0x28, 0x6d, 0xa6, 0x9f, 0x36, 0x73, 0xf7, 0xa2, 0x3b, 0x32, 0x36, 0x23, - 0xb1, 0xe1, 0x34, 0x1e, 0xe9, 0x57, 0xd1, 0xf6, 0x9f, 0xa6, 0xd1, 0x76, - 0x20, 0xbb, 0x76, 0xd1, 0xbb, 0xec, 0xfa, 0xa5, 0xde, 0x28, 0xf3, 0xc8, - 0x1a, 0x65, 0x2f, 0xd9, 0xdf, 0xaf, 0x7f, 0xaf, 0xd6, 0x9c, 0x78, 0xc2, - 0xdc, 0xd7, 0xdf, 0x57, 0x5b, 0x75, 0xfa, 0xec, 0x7e, 0xc2, 0x37, 0x7d, - 0xaf, 0xbd, 0xed, 0xc6, 0xef, 0x7b, 0xdd, 0x37, 0x7e, 0x3f, 0x79, 0xd3, - 0xf3, 0xac, 0x6d, 0x5c, 0x97, 0x69, 0xa7, 0xee, 0xeb, 0x9c, 0xe4, 0x3e, - 0x3f, 0xba, 0xeb, 0xb0, 0xd1, 0xfe, 0xb0, 0xac, 0x25, 0x40, 0x9e, 0x24, - 0xeb, 0x7b, 0x0f, 0x0b, 0xfe, 0x68, 0x6d, 0xef, 0x64, 0x6c, 0xc9, 0x7c, - 0x37, 0xc8, 0xd4, 0xab, 0xd7, 0x27, 0x34, 0xfc, 0xf8, 0x86, 0xfb, 0x8b, - 0x01, 0x65, 0x47, 0x4c, 0x74, 0xca, 0x11, 0x71, 0x35, 0x41, 0xb9, 0xd3, - 0x1f, 0xc1, 0x42, 0x7f, 0x17, 0x3e, 0xa2, 0xce, 0xb7, 0x29, 0x1a, 0xe3, - 0xbb, 0x24, 0xe2, 0x63, 0x5e, 0x7d, 0x13, 0xb1, 0x22, 0x36, 0xf6, 0x97, - 0x38, 0x91, 0xcc, 0xa7, 0x0e, 0x76, 0x61, 0x65, 0xd0, 0x1b, 0x18, 0xa2, - 0xef, 0xbd, 0xa0, 0x8b, 0x9d, 0x4a, 0xed, 0xd7, 0x43, 0x0c, 0x0d, 0x08, - 0x06, 0xaa, 0x29, 0xf1, 0xc9, 0xb4, 0x3d, 0xe1, 0xd8, 0x0e, 0xea, 0xc6, - 0xd6, 0xe1, 0xb7, 0xd0, 0x12, 0x95, 0x7c, 0xeb, 0x71, 0x3c, 0x9a, 0xa4, - 0x0f, 0xd2, 0x68, 0xb7, 0x8b, 0x1c, 0xd0, 0xca, 0x24, 0x27, 0xec, 0xc0, - 0xda, 0xf8, 0x7c, 0x44, 0xaa, 0xa4, 0xae, 0xb2, 0x12, 0xdb, 0x07, 0x15, - 0xfc, 0x56, 0x6a, 0x98, 0x8c, 0xc1, 0x5f, 0x27, 0x47, 0x9c, 0x8c, 0x6e, - 0xc1, 0x88, 0x59, 0xa3, 0xd6, 0xfa, 0xaa, 0xed, 0xe1, 0x17, 0x4b, 0xc9, - 0xb7, 0x13, 0xba, 0xbf, 0x9d, 0xf6, 0xe8, 0x29, 0x6a, 0xf2, 0x87, 0x63, - 0xca, 0x57, 0xf8, 0x37, 0xf3, 0xae, 0x8d, 0xee, 0xda, 0x44, 0x5d, 0xdf, - 0x33, 0x2c, 0xfd, 0xb8, 0xc7, 0x5b, 0xe6, 0x3a, 0xac, 0x77, 0xdd, 0xad, - 0xbc, 0xe4, 0x5b, 0x38, 0x98, 0x76, 0xe1, 0xa9, 0xb8, 0x47, 0xb1, 0xef, - 0x51, 0xd1, 0x12, 0xf7, 0x9e, 0xbc, 0x60, 0x37, 0x8c, 0xba, 0xc5, 0x25, - 0x98, 0x21, 0xbf, 0xa8, 0x5c, 0x2c, 0x3e, 0xe1, 0x3f, 0x23, 0x55, 0xd5, - 0x4c, 0x6c, 0x43, 0xa1, 0x6d, 0x89, 0x57, 0xb7, 0xd9, 0x7d, 0xad, 0x33, - 0xd8, 0x8a, 0xbc, 0xb1, 0x07, 0xcc, 0x75, 0x7f, 0x23, 0x2e, 0xef, 0x2f, - 0xd5, 0x53, 0xdf, 0xe8, 0x27, 0x0f, 0x89, 0x0c, 0x11, 0xa9, 0x6c, 0x82, - 0xa7, 0xa2, 0x69, 0xd7, 0x7c, 0xe4, 0x7f, 0x45, 0xce, 0x3d, 0x8d, 0x89, - 0xa4, 0xd6, 0x51, 0x62, 0x33, 0x70, 0x3a, 0x78, 0x27, 0x52, 0x66, 0x0d, - 0x63, 0x25, 0xfa, 0x07, 0x25, 0x3f, 0xaf, 0x40, 0x5b, 0x54, 0x40, 0xce, - 0xa7, 0x05, 0x5e, 0xb4, 0x49, 0xcd, 0x79, 0x0b, 0xbe, 0xc1, 0xbd, 0xde, - 0x1f, 0x15, 0x7b, 0xd5, 0xdc, 0x6d, 0x4a, 0xf8, 0xaa, 0x9d, 0x7b, 0xfd, - 0xb5, 0xee, 0x3f, 0xf9, 0x6b, 0xbb, 0x7f, 0x2a, 0x64, 0xd7, 0x5d, 0x93, - 0xe3, 0x2a, 0x31, 0xc4, 0x8a, 0x31, 0xd3, 0xe4, 0xb4, 0x85, 0x1c, 0xb7, - 0x20, 0x78, 0x89, 0xdc, 0x40, 0xc6, 0x5d, 0x3e, 0x0f, 0xc5, 0x2d, 0xe8, - 0xdf, 0xfb, 0xa1, 0x11, 0x6e, 0x93, 0x39, 0xfe, 0xc0, 0xb8, 0xd4, 0x89, - 0x95, 0x6b, 0x3d, 0x58, 0x11, 0x97, 0x9c, 0xea, 0x8f, 0x2b, 0x2d, 0xdd, - 0x92, 0xef, 0x0e, 0x74, 0xe8, 0x04, 0xdb, 0xaa, 0x2f, 0x8d, 0x0a, 0x33, - 0x66, 0xbd, 0x6f, 0xbe, 0xe8, 0x4b, 0x6f, 0xe2, 0x85, 0xf9, 0x62, 0xdf, - 0xbd, 0x13, 0x4f, 0xbb, 0x2d, 0xbd, 0x7b, 0x99, 0xdf, 0x65, 0x2c, 0x6d, - 0xdf, 0x16, 0x9c, 0xa9, 0x14, 0x5e, 0xf3, 0xe8, 0xf8, 0xec, 0xf6, 0x56, - 0xbd, 0xea, 0xf5, 0x6b, 0xb9, 0x1a, 0xa9, 0x13, 0x86, 0x95, 0xb6, 0x68, - 0xab, 0xb2, 0x3a, 0x2a, 0xb5, 0x42, 0x5b, 0xa8, 0x80, 0x1c, 0xe6, 0x98, - 0x2e, 0xef, 0xea, 0x65, 0xeb, 0x86, 0x11, 0xa5, 0x2f, 0x44, 0xc6, 0x33, - 0xd6, 0xac, 0xec, 0x88, 0x96, 0xc9, 0x5d, 0x07, 0xea, 0xa5, 0x83, 0x32, - 0x75, 0x21, 0x67, 0x54, 0x62, 0xf2, 0x02, 0xe4, 0x1c, 0xd0, 0x90, 0x3b, - 0xd6, 0x8e, 0x11, 0x32, 0xb8, 0x92, 0xda, 0x72, 0x1c, 0x0a, 0xc8, 0x5d, - 0x8e, 0x0a, 0x14, 0x09, 0xb6, 0x6a, 0x3d, 0x78, 0xb5, 0x0d, 0x4a, 0x41, - 0xed, 0x6c, 0x9e, 0x6a, 0xde, 0x5f, 0x57, 0xdd, 0x4d, 0xe2, 0xdb, 0x25, - 0xc7, 0x6f, 0xd5, 0x1d, 0xcf, 0xa6, 0x37, 0x60, 0x4c, 0xe5, 0xb2, 0xb5, - 0x7f, 0x33, 0xc6, 0x2b, 0xcc, 0x77, 0x7e, 0xc8, 0x81, 0x0f, 0x93, 0x03, - 0x1b, 0xcb, 0xba, 0x82, 0x91, 0x9f, 0xd5, 0xc0, 0xdb, 0xa7, 0xdb, 0xbd, - 0x9e, 0x46, 0x9b, 0xe4, 0x10, 0xa0, 0xe4, 0xd4, 0x46, 0x90, 0x5b, 0x5b, - 0x18, 0xb1, 0x53, 0xbf, 0xcf, 0xe8, 0x22, 0xfb, 0x2e, 0xec, 0xd4, 0xf3, - 0xe5, 0x7d, 0xf9, 0x48, 0x31, 0x79, 0x4b, 0x0c, 0x9a, 0x7a, 0x1a, 0xda, - 0xcc, 0x27, 0xec, 0xb7, 0x82, 0xf6, 0xd0, 0x3d, 0xe6, 0x0d, 0x5f, 0x54, - 0xbc, 0x53, 0x77, 0xd3, 0x46, 0x5e, 0x19, 0xa3, 0x1d, 0x12, 0x77, 0xfb, - 0x69, 0x03, 0x7d, 0xb4, 0x85, 0x7d, 0x13, 0x87, 0x84, 0x47, 0xf4, 0xb5, - 0x2b, 0xd6, 0x3d, 0x4c, 0xab, 0xde, 0x2e, 0x35, 0xb5, 0x88, 0xb2, 0x21, - 0x24, 0x7e, 0xb0, 0x08, 0xe7, 0x93, 0xc0, 0x91, 0x74, 0x0e, 0x5e, 0x1b, - 0x41, 0x8b, 0x0d, 0xf6, 0x5e, 0x17, 0xea, 0xd6, 0xa9, 0x78, 0xa3, 0xae, - 0x40, 0xfe, 0x87, 0x11, 0x15, 0x9d, 0x8c, 0x09, 0xcb, 0xb0, 0x62, 0xb7, - 0xb1, 0xec, 0xae, 0x45, 0xc6, 0xb2, 0xcd, 0xfa, 0x63, 0x58, 0x63, 0x62, - 0x4c, 0x77, 0x7b, 0x01, 0xe3, 0xdb, 0x1f, 0x8e, 0x38, 0x91, 0x4a, 0xb1, - 0x17, 0xe5, 0x35, 0x9c, 0xc2, 0x03, 0x0e, 0x62, 0x27, 0xfd, 0x58, 0x5d, - 0x71, 0x93, 0xbf, 0xed, 0x6e, 0x85, 0xbc, 0x32, 0x5d, 0x81, 0x54, 0x5a, - 0xe3, 0x5f, 0x80, 0x7f, 0x0d, 0xfc, 0x6b, 0xc4, 0x9a, 0xa8, 0xe8, 0xa8, - 0x1b, 0x63, 0xe9, 0x22, 0x7c, 0x98, 0xd4, 0x02, 0x2e, 0xea, 0xcf, 0x88, - 0x3e, 0x6e, 0x44, 0xda, 0xac, 0x38, 0xe4, 0xf3, 0xa4, 0xe4, 0x74, 0x8a, - 0xf0, 0x59, 0xea, 0xf4, 0x7c, 0x8b, 0xdb, 0x77, 0xe1, 0x62, 0x30, 0x3f, - 0x52, 0x6a, 0xfa, 0x1c, 0x6f, 0xe0, 0x35, 0x68, 0xeb, 0xae, 0x70, 0xdf, - 0xbb, 0xc6, 0x52, 0xc6, 0xb9, 0x0a, 0xb1, 0xf5, 0xe3, 0xf8, 0x49, 0xf2, - 0x8a, 0x51, 0x23, 0x9c, 0x33, 0x21, 0xf7, 0xf5, 0xad, 0x3c, 0x8b, 0xc4, - 0x46, 0x85, 0x4b, 0x67, 0x9f, 0xc9, 0x71, 0xa4, 0x53, 0xb3, 0xcf, 0x05, - 0xed, 0x8e, 0x26, 0x57, 0xc3, 0x8e, 0xa8, 0xfd, 0x4a, 0x3e, 0x79, 0xd4, - 0xfd, 0x4b, 0x34, 0xbd, 0x4e, 0x71, 0x35, 0xf4, 0xa6, 0x5d, 0x0d, 0x7d, - 0xd1, 0xd9, 0xe7, 0x7a, 0x44, 0xb1, 0x37, 0xc9, 0x38, 0x7e, 0xc6, 0xdc, - 0xd9, 0xb1, 0x5c, 0x0d, 0xdd, 0xe9, 0xd9, 0x63, 0x75, 0xa1, 0x23, 0x28, - 0x67, 0xe4, 0xdd, 0xe4, 0xbc, 0xa1, 0x6e, 0x20, 0x3e, 0xdc, 0x7c, 0xcf, - 0xa5, 0xe3, 0xbb, 0xd7, 0xfa, 0x6a, 0xc4, 0x32, 0xfa, 0xc5, 0x89, 0xd9, - 0xfd, 0xa7, 0xf1, 0x6e, 0xd2, 0xfc, 0x7f, 0x06, 0x74, 0x7c, 0xce, 0x18, - 0xf1, 0x54, 0xf0, 0xb0, 0xe1, 0x29, 0x15, 0x19, 0x1f, 0xc7, 0x07, 0xdc, - 0x5b, 0xa1, 0xb6, 0xb5, 0xdd, 0xad, 0x69, 0x27, 0x3f, 0xb6, 0x3b, 0x50, - 0xb7, 0xf4, 0x38, 0x4e, 0xa4, 0xe4, 0x0c, 0x8b, 0xcc, 0x77, 0x6d, 0x27, - 0x79, 0x06, 0x07, 0x53, 0xc5, 0xb7, 0xcb, 0xfd, 0x75, 0xbb, 0xdc, 0x63, - 0xc6, 0xff, 0x07, 0xb6, 0x0b, 0xca, 0xea, 0xc4, 0x79, 0x00, 0x00, 0x00 }; + 0xec, 0x5c, 0x7f, 0x70, 0x1c, 0xd5, 0x7d, 0xff, 0xbc, 0xbd, 0xbd, 0xbb, + 0x95, 0x74, 0x3e, 0xed, 0x9d, 0x4e, 0xb2, 0x04, 0x06, 0xef, 0xa2, 0x95, + 0x74, 0x58, 0xc6, 0xec, 0x9d, 0x4e, 0xb6, 0x48, 0xb7, 0xc9, 0xd5, 0x36, + 0x20, 0x17, 0x52, 0x84, 0xa1, 0xc1, 0xcc, 0x30, 0x9d, 0x1b, 0x63, 0x8c, + 0xb0, 0x1d, 0xa2, 0x00, 0x33, 0xc8, 0x29, 0x13, 0x16, 0xfc, 0xb3, 0xf8, + 0xa4, 0x93, 0x8d, 0x8c, 0xc9, 0xf4, 0xd7, 0x21, 0xcb, 0x8a, 0x81, 0x93, + 0xce, 0x04, 0xda, 0x98, 0x69, 0xa8, 0x15, 0x6c, 0x53, 0x87, 0x5f, 0x21, + 0x19, 0x68, 0x4d, 0x9b, 0x99, 0xa8, 0x06, 0x1c, 0xd3, 0xa6, 0xd4, 0xb4, + 0x0e, 0xb5, 0x8b, 0xeb, 0xd7, 0xef, 0x77, 0x4f, 0x97, 0x50, 0x42, 0xcb, + 0x64, 0xa6, 0x7f, 0xee, 0x77, 0xe6, 0xe6, 0xf6, 0xde, 0xfb, 0xbe, 0xef, + 0x7b, 0xdf, 0xdf, 0x9f, 0xb7, 0x1a, 0xfb, 0xbe, 0x08, 0x6a, 0x31, 0x4b, + 0x73, 0xe8, 0x93, 0x19, 0x18, 0xbc, 0x27, 0xbd, 0x28, 0xb3, 0x88, 0x1e, + 0xbb, 0x02, 0x73, 0x55, 0x95, 0xc7, 0x05, 0x7c, 0xf2, 0xc9, 0x27, 0x9f, + 0x7c, 0xf2, 0xc9, 0x27, 0x9f, 0x7c, 0xf2, 0xc9, 0x27, 0x9f, 0x7c, 0xf2, + 0xc9, 0x27, 0x9f, 0x7c, 0xf2, 0xc9, 0x27, 0x9f, 0x7c, 0xf2, 0xc9, 0x27, + 0x9f, 0x7c, 0xf2, 0xc9, 0x27, 0x9f, 0x7c, 0xf2, 0xc9, 0x27, 0x9f, 0x7c, + 0xf2, 0xc9, 0x27, 0x9f, 0x7c, 0xf2, 0xc9, 0x27, 0x9f, 0x7c, 0xf2, 0xc9, + 0x27, 0x9f, 0x7c, 0xf2, 0xc9, 0x27, 0x9f, 0x7c, 0xfa, 0xff, 0xa4, 0x00, + 0xa0, 0xf3, 0xf7, 0x9c, 0xd9, 0x0f, 0x34, 0xc5, 0x71, 0x37, 0x2e, 0xb5, + 0xa0, 0x05, 0x9c, 0x33, 0x1b, 0x6f, 0xb7, 0x80, 0x6c, 0xa9, 0xd3, 0x58, + 0x86, 0xff, 0x92, 0x6e, 0x42, 0x05, 0x8f, 0x5f, 0xe2, 0x9c, 0xff, 0xf3, + 0x17, 0x96, 0x98, 0xa7, 0x8b, 0x01, 0x68, 0xba, 0xf3, 0x46, 0x4a, 0x6f, + 0x87, 0x36, 0x8f, 0xd6, 0xfc, 0x49, 0xc7, 0x95, 0x71, 0x44, 0xab, 0xb2, + 0xe0, 0x2a, 0x8e, 0x94, 0xfb, 0x6c, 0x89, 0x97, 0x6c, 0x57, 0xf4, 0x66, + 0xe0, 0x06, 0x9c, 0x83, 0xe2, 0xae, 0xfc, 0x05, 0x69, 0x04, 0x2b, 0x3b, + 0xab, 0x93, 0x1a, 0x82, 0xfb, 0xa0, 0xab, 0x8e, 0x82, 0xa0, 0x55, 0x8b, + 0xd0, 0x13, 0x75, 0x08, 0x3e, 0xd1, 0x8c, 0xf0, 0xe4, 0x01, 0x91, 0x2b, + 0x6a, 0x98, 0x09, 0x1c, 0x14, 0x6b, 0x4a, 0xc8, 0x05, 0x9d, 0xb3, 0x37, + 0x8c, 0xd1, 0xba, 0xac, 0xf7, 0xef, 0x4b, 0xa6, 0x6f, 0x18, 0x2f, 0x41, + 0x0f, 0x38, 0x50, 0x54, 0xe7, 0x08, 0x3d, 0x33, 0xdf, 0xd9, 0x1b, 0xf6, + 0x96, 0x4e, 0xc9, 0x17, 0x3a, 0x12, 0x38, 0x54, 0xd6, 0x71, 0xa0, 0xfc, + 0x10, 0x9d, 0xc3, 0x74, 0x5d, 0x68, 0xae, 0xea, 0xb8, 0xd8, 0x92, 0x09, + 0x62, 0x62, 0xe4, 0x82, 0x0c, 0x58, 0xa6, 0x01, 0xc5, 0xd2, 0x0f, 0x83, + 0xf8, 0x0a, 0xc4, 0x57, 0x08, 0x62, 0xac, 0xb8, 0x23, 0x8e, 0xda, 0x66, + 0xbc, 0xd0, 0xc1, 0xeb, 0x79, 0x2d, 0xcb, 0xf8, 0x38, 0x5a, 0x5d, 0x1f, + 0xa2, 0xf5, 0x47, 0x33, 0xc0, 0xf8, 0x48, 0x1f, 0x2d, 0x95, 0xd8, 0x64, + 0x87, 0xb1, 0x5a, 0x87, 0x5b, 0xe3, 0xb0, 0xac, 0xaa, 0x1c, 0x57, 0x18, + 0x93, 0xff, 0x5c, 0x5f, 0x91, 0x03, 0xa1, 0x59, 0x70, 0xc3, 0x9f, 0x9a, + 0x3f, 0x55, 0xaa, 0xce, 0x6f, 0xa7, 0x7d, 0x34, 0x9a, 0xef, 0xc7, 0x5f, + 0x96, 0xd7, 0xe0, 0x2f, 0xca, 0xb7, 0xe1, 0xd9, 0x72, 0x1f, 0xed, 0x7b, + 0x1f, 0xed, 0x3b, 0x80, 0xbf, 0x2e, 0x6f, 0xc0, 0x77, 0xcb, 0x39, 0x3c, + 0x57, 0x5e, 0x85, 0xef, 0x94, 0x6f, 0xc6, 0x33, 0x65, 0x78, 0x67, 0x38, + 0x95, 0x49, 0x8a, 0x1f, 0xe5, 0x6b, 0xa0, 0xee, 0xdc, 0x8c, 0xe9, 0x52, + 0x10, 0xc1, 0x9d, 0x12, 0x23, 0xb6, 0xf9, 0x38, 0xd0, 0xa1, 0x07, 0x21, + 0xb0, 0xcc, 0x36, 0xf7, 0x03, 0x5f, 0x40, 0x2e, 0x61, 0x1e, 0x00, 0x9a, + 0xc4, 0x8f, 0x47, 0x9b, 0xc4, 0x6b, 0xa3, 0xaa, 0x78, 0x3d, 0x2f, 0x50, + 0xef, 0x20, 0xf2, 0x72, 0x46, 0xca, 0xeb, 0xd2, 0x52, 0x96, 0x52, 0x56, + 0xef, 0x0f, 0x85, 0x69, 0x3f, 0x22, 0x2e, 0x85, 0xd1, 0x68, 0x66, 0xd7, + 0x09, 0xcd, 0xad, 0x25, 0xf9, 0x2b, 0xba, 0x01, 0x6b, 0xa7, 0x41, 0x7e, + 0x60, 0x1d, 0x37, 0xe1, 0x0e, 0x2f, 0x26, 0xfa, 0xd0, 0x60, 0x2d, 0xc5, + 0xbd, 0x7d, 0x36, 0x8a, 0x65, 0x68, 0x31, 0xe7, 0x0c, 0x52, 0xc3, 0x02, + 0x36, 0xf9, 0x5b, 0xd0, 0xb3, 0x5d, 0x5a, 0xdf, 0x50, 0xf1, 0x37, 0x9d, + 0xbd, 0x40, 0x67, 0x2f, 0xd0, 0xd9, 0x0b, 0xa4, 0x57, 0x81, 0xf4, 0x2a, + 0x90, 0x0e, 0x05, 0xd2, 0xad, 0x40, 0x7a, 0x14, 0x48, 0x8f, 0x02, 0xe9, + 0x58, 0x60, 0x5f, 0x0d, 0x92, 0x0d, 0x22, 0xf8, 0xbb, 0xfc, 0x3c, 0x9c, + 0xe1, 0xcf, 0x4a, 0x1d, 0xc7, 0xe9, 0x8c, 0x8a, 0xf5, 0x9b, 0xca, 0xf8, + 0x6e, 0x84, 0x7c, 0x64, 0xfc, 0xe6, 0x7b, 0x2f, 0xc4, 0xc9, 0xfc, 0xbb, + 0x32, 0x34, 0x97, 0xf7, 0xfc, 0x22, 0xe4, 0x28, 0x70, 0xe9, 0x6e, 0x29, + 0xcf, 0x75, 0xcd, 0xc8, 0xb7, 0x6f, 0x61, 0x59, 0x0e, 0x4e, 0x8c, 0x2a, + 0x08, 0xd0, 0xd8, 0xb5, 0xf6, 0xdf, 0xcb, 0x3b, 0x13, 0xcc, 0xf7, 0x51, + 0x04, 0xb5, 0x6c, 0x27, 0x68, 0x0d, 0xce, 0xbb, 0x1b, 0xef, 0x6d, 0x87, + 0x1b, 0x75, 0x54, 0xf1, 0xe6, 0x90, 0x81, 0xb9, 0x4e, 0x16, 0x73, 0x1c, + 0x6b, 0x64, 0x8f, 0xd2, 0x39, 0x18, 0x47, 0xf6, 0xf2, 0x7a, 0xd8, 0xd8, + 0x57, 0x56, 0xc5, 0xab, 0x43, 0x73, 0x10, 0xdf, 0x69, 0xad, 0x1a, 0x12, + 0x0a, 0x72, 0x8d, 0x59, 0x8c, 0x67, 0x4c, 0xa3, 0x08, 0x03, 0xab, 0xd2, + 0x0a, 0x30, 0xd7, 0xc5, 0xd6, 0x8c, 0x69, 0xbb, 0x78, 0x08, 0xd3, 0x09, + 0x1b, 0x13, 0x65, 0x8d, 0x72, 0xc3, 0xc5, 0x9d, 0x19, 0x0d, 0x72, 0x24, + 0x8b, 0x93, 0x5d, 0x21, 0x4c, 0xf7, 0x71, 0x8c, 0xa8, 0xb4, 0xf7, 0x56, + 0x28, 0xf1, 0x38, 0xf9, 0xe5, 0xb0, 0x0c, 0xc6, 0x79, 0x0c, 0xe2, 0x5f, + 0x32, 0xbc, 0xff, 0x45, 0xe2, 0xd5, 0xdd, 0x51, 0xd4, 0xee, 0xd6, 0xf0, + 0xf4, 0x4e, 0x15, 0x2b, 0xc8, 0xb7, 0x7b, 0x52, 0xaa, 0xb1, 0x4e, 0x38, + 0x18, 0x2f, 0xab, 0x48, 0x0c, 0xb5, 0xc0, 0x88, 0x69, 0xb8, 0x74, 0xc8, + 0xc5, 0x3b, 0x24, 0x77, 0x90, 0xe4, 0xd6, 0x77, 0xe9, 0x98, 0x69, 0xac, + 0xf8, 0xf5, 0xeb, 0xf9, 0x56, 0x77, 0xa7, 0x12, 0x02, 0x42, 0x70, 0x35, + 0x27, 0x83, 0xfb, 0xf3, 0xad, 0xa4, 0xc3, 0xad, 0x58, 0x1a, 0xd2, 0xb0, + 0x7a, 0x98, 0xc7, 0x96, 0x03, 0x93, 0x73, 0xe7, 0xa0, 0x96, 0xf5, 0xe7, + 0x7c, 0x5e, 0x4a, 0xcf, 0x1c, 0x07, 0xbf, 0x9d, 0x60, 0xbb, 0xbb, 0xca, + 0x7f, 0xc8, 0x6c, 0x82, 0xf9, 0x2a, 0x39, 0x72, 0x38, 0x93, 0xc1, 0xc6, + 0x7c, 0x6b, 0xf6, 0x5b, 0x4a, 0x03, 0x10, 0x34, 0x0d, 0x43, 0x81, 0x96, + 0x70, 0x90, 0x1a, 0xa5, 0x78, 0x79, 0xd4, 0x8b, 0x17, 0xa4, 0xba, 0x4a, + 0x9c, 0x97, 0x9a, 0xab, 0x13, 0xff, 0xfc, 0xc5, 0x6d, 0xf8, 0xe8, 0x51, + 0xe6, 0x53, 0xf1, 0x03, 0x7a, 0x7e, 0x7f, 0xef, 0x8e, 0xd9, 0xda, 0xf1, + 0xa7, 0x9e, 0x5f, 0x0d, 0xa5, 0xba, 0xb7, 0x8d, 0x3b, 0xf3, 0xad, 0x67, + 0xb7, 0x29, 0xe4, 0xbf, 0x8b, 0x23, 0xa8, 0xa1, 0xfa, 0x13, 0x24, 0x59, + 0xfb, 0xf2, 0xe7, 0xb1, 0x32, 0x6d, 0x1e, 0xe4, 0x7f, 0x6f, 0x36, 0x66, + 0x55, 0xe4, 0x5f, 0x56, 0xb2, 0xf1, 0x64, 0xd9, 0xc6, 0xed, 0x74, 0x8e, + 0xfb, 0xf0, 0x8f, 0x40, 0xcb, 0x02, 0xe3, 0x94, 0x72, 0x42, 0xba, 0x37, + 0xb3, 0xbc, 0x79, 0x38, 0x15, 0x6f, 0xcd, 0x9d, 0x52, 0xcc, 0xe2, 0x76, + 0x85, 0x6d, 0xa5, 0xe0, 0xcb, 0xe9, 0x0c, 0x8a, 0x31, 0x1d, 0xb7, 0xa6, + 0x35, 0xf7, 0x52, 0x3a, 0xd3, 0x1b, 0x4b, 0x34, 0x34, 0xed, 0xca, 0xe2, + 0xad, 0xf4, 0x9b, 0x28, 0xae, 0x64, 0x3b, 0xf0, 0x3a, 0x3e, 0x73, 0x33, + 0xe2, 0x56, 0x0d, 0xe2, 0x63, 0x41, 0xd4, 0xef, 0xba, 0x20, 0x9b, 0x2d, + 0x1e, 0xb7, 0x06, 0xce, 0x0a, 0x3e, 0x73, 0x10, 0xd1, 0xb1, 0xab, 0xa0, + 0x5a, 0x66, 0x92, 0x1c, 0x9b, 0x60, 0xde, 0x90, 0x55, 0x3d, 0xbb, 0xc0, + 0x75, 0x5f, 0x10, 0x58, 0x97, 0xfa, 0xbe, 0xcc, 0x36, 0xf2, 0x9a, 0x67, + 0x68, 0x9c, 0xcf, 0x50, 0x73, 0x36, 0x8b, 0x26, 0x5a, 0x53, 0xe5, 0x8b, + 0xa0, 0x7f, 0x57, 0xe5, 0x0c, 0x6f, 0x2f, 0xc1, 0xb3, 0x1a, 0x7a, 0xd0, + 0x51, 0x78, 0x08, 0x6f, 0x2d, 0xf6, 0xf6, 0x3f, 0xbd, 0x2f, 0xbd, 0x83, + 0x6c, 0xc2, 0x75, 0xf4, 0xd3, 0x7e, 0xe1, 0xf9, 0xff, 0x64, 0x7f, 0x24, + 0x21, 0x9a, 0x69, 0x8c, 0xe3, 0x77, 0xa7, 0x34, 0x6e, 0xaa, 0xf8, 0x25, + 0x4c, 0xf2, 0xde, 0xcf, 0xf4, 0xa0, 0x75, 0x48, 0x85, 0xcc, 0xb7, 0xda, + 0x3f, 0x0d, 0x3c, 0x22, 0xa7, 0x6f, 0xe3, 0xb9, 0x56, 0xfd, 0x70, 0x40, + 0x60, 0xa9, 0x6a, 0x9e, 0xce, 0xa1, 0x19, 0xfb, 0xa9, 0xc6, 0xb4, 0x38, + 0x3a, 0xd5, 0x9c, 0x04, 0xd5, 0x1e, 0x43, 0x74, 0xec, 0xb1, 0xb1, 0x60, + 0xe8, 0x36, 0x7c, 0x69, 0xb7, 0x83, 0x83, 0x05, 0x1b, 0x4f, 0x17, 0xa4, + 0x3c, 0x69, 0x4b, 0xf9, 0xaf, 0x5d, 0x66, 0xff, 0x31, 0x6a, 0x07, 0x8b, + 0x96, 0x74, 0xe6, 0xea, 0x03, 0x2a, 0xd9, 0xa7, 0xcd, 0xd8, 0x20, 0xcc, + 0xe6, 0x29, 0x61, 0x53, 0xcc, 0xf5, 0x92, 0xed, 0x0d, 0xec, 0x2d, 0x27, + 0xf1, 0x54, 0xd9, 0xa2, 0xcf, 0x42, 0x8a, 0x95, 0x0c, 0xd5, 0x33, 0xd6, + 0x55, 0xc7, 0x78, 0x07, 0xe5, 0x45, 0x41, 0xc1, 0x7e, 0x9b, 0xe2, 0x3f, + 0x46, 0xbc, 0x85, 0x0b, 0xe4, 0x3f, 0x0d, 0xc9, 0x9d, 0x59, 0xd4, 0xa4, + 0x1a, 0x60, 0xdc, 0x68, 0x61, 0xbc, 0xa0, 0xb9, 0x41, 0x8a, 0xf9, 0xb1, + 0xfc, 0x38, 0xfe, 0x40, 0x4f, 0xa0, 0x96, 0xec, 0xb7, 0x2a, 0x1d, 0x01, + 0x6e, 0xe2, 0xb9, 0x08, 0x5a, 0xac, 0xef, 0xa3, 0x25, 0x3e, 0x07, 0xa1, + 0x05, 0x7f, 0x85, 0x69, 0x3d, 0x8a, 0x30, 0xf5, 0x8c, 0xf9, 0xc4, 0x33, + 0x9f, 0x7c, 0xd5, 0x68, 0x59, 0x24, 0x53, 0xc0, 0x6a, 0x23, 0x5e, 0xca, + 0xa7, 0x66, 0xd2, 0x3d, 0xb8, 0x24, 0x81, 0x32, 0x9d, 0x7f, 0x2a, 0x2f, + 0x65, 0x24, 0x63, 0xf6, 0x17, 0x28, 0x37, 0x27, 0x4b, 0x3d, 0x98, 0x2a, + 0xff, 0x1e, 0xd5, 0x73, 0x1b, 0x7b, 0xf3, 0x0e, 0xc6, 0x0a, 0xea, 0xaa, + 0x3c, 0xcc, 0xbe, 0xf5, 0xc8, 0xe0, 0x29, 0x8a, 0x9f, 0x89, 0x82, 0x69, + 0xbc, 0x18, 0xd0, 0x70, 0xcc, 0xae, 0xa3, 0x73, 0x52, 0xde, 0x92, 0x4e, + 0xcf, 0xe7, 0x47, 0x60, 0x35, 0xb0, 0xfd, 0xd9, 0x4f, 0x19, 0x7c, 0xbb, + 0xe0, 0xc5, 0xf7, 0x75, 0x1a, 0x5c, 0xd8, 0xdd, 0xec, 0x1b, 0xf7, 0x74, + 0x30, 0x5d, 0xa9, 0xa3, 0x7d, 0xdd, 0x36, 0xc2, 0xc3, 0x3d, 0x24, 0xb7, + 0xd5, 0x3e, 0x81, 0x3b, 0x30, 0xdd, 0xec, 0x62, 0x11, 0xc5, 0xbf, 0xea, + 0x3c, 0x9e, 0xda, 0x9c, 0x77, 0x65, 0xbd, 0x65, 0xf5, 0xff, 0x50, 0x3c, + 0x88, 0x57, 0x53, 0x5c, 0xd7, 0x55, 0xca, 0x7b, 0x1d, 0x3b, 0xec, 0x11, + 0xbc, 0x56, 0xfa, 0x2d, 0xe4, 0x62, 0x66, 0x72, 0x93, 0x58, 0x8f, 0x83, + 0x23, 0x57, 0x01, 0xb7, 0x70, 0x9e, 0x90, 0x6e, 0xd6, 0x7a, 0x1c, 0x2a, + 0x7e, 0x03, 0x47, 0x47, 0x6b, 0xf1, 0xbc, 0x15, 0x47, 0xcb, 0x44, 0x65, + 0x9f, 0xab, 0xbb, 0x35, 0x8c, 0x51, 0x4e, 0x5f, 0x6b, 0xab, 0x98, 0x49, + 0x70, 0xfd, 0xa0, 0x58, 0x4b, 0x6f, 0xa0, 0x5a, 0xe3, 0xb5, 0x5e, 0xac, + 0xc9, 0x18, 0xc8, 0xe7, 0xb3, 0x54, 0xff, 0x6a, 0xb0, 0x2b, 0x06, 0x71, + 0x3b, 0xf5, 0xb0, 0xbb, 0xf3, 0xad, 0xfd, 0xc3, 0x4a, 0x1c, 0xc5, 0x96, + 0x2c, 0xf9, 0x42, 0xa0, 0xc9, 0x32, 0xb0, 0xa5, 0x44, 0x15, 0xb4, 0xa4, + 0xe2, 0x9b, 0xa5, 0x2b, 0x50, 0x6c, 0xe2, 0xb5, 0x1d, 0x98, 0xf6, 0xbe, + 0x83, 0x98, 0x89, 0x9b, 0xcd, 0x20, 0x9b, 0x8d, 0x17, 0x54, 0xec, 0xb6, + 0xf7, 0x5c, 0x28, 0xae, 0x34, 0xf5, 0x1c, 0xe5, 0x5b, 0xc0, 0x8b, 0x5b, + 0x7e, 0x06, 0xbe, 0x96, 0xff, 0x50, 0x9e, 0xf1, 0xf6, 0x54, 0x39, 0xff, + 0xa7, 0xdf, 0x0e, 0xbc, 0x2f, 0x45, 0x98, 0xe5, 0xdf, 0x1f, 0xad, 0xfc, + 0x5b, 0xd1, 0x67, 0x99, 0x37, 0x0b, 0x70, 0x1c, 0xcc, 0xfd, 0x44, 0xcc, + 0x57, 0xea, 0x80, 0xbe, 0x98, 0xcf, 0x51, 0xcd, 0xb3, 0x38, 0x9a, 0x26, + 0xda, 0x50, 0xb3, 0x8b, 0x7f, 0xf3, 0xb8, 0xc0, 0x65, 0xdd, 0x9c, 0x63, + 0x6d, 0x50, 0xc6, 0x56, 0x47, 0x2b, 0x35, 0xb8, 0x5a, 0x1f, 0xfe, 0x70, + 0x56, 0xbe, 0xd7, 0xeb, 0xe9, 0x77, 0xa5, 0x86, 0x7e, 0x33, 0xc3, 0xcf, + 0xbc, 0xa6, 0x06, 0x6f, 0xed, 0x35, 0xed, 0xa2, 0xb2, 0x84, 0xf7, 0xac, + 0xe4, 0x08, 0x36, 0xce, 0xae, 0xa1, 0x98, 0x2f, 0x4c, 0x49, 0xdc, 0xca, + 0xf2, 0xaa, 0xeb, 0xdb, 0x10, 0xfa, 0xe5, 0xbe, 0x2a, 0x5e, 0xcc, 0x7c, + 0x7a, 0xdf, 0xdb, 0x64, 0xed, 0xca, 0x38, 0xc5, 0x59, 0x23, 0xd4, 0x05, + 0xd4, 0xe0, 0xf5, 0x26, 0xd4, 0x51, 0xde, 0x06, 0xac, 0x5b, 0x64, 0xe0, + 0x2b, 0x1c, 0xa7, 0x9a, 0x1b, 0x71, 0x2e, 0xc6, 0xf0, 0xce, 0x17, 0xc8, + 0xc7, 0x51, 0x8e, 0x47, 0xf2, 0xf3, 0xc5, 0x18, 0x7a, 0xe2, 0x92, 0x28, + 0xeb, 0xbb, 0x2a, 0x0d, 0x77, 0x3e, 0xd5, 0xec, 0xf7, 0xf6, 0xdc, 0x2d, + 0x8b, 0x7d, 0x3a, 0x5e, 0xca, 0xfc, 0x0e, 0x8d, 0x73, 0x3c, 0xd9, 0x78, + 0x2e, 0xaf, 0xe1, 0xfe, 0xe1, 0x66, 0x3a, 0x27, 0xd7, 0xca, 0x9a, 0xb3, + 0x33, 0x8a, 0x8d, 0x67, 0x29, 0x16, 0x9f, 0x29, 0xb0, 0xad, 0x54, 0x5c, + 0x96, 0x5e, 0x21, 0xc3, 0x4d, 0x1c, 0xdf, 0x49, 0x5a, 0xa3, 0x93, 0xec, + 0x28, 0x74, 0x6b, 0x99, 0x3c, 0xb0, 0x92, 0x9f, 0x3b, 0x68, 0xac, 0x89, + 0xbe, 0xbb, 0x65, 0xdd, 0xaf, 0x9d, 0x43, 0xff, 0xac, 0x73, 0x50, 0xdc, + 0x9b, 0xf6, 0x5a, 0x74, 0x12, 0x0e, 0x52, 0x91, 0xa5, 0x3e, 0x3f, 0x41, + 0x31, 0xb0, 0x8d, 0x7a, 0xf0, 0x7b, 0x84, 0xf5, 0xb6, 0x78, 0x78, 0xca, + 0x83, 0x67, 0x1e, 0x5e, 0x5b, 0x5d, 0xc1, 0x5d, 0x9a, 0x6a, 0x31, 0x16, + 0xab, 0xce, 0x71, 0x9e, 0xf6, 0x62, 0x6c, 0x54, 0xca, 0xcd, 0x76, 0x0b, + 0xc9, 0x88, 0x63, 0xb3, 0x45, 0x39, 0x3d, 0xca, 0x6b, 0xa4, 0x4c, 0xa6, + 0x16, 0xf4, 0xa8, 0xa2, 0x01, 0x33, 0xba, 0x2b, 0xd6, 0x66, 0x0c, 0xf1, + 0xd5, 0x51, 0x15, 0xf9, 0xc2, 0x45, 0x64, 0x2f, 0x29, 0x9f, 0x4a, 0x21, + 0xbb, 0x29, 0x55, 0x87, 0x57, 0x8a, 0x3a, 0x72, 0xfa, 0x05, 0xb9, 0xbc, + 0xad, 0x17, 0x65, 0x92, 0xf3, 0x41, 0xaa, 0x33, 0x79, 0x44, 0x44, 0x50, + 0x4c, 0x44, 0xf0, 0x78, 0x21, 0x81, 0x23, 0xe3, 0x11, 0x6c, 0xa5, 0x18, + 0x7d, 0x31, 0xc3, 0x7b, 0x46, 0xf0, 0x70, 0x99, 0x31, 0x55, 0x80, 0x6c, + 0xe4, 0x8a, 0x13, 0xde, 0x58, 0x1d, 0x96, 0x17, 0x99, 0xf7, 0x82, 0x6c, + 0xb1, 0x2c, 0xbd, 0x25, 0x50, 0xe5, 0x3b, 0x4e, 0xf8, 0xca, 0xa0, 0x5a, + 0x36, 0x8f, 0x70, 0x55, 0x33, 0x61, 0xa8, 0x04, 0x61, 0x28, 0x6b, 0x16, + 0x17, 0x9a, 0x94, 0x8d, 0x52, 0x3e, 0x4b, 0xb5, 0xec, 0xc7, 0xf4, 0x39, + 0x43, 0xf5, 0x34, 0x46, 0x3a, 0x5e, 0x36, 0xcc, 0x3a, 0xba, 0xc2, 0xa6, + 0x7a, 0x9b, 0x55, 0x94, 0x7a, 0xee, 0x43, 0x81, 0x29, 0xde, 0x5f, 0xc5, + 0x96, 0x02, 0xb0, 0xa9, 0x00, 0xf7, 0x08, 0xe5, 0x7e, 0xc3, 0x44, 0x14, + 0xf1, 0x09, 0x1d, 0xc1, 0x89, 0x24, 0xcd, 0x6b, 0x48, 0xd0, 0x6f, 0x97, + 0xb0, 0x60, 0xbd, 0xd3, 0x24, 0x16, 0x3e, 0x76, 0x5e, 0xee, 0x48, 0xa9, + 0x58, 0xd7, 0x66, 0xf6, 0xde, 0x28, 0x90, 0x4d, 0x0e, 0x49, 0x19, 0x4e, + 0x85, 0x29, 0x37, 0xe5, 0xa1, 0x04, 0xe9, 0x1d, 0x75, 0xe4, 0x83, 0xaf, + 0x75, 0x5b, 0xf6, 0x6b, 0x20, 0xb9, 0x65, 0x5e, 0xc3, 0xe3, 0xae, 0xf8, + 0xb0, 0xdb, 0x7a, 0xfc, 0x4d, 0xb4, 0xa3, 0x6b, 0x42, 0x15, 0xff, 0x36, + 0xb4, 0x10, 0xe9, 0x29, 0xe8, 0x21, 0xe7, 0x80, 0x98, 0x79, 0xe2, 0xa0, + 0x38, 0x39, 0x49, 0xe7, 0x2e, 0x90, 0x2e, 0x05, 0xd2, 0xa5, 0x40, 0xba, + 0x90, 0x5d, 0x9e, 0xf1, 0xf0, 0x24, 0xeb, 0x9a, 0x24, 0x2c, 0x73, 0xdc, + 0xc3, 0xbc, 0x8c, 0x11, 0x63, 0x8e, 0x99, 0x75, 0xc1, 0x7a, 0xb3, 0x9e, + 0x52, 0xbe, 0x69, 0x57, 0xf4, 0x71, 0xa9, 0xdc, 0x6a, 0x53, 0x55, 0x5b, + 0x48, 0xf9, 0xef, 0x36, 0xdb, 0x82, 0x75, 0x94, 0xf2, 0x3b, 0xa4, 0xd3, + 0x16, 0xd2, 0x71, 0x53, 0x41, 0x1e, 0x0a, 0x59, 0x96, 0x31, 0x41, 0x67, + 0x8b, 0x93, 0x4e, 0x89, 0x09, 0x8d, 0x74, 0x6d, 0x87, 0x4a, 0xba, 0x06, + 0x26, 0xa0, 0x2b, 0x74, 0x1e, 0x63, 0x8c, 0xec, 0x34, 0xf5, 0x79, 0xe7, + 0x61, 0xcc, 0xef, 0x8a, 0xab, 0x09, 0x9f, 0xa8, 0x64, 0xd7, 0x4d, 0x14, + 0x3b, 0x39, 0x15, 0x46, 0xd8, 0x52, 0xa8, 0x27, 0x6a, 0xf8, 0xf6, 0x78, + 0x1d, 0x26, 0xc8, 0xef, 0xc5, 0x71, 0xe8, 0x41, 0x92, 0xe9, 0x16, 0x0f, + 0x8a, 0x4f, 0xc6, 0x5b, 0xd0, 0x19, 0x20, 0x9c, 0x04, 0x3c, 0x92, 0x8f, + 0x8b, 0x89, 0x11, 0x15, 0x9b, 0x0b, 0xa7, 0x49, 0x3f, 0x89, 0xc3, 0xf6, + 0xc3, 0xcd, 0xc4, 0x22, 0x1e, 0xb6, 0xcd, 0x1e, 0xe0, 0x2a, 0x8a, 0xb7, + 0x00, 0xd6, 0x5a, 0xc8, 0x6e, 0xb3, 0xaf, 0xc2, 0x4c, 0x1f, 0x8c, 0xed, + 0xb6, 0xab, 0x87, 0x60, 0x1e, 0xbb, 0x9a, 0x7a, 0xd3, 0x95, 0xa4, 0xcf, + 0xa0, 0xe5, 0x0e, 0x50, 0xe1, 0x42, 0xb9, 0x6c, 0xf6, 0x1f, 0x25, 0x5f, + 0x94, 0xa8, 0xff, 0x95, 0xca, 0x4d, 0xe2, 0xe9, 0xd1, 0xf3, 0xf2, 0xae, + 0x94, 0x99, 0x6d, 0xa3, 0xb1, 0xe0, 0x90, 0x46, 0x38, 0x4d, 0xa3, 0x9c, + 0x32, 0x6d, 0x80, 0x6b, 0x03, 0xb4, 0x30, 0xd5, 0xe2, 0x9f, 0x59, 0x47, + 0x08, 0xa7, 0x6b, 0x20, 0x0c, 0x8f, 0xa5, 0x23, 0x02, 0xfb, 0x28, 0xc7, + 0x27, 0x17, 0x9a, 0xc7, 0x56, 0xc3, 0x9d, 0x6e, 0x81, 0x39, 0x18, 0x0e, + 0x9c, 0xc6, 0x07, 0x43, 0x21, 0xc2, 0x0d, 0xed, 0xf6, 0xeb, 0x30, 0xf5, + 0x7d, 0x81, 0x5f, 0xc8, 0xfd, 0x09, 0x5c, 0x14, 0xc4, 0x19, 0x69, 0xfc, + 0x3e, 0xaf, 0x61, 0xdd, 0x07, 0xb0, 0x2d, 0xc3, 0x38, 0x45, 0x25, 0x9c, + 0x02, 0xbc, 0x93, 0x37, 0xb0, 0x7f, 0x61, 0x0d, 0xf5, 0x93, 0xd6, 0x9e, + 0x75, 0x70, 0x57, 0xd1, 0xf5, 0x47, 0x8b, 0xd0, 0x5e, 0x79, 0x8a, 0x95, + 0x0d, 0x42, 0xe0, 0x29, 0xeb, 0xac, 0xdd, 0x31, 0xc9, 0x18, 0x46, 0x4d, + 0x2d, 0xa0, 0x5c, 0xdc, 0x5a, 0x16, 0xd4, 0xdb, 0x4c, 0x7d, 0x06, 0x6c, + 0x1b, 0x9d, 0xec, 0x7a, 0x5e, 0x22, 0xc6, 0xba, 0xbb, 0x39, 0xd2, 0x73, + 0xd5, 0x16, 0x3a, 0xff, 0x1a, 0xd2, 0xe9, 0x2e, 0xcb, 0xed, 0x21, 0xa9, + 0xd4, 0xa3, 0xcc, 0xe6, 0xf7, 0x48, 0xf7, 0xb5, 0x54, 0x47, 0x8a, 0xe5, + 0xe7, 0xea, 0xb9, 0x66, 0x4c, 0x94, 0xf9, 0x1e, 0xd7, 0x83, 0xa5, 0xf9, + 0x6a, 0x3e, 0xb0, 0xff, 0xd9, 0xf7, 0x1c, 0x0b, 0x1c, 0x33, 0x1c, 0x27, + 0x8c, 0xd1, 0x7a, 0x30, 0xda, 0xae, 0x20, 0x9b, 0x90, 0x72, 0xa5, 0x65, + 0x8e, 0x70, 0x1d, 0xa7, 0x98, 0xcf, 0xee, 0xb5, 0xeb, 0x29, 0x3f, 0xe1, + 0x3e, 0x69, 0x1b, 0x08, 0x39, 0x1c, 0x1b, 0x75, 0x14, 0xeb, 0x11, 0x6c, + 0xa3, 0x58, 0xd1, 0x2c, 0x2b, 0x49, 0x97, 0x0d, 0xfd, 0x9d, 0x0c, 0xf1, + 0x96, 0x61, 0x94, 0xed, 0x5a, 0xc2, 0x95, 0x2a, 0x62, 0xce, 0x21, 0xd9, + 0x60, 0x35, 0xea, 0xd4, 0xb8, 0xf5, 0x7b, 0xb1, 0x9a, 0xee, 0x17, 0x06, + 0xea, 0x1c, 0x9e, 0x3f, 0x27, 0x67, 0x62, 0x11, 0x8a, 0x33, 0xe6, 0xb1, + 0xdc, 0x67, 0xf0, 0x91, 0x44, 0x9c, 0x79, 0xb3, 0x58, 0x9d, 0x81, 0x38, + 0x48, 0x7b, 0xa1, 0x81, 0x73, 0xd7, 0xc0, 0x7c, 0xc7, 0x3a, 0x76, 0x88, + 0x7a, 0x8f, 0xd1, 0x00, 0xaa, 0xb9, 0x2a, 0x02, 0x8e, 0xa5, 0xef, 0xc5, + 0x51, 0xaf, 0x4e, 0x11, 0x52, 0x17, 0x2b, 0x76, 0xcf, 0x13, 0xbd, 0x84, + 0xcd, 0xdb, 0x53, 0x70, 0x34, 0xb4, 0x19, 0x7f, 0x43, 0xa3, 0x9b, 0x29, + 0xfe, 0xe7, 0x38, 0x11, 0x51, 0xda, 0x0d, 0xfd, 0x69, 0x5b, 0xa3, 0x3e, + 0x2a, 0xe5, 0xd6, 0x94, 0x81, 0x29, 0x9b, 0x70, 0x74, 0x63, 0x10, 0x31, + 0x0b, 0xba, 0xee, 0x58, 0x83, 0x07, 0x30, 0xc0, 0xf8, 0x37, 0x3a, 0x9f, + 0x7a, 0x25, 0x8d, 0x89, 0x31, 0xbb, 0x06, 0xd9, 0x9b, 0x05, 0x22, 0x4e, + 0x82, 0xce, 0x16, 0x42, 0xce, 0x7b, 0x66, 0x1d, 0x91, 0x7d, 0xd7, 0xde, + 0x43, 0xfa, 0x8a, 0xf9, 0xb5, 0x0e, 0x8f, 0x59, 0x76, 0x09, 0x77, 0x11, + 0x56, 0xa7, 0x21, 0x9a, 0xdf, 0x4c, 0xf3, 0x8f, 0x92, 0xec, 0x5c, 0xdc, + 0xbb, 0x87, 0xd6, 0xb7, 0x38, 0xd6, 0xf4, 0xf3, 0xd8, 0x4e, 0x3a, 0x70, + 0x8d, 0xe7, 0x31, 0x3e, 0xf3, 0x42, 0x3e, 0x33, 0xf5, 0x78, 0x8e, 0x2b, + 0x1b, 0x3f, 0xcb, 0xd3, 0xde, 0x09, 0x64, 0xb7, 0xdb, 0x10, 0x13, 0xf6, + 0x6e, 0xc2, 0x2f, 0xa8, 0x8f, 0x3a, 0x56, 0xff, 0x14, 0xa0, 0x44, 0x9c, + 0x9d, 0x28, 0xc5, 0x80, 0x47, 0x0b, 0x96, 0x7b, 0x8f, 0x62, 0x0e, 0x26, + 0x08, 0x13, 0x9f, 0x21, 0x4c, 0xbf, 0xab, 0x7d, 0xda, 0x8c, 0x83, 0xb1, + 0x7e, 0x54, 0xbc, 0xb4, 0x5b, 0x41, 0xc7, 0x62, 0xea, 0x4b, 0x54, 0x4b, + 0xae, 0xb1, 0xf9, 0xbe, 0x7c, 0x79, 0x7d, 0x05, 0x2f, 0xff, 0x6f, 0x39, + 0x69, 0x92, 0xc5, 0xaa, 0x79, 0x69, 0xf5, 0x3d, 0x8d, 0x3f, 0x93, 0xd9, + 0x18, 0xfb, 0x22, 0x42, 0xb5, 0xf8, 0x97, 0xf5, 0x28, 0x39, 0x49, 0xf2, + 0x37, 0x75, 0x07, 0x75, 0x8e, 0x19, 0xf2, 0x65, 0xf6, 0x8d, 0x3c, 0x44, + 0x7d, 0x9a, 0xf2, 0x2a, 0xc6, 0x7e, 0xe1, 0xfb, 0x3d, 0x19, 0x6f, 0x38, + 0x41, 0xba, 0xa9, 0xe8, 0x4a, 0xa3, 0x5e, 0x71, 0xac, 0xb3, 0x63, 0x74, + 0xe6, 0x16, 0xa7, 0x1e, 0xe7, 0x1a, 0xb8, 0x36, 0x46, 0xc5, 0x0f, 0x46, + 0xcd, 0x1e, 0xc2, 0xc3, 0xab, 0xee, 0x21, 0x1c, 0x75, 0x9f, 0x50, 0xd1, + 0x4b, 0x67, 0xb7, 0xda, 0xc8, 0x07, 0x84, 0x4d, 0x12, 0x6d, 0xd3, 0x66, + 0x02, 0xd5, 0xf3, 0x5e, 0x90, 0x71, 0xcb, 0x72, 0xe3, 0xca, 0xc7, 0x32, + 0x95, 0xe6, 0x18, 0xdf, 0x80, 0x70, 0x5c, 0x20, 0x94, 0x1e, 0xf2, 0x6c, + 0x4b, 0x77, 0x2a, 0xd4, 0xa7, 0x1f, 0x62, 0x1f, 0x11, 0x7e, 0x7b, 0x59, + 0xe6, 0xbe, 0xc2, 0xba, 0x6d, 0x9f, 0xd5, 0x73, 0x2d, 0xc7, 0x15, 0xfd, + 0x96, 0x73, 0xd8, 0xde, 0x87, 0xa8, 0x8e, 0x77, 0x2d, 0xe9, 0xdc, 0x3e, + 0xa8, 0x0c, 0x49, 0x63, 0x25, 0xfb, 0x93, 0x2e, 0x37, 0xb5, 0x9e, 0xaf, + 0xb5, 0xa8, 0x73, 0x1c, 0xaf, 0x0f, 0x45, 0x45, 0xfd, 0x63, 0xae, 0xd7, + 0x53, 0x5f, 0xa3, 0xb3, 0x9c, 0x4c, 0xf1, 0x19, 0x38, 0xc7, 0x8e, 0xe3, + 0x8a, 0xd2, 0xed, 0xc4, 0x1b, 0xa0, 0xfd, 0xa1, 0x51, 0xbc, 0x41, 0x52, + 0x9f, 0x39, 0xd7, 0x35, 0x25, 0x8d, 0x06, 0x96, 0x4f, 0xb6, 0x1e, 0x65, + 0x5b, 0xf3, 0xdd, 0xb2, 0x6a, 0x6f, 0xe6, 0xe7, 0xf5, 0x74, 0xe9, 0x8e, + 0xb1, 0xff, 0x50, 0x5f, 0xe7, 0xb0, 0x4d, 0x21, 0x6a, 0x9c, 0x4e, 0x63, + 0x81, 0xd8, 0x21, 0xdd, 0x44, 0xb5, 0x86, 0x45, 0xc5, 0x84, 0xb7, 0x9e, + 0xf7, 0xfe, 0xf4, 0xfa, 0x26, 0xf1, 0xce, 0x9e, 0xdf, 0xa5, 0x67, 0x2f, + 0x46, 0x7a, 0x9f, 0xa2, 0x1c, 0xd2, 0x9c, 0x7e, 0x99, 0x6c, 0xe4, 0x18, + 0x83, 0xf2, 0x8a, 0xbd, 0x56, 0xe6, 0x1a, 0x39, 0xd6, 0xe0, 0x26, 0x48, + 0xce, 0xae, 0xc7, 0x7e, 0x75, 0x8e, 0xab, 0xdb, 0xa5, 0x9c, 0xb0, 0xd7, + 0x90, 0x2d, 0x58, 0x4e, 0xd5, 0x16, 0x7b, 0x66, 0x6d, 0xd3, 0x5e, 0xf1, + 0x5f, 0xc1, 0x3b, 0x83, 0x16, 0x72, 0xde, 0xc0, 0x4b, 0x79, 0xa5, 0x89, + 0x6e, 0x2b, 0xe8, 0xb3, 0x05, 0x7e, 0xda, 0x43, 0xfa, 0x5d, 0x49, 0x58, + 0x65, 0x91, 0x35, 0xdd, 0x1a, 0x58, 0x2f, 0x31, 0x77, 0x9a, 0x82, 0xe3, + 0xbc, 0xd4, 0xda, 0x55, 0x84, 0xaf, 0xe0, 0x1e, 0xc5, 0xb6, 0x57, 0xf0, + 0x32, 0xf1, 0xad, 0xb8, 0xc2, 0x32, 0x5a, 0x05, 0xf5, 0xb5, 0xbe, 0xa5, + 0xe9, 0xe0, 0x2f, 0x63, 0x8f, 0xcf, 0x90, 0xf3, 0x74, 0xe0, 0x18, 0xec, + 0x22, 0xdf, 0xe5, 0x56, 0x2a, 0x48, 0x2d, 0x06, 0x61, 0x8d, 0xa8, 0xd8, + 0xba, 0x9b, 0xfd, 0xff, 0x3d, 0x9a, 0x67, 0xbe, 0xce, 0x66, 0x1d, 0xd6, + 0xaa, 0xc3, 0x74, 0xb1, 0x24, 0x2c, 0x4a, 0xf6, 0xe0, 0xbd, 0xaa, 0x72, + 0xaa, 0x32, 0xa2, 0x62, 0x72, 0x94, 0x79, 0x59, 0x17, 0xaa, 0xcd, 0x1c, + 0x2b, 0x29, 0x8e, 0x8f, 0x8f, 0x65, 0x47, 0x3a, 0x1a, 0x43, 0x2d, 0xaf, + 0x89, 0x0a, 0x7d, 0x0f, 0xcb, 0x85, 0x60, 0x3b, 0xc6, 0x48, 0xff, 0xf6, + 0xf4, 0xe5, 0xb3, 0xfa, 0xff, 0xb1, 0x5e, 0xc1, 0x71, 0x51, 0x71, 0xd4, + 0xdb, 0xbb, 0x62, 0xa3, 0x49, 0xb2, 0xf5, 0x44, 0xaa, 0xca, 0xf3, 0x38, + 0xf1, 0x70, 0x9c, 0x7d, 0x66, 0x4f, 0x22, 0xea, 0x15, 0x8f, 0xe4, 0xe9, + 0x92, 0x6a, 0x29, 0xd7, 0xd7, 0x52, 0x9e, 0x3c, 0x49, 0xbd, 0x69, 0x7f, + 0xb1, 0x57, 0x6c, 0xcb, 0xeb, 0xd4, 0xa7, 0x96, 0x8b, 0xad, 0x79, 0x8b, + 0x71, 0xd1, 0x6c, 0x9f, 0xaa, 0xbc, 0x8b, 0xda, 0x52, 0xfa, 0xe4, 0x3b, + 0xa2, 0x48, 0x4e, 0x77, 0xd0, 0x37, 0x7f, 0xf8, 0x41, 0xa9, 0x58, 0xfc, + 0x3e, 0xc8, 0x3a, 0x76, 0x22, 0x10, 0xe9, 0xe9, 0x59, 0x12, 0x40, 0xbd, + 0x85, 0xbe, 0x66, 0xc2, 0x07, 0x57, 0x7a, 0x35, 0xdd, 0x80, 0x51, 0x6a, + 0x6f, 0xac, 0xf8, 0x89, 0xf3, 0x0e, 0x6a, 0xad, 0x83, 0x5c, 0x0d, 0xd5, + 0x91, 0x6b, 0xba, 0x43, 0xda, 0xd1, 0xee, 0xde, 0x96, 0xf6, 0xc9, 0xa6, + 0x5c, 0xad, 0x73, 0x7d, 0x4b, 0xdb, 0xa4, 0xdb, 0xb2, 0x70, 0x08, 0xf8, + 0xf2, 0x90, 0x0e, 0xcd, 0xb9, 0xd1, 0x0d, 0x74, 0x23, 0xa7, 0x52, 0x5c, + 0xec, 0xe8, 0xb6, 0x7a, 0xa6, 0xc4, 0x4d, 0x37, 0x91, 0x1e, 0x2d, 0x9d, + 0x93, 0x86, 0xb1, 0x39, 0xf3, 0xc0, 0x4d, 0x81, 0x29, 0xee, 0x2f, 0x1b, + 0x06, 0xf7, 0xf1, 0x7b, 0x33, 0xba, 0x9b, 0x9e, 0xd0, 0xf1, 0xc0, 0xb2, + 0xee, 0x41, 0x0c, 0xe4, 0x1f, 0x40, 0x7f, 0x9e, 0xdf, 0x3b, 0x69, 0x18, + 0xe1, 0x1a, 0x5f, 0xe0, 0x77, 0x4e, 0x0f, 0x35, 0x30, 0x6e, 0xdc, 0x5e, + 0x56, 0x71, 0xed, 0x10, 0xcf, 0x99, 0xcd, 0xef, 0xa3, 0xca, 0xfb, 0x59, + 0x7c, 0x9f, 0xd4, 0x93, 0x6b, 0x1e, 0xb2, 0x81, 0x61, 0x29, 0x95, 0x0c, + 0xdf, 0x63, 0x4e, 0x13, 0xd6, 0xe3, 0xbd, 0x7f, 0x4e, 0xbd, 0x71, 0x2e, + 0xbf, 0x0b, 0x63, 0xca, 0x86, 0x87, 0x79, 0xee, 0xd4, 0xec, 0xdc, 0xbb, + 0x34, 0x07, 0x71, 0x92, 0xea, 0xfa, 0x74, 0x25, 0x2f, 0xb2, 0xb5, 0xc3, + 0x1a, 0xfe, 0xa8, 0xc0, 0x3c, 0x33, 0xb3, 0x3c, 0x3f, 0x21, 0x9e, 0x04, + 0x56, 0xc4, 0xb8, 0x76, 0x53, 0xce, 0xec, 0xae, 0xbe, 0x2b, 0x93, 0xf2, + 0x25, 0xfb, 0xc3, 0x68, 0xe5, 0x5d, 0x59, 0x54, 0x68, 0x8f, 0xd1, 0x33, + 0x61, 0x95, 0x50, 0x2a, 0x2a, 0x42, 0x8f, 0xf1, 0xfa, 0x57, 0x53, 0x95, + 0xf5, 0xc7, 0x52, 0xbc, 0xfe, 0xd7, 0xd7, 0xa8, 0xd9, 0xc8, 0x30, 0xdd, + 0xa9, 0x0a, 0xff, 0x24, 0x77, 0x34, 0x56, 0x64, 0x57, 0xd6, 0x7d, 0x6f, + 0x76, 0xdd, 0x41, 0x5a, 0xb7, 0x8f, 0x62, 0x8c, 0xd7, 0xb2, 0x9e, 0x1c, + 0xa3, 0xd5, 0xf7, 0x86, 0x49, 0x71, 0x80, 0x7a, 0xf5, 0x81, 0x92, 0x2a, + 0xf6, 0x52, 0x1d, 0x1c, 0xcf, 0x13, 0x36, 0xf2, 0xde, 0x05, 0x52, 0xcd, + 0x2f, 0x7f, 0x23, 0x56, 0xf1, 0x21, 0xf7, 0xd5, 0x69, 0xea, 0xab, 0xed, + 0x54, 0xdf, 0x55, 0x4f, 0xa7, 0xb0, 0x73, 0x84, 0xea, 0xbb, 0xc0, 0x49, + 0xaf, 0xbe, 0x1c, 0x41, 0x7b, 0x89, 0xfb, 0x80, 0x25, 0xce, 0x15, 0x8c, + 0x5c, 0x33, 0xc9, 0x6e, 0x29, 0x57, 0x6a, 0x03, 0xf5, 0x82, 0x2c, 0xf5, + 0x64, 0xf1, 0x62, 0x89, 0x7f, 0x52, 0xf1, 0x8c, 0xf3, 0x19, 0xb2, 0x62, + 0x4e, 0xbb, 0x8b, 0xfa, 0x76, 0x97, 0x71, 0xec, 0xc0, 0xf3, 0xc2, 0x9a, + 0x3e, 0x27, 0xb2, 0xb7, 0x36, 0xe3, 0x41, 0xfc, 0x3c, 0x95, 0x5d, 0x11, + 0xa5, 0x6f, 0xc2, 0xcc, 0x86, 0xc6, 0xef, 0x48, 0xbb, 0xdb, 0x7a, 0x36, + 0x88, 0x36, 0xaa, 0x37, 0x6d, 0xee, 0x16, 0xb4, 0x51, 0xcf, 0xb7, 0xb5, + 0xc3, 0x25, 0x5b, 0x7b, 0xa3, 0x54, 0xb5, 0x03, 0xc7, 0x29, 0xdb, 0x80, + 0x42, 0xdf, 0xb1, 0xb2, 0x0b, 0x04, 0xf5, 0x55, 0xea, 0xbb, 0xc3, 0xd4, + 0xb3, 0x2b, 0xf7, 0xce, 0x30, 0xe1, 0x16, 0xde, 0x7b, 0xdd, 0xec, 0xbb, + 0x96, 0x7f, 0x90, 0x95, 0x1e, 0xf5, 0x0a, 0xd9, 0x83, 0xcf, 0xfc, 0xa3, + 0x48, 0x65, 0xfc, 0x4c, 0x6c, 0xf6, 0xff, 0xf9, 0x21, 0x9c, 0x42, 0xf7, + 0xc8, 0x21, 0x81, 0x1d, 0x6d, 0x95, 0x58, 0xee, 0xe4, 0xf7, 0x98, 0xde, + 0x7b, 0xb7, 0x2a, 0x4f, 0xc5, 0x86, 0x0a, 0xe1, 0x99, 0x43, 0xe5, 0xac, + 0xb8, 0x26, 0x8f, 0x01, 0xea, 0x89, 0xd9, 0x20, 0xf1, 0x5e, 0x53, 0xea, + 0x15, 0xcb, 0xf3, 0x96, 0xb1, 0x89, 0x74, 0xdd, 0xa2, 0x77, 0xea, 0xe3, + 0x84, 0x21, 0x68, 0x3f, 0x23, 0x4c, 0xf1, 0xaf, 0x39, 0x73, 0xb1, 0x7d, + 0x36, 0x76, 0x28, 0x1f, 0x28, 0x7f, 0x06, 0xc5, 0x82, 0x49, 0xfe, 0xa9, + 0x7b, 0xb1, 0x5b, 0xd1, 0xe3, 0x9c, 0xdc, 0x76, 0x33, 0xcf, 0x5f, 0x31, + 0x6b, 0xfb, 0xa6, 0x38, 0xed, 0x49, 0xbf, 0x47, 0x66, 0xcf, 0xff, 0x7f, + 0xad, 0xbd, 0xf6, 0x92, 0xff, 0xb9, 0x66, 0x86, 0xce, 0xc9, 0x18, 0x08, + 0x6e, 0xdc, 0x61, 0xfc, 0x33, 0x6f, 0xd6, 0xe7, 0xd4, 0x15, 0xa3, 0x03, + 0xb8, 0x71, 0x31, 0xdd, 0x7c, 0xe9, 0x0e, 0xb6, 0x8d, 0x7c, 0x95, 0x1c, + 0x66, 0xbd, 0xcf, 0x93, 0xde, 0xd0, 0x6a, 0x9c, 0xb3, 0xb8, 0x7c, 0xa8, + 0xb5, 0x3f, 0x2c, 0xcc, 0xe4, 0x90, 0x30, 0xfb, 0xa8, 0xbe, 0xd9, 0x93, + 0x30, 0x9b, 0x17, 0x08, 0xd3, 0x58, 0x0b, 0xb6, 0xc9, 0x79, 0xb4, 0x95, + 0xf8, 0xfb, 0x2c, 0x2c, 0xf2, 0x6b, 0xdf, 0x70, 0x00, 0x4a, 0xfa, 0x03, + 0xb2, 0x2b, 0xe1, 0x35, 0xd1, 0x4c, 0xb9, 0xc4, 0xb1, 0x77, 0x1e, 0x9b, + 0xf3, 0xd0, 0x5a, 0x88, 0xe7, 0x2a, 0xaa, 0xd1, 0xad, 0xc3, 0xe6, 0x59, + 0xc2, 0x9c, 0x83, 0x5f, 0x0a, 0xb4, 0x26, 0xfb, 0x61, 0x0e, 0x6c, 0x41, + 0xe7, 0xf4, 0x51, 0x61, 0x66, 0xcf, 0x12, 0x16, 0x0c, 0xa7, 0x2b, 0x32, + 0x17, 0xcd, 0xca, 0x4c, 0x32, 0x3e, 0xf6, 0x72, 0x88, 0x30, 0x74, 0xfa, + 0x6f, 0xe5, 0xb4, 0x67, 0xb3, 0xe0, 0xac, 0xfe, 0x4b, 0xe2, 0x15, 0x1f, + 0x3c, 0x37, 0x6b, 0x1f, 0x42, 0x24, 0xb5, 0xcc, 0xc7, 0xf7, 0x30, 0x88, + 0x35, 0xf9, 0x2f, 0xe2, 0x61, 0xc2, 0x43, 0x59, 0x6f, 0x7d, 0x2f, 0x72, + 0x25, 0x88, 0xb5, 0xf9, 0xe9, 0xf0, 0x51, 0x3b, 0x88, 0xa2, 0x27, 0xe7, + 0x7a, 0x1a, 0xeb, 0xa3, 0x0f, 0xdb, 0x8c, 0xef, 0xe4, 0x37, 0xd3, 0x73, + 0xd6, 0xe3, 0xeb, 0xcf, 0xa3, 0x27, 0x9c, 0x22, 0xdc, 0xe6, 0xf1, 0x79, + 0xf7, 0x75, 0xe2, 0x59, 0xce, 0x73, 0x23, 0xfc, 0xae, 0x61, 0x75, 0xa6, + 0xcd, 0x78, 0xd8, 0xbb, 0x23, 0x1a, 0x58, 0x53, 0x32, 0x70, 0x07, 0xd5, + 0xd5, 0xa2, 0x57, 0x57, 0x7f, 0x85, 0xe7, 0x15, 0xe2, 0x5b, 0x46, 0x7c, + 0x9b, 0xbc, 0x31, 0x03, 0xcb, 0x4b, 0xc7, 0xbd, 0x58, 0x51, 0x1d, 0xf6, + 0x03, 0xdb, 0x9e, 0xf1, 0x68, 0xf5, 0xae, 0xc6, 0x3e, 0xc9, 0x8a, 0x47, + 0xf3, 0xbd, 0x62, 0x67, 0x3e, 0x4a, 0xfb, 0xb9, 0x62, 0x24, 0xa3, 0x8c, + 0xc6, 0x20, 0xb1, 0x2c, 0x7d, 0x35, 0xd5, 0x19, 0x2b, 0x69, 0xd1, 0xb5, + 0x65, 0x6d, 0x72, 0x2e, 0x61, 0xa7, 0x25, 0x58, 0x97, 0x0c, 0x51, 0xff, + 0xfe, 0x16, 0xee, 0xd4, 0xc3, 0xe8, 0x4f, 0xde, 0x0b, 0xdc, 0x58, 0x43, + 0xfd, 0xf6, 0x61, 0x0f, 0xb3, 0x86, 0x68, 0xdf, 0x1a, 0xaa, 0x0d, 0x77, + 0x79, 0x7a, 0x4f, 0xb1, 0xae, 0x74, 0xce, 0xe5, 0x62, 0x84, 0xea, 0x7d, + 0xa2, 0x82, 0x01, 0x36, 0x66, 0x8a, 0xfc, 0x3d, 0xb3, 0xb1, 0xcb, 0xb3, + 0xf3, 0x4f, 0x36, 0xda, 0xa5, 0x5f, 0xc4, 0x2b, 0x3d, 0x75, 0x29, 0xb2, + 0x8d, 0xdd, 0x58, 0x9f, 0xec, 0xc1, 0x1c, 0x6b, 0x39, 0xbe, 0xaa, 0xbb, + 0x88, 0x5a, 0x63, 0xb8, 0xdb, 0x93, 0xc1, 0xf2, 0xbc, 0xbf, 0x6d, 0x10, + 0x4d, 0x13, 0xc8, 0xf9, 0xbc, 0xfb, 0x50, 0xe5, 0xdd, 0x42, 0x4e, 0x09, + 0x62, 0xd3, 0x2e, 0xfe, 0x56, 0x71, 0x77, 0xa6, 0xf2, 0xce, 0x70, 0x78, + 0x2c, 0x88, 0xa1, 0x5d, 0xd4, 0xfb, 0x52, 0x21, 0xb8, 0x8d, 0x9f, 0x96, + 0xdd, 0x4f, 0xb2, 0x2b, 0xf7, 0xef, 0xaf, 0x91, 0x5d, 0x67, 0x82, 0x41, + 0x34, 0x13, 0x0c, 0x4b, 0x10, 0x4f, 0xc3, 0x54, 0x1d, 0x9a, 0xc7, 0xf8, + 0xef, 0x23, 0x07, 0xc5, 0x7d, 0xa5, 0x0a, 0xcf, 0x46, 0xfe, 0x9b, 0x4a, + 0x58, 0xc1, 0x7c, 0x8b, 0xd5, 0x55, 0x89, 0x47, 0xa3, 0x7b, 0x5c, 0x2d, + 0xe6, 0x8f, 0xd5, 0xd1, 0x47, 0x47, 0x6c, 0x82, 0x26, 0xa6, 0x96, 0x8b, + 0xaf, 0xe7, 0x93, 0x88, 0xd1, 0xfd, 0x32, 0xee, 0x54, 0xd6, 0xdf, 0x53, + 0xfa, 0xbc, 0xf3, 0x07, 0xff, 0xbb, 0xb2, 0x6f, 0x01, 0x8e, 0xea, 0xbc, + 0xd2, 0xfc, 0x6e, 0x3f, 0xa4, 0xd6, 0x93, 0xab, 0x27, 0x2d, 0x1e, 0xa6, + 0x9b, 0xbe, 0x2d, 0xb5, 0xad, 0x4e, 0xb8, 0x0d, 0xa2, 0x90, 0x3d, 0xbd, + 0xa5, 0x06, 0x0b, 0x5b, 0x04, 0x63, 0xcb, 0xb6, 0x32, 0x83, 0x67, 0x53, + 0x63, 0x05, 0x03, 0xc6, 0xd8, 0x33, 0x91, 0x09, 0x35, 0x25, 0xef, 0xce, + 0x44, 0x77, 0x25, 0x10, 0x02, 0xf5, 0x4b, 0x12, 0x04, 0x98, 0xaa, 0x2d, + 0x37, 0x92, 0x40, 0xd8, 0x69, 0x49, 0x78, 0x92, 0xec, 0x90, 0x4c, 0xd5, + 0x58, 0x01, 0x61, 0x20, 0x04, 0xe3, 0xec, 0x4e, 0x6d, 0x91, 0x5d, 0xcf, + 0x98, 0xc2, 0x06, 0x9c, 0x18, 0x3f, 0x33, 0x59, 0x8b, 0x78, 0xe2, 0xbb, + 0xdf, 0xb9, 0xdd, 0x0d, 0x82, 0x21, 0x99, 0x1a, 0x57, 0x75, 0x89, 0xee, + 0x7b, 0xff, 0xff, 0x9e, 0xff, 0xfc, 0xe7, 0x7c, 0xe7, 0x3b, 0xe7, 0xfc, + 0xb7, 0x4c, 0x2e, 0x2d, 0xfb, 0xb5, 0x08, 0xc5, 0xda, 0x94, 0xf9, 0x42, + 0x96, 0xe3, 0x48, 0x1c, 0xed, 0xbe, 0xd9, 0x8f, 0x11, 0x99, 0x84, 0xcb, + 0x41, 0xad, 0x08, 0x4b, 0x9e, 0xc7, 0x1f, 0xad, 0x3c, 0x51, 0x64, 0x90, + 0xb9, 0x0b, 0x91, 0x3f, 0x2c, 0x73, 0x17, 0x21, 0xef, 0xa6, 0x2c, 0xf2, + 0x1c, 0xa6, 0x5c, 0x13, 0x12, 0x5b, 0xe5, 0x79, 0xc7, 0x95, 0xa1, 0xb4, + 0xc8, 0x90, 0x7b, 0xee, 0x59, 0x73, 0xa3, 0x5a, 0xc4, 0x18, 0x3e, 0x62, + 0x6e, 0x62, 0x5e, 0xe2, 0x5f, 0xfa, 0x86, 0x99, 0x6a, 0x93, 0xb5, 0xba, + 0xcd, 0xbd, 0x09, 0x27, 0xfa, 0xa9, 0xb7, 0xad, 0xa1, 0xa3, 0xc2, 0x67, + 0xb3, 0xff, 0xe5, 0xf4, 0xf6, 0x97, 0xd4, 0xdb, 0xa9, 0xec, 0x3e, 0x1e, + 0x57, 0x4e, 0xde, 0x8c, 0xf5, 0x22, 0xa3, 0xc8, 0xa5, 0xa0, 0x42, 0x13, + 0xb9, 0x6c, 0x28, 0x67, 0xdc, 0xac, 0xa0, 0x7e, 0xca, 0x2d, 0x99, 0x9a, + 0x95, 0x9f, 0x47, 0xa1, 0xce, 0x21, 0x17, 0x2c, 0x9b, 0xc8, 0xc8, 0x35, + 0x45, 0xfd, 0x5c, 0xb8, 0x69, 0x13, 0xb3, 0xf5, 0x2c, 0x74, 0x46, 0x7c, + 0xfa, 0xe2, 0x4b, 0x3b, 0x92, 0x32, 0xaf, 0x5d, 0xf2, 0x04, 0x2b, 0xdf, + 0xb3, 0xd1, 0x9e, 0x56, 0x45, 0x33, 0x3a, 0xb0, 0x59, 0x7b, 0x20, 0x3e, + 0x20, 0xeb, 0xcf, 0xad, 0xbd, 0x59, 0x79, 0x3a, 0x2a, 0xe3, 0x35, 0x2c, + 0xb2, 0xc6, 0x59, 0xfb, 0xce, 0x71, 0x6f, 0x73, 0x5c, 0x80, 0x63, 0x32, + 0xb6, 0xe9, 0x49, 0x7d, 0x26, 0x7e, 0xcd, 0x7d, 0x3a, 0xae, 0x74, 0xf2, + 0x99, 0xb0, 0xf6, 0xf6, 0xfd, 0xac, 0xaf, 0x1f, 0xa7, 0x6f, 0xf2, 0x37, + 0xa7, 0x8d, 0xf6, 0x5e, 0x04, 0xc7, 0xb0, 0xcb, 0xaa, 0x49, 0xc8, 0xdc, + 0xcf, 0x45, 0xcb, 0x51, 0x70, 0x24, 0x37, 0x36, 0x13, 0xc3, 0x33, 0xbd, + 0xac, 0x9c, 0x3f, 0x0a, 0x3e, 0x0a, 0x76, 0x1b, 0x4a, 0xe4, 0x66, 0x3f, + 0x4a, 0x6a, 0x38, 0xd2, 0xa7, 0xcb, 0xa7, 0x3c, 0x52, 0xef, 0x53, 0x88, + 0x19, 0xcc, 0x07, 0xd5, 0x55, 0x1e, 0x07, 0x71, 0x6e, 0x13, 0xbe, 0x20, + 0xb7, 0x8d, 0x04, 0x9c, 0x96, 0x0f, 0x4b, 0xcd, 0x2f, 0x1f, 0x19, 0x0c, + 0x02, 0x86, 0xa3, 0x8c, 0xbb, 0x5c, 0x2b, 0x63, 0x3d, 0xba, 0xd3, 0x5f, + 0x98, 0x53, 0x95, 0xcc, 0xd9, 0xb5, 0x9b, 0x35, 0x22, 0xfa, 0x9d, 0x69, + 0x8e, 0xf0, 0x5a, 0x6f, 0x3a, 0xb7, 0x4f, 0xe4, 0x10, 0xe4, 0x68, 0xcf, + 0x68, 0xbf, 0x35, 0x37, 0xdc, 0x76, 0x6f, 0x0e, 0x9b, 0x73, 0x79, 0xa9, + 0x60, 0x73, 0x31, 0x7a, 0xf7, 0x7a, 0x93, 0x29, 0x54, 0x22, 0xa9, 0xd9, + 0xe6, 0xd3, 0x4b, 0x98, 0xf5, 0x7b, 0xfb, 0x9a, 0x61, 0xe5, 0xeb, 0x9e, + 0x14, 0xfa, 0x2b, 0xc4, 0x8f, 0x9c, 0x5a, 0xbd, 0xa7, 0xcc, 0x56, 0x2e, + 0xb2, 0x5b, 0x52, 0xd9, 0x07, 0x0b, 0xb0, 0x89, 0xb9, 0x76, 0xaa, 0x95, + 0x98, 0x35, 0x68, 0xb4, 0x70, 0x7a, 0x57, 0x61, 0x38, 0xd5, 0xf9, 0x35, + 0xbf, 0x97, 0xf1, 0x10, 0xc8, 0x67, 0xde, 0x7f, 0x09, 0x59, 0x4c, 0x1b, + 0xf4, 0x1a, 0x36, 0x9b, 0x8c, 0xff, 0xcc, 0x34, 0xda, 0x64, 0xac, 0xcc, + 0xc1, 0x67, 0xff, 0x1b, 0x5f, 0xf0, 0x50, 0x4f, 0x87, 0x2b, 0xa4, 0x7e, + 0xa6, 0xd6, 0x92, 0xab, 0x0f, 0x16, 0xa3, 0x88, 0xb9, 0x6b, 0x7f, 0x95, + 0xaf, 0x43, 0xb7, 0x15, 0xe2, 0xfc, 0x57, 0xfe, 0x13, 0x52, 0x55, 0x79, + 0x70, 0xd5, 0x02, 0x0f, 0xc6, 0x6d, 0xb0, 0xd5, 0x12, 0x7b, 0x1b, 0x80, + 0xe6, 0x09, 0xee, 0xdb, 0xa0, 0x82, 0xa7, 0x92, 0x36, 0x3c, 0x9a, 0xb4, + 0x63, 0x6d, 0x12, 0xdf, 0x59, 0x04, 0x4c, 0xd7, 0xc0, 0xdf, 0x3e, 0xa3, + 0x60, 0x6b, 0x29, 0xfc, 0xad, 0x31, 0xc5, 0xdf, 0xb2, 0x96, 0x39, 0xd3, + 0x9a, 0x09, 0xe2, 0x19, 0xef, 0x75, 0x0e, 0x70, 0x5f, 0x07, 0xec, 0xa8, + 0x19, 0xc0, 0x3d, 0xf9, 0x40, 0x83, 0x13, 0xfe, 0x19, 0xc6, 0x99, 0x72, + 0x07, 0xfc, 0x53, 0x97, 0xed, 0xfe, 0xce, 0x1a, 0x3b, 0x37, 0xb7, 0x56, + 0x64, 0x71, 0xe1, 0x31, 0xda, 0xf3, 0xa2, 0x41, 0xde, 0xcf, 0xfc, 0x5d, + 0x65, 0x9e, 0xf3, 0xc9, 0x9f, 0x48, 0xfd, 0x52, 0xae, 0x49, 0xef, 0x52, + 0x41, 0xe9, 0xa0, 0x9d, 0x18, 0x76, 0xce, 0x3c, 0x5f, 0x25, 0xf8, 0x0d, + 0x3c, 0x45, 0xd9, 0xdc, 0xfc, 0x4d, 0xad, 0x25, 0x37, 0x5d, 0xa1, 0x62, + 0xfd, 0xb0, 0xdc, 0x0b, 0x6b, 0x1e, 0x27, 0x7d, 0x2a, 0x8f, 0x3e, 0x7e, + 0xc4, 0xea, 0x77, 0xd9, 0xb8, 0x46, 0x3b, 0x8a, 0x06, 0x81, 0x35, 0x71, + 0x3c, 0x51, 0x0c, 0x7f, 0x44, 0x64, 0xac, 0x5b, 0xee, 0xe0, 0xd8, 0x62, + 0xb4, 0x4c, 0x64, 0xc6, 0x3d, 0x3c, 0xf1, 0xa3, 0x8a, 0x4c, 0x2d, 0xf7, + 0xf7, 0xf7, 0x5e, 0x7b, 0x1a, 0xfc, 0xd8, 0x94, 0xa4, 0xcd, 0xd9, 0x3c, + 0x18, 0xce, 0xd6, 0x54, 0x37, 0xa4, 0xbc, 0xb3, 0x7a, 0xa3, 0xff, 0xbd, + 0x38, 0xdb, 0x37, 0xa5, 0x2f, 0xcc, 0x70, 0x1e, 0x43, 0xd9, 0x40, 0xdd, + 0x0d, 0x4f, 0x9a, 0x88, 0xea, 0x26, 0xc6, 0xf9, 0x79, 0x53, 0x87, 0x51, + 0x44, 0x5f, 0xd8, 0x18, 0xfb, 0xd2, 0x34, 0xb2, 0xfe, 0xfc, 0x4a, 0x22, + 0xa0, 0x6c, 0x21, 0x57, 0x7e, 0x95, 0xf1, 0x74, 0x8c, 0x9f, 0x51, 0xe6, + 0x70, 0x4e, 0xca, 0x6d, 0xa3, 0x5f, 0xef, 0x4c, 0x01, 0x23, 0xcc, 0xd1, + 0x0f, 0x2e, 0x17, 0xfe, 0x5e, 0xc4, 0xe7, 0xd1, 0x6b, 0x78, 0x4f, 0x9a, + 0x9f, 0x23, 0xfc, 0x4c, 0x72, 0x4f, 0xf9, 0x3c, 0x04, 0xc6, 0x1d, 0x88, + 0x8c, 0x13, 0x68, 0xc7, 0x03, 0x98, 0x62, 0x0c, 0xbc, 0x31, 0xaa, 0xa2, + 0x64, 0xac, 0x1c, 0x1f, 0x1d, 0x26, 0x3e, 0x1e, 0xca, 0x70, 0xfe, 0x4d, + 0xe3, 0xd2, 0xdf, 0x92, 0xf5, 0x49, 0x1f, 0x58, 0xfc, 0xa9, 0x00, 0x63, + 0xa4, 0x1f, 0xd2, 0x0b, 0x7e, 0x57, 0xe7, 0xdc, 0xaa, 0xf4, 0xf1, 0x5a, + 0x71, 0x34, 0xea, 0xf3, 0xf4, 0xd1, 0xe6, 0x0d, 0x87, 0xf8, 0x58, 0x03, + 0x5e, 0x8d, 0xe6, 0x7a, 0x42, 0xbe, 0x96, 0x9f, 0x4a, 0x3d, 0x83, 0x21, + 0x3b, 0x4f, 0x93, 0x6b, 0xb9, 0x58, 0x2a, 0x6b, 0x96, 0xba, 0x74, 0x8e, + 0xb7, 0xcc, 0xfe, 0xfd, 0x8c, 0x29, 0x7d, 0xca, 0xd7, 0x26, 0xbd, 0x7d, + 0x29, 0xe8, 0x56, 0xac, 0x3c, 0x5c, 0xe7, 0x4d, 0x1a, 0x90, 0xfd, 0x6d, + 0xa0, 0x0c, 0xdf, 0xa5, 0xed, 0x07, 0x44, 0xd7, 0x8c, 0xed, 0x52, 0xef, + 0x2d, 0x43, 0xff, 0x40, 0x39, 0xf6, 0x0c, 0x18, 0xe8, 0x5d, 0xde, 0x86, + 0x33, 0x51, 0x13, 0x9b, 0x42, 0x26, 0xd6, 0x84, 0xbc, 0x81, 0x57, 0x50, + 0xdf, 0x78, 0x14, 0x8f, 0x91, 0x43, 0xa8, 0xd4, 0xc9, 0x37, 0xf0, 0xce, + 0x5e, 0x07, 0x36, 0xeb, 0x7f, 0x4c, 0x1f, 0x36, 0xcd, 0xf7, 0x96, 0x2d, + 0xc0, 0x70, 0xa2, 0x5e, 0xed, 0xa6, 0x7c, 0x91, 0x36, 0xee, 0x55, 0xd0, + 0x81, 0x67, 0xf5, 0xef, 0xf0, 0x5e, 0xb7, 0xcd, 0xa1, 0xc9, 0x77, 0x1b, + 0xe3, 0xa9, 0xec, 0xa5, 0x41, 0xfb, 0xca, 0xc4, 0xb2, 0x48, 0xb6, 0xce, + 0xbe, 0xb9, 0x41, 0x30, 0xbf, 0x18, 0xa7, 0xa9, 0xb7, 0x13, 0xc9, 0x08, + 0xc3, 0x2e, 0x94, 0x67, 0x1b, 0xba, 0xf0, 0x34, 0xf9, 0xc6, 0x3b, 0x24, + 0x02, 0xf7, 0xc7, 0x15, 0x34, 0xd6, 0xe9, 0xb8, 0x98, 0xfe, 0x06, 0xde, + 0x1a, 0x0d, 0xe3, 0x4d, 0xc6, 0xf4, 0x25, 0xdf, 0xf5, 0x92, 0x83, 0x7a, + 0x70, 0x3e, 0x1d, 0xc6, 0xb9, 0xa8, 0xb7, 0xf5, 0x05, 0x65, 0x01, 0x7e, + 0x9a, 0x76, 0xe0, 0xde, 0x38, 0xf0, 0x4b, 0xce, 0xe3, 0x8f, 0x3b, 0x70, + 0x25, 0xad, 0xe2, 0x28, 0xf7, 0xc7, 0x11, 0x5a, 0x02, 0xa3, 0xcd, 0x83, + 0x23, 0x43, 0x8f, 0x62, 0x2a, 0xf5, 0x28, 0x4e, 0x25, 0xdf, 0x31, 0x5d, + 0x9a, 0xf4, 0x75, 0x5c, 0xb8, 0xc2, 0x7c, 0x6c, 0x9a, 0xda, 0x28, 0x5e, + 0xd1, 0xca, 0x38, 0xaf, 0x19, 0xa2, 0xf7, 0xb7, 0xf8, 0xdb, 0xfd, 0xf1, + 0x46, 0x1c, 0x1c, 0xa7, 0x4a, 0x13, 0x3a, 0x12, 0x31, 0x79, 0x56, 0x03, + 0x62, 0xe4, 0x85, 0xfd, 0x4c, 0xdb, 0xb7, 0x86, 0xee, 0x95, 0x5c, 0x43, + 0x69, 0xa9, 0xed, 0xcf, 0xae, 0xa3, 0x71, 0x56, 0xcf, 0x4e, 0x72, 0x28, + 0xea, 0x95, 0xe3, 0xfe, 0x36, 0x11, 0xb4, 0x62, 0xd3, 0xb1, 0x9b, 0xfb, + 0xd1, 0xc8, 0xfd, 0xf8, 0x06, 0x2e, 0xee, 0x6d, 0xc3, 0x5b, 0xc4, 0xbb, + 0xd2, 0x65, 0xbe, 0x4e, 0xa7, 0xad, 0x9e, 0x73, 0xa7, 0xcd, 0x54, 0x95, + 0xe8, 0xb4, 0x0d, 0xbf, 0x88, 0x8a, 0x4e, 0xd3, 0xc4, 0x3f, 0x9f, 0xc7, + 0x6f, 0xff, 0xcb, 0x4a, 0xda, 0xb3, 0xad, 0x3b, 0x98, 0xe9, 0x41, 0x15, + 0xaf, 0x70, 0xe1, 0xaa, 0x25, 0x9b, 0xc8, 0xfa, 0x87, 0xe4, 0xfb, 0x85, + 0xb9, 0xa6, 0x4a, 0xe4, 0x33, 0xcc, 0x3c, 0x4d, 0x0b, 0xe4, 0x29, 0x12, + 0x67, 0x03, 0x56, 0x3d, 0xbe, 0x2e, 0xde, 0x05, 0x7b, 0xa8, 0x98, 0x79, + 0x98, 0x77, 0xa6, 0x03, 0x6f, 0xe1, 0xda, 0xa4, 0x0b, 0x8b, 0xe3, 0x1a, + 0x5e, 0x9e, 0x7c, 0x8d, 0xcf, 0xfa, 0x47, 0x5c, 0xe6, 0x77, 0x5f, 0x3c, + 0xe3, 0x6f, 0xdd, 0x0d, 0x6d, 0x78, 0x30, 0x2d, 0xeb, 0xcb, 0xe3, 0x83, + 0x74, 0x44, 0xd2, 0xb2, 0xce, 0x18, 0x7d, 0x43, 0xd6, 0x59, 0xfe, 0xef, + 0xac, 0xf3, 0xbf, 0x72, 0xbe, 0x05, 0xf4, 0xa5, 0x5c, 0xec, 0x28, 0xc1, + 0x91, 0xa4, 0x8a, 0xd3, 0x7a, 0x31, 0x2e, 0xa9, 0x52, 0x5f, 0x76, 0x31, + 0x86, 0x38, 0xd0, 0xcc, 0x9c, 0x71, 0x84, 0x9f, 0x8d, 0xcc, 0x7f, 0xce, + 0xea, 0x0e, 0x9c, 0xd2, 0x17, 0x10, 0xeb, 0xef, 0xb4, 0x61, 0xb9, 0x46, + 0xb2, 0x5f, 0x56, 0x8e, 0x73, 0x52, 0xff, 0xb3, 0xae, 0xbb, 0xa4, 0x2f, + 0x89, 0x31, 0xea, 0x2b, 0x2f, 0xf6, 0x1b, 0xf3, 0xaa, 0x85, 0x35, 0x77, + 0xca, 0x77, 0xe7, 0x3c, 0x12, 0x82, 0x7f, 0x69, 0x6e, 0xad, 0xca, 0xc6, + 0x2e, 0xe5, 0x4f, 0x2b, 0x33, 0x78, 0x21, 0x71, 0xec, 0xef, 0x72, 0xd8, + 0x21, 0xf9, 0x64, 0x1b, 0xe3, 0x10, 0xe3, 0xf2, 0xf1, 0x6d, 0x92, 0xe7, + 0xd9, 0xc2, 0xef, 0xb5, 0xad, 0xd2, 0xf2, 0x60, 0xb7, 0xf8, 0xde, 0x7b, + 0x2f, 0x65, 0x38, 0xfa, 0xfb, 0x2f, 0x69, 0xd6, 0xdf, 0xeb, 0x2f, 0x2d, + 0xb6, 0xfe, 0x7e, 0xf2, 0x92, 0x2f, 0x75, 0x2b, 0x5e, 0x65, 0x38, 0xb0, + 0x75, 0x6e, 0x05, 0x7d, 0xba, 0xa1, 0x3c, 0xdc, 0x20, 0x5c, 0x72, 0x36, + 0x8f, 0x08, 0x28, 0x67, 0xa3, 0x92, 0xa7, 0x15, 0x1a, 0xcc, 0xe3, 0x95, + 0x46, 0xbf, 0x46, 0x3c, 0xee, 0x42, 0xc9, 0x32, 0x0d, 0x17, 0xa8, 0x73, + 0xc2, 0x28, 0xed, 0xf8, 0xff, 0x20, 0xba, 0x17, 0xed, 0x85, 0x16, 0xf6, + 0x98, 0x66, 0x7f, 0x48, 0x6a, 0x0c, 0x32, 0xaf, 0x03, 0x1f, 0x70, 0x2f, + 0x7f, 0x35, 0x5a, 0x84, 0xf7, 0x53, 0x1a, 0x2e, 0xa5, 0xdb, 0xb0, 0x7b, + 0x32, 0xc3, 0x33, 0x4e, 0x59, 0xfc, 0x5b, 0x63, 0x8e, 0xe9, 0xc0, 0xc1, + 0xa8, 0x86, 0x58, 0xe2, 0x75, 0xb3, 0x40, 0xf3, 0x4d, 0xf9, 0xed, 0x0e, + 0x1c, 0x48, 0x4f, 0x63, 0x72, 0xe0, 0x63, 0xd3, 0xae, 0x75, 0xe1, 0xa3, + 0xd0, 0x34, 0x26, 0x0e, 0x49, 0x5f, 0x4f, 0x47, 0xff, 0x90, 0x86, 0xde, + 0x84, 0x0d, 0x7b, 0x96, 0xb7, 0xa0, 0x7f, 0xb2, 0x19, 0xc6, 0x98, 0x07, + 0x7b, 0xd2, 0x69, 0x4c, 0x8d, 0x4e, 0xe3, 0x4c, 0x52, 0x6b, 0x2c, 0x50, + 0xa6, 0x71, 0x9a, 0xcf, 0xd9, 0x91, 0x78, 0x1b, 0x06, 0xe7, 0xd8, 0x99, + 0x94, 0x9a, 0xa4, 0x3c, 0x67, 0x1a, 0xdd, 0xa9, 0xbb, 0xd5, 0x44, 0x28, + 0x4f, 0xa2, 0xa7, 0x3d, 0x53, 0xab, 0x27, 0xbe, 0xa6, 0x35, 0xa5, 0x8f, + 0xfb, 0x74, 0x34, 0x9d, 0xab, 0xdb, 0xdf, 0x59, 0x0b, 0xd1, 0xd1, 0x37, + 0xd4, 0xc2, 0x31, 0x1a, 0xba, 0x13, 0xd2, 0x1b, 0xf5, 0xf1, 0x99, 0x26, + 0x7e, 0xa9, 0x7b, 0xdd, 0x8b, 0xf9, 0xf7, 0xb0, 0xde, 0x89, 0x2d, 0x9c, + 0x6b, 0x8a, 0x79, 0x90, 0xa6, 0x78, 0x1b, 0x0d, 0xd8, 0xf1, 0x9e, 0x4e, + 0xce, 0x53, 0x69, 0xc7, 0xab, 0x7a, 0x09, 0x22, 0x65, 0x76, 0xd4, 0x87, + 0x18, 0xa7, 0xb3, 0x71, 0xfb, 0xc3, 0xa4, 0x82, 0x47, 0x89, 0xa9, 0x27, + 0x42, 0xf5, 0xed, 0xab, 0x85, 0xd1, 0x1d, 0x52, 0x70, 0x4d, 0xbb, 0x61, + 0x1a, 0x8c, 0x5d, 0x2e, 0x7f, 0x6e, 0x8f, 0x7e, 0x6d, 0x66, 0xfa, 0x9b, + 0x5f, 0x98, 0xb9, 0x71, 0x33, 0x94, 0xf1, 0x29, 0x8e, 0x5b, 0xbc, 0xac, + 0xbe, 0x53, 0xc6, 0xb9, 0x89, 0xe9, 0x32, 0x4e, 0xea, 0xd1, 0xb7, 0xc6, + 0xe9, 0xd8, 0x39, 0x14, 0xb1, 0xe4, 0xdd, 0x95, 0xc0, 0x52, 0x07, 0xc4, + 0x9f, 0xea, 0xd5, 0x2b, 0x40, 0xd7, 0xb4, 0x3e, 0x87, 0x5c, 0xc7, 0x1f, + 0xd8, 0x08, 0xd1, 0x95, 0xe4, 0x92, 0x6f, 0x63, 0x4f, 0x74, 0x14, 0xcc, + 0x27, 0x89, 0x73, 0xfe, 0xf5, 0x23, 0x48, 0xe1, 0xf9, 0x74, 0x0a, 0x2f, + 0x50, 0x47, 0x86, 0x75, 0x6e, 0x29, 0x8d, 0x3f, 0x8f, 0xbe, 0x8d, 0x98, + 0xb5, 0x67, 0x47, 0xb1, 0x21, 0xfa, 0xf7, 0x55, 0xc2, 0x11, 0x77, 0x24, + 0x56, 0x72, 0x7e, 0xd1, 0xab, 0xb7, 0xd5, 0xc0, 0x97, 0x9c, 0x7f, 0x25, + 0x7a, 0x46, 0x4c, 0xf3, 0x7b, 0x8c, 0x5f, 0x3f, 0x23, 0xbf, 0xba, 0x96, + 0x3d, 0x03, 0x55, 0x40, 0x7d, 0x6b, 0x56, 0x1c, 0x6b, 0xe3, 0x3e, 0x57, + 0x0b, 0xaf, 0x47, 0xc9, 0xb8, 0xa6, 0x2c, 0x8e, 0xc9, 0xbe, 0x93, 0x37, + 0x8e, 0x7b, 0xf0, 0x14, 0x39, 0x4a, 0xfe, 0xe1, 0x1f, 0x28, 0x12, 0xcb, + 0x6a, 0x0e, 0x91, 0xef, 0x1f, 0xf2, 0x28, 0x4b, 0xf6, 0xb9, 0xf0, 0x68, + 0x4c, 0xea, 0x37, 0xcd, 0xe8, 0xd9, 0xaf, 0xf1, 0x1e, 0xaf, 0x7e, 0x81, + 0x39, 0xe9, 0x69, 0xf8, 0x3c, 0x23, 0xe4, 0x55, 0x6e, 0x62, 0xb1, 0xe3, + 0x70, 0x29, 0x8a, 0x0e, 0xab, 0xb0, 0x1d, 0x2e, 0x47, 0xf1, 0x61, 0x37, + 0x6a, 0x18, 0xdb, 0xdc, 0xe3, 0x17, 0x31, 0xb9, 0x0f, 0x6a, 0x51, 0xf8, + 0x73, 0x33, 0x5f, 0x93, 0x3e, 0x5b, 0x00, 0xa5, 0xe3, 0xdb, 0x91, 0x8e, + 0x05, 0x51, 0x3c, 0x4e, 0x2a, 0x35, 0x7e, 0x5c, 0xa9, 0xe7, 0x33, 0x1f, + 0x8a, 0x69, 0x9c, 0x2b, 0xc3, 0x75, 0x56, 0x73, 0x5c, 0x5f, 0xc2, 0xbb, + 0x5e, 0x7a, 0x65, 0xd7, 0xf4, 0x37, 0x50, 0x30, 0x70, 0xeb, 0x2c, 0x97, + 0x16, 0xc2, 0x3c, 0x72, 0x91, 0xd6, 0x67, 0x91, 0x39, 0xd7, 0xf5, 0x70, + 0x76, 0x4d, 0x41, 0x59, 0x93, 0xb3, 0x8d, 0xb6, 0x30, 0x57, 0xea, 0x5f, + 0xb8, 0x4c, 0xfb, 0xb9, 0x9f, 0xf2, 0xde, 0x60, 0x6e, 0xd8, 0x19, 0x13, + 0xbb, 0xff, 0x81, 0x42, 0xbf, 0xc1, 0x4c, 0xaa, 0x08, 0x1f, 0xa7, 0x3c, + 0x8a, 0x8f, 0xeb, 0xf9, 0x0b, 0x5e, 0xff, 0x73, 0xae, 0x67, 0xc7, 0x7e, + 0x6f, 0xeb, 0x49, 0xc5, 0xdb, 0xbe, 0x4e, 0xf1, 0xa9, 0x3b, 0x94, 0x62, + 0x5c, 0x1e, 0x2d, 0xc5, 0x15, 0xc6, 0xe2, 0x1b, 0xa3, 0xe5, 0xb8, 0x3a, + 0x5a, 0x49, 0x5f, 0xd1, 0x38, 0x87, 0x69, 0x96, 0x68, 0x6e, 0xcc, 0xa4, + 0x5f, 0xc0, 0x9c, 0xd8, 0x02, 0x7c, 0x9c, 0xde, 0x82, 0xd2, 0x98, 0x70, + 0x76, 0x0f, 0x3e, 0xe2, 0xf5, 0x0f, 0xd3, 0x13, 0x28, 0xdc, 0xf7, 0x39, + 0xef, 0x31, 0xcd, 0x87, 0xb8, 0xc6, 0xab, 0xe9, 0x0e, 0x14, 0xef, 0xdb, + 0x06, 0xc7, 0x3e, 0xb3, 0xab, 0x27, 0x84, 0x9f, 0xda, 0xb9, 0x96, 0x6e, + 0xdd, 0x3b, 0xb5, 0xd8, 0x1e, 0xe4, 0x1c, 0x3a, 0xe7, 0x3c, 0xae, 0x2c, + 0x19, 0xdf, 0x86, 0xd2, 0x7d, 0x1e, 0x6c, 0xa5, 0x2e, 0x27, 0xa0, 0x05, + 0xd6, 0x29, 0xdb, 0x90, 0x77, 0x38, 0xa3, 0x83, 0x4d, 0xe3, 0x19, 0x1f, + 0x79, 0xa8, 0x41, 0xea, 0x43, 0xc7, 0x95, 0x11, 0xcb, 0x47, 0xdc, 0x72, + 0xfe, 0x04, 0xd3, 0xe9, 0x22, 0x9c, 0x4d, 0x89, 0x8e, 0xe4, 0xec, 0xda, + 0x04, 0xf2, 0xf7, 0x11, 0x23, 0x47, 0x75, 0x8b, 0x43, 0x88, 0x6f, 0x8c, + 0xa6, 0xef, 0xe6, 0x5f, 0x41, 0xec, 0x49, 0xd4, 0xd0, 0xb7, 0x16, 0x60, + 0xcd, 0x3e, 0xe9, 0x91, 0x4e, 0xdd, 0xef, 0xa2, 0x35, 0x8d, 0xa5, 0xef, + 0xe6, 0x5b, 0x0d, 0xb4, 0x53, 0x6f, 0x8b, 0x01, 0x39, 0xab, 0x61, 0x62, + 0x5a, 0x3f, 0xae, 0xd8, 0x62, 0x92, 0x6f, 0xb5, 0xd1, 0xe7, 0x5b, 0xd1, + 0x33, 0x84, 0xf6, 0x83, 0x0d, 0xd2, 0xb7, 0x75, 0x62, 0x84, 0xf9, 0xd3, + 0x65, 0xe6, 0x1c, 0xd4, 0xb9, 0x9a, 0x17, 0xce, 0xc3, 0xf0, 0xa8, 0x0b, + 0x3f, 0x1a, 0xf5, 0xa0, 0x31, 0xf6, 0x39, 0x31, 0xa3, 0x10, 0xc7, 0xa9, + 0xef, 0x49, 0xf2, 0x9f, 0x8f, 0xa2, 0x2a, 0x26, 0x18, 0x6b, 0x3f, 0x8c, + 0x56, 0x62, 0x9c, 0xb9, 0xd6, 0x75, 0xe2, 0x4c, 0x9a, 0x7b, 0xf3, 0x01, + 0xf3, 0x8e, 0xef, 0xa5, 0x83, 0xf8, 0x55, 0x34, 0x88, 0x57, 0xa9, 0xc7, + 0xba, 0x98, 0x9b, 0x32, 0x1d, 0x53, 0x70, 0xe8, 0xb8, 0x92, 0x47, 0xbb, + 0xf0, 0xc7, 0x34, 0xcf, 0x48, 0xd6, 0x2e, 0xb4, 0xf1, 0x56, 0xfa, 0x91, + 0xf4, 0xff, 0x25, 0x3e, 0x38, 0xf4, 0x11, 0x90, 0xd3, 0x05, 0x73, 0x75, + 0x42, 0xaf, 0x7b, 0x0a, 0x15, 0xf4, 0xa5, 0x2f, 0x4d, 0x55, 0x93, 0x9a, + 0x58, 0x32, 0x74, 0x2d, 0xaa, 0xa9, 0x57, 0xad, 0x35, 0x18, 0x8a, 0x73, + 0x39, 0x39, 0x46, 0xe5, 0x0e, 0xae, 0x5f, 0x23, 0x66, 0x38, 0xe8, 0x32, + 0x26, 0xef, 0xbb, 0x8e, 0xfb, 0x0e, 0xfd, 0x69, 0x75, 0x86, 0x03, 0xd1, + 0x9f, 0x6d, 0x77, 0xd6, 0xb1, 0xa4, 0x96, 0xbd, 0x37, 0xf4, 0x46, 0x34, + 0x56, 0x2d, 0x3d, 0xa5, 0x93, 0x08, 0x52, 0x2f, 0x77, 0xcb, 0x15, 0x4c, + 0xbc, 0x45, 0x4c, 0xb9, 0x9a, 0x14, 0xbe, 0x24, 0x3c, 0xa9, 0x8b, 0x31, + 0xa9, 0x84, 0x3c, 0x41, 0xc3, 0x4e, 0x72, 0x79, 0x5f, 0x7c, 0x8a, 0xb9, + 0xca, 0x57, 0xc9, 0xd5, 0x4a, 0x39, 0x8d, 0xc1, 0xe7, 0xb5, 0x62, 0x0f, + 0x7d, 0xb3, 0x40, 0x5b, 0x8c, 0x35, 0xe4, 0x41, 0x0e, 0x8d, 0xa1, 0xe4, + 0x09, 0x89, 0x27, 0x40, 0x6d, 0x5c, 0x95, 0x7e, 0xcf, 0xfa, 0x9f, 0xe1, + 0x7e, 0xb4, 0x57, 0xb9, 0x20, 0x3d, 0x9a, 0x37, 0xd1, 0x84, 0xd4, 0xd7, + 0xad, 0xde, 0x30, 0xdc, 0x61, 0xcd, 0xb8, 0x88, 0x45, 0x16, 0x23, 0x2f, + 0x0c, 0x8b, 0x3c, 0x95, 0xd4, 0xbf, 0x8a, 0x77, 0xa9, 0xd7, 0x2b, 0x51, + 0xdf, 0xcc, 0x83, 0xa8, 0x3f, 0x73, 0xc5, 0x2e, 0xfd, 0x2b, 0xb9, 0x3f, + 0x08, 0x8d, 0xf3, 0x7d, 0x1a, 0x0d, 0x61, 0x40, 0x95, 0xef, 0xc2, 0x1b, + 0x5b, 0xd1, 0x3d, 0x22, 0x32, 0x98, 0x66, 0x39, 0xf1, 0xf1, 0x09, 0xeb, + 0xf9, 0xf2, 0xec, 0x3b, 0xf3, 0x0e, 0xaf, 0x6a, 0x20, 0x97, 0x7b, 0x4c, + 0xe3, 0x68, 0xd2, 0x03, 0xc7, 0xf2, 0xff, 0x41, 0x3d, 0x4c, 0x63, 0x34, + 0xa5, 0x91, 0x53, 0x16, 0xc1, 0x53, 0x15, 0x44, 0x3f, 0xe3, 0x78, 0x8c, + 0xf7, 0xa7, 0x63, 0x45, 0x30, 0xaa, 0x32, 0xcf, 0xfc, 0x6a, 0xfc, 0xba, + 0x39, 0xf5, 0xb8, 0xcc, 0x29, 0xdf, 0x7f, 0xce, 0x31, 0x73, 0xe5, 0xd8, + 0x23, 0x36, 0xc7, 0xae, 0x9a, 0x53, 0xad, 0xb3, 0x7f, 0x2f, 0xb3, 0xce, + 0x10, 0x45, 0x6c, 0x55, 0x52, 0x6f, 0xb1, 0xf4, 0xd2, 0x4d, 0xbd, 0xcc, + 0xd1, 0xde, 0x36, 0x1f, 0xb3, 0xe4, 0x9a, 0xaa, 0x16, 0x9e, 0x5f, 0x1b, + 0xff, 0xbc, 0x5a, 0xea, 0xa5, 0x12, 0xc3, 0x5c, 0x61, 0xad, 0xf1, 0x0c, + 0xfe, 0xd1, 0xbc, 0x74, 0xdb, 0x3c, 0x15, 0xbc, 0x26, 0xf1, 0xe8, 0x52, + 0xb6, 0x1f, 0xed, 0xce, 0xe6, 0x02, 0xd3, 0x38, 0x99, 0x94, 0x58, 0xe0, + 0xc1, 0x06, 0xa9, 0x43, 0xa9, 0xde, 0x3e, 0x03, 0x53, 0xe4, 0x7e, 0xef, + 0x50, 0xf7, 0x4c, 0x80, 0xfc, 0x53, 0xe4, 0x7f, 0xb3, 0xe3, 0x55, 0x04, + 0xa9, 0x4a, 0xe9, 0x29, 0x08, 0x9e, 0x4e, 0x63, 0x57, 0xf2, 0x75, 0xe2, + 0xda, 0xc7, 0xe4, 0x43, 0x5d, 0xe4, 0xda, 0xd3, 0xe8, 0x49, 0x35, 0xe3, + 0xe5, 0xfd, 0x2d, 0xc4, 0x18, 0xc1, 0x4a, 0xdf, 0x99, 0xcb, 0xf6, 0x66, + 0x1c, 0x1c, 0x4b, 0x23, 0x75, 0x58, 0x62, 0xa4, 0x9c, 0xc7, 0x92, 0xf8, + 0xa8, 0x21, 0x9a, 0x38, 0x0d, 0x83, 0x7f, 0xf7, 0x24, 0xb6, 0x21, 0x72, + 0xf8, 0x6d, 0x72, 0xfc, 0x69, 0xac, 0x1e, 0xd0, 0xd6, 0x1f, 0xc1, 0x34, + 0xd6, 0x32, 0x7e, 0x26, 0x13, 0x2d, 0x9c, 0xbf, 0x19, 0xbd, 0xfb, 0xbd, + 0x01, 0x87, 0x6d, 0x0e, 0x63, 0x94, 0x07, 0x3b, 0x27, 0x23, 0x30, 0x46, + 0xe4, 0x8c, 0x81, 0x0b, 0xc1, 0xb8, 0x47, 0xf9, 0x90, 0x3c, 0xb9, 0x3e, + 0xee, 0x65, 0x7e, 0xe6, 0x35, 0xd6, 0x2a, 0x3e, 0x4f, 0x9e, 0x4d, 0xfa, + 0x59, 0x73, 0x70, 0x46, 0x57, 0x50, 0x70, 0xbf, 0x82, 0x10, 0x63, 0x97, + 0xa7, 0x9a, 0x31, 0x65, 0x44, 0x47, 0xef, 0x10, 0xd7, 0x7b, 0x73, 0xdf, + 0x64, 0xbf, 0x1e, 0xe1, 0x7c, 0xb2, 0x77, 0x2d, 0xe8, 0x9d, 0xf4, 0x75, + 0x9c, 0x81, 0xdb, 0xe2, 0x5c, 0xbd, 0x43, 0xb9, 0x7b, 0x50, 0xfc, 0x71, + 0x83, 0x37, 0x30, 0x47, 0x91, 0x7b, 0x77, 0x10, 0xbf, 0x66, 0xdf, 0x6f, + 0x28, 0xc9, 0xe5, 0xe4, 0xa5, 0x36, 0xf1, 0x8b, 0x6e, 0xcb, 0x5f, 0x44, + 0x17, 0xbd, 0xc9, 0x08, 0x6d, 0xfa, 0xc7, 0x66, 0xaa, 0xb5, 0x95, 0x72, + 0x36, 0x48, 0xaf, 0xc7, 0xe2, 0x26, 0xe7, 0xa5, 0xee, 0xe6, 0x94, 0xd8, + 0xdd, 0xdd, 0xee, 0xa2, 0x3d, 0xe5, 0x13, 0x9f, 0x0a, 0x26, 0x5c, 0x70, + 0x1d, 0x29, 0x42, 0xfe, 0xb0, 0xf0, 0x34, 0xa8, 0xa5, 0xcc, 0xfb, 0xe5, + 0x3c, 0xc3, 0x30, 0x6d, 0xd4, 0x36, 0x41, 0x1f, 0x8b, 0xba, 0xb1, 0x68, + 0xc2, 0x8d, 0x1f, 0x11, 0x03, 0x6a, 0x26, 0x34, 0x1c, 0x27, 0x06, 0xb8, + 0x27, 0x02, 0x98, 0x24, 0x06, 0xcc, 0xc9, 0xd6, 0x3e, 0xde, 0x4c, 0xcf, + 0x9f, 0x8b, 0x42, 0x79, 0x96, 0xe8, 0x31, 0xb7, 0xaf, 0xb2, 0xa7, 0x2d, + 0xc4, 0x3d, 0xd9, 0xdf, 0x00, 0x76, 0x0f, 0xa5, 0xb1, 0x6a, 0x9f, 0x89, + 0x9f, 0xeb, 0xf5, 0xee, 0x02, 0x45, 0xf2, 0x04, 0x13, 0x69, 0x5d, 0xce, + 0x4d, 0x7a, 0xd7, 0xcb, 0xb9, 0xe2, 0xf6, 0x4a, 0x13, 0x79, 0x21, 0xaf, + 0x4e, 0xb4, 0x5f, 0x5f, 0xa0, 0x48, 0xdc, 0xaa, 0xf7, 0x6c, 0xc1, 0x7c, + 0x64, 0x7a, 0x65, 0x0f, 0x62, 0x8b, 0xaa, 0xd0, 0x1f, 0x5b, 0xb0, 0xa7, + 0xcc, 0x70, 0x5d, 0x6b, 0x30, 0xcd, 0x4d, 0xa1, 0xdf, 0x56, 0x59, 0xb5, + 0x65, 0xdb, 0x1f, 0x71, 0xed, 0x6d, 0x5c, 0xb7, 0xac, 0xbd, 0x03, 0xb1, + 0xbd, 0x0a, 0xd2, 0xfe, 0x0e, 0x44, 0x47, 0x3b, 0xd0, 0xbf, 0x57, 0x30, + 0xa1, 0x8f, 0x98, 0x60, 0x76, 0x3d, 0x1b, 0x7a, 0x0c, 0x57, 0x2d, 0x16, + 0x20, 0x63, 0xbc, 0x01, 0x8f, 0x6d, 0xf6, 0x3e, 0xe4, 0x53, 0xfe, 0x8c, + 0xef, 0x34, 0x0f, 0x08, 0xa7, 0xf6, 0xf7, 0xf5, 0x72, 0xff, 0x1f, 0x3f, + 0x24, 0xf1, 0xc6, 0x34, 0xfb, 0xc8, 0x59, 0x51, 0x26, 0x6b, 0xd0, 0xa4, + 0x3e, 0xfe, 0x71, 0x8d, 0xe6, 0x9b, 0xe9, 0x67, 0x6c, 0xbf, 0xb8, 0xaf, + 0x7e, 0xcb, 0x16, 0xe1, 0x31, 0xcb, 0x84, 0xdb, 0xa5, 0x71, 0xe1, 0xf0, + 0x7d, 0x48, 0x3d, 0xce, 0xf5, 0x70, 0xaf, 0x9c, 0xf1, 0x2f, 0x4c, 0xe1, + 0x72, 0x76, 0x4d, 0x53, 0x8f, 0x12, 0xfb, 0x6c, 0x13, 0x7e, 0xf4, 0x94, + 0xc1, 0xb8, 0xd6, 0x20, 0xcf, 0xbf, 0x29, 0x3f, 0xd7, 0xdb, 0x8c, 0xfe, + 0xfd, 0xc2, 0x35, 0x84, 0x97, 0xf9, 0x8c, 0x0f, 0xd0, 0x82, 0xe4, 0x64, + 0xe6, 0x59, 0xd1, 0xc4, 0x9d, 0xb6, 0x22, 0xfb, 0x7e, 0x1a, 0xbb, 0x69, + 0x97, 0x2e, 0xce, 0xcf, 0xf8, 0xc2, 0xf9, 0xb4, 0x40, 0x81, 0x3c, 0x6f, + 0xe2, 0xc7, 0xe6, 0x9e, 0x2a, 0xd1, 0x8d, 0xcc, 0x7f, 0xba, 0x4a, 0x30, + 0x63, 0x53, 0xe8, 0x0f, 0xad, 0xf5, 0x75, 0xfe, 0xf5, 0xb6, 0x64, 0xf4, + 0x21, 0xf7, 0x9e, 0xfe, 0x3d, 0xf2, 0x5c, 0xe0, 0x7d, 0x22, 0x53, 0x07, + 0x76, 0xef, 0x85, 0x51, 0xa8, 0x49, 0xaf, 0xa0, 0x03, 0x7d, 0xd4, 0xef, + 0xce, 0x64, 0x07, 0x0e, 0xd2, 0x67, 0x87, 0xf5, 0x13, 0x35, 0x36, 0xd4, + 0xcd, 0xd8, 0x31, 0xf5, 0x93, 0x45, 0xc4, 0xd3, 0x25, 0xcb, 0xfc, 0xf4, + 0xaf, 0x0e, 0xc4, 0x53, 0x63, 0x73, 0xad, 0x3e, 0x9f, 0x4d, 0xe2, 0x9f, + 0xe8, 0xa2, 0x13, 0x85, 0x03, 0xa7, 0xe1, 0x1c, 0xe8, 0x44, 0x81, 0xbf, + 0x09, 0x0f, 0x87, 0x2e, 0x99, 0x57, 0x35, 0x87, 0xfb, 0x24, 0xf5, 0x73, + 0x22, 0x58, 0xc3, 0x7c, 0x92, 0x39, 0xcc, 0xc8, 0x3c, 0xfa, 0x7e, 0x03, + 0xf9, 0xae, 0xf4, 0xf4, 0x6d, 0x58, 0xbb, 0x5c, 0x72, 0x75, 0x85, 0xb6, + 0x5d, 0xcd, 0x5c, 0x53, 0x53, 0x9f, 0xb7, 0xce, 0x5f, 0x90, 0x87, 0x55, + 0x7a, 0xf0, 0x8c, 0x75, 0xee, 0x40, 0xae, 0x6f, 0x67, 0x8e, 0xb0, 0x1d, + 0x35, 0x31, 0xc3, 0x14, 0x7d, 0x9f, 0x44, 0xe4, 0x25, 0x1b, 0xe5, 0x68, + 0x5c, 0xe6, 0xdf, 0x32, 0xa3, 0x88, 0x4d, 0xfb, 0xdb, 0x27, 0x14, 0xdd, + 0xf5, 0xc8, 0xb8, 0x82, 0xc0, 0x00, 0xe7, 0x0a, 0xfd, 0xf5, 0xdc, 0x4c, + 0x7d, 0x2c, 0xc7, 0xf9, 0xb6, 0x93, 0x27, 0x6c, 0x47, 0x09, 0xc7, 0xbb, + 0x35, 0xc1, 0x86, 0xc8, 0x4a, 0xe9, 0xa5, 0xa4, 0x43, 0xfe, 0xd6, 0x62, + 0x45, 0xf8, 0x90, 0xbf, 0x71, 0xad, 0x22, 0xdc, 0x45, 0xc6, 0xe9, 0xae, + 0xba, 0xf1, 0x8b, 0xd9, 0x9e, 0x57, 0x03, 0xf1, 0xc1, 0x63, 0x9d, 0x85, + 0x7c, 0xed, 0xe6, 0x79, 0x89, 0x4c, 0xbd, 0xda, 0x19, 0x97, 0xbc, 0xe2, + 0x58, 0x68, 0x55, 0xb4, 0x91, 0x58, 0x67, 0x36, 0x8d, 0xd1, 0xee, 0x2f, + 0xa3, 0x12, 0xff, 0x33, 0x2a, 0xb8, 0xe6, 0xc1, 0xff, 0x8a, 0xe6, 0x4b, + 0xbe, 0x9c, 0x92, 0x7a, 0xe4, 0xb9, 0xa4, 0x61, 0x52, 0xaf, 0x2d, 0x6b, + 0x69, 0x4b, 0x81, 0x50, 0x31, 0x50, 0xd5, 0xfd, 0x8c, 0xd3, 0xca, 0xdf, + 0x4b, 0x50, 0xc6, 0x18, 0x30, 0x30, 0xf2, 0xfb, 0x6a, 0xaf, 0xc4, 0xe1, + 0x42, 0xa9, 0x81, 0xda, 0xb1, 0x33, 0xf4, 0x2f, 0x66, 0x2a, 0x7b, 0x76, + 0xf5, 0xc2, 0x5e, 0xb1, 0xd3, 0x00, 0xf2, 0xe3, 0x17, 0x69, 0x93, 0x2a, + 0xce, 0x47, 0x7d, 0xfa, 0x3a, 0xdb, 0x37, 0x68, 0xff, 0x8b, 0x6e, 0xc3, + 0xee, 0x45, 0xda, 0xa3, 0x78, 0xda, 0xc2, 0xee, 0x30, 0x7a, 0x18, 0x1b, + 0xc8, 0xe3, 0x0e, 0x3c, 0x63, 0x53, 0x51, 0x10, 0xf3, 0xa9, 0x3e, 0xe6, + 0xdb, 0x3d, 0x7c, 0x86, 0x70, 0xcc, 0x0a, 0x72, 0xc0, 0x67, 0xa3, 0xf5, + 0x9e, 0x5f, 0x63, 0x03, 0xfd, 0x51, 0x9e, 0x21, 0x6b, 0xd2, 0x50, 0xcc, + 0xbc, 0xf2, 0x14, 0xd7, 0xb1, 0xb3, 0x2c, 0xf3, 0xdc, 0xd2, 0xec, 0xdc, + 0xf1, 0x11, 0xe1, 0x5f, 0x2b, 0xb0, 0xce, 0x9a, 0x3b, 0x68, 0xf9, 0xe6, + 0x01, 0x39, 0x5b, 0x5e, 0xa7, 0x21, 0x91, 0x6e, 0xc6, 0xb6, 0xf2, 0x05, + 0x38, 0x98, 0xd8, 0x8e, 0xa5, 0xe4, 0xc1, 0x4f, 0x96, 0x1b, 0x8c, 0x8d, + 0xc4, 0xa1, 0xb8, 0xa6, 0xde, 0xa7, 0x3c, 0x90, 0xed, 0x3f, 0x54, 0xc2, + 0x11, 0x97, 0x98, 0x97, 0x87, 0x41, 0x75, 0x3e, 0x8a, 0xac, 0x33, 0x7f, + 0x99, 0xb9, 0xfb, 0x47, 0xbc, 0xd9, 0x38, 0x48, 0xd4, 0x88, 0x5b, 0xe7, + 0x2d, 0x02, 0x2f, 0x90, 0x4b, 0xa4, 0x18, 0x01, 0xf3, 0xc2, 0x5a, 0x6a, + 0x33, 0x0a, 0x60, 0x54, 0x0b, 0x26, 0xca, 0x98, 0x79, 0x77, 0xc8, 0x54, + 0x9e, 0x95, 0x29, 0x77, 0x3d, 0xc5, 0x6b, 0x62, 0x5b, 0xc2, 0x2f, 0xe4, + 0xf7, 0x42, 0xb4, 0xd2, 0x9e, 0x2a, 0x29, 0x73, 0xc2, 0x3a, 0xb7, 0xe9, + 0xd5, 0x0d, 0x5b, 0x03, 0x3e, 0xdb, 0x97, 0xb1, 0xc1, 0xf5, 0xb5, 0xdc, + 0xff, 0xd2, 0x06, 0xcc, 0x1c, 0x96, 0x78, 0xf6, 0xfb, 0xcf, 0x52, 0x18, + 0x37, 0xcf, 0x52, 0x88, 0x5e, 0xbd, 0x67, 0xde, 0x45, 0xfd, 0xd4, 0x53, + 0xb6, 0xa3, 0x26, 0x2a, 0x44, 0xc7, 0x9b, 0xdd, 0x92, 0x87, 0xda, 0xc8, + 0x23, 0x8c, 0x74, 0xd2, 0x2d, 0xb1, 0xd2, 0x11, 0x07, 0x16, 0xc5, 0x0d, + 0xe4, 0x87, 0xb5, 0x03, 0xd7, 0xec, 0x37, 0xcc, 0xf6, 0xea, 0x79, 0xcc, + 0x03, 0x6f, 0xad, 0xb9, 0x8f, 0xb2, 0xdb, 0xb5, 0x1f, 0x9b, 0x0f, 0x56, + 0x8a, 0x8c, 0x3f, 0x72, 0x67, 0xea, 0xcc, 0x0b, 0xa9, 0x97, 0x9c, 0x4e, + 0x4c, 0xda, 0xcf, 0xdf, 0x98, 0x5f, 0xbb, 0xed, 0xba, 0xf0, 0x19, 0xb1, + 0xd3, 0xd9, 0x67, 0xdb, 0xc4, 0x66, 0x3d, 0xb4, 0xd3, 0x69, 0x8c, 0x25, + 0x1b, 0x30, 0x90, 0x10, 0x1d, 0x47, 0x70, 0x99, 0xfc, 0xb0, 0x76, 0x70, + 0x1a, 0xc3, 0xe4, 0x87, 0xbe, 0xb8, 0xf7, 0x00, 0x35, 0x89, 0x6d, 0x6a, + 0x93, 0xc5, 0x93, 0x5c, 0x5a, 0x4e, 0x86, 0xaf, 0x5a, 0x7a, 0x97, 0x18, + 0xb3, 0x87, 0xeb, 0xbd, 0x97, 0x3c, 0xa9, 0x39, 0x96, 0x0f, 0xad, 0xac, + 0x14, 0xc5, 0x9a, 0xf4, 0x2b, 0x32, 0xf7, 0x45, 0x29, 0x4b, 0x91, 0xe6, + 0xc3, 0x5a, 0xeb, 0x5e, 0x8f, 0x75, 0xae, 0xc1, 0x51, 0x2e, 0x31, 0x58, + 0xe2, 0x2e, 0xf9, 0xf7, 0x72, 0x89, 0xbb, 0x61, 0xca, 0xb6, 0x98, 0x7b, + 0xb6, 0x14, 0xee, 0x07, 0x3c, 0xa8, 0x79, 0x80, 0x31, 0x72, 0x89, 0x82, + 0xf2, 0x25, 0x7e, 0x63, 0xa9, 0xad, 0x19, 0xa8, 0xd6, 0x88, 0x3f, 0x6e, + 0xb3, 0x27, 0xf1, 0x3b, 0xce, 0xd1, 0x01, 0x73, 0x6f, 0x21, 0x36, 0xec, + 0x9d, 0x43, 0x5b, 0xf5, 0x48, 0x7d, 0xdd, 0xe5, 0x0a, 0x47, 0x43, 0xae, + 0x58, 0xbd, 0xee, 0x54, 0x16, 0x33, 0x1e, 0xcb, 0xfe, 0xc9, 0xf3, 0xbf, + 0x72, 0x1b, 0x5f, 0xaa, 0x60, 0x7c, 0x7b, 0xd2, 0x92, 0x41, 0x6a, 0xc0, + 0x32, 0xee, 0xdf, 0xee, 0xd3, 0xd4, 0xcd, 0x7d, 0xba, 0x0f, 0x8e, 0x27, + 0x2a, 0xc9, 0xbf, 0xee, 0x1e, 0x43, 0x0a, 0x18, 0x43, 0xee, 0x8d, 0x99, + 0x5d, 0x5b, 0x43, 0x45, 0x52, 0x17, 0xb2, 0x62, 0x48, 0xbb, 0x8d, 0x38, + 0x5a, 0x2a, 0x76, 0xe1, 0xab, 0x21, 0xc6, 0xe9, 0x99, 0xdf, 0xc4, 0x3e, + 0xac, 0x3a, 0x5e, 0xf6, 0xb7, 0x0e, 0xec, 0x22, 0x66, 0xca, 0xd9, 0x6e, + 0xa7, 0xa6, 0xd1, 0xff, 0x3b, 0xd0, 0xc3, 0x39, 0x5f, 0x26, 0x6e, 0x0e, + 0x10, 0x37, 0x6f, 0x2c, 0x3b, 0xf1, 0x93, 0x1a, 0xd4, 0xd1, 0x08, 0xa6, + 0xfe, 0x5b, 0xb9, 0xe0, 0xe6, 0x52, 0x7f, 0xc7, 0x27, 0x16, 0x6e, 0xca, + 0xdc, 0x32, 0xdf, 0xec, 0xb9, 0x17, 0xf2, 0xdf, 0x85, 0x52, 0x4b, 0x34, + 0x9d, 0xda, 0xff, 0x36, 0x77, 0x56, 0x8a, 0xac, 0x77, 0x93, 0x43, 0xb0, + 0x76, 0x76, 0x4f, 0x7e, 0x9a, 0x98, 0x6b, 0xe5, 0x08, 0x8c, 0xb9, 0x11, + 0xac, 0x59, 0xae, 0xe2, 0x6a, 0x74, 0x1a, 0x05, 0x87, 0x72, 0xf8, 0x64, + 0x36, 0x9d, 0x22, 0x36, 0x0d, 0x43, 0xf0, 0xa8, 0x91, 0xfb, 0x62, 0xd0, + 0x4f, 0x4a, 0x30, 0x91, 0xd4, 0x88, 0x99, 0x26, 0xfa, 0x43, 0x2e, 0x72, + 0xdb, 0xee, 0x93, 0x79, 0x56, 0x9c, 0x28, 0x21, 0x86, 0xe7, 0x78, 0xb7, + 0x70, 0x6e, 0xc1, 0x1f, 0xe6, 0x18, 0x23, 0x76, 0xe4, 0x2d, 0x93, 0xbc, + 0xe2, 0x73, 0xf3, 0x42, 0x9b, 0xdc, 0xb7, 0x00, 0xc3, 0x7b, 0xc5, 0xfe, + 0x7c, 0xa8, 0xd1, 0x2e, 0x32, 0xcf, 0x00, 0xde, 0x8f, 0xda, 0xee, 0x71, + 0x91, 0x1b, 0x77, 0xe9, 0xcb, 0x71, 0xa3, 0xa2, 0x87, 0x3e, 0xef, 0xe6, + 0x6f, 0x53, 0x38, 0x12, 0x75, 0x21, 0xcf, 0xd2, 0x69, 0x29, 0xd7, 0x90, + 0xb1, 0xa1, 0x9d, 0xb4, 0xa1, 0x7c, 0xe6, 0x6f, 0x0f, 0x5b, 0xbe, 0x2a, + 0xf3, 0x4c, 0xe3, 0x15, 0x72, 0x5a, 0x6d, 0xb9, 0xf0, 0xd9, 0x20, 0xe3, + 0x62, 0x09, 0xe2, 0x03, 0x5d, 0x38, 0x1f, 0x2a, 0x41, 0xec, 0x90, 0xf8, + 0xd8, 0x02, 0xc1, 0x52, 0x3e, 0xb7, 0x91, 0x3a, 0x51, 0x89, 0x35, 0xf5, + 0x9d, 0x76, 0x7b, 0x09, 0x2e, 0x95, 0x31, 0xaf, 0xb5, 0xde, 0xe3, 0x69, + 0xc5, 0xc1, 0xac, 0x5d, 0xa8, 0xb4, 0x8b, 0xd6, 0x9b, 0x3c, 0x3a, 0xb7, + 0x96, 0x9c, 0xcf, 0x66, 0xfa, 0xe1, 0xbd, 0xe4, 0x36, 0x2f, 0x4b, 0xfd, + 0xc8, 0xe6, 0x63, 0x2c, 0x61, 0xce, 0x34, 0x29, 0xfa, 0xfd, 0xeb, 0xb9, + 0x19, 0xac, 0x78, 0xa5, 0x26, 0x73, 0x76, 0x25, 0xa7, 0xf7, 0xdc, 0x77, + 0x6d, 0x7d, 0xa1, 0xf2, 0x0b, 0x73, 0x6b, 0x95, 0xc8, 0x77, 0x9d, 0x79, + 0xda, 0x77, 0xf9, 0xfb, 0x2a, 0xf4, 0x8e, 0xcc, 0x8e, 0x15, 0xe2, 0x87, + 0x9e, 0xdb, 0xce, 0xd5, 0x95, 0xc5, 0xe5, 0xdd, 0xa9, 0x63, 0xa1, 0x67, + 0xb8, 0x0f, 0xfe, 0xa5, 0xf5, 0x56, 0xdd, 0x85, 0xdc, 0x97, 0x79, 0x89, + 0x60, 0xac, 0xc1, 0x18, 0x5f, 0x82, 0x9f, 0x26, 0x25, 0xe6, 0x9a, 0xc8, + 0xa7, 0xfd, 0x5d, 0xaa, 0xec, 0x7e, 0xbe, 0xcc, 0xe2, 0xd2, 0x25, 0x28, + 0xa7, 0xbd, 0x0f, 0x8e, 0xdc, 0xcd, 0xb6, 0x6f, 0xc5, 0x85, 0x74, 0x48, + 0x21, 0x4e, 0xfc, 0x8b, 0xd9, 0xff, 0xf5, 0xcc, 0x98, 0x0b, 0x49, 0x17, + 0x3e, 0x0a, 0xb5, 0x63, 0xaa, 0x2c, 0x8c, 0xa1, 0x44, 0x01, 0xda, 0xab, + 0xeb, 0xac, 0x77, 0x0a, 0x6a, 0xe2, 0x1e, 0x5c, 0x8c, 0x3a, 0xd1, 0x38, + 0xd7, 0x63, 0xd5, 0xd3, 0x6c, 0xf4, 0x85, 0x77, 0xa2, 0x11, 0xcb, 0xe7, + 0x66, 0xc7, 0x8c, 0x3c, 0x6d, 0x19, 0x1e, 0xca, 0xe2, 0xfa, 0xc1, 0xc4, + 0xe7, 0xc4, 0x9d, 0x52, 0xa3, 0x22, 0x5c, 0x82, 0x7b, 0x87, 0x0c, 0xc1, + 0x64, 0xa3, 0x24, 0xac, 0xcd, 0xdc, 0xa7, 0x94, 0xa0, 0x69, 0x44, 0x30, + 0x5e, 0x7c, 0x35, 0x4d, 0x5f, 0x6d, 0xe3, 0x1e, 0x75, 0xa2, 0x6e, 0xbf, + 0xa5, 0x57, 0xd5, 0xae, 0x98, 0x5d, 0x57, 0xf4, 0x88, 0xce, 0x18, 0xd7, + 0xf9, 0x10, 0xed, 0x7e, 0x26, 0xe4, 0x6d, 0xaf, 0xb0, 0x6b, 0x1d, 0xef, + 0x29, 0x41, 0x4c, 0x8c, 0x03, 0x03, 0x87, 0x03, 0xf8, 0x20, 0x21, 0x9c, + 0x3f, 0x80, 0x5f, 0x4d, 0x06, 0xf1, 0x2e, 0x63, 0x53, 0x41, 0xdc, 0x1b, + 0x79, 0x8e, 0x39, 0xdd, 0xfb, 0xfc, 0x9e, 0x1f, 0xd7, 0x71, 0x8d, 0xfa, + 0x73, 0xc6, 0x1b, 0x70, 0x65, 0xf2, 0x01, 0x5c, 0xdd, 0xaf, 0xe0, 0x84, + 0xf6, 0x00, 0x2e, 0x8f, 0x75, 0x62, 0xd9, 0x7e, 0x39, 0x87, 0x76, 0x2c, + 0xa4, 0x32, 0x36, 0x3c, 0x53, 0x6b, 0x76, 0xbd, 0xa8, 0xd7, 0x41, 0x2f, + 0xf7, 0xea, 0xed, 0xcc, 0x99, 0x04, 0xd3, 0x23, 0x36, 0xd9, 0x33, 0xd9, + 0xbb, 0x4e, 0x5c, 0xb5, 0x70, 0xfc, 0xee, 0xd8, 0x70, 0x0b, 0xc3, 0xe5, + 0x39, 0x82, 0x27, 0x0b, 0xf1, 0x7d, 0x26, 0xab, 0x3d, 0xbc, 0xcf, 0x45, + 0xec, 0x7b, 0x36, 0x5a, 0x80, 0xfc, 0xaa, 0x52, 0x2b, 0x97, 0x29, 0x8c, + 0x07, 0x70, 0x96, 0xba, 0x5b, 0x53, 0xe5, 0xe5, 0x77, 0x89, 0xbb, 0x41, + 0xe6, 0x2d, 0x15, 0xf8, 0xe0, 0xb6, 0x78, 0xfb, 0x7d, 0xf3, 0x49, 0x0b, + 0x9f, 0xeb, 0xe7, 0x09, 0xff, 0x7a, 0x3d, 0xf1, 0xeb, 0x1a, 0xc1, 0x69, + 0xa9, 0x21, 0x96, 0x6a, 0xda, 0x96, 0xbf, 0x80, 0xbc, 0x6f, 0x75, 0xe2, + 0x3f, 0x17, 0x93, 0x17, 0xbf, 0x18, 0xaa, 0x33, 0xca, 0xa0, 0xf1, 0xbe, + 0xa9, 0x65, 0x2a, 0x56, 0xf1, 0xaf, 0x9f, 0xf7, 0x05, 0x29, 0xc7, 0x75, + 0x33, 0xa5, 0xfa, 0xf8, 0xef, 0x05, 0x8c, 0xef, 0xdb, 0x71, 0x3e, 0x56, + 0xdf, 0x7e, 0x58, 0xb9, 0x66, 0x1a, 0x55, 0xb5, 0xfc, 0xad, 0x12, 0x17, + 0xa2, 0xde, 0xa9, 0x31, 0xd4, 0x7b, 0x66, 0x94, 0x83, 0xa6, 0xa1, 0xca, + 0xfe, 0xc8, 0x7a, 0x65, 0xfc, 0x62, 0x5e, 0xbf, 0x34, 0xcb, 0x0e, 0x6f, + 0xe5, 0x5d, 0xce, 0x9b, 0xf6, 0x27, 0xbc, 0xc4, 0x6c, 0x1a, 0xd5, 0xeb, + 0xd5, 0x1e, 0x62, 0x41, 0x44, 0xbd, 0x9b, 0xfd, 0x15, 0xd0, 0xfe, 0xc2, + 0xcc, 0x23, 0x4b, 0xa0, 0x5a, 0xf1, 0xa9, 0x15, 0xc9, 0x91, 0xd9, 0xdc, + 0x52, 0xec, 0x2e, 0xc3, 0x53, 0xdb, 0xcb, 0xba, 0x4f, 0x3a, 0x89, 0x45, + 0x09, 0xe2, 0x78, 0x9c, 0x38, 0x9e, 0x4f, 0x1c, 0xbf, 0xbe, 0xaf, 0x10, + 0xe7, 0xf7, 0x35, 0x22, 0x5d, 0x26, 0x63, 0xec, 0x70, 0x72, 0x75, 0xa9, + 0xec, 0x79, 0x85, 0x9a, 0xc1, 0x95, 0x72, 0x8e, 0x13, 0x82, 0x5f, 0x79, + 0x71, 0xe6, 0x59, 0xad, 0x76, 0x38, 0xac, 0x33, 0xf6, 0x73, 0x6e, 0xb3, + 0x3f, 0x97, 0x96, 0x8f, 0x96, 0x4a, 0xc1, 0x87, 0xd7, 0xe7, 0x49, 0x1c, + 0x7d, 0x9d, 0xb2, 0x9c, 0xa4, 0x4d, 0x6f, 0xd4, 0x57, 0x48, 0x5f, 0x8f, + 0xf7, 0xcb, 0x38, 0xc9, 0x6d, 0x4c, 0xec, 0xa6, 0x85, 0xd5, 0x55, 0x99, + 0x48, 0xe8, 0x61, 0xc6, 0xac, 0x10, 0x22, 0x65, 0x41, 0xc6, 0x2a, 0xf9, + 0xae, 0xe2, 0x0a, 0xf3, 0xb2, 0xf1, 0xa0, 0x82, 0x8f, 0xbe, 0x22, 0x5c, + 0xc0, 0xaf, 0x9f, 0x57, 0x84, 0x0b, 0xc8, 0x78, 0xc1, 0x88, 0x52, 0x0b, + 0x23, 0xf2, 0x2d, 0x5e, 0x34, 0xd7, 0xc2, 0x16, 0x79, 0x47, 0xa9, 0x86, + 0x71, 0xe7, 0xfe, 0x44, 0xfd, 0x94, 0xcf, 0x4e, 0x8e, 0xf6, 0x27, 0x5f, + 0x21, 0x37, 0xb3, 0x38, 0x02, 0xf1, 0x3e, 0x87, 0x0d, 0x72, 0xee, 0x76, + 0xb6, 0x3e, 0x72, 0xe7, 0x72, 0x3d, 0x19, 0xac, 0x2c, 0x15, 0x2e, 0xf7, + 0xff, 0xcc, 0xd6, 0xdb, 0xe4, 0xcf, 0xe1, 0xc8, 0x3f, 0xf0, 0xbb, 0x8c, + 0x17, 0xbf, 0xa3, 0x5d, 0xc4, 0x7f, 0x62, 0x3e, 0x6d, 0xf1, 0xb9, 0x97, + 0xe7, 0xc9, 0xf9, 0x43, 0xc7, 0xe0, 0xd0, 0x3c, 0x39, 0x6f, 0x65, 0x9b, + 0xc5, 0x0b, 0x32, 0xb1, 0xf6, 0x5d, 0x73, 0xad, 0x25, 0xeb, 0x91, 0xec, + 0x7d, 0x92, 0x43, 0x8b, 0x2c, 0x0a, 0x5e, 0xd1, 0xea, 0xd5, 0xb3, 0x28, + 0x16, 0x3c, 0x89, 0x48, 0x0f, 0xb3, 0x50, 0xf3, 0xb9, 0x8f, 0xf0, 0x6f, + 0x3f, 0xaf, 0xbf, 0xa1, 0x39, 0x1a, 0xb7, 0x42, 0xfa, 0xb6, 0x36, 0xee, + 0x55, 0xbd, 0xfb, 0x2c, 0xfc, 0x91, 0x7c, 0x65, 0xc6, 0x6c, 0xaf, 0x94, + 0x7b, 0x32, 0xfd, 0x5b, 0x28, 0x17, 0xad, 0xfa, 0x49, 0xc6, 0x66, 0x16, + 0xd0, 0x66, 0x04, 0xbb, 0x84, 0x8b, 0x2c, 0xe1, 0xda, 0x55, 0x8c, 0x4c, + 0x02, 0x79, 0x83, 0x2e, 0x8b, 0x1b, 0xa9, 0xb5, 0xb5, 0x9e, 0xcd, 0xf8, + 0xe7, 0x79, 0xf2, 0xee, 0xd1, 0x0e, 0x1d, 0xf7, 0xd8, 0xf0, 0xf6, 0x3d, + 0xb6, 0xf0, 0xca, 0x6f, 0x3d, 0xd4, 0x90, 0x37, 0x5f, 0xde, 0xff, 0x20, + 0xc3, 0x93, 0xfa, 0xad, 0x5b, 0x7a, 0x8d, 0xab, 0x19, 0xc3, 0x86, 0x99, + 0xe3, 0xaf, 0x0e, 0xfe, 0xd6, 0xfc, 0xa6, 0x23, 0xe2, 0xb1, 0xa3, 0xd6, + 0xd3, 0x8b, 0x1b, 0x66, 0xaa, 0x52, 0xae, 0xcb, 0x1c, 0xf2, 0x6e, 0xa1, + 0xf4, 0x4b, 0x4c, 0xf3, 0xde, 0x5a, 0x93, 0xf9, 0xb3, 0x6d, 0x95, 0x9d, + 0x7e, 0x91, 0xaf, 0x5d, 0x36, 0xeb, 0xaa, 0x6b, 0xdd, 0x36, 0xa5, 0x8e, + 0xd6, 0x51, 0x89, 0x57, 0x69, 0xbf, 0xaf, 0x4e, 0x4a, 0xcc, 0x53, 0x71, + 0x94, 0x7e, 0x3a, 0x56, 0xe7, 0xeb, 0xbc, 0xca, 0x5c, 0xf2, 0x43, 0x72, + 0xfc, 0x37, 0x35, 0x6f, 0xfb, 0x19, 0xa9, 0x3b, 0x86, 0x1c, 0x38, 0x17, + 0xbc, 0x61, 0xd5, 0x82, 0x63, 0x87, 0x54, 0x0c, 0x27, 0x32, 0xfe, 0xfe, + 0x1a, 0xfd, 0xf8, 0xd6, 0xd9, 0x05, 0x1d, 0x3d, 0x43, 0xe2, 0x1f, 0x0d, + 0x96, 0x1f, 0xdd, 0xaa, 0x15, 0x09, 0x5e, 0x8b, 0x5f, 0x6c, 0x90, 0xde, + 0x9d, 0x91, 0x02, 0xb9, 0xcc, 0xe0, 0x6a, 0x72, 0x60, 0x89, 0xb1, 0x01, + 0xe6, 0xbb, 0x0e, 0xfa, 0xcf, 0x19, 0xe6, 0x1e, 0x94, 0x2d, 0x6c, 0x9a, + 0xef, 0x32, 0x17, 0x1b, 0x41, 0xbd, 0x7a, 0x0a, 0xeb, 0xc8, 0x63, 0xc9, + 0x71, 0x26, 0x9b, 0xb1, 0xc7, 0xca, 0xa5, 0x7c, 0xea, 0xc3, 0xca, 0x52, + 0xae, 0xbf, 0x19, 0xdd, 0x63, 0x0b, 0x70, 0x80, 0xeb, 0x7a, 0x44, 0xff, + 0x2b, 0x94, 0x0f, 0x75, 0x77, 0x96, 0x53, 0x1f, 0x9f, 0x86, 0x8c, 0x0e, + 0x62, 0xfa, 0x96, 0x53, 0x4a, 0xfd, 0xfa, 0x98, 0xf2, 0x4d, 0xee, 0x87, + 0xd4, 0x47, 0x3c, 0xcc, 0xd3, 0x1f, 0x61, 0x3c, 0xfb, 0x33, 0xec, 0x56, + 0x95, 0x26, 0x5b, 0x58, 0x38, 0x22, 0xfc, 0xaa, 0x75, 0x76, 0xf0, 0xbf, + 0x40, 0x9f, 0xdb, 0xc0, 0x6b, 0x12, 0xd7, 0xe5, 0x5e, 0x39, 0x37, 0xde, + 0x89, 0x93, 0x69, 0xda, 0x75, 0xb4, 0x0f, 0xa7, 0xd2, 0xf2, 0x4c, 0xe1, + 0x58, 0x01, 0xc4, 0x86, 0xec, 0x98, 0xd0, 0x7d, 0x91, 0x52, 0xea, 0xa5, + 0x30, 0xe4, 0x8d, 0xac, 0x53, 0x02, 0xe4, 0x72, 0x69, 0x9c, 0xdb, 0xeb, + 0x6d, 0xaf, 0x63, 0xde, 0x18, 0x9d, 0x84, 0xfa, 0xdc, 0xf2, 0x34, 0xce, + 0x8e, 0x3e, 0x0e, 0x4f, 0xb5, 0xd7, 0xb3, 0x5a, 0x69, 0xc1, 0x8e, 0xc9, + 0x7f, 0xaf, 0xc6, 0xe4, 0xe1, 0xb3, 0x5b, 0x60, 0x50, 0xf7, 0xbb, 0xf0, + 0xad, 0xf9, 0xe2, 0xf3, 0xbd, 0x93, 0xc5, 0x58, 0xc4, 0x78, 0xf4, 0xb2, + 0x15, 0x67, 0x33, 0x7e, 0x54, 0xa3, 0x7d, 0x64, 0x3e, 0x95, 0x8d, 0xe1, + 0x7f, 0x58, 0x5f, 0x3f, 0x34, 0x23, 0xaa, 0xe8, 0x4b, 0xc6, 0xd5, 0xa0, + 0x80, 0xf3, 0xec, 0xce, 0xc6, 0xeb, 0x32, 0xed, 0x9f, 0xcc, 0xc7, 0xad, + 0x39, 0x56, 0xce, 0x97, 0x44, 0x61, 0xa7, 0x95, 0xe7, 0xcb, 0xba, 0x75, + 0x7c, 0x16, 0x95, 0x5a, 0x87, 0x8a, 0x53, 0xba, 0xe0, 0x48, 0x0b, 0x7d, + 0xd5, 0x89, 0x2d, 0x41, 0xba, 0xa3, 0x55, 0xf7, 0x9f, 0xc6, 0x9e, 0xe4, + 0xbf, 0x9a, 0xcf, 0xd3, 0x8e, 0xd6, 0x90, 0xc3, 0x78, 0x88, 0x03, 0x1b, + 0x43, 0x8f, 0x90, 0x87, 0x72, 0xcd, 0x09, 0x07, 0x31, 0x48, 0x41, 0xa2, + 0x91, 0xfe, 0x1f, 0x5a, 0x82, 0x29, 0xeb, 0xfe, 0x4f, 0xe7, 0x65, 0x6a, + 0x8b, 0x67, 0xe6, 0x67, 0x72, 0x43, 0xd1, 0xff, 0x7f, 0x44, 0x7f, 0xaf, + 0x99, 0x9e, 0x72, 0xd1, 0x9f, 0x03, 0x6e, 0xc6, 0xad, 0x03, 0xbc, 0xe7, + 0xc2, 0x5e, 0x07, 0x06, 0xb5, 0x16, 0x0c, 0x4e, 0xc2, 0xf3, 0x29, 0xef, + 0xf9, 0xf9, 0x68, 0xc7, 0xfc, 0x0c, 0x57, 0x78, 0x1b, 0xdd, 0xd1, 0x17, + 0xcc, 0x55, 0xe5, 0xb2, 0x5e, 0x39, 0xaf, 0xd3, 0xca, 0xfb, 0x73, 0x75, + 0xbe, 0xcd, 0xe6, 0x13, 0x56, 0x9c, 0x78, 0x71, 0xbe, 0xf4, 0xd7, 0x5e, + 0x4f, 0x98, 0xb8, 0xa2, 0xf7, 0x58, 0xb9, 0xb9, 0x60, 0x43, 0x6f, 0x42, + 0xf6, 0x56, 0x64, 0xfb, 0x66, 0x56, 0x1f, 0x13, 0x55, 0xb7, 0xcb, 0xbd, + 0x2a, 0x6b, 0xcb, 0xd2, 0xdf, 0xce, 0xf1, 0x7e, 0xb1, 0x65, 0xb1, 0x63, + 0xeb, 0xbd, 0x96, 0xa4, 0xbc, 0xd3, 0xb9, 0x41, 0xfd, 0x1d, 0x9f, 0x21, + 0x75, 0x96, 0x16, 0xce, 0x61, 0x9a, 0x9b, 0xf5, 0x7a, 0xcf, 0x29, 0xfc, + 0x31, 0x6d, 0x5b, 0xc7, 0xae, 0x21, 0xa9, 0xc3, 0x7a, 0x14, 0xc7, 0xbe, + 0x75, 0xb8, 0xc2, 0xf8, 0xbf, 0xc7, 0xb2, 0x43, 0xc1, 0x15, 0x91, 0x43, + 0xb0, 0xa5, 0x8d, 0x71, 0x5c, 0x6a, 0xdd, 0x46, 0xa4, 0x26, 0xdc, 0xa9, + 0x7c, 0x58, 0xd7, 0x89, 0x63, 0x21, 0xc3, 0x2c, 0xd5, 0xfc, 0xeb, 0x6b, + 0x6c, 0x28, 0x98, 0x6c, 0xc8, 0xc7, 0xf1, 0x90, 0xf0, 0x47, 0xb8, 0xd2, + 0x69, 0xaf, 0x31, 0xc7, 0xae, 0xba, 0xbe, 0x97, 0xce, 0x62, 0xa5, 0xad, + 0x7e, 0xbe, 0xe4, 0x50, 0x49, 0x0b, 0x47, 0xbe, 0x8a, 0x07, 0xad, 0xbd, + 0x55, 0x19, 0x43, 0xa5, 0x0e, 0x7c, 0x2c, 0x74, 0x2d, 0x2a, 0x98, 0x62, + 0x36, 0x35, 0x87, 0xea, 0xd5, 0x5d, 0xb8, 0x87, 0xd8, 0xd5, 0x84, 0x73, + 0xba, 0xf4, 0x3f, 0x8c, 0x6f, 0x3a, 0xac, 0xb3, 0x34, 0x47, 0x43, 0x3b, + 0xa2, 0x2b, 0x71, 0x60, 0xc8, 0x50, 0x9c, 0x61, 0x6f, 0x24, 0x46, 0x2e, + 0xc4, 0x1c, 0xdd, 0xaa, 0x03, 0x4a, 0x8d, 0x61, 0xb8, 0xa1, 0x13, 0xbb, + 0xf4, 0x7c, 0xf4, 0xea, 0x91, 0x82, 0x9e, 0xe5, 0x5d, 0x38, 0xa8, 0x17, + 0x1b, 0x8b, 0xc2, 0x06, 0x31, 0x5d, 0xdb, 0x92, 0x84, 0xbf, 0xe5, 0x32, + 0x39, 0xc7, 0x49, 0x78, 0x3b, 0x9a, 0xec, 0xc4, 0xdc, 0x15, 0x0e, 0x57, + 0x6c, 0xbc, 0x11, 0x89, 0xc9, 0x4a, 0xd7, 0xee, 0xf1, 0x20, 0xe2, 0x93, + 0xdc, 0x6f, 0xe6, 0xba, 0x8e, 0xf1, 0x95, 0xe4, 0xa0, 0xa2, 0x47, 0x3b, + 0x6d, 0xb1, 0x0e, 0xcf, 0xb5, 0x5e, 0x32, 0x9f, 0xf1, 0x0b, 0x7e, 0x2e, + 0xc0, 0x56, 0xd5, 0x67, 0x71, 0xca, 0x88, 0xed, 0x0f, 0xf9, 0x87, 0x9d, + 0x36, 0xf7, 0x7d, 0xd3, 0xf3, 0x75, 0xd1, 0x9b, 0x63, 0x01, 0x0a, 0x1f, + 0x21, 0x7e, 0xca, 0xbf, 0x45, 0x77, 0xa2, 0x43, 0x13, 0x9b, 0x74, 0xa9, + 0xf1, 0x35, 0xd0, 0x67, 0xdc, 0x78, 0x47, 0xbd, 0xb5, 0x0f, 0xcf, 0xea, + 0x3e, 0x7d, 0x0c, 0x52, 0xdb, 0x5b, 0xc1, 0x71, 0x52, 0x83, 0x69, 0xc4, + 0x4b, 0xd9, 0x9c, 0xc3, 0x63, 0x2b, 0x22, 0xee, 0xe6, 0xe2, 0x88, 0x5c, + 0xf7, 0x26, 0x23, 0xb4, 0xd3, 0x6d, 0xc1, 0x19, 0x33, 0x52, 0x6e, 0x74, + 0xca, 0xf9, 0x15, 0x77, 0x78, 0xba, 0xd3, 0x5d, 0xe7, 0xed, 0x98, 0x51, + 0x80, 0x73, 0x31, 0xc6, 0x61, 0xeb, 0x7f, 0xb1, 0x28, 0x73, 0x3b, 0x31, + 0x12, 0x5c, 0x88, 0xf6, 0x36, 0x79, 0x56, 0x33, 0xfa, 0xf6, 0x9b, 0x66, + 0x71, 0xc8, 0xa7, 0xa6, 0xe1, 0xc4, 0xc3, 0x41, 0x3b, 0x2e, 0xa9, 0x26, + 0x1c, 0xa1, 0x7f, 0x35, 0xc7, 0x19, 0x1f, 0x47, 0xe9, 0x27, 0xbb, 0x69, + 0x63, 0xf2, 0xbe, 0x8f, 0x9f, 0x7e, 0x12, 0xa7, 0x9f, 0x9c, 0x0b, 0xdd, + 0x97, 0x7d, 0x5f, 0x50, 0x23, 0xaf, 0x98, 0x46, 0xd3, 0x90, 0x8a, 0x4f, + 0x57, 0x4c, 0x23, 0x34, 0x92, 0x93, 0x5d, 0xfc, 0x32, 0x27, 0xbf, 0xf4, + 0x11, 0x45, 0x76, 0x91, 0x51, 0xd6, 0x22, 0xff, 0xce, 0x5d, 0xcb, 0xfd, + 0x26, 0x71, 0xd6, 0x89, 0x56, 0x6b, 0x6d, 0x7f, 0x56, 0x93, 0xc1, 0x8c, + 0xdc, 0x9a, 0x2e, 0xb9, 0x6f, 0xff, 0x7e, 0xe2, 0x8e, 0xeb, 0x2b, 0xee, + 0xb8, 0xbe, 0x71, 0xde, 0xed, 0xdf, 0x73, 0x3e, 0x71, 0x4b, 0xaf, 0x1d, + 0xba, 0x6f, 0xea, 0x18, 0xd7, 0x3a, 0x67, 0xc9, 0x98, 0x79, 0xa9, 0x4c, + 0x64, 0x91, 0x3c, 0x36, 0x23, 0xeb, 0xaa, 0xf1, 0xd9, 0xb2, 0xbe, 0x95, + 0xed, 0x19, 0x58, 0x67, 0x7c, 0xe9, 0x37, 0x1a, 0x7e, 0x78, 0xdb, 0xb9, + 0x43, 0xb1, 0xb5, 0x80, 0xd2, 0x17, 0x93, 0xf7, 0x33, 0x0b, 0xad, 0x77, + 0xac, 0x55, 0xbf, 0x81, 0x22, 0xbf, 0xb6, 0x65, 0x8e, 0xad, 0x0b, 0xce, + 0xa5, 0x5a, 0xc7, 0xb7, 0x94, 0x24, 0xe2, 0xe3, 0xde, 0xc0, 0x18, 0x75, + 0x15, 0x1b, 0xbf, 0xce, 0x5c, 0xbb, 0x0b, 0xcf, 0x85, 0x1c, 0x46, 0x61, + 0x58, 0xce, 0x82, 0xae, 0xc2, 0xae, 0x91, 0xbf, 0xc2, 0xe6, 0xa4, 0x70, + 0xfc, 0x05, 0xe8, 0x99, 0xb4, 0xe1, 0x04, 0xed, 0xbb, 0x8f, 0xcf, 0x21, + 0xfe, 0xb9, 0x53, 0x90, 0xf7, 0x6b, 0x1a, 0x98, 0x37, 0xeb, 0xd6, 0x67, + 0xc7, 0xc8, 0xcf, 0xb0, 0x39, 0x6a, 0xe2, 0x53, 0x9d, 0xb1, 0x47, 0x13, + 0xf9, 0x1c, 0xd0, 0xca, 0x5b, 0x2d, 0x2c, 0x7d, 0x32, 0xce, 0xfd, 0xac, + 0x16, 0x5f, 0x5d, 0x49, 0x9f, 0x55, 0xf0, 0x99, 0xf4, 0x27, 0xcb, 0x29, + 0x33, 0xb9, 0xe1, 0xf1, 0xe8, 0x76, 0x8c, 0x5a, 0xfd, 0x67, 0xad, 0xaf, + 0xc6, 0x1e, 0x79, 0xb1, 0x8c, 0x3c, 0x3b, 0xa1, 0xfb, 0xdb, 0x2f, 0x28, + 0xf0, 0x94, 0x84, 0xfd, 0x8c, 0x33, 0x5f, 0xe2, 0x37, 0xba, 0xd4, 0xd8, + 0x74, 0xd7, 0x5a, 0xda, 0xfb, 0xbe, 0x91, 0x80, 0x55, 0x33, 0xf8, 0xe1, + 0x5d, 0x6b, 0x1a, 0x99, 0x77, 0xab, 0x33, 0xf5, 0xc7, 0x9f, 0xe1, 0x48, + 0xda, 0x85, 0xa7, 0xe2, 0x1e, 0x65, 0xd1, 0x3e, 0x15, 0x0f, 0xc5, 0xbd, + 0x53, 0x4d, 0x76, 0xf2, 0x8f, 0x65, 0x73, 0x38, 0x9f, 0x82, 0x1f, 0x2c, + 0x95, 0x58, 0xf0, 0x47, 0x30, 0xaa, 0x23, 0x9c, 0x13, 0xc5, 0x79, 0xcb, + 0xbd, 0xea, 0x11, 0x9b, 0xcf, 0xfd, 0x1b, 0xec, 0x80, 0x7d, 0xfc, 0x11, + 0x74, 0x53, 0xfe, 0x35, 0x71, 0xe9, 0x69, 0xd5, 0x03, 0x65, 0xcd, 0xd8, + 0x3d, 0x26, 0xbe, 0x09, 0xa3, 0x2a, 0x0c, 0x4f, 0x65, 0xd8, 0xbf, 0x10, + 0x85, 0x5f, 0x92, 0x6b, 0x4f, 0x4b, 0xfe, 0xb9, 0xa5, 0xd4, 0x66, 0x32, + 0x7f, 0xb9, 0x2f, 0xdb, 0xab, 0x58, 0x89, 0x1d, 0x43, 0x52, 0x87, 0x27, + 0x6e, 0xeb, 0xcc, 0x83, 0xca, 0xb4, 0xc0, 0x46, 0x9b, 0xf4, 0x87, 0xb6, + 0xc3, 0x17, 0xdb, 0x8e, 0x40, 0x4c, 0x7c, 0x56, 0x53, 0x3b, 0x10, 0x39, + 0x2b, 0xb5, 0xbf, 0x45, 0x21, 0x3f, 0xe5, 0xf2, 0xf7, 0x55, 0xda, 0x75, + 0xd7, 0x6b, 0x13, 0x2a, 0xa6, 0xd4, 0x4c, 0x1e, 0x39, 0x96, 0xd4, 0xd6, + 0xe7, 0xdb, 0xe4, 0x0c, 0xc5, 0x55, 0xeb, 0x3d, 0xeb, 0x88, 0xed, 0x9f, + 0x89, 0x47, 0xcd, 0x18, 0xd8, 0xff, 0x3e, 0x63, 0x90, 0x3c, 0xe3, 0x77, + 0xcc, 0xaf, 0x9d, 0x58, 0xdd, 0xe6, 0xc1, 0x83, 0x71, 0xa9, 0x9d, 0xae, + 0xaf, 0xca, 0x9c, 0x01, 0x91, 0xef, 0x0e, 0x74, 0xe8, 0x04, 0xd9, 0xea, + 0x2f, 0xcc, 0x4a, 0x2b, 0x2f, 0xfd, 0xbf, 0x19, 0x9b, 0x49, 0xe4, 0x2d, + 0x14, 0x1f, 0xef, 0x9d, 0x64, 0x02, 0x69, 0xd9, 0x5d, 0x15, 0xbf, 0xcb, + 0x5c, 0xda, 0x81, 0xed, 0xd8, 0x56, 0x25, 0x7c, 0xe6, 0xc9, 0x89, 0xd9, + 0xf7, 0xe7, 0xea, 0x32, 0x95, 0x59, 0x4e, 0x95, 0xb3, 0x37, 0xe9, 0x05, + 0x46, 0x94, 0x27, 0xa2, 0x2d, 0xca, 0xda, 0xa8, 0xf4, 0x03, 0x6d, 0xd1, + 0x22, 0x72, 0x18, 0xdf, 0x52, 0x13, 0xdf, 0x0e, 0x1d, 0x57, 0x76, 0x5a, + 0xe7, 0x66, 0xe5, 0xac, 0x2b, 0x50, 0x3e, 0xd1, 0xac, 0xec, 0x8a, 0x7e, + 0x62, 0x6e, 0xb4, 0x7a, 0xf0, 0x79, 0xd6, 0x79, 0x9c, 0xfc, 0x09, 0x17, + 0xca, 0x8e, 0xc8, 0xf9, 0x41, 0x0d, 0x15, 0x13, 0x8f, 0x91, 0xb7, 0x0a, + 0xd7, 0x31, 0x5a, 0x1c, 0xd6, 0xb9, 0xb6, 0xe6, 0x97, 0x72, 0xe7, 0xda, + 0x1c, 0x31, 0x79, 0x1b, 0xd9, 0xfa, 0x8f, 0xb9, 0xd2, 0x51, 0xe6, 0x4a, + 0x66, 0xd3, 0xb7, 0x43, 0xc6, 0xee, 0x0a, 0x78, 0x03, 0xe5, 0x36, 0xc3, + 0x94, 0x7a, 0xce, 0x6b, 0x24, 0x8c, 0xeb, 0x6a, 0x0d, 0x3c, 0x5c, 0x2b, + 0xef, 0x1f, 0xca, 0xbb, 0xc7, 0x5d, 0x38, 0x1a, 0xea, 0xc2, 0x2f, 0xf5, + 0x2e, 0xec, 0xd1, 0xe5, 0x4c, 0x43, 0x31, 0x65, 0xd5, 0xa6, 0xa2, 0xd0, + 0xf4, 0xb4, 0xa2, 0x9d, 0xb9, 0x0e, 0xef, 0x01, 0x9f, 0xe2, 0x35, 0x56, + 0x29, 0x1a, 0xae, 0x8e, 0x7b, 0x67, 0x4a, 0xe9, 0x03, 0x37, 0xc6, 0x03, + 0x98, 0x21, 0xae, 0x26, 0x27, 0xe5, 0xfc, 0xc9, 0x02, 0x0c, 0x4d, 0x7e, + 0x4d, 0xb8, 0x81, 0x41, 0x4c, 0xb2, 0xce, 0x48, 0x3e, 0x2f, 0xbd, 0x4e, + 0x67, 0x30, 0xcb, 0x61, 0x0c, 0x65, 0x53, 0x43, 0x09, 0x6e, 0x30, 0x3a, + 0xfd, 0x6d, 0xba, 0x93, 0xf9, 0x1c, 0xde, 0xa8, 0x81, 0xfd, 0x3b, 0x6e, + 0xd4, 0x25, 0xe7, 0xe0, 0x44, 0x5d, 0x39, 0xf2, 0x70, 0x6c, 0xf4, 0x45, + 0x72, 0xfc, 0xee, 0xf6, 0x52, 0xe6, 0xa7, 0x13, 0xa3, 0x4e, 0xa4, 0x52, + 0x52, 0x73, 0xb0, 0x7a, 0x96, 0xd3, 0x0e, 0xfa, 0x52, 0x7f, 0x02, 0x75, + 0x35, 0x61, 0x7f, 0xb2, 0xc6, 0xae, 0x72, 0x8e, 0x4a, 0xa4, 0xd2, 0x1a, + 0x3f, 0x01, 0x7e, 0x82, 0xfc, 0x34, 0xe2, 0xdb, 0xf4, 0xd9, 0x32, 0xe2, + 0xed, 0xf7, 0xd3, 0x25, 0xf8, 0x24, 0xa9, 0x05, 0x74, 0xda, 0xc1, 0x28, + 0x73, 0x04, 0xc3, 0xd2, 0x53, 0x09, 0xae, 0xd3, 0x4f, 0x5f, 0x0e, 0x95, + 0xc0, 0x4c, 0xdd, 0x2d, 0x27, 0x94, 0xdc, 0x16, 0x6a, 0x61, 0x58, 0xf8, + 0xe2, 0x31, 0x25, 0x95, 0x3d, 0xf3, 0xf5, 0xea, 0x38, 0xda, 0xcb, 0xc3, + 0xae, 0xe0, 0xea, 0xb8, 0xfd, 0x13, 0x79, 0x9f, 0x75, 0x43, 0x83, 0xbc, + 0xf3, 0xe4, 0x0a, 0x3e, 0x3d, 0xe1, 0x0a, 0xae, 0x8f, 0x1f, 0x53, 0x28, + 0xcf, 0x81, 0x1a, 0xbb, 0x2b, 0xf8, 0xe4, 0xc4, 0xb1, 0x85, 0x99, 0xbc, + 0x0f, 0xca, 0xd3, 0xb5, 0x06, 0x6d, 0x8c, 0x79, 0xef, 0x32, 0xe9, 0xcb, + 0x68, 0x9d, 0x57, 0xec, 0x85, 0x46, 0x4d, 0xd8, 0xeb, 0xa9, 0xb1, 0xcb, + 0xd9, 0x90, 0x69, 0xc4, 0x93, 0xf2, 0xae, 0x97, 0xd8, 0xfe, 0x3f, 0x99, + 0x46, 0x99, 0x9c, 0xf5, 0xe8, 0x44, 0x5c, 0x2b, 0x67, 0xee, 0x24, 0x67, + 0xcd, 0x8f, 0x86, 0xa2, 0xb1, 0x62, 0x79, 0x77, 0xb6, 0xe9, 0x7b, 0x21, + 0x6f, 0xcb, 0xa0, 0x62, 0x3c, 0x5e, 0x04, 0xd9, 0xd7, 0x2e, 0xe2, 0xb7, + 0xa6, 0x3a, 0x15, 0x6f, 0x63, 0x0f, 0x02, 0x38, 0x91, 0x16, 0x5d, 0x07, + 0xe5, 0x8c, 0xba, 0xa5, 0xeb, 0x5b, 0x67, 0xae, 0x33, 0xb6, 0xb3, 0x2d, + 0xea, 0xe0, 0x5f, 0xb1, 0x17, 0x1b, 0x63, 0x0a, 0xe3, 0x8a, 0x65, 0x33, + 0xb7, 0x64, 0x5c, 0x57, 0xdb, 0x85, 0xc9, 0x50, 0xa1, 0xbc, 0x77, 0xcd, + 0xb8, 0xee, 0x0d, 0x7c, 0xa2, 0x58, 0xf1, 0xdc, 0x28, 0x62, 0x9c, 0x7d, + 0x61, 0xfc, 0xef, 0xcc, 0xf6, 0x6a, 0xc1, 0x2b, 0x3b, 0xc7, 0x5e, 0xc7, + 0x6b, 0xa9, 0x5b, 0xe3, 0x5a, 0x38, 0xae, 0x90, 0xe3, 0x8a, 0xc2, 0x92, + 0x3b, 0x7a, 0xf5, 0xb5, 0x8a, 0xe6, 0x29, 0x50, 0xa4, 0x57, 0xa6, 0xe1, + 0xbd, 0xf4, 0xe4, 0x42, 0xc9, 0x79, 0x7b, 0x27, 0xcb, 0xb1, 0x6e, 0xaf, + 0xd9, 0xb4, 0x68, 0xa9, 0xd9, 0x94, 0x0e, 0x45, 0xcd, 0x97, 0xab, 0x64, + 0x4f, 0xa5, 0xff, 0x27, 0x63, 0x34, 0xd5, 0xc7, 0x5c, 0xf3, 0x6b, 0x7a, + 0x6f, 0xf6, 0xcc, 0x2e, 0xed, 0x9a, 0xcf, 0x38, 0x9d, 0x12, 0x3b, 0xd9, + 0xd1, 0xee, 0x62, 0x3e, 0x2a, 0xef, 0x87, 0x1e, 0xe5, 0xfe, 0x1f, 0x49, + 0xfd, 0xcd, 0x42, 0x39, 0xc3, 0x2e, 0x67, 0x08, 0x80, 0xff, 0x0f, 0x1d, + 0xab, 0x22, 0x97, 0x70, 0x78, 0x00, 0x00, 0x00 }; static const u32 bnx2_RXP_b09FwData[(0x0/4) + 1] = { 0x0 }; -static const u32 bnx2_RXP_b09FwRodata[(0xb0/4) + 1] = { - 0x80080100, 0x80080080, 0x80080000, 0x08005054, 0x08005054, 0x08005130, - 0x08005104, 0x080050e8, 0x08005024, 0x08005024, 0x08005024, 0x0800505c, - 0x080073b8, 0x08007404, 0x080073c4, 0x080072ec, 0x080073c4, 0x080073f4, - 0x080073c4, 0x080072ec, 0x080072ec, 0x080072ec, 0x080072ec, 0x080072ec, - 0x080072ec, 0x080072ec, 0x080072ec, 0x080072ec, 0x080072ec, 0x080073e4, - 0x080073d4, 0x080072ec, 0x080072ec, 0x080072ec, 0x080072ec, 0x080072ec, - 0x080072ec, 0x080072ec, 0x080072ec, 0x080072ec, 0x080072ec, 0x080072ec, - 0x080072ec, 0x080073d4, 0x00000000 }; +static const u32 bnx2_RXP_b09FwRodata[(0xf0/4) + 1] = { + 0x5f865437, 0xe4ac62cc, 0x50103a45, 0x36621985, 0xbf14c0e8, 0x1bc27a1e, + 0x84f4b556, 0x094ea6fe, 0x7dda01e7, 0xc04d7481, 0x80080100, 0x80080080, + 0x80080000, 0x08004efc, 0x08004efc, 0x08004fd8, 0x08004fac, 0x08004f90, + 0x08004ecc, 0x08004ecc, 0x08004ecc, 0x08004f04, 0x08007220, 0x0800726c, + 0x0800722c, 0x08007150, 0x0800722c, 0x0800725c, 0x0800722c, 0x08007150, + 0x08007150, 0x08007150, 0x08007150, 0x08007150, 0x08007150, 0x08007150, + 0x08007150, 0x08007150, 0x08007150, 0x0800724c, 0x0800723c, 0x08007150, + 0x08007150, 0x08007150, 0x08007150, 0x08007150, 0x08007150, 0x08007150, + 0x08007150, 0x08007150, 0x08007150, 0x08007150, 0x08007150, 0x0800723c, + 0x080077f4, 0x080076bc, 0x080077bc, 0x08007718, 0x080076e8, 0x080075a4, + 0x00000000 }; static struct fw_info bnx2_rxp_fw_09 = { - /* Firmware version: 4.0.5 */ + /* Firmware version: 4.4.23 */ .ver_major = 0x4, - .ver_minor = 0x0, - .ver_fix = 0x5, + .ver_minor = 0x4, + .ver_fix = 0x17, .start_addr = 0x080031d0, .text_addr = 0x08000000, - .text_len = 0x79c0, + .text_len = 0x786c, .text_index = 0x0, .gz_text = bnx2_RXP_b09FwText, .gz_text_len = sizeof(bnx2_RXP_b09FwText), @@ -3158,522 +3158,532 @@ static struct fw_info bnx2_rxp_fw_09 = { .data_index = 0x0, .data = bnx2_RXP_b09FwData, - .sbss_addr = 0x08007aa0, + .sbss_addr = 0x08007980, .sbss_len = 0x58, .sbss_index = 0x0, - .bss_addr = 0x08007af8, + .bss_addr = 0x080079d8, .bss_len = 0x1c, .bss_index = 0x0, - .rodata_addr = 0x080079c0, - .rodata_len = 0xb0, + .rodata_addr = 0x0800786c, + .rodata_len = 0xf0, .rodata_index = 0x0, .rodata = bnx2_RXP_b09FwRodata, }; static u8 bnx2_xi_rv2p_proc1[] = { - /* Date: 04/25/2008 22:02 */ - 0xbd, 0x56, 0x4f, 0x68, 0x1c, 0x55, 0x18, 0xff, 0x76, 0x76, 0x77, 0x66, - 0x33, 0x3b, 0xbb, 0xb3, 0xd8, 0x34, 0x4c, 0xb7, 0x2b, 0x59, 0x83, 0x97, - 0xdd, 0x6c, 0x69, 0xa2, 0x15, 0x04, 0x53, 0x5a, 0x72, 0x09, 0xd8, 0x9e, - 0x02, 0xb5, 0x52, 0x84, 0xb6, 0x8b, 0xf4, 0x52, 0x5a, 0x28, 0x78, 0x11, - 0x84, 0x0e, 0x6d, 0x93, 0x82, 0xe8, 0x61, 0xc1, 0x06, 0x12, 0x44, 0xa3, - 0x07, 0x95, 0x60, 0x61, 0x07, 0x3c, 0x78, 0x10, 0x14, 0x15, 0x11, 0x6c, - 0x0f, 0x85, 0x88, 0xf6, 0xd2, 0x54, 0x4b, 0x0b, 0x1e, 0x5b, 0x3c, 0xd6, - 0x8c, 0xef, 0xfb, 0xf3, 0x92, 0x99, 0x97, 0x9d, 0x24, 0xa7, 0x2e, 0xb4, - 0x3f, 0xbe, 0x37, 0xdf, 0xbf, 0xf7, 0xfd, 0xf9, 0xbd, 0xd4, 0x00, 0xc0, - 0x82, 0x30, 0x1a, 0x55, 0x08, 0x65, 0x2b, 0x5f, 0x52, 0x90, 0x03, 0xf8, - 0x1a, 0xf8, 0x57, 0xf4, 0x48, 0x0e, 0x0f, 0x8a, 0x3c, 0xce, 0x10, 0x8e, - 0xd7, 0xd4, 0xff, 0x17, 0xe0, 0x48, 0x13, 0x31, 0x0f, 0x47, 0x5e, 0x40, - 0x3c, 0x0c, 0xdf, 0x37, 0x03, 0x85, 0xff, 0xc5, 0x10, 0xa2, 0x3c, 0xdc, - 0xff, 0x36, 0x2a, 0x93, 0xff, 0x35, 0xb1, 0xff, 0x33, 0xcf, 0xf8, 0x6a, - 0xa7, 0xc4, 0x7e, 0x04, 0xe1, 0x40, 0x8d, 0x60, 0xb5, 0x87, 0xf2, 0x89, - 0x13, 0x60, 0xa3, 0x9f, 0x4f, 0x94, 0x02, 0xca, 0x8d, 0x5c, 0x78, 0x40, - 0xf2, 0xb2, 0x58, 0xef, 0x5e, 0xcf, 0xc7, 0x73, 0xb8, 0x3f, 0x8d, 0xf2, - 0x3e, 0xf7, 0x5a, 0x0f, 0x31, 0x80, 0x73, 0x25, 0x8f, 0xef, 0x33, 0xca, - 0x6e, 0xd7, 0xda, 0x68, 0xa7, 0x74, 0xdb, 0xe2, 0xb7, 0x88, 0x7e, 0xff, - 0x89, 0xd9, 0x2f, 0xfa, 0x4b, 0xfa, 0x69, 0x28, 0x3f, 0x78, 0x6e, 0x4b, - 0x5e, 0xb6, 0x91, 0x97, 0xad, 0xf2, 0x90, 0x3a, 0x80, 0xce, 0x03, 0x71, - 0xaf, 0x8a, 0x8b, 0x7e, 0x1f, 0xcb, 0xbd, 0x01, 0x4e, 0x37, 0xc5, 0x7f, - 0x84, 0xe8, 0xe5, 0xd8, 0x9f, 0xfa, 0x27, 0xf7, 0xd8, 0xea, 0x47, 0xd7, - 0x29, 0x9d, 0xbf, 0xd3, 0xd1, 0xdf, 0x75, 0x3f, 0x30, 0xce, 0x1d, 0x15, - 0x27, 0xa9, 0x0f, 0x3b, 0xe8, 0xff, 0xa6, 0xf4, 0xd3, 0x7e, 0xf9, 0xfc, - 0xd7, 0xcd, 0xf3, 0xd6, 0xa0, 0xba, 0x15, 0x8d, 0xba, 0xfd, 0x28, 0x75, - 0x9b, 0x81, 0x17, 0xad, 0x80, 0xf4, 0x0a, 0x80, 0xb8, 0x5f, 0x25, 0x80, - 0xf8, 0xbc, 0xe0, 0x45, 0xc1, 0xcf, 0x04, 0x97, 0x05, 0xf7, 0x0a, 0x0e, - 0x0b, 0xee, 0x11, 0x7c, 0x4e, 0xf0, 0x6f, 0xc1, 0x9a, 0xa0, 0x2f, 0x58, - 0x15, 0xbc, 0x27, 0xe8, 0x09, 0x96, 0x0d, 0x7f, 0x75, 0xc1, 0x92, 0x60, - 0x24, 0xf8, 0x9a, 0x61, 0xef, 0xe6, 0x18, 0x57, 0x45, 0x3e, 0x28, 0xf2, - 0x49, 0x91, 0xb1, 0xa0, 0x32, 0xf7, 0xa9, 0x7a, 0x7d, 0xbe, 0xd1, 0xdf, - 0xd5, 0x9e, 0x7c, 0x6f, 0x69, 0xbd, 0x12, 0xd5, 0x0f, 0xda, 0x49, 0xfd, - 0x8f, 0xb7, 0xd1, 0x67, 0xb5, 0xe9, 0xd6, 0x20, 0xbb, 0x1b, 0x31, 0xe7, - 0xf1, 0x91, 0xd8, 0x07, 0xfd, 0xef, 0x32, 0xf6, 0x68, 0xaa, 0x63, 0xce, - 0xd7, 0xa0, 0x3d, 0x7a, 0x45, 0xf6, 0xe8, 0xd0, 0x96, 0xf9, 0xe5, 0x39, - 0x3d, 0x2a, 0xf6, 0x53, 0x32, 0x9f, 0x8d, 0x0c, 0xbd, 0x30, 0xb1, 0xaf, - 0x14, 0x2f, 0x63, 0x1f, 0x6e, 0xe6, 0xba, 0x1d, 0x8c, 0x5b, 0x94, 0xb8, - 0x59, 0xf9, 0xa1, 0xbd, 0xcc, 0x6f, 0x4b, 0xcf, 0x71, 0x7a, 0x7e, 0x79, - 0x0e, 0x6d, 0x63, 0x0e, 0x2f, 0xed, 0xd0, 0x87, 0xb2, 0x51, 0xcf, 0xf3, - 0x4a, 0x9f, 0x45, 0xcb, 0x62, 0x5c, 0x62, 0xec, 0x78, 0x76, 0x01, 0xf1, - 0x90, 0xf7, 0x0b, 0xfb, 0x1b, 0xa5, 0x7b, 0x78, 0xc1, 0x02, 0xed, 0x6d, - 0x01, 0x16, 0xec, 0x21, 0x85, 0x4f, 0xe3, 0x0f, 0x59, 0xaf, 0x5e, 0xbc, - 0x4d, 0x18, 0x2c, 0xdd, 0x62, 0xfd, 0x3f, 0x9a, 0x9c, 0xf7, 0x1b, 0xe3, - 0x60, 0xfc, 0xf4, 0x77, 0xd9, 0x77, 0x1f, 0xe5, 0x7f, 0x73, 0x61, 0xa4, - 0xe3, 0x88, 0xdd, 0x79, 0xbd, 0x47, 0xfc, 0xbb, 0x62, 0xd7, 0xa8, 0x6e, - 0xef, 0x47, 0x24, 0x0e, 0x7b, 0xf3, 0xcc, 0xaf, 0x1f, 0x44, 0xfa, 0x3e, - 0xc2, 0x2b, 0x6d, 0xb6, 0xab, 0x50, 0x9c, 0x3d, 0xfd, 0x65, 0x63, 0x3e, - 0x9a, 0xbb, 0xe2, 0xd7, 0x27, 0xf1, 0x26, 0xbf, 0x26, 0xef, 0xaf, 0xf9, - 0xb5, 0x04, 0x67, 0x66, 0x7c, 0x8a, 0x57, 0xb5, 0xd9, 0xcd, 0x9b, 0x3e, - 0xe3, 0xdb, 0x2e, 0xe3, 0x43, 0x17, 0xeb, 0x13, 0xc7, 0xe7, 0xca, 0x2c, - 0x9f, 0xad, 0xe8, 0xbd, 0xd6, 0xf6, 0x3a, 0xaf, 0xed, 0xf2, 0xc1, 0xf8, - 0x3a, 0x8e, 0xce, 0x43, 0xc7, 0x4b, 0xcf, 0x43, 0x76, 0x5c, 0xc6, 0xae, - 0x95, 0xae, 0xc3, 0xd2, 0x04, 0x63, 0x61, 0x12, 0xf3, 0xfa, 0x21, 0xde, - 0xd8, 0xeb, 0x56, 0x8d, 0xf4, 0xc6, 0x80, 0xe5, 0x59, 0x99, 0xbf, 0x59, - 0xda, 0x47, 0xc5, 0x37, 0x16, 0x62, 0x1d, 0x42, 0x7a, 0x6f, 0x2c, 0xf7, - 0x67, 0x9a, 0x87, 0xbc, 0x9c, 0xab, 0xfa, 0x8f, 0xa5, 0xf7, 0x78, 0x8d, - 0xe7, 0xad, 0x94, 0x9e, 0xd3, 0x46, 0x3c, 0x78, 0xfe, 0xdd, 0xfe, 0x72, - 0x6f, 0x50, 0x3f, 0x74, 0x7e, 0x01, 0x74, 0x27, 0xb3, 0xde, 0x09, 0xfd, - 0x3e, 0x6b, 0x9e, 0xa4, 0xe3, 0x7e, 0x98, 0x4f, 0xdd, 0xfb, 0x28, 0x74, - 0x06, 0xf9, 0xff, 0x46, 0xbf, 0x7b, 0x03, 0xf6, 0x76, 0xa7, 0xb8, 0x29, - 0xff, 0x55, 0xb5, 0x39, 0xb0, 0x75, 0xef, 0x1c, 0x63, 0x4f, 0x9f, 0xae, - 0xf3, 0x9e, 0x36, 0xb6, 0xcc, 0xa7, 0xe6, 0xaf, 0xe6, 0xb6, 0xfc, 0xf5, - 0xac, 0xf8, 0xca, 0x02, 0xe6, 0x2b, 0x7c, 0x4f, 0xd2, 0x79, 0x3a, 0xfa, - 0x9e, 0x06, 0x2f, 0xf1, 0xfd, 0xee, 0xaf, 0xef, 0x8e, 0xdf, 0x92, 0x75, - 0x1a, 0xc4, 0x6f, 0xae, 0xc1, 0x57, 0xbf, 0xaf, 0x6f, 0xf2, 0x1b, 0x7e, - 0x5f, 0x59, 0xe1, 0xfe, 0xbd, 0x97, 0x98, 0xdf, 0x64, 0xdd, 0x87, 0xa4, - 0xee, 0x4a, 0x8f, 0xec, 0x6f, 0x1b, 0xf6, 0xba, 0xff, 0xef, 0x08, 0x6f, - 0x5a, 0x53, 0x3c, 0x7f, 0x4e, 0xf7, 0x91, 0xd1, 0x97, 0xc9, 0x0e, 0xee, - 0xd5, 0x65, 0x88, 0xa4, 0x6e, 0x77, 0x53, 0xf5, 0xab, 0x08, 0x4f, 0x38, - 0xf0, 0x55, 0xa4, 0xeb, 0xac, 0xfb, 0xc8, 0xf8, 0x25, 0xe9, 0xd7, 0x76, - 0xa8, 0x77, 0x0d, 0xbe, 0xd8, 0xe0, 0x41, 0x9f, 0xfc, 0x4d, 0x08, 0xaf, - 0x9c, 0x91, 0xfd, 0xfe, 0xcb, 0x65, 0xfe, 0xe8, 0x1e, 0xa3, 0x3d, 0x87, - 0x11, 0xd9, 0xf3, 0x6e, 0x85, 0xe5, 0x7a, 0x85, 0x79, 0x71, 0xc2, 0xf1, - 0x48, 0xaf, 0x5e, 0x61, 0x1c, 0x29, 0xa3, 0x5d, 0x00, 0x0f, 0x8e, 0x93, - 0x7a, 0x67, 0xd1, 0x63, 0x7e, 0x5f, 0xbc, 0x25, 0xfc, 0xe3, 0xeb, 0xfa, - 0xc9, 0x7d, 0x5f, 0xc6, 0xf3, 0x11, 0xb5, 0xcf, 0xc9, 0x7e, 0x28, 0x9d, - 0x36, 0xe7, 0xf7, 0xa9, 0x64, 0xdf, 0xf4, 0x93, 0xf5, 0xd6, 0xf3, 0xbd, - 0x9c, 0xd1, 0xa7, 0x99, 0x58, 0xf3, 0xdf, 0xd8, 0x0c, 0xe6, 0xeb, 0x43, - 0xd5, 0xe1, 0xf9, 0x60, 0x54, 0x7e, 0x2c, 0x07, 0xcd, 0x1a, 0x73, 0xc2, - 0x27, 0x73, 0x57, 0xc8, 0xcd, 0xf1, 0x39, 0x7d, 0x3e, 0x4d, 0x0b, 0x32, - 0xbb, 0xf2, 0x13, 0x9d, 0x57, 0xa3, 0x3c, 0x9f, 0x3b, 0xc7, 0x74, 0xbd, - 0x7c, 0xba, 0xff, 0x02, 0xd7, 0xeb, 0xad, 0x1b, 0x8c, 0xa7, 0xe0, 0x75, - 0x42, 0x77, 0xc1, 0x63, 0x7e, 0x5c, 0xf4, 0x4a, 0x84, 0x40, 0xf5, 0xb2, - 0x5e, 0xe2, 0x77, 0xad, 0x28, 0xef, 0xd1, 0x50, 0xa2, 0x8f, 0xe6, 0xfb, - 0xb1, 0xdb, 0x7e, 0x26, 0xf9, 0x54, 0xbf, 0x6b, 0x39, 0xe3, 0xef, 0xc8, - 0x8a, 0x31, 0x9f, 0xef, 0x66, 0xcc, 0x67, 0x33, 0x63, 0xbe, 0x4d, 0x5e, - 0xb9, 0x24, 0x7b, 0x57, 0x80, 0x62, 0x9e, 0x1e, 0x26, 0xaf, 0x70, 0x95, - 0xfa, 0x6b, 0xcd, 0xf1, 0xbb, 0xee, 0x15, 0xe7, 0x73, 0x54, 0x37, 0x6f, - 0x9e, 0xf5, 0x0a, 0x7c, 0x1e, 0x68, 0xbc, 0x7e, 0x95, 0xdf, 0x4f, 0x0b, - 0xfe, 0x07, 0x89, 0x6e, 0x1e, 0x13, 0x00, 0x0d, 0x00, 0x00, 0x00 }; + /* Date: 06/17/2008 16:52 */ + 0xbd, 0x56, 0xcf, 0x6b, 0x1c, 0x75, 0x14, 0x7f, 0x3b, 0xbb, 0x33, 0x3b, + 0x99, 0x9d, 0xdd, 0x99, 0xda, 0x34, 0x4c, 0xb7, 0x2b, 0xd9, 0x86, 0x5e, + 0x36, 0x99, 0x62, 0xa2, 0x11, 0x0a, 0x46, 0x5b, 0x72, 0x09, 0xd8, 0x9e, + 0x02, 0x95, 0x22, 0x82, 0x71, 0xa9, 0x3d, 0xd8, 0x96, 0xe2, 0x5f, 0xe0, + 0x90, 0x9a, 0x08, 0x45, 0x0f, 0x0b, 0x36, 0x90, 0x20, 0x1a, 0x7b, 0x50, + 0x09, 0x0a, 0x3b, 0x07, 0x41, 0x44, 0x2d, 0xa8, 0x88, 0x60, 0x3d, 0x08, + 0x85, 0xda, 0x8b, 0x51, 0x8b, 0x8a, 0x07, 0x0f, 0x01, 0x8f, 0x9a, 0xf1, + 0xfb, 0x7e, 0x7c, 0x37, 0x33, 0x93, 0xdd, 0x24, 0x27, 0x03, 0xed, 0x87, + 0xf7, 0x9d, 0xf7, 0x7d, 0xdf, 0xf7, 0xde, 0xf7, 0xf3, 0x3e, 0xdf, 0xf5, + 0x01, 0xc0, 0x80, 0x28, 0x1e, 0x55, 0x08, 0x87, 0x8c, 0xa2, 0xad, 0xa0, + 0x00, 0xf0, 0x21, 0xf0, 0x9f, 0xe9, 0x92, 0x1d, 0x3d, 0x22, 0xf6, 0x04, + 0x43, 0x34, 0xe1, 0xab, 0xff, 0xaf, 0xc2, 0xe9, 0x26, 0x62, 0x11, 0x4e, + 0x1f, 0x47, 0x7c, 0x12, 0x6e, 0x37, 0x03, 0x85, 0xff, 0x26, 0x10, 0xa1, + 0x3d, 0xdc, 0xfd, 0x24, 0xae, 0x50, 0xfc, 0x4d, 0xd9, 0xff, 0x63, 0x91, + 0xf1, 0x54, 0x68, 0x73, 0x1c, 0x41, 0x38, 0xe9, 0x13, 0xdc, 0xed, 0xa0, + 0x7d, 0xfe, 0x3c, 0x58, 0x18, 0xe7, 0x6d, 0xe5, 0x80, 0x76, 0xa3, 0x10, + 0x9d, 0x94, 0xbc, 0x0c, 0xf6, 0xfb, 0xa9, 0xe3, 0xe1, 0x3a, 0xfc, 0x3c, + 0x8b, 0xf6, 0x51, 0xe7, 0xd5, 0x0e, 0x62, 0x00, 0x97, 0x6c, 0x97, 0xeb, + 0x19, 0xe5, 0xb0, 0x9b, 0xe3, 0xb8, 0x4f, 0xf9, 0x8e, 0x4b, 0x5c, 0x13, + 0xe3, 0xfe, 0x99, 0x70, 0x5c, 0x8c, 0x97, 0x8e, 0xd3, 0x50, 0x71, 0x70, + 0xdd, 0x92, 0xbc, 0xac, 0x5c, 0x5e, 0x96, 0xca, 0x43, 0xfa, 0x00, 0x3a, + 0x0f, 0xc4, 0x23, 0xea, 0x5c, 0x8c, 0xbb, 0x25, 0x75, 0x03, 0x3c, 0xdf, + 0x94, 0xf8, 0x31, 0xa2, 0x5b, 0xe0, 0x78, 0xea, 0x9f, 0xd4, 0xb1, 0x3b, + 0x8e, 0xee, 0x53, 0x36, 0xff, 0x72, 0xa8, 0xbf, 0xeb, 0xfb, 0xc0, 0x73, + 0x7e, 0x50, 0xe7, 0xa4, 0xfd, 0x61, 0x1f, 0xff, 0xef, 0x94, 0x7f, 0x36, + 0x2e, 0xaf, 0x7f, 0xbb, 0xb3, 0xde, 0xea, 0xd7, 0x37, 0x33, 0xd7, 0xb7, + 0x2f, 0xa5, 0x6f, 0x73, 0x70, 0xc2, 0x08, 0xc8, 0xaf, 0x04, 0x88, 0xc7, + 0x54, 0x02, 0x88, 0x0f, 0x0b, 0x5e, 0x13, 0xbc, 0x25, 0xf8, 0xae, 0xe0, + 0x11, 0xc1, 0x61, 0xc1, 0xc3, 0x82, 0x0f, 0x09, 0x6e, 0x09, 0xfa, 0x82, + 0x9e, 0x60, 0x4d, 0xf0, 0x2f, 0x41, 0x57, 0xb0, 0x92, 0x8b, 0x57, 0x17, + 0xb4, 0x05, 0x3f, 0x17, 0x7c, 0x22, 0xb7, 0xff, 0x68, 0x81, 0xf1, 0x81, + 0xd8, 0x4f, 0x89, 0x7d, 0x41, 0x6c, 0x6c, 0xa8, 0xf0, 0x3e, 0xd3, 0xaf, + 0x5b, 0xbd, 0xfb, 0xbd, 0xdb, 0x91, 0xef, 0x2d, 0xed, 0x67, 0x53, 0xff, + 0x60, 0x3c, 0xed, 0xff, 0xd6, 0x1e, 0xfe, 0xec, 0x36, 0xdb, 0xea, 0xb7, + 0xef, 0x66, 0xc2, 0x79, 0xbc, 0x29, 0xfb, 0x83, 0xee, 0x67, 0x03, 0xe6, + 0x68, 0x26, 0xcc, 0xf3, 0xab, 0xdf, 0x1c, 0x3d, 0x2e, 0x73, 0x34, 0xbd, + 0x8b, 0xbf, 0xcc, 0xd3, 0x33, 0xb2, 0x7f, 0x46, 0xf8, 0xd9, 0x18, 0xe0, + 0x17, 0xa5, 0xe6, 0x95, 0xce, 0x1b, 0x30, 0x0f, 0x1f, 0x15, 0xda, 0x61, + 0xc0, 0xfc, 0x89, 0xf6, 0xca, 0x0f, 0xf7, 0x0b, 0x7f, 0x5b, 0x9a, 0xc7, + 0x59, 0xfe, 0x32, 0x0f, 0xad, 0x1c, 0x0f, 0x5f, 0xde, 0xe7, 0x1e, 0x2a, + 0xb9, 0x7e, 0x5e, 0x56, 0xfe, 0x6c, 0x1a, 0x06, 0xe3, 0x1a, 0x63, 0xe8, + 0x5a, 0x25, 0xc4, 0x69, 0xf7, 0x1b, 0x8e, 0x37, 0x4a, 0x75, 0xb8, 0xc1, + 0x0a, 0xcd, 0x6d, 0x09, 0x56, 0xac, 0x21, 0x85, 0xff, 0x24, 0x6f, 0xb0, + 0x5f, 0xdd, 0xfc, 0x9e, 0x30, 0x58, 0xbb, 0xc3, 0xfe, 0xf7, 0x9a, 0x9c, + 0xf7, 0x33, 0x13, 0x90, 0xfb, 0xd3, 0xdf, 0x65, 0xde, 0x3d, 0xb4, 0xff, + 0x2e, 0x44, 0xb1, 0x3e, 0x47, 0xf6, 0x5d, 0xd6, 0x73, 0xc4, 0x7f, 0x8b, + 0x96, 0x4f, 0xf5, 0xde, 0x88, 0xc9, 0x1c, 0x76, 0x97, 0x7d, 0xfa, 0xfa, + 0x7a, 0xac, 0xeb, 0x11, 0x5d, 0x19, 0xd7, 0xf5, 0xf3, 0xfe, 0x2a, 0x9d, + 0x77, 0xb8, 0xbb, 0x9e, 0xe3, 0x49, 0xf3, 0x40, 0x3a, 0xbb, 0x95, 0xec, + 0xe8, 0x6c, 0xba, 0x0f, 0x5a, 0x67, 0x6d, 0x58, 0x98, 0xf3, 0xe8, 0xdc, + 0x9a, 0xc5, 0x61, 0x2e, 0x78, 0x8c, 0x17, 0x1d, 0xc6, 0xdf, 0x1c, 0xec, + 0x53, 0x92, 0x5c, 0xaa, 0xb0, 0xfd, 0x42, 0x55, 0xcf, 0xb7, 0xde, 0xaf, + 0xf3, 0xda, 0x2b, 0x1f, 0x3c, 0x5f, 0x9f, 0xa3, 0xf3, 0xd0, 0xe7, 0x65, + 0x79, 0x31, 0xf8, 0x5c, 0xc6, 0xb6, 0x91, 0xed, 0xc3, 0xda, 0x24, 0x63, + 0x69, 0x0a, 0xf3, 0xba, 0x9d, 0xf4, 0xe6, 0xbb, 0xe5, 0x93, 0xdf, 0x18, + 0xb0, 0x3d, 0x2f, 0x3c, 0x9c, 0xa7, 0xb9, 0x54, 0xba, 0x63, 0x20, 0xd6, + 0x21, 0xa2, 0x77, 0xc7, 0x70, 0xbe, 0x26, 0x5e, 0x14, 0x65, 0x5d, 0xdd, + 0xc3, 0x58, 0x76, 0x9e, 0x37, 0x99, 0x77, 0x76, 0x96, 0xaf, 0xc7, 0x84, + 0xaf, 0x4e, 0x77, 0xbd, 0xb3, 0xdf, 0x3c, 0x48, 0xc1, 0xbd, 0xfe, 0x6b, + 0x3d, 0xd4, 0xef, 0xb2, 0xd6, 0x3d, 0xfa, 0xdc, 0x8d, 0x8a, 0x99, 0x3a, + 0xcf, 0x40, 0xd8, 0xef, 0x7e, 0x3f, 0x16, 0x3d, 0x99, 0x16, 0x7d, 0x53, + 0x97, 0x18, 0x65, 0xf6, 0xd5, 0x80, 0xf2, 0x29, 0xe7, 0xe6, 0xac, 0xd4, + 0x9b, 0x9b, 0x45, 0x6b, 0x80, 0xde, 0x99, 0xfc, 0x7e, 0x2e, 0xcc, 0xe1, + 0xb9, 0x76, 0xe3, 0x06, 0xcd, 0x7f, 0x19, 0xfe, 0x70, 0xf9, 0x5e, 0xda, + 0x26, 0xda, 0xe6, 0xf0, 0x95, 0x4f, 0x33, 0xfd, 0x01, 0x38, 0xae, 0xdf, + 0x97, 0xf4, 0x1c, 0x07, 0xd0, 0x9e, 0x3a, 0xe8, 0x7b, 0x99, 0xe6, 0x7d, + 0x6d, 0x17, 0xef, 0xb5, 0x3e, 0x36, 0xc3, 0xf4, 0x9c, 0xe0, 0x3b, 0xc1, + 0xf7, 0xcd, 0xfa, 0x54, 0xc9, 0xf7, 0x41, 0xbd, 0x9f, 0xba, 0xbe, 0x7e, + 0xef, 0xe8, 0xaf, 0xdb, 0x07, 0xd3, 0xb3, 0x74, 0x9f, 0xfa, 0xe9, 0x99, + 0x93, 0xd3, 0xa7, 0x7b, 0xdb, 0x3d, 0x7d, 0x32, 0xfb, 0xd5, 0xff, 0x7f, + 0xe8, 0x36, 0xf7, 0xd3, 0x81, 0x74, 0x3d, 0x1b, 0x1b, 0xcc, 0x9f, 0xab, + 0xa9, 0x79, 0x49, 0xdf, 0xff, 0x90, 0xf0, 0x45, 0xf9, 0x51, 0x1d, 0x5f, + 0x6c, 0xef, 0xe8, 0x72, 0x9a, 0x7f, 0x2f, 0x0a, 0xff, 0x8d, 0x99, 0x75, + 0xe6, 0x47, 0xfb, 0xf7, 0xdc, 0x7d, 0x4d, 0x85, 0xc8, 0x97, 0x57, 0x20, + 0x96, 0x3c, 0xef, 0x67, 0xf2, 0xad, 0x8a, 0x2e, 0x95, 0xe1, 0x83, 0x58, + 0xd7, 0xc5, 0x9f, 0x9b, 0x21, 0xe3, 0xfb, 0xe4, 0xef, 0xef, 0xf3, 0x2e, + 0xf9, 0xf0, 0x5e, 0x4f, 0x7f, 0x3d, 0x8a, 0x37, 0x29, 0x3a, 0xb6, 0x20, + 0x7a, 0xf2, 0x8b, 0xc3, 0x7a, 0xd5, 0x3e, 0x4b, 0xfc, 0x85, 0x11, 0xd1, + 0x95, 0x76, 0x95, 0xed, 0x7a, 0x95, 0x7f, 0xef, 0x4e, 0x96, 0x5d, 0xf2, + 0xab, 0x57, 0x19, 0x47, 0x2a, 0xb8, 0x2f, 0x80, 0x07, 0xe7, 0xc8, 0x3d, + 0x5c, 0x75, 0xf9, 0x5d, 0x59, 0xbd, 0x23, 0x7a, 0xe7, 0xe9, 0xfe, 0x49, + 0xbd, 0x8f, 0xe1, 0xfa, 0x88, 0xd2, 0x0f, 0xb6, 0x99, 0x17, 0x6e, 0x6f, + 0x1e, 0xde, 0x91, 0xec, 0x9b, 0x5e, 0xba, 0xdf, 0x7a, 0x2e, 0x3b, 0xb9, + 0x3e, 0xeb, 0x7b, 0x3a, 0x95, 0x68, 0xbd, 0x1d, 0x9b, 0xc3, 0x7c, 0x3d, + 0xa8, 0x95, 0x99, 0x47, 0x8c, 0x2a, 0x8e, 0x51, 0xc6, 0x6d, 0x8d, 0x25, + 0xd1, 0xaf, 0xa5, 0x45, 0x0a, 0x73, 0x6e, 0x49, 0xaf, 0xcf, 0xd2, 0xe0, + 0xcc, 0x6f, 0x7c, 0x45, 0xeb, 0xb5, 0xb8, 0xc8, 0xeb, 0xe5, 0xb3, 0xba, + 0x5f, 0x1e, 0xd5, 0xbf, 0xc2, 0xfd, 0x7a, 0xee, 0x26, 0xe3, 0xb3, 0xf0, + 0x34, 0xa1, 0xb3, 0x22, 0x73, 0xbf, 0xea, 0xda, 0x84, 0x40, 0xfd, 0x32, + 0x1e, 0xe5, 0xf7, 0xd4, 0x94, 0x77, 0x70, 0x28, 0x75, 0x8f, 0xf9, 0xf7, + 0xea, 0xa0, 0xf7, 0x99, 0xd6, 0x6f, 0xfd, 0x9e, 0x16, 0x72, 0xbf, 0x5f, + 0xab, 0x39, 0x7e, 0xbe, 0x34, 0x80, 0x9f, 0x87, 0x06, 0xf0, 0x3b, 0xaf, + 0x87, 0x6d, 0x99, 0xff, 0x12, 0x98, 0x45, 0x7a, 0x08, 0xdd, 0xd2, 0x75, + 0xba, 0x5f, 0x63, 0x89, 0x7f, 0x4f, 0xb8, 0xe6, 0x72, 0x81, 0xfa, 0xe6, + 0x2e, 0xb3, 0x5f, 0x89, 0xd7, 0x03, 0x8d, 0xaf, 0x5d, 0xe7, 0x39, 0x33, + 0xe0, 0x3f, 0xdd, 0xd1, 0x99, 0x07, 0x78, 0x0d, 0x00, 0x00, 0x00 }; static u8 bnx2_xi_rv2p_proc2[] = { - /* Date: 04/25/2008 22:02 */ + /* Date: 06/17/2008 16:52 */ #define XI_RV2P_PROC2_MAX_BD_PAGE_LOC 5 #define XI_RV2P_PROC2_BD_PAGE_SIZE_MSK 0xffff -#define XI_RV2P_PROC2_BD_PAGE_SIZE ((PAGE_SIZE / 16) - 1) - 0xad, 0x58, 0x5b, 0x6c, 0x54, 0x55, 0x14, 0x3d, 0xf3, 0xe8, 0xcc, 0xed, - 0xcc, 0x9d, 0x99, 0xd2, 0xd6, 0xe9, 0x8b, 0x48, 0x69, 0xa5, 0x74, 0x70, - 0x0a, 0x65, 0x5a, 0x1e, 0x3e, 0x12, 0x49, 0xd1, 0x02, 0x3e, 0x42, 0xa9, - 0x86, 0x98, 0x18, 0x03, 0x9d, 0x4a, 0xe9, 0x40, 0x4b, 0x2a, 0x25, 0x7c, - 0xf0, 0xe3, 0x84, 0x62, 0xf9, 0x99, 0x44, 0x4b, 0x80, 0x16, 0x63, 0x48, - 0x23, 0x3f, 0xc4, 0xbf, 0x26, 0x28, 0x45, 0x3f, 0x4c, 0x88, 0x36, 0x04, - 0x3e, 0xc0, 0x44, 0x63, 0xfc, 0x21, 0x12, 0xc4, 0x5a, 0xa0, 0xc1, 0x82, - 0x36, 0xc6, 0x48, 0xeb, 0x3d, 0x7b, 0xed, 0x73, 0xe7, 0xde, 0xe9, 0x2d, - 0x8f, 0x48, 0x3f, 0x58, 0x9c, 0x73, 0xf7, 0x39, 0x67, 0xef, 0xb5, 0x1f, - 0x67, 0x9f, 0x29, 0x10, 0x42, 0x78, 0x45, 0x7a, 0x64, 0x91, 0x81, 0x22, - 0xe8, 0xf6, 0x68, 0x06, 0xcc, 0x0a, 0x91, 0x57, 0x2a, 0xc7, 0xc2, 0x2d, - 0xf8, 0x6f, 0x59, 0x01, 0xc1, 0x0f, 0x23, 0xf2, 0xbb, 0x5f, 0xbc, 0xe5, - 0xc6, 0x77, 0xaf, 0x90, 0x18, 0x11, 0x22, 0x2d, 0xb1, 0x80, 0x31, 0xc6, - 0xe8, 0x72, 0x01, 0x4b, 0x18, 0x5f, 0x61, 0x14, 0x8c, 0xba, 0x1b, 0xe8, - 0x66, 0xf4, 0xaa, 0x79, 0x5e, 0xaf, 0xf1, 0x7c, 0x3b, 0xe3, 0x76, 0x9e, - 0xff, 0xdd, 0x40, 0xa5, 0x97, 0x1c, 0x4f, 0xce, 0x8a, 0xb4, 0x8e, 0x6d, - 0x63, 0x6a, 0x5e, 0x27, 0x48, 0xc7, 0xa0, 0xf7, 0x9b, 0x95, 0xb4, 0xce, - 0x41, 0x4e, 0xce, 0xdf, 0x98, 0x55, 0xfb, 0x1d, 0xf4, 0xc8, 0xf1, 0x2f, - 0xc6, 0xd8, 0x25, 0x87, 0xc5, 0x51, 0x6c, 0x53, 0x5c, 0x9a, 0x91, 0xfb, - 0x78, 0xc4, 0xd0, 0x80, 0x46, 0xac, 0x1c, 0xd7, 0x31, 0x4e, 0x13, 0x1f, - 0x2e, 0x63, 0xcc, 0xfb, 0x31, 0x96, 0x85, 0x70, 0xee, 0xd6, 0x4a, 0x9c, - 0xf7, 0xd3, 0xb3, 0x90, 0x4b, 0x47, 0x14, 0xa1, 0xf8, 0xbe, 0x48, 0xf0, - 0xf7, 0xdd, 0x72, 0x3c, 0xe5, 0x2a, 0x72, 0x81, 0x57, 0xbf, 0x50, 0x7a, - 0x42, 0xee, 0xea, 0x40, 0xae, 0x3c, 0x0d, 0x3f, 0x4f, 0xaf, 0x50, 0x76, - 0x00, 0xda, 0x42, 0xc0, 0xa4, 0x07, 0xb8, 0x2e, 0x4e, 0x90, 0x69, 0x67, - 0x47, 0x36, 0xd7, 0x48, 0x3d, 0x0a, 0x85, 0xd7, 0x2d, 0xf7, 0x5b, 0xa1, - 0xf9, 0xce, 0x61, 0xfe, 0x6d, 0xd6, 0xeb, 0xbd, 0x00, 0xf0, 0x46, 0x20, - 0xdf, 0xf8, 0x77, 0x76, 0xb6, 0x23, 0x68, 0xb7, 0x2b, 0x1d, 0xc4, 0xfa, - 0x31, 0xdd, 0xc9, 0x3e, 0xcf, 0x03, 0xec, 0xc3, 0xba, 0x05, 0x4b, 0xf1, - 0xf5, 0xe3, 0x0e, 0x8c, 0x2b, 0x4e, 0x49, 0x39, 0x9f, 0x18, 0x1a, 0x71, - 0xe2, 0x23, 0x77, 0x7f, 0x23, 0x4e, 0x23, 0x38, 0x47, 0x54, 0x69, 0xa4, - 0x54, 0x3a, 0x0e, 0x14, 0x75, 0x8e, 0xfc, 0x88, 0xe3, 0x4b, 0xe4, 0xbc, - 0x5b, 0xb4, 0x7a, 0x74, 0x3a, 0xa7, 0x35, 0xa5, 0xe2, 0x02, 0xdf, 0x3b, - 0x7c, 0x04, 0xa5, 0x6d, 0xfd, 0xd2, 0xde, 0x88, 0xd8, 0xee, 0x8e, 0x90, - 0x3c, 0xf8, 0xf1, 0x68, 0xfa, 0x97, 0x90, 0xff, 0x66, 0x91, 0x4e, 0x36, - 0x75, 0x34, 0x60, 0x5d, 0x71, 0x02, 0x78, 0x2c, 0x91, 0x27, 0x21, 0xde, - 0xd1, 0x4b, 0xc3, 0xe5, 0xd7, 0x57, 0x6a, 0x24, 0x97, 0xae, 0x53, 0x71, - 0xa7, 0xfc, 0x27, 0xfd, 0x3a, 0x64, 0xc6, 0x99, 0xa8, 0x06, 0xbf, 0xbf, - 0x2d, 0x91, 0xf2, 0x06, 0xc9, 0x55, 0x38, 0x27, 0xab, 0x9f, 0x35, 0x6e, - 0x07, 0x2c, 0x71, 0xfb, 0x78, 0xf1, 0xb0, 0x8e, 0xf8, 0x59, 0xc7, 0x3c, - 0x55, 0x1a, 0x3c, 0x49, 0x5c, 0xe8, 0x4a, 0xd7, 0xd9, 0xfd, 0x74, 0x75, - 0x20, 0x42, 0xff, 0xbf, 0xd9, 0x54, 0x40, 0x3c, 0x6f, 0xc6, 0xfc, 0x91, - 0xe6, 0xb3, 0xf0, 0xd3, 0x26, 0xe2, 0x43, 0x04, 0x0e, 0x7d, 0x81, 0x55, - 0x6d, 0x14, 0xdf, 0xdd, 0x8d, 0x1d, 0x5f, 0x61, 0x9c, 0xf4, 0xc8, 0xf1, - 0x6e, 0xbd, 0x7d, 0x14, 0xf2, 0x79, 0x7d, 0xe0, 0x7d, 0x33, 0x9f, 0xb2, - 0xc9, 0x43, 0xf9, 0x94, 0xf1, 0xf5, 0xd1, 0x50, 0x1f, 0xa3, 0xef, 0x05, - 0xe2, 0xf0, 0x08, 0xbe, 0xef, 0x09, 0x4a, 0x3b, 0xdf, 0x37, 0xf3, 0x2e, - 0xe5, 0xc3, 0xfa, 0xcc, 0x00, 0xf2, 0x66, 0xe2, 0x8c, 0x1c, 0x6f, 0x8b, - 0x4f, 0x40, 0x3e, 0x9e, 0xea, 0xe7, 0x8d, 0xdd, 0xe0, 0xf1, 0xa6, 0x1b, - 0xf2, 0x1c, 0xa6, 0x01, 0x2f, 0xf9, 0xd1, 0x25, 0xf4, 0x66, 0xe0, 0x87, - 0xf4, 0xfd, 0x5f, 0x57, 0x86, 0x78, 0xdb, 0x1a, 0xf6, 0x9e, 0x55, 0xfc, - 0x30, 0x46, 0x94, 0x5d, 0xc0, 0x47, 0xcd, 0x83, 0xfe, 0x79, 0xf3, 0x80, - 0xfd, 0x19, 0x7b, 0x58, 0x1e, 0x00, 0x9b, 0x6b, 0x80, 0xbe, 0x6a, 0x29, - 0x9f, 0xff, 0x18, 0xf9, 0xc0, 0x7a, 0xcd, 0xc9, 0x37, 0xcc, 0x66, 0xe3, - 0x94, 0xc0, 0x88, 0x4f, 0x5b, 0xbc, 0x72, 0x7e, 0x2c, 0x36, 0xfc, 0xa0, - 0xe2, 0x4e, 0x6e, 0xe8, 0x17, 0xbb, 0x79, 0xdf, 0x14, 0xf3, 0xd1, 0xc5, - 0x7c, 0x4c, 0x32, 0xee, 0x09, 0x2a, 0x1e, 0x80, 0x87, 0x75, 0x9c, 0xdb, - 0x9a, 0x92, 0x7e, 0x5c, 0xeb, 0x50, 0x3f, 0x55, 0x9d, 0x84, 0x9f, 0x86, - 0xd8, 0xaf, 0x27, 0xcc, 0x7a, 0xa9, 0xf8, 0x9d, 0xaf, 0x6e, 0xda, 0xf3, - 0x29, 0xc7, 0xce, 0xcc, 0x77, 0x55, 0x58, 0x5e, 0x58, 0x0d, 0x34, 0xf9, - 0xad, 0xa1, 0x3c, 0x0e, 0x97, 0x8c, 0x2a, 0xfb, 0xa4, 0x7e, 0xb7, 0x55, - 0x1e, 0x86, 0x07, 0x0f, 0x12, 0x06, 0x0a, 0x4f, 0xc9, 0x73, 0xca, 0x1d, - 0xea, 0x8a, 0x3d, 0x9f, 0x73, 0xf9, 0xdd, 0x13, 0xa2, 0x42, 0xdb, 0x78, - 0x79, 0xdc, 0x9e, 0xb7, 0xc8, 0x4f, 0xbf, 0x19, 0xdf, 0xc5, 0xab, 0xd9, - 0x0f, 0x8c, 0xd1, 0x35, 0x72, 0xdf, 0x16, 0x3e, 0xa7, 0x9e, 0xcf, 0xd1, - 0x2d, 0x75, 0x43, 0xea, 0x59, 0x68, 0xd6, 0x0b, 0x15, 0x1f, 0xd9, 0xba, - 0xa1, 0xfc, 0x40, 0xe7, 0xc7, 0x2f, 0x8f, 0xcb, 0xf5, 0x15, 0x0f, 0xa9, - 0x23, 0x9a, 0xb9, 0xdf, 0x8f, 0x66, 0x9d, 0x90, 0xdf, 0x83, 0xe2, 0x25, - 0x1e, 0xda, 0xeb, 0xe1, 0x1f, 0x46, 0x3d, 0x24, 0x3b, 0x34, 0xfd, 0x2c, - 0xd7, 0xbf, 0x5e, 0x79, 0x4e, 0x29, 0xeb, 0x5d, 0xca, 0x7a, 0x1b, 0xd7, - 0x73, 0x1d, 0xd7, 0xc9, 0x6d, 0xd6, 0x7a, 0xf7, 0xcf, 0x4c, 0xb6, 0x6e, - 0xc9, 0xf1, 0xdf, 0x33, 0x73, 0xef, 0x5f, 0x47, 0x5e, 0xd3, 0x22, 0x82, - 0x3e, 0x23, 0x1d, 0x51, 0x7d, 0x41, 0x6e, 0xfd, 0xcb, 0xb5, 0x03, 0xbc, - 0xb4, 0xb9, 0x43, 0x24, 0x77, 0xad, 0xc7, 0xde, 0x27, 0xa0, 0x0e, 0x56, - 0xba, 0xa0, 0xf7, 0x42, 0xd6, 0xdb, 0xd8, 0xaf, 0x8e, 0xf2, 0x41, 0xbb, - 0xd6, 0x63, 0xd5, 0xfb, 0xfa, 0xcc, 0xfc, 0xe7, 0x39, 0xc7, 0x41, 0x0f, - 0xdf, 0xaf, 0x49, 0xc4, 0xb1, 0xd6, 0xfe, 0xb5, 0xd2, 0x8b, 0xcf, 0x8f, - 0x28, 0x3d, 0x74, 0xf2, 0xd3, 0x78, 0xaf, 0xdc, 0xa7, 0x48, 0x70, 0xd8, - 0x88, 0xee, 0x5a, 0xd4, 0xdf, 0xc9, 0x1d, 0xb0, 0xa3, 0xbb, 0x46, 0xea, - 0x61, 0x78, 0x25, 0x8d, 0x3c, 0x17, 0x7c, 0x1f, 0x7d, 0x3b, 0xe0, 0xe4, - 0xd7, 0x4b, 0x2c, 0x57, 0xcc, 0xf6, 0x15, 0xb0, 0x7d, 0x71, 0x91, 0x5b, - 0xe7, 0xb7, 0x55, 0xd2, 0x7d, 0xc0, 0x72, 0x2f, 0xaa, 0xfb, 0xc0, 0x90, - 0x93, 0xfb, 0xe4, 0xf1, 0x3e, 0x4e, 0x3c, 0x39, 0xed, 0x33, 0xca, 0x71, - 0xd0, 0xc9, 0x72, 0x5e, 0x87, 0x7b, 0x05, 0xa3, 0xe9, 0xa5, 0x74, 0xaf, - 0x9c, 0x3c, 0x40, 0xf7, 0x43, 0xc8, 0x8c, 0x53, 0xbb, 0x1d, 0x67, 0x9e, - 0x20, 0xef, 0x52, 0x3e, 0x2a, 0x76, 0x86, 0xe7, 0xe3, 0xd7, 0x2b, 0xa7, - 0x87, 0xa7, 0x46, 0x95, 0x7f, 0x74, 0xb2, 0x77, 0xbc, 0x57, 0xf5, 0xb1, - 0x56, 0xde, 0xdd, 0x16, 0xde, 0x21, 0xff, 0x74, 0xfc, 0xff, 0xf2, 0xed, - 0xd4, 0x1f, 0x1c, 0x9d, 0x31, 0xfb, 0x50, 0x9f, 0x53, 0xfd, 0x5f, 0x61, - 0xc6, 0xcb, 0x5e, 0xee, 0xef, 0xa6, 0x75, 0xfa, 0x4f, 0x62, 0x32, 0x43, - 0x43, 0xbd, 0xec, 0xb4, 0x94, 0x5b, 0x96, 0xd8, 0xcb, 0x76, 0x5d, 0xf4, - 0xc0, 0xee, 0xce, 0x1d, 0x18, 0x5f, 0xe6, 0x7a, 0x7d, 0x97, 0xeb, 0xe3, - 0x16, 0x0d, 0x38, 0x59, 0x4b, 0x7c, 0x24, 0xf6, 0x9e, 0x53, 0xfb, 0xd3, - 0xbe, 0xfa, 0x34, 0xf3, 0xf9, 0xb2, 0x87, 0xed, 0xac, 0x22, 0x3f, 0x26, - 0xee, 0x50, 0x3d, 0xf0, 0x8a, 0xa6, 0xc5, 0x12, 0xcb, 0x0c, 0xde, 0x58, - 0x9f, 0x17, 0x80, 0xad, 0x7e, 0xa6, 0x21, 0x96, 0xeb, 0x67, 0x4c, 0xfb, - 0xaa, 0x78, 0x7d, 0x1b, 0xc6, 0x7e, 0xae, 0x67, 0x83, 0xac, 0xd7, 0xd1, - 0x5a, 0x60, 0x38, 0x86, 0x3e, 0x61, 0x9c, 0xee, 0x85, 0x48, 0xa2, 0x77, - 0x14, 0xf6, 0x74, 0xad, 0x87, 0xbd, 0xf7, 0x98, 0x07, 0xc6, 0xf0, 0x89, - 0x3e, 0xba, 0x77, 0xc2, 0xfd, 0xe8, 0x33, 0xc2, 0xbe, 0x3e, 0xd8, 0xd1, - 0x35, 0x8d, 0xf1, 0xbd, 0xe7, 0x80, 0x7f, 0x3d, 0x8f, 0x75, 0xfb, 0x0e, - 0x30, 0x3f, 0xeb, 0x9d, 0xd7, 0x75, 0xfe, 0x09, 0xb9, 0xee, 0x5a, 0x79, - 0xfe, 0xbb, 0xc3, 0xdc, 0x7f, 0x88, 0x14, 0xf5, 0x3b, 0xef, 0xe8, 0xd3, - 0x3c, 0xde, 0xc5, 0xf7, 0xe2, 0x2d, 0xee, 0x17, 0xba, 0x72, 0xfa, 0x85, - 0x09, 0xd4, 0xe9, 0xe1, 0xe9, 0x8c, 0x9c, 0x30, 0xea, 0x65, 0xbe, 0x93, - 0x7f, 0xf5, 0x44, 0x09, 0xfb, 0xad, 0x78, 0x15, 0xf0, 0xd8, 0x2a, 0xdc, - 0xd7, 0x5d, 0xfb, 0x99, 0x9f, 0x46, 0xf2, 0xd3, 0xf2, 0xa9, 0xd1, 0xdc, - 0xf5, 0x32, 0x7e, 0x3a, 0x8d, 0xf8, 0x51, 0xe7, 0x40, 0x3e, 0x19, 0x92, - 0xf3, 0xf7, 0xcc, 0xba, 0x3f, 0x41, 0x7a, 0x57, 0x0c, 0x4f, 0xd3, 0xfa, - 0x72, 0x51, 0x44, 0xf1, 0x57, 0x16, 0x9e, 0x82, 0x1d, 0x89, 0x41, 0xb6, - 0xbf, 0x67, 0x2d, 0x70, 0x3f, 0xfb, 0x5f, 0xf9, 0xf5, 0xca, 0x1a, 0x9d, - 0xd6, 0x8d, 0xf7, 0xe2, 0x1c, 0x95, 0x3f, 0xb9, 0xfd, 0xb0, 0x8a, 0x87, - 0xb2, 0x06, 0x1a, 0x8b, 0xce, 0x7d, 0xf2, 0x9c, 0x90, 0xe1, 0x47, 0x19, - 0x47, 0x06, 0x47, 0x7c, 0x5f, 0xdb, 0xe3, 0x44, 0xc6, 0x91, 0x8a, 0x57, - 0x6b, 0x7c, 0x59, 0xe3, 0xc7, 0x1e, 0x37, 0x61, 0xba, 0x57, 0x8c, 0x22, - 0x90, 0xa6, 0x77, 0x44, 0x62, 0x70, 0xe0, 0xc1, 0xfc, 0x9d, 0x00, 0x7f, - 0x09, 0xd6, 0x5b, 0x4f, 0x51, 0x1f, 0xfa, 0x94, 0xe8, 0x67, 0x3f, 0x4e, - 0xd4, 0x72, 0xde, 0x57, 0xc1, 0x8f, 0x3d, 0xcf, 0x40, 0x9f, 0x1e, 0xce, - 0x9f, 0xdb, 0xdc, 0x5f, 0xc0, 0xff, 0x7e, 0xbd, 0x63, 0x94, 0xfd, 0xcd, - 0x71, 0xb8, 0x8b, 0x79, 0xb8, 0x05, 0x1e, 0x74, 0xc5, 0x43, 0xca, 0xe4, - 0x41, 0xd5, 0x19, 0xeb, 0x3e, 0x85, 0x46, 0x1c, 0x49, 0x5c, 0xa0, 0x5f, - 0xa1, 0x3e, 0x2c, 0x8f, 0xed, 0x36, 0xe4, 0x1a, 0xa4, 0x7d, 0x61, 0xb6, - 0x2f, 0x24, 0x76, 0x2e, 0xb7, 0xae, 0x0b, 0xf2, 0xba, 0x80, 0xb1, 0x0e, - 0xf3, 0xc8, 0x53, 0x7d, 0x1e, 0x7e, 0x25, 0x8f, 0x6a, 0xdf, 0xdc, 0x7c, - 0xb4, 0xf2, 0x49, 0x15, 0x9a, 0xfe, 0x50, 0x87, 0x0c, 0xbf, 0x51, 0xbd, - 0xd2, 0xcd, 0xfa, 0x73, 0x97, 0xea, 0x79, 0xe0, 0x64, 0x37, 0xea, 0xc5, - 0xc9, 0xee, 0xd3, 0x7c, 0xff, 0x32, 0x2f, 0x2d, 0xf4, 0x6e, 0x30, 0xb8, - 0xab, 0xb2, 0xd7, 0x1f, 0xbb, 0x1e, 0x15, 0x16, 0x3d, 0xd4, 0xb9, 0x0f, - 0xeb, 0x0f, 0xd0, 0x9f, 0x6e, 0xa0, 0xfe, 0x40, 0x33, 0xfb, 0x6c, 0xfb, - 0x3d, 0x72, 0xeb, 0xfe, 0xe3, 0xde, 0x23, 0x5b, 0x1a, 0xac, 0xe7, 0xc5, - 0xc4, 0xd8, 0x08, 0xce, 0x69, 0xe1, 0x7b, 0x7b, 0x3b, 0xe7, 0xf7, 0xb5, - 0x40, 0x84, 0xce, 0x4d, 0xbe, 0x46, 0xf6, 0x8a, 0x68, 0x10, 0xf6, 0x25, - 0x5f, 0xc7, 0xf7, 0x64, 0x08, 0xf3, 0xe5, 0x21, 0xfc, 0x3e, 0xd0, 0xe2, - 0xd7, 0x49, 0xbe, 0x3c, 0x04, 0x8c, 0x72, 0x5d, 0x18, 0x33, 0xdf, 0x11, - 0xc0, 0x21, 0xdf, 0x7c, 0xef, 0x08, 0xbc, 0xc7, 0xce, 0xfb, 0x50, 0x37, - 0x44, 0x0c, 0xfd, 0x73, 0x53, 0x8d, 0x4e, 0xdf, 0x5b, 0x63, 0xb8, 0x9f, - 0x51, 0x97, 0xe7, 0xda, 0x55, 0x81, 0x78, 0x2d, 0xcf, 0xbe, 0x37, 0xac, - 0xef, 0x12, 0x3d, 0x31, 0x68, 0xf6, 0xfd, 0x76, 0x3d, 0x90, 0x67, 0x72, - 0x7f, 0x1a, 0x1a, 0xfd, 0xf5, 0xa3, 0xbc, 0x47, 0x3c, 0xdc, 0xaf, 0xdd, - 0x99, 0x45, 0xbc, 0x16, 0x89, 0x0b, 0x23, 0xe0, 0x61, 0x6c, 0xc4, 0x29, - 0x8f, 0xa5, 0x1e, 0xea, 0x1c, 0xd8, 0xa5, 0xec, 0xcc, 0x9e, 0x0b, 0xbd, - 0x76, 0xb0, 0xfe, 0xbf, 0xd2, 0xef, 0x17, 0x51, 0xb6, 0x57, 0xee, 0x8b, - 0xf9, 0x8d, 0xf4, 0x6e, 0xca, 0x13, 0x69, 0x73, 0x6c, 0x7f, 0xcf, 0xb4, - 0x90, 0x5e, 0x85, 0x7c, 0xaf, 0x47, 0x2d, 0xfd, 0x07, 0xe4, 0x8b, 0xeb, - 0x81, 0xc7, 0xea, 0x95, 0xdf, 0x94, 0x7f, 0x95, 0x3f, 0xe1, 0xf7, 0xe8, - 0x4a, 0x12, 0x6b, 0x4c, 0xae, 0xa4, 0x84, 0xaf, 0x4f, 0x4e, 0xa9, 0x7b, - 0x1e, 0xeb, 0xb7, 0xc4, 0xa5, 0xfc, 0x07, 0xe2, 0xfb, 0x38, 0x2e, 0xd6, - 0x9f, 0x19, 0xb3, 0xfd, 0xbd, 0xe0, 0x3f, 0xeb, 0x3b, 0xc1, 0x23, 0xce, - 0xe7, 0xf1, 0x74, 0x83, 0xea, 0x7b, 0xe7, 0x7b, 0xef, 0x48, 0x3b, 0x3e, - 0xba, 0x9f, 0xdb, 0x47, 0x67, 0xfb, 0x60, 0x65, 0xaf, 0x5c, 0x57, 0xcf, - 0x71, 0xac, 0x89, 0xa6, 0x0d, 0xf8, 0x7d, 0x23, 0xec, 0x47, 0xde, 0x84, - 0xfd, 0x4e, 0xef, 0x52, 0x23, 0x8e, 0xf2, 0xa9, 0x60, 0x2c, 0x2c, 0xcc, - 0x27, 0xfb, 0x8e, 0x5c, 0xbc, 0x44, 0x62, 0x9f, 0x0d, 0x06, 0x31, 0x5f, - 0xd2, 0x84, 0x63, 0xbc, 0x14, 0xf7, 0x1e, 0x71, 0x08, 0x79, 0xf1, 0xe9, - 0x31, 0xe0, 0x27, 0xe2, 0x55, 0xec, 0x53, 0x78, 0x90, 0xee, 0x53, 0xad, - 0x04, 0x34, 0x67, 0x06, 0x39, 0xde, 0x4b, 0xdd, 0xf4, 0xfb, 0xe2, 0xac, - 0x08, 0x49, 0xf4, 0x99, 0xf9, 0x8b, 0xb8, 0xf6, 0x5a, 0xfc, 0xff, 0xa8, - 0x71, 0x4e, 0xf5, 0xc9, 0x88, 0x63, 0x6c, 0xc3, 0xf1, 0xae, 0xe5, 0xc6, - 0xbb, 0xe2, 0xa9, 0xd4, 0xed, 0x18, 0xdf, 0xab, 0xe7, 0xc6, 0xb7, 0xd2, - 0x4f, 0xf2, 0x7d, 0xd7, 0xbc, 0x3f, 0xe7, 0xee, 0x8f, 0xf7, 0xd3, 0x85, - 0x27, 0x16, 0xdf, 0xc0, 0x8d, 0xd5, 0xf2, 0xfc, 0x92, 0x39, 0x7d, 0x72, - 0x6e, 0xfe, 0xa1, 0xde, 0xbd, 0x61, 0xc4, 0xc3, 0x7f, 0x69, 0x4a, 0x77, - 0x8f, 0xc8, 0x15, 0x00, 0x00, 0x00 }; +#define XI_RV2P_PROC2_BD_PAGE_SIZE ((BCM_PAGE_SIZE / 16) - 1) + 0xad, 0x58, 0x4d, 0x4c, 0x54, 0x57, 0x14, 0xbe, 0xf3, 0xc3, 0xcc, 0x30, + 0xbc, 0x99, 0x41, 0x98, 0x0e, 0x7f, 0xa6, 0x22, 0x28, 0x82, 0x1d, 0x14, + 0x06, 0xd4, 0xb6, 0x36, 0xa9, 0xc1, 0x06, 0xb5, 0xb5, 0x11, 0x69, 0x63, + 0xba, 0x68, 0x8a, 0x60, 0x45, 0x06, 0xc1, 0x10, 0x31, 0x2e, 0xdc, 0x74, + 0x02, 0x16, 0xbb, 0x98, 0x85, 0x98, 0xe2, 0x60, 0xd3, 0x18, 0x52, 0x37, + 0xa6, 0x3b, 0x92, 0xb6, 0x62, 0xbb, 0x30, 0x31, 0x2d, 0xb1, 0xb6, 0x89, + 0x36, 0xb1, 0x7f, 0x9b, 0xa6, 0xa6, 0x5a, 0x8a, 0x4a, 0x2d, 0xda, 0xb2, + 0xaa, 0xd0, 0x77, 0xcf, 0x77, 0xee, 0x9b, 0x37, 0x33, 0x6f, 0x44, 0x53, + 0xd9, 0x1c, 0xee, 0x7d, 0xe7, 0x9e, 0x7b, 0xce, 0x77, 0x7e, 0xef, 0xe4, + 0x0b, 0x21, 0x9c, 0x22, 0x36, 0xbe, 0x4c, 0xa7, 0x62, 0x89, 0xdd, 0xe1, + 0xd1, 0xc9, 0x82, 0x10, 0x39, 0xc5, 0x72, 0x2d, 0xec, 0x82, 0xff, 0x56, + 0xe7, 0x13, 0xb9, 0x36, 0x2e, 0xbf, 0xbb, 0xc5, 0xeb, 0x76, 0x7c, 0x77, + 0x0a, 0x49, 0x03, 0x42, 0xc4, 0x24, 0xcd, 0x67, 0xba, 0x9d, 0xe9, 0x4a, + 0x1b, 0xe8, 0x46, 0xa6, 0x51, 0xa6, 0x2b, 0x98, 0xd6, 0xdb, 0x41, 0x57, + 0x31, 0xad, 0xe6, 0x7d, 0x8d, 0xcf, 0xd7, 0xf2, 0xfe, 0x7b, 0x4c, 0x8f, + 0xf2, 0xbe, 0xa6, 0xf3, 0x29, 0xbd, 0xe4, 0x7a, 0x66, 0x41, 0xc4, 0xf4, + 0x33, 0x42, 0xdf, 0xae, 0x51, 0xfb, 0x1a, 0x91, 0x58, 0x0d, 0xf4, 0x7e, + 0xad, 0x5c, 0xf2, 0xfd, 0x61, 0xc1, 0x27, 0xf7, 0x6f, 0x2e, 0x28, 0x79, + 0x03, 0x0e, 0xb9, 0xfe, 0x55, 0x5f, 0xdb, 0xe4, 0x32, 0x18, 0x82, 0x98, + 0x60, 0x71, 0x5c, 0xca, 0x71, 0x88, 0xd1, 0x61, 0x0f, 0xa1, 0x72, 0x52, + 0xc3, 0x3a, 0x46, 0x78, 0xd8, 0xf4, 0x35, 0xcb, 0x63, 0x5a, 0xe2, 0xc3, + 0xbd, 0xbb, 0xca, 0x71, 0xdf, 0x8f, 0xcf, 0x80, 0x2f, 0x16, 0x50, 0x80, + 0xe2, 0xfb, 0x32, 0xc1, 0xdf, 0xf7, 0xcb, 0xf5, 0xac, 0xad, 0xd0, 0x06, + 0x5c, 0xdd, 0xcc, 0x65, 0xcf, 0x91, 0xfb, 0xcb, 0x1b, 0x4f, 0x0e, 0x83, + 0xbf, 0xad, 0x1c, 0xfb, 0x4f, 0x87, 0xa5, 0x3c, 0x97, 0x88, 0x31, 0x15, + 0xb5, 0xa4, 0x97, 0x2d, 0x56, 0x9b, 0x2a, 0xff, 0x97, 0x61, 0xac, 0xda, + 0x7d, 0x90, 0xeb, 0x4d, 0x91, 0x1b, 0xca, 0x90, 0xfb, 0x53, 0xae, 0x59, + 0xbe, 0xdf, 0x06, 0xf9, 0xde, 0x45, 0xe5, 0x77, 0xf8, 0x40, 0x0b, 0xc3, + 0x56, 0xf7, 0xe4, 0x2e, 0xa2, 0x7f, 0xf7, 0xa2, 0xf2, 0x8f, 0x18, 0xfa, + 0x2b, 0xff, 0xa9, 0xef, 0xe9, 0x38, 0xd2, 0xf2, 0xe3, 0xd8, 0x5a, 0x16, + 0xb3, 0x5a, 0xd9, 0xcf, 0x7a, 0x3a, 0x40, 0x37, 0x85, 0x89, 0xc4, 0xf7, + 0x70, 0x80, 0x37, 0x57, 0xc9, 0xfb, 0x0b, 0x84, 0xd3, 0x2e, 0xe5, 0xd5, + 0x79, 0x5c, 0xe7, 0xb1, 0xff, 0x06, 0xfb, 0xeb, 0x6d, 0x36, 0xe8, 0xa6, + 0x57, 0x02, 0xb4, 0xb0, 0xd0, 0x99, 0xc7, 0xf2, 0xd9, 0xdf, 0xb1, 0x3c, + 0x9c, 0x9f, 0xd4, 0xa4, 0x9e, 0x5f, 0xeb, 0xf1, 0x63, 0xe5, 0x7f, 0xc7, + 0x43, 0xfc, 0x8f, 0xf3, 0x4b, 0x56, 0xe1, 0xeb, 0xf1, 0x4e, 0xac, 0xcb, + 0xce, 0xe4, 0x13, 0x4e, 0xa3, 0xe3, 0x56, 0xf1, 0x92, 0x2e, 0x5f, 0xcf, + 0xe3, 0x00, 0xee, 0x11, 0x15, 0x1e, 0x52, 0x0e, 0xf8, 0xea, 0x3c, 0xb5, + 0x96, 0x38, 0x89, 0x93, 0x2b, 0xe5, 0xbe, 0x5d, 0xb4, 0x3a, 0x34, 0xba, + 0xa7, 0x35, 0xaa, 0xf2, 0x06, 0xdf, 0x3b, 0x5d, 0x44, 0x8a, 0xdb, 0x87, + 0xa4, 0xdd, 0x01, 0xb1, 0xdb, 0x1e, 0x20, 0x7e, 0xe0, 0xe4, 0xf0, 0x68, + 0x9f, 0x81, 0xff, 0xc2, 0x32, 0x8d, 0x6c, 0xea, 0x6c, 0xc0, 0xb9, 0x60, + 0x04, 0x74, 0x24, 0x92, 0x23, 0x49, 0xb8, 0xb3, 0x9f, 0x96, 0x6b, 0x7e, + 0xab, 0xf7, 0x10, 0x5f, 0xac, 0x56, 0xe5, 0xa5, 0xf2, 0xa3, 0xc4, 0xed, + 0x90, 0x91, 0x87, 0xa2, 0x12, 0x38, 0xff, 0xbe, 0x52, 0xf2, 0xeb, 0x60, + 0x57, 0xe0, 0x9e, 0xa4, 0x7e, 0xe6, 0xbc, 0xee, 0x35, 0xe5, 0xf5, 0xe3, + 0xc5, 0xc5, 0x26, 0xc2, 0x67, 0x13, 0xe3, 0x54, 0xce, 0x71, 0xb8, 0xd4, + 0x22, 0x0e, 0x03, 0xf4, 0xff, 0xad, 0xa6, 0x7c, 0xc2, 0x79, 0x07, 0xf6, + 0x4f, 0x34, 0x9f, 0x83, 0x9f, 0xb6, 0x11, 0x1e, 0xc2, 0x7b, 0xf4, 0x53, + 0x9c, 0x6a, 0xa7, 0xfc, 0xef, 0x6d, 0xec, 0xfc, 0x1c, 0xeb, 0x0e, 0x87, + 0x5c, 0xef, 0xd7, 0xf6, 0x4c, 0x80, 0x3f, 0x67, 0x10, 0xb8, 0xef, 0xe0, + 0x5b, 0xb6, 0x39, 0xa8, 0xde, 0xc4, 0x5d, 0x83, 0xb4, 0xd4, 0x26, 0xe9, + 0x7b, 0xbe, 0x38, 0x36, 0x8e, 0xef, 0x07, 0xf2, 0xa4, 0x9d, 0xaf, 0x1a, + 0x75, 0x29, 0xea, 0xc2, 0xf9, 0xf8, 0x30, 0xea, 0xca, 0xf4, 0x27, 0x72, + 0xdd, 0x16, 0x9e, 0x06, 0x7f, 0x38, 0x3a, 0xc4, 0x82, 0xed, 0xc0, 0xf1, + 0x96, 0x1d, 0xfc, 0x1c, 0xae, 0x5e, 0x27, 0xf9, 0xd1, 0x26, 0xb4, 0x66, + 0xd0, 0x77, 0xe9, 0xfb, 0xbf, 0xb6, 0x38, 0xe1, 0xb6, 0xcb, 0xef, 0x3c, + 0xa7, 0xf0, 0x61, 0x1a, 0x50, 0x76, 0x81, 0x3e, 0x6a, 0x3e, 0x0c, 0x69, + 0xd9, 0xf2, 0x80, 0xfd, 0x59, 0xb3, 0x58, 0x1e, 0x80, 0x36, 0x57, 0x81, + 0xba, 0x2a, 0xa9, 0x9e, 0x3c, 0x46, 0x3e, 0xb0, 0x5e, 0x19, 0xf9, 0x86, + 0xdd, 0x64, 0x9c, 0x12, 0xd1, 0xe3, 0x33, 0x25, 0x5e, 0x39, 0x3f, 0x96, + 0xeb, 0x7e, 0x50, 0x71, 0x27, 0x05, 0xba, 0xc5, 0x7e, 0x96, 0x1b, 0x65, + 0x3c, 0x7a, 0x18, 0x8f, 0x19, 0xa6, 0x07, 0xf2, 0x14, 0x0e, 0xa0, 0xc7, + 0x34, 0xdc, 0xdb, 0x1a, 0x95, 0x7e, 0x0c, 0x5a, 0xf4, 0x17, 0xd5, 0x47, + 0xe0, 0xa7, 0x51, 0xf6, 0xeb, 0x29, 0xa3, 0x9f, 0x28, 0x7c, 0xb3, 0xf5, + 0x95, 0xd4, 0x7c, 0x4a, 0xb3, 0x33, 0xfe, 0x55, 0x05, 0x8e, 0x17, 0x54, + 0x82, 0x1a, 0xf8, 0x56, 0x51, 0x1e, 0xfb, 0x8b, 0x26, 0x94, 0x7d, 0x52, + 0xbf, 0x3b, 0x2a, 0x0f, 0xfd, 0x89, 0x01, 0xa2, 0xde, 0x82, 0x33, 0xf2, + 0x9e, 0x52, 0x8b, 0xba, 0x92, 0x9a, 0xcf, 0xe9, 0xf8, 0x1e, 0xf0, 0x51, + 0xc1, 0x6d, 0xbc, 0x32, 0x95, 0x9a, 0xb7, 0xc8, 0x4f, 0xb7, 0x11, 0xdf, + 0xc1, 0xf5, 0xec, 0x07, 0xa6, 0xa1, 0x0d, 0x52, 0x6e, 0x0b, 0xdf, 0x53, + 0xc7, 0xf7, 0x68, 0xa6, 0xba, 0x21, 0xf5, 0xfc, 0x73, 0x5e, 0xd5, 0x0b, + 0x15, 0x1f, 0xc9, 0xba, 0xa1, 0xfc, 0x40, 0xf7, 0x87, 0xaf, 0x4c, 0xc9, + 0xf3, 0x65, 0x8b, 0xd4, 0x91, 0x1b, 0x86, 0xbc, 0xef, 0x8d, 0x3a, 0x21, + 0xbf, 0xe7, 0x89, 0x17, 0x79, 0x99, 0x5a, 0x0f, 0xff, 0xd2, 0xeb, 0x21, + 0xd9, 0xe1, 0xd1, 0xce, 0x71, 0xfd, 0xeb, 0x97, 0xf7, 0x14, 0xb3, 0xde, + 0xc5, 0xaa, 0xaf, 0xe9, 0x7a, 0x73, 0x9d, 0x6c, 0x33, 0xd7, 0xbb, 0x1f, + 0xe6, 0x93, 0x75, 0x4b, 0xae, 0xaf, 0xcd, 0x67, 0xce, 0x27, 0x96, 0xb8, + 0xc6, 0x44, 0x00, 0x73, 0x58, 0x2c, 0x20, 0xcf, 0xe5, 0xd8, 0x32, 0xeb, + 0x5f, 0xba, 0x1d, 0xc0, 0xa5, 0xdd, 0xee, 0x23, 0xbe, 0xeb, 0x7d, 0xf2, + 0xdc, 0xb4, 0x50, 0xf6, 0xa2, 0x0e, 0x96, 0x73, 0xbf, 0x5f, 0xca, 0x7a, + 0xeb, 0xf2, 0x6a, 0x29, 0x1f, 0x3c, 0xd7, 0xfb, 0xcc, 0x7a, 0x5f, 0x98, + 0xcf, 0x7e, 0x9f, 0x75, 0x1c, 0xf4, 0x71, 0x9f, 0xe5, 0x39, 0xc1, 0xb3, + 0xe7, 0x0b, 0xa5, 0x17, 0xdf, 0x1f, 0x50, 0x7a, 0x68, 0xe4, 0xa7, 0xa9, + 0x7e, 0x29, 0xa7, 0x50, 0x70, 0xd8, 0x88, 0xde, 0x6a, 0xd4, 0xdf, 0x99, + 0xbd, 0xb0, 0xa3, 0xb7, 0x4a, 0xea, 0xa1, 0x7b, 0x25, 0x86, 0x3c, 0x17, + 0xdc, 0x8f, 0xbe, 0x1c, 0xb6, 0xf2, 0xeb, 0xb7, 0xcc, 0x17, 0x64, 0xfb, + 0xf2, 0xd9, 0xbe, 0xb0, 0x48, 0xaf, 0xf3, 0x6d, 0xe5, 0xd4, 0x0f, 0x98, + 0xef, 0x05, 0xd5, 0x0f, 0x74, 0x3e, 0xc2, 0x99, 0xe5, 0x58, 0xe1, 0x64, + 0x25, 0x67, 0x82, 0xe3, 0xa0, 0x8b, 0xf9, 0x9c, 0x59, 0xe7, 0x9b, 0xb9, + 0x55, 0xd4, 0x57, 0x4e, 0x1f, 0xa1, 0xfe, 0xe0, 0x33, 0xe2, 0x34, 0xd5, + 0x8e, 0xe3, 0x4f, 0x10, 0x77, 0x9a, 0xff, 0xc4, 0x3e, 0x7f, 0x36, 0x7c, + 0x9d, 0x72, 0x7b, 0x6c, 0x76, 0x42, 0xf9, 0x47, 0x23, 0x7b, 0xa7, 0xfa, + 0xd5, 0x9c, 0x6f, 0xc6, 0xdd, 0x6e, 0xc2, 0x1d, 0xfc, 0x98, 0xef, 0xfe, + 0x0f, 0xde, 0x56, 0xf3, 0x41, 0x9f, 0x91, 0x9f, 0x03, 0x2e, 0xab, 0xfa, + 0xbf, 0xd6, 0x88, 0x97, 0x83, 0x3c, 0xe7, 0xcd, 0x69, 0xf4, 0x4f, 0x64, + 0x26, 0x4e, 0x4b, 0xad, 0xe4, 0xac, 0xe4, 0x5b, 0x1d, 0x39, 0xc8, 0x76, + 0x5d, 0x76, 0xc0, 0xee, 0xae, 0xbd, 0x58, 0x5f, 0xe1, 0x7a, 0x7d, 0x8f, + 0xeb, 0xe3, 0x4e, 0x0f, 0xe8, 0x4c, 0x35, 0xe1, 0x11, 0x39, 0x78, 0x5e, + 0xc9, 0x27, 0xb9, 0xda, 0x1c, 0xe3, 0xf9, 0x92, 0x83, 0xed, 0xac, 0x20, + 0x3f, 0x46, 0xee, 0x52, 0x3d, 0x70, 0x8a, 0xa6, 0xe5, 0x92, 0x96, 0xe8, + 0xb8, 0xb1, 0x3e, 0x1b, 0x41, 0x5b, 0xd5, 0x80, 0x5f, 0x93, 0xee, 0x67, + 0x6c, 0xbb, 0x2a, 0xf8, 0x7c, 0x3b, 0xd6, 0x6e, 0xae, 0x67, 0x09, 0xd6, + 0xeb, 0xfd, 0x6a, 0x50, 0x7f, 0x0d, 0xe6, 0x84, 0x29, 0xea, 0x0b, 0x81, + 0x48, 0xff, 0x04, 0xec, 0xe9, 0xd9, 0x0c, 0x7b, 0xef, 0x33, 0x0e, 0x4c, + 0xfd, 0xa7, 0x06, 0xa9, 0xef, 0xf8, 0x87, 0x30, 0x67, 0xf8, 0x5d, 0x83, + 0xb0, 0xa3, 0x67, 0x0e, 0xeb, 0xfb, 0xcf, 0x81, 0xfe, 0xf3, 0x3c, 0xce, + 0x1d, 0x3a, 0xc2, 0xf8, 0x6c, 0xb6, 0x3e, 0xd7, 0xf5, 0x37, 0xf8, 0x7a, + 0xab, 0xe5, 0xfd, 0x6f, 0x8d, 0xf1, 0xfc, 0x21, 0xa2, 0x34, 0xef, 0xbc, + 0xa9, 0xcd, 0xf1, 0xba, 0x9b, 0xfb, 0xe2, 0x6d, 0x9e, 0x17, 0x7a, 0xd2, + 0xe6, 0x85, 0x69, 0xd4, 0xe9, 0xb1, 0xb9, 0xb8, 0xdc, 0xd0, 0xeb, 0x65, + 0xae, 0x95, 0x7f, 0x7d, 0x91, 0x22, 0xf6, 0x5b, 0x70, 0x1d, 0xe8, 0xc8, + 0x3a, 0xf4, 0xeb, 0x9e, 0xc3, 0x8c, 0x4f, 0x23, 0xf9, 0x69, 0xcd, 0xec, + 0x44, 0xfa, 0x79, 0x19, 0x3f, 0xed, 0xf3, 0x78, 0x3f, 0x6e, 0xd6, 0xa9, + 0xba, 0x0f, 0xe7, 0x3a, 0xe8, 0x7d, 0x71, 0xcf, 0x98, 0x3f, 0xa7, 0x49, + 0xff, 0xb2, 0xb1, 0x39, 0x92, 0x53, 0x2a, 0x0a, 0x29, 0x0e, 0x4b, 0xfc, + 0xb3, 0xb0, 0x27, 0x92, 0x60, 0x1c, 0xfa, 0x9e, 0x05, 0x3d, 0xcc, 0x71, + 0xa0, 0xfc, 0x7b, 0x75, 0x83, 0x46, 0xe7, 0xa6, 0xfa, 0x71, 0x8f, 0xca, + 0xa3, 0xf4, 0xb9, 0x58, 0xc5, 0x45, 0x49, 0x03, 0xad, 0x45, 0xd7, 0x21, + 0xb2, 0x53, 0xf7, 0xa7, 0x8c, 0x27, 0x1d, 0x2b, 0xee, 0xdb, 0xa9, 0xf1, + 0x22, 0xe3, 0x49, 0xc5, 0xad, 0x39, 0xce, 0xcc, 0x71, 0x94, 0x1a, 0x3f, + 0x7e, 0xea, 0x2f, 0x7a, 0x31, 0xa0, 0x77, 0x89, 0x2b, 0x92, 0x18, 0x7e, + 0x38, 0x8e, 0xa7, 0x80, 0x63, 0x84, 0xf5, 0xd6, 0xa2, 0x34, 0x8f, 0x3e, + 0x25, 0x86, 0xd8, 0x9f, 0xd3, 0xd5, 0x9c, 0xff, 0x15, 0xf0, 0x67, 0xdf, + 0x0a, 0xe8, 0xd3, 0xc7, 0x79, 0x74, 0x87, 0xe7, 0x0c, 0xc4, 0x81, 0x5b, + 0xeb, 0x9c, 0x60, 0xbf, 0x73, 0x3c, 0x76, 0x33, 0x0e, 0xb7, 0x81, 0x83, + 0xa6, 0x70, 0x88, 0x1a, 0x38, 0xa8, 0x7a, 0x63, 0x96, 0x53, 0xa0, 0xc7, + 0x93, 0xa4, 0x4b, 0xb4, 0xab, 0x34, 0x8f, 0xe5, 0xb0, 0xdd, 0x3a, 0x5f, + 0x83, 0xb4, 0xcf, 0xcf, 0xf6, 0xf9, 0xc4, 0xbe, 0x35, 0xe6, 0x73, 0x79, + 0x7c, 0xce, 0xab, 0x9f, 0xc3, 0x3e, 0xf2, 0x55, 0xcb, 0x82, 0xaf, 0xc4, + 0x51, 0xc9, 0x4d, 0xcf, 0x4b, 0x33, 0x9e, 0x54, 0xa9, 0xe9, 0x0f, 0xf5, + 0x48, 0xf7, 0x1b, 0xd5, 0x2d, 0xcd, 0xa8, 0x43, 0xf7, 0xa8, 0xae, 0x7b, + 0x4f, 0xf7, 0xa2, 0x6e, 0x9c, 0xee, 0x3d, 0xcb, 0x7d, 0x98, 0x71, 0x69, + 0xa1, 0xf7, 0x83, 0x8e, 0x5d, 0x45, 0x6a, 0x1d, 0x4a, 0xd5, 0xa3, 0xcc, + 0xa4, 0x87, 0xba, 0x77, 0xb1, 0x39, 0x01, 0x73, 0xea, 0x16, 0x9a, 0x13, + 0x3c, 0xc6, 0xbc, 0x9d, 0xda, 0x4f, 0x26, 0x1f, 0x3c, 0x6e, 0x3f, 0xd9, + 0xd9, 0x60, 0xbe, 0xaf, 0x46, 0x4c, 0x8e, 0xe3, 0x9e, 0x16, 0xee, 0xdf, + 0xbb, 0x39, 0xcf, 0xaf, 0x7b, 0x03, 0x74, 0x6f, 0xc7, 0x2b, 0x64, 0xaf, + 0x08, 0xe5, 0xc1, 0xbe, 0x8e, 0xed, 0xf8, 0xde, 0xe1, 0xc3, 0x7e, 0xa9, + 0x0f, 0xbf, 0xa3, 0xb4, 0xb8, 0x35, 0xe2, 0x2f, 0xf5, 0x81, 0x86, 0xb8, + 0x3e, 0x4c, 0x1a, 0xef, 0x09, 0xd0, 0x51, 0x57, 0xb6, 0xf7, 0x04, 0xde, + 0x65, 0x17, 0x5d, 0xa8, 0x1f, 0xa2, 0x06, 0x73, 0x74, 0x53, 0x95, 0x46, + 0xdf, 0x5b, 0x6b, 0xd0, 0xa7, 0x51, 0x9f, 0x33, 0xed, 0x2a, 0x43, 0xbc, + 0x96, 0x26, 0xdf, 0x1d, 0xe6, 0xf7, 0x89, 0x16, 0x49, 0x18, 0xf3, 0x7f, + 0xaa, 0x1e, 0xc8, 0x33, 0x29, 0x9f, 0x96, 0xfa, 0x9c, 0xfd, 0x28, 0xef, + 0x12, 0x07, 0xcf, 0x6d, 0x77, 0xf9, 0x77, 0x82, 0x42, 0x71, 0x69, 0x1c, + 0x38, 0x4c, 0x8e, 0x5b, 0xe5, 0xb1, 0xd4, 0x43, 0xdd, 0x03, 0xbb, 0x94, + 0x9d, 0xc9, 0x7b, 0xa1, 0xd7, 0x5e, 0xd6, 0xff, 0x06, 0xfd, 0x9e, 0x11, + 0x62, 0x7b, 0xa5, 0x5c, 0xec, 0x6f, 0xa5, 0xf7, 0x53, 0x8e, 0x88, 0x19, + 0xeb, 0xd4, 0x77, 0x4d, 0x0b, 0xe9, 0x55, 0xc0, 0xfd, 0x3d, 0x64, 0x9a, + 0x43, 0xc0, 0x1f, 0xac, 0x03, 0x1d, 0xa9, 0x53, 0x7e, 0x53, 0xfe, 0x55, + 0xfe, 0x84, 0xdf, 0x43, 0xf5, 0xc4, 0xd6, 0xd8, 0x51, 0x4f, 0x09, 0x5f, + 0xd7, 0x31, 0xab, 0xfa, 0x3d, 0xce, 0xef, 0x0c, 0x4b, 0xfe, 0x77, 0xc4, + 0x77, 0x61, 0x34, 0xd8, 0x9f, 0x99, 0x26, 0xe7, 0x7c, 0xc1, 0x7f, 0xe6, + 0xf7, 0x82, 0x43, 0x5c, 0xcc, 0xe1, 0xed, 0x06, 0x35, 0xff, 0x66, 0x7b, + 0xf7, 0x48, 0x3b, 0xba, 0x1f, 0xa4, 0xcf, 0xd3, 0xc9, 0x79, 0x58, 0xd9, + 0x2b, 0xcf, 0xd5, 0x71, 0x1c, 0x7b, 0x44, 0xd3, 0x16, 0xfc, 0xce, 0xe1, + 0x77, 0x23, 0x6f, 0xfc, 0x6e, 0xab, 0xf7, 0xa9, 0x1e, 0x47, 0xb9, 0x54, + 0x30, 0x96, 0x16, 0xe4, 0x92, 0x7d, 0x27, 0x2e, 0x7f, 0x43, 0x6c, 0x1f, + 0x25, 0xf2, 0xb0, 0x5f, 0xd4, 0x84, 0x6b, 0x9c, 0x14, 0xf7, 0x0e, 0x71, + 0x14, 0x79, 0xf1, 0xe1, 0x08, 0xe8, 0x07, 0xe2, 0x65, 0xc8, 0x29, 0x18, + 0xa0, 0xbe, 0xea, 0x29, 0x02, 0xcc, 0xf1, 0x04, 0xc7, 0x7b, 0xb1, 0x9d, + 0x7e, 0x87, 0x5d, 0x10, 0x3e, 0xfe, 0x9d, 0x8c, 0xf3, 0x17, 0x71, 0xed, + 0x34, 0xf9, 0xff, 0x51, 0xe3, 0x1c, 0xfd, 0x33, 0xc1, 0x7e, 0xe7, 0x78, + 0xf7, 0xa4, 0xc7, 0xbb, 0xc2, 0xa9, 0xd8, 0x6e, 0x19, 0xdf, 0xeb, 0x33, + 0xe3, 0x5b, 0xe9, 0x97, 0xda, 0x3f, 0x33, 0xe5, 0xe3, 0x1d, 0x75, 0xe9, + 0x89, 0xc5, 0x37, 0xe8, 0xd6, 0x4a, 0x79, 0x7f, 0x51, 0xc6, 0xbc, 0x9c, + 0x9e, 0x7f, 0xa8, 0x77, 0xd5, 0x7a, 0x3c, 0xfc, 0x07, 0xd7, 0x0d, 0x36, + 0x4f, 0xf0, 0x16, 0x00, 0x00, 0x00 }; static u8 bnx2_TPAT_b09FwText[] = { - 0xbd, 0x58, 0x5d, 0x6c, 0x1c, 0xd5, 0x15, 0x3e, 0x73, 0x67, 0xd6, 0x3b, - 0xb6, 0x9c, 0x78, 0x4c, 0xb6, 0xb0, 0x14, 0x47, 0xcc, 0xc4, 0xe3, 0x9f, - 0xca, 0x16, 0x0c, 0xe9, 0x96, 0x1a, 0x69, 0x55, 0x0d, 0xbb, 0x1b, 0x63, - 0xa5, 0x3c, 0x18, 0x29, 0x52, 0x91, 0xa0, 0xc8, 0x5d, 0x13, 0xe0, 0x81, - 0x87, 0xa0, 0xf6, 0xa1, 0x15, 0x0f, 0x59, 0xd6, 0x9b, 0x90, 0x87, 0x6d, - 0x06, 0x96, 0x2a, 0x79, 0x68, 0x55, 0x45, 0x0e, 0x8e, 0xa3, 0x76, 0xe5, - 0x25, 0x48, 0x7d, 0x8c, 0x40, 0xa1, 0x4a, 0x5f, 0x79, 0xa0, 0x15, 0x7d, - 0x22, 0x52, 0x5f, 0x78, 0xe8, 0x4f, 0x84, 0xd4, 0x16, 0xb5, 0x34, 0xb7, - 0xdf, 0x77, 0x67, 0xc6, 0x6c, 0x4d, 0x22, 0xc4, 0x4b, 0x57, 0x5a, 0xdd, - 0x99, 0x7b, 0xcf, 0x39, 0xf7, 0xdc, 0xf3, 0xf3, 0x9d, 0x73, 0xe7, 0x90, - 0x92, 0x31, 0xc9, 0x7e, 0xfb, 0xf0, 0xaf, 0xfc, 0xe0, 0xc4, 0x8f, 0xbe, - 0xf5, 0x40, 0xf4, 0x00, 0xdf, 0xad, 0x82, 0x38, 0xf2, 0x7f, 0xfc, 0xd9, - 0x22, 0x5e, 0xae, 0x07, 0xff, 0xe2, 0xaa, 0xea, 0xda, 0xc1, 0x5a, 0x28, - 0xae, 0x5d, 0x5d, 0x79, 0x60, 0x3d, 0x14, 0x89, 0xfb, 0x0b, 0x7e, 0x5d, - 0xfe, 0xa3, 0x5b, 0x25, 0x47, 0x38, 0x7f, 0xb0, 0xfa, 0xd9, 0x83, 0x57, - 0xbf, 0x1d, 0xdc, 0xbc, 0x60, 0x8b, 0xeb, 0x55, 0xcf, 0xb8, 0xde, 0xac, - 0xb8, 0x53, 0xe0, 0xf9, 0xc5, 0x5c, 0x6f, 0x44, 0xf6, 0xe7, 0xb2, 0x5a, - 0x5a, 0x85, 0x37, 0xf4, 0xd5, 0xb9, 0xd0, 0x6b, 0x4b, 0x49, 0xae, 0x0c, - 0x7c, 0xa9, 0x0d, 0xa6, 0xe4, 0x9d, 0x41, 0x59, 0xde, 0x1e, 0x78, 0xf2, - 0xd6, 0xc0, 0x91, 0xe3, 0x6f, 0x9c, 0x94, 0x4e, 0x14, 0x94, 0x1b, 0xb6, - 0x2b, 0xaa, 0x1a, 0x94, 0x9b, 0xe2, 0xcb, 0x56, 0x14, 0x9c, 0x59, 0xb3, - 0x27, 0x2d, 0xb7, 0xea, 0xca, 0xcb, 0x73, 0x4a, 0x2e, 0x94, 0x9e, 0x96, - 0xe7, 0xc2, 0x27, 0xf1, 0x77, 0xe4, 0x50, 0xcf, 0xb1, 0xea, 0xe7, 0x1d, - 0x09, 0x7b, 0x13, 0xf2, 0x58, 0xa4, 0xf5, 0x7a, 0x14, 0x83, 0x7f, 0x7a, - 0xfe, 0x79, 0x19, 0x95, 0x96, 0x17, 0xac, 0x88, 0x14, 0x48, 0x23, 0xb5, - 0xa8, 0x20, 0xb1, 0x97, 0x9e, 0xed, 0x82, 0x19, 0x3f, 0xd3, 0x5b, 0xe0, - 0x1f, 0x0d, 0xf3, 0xf5, 0xbb, 0xb2, 0x75, 0x2f, 0x5b, 0x57, 0x72, 0xe8, - 0x5c, 0xe0, 0x6f, 0xcb, 0x4c, 0xec, 0x58, 0xb7, 0x74, 0x2d, 0xbc, 0xdb, - 0xab, 0x6d, 0x3b, 0x32, 0xdd, 0xe3, 0x19, 0x42, 0xaf, 0x2e, 0x1a, 0x3c, - 0x36, 0x79, 0x1c, 0x55, 0xfd, 0x21, 0x7c, 0x37, 0x13, 0x2b, 0x4b, 0xe4, - 0x5a, 0xb7, 0xec, 0xd5, 0x06, 0x3f, 0xb6, 0x6a, 0xc9, 0x2d, 0x1d, 0x3b, - 0x63, 0xa2, 0xc2, 0xd8, 0xaa, 0x6d, 0x53, 0xd6, 0xa8, 0x38, 0x61, 0x11, - 0x3c, 0xd3, 0x9e, 0x12, 0x8e, 0xb5, 0x6c, 0x9e, 0xb2, 0x1b, 0x78, 0x5e, - 0xb6, 0xe2, 0x6d, 0xc7, 0xaa, 0x9d, 0x5f, 0xc1, 0xb3, 0x0b, 0x7e, 0xd8, - 0x26, 0xb2, 0x24, 0x5e, 0xb5, 0xc0, 0xc7, 0x73, 0x7a, 0x78, 0x57, 0x12, - 0x97, 0x3c, 0xd9, 0xa8, 0x04, 0xe5, 0x96, 0x1c, 0xb5, 0xea, 0xdb, 0x5f, - 0x70, 0x9c, 0xb7, 0x32, 0xf8, 0xe2, 0x1c, 0x75, 0x79, 0xd4, 0xd1, 0x5a, - 0x3d, 0x54, 0xcc, 0xce, 0x48, 0x79, 0x71, 0xaa, 0x7f, 0x89, 0xef, 0xd0, - 0x39, 0x81, 0xee, 0xfd, 0x11, 0xe8, 0xa3, 0x35, 0xf7, 0xa9, 0x85, 0xed, - 0xd7, 0x14, 0x2c, 0x78, 0x97, 0x04, 0xad, 0xa7, 0x68, 0x8d, 0xb3, 0x07, - 0xc4, 0x9f, 0x54, 0xa1, 0x92, 0xc0, 0xdb, 0x96, 0x29, 0xd9, 0x48, 0xa6, - 0xbc, 0x23, 0x49, 0xdb, 0x23, 0x0d, 0xe7, 0xea, 0xa0, 0x39, 0xd2, 0xd7, - 0xfa, 0x52, 0x74, 0x5f, 0x51, 0xf6, 0xab, 0xc5, 0x82, 0x04, 0x7e, 0x6c, - 0xf8, 0x64, 0xca, 0x11, 0xca, 0xc4, 0xf3, 0x0e, 0xdf, 0x67, 0x0c, 0xad, - 0xda, 0xd9, 0x6b, 0xcb, 0xb9, 0x4c, 0x37, 0xfa, 0x43, 0xd1, 0x4e, 0xd9, - 0xfb, 0xb8, 0x57, 0x3b, 0x9f, 0xdb, 0xdf, 0x9c, 0x07, 0xf6, 0x8e, 0xa4, - 0x56, 0xc1, 0xb9, 0xee, 0x78, 0xd6, 0x9c, 0x8f, 0x3a, 0x72, 0xef, 0x88, - 0xe7, 0xd9, 0xd5, 0xf5, 0xa9, 0x2f, 0xe8, 0xda, 0xf2, 0x71, 0x4e, 0xff, - 0xe7, 0x98, 0xdf, 0xe8, 0x4a, 0x49, 0x09, 0xe3, 0x08, 0xcf, 0x7d, 0xbe, - 0xcf, 0x20, 0x06, 0xf9, 0xac, 0x24, 0x3c, 0xe7, 0x4a, 0x27, 0x7c, 0xc6, - 0x96, 0xfd, 0x5a, 0x77, 0x22, 0xc7, 0x6a, 0x9c, 0x7f, 0x31, 0x7b, 0x46, - 0x0c, 0x27, 0x88, 0xe1, 0x04, 0x31, 0x9d, 0x20, 0x8e, 0x13, 0xf1, 0x54, - 0xd5, 0x97, 0xab, 0x73, 0xae, 0xdc, 0xb0, 0x11, 0x0b, 0x83, 0x05, 0xef, - 0x4d, 0xc4, 0x63, 0xec, 0x59, 0x62, 0x87, 0xf1, 0x7c, 0x41, 0xf8, 0x8e, - 0x38, 0x74, 0xe2, 0xb2, 0x8d, 0x38, 0x8c, 0x8f, 0x71, 0xae, 0x28, 0x6b, - 0xe6, 0xbc, 0x0b, 0xde, 0x29, 0xa1, 0x9f, 0x6b, 0x58, 0x9b, 0xf6, 0x4f, - 0x31, 0x60, 0xc7, 0x6a, 0x58, 0xa7, 0xac, 0xc0, 0x6b, 0x81, 0xa2, 0x9d, - 0x7c, 0x8c, 0x1c, 0x2a, 0x21, 0x6f, 0xe6, 0xca, 0x4a, 0x2c, 0x59, 0x5f, - 0x84, 0xbd, 0x16, 0x69, 0x57, 0xe6, 0x10, 0x63, 0xf2, 0xef, 0xb3, 0x4e, - 0x78, 0x12, 0xb1, 0x07, 0x5a, 0xd8, 0xe8, 0x54, 0x32, 0x07, 0xfe, 0xc5, - 0x22, 0x75, 0xdd, 0x8a, 0x1c, 0xe9, 0x24, 0x57, 0x55, 0x21, 0xfc, 0xa7, - 0x92, 0xfd, 0x41, 0x2b, 0x86, 0x7f, 0x95, 0x52, 0x25, 0x6e, 0xfd, 0xda, - 0x00, 0x32, 0x8d, 0xfe, 0x0e, 0xf8, 0xca, 0x99, 0xfe, 0xf4, 0x8d, 0xc8, - 0x66, 0x37, 0x88, 0x96, 0xa1, 0xdb, 0x35, 0xc4, 0x0e, 0xfd, 0x72, 0x09, - 0xb6, 0x69, 0x77, 0x2d, 0xe6, 0xbe, 0xb4, 0xfb, 0xa4, 0x33, 0x30, 0xb1, - 0xe6, 0x54, 0x65, 0xb5, 0xdd, 0x3d, 0xa9, 0xed, 0x50, 0xd6, 0x0a, 0x55, - 0xfa, 0x76, 0x7c, 0x09, 0xbe, 0x5a, 0x6d, 0xf7, 0xa7, 0x1e, 0xdf, 0xec, - 0x4a, 0xeb, 0xeb, 0x55, 0x69, 0xd9, 0x15, 0x75, 0xb7, 0x92, 0x09, 0xc8, - 0xad, 0x62, 0x1f, 0xc6, 0x64, 0xe0, 0xd7, 0xed, 0xa9, 0xc7, 0x2f, 0x76, - 0xef, 0x47, 0xce, 0xcb, 0x67, 0xb5, 0x4a, 0x08, 0x9b, 0x5f, 0xbb, 0xd7, - 0x96, 0x50, 0x36, 0x06, 0xae, 0xd4, 0x92, 0x29, 0xe9, 0x0c, 0x24, 0x7e, - 0x6a, 0x0e, 0xfb, 0x55, 0xf0, 0x3e, 0x58, 0x94, 0xd6, 0x60, 0x6a, 0x4d, - 0x55, 0x5b, 0x12, 0x0f, 0x3a, 0xf8, 0xbb, 0xd2, 0xe8, 0xba, 0xee, 0xc5, - 0x6e, 0x8b, 0xfc, 0xae, 0x55, 0xf5, 0xdd, 0x43, 0xfd, 0x9b, 0x8c, 0x2d, - 0xc8, 0x19, 0xfd, 0x9e, 0xaa, 0x3a, 0xd2, 0x2c, 0x95, 0x20, 0xc3, 0x82, - 0x4d, 0xa8, 0xeb, 0x3c, 0xf6, 0x4d, 0xc7, 0xd6, 0x80, 0xfe, 0x2b, 0x4a, - 0x3b, 0x5a, 0x84, 0x9d, 0x60, 0x77, 0xaf, 0x28, 0x1b, 0xe1, 0xa7, 0xfa, - 0xd9, 0x28, 0x80, 0x8f, 0xf4, 0xfd, 0x35, 0x60, 0x51, 0x0d, 0x26, 0x7d, - 0x39, 0x2c, 0xcb, 0x29, 0xec, 0x9b, 0xf2, 0x75, 0xa0, 0x03, 0xf9, 0x26, - 0xc0, 0xd7, 0x00, 0x5f, 0x49, 0x4e, 0x1b, 0xde, 0x09, 0xf0, 0xde, 0xcc, - 0x78, 0x17, 0xca, 0xcb, 0x12, 0x81, 0x67, 0xda, 0x5f, 0x86, 0x3f, 0xd7, - 0x4a, 0x0d, 0xf0, 0x36, 0xa0, 0x03, 0xc6, 0x44, 0x5a, 0x4e, 0x85, 0x72, - 0x83, 0xf2, 0xb3, 0xcc, 0x25, 0x23, 0xb3, 0x05, 0x99, 0xd0, 0x2b, 0x71, - 0x21, 0x67, 0x09, 0xe3, 0x07, 0xba, 0x9d, 0x00, 0xb3, 0x4a, 0x7c, 0x7e, - 0x47, 0xab, 0x2a, 0xe2, 0xb8, 0x12, 0xfa, 0x6d, 0xe1, 0xfb, 0x88, 0xd4, - 0x91, 0xa3, 0x2a, 0x9c, 0x90, 0xa6, 0x67, 0x59, 0xaa, 0x6a, 0x4b, 0x13, - 0x51, 0x1c, 0xaf, 0x3a, 0x66, 0x6e, 0x0d, 0x71, 0xa6, 0xaa, 0x5b, 0x76, - 0x5a, 0x4f, 0x0a, 0xa0, 0x19, 0xc1, 0xfc, 0x38, 0x6c, 0x30, 0x09, 0xda, - 0x5f, 0x62, 0x7e, 0x06, 0xf8, 0x3b, 0x09, 0x1a, 0x8e, 0xcc, 0x23, 0xda, - 0x85, 0xf4, 0x15, 0xe8, 0x98, 0xcf, 0x55, 0x60, 0x9b, 0xe1, 0xd4, 0xca, - 0x7d, 0x0c, 0x9a, 0xc4, 0xc9, 0x72, 0x73, 0x38, 0xdf, 0xf2, 0x75, 0x1f, - 0xeb, 0xd7, 0xbe, 0xa1, 0xe4, 0xa6, 0xbe, 0x18, 0x32, 0x86, 0xe5, 0xd3, - 0x46, 0x18, 0x4f, 0xda, 0x06, 0x23, 0x72, 0xac, 0xe0, 0xc8, 0x5a, 0x72, - 0xf9, 0xe0, 0x7a, 0x68, 0xd9, 0x9d, 0xc5, 0x03, 0xd2, 0x2a, 0x05, 0x51, - 0x1d, 0xfe, 0xee, 0x24, 0xcc, 0x8d, 0x09, 0x9c, 0x3b, 0x40, 0xd4, 0x4d, - 0xe3, 0x39, 0xbe, 0x17, 0x3c, 0xf0, 0x63, 0x0b, 0xb2, 0x38, 0x22, 0x66, - 0x92, 0x00, 0x3a, 0xc2, 0x1e, 0xe1, 0x82, 0x77, 0x84, 0xf1, 0x58, 0xe2, - 0x1a, 0x6b, 0xd4, 0x65, 0xd4, 0xa8, 0x20, 0x6a, 0x66, 0xb9, 0xf2, 0x2e, - 0x6c, 0xdb, 0x4e, 0x58, 0x6f, 0xca, 0xc8, 0x15, 0xd6, 0x1b, 0xe6, 0x07, - 0x63, 0x25, 0xc7, 0x67, 0xf0, 0x84, 0xcc, 0x4f, 0x37, 0xc3, 0xe9, 0x5a, - 0x86, 0xc1, 0x4b, 0xd0, 0x43, 0xeb, 0x27, 0x80, 0xbf, 0xed, 0xc8, 0xc4, - 0x67, 0xcb, 0x57, 0xb7, 0xf4, 0xf4, 0x2c, 0x6d, 0xae, 0xf5, 0x89, 0x68, - 0x19, 0xb4, 0x7f, 0x83, 0xbd, 0x56, 0x80, 0xc1, 0xc4, 0x6d, 0xee, 0x5d, - 0x75, 0x6b, 0xdd, 0x7d, 0xd0, 0xc5, 0x07, 0x36, 0xc2, 0x06, 0x06, 0xab, - 0x47, 0x91, 0xef, 0xcc, 0xf9, 0xc0, 0x5f, 0x13, 0xce, 0xcb, 0xa8, 0xc2, - 0x7b, 0x13, 0x7e, 0xea, 0x54, 0x8e, 0x5a, 0x8d, 0xed, 0x31, 0x27, 0xab, - 0xf9, 0x13, 0x0a, 0x75, 0xa8, 0x59, 0x22, 0xdf, 0x08, 0xf8, 0xf6, 0x81, - 0x67, 0x14, 0x6b, 0x05, 0x8c, 0xc3, 0x72, 0x0c, 0xe6, 0x63, 0x2f, 0x1f, - 0x7b, 0xad, 0x88, 0x53, 0x7d, 0x05, 0xf8, 0x33, 0xe3, 0x37, 0xe4, 0x57, - 0x76, 0x5a, 0x63, 0xe9, 0x9b, 0xef, 0x0c, 0xf9, 0xc6, 0x17, 0xdb, 0xe4, - 0xe0, 0x23, 0x59, 0x4c, 0x11, 0x57, 0x1f, 0xce, 0xd6, 0x4b, 0xc0, 0xc7, - 0x6f, 0x66, 0xf8, 0xef, 0x12, 0x2b, 0xe5, 0x8c, 0xc1, 0xca, 0x11, 0x62, - 0x25, 0x70, 0xa5, 0xb5, 0x04, 0x7b, 0x47, 0x1f, 0x03, 0x5f, 0xea, 0xf0, - 0xc4, 0x6f, 0xbb, 0x0e, 0xe2, 0xca, 0x06, 0x3f, 0xeb, 0xf8, 0x77, 0xa1, - 0x5b, 0xe0, 0x7d, 0x0c, 0xbc, 0x89, 0x8f, 0x31, 0x0f, 0xb4, 0x46, 0xae, - 0x03, 0xab, 0x66, 0xcb, 0xa7, 0x10, 0xf7, 0x36, 0x70, 0x02, 0x15, 0x19, - 0xfb, 0xe6, 0x35, 0x37, 0xaf, 0xff, 0xfc, 0xbd, 0x6f, 0xc1, 0xcd, 0xa8, - 0x93, 0x47, 0x21, 0x63, 0xc6, 0x3f, 0x02, 0x3f, 0x6e, 0x2c, 0x7d, 0x19, - 0xcf, 0x1f, 0x33, 0x1e, 0xad, 0x1b, 0x15, 0xee, 0x2b, 0xd2, 0xe8, 0xd3, - 0x0e, 0x11, 0xec, 0x60, 0x30, 0x08, 0x39, 0x1f, 0x21, 0xe7, 0x45, 0x9a, - 0xc4, 0x0a, 0x60, 0x18, 0x71, 0x6f, 0x03, 0xf4, 0xaa, 0x52, 0x84, 0x5d, - 0x11, 0x4b, 0x4a, 0x5c, 0xa7, 0x7a, 0xcc, 0xed, 0x80, 0xb6, 0x50, 0x5d, - 0x75, 0xb7, 0xc2, 0x17, 0x73, 0xdb, 0x03, 0xc7, 0xc4, 0xaa, 0xa5, 0x7e, - 0xce, 0xe8, 0x1e, 0xcf, 0xe8, 0x56, 0x86, 0xe9, 0x30, 0xdf, 0xc8, 0xe6, - 0x63, 0xcc, 0xcf, 0x65, 0x36, 0x67, 0x3d, 0x70, 0x51, 0xa3, 0x59, 0x0b, - 0x02, 0xdf, 0x57, 0x88, 0xb5, 0x3b, 0xd6, 0x81, 0xa5, 0x21, 0xec, 0x16, - 0x65, 0x7a, 0x92, 0x12, 0x63, 0x72, 0xf8, 0xac, 0xa3, 0x28, 0x34, 0xbb, - 0xf1, 0x89, 0xdf, 0xdb, 0xd9, 0x3e, 0xa4, 0x25, 0x5e, 0x0f, 0xd3, 0x22, - 0x8d, 0x42, 0xd6, 0xd4, 0xdb, 0xd9, 0xec, 0x00, 0xd6, 0x90, 0xf3, 0x89, - 0x2d, 0x8f, 0x3a, 0xcc, 0xef, 0xc3, 0x05, 0x73, 0x0e, 0xd6, 0xe0, 0x9d, - 0x29, 0x83, 0x33, 0x2b, 0xdd, 0x22, 0x80, 0x7d, 0x5c, 0x8e, 0x23, 0x9f, - 0x9f, 0x85, 0xef, 0x2f, 0x46, 0x0a, 0x9d, 0x06, 0x6b, 0x8e, 0x46, 0x1c, - 0x06, 0xc6, 0x17, 0xb5, 0x70, 0x03, 0x91, 0xfc, 0x8a, 0x5c, 0x5b, 0x1c, - 0x93, 0xc2, 0x25, 0xea, 0xe0, 0x88, 0xb3, 0x39, 0xbc, 0xcf, 0x02, 0xf6, - 0x99, 0x02, 0x06, 0x3e, 0x82, 0xfa, 0x52, 0x12, 0x67, 0x16, 0x58, 0x9b, - 0xb8, 0x56, 0x1d, 0xf2, 0xd5, 0x25, 0x9e, 0x9f, 0x18, 0xec, 0x66, 0xb5, - 0x8d, 0xb9, 0x55, 0x14, 0xbb, 0xf7, 0x67, 0xe4, 0xae, 0x92, 0xf5, 0x8a, - 0xd6, 0x47, 0xa2, 0xf7, 0x60, 0x5f, 0xcc, 0x6d, 0x72, 0xed, 0x26, 0xe6, - 0x39, 0x47, 0x19, 0x8c, 0xc5, 0x03, 0xa8, 0x6b, 0xd8, 0xf3, 0x18, 0x79, - 0x8a, 0xa2, 0x7a, 0xc4, 0x7f, 0x8c, 0x9b, 0x7c, 0xe7, 0x99, 0x88, 0x6d, - 0x36, 0xc6, 0x31, 0x8c, 0x3c, 0xd3, 0x47, 0x99, 0xaf, 0xf8, 0xac, 0xb5, - 0x53, 0x1d, 0x97, 0x7a, 0x37, 0x04, 0xc6, 0xce, 0x94, 0x8f, 0x0b, 0xd7, - 0xf0, 0xde, 0xe7, 0xbc, 0x37, 0x34, 0x8f, 0xe7, 0xbe, 0xd1, 0x59, 0x9c, - 0xdd, 0xde, 0x67, 0x03, 0x86, 0x2d, 0x60, 0x1f, 0xf6, 0x39, 0xac, 0x7f, - 0x06, 0xb7, 0xe6, 0xd9, 0xb7, 0x5c, 0xee, 0xb2, 0x16, 0x3a, 0xcc, 0xcb, - 0x7b, 0x94, 0x1c, 0x90, 0x7a, 0x29, 0x3f, 0x17, 0xe2, 0x38, 0x22, 0xff, - 0x34, 0xfb, 0x19, 0x8d, 0xbc, 0x2b, 0xdb, 0xa6, 0x6f, 0x9c, 0x89, 0xd9, - 0x3f, 0x5c, 0xee, 0x23, 0x97, 0x7b, 0x5a, 0x9a, 0xa9, 0x2c, 0x6f, 0x15, - 0xfd, 0x6f, 0xed, 0x35, 0xd6, 0x40, 0xda, 0xf9, 0x5e, 0xf8, 0x06, 0x18, - 0xbd, 0xe9, 0xc8, 0xc5, 0x6e, 0x2a, 0x8b, 0x39, 0xf5, 0x42, 0x26, 0xaf, - 0x21, 0x7f, 0x80, 0x1c, 0xf6, 0x25, 0xec, 0x31, 0xd1, 0x53, 0x9e, 0x73, - 0x20, 0x8f, 0x36, 0xc0, 0xb5, 0xa0, 0x37, 0x9f, 0xe9, 0x1b, 0x80, 0xce, - 0x81, 0x4d, 0x69, 0x4b, 0xca, 0x62, 0xac, 0xfd, 0x5b, 0x13, 0x3f, 0x50, - 0x37, 0xb0, 0x07, 0xde, 0x07, 0x23, 0xe0, 0x99, 0x92, 0x57, 0x13, 0x83, - 0xa5, 0xde, 0x09, 0x60, 0x52, 0xa3, 0xfb, 0x8f, 0xbc, 0xb6, 0xc4, 0x6d, - 0xe0, 0xeb, 0xf3, 0x32, 0x2e, 0xce, 0xce, 0xb8, 0xbc, 0x80, 0x5e, 0xb0, - 0xd0, 0x43, 0x1d, 0x87, 0x0d, 0xd5, 0xd9, 0xd6, 0x3c, 0xfb, 0xb9, 0xb7, - 0xd8, 0x17, 0x55, 0xc2, 0xc8, 0xb6, 0x66, 0xe5, 0xcc, 0xcf, 0x82, 0xf9, - 0x6d, 0x93, 0xaf, 0x58, 0xdf, 0xf1, 0xe5, 0x74, 0x3f, 0x94, 0x33, 0x7d, - 0x0f, 0x7a, 0x79, 0xbb, 0x3d, 0xaf, 0x0a, 0x89, 0xa7, 0x0d, 0xfc, 0x89, - 0x97, 0x3c, 0x17, 0x6c, 0x5c, 0xa5, 0x4d, 0xd8, 0xe3, 0xd2, 0x7f, 0xc4, - 0xaf, 0xa3, 0x78, 0x1e, 0x13, 0x1b, 0x67, 0x52, 0x3d, 0xda, 0x82, 0xf6, - 0x1f, 0xee, 0x93, 0x89, 0x6d, 0x9e, 0xe9, 0x1d, 0x9b, 0x49, 0x9e, 0x7b, - 0x79, 0x2e, 0x32, 0xcf, 0x1d, 0x6b, 0x19, 0xf6, 0xba, 0x1e, 0x31, 0x1f, - 0x6f, 0xe9, 0xeb, 0xa6, 0x3f, 0xf3, 0xd8, 0x33, 0x0f, 0xf5, 0x67, 0x79, - 0x5f, 0xc3, 0x78, 0x2c, 0x0f, 0xe5, 0xe3, 0x0d, 0x93, 0x8b, 0x57, 0x90, - 0x97, 0xaf, 0x27, 0x65, 0x93, 0x93, 0x87, 0x0e, 0xdf, 0x2e, 0x27, 0x7f, - 0xfd, 0x15, 0x72, 0xf2, 0xed, 0x2c, 0x27, 0x47, 0x4c, 0xdc, 0xaa, 0xde, - 0xf0, 0xda, 0x6f, 0xb0, 0xc6, 0x39, 0xde, 0x37, 0x58, 0x43, 0xd1, 0xff, - 0x3f, 0x4c, 0x1f, 0xe5, 0xfe, 0x49, 0xe3, 0xb0, 0xee, 0x90, 0x06, 0x3e, - 0xec, 0x8d, 0x8b, 0x7d, 0x96, 0x39, 0x9b, 0xc7, 0x8c, 0x8f, 0x58, 0xcd, - 0xf9, 0xd1, 0x4f, 0x1e, 0x63, 0x2c, 0x14, 0x4c, 0x5e, 0xd8, 0xd5, 0x9c, - 0xa6, 0x2c, 0xcb, 0xe8, 0xd5, 0xde, 0xe3, 0xd8, 0x4f, 0x63, 0x65, 0xa4, - 0xe7, 0xca, 0x4b, 0x73, 0xc4, 0xa6, 0x20, 0xba, 0x06, 0x9d, 0xaf, 0x87, - 0x25, 0x29, 0xcc, 0x32, 0x5f, 0x59, 0x6d, 0x46, 0x10, 0x43, 0xb8, 0x77, - 0x25, 0xfa, 0x24, 0xfa, 0x29, 0xdf, 0x81, 0x9f, 0x5f, 0x47, 0x1c, 0x11, - 0x3b, 0x11, 0x13, 0xf3, 0x9b, 0x88, 0x89, 0xe3, 0x7c, 0x37, 0xfb, 0x16, - 0x0c, 0xad, 0x6d, 0xf6, 0x2f, 0x41, 0x7f, 0x57, 0x8a, 0xe7, 0x34, 0xee, - 0x5b, 0x9f, 0xf3, 0x9d, 0x36, 0xf1, 0x0b, 0xac, 0xc0, 0xfc, 0xba, 0x89, - 0x5f, 0xfa, 0x34, 0xf0, 0x88, 0xf3, 0x7f, 0x32, 0xb9, 0xf1, 0xa1, 0xc9, - 0xf1, 0xeb, 0x91, 0x89, 0xe7, 0x88, 0xfd, 0xe4, 0xe9, 0xfe, 0xfb, 0x05, - 0x83, 0x01, 0xc8, 0x8f, 0x53, 0x91, 0x89, 0xb5, 0xf9, 0x2b, 0x38, 0xf6, - 0x9b, 0x69, 0x2e, 0x0c, 0xc9, 0x99, 0xf6, 0x1e, 0x4b, 0x73, 0xcb, 0xdf, - 0x30, 0x77, 0x8a, 0x19, 0xf4, 0x43, 0xa0, 0xeb, 0xef, 0xc5, 0x83, 0x49, - 0x8c, 0xb4, 0xf7, 0x27, 0x90, 0xeb, 0xc1, 0x86, 0x94, 0x43, 0xbd, 0xa9, - 0xd7, 0xb8, 0x84, 0x67, 0x73, 0x9d, 0x3e, 0x31, 0xba, 0xfc, 0xaf, 0x3c, - 0xac, 0xef, 0xdc, 0x8e, 0xcf, 0x1b, 0xe2, 0xfb, 0xeb, 0x6d, 0xf8, 0xb0, - 0xbe, 0x43, 0x9e, 0xb1, 0xdd, 0x5e, 0xa2, 0xbe, 0x1b, 0xd7, 0x31, 0xe2, - 0x9e, 0xbc, 0x7b, 0xef, 0x79, 0xc3, 0x39, 0x90, 0xd7, 0x70, 0xc6, 0x39, - 0xf7, 0xcc, 0x63, 0x3d, 0x8f, 0xf1, 0x3c, 0xe6, 0xf3, 0x58, 0x0f, 0xa2, - 0xe7, 0x24, 0xf5, 0xaf, 0xd3, 0x0b, 0xb0, 0xff, 0xd8, 0x1d, 0xee, 0x26, - 0x5f, 0x56, 0x8f, 0x24, 0xfe, 0xfc, 0x1e, 0xf8, 0xfb, 0xac, 0x67, 0x74, - 0x99, 0x6b, 0xf8, 0xb3, 0x4f, 0xbf, 0x89, 0xfa, 0x1f, 0x65, 0xb6, 0x8d, - 0xb3, 0x31, 0xa5, 0x49, 0xfb, 0xbd, 0x9f, 0x64, 0x98, 0xfb, 0xfd, 0xb4, - 0xbe, 0x48, 0x9e, 0x53, 0xcc, 0x21, 0x93, 0x53, 0x3c, 0x0f, 0xee, 0xe8, - 0x5a, 0xaf, 0xc2, 0x8f, 0x2f, 0x45, 0x79, 0x1e, 0x21, 0x9e, 0x0e, 0xe7, - 0x39, 0x0e, 0x3b, 0x85, 0xb7, 0xb4, 0x33, 0x1b, 0xc3, 0x66, 0xbc, 0x17, - 0x37, 0xd0, 0x1b, 0xd1, 0x4e, 0x2b, 0xd6, 0x13, 0xbb, 0x77, 0xe1, 0xbd, - 0x7d, 0x10, 0xed, 0x46, 0xbb, 0x0e, 0xdb, 0x2d, 0x88, 0x26, 0x15, 0x31, - 0xe0, 0x76, 0x38, 0x91, 0xd7, 0x6b, 0x60, 0xd0, 0x6c, 0x6e, 0xa7, 0xaf, - 0x5c, 0xb3, 0xe3, 0xf4, 0x3b, 0xc2, 0x5e, 0x7c, 0xd8, 0xb4, 0x87, 0xf0, - 0xe1, 0x36, 0x3d, 0x25, 0x65, 0xd0, 0x06, 0xa8, 0x5f, 0xa6, 0xcf, 0x60, - 0x0f, 0x79, 0x4b, 0xdb, 0xa6, 0x9f, 0x24, 0x36, 0xb2, 0x8f, 0xec, 0x8c, - 0xc8, 0xd8, 0x3e, 0xf3, 0x1e, 0x6f, 0x73, 0x64, 0x4c, 0x48, 0x5a, 0x97, - 0x8c, 0xfe, 0xcf, 0x64, 0xfa, 0xa7, 0x3a, 0x8b, 0xba, 0x13, 0xa6, 0x51, - 0x57, 0x0f, 0xba, 0x3e, 0x94, 0xdb, 0xa5, 0xa5, 0xaa, 0x27, 0xa4, 0x51, - 0x31, 0x77, 0x5b, 0xdc, 0xa5, 0xa0, 0xc3, 0x12, 0xf5, 0x28, 0x43, 0x8f, - 0x71, 0xdc, 0x3d, 0x82, 0x95, 0x96, 0x04, 0xf1, 0x1a, 0x08, 0xe7, 0x7e, - 0x4a, 0xbb, 0x3d, 0xed, 0x6e, 0x75, 0x69, 0xb7, 0x27, 0xdd, 0x4e, 0x77, - 0x1a, 0xfd, 0x5f, 0x00, 0x6f, 0x07, 0xf3, 0x97, 0x84, 0x31, 0xb6, 0x10, - 0x71, 0x3c, 0x2d, 0xec, 0xb7, 0x9e, 0x76, 0x67, 0xfa, 0x1c, 0x9f, 0x74, - 0xc3, 0xfe, 0xb0, 0xdc, 0xbf, 0x68, 0x60, 0x62, 0x7c, 0x03, 0x79, 0xf4, - 0xea, 0x20, 0xdd, 0x1b, 0xf7, 0xbf, 0x4c, 0x2e, 0xe6, 0x92, 0x5c, 0xb6, - 0x10, 0xa7, 0x28, 0x1b, 0x72, 0xa7, 0xa3, 0xdf, 0x99, 0x3d, 0x78, 0xff, - 0xb9, 0xd3, 0x1e, 0x77, 0xe7, 0xdf, 0x2e, 0x90, 0x3b, 0x05, 0x83, 0x3d, - 0x1b, 0x09, 0xee, 0xcc, 0x25, 0xad, 0x9b, 0xe1, 0x87, 0xb0, 0x1d, 0x7a, - 0x80, 0x45, 0x0f, 0x7f, 0xe0, 0xea, 0x2a, 0xd7, 0xd0, 0x67, 0xe3, 0xae, - 0xc7, 0xfb, 0xda, 0x46, 0xc2, 0x35, 0xc6, 0x38, 0x7a, 0xc1, 0xc5, 0x8f, - 0x40, 0xfb, 0x81, 0x6e, 0x0d, 0x94, 0xb9, 0x8f, 0xab, 0x10, 0xf7, 0xac, - 0x01, 0xfb, 0x15, 0xb1, 0x1a, 0x89, 0xf8, 0xcd, 0x68, 0xc9, 0xdc, 0xc7, - 0x62, 0xcf, 0xe7, 0x9d, 0x13, 0x3d, 0xe6, 0xe2, 0x50, 0x8f, 0xb9, 0x88, - 0x1e, 0xf3, 0x9e, 0x22, 0xe2, 0x3c, 0xc6, 0x3d, 0x53, 0x35, 0xd3, 0xbc, - 0x99, 0xe0, 0x9d, 0xb2, 0x5d, 0x92, 0x7d, 0xe8, 0x9e, 0xa0, 0x5b, 0x88, - 0xfd, 0xb9, 0x7e, 0x30, 0xfb, 0xee, 0x85, 0x4d, 0xc7, 0x62, 0xd3, 0x6f, - 0xb5, 0x4b, 0x23, 0xa8, 0xff, 0xa4, 0xb9, 0x2f, 0xa3, 0x79, 0x6e, 0x0f, - 0xcd, 0xd7, 0x78, 0x46, 0xca, 0x96, 0xe6, 0x1b, 0xcc, 0x3b, 0xd6, 0xd2, - 0x91, 0x2c, 0xdf, 0x4e, 0xe0, 0xb9, 0x98, 0x3d, 0xe7, 0xf4, 0x87, 0xf7, - 0xf0, 0x3f, 0xa2, 0xd2, 0x77, 0x3e, 0x53, 0xe7, 0x98, 0x7d, 0x30, 0xe4, - 0x2d, 0x59, 0xe9, 0xb7, 0x92, 0xf3, 0x38, 0x3b, 0x7d, 0x92, 0xf6, 0x17, - 0xc0, 0x60, 0x74, 0x57, 0x33, 0xb0, 0xbb, 0xd6, 0xed, 0x25, 0xe2, 0xda, - 0xc2, 0xfc, 0x11, 0x83, 0x6f, 0x6a, 0x4a, 0x49, 0x8e, 0xb9, 0xc3, 0xcf, - 0x18, 0x97, 0xcc, 0x37, 0x01, 0xbc, 0xa7, 0x32, 0xb6, 0x70, 0x3f, 0x16, - 0xe4, 0x70, 0xcb, 0xe8, 0x65, 0xa5, 0xf7, 0x1e, 0xaf, 0xc6, 0x7a, 0x80, - 0xba, 0xf1, 0x20, 0xf5, 0xda, 0xfd, 0x76, 0xb1, 0x86, 0x5a, 0xf3, 0x2e, - 0x62, 0x1f, 0xf9, 0x69, 0x7a, 0xa8, 0x2d, 0xf3, 0xed, 0x00, 0x75, 0x08, - 0xd7, 0xa0, 0x4e, 0xb8, 0xfb, 0x0d, 0x41, 0x2e, 0x80, 0xe6, 0x22, 0xd6, - 0x4e, 0xf7, 0xf3, 0x9e, 0x16, 0x7d, 0x3c, 0x70, 0x6f, 0x3d, 0xfc, 0x97, - 0x6e, 0x96, 0x86, 0x69, 0xf9, 0xfb, 0x2f, 0xb4, 0x78, 0xd5, 0x79, 0x38, + 0xbd, 0x58, 0x5d, 0x6c, 0x1c, 0x57, 0x15, 0x3e, 0x73, 0xe7, 0xee, 0x7a, + 0x6d, 0x39, 0xf1, 0xb8, 0x99, 0x96, 0x4d, 0x63, 0xd4, 0x99, 0x78, 0xfc, + 0x43, 0x6d, 0x95, 0x69, 0x59, 0x15, 0x17, 0x56, 0x68, 0xba, 0xbb, 0x71, + 0xad, 0xaa, 0xaa, 0x5c, 0x29, 0x88, 0x4a, 0x8d, 0x90, 0x59, 0x37, 0x6d, + 0x79, 0x4b, 0x11, 0x0f, 0x48, 0x45, 0xca, 0xb2, 0x76, 0xd2, 0x08, 0x2d, + 0x99, 0xd6, 0x85, 0x44, 0x42, 0x7d, 0x88, 0x9c, 0x3a, 0xee, 0xc3, 0xca, + 0x9b, 0x8a, 0x07, 0x24, 0xa4, 0xa8, 0x55, 0x80, 0xc0, 0x1b, 0x7d, 0xa8, + 0xf8, 0x79, 0x22, 0x12, 0x0f, 0x54, 0x08, 0x90, 0x85, 0x04, 0x2a, 0xa5, + 0xe4, 0xf2, 0x7d, 0x77, 0x67, 0x92, 0xc5, 0x4d, 0x41, 0xe5, 0x81, 0x95, + 0x56, 0x77, 0xe6, 0xde, 0x73, 0xce, 0x3d, 0xf7, 0xfc, 0x7c, 0xe7, 0xdc, + 0x39, 0xec, 0xc8, 0x88, 0x64, 0xbf, 0x7d, 0xf8, 0x57, 0xbe, 0x72, 0xe2, + 0xeb, 0x0f, 0xdc, 0x57, 0xb9, 0x0f, 0x8f, 0x0f, 0x3a, 0x77, 0x6b, 0x2d, + 0xff, 0xc7, 0x9f, 0x2b, 0xe2, 0xe5, 0x7a, 0xf0, 0x2f, 0x25, 0x55, 0x4d, + 0x0e, 0xd6, 0x22, 0x29, 0xb9, 0xd5, 0xea, 0xfc, 0x6a, 0x24, 0x92, 0x74, + 0xe7, 0x82, 0xba, 0xfc, 0xd3, 0xb4, 0x7c, 0x2d, 0x9c, 0xff, 0x64, 0xf5, + 0x83, 0x4f, 0x5f, 0xf9, 0x6c, 0xb8, 0x7b, 0xc1, 0x95, 0x92, 0x57, 0x3d, + 0xa3, 0xbd, 0x69, 0x29, 0x4d, 0x80, 0xe7, 0xd5, 0x99, 0x6f, 0x17, 0x64, + 0x7f, 0x2e, 0xab, 0x65, 0x54, 0x74, 0xdd, 0x5c, 0x99, 0x89, 0xbc, 0x36, + 0x36, 0xb8, 0xdc, 0x0b, 0xa4, 0xd6, 0x2b, 0xcb, 0x9b, 0x3d, 0x5f, 0xde, + 0xe8, 0x69, 0x39, 0xfe, 0xca, 0x49, 0x59, 0x8f, 0xc3, 0x72, 0xc3, 0x2d, + 0x89, 0xaa, 0x86, 0xe5, 0xa6, 0x04, 0xb2, 0x15, 0x87, 0xad, 0x15, 0x77, + 0xdc, 0x29, 0x55, 0x4b, 0xf2, 0xc2, 0x8c, 0x92, 0x0b, 0xfe, 0x31, 0x79, + 0x26, 0x7a, 0x12, 0x7f, 0x2d, 0x6a, 0x43, 0x3b, 0xf5, 0xf3, 0x5a, 0xf4, + 0xc6, 0x98, 0x3c, 0x12, 0x1b, 0xb3, 0x1a, 0x27, 0xe0, 0x9f, 0x9c, 0x7d, + 0x56, 0x86, 0xa5, 0xe5, 0x85, 0x4b, 0x22, 0x05, 0xd2, 0x48, 0x2d, 0x2e, + 0x48, 0xe2, 0xf5, 0xcf, 0x75, 0xc1, 0x8e, 0x1f, 0x98, 0x2d, 0xf0, 0x0f, + 0x47, 0xf9, 0xfa, 0x1d, 0xd9, 0xba, 0x97, 0xad, 0x2b, 0x51, 0xe7, 0xc2, + 0x60, 0x5b, 0xa6, 0x12, 0xed, 0xdc, 0x30, 0xb5, 0xe8, 0x2e, 0xaf, 0xb6, + 0xad, 0xc5, 0xdd, 0xa0, 0xfe, 0x91, 0x57, 0x17, 0x03, 0x1e, 0x97, 0x3c, + 0x5a, 0x55, 0xbf, 0x06, 0xbf, 0x4d, 0x25, 0xca, 0x11, 0xb9, 0xda, 0x29, + 0x7b, 0xb5, 0xde, 0x37, 0x9c, 0x5a, 0x7a, 0xc3, 0x24, 0x7a, 0x44, 0x54, + 0x94, 0x38, 0xb5, 0x6d, 0xca, 0x1a, 0x16, 0x1d, 0x0d, 0x81, 0x67, 0xd2, + 0x53, 0xc2, 0xb1, 0x96, 0xcd, 0x53, 0x76, 0x03, 0xcf, 0x8b, 0x4e, 0xb2, + 0xad, 0x9d, 0xda, 0xf9, 0x25, 0x3c, 0x97, 0xc0, 0x0f, 0xbb, 0xc4, 0x8e, + 0x24, 0xcb, 0x0e, 0xf8, 0x78, 0x4e, 0x0f, 0xef, 0x4a, 0x12, 0xdf, 0x93, + 0xb5, 0x4a, 0x58, 0x6e, 0xc9, 0xa3, 0x4e, 0x7d, 0xfb, 0x43, 0x4e, 0xf3, + 0x96, 0x7a, 0x1f, 0x9e, 0xa3, 0x2e, 0x0f, 0x6b, 0x63, 0xd4, 0xfd, 0x43, + 0xd9, 0x19, 0x29, 0x2f, 0xe9, 0xeb, 0xef, 0xf3, 0x1d, 0x3a, 0xa7, 0xd0, + 0xbd, 0x5b, 0x84, 0x3e, 0xc6, 0x70, 0x9f, 0x5a, 0x54, 0x87, 0x9e, 0x09, + 0xfe, 0xe1, 0x99, 0x26, 0x42, 0xe1, 0xf0, 0xb9, 0x7d, 0x12, 0x8c, 0x1b, + 0xd3, 0x88, 0x43, 0x6f, 0x5b, 0x26, 0x64, 0x2d, 0x9d, 0xf0, 0x8e, 0xa4, + 0x6d, 0xac, 0xb7, 0x48, 0x03, 0x7b, 0x88, 0x1c, 0xe9, 0x1a, 0x73, 0x29, + 0x3e, 0x50, 0x94, 0xfd, 0x6a, 0xbe, 0x20, 0x61, 0x90, 0x60, 0xee, 0xf0, + 0xa5, 0xbd, 0x36, 0xbb, 0x27, 0xd3, 0x81, 0x76, 0xc7, 0x3e, 0xf1, 0xa1, + 0xec, 0x7d, 0xd4, 0xab, 0x9d, 0xcf, 0xed, 0x6c, 0xf5, 0x86, 0x5d, 0x63, + 0xa9, 0x55, 0xa0, 0xff, 0x47, 0x9e, 0x29, 0xe7, 0xa3, 0x2e, 0xd4, 0x1b, + 0xf4, 0xd1, 0x2d, 0x9d, 0x9e, 0xfa, 0x90, 0x4e, 0xd4, 0x47, 0x89, 0x3e, + 0x57, 0x92, 0xf5, 0xe8, 0x71, 0x25, 0xfb, 0x8d, 0x59, 0x8f, 0xb5, 0xd3, + 0x38, 0x7f, 0x2c, 0x7b, 0x46, 0x1c, 0xa6, 0x88, 0xc3, 0x14, 0x71, 0x99, + 0x8a, 0xa7, 0xaa, 0x81, 0x5c, 0x99, 0x29, 0xc9, 0x75, 0x17, 0xfe, 0xec, + 0xcd, 0x79, 0xaf, 0x21, 0xa6, 0x12, 0xcf, 0x11, 0x37, 0x4a, 0x66, 0x0b, + 0xc2, 0x77, 0xc4, 0x92, 0x4e, 0xca, 0x2e, 0x62, 0x29, 0x39, 0xca, 0xb9, + 0x21, 0x59, 0xb1, 0x67, 0x99, 0xf3, 0x4e, 0x09, 0x7d, 0x55, 0xc3, 0xda, + 0x64, 0x70, 0x4a, 0x76, 0x11, 0x1f, 0x35, 0xac, 0x53, 0x56, 0xe8, 0xb5, + 0x40, 0xd1, 0x4e, 0xdf, 0x45, 0x0e, 0xf8, 0x88, 0xfb, 0x99, 0xb2, 0x12, + 0x47, 0x56, 0xe7, 0x61, 0x8b, 0xf9, 0x29, 0xd8, 0x88, 0x39, 0xc1, 0xb8, + 0xfa, 0xeb, 0xb4, 0x8e, 0x4e, 0x22, 0x7e, 0x40, 0x8b, 0xf3, 0x9f, 0x4a, + 0x67, 0xc0, 0x1f, 0x15, 0xa9, 0xe7, 0x56, 0xac, 0x65, 0x3d, 0xbd, 0xa2, + 0x0a, 0xd1, 0xef, 0x1d, 0xd9, 0x1f, 0xb6, 0x12, 0x09, 0x5b, 0x4a, 0x29, + 0x9f, 0x5b, 0xbf, 0x84, 0x3c, 0x7a, 0xd3, 0xea, 0xaf, 0xc1, 0x57, 0xce, + 0xf4, 0xa7, 0xdd, 0x45, 0x36, 0x3b, 0x61, 0xbc, 0x08, 0xdd, 0xae, 0xc2, + 0xff, 0xb4, 0xf9, 0xa5, 0x2e, 0x64, 0x77, 0x1c, 0xe6, 0xae, 0xb4, 0xbb, + 0xa4, 0xb3, 0x69, 0xbe, 0xa2, 0xab, 0xb2, 0xdc, 0xee, 0x9c, 0x34, 0x6e, + 0x24, 0x2b, 0x85, 0x2a, 0xfd, 0x36, 0xba, 0x00, 0x3f, 0x2c, 0xb7, 0xbb, + 0x13, 0x8f, 0x6d, 0x76, 0xa4, 0x75, 0x77, 0x55, 0x5a, 0x6e, 0x45, 0xdd, + 0xa5, 0x64, 0x0c, 0x72, 0xab, 0xd8, 0x87, 0x71, 0x15, 0x06, 0x75, 0x77, + 0xe2, 0xb1, 0x8b, 0x9d, 0x7b, 0x90, 0xb7, 0xf2, 0x41, 0xad, 0x12, 0x21, + 0x77, 0xaf, 0x1e, 0x74, 0x25, 0x92, 0xb5, 0x5e, 0x49, 0x6a, 0xe9, 0x84, + 0xac, 0xf7, 0x24, 0x79, 0x6a, 0x06, 0xfb, 0x55, 0xf0, 0xde, 0x9b, 0x97, + 0x56, 0x6f, 0x62, 0x45, 0x55, 0x5b, 0x92, 0xf4, 0xd6, 0xf1, 0x2f, 0x49, + 0xa3, 0x53, 0x2a, 0x5d, 0xec, 0xb4, 0xc8, 0x5f, 0x72, 0xaa, 0x81, 0x3e, + 0xdc, 0xdd, 0x65, 0xdc, 0x40, 0xce, 0xf0, 0x97, 0x54, 0x55, 0x4b, 0xd3, + 0xf7, 0x21, 0xc3, 0x81, 0x4d, 0xa8, 0xeb, 0x2c, 0xf6, 0xed, 0x8f, 0xad, + 0x1e, 0x7d, 0x37, 0x24, 0xed, 0x78, 0x1e, 0x76, 0x62, 0xd4, 0x0e, 0xc9, + 0x5a, 0xf4, 0x9e, 0x79, 0x1a, 0xb1, 0xfa, 0x9a, 0x98, 0x7b, 0x6a, 0xc0, + 0x93, 0x1a, 0x4c, 0xfa, 0x42, 0x54, 0x96, 0x53, 0xd8, 0xb7, 0xcf, 0xb7, + 0x0e, 0x1d, 0xc8, 0x37, 0x06, 0xbe, 0x06, 0xf8, 0x7c, 0x39, 0x6d, 0x79, + 0xc7, 0xc0, 0xbb, 0x9b, 0xf1, 0xce, 0x95, 0x17, 0x25, 0x06, 0xcf, 0x64, + 0xb0, 0x08, 0x7f, 0xae, 0xf8, 0x0d, 0xf0, 0x36, 0xa0, 0x03, 0xc6, 0x54, + 0x5a, 0xba, 0x42, 0xb9, 0x61, 0xf9, 0x69, 0xe6, 0x83, 0x95, 0xd9, 0x82, + 0x4c, 0xe8, 0x95, 0x96, 0x20, 0x67, 0x01, 0xe3, 0x3b, 0xa6, 0x9d, 0x02, + 0x77, 0x7c, 0x3e, 0xbf, 0x69, 0x54, 0x15, 0x31, 0x5a, 0x89, 0x82, 0xb6, + 0xf0, 0xbd, 0x28, 0x75, 0xe4, 0x99, 0x8a, 0xc6, 0xa4, 0xe9, 0x39, 0x8e, + 0xaa, 0xba, 0xd2, 0x44, 0x84, 0x26, 0xcb, 0xda, 0xce, 0xad, 0x20, 0xce, + 0x54, 0xf5, 0x7b, 0xaa, 0x5f, 0x0f, 0x0a, 0xa0, 0x41, 0x6e, 0x46, 0xa3, + 0xb0, 0xc1, 0x38, 0x68, 0xcf, 0x62, 0x7e, 0x0a, 0xf8, 0x39, 0x0e, 0x1a, + 0x8e, 0xcc, 0x11, 0xda, 0x85, 0xf4, 0x15, 0xe8, 0x98, 0xcf, 0x55, 0x60, + 0x9b, 0xc1, 0xb4, 0xc9, 0x7d, 0x0c, 0x9a, 0x54, 0x67, 0x79, 0x37, 0x98, + 0x4b, 0xf9, 0x7a, 0x80, 0xf5, 0xab, 0x9f, 0x52, 0xb2, 0x6b, 0x2e, 0x46, + 0x8c, 0x61, 0x79, 0xaf, 0x11, 0x25, 0xe3, 0xae, 0xcd, 0xf3, 0x3c, 0xdf, + 0x39, 0xb2, 0x16, 0x9c, 0x39, 0xb8, 0x1a, 0x39, 0xee, 0xfa, 0xfc, 0x01, + 0x69, 0xf9, 0x61, 0x5c, 0x87, 0xbf, 0xd7, 0x53, 0xe6, 0xc6, 0x18, 0xce, + 0x1d, 0x22, 0xea, 0x26, 0xf1, 0x9c, 0x1c, 0x04, 0x0f, 0xfc, 0xd8, 0x82, + 0x2c, 0x8e, 0x88, 0x99, 0x34, 0x84, 0x8e, 0xb0, 0x47, 0x34, 0xe7, 0x1d, + 0x61, 0x3c, 0xfa, 0x5c, 0x63, 0x8d, 0x79, 0xf5, 0x50, 0x2d, 0x0a, 0xe3, + 0x66, 0x96, 0x2b, 0x6f, 0xc1, 0xb6, 0xed, 0x94, 0xf5, 0x22, 0xaf, 0x11, + 0xcc, 0x0f, 0xc6, 0x4a, 0x8e, 0xb1, 0xe0, 0x89, 0x98, 0x9f, 0xa5, 0x0c, + 0x6b, 0x6b, 0x19, 0x8e, 0x2e, 0x40, 0x0f, 0x63, 0x9e, 0x00, 0x86, 0xb6, + 0x63, 0x1b, 0x9f, 0xad, 0x40, 0xdd, 0x30, 0x93, 0xd3, 0xb4, 0xb9, 0x31, + 0x27, 0xe2, 0x45, 0xd0, 0xfe, 0x16, 0xf6, 0x5a, 0x02, 0x8e, 0x12, 0x7b, + 0xb9, 0x77, 0x55, 0xd7, 0x3a, 0xfb, 0xa0, 0x4b, 0x00, 0x7c, 0x83, 0x0d, + 0x2c, 0xde, 0x0e, 0x23, 0xdf, 0x99, 0xf3, 0x61, 0xb0, 0x22, 0x9c, 0x97, + 0x61, 0x85, 0xf7, 0x26, 0xfc, 0xb4, 0x5e, 0x79, 0xd4, 0x69, 0x6c, 0xbf, + 0x9f, 0xf9, 0x48, 0xc6, 0x14, 0x6a, 0x49, 0xd3, 0x27, 0x5f, 0x11, 0x7c, + 0xfb, 0xc0, 0xf3, 0x77, 0xac, 0x15, 0x30, 0x0e, 0xca, 0xb1, 0xb8, 0x8d, + 0xbd, 0x02, 0xec, 0xb5, 0x24, 0xba, 0xfa, 0x3c, 0xb0, 0x67, 0x2a, 0x68, + 0xc8, 0xf7, 0x55, 0xbf, 0x46, 0xd2, 0x37, 0x5f, 0x18, 0xf0, 0x4d, 0x20, + 0xae, 0xcd, 0xc1, 0x87, 0xb2, 0x98, 0x22, 0x66, 0x3e, 0x98, 0xad, 0xfb, + 0xc0, 0xbe, 0xcf, 0x64, 0x18, 0x5e, 0x22, 0x0e, 0xca, 0x19, 0x8b, 0x83, + 0x45, 0xe2, 0x20, 0x70, 0xa5, 0xb5, 0x00, 0x7b, 0xc7, 0xef, 0x02, 0x5f, + 0xea, 0xf0, 0xc4, 0x4f, 0x3a, 0x1a, 0x71, 0xe5, 0x82, 0x9f, 0x75, 0xf8, + 0xf3, 0xae, 0x8c, 0x84, 0xde, 0xbb, 0xc0, 0x9b, 0xe4, 0x28, 0xf3, 0xc0, + 0x18, 0xe4, 0x3a, 0xb0, 0x6a, 0xba, 0x7c, 0x0a, 0x71, 0xef, 0x02, 0x27, + 0xb4, 0x70, 0xdf, 0xbc, 0x6e, 0xe6, 0xf5, 0x9b, 0xbf, 0xb7, 0x1d, 0xb8, + 0x19, 0xb5, 0xee, 0x73, 0x90, 0x31, 0x15, 0x1c, 0x81, 0x1f, 0xd7, 0x16, + 0xfe, 0x1b, 0xcf, 0x6f, 0x32, 0x1e, 0xd4, 0x90, 0x0a, 0xf7, 0x15, 0x69, + 0x74, 0x69, 0x87, 0x18, 0x76, 0xb0, 0x18, 0x84, 0x9c, 0x8f, 0x91, 0xf3, + 0x22, 0x4d, 0x62, 0x05, 0x30, 0x8c, 0xb8, 0xb7, 0x06, 0x7a, 0x55, 0x19, + 0x82, 0x5d, 0x11, 0x4b, 0x4a, 0x4a, 0xba, 0x7a, 0x54, 0xaf, 0x83, 0xb6, + 0x50, 0x5d, 0xd6, 0x5b, 0xd1, 0x31, 0x37, 0xef, 0x97, 0xda, 0x1d, 0x71, + 0x6a, 0x7d, 0x3f, 0x67, 0x74, 0x8f, 0x65, 0x74, 0x4b, 0x83, 0x74, 0x98, + 0x6f, 0x64, 0xf3, 0x09, 0xe6, 0x3f, 0x91, 0xd9, 0x9c, 0xb5, 0xa0, 0x84, + 0x3a, 0xcb, 0x3a, 0x10, 0x06, 0x81, 0xfa, 0x4f, 0x75, 0x60, 0x61, 0x00, + 0xbb, 0x45, 0xd9, 0xbe, 0xc2, 0x67, 0x4c, 0x0e, 0x9e, 0x75, 0x58, 0x49, + 0x74, 0x33, 0x3e, 0xf1, 0xdb, 0xcc, 0xf6, 0x21, 0x2d, 0xf1, 0x7a, 0x90, + 0x16, 0x69, 0x04, 0xbb, 0xa8, 0xb3, 0xb7, 0xb3, 0xd9, 0x01, 0xac, 0x21, + 0xe7, 0x53, 0x57, 0x1e, 0xd6, 0xcc, 0xef, 0x7b, 0xb5, 0x3d, 0xc7, 0x0e, + 0xe8, 0x77, 0x26, 0x2c, 0xce, 0x2c, 0x75, 0x86, 0x20, 0x7e, 0x54, 0x8e, + 0x23, 0x9f, 0x9f, 0x86, 0xef, 0x2f, 0xc6, 0x0a, 0xdd, 0x02, 0x6b, 0x8e, + 0x41, 0x1c, 0x86, 0xd6, 0x17, 0xb5, 0x68, 0x0d, 0x91, 0xfc, 0x2d, 0xb9, + 0x3a, 0x3f, 0x22, 0x85, 0x4b, 0xd4, 0x01, 0xfd, 0xd2, 0xe6, 0xe0, 0x3e, + 0x73, 0xd8, 0x67, 0x02, 0x18, 0x78, 0x3f, 0xea, 0x8b, 0x2f, 0x7a, 0x1a, + 0x58, 0x9b, 0x96, 0x9c, 0x3a, 0xe4, 0xab, 0x4b, 0x3c, 0x3f, 0x31, 0xb8, + 0x94, 0xd5, 0x36, 0xe6, 0xd6, 0x10, 0x6a, 0xfa, 0x1f, 0x91, 0xbb, 0x4a, + 0x56, 0x2b, 0xc6, 0x1c, 0x89, 0x7f, 0x00, 0xfb, 0x62, 0x6e, 0x93, 0x6b, + 0xbb, 0x98, 0xe7, 0x1c, 0x65, 0x30, 0x16, 0x0f, 0xa0, 0xae, 0x61, 0xcf, + 0xa3, 0xe4, 0x19, 0x42, 0xcd, 0x27, 0xfe, 0x63, 0xdc, 0xe4, 0x3b, 0xcf, + 0x44, 0x6c, 0x73, 0x31, 0x8e, 0x60, 0xe4, 0x99, 0x7e, 0x91, 0xf9, 0x8a, + 0xcf, 0xc6, 0xe8, 0xea, 0xa8, 0xd4, 0x3b, 0x11, 0x30, 0x76, 0xaa, 0x7c, + 0x5c, 0xb8, 0x86, 0xf7, 0x2e, 0xe7, 0xbd, 0x81, 0x79, 0x3c, 0x77, 0xad, + 0xce, 0xa8, 0xed, 0x79, 0xff, 0xb2, 0x06, 0xc3, 0xa2, 0xc7, 0xd8, 0x64, + 0xaf, 0xc2, 0xfa, 0x67, 0x71, 0x6b, 0x96, 0x7d, 0xca, 0xeb, 0x1d, 0xd6, + 0x42, 0xcd, 0xbc, 0x44, 0x00, 0x1c, 0x92, 0xba, 0x9f, 0x9f, 0x0b, 0x71, + 0x1c, 0x53, 0x36, 0x65, 0x4c, 0xc2, 0x76, 0xec, 0x47, 0xa2, 0xb2, 0x76, + 0xa6, 0x92, 0x26, 0xf9, 0xba, 0x05, 0x29, 0x6c, 0xcc, 0x8b, 0x7b, 0xd6, + 0xc8, 0x66, 0x5f, 0x9e, 0xb7, 0x2c, 0xbe, 0xd4, 0x5e, 0xa2, 0x1e, 0x98, + 0xdf, 0x61, 0x3d, 0x0c, 0x81, 0x67, 0xc5, 0x6c, 0xdf, 0xb2, 0x34, 0x3b, + 0x91, 0xd7, 0x10, 0x8c, 0xdd, 0x3b, 0xe0, 0xbb, 0x22, 0xce, 0xac, 0xe5, + 0x62, 0xa7, 0xbf, 0x17, 0x73, 0xee, 0xb9, 0xb8, 0xbf, 0x57, 0x43, 0x7e, + 0x89, 0xbd, 0xc4, 0x57, 0xc2, 0x3e, 0x12, 0x7d, 0xe3, 0x39, 0x8d, 0xfd, + 0x68, 0xa3, 0x02, 0x7a, 0xdb, 0xd9, 0xec, 0x3c, 0x21, 0xe8, 0x34, 0x6c, + 0x4e, 0x5b, 0x73, 0x0f, 0xc6, 0xe2, 0x3f, 0x0c, 0xf1, 0x05, 0x75, 0x05, + 0xfa, 0xe2, 0xbd, 0xc7, 0x3d, 0x26, 0xe4, 0xc5, 0xd4, 0x62, 0xad, 0x77, + 0x02, 0x98, 0xd5, 0xe8, 0xfc, 0x2d, 0xaf, 0x3d, 0x49, 0x1b, 0xf8, 0xfb, + 0xac, 0x8c, 0x8a, 0xde, 0x19, 0x95, 0xe7, 0xd0, 0xef, 0x15, 0x36, 0x50, + 0xe7, 0x61, 0x63, 0x75, 0xb6, 0x35, 0xcb, 0x9e, 0xed, 0x32, 0x72, 0x79, + 0xb5, 0x12, 0xc5, 0xae, 0x33, 0x2d, 0x67, 0xbe, 0x1b, 0xce, 0x6e, 0xdb, + 0x7c, 0xc6, 0xfa, 0x4e, 0x20, 0xa7, 0xbb, 0x91, 0x9c, 0xe9, 0x7a, 0xd0, + 0xcb, 0xbb, 0xd5, 0xd7, 0x46, 0xc4, 0xdb, 0x06, 0xfe, 0xc4, 0x53, 0x9e, + 0x0b, 0x3e, 0xa8, 0xd2, 0x6e, 0xec, 0x63, 0xe9, 0x5f, 0xe2, 0xdb, 0xa3, + 0x78, 0x1e, 0x11, 0xf7, 0x1c, 0xfb, 0x4e, 0xc6, 0x24, 0xfd, 0x33, 0xd8, + 0x0b, 0x13, 0xfb, 0x20, 0x73, 0x87, 0xb9, 0x9f, 0xe7, 0x66, 0x9e, 0xab, + 0xc4, 0x01, 0xed, 0x2c, 0xc2, 0x5e, 0xd7, 0x62, 0xe6, 0xeb, 0x0d, 0x73, + 0xcd, 0xf6, 0x6e, 0x1e, 0xfb, 0xe2, 0x81, 0xde, 0x2d, 0xef, 0x7b, 0x18, + 0xaf, 0xe5, 0x81, 0x7c, 0xbd, 0x6e, 0x73, 0xf5, 0x0d, 0xe4, 0xed, 0xcb, + 0x69, 0xd9, 0xe6, 0xec, 0xe1, 0x07, 0x6e, 0x97, 0xb3, 0x97, 0x3f, 0x46, + 0xce, 0xfe, 0x30, 0xcb, 0xd9, 0xa2, 0x8d, 0x6b, 0xb5, 0x31, 0xb8, 0xf6, + 0x23, 0xac, 0x0d, 0x65, 0x77, 0x0a, 0x6d, 0x3b, 0xe8, 0xc3, 0x0f, 0xd2, + 0x47, 0xb9, 0x7f, 0xfa, 0x71, 0x5a, 0xd7, 0xa4, 0x81, 0x0f, 0x37, 0x46, + 0x11, 0x4f, 0xcc, 0xe9, 0x3c, 0x9e, 0x02, 0xc4, 0x72, 0xce, 0x8f, 0x7e, + 0xf3, 0x28, 0x63, 0xa1, 0x60, 0xf3, 0xc6, 0xad, 0xe6, 0x34, 0x65, 0x59, + 0x44, 0x2f, 0xf7, 0x63, 0x8e, 0xdd, 0x7e, 0xac, 0x14, 0x37, 0x4a, 0xf2, + 0xfc, 0x0c, 0xb1, 0x2b, 0x8c, 0xaf, 0x42, 0xe7, 0x6b, 0x91, 0x2f, 0x85, + 0x69, 0xe6, 0x33, 0xab, 0x51, 0x11, 0x31, 0x84, 0xbb, 0x55, 0x6a, 0x4e, + 0xa2, 0xdf, 0x0a, 0x34, 0xfc, 0xfc, 0x32, 0xe2, 0x88, 0xd8, 0x8a, 0x98, + 0x98, 0xdd, 0x44, 0x4c, 0x1c, 0xe7, 0xbb, 0xdd, 0xb7, 0x60, 0x69, 0x5d, + 0xbb, 0xbf, 0x0f, 0xfd, 0x4b, 0x32, 0x74, 0xce, 0xe0, 0x4e, 0x75, 0x8b, + 0xef, 0xb4, 0x8d, 0x5f, 0x60, 0x09, 0xe6, 0x57, 0x6d, 0xfc, 0xd2, 0xa7, + 0x8c, 0x7b, 0x63, 0x7e, 0x67, 0xf3, 0xe6, 0xd7, 0x16, 0x03, 0xae, 0xc5, + 0x36, 0x9e, 0x63, 0xf6, 0x9b, 0xa7, 0xbb, 0x3f, 0xd7, 0x16, 0x23, 0x36, + 0x8c, 0x9c, 0x8a, 0x6d, 0xac, 0xcd, 0xbe, 0x81, 0x63, 0xbf, 0xd6, 0xcf, + 0x85, 0x01, 0x39, 0x93, 0xde, 0x23, 0x90, 0x83, 0x9a, 0x17, 0xac, 0xb1, + 0x3f, 0x88, 0xa7, 0xd0, 0x2f, 0x81, 0xae, 0xbb, 0x17, 0x2f, 0xc6, 0x31, + 0xd2, 0xde, 0x7f, 0x80, 0x5c, 0x0f, 0x36, 0xa4, 0x1c, 0xea, 0x4d, 0xbd, + 0x46, 0x25, 0x3a, 0x9b, 0xeb, 0xf4, 0x17, 0xab, 0xcb, 0xbf, 0xcb, 0xc3, + 0xfa, 0xce, 0xed, 0xf8, 0xbc, 0x01, 0xbe, 0x3f, 0xdf, 0x86, 0x0f, 0xeb, + 0x3b, 0xe4, 0x19, 0xb9, 0xd9, 0x6b, 0xd4, 0x6f, 0xc6, 0x75, 0x82, 0xb8, + 0x27, 0xef, 0xde, 0xbb, 0xdc, 0x60, 0x0e, 0xe4, 0x35, 0x9e, 0x71, 0xce, + 0x3d, 0xf3, 0x58, 0xcf, 0x63, 0x3c, 0x8f, 0xf9, 0x3c, 0xd6, 0xc3, 0xf8, + 0x19, 0xe9, 0xfb, 0x57, 0x6f, 0x84, 0xd8, 0x7f, 0xe4, 0x7f, 0xb8, 0xb7, + 0x10, 0x23, 0x24, 0xb9, 0x75, 0xd7, 0xfb, 0x69, 0xd6, 0xaf, 0x94, 0x98, + 0x6b, 0xf8, 0xb3, 0x8f, 0xdf, 0x45, 0x7f, 0x10, 0x67, 0xb6, 0x4d, 0xb2, + 0xb1, 0x4f, 0xd3, 0xef, 0x07, 0xbf, 0x9a, 0x61, 0xf2, 0x17, 0xfb, 0xf5, + 0x47, 0xf2, 0x9c, 0x62, 0x0e, 0xd9, 0x9c, 0xe2, 0x79, 0x70, 0x0f, 0x37, + 0x66, 0x19, 0x7e, 0x7c, 0x3e, 0xce, 0xf3, 0x08, 0xf1, 0xf4, 0x40, 0x9e, + 0xe3, 0xb0, 0x53, 0x74, 0xc3, 0xe8, 0xe9, 0x04, 0x36, 0xe3, 0xdd, 0xb7, + 0x81, 0xde, 0x89, 0x76, 0x5a, 0x72, 0x9e, 0xb8, 0x79, 0xdf, 0xdd, 0xdb, + 0x27, 0xd1, 0x6e, 0xb4, 0xeb, 0xa0, 0xdd, 0xc2, 0x78, 0x5c, 0x11, 0x03, + 0x6e, 0x87, 0x13, 0x79, 0x3d, 0x07, 0x06, 0x4d, 0xe7, 0x76, 0xfa, 0xd8, + 0x35, 0x3d, 0xe9, 0x7f, 0x2b, 0xd8, 0x8b, 0x0f, 0xdb, 0xee, 0x00, 0x3e, + 0xdc, 0xa6, 0xe7, 0xa4, 0x0c, 0xda, 0x00, 0xf5, 0xcd, 0xf6, 0x21, 0xec, + 0x31, 0x6f, 0x18, 0xd7, 0xf6, 0x9b, 0xc4, 0x46, 0xf6, 0x99, 0xdf, 0x2c, + 0xc8, 0xc8, 0x3e, 0xfb, 0x9e, 0x6c, 0x73, 0x64, 0x4c, 0x48, 0xbf, 0x6e, + 0x59, 0xfd, 0x1f, 0xcf, 0xf4, 0xef, 0xeb, 0x2c, 0xea, 0xa3, 0x30, 0x8d, + 0xba, 0x7a, 0xd0, 0x35, 0xcc, 0xed, 0xd2, 0x52, 0xd5, 0x13, 0xd2, 0xa8, + 0xb0, 0x5f, 0x12, 0xdc, 0xb5, 0xa0, 0xc3, 0x02, 0xf5, 0x28, 0x43, 0x8f, + 0x51, 0xdc, 0x4d, 0xc2, 0xa5, 0x96, 0x84, 0xc9, 0x0a, 0x08, 0x67, 0xbe, + 0x43, 0xbb, 0x1d, 0xd3, 0x5b, 0x1d, 0xda, 0xed, 0x49, 0xbd, 0xde, 0x99, + 0x44, 0x7f, 0x18, 0xc2, 0xdb, 0xe1, 0xec, 0x25, 0x61, 0x8c, 0xcd, 0xc5, + 0x1c, 0x4f, 0x0b, 0xfb, 0xb1, 0x63, 0x7a, 0xaa, 0xcb, 0xf1, 0x49, 0x1d, + 0x75, 0x07, 0xe5, 0xfe, 0xc9, 0x00, 0x13, 0x93, 0xeb, 0xc8, 0xa3, 0x17, + 0x7b, 0xfd, 0xbd, 0x71, 0x3f, 0xcc, 0xe4, 0x62, 0x2e, 0xcd, 0x65, 0x0b, + 0x71, 0x8a, 0xb2, 0x21, 0x77, 0x32, 0xfe, 0x99, 0xdd, 0x83, 0xf7, 0xa3, + 0x8f, 0xda, 0xe3, 0xae, 0xfc, 0xfb, 0x04, 0x72, 0xa7, 0x60, 0xb1, 0x67, + 0x2d, 0xc5, 0x9d, 0xda, 0x37, 0xa6, 0x19, 0xbd, 0x0d, 0xdb, 0xa1, 0x47, + 0x98, 0xf7, 0xf0, 0x07, 0xae, 0x2e, 0x73, 0x0d, 0x7d, 0x38, 0xee, 0x82, + 0xbc, 0xcf, 0xad, 0xa5, 0x5c, 0x63, 0x8c, 0xa3, 0x57, 0x9c, 0xff, 0x15, + 0x68, 0xdf, 0x31, 0xad, 0x9e, 0xb2, 0xf7, 0x75, 0x15, 0xe1, 0x1e, 0xd6, + 0x63, 0x3f, 0x23, 0x4e, 0x23, 0x95, 0xa0, 0x19, 0x2f, 0xd8, 0xfb, 0x5a, + 0xe2, 0x05, 0xbc, 0x93, 0xa2, 0x07, 0x9d, 0x1f, 0xe8, 0x41, 0xe7, 0xd1, + 0x83, 0x8e, 0x15, 0x11, 0xe7, 0x09, 0xee, 0xa1, 0xaa, 0xd9, 0xcf, 0x9b, + 0x31, 0xde, 0x39, 0xdb, 0xbe, 0xec, 0x43, 0x77, 0x05, 0xdd, 0x22, 0xec, + 0xcf, 0xf5, 0x3b, 0xb3, 0xef, 0x5a, 0xa3, 0xa0, 0x4f, 0x6c, 0x3f, 0xd6, + 0xf6, 0x8b, 0xd2, 0x8c, 0x49, 0x73, 0x28, 0xa3, 0xf9, 0xf2, 0x1e, 0x9a, + 0x3b, 0x79, 0x46, 0xca, 0x96, 0xe6, 0x2b, 0xcc, 0x3b, 0xd6, 0xd2, 0x62, + 0x96, 0x6f, 0x27, 0xf0, 0x3c, 0x94, 0x3d, 0xe7, 0xf4, 0xf7, 0xee, 0xe1, + 0x7f, 0xc8, 0xe9, 0xbf, 0xf3, 0x99, 0x3a, 0x27, 0xec, 0x93, 0x21, 0x6f, + 0xc1, 0xe9, 0x7f, 0x27, 0xc1, 0x85, 0x73, 0x84, 0x3e, 0xe9, 0xf7, 0x17, + 0xc0, 0x60, 0x74, 0x5f, 0x53, 0xb0, 0xbb, 0x31, 0xed, 0x05, 0xe2, 0xda, + 0xdc, 0xec, 0x11, 0x8b, 0x6f, 0x6a, 0x42, 0x49, 0x8e, 0xb9, 0x83, 0xcf, + 0x18, 0x17, 0xec, 0x37, 0x03, 0xbc, 0xf7, 0x65, 0x6c, 0xe1, 0xfe, 0x2c, + 0xc8, 0xe1, 0x96, 0xd5, 0xcb, 0xe9, 0xdf, 0x8b, 0xbc, 0x1a, 0xeb, 0x01, + 0xea, 0xc6, 0x0c, 0xf5, 0xba, 0xf9, 0x6d, 0x63, 0x05, 0xb5, 0xe6, 0x2d, + 0xc4, 0x3e, 0xf2, 0xd3, 0xf6, 0x58, 0x5b, 0xf6, 0xdb, 0x02, 0xea, 0xd0, + 0x08, 0xee, 0x4b, 0xd1, 0xcd, 0x6f, 0x0c, 0x72, 0x01, 0x34, 0x17, 0xb1, + 0x76, 0xba, 0x9b, 0xf7, 0xbc, 0xe8, 0xf3, 0x81, 0x7b, 0xab, 0xd1, 0xfb, + 0xa6, 0xe9, 0x0f, 0xd2, 0xf2, 0xf7, 0x2f, 0x97, 0xa2, 0x15, 0x3a, 0x18, 0x15, 0x00, 0x00, 0x00 }; static const u32 bnx2_TPAT_b09FwData[(0x0/4) + 1] = { 0x0 }; @@ -3681,15 +3691,15 @@ static const u32 bnx2_TPAT_b09FwRodata[(0x4/4) + 1] = { 0x00000001, 0x00000000 }; static struct fw_info bnx2_tpat_fw_09 = { - /* Firmware version: 4.0.5 */ + /* Firmware version: 4.4.26 */ .ver_major = 0x4, - .ver_minor = 0x0, - .ver_fix = 0x5, + .ver_minor = 0x4, + .ver_fix = 0x1a, - .start_addr = 0x08000888, + .start_addr = 0x08000488, - .text_addr = 0x08000800, - .text_len = 0x1534, + .text_addr = 0x08000400, + .text_len = 0x1514, .text_index = 0x0, .gz_text = bnx2_TPAT_b09FwText, .gz_text_len = sizeof(bnx2_TPAT_b09FwText), @@ -3699,863 +3709,871 @@ static struct fw_info bnx2_tpat_fw_09 = { .data_index = 0x0, .data = bnx2_TPAT_b09FwData, - .sbss_addr = 0x08001d60, + .sbss_addr = 0x08001940, .sbss_len = 0x48, .sbss_index = 0x0, - .bss_addr = 0x08001da8, - .bss_len = 0x10a0, + .bss_addr = 0x08001988, + .bss_len = 0x12b4, .bss_index = 0x0, - .rodata_addr = 0x08001d34, + .rodata_addr = 0x08001914, .rodata_len = 0x4, .rodata_index = 0x0, .rodata = bnx2_TPAT_b09FwRodata, }; static u8 bnx2_TXP_b09FwText[] = { - 0xa5, 0x7b, 0x0b, 0x74, 0x1c, 0x55, 0x7a, 0xe6, 0x77, 0xab, 0xba, 0xa5, - 0xea, 0x56, 0xab, 0x55, 0x92, 0xdb, 0xa6, 0x95, 0xd1, 0xe0, 0x2e, 0x77, - 0xb5, 0xdc, 0x58, 0xc2, 0x54, 0xcb, 0x2d, 0xd3, 0x44, 0xe5, 0xb8, 0xc7, - 0x08, 0x5b, 0x06, 0x4d, 0x46, 0x38, 0xca, 0xac, 0x98, 0xc3, 0x2e, 0x1d, - 0x63, 0x83, 0x30, 0x06, 0x04, 0xc3, 0x66, 0x95, 0x2c, 0x89, 0x6a, 0xe4, - 0x07, 0x7e, 0xb4, 0xba, 0xf5, 0x32, 0x32, 0xd9, 0x9c, 0xb8, 0x2d, 0xc9, - 0x96, 0x81, 0x7e, 0xc0, 0x00, 0x33, 0x43, 0x76, 0x67, 0xe9, 0x35, 0x60, - 0x0c, 0x8c, 0x61, 0x92, 0x3d, 0x67, 0x97, 0xc9, 0x99, 0x49, 0x7c, 0x30, - 0x78, 0x6c, 0xde, 0x9b, 0x99, 0xdd, 0x15, 0x09, 0x93, 0xda, 0xff, 0xaf, - 0x96, 0x8c, 0x61, 0xd8, 0x24, 0x9b, 0xd5, 0x39, 0x7d, 0x4a, 0x5d, 0x75, - 0xeb, 0xde, 0xff, 0xfd, 0x7f, 0xff, 0x7f, 0x6f, 0x47, 0x00, 0x2f, 0x16, - 0xfe, 0x6a, 0xe9, 0x13, 0x1f, 0x18, 0x7c, 0xb0, 0x7d, 0xb5, 0xb1, 0xda, - 0xb9, 0xe1, 0x86, 0x8b, 0x1f, 0xae, 0x15, 0x40, 0xea, 0x5d, 0xfc, 0x8b, - 0xfe, 0xbe, 0xfa, 0x2f, 0x7b, 0x0d, 0x32, 0xa0, 0x2e, 0xd2, 0xc4, 0x1f, - 0x28, 0x92, 0x99, 0xfb, 0xcd, 0x0d, 0x3a, 0x14, 0xd9, 0xec, 0x5b, 0x77, - 0xbb, 0x0e, 0x24, 0xf3, 0x2d, 0xa1, 0xeb, 0xf1, 0x2b, 0xdb, 0x0a, 0xb8, - 0xc0, 0xf7, 0xbf, 0x6a, 0x7e, 0x3a, 0xf4, 0xc3, 0x6b, 0xb5, 0x8f, 0x73, - 0x32, 0x14, 0xd5, 0x9c, 0x84, 0xda, 0x0c, 0xa5, 0x89, 0xde, 0xf9, 0xd3, - 0x95, 0xdf, 0x77, 0xc1, 0xbf, 0x38, 0x17, 0x2c, 0xb7, 0x69, 0x60, 0x57, - 0x76, 0x00, 0x73, 0x71, 0xe0, 0x42, 0x3a, 0x62, 0xec, 0x02, 0x46, 0x25, - 0x33, 0x12, 0x3a, 0x89, 0x10, 0x66, 0xf3, 0xb0, 0xaa, 0x4d, 0x1d, 0xfb, - 0x4a, 0x21, 0x5c, 0x4c, 0xff, 0x83, 0x1d, 0x72, 0x0f, 0xe0, 0xed, 0x38, - 0x94, 0xa0, 0xf9, 0x10, 0x82, 0x59, 0x28, 0xb5, 0xe6, 0x20, 0x0a, 0x23, - 0xc0, 0x9e, 0xb4, 0x36, 0x00, 0x68, 0x7d, 0x45, 0x11, 0x3e, 0x7d, 0x02, - 0x5a, 0x4f, 0xa3, 0xdc, 0x92, 0xba, 0x45, 0x68, 0xc9, 0x9d, 0x02, 0x8a, - 0xa0, 0xb1, 0xab, 0xf2, 0x7c, 0x1d, 0x44, 0x34, 0xaf, 0xe0, 0xac, 0xcc, - 0xcb, 0x9a, 0x24, 0x67, 0x01, 0x97, 0x6e, 0x60, 0x4f, 0x16, 0x96, 0xcb, - 0x14, 0xd8, 0x15, 0x8f, 0xa8, 0x33, 0xe0, 0xe7, 0x21, 0x0c, 0x3b, 0xe3, - 0x34, 0xe2, 0xd8, 0xb6, 0x77, 0x1b, 0xb6, 0x7d, 0xcc, 0xa8, 0x86, 0xa5, - 0x6a, 0x41, 0x40, 0x60, 0xd8, 0x90, 0x90, 0x54, 0x37, 0x84, 0x5c, 0xd0, - 0x82, 0xdb, 0xf1, 0xf7, 0xc4, 0x6f, 0x32, 0xea, 0x46, 0x65, 0x7c, 0x0a, - 0xd5, 0x28, 0xab, 0x15, 0x89, 0x4d, 0xa7, 0x6d, 0xfb, 0x94, 0xee, 0xc2, - 0x31, 0x92, 0xcd, 0x70, 0xfe, 0xef, 0xed, 0x32, 0xc9, 0x65, 0xb7, 0xbe, - 0xb8, 0xbe, 0x82, 0x9c, 0x6a, 0xdb, 0x33, 0xf4, 0x6c, 0x6f, 0x7e, 0x51, - 0xc6, 0xb6, 0x2d, 0xe9, 0xb6, 0x7d, 0xbb, 0xfe, 0x77, 0xf6, 0xd6, 0xcf, - 0x8d, 0x8d, 0xe1, 0xf1, 0x51, 0x15, 0x4f, 0x64, 0x93, 0xc8, 0xa7, 0x6d, - 0xc8, 0xa6, 0x0b, 0xfd, 0x23, 0x21, 0xec, 0x2c, 0x74, 0xa2, 0x90, 0xd6, - 0x52, 0x67, 0xe9, 0xbd, 0xad, 0x71, 0x1d, 0xf7, 0x14, 0xba, 0x30, 0x97, - 0x86, 0xed, 0x31, 0xf5, 0xb2, 0x47, 0x44, 0x71, 0x67, 0xa1, 0x1b, 0xc5, - 0xb4, 0x7e, 0x7a, 0x58, 0x44, 0x06, 0x1b, 0x65, 0x17, 0xee, 0x2b, 0xb4, - 0xe2, 0xde, 0x42, 0x82, 0xde, 0xb1, 0x71, 0x63, 0xac, 0x89, 0xc6, 0xb7, - 0xe1, 0xb1, 0x49, 0xdb, 0x8e, 0xc6, 0x54, 0xf4, 0x17, 0x0c, 0xcc, 0x8d, - 0x4a, 0x48, 0x1d, 0x73, 0x21, 0x75, 0x14, 0xb8, 0xf3, 0x68, 0x1b, 0x66, - 0x46, 0x6d, 0x6c, 0x35, 0x86, 0x1b, 0x25, 0x32, 0xbb, 0x94, 0x2a, 0xe0, - 0xd6, 0xfd, 0xd8, 0xae, 0x56, 0x68, 0x3f, 0x2b, 0x0b, 0xec, 0x38, 0x1a, - 0xc5, 0x9b, 0x69, 0x0b, 0x37, 0xb6, 0x07, 0x31, 0x58, 0x08, 0xe0, 0x8d, - 0x74, 0x80, 0xd6, 0x30, 0xf0, 0x7a, 0x5a, 0xa1, 0x75, 0x5a, 0xf1, 0x62, - 0x9a, 0xc7, 0xf0, 0x58, 0x1f, 0xb6, 0x15, 0x9a, 0x70, 0x26, 0x1d, 0xa4, - 0x35, 0x03, 0x78, 0x85, 0xc6, 0xdd, 0x55, 0xd0, 0x71, 0x9a, 0xc6, 0xf5, - 0x17, 0x42, 0x78, 0x39, 0xed, 0x23, 0x5a, 0x03, 0x38, 0x99, 0x1e, 0xc0, - 0xae, 0x74, 0xcb, 0xe9, 0xeb, 0x49, 0x86, 0xa1, 0x25, 0xbc, 0x0e, 0xdf, - 0x7b, 0xdb, 0xee, 0x0e, 0x38, 0x66, 0x42, 0xeb, 0x2c, 0xae, 0x3b, 0x80, - 0xe1, 0xf4, 0x8b, 0x0b, 0x7e, 0x62, 0x60, 0xff, 0xe8, 0xbc, 0xfd, 0xc3, - 0x95, 0x4d, 0x38, 0x91, 0x05, 0x1e, 0x9b, 0x01, 0x66, 0xb2, 0x96, 0x5d, - 0x6b, 0xda, 0xf6, 0x74, 0x7b, 0x2b, 0xc9, 0x4b, 0xef, 0xdb, 0x4a, 0xa3, - 0x9e, 0x28, 0xb9, 0x80, 0xa3, 0x5a, 0x5f, 0x19, 0x12, 0x72, 0x73, 0x2e, - 0x54, 0x8d, 0x68, 0x5d, 0x39, 0x68, 0xa7, 0xef, 0x24, 0x4f, 0x3a, 0x96, - 0xd5, 0x7a, 0x2c, 0x0c, 0xd9, 0x41, 0xb3, 0x39, 0xd4, 0x2a, 0xdb, 0xf0, - 0x93, 0x2d, 0xa4, 0x5b, 0x6d, 0xbb, 0xee, 0x5a, 0xdb, 0x3e, 0xd3, 0x0e, - 0x5b, 0x32, 0xf5, 0xd3, 0x25, 0xe8, 0xe5, 0x0f, 0xa0, 0x0f, 0x9e, 0x44, - 0xf9, 0xab, 0x3e, 0x44, 0xfa, 0xc3, 0x72, 0x64, 0x60, 0x9e, 0xde, 0xad, - 0x2d, 0x90, 0x29, 0x13, 0x2f, 0x3a, 0xd9, 0x60, 0xa1, 0xa4, 0xc0, 0x45, - 0xfc, 0xb4, 0x8e, 0xd8, 0xb6, 0x4b, 0xf7, 0xc1, 0x47, 0xf2, 0xdd, 0x74, - 0xc8, 0xb6, 0xcf, 0x1b, 0x2a, 0xaa, 0x48, 0x37, 0x37, 0x8c, 0xd9, 0x98, - 0x36, 0x4e, 0x92, 0x3c, 0x05, 0x52, 0x3d, 0x71, 0x7a, 0x27, 0x40, 0xe3, - 0x13, 0xd8, 0x34, 0x12, 0xc4, 0xe3, 0x59, 0x05, 0x3f, 0x5c, 0x19, 0x45, - 0x0d, 0xcd, 0xe5, 0x25, 0x59, 0x55, 0x93, 0xfc, 0x50, 0x20, 0x73, 0x2b, - 0x54, 0xec, 0x11, 0x85, 0xb3, 0xc4, 0x63, 0x10, 0xdf, 0x2d, 0x05, 0xf0, - 0x54, 0x49, 0xc5, 0x93, 0xa5, 0x26, 0x3c, 0x5f, 0x32, 0x90, 0x1d, 0xd5, - 0xf6, 0x95, 0x61, 0xa3, 0x96, 0xcc, 0xf9, 0x8d, 0x5c, 0x0c, 0x99, 0x51, - 0xdb, 0xce, 0x13, 0xcd, 0x5e, 0xe2, 0xe1, 0xf5, 0xdc, 0x95, 0x38, 0x3e, - 0xe9, 0x42, 0x68, 0x3a, 0x80, 0x27, 0xd2, 0x2e, 0x5c, 0x95, 0xd1, 0xac, - 0x1c, 0xf4, 0xe8, 0x4e, 0xa1, 0x27, 0x57, 0x09, 0x6d, 0xd4, 0x42, 0x24, - 0xe4, 0x16, 0x12, 0x9a, 0x8f, 0xbb, 0xa0, 0x17, 0x43, 0x70, 0x37, 0x2b, - 0xd0, 0x9b, 0xc9, 0x8d, 0xfc, 0x12, 0xaa, 0xc8, 0x2f, 0x36, 0x8d, 0x47, - 0xe9, 0x5e, 0x80, 0xee, 0xe1, 0xca, 0x6a, 0xc8, 0xcb, 0x64, 0x90, 0xdc, - 0x74, 0x19, 0x49, 0x97, 0x6d, 0xcb, 0x7a, 0x1b, 0xfa, 0x1e, 0xa1, 0xeb, - 0x1a, 0x1e, 0xaf, 0x22, 0x5c, 0x24, 0x19, 0x34, 0x13, 0x4d, 0x59, 0xa2, - 0x31, 0x4b, 0x34, 0x66, 0x89, 0xc6, 0xac, 0x4c, 0x36, 0xa3, 0x19, 0xc0, - 0x1f, 0x92, 0xae, 0x42, 0xc4, 0xdf, 0x9b, 0x8e, 0x9e, 0x9e, 0x2a, 0x05, - 0x89, 0xfe, 0x90, 0x43, 0xff, 0x63, 0xa3, 0x02, 0x92, 0xae, 0xf5, 0x9c, - 0xc5, 0x7a, 0x84, 0x63, 0x5a, 0x32, 0x87, 0x24, 0xbd, 0xa7, 0xed, 0xb3, - 0xa0, 0x75, 0x95, 0x49, 0xff, 0x5b, 0xd5, 0x04, 0xe6, 0xb2, 0x6e, 0xd4, - 0xe8, 0x5a, 0x88, 0xf4, 0x15, 0x2d, 0x63, 0x09, 0xee, 0x56, 0x69, 0x4e, - 0xa9, 0x4a, 0x54, 0x62, 0xc8, 0x43, 0x88, 0x8c, 0x4b, 0x98, 0x35, 0x64, - 0xf2, 0x4f, 0x03, 0x72, 0x33, 0x2d, 0x57, 0x8c, 0xd3, 0x95, 0xe6, 0xcf, - 0xd2, 0x5a, 0x44, 0x0f, 0xcd, 0x47, 0x7e, 0xc9, 0x72, 0x8c, 0x12, 0x0d, - 0x7b, 0x1c, 0x7a, 0x9f, 0x2c, 0x75, 0x8b, 0x8a, 0xfd, 0x98, 0x64, 0x2f, - 0x5a, 0x08, 0x42, 0x8b, 0x86, 0x84, 0x66, 0x24, 0x85, 0x8a, 0x99, 0xd2, - 0x8f, 0x68, 0x4c, 0xe0, 0xb2, 0x31, 0x3d, 0x18, 0xce, 0x0a, 0x5c, 0xaf, - 0xdb, 0xd8, 0x60, 0xf4, 0x60, 0x57, 0x69, 0xd1, 0x2f, 0x39, 0x76, 0xa9, - 0xfe, 0x99, 0x74, 0x27, 0x76, 0x67, 0x43, 0xd8, 0x95, 0x0f, 0xfa, 0xa7, - 0xd3, 0xfc, 0x4c, 0x27, 0x7f, 0xe7, 0x67, 0x81, 0xcb, 0x9e, 0x35, 0x5d, - 0xf6, 0x2c, 0x81, 0xe1, 0x89, 0xaf, 0x50, 0x0c, 0xa9, 0xc3, 0x2e, 0xfd, - 0x63, 0xb2, 0x15, 0x3d, 0xb1, 0x0d, 0x8d, 0x38, 0xab, 0xb6, 0xe2, 0xe0, - 0x54, 0x37, 0x76, 0x4f, 0xad, 0xc6, 0xfe, 0x89, 0xa6, 0x94, 0xd7, 0x1c, - 0xa1, 0xf5, 0xc3, 0xc9, 0x6d, 0x42, 0x1b, 0x90, 0x45, 0x38, 0xba, 0x8d, - 0x6c, 0xb7, 0xb9, 0xde, 0xb6, 0x4f, 0xc6, 0xc8, 0xb6, 0x8d, 0x16, 0x63, - 0x13, 0x09, 0xa0, 0xdc, 0xa3, 0x75, 0xbd, 0x0d, 0x1f, 0xbe, 0x4e, 0x36, - 0x37, 0x13, 0xc3, 0x36, 0x19, 0x72, 0xab, 0x0f, 0xbf, 0xb0, 0x8f, 0xba, - 0x58, 0xee, 0xf6, 0xd0, 0xed, 0xc6, 0x1e, 0xc1, 0x71, 0xae, 0xea, 0x52, - 0x2c, 0xe1, 0xf9, 0xf9, 0x1d, 0xdb, 0x0e, 0xd3, 0x3c, 0xfd, 0xb1, 0x96, - 0x44, 0x3f, 0xe6, 0xed, 0xb3, 0xbd, 0xdd, 0xd8, 0x35, 0xb7, 0x1a, 0x07, - 0x26, 0xdc, 0x48, 0xd6, 0x0b, 0xd4, 0xe9, 0xe1, 0xf2, 0xdd, 0x58, 0x0d, - 0x6b, 0x86, 0xdf, 0xeb, 0xc6, 0xe1, 0xb9, 0xca, 0xf7, 0xec, 0xa5, 0xef, - 0x8b, 0xf3, 0x5d, 0x20, 0x9d, 0xb2, 0x3c, 0x39, 0x4e, 0x92, 0x0a, 0xcc, - 0x16, 0x9c, 0x98, 0x08, 0x90, 0x6e, 0x3b, 0x85, 0xeb, 0xf8, 0x32, 0xbf, - 0xf7, 0x11, 0x1b, 0xa7, 0x0c, 0xd2, 0x73, 0x76, 0xa3, 0xf0, 0x1e, 0xef, - 0x12, 0xee, 0xe2, 0x16, 0x51, 0x35, 0xfd, 0x2d, 0xa1, 0x1c, 0x4f, 0x89, - 0xea, 0x62, 0x2b, 0xc9, 0xbe, 0x4f, 0x78, 0x8e, 0x6b, 0xa1, 0x90, 0xf8, - 0x03, 0xd2, 0x67, 0xaf, 0x90, 0x8b, 0x50, 0x25, 0x73, 0x50, 0x48, 0x45, - 0x9a, 0xc3, 0xb1, 0x21, 0x5e, 0x27, 0x48, 0x7a, 0x83, 0x25, 0x9b, 0x03, - 0xd8, 0x4a, 0x39, 0xe2, 0xa6, 0xb4, 0x89, 0x03, 0xd9, 0x6a, 0x8a, 0x8f, - 0xec, 0xf7, 0xf3, 0xb4, 0xae, 0x8e, 0x83, 0x25, 0x58, 0x1e, 0xf3, 0x00, - 0x56, 0x93, 0xbf, 0x9d, 0x89, 0xb1, 0x2f, 0x02, 0xf9, 0x6c, 0x38, 0x79, - 0x40, 0xd8, 0x76, 0x75, 0xc4, 0x5e, 0x7e, 0xde, 0x68, 0x89, 0xbe, 0x88, - 0xff, 0x6d, 0xe7, 0x02, 0x03, 0x88, 0xb6, 0x43, 0xa9, 0x36, 0x77, 0xe3, - 0xe7, 0x69, 0x28, 0x55, 0xa6, 0x85, 0x53, 0x69, 0xc0, 0x37, 0x32, 0xac, - 0x7a, 0x41, 0x76, 0x80, 0x70, 0xf0, 0xa0, 0xd0, 0x7a, 0xce, 0x51, 0x3a, - 0x4b, 0xb4, 0x5b, 0x83, 0x12, 0x28, 0x1e, 0x09, 0xad, 0xef, 0x45, 0xb2, - 0xc7, 0x3f, 0x10, 0x9a, 0x3a, 0x2f, 0xd8, 0x4f, 0x39, 0x97, 0xec, 0x5e, - 0xc8, 0x29, 0x16, 0xae, 0xba, 0x2c, 0xa7, 0x0c, 0x13, 0x5d, 0x7b, 0x89, - 0xae, 0x97, 0x0c, 0x2d, 0x38, 0x0d, 0x7b, 0xf9, 0x36, 0x83, 0x9f, 0x99, - 0xd8, 0x5d, 0xb2, 0x43, 0x2e, 0x93, 0x65, 0x05, 0x4b, 0x31, 0x7f, 0x65, - 0x0f, 0xc7, 0x55, 0x92, 0x11, 0x79, 0x5a, 0xe1, 0xcb, 0x72, 0xad, 0x8d, - 0xe5, 0x34, 0xe6, 0x93, 0x6b, 0xe1, 0x6f, 0x2c, 0xb8, 0x52, 0x35, 0x26, - 0x7a, 0xee, 0x1b, 0xa1, 0xf8, 0xa4, 0x4b, 0x14, 0x9b, 0xf4, 0xc4, 0xbc, - 0xf0, 0x25, 0xde, 0x8f, 0x7b, 0x04, 0xc5, 0xa6, 0x54, 0xb5, 0x19, 0xec, - 0xfe, 0x20, 0xef, 0x21, 0xfd, 0xa2, 0x67, 0x67, 0x21, 0xe1, 0x7a, 0x97, - 0x6c, 0xac, 0x8a, 0x62, 0x29, 0x0a, 0x4d, 0xdd, 0x17, 0x29, 0xff, 0xdc, - 0x10, 0xf3, 0xfc, 0xab, 0x2a, 0x53, 0xba, 0xd2, 0x83, 0xfb, 0xaf, 0x99, - 0x4d, 0xd4, 0x51, 0x3c, 0x57, 0x71, 0x3a, 0xde, 0x85, 0xe1, 0x52, 0x35, - 0xd9, 0xdf, 0xd3, 0xe5, 0x3d, 0x7a, 0x53, 0xf7, 0xbb, 0xe9, 0xe5, 0xf0, - 0x99, 0xf8, 0xf4, 0x60, 0xbb, 0xde, 0x75, 0x93, 0x38, 0xd9, 0xe8, 0x41, - 0x9c, 0x6d, 0x5c, 0x99, 0x4f, 0xe3, 0xe3, 0x46, 0x5d, 0xa7, 0xdc, 0xd1, - 0x3c, 0x70, 0x41, 0x34, 0x27, 0xce, 0x0b, 0x81, 0xf3, 0xad, 0x02, 0x67, - 0xae, 0x8e, 0x24, 0xcf, 0xc0, 0x03, 0xdc, 0x9c, 0x20, 0xfb, 0x68, 0x4a, - 0xc9, 0xa6, 0x82, 0x6d, 0x69, 0xf6, 0x63, 0xb2, 0xeb, 0x19, 0x3c, 0x74, - 0xc4, 0xe8, 0x86, 0x35, 0xc7, 0xb6, 0xd3, 0x8a, 0x23, 0x73, 0x3d, 0xb0, - 0x4a, 0x32, 0x72, 0x01, 0x93, 0xae, 0x48, 0xb9, 0xcd, 0xd6, 0xce, 0x5c, - 0x7e, 0xab, 0xbb, 0xe2, 0xbb, 0x24, 0x83, 0xec, 0xbd, 0x7e, 0x78, 0x59, - 0xbf, 0xa7, 0x49, 0x36, 0xad, 0x78, 0xba, 0x14, 0xa5, 0x18, 0x67, 0x90, - 0x6c, 0x74, 0x8a, 0x13, 0x21, 0xb2, 0x2b, 0x05, 0x5b, 0x27, 0xb4, 0xc3, - 0x14, 0x0f, 0x46, 0x73, 0x68, 0x47, 0x32, 0xa0, 0x52, 0xce, 0x3e, 0xb5, - 0xe0, 0xfb, 0xdb, 0xe9, 0xaa, 0x59, 0x49, 0xe0, 0x45, 0x09, 0x68, 0x6b, - 0x34, 0x23, 0xfb, 0x1a, 0x49, 0x0f, 0xf5, 0x45, 0x0f, 0xee, 0x9b, 0x68, - 0xc0, 0xbd, 0x53, 0x5e, 0xec, 0x98, 0xb0, 0xf1, 0x7e, 0x8c, 0x6d, 0x42, - 0xeb, 0x23, 0x6f, 0xea, 0xac, 0x21, 0xd9, 0x6e, 0x8e, 0x45, 0x12, 0x1e, - 0xe1, 0x42, 0x75, 0xb1, 0x87, 0x72, 0x7f, 0x92, 0xfd, 0xc1, 0xa0, 0x39, - 0x42, 0xbb, 0x8c, 0xaf, 0x23, 0x15, 0x50, 0xe0, 0x2e, 0xfa, 0x28, 0x86, - 0xb0, 0xff, 0xf2, 0xb3, 0x6f, 0x60, 0x6b, 0x95, 0x0f, 0x72, 0x46, 0xc1, - 0x28, 0xe5, 0x7d, 0x2c, 0xab, 0x42, 0x57, 0xb3, 0x44, 0x9f, 0x80, 0x7f, - 0x76, 0xb2, 0xc9, 0x7f, 0x8c, 0xe2, 0xea, 0x9d, 0x59, 0x89, 0xd7, 0x61, - 0x9c, 0x40, 0x73, 0xab, 0x78, 0x8c, 0x62, 0xf4, 0x03, 0x14, 0x77, 0x4e, - 0x94, 0xf2, 0x82, 0xe3, 0x88, 0xc3, 0x4f, 0x96, 0x78, 0xcb, 0x12, 0x6f, - 0x59, 0xe2, 0x8b, 0xe2, 0xc1, 0x93, 0x59, 0xe6, 0xe3, 0x23, 0xf2, 0xcd, - 0x04, 0xf1, 0xee, 0xc1, 0x76, 0xa2, 0xf7, 0xfe, 0xa9, 0x1a, 0xdc, 0x43, - 0xf4, 0x16, 0x0d, 0xad, 0xef, 0x2f, 0x84, 0x8d, 0x7c, 0x4c, 0xb3, 0x76, - 0x0a, 0x2f, 0xa4, 0x66, 0xdb, 0xee, 0x31, 0x98, 0x67, 0xb2, 0x4f, 0xc9, - 0xe1, 0x79, 0x5f, 0x92, 0xe4, 0xdf, 0x4f, 0xef, 0x6c, 0x9b, 0xc2, 0xa7, - 0x12, 0xf1, 0xe4, 0x21, 0x1e, 0x0f, 0x18, 0x5a, 0x62, 0x15, 0xc5, 0xf3, - 0x73, 0x7a, 0xa4, 0x7c, 0x4e, 0xc6, 0xd7, 0x48, 0x1e, 0x06, 0xcb, 0xa3, - 0x99, 0xf8, 0xb9, 0x8f, 0x30, 0x8e, 0xdf, 0x64, 0x3e, 0x23, 0xd1, 0x5f, - 0x10, 0xef, 0x91, 0x62, 0xc0, 0x7f, 0xe6, 0x50, 0x93, 0xff, 0xa5, 0x91, - 0x0a, 0xfd, 0x3b, 0x89, 0xfe, 0xd9, 0x98, 0x8d, 0x83, 0x44, 0xff, 0x13, - 0x44, 0x7f, 0x3f, 0xc7, 0xf1, 0x05, 0xfa, 0x4f, 0x94, 0x78, 0xdd, 0x2f, - 0xe3, 0x61, 0x91, 0xfe, 0x06, 0x6c, 0x9d, 0x5a, 0x94, 0x97, 0x6d, 0xdf, - 0x66, 0x3c, 0x63, 0xff, 0x1e, 0xc9, 0x6c, 0x79, 0x91, 0xe5, 0xc6, 0xf8, - 0x2d, 0x72, 0xf8, 0x4e, 0xdc, 0x21, 0xc1, 0xeb, 0xc3, 0x92, 0x22, 0xe7, - 0x80, 0x10, 0x9e, 0x21, 0xfd, 0x3e, 0x4f, 0x39, 0xec, 0xe9, 0xd2, 0xe5, - 0x39, 0x8d, 0x75, 0x3d, 0x49, 0x3a, 0xd6, 0x72, 0x16, 0xc5, 0xb4, 0x54, - 0x29, 0x89, 0x3d, 0x53, 0x48, 0xce, 0x1a, 0x7f, 0x46, 0x81, 0x65, 0x19, - 0x64, 0xbd, 0x3a, 0xa9, 0xea, 0x5e, 0xdc, 0x3e, 0x13, 0xc0, 0x40, 0x69, - 0x03, 0xb2, 0x14, 0x67, 0x76, 0x52, 0x5c, 0xfe, 0x30, 0x96, 0xdc, 0xe1, - 0x47, 0x84, 0xf4, 0x1b, 0xc0, 0xdd, 0xf4, 0xce, 0x81, 0x29, 0xa6, 0x5f, - 0x5d, 0xd0, 0x73, 0x00, 0x77, 0xd2, 0xbd, 0xbd, 0x53, 0x0a, 0x5e, 0x30, - 0x8e, 0x10, 0x8e, 0xa9, 0xe0, 0x8a, 0x3b, 0xb2, 0x50, 0xc9, 0x2d, 0x09, - 0xf7, 0x45, 0xa2, 0x2f, 0xd0, 0xf7, 0xed, 0x25, 0xaf, 0x7f, 0x78, 0x12, - 0xdf, 0x59, 0x6e, 0xfa, 0xb1, 0x84, 0x30, 0xd8, 0x2d, 0x46, 0xa4, 0xbc, - 0x9e, 0x30, 0xd3, 0x60, 0x49, 0xc2, 0xb7, 0x67, 0xbc, 0x78, 0x60, 0xe2, - 0x53, 0xbb, 0x2a, 0xee, 0xc2, 0xcd, 0xcd, 0x5e, 0xdc, 0x3f, 0x93, 0xc4, - 0xbe, 0x29, 0x84, 0xaa, 0x63, 0x63, 0x14, 0xb3, 0x2b, 0x79, 0xa0, 0x86, - 0x78, 0xdf, 0x3f, 0xe5, 0xf3, 0xf7, 0x1f, 0x62, 0x19, 0x6c, 0x08, 0x92, - 0x77, 0x94, 0xab, 0x63, 0x32, 0xb6, 0x1b, 0xf2, 0x92, 0x6a, 0x32, 0xf4, - 0x23, 0x34, 0xdf, 0x34, 0xe4, 0x57, 0x97, 0x23, 0x72, 0xb8, 0x51, 0x2e, - 0x8f, 0x2e, 0x41, 0x03, 0x1e, 0x98, 0x4b, 0x62, 0x8c, 0x6c, 0xf4, 0xbe, - 0x89, 0xe1, 0xef, 0xd4, 0x53, 0xec, 0xf0, 0xb7, 0x69, 0xfd, 0x6f, 0x08, - 0x13, 0xf9, 0x88, 0x07, 0x3b, 0x67, 0x7c, 0xfe, 0x1d, 0x87, 0xec, 0xf5, - 0x6c, 0x4f, 0x77, 0xcd, 0x35, 0xe0, 0x9e, 0x29, 0xba, 0x37, 0xc1, 0x36, - 0x4c, 0xb6, 0x16, 0xa9, 0x26, 0xde, 0xc2, 0x49, 0x0f, 0xe1, 0x24, 0x39, - 0x56, 0x43, 0xf2, 0xf0, 0xe0, 0x4e, 0xc7, 0x16, 0x54, 0x6c, 0x9f, 0xb2, - 0xf1, 0x96, 0x11, 0xc5, 0x28, 0xd9, 0xf5, 0xe1, 0x29, 0x6d, 0xbe, 0x93, - 0x30, 0xce, 0x3b, 0xb2, 0x76, 0xb8, 0x59, 0x4e, 0xa2, 0x61, 0x0d, 0xc5, - 0xf6, 0x06, 0xdb, 0xbe, 0xa3, 0xad, 0x65, 0xe0, 0xc7, 0x44, 0x73, 0xbd, - 0xb9, 0x0c, 0xe5, 0x7a, 0x6d, 0x14, 0x68, 0x19, 0xac, 0x92, 0xae, 0xc6, - 0xd9, 0xa5, 0x1c, 0xff, 0x38, 0x86, 0x07, 0xfc, 0x0d, 0x99, 0x4a, 0x6e, - 0x6b, 0x28, 0x36, 0xf9, 0xeb, 0x33, 0x41, 0x7f, 0x7d, 0x11, 0xfe, 0xaa, - 0x22, 0xf0, 0x03, 0x8a, 0x2f, 0x4b, 0xd6, 0xfc, 0xca, 0x4e, 0x35, 0x38, - 0x38, 0xd0, 0xff, 0xdc, 0xa4, 0x66, 0x95, 0xa1, 0xed, 0xa3, 0x70, 0x89, - 0x47, 0xe7, 0x5c, 0xfe, 0xe3, 0x14, 0x07, 0x1a, 0xf4, 0x28, 0xf6, 0x92, - 0x3e, 0x87, 0xc8, 0x16, 0x7e, 0xb1, 0x06, 0xd8, 0x9f, 0x09, 0x87, 0x0c, - 0xd1, 0x47, 0x13, 0x03, 0xbb, 0x8b, 0x14, 0xeb, 0xa5, 0xdf, 0xa2, 0x40, - 0xa6, 0x45, 0x29, 0x9d, 0x21, 0x9d, 0x71, 0xc3, 0x5a, 0x5a, 0xd1, 0xc9, - 0x3d, 0xd9, 0xe7, 0x6d, 0xbf, 0xae, 0xe7, 0x8a, 0xa4, 0xb3, 0x07, 0x4b, - 0x3e, 0x0c, 0x12, 0x0e, 0x58, 0x42, 0xd8, 0xf1, 0x7e, 0xb2, 0x8b, 0xfb, - 0x26, 0x64, 0xa2, 0x8f, 0xc7, 0x25, 0x91, 0x5c, 0x56, 0xc1, 0xa0, 0x0f, - 0xcc, 0xb0, 0x5d, 0x92, 0x1d, 0x91, 0x2d, 0x3e, 0x43, 0xb9, 0xfe, 0xe9, - 0xcf, 0x61, 0x0f, 0x4d, 0xb5, 0x2e, 0xe5, 0xfc, 0x8a, 0x3c, 0x86, 0xa7, - 0x98, 0x67, 0xed, 0x30, 0xa4, 0x24, 0x6e, 0x30, 0x7e, 0x42, 0xb9, 0x80, - 0x79, 0x27, 0xec, 0x3b, 0x15, 0xc5, 0xc3, 0x59, 0xc2, 0x32, 0xb1, 0xf7, - 0xed, 0x3b, 0x03, 0x2c, 0x03, 0xe6, 0x27, 0x2e, 0x73, 0xde, 0x6c, 0x20, - 0xcc, 0xfb, 0xff, 0x6f, 0x77, 0xb7, 0xdb, 0x29, 0x07, 0xc3, 0x12, 0xb6, - 0x26, 0x7b, 0x4a, 0x5d, 0xb2, 0x9f, 0xfb, 0xed, 0xb3, 0x01, 0xce, 0xd3, - 0x0d, 0x48, 0x5d, 0xb2, 0x05, 0xb6, 0x25, 0x2c, 0x37, 0xda, 0x76, 0xdd, - 0xaf, 0x82, 0xed, 0x21, 0x7a, 0x99, 0x3d, 0xb8, 0x89, 0x26, 0x15, 0x3b, - 0xe6, 0xd8, 0x7e, 0xed, 0x8f, 0x96, 0x9b, 0xff, 0x40, 0x39, 0x42, 0x3f, - 0xfc, 0x13, 0xdc, 0x48, 0xf7, 0x03, 0xf8, 0x36, 0xf9, 0xd1, 0xdd, 0xc4, - 0xe7, 0x8e, 0xf6, 0xbb, 0x1d, 0xbf, 0xdd, 0x51, 0xba, 0x8e, 0xee, 0xb3, - 0xbc, 0x3b, 0xb1, 0x2f, 0x6b, 0x20, 0x9d, 0x2d, 0x3b, 0xf9, 0xc7, 0x65, - 0xc6, 0xf1, 0x7d, 0x8a, 0xb3, 0xcf, 0x94, 0x18, 0x8b, 0x25, 0x1c, 0x1c, - 0xf6, 0xbd, 0x52, 0x2b, 0x9e, 0x25, 0x9f, 0x7c, 0x9a, 0x62, 0xee, 0x77, - 0x1d, 0x7c, 0xe6, 0x12, 0x07, 0xd3, 0x84, 0x45, 0x47, 0x2c, 0xa4, 0xf3, - 0x21, 0x78, 0x0e, 0x85, 0xf7, 0xed, 0x10, 0xda, 0x0f, 0x48, 0x5e, 0xfe, - 0xfd, 0xb3, 0x2b, 0x50, 0x7d, 0x48, 0xcb, 0x11, 0xdd, 0xfe, 0x87, 0x67, - 0x75, 0xc2, 0xd2, 0x41, 0xff, 0xde, 0xbc, 0xea, 0xdf, 0x33, 0x19, 0xf0, - 0xef, 0x99, 0x6d, 0x20, 0x3f, 0x5a, 0xe6, 0x1f, 0x9e, 0x0d, 0xfa, 0x77, - 0xa5, 0x9b, 0xfc, 0xbb, 0xf2, 0x6b, 0x10, 0x6a, 0x80, 0xb5, 0x8c, 0x72, - 0xc4, 0x3d, 0x13, 0xdf, 0x44, 0xae, 0xbe, 0x12, 0xf7, 0x07, 0xc8, 0x36, - 0xea, 0xc8, 0x0e, 0xaf, 0x91, 0x6e, 0x46, 0x79, 0x69, 0xe5, 0xde, 0xb7, - 0xe9, 0xde, 0x03, 0x6d, 0xf0, 0xff, 0xa5, 0x13, 0x7b, 0x81, 0x67, 0xc9, - 0xd6, 0x9e, 0x69, 0xa3, 0x7a, 0xf2, 0x92, 0xad, 0xb9, 0x28, 0xde, 0xda, - 0xb6, 0xb1, 0x46, 0x20, 0xd8, 0xb6, 0x11, 0x58, 0xb2, 0x58, 0x43, 0x26, - 0x73, 0xae, 0xb6, 0x24, 0x96, 0xeb, 0x9b, 0x70, 0x44, 0xa5, 0x54, 0xd3, - 0xf6, 0x35, 0x2c, 0xbc, 0x83, 0x6f, 0x4f, 0x78, 0x90, 0xda, 0xa2, 0x62, - 0x96, 0x30, 0xca, 0x5d, 0x34, 0xff, 0xca, 0x58, 0x8b, 0x3a, 0x47, 0x7a, - 0x48, 0xaa, 0x7c, 0x8f, 0x7c, 0xa2, 0x6d, 0x2d, 0xf9, 0x44, 0x65, 0xfd, - 0xa7, 0x48, 0x5f, 0xa3, 0x73, 0x51, 0xec, 0x29, 0xfd, 0x40, 0xaa, 0xe4, - 0x17, 0x2d, 0x97, 0xc4, 0x69, 0x67, 0xec, 0x53, 0xd9, 0x37, 0xec, 0x90, - 0x63, 0x77, 0x02, 0x8f, 0xac, 0x8e, 0xec, 0xfb, 0xef, 0x52, 0x23, 0xf1, - 0x45, 0xb2, 0xcb, 0x3a, 0xf5, 0x63, 0xdd, 0x15, 0xfa, 0xbf, 0xc5, 0xf7, - 0x55, 0x96, 0xed, 0xa0, 0xd8, 0x47, 0x75, 0x2a, 0x95, 0x4c, 0x75, 0x4b, - 0xf4, 0x43, 0x78, 0xba, 0x87, 0xef, 0x05, 0xfc, 0xfb, 0x27, 0x93, 0x52, - 0x40, 0x87, 0xea, 0x36, 0x3b, 0xc5, 0xfe, 0xd9, 0x65, 0xfe, 0x87, 0x27, - 0x37, 0x8a, 0x87, 0x67, 0x9b, 0xfc, 0xc3, 0xe9, 0x2e, 0x31, 0x9c, 0xdf, - 0x22, 0xac, 0xdc, 0xb7, 0x84, 0x35, 0x9b, 0x12, 0x56, 0xbe, 0x8f, 0xae, - 0xbd, 0x62, 0x32, 0x3f, 0x28, 0xf6, 0xe4, 0x79, 0x7e, 0xd2, 0x15, 0xad, - 0xf1, 0x3d, 0x8a, 0xbd, 0xcf, 0x52, 0xec, 0x7d, 0x86, 0x62, 0xef, 0xd3, - 0x64, 0xef, 0xdf, 0xbd, 0x84, 0x6d, 0xd9, 0xc6, 0x93, 0x8c, 0x49, 0xfc, - 0x7f, 0x51, 0x3c, 0x49, 0xfa, 0x66, 0xd9, 0xfd, 0x27, 0xb2, 0x6d, 0x96, - 0xc9, 0x03, 0x9c, 0x2b, 0x48, 0x4f, 0x17, 0x1d, 0x5b, 0x7e, 0x64, 0x35, - 0x63, 0xa8, 0x41, 0xb1, 0x95, 0xe8, 0x4b, 0xba, 0x08, 0xfb, 0xe8, 0x84, - 0x4b, 0xb2, 0x83, 0xe2, 0x8e, 0x3c, 0xdf, 0x3f, 0x80, 0x9d, 0x54, 0x0b, - 0x1e, 0x8c, 0x85, 0x7b, 0xb6, 0x11, 0x66, 0xda, 0x4c, 0x98, 0x69, 0x65, - 0x4c, 0xc1, 0x85, 0xd6, 0x4f, 0x6c, 0x2c, 0x45, 0xf2, 0xde, 0xb8, 0x96, - 0xcb, 0x55, 0xf2, 0xed, 0x68, 0x06, 0x5c, 0xaf, 0xa3, 0xae, 0x56, 0xd7, - 0x4e, 0x24, 0x11, 0xde, 0x17, 0x97, 0x60, 0x55, 0x99, 0x6e, 0xdc, 0xe3, - 0xd4, 0x88, 0x1b, 0x30, 0x31, 0x21, 0xb0, 0xbd, 0x2d, 0xf9, 0x87, 0x6e, - 0x92, 0xd5, 0x3b, 0xed, 0x08, 0x90, 0x7a, 0x85, 0x42, 0xf5, 0x7c, 0x17, - 0x49, 0xaf, 0x93, 0x72, 0xee, 0x91, 0xec, 0x5a, 0x34, 0xb6, 0x29, 0xa4, - 0x43, 0x17, 0x6e, 0x2b, 0xde, 0x40, 0x7a, 0x8c, 0x1c, 0x7e, 0x0e, 0x5e, - 0xff, 0x0b, 0x93, 0x26, 0x46, 0xb2, 0xf8, 0x8e, 0x8f, 0x6a, 0xb7, 0xbb, - 0x09, 0x37, 0x7d, 0x97, 0x68, 0xd8, 0xd4, 0x16, 0xe9, 0xa2, 0x1a, 0x5e, - 0xf5, 0x9a, 0x55, 0x18, 0x6f, 0xf6, 0x43, 0xd5, 0x53, 0xe2, 0x95, 0x7c, - 0xe4, 0xf0, 0x0e, 0xe9, 0x5b, 0xe2, 0xc7, 0xb3, 0x26, 0x1e, 0x2e, 0xf5, - 0x89, 0xbf, 0x9c, 0x55, 0x40, 0xba, 0xa1, 0xb8, 0x65, 0xe0, 0x30, 0xd1, - 0xe5, 0x26, 0x9c, 0xe4, 0xfe, 0x1d, 0x81, 0x2b, 0xf4, 0x24, 0xbe, 0xbd, - 0x96, 0x7d, 0xa1, 0x12, 0xd3, 0x5c, 0x6b, 0x81, 0x7d, 0x64, 0x93, 0x8d, - 0x99, 0x4e, 0xb1, 0x9c, 0xfe, 0xbf, 0x40, 0x79, 0x2d, 0x29, 0x75, 0x89, - 0x46, 0xc2, 0xa4, 0x4b, 0xa7, 0x7b, 0xc5, 0x92, 0x22, 0x63, 0x50, 0xa8, - 0x4b, 0x49, 0x46, 0x4b, 0x8b, 0xe7, 0xe5, 0x0a, 0xf6, 0x77, 0xb3, 0x2d, - 0x59, 0x3e, 0x53, 0xf1, 0x1f, 0xa4, 0xd8, 0xbe, 0x23, 0xd6, 0x45, 0xf8, - 0x98, 0xef, 0x0f, 0x8a, 0x11, 0x92, 0x63, 0xce, 0xed, 0xd8, 0x8e, 0xff, - 0xc8, 0x24, 0xdc, 0x8d, 0x26, 0x42, 0x55, 0x94, 0x3b, 0xfe, 0xe7, 0x9a, - 0x88, 0xf5, 0x9c, 0xd4, 0x2d, 0x46, 0xf3, 0x01, 0xff, 0xe1, 0x49, 0xce, - 0x33, 0x9d, 0xe2, 0x30, 0xe9, 0x3c, 0x4b, 0x3a, 0xcf, 0x92, 0xce, 0x33, - 0xa4, 0xf3, 0xcc, 0x97, 0xe8, 0x7c, 0x2f, 0xe9, 0x7c, 0x57, 0xfe, 0x63, - 0x47, 0x87, 0x2e, 0xd3, 0x44, 0x96, 0xf2, 0xf2, 0x78, 0x73, 0x85, 0xbf, - 0x0f, 0x49, 0x16, 0xa7, 0x62, 0x5f, 0x77, 0xc1, 0x6b, 0x52, 0x6c, 0xed, - 0xa6, 0x77, 0xbe, 0xb2, 0x60, 0xe3, 0xaa, 0x7f, 0x6c, 0xb2, 0x53, 0x8c, - 0x91, 0xdf, 0x8d, 0xd3, 0xfc, 0xe3, 0xe4, 0x77, 0xc3, 0xe9, 0x7f, 0x8e, - 0xdd, 0xb0, 0xdd, 0xc1, 0xf2, 0x52, 0xde, 0xaa, 0x21, 0xbb, 0x74, 0x99, - 0x6c, 0x43, 0x5b, 0x44, 0xf2, 0xe8, 0xb7, 0x44, 0xf2, 0x58, 0x4a, 0x24, - 0x0b, 0x7d, 0x74, 0xed, 0x15, 0x37, 0x39, 0xf5, 0xe7, 0xa0, 0xe8, 0x2c, - 0x04, 0xfc, 0x53, 0xb4, 0xce, 0x14, 0xf1, 0xf1, 0x08, 0xad, 0xf3, 0x88, - 0x63, 0xbb, 0xe3, 0x2e, 0xce, 0xff, 0xcf, 0x67, 0xd9, 0xce, 0xd8, 0xbe, - 0xde, 0x25, 0xda, 0xd9, 0x37, 0x2e, 0xf5, 0x76, 0xe8, 0xaf, 0x5d, 0x86, - 0xbe, 0xc3, 0x55, 0xe1, 0x89, 0x73, 0x3f, 0xe7, 0x7a, 0x8e, 0xc3, 0xaa, - 0x53, 0x03, 0x3e, 0x73, 0x09, 0x03, 0x30, 0x1e, 0x80, 0xb2, 0xc4, 0x7c, - 0xb0, 0xe3, 0xdb, 0xcd, 0xff, 0x8b, 0xe6, 0x1b, 0x80, 0xb1, 0x16, 0x4a, - 0xc0, 0xfc, 0x65, 0xc7, 0x64, 0x33, 0xc5, 0x69, 0x9a, 0x53, 0xc9, 0x00, - 0x7a, 0x46, 0x60, 0x57, 0x42, 0x10, 0x8e, 0x5d, 0x46, 0x7e, 0xc9, 0xf4, - 0x6b, 0x5d, 0x49, 0x7a, 0xb6, 0x62, 0x04, 0xca, 0x72, 0x73, 0x27, 0xec, - 0x2c, 0x94, 0x3a, 0xb3, 0x1f, 0x1f, 0x8d, 0x84, 0x83, 0x5d, 0xd0, 0x52, - 0xe7, 0x64, 0xad, 0x4c, 0xf9, 0x6d, 0x60, 0x97, 0xd0, 0xfa, 0xe7, 0x05, - 0xf7, 0x87, 0x18, 0xb3, 0xef, 0x44, 0xab, 0x83, 0xdd, 0xfb, 0xd1, 0x92, - 0x07, 0xd5, 0xdf, 0x84, 0x6b, 0x69, 0xce, 0x97, 0x8c, 0x0f, 0x38, 0x27, - 0x24, 0x09, 0x0b, 0x7e, 0x61, 0x2e, 0x10, 0x8e, 0xe1, 0x79, 0x78, 0x8e, - 0xb0, 0xda, 0x4f, 0xf3, 0xbe, 0x25, 0xb7, 0x0c, 0x0c, 0x0b, 0x2d, 0xf1, - 0xc5, 0xf9, 0x56, 0xe6, 0x21, 0x56, 0x66, 0x2c, 0xbb, 0x46, 0xf7, 0x32, - 0x1e, 0x92, 0xce, 0xeb, 0x7a, 0xf2, 0x35, 0x84, 0xb0, 0x92, 0xea, 0xe3, - 0x68, 0x91, 0x79, 0x18, 0xc2, 0x8b, 0x86, 0xd6, 0x43, 0x55, 0x28, 0xd5, - 0x2b, 0x9d, 0x38, 0x40, 0xb1, 0xf7, 0xe1, 0x12, 0xf7, 0xb7, 0x06, 0xc5, - 0xaa, 0x11, 0xf2, 0x4b, 0xc7, 0x9e, 0xa0, 0x34, 0x9a, 0x0f, 0xe2, 0x3a, - 0x5a, 0xdf, 0x4f, 0x35, 0xcf, 0xeb, 0xb4, 0xbe, 0x94, 0xd1, 0x06, 0x69, - 0xfd, 0xd4, 0x1b, 0x22, 0x3c, 0x4f, 0x7c, 0xf5, 0xad, 0x97, 0x5b, 0xfa, - 0x87, 0x84, 0x96, 0x24, 0xd2, 0xc9, 0x8f, 0x79, 0xed, 0x07, 0x99, 0x17, - 0xba, 0x52, 0x7d, 0x43, 0x76, 0xd4, 0x5c, 0x50, 0x44, 0x64, 0x6c, 0x03, - 0xf6, 0xcc, 0x6c, 0xc0, 0x6e, 0xf2, 0xc7, 0xfd, 0x46, 0x1d, 0x42, 0xf5, - 0xa8, 0xad, 0xd3, 0x31, 0x7f, 0x4e, 0x17, 0xf2, 0x8e, 0xd6, 0x26, 0xb2, - 0xe3, 0x93, 0x8d, 0xd5, 0xf8, 0xd8, 0xde, 0xa6, 0x6f, 0xe8, 0xa2, 0x88, - 0x78, 0x9d, 0x07, 0x87, 0x64, 0xf2, 0xef, 0x37, 0x7f, 0x41, 0x01, 0xd5, - 0x63, 0x32, 0x6e, 0x4b, 0x88, 0x8b, 0xf9, 0x53, 0xae, 0x8a, 0x1f, 0x34, - 0xe3, 0x23, 0x15, 0x75, 0x41, 0x7d, 0x15, 0xe6, 0x55, 0x85, 0xe2, 0x85, - 0xe5, 0xd4, 0x62, 0x37, 0x8e, 0xf6, 0xa0, 0x91, 0xea, 0xe2, 0xdb, 0x62, - 0xbf, 0xb0, 0x3f, 0xb9, 0x82, 0xdf, 0xfb, 0x23, 0x4f, 0x25, 0x76, 0x7e, - 0xd9, 0x1c, 0x71, 0x8a, 0x37, 0x2d, 0x54, 0xc7, 0xd6, 0x50, 0x90, 0xee, - 0xa2, 0x7c, 0xa4, 0xf5, 0xa5, 0xa9, 0x0e, 0xed, 0x8f, 0xb4, 0x18, 0xb2, - 0xa8, 0x42, 0x39, 0x10, 0x1e, 0xd8, 0x86, 0xe4, 0x5d, 0xfe, 0x05, 0x3a, - 0x9e, 0x11, 0x2b, 0xdc, 0xf4, 0x1e, 0xcf, 0x73, 0x99, 0x3d, 0xe5, 0xc9, - 0x9e, 0xf8, 0x39, 0xff, 0x7f, 0xe9, 0xb9, 0xf2, 0x15, 0xf3, 0x97, 0xe6, - 0xbf, 0x5f, 0xf9, 0x65, 0xf7, 0x03, 0xeb, 0x7e, 0xfd, 0xfe, 0xff, 0xad, - 0x9e, 0x2f, 0xd7, 0xbb, 0x1c, 0xcc, 0x90, 0x94, 0xb8, 0x7f, 0xe9, 0x32, - 0x7d, 0x1d, 0xbb, 0xf5, 0xdf, 0xa0, 0x98, 0xc6, 0xfd, 0x0b, 0xce, 0xd3, - 0x67, 0x9d, 0xfe, 0xc5, 0xf3, 0x9f, 0xc3, 0xac, 0x1c, 0x5b, 0x3c, 0xa2, - 0x66, 0xdc, 0xb2, 0x1b, 0xf4, 0xdb, 0xa8, 0xae, 0x19, 0xc2, 0xb6, 0x98, - 0x81, 0xb1, 0xac, 0xd6, 0x73, 0x33, 0xf4, 0xe4, 0x16, 0x41, 0x13, 0x15, - 0x3d, 0x42, 0x1e, 0x5f, 0x78, 0x66, 0x58, 0x54, 0xab, 0x95, 0x51, 0x4d, - 0xb1, 0xc9, 0xa5, 0xab, 0x0a, 0x8a, 0x01, 0xc5, 0x55, 0x0c, 0x2a, 0x55, - 0xc5, 0x26, 0xa5, 0x9a, 0xc6, 0xf9, 0xc6, 0xb5, 0xf9, 0x9b, 0x31, 0x84, - 0xf9, 0x35, 0x5e, 0xab, 0xd1, 0xd4, 0xd4, 0x46, 0x79, 0x08, 0xbb, 0x63, - 0xfc, 0x6e, 0x27, 0xd5, 0x6c, 0x10, 0xf5, 0x19, 0x42, 0xc6, 0xa6, 0xc0, - 0x9e, 0x76, 0x6d, 0x70, 0x85, 0xa4, 0x77, 0xfd, 0xad, 0x70, 0x29, 0x9e, - 0x22, 0x84, 0x3f, 0x23, 0xe1, 0x70, 0x3b, 0x3c, 0x9e, 0xb5, 0x5a, 0xff, - 0x49, 0x31, 0x88, 0x27, 0x62, 0x91, 0x9e, 0xed, 0x22, 0xa4, 0x78, 0xe9, - 0x99, 0x3b, 0x43, 0xf1, 0x37, 0x63, 0x79, 0xdc, 0x6b, 0xb5, 0xa0, 0x24, - 0x92, 0xd8, 0xa6, 0xeb, 0xc6, 0x38, 0x14, 0x5a, 0x13, 0xa2, 0x3a, 0xa3, - 0xcd, 0xbf, 0x45, 0x98, 0xea, 0x93, 0x95, 0x83, 0x68, 0x5b, 0x13, 0xd9, - 0xd7, 0x27, 0xe9, 0x0a, 0x61, 0x3d, 0xe1, 0xca, 0xf8, 0x70, 0xcd, 0xa1, - 0xc5, 0x7e, 0x8e, 0x6d, 0x7f, 0x18, 0x2b, 0x93, 0x5e, 0xa0, 0xd4, 0x16, - 0xa3, 0x8a, 0x8f, 0x70, 0x7d, 0xcb, 0x21, 0xc6, 0x59, 0xb6, 0xbd, 0x23, - 0x56, 0xfe, 0x9a, 0x17, 0xad, 0xc4, 0x63, 0x0f, 0x66, 0xd2, 0x8c, 0xbb, - 0x4c, 0x4c, 0x53, 0x4d, 0xa4, 0x8f, 0x34, 0xe1, 0x38, 0xc5, 0xa1, 0xb9, - 0x34, 0xf7, 0x7d, 0xfa, 0x49, 0xc6, 0x7d, 0x44, 0x7f, 0x2f, 0xd5, 0xc1, - 0x29, 0x8a, 0x5f, 0x2c, 0xe3, 0x6d, 0x64, 0xf7, 0x50, 0xbc, 0x66, 0xac, - 0xe3, 0xc6, 0x31, 0x28, 0x1e, 0x73, 0x55, 0xc7, 0x55, 0x87, 0x50, 0x4f, - 0x79, 0xdf, 0xa4, 0x8a, 0x07, 0xd1, 0x48, 0xc4, 0xb8, 0x80, 0x48, 0xf0, - 0x25, 0xd2, 0xc7, 0xb0, 0x0e, 0xec, 0x72, 0x6a, 0x6c, 0x17, 0xac, 0x3c, - 0xd7, 0xcf, 0xf0, 0x54, 0xb7, 0xd7, 0xe3, 0xfc, 0xa8, 0xcb, 0xe9, 0x1d, - 0x59, 0x54, 0xff, 0xbc, 0x60, 0x68, 0xa9, 0x1c, 0xbd, 0xb7, 0x55, 0xfd, - 0xd9, 0xde, 0x9a, 0x38, 0x14, 0x8a, 0x69, 0x64, 0x7b, 0x7f, 0xe2, 0x7d, - 0x8b, 0x6c, 0xf4, 0x96, 0xc9, 0x3f, 0xf5, 0x7e, 0x14, 0xcf, 0x79, 0x3f, - 0x88, 0xdb, 0x76, 0x82, 0xf0, 0x68, 0x1f, 0xd5, 0xdc, 0x1f, 0x8e, 0x58, - 0xde, 0x0b, 0x71, 0xee, 0xff, 0xba, 0xf0, 0xdb, 0xf4, 0xfd, 0xb1, 0x11, - 0x05, 0x9b, 0x0b, 0x8d, 0x70, 0x8f, 0xc9, 0x98, 0x31, 0xae, 0xc7, 0x36, - 0x55, 0xc2, 0x1d, 0xd1, 0x27, 0xc9, 0x26, 0x25, 0x1a, 0x73, 0x90, 0xbe, - 0x73, 0x2f, 0xeb, 0x11, 0x6c, 0x57, 0x67, 0xbd, 0xe7, 0xe3, 0x4c, 0x6f, - 0x88, 0xe9, 0x55, 0x24, 0xfd, 0xeb, 0xd8, 0x7a, 0x33, 0xd7, 0x56, 0xce, - 0xc7, 0xf3, 0x52, 0x7b, 0x03, 0x8e, 0x8f, 0x36, 0xe2, 0xb9, 0x51, 0xcb, - 0xf3, 0x5a, 0x7b, 0x14, 0xfd, 0x23, 0x36, 0x5e, 0x36, 0xac, 0xc1, 0x6a, - 0xb2, 0xf3, 0x04, 0xd5, 0x57, 0xe1, 0x35, 0xdc, 0x43, 0x40, 0x44, 0x46, - 0x64, 0x80, 0x40, 0xe6, 0xad, 0x14, 0xba, 0x52, 0xb5, 0x54, 0xa7, 0x9d, - 0x11, 0x76, 0xd5, 0x5d, 0xed, 0x2e, 0xa2, 0x01, 0xd8, 0x58, 0x68, 0x25, - 0xb9, 0x45, 0xb1, 0x39, 0xa2, 0x60, 0x53, 0xc1, 0xc0, 0x73, 0x69, 0x1f, - 0x6e, 0x29, 0xc4, 0x09, 0x7b, 0xab, 0x44, 0x7b, 0x02, 0xa5, 0x74, 0x00, - 0xdf, 0x28, 0x34, 0x91, 0xbc, 0x83, 0xb8, 0xbe, 0x10, 0xc2, 0x89, 0x34, - 0xe7, 0x6f, 0xd3, 0xb3, 0x35, 0xde, 0x84, 0xae, 0x82, 0x8e, 0xd9, 0x34, - 0x3c, 0xf7, 0xc5, 0x43, 0xe8, 0x2c, 0x44, 0x51, 0x20, 0x0c, 0xf7, 0x75, - 0x9a, 0xf3, 0x16, 0xd2, 0x49, 0x6b, 0x21, 0x80, 0x15, 0x11, 0xe0, 0xba, - 0x82, 0x4f, 0x0c, 0x12, 0xb6, 0x4a, 0x14, 0x1a, 0x70, 0x61, 0x8c, 0xed, - 0xdc, 0xe8, 0xd8, 0x3d, 0xaa, 0x22, 0x54, 0xc0, 0x35, 0x0a, 0xb0, 0x93, - 0xaa, 0xc3, 0x54, 0x81, 0xe8, 0x3d, 0xd0, 0x5e, 0xe9, 0xdd, 0xae, 0x2a, - 0x7c, 0xc6, 0x6f, 0x1d, 0xe9, 0xe9, 0xa3, 0x43, 0xb3, 0xde, 0x4f, 0xe2, - 0x1c, 0x9b, 0x9a, 0x3a, 0x5e, 0x3f, 0x04, 0x44, 0xa7, 0x98, 0x37, 0x27, - 0x36, 0x72, 0x3c, 0x6c, 0x55, 0xf0, 0xb7, 0x36, 0xd5, 0xa0, 0xa1, 0x19, - 0xde, 0x23, 0xd0, 0x7d, 0x44, 0x87, 0x8a, 0x24, 0xad, 0x7d, 0x53, 0xe1, - 0x7b, 0xf6, 0xd6, 0xa5, 0x41, 0xdc, 0x18, 0xa9, 0xc8, 0xea, 0x0c, 0xe9, - 0x70, 0x7a, 0xac, 0x11, 0x73, 0x44, 0x83, 0xdb, 0x6c, 0xee, 0x38, 0x36, - 0x69, 0x63, 0xa3, 0x61, 0x79, 0x5f, 0x6b, 0x5f, 0x85, 0x7b, 0x0f, 0x0d, - 0x9f, 0xae, 0x22, 0xbd, 0xce, 0x1b, 0xb7, 0xe2, 0xe1, 0x29, 0x5c, 0xd9, - 0x08, 0x3c, 0x14, 0x04, 0xf7, 0xaa, 0xb5, 0xd0, 0x09, 0x44, 0xba, 0xee, - 0x43, 0x44, 0xd5, 0x85, 0x66, 0xbc, 0x2c, 0x90, 0xac, 0x31, 0x23, 0xa7, - 0x6f, 0x02, 0x5e, 0xac, 0x22, 0x0f, 0xbe, 0xa5, 0xe0, 0x22, 0x19, 0x05, - 0x51, 0x1a, 0xab, 0x82, 0x4c, 0x7e, 0x72, 0x51, 0xc7, 0xc6, 0x3a, 0x92, - 0xb5, 0x2c, 0x14, 0xd2, 0x73, 0x2b, 0x8e, 0x8d, 0x2c, 0xca, 0xca, 0x87, - 0x1b, 0x48, 0x86, 0x4f, 0x8c, 0xd8, 0x43, 0x7a, 0x2c, 0x40, 0xb2, 0x56, - 0x89, 0xbe, 0x45, 0x39, 0xb1, 0xfc, 0x16, 0xe5, 0x74, 0x2b, 0x76, 0xcf, - 0xb1, 0xdc, 0xfe, 0x5f, 0xe4, 0x35, 0xeb, 0xd8, 0xdd, 0xc6, 0xc9, 0x28, - 0x1a, 0x0f, 0x5d, 0x92, 0x1d, 0xd3, 0xf7, 0x10, 0xf1, 0xf1, 0x1d, 0xff, - 0xb5, 0x91, 0xfe, 0xf7, 0x84, 0x8f, 0xe8, 0x51, 0x49, 0x37, 0xef, 0xb9, - 0x19, 0xbb, 0x93, 0x4c, 0x2e, 0xc9, 0x38, 0x48, 0x32, 0x0e, 0x4e, 0xb1, - 0xac, 0x9b, 0x48, 0xd6, 0xc0, 0xeb, 0x84, 0xcb, 0xae, 0x8b, 0x45, 0x51, - 0x7b, 0x48, 0x4b, 0x36, 0xca, 0xe1, 0x44, 0x9d, 0x00, 0x55, 0x25, 0x68, - 0xad, 0xc5, 0x87, 0x2c, 0x67, 0x83, 0xe4, 0xfc, 0x9d, 0x61, 0xe2, 0x67, - 0x03, 0xcd, 0xb7, 0x91, 0xe4, 0x9c, 0x24, 0xfe, 0x6f, 0x72, 0xe6, 0x6d, - 0xa2, 0x79, 0x7b, 0xa9, 0xf6, 0x98, 0xf5, 0x5e, 0x24, 0x7a, 0xa2, 0x9f, - 0xd1, 0x42, 0x68, 0x3c, 0x12, 0x7c, 0x8f, 0x6a, 0xec, 0xeb, 0x9d, 0x71, - 0x2a, 0x8d, 0x63, 0xda, 0x7f, 0x5c, 0x2d, 0xe9, 0x5f, 0xd6, 0x67, 0xfe, - 0x16, 0xb8, 0xe7, 0x60, 0xa1, 0x8f, 0xea, 0x88, 0x5e, 0xaa, 0x95, 0x14, - 0xca, 0x6d, 0x16, 0xbe, 0x1b, 0xd7, 0xa2, 0xf5, 0x82, 0xe3, 0x9f, 0x45, - 0x7e, 0x58, 0xa6, 0x3a, 0x29, 0x1c, 0x9a, 0x43, 0x50, 0x91, 0x8a, 0x0a, - 0xe1, 0xc1, 0x26, 0x45, 0x2e, 0x92, 0xbf, 0x06, 0xfb, 0x08, 0x4f, 0xbb, - 0xf0, 0x52, 0xde, 0x85, 0x57, 0xd2, 0xbd, 0xd8, 0x5f, 0xf2, 0x10, 0x6e, - 0xb6, 0x3c, 0xae, 0xb5, 0x7f, 0x56, 0x55, 0x89, 0xc9, 0x2b, 0xd1, 0x3d, - 0xfe, 0x20, 0x6a, 0x32, 0xae, 0x1e, 0xca, 0xa7, 0xc6, 0x4d, 0x24, 0x97, - 0x8d, 0x45, 0x7e, 0xde, 0x84, 0x4c, 0x3a, 0x45, 0x18, 0x28, 0x4c, 0x35, - 0x90, 0x0b, 0xb9, 0xc6, 0x26, 0xa7, 0x9f, 0x3b, 0x4a, 0xf7, 0x46, 0x4b, - 0x5f, 0xec, 0x33, 0xdf, 0xba, 0xd0, 0x5f, 0xee, 0xc7, 0xde, 0x6c, 0x1f, - 0x61, 0xd3, 0x5e, 0x8a, 0xef, 0x15, 0x1a, 0x67, 0xe3, 0x3d, 0xd8, 0x9b, - 0x37, 0x2f, 0xc5, 0x8f, 0x69, 0x27, 0x7e, 0x0c, 0xa0, 0xba, 0x9d, 0xf7, - 0xad, 0x7a, 0x71, 0x7b, 0x1a, 0x78, 0x37, 0xcd, 0x7d, 0x44, 0xc2, 0x14, - 0x94, 0x0f, 0x0e, 0x1a, 0x9c, 0x43, 0x7b, 0xb1, 0x22, 0x6f, 0x23, 0x6f, - 0xd8, 0x38, 0x6d, 0xe8, 0x94, 0xa3, 0x39, 0x57, 0x0f, 0x0a, 0x9d, 0xf2, - 0xb3, 0xe5, 0x1a, 0x40, 0xa4, 0x9d, 0x75, 0xf4, 0xe0, 0xc2, 0xfe, 0xd3, - 0x80, 0xb3, 0xff, 0x34, 0x97, 0x96, 0xf1, 0x04, 0x29, 0xe2, 0xb9, 0x6c, - 0x38, 0xf4, 0x2e, 0xec, 0x21, 0xd9, 0xd4, 0x12, 0x2e, 0x99, 0xf7, 0x65, - 0x78, 0x5f, 0x4a, 0xef, 0x59, 0x21, 0x6b, 0x46, 0x51, 0xb4, 0xf4, 0xbd, - 0x8d, 0xf2, 0x26, 0x05, 0x5a, 0xe8, 0x35, 0x44, 0xa2, 0x5d, 0xbc, 0xf7, - 0x50, 0xaa, 0xe4, 0xee, 0x95, 0x0b, 0xb9, 0x5b, 0xcf, 0x7b, 0x45, 0x78, - 0x4c, 0x42, 0x6e, 0xc6, 0xb6, 0x24, 0xb2, 0xdf, 0x19, 0x9a, 0xf3, 0x07, - 0xd9, 0x21, 0x64, 0x63, 0xb6, 0x7d, 0x4b, 0x5c, 0xef, 0x6f, 0x94, 0xf1, - 0xfb, 0x94, 0xc9, 0x41, 0x36, 0x9f, 0x22, 0x5f, 0x0b, 0xed, 0x68, 0xb7, - 0xec, 0x2a, 0xa7, 0xae, 0xe0, 0xbe, 0x64, 0xb7, 0x68, 0x2d, 0xf4, 0x8a, - 0x55, 0x84, 0xdd, 0x42, 0xc7, 0xb6, 0x88, 0xe6, 0xa3, 0x15, 0xec, 0x16, - 0x29, 0x7c, 0xd6, 0x3b, 0xbd, 0x31, 0x6d, 0x23, 0x4d, 0x7c, 0x3d, 0xf1, - 0x6b, 0x7c, 0xb1, 0x2e, 0x06, 0x70, 0x55, 0x3b, 0xfb, 0xe2, 0x83, 0x38, - 0x96, 0x66, 0x3b, 0x1f, 0xc0, 0x6e, 0x92, 0xcf, 0xea, 0x11, 0xde, 0x07, - 0xd3, 0x4e, 0x0f, 0x23, 0xdc, 0xff, 0xaa, 0xd0, 0xca, 0x05, 0xb4, 0x18, - 0xb5, 0x32, 0xc7, 0x57, 0x6d, 0xb0, 0x59, 0xae, 0xd0, 0x9f, 0xc8, 0x83, - 0xe2, 0x69, 0x85, 0x87, 0x6b, 0xf2, 0x2b, 0xc8, 0x56, 0x2d, 0xcf, 0xc5, - 0x78, 0xcb, 0x40, 0x0d, 0x36, 0x8a, 0x0f, 0x66, 0x43, 0xf0, 0x1e, 0x4a, - 0x2e, 0xf5, 0xa3, 0x53, 0xbc, 0xeb, 0xd4, 0x8b, 0x5d, 0xe2, 0x7c, 0xbe, - 0x47, 0xbc, 0x9f, 0xeb, 0x46, 0x64, 0xec, 0x1e, 0xf1, 0x4e, 0x8e, 0xe9, - 0xec, 0x13, 0x67, 0x67, 0xb9, 0x3f, 0x6a, 0x63, 0xb7, 0xc1, 0xbd, 0xd1, - 0xa5, 0xd5, 0xf0, 0xdb, 0x38, 0x66, 0xb0, 0x3e, 0xb9, 0x4f, 0x58, 0xe9, - 0x2f, 0x6d, 0x8c, 0x8f, 0xda, 0x2e, 0x9d, 0x7b, 0xc4, 0x41, 0x87, 0xdf, - 0x19, 0xc2, 0xd1, 0xb3, 0xb9, 0x5e, 0x71, 0x3c, 0x5f, 0xe1, 0x75, 0x3a, - 0xcf, 0xf6, 0xab, 0x90, 0x8e, 0xbf, 0x98, 0xa7, 0x2d, 0xa8, 0xed, 0x41, - 0x54, 0x39, 0xfd, 0x28, 0x1b, 0xe3, 0x46, 0x24, 0xf4, 0x32, 0x82, 0x70, - 0x15, 0xd9, 0xb6, 0x6d, 0x3c, 0x65, 0xb8, 0x21, 0x8f, 0x2b, 0x24, 0x23, - 0xb2, 0x25, 0xbf, 0x1b, 0xd2, 0x34, 0xd7, 0x06, 0xeb, 0xab, 0xb9, 0x4f, - 0x11, 0x92, 0xf8, 0xff, 0x2f, 0xda, 0x9c, 0x9b, 0xf2, 0x01, 0xf7, 0xd5, - 0xdf, 0xac, 0xaa, 0xd8, 0x5e, 0xa5, 0xb7, 0xeb, 0x31, 0xb9, 0xf7, 0xed, - 0xac, 0xe7, 0x59, 0xd9, 0xee, 0xc1, 0x3b, 0xa3, 0x55, 0xdc, 0xa2, 0x50, - 0x6a, 0x28, 0xbe, 0xdd, 0x7d, 0xc8, 0xa6, 0xdc, 0x02, 0x4f, 0xb4, 0xfd, - 0x4d, 0xfb, 0x00, 0xe5, 0x1d, 0xb7, 0x9e, 0xa0, 0x7c, 0xc5, 0x7b, 0x2d, - 0xb7, 0x62, 0x7e, 0xd2, 0x25, 0xa9, 0x26, 0xe2, 0x14, 0xf3, 0xec, 0xba, - 0x35, 0x91, 0x81, 0x8f, 0xc9, 0x36, 0x32, 0xc4, 0xd3, 0x07, 0xa3, 0x21, - 0xe4, 0xa9, 0x0e, 0xb3, 0x9c, 0x9a, 0xe3, 0xb7, 0x71, 0x6e, 0x54, 0x16, - 0x3e, 0x13, 0xf2, 0x70, 0xbb, 0x8d, 0x21, 0x23, 0x72, 0xfa, 0x2d, 0x59, - 0xa1, 0x79, 0x5c, 0x78, 0x34, 0x5f, 0x0f, 0x3f, 0xc5, 0x52, 0x69, 0x6c, - 0x38, 0xe5, 0xa6, 0xb8, 0xf9, 0xe3, 0xd8, 0x70, 0x50, 0xa5, 0xeb, 0x6d, - 0x06, 0x4e, 0x11, 0xb4, 0xf9, 0xd1, 0x72, 0xf0, 0x1e, 0x60, 0x64, 0xe0, - 0xbd, 0x4a, 0xbc, 0xb4, 0x5e, 0x13, 0x6f, 0xda, 0xa3, 0xf9, 0x06, 0xc8, - 0x63, 0x71, 0x7c, 0x92, 0xf6, 0x89, 0xf5, 0x23, 0xbc, 0xd7, 0xa7, 0x95, - 0xbb, 0x11, 0x1e, 0x58, 0x2f, 0x63, 0x28, 0x88, 0x48, 0xdf, 0x79, 0xaa, - 0x03, 0x5f, 0x8a, 0x59, 0xfd, 0x3e, 0x8a, 0xb7, 0xdb, 0x09, 0x6b, 0x3e, - 0x2e, 0x42, 0x94, 0x9f, 0x58, 0x5e, 0x51, 0xa8, 0x11, 0x85, 0xe4, 0xc8, - 0xfb, 0x41, 0x16, 0xde, 0x76, 0x64, 0xe6, 0xc1, 0xde, 0x1c, 0xd9, 0x89, - 0xf4, 0xc5, 0xbe, 0xfd, 0x1f, 0x55, 0xc3, 0xdb, 0xc0, 0x72, 0x5a, 0xe8, - 0xfb, 0x2d, 0xe2, 0x7d, 0x96, 0x11, 0x63, 0xfe, 0x4a, 0x3d, 0x50, 0x65, - 0xd6, 0x88, 0x17, 0x46, 0x59, 0x2f, 0x36, 0x9e, 0x36, 0x0c, 0xa6, 0x85, - 0xea, 0xd6, 0xdf, 0x27, 0x8c, 0xaf, 0x59, 0x0c, 0x95, 0x5f, 0x8a, 0x2b, - 0x38, 0x31, 0x8a, 0xdf, 0x52, 0x20, 0x37, 0x57, 0xe3, 0x08, 0x15, 0x13, - 0x2c, 0x3f, 0xb6, 0x37, 0xa3, 0x23, 0x92, 0x83, 0x55, 0x6b, 0x76, 0x21, - 0xe7, 0xd8, 0x79, 0x8d, 0xb8, 0x9f, 0x64, 0x16, 0x69, 0x23, 0x8c, 0xa9, - 0x72, 0x2f, 0xc5, 0xa2, 0x58, 0xaf, 0xe0, 0xb6, 0x51, 0xbc, 0xbe, 0x1c, - 0xf2, 0xa9, 0x46, 0x1c, 0x03, 0xaa, 0x59, 0x9f, 0xfc, 0x3e, 0xe9, 0xce, - 0xcf, 0xb8, 0x8e, 0xc7, 0xd5, 0x88, 0x1d, 0x63, 0x49, 0x6c, 0x8e, 0xc9, - 0x84, 0x93, 0xfb, 0x08, 0xbf, 0xf5, 0x11, 0x3e, 0xb5, 0xed, 0xb1, 0x08, - 0xeb, 0x94, 0x75, 0x66, 0x79, 0xc3, 0xed, 0xad, 0xb8, 0x77, 0xb2, 0x1e, - 0xae, 0xb1, 0x06, 0x54, 0x8f, 0x05, 0xb1, 0x9d, 0xe8, 0x3d, 0x62, 0x70, - 0xbf, 0xcd, 0x3a, 0x2d, 0x41, 0x2b, 0xaf, 0x97, 0xb5, 0x7e, 0x55, 0xb6, - 0xf1, 0xa4, 0xa1, 0x19, 0x4f, 0x0a, 0x2f, 0xde, 0xa0, 0x5a, 0xf0, 0xe3, - 0xd8, 0xad, 0xc8, 0xcc, 0x31, 0x9d, 0xcd, 0x1d, 0x57, 0xcf, 0xf2, 0x35, - 0xda, 0xd1, 0xec, 0x5c, 0x57, 0x2d, 0x5c, 0x43, 0x1d, 0x21, 0xe7, 0xda, - 0x44, 0xd7, 0xc5, 0x1e, 0xef, 0x7f, 0x74, 0xf3, 0x35, 0x09, 0xfe, 0x9c, - 0x76, 0x57, 0x6c, 0xf0, 0xdf, 0xc0, 0x72, 0xfa, 0x0f, 0x1f, 0x2d, 0x8c, - 0x81, 0x52, 0x4f, 0xbc, 0xc7, 0xc6, 0x65, 0xc4, 0xdb, 0xa8, 0xf8, 0x6d, - 0x60, 0x7d, 0xf4, 0x21, 0x43, 0x71, 0xaf, 0x96, 0xe2, 0xde, 0xf1, 0x76, - 0x81, 0x1f, 0x45, 0x4c, 0xfc, 0x28, 0xcf, 0x71, 0xd0, 0x85, 0x27, 0xd2, - 0x5a, 0xc8, 0x12, 0xe1, 0x9e, 0x9d, 0x42, 0x42, 0xb2, 0x91, 0x78, 0xa3, - 0x98, 0x3c, 0x9b, 0xe6, 0x18, 0xec, 0x72, 0xf6, 0xd8, 0xb9, 0xde, 0x48, - 0x2c, 0xc4, 0xcc, 0x52, 0x5c, 0xb3, 0xfa, 0x28, 0x37, 0x7c, 0x5c, 0xe0, - 0x39, 0x2d, 0xbc, 0x15, 0x67, 0x79, 0x69, 0xd1, 0x94, 0x74, 0x37, 0x92, - 0x39, 0xf6, 0x4b, 0x5a, 0x8e, 0xd6, 0x3a, 0x92, 0xad, 0x42, 0x6f, 0xbc, - 0x5b, 0xdc, 0x56, 0xbc, 0x85, 0xfb, 0xf9, 0xea, 0x12, 0x73, 0x8b, 0xd8, - 0x30, 0xcd, 0xfd, 0xb8, 0x5e, 0xd1, 0x5b, 0x64, 0x3f, 0x19, 0x14, 0xbf, - 0x53, 0xbc, 0xbc, 0x37, 0xb7, 0x68, 0x17, 0xdc, 0x93, 0xb3, 0x3c, 0x2f, - 0x90, 0x5e, 0xee, 0x1f, 0xc5, 0x1f, 0xd7, 0x43, 0xa6, 0x98, 0xd6, 0x8e, - 0x72, 0xa5, 0xf6, 0xa1, 0xfb, 0x5f, 0xc1, 0x10, 0xe5, 0x57, 0x69, 0x41, - 0xbf, 0x2b, 0x72, 0x12, 0x3e, 0x59, 0xb3, 0xdf, 0x0e, 0x2d, 0x61, 0xfd, - 0x12, 0x6e, 0x24, 0xdd, 0xec, 0xce, 0xee, 0xb1, 0xdf, 0x76, 0x7a, 0x6a, - 0x6c, 0x8f, 0x4e, 0xc9, 0xc4, 0xba, 0xc6, 0x76, 0xf2, 0xb9, 0xc7, 0x47, - 0x97, 0x41, 0xd1, 0xb9, 0x17, 0x5f, 0x8b, 0xa8, 0xe3, 0x37, 0x1e, 0x14, - 0x46, 0x19, 0xaf, 0x18, 0x1d, 0xaf, 0x8f, 0x29, 0xf0, 0xd1, 0xb3, 0xd9, - 0x98, 0xc0, 0xa9, 0xf6, 0xca, 0xfc, 0xcd, 0xb9, 0xab, 0x91, 0x56, 0xbd, - 0xa8, 0xd3, 0x9b, 0x91, 0x55, 0x7d, 0xb4, 0xee, 0xad, 0x0b, 0x73, 0xfe, - 0xb8, 0x9a, 0xeb, 0x56, 0xd9, 0xbc, 0xb7, 0xba, 0xa2, 0x0f, 0x45, 0xa9, - 0xd4, 0x31, 0x8a, 0xe5, 0xa3, 0xb5, 0x0e, 0xb6, 0xf7, 0x62, 0xc7, 0x88, - 0x4f, 0xbc, 0x92, 0xfe, 0xd7, 0x36, 0xdb, 0xcc, 0x01, 0xb2, 0xe5, 0x2a, - 0x7d, 0x71, 0xce, 0xd7, 0x9d, 0x77, 0x6b, 0x29, 0x2e, 0x0f, 0x8c, 0x4a, - 0x08, 0x2c, 0xdc, 0x8f, 0xe7, 0x42, 0x08, 0xb6, 0x09, 0xfa, 0xde, 0x6b, - 0xe3, 0x0a, 0x05, 0xaa, 0xfe, 0x06, 0x8d, 0x73, 0xd1, 0x55, 0xa1, 0xfa, - 0xd8, 0xc2, 0xc3, 0xf1, 0x04, 0x2e, 0x10, 0x06, 0xd9, 0x47, 0xf9, 0x72, - 0x57, 0xda, 0xc4, 0xb9, 0xfc, 0x5f, 0x3b, 0xf3, 0xd4, 0x98, 0x1e, 0x4c, - 0xe7, 0xbe, 0x48, 0x57, 0x80, 0x68, 0x7d, 0x98, 0x68, 0xe2, 0x67, 0x17, - 0x9c, 0xda, 0xfa, 0xf9, 0xcb, 0x6a, 0x12, 0x69, 0x9c, 0xfb, 0x31, 0x95, - 0x38, 0xda, 0x69, 0x28, 0x16, 0xf7, 0xb6, 0xe7, 0x27, 0x2c, 0x9c, 0xbb, - 0xb6, 0x0e, 0x9f, 0x4c, 0x34, 0xe3, 0xde, 0x51, 0x2f, 0x2e, 0x4e, 0xd8, - 0xb8, 0x66, 0x0d, 0xee, 0x08, 0x12, 0x8e, 0xa9, 0xa3, 0x78, 0xf1, 0x1a, - 0xd5, 0x0d, 0x54, 0x53, 0x92, 0xf7, 0x44, 0x12, 0x1b, 0x85, 0x8d, 0x68, - 0x0c, 0xa9, 0x1b, 0xe2, 0x91, 0xd0, 0x05, 0x7c, 0xc7, 0x26, 0x7d, 0xa8, - 0xb2, 0xd9, 0x2d, 0x5c, 0xce, 0xde, 0x5c, 0xaf, 0xb3, 0x97, 0x27, 0x4d, - 0x0f, 0x0a, 0xb9, 0x78, 0xb9, 0xbf, 0x7f, 0x59, 0x0c, 0xe7, 0xb8, 0xcd, - 0xf5, 0xff, 0xb8, 0xed, 0xd6, 0xb9, 0xcf, 0xb1, 0x45, 0xec, 0xc9, 0x5d, - 0x8a, 0xeb, 0x97, 0x62, 0xf9, 0xae, 0x85, 0x18, 0x3e, 0x9c, 0x7f, 0xf3, - 0x0b, 0x18, 0x24, 0xb4, 0xb0, 0x57, 0xc0, 0xb1, 0xdb, 0x23, 0xde, 0x22, - 0xbf, 0xdb, 0x6b, 0xb0, 0x9f, 0x9d, 0x0c, 0x52, 0x74, 0x85, 0x8b, 0xe4, - 0x79, 0x3f, 0x9f, 0xcf, 0x08, 0xd8, 0xd8, 0x42, 0x7c, 0x7a, 0x48, 0x8e, - 0x6b, 0xda, 0xdd, 0xe8, 0xa7, 0x78, 0xee, 0x8e, 0xf9, 0x28, 0x0e, 0xa8, - 0x78, 0xd5, 0x60, 0x1b, 0xee, 0x59, 0x88, 0xe7, 0xbc, 0x57, 0x55, 0xd9, - 0x1f, 0xfe, 0x7c, 0xcf, 0x78, 0xd1, 0x36, 0x0d, 0x24, 0x97, 0xc2, 0xfb, - 0x4e, 0x5c, 0x27, 0xec, 0xad, 0x10, 0xee, 0xde, 0x84, 0xc4, 0x12, 0x8d, - 0xdb, 0x02, 0x84, 0x5b, 0x2d, 0xfc, 0xd7, 0xf6, 0x7e, 0xdc, 0x33, 0x2e, - 0xa1, 0x46, 0xe7, 0x3d, 0x1a, 0xb2, 0x83, 0x7a, 0x8e, 0x5f, 0xdd, 0x18, - 0x1a, 0xf7, 0x88, 0x17, 0xa9, 0x26, 0x39, 0xd2, 0xf3, 0x10, 0x96, 0xb4, - 0xdd, 0x09, 0x38, 0xb6, 0xc7, 0xff, 0x7f, 0x0b, 0xa9, 0x65, 0xbc, 0x3e, - 0xf7, 0xa9, 0x04, 0x7c, 0x6d, 0xcc, 0x07, 0xbc, 0xef, 0xd1, 0xfc, 0xdb, - 0x47, 0x5c, 0xe2, 0x42, 0xfa, 0xa7, 0xf6, 0x89, 0x00, 0xe7, 0x58, 0x7e, - 0x56, 0x4b, 0xb1, 0x9e, 0xc7, 0xb2, 0x0e, 0x7d, 0x54, 0xd7, 0xf5, 0x63, - 0x84, 0xe8, 0x3a, 0xe3, 0xcc, 0xf5, 0xbd, 0x05, 0xfa, 0x7d, 0xa2, 0x2e, - 0xa3, 0x58, 0x41, 0xa2, 0x45, 0xbd, 0xb6, 0x07, 0x75, 0xc5, 0xcb, 0x73, - 0xd5, 0x5f, 0x29, 0xdc, 0xeb, 0x63, 0xdf, 0xa9, 0x26, 0x5f, 0xf9, 0x79, - 0x5a, 0xe0, 0xbc, 0x63, 0x7b, 0xdb, 0xd0, 0x9c, 0xa7, 0x1a, 0xda, 0x89, - 0x21, 0x3c, 0x6e, 0x7d, 0xc5, 0xa6, 0xa5, 0x7e, 0xdc, 0x47, 0xbc, 0xd4, - 0x12, 0x2f, 0x1f, 0xc6, 0x56, 0xd0, 0x3a, 0x7c, 0x2f, 0xa3, 0x54, 0xec, - 0x6c, 0x71, 0x2e, 0x2a, 0xc0, 0xfd, 0x5c, 0x2b, 0x45, 0xb0, 0x73, 0x3c, - 0xd2, 0xe7, 0x93, 0xd8, 0x0e, 0x23, 0xb8, 0x7b, 0xfa, 0x37, 0x3c, 0x54, - 0x17, 0xd3, 0x5c, 0x41, 0xdc, 0x9e, 0x71, 0x89, 0xb7, 0xa9, 0xd6, 0x78, - 0x3e, 0x2d, 0x2d, 0x93, 0xf1, 0xac, 0x7d, 0x24, 0x30, 0x84, 0x1b, 0x8c, - 0x6e, 0xdc, 0x45, 0x36, 0xd8, 0xd9, 0x3c, 0x84, 0x09, 0xb2, 0x81, 0xed, - 0x0d, 0x54, 0xff, 0xc4, 0x4a, 0xf6, 0xb6, 0x00, 0xcb, 0x51, 0xa0, 0x8b, - 0xee, 0xd7, 0x53, 0x4d, 0x24, 0xc5, 0xc8, 0xda, 0x1a, 0x04, 0xf9, 0xac, - 0x36, 0x9a, 0xc4, 0xcf, 0x9d, 0x35, 0xeb, 0xf5, 0xc5, 0xf8, 0xcc, 0x39, - 0xf6, 0x8b, 0xf4, 0x58, 0x76, 0xb5, 0xae, 0x47, 0x37, 0x49, 0xcd, 0xa3, - 0x73, 0x64, 0xb3, 0x1b, 0xda, 0x2e, 0x7f, 0x6f, 0x51, 0x46, 0x06, 0xaa, - 0xda, 0x66, 0xec, 0xb2, 0x3a, 0x0c, 0xb5, 0xed, 0x72, 0xdd, 0x2f, 0xce, - 0xc1, 0x34, 0x57, 0xe2, 0x5a, 0x48, 0x8a, 0xa8, 0x77, 0xe0, 0x49, 0x5a, - 0x23, 0x88, 0xad, 0xc5, 0x6e, 0x6c, 0x1b, 0x97, 0x3f, 0xcb, 0xed, 0x7e, - 0xb6, 0xe5, 0xcf, 0xf8, 0xdf, 0x31, 0x1e, 0xe9, 0xf2, 0x2e, 0xf0, 0x7f, - 0xd7, 0xf4, 0x67, 0x73, 0x0d, 0x66, 0x38, 0x86, 0xf2, 0x7c, 0x9c, 0x67, - 0x17, 0xe5, 0x1b, 0xc4, 0x7d, 0xce, 0x7c, 0x5b, 0x3d, 0xec, 0xe3, 0x6e, - 0xca, 0x95, 0x1b, 0xdb, 0x2c, 0xbc, 0x9a, 0xb8, 0xd7, 0xde, 0xe1, 0xc8, - 0xa0, 0xc3, 0xc3, 0xef, 0x77, 0x35, 0x9f, 0x5e, 0xd8, 0x43, 0xaf, 0xf4, - 0x30, 0x9f, 0x2f, 0xb5, 0x3a, 0xfd, 0xf9, 0xef, 0x51, 0x7e, 0x7c, 0xf6, - 0x73, 0x3d, 0xb2, 0x3b, 0xdd, 0xdc, 0xd7, 0x7f, 0xaa, 0xa4, 0x08, 0xd7, - 0x78, 0x8d, 0x70, 0x8f, 0x33, 0x6d, 0xff, 0x45, 0xa9, 0xf8, 0xd8, 0x5f, - 0x23, 0x19, 0xe0, 0x3d, 0xba, 0x8a, 0xfd, 0x47, 0xdb, 0xef, 0x06, 0x8e, - 0x5a, 0x9e, 0xea, 0xb5, 0xa0, 0x3a, 0xb9, 0xc7, 0xb1, 0x87, 0xa5, 0x66, - 0x7c, 0xdd, 0xb3, 0xcd, 0x5c, 0x2b, 0x73, 0x5f, 0xad, 0x73, 0xdd, 0x24, - 0x81, 0xb7, 0xad, 0x2a, 0xaf, 0xa9, 0x9d, 0xe0, 0x5e, 0x37, 0xf7, 0xc0, - 0x97, 0xeb, 0xf0, 0xd6, 0xaf, 0xb5, 0x3c, 0x4b, 0xd6, 0xba, 0xc4, 0x15, - 0x99, 0x3e, 0xb2, 0x3d, 0x1d, 0x89, 0x8c, 0xe5, 0x6d, 0x5c, 0x1b, 0xc2, - 0x03, 0x99, 0x4a, 0x0c, 0x5b, 0x9f, 0x6b, 0x45, 0xeb, 0x14, 0x59, 0x63, - 0x26, 0x88, 0x96, 0x89, 0xf0, 0xc0, 0xd7, 0xa5, 0xf0, 0xe0, 0xbc, 0xc4, - 0xcf, 0x7c, 0x1d, 0xd7, 0x38, 0x38, 0x56, 0xed, 0x58, 0xed, 0x5c, 0xe3, - 0x1d, 0x57, 0xe7, 0x6f, 0x45, 0x7a, 0xce, 0x33, 0x5f, 0x96, 0x6c, 0x3c, - 0x10, 0x93, 0x70, 0xa3, 0xf1, 0x9f, 0xc9, 0xb7, 0x04, 0xd9, 0xc6, 0xab, - 0x9c, 0x9f, 0x9d, 0xe0, 0xbc, 0x7c, 0xad, 0x8e, 0xb5, 0x99, 0x7a, 0x8a, - 0x49, 0x0d, 0x14, 0x9f, 0xea, 0xf1, 0x11, 0xc5, 0xa4, 0xd5, 0x6b, 0x28, - 0x3c, 0xae, 0xb1, 0xfa, 0xaf, 0x00, 0xef, 0xdf, 0x6a, 0x56, 0x51, 0x68, - 0x7d, 0xdd, 0x92, 0xd6, 0xd3, 0x20, 0xa9, 0xb8, 0x2b, 0xc2, 0x73, 0x27, - 0x3a, 0xd6, 0xe6, 0x2b, 0xf9, 0x74, 0x95, 0x93, 0x3f, 0xf5, 0x8e, 0xab, - 0x66, 0x2b, 0x79, 0xd6, 0x98, 0xd5, 0x7e, 0x90, 0x92, 0x78, 0xcf, 0xa1, - 0x0f, 0xe3, 0xd9, 0x14, 0xf6, 0x64, 0x43, 0xf8, 0x45, 0xa6, 0x8a, 0x6c, - 0x23, 0x6c, 0x7c, 0x17, 0x3c, 0xa6, 0xb5, 0x23, 0x96, 0x0f, 0x47, 0x1f, - 0x90, 0xfe, 0x1c, 0x65, 0x97, 0x76, 0x98, 0x10, 0x36, 0x72, 0xae, 0x96, - 0xd0, 0x4b, 0xf8, 0x73, 0x67, 0x8f, 0x0a, 0xa8, 0xf0, 0xd0, 0x9c, 0x07, - 0x46, 0x33, 0x9e, 0x79, 0x38, 0xfd, 0x4c, 0xde, 0x73, 0x95, 0xb0, 0xc1, - 0xb8, 0x97, 0xe4, 0x2c, 0xd0, 0xdc, 0x56, 0x8f, 0x72, 0xaf, 0x0b, 0xe3, - 0x24, 0x13, 0xc5, 0x0c, 0x74, 0x28, 0x23, 0x28, 0x2f, 0xec, 0x27, 0x26, - 0x64, 0xca, 0xd0, 0x2f, 0x17, 0x81, 0x03, 0x14, 0x3b, 0x36, 0xc7, 0x7e, - 0x45, 0xb9, 0xa1, 0xb2, 0x7f, 0x91, 0x9e, 0x14, 0x58, 0xa2, 0x27, 0x49, - 0x1e, 0x2e, 0xff, 0x41, 0xaa, 0xef, 0x0f, 0x96, 0xf8, 0x7d, 0xcf, 0x7c, - 0xd2, 0x99, 0x3f, 0xb2, 0x6f, 0x85, 0x24, 0xe1, 0xea, 0xb6, 0xa3, 0xc8, - 0x2d, 0xad, 0xd0, 0x10, 0x24, 0x4c, 0xc0, 0x75, 0x60, 0x03, 0xf1, 0xb8, - 0xe5, 0x11, 0xee, 0x09, 0x5e, 0xd9, 0x71, 0xdd, 0x14, 0xfb, 0x75, 0xa0, - 0xe3, 0xe7, 0x69, 0x2d, 0xd9, 0x20, 0x33, 0xae, 0x4c, 0x74, 0xdc, 0x3d, - 0xc2, 0xb9, 0xad, 0x8d, 0x6b, 0x71, 0xca, 0xcb, 0xda, 0x60, 0xa3, 0xf0, - 0x89, 0x1b, 0x33, 0x54, 0x8f, 0x13, 0xbd, 0xef, 0x47, 0xb4, 0x20, 0xc9, - 0xae, 0xeb, 0x4e, 0xd1, 0xcf, 0x78, 0xdf, 0x91, 0xdb, 0x55, 0xf9, 0x0a, - 0xee, 0x08, 0x2f, 0xe0, 0x90, 0xa8, 0x83, 0x3b, 0x6c, 0x7b, 0x77, 0x8c, - 0xf3, 0xb8, 0xb3, 0x9f, 0x4e, 0xf7, 0x63, 0x94, 0x77, 0x15, 0x0c, 0x33, - 0x7d, 0x7c, 0x2e, 0x42, 0xa2, 0x3a, 0x2e, 0x7b, 0x7a, 0x01, 0x97, 0xf8, - 0xb0, 0x97, 0xee, 0x97, 0x1d, 0x7c, 0xc2, 0x67, 0xfb, 0x56, 0x75, 0xa8, - 0x8f, 0xf0, 0x79, 0xc0, 0x2b, 0x3b, 0x36, 0x4c, 0x6a, 0x21, 0x89, 0xf8, - 0xd8, 0xc3, 0x7b, 0xdb, 0x34, 0xe7, 0xac, 0xc1, 0x74, 0xfb, 0x3a, 0xb8, - 0x97, 0xb9, 0x9c, 0xe8, 0xb6, 0xb3, 0x61, 0xc2, 0x49, 0x15, 0x5b, 0x49, - 0xe4, 0xa9, 0x22, 0xbe, 0xa2, 0xc2, 0xab, 0x9b, 0x74, 0x72, 0x2c, 0x9d, - 0xc4, 0xf3, 0xf1, 0x8a, 0x7e, 0xd6, 0xe7, 0xbf, 0x81, 0x54, 0x43, 0x27, - 0x46, 0xb3, 0xaa, 0x7f, 0x63, 0xa6, 0x13, 0x13, 0xa4, 0xc3, 0x3b, 0x8a, - 0x41, 0x7f, 0x67, 0x46, 0xc7, 0xb6, 0x22, 0xd7, 0x26, 0xa1, 0x8e, 0xdd, - 0x93, 0xb9, 0x85, 0x1a, 0xb2, 0x92, 0x4b, 0xf6, 0x67, 0x2a, 0x36, 0x17, - 0xce, 0x7b, 0xe6, 0x43, 0xa2, 0x32, 0xaf, 0x42, 0xeb, 0x28, 0x23, 0x7f, - 0x6c, 0x63, 0x29, 0xdb, 0xc2, 0xad, 0x98, 0x9c, 0xf2, 0x5b, 0x57, 0x98, - 0x2a, 0xd6, 0xb6, 0xbd, 0x41, 0xef, 0xb6, 0xe2, 0x97, 0xc7, 0xbf, 0x86, - 0xf2, 0x37, 0x5d, 0x78, 0x3c, 0x93, 0x44, 0x4b, 0xdb, 0x4d, 0x48, 0xfd, - 0xae, 0x82, 0xa7, 0x32, 0x3e, 0x3c, 0x97, 0xa9, 0xec, 0x77, 0x7f, 0x3f, - 0x4b, 0x7e, 0x48, 0x3e, 0xf0, 0xec, 0x97, 0xee, 0x31, 0x52, 0x3c, 0x97, - 0x79, 0xff, 0xfb, 0x9f, 0x1e, 0x77, 0xd6, 0x19, 0xe7, 0x11, 0xf5, 0xe3, - 0x8b, 0xf3, 0xda, 0xd0, 0xdb, 0xfe, 0xb1, 0x77, 0xb4, 0x28, 0x40, 0x31, - 0xa4, 0x72, 0x3e, 0x40, 0x28, 0xe3, 0xce, 0x9e, 0x0b, 0xe1, 0xdf, 0x88, - 0x71, 0x0e, 0x16, 0xaa, 0x08, 0x57, 0xad, 0x20, 0x59, 0xe8, 0x99, 0x80, - 0x5f, 0x2a, 0xaa, 0xf4, 0x69, 0xf2, 0xbb, 0x48, 0x3e, 0xae, 0xe2, 0x0f, - 0x29, 0xa6, 0xb0, 0x4f, 0x55, 0x72, 0x9c, 0x54, 0xdc, 0xec, 0x85, 0x57, - 0xa7, 0x6b, 0xc5, 0xa6, 0x43, 0xf9, 0xb7, 0xf9, 0x39, 0xd9, 0x75, 0xe5, - 0x7b, 0xe4, 0xd2, 0x77, 0xd2, 0xb3, 0x23, 0xb3, 0xdb, 0x68, 0x3c, 0xcb, - 0xe2, 0x59, 0x3b, 0xb5, 0x85, 0xe5, 0x15, 0xf0, 0xbf, 0x41, 0xf2, 0x9f, - 0x24, 0x1a, 0xb3, 0xb4, 0xc6, 0xeb, 0xb4, 0x66, 0xa6, 0xd8, 0x47, 0x63, - 0xf8, 0x19, 0xc9, 0xd9, 0xb1, 0xdd, 0xad, 0x5e, 0xde, 0xdb, 0x7f, 0x2e, - 0x03, 0xaa, 0xbb, 0x2d, 0xcd, 0xb5, 0x70, 0x16, 0x72, 0x18, 0x8b, 0xf8, - 0xf1, 0x2e, 0x5c, 0x3f, 0xaa, 0x25, 0x2d, 0xc2, 0x61, 0x29, 0x15, 0xc2, - 0x65, 0xb2, 0x0d, 0xc7, 0xc9, 0x86, 0x9b, 0x88, 0xa7, 0x70, 0xe8, 0x1c, - 0x8d, 0xb7, 0x5c, 0x0a, 0xf6, 0x4f, 0xc8, 0x38, 0xc7, 0xfb, 0xaf, 0xa2, - 0xf2, 0x3e, 0x01, 0x7f, 0x1a, 0xbb, 0xf8, 0x7f, 0x0d, 0xe1, 0xf2, 0x70, - 0x82, 0xb2, 0x2a, 0xe3, 0x5b, 0x4f, 0xbe, 0xfd, 0x21, 0x1c, 0xa4, 0x3a, - 0x79, 0x47, 0x2c, 0x84, 0x64, 0x7d, 0x1c, 0x1e, 0xbd, 0x65, 0xe0, 0x22, - 0xfe, 0x87, 0x5d, 0xe6, 0x3d, 0x6c, 0x11, 0x4e, 0x5c, 0xc4, 0xa7, 0xb6, - 0xac, 0xeb, 0xa7, 0x67, 0xa0, 0x97, 0xcf, 0xa1, 0x65, 0xf0, 0x13, 0xbc, - 0x6b, 0xf3, 0xfe, 0xb6, 0x22, 0xcb, 0x78, 0xd1, 0x08, 0xab, 0x2e, 0x04, - 0x50, 0x0e, 0xc8, 0xd8, 0x6c, 0x30, 0xfe, 0xd7, 0x06, 0x1f, 0x83, 0x36, - 0x70, 0x5e, 0xb4, 0xf4, 0x7f, 0x88, 0xb3, 0x76, 0xae, 0x9e, 0xd7, 0x15, - 0x48, 0x5c, 0xdd, 0x72, 0xba, 0x0a, 0x5a, 0x97, 0x5b, 0xe8, 0x89, 0x46, - 0xf9, 0xaf, 0xec, 0xb3, 0x81, 0x4f, 0x6d, 0x3d, 0xf2, 0x29, 0xe1, 0x20, - 0x3d, 0x38, 0x4d, 0xb6, 0xdf, 0x8f, 0x45, 0xda, 0x5e, 0x27, 0xfe, 0xa9, - 0xb0, 0xd3, 0x79, 0x9f, 0xc8, 0xf2, 0xec, 0x25, 0xda, 0x5e, 0x23, 0x1c, - 0xb0, 0x23, 0x76, 0xd1, 0x4e, 0x2e, 0xe5, 0x1a, 0xe9, 0x67, 0xde, 0x4a, - 0xff, 0x98, 0x7b, 0x0e, 0xb7, 0xe2, 0x76, 0xc2, 0x77, 0xc3, 0xd9, 0x45, - 0xbc, 0xe6, 0xa6, 0x18, 0xcc, 0xb1, 0xbf, 0x7c, 0x15, 0x95, 0xd4, 0x12, - 0x95, 0xc7, 0xd8, 0x4d, 0x71, 0x61, 0x97, 0x93, 0x0b, 0xe0, 0x5d, 0xbe, - 0xb6, 0x0d, 0x9f, 0x4c, 0x95, 0xbc, 0xe4, 0x4b, 0xeb, 0xf5, 0x35, 0x10, - 0xc1, 0x8c, 0x25, 0xea, 0x4c, 0x19, 0x1f, 0xb6, 0x6b, 0x5d, 0x92, 0x3c, - 0x88, 0xab, 0x63, 0x96, 0xed, 0xd3, 0xf5, 0xbe, 0x56, 0x11, 0xe9, 0x29, - 0x8a, 0x28, 0x6a, 0x8a, 0x3e, 0xa5, 0xa6, 0xd8, 0xaa, 0x78, 0x8b, 0x96, - 0x47, 0x5d, 0x7b, 0x17, 0xd5, 0xb4, 0x43, 0x58, 0x19, 0xf3, 0x51, 0x3d, - 0xac, 0x19, 0x17, 0x50, 0x45, 0xf2, 0x0f, 0x61, 0x6f, 0xc9, 0x84, 0x2b, - 0xb3, 0x13, 0xee, 0x4c, 0x58, 0xdd, 0x83, 0x21, 0x24, 0x83, 0x15, 0x4c, - 0xab, 0x90, 0xae, 0xaa, 0xdb, 0x19, 0xcb, 0xdc, 0x85, 0xb3, 0x39, 0xc6, - 0xe7, 0x54, 0x9f, 0xa6, 0xf9, 0x3b, 0xbc, 0x2f, 0xc5, 0x4d, 0x3c, 0x49, - 0x75, 0x95, 0xa7, 0xad, 0x91, 0xf4, 0xd0, 0x84, 0xe1, 0x92, 0x60, 0xb3, - 0x22, 0x5d, 0xc0, 0xfb, 0x64, 0xbb, 0x82, 0x03, 0x33, 0x94, 0x48, 0x28, - 0x5f, 0xb9, 0x32, 0x2a, 0xc5, 0x09, 0xc6, 0xd8, 0x3e, 0xfa, 0x1e, 0xe0, - 0x33, 0x3f, 0x64, 0x67, 0x57, 0x76, 0xb4, 0x3a, 0xb1, 0xa6, 0x8d, 0x6a, - 0x9c, 0xa7, 0xbd, 0x95, 0x9a, 0xcb, 0x44, 0xcd, 0xf8, 0x62, 0xad, 0xb8, - 0xe1, 0xe6, 0x1a, 0xaa, 0xc5, 0x87, 0x4b, 0x8c, 0x03, 0x2b, 0x67, 0x3c, - 0x37, 0xc4, 0xda, 0x08, 0xb3, 0x8b, 0x05, 0x8c, 0x35, 0xac, 0xf9, 0xb0, - 0x1e, 0x07, 0xa9, 0x56, 0xf6, 0xeb, 0x5b, 0x91, 0x51, 0xcb, 0xde, 0x37, - 0xe3, 0x8c, 0x7f, 0xe1, 0xdd, 0x46, 0x18, 0x6a, 0x24, 0xfd, 0x55, 0x8e, - 0x99, 0x9e, 0x3b, 0xe2, 0x06, 0x0e, 0x8f, 0x52, 0x88, 0xd2, 0xd7, 0xa3, - 0x6e, 0x4d, 0x37, 0x3e, 0xac, 0x67, 0xfc, 0x4b, 0xb1, 0x8a, 0xe8, 0xd9, - 0x33, 0x13, 0x70, 0xce, 0x24, 0xec, 0x2d, 0x2d, 0xd2, 0x7c, 0x39, 0xad, - 0x5f, 0x46, 0x23, 0xcb, 0xe4, 0x9f, 0xa2, 0x91, 0x6c, 0x96, 0x30, 0xcf, - 0x68, 0x7a, 0x1b, 0x5e, 0x4e, 0xf3, 0xbc, 0xe1, 0xa4, 0x21, 0x54, 0xee, - 0x6b, 0x3b, 0x32, 0xb1, 0x66, 0x78, 0x0d, 0x5e, 0x7f, 0x71, 0x9d, 0x00, - 0xf6, 0x7d, 0xa9, 0x3c, 0xfe, 0x39, 0x6b, 0x51, 0xdc, 0x18, 0x5d, 0x4f, - 0x75, 0x50, 0x14, 0xfa, 0xef, 0x94, 0x49, 0x1f, 0xdc, 0xe7, 0x5d, 0x41, - 0x98, 0x17, 0x9e, 0x57, 0xe2, 0x7c, 0xee, 0xd7, 0x1e, 0x52, 0x4c, 0xdb, - 0x76, 0xb7, 0xeb, 0xea, 0x3b, 0x60, 0x3b, 0xf4, 0xf1, 0x7e, 0x81, 0x67, - 0x4f, 0xbb, 0x0f, 0x07, 0x28, 0x07, 0x3e, 0x91, 0x6e, 0xb1, 0x6e, 0x12, - 0x7c, 0x7e, 0x89, 0x62, 0xb6, 0x48, 0xd1, 0xbb, 0x37, 0xd6, 0xb0, 0xcf, - 0xee, 0x2e, 0xed, 0x84, 0x94, 0x89, 0xd4, 0x70, 0x3d, 0x51, 0x45, 0x35, - 0xf4, 0x70, 0x9a, 0xe9, 0xb5, 0x87, 0x5c, 0x34, 0xd7, 0xae, 0xb8, 0x3e, - 0x7f, 0x3d, 0xd9, 0x45, 0xa3, 0xc9, 0x72, 0x0c, 0xe0, 0x08, 0x8d, 0x0d, - 0x95, 0x58, 0x96, 0x7d, 0x35, 0xdc, 0x33, 0xdc, 0x4b, 0xfa, 0xad, 0xcb, - 0x56, 0xe6, 0xc9, 0x96, 0xfa, 0xb1, 0x62, 0x64, 0xdc, 0x99, 0x87, 0x7d, - 0xe0, 0xc5, 0xf8, 0x00, 0xf6, 0xa6, 0x03, 0x98, 0x49, 0xb7, 0xa8, 0x2f, - 0x38, 0xfb, 0xed, 0x95, 0xfe, 0xd2, 0x70, 0x7a, 0x71, 0x4c, 0x00, 0xd3, - 0x97, 0xfe, 0x67, 0xf9, 0x54, 0xfa, 0x8e, 0x95, 0x7e, 0x80, 0x82, 0x5c, - 0xa0, 0x82, 0x87, 0x28, 0x56, 0x78, 0x1f, 0x26, 0xbd, 0x9e, 0x27, 0xbd, - 0x4a, 0xa4, 0xd7, 0x17, 0x8c, 0xef, 0x33, 0x66, 0xf1, 0xec, 0x8e, 0xfb, - 0x78, 0x8f, 0xc5, 0x22, 0xd0, 0xe2, 0x8c, 0xc9, 0xc4, 0x5d, 0x38, 0x33, - 0xc2, 0xe7, 0xf9, 0xd4, 0x8e, 0x53, 0x69, 0x7b, 0xfd, 0x5c, 0xac, 0x25, - 0x75, 0x9e, 0xf0, 0xb4, 0xf5, 0xbb, 0x9a, 0x71, 0x96, 0xfc, 0x34, 0x3b, - 0xf1, 0xfb, 0x38, 0x5b, 0xdf, 0xa2, 0xfe, 0x98, 0xca, 0xf9, 0x47, 0xe3, - 0x0f, 0x21, 0x31, 0x41, 0x75, 0xc3, 0x9a, 0x7f, 0x47, 0x4e, 0x16, 0x87, - 0xac, 0xb7, 0xcc, 0xbf, 0x80, 0xff, 0x86, 0xb3, 0x57, 0x84, 0x8d, 0x17, - 0xc0, 0x63, 0x2a, 0xf5, 0x78, 0x78, 0xf6, 0x1e, 0x3e, 0x8b, 0x14, 0xe4, - 0x5a, 0xdb, 0xd9, 0x0b, 0x4a, 0xf3, 0xde, 0x95, 0x40, 0xae, 0x57, 0x0b, - 0xa5, 0x9c, 0xb3, 0x9f, 0xf0, 0x3e, 0x46, 0x7e, 0x11, 0x1d, 0xe3, 0xf1, - 0x81, 0x0e, 0x3d, 0x1f, 0x82, 0x4c, 0x18, 0x27, 0x15, 0xd0, 0xba, 0x80, - 0xa0, 0xff, 0xb1, 0x74, 0x10, 0xfb, 0xb2, 0x2d, 0x3d, 0x51, 0x71, 0xdb, - 0xc2, 0x9e, 0x31, 0xe7, 0xb9, 0x00, 0xe5, 0x39, 0x2d, 0xf5, 0x18, 0x5a, - 0xfa, 0x7c, 0xe2, 0x56, 0xa4, 0xea, 0x5b, 0xfa, 0x9f, 0x44, 0x38, 0xe1, - 0x11, 0x5a, 0xf4, 0x2c, 0x2a, 0xf3, 0xac, 0xcc, 0xcb, 0x40, 0x03, 0xc7, - 0x99, 0x34, 0x9e, 0x54, 0x65, 0xac, 0x6a, 0xd3, 0xe7, 0xa7, 0xb1, 0x68, - 0x2f, 0x95, 0x31, 0xeb, 0xf3, 0x34, 0x5e, 0x56, 0xa9, 0x0e, 0xae, 0x82, - 0xab, 0x81, 0xf7, 0xe3, 0x76, 0x62, 0x47, 0x9a, 0xf3, 0x34, 0xc9, 0x85, - 0x7c, 0xb3, 0x27, 0xb2, 0x13, 0x03, 0xf9, 0x00, 0x0e, 0x66, 0xc3, 0xfb, - 0xf6, 0x10, 0xae, 0x1b, 0x2b, 0x85, 0x43, 0xdb, 0x45, 0x80, 0xf4, 0x2d, - 0x21, 0xd4, 0x10, 0x44, 0xb5, 0xae, 0xd2, 0xa7, 0x52, 0xcf, 0x9c, 0xa2, - 0x7a, 0xe6, 0x0c, 0xf9, 0x9a, 0x6f, 0xa1, 0x46, 0x5d, 0x99, 0xb3, 0x31, - 0x17, 0xdb, 0x84, 0xf7, 0x1d, 0x9d, 0x05, 0xc9, 0xc6, 0x38, 0x17, 0x39, - 0x35, 0xa8, 0xd8, 0x3e, 0x66, 0x79, 0xee, 0x6f, 0x0f, 0x22, 0x9c, 0x61, - 0xcc, 0x29, 0x7d, 0x53, 0x26, 0x79, 0xcc, 0xe8, 0x43, 0xd8, 0x18, 0x1b, - 0xc2, 0x80, 0xf1, 0xc7, 0xa8, 0x6a, 0xe0, 0x78, 0xa4, 0x58, 0x75, 0x34, - 0xef, 0xc5, 0xf6, 0x6e, 0x84, 0x8f, 0x72, 0x0e, 0x6e, 0xa5, 0x1c, 0xcc, - 0xbe, 0xcb, 0xf3, 0xdf, 0xdf, 0xb1, 0x9a, 0x70, 0x45, 0x6d, 0x7b, 0x25, - 0xcf, 0x5f, 0x9d, 0x57, 0xb9, 0x8f, 0x43, 0xb5, 0x29, 0xbc, 0x6f, 0x5f, - 0x6b, 0xe2, 0x51, 0x8a, 0x31, 0x89, 0x35, 0x6e, 0x60, 0x09, 0x9f, 0xf7, - 0x15, 0x0b, 0x3d, 0x80, 0x40, 0xc7, 0x8a, 0xbc, 0xc0, 0x6c, 0x9c, 0xec, - 0xe3, 0xd7, 0xce, 0xf7, 0x84, 0x16, 0xce, 0x63, 0x72, 0xff, 0xe4, 0x90, - 0x9d, 0xe4, 0x33, 0xfa, 0xd2, 0x3b, 0x64, 0x57, 0x5a, 0xb0, 0x8c, 0x9f, - 0xd5, 0x70, 0x5c, 0x96, 0xf5, 0x45, 0xb9, 0xb3, 0xac, 0x4f, 0xd8, 0xb9, - 0x05, 0x5d, 0xb8, 0xe8, 0x9d, 0xdd, 0x93, 0xda, 0xe0, 0x1e, 0xb4, 0x0c, - 0xfc, 0x5c, 0x54, 0x3b, 0xbb, 0x7f, 0xd3, 0xad, 0x48, 0x2d, 0x37, 0x5d, - 0xbd, 0x9f, 0x64, 0xd7, 0x13, 0x1d, 0xe7, 0x08, 0x84, 0x6e, 0x70, 0xf6, - 0x88, 0xa6, 0x5b, 0xff, 0x84, 0xe6, 0xe6, 0xff, 0xbb, 0x7c, 0x7c, 0x5e, - 0xf1, 0xf9, 0xec, 0x73, 0x76, 0x74, 0x69, 0x45, 0x3e, 0x27, 0xc9, 0xf7, - 0x83, 0xa6, 0x84, 0x46, 0x3d, 0x32, 0xdf, 0x47, 0xdf, 0xff, 0x26, 0x4f, - 0x68, 0xff, 0xda, 0x7e, 0xfc, 0x24, 0x67, 0x62, 0x3f, 0xe5, 0x81, 0x3a, - 0x5d, 0x53, 0x73, 0x08, 0x71, 0x2d, 0xed, 0xf0, 0x7f, 0x4d, 0x8e, 0xfc, - 0xb0, 0x5e, 0x75, 0x6a, 0x8c, 0x0a, 0x7f, 0x3e, 0xe2, 0xef, 0xb7, 0x7c, - 0xec, 0x0b, 0x84, 0x91, 0xc8, 0x66, 0x52, 0x14, 0x57, 0x5a, 0xa2, 0x54, - 0xc1, 0x93, 0x1f, 0x68, 0xfb, 0x40, 0xfe, 0x3a, 0x96, 0x66, 0xf9, 0x07, - 0xfd, 0xdb, 0xf8, 0x48, 0xb0, 0xee, 0xf4, 0x24, 0x8d, 0x90, 0xc4, 0x71, - 0xd7, 0x89, 0xa7, 0x56, 0x48, 0xfa, 0x51, 0x0d, 0xd3, 0x35, 0x5c, 0x0a, - 0x07, 0xbd, 0x7c, 0x7e, 0x9e, 0xc0, 0xe1, 0x36, 0xa3, 0x92, 0x2b, 0xe7, - 0x28, 0x1f, 0xbd, 0x4f, 0x74, 0x1c, 0x8c, 0x35, 0x22, 0x45, 0xf9, 0x28, - 0xa3, 0x57, 0x6c, 0x49, 0x9f, 0x65, 0x8c, 0xd9, 0x46, 0x18, 0x53, 0x0b, - 0xb9, 0xe5, 0x96, 0xc1, 0x17, 0xb1, 0xd3, 0x3e, 0x5b, 0xcf, 0x36, 0xe5, - 0xc6, 0xf1, 0xd6, 0x59, 0xbb, 0x1c, 0x60, 0x7e, 0x65, 0x3c, 0x67, 0x90, - 0xcd, 0x5c, 0x11, 0x0e, 0x3e, 0x47, 0x39, 0x75, 0x66, 0x41, 0x1f, 0xe1, - 0xfc, 0xa2, 0x3d, 0xd6, 0xf8, 0xb8, 0x06, 0x4c, 0x41, 0x4f, 0xe4, 0x41, - 0xc5, 0xb6, 0xb7, 0x39, 0xf8, 0xfe, 0x82, 0xad, 0xae, 0x9e, 0xfd, 0x0f, - 0xbe, 0x85, 0xdf, 0xb2, 0x38, 0xef, 0x84, 0xf2, 0x9b, 0xe8, 0x3b, 0xcf, - 0x19, 0x60, 0x2c, 0xc3, 0xe7, 0x9c, 0xbc, 0x3b, 0xda, 0xab, 0xd8, 0x5f, - 0x54, 0x3e, 0xc7, 0xbf, 0x71, 0x8c, 0x7b, 0xaa, 0x36, 0xe5, 0x67, 0x19, - 0x7b, 0x2e, 0xfd, 0xce, 0x80, 0xaf, 0x5d, 0xd8, 0x3c, 0xc6, 0xbd, 0x88, - 0x93, 0xd7, 0x29, 0xf8, 0x3b, 0xca, 0xc3, 0xdc, 0x2b, 0x61, 0x5f, 0x6f, - 0xea, 0x38, 0x35, 0xc9, 0x39, 0x35, 0xde, 0x71, 0x7b, 0x7a, 0x51, 0xc7, - 0x97, 0x78, 0x3a, 0x7d, 0x07, 0xc5, 0x9d, 0x4c, 0x5a, 0x1b, 0x8c, 0xc8, - 0xce, 0xde, 0x54, 0xaa, 0x28, 0xbe, 0x4a, 0x45, 0x1a, 0xcf, 0xa7, 0xfa, - 0x07, 0x0f, 0x85, 0x90, 0xc9, 0x76, 0xe3, 0x1b, 0x63, 0xb6, 0x5d, 0xb5, - 0xc6, 0x85, 0x57, 0x46, 0x6c, 0x7c, 0x10, 0x03, 0x5e, 0x1e, 0x09, 0x0f, - 0x9e, 0x01, 0x7e, 0xaf, 0x8e, 0x6a, 0xe4, 0x56, 0xa1, 0xf5, 0x10, 0x36, - 0x08, 0xbd, 0x8b, 0x96, 0x60, 0x1e, 0xda, 0xe9, 0x5d, 0x34, 0xdf, 0x4b, - 0x05, 0xe0, 0x27, 0x05, 0x2f, 0xde, 0x1c, 0xe3, 0x39, 0xbd, 0x38, 0x73, - 0xb4, 0xc1, 0xbf, 0x93, 0xe6, 0x3a, 0x40, 0xf1, 0xbd, 0xfb, 0x58, 0x02, - 0x9b, 0x0f, 0x09, 0x44, 0x23, 0x09, 0x74, 0x1d, 0xab, 0xc5, 0xa6, 0x31, - 0x05, 0xef, 0xc5, 0x6b, 0x71, 0xd3, 0xd1, 0x45, 0x3e, 0x2a, 0x7d, 0x0d, - 0x3e, 0xe7, 0xc8, 0x67, 0xc8, 0x9e, 0xcc, 0x72, 0xcc, 0xa6, 0x7c, 0x91, - 0xe5, 0x18, 0x68, 0xdb, 0xc1, 0xf6, 0x4a, 0x9f, 0xe3, 0x29, 0xca, 0x1f, - 0x8f, 0xb6, 0xeb, 0xc1, 0xa0, 0x64, 0x62, 0xd5, 0x44, 0xf9, 0xb6, 0x3a, - 0xd8, 0xcf, 0xf3, 0x5e, 0xc0, 0xc7, 0xad, 0xb6, 0xbd, 0x39, 0x1e, 0x99, - 0xbf, 0xdb, 0xc1, 0xb5, 0x71, 0xf2, 0xa9, 0x26, 0x3c, 0x9a, 0x5d, 0xdc, - 0x2f, 0xd2, 0xfb, 0x2e, 0xca, 0xd6, 0x90, 0x0a, 0xfb, 0xa3, 0x6a, 0xd3, - 0xfe, 0xd8, 0x6d, 0x46, 0x82, 0xf7, 0x09, 0x3e, 0x67, 0x11, 0xa2, 0x1a, - 0xc4, 0xb6, 0xdf, 0x8a, 0xdb, 0x76, 0x21, 0x6e, 0x79, 0x56, 0xaf, 0x55, - 0x71, 0x6c, 0x25, 0xf7, 0x9c, 0xc3, 0xc9, 0x46, 0xb2, 0x2f, 0xef, 0x4a, - 0x3d, 0xb8, 0x15, 0x9a, 0x65, 0x51, 0x90, 0x0b, 0x2d, 0xd5, 0xfa, 0x80, - 0x26, 0xff, 0xc1, 0x91, 0x06, 0x3c, 0x3e, 0xf7, 0x9b, 0x7c, 0xf4, 0x85, - 0x62, 0x84, 0x8d, 0x8f, 0x0c, 0xac, 0xaf, 0x43, 0x24, 0x79, 0x27, 0xe5, - 0x02, 0xc9, 0xe4, 0xf3, 0xa0, 0x16, 0x6e, 0x8a, 0xf7, 0x63, 0xc7, 0x18, - 0xef, 0x51, 0xc5, 0x3a, 0x3e, 0x1a, 0xb3, 0xff, 0xc6, 0x43, 0xf4, 0xaf, - 0x6f, 0x6f, 0x49, 0x79, 0x9d, 0xdf, 0x05, 0xe9, 0x54, 0x07, 0xd4, 0xa3, - 0x34, 0xa3, 0x97, 0x97, 0x8b, 0xe4, 0x1b, 0x3e, 0x44, 0x82, 0x8d, 0x14, - 0xab, 0xe6, 0xc8, 0x77, 0x67, 0x4a, 0x5c, 0x07, 0xac, 0xe9, 0xb0, 0x27, - 0x96, 0x61, 0x7a, 0x8e, 0xe6, 0xca, 0xea, 0x5d, 0x1f, 0x10, 0xce, 0xab, - 0x31, 0xed, 0x3a, 0xaf, 0x19, 0x39, 0xdd, 0x22, 0x64, 0xcc, 0xaf, 0xb1, - 0xed, 0xee, 0x76, 0x7d, 0xb0, 0x56, 0x60, 0x80, 0xe6, 0x4a, 0xb4, 0xca, - 0xb8, 0x32, 0x88, 0x48, 0xd7, 0x5b, 0x88, 0xf4, 0x9d, 0xa3, 0x18, 0xf6, - 0x44, 0x89, 0xcf, 0xd8, 0x3e, 0x84, 0xbf, 0x19, 0x5b, 0x8a, 0xe7, 0x67, - 0x06, 0x16, 0x7a, 0x62, 0xf0, 0x5e, 0xbd, 0xd6, 0xc4, 0xf1, 0xb1, 0x10, - 0xd9, 0x4f, 0x15, 0xc5, 0x75, 0x05, 0x52, 0x33, 0xf7, 0x48, 0x43, 0x1d, - 0xb1, 0x47, 0x6c, 0x7b, 0x75, 0x73, 0xa5, 0xe6, 0x59, 0x3d, 0x7b, 0xf9, - 0xef, 0x02, 0x16, 0xfb, 0x3d, 0x41, 0xd2, 0x5f, 0x4b, 0x6a, 0x87, 0x78, - 0xd1, 0xb6, 0x7e, 0x57, 0x10, 0xcf, 0x91, 0x5a, 0x78, 0x99, 0x6f, 0x05, - 0xbb, 0x26, 0x08, 0x94, 0x39, 0xe7, 0x56, 0xe0, 0xed, 0x8a, 0xf3, 0x5e, - 0x33, 0xeb, 0xa8, 0xec, 0xdd, 0x18, 0xa7, 0x98, 0x28, 0xfc, 0x84, 0xa7, - 0x2c, 0x4f, 0x27, 0xe5, 0xa7, 0xea, 0x31, 0xfe, 0x8d, 0x82, 0x0f, 0xfb, - 0x29, 0x6e, 0xbc, 0x6f, 0xd4, 0xe0, 0x60, 0xbd, 0x96, 0xe0, 0x7a, 0xfa, - 0xb1, 0x12, 0xf7, 0x25, 0x77, 0xe2, 0x2e, 0xfe, 0x8d, 0x47, 0xe9, 0x5a, - 0xe7, 0x5c, 0x1e, 0xdd, 0x23, 0x6c, 0xc0, 0x74, 0x2c, 0xae, 0xdf, 0x85, - 0xe5, 0x23, 0xac, 0xc7, 0x40, 0x47, 0x90, 0x64, 0xf4, 0x28, 0xd9, 0x85, - 0x64, 0x76, 0x42, 0x19, 0xb1, 0xed, 0xeb, 0xe3, 0x97, 0xcf, 0xa1, 0x0f, - 0x9c, 0x93, 0xa9, 0xbe, 0x93, 0x79, 0x4f, 0x4c, 0x4b, 0x9c, 0x10, 0x97, - 0xcf, 0xf9, 0x87, 0x44, 0x33, 0xcf, 0x5b, 0xc9, 0x4b, 0xc7, 0x29, 0x2f, - 0xbd, 0x3c, 0xca, 0x3e, 0xd2, 0xe6, 0xf8, 0x88, 0x44, 0xb1, 0x76, 0x43, - 0x3a, 0x84, 0x73, 0x06, 0xf4, 0x2a, 0xc4, 0x88, 0xee, 0x48, 0x4f, 0xe7, - 0x02, 0xe6, 0x73, 0x53, 0xfc, 0x9f, 0x19, 0xe5, 0x7d, 0x2a, 0x81, 0x5a, - 0x9d, 0x6d, 0xc0, 0xc9, 0x05, 0x14, 0xd3, 0x06, 0x50, 0x77, 0x2d, 0x70, - 0x71, 0x84, 0xf7, 0xcc, 0x74, 0xec, 0x2f, 0x0d, 0x8a, 0xc6, 0x91, 0x7f, - 0xb0, 0x43, 0xd5, 0x8b, 0xfb, 0x67, 0x0f, 0xf2, 0xfe, 0x19, 0xd9, 0xc0, - 0x80, 0x73, 0x46, 0xe6, 0xad, 0x34, 0x9f, 0x91, 0x09, 0x87, 0x36, 0x93, - 0xef, 0x6c, 0x43, 0x8b, 0x31, 0x4b, 0xd8, 0x79, 0x9e, 0xe8, 0x6c, 0x16, - 0x95, 0x3d, 0xa2, 0xc8, 0xc2, 0x1e, 0xd7, 0xca, 0x7c, 0x97, 0xa8, 0x2d, - 0x30, 0x4d, 0x71, 0xa2, 0xa9, 0x53, 0xd4, 0x1c, 0xdb, 0x28, 0x7c, 0xc7, - 0xba, 0x85, 0x54, 0xe0, 0x98, 0x1c, 0xeb, 0xd8, 0x3d, 0xca, 0xf9, 0x6c, - 0x8b, 0x70, 0x1d, 0xed, 0x15, 0xde, 0x42, 0x9f, 0xf0, 0x1f, 0xb3, 0x70, - 0x6f, 0xbc, 0x1b, 0x67, 0xc6, 0xf8, 0x1c, 0xd8, 0x3d, 0xa2, 0x76, 0x61, - 0x5f, 0xcb, 0x5b, 0x68, 0xf2, 0x17, 0x68, 0x7d, 0xc2, 0x12, 0x1d, 0xe9, - 0x91, 0x65, 0xfe, 0x27, 0x26, 0x03, 0xfe, 0xc7, 0x26, 0xb5, 0x81, 0xbd, - 0xc2, 0xb6, 0x77, 0xc6, 0xa6, 0x59, 0x87, 0x76, 0x4b, 0xac, 0x82, 0x0f, - 0x76, 0x91, 0x3c, 0xb6, 0x53, 0x6e, 0x99, 0x36, 0x5a, 0x16, 0xb0, 0x88, - 0x96, 0xe2, 0xdf, 0x8b, 0xd1, 0xa7, 0x87, 0x73, 0x1b, 0xef, 0x09, 0xba, - 0xda, 0x41, 0x71, 0xf7, 0x33, 0x5e, 0x6b, 0x47, 0xf8, 0x7c, 0xd7, 0x00, - 0xfc, 0x5f, 0xb2, 0x27, 0x76, 0xe6, 0xb3, 0x3d, 0xb1, 0xc4, 0x63, 0x42, - 0x2b, 0xcf, 0x11, 0xbf, 0xd5, 0xf2, 0xe7, 0xf6, 0xc3, 0x16, 0xf6, 0xc2, - 0xba, 0x84, 0xaf, 0xc0, 0xf5, 0x79, 0xbc, 0xe3, 0xf5, 0x91, 0x4e, 0xe1, - 0x3d, 0x36, 0x46, 0xf9, 0x71, 0x23, 0xf1, 0xcc, 0xe7, 0xae, 0xba, 0x85, - 0xbf, 0xb0, 0x45, 0xf8, 0x88, 0xcf, 0x1a, 0xe2, 0x13, 0xc7, 0x3c, 0xc2, - 0x4b, 0x3c, 0x7a, 0x88, 0x47, 0xef, 0x02, 0x8f, 0x9e, 0x42, 0xd0, 0x9f, - 0x4e, 0x37, 0xf8, 0x1f, 0x9e, 0x54, 0xfd, 0x7b, 0x27, 0x6d, 0xfb, 0x3d, - 0xe3, 0x67, 0x0e, 0x5f, 0xaf, 0x1a, 0x5f, 0xe4, 0xeb, 0x3a, 0xe2, 0xab, - 0xb2, 0x8f, 0x49, 0x3a, 0x4c, 0xb1, 0x0e, 0xf9, 0x0c, 0xc4, 0x22, 0x5f, - 0x07, 0xd2, 0xbc, 0x8f, 0xc1, 0x7b, 0x7e, 0x83, 0x62, 0x35, 0xf1, 0x55, - 0x26, 0xbe, 0xae, 0xf9, 0x12, 0xbe, 0x3e, 0xbc, 0x8c, 0xaf, 0x57, 0xff, - 0x51, 0xbe, 0x3c, 0x62, 0xd5, 0x18, 0xc7, 0xa1, 0xfb, 0x3b, 0x94, 0x31, - 0x9b, 0xb0, 0xa3, 0x8c, 0xc7, 0x67, 0x80, 0x62, 0x76, 0x08, 0x0a, 0xc5, - 0x9b, 0x93, 0xf1, 0x48, 0xe8, 0x15, 0xaa, 0x27, 0x67, 0x4b, 0x5e, 0xb1, - 0xd2, 0xd9, 0xcf, 0xc4, 0x6a, 0x85, 0x68, 0x9a, 0x73, 0x7e, 0x9f, 0x05, - 0xa3, 0x4e, 0x67, 0x5d, 0xea, 0xa7, 0xb7, 0x22, 0x52, 0x8e, 0xc8, 0xdd, - 0x22, 0x51, 0xe0, 0xfd, 0xcb, 0x5e, 0x71, 0x8d, 0xb3, 0x77, 0xd9, 0x25, - 0xae, 0x2e, 0x74, 0x8a, 0x56, 0xb2, 0x8b, 0x96, 0x63, 0x7c, 0x96, 0x6a, - 0x8b, 0x68, 0x59, 0x90, 0xc7, 0x2a, 0x92, 0xc7, 0xc8, 0xe7, 0xe4, 0xb1, - 0xc4, 0xcf, 0xf2, 0xf8, 0x91, 0x71, 0xe1, 0xb2, 0x1e, 0x1a, 0xd7, 0x55, - 0x94, 0x0d, 0xa9, 0x76, 0xaa, 0x5b, 0xa8, 0x9d, 0xde, 0x8e, 0xf1, 0x19, - 0x19, 0xcb, 0xae, 0xd5, 0x11, 0x72, 0x99, 0x5a, 0xdf, 0x49, 0xa1, 0xa7, - 0xee, 0x11, 0xc9, 0xcd, 0x3e, 0xaa, 0x7f, 0x76, 0xc4, 0x22, 0xc9, 0x55, - 0x22, 0x92, 0x70, 0x09, 0xce, 0x2b, 0x86, 0x52, 0x5d, 0xb4, 0xb0, 0x97, - 0xe2, 0xdb, 0x4b, 0xa3, 0x12, 0x61, 0x07, 0xfe, 0xcd, 0x96, 0x0b, 0xd7, - 0xab, 0x3e, 0x1c, 0x21, 0xdc, 0xf1, 0x68, 0xb6, 0x1f, 0x47, 0xf2, 0xdb, - 0xf0, 0x68, 0xfe, 0xd7, 0x7e, 0x9f, 0xa2, 0x78, 0xcd, 0x9e, 0x6b, 0x2b, - 0xfb, 0xf8, 0xd1, 0xc4, 0x55, 0x11, 0x96, 0xcd, 0x4f, 0x5b, 0x94, 0x08, - 0xd7, 0xba, 0x89, 0xeb, 0x7e, 0xae, 0xb3, 0x2f, 0xa6, 0xdb, 0x4f, 0x39, - 0x58, 0xe4, 0xed, 0xb6, 0x63, 0xce, 0xf9, 0xa2, 0x5f, 0xae, 0xde, 0xed, - 0xfc, 0x7e, 0x32, 0xb9, 0xf6, 0x76, 0x9d, 0xfd, 0xe1, 0xa7, 0x6b, 0x36, - 0x38, 0xf9, 0xd5, 0x5c, 0x57, 0xf9, 0x6d, 0x49, 0x62, 0x5d, 0xa5, 0x57, - 0x13, 0x5f, 0x17, 0x75, 0xae, 0xc9, 0x75, 0x95, 0x7d, 0xe2, 0x9e, 0x75, - 0xcd, 0xce, 0xb5, 0x6b, 0x5d, 0xc5, 0xa7, 0x3a, 0xd7, 0xe9, 0xce, 0xb5, - 0x77, 0x5d, 0x25, 0x2f, 0x77, 0xaf, 0x5b, 0x71, 0xe9, 0x37, 0x29, 0xfc, - 0xf7, 0x7f, 0x00, 0x2f, 0xc1, 0x67, 0x8a, 0x54, 0x3a, 0x00, 0x00, 0x00 }; + 0xc5, 0x7b, 0x7b, 0x74, 0x1c, 0x55, 0x9a, 0xdf, 0xef, 0x56, 0x3f, 0x54, + 0xdd, 0x6a, 0xb5, 0x4a, 0x72, 0xdb, 0x6e, 0xed, 0x68, 0xc6, 0x5d, 0xee, + 0x6a, 0xb9, 0xb1, 0x84, 0x5d, 0x2d, 0xb5, 0xec, 0x66, 0x5d, 0xb1, 0x7b, + 0x8c, 0xb0, 0x65, 0x10, 0x3b, 0xc2, 0xeb, 0x9d, 0x88, 0x09, 0x27, 0xf4, + 0x18, 0x19, 0x64, 0x63, 0x40, 0x30, 0x64, 0xa3, 0xd9, 0x25, 0xeb, 0x1a, + 0xf9, 0x81, 0x1f, 0xad, 0xee, 0xd6, 0xc3, 0xc8, 0xec, 0xd9, 0x13, 0x64, + 0x49, 0xb6, 0xcc, 0xd0, 0x0f, 0x33, 0xc0, 0xcc, 0x30, 0x27, 0x13, 0x77, + 0x8c, 0x01, 0x03, 0x63, 0x98, 0xdd, 0x6c, 0x92, 0x99, 0x3d, 0x49, 0xd6, + 0x07, 0xf3, 0xb0, 0xc1, 0x60, 0x32, 0x43, 0x12, 0xb1, 0xcb, 0x4c, 0xe5, + 0xfb, 0xaa, 0x25, 0x63, 0x58, 0xb2, 0x9b, 0x6c, 0xfe, 0x88, 0xce, 0xd1, + 0xe9, 0xee, 0xaa, 0x5b, 0xf7, 0x7e, 0xef, 0xef, 0xf7, 0x7d, 0xf7, 0x56, + 0x04, 0xf0, 0x62, 0xee, 0xaf, 0x86, 0xfe, 0xe3, 0xfd, 0x03, 0x0f, 0xb7, + 0xae, 0x88, 0xaf, 0xa0, 0xaf, 0x6d, 0x58, 0xec, 0x74, 0xf2, 0xcd, 0x55, + 0x02, 0x48, 0xbd, 0x87, 0x7f, 0xd4, 0xdf, 0x57, 0xff, 0x71, 0x8f, 0xc1, + 0x01, 0x28, 0xf3, 0x34, 0xf1, 0x3f, 0x64, 0xc9, 0x30, 0xd7, 0xac, 0xd7, + 0x20, 0x3b, 0x8c, 0xc4, 0xda, 0xbb, 0x34, 0x20, 0x99, 0x6f, 0x0e, 0xdd, + 0x88, 0xdf, 0x58, 0x66, 0xc0, 0x09, 0xbe, 0xfe, 0x55, 0xe3, 0xd3, 0x5d, + 0x3f, 0x5d, 0xad, 0x7e, 0x34, 0xe1, 0x80, 0xac, 0x18, 0x63, 0x50, 0x9a, + 0x20, 0x37, 0xd2, 0x33, 0x7f, 0xb6, 0xec, 0x79, 0x27, 0xfc, 0xf3, 0x73, + 0xc1, 0x74, 0x19, 0x3a, 0x76, 0x67, 0xfb, 0x31, 0x13, 0x07, 0x2e, 0xa6, + 0x23, 0xfa, 0x6e, 0x20, 0x27, 0x19, 0x91, 0xd0, 0x69, 0x84, 0x30, 0x9d, + 0x87, 0x59, 0x65, 0x68, 0xd8, 0x5f, 0x0a, 0xe1, 0x52, 0xfa, 0xb7, 0x56, + 0xc8, 0xd5, 0x8f, 0xb7, 0xe2, 0x90, 0x83, 0xc6, 0x23, 0x08, 0x66, 0x21, + 0xd7, 0x18, 0x03, 0x28, 0x0c, 0x01, 0x7b, 0xd3, 0x6a, 0x3f, 0xa0, 0xf6, + 0x14, 0x45, 0xf8, 0xec, 0x09, 0xa8, 0xdd, 0x0d, 0x8e, 0xe6, 0xd4, 0xed, + 0x42, 0x4d, 0xee, 0x14, 0x90, 0x05, 0x8d, 0x5d, 0x9e, 0xe7, 0xcf, 0x01, + 0x44, 0xf3, 0x32, 0xce, 0x3b, 0x78, 0x59, 0x83, 0xe4, 0x2c, 0xe0, 0xd4, + 0x74, 0xec, 0xcd, 0xc2, 0x74, 0x1a, 0x02, 0xbb, 0xe3, 0x11, 0x65, 0x0a, + 0x7c, 0x3f, 0x84, 0x41, 0x7b, 0x9c, 0x4a, 0x1c, 0x5b, 0xd6, 0x1e, 0xdd, + 0xb2, 0x8e, 0xe9, 0x55, 0x30, 0x15, 0x35, 0x08, 0x08, 0x0c, 0xea, 0x12, + 0x92, 0xca, 0xfa, 0x90, 0x13, 0x6a, 0x70, 0x1b, 0xfe, 0x96, 0xf8, 0x4d, + 0x46, 0x5d, 0xa8, 0x8c, 0x4f, 0xa1, 0x0a, 0x65, 0xa5, 0x22, 0xb1, 0xc9, + 0xb4, 0x65, 0xbd, 0xa4, 0x39, 0x71, 0x8c, 0x64, 0x33, 0x98, 0xff, 0x5b, + 0xab, 0x4c, 0x72, 0xd9, 0xa3, 0xcd, 0xaf, 0x2f, 0x63, 0x42, 0xb1, 0xac, + 0x29, 0xba, 0xb7, 0x2f, 0x3f, 0x2f, 0x63, 0xcb, 0x92, 0x34, 0xcb, 0xba, + 0x4b, 0xfb, 0x1b, 0x6b, 0xeb, 0xe7, 0xc6, 0xc6, 0xf0, 0xfd, 0x9c, 0x82, + 0xa7, 0xb2, 0x49, 0xe4, 0xd3, 0x16, 0x1c, 0x86, 0x13, 0x7d, 0x43, 0x21, + 0xec, 0x2c, 0x74, 0xa0, 0x90, 0x56, 0x53, 0xe7, 0xe9, 0xb9, 0xad, 0x71, + 0x0d, 0xf7, 0x15, 0x3a, 0x31, 0x93, 0x86, 0xe5, 0x31, 0xb4, 0xb2, 0x47, + 0x44, 0x71, 0x4f, 0xa1, 0x0b, 0xc5, 0xb4, 0x76, 0x76, 0x50, 0x44, 0x06, + 0x1a, 0x1c, 0x4e, 0x3c, 0x50, 0x68, 0xc1, 0xfd, 0x85, 0x04, 0x3d, 0x63, + 0xe1, 0xe6, 0x58, 0x23, 0x8d, 0x6f, 0xc5, 0x93, 0x63, 0x96, 0x15, 0x8d, + 0x29, 0xe8, 0x2b, 0xe8, 0x98, 0xc9, 0x49, 0x48, 0x1d, 0x73, 0x22, 0x75, + 0x14, 0xb8, 0xe7, 0x68, 0x2b, 0xa6, 0x72, 0x16, 0xb6, 0xea, 0x83, 0x0d, + 0x12, 0x5c, 0x48, 0x29, 0x02, 0x2e, 0xcd, 0x8f, 0x6d, 0x4a, 0x85, 0xf6, + 0xf3, 0x0e, 0x81, 0x1d, 0x47, 0xa3, 0xf8, 0x45, 0xda, 0xc4, 0xcd, 0xed, + 0x41, 0x0c, 0x14, 0x02, 0x78, 0x23, 0x1d, 0xa0, 0x35, 0x74, 0xbc, 0x9e, + 0x96, 0x69, 0x9d, 0x16, 0x9c, 0x49, 0xf3, 0x18, 0x1e, 0xeb, 0x43, 0x6f, + 0xa1, 0x11, 0xe7, 0xd2, 0x41, 0x5a, 0x33, 0x80, 0x57, 0x68, 0xdc, 0xf6, + 0x82, 0x86, 0xb3, 0x34, 0xae, 0xaf, 0x10, 0xc2, 0xcb, 0x69, 0x1f, 0xd1, + 0x1a, 0xc0, 0xe9, 0x74, 0x3f, 0x76, 0xa7, 0x9b, 0xcf, 0xde, 0x48, 0x32, + 0x0c, 0x2d, 0xe0, 0x75, 0xf8, 0xda, 0x5b, 0x56, 0x57, 0xc0, 0x36, 0x13, + 0x5a, 0x67, 0x7e, 0xdd, 0x7e, 0x0c, 0xa6, 0xcf, 0xcc, 0xf9, 0x89, 0x8e, + 0x03, 0xb9, 0x59, 0xeb, 0xa7, 0xcb, 0x1a, 0x71, 0x22, 0x0b, 0x3c, 0x39, + 0x05, 0x4c, 0x65, 0x4d, 0xab, 0xc6, 0xb0, 0xac, 0xc9, 0xf6, 0x16, 0x92, + 0x97, 0xd6, 0xb3, 0x95, 0x46, 0x3d, 0x55, 0x72, 0x02, 0x47, 0xd5, 0x9e, + 0x32, 0x24, 0x4c, 0xcc, 0x38, 0xe1, 0x1e, 0x52, 0x3b, 0x27, 0xa0, 0x9e, + 0xbd, 0x87, 0x3c, 0xe9, 0x58, 0x56, 0xed, 0x36, 0xb1, 0xcb, 0x0a, 0x1a, + 0x4d, 0xa1, 0x16, 0x87, 0x05, 0x3f, 0xd9, 0x42, 0xba, 0xc5, 0xb2, 0x6a, + 0x57, 0x5b, 0xd6, 0xb9, 0x76, 0x58, 0x92, 0xa1, 0x9d, 0x2d, 0x41, 0x2b, + 0x7f, 0x00, 0x6d, 0xe0, 0x34, 0xca, 0x5f, 0xf5, 0x21, 0xd2, 0x17, 0x76, + 0x44, 0xfa, 0x67, 0xe9, 0xd9, 0x9a, 0x02, 0x99, 0x32, 0xf1, 0xa2, 0x91, + 0x0d, 0x16, 0x4a, 0x32, 0x9c, 0xc4, 0x4f, 0xcb, 0x90, 0x65, 0x39, 0x35, + 0x1f, 0x7c, 0x24, 0xdf, 0x8d, 0x87, 0x2d, 0xeb, 0x1d, 0x5d, 0x81, 0x9b, + 0x74, 0x73, 0xd3, 0xb0, 0x85, 0x49, 0xfd, 0x34, 0xc9, 0x53, 0x20, 0xd5, + 0x1d, 0xa7, 0x67, 0x02, 0x34, 0x3e, 0x81, 0x8d, 0x43, 0x41, 0x7c, 0x3f, + 0x2b, 0xe3, 0xa7, 0xcb, 0xa2, 0xa8, 0xa6, 0xb9, 0xbc, 0x24, 0xab, 0x2a, + 0x92, 0x1f, 0x0a, 0x64, 0x6e, 0x85, 0x8a, 0x3d, 0xa2, 0x70, 0x9e, 0x78, + 0x0c, 0xe2, 0x07, 0xa5, 0x00, 0x9e, 0x2e, 0x29, 0x38, 0x59, 0x6a, 0xc4, + 0xa9, 0x92, 0x8e, 0x6c, 0x4e, 0xdd, 0x5f, 0x86, 0x85, 0x1a, 0x32, 0xe7, + 0x37, 0x26, 0x62, 0xc8, 0xe4, 0x2c, 0x2b, 0x4f, 0x34, 0x7b, 0x89, 0x87, + 0xd7, 0x27, 0xbe, 0x86, 0xe3, 0x63, 0x4e, 0x84, 0x26, 0x03, 0x78, 0x2a, + 0xed, 0xc4, 0x75, 0x19, 0xd5, 0x9c, 0x80, 0x16, 0xdd, 0x29, 0xb4, 0xe4, + 0x72, 0xa1, 0xe6, 0x4c, 0x44, 0x42, 0x2e, 0x21, 0xa1, 0xe9, 0xb8, 0x13, + 0x5a, 0x31, 0x04, 0x57, 0x93, 0x0c, 0xad, 0x89, 0xdc, 0xc8, 0x2f, 0xc1, + 0x4d, 0x7e, 0xb1, 0x71, 0x24, 0x4a, 0xd7, 0x02, 0x74, 0x0d, 0x5f, 0xab, + 0x82, 0x63, 0x91, 0x03, 0x24, 0x37, 0xcd, 0x81, 0xa4, 0xd3, 0xb2, 0x1c, + 0x5a, 0x2b, 0x7a, 0x1e, 0xa3, 0xcf, 0x36, 0x1e, 0xaf, 0x20, 0x5c, 0x24, + 0x19, 0x34, 0x11, 0x4d, 0x59, 0xa2, 0x31, 0x4b, 0x34, 0x66, 0x89, 0xc6, + 0xac, 0x83, 0x6c, 0x46, 0xd5, 0x81, 0x3f, 0x22, 0x5d, 0x85, 0x88, 0xbf, + 0x5f, 0xd8, 0x7a, 0x7a, 0xba, 0x14, 0x24, 0xfa, 0x43, 0x36, 0xfd, 0x4f, + 0xe6, 0x04, 0x24, 0x4d, 0xed, 0x3e, 0x8f, 0x75, 0x08, 0xc7, 0xd4, 0xe4, + 0x04, 0x92, 0xf4, 0x9c, 0xba, 0xdf, 0x84, 0xda, 0x59, 0x26, 0xfd, 0x6f, + 0x55, 0x12, 0x98, 0xc9, 0xba, 0x50, 0xad, 0xa9, 0x21, 0xd2, 0x57, 0xb4, + 0x8c, 0x05, 0xb8, 0x57, 0xa1, 0x39, 0x25, 0xb7, 0xa8, 0xc4, 0x90, 0x47, + 0x10, 0x19, 0x91, 0x30, 0xad, 0x3b, 0xc8, 0x3f, 0x75, 0x38, 0x9a, 0x68, + 0xb9, 0x62, 0x9c, 0x3e, 0x69, 0xfe, 0x2c, 0xad, 0x45, 0xf4, 0xd0, 0x7c, + 0xe4, 0x97, 0x2c, 0xc7, 0x28, 0xd1, 0xb0, 0xd7, 0xa6, 0xf7, 0x64, 0xa9, + 0x4b, 0x54, 0xec, 0xc7, 0x20, 0x7b, 0x51, 0x43, 0x10, 0x6a, 0x34, 0x24, + 0x54, 0x3d, 0x29, 0x14, 0x4c, 0x95, 0x7e, 0x46, 0x63, 0x02, 0xd7, 0x8c, + 0xe9, 0xc6, 0x60, 0x56, 0xe0, 0x46, 0xcd, 0xc2, 0x7a, 0xbd, 0x1b, 0xbb, + 0x4b, 0xf3, 0x7e, 0xc9, 0xb1, 0x4b, 0xf1, 0x4f, 0xa5, 0x3b, 0xb0, 0x27, + 0x1b, 0xc2, 0xee, 0x7c, 0xd0, 0x3f, 0x99, 0xe6, 0x7b, 0x1a, 0xf9, 0x3b, + 0xdf, 0x0b, 0x5c, 0x73, 0xaf, 0xf1, 0x9a, 0x7b, 0x09, 0x0c, 0x8e, 0x7e, + 0x85, 0x62, 0x48, 0x2d, 0x76, 0x6b, 0x1f, 0x91, 0xad, 0x68, 0x89, 0x5e, + 0x34, 0xe0, 0xbc, 0xd2, 0x82, 0x43, 0xe3, 0x5d, 0xd8, 0x33, 0xbe, 0x02, + 0x07, 0x46, 0x1b, 0x53, 0x5e, 0x63, 0x88, 0xd6, 0x0f, 0x27, 0x7b, 0x85, + 0xda, 0xef, 0x10, 0xe1, 0x68, 0x2f, 0xd9, 0x6e, 0x53, 0x9d, 0x65, 0x9d, + 0x8e, 0x91, 0x6d, 0xeb, 0xcd, 0xfa, 0x46, 0x12, 0x40, 0xb9, 0x5b, 0xed, + 0x7c, 0x0b, 0x3e, 0xdc, 0x4a, 0x36, 0x37, 0x15, 0x43, 0xaf, 0x03, 0x8e, + 0x16, 0x1f, 0x7e, 0x6d, 0x1d, 0x75, 0xb2, 0xdc, 0xad, 0x5d, 0x77, 0xe9, + 0x7b, 0x05, 0xc7, 0x39, 0xf7, 0xd5, 0x58, 0xc2, 0xf3, 0xf3, 0x33, 0x96, + 0x15, 0xa6, 0x79, 0xfa, 0x62, 0xcd, 0x89, 0x3e, 0xcc, 0x5a, 0xe7, 0xb7, + 0x74, 0x61, 0xf7, 0xcc, 0x0a, 0x1c, 0x1c, 0x75, 0x21, 0x59, 0x27, 0x50, + 0xab, 0x85, 0xcb, 0xf7, 0x62, 0x05, 0xcc, 0x29, 0x7e, 0xae, 0x0b, 0x47, + 0x66, 0x2a, 0xbf, 0xb3, 0x57, 0x7f, 0xcf, 0xcf, 0x77, 0x91, 0x74, 0xca, + 0xf2, 0xe4, 0x38, 0x49, 0x2a, 0x30, 0x9a, 0x71, 0x62, 0x34, 0x40, 0xba, + 0xed, 0x10, 0xce, 0xe3, 0x8b, 0xfc, 0xde, 0xc7, 0x2c, 0xbc, 0xa4, 0x93, + 0x9e, 0xb3, 0x1b, 0x84, 0xf7, 0x78, 0xa7, 0x70, 0x15, 0x37, 0x0b, 0xf7, + 0xe4, 0xb7, 0x84, 0x7c, 0x3c, 0x25, 0xaa, 0x8a, 0x2d, 0x24, 0xfb, 0x1e, + 0xe1, 0x39, 0xae, 0x86, 0x42, 0xe2, 0xbb, 0xa4, 0xcf, 0x2d, 0xc2, 0x51, + 0x84, 0x22, 0x19, 0x03, 0x42, 0x2a, 0xd2, 0x1c, 0xb6, 0x0d, 0xf1, 0x3a, + 0x41, 0xd2, 0x1b, 0x4c, 0x87, 0xd1, 0x8f, 0xad, 0x94, 0x23, 0x6e, 0x49, + 0x1b, 0x38, 0x98, 0xad, 0xa2, 0xf8, 0xc8, 0x7e, 0x3f, 0x4b, 0xeb, 0x6a, + 0x38, 0x54, 0x82, 0xe9, 0x31, 0x0e, 0x62, 0x05, 0xf9, 0xdb, 0xb9, 0x18, + 0xfb, 0x22, 0x90, 0xcf, 0x86, 0x93, 0x07, 0x85, 0x65, 0x55, 0x45, 0xac, + 0x25, 0xef, 0xe8, 0xcd, 0xd1, 0x33, 0xf8, 0x9f, 0xd6, 0x44, 0xa0, 0x1f, + 0xd1, 0x76, 0xc8, 0x55, 0xc6, 0x1e, 0xbc, 0x9b, 0x86, 0xec, 0x36, 0x4c, + 0xbc, 0x94, 0x06, 0x7c, 0x43, 0x83, 0x8a, 0x17, 0x64, 0x07, 0x08, 0x07, + 0x0f, 0x09, 0xb5, 0xfb, 0x02, 0xa5, 0xb3, 0x44, 0xbb, 0x39, 0x20, 0x81, + 0xe2, 0x91, 0x50, 0x7b, 0xce, 0x90, 0x3d, 0x7e, 0x57, 0xa8, 0xca, 0xac, + 0x60, 0x3f, 0xe5, 0x5c, 0xb2, 0x67, 0x2e, 0xa7, 0x98, 0xb8, 0xee, 0x9a, + 0x9c, 0x32, 0x48, 0x74, 0xed, 0x23, 0xba, 0x5e, 0xd4, 0xd5, 0xe0, 0x24, + 0xac, 0x25, 0xbd, 0x3a, 0xdf, 0x33, 0xb0, 0xa7, 0x64, 0x85, 0x1c, 0x06, + 0xcb, 0x0a, 0xa9, 0x2a, 0x03, 0xa6, 0x6c, 0x28, 0xe4, 0x1b, 0xbf, 0xb1, + 0x7a, 0xe3, 0xb2, 0xfe, 0x76, 0x5e, 0x21, 0x79, 0xc1, 0xef, 0x2c, 0x7c, + 0x59, 0xde, 0xb5, 0x20, 0x19, 0xbf, 0xb1, 0xee, 0x8c, 0xc3, 0xbf, 0xa4, + 0xe0, 0x4c, 0x55, 0x1b, 0xe8, 0x1e, 0x18, 0xda, 0x65, 0x35, 0x68, 0x12, + 0xc5, 0x29, 0x8d, 0xe2, 0xba, 0x2f, 0x71, 0xb9, 0xdd, 0x23, 0xce, 0xb5, + 0x07, 0xbb, 0x3e, 0xc8, 0x7b, 0x48, 0xcf, 0xe8, 0xde, 0x59, 0x48, 0x38, + 0xdf, 0x23, 0x5b, 0x73, 0x53, 0x4c, 0x45, 0xa1, 0xb1, 0xeb, 0x12, 0xe5, + 0xa1, 0x9b, 0x62, 0x9e, 0x7f, 0xea, 0x36, 0xa4, 0xaf, 0x79, 0xf0, 0xe0, + 0xca, 0xe9, 0x44, 0x2d, 0xc5, 0x75, 0x05, 0x67, 0xe3, 0x9d, 0x18, 0x2c, + 0x55, 0x91, 0x1d, 0x3e, 0x53, 0xde, 0xab, 0x35, 0x76, 0xbd, 0x9f, 0x5e, + 0xc2, 0x71, 0xe4, 0xd3, 0x7c, 0xbb, 0xd6, 0xbd, 0x53, 0x9c, 0xde, 0xe4, + 0x45, 0x1c, 0x07, 0x4a, 0xb2, 0xfc, 0x49, 0x1a, 0x1f, 0x2d, 0xd1, 0xb4, + 0xf2, 0x3a, 0x47, 0x53, 0xbf, 0xec, 0x68, 0x1a, 0x70, 0x53, 0x0c, 0xbe, + 0x78, 0xbd, 0xc0, 0x4b, 0xd7, 0x47, 0x12, 0x6e, 0xe1, 0xc1, 0xf9, 0xee, + 0x04, 0xd9, 0x49, 0x63, 0xca, 0x63, 0x50, 0xfc, 0x20, 0x93, 0x75, 0x68, + 0x09, 0xec, 0x9e, 0xc2, 0x23, 0x83, 0x7a, 0x17, 0xcc, 0x19, 0xb6, 0xa1, + 0x16, 0x0c, 0xce, 0x74, 0xc3, 0x2c, 0x39, 0x30, 0x11, 0x20, 0xe6, 0x4b, + 0x48, 0xb9, 0x8c, 0x96, 0x8e, 0x89, 0x7c, 0xaf, 0xab, 0xe2, 0xc3, 0xc4, + 0x7f, 0xf6, 0xa8, 0x1f, 0x5e, 0xd6, 0xf3, 0x59, 0x92, 0x51, 0x0b, 0x9e, + 0x29, 0x45, 0x29, 0xd6, 0xe9, 0x24, 0x17, 0x8d, 0xe2, 0x45, 0x88, 0xec, + 0x4b, 0xc6, 0xd6, 0x51, 0xf5, 0x08, 0xc5, 0x85, 0xdc, 0x04, 0xda, 0x91, + 0x0c, 0x28, 0x94, 0xbb, 0x5f, 0x9a, 0x8b, 0x01, 0xdb, 0xe8, 0x53, 0x35, + 0x93, 0xc0, 0x19, 0x09, 0x68, 0x6d, 0x30, 0x22, 0xfb, 0x1b, 0x48, 0x1f, + 0x75, 0x45, 0x0f, 0x1e, 0x18, 0xad, 0xc7, 0xfd, 0xe3, 0x5e, 0xec, 0x18, + 0xb5, 0x70, 0x39, 0xc6, 0xb6, 0xa1, 0xf6, 0x10, 0x89, 0x1d, 0xd5, 0x24, + 0xd7, 0x4d, 0xb1, 0x48, 0xc2, 0x23, 0x9c, 0xa8, 0x2a, 0x76, 0x13, 0x06, + 0x48, 0xb2, 0x5f, 0xe8, 0x34, 0x47, 0x68, 0xb7, 0x7e, 0x2b, 0x52, 0x01, + 0x19, 0xae, 0xa2, 0x8f, 0x62, 0x09, 0xfb, 0x31, 0xdf, 0xfb, 0x06, 0xb6, + 0xba, 0x7d, 0x70, 0x64, 0x64, 0xe4, 0x28, 0xff, 0x63, 0x91, 0x1b, 0x9d, + 0x4d, 0x12, 0xfd, 0x07, 0xfc, 0xd3, 0x63, 0x8d, 0xfe, 0x63, 0x14, 0x5f, + 0xef, 0xc9, 0x4a, 0xbc, 0x0e, 0xe3, 0x05, 0x9a, 0x5b, 0xc1, 0x93, 0x14, + 0xab, 0x1f, 0xa2, 0xf8, 0x73, 0xa2, 0x94, 0x17, 0x1c, 0x4f, 0x6c, 0x7e, + 0xb2, 0xc4, 0x5b, 0x96, 0x78, 0xcb, 0x12, 0x5f, 0x14, 0x17, 0x4e, 0x66, + 0x99, 0x8f, 0x2b, 0xe4, 0xa3, 0x09, 0xe2, 0xdd, 0x83, 0x6d, 0x44, 0xef, + 0x83, 0xe3, 0xd5, 0xb8, 0x8f, 0xe8, 0x2d, 0xea, 0x6a, 0xcf, 0x9f, 0x0b, + 0x0b, 0xf9, 0x98, 0x6a, 0xee, 0x14, 0x5e, 0x48, 0x4d, 0x96, 0xd5, 0xad, + 0x33, 0xcf, 0x64, 0xa7, 0x92, 0xcd, 0xf3, 0xfe, 0x24, 0x3c, 0xe8, 0xa3, + 0x67, 0x7a, 0xc7, 0xf1, 0xa9, 0x44, 0x3c, 0x79, 0x88, 0xc7, 0x83, 0xba, + 0x9a, 0x58, 0x4e, 0x71, 0xfd, 0x82, 0x16, 0x29, 0x5f, 0x70, 0xe0, 0xeb, + 0x24, 0x0f, 0x9d, 0xe5, 0xd1, 0x44, 0xfc, 0x3c, 0x40, 0x58, 0xc7, 0x6f, + 0x30, 0x9f, 0x91, 0xe8, 0xaf, 0x89, 0xf7, 0x48, 0x31, 0xe0, 0x3f, 0x77, + 0xb8, 0xd1, 0xff, 0xe2, 0x50, 0x85, 0xfe, 0x9d, 0x44, 0xff, 0x74, 0xcc, + 0xc2, 0x21, 0xa2, 0xff, 0x29, 0xa2, 0xbf, 0x8f, 0xe3, 0xf9, 0x1c, 0xfd, + 0x27, 0x4a, 0xbc, 0xee, 0x97, 0xf1, 0x30, 0x4f, 0x7f, 0x3d, 0xb6, 0x8e, + 0xcf, 0xcb, 0xcb, 0xb2, 0xee, 0xd4, 0x9f, 0xb5, 0xbe, 0x4d, 0x32, 0x5b, + 0x52, 0x64, 0xb9, 0x31, 0x8e, 0x8b, 0x1c, 0xb9, 0x07, 0x7d, 0x12, 0xbc, + 0x3e, 0x2c, 0x28, 0x72, 0x2e, 0x08, 0xe1, 0x59, 0xd2, 0xef, 0x29, 0xca, + 0x65, 0xcf, 0x94, 0xae, 0xcd, 0x6d, 0xac, 0xeb, 0x31, 0xd2, 0xb1, 0x3a, + 0x61, 0x52, 0x6c, 0x4b, 0x95, 0x92, 0xd8, 0x3b, 0x8e, 0xe4, 0xb4, 0xfe, + 0xaf, 0x29, 0xc0, 0x2c, 0x22, 0xfb, 0xaa, 0x4a, 0x2a, 0x9a, 0x17, 0x77, + 0x4d, 0x05, 0xd0, 0x5f, 0x5a, 0x8f, 0x2c, 0xc5, 0x9b, 0x9d, 0x14, 0x9f, + 0x3f, 0x8c, 0x25, 0x77, 0xf8, 0x11, 0x21, 0xfd, 0x06, 0x70, 0x2f, 0x3d, + 0x73, 0x70, 0x9c, 0xe9, 0x57, 0xe6, 0xf4, 0x1c, 0xc0, 0x3d, 0x74, 0x6d, + 0xdf, 0xb8, 0x8c, 0x17, 0xf4, 0x27, 0x08, 0xcf, 0x54, 0xf0, 0xc5, 0xdd, + 0x59, 0x28, 0xe4, 0x9e, 0x84, 0xff, 0x22, 0xd1, 0x17, 0xe8, 0xf7, 0xb6, + 0x92, 0xd7, 0x3f, 0x38, 0x86, 0xef, 0x2d, 0x31, 0xfc, 0x58, 0x40, 0x58, + 0xec, 0x76, 0x3d, 0x42, 0x76, 0xef, 0xc4, 0x40, 0x49, 0xc2, 0x77, 0xa6, + 0xbc, 0x78, 0x68, 0xf4, 0x53, 0xcb, 0x1d, 0x77, 0xe2, 0xb6, 0x26, 0x2f, + 0x1e, 0x9c, 0x4a, 0x62, 0xff, 0x38, 0x42, 0x55, 0xb1, 0x61, 0x8a, 0xdd, + 0x95, 0x7c, 0x50, 0x4d, 0xbc, 0x1f, 0x18, 0xf7, 0xf9, 0xfb, 0x0e, 0xb3, + 0x0c, 0xd6, 0x07, 0x3d, 0x40, 0xb9, 0x2a, 0xe6, 0xc0, 0x36, 0xdd, 0xb1, + 0xa0, 0x8a, 0x0c, 0xfd, 0x09, 0x9a, 0x6f, 0x12, 0x8e, 0x57, 0x97, 0x20, + 0x72, 0xa4, 0xc1, 0x51, 0xce, 0x2d, 0x40, 0x3d, 0x1e, 0x9a, 0x49, 0x62, + 0x98, 0x6c, 0xf4, 0x81, 0xd1, 0xc1, 0xef, 0xd5, 0x51, 0x0c, 0xf1, 0xb7, + 0xaa, 0x7d, 0x6f, 0x08, 0x03, 0xf9, 0x88, 0x07, 0x3b, 0xa7, 0x7c, 0xfe, + 0x1d, 0x87, 0xad, 0x75, 0x6c, 0x4f, 0xdb, 0x67, 0xea, 0x71, 0xdf, 0x38, + 0x5d, 0x1b, 0x65, 0x1b, 0x26, 0x5b, 0x8b, 0x54, 0x11, 0x6f, 0xe1, 0xa4, + 0x87, 0xf0, 0x92, 0x23, 0x56, 0x4d, 0xf2, 0xf0, 0xe0, 0x1e, 0xdb, 0x16, + 0x14, 0x6c, 0x1b, 0xb7, 0xf0, 0xa6, 0x1e, 0x45, 0x8e, 0xec, 0xfa, 0xc8, + 0xb8, 0x3a, 0xdb, 0x41, 0x58, 0xe7, 0x6d, 0x87, 0x7a, 0xa4, 0xc9, 0x91, + 0x44, 0x7d, 0x1b, 0xc5, 0xf8, 0x7a, 0xcb, 0xba, 0xbb, 0xb5, 0xb9, 0xff, + 0xe7, 0x44, 0x73, 0x9d, 0xb1, 0x08, 0xe5, 0x3a, 0x35, 0x07, 0x34, 0x0f, + 0xb8, 0xa5, 0xeb, 0x71, 0x7e, 0x21, 0xc7, 0x41, 0x8e, 0xe5, 0x01, 0x7f, + 0x7d, 0xa6, 0x92, 0xe3, 0xea, 0x8b, 0x8d, 0xfe, 0xba, 0x4c, 0xd0, 0x5f, + 0x57, 0x84, 0xdf, 0x5d, 0x04, 0x7e, 0x4c, 0xf1, 0x65, 0x41, 0xdb, 0x6f, + 0xac, 0x54, 0xbd, 0x8d, 0x07, 0xfd, 0xcf, 0x8f, 0xa9, 0x66, 0x19, 0xea, + 0x7e, 0x0a, 0x9b, 0x78, 0x7c, 0xc6, 0xe9, 0x3f, 0x4e, 0xd8, 0xaf, 0x5e, + 0x8b, 0x62, 0x1f, 0xe9, 0x73, 0x17, 0xd9, 0xc2, 0xaf, 0xdb, 0x80, 0x03, + 0x99, 0x70, 0x48, 0x17, 0x3d, 0x34, 0x31, 0xb0, 0xa7, 0x48, 0x31, 0x5f, + 0x4a, 0x52, 0x10, 0x53, 0xa3, 0x94, 0xd6, 0x90, 0xce, 0xb8, 0x60, 0x2e, + 0xac, 0xe8, 0xe4, 0xbe, 0xec, 0x29, 0xcb, 0xaf, 0x69, 0x13, 0x45, 0xd2, + 0xd9, 0xc3, 0x25, 0x1f, 0x06, 0x08, 0x0f, 0x2c, 0x20, 0x0c, 0xf9, 0x20, + 0xd9, 0xc5, 0x03, 0xa3, 0x0e, 0xa2, 0x8f, 0xc7, 0x25, 0x91, 0x5c, 0x54, + 0xc1, 0xa2, 0x0f, 0x4d, 0xb1, 0x5d, 0x92, 0x1d, 0x91, 0x2d, 0x3e, 0x4b, + 0x39, 0xff, 0x99, 0xcf, 0x61, 0x10, 0x55, 0x31, 0xaf, 0xe6, 0xfe, 0x8a, + 0x3c, 0x06, 0xc7, 0x99, 0x67, 0xf5, 0x08, 0xa4, 0x24, 0x6e, 0xd2, 0x7f, + 0x49, 0x39, 0x81, 0x79, 0x27, 0x0c, 0x3c, 0x1e, 0xc5, 0xa3, 0x59, 0xc2, + 0x34, 0xb1, 0xcb, 0xd6, 0x3d, 0x01, 0x96, 0x01, 0xf3, 0xb3, 0xca, 0xc1, + 0xf9, 0xb3, 0x9e, 0xb0, 0xef, 0xff, 0xbb, 0xdd, 0xdd, 0x65, 0xa5, 0x6c, + 0x2c, 0x4b, 0x18, 0x9b, 0xec, 0x29, 0x75, 0xd5, 0x7e, 0x1e, 0xb4, 0xce, + 0x07, 0x38, 0x5f, 0xd7, 0x23, 0x75, 0xd5, 0x16, 0xd8, 0x96, 0xb0, 0x44, + 0x6f, 0xdd, 0xfd, 0xa0, 0x02, 0xb6, 0x87, 0xe8, 0x35, 0xf6, 0x50, 0x45, + 0x34, 0x29, 0xd8, 0x31, 0xc3, 0xf6, 0x6b, 0x5d, 0x59, 0x62, 0xfc, 0xd6, + 0xfa, 0x64, 0xb5, 0x76, 0xe4, 0x97, 0xe8, 0xa2, 0xeb, 0x01, 0x7c, 0x87, + 0xfc, 0xe8, 0x5e, 0xe2, 0x73, 0x47, 0xfb, 0xbd, 0xb6, 0xdf, 0xee, 0x28, + 0xad, 0xa1, 0xeb, 0x2c, 0xef, 0x0e, 0xec, 0xcf, 0xea, 0x48, 0x67, 0xcb, + 0x9c, 0x87, 0xc8, 0xe6, 0xe3, 0xf8, 0x11, 0xc5, 0xd9, 0x67, 0x4b, 0x8c, + 0xc9, 0x12, 0x36, 0x1e, 0xfb, 0x61, 0xa9, 0x05, 0xcf, 0x91, 0x4f, 0x3e, + 0x43, 0x31, 0xf7, 0x07, 0x36, 0x4e, 0x73, 0x8a, 0x43, 0x69, 0xc2, 0xa4, + 0x43, 0x26, 0xd2, 0xf9, 0x10, 0x3c, 0x87, 0xc3, 0xfb, 0x77, 0x08, 0xf5, + 0xc7, 0x24, 0x2f, 0xff, 0x81, 0xe9, 0xa5, 0xa8, 0x3a, 0xac, 0x4e, 0x10, + 0xdd, 0xfe, 0x47, 0xa7, 0x35, 0xc2, 0xd4, 0x41, 0xff, 0xbe, 0xbc, 0xe2, + 0xdf, 0x3b, 0x16, 0xf0, 0xef, 0x9d, 0xae, 0x27, 0x3f, 0x5a, 0xe4, 0x1f, + 0x9c, 0x0e, 0xfa, 0x77, 0xa7, 0x1b, 0xfd, 0xbb, 0xf3, 0x6d, 0x08, 0xd5, + 0xc3, 0x5c, 0x44, 0x39, 0xe2, 0xbe, 0xd1, 0x6f, 0x62, 0xa2, 0xae, 0x12, + 0xf7, 0xfb, 0xc9, 0x36, 0x6a, 0xc9, 0x0e, 0x57, 0x4a, 0xb7, 0xa1, 0xbc, + 0xb0, 0x72, 0xed, 0x3b, 0x74, 0xed, 0xa1, 0x56, 0xf8, 0xff, 0xc2, 0x8e, + 0xbd, 0xc0, 0x73, 0x64, 0x6b, 0xcf, 0xb6, 0x52, 0x5d, 0x79, 0xd5, 0xd6, + 0x9c, 0x14, 0x6f, 0x2d, 0x4b, 0x6f, 0x13, 0x08, 0xb6, 0x6e, 0x00, 0x16, + 0xcc, 0xd7, 0x92, 0xc9, 0x09, 0x67, 0x6b, 0x12, 0x4b, 0xb4, 0x8d, 0x78, + 0x42, 0xa1, 0x54, 0xd3, 0xfa, 0x75, 0xcc, 0x3d, 0x83, 0xef, 0x8c, 0x7a, + 0x90, 0xda, 0xac, 0x60, 0x9a, 0xb0, 0xca, 0x76, 0x9a, 0x7f, 0x59, 0xac, + 0x59, 0x99, 0x21, 0x3d, 0x24, 0x15, 0xbe, 0x46, 0x3e, 0xd1, 0xba, 0x8a, + 0x7c, 0xa2, 0xb2, 0xfe, 0xd3, 0xa4, 0xaf, 0xdc, 0x4c, 0x14, 0x7b, 0x4b, + 0x3f, 0x91, 0x2a, 0xf9, 0x45, 0x9d, 0x48, 0xe2, 0xac, 0x3d, 0xf6, 0xe9, + 0xec, 0x1b, 0x56, 0xc8, 0xb6, 0x3b, 0x81, 0xc7, 0x56, 0x44, 0xf6, 0xff, + 0x27, 0xa9, 0x81, 0xf8, 0x22, 0xd9, 0x65, 0xed, 0x3a, 0xb2, 0x76, 0xb1, + 0xf6, 0x2f, 0xf0, 0x23, 0x85, 0x65, 0x3b, 0x20, 0xf6, 0x53, 0xbd, 0x4a, + 0xa5, 0x53, 0xed, 0x02, 0xed, 0x30, 0x9e, 0xe9, 0xe6, 0x6b, 0x01, 0xff, + 0x81, 0xb1, 0xa4, 0x14, 0xd0, 0xa0, 0xb8, 0x8c, 0x0e, 0x71, 0x60, 0x7a, + 0x91, 0xff, 0xd1, 0xb1, 0x0d, 0xe2, 0xd1, 0xe9, 0x46, 0xff, 0x60, 0xba, + 0x53, 0x0c, 0xe6, 0x37, 0x0b, 0x73, 0xe2, 0x5b, 0xc2, 0x9c, 0x4e, 0x09, + 0x33, 0xdf, 0x43, 0x9f, 0x5b, 0xc4, 0x58, 0x7e, 0x40, 0xec, 0xcd, 0xf3, + 0xfc, 0xa4, 0x2b, 0x5a, 0xe3, 0x87, 0x14, 0x7b, 0x9f, 0xa3, 0xd8, 0xfb, + 0x2c, 0xc5, 0xde, 0x67, 0xc8, 0xde, 0x7f, 0x70, 0x15, 0xe3, 0xb2, 0x8d, + 0x27, 0x19, 0x9b, 0xf8, 0xff, 0xbc, 0x78, 0x86, 0xf4, 0xcd, 0xb2, 0xfb, + 0x37, 0x64, 0xdb, 0x2c, 0x93, 0x87, 0x38, 0x57, 0x90, 0x9e, 0xde, 0xb7, + 0x6d, 0xf9, 0xb1, 0x15, 0x8c, 0xa5, 0x06, 0xc4, 0x56, 0xa2, 0x2f, 0xe9, + 0x24, 0x0c, 0xa4, 0x11, 0x3e, 0xc9, 0x0e, 0x88, 0xbb, 0xf3, 0x7c, 0xfd, + 0x20, 0x76, 0x52, 0x4d, 0x78, 0x28, 0x16, 0xee, 0xee, 0x25, 0xec, 0xb4, + 0x89, 0xb0, 0xd3, 0xb2, 0x98, 0x8c, 0x8b, 0x2d, 0x9f, 0x58, 0x58, 0x88, + 0xe4, 0xfd, 0x71, 0x75, 0x62, 0xa2, 0x92, 0x6f, 0x73, 0x19, 0x70, 0xdd, + 0x8e, 0xda, 0x1a, 0x4d, 0x3d, 0x91, 0x44, 0x78, 0x7f, 0x5c, 0x82, 0xe9, + 0x36, 0x5c, 0xb8, 0xcf, 0xae, 0x15, 0xd7, 0x63, 0x74, 0x54, 0x60, 0x5b, + 0x6b, 0xf2, 0x8f, 0x5c, 0x24, 0xab, 0xb7, 0xdb, 0x11, 0x20, 0xf5, 0x0a, + 0x99, 0xea, 0xfa, 0x4e, 0x92, 0x5e, 0x07, 0xe5, 0xdc, 0x27, 0xb2, 0xab, + 0xd0, 0xd0, 0x2a, 0x93, 0x0e, 0x9d, 0xb8, 0xb3, 0x78, 0x13, 0xe9, 0x31, + 0x72, 0xe4, 0x79, 0x78, 0xfd, 0x2f, 0x8c, 0x19, 0x18, 0xca, 0xe2, 0x7b, + 0x3e, 0xaa, 0xe1, 0xee, 0x25, 0xfc, 0xf4, 0x03, 0xa2, 0x61, 0x63, 0x6b, + 0xa4, 0x93, 0x6a, 0x79, 0xc5, 0x6b, 0xb8, 0x31, 0xd2, 0xe4, 0x87, 0xa2, + 0xa5, 0xc4, 0x2b, 0xf9, 0xc8, 0x91, 0x1d, 0xd2, 0xb7, 0xc4, 0xcf, 0xa7, + 0x0d, 0x3c, 0x5a, 0xea, 0x11, 0x7f, 0x31, 0x2d, 0x83, 0x74, 0x43, 0x71, + 0x4b, 0xc7, 0x11, 0xa2, 0xcb, 0x45, 0x18, 0xc9, 0xf5, 0xfb, 0x02, 0x8b, + 0xb5, 0x24, 0xbe, 0xb3, 0x8a, 0x7d, 0xa1, 0x12, 0xd3, 0x9c, 0xab, 0x80, + 0xfd, 0x64, 0x93, 0x0d, 0x99, 0x0e, 0xb1, 0x84, 0xbe, 0x5f, 0xa4, 0xbc, + 0x96, 0x94, 0x3a, 0x45, 0x03, 0x61, 0xd3, 0x85, 0x93, 0x5b, 0xc4, 0x82, + 0x22, 0x63, 0x51, 0x28, 0x0b, 0x49, 0x46, 0x0b, 0x8b, 0x17, 0x1d, 0x95, + 0x1a, 0xc0, 0xc5, 0xb6, 0x64, 0xfa, 0x0c, 0xd9, 0x7f, 0x88, 0x62, 0xfb, + 0x8e, 0x58, 0x27, 0xe1, 0x64, 0xbe, 0x3e, 0x20, 0x86, 0x48, 0x8e, 0x13, + 0x2e, 0xdb, 0x76, 0xfc, 0x4f, 0x8c, 0xc1, 0xd5, 0x60, 0x20, 0xe4, 0xa6, + 0xdc, 0xf1, 0xdf, 0xdb, 0x22, 0xe6, 0xf3, 0x52, 0x97, 0xc8, 0xe5, 0x03, + 0xfe, 0x23, 0x63, 0x9c, 0x67, 0x3a, 0xc4, 0x11, 0xd2, 0x79, 0x96, 0x74, + 0x9e, 0x25, 0x9d, 0x67, 0x48, 0xe7, 0x99, 0x2f, 0xd1, 0xf9, 0x3e, 0xd2, + 0xf9, 0xee, 0xfc, 0xaf, 0x6c, 0x1d, 0x3a, 0x0d, 0x03, 0x59, 0xca, 0xcb, + 0x23, 0x4d, 0x15, 0xfe, 0x3e, 0x24, 0x59, 0xbc, 0x14, 0xfb, 0x86, 0x13, + 0x5e, 0x83, 0x62, 0x6b, 0x17, 0x3d, 0xf3, 0x95, 0x39, 0x1b, 0x57, 0xfc, + 0xc3, 0x63, 0x1d, 0x62, 0x98, 0xfc, 0x6e, 0x84, 0xe6, 0x1f, 0x21, 0xbf, + 0x1b, 0x4c, 0xff, 0x9f, 0xd8, 0x0d, 0xdb, 0x1d, 0x4c, 0x2f, 0xe5, 0xad, + 0x6a, 0xb2, 0x4b, 0xa7, 0xc1, 0x36, 0xb4, 0x59, 0x24, 0x8f, 0x7e, 0x4b, + 0x24, 0x8f, 0xa5, 0x44, 0xb2, 0xd0, 0x43, 0x9f, 0x5b, 0xc4, 0x2d, 0x76, + 0x1d, 0x3a, 0x20, 0x3a, 0x0a, 0x01, 0xff, 0x38, 0xad, 0x33, 0x4e, 0x7c, + 0x3c, 0x46, 0xeb, 0x3c, 0x66, 0xdb, 0x2e, 0x15, 0x99, 0x5e, 0x5e, 0x8b, + 0xed, 0x8c, 0xed, 0xeb, 0x32, 0xd1, 0xce, 0xbe, 0x71, 0xb5, 0xc7, 0x43, + 0x7f, 0x37, 0x38, 0xa0, 0xed, 0x74, 0x56, 0x78, 0xe2, 0xdc, 0xcf, 0xb9, + 0x9e, 0xe3, 0xb0, 0x62, 0xd7, 0x82, 0xcf, 0x5e, 0xc5, 0x00, 0x8c, 0x07, + 0x20, 0x2f, 0x30, 0xb6, 0x18, 0xdf, 0x69, 0xfa, 0x1f, 0x34, 0x5f, 0x3f, + 0xf4, 0x55, 0x90, 0x03, 0xc6, 0x5f, 0x1a, 0x63, 0x4d, 0x14, 0xa7, 0x69, + 0x4e, 0x39, 0x03, 0x68, 0x19, 0x81, 0xdd, 0x09, 0x41, 0x38, 0x76, 0x11, + 0xf9, 0x25, 0xd3, 0xaf, 0x76, 0x52, 0x36, 0xc1, 0xd2, 0x21, 0xc8, 0x4b, + 0x8c, 0x9d, 0xb0, 0xb2, 0x90, 0x6b, 0x8d, 0x3e, 0x5c, 0x19, 0x0a, 0x07, + 0x3b, 0xa1, 0xa6, 0x2e, 0x38, 0xd4, 0x32, 0xe5, 0xb7, 0xfe, 0xdd, 0x42, + 0xed, 0x9b, 0x15, 0xdc, 0x27, 0x62, 0xec, 0xbe, 0x13, 0x2d, 0x36, 0x86, + 0xef, 0x43, 0x73, 0x1e, 0x54, 0x87, 0x0b, 0xbc, 0x43, 0x73, 0xbe, 0xa8, + 0x7f, 0xc0, 0x39, 0x21, 0x49, 0x58, 0xf0, 0x0b, 0x73, 0x81, 0x70, 0x0c, + 0xcf, 0xc3, 0x73, 0x84, 0x95, 0x3e, 0x9a, 0xf7, 0x4d, 0x47, 0x73, 0xff, + 0xa0, 0x50, 0x13, 0x5f, 0x9c, 0x6f, 0x59, 0x1e, 0x62, 0x59, 0xc6, 0xb4, + 0xaa, 0x35, 0x2f, 0xe3, 0x21, 0xe9, 0x1d, 0x4d, 0x4b, 0xbe, 0x86, 0x10, + 0x96, 0x51, 0x9d, 0x1c, 0x2d, 0x32, 0x0f, 0xbb, 0x70, 0x46, 0x57, 0xbb, + 0xa9, 0x1a, 0xa5, 0xba, 0xa5, 0x03, 0x07, 0x29, 0xf6, 0x3e, 0x5a, 0xe2, + 0x3e, 0xd7, 0x80, 0x58, 0x3e, 0x44, 0x7e, 0x69, 0xdb, 0x13, 0xe4, 0x06, + 0xe3, 0x61, 0xdc, 0x40, 0xeb, 0xfb, 0xa9, 0xf6, 0x79, 0x9d, 0xd6, 0x97, + 0x32, 0xea, 0x00, 0xad, 0x9f, 0x7a, 0x43, 0x84, 0x67, 0x89, 0xaf, 0x9e, + 0x75, 0x8e, 0xe6, 0xbe, 0x5d, 0x42, 0x4d, 0x12, 0xe9, 0xe4, 0xc7, 0xbc, + 0xf6, 0xc3, 0xcc, 0x0b, 0x7d, 0x52, 0x9d, 0x43, 0x76, 0xd4, 0x54, 0x90, + 0x45, 0x64, 0x78, 0x3d, 0xf6, 0x4e, 0xad, 0xc7, 0x1e, 0xf2, 0xc7, 0x03, + 0x7a, 0x2d, 0x42, 0x75, 0xa8, 0xa9, 0xd5, 0x30, 0x7b, 0x41, 0x13, 0x8e, + 0x1d, 0x2d, 0x8d, 0x64, 0xc7, 0xa7, 0x1b, 0xaa, 0xf0, 0x91, 0xd5, 0xab, + 0xad, 0xef, 0xa4, 0x88, 0x78, 0x83, 0x07, 0xe3, 0x0e, 0xf2, 0xef, 0x5f, + 0xfc, 0x9a, 0x02, 0xaa, 0xc7, 0x60, 0xdc, 0x96, 0x10, 0x97, 0xf2, 0x67, + 0x9d, 0x15, 0x3f, 0x68, 0xc2, 0x15, 0x05, 0xb5, 0x41, 0x6d, 0x39, 0x66, + 0x15, 0x99, 0xe2, 0x85, 0x69, 0xd7, 0x64, 0x37, 0xe7, 0xba, 0xd1, 0x40, + 0xf5, 0xf1, 0x9d, 0xb1, 0x5f, 0x5b, 0x9f, 0x2c, 0xe6, 0xe7, 0x4e, 0x7a, + 0x2a, 0xb1, 0xf3, 0xcb, 0xe6, 0x88, 0x53, 0xbc, 0x69, 0xa6, 0x7a, 0xb6, + 0x9a, 0x82, 0x74, 0x27, 0xe5, 0x23, 0xb5, 0x27, 0x4d, 0xf5, 0x68, 0x5f, + 0xa4, 0x59, 0x77, 0x08, 0x37, 0xca, 0x81, 0x70, 0x7f, 0x2f, 0x92, 0xdb, + 0xfd, 0x73, 0x74, 0x3c, 0x2b, 0x34, 0x17, 0x3d, 0xc7, 0xf3, 0x5c, 0x63, + 0x4f, 0x27, 0xc9, 0x9e, 0xf8, 0x3e, 0x7f, 0xbf, 0x7a, 0x5f, 0xfe, 0x8a, + 0xf1, 0x97, 0xff, 0xe4, 0x8f, 0x97, 0x7d, 0xd9, 0xf5, 0x8f, 0xbf, 0xe4, + 0xfa, 0xff, 0xae, 0xae, 0x2f, 0xd7, 0x39, 0x6d, 0xcc, 0x90, 0x94, 0xb8, + 0x8f, 0xe9, 0x34, 0x2e, 0xaf, 0xd9, 0xa3, 0xfd, 0x0e, 0xc5, 0x34, 0xee, + 0x63, 0x70, 0x9e, 0x3e, 0x6f, 0xf7, 0x31, 0x4e, 0x7d, 0x0e, 0xb3, 0x72, + 0x6c, 0xf1, 0x88, 0xea, 0x11, 0xd3, 0xaa, 0xd7, 0xbe, 0x4d, 0x75, 0xcd, + 0x2e, 0xf4, 0xc6, 0x74, 0x0c, 0x67, 0xd5, 0xee, 0xdb, 0xa0, 0x25, 0x37, + 0x0b, 0x9a, 0xa8, 0xe8, 0x11, 0x8e, 0x91, 0xb9, 0x7b, 0xba, 0x49, 0xb5, + 0x5a, 0x19, 0x55, 0x14, 0x9b, 0x9c, 0x9a, 0x22, 0xa3, 0x18, 0x90, 0x9d, + 0xc5, 0xa0, 0xec, 0x2e, 0x36, 0xca, 0x55, 0x34, 0xce, 0x37, 0xa2, 0xce, + 0xde, 0x86, 0x5d, 0x98, 0x6d, 0xf3, 0x9a, 0x0d, 0x86, 0xaa, 0x34, 0x38, + 0x76, 0x61, 0x4f, 0x8c, 0x9f, 0xed, 0xa0, 0x9a, 0x0d, 0xa2, 0x2e, 0x43, + 0xc8, 0xd8, 0x10, 0xd8, 0xdb, 0xae, 0x0e, 0x2c, 0x95, 0xb4, 0xce, 0x5f, + 0x09, 0xa7, 0xec, 0x29, 0x42, 0xf8, 0x33, 0x12, 0x8e, 0xb4, 0xc3, 0xe3, + 0x59, 0xa5, 0xf6, 0x9d, 0x16, 0x03, 0x78, 0x2a, 0x16, 0xe9, 0xde, 0x26, + 0x42, 0xb2, 0x97, 0xee, 0xb9, 0x32, 0x14, 0x7f, 0x33, 0xa6, 0xc7, 0xb5, + 0x4a, 0x0d, 0x4a, 0x22, 0x89, 0x5e, 0x4d, 0xd3, 0x47, 0x20, 0xd3, 0x9a, + 0x10, 0x55, 0x19, 0x75, 0xf6, 0x4d, 0xc2, 0x54, 0x9f, 0x2c, 0x1b, 0x40, + 0x6b, 0x5b, 0x64, 0x7f, 0x8f, 0xa4, 0xc9, 0x84, 0xf5, 0x84, 0x33, 0xe3, + 0xc3, 0xca, 0xc3, 0xf3, 0x7d, 0x1d, 0xcb, 0xfa, 0x30, 0x56, 0x26, 0xbd, + 0x40, 0xae, 0x29, 0x46, 0x65, 0x1f, 0xe1, 0xfa, 0xe6, 0xc3, 0x8c, 0xb3, + 0x2c, 0x6b, 0x47, 0xac, 0xfc, 0x75, 0x2f, 0x5a, 0x88, 0xc7, 0x6e, 0x4c, + 0xa5, 0x19, 0x77, 0x19, 0x98, 0xa4, 0x9a, 0x48, 0x1b, 0x6a, 0xc4, 0x71, + 0x8a, 0x43, 0x33, 0x69, 0xee, 0xff, 0xf4, 0x91, 0x8c, 0x7b, 0x88, 0xfe, + 0x2d, 0x54, 0x0f, 0xa7, 0x28, 0x7e, 0xb1, 0x8c, 0x7b, 0xc9, 0xee, 0x21, + 0x7b, 0x8d, 0x3a, 0xe3, 0xe6, 0x61, 0xc8, 0x1e, 0xc3, 0x6b, 0x5c, 0x77, + 0x18, 0x75, 0x94, 0xf7, 0x0d, 0xaa, 0x78, 0x10, 0x8d, 0x44, 0xf4, 0x8b, + 0x88, 0x04, 0x5f, 0x24, 0x7d, 0x0c, 0x6a, 0xc0, 0x6e, 0xbb, 0xd6, 0x76, + 0xc2, 0xcc, 0x73, 0x0d, 0x0d, 0x4f, 0x55, 0x7b, 0x1d, 0xde, 0xc9, 0x45, + 0xed, 0x1e, 0x92, 0x49, 0xf5, 0xcf, 0x0b, 0xba, 0x9a, 0x9a, 0xa0, 0xe7, + 0xb6, 0x2a, 0xff, 0x65, 0x5f, 0x75, 0x1c, 0x32, 0xc5, 0x34, 0xb2, 0xbd, + 0x3f, 0xf5, 0xbe, 0x49, 0x36, 0x7a, 0xfb, 0xd8, 0x9f, 0x79, 0xaf, 0xc4, + 0x27, 0xbc, 0x1f, 0xc4, 0x2d, 0x2b, 0x41, 0x78, 0xb4, 0x87, 0xea, 0xed, + 0x0f, 0x87, 0x4c, 0xef, 0xc5, 0x38, 0xf7, 0x81, 0x9d, 0xf8, 0x3d, 0xfa, + 0xfd, 0xe4, 0x90, 0x8c, 0x4d, 0x85, 0x06, 0xb8, 0x86, 0x1d, 0x98, 0xd2, + 0x6f, 0x44, 0xaf, 0x22, 0xe1, 0xee, 0xe8, 0x49, 0xb2, 0x49, 0x89, 0xc6, + 0x1c, 0xa2, 0xdf, 0xdc, 0xd3, 0x7a, 0x0c, 0xdb, 0x94, 0x69, 0xef, 0x3b, + 0x71, 0xa6, 0x17, 0x4c, 0xaf, 0x2c, 0x69, 0xb7, 0x62, 0xeb, 0x6d, 0x5c, + 0x5b, 0xd9, 0xff, 0x9e, 0x17, 0xdb, 0xeb, 0x71, 0x3c, 0xd7, 0x80, 0xe7, + 0x73, 0xa6, 0xe7, 0xb5, 0xf6, 0x28, 0xfa, 0x86, 0x2c, 0xbc, 0xac, 0x9b, + 0x03, 0x55, 0x64, 0xe7, 0x09, 0xaa, 0xaf, 0xc2, 0x6d, 0xdc, 0x4b, 0x40, + 0xc4, 0x81, 0x48, 0x3f, 0x81, 0xcc, 0x3b, 0x28, 0x74, 0xa5, 0x6a, 0xa8, + 0x4e, 0x3b, 0x27, 0x2c, 0xf7, 0xf6, 0x76, 0x27, 0xd1, 0x00, 0x6c, 0x28, + 0xb4, 0x90, 0xdc, 0xa2, 0xd8, 0x14, 0x91, 0xb1, 0xb1, 0xa0, 0xe3, 0xf9, + 0xb4, 0x0f, 0xb7, 0x17, 0xe2, 0x84, 0xbd, 0x15, 0xa2, 0x3d, 0x81, 0x52, + 0x3a, 0x80, 0x6f, 0x14, 0x1a, 0x49, 0xde, 0x41, 0xdc, 0x58, 0x08, 0xe1, + 0x44, 0x9a, 0xf3, 0xb7, 0xe1, 0xd9, 0x1a, 0x6f, 0x44, 0x67, 0x41, 0xc3, + 0x74, 0x1a, 0x9e, 0x07, 0xe2, 0x21, 0x74, 0x14, 0xa2, 0x28, 0x10, 0x86, + 0xbb, 0x95, 0xe6, 0xbc, 0x9d, 0x74, 0xd2, 0x52, 0x08, 0x60, 0x69, 0x84, + 0x22, 0x72, 0xc1, 0x27, 0x06, 0x08, 0x5b, 0x25, 0x0a, 0xf5, 0xb8, 0x38, + 0xcc, 0x76, 0xae, 0x18, 0x7b, 0x72, 0x0a, 0x42, 0x05, 0xac, 0x94, 0x01, + 0x0a, 0xd6, 0x91, 0x54, 0x81, 0xe8, 0x3d, 0xd8, 0x5e, 0xe9, 0xe1, 0x2e, + 0x2f, 0x7c, 0xc6, 0x6f, 0x2d, 0xe9, 0xe9, 0xca, 0xe1, 0x69, 0xef, 0x27, + 0x71, 0x8e, 0x4d, 0x9f, 0xae, 0x79, 0xfd, 0x30, 0x10, 0x1d, 0x67, 0xde, + 0xec, 0xd8, 0xc8, 0xf1, 0xb0, 0x45, 0xc6, 0xaf, 0x2c, 0xaa, 0x41, 0x43, + 0x53, 0xbc, 0x57, 0xa0, 0xf9, 0x88, 0x0e, 0x05, 0x49, 0x5a, 0xfb, 0x96, + 0xc2, 0x0f, 0xad, 0xad, 0x0b, 0x83, 0xb8, 0x39, 0x52, 0x91, 0xd5, 0x39, + 0xd2, 0xe1, 0xe4, 0x70, 0x03, 0x66, 0x88, 0x06, 0x97, 0xe1, 0x36, 0x8e, + 0x8d, 0x59, 0xd8, 0xa0, 0x9b, 0xde, 0xd7, 0xda, 0x97, 0xe3, 0xfe, 0xc3, + 0x83, 0x67, 0xdd, 0xa4, 0xd7, 0x59, 0xfd, 0x0e, 0x3c, 0x3a, 0x8e, 0xaf, + 0x35, 0x00, 0x8f, 0x04, 0xc1, 0x3d, 0x6b, 0x35, 0x74, 0x02, 0x91, 0xce, + 0x07, 0x10, 0x51, 0x34, 0xa1, 0xea, 0x2f, 0x0b, 0x24, 0xab, 0x8d, 0xc8, + 0xd9, 0x5b, 0x80, 0x33, 0x6e, 0xf2, 0xe0, 0xdb, 0x0b, 0x4e, 0x92, 0x51, + 0x10, 0xa5, 0x61, 0x37, 0x1c, 0xe4, 0x27, 0x97, 0x34, 0x6c, 0xa8, 0x25, + 0x59, 0x3b, 0x84, 0x4c, 0x7a, 0x6e, 0xc1, 0xb1, 0xa1, 0x79, 0x59, 0xf9, + 0x70, 0x13, 0xc9, 0xf0, 0xa9, 0x21, 0x6b, 0x97, 0x16, 0x0b, 0x90, 0xac, + 0x15, 0xa2, 0x6f, 0x5e, 0x4e, 0x2c, 0xbf, 0x79, 0x39, 0xdd, 0x81, 0x3d, + 0x33, 0x2c, 0xb7, 0xff, 0x1b, 0x79, 0x4d, 0xdb, 0x76, 0xb7, 0x61, 0x2c, + 0x8a, 0x86, 0xc3, 0x57, 0x65, 0xc7, 0xf4, 0x3d, 0x42, 0x7c, 0x7c, 0xcf, + 0xbf, 0x3a, 0xd2, 0xf7, 0xbe, 0xf0, 0x11, 0x3d, 0x0a, 0xe9, 0xe6, 0x03, + 0x17, 0x63, 0x77, 0x92, 0xc9, 0x55, 0x19, 0x07, 0x49, 0xc6, 0xc1, 0x71, + 0x96, 0xf5, 0xa7, 0x6b, 0xae, 0x90, 0x7c, 0x5f, 0x27, 0x5c, 0x76, 0x43, + 0x2c, 0x8a, 0x9a, 0xc3, 0x6a, 0xb2, 0xc1, 0x11, 0x4e, 0xd4, 0x0a, 0x50, + 0x55, 0x82, 0x96, 0x1a, 0x7c, 0xc8, 0x72, 0xd6, 0x49, 0xce, 0xdf, 0x1b, + 0x24, 0x7e, 0xd6, 0xd3, 0x7c, 0x1b, 0x48, 0xce, 0x49, 0xe2, 0xff, 0x16, + 0x7b, 0xde, 0x46, 0x9a, 0x77, 0x0b, 0xd5, 0x1e, 0xd3, 0xde, 0x4b, 0x44, + 0x4f, 0xf4, 0x33, 0x5a, 0x08, 0x8d, 0x47, 0x82, 0xef, 0x53, 0x8d, 0x7d, + 0xa3, 0x3d, 0x4e, 0xa1, 0x71, 0x4c, 0xfb, 0xcf, 0xab, 0x24, 0xed, 0xcb, + 0xfa, 0xcd, 0xdf, 0x02, 0xf7, 0x1c, 0x4c, 0xf4, 0x50, 0x1d, 0xb1, 0x85, + 0x6a, 0x25, 0x99, 0x72, 0x9b, 0x89, 0x1f, 0xc4, 0xd5, 0x68, 0x9d, 0xe0, + 0xf8, 0x67, 0x92, 0x1f, 0x96, 0xa9, 0x4e, 0x0a, 0x87, 0x66, 0x10, 0x94, + 0xa5, 0xa2, 0x4c, 0x78, 0xb0, 0x51, 0x76, 0x14, 0xc9, 0x5f, 0x83, 0x3d, + 0x84, 0xa7, 0x9d, 0x78, 0x31, 0xef, 0xc4, 0x2b, 0xe9, 0x2d, 0x38, 0x50, + 0xf2, 0x10, 0x6e, 0x36, 0x3d, 0xce, 0x55, 0x13, 0xee, 0x4a, 0x4c, 0x5e, + 0x86, 0xae, 0x91, 0x87, 0x51, 0x9d, 0x71, 0x76, 0x53, 0x3e, 0xd5, 0x6f, + 0x21, 0xb9, 0x6c, 0x28, 0xf2, 0xfd, 0x46, 0x64, 0xd2, 0x29, 0xc2, 0x40, + 0x61, 0xaa, 0x81, 0x9c, 0x98, 0x68, 0x68, 0xb4, 0xfb, 0xba, 0x39, 0xba, + 0x96, 0x2b, 0x7d, 0xb1, 0xdf, 0x7c, 0xc7, 0x5c, 0x9f, 0xb9, 0x0f, 0xfb, + 0xb2, 0x3d, 0x84, 0x4d, 0xb7, 0x50, 0x7c, 0xaf, 0xd0, 0x38, 0x1d, 0xef, + 0xc6, 0xbe, 0xbc, 0x71, 0x35, 0x7e, 0x4c, 0xda, 0xf1, 0xa3, 0x1f, 0x55, + 0xed, 0xbc, 0x7f, 0xb5, 0x05, 0x77, 0xa5, 0x81, 0xf7, 0xd2, 0xdc, 0x4f, + 0x24, 0x4c, 0x41, 0xf9, 0xe0, 0x90, 0xce, 0x39, 0x74, 0x0b, 0x96, 0xe6, + 0x2d, 0xe4, 0x75, 0x0b, 0x67, 0x75, 0x8d, 0x72, 0x34, 0xe7, 0xea, 0x01, + 0xa1, 0x51, 0x7e, 0x36, 0x9d, 0xfd, 0x88, 0xb4, 0xb3, 0x8e, 0x1e, 0x9e, + 0xdb, 0x87, 0xea, 0xb7, 0xf7, 0xa1, 0x66, 0xd2, 0x0e, 0x3c, 0x45, 0x8a, + 0x78, 0x3e, 0x1b, 0x0e, 0xbd, 0x07, 0x6b, 0x97, 0xc3, 0x50, 0x13, 0x4e, + 0x07, 0xef, 0xcf, 0xf0, 0xfe, 0x94, 0xd6, 0xbd, 0xd4, 0xa1, 0xea, 0x45, + 0xd1, 0xdc, 0xf3, 0x16, 0xca, 0x1b, 0x65, 0xa8, 0xa1, 0xd7, 0x10, 0x89, + 0x76, 0xf2, 0x1e, 0x44, 0xa9, 0x92, 0xbb, 0x97, 0xcd, 0xe5, 0x6e, 0x2d, + 0xef, 0x15, 0xe1, 0x61, 0x09, 0x13, 0x53, 0x96, 0x29, 0x91, 0xfd, 0x4e, + 0xd1, 0x9c, 0x3f, 0xce, 0xee, 0x42, 0x36, 0x66, 0x59, 0xb7, 0xc7, 0xb5, + 0xbe, 0x06, 0x07, 0xfe, 0x90, 0x32, 0x39, 0xc8, 0xe6, 0x53, 0xe4, 0x6b, + 0xa1, 0x1d, 0xed, 0xa6, 0xe5, 0xb6, 0xeb, 0x0a, 0xee, 0x4f, 0x76, 0x89, + 0x96, 0xc2, 0x16, 0xb1, 0x9c, 0xb0, 0x5b, 0xe8, 0xd8, 0x66, 0xd1, 0x74, + 0xb4, 0x82, 0xdd, 0x22, 0x85, 0xcf, 0x7a, 0xa8, 0x37, 0xa7, 0x2d, 0xa4, + 0x89, 0xaf, 0xa7, 0xfe, 0x0e, 0x5f, 0xac, 0x8b, 0x7e, 0x5c, 0xd7, 0xce, + 0xbe, 0xf8, 0x30, 0x8e, 0xa5, 0xd9, 0xce, 0xfb, 0xb1, 0x87, 0xe4, 0xb3, + 0x62, 0x88, 0xf7, 0xc3, 0xd4, 0xb3, 0x83, 0x08, 0xf7, 0xbd, 0x2a, 0xd4, + 0x72, 0x01, 0xcd, 0x7a, 0x8d, 0x83, 0xe3, 0xab, 0x3a, 0xd0, 0xe4, 0xa8, + 0xd0, 0x9f, 0xc8, 0x83, 0xe2, 0x69, 0x85, 0x87, 0x95, 0xf9, 0xa5, 0x64, + 0xab, 0xa6, 0xe7, 0x52, 0xbc, 0xb9, 0xbf, 0x1a, 0x1b, 0xc4, 0x07, 0xd3, + 0x21, 0x78, 0x0f, 0x27, 0x17, 0xfa, 0xd1, 0x21, 0xde, 0xb3, 0xeb, 0xc5, + 0x4e, 0xf1, 0x4e, 0xbe, 0x5b, 0x5c, 0x9e, 0xe8, 0x42, 0x64, 0xf8, 0x3e, + 0xf1, 0xf6, 0x04, 0xd3, 0xd9, 0x23, 0xce, 0x4f, 0x73, 0x9f, 0xd4, 0xc2, + 0x1e, 0x9d, 0xfb, 0xa2, 0x8b, 0xab, 0xe0, 0xb7, 0x70, 0x4c, 0x67, 0x7d, + 0x72, 0x9f, 0xb0, 0xd2, 0x5f, 0xda, 0x10, 0xcf, 0x59, 0x4e, 0x8d, 0x7b, + 0xc5, 0x41, 0x9b, 0xdf, 0x29, 0xc2, 0xd1, 0xd3, 0x13, 0x5b, 0xc4, 0xf1, + 0x7c, 0x85, 0xd7, 0xc9, 0x3c, 0xdb, 0xaf, 0x4c, 0x3a, 0xfe, 0x62, 0x9e, + 0x36, 0xa1, 0xb4, 0x07, 0xe1, 0xb6, 0xfb, 0x51, 0x16, 0x46, 0xf4, 0x48, + 0xe8, 0x65, 0x04, 0xe1, 0x2c, 0xb2, 0x6d, 0x5b, 0x78, 0x5a, 0x77, 0xc1, + 0x31, 0x22, 0x93, 0x8c, 0xc8, 0x96, 0xfc, 0x2e, 0x48, 0x93, 0x5c, 0x1b, + 0x7c, 0xbd, 0x8a, 0xfb, 0x14, 0x21, 0x89, 0xbf, 0x7f, 0xd1, 0xe6, 0x5c, + 0x94, 0x0f, 0xb8, 0xbf, 0xfe, 0x57, 0xee, 0x8a, 0xed, 0xb1, 0x5d, 0xcd, + 0xf7, 0xc4, 0x29, 0xd7, 0xb6, 0x73, 0x2f, 0xdc, 0x83, 0x99, 0x9c, 0x9b, + 0x5b, 0x14, 0x1e, 0x77, 0xbb, 0x85, 0x0b, 0xba, 0x93, 0xea, 0x97, 0x87, + 0x28, 0x47, 0x49, 0x90, 0xb5, 0x3b, 0x50, 0x1c, 0x73, 0x4a, 0xbc, 0x5f, + 0xf5, 0xb3, 0x18, 0xf7, 0x10, 0x80, 0x43, 0xc4, 0xc3, 0xf7, 0x73, 0x21, + 0x6c, 0xa2, 0xba, 0x2b, 0x64, 0xd7, 0x18, 0xbf, 0x87, 0x53, 0x39, 0x87, + 0xa0, 0xba, 0xc2, 0x91, 0x58, 0x6d, 0xe1, 0x4a, 0x5b, 0x24, 0xca, 0x7d, + 0x68, 0x85, 0x72, 0xd6, 0xde, 0x7c, 0x1d, 0x7e, 0x96, 0xab, 0xc3, 0x2b, + 0x39, 0x0b, 0x07, 0x63, 0x83, 0x3d, 0x5e, 0x8a, 0x95, 0xcb, 0x62, 0x2e, + 0xec, 0x88, 0x98, 0x8a, 0x17, 0x51, 0x5c, 0x48, 0x5c, 0x87, 0x54, 0x20, + 0xdc, 0x39, 0x88, 0x7a, 0xbc, 0x91, 0x03, 0x61, 0x09, 0x78, 0x96, 0xd2, + 0x1c, 0x6f, 0xc7, 0xcc, 0x7e, 0x17, 0xe1, 0xd8, 0x9f, 0x0b, 0xc4, 0x6b, + 0x60, 0xb9, 0xcf, 0xc4, 0x29, 0x57, 0x17, 0xea, 0xd0, 0x95, 0xab, 0x47, + 0x0f, 0xe5, 0xac, 0x75, 0xab, 0xe3, 0x78, 0x2b, 0xeb, 0x13, 0x2b, 0xb3, + 0x83, 0x3d, 0x0a, 0xcd, 0xe9, 0x6a, 0x53, 0xfb, 0x9f, 0x22, 0xe0, 0x26, + 0x23, 0x4c, 0xe6, 0x8e, 0x07, 0xfc, 0x14, 0x77, 0x8f, 0x8b, 0x4f, 0xf1, + 0x04, 0xd9, 0xe3, 0x3d, 0xba, 0x5a, 0xbe, 0xe4, 0x88, 0x9c, 0xdd, 0x08, + 0x75, 0xe0, 0x16, 0x61, 0x46, 0x6b, 0x29, 0x9e, 0x34, 0x54, 0x62, 0x85, + 0x19, 0x11, 0x32, 0x61, 0x73, 0x27, 0x3c, 0x9a, 0x89, 0xce, 0x76, 0x96, + 0xa9, 0x07, 0x9e, 0xa3, 0x64, 0x47, 0xd2, 0x17, 0xfb, 0xfb, 0x75, 0x78, + 0x9d, 0xf2, 0xe5, 0xb9, 0x1c, 0xf7, 0xe6, 0xdd, 0xc6, 0xbb, 0x94, 0x03, + 0x5e, 0x8a, 0x0d, 0x86, 0x38, 0xf6, 0xe7, 0x63, 0xf8, 0xe7, 0x64, 0x96, + 0x8d, 0x3e, 0x5a, 0xf3, 0x2e, 0xc1, 0xeb, 0x20, 0xb9, 0xc4, 0xe0, 0xbe, + 0x9c, 0xcd, 0x0f, 0xc5, 0x63, 0xe6, 0xe9, 0xff, 0x27, 0xed, 0x8f, 0x54, + 0xc1, 0x5b, 0x4f, 0xba, 0x9c, 0xef, 0x69, 0x5e, 0xdb, 0xcf, 0xe4, 0x7a, + 0xa6, 0x82, 0x0f, 0xdd, 0x46, 0xb5, 0x78, 0x21, 0xc7, 0x36, 0x67, 0xe1, + 0x19, 0x5d, 0xa7, 0xda, 0x85, 0x6b, 0xf2, 0x7e, 0xaa, 0x5f, 0xb8, 0xcf, + 0x64, 0x7a, 0xce, 0x10, 0x85, 0xfb, 0x73, 0x58, 0x2b, 0xc3, 0xb1, 0xa2, + 0x0a, 0xe3, 0x98, 0x70, 0x3a, 0x09, 0x73, 0x70, 0xac, 0x65, 0x7f, 0x52, + 0x0c, 0x6d, 0x82, 0xeb, 0xcf, 0x4e, 0x98, 0xb6, 0x1f, 0x57, 0x8b, 0xfb, + 0xc9, 0x46, 0x5e, 0x8c, 0x55, 0x61, 0x82, 0xea, 0x1f, 0xc9, 0x30, 0x3d, + 0xdf, 0xa5, 0xe7, 0x13, 0xa3, 0xd8, 0x17, 0x84, 0xe3, 0x4f, 0x14, 0xfc, + 0x19, 0xde, 0x74, 0xc9, 0x74, 0x1d, 0x9e, 0xee, 0xb8, 0xe9, 0xdd, 0x18, + 0xaf, 0x16, 0xb7, 0xe6, 0x5a, 0xf0, 0xfe, 0x58, 0x1d, 0xd9, 0x77, 0x3d, + 0x96, 0x8c, 0x04, 0xf1, 0x36, 0xd1, 0x32, 0x40, 0xb4, 0x7c, 0xd2, 0x66, + 0x0e, 0x34, 0x40, 0xed, 0xa7, 0xba, 0xa8, 0x9b, 0xfb, 0xcd, 0x4f, 0xeb, + 0x6a, 0xe7, 0x6d, 0xc2, 0x0b, 0x2d, 0x92, 0x24, 0xd9, 0x5b, 0xd6, 0xb0, + 0xde, 0xac, 0xfb, 0xc0, 0xfd, 0xa3, 0x3b, 0x70, 0x68, 0x86, 0x69, 0x71, + 0x1b, 0xcb, 0xa7, 0xf9, 0x53, 0x36, 0xae, 0xb3, 0x3f, 0xbd, 0x73, 0x9f, + 0x30, 0x42, 0xf6, 0xe7, 0xa7, 0x6b, 0x42, 0xd3, 0xdc, 0xa7, 0x0e, 0x9b, + 0x6e, 0xf1, 0x53, 0x17, 0xf7, 0xab, 0x93, 0xe0, 0xff, 0x57, 0x5d, 0x95, + 0x7e, 0xdf, 0x1d, 0x30, 0xed, 0x1e, 0xca, 0x15, 0xbb, 0x97, 0x1d, 0x22, + 0x37, 0x90, 0x89, 0x3f, 0x99, 0x30, 0x57, 0x20, 0x46, 0x05, 0x7c, 0xbd, + 0x6c, 0x2e, 0x31, 0x7a, 0xa8, 0x46, 0x90, 0x89, 0x5f, 0x13, 0xfb, 0xda, + 0x05, 0x0e, 0x69, 0x06, 0x5e, 0xcb, 0x73, 0x2c, 0x77, 0xe2, 0xfb, 0x69, + 0x35, 0x94, 0x12, 0xe1, 0xce, 0x5b, 0x84, 0x84, 0x50, 0x43, 0x0f, 0x0e, + 0x51, 0x5e, 0x99, 0x4e, 0x73, 0x1e, 0x71, 0xda, 0xe7, 0x05, 0x6a, 0x29, + 0x0e, 0x7d, 0x38, 0x54, 0x89, 0xfb, 0x85, 0xb8, 0xba, 0xff, 0xf7, 0x48, + 0xa7, 0x4f, 0x17, 0x78, 0x4e, 0x13, 0x9f, 0xac, 0x66, 0x1f, 0x56, 0xa3, + 0x29, 0xe9, 0x5e, 0x84, 0xa6, 0x38, 0xb6, 0xd0, 0x72, 0xb4, 0xd6, 0x91, + 0xac, 0x1b, 0xdd, 0xf1, 0x2e, 0xd1, 0x53, 0xfc, 0x67, 0xbc, 0x27, 0xa1, + 0x2c, 0x30, 0x36, 0x8b, 0xf5, 0x93, 0xdc, 0x53, 0xdc, 0x22, 0xba, 0x8b, + 0xdc, 0x57, 0x1c, 0x10, 0xbf, 0x5f, 0x64, 0x9f, 0x9f, 0xef, 0x2f, 0xce, + 0xeb, 0x9f, 0xfb, 0x8a, 0xa6, 0xe7, 0x05, 0x92, 0xfd, 0x03, 0x39, 0x8e, + 0xc9, 0x8e, 0xfb, 0xfd, 0x68, 0xc3, 0x84, 0x0b, 0x9e, 0xd3, 0xf1, 0xaf, + 0xe0, 0x76, 0xc2, 0x07, 0x4b, 0xb4, 0x8a, 0xfe, 0xd6, 0x4d, 0x48, 0x48, + 0xb4, 0x91, 0xd0, 0x17, 0xb0, 0x4e, 0x7b, 0x29, 0x9e, 0x65, 0xac, 0xbe, + 0x00, 0xeb, 0x92, 0xed, 0xcd, 0x2e, 0xf7, 0x28, 0x0e, 0x9b, 0x94, 0x57, + 0x3c, 0x98, 0xce, 0x2d, 0xa2, 0xda, 0xc0, 0xc2, 0x7e, 0xbd, 0x06, 0x55, + 0x76, 0x0c, 0xf0, 0x10, 0x9e, 0x84, 0xec, 0xa3, 0x79, 0xd2, 0xc3, 0x32, + 0xbc, 0x74, 0xef, 0x8c, 0x4e, 0x72, 0x69, 0xaf, 0xcc, 0xdd, 0x3c, 0xb1, + 0x12, 0x07, 0xc9, 0xe3, 0x6b, 0xb4, 0x28, 0x86, 0x14, 0x1f, 0xc5, 0x9a, + 0x3b, 0xe6, 0xe6, 0xf4, 0xd0, 0x60, 0x5e, 0xaf, 0xbf, 0xaa, 0xa2, 0x87, + 0x35, 0x72, 0xa5, 0x06, 0x93, 0xcd, 0x6a, 0x5a, 0x6b, 0x47, 0xfb, 0x16, + 0x74, 0x0e, 0xf9, 0xc4, 0x2b, 0xe9, 0xbb, 0xad, 0x50, 0x1d, 0x8d, 0x23, + 0x9b, 0x75, 0xcf, 0xd1, 0xdb, 0x34, 0x21, 0xf3, 0x58, 0xee, 0x79, 0xe0, + 0xc1, 0x9c, 0x84, 0xc0, 0xdc, 0xf5, 0xf8, 0x44, 0x08, 0x7a, 0x6b, 0x35, + 0x50, 0x2f, 0xe8, 0x1a, 0xcf, 0xcd, 0x6b, 0xc8, 0xa8, 0x23, 0x3f, 0xb9, + 0x33, 0x9e, 0xc0, 0xbb, 0x59, 0x27, 0x36, 0x52, 0x9e, 0xbf, 0x31, 0x6d, + 0xe0, 0x42, 0x29, 0x60, 0xcf, 0x21, 0x19, 0xf3, 0xe3, 0x9c, 0x34, 0xce, + 0x83, 0xc9, 0x89, 0x2f, 0xd2, 0x17, 0x20, 0x9a, 0x7f, 0x42, 0xdf, 0xf9, + 0xde, 0x45, 0xbb, 0x3f, 0x70, 0xea, 0x9a, 0xba, 0x4a, 0x1a, 0xe1, 0x9e, + 0x52, 0x25, 0x17, 0x74, 0xe8, 0xac, 0x4b, 0x3f, 0x66, 0x47, 0x4d, 0x5c, + 0x58, 0x5d, 0x8b, 0x4f, 0x46, 0x9b, 0x70, 0x7f, 0xce, 0x8b, 0x4b, 0xa3, + 0x16, 0x56, 0xb6, 0xe1, 0xee, 0x20, 0x61, 0xb1, 0x5a, 0xf2, 0xfb, 0xd7, + 0xa8, 0xf6, 0xa1, 0x78, 0x4a, 0x94, 0x46, 0x12, 0x1b, 0xc8, 0xae, 0xa3, + 0x31, 0xa4, 0x6e, 0x8a, 0x47, 0x42, 0x17, 0xf1, 0x3d, 0x8b, 0x62, 0xb1, + 0xe2, 0x30, 0xba, 0x84, 0xd3, 0xde, 0x67, 0xdc, 0x62, 0xef, 0x4b, 0x4a, + 0x93, 0x03, 0xc2, 0x51, 0xbc, 0xd6, 0xaf, 0xbf, 0x2c, 0x0f, 0x71, 0xee, + 0xe1, 0x1e, 0xc6, 0x88, 0xe5, 0xd2, 0xb8, 0x57, 0xb3, 0x59, 0xec, 0x9d, + 0xb8, 0x9a, 0x9b, 0xae, 0xe6, 0xa3, 0xdd, 0x73, 0x79, 0x68, 0x30, 0xff, + 0x8b, 0x2f, 0xe0, 0xa8, 0xd0, 0xdc, 0x7e, 0x07, 0xe7, 0x1f, 0x8f, 0x78, + 0x93, 0xcc, 0x61, 0x1f, 0xf9, 0xe0, 0x49, 0xfd, 0x74, 0x90, 0x32, 0x04, + 0x9c, 0xad, 0x02, 0x0f, 0xf2, 0x59, 0x93, 0x80, 0x85, 0xcd, 0x7a, 0xc5, + 0x1e, 0xda, 0xda, 0x5d, 0xe8, 0xa3, 0x9c, 0xe4, 0x8a, 0xf9, 0xc8, 0xd7, + 0x15, 0xbc, 0xaa, 0xb3, 0x0d, 0x6f, 0x9e, 0xcb, 0x49, 0xbc, 0x7f, 0x5e, + 0xd9, 0xeb, 0xfe, 0x7c, 0xdf, 0x7b, 0xde, 0x36, 0x75, 0x24, 0x17, 0xc2, + 0xfb, 0x76, 0x5c, 0xa3, 0xfa, 0x41, 0xa6, 0xda, 0x61, 0x23, 0x12, 0x0b, + 0x54, 0x6e, 0x6d, 0x10, 0xf6, 0x36, 0xf1, 0xef, 0xdb, 0xfb, 0x70, 0xdf, + 0x88, 0x84, 0x6a, 0x8d, 0xe3, 0xac, 0x89, 0x43, 0x75, 0x1c, 0xa7, 0xba, + 0xb0, 0x6b, 0xc4, 0x23, 0xce, 0xe4, 0x9c, 0x78, 0xa2, 0xfb, 0x11, 0x2c, + 0x68, 0xbd, 0x07, 0xb0, 0x6d, 0x90, 0xbf, 0x7f, 0x0b, 0xa9, 0x45, 0xbc, + 0x3e, 0xf7, 0xda, 0x04, 0x7c, 0xad, 0xcc, 0x07, 0xbc, 0xef, 0xd3, 0xfc, + 0xdb, 0x86, 0x9c, 0xe2, 0x62, 0xfa, 0x3f, 0x5b, 0x27, 0x02, 0x8c, 0x13, + 0xf8, 0x5e, 0x0d, 0xcc, 0x3a, 0x1e, 0xcb, 0x3a, 0xf4, 0x51, 0x6d, 0xda, + 0x87, 0x21, 0xa2, 0xeb, 0x9c, 0x3d, 0xd7, 0x95, 0x39, 0xfa, 0x7d, 0xa2, + 0x36, 0x23, 0x9b, 0x41, 0xa2, 0x45, 0x59, 0xdd, 0x8d, 0xda, 0xe2, 0xb5, + 0xf9, 0xb6, 0xc6, 0xc3, 0xfd, 0x4a, 0xd2, 0x15, 0xe5, 0x84, 0x5e, 0xbc, + 0x9b, 0x16, 0x78, 0xc7, 0xb6, 0xc1, 0x5e, 0x34, 0xe5, 0x6b, 0x00, 0x3b, + 0x86, 0xf0, 0xb8, 0xaf, 0x57, 0x6c, 0x5b, 0xea, 0xc3, 0x03, 0xc4, 0x4b, + 0x0d, 0xf1, 0xf2, 0x61, 0x6c, 0x29, 0xad, 0xc3, 0xd7, 0xfe, 0x9d, 0x3c, + 0x77, 0xd6, 0x68, 0x6e, 0x2e, 0x4a, 0x18, 0x7e, 0xae, 0xf7, 0x22, 0xd8, + 0x39, 0x12, 0xe9, 0xf1, 0x49, 0x6c, 0x87, 0x11, 0xdc, 0x3b, 0x79, 0x2b, + 0xdd, 0xe7, 0xb9, 0x82, 0xb8, 0x2b, 0xe3, 0x14, 0x6f, 0x51, 0xbd, 0x74, + 0x2a, 0x2d, 0x2d, 0x72, 0xe0, 0x39, 0xeb, 0x89, 0xc0, 0x2e, 0xdc, 0xa4, + 0x77, 0x61, 0x3b, 0xd9, 0x60, 0x47, 0xd3, 0x2e, 0x8c, 0x92, 0x0d, 0x6c, + 0xab, 0xa7, 0x1a, 0x2e, 0x56, 0xb2, 0x7a, 0x03, 0x2c, 0x47, 0x81, 0x4e, + 0xba, 0x5e, 0x47, 0x75, 0x9d, 0x14, 0x23, 0x6b, 0x23, 0xbf, 0x90, 0x35, + 0x35, 0x97, 0xc4, 0xef, 0xd8, 0x6b, 0xd6, 0x51, 0x9e, 0x76, 0x31, 0x3e, + 0xf0, 0x33, 0x4e, 0xf8, 0x22, 0x3d, 0xa6, 0x55, 0xa5, 0x69, 0xd1, 0x8d, + 0x52, 0x53, 0x6e, 0x86, 0x6c, 0x76, 0x7d, 0xeb, 0xb5, 0xcf, 0xcd, 0xcb, + 0x48, 0x87, 0xbb, 0x75, 0xca, 0x2a, 0x2b, 0x83, 0x50, 0x5a, 0xaf, 0xd5, + 0xfd, 0xfc, 0x1c, 0x4c, 0x73, 0x25, 0xae, 0x85, 0xa4, 0x88, 0x72, 0x37, + 0x2e, 0xd0, 0x1a, 0x41, 0x6c, 0x2d, 0x76, 0xa1, 0x77, 0xc4, 0xf1, 0x19, + 0x3e, 0xf1, 0xb3, 0x2d, 0x7f, 0xc6, 0xff, 0x8e, 0x91, 0x48, 0xa7, 0x77, + 0x8e, 0xff, 0xed, 0x93, 0x9f, 0xcd, 0x35, 0x90, 0xe1, 0xbc, 0xca, 0xf3, + 0xf1, 0xb9, 0xa1, 0x79, 0xf9, 0x06, 0xf1, 0x80, 0x3d, 0xdf, 0x61, 0x0f, + 0xfb, 0xb0, 0x8b, 0x7c, 0x7d, 0x43, 0xab, 0x89, 0x57, 0x13, 0xf7, 0x5b, + 0x3b, 0x6c, 0x19, 0xdc, 0x6f, 0x3f, 0xdf, 0xd9, 0x74, 0x76, 0x0e, 0xfb, + 0x54, 0xfa, 0xb0, 0xa7, 0x4a, 0x2d, 0xf6, 0x1e, 0xc3, 0x0f, 0x29, 0x0f, + 0x3e, 0xf7, 0xb9, 0x3e, 0xdf, 0x76, 0x17, 0xef, 0x4d, 0x3c, 0x5d, 0x92, + 0x85, 0x73, 0xa4, 0x5a, 0xb8, 0x46, 0x98, 0xb6, 0x8f, 0xe5, 0x8a, 0x8f, + 0xfd, 0x57, 0x24, 0x03, 0xbc, 0xcf, 0x58, 0xb1, 0xff, 0x68, 0xfb, 0xbd, + 0xc0, 0x51, 0xd3, 0x53, 0xb5, 0x0a, 0x54, 0xeb, 0x77, 0xdb, 0xf6, 0xb0, + 0xd0, 0x08, 0xac, 0x7d, 0xae, 0x89, 0xeb, 0x7d, 0xee, 0x0d, 0x6a, 0x6b, + 0xc7, 0x08, 0x80, 0x6e, 0x55, 0x78, 0x4d, 0xf5, 0x04, 0xf7, 0xeb, 0xb9, + 0x8f, 0x4f, 0x71, 0xd7, 0x5b, 0xb7, 0xca, 0xf4, 0x2c, 0x58, 0xe5, 0x14, + 0x8b, 0x33, 0x3d, 0x64, 0x7b, 0x1a, 0x12, 0x19, 0xd3, 0xdb, 0xb0, 0x2a, + 0x84, 0x87, 0x32, 0xf3, 0x31, 0xb9, 0x05, 0x2d, 0xe3, 0xc0, 0x0f, 0x33, + 0x41, 0x34, 0x8f, 0x86, 0xfb, 0x6f, 0x95, 0xc2, 0x03, 0xb3, 0x12, 0xdf, + 0xbb, 0xbc, 0x66, 0xa5, 0x8d, 0xc5, 0x3f, 0x5a, 0xb3, 0xc2, 0xfe, 0x0c, + 0x18, 0xd7, 0xe7, 0xef, 0x40, 0x7a, 0xc6, 0x33, 0x5b, 0x96, 0x2c, 0x3c, + 0x14, 0x93, 0x70, 0xb3, 0xfe, 0x6f, 0xc9, 0xb7, 0x04, 0xd9, 0xc6, 0xab, + 0x9c, 0x83, 0xed, 0x60, 0xb6, 0x64, 0x95, 0x86, 0x55, 0x99, 0x3a, 0x8a, + 0x49, 0xf5, 0x14, 0x9f, 0xea, 0x70, 0x85, 0x62, 0xd2, 0x8a, 0x36, 0x0b, + 0x8b, 0xdb, 0xcc, 0xbe, 0xc5, 0xe0, 0x3d, 0x68, 0xd5, 0x2c, 0x0a, 0xb5, + 0xa7, 0x4b, 0x52, 0xbb, 0xeb, 0x25, 0x05, 0xdb, 0x23, 0x3c, 0x77, 0xd0, + 0x58, 0x95, 0xaf, 0xe4, 0xd3, 0x4a, 0x5e, 0x75, 0xce, 0xe5, 0x53, 0xb7, + 0xa1, 0x4f, 0xab, 0x3f, 0x4e, 0x49, 0xbc, 0x6f, 0xd2, 0x83, 0x91, 0x6c, + 0x0a, 0x7b, 0xb3, 0x21, 0xfc, 0x3a, 0xe3, 0x26, 0xdb, 0x08, 0xeb, 0x3f, + 0x00, 0x8f, 0xf1, 0x19, 0xb1, 0x7c, 0x38, 0xfa, 0x90, 0xf4, 0x13, 0x94, + 0x9d, 0xea, 0x11, 0xaa, 0x12, 0x08, 0x37, 0x34, 0x87, 0x5e, 0xc4, 0x4f, + 0xec, 0x7d, 0x36, 0xa0, 0xc2, 0x43, 0x53, 0x1e, 0xc8, 0x65, 0x3c, 0xb3, + 0xb0, 0x7b, 0xb2, 0xbc, 0x6f, 0x2c, 0x61, 0xbd, 0x7e, 0x3f, 0xc9, 0x59, + 0xa0, 0xa9, 0xb5, 0x0e, 0xe5, 0x2d, 0x4e, 0x8c, 0x64, 0x38, 0x0f, 0x7f, + 0xbc, 0x46, 0x1e, 0x42, 0x79, 0x6e, 0x4f, 0x34, 0xe1, 0xa0, 0x0c, 0xfd, + 0x72, 0x11, 0x38, 0x48, 0xb1, 0x63, 0x53, 0xec, 0x37, 0x56, 0x05, 0x8f, + 0xca, 0xfe, 0xf4, 0x98, 0xc0, 0x02, 0x2d, 0x49, 0xf2, 0x70, 0xfa, 0x0f, + 0xa5, 0xa3, 0x76, 0x0e, 0x1e, 0xa1, 0xf9, 0x93, 0xf6, 0xfc, 0x91, 0xfd, + 0x4b, 0x25, 0x09, 0xd7, 0xb7, 0x1e, 0xc5, 0xc4, 0xc2, 0x0a, 0x0d, 0x41, + 0xc2, 0x04, 0x5c, 0xcb, 0xd6, 0x13, 0x8f, 0x9b, 0x1f, 0xe3, 0xbe, 0xe6, + 0x6f, 0xd7, 0xdc, 0x30, 0xce, 0x7e, 0xfd, 0xf1, 0x9a, 0x77, 0xd3, 0x6a, + 0xb2, 0x9e, 0xea, 0x87, 0x6a, 0x92, 0xc3, 0xbd, 0x43, 0xdc, 0x4f, 0xa8, + 0x37, 0x5e, 0x3f, 0xcc, 0x79, 0x59, 0x1d, 0x68, 0x10, 0x3e, 0x71, 0x73, + 0x46, 0xed, 0x63, 0xc2, 0x2f, 0x47, 0xd4, 0x20, 0xc9, 0xae, 0xf3, 0x1e, + 0xd1, 0xc7, 0x35, 0x8b, 0x2d, 0xb7, 0xeb, 0xf2, 0x15, 0xdc, 0x11, 0x9e, + 0xc3, 0x21, 0x51, 0x1b, 0x77, 0x58, 0xd6, 0x9e, 0x18, 0xe7, 0x71, 0xfb, + 0x4c, 0x00, 0x5d, 0xaf, 0x33, 0x96, 0x52, 0x6d, 0x31, 0xc8, 0xf4, 0xf1, + 0x19, 0x0f, 0x89, 0x6a, 0xd1, 0xec, 0xab, 0x73, 0xb8, 0xc4, 0x87, 0x7d, + 0x74, 0xbd, 0x6c, 0xe3, 0x13, 0x3e, 0xa7, 0xe8, 0x35, 0x94, 0xc7, 0xf8, + 0x6c, 0xe3, 0x6f, 0xd7, 0xac, 0x1f, 0x53, 0x43, 0x12, 0xf1, 0xb1, 0x97, + 0xf7, 0xe7, 0x69, 0xce, 0x69, 0x9d, 0xe9, 0xbe, 0xbc, 0x86, 0xfb, 0xb1, + 0x4b, 0x88, 0x6e, 0x2b, 0x1b, 0x66, 0x0c, 0x6a, 0xdb, 0x4a, 0x22, 0x4f, + 0x55, 0xfd, 0xe2, 0x0a, 0xaf, 0x2e, 0xd2, 0xc9, 0xb1, 0x74, 0x12, 0xa7, + 0xe2, 0x15, 0xfd, 0xac, 0xcb, 0x7f, 0x03, 0xa9, 0xfa, 0x0e, 0xe4, 0xb2, + 0x8a, 0x7f, 0x43, 0xa6, 0x03, 0xa3, 0xa4, 0xc3, 0xbb, 0x8b, 0x41, 0x7f, + 0x47, 0x46, 0x43, 0x6f, 0x91, 0xeb, 0x2b, 0x18, 0x7b, 0xc6, 0x26, 0xe7, + 0xea, 0xe0, 0x4a, 0x2e, 0x39, 0x90, 0xa9, 0xd8, 0x5c, 0x38, 0xef, 0x99, + 0x0d, 0x89, 0xca, 0xbc, 0x32, 0xad, 0x23, 0x0f, 0xfd, 0x89, 0x85, 0x85, + 0x6c, 0x0b, 0x77, 0x60, 0x6c, 0xdc, 0x6f, 0x2e, 0x36, 0x14, 0xac, 0x6a, + 0xfd, 0x73, 0x7a, 0xb6, 0x05, 0x1f, 0x1f, 0xff, 0x3a, 0xca, 0xdf, 0x24, + 0x7c, 0x94, 0x49, 0xa2, 0xb9, 0xf5, 0x16, 0xa4, 0xfe, 0x40, 0xc6, 0xd3, + 0x19, 0x1f, 0x9e, 0xcf, 0x54, 0xf6, 0xec, 0x7f, 0x94, 0x25, 0x3f, 0x24, + 0x1f, 0x78, 0xee, 0x4b, 0xf7, 0x49, 0x29, 0x9e, 0x3b, 0x78, 0x0f, 0xff, + 0x1f, 0x1e, 0x77, 0xde, 0x1e, 0xe7, 0x11, 0x75, 0x23, 0xf3, 0xf3, 0x5a, + 0xd0, 0x5a, 0xff, 0xbe, 0x67, 0x08, 0xf3, 0x81, 0x62, 0x48, 0xe5, 0x8c, + 0x83, 0x90, 0x47, 0xec, 0x7d, 0x23, 0xc2, 0xb9, 0x11, 0xfd, 0x02, 0x4c, + 0xb8, 0x09, 0x5f, 0x2d, 0x25, 0x59, 0x68, 0x99, 0x80, 0x5f, 0x2a, 0x2a, + 0xf4, 0xdf, 0xe8, 0x77, 0x92, 0x7c, 0x9c, 0xc5, 0x8f, 0x28, 0xa6, 0xb0, + 0x4f, 0x55, 0x72, 0x9c, 0x54, 0x7c, 0xc4, 0x4b, 0xc0, 0x87, 0x3e, 0x2b, + 0x36, 0x1d, 0xca, 0x2f, 0xf6, 0x32, 0x96, 0xc9, 0x65, 0x2a, 0xbf, 0x23, + 0x57, 0x7f, 0x93, 0x9e, 0x6d, 0x99, 0x8d, 0xd0, 0x6f, 0x96, 0xc5, 0x73, + 0x56, 0x6a, 0x33, 0xcb, 0x2b, 0xe0, 0x7f, 0x83, 0xe4, 0x3f, 0x46, 0x34, + 0x66, 0x69, 0x8d, 0xd7, 0x69, 0xcd, 0x4c, 0xf1, 0x10, 0x8d, 0xe1, 0x7b, + 0x24, 0x67, 0xdb, 0x76, 0x0f, 0x7b, 0xf9, 0x7c, 0xc2, 0xf3, 0x19, 0x60, + 0x30, 0x6b, 0xaa, 0xce, 0xb9, 0x73, 0x9d, 0x83, 0x94, 0x2f, 0xab, 0x28, + 0x16, 0xbd, 0x19, 0xdf, 0x8e, 0x1b, 0x73, 0x6a, 0xd2, 0x24, 0x3c, 0x96, + 0x52, 0x20, 0x48, 0x77, 0x64, 0xc3, 0x01, 0xe3, 0xdd, 0x74, 0x23, 0xf1, + 0x14, 0x0e, 0x5d, 0xa0, 0xf1, 0xa6, 0x53, 0xc6, 0x81, 0x51, 0x07, 0x2e, + 0xf0, 0x1e, 0xb2, 0xa8, 0x3c, 0x6f, 0x82, 0xc7, 0xce, 0x7f, 0xaf, 0xa6, + 0xba, 0x2e, 0x9c, 0xa0, 0xac, 0x6a, 0xd6, 0x10, 0x6e, 0xcf, 0xb7, 0x3f, + 0x82, 0x43, 0x54, 0xeb, 0xef, 0x88, 0x85, 0x90, 0xac, 0x8b, 0x53, 0xbd, + 0xd1, 0xdc, 0x7f, 0x09, 0xff, 0xcd, 0x2a, 0xf3, 0x3e, 0xbc, 0x08, 0x27, + 0x2e, 0xe1, 0x53, 0xcb, 0xa1, 0x69, 0x67, 0xa7, 0xa0, 0x95, 0x2f, 0xa0, + 0x79, 0xe0, 0x13, 0xbc, 0x67, 0xf1, 0x1e, 0xbd, 0xec, 0x70, 0x10, 0x06, + 0x0c, 0x2b, 0x4e, 0x04, 0x50, 0x0e, 0x38, 0xb0, 0x49, 0xe7, 0xde, 0xb4, + 0x3a, 0xf0, 0x24, 0x61, 0xf9, 0x77, 0x44, 0x73, 0xdf, 0x87, 0x38, 0x6f, + 0x4d, 0xd4, 0xf1, 0xba, 0x02, 0x89, 0xeb, 0x9b, 0xcf, 0xba, 0xa1, 0x76, + 0xba, 0x84, 0x96, 0x68, 0x70, 0xfc, 0x95, 0x75, 0x3e, 0xf0, 0xa9, 0xa5, + 0x45, 0x3e, 0x25, 0x1c, 0xa4, 0x05, 0x27, 0xc9, 0xf6, 0xfb, 0x30, 0x4f, + 0x9b, 0xa8, 0x86, 0x57, 0x27, 0x1a, 0x18, 0xf7, 0x99, 0x9e, 0x7d, 0x44, + 0xdb, 0x6b, 0x84, 0x03, 0x76, 0xc4, 0x2e, 0x59, 0xc9, 0x85, 0x7c, 0xfe, + 0x4f, 0xa9, 0xae, 0xf4, 0xc0, 0xb9, 0x6f, 0x72, 0x07, 0xee, 0x4a, 0x3b, + 0x49, 0x4e, 0xf3, 0x78, 0xcd, 0x45, 0x31, 0x98, 0x63, 0x7f, 0xf9, 0x3a, + 0x2a, 0xcd, 0x24, 0x2a, 0xf1, 0xb1, 0x87, 0xe2, 0xc2, 0x6e, 0x3b, 0x17, + 0xc0, 0xbb, 0x64, 0x55, 0x2b, 0x3e, 0x19, 0x7f, 0xd3, 0x4b, 0xbe, 0xb4, + 0x4e, 0x6b, 0x83, 0x08, 0x66, 0x4c, 0x51, 0x6b, 0x38, 0xf0, 0x61, 0xbb, + 0xda, 0x29, 0x39, 0x06, 0x70, 0x7d, 0xcc, 0xb4, 0x7c, 0x9a, 0xd6, 0xd3, + 0x22, 0x22, 0xdd, 0x45, 0x11, 0x45, 0x75, 0xd1, 0x27, 0x57, 0x17, 0x5b, + 0x64, 0x6f, 0xd1, 0xf4, 0x28, 0xab, 0xb6, 0x53, 0xdd, 0xb2, 0x8b, 0x6a, + 0x5b, 0x1f, 0xd5, 0xd7, 0xaa, 0x7e, 0x11, 0x6e, 0x92, 0x7f, 0x08, 0xfb, + 0x4a, 0x06, 0x9c, 0x99, 0x9d, 0x70, 0x65, 0xc2, 0xca, 0x5e, 0xec, 0x42, + 0x32, 0x58, 0xc1, 0xb6, 0x32, 0xe9, 0xaa, 0xaa, 0x9d, 0xb1, 0xcc, 0x76, + 0x9c, 0x9f, 0x60, 0x7c, 0x9e, 0xc0, 0xd6, 0x34, 0xff, 0x86, 0xf7, 0xc5, + 0xb8, 0x81, 0x93, 0x54, 0x3b, 0x79, 0x5a, 0x1b, 0x48, 0x0f, 0x8d, 0x18, + 0x2c, 0x09, 0x36, 0x2b, 0xd2, 0x05, 0xbc, 0x27, 0xdb, 0x65, 0x1c, 0x9c, + 0xa2, 0x44, 0x42, 0xf9, 0xca, 0x99, 0x51, 0x28, 0x4e, 0xc8, 0xf0, 0x69, + 0x3e, 0xfa, 0x1d, 0xe0, 0x73, 0x4b, 0x64, 0x67, 0xbf, 0x5d, 0xd3, 0x62, + 0xc7, 0x9a, 0x7a, 0xaa, 0x75, 0xde, 0x21, 0x5e, 0x58, 0x16, 0x06, 0xaa, + 0x47, 0xe6, 0x6b, 0xc2, 0xf5, 0xb7, 0x55, 0x23, 0x48, 0x73, 0x32, 0x0e, + 0xac, 0x9c, 0x57, 0x5d, 0x1f, 0x6b, 0x45, 0x21, 0x27, 0xe6, 0x30, 0xd6, + 0xa0, 0xea, 0xc3, 0x3a, 0x1c, 0xa2, 0xda, 0xdf, 0xaf, 0x6d, 0x45, 0x46, + 0x29, 0x7b, 0x7f, 0x11, 0xe7, 0x1a, 0x00, 0xde, 0x5e, 0xc2, 0x50, 0x43, + 0xe9, 0xaf, 0x72, 0xcc, 0xf4, 0xdc, 0x1d, 0xd7, 0x71, 0x24, 0x47, 0x21, + 0x4a, 0x5b, 0x87, 0xda, 0xb6, 0x2e, 0x7c, 0x58, 0xc7, 0xf8, 0x97, 0x62, + 0x15, 0xd1, 0xb3, 0x77, 0x2a, 0x60, 0x9f, 0xab, 0xd8, 0x57, 0x9a, 0xa7, + 0xf9, 0x5a, 0x5a, 0xbf, 0x8c, 0x46, 0x96, 0xc9, 0x3f, 0x44, 0x23, 0xd9, + 0x2c, 0x61, 0x9e, 0x5c, 0xba, 0x17, 0x2f, 0xa7, 0x79, 0xde, 0x70, 0x52, + 0x17, 0x0a, 0xf7, 0xe6, 0x6d, 0x99, 0x98, 0x53, 0xbc, 0x06, 0xaf, 0x3f, + 0xbf, 0x4e, 0x80, 0x6a, 0x85, 0x7f, 0xec, 0x5a, 0x14, 0x37, 0x72, 0xeb, + 0xa8, 0xee, 0x8c, 0x42, 0xfb, 0xfd, 0x32, 0xe9, 0x83, 0x7b, 0xd5, 0x4b, + 0x09, 0xf3, 0xc2, 0xf3, 0x4a, 0x9c, 0xcf, 0x30, 0x5b, 0xbb, 0x64, 0xc3, + 0xb2, 0x5c, 0xed, 0x9a, 0xf2, 0x36, 0xd8, 0x0e, 0x7d, 0xbc, 0xe7, 0xe1, + 0xd9, 0xdb, 0xee, 0xc3, 0x41, 0xca, 0x81, 0x4f, 0xa5, 0x9b, 0x4d, 0xae, + 0xfd, 0xc0, 0x38, 0x54, 0xa4, 0xe8, 0xd9, 0x7f, 0x55, 0xcd, 0x3e, 0xbb, + 0xa7, 0xb4, 0x13, 0x52, 0xa6, 0xa7, 0x9a, 0xeb, 0x0d, 0x37, 0xd5, 0xc9, + 0x83, 0x69, 0xa6, 0xd7, 0xda, 0xe5, 0xa4, 0xb9, 0x76, 0xc7, 0xb5, 0xd9, + 0x1b, 0xc9, 0x2e, 0x1a, 0x0c, 0x96, 0x63, 0x00, 0x4f, 0xd0, 0xd8, 0x50, + 0x89, 0x65, 0x79, 0xa8, 0x9a, 0xfb, 0x9e, 0xfb, 0x48, 0xbf, 0xb5, 0xd9, + 0xca, 0x3c, 0xd9, 0x52, 0x1f, 0x96, 0x0e, 0xbd, 0x58, 0x5d, 0xa9, 0x7d, + 0xb8, 0x2e, 0xef, 0xc7, 0xbe, 0x74, 0x00, 0x53, 0xe9, 0x66, 0xe5, 0x05, + 0xfb, 0xcc, 0x40, 0xa5, 0x47, 0x36, 0x98, 0x9e, 0x1f, 0x13, 0xc0, 0xe4, + 0xd5, 0xef, 0x2c, 0x9f, 0x4a, 0xef, 0xf4, 0x94, 0x8d, 0xf9, 0x65, 0x4c, + 0x04, 0x2a, 0x78, 0x88, 0x62, 0x85, 0xf7, 0x51, 0xd2, 0xeb, 0x3b, 0xa4, + 0x57, 0x89, 0xf4, 0xfa, 0x82, 0xfe, 0x23, 0xc6, 0x2c, 0x9e, 0x3d, 0x71, + 0x1f, 0xef, 0x13, 0x99, 0x04, 0x5a, 0xec, 0x31, 0x99, 0xb8, 0x13, 0xe7, + 0x86, 0xf8, 0x6c, 0xe2, 0x47, 0x6b, 0x5e, 0x4a, 0x5b, 0xeb, 0x66, 0x62, + 0xcd, 0xa9, 0x77, 0x08, 0x4f, 0x9b, 0x7f, 0xa0, 0xea, 0xe7, 0xc9, 0x4f, + 0xb3, 0xa3, 0x7f, 0x88, 0xf3, 0x75, 0xcd, 0xca, 0xcf, 0x61, 0x7a, 0x1e, + 0x8f, 0x3f, 0x42, 0x35, 0x3f, 0xd5, 0x0d, 0x6d, 0xff, 0x92, 0x9c, 0x2c, + 0x0e, 0x87, 0xd6, 0x3c, 0xfb, 0x02, 0xfe, 0x23, 0xce, 0x2f, 0x0e, 0xeb, + 0x2f, 0x80, 0xc7, 0x54, 0xea, 0xf1, 0xf0, 0xf4, 0x7d, 0x7c, 0x9e, 0x2a, + 0x48, 0x69, 0xb4, 0xb2, 0x9f, 0x95, 0xe6, 0xfd, 0x37, 0x81, 0x89, 0x2d, + 0x54, 0x4b, 0xdb, 0xe7, 0x58, 0xe1, 0x7d, 0x92, 0xfc, 0x22, 0x3a, 0xcc, + 0xe3, 0x3f, 0x5e, 0xa3, 0xe5, 0x43, 0x70, 0x10, 0xc6, 0x49, 0x05, 0xd4, + 0x4e, 0x20, 0xe8, 0x7f, 0x32, 0x1d, 0xa4, 0x1a, 0xad, 0xb9, 0x3b, 0x2a, + 0xee, 0x9c, 0xdb, 0xf7, 0xe6, 0x3c, 0xf7, 0xf1, 0x9a, 0x63, 0x69, 0x35, + 0xf5, 0x24, 0x9a, 0x7b, 0x7c, 0xe2, 0x0e, 0xa4, 0xea, 0x9a, 0xfb, 0x4e, + 0x22, 0x9c, 0xf0, 0x08, 0x35, 0x7a, 0x1e, 0x95, 0x79, 0x96, 0xe5, 0x1d, + 0x54, 0x27, 0x72, 0x9c, 0x49, 0xe3, 0xa4, 0xe2, 0xc0, 0xf2, 0x56, 0x6d, + 0x76, 0x12, 0xf3, 0xf6, 0x52, 0x19, 0xb3, 0x2e, 0x4f, 0xe3, 0x1d, 0x0a, + 0xd5, 0xfb, 0x6e, 0x38, 0xeb, 0x79, 0x4f, 0x71, 0x27, 0x76, 0xa4, 0x39, + 0x4f, 0x93, 0x5c, 0xc8, 0x37, 0xbb, 0x23, 0x3b, 0xd1, 0x9f, 0x0f, 0xe0, + 0x50, 0x36, 0xbc, 0x7f, 0x2f, 0xe1, 0xba, 0xe1, 0x52, 0x38, 0xb4, 0x4d, + 0x04, 0x48, 0xdf, 0x54, 0xff, 0xd7, 0x07, 0xa9, 0x4e, 0x56, 0xe8, 0xbf, + 0x52, 0xcf, 0xbc, 0x44, 0xf5, 0xcc, 0x39, 0xf2, 0x35, 0xdf, 0x5c, 0xad, + 0xba, 0x6c, 0xc2, 0xc2, 0x4c, 0x6c, 0x23, 0x2e, 0xdb, 0x3a, 0x0b, 0x92, + 0x8d, 0x71, 0x2e, 0xe2, 0xb3, 0x35, 0x1e, 0xb1, 0x6d, 0xd8, 0xf4, 0x3c, + 0xd8, 0x1e, 0x44, 0x38, 0xc3, 0x98, 0x53, 0xfa, 0xa6, 0x83, 0xe4, 0x31, + 0xa5, 0xed, 0xc2, 0x86, 0xd8, 0x2e, 0xf4, 0xeb, 0x7f, 0x02, 0x77, 0x3d, + 0xc7, 0x23, 0xd9, 0xac, 0xa5, 0x79, 0x2f, 0xb5, 0x77, 0x21, 0x7c, 0x94, + 0x73, 0x30, 0x55, 0xc3, 0x43, 0xec, 0xbb, 0x3c, 0xff, 0x6d, 0xc6, 0x0a, + 0xc2, 0x15, 0x35, 0xed, 0x95, 0x3c, 0x7f, 0x7d, 0x9e, 0xcf, 0x74, 0x82, + 0x6a, 0x53, 0x78, 0xdf, 0x5a, 0x6d, 0xe0, 0x71, 0x8a, 0x31, 0x89, 0x36, + 0x17, 0xb0, 0x80, 0xcf, 0x2e, 0x57, 0xea, 0x18, 0xe6, 0x77, 0x69, 0x5e, + 0x60, 0x3a, 0x4e, 0xf6, 0xf1, 0x77, 0xce, 0x28, 0x85, 0xe6, 0xce, 0x96, + 0x72, 0xff, 0xe4, 0xb0, 0x95, 0xe4, 0xf7, 0x0d, 0xa4, 0xa0, 0x8f, 0xe2, + 0x6d, 0xb0, 0x0c, 0x2a, 0xea, 0x29, 0x2e, 0x3b, 0xb4, 0x79, 0xb9, 0xb3, + 0xac, 0x4f, 0x58, 0x13, 0x73, 0xba, 0x70, 0xd2, 0x33, 0x7b, 0xc6, 0xd4, + 0x81, 0xbd, 0x68, 0xee, 0x7f, 0x57, 0x54, 0xd9, 0x3b, 0x98, 0x93, 0x2d, + 0x48, 0x2d, 0x31, 0x9c, 0x5b, 0x3e, 0xc9, 0xae, 0x23, 0x3a, 0x2e, 0x10, + 0x08, 0x5d, 0x6f, 0xef, 0x73, 0x4d, 0xb6, 0xfc, 0x29, 0xcd, 0xcd, 0xdf, + 0xff, 0xd8, 0xc7, 0x67, 0x2e, 0x4f, 0x65, 0x9f, 0xb7, 0xa2, 0x0b, 0x2b, + 0xf2, 0x39, 0x4d, 0xbe, 0x1f, 0x34, 0x24, 0x34, 0x68, 0x91, 0xd9, 0x1e, + 0xfa, 0xfd, 0xd7, 0x79, 0x42, 0xfb, 0xab, 0xfb, 0xf0, 0xcb, 0x09, 0x03, + 0x07, 0x28, 0x0f, 0xd4, 0x6a, 0xaa, 0x32, 0x81, 0x10, 0xd7, 0xd2, 0x36, + 0xff, 0x2b, 0x27, 0xc8, 0x0f, 0xeb, 0x14, 0xbb, 0xc6, 0xa8, 0xf0, 0x77, + 0x99, 0xf8, 0x7b, 0xd0, 0xc7, 0xbe, 0xb0, 0x84, 0xfc, 0x62, 0x3f, 0xf9, + 0xeb, 0x01, 0xb2, 0x35, 0xaa, 0xe0, 0xc9, 0x0f, 0xd4, 0xfd, 0x20, 0x7f, + 0x1d, 0x4e, 0xb3, 0xfc, 0x83, 0xfe, 0x5e, 0x3e, 0xde, 0xac, 0xd9, 0x7d, + 0x55, 0x3d, 0x24, 0x71, 0xdc, 0xb5, 0xe3, 0xa9, 0x19, 0x92, 0xac, 0x6a, + 0xa6, 0x6b, 0xb0, 0x14, 0x0e, 0x7a, 0xf9, 0x5d, 0x00, 0x02, 0x87, 0xbd, + 0x7a, 0x25, 0x57, 0xce, 0x50, 0x3e, 0xba, 0x4c, 0x74, 0x1c, 0x8a, 0x35, + 0x20, 0x45, 0xf9, 0x28, 0xa3, 0x55, 0x6c, 0x49, 0x9b, 0x66, 0x8c, 0x59, + 0x6f, 0x04, 0xc7, 0xd5, 0x90, 0xcb, 0xd1, 0x3c, 0x70, 0x06, 0x3b, 0xad, + 0xf3, 0x75, 0x6c, 0x53, 0x2e, 0x1c, 0x6f, 0x99, 0xb6, 0xca, 0x01, 0xe6, + 0xd7, 0x81, 0xe7, 0x75, 0xb2, 0x99, 0xc5, 0xe1, 0xe0, 0xf3, 0x94, 0x53, + 0xa7, 0xe6, 0xf4, 0x11, 0xce, 0xcf, 0xdb, 0xe3, 0x5a, 0x96, 0x75, 0x34, + 0x05, 0x2d, 0x91, 0x47, 0x2f, 0x7d, 0x6f, 0x0a, 0x5e, 0x9e, 0xb3, 0xd5, + 0x15, 0xd3, 0xaf, 0xfb, 0xe6, 0xde, 0xcb, 0xb1, 0x9f, 0x09, 0xe5, 0xff, + 0x88, 0x7e, 0xf3, 0x9c, 0x01, 0xc6, 0x32, 0x7c, 0x56, 0xcb, 0xbb, 0xa3, + 0xdd, 0xcd, 0xfe, 0xa2, 0xf0, 0x3b, 0x09, 0x1b, 0x86, 0xb9, 0x2f, 0xcc, + 0x3d, 0x1a, 0x07, 0xf6, 0x5e, 0x7d, 0x67, 0x82, 0x3f, 0x3b, 0xb1, 0x69, + 0x98, 0x7b, 0x11, 0xa7, 0x6f, 0x90, 0xf1, 0x37, 0x94, 0x87, 0x65, 0xf6, + 0x79, 0xf2, 0xf5, 0x4f, 0xd7, 0xbc, 0x34, 0xc6, 0x39, 0x35, 0x60, 0xdc, + 0x95, 0x9e, 0xd7, 0xf1, 0x55, 0x9e, 0xce, 0xde, 0x4d, 0x71, 0x27, 0x93, + 0x56, 0x07, 0x22, 0x0e, 0x7b, 0x7f, 0x2d, 0x55, 0x14, 0x5f, 0xa5, 0x22, + 0x8d, 0xe7, 0x53, 0xfc, 0x03, 0x87, 0x43, 0xc8, 0x64, 0xbb, 0xf0, 0x8d, + 0x61, 0xcb, 0x72, 0xb7, 0x39, 0xf1, 0xca, 0x90, 0x85, 0x0f, 0x62, 0xc0, + 0xcb, 0x43, 0xe1, 0x81, 0x73, 0xc0, 0xb7, 0x6b, 0xa9, 0x46, 0x6e, 0x11, + 0x6a, 0x37, 0x61, 0x83, 0xd0, 0x7b, 0x68, 0x0e, 0xe6, 0xa1, 0x9e, 0xdd, + 0x4d, 0xf3, 0xbd, 0x58, 0x00, 0x7e, 0x59, 0xf0, 0xe2, 0x17, 0xc3, 0x3c, + 0xa7, 0x17, 0xe7, 0x8e, 0xd6, 0xfb, 0x77, 0xd2, 0x5c, 0x07, 0x29, 0xbe, + 0x77, 0x1d, 0x4b, 0x60, 0xd3, 0x61, 0x81, 0x68, 0x24, 0x81, 0xce, 0x63, + 0x35, 0xd8, 0x38, 0x2c, 0xe3, 0xfd, 0x78, 0x0d, 0x6e, 0x39, 0x3a, 0xcf, + 0x47, 0xa5, 0xaf, 0xc1, 0x67, 0x35, 0xf9, 0x1c, 0xdc, 0xc9, 0x2c, 0xc7, + 0x6c, 0xca, 0x17, 0x59, 0x8e, 0x81, 0x96, 0x15, 0x6c, 0xaf, 0xf4, 0x39, + 0x9e, 0xa6, 0xfc, 0xf1, 0x78, 0xbb, 0x16, 0x0c, 0x4a, 0x06, 0x96, 0x8f, + 0x96, 0xef, 0xac, 0x85, 0x75, 0x8a, 0xf7, 0x33, 0x3e, 0x6a, 0xb1, 0xac, + 0x4d, 0xf1, 0xc8, 0xec, 0xbd, 0x36, 0xae, 0x0d, 0x90, 0x4f, 0x35, 0xe2, + 0xf1, 0xec, 0xfc, 0x9e, 0x97, 0xd6, 0x73, 0xc9, 0x61, 0xee, 0x52, 0x60, + 0x5d, 0xa9, 0x32, 0xac, 0x8f, 0x5c, 0x46, 0x24, 0xf8, 0x80, 0xe0, 0xb3, + 0x22, 0xdc, 0x13, 0xb7, 0xac, 0x37, 0xe3, 0x96, 0x55, 0x88, 0x9b, 0x9e, + 0x15, 0xab, 0x14, 0x1c, 0x5b, 0xc6, 0xef, 0x2a, 0x84, 0x93, 0x0d, 0x64, + 0x5f, 0xde, 0x65, 0x5a, 0x70, 0x2b, 0x54, 0xd3, 0xa4, 0x20, 0x17, 0x5a, + 0xa8, 0xf6, 0x00, 0x8d, 0xfe, 0x43, 0x43, 0xf5, 0xf8, 0xfe, 0xcc, 0xef, + 0xf2, 0xf1, 0x1d, 0xbb, 0x9f, 0x76, 0x45, 0xc7, 0xba, 0x5a, 0x44, 0x92, + 0xf7, 0x80, 0x7b, 0xa3, 0x7c, 0xa6, 0xd5, 0xc4, 0x2d, 0xf1, 0x3e, 0xec, + 0x18, 0xe6, 0x7d, 0xb6, 0x3a, 0xe3, 0xca, 0xb0, 0xf5, 0xd7, 0x1e, 0xa2, + 0x7f, 0x5d, 0x7b, 0x73, 0xca, 0x6b, 0xbf, 0xe3, 0xe4, 0x34, 0xd6, 0x8f, + 0xd5, 0xa1, 0x34, 0xa5, 0x95, 0x97, 0x88, 0xe4, 0x1b, 0x3e, 0x44, 0x82, + 0x0d, 0x14, 0xab, 0x66, 0xc8, 0x77, 0xa7, 0x4a, 0x5c, 0x07, 0x2c, 0x30, + 0xac, 0xd1, 0x45, 0x98, 0x9c, 0xa1, 0xb9, 0xb2, 0x5a, 0xe7, 0x07, 0x84, + 0xf3, 0xaa, 0x0d, 0xab, 0xd6, 0x6b, 0x44, 0xce, 0x36, 0x0b, 0x07, 0x66, + 0xdb, 0x2c, 0xab, 0xab, 0x5d, 0x1b, 0xa8, 0x11, 0xe8, 0x97, 0x0c, 0x2d, + 0xd1, 0xe2, 0xc0, 0xd7, 0x82, 0x88, 0x74, 0xbe, 0x89, 0x48, 0xcf, 0x05, + 0x8a, 0x61, 0x4f, 0x95, 0xf8, 0x9c, 0xf0, 0x23, 0xf8, 0xeb, 0xe1, 0x85, + 0x38, 0x35, 0xd5, 0x3f, 0xd7, 0x13, 0x83, 0xf7, 0xfa, 0x55, 0x06, 0x8e, + 0x0f, 0x87, 0xc8, 0x7e, 0xdc, 0x14, 0xd7, 0x65, 0x48, 0x4d, 0x90, 0xeb, + 0xa8, 0x4e, 0x88, 0x3d, 0x66, 0x59, 0x2b, 0x9a, 0x2a, 0x35, 0xcf, 0x8a, + 0xe9, 0x6b, 0xdf, 0x71, 0x98, 0xef, 0xf7, 0x04, 0x49, 0x7f, 0xcd, 0xa9, + 0x1d, 0xe2, 0x8c, 0x65, 0xfe, 0x81, 0x20, 0x9e, 0x7b, 0x6a, 0xe0, 0x65, + 0xbe, 0x65, 0xec, 0x1e, 0xe5, 0x3e, 0x1c, 0xeb, 0x0d, 0xde, 0xce, 0x38, + 0xef, 0x97, 0xb3, 0x8e, 0xca, 0xde, 0x0d, 0x71, 0x8a, 0x89, 0xc2, 0x4f, + 0x78, 0xca, 0xf4, 0x74, 0x50, 0x7e, 0xaa, 0x1a, 0xe6, 0xf7, 0x2d, 0x7c, + 0x38, 0x40, 0x71, 0xe3, 0xb2, 0x5e, 0x8d, 0x43, 0x75, 0x6a, 0x82, 0xeb, + 0xe9, 0x27, 0x4b, 0xdc, 0x33, 0xdc, 0x89, 0xed, 0xfc, 0xbe, 0x4a, 0x69, + 0xb5, 0x7d, 0xb6, 0x90, 0xae, 0x11, 0x36, 0x60, 0x3a, 0xe6, 0xd7, 0xef, + 0xc4, 0x92, 0x21, 0xd6, 0xe3, 0xc7, 0x6b, 0x82, 0x24, 0xa3, 0xc7, 0xc9, + 0x2e, 0x24, 0xa3, 0x03, 0xf2, 0x90, 0x65, 0xdd, 0x18, 0xbf, 0x76, 0x0e, + 0xad, 0xff, 0x82, 0x83, 0xea, 0x3b, 0x07, 0xef, 0xeb, 0xa9, 0x89, 0x13, + 0xe2, 0xda, 0x39, 0x0b, 0x35, 0xdc, 0x4f, 0x34, 0xa7, 0x2a, 0x79, 0xe9, + 0x38, 0xe5, 0xa5, 0x97, 0x73, 0xec, 0x23, 0xf5, 0x06, 0xfb, 0x88, 0x44, + 0xb1, 0x76, 0x7d, 0x3a, 0x84, 0x0b, 0x3a, 0x34, 0x37, 0x62, 0x44, 0x77, + 0xa4, 0xbb, 0x63, 0x0e, 0xf3, 0xb9, 0x28, 0xfe, 0x4f, 0xe5, 0x78, 0xaf, + 0x4d, 0xa0, 0x46, 0x63, 0x1b, 0xb0, 0x73, 0x01, 0xc5, 0xb4, 0x7e, 0xd4, + 0xae, 0x06, 0x2e, 0x0d, 0xf1, 0xfe, 0x8c, 0x86, 0x03, 0xa5, 0x01, 0xd1, + 0x30, 0xf4, 0x5b, 0x2b, 0x54, 0x35, 0xbf, 0x07, 0xf8, 0x30, 0xef, 0x01, + 0x92, 0x0d, 0xf4, 0xdb, 0xe7, 0x7c, 0xde, 0x4c, 0xf3, 0x39, 0x9f, 0x70, + 0x68, 0x13, 0xf9, 0x4e, 0x2f, 0x9a, 0xf5, 0x69, 0xc2, 0xce, 0xb3, 0x44, + 0x67, 0x93, 0xa8, 0xec, 0x73, 0x45, 0xe6, 0xf6, 0xe9, 0x96, 0xe5, 0x3b, + 0x45, 0x4d, 0x81, 0x69, 0x0a, 0x10, 0x4d, 0x1d, 0xa2, 0xfa, 0xd8, 0x06, + 0xe1, 0x3b, 0xd6, 0x25, 0xa4, 0x02, 0xc7, 0xe4, 0x3a, 0x63, 0x4f, 0x8e, + 0xf3, 0xd9, 0x66, 0xe1, 0x3c, 0xba, 0x45, 0x78, 0x0b, 0x3d, 0xc2, 0x7f, + 0xcc, 0xc4, 0xfd, 0xf1, 0x2e, 0x9c, 0x1b, 0xe6, 0xb3, 0x6c, 0xf7, 0x89, + 0x9a, 0xb9, 0xbd, 0x39, 0x6f, 0xa1, 0xd1, 0x5f, 0x48, 0x73, 0x7f, 0xf7, + 0xe3, 0x35, 0xe9, 0xa1, 0x45, 0xfe, 0xa7, 0xc6, 0x02, 0xfe, 0x27, 0xc7, + 0xd4, 0xfe, 0x7d, 0xc2, 0xb2, 0x76, 0xc6, 0xfe, 0x03, 0xeb, 0xd0, 0x6a, + 0x8e, 0x55, 0xf0, 0xc1, 0x6e, 0x92, 0xc7, 0x36, 0xca, 0x2d, 0x93, 0x7a, + 0xf3, 0x1c, 0x16, 0x51, 0x53, 0xfc, 0xee, 0x1b, 0xfd, 0x77, 0x73, 0x6e, + 0xe3, 0x7d, 0x4d, 0x67, 0x3b, 0x28, 0xee, 0x7e, 0xc6, 0x6b, 0xcd, 0x10, + 0x9f, 0x51, 0xeb, 0x87, 0xff, 0x4b, 0xf6, 0xf5, 0xce, 0x7d, 0xb6, 0xaf, + 0x97, 0x78, 0x52, 0xa8, 0xe5, 0x19, 0xe2, 0xb7, 0xca, 0xf1, 0xb9, 0x3d, + 0xbd, 0xb9, 0xfd, 0xbc, 0x4e, 0xe1, 0x2b, 0x70, 0x7d, 0x1e, 0x30, 0x5e, + 0x1f, 0xea, 0x10, 0xde, 0x63, 0xc3, 0x94, 0x1f, 0x37, 0x10, 0xcf, 0x7c, + 0x76, 0xac, 0x4b, 0xf8, 0x0b, 0x9b, 0x85, 0x8f, 0xf8, 0xac, 0x26, 0x3e, + 0x71, 0xcc, 0x23, 0xbc, 0xc4, 0xa3, 0x87, 0x78, 0xf4, 0xce, 0xf1, 0xe8, + 0x29, 0x04, 0xfd, 0xe9, 0x74, 0xbd, 0xff, 0xd1, 0x31, 0xc5, 0xbf, 0x6f, + 0xcc, 0xb2, 0xde, 0xd7, 0x15, 0x3f, 0xf3, 0xf5, 0xaa, 0xfe, 0x45, 0xbe, + 0x6e, 0x20, 0xbe, 0x2a, 0x7b, 0xb1, 0xa4, 0xc3, 0x14, 0xeb, 0x90, 0xcf, + 0x71, 0xcc, 0xf3, 0x75, 0x30, 0xcd, 0xfb, 0x95, 0xbc, 0x6f, 0x39, 0x20, + 0x56, 0x10, 0x5f, 0x65, 0xe2, 0x6b, 0xe5, 0x97, 0xf0, 0xf5, 0xe1, 0x35, + 0x7c, 0xbd, 0xfa, 0xf7, 0xf2, 0xe5, 0x11, 0xcb, 0x87, 0x39, 0x0e, 0xdd, + 0x66, 0xc8, 0xc3, 0x16, 0x61, 0x47, 0x07, 0xbe, 0x3f, 0x05, 0x14, 0xb3, + 0xbb, 0x20, 0x53, 0xbc, 0x39, 0x1d, 0x8f, 0x84, 0x5e, 0xa1, 0x7a, 0x72, + 0xba, 0xe4, 0x15, 0xcb, 0xec, 0x3d, 0x59, 0xac, 0x90, 0x89, 0xa6, 0x19, + 0xfb, 0x5d, 0x33, 0xe8, 0xb5, 0x1a, 0xeb, 0x52, 0x3b, 0xbb, 0x15, 0x91, + 0x72, 0xc4, 0xd1, 0x25, 0x12, 0x05, 0xde, 0x83, 0xdd, 0x22, 0x56, 0xda, + 0xfb, 0xaf, 0x9d, 0xe2, 0xfa, 0x42, 0x87, 0x68, 0x21, 0xbb, 0x68, 0x3e, + 0xc6, 0xe7, 0xc1, 0x36, 0x8b, 0xe6, 0x39, 0x79, 0x2c, 0x27, 0x79, 0x0c, + 0x7d, 0x4e, 0x1e, 0x1b, 0x6c, 0x79, 0xfc, 0x4c, 0xbf, 0x78, 0x4d, 0x0f, + 0x8d, 0xeb, 0x2a, 0xca, 0x86, 0x54, 0x3b, 0xd5, 0xce, 0xd5, 0x4e, 0x6f, + 0xc5, 0xf8, 0x9c, 0x8f, 0x69, 0xd5, 0x68, 0x08, 0x39, 0x0d, 0xb5, 0xe7, + 0xb4, 0xd0, 0x52, 0xf7, 0x89, 0xe4, 0x26, 0x1f, 0xd5, 0x3f, 0x3b, 0x62, + 0x91, 0xe4, 0x72, 0x11, 0x49, 0x38, 0x05, 0xe7, 0x15, 0x5d, 0xae, 0x2a, + 0x9a, 0xd8, 0x47, 0xf1, 0xed, 0xc5, 0x9c, 0x44, 0xd8, 0x81, 0xdf, 0x3f, + 0x73, 0xe2, 0x46, 0x82, 0x12, 0x4f, 0x10, 0xee, 0x78, 0x3c, 0xdb, 0x87, + 0x27, 0xf2, 0xbd, 0x78, 0x3c, 0xff, 0x77, 0xde, 0xb5, 0x91, 0xbd, 0x46, + 0x63, 0xa2, 0x72, 0x16, 0xe1, 0xe3, 0xc4, 0x75, 0x11, 0x96, 0xcd, 0x89, + 0x16, 0x39, 0xc2, 0xb5, 0xae, 0xf3, 0x77, 0xdf, 0xd5, 0xd8, 0x17, 0x7b, + 0x56, 0xbd, 0x64, 0x63, 0x91, 0x93, 0x6d, 0xc7, 0xec, 0x33, 0x52, 0xe5, + 0x95, 0x7b, 0xec, 0x77, 0x41, 0x7d, 0xab, 0xef, 0xd2, 0xd8, 0x1f, 0x4e, + 0xc4, 0xd7, 0xdb, 0xf9, 0xb5, 0x71, 0x6d, 0xe5, 0x3d, 0x99, 0xe0, 0xda, + 0x4a, 0xaf, 0x26, 0xb0, 0x36, 0x6a, 0x7f, 0x86, 0xd6, 0x56, 0xf6, 0xba, + 0xf5, 0xb5, 0x4d, 0xf6, 0x67, 0x74, 0x6d, 0xc5, 0xa7, 0xb4, 0xb5, 0x9a, + 0xfd, 0x19, 0x5f, 0x5b, 0xc9, 0xcb, 0x2d, 0x6b, 0x97, 0x5e, 0x7d, 0xbf, + 0x86, 0xff, 0xfe, 0x17, 0x9f, 0xed, 0x4e, 0xb2, 0x20, 0x3b, 0x00, 0x00, + 0x00 }; static const u32 bnx2_TXP_b09FwData[(0x0/4) + 1] = { 0x0 }; static const u32 bnx2_TXP_b09FwRodata[(0x30/4) + 1] = { @@ -4564,15 +4582,15 @@ static const u32 bnx2_TXP_b09FwRodata[(0x30/4) + 1] = { 0x00000000 }; static struct fw_info bnx2_txp_fw_09 = { - /* Firmware version: 4.0.5 */ + /* Firmware version: 4.4.23 */ .ver_major = 0x4, - .ver_minor = 0x0, - .ver_fix = 0x5, + .ver_minor = 0x4, + .ver_fix = 0x17, .start_addr = 0x08000094, .text_addr = 0x08000000, - .text_len = 0x3a50, + .text_len = 0x3b1c, .text_index = 0x0, .gz_text = bnx2_TXP_b09FwText, .gz_text_len = sizeof(bnx2_TXP_b09FwText), @@ -4582,15 +4600,15 @@ static struct fw_info bnx2_txp_fw_09 = { .data_index = 0x0, .data = bnx2_TXP_b09FwData, - .sbss_addr = 0x08003aa0, + .sbss_addr = 0x08003b80, .sbss_len = 0x6c, .sbss_index = 0x0, - .bss_addr = 0x08003b0c, + .bss_addr = 0x08003bec, .bss_len = 0x24c, .bss_index = 0x0, - .rodata_addr = 0x08003a50, + .rodata_addr = 0x08003b1c, .rodata_len = 0x30, .rodata_index = 0x0, .rodata = bnx2_TXP_b09FwRodata, diff --git a/drivers/net/bnx2x.c b/drivers/net/bnx2x.c deleted file mode 100644 index 70cba64732ca..000000000000 --- a/drivers/net/bnx2x.c +++ /dev/null @@ -1,9988 +0,0 @@ -/* bnx2x.c: Broadcom Everest network driver. - * - * Copyright (c) 2007-2008 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 <eilong@broadcom.com> - * Written by: Eliezer Tamir - * Based on code from Michael Chan's bnx2 driver - * UDP CSUM errata workaround by Arik Gendelman - * Slowpath rework by Vladislav Zolotarov - * Statistics and Link management by Yitchak Gertner - * - */ - -/* define this to make the driver freeze on error - * to allow getting debug info - * (you will need to reboot afterwards) - */ -/*#define BNX2X_STOP_ON_ERROR*/ - -#include <linux/module.h> -#include <linux/moduleparam.h> -#include <linux/kernel.h> -#include <linux/device.h> /* for dev_info() */ -#include <linux/timer.h> -#include <linux/errno.h> -#include <linux/ioport.h> -#include <linux/slab.h> -#include <linux/vmalloc.h> -#include <linux/interrupt.h> -#include <linux/pci.h> -#include <linux/init.h> -#include <linux/netdevice.h> -#include <linux/etherdevice.h> -#include <linux/skbuff.h> -#include <linux/dma-mapping.h> -#include <linux/bitops.h> -#include <linux/irq.h> -#include <linux/delay.h> -#include <asm/byteorder.h> -#include <linux/time.h> -#include <linux/ethtool.h> -#include <linux/mii.h> -#ifdef NETIF_F_HW_VLAN_TX - #include <linux/if_vlan.h> - #define BCM_VLAN 1 -#endif -#include <net/ip.h> -#include <net/tcp.h> -#include <net/checksum.h> -#include <linux/workqueue.h> -#include <linux/crc32.h> -#include <linux/prefetch.h> -#include <linux/zlib.h> -#include <linux/version.h> -#include <linux/io.h> - -#include "bnx2x_reg.h" -#include "bnx2x_fw_defs.h" -#include "bnx2x_hsi.h" -#include "bnx2x.h" -#include "bnx2x_init.h" - -#define DRV_MODULE_VERSION "1.42.4" -#define DRV_MODULE_RELDATE "2008/4/9" -#define BNX2X_BC_VER 0x040200 - -/* Time in jiffies before concluding the transmitter is hung. */ -#define TX_TIMEOUT (5*HZ) - -static char version[] __devinitdata = - "Broadcom NetXtreme II 5771X 10Gigabit Ethernet Driver " - DRV_MODULE_NAME " " DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n"; - -MODULE_AUTHOR("Eliezer Tamir"); -MODULE_DESCRIPTION("Broadcom NetXtreme II BCM57710 Driver"); -MODULE_LICENSE("GPL"); -MODULE_VERSION(DRV_MODULE_VERSION); - -static int use_inta; -static int poll; -static int onefunc; -static int nomcp; -static int debug; -static int use_multi; - -module_param(use_inta, int, 0); -module_param(poll, int, 0); -module_param(onefunc, int, 0); -module_param(debug, int, 0); -MODULE_PARM_DESC(use_inta, "use INT#A instead of MSI-X"); -MODULE_PARM_DESC(poll, "use polling (for debug)"); -MODULE_PARM_DESC(onefunc, "enable only first function"); -MODULE_PARM_DESC(nomcp, "ignore management CPU (Implies onefunc)"); -MODULE_PARM_DESC(debug, "default debug msglevel"); - -#ifdef BNX2X_MULTI -module_param(use_multi, int, 0); -MODULE_PARM_DESC(use_multi, "use per-CPU queues"); -#endif - -enum bnx2x_board_type { - BCM57710 = 0, -}; - -/* indexed by board_t, above */ -static struct { - char *name; -} board_info[] __devinitdata = { - { "Broadcom NetXtreme II BCM57710 XGb" } -}; - -static const struct pci_device_id bnx2x_pci_tbl[] = { - { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_57710, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM57710 }, - { 0 } -}; - -MODULE_DEVICE_TABLE(pci, bnx2x_pci_tbl); - -/**************************************************************************** -* General service functions -****************************************************************************/ - -/* used only at init - * locking is done by mcp - */ -static void bnx2x_reg_wr_ind(struct bnx2x *bp, u32 addr, u32 val) -{ - pci_write_config_dword(bp->pdev, PCICFG_GRC_ADDRESS, addr); - pci_write_config_dword(bp->pdev, PCICFG_GRC_DATA, val); - pci_write_config_dword(bp->pdev, PCICFG_GRC_ADDRESS, - PCICFG_VENDOR_ID_OFFSET); -} - -#ifdef BNX2X_IND_RD -static u32 bnx2x_reg_rd_ind(struct bnx2x *bp, u32 addr) -{ - u32 val; - - pci_write_config_dword(bp->pdev, PCICFG_GRC_ADDRESS, addr); - pci_read_config_dword(bp->pdev, PCICFG_GRC_DATA, &val); - pci_write_config_dword(bp->pdev, PCICFG_GRC_ADDRESS, - PCICFG_VENDOR_ID_OFFSET); - - return val; -} -#endif - -static const u32 dmae_reg_go_c[] = { - DMAE_REG_GO_C0, DMAE_REG_GO_C1, DMAE_REG_GO_C2, DMAE_REG_GO_C3, - DMAE_REG_GO_C4, DMAE_REG_GO_C5, DMAE_REG_GO_C6, DMAE_REG_GO_C7, - DMAE_REG_GO_C8, DMAE_REG_GO_C9, DMAE_REG_GO_C10, DMAE_REG_GO_C11, - DMAE_REG_GO_C12, DMAE_REG_GO_C13, DMAE_REG_GO_C14, DMAE_REG_GO_C15 -}; - -/* copy command into DMAE command memory and set DMAE command go */ -static void bnx2x_post_dmae(struct bnx2x *bp, struct dmae_command *dmae, - int idx) -{ - u32 cmd_offset; - int i; - - cmd_offset = (DMAE_REG_CMD_MEM + sizeof(struct dmae_command) * idx); - for (i = 0; i < (sizeof(struct dmae_command)/4); i++) { - REG_WR(bp, cmd_offset + i*4, *(((u32 *)dmae) + i)); - -/* DP(NETIF_MSG_DMAE, "DMAE cmd[%d].%d (0x%08x) : 0x%08x\n", - idx, i, cmd_offset + i*4, *(((u32 *)dmae) + i)); */ - } - REG_WR(bp, dmae_reg_go_c[idx], 1); -} - -static void bnx2x_write_dmae(struct bnx2x *bp, dma_addr_t dma_addr, - u32 dst_addr, u32 len32) -{ - struct dmae_command *dmae = &bp->dmae; - int port = bp->port; - u32 *wb_comp = bnx2x_sp(bp, wb_comp); - int timeout = 200; - - memset(dmae, 0, sizeof(struct dmae_command)); - - dmae->opcode = (DMAE_CMD_SRC_PCI | DMAE_CMD_DST_GRC | - DMAE_CMD_C_DST_PCI | DMAE_CMD_C_ENABLE | - DMAE_CMD_SRC_RESET | DMAE_CMD_DST_RESET | -#ifdef __BIG_ENDIAN - DMAE_CMD_ENDIANITY_B_DW_SWAP | -#else - DMAE_CMD_ENDIANITY_DW_SWAP | -#endif - (port ? DMAE_CMD_PORT_1 : DMAE_CMD_PORT_0)); - dmae->src_addr_lo = U64_LO(dma_addr); - dmae->src_addr_hi = U64_HI(dma_addr); - dmae->dst_addr_lo = dst_addr >> 2; - dmae->dst_addr_hi = 0; - dmae->len = len32; - dmae->comp_addr_lo = U64_LO(bnx2x_sp_mapping(bp, wb_comp)); - dmae->comp_addr_hi = U64_HI(bnx2x_sp_mapping(bp, wb_comp)); - dmae->comp_val = BNX2X_WB_COMP_VAL; - -/* - DP(NETIF_MSG_DMAE, "dmae: opcode 0x%08x\n" - DP_LEVEL "src_addr [%x:%08x] len [%d *4] " - "dst_addr [%x:%08x (%08x)]\n" - DP_LEVEL "comp_addr [%x:%08x] comp_val 0x%08x\n", - dmae->opcode, dmae->src_addr_hi, dmae->src_addr_lo, - dmae->len, dmae->dst_addr_hi, dmae->dst_addr_lo, dst_addr, - dmae->comp_addr_hi, dmae->comp_addr_lo, dmae->comp_val); -*/ -/* - DP(NETIF_MSG_DMAE, "data [0x%08x 0x%08x 0x%08x 0x%08x]\n", - bp->slowpath->wb_data[0], bp->slowpath->wb_data[1], - bp->slowpath->wb_data[2], bp->slowpath->wb_data[3]); -*/ - - *wb_comp = 0; - - bnx2x_post_dmae(bp, dmae, port * 8); - - udelay(5); - /* adjust timeout for emulation/FPGA */ - if (CHIP_REV_IS_SLOW(bp)) - timeout *= 100; - while (*wb_comp != BNX2X_WB_COMP_VAL) { -/* DP(NETIF_MSG_DMAE, "wb_comp 0x%08x\n", *wb_comp); */ - udelay(5); - if (!timeout) { - BNX2X_ERR("dmae timeout!\n"); - break; - } - timeout--; - } -} - -#ifdef BNX2X_DMAE_RD -static void bnx2x_read_dmae(struct bnx2x *bp, u32 src_addr, u32 len32) -{ - struct dmae_command *dmae = &bp->dmae; - int port = bp->port; - u32 *wb_comp = bnx2x_sp(bp, wb_comp); - int timeout = 200; - - memset(bnx2x_sp(bp, wb_data[0]), 0, sizeof(u32) * 4); - memset(dmae, 0, sizeof(struct dmae_command)); - - dmae->opcode = (DMAE_CMD_SRC_GRC | DMAE_CMD_DST_PCI | - DMAE_CMD_C_DST_PCI | DMAE_CMD_C_ENABLE | - DMAE_CMD_SRC_RESET | DMAE_CMD_DST_RESET | -#ifdef __BIG_ENDIAN - DMAE_CMD_ENDIANITY_B_DW_SWAP | -#else - DMAE_CMD_ENDIANITY_DW_SWAP | -#endif - (port ? DMAE_CMD_PORT_1 : DMAE_CMD_PORT_0)); - dmae->src_addr_lo = src_addr >> 2; - dmae->src_addr_hi = 0; - dmae->dst_addr_lo = U64_LO(bnx2x_sp_mapping(bp, wb_data)); - dmae->dst_addr_hi = U64_HI(bnx2x_sp_mapping(bp, wb_data)); - dmae->len = len32; - dmae->comp_addr_lo = U64_LO(bnx2x_sp_mapping(bp, wb_comp)); - dmae->comp_addr_hi = U64_HI(bnx2x_sp_mapping(bp, wb_comp)); - dmae->comp_val = BNX2X_WB_COMP_VAL; - -/* - DP(NETIF_MSG_DMAE, "dmae: opcode 0x%08x\n" - DP_LEVEL "src_addr [%x:%08x] len [%d *4] " - "dst_addr [%x:%08x (%08x)]\n" - DP_LEVEL "comp_addr [%x:%08x] comp_val 0x%08x\n", - dmae->opcode, dmae->src_addr_hi, dmae->src_addr_lo, - dmae->len, dmae->dst_addr_hi, dmae->dst_addr_lo, src_addr, - dmae->comp_addr_hi, dmae->comp_addr_lo, dmae->comp_val); -*/ - - *wb_comp = 0; - - bnx2x_post_dmae(bp, dmae, port * 8); - - udelay(5); - while (*wb_comp != BNX2X_WB_COMP_VAL) { - udelay(5); - if (!timeout) { - BNX2X_ERR("dmae timeout!\n"); - break; - } - timeout--; - } -/* - DP(NETIF_MSG_DMAE, "data [0x%08x 0x%08x 0x%08x 0x%08x]\n", - bp->slowpath->wb_data[0], bp->slowpath->wb_data[1], - bp->slowpath->wb_data[2], bp->slowpath->wb_data[3]); -*/ -} -#endif - -static int bnx2x_mc_assert(struct bnx2x *bp) -{ - int i, j, rc = 0; - char last_idx; - const char storm[] = {"XTCU"}; - const u32 intmem_base[] = { - BAR_XSTRORM_INTMEM, - BAR_TSTRORM_INTMEM, - BAR_CSTRORM_INTMEM, - BAR_USTRORM_INTMEM - }; - - /* Go through all instances of all SEMIs */ - for (i = 0; i < 4; i++) { - last_idx = REG_RD8(bp, XSTORM_ASSERT_LIST_INDEX_OFFSET + - intmem_base[i]); - if (last_idx) - BNX2X_LOG("DATA %cSTORM_ASSERT_LIST_INDEX 0x%x\n", - storm[i], last_idx); - - /* print the asserts */ - for (j = 0; j < STROM_ASSERT_ARRAY_SIZE; j++) { - u32 row0, row1, row2, row3; - - row0 = REG_RD(bp, XSTORM_ASSERT_LIST_OFFSET(j) + - intmem_base[i]); - row1 = REG_RD(bp, XSTORM_ASSERT_LIST_OFFSET(j) + 4 + - intmem_base[i]); - row2 = REG_RD(bp, XSTORM_ASSERT_LIST_OFFSET(j) + 8 + - intmem_base[i]); - row3 = REG_RD(bp, XSTORM_ASSERT_LIST_OFFSET(j) + 12 + - intmem_base[i]); - - if (row0 != COMMON_ASM_INVALID_ASSERT_OPCODE) { - BNX2X_LOG("DATA %cSTORM_ASSERT_INDEX 0x%x =" - " 0x%08x 0x%08x 0x%08x 0x%08x\n", - storm[i], j, row3, row2, row1, row0); - rc++; - } else { - break; - } - } - } - return rc; -} - -static void bnx2x_fw_dump(struct bnx2x *bp) -{ - u32 mark, offset; - u32 data[9]; - int word; - - mark = REG_RD(bp, MCP_REG_MCPR_SCRATCH + 0xf104); - mark = ((mark + 0x3) & ~0x3); - printk(KERN_ERR PFX "begin fw dump (mark 0x%x)\n" KERN_ERR, mark); - - for (offset = mark - 0x08000000; offset <= 0xF900; offset += 0x8*4) { - for (word = 0; word < 8; word++) - data[word] = htonl(REG_RD(bp, MCP_REG_MCPR_SCRATCH + - offset + 4*word)); - data[8] = 0x0; - printk(KERN_CONT "%s", (char *)data); - } - for (offset = 0xF108; offset <= mark - 0x08000000; offset += 0x8*4) { - for (word = 0; word < 8; word++) - data[word] = htonl(REG_RD(bp, MCP_REG_MCPR_SCRATCH + - offset + 4*word)); - data[8] = 0x0; - printk(KERN_CONT "%s", (char *)data); - } - printk("\n" KERN_ERR PFX "end of fw dump\n"); -} - -static void bnx2x_panic_dump(struct bnx2x *bp) -{ - int i; - u16 j, start, end; - - BNX2X_ERR("begin crash dump -----------------\n"); - - for_each_queue(bp, i) { - struct bnx2x_fastpath *fp = &bp->fp[i]; - struct eth_tx_db_data *hw_prods = fp->hw_tx_prods; - - BNX2X_ERR("queue[%d]: tx_pkt_prod(%x) tx_pkt_cons(%x)" - " tx_bd_prod(%x) tx_bd_cons(%x) *tx_cons_sb(%x)" - " *rx_cons_sb(%x) rx_comp_prod(%x)" - " rx_comp_cons(%x) fp_c_idx(%x) fp_u_idx(%x)" - " bd data(%x,%x)\n", - i, fp->tx_pkt_prod, fp->tx_pkt_cons, fp->tx_bd_prod, - fp->tx_bd_cons, *fp->tx_cons_sb, *fp->rx_cons_sb, - fp->rx_comp_prod, fp->rx_comp_cons, fp->fp_c_idx, - fp->fp_u_idx, hw_prods->packets_prod, - hw_prods->bds_prod); - - start = TX_BD(le16_to_cpu(*fp->tx_cons_sb) - 10); - end = TX_BD(le16_to_cpu(*fp->tx_cons_sb) + 245); - for (j = start; j < end; j++) { - struct sw_tx_bd *sw_bd = &fp->tx_buf_ring[j]; - - BNX2X_ERR("packet[%x]=[%p,%x]\n", j, - sw_bd->skb, sw_bd->first_bd); - } - - start = TX_BD(fp->tx_bd_cons - 10); - end = TX_BD(fp->tx_bd_cons + 254); - for (j = start; j < end; j++) { - u32 *tx_bd = (u32 *)&fp->tx_desc_ring[j]; - - BNX2X_ERR("tx_bd[%x]=[%x:%x:%x:%x]\n", - j, tx_bd[0], tx_bd[1], tx_bd[2], tx_bd[3]); - } - - start = RX_BD(le16_to_cpu(*fp->rx_cons_sb) - 10); - end = RX_BD(le16_to_cpu(*fp->rx_cons_sb) + 503); - for (j = start; j < end; j++) { - u32 *rx_bd = (u32 *)&fp->rx_desc_ring[j]; - struct sw_rx_bd *sw_bd = &fp->rx_buf_ring[j]; - - BNX2X_ERR("rx_bd[%x]=[%x:%x] sw_bd=[%p]\n", - j, rx_bd[0], rx_bd[1], sw_bd->skb); - } - - start = RCQ_BD(fp->rx_comp_cons - 10); - end = RCQ_BD(fp->rx_comp_cons + 503); - for (j = start; j < end; j++) { - u32 *cqe = (u32 *)&fp->rx_comp_ring[j]; - - BNX2X_ERR("cqe[%x]=[%x:%x:%x:%x]\n", - j, cqe[0], cqe[1], cqe[2], cqe[3]); - } - } - - BNX2X_ERR("def_c_idx(%u) def_u_idx(%u) def_x_idx(%u)" - " def_t_idx(%u) def_att_idx(%u) attn_state(%u)" - " spq_prod_idx(%u)\n", - bp->def_c_idx, bp->def_u_idx, bp->def_x_idx, bp->def_t_idx, - bp->def_att_idx, bp->attn_state, bp->spq_prod_idx); - - - bnx2x_mc_assert(bp); - BNX2X_ERR("end crash dump -----------------\n"); - - bp->stats_state = STATS_STATE_DISABLE; - DP(BNX2X_MSG_STATS, "stats_state - DISABLE\n"); -} - -static void bnx2x_int_enable(struct bnx2x *bp) -{ - int port = bp->port; - u32 addr = port ? HC_REG_CONFIG_1 : HC_REG_CONFIG_0; - u32 val = REG_RD(bp, addr); - int msix = (bp->flags & USING_MSIX_FLAG) ? 1 : 0; - - if (msix) { - val &= ~HC_CONFIG_0_REG_SINGLE_ISR_EN_0; - val |= (HC_CONFIG_0_REG_MSI_MSIX_INT_EN_0 | - HC_CONFIG_0_REG_ATTN_BIT_EN_0); - } else { - val |= (HC_CONFIG_0_REG_SINGLE_ISR_EN_0 | - HC_CONFIG_0_REG_MSI_MSIX_INT_EN_0 | - HC_CONFIG_0_REG_INT_LINE_EN_0 | - HC_CONFIG_0_REG_ATTN_BIT_EN_0); - - /* Errata A0.158 workaround */ - DP(NETIF_MSG_INTR, "write %x to HC %d (addr 0x%x) MSI-X %d\n", - val, port, addr, msix); - - REG_WR(bp, addr, val); - - val &= ~HC_CONFIG_0_REG_MSI_MSIX_INT_EN_0; - } - - DP(NETIF_MSG_INTR, "write %x to HC %d (addr 0x%x) MSI-X %d\n", - val, port, addr, msix); - - REG_WR(bp, addr, val); -} - -static void bnx2x_int_disable(struct bnx2x *bp) -{ - int port = bp->port; - u32 addr = port ? HC_REG_CONFIG_1 : HC_REG_CONFIG_0; - u32 val = REG_RD(bp, addr); - - val &= ~(HC_CONFIG_0_REG_SINGLE_ISR_EN_0 | - HC_CONFIG_0_REG_MSI_MSIX_INT_EN_0 | - HC_CONFIG_0_REG_INT_LINE_EN_0 | - HC_CONFIG_0_REG_ATTN_BIT_EN_0); - - DP(NETIF_MSG_INTR, "write %x to HC %d (addr 0x%x)\n", - val, port, addr); - - REG_WR(bp, addr, val); - if (REG_RD(bp, addr) != val) - BNX2X_ERR("BUG! proper val not read from IGU!\n"); -} - -static void bnx2x_int_disable_sync(struct bnx2x *bp) -{ - - int msix = (bp->flags & USING_MSIX_FLAG) ? 1 : 0; - int i; - - atomic_inc(&bp->intr_sem); - /* prevent the HW from sending interrupts */ - bnx2x_int_disable(bp); - - /* make sure all ISRs are done */ - if (msix) { - for_each_queue(bp, i) - synchronize_irq(bp->msix_table[i].vector); - - /* one more for the Slow Path IRQ */ - synchronize_irq(bp->msix_table[i].vector); - } else - synchronize_irq(bp->pdev->irq); - - /* make sure sp_task is not running */ - cancel_work_sync(&bp->sp_task); - -} - -/* fast path code */ - -/* - * general service functions - */ - -static inline void bnx2x_ack_sb(struct bnx2x *bp, u8 id, - u8 storm, u16 index, u8 op, u8 update) -{ - u32 igu_addr = (IGU_ADDR_INT_ACK + IGU_PORT_BASE * bp->port) * 8; - struct igu_ack_register igu_ack; - - igu_ack.status_block_index = index; - igu_ack.sb_id_and_flags = - ((id << IGU_ACK_REGISTER_STATUS_BLOCK_ID_SHIFT) | - (storm << IGU_ACK_REGISTER_STORM_ID_SHIFT) | - (update << IGU_ACK_REGISTER_UPDATE_INDEX_SHIFT) | - (op << IGU_ACK_REGISTER_INTERRUPT_MODE_SHIFT)); - -/* DP(NETIF_MSG_INTR, "write 0x%08x to IGU addr 0x%x\n", - (*(u32 *)&igu_ack), BAR_IGU_INTMEM + igu_addr); */ - REG_WR(bp, BAR_IGU_INTMEM + igu_addr, (*(u32 *)&igu_ack)); -} - -static inline u16 bnx2x_update_fpsb_idx(struct bnx2x_fastpath *fp) -{ - struct host_status_block *fpsb = fp->status_blk; - u16 rc = 0; - - barrier(); /* status block is written to by the chip */ - if (fp->fp_c_idx != fpsb->c_status_block.status_block_index) { - fp->fp_c_idx = fpsb->c_status_block.status_block_index; - rc |= 1; - } - if (fp->fp_u_idx != fpsb->u_status_block.status_block_index) { - fp->fp_u_idx = fpsb->u_status_block.status_block_index; - rc |= 2; - } - return rc; -} - -static inline int bnx2x_has_work(struct bnx2x_fastpath *fp) -{ - u16 rx_cons_sb = le16_to_cpu(*fp->rx_cons_sb); - - if ((rx_cons_sb & MAX_RCQ_DESC_CNT) == MAX_RCQ_DESC_CNT) - rx_cons_sb++; - - if ((rx_cons_sb != fp->rx_comp_cons) || - (le16_to_cpu(*fp->tx_cons_sb) != fp->tx_pkt_cons)) - return 1; - - return 0; -} - -static u16 bnx2x_ack_int(struct bnx2x *bp) -{ - u32 igu_addr = (IGU_ADDR_SIMD_MASK + IGU_PORT_BASE * bp->port) * 8; - u32 result = REG_RD(bp, BAR_IGU_INTMEM + igu_addr); - -/* DP(NETIF_MSG_INTR, "read 0x%08x from IGU addr 0x%x\n", - result, BAR_IGU_INTMEM + igu_addr); */ - -#ifdef IGU_DEBUG -#warning IGU_DEBUG active - if (result == 0) { - BNX2X_ERR("read %x from IGU\n", result); - REG_WR(bp, TM_REG_TIMER_SOFT_RST, 0); - } -#endif - return result; -} - - -/* - * fast path service functions - */ - -/* free skb in the packet ring at pos idx - * return idx of last bd freed - */ -static u16 bnx2x_free_tx_pkt(struct bnx2x *bp, struct bnx2x_fastpath *fp, - u16 idx) -{ - struct sw_tx_bd *tx_buf = &fp->tx_buf_ring[idx]; - struct eth_tx_bd *tx_bd; - struct sk_buff *skb = tx_buf->skb; - u16 bd_idx = tx_buf->first_bd; - int nbd; - - DP(BNX2X_MSG_OFF, "pkt_idx %d buff @(%p)->skb %p\n", - idx, tx_buf, skb); - - /* unmap first bd */ - DP(BNX2X_MSG_OFF, "free bd_idx %d\n", bd_idx); - tx_bd = &fp->tx_desc_ring[bd_idx]; - pci_unmap_single(bp->pdev, BD_UNMAP_ADDR(tx_bd), - BD_UNMAP_LEN(tx_bd), PCI_DMA_TODEVICE); - - nbd = le16_to_cpu(tx_bd->nbd) - 1; -#ifdef BNX2X_STOP_ON_ERROR - if (nbd > (MAX_SKB_FRAGS + 2)) { - BNX2X_ERR("bad nbd!\n"); - bnx2x_panic(); - } -#endif - - /* Skip a parse bd and the TSO split header bd - since they have no mapping */ - if (nbd) - bd_idx = TX_BD(NEXT_TX_IDX(bd_idx)); - - if (tx_bd->bd_flags.as_bitfield & (ETH_TX_BD_FLAGS_IP_CSUM | - ETH_TX_BD_FLAGS_TCP_CSUM | - ETH_TX_BD_FLAGS_SW_LSO)) { - if (--nbd) - bd_idx = TX_BD(NEXT_TX_IDX(bd_idx)); - tx_bd = &fp->tx_desc_ring[bd_idx]; - /* is this a TSO split header bd? */ - if (tx_bd->bd_flags.as_bitfield & ETH_TX_BD_FLAGS_SW_LSO) { - if (--nbd) - bd_idx = TX_BD(NEXT_TX_IDX(bd_idx)); - } - } - - /* now free frags */ - while (nbd > 0) { - - DP(BNX2X_MSG_OFF, "free frag bd_idx %d\n", bd_idx); - tx_bd = &fp->tx_desc_ring[bd_idx]; - pci_unmap_page(bp->pdev, BD_UNMAP_ADDR(tx_bd), - BD_UNMAP_LEN(tx_bd), PCI_DMA_TODEVICE); - if (--nbd) - bd_idx = TX_BD(NEXT_TX_IDX(bd_idx)); - } - - /* release skb */ - BUG_TRAP(skb); - dev_kfree_skb(skb); - tx_buf->first_bd = 0; - tx_buf->skb = NULL; - - return bd_idx; -} - -static inline u32 bnx2x_tx_avail(struct bnx2x_fastpath *fp) -{ - u16 used; - u32 prod; - u32 cons; - - /* Tell compiler that prod and cons can change */ - barrier(); - prod = fp->tx_bd_prod; - cons = fp->tx_bd_cons; - - used = (NUM_TX_BD - NUM_TX_RINGS + prod - cons + - (cons / TX_DESC_CNT) - (prod / TX_DESC_CNT)); - - if (prod >= cons) { - /* used = prod - cons - prod/size + cons/size */ - used -= NUM_TX_BD - NUM_TX_RINGS; - } - - BUG_TRAP(used <= fp->bp->tx_ring_size); - BUG_TRAP((fp->bp->tx_ring_size - used) <= MAX_TX_AVAIL); - - return (fp->bp->tx_ring_size - used); -} - -static void bnx2x_tx_int(struct bnx2x_fastpath *fp, int work) -{ - struct bnx2x *bp = fp->bp; - u16 hw_cons, sw_cons, bd_cons = fp->tx_bd_cons; - int done = 0; - -#ifdef BNX2X_STOP_ON_ERROR - if (unlikely(bp->panic)) - return; -#endif - - hw_cons = le16_to_cpu(*fp->tx_cons_sb); - sw_cons = fp->tx_pkt_cons; - - while (sw_cons != hw_cons) { - u16 pkt_cons; - - pkt_cons = TX_BD(sw_cons); - - /* prefetch(bp->tx_buf_ring[pkt_cons].skb); */ - - DP(NETIF_MSG_TX_DONE, "hw_cons %u sw_cons %u pkt_cons %d\n", - hw_cons, sw_cons, pkt_cons); - -/* if (NEXT_TX_IDX(sw_cons) != hw_cons) { - rmb(); - prefetch(fp->tx_buf_ring[NEXT_TX_IDX(sw_cons)].skb); - } -*/ - bd_cons = bnx2x_free_tx_pkt(bp, fp, pkt_cons); - sw_cons++; - done++; - - if (done == work) - break; - } - - fp->tx_pkt_cons = sw_cons; - fp->tx_bd_cons = bd_cons; - - /* Need to make the tx_cons update visible to start_xmit() - * before checking for netif_queue_stopped(). Without the - * memory barrier, there is a small possibility that start_xmit() - * will miss it and cause the queue to be stopped forever. - */ - smp_mb(); - - /* TBD need a thresh? */ - if (unlikely(netif_queue_stopped(bp->dev))) { - - netif_tx_lock(bp->dev); - - if (netif_queue_stopped(bp->dev) && - (bnx2x_tx_avail(fp) >= MAX_SKB_FRAGS + 3)) - netif_wake_queue(bp->dev); - - netif_tx_unlock(bp->dev); - - } -} - -static void bnx2x_sp_event(struct bnx2x_fastpath *fp, - union eth_rx_cqe *rr_cqe) -{ - struct bnx2x *bp = fp->bp; - int cid = SW_CID(rr_cqe->ramrod_cqe.conn_and_cmd_data); - int command = CQE_CMD(rr_cqe->ramrod_cqe.conn_and_cmd_data); - - DP(NETIF_MSG_RX_STATUS, - "fp %d cid %d got ramrod #%d state is %x type is %d\n", - fp->index, cid, command, bp->state, rr_cqe->ramrod_cqe.type); - - bp->spq_left++; - - if (fp->index) { - switch (command | fp->state) { - case (RAMROD_CMD_ID_ETH_CLIENT_SETUP | - BNX2X_FP_STATE_OPENING): - DP(NETIF_MSG_IFUP, "got MULTI[%d] setup ramrod\n", - cid); - fp->state = BNX2X_FP_STATE_OPEN; - break; - - case (RAMROD_CMD_ID_ETH_HALT | BNX2X_FP_STATE_HALTING): - DP(NETIF_MSG_IFDOWN, "got MULTI[%d] halt ramrod\n", - cid); - fp->state = BNX2X_FP_STATE_HALTED; - break; - - default: - BNX2X_ERR("unexpected MC reply(%d) state is %x\n", - command, fp->state); - } - mb(); /* force bnx2x_wait_ramrod to see the change */ - return; - } - - switch (command | bp->state) { - case (RAMROD_CMD_ID_ETH_PORT_SETUP | BNX2X_STATE_OPENING_WAIT4_PORT): - DP(NETIF_MSG_IFUP, "got setup ramrod\n"); - bp->state = BNX2X_STATE_OPEN; - break; - - case (RAMROD_CMD_ID_ETH_HALT | BNX2X_STATE_CLOSING_WAIT4_HALT): - DP(NETIF_MSG_IFDOWN, "got halt ramrod\n"); - bp->state = BNX2X_STATE_CLOSING_WAIT4_DELETE; - fp->state = BNX2X_FP_STATE_HALTED; - break; - - case (RAMROD_CMD_ID_ETH_CFC_DEL | BNX2X_STATE_CLOSING_WAIT4_HALT): - DP(NETIF_MSG_IFDOWN, "got delete ramrod for MULTI[%d]\n", - cid); - bnx2x_fp(bp, cid, state) = BNX2X_FP_STATE_CLOSED; - break; - - case (RAMROD_CMD_ID_ETH_SET_MAC | BNX2X_STATE_OPEN): - DP(NETIF_MSG_IFUP, "got set mac ramrod\n"); - break; - - case (RAMROD_CMD_ID_ETH_SET_MAC | BNX2X_STATE_CLOSING_WAIT4_HALT): - DP(NETIF_MSG_IFUP, "got (un)set mac ramrod\n"); - break; - - default: - BNX2X_ERR("unexpected ramrod (%d) state is %x\n", - command, bp->state); - } - - mb(); /* force bnx2x_wait_ramrod to see the change */ -} - -static inline int bnx2x_alloc_rx_skb(struct bnx2x *bp, - struct bnx2x_fastpath *fp, u16 index) -{ - struct sk_buff *skb; - struct sw_rx_bd *rx_buf = &fp->rx_buf_ring[index]; - struct eth_rx_bd *rx_bd = &fp->rx_desc_ring[index]; - dma_addr_t mapping; - - skb = netdev_alloc_skb(bp->dev, bp->rx_buf_size); - if (unlikely(skb == NULL)) - return -ENOMEM; - - mapping = pci_map_single(bp->pdev, skb->data, bp->rx_buf_use_size, - PCI_DMA_FROMDEVICE); - if (unlikely(dma_mapping_error(mapping))) { - - dev_kfree_skb(skb); - return -ENOMEM; - } - - rx_buf->skb = skb; - pci_unmap_addr_set(rx_buf, mapping, mapping); - - rx_bd->addr_hi = cpu_to_le32(U64_HI(mapping)); - rx_bd->addr_lo = cpu_to_le32(U64_LO(mapping)); - - return 0; -} - -/* note that we are not allocating a new skb, - * we are just moving one from cons to prod - * we are not creating a new mapping, - * so there is no need to check for dma_mapping_error(). - */ -static void bnx2x_reuse_rx_skb(struct bnx2x_fastpath *fp, - struct sk_buff *skb, u16 cons, u16 prod) -{ - struct bnx2x *bp = fp->bp; - struct sw_rx_bd *cons_rx_buf = &fp->rx_buf_ring[cons]; - struct sw_rx_bd *prod_rx_buf = &fp->rx_buf_ring[prod]; - struct eth_rx_bd *cons_bd = &fp->rx_desc_ring[cons]; - struct eth_rx_bd *prod_bd = &fp->rx_desc_ring[prod]; - - pci_dma_sync_single_for_device(bp->pdev, - pci_unmap_addr(cons_rx_buf, mapping), - bp->rx_offset + RX_COPY_THRESH, - PCI_DMA_FROMDEVICE); - - prod_rx_buf->skb = cons_rx_buf->skb; - pci_unmap_addr_set(prod_rx_buf, mapping, - pci_unmap_addr(cons_rx_buf, mapping)); - *prod_bd = *cons_bd; -} - -static int bnx2x_rx_int(struct bnx2x_fastpath *fp, int budget) -{ - struct bnx2x *bp = fp->bp; - u16 bd_cons, bd_prod, comp_ring_cons; - u16 hw_comp_cons, sw_comp_cons, sw_comp_prod; - int rx_pkt = 0; - -#ifdef BNX2X_STOP_ON_ERROR - if (unlikely(bp->panic)) - return 0; -#endif - - hw_comp_cons = le16_to_cpu(*fp->rx_cons_sb); - if ((hw_comp_cons & MAX_RCQ_DESC_CNT) == MAX_RCQ_DESC_CNT) - hw_comp_cons++; - - bd_cons = fp->rx_bd_cons; - bd_prod = fp->rx_bd_prod; - sw_comp_cons = fp->rx_comp_cons; - sw_comp_prod = fp->rx_comp_prod; - - /* Memory barrier necessary as speculative reads of the rx - * buffer can be ahead of the index in the status block - */ - rmb(); - - DP(NETIF_MSG_RX_STATUS, - "queue[%d]: hw_comp_cons %u sw_comp_cons %u\n", - fp->index, hw_comp_cons, sw_comp_cons); - - while (sw_comp_cons != hw_comp_cons) { - unsigned int len, pad; - struct sw_rx_bd *rx_buf; - struct sk_buff *skb; - union eth_rx_cqe *cqe; - - comp_ring_cons = RCQ_BD(sw_comp_cons); - bd_prod = RX_BD(bd_prod); - bd_cons = RX_BD(bd_cons); - - cqe = &fp->rx_comp_ring[comp_ring_cons]; - - DP(NETIF_MSG_RX_STATUS, "hw_comp_cons %u sw_comp_cons %u" - " comp_ring (%u) bd_ring (%u,%u)\n", - hw_comp_cons, sw_comp_cons, - comp_ring_cons, bd_prod, bd_cons); - DP(NETIF_MSG_RX_STATUS, "CQE type %x err %x status %x" - " queue %x vlan %x len %x\n", - cqe->fast_path_cqe.type, - cqe->fast_path_cqe.error_type_flags, - cqe->fast_path_cqe.status_flags, - cqe->fast_path_cqe.rss_hash_result, - cqe->fast_path_cqe.vlan_tag, cqe->fast_path_cqe.pkt_len); - - /* is this a slowpath msg? */ - if (unlikely(cqe->fast_path_cqe.type)) { - bnx2x_sp_event(fp, cqe); - goto next_cqe; - - /* this is an rx packet */ - } else { - rx_buf = &fp->rx_buf_ring[bd_cons]; - skb = rx_buf->skb; - - len = le16_to_cpu(cqe->fast_path_cqe.pkt_len); - pad = cqe->fast_path_cqe.placement_offset; - - pci_dma_sync_single_for_device(bp->pdev, - pci_unmap_addr(rx_buf, mapping), - pad + RX_COPY_THRESH, - PCI_DMA_FROMDEVICE); - prefetch(skb); - prefetch(((char *)(skb)) + 128); - - /* is this an error packet? */ - if (unlikely(cqe->fast_path_cqe.error_type_flags & - ETH_RX_ERROR_FALGS)) { - /* do we sometimes forward error packets anyway? */ - DP(NETIF_MSG_RX_ERR, - "ERROR flags(%u) Rx packet(%u)\n", - cqe->fast_path_cqe.error_type_flags, - sw_comp_cons); - /* TBD make sure MC counts this as a drop */ - goto reuse_rx; - } - - /* Since we don't have a jumbo ring - * copy small packets if mtu > 1500 - */ - if ((bp->dev->mtu > ETH_MAX_PACKET_SIZE) && - (len <= RX_COPY_THRESH)) { - struct sk_buff *new_skb; - - new_skb = netdev_alloc_skb(bp->dev, - len + pad); - if (new_skb == NULL) { - DP(NETIF_MSG_RX_ERR, - "ERROR packet dropped " - "because of alloc failure\n"); - /* TBD count this as a drop? */ - goto reuse_rx; - } - - /* aligned copy */ - skb_copy_from_linear_data_offset(skb, pad, - new_skb->data + pad, len); - skb_reserve(new_skb, pad); - skb_put(new_skb, len); - - bnx2x_reuse_rx_skb(fp, skb, bd_cons, bd_prod); - - skb = new_skb; - - } else if (bnx2x_alloc_rx_skb(bp, fp, bd_prod) == 0) { - pci_unmap_single(bp->pdev, - pci_unmap_addr(rx_buf, mapping), - bp->rx_buf_use_size, - PCI_DMA_FROMDEVICE); - skb_reserve(skb, pad); - skb_put(skb, len); - - } else { - DP(NETIF_MSG_RX_ERR, - "ERROR packet dropped because " - "of alloc failure\n"); -reuse_rx: - bnx2x_reuse_rx_skb(fp, skb, bd_cons, bd_prod); - goto next_rx; - } - - skb->protocol = eth_type_trans(skb, bp->dev); - - skb->ip_summed = CHECKSUM_NONE; - if (bp->rx_csum && BNX2X_RX_SUM_OK(cqe)) - skb->ip_summed = CHECKSUM_UNNECESSARY; - - /* TBD do we pass bad csum packets in promisc */ - } - -#ifdef BCM_VLAN - if ((le16_to_cpu(cqe->fast_path_cqe.pars_flags.flags) - & PARSING_FLAGS_NUMBER_OF_NESTED_VLANS) - && (bp->vlgrp != NULL)) - vlan_hwaccel_receive_skb(skb, bp->vlgrp, - le16_to_cpu(cqe->fast_path_cqe.vlan_tag)); - else -#endif - netif_receive_skb(skb); - - bp->dev->last_rx = jiffies; - -next_rx: - rx_buf->skb = NULL; - - bd_cons = NEXT_RX_IDX(bd_cons); - bd_prod = NEXT_RX_IDX(bd_prod); -next_cqe: - sw_comp_prod = NEXT_RCQ_IDX(sw_comp_prod); - sw_comp_cons = NEXT_RCQ_IDX(sw_comp_cons); - rx_pkt++; - - if ((rx_pkt == budget)) - break; - } /* while */ - - fp->rx_bd_cons = bd_cons; - fp->rx_bd_prod = bd_prod; - fp->rx_comp_cons = sw_comp_cons; - fp->rx_comp_prod = sw_comp_prod; - - REG_WR(bp, BAR_TSTRORM_INTMEM + - TSTORM_RCQ_PROD_OFFSET(bp->port, fp->index), sw_comp_prod); - - mmiowb(); /* keep prod updates ordered */ - - fp->rx_pkt += rx_pkt; - fp->rx_calls++; - - return rx_pkt; -} - -static irqreturn_t bnx2x_msix_fp_int(int irq, void *fp_cookie) -{ - struct bnx2x_fastpath *fp = fp_cookie; - struct bnx2x *bp = fp->bp; - struct net_device *dev = bp->dev; - int index = fp->index; - - DP(NETIF_MSG_INTR, "got an msix interrupt on [%d]\n", index); - bnx2x_ack_sb(bp, index, USTORM_ID, 0, IGU_INT_DISABLE, 0); - -#ifdef BNX2X_STOP_ON_ERROR - if (unlikely(bp->panic)) - return IRQ_HANDLED; -#endif - - prefetch(fp->rx_cons_sb); - prefetch(fp->tx_cons_sb); - prefetch(&fp->status_blk->c_status_block.status_block_index); - prefetch(&fp->status_blk->u_status_block.status_block_index); - - netif_rx_schedule(dev, &bnx2x_fp(bp, index, napi)); - return IRQ_HANDLED; -} - -static irqreturn_t bnx2x_interrupt(int irq, void *dev_instance) -{ - struct net_device *dev = dev_instance; - struct bnx2x *bp = netdev_priv(dev); - u16 status = bnx2x_ack_int(bp); - - if (unlikely(status == 0)) { - DP(NETIF_MSG_INTR, "not our interrupt!\n"); - return IRQ_NONE; - } - - DP(NETIF_MSG_INTR, "got an interrupt status is %u\n", status); - -#ifdef BNX2X_STOP_ON_ERROR - if (unlikely(bp->panic)) - return IRQ_HANDLED; -#endif - - /* Return here if interrupt is shared and is disabled */ - if (unlikely(atomic_read(&bp->intr_sem) != 0)) { - DP(NETIF_MSG_INTR, "called but intr_sem not 0, returning\n"); - return IRQ_HANDLED; - } - - if (status & 0x2) { - struct bnx2x_fastpath *fp = &bp->fp[0]; - - prefetch(fp->rx_cons_sb); - prefetch(fp->tx_cons_sb); - prefetch(&fp->status_blk->c_status_block.status_block_index); - prefetch(&fp->status_blk->u_status_block.status_block_index); - - netif_rx_schedule(dev, &bnx2x_fp(bp, 0, napi)); - - status &= ~0x2; - if (!status) - return IRQ_HANDLED; - } - - if (unlikely(status & 0x1)) { - - schedule_work(&bp->sp_task); - - status &= ~0x1; - if (!status) - return IRQ_HANDLED; - } - - DP(NETIF_MSG_INTR, "got an unknown interrupt! (status is %u)\n", - status); - - return IRQ_HANDLED; -} - -/* end of fast path */ - -/* PHY/MAC */ - -/* - * General service functions - */ - -static void bnx2x_leds_set(struct bnx2x *bp, unsigned int speed) -{ - int port = bp->port; - - NIG_WR(NIG_REG_LED_MODE_P0 + port*4, - ((bp->hw_config & SHARED_HW_CFG_LED_MODE_MASK) >> - SHARED_HW_CFG_LED_MODE_SHIFT)); - NIG_WR(NIG_REG_LED_CONTROL_OVERRIDE_TRAFFIC_P0 + port*4, 0); - - /* Set blinking rate to ~15.9Hz */ - NIG_WR(NIG_REG_LED_CONTROL_BLINK_RATE_P0 + port*4, - LED_BLINK_RATE_VAL); - NIG_WR(NIG_REG_LED_CONTROL_BLINK_RATE_ENA_P0 + port*4, 1); - - /* On Ax chip versions for speeds less than 10G - LED scheme is different */ - if ((CHIP_REV(bp) == CHIP_REV_Ax) && (speed < SPEED_10000)) { - NIG_WR(NIG_REG_LED_CONTROL_OVERRIDE_TRAFFIC_P0 + port*4, 1); - NIG_WR(NIG_REG_LED_CONTROL_TRAFFIC_P0 + port*4, 0); - NIG_WR(NIG_REG_LED_CONTROL_BLINK_TRAFFIC_P0 + port*4, 1); - } -} - -static void bnx2x_leds_unset(struct bnx2x *bp) -{ - int port = bp->port; - - NIG_WR(NIG_REG_LED_10G_P0 + port*4, 0); - NIG_WR(NIG_REG_LED_MODE_P0 + port*4, SHARED_HW_CFG_LED_MAC1); -} - -static u32 bnx2x_bits_en(struct bnx2x *bp, u32 reg, u32 bits) -{ - u32 val = REG_RD(bp, reg); - - val |= bits; - REG_WR(bp, reg, val); - return val; -} - -static u32 bnx2x_bits_dis(struct bnx2x *bp, u32 reg, u32 bits) -{ - u32 val = REG_RD(bp, reg); - - val &= ~bits; - REG_WR(bp, reg, val); - return val; -} - -static int bnx2x_hw_lock(struct bnx2x *bp, u32 resource) -{ - u32 cnt; - u32 lock_status; - u32 resource_bit = (1 << resource); - u8 func = bp->port; - - /* Validating that the resource is within range */ - if (resource > HW_LOCK_MAX_RESOURCE_VALUE) { - DP(NETIF_MSG_HW, - "resource(0x%x) > HW_LOCK_MAX_RESOURCE_VALUE(0x%x)\n", - resource, HW_LOCK_MAX_RESOURCE_VALUE); - return -EINVAL; - } - - /* Validating that the resource is not already taken */ - lock_status = REG_RD(bp, MISC_REG_DRIVER_CONTROL_1 + func*8); - if (lock_status & resource_bit) { - DP(NETIF_MSG_HW, "lock_status 0x%x resource_bit 0x%x\n", - lock_status, resource_bit); - return -EEXIST; - } - - /* Try for 1 second every 5ms */ - for (cnt = 0; cnt < 200; cnt++) { - /* Try to acquire the lock */ - REG_WR(bp, MISC_REG_DRIVER_CONTROL_1 + func*8 + 4, - resource_bit); - lock_status = REG_RD(bp, MISC_REG_DRIVER_CONTROL_1 + func*8); - if (lock_status & resource_bit) - return 0; - - msleep(5); - } - DP(NETIF_MSG_HW, "Timeout\n"); - return -EAGAIN; -} - -static int bnx2x_hw_unlock(struct bnx2x *bp, u32 resource) -{ - u32 lock_status; - u32 resource_bit = (1 << resource); - u8 func = bp->port; - - /* Validating that the resource is within range */ - if (resource > HW_LOCK_MAX_RESOURCE_VALUE) { - DP(NETIF_MSG_HW, - "resource(0x%x) > HW_LOCK_MAX_RESOURCE_VALUE(0x%x)\n", - resource, HW_LOCK_MAX_RESOURCE_VALUE); - return -EINVAL; - } - - /* Validating that the resource is currently taken */ - lock_status = REG_RD(bp, MISC_REG_DRIVER_CONTROL_1 + func*8); - if (!(lock_status & resource_bit)) { - DP(NETIF_MSG_HW, "lock_status 0x%x resource_bit 0x%x\n", - lock_status, resource_bit); - return -EFAULT; - } - - REG_WR(bp, MISC_REG_DRIVER_CONTROL_1 + func*8, resource_bit); - return 0; -} - -static int bnx2x_set_gpio(struct bnx2x *bp, int gpio_num, u32 mode) -{ - /* The GPIO should be swapped if swap register is set and active */ - int gpio_port = (REG_RD(bp, NIG_REG_PORT_SWAP) && - REG_RD(bp, NIG_REG_STRAP_OVERRIDE)) ^ bp->port; - int gpio_shift = gpio_num + - (gpio_port ? MISC_REGISTERS_GPIO_PORT_SHIFT : 0); - u32 gpio_mask = (1 << gpio_shift); - u32 gpio_reg; - - if (gpio_num > MISC_REGISTERS_GPIO_3) { - BNX2X_ERR("Invalid GPIO %d\n", gpio_num); - return -EINVAL; - } - - bnx2x_hw_lock(bp, HW_LOCK_RESOURCE_GPIO); - /* read GPIO and mask except the float bits */ - gpio_reg = (REG_RD(bp, MISC_REG_GPIO) & MISC_REGISTERS_GPIO_FLOAT); - - switch (mode) { - case MISC_REGISTERS_GPIO_OUTPUT_LOW: - DP(NETIF_MSG_LINK, "Set GPIO %d (shift %d) -> output low\n", - gpio_num, gpio_shift); - /* clear FLOAT and set CLR */ - gpio_reg &= ~(gpio_mask << MISC_REGISTERS_GPIO_FLOAT_POS); - gpio_reg |= (gpio_mask << MISC_REGISTERS_GPIO_CLR_POS); - break; - - case MISC_REGISTERS_GPIO_OUTPUT_HIGH: - DP(NETIF_MSG_LINK, "Set GPIO %d (shift %d) -> output high\n", - gpio_num, gpio_shift); - /* clear FLOAT and set SET */ - gpio_reg &= ~(gpio_mask << MISC_REGISTERS_GPIO_FLOAT_POS); - gpio_reg |= (gpio_mask << MISC_REGISTERS_GPIO_SET_POS); - break; - - case MISC_REGISTERS_GPIO_INPUT_HI_Z : - DP(NETIF_MSG_LINK, "Set GPIO %d (shift %d) -> input\n", - gpio_num, gpio_shift); - /* set FLOAT */ - gpio_reg |= (gpio_mask << MISC_REGISTERS_GPIO_FLOAT_POS); - break; - - default: - break; - } - - REG_WR(bp, MISC_REG_GPIO, gpio_reg); - bnx2x_hw_unlock(bp, HW_LOCK_RESOURCE_GPIO); - - return 0; -} - -static int bnx2x_set_spio(struct bnx2x *bp, int spio_num, u32 mode) -{ - u32 spio_mask = (1 << spio_num); - u32 spio_reg; - - if ((spio_num < MISC_REGISTERS_SPIO_4) || - (spio_num > MISC_REGISTERS_SPIO_7)) { - BNX2X_ERR("Invalid SPIO %d\n", spio_num); - return -EINVAL; - } - - bnx2x_hw_lock(bp, HW_LOCK_RESOURCE_SPIO); - /* read SPIO and mask except the float bits */ - spio_reg = (REG_RD(bp, MISC_REG_SPIO) & MISC_REGISTERS_SPIO_FLOAT); - - switch (mode) { - case MISC_REGISTERS_SPIO_OUTPUT_LOW : - DP(NETIF_MSG_LINK, "Set SPIO %d -> output low\n", spio_num); - /* clear FLOAT and set CLR */ - spio_reg &= ~(spio_mask << MISC_REGISTERS_SPIO_FLOAT_POS); - spio_reg |= (spio_mask << MISC_REGISTERS_SPIO_CLR_POS); - break; - - case MISC_REGISTERS_SPIO_OUTPUT_HIGH : - DP(NETIF_MSG_LINK, "Set SPIO %d -> output high\n", spio_num); - /* clear FLOAT and set SET */ - spio_reg &= ~(spio_mask << MISC_REGISTERS_SPIO_FLOAT_POS); - spio_reg |= (spio_mask << MISC_REGISTERS_SPIO_SET_POS); - break; - - case MISC_REGISTERS_SPIO_INPUT_HI_Z: - DP(NETIF_MSG_LINK, "Set SPIO %d -> input\n", spio_num); - /* set FLOAT */ - spio_reg |= (spio_mask << MISC_REGISTERS_SPIO_FLOAT_POS); - break; - - default: - break; - } - - REG_WR(bp, MISC_REG_SPIO, spio_reg); - bnx2x_hw_unlock(bp, HW_LOCK_RESOURCE_SPIO); - - return 0; -} - -static int bnx2x_mdio22_write(struct bnx2x *bp, u32 reg, u32 val) -{ - int port = bp->port; - u32 emac_base = port ? GRCBASE_EMAC1 : GRCBASE_EMAC0; - u32 tmp; - int i, rc; - -/* DP(NETIF_MSG_HW, "phy_addr 0x%x reg 0x%x val 0x%08x\n", - bp->phy_addr, reg, val); */ - - if (bp->phy_flags & PHY_INT_MODE_AUTO_POLLING_FLAG) { - - tmp = REG_RD(bp, emac_base + EMAC_REG_EMAC_MDIO_MODE); - tmp &= ~EMAC_MDIO_MODE_AUTO_POLL; - EMAC_WR(EMAC_REG_EMAC_MDIO_MODE, tmp); - REG_RD(bp, emac_base + EMAC_REG_EMAC_MDIO_MODE); - udelay(40); - } - - tmp = ((bp->phy_addr << 21) | (reg << 16) | - (val & EMAC_MDIO_COMM_DATA) | - EMAC_MDIO_COMM_COMMAND_WRITE_22 | - EMAC_MDIO_COMM_START_BUSY); - EMAC_WR(EMAC_REG_EMAC_MDIO_COMM, tmp); - - for (i = 0; i < 50; i++) { - udelay(10); - - tmp = REG_RD(bp, emac_base + EMAC_REG_EMAC_MDIO_COMM); - if (!(tmp & EMAC_MDIO_COMM_START_BUSY)) { - udelay(5); - break; - } - } - - if (tmp & EMAC_MDIO_COMM_START_BUSY) { - BNX2X_ERR("write phy register failed\n"); - - rc = -EBUSY; - } else { - rc = 0; - } - - if (bp->phy_flags & PHY_INT_MODE_AUTO_POLLING_FLAG) { - - tmp = REG_RD(bp, emac_base + EMAC_REG_EMAC_MDIO_MODE); - tmp |= EMAC_MDIO_MODE_AUTO_POLL; - EMAC_WR(EMAC_REG_EMAC_MDIO_MODE, tmp); - } - - return rc; -} - -static int bnx2x_mdio22_read(struct bnx2x *bp, u32 reg, u32 *ret_val) -{ - int port = bp->port; - u32 emac_base = port ? GRCBASE_EMAC1 : GRCBASE_EMAC0; - u32 val; - int i, rc; - - if (bp->phy_flags & PHY_INT_MODE_AUTO_POLLING_FLAG) { - - val = REG_RD(bp, emac_base + EMAC_REG_EMAC_MDIO_MODE); - val &= ~EMAC_MDIO_MODE_AUTO_POLL; - EMAC_WR(EMAC_REG_EMAC_MDIO_MODE, val); - REG_RD(bp, emac_base + EMAC_REG_EMAC_MDIO_MODE); - udelay(40); - } - - val = ((bp->phy_addr << 21) | (reg << 16) | - EMAC_MDIO_COMM_COMMAND_READ_22 | - EMAC_MDIO_COMM_START_BUSY); - EMAC_WR(EMAC_REG_EMAC_MDIO_COMM, val); - - for (i = 0; i < 50; i++) { - udelay(10); - - val = REG_RD(bp, emac_base + EMAC_REG_EMAC_MDIO_COMM); - if (!(val & EMAC_MDIO_COMM_START_BUSY)) { - val &= EMAC_MDIO_COMM_DATA; - break; - } - } - - if (val & EMAC_MDIO_COMM_START_BUSY) { - BNX2X_ERR("read phy register failed\n"); - - *ret_val = 0x0; - rc = -EBUSY; - } else { - *ret_val = val; - rc = 0; - } - - if (bp->phy_flags & PHY_INT_MODE_AUTO_POLLING_FLAG) { - - val = REG_RD(bp, emac_base + EMAC_REG_EMAC_MDIO_MODE); - val |= EMAC_MDIO_MODE_AUTO_POLL; - EMAC_WR(EMAC_REG_EMAC_MDIO_MODE, val); - } - -/* DP(NETIF_MSG_HW, "phy_addr 0x%x reg 0x%x ret_val 0x%08x\n", - bp->phy_addr, reg, *ret_val); */ - - return rc; -} - -static int bnx2x_mdio45_ctrl_write(struct bnx2x *bp, u32 mdio_ctrl, - u32 phy_addr, u32 reg, u32 addr, u32 val) -{ - u32 tmp; - int i, rc = 0; - - /* set clause 45 mode, slow down the MDIO clock to 2.5MHz - * (a value of 49==0x31) and make sure that the AUTO poll is off - */ - tmp = REG_RD(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE); - tmp &= ~(EMAC_MDIO_MODE_AUTO_POLL | EMAC_MDIO_MODE_CLOCK_CNT); - tmp |= (EMAC_MDIO_MODE_CLAUSE_45 | - (49 << EMAC_MDIO_MODE_CLOCK_CNT_BITSHIFT)); - REG_WR(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE, tmp); - REG_RD(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE); - udelay(40); - - /* address */ - tmp = ((phy_addr << 21) | (reg << 16) | addr | - EMAC_MDIO_COMM_COMMAND_ADDRESS | - EMAC_MDIO_COMM_START_BUSY); - REG_WR(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM, tmp); - - for (i = 0; i < 50; i++) { - udelay(10); - - tmp = REG_RD(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM); - if (!(tmp & EMAC_MDIO_COMM_START_BUSY)) { - udelay(5); - break; - } - } - if (tmp & EMAC_MDIO_COMM_START_BUSY) { - BNX2X_ERR("write phy register failed\n"); - - rc = -EBUSY; - - } else { - /* data */ - tmp = ((phy_addr << 21) | (reg << 16) | val | - EMAC_MDIO_COMM_COMMAND_WRITE_45 | - EMAC_MDIO_COMM_START_BUSY); - REG_WR(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM, tmp); - - for (i = 0; i < 50; i++) { - udelay(10); - - tmp = REG_RD(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM); - if (!(tmp & EMAC_MDIO_COMM_START_BUSY)) { - udelay(5); - break; - } - } - - if (tmp & EMAC_MDIO_COMM_START_BUSY) { - BNX2X_ERR("write phy register failed\n"); - - rc = -EBUSY; - } - } - - /* unset clause 45 mode, set the MDIO clock to a faster value - * (0x13 => 6.25Mhz) and restore the AUTO poll if needed - */ - tmp = REG_RD(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE); - tmp &= ~(EMAC_MDIO_MODE_CLAUSE_45 | EMAC_MDIO_MODE_CLOCK_CNT); - tmp |= (0x13 << EMAC_MDIO_MODE_CLOCK_CNT_BITSHIFT); - if (bp->phy_flags & PHY_INT_MODE_AUTO_POLLING_FLAG) - tmp |= EMAC_MDIO_MODE_AUTO_POLL; - REG_WR(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE, tmp); - - return rc; -} - -static int bnx2x_mdio45_write(struct bnx2x *bp, u32 phy_addr, u32 reg, - u32 addr, u32 val) -{ - u32 emac_base = bp->port ? GRCBASE_EMAC1 : GRCBASE_EMAC0; - - return bnx2x_mdio45_ctrl_write(bp, emac_base, phy_addr, - reg, addr, val); -} - -static int bnx2x_mdio45_ctrl_read(struct bnx2x *bp, u32 mdio_ctrl, - u32 phy_addr, u32 reg, u32 addr, - u32 *ret_val) -{ - u32 val; - int i, rc = 0; - - /* set clause 45 mode, slow down the MDIO clock to 2.5MHz - * (a value of 49==0x31) and make sure that the AUTO poll is off - */ - val = REG_RD(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE); - val &= ~(EMAC_MDIO_MODE_AUTO_POLL | EMAC_MDIO_MODE_CLOCK_CNT); - val |= (EMAC_MDIO_MODE_CLAUSE_45 | - (49 << EMAC_MDIO_MODE_CLOCK_CNT_BITSHIFT)); - REG_WR(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE, val); - REG_RD(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE); - udelay(40); - - /* address */ - val = ((phy_addr << 21) | (reg << 16) | addr | - EMAC_MDIO_COMM_COMMAND_ADDRESS | - EMAC_MDIO_COMM_START_BUSY); - REG_WR(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM, val); - - for (i = 0; i < 50; i++) { - udelay(10); - - val = REG_RD(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM); - if (!(val & EMAC_MDIO_COMM_START_BUSY)) { - udelay(5); - break; - } - } - if (val & EMAC_MDIO_COMM_START_BUSY) { - BNX2X_ERR("read phy register failed\n"); - - *ret_val = 0; - rc = -EBUSY; - - } else { - /* data */ - val = ((phy_addr << 21) | (reg << 16) | - EMAC_MDIO_COMM_COMMAND_READ_45 | - EMAC_MDIO_COMM_START_BUSY); - REG_WR(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM, val); - - for (i = 0; i < 50; i++) { - udelay(10); - - val = REG_RD(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM); - if (!(val & EMAC_MDIO_COMM_START_BUSY)) { - val &= EMAC_MDIO_COMM_DATA; - break; - } - } - - if (val & EMAC_MDIO_COMM_START_BUSY) { - BNX2X_ERR("read phy register failed\n"); - - val = 0; - rc = -EBUSY; - } - - *ret_val = val; - } - - /* unset clause 45 mode, set the MDIO clock to a faster value - * (0x13 => 6.25Mhz) and restore the AUTO poll if needed - */ - val = REG_RD(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE); - val &= ~(EMAC_MDIO_MODE_CLAUSE_45 | EMAC_MDIO_MODE_CLOCK_CNT); - val |= (0x13 << EMAC_MDIO_MODE_CLOCK_CNT_BITSHIFT); - if (bp->phy_flags & PHY_INT_MODE_AUTO_POLLING_FLAG) - val |= EMAC_MDIO_MODE_AUTO_POLL; - REG_WR(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE, val); - - return rc; -} - -static int bnx2x_mdio45_read(struct bnx2x *bp, u32 phy_addr, u32 reg, - u32 addr, u32 *ret_val) -{ - u32 emac_base = bp->port ? GRCBASE_EMAC1 : GRCBASE_EMAC0; - - return bnx2x_mdio45_ctrl_read(bp, emac_base, phy_addr, - reg, addr, ret_val); -} - -static int bnx2x_mdio45_vwrite(struct bnx2x *bp, u32 phy_addr, u32 reg, - u32 addr, u32 val) -{ - int i; - u32 rd_val; - - might_sleep(); - for (i = 0; i < 10; i++) { - bnx2x_mdio45_write(bp, phy_addr, reg, addr, val); - msleep(5); - bnx2x_mdio45_read(bp, phy_addr, reg, addr, &rd_val); - /* if the read value is not the same as the value we wrote, - we should write it again */ - if (rd_val == val) - return 0; - } - BNX2X_ERR("MDIO write in CL45 failed\n"); - return -EBUSY; -} - -/* - * link management - */ - -static void bnx2x_pause_resolve(struct bnx2x *bp, u32 pause_result) -{ - switch (pause_result) { /* ASYM P ASYM P */ - case 0xb: /* 1 0 1 1 */ - bp->flow_ctrl = FLOW_CTRL_TX; - break; - - case 0xe: /* 1 1 1 0 */ - bp->flow_ctrl = FLOW_CTRL_RX; - break; - - case 0x5: /* 0 1 0 1 */ - case 0x7: /* 0 1 1 1 */ - case 0xd: /* 1 1 0 1 */ - case 0xf: /* 1 1 1 1 */ - bp->flow_ctrl = FLOW_CTRL_BOTH; - break; - - default: - break; - } -} - -static u8 bnx2x_ext_phy_resove_fc(struct bnx2x *bp) -{ - u32 ext_phy_addr; - u32 ld_pause; /* local */ - u32 lp_pause; /* link partner */ - u32 an_complete; /* AN complete */ - u32 pause_result; - u8 ret = 0; - - ext_phy_addr = ((bp->ext_phy_config & - PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >> - PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT); - - /* read twice */ - bnx2x_mdio45_read(bp, ext_phy_addr, - EXT_PHY_KR_AUTO_NEG_DEVAD, - EXT_PHY_KR_STATUS, &an_complete); - bnx2x_mdio45_read(bp, ext_phy_addr, - EXT_PHY_KR_AUTO_NEG_DEVAD, - EXT_PHY_KR_STATUS, &an_complete); - - if (an_complete & EXT_PHY_KR_AUTO_NEG_COMPLETE) { - ret = 1; - bnx2x_mdio45_read(bp, ext_phy_addr, - EXT_PHY_KR_AUTO_NEG_DEVAD, - EXT_PHY_KR_AUTO_NEG_ADVERT, &ld_pause); - bnx2x_mdio45_read(bp, ext_phy_addr, - EXT_PHY_KR_AUTO_NEG_DEVAD, - EXT_PHY_KR_LP_AUTO_NEG, &lp_pause); - pause_result = (ld_pause & - EXT_PHY_KR_AUTO_NEG_ADVERT_PAUSE_MASK) >> 8; - pause_result |= (lp_pause & - EXT_PHY_KR_AUTO_NEG_ADVERT_PAUSE_MASK) >> 10; - DP(NETIF_MSG_LINK, "Ext PHY pause result 0x%x \n", - pause_result); - bnx2x_pause_resolve(bp, pause_result); - } - return ret; -} - -static void bnx2x_flow_ctrl_resolve(struct bnx2x *bp, u32 gp_status) -{ - u32 ld_pause; /* local driver */ - u32 lp_pause; /* link partner */ - u32 pause_result; - - bp->flow_ctrl = 0; - - /* resolve from gp_status in case of AN complete and not sgmii */ - if ((bp->req_autoneg & AUTONEG_FLOW_CTRL) && - (gp_status & MDIO_AN_CL73_OR_37_COMPLETE) && - (!(bp->phy_flags & PHY_SGMII_FLAG)) && - (XGXS_EXT_PHY_TYPE(bp) == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT)) { - - MDIO_SET_REG_BANK(bp, MDIO_REG_BANK_COMBO_IEEE0); - bnx2x_mdio22_read(bp, MDIO_COMBO_IEEE0_AUTO_NEG_ADV, - &ld_pause); - bnx2x_mdio22_read(bp, - MDIO_COMBO_IEEE0_AUTO_NEG_LINK_PARTNER_ABILITY1, - &lp_pause); - pause_result = (ld_pause & - MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_MASK)>>5; - pause_result |= (lp_pause & - MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_MASK)>>7; - DP(NETIF_MSG_LINK, "pause_result 0x%x\n", pause_result); - bnx2x_pause_resolve(bp, pause_result); - } else if (!(bp->req_autoneg & AUTONEG_FLOW_CTRL) || - !(bnx2x_ext_phy_resove_fc(bp))) { - /* forced speed */ - if (bp->req_autoneg & AUTONEG_FLOW_CTRL) { - switch (bp->req_flow_ctrl) { - case FLOW_CTRL_AUTO: - if (bp->dev->mtu <= 4500) - bp->flow_ctrl = FLOW_CTRL_BOTH; - else - bp->flow_ctrl = FLOW_CTRL_TX; - break; - - case FLOW_CTRL_TX: - bp->flow_ctrl = FLOW_CTRL_TX; - break; - - case FLOW_CTRL_RX: - if (bp->dev->mtu <= 4500) - bp->flow_ctrl = FLOW_CTRL_RX; - break; - - case FLOW_CTRL_BOTH: - if (bp->dev->mtu <= 4500) - bp->flow_ctrl = FLOW_CTRL_BOTH; - else - bp->flow_ctrl = FLOW_CTRL_TX; - break; - - case FLOW_CTRL_NONE: - default: - break; - } - } else { /* forced mode */ - switch (bp->req_flow_ctrl) { - case FLOW_CTRL_AUTO: - DP(NETIF_MSG_LINK, "req_flow_ctrl 0x%x while" - " req_autoneg 0x%x\n", - bp->req_flow_ctrl, bp->req_autoneg); - break; - - case FLOW_CTRL_TX: - case FLOW_CTRL_RX: - case FLOW_CTRL_BOTH: - bp->flow_ctrl = bp->req_flow_ctrl; - break; - - case FLOW_CTRL_NONE: - default: - break; - } - } - } - DP(NETIF_MSG_LINK, "flow_ctrl 0x%x\n", bp->flow_ctrl); -} - -static void bnx2x_link_settings_status(struct bnx2x *bp, u32 gp_status) -{ - bp->link_status = 0; - - if (gp_status & MDIO_GP_STATUS_TOP_AN_STATUS1_LINK_STATUS) { - DP(NETIF_MSG_LINK, "phy link up\n"); - - bp->phy_link_up = 1; - bp->link_status |= LINK_STATUS_LINK_UP; - - if (gp_status & MDIO_GP_STATUS_TOP_AN_STATUS1_DUPLEX_STATUS) - bp->duplex = DUPLEX_FULL; - else - bp->duplex = DUPLEX_HALF; - - bnx2x_flow_ctrl_resolve(bp, gp_status); - - switch (gp_status & GP_STATUS_SPEED_MASK) { - case GP_STATUS_10M: - bp->line_speed = SPEED_10; - if (bp->duplex == DUPLEX_FULL) - bp->link_status |= LINK_10TFD; - else - bp->link_status |= LINK_10THD; - break; - - case GP_STATUS_100M: - bp->line_speed = SPEED_100; - if (bp->duplex == DUPLEX_FULL) - bp->link_status |= LINK_100TXFD; - else - bp->link_status |= LINK_100TXHD; - break; - - case GP_STATUS_1G: - case GP_STATUS_1G_KX: - bp->line_speed = SPEED_1000; - if (bp->duplex == DUPLEX_FULL) - bp->link_status |= LINK_1000TFD; - else - bp->link_status |= LINK_1000THD; - break; - - case GP_STATUS_2_5G: - bp->line_speed = SPEED_2500; - if (bp->duplex == DUPLEX_FULL) - bp->link_status |= LINK_2500TFD; - else - bp->link_status |= LINK_2500THD; - break; - - case GP_STATUS_5G: - case GP_STATUS_6G: - BNX2X_ERR("link speed unsupported gp_status 0x%x\n", - gp_status); - break; - - case GP_STATUS_10G_KX4: - case GP_STATUS_10G_HIG: - case GP_STATUS_10G_CX4: - bp->line_speed = SPEED_10000; - bp->link_status |= LINK_10GTFD; - break; - - case GP_STATUS_12G_HIG: - bp->line_speed = SPEED_12000; - bp->link_status |= LINK_12GTFD; - break; - - case GP_STATUS_12_5G: - bp->line_speed = SPEED_12500; - bp->link_status |= LINK_12_5GTFD; - break; - - case GP_STATUS_13G: - bp->line_speed = SPEED_13000; - bp->link_status |= LINK_13GTFD; - break; - - case GP_STATUS_15G: - bp->line_speed = SPEED_15000; - bp->link_status |= LINK_15GTFD; - break; - - case GP_STATUS_16G: - bp->line_speed = SPEED_16000; - bp->link_status |= LINK_16GTFD; - break; - - default: - BNX2X_ERR("link speed unsupported gp_status 0x%x\n", - gp_status); - break; - } - - bp->link_status |= LINK_STATUS_SERDES_LINK; - - if (bp->req_autoneg & AUTONEG_SPEED) { - bp->link_status |= LINK_STATUS_AUTO_NEGOTIATE_ENABLED; - - if (gp_status & MDIO_AN_CL73_OR_37_COMPLETE) - bp->link_status |= - LINK_STATUS_AUTO_NEGOTIATE_COMPLETE; - - if (bp->autoneg & AUTONEG_PARALLEL) - bp->link_status |= - LINK_STATUS_PARALLEL_DETECTION_USED; - } - - if (bp->flow_ctrl & FLOW_CTRL_TX) - bp->link_status |= LINK_STATUS_TX_FLOW_CONTROL_ENABLED; - - if (bp->flow_ctrl & FLOW_CTRL_RX) - bp->link_status |= LINK_STATUS_RX_FLOW_CONTROL_ENABLED; - - } else { /* link_down */ - DP(NETIF_MSG_LINK, "phy link down\n"); - - bp->phy_link_up = 0; - - bp->line_speed = 0; - bp->duplex = DUPLEX_FULL; - bp->flow_ctrl = 0; - } - - DP(NETIF_MSG_LINK, "gp_status 0x%x phy_link_up %d\n" - DP_LEVEL " line_speed %d duplex %d flow_ctrl 0x%x" - " link_status 0x%x\n", - gp_status, bp->phy_link_up, bp->line_speed, bp->duplex, - bp->flow_ctrl, bp->link_status); -} - -static void bnx2x_link_int_ack(struct bnx2x *bp, int is_10g) -{ - int port = bp->port; - - /* first reset all status - * we assume only one line will be change at a time */ - bnx2x_bits_dis(bp, NIG_REG_STATUS_INTERRUPT_PORT0 + port*4, - (NIG_STATUS_XGXS0_LINK10G | - NIG_STATUS_XGXS0_LINK_STATUS | - NIG_STATUS_SERDES0_LINK_STATUS)); - if (bp->phy_link_up) { - if (is_10g) { - /* Disable the 10G link interrupt - * by writing 1 to the status register - */ - DP(NETIF_MSG_LINK, "10G XGXS phy link up\n"); - bnx2x_bits_en(bp, - NIG_REG_STATUS_INTERRUPT_PORT0 + port*4, - NIG_STATUS_XGXS0_LINK10G); - - } else if (bp->phy_flags & PHY_XGXS_FLAG) { - /* Disable the link interrupt - * by writing 1 to the relevant lane - * in the status register - */ - DP(NETIF_MSG_LINK, "1G XGXS phy link up\n"); - bnx2x_bits_en(bp, - NIG_REG_STATUS_INTERRUPT_PORT0 + port*4, - ((1 << bp->ser_lane) << - NIG_STATUS_XGXS0_LINK_STATUS_SIZE)); - - } else { /* SerDes */ - DP(NETIF_MSG_LINK, "SerDes phy link up\n"); - /* Disable the link interrupt - * by writing 1 to the status register - */ - bnx2x_bits_en(bp, - NIG_REG_STATUS_INTERRUPT_PORT0 + port*4, - NIG_STATUS_SERDES0_LINK_STATUS); - } - - } else { /* link_down */ - } -} - -static int bnx2x_ext_phy_is_link_up(struct bnx2x *bp) -{ - u32 ext_phy_type; - u32 ext_phy_addr; - u32 val1 = 0, val2; - u32 rx_sd, pcs_status; - - if (bp->phy_flags & PHY_XGXS_FLAG) { - ext_phy_addr = ((bp->ext_phy_config & - PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >> - PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT); - - ext_phy_type = XGXS_EXT_PHY_TYPE(bp); - switch (ext_phy_type) { - case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT: - DP(NETIF_MSG_LINK, "XGXS Direct\n"); - val1 = 1; - break; - - case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705: - DP(NETIF_MSG_LINK, "XGXS 8705\n"); - bnx2x_mdio45_read(bp, ext_phy_addr, - EXT_PHY_OPT_WIS_DEVAD, - EXT_PHY_OPT_LASI_STATUS, &val1); - DP(NETIF_MSG_LINK, "8705 LASI status 0x%x\n", val1); - - bnx2x_mdio45_read(bp, ext_phy_addr, - EXT_PHY_OPT_WIS_DEVAD, - EXT_PHY_OPT_LASI_STATUS, &val1); - DP(NETIF_MSG_LINK, "8705 LASI status 0x%x\n", val1); - - bnx2x_mdio45_read(bp, ext_phy_addr, - EXT_PHY_OPT_PMA_PMD_DEVAD, - EXT_PHY_OPT_PMD_RX_SD, &rx_sd); - DP(NETIF_MSG_LINK, "8705 rx_sd 0x%x\n", rx_sd); - val1 = (rx_sd & 0x1); - break; - - case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706: - DP(NETIF_MSG_LINK, "XGXS 8706\n"); - bnx2x_mdio45_read(bp, ext_phy_addr, - EXT_PHY_OPT_PMA_PMD_DEVAD, - EXT_PHY_OPT_LASI_STATUS, &val1); - DP(NETIF_MSG_LINK, "8706 LASI status 0x%x\n", val1); - - bnx2x_mdio45_read(bp, ext_phy_addr, - EXT_PHY_OPT_PMA_PMD_DEVAD, - EXT_PHY_OPT_LASI_STATUS, &val1); - DP(NETIF_MSG_LINK, "8706 LASI status 0x%x\n", val1); - - bnx2x_mdio45_read(bp, ext_phy_addr, - EXT_PHY_OPT_PMA_PMD_DEVAD, - EXT_PHY_OPT_PMD_RX_SD, &rx_sd); - bnx2x_mdio45_read(bp, ext_phy_addr, - EXT_PHY_OPT_PCS_DEVAD, - EXT_PHY_OPT_PCS_STATUS, &pcs_status); - bnx2x_mdio45_read(bp, ext_phy_addr, - EXT_PHY_AUTO_NEG_DEVAD, - EXT_PHY_OPT_AN_LINK_STATUS, &val2); - - DP(NETIF_MSG_LINK, "8706 rx_sd 0x%x" - " pcs_status 0x%x 1Gbps link_status 0x%x 0x%x\n", - rx_sd, pcs_status, val2, (val2 & (1<<1))); - /* link is up if both bit 0 of pmd_rx_sd and - * bit 0 of pcs_status are set, or if the autoneg bit - 1 is set - */ - val1 = ((rx_sd & pcs_status & 0x1) || (val2 & (1<<1))); - break; - - case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072: - bnx2x_hw_lock(bp, HW_LOCK_RESOURCE_8072_MDIO); - - /* clear the interrupt LASI status register */ - bnx2x_mdio45_ctrl_read(bp, GRCBASE_EMAC0, - ext_phy_addr, - EXT_PHY_KR_PCS_DEVAD, - EXT_PHY_KR_LASI_STATUS, &val2); - bnx2x_mdio45_ctrl_read(bp, GRCBASE_EMAC0, - ext_phy_addr, - EXT_PHY_KR_PCS_DEVAD, - EXT_PHY_KR_LASI_STATUS, &val1); - DP(NETIF_MSG_LINK, "KR LASI status 0x%x->0x%x\n", - val2, val1); - /* Check the LASI */ - bnx2x_mdio45_ctrl_read(bp, GRCBASE_EMAC0, - ext_phy_addr, - EXT_PHY_KR_PMA_PMD_DEVAD, - 0x9003, &val2); - bnx2x_mdio45_ctrl_read(bp, GRCBASE_EMAC0, - ext_phy_addr, - EXT_PHY_KR_PMA_PMD_DEVAD, - 0x9003, &val1); - DP(NETIF_MSG_LINK, "KR 0x9003 0x%x->0x%x\n", - val2, val1); - /* Check the link status */ - bnx2x_mdio45_ctrl_read(bp, GRCBASE_EMAC0, - ext_phy_addr, - EXT_PHY_KR_PCS_DEVAD, - EXT_PHY_KR_PCS_STATUS, &val2); - DP(NETIF_MSG_LINK, "KR PCS status 0x%x\n", val2); - /* Check the link status on 1.1.2 */ - bnx2x_mdio45_ctrl_read(bp, GRCBASE_EMAC0, - ext_phy_addr, - EXT_PHY_OPT_PMA_PMD_DEVAD, - EXT_PHY_KR_STATUS, &val2); - bnx2x_mdio45_ctrl_read(bp, GRCBASE_EMAC0, - ext_phy_addr, - EXT_PHY_OPT_PMA_PMD_DEVAD, - EXT_PHY_KR_STATUS, &val1); - DP(NETIF_MSG_LINK, - "KR PMA status 0x%x->0x%x\n", val2, val1); - val1 = ((val1 & 4) == 4); - /* If 1G was requested assume the link is up */ - if (!(bp->req_autoneg & AUTONEG_SPEED) && - (bp->req_line_speed == SPEED_1000)) - val1 = 1; - bnx2x_hw_unlock(bp, HW_LOCK_RESOURCE_8072_MDIO); - break; - - case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101: - bnx2x_mdio45_read(bp, ext_phy_addr, - EXT_PHY_OPT_PMA_PMD_DEVAD, - EXT_PHY_OPT_LASI_STATUS, &val2); - bnx2x_mdio45_read(bp, ext_phy_addr, - EXT_PHY_OPT_PMA_PMD_DEVAD, - EXT_PHY_OPT_LASI_STATUS, &val1); - DP(NETIF_MSG_LINK, - "10G-base-T LASI status 0x%x->0x%x\n", val2, val1); - bnx2x_mdio45_read(bp, ext_phy_addr, - EXT_PHY_OPT_PMA_PMD_DEVAD, - EXT_PHY_KR_STATUS, &val2); - bnx2x_mdio45_read(bp, ext_phy_addr, - EXT_PHY_OPT_PMA_PMD_DEVAD, - EXT_PHY_KR_STATUS, &val1); - DP(NETIF_MSG_LINK, - "10G-base-T PMA status 0x%x->0x%x\n", val2, val1); - val1 = ((val1 & 4) == 4); - /* if link is up - * print the AN outcome of the SFX7101 PHY - */ - if (val1) { - bnx2x_mdio45_read(bp, ext_phy_addr, - EXT_PHY_KR_AUTO_NEG_DEVAD, - 0x21, &val2); - DP(NETIF_MSG_LINK, - "SFX7101 AN status 0x%x->%s\n", val2, - (val2 & (1<<14)) ? "Master" : "Slave"); - } - break; - - default: - DP(NETIF_MSG_LINK, "BAD XGXS ext_phy_config 0x%x\n", - bp->ext_phy_config); - val1 = 0; - break; - } - - } else { /* SerDes */ - ext_phy_type = SERDES_EXT_PHY_TYPE(bp); - switch (ext_phy_type) { - case PORT_HW_CFG_SERDES_EXT_PHY_TYPE_DIRECT: - DP(NETIF_MSG_LINK, "SerDes Direct\n"); - val1 = 1; - break; - - case PORT_HW_CFG_SERDES_EXT_PHY_TYPE_BCM5482: - DP(NETIF_MSG_LINK, "SerDes 5482\n"); - val1 = 1; - break; - - default: - DP(NETIF_MSG_LINK, "BAD SerDes ext_phy_config 0x%x\n", - bp->ext_phy_config); - val1 = 0; - break; - } - } - - return val1; -} - -static void bnx2x_bmac_enable(struct bnx2x *bp, int is_lb) -{ - int port = bp->port; - u32 bmac_addr = port ? NIG_REG_INGRESS_BMAC1_MEM : - NIG_REG_INGRESS_BMAC0_MEM; - u32 wb_write[2]; - u32 val; - - DP(NETIF_MSG_LINK, "enabling BigMAC\n"); - /* reset and unreset the BigMac */ - REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_CLEAR, - (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port)); - msleep(5); - REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_SET, - (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port)); - - /* enable access for bmac registers */ - NIG_WR(NIG_REG_BMAC0_REGS_OUT_EN + port*4, 0x1); - - /* XGXS control */ - wb_write[0] = 0x3c; - wb_write[1] = 0; - REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_BMAC_XGXS_CONTROL, - wb_write, 2); - - /* tx MAC SA */ - wb_write[0] = ((bp->dev->dev_addr[2] << 24) | - (bp->dev->dev_addr[3] << 16) | - (bp->dev->dev_addr[4] << 8) | - bp->dev->dev_addr[5]); - wb_write[1] = ((bp->dev->dev_addr[0] << 8) | - bp->dev->dev_addr[1]); - REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_TX_SOURCE_ADDR, - wb_write, 2); - - /* tx control */ - val = 0xc0; - if (bp->flow_ctrl & FLOW_CTRL_TX) - val |= 0x800000; - wb_write[0] = val; - wb_write[1] = 0; - REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_TX_CONTROL, wb_write, 2); - - /* set tx mtu */ - wb_write[0] = ETH_MAX_JUMBO_PACKET_SIZE + ETH_OVREHEAD; /* -CRC */ - wb_write[1] = 0; - REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_TX_MAX_SIZE, wb_write, 2); - - /* mac control */ - val = 0x3; - if (is_lb) { - val |= 0x4; - DP(NETIF_MSG_LINK, "enable bmac loopback\n"); - } - wb_write[0] = val; - wb_write[1] = 0; - REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_BMAC_CONTROL, - wb_write, 2); - - /* rx control set to don't strip crc */ - val = 0x14; - if (bp->flow_ctrl & FLOW_CTRL_RX) - val |= 0x20; - wb_write[0] = val; - wb_write[1] = 0; - REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_RX_CONTROL, wb_write, 2); - - /* set rx mtu */ - wb_write[0] = ETH_MAX_JUMBO_PACKET_SIZE + ETH_OVREHEAD; - wb_write[1] = 0; - REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_RX_MAX_SIZE, wb_write, 2); - - /* set cnt max size */ - wb_write[0] = ETH_MAX_JUMBO_PACKET_SIZE + ETH_OVREHEAD; /* -VLAN */ - wb_write[1] = 0; - REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_CNT_MAX_SIZE, - wb_write, 2); - - /* configure safc */ - wb_write[0] = 0x1000200; - wb_write[1] = 0; - REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_RX_LLFC_MSG_FLDS, - wb_write, 2); - - /* fix for emulation */ - if (CHIP_REV(bp) == CHIP_REV_EMUL) { - wb_write[0] = 0xf000; - wb_write[1] = 0; - REG_WR_DMAE(bp, - bmac_addr + BIGMAC_REGISTER_TX_PAUSE_THRESHOLD, - wb_write, 2); - } - - /* reset old bmac stats */ - memset(&bp->old_bmac, 0, sizeof(struct bmac_stats)); - - NIG_WR(NIG_REG_XCM0_OUT_EN + port*4, 0x0); - - /* select XGXS */ - NIG_WR(NIG_REG_XGXS_SERDES0_MODE_SEL + port*4, 0x1); - NIG_WR(NIG_REG_XGXS_LANE_SEL_P0 + port*4, 0x0); - - /* disable the NIG in/out to the emac */ - NIG_WR(NIG_REG_EMAC0_IN_EN + port*4, 0x0); - NIG_WR(NIG_REG_EMAC0_PAUSE_OUT_EN + port*4, 0x0); - NIG_WR(NIG_REG_EGRESS_EMAC0_OUT_EN + port*4, 0x0); - - /* enable the NIG in/out to the bmac */ - NIG_WR(NIG_REG_EGRESS_EMAC0_PORT + port*4, 0x0); - - NIG_WR(NIG_REG_BMAC0_IN_EN + port*4, 0x1); - val = 0; - if (bp->flow_ctrl & FLOW_CTRL_TX) - val = 1; - NIG_WR(NIG_REG_BMAC0_PAUSE_OUT_EN + port*4, val); - NIG_WR(NIG_REG_BMAC0_OUT_EN + port*4, 0x1); - - bp->phy_flags |= PHY_BMAC_FLAG; - - bp->stats_state = STATS_STATE_ENABLE; -} - -static void bnx2x_bmac_rx_disable(struct bnx2x *bp) -{ - int port = bp->port; - u32 bmac_addr = port ? NIG_REG_INGRESS_BMAC1_MEM : - NIG_REG_INGRESS_BMAC0_MEM; - u32 wb_write[2]; - - /* Only if the bmac is out of reset */ - if (REG_RD(bp, MISC_REG_RESET_REG_2) & - (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port)) { - /* Clear Rx Enable bit in BMAC_CONTROL register */ -#ifdef BNX2X_DMAE_RD - bnx2x_read_dmae(bp, bmac_addr + - BIGMAC_REGISTER_BMAC_CONTROL, 2); - wb_write[0] = *bnx2x_sp(bp, wb_data[0]); - wb_write[1] = *bnx2x_sp(bp, wb_data[1]); -#else - wb_write[0] = REG_RD(bp, - bmac_addr + BIGMAC_REGISTER_BMAC_CONTROL); - wb_write[1] = REG_RD(bp, - bmac_addr + BIGMAC_REGISTER_BMAC_CONTROL + 4); -#endif - wb_write[0] &= ~BMAC_CONTROL_RX_ENABLE; - REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_BMAC_CONTROL, - wb_write, 2); - msleep(1); - } -} - -static void bnx2x_emac_enable(struct bnx2x *bp) -{ - int port = bp->port; - u32 emac_base = port ? GRCBASE_EMAC1 : GRCBASE_EMAC0; - u32 val; - int timeout; - - DP(NETIF_MSG_LINK, "enabling EMAC\n"); - /* reset and unreset the emac core */ - REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_CLEAR, - (MISC_REGISTERS_RESET_REG_2_RST_EMAC0_HARD_CORE << port)); - msleep(5); - REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_SET, - (MISC_REGISTERS_RESET_REG_2_RST_EMAC0_HARD_CORE << port)); - - /* enable emac and not bmac */ - NIG_WR(NIG_REG_EGRESS_EMAC0_PORT + port*4, 1); - - /* for paladium */ - if (CHIP_REV(bp) == CHIP_REV_EMUL) { - /* Use lane 1 (of lanes 0-3) */ - NIG_WR(NIG_REG_XGXS_LANE_SEL_P0 + port*4, 1); - NIG_WR(NIG_REG_XGXS_SERDES0_MODE_SEL + port*4, 1); - } - /* for fpga */ - else if (CHIP_REV(bp) == CHIP_REV_FPGA) { - /* Use lane 1 (of lanes 0-3) */ - NIG_WR(NIG_REG_XGXS_LANE_SEL_P0 + port*4, 1); - NIG_WR(NIG_REG_XGXS_SERDES0_MODE_SEL + port*4, 0); - } - /* ASIC */ - else { - if (bp->phy_flags & PHY_XGXS_FLAG) { - DP(NETIF_MSG_LINK, "XGXS\n"); - /* select the master lanes (out of 0-3) */ - NIG_WR(NIG_REG_XGXS_LANE_SEL_P0 + port*4, - bp->ser_lane); - /* select XGXS */ - NIG_WR(NIG_REG_XGXS_SERDES0_MODE_SEL + port*4, 1); - - } else { /* SerDes */ - DP(NETIF_MSG_LINK, "SerDes\n"); - /* select SerDes */ - NIG_WR(NIG_REG_XGXS_SERDES0_MODE_SEL + port*4, 0); - } - } - - /* enable emac */ - NIG_WR(NIG_REG_NIG_EMAC0_EN + port*4, 1); - - /* init emac - use read-modify-write */ - /* self clear reset */ - val = REG_RD(bp, emac_base + EMAC_REG_EMAC_MODE); - EMAC_WR(EMAC_REG_EMAC_MODE, (val | EMAC_MODE_RESET)); - - timeout = 200; - while (val & EMAC_MODE_RESET) { - val = REG_RD(bp, emac_base + EMAC_REG_EMAC_MODE); - DP(NETIF_MSG_LINK, "EMAC reset reg is %u\n", val); - if (!timeout) { - BNX2X_ERR("EMAC timeout!\n"); - break; - } - timeout--; - } - - /* reset tx part */ - EMAC_WR(EMAC_REG_EMAC_TX_MODE, EMAC_TX_MODE_RESET); - - timeout = 200; - while (val & EMAC_TX_MODE_RESET) { - val = REG_RD(bp, emac_base + EMAC_REG_EMAC_TX_MODE); - DP(NETIF_MSG_LINK, "EMAC reset reg is %u\n", val); - if (!timeout) { - BNX2X_ERR("EMAC timeout!\n"); - break; - } - timeout--; - } - - if (CHIP_REV_IS_SLOW(bp)) { - /* config GMII mode */ - val = REG_RD(bp, emac_base + EMAC_REG_EMAC_MODE); - EMAC_WR(EMAC_REG_EMAC_MODE, (val | EMAC_MODE_PORT_GMII)); - - } else { /* ASIC */ - /* pause enable/disable */ - bnx2x_bits_dis(bp, emac_base + EMAC_REG_EMAC_RX_MODE, - EMAC_RX_MODE_FLOW_EN); - if (bp->flow_ctrl & FLOW_CTRL_RX) - bnx2x_bits_en(bp, emac_base + EMAC_REG_EMAC_RX_MODE, - EMAC_RX_MODE_FLOW_EN); - - bnx2x_bits_dis(bp, emac_base + EMAC_REG_EMAC_TX_MODE, - EMAC_TX_MODE_EXT_PAUSE_EN); - if (bp->flow_ctrl & FLOW_CTRL_TX) - bnx2x_bits_en(bp, emac_base + EMAC_REG_EMAC_TX_MODE, - EMAC_TX_MODE_EXT_PAUSE_EN); - } - - /* KEEP_VLAN_TAG, promiscuous */ - val = REG_RD(bp, emac_base + EMAC_REG_EMAC_RX_MODE); - val |= EMAC_RX_MODE_KEEP_VLAN_TAG | EMAC_RX_MODE_PROMISCUOUS; - EMAC_WR(EMAC_REG_EMAC_RX_MODE, val); - - /* identify magic packets */ - val = REG_RD(bp, emac_base + EMAC_REG_EMAC_MODE); - EMAC_WR(EMAC_REG_EMAC_MODE, (val | EMAC_MODE_MPKT)); - - /* enable emac for jumbo packets */ - EMAC_WR(EMAC_REG_EMAC_RX_MTU_SIZE, - (EMAC_RX_MTU_SIZE_JUMBO_ENA | - (ETH_MAX_JUMBO_PACKET_SIZE + ETH_OVREHEAD))); /* -VLAN */ - - /* strip CRC */ - NIG_WR(NIG_REG_NIG_INGRESS_EMAC0_NO_CRC + port*4, 0x1); - - val = ((bp->dev->dev_addr[0] << 8) | - bp->dev->dev_addr[1]); - EMAC_WR(EMAC_REG_EMAC_MAC_MATCH, val); - - val = ((bp->dev->dev_addr[2] << 24) | - (bp->dev->dev_addr[3] << 16) | - (bp->dev->dev_addr[4] << 8) | - bp->dev->dev_addr[5]); - EMAC_WR(EMAC_REG_EMAC_MAC_MATCH + 4, val); - - /* disable the NIG in/out to the bmac */ - NIG_WR(NIG_REG_BMAC0_IN_EN + port*4, 0x0); - NIG_WR(NIG_REG_BMAC0_PAUSE_OUT_EN + port*4, 0x0); - NIG_WR(NIG_REG_BMAC0_OUT_EN + port*4, 0x0); - - /* enable the NIG in/out to the emac */ - NIG_WR(NIG_REG_EMAC0_IN_EN + port*4, 0x1); - val = 0; - if (bp->flow_ctrl & FLOW_CTRL_TX) - val = 1; - NIG_WR(NIG_REG_EMAC0_PAUSE_OUT_EN + port*4, val); - NIG_WR(NIG_REG_EGRESS_EMAC0_OUT_EN + port*4, 0x1); - - if (CHIP_REV(bp) == CHIP_REV_FPGA) { - /* take the BigMac out of reset */ - REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_SET, - (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port)); - - /* enable access for bmac registers */ - NIG_WR(NIG_REG_BMAC0_REGS_OUT_EN + port*4, 0x1); - } - - bp->phy_flags |= PHY_EMAC_FLAG; - - bp->stats_state = STATS_STATE_ENABLE; -} - -static void bnx2x_emac_program(struct bnx2x *bp) -{ - u16 mode = 0; - int port = bp->port; - - DP(NETIF_MSG_LINK, "setting link speed & duplex\n"); - bnx2x_bits_dis(bp, GRCBASE_EMAC0 + port*0x400 + EMAC_REG_EMAC_MODE, - (EMAC_MODE_25G_MODE | - EMAC_MODE_PORT_MII_10M | - EMAC_MODE_HALF_DUPLEX)); - switch (bp->line_speed) { - case SPEED_10: - mode |= EMAC_MODE_PORT_MII_10M; - break; - - case SPEED_100: - mode |= EMAC_MODE_PORT_MII; - break; - - case SPEED_1000: - mode |= EMAC_MODE_PORT_GMII; - break; - - case SPEED_2500: - mode |= (EMAC_MODE_25G_MODE | EMAC_MODE_PORT_GMII); - break; - - default: - /* 10G not valid for EMAC */ - BNX2X_ERR("Invalid line_speed 0x%x\n", bp->line_speed); - break; - } - - if (bp->duplex == DUPLEX_HALF) - mode |= EMAC_MODE_HALF_DUPLEX; - bnx2x_bits_en(bp, GRCBASE_EMAC0 + port*0x400 + EMAC_REG_EMAC_MODE, - mode); - - bnx2x_leds_set(bp, bp->line_speed); -} - -static void bnx2x_set_sgmii_tx_driver(struct bnx2x *bp) -{ - u32 lp_up2; - u32 tx_driver; - - /* read precomp */ - MDIO_SET_REG_BANK(bp, MDIO_REG_BANK_OVER_1G); - bnx2x_mdio22_read(bp, MDIO_OVER_1G_LP_UP2, &lp_up2); - - MDIO_SET_REG_BANK(bp, MDIO_REG_BANK_TX0); - bnx2x_mdio22_read(bp, MDIO_TX0_TX_DRIVER, &tx_driver); - - /* bits [10:7] at lp_up2, positioned at [15:12] */ - lp_up2 = (((lp_up2 & MDIO_OVER_1G_LP_UP2_PREEMPHASIS_MASK) >> - MDIO_OVER_1G_LP_UP2_PREEMPHASIS_SHIFT) << - MDIO_TX0_TX_DRIVER_PREEMPHASIS_SHIFT); - - if ((lp_up2 != 0) && - (lp_up2 != (tx_driver & MDIO_TX0_TX_DRIVER_PREEMPHASIS_MASK))) { - /* replace tx_driver bits [15:12] */ - tx_driver &= ~MDIO_TX0_TX_DRIVER_PREEMPHASIS_MASK; - tx_driver |= lp_up2; - bnx2x_mdio22_write(bp, MDIO_TX0_TX_DRIVER, tx_driver); - } -} - -static void bnx2x_pbf_update(struct bnx2x *bp) -{ - int port = bp->port; - u32 init_crd, crd; - u32 count = 1000; - u32 pause = 0; - - /* disable port */ - REG_WR(bp, PBF_REG_DISABLE_NEW_TASK_PROC_P0 + port*4, 0x1); - - /* wait for init credit */ - init_crd = REG_RD(bp, PBF_REG_P0_INIT_CRD + port*4); - crd = REG_RD(bp, PBF_REG_P0_CREDIT + port*8); - DP(NETIF_MSG_LINK, "init_crd 0x%x crd 0x%x\n", init_crd, crd); - - while ((init_crd != crd) && count) { - msleep(5); - - crd = REG_RD(bp, PBF_REG_P0_CREDIT + port*8); - count--; - } - crd = REG_RD(bp, PBF_REG_P0_CREDIT + port*8); - if (init_crd != crd) - BNX2X_ERR("BUG! init_crd 0x%x != crd 0x%x\n", init_crd, crd); - - if (bp->flow_ctrl & FLOW_CTRL_RX) - pause = 1; - REG_WR(bp, PBF_REG_P0_PAUSE_ENABLE + port*4, pause); - if (pause) { - /* update threshold */ - REG_WR(bp, PBF_REG_P0_ARB_THRSH + port*4, 0); - /* update init credit */ - init_crd = 778; /* (800-18-4) */ - - } else { - u32 thresh = (ETH_MAX_JUMBO_PACKET_SIZE + ETH_OVREHEAD)/16; - - /* update threshold */ - REG_WR(bp, PBF_REG_P0_ARB_THRSH + port*4, thresh); - /* update init credit */ - switch (bp->line_speed) { - case SPEED_10: - case SPEED_100: - case SPEED_1000: - init_crd = thresh + 55 - 22; - break; - - case SPEED_2500: - init_crd = thresh + 138 - 22; - break; - - case SPEED_10000: - init_crd = thresh + 553 - 22; - break; - - default: - BNX2X_ERR("Invalid line_speed 0x%x\n", - bp->line_speed); - break; - } - } - REG_WR(bp, PBF_REG_P0_INIT_CRD + port*4, init_crd); - DP(NETIF_MSG_LINK, "PBF updated to speed %d credit %d\n", - bp->line_speed, init_crd); - - /* probe the credit changes */ - REG_WR(bp, PBF_REG_INIT_P0 + port*4, 0x1); - msleep(5); - REG_WR(bp, PBF_REG_INIT_P0 + port*4, 0x0); - - /* enable port */ - REG_WR(bp, PBF_REG_DISABLE_NEW_TASK_PROC_P0 + port*4, 0x0); -} - -static void bnx2x_update_mng(struct bnx2x *bp) -{ - if (!nomcp) - SHMEM_WR(bp, port_mb[bp->port].link_status, - bp->link_status); -} - -static void bnx2x_link_report(struct bnx2x *bp) -{ - if (bp->link_up) { - netif_carrier_on(bp->dev); - printk(KERN_INFO PFX "%s NIC Link is Up, ", bp->dev->name); - - printk("%d Mbps ", bp->line_speed); - - if (bp->duplex == DUPLEX_FULL) - printk("full duplex"); - else - printk("half duplex"); - - if (bp->flow_ctrl) { - if (bp->flow_ctrl & FLOW_CTRL_RX) { - printk(", receive "); - if (bp->flow_ctrl & FLOW_CTRL_TX) - printk("& transmit "); - } else { - printk(", transmit "); - } - printk("flow control ON"); - } - printk("\n"); - - } else { /* link_down */ - netif_carrier_off(bp->dev); - printk(KERN_INFO PFX "%s NIC Link is Down\n", bp->dev->name); - } -} - -static void bnx2x_link_up(struct bnx2x *bp) -{ - int port = bp->port; - - /* PBF - link up */ - bnx2x_pbf_update(bp); - - /* disable drain */ - NIG_WR(NIG_REG_EGRESS_DRAIN0_MODE + port*4, 0); - - /* update shared memory */ - bnx2x_update_mng(bp); - - /* indicate link up */ - bnx2x_link_report(bp); -} - -static void bnx2x_link_down(struct bnx2x *bp) -{ - int port = bp->port; - - /* notify stats */ - if (bp->stats_state != STATS_STATE_DISABLE) { - bp->stats_state = STATS_STATE_STOP; - DP(BNX2X_MSG_STATS, "stats_state - STOP\n"); - } - - /* indicate no mac active */ - bp->phy_flags &= ~(PHY_BMAC_FLAG | PHY_EMAC_FLAG); - - /* update shared memory */ - bnx2x_update_mng(bp); - - /* activate nig drain */ - NIG_WR(NIG_REG_EGRESS_DRAIN0_MODE + port*4, 1); - - /* reset BigMac */ - bnx2x_bmac_rx_disable(bp); - REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_CLEAR, - (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port)); - - /* indicate link down */ - bnx2x_link_report(bp); -} - -static void bnx2x_init_mac_stats(struct bnx2x *bp); - -/* This function is called upon link interrupt */ -static void bnx2x_link_update(struct bnx2x *bp) -{ - int port = bp->port; - int i; - u32 gp_status; - int link_10g; - - DP(NETIF_MSG_LINK, "port %x, %s, int_status 0x%x," - " int_mask 0x%x, saved_mask 0x%x, MI_INT %x, SERDES_LINK %x," - " 10G %x, XGXS_LINK %x\n", port, - (bp->phy_flags & PHY_XGXS_FLAG)? "XGXS":"SerDes", - REG_RD(bp, NIG_REG_STATUS_INTERRUPT_PORT0 + port*4), - REG_RD(bp, NIG_REG_MASK_INTERRUPT_PORT0 + port*4), bp->nig_mask, - REG_RD(bp, NIG_REG_EMAC0_STATUS_MISC_MI_INT + port*0x18), - REG_RD(bp, NIG_REG_SERDES0_STATUS_LINK_STATUS + port*0x3c), - REG_RD(bp, NIG_REG_XGXS0_STATUS_LINK10G + port*0x68), - REG_RD(bp, NIG_REG_XGXS0_STATUS_LINK_STATUS + port*0x68) - ); - - might_sleep(); - MDIO_SET_REG_BANK(bp, MDIO_REG_BANK_GP_STATUS); - /* avoid fast toggling */ - for (i = 0; i < 10; i++) { - msleep(10); - bnx2x_mdio22_read(bp, MDIO_GP_STATUS_TOP_AN_STATUS1, - &gp_status); - } - - bnx2x_link_settings_status(bp, gp_status); - - /* anything 10 and over uses the bmac */ - link_10g = ((bp->line_speed >= SPEED_10000) && - (bp->line_speed <= SPEED_16000)); - - bnx2x_link_int_ack(bp, link_10g); - - /* link is up only if both local phy and external phy are up */ - bp->link_up = (bp->phy_link_up && bnx2x_ext_phy_is_link_up(bp)); - if (bp->link_up) { - if (link_10g) { - bnx2x_bmac_enable(bp, 0); - bnx2x_leds_set(bp, SPEED_10000); - - } else { - bnx2x_emac_enable(bp); - bnx2x_emac_program(bp); - - /* AN complete? */ - if (gp_status & MDIO_AN_CL73_OR_37_COMPLETE) { - if (!(bp->phy_flags & PHY_SGMII_FLAG)) - bnx2x_set_sgmii_tx_driver(bp); - } - } - bnx2x_link_up(bp); - - } else { /* link down */ - bnx2x_leds_unset(bp); - bnx2x_link_down(bp); - } - - bnx2x_init_mac_stats(bp); -} - -/* - * Init service functions - */ - -static void bnx2x_set_aer_mmd(struct bnx2x *bp) -{ - u16 offset = (bp->phy_flags & PHY_XGXS_FLAG) ? - (bp->phy_addr + bp->ser_lane) : 0; - - MDIO_SET_REG_BANK(bp, MDIO_REG_BANK_AER_BLOCK); - bnx2x_mdio22_write(bp, MDIO_AER_BLOCK_AER_REG, 0x3800 + offset); -} - -static void bnx2x_set_master_ln(struct bnx2x *bp) -{ - u32 new_master_ln; - - /* set the master_ln for AN */ - MDIO_SET_REG_BANK(bp, MDIO_REG_BANK_XGXS_BLOCK2); - bnx2x_mdio22_read(bp, MDIO_XGXS_BLOCK2_TEST_MODE_LANE, - &new_master_ln); - bnx2x_mdio22_write(bp, MDIO_XGXS_BLOCK2_TEST_MODE_LANE, - (new_master_ln | bp->ser_lane)); -} - -static void bnx2x_reset_unicore(struct bnx2x *bp) -{ - u32 mii_control; - int i; - - MDIO_SET_REG_BANK(bp, MDIO_REG_BANK_COMBO_IEEE0); - bnx2x_mdio22_read(bp, MDIO_COMBO_IEEE0_MII_CONTROL, &mii_control); - /* reset the unicore */ - bnx2x_mdio22_write(bp, MDIO_COMBO_IEEE0_MII_CONTROL, - (mii_control | MDIO_COMBO_IEEO_MII_CONTROL_RESET)); - - /* wait for the reset to self clear */ - for (i = 0; i < MDIO_ACCESS_TIMEOUT; i++) { - udelay(5); - - /* the reset erased the previous bank value */ - MDIO_SET_REG_BANK(bp, MDIO_REG_BANK_COMBO_IEEE0); - bnx2x_mdio22_read(bp, MDIO_COMBO_IEEE0_MII_CONTROL, - &mii_control); - - if (!(mii_control & MDIO_COMBO_IEEO_MII_CONTROL_RESET)) { - udelay(5); - return; - } - } - - BNX2X_ERR("BUG! %s (0x%x) is still in reset!\n", - (bp->phy_flags & PHY_XGXS_FLAG)? "XGXS":"SerDes", - bp->phy_addr); -} - -static void bnx2x_set_swap_lanes(struct bnx2x *bp) -{ - /* Each two bits represents a lane number: - No swap is 0123 => 0x1b no need to enable the swap */ - - MDIO_SET_REG_BANK(bp, MDIO_REG_BANK_XGXS_BLOCK2); - if (bp->rx_lane_swap != 0x1b) { - bnx2x_mdio22_write(bp, MDIO_XGXS_BLOCK2_RX_LN_SWAP, - (bp->rx_lane_swap | - MDIO_XGXS_BLOCK2_RX_LN_SWAP_ENABLE | - MDIO_XGXS_BLOCK2_RX_LN_SWAP_FORCE_ENABLE)); - } else { - bnx2x_mdio22_write(bp, MDIO_XGXS_BLOCK2_RX_LN_SWAP, 0); - } - - if (bp->tx_lane_swap != 0x1b) { - bnx2x_mdio22_write(bp, MDIO_XGXS_BLOCK2_TX_LN_SWAP, - (bp->tx_lane_swap | - MDIO_XGXS_BLOCK2_TX_LN_SWAP_ENABLE)); - } else { - bnx2x_mdio22_write(bp, MDIO_XGXS_BLOCK2_TX_LN_SWAP, 0); - } -} - -static void bnx2x_set_parallel_detection(struct bnx2x *bp) -{ - u32 control2; - - MDIO_SET_REG_BANK(bp, MDIO_REG_BANK_SERDES_DIGITAL); - bnx2x_mdio22_read(bp, MDIO_SERDES_DIGITAL_A_1000X_CONTROL2, - &control2); - - if (bp->autoneg & AUTONEG_PARALLEL) { - control2 |= MDIO_SERDES_DIGITAL_A_1000X_CONTROL2_PRL_DT_EN; - } else { - control2 &= ~MDIO_SERDES_DIGITAL_A_1000X_CONTROL2_PRL_DT_EN; - } - bnx2x_mdio22_write(bp, MDIO_SERDES_DIGITAL_A_1000X_CONTROL2, - control2); - - if (bp->phy_flags & PHY_XGXS_FLAG) { - DP(NETIF_MSG_LINK, "XGXS\n"); - MDIO_SET_REG_BANK(bp, MDIO_REG_BANK_10G_PARALLEL_DETECT); - - bnx2x_mdio22_write(bp, - MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_LINK, - MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_LINK_CNT); - - bnx2x_mdio22_read(bp, - MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_CONTROL, - &control2); - - if (bp->autoneg & AUTONEG_PARALLEL) { - control2 |= - MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_CONTROL_PARDET10G_EN; - } else { - control2 &= - ~MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_CONTROL_PARDET10G_EN; - } - bnx2x_mdio22_write(bp, - MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_CONTROL, - control2); - - /* Disable parallel detection of HiG */ - MDIO_SET_REG_BANK(bp, MDIO_REG_BANK_XGXS_BLOCK2); - bnx2x_mdio22_write(bp, MDIO_XGXS_BLOCK2_UNICORE_MODE_10G, - MDIO_XGXS_BLOCK2_UNICORE_MODE_10G_CX4_XGXS | - MDIO_XGXS_BLOCK2_UNICORE_MODE_10G_HIGIG_XGXS); - } -} - -static void bnx2x_set_autoneg(struct bnx2x *bp) -{ - u32 reg_val; - - /* CL37 Autoneg */ - MDIO_SET_REG_BANK(bp, MDIO_REG_BANK_COMBO_IEEE0); - bnx2x_mdio22_read(bp, MDIO_COMBO_IEEE0_MII_CONTROL, ®_val); - if ((bp->req_autoneg & AUTONEG_SPEED) && - (bp->autoneg & AUTONEG_CL37)) { - /* CL37 Autoneg Enabled */ - reg_val |= MDIO_COMBO_IEEO_MII_CONTROL_AN_EN; - } else { - /* CL37 Autoneg Disabled */ - reg_val &= ~(MDIO_COMBO_IEEO_MII_CONTROL_AN_EN | - MDIO_COMBO_IEEO_MII_CONTROL_RESTART_AN); - } - bnx2x_mdio22_write(bp, MDIO_COMBO_IEEE0_MII_CONTROL, reg_val); - - /* Enable/Disable Autodetection */ - MDIO_SET_REG_BANK(bp, MDIO_REG_BANK_SERDES_DIGITAL); - bnx2x_mdio22_read(bp, MDIO_SERDES_DIGITAL_A_1000X_CONTROL1, ®_val); - reg_val &= ~MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_SIGNAL_DETECT_EN; - - if ((bp->req_autoneg & AUTONEG_SPEED) && - (bp->autoneg & AUTONEG_SGMII_FIBER_AUTODET)) { - reg_val |= MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_AUTODET; - } else { - reg_val &= ~MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_AUTODET; - } - bnx2x_mdio22_write(bp, MDIO_SERDES_DIGITAL_A_1000X_CONTROL1, reg_val); - - /* Enable TetonII and BAM autoneg */ - MDIO_SET_REG_BANK(bp, MDIO_REG_BANK_BAM_NEXT_PAGE); - bnx2x_mdio22_read(bp, MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL, - ®_val); - if ((bp->req_autoneg & AUTONEG_SPEED) && - (bp->autoneg & AUTONEG_CL37) && (bp->autoneg & AUTONEG_BAM)) { - /* Enable BAM aneg Mode and TetonII aneg Mode */ - reg_val |= (MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL_BAM_MODE | - MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL_TETON_AN); - } else { - /* TetonII and BAM Autoneg Disabled */ - reg_val &= ~(MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL_BAM_MODE | - MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL_TETON_AN); - } - bnx2x_mdio22_write(bp, MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL, - reg_val); - - /* Enable Clause 73 Aneg */ - if ((bp->req_autoneg & AUTONEG_SPEED) && - (bp->autoneg & AUTONEG_CL73)) { - /* Enable BAM Station Manager */ - MDIO_SET_REG_BANK(bp, MDIO_REG_BANK_CL73_USERB0); - bnx2x_mdio22_write(bp, MDIO_CL73_USERB0_CL73_BAM_CTRL1, - (MDIO_CL73_USERB0_CL73_BAM_CTRL1_BAM_EN | - MDIO_CL73_USERB0_CL73_BAM_CTRL1_BAM_STATION_MNGR_EN | - MDIO_CL73_USERB0_CL73_BAM_CTRL1_BAM_NP_AFTER_BP_EN)); - - /* Merge CL73 and CL37 aneg resolution */ - bnx2x_mdio22_read(bp, MDIO_CL73_USERB0_CL73_BAM_CTRL3, - ®_val); - bnx2x_mdio22_write(bp, MDIO_CL73_USERB0_CL73_BAM_CTRL3, - (reg_val | - MDIO_CL73_USERB0_CL73_BAM_CTRL3_USE_CL73_HCD_MR)); - - /* Set the CL73 AN speed */ - MDIO_SET_REG_BANK(bp, MDIO_REG_BANK_CL73_IEEEB1); - bnx2x_mdio22_read(bp, MDIO_CL73_IEEEB1_AN_ADV2, ®_val); - /* In the SerDes we support only the 1G. - In the XGXS we support the 10G KX4 - but we currently do not support the KR */ - if (bp->phy_flags & PHY_XGXS_FLAG) { - DP(NETIF_MSG_LINK, "XGXS\n"); - /* 10G KX4 */ - reg_val |= MDIO_CL73_IEEEB1_AN_ADV2_ADVR_10G_KX4; - } else { - DP(NETIF_MSG_LINK, "SerDes\n"); - /* 1000M KX */ - reg_val |= MDIO_CL73_IEEEB1_AN_ADV2_ADVR_1000M_KX; - } - bnx2x_mdio22_write(bp, MDIO_CL73_IEEEB1_AN_ADV2, reg_val); - - /* CL73 Autoneg Enabled */ - reg_val = MDIO_CL73_IEEEB0_CL73_AN_CONTROL_AN_EN; - } else { - /* CL73 Autoneg Disabled */ - reg_val = 0; - } - MDIO_SET_REG_BANK(bp, MDIO_REG_BANK_CL73_IEEEB0); - bnx2x_mdio22_write(bp, MDIO_CL73_IEEEB0_CL73_AN_CONTROL, reg_val); -} - -/* program SerDes, forced speed */ -static void bnx2x_program_serdes(struct bnx2x *bp) -{ - u32 reg_val; - - /* program duplex, disable autoneg */ - MDIO_SET_REG_BANK(bp, MDIO_REG_BANK_COMBO_IEEE0); - bnx2x_mdio22_read(bp, MDIO_COMBO_IEEE0_MII_CONTROL, ®_val); - reg_val &= ~(MDIO_COMBO_IEEO_MII_CONTROL_FULL_DUPLEX | - MDIO_COMBO_IEEO_MII_CONTROL_AN_EN); - if (bp->req_duplex == DUPLEX_FULL) - reg_val |= MDIO_COMBO_IEEO_MII_CONTROL_FULL_DUPLEX; - bnx2x_mdio22_write(bp, MDIO_COMBO_IEEE0_MII_CONTROL, reg_val); - - /* program speed - - needed only if the speed is greater than 1G (2.5G or 10G) */ - if (bp->req_line_speed > SPEED_1000) { - MDIO_SET_REG_BANK(bp, MDIO_REG_BANK_SERDES_DIGITAL); - bnx2x_mdio22_read(bp, MDIO_SERDES_DIGITAL_MISC1, ®_val); - /* clearing the speed value before setting the right speed */ - reg_val &= ~MDIO_SERDES_DIGITAL_MISC1_FORCE_SPEED_MASK; - reg_val |= (MDIO_SERDES_DIGITAL_MISC1_REFCLK_SEL_156_25M | - MDIO_SERDES_DIGITAL_MISC1_FORCE_SPEED_SEL); - if (bp->req_line_speed == SPEED_10000) - reg_val |= - MDIO_SERDES_DIGITAL_MISC1_FORCE_SPEED_10G_CX4; - bnx2x_mdio22_write(bp, MDIO_SERDES_DIGITAL_MISC1, reg_val); - } -} - -static void bnx2x_set_brcm_cl37_advertisment(struct bnx2x *bp) -{ - u32 val = 0; - - /* configure the 48 bits for BAM AN */ - MDIO_SET_REG_BANK(bp, MDIO_REG_BANK_OVER_1G); - - /* set extended capabilities */ - if (bp->advertising & ADVERTISED_2500baseX_Full) - val |= MDIO_OVER_1G_UP1_2_5G; - if (bp->advertising & ADVERTISED_10000baseT_Full) - val |= MDIO_OVER_1G_UP1_10G; - bnx2x_mdio22_write(bp, MDIO_OVER_1G_UP1, val); - - bnx2x_mdio22_write(bp, MDIO_OVER_1G_UP3, 0); -} - -static void bnx2x_set_ieee_aneg_advertisment(struct bnx2x *bp) -{ - u32 an_adv; - - /* for AN, we are always publishing full duplex */ - an_adv = MDIO_COMBO_IEEE0_AUTO_NEG_ADV_FULL_DUPLEX; - - /* resolve pause mode and advertisement - * Please refer to Table 28B-3 of the 802.3ab-1999 spec */ - if (bp->req_autoneg & AUTONEG_FLOW_CTRL) { - switch (bp->req_flow_ctrl) { - case FLOW_CTRL_AUTO: - if (bp->dev->mtu <= 4500) { - an_adv |= - MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH; - bp->advertising |= (ADVERTISED_Pause | - ADVERTISED_Asym_Pause); - } else { - an_adv |= - MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC; - bp->advertising |= ADVERTISED_Asym_Pause; - } - break; - - case FLOW_CTRL_TX: - an_adv |= - MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC; - bp->advertising |= ADVERTISED_Asym_Pause; - break; - - case FLOW_CTRL_RX: - if (bp->dev->mtu <= 4500) { - an_adv |= - MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH; - bp->advertising |= (ADVERTISED_Pause | - ADVERTISED_Asym_Pause); - } else { - an_adv |= - MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_NONE; - bp->advertising &= ~(ADVERTISED_Pause | - ADVERTISED_Asym_Pause); - } - break; - - case FLOW_CTRL_BOTH: - if (bp->dev->mtu <= 4500) { - an_adv |= - MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH; - bp->advertising |= (ADVERTISED_Pause | - ADVERTISED_Asym_Pause); - } else { - an_adv |= - MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC; - bp->advertising |= ADVERTISED_Asym_Pause; - } - break; - - case FLOW_CTRL_NONE: - default: - an_adv |= MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_NONE; - bp->advertising &= ~(ADVERTISED_Pause | - ADVERTISED_Asym_Pause); - break; - } - } else { /* forced mode */ - switch (bp->req_flow_ctrl) { - case FLOW_CTRL_AUTO: - DP(NETIF_MSG_LINK, "req_flow_ctrl 0x%x while" - " req_autoneg 0x%x\n", - bp->req_flow_ctrl, bp->req_autoneg); - break; - - case FLOW_CTRL_TX: - an_adv |= - MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC; - bp->advertising |= ADVERTISED_Asym_Pause; - break; - - case FLOW_CTRL_RX: - case FLOW_CTRL_BOTH: - an_adv |= MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH; - bp->advertising |= (ADVERTISED_Pause | - ADVERTISED_Asym_Pause); - break; - - case FLOW_CTRL_NONE: - default: - an_adv |= MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_NONE; - bp->advertising &= ~(ADVERTISED_Pause | - ADVERTISED_Asym_Pause); - break; - } - } - - MDIO_SET_REG_BANK(bp, MDIO_REG_BANK_COMBO_IEEE0); - bnx2x_mdio22_write(bp, MDIO_COMBO_IEEE0_AUTO_NEG_ADV, an_adv); -} - -static void bnx2x_restart_autoneg(struct bnx2x *bp) -{ - if (bp->autoneg & AUTONEG_CL73) { - /* enable and restart clause 73 aneg */ - u32 an_ctrl; - - MDIO_SET_REG_BANK(bp, MDIO_REG_BANK_CL73_IEEEB0); - bnx2x_mdio22_read(bp, MDIO_CL73_IEEEB0_CL73_AN_CONTROL, - &an_ctrl); - bnx2x_mdio22_write(bp, MDIO_CL73_IEEEB0_CL73_AN_CONTROL, - (an_ctrl | - MDIO_CL73_IEEEB0_CL73_AN_CONTROL_AN_EN | - MDIO_CL73_IEEEB0_CL73_AN_CONTROL_RESTART_AN)); - - } else { - /* Enable and restart BAM/CL37 aneg */ - u32 mii_control; - - MDIO_SET_REG_BANK(bp, MDIO_REG_BANK_COMBO_IEEE0); - bnx2x_mdio22_read(bp, MDIO_COMBO_IEEE0_MII_CONTROL, - &mii_control); - bnx2x_mdio22_write(bp, MDIO_COMBO_IEEE0_MII_CONTROL, - (mii_control | - MDIO_COMBO_IEEO_MII_CONTROL_AN_EN | - MDIO_COMBO_IEEO_MII_CONTROL_RESTART_AN)); - } -} - -static void bnx2x_initialize_sgmii_process(struct bnx2x *bp) -{ - u32 control1; - - /* in SGMII mode, the unicore is always slave */ - MDIO_SET_REG_BANK(bp, MDIO_REG_BANK_SERDES_DIGITAL); - bnx2x_mdio22_read(bp, MDIO_SERDES_DIGITAL_A_1000X_CONTROL1, - &control1); - control1 |= MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_INVERT_SIGNAL_DETECT; - /* set sgmii mode (and not fiber) */ - control1 &= ~(MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_FIBER_MODE | - MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_AUTODET | - MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_MSTR_MODE); - bnx2x_mdio22_write(bp, MDIO_SERDES_DIGITAL_A_1000X_CONTROL1, - control1); - - /* if forced speed */ - if (!(bp->req_autoneg & AUTONEG_SPEED)) { - /* set speed, disable autoneg */ - u32 mii_control; - - MDIO_SET_REG_BANK(bp, MDIO_REG_BANK_COMBO_IEEE0); - bnx2x_mdio22_read(bp, MDIO_COMBO_IEEE0_MII_CONTROL, - &mii_control); - mii_control &= ~(MDIO_COMBO_IEEO_MII_CONTROL_AN_EN | - MDIO_COMBO_IEEO_MII_CONTROL_MAN_SGMII_SP_MASK | - MDIO_COMBO_IEEO_MII_CONTROL_FULL_DUPLEX); - - switch (bp->req_line_speed) { - case SPEED_100: - mii_control |= - MDIO_COMBO_IEEO_MII_CONTROL_MAN_SGMII_SP_100; - break; - case SPEED_1000: - mii_control |= - MDIO_COMBO_IEEO_MII_CONTROL_MAN_SGMII_SP_1000; - break; - case SPEED_10: - /* there is nothing to set for 10M */ - break; - default: - /* invalid speed for SGMII */ - DP(NETIF_MSG_LINK, "Invalid req_line_speed 0x%x\n", - bp->req_line_speed); - break; - } - - /* setting the full duplex */ - if (bp->req_duplex == DUPLEX_FULL) - mii_control |= - MDIO_COMBO_IEEO_MII_CONTROL_FULL_DUPLEX; - bnx2x_mdio22_write(bp, MDIO_COMBO_IEEE0_MII_CONTROL, - mii_control); - - } else { /* AN mode */ - /* enable and restart AN */ - bnx2x_restart_autoneg(bp); - } -} - -static void bnx2x_link_int_enable(struct bnx2x *bp) -{ - int port = bp->port; - u32 ext_phy_type; - u32 mask; - - /* setting the status to report on link up - for either XGXS or SerDes */ - bnx2x_bits_dis(bp, NIG_REG_STATUS_INTERRUPT_PORT0 + port*4, - (NIG_STATUS_XGXS0_LINK10G | - NIG_STATUS_XGXS0_LINK_STATUS | - NIG_STATUS_SERDES0_LINK_STATUS)); - - if (bp->phy_flags & PHY_XGXS_FLAG) { - mask = (NIG_MASK_XGXS0_LINK10G | - NIG_MASK_XGXS0_LINK_STATUS); - DP(NETIF_MSG_LINK, "enabled XGXS interrupt\n"); - ext_phy_type = XGXS_EXT_PHY_TYPE(bp); - if ((ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT) && - (ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE) && - (ext_phy_type != - PORT_HW_CFG_XGXS_EXT_PHY_TYPE_NOT_CONN)) { - mask |= NIG_MASK_MI_INT; - DP(NETIF_MSG_LINK, "enabled external phy int\n"); - } - - } else { /* SerDes */ - mask = NIG_MASK_SERDES0_LINK_STATUS; - DP(NETIF_MSG_LINK, "enabled SerDes interrupt\n"); - ext_phy_type = SERDES_EXT_PHY_TYPE(bp); - if ((ext_phy_type != - PORT_HW_CFG_SERDES_EXT_PHY_TYPE_DIRECT) && - (ext_phy_type != - PORT_HW_CFG_SERDES_EXT_PHY_TYPE_NOT_CONN)) { - mask |= NIG_MASK_MI_INT; - DP(NETIF_MSG_LINK, "enabled external phy int\n"); - } - } - bnx2x_bits_en(bp, - NIG_REG_MASK_INTERRUPT_PORT0 + port*4, - mask); - DP(NETIF_MSG_LINK, "port %x, %s, int_status 0x%x," - " int_mask 0x%x, MI_INT %x, SERDES_LINK %x," - " 10G %x, XGXS_LINK %x\n", port, - (bp->phy_flags & PHY_XGXS_FLAG)? "XGXS":"SerDes", - REG_RD(bp, NIG_REG_STATUS_INTERRUPT_PORT0 + port*4), - REG_RD(bp, NIG_REG_MASK_INTERRUPT_PORT0 + port*4), - REG_RD(bp, NIG_REG_EMAC0_STATUS_MISC_MI_INT + port*0x18), - REG_RD(bp, NIG_REG_SERDES0_STATUS_LINK_STATUS + port*0x3c), - REG_RD(bp, NIG_REG_XGXS0_STATUS_LINK10G + port*0x68), - REG_RD(bp, NIG_REG_XGXS0_STATUS_LINK_STATUS + port*0x68) - ); -} - -static void bnx2x_bcm8072_external_rom_boot(struct bnx2x *bp) -{ - u32 ext_phy_addr = ((bp->ext_phy_config & - PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >> - PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT); - u32 fw_ver1, fw_ver2; - - /* Need to wait 200ms after reset */ - msleep(200); - /* Boot port from external ROM - * Set ser_boot_ctl bit in the MISC_CTRL1 register - */ - bnx2x_mdio45_ctrl_write(bp, GRCBASE_EMAC0, ext_phy_addr, - EXT_PHY_KR_PMA_PMD_DEVAD, - EXT_PHY_KR_MISC_CTRL1, 0x0001); - - /* Reset internal microprocessor */ - bnx2x_mdio45_ctrl_write(bp, GRCBASE_EMAC0, ext_phy_addr, - EXT_PHY_KR_PMA_PMD_DEVAD, EXT_PHY_KR_GEN_CTRL, - EXT_PHY_KR_ROM_RESET_INTERNAL_MP); - /* set micro reset = 0 */ - bnx2x_mdio45_ctrl_write(bp, GRCBASE_EMAC0, ext_phy_addr, - EXT_PHY_KR_PMA_PMD_DEVAD, EXT_PHY_KR_GEN_CTRL, - EXT_PHY_KR_ROM_MICRO_RESET); - /* Reset internal microprocessor */ - bnx2x_mdio45_ctrl_write(bp, GRCBASE_EMAC0, ext_phy_addr, - EXT_PHY_KR_PMA_PMD_DEVAD, EXT_PHY_KR_GEN_CTRL, - EXT_PHY_KR_ROM_RESET_INTERNAL_MP); - /* wait for 100ms for code download via SPI port */ - msleep(100); - - /* Clear ser_boot_ctl bit */ - bnx2x_mdio45_ctrl_write(bp, GRCBASE_EMAC0, ext_phy_addr, - EXT_PHY_KR_PMA_PMD_DEVAD, - EXT_PHY_KR_MISC_CTRL1, 0x0000); - /* Wait 100ms */ - msleep(100); - - /* Print the PHY FW version */ - bnx2x_mdio45_ctrl_read(bp, GRCBASE_EMAC0, ext_phy_addr, - EXT_PHY_KR_PMA_PMD_DEVAD, - 0xca19, &fw_ver1); - bnx2x_mdio45_ctrl_read(bp, GRCBASE_EMAC0, ext_phy_addr, - EXT_PHY_KR_PMA_PMD_DEVAD, - 0xca1a, &fw_ver2); - DP(NETIF_MSG_LINK, - "8072 FW version 0x%x:0x%x\n", fw_ver1, fw_ver2); -} - -static void bnx2x_bcm8072_force_10G(struct bnx2x *bp) -{ - u32 ext_phy_addr = ((bp->ext_phy_config & - PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >> - PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT); - - /* Force KR or KX */ - bnx2x_mdio45_ctrl_write(bp, GRCBASE_EMAC0, ext_phy_addr, - EXT_PHY_KR_PMA_PMD_DEVAD, EXT_PHY_KR_CTRL, - 0x2040); - bnx2x_mdio45_ctrl_write(bp, GRCBASE_EMAC0, ext_phy_addr, - EXT_PHY_KR_PMA_PMD_DEVAD, EXT_PHY_KR_CTRL2, - 0x000b); - bnx2x_mdio45_ctrl_write(bp, GRCBASE_EMAC0, ext_phy_addr, - EXT_PHY_KR_PMA_PMD_DEVAD, EXT_PHY_KR_PMD_CTRL, - 0x0000); - bnx2x_mdio45_ctrl_write(bp, GRCBASE_EMAC0, ext_phy_addr, - EXT_PHY_KR_AUTO_NEG_DEVAD, EXT_PHY_KR_CTRL, - 0x0000); -} - -static void bnx2x_ext_phy_init(struct bnx2x *bp) -{ - u32 ext_phy_type; - u32 ext_phy_addr; - u32 cnt; - u32 ctrl; - u32 val = 0; - - if (bp->phy_flags & PHY_XGXS_FLAG) { - ext_phy_addr = ((bp->ext_phy_config & - PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >> - PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT); - - ext_phy_type = XGXS_EXT_PHY_TYPE(bp); - /* Make sure that the soft reset is off (expect for the 8072: - * due to the lock, it will be done inside the specific - * handling) - */ - if ((ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT) && - (ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE) && - (ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_NOT_CONN) && - (ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072)) { - /* Wait for soft reset to get cleared upto 1 sec */ - for (cnt = 0; cnt < 1000; cnt++) { - bnx2x_mdio45_read(bp, ext_phy_addr, - EXT_PHY_OPT_PMA_PMD_DEVAD, - EXT_PHY_OPT_CNTL, &ctrl); - if (!(ctrl & (1<<15))) - break; - msleep(1); - } - DP(NETIF_MSG_LINK, - "control reg 0x%x (after %d ms)\n", ctrl, cnt); - } - - switch (ext_phy_type) { - case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT: - DP(NETIF_MSG_LINK, "XGXS Direct\n"); - break; - - case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705: - DP(NETIF_MSG_LINK, "XGXS 8705\n"); - - bnx2x_mdio45_vwrite(bp, ext_phy_addr, - EXT_PHY_OPT_PMA_PMD_DEVAD, - EXT_PHY_OPT_PMD_MISC_CNTL, - 0x8288); - bnx2x_mdio45_vwrite(bp, ext_phy_addr, - EXT_PHY_OPT_PMA_PMD_DEVAD, - EXT_PHY_OPT_PHY_IDENTIFIER, - 0x7fbf); - bnx2x_mdio45_vwrite(bp, ext_phy_addr, - EXT_PHY_OPT_PMA_PMD_DEVAD, - EXT_PHY_OPT_CMU_PLL_BYPASS, - 0x0100); - bnx2x_mdio45_vwrite(bp, ext_phy_addr, - EXT_PHY_OPT_WIS_DEVAD, - EXT_PHY_OPT_LASI_CNTL, 0x1); - break; - - case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706: - DP(NETIF_MSG_LINK, "XGXS 8706\n"); - - if (!(bp->req_autoneg & AUTONEG_SPEED)) { - /* Force speed */ - if (bp->req_line_speed == SPEED_10000) { - DP(NETIF_MSG_LINK, - "XGXS 8706 force 10Gbps\n"); - bnx2x_mdio45_vwrite(bp, ext_phy_addr, - EXT_PHY_OPT_PMA_PMD_DEVAD, - EXT_PHY_OPT_PMD_DIGITAL_CNT, - 0x400); - } else { - /* Force 1Gbps */ - DP(NETIF_MSG_LINK, - "XGXS 8706 force 1Gbps\n"); - - bnx2x_mdio45_vwrite(bp, ext_phy_addr, - EXT_PHY_OPT_PMA_PMD_DEVAD, - EXT_PHY_OPT_CNTL, - 0x0040); - - bnx2x_mdio45_vwrite(bp, ext_phy_addr, - EXT_PHY_OPT_PMA_PMD_DEVAD, - EXT_PHY_OPT_CNTL2, - 0x000D); - } - - /* Enable LASI */ - bnx2x_mdio45_vwrite(bp, ext_phy_addr, - EXT_PHY_OPT_PMA_PMD_DEVAD, - EXT_PHY_OPT_LASI_CNTL, - 0x1); - } else { - /* AUTONEG */ - /* Allow CL37 through CL73 */ - DP(NETIF_MSG_LINK, "XGXS 8706 AutoNeg\n"); - bnx2x_mdio45_vwrite(bp, ext_phy_addr, - EXT_PHY_AUTO_NEG_DEVAD, - EXT_PHY_OPT_AN_CL37_CL73, - 0x040c); - - /* Enable Full-Duplex advertisment on CL37 */ - bnx2x_mdio45_vwrite(bp, ext_phy_addr, - EXT_PHY_AUTO_NEG_DEVAD, - EXT_PHY_OPT_AN_CL37_FD, - 0x0020); - /* Enable CL37 AN */ - bnx2x_mdio45_vwrite(bp, ext_phy_addr, - EXT_PHY_AUTO_NEG_DEVAD, - EXT_PHY_OPT_AN_CL37_AN, - 0x1000); - /* Advertise 10G/1G support */ - if (bp->advertising & - ADVERTISED_1000baseT_Full) - val = (1<<5); - if (bp->advertising & - ADVERTISED_10000baseT_Full) - val |= (1<<7); - - bnx2x_mdio45_vwrite(bp, ext_phy_addr, - EXT_PHY_AUTO_NEG_DEVAD, - EXT_PHY_OPT_AN_ADV, val); - /* Enable LASI */ - bnx2x_mdio45_vwrite(bp, ext_phy_addr, - EXT_PHY_OPT_PMA_PMD_DEVAD, - EXT_PHY_OPT_LASI_CNTL, - 0x1); - - /* Enable clause 73 AN */ - bnx2x_mdio45_write(bp, ext_phy_addr, - EXT_PHY_AUTO_NEG_DEVAD, - EXT_PHY_OPT_CNTL, - 0x1200); - } - break; - - case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072: - bnx2x_hw_lock(bp, HW_LOCK_RESOURCE_8072_MDIO); - /* Wait for soft reset to get cleared upto 1 sec */ - for (cnt = 0; cnt < 1000; cnt++) { - bnx2x_mdio45_ctrl_read(bp, GRCBASE_EMAC0, - ext_phy_addr, - EXT_PHY_OPT_PMA_PMD_DEVAD, - EXT_PHY_OPT_CNTL, &ctrl); - if (!(ctrl & (1<<15))) - break; - msleep(1); - } - DP(NETIF_MSG_LINK, - "8072 control reg 0x%x (after %d ms)\n", - ctrl, cnt); - - bnx2x_bcm8072_external_rom_boot(bp); - DP(NETIF_MSG_LINK, "Finshed loading 8072 KR ROM\n"); - - /* enable LASI */ - bnx2x_mdio45_ctrl_write(bp, GRCBASE_EMAC0, - ext_phy_addr, - EXT_PHY_KR_PMA_PMD_DEVAD, - 0x9000, 0x0400); - bnx2x_mdio45_ctrl_write(bp, GRCBASE_EMAC0, - ext_phy_addr, - EXT_PHY_KR_PMA_PMD_DEVAD, - EXT_PHY_KR_LASI_CNTL, 0x0004); - - /* If this is forced speed, set to KR or KX - * (all other are not supported) - */ - if (!(bp->req_autoneg & AUTONEG_SPEED)) { - if (bp->req_line_speed == SPEED_10000) { - bnx2x_bcm8072_force_10G(bp); - DP(NETIF_MSG_LINK, - "Forced speed 10G on 8072\n"); - /* unlock */ - bnx2x_hw_unlock(bp, - HW_LOCK_RESOURCE_8072_MDIO); - break; - } else - val = (1<<5); - } else { - - /* Advertise 10G/1G support */ - if (bp->advertising & - ADVERTISED_1000baseT_Full) - val = (1<<5); - if (bp->advertising & - ADVERTISED_10000baseT_Full) - val |= (1<<7); - } - bnx2x_mdio45_ctrl_write(bp, GRCBASE_EMAC0, - ext_phy_addr, - EXT_PHY_KR_AUTO_NEG_DEVAD, - 0x11, val); - /* Add support for CL37 ( passive mode ) I */ - bnx2x_mdio45_ctrl_write(bp, GRCBASE_EMAC0, - ext_phy_addr, - EXT_PHY_KR_AUTO_NEG_DEVAD, - 0x8370, 0x040c); - /* Add support for CL37 ( passive mode ) II */ - bnx2x_mdio45_ctrl_write(bp, GRCBASE_EMAC0, - ext_phy_addr, - EXT_PHY_KR_AUTO_NEG_DEVAD, - 0xffe4, 0x20); - /* Add support for CL37 ( passive mode ) III */ - bnx2x_mdio45_ctrl_write(bp, GRCBASE_EMAC0, - ext_phy_addr, - EXT_PHY_KR_AUTO_NEG_DEVAD, - 0xffe0, 0x1000); - /* Restart autoneg */ - msleep(500); - bnx2x_mdio45_ctrl_write(bp, GRCBASE_EMAC0, - ext_phy_addr, - EXT_PHY_KR_AUTO_NEG_DEVAD, - EXT_PHY_KR_CTRL, 0x1200); - DP(NETIF_MSG_LINK, "8072 Autoneg Restart: " - "1G %ssupported 10G %ssupported\n", - (val & (1<<5)) ? "" : "not ", - (val & (1<<7)) ? "" : "not "); - - /* unlock */ - bnx2x_hw_unlock(bp, HW_LOCK_RESOURCE_8072_MDIO); - break; - - case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101: - DP(NETIF_MSG_LINK, - "Setting the SFX7101 LASI indication\n"); - bnx2x_mdio45_vwrite(bp, ext_phy_addr, - EXT_PHY_OPT_PMA_PMD_DEVAD, - EXT_PHY_OPT_LASI_CNTL, 0x1); - DP(NETIF_MSG_LINK, - "Setting the SFX7101 LED to blink on traffic\n"); - bnx2x_mdio45_vwrite(bp, ext_phy_addr, - EXT_PHY_OPT_PMA_PMD_DEVAD, - 0xC007, (1<<3)); - - /* read modify write pause advertizing */ - bnx2x_mdio45_read(bp, ext_phy_addr, - EXT_PHY_KR_AUTO_NEG_DEVAD, - EXT_PHY_KR_AUTO_NEG_ADVERT, &val); - val &= ~EXT_PHY_KR_AUTO_NEG_ADVERT_PAUSE_BOTH; - /* Please refer to Table 28B-3 of 802.3ab-1999 spec. */ - if (bp->advertising & ADVERTISED_Pause) - val |= EXT_PHY_KR_AUTO_NEG_ADVERT_PAUSE; - - if (bp->advertising & ADVERTISED_Asym_Pause) { - val |= - EXT_PHY_KR_AUTO_NEG_ADVERT_PAUSE_ASYMMETRIC; - } - DP(NETIF_MSG_LINK, "SFX7101 AN advertize 0x%x\n", val); - bnx2x_mdio45_vwrite(bp, ext_phy_addr, - EXT_PHY_KR_AUTO_NEG_DEVAD, - EXT_PHY_KR_AUTO_NEG_ADVERT, val); - /* Restart autoneg */ - bnx2x_mdio45_read(bp, ext_phy_addr, - EXT_PHY_KR_AUTO_NEG_DEVAD, - EXT_PHY_KR_CTRL, &val); - val |= 0x200; - bnx2x_mdio45_write(bp, ext_phy_addr, - EXT_PHY_KR_AUTO_NEG_DEVAD, - EXT_PHY_KR_CTRL, val); - break; - - default: - BNX2X_ERR("BAD XGXS ext_phy_config 0x%x\n", - bp->ext_phy_config); - break; - } - - } else { /* SerDes */ -/* ext_phy_addr = ((bp->ext_phy_config & - PORT_HW_CFG_SERDES_EXT_PHY_ADDR_MASK) >> - PORT_HW_CFG_SERDES_EXT_PHY_ADDR_SHIFT); -*/ - ext_phy_type = SERDES_EXT_PHY_TYPE(bp); - switch (ext_phy_type) { - case PORT_HW_CFG_SERDES_EXT_PHY_TYPE_DIRECT: - DP(NETIF_MSG_LINK, "SerDes Direct\n"); - break; - - case PORT_HW_CFG_SERDES_EXT_PHY_TYPE_BCM5482: - DP(NETIF_MSG_LINK, "SerDes 5482\n"); - break; - - default: - DP(NETIF_MSG_LINK, "BAD SerDes ext_phy_config 0x%x\n", - bp->ext_phy_config); - break; - } - } -} - -static void bnx2x_ext_phy_reset(struct bnx2x *bp) -{ - u32 ext_phy_type; - u32 ext_phy_addr = ((bp->ext_phy_config & - PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >> - PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT); - u32 board = (bp->board & SHARED_HW_CFG_BOARD_TYPE_MASK); - - /* The PHY reset is controled by GPIO 1 - * Give it 1ms of reset pulse - */ - if ((board != SHARED_HW_CFG_BOARD_TYPE_BCM957710T1002G) && - (board != SHARED_HW_CFG_BOARD_TYPE_BCM957710T1003G)) { - bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1, - MISC_REGISTERS_GPIO_OUTPUT_LOW); - msleep(1); - bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1, - MISC_REGISTERS_GPIO_OUTPUT_HIGH); - } - - if (bp->phy_flags & PHY_XGXS_FLAG) { - ext_phy_type = XGXS_EXT_PHY_TYPE(bp); - switch (ext_phy_type) { - case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT: - DP(NETIF_MSG_LINK, "XGXS Direct\n"); - break; - - case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705: - case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706: - DP(NETIF_MSG_LINK, "XGXS 8705/8706\n"); - bnx2x_mdio45_write(bp, ext_phy_addr, - EXT_PHY_OPT_PMA_PMD_DEVAD, - EXT_PHY_OPT_CNTL, 0xa040); - break; - - case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072: - DP(NETIF_MSG_LINK, "XGXS 8072\n"); - bnx2x_hw_lock(bp, HW_LOCK_RESOURCE_8072_MDIO); - bnx2x_mdio45_ctrl_write(bp, GRCBASE_EMAC0, - ext_phy_addr, - EXT_PHY_KR_PMA_PMD_DEVAD, - 0, 1<<15); - bnx2x_hw_unlock(bp, HW_LOCK_RESOURCE_8072_MDIO); - break; - - case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101: - DP(NETIF_MSG_LINK, "XGXS SFX7101\n"); - break; - - default: - DP(NETIF_MSG_LINK, "BAD XGXS ext_phy_config 0x%x\n", - bp->ext_phy_config); - break; - } - - } else { /* SerDes */ - ext_phy_type = SERDES_EXT_PHY_TYPE(bp); - switch (ext_phy_type) { - case PORT_HW_CFG_SERDES_EXT_PHY_TYPE_DIRECT: - DP(NETIF_MSG_LINK, "SerDes Direct\n"); - break; - - case PORT_HW_CFG_SERDES_EXT_PHY_TYPE_BCM5482: - DP(NETIF_MSG_LINK, "SerDes 5482\n"); - break; - - default: - DP(NETIF_MSG_LINK, "BAD SerDes ext_phy_config 0x%x\n", - bp->ext_phy_config); - break; - } - } -} - -static void bnx2x_link_initialize(struct bnx2x *bp) -{ - int port = bp->port; - - /* disable attentions */ - bnx2x_bits_dis(bp, NIG_REG_MASK_INTERRUPT_PORT0 + port*4, - (NIG_MASK_XGXS0_LINK_STATUS | - NIG_MASK_XGXS0_LINK10G | - NIG_MASK_SERDES0_LINK_STATUS | - NIG_MASK_MI_INT)); - - /* Activate the external PHY */ - bnx2x_ext_phy_reset(bp); - - bnx2x_set_aer_mmd(bp); - - if (bp->phy_flags & PHY_XGXS_FLAG) - bnx2x_set_master_ln(bp); - - /* reset the SerDes and wait for reset bit return low */ - bnx2x_reset_unicore(bp); - - bnx2x_set_aer_mmd(bp); - - /* setting the masterLn_def again after the reset */ - if (bp->phy_flags & PHY_XGXS_FLAG) { - bnx2x_set_master_ln(bp); - bnx2x_set_swap_lanes(bp); - } - - /* Set Parallel Detect */ - if (bp->req_autoneg & AUTONEG_SPEED) - bnx2x_set_parallel_detection(bp); - - if (bp->phy_flags & PHY_XGXS_FLAG) { - if (bp->req_line_speed && - bp->req_line_speed < SPEED_1000) { - bp->phy_flags |= PHY_SGMII_FLAG; - } else { - bp->phy_flags &= ~PHY_SGMII_FLAG; - } - } - - if (!(bp->phy_flags & PHY_SGMII_FLAG)) { - u16 bank, rx_eq; - - rx_eq = ((bp->serdes_config & - PORT_HW_CFG_SERDES_RX_DRV_EQUALIZER_MASK) >> - PORT_HW_CFG_SERDES_RX_DRV_EQUALIZER_SHIFT); - - DP(NETIF_MSG_LINK, "setting rx eq to %d\n", rx_eq); - for (bank = MDIO_REG_BANK_RX0; bank <= MDIO_REG_BANK_RX_ALL; - bank += (MDIO_REG_BANK_RX1 - MDIO_REG_BANK_RX0)) { - MDIO_SET_REG_BANK(bp, bank); - bnx2x_mdio22_write(bp, MDIO_RX0_RX_EQ_BOOST, - ((rx_eq & - MDIO_RX0_RX_EQ_BOOST_EQUALIZER_CTRL_MASK) | - MDIO_RX0_RX_EQ_BOOST_OFFSET_CTRL)); - } - - /* forced speed requested? */ - if (!(bp->req_autoneg & AUTONEG_SPEED)) { - DP(NETIF_MSG_LINK, "not SGMII, no AN\n"); - - /* disable autoneg */ - bnx2x_set_autoneg(bp); - - /* program speed and duplex */ - bnx2x_program_serdes(bp); - - } else { /* AN_mode */ - DP(NETIF_MSG_LINK, "not SGMII, AN\n"); - - /* AN enabled */ - bnx2x_set_brcm_cl37_advertisment(bp); - - /* program duplex & pause advertisement (for aneg) */ - bnx2x_set_ieee_aneg_advertisment(bp); - - /* enable autoneg */ - bnx2x_set_autoneg(bp); - - /* enable and restart AN */ - bnx2x_restart_autoneg(bp); - } - - } else { /* SGMII mode */ - DP(NETIF_MSG_LINK, "SGMII\n"); - - bnx2x_initialize_sgmii_process(bp); - } - - /* init ext phy and enable link state int */ - bnx2x_ext_phy_init(bp); - - /* enable the interrupt */ - bnx2x_link_int_enable(bp); -} - -static void bnx2x_phy_deassert(struct bnx2x *bp) -{ - int port = bp->port; - u32 val; - - if (bp->phy_flags & PHY_XGXS_FLAG) { - DP(NETIF_MSG_LINK, "XGXS\n"); - val = XGXS_RESET_BITS; - - } else { /* SerDes */ - DP(NETIF_MSG_LINK, "SerDes\n"); - val = SERDES_RESET_BITS; - } - - val = val << (port*16); - - /* reset and unreset the SerDes/XGXS */ - REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_3_CLEAR, val); - msleep(5); - REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_3_SET, val); -} - -static int bnx2x_phy_init(struct bnx2x *bp) -{ - DP(NETIF_MSG_LINK, "started\n"); - if (CHIP_REV(bp) == CHIP_REV_FPGA) { - bp->phy_flags |= PHY_EMAC_FLAG; - bp->link_up = 1; - bp->line_speed = SPEED_10000; - bp->duplex = DUPLEX_FULL; - NIG_WR(NIG_REG_EGRESS_DRAIN0_MODE + bp->port*4, 0); - bnx2x_emac_enable(bp); - bnx2x_link_report(bp); - return 0; - - } else if (CHIP_REV(bp) == CHIP_REV_EMUL) { - bp->phy_flags |= PHY_BMAC_FLAG; - bp->link_up = 1; - bp->line_speed = SPEED_10000; - bp->duplex = DUPLEX_FULL; - NIG_WR(NIG_REG_EGRESS_DRAIN0_MODE + bp->port*4, 0); - bnx2x_bmac_enable(bp, 0); - bnx2x_link_report(bp); - return 0; - - } else { - bnx2x_phy_deassert(bp); - bnx2x_link_initialize(bp); - } - - return 0; -} - -static void bnx2x_link_reset(struct bnx2x *bp) -{ - int port = bp->port; - u32 board = (bp->board & SHARED_HW_CFG_BOARD_TYPE_MASK); - - /* update shared memory */ - bp->link_status = 0; - bnx2x_update_mng(bp); - - /* disable attentions */ - bnx2x_bits_dis(bp, NIG_REG_MASK_INTERRUPT_PORT0 + port*4, - (NIG_MASK_XGXS0_LINK_STATUS | - NIG_MASK_XGXS0_LINK10G | - NIG_MASK_SERDES0_LINK_STATUS | - NIG_MASK_MI_INT)); - - /* activate nig drain */ - NIG_WR(NIG_REG_EGRESS_DRAIN0_MODE + port*4, 1); - - /* disable nig egress interface */ - NIG_WR(NIG_REG_BMAC0_OUT_EN + port*4, 0); - NIG_WR(NIG_REG_EGRESS_EMAC0_OUT_EN + port*4, 0); - - /* Stop BigMac rx */ - bnx2x_bmac_rx_disable(bp); - - /* disable emac */ - NIG_WR(NIG_REG_NIG_EMAC0_EN + port*4, 0); - - msleep(10); - - /* The PHY reset is controled by GPIO 1 - * Hold it as output low - */ - if ((board != SHARED_HW_CFG_BOARD_TYPE_BCM957710T1002G) && - (board != SHARED_HW_CFG_BOARD_TYPE_BCM957710T1003G)) { - bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1, - MISC_REGISTERS_GPIO_OUTPUT_LOW); - DP(NETIF_MSG_LINK, "reset external PHY\n"); - } - - /* reset the SerDes/XGXS */ - REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_3_CLEAR, - (0x1ff << (port*16))); - - /* reset BigMac */ - REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_CLEAR, - (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port)); - - /* disable nig ingress interface */ - NIG_WR(NIG_REG_BMAC0_IN_EN + port*4, 0); - NIG_WR(NIG_REG_EMAC0_IN_EN + port*4, 0); - - /* set link down */ - bp->link_up = 0; -} - -#ifdef BNX2X_XGXS_LB -static void bnx2x_set_xgxs_loopback(struct bnx2x *bp, int is_10g) -{ - int port = bp->port; - - if (is_10g) { - u32 md_devad; - - DP(NETIF_MSG_LINK, "XGXS 10G loopback enable\n"); - - /* change the uni_phy_addr in the nig */ - REG_RD(bp, (NIG_REG_XGXS0_CTRL_MD_DEVAD + port*0x18), - &md_devad); - NIG_WR(NIG_REG_XGXS0_CTRL_MD_DEVAD + port*0x18, 0x5); - - /* change the aer mmd */ - MDIO_SET_REG_BANK(bp, MDIO_REG_BANK_AER_BLOCK); - bnx2x_mdio22_write(bp, MDIO_AER_BLOCK_AER_REG, 0x2800); - - /* config combo IEEE0 control reg for loopback */ - MDIO_SET_REG_BANK(bp, MDIO_REG_BANK_CL73_IEEEB0); - bnx2x_mdio22_write(bp, MDIO_CL73_IEEEB0_CL73_AN_CONTROL, - 0x6041); - - /* set aer mmd back */ - bnx2x_set_aer_mmd(bp); - - /* and md_devad */ - NIG_WR(NIG_REG_XGXS0_CTRL_MD_DEVAD + port*0x18, md_devad); - - } else { - u32 mii_control; - - DP(NETIF_MSG_LINK, "XGXS 1G loopback enable\n"); - - MDIO_SET_REG_BANK(bp, MDIO_REG_BANK_COMBO_IEEE0); - bnx2x_mdio22_read(bp, MDIO_COMBO_IEEE0_MII_CONTROL, - &mii_control); - bnx2x_mdio22_write(bp, MDIO_COMBO_IEEE0_MII_CONTROL, - (mii_control | - MDIO_COMBO_IEEO_MII_CONTROL_LOOPBACK)); - } -} -#endif - -/* end of PHY/MAC */ - -/* slow path */ - -/* - * General service functions - */ - -/* the slow path queue is odd since completions arrive on the fastpath ring */ -static int bnx2x_sp_post(struct bnx2x *bp, int command, int cid, - u32 data_hi, u32 data_lo, int common) -{ - int port = bp->port; - - DP(NETIF_MSG_TIMER, - "spe (%x:%x) command %d hw_cid %x data (%x:%x) left %x\n", - (u32)U64_HI(bp->spq_mapping), (u32)(U64_LO(bp->spq_mapping) + - (void *)bp->spq_prod_bd - (void *)bp->spq), command, - HW_CID(bp, cid), data_hi, data_lo, bp->spq_left); - -#ifdef BNX2X_STOP_ON_ERROR - if (unlikely(bp->panic)) - return -EIO; -#endif - - spin_lock(&bp->spq_lock); - - if (!bp->spq_left) { - BNX2X_ERR("BUG! SPQ ring full!\n"); - spin_unlock(&bp->spq_lock); - bnx2x_panic(); - return -EBUSY; - } - - /* CID needs port number to be encoded int it */ - bp->spq_prod_bd->hdr.conn_and_cmd_data = - cpu_to_le32(((command << SPE_HDR_CMD_ID_SHIFT) | - HW_CID(bp, cid))); - bp->spq_prod_bd->hdr.type = cpu_to_le16(ETH_CONNECTION_TYPE); - if (common) - bp->spq_prod_bd->hdr.type |= - cpu_to_le16((1 << SPE_HDR_COMMON_RAMROD_SHIFT)); - - bp->spq_prod_bd->data.mac_config_addr.hi = cpu_to_le32(data_hi); - bp->spq_prod_bd->data.mac_config_addr.lo = cpu_to_le32(data_lo); - - bp->spq_left--; - - if (bp->spq_prod_bd == bp->spq_last_bd) { - bp->spq_prod_bd = bp->spq; - bp->spq_prod_idx = 0; - DP(NETIF_MSG_TIMER, "end of spq\n"); - - } else { - bp->spq_prod_bd++; - bp->spq_prod_idx++; - } - - REG_WR(bp, BAR_XSTRORM_INTMEM + XSTORM_SPQ_PROD_OFFSET(port), - bp->spq_prod_idx); - - spin_unlock(&bp->spq_lock); - return 0; -} - -/* acquire split MCP access lock register */ -static int bnx2x_lock_alr(struct bnx2x *bp) -{ - int rc = 0; - u32 i, j, val; - - might_sleep(); - i = 100; - for (j = 0; j < i*10; j++) { - val = (1UL << 31); - REG_WR(bp, GRCBASE_MCP + 0x9c, val); - val = REG_RD(bp, GRCBASE_MCP + 0x9c); - if (val & (1L << 31)) - break; - - msleep(5); - } - - if (!(val & (1L << 31))) { - BNX2X_ERR("Cannot acquire nvram interface\n"); - - rc = -EBUSY; - } - - return rc; -} - -/* Release split MCP access lock register */ -static void bnx2x_unlock_alr(struct bnx2x *bp) -{ - u32 val = 0; - - REG_WR(bp, GRCBASE_MCP + 0x9c, val); -} - -static inline u16 bnx2x_update_dsb_idx(struct bnx2x *bp) -{ - struct host_def_status_block *def_sb = bp->def_status_blk; - u16 rc = 0; - - barrier(); /* status block is written to by the chip */ - - if (bp->def_att_idx != def_sb->atten_status_block.attn_bits_index) { - bp->def_att_idx = def_sb->atten_status_block.attn_bits_index; - rc |= 1; - } - if (bp->def_c_idx != def_sb->c_def_status_block.status_block_index) { - bp->def_c_idx = def_sb->c_def_status_block.status_block_index; - rc |= 2; - } - if (bp->def_u_idx != def_sb->u_def_status_block.status_block_index) { - bp->def_u_idx = def_sb->u_def_status_block.status_block_index; - rc |= 4; - } - if (bp->def_x_idx != def_sb->x_def_status_block.status_block_index) { - bp->def_x_idx = def_sb->x_def_status_block.status_block_index; - rc |= 8; - } - if (bp->def_t_idx != def_sb->t_def_status_block.status_block_index) { - bp->def_t_idx = def_sb->t_def_status_block.status_block_index; - rc |= 16; - } - return rc; -} - -/* - * slow path service functions - */ - -static void bnx2x_attn_int_asserted(struct bnx2x *bp, u32 asserted) -{ - int port = bp->port; - u32 igu_addr = (IGU_ADDR_ATTN_BITS_SET + IGU_PORT_BASE * port) * 8; - u32 aeu_addr = port ? MISC_REG_AEU_MASK_ATTN_FUNC_1 : - MISC_REG_AEU_MASK_ATTN_FUNC_0; - u32 nig_int_mask_addr = port ? NIG_REG_MASK_INTERRUPT_PORT1 : - NIG_REG_MASK_INTERRUPT_PORT0; - - if (~bp->aeu_mask & (asserted & 0xff)) - BNX2X_ERR("IGU ERROR\n"); - if (bp->attn_state & asserted) - BNX2X_ERR("IGU ERROR\n"); - - DP(NETIF_MSG_HW, "aeu_mask %x newly asserted %x\n", - bp->aeu_mask, asserted); - bp->aeu_mask &= ~(asserted & 0xff); - DP(NETIF_MSG_HW, "after masking: aeu_mask %x\n", bp->aeu_mask); - - REG_WR(bp, aeu_addr, bp->aeu_mask); - - bp->attn_state |= asserted; - - if (asserted & ATTN_HARD_WIRED_MASK) { - if (asserted & ATTN_NIG_FOR_FUNC) { - - /* save nig interrupt mask */ - bp->nig_mask = REG_RD(bp, nig_int_mask_addr); - REG_WR(bp, nig_int_mask_addr, 0); - - bnx2x_link_update(bp); - - /* handle unicore attn? */ - } - if (asserted & ATTN_SW_TIMER_4_FUNC) - DP(NETIF_MSG_HW, "ATTN_SW_TIMER_4_FUNC!\n"); - - if (asserted & GPIO_2_FUNC) - DP(NETIF_MSG_HW, "GPIO_2_FUNC!\n"); - - if (asserted & GPIO_3_FUNC) - DP(NETIF_MSG_HW, "GPIO_3_FUNC!\n"); - - if (asserted & GPIO_4_FUNC) - DP(NETIF_MSG_HW, "GPIO_4_FUNC!\n"); - - if (port == 0) { - if (asserted & ATTN_GENERAL_ATTN_1) { - DP(NETIF_MSG_HW, "ATTN_GENERAL_ATTN_1!\n"); - REG_WR(bp, MISC_REG_AEU_GENERAL_ATTN_1, 0x0); - } - if (asserted & ATTN_GENERAL_ATTN_2) { - DP(NETIF_MSG_HW, "ATTN_GENERAL_ATTN_2!\n"); - REG_WR(bp, MISC_REG_AEU_GENERAL_ATTN_2, 0x0); - } - if (asserted & ATTN_GENERAL_ATTN_3) { - DP(NETIF_MSG_HW, "ATTN_GENERAL_ATTN_3!\n"); - REG_WR(bp, MISC_REG_AEU_GENERAL_ATTN_3, 0x0); - } - } else { - if (asserted & ATTN_GENERAL_ATTN_4) { - DP(NETIF_MSG_HW, "ATTN_GENERAL_ATTN_4!\n"); - REG_WR(bp, MISC_REG_AEU_GENERAL_ATTN_4, 0x0); - } - if (asserted & ATTN_GENERAL_ATTN_5) { - DP(NETIF_MSG_HW, "ATTN_GENERAL_ATTN_5!\n"); - REG_WR(bp, MISC_REG_AEU_GENERAL_ATTN_5, 0x0); - } - if (asserted & ATTN_GENERAL_ATTN_6) { - DP(NETIF_MSG_HW, "ATTN_GENERAL_ATTN_6!\n"); - REG_WR(bp, MISC_REG_AEU_GENERAL_ATTN_6, 0x0); - } - } - - } /* if hardwired */ - - DP(NETIF_MSG_HW, "about to mask 0x%08x at IGU addr 0x%x\n", - asserted, BAR_IGU_INTMEM + igu_addr); - REG_WR(bp, BAR_IGU_INTMEM + igu_addr, asserted); - - /* now set back the mask */ - if (asserted & ATTN_NIG_FOR_FUNC) - REG_WR(bp, nig_int_mask_addr, bp->nig_mask); -} - -static inline void bnx2x_attn_int_deasserted0(struct bnx2x *bp, u32 attn) -{ - int port = bp->port; - int reg_offset; - u32 val; - - if (attn & AEU_INPUTS_ATTN_BITS_SPIO5) { - - reg_offset = (port ? MISC_REG_AEU_ENABLE1_FUNC_1_OUT_0 : - MISC_REG_AEU_ENABLE1_FUNC_0_OUT_0); - - val = REG_RD(bp, reg_offset); - val &= ~AEU_INPUTS_ATTN_BITS_SPIO5; - REG_WR(bp, reg_offset, val); - - BNX2X_ERR("SPIO5 hw attention\n"); - - switch (bp->board & SHARED_HW_CFG_BOARD_TYPE_MASK) { - case SHARED_HW_CFG_BOARD_TYPE_BCM957710A1022G: - /* Fan failure attention */ - - /* The PHY reset is controled by GPIO 1 */ - bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1, - MISC_REGISTERS_GPIO_OUTPUT_LOW); - /* Low power mode is controled by GPIO 2 */ - bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2, - MISC_REGISTERS_GPIO_OUTPUT_LOW); - /* mark the failure */ - bp->ext_phy_config &= - ~PORT_HW_CFG_XGXS_EXT_PHY_TYPE_MASK; - bp->ext_phy_config |= - PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE; - SHMEM_WR(bp, - dev_info.port_hw_config[port]. - external_phy_config, - bp->ext_phy_config); - /* log the failure */ - printk(KERN_ERR PFX "Fan Failure on Network" - " Controller %s has caused the driver to" - " shutdown the card to prevent permanent" - " damage. Please contact Dell Support for" - " assistance\n", bp->dev->name); - break; - - default: - break; - } - } -} - -static inline void bnx2x_attn_int_deasserted1(struct bnx2x *bp, u32 attn) -{ - u32 val; - - if (attn & BNX2X_DOORQ_ASSERT) { - - val = REG_RD(bp, DORQ_REG_DORQ_INT_STS_CLR); - BNX2X_ERR("DB hw attention 0x%x\n", val); - /* DORQ discard attention */ - if (val & 0x2) - BNX2X_ERR("FATAL error from DORQ\n"); - } -} - -static inline void bnx2x_attn_int_deasserted2(struct bnx2x *bp, u32 attn) -{ - u32 val; - - if (attn & AEU_INPUTS_ATTN_BITS_CFC_HW_INTERRUPT) { - - val = REG_RD(bp, CFC_REG_CFC_INT_STS_CLR); - BNX2X_ERR("CFC hw attention 0x%x\n", val); - /* CFC error attention */ - if (val & 0x2) - BNX2X_ERR("FATAL error from CFC\n"); - } - - if (attn & AEU_INPUTS_ATTN_BITS_PXP_HW_INTERRUPT) { - - val = REG_RD(bp, PXP_REG_PXP_INT_STS_CLR_0); - BNX2X_ERR("PXP hw attention 0x%x\n", val); - /* RQ_USDMDP_FIFO_OVERFLOW */ - if (val & 0x18000) - BNX2X_ERR("FATAL error from PXP\n"); - } -} - -static inline void bnx2x_attn_int_deasserted3(struct bnx2x *bp, u32 attn) -{ - if (attn & EVEREST_GEN_ATTN_IN_USE_MASK) { - - if (attn & BNX2X_MC_ASSERT_BITS) { - - BNX2X_ERR("MC assert!\n"); - REG_WR(bp, MISC_REG_AEU_GENERAL_ATTN_10, 0); - REG_WR(bp, MISC_REG_AEU_GENERAL_ATTN_9, 0); - REG_WR(bp, MISC_REG_AEU_GENERAL_ATTN_8, 0); - REG_WR(bp, MISC_REG_AEU_GENERAL_ATTN_7, 0); - bnx2x_panic(); - - } else if (attn & BNX2X_MCP_ASSERT) { - - BNX2X_ERR("MCP assert!\n"); - REG_WR(bp, MISC_REG_AEU_GENERAL_ATTN_11, 0); - bnx2x_mc_assert(bp); - - } else - BNX2X_ERR("Unknown HW assert! (attn 0x%x)\n", attn); - } - - if (attn & EVEREST_LATCHED_ATTN_IN_USE_MASK) { - - REG_WR(bp, MISC_REG_AEU_CLR_LATCH_SIGNAL, 0x7ff); - BNX2X_ERR("LATCHED attention 0x%x (masked)\n", attn); - } -} - -static void bnx2x_attn_int_deasserted(struct bnx2x *bp, u32 deasserted) -{ - struct attn_route attn; - struct attn_route group_mask; - int port = bp->port; - int index; - u32 reg_addr; - u32 val; - - /* need to take HW lock because MCP or other port might also - try to handle this event */ - bnx2x_lock_alr(bp); - - attn.sig[0] = REG_RD(bp, MISC_REG_AEU_AFTER_INVERT_1_FUNC_0 + port*4); - attn.sig[1] = REG_RD(bp, MISC_REG_AEU_AFTER_INVERT_2_FUNC_0 + port*4); - attn.sig[2] = REG_RD(bp, MISC_REG_AEU_AFTER_INVERT_3_FUNC_0 + port*4); - attn.sig[3] = REG_RD(bp, MISC_REG_AEU_AFTER_INVERT_4_FUNC_0 + port*4); - DP(NETIF_MSG_HW, "attn %llx\n", (unsigned long long)attn.sig[0]); - - for (index = 0; index < MAX_DYNAMIC_ATTN_GRPS; index++) { - if (deasserted & (1 << index)) { - group_mask = bp->attn_group[index]; - - DP(NETIF_MSG_HW, "group[%d]: %llx\n", index, - (unsigned long long)group_mask.sig[0]); - - bnx2x_attn_int_deasserted3(bp, - attn.sig[3] & group_mask.sig[3]); - bnx2x_attn_int_deasserted1(bp, - attn.sig[1] & group_mask.sig[1]); - bnx2x_attn_int_deasserted2(bp, - attn.sig[2] & group_mask.sig[2]); - bnx2x_attn_int_deasserted0(bp, - attn.sig[0] & group_mask.sig[0]); - - if ((attn.sig[0] & group_mask.sig[0] & - HW_INTERRUT_ASSERT_SET_0) || - (attn.sig[1] & group_mask.sig[1] & - HW_INTERRUT_ASSERT_SET_1) || - (attn.sig[2] & group_mask.sig[2] & - HW_INTERRUT_ASSERT_SET_2)) - BNX2X_ERR("FATAL HW block attention" - " set0 0x%x set1 0x%x" - " set2 0x%x\n", - (attn.sig[0] & group_mask.sig[0] & - HW_INTERRUT_ASSERT_SET_0), - (attn.sig[1] & group_mask.sig[1] & - HW_INTERRUT_ASSERT_SET_1), - (attn.sig[2] & group_mask.sig[2] & - HW_INTERRUT_ASSERT_SET_2)); - - if ((attn.sig[0] & group_mask.sig[0] & - HW_PRTY_ASSERT_SET_0) || - (attn.sig[1] & group_mask.sig[1] & - HW_PRTY_ASSERT_SET_1) || - (attn.sig[2] & group_mask.sig[2] & - HW_PRTY_ASSERT_SET_2)) - BNX2X_ERR("FATAL HW block parity attention\n"); - } - } - - bnx2x_unlock_alr(bp); - - reg_addr = (IGU_ADDR_ATTN_BITS_CLR + IGU_PORT_BASE * port) * 8; - - val = ~deasserted; -/* DP(NETIF_MSG_INTR, "write 0x%08x to IGU addr 0x%x\n", - val, BAR_IGU_INTMEM + reg_addr); */ - REG_WR(bp, BAR_IGU_INTMEM + reg_addr, val); - - if (bp->aeu_mask & (deasserted & 0xff)) - BNX2X_ERR("IGU BUG\n"); - if (~bp->attn_state & deasserted) - BNX2X_ERR("IGU BUG\n"); - - reg_addr = port ? MISC_REG_AEU_MASK_ATTN_FUNC_1 : - MISC_REG_AEU_MASK_ATTN_FUNC_0; - - DP(NETIF_MSG_HW, "aeu_mask %x\n", bp->aeu_mask); - bp->aeu_mask |= (deasserted & 0xff); - - DP(NETIF_MSG_HW, "new mask %x\n", bp->aeu_mask); - REG_WR(bp, reg_addr, bp->aeu_mask); - - DP(NETIF_MSG_HW, "attn_state %x\n", bp->attn_state); - bp->attn_state &= ~deasserted; - DP(NETIF_MSG_HW, "new state %x\n", bp->attn_state); -} - -static void bnx2x_attn_int(struct bnx2x *bp) -{ - /* read local copy of bits */ - u32 attn_bits = bp->def_status_blk->atten_status_block.attn_bits; - u32 attn_ack = bp->def_status_blk->atten_status_block.attn_bits_ack; - u32 attn_state = bp->attn_state; - - /* look for changed bits */ - u32 asserted = attn_bits & ~attn_ack & ~attn_state; - u32 deasserted = ~attn_bits & attn_ack & attn_state; - - DP(NETIF_MSG_HW, - "attn_bits %x attn_ack %x asserted %x deasserted %x\n", - attn_bits, attn_ack, asserted, deasserted); - - if (~(attn_bits ^ attn_ack) & (attn_bits ^ attn_state)) - BNX2X_ERR("bad attention state\n"); - - /* handle bits that were raised */ - if (asserted) - bnx2x_attn_int_asserted(bp, asserted); - - if (deasserted) - bnx2x_attn_int_deasserted(bp, deasserted); -} - -static void bnx2x_sp_task(struct work_struct *work) -{ - struct bnx2x *bp = container_of(work, struct bnx2x, sp_task); - u16 status; - - /* Return here if interrupt is disabled */ - if (unlikely(atomic_read(&bp->intr_sem) != 0)) { - DP(BNX2X_MSG_SP, "called but intr_sem not 0, returning\n"); - return; - } - - status = bnx2x_update_dsb_idx(bp); - if (status == 0) - BNX2X_ERR("spurious slowpath interrupt!\n"); - - DP(NETIF_MSG_INTR, "got a slowpath interrupt (updated %x)\n", status); - - /* HW attentions */ - if (status & 0x1) - bnx2x_attn_int(bp); - - /* CStorm events: query_stats, port delete ramrod */ - if (status & 0x2) - bp->stat_pending = 0; - - bnx2x_ack_sb(bp, DEF_SB_ID, ATTENTION_ID, bp->def_att_idx, - IGU_INT_NOP, 1); - bnx2x_ack_sb(bp, DEF_SB_ID, USTORM_ID, le16_to_cpu(bp->def_u_idx), - IGU_INT_NOP, 1); - bnx2x_ack_sb(bp, DEF_SB_ID, CSTORM_ID, le16_to_cpu(bp->def_c_idx), - IGU_INT_NOP, 1); - bnx2x_ack_sb(bp, DEF_SB_ID, XSTORM_ID, le16_to_cpu(bp->def_x_idx), - IGU_INT_NOP, 1); - bnx2x_ack_sb(bp, DEF_SB_ID, TSTORM_ID, le16_to_cpu(bp->def_t_idx), - IGU_INT_ENABLE, 1); - -} - -static irqreturn_t bnx2x_msix_sp_int(int irq, void *dev_instance) -{ - struct net_device *dev = dev_instance; - struct bnx2x *bp = netdev_priv(dev); - - /* Return here if interrupt is disabled */ - if (unlikely(atomic_read(&bp->intr_sem) != 0)) { - DP(BNX2X_MSG_SP, "called but intr_sem not 0, returning\n"); - return IRQ_HANDLED; - } - - bnx2x_ack_sb(bp, DEF_SB_ID, XSTORM_ID, 0, IGU_INT_DISABLE, 0); - -#ifdef BNX2X_STOP_ON_ERROR - if (unlikely(bp->panic)) - return IRQ_HANDLED; -#endif - - schedule_work(&bp->sp_task); - - return IRQ_HANDLED; -} - -/* end of slow path */ - -/* Statistics */ - -/**************************************************************************** -* Macros -****************************************************************************/ - -#define UPDATE_STAT(s, t) \ - do { \ - estats->t += new->s - old->s; \ - old->s = new->s; \ - } while (0) - -/* sum[hi:lo] += add[hi:lo] */ -#define ADD_64(s_hi, a_hi, s_lo, a_lo) \ - do { \ - s_lo += a_lo; \ - s_hi += a_hi + (s_lo < a_lo) ? 1 : 0; \ - } while (0) - -/* difference = minuend - subtrahend */ -#define DIFF_64(d_hi, m_hi, s_hi, d_lo, m_lo, s_lo) \ - do { \ - if (m_lo < s_lo) { /* underflow */ \ - d_hi = m_hi - s_hi; \ - if (d_hi > 0) { /* we can 'loan' 1 */ \ - d_hi--; \ - d_lo = m_lo + (UINT_MAX - s_lo) + 1; \ - } else { /* m_hi <= s_hi */ \ - d_hi = 0; \ - d_lo = 0; \ - } \ - } else { /* m_lo >= s_lo */ \ - if (m_hi < s_hi) { \ - d_hi = 0; \ - d_lo = 0; \ - } else { /* m_hi >= s_hi */ \ - d_hi = m_hi - s_hi; \ - d_lo = m_lo - s_lo; \ - } \ - } \ - } while (0) - -/* minuend -= subtrahend */ -#define SUB_64(m_hi, s_hi, m_lo, s_lo) \ - do { \ - DIFF_64(m_hi, m_hi, s_hi, m_lo, m_lo, s_lo); \ - } while (0) - -#define UPDATE_STAT64(s_hi, t_hi, s_lo, t_lo) \ - do { \ - DIFF_64(diff.hi, new->s_hi, old->s_hi, \ - diff.lo, new->s_lo, old->s_lo); \ - old->s_hi = new->s_hi; \ - old->s_lo = new->s_lo; \ - ADD_64(estats->t_hi, diff.hi, \ - estats->t_lo, diff.lo); \ - } while (0) - -/* sum[hi:lo] += add */ -#define ADD_EXTEND_64(s_hi, s_lo, a) \ - do { \ - s_lo += a; \ - s_hi += (s_lo < a) ? 1 : 0; \ - } while (0) - -#define UPDATE_EXTEND_STAT(s, t_hi, t_lo) \ - do { \ - ADD_EXTEND_64(estats->t_hi, estats->t_lo, new->s); \ - } while (0) - -#define UPDATE_EXTEND_TSTAT(s, t_hi, t_lo) \ - do { \ - diff = le32_to_cpu(tclient->s) - old_tclient->s; \ - old_tclient->s = le32_to_cpu(tclient->s); \ - ADD_EXTEND_64(estats->t_hi, estats->t_lo, diff); \ - } while (0) - -/* - * General service functions - */ - -static inline long bnx2x_hilo(u32 *hiref) -{ - u32 lo = *(hiref + 1); -#if (BITS_PER_LONG == 64) - u32 hi = *hiref; - - return HILO_U64(hi, lo); -#else - return lo; -#endif -} - -/* - * Init service functions - */ - -static void bnx2x_init_mac_stats(struct bnx2x *bp) -{ - struct dmae_command *dmae; - int port = bp->port; - int loader_idx = port * 8; - u32 opcode; - u32 mac_addr; - - bp->executer_idx = 0; - if (bp->fw_mb) { - /* MCP */ - opcode = (DMAE_CMD_SRC_PCI | DMAE_CMD_DST_GRC | - DMAE_CMD_SRC_RESET | DMAE_CMD_DST_RESET | -#ifdef __BIG_ENDIAN - DMAE_CMD_ENDIANITY_B_DW_SWAP | -#else - DMAE_CMD_ENDIANITY_DW_SWAP | -#endif - (port ? DMAE_CMD_PORT_1 : DMAE_CMD_PORT_0)); - - if (bp->link_up) - opcode |= (DMAE_CMD_C_DST_GRC | DMAE_CMD_C_ENABLE); - - dmae = bnx2x_sp(bp, dmae[bp->executer_idx++]); - dmae->opcode = opcode; - dmae->src_addr_lo = U64_LO(bnx2x_sp_mapping(bp, eth_stats) + - sizeof(u32)); - dmae->src_addr_hi = U64_HI(bnx2x_sp_mapping(bp, eth_stats) + - sizeof(u32)); - dmae->dst_addr_lo = bp->fw_mb >> 2; - dmae->dst_addr_hi = 0; - dmae->len = (offsetof(struct bnx2x_eth_stats, mac_stx_end) - - sizeof(u32)) >> 2; - if (bp->link_up) { - dmae->comp_addr_lo = dmae_reg_go_c[loader_idx] >> 2; - dmae->comp_addr_hi = 0; - dmae->comp_val = 1; - } else { - dmae->comp_addr_lo = 0; - dmae->comp_addr_hi = 0; - dmae->comp_val = 0; - } - } - - if (!bp->link_up) { - /* no need to collect statistics in link down */ - return; - } - - opcode = (DMAE_CMD_SRC_GRC | DMAE_CMD_DST_PCI | - DMAE_CMD_C_DST_GRC | DMAE_CMD_C_ENABLE | - DMAE_CMD_SRC_RESET | DMAE_CMD_DST_RESET | -#ifdef __BIG_ENDIAN - DMAE_CMD_ENDIANITY_B_DW_SWAP | -#else - DMAE_CMD_ENDIANITY_DW_SWAP | -#endif - (port ? DMAE_CMD_PORT_1 : DMAE_CMD_PORT_0)); - - if (bp->phy_flags & PHY_BMAC_FLAG) { - - mac_addr = (port ? NIG_REG_INGRESS_BMAC1_MEM : - NIG_REG_INGRESS_BMAC0_MEM); - - /* BIGMAC_REGISTER_TX_STAT_GTPKT .. - BIGMAC_REGISTER_TX_STAT_GTBYT */ - dmae = bnx2x_sp(bp, dmae[bp->executer_idx++]); - dmae->opcode = opcode; - dmae->src_addr_lo = (mac_addr + - BIGMAC_REGISTER_TX_STAT_GTPKT) >> 2; - dmae->src_addr_hi = 0; - dmae->dst_addr_lo = U64_LO(bnx2x_sp_mapping(bp, mac_stats)); - dmae->dst_addr_hi = U64_HI(bnx2x_sp_mapping(bp, mac_stats)); - dmae->len = (8 + BIGMAC_REGISTER_TX_STAT_GTBYT - - BIGMAC_REGISTER_TX_STAT_GTPKT) >> 2; - dmae->comp_addr_lo = dmae_reg_go_c[loader_idx] >> 2; - dmae->comp_addr_hi = 0; - dmae->comp_val = 1; - - /* BIGMAC_REGISTER_RX_STAT_GR64 .. - BIGMAC_REGISTER_RX_STAT_GRIPJ */ - dmae = bnx2x_sp(bp, dmae[bp->executer_idx++]); - dmae->opcode = opcode; - dmae->src_addr_lo = (mac_addr + - BIGMAC_REGISTER_RX_STAT_GR64) >> 2; - dmae->src_addr_hi = 0; - dmae->dst_addr_lo = U64_LO(bnx2x_sp_mapping(bp, mac_stats) + - offsetof(struct bmac_stats, rx_gr64)); - dmae->dst_addr_hi = U64_HI(bnx2x_sp_mapping(bp, mac_stats) + - offsetof(struct bmac_stats, rx_gr64)); - dmae->len = (8 + BIGMAC_REGISTER_RX_STAT_GRIPJ - - BIGMAC_REGISTER_RX_STAT_GR64) >> 2; - dmae->comp_addr_lo = dmae_reg_go_c[loader_idx] >> 2; - dmae->comp_addr_hi = 0; - dmae->comp_val = 1; - - } else if (bp->phy_flags & PHY_EMAC_FLAG) { - - mac_addr = (port ? GRCBASE_EMAC1 : GRCBASE_EMAC0); - - /* EMAC_REG_EMAC_RX_STAT_AC (EMAC_REG_EMAC_RX_STAT_AC_COUNT)*/ - dmae = bnx2x_sp(bp, dmae[bp->executer_idx++]); - dmae->opcode = opcode; - dmae->src_addr_lo = (mac_addr + - EMAC_REG_EMAC_RX_STAT_AC) >> 2; - dmae->src_addr_hi = 0; - dmae->dst_addr_lo = U64_LO(bnx2x_sp_mapping(bp, mac_stats)); - dmae->dst_addr_hi = U64_HI(bnx2x_sp_mapping(bp, mac_stats)); - dmae->len = EMAC_REG_EMAC_RX_STAT_AC_COUNT; - dmae->comp_addr_lo = dmae_reg_go_c[loader_idx] >> 2; - dmae->comp_addr_hi = 0; - dmae->comp_val = 1; - - /* EMAC_REG_EMAC_RX_STAT_AC_28 */ - dmae = bnx2x_sp(bp, dmae[bp->executer_idx++]); - dmae->opcode = opcode; - dmae->src_addr_lo = (mac_addr + - EMAC_REG_EMAC_RX_STAT_AC_28) >> 2; - dmae->src_addr_hi = 0; - dmae->dst_addr_lo = U64_LO(bnx2x_sp_mapping(bp, mac_stats) + - offsetof(struct emac_stats, - rx_falsecarriererrors)); - dmae->dst_addr_hi = U64_HI(bnx2x_sp_mapping(bp, mac_stats) + - offsetof(struct emac_stats, - rx_falsecarriererrors)); - dmae->len = 1; - dmae->comp_addr_lo = dmae_reg_go_c[loader_idx] >> 2; - dmae->comp_addr_hi = 0; - dmae->comp_val = 1; - - /* EMAC_REG_EMAC_TX_STAT_AC (EMAC_REG_EMAC_TX_STAT_AC_COUNT)*/ - dmae = bnx2x_sp(bp, dmae[bp->executer_idx++]); - dmae->opcode = opcode; - dmae->src_addr_lo = (mac_addr + - EMAC_REG_EMAC_TX_STAT_AC) >> 2; - dmae->src_addr_hi = 0; - dmae->dst_addr_lo = U64_LO(bnx2x_sp_mapping(bp, mac_stats) + - offsetof(struct emac_stats, - tx_ifhcoutoctets)); - dmae->dst_addr_hi = U64_HI(bnx2x_sp_mapping(bp, mac_stats) + - offsetof(struct emac_stats, - tx_ifhcoutoctets)); - dmae->len = EMAC_REG_EMAC_TX_STAT_AC_COUNT; - dmae->comp_addr_lo = dmae_reg_go_c[loader_idx] >> 2; - dmae->comp_addr_hi = 0; - dmae->comp_val = 1; - } - - /* NIG */ - dmae = bnx2x_sp(bp, dmae[bp->executer_idx++]); - dmae->opcode = (DMAE_CMD_SRC_GRC | DMAE_CMD_DST_PCI | - DMAE_CMD_C_DST_PCI | DMAE_CMD_C_ENABLE | - DMAE_CMD_SRC_RESET | DMAE_CMD_DST_RESET | -#ifdef __BIG_ENDIAN - DMAE_CMD_ENDIANITY_B_DW_SWAP | -#else - DMAE_CMD_ENDIANITY_DW_SWAP | -#endif - (port ? DMAE_CMD_PORT_1 : DMAE_CMD_PORT_0)); - dmae->src_addr_lo = (port ? NIG_REG_STAT1_BRB_DISCARD : - NIG_REG_STAT0_BRB_DISCARD) >> 2; - dmae->src_addr_hi = 0; - dmae->dst_addr_lo = U64_LO(bnx2x_sp_mapping(bp, nig)); - dmae->dst_addr_hi = U64_HI(bnx2x_sp_mapping(bp, nig)); - dmae->len = (sizeof(struct nig_stats) - 2*sizeof(u32)) >> 2; - dmae->comp_addr_lo = U64_LO(bnx2x_sp_mapping(bp, nig) + - offsetof(struct nig_stats, done)); - dmae->comp_addr_hi = U64_HI(bnx2x_sp_mapping(bp, nig) + - offsetof(struct nig_stats, done)); - dmae->comp_val = 0xffffffff; -} - -static void bnx2x_init_stats(struct bnx2x *bp) -{ - int port = bp->port; - - bp->stats_state = STATS_STATE_DISABLE; - bp->executer_idx = 0; - - bp->old_brb_discard = REG_RD(bp, - NIG_REG_STAT0_BRB_DISCARD + port*0x38); - - memset(&bp->old_bmac, 0, sizeof(struct bmac_stats)); - memset(&bp->old_tclient, 0, sizeof(struct tstorm_per_client_stats)); - memset(&bp->dev->stats, 0, sizeof(struct net_device_stats)); - - REG_WR(bp, BAR_XSTRORM_INTMEM + XSTORM_STATS_FLAGS_OFFSET(port), 1); - REG_WR(bp, BAR_XSTRORM_INTMEM + - XSTORM_STATS_FLAGS_OFFSET(port) + 4, 0); - - REG_WR(bp, BAR_TSTRORM_INTMEM + TSTORM_STATS_FLAGS_OFFSET(port), 1); - REG_WR(bp, BAR_TSTRORM_INTMEM + - TSTORM_STATS_FLAGS_OFFSET(port) + 4, 0); - - REG_WR(bp, BAR_CSTRORM_INTMEM + CSTORM_STATS_FLAGS_OFFSET(port), 0); - REG_WR(bp, BAR_CSTRORM_INTMEM + - CSTORM_STATS_FLAGS_OFFSET(port) + 4, 0); - - REG_WR(bp, BAR_XSTRORM_INTMEM + - XSTORM_ETH_STATS_QUERY_ADDR_OFFSET(port), - U64_LO(bnx2x_sp_mapping(bp, fw_stats))); - REG_WR(bp, BAR_XSTRORM_INTMEM + - XSTORM_ETH_STATS_QUERY_ADDR_OFFSET(port) + 4, - U64_HI(bnx2x_sp_mapping(bp, fw_stats))); - - REG_WR(bp, BAR_TSTRORM_INTMEM + - TSTORM_ETH_STATS_QUERY_ADDR_OFFSET(port), - U64_LO(bnx2x_sp_mapping(bp, fw_stats))); - REG_WR(bp, BAR_TSTRORM_INTMEM + - TSTORM_ETH_STATS_QUERY_ADDR_OFFSET(port) + 4, - U64_HI(bnx2x_sp_mapping(bp, fw_stats))); -} - -static void bnx2x_stop_stats(struct bnx2x *bp) -{ - might_sleep(); - if (bp->stats_state != STATS_STATE_DISABLE) { - int timeout = 10; - - bp->stats_state = STATS_STATE_STOP; - DP(BNX2X_MSG_STATS, "stats_state - STOP\n"); - - while (bp->stats_state != STATS_STATE_DISABLE) { - if (!timeout) { - BNX2X_ERR("timeout waiting for stats stop\n"); - break; - } - timeout--; - msleep(100); - } - } - DP(BNX2X_MSG_STATS, "stats_state - DISABLE\n"); -} - -/* - * Statistics service functions - */ - -static void bnx2x_update_bmac_stats(struct bnx2x *bp) -{ - struct regp diff; - struct regp sum; - struct bmac_stats *new = bnx2x_sp(bp, mac_stats.bmac); - struct bmac_stats *old = &bp->old_bmac; - struct bnx2x_eth_stats *estats = bnx2x_sp(bp, eth_stats); - - sum.hi = 0; - sum.lo = 0; - - UPDATE_STAT64(tx_gtbyt.hi, total_bytes_transmitted_hi, - tx_gtbyt.lo, total_bytes_transmitted_lo); - - UPDATE_STAT64(tx_gtmca.hi, total_multicast_packets_transmitted_hi, - tx_gtmca.lo, total_multicast_packets_transmitted_lo); - ADD_64(sum.hi, diff.hi, sum.lo, diff.lo); - - UPDATE_STAT64(tx_gtgca.hi, total_broadcast_packets_transmitted_hi, - tx_gtgca.lo, total_broadcast_packets_transmitted_lo); - ADD_64(sum.hi, diff.hi, sum.lo, diff.lo); - - UPDATE_STAT64(tx_gtpkt.hi, total_unicast_packets_transmitted_hi, - tx_gtpkt.lo, total_unicast_packets_transmitted_lo); - SUB_64(estats->total_unicast_packets_transmitted_hi, sum.hi, - estats->total_unicast_packets_transmitted_lo, sum.lo); - - UPDATE_STAT(tx_gtxpf.lo, pause_xoff_frames_transmitted); - UPDATE_STAT(tx_gt64.lo, frames_transmitted_64_bytes); - UPDATE_STAT(tx_gt127.lo, frames_transmitted_65_127_bytes); - UPDATE_STAT(tx_gt255.lo, frames_transmitted_128_255_bytes); - UPDATE_STAT(tx_gt511.lo, frames_transmitted_256_511_bytes); - UPDATE_STAT(tx_gt1023.lo, frames_transmitted_512_1023_bytes); - UPDATE_STAT(tx_gt1518.lo, frames_transmitted_1024_1522_bytes); - UPDATE_STAT(tx_gt2047.lo, frames_transmitted_1523_9022_bytes); - UPDATE_STAT(tx_gt4095.lo, frames_transmitted_1523_9022_bytes); - UPDATE_STAT(tx_gt9216.lo, frames_transmitted_1523_9022_bytes); - UPDATE_STAT(tx_gt16383.lo, frames_transmitted_1523_9022_bytes); - - UPDATE_STAT(rx_grfcs.lo, crc_receive_errors); - UPDATE_STAT(rx_grund.lo, runt_packets_received); - UPDATE_STAT(rx_grovr.lo, stat_Dot3statsFramesTooLong); - UPDATE_STAT(rx_grxpf.lo, pause_xoff_frames_received); - UPDATE_STAT(rx_grxcf.lo, control_frames_received); - /* UPDATE_STAT(rx_grxpf.lo, control_frames_received); */ - UPDATE_STAT(rx_grfrg.lo, error_runt_packets_received); - UPDATE_STAT(rx_grjbr.lo, error_jabber_packets_received); - - UPDATE_STAT64(rx_grerb.hi, stat_IfHCInBadOctets_hi, - rx_grerb.lo, stat_IfHCInBadOctets_lo); - UPDATE_STAT64(tx_gtufl.hi, stat_IfHCOutBadOctets_hi, - tx_gtufl.lo, stat_IfHCOutBadOctets_lo); - UPDATE_STAT(tx_gterr.lo, stat_Dot3statsInternalMacTransmitErrors); - /* UPDATE_STAT(rx_grxpf.lo, stat_XoffStateEntered); */ - estats->stat_XoffStateEntered = estats->pause_xoff_frames_received; -} - -static void bnx2x_update_emac_stats(struct bnx2x *bp) -{ - struct emac_stats *new = bnx2x_sp(bp, mac_stats.emac); - struct bnx2x_eth_stats *estats = bnx2x_sp(bp, eth_stats); - - UPDATE_EXTEND_STAT(tx_ifhcoutoctets, total_bytes_transmitted_hi, - total_bytes_transmitted_lo); - UPDATE_EXTEND_STAT(tx_ifhcoutucastpkts, - total_unicast_packets_transmitted_hi, - total_unicast_packets_transmitted_lo); - UPDATE_EXTEND_STAT(tx_ifhcoutmulticastpkts, - total_multicast_packets_transmitted_hi, - total_multicast_packets_transmitted_lo); - UPDATE_EXTEND_STAT(tx_ifhcoutbroadcastpkts, - total_broadcast_packets_transmitted_hi, - total_broadcast_packets_transmitted_lo); - - estats->pause_xon_frames_transmitted += new->tx_outxonsent; - estats->pause_xoff_frames_transmitted += new->tx_outxoffsent; - estats->single_collision_transmit_frames += - new->tx_dot3statssinglecollisionframes; - estats->multiple_collision_transmit_frames += - new->tx_dot3statsmultiplecollisionframes; - estats->late_collision_frames += new->tx_dot3statslatecollisions; - estats->excessive_collision_frames += - new->tx_dot3statsexcessivecollisions; - estats->frames_transmitted_64_bytes += new->tx_etherstatspkts64octets; - estats->frames_transmitted_65_127_bytes += - new->tx_etherstatspkts65octetsto127octets; - estats->frames_transmitted_128_255_bytes += - new->tx_etherstatspkts128octetsto255octets; - estats->frames_transmitted_256_511_bytes += - new->tx_etherstatspkts256octetsto511octets; - estats->frames_transmitted_512_1023_bytes += - new->tx_etherstatspkts512octetsto1023octets; - estats->frames_transmitted_1024_1522_bytes += - new->tx_etherstatspkts1024octetsto1522octet; - estats->frames_transmitted_1523_9022_bytes += - new->tx_etherstatspktsover1522octets; - - estats->crc_receive_errors += new->rx_dot3statsfcserrors; - estats->alignment_errors += new->rx_dot3statsalignmenterrors; - estats->false_carrier_detections += new->rx_falsecarriererrors; - estats->runt_packets_received += new->rx_etherstatsundersizepkts; - estats->stat_Dot3statsFramesTooLong += new->rx_dot3statsframestoolong; - estats->pause_xon_frames_received += new->rx_xonpauseframesreceived; - estats->pause_xoff_frames_received += new->rx_xoffpauseframesreceived; - estats->control_frames_received += new->rx_maccontrolframesreceived; - estats->error_runt_packets_received += new->rx_etherstatsfragments; - estats->error_jabber_packets_received += new->rx_etherstatsjabbers; - - UPDATE_EXTEND_STAT(rx_ifhcinbadoctets, stat_IfHCInBadOctets_hi, - stat_IfHCInBadOctets_lo); - UPDATE_EXTEND_STAT(tx_ifhcoutbadoctets, stat_IfHCOutBadOctets_hi, - stat_IfHCOutBadOctets_lo); - estats->stat_Dot3statsInternalMacTransmitErrors += - new->tx_dot3statsinternalmactransmiterrors; - estats->stat_Dot3StatsCarrierSenseErrors += - new->rx_dot3statscarriersenseerrors; - estats->stat_Dot3StatsDeferredTransmissions += - new->tx_dot3statsdeferredtransmissions; - estats->stat_FlowControlDone += new->tx_flowcontroldone; - estats->stat_XoffStateEntered += new->rx_xoffstateentered; -} - -static int bnx2x_update_storm_stats(struct bnx2x *bp) -{ - struct eth_stats_query *stats = bnx2x_sp(bp, fw_stats); - struct tstorm_common_stats *tstats = &stats->tstorm_common; - struct tstorm_per_client_stats *tclient = - &tstats->client_statistics[0]; - struct tstorm_per_client_stats *old_tclient = &bp->old_tclient; - struct xstorm_common_stats *xstats = &stats->xstorm_common; - struct nig_stats *nstats = bnx2x_sp(bp, nig); - struct bnx2x_eth_stats *estats = bnx2x_sp(bp, eth_stats); - u32 diff; - - /* are DMAE stats valid? */ - if (nstats->done != 0xffffffff) { - DP(BNX2X_MSG_STATS, "stats not updated by dmae\n"); - return -1; - } - - /* are storm stats valid? */ - if (tstats->done.hi != 0xffffffff) { - DP(BNX2X_MSG_STATS, "stats not updated by tstorm\n"); - return -2; - } - if (xstats->done.hi != 0xffffffff) { - DP(BNX2X_MSG_STATS, "stats not updated by xstorm\n"); - return -3; - } - - estats->total_bytes_received_hi = - estats->valid_bytes_received_hi = - le32_to_cpu(tclient->total_rcv_bytes.hi); - estats->total_bytes_received_lo = - estats->valid_bytes_received_lo = - le32_to_cpu(tclient->total_rcv_bytes.lo); - ADD_64(estats->total_bytes_received_hi, - le32_to_cpu(tclient->rcv_error_bytes.hi), - estats->total_bytes_received_lo, - le32_to_cpu(tclient->rcv_error_bytes.lo)); - - UPDATE_EXTEND_TSTAT(rcv_unicast_pkts, - total_unicast_packets_received_hi, - total_unicast_packets_received_lo); - UPDATE_EXTEND_TSTAT(rcv_multicast_pkts, - total_multicast_packets_received_hi, - total_multicast_packets_received_lo); - UPDATE_EXTEND_TSTAT(rcv_broadcast_pkts, - total_broadcast_packets_received_hi, - total_broadcast_packets_received_lo); - - estats->frames_received_64_bytes = MAC_STX_NA; - estats->frames_received_65_127_bytes = MAC_STX_NA; - estats->frames_received_128_255_bytes = MAC_STX_NA; - estats->frames_received_256_511_bytes = MAC_STX_NA; - estats->frames_received_512_1023_bytes = MAC_STX_NA; - estats->frames_received_1024_1522_bytes = MAC_STX_NA; - estats->frames_received_1523_9022_bytes = MAC_STX_NA; - - estats->x_total_sent_bytes_hi = - le32_to_cpu(xstats->total_sent_bytes.hi); - estats->x_total_sent_bytes_lo = - le32_to_cpu(xstats->total_sent_bytes.lo); - estats->x_total_sent_pkts = le32_to_cpu(xstats->total_sent_pkts); - - estats->t_rcv_unicast_bytes_hi = - le32_to_cpu(tclient->rcv_unicast_bytes.hi); - estats->t_rcv_unicast_bytes_lo = - le32_to_cpu(tclient->rcv_unicast_bytes.lo); - estats->t_rcv_broadcast_bytes_hi = - le32_to_cpu(tclient->rcv_broadcast_bytes.hi); - estats->t_rcv_broadcast_bytes_lo = - le32_to_cpu(tclient->rcv_broadcast_bytes.lo); - estats->t_rcv_multicast_bytes_hi = - le32_to_cpu(tclient->rcv_multicast_bytes.hi); - estats->t_rcv_multicast_bytes_lo = - le32_to_cpu(tclient->rcv_multicast_bytes.lo); - estats->t_total_rcv_pkt = le32_to_cpu(tclient->total_rcv_pkts); - - estats->checksum_discard = le32_to_cpu(tclient->checksum_discard); - estats->packets_too_big_discard = - le32_to_cpu(tclient->packets_too_big_discard); - estats->jabber_packets_received = estats->packets_too_big_discard + - estats->stat_Dot3statsFramesTooLong; - estats->no_buff_discard = le32_to_cpu(tclient->no_buff_discard); - estats->ttl0_discard = le32_to_cpu(tclient->ttl0_discard); - estats->mac_discard = le32_to_cpu(tclient->mac_discard); - estats->mac_filter_discard = le32_to_cpu(tstats->mac_filter_discard); - estats->xxoverflow_discard = le32_to_cpu(tstats->xxoverflow_discard); - estats->brb_truncate_discard = - le32_to_cpu(tstats->brb_truncate_discard); - - estats->brb_discard += nstats->brb_discard - bp->old_brb_discard; - bp->old_brb_discard = nstats->brb_discard; - - estats->brb_packet = nstats->brb_packet; - estats->brb_truncate = nstats->brb_truncate; - estats->flow_ctrl_discard = nstats->flow_ctrl_discard; - estats->flow_ctrl_octets = nstats->flow_ctrl_octets; - estats->flow_ctrl_packet = nstats->flow_ctrl_packet; - estats->mng_discard = nstats->mng_discard; - estats->mng_octet_inp = nstats->mng_octet_inp; - estats->mng_octet_out = nstats->mng_octet_out; - estats->mng_packet_inp = nstats->mng_packet_inp; - estats->mng_packet_out = nstats->mng_packet_out; - estats->pbf_octets = nstats->pbf_octets; - estats->pbf_packet = nstats->pbf_packet; - estats->safc_inp = nstats->safc_inp; - - xstats->done.hi = 0; - tstats->done.hi = 0; - nstats->done = 0; - - return 0; -} - -static void bnx2x_update_net_stats(struct bnx2x *bp) -{ - struct bnx2x_eth_stats *estats = bnx2x_sp(bp, eth_stats); - struct net_device_stats *nstats = &bp->dev->stats; - - nstats->rx_packets = - bnx2x_hilo(&estats->total_unicast_packets_received_hi) + - bnx2x_hilo(&estats->total_multicast_packets_received_hi) + - bnx2x_hilo(&estats->total_broadcast_packets_received_hi); - - nstats->tx_packets = - bnx2x_hilo(&estats->total_unicast_packets_transmitted_hi) + - bnx2x_hilo(&estats->total_multicast_packets_transmitted_hi) + - bnx2x_hilo(&estats->total_broadcast_packets_transmitted_hi); - - nstats->rx_bytes = bnx2x_hilo(&estats->total_bytes_received_hi); - - nstats->tx_bytes = bnx2x_hilo(&estats->total_bytes_transmitted_hi); - - nstats->rx_dropped = estats->checksum_discard + estats->mac_discard; - nstats->tx_dropped = 0; - - nstats->multicast = - bnx2x_hilo(&estats->total_multicast_packets_transmitted_hi); - - nstats->collisions = estats->single_collision_transmit_frames + - estats->multiple_collision_transmit_frames + - estats->late_collision_frames + - estats->excessive_collision_frames; - - nstats->rx_length_errors = estats->runt_packets_received + - estats->jabber_packets_received; - nstats->rx_over_errors = estats->brb_discard + - estats->brb_truncate_discard; - nstats->rx_crc_errors = estats->crc_receive_errors; - nstats->rx_frame_errors = estats->alignment_errors; - nstats->rx_fifo_errors = estats->no_buff_discard; - nstats->rx_missed_errors = estats->xxoverflow_discard; - - nstats->rx_errors = nstats->rx_length_errors + - nstats->rx_over_errors + - nstats->rx_crc_errors + - nstats->rx_frame_errors + - nstats->rx_fifo_errors + - nstats->rx_missed_errors; - - nstats->tx_aborted_errors = estats->late_collision_frames + - estats->excessive_collision_frames; - nstats->tx_carrier_errors = estats->false_carrier_detections; - nstats->tx_fifo_errors = 0; - nstats->tx_heartbeat_errors = 0; - nstats->tx_window_errors = 0; - - nstats->tx_errors = nstats->tx_aborted_errors + - nstats->tx_carrier_errors; - - estats->mac_stx_start = ++estats->mac_stx_end; -} - -static void bnx2x_update_stats(struct bnx2x *bp) -{ - int i; - - if (!bnx2x_update_storm_stats(bp)) { - - if (bp->phy_flags & PHY_BMAC_FLAG) { - bnx2x_update_bmac_stats(bp); - - } else if (bp->phy_flags & PHY_EMAC_FLAG) { - bnx2x_update_emac_stats(bp); - - } else { /* unreached */ - BNX2X_ERR("no MAC active\n"); - return; - } - - bnx2x_update_net_stats(bp); - } - - if (bp->msglevel & NETIF_MSG_TIMER) { - struct bnx2x_eth_stats *estats = bnx2x_sp(bp, eth_stats); - struct net_device_stats *nstats = &bp->dev->stats; - - printk(KERN_DEBUG "%s:\n", bp->dev->name); - printk(KERN_DEBUG " tx avail (%4x) tx hc idx (%x)" - " tx pkt (%lx)\n", - bnx2x_tx_avail(bp->fp), - *bp->fp->tx_cons_sb, nstats->tx_packets); - printk(KERN_DEBUG " rx usage (%4x) rx hc idx (%x)" - " rx pkt (%lx)\n", - (u16)(*bp->fp->rx_cons_sb - bp->fp->rx_comp_cons), - *bp->fp->rx_cons_sb, nstats->rx_packets); - printk(KERN_DEBUG " %s (Xoff events %u) brb drops %u\n", - netif_queue_stopped(bp->dev)? "Xoff" : "Xon", - estats->driver_xoff, estats->brb_discard); - printk(KERN_DEBUG "tstats: checksum_discard %u " - "packets_too_big_discard %u no_buff_discard %u " - "mac_discard %u mac_filter_discard %u " - "xxovrflow_discard %u brb_truncate_discard %u " - "ttl0_discard %u\n", - estats->checksum_discard, - estats->packets_too_big_discard, - estats->no_buff_discard, estats->mac_discard, - estats->mac_filter_discard, estats->xxoverflow_discard, - estats->brb_truncate_discard, estats->ttl0_discard); - - for_each_queue(bp, i) { - printk(KERN_DEBUG "[%d]: %lu\t%lu\t%lu\n", i, - bnx2x_fp(bp, i, tx_pkt), - bnx2x_fp(bp, i, rx_pkt), - bnx2x_fp(bp, i, rx_calls)); - } - } - - if (bp->state != BNX2X_STATE_OPEN) { - DP(BNX2X_MSG_STATS, "state is %x, returning\n", bp->state); - return; - } - -#ifdef BNX2X_STOP_ON_ERROR - if (unlikely(bp->panic)) - return; -#endif - - /* loader */ - if (bp->executer_idx) { - struct dmae_command *dmae = &bp->dmae; - int port = bp->port; - int loader_idx = port * 8; - - memset(dmae, 0, sizeof(struct dmae_command)); - - dmae->opcode = (DMAE_CMD_SRC_PCI | DMAE_CMD_DST_GRC | - DMAE_CMD_C_DST_GRC | DMAE_CMD_C_ENABLE | - DMAE_CMD_DST_RESET | -#ifdef __BIG_ENDIAN - DMAE_CMD_ENDIANITY_B_DW_SWAP | -#else - DMAE_CMD_ENDIANITY_DW_SWAP | -#endif - (port ? DMAE_CMD_PORT_1 : DMAE_CMD_PORT_0)); - dmae->src_addr_lo = U64_LO(bnx2x_sp_mapping(bp, dmae[0])); - dmae->src_addr_hi = U64_HI(bnx2x_sp_mapping(bp, dmae[0])); - dmae->dst_addr_lo = (DMAE_REG_CMD_MEM + - sizeof(struct dmae_command) * - (loader_idx + 1)) >> 2; - dmae->dst_addr_hi = 0; - dmae->len = sizeof(struct dmae_command) >> 2; - dmae->len--; /* !!! for A0/1 only */ - dmae->comp_addr_lo = dmae_reg_go_c[loader_idx + 1] >> 2; - dmae->comp_addr_hi = 0; - dmae->comp_val = 1; - - bnx2x_post_dmae(bp, dmae, loader_idx); - } - - if (bp->stats_state != STATS_STATE_ENABLE) { - bp->stats_state = STATS_STATE_DISABLE; - return; - } - - if (bnx2x_sp_post(bp, RAMROD_CMD_ID_ETH_STAT_QUERY, 0, 0, 0, 0) == 0) { - /* stats ramrod has it's own slot on the spe */ - bp->spq_left++; - bp->stat_pending = 1; - } -} - -static void bnx2x_timer(unsigned long data) -{ - struct bnx2x *bp = (struct bnx2x *) data; - - if (!netif_running(bp->dev)) - return; - - if (atomic_read(&bp->intr_sem) != 0) - goto timer_restart; - - if (poll) { - struct bnx2x_fastpath *fp = &bp->fp[0]; - int rc; - - bnx2x_tx_int(fp, 1000); - rc = bnx2x_rx_int(fp, 1000); - } - - if (!nomcp) { - int port = bp->port; - u32 drv_pulse; - u32 mcp_pulse; - - ++bp->fw_drv_pulse_wr_seq; - bp->fw_drv_pulse_wr_seq &= DRV_PULSE_SEQ_MASK; - /* TBD - add SYSTEM_TIME */ - drv_pulse = bp->fw_drv_pulse_wr_seq; - SHMEM_WR(bp, func_mb[port].drv_pulse_mb, drv_pulse); - - mcp_pulse = (SHMEM_RD(bp, func_mb[port].mcp_pulse_mb) & - MCP_PULSE_SEQ_MASK); - /* The delta between driver pulse and mcp response - * should be 1 (before mcp response) or 0 (after mcp response) - */ - if ((drv_pulse != mcp_pulse) && - (drv_pulse != ((mcp_pulse + 1) & MCP_PULSE_SEQ_MASK))) { - /* someone lost a heartbeat... */ - BNX2X_ERR("drv_pulse (0x%x) != mcp_pulse (0x%x)\n", - drv_pulse, mcp_pulse); - } - } - - if (bp->stats_state == STATS_STATE_DISABLE) - goto timer_restart; - - bnx2x_update_stats(bp); - -timer_restart: - mod_timer(&bp->timer, jiffies + bp->current_interval); -} - -/* end of Statistics */ - -/* nic init */ - -/* - * nic init service functions - */ - -static void bnx2x_init_sb(struct bnx2x *bp, struct host_status_block *sb, - dma_addr_t mapping, int id) -{ - int port = bp->port; - u64 section; - int index; - - /* USTORM */ - section = ((u64)mapping) + offsetof(struct host_status_block, - u_status_block); - sb->u_status_block.status_block_id = id; - - REG_WR(bp, BAR_USTRORM_INTMEM + - USTORM_SB_HOST_SB_ADDR_OFFSET(port, id), U64_LO(section)); - REG_WR(bp, BAR_USTRORM_INTMEM + - ((USTORM_SB_HOST_SB_ADDR_OFFSET(port, id)) + 4), - U64_HI(section)); - - for (index = 0; index < HC_USTORM_SB_NUM_INDICES; index++) - REG_WR16(bp, BAR_USTRORM_INTMEM + - USTORM_SB_HC_DISABLE_OFFSET(port, id, index), 0x1); - - /* CSTORM */ - section = ((u64)mapping) + offsetof(struct host_status_block, - c_status_block); - sb->c_status_block.status_block_id = id; - - REG_WR(bp, BAR_CSTRORM_INTMEM + - CSTORM_SB_HOST_SB_ADDR_OFFSET(port, id), U64_LO(section)); - REG_WR(bp, BAR_CSTRORM_INTMEM + - ((CSTORM_SB_HOST_SB_ADDR_OFFSET(port, id)) + 4), - U64_HI(section)); - - for (index = 0; index < HC_CSTORM_SB_NUM_INDICES; index++) - REG_WR16(bp, BAR_CSTRORM_INTMEM + - CSTORM_SB_HC_DISABLE_OFFSET(port, id, index), 0x1); - - bnx2x_ack_sb(bp, id, CSTORM_ID, 0, IGU_INT_ENABLE, 0); -} - -static void bnx2x_init_def_sb(struct bnx2x *bp, - struct host_def_status_block *def_sb, - dma_addr_t mapping, int id) -{ - int port = bp->port; - int index, val, reg_offset; - u64 section; - - /* ATTN */ - section = ((u64)mapping) + offsetof(struct host_def_status_block, - atten_status_block); - def_sb->atten_status_block.status_block_id = id; - - bp->def_att_idx = 0; - bp->attn_state = 0; - - reg_offset = (port ? MISC_REG_AEU_ENABLE1_FUNC_1_OUT_0 : - MISC_REG_AEU_ENABLE1_FUNC_0_OUT_0); - - for (index = 0; index < 3; index++) { - bp->attn_group[index].sig[0] = REG_RD(bp, - reg_offset + 0x10*index); - bp->attn_group[index].sig[1] = REG_RD(bp, - reg_offset + 0x4 + 0x10*index); - bp->attn_group[index].sig[2] = REG_RD(bp, - reg_offset + 0x8 + 0x10*index); - bp->attn_group[index].sig[3] = REG_RD(bp, - reg_offset + 0xc + 0x10*index); - } - - bp->aeu_mask = REG_RD(bp, (port ? MISC_REG_AEU_MASK_ATTN_FUNC_1 : - MISC_REG_AEU_MASK_ATTN_FUNC_0)); - - reg_offset = (port ? HC_REG_ATTN_MSG1_ADDR_L : - HC_REG_ATTN_MSG0_ADDR_L); - - REG_WR(bp, reg_offset, U64_LO(section)); - REG_WR(bp, reg_offset + 4, U64_HI(section)); - - reg_offset = (port ? HC_REG_ATTN_NUM_P1 : HC_REG_ATTN_NUM_P0); - - val = REG_RD(bp, reg_offset); - val |= id; - REG_WR(bp, reg_offset, val); - - /* USTORM */ - section = ((u64)mapping) + offsetof(struct host_def_status_block, - u_def_status_block); - def_sb->u_def_status_block.status_block_id = id; - - bp->def_u_idx = 0; - - REG_WR(bp, BAR_USTRORM_INTMEM + - USTORM_DEF_SB_HOST_SB_ADDR_OFFSET(port), U64_LO(section)); - REG_WR(bp, BAR_USTRORM_INTMEM + - ((USTORM_DEF_SB_HOST_SB_ADDR_OFFSET(port)) + 4), - U64_HI(section)); - REG_WR(bp, BAR_USTRORM_INTMEM + USTORM_HC_BTR_OFFSET(port), - BNX2X_BTR); - - for (index = 0; index < HC_USTORM_DEF_SB_NUM_INDICES; index++) - REG_WR16(bp, BAR_USTRORM_INTMEM + - USTORM_DEF_SB_HC_DISABLE_OFFSET(port, index), 0x1); - - /* CSTORM */ - section = ((u64)mapping) + offsetof(struct host_def_status_block, - c_def_status_block); - def_sb->c_def_status_block.status_block_id = id; - - bp->def_c_idx = 0; - - REG_WR(bp, BAR_CSTRORM_INTMEM + - CSTORM_DEF_SB_HOST_SB_ADDR_OFFSET(port), U64_LO(section)); - REG_WR(bp, BAR_CSTRORM_INTMEM + - ((CSTORM_DEF_SB_HOST_SB_ADDR_OFFSET(port)) + 4), - U64_HI(section)); - REG_WR(bp, BAR_CSTRORM_INTMEM + CSTORM_HC_BTR_OFFSET(port), - BNX2X_BTR); - - for (index = 0; index < HC_CSTORM_DEF_SB_NUM_INDICES; index++) - REG_WR16(bp, BAR_CSTRORM_INTMEM + - CSTORM_DEF_SB_HC_DISABLE_OFFSET(port, index), 0x1); - - /* TSTORM */ - section = ((u64)mapping) + offsetof(struct host_def_status_block, - t_def_status_block); - def_sb->t_def_status_block.status_block_id = id; - - bp->def_t_idx = 0; - - REG_WR(bp, BAR_TSTRORM_INTMEM + - TSTORM_DEF_SB_HOST_SB_ADDR_OFFSET(port), U64_LO(section)); - REG_WR(bp, BAR_TSTRORM_INTMEM + - ((TSTORM_DEF_SB_HOST_SB_ADDR_OFFSET(port)) + 4), - U64_HI(section)); - REG_WR(bp, BAR_TSTRORM_INTMEM + TSTORM_HC_BTR_OFFSET(port), - BNX2X_BTR); - - for (index = 0; index < HC_TSTORM_DEF_SB_NUM_INDICES; index++) - REG_WR16(bp, BAR_TSTRORM_INTMEM + - TSTORM_DEF_SB_HC_DISABLE_OFFSET(port, index), 0x1); - - /* XSTORM */ - section = ((u64)mapping) + offsetof(struct host_def_status_block, - x_def_status_block); - def_sb->x_def_status_block.status_block_id = id; - - bp->def_x_idx = 0; - - REG_WR(bp, BAR_XSTRORM_INTMEM + - XSTORM_DEF_SB_HOST_SB_ADDR_OFFSET(port), U64_LO(section)); - REG_WR(bp, BAR_XSTRORM_INTMEM + - ((XSTORM_DEF_SB_HOST_SB_ADDR_OFFSET(port)) + 4), - U64_HI(section)); - REG_WR(bp, BAR_XSTRORM_INTMEM + XSTORM_HC_BTR_OFFSET(port), - BNX2X_BTR); - - for (index = 0; index < HC_XSTORM_DEF_SB_NUM_INDICES; index++) - REG_WR16(bp, BAR_XSTRORM_INTMEM + - XSTORM_DEF_SB_HC_DISABLE_OFFSET(port, index), 0x1); - - bp->stat_pending = 0; - - bnx2x_ack_sb(bp, id, CSTORM_ID, 0, IGU_INT_ENABLE, 0); -} - -static void bnx2x_update_coalesce(struct bnx2x *bp) -{ - int port = bp->port; - int i; - - for_each_queue(bp, i) { - - /* HC_INDEX_U_ETH_RX_CQ_CONS */ - REG_WR8(bp, BAR_USTRORM_INTMEM + - USTORM_SB_HC_TIMEOUT_OFFSET(port, i, - HC_INDEX_U_ETH_RX_CQ_CONS), - bp->rx_ticks_int/12); - REG_WR16(bp, BAR_USTRORM_INTMEM + - USTORM_SB_HC_DISABLE_OFFSET(port, i, - HC_INDEX_U_ETH_RX_CQ_CONS), - bp->rx_ticks_int ? 0 : 1); - - /* HC_INDEX_C_ETH_TX_CQ_CONS */ - REG_WR8(bp, BAR_CSTRORM_INTMEM + - CSTORM_SB_HC_TIMEOUT_OFFSET(port, i, - HC_INDEX_C_ETH_TX_CQ_CONS), - bp->tx_ticks_int/12); - REG_WR16(bp, BAR_CSTRORM_INTMEM + - CSTORM_SB_HC_DISABLE_OFFSET(port, i, - HC_INDEX_C_ETH_TX_CQ_CONS), - bp->tx_ticks_int ? 0 : 1); - } -} - -static void bnx2x_init_rx_rings(struct bnx2x *bp) -{ - u16 ring_prod; - int i, j; - int port = bp->port; - - bp->rx_buf_use_size = bp->dev->mtu; - - bp->rx_buf_use_size += bp->rx_offset + ETH_OVREHEAD; - bp->rx_buf_size = bp->rx_buf_use_size + 64; - - for_each_queue(bp, j) { - struct bnx2x_fastpath *fp = &bp->fp[j]; - - fp->rx_bd_cons = 0; - fp->rx_cons_sb = BNX2X_RX_SB_INDEX; - - for (i = 1; i <= NUM_RX_RINGS; i++) { - struct eth_rx_bd *rx_bd; - - rx_bd = &fp->rx_desc_ring[RX_DESC_CNT * i - 2]; - rx_bd->addr_hi = - cpu_to_le32(U64_HI(fp->rx_desc_mapping + - BCM_PAGE_SIZE*(i % NUM_RX_RINGS))); - rx_bd->addr_lo = - cpu_to_le32(U64_LO(fp->rx_desc_mapping + - BCM_PAGE_SIZE*(i % NUM_RX_RINGS))); - - } - - for (i = 1; i <= NUM_RCQ_RINGS; i++) { - struct eth_rx_cqe_next_page *nextpg; - - nextpg = (struct eth_rx_cqe_next_page *) - &fp->rx_comp_ring[RCQ_DESC_CNT * i - 1]; - nextpg->addr_hi = - cpu_to_le32(U64_HI(fp->rx_comp_mapping + - BCM_PAGE_SIZE*(i % NUM_RCQ_RINGS))); - nextpg->addr_lo = - cpu_to_le32(U64_LO(fp->rx_comp_mapping + - BCM_PAGE_SIZE*(i % NUM_RCQ_RINGS))); - } - - /* rx completion queue */ - fp->rx_comp_cons = ring_prod = 0; - - for (i = 0; i < bp->rx_ring_size; i++) { - if (bnx2x_alloc_rx_skb(bp, fp, ring_prod) < 0) { - BNX2X_ERR("was only able to allocate " - "%d rx skbs\n", i); - break; - } - ring_prod = NEXT_RX_IDX(ring_prod); - BUG_TRAP(ring_prod > i); - } - - fp->rx_bd_prod = fp->rx_comp_prod = ring_prod; - fp->rx_pkt = fp->rx_calls = 0; - - /* Warning! this will generate an interrupt (to the TSTORM) */ - /* must only be done when chip is initialized */ - REG_WR(bp, BAR_TSTRORM_INTMEM + - TSTORM_RCQ_PROD_OFFSET(port, j), ring_prod); - if (j != 0) - continue; - - REG_WR(bp, BAR_USTRORM_INTMEM + - USTORM_MEM_WORKAROUND_ADDRESS_OFFSET(port), - U64_LO(fp->rx_comp_mapping)); - REG_WR(bp, BAR_USTRORM_INTMEM + - USTORM_MEM_WORKAROUND_ADDRESS_OFFSET(port) + 4, - U64_HI(fp->rx_comp_mapping)); - } -} - -static void bnx2x_init_tx_ring(struct bnx2x *bp) -{ - int i, j; - - for_each_queue(bp, j) { - struct bnx2x_fastpath *fp = &bp->fp[j]; - - for (i = 1; i <= NUM_TX_RINGS; i++) { - struct eth_tx_bd *tx_bd = - &fp->tx_desc_ring[TX_DESC_CNT * i - 1]; - - tx_bd->addr_hi = - cpu_to_le32(U64_HI(fp->tx_desc_mapping + - BCM_PAGE_SIZE*(i % NUM_TX_RINGS))); - tx_bd->addr_lo = - cpu_to_le32(U64_LO(fp->tx_desc_mapping + - BCM_PAGE_SIZE*(i % NUM_TX_RINGS))); - } - - fp->tx_pkt_prod = 0; - fp->tx_pkt_cons = 0; - fp->tx_bd_prod = 0; - fp->tx_bd_cons = 0; - fp->tx_cons_sb = BNX2X_TX_SB_INDEX; - fp->tx_pkt = 0; - } -} - -static void bnx2x_init_sp_ring(struct bnx2x *bp) -{ - int port = bp->port; - - spin_lock_init(&bp->spq_lock); - - bp->spq_left = MAX_SPQ_PENDING; - bp->spq_prod_idx = 0; - bp->dsb_sp_prod = BNX2X_SP_DSB_INDEX; - bp->spq_prod_bd = bp->spq; - bp->spq_last_bd = bp->spq_prod_bd + MAX_SP_DESC_CNT; - - REG_WR(bp, BAR_XSTRORM_INTMEM + XSTORM_SPQ_PAGE_BASE_OFFSET(port), - U64_LO(bp->spq_mapping)); - REG_WR(bp, BAR_XSTRORM_INTMEM + XSTORM_SPQ_PAGE_BASE_OFFSET(port) + 4, - U64_HI(bp->spq_mapping)); - - REG_WR(bp, XSEM_REG_FAST_MEMORY + XSTORM_SPQ_PROD_OFFSET(port), - bp->spq_prod_idx); -} - -static void bnx2x_init_context(struct bnx2x *bp) -{ - int i; - - for_each_queue(bp, i) { - struct eth_context *context = bnx2x_sp(bp, context[i].eth); - struct bnx2x_fastpath *fp = &bp->fp[i]; - - context->xstorm_st_context.tx_bd_page_base_hi = - U64_HI(fp->tx_desc_mapping); - context->xstorm_st_context.tx_bd_page_base_lo = - U64_LO(fp->tx_desc_mapping); - context->xstorm_st_context.db_data_addr_hi = - U64_HI(fp->tx_prods_mapping); - context->xstorm_st_context.db_data_addr_lo = - U64_LO(fp->tx_prods_mapping); - - context->ustorm_st_context.rx_bd_page_base_hi = - U64_HI(fp->rx_desc_mapping); - context->ustorm_st_context.rx_bd_page_base_lo = - U64_LO(fp->rx_desc_mapping); - context->ustorm_st_context.status_block_id = i; - context->ustorm_st_context.sb_index_number = - HC_INDEX_U_ETH_RX_CQ_CONS; - context->ustorm_st_context.rcq_base_address_hi = - U64_HI(fp->rx_comp_mapping); - context->ustorm_st_context.rcq_base_address_lo = - U64_LO(fp->rx_comp_mapping); - context->ustorm_st_context.flags = - USTORM_ETH_ST_CONTEXT_ENABLE_MC_ALIGNMENT; - context->ustorm_st_context.mc_alignment_size = 64; - context->ustorm_st_context.num_rss = bp->num_queues; - - context->cstorm_st_context.sb_index_number = - HC_INDEX_C_ETH_TX_CQ_CONS; - context->cstorm_st_context.status_block_id = i; - - context->xstorm_ag_context.cdu_reserved = - CDU_RSRVD_VALUE_TYPE_A(HW_CID(bp, i), - CDU_REGION_NUMBER_XCM_AG, - ETH_CONNECTION_TYPE); - context->ustorm_ag_context.cdu_usage = - CDU_RSRVD_VALUE_TYPE_A(HW_CID(bp, i), - CDU_REGION_NUMBER_UCM_AG, - ETH_CONNECTION_TYPE); - } -} - -static void bnx2x_init_ind_table(struct bnx2x *bp) -{ - int port = bp->port; - int i; - - if (!is_multi(bp)) - return; - - for (i = 0; i < TSTORM_INDIRECTION_TABLE_SIZE; i++) - REG_WR8(bp, TSTORM_INDIRECTION_TABLE_OFFSET(port) + i, - i % bp->num_queues); - - REG_WR(bp, PRS_REG_A_PRSU_20, 0xf); -} - -static void bnx2x_set_client_config(struct bnx2x *bp) -{ -#ifdef BCM_VLAN - int mode = bp->rx_mode; -#endif - int i, port = bp->port; - struct tstorm_eth_client_config tstorm_client = {0}; - - tstorm_client.mtu = bp->dev->mtu; - tstorm_client.statistics_counter_id = 0; - tstorm_client.config_flags = - TSTORM_ETH_CLIENT_CONFIG_STATSITICS_ENABLE; -#ifdef BCM_VLAN - if (mode && bp->vlgrp) { - tstorm_client.config_flags |= - TSTORM_ETH_CLIENT_CONFIG_VLAN_REMOVAL_ENABLE; - DP(NETIF_MSG_IFUP, "vlan removal enabled\n"); - } -#endif - if (mode != BNX2X_RX_MODE_PROMISC) - tstorm_client.drop_flags = - TSTORM_ETH_CLIENT_CONFIG_DROP_MAC_ERR; - - for_each_queue(bp, i) { - REG_WR(bp, BAR_TSTRORM_INTMEM + - TSTORM_CLIENT_CONFIG_OFFSET(port, i), - ((u32 *)&tstorm_client)[0]); - REG_WR(bp, BAR_TSTRORM_INTMEM + - TSTORM_CLIENT_CONFIG_OFFSET(port, i) + 4, - ((u32 *)&tstorm_client)[1]); - } - -/* DP(NETIF_MSG_IFUP, "tstorm_client: 0x%08x 0x%08x\n", - ((u32 *)&tstorm_client)[0], ((u32 *)&tstorm_client)[1]); */ -} - -static void bnx2x_set_storm_rx_mode(struct bnx2x *bp) -{ - int mode = bp->rx_mode; - int port = bp->port; - struct tstorm_eth_mac_filter_config tstorm_mac_filter = {0}; - int i; - - DP(NETIF_MSG_RX_STATUS, "rx mode is %d\n", mode); - - switch (mode) { - case BNX2X_RX_MODE_NONE: /* no Rx */ - tstorm_mac_filter.ucast_drop_all = 1; - tstorm_mac_filter.mcast_drop_all = 1; - tstorm_mac_filter.bcast_drop_all = 1; - break; - case BNX2X_RX_MODE_NORMAL: - tstorm_mac_filter.bcast_accept_all = 1; - break; - case BNX2X_RX_MODE_ALLMULTI: - tstorm_mac_filter.mcast_accept_all = 1; - tstorm_mac_filter.bcast_accept_all = 1; - break; - case BNX2X_RX_MODE_PROMISC: - tstorm_mac_filter.ucast_accept_all = 1; - tstorm_mac_filter.mcast_accept_all = 1; - tstorm_mac_filter.bcast_accept_all = 1; - break; - default: - BNX2X_ERR("bad rx mode (%d)\n", mode); - } - - for (i = 0; i < sizeof(struct tstorm_eth_mac_filter_config)/4; i++) { - REG_WR(bp, BAR_TSTRORM_INTMEM + - TSTORM_MAC_FILTER_CONFIG_OFFSET(port) + i * 4, - ((u32 *)&tstorm_mac_filter)[i]); - -/* DP(NETIF_MSG_IFUP, "tstorm_mac_filter[%d]: 0x%08x\n", i, - ((u32 *)&tstorm_mac_filter)[i]); */ - } - - if (mode != BNX2X_RX_MODE_NONE) - bnx2x_set_client_config(bp); -} - -static void bnx2x_init_internal(struct bnx2x *bp) -{ - int port = bp->port; - struct tstorm_eth_function_common_config tstorm_config = {0}; - struct stats_indication_flags stats_flags = {0}; - - if (is_multi(bp)) { - tstorm_config.config_flags = MULTI_FLAGS; - tstorm_config.rss_result_mask = MULTI_MASK; - } - - REG_WR(bp, BAR_TSTRORM_INTMEM + - TSTORM_FUNCTION_COMMON_CONFIG_OFFSET(port), - (*(u32 *)&tstorm_config)); - -/* DP(NETIF_MSG_IFUP, "tstorm_config: 0x%08x\n", - (*(u32 *)&tstorm_config)); */ - - bp->rx_mode = BNX2X_RX_MODE_NONE; /* no rx until link is up */ - bnx2x_set_storm_rx_mode(bp); - - stats_flags.collect_eth = cpu_to_le32(1); - - REG_WR(bp, BAR_XSTRORM_INTMEM + XSTORM_STATS_FLAGS_OFFSET(port), - ((u32 *)&stats_flags)[0]); - REG_WR(bp, BAR_XSTRORM_INTMEM + XSTORM_STATS_FLAGS_OFFSET(port) + 4, - ((u32 *)&stats_flags)[1]); - - REG_WR(bp, BAR_TSTRORM_INTMEM + TSTORM_STATS_FLAGS_OFFSET(port), - ((u32 *)&stats_flags)[0]); - REG_WR(bp, BAR_TSTRORM_INTMEM + TSTORM_STATS_FLAGS_OFFSET(port) + 4, - ((u32 *)&stats_flags)[1]); - - REG_WR(bp, BAR_CSTRORM_INTMEM + CSTORM_STATS_FLAGS_OFFSET(port), - ((u32 *)&stats_flags)[0]); - REG_WR(bp, BAR_CSTRORM_INTMEM + CSTORM_STATS_FLAGS_OFFSET(port) + 4, - ((u32 *)&stats_flags)[1]); - -/* DP(NETIF_MSG_IFUP, "stats_flags: 0x%08x 0x%08x\n", - ((u32 *)&stats_flags)[0], ((u32 *)&stats_flags)[1]); */ -} - -static void bnx2x_nic_init(struct bnx2x *bp) -{ - int i; - - for_each_queue(bp, i) { - struct bnx2x_fastpath *fp = &bp->fp[i]; - - fp->state = BNX2X_FP_STATE_CLOSED; - DP(NETIF_MSG_IFUP, "bnx2x_init_sb(%p,%p,%d);\n", - bp, fp->status_blk, i); - fp->index = i; - bnx2x_init_sb(bp, fp->status_blk, fp->status_blk_mapping, i); - } - - bnx2x_init_def_sb(bp, bp->def_status_blk, - bp->def_status_blk_mapping, 0x10); - bnx2x_update_coalesce(bp); - bnx2x_init_rx_rings(bp); - bnx2x_init_tx_ring(bp); - bnx2x_init_sp_ring(bp); - bnx2x_init_context(bp); - bnx2x_init_internal(bp); - bnx2x_init_stats(bp); - bnx2x_init_ind_table(bp); - bnx2x_int_enable(bp); - -} - -/* end of nic init */ - -/* - * gzip service functions - */ - -static int bnx2x_gunzip_init(struct bnx2x *bp) -{ - bp->gunzip_buf = pci_alloc_consistent(bp->pdev, FW_BUF_SIZE, - &bp->gunzip_mapping); - if (bp->gunzip_buf == NULL) - goto gunzip_nomem1; - - bp->strm = kmalloc(sizeof(*bp->strm), GFP_KERNEL); - if (bp->strm == NULL) - goto gunzip_nomem2; - - bp->strm->workspace = kmalloc(zlib_inflate_workspacesize(), - GFP_KERNEL); - if (bp->strm->workspace == NULL) - goto gunzip_nomem3; - - return 0; - -gunzip_nomem3: - kfree(bp->strm); - bp->strm = NULL; - -gunzip_nomem2: - pci_free_consistent(bp->pdev, FW_BUF_SIZE, bp->gunzip_buf, - bp->gunzip_mapping); - bp->gunzip_buf = NULL; - -gunzip_nomem1: - printk(KERN_ERR PFX "%s: Cannot allocate firmware buffer for" - " uncompression\n", bp->dev->name); - return -ENOMEM; -} - -static void bnx2x_gunzip_end(struct bnx2x *bp) -{ - kfree(bp->strm->workspace); - - kfree(bp->strm); - bp->strm = NULL; - - if (bp->gunzip_buf) { - pci_free_consistent(bp->pdev, FW_BUF_SIZE, bp->gunzip_buf, - bp->gunzip_mapping); - bp->gunzip_buf = NULL; - } -} - -static int bnx2x_gunzip(struct bnx2x *bp, u8 *zbuf, int len) -{ - int n, rc; - - /* check gzip header */ - if ((zbuf[0] != 0x1f) || (zbuf[1] != 0x8b) || (zbuf[2] != Z_DEFLATED)) - return -EINVAL; - - n = 10; - -#define FNAME 0x8 - - if (zbuf[3] & FNAME) - while ((zbuf[n++] != 0) && (n < len)); - - 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; - - rc = zlib_inflateInit2(bp->strm, -MAX_WBITS); - if (rc != Z_OK) - return rc; - - rc = zlib_inflate(bp->strm, Z_FINISH); - if ((rc != Z_OK) && (rc != Z_STREAM_END)) - printk(KERN_ERR PFX "%s: Firmware decompression error: %s\n", - bp->dev->name, bp->strm->msg); - - bp->gunzip_outlen = (FW_BUF_SIZE - bp->strm->avail_out); - if (bp->gunzip_outlen & 0x3) - printk(KERN_ERR PFX "%s: Firmware decompression error:" - " gunzip_outlen (%d) not aligned\n", - bp->dev->name, bp->gunzip_outlen); - bp->gunzip_outlen >>= 2; - - zlib_inflateEnd(bp->strm); - - if (rc == Z_STREAM_END) - return 0; - - return rc; -} - -/* nic load/unload */ - -/* - * general service functions - */ - -/* send a NIG loopback debug packet */ -static void bnx2x_lb_pckt(struct bnx2x *bp) -{ -#ifdef USE_DMAE - u32 wb_write[3]; -#endif - - /* Ethernet source and destination addresses */ -#ifdef USE_DMAE - wb_write[0] = 0x55555555; - wb_write[1] = 0x55555555; - wb_write[2] = 0x20; /* SOP */ - REG_WR_DMAE(bp, NIG_REG_DEBUG_PACKET_LB, wb_write, 3); -#else - REG_WR_IND(bp, NIG_REG_DEBUG_PACKET_LB, 0x55555555); - REG_WR_IND(bp, NIG_REG_DEBUG_PACKET_LB + 4, 0x55555555); - /* SOP */ - REG_WR_IND(bp, NIG_REG_DEBUG_PACKET_LB + 8, 0x20); -#endif - - /* NON-IP protocol */ -#ifdef USE_DMAE - wb_write[0] = 0x09000000; - wb_write[1] = 0x55555555; - wb_write[2] = 0x10; /* EOP, eop_bvalid = 0 */ - REG_WR_DMAE(bp, NIG_REG_DEBUG_PACKET_LB, wb_write, 3); -#else - REG_WR_IND(bp, NIG_REG_DEBUG_PACKET_LB, 0x09000000); - REG_WR_IND(bp, NIG_REG_DEBUG_PACKET_LB + 4, 0x55555555); - /* EOP, eop_bvalid = 0 */ - REG_WR_IND(bp, NIG_REG_DEBUG_PACKET_LB + 8, 0x10); -#endif -} - -/* some of the internal memories - * are not directly readable from the driver - * to test them we send debug packets - */ -static int bnx2x_int_mem_test(struct bnx2x *bp) -{ - int factor; - int count, i; - u32 val = 0; - - switch (CHIP_REV(bp)) { - case CHIP_REV_EMUL: - factor = 200; - break; - case CHIP_REV_FPGA: - factor = 120; - break; - default: - factor = 1; - break; - } - - DP(NETIF_MSG_HW, "start part1\n"); - - /* Disable inputs of parser neighbor blocks */ - REG_WR(bp, TSDM_REG_ENABLE_IN1, 0x0); - REG_WR(bp, TCM_REG_PRS_IFEN, 0x0); - REG_WR(bp, CFC_REG_DEBUG0, 0x1); - NIG_WR(NIG_REG_PRS_REQ_IN_EN, 0x0); - - /* Write 0 to parser credits for CFC search request */ - REG_WR(bp, PRS_REG_CFC_SEARCH_INITIAL_CREDIT, 0x0); - - /* send Ethernet packet */ - bnx2x_lb_pckt(bp); - - /* TODO do i reset NIG statistic? */ - /* Wait until NIG register shows 1 packet of size 0x10 */ - count = 1000 * factor; - while (count) { -#ifdef BNX2X_DMAE_RD - bnx2x_read_dmae(bp, NIG_REG_STAT2_BRB_OCTET, 2); - val = *bnx2x_sp(bp, wb_data[0]); -#else - val = REG_RD(bp, NIG_REG_STAT2_BRB_OCTET); - REG_RD(bp, NIG_REG_STAT2_BRB_OCTET + 4); -#endif - if (val == 0x10) - break; - - msleep(10); - count--; - } - if (val != 0x10) { - BNX2X_ERR("NIG timeout val = 0x%x\n", val); - return -1; - } - - /* Wait until PRS register shows 1 packet */ - count = 1000 * factor; - while (count) { - val = REG_RD(bp, PRS_REG_NUM_OF_PACKETS); - - if (val == 1) - break; - - msleep(10); - count--; - } - if (val != 0x1) { - BNX2X_ERR("PRS timeout val = 0x%x\n", val); - return -2; - } - - /* Reset and init BRB, PRS */ - REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_1_CLEAR, 0x3); - msleep(50); - REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_1_SET, 0x3); - msleep(50); - bnx2x_init_block(bp, BRB1_COMMON_START, BRB1_COMMON_END); - bnx2x_init_block(bp, PRS_COMMON_START, PRS_COMMON_END); - - DP(NETIF_MSG_HW, "part2\n"); - - /* Disable inputs of parser neighbor blocks */ - REG_WR(bp, TSDM_REG_ENABLE_IN1, 0x0); - REG_WR(bp, TCM_REG_PRS_IFEN, 0x0); - REG_WR(bp, CFC_REG_DEBUG0, 0x1); - NIG_WR(NIG_REG_PRS_REQ_IN_EN, 0x0); - - /* Write 0 to parser credits for CFC search request */ - REG_WR(bp, PRS_REG_CFC_SEARCH_INITIAL_CREDIT, 0x0); - - /* send 10 Ethernet packets */ - for (i = 0; i < 10; i++) - bnx2x_lb_pckt(bp); - - /* Wait until NIG register shows 10 + 1 - packets of size 11*0x10 = 0xb0 */ - count = 1000 * factor; - while (count) { -#ifdef BNX2X_DMAE_RD - bnx2x_read_dmae(bp, NIG_REG_STAT2_BRB_OCTET, 2); - val = *bnx2x_sp(bp, wb_data[0]); -#else - val = REG_RD(bp, NIG_REG_STAT2_BRB_OCTET); - REG_RD(bp, NIG_REG_STAT2_BRB_OCTET + 4); -#endif - if (val == 0xb0) - break; - - msleep(10); - count--; - } - if (val != 0xb0) { - BNX2X_ERR("NIG timeout val = 0x%x\n", val); - return -3; - } - - /* Wait until PRS register shows 2 packets */ - val = REG_RD(bp, PRS_REG_NUM_OF_PACKETS); - if (val != 2) - BNX2X_ERR("PRS timeout val = 0x%x\n", val); - - /* Write 1 to parser credits for CFC search request */ - REG_WR(bp, PRS_REG_CFC_SEARCH_INITIAL_CREDIT, 0x1); - - /* Wait until PRS register shows 3 packets */ - msleep(10 * factor); - /* Wait until NIG register shows 1 packet of size 0x10 */ - val = REG_RD(bp, PRS_REG_NUM_OF_PACKETS); - if (val != 3) - BNX2X_ERR("PRS timeout val = 0x%x\n", val); - - /* clear NIG EOP FIFO */ - for (i = 0; i < 11; i++) - REG_RD(bp, NIG_REG_INGRESS_EOP_LB_FIFO); - val = REG_RD(bp, NIG_REG_INGRESS_EOP_LB_EMPTY); - if (val != 1) { - BNX2X_ERR("clear of NIG failed\n"); - return -4; - } - - /* Reset and init BRB, PRS, NIG */ - REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_1_CLEAR, 0x03); - 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); -#ifndef BCM_ISCSI - /* set NIC mode */ - REG_WR(bp, PRS_REG_NIC_MODE, 1); -#endif - - /* Enable inputs of parser neighbor blocks */ - REG_WR(bp, TSDM_REG_ENABLE_IN1, 0x7fffffff); - REG_WR(bp, TCM_REG_PRS_IFEN, 0x1); - REG_WR(bp, CFC_REG_DEBUG0, 0x0); - NIG_WR(NIG_REG_PRS_REQ_IN_EN, 0x1); - - DP(NETIF_MSG_HW, "done\n"); - - return 0; /* OK */ -} - -static void enable_blocks_attention(struct bnx2x *bp) -{ - REG_WR(bp, PXP_REG_PXP_INT_MASK_0, 0); - REG_WR(bp, PXP_REG_PXP_INT_MASK_1, 0); - REG_WR(bp, DORQ_REG_DORQ_INT_MASK, 0); - REG_WR(bp, CFC_REG_CFC_INT_MASK, 0); - REG_WR(bp, QM_REG_QM_INT_MASK, 0); - REG_WR(bp, TM_REG_TM_INT_MASK, 0); - REG_WR(bp, XSDM_REG_XSDM_INT_MASK_0, 0); - REG_WR(bp, XSDM_REG_XSDM_INT_MASK_1, 0); - REG_WR(bp, XCM_REG_XCM_INT_MASK, 0); -/* REG_WR(bp, XSEM_REG_XSEM_INT_MASK_0, 0); */ -/* REG_WR(bp, XSEM_REG_XSEM_INT_MASK_1, 0); */ - REG_WR(bp, USDM_REG_USDM_INT_MASK_0, 0); - REG_WR(bp, USDM_REG_USDM_INT_MASK_1, 0); - REG_WR(bp, UCM_REG_UCM_INT_MASK, 0); -/* REG_WR(bp, USEM_REG_USEM_INT_MASK_0, 0); */ -/* REG_WR(bp, USEM_REG_USEM_INT_MASK_1, 0); */ - REG_WR(bp, GRCBASE_UPB + PB_REG_PB_INT_MASK, 0); - REG_WR(bp, CSDM_REG_CSDM_INT_MASK_0, 0); - REG_WR(bp, CSDM_REG_CSDM_INT_MASK_1, 0); - REG_WR(bp, CCM_REG_CCM_INT_MASK, 0); -/* REG_WR(bp, CSEM_REG_CSEM_INT_MASK_0, 0); */ -/* REG_WR(bp, CSEM_REG_CSEM_INT_MASK_1, 0); */ - REG_WR(bp, PXP2_REG_PXP2_INT_MASK, 0x480000); - REG_WR(bp, TSDM_REG_TSDM_INT_MASK_0, 0); - REG_WR(bp, TSDM_REG_TSDM_INT_MASK_1, 0); - REG_WR(bp, TCM_REG_TCM_INT_MASK, 0); -/* REG_WR(bp, TSEM_REG_TSEM_INT_MASK_0, 0); */ -/* REG_WR(bp, TSEM_REG_TSEM_INT_MASK_1, 0); */ - REG_WR(bp, CDU_REG_CDU_INT_MASK, 0); - REG_WR(bp, DMAE_REG_DMAE_INT_MASK, 0); -/* REG_WR(bp, MISC_REG_MISC_INT_MASK, 0); */ - REG_WR(bp, PBF_REG_PBF_INT_MASK, 0X18); /* bit 3,4 masked */ -} - -static int bnx2x_function_init(struct bnx2x *bp, int mode) -{ - int func = bp->port; - int port = func ? PORT1 : PORT0; - u32 val, i; -#ifdef USE_DMAE - u32 wb_write[2]; -#endif - - DP(BNX2X_MSG_MCP, "function is %d mode is %x\n", func, mode); - if ((func != 0) && (func != 1)) { - BNX2X_ERR("BAD function number (%d)\n", func); - return -ENODEV; - } - - bnx2x_gunzip_init(bp); - - if (mode & 0x1) { /* init common */ - DP(BNX2X_MSG_MCP, "starting common init func %d mode %x\n", - func, mode); - 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); - - REG_WR(bp, MISC_REG_LCPLL_CTRL_REG_2, 0x100); - 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, PXP2_COMMON_START, PXP2_COMMON_END); - - bnx2x_init_pxp(bp); - - if (CHIP_REV(bp) == CHIP_REV_Ax) { - /* enable HW interrupt from PXP on USDM - overflow bit 16 on INT_MASK_0 */ - REG_WR(bp, PXP_REG_PXP_INT_MASK_0, 0); - } - -#ifdef __BIG_ENDIAN - REG_WR(bp, PXP2_REG_RQ_QM_ENDIAN_M, 1); - REG_WR(bp, PXP2_REG_RQ_TM_ENDIAN_M, 1); - REG_WR(bp, PXP2_REG_RQ_SRC_ENDIAN_M, 1); - REG_WR(bp, PXP2_REG_RQ_CDU_ENDIAN_M, 1); - REG_WR(bp, PXP2_REG_RQ_DBG_ENDIAN_M, 1); - REG_WR(bp, PXP2_REG_RQ_HC_ENDIAN_M, 1); - -/* REG_WR(bp, PXP2_REG_RD_PBF_SWAP_MODE, 1); */ - REG_WR(bp, PXP2_REG_RD_QM_SWAP_MODE, 1); - REG_WR(bp, PXP2_REG_RD_TM_SWAP_MODE, 1); - REG_WR(bp, PXP2_REG_RD_SRC_SWAP_MODE, 1); - REG_WR(bp, PXP2_REG_RD_CDURD_SWAP_MODE, 1); -#endif - -#ifndef BCM_ISCSI - /* set NIC mode */ - REG_WR(bp, PRS_REG_NIC_MODE, 1); -#endif - - REG_WR(bp, PXP2_REG_RQ_CDU_P_SIZE, 5); -#ifdef BCM_ISCSI - REG_WR(bp, PXP2_REG_RQ_TM_P_SIZE, 5); - REG_WR(bp, PXP2_REG_RQ_QM_P_SIZE, 5); - REG_WR(bp, PXP2_REG_RQ_SRC_P_SIZE, 5); -#endif - - bnx2x_init_block(bp, DMAE_COMMON_START, DMAE_COMMON_END); - - /* let the HW do it's magic ... */ - msleep(100); - /* finish PXP init - (can be moved up if we want to use the DMAE) */ - val = REG_RD(bp, PXP2_REG_RQ_CFG_DONE); - if (val != 1) { - BNX2X_ERR("PXP2 CFG failed\n"); - return -EBUSY; - } - - val = REG_RD(bp, PXP2_REG_RD_INIT_DONE); - if (val != 1) { - BNX2X_ERR("PXP2 RD_INIT failed\n"); - return -EBUSY; - } - - REG_WR(bp, PXP2_REG_RQ_DISABLE_INPUTS, 0); - REG_WR(bp, PXP2_REG_RD_DISABLE_INPUTS, 0); - - 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); - -#ifdef BNX2X_DMAE_RD - 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); -#else - REG_RD(bp, XSEM_REG_PASSIVE_BUFFER); - REG_RD(bp, XSEM_REG_PASSIVE_BUFFER + 4); - REG_RD(bp, XSEM_REG_PASSIVE_BUFFER + 8); - REG_RD(bp, CSEM_REG_PASSIVE_BUFFER); - REG_RD(bp, CSEM_REG_PASSIVE_BUFFER + 4); - REG_RD(bp, CSEM_REG_PASSIVE_BUFFER + 8); - REG_RD(bp, TSEM_REG_PASSIVE_BUFFER); - REG_RD(bp, TSEM_REG_PASSIVE_BUFFER + 4); - REG_RD(bp, TSEM_REG_PASSIVE_BUFFER + 8); - REG_RD(bp, USEM_REG_PASSIVE_BUFFER); - REG_RD(bp, USEM_REG_PASSIVE_BUFFER + 4); - REG_RD(bp, USEM_REG_PASSIVE_BUFFER + 8); -#endif - bnx2x_init_block(bp, QM_COMMON_START, QM_COMMON_END); - /* 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); -#endif - bnx2x_init_block(bp, DQ_COMMON_START, DQ_COMMON_END); - REG_WR(bp, DORQ_REG_DPM_CID_OFST, BCM_PAGE_BITS); - if (CHIP_REV(bp) == CHIP_REV_Ax) { - /* 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); - - if (CHIP_REV_IS_SLOW(bp)) { - /* fix for emulation and FPGA for no pause */ - REG_WR(bp, BRB1_REG_PAUSE_HIGH_THRESHOLD_0, 513); - REG_WR(bp, BRB1_REG_PAUSE_HIGH_THRESHOLD_1, 513); - REG_WR(bp, BRB1_REG_PAUSE_LOW_THRESHOLD_0, 0); - REG_WR(bp, BRB1_REG_PAUSE_LOW_THRESHOLD_1, 0); - } - - bnx2x_init_block(bp, PRS_COMMON_START, PRS_COMMON_END); - - 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_fill(bp, TSTORM_INTMEM_ADDR, 0, STORM_INTMEM_SIZE); - bnx2x_init_fill(bp, CSTORM_INTMEM_ADDR, 0, STORM_INTMEM_SIZE); - bnx2x_init_fill(bp, XSTORM_INTMEM_ADDR, 0, STORM_INTMEM_SIZE); - bnx2x_init_fill(bp, USTORM_INTMEM_ADDR, 0, STORM_INTMEM_SIZE); - - 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); - - /* sync semi rtc */ - REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_1_CLEAR, - 0x80000000); - 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); - - 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 */ - } - /* SRCH COMMON comes here */ - REG_WR(bp, SRC_REG_SOFT_RST, 0); - - if (sizeof(union cdu_context) != 1024) { - /* we currently assume that a context is 1024 bytes */ - printk(KERN_ALERT PFX "please adjust the size of" - " cdu_context(%ld)\n", - (long)sizeof(union cdu_context)); - } - val = (4 << 24) + (0 << 12) + 1024; - REG_WR(bp, CDU_REG_CDU_GLOBAL_PARAMS, val); - bnx2x_init_block(bp, CDU_COMMON_START, CDU_COMMON_END); - - bnx2x_init_block(bp, CFC_COMMON_START, CFC_COMMON_END); - REG_WR(bp, CFC_REG_INIT_REG, 0x7FF); - - bnx2x_init_block(bp, HC_COMMON_START, HC_COMMON_END); - bnx2x_init_block(bp, MISC_AEU_COMMON_START, - MISC_AEU_COMMON_END); - /* RXPCS COMMON comes here */ - /* EMAC0 COMMON comes here */ - /* EMAC1 COMMON comes here */ - /* DBU COMMON comes here */ - /* DBG COMMON comes here */ - bnx2x_init_block(bp, NIG_COMMON_START, NIG_COMMON_END); - - if (CHIP_REV_IS_SLOW(bp)) - msleep(200); - - /* finish CFC init */ - val = REG_RD(bp, CFC_REG_LL_INIT_DONE); - if (val != 1) { - BNX2X_ERR("CFC LL_INIT failed\n"); - return -EBUSY; - } - - val = REG_RD(bp, CFC_REG_AC_INIT_DONE); - if (val != 1) { - BNX2X_ERR("CFC AC_INIT failed\n"); - return -EBUSY; - } - - val = REG_RD(bp, CFC_REG_CAM_INIT_DONE); - if (val != 1) { - BNX2X_ERR("CFC CAM_INIT failed\n"); - return -EBUSY; - } - - REG_WR(bp, CFC_REG_DEBUG0, 0); - - /* read NIG statistic - to see if this is our first up since powerup */ -#ifdef BNX2X_DMAE_RD - bnx2x_read_dmae(bp, NIG_REG_STAT2_BRB_OCTET, 2); - val = *bnx2x_sp(bp, wb_data[0]); -#else - val = REG_RD(bp, NIG_REG_STAT2_BRB_OCTET); - REG_RD(bp, NIG_REG_STAT2_BRB_OCTET + 4); -#endif - /* do internal memory self test */ - if ((val == 0) && bnx2x_int_mem_test(bp)) { - BNX2X_ERR("internal mem selftest failed\n"); - return -EBUSY; - } - - /* clear PXP2 attentions */ - REG_RD(bp, PXP2_REG_PXP2_INT_STS_CLR); - - enable_blocks_attention(bp); - /* enable_blocks_parity(bp); */ - - switch (bp->board & SHARED_HW_CFG_BOARD_TYPE_MASK) { - case SHARED_HW_CFG_BOARD_TYPE_BCM957710A1022G: - /* Fan failure is indicated by SPIO 5 */ - bnx2x_set_spio(bp, MISC_REGISTERS_SPIO_5, - MISC_REGISTERS_SPIO_INPUT_HI_Z); - - /* set to active low mode */ - val = REG_RD(bp, MISC_REG_SPIO_INT); - val |= ((1 << MISC_REGISTERS_SPIO_5) << - MISC_REGISTERS_SPIO_INT_OLD_SET_POS); - REG_WR(bp, MISC_REG_SPIO_INT, val); - - /* enable interrupt to signal the IGU */ - val = REG_RD(bp, MISC_REG_SPIO_EVENT_EN); - val |= (1 << MISC_REGISTERS_SPIO_5); - REG_WR(bp, MISC_REG_SPIO_EVENT_EN, val); - break; - - default: - break; - } - - } /* end of common init */ - - /* per port init */ - - /* the phys address is shifted right 12 bits and has an added - 1=valid bit added to the 53rd bit - then since this is a wide register(TM) - we split it into two 32 bit writes - */ -#define RQ_ONCHIP_AT_PORT_SIZE 384 -#define ONCHIP_ADDR1(x) ((u32)(((u64)x >> 12) & 0xFFFFFFFF)) -#define ONCHIP_ADDR2(x) ((u32)((1 << 20) | ((u64)x >> 44))) -#define PXP_ONE_ILT(x) ((x << 10) | x) - - DP(BNX2X_MSG_MCP, "starting per-function init port is %x\n", func); - - REG_WR(bp, NIG_REG_MASK_INTERRUPT_PORT0 + func*4, 0); - - /* Port PXP comes here */ - /* Port PXP2 comes here */ - - /* Offset is - * Port0 0 - * Port1 384 */ - i = func * RQ_ONCHIP_AT_PORT_SIZE; -#ifdef USE_DMAE - wb_write[0] = ONCHIP_ADDR1(bnx2x_sp_mapping(bp, context)); - wb_write[1] = ONCHIP_ADDR2(bnx2x_sp_mapping(bp, context)); - REG_WR_DMAE(bp, PXP2_REG_RQ_ONCHIP_AT + i*8, wb_write, 2); -#else - REG_WR_IND(bp, PXP2_REG_RQ_ONCHIP_AT + i*8, - ONCHIP_ADDR1(bnx2x_sp_mapping(bp, context))); - REG_WR_IND(bp, PXP2_REG_RQ_ONCHIP_AT + i*8 + 4, - ONCHIP_ADDR2(bnx2x_sp_mapping(bp, context))); -#endif - REG_WR(bp, PXP2_REG_PSWRQ_CDU0_L2P + func*4, PXP_ONE_ILT(i)); - -#ifdef BCM_ISCSI - /* Port0 1 - * Port1 385 */ - i++; - wb_write[0] = ONCHIP_ADDR1(bp->timers_mapping); - wb_write[1] = ONCHIP_ADDR2(bp->timers_mapping); - REG_WR_DMAE(bp, PXP2_REG_RQ_ONCHIP_AT + i*8, wb_write, 2); - REG_WR(bp, PXP2_REG_PSWRQ_TM0_L2P + func*4, PXP_ONE_ILT(i)); - - /* Port0 2 - * Port1 386 */ - i++; - wb_write[0] = ONCHIP_ADDR1(bp->qm_mapping); - wb_write[1] = ONCHIP_ADDR2(bp->qm_mapping); - REG_WR_DMAE(bp, PXP2_REG_RQ_ONCHIP_AT + i*8, wb_write, 2); - REG_WR(bp, PXP2_REG_PSWRQ_QM0_L2P + func*4, PXP_ONE_ILT(i)); - - /* Port0 3 - * Port1 387 */ - i++; - wb_write[0] = ONCHIP_ADDR1(bp->t1_mapping); - wb_write[1] = ONCHIP_ADDR2(bp->t1_mapping); - REG_WR_DMAE(bp, PXP2_REG_RQ_ONCHIP_AT + i*8, wb_write, 2); - REG_WR(bp, PXP2_REG_PSWRQ_SRC0_L2P + func*4, PXP_ONE_ILT(i)); -#endif - - /* Port TCM comes here */ - /* Port UCM comes here */ - /* Port CCM comes here */ - bnx2x_init_block(bp, func ? XCM_PORT1_START : XCM_PORT0_START, - func ? XCM_PORT1_END : XCM_PORT0_END); - -#ifdef USE_DMAE - wb_write[0] = 0; - wb_write[1] = 0; -#endif - for (i = 0; i < 32; i++) { - REG_WR(bp, QM_REG_BASEADDR + (func*32 + i)*4, 1024 * 4 * i); -#ifdef USE_DMAE - REG_WR_DMAE(bp, QM_REG_PTRTBL + (func*32 + i)*8, wb_write, 2); -#else - REG_WR_IND(bp, QM_REG_PTRTBL + (func*32 + i)*8, 0); - REG_WR_IND(bp, QM_REG_PTRTBL + (func*32 + i)*8 + 4, 0); -#endif - } - REG_WR(bp, QM_REG_CONNNUM_0 + func*4, 1024/16 - 1); - - /* 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); -#endif - /* Port DQ comes here */ - /* Port BRB1 comes here */ - bnx2x_init_block(bp, func ? PRS_PORT1_START : PRS_PORT0_START, - func ? PRS_PORT1_END : PRS_PORT0_END); - /* Port TSDM comes here */ - /* Port CSDM comes here */ - /* Port USDM comes here */ - /* Port XSDM comes here */ - bnx2x_init_block(bp, func ? TSEM_PORT1_START : TSEM_PORT0_START, - func ? TSEM_PORT1_END : TSEM_PORT0_END); - bnx2x_init_block(bp, func ? USEM_PORT1_START : USEM_PORT0_START, - func ? USEM_PORT1_END : USEM_PORT0_END); - bnx2x_init_block(bp, func ? CSEM_PORT1_START : CSEM_PORT0_START, - func ? CSEM_PORT1_END : CSEM_PORT0_END); - bnx2x_init_block(bp, func ? XSEM_PORT1_START : XSEM_PORT0_START, - func ? XSEM_PORT1_END : XSEM_PORT0_END); - /* Port UPB comes here */ - /* Port XSDM comes here */ - bnx2x_init_block(bp, func ? PBF_PORT1_START : PBF_PORT0_START, - func ? PBF_PORT1_END : PBF_PORT0_END); - - /* configure PBF to work without PAUSE mtu 9000 */ - REG_WR(bp, PBF_REG_P0_PAUSE_ENABLE + func*4, 0); - - /* update threshold */ - REG_WR(bp, PBF_REG_P0_ARB_THRSH + func*4, (9040/16)); - /* update init credit */ - REG_WR(bp, PBF_REG_P0_INIT_CRD + func*4, (9040/16) + 553 - 22); - - /* probe changes */ - REG_WR(bp, PBF_REG_INIT_P0 + func*4, 1); - msleep(5); - REG_WR(bp, PBF_REG_INIT_P0 + func*4, 0); - -#ifdef BCM_ISCSI - /* tell the searcher where the T2 table is */ - REG_WR(bp, SRC_REG_COUNTFREE0 + func*4, 16*1024/64); - - wb_write[0] = U64_LO(bp->t2_mapping); - wb_write[1] = U64_HI(bp->t2_mapping); - REG_WR_DMAE(bp, SRC_REG_FIRSTFREE0 + func*4, wb_write, 2); - wb_write[0] = U64_LO((u64)bp->t2_mapping + 16*1024 - 64); - wb_write[1] = U64_HI((u64)bp->t2_mapping + 16*1024 - 64); - REG_WR_DMAE(bp, SRC_REG_LASTFREE0 + func*4, wb_write, 2); - - REG_WR(bp, SRC_REG_NUMBER_HASH_BITS0 + func*4, 10); - /* Port SRCH comes here */ -#endif - /* Port CDU comes here */ - /* Port CFC comes here */ - bnx2x_init_block(bp, func ? HC_PORT1_START : HC_PORT0_START, - func ? HC_PORT1_END : HC_PORT0_END); - bnx2x_init_block(bp, func ? MISC_AEU_PORT1_START : - MISC_AEU_PORT0_START, - func ? MISC_AEU_PORT1_END : MISC_AEU_PORT0_END); - /* Port PXPCS comes here */ - /* Port EMAC0 comes here */ - /* Port EMAC1 comes here */ - /* Port DBU comes here */ - /* Port DBG comes here */ - bnx2x_init_block(bp, func ? NIG_PORT1_START : NIG_PORT0_START, - func ? NIG_PORT1_END : NIG_PORT0_END); - REG_WR(bp, NIG_REG_XGXS_SERDES0_MODE_SEL + func*4, 1); - /* Port MCP comes here */ - /* Port DMAE comes here */ - - switch (bp->board & SHARED_HW_CFG_BOARD_TYPE_MASK) { - case SHARED_HW_CFG_BOARD_TYPE_BCM957710A1022G: - /* add SPIO 5 to group 0 */ - val = REG_RD(bp, MISC_REG_AEU_ENABLE1_FUNC_0_OUT_0); - val |= AEU_INPUTS_ATTN_BITS_SPIO5; - REG_WR(bp, MISC_REG_AEU_ENABLE1_FUNC_0_OUT_0, val); - break; - - default: - break; - } - - bnx2x_link_reset(bp); - - /* Reset PCIE errors for debug */ - REG_WR(bp, 0x2114, 0xffffffff); - REG_WR(bp, 0x2120, 0xffffffff); - REG_WR(bp, 0x2814, 0xffffffff); - - /* !!! move to init_values.h */ - REG_WR(bp, XSDM_REG_INIT_CREDIT_PXP_CTRL, 0x1); - REG_WR(bp, USDM_REG_INIT_CREDIT_PXP_CTRL, 0x1); - REG_WR(bp, CSDM_REG_INIT_CREDIT_PXP_CTRL, 0x1); - REG_WR(bp, TSDM_REG_INIT_CREDIT_PXP_CTRL, 0x1); - - REG_WR(bp, DBG_REG_PCI_REQ_CREDIT, 0x1); - REG_WR(bp, TM_REG_PCIARB_CRDCNT_VAL, 0x1); - REG_WR(bp, CDU_REG_CDU_DEBUG, 0x264); - REG_WR(bp, CDU_REG_CDU_DEBUG, 0x0); - - bnx2x_gunzip_end(bp); - - if (!nomcp) { - port = bp->port; - - bp->fw_drv_pulse_wr_seq = - (SHMEM_RD(bp, func_mb[port].drv_pulse_mb) & - DRV_PULSE_SEQ_MASK); - bp->fw_mb = SHMEM_RD(bp, func_mb[port].fw_mb_param); - DP(BNX2X_MSG_MCP, "drv_pulse 0x%x fw_mb 0x%x\n", - bp->fw_drv_pulse_wr_seq, bp->fw_mb); - } else { - bp->fw_mb = 0; - } - - return 0; -} - -/* send the MCP a request, block until there is a reply */ -static u32 bnx2x_fw_command(struct bnx2x *bp, u32 command) -{ - int port = bp->port; - u32 seq = ++bp->fw_seq; - u32 rc = 0; - - SHMEM_WR(bp, func_mb[port].drv_mb_header, (command | seq)); - DP(BNX2X_MSG_MCP, "wrote command (%x) to FW MB\n", (command | seq)); - - /* let the FW do it's magic ... */ - msleep(100); /* TBD */ - - if (CHIP_REV_IS_SLOW(bp)) - msleep(900); - - rc = SHMEM_RD(bp, func_mb[port].fw_mb_header); - DP(BNX2X_MSG_MCP, "read (%x) seq is (%x) from FW MB\n", rc, seq); - - /* is this a reply to our command? */ - if (seq == (rc & FW_MSG_SEQ_NUMBER_MASK)) { - rc &= FW_MSG_CODE_MASK; - - } else { - /* FW BUG! */ - BNX2X_ERR("FW failed to respond!\n"); - bnx2x_fw_dump(bp); - rc = 0; - } - - return rc; -} - -static void bnx2x_free_mem(struct bnx2x *bp) -{ - -#define BNX2X_PCI_FREE(x, y, size) \ - do { \ - if (x) { \ - pci_free_consistent(bp->pdev, size, x, y); \ - x = NULL; \ - y = 0; \ - } \ - } while (0) - -#define BNX2X_FREE(x) \ - do { \ - if (x) { \ - vfree(x); \ - x = NULL; \ - } \ - } while (0) - - int i; - - /* fastpath */ - for_each_queue(bp, i) { - - /* Status blocks */ - BNX2X_PCI_FREE(bnx2x_fp(bp, i, status_blk), - bnx2x_fp(bp, i, status_blk_mapping), - sizeof(struct host_status_block) + - sizeof(struct eth_tx_db_data)); - - /* fast path rings: tx_buf tx_desc rx_buf rx_desc rx_comp */ - BNX2X_FREE(bnx2x_fp(bp, i, tx_buf_ring)); - BNX2X_PCI_FREE(bnx2x_fp(bp, i, tx_desc_ring), - bnx2x_fp(bp, i, tx_desc_mapping), - sizeof(struct eth_tx_bd) * NUM_TX_BD); - - BNX2X_FREE(bnx2x_fp(bp, i, rx_buf_ring)); - BNX2X_PCI_FREE(bnx2x_fp(bp, i, rx_desc_ring), - bnx2x_fp(bp, i, rx_desc_mapping), - sizeof(struct eth_rx_bd) * NUM_RX_BD); - - BNX2X_PCI_FREE(bnx2x_fp(bp, i, rx_comp_ring), - bnx2x_fp(bp, i, rx_comp_mapping), - sizeof(struct eth_fast_path_rx_cqe) * - NUM_RCQ_BD); - } - - BNX2X_FREE(bp->fp); - - /* end of fastpath */ - - BNX2X_PCI_FREE(bp->def_status_blk, bp->def_status_blk_mapping, - (sizeof(struct host_def_status_block))); - - BNX2X_PCI_FREE(bp->slowpath, bp->slowpath_mapping, - (sizeof(struct bnx2x_slowpath))); - -#ifdef BCM_ISCSI - BNX2X_PCI_FREE(bp->t1, bp->t1_mapping, 64*1024); - BNX2X_PCI_FREE(bp->t2, bp->t2_mapping, 16*1024); - BNX2X_PCI_FREE(bp->timers, bp->timers_mapping, 8*1024); - BNX2X_PCI_FREE(bp->qm, bp->qm_mapping, 128*1024); -#endif - BNX2X_PCI_FREE(bp->spq, bp->spq_mapping, PAGE_SIZE); - -#undef BNX2X_PCI_FREE -#undef BNX2X_KFREE -} - -static int bnx2x_alloc_mem(struct bnx2x *bp) -{ - -#define BNX2X_PCI_ALLOC(x, y, size) \ - do { \ - x = pci_alloc_consistent(bp->pdev, size, y); \ - if (x == NULL) \ - goto alloc_mem_err; \ - memset(x, 0, size); \ - } while (0) - -#define BNX2X_ALLOC(x, size) \ - do { \ - x = vmalloc(size); \ - if (x == NULL) \ - goto alloc_mem_err; \ - memset(x, 0, size); \ - } while (0) - - int i; - - /* fastpath */ - BNX2X_ALLOC(bp->fp, sizeof(struct bnx2x_fastpath) * bp->num_queues); - - for_each_queue(bp, i) { - bnx2x_fp(bp, i, bp) = bp; - - /* Status blocks */ - BNX2X_PCI_ALLOC(bnx2x_fp(bp, i, status_blk), - &bnx2x_fp(bp, i, status_blk_mapping), - sizeof(struct host_status_block) + - sizeof(struct eth_tx_db_data)); - - bnx2x_fp(bp, i, hw_tx_prods) = - (void *)(bnx2x_fp(bp, i, status_blk) + 1); - - bnx2x_fp(bp, i, tx_prods_mapping) = - bnx2x_fp(bp, i, status_blk_mapping) + - sizeof(struct host_status_block); - - /* fast path rings: tx_buf tx_desc rx_buf rx_desc rx_comp */ - BNX2X_ALLOC(bnx2x_fp(bp, i, tx_buf_ring), - sizeof(struct sw_tx_bd) * NUM_TX_BD); - BNX2X_PCI_ALLOC(bnx2x_fp(bp, i, tx_desc_ring), - &bnx2x_fp(bp, i, tx_desc_mapping), - sizeof(struct eth_tx_bd) * NUM_TX_BD); - - BNX2X_ALLOC(bnx2x_fp(bp, i, rx_buf_ring), - sizeof(struct sw_rx_bd) * NUM_RX_BD); - BNX2X_PCI_ALLOC(bnx2x_fp(bp, i, rx_desc_ring), - &bnx2x_fp(bp, i, rx_desc_mapping), - sizeof(struct eth_rx_bd) * NUM_RX_BD); - - BNX2X_PCI_ALLOC(bnx2x_fp(bp, i, rx_comp_ring), - &bnx2x_fp(bp, i, rx_comp_mapping), - sizeof(struct eth_fast_path_rx_cqe) * - NUM_RCQ_BD); - - } - /* end of fastpath */ - - BNX2X_PCI_ALLOC(bp->def_status_blk, &bp->def_status_blk_mapping, - sizeof(struct host_def_status_block)); - - BNX2X_PCI_ALLOC(bp->slowpath, &bp->slowpath_mapping, - sizeof(struct bnx2x_slowpath)); - -#ifdef BCM_ISCSI - BNX2X_PCI_ALLOC(bp->t1, &bp->t1_mapping, 64*1024); - - /* Initialize T1 */ - for (i = 0; i < 64*1024; i += 64) { - *(u64 *)((char *)bp->t1 + i + 56) = 0x0UL; - *(u64 *)((char *)bp->t1 + i + 3) = 0x0UL; - } - - /* allocate searcher T2 table - we allocate 1/4 of alloc num for T2 - (which is not entered into the ILT) */ - BNX2X_PCI_ALLOC(bp->t2, &bp->t2_mapping, 16*1024); - - /* Initialize T2 */ - for (i = 0; i < 16*1024; i += 64) - * (u64 *)((char *)bp->t2 + i + 56) = bp->t2_mapping + i + 64; - - /* now fixup the last line in the block to point to the next block */ - *(u64 *)((char *)bp->t2 + 1024*16-8) = bp->t2_mapping; - - /* Timer block array (MAX_CONN*8) phys uncached for now 1024 conns */ - BNX2X_PCI_ALLOC(bp->timers, &bp->timers_mapping, 8*1024); - - /* QM queues (128*MAX_CONN) */ - BNX2X_PCI_ALLOC(bp->qm, &bp->qm_mapping, 128*1024); -#endif - - /* Slow path ring */ - BNX2X_PCI_ALLOC(bp->spq, &bp->spq_mapping, BCM_PAGE_SIZE); - - return 0; - -alloc_mem_err: - bnx2x_free_mem(bp); - return -ENOMEM; - -#undef BNX2X_PCI_ALLOC -#undef BNX2X_ALLOC -} - -static void bnx2x_free_tx_skbs(struct bnx2x *bp) -{ - int i; - - for_each_queue(bp, i) { - struct bnx2x_fastpath *fp = &bp->fp[i]; - - u16 bd_cons = fp->tx_bd_cons; - u16 sw_prod = fp->tx_pkt_prod; - u16 sw_cons = fp->tx_pkt_cons; - - BUG_TRAP(fp->tx_buf_ring != NULL); - - while (sw_cons != sw_prod) { - bd_cons = bnx2x_free_tx_pkt(bp, fp, TX_BD(sw_cons)); - sw_cons++; - } - } -} - -static void bnx2x_free_rx_skbs(struct bnx2x *bp) -{ - int i, j; - - for_each_queue(bp, j) { - struct bnx2x_fastpath *fp = &bp->fp[j]; - - BUG_TRAP(fp->rx_buf_ring != NULL); - - for (i = 0; i < NUM_RX_BD; i++) { - struct sw_rx_bd *rx_buf = &fp->rx_buf_ring[i]; - struct sk_buff *skb = rx_buf->skb; - - if (skb == NULL) - continue; - - pci_unmap_single(bp->pdev, - pci_unmap_addr(rx_buf, mapping), - bp->rx_buf_use_size, - PCI_DMA_FROMDEVICE); - - rx_buf->skb = NULL; - dev_kfree_skb(skb); - } - } -} - -static void bnx2x_free_skbs(struct bnx2x *bp) -{ - bnx2x_free_tx_skbs(bp); - bnx2x_free_rx_skbs(bp); -} - -static void bnx2x_free_msix_irqs(struct bnx2x *bp) -{ - int i; - - free_irq(bp->msix_table[0].vector, bp->dev); - DP(NETIF_MSG_IFDOWN, "released sp irq (%d)\n", - bp->msix_table[0].vector); - - for_each_queue(bp, i) { - DP(NETIF_MSG_IFDOWN, "about to release fp #%d->%d irq " - "state(%x)\n", i, bp->msix_table[i + 1].vector, - bnx2x_fp(bp, i, state)); - - if (bnx2x_fp(bp, i, state) != BNX2X_FP_STATE_CLOSED) - BNX2X_ERR("IRQ of fp #%d being freed while " - "state != closed\n", i); - - free_irq(bp->msix_table[i + 1].vector, &bp->fp[i]); - } - -} - -static void bnx2x_free_irq(struct bnx2x *bp) -{ - - if (bp->flags & USING_MSIX_FLAG) { - - bnx2x_free_msix_irqs(bp); - pci_disable_msix(bp->pdev); - - bp->flags &= ~USING_MSIX_FLAG; - - } else - free_irq(bp->pdev->irq, bp->dev); -} - -static int bnx2x_enable_msix(struct bnx2x *bp) -{ - - int i; - - bp->msix_table[0].entry = 0; - for_each_queue(bp, i) - bp->msix_table[i + 1].entry = i + 1; - - if (pci_enable_msix(bp->pdev, &bp->msix_table[0], - bp->num_queues + 1)){ - BNX2X_LOG("failed to enable MSI-X\n"); - return -1; - - } - - bp->flags |= USING_MSIX_FLAG; - - return 0; - -} - - -static int bnx2x_req_msix_irqs(struct bnx2x *bp) -{ - - int i, rc; - - rc = request_irq(bp->msix_table[0].vector, bnx2x_msix_sp_int, 0, - bp->dev->name, bp->dev); - - if (rc) { - BNX2X_ERR("request sp irq failed\n"); - return -EBUSY; - } - - for_each_queue(bp, i) { - rc = request_irq(bp->msix_table[i + 1].vector, - bnx2x_msix_fp_int, 0, - bp->dev->name, &bp->fp[i]); - - if (rc) { - BNX2X_ERR("request fp #%d irq failed " - "rc %d\n", i, rc); - bnx2x_free_msix_irqs(bp); - return -EBUSY; - } - - bnx2x_fp(bp, i, state) = BNX2X_FP_STATE_IRQ; - - } - - return 0; - -} - -static int bnx2x_req_irq(struct bnx2x *bp) -{ - - int rc = request_irq(bp->pdev->irq, bnx2x_interrupt, - IRQF_SHARED, bp->dev->name, bp->dev); - if (!rc) - bnx2x_fp(bp, 0, state) = BNX2X_FP_STATE_IRQ; - - return rc; - -} - -/* - * Init service functions - */ - -static void bnx2x_set_mac_addr(struct bnx2x *bp) -{ - struct mac_configuration_cmd *config = bnx2x_sp(bp, mac_config); - - /* CAM allocation - * unicasts 0-31:port0 32-63:port1 - * multicast 64-127:port0 128-191:port1 - */ - config->hdr.length_6b = 2; - config->hdr.offset = bp->port ? 31 : 0; - config->hdr.reserved0 = 0; - config->hdr.reserved1 = 0; - - /* primary MAC */ - config->config_table[0].cam_entry.msb_mac_addr = - swab16(*(u16 *)&bp->dev->dev_addr[0]); - config->config_table[0].cam_entry.middle_mac_addr = - swab16(*(u16 *)&bp->dev->dev_addr[2]); - config->config_table[0].cam_entry.lsb_mac_addr = - swab16(*(u16 *)&bp->dev->dev_addr[4]); - config->config_table[0].cam_entry.flags = cpu_to_le16(bp->port); - config->config_table[0].target_table_entry.flags = 0; - config->config_table[0].target_table_entry.client_id = 0; - config->config_table[0].target_table_entry.vlan_id = 0; - - DP(NETIF_MSG_IFUP, "setting MAC (%04x:%04x:%04x)\n", - config->config_table[0].cam_entry.msb_mac_addr, - config->config_table[0].cam_entry.middle_mac_addr, - config->config_table[0].cam_entry.lsb_mac_addr); - - /* broadcast */ - config->config_table[1].cam_entry.msb_mac_addr = 0xffff; - config->config_table[1].cam_entry.middle_mac_addr = 0xffff; - config->config_table[1].cam_entry.lsb_mac_addr = 0xffff; - config->config_table[1].cam_entry.flags = cpu_to_le16(bp->port); - config->config_table[1].target_table_entry.flags = - TSTORM_CAM_TARGET_TABLE_ENTRY_BROADCAST; - config->config_table[1].target_table_entry.client_id = 0; - config->config_table[1].target_table_entry.vlan_id = 0; - - bnx2x_sp_post(bp, RAMROD_CMD_ID_ETH_SET_MAC, 0, - U64_HI(bnx2x_sp_mapping(bp, mac_config)), - U64_LO(bnx2x_sp_mapping(bp, mac_config)), 0); -} - -static int bnx2x_wait_ramrod(struct bnx2x *bp, int state, int idx, - int *state_p, int poll) -{ - /* can take a while if any port is running */ - int timeout = 500; - - DP(NETIF_MSG_IFUP, "%s for state to become %x on IDX [%d]\n", - poll ? "polling" : "waiting", state, idx); - - might_sleep(); - - while (timeout) { - - if (poll) { - bnx2x_rx_int(bp->fp, 10); - /* If index is different from 0 - * The reply for some commands will - * be on the none default queue - */ - if (idx) - bnx2x_rx_int(&bp->fp[idx], 10); - } - - mb(); /* state is changed by bnx2x_sp_event()*/ - - if (*state_p == state) - return 0; - - timeout--; - msleep(1); - - } - - /* timeout! */ - BNX2X_ERR("timeout %s for state %x on IDX [%d]\n", - poll ? "polling" : "waiting", state, idx); - - return -EBUSY; -} - -static int bnx2x_setup_leading(struct bnx2x *bp) -{ - - /* reset IGU state */ - bnx2x_ack_sb(bp, DEF_SB_ID, CSTORM_ID, 0, IGU_INT_ENABLE, 0); - - /* SETUP ramrod */ - bnx2x_sp_post(bp, RAMROD_CMD_ID_ETH_PORT_SETUP, 0, 0, 0, 0); - - return bnx2x_wait_ramrod(bp, BNX2X_STATE_OPEN, 0, &(bp->state), 0); - -} - -static int bnx2x_setup_multi(struct bnx2x *bp, int index) -{ - - /* reset IGU state */ - bnx2x_ack_sb(bp, index, CSTORM_ID, 0, IGU_INT_ENABLE, 0); - - /* SETUP ramrod */ - bp->fp[index].state = BNX2X_FP_STATE_OPENING; - bnx2x_sp_post(bp, RAMROD_CMD_ID_ETH_CLIENT_SETUP, index, 0, index, 0); - - /* Wait for completion */ - return bnx2x_wait_ramrod(bp, BNX2X_FP_STATE_OPEN, index, - &(bp->fp[index].state), 0); - -} - - -static int bnx2x_poll(struct napi_struct *napi, int budget); -static void bnx2x_set_rx_mode(struct net_device *dev); - -static int bnx2x_nic_load(struct bnx2x *bp, int req_irq) -{ - u32 load_code; - int i; - - bp->state = BNX2X_STATE_OPENING_WAIT4_LOAD; - - /* Send LOAD_REQUEST command to MCP. - Returns the type of LOAD command: if it is the - first port to be initialized common blocks should be - initialized, otherwise - not. - */ - if (!nomcp) { - load_code = bnx2x_fw_command(bp, DRV_MSG_CODE_LOAD_REQ); - if (!load_code) { - BNX2X_ERR("MCP response failure, unloading\n"); - return -EBUSY; - } - if (load_code == FW_MSG_CODE_DRV_LOAD_REFUSED) { - BNX2X_ERR("MCP refused load request, unloading\n"); - return -EBUSY; /* other port in diagnostic mode */ - } - } else { - load_code = FW_MSG_CODE_DRV_LOAD_COMMON; - } - - /* if we can't use msix we only need one fp, - * so try to enable msix with the requested number of fp's - * and fallback to inta with one fp - */ - if (req_irq) { - if (use_inta) { - bp->num_queues = 1; - } else { - if ((use_multi > 1) && (use_multi <= 16)) - /* user requested number */ - bp->num_queues = use_multi; - else if (use_multi == 1) - bp->num_queues = num_online_cpus(); - else - bp->num_queues = 1; - - if (bnx2x_enable_msix(bp)) { - /* failed to enable msix */ - bp->num_queues = 1; - if (use_multi) - BNX2X_ERR("Multi requested but failed" - " to enable MSI-X\n"); - } - } - } - - DP(NETIF_MSG_IFUP, "set number of queues to %d\n", bp->num_queues); - - if (bnx2x_alloc_mem(bp)) - return -ENOMEM; - - if (req_irq) { - if (bp->flags & USING_MSIX_FLAG) { - if (bnx2x_req_msix_irqs(bp)) { - pci_disable_msix(bp->pdev); - goto load_error; - } - - } else { - if (bnx2x_req_irq(bp)) { - BNX2X_ERR("IRQ request failed, aborting\n"); - goto load_error; - } - } - } - - for_each_queue(bp, i) - netif_napi_add(bp->dev, &bnx2x_fp(bp, i, napi), - bnx2x_poll, 128); - - - /* Initialize HW */ - if (bnx2x_function_init(bp, - (load_code == FW_MSG_CODE_DRV_LOAD_COMMON))) { - BNX2X_ERR("HW init failed, aborting\n"); - goto load_error; - } - - - atomic_set(&bp->intr_sem, 0); - - - /* Setup NIC internals and enable interrupts */ - bnx2x_nic_init(bp); - - /* Send LOAD_DONE command to MCP */ - if (!nomcp) { - load_code = bnx2x_fw_command(bp, DRV_MSG_CODE_LOAD_DONE); - if (!load_code) { - BNX2X_ERR("MCP response failure, unloading\n"); - goto load_int_disable; - } - } - - bp->state = BNX2X_STATE_OPENING_WAIT4_PORT; - - /* Enable Rx interrupt handling before sending the ramrod - as it's completed on Rx FP queue */ - for_each_queue(bp, i) - napi_enable(&bnx2x_fp(bp, i, napi)); - - if (bnx2x_setup_leading(bp)) - goto load_stop_netif; - - for_each_nondefault_queue(bp, i) - if (bnx2x_setup_multi(bp, i)) - goto load_stop_netif; - - bnx2x_set_mac_addr(bp); - - bnx2x_phy_init(bp); - - /* Start fast path */ - if (req_irq) { /* IRQ is only requested from bnx2x_open */ - netif_start_queue(bp->dev); - if (bp->flags & USING_MSIX_FLAG) - printk(KERN_INFO PFX "%s: using MSI-X\n", - bp->dev->name); - - /* Otherwise Tx queue should be only reenabled */ - } else if (netif_running(bp->dev)) { - netif_wake_queue(bp->dev); - bnx2x_set_rx_mode(bp->dev); - } - - /* start the timer */ - mod_timer(&bp->timer, jiffies + bp->current_interval); - - return 0; - -load_stop_netif: - for_each_queue(bp, i) - napi_disable(&bnx2x_fp(bp, i, napi)); - -load_int_disable: - bnx2x_int_disable_sync(bp); - - bnx2x_free_skbs(bp); - bnx2x_free_irq(bp); - -load_error: - bnx2x_free_mem(bp); - - /* TBD we really need to reset the chip - if we want to recover from this */ - return -EBUSY; -} - - -static void bnx2x_reset_chip(struct bnx2x *bp, u32 reset_code) -{ - int port = bp->port; -#ifdef USE_DMAE - u32 wb_write[2]; -#endif - int base, i; - - DP(NETIF_MSG_IFDOWN, "reset called with code %x\n", reset_code); - - /* Do not rcv packets to BRB */ - REG_WR(bp, NIG_REG_LLH0_BRB1_DRV_MASK + port*4, 0x0); - /* Do not direct rcv packets that are not for MCP to the BRB */ - REG_WR(bp, (port ? NIG_REG_LLH1_BRB1_NOT_MCP : - NIG_REG_LLH0_BRB1_NOT_MCP), 0x0); - - /* Configure IGU and AEU */ - REG_WR(bp, HC_REG_CONFIG_0 + port*4, 0x1000); - REG_WR(bp, MISC_REG_AEU_MASK_ATTN_FUNC_0 + port*4, 0); - - /* TODO: Close Doorbell port? */ - - /* Clear ILT */ -#ifdef USE_DMAE - wb_write[0] = 0; - wb_write[1] = 0; -#endif - base = port * RQ_ONCHIP_AT_PORT_SIZE; - for (i = base; i < base + RQ_ONCHIP_AT_PORT_SIZE; i++) { -#ifdef USE_DMAE - REG_WR_DMAE(bp, PXP2_REG_RQ_ONCHIP_AT + i*8, wb_write, 2); -#else - REG_WR_IND(bp, PXP2_REG_RQ_ONCHIP_AT, 0); - REG_WR_IND(bp, PXP2_REG_RQ_ONCHIP_AT + 4, 0); -#endif - } - - if (reset_code == FW_MSG_CODE_DRV_UNLOAD_COMMON) { - /* reset_common */ - REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_1_CLEAR, - 0xd3ffff7f); - REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_CLEAR, - 0x1403); - } -} - -static int bnx2x_stop_multi(struct bnx2x *bp, int index) -{ - - int rc; - - /* halt the connection */ - bp->fp[index].state = BNX2X_FP_STATE_HALTING; - bnx2x_sp_post(bp, RAMROD_CMD_ID_ETH_HALT, index, 0, 0, 0); - - - rc = bnx2x_wait_ramrod(bp, BNX2X_FP_STATE_HALTED, index, - &(bp->fp[index].state), 1); - if (rc) /* timeout */ - return rc; - - /* delete cfc entry */ - bnx2x_sp_post(bp, RAMROD_CMD_ID_ETH_CFC_DEL, index, 0, 0, 1); - - return bnx2x_wait_ramrod(bp, BNX2X_FP_STATE_CLOSED, index, - &(bp->fp[index].state), 1); - -} - - -static void bnx2x_stop_leading(struct bnx2x *bp) -{ - u16 dsb_sp_prod_idx; - /* if the other port is handling traffic, - this can take a lot of time */ - int timeout = 500; - - might_sleep(); - - /* Send HALT ramrod */ - bp->fp[0].state = BNX2X_FP_STATE_HALTING; - bnx2x_sp_post(bp, RAMROD_CMD_ID_ETH_HALT, 0, 0, 0, 0); - - if (bnx2x_wait_ramrod(bp, BNX2X_FP_STATE_HALTED, 0, - &(bp->fp[0].state), 1)) - return; - - dsb_sp_prod_idx = *bp->dsb_sp_prod; - - /* Send PORT_DELETE ramrod */ - bnx2x_sp_post(bp, RAMROD_CMD_ID_ETH_PORT_DEL, 0, 0, 0, 1); - - /* Wait for completion to arrive on default status block - we are going to reset the chip anyway - so there is not much to do if this times out - */ - while ((dsb_sp_prod_idx == *bp->dsb_sp_prod) && timeout) { - timeout--; - msleep(1); - } - if (!timeout) { - DP(NETIF_MSG_IFDOWN, "timeout polling for completion " - "dsb_sp_prod 0x%x != dsb_sp_prod_idx 0x%x\n", - *bp->dsb_sp_prod, dsb_sp_prod_idx); - } - bp->state = BNX2X_STATE_CLOSING_WAIT4_UNLOAD; - bp->fp[0].state = BNX2X_FP_STATE_CLOSED; -} - - -static int bnx2x_nic_unload(struct bnx2x *bp, int free_irq) -{ - u32 reset_code = 0; - int i, timeout; - - bp->state = BNX2X_STATE_CLOSING_WAIT4_HALT; - - del_timer_sync(&bp->timer); - - bp->rx_mode = BNX2X_RX_MODE_NONE; - bnx2x_set_storm_rx_mode(bp); - - if (netif_running(bp->dev)) { - netif_tx_disable(bp->dev); - bp->dev->trans_start = jiffies; /* prevent tx timeout */ - } - - /* Wait until all fast path tasks complete */ - for_each_queue(bp, i) { - struct bnx2x_fastpath *fp = &bp->fp[i]; - - timeout = 1000; - while (bnx2x_has_work(fp) && (timeout--)) - msleep(1); - if (!timeout) - BNX2X_ERR("timeout waiting for queue[%d]\n", i); - } - - /* Wait until stat ramrod returns and all SP tasks complete */ - timeout = 1000; - while ((bp->stat_pending || (bp->spq_left != MAX_SPQ_PENDING)) && - (timeout--)) - msleep(1); - - for_each_queue(bp, i) - napi_disable(&bnx2x_fp(bp, i, napi)); - /* Disable interrupts after Tx and Rx are disabled on stack level */ - bnx2x_int_disable_sync(bp); - - if (bp->flags & NO_WOL_FLAG) - reset_code = DRV_MSG_CODE_UNLOAD_REQ_WOL_MCP; - - else if (bp->wol) { - u32 emac_base = bp->port ? GRCBASE_EMAC0 : GRCBASE_EMAC1; - u8 *mac_addr = bp->dev->dev_addr; - u32 val = (EMAC_MODE_MPKT | EMAC_MODE_MPKT_RCVD | - EMAC_MODE_ACPI_RCVD); - - EMAC_WR(EMAC_REG_EMAC_MODE, val); - - val = (mac_addr[0] << 8) | mac_addr[1]; - EMAC_WR(EMAC_REG_EMAC_MAC_MATCH, val); - - val = (mac_addr[2] << 24) | (mac_addr[3] << 16) | - (mac_addr[4] << 8) | mac_addr[5]; - EMAC_WR(EMAC_REG_EMAC_MAC_MATCH + 4, val); - - reset_code = DRV_MSG_CODE_UNLOAD_REQ_WOL_EN; - - } else - reset_code = DRV_MSG_CODE_UNLOAD_REQ_WOL_DIS; - - /* Close multi and leading connections */ - for_each_nondefault_queue(bp, i) - if (bnx2x_stop_multi(bp, i)) - goto unload_error; - - bnx2x_stop_leading(bp); - if ((bp->state != BNX2X_STATE_CLOSING_WAIT4_UNLOAD) || - (bp->fp[0].state != BNX2X_FP_STATE_CLOSED)) { - DP(NETIF_MSG_IFDOWN, "failed to close leading properly!" - "state 0x%x fp[0].state 0x%x", - bp->state, bp->fp[0].state); - } - -unload_error: - bnx2x_link_reset(bp); - - if (!nomcp) - reset_code = bnx2x_fw_command(bp, reset_code); - else - reset_code = FW_MSG_CODE_DRV_UNLOAD_COMMON; - - /* Release IRQs */ - if (free_irq) - bnx2x_free_irq(bp); - - /* Reset the chip */ - bnx2x_reset_chip(bp, reset_code); - - /* Report UNLOAD_DONE to MCP */ - if (!nomcp) - bnx2x_fw_command(bp, DRV_MSG_CODE_UNLOAD_DONE); - - /* Free SKBs and driver internals */ - bnx2x_free_skbs(bp); - bnx2x_free_mem(bp); - - bp->state = BNX2X_STATE_CLOSED; - - netif_carrier_off(bp->dev); - - return 0; -} - -/* end of nic load/unload */ - -/* ethtool_ops */ - -/* - * Init service functions - */ - -static void bnx2x_link_settings_supported(struct bnx2x *bp, u32 switch_cfg) -{ - int port = bp->port; - u32 ext_phy_type; - - bp->phy_flags = 0; - - switch (switch_cfg) { - case SWITCH_CFG_1G: - BNX2X_DEV_INFO("switch_cfg 0x%x (1G)\n", switch_cfg); - - ext_phy_type = SERDES_EXT_PHY_TYPE(bp); - switch (ext_phy_type) { - case PORT_HW_CFG_SERDES_EXT_PHY_TYPE_DIRECT: - BNX2X_DEV_INFO("ext_phy_type 0x%x (Direct)\n", - ext_phy_type); - - bp->supported |= (SUPPORTED_10baseT_Half | - SUPPORTED_10baseT_Full | - SUPPORTED_100baseT_Half | - SUPPORTED_100baseT_Full | - SUPPORTED_1000baseT_Full | - SUPPORTED_2500baseX_Full | - SUPPORTED_TP | SUPPORTED_FIBRE | - SUPPORTED_Autoneg | - SUPPORTED_Pause | - SUPPORTED_Asym_Pause); - break; - - case PORT_HW_CFG_SERDES_EXT_PHY_TYPE_BCM5482: - BNX2X_DEV_INFO("ext_phy_type 0x%x (5482)\n", - ext_phy_type); - - bp->phy_flags |= PHY_SGMII_FLAG; - - bp->supported |= (SUPPORTED_10baseT_Half | - SUPPORTED_10baseT_Full | - SUPPORTED_100baseT_Half | - SUPPORTED_100baseT_Full | - SUPPORTED_1000baseT_Full | - SUPPORTED_TP | SUPPORTED_FIBRE | - SUPPORTED_Autoneg | - SUPPORTED_Pause | - SUPPORTED_Asym_Pause); - break; - - default: - BNX2X_ERR("NVRAM config error. " - "BAD SerDes ext_phy_config 0x%x\n", - bp->ext_phy_config); - return; - } - - bp->phy_addr = REG_RD(bp, NIG_REG_SERDES0_CTRL_PHY_ADDR + - port*0x10); - BNX2X_DEV_INFO("phy_addr 0x%x\n", bp->phy_addr); - break; - - case SWITCH_CFG_10G: - BNX2X_DEV_INFO("switch_cfg 0x%x (10G)\n", switch_cfg); - - bp->phy_flags |= PHY_XGXS_FLAG; - - ext_phy_type = XGXS_EXT_PHY_TYPE(bp); - switch (ext_phy_type) { - case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT: - BNX2X_DEV_INFO("ext_phy_type 0x%x (Direct)\n", - ext_phy_type); - - bp->supported |= (SUPPORTED_10baseT_Half | - SUPPORTED_10baseT_Full | - SUPPORTED_100baseT_Half | - SUPPORTED_100baseT_Full | - SUPPORTED_1000baseT_Full | - SUPPORTED_2500baseX_Full | - SUPPORTED_10000baseT_Full | - SUPPORTED_TP | SUPPORTED_FIBRE | - SUPPORTED_Autoneg | - SUPPORTED_Pause | - SUPPORTED_Asym_Pause); - break; - - case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705: - BNX2X_DEV_INFO("ext_phy_type 0x%x (8705)\n", - ext_phy_type); - - bp->supported |= (SUPPORTED_10000baseT_Full | - SUPPORTED_FIBRE | - SUPPORTED_Pause | - SUPPORTED_Asym_Pause); - break; - - case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706: - BNX2X_DEV_INFO("ext_phy_type 0x%x (8706)\n", - ext_phy_type); - - bp->supported |= (SUPPORTED_10000baseT_Full | - SUPPORTED_1000baseT_Full | - SUPPORTED_Autoneg | - SUPPORTED_FIBRE | - SUPPORTED_Pause | - SUPPORTED_Asym_Pause); - break; - - case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072: - BNX2X_DEV_INFO("ext_phy_type 0x%x (8072)\n", - ext_phy_type); - - bp->supported |= (SUPPORTED_10000baseT_Full | - SUPPORTED_1000baseT_Full | - SUPPORTED_FIBRE | - SUPPORTED_Autoneg | - SUPPORTED_Pause | - SUPPORTED_Asym_Pause); - break; - - case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101: - BNX2X_DEV_INFO("ext_phy_type 0x%x (SFX7101)\n", - ext_phy_type); - - bp->supported |= (SUPPORTED_10000baseT_Full | - SUPPORTED_TP | - SUPPORTED_Autoneg | - SUPPORTED_Pause | - SUPPORTED_Asym_Pause); - break; - - default: - BNX2X_ERR("NVRAM config error. " - "BAD XGXS ext_phy_config 0x%x\n", - bp->ext_phy_config); - return; - } - - bp->phy_addr = REG_RD(bp, NIG_REG_XGXS0_CTRL_PHY_ADDR + - port*0x18); - BNX2X_DEV_INFO("phy_addr 0x%x\n", bp->phy_addr); - - bp->ser_lane = ((bp->lane_config & - PORT_HW_CFG_LANE_SWAP_CFG_MASTER_MASK) >> - PORT_HW_CFG_LANE_SWAP_CFG_MASTER_SHIFT); - bp->rx_lane_swap = ((bp->lane_config & - PORT_HW_CFG_LANE_SWAP_CFG_RX_MASK) >> - PORT_HW_CFG_LANE_SWAP_CFG_RX_SHIFT); - bp->tx_lane_swap = ((bp->lane_config & - PORT_HW_CFG_LANE_SWAP_CFG_TX_MASK) >> - PORT_HW_CFG_LANE_SWAP_CFG_TX_SHIFT); - BNX2X_DEV_INFO("rx_lane_swap 0x%x tx_lane_swap 0x%x\n", - bp->rx_lane_swap, bp->tx_lane_swap); - break; - - default: - BNX2X_ERR("BAD switch_cfg link_config 0x%x\n", - bp->link_config); - return; - } - - /* mask what we support according to speed_cap_mask */ - if (!(bp->speed_cap_mask & - PORT_HW_CFG_SPEED_CAPABILITY_D0_10M_HALF)) - bp->supported &= ~SUPPORTED_10baseT_Half; - - if (!(bp->speed_cap_mask & - PORT_HW_CFG_SPEED_CAPABILITY_D0_10M_FULL)) - bp->supported &= ~SUPPORTED_10baseT_Full; - - if (!(bp->speed_cap_mask & - PORT_HW_CFG_SPEED_CAPABILITY_D0_100M_HALF)) - bp->supported &= ~SUPPORTED_100baseT_Half; - - if (!(bp->speed_cap_mask & - PORT_HW_CFG_SPEED_CAPABILITY_D0_100M_FULL)) - bp->supported &= ~SUPPORTED_100baseT_Full; - - if (!(bp->speed_cap_mask & PORT_HW_CFG_SPEED_CAPABILITY_D0_1G)) - bp->supported &= ~(SUPPORTED_1000baseT_Half | - SUPPORTED_1000baseT_Full); - - if (!(bp->speed_cap_mask & PORT_HW_CFG_SPEED_CAPABILITY_D0_2_5G)) - bp->supported &= ~SUPPORTED_2500baseX_Full; - - if (!(bp->speed_cap_mask & PORT_HW_CFG_SPEED_CAPABILITY_D0_10G)) - bp->supported &= ~SUPPORTED_10000baseT_Full; - - BNX2X_DEV_INFO("supported 0x%x\n", bp->supported); -} - -static void bnx2x_link_settings_requested(struct bnx2x *bp) -{ - bp->req_autoneg = 0; - bp->req_duplex = DUPLEX_FULL; - - switch (bp->link_config & PORT_FEATURE_LINK_SPEED_MASK) { - case PORT_FEATURE_LINK_SPEED_AUTO: - if (bp->supported & SUPPORTED_Autoneg) { - bp->req_autoneg |= AUTONEG_SPEED; - bp->req_line_speed = 0; - bp->advertising = bp->supported; - } else { - if (XGXS_EXT_PHY_TYPE(bp) == - PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705) { - /* force 10G, no AN */ - bp->req_line_speed = SPEED_10000; - bp->advertising = - (ADVERTISED_10000baseT_Full | - ADVERTISED_FIBRE); - break; - } - BNX2X_ERR("NVRAM config error. " - "Invalid link_config 0x%x" - " Autoneg not supported\n", - bp->link_config); - return; - } - break; - - case PORT_FEATURE_LINK_SPEED_10M_FULL: - if (bp->supported & SUPPORTED_10baseT_Full) { - bp->req_line_speed = SPEED_10; - bp->advertising = (ADVERTISED_10baseT_Full | - ADVERTISED_TP); - } else { - BNX2X_ERR("NVRAM config error. " - "Invalid link_config 0x%x" - " speed_cap_mask 0x%x\n", - bp->link_config, bp->speed_cap_mask); - return; - } - break; - - case PORT_FEATURE_LINK_SPEED_10M_HALF: - if (bp->supported & SUPPORTED_10baseT_Half) { - bp->req_line_speed = SPEED_10; - bp->req_duplex = DUPLEX_HALF; - bp->advertising = (ADVERTISED_10baseT_Half | - ADVERTISED_TP); - } else { - BNX2X_ERR("NVRAM config error. " - "Invalid link_config 0x%x" - " speed_cap_mask 0x%x\n", - bp->link_config, bp->speed_cap_mask); - return; - } - break; - - case PORT_FEATURE_LINK_SPEED_100M_FULL: - if (bp->supported & SUPPORTED_100baseT_Full) { - bp->req_line_speed = SPEED_100; - bp->advertising = (ADVERTISED_100baseT_Full | - ADVERTISED_TP); - } else { - BNX2X_ERR("NVRAM config error. " - "Invalid link_config 0x%x" - " speed_cap_mask 0x%x\n", - bp->link_config, bp->speed_cap_mask); - return; - } - break; - - case PORT_FEATURE_LINK_SPEED_100M_HALF: - if (bp->supported & SUPPORTED_100baseT_Half) { - bp->req_line_speed = SPEED_100; - bp->req_duplex = DUPLEX_HALF; - bp->advertising = (ADVERTISED_100baseT_Half | - ADVERTISED_TP); - } else { - BNX2X_ERR("NVRAM config error. " - "Invalid link_config 0x%x" - " speed_cap_mask 0x%x\n", - bp->link_config, bp->speed_cap_mask); - return; - } - break; - - case PORT_FEATURE_LINK_SPEED_1G: - if (bp->supported & SUPPORTED_1000baseT_Full) { - bp->req_line_speed = SPEED_1000; - bp->advertising = (ADVERTISED_1000baseT_Full | - ADVERTISED_TP); - } else { - BNX2X_ERR("NVRAM config error. " - "Invalid link_config 0x%x" - " speed_cap_mask 0x%x\n", - bp->link_config, bp->speed_cap_mask); - return; - } - break; - - case PORT_FEATURE_LINK_SPEED_2_5G: - if (bp->supported & SUPPORTED_2500baseX_Full) { - bp->req_line_speed = SPEED_2500; - bp->advertising = (ADVERTISED_2500baseX_Full | - ADVERTISED_TP); - } else { - BNX2X_ERR("NVRAM config error. " - "Invalid link_config 0x%x" - " speed_cap_mask 0x%x\n", - bp->link_config, bp->speed_cap_mask); - return; - } - break; - - case PORT_FEATURE_LINK_SPEED_10G_CX4: - case PORT_FEATURE_LINK_SPEED_10G_KX4: - case PORT_FEATURE_LINK_SPEED_10G_KR: - if (bp->supported & SUPPORTED_10000baseT_Full) { - bp->req_line_speed = SPEED_10000; - bp->advertising = (ADVERTISED_10000baseT_Full | - ADVERTISED_FIBRE); - } else { - BNX2X_ERR("NVRAM config error. " - "Invalid link_config 0x%x" - " speed_cap_mask 0x%x\n", - bp->link_config, bp->speed_cap_mask); - return; - } - break; - - default: - BNX2X_ERR("NVRAM config error. " - "BAD link speed link_config 0x%x\n", - bp->link_config); - bp->req_autoneg |= AUTONEG_SPEED; - bp->req_line_speed = 0; - bp->advertising = bp->supported; - break; - } - BNX2X_DEV_INFO("req_line_speed %d req_duplex %d\n", - bp->req_line_speed, bp->req_duplex); - - bp->req_flow_ctrl = (bp->link_config & - PORT_FEATURE_FLOW_CONTROL_MASK); - if ((bp->req_flow_ctrl == FLOW_CTRL_AUTO) && - (bp->supported & SUPPORTED_Autoneg)) - bp->req_autoneg |= AUTONEG_FLOW_CTRL; - - BNX2X_DEV_INFO("req_autoneg 0x%x req_flow_ctrl 0x%x" - " advertising 0x%x\n", - bp->req_autoneg, bp->req_flow_ctrl, bp->advertising); -} - -static void bnx2x_get_hwinfo(struct bnx2x *bp) -{ - u32 val, val2, val3, val4, id; - int port = bp->port; - u32 switch_cfg; - - bp->shmem_base = REG_RD(bp, MISC_REG_SHARED_MEM_ADDR); - BNX2X_DEV_INFO("shmem offset is %x\n", bp->shmem_base); - - /* Get the chip revision id and number. */ - /* chip num:16-31, rev:12-15, metal:4-11, bond_id:0-3 */ - val = REG_RD(bp, MISC_REG_CHIP_NUM); - id = ((val & 0xffff) << 16); - val = REG_RD(bp, MISC_REG_CHIP_REV); - id |= ((val & 0xf) << 12); - val = REG_RD(bp, MISC_REG_CHIP_METAL); - id |= ((val & 0xff) << 4); - REG_RD(bp, MISC_REG_BOND_ID); - id |= (val & 0xf); - bp->chip_id = id; - BNX2X_DEV_INFO("chip ID is %x\n", id); - - if (!bp->shmem_base || (bp->shmem_base != 0xAF900)) { - BNX2X_DEV_INFO("MCP not active\n"); - nomcp = 1; - goto set_mac; - } - - val = SHMEM_RD(bp, validity_map[port]); - if ((val & (SHR_MEM_VALIDITY_DEV_INFO | SHR_MEM_VALIDITY_MB)) - != (SHR_MEM_VALIDITY_DEV_INFO | SHR_MEM_VALIDITY_MB)) - BNX2X_ERR("BAD MCP validity signature\n"); - - bp->fw_seq = (SHMEM_RD(bp, func_mb[port].drv_mb_header) & - DRV_MSG_SEQ_NUMBER_MASK); - - bp->hw_config = SHMEM_RD(bp, dev_info.shared_hw_config.config); - bp->board = SHMEM_RD(bp, dev_info.shared_hw_config.board); - bp->serdes_config = - SHMEM_RD(bp, dev_info.port_hw_config[port].serdes_config); - bp->lane_config = - SHMEM_RD(bp, dev_info.port_hw_config[port].lane_config); - bp->ext_phy_config = - SHMEM_RD(bp, - dev_info.port_hw_config[port].external_phy_config); - bp->speed_cap_mask = - SHMEM_RD(bp, - dev_info.port_hw_config[port].speed_capability_mask); - - bp->link_config = - SHMEM_RD(bp, dev_info.port_feature_config[port].link_config); - - BNX2X_DEV_INFO("hw_config (%08x) board (%08x) serdes_config (%08x)\n" - KERN_INFO " lane_config (%08x) ext_phy_config (%08x)\n" - KERN_INFO " speed_cap_mask (%08x) link_config (%08x)" - " fw_seq (%08x)\n", - bp->hw_config, bp->board, bp->serdes_config, - bp->lane_config, bp->ext_phy_config, - bp->speed_cap_mask, bp->link_config, bp->fw_seq); - - switch_cfg = (bp->link_config & PORT_FEATURE_CONNECTED_SWITCH_MASK); - bnx2x_link_settings_supported(bp, switch_cfg); - - bp->autoneg = (bp->hw_config & SHARED_HW_CFG_AN_ENABLE_MASK); - /* for now disable cl73 */ - bp->autoneg &= ~SHARED_HW_CFG_AN_ENABLE_CL73; - BNX2X_DEV_INFO("autoneg 0x%x\n", bp->autoneg); - - bnx2x_link_settings_requested(bp); - - val2 = SHMEM_RD(bp, dev_info.port_hw_config[port].mac_upper); - val = SHMEM_RD(bp, dev_info.port_hw_config[port].mac_lower); - bp->dev->dev_addr[0] = (u8)(val2 >> 8 & 0xff); - bp->dev->dev_addr[1] = (u8)(val2 & 0xff); - bp->dev->dev_addr[2] = (u8)(val >> 24 & 0xff); - bp->dev->dev_addr[3] = (u8)(val >> 16 & 0xff); - bp->dev->dev_addr[4] = (u8)(val >> 8 & 0xff); - bp->dev->dev_addr[5] = (u8)(val & 0xff); - - memcpy(bp->dev->perm_addr, bp->dev->dev_addr, 6); - - - val = SHMEM_RD(bp, dev_info.shared_hw_config.part_num); - val2 = SHMEM_RD(bp, dev_info.shared_hw_config.part_num[4]); - val3 = SHMEM_RD(bp, dev_info.shared_hw_config.part_num[8]); - val4 = SHMEM_RD(bp, dev_info.shared_hw_config.part_num[12]); - - printk(KERN_INFO PFX "part number %X-%X-%X-%X\n", - val, val2, val3, val4); - - /* bc ver */ - if (!nomcp) { - bp->bc_ver = val = ((SHMEM_RD(bp, dev_info.bc_rev)) >> 8); - BNX2X_DEV_INFO("bc_ver %X\n", val); - if (val < BNX2X_BC_VER) { - /* for now only warn - * later we might need to enforce this */ - BNX2X_ERR("This driver needs bc_ver %X but found %X," - " please upgrade BC\n", BNX2X_BC_VER, val); - } - } else { - bp->bc_ver = 0; - } - - val = REG_RD(bp, MCP_REG_MCPR_NVM_CFG4); - bp->flash_size = (NVRAM_1MB_SIZE << (val & MCPR_NVM_CFG4_FLASH_SIZE)); - BNX2X_DEV_INFO("flash_size 0x%x (%d)\n", - bp->flash_size, bp->flash_size); - - return; - -set_mac: /* only supposed to happen on emulation/FPGA */ - BNX2X_ERR("warning rendom MAC workaround active\n"); - random_ether_addr(bp->dev->dev_addr); - memcpy(bp->dev->perm_addr, bp->dev->dev_addr, 6); - -} - -/* - * ethtool service functions - */ - -/* All ethtool functions called with rtnl_lock */ - -static int bnx2x_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) -{ - struct bnx2x *bp = netdev_priv(dev); - - cmd->supported = bp->supported; - cmd->advertising = bp->advertising; - - if (netif_carrier_ok(dev)) { - cmd->speed = bp->line_speed; - cmd->duplex = bp->duplex; - } else { - cmd->speed = bp->req_line_speed; - cmd->duplex = bp->req_duplex; - } - - if (bp->phy_flags & PHY_XGXS_FLAG) { - u32 ext_phy_type = XGXS_EXT_PHY_TYPE(bp); - - switch (ext_phy_type) { - case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT: - case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705: - case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706: - case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072: - cmd->port = PORT_FIBRE; - break; - - case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101: - cmd->port = PORT_TP; - break; - - default: - DP(NETIF_MSG_LINK, "BAD XGXS ext_phy_config 0x%x\n", - bp->ext_phy_config); - } - } else - cmd->port = PORT_TP; - - cmd->phy_address = bp->phy_addr; - cmd->transceiver = XCVR_INTERNAL; - - if (bp->req_autoneg & AUTONEG_SPEED) - cmd->autoneg = AUTONEG_ENABLE; - else - cmd->autoneg = AUTONEG_DISABLE; - - cmd->maxtxpkt = 0; - cmd->maxrxpkt = 0; - - DP(NETIF_MSG_LINK, "ethtool_cmd: cmd %d\n" - DP_LEVEL " supported 0x%x advertising 0x%x speed %d\n" - DP_LEVEL " duplex %d port %d phy_address %d transceiver %d\n" - DP_LEVEL " autoneg %d maxtxpkt %d maxrxpkt %d\n", - cmd->cmd, cmd->supported, cmd->advertising, cmd->speed, - cmd->duplex, cmd->port, cmd->phy_address, cmd->transceiver, - cmd->autoneg, cmd->maxtxpkt, cmd->maxrxpkt); - - return 0; -} - -static int bnx2x_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) -{ - struct bnx2x *bp = netdev_priv(dev); - u32 advertising; - - DP(NETIF_MSG_LINK, "ethtool_cmd: cmd %d\n" - DP_LEVEL " supported 0x%x advertising 0x%x speed %d\n" - DP_LEVEL " duplex %d port %d phy_address %d transceiver %d\n" - DP_LEVEL " autoneg %d maxtxpkt %d maxrxpkt %d\n", - cmd->cmd, cmd->supported, cmd->advertising, cmd->speed, - cmd->duplex, cmd->port, cmd->phy_address, cmd->transceiver, - cmd->autoneg, cmd->maxtxpkt, cmd->maxrxpkt); - - if (cmd->autoneg == AUTONEG_ENABLE) { - if (!(bp->supported & SUPPORTED_Autoneg)) { - DP(NETIF_MSG_LINK, "Aotoneg not supported\n"); - return -EINVAL; - } - - /* advertise the requested speed and duplex if supported */ - cmd->advertising &= bp->supported; - - bp->req_autoneg |= AUTONEG_SPEED; - bp->req_line_speed = 0; - bp->req_duplex = DUPLEX_FULL; - bp->advertising |= (ADVERTISED_Autoneg | cmd->advertising); - - } else { /* forced speed */ - /* advertise the requested speed and duplex if supported */ - switch (cmd->speed) { - case SPEED_10: - if (cmd->duplex == DUPLEX_FULL) { - if (!(bp->supported & - SUPPORTED_10baseT_Full)) { - DP(NETIF_MSG_LINK, - "10M full not supported\n"); - return -EINVAL; - } - - advertising = (ADVERTISED_10baseT_Full | - ADVERTISED_TP); - } else { - if (!(bp->supported & - SUPPORTED_10baseT_Half)) { - DP(NETIF_MSG_LINK, - "10M half not supported\n"); - return -EINVAL; - } - - advertising = (ADVERTISED_10baseT_Half | - ADVERTISED_TP); - } - break; - - case SPEED_100: - if (cmd->duplex == DUPLEX_FULL) { - if (!(bp->supported & - SUPPORTED_100baseT_Full)) { - DP(NETIF_MSG_LINK, - "100M full not supported\n"); - return -EINVAL; - } - - advertising = (ADVERTISED_100baseT_Full | - ADVERTISED_TP); - } else { - if (!(bp->supported & - SUPPORTED_100baseT_Half)) { - DP(NETIF_MSG_LINK, - "100M half not supported\n"); - return -EINVAL; - } - - advertising = (ADVERTISED_100baseT_Half | - ADVERTISED_TP); - } - break; - - case SPEED_1000: - if (cmd->duplex != DUPLEX_FULL) { - DP(NETIF_MSG_LINK, "1G half not supported\n"); - return -EINVAL; - } - - if (!(bp->supported & SUPPORTED_1000baseT_Full)) { - DP(NETIF_MSG_LINK, "1G full not supported\n"); - return -EINVAL; - } - - advertising = (ADVERTISED_1000baseT_Full | - ADVERTISED_TP); - break; - - case SPEED_2500: - if (cmd->duplex != DUPLEX_FULL) { - DP(NETIF_MSG_LINK, - "2.5G half not supported\n"); - return -EINVAL; - } - - if (!(bp->supported & SUPPORTED_2500baseX_Full)) { - DP(NETIF_MSG_LINK, - "2.5G full not supported\n"); - return -EINVAL; - } - - advertising = (ADVERTISED_2500baseX_Full | - ADVERTISED_TP); - break; - - case SPEED_10000: - if (cmd->duplex != DUPLEX_FULL) { - DP(NETIF_MSG_LINK, "10G half not supported\n"); - return -EINVAL; - } - - if (!(bp->supported & SUPPORTED_10000baseT_Full)) { - DP(NETIF_MSG_LINK, "10G full not supported\n"); - return -EINVAL; - } - - advertising = (ADVERTISED_10000baseT_Full | - ADVERTISED_FIBRE); - break; - - default: - DP(NETIF_MSG_LINK, "Unsupported speed\n"); - return -EINVAL; - } - - bp->req_autoneg &= ~AUTONEG_SPEED; - bp->req_line_speed = cmd->speed; - bp->req_duplex = cmd->duplex; - bp->advertising = advertising; - } - - DP(NETIF_MSG_LINK, "req_autoneg 0x%x req_line_speed %d\n" - DP_LEVEL " req_duplex %d advertising 0x%x\n", - bp->req_autoneg, bp->req_line_speed, bp->req_duplex, - bp->advertising); - - bnx2x_stop_stats(bp); - bnx2x_link_initialize(bp); - - return 0; -} - -static void bnx2x_get_drvinfo(struct net_device *dev, - struct ethtool_drvinfo *info) -{ - struct bnx2x *bp = netdev_priv(dev); - - strcpy(info->driver, DRV_MODULE_NAME); - strcpy(info->version, DRV_MODULE_VERSION); - snprintf(info->fw_version, 32, "%d.%d.%d:%d (BC VER %x)", - BCM_5710_FW_MAJOR_VERSION, BCM_5710_FW_MINOR_VERSION, - BCM_5710_FW_REVISION_VERSION, BCM_5710_FW_COMPILE_FLAGS, - bp->bc_ver); - strcpy(info->bus_info, pci_name(bp->pdev)); - info->n_stats = BNX2X_NUM_STATS; - info->testinfo_len = BNX2X_NUM_TESTS; - info->eedump_len = bp->flash_size; - info->regdump_len = 0; -} - -static void bnx2x_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol) -{ - struct bnx2x *bp = netdev_priv(dev); - - if (bp->flags & NO_WOL_FLAG) { - wol->supported = 0; - wol->wolopts = 0; - } else { - wol->supported = WAKE_MAGIC; - if (bp->wol) - wol->wolopts = WAKE_MAGIC; - else - wol->wolopts = 0; - } - memset(&wol->sopass, 0, sizeof(wol->sopass)); -} - -static int bnx2x_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol) -{ - struct bnx2x *bp = netdev_priv(dev); - - if (wol->wolopts & ~WAKE_MAGIC) - return -EINVAL; - - if (wol->wolopts & WAKE_MAGIC) { - if (bp->flags & NO_WOL_FLAG) - return -EINVAL; - - bp->wol = 1; - } else { - bp->wol = 0; - } - return 0; -} - -static u32 bnx2x_get_msglevel(struct net_device *dev) -{ - struct bnx2x *bp = netdev_priv(dev); - - return bp->msglevel; -} - -static void bnx2x_set_msglevel(struct net_device *dev, u32 level) -{ - struct bnx2x *bp = netdev_priv(dev); - - if (capable(CAP_NET_ADMIN)) - bp->msglevel = level; -} - -static int bnx2x_nway_reset(struct net_device *dev) -{ - struct bnx2x *bp = netdev_priv(dev); - - if (bp->state != BNX2X_STATE_OPEN) { - DP(NETIF_MSG_PROBE, "state is %x, returning\n", bp->state); - return -EAGAIN; - } - - bnx2x_stop_stats(bp); - bnx2x_link_initialize(bp); - - return 0; -} - -static int bnx2x_get_eeprom_len(struct net_device *dev) -{ - struct bnx2x *bp = netdev_priv(dev); - - return bp->flash_size; -} - -static int bnx2x_acquire_nvram_lock(struct bnx2x *bp) -{ - int port = bp->port; - int count, i; - u32 val = 0; - - /* adjust timeout for emulation/FPGA */ - count = NVRAM_TIMEOUT_COUNT; - if (CHIP_REV_IS_SLOW(bp)) - count *= 100; - - /* request access to nvram interface */ - REG_WR(bp, MCP_REG_MCPR_NVM_SW_ARB, - (MCPR_NVM_SW_ARB_ARB_REQ_SET1 << port)); - - for (i = 0; i < count*10; i++) { - val = REG_RD(bp, MCP_REG_MCPR_NVM_SW_ARB); - if (val & (MCPR_NVM_SW_ARB_ARB_ARB1 << port)) - break; - - udelay(5); - } - - if (!(val & (MCPR_NVM_SW_ARB_ARB_ARB1 << port))) { - DP(NETIF_MSG_NVM, "cannot get access to nvram interface\n"); - return -EBUSY; - } - - return 0; -} - -static int bnx2x_release_nvram_lock(struct bnx2x *bp) -{ - int port = bp->port; - int count, i; - u32 val = 0; - - /* adjust timeout for emulation/FPGA */ - count = NVRAM_TIMEOUT_COUNT; - if (CHIP_REV_IS_SLOW(bp)) - count *= 100; - - /* relinquish nvram interface */ - REG_WR(bp, MCP_REG_MCPR_NVM_SW_ARB, - (MCPR_NVM_SW_ARB_ARB_REQ_CLR1 << port)); - - for (i = 0; i < count*10; i++) { - val = REG_RD(bp, MCP_REG_MCPR_NVM_SW_ARB); - if (!(val & (MCPR_NVM_SW_ARB_ARB_ARB1 << port))) - break; - - udelay(5); - } - - if (val & (MCPR_NVM_SW_ARB_ARB_ARB1 << port)) { - DP(NETIF_MSG_NVM, "cannot free access to nvram interface\n"); - return -EBUSY; - } - - return 0; -} - -static void bnx2x_enable_nvram_access(struct bnx2x *bp) -{ - u32 val; - - val = REG_RD(bp, MCP_REG_MCPR_NVM_ACCESS_ENABLE); - - /* enable both bits, even on read */ - REG_WR(bp, MCP_REG_MCPR_NVM_ACCESS_ENABLE, - (val | MCPR_NVM_ACCESS_ENABLE_EN | - MCPR_NVM_ACCESS_ENABLE_WR_EN)); -} - -static void bnx2x_disable_nvram_access(struct bnx2x *bp) -{ - u32 val; - - val = REG_RD(bp, MCP_REG_MCPR_NVM_ACCESS_ENABLE); - - /* disable both bits, even after read */ - REG_WR(bp, MCP_REG_MCPR_NVM_ACCESS_ENABLE, - (val & ~(MCPR_NVM_ACCESS_ENABLE_EN | - MCPR_NVM_ACCESS_ENABLE_WR_EN))); -} - -static int bnx2x_nvram_read_dword(struct bnx2x *bp, u32 offset, u32 *ret_val, - u32 cmd_flags) -{ - int count, i, rc; - u32 val; - - /* build the command word */ - cmd_flags |= MCPR_NVM_COMMAND_DOIT; - - /* need to clear DONE bit separately */ - REG_WR(bp, MCP_REG_MCPR_NVM_COMMAND, MCPR_NVM_COMMAND_DONE); - - /* address of the NVRAM to read from */ - REG_WR(bp, MCP_REG_MCPR_NVM_ADDR, - (offset & MCPR_NVM_ADDR_NVM_ADDR_VALUE)); - - /* issue a read command */ - REG_WR(bp, MCP_REG_MCPR_NVM_COMMAND, cmd_flags); - - /* adjust timeout for emulation/FPGA */ - count = NVRAM_TIMEOUT_COUNT; - if (CHIP_REV_IS_SLOW(bp)) - count *= 100; - - /* wait for completion */ - *ret_val = 0; - rc = -EBUSY; - for (i = 0; i < count; i++) { - udelay(5); - val = REG_RD(bp, MCP_REG_MCPR_NVM_COMMAND); - - if (val & MCPR_NVM_COMMAND_DONE) { - val = REG_RD(bp, MCP_REG_MCPR_NVM_READ); - DP(NETIF_MSG_NVM, "val 0x%08x\n", val); - /* we read nvram data in cpu order - * but ethtool sees it as an array of bytes - * converting to big-endian will do the work */ - val = cpu_to_be32(val); - *ret_val = val; - rc = 0; - break; - } - } - - return rc; -} - -static int bnx2x_nvram_read(struct bnx2x *bp, u32 offset, u8 *ret_buf, - int buf_size) -{ - int rc; - u32 cmd_flags; - u32 val; - - if ((offset & 0x03) || (buf_size & 0x03) || (buf_size == 0)) { - DP(NETIF_MSG_NVM, - "Invalid parameter: offset 0x%x buf_size 0x%x\n", - offset, buf_size); - return -EINVAL; - } - - if (offset + buf_size > bp->flash_size) { - DP(NETIF_MSG_NVM, "Invalid parameter: offset (0x%x) +" - " buf_size (0x%x) > flash_size (0x%x)\n", - offset, buf_size, bp->flash_size); - return -EINVAL; - } - - /* request access to nvram interface */ - rc = bnx2x_acquire_nvram_lock(bp); - if (rc) - return rc; - - /* enable access to nvram interface */ - bnx2x_enable_nvram_access(bp); - - /* read the first word(s) */ - cmd_flags = MCPR_NVM_COMMAND_FIRST; - while ((buf_size > sizeof(u32)) && (rc == 0)) { - rc = bnx2x_nvram_read_dword(bp, offset, &val, cmd_flags); - memcpy(ret_buf, &val, 4); - - /* advance to the next dword */ - offset += sizeof(u32); - ret_buf += sizeof(u32); - buf_size -= sizeof(u32); - cmd_flags = 0; - } - - if (rc == 0) { - cmd_flags |= MCPR_NVM_COMMAND_LAST; - rc = bnx2x_nvram_read_dword(bp, offset, &val, cmd_flags); - memcpy(ret_buf, &val, 4); - } - - /* disable access to nvram interface */ - bnx2x_disable_nvram_access(bp); - bnx2x_release_nvram_lock(bp); - - return rc; -} - -static int bnx2x_get_eeprom(struct net_device *dev, - struct ethtool_eeprom *eeprom, u8 *eebuf) -{ - struct bnx2x *bp = netdev_priv(dev); - int rc; - - DP(NETIF_MSG_NVM, "ethtool_eeprom: cmd %d\n" - DP_LEVEL " magic 0x%x offset 0x%x (%d) len 0x%x (%d)\n", - eeprom->cmd, eeprom->magic, eeprom->offset, eeprom->offset, - eeprom->len, eeprom->len); - - /* parameters already validated in ethtool_get_eeprom */ - - rc = bnx2x_nvram_read(bp, eeprom->offset, eebuf, eeprom->len); - - return rc; -} - -static int bnx2x_nvram_write_dword(struct bnx2x *bp, u32 offset, u32 val, - u32 cmd_flags) -{ - int count, i, rc; - - /* build the command word */ - cmd_flags |= MCPR_NVM_COMMAND_DOIT | MCPR_NVM_COMMAND_WR; - - /* need to clear DONE bit separately */ - REG_WR(bp, MCP_REG_MCPR_NVM_COMMAND, MCPR_NVM_COMMAND_DONE); - - /* write the data */ - REG_WR(bp, MCP_REG_MCPR_NVM_WRITE, val); - - /* address of the NVRAM to write to */ - REG_WR(bp, MCP_REG_MCPR_NVM_ADDR, - (offset & MCPR_NVM_ADDR_NVM_ADDR_VALUE)); - - /* issue the write command */ - REG_WR(bp, MCP_REG_MCPR_NVM_COMMAND, cmd_flags); - - /* adjust timeout for emulation/FPGA */ - count = NVRAM_TIMEOUT_COUNT; - if (CHIP_REV_IS_SLOW(bp)) - count *= 100; - - /* wait for completion */ - rc = -EBUSY; - for (i = 0; i < count; i++) { - udelay(5); - val = REG_RD(bp, MCP_REG_MCPR_NVM_COMMAND); - if (val & MCPR_NVM_COMMAND_DONE) { - rc = 0; - break; - } - } - - return rc; -} - -#define BYTE_OFFSET(offset) (8 * (offset & 0x03)) - -static int bnx2x_nvram_write1(struct bnx2x *bp, u32 offset, u8 *data_buf, - int buf_size) -{ - int rc; - u32 cmd_flags; - u32 align_offset; - u32 val; - - if (offset + buf_size > bp->flash_size) { - DP(NETIF_MSG_NVM, "Invalid parameter: offset (0x%x) +" - " buf_size (0x%x) > flash_size (0x%x)\n", - offset, buf_size, bp->flash_size); - return -EINVAL; - } - - /* request access to nvram interface */ - rc = bnx2x_acquire_nvram_lock(bp); - if (rc) - return rc; - - /* enable access to nvram interface */ - bnx2x_enable_nvram_access(bp); - - cmd_flags = (MCPR_NVM_COMMAND_FIRST | MCPR_NVM_COMMAND_LAST); - align_offset = (offset & ~0x03); - rc = bnx2x_nvram_read_dword(bp, align_offset, &val, cmd_flags); - - if (rc == 0) { - val &= ~(0xff << BYTE_OFFSET(offset)); - val |= (*data_buf << BYTE_OFFSET(offset)); - - /* nvram data is returned as an array of bytes - * convert it back to cpu order */ - val = be32_to_cpu(val); - - DP(NETIF_MSG_NVM, "val 0x%08x\n", val); - - rc = bnx2x_nvram_write_dword(bp, align_offset, val, - cmd_flags); - } - - /* disable access to nvram interface */ - bnx2x_disable_nvram_access(bp); - bnx2x_release_nvram_lock(bp); - - return rc; -} - -static int bnx2x_nvram_write(struct bnx2x *bp, u32 offset, u8 *data_buf, - int buf_size) -{ - int rc; - u32 cmd_flags; - u32 val; - u32 written_so_far; - - if (buf_size == 1) { /* ethtool */ - return bnx2x_nvram_write1(bp, offset, data_buf, buf_size); - } - - if ((offset & 0x03) || (buf_size & 0x03) || (buf_size == 0)) { - DP(NETIF_MSG_NVM, - "Invalid parameter: offset 0x%x buf_size 0x%x\n", - offset, buf_size); - return -EINVAL; - } - - if (offset + buf_size > bp->flash_size) { - DP(NETIF_MSG_NVM, "Invalid parameter: offset (0x%x) +" - " buf_size (0x%x) > flash_size (0x%x)\n", - offset, buf_size, bp->flash_size); - return -EINVAL; - } - - /* request access to nvram interface */ - rc = bnx2x_acquire_nvram_lock(bp); - if (rc) - return rc; - - /* enable access to nvram interface */ - bnx2x_enable_nvram_access(bp); - - written_so_far = 0; - cmd_flags = MCPR_NVM_COMMAND_FIRST; - while ((written_so_far < buf_size) && (rc == 0)) { - if (written_so_far == (buf_size - sizeof(u32))) - cmd_flags |= MCPR_NVM_COMMAND_LAST; - else if (((offset + 4) % NVRAM_PAGE_SIZE) == 0) - cmd_flags |= MCPR_NVM_COMMAND_LAST; - else if ((offset % NVRAM_PAGE_SIZE) == 0) - cmd_flags |= MCPR_NVM_COMMAND_FIRST; - - memcpy(&val, data_buf, 4); - DP(NETIF_MSG_NVM, "val 0x%08x\n", val); - - rc = bnx2x_nvram_write_dword(bp, offset, val, cmd_flags); - - /* advance to the next dword */ - offset += sizeof(u32); - data_buf += sizeof(u32); - written_so_far += sizeof(u32); - cmd_flags = 0; - } - - /* disable access to nvram interface */ - bnx2x_disable_nvram_access(bp); - bnx2x_release_nvram_lock(bp); - - return rc; -} - -static int bnx2x_set_eeprom(struct net_device *dev, - struct ethtool_eeprom *eeprom, u8 *eebuf) -{ - struct bnx2x *bp = netdev_priv(dev); - int rc; - - DP(NETIF_MSG_NVM, "ethtool_eeprom: cmd %d\n" - DP_LEVEL " magic 0x%x offset 0x%x (%d) len 0x%x (%d)\n", - eeprom->cmd, eeprom->magic, eeprom->offset, eeprom->offset, - eeprom->len, eeprom->len); - - /* parameters already validated in ethtool_set_eeprom */ - - rc = bnx2x_nvram_write(bp, eeprom->offset, eebuf, eeprom->len); - - return rc; -} - -static int bnx2x_get_coalesce(struct net_device *dev, - struct ethtool_coalesce *coal) -{ - struct bnx2x *bp = netdev_priv(dev); - - memset(coal, 0, sizeof(struct ethtool_coalesce)); - - coal->rx_coalesce_usecs = bp->rx_ticks; - coal->tx_coalesce_usecs = bp->tx_ticks; - coal->stats_block_coalesce_usecs = bp->stats_ticks; - - return 0; -} - -static int bnx2x_set_coalesce(struct net_device *dev, - struct ethtool_coalesce *coal) -{ - struct bnx2x *bp = netdev_priv(dev); - - bp->rx_ticks = (u16) coal->rx_coalesce_usecs; - if (bp->rx_ticks > 3000) - bp->rx_ticks = 3000; - - bp->tx_ticks = (u16) coal->tx_coalesce_usecs; - if (bp->tx_ticks > 0x3000) - bp->tx_ticks = 0x3000; - - bp->stats_ticks = coal->stats_block_coalesce_usecs; - if (bp->stats_ticks > 0xffff00) - bp->stats_ticks = 0xffff00; - bp->stats_ticks &= 0xffff00; - - if (netif_running(bp->dev)) - bnx2x_update_coalesce(bp); - - return 0; -} - -static void bnx2x_get_ringparam(struct net_device *dev, - struct ethtool_ringparam *ering) -{ - struct bnx2x *bp = netdev_priv(dev); - - ering->rx_max_pending = MAX_RX_AVAIL; - ering->rx_mini_max_pending = 0; - ering->rx_jumbo_max_pending = 0; - - ering->rx_pending = bp->rx_ring_size; - ering->rx_mini_pending = 0; - ering->rx_jumbo_pending = 0; - - ering->tx_max_pending = MAX_TX_AVAIL; - ering->tx_pending = bp->tx_ring_size; -} - -static int bnx2x_set_ringparam(struct net_device *dev, - struct ethtool_ringparam *ering) -{ - struct bnx2x *bp = netdev_priv(dev); - - if ((ering->rx_pending > MAX_RX_AVAIL) || - (ering->tx_pending > MAX_TX_AVAIL) || - (ering->tx_pending <= MAX_SKB_FRAGS + 4)) - return -EINVAL; - - bp->rx_ring_size = ering->rx_pending; - bp->tx_ring_size = ering->tx_pending; - - if (netif_running(bp->dev)) { - bnx2x_nic_unload(bp, 0); - bnx2x_nic_load(bp, 0); - } - - return 0; -} - -static void bnx2x_get_pauseparam(struct net_device *dev, - struct ethtool_pauseparam *epause) -{ - struct bnx2x *bp = netdev_priv(dev); - - epause->autoneg = - ((bp->req_autoneg & AUTONEG_FLOW_CTRL) == AUTONEG_FLOW_CTRL); - epause->rx_pause = ((bp->flow_ctrl & FLOW_CTRL_RX) == FLOW_CTRL_RX); - epause->tx_pause = ((bp->flow_ctrl & FLOW_CTRL_TX) == FLOW_CTRL_TX); - - DP(NETIF_MSG_LINK, "ethtool_pauseparam: cmd %d\n" - DP_LEVEL " autoneg %d rx_pause %d tx_pause %d\n", - epause->cmd, epause->autoneg, epause->rx_pause, epause->tx_pause); -} - -static int bnx2x_set_pauseparam(struct net_device *dev, - struct ethtool_pauseparam *epause) -{ - struct bnx2x *bp = netdev_priv(dev); - - DP(NETIF_MSG_LINK, "ethtool_pauseparam: cmd %d\n" - DP_LEVEL " autoneg %d rx_pause %d tx_pause %d\n", - epause->cmd, epause->autoneg, epause->rx_pause, epause->tx_pause); - - if (epause->autoneg) { - if (!(bp->supported & SUPPORTED_Autoneg)) { - DP(NETIF_MSG_LINK, "Aotoneg not supported\n"); - return -EINVAL; - } - - bp->req_autoneg |= AUTONEG_FLOW_CTRL; - } else - bp->req_autoneg &= ~AUTONEG_FLOW_CTRL; - - bp->req_flow_ctrl = FLOW_CTRL_AUTO; - - if (epause->rx_pause) - bp->req_flow_ctrl |= FLOW_CTRL_RX; - if (epause->tx_pause) - bp->req_flow_ctrl |= FLOW_CTRL_TX; - - if (!(bp->req_autoneg & AUTONEG_FLOW_CTRL) && - (bp->req_flow_ctrl == FLOW_CTRL_AUTO)) - bp->req_flow_ctrl = FLOW_CTRL_NONE; - - DP(NETIF_MSG_LINK, "req_autoneg 0x%x req_flow_ctrl 0x%x\n", - bp->req_autoneg, bp->req_flow_ctrl); - - bnx2x_stop_stats(bp); - bnx2x_link_initialize(bp); - - return 0; -} - -static u32 bnx2x_get_rx_csum(struct net_device *dev) -{ - struct bnx2x *bp = netdev_priv(dev); - - return bp->rx_csum; -} - -static int bnx2x_set_rx_csum(struct net_device *dev, u32 data) -{ - struct bnx2x *bp = netdev_priv(dev); - - bp->rx_csum = data; - return 0; -} - -static int bnx2x_set_tso(struct net_device *dev, u32 data) -{ - if (data) - dev->features |= (NETIF_F_TSO | NETIF_F_TSO_ECN); - else - dev->features &= ~(NETIF_F_TSO | NETIF_F_TSO_ECN); - return 0; -} - -static struct { - char string[ETH_GSTRING_LEN]; -} bnx2x_tests_str_arr[BNX2X_NUM_TESTS] = { - { "MC Errors (online)" } -}; - -static int bnx2x_self_test_count(struct net_device *dev) -{ - return BNX2X_NUM_TESTS; -} - -static void bnx2x_self_test(struct net_device *dev, - struct ethtool_test *etest, u64 *buf) -{ - struct bnx2x *bp = netdev_priv(dev); - int stats_state; - - memset(buf, 0, sizeof(u64) * BNX2X_NUM_TESTS); - - if (bp->state != BNX2X_STATE_OPEN) { - DP(NETIF_MSG_PROBE, "state is %x, returning\n", bp->state); - return; - } - - stats_state = bp->stats_state; - bnx2x_stop_stats(bp); - - if (bnx2x_mc_assert(bp) != 0) { - buf[0] = 1; - etest->flags |= ETH_TEST_FL_FAILED; - } - -#ifdef BNX2X_EXTRA_DEBUG - bnx2x_panic_dump(bp); -#endif - bp->stats_state = stats_state; -} - -static struct { - char string[ETH_GSTRING_LEN]; -} bnx2x_stats_str_arr[BNX2X_NUM_STATS] = { - { "rx_bytes"}, - { "rx_error_bytes"}, - { "tx_bytes"}, - { "tx_error_bytes"}, - { "rx_ucast_packets"}, - { "rx_mcast_packets"}, - { "rx_bcast_packets"}, - { "tx_ucast_packets"}, - { "tx_mcast_packets"}, - { "tx_bcast_packets"}, - { "tx_mac_errors"}, /* 10 */ - { "tx_carrier_errors"}, - { "rx_crc_errors"}, - { "rx_align_errors"}, - { "tx_single_collisions"}, - { "tx_multi_collisions"}, - { "tx_deferred"}, - { "tx_excess_collisions"}, - { "tx_late_collisions"}, - { "tx_total_collisions"}, - { "rx_fragments"}, /* 20 */ - { "rx_jabbers"}, - { "rx_undersize_packets"}, - { "rx_oversize_packets"}, - { "rx_xon_frames"}, - { "rx_xoff_frames"}, - { "tx_xon_frames"}, - { "tx_xoff_frames"}, - { "rx_mac_ctrl_frames"}, - { "rx_filtered_packets"}, - { "rx_discards"}, /* 30 */ - { "brb_discard"}, - { "brb_truncate"}, - { "xxoverflow"} -}; - -#define STATS_OFFSET32(offset_name) \ - (offsetof(struct bnx2x_eth_stats, offset_name) / 4) - -static unsigned long bnx2x_stats_offset_arr[BNX2X_NUM_STATS] = { - STATS_OFFSET32(total_bytes_received_hi), - STATS_OFFSET32(stat_IfHCInBadOctets_hi), - STATS_OFFSET32(total_bytes_transmitted_hi), - STATS_OFFSET32(stat_IfHCOutBadOctets_hi), - STATS_OFFSET32(total_unicast_packets_received_hi), - STATS_OFFSET32(total_multicast_packets_received_hi), - STATS_OFFSET32(total_broadcast_packets_received_hi), - STATS_OFFSET32(total_unicast_packets_transmitted_hi), - STATS_OFFSET32(total_multicast_packets_transmitted_hi), - STATS_OFFSET32(total_broadcast_packets_transmitted_hi), - STATS_OFFSET32(stat_Dot3statsInternalMacTransmitErrors), /* 10 */ - STATS_OFFSET32(stat_Dot3StatsCarrierSenseErrors), - STATS_OFFSET32(crc_receive_errors), - STATS_OFFSET32(alignment_errors), - STATS_OFFSET32(single_collision_transmit_frames), - STATS_OFFSET32(multiple_collision_transmit_frames), - STATS_OFFSET32(stat_Dot3StatsDeferredTransmissions), - STATS_OFFSET32(excessive_collision_frames), - STATS_OFFSET32(late_collision_frames), - STATS_OFFSET32(number_of_bugs_found_in_stats_spec), - STATS_OFFSET32(runt_packets_received), /* 20 */ - STATS_OFFSET32(jabber_packets_received), - STATS_OFFSET32(error_runt_packets_received), - STATS_OFFSET32(error_jabber_packets_received), - STATS_OFFSET32(pause_xon_frames_received), - STATS_OFFSET32(pause_xoff_frames_received), - STATS_OFFSET32(pause_xon_frames_transmitted), - STATS_OFFSET32(pause_xoff_frames_transmitted), - STATS_OFFSET32(control_frames_received), - STATS_OFFSET32(mac_filter_discard), - STATS_OFFSET32(no_buff_discard), /* 30 */ - STATS_OFFSET32(brb_discard), - STATS_OFFSET32(brb_truncate_discard), - STATS_OFFSET32(xxoverflow_discard) -}; - -static u8 bnx2x_stats_len_arr[BNX2X_NUM_STATS] = { - 8, 0, 8, 0, 8, 8, 8, 8, 8, 8, - 4, 0, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4 -}; - -static void bnx2x_get_strings(struct net_device *dev, u32 stringset, u8 *buf) -{ - switch (stringset) { - case ETH_SS_STATS: - memcpy(buf, bnx2x_stats_str_arr, sizeof(bnx2x_stats_str_arr)); - break; - - case ETH_SS_TEST: - memcpy(buf, bnx2x_tests_str_arr, sizeof(bnx2x_tests_str_arr)); - break; - } -} - -static int bnx2x_get_stats_count(struct net_device *dev) -{ - return BNX2X_NUM_STATS; -} - -static void bnx2x_get_ethtool_stats(struct net_device *dev, - struct ethtool_stats *stats, u64 *buf) -{ - struct bnx2x *bp = netdev_priv(dev); - u32 *hw_stats = (u32 *)bnx2x_sp_check(bp, eth_stats); - int i; - - for (i = 0; i < BNX2X_NUM_STATS; i++) { - if (bnx2x_stats_len_arr[i] == 0) { - /* skip this counter */ - buf[i] = 0; - continue; - } - if (!hw_stats) { - buf[i] = 0; - continue; - } - if (bnx2x_stats_len_arr[i] == 4) { - /* 4-byte counter */ - buf[i] = (u64) *(hw_stats + bnx2x_stats_offset_arr[i]); - continue; - } - /* 8-byte counter */ - buf[i] = HILO_U64(*(hw_stats + bnx2x_stats_offset_arr[i]), - *(hw_stats + bnx2x_stats_offset_arr[i] + 1)); - } -} - -static int bnx2x_phys_id(struct net_device *dev, u32 data) -{ - struct bnx2x *bp = netdev_priv(dev); - int i; - - if (data == 0) - data = 2; - - for (i = 0; i < (data * 2); i++) { - if ((i % 2) == 0) { - bnx2x_leds_set(bp, SPEED_1000); - } else { - bnx2x_leds_unset(bp); - } - msleep_interruptible(500); - if (signal_pending(current)) - break; - } - - if (bp->link_up) - bnx2x_leds_set(bp, bp->line_speed); - - return 0; -} - -static struct ethtool_ops bnx2x_ethtool_ops = { - .get_settings = bnx2x_get_settings, - .set_settings = bnx2x_set_settings, - .get_drvinfo = bnx2x_get_drvinfo, - .get_wol = bnx2x_get_wol, - .set_wol = bnx2x_set_wol, - .get_msglevel = bnx2x_get_msglevel, - .set_msglevel = bnx2x_set_msglevel, - .nway_reset = bnx2x_nway_reset, - .get_link = ethtool_op_get_link, - .get_eeprom_len = bnx2x_get_eeprom_len, - .get_eeprom = bnx2x_get_eeprom, - .set_eeprom = bnx2x_set_eeprom, - .get_coalesce = bnx2x_get_coalesce, - .set_coalesce = bnx2x_set_coalesce, - .get_ringparam = bnx2x_get_ringparam, - .set_ringparam = bnx2x_set_ringparam, - .get_pauseparam = bnx2x_get_pauseparam, - .set_pauseparam = bnx2x_set_pauseparam, - .get_rx_csum = bnx2x_get_rx_csum, - .set_rx_csum = bnx2x_set_rx_csum, - .get_tx_csum = ethtool_op_get_tx_csum, - .set_tx_csum = ethtool_op_set_tx_csum, - .get_sg = ethtool_op_get_sg, - .set_sg = ethtool_op_set_sg, - .get_tso = ethtool_op_get_tso, - .set_tso = bnx2x_set_tso, - .self_test_count = bnx2x_self_test_count, - .self_test = bnx2x_self_test, - .get_strings = bnx2x_get_strings, - .phys_id = bnx2x_phys_id, - .get_stats_count = bnx2x_get_stats_count, - .get_ethtool_stats = bnx2x_get_ethtool_stats -}; - -/* end of ethtool_ops */ - -/**************************************************************************** -* General service functions -****************************************************************************/ - -static int bnx2x_set_power_state(struct bnx2x *bp, pci_power_t state) -{ - u16 pmcsr; - - pci_read_config_word(bp->pdev, bp->pm_cap + PCI_PM_CTRL, &pmcsr); - - switch (state) { - case PCI_D0: - pci_write_config_word(bp->pdev, - bp->pm_cap + PCI_PM_CTRL, - ((pmcsr & ~PCI_PM_CTRL_STATE_MASK) | - PCI_PM_CTRL_PME_STATUS)); - - if (pmcsr & PCI_PM_CTRL_STATE_MASK) - /* delay required during transition out of D3hot */ - msleep(20); - break; - - case PCI_D3hot: - pmcsr &= ~PCI_PM_CTRL_STATE_MASK; - pmcsr |= 3; - - if (bp->wol) - pmcsr |= PCI_PM_CTRL_PME_ENABLE; - - pci_write_config_word(bp->pdev, bp->pm_cap + PCI_PM_CTRL, - pmcsr); - - /* No more memory access after this point until - * device is brought back to D0. - */ - break; - - default: - return -EINVAL; - } - return 0; -} - -/* - * net_device service functions - */ - -/* called with netif_tx_lock from set_multicast */ -static void bnx2x_set_rx_mode(struct net_device *dev) -{ - struct bnx2x *bp = netdev_priv(dev); - u32 rx_mode = BNX2X_RX_MODE_NORMAL; - - DP(NETIF_MSG_IFUP, "called dev->flags = %x\n", dev->flags); - - if (dev->flags & IFF_PROMISC) - rx_mode = BNX2X_RX_MODE_PROMISC; - - else if ((dev->flags & IFF_ALLMULTI) || - (dev->mc_count > BNX2X_MAX_MULTICAST)) - rx_mode = BNX2X_RX_MODE_ALLMULTI; - - else { /* some multicasts */ - int i, old, offset; - struct dev_mc_list *mclist; - struct mac_configuration_cmd *config = - bnx2x_sp(bp, mcast_config); - - for (i = 0, mclist = dev->mc_list; - mclist && (i < dev->mc_count); - i++, mclist = mclist->next) { - - config->config_table[i].cam_entry.msb_mac_addr = - swab16(*(u16 *)&mclist->dmi_addr[0]); - config->config_table[i].cam_entry.middle_mac_addr = - swab16(*(u16 *)&mclist->dmi_addr[2]); - config->config_table[i].cam_entry.lsb_mac_addr = - swab16(*(u16 *)&mclist->dmi_addr[4]); - config->config_table[i].cam_entry.flags = - cpu_to_le16(bp->port); - config->config_table[i].target_table_entry.flags = 0; - config->config_table[i].target_table_entry. - client_id = 0; - config->config_table[i].target_table_entry. - vlan_id = 0; - - DP(NETIF_MSG_IFUP, - "setting MCAST[%d] (%04x:%04x:%04x)\n", - i, config->config_table[i].cam_entry.msb_mac_addr, - config->config_table[i].cam_entry.middle_mac_addr, - config->config_table[i].cam_entry.lsb_mac_addr); - } - old = config->hdr.length_6b; - if (old > i) { - for (; i < old; i++) { - if (CAM_IS_INVALID(config->config_table[i])) { - i--; /* already invalidated */ - break; - } - /* invalidate */ - CAM_INVALIDATE(config->config_table[i]); - } - } - - if (CHIP_REV_IS_SLOW(bp)) - offset = BNX2X_MAX_EMUL_MULTI*(1 + bp->port); - else - offset = BNX2X_MAX_MULTICAST*(1 + bp->port); - - config->hdr.length_6b = i; - config->hdr.offset = offset; - config->hdr.reserved0 = 0; - config->hdr.reserved1 = 0; - - bnx2x_sp_post(bp, RAMROD_CMD_ID_ETH_SET_MAC, 0, - U64_HI(bnx2x_sp_mapping(bp, mcast_config)), - U64_LO(bnx2x_sp_mapping(bp, mcast_config)), 0); - } - - bp->rx_mode = rx_mode; - bnx2x_set_storm_rx_mode(bp); -} - -static int bnx2x_poll(struct napi_struct *napi, int budget) -{ - struct bnx2x_fastpath *fp = container_of(napi, struct bnx2x_fastpath, - napi); - struct bnx2x *bp = fp->bp; - int work_done = 0; - -#ifdef BNX2X_STOP_ON_ERROR - if (unlikely(bp->panic)) - goto out_panic; -#endif - - prefetch(fp->tx_buf_ring[TX_BD(fp->tx_pkt_cons)].skb); - prefetch(fp->rx_buf_ring[RX_BD(fp->rx_bd_cons)].skb); - prefetch((char *)(fp->rx_buf_ring[RX_BD(fp->rx_bd_cons)].skb) + 256); - - bnx2x_update_fpsb_idx(fp); - - if (le16_to_cpu(*fp->tx_cons_sb) != fp->tx_pkt_cons) - bnx2x_tx_int(fp, budget); - - - if (le16_to_cpu(*fp->rx_cons_sb) != fp->rx_comp_cons) - work_done = bnx2x_rx_int(fp, budget); - - - rmb(); /* bnx2x_has_work() reads the status block */ - - /* must not complete if we consumed full budget */ - if ((work_done < budget) && !bnx2x_has_work(fp)) { - -#ifdef BNX2X_STOP_ON_ERROR -out_panic: -#endif - netif_rx_complete(bp->dev, napi); - - bnx2x_ack_sb(bp, fp->index, USTORM_ID, - le16_to_cpu(fp->fp_u_idx), IGU_INT_NOP, 1); - bnx2x_ack_sb(bp, fp->index, CSTORM_ID, - le16_to_cpu(fp->fp_c_idx), IGU_INT_ENABLE, 1); - } - - return work_done; -} - -/* Called with netif_tx_lock. - * bnx2x_tx_int() runs without netif_tx_lock unless it needs to call - * netif_wake_queue(). - */ -static int bnx2x_start_xmit(struct sk_buff *skb, struct net_device *dev) -{ - struct bnx2x *bp = netdev_priv(dev); - struct bnx2x_fastpath *fp; - struct sw_tx_bd *tx_buf; - struct eth_tx_bd *tx_bd; - struct eth_tx_parse_bd *pbd = NULL; - u16 pkt_prod, bd_prod; - int nbd, fp_index = 0; - dma_addr_t mapping; - -#ifdef BNX2X_STOP_ON_ERROR - if (unlikely(bp->panic)) - return NETDEV_TX_BUSY; -#endif - - fp_index = smp_processor_id() % (bp->num_queues); - - fp = &bp->fp[fp_index]; - if (unlikely(bnx2x_tx_avail(bp->fp) < - (skb_shinfo(skb)->nr_frags + 3))) { - bp->slowpath->eth_stats.driver_xoff++, - netif_stop_queue(dev); - BNX2X_ERR("BUG! Tx ring full when queue awake!\n"); - return NETDEV_TX_BUSY; - } - - /* - This is a bit ugly. First we use one BD which we mark as start, - then for TSO or xsum we have a parsing info BD, - and only then we have the rest of the TSO bds. - (don't forget to mark the last one as last, - and to unmap only AFTER you write to the BD ...) - I would like to thank DovH for this mess. - */ - - pkt_prod = fp->tx_pkt_prod++; - bd_prod = fp->tx_bd_prod; - bd_prod = TX_BD(bd_prod); - - /* get a tx_buff and first bd */ - tx_buf = &fp->tx_buf_ring[TX_BD(pkt_prod)]; - tx_bd = &fp->tx_desc_ring[bd_prod]; - - tx_bd->bd_flags.as_bitfield = ETH_TX_BD_FLAGS_START_BD; - tx_bd->general_data = (UNICAST_ADDRESS << - ETH_TX_BD_ETH_ADDR_TYPE_SHIFT); - tx_bd->general_data |= 1; /* header nbd */ - - /* remember the first bd of the packet */ - tx_buf->first_bd = bd_prod; - - DP(NETIF_MSG_TX_QUEUED, - "sending pkt %u @%p next_idx %u bd %u @%p\n", - pkt_prod, tx_buf, fp->tx_pkt_prod, bd_prod, tx_bd); - - if (skb->ip_summed == CHECKSUM_PARTIAL) { - struct iphdr *iph = ip_hdr(skb); - u8 len; - - tx_bd->bd_flags.as_bitfield |= ETH_TX_BD_FLAGS_IP_CSUM; - - /* turn on parsing and get a bd */ - bd_prod = TX_BD(NEXT_TX_IDX(bd_prod)); - pbd = (void *)&fp->tx_desc_ring[bd_prod]; - len = ((u8 *)iph - (u8 *)skb->data) / 2; - - /* for now NS flag is not used in Linux */ - pbd->global_data = (len | - ((skb->protocol == ntohs(ETH_P_8021Q)) << - ETH_TX_PARSE_BD_LLC_SNAP_EN_SHIFT)); - pbd->ip_hlen = ip_hdrlen(skb) / 2; - pbd->total_hlen = cpu_to_le16(len + pbd->ip_hlen); - if (iph->protocol == IPPROTO_TCP) { - struct tcphdr *th = tcp_hdr(skb); - - tx_bd->bd_flags.as_bitfield |= - ETH_TX_BD_FLAGS_TCP_CSUM; - pbd->tcp_flags = pbd_tcp_flags(skb); - pbd->total_hlen += cpu_to_le16(tcp_hdrlen(skb) / 2); - pbd->tcp_pseudo_csum = swab16(th->check); - - } else if (iph->protocol == IPPROTO_UDP) { - struct udphdr *uh = udp_hdr(skb); - - tx_bd->bd_flags.as_bitfield |= - ETH_TX_BD_FLAGS_TCP_CSUM; - pbd->total_hlen += cpu_to_le16(4); - pbd->global_data |= ETH_TX_PARSE_BD_CS_ANY_FLG; - pbd->cs_offset = 5; /* 10 >> 1 */ - pbd->tcp_pseudo_csum = 0; - /* HW bug: we need to subtract 10 bytes before the - * UDP header from the csum - */ - uh->check = (u16) ~csum_fold(csum_sub(uh->check, - csum_partial(((u8 *)(uh)-10), 10, 0))); - } - } - - if ((bp->vlgrp != NULL) && vlan_tx_tag_present(skb)) { - tx_bd->vlan = cpu_to_le16(vlan_tx_tag_get(skb)); - tx_bd->bd_flags.as_bitfield |= ETH_TX_BD_FLAGS_VLAN_TAG; - } else { - tx_bd->vlan = cpu_to_le16(pkt_prod); - } - - mapping = pci_map_single(bp->pdev, skb->data, - skb->len, PCI_DMA_TODEVICE); - - tx_bd->addr_hi = cpu_to_le32(U64_HI(mapping)); - tx_bd->addr_lo = cpu_to_le32(U64_LO(mapping)); - nbd = skb_shinfo(skb)->nr_frags + ((pbd == NULL)? 1 : 2); - tx_bd->nbd = cpu_to_le16(nbd); - tx_bd->nbytes = cpu_to_le16(skb_headlen(skb)); - - DP(NETIF_MSG_TX_QUEUED, "first bd @%p addr (%x:%x) nbd %d" - " nbytes %d flags %x vlan %u\n", - tx_bd, tx_bd->addr_hi, tx_bd->addr_lo, tx_bd->nbd, - tx_bd->nbytes, tx_bd->bd_flags.as_bitfield, tx_bd->vlan); - - if (skb_shinfo(skb)->gso_size && - (skb->len > (bp->dev->mtu + ETH_HLEN))) { - int hlen = 2 * le16_to_cpu(pbd->total_hlen); - - DP(NETIF_MSG_TX_QUEUED, - "TSO packet len %d hlen %d total len %d tso size %d\n", - skb->len, hlen, skb_headlen(skb), - skb_shinfo(skb)->gso_size); - - tx_bd->bd_flags.as_bitfield |= ETH_TX_BD_FLAGS_SW_LSO; - - if (tx_bd->nbytes > cpu_to_le16(hlen)) { - /* we split the first bd into headers and data bds - * to ease the pain of our fellow micocode engineers - * we use one mapping for both bds - * So far this has only been observed to happen - * in Other Operating Systems(TM) - */ - - /* first fix first bd */ - nbd++; - tx_bd->nbd = cpu_to_le16(nbd); - tx_bd->nbytes = cpu_to_le16(hlen); - - /* we only print this as an error - * because we don't think this will ever happen. - */ - BNX2X_ERR("TSO split header size is %d (%x:%x)" - " nbd %d\n", tx_bd->nbytes, tx_bd->addr_hi, - tx_bd->addr_lo, tx_bd->nbd); - - /* now get a new data bd - * (after the pbd) and fill it */ - bd_prod = TX_BD(NEXT_TX_IDX(bd_prod)); - tx_bd = &fp->tx_desc_ring[bd_prod]; - - tx_bd->addr_hi = cpu_to_le32(U64_HI(mapping)); - tx_bd->addr_lo = cpu_to_le32(U64_LO(mapping) + hlen); - tx_bd->nbytes = cpu_to_le16(skb_headlen(skb) - hlen); - tx_bd->vlan = cpu_to_le16(pkt_prod); - /* this marks the bd - * as one that has no individual mapping - * the FW ignores this flag in a bd not marked start - */ - tx_bd->bd_flags.as_bitfield = ETH_TX_BD_FLAGS_SW_LSO; - DP(NETIF_MSG_TX_QUEUED, - "TSO split data size is %d (%x:%x)\n", - tx_bd->nbytes, tx_bd->addr_hi, tx_bd->addr_lo); - } - - if (!pbd) { - /* supposed to be unreached - * (and therefore not handled properly...) - */ - BNX2X_ERR("LSO with no PBD\n"); - BUG(); - } - - pbd->lso_mss = cpu_to_le16(skb_shinfo(skb)->gso_size); - pbd->tcp_send_seq = swab32(tcp_hdr(skb)->seq); - pbd->ip_id = swab16(ip_hdr(skb)->id); - pbd->tcp_pseudo_csum = - swab16(~csum_tcpudp_magic(ip_hdr(skb)->saddr, - ip_hdr(skb)->daddr, - 0, IPPROTO_TCP, 0)); - pbd->global_data |= ETH_TX_PARSE_BD_PSEUDO_CS_WITHOUT_LEN; - } - - { - int i; - - for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { - skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; - - bd_prod = TX_BD(NEXT_TX_IDX(bd_prod)); - tx_bd = &fp->tx_desc_ring[bd_prod]; - - mapping = pci_map_page(bp->pdev, frag->page, - frag->page_offset, - frag->size, PCI_DMA_TODEVICE); - - tx_bd->addr_hi = cpu_to_le32(U64_HI(mapping)); - tx_bd->addr_lo = cpu_to_le32(U64_LO(mapping)); - tx_bd->nbytes = cpu_to_le16(frag->size); - tx_bd->vlan = cpu_to_le16(pkt_prod); - tx_bd->bd_flags.as_bitfield = 0; - DP(NETIF_MSG_TX_QUEUED, "frag %d bd @%p" - " addr (%x:%x) nbytes %d flags %x\n", - i, tx_bd, tx_bd->addr_hi, tx_bd->addr_lo, - tx_bd->nbytes, tx_bd->bd_flags.as_bitfield); - } /* for */ - } - - /* now at last mark the bd as the last bd */ - tx_bd->bd_flags.as_bitfield |= ETH_TX_BD_FLAGS_END_BD; - - DP(NETIF_MSG_TX_QUEUED, "last bd @%p flags %x\n", - tx_bd, tx_bd->bd_flags.as_bitfield); - - tx_buf->skb = skb; - - bd_prod = TX_BD(NEXT_TX_IDX(bd_prod)); - - /* now send a tx doorbell, counting the next bd - * if the packet contains or ends with it - */ - if (TX_BD_POFF(bd_prod) < nbd) - nbd++; - - if (pbd) - DP(NETIF_MSG_TX_QUEUED, - "PBD @%p ip_data %x ip_hlen %u ip_id %u lso_mss %u" - " tcp_flags %x xsum %x seq %u hlen %u\n", - pbd, pbd->global_data, pbd->ip_hlen, pbd->ip_id, - pbd->lso_mss, pbd->tcp_flags, pbd->tcp_pseudo_csum, - pbd->tcp_send_seq, pbd->total_hlen); - - DP(NETIF_MSG_TX_QUEUED, "doorbell: nbd %u bd %d\n", nbd, bd_prod); - - fp->hw_tx_prods->bds_prod = - cpu_to_le16(le16_to_cpu(fp->hw_tx_prods->bds_prod) + nbd); - mb(); /* FW restriction: must not reorder writing nbd and packets */ - fp->hw_tx_prods->packets_prod = - cpu_to_le32(le32_to_cpu(fp->hw_tx_prods->packets_prod) + 1); - DOORBELL(bp, fp_index, 0); - - mmiowb(); - - fp->tx_bd_prod = bd_prod; - dev->trans_start = jiffies; - - if (unlikely(bnx2x_tx_avail(fp) < MAX_SKB_FRAGS + 3)) { - netif_stop_queue(dev); - bp->slowpath->eth_stats.driver_xoff++; - if (bnx2x_tx_avail(fp) >= MAX_SKB_FRAGS + 3) - netif_wake_queue(dev); - } - fp->tx_pkt++; - - return NETDEV_TX_OK; -} - -/* Called with rtnl_lock */ -static int bnx2x_open(struct net_device *dev) -{ - struct bnx2x *bp = netdev_priv(dev); - - bnx2x_set_power_state(bp, PCI_D0); - - return bnx2x_nic_load(bp, 1); -} - -/* Called with rtnl_lock */ -static int bnx2x_close(struct net_device *dev) -{ - struct bnx2x *bp = netdev_priv(dev); - - /* Unload the driver, release IRQs */ - bnx2x_nic_unload(bp, 1); - - if (!CHIP_REV_IS_SLOW(bp)) - bnx2x_set_power_state(bp, PCI_D3hot); - - return 0; -} - -/* Called with rtnl_lock */ -static int bnx2x_change_mac_addr(struct net_device *dev, void *p) -{ - struct sockaddr *addr = p; - struct bnx2x *bp = netdev_priv(dev); - - if (!is_valid_ether_addr(addr->sa_data)) - return -EINVAL; - - memcpy(dev->dev_addr, addr->sa_data, dev->addr_len); - if (netif_running(dev)) - bnx2x_set_mac_addr(bp); - - return 0; -} - -/* Called with rtnl_lock */ -static int bnx2x_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) -{ - struct mii_ioctl_data *data = if_mii(ifr); - struct bnx2x *bp = netdev_priv(dev); - int err; - - switch (cmd) { - case SIOCGMIIPHY: - data->phy_id = bp->phy_addr; - - /* fallthrough */ - case SIOCGMIIREG: { - u32 mii_regval; - - spin_lock_bh(&bp->phy_lock); - if (bp->state == BNX2X_STATE_OPEN) { - err = bnx2x_mdio22_read(bp, data->reg_num & 0x1f, - &mii_regval); - - data->val_out = mii_regval; - } else { - err = -EAGAIN; - } - spin_unlock_bh(&bp->phy_lock); - return err; - } - - case SIOCSMIIREG: - if (!capable(CAP_NET_ADMIN)) - return -EPERM; - - spin_lock_bh(&bp->phy_lock); - if (bp->state == BNX2X_STATE_OPEN) { - err = bnx2x_mdio22_write(bp, data->reg_num & 0x1f, - data->val_in); - } else { - err = -EAGAIN; - } - spin_unlock_bh(&bp->phy_lock); - return err; - - default: - /* do nothing */ - break; - } - - return -EOPNOTSUPP; -} - -/* Called with rtnl_lock */ -static int bnx2x_change_mtu(struct net_device *dev, int new_mtu) -{ - struct bnx2x *bp = netdev_priv(dev); - - if ((new_mtu > ETH_MAX_JUMBO_PACKET_SIZE) || - ((new_mtu + ETH_HLEN) < ETH_MIN_PACKET_SIZE)) - return -EINVAL; - - /* This does not race with packet allocation - * because the actual alloc size is - * only updated as part of load - */ - dev->mtu = new_mtu; - - if (netif_running(dev)) { - bnx2x_nic_unload(bp, 0); - bnx2x_nic_load(bp, 0); - } - return 0; -} - -static void bnx2x_tx_timeout(struct net_device *dev) -{ - struct bnx2x *bp = netdev_priv(dev); - -#ifdef BNX2X_STOP_ON_ERROR - if (!bp->panic) - bnx2x_panic(); -#endif - /* This allows the netif to be shutdown gracefully before resetting */ - schedule_work(&bp->reset_task); -} - -#ifdef BCM_VLAN -/* Called with rtnl_lock */ -static void bnx2x_vlan_rx_register(struct net_device *dev, - struct vlan_group *vlgrp) -{ - struct bnx2x *bp = netdev_priv(dev); - - bp->vlgrp = vlgrp; - if (netif_running(dev)) - bnx2x_set_client_config(bp); -} -#endif - -#if defined(HAVE_POLL_CONTROLLER) || defined(CONFIG_NET_POLL_CONTROLLER) -static void poll_bnx2x(struct net_device *dev) -{ - struct bnx2x *bp = netdev_priv(dev); - - disable_irq(bp->pdev->irq); - bnx2x_interrupt(bp->pdev->irq, dev); - enable_irq(bp->pdev->irq); -} -#endif - -static void bnx2x_reset_task(struct work_struct *work) -{ - struct bnx2x *bp = container_of(work, struct bnx2x, reset_task); - -#ifdef BNX2X_STOP_ON_ERROR - BNX2X_ERR("reset task called but STOP_ON_ERROR defined" - " so reset not done to allow debug dump,\n" - KERN_ERR " you will need to reboot when done\n"); - return; -#endif - - if (!netif_running(bp->dev)) - return; - - rtnl_lock(); - - if (bp->state != BNX2X_STATE_OPEN) { - DP(NETIF_MSG_TX_ERR, "state is %x, returning\n", bp->state); - goto reset_task_exit; - } - - bnx2x_nic_unload(bp, 0); - bnx2x_nic_load(bp, 0); - -reset_task_exit: - rtnl_unlock(); -} - -static int __devinit bnx2x_init_board(struct pci_dev *pdev, - struct net_device *dev) -{ - struct bnx2x *bp; - int rc; - - SET_NETDEV_DEV(dev, &pdev->dev); - bp = netdev_priv(dev); - - bp->flags = 0; - bp->port = PCI_FUNC(pdev->devfn); - - rc = pci_enable_device(pdev); - if (rc) { - printk(KERN_ERR PFX "Cannot enable PCI device, aborting\n"); - goto err_out; - } - - if (!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM)) { - printk(KERN_ERR PFX "Cannot find PCI device base address," - " aborting\n"); - rc = -ENODEV; - goto err_out_disable; - } - - if (!(pci_resource_flags(pdev, 2) & IORESOURCE_MEM)) { - printk(KERN_ERR PFX "Cannot find second PCI device" - " base address, aborting\n"); - rc = -ENODEV; - goto err_out_disable; - } - - rc = pci_request_regions(pdev, DRV_MODULE_NAME); - if (rc) { - printk(KERN_ERR PFX "Cannot obtain PCI resources," - " aborting\n"); - goto err_out_disable; - } - - pci_set_master(pdev); - - bp->pm_cap = pci_find_capability(pdev, PCI_CAP_ID_PM); - if (bp->pm_cap == 0) { - printk(KERN_ERR PFX "Cannot find power management" - " capability, aborting\n"); - rc = -EIO; - goto err_out_release; - } - - bp->pcie_cap = pci_find_capability(pdev, PCI_CAP_ID_EXP); - if (bp->pcie_cap == 0) { - printk(KERN_ERR PFX "Cannot find PCI Express capability," - " aborting\n"); - rc = -EIO; - goto err_out_release; - } - - if (pci_set_dma_mask(pdev, DMA_64BIT_MASK) == 0) { - bp->flags |= USING_DAC_FLAG; - if (pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK) != 0) { - printk(KERN_ERR PFX "pci_set_consistent_dma_mask" - " failed, aborting\n"); - rc = -EIO; - goto err_out_release; - } - - } else if (pci_set_dma_mask(pdev, DMA_32BIT_MASK) != 0) { - printk(KERN_ERR PFX "System does not support DMA," - " aborting\n"); - rc = -EIO; - goto err_out_release; - } - - bp->dev = dev; - bp->pdev = pdev; - - spin_lock_init(&bp->phy_lock); - - INIT_WORK(&bp->reset_task, bnx2x_reset_task); - INIT_WORK(&bp->sp_task, bnx2x_sp_task); - - dev->base_addr = pci_resource_start(pdev, 0); - - dev->irq = pdev->irq; - - bp->regview = ioremap_nocache(dev->base_addr, - pci_resource_len(pdev, 0)); - if (!bp->regview) { - printk(KERN_ERR PFX "Cannot map register space, aborting\n"); - rc = -ENOMEM; - goto err_out_release; - } - - bp->doorbells = ioremap_nocache(pci_resource_start(pdev , 2), - pci_resource_len(pdev, 2)); - if (!bp->doorbells) { - printk(KERN_ERR PFX "Cannot map doorbell space, aborting\n"); - rc = -ENOMEM; - goto err_out_unmap; - } - - bnx2x_set_power_state(bp, PCI_D0); - - bnx2x_get_hwinfo(bp); - - if (CHIP_REV(bp) == CHIP_REV_FPGA) { - printk(KERN_ERR PFX "FPGA detected. MCP disabled," - " will only init first device\n"); - onefunc = 1; - nomcp = 1; - } - - if (nomcp) { - printk(KERN_ERR PFX "MCP disabled, will only" - " init first device\n"); - onefunc = 1; - } - - if (onefunc && bp->port) { - printk(KERN_ERR PFX "Second device disabled, exiting\n"); - rc = -ENODEV; - goto err_out_unmap; - } - - bp->tx_ring_size = MAX_TX_AVAIL; - bp->rx_ring_size = MAX_RX_AVAIL; - - bp->rx_csum = 1; - - bp->rx_offset = 0; - - bp->tx_quick_cons_trip_int = 0xff; - bp->tx_quick_cons_trip = 0xff; - bp->tx_ticks_int = 50; - bp->tx_ticks = 50; - - bp->rx_quick_cons_trip_int = 0xff; - bp->rx_quick_cons_trip = 0xff; - bp->rx_ticks_int = 25; - bp->rx_ticks = 25; - - bp->stats_ticks = 1000000 & 0xffff00; - - bp->timer_interval = HZ; - bp->current_interval = (poll ? poll : HZ); - - init_timer(&bp->timer); - bp->timer.expires = jiffies + bp->current_interval; - bp->timer.data = (unsigned long) bp; - bp->timer.function = bnx2x_timer; - - return 0; - -err_out_unmap: - if (bp->regview) { - iounmap(bp->regview); - bp->regview = NULL; - } - - if (bp->doorbells) { - iounmap(bp->doorbells); - bp->doorbells = NULL; - } - -err_out_release: - pci_release_regions(pdev); - -err_out_disable: - pci_disable_device(pdev); - pci_set_drvdata(pdev, NULL); - -err_out: - return rc; -} - -static int __devinit bnx2x_get_pcie_width(struct bnx2x *bp) -{ - u32 val = REG_RD(bp, PCICFG_OFFSET + PCICFG_LINK_CONTROL); - - val = (val & PCICFG_LINK_WIDTH) >> PCICFG_LINK_WIDTH_SHIFT; - return val; -} - -/* return value of 1=2.5GHz 2=5GHz */ -static int __devinit bnx2x_get_pcie_speed(struct bnx2x *bp) -{ - u32 val = REG_RD(bp, PCICFG_OFFSET + PCICFG_LINK_CONTROL); - - val = (val & PCICFG_LINK_SPEED) >> PCICFG_LINK_SPEED_SHIFT; - return val; -} - -static int __devinit bnx2x_init_one(struct pci_dev *pdev, - const struct pci_device_id *ent) -{ - static int version_printed; - struct net_device *dev = NULL; - struct bnx2x *bp; - int rc; - int port = PCI_FUNC(pdev->devfn); - DECLARE_MAC_BUF(mac); - - if (version_printed++ == 0) - printk(KERN_INFO "%s", version); - - /* dev zeroed in init_etherdev */ - dev = alloc_etherdev(sizeof(*bp)); - if (!dev) - return -ENOMEM; - - netif_carrier_off(dev); - - bp = netdev_priv(dev); - bp->msglevel = debug; - - if (port && onefunc) { - printk(KERN_ERR PFX "second function disabled. exiting\n"); - free_netdev(dev); - return 0; - } - - rc = bnx2x_init_board(pdev, dev); - if (rc < 0) { - free_netdev(dev); - return rc; - } - - dev->hard_start_xmit = bnx2x_start_xmit; - dev->watchdog_timeo = TX_TIMEOUT; - - dev->ethtool_ops = &bnx2x_ethtool_ops; - dev->open = bnx2x_open; - dev->stop = bnx2x_close; - dev->set_multicast_list = bnx2x_set_rx_mode; - dev->set_mac_address = bnx2x_change_mac_addr; - dev->do_ioctl = bnx2x_ioctl; - dev->change_mtu = bnx2x_change_mtu; - dev->tx_timeout = bnx2x_tx_timeout; -#ifdef BCM_VLAN - dev->vlan_rx_register = bnx2x_vlan_rx_register; -#endif -#if defined(HAVE_POLL_CONTROLLER) || defined(CONFIG_NET_POLL_CONTROLLER) - dev->poll_controller = poll_bnx2x; -#endif - dev->features |= NETIF_F_SG; - if (bp->flags & USING_DAC_FLAG) - dev->features |= NETIF_F_HIGHDMA; - dev->features |= NETIF_F_IP_CSUM; -#ifdef BCM_VLAN - dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX; -#endif - dev->features |= NETIF_F_TSO | NETIF_F_TSO_ECN; - - rc = register_netdev(dev); - if (rc) { - dev_err(&pdev->dev, "Cannot register net device\n"); - if (bp->regview) - iounmap(bp->regview); - if (bp->doorbells) - iounmap(bp->doorbells); - pci_release_regions(pdev); - pci_disable_device(pdev); - pci_set_drvdata(pdev, NULL); - free_netdev(dev); - return rc; - } - - pci_set_drvdata(pdev, dev); - - bp->name = board_info[ent->driver_data].name; - printk(KERN_INFO "%s: %s (%c%d) PCI-E x%d %s found at mem %lx," - " IRQ %d, ", dev->name, bp->name, - ((CHIP_ID(bp) & 0xf000) >> 12) + 'A', - ((CHIP_ID(bp) & 0x0ff0) >> 4), - bnx2x_get_pcie_width(bp), - (bnx2x_get_pcie_speed(bp) == 2) ? "5GHz (Gen2)" : "2.5GHz", - dev->base_addr, bp->pdev->irq); - printk(KERN_CONT "node addr %s\n", print_mac(mac, dev->dev_addr)); - return 0; -} - -static void __devexit bnx2x_remove_one(struct pci_dev *pdev) -{ - struct net_device *dev = pci_get_drvdata(pdev); - struct bnx2x *bp; - - if (!dev) { - /* we get here if init_one() fails */ - printk(KERN_ERR PFX "BAD net device from bnx2x_init_one\n"); - return; - } - - bp = netdev_priv(dev); - - unregister_netdev(dev); - - if (bp->regview) - iounmap(bp->regview); - - if (bp->doorbells) - iounmap(bp->doorbells); - - free_netdev(dev); - pci_release_regions(pdev); - pci_disable_device(pdev); - pci_set_drvdata(pdev, NULL); -} - -static int bnx2x_suspend(struct pci_dev *pdev, pm_message_t state) -{ - struct net_device *dev = pci_get_drvdata(pdev); - struct bnx2x *bp; - - if (!dev) - return 0; - - if (!netif_running(dev)) - return 0; - - bp = netdev_priv(dev); - - bnx2x_nic_unload(bp, 0); - - netif_device_detach(dev); - - pci_save_state(pdev); - bnx2x_set_power_state(bp, pci_choose_state(pdev, state)); - - return 0; -} - -static int bnx2x_resume(struct pci_dev *pdev) -{ - struct net_device *dev = pci_get_drvdata(pdev); - struct bnx2x *bp; - int rc; - - if (!dev) { - printk(KERN_ERR PFX "BAD net device from bnx2x_init_one\n"); - return -ENODEV; - } - - if (!netif_running(dev)) - return 0; - - bp = netdev_priv(dev); - - pci_restore_state(pdev); - bnx2x_set_power_state(bp, PCI_D0); - netif_device_attach(dev); - - rc = bnx2x_nic_load(bp, 0); - if (rc) - return rc; - - return 0; -} - -static struct pci_driver bnx2x_pci_driver = { - .name = DRV_MODULE_NAME, - .id_table = bnx2x_pci_tbl, - .probe = bnx2x_init_one, - .remove = __devexit_p(bnx2x_remove_one), - .suspend = bnx2x_suspend, - .resume = bnx2x_resume, -}; - -static int __init bnx2x_init(void) -{ - return pci_register_driver(&bnx2x_pci_driver); -} - -static void __exit bnx2x_cleanup(void) -{ - pci_unregister_driver(&bnx2x_pci_driver); -} - -module_init(bnx2x_init); -module_exit(bnx2x_cleanup); - diff --git a/drivers/net/bnx2x.h b/drivers/net/bnx2x.h index 8e68d06510a6..4bf4f7b205f2 100644 --- a/drivers/net/bnx2x.h +++ b/drivers/net/bnx2x.h @@ -14,39 +14,46 @@ #ifndef BNX2X_H #define BNX2X_H +/* compilation time flags */ + +/* define this to make the driver freeze on error to allow getting debug info + * (you will need to reboot afterwards) */ +/* #define BNX2X_STOP_ON_ERROR */ + /* error/debug prints */ -#define DRV_MODULE_NAME "bnx2x" -#define PFX DRV_MODULE_NAME ": " +#define DRV_MODULE_NAME "bnx2x" +#define PFX DRV_MODULE_NAME ": " /* for messages that are currently off */ -#define BNX2X_MSG_OFF 0 -#define BNX2X_MSG_MCP 0x10000 /* was: NETIF_MSG_HW */ -#define BNX2X_MSG_STATS 0x20000 /* was: NETIF_MSG_TIMER */ -#define NETIF_MSG_NVM 0x40000 /* was: NETIF_MSG_HW */ -#define NETIF_MSG_DMAE 0x80000 /* was: NETIF_MSG_HW */ +#define BNX2X_MSG_OFF 0 +#define BNX2X_MSG_MCP 0x010000 /* was: NETIF_MSG_HW */ +#define BNX2X_MSG_STATS 0x020000 /* was: NETIF_MSG_TIMER */ +#define BNX2X_MSG_NVM 0x040000 /* was: NETIF_MSG_HW */ +#define BNX2X_MSG_DMAE 0x080000 /* was: NETIF_MSG_HW */ #define BNX2X_MSG_SP 0x100000 /* was: NETIF_MSG_INTR */ #define BNX2X_MSG_FP 0x200000 /* was: NETIF_MSG_INTR */ -#define DP_LEVEL KERN_NOTICE /* was: KERN_DEBUG */ +#define DP_LEVEL KERN_NOTICE /* was: KERN_DEBUG */ /* regular debug print */ #define DP(__mask, __fmt, __args...) do { \ if (bp->msglevel & (__mask)) \ - printk(DP_LEVEL "[%s:%d(%s)]" __fmt, __FUNCTION__, \ - __LINE__, bp->dev?(bp->dev->name):"?", ##__args); \ + printk(DP_LEVEL "[%s:%d(%s)]" __fmt, __func__, __LINE__, \ + bp->dev?(bp->dev->name):"?", ##__args); \ } while (0) -/* for errors (never masked) */ -#define BNX2X_ERR(__fmt, __args...) do { \ - printk(KERN_ERR "[%s:%d(%s)]" __fmt, __FUNCTION__, \ - __LINE__, bp->dev?(bp->dev->name):"?", ##__args); \ +/* errors debug print */ +#define BNX2X_DBG_ERR(__fmt, __args...) do { \ + if (bp->msglevel & NETIF_MSG_PROBE) \ + printk(KERN_ERR "[%s:%d(%s)]" __fmt, __func__, __LINE__, \ + bp->dev?(bp->dev->name):"?", ##__args); \ } while (0) -/* for logging (never masked) */ -#define BNX2X_LOG(__fmt, __args...) do { \ - printk(KERN_NOTICE "[%s:%d(%s)]" __fmt, __FUNCTION__, \ - __LINE__, bp->dev?(bp->dev->name):"?", ##__args); \ +/* for errors (never masked) */ +#define BNX2X_ERR(__fmt, __args...) do { \ + printk(KERN_ERR "[%s:%d(%s)]" __fmt, __func__, __LINE__, \ + bp->dev?(bp->dev->name):"?", ##__args); \ } while (0) /* before we have a dev->name use dev_info() */ @@ -60,7 +67,7 @@ #define bnx2x_panic() do { \ bp->panic = 1; \ BNX2X_ERR("driver assert\n"); \ - bnx2x_disable_int(bp); \ + bnx2x_int_disable(bp); \ bnx2x_panic_dump(bp); \ } while (0) #else @@ -71,164 +78,412 @@ #endif -#define U64_LO(x) (((u64)x) & 0xffffffff) -#define U64_HI(x) (((u64)x) >> 32) -#define HILO_U64(hi, lo) (((u64)hi << 32) + lo) +#ifdef NETIF_F_HW_VLAN_TX +#define BCM_VLAN 1 +#endif + +#define U64_LO(x) (u32)(((u64)(x)) & 0xffffffff) +#define U64_HI(x) (u32)(((u64)(x)) >> 32) +#define HILO_U64(hi, lo) ((((u64)(hi)) << 32) + (lo)) -#define REG_ADDR(bp, offset) (bp->regview + offset) -#define REG_RD(bp, offset) readl(REG_ADDR(bp, offset)) -#define REG_RD8(bp, offset) readb(REG_ADDR(bp, offset)) -#define REG_RD64(bp, offset) readq(REG_ADDR(bp, offset)) +#define REG_ADDR(bp, offset) (bp->regview + offset) -#define REG_WR(bp, offset, val) writel((u32)val, REG_ADDR(bp, offset)) +#define REG_RD(bp, offset) readl(REG_ADDR(bp, offset)) +#define REG_RD8(bp, offset) readb(REG_ADDR(bp, offset)) +#define REG_RD64(bp, offset) readq(REG_ADDR(bp, offset)) + +#define REG_WR(bp, offset, val) writel((u32)val, REG_ADDR(bp, offset)) #define REG_WR8(bp, offset, val) writeb((u8)val, REG_ADDR(bp, offset)) -#define REG_WR16(bp, offset, val) writew((u16)val, REG_ADDR(bp, offset)) -#define REG_WR32(bp, offset, val) REG_WR(bp, offset, val) +#define REG_WR16(bp, offset, val) writew((u16)val, REG_ADDR(bp, offset)) +#define REG_WR32(bp, offset, val) REG_WR(bp, offset, val) + +#define REG_RD_IND(bp, offset) bnx2x_reg_rd_ind(bp, offset) +#define REG_WR_IND(bp, offset, val) bnx2x_reg_wr_ind(bp, offset, val) -#define REG_RD_IND(bp, offset) bnx2x_reg_rd_ind(bp, offset) -#define REG_WR_IND(bp, offset, val) bnx2x_reg_wr_ind(bp, offset, val) +#define REG_RD_DMAE(bp, offset, valp, len32) \ + do { \ + bnx2x_read_dmae(bp, offset, len32);\ + memcpy(valp, bnx2x_sp(bp, wb_data[0]), len32 * 4); \ + } while (0) -#define REG_WR_DMAE(bp, offset, val, len32) \ +#define REG_WR_DMAE(bp, offset, valp, len32) \ do { \ - memcpy(bnx2x_sp(bp, wb_data[0]), val, len32 * 4); \ + memcpy(bnx2x_sp(bp, wb_data[0]), valp, len32 * 4); \ bnx2x_write_dmae(bp, bnx2x_sp_mapping(bp, wb_data), \ offset, len32); \ } while (0) -#define SHMEM_RD(bp, type) \ - REG_RD(bp, bp->shmem_base + offsetof(struct shmem_region, type)) -#define SHMEM_WR(bp, type, val) \ - REG_WR(bp, bp->shmem_base + offsetof(struct shmem_region, type), val) +#define SHMEM_ADDR(bp, field) (bp->common.shmem_base + \ + offsetof(struct shmem_region, field)) +#define SHMEM_RD(bp, field) REG_RD(bp, SHMEM_ADDR(bp, field)) +#define SHMEM_WR(bp, field, val) REG_WR(bp, SHMEM_ADDR(bp, field), val) #define NIG_WR(reg, val) REG_WR(bp, reg, val) -#define EMAC_WR(reg, val) REG_WR(bp, emac_base + reg, val) -#define BMAC_WR(reg, val) REG_WR(bp, GRCBASE_NIG + bmac_addr + reg, val) +#define EMAC_WR(reg, val) REG_WR(bp, emac_base + reg, val) +#define BMAC_WR(reg, val) REG_WR(bp, GRCBASE_NIG + bmac_addr + reg, val) -#define for_each_queue(bp, var) for (var = 0; var < bp->num_queues; var++) +#define for_each_queue(bp, var) for (var = 0; var < bp->num_queues; var++) #define for_each_nondefault_queue(bp, var) \ for (var = 1; var < bp->num_queues; var++) -#define is_multi(bp) (bp->num_queues > 1) +#define is_multi(bp) (bp->num_queues > 1) -struct regp { - u32 lo; - u32 hi; +/* fast path */ + +struct sw_rx_bd { + struct sk_buff *skb; + DECLARE_PCI_UNMAP_ADDR(mapping) +}; + +struct sw_tx_bd { + struct sk_buff *skb; + u16 first_bd; }; -struct bmac_stats { - struct regp tx_gtpkt; - struct regp tx_gtxpf; - struct regp tx_gtfcs; - struct regp tx_gtmca; - struct regp tx_gtgca; - struct regp tx_gtfrg; - struct regp tx_gtovr; - struct regp tx_gt64; - struct regp tx_gt127; - struct regp tx_gt255; /* 10 */ - struct regp tx_gt511; - struct regp tx_gt1023; - struct regp tx_gt1518; - struct regp tx_gt2047; - struct regp tx_gt4095; - struct regp tx_gt9216; - struct regp tx_gt16383; - struct regp tx_gtmax; - struct regp tx_gtufl; - struct regp tx_gterr; /* 20 */ - struct regp tx_gtbyt; - - struct regp rx_gr64; - struct regp rx_gr127; - struct regp rx_gr255; - struct regp rx_gr511; - struct regp rx_gr1023; - struct regp rx_gr1518; - struct regp rx_gr2047; - struct regp rx_gr4095; - struct regp rx_gr9216; /* 30 */ - struct regp rx_gr16383; - struct regp rx_grmax; - struct regp rx_grpkt; - struct regp rx_grfcs; - struct regp rx_grmca; - struct regp rx_grbca; - struct regp rx_grxcf; - struct regp rx_grxpf; - struct regp rx_grxuo; - struct regp rx_grjbr; /* 40 */ - struct regp rx_grovr; - struct regp rx_grflr; - struct regp rx_grmeg; - struct regp rx_grmeb; - struct regp rx_grbyt; - struct regp rx_grund; - struct regp rx_grfrg; - struct regp rx_grerb; - struct regp rx_grfre; - struct regp rx_gripj; /* 50 */ +struct sw_rx_page { + struct page *page; + DECLARE_PCI_UNMAP_ADDR(mapping) }; -struct emac_stats { - u32 rx_ifhcinoctets ; - u32 rx_ifhcinbadoctets ; - u32 rx_etherstatsfragments ; - u32 rx_ifhcinucastpkts ; - u32 rx_ifhcinmulticastpkts ; - u32 rx_ifhcinbroadcastpkts ; - u32 rx_dot3statsfcserrors ; - u32 rx_dot3statsalignmenterrors ; - u32 rx_dot3statscarriersenseerrors ; - u32 rx_xonpauseframesreceived ; /* 10 */ - u32 rx_xoffpauseframesreceived ; - u32 rx_maccontrolframesreceived ; - u32 rx_xoffstateentered ; - u32 rx_dot3statsframestoolong ; - u32 rx_etherstatsjabbers ; - u32 rx_etherstatsundersizepkts ; - u32 rx_etherstatspkts64octets ; - u32 rx_etherstatspkts65octetsto127octets ; - u32 rx_etherstatspkts128octetsto255octets ; - u32 rx_etherstatspkts256octetsto511octets ; /* 20 */ - u32 rx_etherstatspkts512octetsto1023octets ; - u32 rx_etherstatspkts1024octetsto1522octets; - u32 rx_etherstatspktsover1522octets ; - - u32 rx_falsecarriererrors ; - - u32 tx_ifhcoutoctets ; - u32 tx_ifhcoutbadoctets ; - u32 tx_etherstatscollisions ; - u32 tx_outxonsent ; - u32 tx_outxoffsent ; - u32 tx_flowcontroldone ; /* 30 */ - u32 tx_dot3statssinglecollisionframes ; - u32 tx_dot3statsmultiplecollisionframes ; - u32 tx_dot3statsdeferredtransmissions ; - u32 tx_dot3statsexcessivecollisions ; - u32 tx_dot3statslatecollisions ; - u32 tx_ifhcoutucastpkts ; - u32 tx_ifhcoutmulticastpkts ; - u32 tx_ifhcoutbroadcastpkts ; - u32 tx_etherstatspkts64octets ; - u32 tx_etherstatspkts65octetsto127octets ; /* 40 */ - u32 tx_etherstatspkts128octetsto255octets ; - u32 tx_etherstatspkts256octetsto511octets ; - u32 tx_etherstatspkts512octetsto1023octets ; - u32 tx_etherstatspkts1024octetsto1522octet ; - u32 tx_etherstatspktsover1522octets ; - u32 tx_dot3statsinternalmactransmiterrors ; /* 46 */ + +/* MC hsi */ +#define BCM_PAGE_SHIFT 12 +#define BCM_PAGE_SIZE (1 << BCM_PAGE_SHIFT) +#define BCM_PAGE_MASK (~(BCM_PAGE_SIZE - 1)) +#define BCM_PAGE_ALIGN(addr) (((addr) + BCM_PAGE_SIZE - 1) & BCM_PAGE_MASK) + +#define PAGES_PER_SGE_SHIFT 0 +#define PAGES_PER_SGE (1 << PAGES_PER_SGE_SHIFT) + +/* SGE ring related macros */ +#define NUM_RX_SGE_PAGES 2 +#define RX_SGE_CNT (BCM_PAGE_SIZE / sizeof(struct eth_rx_sge)) +#define MAX_RX_SGE_CNT (RX_SGE_CNT - 2) +/* RX_SGE_CNT is promissed to be a power of 2 */ +#define RX_SGE_MASK (RX_SGE_CNT - 1) +#define NUM_RX_SGE (RX_SGE_CNT * NUM_RX_SGE_PAGES) +#define MAX_RX_SGE (NUM_RX_SGE - 1) +#define NEXT_SGE_IDX(x) ((((x) & RX_SGE_MASK) == \ + (MAX_RX_SGE_CNT - 1)) ? (x) + 3 : (x) + 1) +#define RX_SGE(x) ((x) & MAX_RX_SGE) + +/* SGE producer mask related macros */ +/* Number of bits in one sge_mask array element */ +#define RX_SGE_MASK_ELEM_SZ 64 +#define RX_SGE_MASK_ELEM_SHIFT 6 +#define RX_SGE_MASK_ELEM_MASK ((u64)RX_SGE_MASK_ELEM_SZ - 1) + +/* Creates a bitmask of all ones in less significant bits. + idx - index of the most significant bit in the created mask */ +#define RX_SGE_ONES_MASK(idx) \ + (((u64)0x1 << (((idx) & RX_SGE_MASK_ELEM_MASK) + 1)) - 1) +#define RX_SGE_MASK_ELEM_ONE_MASK ((u64)(~0)) + +/* Number of u64 elements in SGE mask array */ +#define RX_SGE_MASK_LEN ((NUM_RX_SGE_PAGES * RX_SGE_CNT) / \ + RX_SGE_MASK_ELEM_SZ) +#define RX_SGE_MASK_LEN_MASK (RX_SGE_MASK_LEN - 1) +#define NEXT_SGE_MASK_ELEM(el) (((el) + 1) & RX_SGE_MASK_LEN_MASK) + + +struct bnx2x_fastpath { + + struct napi_struct napi; + + struct host_status_block *status_blk; + dma_addr_t status_blk_mapping; + + struct eth_tx_db_data *hw_tx_prods; + dma_addr_t tx_prods_mapping; + + struct sw_tx_bd *tx_buf_ring; + + struct eth_tx_bd *tx_desc_ring; + dma_addr_t tx_desc_mapping; + + struct sw_rx_bd *rx_buf_ring; /* BDs mappings ring */ + struct sw_rx_page *rx_page_ring; /* SGE pages mappings ring */ + + struct eth_rx_bd *rx_desc_ring; + dma_addr_t rx_desc_mapping; + + union eth_rx_cqe *rx_comp_ring; + dma_addr_t rx_comp_mapping; + + /* SGE ring */ + struct eth_rx_sge *rx_sge_ring; + dma_addr_t rx_sge_mapping; + + u64 sge_mask[RX_SGE_MASK_LEN]; + + int state; +#define BNX2X_FP_STATE_CLOSED 0 +#define BNX2X_FP_STATE_IRQ 0x80000 +#define BNX2X_FP_STATE_OPENING 0x90000 +#define BNX2X_FP_STATE_OPEN 0xa0000 +#define BNX2X_FP_STATE_HALTING 0xb0000 +#define BNX2X_FP_STATE_HALTED 0xc0000 + + u8 index; /* number in fp array */ + u8 cl_id; /* eth client id */ + u8 sb_id; /* status block number in HW */ +#define FP_IDX(fp) (fp->index) +#define FP_CL_ID(fp) (fp->cl_id) +#define BP_CL_ID(bp) (bp->fp[0].cl_id) +#define FP_SB_ID(fp) (fp->sb_id) +#define CNIC_SB_ID 0 + + u16 tx_pkt_prod; + u16 tx_pkt_cons; + u16 tx_bd_prod; + u16 tx_bd_cons; + u16 *tx_cons_sb; + + u16 fp_c_idx; + u16 fp_u_idx; + + u16 rx_bd_prod; + u16 rx_bd_cons; + u16 rx_comp_prod; + u16 rx_comp_cons; + u16 rx_sge_prod; + /* The last maximal completed SGE */ + u16 last_max_sge; + u16 *rx_cons_sb; + u16 *rx_bd_cons_sb; + + unsigned long tx_pkt, + rx_pkt, + rx_calls, + rx_alloc_failed; + /* TPA related */ + struct sw_rx_bd tpa_pool[ETH_MAX_AGGREGATION_QUEUES_E1H]; + u8 tpa_state[ETH_MAX_AGGREGATION_QUEUES_E1H]; +#define BNX2X_TPA_START 1 +#define BNX2X_TPA_STOP 2 + u8 disable_tpa; +#ifdef BNX2X_STOP_ON_ERROR + u64 tpa_queue_used; +#endif + + struct bnx2x *bp; /* parent */ }; -union mac_stats { - struct emac_stats emac; - struct bmac_stats bmac; +#define bnx2x_fp(bp, nr, var) (bp->fp[nr].var) + + +/* MC hsi */ +#define MAX_FETCH_BD 13 /* HW max BDs per packet */ +#define RX_COPY_THRESH 92 + +#define NUM_TX_RINGS 16 +#define TX_DESC_CNT (BCM_PAGE_SIZE / sizeof(struct eth_tx_bd)) +#define MAX_TX_DESC_CNT (TX_DESC_CNT - 1) +#define NUM_TX_BD (TX_DESC_CNT * NUM_TX_RINGS) +#define MAX_TX_BD (NUM_TX_BD - 1) +#define MAX_TX_AVAIL (MAX_TX_DESC_CNT * NUM_TX_RINGS - 2) +#define NEXT_TX_IDX(x) ((((x) & MAX_TX_DESC_CNT) == \ + (MAX_TX_DESC_CNT - 1)) ? (x) + 2 : (x) + 1) +#define TX_BD(x) ((x) & MAX_TX_BD) +#define TX_BD_POFF(x) ((x) & MAX_TX_DESC_CNT) + +/* The RX BD ring is special, each bd is 8 bytes but the last one is 16 */ +#define NUM_RX_RINGS 8 +#define RX_DESC_CNT (BCM_PAGE_SIZE / sizeof(struct eth_rx_bd)) +#define MAX_RX_DESC_CNT (RX_DESC_CNT - 2) +#define RX_DESC_MASK (RX_DESC_CNT - 1) +#define NUM_RX_BD (RX_DESC_CNT * NUM_RX_RINGS) +#define MAX_RX_BD (NUM_RX_BD - 1) +#define MAX_RX_AVAIL (MAX_RX_DESC_CNT * NUM_RX_RINGS - 2) +#define NEXT_RX_IDX(x) ((((x) & RX_DESC_MASK) == \ + (MAX_RX_DESC_CNT - 1)) ? (x) + 3 : (x) + 1) +#define RX_BD(x) ((x) & MAX_RX_BD) + +/* As long as CQE is 4 times bigger than BD entry we have to allocate + 4 times more pages for CQ ring in order to keep it balanced with + BD ring */ +#define NUM_RCQ_RINGS (NUM_RX_RINGS * 4) +#define RCQ_DESC_CNT (BCM_PAGE_SIZE / sizeof(union eth_rx_cqe)) +#define MAX_RCQ_DESC_CNT (RCQ_DESC_CNT - 1) +#define NUM_RCQ_BD (RCQ_DESC_CNT * NUM_RCQ_RINGS) +#define MAX_RCQ_BD (NUM_RCQ_BD - 1) +#define MAX_RCQ_AVAIL (MAX_RCQ_DESC_CNT * NUM_RCQ_RINGS - 2) +#define NEXT_RCQ_IDX(x) ((((x) & MAX_RCQ_DESC_CNT) == \ + (MAX_RCQ_DESC_CNT - 1)) ? (x) + 2 : (x) + 1) +#define RCQ_BD(x) ((x) & MAX_RCQ_BD) + + +/* This is needed for determening of last_max */ +#define SUB_S16(a, b) (s16)((s16)(a) - (s16)(b)) + +#define __SGE_MASK_SET_BIT(el, bit) \ + do { \ + el = ((el) | ((u64)0x1 << (bit))); \ + } while (0) + +#define __SGE_MASK_CLEAR_BIT(el, bit) \ + do { \ + el = ((el) & (~((u64)0x1 << (bit)))); \ + } while (0) + +#define SGE_MASK_SET_BIT(fp, idx) \ + __SGE_MASK_SET_BIT(fp->sge_mask[(idx) >> RX_SGE_MASK_ELEM_SHIFT], \ + ((idx) & RX_SGE_MASK_ELEM_MASK)) + +#define SGE_MASK_CLEAR_BIT(fp, idx) \ + __SGE_MASK_CLEAR_BIT(fp->sge_mask[(idx) >> RX_SGE_MASK_ELEM_SHIFT], \ + ((idx) & RX_SGE_MASK_ELEM_MASK)) + + +/* used on a CID received from the HW */ +#define SW_CID(x) (le32_to_cpu(x) & \ + (COMMON_RAMROD_ETH_RX_CQE_CID >> 7)) +#define CQE_CMD(x) (le32_to_cpu(x) >> \ + COMMON_RAMROD_ETH_RX_CQE_CMD_ID_SHIFT) + +#define BD_UNMAP_ADDR(bd) HILO_U64(le32_to_cpu((bd)->addr_hi), \ + le32_to_cpu((bd)->addr_lo)) +#define BD_UNMAP_LEN(bd) (le16_to_cpu((bd)->nbytes)) + + +#define DPM_TRIGER_TYPE 0x40 +#define DOORBELL(bp, cid, val) \ + do { \ + writel((u32)val, (bp)->doorbells + (BCM_PAGE_SIZE * cid) + \ + DPM_TRIGER_TYPE); \ + } while (0) + + +/* TX CSUM helpers */ +#define SKB_CS_OFF(skb) (offsetof(struct tcphdr, check) - \ + skb->csum_offset) +#define SKB_CS(skb) (*(u16 *)(skb_transport_header(skb) + \ + skb->csum_offset)) + +#define pbd_tcp_flags(skb) (ntohl(tcp_flag_word(tcp_hdr(skb)))>>16 & 0xff) + +#define XMIT_PLAIN 0 +#define XMIT_CSUM_V4 0x1 +#define XMIT_CSUM_V6 0x2 +#define XMIT_CSUM_TCP 0x4 +#define XMIT_GSO_V4 0x8 +#define XMIT_GSO_V6 0x10 + +#define XMIT_CSUM (XMIT_CSUM_V4 | XMIT_CSUM_V6) +#define XMIT_GSO (XMIT_GSO_V4 | XMIT_GSO_V6) + + +/* stuff added to make the code fit 80Col */ + +#define CQE_TYPE(cqe_fp_flags) ((cqe_fp_flags) & ETH_FAST_PATH_RX_CQE_TYPE) + +#define TPA_TYPE_START ETH_FAST_PATH_RX_CQE_START_FLG +#define TPA_TYPE_END ETH_FAST_PATH_RX_CQE_END_FLG +#define TPA_TYPE(cqe_fp_flags) ((cqe_fp_flags) & \ + (TPA_TYPE_START | TPA_TYPE_END)) + +#define BNX2X_RX_SUM_OK(cqe) \ + (!(cqe->fast_path_cqe.status_flags & \ + (ETH_FAST_PATH_RX_CQE_IP_XSUM_NO_VALIDATION_FLG | \ + ETH_FAST_PATH_RX_CQE_L4_XSUM_NO_VALIDATION_FLG))) + +#define BNX2X_RX_SUM_FIX(cqe) \ + ((le16_to_cpu(cqe->fast_path_cqe.pars_flags.flags) & \ + PARSING_FLAGS_OVER_ETHERNET_PROTOCOL) == \ + (1 << PARSING_FLAGS_OVER_ETHERNET_PROTOCOL_SHIFT)) + +#define ETH_RX_ERROR_FALGS (ETH_FAST_PATH_RX_CQE_PHY_DECODE_ERR_FLG | \ + ETH_FAST_PATH_RX_CQE_IP_BAD_XSUM_FLG | \ + ETH_FAST_PATH_RX_CQE_L4_BAD_XSUM_FLG) + + +#define FP_USB_FUNC_OFF (2 + 2*HC_USTORM_SB_NUM_INDICES) +#define FP_CSB_FUNC_OFF (2 + 2*HC_CSTORM_SB_NUM_INDICES) + +#define U_SB_ETH_RX_CQ_INDEX HC_INDEX_U_ETH_RX_CQ_CONS +#define U_SB_ETH_RX_BD_INDEX HC_INDEX_U_ETH_RX_BD_CONS +#define C_SB_ETH_TX_CQ_INDEX HC_INDEX_C_ETH_TX_CQ_CONS + +#define BNX2X_RX_SB_INDEX \ + (&fp->status_blk->u_status_block.index_values[U_SB_ETH_RX_CQ_INDEX]) + +#define BNX2X_RX_SB_BD_INDEX \ + (&fp->status_blk->u_status_block.index_values[U_SB_ETH_RX_BD_INDEX]) + +#define BNX2X_RX_SB_INDEX_NUM \ + (((U_SB_ETH_RX_CQ_INDEX << \ + USTORM_ETH_ST_CONTEXT_CONFIG_CQE_SB_INDEX_NUMBER_SHIFT) & \ + USTORM_ETH_ST_CONTEXT_CONFIG_CQE_SB_INDEX_NUMBER) | \ + ((U_SB_ETH_RX_BD_INDEX << \ + USTORM_ETH_ST_CONTEXT_CONFIG_BD_SB_INDEX_NUMBER_SHIFT) & \ + USTORM_ETH_ST_CONTEXT_CONFIG_BD_SB_INDEX_NUMBER)) + +#define BNX2X_TX_SB_INDEX \ + (&fp->status_blk->c_status_block.index_values[C_SB_ETH_TX_CQ_INDEX]) + + +/* end of fast path */ + +/* common */ + +struct bnx2x_common { + + u32 chip_id; +/* chip num:16-31, rev:12-15, metal:4-11, bond_id:0-3 */ +#define CHIP_ID(bp) (bp->common.chip_id & 0xfffffff0) + +#define CHIP_NUM(bp) (bp->common.chip_id >> 16) +#define CHIP_NUM_57710 0x164e +#define CHIP_NUM_57711 0x164f +#define CHIP_NUM_57711E 0x1650 +#define CHIP_IS_E1(bp) (CHIP_NUM(bp) == CHIP_NUM_57710) +#define CHIP_IS_57711(bp) (CHIP_NUM(bp) == CHIP_NUM_57711) +#define CHIP_IS_57711E(bp) (CHIP_NUM(bp) == CHIP_NUM_57711E) +#define CHIP_IS_E1H(bp) (CHIP_IS_57711(bp) || \ + CHIP_IS_57711E(bp)) +#define IS_E1H_OFFSET CHIP_IS_E1H(bp) + +#define CHIP_REV(bp) (bp->common.chip_id & 0x0000f000) +#define CHIP_REV_Ax 0x00000000 +/* assume maximum 5 revisions */ +#define CHIP_REV_IS_SLOW(bp) (CHIP_REV(bp) > 0x00005000) +/* Emul versions are A=>0xe, B=>0xc, C=>0xa, D=>8, E=>6 */ +#define CHIP_REV_IS_EMUL(bp) ((CHIP_REV_IS_SLOW(bp)) && \ + !(CHIP_REV(bp) & 0x00001000)) +/* FPGA versions are A=>0xf, B=>0xd, C=>0xb, D=>9, E=>7 */ +#define CHIP_REV_IS_FPGA(bp) ((CHIP_REV_IS_SLOW(bp)) && \ + (CHIP_REV(bp) & 0x00001000)) + +#define CHIP_TIME(bp) ((CHIP_REV_IS_EMUL(bp)) ? 2000 : \ + ((CHIP_REV_IS_FPGA(bp)) ? 200 : 1)) + +#define CHIP_METAL(bp) (bp->common.chip_id & 0x00000ff0) +#define CHIP_BOND_ID(bp) (bp->common.chip_id & 0x0000000f) + + int flash_size; +#define NVRAM_1MB_SIZE 0x20000 /* 1M bit in bytes */ +#define NVRAM_TIMEOUT_COUNT 30000 +#define NVRAM_PAGE_SIZE 256 + + u32 shmem_base; + + u32 hw_config; + u32 board; + + u32 bc_ver; + + char *name; }; + +/* end of common */ + +/* port */ + struct nig_stats { u32 brb_discard; u32 brb_packet; @@ -244,13 +499,53 @@ struct nig_stats { u32 pbf_octets; u32 pbf_packet; u32 safc_inp; - u32 done; - u32 pad; + u32 egress_mac_pkt0_lo; + u32 egress_mac_pkt0_hi; + u32 egress_mac_pkt1_lo; + u32 egress_mac_pkt1_hi; +}; + +struct bnx2x_port { + u32 pmf; + + u32 link_config; + + u32 supported; +/* link settings - missing defines */ +#define SUPPORTED_2500baseX_Full (1 << 15) + + u32 advertising; +/* link settings - missing defines */ +#define ADVERTISED_2500baseX_Full (1 << 15) + + u32 phy_addr; + + /* used to synchronize phy accesses */ + struct mutex phy_mutex; + + u32 port_stx; + + struct nig_stats old_nig_stats; +}; + +/* end of port */ + + +enum bnx2x_stats_event { + STATS_EVENT_PMF = 0, + STATS_EVENT_LINK_UP, + STATS_EVENT_UPDATE, + STATS_EVENT_STOP, + STATS_EVENT_MAX +}; + +enum bnx2x_stats_state { + STATS_STATE_DISABLED = 0, + STATS_STATE_ENABLED, + STATS_STATE_MAX }; struct bnx2x_eth_stats { - u32 pad; /* to make long counters u64 aligned */ - u32 mac_stx_start; u32 total_bytes_received_hi; u32 total_bytes_received_lo; u32 total_bytes_transmitted_hi; @@ -267,97 +562,117 @@ struct bnx2x_eth_stats { u32 total_multicast_packets_transmitted_lo; u32 total_broadcast_packets_transmitted_hi; u32 total_broadcast_packets_transmitted_lo; - u32 crc_receive_errors; - u32 alignment_errors; - u32 false_carrier_detections; - u32 runt_packets_received; - u32 jabber_packets_received; - u32 pause_xon_frames_received; - u32 pause_xoff_frames_received; - u32 pause_xon_frames_transmitted; - u32 pause_xoff_frames_transmitted; - u32 single_collision_transmit_frames; - u32 multiple_collision_transmit_frames; - u32 late_collision_frames; - u32 excessive_collision_frames; - u32 control_frames_received; - u32 frames_received_64_bytes; - u32 frames_received_65_127_bytes; - u32 frames_received_128_255_bytes; - u32 frames_received_256_511_bytes; - u32 frames_received_512_1023_bytes; - u32 frames_received_1024_1522_bytes; - u32 frames_received_1523_9022_bytes; - u32 frames_transmitted_64_bytes; - u32 frames_transmitted_65_127_bytes; - u32 frames_transmitted_128_255_bytes; - u32 frames_transmitted_256_511_bytes; - u32 frames_transmitted_512_1023_bytes; - u32 frames_transmitted_1024_1522_bytes; - u32 frames_transmitted_1523_9022_bytes; u32 valid_bytes_received_hi; u32 valid_bytes_received_lo; - u32 error_runt_packets_received; - u32 error_jabber_packets_received; - u32 mac_stx_end; - - u32 pad2; - u32 stat_IfHCInBadOctets_hi; - u32 stat_IfHCInBadOctets_lo; - u32 stat_IfHCOutBadOctets_hi; - u32 stat_IfHCOutBadOctets_lo; - u32 stat_Dot3statsFramesTooLong; - u32 stat_Dot3statsInternalMacTransmitErrors; - u32 stat_Dot3StatsCarrierSenseErrors; - u32 stat_Dot3StatsDeferredTransmissions; - u32 stat_FlowControlDone; - u32 stat_XoffStateEntered; - - u32 x_total_sent_bytes_hi; - u32 x_total_sent_bytes_lo; - u32 x_total_sent_pkts; - - u32 t_rcv_unicast_bytes_hi; - u32 t_rcv_unicast_bytes_lo; - u32 t_rcv_broadcast_bytes_hi; - u32 t_rcv_broadcast_bytes_lo; - u32 t_rcv_multicast_bytes_hi; - u32 t_rcv_multicast_bytes_lo; - u32 t_total_rcv_pkt; - - u32 checksum_discard; - u32 packets_too_big_discard; + + u32 error_bytes_received_hi; + u32 error_bytes_received_lo; + + u32 rx_stat_ifhcinbadoctets_hi; + u32 rx_stat_ifhcinbadoctets_lo; + u32 tx_stat_ifhcoutbadoctets_hi; + u32 tx_stat_ifhcoutbadoctets_lo; + u32 rx_stat_dot3statsfcserrors_hi; + u32 rx_stat_dot3statsfcserrors_lo; + u32 rx_stat_dot3statsalignmenterrors_hi; + u32 rx_stat_dot3statsalignmenterrors_lo; + u32 rx_stat_dot3statscarriersenseerrors_hi; + u32 rx_stat_dot3statscarriersenseerrors_lo; + u32 rx_stat_falsecarriererrors_hi; + u32 rx_stat_falsecarriererrors_lo; + u32 rx_stat_etherstatsundersizepkts_hi; + u32 rx_stat_etherstatsundersizepkts_lo; + u32 rx_stat_dot3statsframestoolong_hi; + u32 rx_stat_dot3statsframestoolong_lo; + u32 rx_stat_etherstatsfragments_hi; + u32 rx_stat_etherstatsfragments_lo; + u32 rx_stat_etherstatsjabbers_hi; + u32 rx_stat_etherstatsjabbers_lo; + u32 rx_stat_maccontrolframesreceived_hi; + u32 rx_stat_maccontrolframesreceived_lo; + u32 rx_stat_bmac_xpf_hi; + u32 rx_stat_bmac_xpf_lo; + u32 rx_stat_bmac_xcf_hi; + u32 rx_stat_bmac_xcf_lo; + u32 rx_stat_xoffstateentered_hi; + u32 rx_stat_xoffstateentered_lo; + u32 rx_stat_xonpauseframesreceived_hi; + u32 rx_stat_xonpauseframesreceived_lo; + u32 rx_stat_xoffpauseframesreceived_hi; + u32 rx_stat_xoffpauseframesreceived_lo; + u32 tx_stat_outxonsent_hi; + u32 tx_stat_outxonsent_lo; + u32 tx_stat_outxoffsent_hi; + u32 tx_stat_outxoffsent_lo; + u32 tx_stat_flowcontroldone_hi; + u32 tx_stat_flowcontroldone_lo; + u32 tx_stat_etherstatscollisions_hi; + u32 tx_stat_etherstatscollisions_lo; + u32 tx_stat_dot3statssinglecollisionframes_hi; + u32 tx_stat_dot3statssinglecollisionframes_lo; + u32 tx_stat_dot3statsmultiplecollisionframes_hi; + u32 tx_stat_dot3statsmultiplecollisionframes_lo; + u32 tx_stat_dot3statsdeferredtransmissions_hi; + u32 tx_stat_dot3statsdeferredtransmissions_lo; + u32 tx_stat_dot3statsexcessivecollisions_hi; + u32 tx_stat_dot3statsexcessivecollisions_lo; + u32 tx_stat_dot3statslatecollisions_hi; + u32 tx_stat_dot3statslatecollisions_lo; + u32 tx_stat_etherstatspkts64octets_hi; + u32 tx_stat_etherstatspkts64octets_lo; + u32 tx_stat_etherstatspkts65octetsto127octets_hi; + u32 tx_stat_etherstatspkts65octetsto127octets_lo; + u32 tx_stat_etherstatspkts128octetsto255octets_hi; + u32 tx_stat_etherstatspkts128octetsto255octets_lo; + u32 tx_stat_etherstatspkts256octetsto511octets_hi; + u32 tx_stat_etherstatspkts256octetsto511octets_lo; + u32 tx_stat_etherstatspkts512octetsto1023octets_hi; + u32 tx_stat_etherstatspkts512octetsto1023octets_lo; + u32 tx_stat_etherstatspkts1024octetsto1522octets_hi; + u32 tx_stat_etherstatspkts1024octetsto1522octets_lo; + u32 tx_stat_etherstatspktsover1522octets_hi; + u32 tx_stat_etherstatspktsover1522octets_lo; + u32 tx_stat_bmac_2047_hi; + u32 tx_stat_bmac_2047_lo; + u32 tx_stat_bmac_4095_hi; + u32 tx_stat_bmac_4095_lo; + u32 tx_stat_bmac_9216_hi; + u32 tx_stat_bmac_9216_lo; + u32 tx_stat_bmac_16383_hi; + u32 tx_stat_bmac_16383_lo; + u32 tx_stat_dot3statsinternalmactransmiterrors_hi; + u32 tx_stat_dot3statsinternalmactransmiterrors_lo; + u32 tx_stat_bmac_ufl_hi; + u32 tx_stat_bmac_ufl_lo; + + u32 brb_drop_hi; + u32 brb_drop_lo; + + u32 jabber_packets_received; + + u32 etherstatspkts1024octetsto1522octets_hi; + u32 etherstatspkts1024octetsto1522octets_lo; + u32 etherstatspktsover1522octets_hi; + u32 etherstatspktsover1522octets_lo; + u32 no_buff_discard; - u32 ttl0_discard; - u32 mac_discard; + u32 mac_filter_discard; u32 xxoverflow_discard; u32 brb_truncate_discard; + u32 mac_discard; - u32 brb_discard; - u32 brb_packet; - u32 brb_truncate; - u32 flow_ctrl_discard; - u32 flow_ctrl_octets; - u32 flow_ctrl_packet; - u32 mng_discard; - u32 mng_octet_inp; - u32 mng_octet_out; - u32 mng_packet_inp; - u32 mng_packet_out; - u32 pbf_octets; - u32 pbf_packet; - u32 safc_inp; u32 driver_xoff; - u32 number_of_bugs_found_in_stats_spec; /* just kidding */ }; -#define MAC_STX_NA 0xffffffff +#define STATS_OFFSET32(stat_name) \ + (offsetof(struct bnx2x_eth_stats, stat_name) / 4) + #ifdef BNX2X_MULTI -#define MAX_CONTEXT 16 +#define MAX_CONTEXT 16 #else -#define MAX_CONTEXT 1 +#define MAX_CONTEXT 1 #endif union cdu_context { @@ -365,345 +680,191 @@ union cdu_context { char pad[1024]; }; -#define MAX_DMAE_C 5 +#define MAX_DMAE_C 8 /* DMA memory not used in fastpath */ struct bnx2x_slowpath { - union cdu_context context[MAX_CONTEXT]; - struct eth_stats_query fw_stats; - struct mac_configuration_cmd mac_config; - struct mac_configuration_cmd mcast_config; + union cdu_context context[MAX_CONTEXT]; + struct eth_stats_query fw_stats; + struct mac_configuration_cmd mac_config; + struct mac_configuration_cmd mcast_config; /* used by dmae command executer */ - struct dmae_command dmae[MAX_DMAE_C]; + struct dmae_command dmae[MAX_DMAE_C]; - union mac_stats mac_stats; - struct nig_stats nig; - struct bnx2x_eth_stats eth_stats; + u32 stats_comp; + union mac_stats mac_stats; + struct nig_stats nig_stats; + struct host_port_stats port_stats; + struct host_func_stats func_stats; - u32 wb_comp; -#define BNX2X_WB_COMP_VAL 0xe0d0d0ae - u32 wb_data[4]; + u32 wb_comp; + u32 wb_data[4]; }; -#define bnx2x_sp(bp, var) (&bp->slowpath->var) -#define bnx2x_sp_check(bp, var) ((bp->slowpath) ? (&bp->slowpath->var) : NULL) +#define bnx2x_sp(bp, var) (&bp->slowpath->var) #define bnx2x_sp_mapping(bp, var) \ (bp->slowpath_mapping + offsetof(struct bnx2x_slowpath, var)) -struct sw_rx_bd { - struct sk_buff *skb; - DECLARE_PCI_UNMAP_ADDR(mapping) -}; - -struct sw_tx_bd { - struct sk_buff *skb; - u16 first_bd; -}; - -struct bnx2x_fastpath { - - struct napi_struct napi; - - struct host_status_block *status_blk; - dma_addr_t status_blk_mapping; - - struct eth_tx_db_data *hw_tx_prods; - dma_addr_t tx_prods_mapping; - - struct sw_tx_bd *tx_buf_ring; - - struct eth_tx_bd *tx_desc_ring; - dma_addr_t tx_desc_mapping; - - struct sw_rx_bd *rx_buf_ring; - - struct eth_rx_bd *rx_desc_ring; - dma_addr_t rx_desc_mapping; - - union eth_rx_cqe *rx_comp_ring; - dma_addr_t rx_comp_mapping; - - int state; -#define BNX2X_FP_STATE_CLOSED 0 -#define BNX2X_FP_STATE_IRQ 0x80000 -#define BNX2X_FP_STATE_OPENING 0x90000 -#define BNX2X_FP_STATE_OPEN 0xa0000 -#define BNX2X_FP_STATE_HALTING 0xb0000 -#define BNX2X_FP_STATE_HALTED 0xc0000 - - int index; - - u16 tx_pkt_prod; - u16 tx_pkt_cons; - u16 tx_bd_prod; - u16 tx_bd_cons; - u16 *tx_cons_sb; - - u16 fp_c_idx; - u16 fp_u_idx; - - u16 rx_bd_prod; - u16 rx_bd_cons; - u16 rx_comp_prod; - u16 rx_comp_cons; - u16 *rx_cons_sb; - - unsigned long tx_pkt, - rx_pkt, - rx_calls; - - struct bnx2x *bp; /* parent */ -}; - -#define bnx2x_fp(bp, nr, var) (bp->fp[nr].var) - - /* attn group wiring */ -#define MAX_DYNAMIC_ATTN_GRPS 8 +#define MAX_DYNAMIC_ATTN_GRPS 8 struct attn_route { - u32 sig[4]; + u32 sig[4]; }; struct bnx2x { /* Fields used in the tx and intr/napi performance paths * are grouped together in the beginning of the structure */ - struct bnx2x_fastpath *fp; - void __iomem *regview; - void __iomem *doorbells; + struct bnx2x_fastpath fp[MAX_CONTEXT]; + void __iomem *regview; + void __iomem *doorbells; +#define BNX2X_DB_SIZE (16*2048) - struct net_device *dev; - struct pci_dev *pdev; + struct net_device *dev; + struct pci_dev *pdev; atomic_t intr_sem; - struct msix_entry msix_table[MAX_CONTEXT+1]; + struct msix_entry msix_table[MAX_CONTEXT+1]; - int tx_ring_size; + int tx_ring_size; #ifdef BCM_VLAN - struct vlan_group *vlgrp; + struct vlan_group *vlgrp; #endif - u32 rx_csum; - u32 rx_offset; - u32 rx_buf_use_size; /* useable size */ - u32 rx_buf_size; /* with alignment */ -#define ETH_OVREHEAD (ETH_HLEN + 8) /* 8 for CRC + VLAN */ -#define ETH_MIN_PACKET_SIZE 60 -#define ETH_MAX_PACKET_SIZE 1500 -#define ETH_MAX_JUMBO_PACKET_SIZE 9600 + u32 rx_csum; + u32 rx_offset; + u32 rx_buf_use_size; /* useable size */ + u32 rx_buf_size; /* with alignment */ +#define ETH_OVREHEAD (ETH_HLEN + 8) /* 8 for CRC + VLAN */ +#define ETH_MIN_PACKET_SIZE 60 +#define ETH_MAX_PACKET_SIZE 1500 +#define ETH_MAX_JUMBO_PACKET_SIZE 9600 struct host_def_status_block *def_status_blk; -#define DEF_SB_ID 16 - u16 def_c_idx; - u16 def_u_idx; - u16 def_t_idx; - u16 def_x_idx; - u16 def_att_idx; - u32 attn_state; - struct attn_route attn_group[MAX_DYNAMIC_ATTN_GRPS]; - u32 aeu_mask; - u32 nig_mask; +#define DEF_SB_ID 16 + u16 def_c_idx; + u16 def_u_idx; + u16 def_x_idx; + u16 def_t_idx; + u16 def_att_idx; + u32 attn_state; + struct attn_route attn_group[MAX_DYNAMIC_ATTN_GRPS]; + u32 aeu_mask; + u32 nig_mask; /* slow path ring */ - struct eth_spe *spq; - dma_addr_t spq_mapping; - u16 spq_prod_idx; - struct eth_spe *spq_prod_bd; - struct eth_spe *spq_last_bd; - u16 *dsb_sp_prod; - u16 spq_left; /* serialize spq */ - spinlock_t spq_lock; - - /* Flag for marking that there is either - * STAT_QUERY or CFC DELETE ramrod pending - */ - u8 stat_pending; - - /* End of fields used in the performance code paths */ - - int panic; - int msglevel; - - u32 flags; -#define PCIX_FLAG 1 -#define PCI_32BIT_FLAG 2 -#define ONE_TDMA_FLAG 4 /* no longer used */ -#define NO_WOL_FLAG 8 -#define USING_DAC_FLAG 0x10 -#define USING_MSIX_FLAG 0x20 -#define ASF_ENABLE_FLAG 0x40 - - int port; - - int pm_cap; - int pcie_cap; - - /* Used to synchronize phy accesses */ - spinlock_t phy_lock; - - struct work_struct reset_task; - struct work_struct sp_task; - - struct timer_list timer; - int timer_interval; - int current_interval; - - u32 shmem_base; - - u32 chip_id; -/* chip num:16-31, rev:12-15, metal:4-11, bond_id:0-3 */ -#define CHIP_ID(bp) (((bp)->chip_id) & 0xfffffff0) - -#define CHIP_NUM(bp) (((bp)->chip_id) & 0xffff0000) - -#define CHIP_REV(bp) (((bp)->chip_id) & 0x0000f000) -#define CHIP_REV_Ax 0x00000000 -#define CHIP_REV_Bx 0x00001000 -#define CHIP_REV_Cx 0x00002000 -#define CHIP_REV_EMUL 0x0000e000 -#define CHIP_REV_FPGA 0x0000f000 -#define CHIP_REV_IS_SLOW(bp) ((CHIP_REV(bp) == CHIP_REV_EMUL) || \ - (CHIP_REV(bp) == CHIP_REV_FPGA)) - -#define CHIP_METAL(bp) (((bp)->chip_id) & 0x00000ff0) -#define CHIP_BOND_ID(bp) (((bp)->chip_id) & 0x0000000f) - - u16 fw_seq; - u16 fw_drv_pulse_wr_seq; - u32 fw_mb; - - u32 hw_config; - u32 board; - u32 serdes_config; - u32 lane_config; - u32 ext_phy_config; -#define XGXS_EXT_PHY_TYPE(bp) (bp->ext_phy_config & \ - PORT_HW_CFG_XGXS_EXT_PHY_TYPE_MASK) -#define SERDES_EXT_PHY_TYPE(bp) (bp->ext_phy_config & \ - PORT_HW_CFG_SERDES_EXT_PHY_TYPE_MASK) - - u32 speed_cap_mask; - u32 link_config; -#define SWITCH_CFG_1G PORT_FEATURE_CON_SWITCH_1G_SWITCH -#define SWITCH_CFG_10G PORT_FEATURE_CON_SWITCH_10G_SWITCH -#define SWITCH_CFG_AUTO_DETECT PORT_FEATURE_CON_SWITCH_AUTO_DETECT -#define SWITCH_CFG_ONE_TIME_DETECT \ - PORT_FEATURE_CON_SWITCH_ONE_TIME_DETECT - - u8 ser_lane; - u8 rx_lane_swap; - u8 tx_lane_swap; - - u8 link_up; - u8 phy_link_up; - - u32 supported; -/* link settings - missing defines */ -#define SUPPORTED_2500baseT_Full (1 << 15) - - u32 phy_flags; -/*#define PHY_SERDES_FLAG 0x1*/ -#define PHY_BMAC_FLAG 0x2 -#define PHY_EMAC_FLAG 0x4 -#define PHY_XGXS_FLAG 0x8 -#define PHY_SGMII_FLAG 0x10 -#define PHY_INT_MODE_MASK_FLAG 0x300 -#define PHY_INT_MODE_AUTO_POLLING_FLAG 0x100 -#define PHY_INT_MODE_LINK_READY_FLAG 0x200 - - u32 phy_addr; - u32 phy_id; - - u32 autoneg; -#define AUTONEG_CL37 SHARED_HW_CFG_AN_ENABLE_CL37 -#define AUTONEG_CL73 SHARED_HW_CFG_AN_ENABLE_CL73 -#define AUTONEG_BAM SHARED_HW_CFG_AN_ENABLE_BAM -#define AUTONEG_PARALLEL \ - SHARED_HW_CFG_AN_ENABLE_PARALLEL_DETECTION -#define AUTONEG_SGMII_FIBER_AUTODET \ - SHARED_HW_CFG_AN_EN_SGMII_FIBER_AUTO_DETECT -#define AUTONEG_REMOTE_PHY SHARED_HW_CFG_AN_ENABLE_REMOTE_PHY - - u32 req_autoneg; -#define AUTONEG_SPEED 0x1 -#define AUTONEG_FLOW_CTRL 0x2 - - u32 req_line_speed; -/* link settings - missing defines */ -#define SPEED_12000 12000 -#define SPEED_12500 12500 -#define SPEED_13000 13000 -#define SPEED_15000 15000 -#define SPEED_16000 16000 - - u32 req_duplex; - u32 req_flow_ctrl; -#define FLOW_CTRL_AUTO PORT_FEATURE_FLOW_CONTROL_AUTO -#define FLOW_CTRL_TX PORT_FEATURE_FLOW_CONTROL_TX -#define FLOW_CTRL_RX PORT_FEATURE_FLOW_CONTROL_RX -#define FLOW_CTRL_BOTH PORT_FEATURE_FLOW_CONTROL_BOTH -#define FLOW_CTRL_NONE PORT_FEATURE_FLOW_CONTROL_NONE - - u32 advertising; -/* link settings - missing defines */ -#define ADVERTISED_2500baseT_Full (1 << 15) - - u32 link_status; - u32 line_speed; - u32 duplex; - u32 flow_ctrl; - - u32 bc_ver; - - int flash_size; -#define NVRAM_1MB_SIZE 0x20000 /* 1M bit in bytes */ -#define NVRAM_TIMEOUT_COUNT 30000 -#define NVRAM_PAGE_SIZE 256 + struct eth_spe *spq; + dma_addr_t spq_mapping; + u16 spq_prod_idx; + struct eth_spe *spq_prod_bd; + struct eth_spe *spq_last_bd; + u16 *dsb_sp_prod; + u16 spq_left; /* serialize spq */ + /* used to synchronize spq accesses */ + spinlock_t spq_lock; + + /* Flags for marking that there is a STAT_QUERY or + SET_MAC ramrod pending */ + u8 stats_pending; + u8 set_mac_pending; + + /* End of fileds used in the performance code paths */ + + int panic; + int msglevel; + + u32 flags; +#define PCIX_FLAG 1 +#define PCI_32BIT_FLAG 2 +#define ONE_TDMA_FLAG 4 /* no longer used */ +#define NO_WOL_FLAG 8 +#define USING_DAC_FLAG 0x10 +#define USING_MSIX_FLAG 0x20 +#define ASF_ENABLE_FLAG 0x40 +#define TPA_ENABLE_FLAG 0x80 +#define NO_MCP_FLAG 0x100 +#define BP_NOMCP(bp) (bp->flags & NO_MCP_FLAG) + + int func; +#define BP_PORT(bp) (bp->func % PORT_MAX) +#define BP_FUNC(bp) (bp->func) +#define BP_E1HVN(bp) (bp->func >> 1) +#define BP_L_ID(bp) (BP_E1HVN(bp) << 2) +/* assorted E1HVN */ +#define IS_E1HMF(bp) (bp->e1hmf != 0) +#define BP_MAX_QUEUES(bp) (IS_E1HMF(bp) ? 4 : 16) + + int pm_cap; + int pcie_cap; + + struct work_struct sp_task; + struct work_struct reset_task; + + struct timer_list timer; + int timer_interval; + int current_interval; + + u16 fw_seq; + u16 fw_drv_pulse_wr_seq; + u32 func_stx; + + struct link_params link_params; + struct link_vars link_vars; + + struct bnx2x_common common; + struct bnx2x_port port; + + u32 mf_config; + u16 e1hov; + u8 e1hmf; u8 wol; - int rx_ring_size; + int rx_ring_size; - u16 tx_quick_cons_trip_int; - u16 tx_quick_cons_trip; - u16 tx_ticks_int; - u16 tx_ticks; + u16 tx_quick_cons_trip_int; + u16 tx_quick_cons_trip; + u16 tx_ticks_int; + u16 tx_ticks; - u16 rx_quick_cons_trip_int; - u16 rx_quick_cons_trip; - u16 rx_ticks_int; - u16 rx_ticks; + u16 rx_quick_cons_trip_int; + u16 rx_quick_cons_trip; + u16 rx_ticks_int; + u16 rx_ticks; - u32 stats_ticks; + u32 stats_ticks; + u32 lin_cnt; - int state; -#define BNX2X_STATE_CLOSED 0x0 -#define BNX2X_STATE_OPENING_WAIT4_LOAD 0x1000 -#define BNX2X_STATE_OPENING_WAIT4_PORT 0x2000 + int state; +#define BNX2X_STATE_CLOSED 0x0 +#define BNX2X_STATE_OPENING_WAIT4_LOAD 0x1000 +#define BNX2X_STATE_OPENING_WAIT4_PORT 0x2000 #define BNX2X_STATE_OPEN 0x3000 -#define BNX2X_STATE_CLOSING_WAIT4_HALT 0x4000 +#define BNX2X_STATE_CLOSING_WAIT4_HALT 0x4000 #define BNX2X_STATE_CLOSING_WAIT4_DELETE 0x5000 #define BNX2X_STATE_CLOSING_WAIT4_UNLOAD 0x6000 -#define BNX2X_STATE_ERROR 0xF000 +#define BNX2X_STATE_DISABLED 0xd000 +#define BNX2X_STATE_DIAG 0xe000 +#define BNX2X_STATE_ERROR 0xf000 - int num_queues; + int num_queues; - u32 rx_mode; -#define BNX2X_RX_MODE_NONE 0 -#define BNX2X_RX_MODE_NORMAL 1 -#define BNX2X_RX_MODE_ALLMULTI 2 -#define BNX2X_RX_MODE_PROMISC 3 -#define BNX2X_MAX_MULTICAST 64 -#define BNX2X_MAX_EMUL_MULTI 16 + u32 rx_mode; +#define BNX2X_RX_MODE_NONE 0 +#define BNX2X_RX_MODE_NORMAL 1 +#define BNX2X_RX_MODE_ALLMULTI 2 +#define BNX2X_RX_MODE_PROMISC 3 +#define BNX2X_MAX_MULTICAST 64 +#define BNX2X_MAX_EMUL_MULTI 16 - dma_addr_t def_status_blk_mapping; + dma_addr_t def_status_blk_mapping; - struct bnx2x_slowpath *slowpath; - dma_addr_t slowpath_mapping; + struct bnx2x_slowpath *slowpath; + dma_addr_t slowpath_mapping; #ifdef BCM_ISCSI void *t1; @@ -716,264 +877,164 @@ struct bnx2x { dma_addr_t qm_mapping; #endif - char *name; + int dmae_ready; + /* used to synchronize dmae accesses */ + struct mutex dmae_mutex; + struct dmae_command init_dmae; /* used to synchronize stats collecting */ - int stats_state; -#define STATS_STATE_DISABLE 0 -#define STATS_STATE_ENABLE 1 -#define STATS_STATE_STOP 2 /* stop stats on next iteration */ - + int stats_state; /* used by dmae command loader */ - struct dmae_command dmae; - int executer_idx; + struct dmae_command stats_dmae; + int executer_idx; - u32 old_brb_discard; - struct bmac_stats old_bmac; + u16 stats_counter; struct tstorm_per_client_stats old_tclient; - struct z_stream_s *strm; - void *gunzip_buf; - dma_addr_t gunzip_mapping; - int gunzip_outlen; -#define FW_BUF_SIZE 0x8000 - -}; + struct xstorm_per_client_stats old_xclient; + struct bnx2x_eth_stats eth_stats; + struct z_stream_s *strm; + void *gunzip_buf; + dma_addr_t gunzip_mapping; + int gunzip_outlen; +#define FW_BUF_SIZE 0x8000 -/* DMAE command defines */ -#define DMAE_CMD_SRC_PCI 0 -#define DMAE_CMD_SRC_GRC DMAE_COMMAND_SRC +}; -#define DMAE_CMD_DST_PCI (1 << DMAE_COMMAND_DST_SHIFT) -#define DMAE_CMD_DST_GRC (2 << DMAE_COMMAND_DST_SHIFT) -#define DMAE_CMD_C_DST_PCI 0 -#define DMAE_CMD_C_DST_GRC (1 << DMAE_COMMAND_C_DST_SHIFT) +void bnx2x_read_dmae(struct bnx2x *bp, u32 src_addr, u32 len32); +void bnx2x_write_dmae(struct bnx2x *bp, dma_addr_t dma_addr, u32 dst_addr, + u32 len32); +int bnx2x_set_gpio(struct bnx2x *bp, int gpio_num, u32 mode); -#define DMAE_CMD_C_ENABLE DMAE_COMMAND_C_TYPE_ENABLE +static inline u32 reg_poll(struct bnx2x *bp, u32 reg, u32 expected, int ms, + int wait) +{ + u32 val; -#define DMAE_CMD_ENDIANITY_NO_SWAP (0 << DMAE_COMMAND_ENDIANITY_SHIFT) -#define DMAE_CMD_ENDIANITY_B_SWAP (1 << DMAE_COMMAND_ENDIANITY_SHIFT) -#define DMAE_CMD_ENDIANITY_DW_SWAP (2 << DMAE_COMMAND_ENDIANITY_SHIFT) -#define DMAE_CMD_ENDIANITY_B_DW_SWAP (3 << DMAE_COMMAND_ENDIANITY_SHIFT) + do { + val = REG_RD(bp, reg); + if (val == expected) + break; + ms -= wait; + msleep(wait); -#define DMAE_CMD_PORT_0 0 -#define DMAE_CMD_PORT_1 DMAE_COMMAND_PORT + } while (ms > 0); -#define DMAE_CMD_SRC_RESET DMAE_COMMAND_SRC_RESET -#define DMAE_CMD_DST_RESET DMAE_COMMAND_DST_RESET + return val; +} -#define DMAE_LEN32_MAX 0x400 +/* load/unload mode */ +#define LOAD_NORMAL 0 +#define LOAD_OPEN 1 +#define LOAD_DIAG 2 +#define UNLOAD_NORMAL 0 +#define UNLOAD_CLOSE 1 -/* MC hsi */ -#define RX_COPY_THRESH 92 -#define BCM_PAGE_BITS 12 -#define BCM_PAGE_SIZE (1 << BCM_PAGE_BITS) - -#define NUM_TX_RINGS 16 -#define TX_DESC_CNT (BCM_PAGE_SIZE / sizeof(struct eth_tx_bd)) -#define MAX_TX_DESC_CNT (TX_DESC_CNT - 1) -#define NUM_TX_BD (TX_DESC_CNT * NUM_TX_RINGS) -#define MAX_TX_BD (NUM_TX_BD - 1) -#define MAX_TX_AVAIL (MAX_TX_DESC_CNT * NUM_TX_RINGS - 2) -#define NEXT_TX_IDX(x) ((((x) & MAX_TX_DESC_CNT) == \ - (MAX_TX_DESC_CNT - 1)) ? (x) + 2 : (x) + 1) -#define TX_BD(x) ((x) & MAX_TX_BD) -#define TX_BD_POFF(x) ((x) & MAX_TX_DESC_CNT) -/* The RX BD ring is special, each bd is 8 bytes but the last one is 16 */ -#define NUM_RX_RINGS 8 -#define RX_DESC_CNT (BCM_PAGE_SIZE / sizeof(struct eth_rx_bd)) -#define MAX_RX_DESC_CNT (RX_DESC_CNT - 2) -#define RX_DESC_MASK (RX_DESC_CNT - 1) -#define NUM_RX_BD (RX_DESC_CNT * NUM_RX_RINGS) -#define MAX_RX_BD (NUM_RX_BD - 1) -#define MAX_RX_AVAIL (MAX_RX_DESC_CNT * NUM_RX_RINGS - 2) -#define NEXT_RX_IDX(x) ((((x) & RX_DESC_MASK) == \ - (MAX_RX_DESC_CNT - 1)) ? (x) + 3 : (x) + 1) -#define RX_BD(x) ((x) & MAX_RX_BD) +/* DMAE command defines */ +#define DMAE_CMD_SRC_PCI 0 +#define DMAE_CMD_SRC_GRC DMAE_COMMAND_SRC -#define NUM_RCQ_RINGS (NUM_RX_RINGS * 2) -#define RCQ_DESC_CNT (BCM_PAGE_SIZE / sizeof(union eth_rx_cqe)) -#define MAX_RCQ_DESC_CNT (RCQ_DESC_CNT - 1) -#define NUM_RCQ_BD (RCQ_DESC_CNT * NUM_RCQ_RINGS) -#define MAX_RCQ_BD (NUM_RCQ_BD - 1) -#define MAX_RCQ_AVAIL (MAX_RCQ_DESC_CNT * NUM_RCQ_RINGS - 2) -#define NEXT_RCQ_IDX(x) ((((x) & MAX_RCQ_DESC_CNT) == \ - (MAX_RCQ_DESC_CNT - 1)) ? (x) + 2 : (x) + 1) -#define RCQ_BD(x) ((x) & MAX_RCQ_BD) +#define DMAE_CMD_DST_PCI (1 << DMAE_COMMAND_DST_SHIFT) +#define DMAE_CMD_DST_GRC (2 << DMAE_COMMAND_DST_SHIFT) +#define DMAE_CMD_C_DST_PCI 0 +#define DMAE_CMD_C_DST_GRC (1 << DMAE_COMMAND_C_DST_SHIFT) -/* used on a CID received from the HW */ -#define SW_CID(x) (le32_to_cpu(x) & \ - (COMMON_RAMROD_ETH_RX_CQE_CID >> 1)) -#define CQE_CMD(x) (le32_to_cpu(x) >> \ - COMMON_RAMROD_ETH_RX_CQE_CMD_ID_SHIFT) +#define DMAE_CMD_C_ENABLE DMAE_COMMAND_C_TYPE_ENABLE -#define BD_UNMAP_ADDR(bd) HILO_U64(le32_to_cpu((bd)->addr_hi), \ - le32_to_cpu((bd)->addr_lo)) -#define BD_UNMAP_LEN(bd) (le16_to_cpu((bd)->nbytes)) +#define DMAE_CMD_ENDIANITY_NO_SWAP (0 << DMAE_COMMAND_ENDIANITY_SHIFT) +#define DMAE_CMD_ENDIANITY_B_SWAP (1 << DMAE_COMMAND_ENDIANITY_SHIFT) +#define DMAE_CMD_ENDIANITY_DW_SWAP (2 << DMAE_COMMAND_ENDIANITY_SHIFT) +#define DMAE_CMD_ENDIANITY_B_DW_SWAP (3 << DMAE_COMMAND_ENDIANITY_SHIFT) +#define DMAE_CMD_PORT_0 0 +#define DMAE_CMD_PORT_1 DMAE_COMMAND_PORT -#define STROM_ASSERT_ARRAY_SIZE 50 +#define DMAE_CMD_SRC_RESET DMAE_COMMAND_SRC_RESET +#define DMAE_CMD_DST_RESET DMAE_COMMAND_DST_RESET +#define DMAE_CMD_E1HVN_SHIFT DMAE_COMMAND_E1HVN_SHIFT +#define DMAE_LEN32_RD_MAX 0x80 +#define DMAE_LEN32_WR_MAX 0x400 -#define MDIO_INDIRECT_REG_ADDR 0x1f -#define MDIO_SET_REG_BANK(bp, reg_bank) \ - bnx2x_mdio22_write(bp, MDIO_INDIRECT_REG_ADDR, reg_bank) +#define DMAE_COMP_VAL 0xe0d0d0ae -#define MDIO_ACCESS_TIMEOUT 1000 +#define MAX_DMAE_C_PER_PORT 8 +#define INIT_DMAE_C(bp) (BP_PORT(bp)*MAX_DMAE_C_PER_PORT + \ + BP_E1HVN(bp)) +#define PMF_DMAE_C(bp) (BP_PORT(bp)*MAX_DMAE_C_PER_PORT + \ + E1HVN_MAX) -/* must be used on a CID before placing it on a HW ring */ -#define HW_CID(bp, x) (x | (bp->port << 23)) +/* PCIE link and speed */ +#define PCICFG_LINK_WIDTH 0x1f00000 +#define PCICFG_LINK_WIDTH_SHIFT 20 +#define PCICFG_LINK_SPEED 0xf0000 +#define PCICFG_LINK_SPEED_SHIFT 16 -#define SP_DESC_CNT (BCM_PAGE_SIZE / sizeof(struct eth_spe)) -#define MAX_SP_DESC_CNT (SP_DESC_CNT - 1) -#define ATTN_NIG_FOR_FUNC (1L << 8) -#define ATTN_SW_TIMER_4_FUNC (1L << 9) -#define GPIO_2_FUNC (1L << 10) -#define GPIO_3_FUNC (1L << 11) -#define GPIO_4_FUNC (1L << 12) -#define ATTN_GENERAL_ATTN_1 (1L << 13) -#define ATTN_GENERAL_ATTN_2 (1L << 14) -#define ATTN_GENERAL_ATTN_3 (1L << 15) -#define ATTN_GENERAL_ATTN_4 (1L << 13) -#define ATTN_GENERAL_ATTN_5 (1L << 14) -#define ATTN_GENERAL_ATTN_6 (1L << 15) +#define BNX2X_NUM_STATS 39 +#define BNX2X_NUM_TESTS 8 -#define ATTN_HARD_WIRED_MASK 0xff00 -#define ATTENTION_ID 4 +#define BNX2X_MAC_LOOPBACK 0 +#define BNX2X_PHY_LOOPBACK 1 +#define BNX2X_MAC_LOOPBACK_FAILED 1 +#define BNX2X_PHY_LOOPBACK_FAILED 2 +#define BNX2X_LOOPBACK_FAILED (BNX2X_MAC_LOOPBACK_FAILED | \ + BNX2X_PHY_LOOPBACK_FAILED) -#define BNX2X_BTR 3 -#define MAX_SPQ_PENDING 8 +#define STROM_ASSERT_ARRAY_SIZE 50 -#define BNX2X_NUM_STATS 34 -#define BNX2X_NUM_TESTS 1 +/* must be used on a CID before placing it on a HW ring */ +#define HW_CID(bp, x) ((BP_PORT(bp) << 23) | (BP_E1HVN(bp) << 17) | x) +#define SP_DESC_CNT (BCM_PAGE_SIZE / sizeof(struct eth_spe)) +#define MAX_SP_DESC_CNT (SP_DESC_CNT - 1) -#define DPM_TRIGER_TYPE 0x40 -#define DOORBELL(bp, cid, val) \ - do { \ - writel((u32)val, (bp)->doorbells + (BCM_PAGE_SIZE * cid) + \ - DPM_TRIGER_TYPE); \ - } while (0) -/* PCIE link and speed */ -#define PCICFG_LINK_WIDTH 0x1f00000 -#define PCICFG_LINK_WIDTH_SHIFT 20 -#define PCICFG_LINK_SPEED 0xf0000 -#define PCICFG_LINK_SPEED_SHIFT 16 +#define BNX2X_BTR 3 +#define MAX_SPQ_PENDING 8 -#define BMAC_CONTROL_RX_ENABLE 2 -#define pbd_tcp_flags(skb) (ntohl(tcp_flag_word(tcp_hdr(skb)))>>16 & 0xff) +/* CMNG constants + derived from lab experiments, and not from system spec calculations !!! */ +#define DEF_MIN_RATE 100 +/* resolution of the rate shaping timer - 100 usec */ +#define RS_PERIODIC_TIMEOUT_USEC 100 +/* resolution of fairness algorithm in usecs - + coefficient for clauclating the actuall t fair */ +#define T_FAIR_COEF 10000000 +/* number of bytes in single QM arbitration cycle - + coeffiecnt for calculating the fairness timer */ +#define QM_ARB_BYTES 40000 +#define FAIR_MEM 2 -/* stuff added to make the code fit 80Col */ -#define TPA_TYPE_START ETH_FAST_PATH_RX_CQE_START_FLG -#define TPA_TYPE_END ETH_FAST_PATH_RX_CQE_END_FLG -#define TPA_TYPE(cqe) (cqe->fast_path_cqe.error_type_flags & \ - (TPA_TYPE_START | TPA_TYPE_END)) -#define BNX2X_RX_SUM_OK(cqe) \ - (!(cqe->fast_path_cqe.status_flags & \ - (ETH_FAST_PATH_RX_CQE_IP_XSUM_NO_VALIDATION_FLG | \ - ETH_FAST_PATH_RX_CQE_L4_XSUM_NO_VALIDATION_FLG))) +#define ATTN_NIG_FOR_FUNC (1L << 8) +#define ATTN_SW_TIMER_4_FUNC (1L << 9) +#define GPIO_2_FUNC (1L << 10) +#define GPIO_3_FUNC (1L << 11) +#define GPIO_4_FUNC (1L << 12) +#define ATTN_GENERAL_ATTN_1 (1L << 13) +#define ATTN_GENERAL_ATTN_2 (1L << 14) +#define ATTN_GENERAL_ATTN_3 (1L << 15) +#define ATTN_GENERAL_ATTN_4 (1L << 13) +#define ATTN_GENERAL_ATTN_5 (1L << 14) +#define ATTN_GENERAL_ATTN_6 (1L << 15) -#define BNX2X_RX_SUM_FIX(cqe) \ - ((le16_to_cpu(cqe->fast_path_cqe.pars_flags.flags) & \ - PARSING_FLAGS_OVER_ETHERNET_PROTOCOL) == \ - (1 << PARSING_FLAGS_OVER_ETHERNET_PROTOCOL_SHIFT)) +#define ATTN_HARD_WIRED_MASK 0xff00 +#define ATTENTION_ID 4 -#define MDIO_AN_CL73_OR_37_COMPLETE \ - (MDIO_GP_STATUS_TOP_AN_STATUS1_CL73_AUTONEG_COMPLETE | \ - MDIO_GP_STATUS_TOP_AN_STATUS1_CL37_AUTONEG_COMPLETE) - -#define GP_STATUS_PAUSE_RSOLUTION_TXSIDE \ - MDIO_GP_STATUS_TOP_AN_STATUS1_PAUSE_RSOLUTION_TXSIDE -#define GP_STATUS_PAUSE_RSOLUTION_RXSIDE \ - MDIO_GP_STATUS_TOP_AN_STATUS1_PAUSE_RSOLUTION_RXSIDE -#define GP_STATUS_SPEED_MASK \ - MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_MASK -#define GP_STATUS_10M MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_10M -#define GP_STATUS_100M MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_100M -#define GP_STATUS_1G MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_1G -#define GP_STATUS_2_5G MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_2_5G -#define GP_STATUS_5G MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_5G -#define GP_STATUS_6G MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_6G -#define GP_STATUS_10G_HIG \ - MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_10G_HIG -#define GP_STATUS_10G_CX4 \ - MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_10G_CX4 -#define GP_STATUS_12G_HIG \ - MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_12G_HIG -#define GP_STATUS_12_5G MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_12_5G -#define GP_STATUS_13G MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_13G -#define GP_STATUS_15G MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_15G -#define GP_STATUS_16G MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_16G -#define GP_STATUS_1G_KX MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_1G_KX -#define GP_STATUS_10G_KX4 \ - MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_10G_KX4 - -#define LINK_10THD LINK_STATUS_SPEED_AND_DUPLEX_10THD -#define LINK_10TFD LINK_STATUS_SPEED_AND_DUPLEX_10TFD -#define LINK_100TXHD LINK_STATUS_SPEED_AND_DUPLEX_100TXHD -#define LINK_100T4 LINK_STATUS_SPEED_AND_DUPLEX_100T4 -#define LINK_100TXFD LINK_STATUS_SPEED_AND_DUPLEX_100TXFD -#define LINK_1000THD LINK_STATUS_SPEED_AND_DUPLEX_1000THD -#define LINK_1000TFD LINK_STATUS_SPEED_AND_DUPLEX_1000TFD -#define LINK_1000XFD LINK_STATUS_SPEED_AND_DUPLEX_1000XFD -#define LINK_2500THD LINK_STATUS_SPEED_AND_DUPLEX_2500THD -#define LINK_2500TFD LINK_STATUS_SPEED_AND_DUPLEX_2500TFD -#define LINK_2500XFD LINK_STATUS_SPEED_AND_DUPLEX_2500XFD -#define LINK_10GTFD LINK_STATUS_SPEED_AND_DUPLEX_10GTFD -#define LINK_10GXFD LINK_STATUS_SPEED_AND_DUPLEX_10GXFD -#define LINK_12GTFD LINK_STATUS_SPEED_AND_DUPLEX_12GTFD -#define LINK_12GXFD LINK_STATUS_SPEED_AND_DUPLEX_12GXFD -#define LINK_12_5GTFD LINK_STATUS_SPEED_AND_DUPLEX_12_5GTFD -#define LINK_12_5GXFD LINK_STATUS_SPEED_AND_DUPLEX_12_5GXFD -#define LINK_13GTFD LINK_STATUS_SPEED_AND_DUPLEX_13GTFD -#define LINK_13GXFD LINK_STATUS_SPEED_AND_DUPLEX_13GXFD -#define LINK_15GTFD LINK_STATUS_SPEED_AND_DUPLEX_15GTFD -#define LINK_15GXFD LINK_STATUS_SPEED_AND_DUPLEX_15GXFD -#define LINK_16GTFD LINK_STATUS_SPEED_AND_DUPLEX_16GTFD -#define LINK_16GXFD LINK_STATUS_SPEED_AND_DUPLEX_16GXFD - -#define NIG_STATUS_XGXS0_LINK10G \ - NIG_STATUS_INTERRUPT_PORT0_REG_STATUS_XGXS0_LINK10G -#define NIG_STATUS_XGXS0_LINK_STATUS \ - NIG_STATUS_INTERRUPT_PORT0_REG_STATUS_XGXS0_LINK_STATUS -#define NIG_STATUS_XGXS0_LINK_STATUS_SIZE \ - NIG_STATUS_INTERRUPT_PORT0_REG_STATUS_XGXS0_LINK_STATUS_SIZE -#define NIG_STATUS_SERDES0_LINK_STATUS \ - NIG_STATUS_INTERRUPT_PORT0_REG_STATUS_SERDES0_LINK_STATUS -#define NIG_MASK_MI_INT \ - NIG_MASK_INTERRUPT_PORT0_REG_MASK_EMAC0_MISC_MI_INT -#define NIG_MASK_XGXS0_LINK10G \ - NIG_MASK_INTERRUPT_PORT0_REG_MASK_XGXS0_LINK10G -#define NIG_MASK_XGXS0_LINK_STATUS \ - NIG_MASK_INTERRUPT_PORT0_REG_MASK_XGXS0_LINK_STATUS -#define NIG_MASK_SERDES0_LINK_STATUS \ - NIG_MASK_INTERRUPT_PORT0_REG_MASK_SERDES0_LINK_STATUS - -#define XGXS_RESET_BITS \ - (MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_XGXS0_RSTB_HW | \ - MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_XGXS0_IDDQ | \ - MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_XGXS0_PWRDWN | \ - MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_XGXS0_PWRDWN_SD | \ - MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_XGXS0_TXD_FIFO_RSTB) - -#define SERDES_RESET_BITS \ - (MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_SERDES0_RSTB_HW | \ - MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_SERDES0_IDDQ | \ - MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_SERDES0_PWRDWN | \ - MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_SERDES0_PWRDWN_SD) +/* stuff added to make the code fit 80Col */ +#define BNX2X_PMF_LINK_ASSERT \ + GENERAL_ATTEN_OFFSET(LINK_SYNC_ATTENTION_BIT_FUNC_0 + BP_FUNC(bp)) #define BNX2X_MC_ASSERT_BITS \ (GENERAL_ATTEN_OFFSET(TSTORM_FATAL_ASSERT_ATTENTION_BIT) | \ @@ -987,12 +1048,20 @@ struct bnx2x { #define BNX2X_DOORQ_ASSERT \ AEU_INPUTS_ATTN_BITS_DOORBELLQ_HW_INTERRUPT +#define BNX2X_GRC_TIMEOUT GENERAL_ATTEN_OFFSET(LATCHED_ATTN_TIMEOUT_GRC) +#define BNX2X_GRC_RSV (GENERAL_ATTEN_OFFSET(LATCHED_ATTN_RBCR) | \ + GENERAL_ATTEN_OFFSET(LATCHED_ATTN_RBCT) | \ + GENERAL_ATTEN_OFFSET(LATCHED_ATTN_RBCN) | \ + GENERAL_ATTEN_OFFSET(LATCHED_ATTN_RBCU) | \ + GENERAL_ATTEN_OFFSET(LATCHED_ATTN_RBCP) | \ + GENERAL_ATTEN_OFFSET(LATCHED_ATTN_RSVD_GRC)) + #define HW_INTERRUT_ASSERT_SET_0 \ (AEU_INPUTS_ATTN_BITS_TSDM_HW_INTERRUPT | \ AEU_INPUTS_ATTN_BITS_TCM_HW_INTERRUPT | \ AEU_INPUTS_ATTN_BITS_TSEMI_HW_INTERRUPT | \ AEU_INPUTS_ATTN_BITS_PBF_HW_INTERRUPT) -#define HW_PRTY_ASSERT_SET_0 (AEU_INPUTS_ATTN_BITS_BRB_PARITY_ERROR | \ +#define HW_PRTY_ASSERT_SET_0 (AEU_INPUTS_ATTN_BITS_BRB_PARITY_ERROR | \ AEU_INPUTS_ATTN_BITS_PARSER_PARITY_ERROR | \ AEU_INPUTS_ATTN_BITS_TSDM_PARITY_ERROR | \ AEU_INPUTS_ATTN_BITS_SEARCHER_PARITY_ERROR |\ @@ -1009,7 +1078,7 @@ struct bnx2x { AEU_INPUTS_ATTN_BITS_UPB_HW_INTERRUPT | \ AEU_INPUTS_ATTN_BITS_CSDM_HW_INTERRUPT | \ AEU_INPUTS_ATTN_BITS_CCM_HW_INTERRUPT) -#define HW_PRTY_ASSERT_SET_1 (AEU_INPUTS_ATTN_BITS_PBCLIENT_PARITY_ERROR |\ +#define HW_PRTY_ASSERT_SET_1 (AEU_INPUTS_ATTN_BITS_PBCLIENT_PARITY_ERROR |\ AEU_INPUTS_ATTN_BITS_QM_PARITY_ERROR | \ AEU_INPUTS_ATTN_BITS_XSDM_PARITY_ERROR | \ AEU_INPUTS_ATTN_BITS_XSEMI_PARITY_ERROR | \ @@ -1026,7 +1095,7 @@ struct bnx2x { AEU_INPUTS_ATTN_BITS_DMAE_HW_INTERRUPT | \ AEU_INPUTS_ATTN_BITS_PXPPCICLOCKCLIENT_HW_INTERRUPT |\ AEU_INPUTS_ATTN_BITS_MISC_HW_INTERRUPT) -#define HW_PRTY_ASSERT_SET_2 (AEU_INPUTS_ATTN_BITS_CSEMI_PARITY_ERROR | \ +#define HW_PRTY_ASSERT_SET_2 (AEU_INPUTS_ATTN_BITS_CSEMI_PARITY_ERROR | \ AEU_INPUTS_ATTN_BITS_PXP_PARITY_ERROR | \ AEU_INPUTS_ATTN_BITS_PXPPCICLOCKCLIENT_PARITY_ERROR |\ AEU_INPUTS_ATTN_BITS_CFC_PARITY_ERROR | \ @@ -1035,42 +1104,44 @@ struct bnx2x { AEU_INPUTS_ATTN_BITS_MISC_PARITY_ERROR) -#define ETH_RX_ERROR_FALGS (ETH_FAST_PATH_RX_CQE_PHY_DECODE_ERR_FLG | \ - ETH_FAST_PATH_RX_CQE_IP_BAD_XSUM_FLG | \ - ETH_FAST_PATH_RX_CQE_L4_BAD_XSUM_FLG) - - #define MULTI_FLAGS \ - (TSTORM_ETH_FUNCTION_COMMON_CONFIG_RSS_IPV4_CAPABILITY | \ - TSTORM_ETH_FUNCTION_COMMON_CONFIG_RSS_IPV4_TCP_CAPABILITY | \ - TSTORM_ETH_FUNCTION_COMMON_CONFIG_RSS_IPV6_CAPABILITY | \ - TSTORM_ETH_FUNCTION_COMMON_CONFIG_RSS_IPV6_TCP_CAPABILITY | \ - TSTORM_ETH_FUNCTION_COMMON_CONFIG_RSS_ENABLE) - -#define MULTI_MASK 0x7f + (TSTORM_ETH_FUNCTION_COMMON_CONFIG_RSS_IPV4_CAPABILITY | \ + TSTORM_ETH_FUNCTION_COMMON_CONFIG_RSS_IPV4_TCP_CAPABILITY | \ + TSTORM_ETH_FUNCTION_COMMON_CONFIG_RSS_IPV6_CAPABILITY | \ + TSTORM_ETH_FUNCTION_COMMON_CONFIG_RSS_IPV6_TCP_CAPABILITY | \ + TSTORM_ETH_FUNCTION_COMMON_CONFIG_RSS_ENABLE) +#define MULTI_MASK 0x7f -#define U_SB_ETH_RX_CQ_INDEX HC_INDEX_U_ETH_RX_CQ_CONS -#define C_SB_ETH_TX_CQ_INDEX HC_INDEX_C_ETH_TX_CQ_CONS -#define C_DEF_SB_SP_INDEX HC_INDEX_DEF_C_ETH_SLOW_PATH -#define BNX2X_RX_SB_INDEX \ - &fp->status_blk->u_status_block.index_values[U_SB_ETH_RX_CQ_INDEX] +#define DEF_USB_FUNC_OFF (2 + 2*HC_USTORM_DEF_SB_NUM_INDICES) +#define DEF_CSB_FUNC_OFF (2 + 2*HC_CSTORM_DEF_SB_NUM_INDICES) +#define DEF_XSB_FUNC_OFF (2 + 2*HC_XSTORM_DEF_SB_NUM_INDICES) +#define DEF_TSB_FUNC_OFF (2 + 2*HC_TSTORM_DEF_SB_NUM_INDICES) -#define BNX2X_TX_SB_INDEX \ - &fp->status_blk->c_status_block.index_values[C_SB_ETH_TX_CQ_INDEX] +#define C_DEF_SB_SP_INDEX HC_INDEX_DEF_C_ETH_SLOW_PATH #define BNX2X_SP_DSB_INDEX \ -&bp->def_status_blk->c_def_status_block.index_values[C_DEF_SB_SP_INDEX] +(&bp->def_status_blk->c_def_status_block.index_values[C_DEF_SB_SP_INDEX]) #define CAM_IS_INVALID(x) \ (x.target_table_entry.flags == TSTORM_CAM_TARGET_TABLE_ENTRY_ACTION_TYPE) #define CAM_INVALIDATE(x) \ -x.target_table_entry.flags = TSTORM_CAM_TARGET_TABLE_ENTRY_ACTION_TYPE + (x.target_table_entry.flags = TSTORM_CAM_TARGET_TABLE_ENTRY_ACTION_TYPE) +/* Number of u32 elements in MC hash array */ +#define MC_HASH_SIZE 8 +#define MC_HASH_OFFSET(bp, i) (BAR_TSTRORM_INTMEM + \ + TSTORM_APPROXIMATE_MATCH_MULTICAST_FILTERING_OFFSET(BP_FUNC(bp)) + i*4) + + +#ifndef PXP2_REG_PXP2_INT_STS +#define PXP2_REG_PXP2_INT_STS PXP2_REG_PXP2_INT_STS_0 +#endif + /* MISC_REG_RESET_REG - this is here for the hsi to work don't touch */ #endif /* bnx2x.h */ diff --git a/drivers/net/bnx2x_fw_defs.h b/drivers/net/bnx2x_fw_defs.h index 3b968904ca65..e3da7f69d27b 100644 --- a/drivers/net/bnx2x_fw_defs.h +++ b/drivers/net/bnx2x_fw_defs.h @@ -8,191 +8,390 @@ */ -#define CSTORM_DEF_SB_HC_DISABLE_OFFSET(port, index)\ - (0x1922 + (port * 0x40) + (index * 0x4)) -#define CSTORM_DEF_SB_HOST_SB_ADDR_OFFSET(port)\ - (0x1900 + (port * 0x40)) -#define CSTORM_HC_BTR_OFFSET(port)\ - (0x1984 + (port * 0xc0)) -#define CSTORM_SB_HC_DISABLE_OFFSET(port, cpu_id, index)\ - (0x141a + (port * 0x280) + (cpu_id * 0x28) + (index * 0x4)) -#define CSTORM_SB_HC_TIMEOUT_OFFSET(port, cpu_id, index)\ - (0x1418 + (port * 0x280) + (cpu_id * 0x28) + (index * 0x4)) -#define CSTORM_SB_HOST_SB_ADDR_OFFSET(port, cpu_id)\ - (0x1400 + (port * 0x280) + (cpu_id * 0x28)) -#define CSTORM_STATS_FLAGS_OFFSET(port) (0x5108 + (port * 0x8)) -#define TSTORM_CLIENT_CONFIG_OFFSET(port, client_id)\ - (0x1510 + (port * 0x240) + (client_id * 0x20)) -#define TSTORM_DEF_SB_HC_DISABLE_OFFSET(port, index)\ - (0x138a + (port * 0x28) + (index * 0x4)) -#define TSTORM_DEF_SB_HOST_SB_ADDR_OFFSET(port)\ - (0x1370 + (port * 0x28)) -#define TSTORM_ETH_STATS_QUERY_ADDR_OFFSET(port)\ - (0x4b70 + (port * 0x8)) -#define TSTORM_FUNCTION_COMMON_CONFIG_OFFSET(function)\ - (0x1418 + (function * 0x30)) -#define TSTORM_HC_BTR_OFFSET(port)\ - (0x13c4 + (port * 0x18)) -#define TSTORM_INDIRECTION_TABLE_OFFSET(port)\ - (0x22c8 + (port * 0x80)) -#define TSTORM_INDIRECTION_TABLE_SIZE 0x80 -#define TSTORM_MAC_FILTER_CONFIG_OFFSET(port)\ - (0x1420 + (port * 0x30)) -#define TSTORM_RCQ_PROD_OFFSET(port, client_id)\ - (0x1508 + (port * 0x240) + (client_id * 0x20)) -#define TSTORM_STATS_FLAGS_OFFSET(port) (0x4b90 + (port * 0x8)) -#define USTORM_DEF_SB_HC_DISABLE_OFFSET(port, index)\ - (0x191a + (port * 0x28) + (index * 0x4)) -#define USTORM_DEF_SB_HOST_SB_ADDR_OFFSET(port)\ - (0x1900 + (port * 0x28)) -#define USTORM_HC_BTR_OFFSET(port)\ - (0x1954 + (port * 0xb8)) -#define USTORM_MEM_WORKAROUND_ADDRESS_OFFSET(port)\ - (0x5408 + (port * 0x8)) -#define USTORM_SB_HC_DISABLE_OFFSET(port, cpu_id, index)\ - (0x141a + (port * 0x280) + (cpu_id * 0x28) + (index * 0x4)) -#define USTORM_SB_HC_TIMEOUT_OFFSET(port, cpu_id, index)\ - (0x1418 + (port * 0x280) + (cpu_id * 0x28) + (index * 0x4)) -#define USTORM_SB_HOST_SB_ADDR_OFFSET(port, cpu_id)\ - (0x1400 + (port * 0x280) + (cpu_id * 0x28)) -#define XSTORM_ASSERT_LIST_INDEX_OFFSET 0x1000 -#define XSTORM_ASSERT_LIST_OFFSET(idx) (0x1020 + (idx * 0x10)) -#define XSTORM_DEF_SB_HC_DISABLE_OFFSET(port, index)\ - (0x141a + (port * 0x28) + (index * 0x4)) -#define XSTORM_DEF_SB_HOST_SB_ADDR_OFFSET(port)\ - (0x1400 + (port * 0x28)) -#define XSTORM_ETH_STATS_QUERY_ADDR_OFFSET(port)\ - (0x5408 + (port * 0x8)) -#define XSTORM_HC_BTR_OFFSET(port)\ - (0x1454 + (port * 0x18)) -#define XSTORM_SPQ_PAGE_BASE_OFFSET(port)\ - (0x5328 + (port * 0x18)) -#define XSTORM_SPQ_PROD_OFFSET(port)\ - (0x5330 + (port * 0x18)) -#define XSTORM_STATS_FLAGS_OFFSET(port) (0x53f8 + (port * 0x8)) +#define CSTORM_ASSERT_LIST_INDEX_OFFSET \ + (IS_E1H_OFFSET? 0x7000 : 0x1000) +#define CSTORM_ASSERT_LIST_OFFSET(idx) \ + (IS_E1H_OFFSET? (0x7020 + (idx * 0x10)) : (0x1020 + (idx * 0x10))) +#define CSTORM_DEF_SB_HC_DISABLE_OFFSET(function, index) \ + (IS_E1H_OFFSET? (0x8522 + ((function>>1) * 0x40) + ((function&1) \ + * 0x100) + (index * 0x4)) : (0x1922 + (function * 0x40) + (index \ + * 0x4))) +#define CSTORM_DEF_SB_HOST_SB_ADDR_OFFSET(function) \ + (IS_E1H_OFFSET? (0x8500 + ((function>>1) * 0x40) + ((function&1) \ + * 0x100)) : (0x1900 + (function * 0x40))) +#define CSTORM_DEF_SB_HOST_STATUS_BLOCK_OFFSET(function) \ + (IS_E1H_OFFSET? (0x8508 + ((function>>1) * 0x40) + ((function&1) \ + * 0x100)) : (0x1908 + (function * 0x40))) +#define CSTORM_FUNCTION_MODE_OFFSET \ + (IS_E1H_OFFSET? 0x11e8 : 0xffffffff) +#define CSTORM_HC_BTR_OFFSET(port) \ + (IS_E1H_OFFSET? (0x8704 + (port * 0xf0)) : (0x1984 + (port * 0xc0))) +#define CSTORM_SB_HC_DISABLE_OFFSET(port, cpu_id, index) \ + (IS_E1H_OFFSET? (0x801a + (port * 0x280) + (cpu_id * 0x28) + \ + (index * 0x4)) : (0x141a + (port * 0x280) + (cpu_id * 0x28) + \ + (index * 0x4))) +#define CSTORM_SB_HC_TIMEOUT_OFFSET(port, cpu_id, index) \ + (IS_E1H_OFFSET? (0x8018 + (port * 0x280) + (cpu_id * 0x28) + \ + (index * 0x4)) : (0x1418 + (port * 0x280) + (cpu_id * 0x28) + \ + (index * 0x4))) +#define CSTORM_SB_HOST_SB_ADDR_OFFSET(port, cpu_id) \ + (IS_E1H_OFFSET? (0x8000 + (port * 0x280) + (cpu_id * 0x28)) : \ + (0x1400 + (port * 0x280) + (cpu_id * 0x28))) +#define CSTORM_SB_HOST_STATUS_BLOCK_OFFSET(port, cpu_id) \ + (IS_E1H_OFFSET? (0x8008 + (port * 0x280) + (cpu_id * 0x28)) : \ + (0x1408 + (port * 0x280) + (cpu_id * 0x28))) +#define CSTORM_STATS_FLAGS_OFFSET(function) \ + (IS_E1H_OFFSET? (0x1108 + (function * 0x8)) : (0x5108 + \ + (function * 0x8))) +#define TSTORM_APPROXIMATE_MATCH_MULTICAST_FILTERING_OFFSET(function) \ + (IS_E1H_OFFSET? (0x31c0 + (function * 0x20)) : 0xffffffff) +#define TSTORM_ASSERT_LIST_INDEX_OFFSET \ + (IS_E1H_OFFSET? 0xa000 : 0x1000) +#define TSTORM_ASSERT_LIST_OFFSET(idx) \ + (IS_E1H_OFFSET? (0xa020 + (idx * 0x10)) : (0x1020 + (idx * 0x10))) +#define TSTORM_CLIENT_CONFIG_OFFSET(port, client_id) \ + (IS_E1H_OFFSET? (0x3358 + (port * 0x3e8) + (client_id * 0x28)) : \ + (0x9c8 + (port * 0x2f8) + (client_id * 0x28))) +#define TSTORM_DEF_SB_HC_DISABLE_OFFSET(function, index) \ + (IS_E1H_OFFSET? (0xb01a + ((function>>1) * 0x28) + ((function&1) \ + * 0xa0) + (index * 0x4)) : (0x141a + (function * 0x28) + (index * \ + 0x4))) +#define TSTORM_DEF_SB_HOST_SB_ADDR_OFFSET(function) \ + (IS_E1H_OFFSET? (0xb000 + ((function>>1) * 0x28) + ((function&1) \ + * 0xa0)) : (0x1400 + (function * 0x28))) +#define TSTORM_DEF_SB_HOST_STATUS_BLOCK_OFFSET(function) \ + (IS_E1H_OFFSET? (0xb008 + ((function>>1) * 0x28) + ((function&1) \ + * 0xa0)) : (0x1408 + (function * 0x28))) +#define TSTORM_ETH_STATS_QUERY_ADDR_OFFSET(function) \ + (IS_E1H_OFFSET? (0x2b80 + (function * 0x8)) : (0x4b68 + \ + (function * 0x8))) +#define TSTORM_FUNCTION_COMMON_CONFIG_OFFSET(function) \ + (IS_E1H_OFFSET? (0x3000 + (function * 0x38)) : (0x1500 + \ + (function * 0x38))) +#define TSTORM_FUNCTION_MODE_OFFSET \ + (IS_E1H_OFFSET? 0x1ad0 : 0xffffffff) +#define TSTORM_HC_BTR_OFFSET(port) \ + (IS_E1H_OFFSET? (0xb144 + (port * 0x30)) : (0x1454 + (port * 0x18))) +#define TSTORM_INDIRECTION_TABLE_OFFSET(function) \ + (IS_E1H_OFFSET? (0x12c8 + (function * 0x80)) : (0x22c8 + \ + (function * 0x80))) +#define TSTORM_INDIRECTION_TABLE_SIZE 0x80 +#define TSTORM_MAC_FILTER_CONFIG_OFFSET(function) \ + (IS_E1H_OFFSET? (0x3008 + (function * 0x38)) : (0x1508 + \ + (function * 0x38))) +#define TSTORM_RX_PRODS_OFFSET(port, client_id) \ + (IS_E1H_OFFSET? (0x3350 + (port * 0x3e8) + (client_id * 0x28)) : \ + (0x9c0 + (port * 0x2f8) + (client_id * 0x28))) +#define TSTORM_STATS_FLAGS_OFFSET(function) \ + (IS_E1H_OFFSET? (0x2c00 + (function * 0x8)) : (0x4b88 + \ + (function * 0x8))) +#define TSTORM_TPA_EXIST_OFFSET (IS_E1H_OFFSET? 0x3b30 : 0x1c20) +#define USTORM_AGG_DATA_OFFSET (IS_E1H_OFFSET? 0xa040 : 0x2c10) +#define USTORM_AGG_DATA_SIZE (IS_E1H_OFFSET? 0x2440 : 0x1200) +#define USTORM_ASSERT_LIST_INDEX_OFFSET \ + (IS_E1H_OFFSET? 0x8000 : 0x1000) +#define USTORM_ASSERT_LIST_OFFSET(idx) \ + (IS_E1H_OFFSET? (0x8020 + (idx * 0x10)) : (0x1020 + (idx * 0x10))) +#define USTORM_CQE_PAGE_BASE_OFFSET(port, clientId) \ + (IS_E1H_OFFSET? (0x3298 + (port * 0x258) + (clientId * 0x18)) : \ + (0x5450 + (port * 0x1c8) + (clientId * 0x18))) +#define USTORM_DEF_SB_HC_DISABLE_OFFSET(function, index) \ + (IS_E1H_OFFSET? (0x951a + ((function>>1) * 0x28) + ((function&1) \ + * 0xa0) + (index * 0x4)) : (0x191a + (function * 0x28) + (index * \ + 0x4))) +#define USTORM_DEF_SB_HOST_SB_ADDR_OFFSET(function) \ + (IS_E1H_OFFSET? (0x9500 + ((function>>1) * 0x28) + ((function&1) \ + * 0xa0)) : (0x1900 + (function * 0x28))) +#define USTORM_DEF_SB_HOST_STATUS_BLOCK_OFFSET(function) \ + (IS_E1H_OFFSET? (0x9508 + ((function>>1) * 0x28) + ((function&1) \ + * 0xa0)) : (0x1908 + (function * 0x28))) +#define USTORM_FUNCTION_MODE_OFFSET \ + (IS_E1H_OFFSET? 0x2448 : 0xffffffff) +#define USTORM_HC_BTR_OFFSET(port) \ + (IS_E1H_OFFSET? (0x9644 + (port * 0xd0)) : (0x1954 + (port * 0xb8))) +#define USTORM_MAX_AGG_SIZE_OFFSET(port, clientId) \ + (IS_E1H_OFFSET? (0x3290 + (port * 0x258) + (clientId * 0x18)) : \ + (0x5448 + (port * 0x1c8) + (clientId * 0x18))) +#define USTORM_MEM_WORKAROUND_ADDRESS_OFFSET(function) \ + (IS_E1H_OFFSET? (0x2408 + (function * 0x8)) : (0x5408 + \ + (function * 0x8))) +#define USTORM_SB_HC_DISABLE_OFFSET(port, cpu_id, index) \ + (IS_E1H_OFFSET? (0x901a + (port * 0x280) + (cpu_id * 0x28) + \ + (index * 0x4)) : (0x141a + (port * 0x280) + (cpu_id * 0x28) + \ + (index * 0x4))) +#define USTORM_SB_HC_TIMEOUT_OFFSET(port, cpu_id, index) \ + (IS_E1H_OFFSET? (0x9018 + (port * 0x280) + (cpu_id * 0x28) + \ + (index * 0x4)) : (0x1418 + (port * 0x280) + (cpu_id * 0x28) + \ + (index * 0x4))) +#define USTORM_SB_HOST_SB_ADDR_OFFSET(port, cpu_id) \ + (IS_E1H_OFFSET? (0x9000 + (port * 0x280) + (cpu_id * 0x28)) : \ + (0x1400 + (port * 0x280) + (cpu_id * 0x28))) +#define USTORM_SB_HOST_STATUS_BLOCK_OFFSET(port, cpu_id) \ + (IS_E1H_OFFSET? (0x9008 + (port * 0x280) + (cpu_id * 0x28)) : \ + (0x1408 + (port * 0x280) + (cpu_id * 0x28))) +#define XSTORM_ASSERT_LIST_INDEX_OFFSET \ + (IS_E1H_OFFSET? 0x9000 : 0x1000) +#define XSTORM_ASSERT_LIST_OFFSET(idx) \ + (IS_E1H_OFFSET? (0x9020 + (idx * 0x10)) : (0x1020 + (idx * 0x10))) +#define XSTORM_CMNG_PER_PORT_VARS_OFFSET(port) \ + (IS_E1H_OFFSET? (0x24a8 + (port * 0x40)) : (0x3ba0 + (port * 0x40))) +#define XSTORM_DEF_SB_HC_DISABLE_OFFSET(function, index) \ + (IS_E1H_OFFSET? (0xa01a + ((function>>1) * 0x28) + ((function&1) \ + * 0xa0) + (index * 0x4)) : (0x141a + (function * 0x28) + (index * \ + 0x4))) +#define XSTORM_DEF_SB_HOST_SB_ADDR_OFFSET(function) \ + (IS_E1H_OFFSET? (0xa000 + ((function>>1) * 0x28) + ((function&1) \ + * 0xa0)) : (0x1400 + (function * 0x28))) +#define XSTORM_DEF_SB_HOST_STATUS_BLOCK_OFFSET(function) \ + (IS_E1H_OFFSET? (0xa008 + ((function>>1) * 0x28) + ((function&1) \ + * 0xa0)) : (0x1408 + (function * 0x28))) +#define XSTORM_E1HOV_OFFSET(function) \ + (IS_E1H_OFFSET? (0x2ab8 + (function * 0x2)) : 0xffffffff) +#define XSTORM_ETH_STATS_QUERY_ADDR_OFFSET(function) \ + (IS_E1H_OFFSET? (0x2418 + (function * 0x8)) : (0x3b70 + \ + (function * 0x8))) +#define XSTORM_FAIRNESS_PER_VN_VARS_OFFSET(function) \ + (IS_E1H_OFFSET? (0x2568 + (function * 0x70)) : (0x3c60 + \ + (function * 0x70))) +#define XSTORM_FUNCTION_MODE_OFFSET \ + (IS_E1H_OFFSET? 0x2ac8 : 0xffffffff) +#define XSTORM_HC_BTR_OFFSET(port) \ + (IS_E1H_OFFSET? (0xa144 + (port * 0x30)) : (0x1454 + (port * 0x18))) +#define XSTORM_RATE_SHAPING_PER_VN_VARS_OFFSET(function) \ + (IS_E1H_OFFSET? (0x2528 + (function * 0x70)) : (0x3c20 + \ + (function * 0x70))) +#define XSTORM_SPQ_PAGE_BASE_OFFSET(function) \ + (IS_E1H_OFFSET? (0x2000 + (function * 0x10)) : (0x3328 + \ + (function * 0x10))) +#define XSTORM_SPQ_PROD_OFFSET(function) \ + (IS_E1H_OFFSET? (0x2008 + (function * 0x10)) : (0x3330 + \ + (function * 0x10))) +#define XSTORM_STATS_FLAGS_OFFSET(function) \ + (IS_E1H_OFFSET? (0x23d8 + (function * 0x8)) : (0x3b60 + \ + (function * 0x8))) #define COMMON_ASM_INVALID_ASSERT_OPCODE 0x0 /** * This file defines HSI constatnts for the ETH flow */ - -/* hash types */ -#define DEFAULT_HASH_TYPE 0 -#define IPV4_HASH_TYPE 1 -#define TCP_IPV4_HASH_TYPE 2 -#define IPV6_HASH_TYPE 3 -#define TCP_IPV6_HASH_TYPE 4 +#ifdef _EVEREST_MICROCODE +#include "microcode_constants.h" +#include "eth_rx_bd.h" +#include "eth_tx_bd.h" +#include "eth_rx_cqe.h" +#include "eth_rx_sge.h" +#include "eth_rx_cqe_next_page.h" +#endif + +/* RSS hash types */ +#define DEFAULT_HASH_TYPE 0 +#define IPV4_HASH_TYPE 1 +#define TCP_IPV4_HASH_TYPE 2 +#define IPV6_HASH_TYPE 3 +#define TCP_IPV6_HASH_TYPE 4 + +/* Ethernet Ring parmaters */ +#define X_ETH_LOCAL_RING_SIZE 13 +#define FIRST_BD_IN_PKT 0 +#define PARSE_BD_INDEX 1 +#define NUM_OF_ETH_BDS_IN_PAGE \ + ((PAGE_SIZE) / (STRUCT_SIZE(eth_tx_bd)/8)) + + +/* Rx ring params */ +#define U_ETH_LOCAL_BD_RING_SIZE (16) +#define U_ETH_LOCAL_SGE_RING_SIZE (12) +#define U_ETH_SGL_SIZE (8) + + +#define U_ETH_BDS_PER_PAGE_MASK \ + ((PAGE_SIZE/(STRUCT_SIZE(eth_rx_bd)/8))-1) +#define U_ETH_CQE_PER_PAGE_MASK \ + ((PAGE_SIZE/(STRUCT_SIZE(eth_rx_cqe)/8))-1) +#define U_ETH_SGES_PER_PAGE_MASK \ + ((PAGE_SIZE/(STRUCT_SIZE(eth_rx_sge)/8))-1) + +#define U_ETH_SGES_PER_PAGE_INVERSE_MASK \ + (0xFFFF - ((PAGE_SIZE/((STRUCT_SIZE(eth_rx_sge))/8))-1)) + + +#define TU_ETH_CQES_PER_PAGE \ + (PAGE_SIZE/(STRUCT_SIZE(eth_rx_cqe_next_page)/8)) +#define U_ETH_BDS_PER_PAGE (PAGE_SIZE/(STRUCT_SIZE(eth_rx_bd)/8)) +#define U_ETH_SGES_PER_PAGE (PAGE_SIZE/(STRUCT_SIZE(eth_rx_sge)/8)) + +#define U_ETH_UNDEFINED_Q 0xFF /* values of command IDs in the ramrod message */ -#define RAMROD_CMD_ID_ETH_PORT_SETUP (80) -#define RAMROD_CMD_ID_ETH_CLIENT_SETUP (85) -#define RAMROD_CMD_ID_ETH_STAT_QUERY (90) -#define RAMROD_CMD_ID_ETH_UPDATE (100) -#define RAMROD_CMD_ID_ETH_HALT (105) -#define RAMROD_CMD_ID_ETH_SET_MAC (110) -#define RAMROD_CMD_ID_ETH_CFC_DEL (115) -#define RAMROD_CMD_ID_ETH_PORT_DEL (120) -#define RAMROD_CMD_ID_ETH_FORWARD_SETUP (125) +#define RAMROD_CMD_ID_ETH_PORT_SETUP (80) +#define RAMROD_CMD_ID_ETH_CLIENT_SETUP (85) +#define RAMROD_CMD_ID_ETH_STAT_QUERY (90) +#define RAMROD_CMD_ID_ETH_UPDATE (100) +#define RAMROD_CMD_ID_ETH_HALT (105) +#define RAMROD_CMD_ID_ETH_SET_MAC (110) +#define RAMROD_CMD_ID_ETH_CFC_DEL (115) +#define RAMROD_CMD_ID_ETH_PORT_DEL (120) +#define RAMROD_CMD_ID_ETH_FORWARD_SETUP (125) /* command values for set mac command */ -#define T_ETH_MAC_COMMAND_SET 0 -#define T_ETH_MAC_COMMAND_INVALIDATE 1 +#define T_ETH_MAC_COMMAND_SET 0 +#define T_ETH_MAC_COMMAND_INVALIDATE 1 + +#define T_ETH_INDIRECTION_TABLE_SIZE 128 -#define T_ETH_INDIRECTION_TABLE_SIZE 128 +/*The CRC32 seed, that is used for the hash(reduction) multicast address */ +#define T_ETH_CRC32_HASH_SEED 0x00000000 /* Maximal L2 clients supported */ -#define ETH_MAX_RX_CLIENTS (18) +#define ETH_MAX_RX_CLIENTS_E1 19 +#define ETH_MAX_RX_CLIENTS_E1H 25 + +/* Maximal aggregation queues supported */ +#define ETH_MAX_AGGREGATION_QUEUES_E1 (32) +#define ETH_MAX_AGGREGATION_QUEUES_E1H (64) + /** * This file defines HSI constatnts common to all microcode flows */ /* Connection types */ -#define ETH_CONNECTION_TYPE 0 +#define ETH_CONNECTION_TYPE 0 +#define TOE_CONNECTION_TYPE 1 +#define RDMA_CONNECTION_TYPE 2 +#define ISCSI_CONNECTION_TYPE 3 +#define FCOE_CONNECTION_TYPE 4 +#define RESERVED_CONNECTION_TYPE_0 5 +#define RESERVED_CONNECTION_TYPE_1 6 +#define RESERVED_CONNECTION_TYPE_2 7 + -#define PROTOCOL_STATE_BIT_OFFSET 6 +#define PROTOCOL_STATE_BIT_OFFSET 6 -#define ETH_STATE (ETH_CONNECTION_TYPE << PROTOCOL_STATE_BIT_OFFSET) +#define ETH_STATE (ETH_CONNECTION_TYPE << PROTOCOL_STATE_BIT_OFFSET) +#define TOE_STATE (TOE_CONNECTION_TYPE << PROTOCOL_STATE_BIT_OFFSET) +#define RDMA_STATE (RDMA_CONNECTION_TYPE << PROTOCOL_STATE_BIT_OFFSET) +#define ISCSI_STATE \ + (ISCSI_CONNECTION_TYPE << PROTOCOL_STATE_BIT_OFFSET) +#define FCOE_STATE (FCOE_CONNECTION_TYPE << PROTOCOL_STATE_BIT_OFFSET) /* microcode fixed page page size 4K (chains and ring segments) */ -#define MC_PAGE_SIZE (4096) +#define MC_PAGE_SIZE (4096) -/* Host coalescing constants */ -/* IGU constants */ -#define IGU_PORT_BASE 0x0400 - -#define IGU_ADDR_MSIX 0x0000 -#define IGU_ADDR_INT_ACK 0x0200 -#define IGU_ADDR_PROD_UPD 0x0201 -#define IGU_ADDR_ATTN_BITS_UPD 0x0202 -#define IGU_ADDR_ATTN_BITS_SET 0x0203 -#define IGU_ADDR_ATTN_BITS_CLR 0x0204 -#define IGU_ADDR_COALESCE_NOW 0x0205 -#define IGU_ADDR_SIMD_MASK 0x0206 -#define IGU_ADDR_SIMD_NOMASK 0x0207 -#define IGU_ADDR_MSI_CTL 0x0210 -#define IGU_ADDR_MSI_ADDR_LO 0x0211 -#define IGU_ADDR_MSI_ADDR_HI 0x0212 -#define IGU_ADDR_MSI_DATA 0x0213 - -#define IGU_INT_ENABLE 0 -#define IGU_INT_DISABLE 1 -#define IGU_INT_NOP 2 -#define IGU_INT_NOP2 3 +/* Host coalescing constants */ /* index numbers */ -#define HC_USTORM_DEF_SB_NUM_INDICES 4 -#define HC_CSTORM_DEF_SB_NUM_INDICES 8 -#define HC_XSTORM_DEF_SB_NUM_INDICES 4 -#define HC_TSTORM_DEF_SB_NUM_INDICES 4 -#define HC_USTORM_SB_NUM_INDICES 4 -#define HC_CSTORM_SB_NUM_INDICES 4 +#define HC_USTORM_DEF_SB_NUM_INDICES 4 +#define HC_CSTORM_DEF_SB_NUM_INDICES 8 +#define HC_XSTORM_DEF_SB_NUM_INDICES 4 +#define HC_TSTORM_DEF_SB_NUM_INDICES 4 +#define HC_USTORM_SB_NUM_INDICES 4 +#define HC_CSTORM_SB_NUM_INDICES 4 /* index values - which counterto update */ -#define HC_INDEX_U_ETH_RX_CQ_CONS 1 +#define HC_INDEX_U_TOE_RX_CQ_CONS 0 +#define HC_INDEX_U_ETH_RX_CQ_CONS 1 +#define HC_INDEX_U_ETH_RX_BD_CONS 2 +#define HC_INDEX_U_FCOE_EQ_CONS 3 + +#define HC_INDEX_C_TOE_TX_CQ_CONS 0 +#define HC_INDEX_C_ETH_TX_CQ_CONS 1 +#define HC_INDEX_C_ISCSI_EQ_CONS 2 + +#define HC_INDEX_DEF_X_SPQ_CONS 0 -#define HC_INDEX_C_ETH_TX_CQ_CONS 1 +#define HC_INDEX_DEF_C_RDMA_EQ_CONS 0 +#define HC_INDEX_DEF_C_RDMA_NAL_PROD 1 +#define HC_INDEX_DEF_C_ETH_FW_TX_CQ_CONS 2 +#define HC_INDEX_DEF_C_ETH_SLOW_PATH 3 +#define HC_INDEX_DEF_C_ETH_RDMA_CQ_CONS 4 +#define HC_INDEX_DEF_C_ETH_ISCSI_CQ_CONS 5 -#define HC_INDEX_DEF_X_SPQ_CONS 0 +#define HC_INDEX_DEF_U_ETH_RDMA_RX_CQ_CONS 0 +#define HC_INDEX_DEF_U_ETH_ISCSI_RX_CQ_CONS 1 +#define HC_INDEX_DEF_U_ETH_RDMA_RX_BD_CONS 2 +#define HC_INDEX_DEF_U_ETH_ISCSI_RX_BD_CONS 3 -#define HC_INDEX_DEF_C_ETH_FW_TX_CQ_CONS 2 -#define HC_INDEX_DEF_C_ETH_SLOW_PATH 3 /* used by the driver to get the SB offset */ -#define USTORM_ID 0 -#define CSTORM_ID 1 -#define XSTORM_ID 2 -#define TSTORM_ID 3 -#define ATTENTION_ID 4 +#define USTORM_ID 0 +#define CSTORM_ID 1 +#define XSTORM_ID 2 +#define TSTORM_ID 3 +#define ATTENTION_ID 4 /* max number of slow path commands per port */ -#define MAX_RAMRODS_PER_PORT (8) +#define MAX_RAMRODS_PER_PORT (8) /* values for RX ETH CQE type field */ -#define RX_ETH_CQE_TYPE_ETH_FASTPATH (0) -#define RX_ETH_CQE_TYPE_ETH_RAMROD (1) - -/* MAC address list size */ -#define T_MAC_ADDRESS_LIST_SIZE (96) - +#define RX_ETH_CQE_TYPE_ETH_FASTPATH (0) +#define RX_ETH_CQE_TYPE_ETH_RAMROD (1) + + +/**** DEFINES FOR TIMERS/CLOCKS RESOLUTIONS ****/ +#define EMULATION_FREQUENCY_FACTOR (1600) +#define FPGA_FREQUENCY_FACTOR (100) + +#define TIMERS_TICK_SIZE_CHIP (1e-3) +#define TIMERS_TICK_SIZE_EMUL \ + ((TIMERS_TICK_SIZE_CHIP)/((EMULATION_FREQUENCY_FACTOR))) +#define TIMERS_TICK_SIZE_FPGA \ + ((TIMERS_TICK_SIZE_CHIP)/((FPGA_FREQUENCY_FACTOR))) + +#define TSEMI_CLK1_RESUL_CHIP (1e-3) +#define TSEMI_CLK1_RESUL_EMUL \ + ((TSEMI_CLK1_RESUL_CHIP)/(EMULATION_FREQUENCY_FACTOR)) +#define TSEMI_CLK1_RESUL_FPGA \ + ((TSEMI_CLK1_RESUL_CHIP)/(FPGA_FREQUENCY_FACTOR)) + +#define USEMI_CLK1_RESUL_CHIP \ + (TIMERS_TICK_SIZE_CHIP) +#define USEMI_CLK1_RESUL_EMUL \ + (TIMERS_TICK_SIZE_EMUL) +#define USEMI_CLK1_RESUL_FPGA \ + (TIMERS_TICK_SIZE_FPGA) + +#define XSEMI_CLK1_RESUL_CHIP (1e-3) +#define XSEMI_CLK1_RESUL_EMUL \ + ((XSEMI_CLK1_RESUL_CHIP)/(EMULATION_FREQUENCY_FACTOR)) +#define XSEMI_CLK1_RESUL_FPGA \ + ((XSEMI_CLK1_RESUL_CHIP)/(FPGA_FREQUENCY_FACTOR)) + +#define XSEMI_CLK2_RESUL_CHIP (1e-6) +#define XSEMI_CLK2_RESUL_EMUL \ + ((XSEMI_CLK2_RESUL_CHIP)/(EMULATION_FREQUENCY_FACTOR)) +#define XSEMI_CLK2_RESUL_FPGA \ + ((XSEMI_CLK2_RESUL_CHIP)/(FPGA_FREQUENCY_FACTOR)) + +#define SDM_TIMER_TICK_RESUL_CHIP (4*(1e-6)) +#define SDM_TIMER_TICK_RESUL_EMUL \ + ((SDM_TIMER_TICK_RESUL_CHIP)/(EMULATION_FREQUENCY_FACTOR)) +#define SDM_TIMER_TICK_RESUL_FPGA \ + ((SDM_TIMER_TICK_RESUL_CHIP)/(FPGA_FREQUENCY_FACTOR)) + + +/**** END DEFINES FOR TIMERS/CLOCKS RESOLUTIONS ****/ #define XSTORM_IP_ID_ROLL_HALF 0x8000 #define XSTORM_IP_ID_ROLL_ALL 0 -#define FW_LOG_LIST_SIZE (50) +#define FW_LOG_LIST_SIZE (50) + +#define NUM_OF_PROTOCOLS 4 +#define MAX_COS_NUMBER 16 +#define MAX_T_STAT_COUNTER_ID 18 +#define MAX_X_STAT_COUNTER_ID 18 -#define NUM_OF_PROTOCOLS 4 -#define MAX_COS_NUMBER 16 -#define MAX_T_STAT_COUNTER_ID 18 +#define UNKNOWN_ADDRESS 0 +#define UNICAST_ADDRESS 1 +#define MULTICAST_ADDRESS 2 +#define BROADCAST_ADDRESS 3 -#define T_FAIR 1 -#define FAIR_MEM 2 -#define RS_PERIODIC_TIMEOUT_IN_SDM_TICS 25 +#define SINGLE_FUNCTION 0 +#define MULTI_FUNCTION 1 -#define UNKNOWN_ADDRESS 0 -#define UNICAST_ADDRESS 1 -#define MULTICAST_ADDRESS 2 -#define BROADCAST_ADDRESS 3 +#define IP_V4 0 +#define IP_V6 1 diff --git a/drivers/net/bnx2x_hsi.h b/drivers/net/bnx2x_hsi.h index b21075ccb52e..d3e8198d7dba 100644 --- a/drivers/net/bnx2x_hsi.h +++ b/drivers/net/bnx2x_hsi.h @@ -132,6 +132,12 @@ struct shared_hw_cfg { /* NVRAM Offset */ #define SHARED_HW_CFG_BOARD_TYPE_BCM957710T1003G 0x00000008 #define SHARED_HW_CFG_BOARD_TYPE_BCM957710A1022G 0x00000009 #define SHARED_HW_CFG_BOARD_TYPE_BCM957710A1021G 0x0000000a +#define SHARED_HW_CFG_BOARD_TYPE_BCM957710A1023G 0x0000000b +#define SHARED_HW_CFG_BOARD_TYPE_BCM957710A1033G 0x0000000c +#define SHARED_HW_CFG_BOARD_TYPE_BCM957711T1101 0x0000000d +#define SHARED_HW_CFG_BOARD_TYPE_BCM957711ET1201 0x0000000e +#define SHARED_HW_CFG_BOARD_TYPE_BCM957711A1133G 0x0000000f +#define SHARED_HW_CFG_BOARD_TYPE_BCM957711EA1233G 0x00000010 #define SHARED_HW_CFG_BOARD_VER_MASK 0xffff0000 #define SHARED_HW_CFG_BOARD_VER_SHIFT 16 @@ -313,6 +319,7 @@ struct shared_feat_cfg { /* NVRAM Offset */ u32 config; /* 0x450 */ #define SHARED_FEATURE_BMC_ECHO_MODE_EN 0x00000001 +#define SHARED_FEATURE_MF_MODE_DISABLED 0x00000100 }; @@ -502,28 +509,41 @@ struct port_feat_cfg { /* port 0: 0x454 port 1: 0x4c8 */ }; -/***************************************************************************** - * Device Information * - *****************************************************************************/ -struct dev_info { /* size */ +/**************************************************************************** + * Device Information * + ****************************************************************************/ +struct dev_info { /* size */ - u32 bc_rev; /* 8 bits each: major, minor, build */ /* 4 */ + u32 bc_rev; /* 8 bits each: major, minor, build */ /* 4 */ - struct shared_hw_cfg shared_hw_config; /* 40 */ + struct shared_hw_cfg shared_hw_config; /* 40 */ - struct port_hw_cfg port_hw_config[PORT_MAX]; /* 400*2=800 */ + struct port_hw_cfg port_hw_config[PORT_MAX]; /* 400*2=800 */ - struct shared_feat_cfg shared_feature_config; /* 4 */ + struct shared_feat_cfg shared_feature_config; /* 4 */ - struct port_feat_cfg port_feature_config[PORT_MAX]; /* 116*2=232 */ + struct port_feat_cfg port_feature_config[PORT_MAX];/* 116*2=232 */ }; #define FUNC_0 0 #define FUNC_1 1 +#define FUNC_2 2 +#define FUNC_3 3 +#define FUNC_4 4 +#define FUNC_5 5 +#define FUNC_6 6 +#define FUNC_7 7 #define E1_FUNC_MAX 2 -#define FUNC_MAX E1_FUNC_MAX +#define E1H_FUNC_MAX 8 + +#define VN_0 0 +#define VN_1 1 +#define VN_2 2 +#define VN_3 3 +#define E1VN_MAX 1 +#define E1HVN_MAX 4 /* This value (in milliseconds) determines the frequency of the driver @@ -619,7 +639,9 @@ struct drv_port_mb { #define LINK_STATUS_LINK_PARTNER_15GXFD_CAPABLE 0x08000000 #define LINK_STATUS_LINK_PARTNER_16GXFD_CAPABLE 0x10000000 - u32 reserved[3]; + u32 port_stx; + + u32 reserved[2]; }; @@ -642,6 +664,11 @@ struct drv_func_mb { #define DRV_MSG_CODE_GET_MANUF_KEY 0x82000000 #define DRV_MSG_CODE_LOAD_L2B_PRAM 0x90000000 +#define BIOS_MSG_CODE_LIC_CHALLENGE 0xff010000 +#define BIOS_MSG_CODE_LIC_RESPONSE 0xff020000 +#define BIOS_MSG_CODE_VIRT_MAC_PRIM 0xff030000 +#define BIOS_MSG_CODE_VIRT_MAC_ISCSI 0xff040000 + #define DRV_MSG_SEQ_NUMBER_MASK 0x0000ffff u32 drv_mb_param; @@ -671,6 +698,11 @@ struct drv_func_mb { #define FW_MSG_CODE_L2B_PRAM_X_LOAD_FAILURE 0x90230000 #define FW_MSG_CODE_L2B_PRAM_U_LOAD_FAILURE 0x90240000 +#define FW_MSG_CODE_LIC_CHALLENGE 0xff010000 +#define FW_MSG_CODE_LIC_RESPONSE 0xff020000 +#define FW_MSG_CODE_VIRT_MAC_PRIM 0xff030000 +#define FW_MSG_CODE_VIRT_MAC_ISCSI 0xff040000 + #define FW_MSG_SEQ_NUMBER_MASK 0x0000ffff u32 fw_mb_param; @@ -696,7 +728,13 @@ struct drv_func_mb { u32 iscsi_boot_signature; u32 iscsi_boot_block_offset; - u32 reserved[3]; + u32 drv_status; +#define DRV_STATUS_PMF 0x00000001 + + u32 virt_mac_upper; +#define VIRT_MAC_SIGN_MASK 0xffff0000 +#define VIRT_MAC_SIGNATURE 0x564d0000 + u32 virt_mac_lower; }; @@ -713,6 +751,92 @@ struct mgmtfw_state { /**************************************************************************** + * Multi-Function configuration * + ****************************************************************************/ +struct shared_mf_cfg { + + u32 clp_mb; +#define SHARED_MF_CLP_SET_DEFAULT 0x00000000 + /* set by CLP */ +#define SHARED_MF_CLP_EXIT 0x00000001 + /* set by MCP */ +#define SHARED_MF_CLP_EXIT_DONE 0x00010000 + +}; + +struct port_mf_cfg { + + u32 dynamic_cfg; /* device control channel */ +#define PORT_MF_CFG_OUTER_VLAN_TAG_MASK 0x0000ffff +#define PORT_MF_CFG_OUTER_VLAN_TAG_SHIFT 0 +#define PORT_MF_CFG_DYNAMIC_CFG_ENABLED 0x00010000 +#define PORT_MF_CFG_DYNAMIC_CFG_DEFAULT 0x00000000 + + u32 reserved[3]; + +}; + +struct func_mf_cfg { + + u32 config; + /* E/R/I/D */ + /* function 0 of each port cannot be hidden */ +#define FUNC_MF_CFG_FUNC_HIDE 0x00000001 + +#define FUNC_MF_CFG_PROTOCOL_MASK 0x00000007 +#define FUNC_MF_CFG_PROTOCOL_ETHERNET 0x00000002 +#define FUNC_MF_CFG_PROTOCOL_ETHERNET_WITH_RDMA 0x00000004 +#define FUNC_MF_CFG_PROTOCOL_ISCSI 0x00000006 +#define FUNC_MF_CFG_PROTOCOL_DEFAULT\ + FUNC_MF_CFG_PROTOCOL_ETHERNET_WITH_RDMA + +#define FUNC_MF_CFG_FUNC_DISABLED 0x00000008 + + /* PRI */ + /* 0 - low priority, 3 - high priority */ +#define FUNC_MF_CFG_TRANSMIT_PRIORITY_MASK 0x00000300 +#define FUNC_MF_CFG_TRANSMIT_PRIORITY_SHIFT 8 +#define FUNC_MF_CFG_TRANSMIT_PRIORITY_DEFAULT 0x00000000 + + /* MINBW, MAXBW */ + /* value range - 0..100, increments in 100Mbps */ +#define FUNC_MF_CFG_MIN_BW_MASK 0x00ff0000 +#define FUNC_MF_CFG_MIN_BW_SHIFT 16 +#define FUNC_MF_CFG_MIN_BW_DEFAULT 0x00000000 +#define FUNC_MF_CFG_MAX_BW_MASK 0xff000000 +#define FUNC_MF_CFG_MAX_BW_SHIFT 24 +#define FUNC_MF_CFG_MAX_BW_DEFAULT 0x64000000 + + u32 mac_upper; /* MAC */ +#define FUNC_MF_CFG_UPPERMAC_MASK 0x0000ffff +#define FUNC_MF_CFG_UPPERMAC_SHIFT 0 +#define FUNC_MF_CFG_UPPERMAC_DEFAULT FUNC_MF_CFG_UPPERMAC_MASK + u32 mac_lower; +#define FUNC_MF_CFG_LOWERMAC_DEFAULT 0xffffffff + + u32 e1hov_tag; /* VNI */ +#define FUNC_MF_CFG_E1HOV_TAG_MASK 0x0000ffff +#define FUNC_MF_CFG_E1HOV_TAG_SHIFT 0 +#define FUNC_MF_CFG_E1HOV_TAG_DEFAULT FUNC_MF_CFG_E1HOV_TAG_MASK + + u32 reserved[2]; + +}; + +struct mf_cfg { + + struct shared_mf_cfg shared_mf_config; + struct port_mf_cfg port_mf_config[PORT_MAX]; +#if defined(b710) + struct func_mf_cfg func_mf_config[E1_FUNC_MAX]; +#else + struct func_mf_cfg func_mf_config[E1H_FUNC_MAX]; +#endif + +}; + + +/**************************************************************************** * Shared Memory Region * ****************************************************************************/ struct shmem_region { /* SharedMem Offset (size) */ @@ -747,14 +871,349 @@ struct shmem_region { /* SharedMem Offset (size) */ struct mgmtfw_state mgmtfw_state; /* 0x4ac (0x1b8) */ struct drv_port_mb port_mb[PORT_MAX]; /* 0x664 (16*2=0x20) */ - struct drv_func_mb func_mb[FUNC_MAX]; /* 0x684 (44*2=0x58) */ + struct drv_func_mb func_mb[E1H_FUNC_MAX]; + + struct mf_cfg mf_cfg; }; /* 0x6dc */ +struct emac_stats { + u32 rx_stat_ifhcinoctets; + u32 rx_stat_ifhcinbadoctets; + u32 rx_stat_etherstatsfragments; + u32 rx_stat_ifhcinucastpkts; + u32 rx_stat_ifhcinmulticastpkts; + u32 rx_stat_ifhcinbroadcastpkts; + u32 rx_stat_dot3statsfcserrors; + u32 rx_stat_dot3statsalignmenterrors; + u32 rx_stat_dot3statscarriersenseerrors; + u32 rx_stat_xonpauseframesreceived; + u32 rx_stat_xoffpauseframesreceived; + u32 rx_stat_maccontrolframesreceived; + u32 rx_stat_xoffstateentered; + u32 rx_stat_dot3statsframestoolong; + u32 rx_stat_etherstatsjabbers; + u32 rx_stat_etherstatsundersizepkts; + u32 rx_stat_etherstatspkts64octets; + u32 rx_stat_etherstatspkts65octetsto127octets; + u32 rx_stat_etherstatspkts128octetsto255octets; + u32 rx_stat_etherstatspkts256octetsto511octets; + u32 rx_stat_etherstatspkts512octetsto1023octets; + u32 rx_stat_etherstatspkts1024octetsto1522octets; + u32 rx_stat_etherstatspktsover1522octets; + + u32 rx_stat_falsecarriererrors; + + u32 tx_stat_ifhcoutoctets; + u32 tx_stat_ifhcoutbadoctets; + u32 tx_stat_etherstatscollisions; + u32 tx_stat_outxonsent; + u32 tx_stat_outxoffsent; + u32 tx_stat_flowcontroldone; + u32 tx_stat_dot3statssinglecollisionframes; + u32 tx_stat_dot3statsmultiplecollisionframes; + u32 tx_stat_dot3statsdeferredtransmissions; + u32 tx_stat_dot3statsexcessivecollisions; + u32 tx_stat_dot3statslatecollisions; + u32 tx_stat_ifhcoutucastpkts; + u32 tx_stat_ifhcoutmulticastpkts; + u32 tx_stat_ifhcoutbroadcastpkts; + u32 tx_stat_etherstatspkts64octets; + u32 tx_stat_etherstatspkts65octetsto127octets; + u32 tx_stat_etherstatspkts128octetsto255octets; + u32 tx_stat_etherstatspkts256octetsto511octets; + u32 tx_stat_etherstatspkts512octetsto1023octets; + u32 tx_stat_etherstatspkts1024octetsto1522octets; + u32 tx_stat_etherstatspktsover1522octets; + u32 tx_stat_dot3statsinternalmactransmiterrors; +}; + + +struct bmac_stats { + u32 tx_stat_gtpkt_lo; + u32 tx_stat_gtpkt_hi; + u32 tx_stat_gtxpf_lo; + u32 tx_stat_gtxpf_hi; + u32 tx_stat_gtfcs_lo; + u32 tx_stat_gtfcs_hi; + u32 tx_stat_gtmca_lo; + u32 tx_stat_gtmca_hi; + u32 tx_stat_gtbca_lo; + u32 tx_stat_gtbca_hi; + u32 tx_stat_gtfrg_lo; + u32 tx_stat_gtfrg_hi; + u32 tx_stat_gtovr_lo; + u32 tx_stat_gtovr_hi; + u32 tx_stat_gt64_lo; + u32 tx_stat_gt64_hi; + u32 tx_stat_gt127_lo; + u32 tx_stat_gt127_hi; + u32 tx_stat_gt255_lo; + u32 tx_stat_gt255_hi; + u32 tx_stat_gt511_lo; + u32 tx_stat_gt511_hi; + u32 tx_stat_gt1023_lo; + u32 tx_stat_gt1023_hi; + u32 tx_stat_gt1518_lo; + u32 tx_stat_gt1518_hi; + u32 tx_stat_gt2047_lo; + u32 tx_stat_gt2047_hi; + u32 tx_stat_gt4095_lo; + u32 tx_stat_gt4095_hi; + u32 tx_stat_gt9216_lo; + u32 tx_stat_gt9216_hi; + u32 tx_stat_gt16383_lo; + u32 tx_stat_gt16383_hi; + u32 tx_stat_gtmax_lo; + u32 tx_stat_gtmax_hi; + u32 tx_stat_gtufl_lo; + u32 tx_stat_gtufl_hi; + u32 tx_stat_gterr_lo; + u32 tx_stat_gterr_hi; + u32 tx_stat_gtbyt_lo; + u32 tx_stat_gtbyt_hi; + + u32 rx_stat_gr64_lo; + u32 rx_stat_gr64_hi; + u32 rx_stat_gr127_lo; + u32 rx_stat_gr127_hi; + u32 rx_stat_gr255_lo; + u32 rx_stat_gr255_hi; + u32 rx_stat_gr511_lo; + u32 rx_stat_gr511_hi; + u32 rx_stat_gr1023_lo; + u32 rx_stat_gr1023_hi; + u32 rx_stat_gr1518_lo; + u32 rx_stat_gr1518_hi; + u32 rx_stat_gr2047_lo; + u32 rx_stat_gr2047_hi; + u32 rx_stat_gr4095_lo; + u32 rx_stat_gr4095_hi; + u32 rx_stat_gr9216_lo; + u32 rx_stat_gr9216_hi; + u32 rx_stat_gr16383_lo; + u32 rx_stat_gr16383_hi; + u32 rx_stat_grmax_lo; + u32 rx_stat_grmax_hi; + u32 rx_stat_grpkt_lo; + u32 rx_stat_grpkt_hi; + u32 rx_stat_grfcs_lo; + u32 rx_stat_grfcs_hi; + u32 rx_stat_grmca_lo; + u32 rx_stat_grmca_hi; + u32 rx_stat_grbca_lo; + u32 rx_stat_grbca_hi; + u32 rx_stat_grxcf_lo; + u32 rx_stat_grxcf_hi; + u32 rx_stat_grxpf_lo; + u32 rx_stat_grxpf_hi; + u32 rx_stat_grxuo_lo; + u32 rx_stat_grxuo_hi; + u32 rx_stat_grjbr_lo; + u32 rx_stat_grjbr_hi; + u32 rx_stat_grovr_lo; + u32 rx_stat_grovr_hi; + u32 rx_stat_grflr_lo; + u32 rx_stat_grflr_hi; + u32 rx_stat_grmeg_lo; + u32 rx_stat_grmeg_hi; + u32 rx_stat_grmeb_lo; + u32 rx_stat_grmeb_hi; + u32 rx_stat_grbyt_lo; + u32 rx_stat_grbyt_hi; + u32 rx_stat_grund_lo; + u32 rx_stat_grund_hi; + u32 rx_stat_grfrg_lo; + u32 rx_stat_grfrg_hi; + u32 rx_stat_grerb_lo; + u32 rx_stat_grerb_hi; + u32 rx_stat_grfre_lo; + u32 rx_stat_grfre_hi; + u32 rx_stat_gripj_lo; + u32 rx_stat_gripj_hi; +}; + + +union mac_stats { + struct emac_stats emac_stats; + struct bmac_stats bmac_stats; +}; + + +struct mac_stx { + /* in_bad_octets */ + u32 rx_stat_ifhcinbadoctets_hi; + u32 rx_stat_ifhcinbadoctets_lo; + + /* out_bad_octets */ + u32 tx_stat_ifhcoutbadoctets_hi; + u32 tx_stat_ifhcoutbadoctets_lo; + + /* crc_receive_errors */ + u32 rx_stat_dot3statsfcserrors_hi; + u32 rx_stat_dot3statsfcserrors_lo; + /* alignment_errors */ + u32 rx_stat_dot3statsalignmenterrors_hi; + u32 rx_stat_dot3statsalignmenterrors_lo; + /* carrier_sense_errors */ + u32 rx_stat_dot3statscarriersenseerrors_hi; + u32 rx_stat_dot3statscarriersenseerrors_lo; + /* false_carrier_detections */ + u32 rx_stat_falsecarriererrors_hi; + u32 rx_stat_falsecarriererrors_lo; + + /* runt_packets_received */ + u32 rx_stat_etherstatsundersizepkts_hi; + u32 rx_stat_etherstatsundersizepkts_lo; + /* jabber_packets_received */ + u32 rx_stat_dot3statsframestoolong_hi; + u32 rx_stat_dot3statsframestoolong_lo; + + /* error_runt_packets_received */ + u32 rx_stat_etherstatsfragments_hi; + u32 rx_stat_etherstatsfragments_lo; + /* error_jabber_packets_received */ + u32 rx_stat_etherstatsjabbers_hi; + u32 rx_stat_etherstatsjabbers_lo; + + /* control_frames_received */ + u32 rx_stat_maccontrolframesreceived_hi; + u32 rx_stat_maccontrolframesreceived_lo; + u32 rx_stat_bmac_xpf_hi; + u32 rx_stat_bmac_xpf_lo; + u32 rx_stat_bmac_xcf_hi; + u32 rx_stat_bmac_xcf_lo; + + /* xoff_state_entered */ + u32 rx_stat_xoffstateentered_hi; + u32 rx_stat_xoffstateentered_lo; + /* pause_xon_frames_received */ + u32 rx_stat_xonpauseframesreceived_hi; + u32 rx_stat_xonpauseframesreceived_lo; + /* pause_xoff_frames_received */ + u32 rx_stat_xoffpauseframesreceived_hi; + u32 rx_stat_xoffpauseframesreceived_lo; + /* pause_xon_frames_transmitted */ + u32 tx_stat_outxonsent_hi; + u32 tx_stat_outxonsent_lo; + /* pause_xoff_frames_transmitted */ + u32 tx_stat_outxoffsent_hi; + u32 tx_stat_outxoffsent_lo; + /* flow_control_done */ + u32 tx_stat_flowcontroldone_hi; + u32 tx_stat_flowcontroldone_lo; + + /* ether_stats_collisions */ + u32 tx_stat_etherstatscollisions_hi; + u32 tx_stat_etherstatscollisions_lo; + /* single_collision_transmit_frames */ + u32 tx_stat_dot3statssinglecollisionframes_hi; + u32 tx_stat_dot3statssinglecollisionframes_lo; + /* multiple_collision_transmit_frames */ + u32 tx_stat_dot3statsmultiplecollisionframes_hi; + u32 tx_stat_dot3statsmultiplecollisionframes_lo; + /* deferred_transmissions */ + u32 tx_stat_dot3statsdeferredtransmissions_hi; + u32 tx_stat_dot3statsdeferredtransmissions_lo; + /* excessive_collision_frames */ + u32 tx_stat_dot3statsexcessivecollisions_hi; + u32 tx_stat_dot3statsexcessivecollisions_lo; + /* late_collision_frames */ + u32 tx_stat_dot3statslatecollisions_hi; + u32 tx_stat_dot3statslatecollisions_lo; + + /* frames_transmitted_64_bytes */ + u32 tx_stat_etherstatspkts64octets_hi; + u32 tx_stat_etherstatspkts64octets_lo; + /* frames_transmitted_65_127_bytes */ + u32 tx_stat_etherstatspkts65octetsto127octets_hi; + u32 tx_stat_etherstatspkts65octetsto127octets_lo; + /* frames_transmitted_128_255_bytes */ + u32 tx_stat_etherstatspkts128octetsto255octets_hi; + u32 tx_stat_etherstatspkts128octetsto255octets_lo; + /* frames_transmitted_256_511_bytes */ + u32 tx_stat_etherstatspkts256octetsto511octets_hi; + u32 tx_stat_etherstatspkts256octetsto511octets_lo; + /* frames_transmitted_512_1023_bytes */ + u32 tx_stat_etherstatspkts512octetsto1023octets_hi; + u32 tx_stat_etherstatspkts512octetsto1023octets_lo; + /* frames_transmitted_1024_1522_bytes */ + u32 tx_stat_etherstatspkts1024octetsto1522octets_hi; + u32 tx_stat_etherstatspkts1024octetsto1522octets_lo; + /* frames_transmitted_1523_9022_bytes */ + u32 tx_stat_etherstatspktsover1522octets_hi; + u32 tx_stat_etherstatspktsover1522octets_lo; + u32 tx_stat_bmac_2047_hi; + u32 tx_stat_bmac_2047_lo; + u32 tx_stat_bmac_4095_hi; + u32 tx_stat_bmac_4095_lo; + u32 tx_stat_bmac_9216_hi; + u32 tx_stat_bmac_9216_lo; + u32 tx_stat_bmac_16383_hi; + u32 tx_stat_bmac_16383_lo; + + /* internal_mac_transmit_errors */ + u32 tx_stat_dot3statsinternalmactransmiterrors_hi; + u32 tx_stat_dot3statsinternalmactransmiterrors_lo; + + /* if_out_discards */ + u32 tx_stat_bmac_ufl_hi; + u32 tx_stat_bmac_ufl_lo; +}; + + +#define MAC_STX_IDX_MAX 2 + +struct host_port_stats { + u32 host_port_stats_start; + + struct mac_stx mac_stx[MAC_STX_IDX_MAX]; + + u32 brb_drop_hi; + u32 brb_drop_lo; + + u32 host_port_stats_end; +}; + + +struct host_func_stats { + u32 host_func_stats_start; + + u32 total_bytes_received_hi; + u32 total_bytes_received_lo; + + u32 total_bytes_transmitted_hi; + u32 total_bytes_transmitted_lo; + + u32 total_unicast_packets_received_hi; + u32 total_unicast_packets_received_lo; + + u32 total_multicast_packets_received_hi; + u32 total_multicast_packets_received_lo; + + u32 total_broadcast_packets_received_hi; + u32 total_broadcast_packets_received_lo; + + u32 total_unicast_packets_transmitted_hi; + u32 total_unicast_packets_transmitted_lo; + + u32 total_multicast_packets_transmitted_hi; + u32 total_multicast_packets_transmitted_lo; + + u32 total_broadcast_packets_transmitted_hi; + u32 total_broadcast_packets_transmitted_lo; + + u32 valid_bytes_received_hi; + u32 valid_bytes_received_lo; + + u32 host_func_stats_end; +}; + + #define BCM_5710_FW_MAJOR_VERSION 4 -#define BCM_5710_FW_MINOR_VERSION 0 -#define BCM_5710_FW_REVISION_VERSION 14 +#define BCM_5710_FW_MINOR_VERSION 5 +#define BCM_5710_FW_REVISION_VERSION 1 #define BCM_5710_FW_COMPILE_FLAGS 1 @@ -793,7 +1252,7 @@ struct doorbell_hdr { }; /* - * doorbell message send to the chip + * doorbell message sent to the chip */ struct doorbell { #if defined(__BIG_ENDIAN) @@ -849,8 +1308,10 @@ struct parsing_flags { u16 flags; #define PARSING_FLAGS_ETHERNET_ADDRESS_TYPE (0x1<<0) #define PARSING_FLAGS_ETHERNET_ADDRESS_TYPE_SHIFT 0 -#define PARSING_FLAGS_NUMBER_OF_NESTED_VLANS (0x3<<1) -#define PARSING_FLAGS_NUMBER_OF_NESTED_VLANS_SHIFT 1 +#define PARSING_FLAGS_VLAN (0x1<<1) +#define PARSING_FLAGS_VLAN_SHIFT 1 +#define PARSING_FLAGS_EXTRA_VLAN (0x1<<2) +#define PARSING_FLAGS_EXTRA_VLAN_SHIFT 2 #define PARSING_FLAGS_OVER_ETHERNET_PROTOCOL (0x3<<3) #define PARSING_FLAGS_OVER_ETHERNET_PROTOCOL_SHIFT 3 #define PARSING_FLAGS_IP_OPTIONS (0x1<<5) @@ -874,6 +1335,12 @@ struct parsing_flags { }; +struct regpair { + u32 lo; + u32 hi; +}; + + /* * dmae command structure */ @@ -901,8 +1368,10 @@ struct dmae_command { #define DMAE_COMMAND_SRC_RESET_SHIFT 13 #define DMAE_COMMAND_DST_RESET (0x1<<14) #define DMAE_COMMAND_DST_RESET_SHIFT 14 -#define DMAE_COMMAND_RESERVED0 (0x1FFFF<<15) -#define DMAE_COMMAND_RESERVED0_SHIFT 15 +#define DMAE_COMMAND_E1HVN (0x3<<15) +#define DMAE_COMMAND_E1HVN_SHIFT 15 +#define DMAE_COMMAND_RESERVED0 (0x7FFF<<17) +#define DMAE_COMMAND_RESERVED0_SHIFT 17 u32 src_addr_lo; u32 src_addr_hi; u32 dst_addr_lo; @@ -952,72 +1421,107 @@ struct double_regpair { /* - * The eth Rx Buffer Descriptor - */ -struct eth_rx_bd { - u32 addr_lo; - u32 addr_hi; -}; - -/* - * The eth storm context of Ustorm + * The eth storm context of Ustorm (configuration part) */ -struct ustorm_eth_st_context { +struct ustorm_eth_st_context_config { #if defined(__BIG_ENDIAN) - u8 sb_index_number; + u8 flags; +#define USTORM_ETH_ST_CONTEXT_CONFIG_ENABLE_MC_ALIGNMENT (0x1<<0) +#define USTORM_ETH_ST_CONTEXT_CONFIG_ENABLE_MC_ALIGNMENT_SHIFT 0 +#define USTORM_ETH_ST_CONTEXT_CONFIG_ENABLE_DYNAMIC_HC (0x1<<1) +#define USTORM_ETH_ST_CONTEXT_CONFIG_ENABLE_DYNAMIC_HC_SHIFT 1 +#define USTORM_ETH_ST_CONTEXT_CONFIG_ENABLE_TPA (0x1<<2) +#define USTORM_ETH_ST_CONTEXT_CONFIG_ENABLE_TPA_SHIFT 2 +#define USTORM_ETH_ST_CONTEXT_CONFIG_ENABLE_SGE_RING (0x1<<3) +#define USTORM_ETH_ST_CONTEXT_CONFIG_ENABLE_SGE_RING_SHIFT 3 +#define __USTORM_ETH_ST_CONTEXT_CONFIG_RESERVED0 (0xF<<4) +#define __USTORM_ETH_ST_CONTEXT_CONFIG_RESERVED0_SHIFT 4 u8 status_block_id; - u8 __local_rx_bd_cons; - u8 __local_rx_bd_prod; + u8 clientId; + u8 sb_index_numbers; +#define USTORM_ETH_ST_CONTEXT_CONFIG_CQE_SB_INDEX_NUMBER (0xF<<0) +#define USTORM_ETH_ST_CONTEXT_CONFIG_CQE_SB_INDEX_NUMBER_SHIFT 0 +#define USTORM_ETH_ST_CONTEXT_CONFIG_BD_SB_INDEX_NUMBER (0xF<<4) +#define USTORM_ETH_ST_CONTEXT_CONFIG_BD_SB_INDEX_NUMBER_SHIFT 4 #elif defined(__LITTLE_ENDIAN) - u8 __local_rx_bd_prod; - u8 __local_rx_bd_cons; + u8 sb_index_numbers; +#define USTORM_ETH_ST_CONTEXT_CONFIG_CQE_SB_INDEX_NUMBER (0xF<<0) +#define USTORM_ETH_ST_CONTEXT_CONFIG_CQE_SB_INDEX_NUMBER_SHIFT 0 +#define USTORM_ETH_ST_CONTEXT_CONFIG_BD_SB_INDEX_NUMBER (0xF<<4) +#define USTORM_ETH_ST_CONTEXT_CONFIG_BD_SB_INDEX_NUMBER_SHIFT 4 + u8 clientId; u8 status_block_id; - u8 sb_index_number; + u8 flags; +#define USTORM_ETH_ST_CONTEXT_CONFIG_ENABLE_MC_ALIGNMENT (0x1<<0) +#define USTORM_ETH_ST_CONTEXT_CONFIG_ENABLE_MC_ALIGNMENT_SHIFT 0 +#define USTORM_ETH_ST_CONTEXT_CONFIG_ENABLE_DYNAMIC_HC (0x1<<1) +#define USTORM_ETH_ST_CONTEXT_CONFIG_ENABLE_DYNAMIC_HC_SHIFT 1 +#define USTORM_ETH_ST_CONTEXT_CONFIG_ENABLE_TPA (0x1<<2) +#define USTORM_ETH_ST_CONTEXT_CONFIG_ENABLE_TPA_SHIFT 2 +#define USTORM_ETH_ST_CONTEXT_CONFIG_ENABLE_SGE_RING (0x1<<3) +#define USTORM_ETH_ST_CONTEXT_CONFIG_ENABLE_SGE_RING_SHIFT 3 +#define __USTORM_ETH_ST_CONTEXT_CONFIG_RESERVED0 (0xF<<4) +#define __USTORM_ETH_ST_CONTEXT_CONFIG_RESERVED0_SHIFT 4 #endif #if defined(__BIG_ENDIAN) - u16 rcq_cons; - u16 rx_bd_cons; + u16 bd_buff_size; + u16 mc_alignment_size; #elif defined(__LITTLE_ENDIAN) - u16 rx_bd_cons; - u16 rcq_cons; + u16 mc_alignment_size; + u16 bd_buff_size; #endif - u32 rx_bd_page_base_lo; - u32 rx_bd_page_base_hi; - u32 rcq_base_address_lo; - u32 rcq_base_address_hi; #if defined(__BIG_ENDIAN) - u16 __num_of_returned_cqes; - u8 num_rss; - u8 flags; -#define USTORM_ETH_ST_CONTEXT_ENABLE_MC_ALIGNMENT (0x1<<0) -#define USTORM_ETH_ST_CONTEXT_ENABLE_MC_ALIGNMENT_SHIFT 0 -#define USTORM_ETH_ST_CONTEXT_ENABLE_DYNAMIC_HC (0x1<<1) -#define USTORM_ETH_ST_CONTEXT_ENABLE_DYNAMIC_HC_SHIFT 1 -#define USTORM_ETH_ST_CONTEXT_ENABLE_TPA (0x1<<2) -#define USTORM_ETH_ST_CONTEXT_ENABLE_TPA_SHIFT 2 -#define __USTORM_ETH_ST_CONTEXT_RESERVED0 (0x1F<<3) -#define __USTORM_ETH_ST_CONTEXT_RESERVED0_SHIFT 3 + u8 __local_sge_prod; + u8 __local_bd_prod; + u16 sge_buff_size; #elif defined(__LITTLE_ENDIAN) - u8 flags; -#define USTORM_ETH_ST_CONTEXT_ENABLE_MC_ALIGNMENT (0x1<<0) -#define USTORM_ETH_ST_CONTEXT_ENABLE_MC_ALIGNMENT_SHIFT 0 -#define USTORM_ETH_ST_CONTEXT_ENABLE_DYNAMIC_HC (0x1<<1) -#define USTORM_ETH_ST_CONTEXT_ENABLE_DYNAMIC_HC_SHIFT 1 -#define USTORM_ETH_ST_CONTEXT_ENABLE_TPA (0x1<<2) -#define USTORM_ETH_ST_CONTEXT_ENABLE_TPA_SHIFT 2 -#define __USTORM_ETH_ST_CONTEXT_RESERVED0 (0x1F<<3) -#define __USTORM_ETH_ST_CONTEXT_RESERVED0_SHIFT 3 - u8 num_rss; - u16 __num_of_returned_cqes; + u16 sge_buff_size; + u8 __local_bd_prod; + u8 __local_sge_prod; #endif #if defined(__BIG_ENDIAN) - u16 mc_alignment_size; - u16 agg_threshold; + u16 __bd_cons; + u16 __sge_cons; #elif defined(__LITTLE_ENDIAN) - u16 agg_threshold; - u16 mc_alignment_size; + u16 __sge_cons; + u16 __bd_cons; #endif + u32 bd_page_base_lo; + u32 bd_page_base_hi; + u32 sge_page_base_lo; + u32 sge_page_base_hi; +}; + +/* + * The eth Rx Buffer Descriptor + */ +struct eth_rx_bd { + u32 addr_lo; + u32 addr_hi; +}; + +/* + * The eth Rx SGE Descriptor + */ +struct eth_rx_sge { + u32 addr_lo; + u32 addr_hi; +}; + +/* + * Local BDs and SGEs rings (in ETH) + */ +struct eth_local_rx_rings { struct eth_rx_bd __local_bd_ring[16]; + struct eth_rx_sge __local_sge_ring[12]; +}; + +/* + * The eth storm context of Ustorm + */ +struct ustorm_eth_st_context { + struct ustorm_eth_st_context_config common; + struct eth_local_rx_rings __rings; }; /* @@ -1088,9 +1592,9 @@ struct xstorm_eth_extra_ag_context_section { #if defined(__BIG_ENDIAN) u16 __reserved3; u8 __reserved2; - u8 __agg_misc7; + u8 __da_only_cnt; #elif defined(__LITTLE_ENDIAN) - u8 __agg_misc7; + u8 __da_only_cnt; u8 __reserved2; u16 __reserved3; #endif @@ -1368,7 +1872,13 @@ struct timers_block_context { u32 __reserved_0; u32 __reserved_1; u32 __reserved_2; - u32 __reserved_flags; + u32 flags; +#define __TIMERS_BLOCK_CONTEXT_NUM_OF_ACTIVE_TIMERS (0x3<<0) +#define __TIMERS_BLOCK_CONTEXT_NUM_OF_ACTIVE_TIMERS_SHIFT 0 +#define TIMERS_BLOCK_CONTEXT_CONN_VALID_FLG (0x1<<2) +#define TIMERS_BLOCK_CONTEXT_CONN_VALID_FLG_SHIFT 2 +#define __TIMERS_BLOCK_CONTEXT_RESERVED0 (0x1FFFFFFF<<3) +#define __TIMERS_BLOCK_CONTEXT_RESERVED0_SHIFT 3 }; /* @@ -1478,11 +1988,19 @@ struct xstorm_eth_st_context { u32 tx_bd_page_base_hi; #if defined(__BIG_ENDIAN) u16 tx_bd_cons; - u8 __reserved0; + u8 statistics_data; +#define XSTORM_ETH_ST_CONTEXT_STATISTICS_COUNTER_ID (0x7F<<0) +#define XSTORM_ETH_ST_CONTEXT_STATISTICS_COUNTER_ID_SHIFT 0 +#define XSTORM_ETH_ST_CONTEXT_STATISTICS_ENABLE (0x1<<7) +#define XSTORM_ETH_ST_CONTEXT_STATISTICS_ENABLE_SHIFT 7 u8 __local_tx_bd_prod; #elif defined(__LITTLE_ENDIAN) u8 __local_tx_bd_prod; - u8 __reserved0; + u8 statistics_data; +#define XSTORM_ETH_ST_CONTEXT_STATISTICS_COUNTER_ID (0x7F<<0) +#define XSTORM_ETH_ST_CONTEXT_STATISTICS_COUNTER_ID_SHIFT 0 +#define XSTORM_ETH_ST_CONTEXT_STATISTICS_ENABLE (0x1<<7) +#define XSTORM_ETH_ST_CONTEXT_STATISTICS_ENABLE_SHIFT 7 u16 tx_bd_cons; #endif u32 db_data_addr_lo; @@ -1559,7 +2077,7 @@ struct eth_tx_doorbell { struct ustorm_def_status_block { u16 index_values[HC_USTORM_DEF_SB_NUM_INDICES]; u16 status_block_index; - u8 reserved0; + u8 func; u8 status_block_id; u32 __flags; }; @@ -1570,7 +2088,7 @@ struct ustorm_def_status_block { struct cstorm_def_status_block { u16 index_values[HC_CSTORM_DEF_SB_NUM_INDICES]; u16 status_block_index; - u8 reserved0; + u8 func; u8 status_block_id; u32 __flags; }; @@ -1581,7 +2099,7 @@ struct cstorm_def_status_block { struct xstorm_def_status_block { u16 index_values[HC_XSTORM_DEF_SB_NUM_INDICES]; u16 status_block_index; - u8 reserved0; + u8 func; u8 status_block_id; u32 __flags; }; @@ -1592,7 +2110,7 @@ struct xstorm_def_status_block { struct tstorm_def_status_block { u16 index_values[HC_TSTORM_DEF_SB_NUM_INDICES]; u16 status_block_index; - u8 reserved0; + u8 func; u8 status_block_id; u32 __flags; }; @@ -1615,7 +2133,7 @@ struct host_def_status_block { struct ustorm_status_block { u16 index_values[HC_USTORM_SB_NUM_INDICES]; u16 status_block_index; - u8 reserved0; + u8 func; u8 status_block_id; u32 __flags; }; @@ -1626,7 +2144,7 @@ struct ustorm_status_block { struct cstorm_status_block { u16 index_values[HC_CSTORM_SB_NUM_INDICES]; u16 status_block_index; - u8 reserved0; + u8 func; u8 status_block_id; u32 __flags; }; @@ -1664,20 +2182,21 @@ struct eth_dynamic_hc_config { * regular eth FP CQE parameters struct */ struct eth_fast_path_rx_cqe { - u8 type; - u8 error_type_flags; -#define ETH_FAST_PATH_RX_CQE_PHY_DECODE_ERR_FLG (0x1<<0) -#define ETH_FAST_PATH_RX_CQE_PHY_DECODE_ERR_FLG_SHIFT 0 -#define ETH_FAST_PATH_RX_CQE_IP_BAD_XSUM_FLG (0x1<<1) -#define ETH_FAST_PATH_RX_CQE_IP_BAD_XSUM_FLG_SHIFT 1 -#define ETH_FAST_PATH_RX_CQE_L4_BAD_XSUM_FLG (0x1<<2) -#define ETH_FAST_PATH_RX_CQE_L4_BAD_XSUM_FLG_SHIFT 2 -#define ETH_FAST_PATH_RX_CQE_START_FLG (0x1<<3) -#define ETH_FAST_PATH_RX_CQE_START_FLG_SHIFT 3 -#define ETH_FAST_PATH_RX_CQE_END_FLG (0x1<<4) -#define ETH_FAST_PATH_RX_CQE_END_FLG_SHIFT 4 -#define ETH_FAST_PATH_RX_CQE_RESERVED0 (0x7<<5) -#define ETH_FAST_PATH_RX_CQE_RESERVED0_SHIFT 5 + u8 type_error_flags; +#define ETH_FAST_PATH_RX_CQE_TYPE (0x1<<0) +#define ETH_FAST_PATH_RX_CQE_TYPE_SHIFT 0 +#define ETH_FAST_PATH_RX_CQE_PHY_DECODE_ERR_FLG (0x1<<1) +#define ETH_FAST_PATH_RX_CQE_PHY_DECODE_ERR_FLG_SHIFT 1 +#define ETH_FAST_PATH_RX_CQE_IP_BAD_XSUM_FLG (0x1<<2) +#define ETH_FAST_PATH_RX_CQE_IP_BAD_XSUM_FLG_SHIFT 2 +#define ETH_FAST_PATH_RX_CQE_L4_BAD_XSUM_FLG (0x1<<3) +#define ETH_FAST_PATH_RX_CQE_L4_BAD_XSUM_FLG_SHIFT 3 +#define ETH_FAST_PATH_RX_CQE_START_FLG (0x1<<4) +#define ETH_FAST_PATH_RX_CQE_START_FLG_SHIFT 4 +#define ETH_FAST_PATH_RX_CQE_END_FLG (0x1<<5) +#define ETH_FAST_PATH_RX_CQE_END_FLG_SHIFT 5 +#define ETH_FAST_PATH_RX_CQE_RESERVED0 (0x3<<6) +#define ETH_FAST_PATH_RX_CQE_RESERVED0_SHIFT 6 u8 status_flags; #define ETH_FAST_PATH_RX_CQE_RSS_HASH_TYPE (0x7<<0) #define ETH_FAST_PATH_RX_CQE_RSS_HASH_TYPE_SHIFT 0 @@ -1692,11 +2211,13 @@ struct eth_fast_path_rx_cqe { #define ETH_FAST_PATH_RX_CQE_L4_XSUM_NO_VALIDATION_FLG (0x1<<7) #define ETH_FAST_PATH_RX_CQE_L4_XSUM_NO_VALIDATION_FLG_SHIFT 7 u8 placement_offset; + u8 queue_index; u32 rss_hash_result; u16 vlan_tag; u16 pkt_len; - u16 queue_index; + u16 len_on_bd; struct parsing_flags pars_flags; + u16 sgl[8]; }; @@ -1710,6 +2231,23 @@ struct eth_halt_ramrod_data { /* + * The data for statistics query ramrod + */ +struct eth_query_ramrod_data { +#if defined(__BIG_ENDIAN) + u8 reserved0; + u8 collect_port_1b; + u16 drv_counter; +#elif defined(__LITTLE_ENDIAN) + u16 drv_counter; + u8 collect_port_1b; + u8 reserved0; +#endif + u32 ctr_id_vector; +}; + + +/* * Place holder for ramrods protocol specific data */ struct ramrod_data { @@ -1739,15 +2277,20 @@ struct eth_rx_bd_next_page { * Eth Rx Cqe structure- general structure for ramrods */ struct common_ramrod_eth_rx_cqe { - u8 type; + u8 ramrod_type; +#define COMMON_RAMROD_ETH_RX_CQE_TYPE (0x1<<0) +#define COMMON_RAMROD_ETH_RX_CQE_TYPE_SHIFT 0 +#define COMMON_RAMROD_ETH_RX_CQE_RESERVED0 (0x7F<<1) +#define COMMON_RAMROD_ETH_RX_CQE_RESERVED0_SHIFT 1 u8 conn_type_3b; - u16 reserved; + u16 reserved1; u32 conn_and_cmd_data; #define COMMON_RAMROD_ETH_RX_CQE_CID (0xFFFFFF<<0) #define COMMON_RAMROD_ETH_RX_CQE_CID_SHIFT 0 #define COMMON_RAMROD_ETH_RX_CQE_CMD_ID (0xFF<<24) #define COMMON_RAMROD_ETH_RX_CQE_CMD_ID_SHIFT 24 struct ramrod_data protocol_data; + u32 reserved2[4]; }; /* @@ -1756,8 +2299,7 @@ struct common_ramrod_eth_rx_cqe { struct eth_rx_cqe_next_page { u32 addr_lo; u32 addr_hi; - u32 reserved0; - u32 reserved1; + u32 reserved[6]; }; /* @@ -1787,11 +2329,6 @@ struct spe_hdr { u16 reserved; }; -struct regpair { - u32 lo; - u32 hi; -}; - /* * ethernet slow path element */ @@ -1802,6 +2339,7 @@ union eth_specific_data { struct eth_halt_ramrod_data halt_ramrod_data; struct regpair leading_cqe_addr; struct regpair update_data_addr; + struct eth_query_ramrod_data query_ramrod_data; }; /* @@ -1824,10 +2362,13 @@ struct eth_tx_db_data { /* - * Common configuration parameters per port in Tstorm + * Common configuration parameters per function in Tstorm */ struct tstorm_eth_function_common_config { - u32 config_flags; +#if defined(__BIG_ENDIAN) + u8 leading_client_id; + u8 rss_result_mask; + u16 config_flags; #define TSTORM_ETH_FUNCTION_COMMON_CONFIG_RSS_IPV4_CAPABILITY (0x1<<0) #define TSTORM_ETH_FUNCTION_COMMON_CONFIG_RSS_IPV4_CAPABILITY_SHIFT 0 #define TSTORM_ETH_FUNCTION_COMMON_CONFIG_RSS_IPV4_TCP_CAPABILITY (0x1<<1) @@ -1840,17 +2381,32 @@ struct tstorm_eth_function_common_config { #define TSTORM_ETH_FUNCTION_COMMON_CONFIG_RSS_ENABLE_SHIFT 4 #define TSTORM_ETH_FUNCTION_COMMON_CONFIG_DEFAULT_ENABLE (0x1<<5) #define TSTORM_ETH_FUNCTION_COMMON_CONFIG_DEFAULT_ENABLE_SHIFT 5 -#define __TSTORM_ETH_FUNCTION_COMMON_CONFIG_RESERVED0 (0x3FFFFFF<<6) -#define __TSTORM_ETH_FUNCTION_COMMON_CONFIG_RESERVED0_SHIFT 6 -#if defined(__BIG_ENDIAN) - u16 __secondary_vlan_id; - u8 leading_client_id; - u8 rss_result_mask; +#define TSTORM_ETH_FUNCTION_COMMON_CONFIG_VLAN_IN_CAM (0x1<<6) +#define TSTORM_ETH_FUNCTION_COMMON_CONFIG_VLAN_IN_CAM_SHIFT 6 +#define __TSTORM_ETH_FUNCTION_COMMON_CONFIG_RESERVED0 (0x1FF<<7) +#define __TSTORM_ETH_FUNCTION_COMMON_CONFIG_RESERVED0_SHIFT 7 #elif defined(__LITTLE_ENDIAN) + u16 config_flags; +#define TSTORM_ETH_FUNCTION_COMMON_CONFIG_RSS_IPV4_CAPABILITY (0x1<<0) +#define TSTORM_ETH_FUNCTION_COMMON_CONFIG_RSS_IPV4_CAPABILITY_SHIFT 0 +#define TSTORM_ETH_FUNCTION_COMMON_CONFIG_RSS_IPV4_TCP_CAPABILITY (0x1<<1) +#define TSTORM_ETH_FUNCTION_COMMON_CONFIG_RSS_IPV4_TCP_CAPABILITY_SHIFT 1 +#define TSTORM_ETH_FUNCTION_COMMON_CONFIG_RSS_IPV6_CAPABILITY (0x1<<2) +#define TSTORM_ETH_FUNCTION_COMMON_CONFIG_RSS_IPV6_CAPABILITY_SHIFT 2 +#define TSTORM_ETH_FUNCTION_COMMON_CONFIG_RSS_IPV6_TCP_CAPABILITY (0x1<<3) +#define TSTORM_ETH_FUNCTION_COMMON_CONFIG_RSS_IPV6_TCP_CAPABILITY_SHIFT 3 +#define TSTORM_ETH_FUNCTION_COMMON_CONFIG_RSS_ENABLE (0x1<<4) +#define TSTORM_ETH_FUNCTION_COMMON_CONFIG_RSS_ENABLE_SHIFT 4 +#define TSTORM_ETH_FUNCTION_COMMON_CONFIG_DEFAULT_ENABLE (0x1<<5) +#define TSTORM_ETH_FUNCTION_COMMON_CONFIG_DEFAULT_ENABLE_SHIFT 5 +#define TSTORM_ETH_FUNCTION_COMMON_CONFIG_VLAN_IN_CAM (0x1<<6) +#define TSTORM_ETH_FUNCTION_COMMON_CONFIG_VLAN_IN_CAM_SHIFT 6 +#define __TSTORM_ETH_FUNCTION_COMMON_CONFIG_RESERVED0 (0x1FF<<7) +#define __TSTORM_ETH_FUNCTION_COMMON_CONFIG_RESERVED0_SHIFT 7 u8 rss_result_mask; u8 leading_client_id; - u16 __secondary_vlan_id; #endif + u16 vlan_id[2]; }; /* @@ -1868,7 +2424,7 @@ struct eth_update_ramrod_data { struct mac_configuration_hdr { u8 length_6b; u8 offset; - u16 reserved0; + u16 client_id; u32 reserved1; }; @@ -1925,15 +2481,55 @@ struct mac_configuration_cmd { /* + * MAC address in list for ramrod + */ +struct mac_configuration_entry_e1h { + u16 lsb_mac_addr; + u16 middle_mac_addr; + u16 msb_mac_addr; + u16 vlan_id; + u16 e1hov_id; + u8 client_id; + u8 flags; +#define MAC_CONFIGURATION_ENTRY_E1H_PORT (0x1<<0) +#define MAC_CONFIGURATION_ENTRY_E1H_PORT_SHIFT 0 +#define MAC_CONFIGURATION_ENTRY_E1H_ACTION_TYPE (0x1<<1) +#define MAC_CONFIGURATION_ENTRY_E1H_ACTION_TYPE_SHIFT 1 +#define MAC_CONFIGURATION_ENTRY_E1H_RDMA_MAC (0x1<<2) +#define MAC_CONFIGURATION_ENTRY_E1H_RDMA_MAC_SHIFT 2 +#define MAC_CONFIGURATION_ENTRY_E1H_RESERVED0 (0x1F<<3) +#define MAC_CONFIGURATION_ENTRY_E1H_RESERVED0_SHIFT 3 +}; + +/* + * MAC filtering configuration command + */ +struct mac_configuration_cmd_e1h { + struct mac_configuration_hdr hdr; + struct mac_configuration_entry_e1h config_table[32]; +}; + + +/* + * approximate-match multicast filtering for E1H per function in Tstorm + */ +struct tstorm_eth_approximate_match_multicast_filtering { + u32 mcast_add_hash_bit_array[8]; +}; + + +/* * Configuration parameters per client in Tstorm */ struct tstorm_eth_client_config { #if defined(__BIG_ENDIAN) - u16 statistics_counter_id; + u8 max_sges_for_packet; + u8 statistics_counter_id; u16 mtu; #elif defined(__LITTLE_ENDIAN) u16 mtu; - u16 statistics_counter_id; + u8 statistics_counter_id; + u8 max_sges_for_packet; #endif #if defined(__BIG_ENDIAN) u16 drop_flags; @@ -1941,42 +2537,42 @@ struct tstorm_eth_client_config { #define TSTORM_ETH_CLIENT_CONFIG_DROP_IP_CS_ERR_SHIFT 0 #define TSTORM_ETH_CLIENT_CONFIG_DROP_TCP_CS_ERR (0x1<<1) #define TSTORM_ETH_CLIENT_CONFIG_DROP_TCP_CS_ERR_SHIFT 1 -#define TSTORM_ETH_CLIENT_CONFIG_DROP_MAC_ERR (0x1<<2) -#define TSTORM_ETH_CLIENT_CONFIG_DROP_MAC_ERR_SHIFT 2 -#define TSTORM_ETH_CLIENT_CONFIG_DROP_TTL0 (0x1<<3) -#define TSTORM_ETH_CLIENT_CONFIG_DROP_TTL0_SHIFT 3 -#define TSTORM_ETH_CLIENT_CONFIG_DROP_UDP_CS_ERR (0x1<<4) -#define TSTORM_ETH_CLIENT_CONFIG_DROP_UDP_CS_ERR_SHIFT 4 -#define __TSTORM_ETH_CLIENT_CONFIG_RESERVED1 (0x7FF<<5) -#define __TSTORM_ETH_CLIENT_CONFIG_RESERVED1_SHIFT 5 +#define TSTORM_ETH_CLIENT_CONFIG_DROP_TTL0 (0x1<<2) +#define TSTORM_ETH_CLIENT_CONFIG_DROP_TTL0_SHIFT 2 +#define TSTORM_ETH_CLIENT_CONFIG_DROP_UDP_CS_ERR (0x1<<3) +#define TSTORM_ETH_CLIENT_CONFIG_DROP_UDP_CS_ERR_SHIFT 3 +#define __TSTORM_ETH_CLIENT_CONFIG_RESERVED1 (0xFFF<<4) +#define __TSTORM_ETH_CLIENT_CONFIG_RESERVED1_SHIFT 4 u16 config_flags; #define TSTORM_ETH_CLIENT_CONFIG_VLAN_REMOVAL_ENABLE (0x1<<0) #define TSTORM_ETH_CLIENT_CONFIG_VLAN_REMOVAL_ENABLE_SHIFT 0 #define TSTORM_ETH_CLIENT_CONFIG_STATSITICS_ENABLE (0x1<<1) #define TSTORM_ETH_CLIENT_CONFIG_STATSITICS_ENABLE_SHIFT 1 -#define __TSTORM_ETH_CLIENT_CONFIG_RESERVED0 (0x3FFF<<2) -#define __TSTORM_ETH_CLIENT_CONFIG_RESERVED0_SHIFT 2 +#define TSTORM_ETH_CLIENT_CONFIG_ENABLE_SGE_RING (0x1<<2) +#define TSTORM_ETH_CLIENT_CONFIG_ENABLE_SGE_RING_SHIFT 2 +#define __TSTORM_ETH_CLIENT_CONFIG_RESERVED0 (0x1FFF<<3) +#define __TSTORM_ETH_CLIENT_CONFIG_RESERVED0_SHIFT 3 #elif defined(__LITTLE_ENDIAN) u16 config_flags; #define TSTORM_ETH_CLIENT_CONFIG_VLAN_REMOVAL_ENABLE (0x1<<0) #define TSTORM_ETH_CLIENT_CONFIG_VLAN_REMOVAL_ENABLE_SHIFT 0 #define TSTORM_ETH_CLIENT_CONFIG_STATSITICS_ENABLE (0x1<<1) #define TSTORM_ETH_CLIENT_CONFIG_STATSITICS_ENABLE_SHIFT 1 -#define __TSTORM_ETH_CLIENT_CONFIG_RESERVED0 (0x3FFF<<2) -#define __TSTORM_ETH_CLIENT_CONFIG_RESERVED0_SHIFT 2 +#define TSTORM_ETH_CLIENT_CONFIG_ENABLE_SGE_RING (0x1<<2) +#define TSTORM_ETH_CLIENT_CONFIG_ENABLE_SGE_RING_SHIFT 2 +#define __TSTORM_ETH_CLIENT_CONFIG_RESERVED0 (0x1FFF<<3) +#define __TSTORM_ETH_CLIENT_CONFIG_RESERVED0_SHIFT 3 u16 drop_flags; #define TSTORM_ETH_CLIENT_CONFIG_DROP_IP_CS_ERR (0x1<<0) #define TSTORM_ETH_CLIENT_CONFIG_DROP_IP_CS_ERR_SHIFT 0 #define TSTORM_ETH_CLIENT_CONFIG_DROP_TCP_CS_ERR (0x1<<1) #define TSTORM_ETH_CLIENT_CONFIG_DROP_TCP_CS_ERR_SHIFT 1 -#define TSTORM_ETH_CLIENT_CONFIG_DROP_MAC_ERR (0x1<<2) -#define TSTORM_ETH_CLIENT_CONFIG_DROP_MAC_ERR_SHIFT 2 -#define TSTORM_ETH_CLIENT_CONFIG_DROP_TTL0 (0x1<<3) -#define TSTORM_ETH_CLIENT_CONFIG_DROP_TTL0_SHIFT 3 -#define TSTORM_ETH_CLIENT_CONFIG_DROP_UDP_CS_ERR (0x1<<4) -#define TSTORM_ETH_CLIENT_CONFIG_DROP_UDP_CS_ERR_SHIFT 4 -#define __TSTORM_ETH_CLIENT_CONFIG_RESERVED1 (0x7FF<<5) -#define __TSTORM_ETH_CLIENT_CONFIG_RESERVED1_SHIFT 5 +#define TSTORM_ETH_CLIENT_CONFIG_DROP_TTL0 (0x1<<2) +#define TSTORM_ETH_CLIENT_CONFIG_DROP_TTL0_SHIFT 2 +#define TSTORM_ETH_CLIENT_CONFIG_DROP_UDP_CS_ERR (0x1<<3) +#define TSTORM_ETH_CLIENT_CONFIG_DROP_UDP_CS_ERR_SHIFT 3 +#define __TSTORM_ETH_CLIENT_CONFIG_RESERVED1 (0xFFF<<4) +#define __TSTORM_ETH_CLIENT_CONFIG_RESERVED1_SHIFT 4 #endif }; @@ -1992,103 +2588,119 @@ struct tstorm_eth_mac_filter_config { u32 bcast_drop_all; u32 bcast_accept_all; u32 strict_vlan; - u32 __secondary_vlan_clients; + u32 vlan_filter[2]; + u32 reserved; }; -struct rate_shaping_per_protocol { +/* + * Three RX producers for ETH + */ +struct tstorm_eth_rx_producers { #if defined(__BIG_ENDIAN) - u16 reserved0; - u16 protocol_rate; + u16 bd_prod; + u16 cqe_prod; #elif defined(__LITTLE_ENDIAN) - u16 protocol_rate; - u16 reserved0; + u16 cqe_prod; + u16 bd_prod; #endif - u32 protocol_quota; - s32 current_credit; - u32 reserved; -}; - -struct rate_shaping_vars { - struct rate_shaping_per_protocol protocol_vars[NUM_OF_PROTOCOLS]; - u32 pause_mask; - u32 periodic_stop; - u32 rs_periodic_timeout; - u32 rs_threshold; - u32 last_periodic_time; - u32 reserved; -}; - -struct fairness_per_protocol { - u32 credit_delta; - s32 fair_credit; #if defined(__BIG_ENDIAN) - u16 reserved0; - u8 state; - u8 weight; + u16 reserved; + u16 sge_prod; #elif defined(__LITTLE_ENDIAN) - u8 weight; - u8 state; - u16 reserved0; + u16 sge_prod; + u16 reserved; #endif - u32 reserved1; }; -struct fairness_vars { - struct fairness_per_protocol protocol_vars[NUM_OF_PROTOCOLS]; - u32 upper_bound; - u32 port_rate; - u32 pause_mask; - u32 fair_threshold; -}; -struct safc_struct { - u32 cur_pause_mask; - u32 expire_time; +/* + * common flag to indicate existance of TPA. + */ +struct tstorm_eth_tpa_exist { #if defined(__BIG_ENDIAN) - u16 reserved0; - u8 cur_cos_types; - u8 safc_timeout_usec; + u16 reserved1; + u8 reserved0; + u8 tpa_exist; #elif defined(__LITTLE_ENDIAN) - u8 safc_timeout_usec; - u8 cur_cos_types; - u16 reserved0; + u8 tpa_exist; + u8 reserved0; + u16 reserved1; #endif - u32 reserved1; + u32 reserved2; }; -struct demo_struct { + +/* + * per-port SAFC demo variables + */ +struct cmng_flags_per_port { u8 con_number[NUM_OF_PROTOCOLS]; #if defined(__BIG_ENDIAN) - u8 reserved1; u8 fairness_enable; u8 rate_shaping_enable; - u8 cmng_enable; + u8 cmng_protocol_enable; + u8 cmng_vn_enable; #elif defined(__LITTLE_ENDIAN) - u8 cmng_enable; + u8 cmng_vn_enable; + u8 cmng_protocol_enable; u8 rate_shaping_enable; u8 fairness_enable; - u8 reserved1; #endif }; -struct cmng_struct { - struct rate_shaping_vars rs_vars; - struct fairness_vars fair_vars; - struct safc_struct safc_vars; - struct demo_struct demo_vars; + +/* + * per-port rate shaping variables + */ +struct rate_shaping_vars_per_port { + u32 rs_periodic_timeout; + u32 rs_threshold; }; -struct cos_to_protocol { - u8 mask[MAX_COS_NUMBER]; +/* + * per-port fairness variables + */ +struct fairness_vars_per_port { + u32 upper_bound; + u32 fair_threshold; + u32 fairness_timeout; }; /* - * Common statistics collected by the Xstorm (per port) + * per-port SAFC variables */ -struct xstorm_common_stats { +struct safc_struct_per_port { +#if defined(__BIG_ENDIAN) + u16 __reserved0; + u8 cur_cos_types; + u8 safc_timeout_usec; +#elif defined(__LITTLE_ENDIAN) + u8 safc_timeout_usec; + u8 cur_cos_types; + u16 __reserved0; +#endif + u8 cos_to_protocol[MAX_COS_NUMBER]; +}; + + +/* + * Per-port congestion management variables + */ +struct cmng_struct_per_port { + struct rate_shaping_vars_per_port rs_vars; + struct fairness_vars_per_port fair_vars; + struct safc_struct_per_port safc_vars; + struct cmng_flags_per_port flags; +}; + + +/* + * Protocol-common statistics collected by the Xstorm (per client) + */ +struct xstorm_per_client_stats { struct regpair total_sent_bytes; u32 total_sent_pkts; u32 unicast_pkts_sent; @@ -2097,9 +2709,31 @@ struct xstorm_common_stats { u32 multicast_pkts_sent; u32 broadcast_pkts_sent; struct regpair broadcast_bytes_sent; - struct regpair done; + u16 stats_counter; + u16 reserved0; + u32 reserved1; }; + +/* + * Common statistics collected by the Xstorm (per port) + */ +struct xstorm_common_stats { + struct xstorm_per_client_stats client_statistics[MAX_X_STAT_COUNTER_ID]; +}; + + +/* + * Protocol-common statistics collected by the Tstorm (per port) + */ +struct tstorm_per_port_stats { + u32 mac_filter_discard; + u32 xxoverflow_discard; + u32 brb_truncate_discard; + u32 mac_discard; +}; + + /* * Protocol-common statistics collected by the Tstorm (per client) */ @@ -2117,20 +2751,17 @@ struct tstorm_per_client_stats { u32 rcv_multicast_pkts; u32 no_buff_discard; u32 ttl0_discard; - u32 mac_discard; - u32 reserved; + u16 stats_counter; + u16 reserved0; + u32 reserved1; }; /* - * Protocol-common statistics collected by the Tstorm (per port) + * Protocol-common statistics collected by the Tstorm */ struct tstorm_common_stats { - struct tstorm_per_client_stats client_statistics[MAX_T_STAT_COUNTER_ID]; - u32 mac_filter_discard; - u32 xxoverflow_discard; - u32 brb_truncate_discard; - u32 reserved; - struct regpair done; + struct tstorm_per_port_stats port_statistics; + struct tstorm_per_client_stats client_statistics[MAX_T_STAT_COUNTER_ID]; }; /* @@ -2143,6 +2774,16 @@ struct eth_stats_query { /* + * per-vnic fairness variables + */ +struct fairness_vars_per_vn { + u32 protocol_credit_delta[NUM_OF_PROTOCOLS]; + u32 vn_credit_delta; + u32 __reserved0; +}; + + +/* * FW version stored in the Xstorm RAM */ struct fw_version { @@ -2160,8 +2801,10 @@ struct fw_version { #define FW_VERSION_OPTIMIZED_SHIFT 0 #define FW_VERSION_BIG_ENDIEN (0x1<<1) #define FW_VERSION_BIG_ENDIEN_SHIFT 1 -#define __FW_VERSION_RESERVED (0x3FFFFFFF<<2) -#define __FW_VERSION_RESERVED_SHIFT 2 +#define FW_VERSION_CHIP_VERSION (0x3<<2) +#define FW_VERSION_CHIP_VERSION_SHIFT 2 +#define __FW_VERSION_RESERVED (0xFFFFFFF<<4) +#define __FW_VERSION_RESERVED_SHIFT 4 }; @@ -2169,15 +2812,9 @@ struct fw_version { * FW version stored in first line of pram */ struct pram_fw_version { -#if defined(__BIG_ENDIAN) - u16 patch; - u8 primary; - u8 client; -#elif defined(__LITTLE_ENDIAN) u8 client; u8 primary; u16 patch; -#endif u8 flags; #define PRAM_FW_VERSION_OPTIMIZED (0x1<<0) #define PRAM_FW_VERSION_OPTIMIZED_SHIFT 0 @@ -2185,8 +2822,34 @@ struct pram_fw_version { #define PRAM_FW_VERSION_STORM_ID_SHIFT 1 #define PRAM_FW_VERSION_BIG_ENDIEN (0x1<<3) #define PRAM_FW_VERSION_BIG_ENDIEN_SHIFT 3 -#define __PRAM_FW_VERSION_RESERVED0 (0xF<<4) -#define __PRAM_FW_VERSION_RESERVED0_SHIFT 4 +#define PRAM_FW_VERSION_CHIP_VERSION (0x3<<4) +#define PRAM_FW_VERSION_CHIP_VERSION_SHIFT 4 +#define __PRAM_FW_VERSION_RESERVED0 (0x3<<6) +#define __PRAM_FW_VERSION_RESERVED0_SHIFT 6 +}; + + +/* + * a single rate shaping counter. can be used as protocol or vnic counter + */ +struct rate_shaping_counter { + u32 quota; +#if defined(__BIG_ENDIAN) + u16 __reserved0; + u16 rate; +#elif defined(__LITTLE_ENDIAN) + u16 rate; + u16 __reserved0; +#endif +}; + + +/* + * per-vnic rate shaping variables + */ +struct rate_shaping_vars_per_vn { + struct rate_shaping_counter protocol_counters[NUM_OF_PROTOCOLS]; + struct rate_shaping_counter vn_counter; }; diff --git a/drivers/net/bnx2x_init.h b/drivers/net/bnx2x_init.h index 370686eef97c..4c7750789b62 100644 --- a/drivers/net/bnx2x_init.h +++ b/drivers/net/bnx2x_init.h @@ -22,7 +22,8 @@ #define INIT_ASIC 0x4 #define INIT_HARDWARE 0x7 -#define STORM_INTMEM_SIZE (0x5800 / 4) +#define STORM_INTMEM_SIZE_E1 (0x5800 / 4) +#define STORM_INTMEM_SIZE_E1H (0x10000 / 4) #define TSTORM_INTMEM_ADDR 0x1a0000 #define CSTORM_INTMEM_ADDR 0x220000 #define XSTORM_INTMEM_ADDR 0x2a0000 @@ -30,7 +31,7 @@ /* Init operation types and structures */ - +/* Common for both E1 and E1H */ #define OP_RD 0x1 /* read single register */ #define OP_WR 0x2 /* write single register */ #define OP_IW 0x3 /* write single register using mailbox */ @@ -38,7 +39,37 @@ #define OP_SI 0x5 /* copy a string using mailbox */ #define OP_ZR 0x6 /* clear memory */ #define OP_ZP 0x7 /* unzip then copy with DMAE */ -#define OP_WB 0x8 /* copy a string using DMAE */ +#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 */ + struct raw_op { u32 op :8; @@ -87,10 +118,6 @@ union init_op { #include "bnx2x_init_values.h" static void bnx2x_reg_wr_ind(struct bnx2x *bp, u32 addr, u32 val); - -static void bnx2x_write_dmae(struct bnx2x *bp, dma_addr_t dma_addr, - u32 dst_addr, u32 len32); - 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, @@ -107,9 +134,6 @@ static void bnx2x_init_str_wr(struct bnx2x *bp, u32 addr, const u32 *data, } } -#define INIT_MEM_WR(reg, data, reg_off, len) \ - bnx2x_init_str_wr(bp, reg + reg_off*4, data, len) - static void bnx2x_init_ind_wr(struct bnx2x *bp, u32 addr, const u32 *data, u16 len) { @@ -124,11 +148,117 @@ static void bnx2x_init_ind_wr(struct bnx2x *bp, u32 addr, const u32 *data, } } +static void bnx2x_write_big_buf(struct bnx2x *bp, u32 addr, u32 len) +{ +#ifdef USE_DMAE + 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); +#else + bnx2x_init_str_wr(bp, addr, bp->gunzip_buf, len); +#endif +} + +static void bnx2x_init_fill(struct bnx2x *bp, u32 addr, int fill, u32 len) +{ + if ((len * 4) > FW_BUF_SIZE) { + BNX2X_ERR("LARGE DMAE OPERATION ! addr 0x%x len 0x%x\n", + addr, len*4); + return; + } + memset(bp->gunzip_buf, fill, len * 4); + + bnx2x_write_big_buf(bp, addr, 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. contigious 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) + 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 @@ -143,64 +273,59 @@ static void bnx2x_init_wr_wb(struct bnx2x *bp, u32 addr, const u32 *data, #endif rc = bnx2x_gunzip(bp, (u8 *)data, len); if (rc) { - DP(NETIF_MSG_HW, "gunzip failed ! rc %d\n", rc); + BNX2X_ERR("gunzip failed ! rc %d\n", rc); return; } len = bp->gunzip_outlen; #ifdef __BIG_ENDIAN kfree(temp); for (i = 0; i < len; i++) - ((u32 *)bp->gunzip_buf)[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 ! len 0x%x\n", len*4); + BNX2X_ERR("LARGE DMAE OPERATION ! " + "addr 0x%x len 0x%x\n", addr, len*4); return; } memcpy(bp->gunzip_buf, data, len * 4); } - while (len > DMAE_LEN32_MAX) { - bnx2x_write_dmae(bp, bp->gunzip_mapping + offset, - addr + offset, DMAE_LEN32_MAX); - offset += DMAE_LEN32_MAX * 4; - len -= DMAE_LEN32_MAX; - } - bnx2x_write_dmae(bp, bp->gunzip_mapping + offset, addr + offset, len); -} - -#define INIT_MEM_WB(reg, data, reg_off, len) \ - bnx2x_init_wr_wb(bp, reg + reg_off*4, data, len, 0) - -#define INIT_GUNZIP_DMAE(reg, data, reg_off, len) \ - bnx2x_init_wr_wb(bp, reg + reg_off*4, data, len, 1) - -static void bnx2x_init_fill(struct bnx2x *bp, u32 addr, int fill, u32 len) -{ - int offset = 0; - - if ((len * 4) > FW_BUF_SIZE) { - BNX2X_ERR("LARGE DMAE OPERATION ! len 0x%x\n", len * 4); - return; - } - memset(bp->gunzip_buf, fill, len * 4); - - while (len > DMAE_LEN32_MAX) { + 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, DMAE_LEN32_MAX); - offset += DMAE_LEN32_MAX * 4; - len -= DMAE_LEN32_MAX; - } - bnx2x_write_dmae(bp, bp->gunzip_mapping + offset, addr + offset, len); + 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 i; + 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; + 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++) { @@ -209,7 +334,30 @@ static void bnx2x_init_block(struct bnx2x *bp, u32 op_start, u32 op_end) op_type = op->str_wr.op; addr = op->str_wr.offset; len = op->str_wr.data_len; - data = init_data + op->str_wr.data_off; + data = data_base + op->str_wr.data_off; + + /* carefull! 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: @@ -222,7 +370,7 @@ static void bnx2x_init_block(struct bnx2x *bp, u32 op_start, u32 op_end) bnx2x_init_str_wr(bp, addr, data, len); break; case OP_WB: - bnx2x_init_wr_wb(bp, addr, data, len, 0); + bnx2x_init_wr_wb(bp, addr, data, len, 0, is_e1, 0); break; case OP_SI: bnx2x_init_ind_wr(bp, addr, data, len); @@ -231,10 +379,21 @@ static void bnx2x_init_block(struct bnx2x *bp, u32 op_start, u32 op_end) bnx2x_init_fill(bp, addr, 0, op->zero.len); break; case OP_ZP: - bnx2x_init_wr_wb(bp, addr, data, len, 1); + 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: - BNX2X_ERR("BAD init operation!\n"); + /* 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; } } } @@ -245,7 +404,7 @@ static void bnx2x_init_block(struct bnx2x *bp, u32 op_start, u32 op_end) ****************************************************************************/ /* * This code configures the PCI read/write arbiter - * which implements a wighted round robin + * which implements a weighted round robin * between the virtual queues in the chip. * * The values were derived for each PCI max payload and max request size. @@ -315,7 +474,7 @@ static const struct arb_line write_arb_data[NUM_WR_Q][MAX_WR_ORD + 1] = { {{8 , 64 , 25}, {16 , 64 , 41}, {32 , 64 , 81} } }; -/* register adresses for read queues */ +/* register addresses for read queues */ static const struct arb_line read_arb_addr[NUM_RD_Q-1] = { {PXP2_REG_RQ_BW_RD_L0, PXP2_REG_RQ_BW_RD_ADD0, PXP2_REG_RQ_BW_RD_UBOUND0}, @@ -375,7 +534,7 @@ static const struct arb_line read_arb_addr[NUM_RD_Q-1] = { PXP2_REG_PSWRQ_BW_UB28} }; -/* register adresses for wrtie queues */ +/* register addresses for write queues */ static const struct arb_line write_arb_addr[NUM_WR_Q-1] = { {PXP2_REG_PSWRQ_BW_L1, PXP2_REG_PSWRQ_BW_ADD1, PXP2_REG_PSWRQ_BW_UB1}, @@ -424,6 +583,10 @@ static void bnx2x_init_pxp(struct bnx2x *bp) 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++) { @@ -481,7 +644,20 @@ static void bnx2x_init_pxp(struct bnx2x *bp) REG_WR(bp, PXP2_REG_RQ_PDR_LIMIT, 0xe00); REG_WR(bp, PXP2_REG_WR_USDMDP_TH, (0x18 << w_order)); - REG_WR(bp, PXP2_REG_WR_DMAE_TH, (128 << w_order)/16); + + if (CHIP_IS_E1H(bp)) { + REG_WR(bp, PXP2_REG_WR_HC_MPS, w_order+1); + REG_WR(bp, PXP2_REG_WR_USDM_MPS, w_order+1); + REG_WR(bp, PXP2_REG_WR_CSDM_MPS, w_order+1); + REG_WR(bp, PXP2_REG_WR_TSDM_MPS, w_order+1); + REG_WR(bp, PXP2_REG_WR_XSDM_MPS, w_order+1); + REG_WR(bp, PXP2_REG_WR_QM_MPS, w_order+1); + REG_WR(bp, PXP2_REG_WR_TM_MPS, w_order+1); + REG_WR(bp, PXP2_REG_WR_SRC_MPS, w_order+1); + REG_WR(bp, PXP2_REG_WR_DBG_MPS, w_order+1); + REG_WR(bp, PXP2_REG_WR_DMAE_MPS, 2); /* DMAE is special */ + REG_WR(bp, PXP2_REG_WR_CDU_MPS, w_order+1); + } } @@ -564,6 +740,72 @@ static u8 calc_crc8(u32 data, u8 crc) return crc_res; } +/* regiesers 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} +}; #endif /* BNX2X_INIT_H */ diff --git a/drivers/net/bnx2x_init_values.h b/drivers/net/bnx2x_init_values.h index bef0a9b19d68..63019055e4bb 100644 --- a/drivers/net/bnx2x_init_values.h +++ b/drivers/net/bnx2x_init_values.h @@ -57,6 +57,7 @@ static const struct raw_op init_ops[] = { {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}, @@ -74,23 +75,27 @@ static const struct raw_op init_ops[] = { {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 46 -#define PRS_PORT0_START 46 - {OP_WR, PRS_REG_CID_PORT_0, 0x0}, -#define PRS_PORT0_END 47 -#define PRS_PORT1_START 47 - {OP_WR, PRS_REG_CID_PORT_1, 0x800000}, -#define PRS_PORT1_END 48 +#define PRS_COMMON_END 47 +#define SRCH_COMMON_START 47 + {OP_WR_E1H, SRC_REG_E1HMF_ENABLE, 0x1}, +#define SRCH_COMMON_END 48 #define TSDM_COMMON_START 48 - {OP_WR, TSDM_REG_CFC_RSP_START_ADDR, 0x411}, - {OP_WR, TSDM_REG_CMP_COUNTER_START_ADDR, 0x400}, - {OP_WR, TSDM_REG_Q_COUNTER_START_ADDR, 0x404}, - {OP_WR, TSDM_REG_PCK_END_MSG_START_ADDR, 0x419}, + {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, TSDM_REG_AGG_INT_EVENT_0, 0x80}, + {OP_ZR, TSDM_REG_AGG_INT_EVENT_0, 0x2}, + {OP_WR, TSDM_REG_AGG_INT_EVENT_2, 0x34}, + {OP_WR, TSDM_REG_AGG_INT_EVENT_3, 0x35}, + {OP_ZR, TSDM_REG_AGG_INT_EVENT_4, 0x7c}, {OP_WR, TSDM_REG_ENABLE_IN1, 0x7ffffff}, {OP_WR, TSDM_REG_ENABLE_IN2, 0x3f}, {OP_WR, TSDM_REG_ENABLE_OUT1, 0x7ffffff}, @@ -109,9 +114,12 @@ static const struct raw_op init_ops[] = { {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, TSDM_REG_TIMER_TICK, 0x3e8}, -#define TSDM_COMMON_END 76 -#define TCM_COMMON_START 76 + {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 86 +#define TCM_COMMON_START 86 {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}, @@ -143,9 +151,14 @@ static const struct raw_op init_ops[] = { {OP_WR, TCM_REG_N_SM_CTX_LD_3, 0x8}, {OP_ZR, TCM_REG_N_SM_CTX_LD_4, 0x4}, {OP_WR, TCM_REG_TCM_REG0_SZ, 0x6}, - {OP_WR, TCM_REG_PHYS_QNUM0_0, 0xd}, - {OP_WR, TCM_REG_PHYS_QNUM0_1, 0x2d}, - {OP_ZR, TCM_REG_PHYS_QNUM1_0, 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}, @@ -162,23 +175,75 @@ static const struct raw_op init_ops[] = { {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 126 -#define BRB1_COMMON_START 126 +#define TCM_COMMON_END 141 +#define TCM_FUNC0_START 141 + {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 145 +#define TCM_FUNC1_START 145 + {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 149 +#define TCM_FUNC2_START 149 + {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 153 +#define TCM_FUNC3_START 153 + {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 157 +#define TCM_FUNC4_START 157 + {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 161 +#define TCM_FUNC5_START 161 + {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 165 +#define TCM_FUNC6_START 165 + {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 169 +#define TCM_FUNC7_START 169 + {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 173 +#define BRB1_COMMON_START 173 {OP_SW, BRB1_REG_LL_RAM, 0x2000020}, {OP_WR, BRB1_REG_SOFT_RESET, 0x1}, - {OP_RD, BRB1_REG_NUM_OF_PAUSE_CYCLES_0, 0x0}, - {OP_RD, BRB1_REG_NUM_OF_PAUSE_CYCLES_1, 0x0}, - {OP_RD, BRB1_REG_NUM_OF_PAUSE_CYCLES_2, 0x0}, - {OP_RD, BRB1_REG_NUM_OF_PAUSE_CYCLES_3, 0x0}, - {OP_RD, BRB1_REG_NUM_OF_FULL_CYCLES_0, 0x0}, - {OP_RD, BRB1_REG_NUM_OF_FULL_CYCLES_1, 0x0}, - {OP_RD, BRB1_REG_NUM_OF_FULL_CYCLES_2, 0x0}, - {OP_RD, BRB1_REG_NUM_OF_FULL_CYCLES_3, 0x0}, {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 139 -#define TSEM_COMMON_START 139 +#define BRB1_COMMON_END 178 +#define BRB1_PORT0_START 178 + {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 182 +#define BRB1_PORT1_START 182 + {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 186 +#define TSEM_COMMON_START 186 {OP_RD, TSEM_REG_MSG_NUM_FIC0, 0x0}, {OP_RD, TSEM_REG_MSG_NUM_FIC1, 0x0}, {OP_RD, TSEM_REG_MSG_NUM_FOC0, 0x0}, @@ -222,106 +287,247 @@ static const struct raw_op init_ops[] = { {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, TSEM_REG_FAST_MEMORY + 0x18300, 0x7a120}, + {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, TSEM_REG_FAST_MEMORY + 0x2000, 0x1b3}, - {OP_SW, TSEM_REG_FAST_MEMORY + 0x2000 + 0x6cc, 0x10223}, - {OP_ZR, TSEM_REG_FAST_MEMORY + 0x1020, 0xc8}, - {OP_ZR, TSEM_REG_FAST_MEMORY + 0x1000, 0x2}, - {OP_ZR, TSEM_REG_FAST_MEMORY + 0x800, 0x2}, - {OP_ZR, TSEM_REG_FAST_MEMORY + 0x808, 0x2}, - {OP_ZR, TSEM_REG_FAST_MEMORY + 0x810, 0x4}, - {OP_ZR, TSEM_REG_FAST_MEMORY + 0x1fa0, 0x4}, - {OP_SW, TSEM_REG_FAST_MEMORY + 0x4cf0, 0x80224}, - {OP_ZP, TSEM_REG_INT_TABLE, 0x8c022c}, - {OP_ZP, TSEM_REG_PRAM, 0x3395024f}, - {OP_ZP, TSEM_REG_PRAM + 0x8000, 0x2c760f35}, - {OP_ZP, TSEM_REG_PRAM + 0x10000, 0x5e1a53}, - {OP_ZP, TSEM_REG_PRAM + 0x18000, 0x5e1a6b}, - {OP_ZP, TSEM_REG_PRAM + 0x20000, 0x5e1a83}, - {OP_ZP, TSEM_REG_PRAM + 0x28000, 0x5e1a9b}, - {OP_ZP, TSEM_REG_PRAM + 0x30000, 0x5e1ab3}, - {OP_ZP, TSEM_REG_PRAM + 0x38000, 0x5e1acb}, -#define TSEM_COMMON_END 202 -#define TSEM_PORT0_START 202 - {OP_ZR, TSEM_REG_FAST_MEMORY + 0x4000, 0x16c}, - {OP_SW, TSEM_REG_FAST_MEMORY + 0x4000 + 0x5b0, 0x21ae3}, - {OP_ZR, TSEM_REG_FAST_MEMORY + 0x1370, 0xa}, - {OP_ZR, TSEM_REG_FAST_MEMORY + 0x13c0, 0x6}, - {OP_ZR, TSEM_REG_FAST_MEMORY + 0x1418, 0xc}, - {OP_ZR, TSEM_REG_FAST_MEMORY + 0x1478, 0x12}, - {OP_ZR, TSEM_REG_FAST_MEMORY + 0x1508, 0x90}, - {OP_ZR, TSEM_REG_FAST_MEMORY + 0x800, 0x2}, - {OP_ZR, TSEM_REG_FAST_MEMORY + 0x820, 0x10}, - {OP_SW, TSEM_REG_FAST_MEMORY + 0x820 + 0x40, 0x21ae5}, - {OP_ZR, TSEM_REG_FAST_MEMORY + 0x2908, 0xa}, -#define TSEM_PORT0_END 213 -#define TSEM_PORT1_START 213 - {OP_ZR, TSEM_REG_FAST_MEMORY + 0x45b8, 0x16c}, - {OP_SW, TSEM_REG_FAST_MEMORY + 0x45b8 + 0x5b0, 0x21ae7}, - {OP_ZR, TSEM_REG_FAST_MEMORY + 0x1398, 0xa}, - {OP_ZR, TSEM_REG_FAST_MEMORY + 0x13d8, 0x6}, - {OP_ZR, TSEM_REG_FAST_MEMORY + 0x1448, 0xc}, - {OP_ZR, TSEM_REG_FAST_MEMORY + 0x14c0, 0x12}, - {OP_ZR, TSEM_REG_FAST_MEMORY + 0x1748, 0x90}, - {OP_ZR, TSEM_REG_FAST_MEMORY + 0x808, 0x2}, - {OP_ZR, TSEM_REG_FAST_MEMORY + 0x868, 0x10}, - {OP_SW, TSEM_REG_FAST_MEMORY + 0x868 + 0x40, 0x21ae9}, - {OP_ZR, TSEM_REG_FAST_MEMORY + 0x2930, 0xa}, -#define TSEM_PORT1_END 224 -#define MISC_COMMON_START 224 - {OP_WR, MISC_REG_GRC_TIMEOUT_EN, 0x1}, + {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 + 0x800, 0x2}, + {OP_WR_E1H, TSEM_REG_FAST_MEMORY + 0x1ad0, 0x0}, + {OP_ZR_E1, TSEM_REG_FAST_MEMORY + 0x808, 0x2}, + {OP_ZR_E1H, TSEM_REG_FAST_MEMORY + 0x3b28, 0x6}, + {OP_ZR_E1, TSEM_REG_FAST_MEMORY + 0x810, 0x4}, + {OP_ZR_E1H, TSEM_REG_FAST_MEMORY + 0x5000, 0x2}, + {OP_SW_E1, TSEM_REG_FAST_MEMORY + 0x1fb0, 0x40224}, + {OP_ZR_E1H, TSEM_REG_FAST_MEMORY + 0x5008, 0x4}, + {OP_SW_E1, TSEM_REG_FAST_MEMORY + 0x4cb0, 0x80228}, + {OP_ZR_E1H, TSEM_REG_FAST_MEMORY + 0x5018, 0x4}, + {OP_ZP_E1, TSEM_REG_INT_TABLE, 0x940000}, + {OP_ZR_E1H, TSEM_REG_FAST_MEMORY + 0x5028, 0x4}, + {OP_WR_64_E1, TSEM_REG_INT_TABLE + 0x360, 0x140230}, + {OP_ZR_E1H, TSEM_REG_FAST_MEMORY + 0x5038, 0x4}, + {OP_ZP_E1, TSEM_REG_PRAM, 0x30b10000}, + {OP_ZR_E1H, TSEM_REG_FAST_MEMORY + 0x5048, 0x4}, + {OP_ZP_E1, TSEM_REG_PRAM + 0x8000, 0x33c50c2d}, + {OP_ZR_E1H, TSEM_REG_FAST_MEMORY + 0x5058, 0x4}, + {OP_ZP_E1, TSEM_REG_PRAM + 0x10000, 0xbc6191f}, + {OP_ZR_E1H, TSEM_REG_FAST_MEMORY + 0x5068, 0x4}, + {OP_WR_64_E1, TSEM_REG_PRAM + 0x117f0, 0x5d020232}, + {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 + 0x6140, 0x200224}, + {OP_ZP_E1H, TSEM_REG_INT_TABLE, 0x960000}, + {OP_WR_64_E1H, TSEM_REG_INT_TABLE + 0x360, 0x140244}, + {OP_ZP_E1H, TSEM_REG_PRAM, 0x30cc0000}, + {OP_ZP_E1H, TSEM_REG_PRAM + 0x8000, 0x33df0c33}, + {OP_ZP_E1H, TSEM_REG_PRAM + 0x10000, 0xdce192b}, + {OP_WR_64_E1H, TSEM_REG_PRAM + 0x11c70, 0x5c720246}, +#define TSEM_COMMON_END 276 +#define TSEM_PORT0_START 276 + {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, 0xfc}, + {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, 0xfa}, + {OP_ZR_E1, TSEM_REG_FAST_MEMORY + 0x1500, 0xe}, + {OP_ZR_E1H, TSEM_REG_FAST_MEMORY + 0x8108, 0x2}, + {OP_ZR_E1, TSEM_REG_FAST_MEMORY + 0x1570, 0x12}, + {OP_ZR_E1, TSEM_REG_FAST_MEMORY + 0x9c0, 0xbe}, + {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, 0x20234}, + {OP_ZR_E1, TSEM_REG_FAST_MEMORY + 0x2908, 0x2}, +#define TSEM_PORT0_END 294 +#define TSEM_PORT1_START 294 + {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 + 0x43f0, 0xfc}, + {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 + 0x3738, 0xfa}, + {OP_ZR_E1, TSEM_REG_FAST_MEMORY + 0x1538, 0xe}, + {OP_ZR_E1H, TSEM_REG_FAST_MEMORY + 0x8110, 0x2}, + {OP_ZR_E1, TSEM_REG_FAST_MEMORY + 0x15b8, 0x12}, + {OP_ZR_E1, TSEM_REG_FAST_MEMORY + 0xcb8, 0xbe}, + {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, 0x20236}, + {OP_ZR_E1, TSEM_REG_FAST_MEMORY + 0x2910, 0x2}, +#define TSEM_PORT1_END 312 +#define TSEM_FUNC0_START 312 + {OP_WR_E1H, TSEM_REG_FAST_MEMORY + 0x2b60, 0x0}, + {OP_ZR_E1H, TSEM_REG_FAST_MEMORY + 0x3000, 0xe}, + {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 318 +#define TSEM_FUNC1_START 318 + {OP_WR_E1H, TSEM_REG_FAST_MEMORY + 0x2b64, 0x0}, + {OP_ZR_E1H, TSEM_REG_FAST_MEMORY + 0x3038, 0xe}, + {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 324 +#define TSEM_FUNC2_START 324 + {OP_WR_E1H, TSEM_REG_FAST_MEMORY + 0x2b68, 0x0}, + {OP_ZR_E1H, TSEM_REG_FAST_MEMORY + 0x3070, 0xe}, + {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, 0x20248}, +#define TSEM_FUNC2_END 330 +#define TSEM_FUNC3_START 330 + {OP_WR_E1H, TSEM_REG_FAST_MEMORY + 0x2b6c, 0x0}, + {OP_ZR_E1H, TSEM_REG_FAST_MEMORY + 0x30a8, 0xe}, + {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, 0x2024a}, +#define TSEM_FUNC3_END 336 +#define TSEM_FUNC4_START 336 + {OP_WR_E1H, TSEM_REG_FAST_MEMORY + 0x2b70, 0x0}, + {OP_ZR_E1H, TSEM_REG_FAST_MEMORY + 0x30e0, 0xe}, + {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, 0x2024c}, +#define TSEM_FUNC4_END 342 +#define TSEM_FUNC5_START 342 + {OP_WR_E1H, TSEM_REG_FAST_MEMORY + 0x2b74, 0x0}, + {OP_ZR_E1H, TSEM_REG_FAST_MEMORY + 0x3118, 0xe}, + {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, 0x2024e}, +#define TSEM_FUNC5_END 348 +#define TSEM_FUNC6_START 348 + {OP_WR_E1H, TSEM_REG_FAST_MEMORY + 0x2b78, 0x0}, + {OP_ZR_E1H, TSEM_REG_FAST_MEMORY + 0x3150, 0xe}, + {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, 0x20250}, +#define TSEM_FUNC6_END 354 +#define TSEM_FUNC7_START 354 + {OP_WR_E1H, TSEM_REG_FAST_MEMORY + 0x2b7c, 0x0}, + {OP_ZR_E1H, TSEM_REG_FAST_MEMORY + 0x3188, 0xe}, + {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, 0x20252}, +#define TSEM_FUNC7_END 360 +#define MISC_COMMON_START 360 + {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}, -#define MISC_COMMON_END 230 -#define NIG_COMMON_START 230 + {OP_WR_E1, MISC_REG_SPIO, 0xff000000}, +#define MISC_COMMON_END 367 +#define MISC_FUNC0_START 367 + {OP_WR_E1H, MISC_REG_NIG_WOL_P0, 0x0}, +#define MISC_FUNC0_END 368 +#define MISC_FUNC1_START 368 + {OP_WR_E1H, MISC_REG_NIG_WOL_P1, 0x0}, +#define MISC_FUNC1_END 369 +#define MISC_FUNC2_START 369 + {OP_WR_E1H, MISC_REG_NIG_WOL_P0, 0x0}, +#define MISC_FUNC2_END 370 +#define MISC_FUNC3_START 370 + {OP_WR_E1H, MISC_REG_NIG_WOL_P1, 0x0}, +#define MISC_FUNC3_END 371 +#define MISC_FUNC4_START 371 + {OP_WR_E1H, MISC_REG_NIG_WOL_P0, 0x0}, +#define MISC_FUNC4_END 372 +#define MISC_FUNC5_START 372 + {OP_WR_E1H, MISC_REG_NIG_WOL_P1, 0x0}, +#define MISC_FUNC5_END 373 +#define MISC_FUNC6_START 373 + {OP_WR_E1H, MISC_REG_NIG_WOL_P0, 0x0}, +#define MISC_FUNC6_END 374 +#define MISC_FUNC7_START 374 + {OP_WR_E1H, MISC_REG_NIG_WOL_P1, 0x0}, +#define MISC_FUNC7_END 375 +#define NIG_COMMON_START 375 {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 235 -#define NIG_PORT0_START 235 +#define NIG_COMMON_END 380 +#define NIG_PORT0_START 380 {OP_WR, NIG_REG_LLH0_CM_HEADER, 0x300000}, - {OP_WR, NIG_REG_LLH0_EVENT_ID, 0x26}, + {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 246 -#define NIG_PORT1_START 246 +#define NIG_PORT0_END 392 +#define NIG_PORT1_START 392 {OP_WR, NIG_REG_LLH1_CM_HEADER, 0x300000}, - {OP_WR, NIG_REG_LLH1_EVENT_ID, 0x26}, + {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 257 -#define UPB_COMMON_START 257 +#define NIG_PORT1_END 404 +#define UPB_COMMON_START 404 {OP_WR, GRCBASE_UPB + PB_REG_CONTROL, 0x20}, -#define UPB_COMMON_END 258 -#define CSDM_COMMON_START 258 - {OP_WR, CSDM_REG_CFC_RSP_START_ADDR, 0xa11}, - {OP_WR, CSDM_REG_CMP_COUNTER_START_ADDR, 0xa00}, - {OP_WR, CSDM_REG_Q_COUNTER_START_ADDR, 0xa04}, +#define UPB_COMMON_END 405 +#define CSDM_COMMON_START 405 + {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_ZR, CSDM_REG_AGG_INT_EVENT_0, 0x80}, + {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}, @@ -340,19 +546,29 @@ static const struct raw_op init_ops[] = { {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, CSDM_REG_TIMER_TICK, 0x3e8}, -#define CSDM_COMMON_END 285 -#define USDM_COMMON_START 285 - {OP_WR, USDM_REG_CFC_RSP_START_ADDR, 0xa11}, - {OP_WR, USDM_REG_CMP_COUNTER_START_ADDR, 0xa00}, - {OP_WR, USDM_REG_Q_COUNTER_START_ADDR, 0xa04}, - {OP_WR, USDM_REG_PCK_END_MSG_START_ADDR, 0xa21}, + {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 444 +#define USDM_COMMON_START 444 + {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_ZR, USDM_REG_AGG_INT_EVENT_1, 0x5f}, + {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, USDM_REG_AGG_INT_EVENT_4, 0x5c}, {OP_WR, USDM_REG_AGG_INT_MODE_0, 0x1}, {OP_ZR, USDM_REG_AGG_INT_MODE_1, 0x1f}, {OP_WR, USDM_REG_ENABLE_IN1, 0x7ffffff}, @@ -374,9 +590,12 @@ static const struct raw_op init_ops[] = { {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, USDM_REG_TIMER_TICK, 0x3e8}, -#define USDM_COMMON_END 317 -#define CCM_COMMON_START 317 + {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 486 +#define CCM_COMMON_START 486 {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}, @@ -401,23 +620,28 @@ static const struct raw_op init_ops[] = { {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, CCM_REG_XX_DESCR_TABLE, 0x241aeb}, + {OP_SW_E1, CCM_REG_XX_DESCR_TABLE, 0x240238}, + {OP_SW_E1H, CCM_REG_XX_DESCR_TABLE, 0x240254}, {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, CCM_REG_QOS_PHYS_QNUM0_0, 0x9}, - {OP_WR, CCM_REG_QOS_PHYS_QNUM0_1, 0x29}, - {OP_WR, CCM_REG_QOS_PHYS_QNUM1_0, 0xa}, - {OP_WR, CCM_REG_QOS_PHYS_QNUM1_1, 0x2a}, - {OP_ZR, CCM_REG_QOS_PHYS_QNUM2_0, 0x4}, - {OP_WR, CCM_REG_PHYS_QNUM1_0, 0xc}, - {OP_WR, CCM_REG_PHYS_QNUM1_1, 0x2c}, - {OP_WR, CCM_REG_PHYS_QNUM2_0, 0xb}, - {OP_WR, CCM_REG_PHYS_QNUM2_1, 0x2b}, - {OP_ZR, CCM_REG_PHYS_QNUM3_0, 0x2}, + {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}, @@ -433,8 +657,80 @@ static const struct raw_op init_ops[] = { {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 373 -#define UCM_COMMON_START 373 +#define CCM_COMMON_END 547 +#define CCM_FUNC0_START 547 + {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 554 +#define CCM_FUNC1_START 554 + {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 561 +#define CCM_FUNC2_START 561 + {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 568 +#define CCM_FUNC3_START 568 + {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 575 +#define CCM_FUNC4_START 575 + {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 582 +#define CCM_FUNC5_START 582 + {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 589 +#define CCM_FUNC6_START 589 + {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 596 +#define CCM_FUNC7_START 596 + {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 603 +#define UCM_COMMON_START 603 {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}, @@ -457,20 +753,23 @@ static const struct raw_op init_ops[] = { {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, 0xc}, - {OP_WR, UCM_REG_XX_MSG_NUM, 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, UCM_REG_XX_DESCR_TABLE, 0x201b0f}, - {OP_WR, UCM_REG_N_SM_CTX_LD_0, 0xa}, + {OP_SW_E1, UCM_REG_XX_DESCR_TABLE, 0x1b025c}, + {OP_SW_E1H, UCM_REG_XX_DESCR_TABLE, 0x1b0278}, + {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, UCM_REG_N_SM_CTX_LD_4, 0x4}, + {OP_ZR_E1, UCM_REG_N_SM_CTX_LD_4, 0x4}, + {OP_WR_E1H, UCM_REG_N_SM_CTX_LD_4, 0xd}, + {OP_ZR_E1H, UCM_REG_N_SM_CTX_LD_5, 0x3}, {OP_WR, UCM_REG_UCM_REG0_SZ, 0x3}, - {OP_WR, UCM_REG_PHYS_QNUM0_0, 0xf}, - {OP_WR, UCM_REG_PHYS_QNUM0_1, 0x2f}, - {OP_WR, UCM_REG_PHYS_QNUM1_0, 0xe}, - {OP_WR, UCM_REG_PHYS_QNUM1_1, 0x2e}, + {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}, @@ -488,8 +787,56 @@ static const struct raw_op init_ops[] = { {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 426 -#define USEM_COMMON_START 426 +#define UCM_COMMON_END 659 +#define UCM_FUNC0_START 659 + {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 663 +#define UCM_FUNC1_START 663 + {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 667 +#define UCM_FUNC2_START 667 + {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 671 +#define UCM_FUNC3_START 671 + {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 675 +#define UCM_FUNC4_START 675 + {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 679 +#define UCM_FUNC5_START 679 + {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 683 +#define UCM_FUNC6_START 683 + {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 687 +#define UCM_FUNC7_START 687 + {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 691 +#define USEM_COMMON_START 691 {OP_RD, USEM_REG_MSG_NUM_FIC0, 0x0}, {OP_RD, USEM_REG_MSG_NUM_FIC1, 0x0}, {OP_RD, USEM_REG_MSG_NUM_FOC0, 0x0}, @@ -533,87 +880,196 @@ static const struct raw_op init_ops[] = { {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, USEM_REG_FAST_MEMORY + 0x18300, 0x7a120}, + {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, USEM_REG_FAST_MEMORY + 0x18380, 0x1dcd6500}, - {OP_ZR, USEM_REG_FAST_MEMORY + 0x5000, 0x102}, - {OP_ZR, USEM_REG_FAST_MEMORY + 0x1020, 0xc8}, - {OP_ZR, USEM_REG_FAST_MEMORY + 0x1000, 0x2}, - {OP_ZR, USEM_REG_FAST_MEMORY + 0x1e20, 0x40}, - {OP_ZR, USEM_REG_FAST_MEMORY + 0x3000, 0x400}, - {OP_ZR, USEM_REG_FAST_MEMORY + 0x2400, 0x2}, - {OP_ZR, USEM_REG_FAST_MEMORY + 0x2408, 0x2}, - {OP_ZR, USEM_REG_FAST_MEMORY + 0x2410, 0x6}, - {OP_SW, USEM_REG_FAST_MEMORY + 0x2410 + 0x18, 0x21b2f}, - {OP_ZR, USEM_REG_FAST_MEMORY + 0x4b68, 0x2}, - {OP_SW, USEM_REG_FAST_MEMORY + 0x4b68 + 0x8, 0x21b31}, - {OP_ZR, USEM_REG_FAST_MEMORY + 0x4b10, 0x2}, - {OP_SW, USEM_REG_FAST_MEMORY + 0x2c30, 0x21b33}, + {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, 0x102}, + {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 + 0x57e8, 0x4}, + {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x8020, 0xc8}, + {OP_ZR_E1, USEM_REG_FAST_MEMORY + 0x57d0, 0x5}, + {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x8000, 0x2}, + {OP_SW_E1, USEM_REG_FAST_MEMORY + 0x57d0 + 0x14, 0x10277}, + {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x3760, 0x4}, + {OP_ZR_E1, USEM_REG_FAST_MEMORY + 0x1e20, 0x42}, + {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x3738, 0x9}, + {OP_ZR_E1, USEM_REG_FAST_MEMORY + 0x3000, 0x400}, + {OP_SW_E1H, USEM_REG_FAST_MEMORY + 0x3738 + 0x24, 0x10293}, + {OP_ZR_E1, USEM_REG_FAST_MEMORY + 0x2c00, 0x2}, + {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x3180, 0x42}, + {OP_SW_E1, USEM_REG_FAST_MEMORY + 0x2c00 + 0x8, 0x20278}, + {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x5000, 0x400}, + {OP_ZR_E1, USEM_REG_FAST_MEMORY + 0x4b68, 0x2}, + {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x4000, 0x2}, + {OP_SW_E1, USEM_REG_FAST_MEMORY + 0x4b68 + 0x8, 0x2027a}, + {OP_SW_E1H, USEM_REG_FAST_MEMORY + 0x4000 + 0x8, 0x20294}, + {OP_ZR_E1, USEM_REG_FAST_MEMORY + 0x4b10, 0x2}, + {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x6b68, 0x2}, + {OP_SW_E1, USEM_REG_FAST_MEMORY + 0x2830, 0x2027c}, + {OP_SW_E1H, USEM_REG_FAST_MEMORY + 0x6b68 + 0x8, 0x20296}, + {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x6b10, 0x2}, + {OP_SW_E1H, USEM_REG_FAST_MEMORY + 0x74c0, 0x20298}, {OP_WR, USEM_REG_FAST_MEMORY + 0x10800, 0x1000000}, - {OP_SW, USEM_REG_FAST_MEMORY + 0x10c00, 0x101b35}, + {OP_SW_E1, USEM_REG_FAST_MEMORY + 0x10c00, 0x10027e}, + {OP_SW_E1H, USEM_REG_FAST_MEMORY + 0x10c00, 0x10029a}, {OP_WR, USEM_REG_FAST_MEMORY + 0x10800, 0x0}, - {OP_SW, USEM_REG_FAST_MEMORY + 0x10c40, 0x101b45}, - {OP_ZP, USEM_REG_INT_TABLE, 0xb41b55}, - {OP_ZP, USEM_REG_PRAM, 0x32d01b82}, - {OP_ZP, USEM_REG_PRAM + 0x8000, 0x32172836}, - {OP_ZP, USEM_REG_PRAM + 0x10000, 0x1a7a34bc}, - {OP_ZP, USEM_REG_PRAM + 0x18000, 0x5f3b5b}, - {OP_ZP, USEM_REG_PRAM + 0x20000, 0x5f3b73}, - {OP_ZP, USEM_REG_PRAM + 0x28000, 0x5f3b8b}, - {OP_ZP, USEM_REG_PRAM + 0x30000, 0x5f3ba3}, - {OP_ZP, USEM_REG_PRAM + 0x38000, 0x5f3bbb}, -#define USEM_COMMON_END 498 -#define USEM_PORT0_START 498 - {OP_ZR, USEM_REG_FAST_MEMORY + 0x1400, 0xa0}, - {OP_ZR, USEM_REG_FAST_MEMORY + 0x1900, 0xa}, - {OP_ZR, USEM_REG_FAST_MEMORY + 0x1950, 0x2e}, - {OP_ZR, USEM_REG_FAST_MEMORY + 0x1d00, 0x24}, - {OP_ZR, USEM_REG_FAST_MEMORY + 0x3000, 0x20}, - {OP_ZR, USEM_REG_FAST_MEMORY + 0x3100, 0x20}, - {OP_ZR, USEM_REG_FAST_MEMORY + 0x3200, 0x20}, - {OP_ZR, USEM_REG_FAST_MEMORY + 0x3300, 0x20}, - {OP_ZR, USEM_REG_FAST_MEMORY + 0x3400, 0x20}, - {OP_ZR, USEM_REG_FAST_MEMORY + 0x3500, 0x20}, - {OP_ZR, USEM_REG_FAST_MEMORY + 0x3600, 0x20}, - {OP_ZR, USEM_REG_FAST_MEMORY + 0x3700, 0x20}, - {OP_ZR, USEM_REG_FAST_MEMORY + 0x3800, 0x20}, - {OP_ZR, USEM_REG_FAST_MEMORY + 0x3900, 0x20}, - {OP_ZR, USEM_REG_FAST_MEMORY + 0x3a00, 0x20}, - {OP_ZR, USEM_REG_FAST_MEMORY + 0x3b00, 0x20}, - {OP_ZR, USEM_REG_FAST_MEMORY + 0x3c00, 0x20}, - {OP_ZR, USEM_REG_FAST_MEMORY + 0x3d00, 0x20}, - {OP_ZR, USEM_REG_FAST_MEMORY + 0x3e00, 0x20}, - {OP_ZR, USEM_REG_FAST_MEMORY + 0x3f00, 0x20}, - {OP_ZR, USEM_REG_FAST_MEMORY + 0x2400, 0x2}, - {OP_ZR, USEM_REG_FAST_MEMORY + 0x4b78, 0x52}, - {OP_ZR, USEM_REG_FAST_MEMORY + 0x4e08, 0xc}, -#define USEM_PORT0_END 521 -#define USEM_PORT1_START 521 - {OP_ZR, USEM_REG_FAST_MEMORY + 0x1680, 0xa0}, - {OP_ZR, USEM_REG_FAST_MEMORY + 0x1928, 0xa}, - {OP_ZR, USEM_REG_FAST_MEMORY + 0x1a08, 0x2e}, - {OP_ZR, USEM_REG_FAST_MEMORY + 0x1d90, 0x24}, - {OP_ZR, USEM_REG_FAST_MEMORY + 0x3080, 0x20}, - {OP_ZR, USEM_REG_FAST_MEMORY + 0x3180, 0x20}, - {OP_ZR, USEM_REG_FAST_MEMORY + 0x3280, 0x20}, - {OP_ZR, USEM_REG_FAST_MEMORY + 0x3380, 0x20}, - {OP_ZR, USEM_REG_FAST_MEMORY + 0x3480, 0x20}, - {OP_ZR, USEM_REG_FAST_MEMORY + 0x3580, 0x20}, - {OP_ZR, USEM_REG_FAST_MEMORY + 0x3680, 0x20}, - {OP_ZR, USEM_REG_FAST_MEMORY + 0x3780, 0x20}, - {OP_ZR, USEM_REG_FAST_MEMORY + 0x3880, 0x20}, - {OP_ZR, USEM_REG_FAST_MEMORY + 0x3980, 0x20}, - {OP_ZR, USEM_REG_FAST_MEMORY + 0x3a80, 0x20}, - {OP_ZR, USEM_REG_FAST_MEMORY + 0x3b80, 0x20}, - {OP_ZR, USEM_REG_FAST_MEMORY + 0x3c80, 0x20}, - {OP_ZR, USEM_REG_FAST_MEMORY + 0x3d80, 0x20}, - {OP_ZR, USEM_REG_FAST_MEMORY + 0x3e80, 0x20}, - {OP_ZR, USEM_REG_FAST_MEMORY + 0x3f80, 0x20}, - {OP_ZR, USEM_REG_FAST_MEMORY + 0x2408, 0x2}, - {OP_ZR, USEM_REG_FAST_MEMORY + 0x4cc0, 0x52}, - {OP_ZR, USEM_REG_FAST_MEMORY + 0x4e38, 0xc}, -#define USEM_PORT1_END 544 -#define CSEM_COMMON_START 544 + {OP_SW_E1, USEM_REG_FAST_MEMORY + 0x10c40, 0x10028e}, + {OP_SW_E1H, USEM_REG_FAST_MEMORY + 0x10c40, 0x1002aa}, + {OP_ZP_E1, USEM_REG_INT_TABLE, 0xc20000}, + {OP_ZP_E1H, USEM_REG_INT_TABLE, 0xc40000}, + {OP_WR_64_E1, USEM_REG_INT_TABLE + 0x368, 0x13029e}, + {OP_WR_64_E1H, USEM_REG_INT_TABLE + 0x368, 0x1302ba}, + {OP_ZP_E1, USEM_REG_PRAM, 0x311c0000}, + {OP_ZP_E1H, USEM_REG_PRAM, 0x31070000}, + {OP_ZP_E1, USEM_REG_PRAM + 0x8000, 0x33450c47}, + {OP_ZP_E1H, USEM_REG_PRAM + 0x8000, 0x330e0c42}, + {OP_ZP_E1, USEM_REG_PRAM + 0x10000, 0x38561919}, + {OP_ZP_E1H, USEM_REG_PRAM + 0x10000, 0x389b1906}, + {OP_WR_64_E1, USEM_REG_PRAM + 0x17fe0, 0x500402a0}, + {OP_ZP_E1H, USEM_REG_PRAM + 0x18000, 0x132272d}, + {OP_WR_64_E1H, USEM_REG_PRAM + 0x18250, 0x4fb602bc}, +#define USEM_COMMON_END 790 +#define USEM_PORT0_START 790 + {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, 0xa}, + {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x9500, 0x28}, + {OP_ZR_E1, USEM_REG_FAST_MEMORY + 0x1950, 0x2e}, + {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x9640, 0x34}, + {OP_ZR_E1, USEM_REG_FAST_MEMORY + 0x1d00, 0x4}, + {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x3080, 0x20}, + {OP_ZR_E1, USEM_REG_FAST_MEMORY + 0x1d20, 0x20}, + {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x3288, 0x96}, + {OP_ZR_E1, USEM_REG_FAST_MEMORY + 0x5440, 0x72}, + {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x5000, 0x20}, + {OP_ZR_E1, USEM_REG_FAST_MEMORY + 0x3000, 0x20}, + {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x5100, 0x20}, + {OP_ZR_E1, USEM_REG_FAST_MEMORY + 0x3100, 0x20}, + {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x5200, 0x20}, + {OP_ZR_E1, USEM_REG_FAST_MEMORY + 0x3200, 0x20}, + {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x5300, 0x20}, + {OP_ZR_E1, USEM_REG_FAST_MEMORY + 0x3300, 0x20}, + {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x5400, 0x20}, + {OP_ZR_E1, USEM_REG_FAST_MEMORY + 0x3400, 0x20}, + {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x5500, 0x20}, + {OP_ZR_E1, USEM_REG_FAST_MEMORY + 0x3500, 0x20}, + {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x5600, 0x20}, + {OP_ZR_E1, USEM_REG_FAST_MEMORY + 0x3600, 0x20}, + {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x5700, 0x20}, + {OP_ZR_E1, USEM_REG_FAST_MEMORY + 0x3700, 0x20}, + {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x5800, 0x20}, + {OP_ZR_E1, USEM_REG_FAST_MEMORY + 0x3800, 0x20}, + {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x5900, 0x20}, + {OP_ZR_E1, USEM_REG_FAST_MEMORY + 0x3900, 0x20}, + {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x5a00, 0x20}, + {OP_ZR_E1, USEM_REG_FAST_MEMORY + 0x3a00, 0x20}, + {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x5b00, 0x20}, + {OP_ZR_E1, USEM_REG_FAST_MEMORY + 0x3b00, 0x20}, + {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x5c00, 0x20}, + {OP_ZR_E1, USEM_REG_FAST_MEMORY + 0x3c00, 0x20}, + {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x5d00, 0x20}, + {OP_ZR_E1, USEM_REG_FAST_MEMORY + 0x3d00, 0x20}, + {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x5e00, 0x20}, + {OP_ZR_E1, USEM_REG_FAST_MEMORY + 0x3e00, 0x20}, + {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x5f00, 0x20}, + {OP_ZR_E1, USEM_REG_FAST_MEMORY + 0x3f00, 0x20}, + {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x6b78, 0x52}, + {OP_ZR_E1, USEM_REG_FAST_MEMORY + 0x2c10, 0x2}, + {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x6e08, 0xc}, + {OP_ZR_E1, USEM_REG_FAST_MEMORY + 0x4b78, 0x52}, + {OP_ZR_E1, USEM_REG_FAST_MEMORY + 0x4e08, 0xc}, +#define USEM_PORT0_END 838 +#define USEM_PORT1_START 838 + {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 + 0x1928, 0xa}, + {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x95a0, 0x28}, + {OP_ZR_E1, USEM_REG_FAST_MEMORY + 0x1a08, 0x2e}, + {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x9710, 0x34}, + {OP_ZR_E1, USEM_REG_FAST_MEMORY + 0x1d10, 0x4}, + {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x3100, 0x20}, + {OP_ZR_E1, USEM_REG_FAST_MEMORY + 0x1da0, 0x20}, + {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x34e0, 0x96}, + {OP_ZR_E1, USEM_REG_FAST_MEMORY + 0x5608, 0x72}, + {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x5080, 0x20}, + {OP_ZR_E1, USEM_REG_FAST_MEMORY + 0x3080, 0x20}, + {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x5180, 0x20}, + {OP_ZR_E1, USEM_REG_FAST_MEMORY + 0x3180, 0x20}, + {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x5280, 0x20}, + {OP_ZR_E1, USEM_REG_FAST_MEMORY + 0x3280, 0x20}, + {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x5380, 0x20}, + {OP_ZR_E1, USEM_REG_FAST_MEMORY + 0x3380, 0x20}, + {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x5480, 0x20}, + {OP_ZR_E1, USEM_REG_FAST_MEMORY + 0x3480, 0x20}, + {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x5580, 0x20}, + {OP_ZR_E1, USEM_REG_FAST_MEMORY + 0x3580, 0x20}, + {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x5680, 0x20}, + {OP_ZR_E1, USEM_REG_FAST_MEMORY + 0x3680, 0x20}, + {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x5780, 0x20}, + {OP_ZR_E1, USEM_REG_FAST_MEMORY + 0x3780, 0x20}, + {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x5880, 0x20}, + {OP_ZR_E1, USEM_REG_FAST_MEMORY + 0x3880, 0x20}, + {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x5980, 0x20}, + {OP_ZR_E1, USEM_REG_FAST_MEMORY + 0x3980, 0x20}, + {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x5a80, 0x20}, + {OP_ZR_E1, USEM_REG_FAST_MEMORY + 0x3a80, 0x20}, + {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x5b80, 0x20}, + {OP_ZR_E1, USEM_REG_FAST_MEMORY + 0x3b80, 0x20}, + {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x5c80, 0x20}, + {OP_ZR_E1, USEM_REG_FAST_MEMORY + 0x3c80, 0x20}, + {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x5d80, 0x20}, + {OP_ZR_E1, USEM_REG_FAST_MEMORY + 0x3d80, 0x20}, + {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x5e80, 0x20}, + {OP_ZR_E1, USEM_REG_FAST_MEMORY + 0x3e80, 0x20}, + {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x5f80, 0x20}, + {OP_ZR_E1, USEM_REG_FAST_MEMORY + 0x3f80, 0x20}, + {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x6cc0, 0x52}, + {OP_ZR_E1, USEM_REG_FAST_MEMORY + 0x2c20, 0x2}, + {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x6e38, 0xc}, + {OP_ZR_E1, USEM_REG_FAST_MEMORY + 0x4cc0, 0x52}, + {OP_ZR_E1, USEM_REG_FAST_MEMORY + 0x4e38, 0xc}, +#define USEM_PORT1_END 886 +#define USEM_FUNC0_START 886 + {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x3000, 0x4}, + {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x4010, 0x2}, +#define USEM_FUNC0_END 888 +#define USEM_FUNC1_START 888 + {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x3010, 0x4}, + {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x4020, 0x2}, +#define USEM_FUNC1_END 890 +#define USEM_FUNC2_START 890 + {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x3020, 0x4}, + {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x4030, 0x2}, +#define USEM_FUNC2_END 892 +#define USEM_FUNC3_START 892 + {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x3030, 0x4}, + {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x4040, 0x2}, +#define USEM_FUNC3_END 894 +#define USEM_FUNC4_START 894 + {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x3040, 0x4}, + {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x4050, 0x2}, +#define USEM_FUNC4_END 896 +#define USEM_FUNC5_START 896 + {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x3050, 0x4}, + {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x4060, 0x2}, +#define USEM_FUNC5_END 898 +#define USEM_FUNC6_START 898 + {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x3060, 0x4}, + {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x4070, 0x2}, +#define USEM_FUNC6_END 900 +#define USEM_FUNC7_START 900 + {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x3070, 0x4}, + {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x4080, 0x2}, +#define USEM_FUNC7_END 902 +#define CSEM_COMMON_START 902 {OP_RD, CSEM_REG_MSG_NUM_FIC0, 0x0}, {OP_RD, CSEM_REG_MSG_NUM_FIC1, 0x0}, {OP_RD, CSEM_REG_MSG_NUM_FOC0, 0x0}, @@ -658,50 +1114,106 @@ static const struct raw_op init_ops[] = { {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, CSEM_REG_FAST_MEMORY + 0x5000, 0x42}, - {OP_ZR, CSEM_REG_FAST_MEMORY + 0x1020, 0xc8}, - {OP_ZR, CSEM_REG_FAST_MEMORY + 0x1000, 0x2}, - {OP_ZR, CSEM_REG_FAST_MEMORY + 0x2000, 0xc0}, - {OP_ZR, CSEM_REG_FAST_MEMORY + 0x3070, 0x80}, - {OP_ZR, CSEM_REG_FAST_MEMORY + 0x4280, 0x4}, - {OP_ZR, CSEM_REG_FAST_MEMORY + 0x25c0, 0x240}, - {OP_SW, CSEM_REG_FAST_MEMORY + 0x25c0 + 0x900, 0x83bd3}, + {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, 0x802a2}, + {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 + 0x6280, 0x240}, + {OP_SW_E1H, CSEM_REG_FAST_MEMORY + 0x6b88, 0x2002be}, {OP_WR, CSEM_REG_FAST_MEMORY + 0x10800, 0x13fffff}, - {OP_SW, CSEM_REG_FAST_MEMORY + 0x10c00, 0x103bdb}, + {OP_SW_E1, CSEM_REG_FAST_MEMORY + 0x10c00, 0x1002aa}, + {OP_SW_E1H, CSEM_REG_FAST_MEMORY + 0x10c00, 0x1002de}, {OP_WR, CSEM_REG_FAST_MEMORY + 0x10800, 0x0}, - {OP_SW, CSEM_REG_FAST_MEMORY + 0x10c40, 0x103beb}, - {OP_ZP, CSEM_REG_INT_TABLE, 0x5f3bfb}, - {OP_ZP, CSEM_REG_PRAM, 0x32423c13}, - {OP_ZP, CSEM_REG_PRAM + 0x8000, 0xf2148a4}, - {OP_ZP, CSEM_REG_PRAM + 0x10000, 0x5f4c6d}, - {OP_ZP, CSEM_REG_PRAM + 0x18000, 0x5f4c85}, - {OP_ZP, CSEM_REG_PRAM + 0x20000, 0x5f4c9d}, - {OP_ZP, CSEM_REG_PRAM + 0x28000, 0x5f4cb5}, - {OP_ZP, CSEM_REG_PRAM + 0x30000, 0x5f4ccd}, - {OP_ZP, CSEM_REG_PRAM + 0x38000, 0x5f4ce5}, -#define CSEM_COMMON_END 609 -#define CSEM_PORT0_START 609 - {OP_ZR, CSEM_REG_FAST_MEMORY + 0x1400, 0xa0}, - {OP_ZR, CSEM_REG_FAST_MEMORY + 0x1900, 0x10}, - {OP_ZR, CSEM_REG_FAST_MEMORY + 0x1980, 0x30}, - {OP_ZR, CSEM_REG_FAST_MEMORY + 0x2300, 0x2}, - {OP_SW, CSEM_REG_FAST_MEMORY + 0x2300 + 0x8, 0x24cfd}, - {OP_ZR, CSEM_REG_FAST_MEMORY + 0x3040, 0x6}, - {OP_ZR, CSEM_REG_FAST_MEMORY + 0x2410, 0x30}, -#define CSEM_PORT0_END 616 -#define CSEM_PORT1_START 616 - {OP_ZR, CSEM_REG_FAST_MEMORY + 0x1680, 0xa0}, - {OP_ZR, CSEM_REG_FAST_MEMORY + 0x1940, 0x10}, - {OP_ZR, CSEM_REG_FAST_MEMORY + 0x1a40, 0x30}, - {OP_ZR, CSEM_REG_FAST_MEMORY + 0x2310, 0x2}, - {OP_SW, CSEM_REG_FAST_MEMORY + 0x2310 + 0x8, 0x24cff}, - {OP_ZR, CSEM_REG_FAST_MEMORY + 0x3058, 0x6}, - {OP_ZR, CSEM_REG_FAST_MEMORY + 0x24d0, 0x30}, -#define CSEM_PORT1_END 623 -#define XPB_COMMON_START 623 + {OP_SW_E1, CSEM_REG_FAST_MEMORY + 0x10c40, 0x1002ba}, + {OP_SW_E1H, CSEM_REG_FAST_MEMORY + 0x10c40, 0x1002ee}, + {OP_ZP_E1, CSEM_REG_INT_TABLE, 0x6e0000}, + {OP_ZP_E1H, CSEM_REG_INT_TABLE, 0x6f0000}, + {OP_WR_64_E1, CSEM_REG_INT_TABLE + 0x380, 0x1002ca}, + {OP_WR_64_E1H, CSEM_REG_INT_TABLE + 0x380, 0x1002fe}, + {OP_ZP_E1, CSEM_REG_PRAM, 0x32580000}, + {OP_ZP_E1H, CSEM_REG_PRAM, 0x31fa0000}, + {OP_ZP_E1, CSEM_REG_PRAM + 0x8000, 0x18270c96}, + {OP_ZP_E1H, CSEM_REG_PRAM + 0x8000, 0x19040c7f}, + {OP_WR_64_E1, CSEM_REG_PRAM + 0xb210, 0x682402cc}, + {OP_WR_64_E1H, CSEM_REG_PRAM + 0xb430, 0x67e00300}, +#define CSEM_COMMON_END 981 +#define CSEM_PORT0_START 981 + {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_E1H, CSEM_REG_FAST_MEMORY + 0x6040, 0x30}, + {OP_ZR_E1, CSEM_REG_FAST_MEMORY + 0x3040, 0x6}, + {OP_ZR_E1, CSEM_REG_FAST_MEMORY + 0x2410, 0x30}, +#define CSEM_PORT0_END 993 +#define CSEM_PORT1_START 993 + {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_E1H, CSEM_REG_FAST_MEMORY + 0x6100, 0x30}, + {OP_ZR_E1, CSEM_REG_FAST_MEMORY + 0x3058, 0x6}, + {OP_ZR_E1, CSEM_REG_FAST_MEMORY + 0x24d0, 0x30}, +#define CSEM_PORT1_END 1005 +#define CSEM_FUNC0_START 1005 + {OP_WR_E1H, CSEM_REG_FAST_MEMORY + 0x1148, 0x0}, + {OP_ZR_E1H, CSEM_REG_FAST_MEMORY + 0x3300, 0x2}, +#define CSEM_FUNC0_END 1007 +#define CSEM_FUNC1_START 1007 + {OP_WR_E1H, CSEM_REG_FAST_MEMORY + 0x114c, 0x0}, + {OP_ZR_E1H, CSEM_REG_FAST_MEMORY + 0x3308, 0x2}, +#define CSEM_FUNC1_END 1009 +#define CSEM_FUNC2_START 1009 + {OP_WR_E1H, CSEM_REG_FAST_MEMORY + 0x1150, 0x0}, + {OP_ZR_E1H, CSEM_REG_FAST_MEMORY + 0x3310, 0x2}, +#define CSEM_FUNC2_END 1011 +#define CSEM_FUNC3_START 1011 + {OP_WR_E1H, CSEM_REG_FAST_MEMORY + 0x1154, 0x0}, + {OP_ZR_E1H, CSEM_REG_FAST_MEMORY + 0x3318, 0x2}, +#define CSEM_FUNC3_END 1013 +#define CSEM_FUNC4_START 1013 + {OP_WR_E1H, CSEM_REG_FAST_MEMORY + 0x1158, 0x0}, + {OP_ZR_E1H, CSEM_REG_FAST_MEMORY + 0x3320, 0x2}, +#define CSEM_FUNC4_END 1015 +#define CSEM_FUNC5_START 1015 + {OP_WR_E1H, CSEM_REG_FAST_MEMORY + 0x115c, 0x0}, + {OP_ZR_E1H, CSEM_REG_FAST_MEMORY + 0x3328, 0x2}, +#define CSEM_FUNC5_END 1017 +#define CSEM_FUNC6_START 1017 + {OP_WR_E1H, CSEM_REG_FAST_MEMORY + 0x1160, 0x0}, + {OP_ZR_E1H, CSEM_REG_FAST_MEMORY + 0x3330, 0x2}, +#define CSEM_FUNC6_END 1019 +#define CSEM_FUNC7_START 1019 + {OP_WR_E1H, CSEM_REG_FAST_MEMORY + 0x1164, 0x0}, + {OP_ZR_E1H, CSEM_REG_FAST_MEMORY + 0x3338, 0x2}, +#define CSEM_FUNC7_END 1021 +#define XPB_COMMON_START 1021 {OP_WR, GRCBASE_XPB + PB_REG_CONTROL, 0x20}, -#define XPB_COMMON_END 624 -#define DQ_COMMON_START 624 +#define XPB_COMMON_END 1022 +#define DQ_COMMON_START 1022 {OP_WR, DORQ_REG_MODE_ACT, 0x2}, {OP_WR, DORQ_REG_NORM_CID_OFST, 0x3}, {OP_WR, DORQ_REG_OUTST_REQ, 0x4}, @@ -720,8 +1232,8 @@ static const struct raw_op init_ops[] = { {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 642 -#define TIMERS_COMMON_START 642 +#define DQ_COMMON_END 1040 +#define TIMERS_COMMON_START 1040 {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}, @@ -730,8 +1242,11 @@ static const struct raw_op init_ops[] = { {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, TM_REG_PCIARB_CRDCNT_VAL, 0x2}, - {OP_WR, TM_REG_TIMER_TICK_SIZE, 0x3d090}, + {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}, @@ -741,24 +1256,37 @@ static const struct raw_op init_ops[] = { {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 661 -#define TIMERS_PORT0_START 661 +#define TIMERS_COMMON_END 1062 +#define TIMERS_PORT0_START 1062 {OP_ZR, TM_REG_LIN0_PHY_ADDR, 0x2}, -#define TIMERS_PORT0_END 662 -#define TIMERS_PORT1_START 662 +#define TIMERS_PORT0_END 1063 +#define TIMERS_PORT1_START 1063 {OP_ZR, TM_REG_LIN1_PHY_ADDR, 0x2}, -#define TIMERS_PORT1_END 663 -#define XSDM_COMMON_START 663 - {OP_WR, XSDM_REG_CFC_RSP_START_ADDR, 0xa14}, - {OP_WR, XSDM_REG_CMP_COUNTER_START_ADDR, 0xa00}, - {OP_WR, XSDM_REG_Q_COUNTER_START_ADDR, 0xa04}, +#define TIMERS_PORT1_END 1064 +#define XSDM_COMMON_START 1064 + {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_ZR, XSDM_REG_AGG_INT_EVENT_2, 0x5e}, + {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_ZR, XSDM_REG_AGG_INT_EVENT_12, 0x54}, {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}, @@ -779,9 +1307,12 @@ static const struct raw_op init_ops[] = { {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, XSDM_REG_TIMER_TICK, 0x3e8}, -#define XSDM_COMMON_END 694 -#define QM_COMMON_START 694 + {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 1111 +#define QM_COMMON_START 1111 {OP_WR, QM_REG_ACTCTRINITVAL_0, 0x6}, {OP_WR, QM_REG_ACTCTRINITVAL_1, 0x5}, {OP_WR, QM_REG_ACTCTRINITVAL_2, 0xa}, @@ -820,13 +1351,27 @@ static const struct raw_op init_ops[] = { {OP_WR, QM_REG_WRRWEIGHTS_3, 0x1010120}, {OP_ZR, QM_REG_QVOQIDX_17, 0x4}, {OP_WR, QM_REG_WRRWEIGHTS_4, 0x1010101}, - {OP_ZR, QM_REG_QVOQIDX_21, 0x4}, - {OP_WR, QM_REG_WRRWEIGHTS_5, 0x1010101}, - {OP_ZR, QM_REG_QVOQIDX_25, 0x4}, - {OP_WR, QM_REG_WRRWEIGHTS_6, 0x1010101}, - {OP_ZR, QM_REG_QVOQIDX_29, 0x3}, + {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, QM_REG_WRRWEIGHTS_7, 0x1010101}, + {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}, @@ -853,36 +1398,169 @@ static const struct raw_op init_ops[] = { {OP_WR, QM_REG_QVOQIDX_52, 0x1}, {OP_WR, QM_REG_WRRWEIGHTS_12, 0x1010101}, {OP_WR, QM_REG_QVOQIDX_53, 0x1}, - {OP_WR, QM_REG_QVOQIDX_54, 0x1}, - {OP_WR, QM_REG_QVOQIDX_55, 0x1}, - {OP_WR, QM_REG_QVOQIDX_56, 0x1}, - {OP_WR, QM_REG_WRRWEIGHTS_13, 0x1010101}, - {OP_WR, QM_REG_QVOQIDX_57, 0x1}, - {OP_WR, QM_REG_QVOQIDX_58, 0x1}, - {OP_WR, QM_REG_QVOQIDX_59, 0x1}, - {OP_WR, QM_REG_QVOQIDX_60, 0x1}, - {OP_WR, QM_REG_WRRWEIGHTS_14, 0x1010101}, - {OP_WR, QM_REG_QVOQIDX_61, 0x1}, - {OP_WR, QM_REG_QVOQIDX_62, 0x1}, - {OP_WR, QM_REG_QVOQIDX_63, 0x1}, - {OP_WR, QM_REG_WRRWEIGHTS_15, 0x1010101}, - {OP_WR, QM_REG_VOQQMASK_0_LSB, 0xffff003f}, - {OP_ZR, QM_REG_VOQQMASK_0_MSB, 0x2}, - {OP_WR, QM_REG_VOQQMASK_1_MSB, 0xffff003f}, - {OP_WR, QM_REG_VOQQMASK_2_LSB, 0x100}, - {OP_WR, QM_REG_VOQQMASK_2_MSB, 0x100}, + {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, QM_REG_VOQQMASK_4_LSB, 0xc0}, - {OP_WR, QM_REG_VOQQMASK_4_MSB, 0xc0}, - {OP_WR, QM_REG_VOQQMASK_5_LSB, 0x1e00}, - {OP_WR, QM_REG_VOQQMASK_5_MSB, 0x1e00}, - {OP_WR, QM_REG_VOQQMASK_6_LSB, 0x4000}, - {OP_WR, QM_REG_VOQQMASK_6_MSB, 0x4000}, - {OP_WR, QM_REG_VOQQMASK_7_LSB, 0x8000}, - {OP_WR, QM_REG_VOQQMASK_7_MSB, 0x8000}, - {OP_WR, QM_REG_VOQQMASK_8_LSB, 0x2000}, - {OP_WR, QM_REG_VOQQMASK_8_MSB, 0x2000}, - {OP_ZR, QM_REG_VOQQMASK_9_LSB, 0x7}, + {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}, @@ -893,8 +1571,12 @@ static const struct raw_op init_ops[] = { {OP_WR, QM_REG_CMINTVOQMASK_5, 0x80}, {OP_WR, QM_REG_CMINTVOQMASK_6, 0x200}, {OP_WR, QM_REG_CMINTVOQMASK_7, 0x0}, - {OP_WR, QM_REG_HWAEMPTYMASK_LSB, 0xffff01ff}, - {OP_WR, QM_REG_HWAEMPTYMASK_MSB, 0xffff01ff}, + {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}, @@ -910,15 +1592,29 @@ static const struct raw_op init_ops[] = { {OP_WR, QM_REG_BYTECRDINITVAL, 0x8000}, {OP_WR, QM_REG_BYTECRDCOST, 0x25e4}, {OP_WR, QM_REG_BYTECREDITAFULLTHR, 0x7fff}, - {OP_WR, QM_REG_ENBYTECRD_LSB, 0x7}, - {OP_WR, QM_REG_ENBYTECRD_MSB, 0x7}, + {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, QM_REG_FUNCNUMSEL_LSB, 0x0}, - {OP_WR, QM_REG_FUNCNUMSEL_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 829 -#define PBF_COMMON_START 829 +#define QM_COMMON_END 1411 +#define PBF_COMMON_START 1411 {OP_WR, PBF_REG_INIT, 0x1}, {OP_WR, PBF_REG_INIT_P4, 0x1}, {OP_WR, PBF_REG_MAC_LB_ENABLE, 0x1}, @@ -926,20 +1622,20 @@ static const struct raw_op init_ops[] = { {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 836 -#define PBF_PORT0_START 836 +#define PBF_COMMON_END 1418 +#define PBF_PORT0_START 1418 {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 840 -#define PBF_PORT1_START 840 +#define PBF_PORT0_END 1422 +#define PBF_PORT1_START 1422 {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 844 -#define XCM_COMMON_START 844 +#define PBF_PORT1_END 1426 +#define XCM_COMMON_START 1426 {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}, @@ -971,14 +1667,18 @@ static const struct raw_op init_ops[] = { {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, XCM_REG_XX_MSG_NUM, 0x1f}, + {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, XCM_REG_XX_DESCR_TABLE, 0x1f4d01}, + {OP_SW_E1, XCM_REG_XX_DESCR_TABLE, 0x1f02ce}, + {OP_SW_E1H, XCM_REG_XX_DESCR_TABLE, 0x1f0302}, {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, XCM_REG_N_SM_CTX_LD_4, 0x4}, + {OP_ZR_E1, XCM_REG_N_SM_CTX_LD_4, 0x4}, + {OP_WR_E1H, XCM_REG_N_SM_CTX_LD_4, 0xc}, + {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}, @@ -1000,28 +1700,116 @@ static const struct raw_op init_ops[] = { {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 904 -#define XCM_PORT0_START 904 - {OP_WR, XCM_REG_GLB_DEL_ACK_TMR_VAL_0, 0xc8}, - {OP_WR, XCM_REG_GLB_DEL_ACK_MAX_CNT_0, 0x2}, - {OP_WR, XCM_REG_WU_DA_SET_TMR_CNT_FLG_CMD00, 0x0}, - {OP_WR, XCM_REG_WU_DA_SET_TMR_CNT_FLG_CMD10, 0x0}, - {OP_WR, XCM_REG_WU_DA_CNT_CMD00, 0x2}, - {OP_WR, XCM_REG_WU_DA_CNT_CMD10, 0x2}, - {OP_WR, XCM_REG_WU_DA_CNT_UPD_VAL00, 0xff}, - {OP_WR, XCM_REG_WU_DA_CNT_UPD_VAL10, 0xff}, -#define XCM_PORT0_END 912 -#define XCM_PORT1_START 912 - {OP_WR, XCM_REG_GLB_DEL_ACK_TMR_VAL_1, 0xc8}, - {OP_WR, XCM_REG_GLB_DEL_ACK_MAX_CNT_1, 0x2}, - {OP_WR, XCM_REG_WU_DA_SET_TMR_CNT_FLG_CMD01, 0x0}, - {OP_WR, XCM_REG_WU_DA_SET_TMR_CNT_FLG_CMD11, 0x0}, - {OP_WR, XCM_REG_WU_DA_CNT_CMD01, 0x2}, - {OP_WR, XCM_REG_WU_DA_CNT_CMD11, 0x2}, - {OP_WR, XCM_REG_WU_DA_CNT_UPD_VAL01, 0xff}, - {OP_WR, XCM_REG_WU_DA_CNT_UPD_VAL11, 0xff}, -#define XCM_PORT1_END 920 -#define XSEM_COMMON_START 920 +#define XCM_COMMON_END 1490 +#define XCM_PORT0_START 1490 + {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 1498 +#define XCM_PORT1_START 1498 + {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 1506 +#define XCM_FUNC0_START 1506 + {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 1515 +#define XCM_FUNC1_START 1515 + {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 1524 +#define XCM_FUNC2_START 1524 + {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 1533 +#define XCM_FUNC3_START 1533 + {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 1542 +#define XCM_FUNC4_START 1542 + {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 1551 +#define XCM_FUNC5_START 1551 + {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 1560 +#define XCM_FUNC6_START 1560 + {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 1569 +#define XCM_FUNC7_START 1569 + {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 1578 +#define XSEM_COMMON_START 1578 {OP_RD, XSEM_REG_MSG_NUM_FIC0, 0x0}, {OP_RD, XSEM_REG_MSG_NUM_FIC1, 0x0}, {OP_RD, XSEM_REG_MSG_NUM_FOC0, 0x0}, @@ -1065,157 +1853,402 @@ static const struct raw_op init_ops[] = { {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, XSEM_REG_FAST_MEMORY + 0x18300, 0x7a120}, + {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, XSEM_REG_FAST_MEMORY + 0x18340, 0x1f4}, - {OP_WR, XSEM_REG_FAST_MEMORY + 0x18380, 0x1dcd6500}, - {OP_ZR, XSEM_REG_FAST_MEMORY + 0x55d8, 0x2}, - {OP_ZR, XSEM_REG_FAST_MEMORY + 0x5000, 0x48}, - {OP_ZR, XSEM_REG_FAST_MEMORY + 0x1020, 0xc8}, - {OP_ZR, XSEM_REG_FAST_MEMORY + 0x1000, 0x2}, - {OP_ZR, XSEM_REG_FAST_MEMORY + 0x5128, 0x92}, - {OP_WR, XSEM_REG_FAST_MEMORY + 0x5378, 0x0}, - {OP_SW, XSEM_REG_FAST_MEMORY + 0x5380, 0x24d20}, - {OP_SW, XSEM_REG_FAST_MEMORY + 0x5428, 0x44d22}, - {OP_WR, XSEM_REG_FAST_MEMORY + 0x1518, 0x1}, - {OP_WR, XSEM_REG_FAST_MEMORY + 0x1830, 0x0}, - {OP_WR, XSEM_REG_FAST_MEMORY + 0x1838, 0x0}, - {OP_SW, XSEM_REG_FAST_MEMORY + 0x1820, 0x24d26}, - {OP_ZR, XSEM_REG_FAST_MEMORY + 0x4ac0, 0x2}, - {OP_SW, XSEM_REG_FAST_MEMORY + 0x4ad8, 0x24d28}, - {OP_ZR, XSEM_REG_FAST_MEMORY + 0x4b08, 0x4}, - {OP_SW, XSEM_REG_FAST_MEMORY + 0x1f50, 0x24d2a}, + {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 + 0x3d00, 0x4}, + {OP_WR_E1H, XSEM_REG_FAST_MEMORY + 0x11480, 0x1}, + {OP_ZR_E1, XSEM_REG_FAST_MEMORY + 0x3000, 0x48}, + {OP_ZR_E1H, XSEM_REG_FAST_MEMORY + 0x28a8, 0x4}, + {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, 0x202ed}, + {OP_ZR_E1H, XSEM_REG_FAST_MEMORY + 0x2000, 0x20}, + {OP_SW_E1, XSEM_REG_FAST_MEMORY + 0x3b90, 0x402ef}, + {OP_WR_E1H, XSEM_REG_FAST_MEMORY + 0x23c8, 0x0}, + {OP_WR_E1, XSEM_REG_FAST_MEMORY + 0x1518, 0x1}, + {OP_SW_E1H, XSEM_REG_FAST_MEMORY + 0x23d0, 0x20321}, + {OP_WR_E1, XSEM_REG_FAST_MEMORY + 0x1830, 0x0}, + {OP_SW_E1H, XSEM_REG_FAST_MEMORY + 0x2498, 0x40323}, + {OP_WR_E1, XSEM_REG_FAST_MEMORY + 0x1838, 0x0}, + {OP_WR_E1H, XSEM_REG_FAST_MEMORY + 0x2ac8, 0x0}, + {OP_SW_E1, XSEM_REG_FAST_MEMORY + 0x1820, 0x202f3}, + {OP_WR_E1H, XSEM_REG_FAST_MEMORY + 0x2ab8, 0x0}, + {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 + 0x1f50, 0x202f5}, + {OP_SW_E1H, XSEM_REG_FAST_MEMORY + 0x4000, 0x100327}, + {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 + 0x83b0, 0x20337}, {OP_WR, XSEM_REG_FAST_MEMORY + 0x10800, 0x0}, - {OP_SW, XSEM_REG_FAST_MEMORY + 0x10c00, 0x104d2c}, + {OP_SW_E1, XSEM_REG_FAST_MEMORY + 0x10c00, 0x1002f7}, + {OP_SW_E1H, XSEM_REG_FAST_MEMORY + 0x10c00, 0x100339}, {OP_WR, XSEM_REG_FAST_MEMORY + 0x10800, 0x1000000}, - {OP_SW, XSEM_REG_FAST_MEMORY + 0x10c40, 0x84d3c}, + {OP_SW_E1, XSEM_REG_FAST_MEMORY + 0x10c40, 0x80307}, + {OP_SW_E1H, XSEM_REG_FAST_MEMORY + 0x10c40, 0x80349}, {OP_WR, XSEM_REG_FAST_MEMORY + 0x10800, 0x2000000}, - {OP_SW, XSEM_REG_FAST_MEMORY + 0x10c60, 0x84d44}, - {OP_WR, XSEM_REG_FAST_MEMORY + 0x10800, 0x3000000}, - {OP_SW, XSEM_REG_FAST_MEMORY + 0x10c80, 0x84d4c}, - {OP_ZP, XSEM_REG_INT_TABLE, 0x814d54}, - {OP_ZP, XSEM_REG_PRAM, 0x35774d75}, - {OP_ZP, XSEM_REG_PRAM + 0x8000, 0x36525ad3}, - {OP_ZP, XSEM_REG_PRAM + 0x10000, 0x27266868}, - {OP_ZP, XSEM_REG_PRAM + 0x18000, 0x5e7232}, - {OP_ZP, XSEM_REG_PRAM + 0x20000, 0x5e724a}, - {OP_ZP, XSEM_REG_PRAM + 0x28000, 0x5e7262}, - {OP_ZP, XSEM_REG_PRAM + 0x30000, 0x5e727a}, - {OP_ZP, XSEM_REG_PRAM + 0x38000, 0x5e7292}, -#define XSEM_COMMON_END 1000 -#define XSEM_PORT0_START 1000 - {OP_ZR, XSEM_REG_FAST_MEMORY + 0x1400, 0xa}, - {OP_ZR, XSEM_REG_FAST_MEMORY + 0x1450, 0x6}, - {OP_ZR, XSEM_REG_FAST_MEMORY + 0x5388, 0xc}, - {OP_SW, XSEM_REG_FAST_MEMORY + 0x5388 + 0x30, 0x272aa}, - {OP_SW, XSEM_REG_FAST_MEMORY + 0x55e0, 0x772ac}, - {OP_ZR, XSEM_REG_FAST_MEMORY + 0x5600, 0x7}, - {OP_WR, XSEM_REG_FAST_MEMORY + 0x1500, 0x0}, - {OP_WR, XSEM_REG_FAST_MEMORY + 0x1508, 0x1}, - {OP_ZR, XSEM_REG_FAST_MEMORY + 0x3020, 0x2}, - {OP_ZR, XSEM_REG_FAST_MEMORY + 0x3030, 0x2}, - {OP_ZR, XSEM_REG_FAST_MEMORY + 0x3000, 0x2}, - {OP_ZR, XSEM_REG_FAST_MEMORY + 0x3010, 0x2}, - {OP_WR, XSEM_REG_FAST_MEMORY + 0x3040, 0x0}, - {OP_ZR, XSEM_REG_FAST_MEMORY + 0x3048, 0xc}, - {OP_SW, XSEM_REG_FAST_MEMORY + 0x3048 + 0x30, 0x272b3}, - {OP_WR, XSEM_REG_FAST_MEMORY + 0x30b8, 0x1}, - {OP_SW, XSEM_REG_FAST_MEMORY + 0x4ac8, 0x272b5}, - {OP_ZR, XSEM_REG_FAST_MEMORY + 0x4b18, 0x42}, - {OP_ZR, XSEM_REG_FAST_MEMORY + 0x4d28, 0x4}, -#define XSEM_PORT0_END 1019 -#define XSEM_PORT1_START 1019 - {OP_ZR, XSEM_REG_FAST_MEMORY + 0x1428, 0xa}, - {OP_ZR, XSEM_REG_FAST_MEMORY + 0x1468, 0x6}, - {OP_ZR, XSEM_REG_FAST_MEMORY + 0x53c0, 0xc}, - {OP_SW, XSEM_REG_FAST_MEMORY + 0x53c0 + 0x30, 0x272b7}, - {OP_SW, XSEM_REG_FAST_MEMORY + 0x5620, 0x772b9}, - {OP_ZR, XSEM_REG_FAST_MEMORY + 0x5640, 0x7}, - {OP_WR, XSEM_REG_FAST_MEMORY + 0x1504, 0x0}, - {OP_WR, XSEM_REG_FAST_MEMORY + 0x150c, 0x1}, - {OP_ZR, XSEM_REG_FAST_MEMORY + 0x3028, 0x2}, - {OP_ZR, XSEM_REG_FAST_MEMORY + 0x3038, 0x2}, - {OP_ZR, XSEM_REG_FAST_MEMORY + 0x3008, 0x2}, - {OP_ZR, XSEM_REG_FAST_MEMORY + 0x3018, 0x2}, - {OP_WR, XSEM_REG_FAST_MEMORY + 0x3044, 0x0}, - {OP_ZR, XSEM_REG_FAST_MEMORY + 0x3080, 0xc}, - {OP_SW, XSEM_REG_FAST_MEMORY + 0x3080 + 0x30, 0x272c0}, - {OP_WR, XSEM_REG_FAST_MEMORY + 0x30bc, 0x1}, - {OP_SW, XSEM_REG_FAST_MEMORY + 0x4ad0, 0x272c2}, - {OP_ZR, XSEM_REG_FAST_MEMORY + 0x4c20, 0x42}, - {OP_ZR, XSEM_REG_FAST_MEMORY + 0x4d38, 0x4}, -#define XSEM_PORT1_END 1038 -#define CDU_COMMON_START 1038 + {OP_SW_E1, XSEM_REG_FAST_MEMORY + 0x10c60, 0x8030f}, + {OP_SW_E1H, XSEM_REG_FAST_MEMORY + 0x10c60, 0x80351}, + {OP_ZP_E1, XSEM_REG_INT_TABLE, 0xa90000}, + {OP_ZP_E1H, XSEM_REG_INT_TABLE, 0xac0000}, + {OP_WR_64_E1, XSEM_REG_INT_TABLE + 0x368, 0x130317}, + {OP_WR_64_E1H, XSEM_REG_INT_TABLE + 0x368, 0x130359}, + {OP_ZP_E1, XSEM_REG_PRAM, 0x344e0000}, + {OP_ZP_E1H, XSEM_REG_PRAM, 0x34620000}, + {OP_ZP_E1, XSEM_REG_PRAM + 0x8000, 0x38840d14}, + {OP_ZP_E1H, XSEM_REG_PRAM + 0x8000, 0x38240d19}, + {OP_ZP_E1, XSEM_REG_PRAM + 0x10000, 0x3e711b35}, + {OP_ZP_E1H, XSEM_REG_PRAM + 0x10000, 0x3e971b22}, + {OP_ZP_E1, XSEM_REG_PRAM + 0x18000, 0x1dd02ad2}, + {OP_ZP_E1H, XSEM_REG_PRAM + 0x18000, 0x21542ac8}, + {OP_WR_64_E1, XSEM_REG_PRAM + 0x1c0d0, 0x47e60319}, + {OP_WR_64_E1H, XSEM_REG_PRAM + 0x1c8d0, 0x46e6035b}, +#define XSEM_COMMON_END 1688 +#define XSEM_PORT0_START 1688 + {OP_ZR_E1, XSEM_REG_FAST_MEMORY + 0x3ba0, 0x10}, + {OP_ZR_E1H, XSEM_REG_FAST_MEMORY + 0xc000, 0xfc}, + {OP_ZR_E1, XSEM_REG_FAST_MEMORY + 0x3c20, 0x1c}, + {OP_ZR_E1H, XSEM_REG_FAST_MEMORY + 0x24a8, 0x10}, + {OP_ZR_E1, XSEM_REG_FAST_MEMORY + 0x1400, 0xa}, + {OP_ZR_E1H, XSEM_REG_FAST_MEMORY + 0x2528, 0x1c}, + {OP_ZR_E1, XSEM_REG_FAST_MEMORY + 0x1450, 0x6}, + {OP_ZR_E1H, XSEM_REG_FAST_MEMORY + 0x2608, 0x1c}, + {OP_ZR_E1, XSEM_REG_FAST_MEMORY + 0x3378, 0xfc}, + {OP_ZR_E1H, XSEM_REG_FAST_MEMORY + 0x26e8, 0x1c}, + {OP_WR_E1, XSEM_REG_FAST_MEMORY + 0x3b58, 0x0}, + {OP_ZR_E1H, XSEM_REG_FAST_MEMORY + 0x27c8, 0x1c}, + {OP_SW_E1, XSEM_REG_FAST_MEMORY + 0x3d10, 0x10031b}, + {OP_ZR_E1H, XSEM_REG_FAST_MEMORY + 0xa000, 0x28}, + {OP_WR_E1, XSEM_REG_FAST_MEMORY + 0x1500, 0x0}, + {OP_ZR_E1H, XSEM_REG_FAST_MEMORY + 0xa140, 0xc}, + {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, 0x2035d}, + {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, 0x2032b}, + {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 1720 +#define XSEM_PORT1_START 1720 + {OP_ZR_E1, XSEM_REG_FAST_MEMORY + 0x3be0, 0x10}, + {OP_ZR_E1H, XSEM_REG_FAST_MEMORY + 0xc3f0, 0xfc}, + {OP_ZR_E1, XSEM_REG_FAST_MEMORY + 0x3c90, 0x1c}, + {OP_ZR_E1H, XSEM_REG_FAST_MEMORY + 0x24e8, 0x10}, + {OP_ZR_E1, XSEM_REG_FAST_MEMORY + 0x1428, 0xa}, + {OP_ZR_E1H, XSEM_REG_FAST_MEMORY + 0x2598, 0x1c}, + {OP_ZR_E1, XSEM_REG_FAST_MEMORY + 0x1468, 0x6}, + {OP_ZR_E1H, XSEM_REG_FAST_MEMORY + 0x2678, 0x1c}, + {OP_ZR_E1, XSEM_REG_FAST_MEMORY + 0x3768, 0xfc}, + {OP_ZR_E1H, XSEM_REG_FAST_MEMORY + 0x2758, 0x1c}, + {OP_WR_E1, XSEM_REG_FAST_MEMORY + 0x3b5c, 0x0}, + {OP_ZR_E1H, XSEM_REG_FAST_MEMORY + 0x2838, 0x1c}, + {OP_SW_E1, XSEM_REG_FAST_MEMORY + 0x3d50, 0x10032d}, + {OP_ZR_E1H, XSEM_REG_FAST_MEMORY + 0xa0a0, 0x28}, + {OP_WR_E1, XSEM_REG_FAST_MEMORY + 0x1504, 0x0}, + {OP_ZR_E1H, XSEM_REG_FAST_MEMORY + 0xa170, 0xc}, + {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, 0x2035f}, + {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, 0x2033d}, + {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 1752 +#define XSEM_FUNC0_START 1752 + {OP_WR_E1H, XSEM_REG_FAST_MEMORY + 0xc7e0, 0x0}, + {OP_SW_E1H, XSEM_REG_FAST_MEMORY + 0x28b8, 0x100361}, + {OP_ZR_E1H, XSEM_REG_FAST_MEMORY + 0x5048, 0xe}, +#define XSEM_FUNC0_END 1755 +#define XSEM_FUNC1_START 1755 + {OP_WR_E1H, XSEM_REG_FAST_MEMORY + 0xc7e4, 0x0}, + {OP_SW_E1H, XSEM_REG_FAST_MEMORY + 0x28f8, 0x100371}, + {OP_ZR_E1H, XSEM_REG_FAST_MEMORY + 0x5080, 0xe}, +#define XSEM_FUNC1_END 1758 +#define XSEM_FUNC2_START 1758 + {OP_WR_E1H, XSEM_REG_FAST_MEMORY + 0xc7e8, 0x0}, + {OP_SW_E1H, XSEM_REG_FAST_MEMORY + 0x2938, 0x100381}, + {OP_ZR_E1H, XSEM_REG_FAST_MEMORY + 0x50b8, 0xe}, +#define XSEM_FUNC2_END 1761 +#define XSEM_FUNC3_START 1761 + {OP_WR_E1H, XSEM_REG_FAST_MEMORY + 0xc7ec, 0x0}, + {OP_SW_E1H, XSEM_REG_FAST_MEMORY + 0x2978, 0x100391}, + {OP_ZR_E1H, XSEM_REG_FAST_MEMORY + 0x50f0, 0xe}, +#define XSEM_FUNC3_END 1764 +#define XSEM_FUNC4_START 1764 + {OP_WR_E1H, XSEM_REG_FAST_MEMORY + 0xc7f0, 0x0}, + {OP_SW_E1H, XSEM_REG_FAST_MEMORY + 0x29b8, 0x1003a1}, + {OP_ZR_E1H, XSEM_REG_FAST_MEMORY + 0x5128, 0xe}, +#define XSEM_FUNC4_END 1767 +#define XSEM_FUNC5_START 1767 + {OP_WR_E1H, XSEM_REG_FAST_MEMORY + 0xc7f4, 0x0}, + {OP_SW_E1H, XSEM_REG_FAST_MEMORY + 0x29f8, 0x1003b1}, + {OP_ZR_E1H, XSEM_REG_FAST_MEMORY + 0x5160, 0xe}, +#define XSEM_FUNC5_END 1770 +#define XSEM_FUNC6_START 1770 + {OP_WR_E1H, XSEM_REG_FAST_MEMORY + 0xc7f8, 0x0}, + {OP_SW_E1H, XSEM_REG_FAST_MEMORY + 0x2a38, 0x1003c1}, + {OP_ZR_E1H, XSEM_REG_FAST_MEMORY + 0x5198, 0xe}, +#define XSEM_FUNC6_END 1773 +#define XSEM_FUNC7_START 1773 + {OP_WR_E1H, XSEM_REG_FAST_MEMORY + 0xc7fc, 0x0}, + {OP_SW_E1H, XSEM_REG_FAST_MEMORY + 0x2a78, 0x1003d1}, + {OP_ZR_E1H, XSEM_REG_FAST_MEMORY + 0x51d0, 0xe}, +#define XSEM_FUNC7_END 1776 +#define CDU_COMMON_START 1776 {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, CDU_REG_L1TT, 0x20072c4}, - {OP_WB, CDU_REG_MATT, 0x2074c4}, - {OP_ZR, CDU_REG_MATT + 0x80, 0x20}, -#define CDU_COMMON_END 1044 -#define DMAE_COMMON_START 1044 + {OP_WB_E1, CDU_REG_L1TT, 0x200033f}, + {OP_WB_E1H, CDU_REG_L1TT, 0x20003e1}, + {OP_WB_E1, CDU_REG_MATT, 0x20053f}, + {OP_WB_E1H, CDU_REG_MATT, 0x2805e1}, + {OP_ZR_E1, CDU_REG_MATT + 0x80, 0x2}, + {OP_WB_E1, CDU_REG_MATT + 0x88, 0x6055f}, + {OP_ZR, CDU_REG_MATT + 0xa0, 0x18}, +#define CDU_COMMON_END 1787 +#define DMAE_COMMON_START 1787 + {OP_ZR, DMAE_REG_CMD_MEM, 0xe0}, {OP_WR, DMAE_REG_CRC16C_INIT, 0x0}, {OP_WR, DMAE_REG_CRC16T10_INIT, 0x1}, - {OP_WR, DMAE_REG_PXP_REQ_INIT_CRD, 0x2}, + {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 1049 -#define PXP_COMMON_START 1049 - {OP_SI, PXP_REG_HST_INBOUND_INT + 0x400, 0x574e4}, - {OP_SI, PXP_REG_HST_INBOUND_INT + 0x420, 0x574e9}, - {OP_SI, PXP_REG_HST_INBOUND_INT, 0x574ee}, -#define PXP_COMMON_END 1052 -#define CFC_COMMON_START 1052 +#define DMAE_COMMON_END 1794 +#define PXP_COMMON_START 1794 + {OP_WB_E1, PXP_REG_HST_INBOUND_INT + 0x400, 0x50565}, + {OP_WB_E1H, PXP_REG_HST_INBOUND_INT + 0x400, 0x50609}, + {OP_WB_E1, PXP_REG_HST_INBOUND_INT + 0x420, 0x5056a}, + {OP_WB_E1H, PXP_REG_HST_INBOUND_INT, 0x5060e}, + {OP_WB_E1, PXP_REG_HST_INBOUND_INT, 0x5056f}, +#define PXP_COMMON_END 1799 +#define CFC_COMMON_START 1799 + {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_LCREQ_WEIGHTS, 0x84924a}, -#define CFC_COMMON_END 1055 -#define HC_COMMON_START 1055 - {OP_ZR, HC_REG_USTORM_ADDR_FOR_COALESCE, 0x4}, -#define HC_COMMON_END 1056 -#define HC_PORT0_START 1056 - {OP_WR, HC_REG_CONFIG_0, 0x1080}, - {OP_ZR, HC_REG_UC_RAM_ADDR_0, 0x2}, - {OP_WR, HC_REG_ATTN_NUM_P0, 0x10}, - {OP_WR, HC_REG_LEADING_EDGE_0, 0xffff}, - {OP_WR, HC_REG_TRAILING_EDGE_0, 0xffff}, - {OP_WR, HC_REG_AGG_INT_0, 0x0}, - {OP_WR, HC_REG_ATTN_IDX, 0x0}, - {OP_ZR, HC_REG_ATTN_BIT, 0x2}, - {OP_WR, HC_REG_VQID_0, 0x2b5}, - {OP_WR, HC_REG_PCI_CONFIG_0, 0x0}, - {OP_ZR, HC_REG_P0_PROD_CONS, 0x4a}, - {OP_ZR, HC_REG_PBA_COMMAND, 0x2}, - {OP_WR, HC_REG_INT_MASK, 0x1ffff}, - {OP_WR, HC_REG_CONFIG_0, 0x1a82}, - {OP_ZR, HC_REG_STATISTIC_COUNTERS, 0x24}, - {OP_ZR, HC_REG_STATISTIC_COUNTERS + 0x120, 0x4a}, - {OP_ZR, HC_REG_STATISTIC_COUNTERS + 0x370, 0x4a}, - {OP_ZR, HC_REG_STATISTIC_COUNTERS + 0x5c0, 0x4a}, -#define HC_PORT0_END 1074 -#define HC_PORT1_START 1074 - {OP_WR, HC_REG_CONFIG_1, 0x1080}, - {OP_ZR, HC_REG_UC_RAM_ADDR_1, 0x2}, - {OP_WR, HC_REG_ATTN_NUM_P1, 0x10}, - {OP_WR, HC_REG_LEADING_EDGE_1, 0xffff}, - {OP_WR, HC_REG_TRAILING_EDGE_1, 0xffff}, - {OP_WR, HC_REG_AGG_INT_1, 0x0}, - {OP_WR, HC_REG_ATTN_IDX + 0x4, 0x0}, - {OP_ZR, HC_REG_ATTN_BIT + 0x8, 0x2}, - {OP_WR, HC_REG_VQID_1, 0x2b5}, - {OP_WR, HC_REG_PCI_CONFIG_1, 0x0}, - {OP_ZR, HC_REG_P1_PROD_CONS, 0x4a}, - {OP_ZR, HC_REG_PBA_COMMAND + 0x8, 0x2}, - {OP_WR, HC_REG_INT_MASK + 0x4, 0x1ffff}, - {OP_WR, HC_REG_CONFIG_1, 0x1a82}, - {OP_ZR, HC_REG_STATISTIC_COUNTERS + 0x90, 0x24}, - {OP_ZR, HC_REG_STATISTIC_COUNTERS + 0x248, 0x4a}, - {OP_ZR, HC_REG_STATISTIC_COUNTERS + 0x498, 0x4a}, - {OP_ZR, HC_REG_STATISTIC_COUNTERS + 0x6e8, 0x4a}, -#define HC_PORT1_END 1092 -#define PXP2_COMMON_START 1092 - {OP_WR, PXP2_REG_PGL_CONTROL0, 0xe38324}, +#define CFC_COMMON_END 1803 +#define HC_COMMON_START 1803 + {OP_ZR_E1, HC_REG_USTORM_ADDR_FOR_COALESCE, 0x4}, +#define HC_COMMON_END 1804 +#define HC_PORT0_START 1804 + {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 1822 +#define HC_PORT1_START 1822 + {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 1840 +#define HC_FUNC0_START 1840 + {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 1855 +#define HC_FUNC1_START 1855 + {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 1870 +#define HC_FUNC2_START 1870 + {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 1885 +#define HC_FUNC3_START 1885 + {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 1900 +#define HC_FUNC4_START 1900 + {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 1915 +#define HC_FUNC5_START 1915 + {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 1930 +#define HC_FUNC6_START 1930 + {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 1945 +#define HC_FUNC7_START 1945 + {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 1960 +#define PXP2_COMMON_START 1960 + {OP_WR_E1, PXP2_REG_PGL_CONTROL0, 0xe38340}, + {OP_WR_E1H, PXP2_REG_RQ_DRAM_ALIGN, 0x1}, {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}, @@ -1231,6 +2264,7 @@ static const struct raw_op init_ops[] = { {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}, @@ -1245,9 +2279,11 @@ static const struct raw_op init_ops[] = { {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, PXP2_REG_PGL_INT_XSDM_0, 0xffff5330}, - {OP_WR, PXP2_REG_PGL_INT_XSDM_1, 0xffff5348}, - {OP_WR, PXP2_REG_PGL_INT_USDM_0, 0xf0003000}, + {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, 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}, @@ -1257,6 +2293,7 @@ static const struct raw_op init_ops[] = { {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}, @@ -1321,58 +2358,103 @@ static const struct raw_op init_ops[] = { {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 1200 -#define MISC_AEU_COMMON_START 1200 + {OP_WR_E1H, PXP2_REG_PGL_CONTROL0, 0xe38340}, +#define PXP2_COMMON_END 2077 +#define MISC_AEU_COMMON_START 2077 {OP_ZR, MISC_REG_AEU_GENERAL_ATTN_0, 0x16}, -#define MISC_AEU_COMMON_END 1201 -#define MISC_AEU_PORT0_START 1201 - {OP_WR, MISC_REG_AEU_ENABLE1_FUNC_0_OUT_0, 0xbf5c0000}, - {OP_WR, MISC_REG_AEU_ENABLE2_FUNC_0_OUT_0, 0xfff51fef}, + {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 2096 +#define MISC_AEU_PORT0_START 2096 + {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, MISC_REG_AEU_ENABLE4_FUNC_0_OUT_0, 0x500003e0}, + {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, MISC_REG_AEU_ENABLE1_FUNC_0_OUT_3, 0x14}, - {OP_WR, MISC_REG_AEU_ENABLE1_NIG_0, 0x55540000}, - {OP_WR, MISC_REG_AEU_ENABLE2_NIG_0, 0x55555555}, - {OP_WR, MISC_REG_AEU_ENABLE3_NIG_0, 0x5555}, - {OP_WR, MISC_REG_AEU_ENABLE4_NIG_0, 0x0}, - {OP_WR, MISC_REG_AEU_ENABLE1_PXP_0, 0x55540000}, - {OP_WR, MISC_REG_AEU_ENABLE2_PXP_0, 0x55555555}, - {OP_WR, MISC_REG_AEU_ENABLE3_PXP_0, 0x5555}, - {OP_WR, MISC_REG_AEU_ENABLE4_PXP_0, 0x0}, - {OP_WR, MISC_REG_AEU_INVERTER_1_FUNC_0, 0x0}, - {OP_ZR, MISC_REG_AEU_INVERTER_2_FUNC_0, 0x3}, - {OP_WR, MISC_REG_AEU_MASK_ATTN_FUNC_0, 0x7}, -#define MISC_AEU_PORT0_END 1221 -#define MISC_AEU_PORT1_START 1221 - {OP_WR, MISC_REG_AEU_ENABLE1_FUNC_1_OUT_0, 0xbf5c0000}, - {OP_WR, MISC_REG_AEU_ENABLE2_FUNC_1_OUT_0, 0xfff51fef}, + {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 2128 +#define MISC_AEU_PORT1_START 2128 + {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, MISC_REG_AEU_ENABLE4_FUNC_1_OUT_0, 0x500003e0}, + {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, MISC_REG_AEU_ENABLE1_FUNC_1_OUT_3, 0x14}, - {OP_WR, MISC_REG_AEU_ENABLE1_NIG_1, 0x55540000}, - {OP_WR, MISC_REG_AEU_ENABLE2_NIG_1, 0x55555555}, - {OP_WR, MISC_REG_AEU_ENABLE3_NIG_1, 0x5555}, - {OP_WR, MISC_REG_AEU_ENABLE4_NIG_1, 0x0}, - {OP_WR, MISC_REG_AEU_ENABLE1_PXP_1, 0x55540000}, - {OP_WR, MISC_REG_AEU_ENABLE2_PXP_1, 0x55555555}, - {OP_WR, MISC_REG_AEU_ENABLE3_PXP_1, 0x5555}, - {OP_WR, MISC_REG_AEU_ENABLE4_PXP_1, 0x0}, - {OP_WR, MISC_REG_AEU_INVERTER_1_FUNC_1, 0x0}, - {OP_ZR, MISC_REG_AEU_INVERTER_2_FUNC_1, 0x3}, - {OP_WR, MISC_REG_AEU_MASK_ATTN_FUNC_1, 0x7} -#define MISC_AEU_PORT1_END 1241 + {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 2160 + }; -static const u32 init_data[] = { +static const u32 init_data_e1[] = { 0x00010000, 0x000204c0, 0x00030980, 0x00040e40, 0x00051300, 0x000617c0, 0x00071c80, 0x00082140, 0x00092600, 0x000a2ac0, 0x000b2f80, 0x000c3440, 0x000d3900, 0x000e3dc0, 0x000f4280, 0x00104740, 0x00114c00, 0x001250c0, @@ -1464,4905 +2546,12215 @@ static const u32 init_data[] = { 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, 0x00088b1f, 0x00000000, - 0x51fbff00, 0x03f0c0cf, 0x3130ef8a, 0x22b1c430, 0x3b0143f8, 0x02ecdd01, - 0xdc406ec4, 0x19b7c404, 0x23dfd348, 0xf1476080, 0x03343031, 0x032f3731, - 0x423f2483, 0x4d5011fc, 0x02ef9025, 0xa40cdb15, 0x77280475, 0xf2c060fb, - 0x77629812, 0x056c1144, 0x58c8f22c, 0x4dde4d11, 0x44af950c, 0xe340ff40, - 0xfca8b235, 0x6d081948, 0x8b5f150b, 0x95051f26, 0xd0849577, 0xe76964eb, - 0x00607a36, 0x2726b9d6, 0x00000400, 0x00088b1f, 0x00000000, 0x7dedff00, - 0xd554780b, 0x333ef0b5, 0x64ccce67, 0x093c991e, 0x20f264af, 0xf09c0682, - 0x93a8a808, 0x07be3040, 0x0e22a5e4, 0x27902018, 0xf5e8bd48, 0x620c19bf, - 0x2f06d6b4, 0x93a45a2a, 0xb6968a80, 0x6c1a06c1, 0x822203b4, 0x6b06f5bf, - 0x368b6d7b, 0x2062a28a, 0xa5ebd8b9, 0xaffadaf7, 0x99def6b5, 0x91332673, - 0xfebffdaa, 0x5fa7f7df, 0xf7b3ecdd, 0xf5ed7bd9, 0xb3ef6b5e, 0xa66e6547, - 0x97d8ce5d, 0x9be507f8, 0x232c630a, 0xa1bbd65a, 0xed58cc9c, 0x9ef8731e, - 0xec66c65c, 0x4f2e44b1, 0x12ab7a87, 0xf4dd42b6, 0x4fda9d92, 0x7af5e56f, - 0x9743f773, 0xb9fb3b40, 0x05053d99, 0x589bb1eb, 0x6c276309, 0xf2f5ff8c, - 0xaf3b72fa, 0x5feeb6d6, 0x557fa0cc, 0xe1d995a7, 0x661d13fd, 0x3cd7d63f, - 0xc01984a5, 0x3eefbb50, 0xbf8c046d, 0xdbb4ac22, 0x0a7f50bd, 0xcafb421e, - 0xfb18730e, 0x33bbb9f7, 0x4ec64e03, 0x5798da36, 0x937ef843, 0xd8c453d9, - 0x59eef0aa, 0xaadfa023, 0x04cf8a5d, 0xaadaacf3, 0x8c9f2e44, 0x19b095cf, - 0xe9dea886, 0x1cb1de60, 0xcd192f86, 0xf358eb4b, 0xe30bcc24, 0x0b45b532, - 0x4dbe70b8, 0xc515d79a, 0x0f46c9cf, 0xb5eb23cd, 0xf03cc2cf, 0x144fdd5e, - 0xceb12e1f, 0x30ed82c4, 0xf67de9ff, 0xb89ddb85, 0xa15af5be, 0x258ebf4b, - 0xab1d717b, 0x2cdaadc2, 0xaad5c227, 0x8e8a2f2d, 0xcd33bd57, 0xfc96d708, - 0x7b5d4161, 0x91b2796c, 0xb4616f31, 0x7f318abe, 0x0fe113bb, 0x47c7b36b, - 0x29641f9f, 0x9deacf44, 0x45b5e666, 0x442c67c7, 0x17cccdcf, 0x2eb2bc41, - 0xb74f4f97, 0xdd231e33, 0x7788a4d6, 0x7df3c013, 0x024d8741, 0xf843df4f, - 0x7bf64ca0, 0xfeb0abd6, 0xa3cc99e4, 0x26fef10c, 0x1ed85b0b, 0x900bbd67, - 0x1630a619, 0xb7822664, 0xc26f058e, 0x50d4cfb2, 0x5fc3c005, 0xeb002b24, - 0xefe14fbd, 0xd4bccf5f, 0x9ad1beff, 0xe9bae91f, 0xe6ed92ca, 0x7496b15c, - 0xfa7f2fac, 0xb5321801, 0xbf10cfc2, 0x88ade22a, 0x43321e16, 0xca576bbb, - 0x7abc07c4, 0xc72d95fc, 0x4d93dcf9, 0xa678fa06, 0xa9ea1927, 0xf0635333, - 0xb89cf4eb, 0x4e01d440, 0x827fa9ab, 0x6958cf9a, 0xedf88db6, 0xe48d6c8e, - 0x38cb8ee6, 0x3b64775c, 0x7fa821c3, 0x08b85f17, 0x42f05aea, 0xc07c1c4f, - 0x859626cc, 0xa6c4d065, 0x466f6e0d, 0x941f023c, 0xf8517ce5, 0xa6f5941e, - 0x2814c2fe, 0x21a52b57, 0xc446cbc4, 0x330e9423, 0x3b75c06b, 0xd4f08cac, - 0x7b64a63c, 0xfba78748, 0xb94f0173, 0xb7ef71d1, 0x1f316434, 0xca840f63, - 0xc070ea43, 0xf7102e6f, 0x3cb78462, 0xf7802a12, 0x42c8ef73, 0x9034da7c, - 0x1afcfd03, 0xf3445fcc, 0x1f1e20b7, 0x9d8c7415, 0xcd3856df, 0xaf3dbf30, - 0x5dbf30ca, 0x2781f983, 0x2b5d089f, 0x8e3c07e6, 0xec07ec60, 0x96df9a5a, - 0x6fe68eb7, 0x619558d6, 0xf981a4fe, 0xd3ef38c3, 0x2e6fe609, 0xfeb8d8bc, - 0xf5c655bc, 0xcffd7c6b, 0xf989e685, 0x3ffd6893, 0xfaf8f362, 0xebe2eef3, - 0xfab8c2b7, 0xf803ddf9, 0xefbc476f, 0xdb7f804d, 0xeb8dd379, 0xae31afcf, - 0x7fe7cadf, 0x988b7421, 0xfff349df, 0xd7c2dd82, 0xcd377f9f, 0xf836b56f, - 0xcd64d03c, 0x23086a49, 0x7fe17b5f, 0x802ca0c3, 0x5942a679, 0xbc18ca94, - 0x47961dff, 0x2923b878, 0xfff61e78, 0xcdf8093c, 0x2c0bd519, 0xb94151bc, - 0x5d3c13af, 0xf6896bb9, 0xb2a5783d, 0x064beb93, 0xc00c74fa, 0xb3f3ba77, - 0xf000ffcf, 0xf628ee56, 0x8f24bd99, 0x265bdf0c, 0xe66f5296, 0x902c60f8, - 0xfa85db3d, 0x673d9029, 0x59f9353c, 0x4645e826, 0xe3e20e30, 0x13962d65, - 0x5af93a3d, 0x5f58c5b1, 0x25d63619, 0x24c8a5dc, 0xd8ca8650, 0xf79806d8, - 0x0623e804, 0xd07df27a, 0x647e5847, 0xdda2b761, 0x15f400f8, 0xb572f4d3, - 0x4272e89e, 0xb13ff8e5, 0xf8f241c5, 0x1ad5a6f9, 0x1c7847cb, 0x7cdd6480, - 0x1156f621, 0x58be73ac, 0x04b9e127, 0xcf5f15f5, 0x6bdaaefc, 0xdc02c4c0, - 0x4ef78669, 0xd416225b, 0xf0b0b75b, 0xfe3059bd, 0xb6ee0f6d, 0xf8ff4904, - 0xae489a47, 0xc81348d9, 0x968582f5, 0xef747bf7, 0x64d8ec2d, 0x8de50919, - 0x9bf3e341, 0xd3f58cab, 0x84c5b096, 0xc2a57976, 0x5bfc615a, 0x72ed8c1a, - 0x54b13f9e, 0xdf31674e, 0xf0c5a07c, 0x06575c54, 0xe1e82fd1, 0x3ebb00eb, - 0x87da246b, 0x53df14db, 0xfb05bf50, 0x1e3a444d, 0xe2f9f0d6, 0x07be2965, - 0x997860d8, 0xdf40930a, 0x78dd8577, 0x743cb557, 0xfe183291, 0x7e1c979e, - 0xebc184d3, 0x56fb8588, 0xdc3a21e6, 0x7cf8ceba, 0x7d762849, 0x3bea0f9c, - 0xd03ed34b, 0xbf6daf3d, 0x1d03ed32, 0x9cef54bf, 0x0cafa86d, 0xbfe868df, - 0x4312cb62, 0x9596b2fb, 0x9adbf686, 0x4bea1b57, 0xfa1a7742, 0xbd6ebadf, - 0x8696fda1, 0x37ed0dfb, 0xd4326d57, 0x6e3e0c6f, 0x6160bfe8, 0x795da1ab, - 0xfa0e6569, 0x305af537, 0xfde03867, 0xacacefd4, 0xb1f2894d, 0x1b8ff3e4, - 0xd93ca8b3, 0x3d72a5e8, 0xbfc82bca, 0xeb2f1f69, 0xa0e496db, 0xffbe4b9c, - 0x8d90d2c8, 0xdfcb1272, 0xcb18f2b1, 0x6837c8c7, 0xf3d91287, 0x5005851a, - 0x6e14fbee, 0x77f3e48f, 0xec65fe84, 0x1ab7921e, 0xcd63cb8d, 0x50cbc3f3, - 0x48b46a5e, 0xf1338361, 0xa15dacb8, 0x46d63075, 0x830cace3, 0x9ae81854, - 0x77b3806f, 0xafe699bf, 0x22e3e743, 0x2581f7b4, 0x791fce0a, 0xf186fb39, - 0x297f8f08, 0x48333bd5, 0x5636f62f, 0x22a07da4, 0x7e5402fe, 0xca90b8dc, - 0x2a418d13, 0xa2ac683f, 0x06c6fdf2, 0xd71a7b2a, 0x636ef951, 0x8d63ca88, - 0xbefe54cd, 0xb7ca85b1, 0xf950b71b, 0x9530c6db, 0x54fd1ba7, 0xb5a9f00e, - 0x43fd10bf, 0x432b07f6, 0x0ebd9717, 0xcdc816fe, 0x7737e919, 0xe11afaf2, - 0x4bc22737, 0xe213dd2c, 0x434c858f, 0x89292dd1, 0xc4c923d3, 0xf9c8182a, - 0xfaf6e303, 0x8abaf296, 0xe008032a, 0x0397fbd3, 0x860d22e3, 0xde3d357d, - 0xf683bb41, 0xd93365ef, 0x99f9163f, 0x1e9706ef, 0xd423401f, 0x8474bf37, - 0x35fd029f, 0x7e72f14a, 0x9cbc0af9, 0x8dddbc39, 0x964d747a, 0xa4c1f3c9, - 0x6dabebc4, 0x7538f5cf, 0x1a77d4f0, 0x945a67eb, 0x7a0fee0a, 0x478ee793, - 0x3e78f07e, 0x65ba4028, 0x59c72951, 0x3e79a593, 0x617ec348, 0x95db0f5a, - 0xf105fc42, 0xb6fbf508, 0x4e3448e1, 0x760e8e14, 0x1f27de1c, 0xff713f3b, - 0xfea17c84, 0x9a3f4349, 0x473e5975, 0xff856abb, 0x1401897f, 0xc72ea953, - 0x87376fad, 0xf3e217ac, 0xe0f9865d, 0xf58caf3d, 0x8a1bccbe, 0x427654ff, - 0xa4a807f2, 0xacde22a3, 0x18f769de, 0xa18a75f5, 0xdc39df5e, 0xf8dfd063, - 0x3657900f, 0x5ed15153, 0xe8b608d5, 0x0acd9d53, 0xf90bb7c0, 0xaf52e806, - 0xb6b57ef0, 0x8f082d1e, 0xcd3474ce, 0x3d8bc4bf, 0xb1bd685b, 0x3c6c9df0, - 0xc4d555ec, 0xcf9b57f0, 0xe38811dc, 0xf0ae7f97, 0xc4c6a538, 0x0b665ffd, - 0x584e51b9, 0x873dc856, 0x07399bf8, 0x0b7143f0, 0xcbaba3cc, 0xe9afc071, - 0x7acf678f, 0x8dafdc4d, 0x526ad79d, 0x757f09ce, 0xc2ce8ebb, 0xb1e2c775, - 0xb43ff3ae, 0xcc8dc520, 0xdf894780, 0x6ac04a5d, 0xed57f182, 0xf9434f7c, - 0x2a12d8fa, 0xc4dce7fc, 0xbf0c19f8, 0x2384eb33, 0x7b35ceba, 0xad5fe45c, - 0xede224d9, 0x79c6eb10, 0x13134e97, 0x74bd017f, 0x62e58070, 0x26dfa826, - 0x5dee326a, 0xfe4d51da, 0xa42c87d5, 0x89f53fa1, 0xfd04a5b9, 0xaded5583, - 0x3ce01f9a, 0x88154cc5, 0x4dec53af, 0xbd1d24f7, 0xd11a4c8a, 0xa366b6e9, - 0xa6fe00df, 0xa6fe0ea1, 0xcd9cbea1, 0x7638c4c9, 0xb80b66f9, 0x434eb4be, - 0x879328fb, 0x3582b0e8, 0x7afb446c, 0xfcd263bc, 0x3f0e904b, 0xf104b27f, - 0x479a14bb, 0x8f1e22a6, 0xd6ff1e12, 0xfbe257f9, 0x1bcf0713, 0x7c98dbe5, - 0xed43c080, 0x8e1fc54e, 0x991737c3, 0xfe4abf38, 0x4ff080da, 0x2dcdfa89, - 0x4d6bf531, 0x6b724a8a, 0xe3a46666, 0x642d8f29, 0x5f76a64a, 0x7a12f004, - 0x026beade, 0x12a3fafe, 0xbb226d98, 0x74c0991e, 0x04a8fefd, 0xf2af79e9, - 0x013472fa, 0xc04c8d4c, 0x06d80b3c, 0xd04d3be2, 0x60f08ad7, 0x1aa59cbc, - 0x728f59d6, 0x9dd8e30d, 0xb7df0c1d, 0xf1da637b, 0xc637681f, 0x8e1bb232, - 0x2776c6b1, 0x87f219b0, 0xbe7c67cb, 0x180fc842, 0x4c3be222, 0xebdfa17b, - 0x662339b6, 0x34d94bf0, 0xce2077b5, 0xc878c3c8, 0xfe91813d, 0x645e52f3, - 0xaff787ad, 0xb5847913, 0x4b0d94ef, 0xa97fc21d, 0x84b61b3f, 0xb57574d3, - 0xa97e435f, 0x12c3bb3f, 0xf40df49e, 0x989617a0, 0x279b9519, 0xca236094, - 0xd49bc4ad, 0x3c3d517f, 0xcb97a3ca, 0xfef431ad, 0x03a470da, 0xec70753d, - 0x482d8252, 0xbe3858f7, 0x8359f8f6, 0xadfadfc6, 0x68305f8e, 0xf0f19dfc, - 0x631c7a78, 0x0337a4dd, 0xfee80cc9, 0xa8f3dd9f, 0x8ff7444c, 0x85233e41, - 0x58f84fe8, 0x4b79e344, 0xb8f8cbac, 0x59e5ebaa, 0x81575718, 0xfe05eb7f, - 0x485ac95d, 0x294c448f, 0xb335cfc2, 0x55de0e88, 0xfea6bf5d, 0xff783aab, - 0xfd4ed66a, 0x3119bf31, 0xe1927bac, 0x7def293d, 0x9cd49ec2, 0x1d11612d, - 0x790b763f, 0xe087bf00, 0x106bcf93, 0xb26bcc3e, 0xb6a79a6e, 0xcf30cd3d, - 0xf6735f80, 0xf9d11662, 0x376ab53d, 0xd9ed77f1, 0x019e68cb, 0x6afe067b, - 0xfc6a1b44, 0xa3b80691, 0xc0334fe3, 0x3a7f1d1b, 0xcfc72bcd, 0xca72039a, - 0x2be513f5, 0xc293cb42, 0xb7a7804d, 0x91f7c1ac, 0x9b5cb25f, 0x76415f73, - 0x04f1fa5a, 0x744fc7d4, 0x1d34df6c, 0xea09fae8, 0x9b975c39, 0x739eb9b9, - 0x92174c86, 0x7c853afe, 0x18bfa030, 0x43f1afe8, 0xb7e8c7b4, 0x8c0af851, - 0x28f59a3f, 0x3746dfa8, 0x8e50f518, 0xef84dd33, 0x3e33ace5, 0x019ea2f7, - 0x521b95bd, 0x9f5ce263, 0x6fcfc709, 0x9f4f3e36, 0xc73aba51, 0xd3516e07, - 0x2798a533, 0xba505f4a, 0xb187a47b, 0x7957d40b, 0xe2d299fd, 0x79ff50e1, - 0x1532bad3, 0x7ff4d5fc, 0x86ce2d2b, 0x91b2d3ba, 0xca15abd7, 0xb7cc592b, - 0x89be8594, 0xcac0081e, 0x6294728d, 0x0a9cfc06, 0xccbf9b1c, 0x5fb47a8b, - 0x9e8478e3, 0xd3d19f80, 0x39467e38, 0xfc46ed8f, 0xd67a98e4, 0xc3f973a3, - 0x052bff17, 0xe62f4643, 0x1e0f013d, 0xf483c1b6, 0xbed34781, 0x8ebfc21c, - 0x5f2533f5, 0xf305b14c, 0x4b938e10, 0x167f7ec7, 0xeaa27d3c, 0x5b0dc500, - 0x71f9fe44, 0xf46eb710, 0x326f55bb, 0x3364e3f2, 0x0965d7cf, 0x378ceebf, - 0xfd487937, 0xa195959e, 0x53eae0ea, 0x9fc8ddfb, 0x5f1c5f7d, 0xd6237e8c, - 0x13d08653, 0x32a359f5, 0xa3139254, 0x749e667e, 0xc14aa3e2, 0x5b378847, - 0xb6cf3466, 0x7e510942, 0xc0b5fa44, 0xbf5c1e01, 0x7f31aa12, 0x8edfc179, - 0xe0d6e3a7, 0x775866d5, 0x83c85985, 0xbdb0b98b, 0xf08f2ab7, 0xf6836e96, - 0x6b3d688c, 0xe809cee9, 0x0398a4e7, 0xc37be2d7, 0xc6cd9f97, 0x43d98e7a, - 0xb4a2dbf8, 0x00f8470c, 0xc3cfb48f, 0x569d82f6, 0xdcc93168, 0xcf26f64f, - 0x69ce2219, 0x1f4acc6b, 0x55cf2fca, 0xde718b83, 0xf7bebdfc, 0xf1fc619b, - 0xf70f9a95, 0x9bafc65b, 0xccf88e99, 0xc03d7132, 0x72f390ee, 0xf82f5f3d, - 0xf8aacfae, 0x77ded0fd, 0x8435a7bb, 0xda0b33ed, 0xb519afd1, 0xfdc3ebce, - 0x42873e80, 0x7a35f7ef, 0xe7282f29, 0x1c95dd1d, 0x9e49bbb1, 0xf3c8373f, - 0xd07d633a, 0x3b7a5f7c, 0x7fbc707b, 0x9c42f8f6, 0x1d0f949e, 0x67d9e82d, - 0x725dfbe6, 0xb42cd1be, 0x7391fd1f, 0xcc5fef9d, 0x7fda74ae, 0xba037410, - 0x925e9084, 0xfbdf402e, 0x121b5f10, 0x78bef7d3, 0x6b6e5df4, 0x5db946c8, - 0x659f6815, 0xe625e781, 0xafd883e0, 0x21f76166, 0x50decd0b, 0xe927fc88, - 0x70d0d4ce, 0x740353d4, 0xfc21497f, 0x7c717667, 0xb7361fd6, 0xcb1e7ee2, - 0x40b7ae0a, 0x42ca99fb, 0xa22627ca, 0xfe75f8f3, 0x017cbd74, 0xfce2b7dd, - 0x9a8ebbe3, 0xef493e10, 0x49de44c7, 0xffecadca, 0xbdfa598c, 0x0f76be62, - 0xfc55f7cd, 0x166eb457, 0x7c780b8d, 0x80dfcf56, 0xff9c76c7, 0x1fe166c7, - 0x3b63c60f, 0x3c073ff6, 0x3c1739ee, 0x939de87e, 0xcfe30799, 0x7f093b32, - 0x87329f2b, 0xbea4b0ad, 0xf52fd2d9, 0x333c335f, 0x5e5627aa, 0xd71fb0d4, - 0x8549f2b9, 0x6bb2acf8, 0xc26c35c5, 0xf96378e0, 0xe3e910c2, 0xd903b8d8, - 0x5ab2f912, 0x7f13178e, 0xff07b354, 0x734e4cc3, 0xf54ef498, 0xbffb634e, - 0x9b30f945, 0x24ce04f2, 0xf1b1b79e, 0xf1d0b2f1, 0xe248be47, 0x8b26717c, - 0x619e1c91, 0xd0f7c429, 0xbb608bee, 0x33fca2e6, 0xdc6291db, 0x314cac9f, - 0x6e8e4fec, 0x4ff21930, 0xc9b1f3b1, 0x5fec4cca, 0x6730e42a, 0x6fb0c99d, - 0xee321b97, 0xa737e5eb, 0x5a63ea1a, 0x9ffa1846, 0xd0cf25b7, 0xbe7c2e3e, - 0x9d82fda1, 0xf1f50d13, 0xfa1b17ed, 0x6659d85f, 0xae4717a8, 0x749ff432, - 0x3ea18e78, 0x4326fba5, 0x2f6fa9ff, 0xd45fb435, 0x7ed0cab3, 0x0c6bc7c9, - 0xeffb4bf5, 0x2c8ff432, 0x00ac38a9, 0xff025efd, 0xe086f314, 0x67c8a857, - 0x99acfe07, 0xfc0e4f90, 0xa8c4d0b9, 0x2bc867dd, 0xa673f81e, 0xf81f9f1f, - 0xfb1f8973, 0xe7cb3295, 0x5952e2f1, 0xdb19b0ce, 0x0be05553, 0xc0d96fb4, - 0x569a9817, 0x7203f28d, 0x39454235, 0x0fc3a7fb, 0x469d0215, 0x46482cac, - 0x34f20d3b, 0xbd373d42, 0x27ef8394, 0x962da792, 0x290f1b96, 0xac7ded83, - 0x38e590be, 0x5bade655, 0xbad37de8, 0x65a7616c, 0xb230f17d, 0x5f9f9233, - 0x7a1c5333, 0xe3d70366, 0x86a43667, 0xdf9efef9, 0x0fe75c39, 0x24e8399e, - 0x9efdcefe, 0xaf01db93, 0x892cebd3, 0x7f2901da, 0x323f22f9, 0x7945582a, - 0xe3fe418f, 0xb8f59ea2, 0x1ff573ce, 0x99c6fd63, 0xff021e92, 0x05d1d709, - 0xf1f68972, 0x27da1483, 0x7161e35a, 0x36b6eff7, 0x16770f36, 0x4b2e7e0c, - 0xdce1cd65, 0xb40f30fb, 0xe159f14f, 0x1fd86dfd, 0xbc587bec, 0xb5ea26d7, - 0xbd454d21, 0xebe22b56, 0x521e71d8, 0x7e466f4b, 0xdd96a1d8, 0xc5d14eac, - 0xdc5a0dd3, 0xd077c7bc, 0x0473c089, 0x0d80efaa, 0xcf5fefe6, 0xff306d7c, - 0x0ca78b1a, 0xf4ee6beb, 0x9af21d12, 0x7ae1667b, 0x5dc13a73, 0x73fbd9d7, - 0xc056a780, 0xd4f08b53, 0xa714fda9, 0xb0a8bff5, 0x879c5cb6, 0x5f66bb8f, - 0x487e432e, 0xd51ce704, 0x72057c42, 0x738e3770, 0x4ed09aa7, 0xf28e7ddf, - 0x638d5eb0, 0xf2ec065f, 0xf15bed52, 0x137072c7, 0x9eb44a78, 0xe196d0ff, - 0x9d39b728, 0xc0a89fa5, 0x60e039b7, 0x9f22a726, 0xd1bef632, 0xebef623f, - 0xf344d0fc, 0x7689557e, 0xf1157def, 0x0631f7ce, 0xc7231dc1, 0xe46f75de, - 0xebe9a417, 0x4c17e7af, 0x10950012, 0x306c14bc, 0xe5e2db88, 0x95f6738b, - 0x2427561e, 0xbdefe786, 0x377881ce, 0x4bfd5e46, 0x7c8f5ec7, 0xb311fb77, - 0xb2845562, 0xc84178c1, 0xe677b2eb, 0xf0e8a664, 0xe5b1b5b3, 0xaf27556a, - 0xf7f012a3, 0x9ff72a9b, 0x5c3635b6, 0xe380595d, 0x3d7a4c7a, 0xca13dd90, - 0xd27988dd, 0x8c2f870e, 0x9327acfa, 0x702b58f0, 0xbe0a6c90, 0xf4bcfc89, - 0xd7ca6ec2, 0xe97c88e6, 0x297e7168, 0x2ae3be76, 0x97f847cf, 0x8c2958da, - 0x16cda7fb, 0x34b277f2, 0x08e28798, 0x5a5b9d07, 0x0a6c0636, 0x93db2fb4, - 0x0c53f5c6, 0xd0c6e15c, 0xa20a1bd5, 0xc71c02f3, 0x3dbc1e51, 0x7f3859c1, - 0x4451c22e, 0xe11276f2, 0xe84d48fb, 0x473c9dcf, 0xd21beb79, 0x43c6c4fe, - 0xf0e2fd09, 0xa7e485fd, 0x7e4dffe6, 0xa1c3fa31, 0x0c3fa8a2, 0xd058b2eb, - 0xeb8c594e, 0x8b55d9d2, 0x95d6dce5, 0xaeda1964, 0x92416e3e, 0x32407389, - 0x9ae1230f, 0x57f2e169, 0xe618d1ef, 0x4e51ead3, 0x54d9f0e3, 0xbb88628b, - 0x3138adbf, 0xede6553f, 0x7887bda4, 0xe5c2e311, 0x33a3e24e, 0x0bfbd6de, - 0x877c7327, 0xc8f7c086, 0x04322375, 0x0f887d5e, 0x16f1c789, 0xbc069ea3, - 0xb5e2e2fa, 0x326af006, 0x57ca75e0, 0x95fc95e0, 0xa98f9daf, 0x9cefee34, - 0xa5dff816, 0xde703304, 0x5bbc3753, 0xbab0f982, 0x086b9f79, 0x679ed7d7, - 0xe7e9b32e, 0x981ef991, 0x9cf383c7, 0x9aafe1be, 0xe825a7d0, 0x39ed3667, - 0x35cf192f, 0x93f38ad4, 0xfd5af6a7, 0x3e5f8e8a, 0x1e70f2fd, 0x1b4fa5ea, - 0xf2c7ccaf, 0x5bcf2a54, 0xf53bda9e, 0xa9d5f210, 0xb12d1c9f, 0x9ea738c0, - 0xd2a25a3f, 0x60d85b3e, 0xef2f6a7f, 0x203b412e, 0x7c03daf3, 0xdfaf8b67, - 0xfcfe0b56, 0x4aafebda, 0xc8d5e788, 0xef1ca707, 0xebfae096, 0x0f09675c, - 0x7cb9db0f, 0x6da1923c, 0xd32332c4, 0x17fa10f4, 0x4fc1a45a, 0x5b8788db, - 0x75265822, 0x7971fbb7, 0x23bbb7ce, 0xfa7bba58, 0xbd7618fd, 0xe201fe05, - 0x67b1f3d5, 0xbe1fd63f, 0x33e504f2, 0x1ab017d9, 0x80916380, 0x3b59f7e3, - 0x3a04a91e, 0xf37d2efc, 0x7e86e423, 0xf685eb01, 0xa0dff19b, 0x1e818e87, - 0xdc6c80f2, 0x7cfb72a4, 0xb512a553, 0x191ff853, 0xe9187947, 0x8a3545d3, - 0xeea5aec1, 0xd3f94199, 0x6429af3e, 0x61a47581, 0xbff81a56, 0x66ceeb4f, - 0xc5cec0df, 0x3883bf96, 0x9d9d7de5, 0x0952acfa, 0x67df30a9, 0x7fac8f42, - 0xd3f1127d, 0x178a65e6, 0xfefb18f1, 0xcb5eeb63, 0x727a099f, 0xf3879dd8, - 0x6efc8267, 0x90027916, 0xa7cf0537, 0x80f22c3d, 0x877b866b, 0x9ae3ede9, - 0x8252f323, 0x46defaba, 0x89d6dfbe, 0x7ca15ee7, 0xed7b9c41, 0xfaa2cc6a, - 0x2a5e8d4b, 0xe9638d23, 0x434b66f9, 0x7bdf9e0a, 0x3342c2cd, 0x77bf97c1, - 0xe51bff78, 0x1ddb42e0, 0x699b2fbf, 0x33d6f187, 0xd6f8cf3a, 0x13ddefbd, - 0x1df00e9a, 0x1929a4f8, 0xd2a740ed, 0xa61c478e, 0x23fdbe2a, 0xcb5d4f51, - 0x75a54f48, 0x306e742a, 0x3611cbad, 0xb7d3fce9, 0x765edc2c, 0x72de785b, - 0xb442da2a, 0x7fa5b32f, 0xef413fd7, 0x0fea0cc7, 0x7b9e1f81, 0xa98f9d8e, - 0x4ecf94fd, 0x7c30def4, 0xbfb9fc6f, 0xad4c77d7, 0x2a89f3a0, 0x66a77fb7, - 0x903eb667, 0xcfebfbcb, 0x79e1f497, 0xfa7238ce, 0xbdef3117, 0xc7f74e16, - 0x64768d72, 0x8fdb9597, 0x1df316ff, 0xa392dc68, 0x9651bf3f, 0xffe8dfc0, - 0x335ff2a6, 0xe488ff68, 0x68f596be, 0x3f72bcfc, 0x11fc49e5, 0x3619af8e, - 0x577d470e, 0xca04b2b1, 0x97ae4e19, 0xe50eb0d2, 0xeb9c550c, 0x689cfc66, - 0x2b56455a, 0xe28e5f9e, 0x5a73af81, 0x1c16bf4f, 0x7dc3dfcf, 0x7c0fb4df, - 0x29ebf20a, 0x7fee39a4, 0xfd11b6cc, 0xaa825b67, 0xbc52f486, 0x9d22578f, - 0x3a238cf6, 0xec958fd9, 0x5c3a464f, 0xde4cf2cb, 0x2dec1f28, 0x9c627a05, - 0xb6f14fb4, 0xa73ee8b1, 0xe340bf9c, 0x23e595f8, 0xc877e04a, 0xea5a05e7, - 0x784fdc0c, 0x82581ec4, 0x7e113247, 0x678c165b, 0x478cde0f, 0x5debedd2, - 0xf4e0154d, 0x3b40b5ed, 0xba360bd4, 0xfe00369b, 0x4704a6f6, 0x6b9796e2, - 0x30e9a3bd, 0xb970a7b6, 0x68e8d828, 0xd1c8b942, 0xe61f3c3c, 0x5f22e7f4, - 0x503dd40d, 0xdbabaf1f, 0xaf2aea62, 0xbed575cb, 0xc843e7fc, 0x5c5d75a7, - 0xd6f006be, 0xfea0ac59, 0x7e135f3c, 0xf4398392, 0x547fddfb, 0xbe341382, - 0xedc85d8f, 0x4a07dc98, 0x81f62ed0, 0x828b58b2, 0x1e04767a, 0xff47cb60, - 0x6cca9bba, 0xdca54fd6, 0x59dbc8df, 0xea04607c, 0x76605353, 0x35e7d239, - 0x18f7970b, 0x72b1efbc, 0x2d6bdd3e, 0xf985659d, 0x63d01e1e, 0x46ba5f7c, - 0x81b669e8, 0xc15eedeb, 0x9b369fbb, 0xc9c01a42, 0x79e83876, 0x553f388d, - 0x4c81cef3, 0xd4f8d7dc, 0xc9e22acf, 0x7b085cc5, 0x5b5f8f11, 0xb946822e, - 0xef907fa8, 0xcc7c819b, 0x21d57c45, 0xd937505c, 0x847ce9ba, 0x87f69ee5, - 0xff3718cc, 0x73c1e2d8, 0xbeb9d58e, 0xa2fe78fd, 0x0fae5f7a, 0xc3bde555, - 0x9d577c79, 0xd1399ed2, 0xbacbe519, 0x21d94dce, 0xfb27f7c0, 0x95f2477f, - 0x61ec878f, 0xa38edafc, 0xd79e105a, 0xa1a7bc75, 0x4524fd61, 0xda3e81fa, - 0xb877bdb7, 0x9c12f92f, 0x3c6657ef, 0xa7803859, 0x14ee96d1, 0xc3c979fd, - 0xa0fde7a0, 0x3d035fcf, 0xd021e58f, 0xf3d07eff, 0xd7f8be47, 0xaf3fd44c, - 0xccd7c25a, 0xcd9e71c1, 0xe15e60f7, 0xc1f84f53, 0xb4ff5089, 0x3d6f8c60, - 0x6b3e57d4, 0x7fbc600e, 0x96716d44, 0x6083ff40, 0x9dfde847, 0xc2f4eaff, - 0xdb0583f3, 0xf471bd33, 0xd36795dd, 0x60981f99, 0x7cef997b, 0x36078f94, - 0x976c9bfa, 0xbeb9f802, 0xea18ac55, 0x0d93795a, 0xa99365e4, 0x1f62d1fd, - 0xc73867d5, 0xce597f81, 0xf2b187e5, 0x278e52a6, 0x71b4dfaa, 0xdfdc0cd3, - 0x8a7bbb5b, 0xc89a7c82, 0x7d9d56de, 0xc825ce8e, 0x6b263e7a, 0xd4aaef80, - 0xaa59e510, 0xce84fece, 0x271acc33, 0x61fe68f3, 0x1f2dc68c, 0x8edd7886, - 0x13177c7b, 0xbdf843c9, 0x68b2f6c2, 0xabc1f51d, 0xd0be02a9, 0x41334d8d, - 0x0cb11fbe, 0xdcf1fbb4, 0xe12b9aa0, 0x523c2167, 0xfb26aafc, 0x099a6e2f, - 0xcd76ea41, 0x36867e38, 0x02afdfd0, 0x249abe1f, 0xfc682beb, 0x6293fd41, - 0xf1c997fa, 0xf3c2e3eb, 0xb75a3d88, 0x2ff57f41, 0x59fbe8d6, 0x3b68ff88, - 0xc727978d, 0x56f0475f, 0xf6f3370f, 0xbf65e850, 0x4dcfa51a, 0xeb4dfdda, - 0xdaaf6f01, 0x97a8a57d, 0xa465affa, 0x7cff916f, 0x49b87e3a, 0xb3aad9e8, - 0x39fd3157, 0x58b49b92, 0x90c75cba, 0xde3ee76e, 0xa2f186f9, 0x7a604ce3, - 0x7e047ffa, 0x6fb7584d, 0xedd762bf, 0x03ce90b3, 0xc510b3f3, 0xf35b55f3, - 0x07a75859, 0x5f1c3ffe, 0x027f0e17, 0x5ffe6638, 0x61ac6386, 0x451c28be, - 0xfefef806, 0x80259470, 0x02b7d663, 0x959dac47, 0x67617ee5, 0x0d5452fb, - 0xbdb63bf7, 0x8ffda564, 0x96c85374, 0xceba7687, 0x5b7a7644, 0xbf1f8b6a, - 0xc6b6d8bf, 0x1ee1e74b, 0x722a04b1, 0xdd0a7fc1, 0xabfda269, 0x6ebe796d, - 0xf6dadfdc, 0x26be792f, 0x8b3d349c, 0x071662ec, 0x3c5b6d81, 0x087e2aff, - 0xa3efef8d, 0x3e3b44e9, 0xf646c532, 0xe59cdb72, 0x9f4fff94, 0xda1c7673, - 0x0a7e9d49, 0x66531d91, 0xf3353f93, 0x3c26d6be, 0x149191ef, 0x2ffd1c78, - 0x74dad425, 0x76bc7878, 0x58667fae, 0xbe6066db, 0xcf595b68, 0x73938c38, - 0x803e702e, 0xfcf5abaa, 0xff311311, 0xbc1adc73, 0xbb780ad6, 0x1bf22aca, - 0xf2852c29, 0xc9051562, 0x6dd2c2a8, 0x5a253ed0, 0xa7caf87f, 0x3191cf29, - 0xefc860af, 0xaf814b18, 0xa67a3abc, 0xf641ffa9, 0x461afeb9, 0x8bf47179, - 0x172feff5, 0x027d7d7e, 0xb4e81dff, 0xad1ce11c, 0xd4c21cf4, 0xd1e75d61, - 0xd45f18d9, 0x139955ae, 0xe46d496c, 0x8bffdc77, 0xfd6207f1, 0x22de595a, - 0x7c44acfc, 0xf3958cf1, 0x25ff80e5, 0xe40fadfc, 0xb3f0a37e, 0x1ea2ed2a, - 0x9e506e73, 0xfe13ec17, 0xfc62df4f, 0x37d61268, 0xd769978c, 0xee7ce904, - 0xe5deb172, 0xd1334a5b, 0x7fdca9bf, 0xd963ad23, 0xf7e4d9e6, 0x84bcdf2f, - 0x784a7bce, 0x9bfc632a, 0x51265acf, 0x1d112bbe, 0xfd221fa4, 0x273f5899, - 0xde157bd1, 0x41cfa256, 0x58edafcf, 0xe67cc36e, 0xf67fa8c4, 0x7367c42a, - 0xf1a6dca0, 0xb31e09ef, 0x1b6d38f3, 0xb6005f7e, 0x399650ff, 0xb957d715, - 0xdf092329, 0x716b623f, 0xf91e5ca2, 0x61d7d7e2, 0xf093f43f, 0x9529ccbc, - 0x9eb2a5fb, 0xb72b9e08, 0x55e93f70, 0xe1accf31, 0xeff3661f, 0x1879c4ab, - 0xe97ca696, 0xec7efc48, 0xa69d9879, 0xaf903bb2, 0x9d7810ef, 0x873e0b62, - 0x155793f5, 0x5ea79f12, 0xc7cdd079, 0x79d79e37, 0xd3a5c44c, 0xee4dc3fb, - 0xbfdf3a74, 0x71e5e1db, 0x23ac1946, 0x653e4fed, 0x7f1e8ea9, 0xaf8978b1, - 0xc528fe31, 0x47d7a438, 0x702ce0f1, 0x0579f82f, 0x7e48df23, 0xa6f3eafb, - 0x2dff066d, 0x69f4de7a, 0x8b4edbf2, 0xacf5e5b8, 0x724be6c8, 0x51ef6c31, - 0xdebd4e31, 0xbf416e99, 0x16bcc030, 0xf5ae4b8c, 0x16eb9cc5, 0x11aedae7, - 0x7dc209fa, 0xfa0daefa, 0xaf15f619, 0xcfac669f, 0x37eb1bf6, 0x7effc454, - 0xee374d8b, 0xdf169fdb, 0xf0299e75, 0xb10ca726, 0x002d82de, 0x3bbd6eb4, - 0xae127f54, 0x9bcb4777, 0x26fe7d6e, 0xb0584f36, 0x4f212345, 0x900eee34, - 0xbca43c0f, 0x9d688580, 0x99dda94f, 0xc0a0b8fa, 0xb579ce22, 0x12f33aff, - 0x36c391a0, 0x9fea266c, 0xe7eb955e, 0x4afefbbe, 0x4b18ebf1, 0xcefc0de4, - 0x168bcc78, 0x2853ee2f, 0xff285a2f, 0x4edb3f51, 0xa5bf03df, 0xf7a1935c, - 0x3900c7c7, 0x5d33ae10, 0x5f3c8663, 0x9bacf73a, 0xb79ec5fa, 0xe7cdfbff, - 0xcec73c24, 0xe23e5ec7, 0x16007bc6, 0xf9d1366c, 0x5c8b85ab, 0xa4889df4, - 0x6338ec6f, 0xe171a8b6, 0x84ff844e, 0xb8f4b774, 0x74e6ff71, 0x4af299bb, - 0x6de3edb1, 0x5f8b37ca, 0xbaf31a17, 0x43fd9ea7, 0x57d60461, 0x375cf4ab, - 0xd8e2972e, 0x638c36f1, 0x5f719d37, 0x3fbe7a49, 0xaefba033, 0x86fdb7a9, - 0xe3cf20a4, 0x4903be18, 0x2f128fc4, 0xea70f089, 0x7e16edf0, 0xd164327e, - 0x28c6d7e7, 0xef9439fe, 0xa7b2a4db, 0xd1a77ce2, 0x7be71364, 0xc44c9ed5, - 0xfda5dd57, 0x2f2ab714, 0x41eee87e, 0x7ef160bd, 0x23e0e29f, 0xe97b0710, - 0x3c775efb, 0xfc1bfdfb, 0xc4ec10ee, 0x8fb71b02, 0x12f3edb1, 0x17f8a39c, - 0xecdf8741, 0x9bd1e4ff, 0xd013e087, 0x6f30733c, 0xd551ef35, 0x3aaef983, - 0xdbc90f4b, 0x3718affc, 0x76fc7f11, 0xa0f29dbf, 0xe9da160b, 0xf9d888fe, - 0x8f3dab4e, 0x9df30cde, 0xff707806, 0x00a8f4ff, 0x66f4f1e1, 0xf6fb83d5, - 0x983ae7f3, 0x54ffd74d, 0x08f9f1c7, 0x0cce99df, 0xba701f3a, 0x49df3e2b, - 0xfb655d3c, 0x45c57986, 0xf209fcc6, 0x8eadca1f, 0x3c57feff, 0xc70abbfe, - 0xd7e1c29e, 0xd53a8b9f, 0x8f1c9f91, 0x7c1f72ae, 0x1cf18b4c, 0x2ee80955, - 0x775eb71e, 0xb180acb0, 0x0c8eb261, 0xa075f30e, 0x7071e39e, 0xfb24f104, - 0xdd7cd43f, 0x8577dc4c, 0x03f11fba, 0x9d5bf9ef, 0x7762bfd4, 0xe8cfc211, - 0x059ab9bb, 0x3b01e64e, 0x74a399f4, 0x54f00db3, 0x43407dd2, 0x6475857f, - 0xc46bfad0, 0x6ef0b1fb, 0x68fd8bb3, 0xe4ca87bb, 0xc23ffdb7, 0xba3a4a7b, - 0x49f8bc93, 0xfc6a4756, 0x5d9a0073, 0x60039c31, 0xf1e50f6a, 0x3cf06632, - 0x473eff6b, 0x87894db8, 0x3bfcf59f, 0x2abb18af, 0x8d46b7e5, 0x11ad7d90, - 0xe6abf5f6, 0x5bdf10ef, 0x9ac492be, 0x355df46d, 0xbfe013e0, 0xb41717fe, - 0x7af9403d, 0x1cac9dfe, 0xf31164a7, 0x47fae9b7, 0xe33cf26c, 0x833d7cc3, - 0xbd70e7de, 0xfb033a02, 0x4cf6a667, 0x01bff250, 0x7e316e1f, 0xeb6b5267, - 0xf43d4429, 0x15fc1284, 0xedfeadd2, 0x77ac4c9e, 0xfc9279bc, 0x67c573ae, - 0x7f3205ee, 0xeed0d114, 0x3a5dddac, 0xb57f286c, 0x9d40e306, 0x7de28c7e, - 0xf187c516, 0x5abcc3c6, 0x2c11d9cd, 0xdd143694, 0x126859b2, 0x9fdf33c7, - 0xdf8099e8, 0x6e3ac1ef, 0x2ff5039d, 0x3fccf462, 0x69e9fc2a, 0x574cffdc, - 0x730d41d9, 0xdd376a6c, 0x214bf0bf, 0xf214bf2f, 0x33dff1d2, 0x74fa46ae, - 0xdcf269bc, 0x97e3ab93, 0xc1b21624, 0x7b5bd77b, 0x8efe827e, 0xebf6cbac, - 0x869d2fc1, 0x72e36afc, 0x66b5e523, 0x7d397c51, 0xfe26e6d2, 0xc476f61c, - 0xc7ce798d, 0xff23e951, 0x7f271fb7, 0xccd3a3a1, 0x61cd93f0, 0xa0e6828b, - 0xc1ff8a33, 0x2a3d70e3, 0x96a21de5, 0xde425c0b, 0xe57bdf91, 0x951e59f7, - 0xc2b5c7fc, 0x3c65ec7f, 0xfb11a87e, 0xf02a7fac, 0x1afe39d3, 0x5c600b3b, - 0x3f8f27f7, 0x78fc8539, 0xdf2d9fa3, 0xbdf67e93, 0xa55e39eb, 0x38a362de, - 0xf266647f, 0xaf296bfd, 0xf687ab2c, 0x207f24b1, 0x03d3c4ff, 0xd47a0a97, - 0xe819359c, 0x46a7a51a, 0xdfcf94f4, 0xd2127b07, 0xfa5cc39d, 0x377d0171, - 0x51f31b73, 0x66b6e33e, 0xe4e90b07, 0x3e51e3b6, 0xc63dc76f, 0x798967f9, - 0x3e38925b, 0xf877c43b, 0x91dfaa1d, 0x37d5145a, 0xae075f80, 0xabcbfd4f, - 0x79498f14, 0x95dce390, 0x7ee1f7c4, 0xadf357f1, 0x2bb67db2, 0x76a5deba, - 0x2f24b7d3, 0x27de437e, 0x24999f8a, 0xc5e58947, 0x92f215f3, 0x4d05f84e, - 0xf97b46ea, 0x9f1ff09c, 0x68aa6c3b, 0xdb7fc38b, 0xe73d7c6d, 0xec01a867, - 0xdb844177, 0x32fd44b3, 0x15f9c553, 0x3c589781, 0x3fc7e7a4, 0xd056b2ff, - 0x7f8ca6a5, 0x22f78ccf, 0xca0c3e60, 0xd78c1f6c, 0xd10ce65b, 0xef22cbf3, - 0xcd493ee2, 0xca2f56f3, 0xf6f3ef6f, 0xf49bcc2a, 0x6aad6f3e, 0xc7a60e73, - 0x1e8d6fe6, 0xebfd6f7f, 0xf42bf49f, 0xbecd3b63, 0xf3c1de31, 0x845dd927, - 0x93bd019f, 0x68d83fc0, 0x3b3c7273, 0x792d9e38, 0x5ba78f5c, 0xb1ff788d, - 0x33748790, 0xd7a0b644, 0xfe7905a6, 0x90bb39e9, 0x5b87900f, 0x4eec2f90, - 0x2c7efe03, 0xafa969fc, 0xc6575f1e, 0x7ee1a78e, 0x6ff6886c, 0xc91f7e3b, - 0x4b7a79c6, 0xb56fdfe3, 0x6309f05b, 0xea6eff46, 0xfb42af4c, 0x678aede8, - 0x9ff68b0c, 0xe7bfceda, 0x061ddb35, 0xf02cdbbf, 0x7638e521, 0x3cc40f9e, - 0x90cfa81d, 0xc31ece2e, 0x03e4bb3e, 0x7ae4d7a9, 0xfd911da4, 0x67f82f7e, - 0x8ccfe0ba, 0xfc1f3e26, 0xca9ac2b3, 0xdeff01ed, 0x7841eb9d, 0x9da2b21e, - 0x78f34160, 0xaddd67a0, 0x16f7d18c, 0x33fc1f62, 0xbb2df047, 0x07e81d6e, - 0x7e16fe92, 0xd738875f, 0xd407fd28, 0x7a9d134f, 0x0e1c43b8, 0x55f5c2b3, - 0x70927e8c, 0x7cfc3ac0, 0x138d171c, 0x8edc6fb5, 0xb58f42a9, 0x6322ef8a, - 0xfe7fe6e5, 0x569b911f, 0xe9025e71, 0xbcdf4f10, 0xc96eec25, 0x0562fedb, - 0xc04c6bf8, 0x624fc3e9, 0x1ce7ba4a, 0xb0bd40b0, 0x37cb414b, 0x82855720, - 0x45bc70df, 0x18f8a3e3, 0xf032e49d, 0x3e2a3fdf, 0x0366df0a, 0xa3a2dff0, - 0x2e2494e7, 0xf32a19c7, 0xc3fedf13, 0x80381fc2, 0x00d4efdf, 0xdf34505d, - 0x969bf01a, 0xbf4763dc, 0x43e66de7, 0xfb74e9bf, 0x8c78d312, 0xbf70b75f, - 0x6e2f4065, 0xbd07ebe6, 0x6d7a8ed6, 0x477edbcc, 0x2167d411, 0x5bce30fd, - 0xd379f8c4, 0xe3185776, 0x198f2925, 0xe0667b73, 0xa39d473e, 0xf75dbd61, - 0x277fa07c, 0xca8dcff4, 0x35ca0d75, 0x82b53bcc, 0x2b4eb3b7, 0x8b160fdd, - 0x47bec62f, 0xeff226f3, 0x7ae24c6e, 0xd234f50d, 0x6ec21ca9, 0x4afdc03b, - 0x798cc86e, 0xe4c657d4, 0x957dc44e, 0xa2c14943, 0xa67ef035, 0x29983738, - 0x26669bce, 0x126b72f1, 0x0e99cbd7, 0x5c1d065e, 0x79ba67bf, 0xef79d8ff, - 0x54defd12, 0xed7f064c, 0x7c3c8204, 0x38af9f30, 0x327e88cb, 0xed42bf4f, - 0x8002cdff, 0x9997456f, 0x4d3b07f2, 0xea24fac1, 0xfb1d12a7, 0x0f8b3d4c, - 0x1ef10123, 0xf3128ba5, 0xb167d493, 0xa3ea34fe, 0xfcf20d9b, 0x3be3825d, - 0x9190afb8, 0xfafcbfd8, 0x027e7d7c, 0xb7c26b7f, 0xfa496fe2, 0x8c80bccb, - 0x307f25bf, 0x6bad20f6, 0xbfce4cea, 0x6177afa0, 0xbafa0afc, 0xebc91a68, - 0x6bbc780f, 0x719178e3, 0x4f66667c, 0xc0b7c61d, 0xbc9ef487, 0xe4f729f7, - 0xe41e749b, 0xf537248d, 0xb7f0e5db, 0x5bc9c526, 0x6869a88d, 0x8487fba2, - 0x42f795dd, 0xafdf6a8d, 0x19be3aa8, 0xfee1c555, 0x60c59269, 0x7d443a17, - 0xd3971277, 0xa5115551, 0xd88dfa00, 0x015143ba, 0xfced119e, 0x0688f77c, - 0x0c9ff746, 0xf0e61bcc, 0x95870d8e, 0x70a28adb, 0x17669b37, 0xe69e0079, - 0x09af874c, 0xe0ce699e, 0xcd77080b, 0x039d08b1, 0x5bac7a9d, 0xd32978c5, - 0xf205ffe9, 0x6bd7849b, 0xbcc08cf6, 0x8718e3bd, 0x9fc065b3, 0x79e6c9ef, - 0x3c0aefc9, 0xc9fb09b7, 0x4efdd30e, 0x336f6e4e, 0xa6db19ef, 0xfd26673f, - 0xccd7e858, 0x72e3ee28, 0x614f799e, 0xb8ba03db, 0xb03f3cb1, 0x0f979f03, - 0xbf11371b, 0x307fcfb7, 0xc73ee2a2, 0x154d5b0b, 0xf6fc38e1, 0xa75394b6, - 0x2eb8d7ff, 0xc957ff09, 0x4967ec87, 0x1def9a1a, 0xb7060f82, 0xa5ed443f, - 0x84dfa64f, 0xd06cd6f0, 0x48f16e18, 0x033a67bc, 0x239f1027, 0xc4155bda, - 0x9f8e63c9, 0xae0e7828, 0xce798aba, 0xaef6d203, 0x7bc1cb6b, 0x7cee6a97, - 0x79ef072e, 0x38c0f092, 0x98d6ef84, 0x0fd28b73, 0x67e11ff9, 0x67033b94, - 0xcebafc70, 0xb7bfb44d, 0x5fbf0772, 0xcfbae127, 0x9eb02f11, 0xd5bfc8f5, - 0x5478bfc0, 0x8dfb0147, 0x6859acf4, 0x6a26efa3, 0x63fe7176, 0x18f0b41b, - 0x8eefb7ac, 0xe47da098, 0xa61f7edd, 0xed77abef, 0xf0e99656, 0x4c26b235, - 0xb9e77bfb, 0x97227ee4, 0x4bed11f7, 0xb38f886a, 0x63e43e1c, 0x71d92fcc, - 0xfdcecf3f, 0x1e52deaa, 0x425af49f, 0xafd0bd63, 0x87c93737, 0xbabd3bdf, - 0xdefa0afb, 0x35bcf5d0, 0x7ca3b8a2, 0x6f7ac0f3, 0x40f9c229, 0xdf20f339, - 0x835fde80, 0x2726f2f5, 0x1a9fbe43, 0x77a9c743, 0x3bf6be73, 0xc31ef2dc, - 0x63d7c889, 0x81aedc1d, 0xeebf205d, 0xf3c38590, 0xdd74e33c, 0x75c8149a, - 0x87f7e064, 0x54f18611, 0x86bb454a, 0x387608f9, 0xbd5bf095, 0x37d683b5, - 0x7bf71772, 0x92b577aa, 0x82fd4a3c, 0x7b7bc0f8, 0x457be2a7, 0x47040fc4, - 0x943b93e9, 0x927fd0e3, 0xbcf3ccc3, 0xc7ec775b, 0xf019887b, 0xd02fc60b, - 0xce4affbe, 0xe96e2a3f, 0xce3dc80d, 0x59e7c453, 0x097b93a6, 0xbff91c77, - 0x1e77e118, 0xe5c83eeb, 0x6fefc23f, 0xe921fc12, 0xf5c1c330, 0x21c7a48f, - 0xe300e80d, 0xa24bca1c, 0xa23ca471, 0xfa11ccfc, 0xc68ce4c9, 0x090e1249, - 0xd9472ee7, 0xb8298e15, 0x775a6eee, 0xe09556ed, 0x0502d72e, 0x3b7c75ab, - 0xfbf9c1cf, 0xb57782c0, 0xf9be781e, 0x9f0947e7, 0x3f0a2db5, 0x5472dac7, - 0x3e7a879b, 0xe319acf4, 0xff19ab9d, 0x51cf747b, 0x7757cfd2, 0x76d7bc70, - 0x736f56ec, 0xf728f946, 0x74c581e4, 0x95bb751f, 0xe9923fa1, 0x788cde0c, - 0x024fc418, 0x25cf520f, 0xf4871392, 0xf91a4253, 0xe421e029, 0xf520dc62, - 0xdf1156e4, 0xfe7f2730, 0x515d624f, 0x41ac10fd, 0xf927947c, 0xdf50d80e, - 0x3ce8544d, 0xe933b487, 0xf51e3833, 0x37bdc4f0, 0xd287e64f, 0xb25f8c98, - 0x63bee8e7, 0xe2b7d018, 0x5d04bbfd, 0x3f8479e1, 0x37687967, 0x74b1dc25, - 0x6bf081fb, 0x1351f0e2, 0x476b1fc2, 0xfac05f24, 0xf73db19a, 0x41ec89a4, - 0x86d6c86d, 0x98af26fb, 0x75df90e6, 0xf09b8160, 0xdf90b357, 0x67f9bc63, - 0x84d4af5c, 0x777f749c, 0x256e704d, 0xdba543ed, 0xc50fb87d, 0x79b50782, - 0xf774c1ae, 0xce9fbf3e, 0xcedd5c31, 0x8f4060e5, 0x4bfa73b6, 0x1fd72efd, - 0xcfc7375d, 0xec858d2c, 0x6dbc51a9, 0x7d08f24d, 0xdfe5cc10, 0x3ccd7fa3, - 0x7b1666f7, 0x88b3d29f, 0xcf5b5a8f, 0x2faadc21, 0xd35fbb79, 0xf2c727ef, - 0xd7baf557, 0xac2ed10a, 0xa54c3aca, 0xb7a0ff3e, 0x7d057b57, 0x8be5149e, - 0xa7985f48, 0xc93b727a, 0x0d07f54d, 0x0ace6f24, 0xc79c67ae, 0xd6307a8c, - 0xb4772a5f, 0xdefdc2cf, 0x9e2a1ff2, 0x5ed89626, 0xde7850ac, 0x2fada3f3, - 0xc19cf1bb, 0xe26bbdc0, 0x0e1bf03c, 0x3bbdffce, 0x97c4e101, 0xfe50da0d, - 0xc78d57e2, 0x74296f22, 0x7dc0808f, 0x1719aeef, 0xd2e7887d, 0x7e532677, - 0x375dd3e7, 0xc021f9dc, 0x72e3bbdd, 0x4de943b2, 0xfe9fe201, 0xf70fbb0c, - 0xa97e20df, 0xebee8050, 0xe3765fdb, 0x3f27e4fe, 0xda2270ba, 0x9c050fb7, - 0x5e667f27, 0xe7b97887, 0x865e9f99, 0x2561d5ed, 0xef6cf50d, 0x15fe1fce, - 0x8ed570f5, 0x9a9f8a7a, 0x0d4bf47e, 0xe14d39f7, 0x677cfe56, 0x7dfb07b2, - 0x65d37db2, 0xf6a6ef88, 0xb93f6a26, 0x07ea95bd, 0x4be9f99e, 0x33f68dff, - 0xbf61f6e0, 0x4fdb3f93, 0xaa09a974, 0x04f0defc, 0xeee8fd7c, 0xa19f5cfd, - 0xb07287bf, 0xc919eb90, 0x3f7f92d7, 0x8bd6e679, 0xc6bbfaf4, 0x60a5181c, - 0x1f5661ff, 0x7d07d79e, 0x15fbfa4e, 0xc4ed533b, 0xce9cadf7, 0xaf74d5e6, - 0xd73e7943, 0xdc61883b, 0x72febaf7, 0x91477d07, 0x4afb10e1, 0x293f1176, - 0xbcc3ed0a, 0x6d05e972, 0x217dba4d, 0x9457bf49, 0x1756a3d9, 0x8b379f45, - 0xb8939b79, 0xf514f93d, 0xd539c430, 0xac1efc65, 0x5f6c7f4f, 0xd6b5fe48, - 0xd76bf743, 0x34be7114, 0x9a3d393b, 0xb7e57e45, 0x39630ee0, 0xcf02e41e, - 0x8eeb40d5, 0xfadf292f, 0x1a6fd913, 0xbed357c2, 0x784752da, 0x0e7f11f9, - 0x8ee7c658, 0x354b06a2, 0x1b592f3c, 0xe91c5e3f, 0x3dfd3274, 0x663a2376, - 0xde92f28f, 0xe8c6fab1, 0x5511d2fc, 0x27dc26c1, 0x906d6ab8, 0xe17ea9ee, - 0x5ee937e3, 0x2ac667e3, 0x30df8893, 0x2f76847f, 0x6a79a4e4, 0x70078f31, - 0x7114ef9e, 0x17a987a3, 0x32aff1eb, 0x75fb49d5, 0x6a97a4fd, 0xdc5d859b, - 0x5b19e221, 0x6bde367f, 0x2f39ef0a, 0xc09bedd6, 0xd5274e7b, 0x8fe7b3fb, - 0x5a143b47, 0xabc87648, 0xa527bc11, 0x09a161fe, 0xa1e2e8b7, 0xf51738d8, - 0xca77e61b, 0xe77ea59d, 0xe3296894, 0xdd3c58df, 0x3877da25, 0xea277efd, - 0x16e79dc7, 0x7a09d687, 0x2cf4aa3f, 0xed0e3e47, 0x2f907bb3, 0x29eb2eeb, - 0x3bb1ebd4, 0x0b4e9e04, 0x41dfc13e, 0x64cdb8a0, 0xb5df110a, 0xa4dad05d, - 0xe77bb60c, 0x44757f09, 0xba41e2a7, 0xc73ad88c, 0x9bf03f40, 0x7f686bd6, - 0xe4252ac6, 0x7eae76cf, 0x11e61c6d, 0xaf586e81, 0x495d98eb, 0x833b03f8, - 0xe75d6cfe, 0x73840eec, 0x3eb5fa64, 0x3f0797dc, 0xe77d1664, 0xa0a6c351, - 0xda3a3efc, 0xad246fbf, 0x1e786143, 0x384b51f3, 0xa3f7ed0b, 0x787d0ae3, - 0x582ea63e, 0x0af24359, 0x2f7d2d7e, 0xfe40dc15, 0x26f79d6b, 0xc6a7ed1f, - 0x853ef9ca, 0x1be054fc, 0xab8b1dfa, 0x7c2cbbf1, 0x7920ec3f, 0x2dccebaf, - 0x9eaef845, 0x9e60f3e9, 0x8fc494ed, 0xf4dd2d2c, 0xf7a7183b, 0x27485958, - 0x03eeaf97, 0xf80266bf, 0xafc17b35, 0x3fdf8099, 0x1571d9fa, 0x0d7a71c6, - 0x5deab779, 0xcdef74b9, 0x7f8ed129, 0x2d7ddd5e, 0xe21195b5, 0xcfe11acb, - 0xc5fd5ba6, 0x26e8ebb7, 0xfa5894fd, 0xf6e4ee3f, 0xe727bce8, 0x00463d12, - 0x239f103d, 0xa26e9ab6, 0x863485f5, 0x8aaabbeb, 0xbe01ea45, 0x229ab6ab, - 0xfa884f97, 0x3de3b131, 0x4f7114e9, 0xf518a05a, 0xa702f95b, 0xca87af4f, - 0xbb26fc93, 0x2c628fce, 0x92e31930, 0x845d338f, 0xaf4e1df7, 0x7e0c87f4, - 0xd3b8e0cf, 0xe1f8c3ee, 0x04d0969a, 0xaf0e87dc, 0xf2885a4f, 0x49d47a08, - 0x781eebfb, 0xb6d6e31f, 0xb8f3b64b, 0xf9d689b5, 0xc247a77d, 0xe301b937, - 0x5ac0fcdc, 0xbe5c7f6e, 0xe5d6fb78, 0x2ee7e94e, 0xbef3c62e, 0x3e9d7375, - 0xff36af8c, 0xe38a5942, 0x746c85d7, 0x705d6e39, 0xf2579bed, 0x5fdf8038, - 0xbaa2fc23, 0x347d1bf4, 0x7a7e20ff, 0x4e8ddb8f, 0x4ebaaf4e, 0x1c642f6e, - 0x5e217a8b, 0x29ca5ede, 0x6b8c63ea, 0x39497f24, 0x3c79573d, 0xfc90096d, - 0x2375869c, 0xe1f00e3f, 0x630f9c0b, 0xff8934e3, 0x8bc2f8d8, 0xef7506c2, - 0x8f7d0776, 0xe69af52f, 0x3d451c0c, 0x6476d754, 0xd0abb123, 0xdc2f7543, - 0x3f94385f, 0x78f95365, 0x3d2b9036, 0x1359e0df, 0x432a44d7, 0xc0df3a4e, - 0xc6df5fb8, 0x1d8e8fef, 0x4f42b7ef, 0xbf4a7c49, 0xcf82f319, 0xc29ff943, - 0xfa227d7e, 0xcf29d5fd, 0xfc0d8457, 0xdf0535e7, 0x44f17dc3, 0xf7be56fa, - 0x7226f34d, 0x63efa97c, 0x99f325e9, 0x45d98eb8, 0xecb5fb89, 0x0c48f117, - 0x3e0b14ff, 0x80e7037e, 0x07724f75, 0xbea0b917, 0xd3f99928, 0x7e8bdf00, - 0x29f7e569, 0xc42fed8c, 0x655aaa78, 0x5797cc21, 0xf584b4ef, 0xa1f736e7, - 0xf5ef040f, 0x33216cb9, 0x3bb95df0, 0x0671c1e8, 0xcbbd87ee, 0xc1e1e74e, - 0x7282994d, 0x481ed23b, 0xf7e06575, 0x4f743d89, 0x1e0e63ec, 0x311ff44f, - 0xc5cbcf87, 0xe87bbe7b, 0xacce84f7, 0xea7ca7cd, 0x61fc2f3b, 0xede01fcf, - 0x1a3e7b53, 0xd493cfad, 0x55364cd9, 0xad3c6f97, 0x2b67dfc4, 0x167d7176, - 0xf3f65bcd, 0x438be5bc, 0x63eb41e7, 0xf3d1fbf2, 0xfdf9b1b3, 0x6fa878e8, - 0xfbf263eb, 0x6f5c5d07, 0xf9e7df47, 0xf14c77fd, 0xc7bd6fbf, 0x8bafdc65, - 0xc5cfbf6d, 0x8f23abf9, 0xe3ff45cb, 0xe4fd184a, 0x115d6be5, 0x396b8fbc, - 0x63bf463c, 0x311427b9, 0xf9ae51b9, 0xcdfc323e, 0xbe5f81b5, 0xe807d844, - 0xbe474ea7, 0xff68790c, 0xd0f42831, 0xff57ce92, 0x72f4f18c, 0xc3a6d995, - 0xbe6d4b38, 0x13fbf843, 0xba673a1f, 0x7e56ed51, 0x744c86e7, 0x6a2d86e6, - 0xf455bca0, 0xf374f57c, 0xfabe72df, 0x57302bb0, 0x7fd21bf2, 0x5f5cedd1, - 0x9756fec8, 0xe467373c, 0xd01377b7, 0x665dc739, 0x3ababe46, 0xc698b029, - 0x4194fdbd, 0x7a569caf, 0xf201fe9e, 0x7bfe6ae3, 0xd7efb147, 0x8afaf98a, - 0xc53ee9bb, 0xc97fd5be, 0xebaebf26, 0xff51b7d5, 0x817bcad5, 0x7b862c3b, - 0xfc932b81, 0xf7efc4d5, 0xfba14f4d, 0x73c186ce, 0x1ab82782, 0xf6fe41e1, - 0xdbf9eba7, 0x2ce78c9b, 0xba01b5ea, 0x921ef7d0, 0xcb946c2e, 0x23ae8f48, - 0x36a58f44, 0x701bdd3f, 0xf0403f9b, 0x4c8e4a2d, 0x5ff018f1, 0xf7dd37f4, - 0xf6e42958, 0xfdfe2d1d, 0x3e09f7e2, 0x8dfb283c, 0x4efafce0, 0x1e7aab36, - 0xff234ccb, 0x2ce42c3e, 0x71cbde2c, 0xbc421ffb, 0x18795e80, 0x8e7400f1, - 0xcaf5e8a4, 0xe7ba7ee4, 0x374a6fa2, 0xae7d1f7d, 0x80ac66f8, 0x8e784bd6, - 0xd1385e73, 0xf0b56f7a, 0xb5df0075, 0x47af48b9, 0x87bfebc6, 0x5b80b9ff, - 0x493be5ca, 0x142cbc46, 0xe091fbeb, 0x87974a93, 0xfd7c1be7, 0x3bce38d9, - 0xb8f1f1a9, 0x768f8a28, 0x7fb583c2, 0x6fd01a71, 0x6d35d83e, 0x12a7e122, - 0x938a0f9f, 0x49ff228a, 0x5c6b6dfb, 0x0bc5ed0c, 0xfdc9be72, 0x963f8f3c, - 0x885a0bcf, 0x57d96eff, 0xc2bd6de0, 0x3145e77f, 0x2b6844c3, 0xdf2f32c7, - 0x7fce980f, 0x203ecaaf, 0x195c8797, 0xcec4fc51, 0xc09b0c7b, 0xc4bb779e, - 0xe63e40f7, 0x1f16f7c3, 0x8b75ccfd, 0xf43df0d7, 0xef4e385b, 0x1fc8479d, - 0x0a45a63b, 0xda719c5b, 0xc7b6c8b5, 0x6b3b6894, 0xadc17ee0, 0xbbe99acf, - 0x9ea66398, 0x2d7f7047, 0xfc99a6f4, 0x3dde3fa8, 0xfa2bbe83, 0xffa30ef4, - 0x45d0527a, 0x20309f7e, 0x830b783f, 0xc5eff079, 0xcb9ce6dc, 0x3ee629e5, - 0x14164af6, 0xfb13fbbf, 0xe103427d, 0x893df079, 0xe73c87eb, 0x7ce6e995, - 0xf38269f3, 0xebfb8a19, 0x3ee327da, 0xc4bed45d, 0xf1f1d3ee, 0x474e6edc, - 0xf6fea769, 0x304aaef9, 0xe77175df, 0xba7cf393, 0xb3bafe3c, 0xd58edcdc, - 0x461becc7, 0xb3e795c7, 0xa49fa85a, 0x2cd9fd77, 0xd2eb2e7a, 0x37be8a8f, - 0xfd8bc68a, 0x13e6472e, 0xa7beff25, 0x9efd1b30, 0xf224db11, 0x78099e86, - 0x687bd0bf, 0x06df412f, 0xf52f60af, 0xfe4b8800, 0x9aa17879, 0xd8efe517, - 0x9d5f0075, 0xd51effd4, 0x4fb8b704, 0x217642ef, 0xf821177d, 0xe59df179, - 0xf25aee74, 0x854f546f, 0x71adbc78, 0xa7319e3f, 0x18b3ff41, 0x13a4b0fb, - 0xb204c1ec, 0xfc0e74cb, 0x12378bf8, 0x5f32571f, 0x17d1e926, 0xe93f74ad, - 0x120bb5d7, 0x4b421b9e, 0x8adefc2c, 0x6bc7ba74, 0x86ff988e, 0x981fee2e, - 0xfbfe7e6c, 0xf5e67e55, 0x03dff264, 0xca05fb21, 0xa5fa855d, 0x00cc8eb2, - 0x3162e9f5, 0xf00fbe0a, 0xb64a2a5f, 0xf2859834, 0xb7ffef26, 0x961670b3, - 0xbcf9174d, 0x04ae5e58, 0xa7070e54, 0x30d62cf3, 0x6c9bfb0a, 0xff9c663d, - 0x58da7991, 0x4fa01fbc, 0xdf89f249, 0x74fba3fb, 0xf3f303ad, 0x9dd64bba, - 0x0eefc32e, 0x7dc5bbd4, 0xa366360f, 0x4673ebdf, 0x057da13e, 0x616cda51, - 0x0701ddfa, 0xcdba448b, 0x8c00fbf8, 0x614f9bbe, 0x3dfc112d, 0xff17be8c, - 0x1e1c518b, 0x76fc0fbd, 0xef2194f7, 0xc7b6370b, 0x2a9e17dc, 0x7e634ae0, - 0xad221fba, 0x635f78c2, 0x42ad7386, 0x3016e13f, 0xc444cf3e, 0x0b61ff43, - 0x6f0bef63, 0xe1fc7051, 0x1b73e341, 0x5f7a463b, 0xbeb20489, 0x93de8b4c, - 0xdf8920b4, 0x22eff44b, 0x115b9c8e, 0x6f015728, 0xafd88bf3, 0xe8de50fc, - 0xe1177e09, 0x4370f1bf, 0x17d40d6d, 0xe3c6cebe, 0xc9c530f7, 0x185dea9e, - 0xefcadd7f, 0x3efe2d6b, 0xec361d67, 0xf0c78a3c, 0xc9b51707, 0x2b2ace78, - 0xb17d718c, 0xd48fb443, 0x7f18bda8, 0x3fdf1100, 0x95f74bcf, 0x74f38bd4, - 0x9a7987f8, 0xc333f3d6, 0x67d30768, 0x7ac46ff4, 0xee8cfdff, 0x19f79059, - 0x408ec76d, 0xbf4afa9f, 0x87da0325, 0xe23e64cf, 0x03bed149, 0xebcf9dff, - 0xdf889797, 0x5d47c08d, 0x2733ca9b, 0xc6fa9b13, 0x5cfcc1b0, 0x18bb35df, - 0x73f954f3, 0x297f13a7, 0xba0a2f82, 0x7c51ff14, 0x3f68c22f, 0x972bbeb5, - 0x1c17dfce, 0x719e51f6, 0xd4e1a981, 0x1bdf5c1e, 0x13effe3c, 0xc84cc6fb, - 0x7918d4f3, 0xafca24b9, 0xe72c5ed4, 0x7accfb97, 0x3ce046be, 0xfc44a0f0, - 0xc7bd12c4, 0x1662ece5, 0x6671c3fd, 0xbd25c744, 0xbdb45332, 0x3fdf0b72, - 0xf646aa9b, 0x225e1ca3, 0x4e5162ca, 0xe2330166, 0x7f73c4ab, 0x5177ce13, - 0xf21a68e0, 0xaf9b74fd, 0x9f46af19, 0xb86150bb, 0x4e9cc4af, 0xffb17ebe, - 0x3d8af52d, 0xfb67e799, 0xddbab3dc, 0xdf997dba, 0x30df85ba, 0xb98d8d96, - 0x24f7ff67, 0x3bffa517, 0xdb18dc91, 0x4066e463, 0x7d3f313f, 0x7dfb18b7, - 0xff3f3ce1, 0xc05e6a6e, 0x7e3e7cf8, 0xe71f97d7, 0x15d0ec77, 0x0b8e8ccb, - 0x78416472, 0x6ec77f62, 0x2ab7f48e, 0xa2d6fe8c, 0x8522fa7f, 0xa7b0c0ec, - 0xc1ccbf6b, 0xe25ce67c, 0xb12ebacb, 0x43fc0f3f, 0xfd89e3df, 0xe34efaf9, - 0xd77d7cfe, 0x74337b92, 0x9d75f3fb, 0xcf3fb55f, 0x5bbfeeed, 0xd30f74c2, - 0xd604afbf, 0x165e7982, 0x7107c2fb, 0x9462783f, 0x3cc5aeee, 0xe35073af, - 0x3107f4fb, 0x4bcba37f, 0xfcf070cc, 0x340b8ce8, 0xe5573e7a, 0x2129f2fb, - 0x0b92f927, 0x665defc4, 0x7e41d998, 0x1fe7847e, 0xeb3e22c2, 0xb40d7e16, - 0x47fca06f, 0xa465dc8c, 0x6547ca31, 0xf2963cdc, 0x8abb0b3a, 0x0d3e6327, - 0x7fe533f4, 0x7a5eddbb, 0x98b0617f, 0x395723f2, 0x8af3a46f, 0x6aad5df5, - 0x7adf4ea5, 0xf5f78d93, 0x9a5df9c4, 0xfa29e482, 0xe019a5df, 0x489e7a27, - 0xa7dfcb0f, 0x9bbe62ac, 0x7de2e597, 0x9d774001, 0x3194b79d, 0x53fb4f7e, - 0x5d2b9d0a, 0x76483ce5, 0x630ed578, 0xd45b943f, 0x6bafd57b, 0xcd537f74, - 0x467c41ae, 0x5de52d72, 0xa1b517de, 0x3ee0afd4, 0xe611df4f, 0x77fa436b, - 0xc05b8cc4, 0xe04f98ed, 0xa5e858b3, 0x3666f349, 0x24e53ee1, 0x565f9713, - 0x7fc91be9, 0xe7917377, 0xc7551d84, 0xfe50cad3, 0x63eb9f40, 0x067dfcb3, - 0xc4531fd4, 0x717ab1f8, 0x2e03f08a, 0x137d6153, 0x0a7d76a3, 0xa683f5e3, - 0xbddd332e, 0x3c9ce02f, 0x9fdc4720, 0xd24a7a90, 0xc6e5ef03, 0x92cb5df3, - 0x63c87e85, 0x184f4879, 0xc157f89f, 0x8d2a73cc, 0xbca1521f, 0xf407cc44, - 0x84df210e, 0x9dfa364c, 0x034a8d8f, 0xfa1b79e9, 0xa03e508d, 0xfd7f4904, - 0x46642abc, 0x1ac45ebc, 0x1726b86e, 0x03b758f5, 0xb07c05e9, 0x4d1fcf52, - 0x5bbd922c, 0xb509f031, 0xe8c4a6f7, 0x3d12a61d, 0xc238304c, 0xa5ad7669, - 0xc42bf47d, 0x6e53a273, 0xc9d51fb4, 0x3fb4618f, 0x87c01fea, 0xf52fddb1, - 0x93ea3309, 0x8f05f65c, 0xf43feed3, 0xfb0f8c1d, 0x8c5fc22c, 0xa1dd4ba1, - 0x641f8b93, 0xbe49fa51, 0x983598ba, 0xca1f00b3, 0xf75e792f, 0x2a5ba462, - 0xfc8c51fa, 0x892c69a7, 0xe64d8be4, 0x57c907f9, 0xa2255e92, 0x4fa484f6, - 0x7841cb0e, 0x53b4ed2f, 0xa462e9de, 0x58bdd013, 0x4aed2f8c, 0x6af4e4c4, - 0xb0174879, 0x7ec1e61b, 0x97aa665e, 0xe4c933e8, 0x614cfa27, 0xdba434be, - 0xd7ddf6cf, 0xe8eb7084, 0xe3192db0, 0x80e80545, 0x3ed8357c, 0xe463db18, - 0x94bbe259, 0x2c9fc979, 0x9c394665, 0x670d04e1, 0x8dcafba2, 0xa0b363f7, - 0x7b94f08a, 0x6f8fdd06, 0x41b1d232, 0xc8ae7845, 0x444bf632, 0xa7a41ccf, - 0x89690fb4, 0x6ae529e9, 0xa9d39db7, 0xfa84e81e, 0xd2afd266, 0x34813867, - 0x25ccade7, 0xc53bb0fb, 0xfaf584db, 0xc5f4851a, 0xcbdf6ee4, 0x106fcf58, - 0x337eb9ed, 0xafd683ee, 0xde53ede5, 0x7ac0cc0a, 0x5ede3ac1, 0xc9b04f7c, - 0xaddfe385, 0x2fd8bdd0, 0xcbc7727c, 0x47be1ed8, 0xcfca5fbc, 0xe06fd6e1, - 0xf9847fef, 0x3cf10bde, 0x7c0ccb44, 0x9739ae3e, 0xf0b00eff, 0xfc172e67, - 0xe3695bb2, 0xc83c20f7, 0xc8715dc7, 0xce28c496, 0x65cafee1, 0x6f979d62, - 0x3f4cebe5, 0x1785557e, 0x37b2a9f8, 0x2d95d740, 0x1109c164, 0x3372ef58, - 0xf1f9f204, 0x10bc1be4, 0x0d288f28, 0x500aa744, 0x72fbf49d, 0xc0b67cd3, - 0xc7ef9e78, 0x92fa79ef, 0xf329bc79, 0x35ffb8e5, 0xfb4f675b, 0x469e7992, - 0x654ccbf6, 0x09ef3f7c, 0x91a3f917, 0x7c8298c7, 0xfec0b88f, 0x57faf289, - 0xbd9037e4, 0xe64722ba, 0xa5d47bf3, 0x97f15f30, 0x178acd9f, 0xcc9e7f07, - 0x62c7e4ed, 0xaf3e4f1f, 0xbdfdf30a, 0xf4cbc8dd, 0x30e9ad7d, 0xe19853d5, - 0xb9ddab1e, 0xfe7aaebc, 0x28f35f7a, 0x06b35dfc, 0x36ca8435, 0xcc7da15b, - 0x679fe0eb, 0xffe14627, 0x2830d93f, 0x00800092, 0x00000000, 0x00088b1f, - 0x00000000, 0x7dedff00, 0x45947c09, 0xf37f78b2, 0x093215cd, 0x87213b93, - 0x98884013, 0x861c2184, 0x4109264b, 0xe8098414, 0x720d7282, 0xeb22dc85, - 0x97f75763, 0xd9110441, 0x73d6f8dd, 0x0160763d, 0x18896151, 0xc3824830, - 0x12a20882, 0x75040411, 0x0844ae22, 0xf1e20c49, 0xabaf2e1e, 0xbe667bba, - 0xfc38666f, 0xddbf7ffb, 0xdb2e23f7, 0xaaefafa9, 0xeaeaeaea, 0x084c8eaa, - 0x908238b9, 0xadc4b45b, 0x9680a1cf, 0xc8401bfe, 0xd5fa25dc, 0x3f02242b, - 0x213c6376, 0x33fe1277, 0x192d7aec, 0xf01dc844, 0x289085bb, 0x2afda4b3, - 0x9fdefe83, 0xd328bff4, 0xf3bfcf72, 0xc84d94a3, 0x3a558caf, 0xd50a1dd2, - 0x8459ece8, 0x9c9b359c, 0x7c84be9a, 0xcce2392e, 0x7d690903, 0x965cff76, - 0x64beceef, 0x47e696be, 0xb048d4d0, 0xefde62df, 0x13d2e27c, 0x977cdfda, - 0x918f0bee, 0xfd22ed0d, 0xa43a6a57, 0xae9a1a27, 0x232f7e57, 0x41e93d1e, - 0xf2ad7948, 0xe271257b, 0xe57acaf7, 0x91d99277, 0x845efd06, 0xf69f8a1f, - 0x5907cb67, 0xcfff6932, 0xe6147fbc, 0xb9346c57, 0x97129a65, 0xc193d5ae, - 0x1e7ce1eb, 0x4e157f34, 0xc8fba793, 0x64246f17, 0x6cc89752, 0xbb9095d2, - 0xe67e8ecc, 0xf99c4238, 0x146529e6, 0xe1e9cebf, 0x5c5025d6, 0x4c396536, - 0x6308fdb4, 0x8bce9b96, 0x4cc588d8, 0x79f12df1, 0x9f0c0d4a, 0x3c52471f, - 0x4832f8c3, 0xe699e006, 0x14d1f53b, 0x8448e3ee, 0x93881bf1, 0x88c23e00, - 0x4252112b, 0xbf1846ac, 0x42475e1f, 0x2179adff, 0x57ccaef1, 0x1f027de1, - 0xd36244cf, 0x47137f41, 0xa775f12b, 0xfbd22169, 0xfbf2bb4e, 0xcb1388af, - 0xc2ac9a4f, 0x24c9b12f, 0xe0aed7de, 0xca1cbb93, 0x9e041372, 0x3cf1ab47, - 0xc515fccc, 0x01309d2f, 0x54d24c7c, 0x58c9e3fd, 0xb30d6f0a, 0x1cf6c5ae, - 0xb852178f, 0xbac12eb3, 0x4b44c002, 0xfdb409d7, 0x926c404a, 0x3d22ae8f, - 0xab189d58, 0xe707e9ed, 0x93761991, 0xee389e0f, 0x1499a0d8, 0xcfe5d22e, - 0x06913c03, 0x29837ffa, 0xd210c53f, 0xb2f80994, 0x18262574, 0x52d47107, - 0xde92d3b8, 0xd814da35, 0x132b488f, 0xfdb4e313, 0xdb4bf8fd, 0x3e066911, - 0xb0cf20b8, 0x2a383267, 0x53f552f3, 0xc131b4e2, 0x5acf37fa, 0x91787809, - 0xa38e81e1, 0xadf943de, 0x2b5f7d73, 0x2a7210e5, 0x942468ce, 0xa67467de, - 0x1f5f52e5, 0xea2ee63e, 0x4a95ed86, 0xd0b6efae, 0xc764836f, 0x52cf3023, - 0xf8cf5b8d, 0xa13a6aa9, 0x6f3f96ed, 0xf748adb0, 0xf8d43fcd, 0x2d23f008, - 0xc93bffa2, 0x1d7ad2d0, 0xeaeb1752, 0x0bdefc74, 0xddca2ce8, 0x2b17451f, - 0x9185ef5d, 0xdd60278e, 0xe8b8c3b7, 0xa309697a, 0xaf8e86eb, 0x01932245, - 0x74e2549f, 0x7e02ca2d, 0x04eba3bc, 0x951297ca, 0x81d1c953, 0x351856fd, - 0x5e1fb764, 0x757d78db, 0x096655b9, 0x9989f7c7, 0x4dc7ff60, 0xdf30d5b6, - 0xae293d16, 0xe96c78a5, 0x9a48d3c2, 0xa01bfad2, 0xcf2840fc, 0x70e0edea, - 0xabe5868b, 0xbee517db, 0xdd9236ac, 0x545fac74, 0xf29bb213, 0x4369e597, - 0x4bb68b95, 0x147fd2a6, 0xa2dbed2f, 0x453e0156, 0xbce67dbd, 0xdd1c604f, - 0x802df64d, 0xcd35d98f, 0xfb5f877a, 0xe01f30ed, 0x579b1d13, 0x454b187b, - 0x45ccfb7f, 0xef1e209f, 0xbcdd20f2, 0xdb0160f0, 0xe1f6fdb1, 0x1fd21e4c, - 0x72c3ac0d, 0xc5cb0ebe, 0xae53ab7a, 0x04a64937, 0x63f9468d, 0x5aa0b941, - 0xc67a957f, 0x17ef844f, 0x4ebac4d3, 0xfb42d089, 0x64535953, 0x1fbec35a, - 0xa64248a5, 0x64b2c91b, 0x21a33f9a, 0x7175e501, 0x1997b3a4, 0x0cd23ce9, - 0x0ce489fb, 0x5f862f97, 0xe4b4bf8a, 0xd93e312b, 0xa9ed6fc7, 0xf6cf384d, - 0x81a63f55, 0x786f2ebc, 0xa875e507, 0x191f3979, 0x48f38516, 0xd6e0fb60, - 0xd9391b6a, 0x059787d3, 0x428f3666, 0x0f40acb9, 0x313664f2, 0x7ea7e81b, - 0xc3d3fba4, 0x57b95c28, 0x6f285c47, 0x93901a6c, 0x9c63c397, 0x7e2c435d, - 0x72612df2, 0xf0c96217, 0x688e49c1, 0xdc5c9c05, 0xb53e514d, 0xff22bbaa, - 0x147d45ba, 0x1ccee9f9, 0xf963dc05, 0xebf94510, 0x7015f26b, 0x536e67ef, - 0x35c1bf94, 0xc2770141, 0x9e3f202f, 0xca4e5d97, 0xbfae37a7, 0xde7f515b, - 0xbf4859be, 0x895ebe3a, 0x4994d6d3, 0xd05b30f1, 0x80686e9f, 0x670e52c7, - 0x68a3ded5, 0xb725b89f, 0xe1cfcb44, 0x69bb31fc, 0xf94258ee, 0x897d6fa3, - 0x67221fa2, 0xd28e30ca, 0xa18912ed, 0x46a73eac, 0x7bcc4fb9, 0x37170946, - 0x992cbe3c, 0xf407ea04, 0xdb4b4327, 0xac5d2129, 0xf5a8dfa0, 0x11519e84, - 0xdd0fc8b1, 0x57c63748, 0x79303e6a, 0x074861f1, 0xf4f5e83e, 0x3e3e01b0, - 0x19ebe2f0, 0xb9d5f109, 0x7b8e07b7, 0xee3a36de, 0x18fc40f4, 0x10fc9512, - 0x43f25166, 0x1f928678, 0x7e4aac22, 0xe4ab9ae8, 0xa3be3507, 0x20fe4a6c, - 0x105ffa1e, 0x568cc77c, 0xbca94df2, 0xefe00f72, 0x5f9e7872, 0x1fe90abf, - 0xf0a987a0, 0x1af01e3a, 0xff6bc3ee, 0x2625b6dd, 0x61df660b, 0xe478041c, - 0x197620f8, 0x046c52e5, 0x3e561dea, 0xcca7a14e, 0x107ae288, 0xd69fa76f, - 0xf7d613bd, 0xa049c932, 0x967fd09e, 0xdcd3bae4, 0xc639df14, 0xd520a02a, - 0xa2b3ec6f, 0xd32c1ca8, 0xdf21b3bb, 0xefc1ef4f, 0x417bd2ad, 0xa7411ef5, - 0x7281c439, 0xa61f0025, 0x2f50f427, 0x3f40ff80, 0xff8411ed, 0xed077ea8, - 0x5179f256, 0x7234b93a, 0x06a4be20, 0x0d911dc9, 0x72106cd3, 0x3fb171d6, - 0x157ca366, 0x4a0da2f8, 0xe84772fe, 0x817da28f, 0x448f211f, 0x255206bb, - 0xab7f0227, 0x50c913e4, 0xa9371de2, 0x223ff841, 0x35e80bd8, 0x416f9bc4, - 0x0899037e, 0xbc4de94a, 0xd30f723f, 0x06a48d4b, 0xb242b2e9, 0x7f69972e, - 0x4be975f2, 0x7f4ba508, 0x64ffd533, 0xa69b42d8, 0xd18d77c0, 0x773ec329, - 0xfe60b91d, 0x3f5a06ea, 0xc5f95d61, 0xbff2d098, 0x5b8d8dfc, 0x281f549d, - 0x2464f4d9, 0x5afaf4a1, 0xa56f135b, 0x2ed6cbf5, 0xb4d1b48d, 0x7d44eb45, - 0x3c976bea, 0x7f6415da, 0xed8a3f7e, 0x264274df, 0x7c153f90, 0x795fa72a, - 0xd7ac1c6c, 0xccead6ef, 0xb9522d32, 0xd036e0de, 0x375151f5, 0x46c92c7f, - 0x8fc199b8, 0x54f8037c, 0x5e4a1b9f, 0x82de327a, 0x5933a3fb, 0x3ba90893, - 0x62b4d099, 0x81463fcd, 0x3a49567e, 0xd4b8c196, 0x1fffa0f5, 0x595afee8, - 0x77d4cf2b, 0xe11e720d, 0xb5d05aeb, 0x6fb1eeb2, 0xcdf848e4, 0x557e07a3, - 0xbd062f97, 0x3b67ea8e, 0x89bb3c84, 0x45eb04dc, 0xe2b883e0, 0xdf93ef50, - 0x99bb2178, 0xf66badc2, 0x787e4a47, 0xc421e422, 0xaced674f, 0x0969bcbf, - 0xaa36874d, 0xfe5e90d7, 0xcf585cf5, 0x9ee12f52, 0x5a581a4a, 0x0e4773a6, - 0xb654aca5, 0x687a874a, 0xaebfc6d9, 0x33c533fb, 0x5eb06639, 0xdd2fdb4f, - 0x43c7f6f8, 0xa6bfbe40, 0xa6cb1d8b, 0x7de29261, 0xffa4a974, 0xe8f8e516, - 0xdbfaf250, 0xfb164b7a, 0x8fb460fe, 0xedafa51e, 0x40ac93d4, 0xeed4147c, - 0x414c7bd4, 0x3cdb52e8, 0x1e02648a, 0xdd03d27e, 0x9121debf, 0xf820f484, - 0xa476f55c, 0xe909e383, 0xa5e4e9c8, 0x5cfabd5b, 0x412bf4c9, 0x2bbe7527, - 0x0afa8cca, 0xca7a87b4, 0xf6ff1b1b, 0xf14fc526, 0xcc2b0627, 0xf76ff8bf, - 0x4e3cc245, 0x5f18ab69, 0xde34b0bf, 0xd62dfb46, 0x98cde339, 0x2fc5efb2, - 0x6df91afe, 0x8ebf87de, 0xd93fa827, 0x38b93492, 0xdf9824cf, 0xc4efe79c, - 0x0e25cdf9, 0x17e2bbe4, 0x9fe83b64, 0xf464b5e7, 0x45d6416b, 0x175b3441, - 0x15d356a7, 0x4a77e74d, 0xf38044cf, 0x8b5aeca0, 0x517bd287, 0x28dafc18, - 0x8402ffd6, 0x9d191bcf, 0xf86b45ba, 0xdf4ba2ba, 0x3cd75f9f, 0x39f404d2, - 0x004b6a9d, 0x6892af3d, 0xd21f1c9d, 0xfcaeda45, 0xa3026161, 0x8568b10f, - 0xa8f2a47c, 0xf943be00, 0x2c2d9d26, 0x5c8f515b, 0xbff5f74c, 0xc74ff790, - 0xd0f405dd, 0xf5c1f153, 0xa668caf2, 0x269fd327, 0x7e5fc7e2, 0xf7ad9beb, - 0xf5b28f35, 0xabbbd62d, 0x7fe43468, 0x1fad887b, 0x839c97a8, 0x602772e3, - 0x243bcefe, 0xe2060794, 0xd7aeb60e, 0x56baf8e8, 0xa13e0be6, 0xb9c2d6e3, - 0x842fcbc7, 0xf14e6f9d, 0x27dcc8f3, 0x7dbf3d68, 0x8bfa12be, 0xac4f6c0c, - 0xfd7c79db, 0xf7cd1cdf, 0xc9febe5d, 0xcf4171f3, 0x5b73eabf, 0xeeb5ce99, - 0xe95eb0cf, 0x605a74fa, 0x30eceabd, 0x761b33ef, 0x5d377c7d, 0xc56a6727, - 0x4fca553a, 0xde2d3af5, 0xa7f236fc, 0xa99e9d7a, 0xe83e3b7d, 0xeded7d3a, - 0xb0664f78, 0x2bbffa75, 0xe6fe053f, 0xa7e52b46, 0xf0a18790, 0x728796a8, - 0xa9f105b4, 0xe7f48796, 0xc8141910, 0x04ef827f, 0x5abc95bf, 0x1dc81d7e, - 0xbe0a5f2f, 0xe0a5f2f3, 0x957cf53b, 0x5be753f8, 0xf9472ce1, 0xf0edbec4, - 0xcf4a64a8, 0x6ac906b2, 0x3dbd60b0, 0xd93c5300, 0x35231b70, 0xfd63927b, - 0xae0a9761, 0xa9b79555, 0xbcaabb60, 0xa9570543, 0x5c70bbca, 0xf4bbf565, - 0x5b81e504, 0x10f75e51, 0x3d804671, 0xad7651a1, 0xa76ca8a6, 0xeb465e63, - 0x47486fb7, 0x12697b7d, 0xc474dbb3, 0xfc8197e9, 0x4477376a, 0x75fc5346, - 0xb373f184, 0xca3223bd, 0xdcd32ecf, 0xf5fca320, 0xdae8c8b8, 0xaa1af620, - 0x3cfd2249, 0x62fe5424, 0x4d90bf66, 0xef408b69, 0xa0ad91af, 0x3c5ecd0b, - 0xcef41229, 0xe31e86f6, 0x73efd327, 0x43baa1f6, 0x903db9da, 0x49b4039e, - 0x38b3fe94, 0xe710b63f, 0x7ce8c353, 0xa2943566, 0xa57b3e3e, 0x4d735e92, - 0x9ccf510b, 0x1efd04fb, 0xe12fdf44, 0xaf3f14ed, 0x2b212fcc, 0x1d289f91, - 0x297760f5, 0x77cca359, 0x2ecffb70, 0x48fde7c1, 0x87b9c53f, 0x3942d5cb, - 0xb064fc73, 0x0995ec57, 0x836749f0, 0xdcef788c, 0x9e08b920, 0xa83d986b, - 0x3ca07482, 0x8569f813, 0x2d0fa0f5, 0x7cb75a6f, 0x5a01e83a, 0xf1eb6ca4, - 0xda68e7ec, 0xaf58f5ba, 0x71bf00ed, 0x0938ed24, 0x08ed3fb2, 0x64dda1b3, - 0x00cb8447, 0x3f7c6ff4, 0xa3b401ed, 0xce30ac18, 0x67df1df6, 0x3fb4df03, - 0x79062864, 0xecca9ed5, 0xbf1a4b23, 0xe57266cf, 0x5b57a461, 0x37e99eb4, - 0x99fdff0d, 0x06fae704, 0xf7d82b3a, 0xf9e38477, 0x30cdf2ad, 0xbff6c117, - 0xfd30e41f, 0xd0a9f372, 0x61f20713, 0x19bc9904, 0x704517c6, 0x07db953e, - 0xed3175ff, 0xa76ebcbf, 0x2fcd167e, 0x6ca7eb78, 0x37db0fd8, 0x4da67d33, - 0x5dd2b847, 0xad1e68f2, 0x61c616d7, 0x056eefe7, 0x160db77d, 0x9e423747, - 0xab70d98e, 0x4f0c14d3, 0x5e21a53f, 0xd13f10ae, 0xfbe47a31, 0x48fc7d7f, - 0x2bf28236, 0x609465c2, 0x767e3fde, 0x0ec1e41c, 0x98a9f203, 0xc5da99ef, - 0x6e5c7fa8, 0xfe62fdde, 0x4ae2f85d, 0xafb92de7, 0x7ff6de64, 0xe21f7a71, - 0x5d7aa8fb, 0xe379f204, 0x8c6f08fd, 0xaf78e2b0, 0xfeabdf90, 0x337dd1af, - 0xe5e47ba5, 0x7fc7fde7, 0xa68779f1, 0x9ce9befb, 0xc3b066ee, 0x13f5be55, - 0xe56aef8e, 0x537fa6dc, 0xba7a17be, 0x3890befa, 0xf0a5a225, 0x744f0e70, - 0xd2e79e4a, 0xc388f77d, 0xd2113a79, 0xdd475048, 0xcad38f27, 0x2a4b24c3, - 0xde132828, 0x7a071dec, 0x8aa932cb, 0x4737eca8, 0x6476d3b7, 0x940c474d, - 0x2d0e242b, 0x217217bb, 0x3c91df1e, 0x15f9d768, 0xb4852db1, 0x9a8ed482, - 0x3bdd6902, 0x97b42547, 0x923f2184, 0x9e3df57a, 0x0d11f516, 0x1de8019d, - 0xce2b00a5, 0xbe9f5a77, 0x8bc20722, 0xa293d8e9, 0x313f7f2f, 0xcfccd63a, - 0x58bd1d7d, 0xc46fd33e, 0xfbe8727d, 0x66f8e55c, 0x4ba76699, 0xf36f41dd, - 0x8c15c71b, 0x291e0093, 0x3ca6de9e, 0x7bfaa463, 0xd1d1dc12, 0x618fecf1, - 0x72ef2df4, 0x141b63e2, 0xe694d01b, 0xa9563f7f, 0xec193627, 0xae0d5b24, - 0xad4fd0b5, 0x1b4ddef2, 0xa1dbcecb, 0xef13d0f1, 0x421e0453, 0x3efaabf1, - 0x1be80665, 0x667c6103, 0x74c6f8c5, 0x29631bb1, 0xf3d47a9c, 0xd5f1a495, - 0xd75b942f, 0x60fa073d, 0x2b7fd33d, 0xf57bb386, 0xda326d8a, 0x0c1ada0f, - 0xb18e892e, 0xde177eb8, 0x1b56b4c7, 0x9eb7dc09, 0xab48eba6, 0x55fe04bd, - 0x371c0df3, 0xcd67075b, 0xea86a746, 0xee5896d5, 0xb24d908f, 0x3fd31e61, - 0xcd31173c, 0x9ede7682, 0x5e76feb1, 0xab37fdef, 0xedcf9017, 0xedef54c0, - 0xcce2f20a, 0x65ef04fd, 0x6d23b689, 0x1cbf9642, 0x23a3ce50, 0xa9e3d186, - 0xb4167b68, 0xf294dcd7, 0x2857b414, 0x06e9ec37, 0xcec859f8, 0xc40c2359, - 0x64e94619, 0x56b5ef90, 0xde95c9f9, 0x9cf196bf, 0xfbc2e9fd, 0xfa6567a2, - 0x692dedda, 0x741eecec, 0xa5bf67f3, 0x988ef4ed, 0xd3daf78a, 0x93bcec0c, - 0xbbb87f7e, 0x6f5f5d07, 0xf81189e9, 0xeabdd74b, 0x4e70ade0, 0xabad928a, - 0x32b17f69, 0x217c0919, 0xce1b1bc6, 0xe7be23e6, 0x0246b0bd, 0x8fbe22f9, - 0x7fd1d258, 0xb1f54d01, 0xf8c53f8c, 0xf4741446, 0xf0f932af, 0xe7e466de, - 0xd716b319, 0xb4c3b093, 0xec0979c1, 0xeb0e7024, 0x3db7c84b, 0x5e1f786d, - 0x20ec4611, 0xdb35bef7, 0x7ce146ba, 0xb66f782c, 0xb7acacd0, 0x04fcd3f0, - 0xa0571f28, 0xe91787bc, 0xc76658ac, 0x4341fb29, 0xe2767e9c, 0x0f5bad32, - 0x1fb281f6, 0x77e9c4f4, 0x9d05fc0f, 0x5cefd3b7, 0x4f4b4f7e, 0x22cc27b4, - 0xcc27b456, 0x9c4e1e5a, 0x3aa2e77e, 0xbd350e3e, 0x56fa71cf, 0x96896944, - 0x2242abce, 0xdb954bf6, 0x9f764ffe, 0x23ff1eaf, 0x70e36eb0, 0x779fb87e, - 0xab5c1a34, 0x9dcb03d3, 0xb8f6618b, 0x3dc51bf4, 0xc5cf07bf, 0x25e5b70b, - 0x8aed2090, 0x1b07e2b4, 0xa5e1f971, 0x7983d682, 0x9230fc56, 0x6f07fab8, - 0x66f982cf, 0x81cede05, 0x5fe81a7c, 0x4df1163f, 0xb091c44f, 0x97a95e7e, - 0xf13d8347, 0xd19abd95, 0x678c83ab, 0x9f679f03, 0xf5f22d38, 0x5b626e8d, - 0xa29e8415, 0xdb347c5c, 0x459f0117, 0xa8788159, 0x074cf7cb, 0x2469b87e, - 0xefeb05b1, 0xc42f9c2f, 0x19a2ebb8, 0x18762b7e, 0xdb405ed0, 0x011455ed, - 0x71733ddf, 0x74959b3d, 0x8d863cfb, 0x4f36eea3, 0x76d3f41a, 0x083ff72b, - 0xe173df41, 0xe018f68e, 0x30b449c3, 0xda4187e5, 0xb7ecc92a, 0xbe94ae3e, - 0xd6ac3f15, 0x102bd3f9, 0xae74ebef, 0xc576befe, 0x22f3643d, 0xe6def519, - 0x95fefc83, 0x62eee3db, 0x499a4cac, 0x97b02ed5, 0x68495734, 0x41dbbbc7, - 0xdeba22c8, 0x14b87aef, 0x97d34ded, 0x8234bebe, 0xca907f7f, 0x0912bb8d, - 0x77a699b9, 0x09da56cf, 0xb70596a6, 0x3f7839a7, 0xfa0748d3, 0xa85f4cf9, - 0xfb702fb2, 0xe541e383, 0x17e02ff7, 0xc60fd72a, 0x0e43bb72, 0xbd7901c9, - 0x3d39e960, 0xf8a109a8, 0xc3ca85ba, 0x8b905a9e, 0xab5b4c46, 0x157e98cd, - 0xf604fb6b, 0x8eb1f3a5, 0xb6ee414f, 0x52e4c87f, 0x4c73cae7, 0x418f2f9e, - 0x2ef2c73b, 0xd78dff6c, 0xd3ea3b58, 0x3e3efe41, 0x8fc51c71, 0xeb5a2fe1, - 0x9b878a12, 0xc0d3353c, 0x35e84525, 0x905aac8f, 0x127e8b11, 0xefc041d6, - 0x32deafb1, 0x7133ec1a, 0x00db86af, 0x5cf22b7f, 0x62b18f78, 0xe7f41771, - 0x0fcdd232, 0x0d8f7ae4, 0x3fb81a79, 0xb16ea1bd, 0xd76d1ba6, 0x0dd3b0dc, - 0x35cb0efe, 0x6b3da0df, 0xf984cdf9, 0x287ef17f, 0x6919fb3e, 0x4c13f13b, - 0x171d2f78, 0x50d44aee, 0xbd46ee38, 0x17ea0975, 0xe0a95f4c, 0x2c976834, - 0x7e0a1c7f, 0x8264fb64, 0x16b13e7e, 0x087daf94, 0x0b92bfb3, 0x0f945f14, - 0x8fc40c60, 0x2dab5aef, 0x92fc9f68, 0xd0fb29db, 0xce8ea1f3, 0x4f8a2be7, - 0x6a1ecb80, 0xebe3051a, 0xabac48d8, 0xb7d89169, 0x912df292, 0xea337780, - 0x13aba7bb, 0x16e31531, 0x6bd947fb, 0x3f41a36b, 0x9999229e, 0x43d7095f, - 0x10121f05, 0x4c9e1456, 0x8bbf9c98, 0xa8539feb, 0xe3a30dd8, 0xd35887bd, - 0x46dddea0, 0xf8a1a912, 0x3b50529f, 0x5299f710, 0xe7ec145d, 0xe30542a0, - 0x8bfa5087, 0x72ea2758, 0x81af41a7, 0xc98db8f5, 0x11758a83, 0x6bbbb44e, - 0xecffb03a, 0x7b1ebe38, 0xd22e3f31, 0xfd60d893, 0xbde8ec54, 0xa062e80a, - 0xa5e303fc, 0x9b98ca72, 0xd19cfa83, 0x7f3fe748, 0x8a5b987b, 0xd9a7a3f4, - 0xfa034fd6, 0x1c9484fc, 0x4a3a97f4, 0xd80447e5, 0xb8693c71, 0xeb47419e, - 0x7d5cc306, 0x54ebdc1b, 0xfb30dc50, 0xee0ccbce, 0x2d6761c6, 0x7978d383, - 0x777066e2, 0xdbddff51, 0xc743fec0, 0x621fcbcb, 0x1f011f70, 0x45b3e566, - 0xce0c63f9, 0x1927f911, 0x7fb4483c, 0x1843c18a, 0xd3c9fc7c, 0x0f4139b7, - 0x8ffae289, 0xaee783d5, 0x6b7b378a, 0xde96fdfc, 0xf3726389, 0x772b1874, - 0x98cc9d3a, 0x08cbf400, 0x5e55fe5e, 0x02c5e85e, 0x493ea27f, 0x266f5e0c, - 0x80bf37af, 0x64e129eb, 0x5bf31879, 0xba524675, 0xbde86eee, 0xc617ca1a, - 0xd03a7345, 0xdaf80676, 0xed11f411, 0x244b7e89, 0xe9b497a6, 0xbbd89d98, - 0xfdb1c66f, 0x30f3f684, 0xd293d3f6, 0x909bda15, 0x81f80fd2, 0xf39681f2, - 0x80f81681, 0x7c6c5590, 0xc028ddb4, 0x3fa3b9b9, 0xbeedbff8, 0xfba7cb40, - 0xcbe6adc6, 0xcddf3807, 0x81cec25f, 0x703d511d, 0xce1118bf, 0x403244f4, - 0x380f8f39, 0x8b89de1e, 0xd2f4f362, 0x7ec24125, 0xa63c7096, 0xc84d7a78, - 0xff79faba, 0x97e78f9e, 0xbd1fb79e, 0xd7e4326c, 0xcd9ab0df, 0xd60bd187, - 0x85ea3447, 0x3bda2b8f, 0x3f5558bd, 0x98702e97, 0xac0f746f, 0x311848ff, - 0xdab277e2, 0x9b3d2f5b, 0xc7a0abe9, 0x27ca2f96, 0x74ff6127, 0x85f78cde, - 0x952a5c65, 0xe3d26f2f, 0x64ad6bfd, 0xef3cbf43, 0xe00ec73c, 0x79f334f3, - 0x5d3cd99a, 0x87257e0a, 0x88eed23a, 0x2f63e408, 0x65edbdfe, 0x14f6f0e6, - 0x7b582372, 0xd1422720, 0xd34bfdc5, 0x85538c45, 0x559e2f4f, 0x84f813e3, - 0x32f58df5, 0xc6297c95, 0xf5a87af9, 0xfb33fe9d, 0xcaf563cb, 0x08e9437f, - 0xc945a7fa, 0xe975e5d7, 0x7d327b9a, 0xae8036f5, 0xf3f3e717, 0xfdc71939, - 0x0a485286, 0x7cce0fec, 0xfec37562, 0xfb80d9b9, 0xfd92e7fe, 0x505c5c54, - 0xaefc20ff, 0x47b6173e, 0x1bec09e9, 0x7b40fb6a, 0x06c9b59c, 0x0967e5f7, - 0x550edffa, 0x6fc033d9, 0x57c9b373, 0x295fb7cf, 0x4cf111e1, 0xc3b40cbf, - 0xe68a7dd0, 0xb868300f, 0x018dd73c, 0x5c203d79, 0xf0d57705, 0xe0c8c4fd, - 0x293b0e04, 0x2034f14c, 0x3187e459, 0x3f513af8, 0x51bf958c, 0x5f70e794, - 0xa208fe55, 0xfdb28784, 0xb0a9e624, 0x20ff7031, 0x78d8a0f4, 0x2e43ce0b, - 0x4be010d0, 0x80d53803, 0xc196f5be, 0xa08d7a05, 0xce94a853, 0x3dd82ab3, - 0xf0bc6a7e, 0x977e6033, 0xbb40f2e8, 0x047615ca, 0x4761568f, 0x3a348f68, - 0xc768aee5, 0xadf605eb, 0xf747788c, 0x32bf5a78, 0x3a7a75bc, 0xff0a1f85, - 0x256cfd0c, 0x258fd31b, 0xa54c998b, 0x575a95e3, 0x23df41d8, 0x16a35625, - 0x4aedc4e9, 0xe94bf770, 0xcbc77db1, 0x6eb3240f, 0xc18e30ec, 0xee54ae5c, - 0xe3bbf1f8, 0x369fffb0, 0x7dfae159, 0xf7b3c370, 0xb838be81, 0x4c8fff61, - 0x5fa1304f, 0x60f718ac, 0xdfa29bf0, 0x380deb73, 0x370dc1fe, 0x43f281cc, - 0x01e86a3f, 0x84fc377c, 0x9988097b, 0x9237c6f6, 0xb91f281d, 0x25392c9f, - 0xd5c19c41, 0x7c5e45ea, 0x7e8f43fc, 0x231f141e, 0xcc2e3e19, 0xc5b4fc05, - 0x41e65c1d, 0x8b0a62a3, 0xe9f5e067, 0xb9fd03b9, 0x2b17493b, 0x23db5dd8, - 0x3b6a3b58, 0x3a22d1e4, 0x787dfa3f, 0x9f811d07, 0x07e23fde, 0x3e4c1523, - 0x29448f38, 0x926302e0, 0x39a17ca2, 0x4b7f915d, 0xfc8a0de2, 0x14fd2d5b, - 0xc18c98f0, 0x5bb7f28a, 0xf8f014f3, 0xe5155bdc, 0x0a456c8b, 0x56bb9fb8, - 0xdeffbe51, 0x21fe657a, 0x721d0322, 0x41775a8e, 0x1b4bf03a, 0xb507359a, - 0x7482ed54, 0x1d0cb7f0, 0x90ec3b6a, 0xc1776a1f, 0x15876177, 0xce30f0fa, - 0x3b2ec22f, 0xf4b93649, 0x89afedc1, 0x959e9a5a, 0x649f283c, 0xafed1d8d, - 0x078e61c9, 0x473d29e2, 0x2814aa91, 0xb0ec0237, 0x33850894, 0xfc01fece, - 0x32a73aad, 0x2051dc7b, 0xbbbbc80c, 0x788ed022, 0xf1b55754, 0xce43ea38, - 0xc3a39054, 0xe62b263b, 0x8707e23d, 0x6479de62, 0xf74e8abe, 0xf342e02a, - 0x6fe5146f, 0xc8ac5c49, 0xa8f2d5bf, 0x2b8f4e8a, 0xcfaddbe0, 0x4ab4e8aa, - 0x1597a745, 0x1bbf82f9, 0x076c7db8, 0x3a68b5d8, 0x0054d3cc, 0xa5b9b874, - 0xdb91e903, 0x74005354, 0x16b4721a, 0x6dc035e9, 0x3bf1002f, 0x2ed56f68, - 0x5cf4dd48, 0x4efef503, 0xee9035cf, 0xb023e7a6, 0xcea9ed8f, 0xb56f74c0, - 0x5bbfbf15, 0x7be98b9d, 0x3f4c36d5, 0x698d1ea8, 0xd31db553, 0x2c5aeada, - 0x9ebab9bf, 0xf862d7d9, 0x0bf1473e, 0x38368c76, 0x9cbca253, 0x0db2f28a, - 0x5f2850ce, 0x177066ef, 0x0c29930e, 0xebe5648e, 0xf2829a9f, 0x8cf83f74, - 0x30bf81c4, 0xd824cf4b, 0xdd3409ec, 0x8186e70b, 0x5a89b8be, 0xe4a7688d, - 0xb1eb9031, 0x525fbc31, 0x4296c632, 0x5ec5d2c8, 0xc18431f8, 0x2307eb28, - 0x1bc1f8b3, 0xe21b6b61, 0xc61edfab, 0x97c6f7f2, 0x4173818c, 0xf330fae9, - 0x29747e97, 0xc0528daf, 0xe649f595, 0x88e8fd2f, 0x7654c97e, 0xe5091492, - 0x36c3d09f, 0x20438e48, 0x1e8dca7f, 0x1aa627f4, 0x6c2bfa30, 0x8044b16c, - 0x85e0ea5d, 0xcf8011de, 0x672edc83, 0x3374fd23, 0xeda79a69, 0xff7d83a7, - 0x124f4aa8, 0xef2941e9, 0x56b76853, 0xf413bd63, 0x3a6de724, 0x413ffc02, - 0x51007662, 0xa604ddee, 0x6edfb4af, 0x21e0f3c0, 0xc60e6d8d, 0x9f024811, - 0x149f718b, 0x11c2f7f3, 0x7489df22, 0xf9128f6b, 0xe5538e1c, 0x1d60a927, - 0x5f19df2b, 0x05fe748d, 0x904ff9f1, 0xca7c6a0b, 0x97a66609, 0xa0a96db9, - 0x50f808c7, 0xe41cad91, 0xdb3ca1c7, 0x83ef30f5, 0x17930376, 0xf5d708f6, - 0x0db33768, 0xfecfd3bc, 0xc3a09d55, 0x1f00777a, 0xddc4fdc3, 0x3515ca32, - 0x604a5ffe, 0x15f22afa, 0x0aefbb9c, 0x21cd73c7, 0x1cde290d, 0x387b5e84, - 0x0974ce1d, 0x277df76e, 0xf9fbed81, 0x6e37cb13, 0x85cf7b81, 0xbb74d861, - 0x93ea37bd, 0xf31255ed, 0x3aa96903, 0x560df2cb, 0x33f4128e, 0xd1bf029f, - 0xf70d8dfc, 0xcb4c3f9d, 0xdc30b67f, 0xb9967b8a, 0x6eefe20f, 0x8c5a785e, - 0x69bff511, 0x61f35213, 0xfdc29e1f, 0x6847a79a, 0x59bdd1e3, 0xd337a51b, - 0xfa9b6676, 0x2418a32d, 0xf48b6373, 0x4e2e1451, 0xa41977b9, 0xd71f3d25, - 0x595dd5c3, 0x40cb6be6, 0x22a72f0d, 0x5bca2063, 0x74d5fbcf, 0xc916335c, - 0xe51e7616, 0xf4adb8fb, 0x045de2aa, 0xf1e21fbf, 0x78091447, 0xf1cbdede, - 0xe5edea2d, 0xe0482af8, 0x245922f7, 0xb8aca2eb, 0x0125b8f7, 0xbda63dee, - 0xbdc42bdf, 0xeb9f3288, 0x59eb1fbf, 0x75eba5bf, 0xb9104f2e, 0x9d812fbc, - 0x89e90f9b, 0x9d55ee0d, 0x277db377, 0x87b9f27b, 0x67f9d206, 0xe8359837, - 0x7ca33457, 0xb3a1d00b, 0x4751d39e, 0x4dfd61ea, 0xecfcce74, 0x96261230, - 0x5e1fc7f8, 0x36b67f6e, 0xf7fc0b99, 0x7b1e01e7, 0x9cfeff81, 0x005351db, - 0x8fd8b0fb, 0xbba83dc5, 0x03ef98ba, 0x77bf2855, 0x78422f57, 0xd313b54f, - 0xf9cbd5bd, 0xf983503e, 0xc33f55ef, 0xdf1701f7, 0xf7e3d607, 0x98c9ea86, - 0x6076a8ee, 0xbd8ba63a, 0x1df4e402, 0x47c60746, 0x81acfdbe, 0x675e7dc0, - 0x47e30183, 0xf1788ae8, 0x538858b9, 0x58579832, 0xd495e302, 0x1f978afb, - 0xb3fb7e54, 0x0b7ed8bb, 0x99e378fd, 0x2ebd3f40, 0x241d3f34, 0xdf390e5c, - 0xd0743945, 0x07d6e42c, 0x7808b60c, 0xa2ad833f, 0xf72807fc, 0xbe78da0e, - 0xed833f73, 0x601c9f3c, 0xefc043b0, 0x944ab831, 0x73dac03f, 0x063df80a, - 0x4df288d7, 0x7831760c, 0xa21fd3ed, 0xd223cc5c, 0x056f586e, 0x2091f4c6, - 0x79cd0b62, 0xdd9d61bb, 0x24733892, 0x826333ac, 0x56fcf905, 0x00dde2cb, - 0xa558c98f, 0xcdba1305, 0xa861efd4, 0xa45b1f97, 0x53237a85, 0xea187dee, - 0xb8f9ea8d, 0xe8debfd6, 0x061ed7cc, 0x9575ac78, 0x236bf416, 0xbe81c5c8, - 0xf22c0476, 0xe2213ec5, 0xd836faf0, 0xaeca3f71, 0x247ee3b7, 0x477f9cf0, - 0x9c3352d1, 0xb325ea03, 0x43b8e304, 0x404f06f2, 0x05c5630c, 0x1e291aba, - 0xe13c12ea, 0x2b3ce98b, 0xf0821e01, 0xd97f8b63, 0x109dd5fd, 0xc2383f64, - 0x2be807e5, 0x23ffb445, 0x3f835d74, 0x4bc70442, 0x88ccc365, 0x755e7899, - 0x189e8044, 0x0490f5c3, 0x2dfe6948, 0xbfcb1d3c, 0xef6c941f, 0x30f8bc82, - 0x03b79f81, 0x1861cde5, 0x73279507, 0xe40238d9, 0xcb9f328d, 0xdf62239b, - 0xb2e2c01a, 0x8b0d49cb, 0x7c4cbee7, 0xb8dc405f, 0x84a71e2a, 0xa5b1eed4, - 0x6f178b07, 0x2e2f1a0a, 0xfd031bfc, 0xb0b9f96d, 0x93cf930b, 0xc3d17641, - 0xb9686760, 0xab971dfb, 0xcca0f0a1, 0xe0e285ff, 0xf90e2389, 0xbc3c5423, - 0xf9c08be0, 0xb6f3b0d5, 0xea9fe196, 0x81c4c69f, 0x8823bf20, 0x6794ab1c, - 0xcf212f87, 0x97f1f2d4, 0x6693bb92, 0xfdc1a794, 0x98b91043, 0xcb54e30a, - 0xc93e6745, 0x7505fb80, 0x0a68f42a, 0xd3de213b, 0xed0c23b9, 0x8e31f514, - 0x0fd0448c, 0x83be3bf3, 0xeb122d78, 0x371c3c41, 0xf6846e39, 0xbff33d25, - 0x2dcdf110, 0x753f7d5e, 0x7923c62c, 0xfb0a7bf5, 0x9efdf7e9, 0xf20b1d49, - 0xdec9bbad, 0x1921da1f, 0xc85d1fcc, 0xbef1508f, 0x3ed91343, 0xff92981f, - 0x8e5838b7, 0xae7a369f, 0xf4e74dda, 0x62bf86ce, 0x57d9ccdc, 0x56c1c79a, - 0x265dba5c, 0xb68f8a46, 0x0dc4110d, 0xe52d1be7, 0xd4969a3f, 0x2b8c36c9, - 0x4d07bad2, 0x5bd7f08c, 0xe974ff98, 0xcadc08a6, 0x5c1b364b, 0x92fd6963, - 0xd1b327ad, 0x0ea1f5af, 0xbe730fbc, 0x22d75922, 0x13d93cfa, 0x1b594fc1, - 0x353e4edc, 0xad87e991, 0x8327c2db, 0xbf5a56bd, 0x25deed13, 0x707493b5, - 0x4dca2a0f, 0x3e21d44c, 0xa7b43968, 0xb8965f3b, 0xe41eeb1e, 0xfc2caf7f, - 0x665f5bb7, 0x7a92a976, 0xc60c2b9d, 0x36b5feb7, 0x3929c788, 0x4dfb406a, - 0xf46ffae5, 0x4d82c740, 0x1f01231b, 0xd932f595, 0x550fbcad, 0x97ac41c6, - 0xe3f006dd, 0x7f472baf, 0x23370a6e, 0x1e3c1b5c, 0xfafe72e8, 0xb71a9ba5, - 0x4b0a293a, 0x12297f5f, 0x374e29e2, 0xbc048dad, 0x192f76d3, 0xf7101487, - 0x25e8fb50, 0x134e1ee3, 0x134b03c6, 0xeb237155, 0xcb71b863, 0x3fdfc83d, - 0x274787c9, 0xf3c6f3a3, 0x5e5c422f, 0x2f33e6eb, 0xfecb78c2, 0xf045ee79, - 0xc23b26cf, 0xad0f60cc, 0xc630e57c, 0x7f7a8935, 0x627a6449, 0xe12fcbdb, - 0x31db6a3d, 0x35b7afa6, 0x6dbe429e, 0x78c7ed7b, 0xd85af388, 0x0efe8858, - 0x2414b70b, 0x02e72090, 0xbadf0291, 0x4d1e20ae, 0x755daf4d, 0xfc8fd0bb, - 0xe837a52c, 0x9638dea1, 0x171672da, 0x2bf1e164, 0xfdc7821b, 0xd4abc405, - 0x1c3f1c4d, 0x3a75e2ec, 0x415c85ab, 0x4a21cadc, 0x4057bec7, 0x728f0dbf, - 0xf4e0fe7f, 0x50bf0b3b, 0x2a26353a, 0xd7ce56e3, 0x9fcbf9cd, 0x262eaf21, - 0xfb8adc64, 0xe226f00a, 0xda24570a, 0x6c3c82f6, 0xc62afcdd, 0xc6dd0109, - 0x6db689d2, 0xf1069f3c, 0x8eba2d98, 0xc1efdce9, 0x25acf70c, 0xfd70478d, - 0x10f96db4, 0x8f08f6e3, 0xde236bef, 0x258f161f, 0x89ae79f1, 0x1c2ef160, - 0x030f10ff, 0x3bf4d0f7, 0x7c617b8f, 0x4261e22c, 0x4c5cc1c5, 0x2df6ceec, - 0xbe58ef1e, 0x2b8f38e6, 0xca4bd1f1, 0x5f353a05, 0xe048be32, 0xb8780cc1, - 0x2bae3fc9, 0x3791bc78, 0x0bd38ffe, 0x5cf107e8, 0x0a2db8de, 0x3a58430f, - 0x83c88242, 0x1e2c55b6, 0xe3ff7d4c, 0x3843cfa3, 0xd152ffaf, 0xf433cc59, - 0xd3ad9239, 0x6aff8dcb, 0xd12673f1, 0x127388a2, 0x10bd6a78, 0x26a78e5c, - 0x67eafdb1, 0x00b6b7eb, 0x092536fd, 0x66badbf4, 0xe62b7e85, 0x05754adb, - 0xafadef90, 0x960c77b0, 0x3942eed5, 0x141796ae, 0xf760b62f, 0x98937d0d, - 0x67a8aa9c, 0xe6eb44fb, 0xb6899708, 0x6df7fad3, 0x1b15cfc8, 0x8fb0f59a, - 0xbaff59ef, 0xb317f99e, 0x84fb03f5, 0xadfc6fcb, 0x8d99db7f, 0x09fa1b72, - 0xbce1d742, 0xe086ca9f, 0xf86e54fd, 0xa94fd146, 0xfccf56b3, 0xdfdd2e8d, - 0x126dad69, 0x49ba77b4, 0x7269a607, 0x6df996ba, 0x24b7fba9, 0x4abdf8e9, - 0xa8f7d70d, 0xc83f47bc, 0x9c271e61, 0x51c3735b, 0xc5e6b63e, 0x35a45da3, - 0x6965af55, 0x7fff842f, 0x935bfbdb, 0xbfac8d72, 0x371f1851, 0xd6e8c62e, - 0x8073f5d0, 0xaf513fbf, 0x00fff677, 0x8707cfee, 0x78e3dfa1, 0x4dbefcc9, - 0x6827bc0a, 0xdf3537dd, 0x5f781d92, 0x91912ad0, 0x65279512, 0xf0a59acd, - 0x0fef6aed, 0x477d16ca, 0xa19d1de0, 0x78102e8b, 0xefeae7df, 0xb3a29a13, - 0x70b7602d, 0xfa6d812c, 0x829ad6a6, 0x597216ae, 0x0edcef3f, 0x67b012d7, - 0xdec0b88c, 0xba4a18b7, 0x4daae158, 0xfccfddca, 0xbeaa79be, 0x31ae9877, - 0x83ddf4b9, 0xe7909fbc, 0xdc82481e, 0x867b8837, 0x8ac730e4, 0xf71081a4, - 0xc01beecf, 0xe4f915f3, 0x3fa6c7b7, 0x3081e780, 0xe71573f4, 0x27f58d99, - 0x9fac60e3, 0xb93dc537, 0x34af7e9d, 0x79f8877f, 0x8f9f8932, 0xf28ac4ac, - 0xf50f7e4b, 0xfb25cff8, 0xfb8a49b3, 0x08b9ef58, 0x63efabbf, 0x8cee7f85, - 0xec276597, 0x0dbf85a3, 0xc608781b, 0x03961751, 0xc31fd8e3, 0x980641fd, - 0xf1401f6f, 0xf5cb7673, 0x5b3fe039, 0x9eefb5e4, 0x88bcbd47, 0x338963db, - 0xafd876f3, 0xd7bd848a, 0xdcf961e9, 0xd9febbde, 0x3ac3b7de, 0xa1c1fe14, - 0xa2c56de4, 0x421f9137, 0xda12cbe6, 0xa6e4c939, 0xbd3f22b4, 0x072e4df9, - 0x397efdc4, 0xa78b0bf7, 0xf68dc8d3, 0xbc5791f9, 0xba46e611, 0xcec4d97e, - 0xe976dbc5, 0x09af1d99, 0xa78f21cf, 0x7c02de3a, 0x81da2c55, 0x762626f8, - 0x6c96396e, 0x1d31fee6, 0x0eae5099, 0x6eb027ce, 0x7da184b6, 0xd1eb4136, - 0x2ab8e95b, 0x8bf4128e, 0x33c7c638, 0xd40be9a8, 0x70e6bff7, 0x37e67ad7, - 0xd7c3c6a1, 0xf1aa1149, 0xc60c37bf, 0x2231f02f, 0xfdc2d49c, 0x958f9d30, - 0x98aac7cf, 0x814fd78f, 0x6ff74bd6, 0xebf0a2d7, 0x5b2af312, 0xdffc49d4, - 0x1c5d6ad3, 0xe311df7c, 0x97dbdf56, 0x840f7698, 0x2ae4a37d, 0x02a7fafd, - 0x3e01c46f, 0x871eaa59, 0x7ee32d3a, 0x17efea1d, 0xf67dc492, 0x7fae3b2f, - 0x69bd7bb7, 0xf9153b55, 0xbbed1633, 0x713f7ba2, 0x75bff71f, 0xdeea17ff, - 0xf66ec1ef, 0x8e946ecc, 0x29fcdfe3, 0x9df108f3, 0x1105eddb, 0xbe51c718, - 0xc8156135, 0x7e470fe5, 0xc2f60f14, 0xf71231fd, 0x1cb4bde7, 0xf7bb52b9, - 0x717bd567, 0x393f625c, 0x5846ed51, 0x3a9f076d, 0xa7bc31e2, 0xdb2dfc1e, - 0xb05e8637, 0xf2c9b91d, 0xc231edf3, 0x32ec230e, 0xd4cf3b6a, 0xefe4666e, - 0xec29bfe9, 0x9417fcca, 0xac472e7c, 0xffdc83d1, 0x17ee7cb9, 0xd65d3347, - 0xe2877b40, 0xce89bda1, 0xb0475ee6, 0xc23de51d, 0x7b8e2e98, 0x73134e80, - 0x88863f99, 0x5b942a5b, 0x7a049c9f, 0xfb8c934e, 0x7ddfc2d7, 0x2ce7b7f4, - 0x34a8f481, 0x131ca277, 0x5eeb1774, 0x86a543f0, 0x14e7b1f9, 0x097fd058, - 0x57d811e4, 0x0d34746b, 0x299ee742, 0x3c600bf9, 0x0e3afded, 0x8abf024f, - 0x669dff2d, 0x09aebd41, 0xb39779cf, 0xbffd80df, 0xd73b105b, 0xe8393cb2, - 0x298977fb, 0x6aceff4c, 0xbbfbb0d6, 0x7aeb92f9, 0x347973b0, 0x39acaa88, - 0xe0192ee9, 0x559f963a, 0x2892e51e, 0x8c38359c, 0x851bdfe5, 0x88d3df71, - 0xf3fb0747, 0xa60af00c, 0xc1624ce9, 0xf1b11674, 0xba3ae5f7, 0x9cfeb44b, - 0x83f32306, 0x309e9e25, 0xfa10ec9f, 0xcc6eceef, 0x3bb7d3be, 0xf37ddf93, - 0x19fc7295, 0x726eff9e, 0xef9849fe, 0x67b66ee9, 0xdd1bed21, 0x704fe2b4, - 0x21a2dcde, 0x1a9df7a0, 0x9bb41bfc, 0x24df7a8a, 0x8dd8bfe7, 0x3124dbd6, - 0x23674aff, 0x1d22a78f, 0xb6f6fef1, 0xd60b93d7, 0x02af7b40, 0xae3c815f, - 0x29be462d, 0x935c3332, 0x457cec91, 0xca5da5eb, 0xf857d20e, 0x5c87c2f7, - 0x86e117ec, 0xfdba4f3f, 0xbeef3a61, 0x073dfa1a, 0x02d8e5c6, 0xf74beae3, - 0xff8c1373, 0x40a71e05, 0xdee0d2aa, 0x068bde6c, 0xc79bec0d, 0xbf03bca8, - 0xa7e0e3eb, 0xb94fd34d, 0xdce7f63f, 0xfc19bb1f, 0x927a69ba, 0xe7482dca, - 0x842560fc, 0x64c8e7f2, 0x95f2235b, 0x883bf82e, 0x21e726ef, 0xb4ebb31e, - 0xd7678fb8, 0xfae7227b, 0x377f65d1, 0xb59a1f16, 0x5848cbe5, 0xef666d4f, - 0xed126cbc, 0x73b71c6a, 0x0736efee, 0xb26ef5e7, 0xe7cc24ed, 0x01c764f5, - 0xa3feb76c, 0x753f04ff, 0x7fde3eda, 0x4f1d4bb4, 0xf102950d, 0xa37f9dea, - 0xe39fcd9e, 0xd3545379, 0x69bfa80a, 0x2cc0774b, 0x2c7ee2c9, 0x0527e804, - 0xe7b33fc3, 0x0c74378d, 0xf8d17380, 0xff50728b, 0x3fef3131, 0xf38b3a0a, - 0x286ba70e, 0xcf9287ba, 0x80cc78de, 0x442e1377, 0xe22f5c82, 0xbafa9376, - 0x6fd0079e, 0xe04caf7f, 0x27ca23dd, 0x498efe0a, 0x48807a66, 0xf8f51ab3, - 0xc6a6cf5e, 0x36ce7aaf, 0xce7a1d21, 0xe4e5e5a1, 0x507a15eb, 0xff1fe0d6, - 0x2c58a7fc, 0x92412f0f, 0x42aac8bb, 0x629af7b8, 0x4c36f9dc, 0xb9b99a61, - 0x66bdee10, 0x207b4a24, 0x1f49699d, 0xe25df705, 0x232b38dc, 0xecb00f6f, - 0xca116b58, 0xc4583ce1, 0x814bfb7e, 0x1eee1c31, 0x39a170bc, 0x92df0146, - 0x7f28ac98, 0x2287a5ab, 0x8dc64c7f, 0x9faf7c8a, 0xefbfb5bc, 0x47c0777b, - 0xc3b07747, 0x9ca079d3, 0xb4656b21, 0x396d66db, 0x148ddb74, 0x4eeeb71e, - 0x9b036c2b, 0xcdb8fe78, 0x4fd82e05, 0xb00a5de1, 0x3ee4b463, 0xa09fd4fa, - 0x5f7b2d31, 0x74611e63, 0xebfc6b28, 0x799b6028, 0x3da1e6c3, 0x8c9de036, - 0xd5dfc135, 0x52c1f610, 0x65e9ecc2, 0xbbf6d41b, 0x550ecc95, 0xe54faca7, - 0x3c827fd1, 0x0ef5bbea, 0x6e97f833, 0x3763fc1a, 0x64d6e790, 0x284bbc65, - 0xbff2f17e, 0x1fe03964, 0x17e6a1e7, 0xe9120761, 0x6e2c83b8, 0xc5e56ae1, - 0xf85e403f, 0xe57917c5, 0x31fb9e98, 0xc41278f1, 0x3f1f0f47, 0x628e4b4f, - 0x5aaf67e5, 0xd0b8ef0a, 0x13c4277c, 0x4b9db291, 0x85efaec1, 0xf32b3617, - 0x2996941f, 0x95d387e0, 0x65bccaf0, 0xad43f5fe, 0x66fa8abb, 0xefca83bd, - 0x39d8278a, 0x639f7024, 0x992ee8eb, 0x6fdb0554, 0x4a31fe44, 0x7853f40b, - 0xc70bed83, 0xfef47aba, 0xc96527fe, 0xbb3b4f4c, 0x7ddff1ed, 0x6de27607, - 0xce46fd04, 0x5cfb3146, 0x8d29dd76, 0x177ae406, 0xb36caf86, 0xec7e0347, - 0x4ee1c5ed, 0x9cac83f0, 0x24fe811f, 0x866ce17d, 0xbfedc9e7, 0x7843d1b7, - 0xbf09efe5, 0x03ff0f57, 0xd13f379c, 0x46fb1468, 0xff9589bb, 0x6cede48f, - 0xeb67c8df, 0x83d03a63, 0x974261cb, 0xe252e566, 0xeeb0cb95, 0xbf003e60, - 0xf78edcf6, 0xd37b009f, 0x5a3eb63e, 0x29e3fb89, 0x4cd8bfb8, 0x95a3ebfe, - 0x7e77b2d4, 0x427dec2d, 0x7218bf71, 0xd1aeecbd, 0xbf8dfbc3, 0x2279baf4, - 0x843bdf99, 0xc7071f5e, 0xdca93e50, 0x3b1afcc6, 0x4aefae1b, 0x804bd6fc, - 0x068cf69e, 0x6dc05af9, 0x3bfdfc0d, 0xd8a17c55, 0x17b58837, 0xf78b13fa, - 0x3ae80f3e, 0x541fa026, 0xc6fd16a3, 0x092ce816, 0x6fea9751, 0xfc5886b9, - 0x68dbebfa, 0xe62df940, 0x73666ed1, 0x3e78dbed, 0x8171de1a, 0xc3ea3174, - 0x87fd8a35, 0x58ba73ee, 0xec455810, 0x6370ec5e, 0xe1d03e42, 0x199c44b0, - 0x309a9839, 0x35fb9bce, 0x27fc244d, 0xffeb4331, 0x6fd0b6ae, 0xf3bc6cef, - 0x3e87d07a, 0xcee7bbae, 0x24fbf401, 0xe29b9778, 0xfb7740f7, 0x81df9834, - 0x73f4255f, 0xfa91fc2a, 0x77f7acfc, 0xf307e50b, 0x65dd80c6, 0xfe83312a, - 0xfa665e3c, 0xad8b7916, 0x2a37212b, 0xe868a6a5, 0x09e4f5ff, 0xbce99287, - 0x01fd1613, 0x3df569f5, 0x5bea95f3, 0x26b0f285, 0xebede81b, 0x6e7f1625, - 0x31577c65, 0x9393ccec, 0x7d508e40, 0xf28ff41e, 0x1ef89dfa, 0xe6dcfa81, - 0xe7d5abd5, 0xf38dabef, 0xedcbd00f, 0x7071c96d, 0x7877388e, 0xcfd40912, - 0xcd56f27d, 0x021f5477, 0xdc36b479, 0xa6aef8c5, 0x6fce94ad, 0xb364dac1, - 0xf6e78a13, 0xa2d6f162, 0xdba7f0fc, 0xcbf3437e, 0x83370a5e, 0x9d30bdda, - 0x818de138, 0xa37aab85, 0xdeafbbbd, 0xd006eaf2, 0xa1d65eaf, 0xe06bf45d, - 0xbd7f0a1d, 0xd81706f9, 0x2c69e783, 0x8cf7847f, 0xf9193ac9, 0x060bd4ed, - 0x1fe75fdc, 0x2bfb81e9, 0xa50b23ac, 0x4254a9cf, 0xfcdeb4cc, 0x5db193d7, - 0xaf7625f9, 0x02537f3b, 0xfa0aa1c6, 0x8610bcb6, 0xd9c591f1, 0xf4dcbdb5, - 0x47449edb, 0xbc1c4a54, 0x975ae7ff, 0xf054f144, 0xc01f4fd2, 0x537f36be, - 0x47cbd21c, 0x61fbe0e7, 0xb60f4367, 0x84be39ce, 0xef05fedc, 0x0653120f, - 0x87895f82, 0xeece77bf, 0x7db8720f, 0xd977cd4e, 0x7e32ffbc, 0xd840c3ce, - 0x67cff058, 0xdca24cf1, 0x628d14a8, 0x4f942d3f, 0x3e076c54, 0xf9e037ad, - 0xb82c35b2, 0x0a486a9d, 0x8c2b57db, 0x49ec2adf, 0x507e8b15, 0x322b13d8, - 0xe7bbde09, 0xbff4b12c, 0x71f7a697, 0xd9c4a7fc, 0x4a7cc387, 0xfadf1f6a, - 0xf9f1e21e, 0x7e813ffb, 0x3bd89af7, 0x7c31ef6f, 0x6f02ff0b, 0xbe0ec67b, - 0xf429570e, 0x476db6cb, 0x7f781db2, 0x382bfc77, 0x3c6d9f0f, 0x25a654f2, - 0xc7cc7ec8, 0x658cec2b, 0x60fede30, 0x4b8db487, 0xb473b3f1, 0x5efc1d7f, - 0xeeaff44b, 0x53646cf7, 0xb6dbbc36, 0x07698200, 0x46cff2fa, 0x3ec36537, - 0x4437fc2b, 0x14cccedc, 0x4a947fee, 0xfbc44352, 0x0b8949cc, 0xdf83ef1a, - 0xe7de3aaf, 0x19f78b3c, 0x7de333fe, 0x0c9f393a, 0xef1e0988, 0x5fcf04f2, - 0x43d96a42, 0x43ee5c72, 0x077f0dd8, 0x67bc5658, 0x8899e5c9, 0xc0da18f3, - 0xb943ffec, 0x6364ab1f, 0x88432e71, 0x7aa7b59b, 0xe5640597, 0x89119054, - 0x113ae237, 0xc606fdef, 0x7be13425, 0x0e9337cd, 0xacc46d4c, 0x1ba29485, - 0x8ec491d3, 0x855228e9, 0x835268e9, 0x16a46de9, 0x09a4b1d3, 0x8dc7d253, - 0xff78c7ef, 0xf3adc67e, 0x0cffb034, 0x6f5c1498, 0xbfaf837b, 0x5243e04b, - 0x9578afbc, 0xd84518f8, 0xf121c5fb, 0x7e819292, 0xea2f0258, 0x9c31bfbf, - 0x119db078, 0x80f651b0, 0xef0594f3, 0x0d880a4f, 0xc42bc2e1, 0xa1c7ae47, - 0x2532f665, 0xe0e9025e, 0x1bd4854c, 0x19ee4607, 0x2b038ca7, 0x5e718719, - 0x5cec39fd, 0xe26ff2c0, 0xb1f79de5, 0x2824507c, 0x82ca45fc, 0x5c71fe71, - 0xef190f72, 0xb187261d, 0x6ef17ab8, 0x4230e4c9, 0xb5bf809a, 0xcf9438ce, - 0xde297a8b, 0x392530f3, 0x355ca00e, 0x142d23ba, 0x16670b7f, 0xb1c6ffa2, - 0xdb8dcb38, 0x7e3c5f25, 0xd75b0a4b, 0xc4aaa547, 0x8f1e743e, 0x77dfa7e4, - 0xbfafba7f, 0x04e7e82b, 0x3f755bac, 0x3c3ac46f, 0xf6313fd0, 0x2cfcf3c2, - 0xde6cafbe, 0xaadb343c, 0xaccd7e81, 0xdd67dfdf, 0x32cd3f77, 0x424edaa7, - 0x821496f9, 0x5da44deb, 0xf02dece2, 0x893bc45d, 0xbf33edef, 0xbe26eadf, - 0x531faa38, 0x5ca1671c, 0xd693c6a5, 0x571d0e5f, 0x5c46c4b6, 0x655be47a, - 0x2e3a993c, 0x3df7b68b, 0xee52abcc, 0xd3fc0b98, 0xfe91f516, 0xcaefea2c, - 0x1dc6acb8, 0x687114fb, 0xe3781d62, 0x1c593ad0, 0x438850da, 0xbff1f48b, - 0x7c134388, 0x10c3d62c, 0x72c34388, 0xf281cc37, 0x813a3fc3, 0x4e236871, - 0xda1c7878, 0x9a1c6511, 0x159ffbed, 0xb1de2687, 0xbd85b058, 0xdb80bfa7, - 0xfd060077, 0x5f7894e2, 0xc4579f86, 0xdf7ca4b9, 0xdf9eecdb, 0x041bff49, - 0xa7ec907e, 0xe859f9f8, 0x0fe0122f, 0x0cb5c279, 0x0fe01dc6, 0x09aff2a9, - 0x568277fd, 0xe9fbf506, 0x2bcfca93, 0x5c219f7c, 0xcbc7997f, 0xaec0fcc0, - 0x8f51a0b5, 0x1782d1fa, 0xfe82b3ee, 0x64d520b4, 0xf2b77945, 0x514be43e, - 0xfccf3c9e, 0x9b7ac473, 0xdea09cbf, 0xac4f3de5, 0xeff0d833, 0x404bac23, - 0x3e7bcafd, 0x0814f6e7, 0xebfb84d3, 0xdd1d514d, 0x536ddee1, 0xf4158663, - 0x5b220fbb, 0x71b14256, 0x5e9f0ce1, 0x0e98797d, 0x9603aff5, 0x74888298, - 0xf3b13adf, 0xf99e4275, 0x3af98335, 0x7bb136b3, 0xf6a39c85, 0xdc0b4882, - 0x84fbb02b, 0xefc12d41, 0x4ae7c7a9, 0xc08a7b8a, 0xcb16c9f7, 0x7fb8255d, - 0x6a10f760, 0xbfb8bd3b, 0x2985b22e, 0xdd423fee, 0x0ef38b67, 0x1e89efdd, - 0x118d7bf6, 0xc48337fd, 0xf7233dd3, 0xf663bdf0, 0xf3c0e48e, 0xa6c61dd0, - 0x4fabe034, 0x53731c63, 0xcb6e20e3, 0xce39416a, 0xf17ceae3, 0xbca06f40, - 0x073ef114, 0x20e32da5, 0x54deea1e, 0xa3d40547, 0x067b30d3, 0x9947def9, - 0xc5f27b99, 0xa7682dd7, 0xb7f54caf, 0x3bbff3d3, 0x1e2f5ea2, 0x59e3058d, - 0x5095bf9c, 0x8d0338af, 0x15f3c60c, 0x8a674ff2, 0xdbf98729, 0x4adefeaa, - 0xdfe5576c, 0xf167a95b, 0xad89a50d, 0x59b3af4c, 0xfa6e2cad, 0x959dfde7, - 0x9553ddcb, 0xf428b626, 0xe621b255, 0xbea6ec8a, 0xfdae5df9, 0x5a7f6c36, - 0x7e0a87d5, 0x98e8b198, 0x3a66cf82, 0xb5f9959b, 0xaf7838d2, 0x1567d28c, - 0x35b3c7d0, 0x0b14d469, 0xf01801f8, 0xf7cbbf5d, 0x77f11a7b, 0xcf09baa2, - 0x9f5e628b, 0xd8451f55, 0xc651ed53, 0xa979f067, 0x704f8bfd, 0xdc1399bf, - 0xf704e66f, 0xfdc1399b, 0xbf704e5a, 0x7c87e116, 0x4c8aa242, 0xe47f5074, - 0x828f8137, 0xc23723f8, 0xc8fe90f7, 0x0a71c7e4, 0xb7e7647f, 0xe47f0b08, - 0x91e7a95d, 0xec9bbb8f, 0xc43b436f, 0x9ffbd1e6, 0x23f943bb, 0xeeca9fbf, - 0xa5503e93, 0x22f3d29f, 0xb4f1a9fa, 0x0bd95e50, 0x37ac59df, 0xcb879010, - 0xf1a6d924, 0xb0f18fbf, 0x16ce5377, 0x1dfc28a5, 0x8b7f962a, 0x0f7e17f8, - 0xd0196f39, 0xdf7ca04f, 0xd7405ec1, 0xe71d53c7, 0x1dfd9952, 0xab2e87df, - 0x5fbfb033, 0xbf21cfc7, 0xebf139e0, 0x718181d4, 0x77e6a114, 0x53d34e76, - 0xe55e7499, 0xef153b91, 0x8af18b22, 0xfa718979, 0x5f8cb9da, 0xc50ef2c9, - 0xf6db6b3a, 0x63e02f48, 0x9c167ef1, 0xa904275b, 0xe8c69f1f, 0x5287cf42, - 0xa4bfed1a, 0x7d0f9d8a, 0xffb9adf4, 0x3ec7a013, 0x509dca13, 0x2cf3d5f5, - 0xf10fb1df, 0xd2173ea1, 0x0b4d7679, 0x3b9fcf32, 0x6bf5abbf, 0x4e217437, - 0x715097e0, 0x9b250751, 0x2d77c605, 0x4b5e96bd, 0xd2d7a5af, 0xf4b5e96b, - 0xbd2d7a5a, 0xaf4b5e96, 0x6bd2d7a5, 0xf4e5ffe9, 0xfffd007f, 0x8000c102, - 0x00008000, 0x00088b1f, 0x00000000, 0xc5edff00, 0x30001131, 0xafb00408, - 0x521cae88, 0x11447fea, 0x992c9a42, 0x326ebaf3, 0xb6db6db6, 0x6db6db6d, - 0xdb6db6db, 0xb6db6db6, 0x6db6db6d, 0xdb6db6db, 0xb6db6db6, 0x6db6db6d, - 0xdb6db6db, 0xb6db6db6, 0x6db6db6d, 0x7f6db6db, 0x98a102fc, 0x80005382, - 0x00008000, 0x00088b1f, 0x00000000, 0xc5edff00, 0x30001131, 0xafb00408, - 0x521cae88, 0x11447fea, 0x992c9a42, 0x326ebaf3, 0xb6db6db6, 0x6db6db6d, - 0xdb6db6db, 0xb6db6db6, 0x6db6db6d, 0xdb6db6db, 0xb6db6db6, 0x6db6db6d, - 0xdb6db6db, 0xb6db6db6, 0x6db6db6d, 0x7f6db6db, 0x98a102fc, 0x80005382, - 0x00008000, 0x00088b1f, 0x00000000, 0xc5edff00, 0x30001131, 0xafb00408, - 0x521cae88, 0x11447fea, 0x992c9a42, 0x326ebaf3, 0xb6db6db6, 0x6db6db6d, - 0xdb6db6db, 0xb6db6db6, 0x6db6db6d, 0xdb6db6db, 0xb6db6db6, 0x6db6db6d, - 0xdb6db6db, 0xb6db6db6, 0x6db6db6d, 0x7f6db6db, 0x98a102fc, 0x80005382, - 0x00008000, 0x00088b1f, 0x00000000, 0xc5edff00, 0x30001131, 0xafb00408, - 0x521cae88, 0x11447fea, 0x992c9a42, 0x326ebaf3, 0xb6db6db6, 0x6db6db6d, - 0xdb6db6db, 0xb6db6db6, 0x6db6db6d, 0xdb6db6db, 0xb6db6db6, 0x6db6db6d, - 0xdb6db6db, 0xb6db6db6, 0x6db6db6d, 0x7f6db6db, 0x98a102fc, 0x80005382, - 0x00008000, 0x00088b1f, 0x00000000, 0xc5edff00, 0x30001131, 0xafb00408, - 0x521cae88, 0x11447fea, 0x992c9a42, 0x326ebaf3, 0xb6db6db6, 0x6db6db6d, - 0xdb6db6db, 0xb6db6db6, 0x6db6db6d, 0xdb6db6db, 0xb6db6db6, 0x6db6db6d, - 0xdb6db6db, 0xb6db6db6, 0x6db6db6d, 0x7f6db6db, 0x98a102fc, 0x80005382, - 0x00008000, 0x00088b1f, 0x00000000, 0xc5edff00, 0x30001131, 0xafb00408, - 0x521cae88, 0x11447fea, 0x992c9a42, 0x326ebaf3, 0xb6db6db6, 0x6db6db6d, - 0xdb6db6db, 0xb6db6db6, 0x6db6db6d, 0xdb6db6db, 0xb6db6db6, 0x6db6db6d, - 0xdb6db6db, 0xb6db6db6, 0x6db6db6d, 0x7f6db6db, 0x98a102fc, 0x80005382, - 0x00008000, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, 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, 0x00010300, 0x00018600, - 0x00020900, 0x00028c00, 0x00030f00, 0x00039200, 0x00041500, 0x00049800, - 0x00051b00, 0x00059e00, 0x00062100, 0x0006a400, 0x00072700, 0x0007aa00, - 0x00082d00, 0x0008b000, 0x00093300, 0x0009b600, 0x000a3900, 0x000abc00, - 0x000b3f00, 0x000bc200, 0x000c4500, 0x000cc800, 0x000d4b00, 0x000dce00, - 0x000e5100, 0x000ed400, 0x000f5700, 0x000fda00, 0x00105d00, 0x00000028, - 0x00000000, 0x00100000, 0x00000000, 0x00000000, 0xffffffff, 0x40000000, + 0x00000200, 0x00000001, 0x00000003, 0x00bebc20, 0x00000003, 0x00bebc20, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0x00000000, 0x00007ff8, 0x00000000, 0x00003500, + 0x00000003, 0x00bebc20, 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, 0x00000000, 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, 0x40000000, 0x40000000, 0x40000000, 0x40000000, 0x40000000, 0x40000000, 0x40000000, 0x40000000, 0x40000000, 0x40000000, 0x40000000, 0x40000000, 0x40000000, 0x40000000, 0x40000000, 0x40000000, 0x40000000, 0x40000000, 0x40000000, 0x40000000, - 0x40000000, 0x00088b1f, 0x00000000, 0x51fbff00, 0x03f0c0cf, 0x65e21f09, - 0x63e62860, 0x88237860, 0xcc2b4e2a, 0xfe9942ce, 0x0c0cccf3, 0x32f88117, - 0xe2055f10, 0xe9a48cd3, 0xb045e2b7, 0x30327377, 0x7df90358, 0x9b8b5a40, - 0xc8014181, 0xb3e201b6, 0x204bfe40, 0xadc40afe, 0xdc0c0c3c, 0x6a0c0c5c, - 0xc4042c40, 0xcdf8bcb6, 0xff2023b7, 0xaf951b9f, 0x17ca83cd, 0x3fafc6e6, - 0x7cbf0789, 0x6c790106, 0xf928b3f8, 0x4620e1f1, 0x2d43749f, 0xca86aeac, - 0x6065522f, 0xe7c40df8, 0x681ae2a1, 0x10aac5f2, 0x03329cfa, 0x7e1ab243, - 0xc80853b3, 0x000c060f, 0x4022bae9, 0x00000400, 0x00088b1f, 0x00000000, - 0x7dedff00, 0xd554780b, 0x733ef0b5, 0x27bcce66, 0x20212793, 0xf0841e4c, - 0x04242074, 0x11093a8c, 0x5076c403, 0xc2ab16fe, 0x25786784, 0x5ae5a911, - 0xc0133bff, 0x51b91688, 0x7e2da5a8, 0x68bc104e, 0x01226f69, 0x903a4483, - 0xbd08a5c0, 0x168b6ad1, 0xe088786d, 0x7e929205, 0xcfe956de, 0xe7dad6bf, - 0x9939cccc, 0x77e8f881, 0xbf41ffbf, 0xdecfb3ba, 0xd7b5ef67, 0xcfb5ef5e, - 0x30733d1e, 0xd7632776, 0x73941ff1, 0x4158c645, 0xf81d0ca4, 0x614b3ce2, - 0xc18b72ec, 0x6c64cc65, 0xe8431eca, 0x68afa84e, 0xd7588214, 0x3633301d, - 0x5b2bb181, 0xec46bd79, 0xb41b78dc, 0xb645d7b3, 0xd3b60a03, 0x8c8563a6, - 0xfe31379d, 0xb1d76f4f, 0x9916c634, 0xe3457579, 0x7e3839c1, 0x9991ab55, - 0x2df3fde1, 0x2beb07a2, 0x26410877, 0x27befb40, 0x7f180ca5, 0x32685071, - 0xe3bea0bb, 0x6765c959, 0x2f81cd6c, 0x0abce0ae, 0x4dfa9f5c, 0x7c2125cc, - 0x8d75a5ef, 0xb0696c66, 0x8c066a79, 0xe09774b3, 0x4b3cc1d6, 0x3ba10ab7, - 0x2173e027, 0xcbb8c228, 0x2b995a76, 0x9d70c38f, 0x8eb4bcd1, 0xbcc02f95, - 0x83670899, 0xe647b5e4, 0xa9f3f053, 0x72b981bf, 0xaf15f523, 0x5ef03cc0, - 0x3704aff5, 0xc75ab12e, 0xff304d7c, 0xd9e67d95, 0x7d70d92f, 0x3dae5275, - 0x7b951d7a, 0x834b1d71, 0x1b54d28d, 0x2d28d5c2, 0x6f191d1a, 0xcc4dced9, - 0x6b828a65, 0x5f00f64b, 0xfcb6bb54, 0xf054cfd4, 0xd3cc652c, 0x83f84364, - 0x9131ccd2, 0x22422de7, 0xbe38a963, 0xb19f1aa8, 0x99173d00, 0x6778843b, - 0xf477766d, 0xaa755dbe, 0xa2656df7, 0x781c6efc, 0x87de45fe, 0x2a4efd67, - 0xa9d3f937, 0x45dfb1fc, 0x9fc4fe70, 0xfd4fe547, 0x73fe7a6e, 0x2f95117f, - 0xbe543df8, 0xb2a72fe8, 0x7ea5efd1, 0x5367f92f, 0xa3efc3b9, 0xafeaffe7, - 0x7f15f2a2, 0x85ff3d2d, 0xbf95357f, 0xf9e807f4, 0x53d7f9bf, 0x04fb8cd9, - 0x16ff6ee5, 0x83f8f72a, 0xff75efd4, 0xf9f72a4e, 0x33f9e89b, 0x13283f88, - 0x3d3ace3c, 0x19424fec, 0xb0790273, 0xceb7af64, 0x59e4f500, 0xd7c03ebc, - 0x7e012750, 0x3a802c06, 0xdaa0dfec, 0xb4233ace, 0xdbc55a0f, 0x6b9c0687, - 0x743ed04c, 0x6ecf6f1d, 0x4331aef0, 0xde66f67b, 0xb0d83c3e, 0xc3ed02c6, - 0x51f6f3b7, 0xac6b9d4d, 0x85aa3ed0, 0x721adfb7, 0xfd41b5ae, 0xcf5e0ed6, - 0xb5aef4ef, 0x5dff3d43, 0xd5d89f5e, 0xef01d6b0, 0xdfc73c4f, 0xd9bde2d7, - 0x60cf9ce0, 0xee0736af, 0x4207e8f2, 0xc23e725d, 0x1cbd8cdc, 0x77d516f8, - 0xded4dc1b, 0x47aef81a, 0x92ea093f, 0x058fda9b, 0xc7bed47c, 0x53f6a5e0, - 0xbed42581, 0xfb52f247, 0x6a4ac095, 0x4b50dd7f, 0x87eeaced, 0x54bafed4, - 0x7549ed4b, 0xcfbea8eb, 0x8c196d00, 0xe33dd4e5, 0xcdfd0009, 0x511b7c11, - 0x6aeb747e, 0x12ca18ab, 0xf91d287d, 0xcd8149e9, 0x5d80fe46, 0xf27bba23, - 0x7c83c916, 0xc29bfcd7, 0x994cc497, 0xbeb052d6, 0x05a7e5e8, 0xd827e71a, - 0x71825baf, 0xce3e6fb2, 0xaa4563b8, 0xab1dc671, 0x1209c652, 0x8dfe963c, - 0xb26c7cd3, 0x4b639e1a, 0xa15e7195, 0x5bfd1c71, 0x8ab7b8d7, 0xb5bcf0d5, - 0x35e7195c, 0x7fa9271a, 0x1b7eecf0, 0xc64423f0, 0xe036fdd9, 0xd9c69327, - 0xf5a4e34f, 0x77fc9e0f, 0xe4e3548a, 0x8ca553bf, 0xce7841d3, 0xbb38dfe8, - 0x86ac99df, 0xcaa59de7, 0x9c682738, 0x575bfd21, 0xd58aeffe, 0xb96efcf0, - 0x69efce32, 0x8dfeac9c, 0x357de7b3, 0x3f79ecfd, 0xa27f3f4c, 0xb7fb7271, - 0xd40f82ae, 0x41f053f4, 0x102e7e98, 0x6ff6479e, 0xa81f3d9c, 0x07cf67e9, - 0x33f9fa61, 0x7fb633c1, 0xa3f82aeb, 0xfe0a7e9a, 0xcf9fa618, 0xfdf19e09, - 0xd3f5e783, 0x7ebcfc6a, 0x511f8c3a, 0xfb0a7840, 0x33c4cf07, 0x3c4cfc6a, - 0x8d8fc613, 0xbfdc99c6, 0xa33f5e71, 0x67ebcfc6, 0x1549f8c2, 0xf4775d70, - 0xcf135d6f, 0xf133f1aa, 0x433f186c, 0x19529e08, 0x8ce3061e, 0xbece3f89, - 0xecfc6a8b, 0x33f1c8bb, 0x3a27d3be, 0xce90dda0, 0xe4ce08dc, 0x0080de0b, - 0xa814faed, 0x30f4b0bb, 0x3d3bc81f, 0xf8d1ddea, 0x84405772, 0xc4aefb76, - 0xa2bb4ff1, 0x58e96ff5, 0x8263975c, 0x3877654e, 0x7aaa2d8b, 0x4a925952, - 0x6454a73f, 0xb369eaa8, 0xf4f554b2, 0xdeaa4707, 0x5e3058cf, 0x7cbc1f55, - 0x643eaab2, 0x7deaa955, 0x55d3e3d7, 0xeeeb59ed, 0x3673d555, 0xcf554f7c, - 0x554f3cdd, 0x54badbcf, 0xedc8de35, 0xd1f5552b, 0xd5531ebb, 0x51acb6c7, - 0x4f6dddd5, 0x3be3eaab, 0x3f8d539e, 0x54cff8e1, 0xb777c2f5, 0xa745eaa9, - 0x3fbd555e, 0x1a6bdcf9, 0x3ce6c6fb, 0x8bae4a3f, 0xc95acf68, 0x910e33ce, - 0x192d5ec8, 0xa3faa262, 0x7f546c43, 0x70df0ef4, 0x8fe3ec27, 0x6bd005f0, - 0x5bbe4a8f, 0x2fec319d, 0x4b1d39d8, 0x63a7d2c7, 0xd7db7d45, 0x80ce801b, - 0x5e874a2e, 0x650d3dcb, 0x3727ae8d, 0xe8dfca11, 0x2e916a4a, 0x4474151f, - 0xd591567f, 0x8d58dd22, 0xfd70e88c, 0x0297c2b0, 0x54f87451, 0xcaf39726, - 0x6a194fb8, 0x3eef51d3, 0x0066f756, 0x9993f2f5, 0x664cbc60, 0x9bc287ec, - 0xbc0e40a1, 0x3a68f99f, 0x09268bda, 0xf9e8d0ec, 0x347f9825, 0xf9c01fcd, - 0x6fcce3eb, 0xcd522dca, 0x52aace6f, 0x60966fcd, 0x4f63277e, 0xe7961dd7, - 0xffde9137, 0xe6987091, 0xa6ad6537, 0xac4bd7f9, 0x25bf354a, 0xf2037f3c, - 0x7f38f3c1, 0xe7f58c41, 0x3faf564e, 0xfd7aa96b, 0xcfff5f12, 0xf3c84eea, - 0x3ffd685b, 0xf5f04e17, 0xd7c63d67, 0xa371846f, 0xf18477e7, 0x5ff9c41f, - 0x69bf338e, 0xfd7ab178, 0xebd5cbd9, 0x5ff9f237, 0x9e4f7bad, 0xfff346df, - 0xaf8f7842, 0x9a71fb3f, 0x75ac68df, 0x38c9a13b, 0x441b52d4, 0x2fe600b9, - 0x050c801b, 0xc6444cf3, 0xde0c6248, 0xd164285f, 0x016a3c3e, 0x9ffe83ba, - 0xd0de8059, 0x72ed977e, 0xd017ac16, 0x6996af0e, 0x4aaec17a, 0x657819e9, - 0x57f72b41, 0xc333f818, 0xad2bbe00, 0x11fd9fbd, 0x7db05de0, 0xa025c91c, - 0x2def8674, 0x23529794, 0xe6307c72, 0xe413321d, 0x877bd329, 0x9a863bdc, - 0x2fd7683c, 0x1f630466, 0x60d85e3a, 0xc515df38, 0xa8b78b6f, 0xea824beb, - 0x097702ba, 0x81940912, 0x0b579652, 0x7f079ef3, 0x7ddd8180, 0x2c6dec06, - 0xb9b0313f, 0x0e7e785e, 0x452605fc, 0xed1d55f3, 0xabbd79cb, 0x73d61d3e, - 0xc3704abe, 0x0d81ec88, 0x3a196395, 0x7bcf0172, 0x77ef0039, 0x852ff298, - 0x7273e9d6, 0x003617f8, 0x7ff1477f, 0xb0bbc88d, 0x0ee08517, 0x7fbfe790, - 0xba054573, 0x83d7d0bc, 0x5e577def, 0xc92de2f7, 0xde98f7aa, 0xa9cdef44, - 0x1ea20c4c, 0xc36ceef8, 0x3b552eb9, 0xf1c03f30, 0xdd0fec91, 0xf1eebacf, - 0xdfb99e82, 0x75d7eea7, 0x8dd1eac0, 0xbb4b7285, 0x3dbec181, 0x8719a550, - 0x1f7f6879, 0xa878e192, 0x973edd56, 0x5fd42539, 0x9fab5773, 0xe3b40657, - 0xcf00f800, 0xf81c793c, 0xe6f844e7, 0xd7f36dcb, 0x7daa021b, 0x0a947a02, - 0xa22cf6e5, 0xbd0f5a02, 0x3fb7dd9f, 0x434041d0, 0xfb588107, 0xf9f7fffe, - 0xae7d8dff, 0x3e492d69, 0x8ad70517, 0xe7c969a6, 0xdb2dfaa2, 0x5f555339, - 0xd55fbc12, 0x4a96f17f, 0x86c2fb55, 0xf9f6aa25, 0xd5561feb, 0xa4ff032b, - 0x75773fea, 0xa1fdaa9d, 0xed54a7da, 0xab3d540f, 0xfbefdfaa, 0x77ffaaa9, - 0xdaaa3767, 0x864b0385, 0x46a8dc62, 0x881d0df2, 0x8df7aef1, 0xa1109b6c, - 0x2fae855b, 0xfca9d3f8, 0xb2a2efd4, 0xc830e50e, 0x5e3edd75, 0x1cab6cd6, - 0xa15bf28a, 0xb50c4ff3, 0x69fe5043, 0x672b55e9, 0x6325d0fb, 0x88bed083, - 0x2e596717, 0xf3ca2f30, 0x19db816e, 0xb213f3ca, 0x0d6c675e, 0x8972d7f1, - 0xd7f2dff3, 0x3f229606, 0xb942972c, 0xe3f8b6b5, 0xd68126b2, 0x1a36d8c1, - 0x10704967, 0xfbd17918, 0xf382ad9a, 0xe69141d2, 0x6e1f46af, 0xdec1da12, - 0x3f9c3a0d, 0xbee43ed4, 0xe78f0831, 0xc1c01d19, 0xdf49535a, 0x2797f25d, - 0xfe23d39f, 0xf05e54bc, 0xbcf2a6cf, 0x39e547df, 0x6795157f, 0x7654b5fc, - 0xf95357f9, 0xe5403f91, 0x2a7aff29, 0x5037f03f, 0x85bfd279, 0x83fbdfca, - 0x7bf15e54, 0xf4e854a8, 0xb57d96ff, 0xf2bdb8e8, 0xffafb8df, 0x16afbd1e, - 0x23c3939d, 0x0d06ebef, 0x55794abc, 0x61797027, 0xf31676e4, 0x788e2958, - 0xc3078955, 0x94571448, 0xf0ddc1e3, 0xd3f62777, 0x1831e537, 0xcfe8eaef, - 0x7b8e3173, 0xb191a4f5, 0xd3ebf8cc, 0x3c5c5fee, 0x46ee80b0, 0x3858b7f8, - 0x72aa015e, 0xdcec1e36, 0xf3dd7b11, 0x92cf5d78, 0x7726fdf0, 0x3c355c74, - 0xc072e22e, 0xd16af1cd, 0xdacf7b71, 0x847c722e, 0xb3efbb76, 0xc6b5e847, - 0x718b93d8, 0x2347f662, 0x36c63d43, 0x055871cb, 0x575e015f, 0x3a7ff5f0, - 0xfda04e3e, 0x1f1f105b, 0x47e0a5dd, 0x32bff0c4, 0x574aafc5, 0xae90439d, - 0x7bf4cab6, 0x027865b5, 0xe7191d1b, 0xd38b9d6e, 0x7ef04df5, 0x0e4be8f5, - 0xa657f3b4, 0xf2e79ceb, 0x456fe3e3, 0x16d3a653, 0xaab4a76d, 0x841b57eb, - 0x70371e72, 0x831acc25, 0x3ce9d1f2, 0x2c728397, 0x9c654a9d, 0xf392e995, - 0x0bf6325c, 0x2576f872, 0xea7e5f12, 0x6fbf5137, 0xe3788e1a, 0x6168e044, - 0x247de167, 0xf1d9ebd1, 0x3ba5c7fb, 0x8c245ffd, 0xc336b0c7, 0x985f6867, - 0xd1d7ffe0, 0xaa7a63ee, 0x34d6e32b, 0xade30189, 0x6a977cf8, 0xa5cf783e, - 0x67ae94e4, 0xf5be88dd, 0x7f42bcec, 0xa0e7ca20, 0x1079489d, 0xbf6d53b3, - 0x35eaaa24, 0x2a9d03ad, 0x00ff067b, 0x04cac739, 0x72c1d23d, 0xf5ba2c99, - 0xc002f5b6, 0x2e9d0937, 0xf78147a4, 0x92ea615b, 0xafa42e7c, 0xcdb9dfb5, - 0x681b3d85, 0x60f85abd, 0xf5ea66ff, 0x265fe1f1, 0x1bd47d5e, 0x22d7fe83, - 0xd01ea3fd, 0x999f3f71, 0x43e40e02, 0xdc701e96, 0x6cc3fc4b, 0x9ae0fc61, - 0x5513cc19, 0xff01c657, 0x5f6d47ad, 0xa4bbbe72, 0x76bbfee3, 0xbcf2cdde, - 0xf55fc337, 0xe2a7b7ae, 0xac78b5ba, 0xe4b3fd6e, 0x5314fca3, 0xefc151e1, - 0x59bbd124, 0xee97f984, 0x7f212d3c, 0x7204305d, 0xb903787f, 0x5b7e17df, - 0x646b79fa, 0xd8f72b9d, 0xf95fbec9, 0x0bd79cac, 0x779c4eb0, 0xf13c915e, - 0x0515e835, 0xa67c6807, 0xd3d88c2b, 0x5e6d7e4a, 0x27f232cb, 0x0901663e, - 0xc51792e3, 0x9fb44286, 0x4a353697, 0x32f3801e, 0xbe2395d3, 0x1c77b32e, - 0xb5fb51f9, 0x9f08944f, 0x899f6760, 0x6cec1386, 0x6cec1d55, 0xbb117d55, - 0x51f30d37, 0xc01b368b, 0xaa75a7c5, 0x9d115fda, 0x5662ee34, 0xc9768f5b, - 0xeffc96d9, 0xf0fb86dc, 0x88850bfa, 0x3cd079df, 0xf8f10928, 0xcbf1e136, - 0xdf04bfce, 0xde77df1f, 0xf26add08, 0x561e328e, 0xc13c14ec, 0x44737418, - 0x7d0ad796, 0x5f8641fd, 0xc59c0f89, 0xdea4417a, 0xa17fa9ad, 0xfe657fa9, - 0x4bba014d, 0x24f7ec8b, 0xe91677d1, 0x38f906ad, 0x5fb7c221, 0x3ef4fc79, - 0xa37f77e3, 0xf3560fe3, 0xc5ff8c0d, 0x4e7e3a37, 0xfa8df81f, 0x77e3be82, - 0x59631d9b, 0xc4a9d902, 0x3a71815f, 0x1fe9bbf2, 0xd2136bda, 0xc0a69fc9, - 0x39ddd638, 0xd9a38c41, 0x14e99dcd, 0x54bf07d7, 0x6024f30f, 0x0edf907f, - 0xf9f016e6, 0x2cd37ed3, 0xf8ca8794, 0xe55eb776, 0xe914267f, 0x7b28fe35, - 0x61f00737, 0x38a6a793, 0xfcedd41b, 0x5b6b666f, 0xe30b7c4c, 0x04e8fca8, - 0x2ffe45d6, 0x9e7aa78c, 0xa1d59a38, 0xa8f44a1a, 0x6d154f9f, 0x9c4b6f14, - 0x9c4e28c6, 0xfad7ae5c, 0xd2c315f7, 0x4740e0a2, 0x32c9ea1b, 0xcfa6e01c, - 0x67fde014, 0xf08cf4cb, 0xc5ff8012, 0xbc593380, 0x01f9c216, 0x39df155e, - 0x65f540f2, 0xe7aabc11, 0x4d19e700, 0xe50f207c, 0xb8b31246, 0x53801e71, - 0xdbd1eed5, 0x0e1e2853, 0xa3e517f2, 0xc989d4cd, 0xaaef9c7f, 0xf4ebaf0a, - 0x190b23e9, 0xfc385085, 0x942fa601, 0x83ef8bf7, 0xd313bfaa, 0x8f04d9d4, - 0xd8361c7a, 0x6f8f2d19, 0x8309fd95, 0xe9133bc1, 0xad6870aa, 0xa717f388, - 0xaec872bb, 0x3a214b68, 0xca5d5acc, 0x685d42ce, 0x9cf78460, 0x39ef1c0d, - 0xf71e3a3d, 0x0e09675c, 0x268cb183, 0x9c833016, 0x301cad02, 0x8259c78c, - 0x5ae49fb2, 0xcd3cc3a3, 0x7829a07a, 0x54a7adaf, 0xa73610b7, 0xfc609b09, - 0x3e3de96f, 0x67c1c63d, 0xe375d2fa, 0x9ae161f0, 0xa5a0c18e, 0xb8211b19, - 0x05080b41, 0xc2de8e87, 0xdf184a43, 0x790f4185, 0xd72ed46c, 0xdaed0859, - 0x2faf0b06, 0xae9417d7, 0x988ff787, 0x5d71cbbc, 0x891ce4cc, 0x4a162b79, - 0xb7c6f5a2, 0x0724024f, 0xb6f2b815, 0x4cb54d77, 0x2814fe40, 0x1ecc3fcf, - 0x24255bb6, 0xa5361dae, 0x6ed0921e, 0x2dbcb6f5, 0xa2bb7fa1, 0xd76a6de9, - 0xa1ca1d61, 0x07535dc9, 0xd4f88981, 0xf4d2b2ba, 0x4b5e3011, 0xd60eba65, - 0xb2badcf5, 0x4f75ea43, 0x1c51d35b, 0x775eb759, 0x77dd66b7, 0xcfdd70df, - 0x5d2eefe9, 0x75ffdc5f, 0x8b3fbec2, 0xa25199f8, 0xeefe510b, 0xf0282da4, - 0xec99bb78, 0xc69c7941, 0x1287f638, 0x7e718437, 0xe850eb8a, 0xa14f7947, - 0x9174789b, 0x79239ccd, 0x1f4d503e, 0x6d9ef4c7, 0x7a4bd708, 0x4054894f, - 0x787b25eb, 0x2ee7cf86, 0x2dd08fcb, 0xd1f2f9b3, 0xe61832be, 0x57e702fd, - 0xb2519ae0, 0x7802cc52, 0x21ec6177, 0xd49eb235, 0x2e7301d5, 0x03d533ac, - 0x7be177d8, 0xcf7c66be, 0x8427bb31, 0x32262647, 0x4620be5f, 0xaf995ee8, - 0xdf1e4dfe, 0x05d4afaf, 0xed5c90d7, 0x08bc7012, 0xe869743d, 0x43d387a1, - 0x87a269eb, 0x9cd3b6ea, 0x4aeb5a1e, 0xdbaa9e91, 0x85d1a704, 0x8719eaeb, - 0xebeffcfb, 0x61ea97e6, 0x7b5a879f, 0x1d0107ea, 0x69655818, 0x7af09985, - 0xb3ebe118, 0xca7c323f, 0x6fede2ba, 0x1facd1c3, 0x707d468d, 0xe61ee75c, - 0xe94de08a, 0xd12f4977, 0x7c906c3e, 0x295e90ef, 0xcb823aea, 0x3be8ed7f, - 0x1c5bb40e, 0x883defc7, 0xc1663bef, 0xf322b90e, 0x535f1c36, 0x1a67e78a, - 0x64381d60, 0xa009eb02, 0x1f1f13dd, 0xf8c25f9c, 0xf84d3968, 0x9e1d61d1, - 0xa7e72abf, 0x5ec8cf80, 0x7ee56a19, 0x1e7ac7ee, 0x5e9bfb3f, 0xef6e4b94, - 0x2abf1ea6, 0x5c4fd0b9, 0xa9fea3a7, 0x5e8e8e58, 0xf7ea3aff, 0x055e5437, - 0xfb287c11, 0x4813d0a9, 0x5fe62b4a, 0x577c5996, 0x6493f4d5, 0x4f1a8acd, - 0x9fa36f79, 0x7f8017b9, 0xde63b137, 0x81ff2823, 0xf543fe7e, 0x198318de, - 0x47f4a6f1, 0x3fb58cfa, 0x14331ef0, 0xd05c79f0, 0xa563b9bf, 0x7f617688, - 0xf650b5f7, 0xacad0b8f, 0xbf7835f6, 0xac4a0130, 0x01f5cb27, 0x2f107d72, - 0x75b94fb3, 0x946f3c02, 0x6e9effb8, 0x7a92e390, 0x3bcc48e7, 0x3db81ba5, - 0x923e9c58, 0xb7c2bee4, 0x2484be88, 0x58021b32, 0xe964f566, 0x3e14df70, - 0x42e8f7d6, 0x594a5076, 0x0dce977a, 0x61f98fcf, 0x9ff037dd, 0xbd108fa6, - 0xd1d1ecb1, 0xfcbf5d06, 0x5276b898, 0x6c3b1f57, 0xec9521b4, 0x42f78da3, - 0xaf447abd, 0xc6b5fb84, 0x8ddb7d5a, 0xe169efce, 0x13ed763f, 0x577bfa07, - 0x8f2c6afe, 0x5078f715, 0xff51dbc6, 0xb14f7a6c, 0x30ab68a3, 0x3ec0cfbe, - 0xd70bf0e2, 0x7d92548d, 0x3c890774, 0x3e80c7dc, 0x55a7f509, 0x777e73a0, - 0xebb3fa46, 0x8477e7c0, 0xb1b05696, 0xb72bf950, 0x3ff04c6f, 0xe98faff4, - 0xed1e747d, 0x9a79e318, 0x3b6d6b42, 0xd33199d6, 0xf985c3bd, 0xa29e753e, - 0x2ca1a130, 0x42489509, 0xc533cd26, 0x0e4f69a4, 0xb2fe51e8, 0xe71e4cec, - 0x945f3062, 0x44f40e9f, 0x7c3658f9, 0x3395d924, 0x65dd2af2, 0x48bdfbf2, - 0x731b7eac, 0xfae44426, 0xeefdd734, 0xd1dd9532, 0xfd3946e0, 0xe245dfd6, - 0x7f1e2d6b, 0x7d7ce065, 0x9775efd4, 0x63c5f4e5, 0x67584ba9, 0xa7c5f577, - 0xfc5a5f16, 0xc95fc3c6, 0x52597729, 0xf1693c0c, 0x46ff0c72, 0x06368f3c, - 0x9de20203, 0x4b98e9e3, 0x78188160, 0x29d2ec52, 0xa4683176, 0x9dd90f76, - 0x68f0c977, 0x4f17d6f1, 0xd2bb8a9e, 0x411ff022, 0x4e91e87c, 0x884aefdc, - 0xdb0304ff, 0xdd0ceb81, 0x6ab7f949, 0x434c1fb9, 0xf93bb579, 0x8375e150, - 0xf087707c, 0x386301bd, 0x6d55fd7d, 0xb83dde7f, 0x14a0dd72, 0xfb9803c4, - 0xd4671f1c, 0xf1b8c374, 0x7da4cd61, 0xdba8fc07, 0x587e3993, 0xcbbf6f32, - 0xd0d769a9, 0x0abd768d, 0x3e1bfcdd, 0x3f17d498, 0x30ecdd0a, 0x067276c8, - 0x1e788c1b, 0x02426fbb, 0x78da2dc5, 0x4f4b5ede, 0xc37a4f13, 0x47f4c8e3, - 0x5f3025f4, 0xfb33b9f8, 0x569bc86b, 0xf25166d0, 0x7be8b866, 0x51bc9623, - 0x7976fff6, 0x81676e9f, 0x4b03a283, 0x74c25ffd, 0xff591993, 0xda275c21, - 0x20d883e7, 0x8318e75c, 0x7969cb8b, 0xcb75e19d, 0xe58a09e7, 0xb64d8bf9, - 0x7acb8e10, 0xf8c297f4, 0x5cf8a2cf, 0xc08a4a40, 0xb3fb9061, 0xdb8cb521, - 0x79d20f5d, 0xbb0bc01c, 0xf1c08d6e, 0xa7a08307, 0xc70c9578, 0x80a69de5, - 0x57ac2b78, 0xf511fdf4, 0xf8e125d6, 0x3e9f5a58, 0x4a7a8b94, 0xdadbdedb, - 0xd0ed8d51, 0x93f5116f, 0x71865fe1, 0x9ea7a007, 0x6dc18d37, 0x8a48e231, - 0x4a6c093d, 0x83e15cf2, 0x6505513b, 0x92dfa5f7, 0x1c7af1d6, 0xa5b74b5f, - 0x1da159e0, 0xbbd7a5aa, 0x7c1ccf58, 0x4553a5ae, 0x7a597eaf, 0x30a9ec50, - 0x74d4845d, 0xd003d0a1, 0xfa42ffc7, 0xf1f09ee8, 0x9efe68f3, 0x169bd098, - 0xbd810f4b, 0xeca293a7, 0xb3f678e8, 0x48273762, 0xc7da333e, 0x595d797a, - 0x9e1d2e79, 0xf25dba8f, 0x62b9f058, 0x0fccdc4f, 0x80e01d60, 0x91cc7d02, - 0x83a4ddf1, 0xc0dbe006, 0xf288214a, 0x63d621e6, 0xaa1ef9c0, 0xc9fca835, - 0x8f9ee639, 0xe6fd087e, 0x3d270dd4, 0xbf28c3e4, 0x38f3ef48, 0xffcf3d44, - 0x5c9ebcb3, 0xaee6bff4, 0xd1fc6836, 0x39e3a224, 0x23ecfe4e, 0x09303be8, - 0x4d4aedc7, 0x76f94d1a, 0xfced7f55, 0xe3b43aca, 0x91abdf6a, 0xee78b2e3, - 0xf7851dca, 0x83b71251, 0x131ef0c2, 0x6f80bc39, 0x6aebac1d, 0xd3e088db, - 0x2954e831, 0x8e5d267d, 0xef52393e, 0x3b38d37a, 0x955f6318, 0x3f7c1479, - 0x7c153ac8, 0x0e8b1e7e, 0xffdc7d8b, 0x910e6dd6, 0x2f1dacbd, 0xec8ca7a7, - 0x81269cb0, 0x4de5deec, 0x2af9ba25, 0xa3fb9bfb, 0xa6efec7d, 0xf2de3483, - 0xfedc8396, 0x3b23aa6e, 0xf70b797e, 0xa43ec047, 0xc80463f3, 0x15cbb268, - 0x7983d33f, 0xb79815a2, 0xbd21ede4, 0xf3d5cf0b, 0x78d235fe, 0xf21ca9f1, - 0xc0ff7913, 0xa7e8b5c4, 0xa85afd86, 0xbab5fb47, 0x9576c2ba, 0x6c281b5f, - 0x5b5f91bf, 0x05385f53, 0x8fe05afd, 0xcdc15245, 0xe4b663f9, 0x797fa1ba, - 0x41ade4c4, 0x02e2533e, 0x6abffdda, 0xfd202572, 0xbdfb253d, 0x23cf57d3, - 0xfc3cde7b, 0xa37990da, 0x7df2de51, 0x76e24c7f, 0x7be88a4b, 0x3eebc70c, - 0xcf172d74, 0x7fb4d4cb, 0xbcf911ba, 0x1ec3ce4d, 0x5d9157f7, 0x13dfeca3, - 0xa777b712, 0xa077688f, 0xc14f7ffd, 0xcfe81cef, 0xbcf3d65c, 0x4922a5cf, - 0x18f66f65, 0xd7027aee, 0x1e8094ad, 0xf16ee511, 0x82938e84, 0x8ffcbe23, - 0x808f77c8, 0x7b5d9df2, 0x5bd70d3b, 0x81d872d3, 0x7e84bef8, 0x5bc9c610, - 0x8f30d3da, 0x77f9a2b8, 0x9e7bf40e, 0x7b5db897, 0x40e9df59, 0x1ef96ebf, - 0x5fc9dbb0, 0x003da50a, 0x32d4ba78, 0x3e69f0bf, 0xbf5a298d, 0x85f57fe1, - 0x76edbb11, 0xeb282053, 0x284e253b, 0xefa1875c, 0x663d116c, 0xedfb5f47, - 0x4dacd1f2, 0xcc0fb815, 0x0f861ee0, 0xec83acf5, 0x09962539, 0x21cf0a92, - 0xbf2b901d, 0xefbde96e, 0xe7162236, 0xda0251ba, 0x0c14be3d, 0x8db69592, - 0x9188375b, 0x73d950be, 0x12ef7b5a, 0x1b77dd73, 0x7aa3b9ca, 0xd6b37686, - 0xfdd163fe, 0x9f7fe387, 0xd6bcbc25, 0xfdc56d92, 0x59d320da, 0x54ef4b4d, - 0x166a97e4, 0x6f7e0efa, 0x3a22dd55, 0x7246ec43, 0xf85bdd77, 0x9b7753fd, - 0xd8f485c1, 0x34d876dd, 0x22adeb16, 0x4e6a99c5, 0x3a428f14, 0x2866d2ba, - 0xbcd7bc47, 0xf903b1f9, 0x57cfd15b, 0xde7a44da, 0x9e9676dd, 0x695ee32b, - 0x7a851e4d, 0xfdc759a5, 0x9f238ebc, 0x7fdf915b, 0x326aed7d, 0x7eb297f9, - 0xaaa7618d, 0xddad4eec, 0x6e19e53a, 0xb5494e47, 0xec579c93, 0xf8fa3ecb, - 0x67675b14, 0x6b1f425f, 0x4919f0f4, 0x616ef3b6, 0xd8af31e3, 0x19792d7a, - 0x9b7765f2, 0xe286b9d5, 0xe88edc1e, 0xb9f4f8ee, 0xb8fcf819, 0xee9c7148, - 0xf1d1226b, 0x86cb03a1, 0xf1a2d976, 0xf5fb4f5c, 0x5f3fc0d9, 0x3ffd0fd9, - 0x07716c3b, 0xf77a7d70, 0xd63daf28, 0x78e504be, 0x97432841, 0x4320658e, - 0xec35f457, 0xe27d93c4, 0x7f91d7f7, 0xa67a9857, 0xddcd18a2, 0xfe425a7a, - 0x057920df, 0x2687e923, 0x8075f22b, 0x73c20e95, 0x561655cc, 0x53d4f48a, - 0xa0db9cc7, 0x9d51cf75, 0x30fb04ce, 0x1ba64761, 0xf955edb7, 0xa692f35c, - 0x4a332906, 0xbf912c5e, 0x0860bb3b, 0x7a8a490c, 0xcb91a4fe, 0x97870bab, - 0xeef248be, 0x161b237d, 0x362dbf43, 0x5bb57d72, 0x85d8cc0a, 0xe8e8cefd, - 0x238ec1fb, 0xf3c11c6f, 0xba4e4b10, 0x28bea1c6, 0x6ffa7231, 0x3d6afe3d, - 0x3d690b9e, 0x76f478c5, 0x83a8a57b, 0x1733f779, 0xabbd3f8f, 0x1c23ff23, - 0x649e63b7, 0x461de75c, 0x1ff6672e, 0xc74795d5, 0xe7cbf605, 0x1a356e1c, - 0x4661fc68, 0x8ed7ca91, 0x23cf2696, 0x19e5f3be, 0x75ceef91, 0x915c3bd5, - 0xef629578, 0xb5f77a4c, 0xcfe06319, 0x4e749749, 0xbbd76edc, 0xaf5c44db, - 0x896302eb, 0x07fb5f42, 0xf88f1bc6, 0x7fdbc657, 0x70078f89, 0x54be421c, - 0xf41a0ff0, 0xbea1a347, 0x849f53bf, 0xf82813df, 0xcca1d657, 0x9e626aef, - 0x8eb11b46, 0xc41bb5e7, 0x8f52314d, 0x54ef91f4, 0x7449cef8, 0x29e486f9, - 0x1810f4e5, 0x870bf582, 0xec57642d, 0x4b11f596, 0xf88a1caf, 0xbe69f653, - 0x0513eb91, 0xcff3789e, 0xca54e191, 0xafd74b2f, 0xa2015c1a, 0xc5023d9b, - 0x90815c19, 0xfb053b29, 0xe739d365, 0x37d8de48, 0xbd87f707, 0xd6ffa6ab, - 0x8ace9d2e, 0x214df1f2, 0xfde0d291, 0x74c34fb4, 0xfa226fa6, 0x88c93d6b, - 0x7cee978f, 0x58cdc798, 0x728e9068, 0xc84181c8, 0x9c3fc8b7, 0x0503437f, - 0x35b52728, 0xf8441dae, 0xaf90390d, 0xbe027822, 0x41b6b2c1, 0xb25d7a42, - 0xe58b978a, 0x6c9647ef, 0x2e7f11f1, 0x15395ada, 0x98d5a7ed, 0x28bd40f4, - 0x59d32bd3, 0x4ebcf032, 0x85df6caf, 0xdd3897e1, 0xd4d96c5e, 0x7d02f38e, - 0x63e233fd, 0xcfb3eb72, 0xbd0ab823, 0xa06edc5e, 0xde90aa71, 0xad74f8a3, - 0xde7bafbc, 0x693ef4e5, 0x7bf4a1bb, 0x0149eeb0, 0xec38c4e6, 0x443bedfe, - 0x91fbdf94, 0x9f39339e, 0x70be9ea3, 0x63eb69f8, 0xeb4ecfa8, 0x777bc618, - 0x39aaac4b, 0x1a3a2f8a, 0xeff1575f, 0x33759dd2, 0x95dcae28, 0xa66ba024, - 0xf782adf0, 0x1a7b92dd, 0x34b7fff1, 0xdfc65ffc, 0x81ff87df, 0xfe649b7e, - 0xfc0e54df, 0xb7128f0f, 0xce380a27, 0x79f6296e, 0xfd8d57a1, 0x5710b73b, - 0x23ef1eae, 0x72355f57, 0x0d91dbff, 0x73df57f3, 0x30effc95, 0x6cdd327c, - 0x26e8532a, 0x7b71f053, 0xf8839753, 0x3d22bc02, 0xf289bd93, 0xb82b24b6, - 0x8f45884d, 0x967c946b, 0x72236f8a, 0x5f5fe14d, 0x5853c21b, 0xed16bb56, - 0x008ae4e4, 0xc145e9d1, 0xf4093437, 0xe7e445da, 0x67e17218, 0x333e5e32, - 0x1be754f8, 0x32c1c2fb, 0xc0abae90, 0x69f3a2e3, 0xee27055b, 0xdaeed28f, - 0xf782fdca, 0x9e573e65, 0xf915ffbf, 0x53f78c3e, 0xeface27d, 0x933eb91b, - 0xdcceb04c, 0x4c67d720, 0x60be2528, 0xc819e9ba, 0x8f404b6f, 0x8f4a2f7d, - 0x1034345d, 0x38782abd, 0x67fbd32b, 0xcfdd7c89, 0xc41e70c9, 0x5be12998, - 0x7a0947ce, 0x5af9c0bd, 0x8bbf3814, 0xc3c5fe38, 0xdd11a793, 0xee9b13df, - 0x246aed97, 0x772c4cfa, 0xb3b9438e, 0x2736ef49, 0x8f258e8e, 0xec765483, - 0x49f909f8, 0xf7c8c748, 0x0aa0f8f1, 0xa0c580f9, 0x7fd020ff, 0x7429fed4, - 0x1d717400, 0xd73ca5f1, 0x379285d2, 0x5bb2f053, 0x669b7793, 0x601a78e2, - 0x25def2e2, 0xfa78a9cb, 0xf3ef2be5, 0x2bf87dbb, 0xe6a054cd, 0x456fdc2f, - 0x13717c4e, 0xe2679b3e, 0xfa644fed, 0x780ede4e, 0xe4a0627a, 0xeb720b5a, - 0xe766d809, 0xa63e48f8, 0x595f9e49, 0xa09348c7, 0xf368dbca, 0x6f830629, - 0x9f0a2984, 0x8d73f798, 0x334bd08e, 0xd81cfce3, 0x43cf946e, 0x5f765538, - 0xc6912981, 0x40c1ea77, 0x967fd405, 0x0361d959, 0x0ceeeeb8, 0xe1718c54, - 0x5981db77, 0xbae264f7, 0x853e829c, 0x53ace5d6, 0xdf20ce8e, 0x7c50b71d, - 0x3ddb3f24, 0x974cfc8a, 0xf7c71f3b, 0xeca4fbc8, 0x6b75bc67, 0xfdbc5cf5, - 0x21e3279c, 0xcad76e55, 0x2e26418f, 0xf9657a37, 0xf83fe5a1, 0x526f9317, - 0x3b242fb7, 0x6d8c9d90, 0x326fde07, 0xff5179f0, 0x00d4bf40, 0x23ddfeff, - 0xdcec27ef, 0xc343c41c, 0xa39d2376, 0x31d7f850, 0xf18e9bcb, 0xe48a4713, - 0xaeb8c176, 0x7e1a6c59, 0xe8f2efbf, 0xd651bfc8, 0x26e1ff5f, 0x7ea26fba, - 0x7da19187, 0x57ef209f, 0x0c162cc2, 0xbaf9f109, 0xb1e80763, 0xd3fe2894, - 0xee89eb07, 0x5103bf80, 0xd93437fc, 0x2d806e97, 0xdbfac1fe, 0xc0b74cca, - 0x8ccc993c, 0xa82aea16, 0x347c006f, 0x96047924, 0xb675f548, 0x0fe3f181, - 0x2e4d303f, 0xbf04f3c3, 0x6fbe7a32, 0xc438a54a, 0x1c2cb00f, 0x28b22b50, - 0x1d99bdbe, 0xb1f955f3, 0xb0738e46, 0x69469036, 0x9ce2f8aa, 0x2f8a2e9d, - 0x507c8d3e, 0x79fe719d, 0x8da6ae1c, 0x078beb9f, 0x678c8a47, 0x17c4e790, - 0x115ade29, 0xcf857ffd, 0xc925379e, 0x3011ebfb, 0x1dd0aefe, 0x93da29f2, - 0xe31d7e4a, 0x2f8a762e, 0xb0ee8907, 0xc23e309e, 0x742a1b7f, 0x61e2b1e5, - 0xafb64cbb, 0xf23487a7, 0xb17db589, 0x4bd031f7, 0x48b7f835, 0x29976af2, - 0x54d81eca, 0xc78d2671, 0x439d19cd, 0xe39e447e, 0xffee35c5, 0xe1f28e18, - 0x947efcb7, 0x80294671, 0xfdc0aae7, 0xe4d33975, 0xda9d90f1, 0xfc1d9084, - 0xd1cf9add, 0xf37f0173, 0x2f951d73, 0x3cb7b3fe, 0x56d9ed13, 0x032c1b9d, - 0x5c93ebcc, 0x41650f70, 0x9373d013, 0x2a9b9f85, 0x9079b769, 0x1305bbfe, - 0x13e99b9d, 0x19ea2f8f, 0xd7da0bb2, 0x411f01b6, 0xb184bbb5, 0xef57844e, - 0x0ad0f3a6, 0xd89ec77e, 0x63df4794, 0x37dc1be9, 0xcbc55b8a, 0xb6af16df, - 0x894adc50, 0xf4f71593, 0xb5649d10, 0x61f8ea65, 0x5e8f3e29, 0xd792af5e, - 0xbef1926d, 0x226be8fb, 0xb2c2b1ea, 0xef68b586, 0xef7d1867, 0x2e4ddd23, - 0x1339db56, 0x3b76da84, 0x4634d7d2, 0x1fc2827e, 0x20ec5dc9, 0x4f12a986, - 0xcfd07976, 0x73c17c9a, 0x04a9fd10, 0x77f8132f, 0x24f3e192, 0x58ff70e7, - 0x07b8478a, 0x13fc29c6, 0xe328bc23, 0x2a5a3eec, 0xd2919da0, 0x46b82659, - 0x2defa5f7, 0xe04e77e8, 0x5f701ee7, 0xe8687f15, 0x6196462f, 0x2fe9487c, - 0xbd5cb99a, 0x429be7cd, 0xafa34fa1, 0x349de717, 0xa98ed83b, 0x81558997, - 0x84f10c76, 0xd184b3d7, 0x02ba8378, 0x27818eb4, 0x9658257d, 0xf7048948, - 0x3a210be4, 0x96a0312f, 0x5b9231d1, 0xfb25df3a, 0x4eda96e1, 0xf771f701, - 0xef0443d1, 0x5e0ecee0, 0x9af57cca, 0xb814ffac, 0xa27f644a, 0xd5c38e44, - 0x8e9f9e5f, 0xecd181fe, 0xa338c12b, 0x12fa8eb2, 0xbf9e3a5f, 0x3ce782dc, - 0xe73fc426, 0x14966691, 0x8cc1373f, 0xaeecee7e, 0x5a7b4823, 0xf8ed39bf, - 0xb48fda19, 0xdd1ddcd5, 0x80a57c72, 0xc1e5b5f4, 0x22b37ed8, 0x71c8b62f, - 0x14f3a8c4, 0x7ad1cd83, 0x9ac932b9, 0xc28f2515, 0x9e722672, 0x9e7cb762, - 0x6f7aa6c2, 0xa46613cc, 0x27834ea7, 0xdf2b9f07, 0xdf2abce1, 0x71f8a01b, - 0x961ebe0a, 0x9e68d3f7, 0x1086e749, 0xe3a04e4f, 0xbfb1cd57, 0xd6685987, - 0xd3977ac9, 0xf4e4eb0b, 0xb688eb82, 0xb999a633, 0xe3cdbd5e, 0x74e7a29b, - 0x9c788452, 0x476c1454, 0x1e589dba, 0xbffa4768, 0x5274c985, 0x4b44e9ce, - 0x939bf7ef, 0xa1e93a64, 0xe0260a7b, 0xe43145f7, 0xdb998563, 0xa59d2977, - 0x0fc03f44, 0x857ce177, 0x03456a83, 0x339cd0a5, 0xf0f8ef50, 0x9e7822f2, - 0x4769e45f, 0xbc7a737a, 0xa8db8e22, 0xc9ba7277, 0xb8c49ef4, 0xe4aa7d77, - 0x38d02b5e, 0xe0c736df, 0xa7e416ab, 0x4a7e11d1, 0x5a47e391, 0xc3229cba, - 0x1cf193e5, 0x43df1e7f, 0xa74a4f38, 0x33f783ce, 0x4c25b9e0, 0x055c4e46, - 0x96f912fa, 0xd2f9d275, 0x09672aa4, 0xe5a0ddf2, 0xf9f7016e, 0x016fbd25, - 0x3c76b3ee, 0x350c9f45, 0xbffe8879, 0x6268deb2, 0xf2ff8d26, 0xb5db99b0, - 0x7e512b1b, 0x8499f2bf, 0xf0a5d5f2, 0xd6f1d1e5, 0xf3745179, 0xf83a5f74, - 0xa07458a7, 0x3a5a7f95, 0xb50bc888, 0xadbc03fc, 0xedc3fbe5, 0x55ce94dc, - 0x6a1b9722, 0x7f6f1779, 0x0d0dc8fa, 0x3de98f1e, 0x097ae0cf, 0xf39105e9, - 0x74f4f1db, 0xae1ff9a3, 0x31cd1ba7, 0xd4ceb4f4, 0x9f3c1bf3, 0x744da2bb, - 0x5f225c61, 0xf6ba8f3e, 0x4f3a24f1, 0xe09362f0, 0xd1439746, 0x502244d3, - 0x6127b2bf, 0x4a15bb2c, 0x6ae78078, 0xb2250302, 0x08c759cf, 0x24d633ca, - 0x1bac70ca, 0xdbb7fa41, 0x51e600a9, 0x256063eb, 0x91d3fa01, 0x684b181d, - 0xf310783a, 0x988b6b2c, 0xb77000cf, 0x80f3f1b7, 0x485bd62f, 0x7e3eef9f, - 0x400f37f5, 0x1d71e73d, 0x0e047f1d, 0x4ab673a6, 0x03b145de, 0xe8590e3a, - 0xb32f703c, 0x7754d1b8, 0xf8790d8b, 0x21fbec02, 0xe8d983c4, 0xe2281fcb, - 0x77aec439, 0xf1eca38a, 0xccbfd6de, 0xe48ae439, 0x7d0e9a97, 0xdf6d185e, - 0x14a9f929, 0x3996f7d1, 0x963fdfca, 0x77cb9677, 0x055fb9cd, 0x9c5e309e, - 0x5da27f1c, 0x2375f04f, 0x48bf687c, 0x10fb861e, 0xe3d648f8, 0xfb94de32, - 0x0adbba0f, 0xbe80fa4e, 0x98393c5e, 0x7b5be1c7, 0xef7768cd, 0x214ef932, - 0xf4b7899d, 0xf6a9f9d0, 0xe811deb6, 0xf9fc834f, 0x1ef79f08, 0x9d149b3f, - 0xeb12feff, 0x3f5a24fb, 0x729f5bc4, 0x1f4b5e3e, 0xda167dda, 0x184dfe0e, - 0x50c07c4b, 0xb086054e, 0xf567fa20, 0x17adc663, 0x31672371, 0x341dc517, - 0x999fb479, 0x8e65ffbc, 0x4c679fe2, 0xde21bfde, 0x4efc1e71, 0x05f9d603, - 0x989ec7d6, 0xdb478f9f, 0xf53ac2be, 0x18fb9896, 0x215afda2, 0xe60567af, - 0x537cf0fd, 0x3852e18b, 0xef231ddf, 0x8091fb07, 0xdd4a05e3, 0x9fb87d27, - 0x6bdcd81f, 0x4efa1f11, 0x0091da27, 0xb3b6227f, 0x97ba4aa2, 0x50f060c7, - 0x3ad5f47e, 0x5bbd7e7e, 0x1e31b8b0, 0x6491dcd6, 0x33f87941, 0xfb1d2f93, - 0x9d5dd48f, 0x09fa7183, 0x3cdd5e9d, 0x41be53d2, 0xe753b216, 0x8e09eaf7, - 0xdfda315a, 0xcfeb12fe, 0xe7dcc4b1, 0xc790fb3e, 0xa1f7c5d7, 0xf462e7df, - 0x3e9c7bfc, 0x45d651f9, 0xfb83f6f1, 0x3cc5c93e, 0x4f81f552, 0x7ead3fc8, - 0x5b9b48c3, 0x0488c6f6, 0x252be3a4, 0x4b89edb1, 0x1eb75afe, 0x967199ec, - 0xcb9b922c, 0x23dd2759, 0x61e9a2b0, 0x5e4a3eb7, 0x71d3f62a, 0x8e056743, - 0x6440bc7f, 0xbd774075, 0x580389ee, 0x94ac390c, 0x097b45bf, 0xfd1f7f60, - 0x9f9bd4d2, 0x9de6d283, 0x338fb4fb, 0x42a11c53, 0xb3cc8763, 0x88f73d70, - 0x8fbc325c, 0xbcbce005, 0xe0e74ed7, 0xcf7f8f2e, 0x5c4b1f81, 0x7e5df96e, - 0xb0ffcf00, 0xbf3047ce, 0x8d8bf816, 0x718aa8fc, 0xd9d7e5ef, 0x3b76fc23, - 0xdbb0418f, 0x70e13f5f, 0xe68aff41, 0x144094f6, 0xa1e7b4fe, 0xc7d7911e, - 0x6e745df4, 0x98bfed84, 0x563ef786, 0x829c3bec, 0xec37fdeb, 0xaedfc318, - 0xf44d5d58, 0x9f22d533, 0x1960caa3, 0x8bfa0f28, 0x0573ed07, 0x5dc7c70f, - 0xf77a821c, 0xd23b1c4a, 0x75ebf72f, 0xf6801a4f, 0xca14854d, 0x55bf1589, - 0xbc2d2bfc, 0x3b373b37, 0x58f7e243, 0xb6af9f6a, 0xebdf3d70, 0xf000b336, - 0x068d23e9, 0xc4eeaefa, 0xcacc3fb5, 0x64f8fd87, 0x06b9c1ab, 0x85eaadf8, - 0x309bc1f6, 0x48ce395e, 0x5c4f97f1, 0xcba41ca1, 0xf3f02fc5, 0x7d6c9fb8, - 0xc8f30d24, 0xb5f409ff, 0xdc58e01c, 0x55e7a068, 0xe7a7df8d, 0x5bba6517, - 0xe52a42fc, 0x3c744f97, 0xaceb869d, 0xdf93fbfa, 0x966ffe41, 0x41c6a39c, - 0xa0977cb9, 0x74b7773a, 0x575559bb, 0xbacad2f2, 0x8f391099, 0x7e7802e7, - 0xe79af969, 0x89f57780, 0xc2d2fe5b, 0xdd6f8bed, 0x2eaeeb07, 0xaefb25e8, - 0x8c8588fd, 0x44db5fa8, 0x71a1dfd2, 0xadd6f5ff, 0x77f29f50, 0xd31f9bbd, - 0xb239274d, 0xece5c4c8, 0x70fa7d94, 0xff719cbe, 0x615776dd, 0x08797cfc, - 0xdbd200e4, 0xe18a9f94, 0x79f479bc, 0x5cde6d54, 0xf36b8fc9, 0x029c78e6, - 0xf2cdf1e5, 0x1c3f0ae6, 0x49cf84b3, 0x1fb7dd12, 0x45f279e1, 0x2f6e45c7, - 0xfc4e44dd, 0xe3d6e116, 0x107b1efe, 0x6427dde3, 0xf6b89c6c, 0xafbc3ac9, - 0x012293e1, 0x93ec2033, 0x58f2c66b, 0x2287707c, 0x659cf02f, 0xef5f645e, - 0xd7092f71, 0x5dbe0d91, 0x1ceab0f4, 0xd5e5ff68, 0x49f0f98d, 0x419eff0b, - 0xfcb4cf2b, 0x67928ff2, 0x0f0ee315, 0x7ca9d809, 0xcd4bcb19, 0xe568ae5c, - 0x14a7581b, 0xe4e55a87, 0xa5c0a2f4, 0x5fc57785, 0x3f3058b3, 0xf5177e1a, - 0x94efa15b, 0xf8acbe50, 0x260b2e6b, 0x50fea37f, 0x3f8635b2, 0xf095fa04, - 0x07d42815, 0xfd408fd1, 0xdb46fd8f, 0x0025c95c, 0x96673ad2, 0x2772e515, - 0x416b7fe8, 0x6a313e24, 0xe50e8357, 0x376fd845, 0xc577fda8, 0x72b2c95f, - 0x795a31ba, 0xddfc98fd, 0x5df3bc4f, 0x3c4af8ca, 0xf184bea4, 0xb91273ef, - 0x839ca6fd, 0x3967eb5c, 0x933e3df8, 0xd26bc3bf, 0xc8f0eff1, 0xfcf5c4a7, - 0x83fdc8d8, 0x5c5574bc, 0x29bf09f0, 0x792def07, 0xf7a4efd2, 0x53a7f29f, - 0x8bbf23f9, 0x79fc67ca, 0x135efc39, 0xc7c8fe46, 0xd18d2c87, 0xe49b04e7, - 0xb093cdbc, 0xd062d7de, 0xe55623e1, 0xf497a03c, 0xd8d2c2db, 0x567bfdf2, - 0xe4a5e13d, 0xa087fbf9, 0xc1f1f1dd, 0x097dd1ef, 0x83e26b1f, 0x6e6f250b, - 0x13f37d2c, 0xc9379f99, 0x32c7e5fa, 0xfd900d7f, 0x9e729047, 0x4f78d1e6, - 0xff773f30, 0xc31dfcac, 0xa9abfd4f, 0xf3cad3bc, 0x8ff76923, 0xf0073b7f, - 0x3f036e75, 0xa4ce749f, 0x6cf3bf23, 0x85bcadad, 0xfd8ef0e0, 0xde76511f, - 0xf1dc329d, 0xfd6355d6, 0x057e726a, 0xdea072eb, 0x876fd30a, 0x5c3e1e3a, - 0xfa432df4, 0x695d66eb, 0xe846afd8, 0x2315ddcc, 0x79209b8f, 0xff84ac6b, - 0x5f28219e, 0xed02fd95, 0xfefa2a31, 0xe72b228c, 0x7ce38fcb, 0xa65ab6ff, - 0xcf25dbdb, 0xfa9e3e6a, 0x195fc37e, 0xf2b43f3d, 0xb4ffe678, 0x8c02f9ca, - 0xce4894df, 0xdb9d7c70, 0xd635dedb, 0x78997118, 0x8e16bf7e, 0x9e9c6c5b, - 0xa500f1b4, 0xcf01e254, 0x65044da0, 0x7049d5a6, 0x1803e36b, 0x07158d27, - 0x8f2b4ff8, 0x3c7ba61f, 0x9f15d5a2, 0xcef8272f, 0x6c9b7dd0, 0x7bf3a336, - 0x0e9b8a03, 0x60643c62, 0xd90eb059, 0xcb513ea5, 0xc63301a7, 0xba7cb249, - 0xa4dbcc34, 0xa33f0275, 0x6a9781bd, 0xd69d22a5, 0x4f5d21d6, 0xf168e9f0, - 0x412c3a13, 0x54e67141, 0x660266e7, 0x0bfeef39, 0xda82f3c2, 0x1db718b5, - 0x797fbcb4, 0x9f7936f7, 0x84d9bc95, 0xc3c206ed, 0xa63fed84, 0xed84d6fc, - 0x2885eb77, 0x35693efe, 0x878bff50, 0xff250e97, 0xaa39ce38, 0x26dc794e, - 0xfc417bc4, 0xadc710f3, 0x8879f8df, 0xb8a8d6e3, 0xab8af54a, 0x5a77c724, - 0x39f8feb9, 0x9f0169e6, 0xe4a05f3f, 0xfe291b69, 0x9a6a5bb6, 0x40887986, - 0x43ce8eb5, 0x0bdcf386, 0xf08f79f8, 0x86ef98fb, 0xe2af3fe7, 0xc181eef9, - 0xf6df2967, 0x03e79999, 0x6461db3f, 0xf25d2798, 0xefe51376, 0xb1d72cb6, - 0xc364f758, 0x9cf9064c, 0xefcf018e, 0x7ca3fee0, 0x081df653, 0x08fdc24b, - 0xf9b5c3e7, 0x8bae193f, 0xe9723e72, 0x4869e6ce, 0x93cb1927, 0x563fbc04, - 0xeaebeb81, 0xbf506f91, 0xe5f7975e, 0x6f55fa66, 0xb55fa18b, 0xe0d3b57a, - 0x6f52da31, 0x641b5fae, 0x2ab5eafa, 0x78e406e7, 0x6247e637, 0xd633cbec, - 0x34ce713e, 0x738857db, 0x3149adfa, 0xf7ca9ce3, 0x6c490d9e, 0xfc18ccee, - 0x37cc98f0, 0x743dcdba, 0x4da5230e, 0x4a972988, 0x17c94924, 0xc545b08d, - 0x35f2b5c7, 0xd8dd7e06, 0xd0aec47f, 0x3e35ec21, 0x668ac731, 0x9c73e000, - 0xf2719f0a, 0x9533bf0c, 0xe4a27d90, 0xd49a2e15, 0x6c77dbf6, 0x6dcf3f4a, - 0xc4b78fb8, 0x6c53db91, 0x297f0282, 0xc5594bf6, 0x2572f154, 0x1b529e4e, - 0xaffbf010, 0x3f230f14, 0xafb26862, 0x7afd00ce, 0x36f73126, 0xe83c27a8, - 0x9779412c, 0x883ee554, 0xcbfadda1, 0x0fcaf7f2, 0x395efa33, 0x65f5ef9c, - 0x7883bd91, 0x4f0efe8f, 0xfaca0fd1, 0x6bdd6f40, 0xb2cd70e3, 0x7d6f40dd, - 0xcf317c83, 0x58be3fd6, 0xf769708c, 0x81ef1b2d, 0x7fd98d4a, 0xb0feac45, - 0xd9fdd5cf, 0xbc720de7, 0xa4f9bfbf, 0xf5f0bd46, 0xf17de5e2, 0xbc2c44f2, - 0xe5d0a86c, 0x009479e1, 0xe963b8b3, 0x7fb62d9d, 0x8b7edc78, 0x9edc462d, - 0xfebf24dd, 0x49773fe2, 0xe2560f18, 0x507b61cf, 0x9e575793, 0xf909b757, - 0xb49597e8, 0xb7fb235f, 0x64e7e0fb, 0x8fcdf6ff, 0x025779f3, 0xdc7f2279, - 0xbf6f9f25, 0xf7fb95ba, 0xa4fd7322, 0x39a8e018, 0x6841606a, 0x606f8abf, - 0x882116fb, 0x3d5f0bf7, 0x8bea853a, 0x192c09f7, 0xe9e02409, 0x160cefc4, - 0x425e3e30, 0x8f754e91, 0x7d47a275, 0x7972784f, 0xea9eaa92, 0x3e13df55, - 0xaa967660, 0xa46fa07d, 0xd5507daa, 0x96fd5578, 0xe13df55a, 0x457f4143, - 0xd30333d7, 0xd7b3fd55, 0x0faaabdf, 0x13df506b, 0xcbadf8ae, 0xdf0cf5e4, - 0x2f7d4f32, 0x61084877, 0xbca163be, 0x38e40bdd, 0x52e088c5, 0xc4cb38d5, - 0xbbf0470d, 0x57de9b8a, 0x7448dad4, 0x68afbdaa, 0x7d754ed9, 0x46fb89ec, - 0x5e0cf3f1, 0xc675373a, 0xdc5f8ea6, 0xc3035f74, 0x1abed6bf, 0x6afbd5d3, - 0x886e5976, 0x7a9e6b37, 0x6f7c999f, 0x766f168c, 0xbfff7ab7, 0xed19bc69, - 0x0c193c6a, 0xe31d8b3e, 0x44abad80, 0x5cb2defa, 0x4bee4e7d, 0xed93ddc4, - 0xcaeee231, 0xcf376abd, 0x0dffb4a7, 0xd04664f3, 0x173c0634, 0x8536e455, - 0x48e627f3, 0xaf2b5d9c, 0x75e41294, 0x2af29d8e, 0x5ad3bc91, 0xff21df86, - 0x2b708bde, 0xf7588979, 0x05ce6880, 0xbe71c68e, 0x4d0afdea, 0xd240e7f8, - 0xae76f983, 0x51ec0b07, 0x8739507a, 0x78c1e8a2, 0x897928e3, 0x4870a578, - 0x0f44b8a4, 0xc86257e6, 0xbfdb6ff1, 0x7be93ea6, 0xf6dbf38e, 0xe0bf2882, - 0x5047bdfb, 0xefde039e, 0xedd9f5c5, 0x888527a0, 0xd589fc9e, 0xf3d3fc41, - 0x3c38311b, 0x48be7233, 0xe1689fc9, 0x0f7cd62d, 0x87b9a6d9, 0xb73c7eb4, - 0xb9dae63b, 0xdf2c3d5e, 0xd7235143, 0x7a76346b, 0x8fee7acd, 0x6d15bde2, - 0x8d5ff651, 0xe7fd4edd, 0x106a4be8, 0xf70b46ee, 0x8105eaab, 0xa67d78f4, - 0x6e3ef340, 0x71f6a52a, 0x5c6a92f6, 0xacb930f7, 0x2a5e58c1, 0xed443bdd, - 0x5efb1892, 0x6e765582, 0x7896cf2f, 0xddfd2fff, 0x0ee60ad4, 0x9bbe44a5, - 0xd3be7162, 0x3d83c6d7, 0x140ece79, 0x3bf55f8b, 0x9a1fc42a, 0x3f1d0ade, - 0x43e70f63, 0xfaf9fbe8, 0x66e7aecc, 0x109ebee0, 0xdb1e78dd, 0x1d602a75, - 0x57c7829b, 0xa02256f1, 0x8d6cad93, 0x038bea19, 0x18f78a2e, 0x8fb25fc0, - 0xcbddf08f, 0xc7c24cf6, 0xd3219398, 0x789f6858, 0xe3107bca, 0x58b3b9c3, - 0x06ed8a12, 0x7f0530d6, 0x55b0291f, 0x5ab31bce, 0x19abfdfa, 0xe8a52b25, - 0x5ba94073, 0xe2f3a61f, 0xf87579ca, 0x28fc4167, 0x9e47dff7, 0x4338f3f3, - 0xe32f654d, 0x98e5297e, 0xc578ec60, 0xccbbf96c, 0x5ddef587, 0x5a63dfb8, - 0xbddee8ba, 0x5b1c8ac5, 0x9defa3a0, 0xe1f793ef, 0x0f3cadbe, 0xbf5daecc, - 0xce46162e, 0x0cf8c1fd, 0x2cf173f9, 0xb3bbdd3b, 0xbe932db8, 0x815e668b, - 0x6d351be2, 0xbf497b6f, 0x44e0984c, 0x01f3d37f, 0x4b7ef013, 0x039701c4, - 0x952efbea, 0x95efd37b, 0xa77ca7d7, 0x8372f20a, 0x78bbf015, 0x81a1dd6b, - 0x2f7bde30, 0xa18fba31, 0xf240acf0, 0x37168981, 0xcb85edda, 0x05cfba04, - 0xbdd1f40f, 0x6d862314, 0x7e3b8e8b, 0xb78bcb2a, 0xe5a078fe, 0x9c297404, - 0x2a48f952, 0xfda768ec, 0x5dfc54c2, 0x95fdc2a8, 0xa338648f, 0x7b2a9bea, - 0xde11bb07, 0x80cb530b, 0xe760fe4e, 0x85d74cf0, 0xd9bbfcf4, 0x543fca4e, - 0xd20f24d8, 0x9d2d8569, 0x80ae37ee, 0xf400bdad, 0xdfa3fd35, 0x9f2e51eb, - 0x05f7cbb2, 0x5c5cb2e4, 0x77c3b267, 0x2accf89e, 0xaf10339f, 0x0fb68d8d, - 0xe539f4a3, 0xacdbba47, 0xf9586994, 0x3fe53666, 0xfbb4f795, 0xdf9f9cfa, - 0xf0ec9873, 0x57fdc79c, 0xfade81fa, 0x93ddeb1c, 0x1db97f3f, 0xfc52bdc6, - 0x17082197, 0x677e8fe0, 0x4ebfb941, 0x296dc719, 0x3f2762b9, 0x3f717986, - 0xf9e3936e, 0xbb6d9d93, 0xebb7dd71, 0x0e516b42, 0xa9fef9be, 0x28671c64, - 0x3eb8e078, 0xf5d573f8, 0x4570bee4, 0xbf7abee4, 0xf9f0a70b, 0xef2bbf0b, - 0x8bc79b9b, 0x500df7bb, 0x0eed8bc5, 0xbfb86fbe, 0xc0937fd4, 0xcfd9f1ef, - 0x937c564b, 0x9055fef7, 0x05824f7f, 0xe577e844, 0xc00fde4d, 0x66a87f21, - 0x13a270ff, 0xb3cb839f, 0x51e7acc9, 0xb6e4e75c, 0x87efa77f, 0xf2792b27, - 0xb93cea0b, 0xe2a59f0f, 0xf43d23b5, 0xb5f7701d, 0x63796fde, 0x43a95bf0, - 0xfbf0fbc9, 0x837ec3f0, 0xf87e1f7c, 0xec5342bc, 0x7197f0fb, 0x89f120ca, - 0xc52f0fdf, 0xe12fe03a, 0xe907f9ef, 0xc166c1fc, 0xb04c798d, 0xcfef5483, - 0x87ded3c8, 0xf17fefcf, 0xe3df93c9, 0xc91f33ee, 0x1e194adf, 0x5dff1b5f, - 0xcf3c0e82, 0xdeea7803, 0x51377fc0, 0x777fcf7b, 0x05b7e739, 0x4ba085eb, - 0x553bfba0, 0xd6650bed, 0x6776085e, 0x3cec9328, 0x3dc477cd, 0x5c5f6c5e, - 0x041befcc, 0xded34fbb, 0x754fe0a0, 0xf961ec4f, 0xfe1671f7, 0xf237d658, - 0x64f32fbd, 0x590f31f8, 0xaf591692, 0xf9147fa2, 0xe16050b9, 0x1abee9f7, - 0xed463ef9, 0xbb95e7fa, 0x36f3cf09, 0x761c6e08, 0xd067aff1, 0x078053f7, - 0x2f995e95, 0x837e73af, 0x6ff3e740, 0xb2a98f76, 0xeeb845ee, 0xaef6becc, - 0x50587ef6, 0x5f842e6f, 0xc6b1f990, 0x49afe1c8, 0x885f7466, 0xba25ec90, - 0x125dc780, 0xf83b0f94, 0x0de10b39, 0xe627c923, 0xf2937b05, 0xe44e6574, - 0x85058143, 0xcffaa3eb, 0x30fbe1af, 0xf842e7c2, 0x12c98efb, 0xc74cdbf9, - 0xca3b6dfd, 0xd223d01d, 0x4e10dac9, 0xf2b126b7, 0x67bc0731, 0x20f06aea, - 0x342e58cb, 0x2cdcb085, 0x3e7bbbc7, 0xaffc1134, 0x846cbe0b, 0x2a18a27f, - 0xe79af927, 0xee93341b, 0xcaf9e3af, 0x167f328d, 0xaefa06b1, 0xa26b3260, - 0x527598b2, 0xa1eb0779, 0xac5f83d2, 0xe03da364, 0x798cb2a6, 0x6aca9ca9, - 0x0d672ca9, 0x712b7e54, 0xc002625e, 0x51359d35, 0x39e402bd, 0x32890bdd, - 0xf74de319, 0xeecec89a, 0xac1cd37e, 0x0e6af800, 0x38bcb918, 0x577d2560, - 0x08466073, 0x1fddf9e3, 0x7bf85cd9, 0xa7b176a0, 0xbf48e29a, 0xf7f93ab6, - 0xbdd52e34, 0x2bb935dc, 0x78e3f77b, 0x7c7f421f, 0xbaad9e90, 0xafe27ba7, - 0x7a8f907f, 0xe1ade260, 0xe81cf27b, 0xcb6d5fcf, 0xcafe3f26, 0x9446dd40, - 0x5219d5d3, 0x7ab7e23d, 0x95ee8598, 0x05d3cee9, 0x415b2824, 0xe9fde3fe, - 0x05efe06f, 0xff26d940, 0xf901c05e, 0xde10f57e, 0xdab60eaf, 0x951e7f21, - 0x95377e1d, 0x5445fc47, 0xa87bf51e, 0x397f31df, 0x5efdc795, 0x9d1eaf2a, - 0x77c7df4f, 0x839e9fa7, 0xc87427bf, 0x19a4f951, 0xb28fe1f4, 0x44fc2e7c, - 0xfdf4eb08, 0x45aec0c8, 0xd508fdf8, 0xd7d67f41, 0xd19dd2f9, 0x555352ed, - 0x92ea1db8, 0x7008fdfc, 0x629e93d2, 0xea4527a8, 0x118dfdf8, 0xbc199ce3, - 0x57f3065e, 0xfb5220bf, 0x303f7811, 0xc72bd618, 0x2e094ca3, 0x03461f2e, - 0x74e18cbd, 0x7c65df83, 0xea99d5d8, 0x69762310, 0x4e5c13e5, 0xedc0be54, - 0xec67cace, 0x9eeef7f2, 0xef0d2132, 0x89cb511d, 0xf94c45f9, 0xbded13fd, - 0xea2c45a5, 0x83b9983e, 0xe60f2475, 0xd3f756ae, 0x4ce807ca, 0x95aad3bf, - 0x643a1f0b, 0x8d9733fb, 0x97faefc1, 0x1d93b1cf, 0xa76ec976, 0x763f7a73, - 0x0164a475, 0x44fbd5bc, 0x0ab413ca, 0xb5b07640, 0xeab8de7f, 0xced0136e, - 0xd7a7159d, 0xbeb1b8a6, 0xaefc49fa, 0x4ff352e2, 0x233aa4a7, 0xf4ec59f5, - 0xdda007c6, 0xddf56eb9, 0x2ffac0f7, 0xb8c0bd23, 0xfc0d5b97, 0x12939b1e, - 0xded32efd, 0x0b21af4c, 0x763f7bea, 0xa6ff3c33, 0x99bbf5e0, 0xbddbfbfc, - 0x2b41be99, 0xa7deab47, 0x1afd61df, 0x6bf133ef, 0x00dc2fbe, 0x8a7bed7e, - 0x7efbdb5c, 0xa77f0dee, 0x6dead976, 0xcea27243, 0x37d32c15, 0x658279d1, - 0x921e5fab, 0xa5cdf603, 0xe88d96e2, 0x7835ef77, 0xf942ef12, 0x71e06cd5, - 0xec904366, 0x89af4f80, 0x02466f34, 0x0609fbd7, 0x7c249f6e, 0x3d446a68, - 0x1382f603, 0x6bdcafbf, 0xa439f0e6, 0xc112572e, 0xc2c3ebc9, 0x86f1f1ef, - 0xf7b97025, 0xb25eb5e9, 0xd76e7ba7, 0x8082efd3, 0xc4faa07c, 0x6884523b, - 0x226f67bb, 0x8af3de7f, 0xcc52fd48, 0xf1e8c49e, 0x2f1debb5, 0xdcd7b7cf, - 0xc53f1aa3, 0xd653dfc0, 0xe36f9da3, 0x9de51324, 0x496e289e, 0xb2ebfcc3, - 0x207bfe12, 0x8abc3245, 0xa3f1357d, 0xe1a3dba9, 0xeeff289b, 0x26e4ceb0, - 0x557079fa, 0x7dfa38e2, 0xe297a742, 0xe71e73fb, 0x38f269f5, 0xe08e4520, - 0xdcb9e772, 0xf20cd153, 0x28657c39, 0x79e417b7, 0x8afd608f, 0xf510a7a1, - 0x24aab886, 0x33de0030, 0x9f495e3c, 0xd5d719f7, 0x6f34b005, 0xe1036468, - 0xcdcdc2f9, 0xa13df70c, 0x8a176cf9, 0xefe69499, 0xaf6d7c53, 0xd813a641, - 0xfe51998f, 0xa96736d7, 0xd7e60137, 0x391db939, 0x4245ac7d, 0x467a607b, - 0xf5f9d906, 0xcc1cc1a5, 0x308cf70f, 0x3a627c53, 0x9f80258c, 0xc5886c72, - 0xd412fe83, 0xcf58893d, 0xa7fd4c98, 0x86591d8f, 0xc658f87a, 0xb78c74f7, - 0x9e2bc7af, 0x5fc0658e, 0xc21fda0e, 0x8969cf57, 0x963eafbe, 0xf92a74b1, - 0xbd382315, 0x6c78cb1f, 0xd22bf62a, 0xc2cbee05, 0xf289a176, 0x70278fae, - 0x0c5d3f3d, 0x09efc71d, 0xcef819ef, 0x566ff471, 0xc77ec826, 0x622b9018, - 0x5c981fc4, 0x9f8edcd4, 0xde7b15cb, 0xeaea829e, 0xb73ff28e, 0x26f1e963, - 0x2f7aa196, 0x03ae3d9d, 0xccdf32cb, 0xe8731032, 0xf88e3caf, 0x70f55a9e, - 0x01ffd607, 0x88e3cafe, 0x55c992e7, 0x9f37fbf4, 0xa3e5dfdd, 0x7024e93c, - 0x7dc463d4, 0x4b09f622, 0x781af7e2, 0x485f5092, 0xdf7db86b, 0x7b244fb3, - 0x39751582, 0xea6e5c74, 0x33aafe90, 0x9e90d2bb, 0x38f207eb, 0x976715cb, - 0xfdf2ea83, 0xf322ff02, 0x57624541, 0xc561d21a, 0x9e0261be, 0xe1e2bd3b, - 0x56a04a76, 0x3061e7e4, 0xff2694cb, 0xd51678ee, 0x93fceec9, 0xfcf5ebc0, - 0xf3d676ee, 0x23ed237d, 0x2f10cf8c, 0xe30f0f3d, 0xeabe0170, 0xb92f5ef1, - 0xb983c33f, 0x52abf748, 0x87f21ee9, 0xfc24a72c, 0xe3302469, 0xae3e50d2, - 0xe276ca68, 0xef06cdf3, 0x15f71a4c, 0x96e389c1, 0x3c966cef, 0x2a4fd236, - 0x90f41e3b, 0x7ba7eed6, 0x3e32e687, 0xd126dcdf, 0x9aba0663, 0x03fcd2db, - 0xeecd2e81, 0x8ff7c832, 0x4d6bdea9, 0xfa9f74e0, 0x4fba66cb, 0x87ce1976, - 0xee81ab65, 0xab365d95, 0xf1443245, 0x3dd6b2cb, 0x577cafd4, 0xcbc5e533, - 0x2f64ecf3, 0xeb0d634f, 0xdf2d5f28, 0x53e3e457, 0xc9add3b0, 0x65003fcf, - 0xbe399fc5, 0x3efc53d8, 0x0f83f9b5, 0xbb2f91d9, 0xfc53960a, 0x942143e7, - 0xf8bd001a, 0x0ee76650, 0xc92e1ff4, 0x0fd68ef6, 0x0b1dfad1, 0xa2a7335c, - 0xdfd7d149, 0x38e8b660, 0xb03f168a, 0xdef11b1d, 0xa24d45a3, 0xd131ef13, - 0xfe0a23fa, 0x953f78b4, 0xc7db2290, 0x3f706320, 0x20eca69b, 0xfa71933f, - 0xd6017b20, 0x987dc971, 0xd39ab3ee, 0x6279efc4, 0x8a14a13d, 0xb3f06b03, - 0x8cda1f41, 0xd60549f7, 0x02fee819, 0x5c02fe1f, 0x8dfdac52, 0xec4a27ba, - 0xeb2d3f5b, 0x5bcf3ecb, 0x7a775fb9, 0x1b9f28bd, 0xdbcfb751, 0xb3247f97, - 0x26fbe31f, 0xeed27df0, 0xcfd002c7, 0xdf8217e4, 0xafa97287, 0xdfa5e85f, - 0xfed9b883, 0xdffff828, 0xc7a90a29, 0x00008000, 0x00088b1f, 0x00000000, - 0x7dedff00, 0xc554780b, 0x3d9cf0d9, 0xcd8dcd7b, 0x09c246fd, 0xb8094404, - 0x9fb1dc24, 0x4a34021b, 0x414045d0, 0x2dc8d812, 0x088d9242, 0x59b6b696, - 0x5a4062e4, 0x7da5aac1, 0x2c142ea8, 0x11a0d05a, 0x86ec5d43, 0xba8b4508, - 0x8ad45cb1, 0x14178026, 0xb16d0042, 0xfbdfad1f, 0xbb2733be, 0x6a2364e7, - 0xffefefd5, 0x27a3cbff, 0x9cccce73, 0x997ef799, 0x6318c399, 0xb17fc39f, - 0x50dff876, 0x261d8ac6, 0xd8c21b27, 0x4fab569c, 0x8a6c61c9, 0xef74676b, - 0xa79cc624, 0x18564c0d, 0xedfd2e6b, 0xd543262f, 0x8ad79b24, 0xcb7693f7, - 0xcd942f0e, 0x3b58eef1, 0xdaf4b7b4, 0xd5f6c468, 0x512c490f, 0x6724ac62, - 0x618b126f, 0x9b0e576c, 0x7783cae5, 0xd0daefe1, 0x950ed135, 0x6cdb1992, - 0xfb622577, 0x1b32dee7, 0x1ec60f58, 0x87f5e78c, 0xe3db99bd, 0xfd5098b6, - 0x687f5841, 0xd5b23ca8, 0x467f58c0, 0xe8c79c3f, 0xb318a30f, 0xebdfca86, - 0xaf94d048, 0xa9a198bd, 0x68fac85f, 0x0759179e, 0xb38f9e68, 0xdfca6817, - 0xa9ad1b4f, 0xa4529d7f, 0x3fe84f29, 0xa27f5341, 0xbca6b263, 0xeb8ac8d6, - 0x63675e61, 0x8f4b5e8c, 0xd8463cd0, 0xb787040d, 0x478702d3, 0x683b584b, - 0x8576c572, 0xa98d5957, 0x7dec35a3, 0x9c38da0f, 0x819c5d58, 0x4eec630d, - 0xffa899f5, 0x58df0143, 0x7be0d599, 0xdd46a303, 0xb5bc046f, 0x160d941f, - 0x42f32fc0, 0xcec614bb, 0x1a17768b, 0xbe207a0b, 0x7f7e01d8, 0xdfdf8d91, - 0xded1f025, 0xc335e0df, 0x816b5bb8, 0xde85fa26, 0x660c56e3, 0xdd7e1843, - 0x8259b28d, 0x730370f2, 0x17dd7be3, 0x1059cccd, 0x5163071a, 0xde76bdfc, - 0xe64e3abf, 0x8defe68c, 0xaedff7e7, 0xec62e245, 0x5d2b5a9d, 0x82cf0e7f, - 0xc0633e38, 0x691fa0cc, 0x34f8cc74, 0x06f6b7a0, 0xfa016ec9, 0x366c6cac, - 0xed17f8e3, 0x316549cc, 0x5ea7e15d, 0x31a6d78f, 0x5aabfa05, 0xd52ab2dc, - 0x1f6ef401, 0x682bf752, 0xe303555f, 0xb1a91200, 0x965bab0f, 0xbb62d8cb, - 0x6716f442, 0x7f43f981, 0xbff4feef, 0xf0073ccf, 0xd4b3fe3b, 0xfd07e47c, - 0xffb559f3, 0x17e8f4fc, 0x27f77f3c, 0x83f63f7f, 0xd3ff6a2f, 0x65fbdecf, - 0xc6eef3d8, 0x932ebb3f, 0x30746129, 0xace1cccc, 0xe90cb7af, 0x3b3ffa0a, - 0x358f1fea, 0xb2497f43, 0xe01d997b, 0x27cd7edc, 0xc51e0cd9, 0xcc34bf0e, - 0x37e2131d, 0x095ffb7d, 0xb1bc037e, 0xfb338018, 0x15b7cd81, 0x0ddf06e9, - 0x924b63e5, 0x5e906b7d, 0x669ac15d, 0x95b1f718, 0xe06b1c7d, 0x0ec7e53d, - 0x86f7338e, 0x2f3cb1f2, 0x24cbfbc3, 0x2cfb8307, 0x3a446acd, 0x5703899d, - 0x2b2ef868, 0xd31674e0, 0xf9d02dd2, 0x7c61adfb, 0xb6a96b33, 0x96d5ee5c, - 0x61fce387, 0xd899cf1e, 0xbc30fab4, 0xeffcc4fb, 0x047c2f89, 0xce3b8be5, - 0x5376e54e, 0xfac85dc7, 0xbfb4f58c, 0x81fa2d1f, 0x32008e39, 0xb7b2f1c5, - 0x9fcf34ac, 0xf89183e1, 0xf2266f3f, 0x4f82dbe3, 0xd6c4c4cf, 0x6707c049, - 0x6f070e14, 0xd2e1cc8d, 0xed056013, 0x6e2777ab, 0xdfc0b822, 0xb3ee5451, - 0xa4c7cb19, 0xde17b240, 0xfb07265b, 0x28cffbe2, 0x1d630fad, 0x4668e2ef, - 0x53b491ed, 0x10fa7c04, 0x30f3148c, 0xe7801f01, 0x69d946cc, 0xf1f0441b, - 0x29a3e0ea, 0xa8d0fe8f, 0x43af7f29, 0xa2f6be5b, 0xb4c85cb6, 0xdaac8bed, - 0x8e02cbf2, 0xfbdaece3, 0x96d34fdf, 0x1e3a55df, 0x1d8bf2e2, 0xf3c30dca, - 0x259521cc, 0xcfe00e2c, 0x179c66ec, 0xb864f78c, 0xc11e2b1c, 0x3adb78e1, - 0x21cbe7c9, 0x5f9e6afc, 0xecab1cc7, 0xdaf74879, 0x418bf0fb, 0xe82b9a7a, - 0xed3aee67, 0x19dfebf3, 0xbc019e35, 0xe325d84e, 0x207f78fb, 0x4e78881b, - 0x419f738c, 0xc744f03e, 0xc37d420d, 0x46b9ede4, 0xabd9ff78, 0xe3990e6c, - 0x3b21cb81, 0x3938ff1f, 0xe7c011c6, 0x058768fe, 0xd3da2d6e, 0x8fe51527, - 0x37cf5eda, 0x52dc800f, 0x9c7be1fa, 0x99af4867, 0x25d20559, 0x28fa021b, - 0xe4c2c81d, 0xf6878f8c, 0xceb71dcf, 0x3be04772, 0xef955ce0, 0x77c8259c, - 0x35f4e63f, 0x1ec8cda6, 0x352c71c7, 0x9c20b26d, 0x8fc427eb, 0xb999fa03, - 0x5b9df38c, 0x3064ac0a, 0x647b99bf, 0x25cce782, 0x44498f92, 0xf435e72f, - 0xbea0f022, 0x5e71f00f, 0x329a5fc7, 0xfdd12850, 0xecc62683, 0x678ebef0, - 0x1466df25, 0x648d53d9, 0xbb6d542f, 0x337047c2, 0xef1117b2, 0x2a8f816e, - 0xa81e2323, 0x0658fe04, 0x4bd4e7f5, 0x178fae34, 0xa8067c5b, 0x261db55f, - 0xae3fcf08, 0x2824f931, 0x3328dc7f, 0xbeb10fce, 0x7db550be, 0x7c2f2f3b, - 0xf82d96fc, 0xff3c5dbc, 0x2db8fb78, 0xa2b5bef8, 0x9062ef7f, 0x6ddf504b, - 0x3e6b5664, 0x0259b75c, 0x63b7a076, 0x4757f651, 0xe8ed3d21, 0x3e0cf0f3, - 0xc618c524, 0xab59c74f, 0x85d0e109, 0x9f03b69f, 0x2be575c5, 0xa0f1d237, - 0x50b9f4ae, 0x839039aa, 0x9267e372, 0x95d2ab63, 0xa974f54e, 0xc17cedd2, - 0xd9b3d01f, 0x1bca1035, 0x1d38f5f4, 0x1fd635ac, 0xb9e715b9, 0x3bfea642, - 0xb71009e7, 0xdc2d4902, 0x28c8f7d1, 0xdabe5e78, 0x32efe884, 0x33f3aecf, - 0x6ce6fcd1, 0x673274e7, 0xa453e4a9, 0xcfd5f3ae, 0x98bccbb3, 0xa63d956b, - 0xcebafceb, 0x218fd383, 0xf1104876, 0xa2d1be75, 0x9dd1fda0, 0xab5d3b7e, - 0xff411b64, 0x675adbb6, 0x238c0732, 0x2575bb7e, 0x907688c8, 0x179fa8c1, - 0xec5ddfac, 0x2d39be05, 0x4a6f7971, 0xf95874e6, 0x5926ea74, 0x6953f50a, - 0x4073f40e, 0x15e3bbbd, 0x81a56382, 0xc1fa09eb, 0x4e0f4e38, 0xc606bcd8, - 0x856de601, 0x32679fa6, 0xe361c937, 0x8604b4ab, 0x3b41fa69, 0x7c9fbc26, - 0x1c19cfde, 0x9fa85e4f, 0xf1da5daa, 0x9a839954, 0xfb0954f1, 0x0ce7ed48, - 0x9fea078e, 0xf784f1c1, 0x3c769cf3, 0x66a09655, 0x769d553c, 0x9f27e895, - 0xae55d3f7, 0x73f634f8, 0xb64e7d55, 0x2b4f0c31, 0xfb1631af, 0x0f4dd822, - 0xbff973c4, 0x7ecd9b70, 0x557eac32, 0xeca6bc7d, 0x9fb74c69, 0x859fa30c, - 0x3bc807f8, 0x032418b6, 0x314ad3c8, 0xfbb291c4, 0xa3d47881, 0x011faf49, - 0x5b559a0b, 0xa748cc3b, 0xfcfa5d8c, 0x865861f3, 0xcf1c653f, 0x38450394, - 0x1d93469f, 0xf00cfd59, 0x71e017bf, 0xf5f061c6, 0x7fddf986, 0x119b83e9, - 0x4dbb313e, 0x7940f709, 0xab45e3ad, 0xdb5fe302, 0xe5f62a68, 0x67dddea1, - 0x5f261d9d, 0xfdb93ad7, 0xeb019ccd, 0xfba181e4, 0x8f5f8331, 0x0cf17b43, - 0x5e2316b3, 0xd6031ad7, 0x587061c1, 0x3eaa2a0b, 0xc5765c02, 0x5fd744cb, - 0xb54b2e1b, 0x01e15170, 0xf085d9f0, 0x535b58f1, 0xffbb4ed0, 0x6871e39a, - 0x360d15a7, 0x9ca7a44a, 0x9721e912, 0xabaff39f, 0x0d7f2644, 0x08525626, - 0xf441bbf0, 0xfa0ad677, 0xdbf06ae9, 0xd885091c, 0xbc71c6ee, 0xd2f978dd, - 0x9e50c9a1, 0xca993dfc, 0x4d99eeaf, 0xe2600d72, 0x27bc0008, 0xbf258d4f, - 0x3863fa0e, 0x9fa8a9be, 0xe126d481, 0xa937682d, 0xe005f258, 0x308e377d, - 0xf3e70f1d, 0x796d4e49, 0x0cb6b172, 0x335f91fd, 0xafbda5d5, 0xe28759da, - 0x07de9363, 0xb1458c17, 0xfed1cf8c, 0x6632fa11, 0x1f6b5ef0, 0x11d9d718, - 0xebcd0766, 0xeca9dfd2, 0xb6c0c6bd, 0xa7337b62, 0xb28d9ffb, 0x84e796fa, - 0x443dfbd3, 0x030e4db7, 0x37fb6133, 0x9bd43e2c, 0xbb33db7f, 0x77a08b17, - 0xd198ed43, 0x35e34690, 0xdcfeb832, 0xfd8c51d4, 0x067bfcff, 0x8ffa0cb6, - 0xfb76651b, 0x27bfb422, 0x4231f85e, 0xef072dde, 0x2f2dfd0f, 0x256c728b, - 0x3f2148bb, 0x58b7f54d, 0xab2a1f5a, 0x340c967e, 0x34fa4419, 0x9e3d1076, - 0x81e9f7f7, 0xe68d8ce3, 0xa07f3c78, 0x2f6e1ed9, 0x047fa234, 0xd01fc676, - 0xa36b823f, 0xb5fd7fb0, 0x00bf2a76, 0x035e0e7e, 0x4ff90ab5, 0xd3fb6b7b, - 0x075ac5f5, 0x8ed7f75d, 0x5a81eba0, 0xb97bd527, 0x07ae98b6, 0x75745d6b, - 0xf9f025c7, 0xec5db918, 0x920afe79, 0xdbafe073, 0x88e28612, 0x3e20066b, - 0x793e3bcf, 0x0af0b7f2, 0xafd3a8cf, 0xacf5c116, 0x735771d4, 0x3ff9fc98, - 0x3f074fcd, 0x7fc71728, 0xef5d7f39, 0xb73d542f, 0x70179763, 0x87a9e0b4, - 0xfbcc18e2, 0x0a5d7194, 0xadcae1ca, 0x709ce32b, 0x0e3bb305, 0x9f29e1f5, - 0x3e891c5c, 0xfa54134a, 0x2848c670, 0xabe718e7, 0xefb89e8f, 0xbfabe406, - 0x51d9356d, 0x7ec0785f, 0xae7e80b1, 0xf89db86e, 0xbc6dca12, 0x1939ef7c, - 0xfe5a8dcb, 0x87bbf059, 0xa2589452, 0xb74e4cbb, 0xdba44c81, 0x8def2dea, - 0xb0f23a47, 0xfad3d20e, 0x8bfef876, 0xbd4f7a00, 0xbd7e8e5c, 0xffcab9fe, - 0x9eae411e, 0xc9cefb86, 0xab57f871, 0xafaef119, 0x0e34815f, 0x41313c7c, - 0x3670f1f0, 0x156ded1c, 0x4c97cc1e, 0xf73f2cfc, 0xa86d419b, 0x39fcb7bf, - 0xcaebca4e, 0x67ebe7af, 0xa507fa3f, 0x176cfe7b, 0x6bd7af74, 0x200c234a, - 0x7e7e8a15, 0xe20534ad, 0xb9fda346, 0xacf244c9, 0x1f6fc772, 0xd3da35fb, - 0x7d1c5a6f, 0xf69bb415, 0xe505191d, 0x494d3b85, 0x311a7c25, 0x2f084a52, - 0x696ff81e, 0x0b0f087e, 0x5667d99e, 0x77fbf206, 0xb1f08427, 0x99936770, - 0x8f0aec0d, 0x7326faa2, 0xbc044c6b, 0x478db7d4, 0xfb9f96be, 0x7ef119a7, - 0xa58905ea, 0xe78044e6, 0x6e717da6, 0xa3c22701, 0xde2753c0, 0x803df574, - 0x1553a417, 0x57e7fa4f, 0xc67a7027, 0xa23c94fe, 0x00ff27e7, 0xcb78a9f0, - 0x57f9c0e2, 0x1c67793c, 0x6303e3ce, 0xdfeba70d, 0xc2714cac, 0xde4c2b7b, - 0xf95d3b14, 0x96478afd, 0x6fcdbd10, 0xc8c29259, 0x1ba670ee, 0xd33cd046, - 0x37737e71, 0xcdf9a54e, 0xbba26e63, 0x2ec8df8a, 0x353e2bb4, 0x119de2b2, - 0xc175e2f8, 0x066c1f17, 0xfbf3046d, 0xef73c840, 0xcb8fb2eb, 0xca183bcd, - 0xdcaa25c9, 0xfca88b64, 0xe9e395a9, 0xe08304f1, 0x70f2e02b, 0x6f72dd7a, - 0x51f3f110, 0xfd153396, 0xbf030f47, 0x7d21f797, 0x2dcafd0e, 0x7e3952e3, - 0xed4cbdb8, 0xc2290ec0, 0x683f58fb, 0xac3b7f22, 0x273cfb1d, 0xe2c5fef4, - 0x28ee30fd, 0x07f3e409, 0xd36edc29, 0x095fefcf, 0xbf028e3c, 0xafa30b20, - 0xfce6fe30, 0xe73565be, 0x7ddf956f, 0xf9f18a93, 0xff388727, 0x7cccbb60, - 0x9520571a, 0x914d379e, 0x58581e48, 0x6f5f1220, 0xd6be0931, 0x04e9573e, - 0x38c46dc6, 0x60bd2746, 0x7f0409ff, 0x3de787b2, 0xe4c2ed08, 0x17df07a1, - 0x953fb5d7, 0xfe0be76f, 0x3ff9057f, 0x6cffc43a, 0xeefbe723, 0xf097adf5, - 0x3df26957, 0x57e46bf6, 0x82af4fe0, 0xe1726afc, 0xdede3fbc, 0xf456e47c, - 0x3e55eb1b, 0x3d4fcad5, 0xbd3c569f, 0xcf53e88f, 0xefd71fa7, 0xa7c8894b, - 0xb4a5f73b, 0xd3e245e6, 0xaa7e56ef, 0x2754fbf0, 0xd879553f, 0xf2f51c1d, - 0x250481f0, 0xdf843ca2, 0x2bac3621, 0xa774a9fd, 0xdf82dbd2, 0xb942f557, - 0x2a9749d3, 0xa5d275dd, 0xf9fa774a, 0x7fa7e16a, 0x158047fe, 0xb90df9e2, - 0xf7da1863, 0x45b8c153, 0x03054dbc, 0x6b1f34a3, 0x4d5f11a5, 0xfef3e311, - 0xb7184983, 0x79c21241, 0xf4bff54d, 0x0df7be19, 0xdfa2f313, 0x2dcf767b, - 0xab57da0a, 0x990ead92, 0xe68f84e4, 0x5eec8efd, 0xb00f7189, 0x8e51aaa3, - 0xdb47f74c, 0xddb96ed1, 0x32709eea, 0x7f448411, 0x8dcbe489, 0x07b2656b, - 0x2e3c79ad, 0xf2611ae1, 0x9efa5fa1, 0x2be345c1, 0xfd5e1829, 0xf73d1a23, - 0xb93dd1cf, 0x2157c606, 0x8c3f87c6, 0xc2ceddd7, 0x0f5faa7e, 0x46bbce5d, - 0xa1c5440a, 0xe3b12c3f, 0xddb87061, 0xefe32da7, 0xfd4252bf, 0x777eae5e, - 0x5f4df47c, 0x3aba05df, 0x1b787e0e, 0xba7c8d5e, 0xcb3cf4e1, 0xa9e8e1cf, - 0x031fc894, 0x615c9bbc, 0x44bad57e, 0xbddef72e, 0xcce280bb, 0xec0ff785, - 0x2e6de5c1, 0x423cd7c5, 0x2af79e7e, 0xa8af503d, 0x03f9eef6, 0xe8efe445, - 0xe822d3c7, 0xdec22ffc, 0x5a563b3d, 0x9ddf0327, 0x3f641d65, 0xd8dac779, - 0x6f7e08d6, 0x7ea7624d, 0xd430f260, 0x86afea4b, 0x4f13b0f8, 0x329e276b, - 0x7f0aea0e, 0xe5571dfc, 0xc3effca0, 0xe109f915, 0x1d6b62d9, 0xcf308aef, - 0x4adc047b, 0x46667ef6, 0x3f937639, 0xb8f084c7, 0xb1acac69, 0x28947f63, - 0x2b0144e4, 0xec9571c0, 0x246e2ebd, 0xec80e3e2, 0x3d5c01b0, 0xf76673fe, - 0x11c3cbc0, 0xf5fb47fb, 0x0f31c984, 0x67e278e1, 0x3e05e636, 0x45c44578, - 0xf51391e0, 0x44e5741a, 0x225f7dfd, 0x9bbc078f, 0x4eb82768, 0x2534292e, - 0x1af37bc3, 0x6f3183ec, 0xbfea2191, 0xf3d0a89b, 0xad4ed14c, 0xebc95197, - 0xd5ed99b5, 0x23dfe691, 0x6a5f53b9, 0xdefb35f0, 0x0fe8cd3b, 0xabe16fff, - 0xc0d8fef0, 0x8d5f8c18, 0x746e4895, 0xfc4663a5, 0x63fc1e70, 0xfbcf13f4, - 0x7cf2bc79, 0x02c38f09, 0x735db93c, 0x8d764493, 0xf87ae74a, 0xabe0273e, - 0x28a8ffbe, 0x9db913fb, 0x8557c2a4, 0x6abc7eab, 0xd757907d, 0x1bfbcb86, - 0x293f071b, 0x2fc23e61, 0x55d00dd9, 0x8cd5b1b5, 0x5c69e77c, 0x667f426f, - 0x65fbc2ba, 0x29a0d746, 0x6ef37461, 0xdbde91a2, 0x267a3f9c, 0xb585c7d2, - 0x77f38616, 0x871739ce, 0x8315f37a, 0xc8d1b5e3, 0xe4caaf7f, 0xc707778f, - 0xafdad6bf, 0xef0c6b1f, 0x39c68737, 0x84d0b2b9, 0x654669ea, 0x8c352993, - 0x4c4dde8e, 0xfdeae7a0, 0xf2854a8c, 0x1a3ef062, 0x16e7f787, 0xd5e49bca, - 0xc344c707, 0xf13519f3, 0xc02afe9c, 0x8e72a6f0, 0xbea68f26, 0x5347cf47, - 0xe535a24a, 0x3dad45d9, 0x96252e11, 0x044762c0, 0xa926f4fa, 0xf535f9f4, - 0x37e81382, 0x5ffedd02, 0xab1617a7, 0x9355a17a, 0xa92ebecf, 0x8d485e8b, - 0x2d1617a4, 0x0f115253, 0xd165be6a, 0x2252e34b, 0xb5c385e9, 0x1472df3c, - 0xcf5e19e4, 0x70bd014e, 0x985e9875, 0xd13a2362, 0xba482bb7, 0xf1505e8c, - 0x99cb1df4, 0x2217a8c3, 0x24f8f5f0, 0xd9b85ead, 0xe17a4e5f, 0x533229e6, - 0x497df3c2, 0x56eefec2, 0x4ca6142f, 0x11c9b2a7, 0x106e811d, 0x3a17189e, - 0xf8eef22a, 0x3f0fd41e, 0xbc13b24e, 0x3ba27af4, 0x39799e39, 0x04bffe39, - 0x2f8e555f, 0xbd912a9a, 0x18ee95d7, 0xe9a2efd1, 0x16ade512, 0x7c72e1ed, - 0xf1c81951, 0xae45d61c, 0x0eae50ba, 0xbcab9709, 0xeb9bb57d, 0xce634f01, - 0xf9e14b2f, 0x0e4cebad, 0x35bfd42b, 0x85876724, 0x271fd9cb, 0x2b672375, - 0xe0bd9cb8, 0x45f1e82f, 0x4263cb71, 0xcafc82be, 0x8ba04475, 0x9ad1a569, - 0x06270375, 0x19ef29ff, 0x64578fe4, 0x27bc878a, 0xc1c1fdf4, 0xf6821a7f, - 0x0f1c61ff, 0x49b7efe0, 0x9f80ef5c, 0xe058fd71, 0xdc39a2fb, 0x2edaae5e, - 0x1baafc13, 0x6f57bf38, 0x3d0e2893, 0x3333ff3e, 0xf0f6ede5, 0x971a86b8, - 0xf0bff156, 0x9955d695, 0xc4937cf8, 0xfc0acce3, 0xcd87cb0b, 0xbf242c73, - 0xad06fe64, 0xe96250ff, 0x4aed8fd8, 0x3639277e, 0xec8bfc91, 0x7e89556f, - 0x3ed36e16, 0x16ac72af, 0xe48057fe, 0xf6bd5576, 0x5fc15ef9, 0xde40e573, - 0x7bcf9833, 0xd244764d, 0x4ebd6a67, 0x9bfc5478, 0x780168f0, 0xf0eaf90c, - 0x44dfddb8, 0x0baf9379, 0x5ffcfd07, 0x3e46e554, 0xf6fc821b, 0x7249c19e, - 0xcf32fbc3, 0xdf59ce3b, 0xfe3c3537, 0x8ba0bafc, 0x55ee0c57, 0x9aaf58e9, - 0x6fe73fe7, 0xca1a8704, 0x306cf5a5, 0x37f36efa, 0xa76bf568, 0x48506f3e, - 0xecd6975f, 0x43cb6e94, 0x5abcf3b8, 0xf8fd6f85, 0xb65e780c, 0xd437f414, - 0x716f9d9f, 0xc5a8fc63, 0x517241d6, 0x05cfcfa5, 0xe053fcbf, 0xc74644e3, - 0x8d3bd258, 0x2ef89d92, 0x087ae360, 0x728362f0, 0x8fbfc8f3, 0x5bb07817, - 0xde392f88, 0xe427803c, 0x517ef1db, 0xddf6e7ae, 0xee39ff0c, 0x4c9bfbff, - 0x91a2aed8, 0xa0236baf, 0x8c3be986, 0x84a61447, 0x1b4f73e1, 0x92adefa7, - 0xe0f86e83, 0xe7c197df, 0xdaa8f065, 0x9f165f23, 0x4f3e5c2a, 0xc0827e12, - 0x582d8b6b, 0xfc798052, 0x3363923d, 0x53c7f656, 0xbae4e15c, 0xd8df843e, - 0x3d578e64, 0x80dfa3dd, 0xf2d4a6eb, 0xfa201c24, 0x7636c5f4, 0x6f6f7d42, - 0xcb855f6e, 0xa3be351d, 0xbe6abf5e, 0x1482c3cc, 0x66f352af, 0x83f76523, - 0x7257a889, 0xa44f5a25, 0x4660cfe6, 0x40dfd7c4, 0xbe9313ff, 0x66967fa0, - 0xecedebe7, 0xe13b7dea, 0x6e5136e9, 0xb4761ace, 0xa17be014, 0xbae0764e, - 0xca0c5bb4, 0x9e506b91, 0xe43131ac, 0x4d070b8f, 0xa3df2e4e, 0xbf949f49, - 0xfa84c272, 0x82731cb0, 0x09ffc798, 0xc4271bd7, 0x3d02de78, 0x2898c4ec, - 0x093a1fab, 0xd1c53fde, 0x9cf30e34, 0xacb48753, 0xe4ee38c4, 0x2391fb22, - 0x32d5cf88, 0xaf1e7c43, 0xeb3f222b, 0xe2243bce, 0x6f0037af, 0x94ea7ed8, - 0xe047239c, 0xc97565bd, 0x75295314, 0x0d3cdf26, 0x6507a5ca, 0x66f50287, - 0x831b18df, 0xfd09d7f1, 0x830ee665, 0xae0b194f, 0x6957f8c4, 0x71531dcd, - 0xe7a015dc, 0xe15d1f30, 0x8a97196f, 0xb5128de5, 0xe6dd78f7, 0xe09d2054, - 0x21e67386, 0x5079fef0, 0xd9eec10f, 0xb679ebc8, 0x754c0e48, 0x27aff3cd, - 0x8b6f3879, 0x598970c4, 0x2b58ec10, 0x8567d7ef, 0xa11b837e, 0x63e7943d, - 0x4b77ec7b, 0x90d3cdfc, 0xd49c618f, 0xfdb2c47e, 0x41e72f28, 0x82cc783b, - 0xfea0ee5b, 0xb128df6e, 0x62afe834, 0x47cfce44, 0x4d077f60, 0xb47e7c0e, - 0x671457e9, 0x4bef099f, 0xcb67fe87, 0x9d68e3ad, 0x3b258fd7, 0xb92abbad, - 0x5677f099, 0x9b4b19f0, 0x47baf64a, 0x6f3daa62, 0x3edb8f0c, 0xe89bdc96, - 0x65d2de78, 0xad5e70ab, 0x031ce4de, 0x5a39d5d1, 0xe0127897, 0xf43b06ed, - 0x83c79984, 0xcc27bd9b, 0xb37261ad, 0xf10fb939, 0x42c69ce5, 0x3aea2f92, - 0x6e32f70a, 0xb4adb467, 0x36987ad1, 0xef1b3d93, 0xd0b4af37, 0x5c1df6fd, - 0xb567b4bf, 0xdc7e83be, 0xcc4d1b07, 0xbe5c630b, 0x88c3cfb1, 0x9bb60fc7, - 0xdfe4de88, 0xcd8e4898, 0x5be3c1df, 0xbf791bcd, 0x72e36c1f, 0x5337e8ad, - 0x9ebca3c7, 0x42c9f20f, 0xafcad3f3, 0x1e02ca79, 0x89b75d47, 0x9557cbf4, - 0x53e45d53, 0x5f1455cf, 0x7aef4eec, 0x77aa8c58, 0x5ebe31f2, 0x7335955e, - 0x196fd203, 0x03068c4f, 0x087d3fbb, 0x2c6569f5, 0x46d53bc3, 0xa712c3fb, - 0x96c7ca07, 0x8a7e77fa, 0x6a515ff4, 0xde1e2073, 0xbf23f847, 0x78a44dac, - 0x395f3cea, 0xab3e79c1, 0xdfcf3821, 0x356fa5a0, 0x2ddd386e, 0x9eb86733, - 0xce6688aa, 0x7f477ab0, 0xef0a7402, 0xf928d599, 0xdb96126c, 0x42192ff6, - 0x6b8d3b65, 0x6bfbd0a9, 0x8f8e8963, 0x4adcf0fe, 0x7799d3a4, 0x6eed0c4b, - 0x42af75e6, 0x41bd57bd, 0xd6bd7052, 0xfb79bbfc, 0xc71ed0f9, 0x9c57f47d, - 0x15ae809e, 0x8deafba4, 0xfd53f7eb, 0xfd82922d, 0x4e54dd1f, 0x57854276, - 0x4b7cf466, 0xa001f91b, 0xd30f2897, 0x905395ec, 0x5857abee, 0x57d798ec, - 0xc7a547e9, 0x661f9136, 0xc9a0c756, 0xb2516ed0, 0xe50e9112, 0xdea75269, - 0x78f17a44, 0xedb57d39, 0x25903930, 0x7c8f4f2e, 0x6f4a825d, 0x90dbd232, - 0x6f35bd10, 0xfd23322c, 0xebe3e07d, 0x5e908a11, 0x571f1e91, 0x262c2ae3, - 0xe9523edc, 0x07e80ab1, 0xe8e5f4e5, 0xd3fa3bb1, 0x02f81dd3, 0xcee47eb4, - 0x771a3695, 0x37ddaad1, 0xc47ce52f, 0xab459c70, 0x8179487e, 0xff1e4679, - 0xeb88e156, 0xd24f30da, 0x2e0f1c65, 0x997fa733, 0xf1c6e8f1, 0x10d8e48b, - 0x96e803fd, 0x01bac59b, 0xe5039443, 0x5698c4d3, 0x31e304a3, 0x51187525, - 0xe14f0f3f, 0xc23979fa, 0x3325eb0a, 0x67281f5a, 0xacee081a, 0xa3d7c297, - 0x876476e6, 0xa67b63c7, 0xb06efea8, 0x189fde27, 0x5851e50d, 0xff404db6, - 0x5745a26e, 0x60a061ee, 0xbc516313, 0x5eca2a9c, 0x4c9d0328, 0x479f54cc, - 0xd12f72f3, 0xebcd1bde, 0xc79f500f, 0xead5f2f0, 0x7f5e18f3, 0x99e7a334, - 0x7013b129, 0x14cf573d, 0x237c66bb, 0xfd0d4951, 0x62d957fa, 0x6eb489a8, - 0x9a8a6fa7, 0xaf146787, 0xf4fff976, 0x5cb5e606, 0xf90098d6, 0xe9d34e07, - 0x867b30d6, 0x13ca7589, 0xa4b23d04, 0xae0bb238, 0x2f01bfc7, 0x26818c13, - 0x06b06f6c, 0xb0573f08, 0xfbf7f615, 0xf65222e3, 0xdd05e7e0, 0x56a86bfb, - 0x6ff30fde, 0x4b632725, 0xc524ae81, 0xe590f94e, 0x46db994b, 0xed4b94eb, - 0xcc49bf68, 0xaf9cf869, 0xfbe17657, 0xefa8f1d5, 0x802e32ef, 0x7c2131b4, - 0x1fa91b5c, 0x07675c75, 0xb798bc5b, 0xfd618ef4, 0x74e0c26b, 0xf08ae916, - 0xe22264b4, 0x098daced, 0xac728bbc, 0x8447fcfa, 0xeaf1b3d7, 0xd64e5173, - 0x95d74f3d, 0xa4febc4d, 0x78272b94, 0x64b3bde1, 0x6814a4e7, 0xd0c73163, - 0x28baeaba, 0xbee5debe, 0xed17b764, 0x5a73a023, 0x32cde497, 0x76317f93, - 0x5f0ce488, 0xd043315f, 0xb114b1f5, 0xaeb2d94e, 0x0ded05a6, 0x4196c3f0, - 0x0ba5cf7d, 0x4c4f8c66, 0x9199b7f4, 0x401baaee, 0xcb15e26e, 0x68dd5798, - 0xf75a4676, 0x56452a76, 0xf59a17e3, 0xfab2fbc0, 0xb9424cad, 0xafcb873c, - 0xc7e3bb45, 0x39517961, 0xbd6ff7b7, 0x0438e766, 0x69ab9941, 0xb1675e25, - 0x8a687dd6, 0x74517ea3, 0x4edc25fa, 0xd449ab2e, 0x03ad6794, 0x75c20e6c, - 0xfef5da99, 0xa7b9e44c, 0xe30fd0b3, 0xde04d38d, 0xa5ada7a7, 0xb774f7bc, - 0x44e73d76, 0x026332ff, 0x2246bb8e, 0xb8e6093d, 0xf066ed82, 0x6c35c219, - 0x7dc0385d, 0x67d0a35c, 0x97ce5c95, 0xb4a97f0a, 0xdd17af82, 0xc2666597, - 0x7f71f2df, 0x84d8fd6a, 0xa3f71421, 0x7f1efef5, 0xcfeb098b, 0x137e0258, - 0x4ec97bf7, 0xda0ea598, 0x86e60ceb, 0xe3c61b8d, 0xe755fa45, 0x3ee50d35, - 0xf5edc3ae, 0x10ed09be, 0x5d668f98, 0x6d0a8ce9, 0x5b46acb9, 0xf733afd6, - 0x3b3908a5, 0x7e400d80, 0x19229adb, 0xf944ff89, 0x5791d674, 0xefae0a03, - 0x194b6d74, 0x0747eb4a, 0x295ca1a1, 0xf9dca9bb, 0xe6a81cdc, 0xc78c07fb, - 0x25cf895b, 0x26e5dfe2, 0xe310bda7, 0x0fdc5529, 0x35cf819e, 0x7d7806eb, - 0xcb5dcb2a, 0xfee14d7f, 0x6b9b72da, 0xc12dc531, 0xc13cc54f, 0x98d3a358, - 0x307c4790, 0x7b3c922d, 0xabffd05b, 0x8c15b40c, 0x25121fab, 0xe4dfa5e0, - 0xcf8c3e1e, 0xb963fbf5, 0xfd53e317, 0x0aef000a, 0x779e05ca, 0xaef2209d, - 0xb33e8037, 0x5c9fb5c1, 0xc7f48d3f, 0x176e66d5, 0x2aac7c8b, 0x6b8f9c4f, - 0x7a13b1f3, 0xe50cf81e, 0xd61b0dce, 0xdb99ff92, 0x1ebf99c7, 0x8d9f77c6, - 0xddbeffbf, 0xcea98fdc, 0x35f24fdb, 0xf4f229d5, 0x36ce4269, 0xe7559c82, - 0x454df80f, 0x64fe87b9, 0x37bd1e49, 0x87bd73bd, 0x14a4e493, 0x1cf86318, - 0x78aa57e4, 0x0a599def, 0x41652bc1, 0xcef384bd, 0x6865de62, 0x6819ff37, - 0xd7abef0a, 0x533ebdaf, 0x56ebf491, 0x541d2067, 0xf58ab5a5, 0xdfcf5faa, - 0xe7fe82fc, 0xf7d41ca2, 0xebe7d30f, 0xec4ced04, 0xf144b847, 0xde2e3540, - 0xad917e9d, 0x30dc8d06, 0xf234a3d9, 0xad7f4265, 0xd0e899bc, 0x471b99ca, - 0x9f3cd1f4, 0x79a01ce4, 0x40b8b93e, 0x1aea9e53, 0xcb7fa9ad, 0xd94d22b4, - 0xa6bd7692, 0x49b94dbe, 0x7fee8e53, 0xac7ea6ab, 0x73cd36e3, 0x4ecf4bcb, - 0x662e0093, 0x0dd5b7ab, 0xde03a870, 0xd2109118, 0xace2031b, 0xaa287eb4, - 0x6c7e46c0, 0x004b60dd, 0x832ea4e9, 0xbcb0d3ef, 0x002d24b4, 0x6c7b58fd, - 0xf5c216b7, 0x0c6f92f7, 0x62ac73c6, 0x7755f61d, 0xf95e8d33, 0x2be70665, - 0xaa657af5, 0x5c1a687b, 0x9929b6f3, 0xf068048c, 0x358fc42a, 0x6bbb718a, - 0x7437df17, 0x91cfea35, 0x64967ea1, 0xc54a0e15, 0xaf3b7776, 0x91b3bf23, - 0xbd42fbd9, 0x91bf62cd, 0xda999777, 0x1ab635e5, 0xfdfc619c, 0x0f2e5487, - 0xb98d721e, 0x32f8898e, 0x0deac3ea, 0xf7e8cdc7, 0x689bfb57, 0xd720e1dd, - 0x16f7da71, 0x9af42fba, 0xd70a23b1, 0x1f553d3d, 0xc2e23d79, 0x6bcd3354, - 0x65e390bf, 0x7f61644b, 0x2aa4f8f3, 0x7676cb97, 0x1b8c6404, 0x93e36954, - 0xf20d397a, 0xded76359, 0x7140223a, 0x11d3900d, 0x0f5545fd, 0x3cd6dc80, - 0x3af6859f, 0x7943275f, 0x9ae39023, 0x4553d3e7, 0xcb006b3c, 0x6fc275c3, - 0xe7110cb8, 0x1e0cdbf7, 0x5dc37ebf, 0x087f7044, 0xc21216e3, 0x0e2f0f53, - 0x69c1cbc7, 0x15bf9a87, 0x7bd7d2f8, 0x6be3832a, 0x3a723747, 0xceedca90, - 0x1f3052cd, 0x15c7a885, 0x033af445, 0x2014a5d7, 0x0ab6fe1e, 0x67b2a8fd, - 0xf4fa8625, 0xd12f4daf, 0xae33263a, 0xa438c24f, 0x6954bf58, 0x7fa19652, - 0x40e0f400, 0x31baa6fb, 0xaaafe340, 0xfbc2682f, 0xce3c8d55, 0xf1e069e2, - 0x4ad66acb, 0x6ee6dd7e, 0x2a6f75c6, 0x5207efa7, 0xc7bf1a15, 0xbd44ef0d, - 0xf9f160de, 0x2b7fc424, 0x76ca57c5, 0x941d6c4b, 0x4eb6af37, 0x3d2f648b, - 0xe2fde02f, 0xf5c3336a, 0x1ed095e6, 0x6b3fb1e7, 0x3be319bf, 0xca253b65, - 0x5bea7867, 0xd6be62a6, 0xd0c4d8b3, 0x77c7508e, 0x7e482b26, 0x84739be4, - 0xc787391f, 0xcc5cde2d, 0xee790fed, 0x9d57147b, 0xc8fc255e, 0x0e281739, - 0xf08566f4, 0xb8f2e723, 0xd43bf4c7, 0x8e968ebc, 0xd3d53a55, 0xf56e9e9f, - 0xe955faf4, 0xa76a4773, 0xf508319d, 0x1c7be03a, 0x1fdef1fa, 0x4c27ca32, - 0x426cd4bb, 0x2af7bf3f, 0x281ee3bb, 0x2b7d940f, 0x9ace5e31, 0x95c1f3f9, - 0x5f2e249b, 0x3e715b94, 0x86667599, 0x020239fb, 0x53c4014f, 0x43a94e32, - 0x357e468a, 0x1ca37b06, 0x0175c1ca, 0xc1a7c700, 0xf949dfcf, 0x065f2e25, - 0x69b6973e, 0xd6bd184d, 0xcaa2b908, 0xe66601bd, 0x017189de, 0xc6067d63, - 0xf8987717, 0xd16c963e, 0x1d3edf5f, 0xb5c127e3, 0x65ffbc4d, 0x7fcb5571, - 0x94fe10c9, 0x75c11673, 0x5da3c8a2, 0x8a5034bf, 0x744ec8f3, 0x6f315307, - 0x12a47d99, 0xef5d5af5, 0x1fd0f397, 0xabc3d751, 0x91e6f471, 0x13bc6c1f, - 0x32bb6be6, 0xdb69f08a, 0xf48edeb3, 0x243beb6b, 0x57de5235, 0x2a2e7abd, - 0x53fc0dcc, 0x5d37b17d, 0xbda4f2d5, 0x6dfd68a7, 0x78dcffb5, 0x698b8fe2, - 0xf76d5f74, 0x81ee3127, 0xf32cff62, 0x065e9127, 0x911c6cb9, 0xc2a7aa1f, - 0x68e75d41, 0xf085bbeb, 0x3c1de775, 0x7ad8c1bf, 0x654667ea, 0xfd0e548b, - 0x9a7262dc, 0x47de0062, 0x709b4c7a, 0xd5d71732, 0xc1c1b8f3, 0xa5c52b5a, - 0x53b5ad5e, 0x469b5839, 0x156bd7e5, 0xec915eba, 0x34e104fa, 0xbe9ac5f5, - 0xace6b708, 0xa7985d87, 0x44d07b3c, 0xaecc60f0, 0xc17de7d9, 0xea3c532f, - 0x5f5f0342, 0xe67f8ea2, 0x4ee60cc5, 0x8a6371e4, 0x0bfd2c57, 0xc54739c9, - 0xf7e8f1b9, 0x5b6cae0c, 0xd2cf6585, 0xee9d694f, 0x282fa03b, 0xe3c8d1ef, - 0x2d8d55a7, 0xf4b9ceb4, 0xb3f50262, 0x1e31d0c3, 0x82fbccf9, 0xde3beb44, - 0x4e673c69, 0xd288fae5, 0x7c451b3a, 0x3c5a4879, 0x1fe3c1c1, 0xe5f8e06c, - 0x8245d579, 0xfaae9a1e, 0xc3e21c47, 0xf5a154ba, 0x6407d522, 0x19acb38a, - 0x8f6711d3, 0x6e317720, 0xde93eb8d, 0xf494eb12, 0xbd99a7cf, 0xc07d717d, - 0xfde44334, 0x50b48ecf, 0x75d71f7e, 0xc7f53297, 0x3f83d7f7, 0xca88eb43, - 0x8ca745fc, 0x6ef9ad78, 0x196acff2, 0xfdf0c1fd, 0x320fe806, 0x34bdfbcd, - 0xae564b7e, 0x85d6ef26, 0x98335bfe, 0xaeaa7802, 0x20173003, 0xd7455f9d, - 0x2af7ddf6, 0xa8d637c8, 0x2f51878e, 0xf2067eb0, 0x5abcaa27, 0xe84b273b, - 0xee0cacad, 0x89a7173f, 0x2fc2b2fd, 0x4267ff02, 0xe27ff71a, 0x5f8d32f6, - 0x7e4fbfa4, 0xc7ec5591, 0x7978001e, 0xafb8c23a, 0xc2e318cc, 0x1d6cd976, - 0xfa0337d1, 0xcfd2ba46, 0x1f1a4673, 0xd3cfca97, 0x28f39f91, 0xacfc4ece, - 0x464877ef, 0xcfb40ce1, 0x5fb37756, 0xefc12aeb, 0xc1181b55, 0x8121b3cb, - 0x6d8674e0, 0x7a018d70, 0xd8e3033c, 0xd678f40c, 0x878e8ae5, 0xaedd67f6, - 0x109884e8, 0x886f57ff, 0x73ab76a2, 0x872c4a6f, 0xf7a08d72, 0x2b22c6f6, - 0x06e679c2, 0xfbea77ce, 0x4f4c09de, 0x6a1a3e44, 0xde6330ea, 0x2dbfa7ae, - 0xa1bbed0e, 0x222727bb, 0x4e3775ff, 0x779f3a77, 0xb445d2d5, 0xb87f155e, - 0xd0a1627e, 0x3a7b9e63, 0xd57ca11e, 0xdbf44652, 0xd5afebb4, 0xfeedbfc8, - 0x9e6bca68, 0x7a4d13d9, 0x3cd3ecf0, 0xd4c679af, 0xaa60eb4a, 0xf476cb77, - 0x7c2f3d07, 0x9ff230fc, 0xa1459767, 0xdeffbd78, 0xb6aeb873, 0xad1d7fd2, - 0xfedca8c3, 0xd541f2dd, 0xfec8bbd2, 0xd71fcb51, 0x37285d5a, 0x2e5c8ddb, - 0x867c6c2c, 0x9785d9ec, 0xfcc20c2e, 0xff3d99ef, 0x98e50c3d, 0x86178fe7, - 0xe7ec3ed1, 0xe7c30c2f, 0x6ba2e79e, 0xef25d922, 0x8e38f066, 0x0e731faa, - 0x9ef13519, 0x73fe8209, 0xc62bac56, 0xb6864d73, 0xaf84714c, 0xd7da1b1b, - 0x8617fb40, 0x389b1e1e, 0x8addac37, 0x392fdf20, 0xf46c65a4, 0x747a309c, - 0xb8d49866, 0xd38ad7d1, 0xa11fb130, 0x34132e33, 0xd5843ed0, 0x6f3f2341, - 0xa1f242a0, 0x8a7600ff, 0x4bd91dbe, 0xe44f6f67, 0x5d1832e7, 0x1d220613, - 0xf697dedc, 0x75af3387, 0x3d986e5f, 0xa0683d34, 0xfcd3ddf5, 0xefd90096, - 0xefad2341, 0x99a4ed56, 0xcd883ee7, 0x5dc42291, 0x0e3ebffa, 0xfe3eb6e5, - 0x6ec6b3d2, 0x2fef0898, 0x08ecc15d, 0x063c7d3f, 0xfb9db17e, 0xf8d75992, - 0xd07c128c, 0x5c95ed8a, 0xa7c71d83, 0xb78899da, 0x3efc0886, 0xb3f39d2d, - 0x822b47ca, 0x8ac7c206, 0x2e6b18e0, 0xe789275c, 0x7136a00d, 0xff0ae8df, - 0x1f18ade4, 0x96e97158, 0x9ef081e8, 0x626e8715, 0xdbbf20f7, 0x62fb58c7, - 0xb7df4bbb, 0xd10bcd4e, 0x4a7dfe89, 0x2127d73a, 0x7eb2207b, 0xfbfc178b, - 0xd8b9e95d, 0x3d6cfff4, 0x52757e07, 0xabf250fa, 0x07b8f067, 0xfaf5abf7, - 0x6abb9541, 0x7e04e3bf, 0x53ddcabb, 0xff80bf64, 0x5c77724b, 0x7af542ba, - 0x922527fa, 0x4a687c5f, 0xb5d312a2, 0x87463eff, 0x6baf2121, 0xe69daaff, - 0x59f73af1, 0xf2717fd1, 0x8a6796fc, 0x90a493e4, 0x4971e75d, 0xa9649f7c, - 0xd4f587c9, 0xf0a70571, 0xa754e9b8, 0xaa86f289, 0x87daa7fd, 0x3c1dcf9d, - 0x8bdaa8af, 0x74185daa, 0x94ec38f1, 0x15f9fc21, 0x106beec9, 0xf588ef5e, - 0xf247432d, 0xf6b98cfb, 0xcb747fa1, 0x7e2312cd, 0x4aa2f617, 0x527b7a9f, - 0x1ddf6f5d, 0xba0a371e, 0x5b2bf954, 0x9eaa17c7, 0xba7a11aa, 0x2274f51a, - 0x34cfe9ea, 0x5fbeb776, 0xf4aed3d0, 0x08c76c64, 0x1b0e43be, 0xeefc915d, - 0x375fa213, 0x3dae0fe2, 0xe2162f83, 0x7058b378, 0xdd8bfa19, 0xb0974fe9, - 0x5e7bba63, 0x5f9fc693, 0x08d78f8e, 0x7c577ffc, 0x9c3feabc, 0xbeed3b8f, - 0xba23ce6e, 0x7ef0a332, 0xb928dba4, 0x7c885826, 0xc51367f7, 0x4af5f5c9, - 0xff063e85, 0xfbbf4355, 0xf406ccb2, 0xdc153c77, 0x578bafff, 0xe4bf235e, - 0xd5d69925, 0x0eff042c, 0x1705b3ed, 0x44ad74ed, 0x33ae183b, 0xfe50b5b6, - 0x76854660, 0x831875fc, 0xe477f6c5, 0x32fc7ad0, 0x44e29636, 0x3b78fe65, - 0x4baf23ee, 0x86f5a7ae, 0xb2b2adde, 0xedfebc35, 0x8f2b7d6a, 0xf74d2d9b, - 0x6b79e72d, 0xab2fbe8d, 0x5af3dbd1, 0xc45a3ffd, 0x03b3ba7d, 0x71b26f9e, - 0x26407279, 0x78c6aefe, 0x998cd5d1, 0x4bd5f5d5, 0xdaa39c79, 0x23f68cbf, - 0x1fe78957, 0x4714831a, 0x5417fca2, 0x9f5fe53d, 0x9cc87c82, 0xd54f7cda, - 0x2724c396, 0x849f79f5, 0x3c8f2e06, 0xf3c8b295, 0x7d68930c, 0xa7d8a363, - 0x223728aa, 0xcc5c61dc, 0x863ee0a7, 0xce3fe413, 0xf325fdd8, 0x17f84e3c, - 0x7fb3cf31, 0xf972a65f, 0x63754f3c, 0x84fd098b, 0xde7be5cb, 0xc38cef49, - 0x97b09c50, 0x7b5fc791, 0xc63b25f9, 0xf5897a97, 0x4757c37e, 0xc77ff5f1, - 0xdf2224e6, 0x9f6978ab, 0xfed9e1c4, 0xd88527e6, 0xa331d86e, 0x3e11d71d, - 0xbfe2e6ff, 0xad32f264, 0x6c7f18d3, 0x25fa3471, 0x4516c7ed, 0x879f3c23, - 0xb9e3e22b, 0xe3118c37, 0x78a1e589, 0x7bd205f2, 0xb2788b77, 0x6c5ef411, - 0x6fa32e28, 0xd72153f7, 0x8adf30ea, 0xe79bb974, 0xddd2ebfd, 0x57f953d7, - 0x13ff69bd, 0xbcc279c3, 0xc63a019e, 0x9800cfb8, 0x9f95e62c, 0x302b628c, - 0xec9753cf, 0xe6f8997e, 0xf9050657, 0x7e53da06, 0x2153bbc8, 0x55a1883d, - 0x020cc3cc, 0x7da563dd, 0x8f944979, 0x2fe04ab9, 0xf452fc1d, 0x5334610f, - 0x403c8f30, 0x450663e4, 0x7ff62331, 0xe6bdc99f, 0x34ffcc4a, 0x88cb1d19, - 0x93891de8, 0x85e6bb62, 0x77cf2724, 0x3521f9ab, 0x7e5dddef, 0x0cf7c248, - 0xf945f4e2, 0x3094e620, 0x81e6ae1f, 0x4a2ecdd8, 0x511f2d4e, 0x7967e743, - 0x9d37d8b2, 0x8b4a29ff, 0xa5719f90, 0x6bef6131, 0xfa6b81f3, 0xfa744d3f, - 0x6b80f355, 0x71e9bfd2, 0xd5efdc2b, 0xfc487b8d, 0xa3f214f9, 0x3a77f9fe, - 0xffb560b7, 0xb3bde902, 0x0e71161d, 0x938f2b45, 0x2f144dfb, 0x58fe0b38, - 0xdd3e9872, 0xddfbc69e, 0xfa222feb, 0x8d8e086f, 0xc487fac6, 0xa687d5fd, - 0xde7b464c, 0xfa3a341b, 0x7fb848d2, 0x0e3410d5, 0x1be4fb45, 0x7a694bc4, - 0xa359f984, 0xf3d23eb8, 0xbfe09c51, 0xe70e0cb8, 0x5fb937a2, 0xf3cc59e5, - 0x1d75761f, 0x73cf0d70, 0x914acfef, 0x6a77f8d4, 0x6ec8fca4, 0xecbd2ebe, - 0x2df68976, 0xc8fcd97f, 0x7fb6c68c, 0x8fa23f2b, 0x219ddf3b, 0x790322f2, - 0xdd23b9dc, 0xa84bf34e, 0xfb885c19, 0x7ef9d49e, 0x901f7083, 0x43e6edf9, - 0xedf9efaf, 0x352fdff6, 0x837cdd02, 0xcb7d97fd, 0x96fc2ffd, 0xf52fbffb, - 0xdb7f85db, 0xcbffdcb7, 0x8fff72df, 0xff07d244, 0xf5ebe6af, 0xfe7d78f9, - 0xb7979f5e, 0x8bd734bc, 0xd695eecf, 0x6ae00476, 0x4d35db8d, 0x8c687902, - 0xbd4562df, 0xe7923259, 0xb58f56af, 0xa14936fa, 0xaf0abe3c, 0x3fdc5991, - 0xf39de7b3, 0x6ce356e2, 0x226c7067, 0x3246bbc6, 0xdacf6ff2, 0x198b1e78, - 0xd798e9ed, 0x37e99a82, 0x67521d81, 0x7d079c8b, 0xf7f0a7af, 0x4b1bd1ba, - 0xc8af0ab2, 0xfed5a64c, 0x59f648ce, 0xdb2f88ad, 0x17c5191b, 0xbf495199, - 0xa4abde89, 0xe3d3fda3, 0x2e3f7e45, 0x689b9cc0, 0x4dce4a5c, 0x928f6e74, - 0x407be383, 0xae1367e4, 0xf18397ef, 0x03b004e4, 0x1eb78f31, 0xa7e479f3, - 0xfa9ea9da, 0xdc99ddbe, 0xc4c07a4f, 0xef305ce8, 0x11dd7c95, 0xbd9156b3, - 0x0ee1e6a6, 0xcb27029a, 0x8dc3ca25, 0x62bff1c1, 0xce6de408, 0x449c4411, - 0x3f296dfb, 0xdfc8eaf8, 0x7bd377f5, 0x86fecd14, 0x6187f466, 0x29ee771c, - 0xb19dfa20, 0x6fed2477, 0x091ae4f0, 0x46fc5dce, 0x43780711, 0x38d431c4, - 0x7a8f9a80, 0xde3fc45b, 0x3f4ab8c1, 0xa1584f3c, 0xc34caceb, 0x5a9e77bf, - 0x159cfe57, 0x203d3f49, 0xf78fb8f1, 0x29f71e15, 0x84fa3b30, 0xccac7faf, - 0x0f2c78e4, 0x1a83bcf0, 0xcc4279c7, 0x7287e0a7, 0x687602c0, 0x6681aac1, - 0xab05ebd4, 0x3af0a2b2, 0xa433e9c8, 0xcfa7bc00, 0xf15069d9, 0xee8e8917, - 0x89f114ca, 0x8f941d03, 0x9797467b, 0xd7c99ddf, 0x7165e41b, 0x64ceeefc, - 0xafb3be54, 0x8b9a3971, 0xcbb1ae3d, 0x6541f291, 0x38e2f7e0, 0xb8f8ebcb, - 0x05977855, 0x4f7c2294, 0x558ebedb, 0xc8afcd78, 0x79b8a229, 0xb455b9e5, - 0x85d2e9bf, 0x1c52d7fd, 0xffa0accc, 0x1b55b330, 0xc5909b4f, 0xa0cfe7e3, - 0xbb708dc1, 0x6ffe48ce, 0xa24675c1, 0x1b32849f, 0x2609a7f9, 0x7960c726, - 0xf283b712, 0xb08a938b, 0x93c4a6cc, 0x407f97fd, 0x179b9f89, 0x5c256f8a, - 0xe11938b7, 0xa8bcb974, 0x22bb271a, 0xa44bf9d9, 0x179aafdf, 0x88783aad, - 0xf3aa7bd6, 0xe6a2e152, 0x8bcbbb37, 0x3c12ebaa, 0xd6689fc5, 0x1d8c7851, - 0x58ae31e3, 0xaccda7b0, 0xcb4b37ee, 0x0b4de509, 0x7ca39f76, 0xf51f9aa9, - 0x3b239cd4, 0xb199da1a, 0x3fa0017d, 0x4364e41d, 0xee9bcf2d, 0x1a7bfb12, - 0xae78fe61, 0xfe601ff6, 0xfcc3f578, 0xb50bfef1, 0xa81ae9fd, 0x6f75d075, - 0x7aba08ed, 0xcf28e7fc, 0x36a642fa, 0x8f99d75f, 0x084d5d93, 0x1d7cb0af, - 0x3af9f595, 0x63c78a39, 0xee303f70, 0xb41cf21f, 0xf42efc92, 0x7f42f797, - 0xee2d6fe0, 0x6aee385e, 0xd18597cc, 0x61d3bb45, 0xdb6c73c3, 0xe61b0e5d, - 0x4e9a0ac9, 0x6a847ed1, 0x15ce9063, 0xa6073ce8, 0x775f1ce1, 0x21b42feb, - 0xd79b2f7c, 0x79fffc6a, 0xd7932fad, 0x32f905ba, 0xf23f2439, 0x26e7065d, - 0xda701ebc, 0x87c986e6, 0x179e2ed5, 0x9bdb9d59, 0x5741eff8, 0x6139f8ef, - 0xe628adfd, 0xeb848a71, 0xf7e16d72, 0x79e2c89f, 0xb98904ac, 0xe4b1c922, - 0xbcb8df9e, 0xef648e4e, 0xf402bfb7, 0xc3d03578, 0x5abdf9ee, 0x71b4ae89, - 0x73c5d5b6, 0xdbb9e17a, 0xac2c37de, 0x69c38f2f, 0x974c6ce2, 0xde2eeb4f, - 0x40d8a336, 0x7bc2e2e7, 0xeb5f51b3, 0xd8cc62e3, 0xb9f5cd91, 0xe4739c53, - 0x582364cd, 0x5bdabc97, 0x173877cc, 0x362f4fea, 0xf3509e90, 0x46c5f96b, - 0x99f40b56, 0xa3e4d4bf, 0xb1b15abc, 0xff0b9e8d, 0x3f3d8570, 0x3bc9e513, - 0x8c76cd07, 0x60e3e9a3, 0x752de28e, 0xa3bda1bd, 0x6d7da252, 0x373fd65d, - 0xf8c38d36, 0xaeb660d9, 0x1bd42c6e, 0xe3b06b9c, 0xe5cbe57a, 0x3d85f2e1, - 0x219f8fa3, 0xa1fda15d, 0x2f5fa38f, 0xb0bd7ef0, 0xbf43ee97, 0x8fd43932, - 0x2f4f4eda, 0xbe94f68f, 0xbf7f2e30, 0x71456fe8, 0xc45ceafe, 0xa1818967, - 0x3c5158de, 0xd61b9ac6, 0x234f595f, 0x7986af5f, 0xbcf0a4bd, 0xe9dfcf1e, - 0x3caa79f3, 0x8cfa682b, 0x083efff6, 0x95f51972, 0xffc78d27, 0x3c285e0b, - 0x34227280, 0x1f9fae4e, 0x37bf534c, 0x7c6788e0, 0xd14fb45e, 0xb8a247bb, - 0x27c97e5b, 0xcca1a37b, 0x7fb4f15c, 0x773073de, 0xef939e39, 0xc50e3129, - 0x971e3afd, 0xc22799d4, 0xd7e4d07c, 0xf5c7ae2a, 0x075305fc, 0xa67e20b7, - 0x9d689a96, 0xa6d7e4de, 0xaae539d1, 0xba982b9e, 0x7c289ee9, 0xf3a25fde, - 0x56bf261a, 0x4f9f063c, 0x88c01ed8, 0xb3889b38, 0x3c193907, 0x7c88d278, - 0xfbb24572, 0x0537c827, 0xa89e4493, 0xa9e3eb94, 0xc62649fe, 0x7e8d46ed, - 0x1bface6c, 0xf3d479c5, 0x7d711204, 0x2f485e42, 0x7d01ec15, 0x57d21b15, - 0x7a9eaeff, 0xe09da7b4, 0x2be83579, 0x24c24f1c, 0x62ef4f9e, 0x77fc08bf, - 0x93ba7fa7, 0xc467a8bb, 0x529983f9, 0xad7d575a, 0x38673c60, 0x9d12e5da, - 0xfd1dd683, 0xcfec26bd, 0xb6ec6ef8, 0x76fd04d7, 0xf1a9aebb, 0xfd13c9bb, - 0x787fe7b9, 0x57f8489e, 0xf548be6a, 0x7b09fac7, 0x215ebd57, 0x7b7fbbfc, - 0xd12a013f, 0x1209fb88, 0x9827ef22, 0xbda12f59, 0xd827eea4, 0x3b856667, - 0xab3d7093, 0x73e44fd8, 0xefb41d91, 0x7aad6fd7, 0x7bce893c, 0xa0cc6dc0, - 0x9f485af7, 0x43fd8157, 0x63ff92f6, 0xe7ad3f1e, 0x1aabb1eb, 0xd496fbb5, - 0x5f616ceb, 0x50f9858f, 0x77ac459e, 0x91ce2f1d, 0xef21c508, 0x21c78632, - 0x59304a3d, 0xe3eb475d, 0x5c4d1779, 0x6438bbb2, 0x75a0eb35, 0x9215d5b3, - 0xb7c3f503, 0x91ec971d, 0xddaf5da5, 0x83cb9327, 0x42496e69, 0x706ad5fb, - 0xf8bad255, 0x6c7ef817, 0x66fa7c3d, 0x413c7971, 0x331e31e4, 0x6c787a73, - 0x5bfb4494, 0xe21c1f70, 0xf817b1f9, 0xf2c7973e, 0x35173ef9, 0x5feea16f, - 0xb79432b9, 0xea6ffda0, 0x1f7517be, 0x780fba8b, 0x00a886d2, 0x99f707da, - 0x1db8d3ea, 0x3c3a25eb, 0xf3d193dc, 0x6f3f0b28, 0xf8ce3f5d, 0x28c3c2ac, - 0xf37f0f87, 0xac88d176, 0x25a67108, 0xaffc2fc2, 0x98fb2eac, 0x30bffb54, - 0xfec6a86b, 0xfedeb2a7, 0x16f2a6ff, 0x6f9f0141, 0x32abde70, 0xe6f8ddbf, - 0xfc72df67, 0x7b247cfa, 0x4b88b976, 0xd9e7e9e9, 0x68bf552c, 0xbac34bbf, - 0xfae43fec, 0x8e524ebb, 0x2f6bb9d2, 0x542573f1, 0xcb175a39, 0xe4215ffb, - 0x547d7aa7, 0x914ceb5c, 0x884f5fe3, 0xe764b3e7, 0x0193a472, 0xc8f1b4db, - 0x78daf581, 0x098dd5e4, 0x40e0f29a, 0xc17ea686, 0xe79ade81, 0x69578343, - 0x237f0f9e, 0xd91e535f, 0x7f534a3a, 0xb46387f4, 0x68755ae7, 0x5ed791e3, - 0x2fb749bc, 0x2bf047d2, 0x6f0dca04, 0xad9d6457, 0xa15997a9, 0x8d56579d, - 0x96bd5e76, 0x2fcee826, 0x78e6fde1, 0x53ebf3b5, 0x025f9da7, 0xbef2d3e6, - 0xd4cd3e7e, 0xecf7a153, 0x61b1f7f5, 0x738a07bb, 0xa99f686d, 0xc1db99fb, - 0x6411786e, 0xffb69fdf, 0x9cd7d696, 0x06eda279, 0x79e6cf3a, 0x0379e199, - 0x5963dbed, 0xa3e3de80, 0x34162873, 0x661ef4c8, 0x1c9b0c0c, 0x9d1afe76, - 0xe9f28f4c, 0x911258a9, 0xf8b69e0b, 0x82fda04a, 0xe106275d, 0x7bf692fe, - 0xfbcb3e78, 0x31f14484, 0x841d6de6, 0x60584bdf, 0xa89dfc8c, 0xbcb8b2d7, - 0x9a3bbd3b, 0xdb49ebd6, 0xbf52669a, 0x3098b7f5, 0xdbd6a69f, 0xa849fc2f, - 0x3d3df7c7, 0x5e77d12e, 0x71e17c70, 0x27bbf54d, 0xfae71fa7, 0x89a3416f, - 0xb059efce, 0x9e3b676d, 0x0de0bd57, 0xe65b9d0b, 0xf48e76d9, 0x3b53d16a, - 0x469ece08, 0xd5a8bd99, 0x8273da57, 0x5db8f1b7, 0xe9154375, 0xff932841, - 0xf91f5d55, 0x9dcbecbc, 0xa9f0bb67, 0x00bcbb3d, 0xfccf85c2, 0x1ee30e2e, - 0xc6b7051f, 0xedbedf91, 0xeee9cf8b, 0xfd702e72, 0x173c2fea, 0x03fc23f8, - 0x2cc5cbe4, 0xdbcab9dd, 0xa9f7c512, 0xf7c2c302, 0xe8e087f9, 0xf1de78e5, - 0x6e7823e9, 0x3fa7e9fd, 0x5bc7047e, 0x8f0baff9, 0xadf498fc, 0xc3728ecd, - 0x3a61c4f3, 0x976d5bf7, 0x40e5cd90, 0xa3bfe3fb, 0xdfdbd2f3, 0xb7b038b4, - 0x641f3df6, 0xefb77d23, 0xe3052cfc, 0x8cf78b5c, 0xe2f078a3, 0xf0be8b67, - 0xb7486b7b, 0xe3e17ebe, 0x3e7375f2, 0xcd5f16b1, 0x38d9cd0d, 0x6f8033ce, - 0x9e75f38c, 0xc55f5cf3, 0xc456cdcf, 0x23dbcef9, 0xe5df8b9f, 0xc986e73c, - 0xed0f7e37, 0x2e7e069e, 0x75cf65cc, 0xbc78043e, 0x6fe04bfa, 0xbe716afb, - 0x9dfc6449, 0x4f003fc1, 0xb9ed6c8e, 0xcc369fce, 0xf8d7f47d, 0xdbb121ac, - 0x5f039d73, 0xb9ea6e02, 0x72ccfffb, 0x3e46ce8e, 0x74f7fa7c, 0xade2368e, - 0x3a73c144, 0x7f46cd3e, 0x075343ee, 0xb1d72b9d, 0xefc762c7, 0x73d82d37, - 0xfda7f894, 0x64b71e59, 0x76fbfce2, 0xe7e3f9d6, 0x8a988b95, 0x3f2c4b67, - 0x1fc05a0f, 0xe2568bcf, 0x1738bee8, 0x7ab1d39a, 0xe777745e, 0xeeca2f44, - 0xf89cf5cd, 0x96d5401e, 0x9fb99abf, 0x3497c21a, 0x7fe9f682, 0x2adbf9e1, - 0xbfc2ec1c, 0x96dbc4eb, 0x7771e7c8, 0xf02f8f9e, 0x73c3f885, 0x35cf3a3c, - 0x5435f287, 0x08b28e96, 0x137da0f2, 0xbdbd2f3f, 0xeea9fd1b, 0xd6caaa0f, - 0x6798a9f1, 0xf2a1fc77, 0xffc6e5e9, 0x3333e155, 0x8bd0d15b, 0x97d3a70a, - 0x75f1cb22, 0xb6bfef82, 0x62ece3fd, 0xf48fdcff, 0x66d0d558, 0x44d9fbe6, - 0xf7cc547e, 0xf4dfd834, 0x6427a4fd, 0xd557e3b2, 0xd71c9337, 0x6eea8bcb, - 0xb39b6df2, 0x7153bac5, 0xa7e9c14e, 0xefb87d63, 0xdddef4ea, 0xf6effd7c, - 0xfa17b336, 0x19edbfdb, 0x721b8f33, 0xe13d41fe, 0xe9ff1b0b, 0x91069b27, - 0xdd66eedc, 0x8f78bd77, 0x3df91fc7, 0x34e7ed9e, 0xade859ef, 0x72efff27, - 0xe8c8fbef, 0xfbfb05bc, 0x3bf7c828, 0x4ffb847e, 0x17ffbc23, 0x176126d9, - 0x22eb13ae, 0x3f03de41, 0x9ee02bbf, 0x3cf5cbd6, 0x9d1999c2, 0xe3be1083, - 0x2725917e, 0xaf979f01, 0x7fa8ec95, 0x4c18af67, 0x9ccf9274, 0x89652744, - 0xfa937bfc, 0xe6cf1cf7, 0x1ab6fc7a, 0xc3fa4313, 0x280cded3, 0xb624eb7f, - 0x3197fb86, 0xe7425313, 0x6ead56d1, 0x0abc2389, 0xef3d533f, 0x3e66a2b6, - 0x39fd07c9, 0xdeac9538, 0x2d6fe78c, 0x2dcfcb58, 0xa38b9fd4, 0xcf5dab97, - 0x85fb5a89, 0x956df672, 0x81cc1cef, 0x07e7377c, 0xd7e456b1, 0x4a68f0ae, - 0xb3ca05be, 0x07a4c80f, 0x2eb0b854, 0xebcbfddf, 0x7f3cf881, 0x973f2fa0, - 0xb152515c, 0x3c1e9cde, 0xdd19282e, 0x597ef1c3, 0x19b87ba2, 0xb19beae5, - 0xb596c7b8, 0x7c50345d, 0x36595980, 0x59d9938e, 0x537db876, 0x60a7b26e, - 0x16cbc4de, 0x58fc51a5, 0xeb0addff, 0x1eff20da, 0x157bf683, 0x5f9c8965, - 0xeff3763a, 0x1e46b1ef, 0xeb32b6bf, 0x9c778c32, 0xe0a5d652, 0x95ae5411, - 0xc53dfe26, 0x4714f1ed, 0x91456db8, 0xba5fcf19, 0xf69e21ad, 0x93af30b5, - 0xe2a8cfbe, 0xc1456db1, 0xf7e834fe, 0x871cfab6, 0x269fc5ac, 0xaea0bc1e, - 0xc9dbc54d, 0x64ede0cb, 0xbe01bc24, 0x7a13f734, 0xeec5f169, 0xe94cf6e6, - 0x62fafb1d, 0x0d7ceefe, 0x77631eff, 0x340e92f2, 0x35c5094a, 0xe33a338b, - 0xef4829b5, 0x250ed617, 0x55f1e9bc, 0xc3d9affc, 0x7b337f71, 0x05ce962b, - 0x66c3eb2e, 0x6ff184dd, 0xd953f389, 0xa316262f, 0x8bd01ade, 0xb56bfdf3, - 0x82d9fe3c, 0x787ecff1, 0xca9dba6e, 0xf3fc4587, 0xe13fc628, 0x3fc626fa, - 0x7c527ae1, 0x33e5433f, 0xd7a20020, 0x7f38bdc1, 0x8925ee0d, 0x34e2ddf8, - 0xff8a4bb4, 0x73f38b25, 0x61637d7e, 0xce878d0c, 0xa3fef9cb, 0x7bd1bebf, - 0x3a37630d, 0x69b4f1b5, 0xb4f1b453, 0x663915f2, 0x736fd7f4, 0xa3d4d68d, - 0x0f5abc88, 0x925e98ba, 0x337e79a8, 0xbfcc34be, 0xf0a5ee2f, 0x1f7147f8, - 0x4b5bbd4d, 0x2a5bdfb5, 0xb3c668bf, 0x62dbd985, 0x26b3309f, 0x87bfc219, - 0xf1ca4402, 0x3e6de762, 0x416e3a31, 0x60e4fc7a, 0x5e7284b2, 0xaf150f8f, - 0x080037b3, 0x1b39dfa0, 0xbd97940c, 0x55e3b66b, 0xaeeccf3c, 0x7bf7f8a7, - 0x467bae4e, 0x39805df3, 0xbf84994f, 0xa1fb2763, 0xf232c568, 0x607dca3b, - 0xcb88022f, 0xa23ef45f, 0x467e3196, 0x0f91594b, 0x80bec90e, 0xe2727844, - 0x4fbd83f7, 0x7e47eff0, 0x0ed86208, 0x2b7677fa, 0x1287c71f, 0x53e5815b, - 0xfdfbb7b6, 0x6675e600, 0x0679bae2, 0x307c8dc4, 0xd3e2e499, 0x2cfa4332, - 0xe744c3bd, 0x587ede39, 0x31f4efa6, 0xc5533f29, 0xd9cbe62b, 0x1dfe1613, - 0x04a00e9b, 0x71f8b7a8, 0x8f9f7d0b, 0xcfcb0328, 0x11adf40e, 0xf2f48874, - 0xc6733c61, 0xfe7960d3, 0x6496a3e0, 0x82119f5a, 0xce106f9b, 0xfae09bd7, - 0xa3a02f51, 0x06f9e68f, 0x3bbafc91, 0x0f47f899, 0x2e6693df, 0xef48bc9f, - 0xea2e4852, 0x26d996ed, 0xc7df7d07, 0xa3a486cb, 0x96b93a5c, 0xf40f477f, - 0x3f5f1c4a, 0xabd134f3, 0x46939efa, 0xef8e3c65, 0xe90e5d64, 0x0ad6dbaf, - 0x06f4137f, 0xfae3efaf, 0x46ecbd6a, 0x275bc3bb, 0xaf9db9b9, 0x4db78fa5, - 0x688b9ede, 0xd68db1fd, 0x6809dcaf, 0x9dca3cc5, 0x2ec9533b, 0x5bec2998, - 0x2ddbc696, 0x3b3a73b6, 0x0f4fa07f, 0xea7ad7dc, 0xea01e010, 0x75f3a7b4, - 0xacc6a705, 0x3747861b, 0x1dec369d, 0xffb803f6, 0xfbef44f1, 0xc8dbc046, - 0x5ee6f76c, 0xac329f18, 0x4473c6cd, 0xfc4fface, 0xf50fbf1c, 0x83930ed1, - 0x97e974d8, 0x0c4ed3b3, 0xeb835d8d, 0xf2eb67c2, 0x3f042704, 0x5bf8293c, - 0x8b6fcfd5, 0xa7036cf2, 0x2482f63f, 0x34c46bbe, 0x9e217872, 0xe4872a43, - 0x2b872aa5, 0xc7fadd85, 0x3e6edc5e, 0x60a5d6c5, 0x4fa005bd, 0x3b3cfef1, - 0xb72a4bb7, 0x7ee7eff1, 0x4c9c7c84, 0xf5c31a7d, 0xe4167cf2, 0xea014e7a, - 0x77dd0949, 0xc0388b45, 0x409fbe3a, 0xb9e7f72f, 0xe06ffb7d, 0xa3003bfd, - 0x7cffe45d, 0x8f1b1ae6, 0x3c6deb71, 0xff97ac9e, 0xb9b7e84c, 0x3d7a7de2, - 0xbbe85730, 0x377d3ab9, 0xce8e71cf, 0x0edca91d, 0xb2b945ef, 0xc2efab4e, - 0x9a44a9e6, 0x872f3ce7, 0x873f3cf7, 0x769d7bcb, 0x08fda30d, 0x3d59dc2a, - 0x77b4d3fc, 0x791c61c5, 0xc33283fe, 0x78aa1cef, 0x823e66a8, 0xb02cc7f7, - 0x8f18ed0a, 0x062e31bc, 0xa1f0ba70, 0x2dc7ecbf, 0xa06b944a, 0x7efef3f3, - 0x9427b3bf, 0xa4b2f37b, 0x6f7efdfc, 0xd570aecf, 0x829bf1c3, 0x6ef9131b, - 0x9863076a, 0x377f85bb, 0xc91eac3a, 0x0901fffb, 0x00d0a8f5, 0x0000d0a8, - 0x00088b1f, 0x00000000, 0x3bedff00, 0xe5557469, 0x73dcfbb5, 0xe1dc8487, - 0xc2040464, 0xc06e49b9, 0x612f4865, 0x1213d41e, 0xde0d4b22, 0x00c10580, - 0x86120137, 0x7c07504c, 0x0040e3e2, 0xaa1a4583, 0xf50af8a5, 0x22d28342, - 0xb04a0834, 0xc141170c, 0xd6de8ba7, 0xa44f7d6a, 0x40932861, 0xd2bb6a52, - 0xf7b79457, 0x3b939df7, 0xed83a404, 0x58b593af, 0x9ef37efb, 0x77f7bdbf, - 0x52015000, 0xaaa8e601, 0xd08eceb5, 0x092bd00c, 0x72c06e60, 0xd80e35b6, - 0x37fc0ddf, 0xbb746b7f, 0x01e5e696, 0xf7473754, 0xa41c5fe3, 0xbfe6cc01, - 0xff5616a1, 0xd845cc41, 0x766f3d12, 0xe890eadc, 0x556679a4, 0x086e17eb, - 0xa1e6ca0c, 0x840cfada, 0x9f12a24d, 0x6e0f351b, 0xca7a01b8, 0x7773948e, - 0xde0bc361, 0xc5c2221b, 0x002300c9, 0x5c78174a, 0x439c1cfe, 0x2186f77f, - 0xb09e7468, 0x39cd23c0, 0x098a6584, 0x68c79cf0, 0xb1c6994f, 0x477f788d, - 0x617c67e2, 0xc1864ef6, 0x15483f08, 0x3a6f3c54, 0xeba236e1, 0x71eb15be, - 0xdf8841e7, 0x11f8137a, 0xcbbf5b9e, 0xfe3e47e9, 0x695dc5fe, 0x88772b04, - 0x66084410, 0xdcf015bf, 0x2f65f582, 0x56fb833f, 0xdaf78d6c, 0x88e2bbb0, - 0x3c7008bf, 0x252b7c0f, 0xe3d7971c, 0xe070c341, 0x71dd8445, 0x8428f23d, - 0xdfd982fd, 0x513de68f, 0xd927efe1, 0xd187faa3, 0xf4cc4fbe, 0xee3f7cff, - 0x04b6c4fb, 0x9248caaf, 0x44e1a682, 0x84041489, 0x7b7f0bd5, 0x04fc8cd2, - 0x9e8f83f1, 0xf2b8014a, 0xb6c408ba, 0x817f24ec, 0xcfdc4a9c, 0x703d05eb, - 0x5d29b89e, 0x22f6c4ca, 0xeff9ecec, 0x8d4ce7e7, 0x4fc4e59f, 0xd599e914, - 0xf3a50e1f, 0xbe70374f, 0x4d99face, 0xf397a7e3, 0xe7e73573, 0x339f8d4c, - 0x7e35788f, 0x4f892bca, 0x9f8d6af2, 0xeace1c0d, 0x3a7537c2, 0x4fc4f5e1, - 0xa7155e6c, 0xa60f885c, 0x173f909a, 0x4f508a76, 0x12a80b6d, 0x4485c3da, - 0xdf511250, 0x3f8d04ff, 0x7e610a0e, 0xe50ecdce, 0xd29e9106, 0xc49d47b5, - 0x453bb9d7, 0x3f2c704e, 0x73eee941, 0xc81f9e44, 0x24d53c25, 0x087942df, - 0x408aa5c0, 0xb7fbe12e, 0x825a7df2, 0x79e3e522, 0xde2dfbed, 0x36efc8cd, - 0x85c01587, 0x8384f676, 0x227265c1, 0x3a81679b, 0x505f3c00, 0xf8845814, - 0xdd3e50db, 0xb2159e90, 0x5905c6cc, 0x87ec5282, 0x7e13200d, 0x24288282, - 0x1d2fed75, 0x3e462283, 0x814c3bb5, 0x67ff48cd, 0x3c80d0d6, 0xffaf187b, - 0xe913b192, 0x03c835f8, 0xd252bce8, 0xccafc235, 0xfc8cd815, 0x6c4c0879, - 0x0cc087df, 0x982708a5, 0xd8713541, 0xba224f60, 0x3fa85990, 0xf1bf35e3, - 0x7410e1ed, 0xef82af21, 0x3fae7081, 0x73a55d30, 0xc14d0726, 0x1e0fe87e, - 0x090f0732, 0xb2714d08, 0x7c73c245, 0x913c84e3, 0x660cb0e4, 0xf15decf8, - 0x21f846db, 0x1326a5bd, 0x8129ebc7, 0x0a28f1d1, 0xdd32f89d, 0x8444470c, - 0x4439e28f, 0x5904b4f7, 0x0816f365, 0xa30ccdde, 0x54df8614, 0x2881bf0d, - 0x4bc87387, 0x0df76ddc, 0x3547d3d4, 0x069f707c, 0xf1cf5b27, 0x1edf9588, - 0xad004f8d, 0xcd6be256, 0x227fef63, 0x71359d20, 0x49f920f6, 0x6e5cb168, - 0x39f9afed, 0x48afe1e4, 0xc05f384e, 0xf4f90083, 0x04db06a8, 0xb87b3bb4, - 0x1e0d21ff, 0xa5ace8d7, 0xde0bca36, 0xdc5b0212, 0x03e73fb7, 0xd3ad8939, - 0x3b0347f7, 0x1026e34d, 0xed6bfc80, 0xb2562dfe, 0xbf5a79bf, 0xb22187ee, - 0x5dacde2d, 0x169f912a, 0x41ba6fc0, 0x8b3edad0, 0x13dc2958, 0x7afb25ef, - 0xa1ecdad4, 0x5e76277b, 0x5874df2c, 0xef53805c, 0x3e75f9a0, 0x03c03465, - 0x0bdbd3df, 0xcbda0a7c, 0xe39de1a4, 0x8e164a8d, 0x8e7f177f, 0x7828e864, - 0x452fc133, 0xd7253ede, 0xfce39685, 0x8a728f0a, 0xdcd39ffc, 0xa0fecc0a, - 0x58bbf191, 0x28061324, 0x28a37d1c, 0xb858f911, 0x6c9e605b, 0xe636e8ea, - 0x50f13a77, 0xd478619f, 0x76f413ec, 0x71bbc148, 0x36ceeeea, 0xb070a3c3, - 0xf27c6a2b, 0x9f1a8868, 0x1be91d78, 0x6a71b5a9, 0xd194f488, 0x4a8d9ff1, - 0x235b6c6f, 0x42dae3e6, 0x4ba74f3a, 0x65ffef0e, 0x835f19e0, 0x9d75d199, - 0xcc5075f9, 0xba6101be, 0x91df665c, 0x5dff223f, 0xe2a48229, 0xfc5f1aba, - 0x6117f26a, 0x3d181a7a, 0x8f9d78a1, 0xf1a37cd1, 0x06bfa442, 0x8d55f1f4, - 0x67cdf20a, 0xd2af9cea, 0x3f3ab1fc, 0x337f7d70, 0x7d6c4973, 0x4686a6d2, - 0x9fa61ed5, 0xbe18b3b5, 0x7c21ee49, 0x295fd339, 0xc42f48ff, 0x4ef906b3, - 0x5ca74557, 0x5f8c75d5, 0x6d1131a1, 0xa62337c2, 0xff022ddd, 0x52fc11de, - 0x59f949d7, 0x7cd2f811, 0x8b4a67c4, 0x127fbd10, 0xb4ddcf1f, 0x1d1d51ae, - 0x90fc036e, 0x5e8227f1, 0x9d299fc6, 0x9be75ef2, 0x6ac7eb85, 0xfee019fc, - 0x45e88fa1, 0x7d3972fa, 0xd2fd2881, 0x65bcaef5, 0x14b48aed, 0x2004b38a, - 0x68f2c37a, 0xe7fc91f2, 0x9bff3a4b, 0x586f8442, 0xa13dbc1e, 0xa9bf3f59, - 0x64abf491, 0x6f2f4eb7, 0xf70bf587, 0xbff216fb, 0xea7c7a21, 0x53f5e8f2, - 0x667f73a0, 0xf53a5357, 0xfa43cf17, 0xbcfc69e6, 0x4853537f, 0xbf76fae5, - 0x67ac353b, 0xad12b365, 0xed85bf74, 0x6be31b71, 0x93b8de27, 0xbc0fe380, - 0x07c7cd1f, 0xb27b79ea, 0xc1af9b7b, 0x4d7ed91e, 0x7764e3e7, 0x7d72bd94, - 0xc4fd1df9, 0x4024f37b, 0x161fbd94, 0x4487dba3, 0x437baf9d, 0xa750e58f, - 0x1f5efe7e, 0xfc0fb7dd, 0x719f1a30, 0xc7bdbd36, 0x6fe91857, 0x5f1937d4, - 0xf9f4fc74, 0xd7a25f45, 0xddaaf3c3, 0x729afa6f, 0x320cdee8, 0xc49a56ff, - 0x71c75c21, 0xb56a47bc, 0xbf68a938, 0xbcd00be8, 0xc2cf416e, 0x873d309c, - 0xff99169e, 0x8085eb56, 0x196cfd07, 0x04ba56c8, 0xa5628267, 0xcb90f5fb, - 0x9c15e8b5, 0x7169f87f, 0x3df70051, 0xc59928b9, 0xadb81f9b, 0x5d87ff8c, - 0x6366d37d, 0x0cc250fb, 0x0ef38cab, 0xc1963b3d, 0x7fe93bb7, 0x337a47d7, - 0xc9a5ce2b, 0x97e65df9, 0xf6f0250e, 0xbedbf72a, 0xd5af28a5, 0xe7ed996e, - 0x5ad2924f, 0x39e13f50, 0x09916c0b, 0x098fef4f, 0x6de7b2bf, 0xfc239f03, - 0x4695de96, 0x41ff2ef2, 0x9c4f5149, 0xe2c2be57, 0xab5e7015, 0x7c274a49, - 0x658dcffd, 0xb96b30fa, 0x18fbd506, 0x4fd5f83c, 0xcf749dea, 0x1c58146e, - 0xcd17f773, 0xbb62e7ef, 0x4bd321b2, 0x30e81ea8, 0x9ce78481, 0x202fdf5e, - 0x899dcaa2, 0x3c777baf, 0xbf340f9f, 0x7c7cbaf2, 0x2f9a60fc, 0xfe70cb4a, - 0x7017ec39, 0x712adcfc, 0x397840b3, 0x2404dd1d, 0xc097dce9, 0x2b73f0ae, - 0xb865816c, 0x7fbb69cf, 0x673a7afa, 0xd29605bd, 0x93d7413a, 0x4e5f198f, - 0x3f5cba4b, 0xa1cfcc6e, 0x2dbd3679, 0xca9f2195, 0x157a9d4c, 0x2aefbc04, - 0xb5fb7912, 0xb6f91f4d, 0x2f73fae0, 0xaaf163f5, 0x276ca19c, 0xa19d3d7d, - 0x3ffb20ec, 0x462ed5f8, 0x3c4bfb5f, 0x51d03b6e, 0x111e569e, 0x315c5427, - 0x68387d33, 0x7c231f95, 0x23eb760f, 0x6a2f2ca8, 0xf8a12e4e, 0xe28cf511, - 0x45ebd46d, 0x1f126ebb, 0x2645ba36, 0x4ddf43af, 0xea472d1d, 0xf9867ab7, - 0xde64e289, 0x6d6eea3e, 0x9cafd154, 0x33822db5, 0xfaf5e159, 0xe8aef9fe, - 0x39983938, 0x81d128e1, 0xca30c679, 0xeb7cf453, 0x0733f533, 0xf533f1c9, - 0xe3630653, 0x43a74ad4, 0xde7fe725, 0x1c9330e1, 0x9c979a4e, 0x62b938a3, - 0xb9f985a3, 0x8ba98d8a, 0x414e29db, 0x5740f17d, 0x2c32927a, 0xda5b9e8c, - 0x2beedaa5, 0x07191dec, 0x5dad7fb4, 0xf36a6eb6, 0x6d6fd935, 0x5b129597, - 0x2d1b4503, 0xcaabb23e, 0xa0330e21, 0xf1b31cbf, 0xefa42d9d, 0xf3e20b95, - 0xe578886c, 0x53931b46, 0x4aa1c3ab, 0x3a77ee38, 0xaf0889cc, 0x6e8c4dba, - 0x60cc8657, 0xb8e60881, 0x5397063c, 0xf10d711e, 0xc5f6c649, 0xa3ac2f45, - 0x0412e4b4, 0x3d430d26, 0xfd70a6bd, 0x0c5bb6bc, 0x66047e50, 0xf98c5cc5, - 0x7ee01cd3, 0x5dbdfaa2, 0x39fc7cd6, 0x41f2aea7, 0xf9f965c8, 0xfcfc98e9, - 0x8e1e7474, 0xfe51a61b, 0x30aaffcd, 0xc43b24de, 0x5e6a3d7c, 0xd51e7e44, - 0xf2d0c96f, 0xa3c83ceb, 0x9d5aee38, 0xdd829b25, 0x13da3b4a, 0x41b059d2, - 0x2e56f860, 0xc4360312, 0xe79920b7, 0xa0976747, 0x5e8caddc, 0x2576c255, - 0x37c4b1e5, 0xf8710210, 0x0b0dbef3, 0x1767e4cc, 0x4ca57e6b, 0xdbe91f00, - 0xfa6f7899, 0x36c78a02, 0x56be33c6, 0xc7ee78fe, 0xd6bae12f, 0xa229c5a5, - 0x5e87d61c, 0xfee03e9a, 0xde149710, 0x67d2fce7, 0x0bdf49d2, 0x4857ee5e, - 0x22657871, 0x26e298ec, 0x974cf539, 0x9579e1ed, 0xe6ce9ecb, 0x8083e2f3, - 0x2ad970f1, 0x6f01d191, 0x521e02d8, 0x4520fec8, 0xf2d66df2, 0x1cd6acf7, - 0xd34a5bfe, 0xfc991ee2, 0x9c5faf37, 0xced171c6, 0xc676a7f8, 0x066ff8bd, - 0xf993d5ed, 0x57d13f09, 0x4c66126a, 0x5bb4fb60, 0x328b8ec9, 0xb7701e78, - 0xbdd2cb06, 0xea8f09d3, 0x32ef3635, 0x1c47df37, 0xb181e1aa, 0x5429b54d, - 0xf3c223f1, 0x0b779b4d, 0xbc796dc9, 0xb924ef12, 0x0e7af282, 0xad98c7ab, - 0xa72fb449, 0x76e64ab3, 0x989ffd8c, 0xc1dabfb1, 0x227560fd, 0x15cedbf2, - 0xb7fb84c4, 0xbe4cafd1, 0xf0dccf5f, 0x85f3cefa, 0xb99df8f0, 0x49e4afc4, - 0xdb1e108f, 0xc8af6645, 0x29c3358c, 0x0e2ed96e, 0xf1a64e7a, 0x57e445c3, - 0xc81cefe7, 0x1db2b6e2, 0x617bb21f, 0x56e726be, 0xc7296f2d, 0x33844ef6, - 0xf8bdb832, 0x666ba845, 0xe8bf9e6d, 0xabc7d6f2, 0x9c985957, 0x937fd1aa, - 0xfa5ea8e3, 0xb56fb65b, 0x79469423, 0x961bf556, 0xcb6fe4a1, 0x97cbfc35, - 0x09fd19f6, 0xc5b94fea, 0x543dd125, 0xa95b16a5, 0xb028d55d, 0x6a5d7876, - 0xe7e3e93a, 0x4938f7cb, 0x07c4ce4f, 0xb4df743d, 0x52f7882f, 0xc0da887e, - 0x97cf93ee, 0x873f367b, 0xc85259ed, 0xacf8e021, 0xc89332c7, 0x82949f2f, - 0xd93f1a56, 0x5b5136ec, 0xd4d1a491, 0x62dfcc56, 0x55d1cfed, 0x43fa6b35, - 0xe046a5fe, 0xed7aacf2, 0xcf0335b0, 0xffc9a95b, 0xb30ff6ca, 0xa756cfc9, - 0x397db287, 0x14d9de4c, 0x04cfc2ff, 0xbcd6df76, 0xba60ebc6, 0xde486bbc, - 0x34f35f68, 0xdeecd739, 0x7de924f3, 0xaf3bc90d, 0xdea0beab, 0xaffd611e, - 0xbe022a6f, 0xc5e908fe, 0x53cc7899, 0x05b97b79, 0xbcacc7db, 0xbfe6acfd, - 0xf790bfb0, 0x4f3c39ab, 0xac6b79e3, 0xbe4adfbe, 0x263f244d, 0xa7f31b0f, - 0xadbd1a4d, 0x9270deab, 0x3f6caefc, 0xc1c8eefc, 0x57e61784, 0x5ef44df2, - 0xd12d47e3, 0xb3f864ef, 0xe896a1b8, 0xefe98675, 0xdecd73d4, 0xa7d3816a, - 0xd66b5bd3, 0xb5c7d7e8, 0x3a345bf5, 0xd7e340ab, 0xbedc7eee, 0x7b227b34, - 0xa749fca5, 0xd7c49fcf, 0xbef9faeb, 0x4d6edf46, 0x766a414f, 0xbe487f12, - 0x7f5067e4, 0xcd50eb14, 0x2b94e06f, 0xfcb1373b, 0x8e979751, 0xfbe1a7ff, - 0x0a4c4942, 0x04d5b1cb, 0x5ded9a73, 0x1a23c5ef, 0xe8ad4f1f, 0xfc82de9e, - 0x06f31cfb, 0xbea36e96, 0xd3ce239a, 0xaf3f46f5, 0xfdc95b60, 0x86600eac, - 0x9fafed20, 0x304d527b, 0x81273ed3, 0xbf8e87db, 0xf505976e, 0xe81feed3, - 0x1c5779a4, 0x37443999, 0x0cd3ff3f, 0x5457ad89, 0x4af3f307, 0x7010108b, - 0xebc094e8, 0xec56a782, 0x84e79671, 0x327ffdf5, 0x62ff4e84, 0xa78aeb4e, - 0xfa117fae, 0x782cf0cc, 0xd4fdf276, 0x7a16f4fe, 0xd74df3a9, 0xca9c584f, - 0x3d5893e2, 0xca7dedad, 0xf6c5e74a, 0x19caf1eb, 0xfec97bca, 0x10faf2f7, - 0x5923872c, 0xeeb0f711, 0x0ecff1d7, 0x84f7c343, 0x65e72f7e, 0x2efa3066, - 0x1f35b341, 0x85d578fd, 0xa6539150, 0xf5644fb8, 0x08bfbba0, 0xb3d42e8a, - 0xbceeddaa, 0xeaad7bc8, 0xa7a611f2, 0x756210d5, 0x1f55b2cb, 0x7d230f16, - 0x45c629fc, 0x8c5757e4, 0x3d5c52b5, 0xa1cccb77, 0x0dd3e724, 0xb8badefc, - 0x142bc87c, 0x786e9f17, 0x0e666d21, 0x1a282bad, 0x6b65fd89, 0x9e393207, - 0x53150f89, 0x1171fdbb, 0x6a358ea8, 0x53c590cb, 0xd1ca3db1, 0x39e89137, - 0x8e1624d9, 0x2cfb908c, 0xa54f1690, 0x92eccc78, 0x6a4e0ec8, 0xc2deabfe, - 0x933bd2e5, 0x277279eb, 0xa0bafee4, 0x44db3ebe, 0x7e84db7c, 0xc5aee913, - 0xd507a018, 0xff1e054d, 0x5c42b1cc, 0x1fd63ccf, 0x4dfb13d7, 0x09aa2709, - 0x13c7b6ff, 0x4ddbaa24, 0x883781b3, 0xfb0769ed, 0xa6e851e4, 0xc6287168, - 0x9d5cecab, 0xbdf9fa4f, 0xc51eb932, 0xf5e20bee, 0xc76fa4a1, 0x19d63ab4, - 0xcb8bef0d, 0xee893a7f, 0x3d5b8ba5, 0xf9f74449, 0x140df1fd, 0x70b79cc7, - 0x7fefa57f, 0xd88f77bb, 0x77d88ef7, 0x0c65800d, 0x189901af, 0x6740253f, - 0xe3eba4fc, 0x70baeaed, 0xcdd78d22, 0xfaf53db5, 0x5ecd1ffa, 0xd64de257, - 0x12f2f0e9, 0xce365864, 0x9e083aa3, 0xe5f0985f, 0xd9c510ae, 0x86c9368d, - 0xbd259ef4, 0x86fab6c6, 0x1481eac8, 0x9f9e9313, 0x8050637d, 0x138ab7f2, - 0x2cd15dbc, 0x7884a804, 0x22b3ed64, 0x718d9fcd, 0x2221775e, 0xed717d6e, - 0x6bff5224, 0x9ecaff5e, 0x56daff38, 0xe037bd81, 0x5e263db0, 0xfca7b77d, - 0xf5578bef, 0xe754bffc, 0xa42ef6bb, 0x57cf5bf3, 0x0c5ea20e, 0xedf30bcf, - 0x2c3992ea, 0xc4bcbd5e, 0x709b60cf, 0x5628cd6a, 0xbab176e7, 0x5e5a2fef, - 0xdc917b10, 0x4ebc0f77, 0xbb48e779, 0xbdbb224b, 0x401164ba, 0x63abad36, - 0x5ebb9750, 0xf77bb9df, 0x6aeeb621, 0xa37da0cb, 0xbb01dd70, 0xcee7f98b, - 0xf79892f7, 0xbc58ef91, 0x7dd913dd, 0x7451dfc1, 0xd772ebf9, 0xded4abe9, - 0x2ffc7445, 0xdee5c53d, 0xd33aded9, 0xfa1ef449, 0x11bef251, 0x9704ef24, - 0xb9da7144, 0x5c5fdcf5, 0xf2bd7388, 0xc2fbca20, 0x80698986, 0xa1f6727e, - 0x7f512787, 0xa2417ec5, 0xbfbbdcf8, 0xd3f949c4, 0x4eadcdef, 0xbf7ef3ca, - 0x0abf7f5e, 0x469fe488, 0x3489838e, 0x0cd0647f, 0xe233ee32, 0x2337ae41, - 0x0a039b2e, 0xcfd83bc5, 0xbbd716ea, 0xfe05bab1, 0xfde09725, 0xaf2f7b39, - 0xd072e873, 0x1a51adf3, 0x9333079d, 0xfeb4ff38, 0xffbce182, 0xe35d86fc, - 0x4d8bbf69, 0xbef08916, 0xfb6164da, 0xc93cc3cf, 0x5b33ef44, 0xed421e79, - 0x37d93778, 0x35e637cf, 0x7aa37cf3, 0xbab14581, 0x4167eaba, 0xe7ca3cc4, - 0x73a64fb0, 0xa7fa6ae7, 0x853cedeb, 0xef0f37d3, 0x5637a235, 0x99a1138f, - 0x4edddbbd, 0x3d56ff9f, 0x37e31dde, 0xa982584e, 0xef9f8993, 0x77565e89, - 0xe87e85b9, 0x403f257c, 0xc3ebac7a, 0x0517d43c, 0x079a9287, 0xea3e93e6, - 0x9bfba1fa, 0xa5e35bf9, 0x2dfe51b3, 0xdb5daa31, 0x1b3a53d2, 0x7a69e719, - 0x99823908, 0xe9d2abe8, 0x535d6b8b, 0xf8a6b082, 0xc421150f, 0xafe88473, - 0x9152a4f0, 0xc05e8bef, 0xc69ed964, 0x642091de, 0x061ef601, 0x6a17ff4c, - 0xa2b1b075, 0xe519bfbd, 0xf3742a58, 0x96d93e52, 0x2e4d50ef, 0xf9327796, - 0x04253e96, 0xc44ffb00, 0x9ea9733b, 0x0e420330, 0xbb3fb637, 0x464d7643, - 0xf5ebd5f9, 0x2d63b56a, 0xe65767d5, 0xfffb5a8b, 0x3aa8944a, 0x8afdffc8, - 0x530f20ea, 0xffb5943d, 0xf6f5425a, 0x71b477b6, 0xe3425eb8, 0xab402b6d, - 0xdbc57d8b, 0x85c7d03f, 0xdb5fb409, 0xe45c7d2a, 0xfdf5e7ed, 0x98daf6b5, - 0xe331a5f1, 0x1ff6f12f, 0x504e227e, 0x88f5c273, 0x9ef7b527, 0x7d5a65d2, - 0x8336f4c2, 0x93df2cf6, 0x1d17cf54, 0xe7941d67, 0x27947914, 0x7bf0dde9, - 0xcd7ffd7d, 0x44af3844, 0x9f78ad50, 0xd9026fc1, 0xda75e7c4, 0xe1ffdd7c, - 0xc9bac83c, 0x6f3439bc, 0xcb3cd448, 0xda7de6cd, 0x376ebf75, 0x89e2979b, - 0xe77f4fde, 0x9c56e29d, 0x278f5f34, 0x94afef62, 0x8c471e2c, 0x699254ca, - 0xb40b239e, 0xe9bc42b8, 0x16615a3b, 0xbb4a038f, 0x99b677f1, 0x32711d43, - 0x37e431e2, 0xf9077afe, 0xbe3c0db3, 0x98efb57a, 0xf41fb43e, 0xc757be8e, - 0xcc43ef21, 0x3cb3b5af, 0x86fb8ff2, 0xd1bfc8b8, 0xebaf24db, 0xea9f7da5, - 0x759dc5ee, 0x67dfbea6, 0xacb74def, 0x409df543, 0x5f71a875, 0x66f3bd71, - 0xc93efcf5, 0x01b0da75, 0xb48fc8dd, 0x25effba4, 0xbb0da63c, 0xf9da88bb, - 0xaef662b6, 0xefafa3dd, 0x6b3fea1e, 0xa1089e52, 0x6346fb3e, 0x7f611b20, - 0xa2130a13, 0x983f0fda, 0x3d844a0c, 0x57b87a4e, 0xd291fb54, 0x53f9a8cc, - 0x3515dd67, 0x0d0b6c5e, 0xf69c7966, 0x78ab7cce, 0xc61df3a2, 0x9f3debc1, - 0xc7d3fbed, 0x6a1fa28f, 0x5d59126b, 0x2dfeee77, 0x70828f1f, 0xec46805c, - 0x74bdfb22, 0x93ca044c, 0x5757eb63, 0xb46eb420, 0x80f135f0, 0xe5c58474, - 0x8d1fa8ff, 0xc6a34bc8, 0xfb4567a7, 0x1f756bd3, 0x23180ba5, 0xac7568d5, - 0x594f7b2b, 0xbbff5e65, 0xeafd0371, 0xde90b47d, 0xfe903b3b, 0x2d7fa841, - 0x38adaca7, 0xe64b23de, 0x05ef4779, 0xe5007966, 0x4acc0b11, 0xa1171e84, - 0xbea8b81d, 0xde3f71d2, 0x83474878, 0x74d7d6c2, 0xb8bb5898, 0x5465b4d7, - 0xc336aa6f, 0xc754dd80, 0x6e2c1d90, 0x7df9fe2a, 0x67e580e3, 0x63f74282, - 0xe7c2a355, 0x4c1ebf8b, 0x1db1b0f5, 0xc53ed8e3, 0x50131c22, 0xe0281f37, - 0x31d5d17e, 0x76d7f581, 0x6e0f9b00, 0x54ace2ff, 0x7144aefe, 0x29aefe6f, - 0x72888985, 0x86795bb2, 0x2297ebf4, 0xfbbb222c, 0x86f7bde5, 0x5f7a1494, - 0x32283418, 0xc59358ff, 0x6a400ddf, 0x5df74ebf, 0x990481ed, 0xc5eac8e4, - 0xb7ed0f14, 0xec7c77b1, 0xda90f567, 0x94cdb603, 0xdb3ad5e7, 0x0afec9b3, - 0x8907c60e, 0xe307438e, 0xcdbf2ccd, 0x73a1aff4, 0x2bf60e0b, 0xd9537ca4, - 0xf3033367, 0x98f7ca63, 0xca589e3d, 0xd25d3ae4, 0xea37fb04, 0xbfbf6c63, - 0x4cabf381, 0x872ebbe3, 0x7eef8d72, 0x1a659f8d, 0xdf1067df, 0xc5f2ee91, - 0x587b6fc8, 0x29a2c52e, 0xb260fd7b, 0xca5e3e8f, 0x15bf743f, 0x8eaaf7cb, - 0xeaf7c638, 0x7c9a1e8e, 0xa1c945bb, 0xb58323bc, 0xdb7dba07, 0x7ae2ce89, - 0x5fee2f94, 0x287a0f6e, 0x17519a3f, 0x87f7a5ef, 0x45dd8b6b, 0xab85d7c4, - 0xfee6e1b0, 0x8ab5ee8b, 0x74add4df, 0x4a65c844, 0xb8c82e47, 0x2c8ec4df, - 0xebed5f06, 0x2e724bdf, 0xcecf18eb, 0x66c8ef29, 0xa95c62e7, 0x23fef8b0, - 0xfbffbe3d, 0x20b9c7be, 0x21811b30, 0x75dfca8a, 0x26ef3602, 0xcbfdfc21, - 0x54238c4c, 0x1696673c, 0x5b650e7f, 0x6c9b7f22, 0xf8424381, 0x72ff18fb, - 0x9da86a91, 0x3be5d7f6, 0x678c7c99, 0x26e5dd70, 0xd543930b, 0x950f5fa1, - 0x9092fc70, 0x4eec9ddf, 0xc47ff24d, 0x810995ee, 0xcf6c161d, 0x73977e7f, - 0x8fd61c84, 0x43d07366, 0xf919a67e, 0xe6b5f548, 0x00b8e2d5, 0x942667af, - 0x9eb5b80c, 0x83b8ebcc, 0xb79febf1, 0x286b4dd3, 0x66cb869f, 0xed879796, - 0xb78ef375, 0xb8127f48, 0x6ecadcfe, 0x58912cf7, 0xbf6b167c, 0x959eddba, - 0xf9227ffd, 0xcfadbbde, 0xfee11fe0, 0x584a5363, 0x99ef1cbd, 0x87583ca8, - 0x7f31eec9, 0xb3b7f9a1, 0xcac7bb6f, 0xcf6b12f8, 0x6db37d7a, 0xb2019dff, - 0xf68093f7, 0x2fb47a4f, 0xd9a2de41, 0xdd07f33b, 0xb3af815c, 0x339951f7, - 0xddef14ed, 0x9e1ddec4, 0xdece6fd4, 0xf23939bf, 0xf85201bc, 0x1c846afb, - 0xa43d50d7, 0xc9852db8, 0x2e9b9751, 0xba7e5d47, 0xfd963ebc, 0x637d1177, - 0xd775fdb6, 0xd55762ff, 0x53073deb, 0x793b767c, 0xfee1e3dc, 0x8f285ff6, - 0xf7373c7b, 0xfe7af7bf, 0x7e8bff09, 0xe26ec072, 0x5bc3a64f, 0xa3f9872f, - 0xb741e3cb, 0x2433d8bf, 0x68241fcc, 0x6f4fd530, 0x9ee98fc7, 0x99fefc6f, - 0x67fa0b7e, 0xfff433fc, 0x1292f9c3, 0x78b12f9d, 0x49e50466, 0x5527963e, - 0xfc83bd53, 0x4fe818df, 0x15bd59f1, 0x9aa43e58, 0xee4979ba, 0x42d97625, - 0xc5259771, 0x3afd216b, 0xbea211ea, 0x48f56bef, 0x2496087d, 0xbd0ddfe8, - 0x128cf2cd, 0x43cb4997, 0x30f6f30e, 0x09bdfc7d, 0x0c94d794, 0x18e1c6d2, - 0x6c089f1f, 0x472df9fc, 0xcdb25e59, 0xfc20aca3, 0x4c48f05e, 0x74b7173e, - 0xfde7e3ef, 0x5747c40d, 0x04bbffb2, 0x5676ad6b, 0xda136b4f, 0xc3b91773, - 0xdfb57ff3, 0x8817f271, 0xaca3c877, 0x502f79a1, 0x12352231, 0x16ad79f2, - 0x84e6f748, 0x5601cbfb, 0xae58bdd0, 0x6044fd1e, 0x1c3c1df1, 0x1fbe9437, - 0x959f7604, 0x35b1dfeb, 0x06c77f44, 0xb3e3175e, 0xfea11dfe, 0xb09de09d, - 0xd7bed25c, 0xf92370db, 0x866ce4eb, 0xafdf1173, 0x2e9059b5, 0x22efd757, - 0xff477d85, 0xabd6fb42, 0xf2cf1ad0, 0xd7efe8d9, 0x4f3013aa, 0x7b287e45, - 0xca3b411c, 0x04f6e171, 0xab986756, 0xa47b8fd7, 0x31f44bb0, 0x3d03d389, - 0xfd7dd8d2, 0xe74ba6b8, 0x2cff4097, 0x6fcdc533, 0x1e23355f, 0xeff1f66f, - 0x99543925, 0x285f483e, 0xdea45d53, 0x95d0f749, 0x4a97a21d, 0x9d5a5530, - 0xb5529a1e, 0xbc188afa, 0xb98fc717, 0xf54cdcef, 0xfe1ec3bd, 0x0dd9714e, - 0x5d519dec, 0x10b6936a, 0xa70fd72e, 0x71ed8d3f, 0xe979f719, 0xcef2eefd, - 0xa366b367, 0xc05ad01c, 0x00fae2c9, 0x36c1675b, 0xd2b91f7d, 0x96ba42fd, - 0x4220fbbf, 0xbb9f3a1e, 0xa28f1ff0, 0x0e29bdfa, 0x09dede98, 0xc78a241b, - 0xa58c3975, 0x838a53c7, 0xc8efe0de, 0x6ce8050b, 0x3e725c53, 0x5dfbe78e, - 0xb0ef8beb, 0x52cd017c, 0x6cdbaa8d, 0xfcf37998, 0xa5602522, 0xbae9bfad, - 0xf68f25e3, 0x06103e4e, 0x791deff2, 0x9b52a35d, 0x952c5633, 0x6a4f44cd, - 0xbfe4979c, 0x77666370, 0x7c3043f2, 0x83ce441d, 0x2f4cc90d, 0x1845ba56, - 0xb7367a8e, 0xfba4c905, 0x160ee5a8, 0x92d83df7, 0xe313a0c4, 0xf8bfea4e, - 0x7983fbca, 0xa7cb871d, 0x63eed5f8, 0x6afb1c58, 0xf563063f, 0x4fb9fcd6, - 0xd84b77a1, 0x123ab023, 0x75ca12f9, 0xc7563d75, 0x6eac8378, 0xeec096f7, - 0xbf9b293d, 0x75495463, 0xd20e1dec, 0xc22f2c7d, 0x2ec94b25, 0x6cddf45d, - 0x8faeff12, 0xf7dacce5, 0x3e4d4eb1, 0x7df9d009, 0x881bef6c, 0xccb67277, - 0x3d208bbf, 0x264949c1, 0x5cfc9bb7, 0x393fb66a, 0xe6bde29b, 0x9f54459d, - 0x4aea0b9a, 0x13d94770, 0x6ae848dc, 0x77b497a7, 0x2b0f5d31, 0x852173b5, - 0xc6855feb, 0x3e8d4ad6, 0x2b5418cb, 0x4772cfa4, 0x377ae6f6, 0x80fe8691, - 0x1f0adf7d, 0x40fe3dfc, 0x3f7407bf, 0x2cf535fd, 0xc7d2cfc6, 0x7ce3ddb9, - 0x0ffd175e, 0x511f5021, 0x6faceac7, 0x77b0233d, 0x326ebd6d, 0xbd0a0ccd, - 0x095422ef, 0xd2f7d296, 0x8598e104, 0x62e38b9d, 0x8cc3ab12, 0x63ebfc62, - 0xd39d5952, 0x9830ebce, 0xfd43dc27, 0xbf66ead7, 0x7920f8cb, 0xc51bf7d9, - 0x6c4f5e36, 0xdf644f7f, 0xee8add1f, 0x555e5af1, 0x6f62e07b, 0x5f71dbb2, - 0xf7e27e89, 0x11e38b71, 0x67c753ca, 0xf197f7f3, 0x9828a6d9, 0xe98bfb2e, - 0xea3b3fdc, 0x5f909ba6, 0xc167be7f, 0x8771df2b, 0xae887ae9, 0x40a7ba2c, - 0x4d3e90b6, 0x371de504, 0xf06df56e, 0x5064f6b3, 0xf7496c19, 0xa54eca4f, - 0xac0310ef, 0x7dc47c7d, 0x8b125eac, 0x655e2c7f, 0x2c5efcd9, 0xc14536cb, - 0xcfdfb271, 0x5e1852f1, 0xd1365fb8, 0x24f5e3a5, 0xdfea4ee9, 0x88555f25, - 0x7ccaef90, 0x02d7df91, 0xf2c3afbf, 0x25496b1d, 0xbd108ef9, 0x0c17ab4c, - 0xe0f48479, 0xa5eadd9a, 0xbe5d3b77, 0x9bde8108, 0x638e72c3, 0x88ba52fa, - 0x6c91cbeb, 0x6a0baf37, 0x580e4772, 0xf942ae28, 0x9a7c4d3f, 0x75e44237, - 0x3fe50938, 0x4addc980, 0x82995e36, 0x2ae8cf72, 0xde2d5adf, 0x66e2d1ad, - 0x66f51fbd, 0xeae9f105, 0x89fd61de, 0x4607b53f, 0x7a9fc4c8, 0xd4dbcf13, - 0xd0ead6ff, 0xa38bc99a, 0x47ef62ee, 0x297af660, 0x45be2aff, 0x9355b29e, - 0x961ef1cb, 0x5fb60171, 0x4076bbf4, 0xa6809fd3, 0x9c70ff57, 0xe2a21fd5, - 0xffa211ac, 0x754fe265, 0xf32b55dc, 0xfe7bda63, 0x19b37a56, 0xd11fd612, - 0xb26ff0ea, 0xf5cbe247, 0x55f9f506, 0x44e7ff5a, 0xa64ce7d4, 0xef28e7cf, - 0x75e56e3c, 0x156456e7, 0xff107ffd, 0xccbbfccb, 0x3e9a77f0, 0xbc512b06, - 0x8042e704, 0xbad0f9c1, 0x9fce1072, 0x469658d8, 0xfc9854f8, 0xa2ad3eec, - 0x3be9bc2f, 0xec2f681b, 0x76fcfc81, 0x7a77d2c3, 0x5e538a20, 0x5c285b74, - 0xb041b49b, 0x97be40f4, 0x41582d34, 0xb78fb46d, 0xb70f4e48, 0x0ee77a6c, - 0xe39d17ec, 0x8f1c7d98, 0x1cac5391, 0x45fc6b0e, 0xd39b787b, 0x70ba30a5, - 0xa1ed4dfd, 0xe12bdd06, 0x01ffffa5, 0xd5b93efd, 0xefd023ff, 0xe3781b15, - 0x7a6ec8e2, 0x3fbfcc83, 0xf3e7f68f, 0xfa27df80, 0x923afa7e, 0xf397dd20, - 0xf4979ba1, 0xfb8592ea, 0x807d4bcd, 0x0125c1d9, 0xf0bcec2f, 0xfee906fd, - 0xe199791e, 0xf4d6a37b, 0x39f92e5a, 0xc77e57bc, 0xe699e2fc, 0xe4dd0395, - 0x64e903ff, 0xd99f96af, 0x735ff5bc, 0x9510ccbf, 0x80ceb4d3, 0x01a03406, - 0x0340680d, 0x0680d01a, 0x0d01a034, 0x1a034068, 0x340680d0, 0x680d01a0, - 0xd01a0340, 0xa0340680, 0x40680d01, 0x80d01a03, 0x01a03406, 0x0340680d, - 0x0680d01a, 0x0d01a034, 0x1a034068, 0x340680d0, 0x680d01a0, 0xd01a0340, - 0xa0340680, 0x40680d01, 0x80d01a03, 0x01a03406, 0x0340680d, 0x055ff01a, - 0x328d1fff, 0x800060f6, 0x00008000, 0x00088b1f, 0x00000000, 0xc5edff00, - 0x30001131, 0xee300408, 0xd80ea5ea, 0xabdef271, 0x964d2104, 0x5dbbcce4, - 0x6db6db15, 0xdb6db6db, 0xb6db6db6, 0x6db6db6d, 0xdb6db6db, 0xb6db6db6, - 0x6db6db6d, 0xdb6db6db, 0xb6db6db6, 0x6db6db6d, 0xdb6db6db, 0xb6db6db6, - 0xee017e3f, 0x0014ab55, 0x000014ab, 0x00088b1f, 0x00000000, 0xc5edff00, - 0x30001131, 0xee300408, 0xd80ea5ea, 0xabdef271, 0x964d2104, 0x5dbbcce4, - 0x6db6db15, 0xdb6db6db, 0xb6db6db6, 0x6db6db6d, 0xdb6db6db, 0xb6db6db6, - 0x6db6db6d, 0xdb6db6db, 0xb6db6db6, 0x6db6db6d, 0xdb6db6db, 0xb6db6db6, - 0xee017e3f, 0x0014ab55, 0x000014ab, 0x00088b1f, 0x00000000, 0xc5edff00, - 0x30001131, 0xee300408, 0xd80ea5ea, 0xabdef271, 0x964d2104, 0x5dbbcce4, - 0x6db6db15, 0xdb6db6db, 0xb6db6db6, 0x6db6db6d, 0xdb6db6db, 0xb6db6db6, - 0x6db6db6d, 0xdb6db6db, 0xb6db6db6, 0x6db6db6d, 0xdb6db6db, 0xb6db6db6, - 0xee017e3f, 0x0014ab55, 0x000014ab, 0x00088b1f, 0x00000000, 0xc5edff00, - 0x30001131, 0xee300408, 0xd80ea5ea, 0xabdef271, 0x964d2104, 0x5dbbcce4, - 0x6db6db15, 0xdb6db6db, 0xb6db6db6, 0x6db6db6d, 0xdb6db6db, 0xb6db6db6, - 0x6db6db6d, 0xdb6db6db, 0xb6db6db6, 0x6db6db6d, 0xdb6db6db, 0xb6db6db6, - 0xee017e3f, 0x0014ab55, 0x000014ab, 0x00088b1f, 0x00000000, 0xc5edff00, - 0x30001131, 0xee300408, 0xd80ea5ea, 0xabdef271, 0x964d2104, 0x5dbbcce4, - 0x6db6db15, 0xdb6db6db, 0xb6db6db6, 0x6db6db6d, 0xdb6db6db, 0xb6db6db6, - 0x6db6db6d, 0xdb6db6db, 0xb6db6db6, 0x6db6db6d, 0xdb6db6db, 0xb6db6db6, - 0xee017e3f, 0x0014ab55, 0x000014ab, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x40000000, 0x40000000, 0x40000000, 0x40000000, 0x40000000, 0x40000000, 0x40000000, 0x40000000, 0x40000000, 0x40000000, 0x40000000, 0x40000000, 0x40000000, + 0x00000000, 0x00007ff8, 0x00000000, 0x00003500, 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, 0x00000000, + 0x00010001, 0x00000604, 0xccccccc1, 0xffffffff, 0xffffffff, 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, 0x00088b1f, 0x00000000, 0x62f3ff00, 0x51f86063, 0x408cc10f, - 0x7f120cb6, 0x66476028, 0x48107d08, 0xf3e2061f, 0x2fe9a48c, 0xb9b04160, - 0x40afec80, 0xa8597833, 0x88a1bee7, 0xcfd2738f, 0x81ae792e, 0x66322ff7, - 0xe86067e6, 0x6ff047e4, 0xb3caa3f2, 0x3dd7d3f0, 0xb000c6b4, 0x00eeff4a, - 0x0000eeff, 0x00088b1f, 0x00000000, 0x7dd5ff00, 0xc554780b, 0x3d9cf0d9, - 0x3764dd97, 0x2485cd9b, 0x200d8410, 0x125c40a2, 0x126e20ee, 0xc3116088, - 0x65e28145, 0xb201ae41, 0xdb3f6911, 0x5cbb7ffa, 0xc6d6a444, 0xa0b45b4b, - 0x06a2828b, 0x82482459, 0xa5c8ba1b, 0x5835b5b4, 0x0da978aa, 0x24c4dc88, - 0x97f4b004, 0x3bef3fca, 0xce7bbb33, 0xf4bc4c6e, 0x7d6f9ffb, 0x7339867c, - 0xef3bccce, 0x6779de7d, 0x313b10a2, 0x0ae42775, 0x64246efc, 0x19084c99, - 0xbbc32d14, 0x32413cbf, 0x46bcf909, 0x08f39a75, 0x86a1d929, 0xc5f5a46f, - 0xd400a41b, 0x0893bb4d, 0xd3484819, 0xcaf7563a, 0xa08e8f0d, 0x4ca764ed, - 0x8482d136, 0x4592266d, 0x610b09c8, 0xd60a673f, 0xeab126e7, 0xee7b0de2, - 0xd7e7fe82, 0xfd12499a, 0xec8d44fe, 0x4d92fa86, 0xb4488052, 0xad21eebd, - 0x5e7fed0b, 0x39260a40, 0x63d37d69, 0x9085339a, 0x6cbfbbe5, 0x5c057182, - 0xe2167c67, 0xbfbe00d4, 0x23f63565, 0xadb03ca4, 0xa7ed0bb4, 0x99725abc, - 0xebe538e8, 0x038df0a4, 0x9014b9e1, 0x370bbf69, 0x0fb3895b, 0xc10ae183, - 0x4b1e7171, 0x6971d3d6, 0xd2a9447f, 0xe3a252ca, 0xf19cfc09, 0x4471c5ad, - 0x744bf17d, 0xc55dfa1c, 0xa60b92ab, 0x9e226158, 0xa9bf1d20, 0xf3da692e, - 0x32df9836, 0xec4a77ad, 0x0ebe663c, 0x6c0f28f3, 0x006d4ad0, 0x6e6d06d7, - 0x0b7f68bf, 0x0f56ff37, 0xd99edad7, 0x6376989e, 0x5147c679, 0x2f5a3bda, - 0xb41dc427, 0x6d01fc01, 0xf3e8ff62, 0x908d295a, 0x4cbfd04e, 0xff68969c, - 0xb9f1f884, 0xc0615c4c, 0xb8a5093b, 0xead6e962, 0x496dd3d0, 0x0db6ff1a, - 0xe9c97e78, 0x81cf98f0, 0x1cbe13e5, 0x73e57f2c, 0xf1bf9c22, 0x29f2c1f5, - 0xff9f0b9f, 0xcb1437d6, 0x96373ef5, 0x62c6facf, 0x8657c1b9, 0x9bef3def, - 0x9f26e586, 0xe8bf9f07, 0x4be58f9b, 0xfe7c4abe, 0x2c7eef8a, 0xf8fcf8b7, - 0x356fab7c, 0x557cdb96, 0xf4e76e58, 0xe00be1da, 0x9b7d3b7b, 0x05f3acb1, - 0xbe1bf9f1, 0x017f2c5a, 0xaa65a478, 0xa14cb1db, 0x4d1d4a74, 0x484d941c, - 0x32d95946, 0xa633d695, 0xa7b67ab0, 0xf146996a, 0xd69b3d94, 0x2b731d29, - 0x6999961b, 0xd652ee7b, 0x58efddde, 0xddeda16e, 0x9ef6b257, 0x93cb6555, - 0x27cf7b68, 0x8135fb59, 0xb4c9e5aa, 0xac8d9afd, 0x61b06fbd, 0xf7b695b9, - 0xd7ed61ad, 0x6c2b1d87, 0x3efd7eb4, 0x286c2f56, 0xeb42915b, 0x7d598785, - 0x0ad56348, 0xc87efd3b, 0x88fdf671, 0x4ceca096, 0x55db1fc0, 0xd2843dd7, - 0x52fed7ee, 0xd68c32b7, 0xc47dd735, 0xff66c845, 0x33a56ead, 0x865a87c5, - 0xd3fcbbed, 0xc32b5d58, 0x33fcb7f6, 0x6a9dfdf1, 0xec7fb625, 0x9df6c72f, - 0xb7b6255a, 0xf6c3eff8, 0xdb0ab53a, 0x601ecb4d, 0xdb0aad75, 0x883d9733, - 0x52a1bfef, 0xd2138760, 0x6ea3d97b, 0x966f853f, 0x7d02a9e4, 0x9caa6cd2, - 0x28b7404f, 0xaf901ce1, 0x0d322487, 0xc4a7e5e4, 0xa1e6fa89, 0xc83734ab, - 0x8343f6e1, 0xc539079f, 0xe7d4265f, 0x0f26b0be, 0xfb0a79fb, 0x3d3f68d1, - 0xf0a7efdb, 0x7ebaa19d, 0x2f99df0a, 0xf80e79fa, 0x63b939be, 0x677f6cfd, - 0x779e1eb8, 0xaf3f45ca, 0x8ef63f60, 0xaff0abcd, 0xfcf0f523, 0xa7e89175, - 0xde95e706, 0xbc767831, 0x1793f14f, 0xfbc767ed, 0xf6123f14, 0x64fd8f53, - 0x419e0c75, 0xf5d50c1f, 0xf983e833, 0xd8039fa2, 0xf58e974f, 0xe183e3b3, - 0x283e787a, 0x8dbcfd17, 0xd8eb74fd, 0x387d06bc, 0x87cf0f52, 0x473f448b, - 0x1d1e9fb0, 0x51e767eb, 0x1e767e3d, 0x28e7e08d, 0x63bbd3f6, 0x4c721af3, - 0xc7219f8f, 0x8339f822, 0x63aebf74, 0xa63cecfd, 0x63cecfc7, 0x479cfc11, - 0x363bf278, 0xe89f21af, 0x93e433f1, 0x632e7e08, 0x831d053f, 0x1eb4eea7, - 0x23a7753f, 0x982551f8, 0xc18ee0d7, 0x1e8cec33, 0x44cec33f, 0x009763f0, - 0xeb1de19e, 0x1e8ceea7, 0x2267753f, 0x7846c9f8, 0x5e6c7546, 0xe3d33ec3, - 0x1167d867, 0x9e1138fc, 0x08cdcae2, 0xf4fda10f, 0x379fbb6f, 0xcff5e9ce, - 0xfe98e71b, 0x8fc47819, 0x21cd57fa, 0x6467002e, 0xa25f994b, 0xd6932575, - 0x89ba509d, 0x055fda87, 0xf83f70ec, 0xd32fd1b8, 0xb4ea94f6, 0x58ce3582, - 0x02ec5c7b, 0x4d03ec78, 0x18ef7b3a, 0xa7abac99, 0xd9d74e8f, 0x5df1cceb, - 0x29acf574, 0x9cf5743d, 0x7dd3ae3b, 0x817665df, 0xd175deae, 0xdbbd5d70, - 0xf7dd62d2, 0xd66e07ce, 0x3958f7b5, 0xf5ef5749, 0xf5750fc8, 0xd2ce4fde, - 0x2bacfbd5, 0xdd77f5d7, 0x7aba25c6, 0xea9feabf, 0xcb35f9ea, 0x68577575, - 0xb05eae8d, 0xff5d71ef, 0x5a7adf03, 0xf87c1f57, 0xe87d5d39, 0xbeeb2f47, - 0x35fc7e1f, 0xd9e47d5d, 0xc7ff065d, 0x97d138e6, 0x77f065d7, 0x9a07e8ad, - 0xcfe869bb, 0x60b37516, 0x6cddc7fd, 0x28f1ff58, 0x4a0e35cf, 0x07c39fd7, - 0x58fdeed4, 0x48ef5cf3, 0x25297f60, 0x4a07244d, 0x8d0c898f, 0x52ad5f6f, - 0x527ca3be, 0xef72fddc, 0x9af4b4a3, 0xd1a77a5a, 0xa2a6eff2, 0x3f17c0a5, - 0x97e84c95, 0x09526559, 0x1335647c, 0x57d5cbe4, 0x1fde7e0f, 0xe70fdfc3, - 0xfd14be31, 0xe656ac3e, 0xeffe1d80, 0x83f3bf65, 0x4f287e1d, 0x93ec3b43, - 0xf7f6177e, 0xfde7dfa2, 0x49fc0738, 0xd4fd468b, 0x3a35f1d8, 0x7f1c3f7e, - 0xa6bf8c25, 0xbd2df18d, 0x4fc6ea87, 0x375f31ea, 0xc746927e, 0xe8f21077, - 0xf1f3dfb2, 0x50bafe29, 0x3dfa50bf, 0x71e96f8e, 0x5abf8e3f, 0xe375f323, - 0x7fc64727, 0x69fde412, 0x82507f18, 0xae1ef7f9, 0x728f7f9f, 0x3635fcfd, - 0xbd9667ff, 0xc64fc7cd, 0xbd2b3ff9, 0xe3dfe6cd, 0x66fe6ca7, 0xf8ec6fda, - 0x37fe08f6, 0xb72ff8c2, 0x9ae5be31, 0xf7f9fa91, 0xbf9fa45c, 0xeaff8d99, - 0xf8f8f7b2, 0xab7f1c36, 0x7f9b1ef4, 0x7c7007cf, 0xe5d2b9b3, 0xeee64da0, - 0xd00195c9, 0x263dd413, 0x746020d9, 0x2820219c, 0xefd084e9, 0x903d4817, - 0xa64e3f0e, 0xffdf477c, 0x1bf29922, 0x6fdcf7f8, 0x12558127, 0x1dd74c19, - 0x5767a79c, 0x417ed4cf, 0xcb5d993f, 0xae8433d6, 0xf0a6ae77, 0xff9ed535, - 0xef0a43e2, 0x50038dec, 0x274e514f, 0x3e1cddf0, 0xf0ccaf15, 0xb7594841, - 0x12bf5489, 0xa4dbaca5, 0x06e4d8fe, 0x411e7fbf, 0x78f8e318, 0xa27a954e, - 0xe6fe4631, 0x17d7d5ad, 0x0175f404, 0x09301177, 0xa4c5fd2d, 0xf71d254f, - 0x10275d18, 0x447f97ea, 0x594270fd, 0xdc9513f6, 0xf2f1465d, 0x404f5d31, - 0x27ae91bd, 0x4cae9da0, 0x14c72e91, 0xb63bf382, 0x7a001ada, 0x0193f17c, - 0xbb87d81a, 0x1bf2a7ef, 0x727edf2b, 0x5fc28738, 0xd339e7c6, 0x076fa19f, - 0x4c3c53bc, 0x0b2bf3e4, 0x974f1e2d, 0xd59ee4c4, 0x459954b9, 0xf24a6bdf, - 0x54ffd0a8, 0xe9b356e2, 0x9d2e7778, 0x5f107aa8, 0xca135cee, 0x5135c939, - 0x56e89f39, 0xf4c6358f, 0x8066a93f, 0x93227b4a, 0xdf9feac7, 0x37afa656, - 0x44d56ea9, 0x5134d3e9, 0xdda81b22, 0xdf4d3a99, 0x2339c62e, 0xc5fce3a5, - 0x6e746578, 0x9e61d39d, 0xeffa63f4, 0x3cd83a1f, 0x34bc3ae8, 0x3f73d617, - 0x689b5c90, 0x57bc2a7d, 0xa83d7400, 0xb769f3c1, 0x90d6b9a4, 0x92897878, - 0xe11cfd83, 0xca23bceb, 0xcd0c5fa6, 0x83ff878b, 0x29b756dd, 0x461e7e3f, - 0xa093a7b8, 0xba76f60a, 0xc67cff47, 0x18fce37c, 0x74e09c5f, 0x407c063e, - 0x07c093cb, 0x39c7cf14, 0x2bf5441f, 0xc01383e3, 0x4eb09907, 0xa7307c66, - 0x6ffd312a, 0x479ff4e7, 0x29676afc, 0x9ca9f74a, 0xba73b7ee, 0xe7ab5bcf, - 0x3cf9b88f, 0x1cc1e1b9, 0x3cf98267, 0xa62547b2, 0x657979f8, 0x2ff91f06, - 0x8e89b029, 0xbea5677b, 0xfd0376fd, 0x777e9c3c, 0x7165e846, 0xbf3e5197, - 0x011927eb, 0x7c7133d0, 0x31f5e9c1, 0xb5b4d7a7, 0x4cefed8f, 0xe46be1e2, - 0xf6b13af4, 0xfb44d579, 0x112f9c6b, 0xf08c6ff0, 0x9bbbe11a, 0xdfa03438, - 0x9febf7dd, 0xa627f4cf, 0x28b6b79f, 0xf3cc78e3, 0x1971c1c5, 0x68e463c7, - 0xba89e6e1, 0x74c082fa, 0xd6f3fbdd, 0xcfb5d4ce, 0x6ba05aa9, 0xbdf567bf, - 0xff4cfaba, 0xdfef744f, 0x5d32ff7d, 0x0f959dfb, 0xcc67daeb, 0x9f574c7f, - 0xf74a79ee, 0x1b69d4fe, 0x95b7ed74, 0x9f6ba4bd, 0xae9b763c, 0xa75dd13e, - 0xbdda5f7b, 0x9fc43ba0, 0xd9e79abc, 0xbd9b886c, 0x49cf266f, 0xe84c7af1, - 0x273ee3bb, 0xebe13f3e, 0x9f29e583, 0xf19f9f0b, 0x1972c50d, 0x176a71e8, - 0xf4ac754c, 0x3bb33e3e, 0x07217fe8, 0x6eaea89f, 0x7a8d3fa0, 0xc4e7a8cf, - 0x46bd46fb, 0xa7e0b97f, 0x59cf15b4, 0xb0329124, 0xf312cd0b, 0x43f3c457, - 0xb2123edc, 0x1a45cb1c, 0xaf45d393, 0x39062e75, 0x7b85a45a, 0xeedada57, - 0x9c250497, 0x9eaa9ccf, 0xade7383a, 0xef806bed, 0x05abe439, 0xf3dd4281, - 0xe8479b85, 0x47bb3bbe, 0x402af846, 0xff8187b6, 0x04deb65d, 0xb7bc31f6, - 0x00fee4db, 0x1319fbaf, 0x09db5bc0, 0xdf59eaed, 0x0ae38cd8, 0xcb0cb9e0, - 0x5869be53, 0xb079f09e, 0x8f9bee3c, 0x255f31e5, 0xfbbe8d96, 0xe7d8fcb1, - 0xdf23f2c7, 0xf03f2c6a, 0xc4796155, 0x77cb16b7, 0x0f2c017d, 0xf96336fb, - 0x65882f8e, 0xcb16af83, 0x4b1b9f26, 0xfc312f21, 0x0c73bdd2, 0x277d08bf, - 0xce29e1f4, 0x5f80672f, 0x73c5f112, 0xa938be7a, 0x185f2256, 0x0e91a1f5, - 0x6df77d46, 0xf4dd21f9, 0x9443f0fd, 0x7a06b9de, 0xde8f6cf7, 0x397d221f, - 0x0e4dd3bd, 0xf7a70f06, 0x45780623, 0x041281a9, 0x7e6665bd, 0x595b711e, - 0xabc453dc, 0x7b8b3249, 0x337578f2, 0xbc0377fd, 0x10fb04a7, 0xbf6b5fda, - 0xe21bdbff, 0xcc47adcc, 0x3db5e484, 0xdafd233f, 0x9bf103c4, 0xc9ff0ebe, - 0x14af0cc9, 0xda84b1aa, 0xbed73587, 0xeac59aee, 0x423b010a, 0xb8d8ae82, - 0xc05fa46f, 0x78fb7665, 0x7f31374d, 0x6657bad3, 0x776f08f8, 0xf2894e4d, - 0xd2dcd7ab, 0x95f833bb, 0xd8099a1f, 0xe9b01233, 0xf5a7e5f1, 0xb57c51c1, - 0xf4f68f35, 0xfc2fffde, 0xda8fa7b4, 0xa48743d3, 0x735fc7af, 0x24f75d31, - 0x008e2f58, 0x6df41c3e, 0x1ba1b0f8, 0xf81061f0, 0x5adff69d, 0xe92a4d73, - 0x66e7ed17, 0x13af9393, 0xde4e9ebe, 0xd37e0854, 0x1334537e, 0xcbae9eb9, - 0xf24dcf65, 0x5dcff020, 0x6f4a7e8d, 0x6bab6eff, 0x49d61385, 0x7612fe67, - 0x75fa17c2, 0xe7c1eb73, 0x59aeb0ed, 0x1c726392, 0x3e9b6c2f, 0x0e79838b, - 0x547fac5b, 0x56b7afab, 0xdc596349, 0xa53a99c4, 0x8769e83f, 0xd02f78e3, - 0x8a58399b, 0x68e4967e, 0xf019e38e, 0x79c9805e, 0x81ea1a75, 0xbe0b3e33, - 0xd1c37df7, 0x38513f56, 0xf427c86a, 0x2b89107b, 0xbf7edb3d, 0x2e56be4d, - 0x228f1068, 0x580bf521, 0xffd1252f, 0x7e80f4af, 0x7e8bac15, 0x6fd941bd, - 0x579e1ebe, 0xdfa3c6eb, 0x1b1ec539, 0xfcb6d77c, 0xe084e428, 0x3f374a5f, - 0x2fb8a7f8, 0xfbd0e494, 0xbaba696d, 0x43b3b6b7, 0x3fc1c7e7, 0x2d1cd1c0, - 0x8b47c029, 0x2b355b38, 0x8512d5b6, 0x322c066f, 0xf6259f81, 0xa34b62de, - 0x968fa1e6, 0x7f4148ec, 0x7c63c978, 0x1a4fcd9f, 0x4359fbe0, 0x29970779, - 0x51fd3154, 0xb44c470b, 0x89af0f7e, 0x3559aefd, 0xff5fd10b, 0xdd71f894, - 0x1aae5a77, 0x796a7e0c, 0xa6e68370, 0x989cfb74, 0xffbe82c6, 0x2f63bc9c, - 0x57b7918c, 0x7be70d64, 0xffbd6acf, 0xbab1d74a, 0xeac75d3a, 0xa4c973ea, - 0x9a17d82c, 0x974aa4fb, 0xd5aeb8d4, 0x7656ffb5, 0x91e77ce0, 0x876055ca, - 0xbc29a93f, 0x71e0047d, 0xb0c1fae7, 0x9b459c4e, 0x29fea973, 0x03487cdf, - 0xe3a6f939, 0x0bef802f, 0xf315c7e2, 0xe407db8a, 0x59bc5878, 0xd8120772, - 0xf76e5abd, 0x3bfa5e84, 0x1eb31fc0, 0x23e7cd3f, 0x3f9adfea, 0x65c32932, - 0x4339e945, 0xc1921cf6, 0xa49f008e, 0x5be2f946, 0xd7139ff7, 0xd7bfdfff, - 0x1d12bbfe, 0x4ffed37f, 0xdefc5e83, 0x0715effa, 0xf044c5ff, 0xb22c3a0b, - 0x17c01c34, 0xbe096e1d, 0x14dcb853, 0x7c60714d, 0x725ab9aa, 0xc4fbe999, - 0x2c8e9c4d, 0x3d601fa6, 0x6a5afcd9, 0xe1bd413e, 0x1f3a6e20, 0x552e7f2b, - 0xd123d9ef, 0x3b4ae175, 0xfe51a771, 0x9953e954, 0x692ad1ca, 0xe5a24580, - 0x7f739ae2, 0x9bf68379, 0x88099214, 0xa1853374, 0xdd97f701, 0xac776069, - 0x03b411e4, 0x257ec7b0, 0xd1a70a23, 0x0578103e, 0x8d8397ec, 0x61b6463b, - 0x9d75a6fc, 0x9955718c, 0x919bf75c, 0x0f782f54, 0xeda2f952, 0xb405f0ad, - 0x5d7095af, 0x04b07adf, 0x24eaf3eb, 0x6beb4192, 0x60f9ec93, 0x26dcd2af, - 0x63373c5d, 0x4e7e3eac, 0x5806eefc, 0xf3e6cfff, 0x1c00c405, 0x53bd790b, - 0x7de1ba59, 0x5c4c5ffa, 0xee67b66c, 0x93f14278, 0x771f4d3d, 0x723f285f, - 0xed3ae200, 0x06ed6dca, 0x9463900d, 0xf59b85db, 0x21b78175, 0x09e64a4a, - 0x6236c9b0, 0xadb5bc03, 0x67c1dbc7, 0x8cdfef63, 0x7c71d81c, 0xce64f11a, - 0xc935e3d1, 0xb5abc7a9, 0x066f018f, 0xf4b8a6bc, 0x3a66a2f8, 0xa9af0890, - 0xfae87b43, 0x7af1bef9, 0x6fb3e017, 0x57f49f14, 0xa262c966, 0x56767007, - 0x46ffc8c2, 0x85b5c979, 0x55f7f825, 0xf8658199, 0xf5052b95, 0x5f870e40, - 0xb3becd9a, 0x60c8bc82, 0x2f285d55, 0x3b046910, 0x391f256e, 0xf2268e80, - 0xb7d2b909, 0x37de3a6d, 0x59d1df71, 0xc075abf4, 0x1f23d7cf, 0xe9fc5d20, - 0x0f22b024, 0x00e5d1e4, 0x59f416bb, 0xbae9b39c, 0x711f55f1, 0xcdfea6ce, - 0x96073e6b, 0xf7b0168f, 0x0091fb9b, 0xe1831bac, 0x884e590b, 0xeba1cf67, - 0x1fffaa34, 0x80265ad5, 0x9517fc3f, 0x55eecfad, 0xab772c35, 0x47ffae26, - 0x79f201ff, 0x00ffa99a, 0xd0e6a5f1, 0x50d5cb26, 0xbf3195af, 0x75569bc0, - 0x14df8c2d, 0xb35c1952, 0xf64f182d, 0xc768abd6, 0xc48f669b, 0x9f311a7c, - 0x163c90a6, 0xa1cdd9e2, 0xc4f7ec4f, 0xdaa69dd8, 0xbb05ae27, 0xb12994f7, - 0x628cfbff, 0xc87e6efa, 0xfa3d38ba, 0xf509d28c, 0xe83da3e7, 0xb6262a3c, - 0x9becbf22, 0x77ce337b, 0x9a724847, 0xf2a5dc29, 0x0fe83f1d, 0x537f86fb, - 0xee24de98, 0x58b333f1, 0x5f563ce8, 0xabd4888c, 0x7ec32afe, 0xc3c45d25, - 0xcac0e2be, 0x8c87e8b9, 0x0292490e, 0xc108ebfa, 0x0fc8467e, 0x7f32c094, - 0xe3a28350, 0x0921c1c7, 0x91b836f1, 0x90d37e60, 0x61f6fa23, 0xae218a8d, - 0x9f819016, 0x3fd29c46, 0x6d7c13af, 0xd7c05927, 0x25965e4f, 0x5b9a4ff0, - 0x1d396b88, 0x977679bf, 0xf9a78022, 0xd046ec02, 0x363cb2f2, 0x8ff7fad1, - 0x9e87f30a, 0xc6fed8d2, 0x816d7353, 0x6fbe9465, 0xb8c72dce, 0xf13f17c4, - 0xbfb44f74, 0x5287a315, 0xdc83684d, 0x75cfb0a9, 0x1295c4df, 0xd552031a, - 0xfe252cb9, 0x82bfc17d, 0x771f059f, 0x09ec9b9e, 0xb2671824, 0xe294fcca, - 0x8d247db9, 0x5bb4d7c2, 0x4da57422, 0x747b969a, 0xe9630ef1, 0x0173cb27, - 0x79ed6f1e, 0x2594ec0d, 0xfa0fd894, 0x3ca3b14c, 0x2ff72d34, 0x1fb5bc83, - 0x3bf46153, 0x27dfaebf, 0x48723e31, 0x2cefb271, 0x9e813355, 0xe42c732d, - 0xd6379639, 0xf00a5279, 0x55b8c97b, 0xcba7de14, 0x9f37684c, 0xbf085d52, - 0x7961317f, 0xa2ff7c71, 0x61b204eb, 0x5cfc8c4d, 0x95248a54, 0x0ea92bf6, - 0xe3c33fec, 0xd77e0092, 0x8769ffbf, 0x4be690fd, 0x1763a466, 0xdf10f71e, - 0xfad95575, 0xfeea8371, 0xd0f58152, 0x0b944cfc, 0x9ceec797, 0xf5f2ed4d, - 0x09ef14b5, 0xffe146fc, 0x98e87ba5, 0x9b749e14, 0xb892f909, 0xd5074edd, - 0x7e225e77, 0x8883947e, 0xa225845c, 0x51ea8e0c, 0x53852429, 0x681c3ea8, - 0x5a6585b1, 0xf3a7cfa6, 0x6231fd86, 0x2835fd61, 0x40fb2367, 0x7ca1aeb8, - 0x4d821839, 0xaef587f4, 0xafd0bfd8, 0x84af2f42, 0x67ed36b8, 0x604a63e5, - 0x9d67ed05, 0x357498d2, 0xcedcf32d, 0xba412062, 0x5003f4e2, 0x2e27cd57, - 0xf6b1210a, 0xf1169f5c, 0x0ed0a847, 0x78c64af8, 0xd38e9180, 0xf4f2f822, - 0xf3fce952, 0x09bcb60f, 0x892b8b6e, 0x6fdae78d, 0xca593b41, 0x4fb0eaed, - 0x17d0014d, 0xee237c24, 0x112d799b, 0x17d3a0fd, 0xc4686ec3, 0xef61ae7c, - 0x54a87833, 0x41fde1b9, 0x7d723c11, 0xa136fdc2, 0x8284863f, 0x2eaeb085, - 0xb5ee1508, 0x3e0bf1d1, 0xa71b7262, 0x15d20e3f, 0xaf6f8f5b, 0x307c8c37, - 0x90e54c20, 0x1d1fa5d3, 0x23a0f0bf, 0x52f68752, 0x7019ea95, 0xc99eb916, - 0x1b30389c, 0x7f38bdf7, 0xe42af119, 0x05e728d9, 0x9af6bbf7, 0x0c885c19, - 0x8a4438e3, 0x09ece1c2, 0x392de87a, 0x1157f415, 0xeb8503c5, 0x696f2e73, - 0x60e30217, 0x6e864ffe, 0x65df224a, 0x7e99b25d, 0xc62f631d, 0x20d99ec9, - 0xd85ed477, 0x7b150f01, 0x8f4c682e, 0x11de9185, 0x0172a7be, 0x10b909df, - 0x6fe46efc, 0xe82b0f21, 0x189ea657, 0x4760249f, 0xce082965, 0xeb61d52e, - 0xe157801c, 0x1a7f1337, 0x3a9663c6, 0x78eb38d8, 0x24d2ca5e, 0xd7fa7677, - 0x25ef5fe8, 0xc4c40913, 0x8b4abc39, 0x7bd17a06, 0x8c812349, 0x8d9f80ef, - 0xad59f871, 0xcfc78a76, 0xebf3c86c, 0xfe02bff4, 0x87fe1180, 0x5ff8519c, - 0x421456b7, 0xe70efe9d, 0xef9bd2c4, 0x15f90a13, 0xb6b43af2, 0x9cb52f72, - 0x2719f271, 0x0c80a197, 0x4f978a78, 0xccf41932, 0x23f33088, 0x817a728c, - 0xf6f9a3cf, 0xefc0de96, 0x0ea7b2f9, 0xf7def7e0, 0x2fe83745, 0xc63249df, - 0x6bf32053, 0x2bd81765, 0xb3a190d2, 0xda76f107, 0xf5c4e8cf, 0x9f9f057a, - 0xd4f94b54, 0x9e05fb0e, 0x0affd07d, 0x41ff5b07, 0xc7f41e40, 0x7bf3c545, - 0x852b0b90, 0xa7e2192d, 0x1879c27d, 0x45c832a7, 0x3560725b, 0xce9079f0, - 0x9f8cec17, 0xa5ab99da, 0x5879e1b6, 0x52f0634d, 0xa23f07e9, 0x06c260eb, - 0x8fb820ab, 0xe59f35da, 0x602d74af, 0x729fd6f9, 0x50c27e7d, 0x3eca545e, - 0x0aa97986, 0xbe0b9bf1, 0x2a00dc3d, 0xaa4e5fc4, 0x1f008fee, 0x9c6eb196, - 0xb883ae47, 0x72276a24, 0xa2e4a095, 0x722fa470, 0x9fc6bda2, 0xbfb49fb0, - 0x22cef1dc, 0xd52e77a0, 0xcaf71089, 0x91247f05, 0xc22aa85c, 0x3ef9adfd, - 0x5f07e710, 0x407f7ce1, 0x18cdf3a3, 0xbcb1a2df, 0xd4ce2a85, 0xdbf0092e, - 0x4e3b7294, 0xc4a2e9b6, 0x8634fcfc, 0x08bae367, 0x52f30608, 0x8d41fd78, - 0xb8e94928, 0xbec3f16e, 0xc164dfb2, 0xb8958b75, 0xbae7a082, 0xbe1e2c68, - 0x86ad724a, 0x16952ffa, 0x78f9e40b, 0xfefd6cad, 0x2e49c8e8, 0xbf62be85, - 0xd61f35a1, 0x3bcf949e, 0xa6fdf469, 0x57bdad91, 0xba5a0ce2, 0xcb737e31, - 0x27c12f30, 0xb56e8215, 0x496e8eaa, 0xa1888f10, 0xad148adb, 0x4dc5f80f, - 0xd60bb252, 0x240b4d29, 0xe164a706, 0xff9053f3, 0x1e127122, 0xf2d42857, - 0x6f423f10, 0x86acf9d3, 0xfb0dc052, 0xf92fd0fa, 0x89b0359d, 0x8f1bfabe, - 0x81c433a5, 0xed8e67b3, 0xaf67710c, 0x491ba5bd, 0xf3a60710, 0xcbf3001b, - 0x40d32b56, 0x79df65cf, 0x30f40edc, 0xd7f62dc2, 0x4bfb07f0, 0x586c656f, - 0x7125fe83, 0xe7cf7ab3, 0x05094eb0, 0x60e39978, 0x2a49cff0, 0xb7d58acb, - 0x132cfa4f, 0xef5a2515, 0xec4bc914, 0xffe7cba3, 0x89daefb5, 0xbd7be9a3, - 0x59372635, 0x9fe3f5a4, 0xd6e671d1, 0x3f105d58, 0x8cf65478, 0x773fb803, - 0x70975f3b, 0x01295d1d, 0x959f8b1c, 0xf079d3c8, 0x43fb611d, 0x1f943f1c, - 0xd98ecf3a, 0x2ef3a037, 0xd3c506d3, 0xb52559b5, 0x7212e710, 0x2ca7c999, - 0x4ba082f4, 0xea9bd026, 0xe5465205, 0x8dce2634, 0xdc6166af, 0xe8527f0a, - 0xbf02fff7, 0x31437ed1, 0x1ba09dca, 0x48f4c3e9, 0x4c75c812, 0xfeb9aabc, - 0x14fcabbd, 0x9fffbf8e, 0xb68429f3, 0x496943ff, 0xf53e3901, 0xdc535fc0, - 0x00f60f90, 0x977acf5b, 0xeebce2a4, 0x8ff77ee2, 0xb46a9e38, 0xd79872b2, - 0x637fbedd, 0x6fa2379c, 0x8efb67ef, 0x8ffaa80b, 0x4b6a2fdd, 0x1479c32f, - 0xfd7793a2, 0x8562ecbe, 0x7e30eb9d, 0xeb6349bf, 0x1bd505e6, 0xc0275cb4, - 0x806ff9e3, 0x5f5f14e7, 0xf161aa9c, 0xacdf011e, 0xf81a01ea, 0x9908ffdc, - 0x1fed9849, 0xb95f4ca9, 0xb7c5126d, 0x08d1e387, 0x179e01f7, 0x3257e739, - 0xe933c1fa, 0xb953f758, 0x601684f7, 0xff08c71c, 0x52bcba9c, 0xf3987fc8, - 0x29eb84b0, 0xaa01ff78, 0x3ff73d3f, 0x68e80e74, 0x9f319f9c, 0x171f18c4, - 0x43c8b37e, 0x983c4d9b, 0x27171297, 0xfb1cfd0a, 0x9e8bc637, 0x797af8d5, - 0xfb021930, 0xbef96725, 0x621b9c3a, 0xcb04ebfb, 0x14925072, 0x1e968b9f, - 0xb926052a, 0xc61b72a3, 0x33f8c5eb, 0xf833f8f8, 0xaae15438, 0xe633c7c0, - 0xf36217ab, 0xdc68b6dc, 0xc7421e6f, 0x89e3a393, 0x39731671, 0x7a0be314, - 0xe72abe0a, 0x7f515d74, 0xd3235bb2, 0x0c498703, 0x9ff88c7d, 0xca2b3bf7, - 0xa1cf0447, 0xfd039c5f, 0x51736738, 0xec271769, 0xc28e545f, 0xcfe269fc, - 0xe16af961, 0x1bb7581c, 0x36a4def1, 0xd8257376, 0xfee2689f, 0xb9717b5c, - 0x03c89a1d, 0x94f2c2a8, 0x67e07552, 0x191b87c0, 0xb9de2c1f, 0xb79075e5, - 0xb2bfadf2, 0x569dbc83, 0xbc60b2aa, 0xb41e9b45, 0x29c57ec3, 0xbd076fc5, - 0xe4c03a78, 0x8aefc8ce, 0x305bec59, 0xe0f6157e, 0x9f3fcbcc, 0xc5f9fc00, - 0x7a01d526, 0x1cd9bbde, 0x547c5336, 0xd0fc30d4, 0x7f5651fa, 0xade2f108, - 0xfe5dc3d5, 0x9cb2afe2, 0xe7969f6c, 0x9d7185f3, 0xd3f1b15f, 0x2f0f9052, - 0x1d7dc169, 0xfe3077e3, 0x97dc74a5, 0xc6a5a99b, 0x11be0bb7, 0x8d6f05eb, - 0x3c469be0, 0x7f7c665f, 0x172fd73e, 0xfe72bf05, 0x0120f811, 0x9de457a6, - 0xd28ff3eb, 0x7f8dd9fa, 0x62fd4bb2, 0xbfcb09f5, 0xf3de0d68, 0xdb672eec, - 0xe71360fe, 0x0177e8c3, 0xcb59cefc, 0xac4230f3, 0xed86a45c, 0xb4591710, - 0xecf5c541, 0xbfcf2da2, 0xbdd834f0, 0xabaecdf7, 0xb70bff69, 0x38777fec, - 0xa6dc2fad, 0xd3678e66, 0x763149b0, 0x5a7c0bda, 0xf943a510, 0xb39afdf6, - 0x40fe7b3f, 0x0b1e947a, 0x48d1edb7, 0x947c78ff, 0x8c68f704, 0x09740dff, - 0x7d852d1e, 0xbfe7796e, 0xe9fba035, 0xbc8112dd, 0x6e7c38cc, 0xd2fb8fd8, - 0x23a42780, 0x6e8453a7, 0x94bdf786, 0x39e7682e, 0xefed8c9d, 0x3fe40e69, - 0x5dce0fe8, 0x757e7e51, 0xfccfc517, 0x982ecc0f, 0xef57fcff, 0x4e3cc3b3, - 0xaf8c952a, 0x05983fd7, 0xeabe6476, 0xc96072cf, 0xe67fcf9e, 0xf36fc847, - 0x8b28fd0e, 0x99d2fd30, 0x9dfcd1c5, 0xd6737e61, 0x9bf386dd, 0x77c83c4b, - 0x65cbd7f3, 0xa8babf10, 0x12dbb190, 0xb94fc5c8, 0xce7c9c5c, 0x27f8fb8c, - 0xb8531ec1, 0xccc8effc, 0xa2f721cf, 0x9f11fd7d, 0x58fcb50b, 0x18e3c8bf, - 0x1e22cd13, 0x2c72b54c, 0xa87c6ebf, 0xe673e801, 0xc436772a, 0xf144bd01, - 0x57487c73, 0xa1f2bf68, 0x3f5cd931, 0x7f189539, 0xc39e04b7, 0x3baa0dfb, - 0x1df75f29, 0x1d1792b9, 0x9f1f297f, 0xfb0c9dc2, 0x12b327c6, 0x305f87c7, - 0xd611624b, 0xa303f3a0, 0x7de4cdf2, 0xbe4cc3e3, 0x2607bc85, 0x0bf6858e, - 0xc0fc9987, 0x53c7e077, 0xd8d9c2b8, 0x848a67be, 0xc3da80fa, 0x51bd7244, - 0x6fad72e5, 0xe1427c17, 0x897fc056, 0xfb610bf0, 0x7e7927bc, 0xe927dcfb, - 0xc1763177, 0xe3d9e30b, 0x3b7213fb, 0x6617f84f, 0x7593fcbd, 0x5bc6129d, - 0x22c47e8c, 0xd3c2f035, 0x3e54af20, 0xda2edf41, 0xbcc196a2, 0xfbdeab3f, - 0x9ca90fee, 0x7214167c, 0x469fd7aa, 0xdaff9d39, 0xa34fe47e, 0xdc167e9c, - 0x4e50959f, 0x73c7edb7, 0xfa72f1b7, 0x053fab3f, 0xf01bd6fe, 0x5b61f427, - 0xc3ea3478, 0x4fc410e1, 0xb7090fa0, 0x13fe46c3, 0xadf8277c, 0xddc595fc, - 0xf844ef41, 0x845df052, 0xc5df052f, 0xf0ead1e5, 0x083f3717, 0x589f01a2, - 0x75828ed6, 0xf6c5c586, 0xcb39ae13, 0x819693e2, 0x67d6fd6c, 0x43f582ad, - 0xb020c726, 0xec4613fb, 0xa427ecfc, 0xbef9fe6d, 0x963e9dcb, 0x65075fa3, - 0x895f042f, 0x1090e3a5, 0x16fbd383, 0x7d40f409, 0xf76396e0, 0x930b640b, - 0xbd1f9df7, 0x2c780856, 0xca97ee6a, 0xae1babf8, 0xb5fc445b, 0x054cefd5, - 0xea1ada7d, 0xad4f7989, 0x4494e507, 0xe25fa5e7, 0xfb857df4, 0x491bcd5b, - 0xadf94c95, 0xdfa0b499, 0xc168dfe0, 0xbe38b67c, 0xe67f3330, 0xe803e2bb, - 0x2978f80f, 0x5134b1a9, 0xf9f09a3c, 0x5ff3784e, 0x0baf1f68, 0xbf81306d, - 0x9346dd7e, 0x24be4fce, 0x1480baf8, 0x784f5f00, 0x20652933, 0x2ecaf3ee, - 0x0dee5738, 0x093cd39d, 0xf38c95f2, 0xdfc1fe87, 0xe0716fea, 0xc1a86fb8, - 0xdbdcf07b, 0xeb0216e7, 0x6aad3a85, 0x3b382261, 0xeb383125, 0x7cba338e, - 0x6a29785f, 0x618b85b6, 0x61237a7f, 0x3a38f671, 0xde0eb613, 0xaa7f704c, - 0x7ab32435, 0xa347db35, 0x2462fca0, 0xf699777c, 0xd79f231a, 0x057b6ed4, - 0x8455e7ce, 0xb6898724, 0x1a8d2857, 0x36b78bf0, 0x363d064d, 0xcbce29c0, - 0x894ffa3b, 0x16febfe1, 0x77b9e705, 0x00331bf8, 0x6acfe72f, 0xddd5f604, - 0x60ec5afb, 0x0a87ceef, 0x9adadf91, 0x191f76d7, 0xfee9eb05, 0x78a77f00, - 0x4eabf63a, 0x9447d5d6, 0x5c00ba78, 0x4b8dcc13, 0xfef0095d, 0xf7d9858a, - 0xdb3e4bef, 0xbf2c3b2b, 0x7afc8587, 0x7c41bf70, 0x378700ff, 0x13b37e46, - 0x6592efc9, 0xf7986cce, 0xd99efa92, 0x7f25cf80, 0xe2253b50, 0x963e2dab, - 0xee15b4df, 0xadf90017, 0x7d7bf2a1, 0x50d6fc8c, 0xff8bcdf9, 0xfbe5ae6e, - 0x202ddf95, 0xfbe009bf, 0x90af9f09, 0x51d0fcdf, 0x1afcdf94, 0x4acef9fd, - 0x2bf27b4b, 0xf2c29a75, 0x04d65c60, 0x00f01afa, 0x795bb2f9, 0x038c387e, - 0x37c2fc72, 0x24bce394, 0x4a7fef06, 0x20ec978e, 0x4f128798, 0x4bc7266f, - 0x4b1ca8ea, 0xc7267740, 0xcb09ea4b, 0x6fc83407, 0x65f9389f, 0xd98457df, - 0xbcdadef7, 0xc741dcdf, 0x2eab702b, 0x20bf7d0b, 0x6283cf2a, 0xb685f9e5, - 0xc760f9e4, 0x970779e4, 0x3da72a67, 0xeae8095c, 0x63f3e90a, 0xb27618de, - 0xe5f03b7a, 0x275c659f, 0x0f79e21d, 0x7276197f, 0x3fc5f020, 0xff8a1e00, - 0x9a6f9c3d, 0xbfec7e7c, 0xe853f874, 0xabec9547, 0x03ec35fa, 0x12a8de2e, - 0x351587d0, 0x328fd147, 0x5f85bfae, 0x0b875c65, 0x7e5ed23d, 0x776e61cc, - 0x088dca26, 0xc65b792f, 0xf38c3ffb, 0xc1c5ef17, 0x5deab079, 0xc042afb8, - 0x407c5ed9, 0xb83da3cc, 0x15debcc4, 0x148032f2, 0xe286dc42, 0xffc5e511, - 0xb5cf1947, 0xad5d1595, 0x23e51fbb, 0xaac2cf8e, 0x870812a2, 0x37e7e44f, - 0xf7bdaee7, 0x18af9c00, 0x0059c474, 0xe188f4ee, 0xa7ac0f66, 0x416a4a5e, - 0x49741679, 0xb974624d, 0xa379fbc4, 0xf031654b, 0x7256b79b, 0x86f1dd80, - 0xc1f785ff, 0x8bea7dec, 0x05a3e052, 0x8cc392f5, 0x834e787c, 0xb5295e75, - 0x854fc0bf, 0x7eb873a1, 0x245f505b, 0xea0bf7c3, 0xa3c0bc24, 0x9474fc3d, - 0x0edc296e, 0x6df8016f, 0xb30b6700, 0xd13e1c6b, 0x3afc55ee, 0xbe9e4bf8, - 0xc1972ab4, 0x571704ed, 0x02283bc0, 0xe7194cef, 0x057841d5, 0x3783dbde, - 0xc74f4935, 0x679e47b7, 0xb4a110fb, 0xbe6bad0e, 0x97887ee9, 0x4cfae034, - 0x90cc8bec, 0xac0b663d, 0xf3e97b6f, 0xc1690995, 0xa1efebbc, 0xf5d7ff7f, - 0x0037d91f, 0xece41dff, 0xcbae2a4f, 0xb338a497, 0x1df1dce1, 0xb75d2af0, - 0xfb336d34, 0xff313de1, 0xabb73e13, 0xc3710297, 0xf19e58b1, 0xf57ab995, - 0x4f6fb18a, 0xbe43b79d, 0x821f7357, 0x294d2179, 0xda274e2c, 0x0b3249dd, - 0x587e73fa, 0xf57c34a4, 0x1b49f821, 0x5c03061b, 0xbcf32e27, 0xb1e6cb92, - 0xd3ddd689, 0xe7109db9, 0x3802ef28, 0x2fb2249d, 0xe59f377a, 0x927e705d, - 0xad6667ae, 0xf8852b4b, 0xa0bcf1b2, 0x83403827, 0xde31a438, 0x11b88738, - 0xd0f9718f, 0xbf1611e4, 0xeedff034, 0x273b0724, 0x706a54aa, 0x3ac4f65e, - 0x8829f889, 0x8f88db0b, 0xf1e24c6f, 0x1fc20ec8, 0x46b1ce77, 0x11b978c2, - 0x971b79ee, 0x6042eaad, 0xf15e6cbe, 0xb579b3f0, 0x78d20f35, 0x8bb58923, - 0xbcec420b, 0x3223c576, 0xaf3c83b3, 0xe02bc044, 0x2a5dc233, 0xa7ff422f, - 0xfa8cad79, 0x607f2ef7, 0xba479c15, 0xfb84a56b, 0x54f9c62e, 0x009cced4, - 0xdf43c0fa, 0xf3693887, 0x69ed0447, 0x00296af3, 0xd73f8c78, 0x4bfb66e9, - 0x427bbc7c, 0x7e7351f2, 0x1ea2f4db, 0x3665d20e, 0x849acba5, 0xd5c8a3fa, - 0x168e462b, 0x7ab9c604, 0xe20bc6e9, 0xe6e17eba, 0xbfe7ba89, 0x74f1e249, - 0x4f6fbf1e, 0x6265489e, 0x47e422bd, 0xaf9093c8, 0x817ce0dd, 0x0702519e, - 0x4f00f372, 0x1a7ea18f, 0x4c5e7b27, 0x8f217962, 0x54afa74e, 0xe79e753c, - 0x0cbc7085, 0x2399f465, 0x6de7c78f, 0x078a31e9, 0xb6c0fedd, 0xe27c7d24, - 0xcc47cebb, 0x9881c843, 0x8c0e519f, 0x21e91bdf, 0xba46c0e2, 0x6721e918, - 0x7e40fa9b, 0x5d939121, 0xb9cb77e0, 0xe8d7caa6, 0x5a7772b8, 0xcbf703f6, - 0x65a4cf25, 0x7928c955, 0xa8572d16, 0x30ad2f4c, 0x1898b8b1, 0x970e5dff, - 0xcb923328, 0x3ec1270e, 0x830ddbe3, 0x0c2f2cad, 0x5c7145f7, 0x9215a78a, - 0xe83f809b, 0xfed04fdf, 0xbd926417, 0x712b7f80, 0xd6fdc50f, 0x9e3e7124, - 0x5fd2e1e5, 0x582e942e, 0x35a70fc7, 0x83473fff, 0x8ab2ecbf, 0x4f5625fa, - 0x153de135, 0xab25ffc4, 0xb93af367, 0xa2b9eacc, 0xfc29d69d, 0x7bfceeae, - 0xef566ff2, 0xcdffda2b, 0xb45ebfde, 0x21dac57f, 0x7fb69481, 0xa357f0f5, - 0xae7f30fd, 0xbbb548c7, 0x62bbf02f, 0xe529eb62, 0xdcf30d4d, 0x15fe3e44, - 0x96ab97ce, 0x8562bf15, 0xb762a23c, 0x67c4f213, 0xdf3b73f0, 0x90f414b6, - 0xf7bc26ad, 0x9ba04a01, 0xc0e2cc96, 0xc6a49e82, 0xcbce17dd, 0x2fbba091, - 0x246635e4, 0xc192927b, 0x61ab7abf, 0xcd47c814, 0x060c1f3b, 0x0ee80bff, - 0x05be14fd, 0xfa50da77, 0x436abced, 0x46705e6c, 0x193d9172, 0x6cdd1af2, - 0x3a724adf, 0x14051dc8, 0xadf6b80e, 0xf4d68427, 0x8035b2fb, 0xfb0f6a3a, - 0xc1659527, 0x986ba478, 0x9cb8fbc5, 0x2e9ecbe4, 0xb8b9bcf0, 0xe061d1f1, - 0x7ed89997, 0xef48693b, 0xe5a13f90, 0x74798fdf, 0x47b5b9e9, 0x3e3ee166, - 0xdc90cfdb, 0x6e838c6e, 0x24179c8d, 0x25603f98, 0x6fdc2ec9, 0x7f1c9177, - 0x307fcf16, 0x1cccbe31, 0xccffb31c, 0x1fbf45e7, 0x870fe70d, 0x375e5958, - 0x710ca79d, 0x89c401b8, 0x33e42165, 0xf55604f4, 0x09177d60, 0xed19f91e, - 0x7624f1ff, 0x336585ef, 0x4c87e5d1, 0xd876664f, 0x21f9656f, 0x12706ac9, - 0x73e4ede8, 0xbb7a01c4, 0xe0a6bd79, 0xf1c50ef9, 0x3c5fcc03, 0xef002260, - 0x01c06a8b, 0xd72d7479, 0x48e7ce2a, 0x4e66bfb4, 0xe3efd17f, 0xc85af39a, - 0xcad078cb, 0xb1162fea, 0xd396833c, 0x5af2005a, 0x952d73d3, 0x93b3f9b1, - 0xf13f9992, 0x78f14a62, 0x3eb043a0, 0x43f8c099, 0xa2065376, 0xbaa579f4, - 0x63f80920, 0xe288e02b, 0xb8ecdd21, 0x3f4bfa17, 0xc3cde14f, 0xafc46ee7, - 0x4a901ce2, 0x66fc3bf1, 0x47ee139b, 0x7829317a, 0xcb41c833, 0x839e1316, - 0x26b9aade, 0xab6b7d42, 0x257901d3, 0x9305e62f, 0x4c5b3e71, 0xc9ad9f38, - 0xa12dd72d, 0xa3e9af70, 0x14f8058c, 0xe92c512b, 0xcec54f20, 0x99f3e97b, - 0xacaf4cc9, 0x7a793134, 0xf589d93c, 0x7e3a25c7, 0x8457bc01, 0x4fce24f2, - 0x75b0b734, 0x0d29a76b, 0xf275f032, 0x25de7144, 0x3c7f832c, 0xbda08cb2, - 0x0353691c, 0xb9538c4e, 0xfd29336d, 0x07661147, 0x08b47d46, 0x0528c3f3, - 0xfda08f0e, 0x04a9b5ed, 0x1e7845e6, 0x4f9c8de8, 0xb28d206e, 0x70dfb685, - 0x74c2b889, 0xe92f1bbc, 0x2ddcbff3, 0x8d14d18e, 0xb62488a4, 0x78f863c7, - 0x00adc4c5, 0xf45894ff, 0x7b018def, 0xe318e14c, 0x49339c30, 0x1bb476e6, - 0x2e7b16e9, 0x8dede447, 0x853dfb91, 0xcd58c0fe, 0x66d87805, 0xfb07bf73, - 0x9506fe7f, 0x46175a24, 0x6a3ed7d6, 0x61537a39, 0x798c94b9, 0x6d1f947b, - 0xadd707c0, 0xfdc3f2ad, 0x62f5d787, 0x81df03fd, 0x7d66b95e, 0x87d80666, - 0x511f4e02, 0x7e033e0a, 0x7e32a472, 0x951f5c72, 0x79c9f5c7, 0xbe429fc8, - 0x9fa0cf80, 0x46606a5d, 0xe50738a2, 0x9fc0f5cf, 0xfd046cdb, 0xb6779fdb, - 0x12b9034c, 0xfce31ce3, 0x2d572c6f, 0x8547b25b, 0x76645f79, 0x4b977466, - 0x3c8c635a, 0xc1852bfe, 0x4d5675eb, 0x1bf1009e, 0x2dfb8a9b, 0x162e3c59, - 0x639d1fcb, 0x59f043f8, 0x51e58d93, 0xa9297e08, 0xbbae2bfb, 0xe2122e4a, - 0x3f1123c8, 0x28cbf04f, 0x61f3187f, 0xd7e61147, 0xe8a5f919, 0x7d015382, - 0xb4bf1ed4, 0x089027c5, 0xc8d27605, 0xb992072f, 0xbf26d29f, 0x5e03b65c, - 0x6497d696, 0xa4fc5d7f, 0x5b47f396, 0x4cacc3ed, 0x5f9f19ef, 0xa8f66148, - 0x41faab4e, 0x5b85e83e, 0x7b902e4c, 0x70b90dca, 0x325d513f, 0x95288efb, - 0x4dbea13d, 0x5b667a61, 0x667a8cc8, 0xc1e3cd9b, 0x161cd07d, 0xa78a241f, - 0x5c9af211, 0x35ce2c5d, 0x0cfcfc31, 0x1aa0bfe7, 0xe212761e, 0x74607f0b, - 0x014b7a1f, 0x9d25189c, 0x1fb93367, 0x00db4a78, 0x6c3dcbf7, 0x7c0d3a2d, - 0x04b20c95, 0x35c74f79, 0x38ad77dc, 0xdbfea1ae, 0x2950fbb9, 0x9e0afdd8, - 0xd76431e7, 0xd062d2a1, 0x37a65627, 0x29fd71cf, 0x4e60c3ea, 0xf70d0fa0, - 0x4c230d15, 0x53ddc54f, 0x1f937c04, 0x77bb8f6d, 0x0635d1a8, 0xef771ac8, - 0x98f711d0, 0x7bdc2714, 0x797bc1e3, 0xe1efeee2, 0x67bc60fc, 0xc7927fa6, - 0xf83f0562, 0x36dd8695, 0xb3276be0, 0xb2ad41c7, 0xa92bcb2f, 0x23fc09ec, - 0x147f0ce4, 0xf7bfc15f, 0x7cf62e79, 0xbe7c2dc3, 0xb614b88f, 0x61a8dd3f, - 0x082fe81e, 0xedc82efb, 0x1e6b6f52, 0x5f4b0bd3, 0x5d7c019d, 0xf98ddf38, - 0xc8a58fb6, 0x2497fcf8, 0x7409e96c, 0xaf182972, 0x92ceaa0a, 0x3df45293, - 0x81f594a2, 0x4eaed4b8, 0xfe3085c9, 0xb5cf56c3, 0x5a513f00, 0x4377c20e, - 0x82141786, 0x580db65e, 0x4a760199, 0x1ae14dc0, 0x8516c9bb, 0x6595c043, - 0xb0f87c65, 0xd6b5e675, 0xd03bec4e, 0x4f47b53b, 0x417be058, 0x39fd60ff, - 0x3e18f746, 0xf947ba00, 0xea1bba40, 0xdc050f02, 0xbff2dede, 0x25c60f87, - 0x87e103e2, 0x76ecbf51, 0x1ff78fc0, 0x73b37b97, 0x6fcf2c1d, 0x24778c88, - 0x9b25f246, 0xb05d8a72, 0xf9d1597f, 0x3e525887, 0xa067ff3a, 0xff766ee7, - 0x04e7f0b0, 0x45cbe4df, 0x234bafd8, 0x2e83de78, 0xe21fb0d8, 0x823cc349, - 0x63060eed, 0x744fdff3, 0x59282ea3, 0x72674d60, 0x1bb5efc9, 0xefd09610, - 0xc715401c, 0x75d7e81d, 0xe2e8bd45, 0x242725f8, 0x03c5ce09, 0x05c95f2b, - 0x019c33ff, 0x8f300fe3, 0xed3ec30f, 0xb951d66b, 0xeb029f30, 0x8fc09ec8, - 0xfa59f7af, 0xaf693027, 0x7dbf9977, 0x4fea33a3, 0x97b8fd09, 0xbfc62b77, - 0xcbf4cadf, 0xcfb66e8d, 0x163d7a0e, 0x801f610e, 0x1487008c, 0x62ba6a9e, - 0x6a1dbd45, 0x11be78a4, 0xd8f4a0e0, 0xf01a9123, 0xee4c8a17, 0xfbf012cc, - 0x8015853a, 0x5ffeb9b3, 0x340e20dd, 0x23fbf43e, 0x9178ef00, 0xe7d2eb1f, - 0x6cfd1ac7, 0xf588ffe1, 0x148ff086, 0x47e1088a, 0x7874fb41, 0xe0e9f14e, - 0x0c8de0f7, 0xfefe305b, 0x5af3ab78, 0x85779737, 0x98bc63ce, 0x572be5c7, - 0x4cba5246, 0x5a3f3120, 0x0a4a05bf, 0x2483f8ff, 0x82f18c9c, 0xe7f80516, - 0x8e449716, 0xadd9f0c5, 0xf875f543, 0xf68aca8d, 0x46fbded7, 0x2242323b, - 0xff1f9b5f, 0x3e83cb4d, 0x47f62fb6, 0x18f7db1f, 0x2bf643de, 0xed0db0e0, - 0x1c3bf6cc, 0xb5070f0c, 0x73ed76c4, 0x4dc3ef2e, 0xef10f98d, 0x4bebb3dd, - 0xee6fa3b4, 0xf05df2fa, 0x569d871b, 0x8767c408, 0x8a981e9f, 0x39a1d271, - 0xf442be78, 0xc6b4fdeb, 0xe473d84a, 0xdfff711f, 0x5b8f0a01, 0x582cf803, - 0xf1f671be, 0x0bbfa027, 0xdbc615c7, 0xcd52fc7c, 0xebe20bd3, 0xc81efca5, - 0xa7f31203, 0x7e01fb44, 0xd6bbdaef, 0x31105e48, 0x3497d2c7, 0xe820bfa0, - 0xb1a9cb78, 0x78fc95a7, 0x98efc0ba, 0x39afbfe0, 0x295edccf, 0x714e97f6, - 0xefbd91bc, 0x4ddb3ee3, 0xe02af735, 0x2394dfa7, 0xb8cc7713, 0xe2569ce3, - 0xfc6b898e, 0x63f06ac3, 0xc4f4bef6, 0xbf8b8804, 0x2f91e325, 0x9fdb686f, - 0x20dea1f2, 0x3377dc27, 0xd0a6f5e2, 0xfdf00abd, 0x97931b38, 0x7e1fc6f6, - 0xeb8fe51d, 0xf984de81, 0x9425837f, 0xdf5d231f, 0x8cdbf5dc, 0xf8f17ec6, - 0x02de8b6e, 0x6f0e82ef, 0x054e2d9c, 0x0747b47c, 0xa6ee9f23, 0x79d3f3f3, - 0xfcfce985, 0xd37b4fd4, 0x3efac0e7, 0x05d60e5f, 0x9feb7a7f, 0x4f3f00cf, - 0x0c98e5f0, 0xeac327c6, 0xb620c89e, 0xf88c9d28, 0x74636eea, 0xc0e9fc9b, - 0x7e3e5414, 0x6ce700d2, 0x536c38ca, 0x57ef1389, 0xbdfcfc24, 0x954dbed1, - 0xea0318ef, 0x8cdf68d2, 0x738a6d76, 0xd7c3de26, 0x6384bdde, 0x2052aadf, - 0x5954b3dd, 0x80fbb0aa, 0xe02e9f99, 0x6ff3d231, 0x09b6eca4, 0x19f0db52, - 0x67071de9, 0x3d353caf, 0x3fc2bc01, 0x4e10f717, 0x78f686f9, 0xd7cf4db8, - 0x7e8d4fe7, 0x5b6ad41b, 0x8ba46472, 0x83e85db1, 0x00a01852, 0x23f83f4b, - 0x48596ce3, 0x1a4bd2bf, 0xb579c371, 0x93e449ae, 0xc642bb18, 0xba7e4777, - 0xb59ec1cf, 0x97154fc5, 0x1193c44c, 0xf6b52be5, 0x55f02b31, 0x8565529d, - 0x6c1babfd, 0x52a45713, 0xb4fe8c3c, 0x5bee0a78, 0x84089a35, 0xce84c6c6, - 0x813885ed, 0x1c5d5f38, 0x7c0253da, 0xc0694fb8, 0x05f35375, 0xf8c61bea, - 0x15a1b599, 0x6ac3f056, 0x0b8c6533, 0xba23481c, 0x6dc7a073, 0x3daaefcc, - 0x9dc13ade, 0x0a73bda0, 0xdc4c9f6b, 0x6768f999, 0x51be3053, 0xf384daba, - 0xf6b92d1f, 0x321f8267, 0xd9afdd9d, 0x7f643f5c, 0xe9b78526, 0x1fd434ce, - 0xba1f6a63, 0x110941d7, 0x3e2177fc, 0xb929996f, 0x95efa39e, 0x2f585d3a, - 0xeb879d9d, 0x655f21b8, 0xed0f1e4c, 0xd75c54e3, 0x2917918c, 0x3cfa6f10, - 0xf5802a47, 0x71a92ee1, 0xe4fc1999, 0xe21c6c89, 0x7ac067f0, 0x19f19df3, - 0xcf20d603, 0x05d5fa88, 0x75ea186b, 0x3ba5b3eb, 0xbf81efce, 0x36f4b04f, - 0x8e51cf09, 0x7f12e471, 0xae94ff0c, 0xfea4f4a6, 0x7650a4d7, 0xe4f1f031, - 0xc40932b1, 0x656df1f0, 0x5d881256, 0xb1f3f20f, 0xde2af52d, 0xf8e42037, - 0x53bfce66, 0xdee865a7, 0x0ede6fa7, 0x886267f6, 0xfcb841c7, 0xd9cb80fc, - 0x3bfd7ccd, 0x1bab93dd, 0xbf308cb7, 0x65a4cfe6, 0x671d2a74, 0x960f4a76, - 0x70d2d51f, 0xe5f07318, 0xcf4083ae, 0x618fa0fd, 0x5a2f2b3d, 0x2390fc89, - 0xb77f00b9, 0xb7edf4b8, 0xe3d7d50e, 0xe8353fee, 0x74e0db81, 0x0faf1c94, - 0x56dfdc84, 0xc710ab2f, 0xe288adb9, 0xbd61fd17, 0x5eaede7f, 0x107cecb8, - 0x5bef86dc, 0xb2a4ec2f, 0xefca9436, 0xae1fa16e, 0x7e815722, 0x3f572318, - 0x4cd2fc01, 0x01399eed, 0x21fb08bf, 0x54a5f3d6, 0xc83f815e, 0xab8c4cd9, - 0xe544b98e, 0x9eba2336, 0xea0be88f, 0xf812b84f, 0x7ad81f39, 0x221df6ea, - 0xd4fe83fa, 0x9fdddfc1, 0xb550a318, 0x75700052, 0xd442fe25, 0x2c571857, - 0x10450385, 0x8739cbdf, 0x42af1b71, 0x5768a7d7, 0x8c7a679f, 0xd2ae0bfe, - 0xf46ffc15, 0x789c4433, 0x7ff08a52, 0x89117cf4, 0x31514e17, 0xa1f8238e, - 0xf208f014, 0x38c6453d, 0x21fc7b7e, 0xe29fffc6, 0xe3c2920b, 0xaf48bd7f, - 0xe083f08e, 0x4617c103, 0x4347f1fb, 0xfb2da75c, 0xf5f29691, 0x1f7f63f6, - 0x7b74f515, 0x6764887e, 0x7363d97a, 0xb5f37960, 0x0fc0d9b7, 0x83f5c499, - 0xf89143b0, 0x17c65ad4, 0x29671bfb, 0x05e46fb0, 0xc51790bd, 0x0adf88bb, - 0x4d58ac3e, 0x9e397e30, 0x7aa6a5eb, 0x8ef3cf16, 0x12900396, 0xec7a1252, - 0xf9675609, 0xb79e822e, 0x5228be70, 0xf7f028f6, 0x49756e5f, 0xb913882e, - 0x82703c79, 0x6078c25b, 0x7f823e9c, 0xc75bf6d0, 0xd758014a, 0xa093f519, - 0x7fde64f7, 0x7df09f1c, 0xdc9f2357, 0xbee5c290, 0x9ffee93b, 0x03c60bf4, - 0x4db53b5d, 0x7b7df157, 0xbe0d9d74, 0x5ed9c82d, 0xfe02bf96, 0xa6f5d035, - 0x3bf60a4b, 0xe7ef4535, 0xf05b385c, 0xf20b5c4b, 0xaf798df7, 0x37b4f9c6, - 0xc7e124fe, 0x8c5ebf73, 0xf2c2b37b, 0xa6768df9, 0xbfc2bb5d, 0x32abd233, - 0x26bfb125, 0xde1c6bf4, 0x8b6dfeb9, 0x5fe9ed6e, 0x53feefa1, 0x2bf457fa, - 0xcf1882ec, 0x5adb97a8, 0xbb3d09cf, 0xe309836a, 0xf5f03727, 0xae3c0df2, - 0xc3f70cfb, 0xdede3c02, 0xf782d17c, 0xb6550653, 0x63dfe53f, 0xd6d038c3, - 0xe97fccdd, 0xfbe2756d, 0xc6324a0f, 0x641c1e29, 0xd74c3d42, 0x3f308526, - 0x3e9098a5, 0x85dacfb0, 0x2b56b3ed, 0xe3d432e1, 0x7e40852e, 0xf1959e54, - 0xfa6f83c1, 0x0fff4067, 0x5a6deb1e, 0x70e37181, 0x4331f803, 0xa7dc140a, - 0x313b334a, 0x6f54dcce, 0xe6aabcc6, 0x03daffba, 0xf9aa277f, 0xf2c17122, - 0x39bd5f66, 0x7a044fb2, 0x96fc8c62, 0xcd11790c, 0x0ef3042d, 0x970b4e47, - 0x06e97ac0, 0xd602b0d2, 0x7635c3e1, 0xa788dd8e, 0xc6de7ca3, 0xbec8847d, - 0x1bcb3d41, 0x79e14929, 0x06fb7123, 0x6fb8250d, 0x15ae48a0, 0xd33ed124, - 0x60df667f, 0xf29ce038, 0x7a0c5ff3, 0x7fb1b488, 0xfb6355b0, 0x54872d4c, - 0x39327e02, 0x5e309995, 0x423eded3, 0xb764eedd, 0x82fb0ed3, 0xdbaf9fcc, - 0xccedc5dd, 0xfcfdfb6f, 0x986296c6, 0xd36ad6c6, 0x47632b4a, 0xe246bb8c, - 0x727c4671, 0xbfedc7bc, 0x61a35c84, 0x63c462dd, 0xe2194b71, 0x4fe29bf7, - 0x13d6c5c8, 0xebe06ec9, 0xb8ba27ad, 0x3c63dc61, 0x3b32e70e, 0xbf7604fe, - 0x326b78ee, 0x6e6ab3ee, 0x5a1bac27, 0x762e2cd2, 0xf3e3110f, 0x78dee760, - 0x3c07fc6f, 0xb935b7ae, 0x337d8fe5, 0xd851f763, 0xc51349be, 0x0faa3eeb, - 0x3cfd5f7f, 0xfe7e03e6, 0x13cc51f2, 0x4c86f85a, 0xadaf102c, 0x85e7e14e, - 0x03f81a03, 0xee3235e5, 0x18b9534f, 0x5625393c, 0x7960acdf, 0x3dd95b34, - 0x99afe59f, 0xf7e9e303, 0x927fafe5, 0x4df6f90f, 0xc00e5bcb, 0xbff01fdf, - 0x33bfb12c, 0x87cc6fe7, 0x95cb9afb, 0x2eb271c4, 0x9d7fe676, 0x034eb3ad, - 0xccda40ff, 0x79605efe, 0x8e6aaa70, 0xd9a5ef59, 0xd31ef155, 0xec492f0b, - 0x5f0a097e, 0xe2bf7dec, 0x7d9c06ef, 0xd5f06249, 0xbbf801aa, 0xb79be583, - 0xbe39c135, 0x5c6623f2, 0x9f3779bf, 0x4b33fbc3, 0xfcc16eb6, 0x4cad6f60, - 0x09d619f6, 0x9b53f3ba, 0x45e430e5, 0xbfb0d455, 0x98eb4023, 0x4c115527, - 0xbdb08e7c, 0xb70b3e73, 0x87eebfd6, 0x2feda83c, 0x9dbec1da, 0x0764d869, - 0xbf7ed3bc, 0xdc62fcf6, 0xc3e0a979, 0xea5e7b5f, 0x5a72610c, 0x379c3762, - 0x37c19cdb, 0x6383c223, 0x78a3faf3, 0x70b9fc64, 0xe067c5cb, 0xd7d9ef3c, - 0xe0067b3e, 0xf9d5f45d, 0x0d7f6067, 0xbd60f512, 0x6ff97dea, 0x7c521e78, - 0xdff72777, 0x117a5e9a, 0xbd3691cf, 0x6f41766f, 0xbb27f54d, 0xa6ca79c1, - 0x82caff6d, 0xfad2deb8, 0x2e77e831, 0xcffd41dd, 0xa2bafb04, 0x83e8326c, - 0x1ab1ceb6, 0x66b7b5e9, 0xf380376f, 0xf06f4a73, 0xdfe7237b, 0x2ecf2c82, - 0x3aadee72, 0xb8e179f1, 0x93356e73, 0x2061bd6f, 0xd40baa94, 0xdde7bb46, - 0x5e3a530e, 0x55fa01df, 0xeaf3cc3f, 0x73efd312, 0xd3a507f8, 0xf3faeccf, - 0xe66b17e6, 0xb434fb3c, 0x79b464d5, 0x01dc2dde, 0xc8f389bc, 0x55eeed63, - 0xd79b9076, 0x85f3c15e, 0x74f1b740, 0x2e5b4da2, 0xdc738376, 0xbb96d4a7, - 0xda836f30, 0x940b8843, 0xf287bfd7, 0x10e3b4d3, 0x3f0969c6, 0x2244dc17, - 0x538e763f, 0x98dcf3e2, 0x71c9cec2, 0x3a39c3fc, 0x39f4e3d0, 0xf8c72f3f, - 0x6ba39c58, 0xbd5cfceb, 0xefbf07bd, 0x77bb13ba, 0x1a87e378, 0x4a20dfbb, - 0x3468692f, 0x3a2dbd0f, 0x00383c09, 0xcf62430f, 0xa73e2683, 0xcc373918, - 0x03f405e9, 0xde722fff, 0x6247d693, 0x248f7a5d, 0x1b4d07d0, 0x26d239d8, - 0xf53df135, 0xad687ce2, 0x9e62ce81, 0x9087c96d, 0xffe0f6d3, 0xc979f8a6, - 0x8bf1d4ee, 0xcbd9d3c0, 0x87f8f589, 0xddbbe976, 0x8c96e36b, 0x607cdaf7, - 0xd3f704ef, 0x98f9e51e, 0xcc5acf2c, 0x96f82cf7, 0xbecf4f94, 0x17fde32c, - 0x517b82ab, 0x85f51b8f, 0xc23597d8, 0xb78739fb, 0x89d996a2, 0x04a5afb3, - 0xb39fb46c, 0x3f21d66f, 0xd51f5457, 0xc0ef8f20, 0x8b1aede6, 0x01f933d7, - 0xc71b113b, 0x9eeafb3a, 0x24dbd47c, 0x97f27e71, 0x437a1f5c, 0x56f1c789, - 0xb38dd39f, 0xfbc41fd0, 0xef1bdab1, 0x0a9ee28c, 0x50699dfd, 0x4cfa3f31, - 0x8d41c590, 0xedcc7fe3, 0x203ee466, 0xcf412f6a, 0x5768fb88, 0x3cf30468, - 0xe79626fd, 0x6a7efc69, 0x00d3c32a, 0xee04b387, 0x82d9750b, 0x52b8b9b8, - 0xd4cdc32e, 0x6c7b9115, 0xf6f7f85c, 0xe4977922, 0x2f309b91, 0x925de452, - 0x50bd5927, 0x613703d4, 0xfe10e51e, 0xdac03fbe, 0xeb4c2161, 0xecf97eb3, - 0x2c7efe4d, 0x3320b26f, 0x9cffcfea, 0x829630fa, 0xd5a67ee8, 0xa049fc4c, - 0x3ebdf82f, 0x22b27f22, 0x3575e449, 0x9ef7f3b2, 0xfa5f9d6c, 0x77a7bb47, - 0x5b73ec2a, 0x552776c2, 0xc6eb4b29, 0x4e2a1da0, 0xfabe2075, 0x03911f6e, - 0xc1ffc1fb, 0x76a707f1, 0xa57f1f8a, 0x6ab7faca, 0xe074dfb4, 0x4025be97, - 0x09ddbee7, 0x831773e6, 0xa3bf4a13, 0x9e7c14cb, 0xfec1c944, 0x073b995e, - 0xd22b1fe2, 0x2c63cc34, 0xdd00b0a6, 0x5e5c658c, 0x72a9aa68, 0xa5c72d1b, - 0xcdc875b2, 0x1ebe4ea9, 0x277f6169, 0xffc2d1cc, 0xe7db184e, 0x9682e597, - 0xe981d830, 0xecbfcc29, 0xdc31f2da, 0xb4eef1ff, 0x37582ebe, 0x7a4c0d4d, - 0x21b7e610, 0xf00933d5, 0xeeb4befb, 0x9b5f946a, 0x34fc0527, 0xfcb1ddc9, - 0x8871f8d0, 0xdbf4fc05, 0x61057187, 0xbc18f763, 0xe955943b, 0xa7c01e78, - 0xae323f18, 0x03d8bf21, 0x13883d71, 0xf11efbf1, 0xce3a7afe, 0xcc26e3f6, - 0xb64a6f8f, 0x59b47bf3, 0x00b608dc, 0x3fc7def0, 0xbef9972f, 0x5f775f96, - 0xa7bb2d5c, 0xb89eee3e, 0x08129e83, 0x8bef1839, 0x3b37de33, 0x4f300494, - 0xdc7f78d4, 0x307ebe08, 0x40f71bde, 0x5d0fb72a, 0xbddd1748, 0x5fd616db, - 0xf03d5beb, 0x09dc1b9c, 0x6b3c5325, 0x4d0c994e, 0x0d73ca8f, 0x3e708fd5, - 0x4e7e75f8, 0xc761ffb8, 0x2d7f003d, 0x79435fdc, 0x1dfc177b, 0x072a2d13, - 0xbb930ffd, 0xb9a75ec1, 0xacd4ff99, 0xd3cb7bb2, 0xbf4058e8, 0xc98fb834, - 0x89c4fa0e, 0x9bfe1b79, 0x3c7bee09, 0xa0499729, 0x92e9721f, 0x5c47ee1b, - 0x3dc7cfc9, 0xf6e9326a, 0xca9d7e61, 0xf96fe3f4, 0xefb1633d, 0xb7a04a4d, - 0xeb654d9f, 0x552cdb85, 0x9f198557, 0x9f740b3d, 0x70a8f26e, 0x599a9b4f, - 0x331c42a9, 0xce4fca35, 0x13e2092b, 0xeecedfef, 0xab5f7f4b, 0x81ebf39a, - 0xef66f3d1, 0xc7814600, 0x6fb8e92c, 0xbee38d3b, 0x4d4ce9d5, 0xd5a7818b, - 0x99dbe426, 0xeadb720a, 0x91e589e9, 0x1f719a1f, 0xcfa688e9, 0x02f71783, - 0xc480fb89, 0x7da2417d, 0x291586fe, 0xe91f1fe0, 0x74e77443, 0xd2ff5c42, - 0xf9039ef5, 0xf3a3047f, 0xa67f73fb, 0xff15dfc2, 0x82f48fab, 0xc5f187bf, - 0x4cdd73f4, 0x73cddf14, 0xd7f8b9ff, 0x79a3ddb4, 0xdcbc04de, 0x1578db9d, - 0x531dd7c8, 0x4dfa41ce, 0xf9bf7cdc, 0x9e3f653c, 0x61250ecb, 0xef3bc23c, - 0x4f180acb, 0xe6f687e8, 0x1d972f9b, 0x2a70bd06, 0x8bde09f0, 0xf626c646, - 0x8dfe8d5f, 0xe71773e0, 0x0db231f3, 0x493356ed, 0x5cac7966, 0x73ee636e, - 0xb37ee273, 0xe209fc9b, 0x98f62b3a, 0xd99fec08, 0xe1778941, 0x87754882, - 0x8af6165d, 0xf5942db8, 0xda1fcd21, 0xb95ea54f, 0x17c42569, 0xc8682fe0, - 0xfa80faf1, 0x56296e2b, 0x4f2bec0f, 0x79d607ac, 0x5a96c056, 0x58607a7b, - 0xdb7e84d8, 0x5f07d537, 0xe281f419, 0x82be2270, 0x605033e0, 0xc43e1fff, - 0x8000938b, 0x00008000, 0x00088b1f, 0x00000000, 0x59edff00, 0xe554707b, - 0xef773f15, 0xc3cdddde, 0x210366e4, 0x804d8404, 0x85701020, 0x5c7c0188, - 0x94422101, 0xd6da0300, 0x02101ba9, 0x16a52d79, 0x9b8cea9d, 0x8e233480, - 0xd29dad13, 0x542cce96, 0x2ec4952a, 0x4dd0689a, 0xd15c04ba, 0x63e02711, - 0xb46d63a0, 0xec083a2d, 0x98f8a71a, 0xe739ec76, 0x647dd7bb, 0xeffa7471, - 0xe5f98617, 0x7cebdfbb, 0xe3cefce7, 0x648a12fb, 0x40a50307, 0x676a733f, - 0xf1d31c02, 0xee016bb7, 0x0d1c442a, 0x00f250e0, 0x007f73e6, 0xd63c03c6, - 0xe9b6dc06, 0xdb007b5a, 0x2ed8c9ae, 0x95d6c801, 0xfc76edf6, 0x06dbb8fd, - 0xbab60173, 0xc00f77f0, 0xf9e9b1f0, 0xffbf8150, 0xbe956be7, 0x16bcea57, - 0x373f4d7c, 0xb772b025, 0xecf7000d, 0xb5ddc372, 0x9d701e34, 0x913ac4a2, - 0x46383668, 0x9dbac401, 0xef289d7b, 0xb1b0b870, 0xddc3db13, 0x5a64d759, - 0x1e17c2cf, 0x40074ec2, 0xf3e36e8d, 0x91bdb05c, 0x35eb8157, 0x87973cf5, - 0x33c685c7, 0xd752e6a7, 0x64df0e9b, 0x4e7dcf1d, 0x9aee5bd9, 0xc1ed1d84, - 0x508fa459, 0x87df2ca4, 0x43b4ccf2, 0xe47b3ec0, 0xf8ddfefa, 0xcb400e71, - 0xcce3376e, 0x987a9cf0, 0xe223df85, 0x8687b43c, 0x817ad35d, 0xb77b17db, - 0xff3d69bb, 0x7c4afa5f, 0x470700b9, 0xc4219dc3, 0x2e98be67, 0x4ec1dbe6, - 0x05e9e7e3, 0xd0402f2c, 0x39170ab6, 0x9c38e1a8, 0x1b0bf177, 0x9ff6b38f, - 0xaab37bd9, 0x222a89a3, 0xfa80031d, 0x3d3b0ac8, 0xa7accf64, 0x676e1400, - 0xfdc14105, 0x528297fa, 0x002bfa89, 0x5dfd82af, 0x01f7f1d9, 0xa73ef1db, - 0x67f61f67, 0xc6e01de9, 0x421cbbf5, 0x8c00d3ff, 0xdf1372e7, 0xc2b2fdad, - 0x65c806bf, 0xea411bbb, 0x0dc077b7, 0x9b7e89b9, 0xfdcb057e, 0xa7f05d43, - 0xcb623b2b, 0x53e23945, 0x5cb1f600, 0xf7813909, 0x169ce4b5, 0x7fb4280c, - 0xa303ecfc, 0x9f7d2e58, 0x7210e487, 0x67aa7842, 0x0dd7cd3f, 0xee96473e, - 0x74f8d2f1, 0x20b3fcb9, 0x9e09f908, 0x55018fe2, 0xd13b3df8, 0xfb855d76, - 0x42de0994, 0xe2fb7660, 0xc4da93eb, 0x7cc4aaf3, 0xfb6d7ebf, 0x1db9e40e, - 0xa9a2afed, 0x70af1073, 0x7c3d39d3, 0x31bca43e, 0x83d0b67a, 0xe394f517, - 0x8cdffd12, 0x52e6fe47, 0xf38c573b, 0x659cf53a, 0x400feca5, 0x8202d0fe, - 0x912af7df, 0x00a937b3, 0xcdaf1fe7, 0x9d73c0af, 0xeb6c0db7, 0xd49f71c4, - 0xd823ca85, 0xfdf3ceae, 0x5efdc75c, 0xaedd6f7c, 0x739fa899, 0x06b79a5d, - 0xe050c1e7, 0x8fa87189, 0xcf346786, 0x007e4923, 0xc445e3e3, 0xfc7df4df, - 0x189eda67, 0x58747e47, 0x1db0b8f1, 0x4813e2d3, 0x47f096ee, 0x7978830e, - 0x078703f8, 0xf81715e7, 0x543f9276, 0x222eb6f5, 0x8e83cebd, 0x0ce23aed, - 0xaf88f81b, 0x0f5c62a1, 0xbb7e1df7, 0x926b5f7c, 0x85753a1d, 0x7dc407e3, - 0x0a916b13, 0xfaffd361, 0xf631721f, 0x24c1f91c, 0x1347bf5a, 0xb5e6b33c, - 0xd238c0c2, 0x631c1b7b, 0x82c7beb4, 0xd9e26af6, 0x775d778c, 0x9fe3491b, - 0x69f9fd36, 0x41710fda, 0xc90f6f81, 0x43e478db, 0xf39d1e47, 0x8009a19f, - 0x4f764243, 0xf97b9ebe, 0xf34fe0f8, 0xee3dbf27, 0x8ffef1a0, 0x7415df91, - 0x079f0f1e, 0x1f23beed, 0xddf078ed, 0xd875e9de, 0xfc2a53df, 0x1dab47b1, - 0xdf5be347, 0x086b34b9, 0x123231f1, 0xd7d4bf8e, 0x86f49138, 0x4d985ffc, - 0xf908767e, 0x69f849ef, 0x8a29f905, 0xaffc415e, 0x8e34f6a4, 0xc18e5dc3, - 0x3d97ec65, 0x44bf2036, 0x203fb3fe, 0x40fdf5ff, 0x781fd1e3, 0xf3f654fe, - 0x419b41ae, 0xf1c600ed, 0xb85edc29, 0x835dda9a, 0x73f6758b, 0x3679f21b, - 0x80646bf9, 0x4c0109d7, 0x5029d321, 0xf648aa1b, 0xa3d63cdb, 0xdba7d4cd, - 0x55d0dff4, 0x9e2f7c9e, 0x53554723, 0xb54f23fc, 0xb502f225, 0x3fdc2bb7, - 0xed0df1e6, 0xc13fa24f, 0x740799a0, 0x2d383bc1, 0x5d4ff9e2, 0x7d6ffe22, - 0x4e8afe65, 0x13d6e73c, 0x13f7f72a, 0xce31ca4f, 0x78193c9b, 0xe536e748, - 0xe7da0f05, 0xfcc543d8, 0x1b6c5afd, 0x1ae74718, 0xba51165b, 0x38eeaaa9, - 0x36bf384a, 0xbc4348b4, 0xa3c1cefe, 0x19f3709a, 0x81eebfc4, 0x29d8675b, - 0x42719dee, 0xfdd88a16, 0x67fdfc55, 0xfadb0f50, 0xf219ff51, 0xf9871e06, - 0x0e3b5007, 0xc7f6478a, 0xdc8e2b14, 0xbc7c4d5f, 0xda26add8, 0x120b4828, - 0xf417da9b, 0x6c01ed6d, 0xc46057df, 0x71bf9789, 0x8d44e2fb, 0x8aafc9d8, - 0xde7b2dc8, 0xe28f30fe, 0x98c3b77f, 0x2ee9fc41, 0x0ca14d83, 0xd74f7d3c, - 0x4e954f98, 0xdfa992d8, 0xa0fc205d, 0x88bb003c, 0xaadd2d47, 0x5fbb441e, - 0xc70d56e8, 0x431f00d5, 0x8a02ed60, 0xb0630137, 0x01bff518, 0xc8031fac, - 0xa6894d1e, 0x68daf641, 0x6b1c3736, 0xd63ca1a8, 0x20e83ea4, 0xa4f8da3f, - 0x55d0e1f6, 0xffc6ee66, 0x27686153, 0x53ff11c5, 0xed82378a, 0xfb527b4d, - 0x7887c21b, 0xa953c35e, 0xb13a9bdf, 0xddb44aed, 0x3a8c5705, 0x997f033b, - 0x42b09304, 0x5c711e20, 0xdc70ecd0, 0xd97dbc89, 0x6f4953ed, 0x3f426d07, - 0x0fd94f18, 0x2cbf2b55, 0x7e287114, 0x2fec8201, 0xf3474207, 0x9df9ae50, - 0x63da5ea5, 0xcff45dbe, 0xfce52def, 0xbaa0f602, 0x65500d12, 0xde9096f8, - 0x176f2f51, 0x9937b9e3, 0xfc7411f1, 0xa6cded87, 0x1e91361e, 0x073635d0, - 0x079ee553, 0x4fb4edc1, 0x3f3c01fd, 0x903c6bce, 0xd7e96fda, 0xb4d3ae6f, - 0x2c7464fb, 0x75287362, 0xfd1e1f9c, 0xa17aa554, 0x73fbf537, 0x5cc09bc0, - 0x60133f4b, 0xeb07e902, 0x97b1802b, 0x8ee4678f, 0x344f97a4, 0x329c5751, - 0xd7fab1d7, 0x41697c9a, 0x344e28f1, 0xf120d505, 0xc8129365, 0xcfb79503, - 0xd7b943ad, 0xe0f0bc5b, 0x3dc7d43f, 0x9bd67ea6, 0xe173e0bc, 0x4a3de6fc, - 0xeff38230, 0xfe553479, 0x25baa10d, 0x79233ce3, 0xab53a9b3, 0x6e7e6073, - 0xb40e2d80, 0x98de48f9, 0x70e800fa, 0xe74afe50, 0xb94f8b4f, 0x6e46dc8c, - 0x5fffdcdd, 0xe22d46ee, 0xf8da7ca0, 0x201bc52b, 0xe27fbbf9, 0xe791b280, - 0x60dbecb0, 0xd73cc4f1, 0x56cf3df7, 0x61d3becb, 0xbab7db3a, 0x37d93bf0, - 0x6f463ebd, 0xc618ff63, 0x9150577c, 0xfcfa4fe0, 0xbd9d6625, 0x5e303774, - 0xcf2cfde8, 0x8362f383, 0x68c079c3, 0x47bca6ab, 0xf149c9ed, 0xcec0ada6, - 0xfe2ceefb, 0x500b63c7, 0x690f4b3f, 0xa0e0ac5e, 0x96ad4ae9, 0x95d373f2, - 0x4e4d14af, 0xe6ed27ca, 0x3687a5f8, 0x9c5165b4, 0x25e293f8, 0x7f858bf7, - 0x40ed4036, 0x829de2a7, 0xc383a3f3, 0x7b202e6f, 0xa5cce714, 0xb77dfcf5, - 0x76c2e8cc, 0xaf1cdf74, 0x17ac49ea, 0x2df38b75, 0x7ce352bd, 0xe724be79, - 0xbf68350f, 0xfb2f6306, 0x9e97f9f1, 0xc79f9077, 0xc62814ba, 0x47c5a28d, - 0xbea00d9f, 0xd270bfcf, 0xa2f84541, 0xa18e93ee, 0x2e03a96f, 0x50885504, - 0x3877b03c, 0xdb52bee8, 0x10c72ff3, 0x7d4f45d5, 0x34bd20e0, 0x471c2af4, - 0x41a8f61a, 0xb47afe0f, 0xf10745ef, 0x8153a5a8, 0xfdc9a531, 0xe663f71a, - 0xc23e7964, 0x092adffe, 0xf933ae7e, 0xe2d3f168, 0xce333aeb, 0xe54f6fac, - 0x763046e3, 0x0dfce096, 0x4f1c759d, 0x8e647437, 0xaabc5633, 0x28ead88f, - 0x4eefd7ee, 0x1bf9b71d, 0x941c061e, 0xd9e3d317, 0xd3878b51, 0x70f11a60, - 0xa26eb238, 0xe97f791d, 0xa844c364, 0x37afa918, 0xe56d7ccc, 0xf5e9cbcb, - 0x0e67ef62, 0xf1fe73ca, 0xfc17df1a, 0x48edffe3, 0xe209c9e6, 0x25b7e609, - 0x3ed94fe1, 0x8b23e135, 0xc0dbbf69, 0xbdfa44d7, 0x53a39c2d, 0x24335bfd, - 0xd85976fc, 0x242a0c19, 0xdbf38d9f, 0x41da106d, 0x3bf58ff6, 0x92f03fb9, - 0x981075c2, 0xd4deac71, 0xdfa9bd77, 0x8d5fbc7a, 0x30f54d9b, 0xfae283ea, - 0x6ea37b55, 0xbf316fec, 0x3476bd37, 0x0cbcf48f, 0x16599c44, 0xb2c67112, - 0xd2279597, 0xd0331cfd, 0x8ddec98f, 0x823c2761, 0x719b97e3, 0xc6277966, - 0xdfa46519, 0x30e6c6c7, 0x423d025f, 0xd8bcf4de, 0xfe3a9dd2, 0x2ba8814c, - 0xf67acd87, 0xd57b34cb, 0x02a721c4, 0x51e65bd7, 0x359e41bd, 0x8ffda768, - 0xe1fe42cf, 0x933dc7fa, 0x397b1ef8, 0xd669bd3b, 0x057b56e9, 0xc3ea8b12, - 0x5b91de90, 0xf737e490, 0x3921d860, 0x01a9e61a, 0xbdd27fd2, 0xd2ecc565, - 0xdd16f78c, 0x1d5fe38d, 0x6bd1febf, 0xc62def92, 0xe1e272de, 0x597f8a2f, - 0x43e29b33, 0x172788a7, 0x7cdd70ab, 0xeb81c3aa, 0x33a77f5a, 0x3f0bf748, - 0xadea88f2, 0xf213c4a5, 0x0b72b0cf, 0xfeeb04f1, 0x4afeb4f1, 0xe146192c, - 0x8af657f9, 0xe2e5647a, 0xaf77994f, 0x46e7164d, 0x74c98dbd, 0xffeab00f, - 0x9d442f96, 0xb16f7d69, 0xa03df10f, 0x6f30ac25, 0x9cbe07bb, 0xc6f28a50, - 0x509f3efa, 0x16eb5887, 0x54f5b479, 0x797d5036, 0xa0ceaff1, 0x74bce513, - 0x1f0fe5f8, 0x2ea5f6c0, 0xf2e63117, 0xc1d95c71, 0x0da2d37e, 0x721d7115, - 0xebbceb18, 0x7c73bd68, 0xc81ee88f, 0xbc40dbba, 0x5137ceb8, 0xb5bb16ff, - 0xa9d71b42, 0x9183b06d, 0x3ae499ea, 0xcac75eae, 0x8d864b14, 0x566bfe66, - 0x7bc42373, 0x57346e2b, 0x883dc625, 0x6b88dffc, 0x533b38dc, 0x5cec08fc, - 0x1b8c8ca0, 0x777b158d, 0xfd5321ba, 0x977ce113, 0xe3dcef5e, 0x24e6de46, - 0x1e2a1b78, 0xde84b67a, 0xa13b4e71, 0xffce94b5, 0xafb204d5, 0x9ceb7e75, - 0x9e7e4ce7, 0xc601fba7, 0x952ad69d, 0x279b65f5, 0x708baad0, 0x7626f31e, - 0xf5483732, 0x17fe8cfe, 0x8d0788cb, 0xb25c7007, 0x7d1da1ff, 0x90438854, - 0x421cdcf9, 0x3ce492a1, 0x74e2ffd8, 0x97d91be2, 0xa6fc9dde, 0xb2e5d37d, - 0xfdc45150, 0xfb88a6d5, 0x287d8f6b, 0xfe4dee8f, 0x306d6ac3, 0xfcd67ec9, - 0x80fe4d7b, 0xefd3dc5d, 0x7c4420a7, 0xd81e0b0a, 0xef2204fa, 0x1a778ad6, - 0x334aca0d, 0x7e442ff4, 0x035e4b7c, 0xea6d0b92, 0x33cce2d7, 0xcb1b49ff, - 0x5c393fe3, 0x03df9c94, 0x8a18eeb4, 0xc04dad7b, 0x28072471, 0x0b1c62ce, - 0xf97b63e4, 0x97ae2ce9, 0x6abb65a2, 0xa9956e38, 0x5b6b7140, 0xc9a9e6ff, - 0x05bfe1f9, 0xe91738aa, 0x95aa98a1, 0xa6fec527, 0x9560da1e, 0xbc17cf79, - 0x7888140d, 0x27a3f782, 0x47ee19dd, 0x6ddeb5df, 0x3d8273ed, 0xfa974ec9, - 0x0dfef9ea, 0x52a6f85f, 0xef9f019c, 0xfd6dc26a, 0xfbe953f5, 0x57cdfea5, - 0xd2a4bbf3, 0x02bf9296, 0xd5315f24, 0x7914ef45, 0xefb9bfb0, 0xd460229d, - 0x276a7e58, 0x6efdafe7, 0x8ec4e751, 0x84fbf164, 0x07826502, 0xdd653930, - 0xb857eea6, 0x55ea688e, 0x583e648d, 0x22dc7af3, 0x1e261e0f, 0x1486b620, - 0x487ced83, 0xf3ef5360, 0x16a34f2c, 0x76b63b62, 0x4bbfa26a, 0x3c97d620, - 0x00ee002f, 0x39feafc9, 0x52754c3c, 0x87964f73, 0x3eb14bde, 0xc4b1f914, - 0xfa8fdc19, 0x99c2f459, 0xcd5b8a22, 0xf50a682f, 0xbbea50c3, 0x679b736d, - 0xbde88fc5, 0xe81575e0, 0xda55e1dd, 0xc4b0ed02, 0x4d54d181, 0x1d66efca, - 0x5f9bb560, 0xc8d4abaa, 0xcb06dbef, 0xe6ce512b, 0x3b4abafe, 0x78b4f419, - 0xb634ba0f, 0x3009eb91, 0x95b65d84, 0x27f0a634, 0xf7290300, 0xb14e506e, - 0x8d61631e, 0x03a281df, 0xfde9ca67, 0x6fe4b9a8, 0x7347e4e5, 0x537bc50a, - 0x554bbd33, 0x7de27c90, 0x4d7f9aca, 0xafb3f0a1, 0x0b7b7f4d, 0x7bcda3bc, - 0x9e1b2ece, 0x4d1aadff, 0x05eb847f, 0x6edd9f51, 0xb7d5cdc6, 0xbc5f5c69, - 0xc78d1e05, 0xcca18a1b, 0xfac8bce5, 0xa78cddb9, 0xe352aa2b, 0xf03dcadb, - 0x91a11670, 0x635b4eb9, 0x0c0abfae, 0x7575775e, 0x6635b8ea, 0x36a6b69d, - 0x56e7fbf5, 0x930c9cdc, 0xc2ea6e39, 0x66c75b9e, 0xb90c7e71, 0x0cdef93c, - 0xb475e279, 0xf541c78f, 0x683c0b9a, 0x1c66e3a7, 0x01c92b6d, 0x177e28f7, - 0xa3fd9209, 0x53bfbed9, 0x719f8ade, 0x34553bf2, 0x1565ce2d, 0x29cd3f0a, - 0x514a7114, 0x9b276ca2, 0xa3ed9c72, 0xed9baf28, 0xe7ec5237, 0x533bc4d7, - 0xfc937914, 0xacc27c8e, 0x788aa223, 0x7b974b47, 0x8778a17c, 0x34dfa11a, - 0x5fd08ebd, 0x36a2de9a, 0x6ec5c751, 0x5ffef856, 0xc519f58e, 0x958bb5af, - 0x14f141a0, 0x2bfdc0f5, 0x54c3d615, 0x62704f88, 0x8f981dff, 0x4d8beea8, - 0xb6fd7513, 0xefe2f9b5, 0x9b780124, 0x64f168ec, 0x57e45d85, 0x286b0f8b, - 0xdf12cebf, 0x6ede9f29, 0x7755d3e6, 0x850af35e, 0xadaf4b45, 0x2f9ca7e4, - 0xb1463146, 0x475e20be, 0x53c7eafb, 0x917d23dc, 0xf32f479f, 0xadc2742e, - 0xa72e7eb1, 0x2fd36abf, 0xa839476e, 0x7adefdae, 0xeba5e734, 0x9530bab3, - 0x2b581887, 0xf2138fc8, 0xc7e6333b, 0x943ca6d5, 0x47e80363, 0xedfd4d6b, - 0x2eadf7cd, 0x0477efc4, 0x7e4c3d57, 0xb3d94675, 0xce2410ff, 0x9d187a4d, - 0x85addeb4, 0x090c3de2, 0x9b7ef192, 0x16f0179e, 0xd7b8e016, 0x54af718f, - 0x241777bc, 0x933eebe9, 0xb161d7d7, 0x079c764a, 0x25de9501, 0xdc3b03ae, - 0x443b6d45, 0x200b88ec, 0xfe81dfc2, 0x4fc45608, 0x9d73fcea, 0x9944723d, - 0xeff8e3c5, 0x9061f343, 0x7108ddc7, 0x3b740346, 0x32f042e1, 0xcb22b956, - 0x08af6ca9, 0x4baa5485, 0x82f64523, 0x5213a8b3, 0x2473a665, 0xb38763ce, - 0xd2a2fd56, 0x0b6011df, 0x3cfd3dd9, 0x0c79d61d, 0x0d4a4bc1, 0x555ca177, - 0x93695210, 0x1548601b, 0x39f32ff1, 0x4ddd6016, 0x01b8b77f, 0xfacd9fed, - 0xebf8f208, 0xa66a3ce9, 0xaf2d0cf3, 0xeb1615e0, 0x29129f24, 0xf39d7db2, - 0x2b11cfdd, 0x6f375e02, 0x03e2fc7d, 0xfbbf8995, 0x9eafc378, 0x2a3d3fa6, - 0xd3f70186, 0x665c4ddf, 0x9fb11add, 0x788f86ff, 0xe17dfd3f, 0x5215dfba, - 0x7ce8f23c, 0x8781f04e, 0xf60638f8, 0xb23f74e8, 0x7142b8d1, 0x128b8fdc, - 0x5c103bbc, 0x2f21b1e5, 0xf2e518ee, 0x43cca5aa, 0xab8d675e, 0xcf7a4ae3, - 0xe14e4d43, 0x91e4c1ba, 0x6aab7f25, 0x2af891fc, 0x8944a251, 0x944a2512, - 0x44a25128, 0x4a251289, 0xa2512894, 0x25128944, 0x5128944a, 0x128944a2, - 0x28944a25, 0x8944a251, 0x944a2512, 0x44a25128, 0x4a251289, 0xa2512894, - 0x25128944, 0x5128944a, 0x128944a2, 0x28944a25, 0x8944a251, 0x944a2512, - 0x44a25128, 0x4a251289, 0xa2512894, 0x25128944, 0x5128944a, 0x128944a2, - 0x28944a25, 0xffe12251, 0x72255300, 0x008000ab, 0x00000000, 0x00088b1f, - 0x00000000, 0xc5edff00, 0x30001131, 0xee300408, 0xd85aa12a, 0xaa66f6b1, - 0x964d2113, 0x5dbbcce4, 0x6db6db15, 0xdb6db6db, 0xb6db6db6, 0x6db6db6d, - 0xdb6db6db, 0xb6db6db6, 0x6db6db6d, 0xdb6db6db, 0xb6db6db6, 0x6db6db6d, - 0xdb6db6db, 0xb6db6db6, 0x3d017e3f, 0x009b1baa, 0x00009b1b, 0x00088b1f, - 0x00000000, 0xc5edff00, 0x30001131, 0xee300408, 0xd85aa12a, 0xaa66f6b1, - 0x964d2113, 0x5dbbcce4, 0x6db6db15, 0xdb6db6db, 0xb6db6db6, 0x6db6db6d, - 0xdb6db6db, 0xb6db6db6, 0x6db6db6d, 0xdb6db6db, 0xb6db6db6, 0x6db6db6d, - 0xdb6db6db, 0xb6db6db6, 0x3d017e3f, 0x009b1baa, 0x00009b1b, 0x00088b1f, - 0x00000000, 0xc5edff00, 0x30001131, 0xee300408, 0xd85aa12a, 0xaa66f6b1, - 0x964d2113, 0x5dbbcce4, 0x6db6db15, 0xdb6db6db, 0xb6db6db6, 0x6db6db6d, - 0xdb6db6db, 0xb6db6db6, 0x6db6db6d, 0xdb6db6db, 0xb6db6db6, 0x6db6db6d, - 0xdb6db6db, 0xb6db6db6, 0x3d017e3f, 0x009b1baa, 0x00009b1b, 0x00088b1f, - 0x00000000, 0xc5edff00, 0x30001131, 0xee300408, 0xd85aa12a, 0xaa66f6b1, - 0x964d2113, 0x5dbbcce4, 0x6db6db15, 0xdb6db6db, 0xb6db6db6, 0x6db6db6d, - 0xdb6db6db, 0xb6db6db6, 0x6db6db6d, 0xdb6db6db, 0xb6db6db6, 0x6db6db6d, - 0xdb6db6db, 0xb6db6db6, 0x3d017e3f, 0x009b1baa, 0x00009b1b, 0x00088b1f, - 0x00000000, 0xc5edff00, 0x30001131, 0xee300408, 0xd85aa12a, 0xaa66f6b1, - 0x964d2113, 0x5dbbcce4, 0x6db6db15, 0xdb6db6db, 0xb6db6db6, 0x6db6db6d, - 0xdb6db6db, 0xb6db6db6, 0x6db6db6d, 0xdb6db6db, 0xb6db6db6, 0x6db6db6d, - 0xdb6db6db, 0xb6db6db6, 0x3d017e3f, 0x009b1baa, 0x00009b1b, 0x00088b1f, - 0x00000000, 0xc5edff00, 0x30001131, 0xee300408, 0xd85aa12a, 0xaa66f6b1, - 0x964d2113, 0x5dbbcce4, 0x6db6db15, 0xdb6db6db, 0xb6db6db6, 0x6db6db6d, - 0xdb6db6db, 0xb6db6db6, 0x6db6db6d, 0xdb6db6db, 0xb6db6db6, 0x6db6db6d, - 0xdb6db6db, 0xb6db6db6, 0x3d017e3f, 0x009b1baa, 0x00009b1b, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, 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, 0x00000000, 0x00010001, - 0x000e0004, 0xcccccccd, 0xffffffff, 0xffffffff, 0xcccc0201, 0xcccccccc, - 0x00100000, 0x00000000, 0x00000000, 0xffffffff, 0x40000000, 0x40000000, 0x40000000, 0x40000000, 0x40000000, 0x40000000, 0x40000000, 0x40000000, + 0x40000000, 0x40000000, 0x40000000, 0x40000000, 0x40000000, 0x00000000, + 0x00007ff8, 0x00000000, 0x00003500, 0x0000ffff, 0x00000000, 0x0000ffff, + 0x00000000, 0x0000ffff, 0x00000000, 0x0000ffff, 0x00000000, 0x0000ffff, + 0x00000000, 0x0000ffff, 0x00000000, 0x0000ffff, 0x00000000, 0x0000ffff, + 0x00000000, 0x00100000, 0x00000000, 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, 0x00000003, 0x00bebc20, 0x00000003, 0x00bebc20, + 0x00000003, 0x00bebc20, 0x00000003, 0x00bebc20, 0x00000003, 0x00bebc20, + 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, 0x00000000, 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, 0x00088b1f, 0x00000000, 0x1113ff00, 0x51f86066, - 0x423ec08f, 0xac9d0c0c, 0xc4b462a8, 0x1818990b, 0x12b102fe, 0x3c430333, - 0x203aded0, 0x2388107d, 0x16181858, 0x2fd610b0, 0x022bd404, 0x2c4062c4, - 0x19b7c401, 0x9cdfb348, 0x1f0f680b, 0xc8037f82, 0x3f4024be, 0x1c360fff, - 0xfb5f40ad, 0x1819d502, 0x8aa06bfe, 0xf2a26831, 0x9bf13519, 0xcf2684c1, - 0x2167c68c, 0x63247fa0, 0x0d75b600, 0x000400f1, 0x00000000, 0x00088b1f, - 0x00000000, 0x7dd5ff00, 0xd554780b, 0x673ef0b5, 0xf3399cce, 0x00fde4cc, - 0x108f0992, 0x2104e034, 0x0432b445, 0x3b69488c, 0xc514543c, 0xf791e109, - 0xb14a3e44, 0x44033bd2, 0x350af808, 0x0380a050, 0xed168d02, 0x06823ca0, - 0xfda2901c, 0x5a1bdedb, 0xcb6ab7bd, 0x880b851f, 0x52d11921, 0xf77ac5ea, - 0xcc9f7b5a, 0xd0049339, 0x9fdffed6, 0xcfb3767e, 0xd6bdaf7e, 0xf7b5ebda, - 0xa441c448, 0x84be421c, 0xfc8471bf, 0xa484205e, 0x83bf52c6, 0xa908a3a6, - 0x2d0867d9, 0xc26425cf, 0x5c64633e, 0x136fcd0a, 0x179a2642, 0xbcb19b0f, - 0xfbcb3373, 0xdd4f6d0d, 0x01c9cb4a, 0x1349d903, 0x49116f92, 0x1467211a, - 0xd146fec2, 0xf321117c, 0xb35b2ccd, 0x426cc8ed, 0x98b797eb, 0x3fb69988, - 0x81e0d7b3, 0x429dc2fc, 0xd439d088, 0x67255c1c, 0x8417fed1, 0x45d9b084, - 0x47e93bf3, 0xd7b15e5a, 0x5dfa8210, 0xaf34b68e, 0x01f3908d, 0x9864b885, - 0xed693bdf, 0x86548405, 0xd16494f6, 0x05bb957a, 0xa9c748b7, 0xc6442cdc, - 0x42ef828d, 0xa8bb40c8, 0x5712b66a, 0x97c39b3e, 0x75c5c704, 0xc742dc2c, - 0xa912fda5, 0x61daf651, 0xcbb2b5bc, 0xf9cf831e, 0x51c71380, 0xd3cf35f3, - 0xdabb6871, 0x2c370497, 0xbe2456b1, 0xf3bf1d30, 0x73e679a0, 0x32df5836, - 0x5daecf39, 0x587ee947, 0x9b686547, 0x7983625c, 0x17e7936d, 0x6aabfac4, - 0x6bcfd64e, 0x9f74a0c3, 0x3d3e3ca6, 0x95c4201f, 0x1257cb17, 0x60db09e2, - 0xea7921fe, 0x63f7d8f0, 0xb3f71124, 0x5c40d9aa, 0x427fac4a, 0x40ddf882, - 0x2b8011dc, 0xb5bbb569, 0xa9d176fb, 0x8985b7df, 0xf31f6dbc, 0xc3ef9a79, - 0x27a70e5a, 0x4d347e61, 0x499738f0, 0x1309fd74, 0x4ab85389, 0x3246b5fb, - 0x7acbdc33, 0x186405ef, 0x888f884d, 0xe25adf38, 0x2ed21fbb, 0x4e9caeb1, - 0x3245fe9e, 0xabbd74bc, 0xfbfed604, 0x57f585c4, 0xb03d900d, 0x2aef6baf, - 0xcb90ce7a, 0xf90292d7, 0xd0d6bbf9, 0x7926932e, 0x0257c008, 0x614015b8, - 0xcb40d07b, 0x4713bbed, 0xe16971ae, 0xc61f3c57, 0x75128c73, 0xcdbce3fb, - 0x4d27cba2, 0xaf838a4c, 0x46e679cd, 0x34f3a79e, 0xd211d189, 0x67c64220, - 0x8b6f882b, 0x9ba465b3, 0x79b3b7c5, 0x85b6ce2d, 0x38ff3482, 0xe685b834, - 0xce4ddf65, 0x4741e05e, 0xa4064916, 0xe98c913e, 0x7000de59, 0x9c5078a4, - 0x03ef2573, 0x68c5fa9a, 0x1f4d225e, 0x0107c616, 0x8e012b2e, 0x481ab534, - 0x6adbac1d, 0x86a70822, 0x05cf4521, 0x9d5a7035, 0x1b94e14b, 0xb1b577eb, - 0x09b8832e, 0x23bc1359, 0xf8526528, 0x1dcdd2e6, 0x23bdf30b, 0xdb4c1c12, - 0x00ce2ee7, 0xa5322a78, 0x32f8ed03, 0xc700bf1d, 0xae38046f, 0x3f18fbe7, - 0x463792be, 0x6079be37, 0xb37c6eb9, 0x38a7c74c, 0x5df829b9, 0x63853e3e, - 0x233f2116, 0x95f1c5df, 0xfc704b81, 0xeb949906, 0x8f74b7c6, 0x7771821f, - 0x437e31f5, 0xfafd58de, 0xd7ea5607, 0xbff5b32f, 0x8f9bbc10, 0xfff5c16f, - 0xd6cddc82, 0x6c47f03f, 0xafda26fd, 0x37477c76, 0xf700c3fc, 0x5fc07dfd, - 0x7e9b7a19, 0xf5aa83fd, 0xf1b137eb, 0xc83e0d5f, 0xf8e1b7c7, 0xd90791af, - 0xc52d07fa, 0x3aa64df1, 0x991693b7, 0x21752c72, 0xfd176bc0, 0x074d3a5f, - 0x45be71d3, 0x422482d3, 0x901ffb68, 0xc5870881, 0xa850df16, 0xf142c97f, - 0x0be316cd, 0x0052b424, 0x38e5afba, 0xa977773d, 0x326d24fc, 0x4bf185b7, - 0x10e9f942, 0x96cebf3a, 0x4fbd2f4f, 0x47773be7, 0x42e0dba1, 0x6ed0247a, - 0xdf8a5f1e, 0x8841e0c0, 0x1daa7b37, 0x7b3793f8, 0xf22c70da, 0x40599f00, - 0xf03d8e70, 0xf1a35e78, 0xbe86bb4c, 0xe7d06c16, 0xbcfa422b, 0x80f1ef3a, - 0x160d3424, 0x3a3afc93, 0x8fca19ee, 0x1f93e508, 0xe9047e52, 0x08792359, - 0x94d38dce, 0x4b59115f, 0x5f70cb57, 0xfe0c48ce, 0x91583667, 0x7dad2f1e, - 0x60832658, 0x640a563e, 0xf24178cd, 0xff9d3e76, 0x089d7c3d, 0x57e022e7, - 0xb4f73d6c, 0x47a14cd6, 0xb2779d2c, 0x31a75dae, 0xf5be0462, 0x963d0920, - 0x7b2ffb41, 0x87d18f62, 0x4fd3c7fc, 0xfd26ba44, 0xf7d74a44, 0xd87e34ce, - 0x733769ae, 0x3f635aef, 0xd3e7de9a, 0xae559f7f, 0x431a77cf, 0xe5ce1146, - 0xa36c810a, 0xa7583ffd, 0xf9c7572f, 0x7db1248c, 0x43dde3e6, 0x049992d7, - 0xfe91fa59, 0xeb64e7db, 0x497ae7a0, 0xca1f383f, 0x9a4ef704, 0x8dea107f, - 0x4b7c7d84, 0xe7b3ef86, 0x90d7ba25, 0x5225f39e, 0x9273f606, 0x25271b9f, - 0x08b753e3, 0x7edfe73d, 0x4711ead8, 0xfc475cf4, 0x4e221fbc, 0x968787dc, - 0x0697bfe8, 0xf0c7d7e3, 0x3e32dfc0, 0x7be6b4f9, 0xe4aef84d, 0xa97c1ad3, - 0xcbaa9e6a, 0xd3ee8457, 0xa1b05fd5, 0xaf3e5754, 0x5e5742b1, 0x2eb0f0d6, - 0x447c1a5f, 0x25a1ff57, 0x0fe574cb, 0x95d6add6, 0xab5f2acf, 0xdbe7dfcb, - 0xef7faba8, 0x72ba6dcc, 0x0e4570e1, 0xd97e37c8, 0xe1499397, 0x135de17e, - 0xf0c42ed9, 0x73f3c558, 0xcf4c0c81, 0x2e985c07, 0xf4a57a03, 0xa9641e2f, - 0x0e697b7f, 0xf78ab9d0, 0xd9758d67, 0xf8f12740, 0xf18f4f1d, 0x03780c78, - 0xe75f50e7, 0xbc40b579, 0x025df740, 0xefd48f3b, 0x97fce67f, 0x6f48e590, - 0xc7a332d5, 0x8b3397ea, 0xe5aa5e81, 0xad9d5e48, 0x58497eef, 0xb21075c0, - 0x08a9fb1d, 0xedd0aa51, 0x3cdd20eb, 0x70188e3b, 0x3e105afc, 0xdef3816e, - 0xf8c02a5b, 0xa7b23791, 0x78f9870f, 0x25be60e6, 0x4762f915, 0x69f25260, - 0xc5e7e009, 0x26605cf4, 0x3e0267a6, 0xca074f4c, 0x5030fd31, 0x607b6987, - 0x0327a609, 0x14ff4c41, 0xbdf4c068, 0x7fa62340, 0xf4c06c0c, 0x4c21033f, - 0x4c1e033b, 0x14d4f1bb, 0x90f903cd, 0x20226fbc, 0x2e1492e2, 0x3372a97f, - 0x5c85f961, 0x2e0bee6e, 0x27defbf1, 0xbc5048fc, 0x2c59beda, 0xa8e83f6c, - 0xf3a50893, 0xbbf6c335, 0x44bcb0e7, 0xdd843f90, 0xbbb2f95a, 0xf483d85f, - 0x9fc7ef6b, 0xf381dce1, 0x9e030def, 0x8af2247f, 0x0b5dba7b, 0xc047ba0f, - 0x86b75e6f, 0xd5fe5276, 0x7c31705f, 0x2e5c06b9, 0x039cf5be, 0x0cc2e8f8, - 0xe6fa79d1, 0x1357d7be, 0x34da75ce, 0xe8b7f1f3, 0x851b17f3, 0x741e4c49, - 0x0e18cc25, 0x9e74e0f8, 0x96fb0c1e, 0xcfdaa981, 0x79d90cc2, 0x85ea193a, - 0x77643d70, 0xd517e222, 0x3fdeb047, 0xf57d1e7b, 0x5ec79b13, 0x47b68a72, - 0xdf507b19, 0x0bc4fbf5, 0xe41933e9, 0xbc6ad268, 0x85aae704, 0x40e5f7fe, - 0xbcc257e8, 0x6c3fafda, 0x826e9a08, 0xe375bbef, 0x552e76d1, 0x7d7683d7, - 0xce449fe3, 0x5941f8a8, 0x6fae09d2, 0x9d9b3556, 0xa89d7e7a, 0x325bfbcb, - 0x0dfe3a9d, 0x4af4a0ff, 0x9c120a26, 0x2b1cd5bb, 0x835b24ba, 0x1bb7e740, - 0x8bee86f0, 0x6af5605f, 0x47d97694, 0x67dc2d3f, 0xe17df3c7, 0x05efae5a, - 0x9fb41b49, 0x70778633, 0xd34ace85, 0x449ce51f, 0x9e32f9a4, 0x39aef553, - 0x7cf0ab7b, 0x94126fff, 0xc8ff3ce1, 0xe70458d0, 0x9b786553, 0x76fba1ec, - 0x80938881, 0xbf205cef, 0x91acdc77, 0x3208afe3, 0x41acb7ae, 0x79516e7f, - 0xf2a79747, 0x9f3f2e8e, 0x3d034b4c, 0x91937e6a, 0xff285e8a, 0x043bcae8, - 0x80bbf627, 0xfe04add4, 0xcdef6a7e, 0x700adcf7, 0xc8a5b03c, 0x6873f347, - 0xbf4a3f71, 0x6427cd95, 0x3aaf93a0, 0x1fb4057e, 0x755c73d9, 0x51f43d5d, - 0x669a870e, 0x85ea13c1, 0xa6459b9f, 0x9f74a9d7, 0x72753a25, 0x7e5c5e5b, - 0xf6fe5c64, 0xc6d7fcb8, 0x908a149f, 0xdefdb169, 0x44f2f82d, 0x478043e0, - 0xf9bc3109, 0xf467fdda, 0x3fe47fe8, 0x44feffb5, 0xffb4ff87, 0xfda9ffdb, - 0xff31ee0f, 0x5ff5bdc9, 0x149e8a6b, 0xdd7b1ce0, 0xe198e78c, 0x7a0839b0, - 0x19ab7f82, 0xf637dcf5, 0xd01775fd, 0x26b3e75d, 0x8e7a6262, 0x93bff280, - 0xdf767bf5, 0x0ffeb75f, 0x8d0b3f2d, 0xb60b7f69, 0xef80fad2, 0x64c8adbb, - 0x184e5eba, 0x2f5d2841, 0xefd1fd78, 0x2e2f2a11, 0x91dee2b0, 0x0f4cbf05, - 0x51fb00ad, 0x799fcb2a, 0x08284071, 0xed979e76, 0x1808c311, 0xa3ed40f7, - 0xad2fee30, 0xa42d1e84, 0xd61375f3, 0xa305fceb, 0x2ee78a7f, 0x24415e9d, - 0xe77e3757, 0xb5241c02, 0xe052f85c, 0xf0e22840, 0xd55ef4a1, 0x8f31e092, - 0xfbeaf800, 0x2e8c60b9, 0x0eff2376, 0x5bc88966, 0x77205922, 0xcb53d7c7, - 0x5540e2fd, 0xb6ec581e, 0xfd53eac5, 0x37cb3e79, 0xa0fd3166, 0x052feb0d, - 0x958d49fa, 0xd597ecf7, 0xcec891ff, 0xac3f58db, 0x53d72d7d, 0x1572e9e3, - 0xe6aacba7, 0xa6f6862f, 0x7f32f55f, 0xa65fbefc, 0xafdd0582, 0x10e6cbe0, - 0x23b5616c, 0x6bef7a82, 0x6d511edc, 0x9e1ea089, 0x3905c7c5, 0x6944f20f, - 0x8ced097f, 0xf404cc07, 0xedd79add, 0x9adfd81e, 0xf33d7ffd, 0x63bdfa33, - 0xf80dd59f, 0x0ffaf350, 0x4c6bdf71, 0xdd02d991, 0x2a1ee8bf, 0x1dfad2ff, - 0x4d9d7e7b, 0xc61d3f68, 0x55d27648, 0x613565ec, 0xcafc9c53, 0xe03e7de6, - 0x98f2019e, 0x3b5447ca, 0x53fb7c5a, 0x45cff162, 0x4417970a, 0x7c88b34f, - 0xa9df6f4b, 0x5d39525c, 0xfdabde7b, 0xbecc4a54, 0xc43f7ea4, 0x1ba87be1, - 0x2e935fce, 0xf2e83d6d, 0x02ebcc10, 0xf3834b69, 0x13f9b6a8, 0x4aed4419, - 0x2e813590, 0xbee032df, 0xa12b9b10, 0x4d4df937, 0x4cc605cf, 0x75de5097, - 0xfedfea63, 0xc28b2381, 0x4f86fe7f, 0xe91ce1b2, 0x199e643a, 0x7f39fd42, - 0xbf1834ba, 0xa0f5dca3, 0x51eb8ac1, 0xe3a4abc7, 0xf5b10bd5, 0x755c6b5f, - 0xaefc753c, 0xcfac9f8d, 0x69f8e174, 0xb8fc7e30, 0x5c753b6a, 0xde7c572a, - 0xd886978d, 0x414b96fe, 0x72c3ce19, 0x947ee122, 0x14797a93, 0xcd8841d2, - 0x74ed4977, 0x97ca9f90, 0x4a5d3edc, 0xf900f366, 0x6901e60d, 0x5ef1c6d7, - 0xfb7fa380, 0x3a520554, 0x305f5c0f, 0x221a16d3, 0x3ca0f9b0, 0x7d414c1f, - 0x777be257, 0xe9fdf026, 0x17b87f4c, 0xb81d39fb, 0xf1c6f313, 0x1437c875, - 0x85a988d2, 0x1ffd3184, 0x8f9c46f1, 0x90238a8d, 0x98f81aa7, 0x0e11c359, - 0xb6245979, 0xe913f87e, 0xcdbf2b38, 0x572ddad7, 0x30e1c53d, 0x580679c5, - 0xbe47d066, 0x08ae5da4, 0xa3f364cc, 0xbe5128f8, 0x517f84e5, 0xc79d3a78, - 0x103826ff, 0x4a7ad9ef, 0x5d056848, 0x7c73248f, 0xbe184c99, 0x5e265c34, - 0xdd3c1d8d, 0x090ef8c0, 0xe83e411e, 0x5fc1fde0, 0x9451e694, 0x245655a7, - 0x7802df64, 0x089270e1, 0x91b7638c, 0xd8047588, 0x5af3a551, 0x1b79c1f9, - 0xa8ecebcd, 0x3a78f2fa, 0xb14bed53, 0x7e70db71, 0xe2cfdfb4, 0xae2cfdfa, - 0xd6aecfdf, 0xbf270aaf, 0x740bddb2, 0x87c058fc, 0xa78ea6fb, 0x7c28f1f0, - 0x113f51f2, 0x429dee2d, 0xd616ae0c, 0x22633d15, 0xc0337fb8, 0xf4e14ce8, - 0xe8e1c278, 0xb29050a3, 0xd7fe0081, 0xfd353b73, 0xed34daf3, 0x7a415388, - 0x99c7cd5e, 0xa1fc6061, 0x9ecff39e, 0xee78cdf5, 0xee6fa8f7, 0xf7a5beab, - 0xe6bef6fa, 0x3e75ed63, 0xd55f955f, 0xff5ffebe, 0xf869711e, 0x52829396, - 0x30ccaf2f, 0x126b7ed0, 0x1dbdfccf, 0x0f5144bf, 0xf7ebfa51, 0x4af802cb, - 0x5832c7f1, 0xa056ddff, 0xf05ee7df, 0xd74996c5, 0x63af9331, 0x14e97366, - 0x86264738, 0x526496a6, 0x5abfbf3c, 0x17709b70, 0xbce8ffe9, 0xbaf3e3ee, - 0x3a4051bf, 0x21917fb8, 0x6ec5eae4, 0x41fe0b35, 0x09d567cb, 0xd3d088a1, - 0x1b4b057e, 0x3e760696, 0x3b4f6e36, 0xeaf1045c, 0x6cde3e21, 0x0c1a4a42, - 0x845bed3d, 0xef2957e3, 0x35dede27, 0x2ed1b887, 0xffcf2f16, 0xe463e419, - 0x91b921c7, 0x46c1afee, 0x31e416f1, 0xfe8dc583, 0x3037fe90, 0xdc2159fd, - 0x2e5047ce, 0xa4040722, 0x573e8bfb, 0xec55d242, 0x33025b30, 0x62f0ced1, - 0xd9a60360, 0xce043c8b, 0x412f6961, 0xa05b7f79, 0xdf0fbf1c, 0xd1942edb, - 0x176ce4bc, 0x6774d3e6, 0x1f7e0960, 0x3fafaf58, 0x644baf7c, 0xd4225cf5, - 0xc3e0367b, 0xea05cf7a, 0x7cf5bed0, 0x3ff301a0, 0xcd31040f, 0x95f3626b, - 0x2fe82a96, 0x11a045fc, 0x18fed1eb, 0x41427aff, 0x2f7c3cfe, 0x79b797ab, - 0x2dd6084c, 0x777e7939, 0x197fe639, 0x377f6108, 0xb5fde0ec, 0xb30b9412, - 0xb3afdd17, 0xce96b863, 0x030fc9d1, 0xe5752beb, 0x3f063aea, 0x6f5750b1, - 0x5890def8, 0xfdf30056, 0xe4bbee91, 0xffe0890c, 0x5cbcdfcb, 0x3b0dcfd7, - 0x15eae8d6, 0xae89feec, 0x4ddec47c, 0x75bbbcba, 0xeeaf2ebb, 0xca65f54f, - 0x5679e9d8, 0x4205f975, 0x2fdb3f28, 0xf4375e79, 0x075cb722, 0x76bca05e, - 0x69f87c2d, 0x5c7083c0, 0x4840f545, 0xb3fcb833, 0x3493ec1a, 0x27d838ff, - 0xecc82fd1, 0x3b734f54, 0x3e40dad5, 0xe0267f7e, 0xc0bafcc6, 0x0c6fcc18, - 0xcffcc24c, 0xdfcc5e02, 0x09bf3123, 0xf00da9e0, 0xda3359f4, 0xe9671087, - 0x525b5d7f, 0x923f2043, 0x32f1c68c, 0xa2e637e4, 0x3f709a5d, 0xb3a70543, - 0x955687b3, 0x7122a6ac, 0x288beb55, 0x9939511f, 0x4e9adc80, 0xefd6bd79, - 0x037f2d77, 0xfef58395, 0x0721b987, 0x258aadf0, 0x0a29c993, 0xcfcda3ef, - 0xfae9da39, 0x432c762b, 0x3abcbb7d, 0x6d20bb28, 0xd3fd067e, 0x0dc4d5e5, - 0xb6e547c7, 0x4b9eff6d, 0x99f55dc7, 0x0f80da40, 0x0107214b, 0x91b376bf, - 0xde58ae72, 0x009cfcdc, 0xd93b34f3, 0xee9d98be, 0x0a79e208, 0xc5710f71, - 0x519cdaf0, 0x7f6e7e87, 0xe825f47a, 0x3c87dcdf, 0x2ee92bfb, 0xe50d1a41, - 0x8a30c46d, 0xf7d80cd1, 0x78582f1f, 0xe791ec04, 0x80b7201f, 0x6bf1e73f, - 0xe74ecbcc, 0x4eeded05, 0x93bb0b06, 0xf36393fb, 0x1d96ff42, 0x9b1b95e6, - 0xe5e89d97, 0x52bccd62, 0x772854a4, 0x4ece780a, 0xf04f1824, 0x79fa6df4, - 0xb2f30d3d, 0x44af3df5, 0xebc02f3a, 0xc4af0e44, 0xfd42f09e, 0x5e0e3134, - 0x6bc37d89, 0x912bcc28, 0xf4230578, 0xebc18333, 0x79fa2999, 0x780d733d, - 0x4179d2a5, 0xaf0e54fb, 0xc2f09ed4, 0xbc1c6a7c, 0xd786fb52, 0xd2979858, - 0x0df1d45f, 0x8e8b60cb, 0xefc0d82f, 0xfb5729a7, 0xd2ca8c73, 0xfddf4f7d, - 0x005150b0, 0xdd40d3f2, 0x3789a4f7, 0x5329f2e8, 0x4ffaea46, 0x9756319b, - 0x58a078cf, 0x3b9acf97, 0x7fbed759, 0x795d34f5, 0x191103fa, 0xcb9a8bf4, - 0xd6f9e3db, 0x7c2f523d, 0x0728cbab, 0x35d7cec1, 0x4163c99c, 0xbd63ca81, - 0x3e8baff0, 0x5b17db86, 0xff436f87, 0x39789fea, 0x1fb40bc7, 0xe0f03d83, - 0x55f7f450, 0x13ddfa73, 0xf3be4668, 0x7c8c204a, 0x6fb71f68, 0x8738801d, - 0x0381823c, 0xd378df68, 0x82788215, 0x19e6dfea, 0xfceb3ce0, 0xfc13329d, - 0x8be69dae, 0xefc8230e, 0x3771d452, 0xa94107cd, 0x8905b881, 0x1f6dea4c, - 0xb7f38dff, 0x9ecf07e5, 0x1d2f7e84, 0xb44cbb34, 0x56af09df, 0xf9a7643c, - 0xdd98f7da, 0xfbfe2fa4, 0x63f7c92b, 0x97e62706, 0x93f97da9, 0x5f8e8411, - 0x00d13bb8, 0x180aa7fc, 0x07f82a44, 0x1f41b3db, 0x05ec791a, 0xfd47fc1d, - 0xfedd65f6, 0x230b1e14, 0x43f752df, 0x7ee84f3d, 0x8538c034, 0x56e3e07d, - 0xe225db89, 0x067f74f9, 0xa7c0b3af, 0xbfe59569, 0x9697eca3, 0xda6cdfcf, - 0xbf9ceb0e, 0xe071d961, 0x1cb767cb, 0x0bbefe38, 0xdbe3a1a7, 0xb9435f54, - 0xe7f36bf0, 0x53dcf07f, 0xbd7e22f1, 0x119b9755, 0x70f9dd2e, 0xbdcef6ef, - 0x7b53d312, 0x57b7d3c2, 0x18587f42, 0x2eaa8ee3, 0x7bdf84bf, 0xd42eb1ca, - 0xd539172f, 0xfdc9b5f9, 0x601d0f80, 0x8545d97e, 0x2fc812e1, 0xbdd1317a, - 0xf95faa02, 0x46834bf2, 0xda345ece, 0x2af0be93, 0xddea91f6, 0xc5ea1226, - 0x4625d23e, 0x48d2996b, 0x578a50e5, 0x2768965d, 0xf5477fe4, 0x986349fa, - 0x12e20abd, 0x62daa59a, 0xbf36ac69, 0xfaca58b0, 0x4d42faea, 0xdfc7c7eb, - 0x817d3127, 0x427f07ea, 0xf5e814f8, 0xe84f5506, 0xae703d6b, 0x0cec3ea3, - 0xbbaf5af7, 0x728d75dc, 0xd2e51ae5, 0x45ffca35, 0xcf29f7e3, 0x55ea66bf, - 0xe058bf9e, 0xd03e074a, 0x76098f45, 0xe064468e, 0x2d0d555f, 0x1adf3f0c, - 0x8ff9009d, 0x7d5abeb9, 0x72f8c439, 0x5cd79588, 0x788108a6, 0xd426e2ca, - 0x49163f7e, 0xe17c6f79, 0x1fd32356, 0x20ff5a6b, 0x73cf80bb, 0x7ce1a93a, - 0x4532e6a4, 0x695f4a28, 0x1bd61346, 0xfe233466, 0xef491915, 0xad8d9f72, - 0x8027e54f, 0xce4fc093, 0x3cc5cc6e, 0xf5f227e5, 0x8e1a93f0, 0x9f955f67, - 0x02f30adc, 0xf3da54bc, 0xf7905e30, 0xdaeebf13, 0xa9c20746, 0xfe80ce9b, - 0xed7e066f, 0x02a63429, 0xf71809dd, 0x4262dd58, 0xa356e439, 0x5eebed8b, - 0xbeac4fe6, 0x03f18bbc, 0x17d38d89, 0x538fc7be, 0xe3a2d8d5, 0x16f83d4b, - 0xff8c578f, 0xf1919f7e, 0xe2848bef, 0xfc4f4147, 0xafa2f150, 0x5b2e6b7e, - 0xdee8f374, 0x767deeef, 0xc6c73ee0, 0x953c7053, 0xa470aa1f, 0x38dbb9f0, - 0x627c27ba, 0x38412970, 0x48fb7276, 0xc98d5f3c, 0xc55edc0f, 0x81e3d9f9, - 0xb5adde3f, 0x38fb5af7, 0x387156c7, 0xd1040eac, 0xf51d242e, 0x5aaec138, - 0x6f07766f, 0x49f0c437, 0xa164d8e6, 0x9d035e62, 0x849525a7, 0x16a6d196, - 0xe7f02b98, 0x2af8825c, 0xfe1d24d9, 0xaf3429c8, 0x288db7e3, 0x13069b27, - 0xe957f001, 0x615f2faf, 0x6b3af164, 0x4b3bb7f2, 0x927fbce9, 0xb820fbff, - 0x6d601dd2, 0xebfda033, 0x63bfaea2, 0xca64dcd2, 0xfcf8132f, 0x72d1b79c, - 0xc1e6f8cd, 0xade4014e, 0x76fa89a4, 0x0cb070f1, 0x8abfeba6, 0x1c524cdd, - 0x20a197e8, 0xc2317662, 0x612230e5, 0x272ae8dc, 0xadcb47e3, 0x95d7a40e, - 0x63ee2239, 0xadb7b713, 0xc81b3b07, 0xfc848a52, 0xeac894cb, 0xb44109cb, - 0x4ec199a3, 0x8a7d806b, 0xda4ede60, 0xeb009f31, 0xb8f2041e, 0x4c9fd70b, - 0x6f412b22, 0xbedf1aef, 0x164fbe18, 0xfe02cf7d, 0x3b6cca5c, 0xd53d8029, - 0xf40a1beb, 0x2c10c1be, 0xcffad174, 0x5085a21a, 0xfd169b2f, 0x39a58931, - 0xd3e4d710, 0xff987ff8, 0xf437963b, 0x912ce7cc, 0x5721fce2, 0x5fcb6a86, - 0x012f3d10, 0x129ca79d, 0xba909e50, 0x09bd4de3, 0x2bf70f10, 0xb1878f23, - 0x2fe93d31, 0x8f4cb9ad, 0xeac721ed, 0xf70537f9, 0x79ba63f4, 0x63f2e3b9, - 0xd8d31fa6, 0x2797fdc3, 0x0ec1f8ea, 0x1d8d03a0, 0x11e4b07d, 0xa4355fc1, - 0xcabf7e91, 0x6dd6bf7e, 0x601a0cbf, 0xf8f1f77e, 0xb3d5220b, 0x22f78f3c, - 0xff744bb0, 0x6cd455df, 0x593bcb3d, 0xf9873fce, 0xc0f9baf3, 0xec045361, - 0xce1eef7b, 0xdcfb062c, 0x51e8c66b, 0x3ff5c82b, 0xfdcdf260, 0x5a331cef, - 0xedefba69, 0x4b9076ed, 0x9cfa724f, 0xd846a24d, 0x0f8f1f47, 0xaafaed53, - 0x55ca8c5d, 0x0f9be046, 0x7f774244, 0x3c1ee697, 0x1c2efa16, 0x8adfb397, - 0x9ad80afe, 0xb12cec2f, 0x16bb4d12, 0x679671f7, 0x45eb34ed, 0x57ad8e7c, - 0xd668f5c1, 0x5b15fb8b, 0x50f082af, 0xfc19fbd7, 0x787ce69f, 0x14fbe8db, - 0xdd7e33f0, 0x5b344ad5, 0xfbf8881a, 0x5a9bc057, 0x8d272f83, 0x00c2e3ae, - 0x5854d0df, 0xf2325b4f, 0x6ff8bebf, 0xf466fc77, 0xcdb71606, 0xf386a7f1, - 0x86fb15fb, 0xe11d8026, 0x220daffc, 0x21e7ddc8, 0xbf7e921e, 0x81343cd8, - 0x73bec55c, 0x2e75db8e, 0xe8095d3a, 0x911d094f, 0xbec00b4b, 0x539e4471, - 0x9a9eb3d0, 0x91ed0f2f, 0xb20ed14b, 0xa2388647, 0x1af71e1a, 0x993f7fdf, - 0x6379c1d1, 0x20e804b8, 0x04e0a2fa, 0xeed55eff, 0x5ed1c73d, 0x247123b2, - 0x710d2f8b, 0x08db473f, 0x908a9fd8, 0x146f1f41, 0x91057266, 0xb0cc46da, - 0x8f52e16b, 0x63fd34ed, 0xed57dcfc, 0x31496cbf, 0xbb720539, 0xfa0f1cec, - 0xc32b7043, 0x1e89b2cf, 0x33f69d83, 0x7f4041b6, 0xdba72de5, 0xaca98e31, - 0xbf409129, 0x472c8f65, 0x9b6d533f, 0xf81da5ab, 0x0f704864, 0x794fe021, - 0x14c7f0b8, 0xb28eeb1e, 0xc3fc807d, 0xb8f32fe8, 0x6fbb1a6c, 0xd0aeb187, - 0xa0f0f409, 0x5cf203cd, 0xbbcf0ce9, 0x205957e0, 0xfe008e45, 0x7d2ceba8, - 0x0e0635c0, 0xd9b0d285, 0x2442a983, 0xa56be50b, 0x4d205112, 0x86648997, - 0xffcfeb7c, 0x6c289cc2, 0xa216e9bd, 0xfebfefb0, 0x8de1e01b, 0x8edeb2cd, - 0x6fe7d619, 0x0be7d16a, 0xcdfcfa23, 0x4ff3e96f, 0xf74941c0, 0x0c2fb5f7, - 0x37f088c4, 0x47fe0085, 0x8588990f, 0x97eaabae, 0x2703d466, 0x9cf0d954, - 0x7305f8f8, 0xde47f208, 0xec08b57b, 0xb4bf954b, 0x6f01b8b3, 0xaf2825f8, - 0x811fa97a, 0x0dff7273, 0x8cb7b544, 0xff64b900, 0x3ed80ddf, 0x9fed3cfa, - 0xe0f8ffd6, 0x947a5fcf, 0xf9f8ffb6, 0x1210497e, 0xdf87d594, 0xef59aabb, - 0x41ba1e1f, 0x2161ff3f, 0x664abe7d, 0x2f0bfafa, 0x187e2ac8, 0xdba5df18, - 0x17f5c695, 0x907f9697, 0x6e20fd45, 0x8182e400, 0x4455efb1, 0xbf46afd3, - 0xe1e9c89f, 0x019dc05c, 0xc88a63e7, 0x85cfeae2, 0x7a0348de, 0x1bc768fa, - 0xe74f4069, 0x4fd04b03, 0x6767bd55, 0xd5e79c12, 0xf0e1bfcf, 0xaedf7a40, - 0xdc82c6a7, 0x0c21bcf4, 0xd3dfa0f3, 0xf8477be0, 0xf4598e57, 0xc91db9fb, - 0xd17def88, 0x30a8457b, 0x7c0e7b43, 0x8ee87c55, 0x383272a3, 0x9de3181c, - 0x0fba5dfe, 0x780d9b55, 0x7c2aa65f, 0x038677f7, 0xa2366c1d, 0x8f7aabdd, - 0xbe3ea091, 0x7bb456ed, 0x813eed55, 0x8dfec771, 0x5e5718a5, 0x61af1124, - 0x664cba24, 0x75ae7a40, 0xb7ec039f, 0x926e7f55, 0xefc81725, 0x78a3fdfa, - 0x548c7180, 0x069a28f2, 0xb2cf494e, 0xa9bff022, 0x57ae7bdf, 0x5f7e3edf, - 0x78d5915e, 0xddaf9225, 0xc97af8df, 0x37688253, 0x5cb25ea9, 0x7d500f17, - 0xfe0651ba, 0x4a0e3f1a, 0xfa739a90, 0x017f0835, 0xeb917f3a, 0x51ce5439, - 0xc3cfa2e8, 0x3cb106bf, 0x80952b9c, 0x1bfeb047, 0x851744c8, 0x3234d547, - 0x032cd209, 0xe42c7bc1, 0xefefe615, 0x7a0473a0, 0x237dd8e8, 0x84bab7da, - 0xc33f5df6, 0xb7c8edfe, 0x07119c3a, 0xb6544dc4, 0xe2ee319a, 0xf2320be3, - 0x37e1658d, 0xdc6f101c, 0x145992f1, 0xf1f5b0a9, 0x8362e49e, 0x37e7f003, - 0x4e19aecc, 0x571d962e, 0x7b9a2fd1, 0x00f8b78f, 0xafcf49fe, 0x273d94ff, - 0x7d678064, 0xe98b9e32, 0xbd8575c9, 0xedaafdc5, 0x42bae452, 0xb3d3c817, - 0x5aefdc6d, 0x72f80b9f, 0x06e197d1, 0x6054a979, 0xf4480efd, 0xed7e849e, - 0x924bd6cc, 0x076c32de, 0x70653a7c, 0xf852762f, 0x945e25cd, 0xf28ee60b, - 0xa48740c9, 0x96fdc59e, 0x51222449, 0xf80cb039, 0xa3cc08ea, 0x59b65efc, - 0xb9a2f8c0, 0xe775184f, 0x69e1c400, 0x1a4e57d7, 0x124adfb1, 0xb37cb4c6, - 0xf802bcbe, 0xa5578534, 0x95e0fcc2, 0xf0718c3b, 0x5a3ea089, 0x930bfbbd, - 0xfd751c76, 0xfaea217f, 0xd1e5973c, 0xfd45fd4c, 0xf70129be, 0xd8c8ffd9, - 0xe65f380c, 0xf8e0f699, 0x985cfc55, 0x7e58ea4f, 0xa00c8922, 0xeba3cfe3, - 0x9e607382, 0x918e8242, 0x92309f2c, 0xdf93c7ad, 0x0eb03d73, 0x36f277ed, - 0x56aaafdb, 0xd61c3221, 0xf20de743, 0x5b47ac37, 0xb3af9aaf, 0xaefd377a, - 0x7690ffb5, 0xf7bb5fac, 0x5fae930b, 0xe7a0cf6e, 0x7dd33110, 0x37cdd758, - 0x71b4c343, 0xe1bdaa23, 0xbac78724, 0x0267e7bb, 0x720d3dbd, 0xd8071658, - 0x8127aa18, 0x032c676f, 0xb7c742ac, 0xc79ddcdc, 0x2ce5a2f2, 0x76b4c83f, - 0x54fe86c2, 0x32fa310f, 0x3329ae41, 0x68438f78, 0x37c54ece, 0x29c744d4, - 0x12d93d93, 0x1e4f75f2, 0xb09659da, 0x6474fff5, 0x5ebab0dd, 0xbf7518e4, - 0x08e10bd6, 0x641d43c6, 0xbd7c41f2, 0x4fc62671, 0x1fb68e12, 0xdd173e07, - 0x5a11e547, 0xc1f0a36f, 0x6de3b071, 0x5645cbbc, 0xdd067cd0, 0x1b77e01f, - 0x502f5205, 0x4bda8cb8, 0xa3d01be5, 0xd4378ef7, 0x4cdd70d8, 0x6dd6b06e, - 0xfa47fb03, 0x0123f943, 0xb930ef5f, 0xdd741e70, 0xe5a34d0f, 0xb983cb19, - 0x384bff60, 0x0ede6a1a, 0x8b70efe7, 0xa74bc61b, 0x6127b1b0, 0x7fe700da, - 0x023c2906, 0xc5319574, 0x88ec1235, 0xffac1ceb, 0xd0f0d154, 0x46539054, - 0x28d27cb2, 0xfb8ed9e2, 0x49c716b3, 0x30499137, 0xf20ef83f, 0xb3d6ed17, - 0xc4349107, 0x5d4275f6, 0x3e9f8c21, 0x7064a588, 0x8bcbca06, 0x9eaa7cb8, - 0xf7f59f6f, 0xea3f0024, 0x3f01f7e2, 0x201279b3, 0x1b1c8c8e, 0x9fed6a26, - 0x0345fd6a, 0xdf50e93c, 0xc124597f, 0x287fe464, 0x5e67fa5f, 0xff857b42, - 0x1a824cb2, 0x9cbfec3e, 0xd777cfa4, 0xb1f6c34b, 0x4a12167a, 0x839eadee, - 0x11fd7484, 0x7f2d7f7d, 0xec24f5e5, 0x77698c8f, 0xe9d91c80, 0xdb3e476a, - 0x46831215, 0x1174f7aa, 0x9dc1f182, 0x6d5df64e, 0x265339df, 0xa2679411, - 0x40474fd8, 0xb2630881, 0xf413f5a9, 0x1eb7561f, 0x35ef8129, 0x7ce30da4, - 0x1256c26b, 0xdbffc5ec, 0x970b0011, 0x3f29fce6, 0xfdd4ed8a, 0x9037b588, - 0xb38fd690, 0x52222da2, 0xeab75a5a, 0xc00a2bd7, 0xd3947704, 0x2b37f04d, - 0x72d1b73c, 0x23a3a883, 0xba6ea8eb, 0x275f3242, 0x061d181a, 0xe262bb7f, - 0xaf3c9a6d, 0xf83edddf, 0x291309bb, 0x602a8ddd, 0xf55d9fed, 0x972c6fef, - 0xae807c62, 0xd76bdb3f, 0xbcb895e4, 0x6b87e68d, 0xf2b8cef2, 0x8cf2b894, - 0x567f7cb8, 0xc91ec3bf, 0x1ca9b836, 0x13f7eab7, 0x3a4fca24, 0xa9b32332, - 0x309e4f04, 0x226133bc, 0x6a8f8dc4, 0x5a79c0f3, 0x59b82adb, 0x5f830fb8, - 0xb9e19bad, 0x832eddcd, 0xaa3adf7f, 0x7688b8ed, 0x7209c12a, 0x27bc2da6, - 0xe7687982, 0x330bb4d2, 0xfc3aa4fd, 0xb3ebb601, 0xe9117cff, 0x87fe4d7c, - 0x765aef58, 0x8faf9274, 0x6e2bef83, 0x3be0b770, 0x92bd026a, 0x77bf9144, - 0x992ff9ec, 0x7c633fdd, 0xf3d333ab, 0x43adf206, 0xb7cb5382, 0xa41f30fc, - 0x0e5c65e7, 0x935c7062, 0xb886517f, 0xb787f78d, 0xa9c703be, 0xcb27d175, - 0x73fb1e40, 0x20d1d9cd, 0x1f2d809f, 0x217af4f8, 0xd6f18664, 0x7861a18b, - 0xc866adff, 0x7a05d111, 0xf016fb7c, 0x75574417, 0xda4ffc22, 0x284007db, - 0x9755c5fb, 0x7db53e59, 0x5dc7ec0b, 0x009b7f0d, 0x0e4f1ef7, 0xd2201f68, - 0x8355a5fc, 0x487e6227, 0xf7c816fb, 0x3f2c1c53, 0x81807dbc, 0x0921cfb6, - 0x76ff6113, 0x8abf193a, 0x3967bfe7, 0xf7e755ff, 0x29cf7f4e, 0x66a90b80, - 0x1c0b7dfc, 0xed9f94cf, 0x73b538ec, 0x9d9fdd17, 0x9fc8cc4b, 0x10bc6429, - 0xe1ce938f, 0xf20ee78c, 0x8df50953, 0x926b384c, 0xcf68fb62, 0x7f21736e, - 0x0f6ea1be, 0xb3e9d79c, 0xff3f900b, 0xac99ec87, 0xfdd2c6a4, 0xfad29a36, - 0xe3271593, 0xed1106a7, 0xda8fe99e, 0xda78fe51, 0x0561d6cc, 0x1b534afe, - 0x7c2b8fdf, 0x4c4c571d, 0xdf24b91f, 0xdacdfd81, 0x950cf946, 0x240966db, - 0x309c80a8, 0x81394655, 0x3341a3aa, 0xdc5537cd, 0xddd27180, 0x335ad2fa, - 0xd0a9bfce, 0x26760993, 0x9a693f55, 0xd44cc9ea, 0xdb4d65c8, 0x67cab958, - 0x5e69729b, 0x12102e73, 0xad9779c6, 0xbb424dcf, 0xf3eec4bc, 0x743b5fac, - 0x573c1afb, 0x9b3ae1a7, 0x68664312, 0x2fffc2a7, 0xf0c93dfd, 0xbef57efd, - 0x7507df28, 0xd30ac9dc, 0xec0cca87, 0xf1527e3c, 0x44cb3ae1, 0x39a208cf, - 0x4d03279f, 0xa448e068, 0xfdf0d1f6, 0x8c7843ff, 0xa3fdf586, 0xf1daf8f0, - 0x84fc71c5, 0xa0bb8df2, 0x67259aff, 0xf30cdc79, 0x5df0a9bf, 0xe98c442f, - 0x77b06f8c, 0xd077e804, 0x3e4c0abb, 0xe753b42f, 0x1ad1fb3d, 0xf5d4d794, - 0x60787f58, 0x9d99dc12, 0xc5fe795d, 0xecfdb49d, 0xf775591f, 0xa4be5581, - 0xae46bde2, 0x11eec618, 0x4fbb29ab, 0xe80a7208, 0x3aeaed77, 0xc4264f24, - 0x18afaf8b, 0x609e8228, 0x828ff805, 0xb7432efb, 0x9c18132f, 0x9caa9e60, - 0x08bb8843, 0x2953b3d6, 0xf97d86ae, 0xa05e2952, 0xf071b2a4, 0xa75e097c, - 0x03d78dfd, 0x7aeae779, 0xfc72610d, 0xefa604a6, 0xd0f10249, 0x8dffcdf9, - 0x811adb71, 0x13e21f03, 0xb0bb30b6, 0xc357972a, 0x79f74ee9, 0xe7e3973e, - 0xc17e3973, 0x1deea306, 0x3e908a82, 0xbcd89a4f, 0x523eb9aa, 0x9fb0da45, - 0xbd7d66aa, 0xd82faa6a, 0x83bf701d, 0x8690f1ca, 0xf9eae5f5, 0xc2f96fe1, - 0xa0f77fa4, 0xa361f711, 0x09f1c999, 0x8fb93d23, 0xb5fc7f01, 0xffcde511, - 0xc2a2fbe6, 0xf1624061, 0x8b5f00c3, 0x9ff84441, 0xec394916, 0x95c0676f, - 0x93307831, 0x02f5a76f, 0x9aaf35bf, 0x361f01cb, 0xffcea22b, 0x64628f78, - 0xcce5c37e, 0x4fbd1e9e, 0xc8133b46, 0xffbd5ac1, 0xe7d54539, 0x10ff72d7, - 0x129a33d3, 0xa9bedc99, 0xe9077049, 0x2b4d277c, 0x5ff800af, 0xc021699c, - 0x3d72e76a, 0x746a42f3, 0xfaadc031, 0x76bb4bbe, 0x7c37d011, 0x74be022f, - 0xc7ecd18a, 0x967fd172, 0x0fb3fe00, 0x7cef8c43, 0xfdc0eb48, 0x9dab6098, - 0x4f1355c5, 0xefda3ce6, 0x6ee9d5a9, 0xe3533b88, 0x641d4e49, 0x46f5cbfe, - 0xf3dc096f, 0xfa63ee0d, 0x574687c3, 0xeb23dc36, 0xd011caf2, 0xd744cbbb, - 0x7b2025d6, 0xaaf6b61d, 0x5a9ff85f, 0xfeae7180, 0x23dfa5ca, 0xfdd3d157, - 0xbd3d7a2d, 0x61b34493, 0x07ca9b5d, 0xfc742386, 0x6e61d6ce, 0x40cad666, - 0x93ad4be3, 0xd54d3dd5, 0x7187bc3a, 0xbdf088c8, 0xff91fede, 0xf0fc7ed1, - 0x684bf06f, 0xef681fed, 0x7a43dbd0, 0xfabed9e6, 0x7e674d5f, 0xeff2b892, - 0xb093becb, 0xf93fb50f, 0x0825c9eb, 0x37d228d7, 0x3e7a6469, 0xa144779d, - 0xb46f4fed, 0xdda77f23, 0xf9fdbde1, 0xbe053654, 0xd194b393, 0xf486f55b, - 0x4837606d, 0x57eac89c, 0x768a186f, 0xfedcb184, 0xea40df3b, 0x133ba015, - 0xa1390069, 0x696ae4cc, 0x9c63c4d7, 0x5bd267b9, 0xbcb45f40, 0x0dabca1e, - 0x82fcdeec, 0x8da2b6b6, 0xecc22f30, 0x02cde5c3, 0x78c53881, 0xdad115fb, - 0x3560a889, 0x80cdbc36, 0x55d83f4a, 0x55df63f2, 0xbf79ee3a, 0x3d26efe5, - 0xbf2a82dc, 0x7abd31f1, 0x9ff83a70, 0x901c7a54, 0x48cc95e8, 0xe074ae07, - 0x3e0c67a7, 0xe02c97b4, 0xb82b1bf7, 0x478eaf9e, 0x3be30df9, 0x281fb70a, - 0x2d70aecc, 0x47daa3fe, 0x0f403b54, 0xf294b3be, 0xf37d119d, 0x0aea421d, - 0x80f84ed1, 0xd2740dcd, 0xfe70ff83, 0xba53eea6, 0xd8d0f8cc, 0xd10321a5, - 0x6497b9c8, 0xcd3697cf, 0xa3ffe2b9, 0x826eb8a2, 0xb40c97bc, 0xbe365c81, - 0xf70a91d2, 0xcebf98dc, 0xdb3c46da, 0x662df7e8, 0xfed02f2a, 0x90b871ee, - 0x0cc8647f, 0x97928c0f, 0xa2f2d214, 0xfb9436e2, 0x09c4a9a3, 0xc6decefc, - 0xa762dffa, 0x3b4246ed, 0xdbba77c6, 0xa2dea42b, 0x2afc5f69, 0xe9725fbb, - 0xdfed1da0, 0x734b1297, 0xbe748f80, 0xa77e476a, 0xba53bbfa, 0x8958d5df, - 0x1e1db9eb, 0xd5854a45, 0x3d03f715, 0xfb93088b, 0xd86277b1, 0xf46358b9, - 0xe9ff00e5, 0x9644d778, 0xe08b7ed3, 0xbc54a231, 0xef0257b7, 0x2ebed536, - 0xca486400, 0x8216772b, 0x5864d91d, 0xf7428f74, 0x34b0c4a7, 0x576d08fa, - 0x04e6c033, 0x9cc4c293, 0x7de7fd3f, 0x5ed1ff34, 0xaba7de23, 0x266139d8, - 0xa2fad1d8, 0xa2fbf8ff, 0x7975bf74, 0xbcbabfba, 0xbf9f45bf, 0x814f6cd7, - 0x36942cfb, 0xd8cf70dd, 0xb73baa64, 0xf4d7ce8d, 0x354dc99a, 0xd9b37211, - 0xe81980f7, 0x071e8c5d, 0x3a729978, 0xe17c8046, 0xc044fd6f, 0x559250f7, - 0x072f80ff, 0x9992e7e8, 0xf3efb3c1, 0x9eec289b, 0x6967551d, 0xc36d94da, - 0x597a68fd, 0x6f8c0908, 0x045d194f, 0xf7e130e7, 0x97183c4f, 0x265367e5, - 0x4cfefc4d, 0x68437ed3, 0xded79c19, 0x5c27bc72, 0x856bcf4b, 0xb87177e6, - 0x8b47d557, 0x53445ee0, 0x3061a4d2, 0xc90be92f, 0x0abbfb0b, 0x17c8d13a, - 0x3fe2cdcb, 0x115a3f76, 0x2d89efe2, 0x7b873a07, 0xf8e9e39b, 0x0cf8bee3, - 0xe8532ee3, 0xc9cfc030, 0xee376656, 0xfda21652, 0x43ae6fda, 0x44b8d5bf, - 0x60b5d709, 0xa0242d80, 0x9f20991d, 0x3932260c, 0xcb41611a, 0xffb986cf, - 0x0b4e0e3a, 0x9ab930b6, 0xbbe033ec, 0xc1400b31, 0xd5fbb902, 0x700f18a9, - 0xc9a7f376, 0x5b6e01e3, 0xbb0270ef, 0xccbdf5a2, 0x8369e78f, 0xada4bbf7, - 0xbd0172df, 0x6262db1f, 0x765448f3, 0xfb8f7ec1, 0x837280c2, 0xc81f1224, - 0x67b24d0d, 0x6b91d018, 0x8012cef3, 0x59a9d9eb, 0x517fd622, 0x37184e20, - 0x7c1a4971, 0x5e48205f, 0xfdfa3f46, 0xa26bf753, 0x05c99939, 0x7f782b86, - 0x4db4d8fa, 0x3e3dcf18, 0xc6f7f367, 0x8d3b7f42, 0xd2846f78, 0x3e703dc7, - 0xc0f5d0d4, 0xbcb66a7c, 0xb38cc693, 0x628a4484, 0xa3fcdbef, 0xaab26074, - 0x07975c78, 0xf2c16c7c, 0x3bed3cba, 0x78f03d1e, 0x1b9ba533, 0x166078a9, - 0xaf2097c8, 0x35ea4ff7, 0x1e5e293e, 0xc54af555, 0x6d3b3c4d, 0x08f3d768, - 0x329d3f94, 0x4e47c84b, 0x27ac6599, 0xf3616dfd, 0x3f105cef, 0xd02dfbeb, - 0x60f10e5f, 0xea2b853c, 0x0ee2a62c, 0x69cf0080, 0x9fc599b2, 0xf51f73d1, - 0x44a9f5a0, 0xffd1aef7, 0x3a51fde5, 0xb2f0077e, 0xc72bddf3, 0xd9b5ae01, - 0x8f40231d, 0x0cfe5ff0, 0x56b65eed, 0xb9b4f766, 0x0d9e64bd, 0x992a7be8, - 0x83e3105b, 0xcfe3377e, 0xd1baebf1, 0x63f16462, 0xc7ec5129, 0xd7f4656a, - 0x4df6f5c4, 0xf7a82c4b, 0x99094a6d, 0x955fd261, 0x573f54ce, 0x2a63b705, - 0x7b415e3b, 0x4e09090e, 0x2e296bf0, 0xe55d2746, 0x3fcf11b3, 0x882831da, - 0xd1e3bdf9, 0xf1db65af, 0x8040c35c, 0x83f30b53, 0x0eeddcd9, 0x3b47df58, - 0x7d60394e, 0xb80c3be5, 0x27d0f2ee, 0x620af369, 0xf049bd74, 0xfaf3c15d, - 0x46b59d0a, 0xc768fb4f, 0x6d7369a7, 0x730a4f4c, 0x706f417b, 0x2f1952f9, - 0xc65c2858, 0x751d9839, 0xf7c453dc, 0x386de232, 0x4f6f6b5b, 0x6af3b0b5, - 0x0dc9859c, 0x7ad0d6e3, 0x7c618788, 0x1ebe29cf, 0x57a32079, 0xf8fc6d3b, - 0xb4441be7, 0x26ac56a3, 0xff3d6768, 0xf46c81fc, 0x903cee6b, 0x5f53473d, - 0x6f8c3f8d, 0xf1616d9f, 0xa7f1a41f, 0xe20d251e, 0x7378d83d, 0x2007cabc, - 0x3b86909f, 0x1e38fa3c, 0xbd4d130a, 0xa7c40dae, 0xefd58a0c, 0x01dcff2a, - 0x5a736a71, 0xb413110d, 0xa70678f7, 0xebcbbc80, 0x2f77f7c7, 0x45a123c7, - 0x5ac93d40, 0xfa3e4510, 0x1134f9b5, 0x4d3e5a6c, 0xe324f7f7, 0xf0e3d1d3, - 0x19d813ee, 0x6b933ce1, 0xf5c8126d, 0x5e182b69, 0xa2207f45, 0xc435ddfc, - 0xf9522f52, 0xb0cace45, 0xb14aff01, 0x01acb8b0, 0xbf58f959, 0x1a679efb, - 0x4999e7bb, 0x8a7e30ea, 0x1f51db38, 0x38863fee, 0x580d0e41, 0x41911c98, - 0x830c1bdc, 0x7a3c9820, 0xf10151ea, 0x8e7c03c4, 0xa9ea0a88, 0x3f185f14, - 0xfa33e477, 0xf952f0e6, 0xa02ad0a8, 0x92db371c, 0x862bf5c8, 0xa3c2d757, - 0x3c62ffd9, 0x778ea05a, 0x12e478bd, 0x5be1f5c8, 0x1fc2761f, 0x845fb828, - 0xf0a771fb, 0x3628a67e, 0xb880af7c, 0xf1dd1d8d, 0xcd9fb464, 0xfd04de54, - 0xf62bb541, 0x62ea515b, 0x76b6e07e, 0xdface790, 0x7c5cf052, 0x05cb6c5c, - 0xcede3a79, 0x11367748, 0x533801ce, 0x1f94bd61, 0x5797fb30, 0x9d71fbc6, - 0xe21b8f01, 0x44880607, 0xcfdf3e02, 0x35ef8b90, 0xdd380bf6, 0x59dc182b, - 0xbb1e631c, 0xb12b5c0f, 0x075942fb, 0x1772c912, 0x5f4cc7c8, 0xcb8eface, - 0x78b52e0d, 0x225346ff, 0x7ea987b3, 0x69ecbef7, 0x9f4f41a4, 0xcbad5daa, - 0x537e174e, 0x0659ce0c, 0x85049f3e, 0x41ee4fdf, 0x35c00ae7, 0xff510c6d, - 0x4b3e4036, 0x14fe37cd, 0xae957bcf, 0xbd9d7b55, 0x736b9bc0, 0x7abb9213, - 0x8be031dd, 0xb8e7efd7, 0xfdd5e57f, 0x025dff1c, 0x9e7a0e7e, 0xb4c39776, - 0xe6ab39e9, 0xae12203d, 0x21cac7b2, 0x11695ece, 0x2575fb78, 0xde5c4877, - 0x3ee7f1c2, 0x3caaef06, 0xf1ba266d, 0xe293f3b4, 0x629087fa, 0xdfad4b9b, - 0x5bfa1138, 0x83e79237, 0x5f83d41f, 0xbea369e7, 0x6f29043f, 0x029a990f, - 0xc9f07fd6, 0x1a9fc741, 0xe1ef3b1c, 0xa97807fc, 0xf7aafee7, 0x44de34a6, - 0x3f3ab2c7, 0xf50778c5, 0xf4a7f6fc, 0x24e22f7e, 0xff5fe3e7, 0x761e841d, - 0x261693ca, 0xc90096df, 0xf9003d51, 0x17a97fb2, 0x9ca825e3, 0xb7cc21f1, - 0x338eddf3, 0xe7796847, 0xf78fcfb4, 0x7d6e3c03, 0x31e83678, 0xfa03b7e0, - 0x501b37f1, 0x055a55ce, 0x462d6f86, 0x7f1517a4, 0x7f1c9d2a, 0x7f788312, - 0x3090e9b0, 0x5445ec1a, 0x9bbecd3f, 0xd5b165ee, 0x31c70173, 0x533fdfea, - 0xeccad953, 0xe2fcfe56, 0xffd0798d, 0xf9c0810e, 0xc3ff26bf, 0xbfa8b9b4, - 0x4f36907c, 0x65a2aed3, 0x691f8b1d, 0x470af636, 0xfa606ad9, 0x1e7dc1dc, - 0x43e70be0, 0xca4b1618, 0x906ad0a5, 0x45cbcb57, 0x8546efd4, 0xbe43ef4a, - 0x2026533d, 0x5c587787, 0xd3cd1e6c, 0xe42f1083, 0xbf81ffa7, 0x7e77936a, - 0x3347ca29, 0xd5c41b15, 0xce2fcf9e, 0x5795fb44, 0x061c0276, 0x926537bc, - 0x149ef80b, 0xadb4b8c6, 0x2091b6b5, 0x83efadd7, 0x63693ecf, 0x782f5cfb, - 0x7e67df83, 0x5bb5a271, 0xf930b4e5, 0xe4cac32e, 0x867bf541, 0xb79dc995, - 0x0026db05, 0xda961c3a, 0xfaf720ad, 0xd013e789, 0xe6d7894b, 0x0f7089da, - 0x129ddea3, 0x4d3da170, 0xfc7f6949, 0x4dbf2826, 0x223b38c2, 0xe3033fb5, - 0x894eae76, 0xfc850bdd, 0x6f680523, 0x1beacc7b, 0x14e3a562, 0xf3b27971, - 0x10859de0, 0xe1ce38d7, 0xe824c9fa, 0xed0973e7, 0x8a9ee33a, 0xf8004db6, - 0xd9903e7d, 0x08e895b9, 0x9376b9ed, 0x9e93ad95, 0x92ef286f, 0xfbf237c3, - 0x1d9eb40a, 0x5a16f1ba, 0xb8de4153, 0xfd18f458, 0x24694c6c, 0x7d549f80, - 0x9282bb40, 0x872025e2, 0x4a96084c, 0x271cb718, 0x71e04c87, 0xf4a4881d, - 0xfbc7317b, 0xe1777421, 0x558a2dfd, 0xc7265ff5, 0xaeb792e4, 0xa3e090cc, - 0x8a88af2a, 0x1399ed0f, 0xc6085a67, 0x1e8cafd3, 0x9e2ec117, 0x0a7af942, - 0xf160cbde, 0xb32ff9a2, 0x466120fb, 0x3ffeddb7, 0xa8fd1da9, 0x7e56ad93, - 0xfc33d7ae, 0xb7186d21, 0xb0900940, 0xd6cf68fd, 0xfd5057de, 0xf27f6a86, - 0xad8f6672, 0x7c17f6e1, 0xdf9696f9, 0xb2ed556d, 0x467e75cb, 0xf0bedc75, - 0xc6aac2ab, 0x804b4453, 0xd507a31e, 0x4a4f8a78, 0x8cfa2f00, 0x5778e0a7, - 0x78f572db, 0xd195bf0a, 0x4f1d37c9, 0x913588f1, 0x11f44bc5, 0x471f114f, - 0x911999d1, 0xda4b5ed0, 0x7d04eeb7, 0x7e84c5bc, 0x6f2d29db, 0xcbce11fe, - 0x43090a29, 0x5cbc56dc, 0x5f4d35e1, 0x75def80e, 0xc056cce1, 0xef7775c3, - 0xb03f3377, 0xd7885e5e, 0x7cabb60f, 0x1b73cb97, 0x1fa7d7ad, 0x29bef5a8, - 0xcbe54eb9, 0x5187ae7e, 0xb9c072fa, 0x23d383b3, 0xd1c41250, 0xdd6dcbc5, - 0x1c9c7ef2, 0xd19eff11, 0x9d6f69a4, 0x61a47bc1, 0xa87100b3, 0xde0919af, - 0x63ee0dd3, 0x85b56dfa, 0xc3ea93f1, 0x2ca9fdec, 0xe3ed1793, 0xf22315e4, - 0xf9e57f0d, 0xfd114497, 0xdc00af04, 0x27e5a653, 0x5faefd40, 0xd50e901b, - 0x85b690f7, 0x2a74fc98, 0x94c88c5f, 0x79c1b7ce, 0xa13ce30c, 0x3d741bf7, - 0x31f18fd9, 0x5ae837ee, 0x9706fccd, 0x6033e3cc, 0x330ecaf3, 0xb7197ffb, - 0xf14aafff, 0xae8332fd, 0xc64ff16b, 0x1e75dda3, 0xd65a61f1, 0xc71bb7a0, - 0xbfccbdec, 0x78af0554, 0xcc05fbb3, 0x8fb1a7df, 0xae523bc1, 0xce18a906, - 0x5ce25ca5, 0x15d97c0e, 0x16fdd0a4, 0xbbf9eb4d, 0x802882c3, 0x4ead213c, - 0xac7ec0b1, 0x012717aa, 0x45eb05bd, 0x5bb88f7c, 0xd7e7e00e, 0x29ffce25, - 0x8e3042c8, 0x77f3d69a, 0x96fed57b, 0xa9023111, 0x9574b028, 0xdbd49a53, - 0x57f6a8b9, 0xc653ac6f, 0x4034be83, 0x25ecbb44, 0xe01333d9, 0x8f29297a, - 0xbd645c40, 0x1261aebd, 0xbf1c472b, 0xb17a8e64, 0x1312dbfc, 0x092b88d8, - 0xfcdbd9f8, 0xdb878edc, 0x3838c6bc, 0xe3f3d9c6, 0x88cb3ee3, 0xa0e6686f, - 0x6f92719e, 0x69733e73, 0xbfbf2e4d, 0xaeaee0c0, 0x067f597f, 0x4b007137, - 0x9e280e07, 0x303ffb09, 0xa04d8651, 0xd223b329, 0x07fce095, 0xef053b7e, - 0xb7cfc513, 0xc023841e, 0xbdecd5ab, 0xff3aaf8f, 0xddff79f8, 0xcce9c69a, - 0x5f780193, 0x3df194e6, 0x17d96baf, 0x705cb972, 0xd6a1fe2d, 0x07f806fb, - 0x1b578bd3, 0x13adbc78, 0x97bc08f9, 0x04a77f08, 0x9e08aef7, 0x79d5a1df, - 0x06d5aeb0, 0xc27e1f7c, 0xef9e1b74, 0xfbd987b5, 0xdb4b3576, 0xad9ce1b3, - 0xf7c76e2d, 0x0de1e36b, 0xfe5495b3, 0x49cdeb43, 0x1c6ef821, 0x79fbd069, - 0x3cb3fa7a, 0xd3e03645, 0x37aec8c6, 0x654338e9, 0xd7c858df, 0x02ee8d2e, - 0x91e3b579, 0x5e404af7, 0xd26f539b, 0x2792a7c5, 0xd2227ef4, 0x65768490, - 0x5effa4d2, 0x5dae39be, 0x2351bf0f, 0xd97ae3e2, 0x7be80c37, 0xd3f9839c, - 0xef88a549, 0x01db75fc, 0xe1ce1a9e, 0xeed3cee7, 0xee7d03ef, 0xef67ad2f, - 0xf77aef59, 0x2fec02f7, 0xbe6ad7dd, 0x7df617bf, 0xb7f60f2b, 0xf2b7cf63, - 0x1bd77f60, 0x3f403d1b, 0x0f9f153b, 0xefa73cfc, 0xa39ca2f0, 0x0b5c45c6, - 0x275d172f, 0xe6fa2e5e, 0xe7aaf2f0, 0xcaa6c05a, 0x5ced5f49, 0x9ead3f83, - 0x218af87d, 0x34bf4668, 0x3d98ffc3, 0xf077fcec, 0x0a2cb95c, 0xabe8f7e0, - 0xae5c51bf, 0x104850cc, 0xc54513ec, 0xe8aed8ed, 0xdc809173, 0xf179caa4, - 0x9f09f870, 0x4f36f3ff, 0x5f879c02, 0xce5aeed7, 0x4fa128eb, 0x43b9fc99, - 0x6bbb3370, 0x1dd5c598, 0x9d82752a, 0xd9885cf5, 0xb1f76b5d, 0x422bea77, - 0x5df0446f, 0x09c156f3, 0x8ec541fa, 0xeef01c0f, 0xae4e2690, 0x448ce819, - 0x9deceff5, 0x40729d0b, 0xb79d1bbc, 0x6b78e415, 0x7a06544a, 0xf1172da8, - 0x295ab3dd, 0xb5bcf18a, 0x241dc429, 0xf5ea5f20, 0x6c2e352d, 0xba465793, - 0xdecad4d9, 0x7d934ca1, 0x0f11fdb9, 0x6dfbe3fb, 0xb7edfd2a, 0xf800fe79, - 0x7ad3f31b, 0x8b576c5a, 0xc32ff91b, 0x617fe636, 0xccd97fe5, 0x6e3502e4, - 0xce8ff544, 0xf3eef1e7, 0xf83bbc79, 0xf81a236d, 0x9b56df82, 0xd5b6fd57, - 0x88322f10, 0xe5b56df9, 0x8d687edd, 0xae5b56df, 0xe889178d, 0x93234df8, - 0x310b0d77, 0x25d2864e, 0x579163c6, 0x88ced505, 0x74a7e9f4, 0x0c6464b0, - 0xf0fdd57f, 0x12b87f97, 0x3cfcf3e2, 0xf01ab2ee, 0x61c60477, 0x5fc04c46, - 0x355f14c3, 0x4b6a2efc, 0x7d7374e4, 0x37e8c8f6, 0xedf1df4c, 0xe3c7573f, - 0xb3aead74, 0x02ad5d7b, 0x75b8c3a3, 0xf189ebc5, 0xcf5569f6, 0x4bdf16bb, - 0xdf1f5fb6, 0xabfdeb53, 0xfdb65ef9, 0xbef7c39f, 0x47fffb29, 0x3034c6ae, - 0xe87b3e05, 0xd083df87, 0xad8312a4, 0x4c9477fb, 0xae3fe1d7, 0x437062d9, - 0x21cd4ddc, 0xaaf21bbb, 0x7fde323f, 0x94f64958, 0xfde3c800, 0x5710d588, - 0xfedae831, 0xb77b62c4, 0xfb573d5f, 0xb151785e, 0x61bf5f9e, 0xa7d934fb, - 0x02e2d3c1, 0x82f7e02a, 0x24148ab7, 0xa9f638da, 0x7eb7e676, 0x9fefbf83, - 0x88069321, 0x6eda7893, 0x14467bc5, 0xa62e306b, 0x6e9dead8, 0x9afc0d1f, - 0x83d9efc1, 0x0b8812f7, 0xc618d67e, 0x1ac13efb, 0x5727de1b, 0xff6a23ed, - 0xa97ea96f, 0xcd73e06b, 0xcd73e275, 0xf1cf8c37, 0xe3ab17ed, 0x61dfaf5d, - 0x06918503, 0xb3f1e3df, 0xf17d76af, 0xef765581, 0x91d23b72, 0x5eb9ef07, - 0x11e8ff2f, 0xf1b92987, 0x4dc41d5e, 0xfc559c42, 0x74f7a87e, 0x6b70b954, - 0x97a1fb9f, 0xc57eb707, 0x3c96b8fd, 0x0de2a4f8, 0x8f4f7ac1, 0x3e81e4f7, - 0xeccecabb, 0x0ccd9b2e, 0x0c0b372f, 0x13e07b1f, 0xe2a3efbf, 0xf5fb01d5, - 0x7ad43bd9, 0x78fe6aff, 0x2d7c2ed4, 0x69fc077b, 0x886c90f1, 0x7d767be2, - 0xfe9ec7f2, 0x5977162e, 0x517a86dc, 0xef8090f4, 0xf6f3ab33, 0xd63b31b7, - 0xd45c39ef, 0x1cb8fbef, 0xfcf0e398, 0xf10a9ec1, 0x8f028a49, 0x59028c3b, - 0x2f28e40e, 0x0da9378b, 0xda8fb8b3, 0x70e304a5, 0xb511fbd4, 0xc809532d, - 0xbecd0b6d, 0x55fb433f, 0x8682d9ef, 0x4fa3b004, 0x75a72023, 0x37f2cbbe, - 0x401f7d9b, 0x3b697fb9, 0xa69bfdda, 0xa138c79d, 0x5d3f2fa2, 0x3a5df609, - 0xa40bb45f, 0xd3f7f498, 0xc7c60e1d, 0x50ead4d4, 0x7b41ebe1, 0xfb950778, - 0xa7f2de40, 0x5f609c78, 0x56cded50, 0xe1da1b57, 0x6732f76b, 0xad81915f, - 0x9fda3c87, 0x8ef6d1f9, 0xe415fc2f, 0x9042e6c3, 0xb7de8b57, 0xe3a8fda1, - 0x138c2c91, 0xbbeacc78, 0x1f6af80c, 0xe40bba15, 0x0e3a1ccb, 0x7b1dadc8, - 0x79842aee, 0xe0a17d77, 0xccecbaba, 0x24f5d0bf, 0xcaf88999, 0x665dd1ed, - 0x9f022786, 0x666ad76f, 0xba1e0a9f, 0xdd03bf91, 0x38368f6d, 0xd1ecc746, - 0xa5407cf1, 0x08fbeeff, 0x1ff414b3, 0xbd61fcab, 0xeaa39d91, 0xeece77f9, - 0x3c16f1e2, 0x2a75aeae, 0x79e0d78b, 0xf8554f1b, 0xe3bb6f3e, 0x9cf3ac1c, - 0xdec7fa5d, 0xe24cbec3, 0x2fd8e7fd, 0xe36939c4, 0xdfe0add5, 0x53897b01, - 0x37b2bc46, 0xa1dfe610, 0xf9f20578, 0x09b6d16d, 0x839d7409, 0x01b7229b, - 0x165f0fbc, 0x53a0bbd9, 0x92f78b7f, 0xde360413, 0x57da27a0, 0x8afb050f, - 0xc36fedf3, 0x9d1abad6, 0x5b92e0c5, 0x870ef668, 0xd52241b8, 0xc578c3e5, - 0x3c5918ef, 0xda2b21df, 0xabb29a09, 0xbb691273, 0x684cf7ce, 0x03e789af, - 0xcb241a6a, 0x606f8e31, 0x0ed01fcb, 0xe82bdf6f, 0x93a6a6e0, 0xf7e6361c, - 0x6095b609, 0x296dc9ac, 0x0e6e77ec, 0x7f041fbd, 0x5f1ab4bd, 0x46f52486, - 0x7572088f, 0x7b411970, 0xa72690e4, 0xc395fb08, 0x0eba44e3, 0x1f08cfff, - 0xddaa9f9e, 0x64a9843d, 0x7a095f6c, 0xfdacb495, 0xc7ec20f6, 0xb6b144de, - 0xd68bfa00, 0x12b27c32, 0x5a739f38, 0x95bf2d06, 0x9c1a73e6, 0x7aea3fe8, - 0x0de30ab5, 0x439d7483, 0xa167597a, 0xdce5c583, 0xa520e3c8, 0xfc115643, - 0xb85ad2d2, 0x5341440d, 0xd29671ef, 0x129c43f6, 0xc38e7de2, 0xd4f00b37, - 0x5902f9ca, 0x9c7f4162, 0x6d78625d, 0x8bdef25f, 0x55bfcf10, 0x1d4fef66, - 0x34e37c3d, 0x96addfb4, 0xc6ab5ed0, 0x74e02e51, 0x47de13dc, 0xe0725e31, - 0xbf303fa1, 0xfa0b1d0d, 0x3f0c8c97, 0xf829d5a4, 0xc87fe07e, 0xfd0b8c3e, - 0x80c47d76, 0xe9e728fe, 0xaeb92667, 0xebc4b7ad, 0x891ccb29, 0x622e295f, - 0x3d9be399, 0x3fdbe24f, 0x55f78eae, 0xd7a210f5, 0x63e87acf, 0x5c7572f1, - 0x0ee4befb, 0xf542ee35, 0x504f1177, 0xcc526f17, 0xbe8a21c7, 0xef0b6abf, - 0x50a3c78f, 0xf205c439, 0xd70ada4e, 0x8ebf8832, 0xdfa098fe, 0x09978d46, - 0x9738b316, 0xbde0a8a0, 0x88d20cab, 0x48fd3271, 0x1ed01044, 0xd3b6e2c6, - 0xb6865e21, 0x8818ef5b, 0xee216ffd, 0x41f20306, 0xa4abbe17, 0xfdd055c6, - 0xd3243a41, 0xc13f1e64, 0x566b37f0, 0x70e2085a, 0x9f7edcfd, 0x7f1f2b35, - 0x3f135567, 0x33feecc1, 0x7d4f882d, 0x10aa53de, 0xd6253df9, 0x1710d36f, - 0x4d7ff3de, 0x693e6bb5, 0xe2e3ed67, 0xaa38542c, 0xfc2a1671, 0xf14c7bd4, - 0x79314c70, 0x57bc02df, 0x7dd425e3, 0x0d8fdeee, 0x55d82ecc, 0x1cbbe221, - 0x155d7f6a, 0xdc83679f, 0x626adc50, 0xefd712f8, 0xaefbeea6, 0x67c63321, - 0x96bd7df3, 0xdfbeaa1c, 0x23bf9475, 0xd7bf8c75, 0xc21665de, 0x399f8006, - 0xc9381b3a, 0xee4784f6, 0x5d817b84, 0xdc3668f6, 0x78dcdc2b, 0xa7cc24ff, - 0xfe424f46, 0xc3ff84b5, 0x5ba243f2, 0x89e19ee1, 0x1e58b3a7, 0x908b2e70, - 0x49848e33, 0xe07f82c1, 0xe3d73a5c, 0x022e1a77, 0xfb486b1c, 0xd3b436ca, - 0x146973f0, 0xa26463e3, 0x44ecc429, 0x13ffdc2e, 0x631dec99, 0xbdc0fe5b, - 0xdfde506d, 0x5a2df684, 0x627bf88e, 0xee5678c8, 0xfa4dfb62, 0x029c59db, - 0x13d33dff, 0x1fd1e3b9, 0x4df8035e, 0x462b85e5, 0xc740989f, 0xe1b420bf, - 0xee27593b, 0xe00161f8, 0x8ffd85eb, 0xe2b9060e, 0x77f7b94e, 0x72731ee1, - 0x7ec8c239, 0xa34de5f7, 0xf9409acf, 0xb3ad1fc3, 0xff69124b, 0xcbc79333, - 0xe0ef3089, 0x51eef8f3, 0xc4bfdf2a, 0x4bee4c19, 0x2015e89c, 0x3363f17e, - 0x1f54b3a3, 0xe2063dfb, 0x3ddc219b, 0x12d7235c, 0xc4113bf6, 0x7b804ae7, - 0x68eff108, 0x6b5e12dc, 0xf7f73900, 0x780ce881, 0xfefd5552, 0x38f7a107, - 0xc604828b, 0x5c19a6c7, 0x141f01c3, 0x29cdf1b1, 0x2bc6c4b7, 0xfbf17048, - 0x70a375c5, 0x51ba86dc, 0x28f4c7a0, 0xd072d1b7, 0xe5a09e93, 0x97297bc3, - 0xd67afb78, 0x938ef35e, 0xa974e01b, 0x2fbc03f4, 0x04eb38b4, 0xc27647be, - 0x0ef03c48, 0xfb93304e, 0x0739e8f5, 0x273c7dfb, 0x3b4fc591, 0x40704c37, - 0xffdb107e, 0xfd0848bb, 0xb06653bc, 0x21df597b, 0xb4edf56d, 0xfa199dde, - 0xcbb963df, 0x277fcfa5, 0xc29f9f5f, 0xebbe07e3, 0x1eff7fd6, 0x0f804a89, - 0xffa31fdf, 0x441797dd, 0x0be0094f, 0x2f8c27e5, 0x2aee3c0a, 0xf9c20845, - 0x2c81e37e, 0xc61a9ef5, 0xf5c0bdb3, 0x7fbf3f11, 0x91aa6701, 0x8586e3ae, - 0x1bdc9dec, 0x93928833, 0xf92bfc04, 0xf07bbe08, 0xa729f711, 0xf4789bc0, - 0xd713a97b, 0xf419e2af, 0x1f7c3b75, 0xe2e0cf9d, 0xd2538321, 0x418eefd8, - 0x6b2309d9, 0x84b1fc1b, 0x7d684e7c, 0x3e2c6ff3, 0xf184bc62, 0xd7ab0277, - 0x4ff86665, 0xfefc524f, 0xe21ede53, 0x27c89caa, 0x4abfdc2d, 0x8be85df0, - 0x78d8d2a3, 0xfa8b0f1c, 0x5bc01629, 0x7cbb5df5, 0x1bf6e127, 0x7069a64a, - 0xe794103e, 0xfd54bc54, 0x3c380348, 0x7f327e28, 0x1f872671, 0x06f7f091, - 0xcfda8932, 0xadc61374, 0x04bafcf1, 0xde2a6f46, 0xb5ec7fae, 0x5f00a737, - 0xc03f5c12, 0x3bb2ee7e, 0x74f9bd61, 0x804999ac, 0x78d829bf, 0xf449e707, - 0x247927bb, 0x8c5d8798, 0xb09a1b18, 0xbf7f307c, 0x4fa4fa6c, 0xfe1a4866, - 0x61adfb45, 0xfdf55afd, 0x459ba3c2, 0x68337e9a, 0x7e9a49bf, 0xf2c2689f, - 0xbfe5fbbe, 0xe7e92147, 0xaf8fb6a7, 0xf3f5ea4f, 0x7c7dabec, 0x14f7f53d, - 0x4df87326, 0xf329e356, 0x640f71f5, 0x7e615b8c, 0xc39c7d6c, 0x8edf1c9b, - 0x306dff5b, 0x09250be8, 0x2844a70f, 0x1a524c3d, 0xf408dbeb, 0xd0fa461b, - 0x802ff5d0, 0x7e652e2e, 0xb6fbbf80, 0xd989e078, 0x97a519d0, 0x7ba309dd, - 0xe7c547ce, 0x3c5179ee, 0xf1543c06, 0xdd9e7e38, 0x30bdfc78, 0xa16d7206, - 0xaaa407f2, 0x9d48423c, 0x0d70eb80, 0x2283ad88, 0x87528961, 0x22b37ff3, - 0x33bdf388, 0xff8c19f1, 0x3be49319, 0x799af302, 0x3dec27d3, 0xa1d28c93, - 0xf9d10720, 0xfd484d1e, 0x355f377f, 0xe1dc796e, 0xbd82373b, 0xe3ee9bb4, - 0x5fed5ce8, 0xf234d395, 0x2af73b15, 0xf2be5545, 0x19642900, 0xe57cb832, - 0xacd678c2, 0xf10dcb80, 0x8af91aaa, 0x44d547c9, 0xeece07bd, 0xa060fced, - 0x987abe5e, 0xb76ebc60, 0x271a557c, 0xede3cd5f, 0xc42092a7, 0x93d936c5, - 0x805e2c42, 0x162d39ce, 0x8db4dbff, 0xb74d8dc9, 0x82419cb8, 0x33d31672, - 0xe87bf166, 0x6bde4cb9, 0x77c98fba, 0xbaea1ce3, 0x6b78fa2c, 0x133567ee, - 0xb8b12f2a, 0x99abb40c, 0xa5d97d9d, 0xb53576f4, 0xf202ffde, 0x007f0832, - 0x00007f08, 0x00088b1f, 0x00000000, 0x7de5ff00, 0xd5547c09, 0x73b9f8b9, - 0x64cacb67, 0x109848df, 0x424e3b08, 0x875b3612, 0xe22948b0, 0x3cb888b0, - 0x4240b21c, 0x3eb44196, 0xc33fedad, 0x0d220222, 0xc168d46d, 0x2a14180e, - 0x0431a0d8, 0xa4587049, 0x141a87d0, 0x2f1f682d, 0x48145840, 0xad88a0c6, - 0xbefbffcb, 0xef726e73, 0xf6b42264, 0xfa7fb6ff, 0xef7397b3, 0x6df3be59, - 0x39ce5be7, 0xd78deec3, 0x1ec658b1, 0xacc630b4, 0x98eb458c, 0xb19436b3, - 0x96eff0ef, 0x95e5e7ae, 0x6289e63a, 0xa31574ac, 0x47d7e5e7, 0x7a83cfa6, - 0x4c8c7697, 0x66e783cf, 0x92d433b3, 0x50e158cd, 0x2fa18a7b, 0x7b46f963, - 0x9b19933a, 0xbeb45e64, 0xcc9eba19, 0xd393f516, 0x5b09fb18, 0xcf074c74, - 0x48ce9151, 0xc8673fac, 0x287a2967, 0x0379f8b3, 0xfd8c611c, 0xc28f675e, - 0x19b98cf7, 0x718535c2, 0x4398a6b8, 0xf870f2bd, 0xa5c340f7, 0xfe8c8196, - 0x1c7183be, 0x4b6f6726, 0x1155630c, 0x67971fb5, 0xa35cf631, 0xe2b6e6c9, - 0xec1496d7, 0x11deb18f, 0x043086e7, 0x543ce185, 0x39e814f0, 0x4cb2d13c, - 0x040bf4f0, 0xc65e630f, 0x68e0ba72, 0x94ae8437, 0xb1e0a97a, 0x00d17eb3, - 0xc7be24a7, 0x06895ab1, 0x6a5383f3, 0x1257e3fc, 0x33d38fd4, 0x63265877, - 0xea97981b, 0x1ce75efd, 0xb3c6e381, 0xb8e1894a, 0x112b6c2b, 0x96e0dd4f, - 0xbf30c901, 0x1ec977d9, 0x0ae60c13, 0x7ace1f09, 0xd4fb3d61, 0xba7f1804, - 0x2af67f18, 0xac0884c7, 0x78e25d37, 0x00ffc2f0, 0xfbe219fe, 0xa9b2c6f4, - 0x3198e00c, 0x13ba70c1, 0xa66ff83e, 0x0181ba65, 0xc2a6b39c, 0x7bd7737b, - 0x61d2209c, 0x2cffd28e, 0x6c39bb6d, 0x387267cd, 0x10191696, 0xd5ee735f, - 0x09669f7e, 0x42173e8b, 0x077c076d, 0x60603af3, 0x79f68f34, 0xe609b3cc, - 0x82cc56f1, 0x3347f7f5, 0x43b7e036, 0x7fe86533, 0xcd716c62, 0xf4bf283a, - 0xbf2a60dc, 0x83cf7b15, 0xf3fbf147, 0xa09e54e9, 0x6e504683, 0xb3ce99ff, - 0x9cd01529, 0x5494d773, 0x9040ff18, 0x467ef7e8, 0x9d83e3ef, 0x5ea1d355, - 0x99bef0fc, 0x04d3e0cb, 0x0aede323, 0xde9ff7f9, 0x9ce54614, 0x191eacfb, - 0x6c109cba, 0x30f7d375, 0xaa09b6c9, 0xd130c91e, 0x53e361f7, 0xccbef7f9, - 0xe7df851e, 0x23fb5185, 0x0b5e2199, 0x47f2f78c, 0x01fbe883, 0x0eb9b3e9, - 0x595b5120, 0x52e91ea8, 0xe336689e, 0xc940c873, 0x3df0083b, 0x5f8c5221, - 0x353de7c6, 0xca226b73, 0xdf5c84cd, 0x6850c75c, 0x670e6897, 0xfe1f1137, - 0x8879f90c, 0x34aadc6d, 0x5f16afe4, 0x150f9a8a, 0xf8574f3a, 0xcf96826f, - 0xc51e7e40, 0xfa9f0af6, 0x87c2a7f3, 0xea0b3e1a, 0xb97f33e2, 0xd7009e57, - 0xb18f924a, 0x97721f20, 0xe38e747c, 0xe3fe2727, 0xf8bf24f6, 0xdca2c527, - 0xc2777f88, 0xd0f24b57, 0xb9e9b99b, 0xcb83e501, 0x8708b3cb, 0xc56cd751, - 0xdb247df7, 0x33c20b60, 0x0c7666ca, 0x0a372eeb, 0x783ac97c, 0x2e1dd991, - 0x3943d3fc, 0x45fe7589, 0xb8e0e747, 0xb3b43bfc, 0xb82ec8b3, 0xa4adfc60, - 0x7870569f, 0xb88b4836, 0xd09763bc, 0x5768b94f, 0x41b7ccae, 0x0678df3b, - 0x2ffa8778, 0xc4967ec4, 0xfe18dddb, 0x82b87995, 0x4f81ee41, 0x611d9966, - 0x1dd39846, 0xb724f911, 0xebf73277, 0xb38f8011, 0xc2136706, 0xae643c77, - 0xed7e1191, 0xf757a146, 0x74285f20, 0xc7f4e052, 0x7a0f794f, 0xfe1e7fcd, - 0x57a2e978, 0x133e0273, 0x2b2a22d8, 0x79e1bdf3, 0xae5e0ff6, 0x69bdf983, - 0x147c9df0, 0x6fcdebe4, 0xeb3736cc, 0x20cdf382, 0xbc3d12eb, 0xd992ff77, - 0xb3e00736, 0x051f8168, 0xb32e772e, 0xcebeb19b, 0x8a9659ec, 0xe06af674, - 0xcfe88fca, 0x7f174c58, 0x5eeb31c5, 0x2afb3154, 0x3d56b6ec, 0x57a487ad, - 0xcf50c2d8, 0xab9f6866, 0x99c4e5e7, 0x50a59eb1, 0xdce8f76e, 0x3c6f1806, - 0x347375e8, 0xefe74fbe, 0x38230b59, 0xc20b3147, 0x90011559, 0xbbaaf7c2, - 0xd1c03dd2, 0xd95bfeac, 0x7ddf041d, 0x0fa4c1c5, 0xc16032aa, 0x83efc2cb, - 0x896efbe9, 0xd62ee38f, 0xd355b8d1, 0xeaa8feb9, 0x53b8f16f, 0x54ceb271, - 0x8daaf7e4, 0xd04884f6, 0x5b328923, 0xa47a0b54, 0xf0ca152a, 0xeec65d8c, - 0xf4c47d43, 0xc3d3e1f6, 0x78fbf0ba, 0x11deb8d8, 0x84b71fc0, 0x96fe75f3, - 0x2af9ccb5, 0x29b563d6, 0xd57587d3, 0x00008a8b, 0xd4305eb0, 0x596efe83, - 0x6286f50d, 0xac2f507f, 0x83763d7b, 0x68a7c476, 0xac608c47, 0x9f11d858, - 0x8299dd6e, 0x9b27c476, 0xa9e4a677, 0xd8945fea, 0xbfd71c1c, 0xbc656f7d, - 0x66ec67ca, 0xa0926f18, 0xf98724fb, 0x50eb8494, 0xe77b44fc, 0x1a7c85fa, - 0x0235bf61, 0xef9061f5, 0xb47ba445, 0xf90e77d1, 0x6261bd8a, 0xa3ae199b, - 0x1a5d72be, 0xf7876faf, 0x1bc8efe5, 0xdb7e0357, 0xdbfe3862, 0xbe041976, - 0x2dff9e5b, 0x0c34af94, 0x3c61ab60, 0x0231bc17, 0xd71cbbff, 0x853d702a, - 0xbfce333f, 0x57112854, 0x55d98983, 0xfc1b60eb, 0xc5d99457, 0xd04ced2f, - 0xe88421b7, 0x1b372e5b, 0x75caff91, 0x70875d92, 0x59ec1c2c, 0xa7e97526, - 0xe8af4512, 0x132972d8, 0x262cede9, 0x9827bcbe, 0xfdf0966d, 0x80c5f4e9, - 0x9af352af, 0xa18f5c66, 0xd70901de, 0xb407a41c, 0x53ed885f, 0xbcb3e3bb, - 0xad54e00e, 0xb4dba5f7, 0xc6642f70, 0x0784efae, 0xd7cbc937, 0xc414e706, - 0xb730596b, 0xcd4b2e43, 0xf03f0839, 0xf017b79d, 0x2649afa9, 0xc0c426be, - 0xbe8a79f8, 0xdc7ce6a9, 0xb3c7d55e, 0x09e7be04, 0xca35e5ba, 0x0b3c135e, - 0x5a7bbce3, 0x2d4addb0, 0xfbc74b1d, 0x3952ea0e, 0x1ea38e1e, 0x4dc152af, - 0xa7054e7a, 0xa25cbddc, 0x7d45eef7, 0xc63f3fe0, 0xeba935be, 0x4ab689dd, - 0xe709f236, 0xf495667b, 0x0797d066, 0x4ca15d05, 0xe62499f3, 0xf5f23466, - 0x14ef9fdb, 0xd08eaefc, 0x8eba3971, 0xbe412dbc, 0xbcbeb98e, 0xb3fef529, - 0xdff56de4, 0x06ec6f29, 0x8267c1d7, 0xf8083b98, 0xd8ca5ab3, 0xfab27a8b, - 0x465b6636, 0x37ebb55f, 0x088673ac, 0xc035fd7c, 0x85987403, 0x9d7906ff, - 0xad3f7d1d, 0xfc97607b, 0x9cd9f516, 0x776ec201, 0x2424bb70, 0x9b19f38b, - 0x61fd3cc0, 0x1ca2610a, 0x23d9b932, 0x1eb91f03, 0x006765ce, 0xf8fb311f, - 0x32f5f2fb, 0xe51375d9, 0xa865d8bf, 0x659431db, 0x5cc80582, 0xd53f4417, - 0xa633f512, 0x24fee371, 0x6e4c4728, 0x7016464e, 0x6674bc3d, 0x9c0208eb, - 0xd058b1e8, 0xdfe1f163, 0x67c5bd50, 0x7d827979, 0x57942f60, 0x799921d7, - 0xa1c761a0, 0x2f2c7a99, 0x28b125d8, 0x104cf718, 0xd501a397, 0xc955663a, - 0x304f20e3, 0x75f8aab3, 0x4d4896c8, 0xa26d5879, 0x0d4dfea6, 0x33df357d, - 0xdf3583bc, 0xd4ca1c47, 0xc79bb394, 0x3c8fea68, 0x8f29ab9e, 0xa9a2996e, - 0x0cc2f63f, 0xbe47f94d, 0x99f535bb, 0x103cdedb, 0xe82050f0, 0x8a0ff8af, - 0x5ae5bafe, 0x2c3da69e, 0xe8095ec7, 0xb15fc85a, 0xc80b3582, 0x2d07193f, - 0xc896fdd4, 0x8da20e6b, 0xf5a95856, 0x6b54164f, 0x1b0dc5cb, 0x5609408d, - 0x2fbed1ec, 0x0f2da2d9, 0x43a79e88, 0x011b3abe, 0xf820c9fe, 0x428b1447, - 0x2ec9eff9, 0x44efa7f1, 0x00758fe1, 0x7e8098df, 0x33dface9, 0x7d234737, - 0xdf03cc0d, 0x7e05b03b, 0xf5c1be07, 0x03d0e3a3, 0x8523e43a, 0x3278fede, - 0x1ee96bc5, 0x3dd2d564, 0xee96a064, 0xdd2d3661, 0xd2d28d7b, 0xa5aec23d, - 0x2d64d47b, 0x5a1c63dd, 0xd1cdc7ba, 0xa9c13dd2, 0x91527ba5, 0x8bc9ee96, - 0xf3ef74b4, 0xa9ae96b0, 0xbe5a85ee, 0xc503e3f0, 0xb95b4b4e, 0x8e9eafd8, - 0xe0fcd4e9, 0x40ca9a28, 0xfcaff4cf, 0x7fffa6b9, 0x45a43f36, 0x92353f0a, - 0x7e477e45, 0x645fbd86, 0x46ff7776, 0x7f6a6bd1, 0x65d39f42, 0xefa4f67f, - 0xd3cbd9ba, 0x47a09c78, 0xdc9ad97b, 0xf5272f65, 0x982797cc, 0x4bd689bb, - 0xf08746b6, 0x70e165dd, 0xa357c15c, 0xd59bbb19, 0x13dfb01a, 0xc0146750, - 0x03e7027b, 0x9acbdfe3, 0xe65cfde9, 0x5993a7a3, 0x63ccf88c, 0x30167a36, - 0xe8a73d07, 0x1e22b79c, 0x392dcd4a, 0xceaf6fa8, 0x42527a3b, 0x21448ea0, - 0x2f23dfd0, 0x4ea75a6e, 0xd999cc57, 0xd6b18fda, 0xb44ce70a, 0x16e33ba7, - 0x568d6676, 0xbc6f2de1, 0x7a8f5034, 0xa1b60e56, 0xa777943d, 0xde6cf644, - 0x3739fc97, 0xfe43af92, 0x2b0f65cf, 0xfe14ab78, 0x1e43f707, 0xbb0ab48e, - 0xc943399e, 0x7059b3be, 0xb8fe805d, 0x9182ff3d, 0x82582eec, 0x2e80d7f5, - 0x4f4e24db, 0x4dda2ba4, 0x7cccf4c3, 0x9843ca0d, 0x27ccfc93, 0x7892a0f4, - 0x1fb1833f, 0xa0dbda17, 0x75234a02, 0x8e394e34, 0x3cd4f007, 0xaa20cccb, - 0xe98126ac, 0x9afb4207, 0xf12ca225, 0xbce1fe32, 0x454cdfc9, 0x4d2b6d78, - 0x4858af64, 0x4ccd923e, 0xe3dc91c4, 0x493ef0dc, 0xed090d06, 0xbfc01bd6, - 0x6b942488, 0x2198c3e6, 0xfaf99ce2, 0x934c157e, 0x51f8539d, 0x0a2f7c26, - 0x1dbfdeb4, 0x9595edc9, 0x40efc715, 0xcdef297a, 0x84b3377a, 0xf7825ea2, - 0xeb31b92a, 0xb0f11d99, 0x533dc2a2, 0xc8d9ff5d, 0xf1e7ea48, 0x4e2d8bde, - 0xdf723ef8, 0x720428a2, 0xd9739067, 0x10a1658f, 0xe9458962, 0x069ad46f, - 0x1ec3fb99, 0x919afd19, 0xd4e7f5c7, 0x2dd1a471, 0x0bd8f2da, 0x0f42b2da, - 0xc177f376, 0x82650728, 0x00f14caf, 0x195eaa97, 0x67c0f63a, 0x0fdcf165, - 0x84c1be63, 0x1b90a377, 0x0de49d53, 0xc130f902, 0x0a61925c, 0x9ccc0c2b, - 0xedeb7480, 0x6e5da0b4, 0xd0ebd44c, 0x2ff2603f, 0xf800ce6c, 0x78a69e53, - 0x7eb555fd, 0x17ea03f9, 0x48d86bb0, 0xdff11236, 0x41e02f09, 0x1a3a7802, - 0x46ae36e2, 0xcdcc9c78, 0x613603cb, 0xb3fea7b9, 0x7a59becd, 0x0b6cc110, - 0xbc3fc67f, 0x447e9674, 0xa3af7af7, 0x64e3075d, 0xd93db8eb, 0x8e5cde9d, - 0x6bb3e93a, 0x01646c81, 0xb0d553e8, 0x7fd4e3ff, 0x25793e9c, 0x51e22ba9, - 0x6fc092ee, 0xcd698787, 0xf8009612, 0xc75aac2e, 0x092e3f90, 0x8f325c38, - 0x24d7b1c3, 0xb5e8a7aa, 0x10022c97, 0x875a1af3, 0x62f04407, 0x0eb72f7a, - 0x6bd2f2e5, 0x2fae88bd, 0xf1474efe, 0xa3cc41b8, 0x610cf9c3, 0x8c3efa5e, - 0x26f950b5, 0x67281514, 0xdbf12b30, 0xbb23e608, 0x2b5cf411, 0xd972b9ea, - 0x2820bbf9, 0xbe764e5f, 0xe84e7a44, 0x4fc174fd, 0xaf7e8ae9, 0xddc7fbd6, - 0xf8a48d3e, 0xad0b6f4a, 0x54ce4223, 0x3af82674, 0x7f91448e, 0xe768e209, - 0x544db4e5, 0xc688303e, 0x587c1429, 0x8d88ec98, 0xc5ebd154, 0xf5336b8a, - 0x7802f92a, 0x5bbf28ec, 0x4d66822a, 0xa397bd50, 0x32071e38, 0xa18fd5df, - 0x2175f9ff, 0xe047b436, 0xf97ec68d, 0x4729c90f, 0x5b97bc01, 0x9a3af5ac, - 0xf50ea567, 0x24efd962, 0x33c01cf6, 0x66b97180, 0x7035e2fd, 0x9848a96d, - 0xf9f40135, 0x0fdc917b, 0x1c7cc971, 0xe28433b6, 0x8cc98531, 0x853f4385, - 0x7c91a7af, 0x0bd0c40d, 0xcc32b1c2, 0x8c2f7683, 0xdd95151b, 0xf1ff1e1d, - 0x35df43df, 0xb733f49b, 0x1ef543bf, 0xdd9973f4, 0x7bc7556e, 0x19bb0b56, - 0xe39213fc, 0x3b9fd160, 0x7aff7197, 0x84fb8f30, 0x296ae6b2, 0x62f5e7ad, - 0x9a651a20, 0x014c02f5, 0x36ce5718, 0x16ae5c93, 0x47acc472, 0xe18fe8ad, - 0x3a184673, 0x8f0e9cfd, 0x1cfbb187, 0x24fd7a2a, 0x3f0baf8a, 0x6a78e289, - 0x077b7337, 0x2a19f5e3, 0x31af387f, 0x251bec9f, 0xec2edfbe, 0x9503f6c9, - 0x27e8c1b9, 0xbe388a57, 0x058a9fb0, 0xfa682d2b, 0x4ad78e4d, 0x3e91587d, - 0xfe7de2f9, 0x535dad4a, 0xf649c5b8, 0x24ecf5cf, 0x09c514c0, 0x49a4edfd, - 0xd96f4251, 0xefc60658, 0x3b49accf, 0x307a8c18, 0x1e305995, 0x9abf249f, - 0xf11428b1, 0x871cace0, 0x4f543df2, 0x67afeb72, 0x1a87041e, 0xe245b9e9, - 0xe7f774f4, 0xd92db4f1, 0xb2dcefdc, 0x7f5a63b7, 0x58cbe7e8, 0xdda52f8e, - 0x6a06b197, 0x38e828f7, 0xd8cb5f7c, 0x6e7e40e4, 0xc977c091, 0x7a8b2096, - 0x8dab2a7d, 0x0d5d94d0, 0x7af51609, 0x2c28f640, 0x4c146caa, 0x7e2ba721, - 0x72d0d653, 0x768ac430, 0xca017381, 0xbfc1fb49, 0x3a250f86, 0xff5072f8, - 0xf9c7183d, 0x02b6e113, 0x9f743b3c, 0xffd355cd, 0x80bd28d1, 0xffa7af9b, - 0x2d765c30, 0x1e87975c, 0xe1c29d8b, 0xd5c239fa, 0x8b1d3de6, 0x8cb805f4, - 0xe476b86a, 0x3f9ff8f2, 0xa1fc9e9e, 0x88f564f0, 0x87df35a7, 0xc0c61da7, - 0x74126cf0, 0x6e80f97b, 0xfac027b2, 0xcfc849b4, 0x1aef0c3f, 0x6b6dfc3f, - 0x15618d9e, 0xe1137780, 0x9635be2f, 0x7f021672, 0xe04e22b5, 0xc6fa12ce, - 0xfd03ba06, 0x7a468fba, 0xead40f50, 0x2c54d459, 0x96d814e7, 0x46af3cc0, - 0x5da0fb38, 0xfe21eae4, 0x7f8091f2, 0x7014a247, 0xef881ffe, 0xf5e48f7b, - 0x89ff75c1, 0xf28626e3, 0x09ebe0af, 0x1339ad4b, 0xe6fa37fb, 0xf59cb0db, - 0x1a1ad9b9, 0xef1d7fa0, 0xf27e57ff, 0x3caff4a1, 0xc81a8ddf, 0x01d247e3, - 0xfb209419, 0x9ac7cdd5, 0x7f9cc3c7, 0x9d27a595, 0x79e30ffa, 0x79fe36b9, - 0x762c7bd9, 0x778be71a, 0x4b97df51, 0x876fc367, 0xbdf24bb2, 0x97f31433, - 0xd7cd2746, 0x6d8991f5, 0xbce7600c, 0x9942f821, 0x057f329f, 0x151fb0ee, - 0xee0091f4, 0x5a2613b0, 0xf5103e0c, 0x97a07595, 0x5e71a3b0, 0xacdc0eb4, - 0x6ca071e7, 0x57f7d13d, 0x1c50c6a3, 0x27c88768, 0x291b46fa, 0x870fe95e, - 0xff8f9a21, 0x9bf7b5c4, 0x8d3f62fb, 0x33e78a06, 0x4cfc4b7d, 0xdbd717e0, - 0x9427877a, 0x8ef266f8, 0x4763a450, 0x753c0b78, 0xa76a06d1, 0x7287bd43, - 0x8c9e4d71, 0xc8fdae7a, 0xc55916e7, 0xccb472e7, 0xb9ac6be3, 0xbff42c79, - 0x30599336, 0xd62a1cbe, 0xad23d0df, 0xe87f0845, 0x249b9fa8, 0x4af6fc55, - 0xadda8994, 0x6d62fa35, 0x09ab9fd0, 0xf78a051c, 0xb1b118b7, 0x85970782, - 0xeb3ca1e3, 0xe866e800, 0x4760d1a7, 0x2b68e578, 0x7700a7d7, 0x1e0fbc3d, - 0x1f25b9f4, 0x78c167bf, 0x87dabb7d, 0x833d3859, 0x439e61b3, 0xb3de5f91, - 0x97b3c014, 0xdf081cc4, 0x3f5cd183, 0xc455702b, 0xfc02fd71, 0xf114321e, - 0x7ca3ac9a, 0x66fae3ea, 0x96e3dfc2, 0x8c25967e, 0x79c76ef0, 0x299b46f9, - 0xed1d56ee, 0xf9c6898c, 0x1e1cd818, 0x8c766cf7, 0x32587c27, 0x07002356, - 0xf0bd9106, 0xc38bc133, 0xb21cf358, 0x168cb20b, 0xf594475c, 0x8ede8bf9, - 0xcd37685e, 0xd076e68d, 0xd742b7f9, 0xc0abbae0, 0x2c02b677, 0xb957633a, - 0x8498e6d0, 0x9ccf9978, 0xe78e502b, 0x551e0157, 0xc0de7efc, 0x16bc2dfb, - 0xaa51bccc, 0x36eea376, 0x6bc2bb62, 0x760bcce1, 0x5e20f9f7, 0x5f187cef, - 0xf18ac6cf, 0x33fc156f, 0xea07fa33, 0x7c9f9b31, 0x8bf3f86d, 0x8d8f5c79, - 0x4995bc45, 0x7bb4462d, 0xabf98ed7, 0xb3e9ed11, 0x4de61615, 0x4679beff, - 0x9c6aaf31, 0xccd77ace, 0x3ca51f34, 0x5b24f917, 0xc250df3d, 0xf88ad9c3, - 0x4931e0eb, 0xfeaec783, 0xd8f06afb, 0x1a74ffbd, 0xc0c56cff, 0xa43ff4eb, - 0x1aadfe87, 0xedfabbf8, 0xedb6e347, 0x04297bcb, 0x779f7bf8, 0x31bb73e9, - 0x64c7bb1e, 0x373ca131, 0x3f22e6d4, 0xbc0edd5e, 0xd0f4fc04, 0xff28af9e, - 0xa326d0f8, 0x3768c70d, 0x02dae6f8, 0xcc7eefe8, 0xea8dd6e2, 0xa746167a, - 0xdffd9d11, 0x0b1ef59b, 0x03cd95c6, 0x375c16f5, 0xb3d9accc, 0x4cd7f894, - 0x3f8944fa, 0x8b4efd28, 0xccfa3592, 0x5fd9f425, 0x9047cef5, 0x5f3aedde, - 0x89da1e7d, 0xb70f3f03, 0x41117f92, 0x3f12ba76, 0x892383d0, 0x3989ad76, - 0xde4de618, 0xa3ba758e, 0x82dfbfa1, 0x411c62b8, 0xc4e3561e, 0x2293fb78, - 0x5064ffee, 0xa54dbc73, 0xeb45d697, 0xb09d987f, 0xb35f8fd2, 0xcbd17c3f, - 0xc47583d7, 0x2bf372af, 0xb58bbf08, 0xc55c7918, 0x5e67f64a, 0x94e3c1d6, - 0xacfc520f, 0x05fbfe95, 0xbfd02392, 0xe11de252, 0x9ae2ace8, 0xd68c36bd, - 0x5e10fceb, 0x28b7ffce, 0x8a819fca, 0x6ac43d26, 0x162f9e65, 0x310e9671, - 0xdaf37687, 0xda1ff414, 0xa3ab1e45, 0x46e83f71, 0x4fecae78, 0xf37fcf74, - 0x9f6869d1, 0x79e33e83, 0x5a30a6ab, 0x624df227, 0x9106279c, 0x9123b17f, - 0x7ab57fdb, 0xcaa6786f, 0x77bc7c1e, 0x685f736e, 0x7f656977, 0x5dcbda1d, - 0x0efbcdfa, 0x39dae7f6, 0x574df888, 0x39e9e83f, 0xd7489718, 0xdcebb0d9, - 0x31eaaffa, 0x16b650de, 0xef1801ec, 0xa469e812, 0xc4feae93, 0x705f5c70, - 0xcb3f5c6c, 0x9fc893ea, 0xd1f10fcc, 0x60b293fe, 0xea05ba5b, 0x4d8fd7e5, - 0xf33fbe47, 0x5c14a0e4, 0x58c74e0f, 0xdc4f3053, 0x192024fe, 0x69ba79e6, - 0x6abf7f00, 0x17d470e4, 0x9c436b61, 0xadfc009e, 0x95fcf7e8, 0x14767226, - 0xcc48ef3a, 0x7c406b68, 0x7e93320c, 0xf6450507, 0xdf21fe53, 0x17786b0c, - 0x473f159e, 0xa15ac7c1, 0x3ffe954f, 0x79517a16, 0xd299fac2, 0x31ef7082, - 0x1ccffd11, 0xc38d7bd1, 0xf1b21ed1, 0xd08556f1, 0x0730f978, 0x29cbc80b, - 0x8e9d8eb1, 0xbc470eb4, 0x2832ebe7, 0xe443ba0f, 0x7c5956e5, 0xe41eb8e1, - 0x194ad9eb, 0xbe62afea, 0xf8d508f0, 0xd7b28df9, 0xfbddf448, 0x4d5ff90e, - 0xabe90c61, 0xfc8c337b, 0xa69bd773, 0x018f684d, 0x6821ddfe, 0x91371e17, - 0xc9afb2df, 0xfb617644, 0xd7f21089, 0x42c3f1fc, 0x3f48297d, 0x44499bd7, - 0xdf64f6df, 0x0c8edcf3, 0x680f9862, 0x891cea3f, 0xd1694274, 0x9ec3e3c5, - 0xd5cd7680, 0xda2f20a6, 0x60f4f035, 0x6acdd07c, 0x9efde9e2, 0x347e8610, - 0xa8643d3c, 0xe0f17549, 0x1082a0b3, 0xfda99bed, 0x01ce2943, 0x4a1f1fa8, - 0xb143fe83, 0xbbd52b7d, 0x9379d7da, 0x1221c785, 0xd48978c5, 0x5fb7326f, - 0x8d39f499, 0xef89fd03, 0x65ddf4cd, 0x79a48e72, 0x36c61c7c, 0x61679806, - 0xa0bcb6a5, 0xf62e5b5a, 0x5b25cb68, 0x745f65b4, 0x814fd114, 0x7f73e15b, - 0x70c4a4bc, 0x87c142bb, 0xd2769f3f, 0x61f03af3, 0xcbf1013c, 0x571d391a, - 0x929aba0f, 0x0f2de387, 0x9753e4d6, 0x3e279d34, 0x9fd8376c, 0x77c075c1, - 0x9136c0d4, 0xd50360fe, 0xf8ffb6fe, 0xe7adf3dd, 0xbcf5be45, 0x26dadf26, - 0x160c2ef4, 0x5084f18e, 0xe11c359b, 0xad4ba1d8, 0x3d5f22f5, 0xbe7c4419, - 0x21cbf716, 0x401baddf, 0x054452f0, 0xf0b3cfc6, 0xfd08cff1, 0x54c5e677, - 0x642d33ca, 0x4b4fa4b5, 0x44bef399, 0x5887e78c, 0x57ff9073, 0xcdfb02d9, - 0x27baf8fe, 0x34e3d386, 0x7d8ac6b3, 0x6fcc564d, 0x80bfe114, 0x74fd4504, - 0xdfbe20f6, 0xd175f48f, 0xd481137a, 0xd8ccf7c9, 0xf3ff9655, 0x0d0077cb, - 0x3655fe11, 0x67ae3877, 0xde7c2c17, 0x91593f60, 0x9f3245be, 0x8875fa07, - 0x2f120bc7, 0xd942fa2b, 0xdf00b12f, 0x989e7ccb, 0x518f2fa7, 0xc7ae38fc, - 0xf75e925c, 0xd693e830, 0xf2386b08, 0xb4aaeb53, 0xb79825c8, 0x66c6b088, - 0x3aecf0aa, 0xd026bcc0, 0x0946d65f, 0xf0ddbf63, 0xf39223b5, 0x085d6fa3, - 0x8eaf2bad, 0xf6ab996b, 0x8635ff13, 0xc58f91db, 0x16a6ff70, 0x40ec826d, - 0x5a74e078, 0xcab4e820, 0xf931fce6, 0x16f57e4b, 0xf412f754, 0xb95f7bf3, - 0x2f295ffb, 0x0fc55eb5, 0x8a4edeb0, 0x385de3e5, 0x374b7464, 0xfb4a5f91, - 0x82eb7c9a, 0x70bf6ec8, 0xae3a4a68, 0x82eb4543, 0x155f5122, 0x8b135e1d, - 0x8db8c8f6, 0x3ae2c58f, 0x6269b055, 0x9fe2533a, 0x482a3e2a, 0x3da3a7b1, - 0xb6567be4, 0xd5453f60, 0x4ab5c132, 0x167e695f, 0x36ab9fde, 0x24549d90, - 0xdbd73ae0, 0x2f788e19, 0x11bd33d2, 0xef4e7ef0, 0xf03b270c, 0x2ffc9959, - 0xbd40f9ff, 0x00ccfa63, 0xfa0b3278, 0x00b48be2, 0x47547bfc, 0x66082a74, - 0x36e75724, 0xb9edfcf2, 0x587de764, 0x157f056e, 0xaaad77f7, 0x0eb70e2c, - 0x73f78eed, 0xddf12766, 0x051f3102, 0x28e3feaf, 0xbc476d78, 0xe871fda2, - 0x2768c9b9, 0x91929eb8, 0xc6ded933, 0x8e47e42b, 0x72789a6b, 0x075fbe2c, - 0xd7158076, 0xdcefbec7, 0x4ad4eb83, 0x909da199, 0xcb1694d7, 0x57d76a86, - 0xdef22fb4, 0xa3ae159e, 0x90d31df7, 0x6d5b4e9f, 0xfb2a99b1, 0xcfc11dee, - 0x5fc974fe, 0xec70b7f7, 0x818d68af, 0xdff057e0, 0xfd93630e, 0x41e21953, - 0xedef6f3e, 0x7a157ea3, 0x2116fd28, 0x81fe15be, 0x2c63577a, 0x7c795f82, - 0x99d535b1, 0x0fc00b63, 0xe3037ff3, 0x61d57f62, 0xdcbfcc76, 0xbccab8e8, - 0xc8aae93b, 0xafd399ad, 0x8a54f9f5, 0xea8eeadf, 0xe9e99369, 0x50535bca, - 0xfd61f2de, 0x5f3a7f46, 0xfe449df2, 0xe315b285, 0x4aebf9d5, 0xf2f1c3ee, - 0xf874984f, 0xadcf75bd, 0x3f2e09c3, 0x529e01fa, 0x7b75f102, 0xa6c52faa, - 0xfbac1fc2, 0x7ccacf24, 0x1c137054, 0xe4307fe0, 0xa054f6ff, 0xbfee4a9b, - 0xf50f7210, 0x63e2462d, 0x5fc470fb, 0x7e2d7ce7, 0xcdf8b5f3, 0x3e2318f7, - 0xcd273666, 0x9323e0a7, 0xfc17df0e, 0x28e9a7fa, 0xc7abad9f, 0x235abcd3, - 0x8e51c3ed, 0xffa0535a, 0x59e7dda1, 0xe7986bf0, 0x6799efd0, 0xabd11065, - 0xfa4679c7, 0x33df679e, 0xed58c8cf, 0xadeacf3c, 0x5c5fa8e1, 0xfb8664bb, - 0x8ec95cc3, 0xd97963b5, 0x768614b2, 0x05d0f589, 0xd5e912fa, 0xb8a068d6, - 0x30ef22a1, 0x83f20dde, 0x35a1f88e, 0x28f4fad7, 0x0b656f5a, 0x575bd9c6, - 0x51e7788f, 0x95aeb728, 0xb407682d, 0x81fc72e6, 0x0f50ebdc, 0xa638a6b4, - 0xc18f7951, 0x39fa14b2, 0x0fb7f953, 0x0c0bf225, 0x73f34656, 0xbe3b45ac, - 0xfd45e01d, 0xcd997805, 0xcd034aed, 0xa7cad57f, 0x7777e256, 0xfe964df5, - 0xa7eb40d6, 0x6b45cf16, 0x321c8d64, 0x73c695bd, 0x8ac93afd, 0x0cf050f3, - 0xc67d349a, 0x607c2eb0, 0x2eb0d679, 0xfd94b8bc, 0xeb3d626c, 0x9f885bd4, - 0xc05d7cbe, 0xafa8ea7d, 0xa77d3f70, 0x57affb3c, 0xdfc67a7e, 0xd04db89e, - 0x16ef5fd3, 0x7ca9cbab, 0x5cbaa15f, 0x4a37a7e2, 0xbac3befd, 0xfc502d3b, - 0x78e77774, 0x02796f1c, 0xaf5c4a6f, 0xd68949fd, 0xd5bd3cd5, 0xabc17e88, - 0x155c78e3, 0x8ff301fc, 0x683b0e49, 0xb67a793e, 0xef8994dc, 0x994f546d, - 0xdcb7f427, 0x8ef46b04, 0xa077ae60, 0xaaa364de, 0x0557e8ac, 0xfe44479e, - 0xc3fe7942, 0xad64f3fe, 0xb38aacff, 0x201b123f, 0xf7299ece, 0xc608ed7d, - 0x64c976db, 0xf30eba37, 0x7d7d8575, 0xf06de9e5, 0x1a4f7cbe, 0xe6555bed, - 0xf6c78fef, 0x7de12b86, 0x21db7de1, 0xcbc63063, 0x72a31af2, 0xf48a2fc9, - 0xaffbc405, 0xfe94fcc4, 0xe12df4da, 0x2df6d5d3, 0xa19f096b, 0x86bc8fe2, - 0x164fb42b, 0x5596e7f0, 0x534cfb7a, 0x79fa2e4c, 0xcc4a7ff9, 0x55f3c1d5, - 0x06b5cf41, 0x506b0beb, 0xc899764e, 0x3c3b6f6f, 0xdbed8747, 0xe789170e, - 0x9e7a7643, 0xe382933d, 0x7f38eb87, 0x14bde32b, 0x7ca5edcb, 0x7fe7a9dd, - 0x8dfefa84, 0xaa65d4b8, 0x2ebe69f8, 0x6dc4fc93, 0x845cdf06, 0x95f1ec1b, - 0xe943efb8, 0x2b58d5e7, 0xebb6d1c1, 0x0fa8f3fc, 0xce4dacce, 0xb6d23544, - 0xcc70c06b, 0x189db7fb, 0x3fe78e91, 0xb04c9eda, 0x66d81ea1, 0xfc443eb0, - 0x86cc2ab6, 0x87f4ae72, 0xac7e60e3, 0x1cc8d76d, 0x4edbb3f4, 0x4ca17870, - 0x73d4377e, 0xa50efee3, 0xf59d70df, 0x8c8fb857, 0x7940c9fd, 0xa4dfc5b4, - 0x1abfa1c5, 0x5f9c0c6e, 0xbb5dfb40, 0xc1296a7f, 0xf1e3ecad, 0x7d95efb7, - 0xd17efe3d, 0xf80bd07c, 0x2b7fdfde, 0x702b9562, 0x1fbf917f, 0xdc7e40c7, - 0xfa62beca, 0xbdf5a5ab, 0x2677cb64, 0x0fb13d4d, 0xbe031a88, 0x571e40f2, - 0xc3c65c53, 0xe52b5fe3, 0x5f42f980, 0x3ec7cf2c, 0xdcedf213, 0x4f5d1516, - 0x1e3e98eb, 0xc8da7af0, 0x7f99f1cc, 0xaf973fbf, 0xbacc57de, 0x73a777fb, - 0x00b9953d, 0x32d5e9d7, 0xa1fd47ed, 0x7b7f9dfe, 0xf3e88480, 0x4effb099, - 0x3e705cc3, 0x5ab3fb3d, 0x067c1578, 0xfe057d89, 0xfe22cdf5, 0x991bf03e, - 0x9bee51d9, 0xcfe41e0c, 0x3f9f8d90, 0x67f20f7d, 0x6a92c1a3, 0xed017ca5, - 0x64bb6573, 0xb75c7f4f, 0x2f84cf1a, 0xd76575c4, 0xd34e3a08, 0x92ecbfe9, - 0xd6dfee29, 0xf3162570, 0xe50fd003, 0x4f4d5d3b, 0x7b7f90d9, 0x4e312382, - 0xeffa61fe, 0xa1f8bf66, 0x6db67bc8, 0xfa8e973c, 0x6260f41d, 0xfa67ca1c, - 0xff9e46d7, 0x7da1c96c, 0x273f1bbf, 0x73ddbcbb, 0x7349ec95, 0x940f6ca3, - 0x671a1c57, 0x4df061fc, 0xf007c2d0, 0x1478450c, 0x3eadcb38, 0xbd737f3a, - 0x5d84ffbc, 0x1cf14b85, 0xd1f9e608, 0x94682fbe, 0x582add69, 0x40ac7b2f, - 0x7e030997, 0xed082fb1, 0x8a24a7d1, 0x6f924e0b, 0xd40e70fe, 0x4ca4f05f, - 0x1f1bbde5, 0x7480d0fa, 0xbca06f5d, 0x99a682e1, 0xfc57da46, 0x122cc494, - 0x37d9ab8d, 0x12972c50, 0x09f6dd5c, 0x680fedf8, 0x7d0b76cb, 0xe37ef7e0, - 0xa2fb198a, 0x9267a9f1, 0x017efbb5, 0xcb103bfc, 0xdfe047cf, 0x126bfe96, - 0x416d0e91, 0x5ca3358c, 0x5fc85bea, 0x3e7e5e61, 0xd9d76db3, 0xeb97a414, - 0x5e292f8d, 0xb01c93d9, 0xf33fbe46, 0xfc8938ce, 0x5cdf81d2, 0x5008e699, - 0x6fc8b67f, 0x13b8316f, 0xb7dd3ed1, 0xe38f2af1, 0xae71e2ec, 0xee67fb1e, - 0xf26f1e20, 0x2c1c5106, 0x0532d6ab, 0x3cec01e5, 0x36b93fcc, 0x09b198ad, - 0x0dbb41ca, 0xabab4456, 0x05c9287f, 0xaaa141ca, 0xb61e455f, 0xb2947c88, - 0xd8b661bf, 0x6feca397, 0xf83bf650, 0x77eca1c3, 0x3bf62d98, 0x78eb1dbc, - 0xc19e0e28, 0xd9385f3a, 0x5ffb7eb1, 0xe2cfda7a, 0x3fd1efbf, 0x4f9fee6e, - 0xcbecad5b, 0x47146088, 0x8dfac237, 0xcd86c395, 0xabf51778, 0xfe4c98e1, - 0xef23ded0, 0xf1f5aac5, 0x38737d0a, 0xd72f31c6, 0xd1fe4419, 0xc316f947, - 0xa98dcf91, 0x862597a4, 0xca0bae76, 0xb375def8, 0x338eaede, 0xe7c71d3f, - 0x9d2e22bb, 0xfb7ab7af, 0xb7afcc21, 0x688cf259, 0x148e1b8f, 0x367e464c, - 0xf919e7c4, 0x54e6b9f8, 0x9e844ba4, 0xa3457ff8, 0x05b36e32, 0x7bf257fb, - 0x2cc71161, 0x598577c8, 0xbf3fbeb3, 0x4a83f227, 0xdf33af7e, 0x7be33f17, - 0xe33b7bf3, 0x8bf71d38, 0xff71bbe7, 0x3b7bf2cf, 0x5265fe91, 0x30f1a4cb, - 0x8ef88ac4, 0x6ebdf9c0, 0xfcb1bcf3, 0x567147de, 0x9ceb7f9e, 0xbdf90f6f, - 0x58dffd6e, 0xff7baf7e, 0xbaf7e43d, 0xf9837ff5, 0x797ecebd, 0x50f96f7e, - 0x5b3fed1d, 0xe3c4dc7e, 0xffbe66e4, 0x65e424c3, 0x668277b9, 0x74f284ff, - 0x184909b3, 0x275e5f27, 0xbcfe464f, 0xa0b3c96c, 0x78221a7c, 0xb064c83c, - 0xd43f464f, 0x85191114, 0x711ff97c, 0xabaf3469, 0x3f888b11, 0xc87982af, - 0x722d89cf, 0xef797960, 0xca649902, 0xd6177f2f, 0xd57cf324, 0x7758b368, - 0x87e4b7df, 0xf3fbfe52, 0x3d1e5538, 0xed00fb2c, 0xce0d648b, 0x8fbf283e, - 0x127f405b, 0x7c50b79f, 0x7f3928c6, 0x76217187, 0xbb639f82, 0x601ce41a, - 0x3ea5c951, 0x2eec28de, 0x33ea126f, 0xa7a2ab37, 0xe10ae1ab, 0x2a478959, - 0x47cc5ddf, 0xa5794778, 0x7a09b8c3, 0x706f7d2b, 0xb573a00e, 0xbb4e8e02, - 0x6ea18fe0, 0x6a69a73c, 0x8ff286fa, 0x34df7aed, 0x36d4eb8c, 0xfc6a21ca, - 0xb973c526, 0x9cfe4dc8, 0xd8e556f2, 0x57e617ae, 0x7ca0064b, 0xc37c9b96, - 0x7b7dee11, 0xf51c36fe, 0x92a6d5ca, 0x0b7ef83e, 0xdc75a7d4, 0xe7572be8, - 0xaaf3fd5d, 0xf381f1d1, 0x969a5bad, 0xdb1c2225, 0xf6005e30, 0x3fc3f955, - 0x663a73a7, 0xea0dff66, 0x837a060f, 0x99868afc, 0x93b438f2, 0x01db003e, - 0xf8bb59ca, 0xcc959bfa, 0x2d37983c, 0x0e60fa6f, 0xdb3cabd2, 0x32974168, - 0x6de78338, 0x16cdb383, 0x45a6ff5c, 0xe2303e71, 0xed869b3a, 0xdd214627, - 0x3031c41e, 0x7b73b9cf, 0xb7f01bbd, 0x854f0ff0, 0x27dfc033, 0xafda4afa, - 0xb1f9ba51, 0x2f3c3b70, 0xc714dde8, 0x0723c4fc, 0x1794ffdc, 0xf6b7f8af, - 0xfe754950, 0x3fdfd3e0, 0x6ef88d31, 0x7982c1b3, 0x1316d77f, 0xaf2b9f9d, - 0x33f3a62b, 0xcbc53e50, 0xfe867f8f, 0xbb41ab95, 0xe97c2f4e, 0xad2b58a9, - 0xb124ee0b, 0x941f11ee, 0x849d9cd7, 0xc1f857f8, 0x8f8e1dbf, 0xb55de5fb, - 0xaf633cf2, 0x7b15dfee, 0x5dff5943, 0xfb884f75, 0x3fc85a01, 0x845faff0, - 0xb19a3232, 0xfddaf199, 0x983e0ad1, 0xa3f48627, 0xf0c373bc, 0x54be5053, - 0x92e16ff3, 0xbf8a4f0a, 0xff9b51d3, 0x3dac37bb, 0xb06defaf, 0x7574b02e, - 0xb3b50f3b, 0x177e0836, 0xf06a5f7c, 0x955ca386, 0xdcd8346e, 0xfb74baf0, - 0x973e2f0b, 0xc3667245, 0xfb64ac75, 0x818e1f5b, 0x430ec972, 0x8d3e54f4, - 0xde754950, 0x61ff05cd, 0xc3a1405e, 0x32ded7c2, 0xf7f1875a, 0xa2ec88bf, - 0xbd8ec947, 0xfc5e7446, 0x76be31f1, 0xbbf291af, 0x3da974fe, 0xef2b7245, - 0xbbec86fc, 0x2c48f64f, 0x3e00352e, 0xee15be37, 0x3a227814, 0xd2753a0a, - 0x92beafcd, 0xe4e8577f, 0xde3b3dff, 0xfd85f242, 0x3f023ca1, 0xc606f2bf, - 0xd9323ffb, 0xaf45fe70, 0xf38e103c, 0xc45faf38, 0x63c37af9, 0xb71876b1, - 0xb58ee0c8, 0x2fbf93d0, 0xc467fe7a, 0xfe8e0b6f, 0xcc7fdb8c, 0xfca3a09e, - 0x7bf29ba5, 0xd0efeb85, 0x0da2ffe8, 0x85ffae3c, 0x11de4d9e, 0x0b8e2e40, - 0x937e72bd, 0xe7d9f289, 0xf6860f31, 0xdf327bcb, 0xa7eec7b7, 0xdf629078, - 0xe54d2780, 0xfe1e842f, 0x894ebc43, 0xfc359b7f, 0x3378f35a, 0x64d3e7d2, - 0x25ea1c7b, 0x05bbd317, 0xa0efa43e, 0xc4e8f95f, 0x1e1f4e38, 0x6076a33f, - 0xf7c78e8f, 0x40d9bf58, 0x3b5550f1, 0x8f966e71, 0x1f18a0ff, 0x7cc60ee0, - 0x5658f9ca, 0xd44fc814, 0xe7c67427, 0x29e7359b, 0xcb9be4bb, 0x2e2acd7b, - 0x7bbc8adf, 0xefc64fa6, 0xf2e31f9f, 0x3292ed83, 0x1c6f2e09, 0x4b3bdf7d, - 0x27cfce1a, 0x75c9037b, 0xb5c8418d, 0x27c2bbf6, 0xee9eb700, 0x05f85021, - 0xfc248ffb, 0xbad2d517, 0x1dd8d26d, 0xbc2f1c2e, 0xdc8a7f7b, 0xfff2102e, - 0x7f38bc7e, 0xad9fe425, 0xf3a1b98f, 0xcf06a545, 0xbca1cf8b, 0xbef7e09e, - 0x90376e94, 0xdb717e5d, 0x06ef0ffe, 0xab58b939, 0x7f56a9c8, 0xd169cbfa, - 0x7f116fab, 0xc5e9cbfa, 0x0362b7da, 0xb78ee9ca, 0x2eee0ec8, 0xfab9ffa7, - 0xdfdfc153, 0xe8a7f0fc, 0xe8f09ec3, 0xe3ab0faf, 0x21f501ad, 0x9f531dfc, - 0xa5f0537b, 0x6fc29df0, 0xeb2e5f0b, 0x93a77a83, 0xebbe152f, 0xef854be4, - 0xd73bedba, 0xfbffcfe0, 0xe00df85b, 0x60faec72, 0xb3d01252, 0xc9fb91b4, - 0x9620eed0, 0x5a764f01, 0x41e558c6, 0x55db6f3c, 0x6b95f8f6, 0xfddbeafd, - 0xfabf0eca, 0x22f2bf4e, 0x821efabf, 0x3f61b4ab, 0xbcc96fdf, 0xa586fa9a, - 0xdd161dcc, 0xf31e0e75, 0xcfd02b58, 0xf4f3c6df, 0xb8f0258f, 0xb8c62fa9, - 0x891ff682, 0xe13e2a7d, 0xb43bb467, 0x354e54fb, 0x5b7fa4ca, 0xf8f3813c, - 0x3c9209e0, 0x3fb0f4b4, 0x4d3b895e, 0x1e534394, 0x2a3a3806, 0x60a0fc79, - 0x94e19dc9, 0xbb4c69cf, 0x850ae31d, 0x2c31f987, 0x73143f65, 0xaa09f5db, - 0x98170efd, 0x319be9fb, 0x4258d64f, 0x35828bf1, 0x0fcd7a5a, 0x0be2907d, - 0xf7b4abf3, 0xad7c2900, 0xd68b0bc4, 0xc42fbf6b, 0x1ee8847b, 0x47da4a85, - 0xfb46b0b4, 0x0e7c89dd, 0x41273c7c, 0x2c1909d8, 0xf9bde443, 0x57a11239, - 0x6f43ca27, 0x21cbfca7, 0x1da5f299, 0xbde1328d, 0xfb449b63, 0x863b9869, - 0xf99ca5e4, 0xf8299f48, 0x60f284b9, 0x5cdf59ec, 0x73dffd7a, 0xa52a851e, - 0xff0f1ff5, 0xd52f3c2d, 0x8ddf489f, 0x4e7f9de5, 0xaf7598f9, 0x104f7e3f, - 0xdf6a1fed, 0x35f74613, 0x9dbd37b5, 0x85e528f2, 0x07ba364c, 0x9497cf61, - 0x6a5f6b7f, 0xd57d422a, 0xcafdcc9e, 0x0e5f4d65, 0x39657ae7, 0xc098df3f, - 0x34744dcf, 0x94f28dfe, 0xca268d1d, 0x84f6b933, 0x7ae11f90, 0x9cfc8823, - 0x292fa6f6, 0x9acffcbe, 0x3788b94f, 0x3cf187b7, 0xbfb8bb4f, 0xf47bb5c4, - 0x2d87980b, 0x446bdbab, 0x9bfc65bf, 0xdf5d90df, 0x67b72afe, 0x1eded0da, - 0x5bae7883, 0x7dc44e33, 0x4d0ecca8, 0x0db77b45, 0xb1912385, 0x9d5dcfa1, - 0x081a1eea, 0x5e50df4f, 0xf3f146f5, 0xfc18ffd2, 0xb9dfb448, 0x63cc31b4, - 0x5fde7096, 0xf518fc9d, 0xd79e1ec1, 0xb17be657, 0x1fd90976, 0xc1f79bd7, - 0xfddfee04, 0xe4b799ef, 0x9f7991bd, 0xef4e6ffd, 0x98d43c62, 0xba2e5ddd, - 0xcf1379f3, 0xb30f6d17, 0xc837bc11, 0xffc486ef, 0x157f7465, 0xfd7e1ee8, - 0x6ffbf779, 0xe99eef3e, 0xa0ae787e, 0xf3e305bb, 0x21bf37ae, 0x3d5efef8, - 0xe87fe137, 0xfd3b15fc, 0x6fd7c67d, 0x91c3a257, 0xee9efb88, 0x5f02bc38, - 0x274e74b9, 0xcd12c3c5, 0x4d9fee74, 0x8e87e28d, 0x33618ef5, 0x57877586, - 0x25fe1bf1, 0x31273ed1, 0x07feaba6, 0xa619efb3, 0x7d57779e, 0x58d1be3e, - 0x379d3f7b, 0xfca50b29, 0xc18f6e2c, 0x36cc2f76, 0xf713fe71, 0x990f1c3c, - 0xa606307b, 0x738347f2, 0xe739c23e, 0xc0ac9fce, 0xca2fb4b2, 0x35e718ba, - 0xdc4725af, 0xc710b08b, 0xfb3b352f, 0x72f9aa60, 0x2f4073b2, 0x511c47b4, - 0x1ccb9e3c, 0xe1011cc3, 0x37ce6b77, 0x994bf62a, 0xea3aa1b0, 0xbe517ad2, - 0x645ed5e4, 0xb8e9b57f, 0xe026d87f, 0xb767e0bd, 0x1a8e7917, 0x5c58ff31, - 0xcea8d473, 0x7389963f, 0x3fe3fea9, 0x23f3c891, 0x87f6be9f, 0x8bf748ab, - 0xa3a7d45f, 0x5d2256bd, 0xdd5d79a2, 0x98ae747a, 0xff9c0adf, 0x14be1d43, - 0xb4abcc23, 0xc791af76, 0xf4fcc523, 0x9beff4be, 0x79ae9b5f, 0xaabb9d12, - 0x8e7ce897, 0xeeacaed2, 0x93b424e8, 0xe8226a8b, 0xa7dc473e, 0xca9dcfc2, - 0x7860fb7e, 0x8eb2493f, 0x4bf7dbf8, 0xd21bf689, 0xe9dfb41f, 0xbee0f08e, - 0xcaee936a, 0x676899b1, 0x8ce7e30f, 0x438307d6, 0xbbc77e0f, 0xc41b5f02, - 0xbf780779, 0x07c7df12, 0x4ff1f6f3, 0xfedf68eb, 0x9409b90b, 0x7bdd543f, - 0x72075291, 0x36b26494, 0x49b8c0b4, 0x0f28bd15, 0xb9d13dbc, 0x5f71f105, - 0x18e52e94, 0x421ce1c1, 0x8e6f80e7, 0x753f21ba, 0xf818b306, 0x9e7e527e, - 0x4f85867d, 0xb5d850a5, 0xee9d9933, 0x3983b8e1, 0x6d7bdea9, 0xd7da3b46, - 0x336e61ef, 0xa3f7ee93, 0x0f3177f7, 0x5e61ef3d, 0xac2fffaa, 0x5f0aca85, - 0x17de3f02, 0x3cf1f9cd, 0x8e8160a6, 0x47dc226f, 0x3f278643, 0xfe9ef80c, - 0x94fe80cc, 0x76e2ad2f, 0x9ee0f5f0, 0x574bfc2e, 0xf210f3a2, 0x2fe4c77b, - 0x7e82af9e, 0xf12f6674, 0x91ee7283, 0x7c11884d, 0xdb72fdf1, 0x0f99d1dc, - 0xe2bf450d, 0x5bd24156, 0x509fdced, 0x2edc0dce, 0xd9ef01e4, 0x343a0489, - 0xa7bdf95b, 0x3dbd2acc, 0xc793ca02, 0xe59fb4c9, 0x20d6e08f, 0x4331fc7f, - 0xd9a5f716, 0xd134fda9, 0x3371d4ef, 0x7a82f797, 0xc96ebe93, 0x9327f3c2, - 0x8afd6b7b, 0x5c6f449f, 0x29cf011e, 0x7fefb4fd, 0x88f59aca, 0xb543a9d7, - 0x2cb4cdfe, 0x38bdbd6d, 0x2a962466, 0x4b845ee9, 0x193fc289, 0xfdab06cc, - 0x1d3e6513, 0xd118af53, 0xe493ec17, 0x597482bc, 0xb9d9db7c, 0xcf4ede74, - 0x4d111ede, 0xbcd1cff7, 0xe6f02b5a, 0x55cec646, 0xa179e998, 0x20ecc2c2, - 0xc4569ff7, 0x8552f3d3, 0x55b7de95, 0xf8e7a40c, 0x90dfc724, 0x9f95053e, - 0x670fd1e9, 0xee34e955, 0x9acf8203, 0x9d1d5e75, 0xd124d85f, 0x82079a7e, - 0x8ef1739a, 0xa73607ac, 0x61739c52, 0x0c41ed43, 0x1d78141f, 0xf39c9093, - 0x883a2d0f, 0xc06bb2cf, 0x158023e9, 0x24a61c12, 0xa763eb94, 0x7ac6df67, - 0xe37b1be6, 0xd05183a9, 0x1b0af9ff, 0xc549f5c1, 0xac5e7a28, 0xb3dc13b0, - 0xa4961c92, 0x67d2a46c, 0x6db73fc4, 0x824fa53b, 0x12ad13fa, 0xb63f2bad, - 0xe4078f33, 0xd7c0daab, 0xb304ea85, 0xdc74e50d, 0x1e1b19b0, 0x9df7a864, - 0x1dc70889, 0xe2278a53, 0xcd46d338, 0xeeb47ba3, 0x7bf19afc, 0x58dc2695, - 0xe9f988dc, 0x247bcbdd, 0x3acbcbe2, 0xff18edeb, 0xa649ff75, 0xde0740fc, - 0xe3fe80d3, 0xe32f7e71, 0xe2d3d7e2, 0x362f3f50, 0x5fd0e358, 0x79f62ddf, - 0xe97a045c, 0xc5eceb55, 0x9cce7fed, 0x25bfd2a7, 0xfabaecaf, 0xf2fbf411, - 0xea1b48c9, 0xe2918bbd, 0x28b6467e, 0x9b48f504, 0x19623bc8, 0xd65015ef, - 0x5833d45d, 0xebcc18be, 0x9492bce7, 0xe382728b, 0x7a5d8d59, 0x6795fd28, - 0xed6a3efa, 0x6d4b6f1a, 0x41cf47e1, 0xe747b2f9, 0x723ac036, 0x61b6d599, - 0x135dd6dc, 0x066dfb4a, 0x87e0fa4a, 0x7c3d6f89, 0xd56488bf, 0xeb6c3c63, - 0xd1121b2b, 0x392dd80e, 0xfa823ee6, 0xffaf037b, 0xe48fd3d2, 0x53e7c2ed, - 0x823eaf65, 0xa08a4f78, 0x2b9ff376, 0x36fc8c1e, 0x5d5efd6c, 0xa9bfbc22, - 0x7c52d4e6, 0xc2a240ce, 0x926d8cf7, 0x8cdd778c, 0x865d4ba8, 0x1fb898af, - 0xfbc0b06e, 0xed9ff5d0, 0xf4107703, 0x08e2ed6b, 0x525757ca, 0x671bd7bb, - 0xc10f7fbe, 0x7bc04ee1, 0x8cf3dd35, 0xb8f03edc, 0x5c9f2237, 0x51b40e76, - 0x7ee1cd7e, 0xd973e916, 0xf5c36b19, 0x0ee75ea0, 0x4ff5831f, 0x76087bf2, - 0xc70d1cd6, 0xeabd11fd, 0xed082c0c, 0xad1f0c95, 0x56c9654b, 0x259659bc, - 0x64eb7f3f, 0xd7927946, 0xa53f5237, 0x99e61b66, 0x42bf5e8b, 0x13f61cf1, - 0xfc8feb66, 0x4fcbc751, 0xfd13b04c, 0xc17e368a, 0x2a0ecdcb, 0x2a77643b, - 0x0f945fdd, 0xfbf40c76, 0x5877588c, 0x47d270cb, 0x2ed672c4, 0x9f013f7c, - 0x3abdf02d, 0xfb809dd5, 0x0af594c3, 0x219f99d6, 0x839ba37f, 0xef739bed, - 0xf775a149, 0xa519d706, 0xfc8c679f, 0x46f5bd7e, 0xb66e1ebe, 0xf42778f0, - 0x4fe514bf, 0x64931759, 0xae1d5869, 0x6c98cf73, 0x3e37accb, 0xfee2ddce, - 0x2af813ae, 0x430d6c41, 0xf8ffba42, 0xe9ffc636, 0xfbf23dfe, 0x15675799, - 0xf941ecf7, 0x4fc3a4e9, 0xe619bf2e, 0xe003f82d, 0x83013820, 0xf2a7f50c, - 0xe38b2c3e, 0xb669d233, 0x2e2b7e61, 0x33dd116a, 0xd307f0a1, 0xdda0477b, - 0x995bfab0, 0xffb94bce, 0x7f714a1a, 0x4ddf787f, 0x7af471e2, 0x639e07c0, - 0x7bf07772, 0x5ac31a9f, 0xf403fe5e, 0x9bdc58df, 0x0dbbc6e2, 0xf756fefc, - 0xdc5df174, 0x5778dd27, 0xa27dc92c, 0x7601eb89, 0xd38d304f, 0x7e6cf068, - 0x8f4fbf1a, 0x85c7f6a7, 0xde671d9c, 0x955f707b, 0x7ba467db, 0x1822ab39, - 0xb55367dd, 0xfdc50064, 0xe07dbfea, 0xbda186df, 0x639f84b2, 0xacf0caab, - 0x55ff7dc4, 0x70e34cbf, 0x1724de48, 0x260e2fb6, 0xdd355d3d, 0x4071809e, - 0xba10b4e7, 0xfba7ba57, 0x28323f5e, 0x09ec89e7, 0x0ae78f88, 0xfdf533fa, - 0xca4e7f41, 0x57748c3d, 0x3a73d1f2, 0x8ecc22f3, 0x21de5bf7, 0x6e15770a, - 0xbb7e420e, 0x14e828a3, 0x178f6bc6, 0xb8c30d2d, 0x7e4e1de3, 0x359b273f, - 0x8f3eaed1, 0xfb24e7f9, 0x5657e461, 0xdeedd8a0, 0x1ed3c47c, 0xbdce999f, - 0xa847f901, 0x7f8544ed, 0xbe77aafe, 0x8ddaed87, 0x92e35ee2, 0xb6cda6af, - 0x6bf1faaa, 0xf27edfe7, 0x37bf330c, 0x7644cea9, 0x8ec27dc1, 0xb3bc9972, - 0xad5a0ed1, 0xf607fe73, 0xe9f85aef, 0xa277b470, 0x17fbf067, 0x09be31db, - 0x7a0a4f75, 0xff7c649d, 0x98517ba0, 0xb2f11bc8, 0x0f28d1f3, 0x9ec7a7bf, - 0x07e58850, 0x1f70d886, 0x99e45390, 0x7c44b958, 0xf9c2d272, 0x146364e4, - 0xe33e8fdf, 0x30e9d3da, 0xab8e938f, 0x7a848f6f, 0x79f81b27, 0xcc3cbf8e, - 0x2f9619cf, 0x60d2913b, 0x7baf3eed, 0xd97bf297, 0x0bf85def, 0x93da6f3a, - 0xaa5bddfc, 0xd21987dd, 0xce15fedb, 0xb5c67a33, 0x1287a849, 0x2d9f4a4b, - 0xdbdabd44, 0x2fbe2df9, 0x2394b637, 0xff77ca3e, 0x7fda0a7b, 0xda5ebbed, - 0xaf9e1071, 0xdeba9d19, 0xade97df8, 0x67618fa9, 0xd72f9ec2, 0xae403d03, - 0x34edea9f, 0x717e06f6, 0x63a6f04d, 0xe6864bbb, 0xf6378849, 0x1bb31b8b, - 0x5cdc6d3f, 0x115fa12f, 0x4f4e58dc, 0xe11c33d9, 0xc37928b8, 0xa71e1ef1, - 0xc97e8fd8, 0x188f0de2, 0x72c7f78a, 0x1f3ff5fe, 0x8ac5a048, 0xaed0327d, - 0xe71656a4, 0x27143c97, 0x025faff6, 0x0ddea9ef, 0xcbce57be, 0xac344495, - 0x66f44b1d, 0xee166f5e, 0xf74feceb, 0xfd7e5d32, 0x5fb574a5, 0x0eecffe5, - 0x9d3f9f2f, 0xa9bcc6e7, 0x7bf7df87, 0xe4068a09, 0x71266db3, 0x51f38f8e, - 0xc104d6db, 0xda8f9c67, 0xa8f00eb6, 0x9cf3b6e5, 0x8736ada0, 0x6bdbedf6, - 0x501ed073, 0x6b999fe4, 0x36677ee9, 0xda3876b0, 0xc23d8add, 0xf4e9b51c, - 0x8e9b53de, 0x3c75ebf5, 0xbb8ca73f, 0x7e24e5f0, 0xeb9998df, 0x0f2f85c5, - 0x94c6fba1, 0xcf37af7e, 0x4d46d501, 0x5b479079, 0xef9bd69e, 0xeffdf85b, - 0xcbf1f73b, 0x93c61ec2, 0x40f79d85, 0xbd73de76, 0xf2f05255, 0xfa0e5260, - 0xaaf28ca3, 0x0be07bbb, 0xbd21ae05, 0xf30b3fb9, 0xbbceb863, 0xbbfae23f, - 0xf331c33e, 0x6fd72836, 0xb6fb2348, 0xe9f8e74d, 0x79e71c30, 0x3ebaafbe, - 0x9cf947c2, 0xfdb967fa, 0x5de62e5b, 0x424ce11f, 0xc2a17a7d, 0xffee2f16, - 0xe96c3b26, 0x98e11589, 0x61dfaff7, 0xd5f8c0c8, 0x63fb3527, 0xad3e2f91, - 0x37ee9878, 0x75e3bc1c, 0x6e94a3ca, 0x1c7de07d, 0x8336d2f7, 0xd2acdd0d, - 0x8b5c5ebb, 0x56e948f6, 0x5be716b9, 0xe53f75ba, 0xbed52fc7, 0x71fb8e15, - 0x9144d42f, 0x53f08c1f, 0x1cf7fafe, 0x2ff8fe0f, 0xabc464f6, 0xc91591f7, - 0x7f78b5ee, 0x5a2d90c9, 0x3c7d17bc, 0xedea10e9, 0x18cff50b, 0x1fbc56f5, - 0xa6fdfb56, 0xeff96d06, 0xe4abaf3d, 0xd4e39091, 0xdcc85c74, 0xdda9f507, - 0xb5645feb, 0x3f18edb3, 0x9727bce8, 0xdae8edcb, 0xbb379475, 0x6e6e78fe, - 0xe9da853c, 0xa379ab9e, 0xe231b7f8, 0xe6b65efe, 0xdbc424e8, 0x5a2427bc, - 0x36bde6ef, 0xcfea00e0, 0x9aee3b53, 0x93d9cf42, 0xe8f91f09, 0xd67ee085, - 0x061bc946, 0x8e28cb65, 0x9e6ac2ef, 0xee5bca17, 0x8d69ee77, 0x2af8fedf, - 0x0d05f7ed, 0xbcc2bf7b, 0x79f99176, 0x3f741f8a, 0xfba1e3c7, 0x605e177f, - 0xac2dcfe4, 0x2814cef9, 0xcca851be, 0xda63fdc3, 0x264dc01f, 0xfff0fff0, - 0x4daee346, 0xe1ea3d47, 0x651b5531, 0x731957c4, 0x2349643e, 0x021bc5bf, - 0x8137cfe3, 0xeb4992dd, 0x4ae7cd21, 0x8f3a2f75, 0x5059ef0e, 0xda03de26, - 0xe4eb839c, 0x1b30ba95, 0x9cd69fdf, 0x02d57683, 0x21f9d328, 0x0bce2956, - 0xf1fee87b, 0xcd06d505, 0x1ec5e07d, 0x7255996d, 0xef14b0fb, 0xfa470ed3, - 0x92bb50b7, 0xa57ada2d, 0x91e39f30, 0xfb51ffb8, 0x5b7cc5de, 0x2b7da45f, - 0xefd498df, 0xb1547b15, 0x0e38958f, 0xe460b228, 0x7237bb97, 0x04b77a3d, - 0x0c3b45f3, 0xafb234ed, 0x420e3b3c, 0x2878aab9, 0xdff54fd9, 0xca5bfdf2, - 0x0caad4f9, 0x279e3a7b, 0x88375aab, 0xb25bbfe6, 0x7a863ea7, 0xd859ba60, - 0xe1ee8c57, 0xa44e2aaf, 0x1c23fbf5, 0x2ced0132, 0xf729ef6e, 0xeea227f5, - 0x18e371c2, 0xb53f8fbf, 0xb37a8bd6, 0x3fae29ea, 0x81563b14, 0x4f675f3b, - 0xb36e75c1, 0xcdebe9d9, 0x23a56ff7, 0x09bff9dc, 0x4557bc22, 0xfce8c2f8, - 0x0dd4517f, 0xc59ba7ad, 0xabcca0fa, 0x7dd07255, 0x293d4ae8, 0x9cdbeb99, - 0xa28bfb5c, 0x0b39c51e, 0x6fab1d72, 0x3c147c01, 0x1fa2b3ad, 0xbb6789dd, - 0x13ef1d3d, 0x94175d68, 0xcc9cf089, 0x47367ae0, 0xf6061bdc, 0x3c137dbb, - 0x9a759383, 0x32706578, 0xc163a7b7, 0x5af1c27f, 0x5438f227, 0xfc839658, - 0xe6a9c079, 0x19e53c1e, 0x302be02b, 0xa3f4fe3a, 0xd274f000, 0x7bc7027b, - 0xad12fdeb, 0xa21f3047, 0x83afce5f, 0x2ad00e28, 0x4e8503d6, 0xb4d92fc0, - 0x54bd09ce, 0x21f80ab5, 0x2da1ed15, 0x6afa835b, 0x0be286f8, 0x3ebe2eec, - 0x7c704554, 0x4c393d56, 0x6f82e5d8, 0xbf120c9e, 0x6cedc0c7, 0xec51fd65, - 0x3d3e6570, 0xef40e1d9, 0x7c2ac961, 0xe999d3f9, 0x7dead93d, 0x5e74fe94, - 0xd2986e60, 0x0bc1550a, 0x5c067825, 0x6b7d91d2, 0xde0892ce, 0x2a7ad581, - 0xb259d51f, 0x8da6ee51, 0x11f179dd, 0x7e7857d4, 0xebf47907, 0x39bbbeef, - 0xa951f707, 0x7dc472fe, 0xeb0fc8ca, 0xef183799, 0xd894afd9, 0xa03acd69, - 0x8fdfe32d, 0xb9fabb63, 0xf89efd5e, 0xdcfd9ff7, 0x69d8c159, 0xf85d8590, - 0xebc347ec, 0x4665fbd5, 0xb93c7236, 0x5f4f308e, 0x597677d2, 0x0467ef8d, - 0xcbfcee1f, 0x6e3023ab, 0x687dae31, 0xe9679e2f, 0xd3ef53a7, 0x5ed660ed, - 0xa3b4efb8, 0xee17ad31, 0x2438eb4b, 0xf0033987, 0x038056f5, 0x572ff1e3, - 0x5ed9e998, 0xf0652ac3, 0x8f99da2b, 0x6bba67f6, 0x5f902ccc, 0x73b934ba, - 0x739319ff, 0x3ba5f7d4, 0xa4ec7d68, 0x9fa9a5d3, 0xc77787e8, 0x569dfe3f, - 0x87f913d6, 0xebf715e3, 0x06b75e20, 0x740a4cb5, 0xe04aafde, 0xafbeda6d, - 0xe0e33f68, 0x943a8dc6, 0x3a35c1f7, 0x26b93acd, 0xca43ec59, 0xd7089964, - 0x61417db4, 0x438f4859, 0xe6082db2, 0xccfc6ae7, 0xd7e00ce8, 0xfb11e3f9, - 0x8702fdc7, 0xa7842d93, 0xf25a86dd, 0x365f772b, 0xbb29fdd3, 0x8125958c, - 0x23eccce0, 0xd8ebc405, 0x5f6833f3, 0x5e157fca, 0x7a87b5c7, 0x588e3173, - 0xbb1c78c3, 0x7d71bf1b, 0xd185b1d4, 0x710ef739, 0x1b63a80e, 0xa01ebca3, - 0x77dc49e2, 0x8b7df203, 0x80d63f7a, 0xe32f1d86, 0x28de5efa, 0x72e4fed1, - 0xf7118b7d, 0x221aba5b, 0x65bfcc64, 0xae3dc558, 0x59b0cb7a, 0x9c38392a, - 0x17e7e7ac, 0x07beecc6, 0xc972bdc7, 0xec87e748, 0xef747c07, 0x11c695c0, - 0x3cefbebd, 0x6c156bce, 0x7b3bde0a, 0x5f119938, 0xd0c1f3f8, 0xf29ac16d, - 0x8899d958, 0xd4cd34f2, 0x002da0f2, 0xc4528add, 0x7aa370fa, 0x89fff3cc, - 0xe8a63b1e, 0x8eaca731, 0x74a46487, 0x817163d3, 0xc962d8f4, 0x5ef8871a, - 0x871694dc, 0xd87c5cf4, 0x8f481310, 0xac38076d, 0x007f7720, 0x7b67c3f9, - 0x9bb1e81d, 0x0eac7a54, 0xbf0058f4, 0x3ae52924, 0x5ff3cc7a, 0x51db6f23, - 0xe798058f, 0x1fae14f0, 0xbc363d14, 0xb1e914f1, 0xcd3a75e1, 0x29feda39, - 0x5263d3d7, 0x2c68accc, 0x01216c1b, 0x89f106f8, 0x27c47779, 0xd41c713e, - 0x9629f967, 0xfd9f4bbf, 0xecfa7af8, 0x8abf08bf, 0x3afc5b3e, 0x3ba37f23, - 0xdfe231df, 0xfd18bbc5, 0x26e2cfce, 0x3716cfae, 0xcf0fbe31, 0xec0d8f4f, - 0xff18c7a6, 0x6f2f165d, 0x7d486aef, 0x2fe85ee6, 0x99b06ed3, 0x97667ea1, - 0xeb56cb5e, 0x1e94fcb5, 0x1ba1daf4, 0x0baf6bd3, 0xaafa06bd, 0x7f51ea2f, - 0x6a35b0be, 0xf763977f, 0x5edbf3e8, 0x5b78f943, 0x4701f3a6, 0x9dfebe45, - 0x90b3e7d1, 0x1e11eaaf, 0x4235d390, 0xdc2adb5e, 0x03f8ffd4, 0xdb657e7c, - 0xca0f5a24, 0x57bdb8eb, 0xf07b235e, 0x31a4e180, 0xff3ed15f, 0xe18926e2, - 0xa6e9b2d1, 0xfef1a7ca, 0x8192f630, 0xd4e53889, 0x143f150c, 0xf8a12a8c, - 0x999e8161, 0xc96ddf71, 0xb73fbe28, 0x7b959444, 0xf53b0ba2, 0xcdbedfa0, - 0xf7e9fb86, 0x7bcffc34, 0xdcf7134e, 0xf2417b4d, 0xdd5ffde0, 0x712a7bcf, - 0x97fbed38, 0xcba77cc5, 0xf61f842d, 0xde73e06e, 0xe5e3fb2f, 0x8d4bc090, - 0x478bc5ac, 0xe517880a, 0x8782ad5c, 0x565bb7e2, 0xf8a75c60, 0x32fc8959, - 0x782b79ff, 0x761f76ea, 0x909dff23, 0xdb62f7ee, 0xd25bbf35, 0x144477ed, - 0x7fcdfb3c, 0x323fa2bb, 0x37bc08d8, 0xf482f81b, 0xfc4ffb87, 0xb8c7421e, - 0x3d6a71fe, 0xc3c09afc, 0xe371ca88, 0x2e99add1, 0xd5f98afc, 0x804c1ff7, - 0xb71f67f9, 0x6303fdd2, 0x9ee898c7, 0x3e41adbe, 0x9f0a6fd2, 0x3e70fa19, - 0xecfd116b, 0x4b945c4e, 0x241a74fb, 0x2e13da0b, 0x37bf106f, 0x082df805, - 0xf67fecaa, 0x478124ea, 0x689efd0b, 0x006f5883, 0x4e57e8ef, 0xc01fd652, - 0x88cfca3b, 0xd7074e46, 0x2c874e16, 0xe567e3c6, 0xf30d92d5, 0xf70de5ea, - 0x8a3e711b, 0x50bf85de, 0xfc545d35, 0x27f357a9, 0x7bad547d, 0x34fbe225, - 0x1887e553, 0xfc06993f, 0x0cd891be, 0xfc3df7fe, 0x5f77eddb, 0x2f7bf3ae, - 0xa78e1f72, 0xf44788ed, 0xdc7d12f3, 0xbac2f26e, 0xddf5d610, 0xf06b77a5, - 0x6bb9fe38, 0x249abf9c, 0x3b01c62b, 0xefc354f1, 0xf056cf6d, 0x788afc84, - 0x63279c6f, 0xf8837e79, 0xf9bf1fdd, 0xb5083ee2, 0x9d37171c, 0x906ffde2, - 0xbcc02c6c, 0x7fdfe47b, 0x927b6f90, 0x2d1f435f, 0xe413beff, 0x2efb823b, - 0x77e24ddc, 0x34231a19, 0x7dfec279, 0x35b01db8, 0xfd1cf808, 0x1b06c3e8, - 0x2fe0a7de, 0x3d62b1ef, 0xaadf7b43, 0x420f97ca, 0xb12e3180, 0x28ceccc5, - 0x76e5f470, 0x6edf5aa5, 0xb331620f, 0xbfee7ab2, 0x4f5ba09f, 0x1e528df6, - 0x5ea1e386, 0x54f1806c, 0x7d7f2cf9, 0xd7e5f8af, 0x0fc6579b, 0xce32979c, - 0xd87e7bdf, 0xfe799ac5, 0xd0245f02, 0x26dfe179, 0x9fa9bc63, 0x7bdf57a4, - 0xfe6fdcae, 0x3b3fe84f, 0xfee7a625, 0xf685bc59, 0x4efb2937, 0x0e3cfd94, - 0xf3fb130b, 0xae33fe6f, 0xfcec57e3, 0x8e9641fc, 0xae33707d, 0x3a06b90f, - 0x88e57ac7, 0x573fe281, 0x2e7bf026, 0xbf7b7f6f, 0xedf2f51e, 0xff0114a8, - 0xe44b67b7, 0xaec51d1f, 0x6d1da347, 0x80257da6, 0x1f9811bf, 0x1ca9a8c9, - 0x333ee78f, 0xe19678b7, 0x17de36d3, 0x6dd20efd, 0x7bf74c9c, 0xc6a3db34, - 0xc0fa3ae3, 0x71819659, 0xa9ef5877, 0x1621e67d, 0xd8c6f583, 0x18fdc863, - 0xb1f9f75d, 0xe8c70099, 0x0acdb223, 0x0fefa6f5, 0xf77cc50d, 0xe63af5c0, - 0x0c6be154, 0x73c32cf3, 0xed5ba33e, 0x22ee1133, 0x2e305fb0, 0x71b8d45f, - 0x2e439e19, 0x7b512f5a, 0x2939db97, 0xbdb3e61c, 0x4349b3fa, 0x3d401f50, - 0x9eb5c6ec, 0x48d573d7, 0xcf394c36, 0x24675c6f, 0xefc3517d, 0x91eed86f, - 0xebf79998, 0xdbbf4331, 0x2cfb43d7, 0xd05b638a, 0x7cd5720e, 0x5cdffb46, - 0xdfb52700, 0xccc5cfc6, 0x94567687, 0xa9fb9a97, 0x12f5e2bf, 0x457323c3, - 0x543af8db, 0xc360c474, 0x9f7b75ef, 0x2a74f5a5, 0x8a90978c, 0x02778eeb, - 0x884739c5, 0xffc77b7d, 0xed5df90f, 0xd58fd38c, 0x2feb92fc, 0x9fbf2989, - 0x4f9f57ab, 0x97d3e8eb, 0x2db10bef, 0x3f414631, 0x498a8cef, 0x7d5f11d5, - 0x71b4e746, 0xf013935f, 0x179c547d, 0x8cea3fdb, 0x409f7d51, 0x4f3f2b2f, - 0x8e30d05b, 0x321551ce, 0x9aa39d07, 0x8fdb9a36, 0xc828feef, 0xde33fb83, - 0xe37af835, 0xe23ffdfb, 0xb6dcd3bf, 0xb6dfeb9d, 0x1fda16e4, 0x307f1e7b, - 0xb65c6009, 0x717d265e, 0xce819b7e, 0x7018c90d, 0xe76dfc44, 0xf5fec5f6, - 0x5bf3dfbc, 0x7e361db8, 0x70931dc3, 0x59b05dbd, 0xf5c46739, 0xce3fe2b3, - 0x62f388b7, 0xfc8d1b95, 0x5fefacde, 0xac3d1477, 0xbf911efc, 0xfceb2d9e, - 0xc92f6cfd, 0xffad594f, 0x2ed0ccf9, 0xefe9043f, 0xb9f88afd, 0xa18188fc, - 0xb99d221f, 0x4f8ff944, 0xef871d70, 0x3b251ba3, 0x3a2a3b9e, 0x1d90f26e, - 0xdf7799ed, 0x393d71cf, 0x3afba261, 0x1cf055ce, 0xef9328f6, 0xf781bf2f, - 0xe3351c9f, 0x97e03cce, 0x05ef8479, 0x3be1116c, 0x473f336b, 0x2ab47597, - 0xe7ae3e76, 0x7fdc7813, 0x9cccb541, 0x89f0fd2a, 0x37799f64, 0x1ee8175f, - 0x598e856b, 0xb8f9cac6, 0xe562de9e, 0xd9bad8fa, 0x2fcde740, 0x760cfd08, - 0x5103dd3e, 0xac5d6bbc, 0xe2ff4551, 0xf8b175a6, 0xc42b2853, 0xe265b439, - 0x91b17a9c, 0x47bc538f, 0x8d546cb2, 0xf4a3f4a3, 0xdbc5dc6b, 0x67f135a5, - 0x2317fd4f, 0x2fcf347c, 0xfc27a88c, 0x7e36e9fb, 0x7a8cfd0f, 0xee155aff, - 0xaef51817, 0x8c72974c, 0x2d35333a, 0x0f643ef0, 0xd31fcf8f, 0x747f7e69, - 0x35825fd4, 0x6cba91f9, 0xdfa07790, 0x4edc0d6d, 0x653ecbab, 0xb2a2cb2c, - 0x5cbbe505, 0x27cb85c4, 0x75f57df0, 0xa3974719, 0x92cd4fbc, 0xdb981f88, - 0x29dfc469, 0x8accbb07, 0x5905a779, 0x6802fdbc, 0xf758728f, 0xd04b972c, - 0x1fd4560f, 0x830017ff, 0x8000007b, 0x00008000, 0x00088b1f, 0x00000000, - 0x7cedff00, 0x55537c7b, 0x393ef0b6, 0x526d3479, 0xa0fa5b42, 0xb4db4e50, - 0x9494b14d, 0x27457897, 0x880b5a3c, 0x46107006, 0xf4228206, 0xbd185499, - 0x35fde338, 0x9c414415, 0x0e7c570b, 0x42d2d37a, 0x1429a2c1, 0x20d5b16c, - 0xb47441d2, 0x3bd15ef6, 0x0f8afea3, 0x52d25a04, 0x8ef4f987, 0x6b5adfa3, - 0xa126d39f, 0xdf7ef515, 0x37f5375f, 0xef6758b3, 0xbdeb1fb3, 0xce275ef6, - 0x620a3b5d, 0xd67318e3, 0x319e920a, 0x6abd54d6, 0xc614f273, 0x2c8ba68a, - 0x67e7c242, 0xf01192b4, 0x2c7133e6, 0xd3e3b187, 0x1939db3f, 0x74339dda, - 0x7ff41d26, 0xc637d357, 0xf3ec6064, 0x991cc64a, 0x5ea5b388, 0x698459c0, - 0x8c09e2c2, 0x060e313d, 0xead8ca99, 0x0c0599e6, 0xeccddf9e, 0xf8bfb19b, - 0x7981f436, 0x47a20d5d, 0x2e9c0027, 0xc60dba8e, 0xc680f77d, 0x7e3b280a, - 0xfdda8e83, 0x153da007, 0x4faed8e0, 0xdcbfc004, 0xe86e61a5, 0xc89771b0, - 0xb2fff418, 0xc5f7a05e, 0x90597ee7, 0x3adaf804, 0x2983aac1, 0xad9aef8f, - 0x1efec24d, 0xd9bc61c0, 0xbc6869cf, 0x7f78fbb5, 0xc5e433f8, 0xf186b633, - 0xe2a635bf, 0x632e599b, 0x65a7cce5, 0x69efd0e9, 0x115da7cd, 0xf87bedbc, - 0x1827b15f, 0xc60fad2f, 0x4bb6d9cb, 0x6f403462, 0x750ef3f0, 0xef386dd7, - 0xb4f41bfa, 0xb637d9ee, 0xeb8f5e9c, 0x5c30d06e, 0xef1bece7, 0xba02ef8f, - 0x963351ae, 0x8e90693c, 0x0cc788e5, 0x559d8eb1, 0xb31fa4da, 0x1c75909e, - 0x3b8c6719, 0x63fc0d7b, 0x3df49b12, 0xb8dcee90, 0x628d8c91, 0x740b5dcc, - 0xb67e0049, 0xf00f360a, 0x4765b8a5, 0xf3d616bc, 0x02fdfe3d, 0xf11db6f0, - 0xb6d73c22, 0xbd2fd408, 0xad62c38d, 0x60aff16d, 0x0aafc51f, 0xb0696aa6, - 0xb9ce32bf, 0x7df10271, 0xbfef3373, 0xb5e015b1, 0xac5f8fc3, 0x0ac6bedd, - 0x65dd4a70, 0x72b864ad, 0xb17e651c, 0x739c782d, 0x8e857cb2, 0x2c1a2f97, - 0x10bba46a, 0xaf7e4569, 0xadbcb817, 0xdc799bbf, 0xacc94f20, 0x87406042, - 0x9013e644, 0xbd29c0df, 0x86fce41d, 0xcb55903e, 0xf17edd20, 0x1d5b0475, - 0x6c99c740, 0x3b3e1064, 0x7fa82922, 0xa83529be, 0xecc4a6fd, 0x52b9f6a0, - 0xdf3e105e, 0xff505d72, 0x4199d605, 0xe7d3adf8, 0x685ff506, 0xdb84185b, - 0xeb8d4998, 0xba5cad6f, 0x999073f8, 0x041d2b57, 0x70287a15, 0xd8c54e86, - 0xee0bc13f, 0xa036ec9b, 0x19288ccf, 0x3e397367, 0xd8d1f002, 0x06ddb37e, - 0x20919d74, 0xc7016ce3, 0x05f69593, 0xe538ffbc, 0xfb785bfd, 0x2dfb4a35, - 0xd2a27dbc, 0xafc72b7e, 0xf1eed467, 0x03776adc, 0x8ed1ebfe, 0xb6f8096a, - 0x138aebe4, 0xfde9a023, 0xa77745aa, 0x45583f02, 0x18d36306, 0x0034875b, - 0xed182ed6, 0x351a4a78, 0x7ff4aed8, 0xe357b255, 0xd14bdef3, 0x63226cb9, - 0x51dfc80d, 0xe6321f3f, 0x716779a3, 0x1159b2d2, 0x33ea1f06, 0x0cf4d08b, - 0x631a51e8, 0x0db18d82, 0x906f4831, 0x0477a213, 0x89a55f41, 0x8995ebe0, - 0x94a8df04, 0x63336ad8, 0x821695ed, 0xf4ad2b27, 0x74e554fc, 0xda576f82, - 0x5953be08, 0xd2a3b048, 0xe290504e, 0x9f1872d8, 0xa23eb1ed, 0xd5b87a41, - 0xfcc2cf23, 0x7e40cff8, 0xd4c64286, 0x1722acec, 0xcabf79d0, 0x65f48ad6, - 0x6ce98c6c, 0x5ef3e0d4, 0x815243a1, 0x46a7bade, 0x0f40eb58, 0xf37a0f8c, - 0x4617a04c, 0x11bac1a7, 0xe59c6168, 0xbb43524b, 0xbad69d71, 0x029fda11, - 0xf587ab73, 0xda991ad4, 0x1cc9f602, 0x34f1100f, 0xf7aa8d0e, 0x7fec0552, - 0x1ff5045f, 0x0236c603, 0x196825fa, 0x7de0f7c3, 0x1ffd8116, 0xdfd81163, - 0x684024fc, 0x10e1adaf, 0x37f48224, 0x43cde741, 0xe2e09efb, 0xd555d8eb, - 0xee304921, 0x5c7ca9ae, 0x29f13158, 0x8119cc5f, 0x499fb2f6, 0xb8394c23, - 0x005abd1f, 0x83d5e881, 0x2bb009df, 0x45034f59, 0xdb24f402, 0x01d4c113, - 0xbd4d757a, 0xe09f0829, 0x3fea0c4d, 0x6a0a59b1, 0x8259f3cf, 0xb49f27da, - 0x3b53e106, 0xbff507a6, 0x105b43f6, 0x61575d7e, 0xcfebff50, 0xfef083d9, - 0x618fd81c, 0x94defe78, 0x9ff50428, 0x703ade0b, 0x89aac67c, 0x232df33e, - 0x1bf79e83, 0x1b869d38, 0x78358177, 0xb71f855c, 0x7f1e0f4e, 0xdc782da1, - 0x3d87cb1f, 0x906a27a0, 0x13d07aff, 0x4f41fb84, 0x0de720d4, 0xbf8827a0, - 0xd0827a08, 0xcf827a0b, 0x209e820f, 0x827a04de, 0x13d011f8, 0x4f419bc4, - 0x3d051e10, 0xa357e7c1, 0xef3cbb57, 0x53de7949, 0xed8cbcf2, 0x8d5d3a20, - 0xefcb6f2e, 0xdfbf23bf, 0x079bef81, 0x30bcb0e5, 0xc835f543, 0xf398ccf3, - 0x87582eda, 0x01575d6d, 0x6f7d4dc6, 0x8246ac8a, 0xc9cf0e6e, 0x5aab8c4a, - 0x9456d962, 0x5bdf7b5f, 0xa70fc42a, 0xfb42b69b, 0x78ffe696, 0x4dfddb07, - 0xcdf184a2, 0x459fcdeb, 0x5f3d38e3, 0x2c753247, 0x3459f7be, 0xdf654bc6, - 0x42b7c230, 0xb9c5fa3b, 0xe5f3228d, 0xb57bbaa0, 0x5663ded8, 0xe3168f70, - 0xa3437b33, 0x5a52f916, 0x6fed48df, 0xedc1357a, 0xed41d5f5, 0xb00fec26, - 0x4689ed54, 0x56685e7a, 0xff51f3c6, 0xc3f73332, 0x6f8fea17, 0x5bd61ebe, - 0x562ab8de, 0x3697f584, 0xd77f17bc, 0xe2ffd00f, 0x1c721791, 0x0b797ef0, - 0x1c18678c, 0x2345bcaf, 0x65fd7ce3, 0x1882c6e6, 0x621a1ba0, 0x87acfcb0, - 0xc01b676d, 0xd736942e, 0x577c6195, 0xc343b96a, 0x5ebd3e80, 0x01d710b1, - 0x71062a7f, 0x9189995b, 0x7ef1e87f, 0x8c177d15, 0xc4f79afb, 0x7a87e82d, - 0xe3478f5b, 0xd04dbdbc, 0xabbf803f, 0xb11c7953, 0xfc4b553a, 0x1e3a69eb, - 0x16fb412d, 0x774e71ef, 0xfff68fb5, 0x02f78cba, 0x8b377a24, 0x5afa2e3c, - 0xc6507c45, 0x9a33a173, 0x4619ed8a, 0x97a757dc, 0xaa7f77cf, 0x579b9fc4, - 0x9ff5c6ad, 0x55365c4a, 0xae05fb24, 0xf1def01a, 0xc2b6ebf3, 0x30bd4a52, - 0xf7f210ee, 0xbb6e3ca8, 0x69bf471c, 0x1a3ed43e, 0x30aa7ee8, 0x807c8f36, - 0xaa636fdc, 0x6815fa8a, 0xe80ae61d, 0x8c9069d7, 0x160fcf28, 0xbf911ba6, - 0xe7c423af, 0x0eb5bb85, 0x7c4d2580, 0x47534ebe, 0x675dca34, 0xe31164d3, - 0x7fbc6551, 0x901de791, 0xb9be01ef, 0x9e454f89, 0x338e036a, 0xfcfe3fc8, - 0xbd1354fe, 0xdef3ca77, 0x7f603b92, 0x2b28969d, 0xcb5da5f2, 0xa5fd708a, - 0xbe7160e8, 0xa46ae4d6, 0xfddf3283, 0x2d7a3f32, 0xbfabe22a, 0xbbf72359, - 0xf5058ea3, 0xd57e70d3, 0xe4c7af06, 0x3bfbf339, 0x73d97fa0, 0xbef8c322, - 0x8f11534c, 0x20fcc7fb, 0x9d32dd68, 0xf8be34cb, 0x2d7900f8, 0x1bd0196b, - 0x8b79c903, 0xf11227a2, 0xa763e153, 0x4aebe445, 0x2c1879d4, 0x8eb1acb9, - 0xced41ae4, 0x4d3907ad, 0xff20ea8e, 0xdccffc97, 0xfc0ad54f, 0xfb2559b9, - 0xb5c7154d, 0x3e2fd100, 0x7853fb27, 0x1f00999f, 0x00146c0b, 0x4fa614d7, - 0x917c4155, 0x21e6362c, 0xb6a9753f, 0xff9854a6, 0xc87ec97d, 0x6489f142, - 0x553e43b4, 0x66e0d97e, 0x7efed023, 0xdbce24f4, 0x047904df, 0xd11e5bcc, - 0x9073ef3c, 0x282b7ecf, 0x7fb7ac08, 0x5ce28697, 0x00833b10, 0xe99acd71, - 0x94be5f5c, 0x8844d31c, 0x54abcb17, 0xc832afb4, 0x5f98f4bf, 0x62eef6c9, - 0x28adea63, 0x452765a7, 0x2be60453, 0x9d7fd4de, 0x86837881, 0x57a72af2, - 0xff30fab0, 0x255a326b, 0x9deacfc0, 0x9d379869, 0xe2d3eaad, 0x3e21677b, - 0xcbcf9c7f, 0xa7cb4f50, 0xd4519f73, 0x193da3bc, 0x57e60960, 0xafc8cfe2, - 0x3a99f242, 0x8c75c7fc, 0xf21539fd, 0xb26f8c1a, 0x37c63659, 0x048ce2f9, - 0x7f995fd2, 0x1710276c, 0x13f5a612, 0xdfa809ac, 0x3cd2d45b, 0xab6f77dc, - 0x71f484c6, 0xc62a1db5, 0x22ca7b75, 0xafd82aad, 0xa251c373, 0x815fef63, - 0xf65710ce, 0x33ca3226, 0x67a7197b, 0x6797336f, 0x44f04697, 0x9e20fbe0, - 0xe0845e34, 0x5ea682a9, 0xd9347f77, 0x510ac621, 0xcb2dd7fe, 0x68bc6150, - 0x80337203, 0x57b91447, 0xf5c0a5fc, 0x977546fc, 0x7bde1238, 0xe7fdc343, - 0x48d353df, 0x9968e7ee, 0x46f5f103, 0xc62bf92b, 0x887de8aa, 0x52fe28a7, - 0x67c435fc, 0xc7254f14, 0x147e497a, 0x6d50bc3f, 0xab8e04d2, 0x821bdfbc, - 0x0580f32b, 0xe0ede3e1, 0xf8c0def1, 0xa6fc7923, 0x1e740f8c, 0x6afe7481, - 0x70fc958a, 0x91f042ca, 0xa41577a4, 0xf59e8a77, 0x01cd5c80, 0x3810cab9, - 0x1d76cabf, 0x728073a3, 0x00e741d6, 0xde7cd105, 0xf11f9c02, 0xd2130e48, - 0xedffda04, 0xdb5e9c69, 0xa7d8a864, 0xc4b66913, 0x698d8034, 0xa469318e, - 0xb792261f, 0x408cb2f5, 0x35d0927c, 0xf75d7d84, 0xf06e7e27, 0xda3dc815, - 0x08575f99, 0xfe203992, 0x6ed3fd29, 0x69c34b2d, 0x18161d6c, 0xbd7188af, - 0xc5d9e451, 0x1b95b2bb, 0x303992f4, 0x7fc3b2fe, 0x72c567a0, 0x279e117b, - 0xd8e0fe40, 0x27992f10, 0x8f627bc3, 0x4fd73c16, 0x73577396, 0x73d3ee30, - 0x0519f379, 0xffc9c60f, 0xf5e72694, 0xc8a7fcb2, 0x10ed58f2, 0xabdf683c, - 0xee1355bf, 0x90782e5e, 0x8784bf07, 0x45e4621b, 0x99a2bf62, 0xbf47f41e, - 0x8ef29404, 0x2fa4719d, 0xb9fb08d4, 0x2fffde4d, 0x0263bed5, 0xc684e7ec, - 0xc2f98a9b, 0x2b08f289, 0x418cbf8e, 0x64f60180, 0x7820eb39, 0xd879ca3a, - 0xc7bb8347, 0x81ff3c62, 0xf8c56743, 0x8d537aa7, 0x2e66ed11, 0x3cc264db, - 0xff514805, 0x9f1fe4fd, 0x0b8830cf, 0x5f0aff90, 0xcbecd31b, 0x073f00d2, - 0x749c493c, 0xefa5fbe5, 0x3e468e1f, 0xd0e6ff76, 0xda19db92, 0x3bb23e9d, - 0x1a551525, 0xa8c41c9c, 0x906d32c3, 0xe0bf0abf, 0x1f1052df, 0x90630f61, - 0x42cf622e, 0x177ffbd2, 0xabb1fa19, 0xf3a151f1, 0xac7e642f, 0x21f6e16d, - 0xdd0abf94, 0xa21e676f, 0x5daff81f, 0x23a617c4, 0xffca147b, 0x0407f1ab, - 0xcd363971, 0xe431d38e, 0xdb8ab26b, 0x2035e4ab, 0x3beeb02f, 0x0bada398, - 0x8fa892e0, 0x32e72434, 0x7ccb969f, 0x167980fa, 0xdfff5258, 0x9a44e9f1, - 0xe91a7b63, 0xfd4869ad, 0x32c7d50c, 0xe2aefac9, 0x67a43c6f, 0x3579fac1, - 0xf85664bd, 0x8e7f802f, 0x7fa4d10d, 0x625d7f0a, 0xd5f7e903, 0xad18f3cf, - 0xf059bcab, 0x847f52f8, 0x10b00a5e, 0x884363e0, 0x1afc2a3e, 0xf6291ece, - 0xfb96b4ec, 0xa27df763, 0x8ff2f307, 0x1309df05, 0xceeca7da, 0xd282640c, - 0x8eaae3ff, 0x38c0f7b1, 0xf0e4cf1f, 0x0159c634, 0xad922db8, 0xa49e23b4, - 0x3f7ee373, 0xa167b216, 0xf858fe7f, 0x9e385be7, 0x5f1095a0, 0x04cb3096, - 0xef0d69f8, 0xc57dd8af, 0xecbc7fde, 0x4fd439da, 0xbee06f60, 0x47a25c60, - 0xa782fddf, 0x256a4406, 0x5f5c6a98, 0x0aa7acea, 0x27f9e0d3, 0x43cf4dbf, - 0x05d6d87e, 0x2e7e878f, 0x3ce22275, 0xebf1baef, 0x9caacd3e, 0xfc0679c1, - 0xf44b9cd4, 0xfd53f15c, 0xb25a1965, 0x2833ab53, 0x69922fde, 0x1ec98b6d, - 0x87f829f1, 0x08fa4f7e, 0x5fa0ce55, 0xc8793fe9, 0xefa008e0, 0x4c3bf079, - 0x3f67801b, 0x97e81296, 0x3479ed8e, 0xa451f913, 0xb9e2e775, 0x3feab9e3, - 0x2edfa0a4, 0x2670f3da, 0xb67b8dc5, 0x5ffc6264, 0xa668f354, 0x0728f08d, - 0x4e6a1fe5, 0xd703ee87, 0x101adeed, 0xf26526a7, 0xc47979f8, 0x1f8c7cb1, - 0xf1735de7, 0xcbf41321, 0x4260adf8, 0xeb35f831, 0xddfd0878, 0x77970b0a, - 0xec8233b6, 0x43678c31, 0x2f65d7be, 0x3d7d45a8, 0xb34cf965, 0x74bfe31a, - 0x056bd135, 0x804b6cf3, 0x6088f676, 0xfd8163aa, 0xff6356c7, 0x6d049b55, - 0xb1fa1c62, 0x97987991, 0xd247d2e9, 0x247cee3a, 0xaf9f1daf, 0x9f3f8078, - 0x7534f3a7, 0x694f38e2, 0x37a475ad, 0x278c34f6, 0xd2ebf595, 0xcadef4b5, - 0xcbc5026d, 0x4f193cca, 0xee0757c6, 0xfdce9753, 0x8db29b32, 0x32adcfec, - 0xe07e6e5f, 0x611237bd, 0x1d6349dc, 0x7f6874c6, 0x66b389e7, 0x139f3c1f, - 0xf3073e73, 0xe3ad0c86, 0x77dc62d9, 0xfb8ace8d, 0x2c9b9298, 0xdfff6026, - 0xe11c7ccc, 0x3d5607ca, 0xf2768c5b, 0x73ca08e9, 0x13adf594, 0x83e61524, - 0xbf6fabc7, 0xee76e913, 0x778a0889, 0x256755d7, 0xdfc81fb0, 0xa5ff02f7, - 0x41f6c64c, 0x05f08efe, 0xd825dfc8, 0x44ca81e2, 0x94aa5fc2, 0x5ca5b208, - 0xb899d6be, 0xbc6e193d, 0x4b9790c9, 0x3ca64760, 0x7c41e302, 0xcd9c6f38, - 0xcaf40e92, 0xb35e5f18, 0x0657de45, 0x4ee79fbc, 0x98748d9d, 0x769ee5b2, - 0xd2e31d0c, 0x56f2fe79, 0xa82923e7, 0x381f6bc7, 0xb4317cf3, 0xe7b74aaf, - 0xbb11fbe1, 0x7e3e512e, 0x15e1e5bc, 0x1aa2ef48, 0xbc9fdf1d, 0x644f73ef, - 0xe78b3c26, 0x286a6f75, 0x3aed763f, 0x8016fcf3, 0x47bb6d77, 0x3fef281b, - 0x7113bf76, 0xba7f533d, 0x97470d9e, 0x8f67ae9f, 0xd53e90a6, 0xfce59e80, - 0x3d733d7c, 0xdcf44550, 0x15ff6e9c, 0x8d39dbca, 0xebf5053b, 0x240df65c, - 0x8136eef7, 0x5fd8a1f8, 0xf2a5fde5, 0xde554bfe, 0xce02336d, 0xc6432f15, - 0xd63ef486, 0xc62665f2, 0x979b97b5, 0x47dc088d, 0xfb023c28, 0x35864c86, - 0xda7dbd03, 0x69a7db2b, 0xd856e91d, 0x8f1534df, 0xabdb4367, 0xbdb255d2, - 0xcf0ffc85, 0xc5ff1433, 0x0f78b43a, 0xf82ad651, 0xaa3ef122, 0x6af3a6f9, - 0xd81257ba, 0x7de741a7, 0xe01a7d8c, 0xe75b8777, 0xc713a0d5, 0xe3da0f51, - 0x31543f6b, 0xbdbf805f, 0xf9922bae, 0xc81de602, 0x114f6023, 0x4b7f1fc0, - 0xd87d9052, 0xe7042e9e, 0x36aef013, 0x15f21fa0, 0x2dfc65ef, 0x9f8835d9, - 0xfb3e72d7, 0xc47c408f, 0x389849cf, 0xe71e906d, 0xd173ba5b, 0x70f42b2e, - 0xb926ed1e, 0xf87e6b29, 0x99f44092, 0x7b9d5e7b, 0xdb1cfa75, 0x7c8b9dd3, - 0x9ae9af3d, 0x5f947986, 0xfc8b95db, 0xedc2be71, 0x93a54ffe, 0x11f8bcf2, - 0x05d800d8, 0x3ca260a7, 0xa1ec5f2f, 0x927fdcbc, 0x96cee5e7, 0xfb7764dd, - 0x88b9f95b, 0x9051d54b, 0x1508e780, 0xeed1da67, 0xfcf227f5, 0x21b7c609, - 0xcba466bd, 0x97dd53fe, 0xdfec10b2, 0xe1390189, 0xd439da79, 0xe38e2d73, - 0xc17b432d, 0x1d58a372, 0xf501778c, 0xd8af9e1e, 0xe519ba90, 0xd4679cff, - 0x6fa3b424, 0x49ddfee5, 0x45af68e7, 0x638a4499, 0x7f0069e0, 0x11e1f607, - 0x1e282d99, 0x80b6628a, 0x74ad2e7e, 0xa7bfc52b, 0x74c7ba44, 0xc67ae78d, - 0x2b3d728e, 0x9b4c74df, 0xa35e3018, 0x7894f76c, 0x7f6bde70, 0x345d7d27, - 0xf023b991, 0x14f597bd, 0x2031b0e7, 0x7a2f80ff, 0xf283c139, 0xdca8f7e0, - 0x178bc81a, 0x87fee64d, 0x7ef1d21d, 0xa454d289, 0x6af31f87, 0x4c794fa0, - 0xc00c6647, 0x2b89df23, 0x4e4f98ed, 0x2be01c02, 0xf2cf9702, 0x23991d45, - 0xd0495cf1, 0xa4bcf0ab, 0x77b786bc, 0x54bc78aa, 0xf7dfc69e, 0x7b57dc0f, - 0xde821653, 0x9cbdb6f5, 0x5be02772, 0x9c35be0d, 0x7c4cbe0f, 0xb99eda0e, - 0x46efe608, 0x5cf74d9f, 0x5ed08be5, 0xdc151b75, 0xf78c71c9, 0xb5cd9ee9, - 0x5baae508, 0xbc15e0af, 0x5c64105d, 0xe5c15f79, 0x8c8547f7, 0xb4859237, - 0x0a4ff487, 0x3dca35c1, 0x58ff3c9c, 0xb517fefe, 0x7bc22cf7, 0xcf3af9b7, - 0x57f44ac9, 0xd218692f, 0xf0e07f55, 0x697fa459, 0xb33bf70b, 0x39ee1c0e, - 0xd872f288, 0xb1e6f748, 0xe3e254e6, 0xdbbd96c6, 0x375ca126, 0xada073f2, - 0xff3fef0d, 0xc3a7ea3b, 0x57183163, 0xe69eb759, 0xebca2f9d, 0x1e39eb66, - 0xdfb3b725, 0xb2847c72, 0x3c71dfaf, 0x6b7fb796, 0xa75a17fe, 0xfb81f0ff, - 0x9fa05e50, 0x17a5e29b, 0xa2605e40, 0x73d94392, 0x1bf59e30, 0xfce0563b, - 0xab3afdce, 0x09e7c25b, 0x95be30b3, 0xa4dcfccc, 0x14f6fc78, 0x4754a7cc, - 0x1df9edf7, 0xd7efbb9e, 0x2ba139d3, 0x12a5db86, 0x3dda7ab1, 0xf7bb3f24, - 0xb5f701fc, 0xf6e74f4f, 0x1edcd1c5, 0xa0c9ef15, 0xfe579ef3, 0x940ad9f1, - 0xd7717c83, 0xd7fe7c1e, 0xe90abd5a, 0x8db5a9d4, 0x4cfd01b8, 0xa9e286a7, - 0x3e2f1962, 0x13d7cb1d, 0xf24055d5, 0x653db713, 0x4948c811, 0xe0b7fdec, - 0xdb8be7ba, 0xce7f479f, 0x0ce8eaf6, 0xa03efceb, 0xbe77bc2b, 0x2da7434e, - 0x35467dfe, 0xb0b76bca, 0x38b3c57d, 0xd7ef1d7e, 0xf44edfad, 0x3165d776, - 0x31fa0f9c, 0x16ea9f3c, 0x3f3d0476, 0x1737b75f, 0xfb0bade3, 0xa5dc53e7, - 0x97a293e8, 0x20bab525, 0x293fc7fd, 0xf963f31e, 0x8666e4cf, 0xc2e9fc80, - 0xcffc6791, 0x85f5e806, 0x0b4f8d06, 0xb1d62a34, 0xa7af784d, 0xf24963e8, - 0xbfb8854d, 0xe6755512, 0x278bc03a, 0xbd40ad77, 0x1167af3c, 0x2defd089, - 0x2e0f3f15, 0x885aaa69, 0xf5b87b76, 0x7c799b14, 0x9f913979, 0xd66e5f97, - 0xa9cf027b, 0x9547e143, 0x3d5b7a4c, 0x42baff88, 0x19473e47, 0xb7ad2def, - 0x670ee30c, 0x9fc3f70c, 0x3306ff40, 0xee6661c4, 0x086e56a7, 0x1cdcbfee, - 0xda9dcf43, 0xcbb44cae, 0xcccbf8ca, 0xd4cf6e26, 0x9fe8995d, 0x7923df43, - 0x82f57b47, 0xa4aaf640, 0xf7433849, 0xf8d248c7, 0x44967a41, 0xee623db8, - 0x9c487cd0, 0xc601f326, 0x77ac87fa, 0x9b7a0d25, 0x8d29c61e, 0x7f468aec, - 0x8aec6655, 0xff6f73c6, 0xc8d59151, 0xc6538bec, 0x4f9c1b4f, 0xbd8b8fc9, - 0xa87e9b1a, 0x183b60f9, 0x7fc5adef, 0x32622903, 0x3514deb8, 0xcc7cd147, - 0xe50d35d4, 0xf05768b6, 0x534fb87b, 0x9bfa3e80, 0xc607c777, 0x75c7bfa1, - 0x8677de53, 0x1ff7a6f4, 0x1ca0a69f, 0x26d8a894, 0x20bee73c, 0xc0617bf0, - 0x82f85ee9, 0xf25e5e7c, 0xca244337, 0x65cb85cf, 0x01fec7a4, 0xd928fb3b, - 0x6762bf07, 0x15c70d59, 0x7076cb3b, 0xeecec07c, 0x3762b8e2, 0x42a3fe95, - 0x1d0a4fde, 0x9077a94f, 0xe6ed93c7, 0x6e7abaa2, 0x7f7e4537, 0x4c6b76c7, - 0xfce27f3c, 0x19d32b5a, 0x95d3b412, 0x123577e4, 0x19c5b1fa, 0x76a579ca, - 0xa0e27e90, 0x7499fa3e, 0xbbf509a0, 0x10f940c8, 0x070d15c4, 0x59791cf1, - 0x07ef15bc, 0x9caee943, 0x7cc5c777, 0x7cf906b3, 0x8af1d6ab, 0x7269ef19, - 0x82afc8ba, 0x74bf90b6, 0xb8a3aabe, 0xb7d357aa, 0x965fed07, 0xf61af1d6, - 0x6c76d32b, 0xea4b029e, 0xe3b574d1, 0x943cd091, 0x5c43b257, 0xbb39fd5e, - 0x39527ce9, 0xe6577f2f, 0x5ea70323, 0x7025f28d, 0x7cde3939, 0x57b46de8, - 0xf2748efe, 0x03e45703, 0xa3478fcd, 0xe210f9dd, 0x5c407714, 0xbdaae1fc, - 0x14b50f74, 0xde011fef, 0x7f7829b9, 0xa62edffd, 0x0b6d8838, 0xbcf28e78, - 0xa50f1833, 0x2fb5ca0b, 0x24dc8f48, 0x9ba5dfc7, 0xeace9608, 0x061d2270, - 0x8b8045f0, 0x21ebf801, 0x667f4878, 0x1e6266f7, 0x08d61dfa, 0xc6ca3d01, - 0xbc534efa, 0xd0c3407a, 0xbf046c3f, 0x28e1f849, 0x1d532baa, 0xc718bf00, - 0x9bfa22fd, 0xca0ee8d2, 0x7587fceb, 0x60f0df74, 0xb82997cb, 0x8ba6bf7f, - 0x96d295f2, 0x9e31e397, 0x344b358d, 0x78dff83e, 0xdc3d8fba, 0xb6318f12, - 0xe54cbcf2, 0x94eb94cd, 0x28fed172, 0x5f45cbcf, 0x54bfae26, 0xf6c5c8e8, - 0xd453b458, 0x7111701f, 0x1328fb46, 0x2d60ddb8, 0x5089f922, 0x706745be, - 0x25f60bbb, 0x8f11ee97, 0xb15978f2, 0x605f6427, 0x79f1d7bc, 0x261fb70e, - 0x5e14fce5, 0x31bb462d, 0xa4d99d84, 0x41564dd8, 0x06644d79, 0x3ef2b75f, - 0x30f3cb8d, 0xd2be776a, 0x83969b9d, 0x7bf249ef, 0x7d2cf601, 0x1da13ed0, - 0xf23b2449, 0xf61e26a0, 0x60bcf255, 0x14af08dd, 0x802aaf2f, 0xfaad6cee, - 0x2fca029e, 0x19ee9b99, 0x8575d742, 0x7f39997e, 0xd2f3e44b, 0xbcfc3d92, - 0x9f8682f4, 0xf2bd832f, 0x3b5afda1, 0xf500aaa7, 0x72b8eeef, 0xdcb9e06d, - 0xb35fc6d5, 0x5b5f1833, 0x30905551, 0x6c979e84, 0x8a3ed1d8, 0x1d17e10d, - 0xd2f105d5, 0x7595cf95, 0xeb2bd05f, 0x1519a59c, 0x55a58f48, 0xae00a305, - 0xf4b9f88d, 0xd0befbe0, 0xdfa1f3a2, 0xf9d2fa06, 0x575f8de9, 0x5c3f9d04, - 0xe662bc6d, 0xe1c2f3a1, 0xcb0a1fd6, 0xcc69df04, 0x57e818a3, 0xe819e91d, - 0x2f7cc04d, 0xb4fbfeca, 0x9e78a04a, 0x871aad15, 0xac7301f9, 0x6b7e871a, - 0x0c0178b8, 0xdd1568e5, 0x8209ba49, 0x0eb0ae1e, 0xffa50f41, 0xbcfc191d, - 0xaf5945e1, 0x7d2fcf46, 0x9fb420e6, 0x19456c96, 0x5c28a8c0, 0x8945e623, - 0xda183c23, 0x7203be53, 0x036394ed, 0x5f7cab43, 0xbb522858, 0x586459ab, - 0x8d12caa7, 0x57d80c9e, 0xf54edb21, 0x7798f37b, 0xa9791506, 0x3d7f7ebb, - 0x4d7fcfb4, 0xd195bc9c, 0x37e50f7d, 0x330e9105, 0x5fb055c6, 0x4ef43f39, - 0x7e701859, 0x37f647b7, 0xfc814433, 0x14525f40, 0x5dced39d, 0x503cbe5a, - 0x10853b4e, 0x72fa79ba, 0xf5f1bf29, 0x6dd206e5, 0x15516bc9, 0xbcc80e74, - 0xcc049653, 0xaf0672f3, 0x696af89f, 0xb8979d06, 0xd27bf32e, 0x27dbf17c, - 0xd7588f31, 0x80af7906, 0x407ea7e3, 0x2f906675, 0x0dd09c62, 0xcc1ce9f9, - 0x66cc1df5, 0x61387b43, 0xae7be514, 0x7ac30203, 0xae8b6733, 0x9d9bef06, - 0x8c78ae9a, 0xbf34b673, 0xec3f45af, 0x569efc3a, 0x92abbcc2, 0x2637f5c9, - 0x05d7d215, 0x5bbf40ec, 0x01f59cde, 0x93f2b5da, 0x5cb0d4fc, 0x3fdd1efd, - 0xce14b9e2, 0x48d4da57, 0xcc658df7, 0xd65f7247, 0xf6ff9c10, 0x075d0e27, - 0xa76cb2f4, 0xd3ee7c14, 0x225fcf3c, 0xb72f0ab2, 0xce9f148b, 0x73a04c4d, - 0x38f7c1d8, 0xf7626d7d, 0xdb6e7843, 0x0558269b, 0xd237aa18, 0x26e309bd, - 0xc73f2677, 0x85f57ded, 0x7ce86b29, 0xeb0533c4, 0x73e57ba4, 0xec8fb9fc, - 0xeb018b50, 0xebcadb99, 0x59237a17, 0xbbe211d1, 0x23f20c63, 0x92ded52b, - 0xb6967181, 0xf1eb9def, 0xaf8e59de, 0x57b1f743, 0x253e6fbe, 0xbacae9c7, - 0xf32727e7, 0x21e618f3, 0xf3976a39, 0xda0a9b62, 0x4cd3ee03, 0x77528299, - 0x046befc7, 0x9c3e8f7e, 0x17bd617e, 0xbd623bd6, 0x72fdc217, 0x7bd6245d, - 0x5ca2fe21, 0x5ef58917, 0xbdeb1cf8, 0xeb926f10, 0x0bdeb122, 0x42f7ac71, - 0x8bae5478, 0xa54b853c, 0xbfd2eef8, 0x3edb9e61, 0xfc721f10, 0x3e084c74, - 0xe9ffb83a, 0x1f182118, 0x33ff502d, 0xcdfe9775, 0x1675839d, 0xf0dfd926, - 0x9ce50b3a, 0xb670b3ab, 0xb1f20779, 0x3c24c275, 0x69266747, 0xb74bea04, - 0x56ffe7cc, 0x1da02fdb, 0xe47d1160, 0x64c4e797, 0x78bb408f, 0xba62e4f2, - 0xd38feb87, 0x93bc3e91, 0x7ec3e8ee, 0x9e6f98ae, 0xeb06cc3f, 0x265a66e6, - 0xfc029a6f, 0xe4106998, 0x44fb7238, 0x059f72bb, 0xbadd99fc, 0xdb9a8a6a, - 0x994e130b, 0xc6ad962f, 0xe925d771, 0xaa1e6327, 0x1dfc734b, 0x5fe855c7, - 0x19ad7a30, 0x48d76fe7, 0xeabc601f, 0xf3cf13fe, 0xa501fa95, 0x33a927df, - 0xdef099f5, 0x26fa4b5c, 0x2819ebcc, 0x4dbc8a1f, 0x3e501acb, 0x6128aa6c, - 0x4933d923, 0x67d5fb8d, 0x92cefdf2, 0x4f80fdf8, 0x6063a92b, 0xcce45f7c, - 0xdb77cc38, 0x949fbe65, 0xe64a7ef9, 0xcdd1d63b, 0x3a3af351, 0x87475884, - 0x20ea10f0, 0xdd2fbfcc, 0x7149931e, 0xd20a5f72, 0x984ba95d, 0xedc67a87, - 0xf5d20a4f, 0x27c72c90, 0x99d3fb64, 0xefe24f66, 0x54acf8f1, 0x96e81fae, - 0x7d9473cf, 0xbe0def2a, 0xfb05e7cf, 0x6ffee12d, 0x5f645510, 0x5b38e543, - 0x788efb96, 0xbd4abde3, 0x3739c608, 0x261fdc88, 0x41dffaab, 0x6f1c93bb, - 0x90c23694, 0x78a3b3f9, 0x09bd36bf, 0xdb6f6c4d, 0xddce7437, 0x296190fb, - 0x30314fbf, 0x3da11efc, 0xe04d4271, 0xe51fe979, 0x908fc079, 0x9a2cba5e, - 0x3923f61f, 0x423f01c6, 0x144e66f9, 0x9bf923dd, 0xa4fca2bf, 0x09aa75b7, - 0xe1dfd4e5, 0x715fa031, 0xc4ffe3fd, 0xb7f0bfa3, 0x6cf5417e, 0xa4bf6ffe, - 0x722db73a, 0xcdebe1bd, 0x87589d72, 0xbde7c464, 0x60159f85, 0x1c32adbf, - 0x3cfc23b4, 0x686f814f, 0x681de66c, 0x51509ecf, 0x8dd8a2fe, 0x98597d50, - 0xf78e5239, 0x676831ec, 0xc4ec5f40, 0x597d01b7, 0xc1798316, 0x12917da0, - 0x132ea87e, 0xcd598bed, 0xb4420bed, 0xb733662f, 0x7da3882f, 0x05f68841, - 0x417da39f, 0xe20bed1c, 0x47105f68, 0xed1082fb, 0xebff3e0b, 0xd3a75e52, - 0x3f29810b, 0x5c5035c7, 0x7f8ebebf, 0x8dbeb27f, 0xafaddbdf, 0xac0ea816, - 0x94dfe607, 0x509d4439, 0xe4275c93, 0xa2f741dd, 0x15a2c3ae, 0xd6017859, - 0x6dcf09bd, 0xd0277d35, 0x051ab82f, 0xcf84956b, 0xb63ad297, 0x60fd4eb4, - 0xd3af3e39, 0x2fe85558, 0xa3c72f5a, 0xad692bdf, 0x2735ff23, 0xbfcb4da1, - 0x9e181197, 0x71d12f1f, 0xe11728fd, 0x3fba24e9, 0xae5ffb26, 0xad73a0eb, - 0x0a417ad2, 0x35c08efc, 0x7fc512fd, 0xf2b9fdca, 0x57b94bdd, 0xca0ead2f, - 0x6ebc6c9f, 0x4aff718b, 0x9e406579, 0xc3277cab, 0x74d56fc4, 0xc08afe3f, - 0xd7ab8562, 0x36b49573, 0xaffac66e, 0xb4767bd0, 0x16d75424, 0x44febf72, - 0x95d75ca6, 0x6f30f2c7, 0xf5627c2e, 0x5f30c381, 0xe51d76ff, 0x774f609d, - 0x409efea1, 0x9cba0439, 0xb9d3d368, 0xb23be7db, 0xde1f1046, 0xf6489914, - 0xb7d90c72, 0xf2811a75, 0x3597b031, 0xc2ecdef8, 0xceaec8bb, 0xfc8abb06, - 0x93eee454, 0xca2d7b54, 0x1209bae7, 0x1d7cb9f9, 0x93c697bb, 0x9200c5eb, - 0x146fe5de, 0x57c02a3c, 0x2f7d2b31, 0x86c812b4, 0xc6af50f1, 0x75d608f0, - 0xaebc64ad, 0x75a39143, 0x8eef943b, 0x577d10c6, 0xd95cf4c8, 0xb06fc7fa, - 0x1d2ee36e, 0x56490f3f, 0xe4803af1, 0xe7bebcad, 0xf5e0e66e, 0x8b4d9872, - 0xdabd2f94, 0x511dcf05, 0x79f85263, 0xe380948f, 0xa1a53aaf, 0x84fce33a, - 0x8a0e9905, 0xfd50e64f, 0x43bbe086, 0x1f9afefc, 0xeb83878a, 0xec684e37, - 0x3b573df4, 0x73d925ca, 0x9553c107, 0xbb150445, 0xf63fd4ad, 0x88dcbdb6, - 0x0cbbe7f3, 0x62b7a456, 0x83a8ae07, 0xa950e48c, 0x100b1c83, 0xc0cc0aeb, - 0xda0c5363, 0x44ec8967, 0xb273aab2, 0x1bfffb84, 0x3f200eff, 0xe30f2da1, - 0xfc7974a6, 0x43fd92d3, 0x9a2d9fe4, 0xbc3df1b9, 0xf40eda4f, 0x080dc02c, - 0x6d7b2f18, 0x6dbfc622, 0x1a46a982, 0x78ee8eca, 0x5c97eb08, 0x7184c166, - 0xf6e44159, 0xbf1878fc, 0x8ad52d20, 0xccd5dc76, 0x403f2de3, 0x3debf7ce, - 0x55dfc0a2, 0xce9c63c7, 0xea9596f9, 0x351ccee8, 0xacbe7cf8, 0x5fadbd4f, - 0xabe3faf1, 0x38b563c7, 0xade99bbe, 0xc8f8f275, 0x8cd7f9f7, 0x914cb8a5, - 0x8486fe9b, 0xef9b941a, 0x7cbbff65, 0xcc1a7bf9, 0x1cd33b03, 0xaff38dff, - 0xa1e97d58, 0xd0e7da78, 0xd3a9507e, 0x4a83f50f, 0xabfff37c, 0xcaedff3e, - 0x54ef820a, 0x51d8206e, 0x51f6a6e9, 0x735cfc59, 0xfc0ab8b8, 0x10d65c43, - 0xbf4294f1, 0xe4aae221, 0xae3ca9ac, 0x89473cc2, 0xa388aeab, 0x0155df40, - 0x75bb3efa, 0x608f9de4, 0x6b53b3dc, 0xeb0090c5, 0xc81bd7a8, 0x4d64643e, - 0x529e2a1d, 0xf8a069e8, 0x27e99fab, 0x2cb3fce1, 0x1fbc6ae9, 0x0425989f, - 0x3fa80be5, 0x1fd46fb8, 0xea3fa884, 0x39e7b880, 0x14f6a82d, 0x29b82f1e, - 0xbf13d05e, 0x5d815737, 0x662efc01, 0x3d2bb20a, 0x31857621, 0x1d70affb, - 0x9d795a6b, 0x3a5f5297, 0x93d7c00b, 0x5e33b086, 0x46c6676e, 0x3ce1f77a, - 0x54919d63, 0xc3427caf, 0x16c4eee5, 0x9ab82f5e, 0x8ff7f9d9, 0x689bda57, - 0xb15defa4, 0x01fc9f7d, 0xa8f5dffa, 0xcd9ee281, 0xfda66b49, 0xf8cdec4f, - 0x7f0f4e2c, 0xe7de6fa5, 0x22731f20, 0x905cf7f9, 0xee2859bb, 0x7e924555, - 0x8ed97e40, 0x6bac57df, 0x8ed0f211, 0x77d9d1cf, 0x6a9d3ae1, 0x27167ebe, - 0x3baa27df, 0xbf42f78a, 0x2b64f8ce, 0x1263cfe6, 0xffac308f, 0xe61577ca, - 0x64ecbda0, 0xbf7be9db, 0x5dc73a8d, 0x39c5e7c8, 0x7b9d0215, 0x5897faca, - 0x95b35518, 0x153591f8, 0x2708bef9, 0xe6e473a3, 0x2e8f98c5, 0xf1c10a8a, - 0x8dce8b1e, 0x6c78e55f, 0xd2827b48, 0x1cc9e32e, 0x2f356777, 0xd2e573c6, - 0xf3e9bd7a, 0x91cffaa0, 0x39abb841, 0x6079f4c9, 0x03fe2a7d, 0x822daecf, - 0x93dc059a, 0x078e0837, 0x85e53f70, 0x2e39f917, 0x5abf23eb, 0x7d112595, - 0x7ccebd47, 0x737dff28, 0x902e748d, 0x87915b10, 0x472c09e7, 0x52fd8a9a, - 0x17147d34, 0x96ab7ef6, 0x8be8b3bf, 0xef202dbe, 0x7f95be7f, 0xcfca117f, - 0x7b970b3c, 0x0db0d997, 0x8c4ce6f9, 0x7ad82088, 0xa616e289, 0xdef19bb6, - 0x3a0af214, 0x3f7d08b7, 0xb7efc2dd, 0x656b3753, 0x90ff813a, 0x8e337ae4, - 0xc674d9bb, 0x948befaa, 0x266ccae9, 0x866d3ff8, 0xfcffc64a, 0x0113e638, - 0x7fd86dfd, 0x6b5f9db0, 0xf77bef2b, 0x26f8fbbe, 0xca1f3cb3, 0xf1461ad7, - 0xa0f7e873, 0x06625a9f, 0x2e5033ea, 0x53d38b9e, 0xf7583f9e, 0x6ba0ebcf, - 0x7f3d72f5, 0xf83fbd68, 0x8ae7f43b, 0x725f7b9f, 0x52bf1d50, 0xf9d4aff7, - 0xcd2f3127, 0xe027b4a7, 0xda88baed, 0x3847a1db, 0x2193f303, 0x659376e8, - 0x91647fe6, 0x17d9b8de, 0xfee7c1ea, 0x810de8a8, 0xe486727c, 0x66593737, - 0xfbca7bd1, 0xb1661be5, 0x26e3262f, 0xaccc38e5, 0x14e7ff22, 0xd9021bd9, - 0xa28f5e11, 0xec1a77bc, 0x9ff7ce3c, 0x7e11f760, 0x0bfef608, 0xc19fe7a0, - 0x08fc21de, 0xff3e1dec, 0xc21dec04, 0xf803f02e, 0x03f053fc, 0x61dc9708, - 0xe57a829c, 0x5f62ae6a, 0x3b3dd704, 0xd3bfe302, 0x97968733, 0x9e2a598b, - 0xdd0ea5bf, 0xe9e596ae, 0x6f9c8df4, 0x4f3377bd, 0xdfc92a4d, 0x86178c26, - 0xd7b7eefb, 0x5afbedc8, 0x37bc1cf9, 0xb2e7e389, 0x473cfc34, 0xf7c69ec5, - 0x3af066d7, 0x2b8ec539, 0x1fc82af9, 0x63acaf8d, 0x29d79c9c, 0x55663cfd, - 0x0a48f7d0, 0xfde1639c, 0x5f313e48, 0x0d4c7947, 0x44a74f90, 0x172a19f2, - 0x1d385a9f, 0x772e3acc, 0xa09768c9, 0x9e82727f, 0xe361c6e2, 0x51ef90b0, - 0x394f90ae, 0x32c64b1e, 0xf3e1988f, 0xf7aca363, 0x7e3f3a3f, 0x943150d8, - 0x3ff998fd, 0x3e80ffdd, 0x8affef06, 0x8e876b7d, 0xf7db873f, 0xca2bbd40, - 0xc1f610cf, 0xb81f603a, 0xb164dcfc, 0x1d4cb78d, 0x05483bfe, 0xebe0cdae, - 0x6a83e456, 0xc5ee3094, 0xee0fa57d, 0x91fd6067, 0xcb5bfb21, 0x94225ee8, - 0x13df018f, 0x05fafb29, 0x1ba147ae, 0xa38a3e58, 0xa81994c7, 0xc590fbce, - 0x4769efc4, 0x0762b97d, 0xf645feb4, 0xf1507f13, 0x6ec51a7a, 0xc4173c0f, - 0x82730b95, 0x513339ec, 0xfd23ad9c, 0x7bbc41f2, 0x4f7830d0, 0xb7f7eca9, - 0xcbf63eb2, 0x6fffb5f9, 0x8ff65f3c, 0x73dfa3ee, 0xefcd3ff0, 0x9bc460d1, - 0x6eee0eb1, 0xcc253bf9, 0x9e5ad5af, 0xcf21ab37, 0x7d2f7bf6, 0xae01f782, - 0xaa3c4467, 0x9733e262, 0xd3fc5097, 0x7e6131a6, 0xc7e9f1be, 0x9dbca24f, - 0x7424126d, 0xd826fed9, 0x3ba7e636, 0xf43d1e8d, 0xe7e2682f, 0x45eb6b27, - 0xfcff048f, 0x696efe42, 0xfa1a33f6, 0x234d699e, 0xfe3977af, 0x6bca7af4, - 0xcf207acf, 0xc40b7186, 0xbcf1da07, 0xfe39e4be, 0xfb2512bb, 0x1efc5adc, - 0xa05aa4af, 0x97c9537c, 0xaf75e4cb, 0x6c7909d9, 0x30483dd0, 0x14bccc5e, - 0x06d4955f, 0x086b2f3f, 0xb5ef7fce, 0x94d77c0c, 0xf9c8ebc7, 0x3f62acbd, - 0xdcab8caf, 0xfac1a7c4, 0xe3c6bfeb, 0x76d8be79, 0x0353e539, 0xf8ca17c7, - 0xca2fc019, 0xfacaf6e7, 0x62e8fc95, 0x85e29b12, 0x2e313afd, 0x50efe495, - 0xc8aedf81, 0x1f485bae, 0x8c268a8f, 0x8b34b6b3, 0x7967a46e, 0x7d377eab, - 0xf4e78537, 0x3df3a446, 0xc26ff7e4, 0x273c267b, 0x83b67c84, 0xce83a6e4, - 0x6fad99e5, 0xb697dd0d, 0x4fe84de8, 0x683f479d, 0xfd06efc7, 0x57860587, - 0x7cefcaf8, 0xd78679ac, 0xcddfc199, 0x229afdf8, 0x5f006217, 0x436bef91, - 0xc33e2af8, 0x8d35f3f3, 0xdedf2823, 0xf568b4f8, 0x39785ca1, 0x17be157f, - 0x3ce8db88, 0x7c48f805, 0xdd4cfd9e, 0x07289193, 0x05fdf8fb, 0xfdf101c8, - 0x77ce2eec, 0xc443db6d, 0x2cb57f77, 0xf7fc2d07, 0xf8ea4a49, 0x17e81079, - 0xf1abc9f9, 0x5f7c6aff, 0x7c83db20, 0x3889c671, 0xe5ef778c, 0xe988adf3, - 0x9a07bf2e, 0x20bb993e, 0x7975f515, 0x26c6eee1, 0x07891980, 0xce621999, - 0x51db3a53, 0x5cb9e04b, 0x79d79e9b, 0xca045103, 0x4bfae433, 0x53dd4ce9, - 0x5e47af68, 0xfe31f143, 0xf79c0445, 0x60cf3f00, 0xb23bd09e, 0xd8cbc0fb, - 0x7e8e946f, 0x55bca58f, 0xa2e5d3e7, 0x9bf2e45f, 0x715bedaf, 0xafddc60f, - 0x433ee8ea, 0x45dff1b0, 0xe3fd6d28, 0xc84f7887, 0x416df29a, 0xff209bbf, - 0xfe2941ae, 0x37b602ae, 0xe8067a68, 0x3fa6ed80, 0x165d7bd1, 0x9e92875e, - 0x71848370, 0xcc65c6ec, 0x943e9911, 0xe764679d, 0x8729ef95, 0x3986c38d, - 0x2fe2506f, 0x12331ee6, 0x7df94cf5, 0xad0ec505, 0x3c5bbf95, 0x7529df71, - 0x96afd22c, 0x714c8eff, 0x389fd82b, 0x7922df3a, 0x38aee73b, 0xbf9782a2, - 0x468ab944, 0x0e68fab9, 0xc7db2ff6, 0x3c0683fb, 0xdf871919, 0x4f286b29, - 0x7937d01b, 0xa3df867c, 0x05f3bb40, 0x0ea6c581, 0xab6a2f61, 0x421e8f37, - 0x2e214a6e, 0xca8745c3, 0xb829b38f, 0x768377df, 0xf8f7c264, 0x9726567d, - 0x662cf72f, 0x0d5ffdc1, 0x40d8f92a, 0x947e067e, 0x19e660ea, 0xc972df29, - 0xd5ced2e7, 0x51273a26, 0xed538dfc, 0xf299b33d, 0x43972332, 0x63dfa335, - 0xb68d54e9, 0xef380d6e, 0x4e979ce8, 0x6fc59fdf, 0xdc70faf4, 0xb58205be, - 0x44e69a06, 0x5f2efcf1, 0x0bdb2f65, 0xb8a86fed, 0xf30e7ddf, 0x17fd1137, - 0xff419397, 0x93cfcfc6, 0x7f3c8d0b, 0x9adca8f3, 0xa61df489, 0xdd94eb1b, - 0x2bd52d76, 0x1d291ced, 0x677c0268, 0xefd90e71, 0x73f1df23, 0x5a65bef4, - 0xf33bf3f2, 0xae51cbec, 0x4f1b2e77, 0xd208afed, 0xe33f7863, 0x7da48e2e, - 0xcfc85cec, 0x4c2e771b, 0x5967f6a4, 0xdf1a955f, 0xd9fbe6ab, 0x3a04d8f9, - 0x39d38dff, 0xbef1b372, 0xd8c7be58, 0xc24b6a99, 0x0527d37a, 0x71bbb2fb, - 0x1a0609bc, 0xe24590ef, 0xc6cb12f7, 0xe907b63f, 0x8a9a4634, 0x7e0fdb76, - 0x7ff00def, 0x4dd86c7f, 0xf71732f5, 0xc705b99f, 0xe4057d2f, 0x37f7c60f, - 0xebbe8318, 0x66efbe57, 0xc5b4df6a, 0xb0bf40c6, 0xbcb5d791, 0xeaf6e464, - 0x3373cea0, 0xe4725fbc, 0xebb45cb3, 0xdafb07fe, 0xdaee3193, 0x243af02f, - 0xde2e5777, 0x87a89647, 0xce6faf8e, 0x4f4bf1e6, 0x8c52d44b, 0x63fa84e7, - 0xe252df54, 0xe7435dbd, 0xd9bf7254, 0x866e3cd9, 0xed1f747e, 0xdfc827de, - 0x05a6f8bb, 0x752b5bde, 0xb8fb3dcd, 0x6b34951c, 0x92e47be8, 0x51ff46fa, - 0x59d43fc4, 0xf55d7c51, 0x783ee897, 0xe8074bf6, 0x3fef02de, 0x473a08de, - 0x3b39dfe6, 0xaae63b65, 0x395ec917, 0x77f9ca9b, 0x19e2f55f, 0xd28fbdc2, - 0xf15d34ef, 0x27731d5d, 0x5f4912ab, 0x29e6b193, 0xa5f4bdb4, 0x206e23b6, - 0xbda1e961, 0x2ee7e8d1, 0x2345d474, 0x55dc61dd, 0x5e7c11da, 0x2b883dfc, - 0x7d05b5c7, 0x6ef2e69f, 0x02ebc4b9, 0x845fc8bb, 0xff80bff6, 0x6f7f3f00, - 0xd91dfcb6, 0xf25aecb5, 0x14b1f5ff, 0xa6fac157, 0x13b77e05, 0x0f4bffea, - 0x0dde7e5c, 0xbb073ded, 0x96f5c79f, 0xd515f77d, 0xf557b123, 0xdae6b754, - 0x73f93eff, 0xcd7fbde5, 0x7fa871e6, 0x583ddedf, 0x2fffea97, 0xf347159d, - 0x22997db7, 0xe36839e1, 0xf10f7437, 0xfa7cb69b, 0x8737e6de, 0xd0fc2767, - 0xb7281177, 0x75c0cc9e, 0x92bf8879, 0xac503bfc, 0xfc218655, 0x3c74de3a, - 0x1179d705, 0xba754df8, 0x72f73f12, 0xbee9cb7a, 0x8007f101, 0x8786cebe, - 0xb8ffa12f, 0x4d9cff1a, 0x61bd6f8b, 0x2b43d90a, 0xf58b95aa, 0xe87ffdd1, - 0xfb7c037b, 0xc4e3e04f, 0x86bfc11f, 0x70ff342d, 0xff88bbfc, 0x081d3e00, - 0xa6e5dfe1, 0xeb1dffbb, 0x6c535968, 0x8128f7d0, 0x08fdf374, 0x7c0915ba, - 0xdb66dffc, 0xf4bed19a, 0x0f617c1c, 0xdf2309d6, 0x2eb0966e, 0x330a72ed, - 0x7d30f7e2, 0x697f282b, 0xaed099d3, 0x407db495, 0xeb97e3fa, 0x80cfe029, - 0x06cfce7e, 0x2fc83afe, 0x55d9b6c9, 0xa2e9f46b, 0xf4efe907, 0xa2942c2c, - 0x7a19f9e9, 0x8c72e1ee, 0x2ddfc3f4, 0xdd8e7a73, 0x97c10c26, 0x9e34ecde, - 0xd1467927, 0xff6bcbbe, 0x00c0e3c2, 0x91d3097e, 0x6e28674f, 0x0a4f8e1c, - 0xeff24c1d, 0xadf00d88, 0x685feb96, 0x87f0177f, 0x7e653fee, 0xf7f0ff21, - 0xceb85cd4, 0x20cf8e68, 0x0d80f85c, 0xd5fc0f61, 0xfce3ca3a, 0x83c9f721, - 0xd79079fc, 0xa9ea855d, 0xf4e1cfbc, 0xabd3d143, 0xd2a7ffad, 0x52d92fe7, - 0x7428bc90, 0x6876f9ea, 0xcf1c6e3b, 0x9f67fef5, 0x3504da3f, 0x7f3a0f8b, - 0xf3c78c34, 0x4133a6c7, 0x7eca8fe7, 0xda73e47b, 0xf922fd9e, 0xeff2cdc7, - 0x0bda84ac, 0xd0983be5, 0xd7938ef5, 0x7f7f94eb, 0xd1a0e7a1, 0x7a718063, - 0x79216f5e, 0xd19c3676, 0x7b6a79e2, 0x9efa21fd, 0xf41fd14e, 0xf5809e13, - 0x2c78bcf7, 0xce36ec97, 0x275f0433, 0x33cf978c, 0xc79e875b, 0x682970d5, - 0x57b7529e, 0x57ab754b, 0xda82ef99, 0x778e3b76, 0x7eff83a1, 0xd0ef05e1, - 0xf1a6a9e7, 0x615cf91a, 0x2fe0873b, 0xbcfe01ed, 0x1b4db053, 0xc30c2a3f, - 0x30c30c30, 0x0c30c30c, 0xc30c30c3, 0x30c30c30, 0x0c30c30c, 0xc30c30c3, - 0x30c30c30, 0x0c30c30c, 0xc30c30c3, 0x30c30c30, 0x0c30c30c, 0xc30c30c3, - 0x30c30c30, 0x0c30c30c, 0xc30c30c3, 0x30c30c30, 0xc1b7ff0c, 0x8dca0bff, - 0x8000e737, 0x00008000, 0x00088b1f, 0x00000000, 0xc5edff00, 0x20000131, - 0x22b0030c, 0xb0131302, 0x14e7ff1b, 0x93c9084d, 0x26ebaf39, 0x6db6db63, - 0xdb6db6db, 0xb6db6db6, 0x6db6db6d, 0xdb6db6db, 0xb6db6db6, 0x6db6db6d, - 0xdb6db6db, 0xb6db6db6, 0x6db6db6d, 0xdb6db6db, 0xf6db6db6, 0x10192fc7, - 0x8000dcb1, 0x00008000, 0x00088b1f, 0x00000000, 0xc5edff00, 0x20000131, - 0x22b0030c, 0xb0131302, 0x14e7ff1b, 0x93c9084d, 0x26ebaf39, 0x6db6db63, - 0xdb6db6db, 0xb6db6db6, 0x6db6db6d, 0xdb6db6db, 0xb6db6db6, 0x6db6db6d, - 0xdb6db6db, 0xb6db6db6, 0x6db6db6d, 0xdb6db6db, 0xf6db6db6, 0x10192fc7, - 0x8000dcb1, 0x00008000, 0x00088b1f, 0x00000000, 0xc5edff00, 0x20000131, - 0x22b0030c, 0xb0131302, 0x14e7ff1b, 0x93c9084d, 0x26ebaf39, 0x6db6db63, - 0xdb6db6db, 0xb6db6db6, 0x6db6db6d, 0xdb6db6db, 0xb6db6db6, 0x6db6db6d, - 0xdb6db6db, 0xb6db6db6, 0x6db6db6d, 0xdb6db6db, 0xf6db6db6, 0x10192fc7, - 0x8000dcb1, 0x00008000, 0x00088b1f, 0x00000000, 0xc5edff00, 0x20000131, - 0x22b0030c, 0xb0131302, 0x14e7ff1b, 0x93c9084d, 0x26ebaf39, 0x6db6db63, - 0xdb6db6db, 0xb6db6db6, 0x6db6db6d, 0xdb6db6db, 0xb6db6db6, 0x6db6db6d, - 0xdb6db6db, 0xb6db6db6, 0x6db6db6d, 0xdb6db6db, 0xf6db6db6, 0x10192fc7, - 0x8000dcb1, 0x00008000, 0x00088b1f, 0x00000000, 0xc5edff00, 0x20000131, - 0x22b0030c, 0xb0131302, 0x14e7ff1b, 0x93c9084d, 0x26ebaf39, 0x6db6db63, - 0xdb6db6db, 0xb6db6db6, 0x6db6db6d, 0xdb6db6db, 0xb6db6db6, 0x6db6db6d, - 0xdb6db6db, 0xb6db6db6, 0x6db6db6d, 0xdb6db6db, 0xf6db6db6, 0x10192fc7, - 0x8000dcb1, 0x00008000, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0x40000000, 0x40000000, 0x00000000, 0x00007ff8, 0x00000000, 0x00001500, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0x00100000, 0x00000000, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0x00100000, 0x00000000, 0xfffffff3, 0x314fffff, - 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, 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, 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, - 0x000a0000, 0x000700a0, 0x00028110, 0x000b8138, 0x000201f0, 0x00010210, - 0x000f0220, 0x00010310, 0x00080000, 0x00080080, 0x00028100, 0x000b8128, - 0x000201e0, 0x00010200, 0x00070210, 0x00020280, 0x000f0000, 0x000800f0, - 0x00028170, 0x000b8198, 0x00020250, 0x00010270, 0x000b8280, 0x00080338, - 0x00100000, 0x00080100, 0x00028180, 0x000b81a8, 0x00020260, 0x00018280, - 0x000e8298, 0x00080380, 0xcccccccc, 0xcccccccc, 0xcccccccc, 0xcccccccc, - 0x00002000, 0xcccccccc, 0xcccccccc, 0xcccccccc, 0xcccccccc, 0x00002000, - 0xcccccccc, 0xcccccccc, 0xcccccccc, 0xcccccccc, 0x00002000 + 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, 0x00003500, 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, 0x00000000, 0x00010001, 0x00000604, + 0xccccccc5, 0xffffffff, 0xffffffff, 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, 0x00100000, 0x00000000, 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, 0x31afffff, 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, 0x058fffff, 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, 0x000d0000, 0x000000d0, 0x000280d0, 0x000b80f8, 0x000201b0, + 0x000101d0, 0x000c81e0, 0x000002a8, 0xcccccccc, 0xcccccccc, 0xcccccccc, + 0xcccccccc, 0x00002000, 0xcccccccc, 0xcccccccc, 0xcccccccc, 0xcccccccc, + 0x00002000 +}; + +static const u32 tsem_int_table_data_e1[] = { + 0x00088b1f, 0x00000000, 0x51fbff00, 0x03f0c0cf, 0x19d9b38a, 0x22717618, + 0xa70143f8, 0xa4303332, 0x10267103, 0x97e204af, 0xaf0c0c8c, 0x2fd78918, + 0xcf608621, 0x38606610, 0x4206c402, 0x22450c0c, 0xa07af108, 0xfe407b9a, + 0xb698a842, 0x76c30328, 0x3bf781d1, 0x34957035, 0x24a458a6, 0x458d5d82, + 0xa0d7191e, 0x4494efc9, 0xd012d7e5, 0x4538d03f, 0x513f9509, 0x547f4201, + 0x342fa684, 0xf95049f9, 0xa57f5039, 0x77376129, 0x001e542e, 0x61aa8a92, + 0x00000360 +}; + +static const u32 tsem_pram_data_e1[] = { + 0x00088b1f, 0x00000000, 0x7dedff00, 0xd554780b, 0x733ef0b5, 0x49999cce, + 0x204e4cce, 0x30840909, 0x43511879, 0x7c061e1c, 0x201276f4, 0x06bf2ae5, + 0x0ea2a17c, 0x2de42108, 0xebf8fea5, 0x092132fd, 0xf636c544, 0xda2f45a2, + 0x05a855e1, 0xa180d03b, 0x4a00ee05, 0x7836daa1, 0xf5ab15bd, 0x62a2968e, + 0x96ad2248, 0xbfcb17fe, 0x24fbdad6, 0x00664e73, 0xbbf7bdcb, 0x9fa7efd7, + 0xece7d9dd, 0xebdaf7b3, 0x7b5ad7b5, 0x5d8a3ded, 0x19d7ea62, 0xa0ff873b, + 0xc631b3ec, 0x9f2c19ae, 0x23a57cc8, 0x6ad8cbd7, 0x3127d43b, 0x0f623c16, + 0x5b18926d, 0xb59fda32, 0x71ca0d30, 0xbc20be69, 0xebe16767, 0xc654c612, + 0x9b4aadff, 0xe8f2c994, 0xf073b9f9, 0xf30f81dc, 0x58564b19, 0x63026530, + 0xafcc6c2b, 0x8fba830f, 0xfc9c0fb1, 0x7ff8739b, 0xf61b24c1, 0xbf874233, + 0xaf3edfa1, 0x814f682d, 0xedcdb37e, 0x1215494e, 0xd5db1993, 0x140bd2c4, + 0x9c9abac6, 0x49b4fe54, 0x60282f4f, 0x26534f6c, 0x7935f7d5, 0x8d348ca9, + 0x9a07e7a5, 0xb34f547c, 0xf7e3d7f5, 0x2b7c8e23, 0xce0d1595, 0x68ae5adf, + 0x060b7182, 0x64cc7feb, 0xf9e00541, 0xafeec2a3, 0x5f9aef80, 0x8512989f, + 0x802c99f2, 0xf7e86536, 0x45fb2ecf, 0x8ce1b4fe, 0x387c3d65, 0x6844da7f, + 0xe139b127, 0x87459c22, 0xe25c6b34, 0x77b19f71, 0xcdc032a4, 0x6991802d, + 0xb9b58c99, 0x4f2e6ffa, 0x44f5cc65, 0x0b9a7fb6, 0x5d0cdde6, 0x2eec648c, + 0xde0c1056, 0xf81ffd00, 0xe80525b8, 0x614976a1, 0x4b26cd78, 0xd012cd15, + 0x7ccedd8b, 0xa538709b, 0xd41479a2, 0xde60eefb, 0xe383bdc7, 0x9880c5dc, + 0x46ccd8e9, 0x32a864e5, 0xa5dd87e8, 0xe2e53686, 0x15c5fd87, 0x2fb712e3, + 0xd517f839, 0xf6f1a6eb, 0x078d328f, 0x7f13b9df, 0xcbe07597, 0xaef7d77d, + 0x78842332, 0xe11f9853, 0xc657753b, 0xde25c7ba, 0x7d8f163e, 0xc70aab2a, + 0x8e1567a1, 0x66dcfc0b, 0x367b74e7, 0xb18d4a17, 0x16663835, 0x9c62b563, + 0x03d95a29, 0x3000b258, 0xb58cb5e7, 0xdda0bd20, 0x3abf6894, 0xdf4ae00f, + 0x852a4b33, 0x0af1fa7a, 0xf2115e69, 0x10cf41a1, 0xb1259ff5, 0x9ef81d8a, + 0x70ca92cd, 0xe71f3b1c, 0x8b50fe86, 0xe86ee007, 0xec9eddca, 0x6194fde5, + 0x48553fbb, 0x3858b5f3, 0x7a4fd4bd, 0xdf038c17, 0x38c0f7a7, 0xa56b3ef0, + 0xfe69bac4, 0xe1a614de, 0x32c67e78, 0x70a6a440, 0xa8d99099, 0x7867e424, + 0xfc8165ae, 0x3f2e3364, 0x8be635a7, 0x9f737e00, 0xd0d47cd4, 0x783579ab, + 0x69c85a3f, 0x266aa076, 0x01b630f3, 0x530593d0, 0x7ca8dd1e, 0xb3918d10, + 0xcda37331, 0x9663fa28, 0x997b9f99, 0x9cf286d7, 0xcf3f341b, 0xbfd7376f, + 0x2769dccd, 0xdc3f82ae, 0x8e4e7dcc, 0xc0e38f33, 0x12cf00d4, 0x6fc0ef21, + 0xadbf2c6a, 0x5a19626d, 0x91396241, 0x5dce1c96, 0xb7687a89, 0xf7c073e4, + 0x907b602f, 0x6ef890ef, 0x05d7a8bd, 0x0d5d8555, 0x1e282025, 0x958afc7f, + 0x1fba406e, 0x101b6567, 0xbf4a0dff, 0x0d7c03aa, 0xa43faa8d, 0x17bf6d0d, + 0xd7db1118, 0x4e03be2b, 0x99bfbf18, 0xf8c3d6f9, 0x197aec4b, 0xec3c97d6, + 0xd798bd25, 0x7e472d1e, 0xea05d31d, 0xfbf0772a, 0x2767808b, 0xecf001c2, + 0x97f4e3e4, 0xdfedfea3, 0xb9f5b12b, 0x77ef0e38, 0x165ceec9, 0xe70c4dcc, + 0xfc4ecc73, 0xbc0b40b4, 0x267ee582, 0x02c62729, 0x83cc3d9a, 0xcaa968f4, + 0x54394efb, 0xe9f7c69f, 0xf9ccf583, 0x00033233, 0x6618d657, 0xb3a557a2, + 0x7af50731, 0x1cb84575, 0x25c3e2f9, 0x12c0acaf, 0x00ae9cf0, 0x2a388fbe, + 0xea7ec75e, 0xa21636e6, 0xe870edc8, 0x7b1afe34, 0x7237d647, 0x1fa50f11, + 0xd06fc02b, 0x1865306d, 0xff4595f2, 0xc60fbfc3, 0x989cba8a, 0x172a17ee, + 0xe20a3f60, 0xf59fcb8d, 0x0f4207fd, 0xf8261e81, 0x957ecbbc, 0xb63c305f, + 0xc17e7afe, 0x09500144, 0x13f0cbc1, 0x4552a2c6, 0x663dbd1c, 0xa561e977, + 0xff3c3138, 0x7404f3d9, 0x001a7cd2, 0x7527c8b7, 0x1cb4356e, 0xa7753df0, + 0xe075f23d, 0x5275ba93, 0xdb7501c8, 0xefbd173e, 0x11ebcb5d, 0xe9f5cab7, + 0x0a83a846, 0x7f74706c, 0xb3e47afb, 0x8f5b329d, 0xf5858edd, 0x09ccf418, + 0xc49b3b01, 0x174ae7d7, 0xdbadd6af, 0x5f7e1f7f, 0x2e60e5d5, 0xf76eafe8, + 0x87af9ba2, 0x76c3a2fa, 0x36ea4d86, 0xa123ab35, 0xd7c438be, 0x0e32bea5, + 0x4c97705f, 0xa79f4beb, 0xa076e33b, 0x2726c9cf, 0xd0f182f3, 0xb8ceeee2, + 0x3aadf80d, 0xbf1cbdb4, 0xf92adeab, 0x7753ed10, 0x85943a6e, 0x9721faf3, + 0xc92d9af3, 0x0fe06bcc, 0x29d13bfe, 0xef0ebe47, 0x193cc097, 0x7588bbf4, + 0xac3ea394, 0xad14f4db, 0x4ebe0633, 0xce34e936, 0x10fe1c80, 0xeaef81c6, + 0x387c925f, 0x0b1b7ac5, 0xeef63ca0, 0xa0d9cd76, 0xd59afce1, 0x6bce3742, + 0x16ed8aa5, 0x72ede685, 0x75be1179, 0xafbc396a, 0xad4ebb5e, 0x9adf918c, + 0x70cdc32d, 0x111fc9ad, 0x717d8f38, 0x6f0bec12, 0x1abd60e1, 0x45ea01f5, + 0xaec6a425, 0xa9496f6b, 0x2d9adf44, 0xf89af332, 0xf83dd388, 0xedd68caf, + 0x5f375ee0, 0x06dd05b7, 0xdba0aaf4, 0x51d05d69, 0x67892fe9, 0xe91b7c7f, + 0x2074f000, 0x255ca09e, 0xc0dcf3e0, 0xdfe8154a, 0x2e3a67e3, 0xcbe217bb, + 0xc79b3b0e, 0xcd39ac60, 0xac0afd9b, 0x7b2a1da3, 0xef99ed10, 0xd3fd86b6, + 0x966dbd60, 0x8025b302, 0xaa05b65b, 0xce15baf8, 0x857f75c4, 0x946f6f58, + 0x15af34bc, 0x809fc059, 0x25e98ef7, 0xc049641b, 0xcaf5869e, 0x4b9e3c1f, + 0xfd43dcfd, 0xfe4fd0a8, 0xcbd1fb85, 0xd1fa98a7, 0x7e8cabcb, 0x493f5016, + 0x474fd717, 0x786675f9, 0x7e8dabca, 0xcf1fa8ea, 0xff4bcdc5, 0x78660dc6, + 0xfd4b51be, 0xb1f34ea4, 0xbaeb8680, 0xedd607e0, 0xb6bde197, 0xe3c27535, + 0xca2f962c, 0xdcf1c61e, 0x7cb12520, 0xc9253291, 0xfea987c4, 0xf43aa661, + 0x2cbad3a4, 0xe3df8ff4, 0x4754b924, 0x4a17a4aa, 0x9e093a47, 0xa46a4687, + 0x2eba1e17, 0x87ae3970, 0x4bda3638, 0xab81a90f, 0x0d7c38f5, 0x132c4a70, + 0x320fb04b, 0x695fbe87, 0x1b2878e7, 0x7df0b675, 0xd6c1bef8, 0xf50a985f, + 0x3fe95b36, 0x959e3ce2, 0x24969db8, 0x976c46b3, 0xdef6e0e4, 0x0d92dcca, + 0xb53c18c1, 0x4bfa068f, 0xdbb6fd83, 0x5fc89903, 0x0ebf4bcf, 0x18adbf22, + 0xfc7d92ad, 0x22aff342, 0x2b8fd041, 0x22665747, 0xc82a1d3e, 0x2af8ec77, + 0xe3445f8c, 0x7ff1c06f, 0x477c6098, 0xf8d314de, 0xd32a9cce, 0xc6154ef8, + 0x26df7e07, 0x07c625bd, 0xd8c75dfc, 0xa1bfcd4b, 0x55391df1, 0xb44afe34, + 0x4fc7634f, 0x27ff181a, 0x5bbb8c12, 0x90d2ebe2, 0x675de7f9, 0xb54e7f9e, + 0x9f2afe79, 0xdfe95eff, 0x3449f8c4, 0xefcd7dff, 0x54e7f9f1, 0x783bf9f3, + 0x7be303bf, 0x107ff006, 0xd1247fe7, 0x306ff3fc, 0xad4c7fcf, 0x3e0efe79, + 0x0fa52ffe, 0x8d1af8c5, 0x13e6abff, 0x6a63fe7c, 0x11d57c69, 0xa91f21f0, + 0xc91a92a3, 0xed06cf9e, 0x94748234, 0xdcb1ca9f, 0xf2976eee, 0x250f0f08, + 0x3cfbbe71, 0x1b4df809, 0x042c77d4, 0xacfa0512, 0xcd7cf05e, 0x503552d6, + 0xde83de24, 0x5d40285b, 0x5f1325d0, 0xd08ed5b3, 0x6f6f0065, 0xfac41c97, + 0x0b5fd582, 0x71deb4c9, 0xb9cc007f, 0xc3ff3e08, 0xc7d6e3d3, 0x2e5acbce, + 0x889fb0ec, 0xc388e49a, 0x63632c13, 0x6bbe011b, 0x67f09d25, 0x1e804fd4, + 0x3f3fa065, 0xe58a3d00, 0x381fc287, 0xa9967a0e, 0x4cd372b1, 0x6f7741df, + 0xeebcc116, 0x509ff010, 0x2c4fbe38, 0xff884295, 0x507a9fcf, 0xb0b4fd45, + 0x3e901923, 0xa0834708, 0x476eff53, 0xf844bd68, 0xee7e22f4, 0xec645124, + 0x5fbec277, 0xe9b866b4, 0xd42cb9bb, 0x1fed0996, 0xb46f3558, 0x67bff30e, + 0x4c82638e, 0x947f9f7e, 0x8d98e48d, 0x318f81b2, 0xfb29f3a7, 0x39dca828, + 0xefb26ec7, 0xeb980aef, 0xeb9954f7, 0xdd90f6bd, 0x62c6f686, 0x7e83ad89, + 0xbf346def, 0xdbb1c637, 0x8c7b0986, 0x0647778f, 0x2c5ef787, 0x9d63e027, + 0xce9f7ae8, 0x69e035bf, 0x22cec478, 0xd3465eb4, 0xc1678fd1, 0x02d7b274, + 0x15b79f3a, 0x4eecfbde, 0x73c0057f, 0xe132c3df, 0x747f0ad3, 0x06dfb25f, + 0xcd745c76, 0xe768ed1f, 0x8563e75a, 0xd665feff, 0xea2ae8f9, 0xeb4179fb, + 0x5627ce73, 0x2ae86a7e, 0xa63c7e1d, 0xeff85d5d, 0xe18f1f87, 0xb32d9aaf, + 0xa1c5f54c, 0x17ed4cbb, 0x7a6799ad, 0xb163b0bf, 0xed03fde9, 0xf3ea9a0f, + 0xda9b0f82, 0xd9acbfdf, 0xc6defef4, 0xefef4cc7, 0x54ca7aa9, 0xacf02bbf, + 0x739dfda9, 0x4bde99d6, 0x898f16fb, 0x8c0d5e92, 0xf2bb42c9, 0x7e43076d, + 0x90ddf834, 0x329a8f87, 0xe4d93ca9, 0xe519b2a5, 0xb6dfe414, 0xeb0d979b, + 0x63d18de7, 0xed0ff6ec, 0x4f28398d, 0xe2b7be56, 0xf0dfcad3, 0x75bc546f, + 0xc16b28c8, 0xd73d475f, 0xe367d627, 0xf8648f79, 0x2e49cb07, 0xb72e556b, + 0xcab23bb5, 0x55ae5fd0, 0x718d8523, 0x79018afc, 0x0f344b0e, 0x3a745686, + 0xd5b80dd2, 0x137cd744, 0x65fb3d9c, 0x651ebf1a, 0xffdff417, 0xb2df1565, + 0x1c883ea1, 0x1c75b9cc, 0xc87fe3c2, 0xa574f086, 0xd3dbfad3, 0x71f86334, + 0x4157f105, 0x734d47e5, 0x14d13ca8, 0x5378f2a0, 0x341f9515, 0x6d195235, + 0x7be5465a, 0xdf2a414d, 0xf2a76a6d, 0x541d4db7, 0x435a6b1e, 0x429a6fe5, + 0xf936f654, 0x2bf01ca9, 0x26993d0c, 0xff614aec, 0xf5410ac3, 0x322e62d3, + 0xf24dddfc, 0x7944cbe8, 0x5e7dad3c, 0xe9f37688, 0x72c60e63, 0xcacbe313, + 0xcaf1090f, 0x545764fc, 0x4c394086, 0x95defa1c, 0xb2e4e9c4, 0xf40c19b1, + 0xfd9763c6, 0x88bf37c0, 0x861b0aea, 0xb37c87df, 0x05fa71dc, 0x75e915df, + 0x7f313a21, 0xa06cf17f, 0xfee789c7, 0xedfb04bd, 0xd70a75c1, 0xad3283cb, + 0xc1b22c97, 0xc18af487, 0xfd3fad1b, 0xbe5e853b, 0xa54efe00, 0xceebf81b, + 0xd8bb7f41, 0xa7ff53a6, 0x414c1d3b, 0x0e49ee3c, 0xf4eaa861, 0x5c1e0de1, + 0xda6496ef, 0xf071e3f4, 0xe1759460, 0x5d8b5d5c, 0xf5ccba27, 0x0cd21dd3, + 0xa6f2bf1e, 0xd67c86dc, 0x0bc7eba4, 0x5499fe90, 0xc92cfd1a, 0xe4e3f554, + 0x3af8871f, 0xf89535b5, 0x6a36fc14, 0x470d1ff7, 0xe1067ea2, 0x87bf64e8, + 0xc917c9ef, 0x337ef2ff, 0x7144fe53, 0xfec7b626, 0x0ee7ae39, 0xf91ceff8, + 0x8dd50af7, 0x72c21b7e, 0x3e3571d0, 0x0f1a6adf, 0x3e1af3be, 0xf3bcb9f1, + 0x4ec2abf1, 0xbdf9f8c4, 0x71f90638, 0xf7acdd2e, 0x86f54d53, 0xb4dd2cae, + 0x201fe00e, 0x524aacf7, 0x056a5f90, 0x5a29f4f7, 0x1df004bb, 0x2e8979b1, + 0x576f120d, 0x01aa8ce7, 0xcb4df22f, 0xb17bd71d, 0x2f1a8765, 0xe9b2716e, + 0x125157b0, 0x9f235fc3, 0x8e22a87e, 0x8d1c3f9d, 0x368bd427, 0x67334f6e, + 0x24fe83d0, 0x667a0ccb, 0x6d3409bb, 0x07e43f00, 0x753138c1, 0x21c59fa3, + 0x75bc7f7b, 0xedc6c7b2, 0x05b8eb64, 0xf85174b2, 0xb47adfab, 0xc56de71c, + 0xa7d77d63, 0x0be4806a, 0x883257fe, 0x47bf0347, 0x3205156c, 0xe5bd5ff4, + 0x3f27b27d, 0x1f0b07b2, 0x1ade8f39, 0x7996bf0a, 0xde663922, 0xe38dd641, + 0x5a7117cc, 0xdf3befe0, 0xe3f17581, 0xe30cecd7, 0xb42cecf0, 0x8303818a, + 0x3fa8364c, 0x3bf36a20, 0xfb3e286b, 0x41db8db1, 0x0785580b, 0xd62ac29d, + 0xe0768251, 0x819b6629, 0xdec53a78, 0xa18c4cf0, 0x25590cd3, 0x6ed03cfa, + 0x7ec043b6, 0xad17d535, 0xd92bd731, 0x33d40cec, 0x2cedab95, 0x4cfcd124, + 0x3ac8a7ef, 0x3588bbf5, 0xb9f5c0ae, 0xdfe3cec5, 0x8ca675f3, 0x5eeaf802, + 0xe304be7e, 0xdcc8b7e2, 0x1be2308f, 0xf871878b, 0x54ebc3ab, 0x7dffbc3f, + 0xae3bc4e7, 0x687df867, 0xc10fae05, 0x936f929d, 0xbf7e2877, 0x7856fc2c, + 0x487bf58d, 0x51c0459c, 0x1b8a45b7, 0xf057bd37, 0x3f8fc1b7, 0xec36f312, + 0x1eb197fa, 0xca37f763, 0x332aae22, 0x4a7ee919, 0x296d0677, 0xefe29ef4, + 0x5f0e1dc1, 0xacefcc0b, 0xf22962ad, 0xc50fd817, 0x59dda62c, 0xf79e805b, + 0xd257af48, 0xa11299be, 0x7b58107d, 0x357dd894, 0x8c53c939, 0x83376371, + 0xf71f35f5, 0x241482d5, 0x9aaee158, 0x6e318ac9, 0xfa00fa0d, 0x7e53d27b, + 0x4bba8258, 0x9fd864eb, 0x971cd323, 0xf5cd7977, 0xf703fc06, 0x8a32c67d, + 0x558f251f, 0x308c782c, 0x9f6e1fd4, 0xe42fbe25, 0x1f13de11, 0xa1c5887b, + 0xb9116a74, 0xe9461918, 0xf297f019, 0xf0e35fd0, 0xda007c53, 0xfb79d52f, + 0x5f07117a, 0x88d976fa, 0x9789e761, 0x15819c35, 0xdd4c7868, 0x519fd388, + 0x25e26858, 0xac2f55e8, 0xf57a31b6, 0x07e05b65, 0xa3d40f48, 0xe3049f08, + 0x04f86204, 0x563d571c, 0xf85a0fce, 0x23866fe1, 0xfbf4998d, 0xe5e05b11, + 0xcdfc7078, 0xe90e67fd, 0x687fe0ff, 0xfa4305ff, 0xfebc75ff, 0xb6de5eeb, + 0x54fc082b, 0x3da7e3fd, 0x63ecccc0, 0x07c323a5, 0xd4ddaf74, 0xfcb941e6, + 0x907a0948, 0x64871fae, 0xf2b3f7da, 0xe4315d81, 0x2549afd3, 0x47c43fc4, + 0xe27c5f27, 0x3eb7b466, 0xc9d764df, 0x88e2dfbf, 0xeb298038, 0xf973173b, + 0x9f78e2d8, 0x8a7e57d7, 0x65d0d9fc, 0x9bd517d6, 0xd2f0ce9f, 0xfe1415fa, + 0x87fc846f, 0x287f8dfa, 0x81ac7b47, 0xb3de93f5, 0x9fe3877e, 0xc2f64619, + 0xe865353c, 0xaebf637b, 0xa1a5e041, 0x654f89f3, 0xf9289612, 0x55f6d68b, + 0x5cf80fc2, 0x9367fb16, 0x33e464d9, 0xc42c1f03, 0xe5f900fd, 0x8e318be7, + 0x35f1b3d3, 0xcb14548f, 0x9def5c9f, 0xfdf03f0e, 0xcb137a9f, 0xc5e82f53, + 0xb0db7b58, 0xc25dbcef, 0xcbc3d97f, 0x83c47b5a, 0x75dafd71, 0x1e105f76, + 0xf0db6ed7, 0xae30e783, 0x77c3b6f2, 0xb35ff419, 0x5cdfd5ed, 0xed9af507, + 0x7c99b4f6, 0x31949a1a, 0xf8069748, 0x4184d96f, 0xe4ff543a, 0x8e3bd555, + 0xd8747f3f, 0xb66a3d20, 0xb8d957ef, 0x1a98f8a1, 0xb546afde, 0xbf097438, + 0x867e8e5f, 0x2a17f2fc, 0x7de3fdd2, 0x1b911b12, 0x5eeb9f07, 0xf1197b25, + 0x74147444, 0xa59ba01a, 0x05d0037d, 0x2741abf5, 0x4263fbeb, 0x6f3fb1de, + 0x4bf3f111, 0x907dc53f, 0x387c3adf, 0xbe97aaff, 0x7c79c1e9, 0xbe7234a8, + 0xc32dbe7e, 0xd956e30f, 0x953a1983, 0x0bd579fc, 0x5b7e22df, 0x195bf474, + 0xfe60bf14, 0x0ad91b2c, 0xdf9c2cc1, 0xd3b7b5c2, 0x80592afc, 0x79eaaef8, + 0xabd702b9, 0x633614cf, 0x78b91c7b, 0x87c5c844, 0x80f1c1eb, 0x0b887df9, + 0xbc0bee07, 0x06de5321, 0x7c520f63, 0x7ec65be4, 0xf5425b0e, 0x4e9c9ccf, + 0xefc315b3, 0x96279585, 0xecae375f, 0x1c9cfa46, 0x71811fed, 0x04a606df, + 0x73a43e05, 0x747cafd0, 0x1f4e08fa, 0xc44a55e6, 0xa7efa077, 0xdf6c73e2, + 0x8abbf76d, 0x73b1df4d, 0x2fe383b9, 0xdc03e315, 0x7ecf6849, 0x1f7f1198, + 0xac62b37f, 0xc5576037, 0x7c8c57f0, 0xf8df7973, 0x436f9718, 0x66b343de, + 0xbd3ffbe0, 0xbf07e5c9, 0xe0057b43, 0xf7a08c8a, 0x48936ffb, 0x2458381f, + 0xb46f5c9e, 0xbf36b90b, 0xe004f837, 0x1ddd7056, 0x7fec17e0, 0xec9fe118, + 0xf0d5cad8, 0x6cbe8c5d, 0x433cf1c0, 0x76e433fb, 0x87ff9091, 0xb3fcb314, + 0x13ee5cb5, 0xc2411bfb, 0xf43dad4f, 0x5e50e783, 0x1f713e41, 0xbd9b76ba, + 0xc9fde702, 0xb9bf83d6, 0x93e4e41b, 0x66a721b0, 0xd39569fd, 0xb0d71daa, + 0x09fa7278, 0x93c413a6, 0x571e7853, 0xf128b54e, 0xfe957ff1, 0x82f7f034, + 0x3e867f05, 0xab47844c, 0xf15ebc3e, 0xfaad3e12, 0xc9bdfe10, 0x9ff2864a, + 0xbf0677c1, 0x6ea8ff55, 0x019dea0c, 0x6ef834be, 0xbe0d2f80, 0x342f121b, + 0x3e886fe1, 0xf00cd8c3, 0x7feec549, 0x99fcc72d, 0x5f7c3dda, 0x843bbe14, + 0x9f93c075, 0x871d61bb, 0xd6c5a546, 0xd87a9643, 0xa96fded2, 0x07da5857, + 0x4b46f52c, 0x0bf710fb, 0x3caa0ebb, 0x6a62254f, 0x82ce5f6f, 0xef538c6e, + 0xd21e2995, 0xc0af3007, 0xb9ada4bc, 0x6863cc21, 0x5338f173, 0x02baba7f, + 0xde9f57f5, 0xb07b41ef, 0x73e3c5df, 0x9efd157d, 0xec3b18d4, 0xe9323dfd, + 0xcd8868df, 0x822fe788, 0x8bf44187, 0x79ef44b2, 0xacba7ddc, 0xf8c32ce5, + 0xc3ec874a, 0xe682cd90, 0xdfb83d3b, 0xff27b7df, 0x7cf03996, 0xb69911e1, + 0xfed0faf3, 0xfb34414e, 0x3f18ac95, 0x7c1623ed, 0xa38c06e6, 0xdafee1ef, + 0xbb165582, 0xbe22ad82, 0xaa96d4a8, 0xbfc117a8, 0x8fbcc0fa, 0x5abbf9c0, + 0xd6b557f4, 0xdef8defc, 0x37abe3f0, 0x8407df9a, 0xf9167fdf, 0xf1d2ed1d, + 0xbbf73c6c, 0x09378f19, 0x2e5d3afd, 0xe00e65ba, 0xccb0efbf, 0xef4e5f90, + 0xa7ff0991, 0x737df2b7, 0x8b5f9f8a, 0x7a4fda7c, 0x0f53c0cd, 0x589a85ca, + 0xfcecf4ef, 0xd023c95d, 0x3bd776a4, 0x6504ffc5, 0x0bb7aecf, 0x97f5867f, + 0x8779cadf, 0x753f6d0d, 0x2bf68b9f, 0x69b9f6fa, 0xef6fb17f, 0xc11e732f, + 0x8f876efa, 0xfdf6fef2, 0xa7f918b9, 0x0aa3b96f, 0x68df56f5, 0xecb667ee, + 0x947173fd, 0xa256c9d6, 0xee76e5db, 0xf3de9ee7, 0x6949efef, 0x70acc258, + 0x4c97dffd, 0x9f86b771, 0xd65e28ba, 0x25cff7b7, 0xa5fbf6b1, 0xec5ea7ce, + 0xd9b9f623, 0x5f081d9c, 0x697fdf2a, 0x1bb5d9f8, 0xa20f319a, 0x00fabf73, + 0xcffa9fbc, 0x3ea3145f, 0xedc1dbec, 0xf47b5e9a, 0x9b27dc05, 0xb962b6d0, + 0x8bd5e81d, 0x64fb8142, 0x0b2f3f6d, 0xf2f0f16a, 0x2f01c505, 0x8f7f1f16, + 0x9fff48f8, 0xf6890f80, 0xb8f76bbf, 0xe7094e43, 0xdef797fd, 0xcfb03d41, + 0xcc697c41, 0x337093f7, 0x9a171dd9, 0x6e57d577, 0x62e452de, 0xbff2bde6, + 0xedbbff39, 0x2acf825e, 0x7cf94307, 0xdf5443ef, 0xbc11f6e6, 0x9befc917, + 0xdf746abf, 0x5cf77401, 0xfe87de78, 0xc8fdd2c7, 0x3aee827d, 0xfc3499e6, + 0xdf0417f3, 0x2773d597, 0x3dd39bfe, 0xfb0dfcd1, 0xaf9b71fc, 0x6ce30f23, + 0x3ac3fd68, 0xb767b9ad, 0xf1efd863, 0xb475b3b1, 0x2fb16517, 0x846f8569, + 0x191ffdca, 0x5e3127f7, 0x3c899a37, 0xd10fee6d, 0xad0c1d96, 0x8f649568, + 0x6e0ada2a, 0x6ebe2b27, 0xf1e5e03f, 0x28fbe72b, 0x384d8787, 0xf67ac016, + 0x438a3e0d, 0x56c2fc5b, 0xb025f989, 0x6f2b9553, 0x8a7e8c3c, 0xe22dac7d, + 0x7df2a628, 0xf88a572c, 0x4d575da2, 0x64568bfe, 0xe6bcbbae, 0xe7f443ba, + 0x677e1c64, 0x9c610b26, 0x80e2be59, 0xf265f98e, 0x50498578, 0x208eb177, + 0x4c8e09fa, 0xc47ff7f3, 0xb898d364, 0x11ebda2c, 0xbe7fd7b0, 0x07c50375, + 0xfef8bd4e, 0xcd6fd8cd, 0x04e664cf, 0x756ef4bc, 0x8df208b3, 0xffd15212, + 0xfd94eea8, 0x523c8f3c, 0x3ecc6b72, 0xd62761a0, 0x704dd8fc, 0x8470ef55, + 0xd5f7c266, 0x4c5f7ebb, 0x7ef2f6eb, 0x2f8363b2, 0x3d4f3c4a, 0x7dc62d18, + 0x0e716abe, 0xf1a74ac0, 0xf77f8f2a, 0x839e4eec, 0x85b4bafe, 0x875649e7, + 0x623bb4ef, 0xaac64bf2, 0xf11da376, 0x1287f051, 0x7c20a9e5, 0x8679f9b1, + 0x43f3da9d, 0x65d7c389, 0x65be610f, 0xbded96f5, 0x3ea87718, 0xd9a1f0e6, + 0x53e5b0d7, 0xfd4f6b8a, 0x944f36f1, 0xe4d92cfc, 0xf7f10e77, 0xd744c8b6, + 0xb23acefa, 0xf44ea15b, 0x8fc70fad, 0x2fc85c7b, 0xdef1f9a9, 0x6140415d, + 0x7b364fcd, 0xb271ae30, 0xfc87937b, 0x8fe72dbe, 0xeff10cb7, 0xd79d8fc2, + 0x7f893bbf, 0xb774fd80, 0xb78ff16a, 0x15fb270c, 0xb7892be0, 0x4df065df, + 0x5ecfb6cd, 0xcf63f8c0, 0x405e4f8e, 0xfaff6b78, 0xfed017c7, 0x3a5cfb64, + 0xbc3443ee, 0xbf14aff8, 0x2a5bbe31, 0x87f7aee4, 0xd5ee299b, 0xf6357e0b, + 0xc3f7bbd6, 0x7a3ff41c, 0x0325ffb7, 0x7ba5e4fd, 0xf9c08fa7, 0x7539dd2e, + 0xbf238b04, 0x1b7c8946, 0x9bb888ba, 0x3b075e95, 0x7c9d920f, 0x7e8de80a, + 0x1ebf80ca, 0x0ff1e3ae, 0xb7d3f0af, 0x0e6f8fc6, 0x6f3bcbf1, 0x936be5bd, + 0x50fbb4b0, 0x3fd05c0d, 0x78e8137f, 0x6fd045f5, 0x5fc263eb, 0x53bf4f89, + 0xe9d007f8, 0x57f0aabb, 0xeb3efd04, 0xe7fdf85c, 0xf0e75df0, 0xe479fe84, + 0xc466f022, 0xfd57ef4f, 0x3728abcf, 0xf1447e3b, 0x4cdba410, 0xb6ef6898, + 0xee3072cf, 0xffbd91fc, 0xef579e3e, 0xad1fd1d0, 0xc916fbde, 0xa3ceef4f, + 0x22649f14, 0x06cbd98e, 0x93b8f1fe, 0xd86b85c8, 0xbd7ee6e8, 0xfdfa3fc0, + 0x173d0f5e, 0x63e73dfe, 0xe44fefc3, 0xf2a9bfef, 0xae23023c, 0x1df1b75b, + 0xd20f3fe1, 0x74829a4b, 0x71bcff7a, 0x3a0f0368, 0x6c7261e2, 0x5c7e2afc, + 0x29ce2065, 0xadc465e8, 0x5053e206, 0x4578c6cf, 0xc58b7a48, 0xebbd07d1, + 0xd7abdc78, 0x199fce6e, 0x678f0fa4, 0xa72adafd, 0x638b8ba1, 0x2ffe085d, + 0xea889f8b, 0x0c73c535, 0x8d9cf53c, 0xab4fc7af, 0x37fa9e3c, 0x902c87ef, + 0x9f21fbac, 0x75d63f22, 0xf3f2afbe, 0xcbbcfc04, 0xc8b7bec0, 0x5179ebf7, + 0x8ac878a6, 0xe3d241f0, 0xec617d56, 0x55e15997, 0xd54f5c1c, 0xa275f177, + 0xa43b8767, 0x073d3f41, 0xd73f1376, 0x455f7d6f, 0x96d0f33f, 0x9edca89f, + 0xeb83f2e2, 0xfe062844, 0x17f6979e, 0xcf1d78f3, 0x338eb63f, 0xd2f1c1cc, + 0x38fe27b0, 0x353f5b0d, 0x0c13538d, 0xf37f3cab, 0x549de3fc, 0x7f6277fc, + 0x0cedbb27, 0x864ef3f3, 0xf6f119e5, 0xeb133f67, 0x035e71a6, 0xb3ca4bd7, + 0x33cfca3e, 0x89237a4c, 0x1e9798f2, 0x9e0ef19d, 0xe20a5b8b, 0x6760f68c, + 0xced3e733, 0x428ff07f, 0xbd1e777a, 0x6a75c65b, 0xc637e217, 0xb3792c2e, + 0xf41baa71, 0x15bbc942, 0xad5d9093, 0x31f266fa, 0x187e099b, 0x03ae0467, + 0x9e0fd0ad, 0x27fcc02f, 0x94f64784, 0x647840cf, 0xe2bba6dd, 0xb5da95e4, + 0x36f3ca0a, 0xe6ebb5fa, 0x76766e3c, 0xe9fb17a2, 0x0bc8c2bd, 0x3c4148aa, + 0x3b7dd67d, 0x29159d2f, 0x99d679fa, 0xecbe848f, 0xef01f269, 0x581673f3, + 0xbdf9106f, 0xd20e7b55, 0xb0aaa2b9, 0xaf80bcc4, 0xe483acc5, 0xaa4766e6, + 0xdb335bc8, 0xfe7bd50f, 0x7757da85, 0x2c35f6f2, 0x3cf1ed4c, 0x1f24c446, + 0x07762d13, 0x913eefe7, 0xa67b51d7, 0xf6624584, 0x7c13ef71, 0x9ba4d3db, + 0xc22d7bf4, 0xa939e1a7, 0x2ea71a6e, 0x8e34dc3c, 0xcceeaed1, 0x93122c75, + 0x74a7547f, 0x9dd5bf13, 0x671a3bf9, 0x329abe40, 0xfb890f09, 0x7b82651f, + 0x2629ffb0, 0xbffb0778, 0xe6b5c681, 0xe6ce6677, 0x5bacc271, 0xce341979, + 0x852654bd, 0xb76f005a, 0x0e25816b, 0x5ee99f68, 0xc32afb9d, 0x285356f3, + 0x8761fa3f, 0x8cde50a4, 0x4a759f38, 0x583682d7, 0xd6d39f6f, 0xa303753f, + 0x707f813c, 0x2793135c, 0x3e7422c0, 0xe43768d3, 0x208f25bd, 0x15013f1b, + 0xf2f80b28, 0x68c11e45, 0xb4f3a516, 0x3cfcdd6b, 0xcd2d18e0, 0x106fdf86, + 0xde71be76, 0x40f9c86f, 0x0bc0b9cb, 0x9b4c079d, 0x18e0fa5a, 0x396f631f, + 0x798a9d3e, 0x967769e2, 0x83a51f6e, 0xa652c1df, 0xe9737d51, 0x97a82cf8, + 0xf5e16fb5, 0xcf8e975f, 0xab957a81, 0x246bd793, 0xb35fabca, 0x60b4c172, + 0xe5e825d1, 0x252300db, 0x11bcbd26, 0xe2aa71e9, 0x7a163bdd, 0x5fa14f31, + 0x1565f8e5, 0x14f46ed8, 0xed6cb78e, 0xa788eddd, 0x3368b631, 0xefef93ea, + 0xea2a73fd, 0x09d32f71, 0xd56b3a3f, 0x68f07e91, 0xe4f3b9ca, 0xc2f359c3, + 0xa5d9fe0c, 0x1c227605, 0xd2c7f36d, 0xaae7bc39, 0x1fd13826, 0x6cf2235c, + 0x0fc81d9e, 0x7ef1e7e4, 0x75fbe0ee, 0xeb0f2299, 0x29b9a3f4, 0x0fa3cec3, + 0x5dbb321a, 0x7d5c0c4a, 0xb3ed3f4a, 0xff7d9df7, 0xc49bcc3e, 0x759c6a7a, + 0x37fbf065, 0x93c90a5d, 0xe981ff39, 0x0b5fc469, 0xde217f04, 0xf879319c, + 0xcaa0e48b, 0x8874c3cf, 0x8e9a6ef5, 0xb58297f3, 0xbeabb9f2, 0x68169e3c, + 0xcf90f781, 0xbc8871df, 0x34be711b, 0x7be33ce6, 0x79eb4788, 0x8a8e8dc6, + 0x55977e28, 0xe5072679, 0xa27ce06d, 0xf48591d4, 0x64779eb3, 0x9e2dbf4a, + 0x9c5eb11f, 0xf7044c77, 0x3e819d8f, 0x9fef3f1c, 0x830e3bbd, 0x40bd5fdc, + 0xe7ca61f5, 0xa526cbd5, 0x215cfc2b, 0x820d05d9, 0x5c6d32af, 0x1887b03f, + 0x39f6d3ed, 0xebfa3f24, 0xc9d4df7d, 0x305ec80e, 0xbee6fc93, 0xe630dce4, + 0xc23df513, 0xfd8297cf, 0x8f7ca120, 0x711293de, 0x3f3e4879, 0xe7e7c8b7, + 0x3cc97b66, 0x6f39df6e, 0xd3fa9457, 0xc8607f45, 0x0f9e0c67, 0xfaf993ee, + 0x25e4d7de, 0xe0b34638, 0x2f13b47e, 0xd38f3c76, 0xf017fe7c, 0xf0633baf, + 0x811c740f, 0x426734f5, 0xc6708e3a, 0x1cf5a3a1, 0x204711ea, 0x587ddb1b, + 0x86056879, 0x4fe7ac5e, 0x42cc1299, 0xdbe9593c, 0x6b3c74a0, 0xec662987, + 0x16ec94f9, 0x2f577e83, 0xc32ba5f3, 0x8b1cf44d, 0xe7bd5e70, 0x6dc21b53, + 0x527bf1d0, 0x8277bb7c, 0xd667af93, 0x44e632f1, 0xed38816d, 0x5095978b, + 0x499f807f, 0x8f5cfc16, 0x14e29af3, 0xfc50c2eb, 0x2fed8f5c, 0x8bfe3f02, + 0xc7e18fc1, 0xae3908d5, 0xa0277dc1, 0xb3bc1ff3, 0xdc60f233, 0x3e235972, + 0xa649bc5d, 0x9fb42db8, 0x28319599, 0x6daf8bf7, 0x7e076fdc, 0x44bcfc59, + 0x9c40b4fc, 0x9c44ff2f, 0xefe6b13f, 0x9209ce55, 0x1e70bd9e, 0x46f4885f, + 0xf3f316cd, 0x7fc29dbb, 0xca1cb374, 0x47f715cb, 0xad7f82c8, 0x09ad3ff8, + 0x6a905eb9, 0xc7a5676a, 0x299b46e8, 0xea6b3c0f, 0xd7e43f40, 0x6fbcda67, + 0x17edfc51, 0x20f18676, 0x293692bf, 0x2498f882, 0x4b7ec34d, 0xfd197c85, + 0xb666598d, 0xe68372eb, 0xedf979f3, 0x9779f3e6, 0xb5348c75, 0x9e4d7cbf, + 0xa115fde9, 0xafef4d2b, 0x54c132da, 0xcebe171f, 0xaeeafed4, 0x7c7d5332, + 0xfb5346e4, 0x9b678789, 0xdf74d7ea, 0xf93f6a6d, 0xfbd37cd8, 0xa6d5a36b, + 0xb47fd7f7, 0x5aff54c4, 0xb531ffff, 0xfae42c8f, 0x665340eb, 0x7c98f1f6, + 0xaa0f03e3, 0x3f9f1d36, 0x8bd36858, 0xf8679f63, 0x9658c5bd, 0x4e9fd1f8, + 0x3aa767a4, 0xd763b2b3, 0x376652f7, 0x4ea99fe9, 0xf0643d73, 0x0bf00e4b, + 0x45937f10, 0x6dbc80ef, 0xd5193941, 0x983b4378, 0xe2e46ca1, 0xa7941482, + 0xc5f9f1a7, 0x9236d9c9, 0x9d08fab3, 0x0e738f8b, 0x17356dfe, 0xf7482ef9, + 0x2e1980a1, 0xa33100ca, 0x9606e60c, 0x29060b0a, 0x28f99cd9, 0xeebad2ef, + 0x15bdeb1b, 0xdc9c071f, 0x6178701e, 0xdfd9379d, 0x645fee21, 0x3129731e, + 0xa8f590f8, 0x1ef0eea9, 0xd77fe2d6, 0xeb2e7a6d, 0x69754cc7, 0xffca4cd1, + 0x3d970449, 0x1b4dfe73, 0xb3d9bf41, 0xcf1a5402, 0xe2d8e6db, 0x9d45f7e6, + 0x9de79717, 0xf10bbed0, 0xfb18a5fc, 0x39748a2e, 0x33c6f695, 0x3f56af98, + 0xeffc9fb7, 0x3f59872c, 0x237dd60c, 0x97963e78, 0xf9d4279f, 0xda9b6b9f, + 0xdf75c26f, 0xb7c2e798, 0x7e606767, 0x7f027642, 0xe7c5c73c, 0xd55342f1, + 0x8cf00b4d, 0x2589da09, 0x73b2e783, 0x68e50d22, 0xf9118d7f, 0xe2d8cfd4, + 0x759d3de7, 0x047b7f72, 0x13b4682a, 0xcb3f7e34, 0x3d77caa9, 0x2455b298, + 0x7f22ce07, 0xbbbabfce, 0xf65f9f84, 0x7c3cf265, 0xf437e09d, 0xf1568e5c, + 0x1cadea0c, 0xb9bcd730, 0x3119e143, 0x2e4662b7, 0x661d6fbc, 0xef5469f3, + 0xf05ce897, 0x870d8ca3, 0x957fadf6, 0x03d6be09, 0x905e52d7, 0xda1805aa, + 0x993cc6e1, 0xf63037c8, 0xbb4b3e11, 0xd6d4fc8d, 0x05ce072b, 0xb55bf231, + 0xf7ec6e8a, 0x0858bc33, 0x932d69c6, 0xb473ef4c, 0x010f078e, 0xc99d951c, + 0xd6549714, 0x967e4cdc, 0x69e1c99a, 0xd962417d, 0xe3c3c112, 0x0f8e1ee6, + 0x42ea83c0, 0x3f73fb3a, 0x869319b7, 0x2a2975f7, 0x9d1ceb9d, 0x8d719e20, + 0x5b7ebf01, 0x9709d906, 0x5795e19b, 0x21e0fd3f, 0x89d903cc, 0xfde11637, + 0x3d04cb22, 0x4b6df3cd, 0x5dcb7d9b, 0x4de5aed0, 0xb800c999, 0x30d8ca37, + 0x0a1c879a, 0x41b7c1c5, 0x1afb802f, 0x535e5b84, 0x15ccf34e, 0x74045e74, + 0xd32575c6, 0xe8833156, 0x3863619e, 0x37fc2b4f, 0x7fdcb8b8, 0x790ba5cd, + 0xe369bcad, 0x90172c70, 0x9b5e81bc, 0xba97fd86, 0xd311da12, 0xdbf4715c, + 0xa8ffee85, 0x087dd39d, 0x136fd94b, 0x61636d76, 0xfa0cbdac, 0xd7ec16f0, + 0x8f29cba8, 0x17bf6316, 0x141bbbb2, 0xee617b5f, 0xb432ed85, 0x0cff90c7, + 0x39e60c7b, 0xcfbbc70f, 0x31ebd665, 0xeb9e7c7a, 0x4ac9ece2, 0xdde1f76c, + 0x12f6b891, 0x1bb271e8, 0xfaf8d5d3, 0x1e82fbee, 0x28caba0d, 0x3ec1302f, + 0x5c5d77d1, 0x4ff3adae, 0xc85ddeb4, 0x611bc8ef, 0x14ec07ee, 0xa5583ff2, + 0xa756fb4a, 0x58f75d1f, 0x68fbe621, 0x9bc79479, 0xcb519fa8, 0x0f3f20de, + 0xe204f9f0, 0xbb5fc0c1, 0xc69e7f85, 0xc5d6f1f7, 0xcda7c05a, 0xd70ecf84, + 0x7f9fd845, 0xf328b9fb, 0x815e9e79, 0x0ffbd077, 0xf5b83e92, 0xb38c12bd, + 0x39fedfd4, 0x79bffde9, 0xb8e6399c, 0x802f1181, 0x9c716a71, 0x2aff5bde, + 0x8a51bae2, 0xbcecb647, 0xab07ee9c, 0x49f4332b, 0x45ce93a3, 0x7d11e766, + 0xf872ed4e, 0xc353ce11, 0xd4ec5c78, 0x3087c9ae, 0xd349f32e, 0x73d8bce1, + 0x3a5ea759, 0xfe87625a, 0x5a38ed4e, 0x0f5e90a2, 0xf78cde11, 0xa5fee775, + 0xe377fd04, 0xdf00c1fc, 0x4bafe339, 0xf9fc16bf, 0xf180f165, 0x525fda78, + 0xcf68b3d8, 0xd6a5e00d, 0x2a7ff79c, 0xc412bdf9, 0x13ffe603, 0x463c045e, + 0x8bb57bbc, 0xa45a9fc7, 0xc6e31060, 0x54f7522d, 0xff06d38c, 0x4073a317, + 0x9256b799, 0xcc3dfe99, 0xd61abc03, 0xb7db0ca1, 0x3e667db1, 0x750b9b1b, + 0x111d2bc7, 0x1dd49f7c, 0xed42bca6, 0x4b047758, 0x8fdfb44f, 0x47fa86db, + 0x6f2c7efa, 0x86ff02d7, 0x0feb0fe3, 0xfdf2815e, 0x3313058f, 0x4ca12631, + 0x62f61df5, 0x852ce21e, 0x7d3a6dee, 0x2275a658, 0x3d739663, 0xa8ceff3f, + 0x5eedccfe, 0x9392375a, 0x81e9f38c, 0x15575c5c, 0xf611fa56, 0xf815d5bb, + 0xc33ff904, 0x08785dd6, 0xfb1d73be, 0x79e60e6d, 0xeda2f71b, 0x8fd8ad2a, + 0xbbfdc6fb, 0x367aef25, 0x9c9f6e34, 0x28dfe5c4, 0xbe3527bf, 0xc961f98d, + 0x63a7db8f, 0xae7bebbc, 0x0547ba46, 0x999df9fe, 0x702b9fd0, 0x71854b0f, + 0xc66da924, 0x876ea0d7, 0x7bf1e3f7, 0xd02b5b5b, 0x606a5761, 0xbbde0d94, + 0x87ad73a5, 0x8dfc3df1, 0x49c965f9, 0x9ef15ae7, 0xe7493538, 0xb902d0f3, + 0xba818748, 0x4c77750e, 0x2ba969dd, 0xabcc6ebc, 0x285fe0ee, 0x0f7eb3ef, + 0xef07d7bf, 0x337dc333, 0xe50cb7bc, 0xe849353f, 0xb1698d09, 0xdacea1e7, + 0x3c49e902, 0xe5c8593e, 0x265f88c4, 0x97e22f78, 0xe291ac85, 0x60f1236b, + 0x5bda3e75, 0xb0e654dd, 0xf88d2a7e, 0x51f31e5b, 0xa82ac059, 0xa83acb1c, + 0xa98592bc, 0x54dd622c, 0x2a7eb316, 0xb1974c7d, 0x547cc09c, 0x8f1ad9a6, + 0xf97d474e, 0xcbe93b0b, 0x1e0f2dc2, 0x0508c918, 0x6aa5ba26, 0x69867e5c, + 0x2864a1a5, 0x80388b57, 0x16a9ae71, 0x3545e669, 0xd07d90a0, 0x93ea6423, + 0xee20b635, 0x2ab9b29f, 0xe715af3d, 0x3edf6b80, 0x27e47640, 0xaa79f8fe, + 0x4b949353, 0xeb3287dc, 0x1ab586c7, 0x73e41be1, 0x1ebbe22a, 0xcdba82e1, + 0x1ee74dd9, 0xdfc3cbed, 0x745f7196, 0x45f69d9b, 0xa026506b, 0x0c2ee35e, + 0xa7984b35, 0x9f6a515b, 0xf24d7c44, 0xce1a9353, 0x9e0da098, 0x78fac407, + 0xebdf906d, 0xc1ca9ebb, 0xf78ff67d, 0xf9eb4dbf, 0x34b9c9f5, 0xa3ceba9f, + 0xfb4dc06a, 0xcdca2a76, 0xf603e9c7, 0x6d8dd937, 0x9e0a5f2e, 0x25ffe93b, + 0xc0ca8fbf, 0x7e95f7df, 0xc7beec57, 0x745026e1, 0x37af632a, 0xabf95265, + 0xbf952f26, 0x1f99d268, 0xf623b91c, 0xe11136a8, 0x11d02f4d, 0xf0f44fde, + 0x612663eb, 0x179e7b1e, 0x7692d3e7, 0xd444d57c, 0x77d93e3f, 0x77638c19, + 0xf7849f2f, 0xce64b627, 0x95947ca6, 0x1fe704da, 0xc5169e00, 0x71874ce7, + 0x6876d35f, 0xd3794197, 0xb89d9317, 0xd696bfae, 0xdf7179a9, 0x3aedfc64, + 0x7f4103ee, 0xfea56fab, 0x09bfa2ec, 0x18ff6c4e, 0xf60da3f6, 0x6fd45fb3, + 0xc348ef72, 0x189a87f7, 0x7a537dc1, 0xf7f61a67, 0xaf85a2f3, 0xdf84984f, + 0xbbdee2db, 0x3499d374, 0x67bb07e6, 0xe61c99e6, 0x737af587, 0x2895e359, + 0x9a4ddfff, 0xf904e6d6, 0xab1b7257, 0x4dac5f51, 0x09cdb9ba, 0x3653efc6, + 0xf54e93a0, 0x0015dae9, 0x1fae34c7, 0xbc36f200, 0x659ed06f, 0xfc3af8a3, + 0x8e5eeba3, 0x8eb8fea0, 0x2d969fbf, 0xfda010f2, 0x9f9fc7cc, 0xad57768e, + 0xe962f9c4, 0xd3ee8ced, 0x544f6448, 0xf3a2499d, 0x7afd4679, 0xf31104ba, + 0x8fb483d8, 0x43c67552, 0xbe2efae7, 0x1ce9a73f, 0x34fed0e0, 0x95f0ef1a, + 0x29f93f06, 0xbb74b36e, 0xf970cfc8, 0xefbb6047, 0x83f98dd9, 0x7c44edbd, + 0x0a83d40d, 0xaa23dbe8, 0x6df9ff31, 0x6e7f40d3, 0xb3df0756, 0x658f9829, + 0xf47e67bc, 0x89248f87, 0x7e3ab07a, 0xfb4b24fb, 0x4dfea33c, 0xe7856f6a, + 0xbac1ae7b, 0x5f2bda13, 0x08ea0638, 0x4b3653df, 0xf18cc37f, 0x6afea11f, + 0xbed16572, 0x12bf55f5, 0xaae0ef43, 0x667bd2f3, 0xad6dd3d2, 0x9011fdf0, + 0x6ebf5a73, 0xa17eb467, 0xf462f9dc, 0x6eb14ce0, 0xd2b99d55, 0x3a418f44, + 0xfee89b14, 0xec65c821, 0xada2eb3e, 0x2173a4df, 0xbcbc9333, 0xe7e4161f, + 0x9be6d69c, 0x3fff57f6, 0x1c2b7f1c, 0x4c7004fe, 0x63862ffb, 0x41bc69ac, + 0xf04c8a38, 0x51c3e7fd, 0xf28e0096, 0x561c14af, 0xc728c57b, 0xf642bda0, + 0xb0f38f2a, 0xb7b236e5, 0x151552fb, 0x369897f3, 0x5204ec85, 0x8eea5e19, + 0xf146f1f6, 0x8f7799ae, 0xf3b61e63, 0x995dac2a, 0xe82afa80, 0xed7dc3cc, + 0xe07ef16f, 0x740561f9, 0x2754e8d0, 0x177b47ed, 0xfc60d454, 0xb2a73bdf, + 0xf1bd4a8e, 0x33ffbc16, 0x3c7fa0a7, 0xb4eb77da, 0x98db17b4, 0x6905ef49, + 0x241e97dd, 0x13ee76bb, 0x2c94dadb, 0xcf8d9bd4, 0x052c1da2, 0xce1db5b7, + 0xeb9ef78a, 0x5f927bad, 0x542975a2, 0x3f44aec6, 0x850ae428, 0xda3d200f, + 0x23d21f34, 0x7b5089f7, 0xc795d41e, 0x8066be6c, 0x6d0d4957, 0x2bf00f59, + 0x9afa164f, 0xf5087de1, 0x527fb61f, 0xab3de109, 0xd9bc9a2b, 0x8b49bf78, + 0xb7d68fb0, 0xdf31d4ce, 0xb30a9ed8, 0xb0ae5204, 0xf685de37, 0xd7e49afa, + 0xe2d79cdb, 0x1f6be07a, 0x267af3ae, 0x8f39b5c0, 0xc55339e5, 0x437f587b, + 0x1ea46ccd, 0x7f4af753, 0x5fbcf995, 0x80dff36f, 0x6a92fceb, 0x157fbfc6, + 0x879b95e3, 0xefe17819, 0x5c7531bd, 0xc1e6944f, 0xf79834fa, 0xbeb9e786, + 0x47fa147f, 0x13e61f7b, 0x1c6e3b24, 0x8c324f9f, 0x2710f78d, 0xf5a3cf8f, + 0x8beb0435, 0x578fdf07, 0xb1963ce8, 0x671ce3bf, 0x6c1dfda3, 0xdce4f58f, + 0x73ffda3c, 0x08be62ce, 0x6966ede6, 0xf150bf7c, 0x38fcc34f, 0xf8bf00f7, + 0x8aa8de29, 0x926d0ffd, 0xa93fff79, 0x39b4bbf5, 0x7e64549e, 0xd7302cee, + 0x1f37cc1d, 0xb66a9683, 0x592879f9, 0xb387efc4, 0xe457e891, 0x6c3682db, + 0x510b0577, 0x908b1579, 0x458e3f5d, 0x86357ea9, 0x38f1f33e, 0x700e9794, + 0x997e644d, 0x642b47c7, 0x68163bf4, 0xbf68cd81, 0xfe164c6f, 0x6fde48ca, + 0x77c1454b, 0xbe297ba6, 0xc5e519b1, 0x559eafa8, 0x448df14e, 0x3c69a5f2, + 0xdee2388e, 0xfbdef382, 0x8f8cf539, 0x3ce46379, 0xbb79e35d, 0xba31b70d, + 0x0f61a28f, 0xf78ca3f7, 0x7ef324af, 0x2fc4121b, 0xc15fae41, 0x459f7c79, + 0x74b9edcb, 0xd3dfc9cf, 0xda8fb03d, 0x17548218, 0x6dfb9b79, 0x513b7b16, + 0x92cfd91e, 0x80f2fe79, 0x18fc235f, 0xce9035f2, 0xe0597fc2, 0xbe6ee832, + 0xc7b8c1cf, 0x4dc84fa1, 0xc44aa55f, 0x09834068, 0x05b7e9ea, 0x4a801ee8, + 0x35ca9f31, 0x1fe819a5, 0x177fd82c, 0xf570b9c1, 0x0e30352c, 0x23cdc9cf, + 0x5d7818bc, 0xfe0ff160, 0xbcf131d8, 0x9ec332f1, 0xc303fc36, 0x09fab01f, + 0x71bfbe89, 0x43a27eec, 0xed296679, 0x7b237edb, 0xc0eb0d96, 0x4fbc7e6d, + 0x78af38ca, 0x9feecec4, 0x6439445d, 0xb3f9f033, 0x550f7e2e, 0x7543dc48, + 0x0c3f9bd8, 0xff919bbf, 0xbe5815c5, 0xa86b0ce6, 0x7b3b5fb7, 0x1ff266f4, + 0x7986b094, 0xee14a717, 0xc67519ff, 0xbf14c8ce, 0xc9bf7817, 0x8fdd06fd, + 0xefee5370, 0x9d78bce8, 0x573a0dfb, 0x4ed3aa7e, 0xb9377279, 0xf7b169c2, + 0xbb94dc67, 0xf87ced37, 0x2387fc31, 0x79c3de02, 0x6804e49f, 0xe19f915c, + 0x4b9d20df, 0x35bdfc4e, 0x471ae33f, 0x61f23759, 0x5dd7e0b7, 0x8345205a, + 0x21766db2, 0xacda4fc9, 0xbfde4e49, 0x94247f39, 0xc57c44cc, 0xff0647cc, + 0x5905ef59, 0xe873f12a, 0x386ae089, 0xafad3363, 0xa884f783, 0x8af6beb4, + 0x26774378, 0x907afa7b, 0xd1ac5997, 0xe26ffb4e, 0xc916957e, 0x313d476b, + 0xdfb96fcb, 0x5551e447, 0x2df0f588, 0x6a051f91, 0xe63f55f1, 0x7d3f3175, + 0x63ee2dd7, 0x8f602c61, 0xfd023f97, 0xaddaf49a, 0xdbf5cc33, 0xeb75cc2b, + 0x1e46863d, 0x7a4d2bcc, 0x5d3dec76, 0x87e812d3, 0xa5db351b, 0xcd1a0fc5, + 0xae2303f1, 0xc3f98757, 0xe3c2cfb4, 0x7c9dd37a, 0x8b88b2fc, 0x341a2ff6, + 0xb8861d75, 0x3de19f51, 0xae35d3f6, 0x845e306f, 0x574d04f7, 0x436dfb8c, + 0xef939f22, 0x6457a47b, 0x7dfdfb8a, 0x54af7499, 0x1ce99257, 0x386711ab, + 0x494de05d, 0x3b7f0f3d, 0xad70d8d6, 0x54afa818, 0x07c89d1a, 0x5e79b32b, + 0x871f20d5, 0xc754f14c, 0xfdee351a, 0x80fd0372, 0xe273c15e, 0xdb6fb12e, + 0xd8f5f8ae, 0x5ec38478, 0xda7f23a1, 0x5edd65dd, 0xab55e5e0, 0xabc72cee, + 0xbf305a0b, 0x4694ec17, 0x822bebed, 0xed3b4fe0, 0xaf78c3be, 0xf36dd3af, + 0xacdc7ae2, 0xab3f68d9, 0xeb49d325, 0x56a90aef, 0xe8d2f5c7, 0x685519d7, + 0x3cb5a73e, 0xe0897fd2, 0x669fc153, 0xbe631fb4, 0x6f3fea8f, 0x0dda8d3c, + 0xe0eaffb9, 0x756714b5, 0xff946d79, 0x746816a4, 0x5fc19a8f, 0x6b9c7ed6, + 0x24fdb894, 0xba427fc2, 0xd794a3db, 0xdfc5abd6, 0xbb497e5f, 0xb9eebcc4, + 0xea777896, 0xf8230a6f, 0xe0f514bd, 0x8f902eb9, 0xab8c3497, 0xabfd3e8d, + 0x47c92f52, 0xe1afcf06, 0x2da2db72, 0x5fbcf277, 0x89693df3, 0x4bc0d1f8, + 0x47283c22, 0x4fdc51fe, 0xfab1601f, 0x563529c6, 0x68e1bed0, 0x138a6d85, + 0x5cdc514f, 0x3e28b74f, 0x6bf95fe2, 0x075c4e15, 0x9ccad39a, 0xa6df9fb8, + 0xd1725378, 0x33223c3e, 0xeab59b8c, 0xca31b966, 0x4f7ef1c7, 0x8898e380, + 0x27df5a8b, 0x380bc825, 0xc7f5d627, 0xeddb5ff7, 0x009f0f3f, 0x491e68de, + 0x7a8e8a79, 0x7873b641, 0xed7dc593, 0xc44dfa89, 0xe7ec4f1f, 0x8abbe0f7, + 0xca8e749c, 0x38ab5e3a, 0xf00ad72f, 0x9adb9da0, 0xbee3e30d, 0xc9d157b8, + 0xc49b1e8e, 0xa17c319c, 0xf7a24ea4, 0x3c34b5a7, 0x135ac7bb, 0xa7819df0, + 0x1f552ed7, 0x97fc2c07, 0x978a5bfe, 0x5fdff0c7, 0x6bdff1e3, 0x1ce973c8, + 0x2d7bd8fe, 0xbfbe5495, 0xc8d78567, 0xdb6677af, 0xc04bed4c, 0xa371e0b7, + 0x032a1cef, 0x50311cd6, 0xf1870607, 0x71cf513a, 0x74e22e7f, 0x714fb60e, + 0x55bca77f, 0xc39d3aa1, 0xebfcef83, 0xf74f6a34, 0xcea1d4d9, 0xf6aa3f07, + 0xb0e98d4e, 0x4bd59f3e, 0x6f00ddd3, 0x7e01f749, 0x9d33a61e, 0xf88b5eff, + 0x8def0ade, 0x1bf74e1e, 0x29953a3d, 0xc23ffcc7, 0xece83fdf, 0x1c62f24e, + 0xfc5873b7, 0xcc7883df, 0x742fe46d, 0x28c8fd88, 0x4fa44bed, 0xff51ebe5, + 0x8ff264ee, 0x99a7e286, 0xb16177df, 0xc1ee0637, 0x77642250, 0xc3bb0ad4, + 0x2e64bf18, 0xf287aff3, 0xeed624d5, 0xca70fb04, 0x15dff8c0, 0x47802dfb, + 0x9f96fb80, 0x4ffb455d, 0xc2af7f46, 0x33ed84b2, 0x92c5a232, 0x13fc097c, + 0xcefba666, 0x42d19cea, 0xd97b1fdc, 0xf88e9816, 0xcd16386e, 0x1be77ac0, + 0xbc1ec927, 0x72ee1e10, 0x7b9a7d73, 0x479f6195, 0xeb38d8d4, 0xe7a5edd2, + 0x8b570f3d, 0xfd1890f1, 0x72b78836, 0x7e90ebc2, 0xe8af3fa1, 0xe92be31f, + 0x3ae9f12d, 0x2c919f48, 0xf47cfc38, 0x89c161c9, 0x22a12e9c, 0xe7dc7f4e, + 0x5d937983, 0xf59b741f, 0x8afeffc9, 0x130d37cc, 0xd29f80d1, 0xbef3c4a1, + 0xde2cef78, 0xe3c4bb8f, 0x693fad35, 0x1d457b0a, 0x4987c316, 0xfa84e82c, + 0x4be88e2d, 0x7518ff68, 0x0e2dfde3, 0xcfec69e0, 0x90c8e5c9, 0xf1b9dadf, + 0xedc736e5, 0xc74df9e1, 0xf7dc1e22, 0x03e38e98, 0xbfc33bbe, 0x3ac77ba7, + 0x3f8664bb, 0x6e62309d, 0x83680e40, 0x0fda1a74, 0xfc86abd7, 0x95793983, + 0xed3fc85b, 0xfee32ee3, 0x8c67a1b5, 0x6b725eef, 0x8b8fa697, 0x7af39c86, + 0xe408e509, 0xcb2e10ea, 0xbdf8cb39, 0x5ee2b577, 0x0f711e9b, 0xdfc207e2, + 0xaff73a60, 0x3eb07b8d, 0xf7c81c28, 0xd6af3f23, 0xde0effe5, 0xca8ec343, + 0x27fa6f94, 0xfdc29fdd, 0xd4bfb343, 0x31b9ee23, 0x66b6a5fc, 0x36736f71, + 0x4936e7e7, 0xf6167fba, 0xf74a363b, 0xf0646718, 0xa738d3f5, 0xf4a332c7, + 0x1f065a7b, 0x7fb3e225, 0x7a80f211, 0x8f97182f, 0xe32fe255, 0xeeb007f9, + 0xb5ec6305, 0xd0151ff9, 0x98079bb9, 0x0f97e28f, 0x60b327b4, 0x5f3b5e0c, + 0x732f9f88, 0x29db8c42, 0x456679ee, 0x7c835e7c, 0xb9d1e7ce, 0x0fdc3e3c, + 0xe8fe70a7, 0x7779f714, 0xc464fe2a, 0xe175a253, 0xf65e80c4, 0x2b1f2327, + 0x99bc1c5f, 0xc79af5c6, 0xfbf457bd, 0xe2cabfb3, 0x8f0004f7, 0x7b607f42, + 0x1762c7a7, 0xf0feb25d, 0x419bd69b, 0xbd234fbc, 0x43fae972, 0x48fe80bf, + 0xf2c2fa23, 0xe2bb41ee, 0x57bf30c5, 0xb6c3c5ed, 0xd0e3eb19, 0xe5c840ad, + 0xdd0ae995, 0x84557643, 0xda89fbaf, 0xf7130c65, 0x5a3c0b0a, 0x8fcb4be1, + 0x08b71fcf, 0xf196d43a, 0x9ef1917b, 0x942f9c76, 0xafe83e39, 0xd20b4ca7, + 0xbc8bbff3, 0xdad17187, 0xfe2f0e1d, 0x0ecf524e, 0x85ea1557, 0xaa8e1d9e, + 0xfa50daf5, 0x9bf42df9, 0xff8cec2c, 0x64bffae9, 0x2fe27fae, 0x4ba01f71, + 0xad1c7ba6, 0x76e93dfd, 0xfa0377d3, 0xe5dd813b, 0x2d33fa10, 0x9ec5d399, + 0xab4dd7c7, 0xf023dd5c, 0x67c08f76, 0x1e57b89a, 0xae2721d6, 0x39bb4643, + 0x0094fde2, 0xef3f7b8b, 0xfa570863, 0xecf03ae0, 0xfbf632b2, 0x7d3bf8e1, + 0x742b8a41, 0x839236fe, 0xf294f6fd, 0xfbf58138, 0x8c67c162, 0xc9e8ed99, + 0xfd12bcd3, 0xd258611e, 0x807edf71, 0x4f7e61de, 0xb2770af0, 0xc5a2cfb0, + 0xf73f92f7, 0x48a3f524, 0x0f1c50af, 0x0dbf366c, 0x0a7e88f3, 0x9e4c5b76, + 0xbd16bde6, 0xbe678563, 0x13b7cf9b, 0xa3f637f5, 0xdde38b45, 0x5bac60ff, + 0x86d3bcc6, 0x49e0e59b, 0x26c71f0f, 0x25974bc6, 0x6eba0f1a, 0xebe30c77, + 0xe60bcf31, 0x479e127a, 0xc80b39e8, 0xfaee00e3, 0xfc6fc5fb, 0x59ce7888, + 0x13d2b03d, 0x5da00763, 0xb095eb4e, 0xc6553bc3, 0x5d844bf7, 0x8274fa88, + 0x90770b16, 0x6d974906, 0xf12b5f5c, 0x43cc35f5, 0x9b897efc, 0x2fb419fa, + 0x4fb11db8, 0x389d6bcc, 0x8daafa3f, 0x21bd92b5, 0xe9c864f0, 0x6e9c8b4e, + 0xec357cf5, 0x77e275b4, 0xf17e912d, 0x614ae1f4, 0xf31c95af, 0x95bcc78f, + 0x1f342acb, 0xdd25a1fa, 0x9e600fb3, 0xfc1ee14e, 0x39419a61, 0x8cfc142e, + 0xc18dcdfd, 0x6e3cefdf, 0xe6f7dd93, 0x857f0457, 0x7cc0d8c7, 0xebd18def, + 0x7ae1eeff, 0x2dfc1d2b, 0x5fd38394, 0x785ebd11, 0x9e00e2ac, 0xba05aac3, + 0xf830caa3, 0x6f3c33a3, 0xe1ed0bb9, 0xf687cc63, 0x9e786f74, 0x47f01c6d, + 0x3f6e1aef, 0xd5f9e80e, 0x97a05f1c, 0x2f97a8c3, 0x2e4fe63b, 0xc296ba82, + 0x7365eef5, 0x2967bf19, 0x5fa10eec, 0xf489e86d, 0xe2a7fadb, 0x727d6f3e, + 0xe62bb363, 0x2efb40f9, 0xa83b9f68, 0xdf516a6f, 0xf3db1378, 0x79925323, + 0xc71e7b3e, 0xe664f4cb, 0xaf3c0174, 0xdc6506e6, 0xb2f57cc7, 0xaf7809dc, + 0x40a4a1fa, 0x7ef812d1, 0x0e3e0cf2, 0x2e8472eb, 0x47878dcb, 0x4433afae, + 0xe44328dc, 0xf124676f, 0xe70a4572, 0x979d24f7, 0x1f9ce9f7, 0xe3f13c32, + 0xbb44cb4c, 0x3bd71b3e, 0xb7c6978f, 0x914bae4b, 0x8b3ced2e, 0xdfc6b24f, + 0x17494baf, 0x06db6af7, 0x3fc1b5f5, 0xc677c427, 0xfc6265f8, 0x89986745, + 0x8d29167f, 0xce8b37c4, 0x8637c428, 0x3fe2245c, 0x1aeeff63, 0x14c6e047, + 0x9fa3f79c, 0x209c6315, 0xdf0f6577, 0xdfdfc237, 0x7cb136b9, 0x4181eb18, + 0x9df3d06f, 0x3d00cf18, 0xad0a693f, 0xfc8bcf43, 0x31a72e53, 0xf08ffa76, + 0xbb3b1df7, 0x8e6bccaf, 0x7ac0eba1, 0x8cfee3e9, 0x85195d75, 0x89e9c049, + 0x7298d5e7, 0xcaedfaa9, 0xf1787604, 0x5e1da97f, 0xe4813dd2, 0x578101f6, + 0xc466be23, 0x7897f0b1, 0x8ab3bdb9, 0x1a7931f0, 0xffc06f97, 0x22ff8156, + 0x1a7fff8e, 0x643dffc0, 0x79707427, 0x4bd688c9, 0xf45f24f9, 0x453bf19d, + 0xa0df27b9, 0x293dce7c, 0xa9df7fdc, 0xbe409ffb, 0xbbf2255c, 0xa888cf27, + 0x407b58de, 0x2ad17efc, 0x1af9c0fb, 0x591bc7ca, 0x0ecdfbcb, 0x189497ef, + 0x8596d1f9, 0xf9802cc7, 0xf9f15767, 0x9bb14dac, 0x5875a7d6, 0x485f2e87, + 0xbb2dfae1, 0x6015222a, 0x4a376b7f, 0x1237f40a, 0xf809877f, 0x0b236466, + 0xd0fefec5, 0x4f1f1f48, 0x07a485f3, 0xd3e7068a, 0xa4559b6e, 0xcf695e83, + 0xa0b5f648, 0x3606a4c8, 0xbed79f23, 0xf2fca11b, 0x2b76efc9, 0x9e5fc7e8, + 0xcf82dfea, 0x6578f98d, 0xbefd247d, 0xce1cbbf9, 0x32f7610e, 0x71e1cd16, + 0xfe0427ff, 0x887b0bd7, 0x23dfa61d, 0x94fdb8d2, 0xe9ac7cb1, 0xff0ce777, + 0xfa73fd07, 0xb599693d, 0x70a78a33, 0xbcb196fd, 0x834bec90, 0x57e7a61f, + 0xd3e7c46c, 0x01315c47, 0x5fc897ef, 0x77f05115, 0xd6ba7fa5, 0x94fef716, + 0xc01f4243, 0xcec7f63c, 0x6b7242e3, 0x9d27b3b4, 0x67936f9f, 0x0ddbb7c4, + 0x3e7d2c3e, 0x0fba6eed, 0xb86555b1, 0xffe064ef, 0x378ad4f2, 0xe1919e11, + 0x46e11275, 0x49c4678c, 0xcfca39f0, 0x9cf9aa07, 0x5cf9425e, 0x82cc63b6, + 0x556cf958, 0x2ceb3e89, 0xe86e13bf, 0xae14de8b, 0xad48efc7, 0x71f203f8, + 0x1453d77d, 0x91bc59b7, 0x424c1eff, 0xfe245cfc, 0x78cdde60, 0xf80d5dcf, + 0xa3ef7817, 0xeec89614, 0xf7c39dad, 0x72b76adf, 0x2aad657e, 0x1b5703dd, + 0x7f411ede, 0x7ea3d462, 0xd5a76e1f, 0x2d2edd6c, 0xa8ebc18c, 0x27e510da, + 0xe436ee5c, 0x2b19eb89, 0xd8dc63df, 0xc876fc05, 0x9eeaedc5, 0xff07ee52, + 0x7ac9083f, 0x0080006b, 0x00000000, 0x00088b1f, 0x00000000, 0x7dd5ff00, + 0xd5947c79, 0x6779f0b9, 0xcc93324f, 0x2133df64, 0x61262201, 0x01161212, + 0xa0084933, 0x24584e08, 0x81ec36c8, 0x8bf628ac, 0x0c197e95, 0x6f62e452, + 0xb90556ac, 0xda544076, 0x1a080962, 0x88b0e834, 0x148d6ad0, 0x43b05b05, + 0x921088a5, 0x6f16b629, 0x79e7bd69, 0x799939ce, 0xf8b0ccdf, 0xabbf7ed1, + 0x9cce1c7f, 0xf3cf6cf7, 0x273f679c, 0x2d675a5d, 0x2ba42229, 0xcae6c229, + 0x9dbde424, 0x91488ee3, 0xe9769884, 0x55ae503d, 0xd034496d, 0x7483b5f6, + 0x4eda16b6, 0x62909b88, 0x8e35a242, 0x12cfd0dd, 0x92adb26b, 0x49eab108, + 0xc848d9a1, 0xeec4f1b0, 0xf0b7e5a6, 0xafad095f, 0x425cf5a4, 0xc1d334ee, + 0x293fa0e2, 0xc9089874, 0x9c709b36, 0xc3211578, 0xac39090b, 0x34432e25, + 0x8be0bb21, 0x89ac8411, 0xe399c472, 0xb10f1e60, 0xf196fed1, 0x4258f7f4, + 0x5b891a6a, 0x6cd5f3a2, 0xf423adda, 0x76847277, 0x6524224a, 0xd6f384bb, + 0x2d2cdf6c, 0x5e67bfa0, 0x075fb5d8, 0xa19357df, 0x7ab3f461, 0xd03b8d89, + 0x7180cf62, 0xf61c7b49, 0x9654eb13, 0xbd70b884, 0xe9b7c6c3, 0x0e38b9ac, + 0xbff4a3ee, 0x079f4ab6, 0x5666cfec, 0x9b3577e3, 0xa64feeb6, 0x626a91f3, + 0xefc56fee, 0xe6c5dff6, 0xff89e8d7, 0x675864fb, 0xa2e75b2e, 0xc4baff5c, + 0x2aaad7fe, 0xdfb4cd73, 0x5b08f8da, 0xb38b6d0b, 0x7ac18738, 0x0f3aa78d, + 0x61918851, 0xa73a3ca7, 0x77febfd1, 0xd1848475, 0x58c3877e, 0x15b352ff, + 0x47563ae1, 0xcebbf85c, 0xe3a56395, 0x8e17ee1d, 0x49b9bde3, 0xa4e01e35, + 0x2773270d, 0x3793f9d3, 0xb454956d, 0xe6411b1e, 0x23d6023a, 0x5cc7bbd6, + 0x062e6156, 0x1c227438, 0x706936ea, 0x473a15fd, 0xff5cf2f6, 0x2acc5377, + 0xf4c0f79c, 0xfa5e74cf, 0x7c6fd3fb, 0x6ba9f884, 0xb06dec95, 0x748fd6de, + 0xac00f2d3, 0x7893533f, 0xf6102642, 0x3e7b33df, 0xefe959d2, 0xfc337613, + 0xa9deedd5, 0xaecb4059, 0x1a4ba352, 0x303c780c, 0xaeace807, 0x24c24f4d, + 0x06739fc0, 0xa74943c0, 0x78841e02, 0x42be81d3, 0xe80233e1, 0x3aaa08a8, + 0x67a47f77, 0xfa64e667, 0xdd346b7d, 0x8ee811bf, 0xd91883ed, 0xbec10fef, + 0xc7e902e2, 0xafe60cb9, 0x801db708, 0x28515173, 0xac085ad9, 0x23ee18f3, + 0x31c19cb6, 0x79953d70, 0x0ab3d6c1, 0x618b89e7, 0x378d12f3, 0xe713e61d, + 0xd64d4e2b, 0xff7f4292, 0xfa578e26, 0x4efd87bb, 0xfcf239fa, 0x6de256eb, + 0x75c259ab, 0x55a7a107, 0x53dacf80, 0xa7a30f1e, 0x93d00d4e, 0x8fa0bf58, + 0xc6693657, 0x56e39e07, 0x6bc70eb3, 0x1d706b35, 0xa27e00cf, 0xe765a968, + 0x065599f2, 0x198ff237, 0xf9488f63, 0xebf72f14, 0xabbe503c, 0xed0b5f9a, + 0xf9b326ef, 0x0f54aad7, 0xa3ed7d40, 0xf882d246, 0xf0093fb4, 0x123d303c, + 0xa55b52f1, 0x38e9eb73, 0xb126bf4f, 0x26e8cbba, 0xceb59ff4, 0x1fa10ba9, + 0xbdb30d89, 0x1e737804, 0xf5334dd2, 0x3d2b27a5, 0xfbfa56f6, 0xce763684, + 0xdb6a1e04, 0xdd015d18, 0x5c39bc23, 0xcb74f0fd, 0xc7c08dce, 0xa333289a, + 0x00274a07, 0x616d9aef, 0x3606b3e6, 0xe804b7d7, 0x37ab22d2, 0xcf9927b4, + 0x35ebf8e6, 0x83a00ff0, 0x8648c4ed, 0x75f075d2, 0xee72a1be, 0x19d43c02, + 0x14b587bc, 0xfa4f43b5, 0xa2875cf0, 0x5fa69adb, 0x843b380d, 0x47896590, + 0x55e714b0, 0x47ed8fdb, 0xc70eff7c, 0xd250cbfb, 0xba730ff1, 0xc36a29a9, + 0xb67358f3, 0x71b1cf11, 0xc667e33c, 0x4d7e7253, 0xbf7c13c8, 0x8a9c71eb, + 0x6ab1b688, 0x9f8af70a, 0x1216e64a, 0x912e5f9a, 0x8e8da388, 0x83a6c5f7, + 0xbe00f391, 0xe355bf57, 0x7ed8c37e, 0xd0fe704f, 0x1c028db5, 0x4751bde9, + 0x46f7ec82, 0xe39e23c7, 0x86bde012, 0x7b6bbec3, 0x513f88f9, 0x8b6d717a, + 0xbdff01b2, 0xc3ca7db8, 0xeeeba27f, 0x53625ada, 0x38b4d903, 0x717c7e90, + 0x942db661, 0x64d5627e, 0xbef144bc, 0xe460edaa, 0xcbefda48, 0xd42e0c5f, + 0x7cdd7ed3, 0x535e179d, 0x1e5c0137, 0x9dc7657d, 0x96e35ed0, 0x778f8062, + 0x3fe9fb6d, 0x6f57cf81, 0x9308006d, 0xa3bc5f96, 0x54efd2f3, 0xf7eccdee, + 0xf866516d, 0x9f17cbee, 0xdde013bc, 0xed82d6d2, 0x8cdc5e17, 0xecaf03f5, + 0xe9bffb78, 0x488eb577, 0xe1777c1b, 0x9788fdb5, 0x0ec6a75a, 0xd7450dfb, + 0xcfdceccf, 0x849b64f8, 0x31548de7, 0x5ae825fe, 0xaf97efd0, 0x28111dcc, + 0x8ed56a1f, 0x4fbe0954, 0x925edbd0, 0x9ca05e50, 0x688c3778, 0xdffee8c2, + 0x9681a5a3, 0xfbe5ea15, 0x2ce780b5, 0xd908cfc6, 0xa7b5e42c, 0x6f7efe84, + 0x75e6c449, 0x3eaeee70, 0x26e78d98, 0x1d1dd182, 0x31c7c0c7, 0x434438c0, + 0x0fbeb0ec, 0xb2db6fd3, 0xa547ce8e, 0x924efb34, 0x47779c70, 0xce05bedf, + 0x8c2f58bd, 0xda0f3937, 0x9e41532b, 0xf2d7df88, 0x670dae75, 0xe722edf2, + 0xc6653537, 0x7c5e50b5, 0xf00aac35, 0x0ef3af53, 0x72fc00b0, 0x5b471d19, + 0x6daebf18, 0x37adae5b, 0xe71c7f62, 0xa0a7ca13, 0xe9e7a3cc, 0xf49f3d1c, + 0x0edfadab, 0xc97ef981, 0x193864f8, 0x3e98fb0e, 0xf0048ceb, 0xd46dc88b, + 0x7f5c20d6, 0x9629dac1, 0xae87db02, 0x4947e760, 0x2316b9b7, 0xb73b1b87, + 0x532bbbc9, 0xf4b7c8ad, 0xfa01feb6, 0xb3b57253, 0xbf7f44c5, 0xa6d3857b, + 0xe6f774a6, 0x536363f9, 0x1c95fd68, 0xabd20869, 0xd8f2625a, 0xea79c465, + 0xe7c8ca9a, 0x2d23bd74, 0x9bc75cec, 0x428ee689, 0x342a9e3f, 0xf8446344, + 0xd5af90fb, 0x7af2e5ad, 0x31275b2b, 0x98a7d2f8, 0x8ef19fb0, 0x683aff68, + 0xeb11a33f, 0xf2fbf4be, 0xaaba3e40, 0x755a3e50, 0x820bdeb8, 0xfe57117f, + 0x7f3f3cec, 0x139b7aa0, 0x475e35e8, 0x8fe3234b, 0xfbfc7495, 0x9695a52c, + 0x1f197f38, 0x7095dace, 0x74ed0f5a, 0x762dd79c, 0x8b6c8efc, 0x50afc991, + 0xe39eb07c, 0xbbc919ff, 0xb5cce818, 0x740ccc37, 0x77a77f5d, 0x5c1f2040, + 0xb07c616b, 0xf74dd39b, 0xef2f465e, 0xd82e54aa, 0x6e5bbbdf, 0xa8740cdf, + 0xff03c794, 0x8695762b, 0x2edc9b8e, 0xc92f0199, 0xf0cb269b, 0x55baf547, + 0xe5d657a0, 0x5f814348, 0x7fcbed48, 0xd7ad1b75, 0xbd41bc53, 0x9f3f377e, + 0xef854f54, 0x172bdbeb, 0xb1297cc2, 0x12d4d977, 0x536347ea, 0x96bebd68, + 0x7ff9c314, 0x37becd26, 0x9121f705, 0x4f20ac97, 0xf20d5ea9, 0xf50f2e34, + 0x56e77af1, 0x8e49bfd4, 0x85bdcb8e, 0x27d7afa8, 0xf9c1b4ce, 0xf627c3ea, + 0xaf7d42ae, 0x0b6e1ade, 0x684fdfa3, 0xfa601e97, 0xf5b0918e, 0x4fa87648, + 0xc3748f70, 0xf8092e7a, 0x39db5288, 0xdeefe607, 0xda2e27a3, 0x71dedefe, + 0xbd05cf28, 0xa3d75e98, 0x98d68f5c, 0x2fcbd025, 0xe7c9db36, 0x65982554, + 0x05bc22b1, 0x67b66b3c, 0x5c9ce0aa, 0x9ff0ede2, 0x43cb9e35, 0x42dd69fa, + 0x2d67d20f, 0xf563dbd7, 0x030782f6, 0x28f427f0, 0x82fc1d25, 0xa6f27fd3, + 0x621c1243, 0xaeee7e25, 0xba069e26, 0xa937bbbe, 0xa8f9253c, 0x7c8fdd5f, + 0x6c8e957f, 0xb78efa91, 0x8a8bf383, 0xf0014718, 0x46e98ac9, 0xaa7f205b, + 0xc2abb708, 0x423cf402, 0xfa2a451c, 0x1378f9dd, 0xd875ffc2, 0xacbd1077, + 0x63967fb7, 0x22bbc02b, 0xa7ed0c21, 0xf95d5a7b, 0x5d6d1fa4, 0xe7055e15, + 0x2363f292, 0xed334df2, 0xdf8bbf4f, 0xe445f232, 0xd705a4b3, 0x6662d9b5, + 0x8a38c4e3, 0x64b5811a, 0x39305639, 0xdb05b266, 0x3f7c7dcf, 0x29cfa607, + 0x4c9d0150, 0xf4f4da35, 0x92dfa7bb, 0xb8dd23e6, 0xf384c0a8, 0xec715ce2, + 0xd8af662e, 0x5388ee80, 0x7d56fa83, 0x9c1dc3a3, 0xd71d18ae, 0xf40bfd53, + 0x88574a70, 0x2676fab7, 0xddb8227f, 0x50227c07, 0x4ae715df, 0xd7e05b9c, + 0xde823740, 0xd1bdb9c4, 0xcfcdd9f3, 0x7fdd3747, 0xde9a7d20, 0x6eb97464, + 0xda14b595, 0x731055d7, 0xb4aabda0, 0xf870ac83, 0x62fadd68, 0x11c61b84, + 0xe2ce2e7c, 0xa8fc0b38, 0x35d1cb7e, 0x2f9cb648, 0xf8f9bfd5, 0x67e96b80, + 0xcf1b0d06, 0x07708ee0, 0x82818fd2, 0xa58854db, 0x4473f80b, 0x12df5c93, + 0xdcb93fe5, 0x65facef8, 0x7c01a4ae, 0xa8f2fd09, 0x0b4ff9ca, 0x45292fd7, + 0xa626f490, 0xaf03c65f, 0x25b07e07, 0x24fc0dc2, 0x77389e3e, 0x97cf5905, + 0xbc099cfc, 0x3e233b0a, 0x1c9f7d92, 0x5324f4cd, 0x8b2efb34, 0x0bf60197, + 0xcaab079e, 0x43a88679, 0x8fd101cb, 0xc5db0bae, 0x1fed7a7a, 0xfc6f5b03, + 0xacb603a3, 0xffa7c00b, 0x0856dd5c, 0xef5ace78, 0xfa37ccd1, 0x48f211e7, + 0x7eb03f49, 0x9fb05b90, 0xdfd0dcca, 0x76e7eeb5, 0xcb9e829c, 0x633af9f8, + 0xf2ddf821, 0x68eae718, 0x45159f5a, 0xff1431ec, 0x23d1deb3, 0xdf1c913d, + 0x6b43b000, 0x8fa5c434, 0xdd6abc06, 0xfe3c00de, 0xfb40f00d, 0x2e0c98f5, + 0x2d073d35, 0x68e2ce31, 0x8cab9e3a, 0xc7a03cd8, 0x0bf29f7e, 0x53c49738, + 0x81a4fc0c, 0x8e012378, 0x239c982f, 0x757abbe0, 0xa9d43a67, 0xf30f931d, + 0xecc11b3c, 0xb551df27, 0xc785207b, 0x47f78365, 0x2e7ae923, 0xb9b2c8af, + 0xdfa738e8, 0xdf9efdfc, 0xed2fafd3, 0x19cd22f9, 0x0deb57c0, 0xc626832a, + 0x4896ef5f, 0xbe105b55, 0xc99a233b, 0x09dbccd3, 0x68b804e9, 0xaeb7a87c, + 0x8027b308, 0xbec567df, 0xe96b84d2, 0xca570df3, 0x9e603b88, 0xfa1fda06, + 0x4b195c35, 0x8c8243dc, 0xf903c74b, 0x992570d0, 0x3cd862b8, 0x315437c0, + 0xfbf8ce4c, 0xed1713a7, 0xaa455a7f, 0xe7fbad83, 0xbb5f0cd1, 0xac1f1909, + 0xd7df077d, 0xfcec7eee, 0x6e4836fa, 0xaf160fb0, 0x14d47930, 0xcfe98ba4, + 0x362d2fa0, 0x48aa3cbb, 0x8f943fe0, 0x4e34460d, 0x647b5035, 0xf467971e, + 0xa028cd3b, 0xcf199757, 0xc39f93a1, 0x7defed79, 0xc589fe03, 0x4518621a, + 0xb06f99c7, 0xbfa14e1d, 0x2638c9ff, 0xc2c4c412, 0x83c4a687, 0xd5984b1c, + 0xbd2273a8, 0x7e83318d, 0xea51912a, 0xa5ae236f, 0x8f50690f, 0x74a27a45, + 0xac718ba0, 0x3a00ba04, 0xf5983a04, 0xe26be320, 0x5e7e5cfb, 0x59f87495, + 0x8ecf7c08, 0xf181cb29, 0x358e512c, 0x5e0fdf48, 0x6ebff192, 0xf3f2fbc9, + 0x4dcba740, 0xdf4897b6, 0x70e13ffe, 0xd4e829ef, 0x2e5a2c91, 0xea3a47ff, + 0x9def1da3, 0x675d3e04, 0xa0d47a30, 0x76d6ec57, 0x283ec579, 0xd945060e, + 0xf073c29f, 0x739651c3, 0x02482694, 0xe3d71dfd, 0x03bf00dc, 0x0363db9d, + 0x151adce9, 0xeba2740d, 0x10c38bc5, 0x490bc7ef, 0xd1f1c935, 0x31f11471, + 0x01d760df, 0x1dd817dc, 0x5159beb8, 0x0cb3629e, 0x6feab9fe, 0xf871bf6f, + 0xf9e7e7af, 0x61d28eb4, 0x83b07390, 0xc31543c3, 0x64e9c6f8, 0xd3a7af46, + 0x282ef549, 0xf692d107, 0xd78fdd3b, 0x007d790b, 0xd59e2eff, 0x797e700f, + 0xa77d9f3a, 0x3e33e79c, 0x7b18eccf, 0xf68bc007, 0x4f00e8f3, 0x41b9876f, + 0xeafca64f, 0x8f13a700, 0x155f9025, 0x1f0006f9, 0xf8a629ec, 0x5759fba2, + 0x013f4bea, 0xde9f64fc, 0x7d7ac5bc, 0xd7c27dbc, 0x97e59df5, 0xa1afca8d, + 0x49f5f932, 0x885f9334, 0x1d12ba27, 0x11b2abd3, 0xea17483f, 0x5bcfc71b, + 0xf4ee0c61, 0x51a3789c, 0x1cf2794e, 0xaffd7c01, 0x8f826e1c, 0xe3970e9c, + 0xf7f7c5d1, 0xeb473f25, 0xde4ccda3, 0x30e97cd9, 0xe0e8e9ce, 0xc7ed5f78, + 0x239e3747, 0x0c4e6fbd, 0xa8fbb7a5, 0x442ba0be, 0xf587ac7c, 0x734bb1f4, + 0x73857f3d, 0x8980f0dc, 0x22bbdc80, 0xa1f22be6, 0x97ca937f, 0x4e8f0674, + 0x87afd41d, 0x27d1f01f, 0xd4951a51, 0xd5a02274, 0x71c5621c, 0x9e3328c8, + 0x3e5eb0b3, 0xf38989a2, 0xef3947c3, 0xc8af8e29, 0x0e734918, 0x36236af0, + 0xa3e737e8, 0x29b34caf, 0x1b325c9d, 0xcf2a2a5c, 0xd19caaae, 0x79efe031, + 0xbbea28f8, 0x019e74a7, 0xed20c6ad, 0xcf0bcf3a, 0xb9f6fe4a, 0x74bb533f, + 0xeeef1cf4, 0x74c9faec, 0xa7677fba, 0xd8e706da, 0x1faff2b9, 0xa5bd030c, + 0x4feb6b53, 0xd7aeae50, 0x991a3ec0, 0x254a767e, 0xefc5ff87, 0xc187edc9, + 0x540f0c31, 0x133a409f, 0x5854e0fc, 0xeba13e64, 0xfd3c4259, 0x51e7ee81, + 0xef4a17c3, 0x10f725f2, 0x181627ca, 0x7dfd22a7, 0xe85dc0f1, 0x9c485e6f, + 0xb9e62fc8, 0xe40c7fb4, 0xcad60ba3, 0xe55a8beb, 0xc9cf25f5, 0xdffebdeb, + 0x4effb972, 0x98635394, 0x0ba8ba5c, 0x863e3ede, 0x9777e3d1, 0xee5083c7, + 0xf9c795f6, 0xe395a728, 0xaee5c3de, 0x1e42cb90, 0x84315c37, 0xe388c718, + 0x7c1c5c5c, 0xf5f1f7fd, 0xa3315c37, 0x3fdbef7c, 0xd53ae516, 0x813bf0c4, + 0x892b86cf, 0x0ba8bbf8, 0x2fdfd07d, 0x8ca3c715, 0xc22e7cdf, 0xdf85fe7f, + 0x19efd057, 0xd0921889, 0xfb927b5e, 0xe0f9cc6b, 0xf2033a87, 0x39d9e29d, + 0xa5edbc8e, 0x48f79c4b, 0x3f4d00d2, 0xf72b7d3f, 0x82e0e941, 0xd59f8037, + 0x716298c6, 0x3064c1de, 0x73e82bcc, 0x5115c3ce, 0xb0ffdf20, 0x50213cb2, + 0x6bf5eaff, 0x447d98e8, 0xaf265188, 0xcd9e4288, 0x2bf2a76b, 0x0188f51f, + 0xef9f9740, 0xb9f4819b, 0x81e2d890, 0xe9f67b6e, 0xf7ffd1d3, 0x5898e51d, + 0x3cd714cf, 0xa92fd32d, 0x65e7a090, 0x4a7f9f32, 0x5467d307, 0xf516bb06, + 0x9ab13b15, 0x64a4d1e3, 0x130a96f2, 0x168fad0d, 0x5a1e2075, 0x2337c51f, + 0xfeba7f41, 0xf324bcd1, 0x9e70899d, 0x1aaf30f4, 0x113b90d8, 0x361196ca, + 0x9225942b, 0xc1d6c343, 0x34963cf0, 0x2af7c2a6, 0xf4cd5783, 0x7882ba25, + 0x63e62fe8, 0xafaf1375, 0xce797a9e, 0x68ddf822, 0xe3af73c2, 0xf05578eb, + 0xc031032f, 0xcf46f5be, 0xe24f1897, 0x8accaba5, 0x1faba876, 0x9c3fbb41, + 0xd79811b4, 0x82e4bc68, 0x59899acd, 0xf9987a82, 0x0211e7b2, 0x52e8cd7c, + 0xb6be460d, 0xf49af913, 0x7be062fe, 0x03e68f94, 0xaed90d1f, 0x2efea0f1, + 0x5f3452f8, 0x4be70b5f, 0x21c18449, 0xbe71d886, 0x23169b1f, 0xae338a5f, + 0x86ffa090, 0x97c8f1c8, 0xb4f001e2, 0x46bc663d, 0x1ce267c6, 0x95427af2, + 0x94e49ebc, 0x14e40dd7, 0xe3c903ca, 0x0636fc48, 0xf01c91ed, 0xd8cb683b, + 0xce1e99f9, 0xeb0dd5d6, 0x1139fba3, 0x937ffaa3, 0xbb7245fb, 0x475a3eb5, + 0x4f150fd0, 0xa8c1e62d, 0x61889c07, 0x2e67c07a, 0x90fb5768, 0xfee09eff, + 0x1de3a983, 0xdf8a1a15, 0x07c972fb, 0x8f9e5a76, 0xef869e73, 0xac691c67, + 0xaaf5a5ab, 0x879e49f7, 0xe6250596, 0x9f14ed9a, 0x6c9b666b, 0x1afad28f, + 0x576d2313, 0x22f51e9c, 0xb698f202, 0xa225566f, 0xfc01a3ff, 0x6bff74ad, + 0x3a006f40, 0x5ed04fe8, 0x1ac87aa6, 0x79b7ed03, 0xcebcd99d, 0xdf2a7e0a, + 0xfa07f058, 0x16f31116, 0x5c3ce412, 0xe28ce7a5, 0x53a845f5, 0xbe9c4a3c, + 0xe15befc4, 0x2f562cf7, 0x1e760a19, 0x83ab2ffb, 0xcff02832, 0xfddce8e4, + 0xa51d3d61, 0xcf5a38da, 0x7f43631a, 0x617ce131, 0x9f879898, 0x73fe91bb, + 0xbc05ed80, 0x64f1dd9e, 0x978c3c45, 0xca7e504b, 0xd62c0dce, 0xca187f4c, + 0x73c0edcc, 0xfff1077b, 0xfb95e307, 0x8dbc47c7, 0xceef6de1, 0x61d8f166, + 0x387ecf1a, 0x597923d7, 0x8774cbc0, 0xa511fe54, 0xed8342d7, 0x802b1ee0, + 0x7d86a1d4, 0xde3f350f, 0x708ff302, 0x7c03147c, 0xf281946c, 0x0cb65a03, + 0x59ccd9b7, 0xf8156fb8, 0x42b5ba97, 0x40a3d91e, 0x92ad4dae, 0x7d00ff5c, + 0xe11a8c60, 0xe53197f3, 0x7794d751, 0x3ab22a4d, 0xd6acce50, 0xf3f7fcc9, + 0x65ff9963, 0xecd8ec5c, 0x2c079458, 0x962837de, 0xdba009f2, 0x7c03921c, + 0xe71ce022, 0xa55d77c3, 0xce750ebf, 0x9cfcede5, 0xd10fb34f, 0xcfcb3ea2, + 0x8eabe0bb, 0x669e7670, 0x74069210, 0x22349532, 0xba563dff, 0x7dfbcf14, + 0x7805a5c4, 0xe0c65a7d, 0x653dd62c, 0x98af5cbc, 0xa7d790e6, 0x0ef52957, + 0x7fbc7b3a, 0x794e19de, 0x3fa164fb, 0x8feb978e, 0x55cffeb3, 0x84b5ca0b, + 0xcdbeeb97, 0x54f83f00, 0x03f81c6d, 0xfa33243b, 0x8c243bc1, 0x195434fb, + 0x6c6fe0dc, 0x5bf16768, 0xefd05ab2, 0x7e80c7bc, 0x31da5653, 0xbedf571e, + 0x80145a53, 0xb75a94af, 0x207cfc04, 0xc8275185, 0x9c77ae2f, 0x83f7bad0, + 0x52c4fcbf, 0x9e74e24a, 0xe1df3c83, 0x143be410, 0x34cee9fa, 0x28fff987, + 0x3c7fa315, 0x03611cd5, 0xaaad79bd, 0x6b85fd10, 0xbf324d23, 0xf655baee, + 0xf84ef80a, 0xcafe4509, 0x6c693d74, 0x43a7fe63, 0xcc8d8cc8, 0x76e6e43f, + 0xd32c7672, 0x6afb68cb, 0xce294ff4, 0x410c5c6d, 0x333711b9, 0x5580fd07, + 0xe045051d, 0x07f2a587, 0xb1d9d3fd, 0xe55fec56, 0xd5ff402c, 0x1819c6dd, + 0xd8e86817, 0xf46859ac, 0x82c3cfd3, 0x044822ee, 0x5faf5dd0, 0xfd1e9768, + 0x8e555742, 0xd57d001f, 0x44f93cea, 0x7bf8974e, 0x84b2f928, 0xe65b5de3, + 0xc288b198, 0x9d03e7a5, 0xaa3bec0d, 0x5ebe2040, 0xfe416bdb, 0x904c99a7, + 0x252eafcf, 0x367b27c8, 0x17c8bf33, 0x687bea96, 0xb52d590b, 0x8eee1f22, + 0x5ff08b1e, 0x7a843c66, 0x4a26f548, 0x7e7c014f, 0xbd7956d9, 0xb2fb3086, + 0xba1f7b76, 0xf8247e44, 0x796efd55, 0xe4cd923f, 0xb9c38db7, 0x42d1f380, + 0x054a6d87, 0x96cabd2c, 0x6244ecc5, 0xfc5e3e07, 0x0bfb8ebe, 0x85cf9967, + 0x597b8b01, 0xd41e96ba, 0x66af3a63, 0xcdf198e7, 0x928f3e62, 0xfd73179f, + 0x9d0d4ee7, 0xcfafd0a7, 0x3f561314, 0x2750eaa4, 0x2debfcaa, 0x1e84fde2, + 0xc0a9f825, 0x4270e957, 0x3b3a5386, 0x8fddf020, 0xd37c03f4, 0x25ce91f1, + 0xc68954c8, 0xef605df1, 0x51f3e48c, 0x5d01707a, 0x370654b9, 0xa91aefd0, + 0x0188e511, 0xae5a65f4, 0x57c89c93, 0xa976a8df, 0x4823de01, 0x327b94e3, + 0x4676bf81, 0x9d289c00, 0x9fa40e1c, 0xdf49e216, 0x08e8c929, 0xbf2cbbdb, + 0x82474a0e, 0x653e7bef, 0xba04c0fa, 0x02a71863, 0x3cb40902, 0x3a412d24, + 0x5a7c6719, 0xad7ffd03, 0x78d3f662, 0xfac0d6e2, 0xfc72cc2a, 0xd7944b8f, + 0xa1f6b2ef, 0xdbff8c0f, 0xe4273c39, 0x82eddbc8, 0xdf39116f, 0x995724ca, + 0xe1f8fb7d, 0x8eaec087, 0x10392268, 0x9d1aa3df, 0xf8907fad, 0x2dec4f49, + 0xc4f7c3f7, 0xf7c3f106, 0xafbeb968, 0xc3faafa0, 0x27ace617, 0xe7143a7e, + 0xa8d20ee1, 0x9370a44e, 0x8ef161de, 0x28fe803b, 0x90370c3d, 0x486fd05c, + 0x8973f311, 0x6de821f3, 0xc545af28, 0x20cafa71, 0xa35f4019, 0xbfd0c3db, + 0x19d00779, 0x3e02dba5, 0x42df90ae, 0xde196f2f, 0xa532ae87, 0x78e3942c, + 0x1f1c84de, 0x7f9ed922, 0x72f41324, 0x01e5ea17, 0x87131474, 0x11d288fc, + 0x723ecf9e, 0xa0aede52, 0xe3ef8133, 0x252cdf5c, 0x535f488d, 0x3d2c5655, + 0x2f4ecc95, 0x40d54e37, 0x3326f7ff, 0x74031b3a, 0xcbdf0598, 0x20dca4e9, + 0x90e92baf, 0x9c0aa8ce, 0xa1974957, 0xe8032ce8, 0x98c7c84c, 0xa8d9d3eb, + 0x674e5bb8, 0x826ee2a3, 0xdadf04ce, 0x372e6619, 0x96aedc82, 0xf90c0e50, + 0xea05bb20, 0x5132eb03, 0xb169dccf, 0x46f6c41d, 0x69d45ed6, 0x42de4357, + 0x9ede0ad6, 0x7a8728e9, 0xa76d1343, 0x671f1743, 0x2bd90d79, 0xa3c17b59, + 0xe04d078d, 0xfeb172c7, 0x46b97e6f, 0xdddb491d, 0xd2ff786b, 0x37a872d6, + 0xbffd65ac, 0x60c87880, 0xb77287c8, 0xadb7efc0, 0xb331b4cf, 0x25b7e994, + 0xa53bbf7c, 0x5fb1075d, 0xe4b7eb2b, 0xa09c21b0, 0xd6f4ccfd, 0x4b3ef93b, + 0xc67db136, 0x78f77e7e, 0x458ba52b, 0x5fea173e, 0x43b554e7, 0xb085af91, + 0xd6a54b3f, 0x51c72854, 0xdda50bb6, 0xeeab5b60, 0x5b61e2c7, 0x714d14e8, + 0xe2217fcc, 0xaeaf1048, 0x9a67d00c, 0x245d98e2, 0x268f8bbe, 0x8d911fa8, + 0x4437b426, 0x2cf3cb9c, 0x850ec091, 0x50bf423d, 0x5971af71, 0x8c2fa88d, + 0x2ef110cb, 0x9d3e66af, 0xafdbe0b7, 0xaff306c6, 0x3d31c734, 0xbf8f3ce5, + 0xddabdf8b, 0x13bf2e2c, 0xe0192488, 0x7057f87a, 0x3c42775e, 0x1727098b, + 0x65780e19, 0x727e27f5, 0x6a5add60, 0x35512fbc, 0xcc205c6a, 0x23cc25d2, + 0x3c49d49a, 0xd77d9151, 0x3c434e3f, 0x8407963a, 0xa2dc5feb, 0xc2203cc3, + 0xc134d9f9, 0xc7f5469e, 0xe3953df3, 0x4fe0a369, 0xe010c843, 0xde38d34f, + 0x3d5033ee, 0xab72e518, 0x5e37c156, 0x21b1be40, 0x6f2dfea4, 0x6a95f057, + 0xae62ef3e, 0x3e252f77, 0x49ce4bd4, 0x6fcf2c6e, 0x8d777a60, 0x35ea38f1, + 0x9e991b3d, 0xa8bc4b59, 0xcb752cf7, 0x36cd42f9, 0x4daebd79, 0x97686f5e, + 0x5cf27bd7, 0x86cf4f38, 0x4fe0a1ba, 0x03ee7eab, 0x0b56dff4, 0xf396e2fe, + 0x32564217, 0x20ecf2fe, 0xed28e7f4, 0xeef76a70, 0xa1f8c38b, 0xe82d6679, + 0x58227305, 0x98da82be, 0x64c07c87, 0x14383b40, 0x39da501f, 0x8320ef42, + 0x2a0f9f82, 0xcf000c69, 0xc6777800, 0x921edb5d, 0x21f02bb7, 0x39fb91ec, + 0x7c50a63e, 0x93bf3cc3, 0x1cf768ec, 0x31f0ca5b, 0xe902b8cd, 0x0c65d3e1, + 0xba2ec21f, 0xaec83b79, 0x90762efe, 0xce2e5fd2, 0xb09a7755, 0x8768ad4f, + 0x29800036, 0xf37bae9f, 0x9fa00bc4, 0x358eef8a, 0xc04d3893, 0x2a563c79, + 0x9e4e8ff7, 0xe4287a70, 0x2b0f6e3b, 0x93e00bfb, 0xffa1c474, 0xd8412eb0, + 0xe9fc6c45, 0xf2eaff3c, 0xe8a8ccca, 0x89bdd96b, 0x009a619d, 0xc68f6cff, + 0x4e760917, 0xe70955cf, 0x4825ba85, 0xffdfc91c, 0x87c41878, 0xf9dfcefb, + 0x3f03dfbd, 0xe302217b, 0x3257977f, 0xa6f2ef7b, 0x7c079881, 0x0549c791, + 0xde1c961c, 0xce17b6f6, 0x1c31d35b, 0x7f7246af, 0x1db687bd, 0xe2633bd5, + 0x3caa0e41, 0x2c57463a, 0x1df6219e, 0x42e96fda, 0xc03ba6fe, 0x0a4face4, + 0xfa4ebcc7, 0xb8c080fb, 0xe302524e, 0x7e0e42c3, 0x2d6afdcc, 0x17d8a5bd, + 0xc4b42bf3, 0x3d60b3d8, 0xc1bac31f, 0x1691f43f, 0xbbf835f9, 0xa548ce21, + 0xee89492e, 0xa3881ebb, 0x3881bd6f, 0xc99e2dba, 0xf694a583, 0x62cd3f30, + 0xcef9802f, 0x79e1b8f3, 0x1f3a771e, 0x2350e2c9, 0x5f1f19e3, 0xe44dfbca, + 0xf110f9e5, 0xd9ddf16e, 0x35618366, 0x9b1feb5d, 0x36756189, 0xf567f125, + 0x339f988d, 0x67abed8b, 0x39f305af, 0xf8aabf45, 0x8eb0a5d2, 0x18c71621, + 0x9eb61728, 0xa9fa05d1, 0xa83f607b, 0xf57db04f, 0xcc52b184, 0xb95f1557, + 0x3ce01e34, 0xec788bc3, 0x75108fad, 0x33df8e07, 0xc24ff19a, 0xfc7510fd, + 0x5b8a85fc, 0xa55e2f5d, 0xe6cefb8c, 0xefb889e3, 0x9914362c, 0x73bee3cd, + 0x0a4d640c, 0x91db9f6d, 0x48d5ecc0, 0xdc5900d7, 0x537115d7, 0x87417771, + 0xb8fe693d, 0x889bc6e9, 0xfe20fe9b, 0x7f4dc796, 0x6e241f10, 0xbfa78caa, + 0xb6417a0e, 0x980f0f1f, 0xd42adc19, 0xcfe0e5b5, 0x6090bcbc, 0xe901731e, + 0xd028ecf7, 0x89688eb3, 0x137c8adb, 0xe1ebe3f5, 0x22a1ce2d, 0x39df9956, + 0xd603589c, 0x968ce49f, 0x0ee351d5, 0xa94c0fc8, 0x4ff5964e, 0xfb27ec6b, + 0x9069a33e, 0x55d33dac, 0xad67ab28, 0x7df643bd, 0x5932d6ff, 0x7773e07d, + 0xcdbfbecb, 0xbf56593d, 0x7e40ff0c, 0x767e46a6, 0x65fbb6fb, 0x1d1c97fd, + 0xddca7e82, 0x9712fe5c, 0x287733bd, 0xfac0a373, 0xcbe6daf3, 0xc91e23c6, + 0x45f6d123, 0x23174f1c, 0x85893dd9, 0x3f9fcc9d, 0x6c997db8, 0x2d751afc, + 0x47194fe2, 0xc3be242c, 0x96ea3f98, 0x37d21e6c, 0x7db4b8ae, 0x9ebbf633, + 0xfafc227e, 0xb14de207, 0x24c91748, 0x92b3d199, 0x70bd8c1e, 0x05197b80, + 0xa3b3c064, 0x20f4648a, 0x1b851bc3, 0x6f2ea9fa, 0xd1de6137, 0x700ba392, + 0x3944fa3d, 0xe559843d, 0x239110f4, 0x4d9307a7, 0xe1a8ff8e, 0xe12bfc72, + 0xe9cbb16d, 0xffe97881, 0xcc7780d7, 0xfcbd3978, 0x1ddce0ab, 0x1c81e3cf, + 0xd90e43be, 0x37088c5b, 0xec243f96, 0xa3b73d7b, 0xcfdcac49, 0x7fa7f425, + 0x1578f3c6, 0xd5f8471f, 0xb42e48d7, 0x66e37bcb, 0x9ee93dc3, 0x1bcfb04c, + 0x38f3f309, 0x41c50954, 0x7bf884fd, 0x80a13f28, 0x67ae54eb, 0xfa3b10d6, + 0xfc4117a5, 0x2b67969b, 0x677fa297, 0x1d69f189, 0x9938bff4, 0xc4d563e9, + 0x7afdfc8d, 0xdc256ff1, 0x01252f40, 0x1c25547e, 0x63c90ea5, 0xe5c33e02, + 0x10e93240, 0xf2c9c072, 0x12fee5f8, 0x00b2f102, 0x5ef4253e, 0x9f80be31, + 0x7c625fe0, 0xe059f83d, 0x19f8281c, 0x45e391c9, 0x63815fe9, 0x181a1860, + 0xc092b12f, 0xafd28af8, 0x50a7f7e2, 0xa7ce92bb, 0x216cc8ce, 0xcc436f14, + 0x15d7f476, 0xf099ce93, 0xa0a7f0bb, 0xd236e17f, 0x29085feb, 0x8f13ae9f, + 0xbc92e29d, 0x8df667cf, 0x2eb88ac3, 0xbfe7c305, 0x49479da7, 0xe4f7c456, + 0x01c60737, 0x2ff5f51d, 0x45be4eda, 0x7cab51c7, 0x3f7e8131, 0x4f7f5fe1, + 0xee7ee2f2, 0x48c7f623, 0x4f519e80, 0xcccec6da, 0x952eff04, 0x3250918b, + 0x5769143f, 0xf41ad9ea, 0x4ee8aaff, 0x486bde80, 0xd3329c40, 0x75758edf, + 0xe68dfadf, 0xc13afcbb, 0x2cbd9dcc, 0xfe70935f, 0xd0c3ec27, 0x7d7c98f6, + 0x330b8c0b, 0x82fbfa25, 0xc0dc75c0, 0x037e453a, 0x7884e3dc, 0x9f2a26c6, + 0xb04bcf51, 0x17515ea2, 0x3b13ea7e, 0x99d4567c, 0x36d7a81e, 0x0301a8e8, + 0x7aebf8f6, 0x936c9716, 0x4c3fcbeb, 0xa12ef960, 0xa8f3c0e1, 0xf5cc7614, + 0x47911df4, 0x16e01135, 0x944b3eb0, 0x9f803fe3, 0x9ef49da4, 0xfefe5493, + 0xcc2eea15, 0xaedcbc13, 0xf54efbc6, 0x1fc85da3, 0xf1aaf7ea, 0xe8777508, + 0x756f3ef1, 0x93d441fb, 0x03299aba, 0x85c97aa2, 0xe6b33a66, 0xec57f01a, + 0x207d9437, 0x4c5e8df2, 0x9f33fce0, 0x2be607e4, 0x8af83e51, 0xdaf60f8c, + 0x4a79bdad, 0x93e304af, 0x28dcea15, 0x9bdae7b8, 0xa5f1a287, 0x8fc00e4f, + 0x720f1f72, 0x1a37e43b, 0x5d025b47, 0xd4ce99d7, 0x0abc6067, 0x64e1c775, + 0xc90acf80, 0x12b47106, 0xa87fbb3d, 0x35b72f57, 0x0375d806, 0x203b521f, + 0xc57a795e, 0xbf70d183, 0x503b8c59, 0x393de152, 0xf67d7642, 0x9f8822fd, + 0xa3adb2cd, 0x667ad9b5, 0x2f7e6657, 0xcf4593c2, 0x763a3bd7, 0xafdb4b3f, + 0x7dfef311, 0xe3fa3516, 0x0c64d562, 0xaf5885d0, 0x7e2857b8, 0x70cefb87, + 0x5efc4d7f, 0xf21be2d2, 0x071f2d00, 0xaff62cfa, 0x37dca4af, 0x87e8d1a4, + 0x6e9c7d7b, 0xdd45e80d, 0x443f2606, 0x6b31159e, 0x30ad7cf0, 0xaa75f3b0, + 0x3d9bb0bf, 0xeabfb026, 0x9851ecc3, 0x9a91f5e7, 0x17f95d80, 0x82ca3db3, + 0xdea2b3fb, 0xfaccc2b9, 0xde7cf375, 0xa1969f15, 0x12d7165d, 0x7ce8cf3c, + 0x6a9fb302, 0x7964a8af, 0x0f1ab546, 0x5ed50be6, 0x913e61d1, 0x148ffdf8, + 0xfe01ae0e, 0xd9f3fcfa, 0x0b5d6163, 0x7c0d6d88, 0x046d60bf, 0x21e80571, + 0x8958af22, 0x7c71efff, 0x44345bd7, 0xe7ef1833, 0xddf5ae3a, 0x0754ff5b, + 0x9d12efbd, 0x5c71cec8, 0xa5ebcb39, 0xe1c60576, 0x2585df94, 0x6cfc8a4a, + 0xecafde2f, 0x5bdb07cd, 0x61ae409a, 0xb15fd7e7, 0xebb3f2cb, 0x57e87f69, + 0x228c657f, 0x4b8f9b3f, 0xfd1ab3c7, 0xe0a16079, 0x6604bdff, 0x9e43d4df, + 0xdfc090d7, 0xe7f8fd19, 0x5b79e589, 0x7f3848de, 0xe3576f3f, 0x1f9fe3fd, + 0x12df8d51, 0x12c3dd64, 0xc506dc19, 0xdc5cf069, 0xcdf621ee, 0xdf17e641, + 0xe205fb89, 0x7d729c7e, 0x73bccbbb, 0xc6c3fd60, 0x72aeff30, 0xec89419c, + 0xddeeb13b, 0xf51f0cd1, 0x607c536f, 0x9fcb08fe, 0x5ded1ddd, 0x2cc0fc8c, + 0x8e7cf3c7, 0x7b77dde7, 0xcbbef1d3, 0x0e7ecc5d, 0xcd570f45, 0x4f8007ce, + 0x42374ed4, 0xaa19192e, 0x01cc9469, 0xf47aebe7, 0x4abb87e0, 0x70bed786, + 0xc57e21d7, 0xffdf42b8, 0xc63539f2, 0xc63cbff1, 0x1bb12dcf, 0xf77c80a5, + 0xebf3092f, 0xa12ad97f, 0x49df3f9e, 0x2fe51348, 0xa0d6b6f3, 0xa5f8b85e, + 0x03629821, 0x7ca4afbf, 0x21225e64, 0xfe72d277, 0x775c796a, 0x7e3efae1, + 0x7f281239, 0x94469117, 0x969f8b17, 0xeb26abf7, 0x837a0cff, 0x3e8cde32, + 0xcf176a4f, 0xf77ae44e, 0xf8143250, 0x7d2f03fd, 0x86b48ba5, 0x94f3ffa6, + 0x806b669f, 0xecb01aaf, 0xb963366a, 0x28bed13c, 0x39a5c291, 0x089d59d1, + 0x188f8cfe, 0x5ed72e3c, 0x2e00f266, 0x7e008e4f, 0xd33ca12d, 0xd8f164cf, + 0x723dc21f, 0x9ebd0f0a, 0xd47575c9, 0x7093c9ca, 0xff846e95, 0x8e79af30, + 0x2d8de505, 0xf63de811, 0x63c6e317, 0x222fd75e, 0x75bf00ec, 0xc197eea5, + 0x556eb08f, 0x0d71fa38, 0xce0f167a, 0x82aa5eda, 0xedb703fb, 0x1f83f696, + 0x5563a1a3, 0x37efdc0e, 0x8f31c35a, 0x5e63aa20, 0x6c639326, 0xc716d89e, + 0x2c67c04e, 0xeba36bdc, 0x4ee9975a, 0xe99a7c64, 0xf61cf539, 0x3ff5923d, + 0xebb39ee1, 0x21ef1aa8, 0xbcb0d65e, 0xe18441fa, 0xc12be455, 0x5cfa81dc, + 0x241b8517, 0x939ef5d5, 0x8da3c936, 0x301c77c4, 0xa8fb50ce, 0xc8267e27, + 0x30699f9b, 0xaebbd34e, 0x20ca9277, 0xcce4231e, 0xfcccc94c, 0x9d5f5c42, + 0x2c7fc441, 0xe9c5539e, 0x53d70661, 0xf8304667, 0x74b627ce, 0x81bf77e8, + 0xd1e8aa44, 0x56de5999, 0xd1abfb8c, 0x116f405a, 0x7ad08971, 0x4e7f7042, + 0x7626cbfd, 0x0df2521f, 0x682e4180, 0x79d6b909, 0x43f9c3db, 0x97e600fd, + 0x0ec4d925, 0xb7fab071, 0xf8866e07, 0xc59c3e87, 0x321f2959, 0xef277bc0, + 0xfba63c82, 0x1856fa5e, 0xdc42bf7b, 0x0bdb3687, 0xc3617ee0, 0xcc42d4e4, + 0xc3e9385f, 0xb5ba0877, 0xaf3c74de, 0x5448bf94, 0x38987e06, 0xa50d1eef, + 0xaa64faf3, 0x3ffad16f, 0xbd581b12, 0x8ab1779f, 0x3d2407d6, 0xbc83eace, + 0x4b6ea0e7, 0x0d1efa7a, 0xf42b63dc, 0xfad3562e, 0xac2da484, 0x324b060e, + 0xcfd26f85, 0xf1d171ee, 0x3eb8582f, 0x3de2f363, 0x0737fad0, 0x84fd02aa, + 0x7f189263, 0xbec610ba, 0xe64990bb, 0xe778064e, 0x873eff04, 0x5cf42f7f, + 0x9fd15fb1, 0xf7ef0624, 0x4b7b9719, 0x92d03df9, 0x8c36b208, 0x915c95c5, + 0x3a870f14, 0xec5c6206, 0xcb346240, 0xf17b35df, 0x8e31109d, 0x4f18a780, + 0xe40cbbcc, 0xc9f311b0, 0xe2f964aa, 0x79d27e5c, 0xd93ce356, 0x727f7676, + 0xe0016a72, 0xc34de28f, 0xbc01a6f1, 0x30d77b89, 0xf91f25ae, 0x43f010fd, + 0xbf4aba1f, 0x5baff4cf, 0x38572749, 0x616d2c9d, 0x259f40f1, 0x24a9e90b, + 0x513bbf82, 0x04c7df24, 0x4931bf0e, 0x5ecfb616, 0x384824bc, 0x63870b4f, + 0xe4c077aa, 0x77df9bbc, 0xcf5b1278, 0x0077dead, 0x7ef0ecbe, 0xdbf6a1c4, + 0x30fdb0b6, 0x473d017c, 0xa4f75ea3, 0xab0bbc6c, 0xd387fd14, 0x8dfb0903, + 0x3ffec2ce, 0x100defe4, 0x5fb7a5b2, 0x3fd33e66, 0xf7152f41, 0x4eeb89e4, + 0xed17e812, 0xc6df0fbd, 0xf7faadee, 0xdf114f79, 0xd3ef99a7, 0x96e9f6cc, + 0xee392bd1, 0xea6a9f4b, 0xf0bdc74b, 0xb72f1def, 0x3b278f90, 0x83c6c1e7, + 0x2f0a1d73, 0x316e93a3, 0x2a758a3d, 0x670bd9e0, 0x3c04fac5, 0xbf637ce1, + 0x8a5d395c, 0x9d42da75, 0x38efccef, 0x57eb295f, 0xbfcb30f7, 0x5d395625, + 0x54ceedd7, 0xf45bdc41, 0xee3e0a3b, 0xcb5fbf38, 0x98e3c499, 0x443524a9, + 0xa4c2dcde, 0x30fea0b8, 0xe7695dfc, 0x3e5858f5, 0xefded2b2, 0xc275b389, + 0x25d7343d, 0xa47a7f76, 0x71013fc2, 0x7f465d92, 0x917cbf3f, 0xf87177d7, + 0xf8aff5f5, 0x91677ef0, 0xab35ecbe, 0x9bff908d, 0xebf20ef4, 0x07b2a8a2, + 0xf57d6933, 0xdfc8fd86, 0xbeca528b, 0x7cfca4ca, 0xac0386cd, 0xafb2f6fd, + 0xe93d41fa, 0xd897ab20, 0x4f7e035f, 0xc67bc1c8, 0x88f5f924, 0x7159261f, + 0x0ab9755e, 0xd5eadfdf, 0xa3d1de5f, 0x1ae022fe, 0xabd22caa, 0x9fc5831a, + 0x81e97b5a, 0xc38609c5, 0xa790ad3f, 0xaf78edc4, 0xf7c76646, 0xaffbb244, + 0x86fefb3d, 0x4f9e19f7, 0xf004fe72, 0x35d110d0, 0x1fd69327, 0xe30cf88d, + 0xea9d9250, 0xb0c7e021, 0xba2cc99a, 0x9d6ba95e, 0xb225f403, 0x20d066cc, + 0x075fb95c, 0xf0a2f4de, 0x9fedeb7b, 0xa6c2923d, 0x463ac071, 0xf0d03e70, + 0x435f37f6, 0x82e1b2dc, 0xe1ea06d1, 0x0f0d8e88, 0xa235be82, 0x30dfd7e3, + 0x5feecc39, 0x008f7588, 0x7dfd1dbf, 0xd71ebb78, 0xb6e3a23f, 0xc8fdf045, + 0x016476df, 0xe53e8c9d, 0xd0b60169, 0x148defb3, 0x2fcdfdf9, 0x186f99ae, + 0xe0248e32, 0x54aa27f1, 0xde3c2145, 0x8ab8f060, 0x71dd51f9, 0xd178d6c7, + 0xdfbf27b9, 0x8c76f542, 0xe1265e83, 0x8bd3f036, 0x7f4ac57b, 0xba4ac9e0, + 0x68fbfa3f, 0x80415d1f, 0x85725cde, 0x7a01ffda, 0xc8b12978, 0x2486e5ea, + 0xe615f7d9, 0xb8fb594c, 0xed64dbc4, 0x640b5977, 0x233909f5, 0xb44fdf64, + 0xf7eaca95, 0xf64bbf0e, 0x52bda57d, 0xb4f02f56, 0x721fbec9, 0x7ede5da4, + 0x0f01a89c, 0x076d2785, 0x6b3e2ca1, 0xd0e2b747, 0xa1078df3, 0x0617f11c, + 0xf43fa50e, 0x076d2b8e, 0x0fe177e1, 0x1157de55, 0x6ae9d1fe, 0xdc175ba3, + 0xa1a89a0f, 0x8bc925e5, 0x62ad44fc, 0x305e55f7, 0x6f01bb39, 0x094abee2, + 0x122943f8, 0x625ee62a, 0x3167b2f7, 0x4049d87f, 0x19a7f00c, 0x9de3f426, + 0xfabe36d4, 0x4ec7167b, 0xda37be03, 0x77db2557, 0x6ca715c9, 0xa964a5df, + 0x65cb4f02, 0xc3f30af5, 0x25c7efb2, 0xdfb592ae, 0x815c7d65, 0xf56527a7, + 0x0a0db689, 0xe0566d3c, 0x76b267e9, 0xdc1ddf41, 0xf836f53f, 0xca396895, + 0x780e59db, 0x0fbcf3b8, 0xb3bc31f1, 0x74f01cb5, 0xc436c9c7, 0x51c79157, + 0xe872ec0e, 0x5083c691, 0x05fda87a, 0x27340efd, 0xd9a87962, 0xc3a9fe8a, + 0x1e5839cd, 0xefe1b669, 0x8e1e6abf, 0x76cdfbe5, 0x3cd37f2c, 0x66cecb1e, + 0xcd6d9607, 0xaefdf86d, 0xdfe676e6, 0xd7bde98a, 0x807e069f, 0x1eb7956e, + 0x27643eee, 0x7e044ec7, 0xedee1dd9, 0xaea3fa86, 0x2fc089e8, 0xa1130007, + 0xcbcf9c78, 0x3df629b1, 0x0dbf94c9, 0x91756649, 0xb2a6d057, 0x5e1e8017, + 0x09e331b2, 0x8f211a4d, 0x9a2472ad, 0xa06eac2d, 0xe6364475, 0x613c655b, + 0x55e4254f, 0x60772510, 0x7bd4227d, 0x90fb58c2, 0x4113198d, 0xf1ceff0f, + 0xbc9f7b60, 0x20e492c0, 0xcf57e0f1, 0xbfe04d5b, 0xa0757639, 0x8c71e009, + 0xa4ecb1fb, 0x968f3b40, 0x2d029aa5, 0x0a93d9c8, 0x3d9444bd, 0xc9f1d2aa, + 0xdb6fb071, 0xbe43cc34, 0x7e804b5b, 0xdecc4b27, 0x4ff5df15, 0x1317f9e1, + 0x1d4f68f5, 0x6117d957, 0x7be493de, 0x64bce001, 0x7b8410e3, 0x0e97c98f, + 0xb1b45bf0, 0x7ce3d590, 0x80b6482f, 0x67c196ba, 0x8982c6fa, 0x0a5bdcae, + 0xe0c1059f, 0x666c9d53, 0x9ec7b6fa, 0xa8807a06, 0xd7b4af1f, 0x5e3e79c1, + 0xa2fbc76a, 0x767a1cc7, 0xbc261d7e, 0xf63440e7, 0xfe0169e2, 0x5ac9b39c, + 0x2e1537ec, 0xf35f819e, 0x739e357e, 0x29553c25, 0x3a470f4c, 0x46733b01, + 0xc705da04, 0xb7deec55, 0x14ccfbf2, 0x0c5d1f66, 0xeb77ee0f, 0xa6cbdbc7, + 0x87babdd4, 0x22b3d78e, 0x71ee870c, 0xac7d440c, 0x7bc251a7, 0x1be73db5, + 0xbd76b12f, 0xe304838d, 0x5fe13392, 0x8ed5fdb4, 0x31faff07, 0x15b3fefd, + 0x21943611, 0xbf0841e6, 0xb3c7f9fb, 0x3fa80c63, 0x569c9ecd, 0x26717206, + 0x31cd738f, 0xdc31e269, 0xe0e8b1a5, 0xc685ba09, 0x82143582, 0xa56c7164, + 0xa9cc9e0e, 0x06be5d4e, 0x4fd965ca, 0xf0ada2ea, 0x35ced77e, 0xd1d6c6a0, + 0xfc8c5c23, 0x3341fbcf, 0x26dcd75d, 0x73d995b5, 0x6bdaae5c, 0x433f2a6e, + 0x9e71efd0, 0x8081432f, 0x87166af6, 0xc597e8b7, 0x325b74e9, 0x91e4138f, + 0xa7df763c, 0x1db00e37, 0xf66ba4e8, 0xc4420307, 0x5cede409, 0xc744fc7f, + 0xbbbe55e6, 0x4ecde620, 0x71fe7a61, 0xd04ca51d, 0x7267ef27, 0xabeabf20, + 0xfee98b47, 0x2acc3bf3, 0xadcfc38c, 0xb87803db, 0xa8f1cedc, 0x9e70ed25, + 0x7de6b8a6, 0x8a4ab986, 0x93d79a7b, 0x734eb697, 0x2cbca079, 0x03ca3af2, + 0x5f70e5e5, 0x45c8396b, 0x7c451f21, 0xcd5cd3d0, 0xf22372f9, 0x4dcd43d3, + 0xecdc3f58, 0xf348f2c2, 0x5b97ce5a, 0xe6fdfdb1, 0x765f38e7, 0x0dbcbe73, + 0xae68ef7f, 0x66edf2c2, 0x28969627, 0x7e016fc7, 0xcc4e0d53, 0x83777bef, + 0xeb7c409e, 0xf31e8772, 0x7889e80e, 0xc858f9e1, 0xbde3d1a7, 0x8d5e653b, + 0xd2f7cf92, 0x25f7df43, 0xf4f300fe, 0xbe80c3e6, 0x9e9a1198, 0x09ab118e, + 0x92dfd2f8, 0xbe82269b, 0x356acc7d, 0x657d3e81, 0xa5f21363, 0x49ab7663, + 0x24dfeb4b, 0x9ddacc3f, 0xd69e9356, 0xc3e37bff, 0x3565ddac, 0xdffad185, + 0xeacfbf93, 0xc482c26e, 0xe7c8cd29, 0x0874894b, 0x21b947ce, 0x17150c73, + 0x1e975e54, 0x2e317382, 0x3818de71, 0x56c97517, 0xacbb8fa4, 0x7d410eab, + 0x0d66ce42, 0x1bb6c55c, 0xbf43560b, 0x0d4ad8b2, 0xba931bf4, 0x1bf4357c, + 0x26a4fd9b, 0xdcf8dfb0, 0x7ea1ab9d, 0x06b36d8f, 0xce3ad3f4, 0xa238c4c7, + 0x9f05da2e, 0x835e7916, 0x0f281c3b, 0x281ddbf2, 0xca5c040f, 0x063e56a6, + 0x7686c77e, 0x3ac12cc9, 0xc1bd4aa6, 0xab91c86f, 0x291af787, 0xfe7a8ebf, + 0xba2ad309, 0xdfa806cf, 0x5627f581, 0x9dfe5add, 0x97d71292, 0xe7e09f7f, + 0xe43de41d, 0xb1d09f65, 0x001e32f7, 0x7de314b8, 0x2bbe1334, 0xd0269c49, + 0x3cb89ab3, 0x6d25095f, 0x3bebcedf, 0xd9579c85, 0xdfd0a7fb, 0x7db85373, + 0xd83f97d9, 0xfcf41d60, 0x8439ee2b, 0xa1fce768, 0x7b2cc530, 0xb08ea15f, + 0xcbd7557b, 0x31e6531b, 0x9629f32b, 0xf6c3b691, 0x1479becc, 0xc7bd84b5, + 0xae4fcca2, 0xad5eec27, 0xd7b94f32, 0xfc670aae, 0x0d780ab4, 0x2989e3a5, + 0x6564f921, 0xe135f14a, 0x910f6f20, 0xb094bd97, 0xf93eec3c, 0x5b1f3c35, + 0x8ce22fb9, 0xf25def63, 0xfee56cfc, 0xddf45d04, 0xbf832b5f, 0xea9fc186, + 0x7d600b77, 0x044d7315, 0xfc8156fc, 0xf06be3e7, 0xbb3f251f, 0xfa727c55, + 0x9f763adc, 0x6b1f2fbf, 0xc7c2094a, 0xb2975e44, 0xdc2a7a14, 0x3efc831b, + 0xec060f78, 0x9c123bfc, 0x3d97402d, 0x55afbe65, 0xb2c68760, 0x2dbb93f7, + 0xbbf035ce, 0x03f963a4, 0xbcf6af22, 0xd04bf5ca, 0xf94a9edb, 0x6ebbf215, + 0x8cf41610, 0xe075a3ac, 0x8e2c4367, 0xe48fd0f5, 0xef817578, 0x1fca8730, + 0xe1cb9a7d, 0xe59125be, 0xfe6cf655, 0x0fde86e6, 0x0a8f050a, 0xdc2f28f5, + 0x3c3cb85f, 0x9767e502, 0xfef03c44, 0x3c69576b, 0x695d2dea, 0xb7940d3a, + 0x4aee2eda, 0x2be3801b, 0xa4aee3ed, 0xef3606e1, 0xfe50f1d8, 0x115ce926, + 0x790fbdc8, 0xcebb613e, 0xe037e435, 0x86111e1f, 0x257bfa71, 0x41c0116f, + 0x1d775769, 0xcd66559d, 0xd35f6bef, 0xfd818dfd, 0x3d519ed5, 0xacddbf06, + 0xf4db5dbd, 0xed3c8135, 0x09574d91, 0xbcdf8fe4, 0x9d19ddfd, 0xc2bd056f, + 0x322402d9, 0x13ea8bac, 0xfcbd7eb4, 0xb5124ba4, 0xec0333d3, 0x66bfe1f2, + 0x54bc4a79, 0xde7de7da, 0x92e65b4b, 0x7a95c3e7, 0x44df318a, 0xfbc48ded, + 0x9ef62aaa, 0x7a57c882, 0xd4f3db8f, 0x829b3f5e, 0x74ceb87e, 0xfdfebd99, + 0x823ce74f, 0xf30c207c, 0xff6d5e33, 0xfad60e3c, 0x9fb8ce87, 0xd3f565bc, + 0x6bf98377, 0x5f679812, 0x565974db, 0xed7ee2ef, 0x2fbb2d56, 0x354ffb54, + 0xc72a25ca, 0xc89e22d6, 0x0103dd01, 0xfdb495f2, 0x83de17b9, 0x04abbf29, + 0x1d7ca180, 0xfb4ec939, 0x887b7255, 0x9d587790, 0x95c48fdb, 0xe271eac2, + 0x7ab31ffb, 0xa9fef89a, 0x4f3a7649, 0xe7689265, 0x75e36ffd, 0x33d58797, + 0x647ff7c5, 0xbb589bdf, 0x498ed37e, 0x3f05ce70, 0xdfcaa537, 0xddfca201, + 0xcd7c5a92, 0x3b791a7c, 0xdde2ffe7, 0xdfef8a9f, 0x9c01f115, 0x730936d3, + 0x6a576ae7, 0x317f5fd1, 0xf03f2dba, 0x7791507d, 0x613728e3, 0xebdd541e, + 0x0b80b703, 0x1e3a6d53, 0x44ca7a0f, 0xa154ff9e, 0xe59c6236, 0xc7c67af2, + 0x8b79e943, 0xe194de9b, 0x7f3b4fab, 0x9103178f, 0x4f4bbe74, 0x90f7b024, + 0xee313bb3, 0xe995383f, 0x22bef0f1, 0xf915e7dc, 0xc459b15c, 0xec71f60e, + 0x5dec611b, 0xc89db3c8, 0xc1bf175f, 0x1b75d7fc, 0x9b3ca20e, 0xffa2b6af, + 0x673f5c68, 0x47c42a71, 0x30039d4c, 0x36f4ddee, 0x673fc39e, 0xcb9c7998, + 0xcf081b97, 0x5fe17dd1, 0x97f81d7a, 0xbfe13bfe, 0x180dea9b, 0x8613dae7, + 0xc6826cf6, 0x1c41b3ab, 0x577b24f3, 0xdb872172, 0xe23fced0, 0x7887ff7d, + 0xc59daa3d, 0x959e4469, 0x54a1f798, 0x8f038313, 0x7e4dd487, 0x43c4147f, + 0x224afe04, 0xb7f81b48, 0x1c6c1e29, 0x83c0360f, 0x2e3fb780, 0x0665fb42, + 0xbd956b8e, 0x1ee02b5f, 0xe92b1cea, 0x195bac43, 0x3c665827, 0x5df80c54, + 0x81799376, 0xbe38d297, 0xfbcc5e35, 0x410673fb, 0xb8f028b9, 0x5dde2fb2, + 0xc4d771a9, 0x5ffdbcbb, 0xdc25778c, 0x8f2d6594, 0x7f7f297b, 0x2ff55521, + 0x36ffe385, 0xc6ecea7f, 0xb9f6b2fd, 0xc86f474d, 0xa0fc2adf, 0xabbf2eff, + 0x7a4eb7f0, 0xe20a896d, 0x7c7b4a32, 0x6be3ba5a, 0xdf7bbfa0, 0x09ee47fc, + 0x00f57c58, 0x90793fcc, 0x51abe5ef, 0x11ecfb7f, 0x355f4f4a, 0xa9d43f32, + 0xad6a5ffd, 0x63e97d79, 0xb11515f6, 0xecd5d007, 0x20b48fa6, 0xcd5366af, + 0xea3c5822, 0x309e9cef, 0x81f2847f, 0xc6d1032a, 0x555ff3d2, 0xae73dec5, + 0x344bc082, 0x6d271e96, 0x1e21a49f, 0xd2b5af78, 0x31e8f1a8, 0xb7bf241e, + 0xb9efe7aa, 0x7652c352, 0x576d557f, 0xb4d37e63, 0x748e2ce1, 0xef0db1bf, + 0xf238ce25, 0x6847a5e8, 0x2aed593b, 0xe2b77966, 0x54efd19e, 0xfa1f1337, + 0x7e612a7b, 0x1dc78954, 0xee316b97, 0x61f7eca8, 0x4d63f32a, 0xbf2c4b52, + 0x4fcb2f60, 0xee91e713, 0x90be88ef, 0xbbc3c1e5, 0x5a8d95a6, 0xd07cc0cf, + 0xfea3f63f, 0x557c30d1, 0x61afe03e, 0x9f46748c, 0x1b03d7ef, 0xfd82fe9a, + 0x5958fc95, 0xe9dfa8de, 0x4823e6b3, 0x3c5f422f, 0xbac1ecd5, 0xab350fd2, + 0x6e303fe4, 0xee2fe233, 0x5e472816, 0x66189fb5, 0x95f6eefd, 0x9d84abb0, + 0x04dbb4a5, 0xb5ef10bf, 0xc3fc140d, 0x777b11f0, 0xbccac351, 0x15ff3934, + 0xd9f2957c, 0x7f8c3482, 0x006ff9ca, 0x7ff6c61f, 0xd3f61f17, 0xfc0da37d, + 0xeca95535, 0xdd25737d, 0xf93226d7, 0x7577a4a9, 0x19f51ab9, 0x3a0bbd25, + 0x19becfbf, 0x20b375fd, 0x31d74f56, 0xfbc241ab, 0xff5f2752, 0xba0643e1, + 0xa7b6ae84, 0xe8f7b2b4, 0xfbee926e, 0xe9b381ca, 0x9677df30, 0x9c33a403, + 0xf8665bdd, 0x47d69458, 0xbb4d2e8e, 0xb7951cb6, 0x17f18bff, 0xbe73ff64, + 0xca241c9b, 0xd473057b, 0xd39f362a, 0x213ef2c8, 0xcdc7acef, 0x675579ee, + 0xd37be2b6, 0x122fb864, 0x7dd2c8f8, 0xc58eb26a, 0x01493437, 0x117508ef, + 0xe92327cf, 0xb1464bef, 0xf9943877, 0x4f3cf598, 0x37719973, 0xbe5213de, + 0x3df22407, 0xca78f9eb, 0x7f448177, 0xf9582f71, 0x34c6d02e, 0x90ad7f7e, + 0xf838b214, 0x3753f9b5, 0xff00c9c8, 0x66d5f770, 0xa4b673b4, 0xae47f1fd, + 0x6f3c7e51, 0x3e7ee34b, 0xbf6c5d3f, 0xff6c5d0e, 0x6a1749ff, 0xef7c56d3, + 0xe2e966e3, 0x3f7dab11, 0x8f9c5bac, 0x96fc73de, 0x78b1cf1e, 0xf967b80f, + 0x471ef8ab, 0xe30437cf, 0xc3f3d740, 0x6bb17494, 0xbacfa33d, 0xaf144c5b, + 0xd0b94f23, 0xb8e2303f, 0x0dbfef13, 0x990edf7b, 0x90e0a4c6, 0x16eb0d43, + 0x1bd0827a, 0xdf80fcfc, 0x1d79e153, 0x6e37ca37, 0xaff1be36, 0xfb886b8a, + 0x4f5add32, 0xdb9009f1, 0xbe82c37b, 0x8d257d97, 0xef50edc9, 0x9ca25a6e, + 0x534f0057, 0xef15df38, 0xd9a8566f, 0x3b97b93b, 0x589fe8d5, 0xfedf83f1, + 0xdf6b79f2, 0x58fa95f1, 0x5072f983, 0x0d9446fb, 0x5f2f962a, 0xbcc56e58, + 0xc07bb02c, 0x17fc215f, 0x5847efca, 0xd1d3c2cb, 0x69d51ede, 0xc73cf587, + 0x5f0a13d6, 0x123e4d0d, 0xa87ceef8, 0x15f61bf9, 0x9c07e79b, 0xbde9098f, + 0x9cf99676, 0x1bef8fc1, 0x6dff8ba5, 0x3524fffa, 0xfe544971, 0xa66e49e6, + 0x57a6124f, 0x589d22ce, 0x2c3e21ce, 0x4fe5849d, 0x2c3627cf, 0xaef61217, + 0x670ca1f9, 0x8de83a49, 0x0fbe1f5a, 0xbff5e97b, 0x4cfbe2e7, 0x856c8e77, + 0xe55ba89c, 0x55ea56b7, 0x8fbe053d, 0xd8ff03a7, 0x2b74f7f3, 0x7b1bffca, + 0x94507aa7, 0x107a4a7d, 0x4a6ff6bf, 0xc4beecd5, 0x5e5107c9, 0x1f599a54, + 0xfdf98632, 0xe2642627, 0xcdf3f1f9, 0x6f82cd84, 0xef2afc42, 0xdfc58a8c, + 0x77f84a97, 0x2abdda79, 0x8b79623c, 0xa86add32, 0x79ed66ef, 0x44b71675, + 0xc22379eb, 0x8b72fb58, 0x67ddf21b, 0xcb9e2f13, 0xaeed90b9, 0xbd13bff6, + 0x7bf9d880, 0x127ebe06, 0xc3a8bfed, 0x89b6f2c0, 0x9bf61b37, 0x1049760f, + 0xe997f73b, 0xee0fbcec, 0xe0fdf8c7, 0xe15fb932, 0x267ede21, 0xe013aca3, + 0xfb74bbf1, 0x0d7ce0f7, 0xf75cee8e, 0x53f81154, 0xc2fc0454, 0x18788c5f, + 0x5fa228e3, 0x11ecb598, 0xc4876ef8, 0xfb5d8bf2, 0xd2dde2f4, 0xfc7f40f8, + 0x55f28ca1, 0x74daddf0, 0xc1429fc6, 0x942efe15, 0x261d8823, 0x8306d5f2, + 0x427e886e, 0xed06ef82, 0x437d5890, 0x577bd8fa, 0xe977d11b, 0xcc33fd02, + 0xec31fcea, 0x108eb063, 0xbfffac23, 0xd219bdf8, 0xef710e98, 0x55e82f25, + 0x4a7c5fa0, 0x27dc31c5, 0x63b53df8, 0xed4d3ca1, 0x40ff2851, 0xcf2851ed, + 0xca147b50, 0x0a3da9cf, 0x362ba2e5, 0x14971c78, 0xce7fd867, 0xbbf83ce8, + 0x33a62f1b, 0xc32679b9, 0xc75b29d9, 0x63ae1d3e, 0xc7f3a587, 0xec75d14f, + 0x82ad93d8, 0xe0a12cfb, 0x6fefb3d1, 0xf820cee9, 0x93dfcdec, 0x6ccbe782, + 0xefe7f3e4, 0xcfdca0d6, 0x2e46f76f, 0x3daef80e, 0xc878875d, 0x123673db, + 0xf736efc6, 0xd12ed5c2, 0xb1524ead, 0x330bfb7a, 0x0b9d5def, 0x0277b0fb, + 0xeef9e8fe, 0xfdbf3280, 0xfb863fb7, 0x8c7c741b, 0xbe48f6c7, 0x532f4067, + 0x6fb943ee, 0xffba2fb1, 0xc77fd075, 0x13b07e9e, 0x3b086fca, 0xfbd8fb2f, + 0xbbf77db8, 0xaf7bd70a, 0xf70457de, 0x56fdee12, 0xf41f341d, 0xc229464c, + 0x99d056bb, 0xba71b788, 0xaefaf812, 0x1e395ae7, 0x0017ef11, 0x3c82b50f, + 0xfa091aba, 0x5b8f2560, 0xfeceefb6, 0x1cb9ef10, 0x3bf81351, 0xe5a38381, + 0xc19d4ee7, 0xf3289dce, 0x801ce9f6, 0xcefb1daf, 0x9cfbc365, 0xf0d93f14, + 0x4abf5b77, 0x17f32fef, 0x66f88de6, 0xfd0fd023, 0xe02eff1e, 0x02b9b20c, + 0x0d33f3e2, 0x2d85dffb, 0xa99f36cd, 0xdcfcf880, 0x9430e944, 0x6399acf3, + 0xf22f2e21, 0x94e4179a, 0x74a3861e, 0xf512ad8f, 0x2e6052b8, 0xdca17201, + 0xe71fc110, 0x46287215, 0x98971f56, 0x2efefb22, 0x7dac966b, 0xb2edce42, + 0x26fbdef6, 0xdffe21b6, 0x7c3c01fb, 0x465e20fd, 0x8efec1f7, 0x7dec4bd9, + 0xc73dbcdd, 0xd69dbeef, 0x0d3cbd27, 0xc1db63df, 0x2aed27db, 0xd623bfc7, + 0xa3a9e143, 0xe1f9d48a, 0x14f33f8f, 0x13b0a60c, 0x78bdf76a, 0xbe67de18, + 0x1d709dae, 0xfbd420fb, 0xd2bfa2a1, 0xf2fca03e, 0x072fc0c7, 0x0cd53ebf, + 0x231da1f1, 0x790649be, 0xefc19994, 0x21bb7187, 0x9ef4dd14, 0x61fac90f, + 0x2528fde0, 0x28f210dd, 0x4e5643a7, 0x01eec63a, 0xfb3f2cdd, 0xb433f013, + 0xf0245dc3, 0xfd2a08ef, 0xb6758365, 0xff041f0f, 0xb86a07ce, 0x3f7bd109, + 0x5bfc316b, 0xb277a7ed, 0x4963f370, 0x0bbbf8b1, 0xee7ae0f4, 0xc1959b3f, + 0x76a4ace2, 0x454963ff, 0xe2b276fe, 0xb27bec8c, 0xab235a52, 0xd794ceaf, + 0x09ae97d7, 0x0f4a1fec, 0x3cdcfc5b, 0xee0f339d, 0xff4149f1, 0x7aef626e, + 0xd85f3962, 0xecf904b7, 0xf14bfdb9, 0xbf2ab9ef, 0x81e3a7af, 0x08716fdf, + 0xd3f82af9, 0xcf7b350c, 0x4cbed957, 0xb5bb67cc, 0x614a7df3, 0x6f5c798f, + 0x69fbb930, 0x93275394, 0x7f4c19eb, 0xc9e1b4bd, 0x710d7c1f, 0x9eccbda4, + 0x726164ba, 0x17f77f23, 0xcc7bf82a, 0x7d19c383, 0x2abd9be5, 0x53d327b8, + 0xbc82e11d, 0x26a586ed, 0xdc1bb7cc, 0xa189f7cf, 0xfc1f9080, 0x1a7fd0f4, + 0x0efe7d28, 0xc805bf2e, 0xb9d01ee1, 0x8cf1fd68, 0x49872843, 0xb86fcb2e, + 0x9c7cfb55, 0xbfa864ea, 0x317e3194, 0xcb8fe807, 0x55cf422b, 0x57a463c3, + 0x021f017e, 0xc0fd40b8, 0xf0fbdf4f, 0x1e33f069, 0xfc02fc65, 0x0f513307, + 0x7ee51bb0, 0x1ef63685, 0x0bbd9598, 0x4242f222, 0x87658ff1, 0x5760755a, + 0xf1fe6ade, 0xc4f9f5f2, 0x8f1409b1, 0x3e597b0d, 0xfe8ee5f7, 0x6f802451, + 0xf0d7e128, 0xb7cf0a9c, 0xa87777a8, 0x5079c3c7, 0x70164bde, 0xb201e626, + 0x181e78f7, 0x20c9b7fd, 0xa7d81f97, 0x50f44161, 0x1155acf3, 0x833cc06b, + 0x8e51e9f7, 0x98f7f589, 0xf7d91f39, 0x5cd2e8d7, 0x220aae56, 0xa01ea94f, + 0xa03d058d, 0xf5bb4252, 0x65097de3, 0x258fff00, 0xe216b1e2, 0x3a2f9810, + 0xbf070d85, 0x899df11b, 0xe04d1cc4, 0x6ec27afb, 0x5a6fb69d, 0x3f57d07f, + 0x63ff3dd9, 0x69f2198a, 0x879e1646, 0x1f8ef0e9, 0x16c7ef85, 0x43f81a47, + 0xeb78f126, 0x175f16c7, 0x8f1fd5e8, 0x6fc0908e, 0x0d5fc749, 0x7d7d8be3, + 0x35a475ac, 0xed17fa06, 0xfbd3be83, 0x42bda25d, 0x0274b2bd, 0x11678bc4, + 0x5efcd77c, 0xc9a3d335, 0x0b3cec3b, 0x7520dabe, 0xc73be346, 0x32bb9319, + 0xa684ff68, 0xab3da11f, 0x51ba27cc, 0x6ed7ba3d, 0x77b126de, 0x4e8c6c32, + 0xfc5d47eb, 0x7f3a74c9, 0x41efb53d, 0xdf6babaf, 0x28a6ef8f, 0x7b5ef9ed, + 0xbc2fe94a, 0x7fe83f8e, 0xca6fb100, 0x0080005b, 0x00000000, 0x00088b1f, + 0x00000000, 0x58adff00, 0xe554700b, 0xdef73e15, 0x66cd927d, 0x421b22f3, + 0x260ddde2, 0x9b709601, 0xf51e4357, 0x8ca4109a, 0x6388376d, 0xfadea56a, + 0x59092040, 0xd6a27509, 0x0071a6e1, 0x3b634ea9, 0xb33088a3, 0x2331e1d2, + 0x3054d353, 0x32d740a3, 0x5da96255, 0x66d42d8b, 0x88d46b98, 0xf1a6c935, + 0xa1986655, 0x5ef7fce7, 0xd6086f76, 0xe6ccdd3a, 0xe73effec, 0x9cff8f3b, + 0xaa36c01f, 0x5cfb0195, 0x8bdff016, 0xed2bf1f6, 0x8ca2c020, 0x06ac43b0, + 0x27c8f2d8, 0xfb0dbd7f, 0x990dedd4, 0x47f18b63, 0x475f8e3e, 0x5c8054b3, + 0x000ea580, 0xd4c0154f, 0xbee8b4fe, 0xf097f500, 0xd9b00350, 0x80453f87, + 0x9c944e8f, 0x8ff1c6ed, 0x8703b0de, 0x9f1b275d, 0xdb107c9e, 0xf9a7f65b, + 0x059e349c, 0xef8d3e6a, 0x38aa8d2b, 0x6a7e3ee1, 0x27073ba4, 0xfb4ba60e, + 0xbdc3fc71, 0xc61fcfa5, 0xafe786f6, 0xaecd8897, 0xd9883c5d, 0x0d885fd8, + 0x3e6dffea, 0xfd7e075b, 0xfd2e75dc, 0x92e0e15c, 0xf8d0379f, 0xce896cc1, + 0xcb39a569, 0x75ec2e00, 0xf00e50cb, 0x7dcac419, 0x731f00c5, 0x1b8f18ea, + 0xcf87f3b7, 0xb3c03c73, 0xe494a50e, 0x37fbb8de, 0x7947ab7f, 0xe77e0f9a, + 0xdfc865e9, 0x40b93386, 0x5cf2c0fb, 0x787e0186, 0x1a728b98, 0x9708b5e7, + 0x60085abc, 0x067158fa, 0xb4f89284, 0xdefb721f, 0xe2b81977, 0xd32073b7, + 0xca1aeed2, 0x965fbdf7, 0x8e83b76c, 0xd9c3dc31, 0x7d0eff68, 0x65798608, + 0x09d5f109, 0x0808039a, 0x97847298, 0x9c085400, 0x13ff840c, 0x65ff864e, + 0xa490dcfa, 0xf8cf222d, 0x1941e0e8, 0x6cfce0f0, 0x702bf970, 0x97e3a2b9, + 0xdf74a278, 0xad66c44e, 0xcd500598, 0xbd592df6, 0x8b7fc924, 0x15e9b230, + 0x977a7fdc, 0xef627253, 0x0cee1bb8, 0xa73eae87, 0xeb64cc55, 0x053eb9d7, + 0x7fb2765b, 0xadbfcf53, 0x51c810ed, 0x27d15f5c, 0xb48fde56, 0xafcbd0db, + 0x0c35e1fc, 0x8f2781f7, 0xee78669e, 0x3a1de079, 0xe98794f7, 0xb8eb4e0f, + 0x23683827, 0xd6fdcc39, 0x56c0a6b9, 0xc73efc49, 0xc7fb35f8, 0xae5b399e, + 0x4763fee0, 0xda039716, 0x7c425df3, 0x67c459ec, 0xfe7e3d32, 0xa783a461, + 0xf15732fe, 0x476fcd5c, 0xcfdb34cf, 0x1c738f6c, 0xe483b793, 0x829bfec0, + 0x9e228de1, 0x09903603, 0x4b9dd1bf, 0x422d7e18, 0x9ff48328, 0xdfcac8f8, + 0xfdcd3e4c, 0xfdccfe4d, 0xa43d79cd, 0xc261c42f, 0xc2cf2f11, 0xa24539fe, + 0x6f09ae45, 0x43d33cbc, 0x3fd63efd, 0x14ed8591, 0x9fa36b7b, 0x1736dfa8, + 0xbf9073d8, 0xea4e36b6, 0x42afd603, 0x0531a316, 0x2ffc3bc7, 0xd841b81b, + 0xab767685, 0x93906761, 0x5a3f236d, 0xdf5dba03, 0x8bc7fb5a, 0x76e0179c, + 0xfa03b018, 0xf7be39cb, 0xe3a42ec7, 0x13b4bf03, 0xbe10e87e, 0x4e5fb431, + 0xbcbf877d, 0x4db96af8, 0xa58d804a, 0x5f831bc6, 0x22ca09b5, 0xcf84cfb8, + 0x014bf2a3, 0x1b39119e, 0x8508579b, 0xa5c70f34, 0x3a81da18, 0x90fa94e8, + 0x787c4b9f, 0xe1dfe12f, 0x1f939588, 0xf12eeb98, 0xe71feb0a, 0x7d23af4e, + 0x1e562d83, 0x647d474e, 0x40cb803a, 0x65c52b9a, 0x0cfd43c4, 0x23015c58, + 0x9518f1fe, 0x1d849ce8, 0x8f9106da, 0xfd37ea46, 0xaaa4ed13, 0x7a0c8f99, + 0xfc93f392, 0x0195db5b, 0xb2aacfdd, 0x2cc0c8f9, 0xc327f1fe, 0x4060fb0f, + 0xd617fdd0, 0x7ae710b8, 0x59006703, 0x64df7f20, 0x3cb937b4, 0x54e30131, + 0x0552ebc2, 0x18febfe4, 0xf5db01ea, 0x44abd8b6, 0x07a1ebd1, 0x310759f5, + 0x6b21bf7d, 0x8f70e6fc, 0xfc1c703b, 0xa91c598b, 0x8dbbd433, 0xd1e9008b, + 0xee8cfd05, 0xd102e2e4, 0xa314c16f, 0x446cf832, 0x97467611, 0x15d19843, + 0x25746110, 0x0aba33f4, 0x19bd1806, 0xa2c28ce2, 0xf8b01f58, 0x58df13ff, + 0xdf6f921a, 0x5a465fc7, 0x66441b75, 0xc32987f3, 0x078dafce, 0xaf9af546, + 0x500ac78f, 0x6baf8cfc, 0x8cbf32e1, 0x8b89b9d9, 0xd711ec93, 0x27ea21b9, + 0xdb1a08da, 0x5c3206e7, 0x1046e7dc, 0x066ed46d, 0xbe5bb599, 0x9ab51e22, + 0xb3425362, 0xbb3cd2e0, 0x70345c9d, 0xab2c25e9, 0x185afa93, 0xd4db5910, + 0x149f201b, 0x27d6afff, 0x559f1114, 0x889f4d69, 0x03b22218, 0xc61b61bd, + 0xa6caaad7, 0x2f6c62ee, 0xb7a93c08, 0xed2a9beb, 0xfbd39e12, 0x8c72f08b, + 0xee0c2eab, 0x2845c46e, 0xa916a016, 0x0396f6e2, 0xb85395fa, 0x54ff225f, + 0x10f100dc, 0x40b9e373, 0xc256d0fe, 0x3e2dbfee, 0x3aef3f5d, 0xda00f494, + 0xe62ba777, 0x2de71115, 0x74792dbd, 0xe8776e0f, 0x2b9bbefb, 0x65057e2e, + 0xae39e272, 0x383ca48a, 0xadb1baae, 0x4f776271, 0x57ee7920, 0x5020af38, + 0x9af3ed7d, 0xfc488afc, 0x4804ab80, 0x3dc605cf, 0x2f58383d, 0xef9d3c49, + 0xe96be763, 0x383ddd25, 0xbc3fa4f4, 0xa44bf690, 0x90b5f6eb, 0xd24dcff0, + 0x94b90135, 0x27f667c6, 0x1a38bf7a, 0x1f137dc3, 0xaeb8c1e0, 0xd394a031, + 0x56bc5db9, 0xf87a8954, 0x0779da69, 0x4fb4dfe9, 0x0772950e, 0x4327dbca, + 0xbeecc1d4, 0xaf2577c1, 0x77da4e2a, 0x0fdc5ee2, 0x870aa871, 0x5c38ed9b, + 0x493916d3, 0x6fe956b4, 0xa73a11c6, 0x12e9f89e, 0xbe91d6a6, 0x38cf3327, + 0x37fe603e, 0x2333b75f, 0x313f1d2e, 0xde8170fc, 0x7f8a430c, 0xf8b89d75, + 0x1e303ff9, 0x247b4d76, 0xec7f5e9a, 0x26f06e99, 0x3ab30afd, 0xfd30dc4b, + 0x19c86eac, 0x85bcd813, 0xc6fcd2f7, 0x14c52333, 0xd1186f6f, 0x42dc30fa, + 0x02d9f8e2, 0x7b8ddedd, 0xfb82fe41, 0x8b42f73a, 0xb8c74a80, 0x1088f9bf, + 0x9b5ca275, 0xda304f29, 0x743fb62a, 0xd0649da1, 0x8f93d97c, 0xe437ad72, + 0x83fe1cea, 0x6d3a8303, 0x1bbc92a3, 0xefd7fe0c, 0xca66fbb9, 0xed4436fb, + 0xdf8ef8c9, 0x36e891f6, 0x90fdbbe2, 0x21229fb5, 0xac65dfc9, 0xabbca0ef, + 0xeb37f298, 0xfc782ebc, 0xba97145f, 0x9bfdac86, 0x4c39e902, 0x063dc60f, + 0x9f78be46, 0xa3e48731, 0x71f379bc, 0xb289d447, 0x2ddbde6d, 0xe85da8f9, + 0xdd1c5891, 0x5bb328f3, 0xc9ec3e73, 0xfa623666, 0xc01d86e7, 0xc71360f2, + 0x329c07a5, 0x81e963e9, 0x62df963c, 0x0af2ce5e, 0xcecc138c, 0x1c262297, + 0x990bddda, 0xcf1e4153, 0x9978e179, 0xcbf37944, 0x6f78655b, 0x333f9241, + 0x0e116f6f, 0x3ed03b37, 0x1f01efa6, 0x50357de5, 0xae0374f6, 0x87653eab, + 0x834f8e28, 0x0be98fae, 0xebbfcb3c, 0x64fd2b86, 0x231cc207, 0x4f31f86e, + 0x2dc3c14f, 0x253101ce, 0x75f135cf, 0x2b4b7a1a, 0xa78cb2cb, 0xeb2cf34b, + 0xd6836a33, 0x0f1caaf5, 0xd69c50d5, 0x8bca67d7, 0xc341f32c, 0x306f1c3f, + 0x5deedbe0, 0xb7ec8a71, 0x66feb3d1, 0x657b29c2, 0x53be6585, 0xff102638, + 0x2cda9f0d, 0x8426fc7a, 0xce51d39b, 0x0f31b7da, 0xc6ea73c1, 0x4d6ee3ad, + 0x7ee75a05, 0xa01f253b, 0x7b6b44fd, 0xf987b4c0, 0x1ed53f30, 0xae7b7892, + 0x50f649e0, 0x782c0b03, 0x0aebc4cf, 0xf3071efe, 0x6ee1ba87, 0xd86e5fc6, + 0x9b5e7b8a, 0xc57cf715, 0x7ac1738a, 0x1185ce2b, 0xf5d7ce2b, 0xa80d7158, + 0x778adc56, 0x5fe659d4, 0x6964dfdf, 0x655aee97, 0xba30bf99, 0x7c5ed2da, + 0xfccb76e8, 0x59770325, 0x6d0e97c6, 0xf69b8cb4, 0xdfff5335, 0x619e6d88, + 0x5ff03c5f, 0x53caffa2, 0x99ce590f, 0x888077a9, 0x6bd6f840, 0x5703bb00, + 0xedfabdeb, 0x578af07e, 0x0f029deb, 0xf5339de5, 0xa7fa453f, 0xffe86f38, + 0xc629d233, 0x17bd37b9, 0xfd37271e, 0xcf1e9a6e, 0xb886845a, 0xb06d7a4c, + 0xcfeb7ab3, 0x3a737662, 0x1ee303c5, 0x18f71b0b, 0xecc1dfac, 0xdbd3ec21, + 0x493a5c52, 0x5ce2ac71, 0xaaf899b8, 0x512722d2, 0xd0b9a84c, 0xf3419cdf, + 0x387d1065, 0xfaf0339f, 0x36072d5e, 0x7b613f8b, 0x5bcf126e, 0x03215ed4, + 0x8a5fd727, 0x4b30b1f6, 0xbf9e0ec5, 0x6ae718da, 0x55a27bf5, 0x052d8376, + 0xf35ac697, 0xfe3108fe, 0x316ffc4c, 0xe7cc08ea, 0x3cf941c1, 0x05f68aef, + 0xa45fcb66, 0xafcb025d, 0xbd6f9614, 0xa27629ce, 0x22f15c6b, 0x9e4aeb8a, + 0xb8882f32, 0xc892f24d, 0xeb4e33f2, 0x2412a123, 0x6a565d18, 0x754cab66, + 0x30a39618, 0xd19f290f, 0xfb187aaa, 0x2f46ad3e, 0x1253e97b, 0x18838a54, + 0xdf394717, 0xfb5c4ab6, 0x45c7dd66, 0xca2d6f74, 0xff501790, 0x3c8ef795, + 0xabe30b94, 0x412a8bc6, 0xb1c43ea0, 0xda63e1fa, 0xdf8a5964, 0x7bb3b0ee, + 0x6a7a8c0a, 0x599381ad, 0x9c61dd4f, 0xac5b8a3b, 0x76bdf8c7, 0x478675e8, + 0xd59c7fbb, 0x926f689f, 0x7bbff70f, 0xea82a7be, 0x252b9049, 0xeb370ebd, + 0x7fe102ab, 0x7acd47b9, 0xdbf35af4, 0x752c17fd, 0xefd61c2e, 0xafef6b97, + 0xca4d7b32, 0xfa3fefad, 0x77bb1a58, 0x6c2b1f46, 0x7fdc9a22, 0x36bfed92, + 0x3ec596f2, 0xbbf9ecee, 0xa47eeec5, 0xd7196bbe, 0x05eca672, 0x3476bf28, + 0x100fc57f, 0xce2389bf, 0x5133aa1a, 0xa60fdf5f, 0x13dac1d4, 0xbce9cba5, + 0x3fe72eff, 0x5b23be19, 0x905b60e3, 0xd6fcf394, 0x6dadac73, 0x299d18d5, + 0x9a9759a7, 0x287bf1d4, 0xa67ea1b3, 0x6cd239b8, 0x41232cef, 0xb91f6f3d, + 0xdd136e71, 0x0e8523bf, 0xf44b4e9b, 0x4bad7e76, 0x4958af6f, 0xecf76134, + 0x8474baa0, 0x7b439903, 0xf9f79d18, 0x516e0701, 0x403ca797, 0xa69a2672, + 0x2977a73e, 0x288ad1c8, 0x2a664c9e, 0x873f520f, 0x167e5fc9, 0xf284b3e3, + 0xfabc0bff, 0x7018c06b, 0xad6ddf60, 0x7a4fd794, 0x647fbb75, 0x2aad2ddf, + 0x199952e2, 0x40eb4ade, 0x917bd8d6, 0x8ef9afc9, 0xd52f7542, 0x4eb70921, + 0x263907b7, 0x74198eff, 0x28d4d537, 0x1d064bdf, 0x384afbe5, 0x4edd87f2, + 0x7e601fd8, 0x315e5320, 0xfba9cc7d, 0x8bc00d81, 0x711defe3, 0x3cf6473e, + 0xbca67917, 0x9633b305, 0xcefc57ff, 0x6138a319, 0x14e4bfbe, 0xe10b3f8b, + 0xec979cfa, 0x4c9fceac, 0xbfc86b17, 0xb2afbd3b, 0xa0a6ebbc, 0x40e4c032, + 0x8c7e2849, 0xdbee751e, 0x2a4dfcc9, 0x7ffe9d5a, 0x103b677d, 0xa68c7564, + 0x3bc691e7, 0x8b77299b, 0x7b9338f0, 0x4813977a, 0xe37b89ce, 0xbbd8854f, + 0x7c445492, 0xdf3af28e, 0x7ca6bf26, 0x7dc91ca6, 0xcd6edcbe, 0x7be4a2f7, + 0xf212f6d6, 0x7f51c403, 0x3bb813c7, 0xfeb2cf57, 0x9aabe90c, 0xa09da7bd, + 0xa231b638, 0xf525a7bf, 0x3bc0ffde, 0x0f61b7a4, 0x5ad7638b, 0xcece533f, + 0x0f0cc313, 0x2487f394, 0xa79c8a5f, 0x7eef2983, 0x3ecfc713, 0xbebf1215, + 0x38c2897c, 0x3c4cdf7b, 0xc448b177, 0x5ec79df5, 0xd276473f, 0x33ffd469, + 0x739da9df, 0x9acc7eb0, 0x6f1a7ded, 0xc97c9485, 0x6f9fae69, 0x04c7aeb3, + 0x886cfc99, 0x0af291fc, 0x5e2927bc, 0x8be4f79b, 0x69c19d46, 0x4d78b1af, + 0x6efd91e7, 0x5f7654e3, 0x7d05ef99, 0x5447de1c, 0x2cdd2b97, 0x79d70b8e, + 0x17cfb224, 0x74e306d1, 0x34e4d8ff, 0xa33c2ef6, 0x54e79d8e, 0xd93b253e, + 0x1e5356f2, 0x6f83b9d5, 0x27ea32ac, 0x36a91efd, 0xce9ab2ec, 0x1943fe27, + 0x32a93eec, 0x4571abf8, 0x0cbade58, 0x177f4154, 0x1e19de30, 0x7752cd7b, + 0xa2bf07fd, 0x17f0846b, 0x000017f0 +}; + +static const u32 usem_int_table_data_e1[] = { + 0x00088b1f, 0x00000000, 0x51fbff00, 0x03f0c0cf, 0x33ab678a, 0x32ea7830, + 0x31e9c830, 0x43d24c30, 0xb712d388, 0x9fa65173, 0x8181859d, 0x81b98813, + 0x5f881798, 0xbc303231, 0xff5e2466, 0x3b046147, 0xe181804b, 0x0b6f9013, + 0x32089fa4, 0xb2075c30, 0x0371033f, 0x88073f90, 0x35b10057, 0x480fbf90, + 0xa3e204df, 0x1845fc40, 0x095ff9bf, 0x42156fc8, 0xe3443fe5, 0xafc4159f, + 0xf980825f, 0xb1e40472, 0xe42269e1, 0x0a6dc7c7, 0xde040ef4, 0x67ca86a6, + 0xe0606553, 0xaac58a07, 0x91dbf843, 0x6281f3e4, 0xf610aaec, 0x8606396b, + 0x1db9405f, 0x7dcdd86a, 0x0dff9403, 0x9a86ab94, 0xf1b90003, 0x03685054, + 0x00000368 +}; + +static const u32 usem_pram_data_e1[] = { + 0x00088b1f, 0x00000000, 0x7dedff00, 0x45547809, 0xbedd70b6, 0xe9d3bb7d, + 0x84849d25, 0x1674b090, 0x26c43510, 0x630a0840, 0x944c2127, 0x615151a8, + 0x8408ec44, 0xf9707d90, 0x37d7d470, 0xdf95012c, 0x3e30eb89, 0x0e0c1a74, + 0x1036a0c3, 0xc6c06a30, 0x680e8300, 0x8cc08378, 0x364584cb, 0x5c710921, + 0x7f9e6466, 0xbb75539d, 0x48e9bdef, 0x9bdffc74, 0x3f6fef37, 0x556ea2bf, + 0x5b3aaa9d, 0xaa753a9d, 0x42049462, 0x1be426ae, 0x71f4d1f8, 0x10921091, + 0x69f2bb4e, 0xb910963a, 0x96bfca27, 0xff6e0d56, 0x401904fa, 0x5be6b9c8, + 0x4254e65c, 0xc1513d3c, 0x39f969ab, 0x4cdf9e7f, 0xbcb60bcb, 0x7cd230ef, + 0x08d116f5, 0x16ed86e5, 0x4ab9df6c, 0xd6be43f0, 0x55d8fedc, 0x45bddf34, + 0x68286b24, 0x2066ceb2, 0x889c8439, 0xb467ec22, 0x2122481b, 0xad961665, + 0x1663bd5e, 0x62de57f4, 0xfeda1626, 0x81e8b344, 0x82b582fc, 0xaafed09f, + 0x4a665b5f, 0xf9e6f0a6, 0x45c58085, 0x371f6bf3, 0x2c84ecb9, 0xa381feda, + 0x19c846c3, 0x9971145f, 0x81e51e70, 0xfc2a424c, 0xd324a71b, 0x041b15f6, + 0xafc281b7, 0x13be7558, 0x2cd157c6, 0xbc29170d, 0xe25675ca, 0xfefac91a, + 0x6d7f4086, 0x2dbfb0c7, 0x57f40652, 0x136ee17e, 0x929e6111, 0xd355da07, + 0x95bcc071, 0x1af8cf7e, 0x18446b89, 0xa1bfd59f, 0x357ad1fd, 0x986e0b2f, + 0x78818d62, 0xaf9d1c61, 0x60bfa659, 0x9bd5f983, 0xf3d5d846, 0xf30add28, + 0x36aff0a8, 0xf8c1b14d, 0x32ca9b56, 0xd72af0c3, 0x515c493d, 0x4cadf1aa, + 0x9555e81f, 0x3e33d3eb, 0x054f19a2, 0x06c05925, 0x6e9bf678, 0x7efe151c, + 0x7a458858, 0x3513ae57, 0xf1e529f0, 0xfd3efcbb, 0xbc83c527, 0x9b5feecd, + 0x02dba61a, 0x2bb7fd27, 0xa71eb74c, 0x1ceec742, 0x7d257c35, 0xc741e80c, + 0x6273e8d3, 0x092f84fa, 0x2e7ca7d3, 0xbe33d3a4, 0xf4ae9891, 0xb3fbf1b9, + 0x574c5cbe, 0x3e983cf9, 0xd4c22bef, 0x7ac12bef, 0x31d37c6b, 0xf179f26d, + 0x72be8bfb, 0xeaf9d74c, 0xdf7afbf0, 0xf8374c42, 0xb2fefc64, 0x01a6396f, + 0xbe4da74e, 0xfb369895, 0xab6f58fc, 0x2da61d6f, 0x5f7e00be, 0x98e7f1c1, + 0x748cf248, 0x710f0efe, 0xb8937252, 0x449e4f62, 0x2c2571f3, 0xce53389f, + 0xa27cd133, 0x3e29e697, 0x7982ab92, 0xae4f9a66, 0x1f43e563, 0x3451f924, + 0xe566543f, 0xf93c2b69, 0x6b4f9a16, 0x5623e564, 0x34d1f9c9, 0xcacfc23f, + 0xcc10db2f, 0x65fcd2b7, 0xd59e5601, 0x346c0a4a, 0xf964159f, 0x029ebdec, + 0xb767cd3b, 0x87ce7cb3, 0xe6838172, 0x7b583a73, 0x1203de3d, 0x6d284d99, + 0x3c8b959e, 0x6f3441c6, 0x37137722, 0xa37c8bc5, 0xe28138c7, 0xf9617241, + 0x5827f976, 0xc2e4c9be, 0x367976f2, 0x1e4b3796, 0x572a3f2c, 0xc9b37961, + 0x917fe583, 0x56fcc5ef, 0xa6e58bc9, 0xfac37ffa, 0x2c5e4d5b, 0x865faa4f, + 0xc64916f9, 0x1beacbf2, 0x498b7eb1, 0x9627f2c6, 0x9933d2fc, 0xef04fb96, + 0x8b67c053, 0x49396f05, 0x2409fe07, 0x69fe5095, 0xe074c810, 0xc98107d7, + 0x20fcd1c6, 0x605dca13, 0x200bce57, 0x001bf8af, 0x1f17b2f9, 0xcf384549, + 0xc2891c21, 0xc70e2f11, 0x03573bbd, 0x5cbbbdc7, 0xd422f381, 0x1fe96c5b, + 0x2beec09c, 0x5dd9e3b5, 0x0579c0a1, 0x37fbd8e1, 0x26eff72f, 0xbbf3c76a, + 0x0b4e052a, 0xdfed89c2, 0xd3ed3678, 0xbed367e2, 0x20767e10, 0x37fa127e, + 0xb577ec9e, 0x377ec9f8, 0x70779f84, 0x07fa833c, 0x5abbd367, 0x377a6cfc, + 0xe03f9f84, 0x6ff48678, 0x69efd95e, 0x5efd93f1, 0x221f3f08, 0xc1fed49c, + 0x8b5f7e69, 0x43f7e69f, 0xe104f9f8, 0xbcdfef0c, 0xe2d41ec6, 0x10c1ec67, + 0x3f113a7e, 0x4e0ff697, 0x7e2d41f3, 0xf0860f9a, 0x678e25f3, 0x35e6ff54, + 0x3f1690f6, 0xf0850f63, 0x33800443, 0xd9e37fba, 0x3f1691fa, 0xe10a3f5b, + 0xc67082c7, 0x393c6ff5, 0x93f16b1f, 0x3f0871f3, 0x42670871, 0xfd6ce0ff, + 0xad9f8b58, 0x93f0871f, 0xf5267082, 0x7f395e6f, 0xe727e2d6, 0x64fc21cf, + 0x3e3c9c20, 0xd8e1421e, 0xf2d386fb, 0x2d3f1689, 0x33f0849f, 0xf214e10a, + 0x4e045cf1, 0x7e2d09ee, 0xf0844f72, 0xae708393, 0x969c1fe9, 0xb4fc5a13, + 0xe7e1089c, 0x5d73846a, 0x7b95e6ff, 0xdc9f8b52, 0xa33f0c93, 0xc1b496f7, + 0x40d7437a, 0x4c9b48b7, 0x08f1ee38, 0x64e8beb4, 0x26e9d179, 0x8a888760, + 0x3dda417d, 0xdb6fad22, 0x08fd9b10, 0xf919db51, 0xec78c037, 0xdb52fad4, + 0xd1b93119, 0xd62bbb1a, 0xc7c9a713, 0xea6b2517, 0x69a49427, 0xbf4e07ca, + 0xc83e534c, 0xa7c9ad9b, 0xa9a95f94, 0x5f2ea43f, 0xf0b61f93, 0x54fd4d5a, + 0x3e4d26f9, 0x344ff97d, 0xde3787f5, 0x64bf29a5, 0xfca68565, 0x4d02ff52, + 0x3f75f2fe, 0x151fd4d3, 0xbf29a458, 0x4d11e5a2, 0x13e0e8f9, 0x3d98fc9a, + 0x8fea6acf, 0x29a35f6b, 0xbd787f1f, 0xc7427ca6, 0x529e4d26, 0x72e279c2, + 0xcf81179e, 0x07ebb309, 0x0b9ed099, 0x37984dda, 0x4ed0db25, 0x5ccbda0f, + 0x4d1d29c7, 0x006baf06, 0x8486814d, 0xc979dbae, 0x507497e5, 0xa577df3a, + 0xfd2712f7, 0x7bc99f7e, 0xfd823385, 0x902fe949, 0x065d4824, 0xcbe5f548, + 0xf97fc624, 0x1c461729, 0x0d6beda1, 0x696223dd, 0xf790cbbe, 0xf1f94094, + 0x7c80c159, 0x3a922d19, 0x266d17a8, 0x4b2ff768, 0x564179cd, 0x21f2e7f1, + 0x3084ee54, 0x3792e5dc, 0xe78aec09, 0xc193dfeb, 0x421868ce, 0xc84c95e7, + 0x82f784af, 0x3f6d0672, 0x4bc92ca4, 0xd44d99e1, 0x6ff7570e, 0x6267fda2, + 0xffd04dff, 0x37fa3efa, 0xfa6ae5a7, 0xae5a1a8f, 0x44ca3fe9, 0x3b5277fb, + 0xef10feb3, 0x4ae9129f, 0x0e115e42, 0xa1e6ff61, 0x32ffd8e5, 0xa88fdd13, + 0xf50e8ffb, 0xf1f20cdf, 0x109ff43a, 0x5769fe61, 0xb43fe76a, 0x137f3b42, + 0xfaf6ff9b, 0xa3fef33f, 0x0a6ffe71, 0x1ff3667f, 0x6fe6c15a, 0xfd437066, + 0xdff8423b, 0xa77ff309, 0x4fa7f9af, 0x587fced4, 0x66fe7695, 0xf5bbffd6, + 0x36ff7927, 0xe13dffec, 0xb0ff9b24, 0x64dfec2a, 0x7f81baf6, 0x75d1294c, + 0x193fda7e, 0x40d1154c, 0x0fda1760, 0x28e323a4, 0xb0f21313, 0xb8e38690, + 0xdbf19a2f, 0xdf94d117, 0x88c8bf50, 0x9aa7e21f, 0x6a43ee8c, 0x6e542cb8, + 0x1e8133c8, 0x1fba72c2, 0x3a87cb99, 0xfe4445a7, 0xfd994f26, 0x3b78e9c3, + 0xf219445b, 0xe49a9e73, 0x6b577d07, 0x40967726, 0xc209233b, 0x1e9e4ff7, + 0x2f3d46b5, 0x51b73a7d, 0x91a1d13a, 0x391e362f, 0xa3ac8c9f, 0x26042be3, + 0x9fce1718, 0x421dfba0, 0xe94711f7, 0x93d2027e, 0x7e8fed12, 0x43f74e3f, + 0x9b96a4c4, 0x64476c7a, 0x7419fbcf, 0xe512b7fc, 0xde79c1e7, 0xe1452281, + 0x4ffe1919, 0xd0357dd0, 0x95a36e63, 0x1e3c3f22, 0x6f9c1f3a, 0x5fe0a977, + 0xd2bc7023, 0xf6f1b7f6, 0xe147c604, 0x36b272cf, 0x0f72511f, 0xb79f28a2, + 0x67035e32, 0x4d2ff106, 0x5f6feda2, 0xb42243b1, 0x74a141ce, 0x97e002c8, + 0xc4122407, 0x0247647d, 0x40cce4c9, 0x0c9d7be1, 0xa5d36dfe, 0x382a1de3, + 0x4f28a4b3, 0xaccf1d09, 0xef1c45fb, 0xbcb6af0c, 0x63d5bb63, 0xcae9a2c8, + 0x494224cf, 0xb6b97b7e, 0x6d3a8efc, 0xda85cefe, 0x098f9d3c, 0x5952b5d6, + 0x874e9dff, 0xd0aef3ce, 0x69c4e9bc, 0x9b2f367e, 0x35925cbd, 0x686d8474, + 0x034f2f0e, 0x13c413b4, 0x5def4fb6, 0x2681f29f, 0x0ea56f3f, 0xff8be71e, + 0xddffff4f, 0xc96daff4, 0x1aae3f8b, 0x9ae07557, 0x7aaae3f8, 0xd46eeb95, + 0x67fbe7e4, 0x5bcfea68, 0x9f29aa59, 0x535f38db, 0x4ff97b3e, 0xf952f935, + 0x3bfd4d7e, 0xca6bd617, 0x587ba8ef, 0xf97b7e53, 0x0cfc9ae3, 0xf5352fef, + 0x5abe9b6f, 0x9f6c2e53, 0xd703ac3f, 0x41b0ef4d, 0xa3fc0fe0, 0x299f0099, + 0xfbf0acfc, 0xa6125f29, 0x4c2e7c67, 0x530f41eb, 0x8d786efd, 0x4a6bb5a5, + 0x573e8187, 0x54a4fff8, 0xa5f41437, 0xfaf59f9e, 0xf4a7cf57, 0xcec91297, + 0x812ad250, 0xd63ac094, 0xe55eedc5, 0xcebe39fb, 0xd308b211, 0xcb93132a, + 0xf2834daa, 0xc1f20389, 0xbeb67511, 0x808092e1, 0xcde020f3, 0xa5ba004c, + 0x4d4bb5d0, 0x38cd74d7, 0xb110eecf, 0xc9901aff, 0x94dcb009, 0xff40326c, + 0x37a1b6c1, 0x78f1828f, 0x25be6336, 0xb3aded01, 0xe3f8a2be, 0x095fc046, + 0xd37ca7a6, 0xf3e13d31, 0x57dc7a62, 0x5f51e98e, 0xbe1da61d, 0xec7e9885, + 0xd0fd3193, 0x3fd31cb7, 0x3d311af9, 0xe9895bec, 0xd31f9f41, 0x53079f4e, + 0x55ff4f85, 0xf0ca3ae8, 0x73d74edf, 0x328eba6a, 0x3878d938, 0xf1851f5d, + 0x939bb046, 0xa71918c1, 0x563c47b2, 0xe02eabf4, 0x896a70fe, 0xef2b3f31, + 0xd705317b, 0x7f8b768e, 0x9ee1e824, 0x011b7f91, 0xc39ee47e, 0xed480174, + 0xfa7a7e7b, 0xe20789f5, 0xccbdfb41, 0x3187174f, 0xd12dcbbd, 0x0316af0c, + 0xd4d92229, 0xa2fe1b5e, 0xcc4caefb, 0xb41c491b, 0xb46fbbf7, 0x6d4b8047, + 0xc5efc041, 0xfed8baf0, 0x3bc01645, 0x39d7ecf1, 0xa4328e90, 0x4db8bb31, + 0x0494bb44, 0x7e03705f, 0xecd67a43, 0x6d3f024e, 0x139370f7, 0xb8a7bdd7, + 0x9fc15a9f, 0xfe0af2cc, 0xafe10e1e, 0x97f10931, 0x14bfc5f1, 0x3ba788fe, + 0x6151a6eb, 0xbe139dfc, 0x39ca7f1d, 0x1bbfbe89, 0xe277e344, 0x0544aecb, + 0x0943edaf, 0xe02de7ed, 0xa7bf0a7f, 0xc01892f9, 0xd93ec873, 0x87f7f662, + 0x4e80e74e, 0x6abc30b6, 0x3d9ebc1d, 0xeec0382f, 0x7064905f, 0x67808f1e, + 0xa40ead25, 0x3b6a6d3a, 0xef9b45a9, 0x028a1469, 0x62b8cf68, 0xfd028da6, + 0xcf1e74eb, 0x84993d00, 0x416702a9, 0x3c79c992, 0xe4c3e91e, 0xca2c437a, + 0x145f19fd, 0xc7a1fbd6, 0xf09c17d1, 0x31c99a38, 0xf9501eda, 0xf5df7a4d, + 0xe353e4fb, 0x37e04c5f, 0x17d2ad23, 0xd144bf60, 0x0381bfff, 0xbcc46232, + 0x2036b702, 0xe02be6ca, 0x7f4d06fb, 0x394b9db4, 0xed26fbc3, 0x48c1e4db, + 0x4afc284e, 0xf0468a97, 0xbe038d49, 0xf6b538b5, 0x5f26ac51, 0xa9c832db, + 0x1fe097b1, 0x72928f54, 0x577c08c1, 0xcba6d9c5, 0xd02e5b68, 0x538255f1, + 0x6055f80a, 0x3aa3aaf5, 0xf0175e4c, 0xaf5be2cb, 0x46cd4172, 0x7c7eaf9c, + 0x1a377e94, 0xbf8f7d8d, 0xafb9ec52, 0x6c7c8224, 0xcabb7ae1, 0x240afcc0, + 0xf9c0764a, 0x1d924917, 0x6871d937, 0xd07e10b6, 0x51fb470f, 0xf33815e5, + 0xd6b752fd, 0xcf91957e, 0xbf981acf, 0x6eefdf40, 0xe2e137e8, 0xb0d9abf8, + 0x5bcc0a7f, 0x969ac78f, 0xca2f26f3, 0x272ffd15, 0xbf05478c, 0x6ec96295, + 0x58afc291, 0xd5f70477, 0xc47924a7, 0x17a2df03, 0x96df8f7b, 0x9aaac274, + 0xa1da4cb7, 0x7972bb9f, 0xdb75c447, 0x9f5f5407, 0x1e44bdfe, 0xa05cba01, + 0xa0e354b5, 0xe4310516, 0xbbf5ed84, 0x618b2b9a, 0xfb0d3efd, 0xe72faa15, + 0x38071290, 0x6349cb1d, 0xe7e7d80e, 0xf008a188, 0x87fc8e74, 0x4e8a8c63, + 0xe2134467, 0x47efda89, 0xf6a3e3d5, 0xed4f26bb, 0x8cbe4d77, 0xe70894dc, + 0x494f65d9, 0xfce02fc4, 0x127fe534, 0x79f7489d, 0xec01aea4, 0x5b12c59d, + 0x1272efd7, 0x5f1d0a63, 0xe5cfabf5, 0x79fcd294, 0xca23d991, 0x38fcec79, + 0xc08afe36, 0x9687936a, 0x731e6b1f, 0xda0455eb, 0xfd601bfb, 0xee08b791, + 0xf8deaeb5, 0xd7e3aefd, 0x87b1578f, 0xf30b9d7a, 0x13af5471, 0x7648fe3c, + 0x8533e711, 0x4e8c631f, 0x45237f8d, 0x9744bf97, 0x7fcba31f, 0x401f796f, + 0x295ef234, 0xe38c537a, 0xfec37c98, 0x2376304e, 0xf86f7f3f, 0x5fe0bd49, + 0x1fc283f2, 0xd13393ac, 0x8507e63b, 0xfc6bd19f, 0x5f824757, 0x5b4beafd, + 0x2a9faa65, 0x41da795e, 0x6d3a7ea8, 0x53744c6c, 0x5dad57fa, 0x383e00ea, + 0xc01d9465, 0x62fda7cf, 0xbe823f91, 0xf0a8d7bb, 0x8026c783, 0x49fe0dff, + 0xff599fe1, 0xaeb0f5e8, 0x7256b17f, 0x9d6d5fa2, 0xf2a66839, 0xbf3cd35a, + 0xfe616498, 0x3b2fcb08, 0x45be422f, 0xbf159fcb, 0x85d13a7e, 0x314e52fa, + 0x8838ffa0, 0xd34d7ff6, 0xdd605327, 0x28dd25af, 0xd076fa67, 0xb87157ff, + 0x629a953e, 0x46e3977a, 0xb3da113e, 0xa3f36d5f, 0xfc0745e7, 0x06fd03ab, + 0xdce5fafa, 0xda332f8e, 0x1afea007, 0xfe83c64f, 0xfc41f052, 0x5f178ecc, + 0xfc0b2e7d, 0x7e9b67a7, 0x785410ef, 0x27ace452, 0xaf57fb30, 0x97d6fabb, + 0xd50e549d, 0x4f62a3f6, 0xfef85ab8, 0x55a595a3, 0x1571d052, 0xab5593d5, + 0x3f4cb725, 0xc2f4bd57, 0x3f82cf8b, 0xf7668ff3, 0xf2bf0a70, 0xaf075da5, + 0x8dcaf9a4, 0x366280d2, 0x18909b0d, 0xfd2d4ba6, 0x9876617f, 0x779b150e, + 0xd8a35c99, 0xc2e307f7, 0xb8dca8f4, 0xf54644c3, 0x604147c6, 0x16c3a987, + 0x23812e81, 0x12fec053, 0x09bbfd5f, 0xbb7a7ee8, 0x46a60640, 0x5deae7c0, + 0x9e019f68, 0x4e9c8e90, 0xeae9ba21, 0x80ba52d7, 0xa4e8573e, 0xfae22f2f, + 0x32b9e004, 0x7e5f9f91, 0xfe84e21d, 0xfcc37664, 0xdbbe5fcb, 0x6938f301, + 0xfd7c63ac, 0x0f44d2dc, 0x925cb7ed, 0xb2989d13, 0xdfcfe5ef, 0x6f36fc8b, + 0xcc89bdff, 0x6419e58f, 0x1e49b5c0, 0xbb9bf304, 0x5f9c16ea, 0xdf22f119, + 0x96273f95, 0xdcfc7e80, 0x46368a48, 0x8d4f8b90, 0xb9380ecc, 0x74b81a86, + 0xb2e9277e, 0xff337183, 0x14fc6221, 0x3f453f21, 0x2e7cbdd9, 0xfcc382d4, + 0x4e8c51e7, 0x5c0d196f, 0xaf15a8ae, 0x65a6d7e6, 0x339f40ed, 0xe1033c43, + 0x1896a5bc, 0xe10f8e65, 0xdc570a1b, 0xd190385f, 0x398cb887, 0xc3b51dbc, + 0xd43be00a, 0x963c976f, 0xf23b4d2c, 0xffb86a4d, 0x74ff787b, 0x3f60d1dc, + 0xbc8c4c9d, 0x2928180f, 0x71d74f72, 0xe4a97f15, 0xd37bc99b, 0x15be4cc3, + 0x58dff779, 0x397fe504, 0xda07e4c0, 0xc748fac1, 0xe5881c15, 0xa809a63b, + 0x1824cc0f, 0x249bae49, 0x72dad72e, 0xb8e84f85, 0x8a8c428d, 0x1c7e005f, + 0xa6ed1fe2, 0x3b68a7b2, 0x85acbe95, 0xe1bd1cfe, 0x8f3b7229, 0x9009ffcb, + 0xf2c3cbff, 0xb931564f, 0x95bedbef, 0x92553f11, 0x4167c5ff, 0xca7ca95e, + 0xa957902e, 0xe9fde604, 0x3f83b686, 0x69f272a1, 0xad539140, 0x69cbd4fe, + 0x097ba6f9, 0x4e5ea7f0, 0x475c1d3f, 0xfd29ca22, 0x074e511e, 0xea97fc77, + 0x0e7f054f, 0x153fab49, 0x1e17d87d, 0xb7f0faf5, 0x53e21746, 0xefe90faf, + 0xcde9c900, 0x29df0a7f, 0xdbf156fc, 0x77a061ea, 0xf0a97c42, 0x152f885d, + 0x57cfd3be, 0xf97d3f8b, 0xd199f061, 0xf6bc9571, 0x4a1494fe, 0xc156aacf, + 0xbb61766d, 0x78a790dd, 0xbfb330f2, 0x00ca7771, 0xcbafde75, 0x3df57407, + 0xae897cba, 0xaf9757be, 0xb3f7d5d3, 0x9b4b487d, 0x041f2089, 0x45a5f535, + 0xfc738644, 0xee226dee, 0x98e8bbbb, 0xaefb681b, 0x997ea90d, 0x16a583ea, + 0x4eefbfb6, 0xfe803530, 0x3b7672ea, 0x616f20e2, 0x92aeb5fe, 0xcaac476e, + 0x2ad23c3e, 0xf0edfea2, 0xfb48a293, 0x22d16a13, 0x5f483a9e, 0xa3bcece5, + 0x5d0db450, 0x46977e08, 0x81ae0dd1, 0x39b7f539, 0xaba1bce0, 0xe986fd35, + 0xb7dcfbf4, 0xe85f0c45, 0xc164768a, 0x31ec88b8, 0x0bed520e, 0x99f9114e, + 0xb33e7489, 0x60fed95b, 0x5d9d0ace, 0x5f205641, 0x31eed994, 0xf6a45e81, + 0x9fad51fc, 0x0577f19e, 0x4abe5787, 0x57b4ae5b, 0x4d158df6, 0xdf2f72da, + 0x5c495667, 0xa3268c5f, 0x308f3ed9, 0xafd7093f, 0x0de66285, 0xbbfe29d3, + 0xf80488f6, 0x4455a7a5, 0x106cf7fc, 0x226fe0fc, 0x4dca0272, 0xbd46e90d, + 0x2ce9e0a6, 0x6fa985c8, 0xcb7673bd, 0xd00f3947, 0x3f5b552a, 0x9a77fac8, + 0xc7fadd9e, 0xfe406f11, 0x3f4343d5, 0x17ebbd20, 0x79e0b76c, 0x3b76d76e, + 0x6d76afc6, 0x01f437db, 0x7666bfc8, 0xb6bb38c3, 0xfc05997f, 0x5cc8b5d3, + 0x6bab7a0e, 0x2cd7db08, 0x5665f6de, 0x4b93ae07, 0x90bf6e90, 0xa7aabed8, + 0x858febf5, 0x59d29001, 0xddbffac1, 0xda9dfe8a, 0xa7182dd7, 0xcbedb5db, + 0x87edaf1c, 0x3f0d4f9b, 0x93b2efbf, 0x7c609be9, 0xba7cecb1, 0x2f098df6, + 0xabfed3d4, 0x6698779b, 0x3782f2d3, 0xfa059eff, 0xb3136bb0, 0x8ea53a6b, + 0x7a7ce1e7, 0x8bedd2cd, 0x4ee78a24, 0x42648a10, 0x4df0d47e, 0x09199cbe, + 0x7f477f2f, 0xf1f17f53, 0x7c18ffda, 0x53ef1808, 0x47f76ad5, 0xbfef3009, + 0xe801fc7e, 0xe466ed81, 0x9fbe654b, 0xeed1ea06, 0x0fbcd8b8, 0xfdc7bcc3, + 0x085bcd2b, 0x5fde67f6, 0xfbd393fe, 0xe385c921, 0x6f41cbd3, 0x1f76df3e, + 0xbbb25fe6, 0xe4fdbc71, 0x7fa681f7, 0xa26fba31, 0x7c5c7774, 0xe4ff39de, + 0xee9beef3, 0x74e2cf6f, 0x8c7de277, 0xe38eff37, 0xee7aaefb, 0xf3a1ffd6, + 0xb373ec57, 0x8f3da4a1, 0x693a6f8e, 0x316183b4, 0x2f67a123, 0x8799c484, + 0x8c0065fc, 0x8ae7e257, 0x332df1fa, 0x048ffdb1, 0x5fb4c6e7, 0xf7c08b72, + 0x743f6c75, 0xae1fb73d, 0xf6865c1f, 0x661ef5e8, 0x496313af, 0x8858de49, + 0x46e39aff, 0x3ec9273f, 0x2dfc85ec, 0xbb5e7893, 0x20577c2f, 0xe3da811e, + 0xda2d0fd7, 0x0de9f603, 0x33418d83, 0xfa408f4b, 0xcf7f83be, 0x665feed5, + 0xdbf9b578, 0xb7f36ba6, 0x82b77870, 0xbffb4571, 0x83f044b5, 0xf21a535f, + 0x39f80254, 0x1112b9a5, 0xa9138804, 0x84fb0a5b, 0xedb44a5b, 0x767ec367, + 0xf38f185c, 0xe153bca3, 0xa46a21fc, 0x61b8f880, 0x24fa8885, 0xf840532a, + 0xc612b925, 0x28627e13, 0x173c01c9, 0xf35f198f, 0x0dce0633, 0xf1cf9df3, + 0xd0ea4655, 0xbe1721de, 0x0e6266f9, 0xda0973f8, 0x843df34b, 0xf5ed475c, + 0x304289b2, 0x3ce5ca9a, 0xb2639123, 0x9029cfc1, 0xa73f1aa3, 0x1fbf0f36, + 0x5ce18625, 0xfc5f7eac, 0x7fa743f8, 0x347ffca6, 0x90cdda83, 0xf33bb9e2, + 0xaafb29d7, 0x1e195b3b, 0x7f04ab6b, 0x5055f21a, 0x7c539f52, 0x85fe626d, + 0x06383f3f, 0xe7ef2ae5, 0x7ed862a3, 0xcced032f, 0xf6676e5a, 0xf018aec8, + 0xa6b4f46f, 0x02b1f3f3, 0x3f023787, 0xadfbe7ef, 0x3ef9c03f, 0x0b26bb4d, + 0xfdd8228d, 0x78fd1ba4, 0x590b64f2, 0xee0e211b, 0xa7e29303, 0x1ffdc3a8, + 0xa01cc4fc, 0xa3cdfb23, 0x54e2634d, 0xdd715b74, 0x6f566369, 0xa8efc03a, + 0x1fe83cea, 0xefec2fc5, 0x2dfbaf00, 0x224a531d, 0x971cf7cc, 0xfeb7e2df, + 0x6eb5f78a, 0x00954d6a, 0x164d372f, 0x9fa6e735, 0x75bef898, 0xe303190c, + 0x1aeb7e2a, 0xcba004c7, 0xf70dd11e, 0xcf5b6ab3, 0xce11bc9b, 0x04f8f48f, + 0x97dfe8f8, 0xcf8065dc, 0x42c7ff63, 0x8fb59f60, 0x4264e79f, 0x6e2674bc, + 0x4fe03de5, 0x75e382fa, 0x7489d9aa, 0x4f38b9be, 0x66fda04a, 0xc3473b36, + 0xaf325691, 0xad16153f, 0xc11c1071, 0x92f529da, 0x23bd58ab, 0xa44d6726, + 0x128a2ff9, 0xfb8579f8, 0x9fe15cbe, 0x3f796e8f, 0x61f307b7, 0xeecc993d, + 0x6be6f5d5, 0x53d1f282, 0xdf41f824, 0xf309fec3, 0xe03eecc5, 0x972b033e, + 0x597a626f, 0x9e3d7be1, 0xcf0ccdd3, 0x3c05ff4a, 0xf0ccd23f, 0xc159e0a3, + 0x4abc7eaf, 0xaeafaa7d, 0x6e21fb56, 0x32fd1968, 0xad3587ac, 0x4140d382, + 0x4c3b18d5, 0x2db58720, 0x67e04b8f, 0x7062e19f, 0xa5907ae9, 0x6a9dd73e, + 0x6debe766, 0x02cd57d9, 0x056cf93e, 0x7b684bb5, 0x0ef39ccf, 0x19f77758, + 0xbdc1efdc, 0x915df949, 0x7d16fdac, 0x79cf81f5, 0x1aa364ed, 0xf38e2a6e, + 0x093caae6, 0x57b726dc, 0xaa0690ed, 0x39aa69f8, 0xef95cb0e, 0x6cae55c9, + 0xc3fb4ef8, 0x998fc871, 0x6787c409, 0x3ef1da06, 0xb175edda, 0x03cb0f8c, + 0x4f984c3b, 0x7f4afac5, 0x797a3f4a, 0x8dac569a, 0xd05d99fb, 0x52f01831, + 0xe3de0e6c, 0x9da7c08e, 0xbbe40e9c, 0xca1e13ae, 0x8bff59b7, 0x947b89d6, + 0x2a43a275, 0x6c89c551, 0xa73d3335, 0x4606275a, 0xd416275a, 0x1d0206bb, + 0x1f4b6c16, 0xe0b24208, 0x48c4c2ed, 0x3efbc4eb, 0x88785e76, 0x9aecdfdf, + 0x2b89d746, 0x34c4eb54, 0xbe89f20b, 0xc4acdf9d, 0x9d645d61, 0x5ff6e850, + 0x87de6fac, 0x7c822275, 0xd76b366f, 0x4b5b5b89, 0x75b89d71, 0x57b9a89a, + 0xb17cdeb1, 0x712f2275, 0xb725e606, 0xbcff0235, 0x43e1edcf, 0xfa0ebe3c, + 0x34e2f581, 0xde84ffe8, 0x7a5f46eb, 0xeafeb1fd, 0x3c26fff5, 0xc17d7a2b, + 0x781eec2d, 0xc8243e6f, 0x50660bcf, 0x3f002ebd, 0xe0bebd32, 0xd317ee0e, + 0xd012d9e9, 0x7ad563b3, 0xf1afb596, 0xb6a175b2, 0x3317f525, 0x1a4ff969, + 0xad147725, 0xdeb093ff, 0xddeb51cd, 0x1377a0d3, 0x72dde822, 0x6b3f77a6, + 0x53f6831d, 0x88fbf35f, 0xcfaa5beb, 0xf811dc32, 0xab4cfa63, 0xb1ce9ee6, + 0xdccbbfd1, 0x4fb2f20c, 0x4fbb73c4, 0x77b01db8, 0x82c6eff4, 0x144a7a9f, + 0xa71c4f1b, 0x5c8fa767, 0x81ea993b, 0x9ecc3982, 0x2220deae, 0x999a6afe, + 0x4464d7fc, 0x3f345dfb, 0x26affb25, 0x636e57c8, 0x06746fe7, 0xfa2a79c5, + 0x68ebee57, 0xe5703f00, 0x0fcf016a, 0xf019ce21, 0xb3e38f39, 0xfb895dcc, + 0x80fc7d15, 0xe6ad17e2, 0xaeb7e6f5, 0x3ea9ff46, 0xe33aa0ae, 0xafb0d3da, + 0x3a333628, 0xfc166f14, 0x1ce153ab, 0xfdcf575b, 0x541b9e30, 0xc7dfb407, + 0x15cef9f0, 0x619b9983, 0xe89ef55f, 0x8dceb48e, 0xfca5e3d1, 0x7ecbc41f, + 0xffb1978a, 0x17d2f1ef, 0x8f7da81e, 0x3e3d64fe, 0xbd7145c6, 0x82c64d92, + 0xf0627e1c, 0xdf915ea0, 0x642e3111, 0x35c3e3ce, 0xa20bfef7, 0x67dabe98, + 0xdc4036f0, 0xe2c35cae, 0xdaade647, 0xe6912bb8, 0x68c80667, 0x5bcf4770, + 0x43875da9, 0x0bb37eeb, 0x7599f5d7, 0x1388051b, 0xfdefcb9c, 0xc71ffb94, + 0x58ee12f7, 0x5a79d748, 0xd9b6767f, 0xfb9fe70b, 0x37a8dd2d, 0x105dbe15, + 0x3a97ecc5, 0xc9638e3e, 0x7d7193dd, 0x289c116a, 0x5b0b418f, 0xe09d28af, + 0x09b6871d, 0x74e14e5f, 0x16887e61, 0x4a5ac746, 0x29e79037, 0x8ebf3cad, + 0x2bb781d9, 0x77e080f9, 0x7757a009, 0x085dec48, 0x9c0bc481, 0x11f5aa08, + 0x12f2d5ce, 0x76de7455, 0x5afff184, 0xfc1f8dc1, 0x43efbff4, 0x9ef93ee7, + 0xe5fd31d9, 0x0b4f0577, 0x6fde7474, 0x831e2f69, 0x1b8233e7, 0x8d68c7df, + 0xe38573c5, 0x079dec8d, 0xcbd3b799, 0x5c3bec05, 0x8dcabf2a, 0x1f887030, + 0x9c60b22d, 0xc69bf61e, 0xbded32ec, 0xd7135940, 0x4ee35df3, 0xda3b496a, + 0x3178e163, 0x802637ef, 0xb5182457, 0xc8dd5c71, 0xfc003fe7, 0x02dfcdd7, + 0x3139249f, 0xa76ef46e, 0xeec9ddf2, 0xdb7cf06f, 0x33439c90, 0x5b3f7e29, + 0xdd79e22e, 0xc1d7066d, 0x1e6fa089, 0xcbc80891, 0x0f257b67, 0xb8ac075b, + 0x3bee94ee, 0x4a5ef786, 0x2911ec59, 0x2fad887d, 0xfe78f8c7, 0x0f6dd744, + 0x604844f8, 0x4dfbc41c, 0x7428ef73, 0xec64df81, 0x2e70a5fe, 0xf3817376, + 0xe7a041e0, 0x93bdecc3, 0x700bcba3, 0x4ff7769f, 0xc3b79405, 0xfed06e94, + 0x07a96996, 0xef7ed20f, 0xe7809e58, 0x093d335c, 0xd7b9c2b7, 0xdba2bdcc, + 0xbecdeb45, 0x73836ec1, 0x4523a9af, 0xe7e155e2, 0x7e8ed20e, 0x3f75999a, + 0x5dc605bd, 0x3143d74e, 0x85fdd215, 0x4abf2103, 0xb2b5f6c0, 0xb29034d7, + 0xf3cafb4e, 0xffb4b1a6, 0xd00f5a32, 0xd58abb5e, 0xdc126dab, 0xd65b7a10, + 0xcbea38fa, 0x1f0126b2, 0xf6a76896, 0xeb83146f, 0xdb70a28f, 0x34f6d157, + 0x03da0f3f, 0x5bd8a6dc, 0x96ab3ce1, 0xe7db138e, 0x6479e3d6, 0x8b476d19, + 0x4fd37b49, 0x55fcde11, 0x447b8102, 0x8fa9b9e5, 0xbdbc02e5, 0x0fca1b92, + 0xc625f8ed, 0xfda2cc8d, 0x67f0a20d, 0xe8851d8b, 0x70407b57, 0x83233be2, + 0x5d7e9033, 0x70686130, 0x64fd0d3c, 0x42e9d718, 0x71d51834, 0x1616c908, + 0xb0b65cdf, 0xd5e601be, 0x1aa42721, 0x9bceaf90, 0x4e3f1d60, 0xf6a5edf1, + 0x8b1331eb, 0x8f93686f, 0x7a543a99, 0x1d25bc74, 0x969cd8f5, 0x9f2f3c3c, + 0xbcf04a4b, 0xeccf5bdc, 0x2d4b2391, 0x30ec017e, 0xbe1439c9, 0xe3352db7, + 0xd897cef7, 0xa439d3fa, 0x27a1fd03, 0xee044957, 0x955e2d39, 0xf1d00cfe, + 0xf90906e4, 0x424e7c4d, 0x25ef363d, 0x5b6b27e6, 0xbc9ee0c5, 0xcfdec4c7, + 0x9f9a7281, 0xff651bf7, 0x6563d5ab, 0x53d40aae, 0x2bd4bd7a, 0x7aa9efee, + 0x2f6cb013, 0x14cf757d, 0x741557d4, 0xeb4601dd, 0x3706afa5, 0xaf52bfa0, + 0x4d896aaf, 0x10d953d1, 0x3d5a5237, 0xe04ad664, 0xc0583be3, 0xb5f07b76, + 0x75869fcf, 0xe04ecab7, 0xf9d18d4b, 0x82f8c08c, 0x6cccbc80, 0xc839f8dd, + 0x0b4cf941, 0x0273bbbe, 0xb37200e8, 0x59c59e22, 0xdf114bf9, 0xbce51c4a, + 0x573e5a95, 0x7867b5ce, 0xaf51e245, 0xe256e55f, 0xf43bd551, 0xda57e510, + 0x822d9dcf, 0xfe4022df, 0xc77beec8, 0xe389de62, 0x83edc85a, 0xe7e47615, + 0x5f9ff743, 0xeb3afc0a, 0xbd808141, 0x036f644e, 0x2b3587ac, 0x65f81705, + 0xdac83de7, 0x61eda3cf, 0xc97e87dc, 0xb7f28af8, 0x66bff80b, 0xb1bbe3d5, + 0x02e0937e, 0x975687f8, 0x2e513da2, 0x9bcb048b, 0x81fee08e, 0x5f1853ae, + 0x898b26d4, 0x4b35ffc0, 0x95304ecc, 0xf8523e14, 0x17bf08f2, 0x59dca24d, + 0x9f76d337, 0xde849000, 0x174e28fc, 0xf029eb42, 0xf8ccad49, 0x924bc8ec, + 0xe2e6d81b, 0xc3eec97c, 0xabebe49e, 0x532ddcf8, 0xd73cc106, 0xb68638b2, + 0xb0260555, 0x05fa4e23, 0xcdef8f3c, 0xb6a6c497, 0x7cbe14a3, 0xfafa604e, + 0xbda87162, 0xa5f38ef8, 0xa9947fc2, 0xb5595f71, 0x0f702257, 0x5e8fcf57, + 0xc42b7029, 0x4cbe940b, 0x5bc743e7, 0xda3f70d0, 0x691e0aeb, 0x65f2113e, + 0xa1ef1646, 0x91b543c8, 0xe77d05c5, 0x37fae9f1, 0x7961ec5b, 0x4adc5910, + 0xbbfbf690, 0x9c602f0d, 0x47f5b9dc, 0xe6fb47ae, 0x8007ca0d, 0x12760dff, + 0x1f87fdc4, 0xb34550f5, 0x4238c1e8, 0x66e73063, 0x895dbed5, 0xc57ca897, + 0xd8aef88e, 0xd317f664, 0x8f5b15f6, 0xf5f9e165, 0xe78c6ea2, 0x680bd790, + 0x23b9131f, 0x546fee0b, 0x86dc5918, 0x64582ede, 0xb3aa7e61, 0x83a759af, + 0x63ac26dd, 0x045569ef, 0x2acc936e, 0x16fdeebf, 0xe787a949, 0x33a53229, + 0xf18693dc, 0x5271dfa9, 0xfece35e2, 0x455ff186, 0x5cf6848b, 0x9d8dbac5, + 0x71577f10, 0xdcfb8cd8, 0x31e775da, 0x95e0b89e, 0xae1df097, 0x135116da, + 0xee2bd57f, 0xe7889d69, 0xd5cd351b, 0xf341bf18, 0x1351ce78, 0x77ff1c88, + 0xca9cf8b1, 0x956db657, 0x372b0a29, 0xef81daff, 0x75afb572, 0x7593bde0, + 0xd8771edf, 0xf029ce2b, 0x39c6b7f0, 0x507f819d, 0x45adfac6, 0xd644e71b, + 0xc746bd31, 0x9ee91397, 0x7adec841, 0x21e7f3e9, 0xa6ecf70e, 0xf1879f4f, + 0x67e7fd56, 0x061c43cf, 0x82716ed9, 0xfebb523d, 0x54638c7d, 0x30b2edda, + 0x37f3affb, 0xcff8c6bf, 0xdd9a3fce, 0xdb73ad00, 0x6f60a1c9, 0x6bfc6e74, + 0xde75c422, 0xfd10adb3, 0x296cf739, 0xf8224818, 0xf814940b, 0xf88fdfd6, + 0xdabd3d53, 0x5e30db9a, 0x37a51ce4, 0xdc5087e8, 0xc59aa05a, 0xbc78ba01, + 0x71c886da, 0xd3e2bdbe, 0x61be6f9a, 0x66c5e812, 0x345c1766, 0xa500ed4e, + 0xa0fd15e3, 0xb98786df, 0xbf4c893e, 0x4a0ff073, 0xfa3a63a7, 0xf73cde7d, + 0x5942cf57, 0x719f7c73, 0xe07ec16a, 0x0e23894d, 0x169d3c58, 0xbf4d9b90, + 0xa040b8c5, 0xf40bb15b, 0xc143e7f3, 0xea4a7c2f, 0xf743ff46, 0x5bde3336, + 0x0876d8ab, 0xcb73a7e5, 0x25d38c7e, 0x93b79e3c, 0xfe2c7e84, 0x6a7afb92, + 0xbe2cec9b, 0xe21fe38d, 0xfc0e5cdf, 0x18dce3ce, 0x6ff12b1f, 0x0dbdc57d, + 0xefe34e8f, 0xbcf8b02a, 0x780fa6ea, 0x5e98591c, 0xe9d02e42, 0x13c6b7c8, + 0x0270782a, 0xe3abc61e, 0x17c72338, 0x397de286, 0xa07e80bd, 0x9a7143a7, + 0xe2183f34, 0x21c2fcf6, 0x741f4112, 0x9ff166ae, 0x1ef6929d, 0x2c3e9868, + 0xad15d3ae, 0xff7f5393, 0x362f39e2, 0x9f8aeffe, 0x269768d8, 0xd3c151ae, + 0xf5910bd9, 0xf0b44178, 0x9a93dd8f, 0x05efe823, 0xc02747e4, 0x1311f979, + 0x7c5e7bc1, 0x37dca4ff, 0xb3b4fee2, 0x0b8c45eb, 0xa1b4086c, 0x8bebd71e, + 0xa24e7e1a, 0xd12def1f, 0xb4d54f4c, 0xece275b0, 0x46dfbb26, 0xeb7d9ce1, + 0x9ae7e435, 0x324c470d, 0xdd7bb785, 0x2b8b1366, 0xeb03f260, 0xfe355f84, + 0xc8ef2fb3, 0xdfcdbd42, 0x33f7d215, 0xdb53f79b, 0xda9fb91a, 0xfd35e70d, + 0x9301ca54, 0xfef176d3, 0xb73d18ce, 0xed33bc01, 0x133a5ecc, 0xdd228b10, + 0x2d12998b, 0x2373fdf1, 0xf5d373f3, 0xb257df12, 0x4494f7b3, 0x5fda3447, + 0x0f73d8f7, 0xd4800cc7, 0x8b127184, 0xc55c79eb, 0xa024ee43, 0xb5fb62f7, + 0x14bbc604, 0xc7daabf0, 0x012f4e4b, 0x2a4a4dbb, 0x673eab19, 0x1a6fc651, + 0x157e2060, 0x17b1effd, 0x27fd840d, 0x6183ca31, 0x7da7d71c, 0xaff58469, + 0xf7fcc7dd, 0x0cb1c2e4, 0x746edef8, 0x70a78aee, 0x6e0b27db, 0xe6f6bd70, + 0xe43f067b, 0xdf68f04f, 0x7a588485, 0xdb8f5f98, 0xdda0f680, 0x2ad27410, + 0x4f696ec4, 0x8bac0dc2, 0x18898cb8, 0xe8718f02, 0xa6a2f88f, 0x073abdc1, + 0xd429e6a1, 0xef351b73, 0x1ae4c424, 0x9026ef75, 0xbd741903, 0x557e71b1, + 0xf67672fc, 0x03b70a6f, 0xcd8863df, 0xbec0f524, 0xb45eec2b, 0xefe49e1b, + 0x48dfd058, 0x23886788, 0x3bf56ed1, 0xcd5fb42e, 0x5fb410fb, 0xa3d63e4d, + 0x1917c7cd, 0x5f5a478f, 0xa638f9e2, 0x43c43688, 0xd941a16c, 0x4f0f15af, + 0x363b8f0c, 0x5083b881, 0xe30d9d7e, 0xc978a9c0, 0x6cd879ea, 0xf1d371da, + 0x4c44f469, 0x606c8766, 0x777cd4e3, 0xf3809712, 0xd3bf68f7, 0xdbf26af1, + 0xaa3c79a3, 0xdf411891, 0x09daa2d9, 0x068f7fc7, 0x7b8c4bdf, 0x7d022487, + 0xcb57df08, 0xc411ee04, 0xfed079f0, 0xe09df535, 0x6bfd601d, 0x4ec190e1, + 0x2bbf7df5, 0xccb7faf8, 0xe81ef25a, 0x75619c9b, 0x313bc818, 0xbde26489, + 0xa801d6d5, 0xe616d29f, 0x2f346393, 0xcabe3234, 0x6e504158, 0x9c59ba32, + 0x8d12590a, 0x8a39a8f6, 0xb86c96c8, 0x296444c7, 0xf3f17a1b, 0x22d725f3, + 0x5c650503, 0xb68d794e, 0x37ceed6b, 0x0844a5cc, 0xbf851140, 0x31f3da37, + 0xa370dff4, 0x1a30c937, 0x74b7de3e, 0xda9460e7, 0x6823c14b, 0xb5ddee10, + 0xe90b0867, 0x089af781, 0xf01777b9, 0x4f286378, 0xbacf7082, 0xf7943a31, + 0xdf7d5144, 0x67f2c698, 0xba5defa3, 0x3fbbc29c, 0x346ce4a6, 0x79ca278c, + 0x05779e19, 0x17fe70e3, 0x71945f5b, 0x98ea6c8e, 0xf9963d12, 0xcf1de14d, + 0x3dd0f6e1, 0xd7875c6a, 0x107c94da, 0xcd2511f7, 0x55af51fb, 0xb963f607, + 0x1d34f201, 0x2531df16, 0xeb109625, 0x930b4ba3, 0xfd78852e, 0x9d0324d2, + 0x974780e7, 0x60fb82ee, 0xa23c3c61, 0xb0d183c1, 0x499ed77c, 0xdf2c3c6a, + 0x7f487605, 0xbac030f1, 0x89f2e97c, 0xe5379ffd, 0xc42b788b, 0xf019e43b, + 0x87f1a5dd, 0xa15fe86d, 0x47ae0b3f, 0x3eeace1c, 0xfb2abfee, 0xc5270a11, + 0x5fcc2e3a, 0xaf853b4a, 0x749be2fa, 0xbd8cbce2, 0x9fe5a7af, 0x0327ab62, + 0x7ab70de0, 0xe1c6d9f6, 0xf63ef1fc, 0x3dd7af54, 0xaf984c79, 0x063bcd89, + 0xb32ef7ee, 0xaaca35de, 0xcd4ecbf2, 0xd1a6205b, 0x2c8166f1, 0x93e78424, + 0x8cb650b0, 0xf04cf3a0, 0x7ace3018, 0x063bd599, 0xef4c71fa, 0x8495d20e, + 0x31de009a, 0x0b961882, 0x6d86bfa5, 0x50debf6c, 0x622ff06a, 0xc002bde7, + 0x8747f30b, 0x19ba3f8e, 0x411cb47f, 0x3d69a8fe, 0xa5a3f8c2, 0x0bf81f3e, + 0x9f60cdce, 0x47ba48df, 0x79afdd03, 0x48d0a9b4, 0xb5987ff9, 0xf28521bb, + 0x14d64485, 0x788a5f16, 0xaf8c31fd, 0xf8f87d17, 0x45f57994, 0x693dc6df, + 0x7ec2668f, 0xcf01af72, 0x85bc14bb, 0x8b2b07ec, 0xf7641c23, 0x6a7e834e, + 0xc3763b73, 0xf9ed37f4, 0x70db8c0f, 0x0769bdec, 0xa34c77b4, 0xfb857214, + 0x08bbdc6d, 0xa46dcbdf, 0x319000f3, 0x75865ba4, 0x307c6fbd, 0x03e109f9, + 0xc04c9eec, 0x979411c7, 0x109efcf5, 0xffbc3b95, 0xdecacc3a, 0x65679865, + 0xac07e7fb, 0x1d994f22, 0xc7b7b096, 0xdaadfb04, 0x9fac0625, 0x7aa66900, + 0xdeb04bfe, 0x26a35603, 0xa7a14e5e, 0x93544fc2, 0x877de15a, 0x3def588c, + 0xb389fe5a, 0x29e0a9a6, 0x11f31eed, 0x4a0c9cf7, 0xdd779d87, 0xe52aeb0d, + 0xed351b9f, 0xc0164946, 0xf81f529b, 0x687d1233, 0xae8c45bb, 0x17b05671, + 0x205cee36, 0x7f42f9c2, 0xef039ae9, 0x39fad1c7, 0x89b75256, 0xa189cfb6, + 0x79e3e429, 0xa7cf207e, 0x43fd34b0, 0xdfa041b7, 0xebbf7357, 0x171e56b3, + 0x065e7460, 0xcb3c53ef, 0x29313af1, 0x4505d71a, 0x8066c16e, 0x3f236b73, + 0x4eeb4ebf, 0x14dd0033, 0x1b763639, 0x68ba7682, 0x065d19a5, 0xc7786388, + 0xec6de747, 0x7b5cef5b, 0xa7bfbb29, 0xa732feff, 0xafb6f7f3, 0xaf75eabf, + 0x4ba065f7, 0x63c75475, 0xcd7cd137, 0xf9e19fa5, 0xcd6b22e0, 0x3b73ea55, + 0xff1faa7d, 0x3a4e173b, 0xfcec3ec0, 0xc9145cca, 0x32b0eece, 0x6f8f77fb, + 0xec53b63a, 0xe815242e, 0x413df564, 0x5768a633, 0x1e5508fd, 0xc63651d0, + 0x656afac1, 0x75aba4fe, 0x147f03f7, 0x42bd7e64, 0xf41238d2, 0x5fd58e64, + 0xe5c38b8c, 0x481718e9, 0x51f662be, 0xce0ffd14, 0x79f90a97, 0x73b0e798, + 0x397f2c27, 0xe3938d31, 0x2a4c7ea0, 0xda23cfc2, 0xe272b9f7, 0x5de82365, + 0xf08a9e92, 0xe574a20a, 0xd1da0903, 0x30cb92e4, 0xa890ab9e, 0xbe3a31ec, + 0x6fc6749c, 0xba964753, 0x9feff327, 0x6cfaf301, 0xd61319c4, 0x66b8d7f3, + 0xec6b27b8, 0xe8374694, 0x5dffdfed, 0x3c5233bc, 0xe31b78c5, 0x12be3dc7, + 0xeb339c37, 0x12ef9af1, 0xbd5dd896, 0x9fc7abf1, 0x3e0adf1e, 0xfbcb78f5, + 0xce393dd0, 0x7a3f1bd5, 0x5074287c, 0xc7c7acf0, 0x8a6ff03b, 0xcd3277af, + 0x3bdacef8, 0x77df8646, 0xdec8b9a8, 0xfda0f46d, 0x43c7c85a, 0x4fb457ed, + 0x6eec120b, 0xe29e1ec6, 0x78f0c4c2, 0xe3d578f5, 0xe3bf8731, 0x7c446242, + 0xe0377447, 0x0161f28b, 0x7ed04c1c, 0x7099b60b, 0x578248ff, 0x06fc7513, + 0x47be061d, 0x17973577, 0xd6392f05, 0x00b19dba, 0xe78a9ccf, 0xa57f57d7, + 0x5b0b67b5, 0x7f069ca7, 0x778c4e40, 0x8941f809, 0x5f384a98, 0x15f2d51d, + 0xd535971f, 0xa8eaf9cf, 0x9198af8e, 0x0bcacf13, 0x74f2ba9d, 0x85507e82, + 0x56f3f4ef, 0xf815ebf8, 0x9e37a130, 0xb2cafe14, 0x993bfb71, 0x387b060c, + 0x31b1b5eb, 0x6b499fa0, 0xc3bf445c, 0x2125c3f8, 0x914f9c38, 0x0de2050f, + 0xffa6777d, 0x9daa7a03, 0x3f2a82ae, 0x5bd10cc0, 0xa7a08b60, 0xc4993e14, + 0xc88935e9, 0x347fc03b, 0x12ff1889, 0x5553f7b2, 0x99e657f3, 0x9e605242, + 0x4c5d58af, 0x8679f3bf, 0x47cd4de6, 0xde44fba0, 0x1b28c4ff, 0xdd20b7de, + 0xfc21b3c6, 0x32bbe1a7, 0x3c2e29b2, 0x27d7890e, 0xb308eb43, 0x7be266d7, + 0xe42f14b6, 0x1c786b1b, 0xc4609b5e, 0x38f85677, 0x928badce, 0x79ed4e21, + 0xec073bd1, 0xdec2b3b8, 0x319f9c2c, 0x37d60238, 0x2d67f97d, 0x9ca06b3b, + 0x7ac32bd6, 0x2295fc7c, 0x6f742ff3, 0xa4d7fb33, 0x52876df6, 0x4075c671, + 0x70899f91, 0x900af15f, 0x8c0a60b7, 0xca586afb, 0x7cfdba68, 0xf2fbee39, + 0xd08db25a, 0x299eaecf, 0x4f9f9718, 0x5fb0463c, 0xe7af7cf5, 0xeb3f3d6f, + 0x8fec37f9, 0xfb0a1ee8, 0x2fcaef90, 0xe2169d8a, 0x6f94c39b, 0xc29beb54, + 0x1e7f942f, 0x8d75bc05, 0x3019e4fd, 0xfd8df7ab, 0x37d6112c, 0xdb0f0ec5, + 0xa0c79e1b, 0xb8f65f5e, 0xbbff8762, 0xf034fbcd, 0xcf7491a3, 0x2369f682, + 0xefb8065d, 0xf3cdb6fe, 0xec577c0c, 0x2bed8b93, 0xe1ba4ec8, 0x8b337ca5, + 0x206021d3, 0xbcabdef8, 0x753d4040, 0xa096e907, 0x24ea3bbf, 0x9675fecd, + 0x07e3fba5, 0xfeb03ce0, 0xf2078c12, 0x889a9442, 0x715c59ed, 0x31efbf03, + 0xe0047bb2, 0xda85cef5, 0x64d8f8f6, 0xcd5df84e, 0xafb6058f, 0x48e9659f, + 0xa5b47b80, 0xbebeb6b2, 0x7a1e657f, 0xb576fab8, 0x78219dfc, 0xb2add8b7, + 0x31b55e0b, 0xde34263b, 0x03bbf877, 0xf006df14, 0xea5eb4d7, 0xff02247f, + 0x2a37a92a, 0xaf18d32e, 0x99b62fb2, 0xff7a47a7, 0xc147e943, 0xaed24cf7, + 0x916ff3e0, 0xe89a2fde, 0xc37dfb65, 0x79cd4153, 0x746692bb, 0x2ebb464f, + 0x1da02023, 0x33c8155d, 0xf3d8d6cc, 0xcbdbbf6c, 0x2977879e, 0x0ef37ea0, + 0xea07cf66, 0xd5505f71, 0xab37f6cc, 0x99398ce1, 0xed13240f, 0x15bed0fc, + 0xe1aaa0e2, 0x1e563f9d, 0xe9e6ab84, 0xd7feac8d, 0x87a685b6, 0xe9df6033, + 0x34dc924d, 0x86a1e2bf, 0x6a3fba28, 0x42162548, 0x5d7f47f7, 0x1594d0f1, + 0xe2ca54b9, 0xc589023c, 0x426d837c, 0x5fc9f7ff, 0x01b078af, 0x7f74c9f6, + 0xed5363d5, 0x8f92fb5b, 0xe21736e3, 0xeafdafb1, 0x5f2531fd, 0x077e54db, + 0xa27bfd3d, 0x7fc0315c, 0xf47df30f, 0xc2ef0bb5, 0x92e581fd, 0xde21430b, + 0xbba7226b, 0xa9fdced9, 0x3acf7656, 0xed9af45f, 0x5d6fdf20, 0xe27e0118, + 0xc31e4677, 0x7f2b597d, 0xafaf716f, 0x8523ed1c, 0x6676718e, 0x697b5fd7, + 0x15f6039b, 0x03fb8dd7, 0x673f0fde, 0x9d99ef64, 0xec6935cd, 0x856c87d8, + 0x495f0071, 0xd044da29, 0xeec713cb, 0x7ceb0c3c, 0x5843eb5f, 0xd0047bff, + 0xfec2e4ff, 0x69df3c44, 0xbf00e5de, 0xdf7e59cd, 0x5b735cfc, 0xad345de2, + 0x0707f8de, 0xf9d2a7ec, 0xdb19cefc, 0xaa9b7df1, 0xcbbe222d, 0xbc4dfb40, + 0xcdc7fc1d, 0x611e73b3, 0xd7a944dd, 0xd5dfc23f, 0x49bfec50, 0xaf9fb251, + 0x12df8a87, 0xbab8e1df, 0x1c58f459, 0x73c0edbd, 0x2c9ed27b, 0xc9107a06, + 0x1a3e1c3d, 0x0bb44ec9, 0xfd0df9f9, 0x7ef784ed, 0x9bccf3b7, 0x7cdd9fcd, + 0x73913215, 0xd802e5c9, 0xcc01de47, 0xb0f4c739, 0xfd5dbf62, 0xa93fd695, + 0x5bf31fb7, 0x21492f47, 0xdef60f88, 0x1fc9b77b, 0xec2ecec9, 0x9ed1129e, + 0xc471e424, 0xf496f657, 0x4cfef0a9, 0x2706dbf6, 0xcec83bf4, 0xf9b6b1f8, + 0xa51f7c33, 0x856f0486, 0xd1669af2, 0xa6df2419, 0x1efc979f, 0x57545efe, + 0xbe02e4ab, 0x15dd6aed, 0x16f90595, 0xb55dfd11, 0x0e5e26fb, 0x2ad9d67c, + 0xb5213be1, 0x80713edb, 0xf7d6501e, 0x7ef656ce, 0x31eb5748, 0xedc0aefc, + 0x1cbf896c, 0x068d9dd6, 0xb9dcbfb6, 0xd0566ffb, 0xe85e6f0b, 0xad7dc789, + 0xb6f73eb2, 0x052f117f, 0xbfe43176, 0x44bfdb55, 0xe200789c, 0x24630a9f, + 0x3b610a22, 0xfcfad7b5, 0x27625921, 0x7ce9d7bd, 0x08c5f758, 0x37c735eb, + 0xfc08cfed, 0xefbf5fae, 0x6a7b73b5, 0xf786c908, 0xc42e5af5, 0xcdbde257, + 0x1173ab56, 0x5d985ffa, 0xccf3b5d2, 0xfbe15313, 0xdbdd915e, 0xdf2220bf, + 0x72bdb5bf, 0x8d4d8758, 0xd7a406f7, 0x77ce8317, 0x7feb41be, 0xf99a2bb1, + 0xcbee8da3, 0xc206f7d5, 0x5f1cfdf5, 0xae7664c1, 0xbbc32725, 0xeedbdf38, + 0x2ef5eeec, 0xb47613d5, 0x80a7bb3b, 0xeab11dfa, 0xc5f40988, 0x53c97b20, + 0xac040f4c, 0xe4991780, 0x6fda10a7, 0x07c93479, 0x27aeeafe, 0xdba3884e, + 0x0060c7b2, 0x9b5d8cba, 0xeb2ef18a, 0xfcdfb9f9, 0x5529a340, 0xf3e65fa5, + 0x9253a373, 0xf54e343c, 0xf4c1d93d, 0x155da9c0, 0xf93d42bf, 0x1e193347, + 0x1bfc5d61, 0x4d9b67d7, 0x500dd4f2, 0xf701a8ef, 0xbf773b1b, 0x69de1bbe, + 0x35d87f9b, 0x0399d61a, 0x5eb40f20, 0x0df5decb, 0xf2db2f10, 0x6aef4121, + 0x68a9534e, 0x41befda0, 0x760fcc5c, 0xe0fb80c0, 0x7890ff90, 0xfb9e61e2, + 0xf9bf6ced, 0xe6831ec6, 0xfe0de99c, 0x765be83e, 0x33b7c189, 0x3da6d43f, + 0xb7a0f1f9, 0x6fbdd907, 0x8f6b1e00, 0x5c383477, 0x6299bf61, 0xb0384d27, + 0xfa28ea69, 0x0d6709cf, 0xebb7204e, 0xe6111ac0, 0x48453aeb, 0xd97a40ac, + 0x2ede144d, 0xce37bc35, 0x1c747832, 0x2a9c816f, 0xef2ba7f8, 0xff3499a3, + 0x0e31bb46, 0xfc14a4e2, 0xfa50f32b, 0x67880577, 0xc9450db5, 0xfc5be9b3, + 0xe69c4ab7, 0xde512718, 0x9cbe4727, 0xcfbcf76a, 0x3b4641f8, 0x68aed4f6, + 0xf33647b4, 0x95248c75, 0x29fc030e, 0xa782fa74, 0xeafa78ca, 0x075f3cff, + 0xf2bbf494, 0x25c97af5, 0x77f0df23, 0x30725cfa, 0xb1e21d2a, 0xeff1d25a, + 0x55e2a8a1, 0xa93e03cf, 0x87f8d602, 0x060c3a5a, 0xb3554fb8, 0x67c5884d, + 0xd769fa42, 0x18ccf886, 0x396bfe40, 0x2b8e504c, 0xf994fdd6, 0xe1bea8ef, + 0x79e157ef, 0x3f0fc834, 0xd0241e97, 0xeaeb4274, 0xdf8829c5, 0x2ae403a0, + 0x372a278c, 0x9a35d690, 0xdfe75f80, 0xfc79d2c3, 0x4afe777c, 0xd967ca2f, + 0x67a7162a, 0x38e2a475, 0x257e71ce, 0x8864e886, 0x1bb068e3, 0x4fc9f134, + 0xdd3dbe70, 0xf41b64fc, 0xd62bf94b, 0x6cafcb41, 0x1819fc79, 0xa7afc2ae, + 0x5384249b, 0xff3dad1e, 0x7830744e, 0x7e300e5b, 0xe524d09f, 0x1349fbc3, + 0x7f04e264, 0x6b4d1bf0, 0x6fdfd045, 0x32a73f00, 0xfd758739, 0xac47aed4, + 0xeef5833f, 0xdf808188, 0x9489b379, 0xc5c9546f, 0x6aafd5ce, 0x5d62b7e4, + 0x6ff454fd, 0xa009c477, 0x55b915e7, 0xe4d9bef0, 0xffe506be, 0x4ffc9d7a, + 0x418bed66, 0x27bd6858, 0x593ffcb9, 0x7e9fe544, 0x158a6d8a, 0x5366ce00, + 0x26b4f7e4, 0xff1fbe39, 0xf1eaf485, 0x92757a5e, 0x1de7ed83, 0x9affb4e9, + 0x3f707aeb, 0xe71f1a1f, 0x2b27279b, 0x002a937c, 0x05291bfe, 0x145f0033, + 0x68cfc0af, 0xcdbe82b7, 0x8277c34b, 0x22e3f37a, 0x234ddce5, 0xa6bd61b7, + 0x06f7afc8, 0xe4ce4f18, 0x5f60c5ba, 0xc8cb17c7, 0xef05a7a7, 0xaeba38b0, + 0x8e79069d, 0x394617a0, 0x42f91e98, 0x11de6af2, 0x920e3def, 0x4e5d7c0c, + 0x2f306a77, 0x02704ab2, 0xd772947d, 0xe09fbe2a, 0x4aef94f0, 0xfde37bfe, + 0xbdfcbd2f, 0xb8718e55, 0x6420999e, 0xad9f8473, 0x47c84467, 0x6b8620b9, + 0xe6de4193, 0x27ec75d3, 0xb4ec75aa, 0xaafc88d4, 0xce3ee1e0, 0xb2c45fef, + 0xfce70f79, 0x3f6c0d31, 0x173f37c4, 0x81468c13, 0x3028b5c9, 0xfe011779, + 0x5e575de9, 0x5d7f7c83, 0xdcafbe64, 0x33f91ab0, 0xf789c8b6, 0xba349e41, + 0x9199b12d, 0xd31fb1f4, 0x817f6b9d, 0x63e02bfb, 0xe4befb90, 0x80e41ca0, + 0x3f7fe044, 0xfd157fe5, 0x7ca03e14, 0xa54384f1, 0xa17cf427, 0x7829df9c, + 0xff3bacd9, 0xf5c1c8fb, 0x7d5d4f3c, 0xf328a1c4, 0x3e74def9, 0xbfce8bdb, + 0xcb0e7461, 0xd15bd017, 0x9c818f13, 0xce5beb8d, 0xac4e316c, 0x6cd1f0d7, + 0xe468fb8c, 0xde0140e7, 0xe7dd685f, 0x39d7d9fc, 0xf7ab32ce, 0xe0fe3575, + 0x1995d1bc, 0x6e428fe6, 0x6b582ed7, 0x8df473c6, 0xbcb3c984, 0xbeafda33, + 0x5234e9a7, 0xfaa29403, 0x09e7d01d, 0x21070ab8, 0x22685aef, 0xf83f7419, + 0x4ee96a45, 0x71f9a788, 0x8a3c5cbb, 0x49a363ce, 0xee1d769e, 0x00d7dc0b, + 0x0d8a6bfc, 0x88af884e, 0xf00538f5, 0x004ba043, 0xeb2f70e4, 0xfbba4c67, + 0xbaafdc72, 0x1f4063dc, 0x52f4e01c, 0xa1e0abe8, 0x2faef5af, 0x9862daba, + 0x72f0245c, 0x99791ebd, 0x4f034dcb, 0x6447ae2f, 0x41c9e411, 0x18448bbc, + 0x07a644ff, 0x22647a43, 0xcfbe73c1, 0xf3e47a75, 0x7c8f5e1f, 0xb923d1ae, + 0x08f5111d, 0xff9445fd, 0x68b9a684, 0x91c392cf, 0x862959ed, 0xb009c7ad, + 0x097ad28e, 0xa1fbfb32, 0x52df3807, 0xc438c48e, 0xc63326c6, 0xc87a2b5d, + 0xc3e48d31, 0xc0753bdf, 0xa6b50bba, 0x824f0f79, 0x9324d7f3, 0x4f83ce0b, + 0xf748dd4b, 0xdcc374d3, 0x2251fc88, 0xe823bd00, 0x0b7e0223, 0x99834ff9, + 0x456c5ddf, 0x48505939, 0xb9dd1d70, 0x55f23c76, 0x009a7179, 0x2eb15b7c, + 0xb8f28056, 0xe8034ec9, 0xe31e652b, 0xc6481a17, 0x94839418, 0x8c1c9518, + 0xc044eb97, 0x6f78b0d7, 0xc84b1492, 0xff4f3165, 0xb9b7ed58, 0x7ed5e684, + 0xf65f9a1b, 0x9736fc5d, 0x65c9fcfd, 0x73c9b7e0, 0x8cc64678, 0x65cdff43, + 0xac0ce690, 0x6f4a8913, 0xfb8ecc5d, 0xcb52fcbe, 0x40e443fd, 0xacec7f2f, + 0xc7f42e75, 0xd47c024e, 0x06789f24, 0x153be1c0, 0x366eed11, 0x2f5c018e, + 0xd2090f90, 0x9d494063, 0x4512fe08, 0x87035cef, 0x1ed428ae, 0x1433ce01, + 0x85bd0379, 0xce3c6ee7, 0x7655fc01, 0x91fbd7f4, 0x931f208f, 0x2b47d61d, + 0xdf110d8a, 0xc633be11, 0x67ea83f6, 0xd6f5fad2, 0xf8f0e59f, 0xe9e5115f, + 0x3d9518ce, 0xd1f164f4, 0xc10e7644, 0x9bbbe5de, 0x45abf1f7, 0x192ef7ee, + 0x615f7e10, 0x4324d9b4, 0x10f1293c, 0x4f155397, 0x410ab42c, 0xfea7c43b, + 0x746e760d, 0x0337fdbf, 0xb7fabfa6, 0xb054a292, 0x6e0c5be7, 0x7c41196a, + 0x7b83ca05, 0x267bc118, 0x616efe01, 0x23cd9b5e, 0x8843bf81, 0x3da0f7e2, + 0xdc8df3da, 0x681ba1ee, 0x3356e2f9, 0xaebdcdfe, 0x1eefe53c, 0xb21ef1b8, + 0x7dacdf82, 0xb8c48e4f, 0x1ba3634d, 0x858d6ce4, 0x51635fc1, 0x6062bbea, + 0x1cebeebd, 0x64c2e27d, 0xfe29f7f4, 0x41dd89c5, 0xd692f011, 0xe0b032ed, + 0xb18fd635, 0x957ce09b, 0xc700f5f3, 0x9b3de6fb, 0x73c75844, 0x862e3726, + 0x764bcefd, 0xf3c00aef, 0x76b51395, 0x0ea158de, 0xb9246eff, 0x493ee086, + 0x0ef88f91, 0x9a4c03b2, 0x1e1dc3d8, 0x9e573d50, 0xfd80ecf2, 0x11094c64, + 0xae2a9e00, 0x5f2017e7, 0xb8478064, 0xbdfc006e, 0x08b7fe4e, 0x7bcd9c39, + 0xf79005f2, 0x0593ed01, 0xfe6f6657, 0xeefb095e, 0x04fe2cb1, 0x07ecaae8, + 0xb2f6fd87, 0x534fe0c9, 0x618d6fea, 0xaf2afc7a, 0xc45c00b7, 0x422f3e74, + 0xfba613bf, 0xa929e0db, 0x9b72e5f1, 0xcf9aa5c9, 0x52f0827c, 0xc79c643a, + 0x3cdec3a0, 0x62d9f748, 0x4f2bdfb1, 0x656e3105, 0x70c11d60, 0x07ed219e, + 0x521a7ed0, 0x1d002ed7, 0x0b79ef37, 0x7db83bc7, 0x5cb94b27, 0x80f6e26d, + 0x367dae32, 0xe3ee5eb6, 0xe70dd1e7, 0x7af97ad8, 0x92e3178c, 0xe4347994, + 0x28ea9379, 0x6f1095fc, 0x78efb633, 0x4263b79b, 0x016f36f1, 0x77a76abd, + 0xd3de06ec, 0xf7120dfb, 0x247a451e, 0xf1db642e, 0x08177b95, 0xce5627a0, + 0x5037ec8c, 0xee4ac5f4, 0xb5c55577, 0x5aa317bc, 0xc696a72f, 0xfa54d359, + 0x4cf76948, 0x3365ae38, 0x53796b8f, 0x52d46ed3, 0x0cd3f00b, 0x8c10e79b, + 0x3f7bf95b, 0xd1dff9eb, 0x0ab1f651, 0x0c9d52be, 0xdcc7af5f, 0x8dce0fb8, + 0xca4e4f00, 0x912debc7, 0x9c13c3e3, 0x306f6e06, 0x8ced217e, 0x6a1e605f, + 0xb702ebbb, 0x78f2ae3b, 0x4f8c8c0b, 0xc93e453e, 0xdf01b7f5, 0xdb922f8e, + 0x1087ff80, 0x8c4527ce, 0x1efcf44f, 0x7ce38ced, 0xef004dd2, 0xb1bde163, + 0x3ff1fa08, 0x067cd863, 0xff23e7b4, 0x0af87950, 0x3a949bd7, 0x4923c251, + 0xc38c54e7, 0x7e995584, 0x69eb931f, 0x7a737e03, 0xd39e504a, 0x07664ead, + 0xa0fe32a5, 0x426705ed, 0x2ffe9e58, 0x4f842ce7, 0x00008000, 0x00088b1f, + 0x00000000, 0x7dedff00, 0xd554780b, 0xb3dae8b9, 0x64932667, 0x6f264c92, + 0x80849af2, 0x3c870108, 0x4e3d2878, 0x0f78601e, 0x02483508, 0x48042bc3, + 0xd2d04132, 0x20196f1e, 0x83548086, 0xa96a1ea5, 0x5af11e0e, 0xd528368a, + 0xf09d8360, 0x41d0582a, 0x396b42d1, 0x0a8a2341, 0xf41ea009, 0xfffde3d0, + 0xcccdad7f, 0x228899de, 0xb9eefbf6, 0x62ecfd37, 0xdaf6bded, 0x8fdffaff, + 0xfb0cd7b5, 0x33d6c60f, 0x2a1d76c6, 0x8cb96c96, 0x794bfbc5, 0xc5a398cb, + 0x8cf3d8cc, 0xff40b595, 0x9dbbfc2b, 0x7463cfb1, 0x1630258c, 0x2b18916b, + 0xa46fac64, 0x598dfa85, 0x187ae4ae, 0x15d236bf, 0x79c0496d, 0x26090e74, + 0xecc27e19, 0xf8743065, 0x99997af2, 0xc4bf5e71, 0xd5acc664, 0xbc232296, + 0x2ec6b537, 0x7efe60b9, 0x0b78ce91, 0x0b1703cd, 0x79d22da0, 0x2d73c0d7, + 0x66a38ed1, 0x6792cf78, 0x269d2dc2, 0xc15f7f46, 0xb12db57f, 0x35bbbeaa, + 0x2039d2c5, 0xff825fd0, 0x0eff8148, 0xc61b1331, 0xc5bf0d58, 0x2caec896, + 0x6b57cc0b, 0x0e6878ea, 0xf37eebf4, 0x92c191b9, 0x805eb86c, 0x7943f9e3, + 0x81cd7391, 0xd62adef5, 0x55c39b79, 0xcff187a2, 0xc66eb946, 0xf08e47e7, + 0xa1e193ee, 0x7d9e65e1, 0xa40b687a, 0xb0517dfa, 0xd996365e, 0xae3f41b7, + 0x4347b583, 0x8744f637, 0x47fa1a23, 0xa784b1cd, 0xb4743f5b, 0x62fac2e7, + 0xe7c24c9c, 0x38f95f01, 0xe5778b1f, 0xde23073b, 0xe00ccb96, 0x61e90178, + 0x8e3d36be, 0xdf04759a, 0x53873351, 0x4884c3a1, 0x5d0b28c7, 0x4f5ef467, + 0xd7801b31, 0x95d04c37, 0x579e8379, 0x4cc5a75a, 0xcf1baee3, 0x307d309f, + 0x7fdb599e, 0xe813f8bd, 0x32dff1bb, 0xf029dde1, 0xd617dd1e, 0xef09f3fd, + 0x95e0ba26, 0x61f7533a, 0xdb51f009, 0x5864db26, 0x9664a0c2, 0xd8c719db, + 0x0eadfb9a, 0x5a2783e4, 0x8c187b24, 0xb3660e67, 0x25643224, 0xdff9d622, + 0xb7610cc7, 0xac170b40, 0x6293ce30, 0xde436ef4, 0x43337fd9, 0x02b1dc38, + 0xc3e8068e, 0x05165d73, 0x0df50730, 0x459feaec, 0xf861f182, 0x6a4b982f, + 0x80976f69, 0x30466b70, 0xdee00197, 0x3f1326d7, 0xe118d13e, 0x7ff9830d, + 0xe1e2e3bb, 0xb9cfd099, 0x82cb875f, 0x339609bf, 0x43a8f891, 0x395a0afa, + 0x0f4034da, 0x8472edf7, 0x2df1865d, 0x5843d111, 0xfb45630c, 0x9ad9f988, + 0xbc0f307e, 0x047b4d67, 0x3f4d6fad, 0xe22c8f90, 0xff917b83, 0x591947f7, + 0x04bf5c0a, 0x86e38372, 0x46378eb3, 0x74e80565, 0x59d3f5a9, 0xeefd617b, + 0xd76f3e48, 0x91fd2bde, 0xe3fb957f, 0x97b5cc56, 0x2c5633e6, 0xf38a7ebb, + 0x1d5fd729, 0xe2345ef0, 0x8234b19b, 0x0727e897, 0x378abbe0, 0x1cafc70b, + 0x7475a7a5, 0xae3b08b1, 0x60e8c5bb, 0x29cf2748, 0x5e0adfce, 0x746f04eb, + 0x709e15b5, 0x389efac1, 0xe7c76691, 0x852f5abb, 0xb37de0eb, 0x230f5c63, + 0xeef4e5dd, 0xe22e6768, 0x1dcdd2f3, 0xe75eb8b9, 0xd2ef8446, 0xaeacf791, + 0xdf5aebdc, 0x7d64df63, 0x49b9bd6e, 0x3fc9e98a, 0xda903e5a, 0x8690bfda, + 0xd4309c90, 0xe60c9e5b, 0x6eeb035d, 0x49b43c1c, 0x634f4246, 0xc64f9436, + 0x06672c2a, 0x313de805, 0x12ddb9c6, 0x188e5f24, 0x2f5c0ee7, 0x8f3527be, + 0xde1cf9d6, 0x5e74721f, 0x5d7741be, 0xf4297ceb, 0xaf447d3a, 0x5a9eb15a, + 0x0327d993, 0xe1976cfc, 0x3e450e93, 0x0bc27bb3, 0xf08bd8f4, 0x27ed8a79, + 0xbfcf485c, 0x106bed9a, 0xc5bf7a1f, 0xeff04519, 0x11b1f7c7, 0xbd719273, + 0xff1d236b, 0xf6fe8665, 0x83f38c55, 0x127f6114, 0xbf73b716, 0xe4f50235, + 0x9fd718c4, 0xba81be71, 0xd09cb38b, 0x753bf02f, 0x781db973, 0x92fbac4d, + 0x97a8e09e, 0x58ebfe71, 0xaf425fff, 0xfe1d07bf, 0x05074c16, 0x7d04a33f, + 0x507e2147, 0x3feb7721, 0xf00530e9, 0x4f528123, 0x8f9cf6b5, 0x840c8eb1, + 0x07f77db7, 0xbe603bfd, 0x983e57ba, 0xf75bf285, 0xb7111872, 0x639be5f4, + 0x17cf8f90, 0x7316f2b1, 0xc9fa7d4f, 0x3ebb7aca, 0x4b4eb187, 0x1ad5e936, + 0xbeb237e6, 0xda974fa8, 0x14fa41f5, 0x47fba620, 0x3809fe0c, 0x994291ff, + 0xbbbe02ad, 0xc49e1f64, 0xa569e842, 0xb3256d7d, 0x7fd807cf, 0xf00e7a8e, + 0x4177643f, 0xcda5e10c, 0x3b58fa4a, 0x6acac8fe, 0xef4e697b, 0x1a191df3, + 0xbb45ee5e, 0xb0673121, 0xe588497d, 0xb4572576, 0x081d28a0, 0xa317b9e7, + 0x74b81ebc, 0x68adef2e, 0xb73a7806, 0x0f7ccdeb, 0xe639cbf0, 0x9407f65f, + 0x6ccd4f9f, 0xa1c76a1b, 0x8aafe56f, 0x0fdbc80a, 0xffb5f046, 0xd1a3a5e0, + 0x613f1836, 0x4f78bee7, 0xc07efe10, 0xe55e9ff4, 0x2f7c2cdf, 0x7d30fc23, + 0x07a47f47, 0x44d9c3fb, 0x7613b41b, 0x7ce7881f, 0x3a43a890, 0xeb7a172f, + 0x64697877, 0x2b09be60, 0x948f88ea, 0x1365ed7e, 0xf505c6f3, 0x9a237ef5, + 0x66cbdabe, 0x5f7185e6, 0x49e2a258, 0x7d61f47f, 0x537c7f50, 0x2baf69bc, + 0xf4323b78, 0xefda066c, 0xf9a1e1f3, 0x77188464, 0x09323ec9, 0x4609a3fd, + 0xc4258e5f, 0x34bcc638, 0x57aebb4e, 0xa5ecba57, 0x1be1defa, 0x96ae646f, + 0xf4347c10, 0x99c37bea, 0xd97ae407, 0xa1d90356, 0x32fe57a3, 0xf7e81f2d, + 0x658316c1, 0xfab3e035, 0x7ed2fbd7, 0x87abf70e, 0xe8245986, 0xe5f3607f, + 0xfc2f1f20, 0x75c4ecb5, 0x5965b07f, 0x3f683ce2, 0x01ac7e06, 0x356e1638, + 0xadeaf5d0, 0xb3f5d2f7, 0xfe174f82, 0xea10613a, 0xd7fba3f9, 0xab3ae227, + 0x87f6b1ff, 0x1a762fa8, 0x4286832d, 0xb243b35b, 0xc5c90697, 0x55c2a7e2, + 0x563a9dfd, 0xd650eb8d, 0xd5d724cd, 0xa78036fb, 0xddf7562a, 0x6afd97fc, + 0x95fc05ff, 0xf204d8aa, 0x09dd2657, 0xbc2baeeb, 0xbee27e44, 0xc7641183, + 0xc99668ff, 0xfd0df01f, 0x02df3fcf, 0xe87f92fd, 0x0843e4ed, 0xf42d1f3e, + 0xa4c96332, 0xbc4caa87, 0x4f5bb25f, 0x944944fe, 0xf186f84c, 0xff70d1e6, + 0x1f78c45f, 0x37e40de8, 0x34da8f26, 0x8e8dc612, 0x13f43031, 0x78b7c5ff, + 0x7efd0302, 0xbbfd65fb, 0x29eb411d, 0xd003cd66, 0x06622911, 0x1e8775cd, + 0xd49897af, 0x8ce747d7, 0x6e768b3b, 0x5d7d45b4, 0x58869b91, 0x0141ffe0, + 0xf077dffe, 0xc3c647a3, 0xc88eaafa, 0x86bb0fdc, 0xe10d797e, 0x5f9d23d7, + 0xcf01d8ad, 0x3958151d, 0x8683e57a, 0x11abe414, 0xfd0d5b12, 0x9584ae0f, + 0x0b879285, 0xbca36fe8, 0x80efa033, 0xda277d00, 0xa3ed5d17, 0xb11e4c38, + 0xe11f6af4, 0xee7ae6ff, 0x11d1e5eb, 0x6bf7a46b, 0x6e56a0f5, 0x383d2fbe, + 0x0c81e861, 0x4fb5144f, 0x4ec9fb63, 0x7ab45fae, 0x14f7ab51, 0xd6f0b4b8, + 0xf4a9d65e, 0x1b58d0dd, 0x3de80b8d, 0x1bbde923, 0x8d1d5f18, 0x815f110d, + 0x797c265d, 0xae29e986, 0x0de1bf03, 0xb66b971c, 0x480115c5, 0x48ec960d, + 0xcc33e7d4, 0xee50b7ae, 0xb03b7f32, 0x1ebd8194, 0x8759a3b4, 0xe24ba37a, + 0x106edaf4, 0x0373f62d, 0x623bcff1, 0xbcb1edfd, 0xc50ff10f, 0x8a2bd98d, + 0xfeb07bd9, 0x84f31330, 0xf7bd91e7, 0xf302f218, 0xa2e31cbf, 0x8c458d71, + 0xdcb19dc7, 0x601ecbef, 0x7e6059d3, 0x87592036, 0x70265af4, 0x25a576b1, + 0x7bf813b7, 0x6a64cadd, 0xe7c45fd1, 0x68237b3c, 0xce4bef5d, 0x6b772821, + 0x7a5a7c05, 0xfe155b64, 0xf60ff676, 0x87141687, 0x56d1d3d6, 0xe8a7ad3d, + 0xe81919d1, 0x7edfbc6f, 0xcfea0677, 0x3f5e01f7, 0x3dbd3fda, 0x84fcebe6, + 0x3e3c8587, 0x8c44ec28, 0x267f2388, 0xc7d804e4, 0xb5fd13b1, 0xbfba4e95, + 0xb539656e, 0xa0ae571b, 0x59b1ddfb, 0x91e8fef4, 0x81b3fbcf, 0x641b9d7e, + 0x8c0b03b2, 0xf0b1fece, 0x8e934ede, 0xeaf7d1e2, 0xccbb65cd, 0x5c519d78, + 0xf1d1e0b3, 0x142e50db, 0xf563ba38, 0xd6deeeb4, 0x3ebd6d99, 0x3acb5dfd, + 0x5d1ed1a2, 0x0077c7e5, 0x7e01893b, 0x32bb219c, 0xc71809ad, 0x38e22474, + 0xbfefe4b7, 0xee808283, 0x956ff40c, 0xeccafff7, 0x6216b6c8, 0xa106c39c, + 0x7044b45c, 0x7385a37b, 0xd9f395a0, 0xc13695da, 0xfda80307, 0xef61f858, + 0xa10a9da3, 0xcf116e57, 0x6e3b361d, 0x6630f7c1, 0xd6937f26, 0xda3bfa81, + 0x42708791, 0xf78050bc, 0xcbd52587, 0xdbf90906, 0xf80df5c2, 0x771fdca5, + 0x2c71c48e, 0x044d21de, 0xf9130c7a, 0x05f2de9b, 0xb4de385a, 0xe6d0f972, + 0xc9569411, 0xf95a9423, 0x6b16fe7a, 0x6c77e551, 0x2a11cc2d, 0xcad5b07f, + 0xc3b266f5, 0x7ada4721, 0xd702bb97, 0xf3191ebb, 0xdecce524, 0x51a49a0f, + 0x3f98ed2d, 0xaef52949, 0x634afcc2, 0x3d0e56ac, 0xc95798e1, 0x3d12e976, + 0xefd12e30, 0x1c02322a, 0xe912625b, 0x7eac497d, 0xc0abd215, 0x1745a3a5, + 0x4af08fec, 0x4307904a, 0x047e85f2, 0x79470d09, 0x9ae51f1b, 0x5f9df843, + 0xc368c6bf, 0x464793fc, 0x025672fd, 0x38fe013e, 0xa422207b, 0x228f773f, + 0x1f7152b7, 0x4f05e934, 0x050f0819, 0x1662fd4f, 0xd4f05bc2, 0x28297a1d, + 0x6ac87f4e, 0x3d9dfc20, 0xe29338b0, 0xac6193e6, 0x79cf565f, 0x545f051b, + 0x60bf7c09, 0xab77cd0c, 0x5baffbc5, 0x7f82774f, 0xd3d2a893, 0x8109adab, + 0xed5d4c7c, 0xb3d3d245, 0xfc3edcac, 0xb072df4a, 0x57f3e00f, 0xf11d99f3, + 0xad99f8be, 0xc17ba794, 0x077632d8, 0xc74ea7ae, 0xffb00f30, 0xfb07cbe0, + 0xdf387fa0, 0x83fd1436, 0xd91fcfab, 0x7fd788de, 0x2286cd55, 0x1bbc53fe, + 0x7c07cc25, 0xf84cde1e, 0x185b7cfa, 0x5a4b055b, 0xec65ac74, 0xb9bfa04f, + 0xaf50c746, 0x6f0dd768, 0xb192e832, 0x237419f5, 0xff51fd38, 0xc6077429, + 0x143d2232, 0x50fe21ba, 0xf6dfed9f, 0xc0afc112, 0x46c625b5, 0xccfc5bf8, + 0x27c8b1ce, 0x12ac6a7d, 0xb81467e6, 0xb89dabbe, 0xf7f3f681, 0x3f666fd6, + 0x69fa465f, 0x6ed6a7ed, 0xf63b30ce, 0x86bbfe90, 0xf8231cfd, 0x0f4237f0, + 0x41ed98db, 0x23b253cc, 0x68f7ca3a, 0xf82a52e9, 0x7a2f2831, 0x791d7ac4, + 0x2b5661d1, 0x179b57bd, 0x7ae46edd, 0x66cad9b4, 0x87e5094f, 0x9b757809, + 0x17688dba, 0x90a4dbe3, 0x99a8e97a, 0x9bd025eb, 0x9f7241ff, 0x86af5a1a, + 0xc419efc0, 0x7c3bcddb, 0x5e54717b, 0xba244e6c, 0x0fcf805d, 0x7814f854, + 0xe0aaf054, 0x88a631b3, 0xf0bb65f8, 0x70c4b733, 0x9970297c, 0x8e7194e3, + 0x7a5f380b, 0x0bfafa2f, 0xff806781, 0xbf1fc232, 0xeaf2a99c, 0xbe3d3e4a, + 0x0b1923de, 0xca302cd0, 0xb9c665bf, 0x5c601956, 0x7f6648f7, 0x1531fa12, + 0x77d42296, 0x3b7b6ad6, 0xcf1bdde6, 0xe366bcf1, 0x4d5de652, 0x7ffe30f3, + 0xa3ca6cae, 0xe69dde22, 0x5941769e, 0x532bd81f, 0x15c1215c, 0xf635f711, + 0x45ca06ea, 0x9337dc72, 0x10b8f48b, 0x731b7b74, 0xc7210980, 0x4379c5f7, + 0xaf0739d0, 0xb7ce8b5f, 0xe5e57889, 0xcd472998, 0x0cb56fc2, 0x4b5dd009, + 0xdf91becf, 0xc4f78f51, 0x09716dcb, 0x61b2f13d, 0x1e806e82, 0xec22c9d7, + 0xa4ceeca1, 0xdf3defb8, 0x442e293f, 0x54fe1fbe, 0xab13f4fe, 0x84dfafed, + 0x5326be70, 0x4fc4f49c, 0x27988c3b, 0x0ad2f256, 0x812feebc, 0x773f40a3, + 0x56a3a97d, 0x26d75eb9, 0x55dc63e5, 0xf90aefb4, 0x5fed5dc7, 0xa5dc7f92, + 0xf7958ff1, 0x89ec03de, 0x365a31f2, 0xdc5fff13, 0x9978e3c2, 0x146dfed9, + 0x643ee1c0, 0xf11b5e60, 0xb40ff92f, 0xc45fe85e, 0x633fc716, 0xe16f78a4, + 0xf98617e1, 0x08cc52e0, 0xe105b31d, 0xc111d62b, 0x8af8416c, 0xfaaab32b, + 0xaa3ece09, 0xd9e549f1, 0xae29fbaa, 0xa9fbaa81, 0x7eaa79d5, 0xaaadfd7a, + 0xb76099f1, 0x9e59fb82, 0x7df1aa71, 0xfaaaa69b, 0x56ef9afd, 0x871e678d, + 0x39d6073f, 0xa6f3ac5f, 0xe35573cd, 0x61f24f99, 0x2081647d, 0xc7dbc7f3, + 0xc8fac21c, 0xb88f917c, 0x3558bbd9, 0x756682df, 0x08f0815e, 0x956aab78, + 0xb78863d8, 0xd5fbeacd, 0x531b1b6d, 0x55e45da1, 0x758c5f5f, 0x53f9090f, + 0x3af7fd7d, 0xe3f432e7, 0xcea7197f, 0xbe935dd3, 0x45ae9b9e, 0xc70fbb5f, + 0x7f2288ef, 0x79e1e167, 0xc9614724, 0xdb86fa6a, 0x7f16be22, 0x9aac0391, + 0xafbff0fb, 0x5d945fc1, 0xfc5a0fcd, 0xc1f759e9, 0xceab8054, 0xac7dd92b, + 0xb516fe27, 0xb538256e, 0xede2d3f8, 0xbcea718f, 0xd748dace, 0x971bd45e, + 0x0ccb975a, 0xbc65f3f3, 0xf5a978fe, 0x6c4721d3, 0x7ef97941, 0x5fe5e6bd, + 0x97910b8d, 0xcb7ac2ef, 0xd41bec2d, 0x817df65b, 0x8b030878, 0xb27a0063, + 0xd5d37611, 0x20784afa, 0x5bd5af0f, 0xfb7a0b4a, 0xcfa4716f, 0x35a97503, + 0x98b0f4f0, 0xaf089db7, 0xef18b752, 0xb7bc1172, 0xe1232020, 0xa75f333f, + 0xe1e00f32, 0x7c679c3d, 0xe3123591, 0xeffb9da7, 0xb58078a1, 0x073d73c5, + 0x1f1e0f24, 0xfe9297e4, 0xa67fc16c, 0x48fc3d90, 0x704fc3d8, 0x321ec53e, + 0x57bf959f, 0xe6dec3d8, 0xbd16ea51, 0x995ed2b5, 0x58dd2fea, 0xcfa1097f, + 0xd1dff18d, 0x23d27cae, 0x0f8c69ff, 0xbdee0f8e, 0x3af51074, 0x1e3c3de0, + 0x051519d6, 0xd80a52f6, 0x8c8b7fcb, 0x3eeb7926, 0x826f7b2c, 0xb64d170b, + 0xa06e6b18, 0x7785a2be, 0xab9ac994, 0x6de3d20f, 0x365eda92, 0x23ff71e6, + 0x1dfb9e31, 0x2fdccc93, 0xe9d62c1d, 0xeeebf8d6, 0x82971e26, 0x05b75434, + 0xe38381f9, 0x3bfc68a3, 0x71834511, 0x5c455b3d, 0xd12598df, 0x89251afb, + 0x312dfaec, 0x9dff74c5, 0x6c5ca2b8, 0x0ef789fb, 0xda089f46, 0x8f0e6ce6, + 0x5013ec4d, 0xc710ffe6, 0x4c5b6217, 0x8b78e0ed, 0x0658efc8, 0x448fbd22, + 0xa35e6838, 0x29fcab2c, 0xe78bcda5, 0x99a7447e, 0x2a937e29, 0xe8463c7f, + 0x8717cc31, 0x26393091, 0xe40c4e8c, 0xea3c998b, 0xe45e31b8, 0xdc7a2589, + 0x5dbc7481, 0xbcb7b1d0, 0x658063b1, 0x4439bc3f, 0x1c97d8de, 0x1f6c6f32, + 0x78637943, 0xd2eb8f52, 0x0e918fe6, 0x3c80d691, 0xaabf8c4c, 0xdf50d26f, + 0x3c756634, 0xe3f91e32, 0x127f6ca8, 0x13c77f41, 0xb6e00439, 0x7c7675d9, + 0xb616e464, 0x0bfa1c3a, 0x2fca363d, 0x8afe2019, 0xefc80bca, 0x4e2cf892, + 0xd33e13ff, 0xfc3fb810, 0xe63b671d, 0x634ffb93, 0xcdff5456, 0x1a24b9ac, + 0x2c2d88fd, 0x2552bc64, 0xd17c66f8, 0x3ce5195e, 0x25f81ba1, 0xe2aa3d04, + 0xbdbf8a75, 0xbc36e900, 0xf50975db, 0x4807a289, 0xb45c6195, 0xb27e475f, + 0xe896f9f6, 0x07c42592, 0x9279d0de, 0xe387334e, 0x29738442, 0x57783fce, + 0xcdf51187, 0xce6f4542, 0xd03d31d7, 0xbf414ef7, 0xbaf0b73b, 0xd5f2bb34, + 0x5fe2b257, 0xa19f9a31, 0x2d38583e, 0x87798bca, 0x1e596d85, 0x5129cb82, + 0x76ddc55e, 0x85fd89cc, 0x8c160505, 0x657f1d73, 0xe40199d2, 0x77ae319a, + 0xa28cecf4, 0xc67ec807, 0xaa629d53, 0xb34eabe0, 0xfd04e08d, 0xe81221bc, + 0xaacb70b0, 0xe12fb8bd, 0x54677fad, 0x7721388f, 0xa6c9c30f, 0xe4567203, + 0x1567ab61, 0xaf30f879, 0xf3134c77, 0xf784be78, 0x9def029a, 0xd69876de, + 0x3cc0c273, 0xae97e026, 0xd0d9773d, 0x304c6d4f, 0x457f89d9, 0xec94eb9d, + 0x878c807a, 0x410ebbbe, 0x6916d19b, 0x58eb0f59, 0xafdc6463, 0x11d845d5, + 0x1dcd13ff, 0xf897e27a, 0xf1e23d6e, 0xf467410d, 0x4fcfc9ed, 0x39274460, + 0x96e9c755, 0x44fbe369, 0xbff9d472, 0xc1dd0497, 0xebc34c6b, 0x58df2313, + 0x7cce036e, 0xc70fd376, 0xdea247e9, 0x1679637b, 0xdd365bf4, 0xfc8f4e35, + 0xa7c6fa9d, 0xcfea2059, 0xf7e72a6f, 0x69f1bd07, 0x6d77f436, 0xdfefc19a, + 0x5ecfbc46, 0x38f774dc, 0x74bfebcc, 0xf9f02f55, 0x12422097, 0xc395bfae, + 0xe2a1f574, 0x92bc5f0b, 0x7c06665f, 0x4fedb38f, 0x3aced027, 0xc3b7fa95, + 0x237faaa0, 0xdf8098c7, 0x62be0bc6, 0x0764d1f1, 0x8dfa09c6, 0x3f68fbd7, + 0x23e4ce8c, 0x1ac4defc, 0x8037c82c, 0xe55f4dad, 0xc07f7cf7, 0x4bf9a9ae, + 0x02b63072, 0x2cd92de8, 0x566b27c4, 0xda385730, 0x5ddd40fd, 0xcceeebc7, + 0xe057ef89, 0x03dfde51, 0xdead202e, 0x16d70c1a, 0xab81479a, 0x0798686b, + 0x9fb149e5, 0x525d5c0a, 0xf498e3f7, 0x0f2fd9fe, 0x75ba404e, 0x48677545, + 0x7090dfd0, 0x95d8e890, 0x64b8fdd0, 0x381bea0f, 0x5a6ccf1d, 0xef03ce36, + 0xce3b28d9, 0x1986dca0, 0x2692bef9, 0x3de0538c, 0x3cb8260f, 0xbe03cf58, + 0xef90fbb3, 0x87a48dd2, 0x79d40b4a, 0x67c16e89, 0xdeb813cb, 0x5cd61d1f, + 0xd2f80c7f, 0xab624bbd, 0xcafbbc60, 0x89da2325, 0x8da76d89, 0x76eb680e, + 0xbea2369d, 0xcc3ec3aa, 0x18c5b753, 0x12796f52, 0xd43f6164, 0xf481f07e, + 0xe3c40ffe, 0x12f985be, 0xd9eee255, 0xfb1a3b1d, 0x55c1ccf7, 0xa8f77632, + 0x5d91a39d, 0x0fed9d2a, 0x759b3b60, 0x9a16401c, 0x7e5592e1, 0x48eacce9, + 0x595b5f95, 0xcfeaa71f, 0x80ea066e, 0x915ecf5c, 0x181f8eaa, 0xcf00abc4, + 0x43f8160c, 0xe82e56fd, 0x83792338, 0xccadf71f, 0x1d3c1970, 0x6c4df341, + 0x22b7a55b, 0x9d92f5dc, 0xd987afd4, 0x7c99b9f0, 0x3dead085, 0xd1b0f5c1, + 0x51893cad, 0x7f226e57, 0x80fb02bf, 0xd91a8ad7, 0x0f10936b, 0x6eefba46, + 0x5bbee895, 0x4b5777dc, 0xec961d4a, 0xe3016cee, 0x46c73dcc, 0xe110b6d3, + 0xcef02bdf, 0x4b3b2f2e, 0x7afc28fc, 0x36e55d65, 0x7d70b3b0, 0x06dbfa6d, + 0x8ff6779c, 0x45971624, 0x50eceaeb, 0xafdd51e1, 0x19f757ac, 0x9e6030eb, + 0xf50af67a, 0xc209e1f5, 0x83620e9e, 0x25469e50, 0x2f927a48, 0xfd24ffd1, + 0x007cd7ed, 0xf3b2e3df, 0x83e004f6, 0xea8fa31a, 0x2ecb8f50, 0xe1f72bea, + 0xb9231d7a, 0xe4807f03, 0x5cf92258, 0x8a587063, 0x95ae8fd0, 0xb2676f88, + 0x2b217f20, 0x72fa9e30, 0x093dfecf, 0x135a5fdc, 0xf54e5cee, 0x65923db0, + 0xd52a5c1b, 0x07e8f43b, 0xe74291ae, 0x70259643, 0x418d7879, 0xf5700ef4, + 0xbb452647, 0xd78c677e, 0xffedef03, 0xf41e39c7, 0x03e7fbef, 0xee50d81f, + 0x2f19bdb9, 0xf024cdec, 0xebffd12f, 0x9394b72f, 0x68c5bf7e, 0xec2efd21, + 0x1c2fa290, 0xa1db51bf, 0x288769f1, 0x79b498fe, 0x8bd405c3, 0x791d7d39, + 0x07be011b, 0x1ffbf9c3, 0x71792ddc, 0xee5d4e1f, 0x499fd241, 0xdef81ec0, + 0x47a164ba, 0xacfbd55b, 0x21af5092, 0xa5c84cc3, 0x1498a6f7, 0x1e90776e, + 0xbac57c94, 0x497e80af, 0x69a9bde2, 0xe257c236, 0xd70916e2, 0xab3cce9d, + 0x45cf8ed0, 0xb40c2c21, 0x97cfedd7, 0xbe7f5a4a, 0xe4f9fc9b, 0x7bc5230e, + 0x9df8dbac, 0xe73d73f2, 0xfcd432ff, 0x53aa7cb0, 0x2bf2e207, 0xb9a798d1, + 0xafdf4f67, 0x9b24dfdd, 0xc1b771d4, 0xc7bb8ea2, 0x9feb500f, 0xdeb57689, + 0xafa23c99, 0xc714feea, 0x3bfdd520, 0xfd55f2cb, 0x54dbcee9, 0x2f2aefe3, + 0x92c3f551, 0x00f269c7, 0xe44abcea, 0x255e7500, 0xa3ceaeca, 0x7dfe1d84, + 0x317804b9, 0x2e1d3c9a, 0xc81343c0, 0xc06b08c6, 0x368a0c8e, 0x22367151, + 0x6d8cdc3f, 0x1f30d0d3, 0x1f5349f2, 0x1d87871e, 0x07d937be, 0x766298f3, + 0xf104b098, 0x1c5bc95b, 0x9a007307, 0xf03a9ea8, 0x39bfb57e, 0x17db8532, + 0xb825f5a5, 0x36844f5e, 0x2a5b19f7, 0x14fd67f7, 0x1822989f, 0x345e8bf7, + 0xc4a45f91, 0xe93ccac9, 0x50074569, 0xefdee47f, 0x6b09baa0, 0x27cc1665, + 0x7914693e, 0xbef917d4, 0x0ed6dcdb, 0xbe48239d, 0xfae44cef, 0xe2ce17e0, + 0x5d7f38b1, 0x9459581b, 0x1aefcda7, 0xd7593eb1, 0xf68d1ed6, 0x5df3886c, + 0x02ebe623, 0xd39d85d7, 0x5d604777, 0x722d77e5, 0x72cafdc8, 0x1febcf22, + 0xf2bd7a14, 0x547c40de, 0xafa02c34, 0xf5f2772b, 0x92374e55, 0x46c2c13e, + 0x7a0dbd28, 0x2ade67ba, 0xf28c1ed8, 0x03ba803e, 0xdc6ab7f4, 0x2e3c69ec, + 0x8dbd00aa, 0x5cfa0c72, 0x91ad3f7d, 0x73e80bf4, 0x010bf5d5, 0x15fb9e7d, + 0x19c2773c, 0xe8f65f7a, 0x3f375e14, 0xfc212ae1, 0x88f002ff, 0x7a2ff27e, + 0xf3e38de0, 0x167af85a, 0x37441f69, 0x2929b8ed, 0xb67c7fdc, 0x433d7d17, + 0xc949f5d0, 0xd4ca879f, 0xbe208ced, 0x8d72699d, 0x7a47ccef, 0xf588de7c, + 0x4bdfca89, 0xdfeced0c, 0x7ed30fda, 0x03cee33d, 0xd28fb889, 0x912072dd, + 0x18d5df01, 0x8fd0ab6c, 0xa3b0be07, 0xead753df, 0x5b6bf823, 0x7af1dbf2, + 0x4764ab6d, 0x75deec55, 0x93ad0c61, 0xbd623475, 0xe05ec9ef, 0x76e44cca, + 0x8da26064, 0x985c07e7, 0xc3e7c113, 0xf9095ebc, 0xc212f400, 0xcd625bb5, + 0x9d727fd0, 0xb79d6429, 0xff7be052, 0x57c5233a, 0xae3cf035, 0x41fa60e3, + 0x68f909a3, 0xc24bac27, 0x1e9b1c75, 0x372ff389, 0x142ff430, 0xfba5cef8, + 0x4ffae14f, 0x070087ce, 0x2f99afae, 0x2e4fbe13, 0x05c87917, 0x58cfea06, + 0xdd7e2464, 0x46bdff37, 0xac9defcc, 0x4bdcfbe1, 0xf9467c16, 0x248b19be, + 0x8a993f65, 0xd57e159f, 0x7f96a7f2, 0xf569f07b, 0x98e9f1f5, 0x3a7cabc4, + 0xd03ced04, 0xf212747d, 0xce218fcf, 0xb2b9f946, 0xf00490cf, 0xec5a3766, + 0xb06bafb8, 0x11207dec, 0x7e3ec4f5, 0x56cd687f, 0xdb1beb89, 0xa98728dd, + 0x1eb6464d, 0xae44cbfd, 0xbd206697, 0xdd69710a, 0x7bc52452, 0x4bd46cfe, + 0x0ef7ca59, 0x13be5606, 0xae7a71f3, 0x94bf066f, 0x107d75bc, 0x39129adf, + 0x707a2abf, 0x76b99190, 0xa5bfde52, 0xe79814cf, 0xdbaf0359, 0xfaf98864, + 0x331eedf5, 0x089fda05, 0xe027997e, 0x0af7fa50, 0xcd4f67fe, 0x344efc20, + 0x5b8fbc71, 0x75c0abe1, 0x8b5d1934, 0x84fee112, 0xd06bb78c, 0xbf6535ce, + 0x42f94b9a, 0xa73b2366, 0x46fbe7c4, 0x1965b07e, 0xe6fc37ac, 0xf863a208, + 0xe4168d9e, 0x057ef0e3, 0x7c10ae49, 0xcbeeb4a7, 0x3902e636, 0x4d9cbbaa, + 0xb29fd2ad, 0xf691acf7, 0x185db721, 0x39727243, 0xcf2bae99, 0xf9114a2d, + 0x53dfb12a, 0x9e825fc9, 0x0bc88fd6, 0xc0f0538c, 0x215e1770, 0xd114f3c2, + 0x3652d96b, 0x37d1a794, 0xd667fad2, 0xc0e6931c, 0x1c19773c, 0xd6167306, + 0x77c7cacf, 0x537ee0e6, 0x71fd5cc6, 0xb9899d9f, 0xcfdfb88c, 0xcaff7d42, + 0xb1bfea64, 0x63ed46d2, 0xd0cfe726, 0x5fdf4cde, 0x4df68fdf, 0x2cea3fa6, + 0x1d74f786, 0xb6be0831, 0x3a94be10, 0x9936a5d0, 0xa5fee099, 0x35d5125d, + 0x5d67f815, 0x715cc3ee, 0xdf15fd8c, 0x5da9ef07, 0x3be926f1, 0x3185f57b, + 0xad0d1718, 0x7d88dd39, 0xc6cf8af7, 0x0a713fa0, 0xf5f907ec, 0x4b27dfe0, + 0x198e47a8, 0xc55d7f71, 0xf3cd2b65, 0x0c7baeac, 0x15e797ca, 0xa74dea89, + 0x93182f5a, 0x08627db8, 0x9f5816ca, 0x1895d703, 0xb771f84b, 0xfa71d50d, + 0x4ab8f0e6, 0xc0fb43f0, 0x1e91a32f, 0xd7b615a6, 0x0fe7c36f, 0x77e50cc9, + 0xb477717d, 0x3dfe8425, 0xfeb2f301, 0x6ad81d7c, 0x3d1b97ef, 0x5cf0ecfd, + 0xfef42eb9, 0x9f0557a8, 0x3e29a602, 0x11293fc0, 0x55ff99e5, 0xac6292c2, + 0x22f8f714, 0xdb2b8e40, 0xb1eace4a, 0xbbd897ad, 0xbd8c78ea, 0xf7b7e41b, + 0xb4df87c6, 0xf4f9c3ad, 0xe201f641, 0x07e41646, 0x54c8dc61, 0xbcf0f7ef, + 0x924e7a52, 0xaf3ac42b, 0x1f4741ca, 0xd57a0366, 0xf3ba0135, 0x5207df91, + 0x5af77e7b, 0x298fca1b, 0xb451fba2, 0x8ebfac13, 0x8f5a8ce2, 0x93d9ffda, + 0x4f78e5cc, 0x77eb9732, 0x12f1d513, 0xa3ef45c4, 0x145c431c, 0xa0df858d, + 0x9d7b4978, 0xca1325e2, 0x1077bc15, 0x10f9e7d0, 0x2e4e1f70, 0x3df908fe, + 0x9f133583, 0xe473e033, 0x3f3aed2f, 0x9153f613, 0xd72819eb, 0x5cadbfc8, + 0x1ef3b5ae, 0x0cfa2e4f, 0xfb8759e1, 0x8de842b5, 0x6b3ac557, 0x97c23337, + 0xf095b37b, 0x766d8e74, 0x9e5f0316, 0xfeb03803, 0x4674e5df, 0xc67d62c6, + 0x9ab48ce5, 0x6ea07a03, 0xb73d0473, 0xdc6a672e, 0x2447e81c, 0xdf3fbe71, + 0x3c42625a, 0xe5ccdacf, 0x29df794f, 0x94388cdf, 0xb74342a7, 0xd3f70ed1, + 0xa3474eda, 0xfbb857df, 0xc39438ce, 0x47fce0de, 0xed775f12, 0xe3c67b8a, + 0x87f85df7, 0xfea54cf9, 0x33ed5ee6, 0x0578dd52, 0x7f6dfe23, 0x28756ff1, + 0x22dbe7c7, 0xcf37682d, 0xa0f489ed, 0x257aeffe, 0x2893abcc, 0x80c4f0ee, + 0xe8673b5e, 0xe5fe4498, 0xfe82d96e, 0x8f95fb9d, 0x7479451f, 0x9e8618bf, + 0xb6d25b1e, 0xbdda02f6, 0x67b1b69a, 0x9f6843f5, 0x1e553ff9, 0x47dc576a, + 0xffd2917e, 0x89c9a578, 0x9ebcf47a, 0xad2589eb, 0xbbbf902f, 0x21a5cae4, + 0xb73ef758, 0xa186bfe7, 0xf1ff735e, 0x67d430d2, 0x1a5c3fee, 0x2fddf786, + 0xf287d645, 0xc8a55657, 0x5ec57f44, 0xabd71d66, 0x0b1f43f2, 0x686ac8fe, + 0x9bfdc32e, 0xd9a6c785, 0xdcab7f31, 0xa3a7ec2f, 0x6f85fafd, 0x082dc695, + 0xafc1ae7a, 0x05ebc32f, 0xe7234ac7, 0x4765f107, 0x2fc941b2, 0x075e575e, + 0x0587eaef, 0x3afc71e5, 0x5b8c3847, 0x7df3d7e7, 0x1792d5b4, 0x5ff00be3, + 0xdf91cfb4, 0xce28b5d4, 0x04fc9ebb, 0x05c1f8e7, 0x5f67efd8, 0x62b5436f, + 0xe413903a, 0xebf0cd27, 0x47c0617c, 0x3e616de5, 0xfafdeff2, 0xfe17d4d3, + 0x1f0bacd3, 0x21496544, 0xde0333f2, 0x5c7a8d18, 0xbf81a79b, 0xf15b8428, + 0x5dea2ab7, 0x36bf08e9, 0xfcbb337f, 0x690fca0e, 0x7e5937f3, 0x01626ebd, + 0x4d79e7d6, 0x937f9d74, 0xf145e509, 0xbb7e9143, 0x67ffc842, 0x8a7e9c49, + 0x75f8355c, 0x7f069744, 0xda0729b1, 0x2efee2f3, 0x1df8a730, 0x9ddb4347, + 0xd08f30db, 0x48aee570, 0x1c355dac, 0x3bf0ca9f, 0xb14b2e8e, 0x773e1fa9, + 0xf4d30ee5, 0x68bf00dc, 0x8927b7df, 0x9f80cbeb, 0x3deeda10, 0x9ff9e427, + 0x27b6ff65, 0xffcfcd5d, 0x20ff6d5f, 0x9499df0e, 0x4cf87140, 0x71e1279e, + 0x286ed6b8, 0xf79958fa, 0x9ee7415d, 0xf92cf8fa, 0x932f1037, 0xc9377e3e, + 0xdad2e346, 0x1c51c4a6, 0x9c5a7c7d, 0xfe73dccd, 0xcebb7abe, 0x7e73db9a, + 0x7b738fc5, 0x184c071c, 0x3ef838e7, 0x8934f731, 0x7e2ad5f6, 0x9129db9f, + 0x30aeee3f, 0x029c7178, 0xcf1a7f97, 0x18774eab, 0xc052e1bc, 0xc7fc543f, + 0x12edf7ab, 0x49fc57dd, 0x3bf46fc5, 0x5a771e79, 0x98ffbf01, 0x093275c9, + 0x70be41eb, 0x92385eba, 0x79cc675f, 0x77fa1520, 0x246250fd, 0x549fc2ff, + 0x6feb54f8, 0xfbeb6c5e, 0xb7e4fbb5, 0xe454fe08, 0x1f23432c, 0x108afd8a, + 0xfb43aa78, 0xfbf6871d, 0xae5f950b, 0xf7ec179d, 0x8e7a24b9, 0x6f05f3d1, + 0xe2a19de9, 0xfe6295f3, 0xa0fd207f, 0x2feff34d, 0x99d37842, 0xf6b9f69f, + 0x85bb5766, 0xfddbd37f, 0xcf286f88, 0xf89d8403, 0x4e73c967, 0x790cfff2, + 0xf617eabe, 0xe1dd9df2, 0xc9c1a2e4, 0xdeb97f48, 0xf7f2845f, 0xfac84367, + 0x7f8115f4, 0x7c557388, 0xa8dd207c, 0x5dc8b8c3, 0x4d03f3cd, 0x29d7b6b1, + 0xd32c397e, 0x1025ebfe, 0xb6ffa207, 0xda85b2f8, 0xa193f41a, 0x31ccf99d, + 0x9997ea03, 0x9bf86ad5, 0xcf8b7730, 0xa2f2cd2f, 0x4ac95cdf, 0xd954af29, + 0xfdc16b16, 0x2d094dcc, 0x3cae5107, 0xb6db64db, 0x06ebf1e0, 0x9e26f18a, + 0xa58eab6f, 0xe34c93fd, 0x6bd65407, 0x5fb57dfd, 0x13c89b70, 0xfc1fe6f5, + 0xeb9c3da1, 0xc9324395, 0x97e61d79, 0xd8cc616e, 0x7b82f5c6, 0x4de53845, + 0xb8435e30, 0x79215c3e, 0xad77004d, 0xdea1f718, 0xaa27f94f, 0xb390c1a7, + 0x51131b6d, 0x5d43992e, 0xea7daa3f, 0xda9bd22d, 0x9775923a, 0xad5d0ba8, + 0xb0930d1b, 0x64f10b5f, 0x3697fa12, 0x3fc464db, 0x47daa7c0, 0x1705f8a6, + 0xf147bd0f, 0xbcddcce7, 0x7ea3d3fe, 0xd78e34d4, 0x0d3ec48f, 0x76721e6d, + 0xa903c1e6, 0x8dd76bb6, 0x198f5aea, 0xe1e8ae30, 0x8efc687f, 0xf3ab269f, + 0x9e7a998c, 0x936ccdc7, 0xca9f982c, 0xbe1c7814, 0xeafc822e, 0x1f9f7f31, + 0xa140fa87, 0x1c29f9d3, 0x7e4fe7af, 0x045b445a, 0x84b7aefe, 0x70febac3, + 0xa99bf972, 0xd9336fbc, 0x91e5b9f0, 0xdff43df4, 0xbc4489ef, 0xdc5a01fe, + 0x09d2f997, 0xa47cc87d, 0x1fe5c294, 0x93cfe1ec, 0x2fde1ed1, 0xb07ad2f2, + 0x7c815187, 0x9b39f68e, 0xc209ae78, 0xee63ca14, 0xa6fdf5e6, 0xea38d714, + 0x6d9b32ff, 0x41d0ff23, 0x8017e779, 0x345f31af, 0xf58b1608, 0x5822e7e7, + 0x9a8bd603, 0x92af5c12, 0x6752fd1c, 0xe7823943, 0xd9e4cea9, 0x88fb2369, + 0xce7ac328, 0x2649b010, 0xf7c0d7da, 0x74140c47, 0x1638814c, 0xcd0049eb, + 0x0f37ac34, 0x219d7512, 0xf38f4c11, 0xad70683f, 0x48eb19bf, 0x2afb7aed, + 0xdc7b0212, 0xf59ea894, 0xebc1c925, 0x499d4ae2, 0x56f78fa9, 0x3df09267, + 0xaf0e1f7c, 0x727d892b, 0xfd893d4a, 0xae4549d0, 0x19ea2335, 0x6949adc6, + 0x0bedbbec, 0xf9e759eb, 0xdab9c63b, 0xc047cf3a, 0xa13f3ce3, 0x1fae2bae, + 0xe9f13cf0, 0x0e27adb7, 0xb8376648, 0xa3f1c5fe, 0xf620bb85, 0x5bc52262, + 0x68cff8ff, 0x976db3b2, 0x75761ec8, 0xe53f3187, 0x9e783b1d, 0xef7f8dbd, + 0x5b7105d3, 0xbd9d9042, 0x7b5bf843, 0xff884adb, 0x234bf977, 0xb0bd7c71, + 0x4f8eebe3, 0xd3bf13bb, 0xb4f5f8f2, 0x1e31872f, 0xebf2ed87, 0xb96fd10b, + 0x22f97481, 0xcdfd4429, 0x93edc114, 0x4b9e8e56, 0xe7a4f9e6, 0x947f3992, + 0x97f1e49c, 0xa3af397b, 0x705e8458, 0x0f491997, 0x944f4c1e, 0x5279fc94, + 0xeecb3aa8, 0x951bb26e, 0x3fda248b, 0x9675dd7b, 0xb76176d6, 0xb2e9f934, + 0x7b37a431, 0xd5075bcb, 0x33f755cd, 0xe13ec452, 0xdd7f3cc1, 0xf5a16c9c, + 0x1687eb5a, 0xaca64ba1, 0xe1d206ff, 0x5bf7ca68, 0xf3eaed67, 0x27bfcefd, + 0xdc9c8421, 0xfb3ff9c0, 0x4397e79e, 0x381ba7e9, 0xefc4df7f, 0xf93fff17, + 0xf79fe79e, 0x6467e33d, 0xfff43d28, 0x6d003eea, 0x2fbb5f9d, 0x0fef5b40, + 0x83c0bc3b, 0x1b4ad6f7, 0x9ad07dba, 0x972c5fa2, 0x63eb5540, 0x1da1329f, + 0xd792309d, 0x9a95d6c1, 0xc0a55bbc, 0x5f0500fe, 0x1c7953a7, 0xe0bdc961, + 0x673c0389, 0x71a5fc38, 0xc91b2798, 0x0aee0e28, 0xa630f5e7, 0xa14ca4b7, + 0x9496f6fd, 0x9b37a0a9, 0xe95ef97a, 0x6f5f3141, 0xad3d2476, 0x214a70e8, + 0x943c8eff, 0xea2596bf, 0xbe569652, 0x6de996df, 0xbde95329, 0x87f414b6, + 0xebf3f662, 0xd8e63ed1, 0xb2d9704a, 0x683c52a6, 0x1ef842cb, 0xeb5ef511, + 0x9859feb8, 0x5f82b68f, 0x8dc0f588, 0x78a41758, 0x94e342d6, 0xc3eccdf7, + 0xc0c47de1, 0x7adfac24, 0x99fbe66e, 0x5542f358, 0xc188ef3d, 0xa24739d7, + 0xea275e7a, 0x5f3aa3eb, 0x825993ee, 0xb9bf0189, 0x67542cbb, 0xffe46d7c, + 0x5bbfc01e, 0x65bdf5e2, 0x1f643e16, 0xc700cdc6, 0xc4f93db2, 0x8ef733bf, + 0xc6054bfc, 0x1cfc391d, 0xa5711e90, 0x109c17c8, 0x5f250ef9, 0xdeb5d4a0, + 0x53927911, 0xb6817f98, 0xd021f303, 0x37747d4a, 0xa1493eda, 0x1223c7ec, + 0x8e790fcf, 0xbe50fcf2, 0x7837ded1, 0xc0b464df, 0xaf1f1ceb, 0x9ef9285b, + 0xf93d62ed, 0x617d963f, 0x37e697e0, 0x9da2360e, 0x8f4c6fcf, 0xc38876c0, + 0xef12c3ab, 0x753bf98c, 0xf142fd0a, 0xee1f7251, 0xd43bac8f, 0x17bd754d, + 0x99fe7534, 0xff748c7d, 0x99c7e0b8, 0x97f5187d, 0x41afd3f5, 0x946631f7, + 0x4f550e45, 0x18b884aa, 0xc4d39ce1, 0x5df056e1, 0xe095b3e9, 0xe81f4e7b, + 0xaf36c46e, 0xf284ab3a, 0x1a1735ed, 0x5f737fd1, 0x76f074b9, 0x6d1997ca, + 0xeacc4f18, 0x2edde750, 0x96fdf2a5, 0x7bfc482f, 0x3d58cf4c, 0x63f9c7c5, + 0xd63fc4f5, 0x5f8a70ca, 0x9b2606ad, 0xfb853fb1, 0xf1657945, 0xd367d825, + 0xcc1fc962, 0x5d8b643b, 0x83c81b90, 0x4f2ec759, 0xab5d3c40, 0xd3e4aabe, + 0x4639331e, 0x6dbf3d22, 0xc8f6b57d, 0xaa57da71, 0x8bc14bac, 0xaded2752, + 0x73ecaabe, 0xaa7d9770, 0xd6e197da, 0xfcc18f77, 0xd39efe63, 0xd2cfb146, + 0xa8159c92, 0xbeefe6bf, 0xa5577540, 0xbfaeeace, 0x3c357e40, 0xe490e747, + 0x4053f903, 0xc95aee4f, 0x022fafeb, 0xc2b6d83c, 0xd7001dfa, 0x6c7eb0cb, + 0x78fd60db, 0x039595fd, 0xb4adf5a8, 0xe577bb53, 0x6ddd6a08, 0xeb5ea817, + 0x7f63d3ea, 0x1ef3d524, 0xfaf39d97, 0x5247f7a8, 0x93ef5b5f, 0xc6be7823, + 0xdf40c87d, 0x988fb82b, 0xb5177f48, 0xf8c4c9cd, 0xae63f3e0, 0x0ebb844c, + 0x7c416deb, 0x0f61de71, 0xce3173c7, 0x58e1ed3b, 0x3f6fcb67, 0x2ffdc46b, + 0x11bf7a75, 0x710061f3, 0x744d6e2a, 0xf7c0baef, 0x8515b6f7, 0x59af7e23, + 0xfffd6b17, 0x536fb175, 0x202afb17, 0xf247a49f, 0x56c73a9c, 0xc2390f6c, + 0x89e90417, 0x4f5e4e75, 0x4d939759, 0x99c9b872, 0x683f3b1d, 0x9e3286be, + 0xcd8eb0bf, 0x3ebe0f09, 0xf340cd35, 0xa09cf15b, 0x156fef10, 0xea06ecfa, + 0x213ed6ed, 0x47f3b6fc, 0x48ddf44d, 0x9985eefb, 0xea5fc41d, 0xb2badc7c, + 0xfdf899f9, 0x1844e7bd, 0x75f3c7eb, 0xd31c7caa, 0xcb7ae3d4, 0xd32ccdcb, + 0xce29c239, 0xbb40ceea, 0x319bcdad, 0xb706777d, 0x7e548eeb, 0x9527835e, + 0xea3d608d, 0xde657f72, 0xfc6072b7, 0xd91d328c, 0x973ea50b, 0x2b67a657, + 0x56f33f81, 0x9754bc18, 0xa69fd32b, 0x6c6e22fb, 0x22a5e4b0, 0x623a9f9f, + 0x57da84b4, 0xaa7b2f6d, 0xb79e1b29, 0x5c7648d7, 0x77eab5d6, 0xa3edad95, + 0x16fd6953, 0xf124e519, 0x53efa320, 0xf8f3d67b, 0xd63cef7e, 0xe30a54dc, + 0x82ce8e58, 0x679b51f6, 0xbf433e43, 0xef879b44, 0x4bbbf612, 0x48c1cfd8, + 0x8f9c04db, 0x73ca4bfb, 0x4d29fe5a, 0xaf36be95, 0xfdca905f, 0xbcb286aa, + 0xdf483975, 0xf6863a09, 0xd8aca1a4, 0x9f341394, 0xe34f552e, 0x60fac11e, + 0x907d707c, 0x75b501d7, 0xe5cf4541, 0x06317fb7, 0xf409bdf1, 0x7731da35, + 0xe41faf32, 0x087452bf, 0x4e0046f5, 0xc94dbebe, 0x8eb7bf57, 0x0c5d7c65, + 0xf679cbf7, 0xcb9f9448, 0xdee9f09b, 0x139fc448, 0xb5ea1eec, 0xcc6b3923, + 0xe8268fa8, 0x1dfbf10b, 0x5aba53b7, 0xd27ac267, 0x8f57af9d, 0xf209efc3, + 0x863d0fa7, 0x615e9f78, 0x7780fda0, 0x063e5ebe, 0x2ff62baf, 0xd5d6fa7f, + 0x807f7811, 0xe1b70f64, 0xbc62b2fd, 0x0f877e3f, 0x226ce933, 0xdcfa0742, + 0x8f53a47f, 0xc998f372, 0xf00a9d95, 0x75114fe6, 0xa76e0aa6, 0x314db7a7, + 0xaa4fee30, 0xf4bee6ec, 0x741f29cf, 0xea9f2da9, 0xefb87147, 0xaf603721, + 0x1d80f7f2, 0xb1d80a8b, 0x4abf6aef, 0xcf842d53, 0x218ec05b, 0xbc29d63c, + 0xbfa5af3e, 0x37bfd04e, 0x1e9bd4bb, 0xe783fb46, 0x4a7ca0a8, 0xb8ed3dc9, + 0xc33ef30d, 0xf0975fd1, 0xf95e9590, 0x6fd0a96f, 0x73f8bdb1, 0x7af80af7, + 0xfad537dd, 0x2d33a9cf, 0x521ffd4d, 0x97f11267, 0xe2526f52, 0x9e04d7b5, + 0xa175f695, 0x77f3be37, 0x435c680c, 0x0d60c77e, 0xacc31dfd, 0x44873a16, + 0x80e18ef9, 0x8ced1591, 0xe2b3fdc7, 0x93af26bb, 0x8f03a4fc, 0x37f1b5fd, + 0x935df8f1, 0x80672784, 0x76463c3d, 0xae8f395e, 0x9e63edae, 0xfbe16d6f, + 0x435b6bc0, 0x9912eb9f, 0x297bedc6, 0x33ea87ac, 0x98ed7f62, 0xe44ea25d, + 0x596d7a30, 0x4fbcb798, 0x74b79c1f, 0xca09fcdb, 0xc52f5dbe, 0x663cea7b, + 0x3acb796f, 0x6afc3be5, 0xd1df8ec9, 0xd31e775c, 0x7ee1f7c1, 0x4be63cdb, + 0xce3aeaa9, 0xad0b1481, 0xd125dcbf, 0x9d264cb9, 0xe7f686b3, 0x425922bf, + 0x9a3eebed, 0xbc75e5ca, 0x6d3c83a8, 0xf4f1fce4, 0x8bed12ad, 0x90edefc7, + 0xc2bf4fee, 0x3a79b7bf, 0xa36f7f8f, 0xef943dd4, 0xd40e6e68, 0x3b3be83d, + 0xe51bfbe5, 0xfbe51a7b, 0x239b29cd, 0x07e23ce8, 0xdcc92d0d, 0x5f10f5ef, + 0xf61e2bfe, 0x30d0f580, 0x5e4a1f56, 0xfd16a777, 0xbb8d2a6b, 0x476f71e1, + 0x29ff086a, 0x7848e309, 0x5ed499cf, 0xa9b385e3, 0xfa8178ea, 0x46e178da, + 0x4bee3dd5, 0xdd7a3765, 0x8df94203, 0x2dfe7037, 0x9bfcf3df, 0x4d6dd143, + 0x15f3e878, 0x1d44d32b, 0x380e735d, 0x245df1eb, 0x924debb7, 0x51b72fed, + 0xf540dd3d, 0x36af4574, 0x73f9f145, 0x7b4a7cc5, 0xb3d71a47, 0xf9d0864d, + 0xdc62a9b2, 0x2831d946, 0xcf41da0d, 0x8397f3a8, 0xcbf9d45b, 0xe7d55a5b, + 0xa9f50c85, 0x3fc903cf, 0xa61f3ea4, 0x1f3eafd0, 0xf509f866, 0x3b2330f9, + 0xdcc3e7d4, 0x7cfaa1f6, 0xab741f98, 0x5fb797f3, 0x5ef9aa9e, 0x77cfcbd3, + 0x7e0dce02, 0x4f34c4ae, 0x4e8d2e73, 0x844d2e73, 0xcd1a5ce6, 0xde622839, + 0xcd1f4f2c, 0xf5ea34f9, 0x971eb159, 0xb8f5fd7b, 0x44d8fa67, 0x386fae3d, + 0x5948f73e, 0x6dfa384e, 0xffd377ca, 0x97ccf821, 0xf48b9ae6, 0x5b1ead71, + 0xb1d57c87, 0xf3032c2a, 0x29d5ae2e, 0x83f03c72, 0xbe8921eb, 0x9d5e2f9b, + 0xe67bfb42, 0x3f250c35, 0xc8398f29, 0x638caa4f, 0x5873cf21, 0xd6f5c69f, + 0x33037adc, 0x6ccbe0c6, 0xd0a81d46, 0x5b124d73, 0x798dedcf, 0x3561f022, + 0xbb587ce3, 0xd53458ee, 0x59dd85bd, 0xaac151c4, 0xb9d217eb, 0x5d73da0d, + 0x318b586a, 0xbc59e605, 0x41e49da1, 0x628bce7b, 0x9e62dc87, 0x7df516da, + 0x8170db37, 0x1d6789ce, 0xee33b446, 0x86fdf556, 0xb32f5134, 0x8dca3b33, + 0x1328beeb, 0x02c597fa, 0x4836732f, 0xce0fac16, 0xb84f686b, 0x0ef3fa0b, + 0x296f14c9, 0xce3d6178, 0x73a5c9e1, 0xea1e2fd2, 0x45f3fe47, 0xc7092d9b, + 0xbc79a2b9, 0xc35de920, 0x9c657af1, 0x5f9e386b, 0x0a327dd6, 0xa761f1bf, + 0x5fc8eb2f, 0x08681f00, 0x36166df9, 0x3bcf3824, 0xc44960c7, 0xdd878b3c, + 0xa6714c93, 0x75957b88, 0xc7104dbb, 0xe21f6346, 0xe93ebe54, 0x46e8892b, + 0xfc1bad26, 0xf80f7c22, 0x9ac7143f, 0xfa156998, 0xcd6d673f, 0x3afae889, + 0x5f90301f, 0x2c477731, 0x1b7315f9, 0xfe788c4a, 0xb15ddcc1, 0x79967fb4, + 0xae31c71c, 0xba78e855, 0x3260ff21, 0x25b73bcc, 0xe9ab2ecb, 0x17138aa7, + 0xe8569d37, 0xba0d79d6, 0x1ba28675, 0xfd754bd0, 0x17e134e5, 0xfbb17a08, + 0xbdfbe8e3, 0xfa07a58a, 0x62efbe61, 0x0efd387d, 0xc038cf45, 0x5a64f5c3, + 0x29de2abc, 0x8e3573eb, 0x2fba73a3, 0xba24286d, 0xf655e969, 0xe386f3df, + 0xafec55f7, 0x8dfd0c51, 0xf66cbeca, 0x5b3eb854, 0xb955f2e2, 0xfa196c66, + 0x7d0a6f39, 0x8b88baf8, 0x045c618e, 0x189bfc7e, 0x2dff4117, 0x05fd1711, + 0x4f6822e3, 0x6d045c62, 0x4fff38a7, 0x00603391, 0x4293d7e2, 0xd55e4ebe, + 0x3193cbf3, 0xdff6569f, 0x80ea166f, 0xb53c12e7, 0x33a74693, 0xf6a1d936, + 0xa9a7cba7, 0x830ee9fd, 0xed324c65, 0x81f5e26b, 0x54dbceb9, 0x66de99e3, + 0x1b073cc4, 0x4eb81f90, 0xc466c7f6, 0x098cc73c, 0x3ff1aa71, 0xf5554a6c, + 0x0c5fa02f, 0xeb294df0, 0x777ebaab, 0x7f5520c5, 0x424065ce, 0x95af723e, + 0xe22ce79f, 0x2794ca24, 0x9f0dea06, 0xfa4f0fd6, 0xe9fbc011, 0xd7dd0311, + 0xeba143d2, 0xca3acdfc, 0x0cdbcedf, 0x3b79836b, 0x5c91e79b, 0x8a227c7d, + 0xdc6987ce, 0x08daff91, 0x61de9fe8, 0xa764fda0, 0xc21ee21b, 0xef4faaf3, + 0xefc68848, 0x328d5cf2, 0xb59e91f3, 0xe6559e90, 0x4558692d, 0xc7307fbf, + 0xf947661b, 0xf3dfb39f, 0xfdc7d2b8, 0x0645b401, 0xecb8e3e5, 0x3f4449f5, + 0x7b77e107, 0x3fc5e538, 0x058f3034, 0x1d79cbfc, 0x250fae1c, 0xb3fd80d6, + 0xfff4efe1, 0x6e71c011, 0x0e957362, 0x48f928fd, 0xe7cbe902, 0x5b7c8665, + 0xe740d4b1, 0x4b7a2f09, 0x267d8ade, 0x7a72a5e5, 0x1d3bf4cb, 0xcd187b6c, + 0x4381bacf, 0xdff2dc60, 0x5eb93d84, 0xffa8b9e4, 0xf5dec1fb, 0x8f913f82, + 0x8e658c3e, 0xe7960258, 0x963a3e1b, 0x009e7540, 0x7043bd3e, 0x3bd4bfdd, + 0xbd83a5fb, 0x3bcaa8fa, 0xfddaf484, 0x5a572409, 0xb91a77bc, 0x1ca0f2de, + 0x197d0148, 0x9dfe3390, 0x3d833cd5, 0xaafa4ed1, 0x55f50520, 0xe50306e7, + 0x11de9915, 0xcf70ebcd, 0xef2b1f13, 0xc6dbd4e9, 0x4d9d7c20, 0xe11df459, + 0xd9320ddc, 0x3e3fe43b, 0xebe3cbde, 0xe30bb28d, 0xe4934f75, 0xcb5d78c2, + 0x0e96cb37, 0x9815dfa7, 0xd9193885, 0x4f9c0f53, 0xa50775e1, 0x3f0f78bf, + 0x74159fd7, 0x0e0da7e8, 0x7f03475e, 0x5f9f325f, 0x26bc7739, 0xf0a74ffb, + 0x878ba668, 0xf7e0c6fa, 0xcb8f6738, 0xb36767c4, 0x0325879b, 0xedd13f3d, + 0xe823f61d, 0x73d13c7f, 0x70fd8f46, 0xebc454d7, 0x0c86dd12, 0xabba1efc, + 0x6e87bded, 0x7a3ee783, 0x312760d6, 0xfa40915f, 0x45f6f163, 0x7df75f99, + 0x3ef05810, 0x48e8cf3c, 0x4b9f0091, 0x30632d6c, 0x3980b07f, 0xf8e21d85, + 0x79e0edb1, 0x9e26cb0c, 0x30af78d7, 0x67ee3d6a, 0x5bc9a79b, 0x13be27bc, + 0xa92e905c, 0xa2ed84fc, 0xf9c74f3f, 0xf3c73d9b, 0xd2a7f059, 0xfbf16eff, + 0x57de8a1e, 0x6b0d75f4, 0x7fa9f3a6, 0xf04d9e94, 0x34bc922c, 0x9a4f0eae, + 0x65551506, 0xcd6af1e1, 0x8a5e6133, 0xe9606d47, 0xdd80fc82, 0x6e7a36e9, + 0x47d9f1b1, 0x32176d91, 0x669f5f3f, 0x6f0647dc, 0xa7ab3f95, 0x6cb2a9bd, + 0xfcd2b06d, 0x57ee3b06, 0xb4e4285c, 0xfaf259b6, 0x6ec83af8, 0x2cf3102e, + 0x6b537610, 0x23d87a9f, 0xa05a1d8d, 0x59acb3b1, 0x5e01576d, 0x815b973a, + 0x33a70b57, 0xb0f08a32, 0xcf9f99b8, 0x1ef2e551, 0x4b70449c, 0x0f64a076, + 0x67321678, 0xe3ae2c69, 0x6b8f1e19, 0xabaed3e1, 0x9d62bc07, 0xecabb85a, + 0x01727c17, 0xda0a3dff, 0x8759a9df, 0xbfad0f42, 0xcaa5d0a6, 0xd55bf1c3, + 0xdf3d1126, 0x3207eabf, 0xf0aa07da, 0xff816b0b, 0x4e779ea9, 0x70b67d42, + 0xacdfe813, 0xfc28ff00, 0x44b598b4, 0x31d4bf23, 0xd496235f, 0x7e5afacf, + 0xcf0b3238, 0xe7463a65, 0x7d585547, 0x80b174fd, 0x1fdfcf42, 0x8041fb2a, + 0xbe78b5af, 0x17af5d16, 0x11d44c6f, 0xd3c039e8, 0xfa64a782, 0x9c6827ae, + 0x243d7f88, 0x8f1ed54f, 0xd5cbeb11, 0xdc3e7e7a, 0xeb74e0b5, 0x5d29eff9, + 0xfc5ede13, 0xf70aefa4, 0xf9bde907, 0x4262fd59, 0x9d6529e9, 0x72bd08ef, + 0xb7aefb4d, 0xbec8c5df, 0x8f984827, 0x575f4de9, 0x00bebb09, 0x67b43ced, + 0xe740bf36, 0xe9bfbe2e, 0xd55f3a05, 0xda02ecf8, 0xf3667097, 0xf7f087bc, + 0x98ecce23, 0xe17d7647, 0x775d8a63, 0x85fd8319, 0x9e73cd92, 0xafc85ff8, + 0xdd5384cf, 0x4bbf6ab8, 0x47a039c4, 0x336d9c61, 0x136c9bd7, 0xd10ba3d7, + 0xfd92e5fe, 0xddc709bb, 0x09bae557, 0x3ae83ef9, 0xe6fbc5d9, 0x07b77eb9, + 0xb7efbde6, 0x2d0f7691, 0x79e3e2d9, 0xed0f8b67, 0x7f3ded5f, 0x0bbf4539, + 0xeb791f25, 0x87bd8ac7, 0x577aedee, 0x97ca0642, 0xf2b5f3b0, 0xfa0b0cd6, + 0xfc2ec205, 0x173df1b3, 0x14fe4df1, 0x4dbbf7c7, 0x6defcf1c, 0xdc6f78e0, + 0xd3e297d1, 0x92fa9b77, 0x8eeef51f, 0xf9ef847e, 0xe4df01eb, 0x7ed4db47, + 0x1be01354, 0x37c404e3, 0xbf7735c0, 0xcedbe04d, 0xf1c4ddf1, 0x76f036cc, + 0x7abc0f7e, 0xfbf4fce8, 0x8ecc3dfe, 0xe187c17e, 0x3e97f23e, 0x99d329dc, + 0xa59f8a67, 0xb19f39f8, 0x1fd1c7e6, 0xa8bdf053, 0xea087fbf, 0x7f8d8a97, + 0x2fbc468a, 0x2393c9da, 0x1ccdf03d, 0x076fe849, 0x2fd57fde, 0x0848cb2a, + 0x21be8bf2, 0x9398ea5d, 0xe1d723f6, 0x82436479, 0xbf2b3df6, 0xe7dda65b, + 0xc8f9e36c, 0x99376630, 0xed349e10, 0x18b9afef, 0xbcfe7bee, 0xf75985df, + 0xab771c90, 0x12634f7e, 0x9cf019f3, 0xd122d602, 0xe5da967e, 0x188ba34b, + 0x4f5a3f9e, 0xe0cdac70, 0xbc2bbd76, 0xb2fc833b, 0xef1c613d, 0xf3aaf19d, + 0x6fdd2789, 0xb457f98f, 0xf9f847fb, 0x763c93c4, 0x1a4e67ca, 0x2ab93431, + 0x2e0bae88, 0xab8973f3, 0xf2e6032e, 0xc6fdf7f1, 0x0587bed2, 0xcea853cd, + 0x496d055f, 0xbe5ef8f0, 0xc19b5bbf, 0xb8539be3, 0x973c3ca6, 0x9d7efc49, + 0xea8d1738, 0x539b80b4, 0x373a4ee1, 0xc98254ef, 0x8bbacfce, 0xeffdf3a1, + 0xa6707a16, 0x13ed20f9, 0xcc3c7987, 0xbfd6e78a, 0xab014069, 0x8b3c7530, + 0xe4ecf021, 0xe935eef7, 0x837f6b70, 0x7773e445, 0x13d7157d, 0xd51d009e, + 0x23b9b9e7, 0x9a3fe742, 0x87255e05, 0x610cea83, 0xbc047730, 0x3619e7ff, + 0x6fec5d7e, 0x9e805b67, 0x85cf3d51, 0x0f33ae53, 0xa6b60f3f, 0x2b7dfe18, + 0x7a848ce3, 0xfaa9d643, 0x7f7e4635, 0xc9c4c67b, 0xf631469b, 0xf7ac0306, + 0xf194bf45, 0x8c4e7f38, 0x4d75f717, 0xaca373c6, 0xaf89ead8, 0x4799eaa6, + 0x3326dbc7, 0x79c43bd6, 0xfe049351, 0xbe608fa6, 0xdf7de018, 0x89b9f561, + 0xbe74f977, 0x93af009b, 0x21ba5cf1, 0xcd9cfe78, 0x38f78160, 0x8c3ca4cb, + 0x7f566a4f, 0x64f77833, 0x94de4f94, 0x8e9d7d06, 0x9e63f9c3, 0xf989988f, + 0x2cc3c079, 0xe72fdb3d, 0x5e237a71, 0xed1b56dc, 0x2a5ee8f3, 0x25147ed1, + 0x7bd0af2f, 0x4f2f2068, 0xe0299c74, 0xa29a7983, 0x686379f1, 0x50ce1d7a, + 0x8a16e8e2, 0xf90897af, 0xe5c8a25c, 0x9e5cb50e, 0x7e823a45, 0xc8893dc6, + 0x0b453357, 0x6bf9a4eb, 0x73947bc4, 0xf064cfd3, 0x0c99e97c, 0xfe387f5e, + 0xccc7df2d, 0x45469cfc, 0xf8c36b3e, 0x27fbcafc, 0xc333b68b, 0xf02bf34a, + 0x1ff1f368, 0x7e43596c, 0xccb7f552, 0x1be907c7, 0xc6497baa, 0x7a88f9ee, + 0x49c25fe9, 0x5b1a66ee, 0x7b9bd5fa, 0x1dce538e, 0x037e60ac, 0x55300faf, + 0x6cb4741d, 0x2b2c73a6, 0x9afbfe24, 0x1e51455d, 0x6be60c5d, 0x8ada440c, + 0xe973f31f, 0xfbe709de, 0xee632b3b, 0x607e849b, 0x4f51b445, 0x7f31ece7, + 0x40565654, 0xc91636ef, 0x04214e74, 0x6eb19382, 0x7feb06b6, 0x23b0ffbc, + 0xa24bb28d, 0x51d7b3ff, 0x02bb4d1f, 0x43fea7f4, 0x0f101d93, 0xf7101d75, + 0x7cf4c3d9, 0x8f8203d7, 0xfde73f3d, 0x37f7285f, 0xe53afef3, 0xffde16fe, + 0xe8bf3299, 0x5fdcd46f, 0x4bffb9a5, 0x627c4fde, 0xfa0f64cb, 0xa59cc5af, + 0xe8956e2b, 0x05ca3577, 0xf6ac559f, 0x742b7e11, 0xcc5b797b, 0x6b82ba7c, + 0x74ce2b8f, 0x211fa396, 0xa1467547, 0xe5909e9d, 0x75bb4728, 0x2b2bba6b, + 0x53c5da13, 0xd6118f24, 0xc97b8ecd, 0x45ea4c6e, 0xbe0b971f, 0xf9f1b22d, + 0x3cc37c14, 0xbf0b3303, 0x847e3cfd, 0x4f35412b, 0xf3c0f5fe, 0x798f5b6b, + 0x3ccf5d46, 0xbaf52cba, 0x89e83f14, 0x385dc76c, 0x2e1ed69f, 0x063da9f9, + 0x35ec50f3, 0xeae1fdf1, 0x987c8c96, 0xbb73c97f, 0xefd0aa33, 0x1d40fe12, + 0x3c7cc3da, 0xc3db82e7, 0xf24fdb8f, 0xdabb707d, 0xbf30638d, 0x3db06d0f, + 0xce05e9ac, 0xd89d4c8a, 0xd791b047, 0xab3b9ec5, 0xd12e7a47, 0x0c799cb5, + 0x52adfbed, 0x1127dfe8, 0xe5ea9dcf, 0x66e68e77, 0x90d43d72, 0xeb8398e3, + 0x3464c92c, 0xe84d64be, 0x9b7f9a73, 0x8572edc9, 0x86f37bb0, 0x806c9945, + 0xaee3c2e7, 0xaabfb835, 0x1e564b6a, 0xa56785e6, 0xfcc92f17, 0x376abcda, + 0xf1b6abcf, 0xd5856abc, 0x37941cbf, 0xedb33a7b, 0x633a5361, 0x914dffe3, + 0x78591033, 0xe94c2cb6, 0x74b939bf, 0x617bcf14, 0x4713dd7f, 0x39b9461e, + 0xfe60f084, 0x08e0f87c, 0x591d0bd4, 0xe80b3a91, 0x7369598b, 0xacfe469e, + 0xda03fe1c, 0x1614532f, 0xcf0e7fd5, 0xcc5f13cf, 0x42ae734a, 0xe63c7138, + 0x5f465c43, 0x0eb05dc2, 0xed32abd7, 0x890d7553, 0x4efc8574, 0xe9e1e059, + 0xebe10b4c, 0xfd199010, 0xe50e0514, 0x2fe7e0fd, 0x9d7cc3f7, 0xe28653ab, + 0xb4be4e77, 0x85996da2, 0xd2fbf781, 0xbf048f5c, 0xfac753bf, 0x4df1a863, + 0xc05878e1, 0x06e90db1, 0xcc9473ad, 0xdef1411c, 0x5548d2d4, 0x3884da7f, + 0xd7ce08e6, 0xf5554b4e, 0xaafa2bcb, 0x7f3ddfc6, 0xc4feea90, 0x7d417f30, + 0xbbdbbf90, 0xe7e1e49f, 0x4545458f, 0xbfbcbee0, 0x36f67db7, 0xd7745efe, + 0x7d1db253, 0xb67b45da, 0x03478dbd, 0xb39fc45f, 0x8da43ca0, 0x1d1f66f2, + 0xd73f1992, 0xae0fa1c2, 0xfe639d0f, 0x1077f147, 0x2907ab7a, 0xcb12eef1, + 0x801dfa7e, 0x3a0f5d1b, 0x41ea2998, 0xed0f2c79, 0xb7fac5e1, 0x67576f28, + 0xb73bebe6, 0x8b4f9f9b, 0x057f53e7, 0x3e077efc, 0x65e1fe88, 0x4bb5e50f, + 0xfd534f5a, 0xeb932aac, 0xa5b4bae9, 0xdd8bf47a, 0x181da2d0, 0x062afa03, + 0xcedfc5f8, 0x7dc2ef06, 0xdc51596c, 0x953cbf5f, 0x2be438b1, 0x9439e79e, + 0x53bf4b18, 0x8ca9a4bc, 0x8e5dd7ae, 0x975ff9a0, 0xcd4fb4fd, 0x754492f3, + 0x95a98988, 0xc6bf71ab, 0xee4f08a1, 0xc4ef7832, 0x8651dddf, 0xc5dbab78, + 0x944c91f7, 0x0a5828df, 0x19734d6d, 0x66513f3d, 0x17f02487, 0xfb7097c6, + 0xbe6d113b, 0x46e0f715, 0x2bbb47ad, 0x7ffd7d1b, 0x18c67a85, 0xe6267a45, + 0x7ef4ddf2, 0x3d1365f7, 0x88f425df, 0x35c383a1, 0xae93b2fa, 0x59f0fc2b, + 0x77eab666, 0x4f090c7f, 0x91f7f1e9, 0xc68c1d0d, 0x903cbb8f, 0xafbd655a, + 0xfa77f80e, 0xc2435b5d, 0xfa5fb4a7, 0x42c978d5, 0x0f46886e, 0x1e1faa5f, + 0xa9e842c3, 0xf111efab, 0x5fea1848, 0x72ccbf68, 0x3012da44, 0x63d0e99e, + 0x4d99885d, 0xffe44fb4, 0x0538cd00, 0x00800076, 0x00000000, 0x00088b1f, + 0x00000000, 0x7dc5ff00, 0xd554780b, 0x399ef0b5, 0x66491e67, 0x99212726, + 0x4ce21024, 0xe010245e, 0x0f080424, 0x860240cb, 0x084013a7, 0xbc80e834, + 0x2b101025, 0x0337e95e, 0x60d22049, 0x45405283, 0x68b0503b, 0xaaf8ff6d, + 0x0131f5a9, 0xe94a0fe4, 0x7ab7bd60, 0x52036b6f, 0xe08d4504, 0xb16dcfed, + 0xbdad6bfe, 0x3267324f, 0xfdeded41, 0xbe3ef9ff, 0x3ef6759d, 0x7af6b1fb, + 0xb30fb5ef, 0xcb5d8aca, 0x0afb188b, 0x9318137f, 0xbb302e8e, 0xda663286, + 0xb1ecc67d, 0xb2816631, 0x96bea23c, 0x046b4f31, 0x2e4995ac, 0x19236323, + 0x3950b6fc, 0xfbc1db0b, 0x631f77cc, 0x576ec64e, 0x4a6dff18, 0xb1832c65, + 0xed04dfbf, 0x0fde7b53, 0x852ea01b, 0x968bc0b1, 0xbbf861e0, 0xc72fb65f, + 0x89e1f505, 0xec39faac, 0x55670e47, 0xcddfa1d9, 0xda15b29d, 0x39559b31, + 0x9ff806ec, 0x6f82ff34, 0x8ba77f39, 0x12b7ffcf, 0xfdfd84db, 0xb084c276, + 0x7ed5e607, 0x921188ff, 0x31dfa7ab, 0x63b5332e, 0x5675d74a, 0xd7bad8ca, + 0x603b5c12, 0xc1fb337d, 0x5ebb8033, 0xba0f04b5, 0xa43339e9, 0x68396960, + 0x8e75fa80, 0x8c2f7cae, 0x5c7afe5f, 0x7e830d88, 0x19938f5f, 0xae52f38c, + 0xa5e20c6f, 0x1541f5fc, 0xf24c0706, 0xa0cc8b15, 0x3c9ba4dd, 0x5f79f163, + 0xaf5e8df3, 0xf9c60256, 0x18a7cefc, 0xadbbbdf1, 0x5529b5fc, 0x22624086, + 0xc954d774, 0x16c608d8, 0x9b0d9b5f, 0x6b92d8c2, 0x5afb04f1, 0x75abf3f8, + 0xdf705369, 0x49866eae, 0x6c963ac3, 0x017d0c36, 0x765cc5d6, 0x30f00f35, + 0xada2c073, 0x5339e60c, 0x677ad232, 0xd60a490e, 0x71dbd343, 0x73e0c7bf, + 0x664861d6, 0x3db97a6c, 0xd6f18460, 0xdfa8535c, 0x1a2e6bda, 0x64b5ed6f, + 0xb35dd782, 0xdae4b952, 0xb96e7a60, 0x801e6466, 0x1c035e97, 0xdb273c00, + 0x3fd70ab7, 0x4a96feb3, 0x35b7cf1c, 0x8b67d4a3, 0x82b317a4, 0x92f40574, + 0xb3d6dcbe, 0x05f6fafe, 0x2fe85530, 0xb2f44bc5, 0x88f2ca14, 0x0e8265fa, + 0x56b6f1a2, 0xa537ffec, 0x5f411a97, 0x3ca16c4b, 0x54c1e023, 0x856ea717, + 0x71495cf9, 0x6cbc414d, 0x6fe38078, 0x6e5bc983, 0x786ef987, 0xcec2a0c4, + 0xd9473bb0, 0x32f00cad, 0xb33addea, 0x176e822f, 0x5cc61b5c, 0xd739feb0, + 0x7dbca972, 0xae336fa0, 0x79b5f17f, 0xa8c34f02, 0x2364d664, 0x46d8c51b, + 0x4e1757dc, 0xb3ef9928, 0x7517df98, 0x85eed3a3, 0x6538bff1, 0xb88bfaa2, + 0x5530252f, 0x9c09e04f, 0x51682997, 0x2ebcc00f, 0x8140589a, 0x9f73b8ad, + 0xdf000591, 0x41f4a14b, 0xb07b5d09, 0x291de59d, 0x92ed8ed8, 0x04a92798, + 0x2deb09f1, 0x057c63e0, 0xc2192eff, 0xfd42f7f9, 0x965b3327, 0x81e0731b, + 0x86552a74, 0x9cf27e75, 0xbe7824c4, 0x4e1bfd6a, 0x95ab1e58, 0x5029640e, + 0xcc10d1bf, 0x3d8c4937, 0xe2f6fb22, 0xd85a3eba, 0xd0656ffa, 0xf3cb7cee, + 0x0d57dc0e, 0x2872adaf, 0x0569fb0f, 0xee60067c, 0x6552cdad, 0x26c346d0, + 0xa1ed0d54, 0xa39e8d6f, 0xb5f57ce9, 0xaba7a26c, 0x2fa19675, 0xdd031d20, + 0x415af3e2, 0xfd2177ef, 0xacea6943, 0xe9c8f414, 0x5aeba35f, 0x5aadcb99, + 0x0030625b, 0xbff99bf3, 0xf500fe80, 0xf2a85f6b, 0x2bba444e, 0x5079a830, + 0x32fc11ac, 0xe0f83a53, 0xcf83e458, 0x787ad452, 0x579af93e, 0xc1f3d73c, + 0xc674fe4b, 0xbc4b19f2, 0xd5c690b6, 0xe822dfe8, 0xdff484dd, 0x2d83de8f, + 0xd9fffe05, 0x77ff9edf, 0xdb90f3f8, 0x6be216f7, 0x7fca1c9a, 0x3b4b052c, + 0x94e4d1d1, 0xe7e9192a, 0xb3cfcb9b, 0xd59e7e42, 0x7db5cfc9, 0xb7f0cfc8, + 0x04d787e4, 0xd85a543f, 0x2e22de1d, 0x7bdb67df, 0x3d97ebfa, 0xea0b9ce9, + 0x7819743f, 0xf343ff7f, 0xca5bf0fe, 0x86fd7ffd, 0x42afff72, 0x79cb47ee, + 0x9ca1fd06, 0xc2d5ecff, 0xf781ea20, 0xd405e819, 0xb824af7b, 0x403d0b0e, + 0x313e227a, 0xd03d2378, 0x5fe77b90, 0x7f03d0fb, 0xa3fdbc43, 0x3fa3407a, + 0xfe345f8d, 0x9a21f8d0, 0x987e347f, 0xf13503fe, 0x401fdc5e, 0x1fe461cc, + 0xae0cf039, 0x5095d6a3, 0xf1a97c8c, 0x0c17dad1, 0xf4bd67c4, 0x1e9be083, + 0x0bebd13e, 0x3e341f8d, 0x56a6f8d1, 0x28b2c3f0, 0xb526387e, 0xde163c3e, + 0x15f6eedb, 0xf87b53b9, 0xd173cd63, 0x7a4fa17a, 0xcb4f4862, 0xd218ea52, + 0x91942d53, 0x83e964f4, 0xdfdd8a9e, 0x126e9e8e, 0x9e8ebfed, 0x6a66dc2a, + 0x4f483ff7, 0x3191ee15, 0xfbb269e9, 0x5c57689f, 0xa97dfbad, 0xb573e60b, + 0xbbace414, 0xbfa6de87, 0x90ddb8c5, 0x7e915763, 0x3af9e23a, 0x8303cc3b, + 0x2beed8f5, 0xd4788756, 0x67db52e8, 0x86580ecd, 0xb6e50074, 0x9c2aef6c, + 0xa07c476f, 0x9337fd68, 0x96cfb477, 0x53d9b094, 0xd61dfb84, 0xecbeffe9, + 0x72dfb5c5, 0xdfdc6b9f, 0xddf86e4c, 0xd17b74ff, 0x272d8eef, 0x7d9dff02, + 0x7f0e599d, 0x94f047f6, 0xf61e33d7, 0x660287e7, 0xcbf22f61, 0xfead32bc, + 0x191e2d37, 0x3dfc03e5, 0x30f04696, 0xc381e12b, 0x0ae1d381, 0x87f4e798, + 0x5803ebbb, 0xa27c793f, 0x0c798fe8, 0x8ffda7ac, 0x6e15bc0f, 0xc2defd26, + 0x94ebeff1, 0xe02343bd, 0x11ed8052, 0xbc145970, 0xc877b79f, 0x7ea14c9d, + 0xa0af9c82, 0xc209437f, 0x7e827f5a, 0x55f8e799, 0xc52cf3c0, 0x3ec076c0, + 0xf0394bad, 0x6b9455c6, 0x7066066d, 0xfd81e045, 0x04c9ebde, 0x20c578ba, + 0x7b08ffe0, 0xf85b1972, 0xb84f8702, 0xc812d4ff, 0xbe02fd15, 0x9b7408d7, + 0x091e0d5a, 0x66535bfa, 0x7bbb6608, 0x5b84fbe3, 0x7cdaabd3, 0xdfea5540, + 0x6f94e667, 0x6d1a3ef7, 0xbd367ef4, 0x8b7cb21f, 0x678fe7f1, 0x7b0c609e, + 0x1f820ff8, 0x63134a2a, 0x4b779fd6, 0x01d7ff1c, 0x4787c6d6, 0xc1fd6073, + 0x5975fc18, 0x1a3617f4, 0xd6ff3e05, 0x36167482, 0x6bfef86b, 0x327be20b, + 0x8274dd63, 0x13e30374, 0x7fdc7ffc, 0x7cc936f5, 0x7c289eb9, 0x6fbd68dd, + 0x2057c0c6, 0x372cbf6a, 0x6ee9f7c0, 0xbef3d0b9, 0xe87eff4b, 0x4ef5fb46, + 0xdd05f1af, 0xd8e8d4ae, 0x44f7a3a3, 0x99f44bd9, 0x02506298, 0xbd6b8f40, + 0x2fe8cd71, 0xa9a7f0f4, 0x8e14f10a, 0x87a9e3d3, 0x1555ccff, 0x448fb236, + 0xe42eeb7b, 0xbbb1af5f, 0x6ec7e73d, 0x029e66ba, 0xd29a2bc0, 0x41d27ef8, + 0x8d80aecb, 0x09ea82e8, 0x77988dce, 0x46b63f34, 0xf8a3e3c1, 0xc91ff057, + 0x8007d40f, 0x6f943ca7, 0xaecd6729, 0xb3513a08, 0x313e9e39, 0xa7946ab0, + 0x8edc49e1, 0xd2f3670c, 0xfaa06d9b, 0x1fbe6cb2, 0xe386511e, 0xa7a0f023, + 0x2bfa109f, 0x3c26eb11, 0xd6d1482d, 0x0335505d, 0xe64e15d6, 0x73b2d3f5, + 0x7b320577, 0x66fee8e0, 0x05541764, 0xcffb228a, 0x5d78833f, 0xcde6f020, + 0xeb06741e, 0x4b507935, 0x11f44284, 0x8b507940, 0x4de861f4, 0xbdd9e91f, + 0xf51033e8, 0x8374c7be, 0xbf7ab3f7, 0x9f7a89ef, 0xcdbe5299, 0x66df62fb, + 0x656bed44, 0x4456bed4, 0x1c1a35c1, 0x4d5fc9d4, 0xdb692f2e, 0x7984e8d5, + 0xe40475dc, 0xe7a48b2c, 0x77cf4451, 0x8efd1a29, 0xbb7a833e, 0x08cb9e87, + 0xf62add9e, 0x1766302d, 0x942a9fea, 0xe07b63c3, 0x08872839, 0x19e55b1e, + 0xc6afa91e, 0x3db942ed, 0x3f6b49bf, 0x6c2fda9e, 0x99bbfad0, 0x647db5ea, + 0xd154ef81, 0xc3b90abe, 0x60ce1302, 0xf857eafd, 0x3d07f5fb, 0x0fc86e67, + 0xd978512d, 0xa207051f, 0x1afeefda, 0xf510d6fd, 0xfaa8e6fe, 0x5f7828e6, + 0x7fa4dc14, 0x0352f17f, 0xa062e1f1, 0x6888dc07, 0x8fa68cbe, 0xedbbb387, + 0x6e7d6e9c, 0xa77d91b0, 0xf5e9abe3, 0xe0fc7e1c, 0xa2a6aacc, 0xd6fb3808, + 0xdff700aa, 0x2697480d, 0x73207fc6, 0x83d01203, 0xf9b90fa9, 0xb2e8be83, + 0xf3df5a20, 0x9fe13ffa, 0x332f6819, 0x4c725d9d, 0x92edc3d2, 0x6745ef36, + 0x43e11636, 0x42a9ae0d, 0x5efa7a7f, 0x9fc0bafd, 0xaac2f015, 0xbb08cc8a, + 0xcaa0b028, 0xad4eb113, 0xbf2f94fd, 0xe7bc7092, 0x1d5417b3, 0x499afa82, + 0x983abca1, 0x2f324d67, 0xa84a5f41, 0xf889d7af, 0x255794cd, 0x9acbea2f, + 0x86de50f8, 0xb27588a2, 0x675c7cd6, 0xed12fdfb, 0xf61ea04f, 0x98b4f007, + 0x8f0a2381, 0x331e64ee, 0xc4fa81cb, 0xc24f4dc4, 0x97eec77b, 0x7e9ea136, + 0x273f537f, 0x39c943fa, 0x963ceedc, 0x19739378, 0x7709edc0, 0xdf6dbc90, + 0xa3ca993e, 0x975b6792, 0xd9dbd8c2, 0x856caaab, 0x78489f58, 0x69707d3a, + 0xefa016d5, 0x7a2ed933, 0x38ac97df, 0xdeded0db, 0x5d876261, 0xe2952f38, + 0x5a778b48, 0x7ce0778a, 0xa2710cb6, 0x47e4b9fd, 0xa0325355, 0x934692dd, + 0xa754768a, 0xf9c2c951, 0x364c76f9, 0x06d2fd63, 0xa16e0651, 0xffbff5f2, + 0xed01dea4, 0xa8371ebb, 0xcdfda107, 0x35beb45f, 0x4d15e00c, 0xd16e2a39, + 0x2807e06b, 0x7db9ce30, 0xd0128283, 0x757107e5, 0xf6f16627, 0xb8afdb0c, + 0xab3d3aee, 0xca4bdb14, 0x017f6856, 0x7cfda39e, 0xa0e901e1, 0xb0e5e701, + 0x49601bc7, 0x1464be17, 0x68d0b9cf, 0xee7c6209, 0xfb77cd9c, 0x9f671c3e, + 0x767d2d09, 0x1872e0c1, 0x1d9f0f00, 0x3d2ab7bc, 0xc45b9f03, 0xb49bdefe, + 0xd8b0f018, 0xa43f4dd8, 0x7127964f, 0x7becb3f8, 0x3ac30eab, 0x88323c2e, + 0x722b57e2, 0x80d95d3c, 0xcf5cc2af, 0x107e58e7, 0xebd6f5c7, 0x40ee977f, + 0x97d7fe3b, 0xbe913897, 0xd6f426fe, 0x3896d76b, 0x55d84497, 0x89913fcb, + 0xbb375e0e, 0x5f7ce236, 0x40681f8f, 0xa0e81b3f, 0x97c9c61f, 0xe805bf0a, + 0x31f3d379, 0xcd7fabec, 0xdabf6896, 0xde3a907f, 0x6deba3a5, 0xdfc8a7a4, + 0x93f6d800, 0xa002bbad, 0x365bcfdb, 0x8e500fb1, 0x7147ee6d, 0xc84ca5db, + 0x82e26781, 0xf4b157e8, 0xf8c8fcd6, 0x8a1f374d, 0xd80c7ff6, 0x847faf09, + 0xfdf7e8f6, 0x761ff031, 0x7eddeb66, 0x401ec385, 0xbb43e2e3, 0x78fdc65d, + 0xb85ff65f, 0xfe5bde0f, 0xc0f489b8, 0x3753c7f2, 0x40b8e177, 0x8b571837, + 0x1c82d75e, 0xf4638f13, 0x878197c5, 0xfe742aab, 0xbf24c3ca, 0xfccbe2fb, + 0x75543c9f, 0x5f37d6c8, 0x7cb850ae, 0xc9b8f29a, 0x62b4fc8b, 0xa0665da4, + 0xfe3d264f, 0xcfc461c6, 0x2571f58a, 0x8af89816, 0x5fb42dc7, 0x407b769d, + 0xc39f7a81, 0x5941272e, 0xd6e5c39a, 0xed171cbc, 0x64c4b973, 0x0d95096b, + 0x82bd6f18, 0x2f800de1, 0xcf787a6d, 0x23e71868, 0x1a379c16, 0xc3c577f0, + 0x0bcaf4e9, 0x991dc512, 0x826791ec, 0xb8c95cbc, 0xf93da89c, 0xfc2279bc, + 0xc56eb2b9, 0x5707f40c, 0x3ae74d05, 0xf18e0f85, 0xf9ac75d8, 0xea186973, + 0xa273fd57, 0xf3d62704, 0x49d61adf, 0x35b6a372, 0xdaebfbf6, 0xe467cff4, + 0x0c2e53d8, 0x2e431861, 0x2bb10c01, 0x067ca675, 0x03615c4b, 0x96f582fe, + 0xbcd037ef, 0x82926c57, 0x79779816, 0x3e2f1e3f, 0x37fd87ef, 0x0a03bad3, + 0x73762bc0, 0x1982b3bd, 0xf3f85682, 0x29ebfd96, 0xc84c797e, 0xe606c599, + 0x20fefa45, 0x3f42cd4e, 0x71e3f97f, 0x4f15df84, 0x47b7faac, 0x2dcebde0, + 0xfd225333, 0x174825ea, 0x9accbf1c, 0x87cfd3dc, 0x859fbe5b, 0x63fe5ff4, + 0x3d618ff0, 0x2fd8922b, 0xbf71b816, 0xb65cb232, 0xb62b769e, 0xdbcf9fde, + 0x7e0d7f81, 0x2407e2f4, 0xd17b075a, 0x78107a42, 0xdbc4895d, 0x669386d2, + 0x5bff1173, 0xdafb0a71, 0x39bc7285, 0xe7fbc12c, 0x11b25ea0, 0x119d02fe, + 0xb03bf271, 0x23920caf, 0x8d5f5c3e, 0x6cc770d1, 0x8ccba7ea, 0x8733bd7c, + 0x441b43c7, 0xbd4b38b9, 0x0fcfe29d, 0x6eadd45a, 0x4a348fde, 0xbbfc03cc, + 0x3978635a, 0x2fd981c6, 0x5957142d, 0x89e710d7, 0xe23f9073, 0x5dfa0e79, + 0x9cd93327, 0xfa72fd8c, 0x72e2e35b, 0x2bbf9e03, 0x3b5af3c3, 0x49b58b97, + 0x97ae6f80, 0xffe8463d, 0x872bfc33, 0xac3197f7, 0xf1eefde7, 0x85f53d0d, + 0xfd5f10c3, 0x3ce355e6, 0xdf112e7e, 0x2c1e3202, 0xe7eefb43, 0xabf408d2, + 0x6c703f17, 0xbbd9ca0a, 0xf0562d9e, 0xf8bfc5d5, 0xbb89e91d, 0xa2773ec4, + 0x037a8f9d, 0x7ca167e0, 0x45cb8732, 0x42e3c49f, 0x687c0a4f, 0xd7d5adfb, + 0xf1e2603e, 0x28e79079, 0xfcb76a40, 0xb5adfa9e, 0x67289d87, 0x8d345f6b, + 0x94fc7942, 0x2d92ff98, 0x0bbfc703, 0x94c4b3f4, 0x5a5ea0a8, 0x46699813, + 0x818b4d78, 0x52f79ee0, 0x3f1e90b3, 0x81c9786e, 0x5c41f274, 0x4ff50f28, + 0xf538fad7, 0xe1402e20, 0x1b8fb971, 0xfc620ef2, 0xb612a966, 0xe97ea01b, + 0x94649cc6, 0x212befd3, 0xdfbfd633, 0xec2236ea, 0x08f19451, 0x04e1e47b, + 0xab220c7f, 0xca0fd055, 0xbe06b599, 0x399e6b9f, 0xf186ce66, 0xfdc3937e, + 0xfe7e4f9b, 0xf38c7cbb, 0xf38566d4, 0x7ec07f51, 0x3c400fe7, 0xfd206d3f, + 0xc919f6bb, 0x67ac3713, 0x7ee2d7bf, 0x16ad7f03, 0x85f6bcfb, 0xba45ee97, + 0x5dfb8b5f, 0x805e9bd2, 0xf3d38f6e, 0x614c0ee7, 0x48e3fdfc, 0x02be9a17, + 0x8c94c1b8, 0x9f0e3a71, 0x02fce1ce, 0xf3f82bcf, 0x4bc91140, 0x67682390, + 0x5f7bd346, 0xd8b1fbfb, 0x2c5b25bf, 0x163f5724, 0xc0f9dbfb, 0xbfdc0e8b, + 0xec7e7e4f, 0xd4a39e04, 0xd8da073e, 0x05ee8315, 0xfae1d63e, 0xb27f341d, + 0x7ae1d623, 0xefeb3d1d, 0x6fc173a6, 0x9f5f18eb, 0xb275deb6, 0x2f56bf58, + 0xd62cbfde, 0x7c0986b9, 0xf38830bd, 0xe427e097, 0xb4c7b457, 0xf992f9f5, + 0x267d1afb, 0xffb972e7, 0x99ff2137, 0xfc40ead2, 0x9ca2fee0, 0x98f1fa01, + 0x01b90947, 0x16793e4d, 0x5fb11fe6, 0x73b3fcda, 0xae403cf9, 0x7b929279, + 0xc8d3b1f6, 0xb73ac656, 0x78e5c84c, 0x9698db3c, 0xfbf806d5, 0x892bfc18, + 0x23957a71, 0x46e8d3c6, 0x67fcaf1b, 0xdd70d355, 0xfb087fd0, 0x3f7dc6d7, + 0x3f632090, 0x1fce33ef, 0xbe35fcda, 0x345faf2c, 0xed81d8ad, 0x14e7b13e, + 0xdd39bae1, 0x542ae766, 0x802ed07a, 0x066d3df7, 0x159f4f8a, 0xc6d9fcfe, + 0x8a4b1c97, 0x25dde87a, 0xd93f8de6, 0x1a9e7bd9, 0x33d045fd, 0xfb7cb3cd, + 0x6b0869fc, 0x4ba68df3, 0x7d1a6f0d, 0x64a9cdb2, 0xe9d344af, 0x66b3ccba, + 0xb9fa2f1c, 0x807cb766, 0xffe415f1, 0xf2e3c654, 0x6e78ec0d, 0x9f863e84, + 0xd1ea8d8d, 0xd79c9a0f, 0x14baf3f4, 0x2fc225cf, 0x43703a0b, 0x5366e736, + 0xc72977bf, 0xfde039b7, 0x74c3e731, 0x87d9abfe, 0x92117f37, 0xf48e3112, + 0x5224bb82, 0x7cb9adcf, 0x96b6e89c, 0xbfa1b785, 0xdf81f8b3, 0xf48d1ccd, + 0xce8994f9, 0x4e37165b, 0xbddda336, 0xa39df0ea, 0x35cfdf70, 0xa9763d71, + 0x6893e461, 0x7a6b9f37, 0x116779d8, 0x653e57be, 0xbc5f3c2c, 0xf5f698ab, + 0x4cf0b883, 0x91eebb84, 0x6f7841d8, 0x9b91e1dc, 0xce3c0217, 0xae12537e, + 0x5243fdef, 0x3a08d8c5, 0xcd94ca58, 0x934ed10b, 0x8be41513, 0xab3c85f7, + 0x5a7df137, 0x517fe82e, 0x45f3e72e, 0xebcb7f62, 0x7cf1f3eb, 0xc800ebbc, + 0x8d63c051, 0xc21ad5d9, 0x234d5f71, 0xd81d7fbb, 0x74c9e908, 0xd2764d4e, + 0x66b3334a, 0x6b73d094, 0x693f3c06, 0xeb83df0a, 0xbd8f7939, 0x58e20b78, + 0x096a3eba, 0x5f896fb7, 0xf1a5aec0, 0x3168edbb, 0x2e82658f, 0xded3fba3, + 0x1ebb40ef, 0xff989ee5, 0xe6a786a5, 0x74babea1, 0xd7192f24, 0x71abe1ff, + 0x7cdf684d, 0x4c72e268, 0xaeec1feb, 0x11f691f3, 0x183a5bd8, 0x0c1d2aec, + 0x6f5e75f4, 0xbc256d8f, 0xb7ab9bdc, 0xad3a34ab, 0x18979f59, 0xcbd01799, + 0x0a43fefe, 0x9cf7ff9d, 0x644e8cbf, 0x7742e431, 0x880fd5dc, 0x3c6c67ca, + 0xcf18fada, 0xf9f2f84d, 0x2ddfda30, 0xeb02c516, 0x8e748f3c, 0x4a2f4be7, + 0x72b7eedc, 0xe2ff3fba, 0x77fa2088, 0xe1c0ffcb, 0x2086ade5, 0xdf1edd1e, + 0xf6c25db5, 0x4beec0cb, 0xb3d84433, 0x03cd77bb, 0x545767f2, 0x680cb6df, + 0xcf08e57f, 0x5b6a8077, 0x227b1d94, 0x1db7d5c3, 0x5fb6cffb, 0x61c0b8b5, + 0x532adf0d, 0x9e1adf11, 0x75e67f35, 0x92b287a0, 0xea7dbc1e, 0xebf6495f, + 0xca8fbf65, 0x1f670ccf, 0x6c74871c, 0x5f91544f, 0xb0f6dd7e, 0xfbf70034, + 0xe8ebe285, 0x25b58e97, 0x9fb7c82a, 0xb9d137fa, 0x1d7f65e6, 0x6b7eda95, + 0x5f9bb171, 0x3ef7a768, 0xcaf11b6d, 0x35ef7838, 0xd790a25b, 0x35f731c9, + 0xeee3bf3a, 0xf0d3a3f5, 0x8faeb6b9, 0xabfbe3ee, 0x23a3fbcd, 0x5d703a77, + 0x7bf58fed, 0x6bee0c65, 0xf682a242, 0xdf910ad9, 0x971f6171, 0x89ad170f, + 0xfd80ce4f, 0x8e7fb8bd, 0x5c9c8193, 0x1e773ed6, 0xaafe5f3e, 0x5cfb4141, + 0x81cab57d, 0xcb3f8df1, 0x4b050e9d, 0xf3842f78, 0xca128391, 0x6c95b1a3, + 0x1b1fb60e, 0xfa0b9992, 0xd3833319, 0x72cb98c9, 0x3e780f10, 0xb714e786, + 0x714f1eb8, 0xc3f5f80b, 0xbf658dfc, 0x0d0ef1e2, 0x35df9aef, 0x04dbac4e, + 0x2e7447ec, 0xf197979e, 0x7fee1fe7, 0x77f6167e, 0xc14990e9, 0xc87a7f79, + 0x06affd44, 0xe308c97f, 0xfdc23c5d, 0xdce38410, 0xdfdcc7c8, 0xfdcadd58, + 0x26f5da8d, 0x37b1398f, 0xb447963d, 0x9e0ebf43, 0x55dc70b9, 0x3a34de82, + 0xebe1ed5d, 0x0d7a0d5b, 0xb74d1bd7, 0x1b75ac49, 0xe8ebe9e2, 0xedd29bf7, + 0x135e90df, 0xe87cb758, 0xe8bed7a6, 0xf913e044, 0xa355e91d, 0xf8fbd587, + 0x6b727a39, 0x3ba444f1, 0x79343e8d, 0x0ac49812, 0x9bd66f50, 0xdde60159, + 0x2af18c04, 0x9b2a81ca, 0x7f7284cb, 0x05674a4e, 0x1e4965a2, 0xb952a797, + 0xfd4463d1, 0x79216f53, 0x526f2d11, 0xdffcb8f2, 0xed074483, 0x2a14f28b, + 0xfc8eac4d, 0x8584ad07, 0x5cfd440c, 0x9ffc9095, 0x5372682e, 0x65b383de, + 0xb8d57f98, 0x54727be4, 0xede506c6, 0xe488f0e6, 0x97a82691, 0x5d9a1feb, + 0x9e457001, 0x445e6067, 0xa70e97bf, 0xc0f5c40d, 0x8c1e5773, 0x97c53dbb, + 0xb33ae583, 0x67f7e48d, 0x9b61ae86, 0xcfed3ddc, 0xff7f6abc, 0xb81eaed7, + 0xd4b2c4d3, 0xcd198422, 0xcaef2b5b, 0xe3e60cf3, 0x612f9fe8, 0xe2f291ac, + 0x5dfbff02, 0xe7e043b4, 0xdefec2b5, 0x8969e82a, 0xfdc216d5, 0xcba64d64, + 0xa80576dd, 0xca26a67e, 0x04b30748, 0x872adc1d, 0x42fdf1da, 0xb05ca0d6, + 0xffb3e992, 0x3a377eab, 0x05d995a7, 0x87a03fad, 0x3eb04ccf, 0x900367a0, + 0x196026d7, 0x06b12003, 0x95e197e4, 0xd85ffdff, 0x75807d6f, 0x6b9e11c6, + 0x067b9414, 0x057e33e6, 0x63826d65, 0x3c33c618, 0x3643d92f, 0x3f0dc7d8, + 0x5fba204f, 0x5217ec25, 0xa65f98c6, 0x74b0f5f0, 0x8f7fde7e, 0xfd0fb7a0, + 0x5817372c, 0xf47613fb, 0xb1e61953, 0x1b37ce2a, 0x78c6bdf1, 0x0b836b2a, + 0x81deb4f9, 0xbf27c576, 0x09145490, 0xc8dd846b, 0x7e0aa50e, 0xa0134297, + 0x785dc3be, 0x8d4bf510, 0x6ecb97a0, 0x606f7e46, 0xfaf2858b, 0x5963f5d8, + 0x995c03f7, 0xfe8a8b7d, 0xb767e5e4, 0x7d832ee7, 0x0ed8c0b2, 0xe854e758, + 0x6aa60cb3, 0x73a25802, 0x03f520de, 0x3c0701f5, 0x387ee6df, 0xf319d38b, + 0xfdb47ae2, 0x6bdef0d1, 0xb468603f, 0x66568d2f, 0x90b1ff42, 0xff9057ed, + 0x8c997db4, 0xfff03dce, 0x9c791786, 0x75818363, 0xf9af18c3, 0x8d780ad0, + 0x4f6a5f21, 0x267641be, 0x27405bb0, 0x19dff657, 0x1d95ff5b, 0xffd76330, + 0x98d83d6c, 0x315ff427, 0x037b262b, 0xadfd0697, 0x4b266d10, 0xd7192e35, + 0x91556a93, 0x9e3c361e, 0x1d867a43, 0xa0f44dd9, 0xfbfb63b5, 0x736c9d11, + 0x55ff844b, 0xcc4cb06d, 0x4feb69d3, 0xda338b79, 0x5c74a992, 0x97e7a74b, + 0x94ab7c9e, 0x3fbe1bcb, 0x369a7f33, 0x7e83f289, 0x6d4a883a, 0xbd041b1e, + 0xe2be7869, 0xc93e7815, 0xbb06d5f5, 0x397dfc99, 0x79489850, 0x0b121d8c, + 0xe4f73c02, 0x57e2131c, 0x6d74e78a, 0x57323749, 0xc459bc0c, 0xe2b9c47e, + 0xded22b99, 0x68c2780f, 0xf517cfd7, 0x51c90509, 0xe6df7cf5, 0xb7cfe589, + 0xf3819cad, 0x75fdabb6, 0x4c776ce3, 0x92ba20e9, 0x5f38cb2e, 0xeb0304cb, + 0x352be787, 0x3b987dfa, 0xc69b0f57, 0xd5f24e7f, 0xbf7a3e34, 0x4dfd0999, + 0xfcff478b, 0x17a13cb5, 0xe461590a, 0x9fc2f63e, 0x0d7c4acd, 0x78ef79da, + 0x9875e780, 0xedc5d058, 0xafc7b435, 0xb7442c78, 0xde04e3db, 0x21e9a50c, + 0xa6589f68, 0x47925fc7, 0x957eaf8f, 0x7aa4fc7a, 0xab4878f5, 0x67d5d6ce, + 0xeaeb06f8, 0xd12cac07, 0xc6eb03c1, 0xb4dfdaea, 0x760e9269, 0xdae9a607, + 0xd6cd34e7, 0x0b2d79c1, 0xed07ed75, 0x2faba25b, 0xd5d6ae0c, 0x41b2390f, + 0xfd6d0f07, 0xe1fb5d17, 0xf5755b6d, 0xba1da1c5, 0x0f1d11fa, 0xe191e0e9, + 0x47ed7547, 0x57507bbf, 0x69f3a63f, 0x8bb8fd5d, 0x9be0e9cf, 0xb5d65ebb, + 0xa8ed709f, 0xdec89e0e, 0xb72fb5d2, 0x4f074efe, 0xd743fe56, 0x0ff496fe, + 0x5d53f574, 0xa7eaeb1f, 0xc1d55c17, 0x097d9877, 0xea97c8f9, 0xcdef74df, + 0x8e1fae62, 0x9f9e3a07, 0x00435462, 0xfc85f3db, 0x8c977410, 0xdaed13fa, + 0x7485965c, 0x1f1a593a, 0x336bba22, 0x4457e8a8, 0x63f927eb, 0x65e307af, + 0x8a8325ec, 0xb044ac71, 0xf188e4eb, 0x70563c92, 0x7ee07b00, 0x4e0e8a95, + 0xdaeba6f5, 0x74bb55a7, 0x02be19f5, 0x9580fd5d, 0x581e0eaa, 0x7f6ba657, + 0x0e8f26d3, 0x752a0776, 0xbc9a73ed, 0xa5af383a, 0xd07ed75a, 0xbeae9f3e, + 0x5752b830, 0x9d48e43f, 0xbada1e0e, 0x787ed749, 0x5f57405b, 0xd5d26a1c, + 0xd168e88f, 0xfbc323c1, 0xbf47ed74, 0x8fd5d41b, 0xaba23ce9, 0x55b1771f, + 0xd5dcdf07, 0xe13f6ba6, 0x4f07485a, 0xed752764, 0x7467adcb, 0x3de564f0, + 0xd25bfb5d, 0xa7eaeacf, 0xeae92eba, 0x7a647b35, 0xe7fae7c1, 0xa9993ec2, + 0xfdee97fe, 0x430f24c0, 0x673c08fa, 0xa05deb50, 0xb9b3f2ff, 0x2d13073e, + 0xc67b424e, 0xc945f94b, 0x7207a098, 0x2060312b, 0x5b9542ba, 0x149ef143, + 0x52a453d2, 0x0347985c, 0xde81de7a, 0xf68ddb93, 0x9d8f426d, 0x88d5f995, + 0x7d676e6f, 0x30387d1f, 0x944db65d, 0x0de563aa, 0xc79f3f7e, 0xfbe50e39, + 0xa2a7e436, 0x14ecf11f, 0xb157b3b4, 0xe79c36c0, 0xb128a964, 0x71a8e313, + 0x568538fa, 0x645eb54e, 0x77dd8472, 0xb325ae32, 0xfcfe06e4, 0x2665eb54, + 0x57e8888f, 0xb00c2fc4, 0xfd110dfe, 0x807e083f, 0x8b7f3e0c, 0x6c0af81f, + 0x0afc87a4, 0xe9fdbbc1, 0xbbf1ef04, 0x2fe7dca8, 0xbf51f2a0, 0xfdfbf54a, + 0xe13f0465, 0xf41c10f7, 0xd0795257, 0x87e7a5ef, 0x3f04d5fc, 0x96317e09, + 0xc64fc047, 0x77f069f2, 0xf019feb1, 0x85fe117f, 0xab65403f, 0x3f9e89bf, + 0xf8216fe7, 0x823eff05, 0x520fe97f, 0x423fe6d9, 0x56fecbe5, 0xdfc57faa, + 0xfe6bf046, 0x7f21c110, 0xfd47c107, 0xfb8f8261, 0x84f825df, 0x0eca93bf, + 0xdf2a45ff, 0xfd5177f4, 0x8235ff29, 0x6f53f67b, 0xf3e346ff, 0x65571123, + 0x215c4ec2, 0x70a587e8, 0x273970fb, 0xd042b605, 0xa81269ad, 0xfa3fb457, + 0x3cc41fe7, 0x574891d6, 0xa7574405, 0x1efd8dbe, 0x25697fed, 0x9bf719d0, + 0x3c781bd7, 0x22efd346, 0xefd3405f, 0x7f70f735, 0xbbd81175, 0x43ffff18, + 0xaf3fb71c, 0xd00a99d4, 0xc431ab8e, 0x5d2f68ab, 0xd933fba9, 0xafcf0c47, + 0x78ee4581, 0x476072c5, 0x0356df84, 0xfde11bef, 0x18b45999, 0x4c3ac356, + 0x332a2e74, 0x357c048f, 0x37efa076, 0x0f561fa8, 0x7fc80634, 0xd1f305b6, + 0xa07dbb6f, 0x7ef48c2f, 0x09d96ea5, 0xd2a28fc2, 0x4b4ce0b9, 0xc63e7528, + 0x144a4e49, 0x1f0bebdf, 0x785e44eb, 0x5daff59f, 0xbc3b44ca, 0x0f92eff2, + 0xc9b4e7f7, 0x83718d5e, 0x1fb9f20f, 0x51be41fa, 0xe81e5e57, 0xfcf3873b, + 0x76eebd8b, 0x2ff0a023, 0xe4ff59df, 0xbf1eeedd, 0x3d7456f9, 0x62ae5ec1, + 0x29e5132e, 0x6e1bcf32, 0xe636eae8, 0x0b3e7823, 0xa67b7950, 0xd75c63ef, + 0xd8241602, 0x1592d637, 0xf3d15d6b, 0x03908bfa, 0xea37c97f, 0xbe59feca, + 0xf2f3e4ff, 0x8f4ebcd0, 0xd71f25b9, 0x616bcda5, 0x3fe68b96, 0x813d758b, + 0xabcbfbf3, 0xe4305f9f, 0xff8fa6f4, 0x61b0ba01, 0x31da0598, 0xc7a8df3c, + 0xafa81cc4, 0xf940cfbf, 0xd45d1ad9, 0xdf104060, 0xbca06cdb, 0x013a1efd, + 0x2bbf40fa, 0xf1ee8ba5, 0x0f249d01, 0x23193a42, 0x4f60cc05, 0xf306369e, + 0xbc5e740d, 0x84718ccc, 0x1f402915, 0xc1d37dd9, 0x409f715a, 0x95f40e7b, + 0xfa7dfd89, 0x8805d1ab, 0x8daf75af, 0xeabe2171, 0xe80fb08d, 0xa929be27, + 0x8b851f3c, 0x50dc697e, 0x5932578a, 0x34ce3155, 0xde5b12d3, 0xe9c41f8e, + 0xa9ba74e7, 0xe9fd4832, 0x074a55cf, 0x1d2b7df1, 0xc373f7c4, 0x48d70ffa, + 0x47d3ef30, 0x947dd12f, 0xf4dff35e, 0xc46e6166, 0x9db5d7bc, 0x2189e29d, + 0xfe8be7bf, 0xcc91ba34, 0x5b01df76, 0xe9babce4, 0xfbae1c78, 0xc740492f, + 0x17c74439, 0x9670fcf0, 0x1f3895c5, 0x09404eca, 0x1fbee9da, 0x2dffe42b, + 0x4b952a61, 0x15ca9799, 0xb748edb0, 0x332ec0de, 0x6b357be2, 0xcb6be7a5, + 0x1d2274ee, 0xc8fa372f, 0x99835e2f, 0xcb9e78b7, 0x01d22aba, 0x6d35b76f, + 0xd01d2379, 0xd765a737, 0xcecf8c64, 0x037e2e0e, 0x8643aacb, 0x0a87980b, + 0xe70b317c, 0x6ba869d5, 0x2fe30fec, 0xe362667c, 0x4b3e7800, 0xdec1fbe2, + 0xc9a1fbe2, 0x0375e88d, 0x941bcc1f, 0xd0f2eb8a, 0xa54724ba, 0xb66a0f8e, + 0xa5218f32, 0x9bbe1f27, 0xfaeeca2f, 0x5f9400d3, 0x07c51772, 0x4966bdd6, + 0xcd5e7dc6, 0xf0603db8, 0xcd0ff168, 0xe744600e, 0x1578b177, 0xe8247ddb, + 0x8c81a3fa, 0x0323fae8, 0x3d258438, 0xf2cb29f6, 0xf4e497a5, 0xc675ebe8, + 0x9e218667, 0xe2d79f40, 0xd07f577c, 0x8dd8adba, 0x85983f72, 0x69e989f6, + 0xd6ef5a8b, 0x55f615e9, 0xeb5c4f42, 0x3b8f1341, 0x50cbcf45, 0xd0bfe276, + 0x5998b11e, 0x8039cf00, 0xe428d9af, 0xe266fee7, 0x2d447aab, 0x7926c7c6, + 0x557cfc5d, 0x3169ffdf, 0xb92f8edf, 0xf5801c3f, 0xf7a49c60, 0x594f5c38, + 0x21c67be2, 0x3464e1b9, 0x9c41cece, 0x98f1b57f, 0xed1333ad, 0x7de3fbf7, + 0xd5fdc03f, 0x3f9a3de2, 0x30fee1d9, 0x8d99ee97, 0xf74354bd, 0xe858c637, + 0x22addf7e, 0x196b760e, 0xaadd838f, 0x47c6bdc5, 0xe2a2bdc5, 0xec7c6c2f, + 0x97269838, 0xefc95319, 0xd07f642d, 0x17f14fd6, 0xd2f60e4d, 0x3090b0ab, + 0x145da5c5, 0xcb8ee8af, 0x1e799b14, 0xad306b8d, 0xe4e42cc7, 0x4f972f4e, + 0xd569fbda, 0xfce8c2e0, 0xd5cb2b08, 0x0e8a11f9, 0xae97581e, 0x26d37f6b, + 0x1ddeae97, 0xe7d5d028, 0x383aa934, 0xd74ca5af, 0x8f3ed07e, 0x560c2e0e, + 0x390fdaea, 0x43c1d5e2, 0xed75ab5b, 0x74f9b787, 0x95a1c5f5, 0x1d11faba, + 0x64783a75, 0xfdae9378, 0xba0377e8, 0x4d9d31fa, 0x1771faba, 0xcdf0745b, + 0xed74fb5d, 0xea0b5c27, 0xa7b227ea, 0xd6e5f574, 0x64f07567, 0xf6ba57e5, + 0x74fd0b8f, 0xeebb7a4b, 0x49d754f9, 0x0bd37bdd, 0xc7e0e8ce, 0x0f919f71, + 0x0f899816, 0xe9efaa66, 0x10f267de, 0xe39b938a, 0x1dfdb3f8, 0x3ca3146f, + 0x170c6fdc, 0x6e3e9f23, 0xf96374ec, 0xb5b5c184, 0xce49d01f, 0xd61489f8, + 0xbc58abce, 0x3341cb15, 0x5d5318b6, 0x0f731fb0, 0x393d456c, 0xe8dda6a4, + 0xd2e87804, 0x889d5bb3, 0x290635f7, 0xd1bdf10d, 0x88e58f5d, 0x74a513cd, + 0xb0d91fa8, 0xe8e51eb8, 0x8b33e6e8, 0x007496d1, 0xfe3187cf, 0x3e887b25, + 0x69186637, 0xc6471bde, 0xcedcde53, 0x9d1936b1, 0x9c3b9d96, 0xdc0f180d, + 0x09a4a3b9, 0xbf606dcb, 0x358ccd07, 0xe58efd81, 0x83dfb00e, 0x3c6c8be0, + 0xe424e7f3, 0x53a6e547, 0xbf2e78e9, 0xaa47d27d, 0x4a15c551, 0xbf438f73, + 0x22f1a9cd, 0x3b9a515f, 0x4efb7411, 0xdf8049e4, 0x1730923f, 0xe1a370f3, + 0xad788717, 0x72f7c805, 0xbaed1b8b, 0xac06fd5e, 0xfe017efa, 0x927afd66, + 0x1e785fb1, 0xad216f33, 0xf7e1eb80, 0xde5a8c0b, 0x715be53a, 0xb04a1c53, + 0x9e41123f, 0xf0e98f35, 0xcabc00ad, 0xee819d4a, 0x26fb8b09, 0xf8a6aa18, + 0x26aff5ee, 0x2e9c03c4, 0xe451dbde, 0xfe802bcb, 0x9ca0606c, 0xf497a08b, + 0xd04700a5, 0xefc05ec7, 0xf99edcb9, 0x0630ee98, 0xa60b9064, 0x1555789f, + 0x516c79c6, 0x7b97393c, 0x223b7acd, 0xdc8de44f, 0xf7146057, 0x68a8e65f, + 0xc057dcff, 0xfe23dcf5, 0xe7cff38b, 0xf35dff62, 0x329e03cf, 0x0f988696, + 0xf54d99e4, 0x611a98aa, 0xb17567aa, 0xf19bc8fc, 0x6fbc0612, 0xee92763a, + 0x702aafaf, 0xd4325e11, 0xff775a16, 0x646fd0a5, 0x33ae4d9c, 0xda403e60, + 0xce033ae6, 0xaaf14d2f, 0xacc78e78, 0xbcfddd4e, 0x997f4db4, 0xa7e41e7f, + 0xb155efc9, 0x46ba699d, 0x222b218f, 0x925aaafb, 0x47cc62c8, 0xfc9d6d2b, + 0x7aafa8fc, 0x759bc947, 0x625a3794, 0xd111e173, 0xeab6c5e3, 0x7bf63103, + 0x66efd895, 0x9b7c7e87, 0xe4203e76, 0x718555f4, 0xf7f8213d, 0x6b0e24ee, + 0x5c5ddcfd, 0xf9c37692, 0xce7463ee, 0x30cdc1a9, 0xf9a9e20e, 0xd715bb7a, + 0x0b798cdf, 0xe9182fa4, 0x547e2789, 0xa1876070, 0xa2f63ef7, 0xc4fca047, + 0xce8fa412, 0x83f03d60, 0xa2acd8bd, 0xdefb645d, 0xdeea0372, 0x89475674, + 0x1591b637, 0x1bb0f21d, 0x4f5aafcc, 0x3d3e6987, 0x97d9329d, 0x62faf941, + 0x1c3d351f, 0xafa66fbd, 0xc872d272, 0xd979e2ee, 0x67fe4e1b, 0xef022f9c, + 0x557c123f, 0xe4245ac6, 0x95acb193, 0x4c2cf1ca, 0x175877e5, 0xc8a61e95, + 0x2a624e58, 0x4bcc1595, 0x475614e5, 0xa16b2565, 0xa56b1a72, 0x530b0672, + 0x950afe09, 0x5f90a65e, 0x36f41b35, 0x97997396, 0x8eac79ca, 0x1d229fca, + 0x59ab3e03, 0x590bc10b, 0xc06d952b, 0xfaa5787f, 0x586f9065, 0x0df202be, + 0xe9fcd7cb, 0x2efc8654, 0xbf47cae6, 0xe3ca80bf, 0x13ca957e, 0x3b2a32fe, + 0xf76a1efc, 0xca92bfa6, 0x952f7e53, 0x54d5fda7, 0x6a3efd86, 0x257fb6f7, + 0xebf8ef95, 0xff37fca8, 0xf5df2a26, 0x77fca807, 0x7995137f, 0x39764666, + 0xcf15082b, 0x7e67fc06, 0x60b8f660, 0x3c0aaf1f, 0x5318f31e, 0xff70530b, + 0x4df18664, 0x2231c55b, 0x48cb9b0a, 0x5c9addf7, 0x289dd947, 0x3b734f07, + 0x27669ecd, 0x72d6d03b, 0x613e619c, 0x4a53a19b, 0x793cbd80, 0xd6b98ee4, + 0xaf93d042, 0x150486b0, 0xadbba5e1, 0x309e07a0, 0x027eeb85, 0x960bc7f5, + 0xce82b5cc, 0xfb7f6b1a, 0x4c39a7e3, 0xb38e63f5, 0xdfe0057a, 0x1bb1591e, + 0x3ce130af, 0x57bede50, 0xe62e7ab0, 0xf2155feb, 0x00c37c02, 0xb7ad2de5, + 0xb16f3105, 0x3168e5b8, 0x7531b62a, 0x37d412b6, 0x1e28ed11, 0xe8bb57d0, + 0xc7bded7a, 0xe2129d6a, 0x64cff9a1, 0x9cccb37e, 0x9dc63150, 0x7e35fb22, + 0x7499f1b3, 0xdb23f183, 0xdfd06e19, 0x9fcf228e, 0xfffccf50, 0xfa68f3a6, + 0xec757d36, 0x062efa59, 0x7e438aeb, 0xe5c4983e, 0xa5d8174d, 0x0b34dfe8, + 0x364b79b8, 0xb507a9d9, 0xcbefb37c, 0x5e307f54, 0xf081d2bd, 0x378a5c96, + 0xe2792734, 0x637db10b, 0xcc9dc936, 0x63794604, 0x8a13d53b, 0xe3ef822b, + 0xb2fcb90b, 0x7285fcdd, 0xefe5ca27, 0xae8f0ccb, 0x3bfefa6f, 0xde00b71d, + 0x05468d5c, 0xe6f12df7, 0x7e512a77, 0xa3cb3704, 0x18e32124, 0x12792fd5, + 0xaa9da6fd, 0xf61f3e39, 0x0ea200f5, 0x1b26aced, 0xfd9959d9, 0xc377c542, + 0xcf328d78, 0x6f968aff, 0x9cb90bb3, 0xc34bda37, 0xc0b76e74, 0x4478c2ea, + 0xd9b0f25f, 0xf3c2caef, 0x6fbc6764, 0x287e0331, 0x4a676a7c, 0xa7732823, + 0xa313db83, 0xf6483a9f, 0x27c8b344, 0xd2314c6d, 0x256c49f7, 0x445203ce, + 0xc87336bf, 0x36f8e785, 0xb163e0a3, 0x3207e69e, 0xf7b75f29, 0xefba5d3c, + 0x9855d915, 0x6e1c8447, 0xee817116, 0x3ff446f1, 0xcdc44520, 0x4a90966c, + 0x4bfa69e3, 0x3fc76f1b, 0x914ede36, 0x678da927, 0x9f5fa51f, 0xf5a61cdd, + 0xa1fd85d9, 0xd713b78d, 0xe30f2317, 0xf5c3c76b, 0x5a378e45, 0x25bb3ebf, + 0x4bb3eb4c, 0x1ee95edc, 0xf1ec476f, 0x4f671afa, 0x569cfe54, 0x72e42fce, + 0x7632cc15, 0xd33ff60e, 0x09f9e9c2, 0xd9c5d313, 0x7e7a0937, 0xa69788b2, + 0x992e5c09, 0xcfba669c, 0x7179d133, 0x6db5d217, 0x9dce91b7, 0xc827296c, + 0x4ed3927e, 0x40fc8931, 0x9fcf8ad6, 0x02f7f030, 0x7998e6a9, 0xe1fc7b2b, + 0x7111b9f9, 0xceb534e3, 0x134ff980, 0xe30c1d9d, 0x3314b6ec, 0x6296dfad, + 0xfca1c60d, 0xcd809955, 0xdb8004c1, 0x0b1b7c8b, 0x954e3d61, 0xc5338bf3, + 0x92f3007c, 0xdfa1aad2, 0x84ff7d08, 0x772663a0, 0xee22abba, 0xc45b3cd7, + 0xaf8d49ed, 0x7237e7a3, 0x41ff5f30, 0x4f31e7f0, 0x8f0c6ba7, 0xdc3e9c93, + 0x5987fc9f, 0xd07bc60f, 0xc0fd3e8f, 0x77820ae0, 0xf5f3a58c, 0x4ec787d3, + 0xd6627f41, 0x8246698e, 0xe303ac0d, 0x2c76b31f, 0xccf3e234, 0xdffb461c, + 0xf24cd675, 0xd58ed675, 0x4cbffda2, 0xc665f6c1, 0x6e30cfc0, 0x91ef7650, + 0x8c8b8c04, 0x00373fb5, 0xcec6d3cb, 0xa07df88d, 0x1bf6155b, 0x5bbcd734, + 0xb228ed92, 0x36c81eab, 0x44f59fa1, 0x99bf3f21, 0x9e263cc3, 0xbf25e187, + 0xf091fc7e, 0xfbb2bc31, 0x72aed69d, 0xb4f6c63c, 0x9cb1c729, 0xdaf15214, + 0xf0e8ab32, 0x4a72c71e, 0xcd02aeb8, 0x5b77cad9, 0x3159638e, 0xe204f7dc, + 0x46f7f0f7, 0xc614fc95, 0x6e6fbac9, 0xd93bda3c, 0x0f27435b, 0x44d65c50, + 0x94f6c2f7, 0x18249b79, 0x6bcb8f6f, 0x27b43d45, 0xf248db25, 0x256ea935, + 0x3c6073ad, 0x51ee75c3, 0x45c9717c, 0xbec97724, 0x11ec137f, 0xe7eeffdc, + 0x33f9fcf1, 0x151afe82, 0xf88935af, 0x027ca140, 0x9acbb09b, 0x151d2799, + 0x04f76ca1, 0xc7b72e31, 0xc078e5c3, 0x6c52fdc6, 0x58ec0dbe, 0xec6992ba, + 0x95594fd9, 0x60c779f5, 0xb2bf60de, 0x10b28768, 0xa6bc5fed, 0x0fe8308a, + 0xc61d5dfe, 0xe6dda1f5, 0x36be38a4, 0xfa14b97f, 0x9c33a08b, 0xcf5b6cff, + 0x67b8da7b, 0x237e7ac4, 0x1f1ef4e4, 0xef9b4fef, 0x463728db, 0x465dbcd2, + 0xe6248f9c, 0x4630eb03, 0x1da227cc, 0xde7bafad, 0xf7e74d4c, 0xdf8c3d4d, + 0x392e6543, 0x8b0efd62, 0x1e912ad7, 0xbf482a34, 0xf948d576, 0x2fdb76fc, + 0x7a3f0f29, 0x790a171d, 0x7287eabc, 0x365fa188, 0xe430f54d, 0x1e2a1fcb, + 0x0164abb2, 0x0edc29cb, 0x624fc793, 0xcaf588a6, 0xdda89329, 0xf18f6834, + 0x096569c5, 0x74ebd22a, 0x70a0dad6, 0x2e78e03f, 0x318f2fcc, 0x2cb75e5d, + 0x9faac7e0, 0xf0bb72ab, 0x7b4b592a, 0xf745da01, 0x9dbca72c, 0x3ad30d86, + 0x05e9be70, 0xa193dbeb, 0xdf39fbde, 0xe3cc5677, 0xcb760372, 0x8cdfbcba, + 0x9e470095, 0x30f4fb5f, 0xbdae83d0, 0x43365746, 0x847682a5, 0xaefae131, + 0xecbf983c, 0x2c1bfae0, 0x4637365c, 0x5d17ba3c, 0xfb6bfc09, 0x4b9c1f63, + 0x1c6d94f8, 0xb54bacef, 0x89f7c6de, 0x84fe8de8, 0x6d81eaf1, 0xbebd1f31, + 0x7de20a42, 0x7b777b4a, 0x1afb8a96, 0x96d94fbd, 0xb8795dae, 0xca4675fe, + 0x2bc68f0f, 0xb9b711d8, 0xa4d6ce91, 0xa73c3d50, 0xe8cc6f7c, 0x8a47eee9, + 0xe3f7eb05, 0xca3fdaeb, 0xbe78bb82, 0x7a79fea9, 0x059bc94a, 0x500714a5, + 0xebeb36f9, 0xf7ea36f3, 0x283a6315, 0x1654d3c7, 0xfdbfb90c, 0x394b4e7e, + 0xbd6cc158, 0xbba355f7, 0xe5b17ecc, 0xce421bfc, 0xd3282667, 0xa7ce500a, + 0xf3fec91a, 0x23531aa6, 0x8329defd, 0xf09cfeb9, 0x37e48d92, 0xf74ac0fb, + 0x3850d4d6, 0x49c4ed01, 0x3ec9185f, 0xd1d4e37f, 0x3941a787, 0x9b4b37f9, + 0x0ce4ddb0, 0x86ed0e78, 0xc47d74be, 0x84b7649d, 0x5f5f910b, 0xed93a166, + 0x4c3b1fa8, 0x2da7bdf4, 0x26536c9f, 0x4cabfee1, 0x6d29dcc5, 0xdc6215dc, + 0x5e029b5f, 0x996ea792, 0x51e7e41d, 0xf6d2bfd7, 0x2865c789, 0xf036577f, + 0xbad57bb5, 0x9997d23a, 0xf142cc45, 0xd22af0ee, 0x19e31bc7, 0xa56ccbf2, + 0xcf08bbf5, 0x4664ecbe, 0xeab66fe8, 0xf3c62d32, 0xce676119, 0x44d35451, + 0x3f95552c, 0x73e7f2b7, 0x9f3d0f15, 0x73f87aab, 0x6feff71b, 0x3f610253, + 0x2d9b77f4, 0xddfd85d9, 0xfd797aa6, 0x9fd50b35, 0x172fff02, 0x171ac158, + 0xb7ae5050, 0xf3f2345c, 0xd13c5f2f, 0xa4ada37b, 0x2bf385c3, 0x36fdd235, + 0x3ee893b0, 0x4bc54ef2, 0x32f791f7, 0xf822065f, 0x64d9d2e5, 0x629cbf47, + 0x2f4b7ba4, 0xbf0c8c7b, 0x91a81403, 0x41423df9, 0x67572f47, 0x3654f9d2, + 0xebf71322, 0x43b256bb, 0x0fa0f11a, 0xe7f757db, 0xf6e642fa, 0x2951bec3, + 0x6161ded4, 0x074895c9, 0x3bca6587, 0x1e78e1ff, 0x650f943f, 0x735ed107, + 0x5df9e8d6, 0xe9c49d2e, 0xf20a6541, 0x25550cc1, 0xcddfafba, 0xf88ba354, + 0x7d87de9e, 0x2cee75a5, 0x1fa2bb7d, 0x55546bc2, 0x93a18ce2, 0x6fa5f517, + 0x8cf83c73, 0xb3be4794, 0x9befbc54, 0xd7c70874, 0xe0b07cf8, 0xf4ae4d4f, + 0xf52a4396, 0xa49a4f63, 0x306800ee, 0xbffc800c, 0x51cf0ccf, 0x74cb242e, + 0xa9706adf, 0xf586521c, 0xe8867df0, 0x4fe0b077, 0xcf9e88f9, 0xe1e90ef2, + 0xeeff0447, 0x1fb92163, 0xe8c2dbf6, 0x8b406a5c, 0x3e781dbe, 0xd1639406, + 0x22abfc7c, 0xd48f1683, 0x9e17a1e1, 0xd9d7b17d, 0x5c40aeb3, 0xc8cbad3e, + 0x5de425d7, 0x3d2b6dae, 0xd56455cf, 0x2d62f385, 0x07fae36f, 0x40c1921c, + 0x352afd85, 0x7801cece, 0x71264046, 0x49859337, 0xbadd7c5e, 0x2b5c451b, + 0xebd19d7a, 0x44b065bb, 0xf1cccbeb, 0xca6ec979, 0x326ec990, 0x18c2006d, + 0xbdb0d78e, 0xa3716e3b, 0xd4fb3b3d, 0xe6439060, 0x182b567b, 0xe4233e0f, + 0x892be992, 0x56fdd7d3, 0xda5357a2, 0xfbc8828c, 0x4f86972a, 0xf318333a, + 0x7ababfbd, 0x4f8f1072, 0xe5a3fe11, 0x7f455fdc, 0xf9f53a63, 0xc62ee386, + 0xe9c7e547, 0x5c270df3, 0x1f951feb, 0x1f951397, 0x3f574437, 0x95111959, + 0x2a2e371f, 0x075cae3f, 0xae982f4f, 0x9d533f6b, 0x2d6f83a3, 0x7daeaefb, + 0x5d4ee795, 0xbbca9cfd, 0x79b7f574, 0xf3c1d6ef, 0xb5d7efab, 0xd7abe05f, + 0xe5777fd5, 0x20f5740f, 0x8bc6622f, 0xf74a3c31, 0x613dd386, 0x3016a0fa, + 0x3d8637bc, 0x57722920, 0xf471fea4, 0x1e4c5fe1, 0x71e3f7c2, 0x3b093fcd, + 0xc4591c78, 0x838b595f, 0x7c5ab1e2, 0x9a763436, 0xb722fd15, 0xbd434d45, + 0xf5cb7ece, 0x74380b06, 0xdf89cb71, 0x1b76a4ab, 0xfce9b292, 0xb3b051e3, + 0xef30f97d, 0xe927cf20, 0x1c6b001f, 0x500ddbe3, 0xd7febb42, 0x2237cccc, + 0x9e2c1e62, 0x3cb585c7, 0xe64f3107, 0x8bf3e049, 0x61f7cfe3, 0xfd1f313c, + 0x0f952b38, 0x4173b53a, 0xf6bf6195, 0xf2807332, 0xed834b11, 0x036f9866, + 0xc51447c8, 0xc74e5e12, 0xbd4db838, 0x7aaa3de1, 0xb3dd3a7f, 0x050d2db1, + 0x3aa5d04c, 0x3d1fd1e4, 0x7cdbef02, 0xe314e28c, 0x11ffec87, 0x433ce1c6, + 0xbb3f345c, 0xf7bcf1cc, 0x74b97ff6, 0x9265e518, 0x45f5ee93, 0xb1dda7d7, + 0x6e37f3f9, 0xd177bf50, 0x765bdef7, 0xdf6ff7a3, 0xa231b674, 0xcbf9afbe, + 0x13ccfeb6, 0x66590741, 0xad55fdfd, 0xfae10ef4, 0x3358dd7d, 0x49272fc5, + 0x604399be, 0xfec6cfbc, 0xe1db7bf5, 0xbe2b4fbd, 0x3bfd1db8, 0xe7c5ee78, + 0xfaf08ed0, 0x2c95e669, 0x04399e7c, 0xb3d47fec, 0xbe662c71, 0xadd05f9c, + 0x45d3569c, 0x99aa79fe, 0x6b4e43e2, 0xb0f3fce7, 0xf1516def, 0xcbf46682, + 0x447baf01, 0x8f8b447c, 0x59fa2ddf, 0xe9494a21, 0x660e73a4, 0x527dd00d, + 0xc5ec5ecd, 0x86328e0f, 0x936ca37e, 0xc5ca442f, 0xc53354f6, 0x4cc52407, + 0x3292e779, 0x2823be8a, 0xe78fa381, 0x985b7637, 0xd4f68cfc, 0x900f1451, + 0xce286342, 0xa885b360, 0x2fb6bf3f, 0x77dfdeaa, 0xbcd3cf5a, 0x759feefa, + 0xc7704f3f, 0x1e6a2718, 0x47d61e38, 0xccc0738f, 0xdcb9dfb8, 0xf1be331a, + 0x0d8990e2, 0x5f915243, 0x82dd773b, 0xd8bbfafc, 0x312b5972, 0x81183e8f, + 0x6486879f, 0xfe605d13, 0x5c62307c, 0x848f97cc, 0xdee80281, 0x6aa0c104, + 0x71425a06, 0xa13c7083, 0x6acd9a07, 0xa087d93a, 0xf71f70fe, 0x0a7e7e09, + 0x51fc8d68, 0x03ef87e1, 0x51f2c63e, 0xda7642bf, 0x843fe07e, 0xa8bbf09f, + 0xa80bfa0c, 0xa957e83c, 0x8cbf90fe, 0x1efd27e0, 0x2bf88f82, 0xefda7ca9, + 0xf8cfe7a5, 0x85fe09ab, 0xab6547df, 0x7f3d257f, 0xf0475fce, 0x044dfe0b, + 0x42ed12ff, 0x9a27cf19, 0xdfd97ca8, 0xf8aff542, 0x9afc11f7, 0xc865483f, + 0x1f9e847f, 0x7c12b7f5, 0xf046dfdc, 0xe0887f09, 0x95077f0e, 0xf4c3fa6f, + 0x5dff94fc, 0x2758afde, 0xfc672278, 0x45b49780, 0x79da1746, 0xcc968b69, + 0x6f7800ae, 0x6df74cb5, 0x4be40b9d, 0x1e2e8007, 0xf7f26555, 0x5234aef6, + 0x2bb347dc, 0x486cd6f7, 0xb9faa72a, 0x1592df54, 0xbed9764f, 0x77ba66a5, + 0xedc55b6d, 0x46ccb659, 0x32c56ded, 0x72ba3fd5, 0xcd8dd92e, 0xae300538, + 0x07818c32, 0x25bb6326, 0xfbdf9246, 0xefbae2a2, 0x6f79fd89, 0x45efcc88, + 0x2253891d, 0x5b6b21cf, 0xbaf07493, 0x7ce50cb6, 0x25dcdd04, 0x989b61c6, + 0xc49df91c, 0x33bdf64f, 0x79d602af, 0x0f7be497, 0xfba7c8e5, 0x3403cdcf, + 0xcbb5a331, 0xc8e4fc8c, 0xbea7ad89, 0x4b3fe4d4, 0xdbf8893f, 0xbf84caab, + 0x69c6eabd, 0x2c5fe8b9, 0x137be992, 0xcfe48b69, 0xbfe99fd1, 0x997ba640, + 0xc53255b6, 0xa322d903, 0x5a46c7c0, 0x7305ff77, 0xe9b95ea9, 0x9dd1c514, + 0x27878eab, 0xf802dda3, 0x387da3ca, 0x4fdf8494, 0xd77110ca, 0x94f1297d, + 0x9f3d1637, 0xf8bbff2f, 0x19f80cd9, 0x5f3f1315, 0xa3cfc2c6, 0x7f75fee2, + 0x68857df1, 0x31df693c, 0xcf7c547d, 0xc791b03b, 0xa5dba3ef, 0xe62ab888, + 0x4ff7d174, 0x1f92656a, 0x81f059fb, 0xc59d807c, 0x7de3dd32, 0xb3ead264, + 0x733e6007, 0x114a7c8a, 0xc855039e, 0x26c65147, 0x6ffef257, 0x893f235a, + 0xbaf40574, 0xb76849ea, 0x99fa617d, 0x05fb287c, 0x7f18ed5c, 0x9fde8fb5, + 0x8df313e1, 0xc5b217a5, 0x447bf63c, 0x81e614fc, 0xaadb3b71, 0xf9c785dd, + 0x504559b8, 0x657accef, 0x77fd5e2a, 0x9832edcd, 0x2c5feca0, 0x2cf1c7af, + 0x893f4ddf, 0x3c06a5e3, 0x38c578da, 0x53c537de, 0x69157dd6, 0xf75deeb1, + 0x4ebf0f25, 0x12288e0e, 0xb00674f7, 0x1f072801, 0x9c527531, 0xcb86703a, + 0xd326a641, 0x71e8b87d, 0x98fbcafa, 0x6193f028, 0xd10de7e1, 0xf6eb4def, + 0xee54025b, 0xa2aff4f7, 0xb2c9a83c, 0x233d0ef8, 0xc4c37b7f, 0x0dcb6578, + 0x421e63ce, 0x36840bf9, 0x7e8988be, 0x7ef2a732, 0x9b9fbc8c, 0x27827ad9, + 0x0dc094da, 0x8b7601ce, 0x5157507e, 0x95c2c45e, 0x3de11abb, 0xca265bfb, + 0xbe4bb355, 0x7e77245d, 0xe47f912b, 0x3aacb634, 0x62dfd116, 0x1ced1eb1, + 0x8a35f302, 0x88f39ee4, 0x91f01af4, 0xbdadf022, 0xd1c450b7, 0x6f7ebb1f, + 0x1445e512, 0xfb438c6f, 0x12b32f6f, 0x214cd81d, 0x7f0238a5, 0x0eff0336, + 0xebfcf44e, 0x1e5acc8b, 0x28e26d80, 0xfc64473c, 0x51ca30be, 0x3eabf798, + 0xd1deff07, 0x0fa677a2, 0x17fc7807, 0x383f9d32, 0x7bf3c597, 0x52367fd0, + 0x226bcf7e, 0xb59df85e, 0x2c3f7415, 0x4ff44b1d, 0x78054fd1, 0x86a666fc, + 0x8d9f7df0, 0xaf9bc1fc, 0xed22e7c9, 0xec152412, 0x4645dc6f, 0x5d71e5f1, + 0xd83eeeb2, 0xf6fa8b98, 0xfa12ffb0, 0xfa9de9b5, 0xfe426976, 0xe8da473b, + 0x1f769d1e, 0xdee5f9cf, 0x13d272c2, 0x1fff24f1, 0xe7e26553, 0x076d4ac7, + 0x2b76ddb0, 0xa27e84bb, 0x4155817d, 0x8ceed039, 0x1b6ab927, 0xf3f64f11, + 0xd6a3ccf6, 0x659fc04e, 0xda0a3be4, 0xbe2d032b, 0x7ebb1803, 0xbcc668b4, + 0xc72431f4, 0x5c03be7b, 0x2f077a06, 0x733c1037, 0xbda6920f, 0xe9df48d8, + 0x63345fda, 0xb68c804f, 0x5b979a16, 0x7cf30652, 0x35786ec0, 0x9c760dda, + 0x63b418fb, 0xd0e01ea0, 0x9401df70, 0x7529e947, 0xcd5748ed, 0x292ba3b6, + 0x429a5d0e, 0xabe4d572, 0x689ca10b, 0x91ac4b56, 0xc9f1adfc, 0x1afbe5b7, + 0x3afef711, 0x7ebafffe, 0x4df3e2fb, 0xfaef9c85, 0x7e68038a, 0x9a7f747e, + 0x60c6ff5f, 0x90a37efe, 0xe6b381e7, 0x70bf7298, 0x65279728, 0x5661ef22, + 0xaf7d254a, 0x53a0567d, 0xa1d3fca6, 0x9bd80fdc, 0x867ca76a, 0xc2166ebd, + 0x016079f8, 0x2ba40fd7, 0x29b29e88, 0x086cd54e, 0x3c1c812b, 0x70b90d0f, + 0x97e09c5f, 0xd17bffe1, 0xa418d0bc, 0x7d05d8ef, 0x393df871, 0x17e747e8, + 0xc57b4ad8, 0xd77ec9ab, 0x1f78d0e2, 0x439bbf1f, 0xa09820ae, 0x7d236af6, + 0xbdfa261f, 0xf0f4bb9b, 0x787a6b84, 0xe77fd322, 0x87aadca5, 0xf87a2b27, + 0x6e472153, 0x9f3fd749, 0xfdc3d2ea, 0x338c1c17, 0x1415fbf2, 0x828ed2af, + 0xc60ef7e1, 0x200806c5, 0xfca16a47, 0x6b9d01a0, 0x3f341e48, 0xbff88338, + 0x7c7d1aff, 0x6dd59d38, 0x9c603649, 0x59dcff5a, 0xefd68674, 0x073fd1ac, + 0xfc60e83c, 0x7dd209ec, 0x3c9f70c5, 0x387fe614, 0xe657e79f, 0x7869de48, + 0x5a0263e4, 0xfdf915bb, 0xdb8fbe76, 0xfe0b5f64, 0x4adb16bf, 0xa0af2853, + 0xb5f7c2cc, 0xf77c58ab, 0xdf8525a6, 0xbcb35edb, 0xa67f0dc9, 0xfba6cc8d, + 0xfedd6dd8, 0x2be48fb5, 0xe291be3b, 0x646b7bff, 0x8676aefa, 0x85eb4035, + 0xc5d15c75, 0x5cba34a9, 0x6049cfc0, 0x587aba3d, 0x3d3d15cf, 0xa874443c, + 0x31f90bad, 0xe45eb110, 0xfb4440c3, 0x72fb86f7, 0x8fc8dd71, 0x72e3cf91, + 0x0f744d3b, 0x2fa7ac59, 0x42e4d4be, 0xd68f3899, 0x10bed2f2, 0x69796a63, + 0x695e451b, 0x878f439b, 0x5127aa2f, 0xf08be11c, 0x0c5f789c, 0x0fbe453e, + 0xc7be73e4, 0x87bc3b72, 0xfae7bd7c, 0x1e38a9e2, 0xc44081ca, 0x084e1bf7, + 0xed87fc3a, 0xbb2896ca, 0x3fbfecfb, 0xaec8cf59, 0xeb0a1cac, 0x8e781dac, + 0xdf174fdf, 0xf4213ab7, 0xe9c094be, 0xebbcafa6, 0x56bc9efa, 0x8a5bae2b, + 0x12bbe3ca, 0x020daf85, 0x57fbda5f, 0xd3c26c94, 0x6b728e95, 0x4262785f, + 0x1f21323e, 0xb32a7bf1, 0x4c6ecfca, 0x3a5b1955, 0xf879b9f4, 0x7759887d, + 0x02cd2d9d, 0xd7d0f378, 0xb3d3fc38, 0xa6800c2f, 0x2dfcfd1f, 0xf67c3f0e, + 0xf9154c8b, 0xe1e73ff2, 0xe21c23f7, 0xaf9b45dc, 0xa1fade36, 0xb758dedc, + 0x238f1ce9, 0xbf3a5ec8, 0xc97a77ac, 0xa52cffcf, 0x07e781cb, 0x9cbb52eb, + 0xd7206e4b, 0x40ba6dd7, 0xe9860c71, 0x5f30a351, 0x9f129188, 0x57c7e5ad, + 0x1de3f3ea, 0xd7c4d58e, 0x50501616, 0x3d59c5de, 0x7d7e7e74, 0x73e68ba8, + 0xf9ab531b, 0x0f2bb9f9, 0x5dd667f7, 0x5ff69886, 0x8f9150e3, 0x68df42ca, + 0xf2f2265c, 0x768994e7, 0x7117f8ca, 0x9e8cdb9c, 0xfffbd446, 0x2a51663a, + 0xbf2d098a, 0x3dcf4869, 0xe6df43b7, 0x0face4fe, 0x24575c0c, 0x53f178f2, + 0xcf345dc3, 0xea0038c8, 0xe5f6be85, 0x3d53d088, 0x38a1e2fb, 0x87b27d67, + 0xe5d28bef, 0x92fb82d8, 0x5adce5d4, 0x7bfaf7d4, 0x3e144fed, 0xcd32875a, + 0x7e90967e, 0xda7f0ebf, 0x607968fe, 0x1e5706f5, 0x87172bd9, 0x609fe2e8, + 0xf6bcbbe8, 0x718df4d8, 0xa7360d4a, 0x648e297b, 0x300b514a, 0xeffeb84f, + 0xe9bccc52, 0xb74e8273, 0xbee9e238, 0x4cc3bd75, 0x1ddabdf7, 0x61da183b, + 0xc236db56, 0x89a3854b, 0x835c9e61, 0xb7d2b59b, 0x82f2a20f, 0x790bec1b, + 0x659f2a7d, 0x8e4d54c3, 0xc6d67e71, 0xdc94aabb, 0x772a2e30, 0xa3affff2, + 0xf2477aaf, 0xec1f9e34, 0xb07e5330, 0x8bae6894, 0x26dc1f95, 0x5c768dec, + 0x83ae0a57, 0xf5b4c9c7, 0xaf3c5d58, 0x9c639f11, 0xd1f2eccc, 0xada2e3ff, + 0x87ec4dbb, 0xaae2ded6, 0x25ef2863, 0xf942eab3, 0xff73c52a, 0x4147f51d, + 0xc6d49c84, 0x89a87e7f, 0xae1b0bdf, 0x2b35fcf0, 0x7eb317d7, 0x7f19886b, + 0xf3543abf, 0xbf19beb7, 0xdb32f469, 0x3461f3c8, 0x336b9ebe, 0x981ed07b, + 0x7ca74b6b, 0x8040b99d, 0xda239317, 0xbf3e677f, 0xe9ab29bf, 0x1bbf4748, + 0xdfc5e137, 0x4c36f801, 0xf6f4f117, 0x6bdd1354, 0x3cc0db7a, 0xe74652e8, + 0x49bd7a23, 0xb79a7193, 0x80db38ce, 0x31d8786c, 0xcbe504be, 0x13728ee1, + 0x3b0067de, 0xca186e21, 0x46eea599, 0xbf30efbc, 0x7fbe98a6, 0xd77fc5a2, + 0x49303d09, 0xddb039f2, 0x9a3f6367, 0xde6c4155, 0x7fdf4595, 0x88dff114, + 0xbb44fd76, 0xaca26ed3, 0xc03efa2e, 0x45e8e515, 0x83f68b9f, 0xf1a21af2, + 0xf912fb89, 0x72698bff, 0x8b3bf502, 0xe123b3b2, 0x949d89ed, 0xa9e9af6f, + 0xcdf23ea6, 0xf2130db6, 0x714fe351, 0x7cc7109e, 0x6493c456, 0xf37b72f0, + 0x3f4fd3c8, 0x37b1eced, 0xa43d0877, 0xd05093f5, 0x2209954a, 0x78a0c4ef, + 0x2564fe88, 0x75801e90, 0xfb197d36, 0x61dcf89e, 0x716d8e5c, 0xf6c74b6f, + 0x3a6ab915, 0x79d14bfa, 0x51eef5de, 0xf57fc8e9, 0xaafd3553, 0xaff9235a, + 0x7bff9ddd, 0x75b42f3c, 0xb9e45898, 0xc669747c, 0xe41bb573, 0xfdc59bed, + 0xc7476dc8, 0xbcbe3158, 0xc61256cd, 0xb66dd9f3, 0xbb721294, 0x478f3c6c, + 0xf1b36f6b, 0xca9b3abc, 0x1b36d5e3, 0xf2d37bcf, 0x27ddda6f, 0xbb5a0f08, + 0xfef8c3e1, 0xff7e54d9, 0x520d5e21, 0x1bd938bb, 0xb8acbcc0, 0x66f64614, + 0xc77f959c, 0xc8c0a12f, 0xf9fc31ac, 0xea266182, 0x49665b67, 0x9b54ec98, + 0xd87642ec, 0x4e925e96, 0x0df11272, 0xbbdbd6e3, 0x19f745f1, 0x6b7c0856, + 0xf3b7d4fd, 0xa9bede75, 0x08c56e72, 0x8bbd13b4, 0xd9b74e90, 0xbf315896, + 0xde97b254, 0xc3f5bfb0, 0xca7cba0c, 0x7994fe9e, 0xd815bfa2, 0x512f649f, + 0x8b133fb0, 0xfa0cfffd, 0xbbfebcc5, 0x819815e7, 0x60e3df46, 0x9e4fbb4c, + 0x68cf4b1e, 0x439c55a5, 0x0ff7bf44, 0xfacd95db, 0x93d82578, 0x75830d0f, + 0x3b9e66d5, 0x709e9131, 0x5e31b27b, 0xd849177c, 0xdbc2b285, 0x3df91a37, + 0x637bed4d, 0x27289d9a, 0x73d0f1e9, 0xc3ef8a7f, 0x31c78555, 0xc518daae, + 0xf9f9a257, 0xba63a9ea, 0x67a8107b, 0xc6dec23d, 0x8f48ed12, 0x3895cf19, + 0x8efc6b5f, 0x3f28ba77, 0xf77f9aaa, 0x2918a6c4, 0xf400c25f, 0xddad744b, + 0x8a4af9df, 0x115d7f69, 0xab486afb, 0x6dbf8951, 0xa32c42a1, 0xf3bf7bf9, + 0xf3f22154, 0xfadd69fe, 0x6d75c156, 0xf7e5ca48, 0x564e4f17, 0x5fc3d962, + 0x71c25f77, 0xa4ddc76e, 0xcf5c9d67, 0x3fbebffe, 0xaf34e8d1, 0x66debd44, + 0x97f7fbd0, 0x50fddc85, 0x9afd8ff0, 0xdbbcf74c, 0x22ef7c8b, 0xde8c98bd, + 0xfb07d46a, 0xbf9366eb, 0x501e0324, 0x30dfeeef, 0xc0af2a2d, 0x08b0fef7, + 0x326b2e7e, 0x1aa677d3, 0xbf208fc0, 0xa31f6a2e, 0xb7eda7f1, 0xf9abdb06, + 0xbfb69a39, 0x216cd313, 0x764bb791, 0xb9653387, 0xb398e501, 0xd9f067da, + 0xec987db1, 0xfddabe8d, 0xad3bc84c, 0xb7fb0dbd, 0x3c4afce1, 0x8c4c7bfc, + 0x6b24aef2, 0xec7fffec, 0x810f0a30, 0xcbac2b1f, 0x82aa7471, 0xeec24afd, + 0xe8f9146d, 0xd5a94af5, 0x94bef113, 0x149d6a54, 0x7df52f41, 0x874a87c4, + 0x942bdb77, 0xfce5a7e7, 0x60af684b, 0xbe4d9f5e, 0x20471ddc, 0x675e20ff, + 0x47e36a2f, 0x9cf7bb9f, 0xbe3a73b3, 0xbd9294aa, 0xbb018f28, 0x4307ec00, + 0x489bd2d2, 0x3f7c9a3f, 0x743c034e, 0xfca167bd, 0x3f05f7db, 0xec7e0a76, + 0xd8056e4b, 0xb7dcba51, 0x4bc71d95, 0x2527401e, 0xf5274889, 0x39dd4699, + 0x8b16568c, 0x5fb0c675, 0xfc8f87f2, 0x90cbf646, 0x17ec31e1, 0xcf224fb4, + 0xf12ed1cf, 0xb445c844, 0xec313c4b, 0xf0a36697, 0xe779c4df, 0xadab9369, + 0xfa70f013, 0xcefa44e6, 0xdbb469cd, 0xfb3ec04a, 0xdc5cd9e9, 0xee865994, + 0x3b0853ef, 0x760c1191, 0x5e7077da, 0x1abbcc55, 0x1cd6ffff, 0x883f1bc9, + 0xffd197e7, 0xfb75f2ab, 0x40b80719, 0xfbc76cbc, 0x1f744570, 0xf9d632ae, + 0xe9baf7da, 0x88974504, 0x601e11c3, 0x5be22217, 0x5176e2bd, 0xa30c3a71, + 0xe6fde774, 0xfdbf6ef4, 0xdae281ba, 0x882c7d3b, 0xb5bfb9df, 0x7b571f4c, + 0xed99e443, 0xcf88ca5c, 0x86b41676, 0x53495fd0, 0xabc9c519, 0x73f6fa3c, + 0xe3bfa32a, 0xddbf8fac, 0xcf4535e6, 0xd6ebbe97, 0xc06fac5f, 0x9714d5ee, + 0x8b8f15eb, 0xfad1c38a, 0xf2943f50, 0x46adbc78, 0x6f655f9f, 0x7ddf419e, + 0x12aeac66, 0x34cce7d7, 0xda8f8c32, 0xcff3a3ab, 0x1ecf0202, 0x9e1a5a12, + 0xd878efb5, 0x7bfc8d8a, 0x540981a4, 0xe1c1e5af, 0x3a2705f7, 0x5b65d67b, + 0x2c53e62f, 0xd881ace2, 0xf189daeb, 0x2e57cc46, 0x83c4830a, 0x302e70fe, + 0xa30d464e, 0xbac299ef, 0x8705e775, 0xd0356f77, 0x03e147ff, 0x3c26ed71, + 0x9813cfe8, 0x5afb40cf, 0x807f3fa3, 0x68e0ea75, 0xecebfebb, 0xb3bbc3f9, + 0x58ff7e63, 0x5038b52b, 0x7610f8af, 0x383a4800, 0x6ca77c5c, 0xf68a1b28, + 0x2378ad8d, 0x4c95c3ed, 0x0acaf79e, 0xa1bb9f62, 0x0ddf8f9d, 0x327c8a9a, + 0xa679fd12, 0xf302cefb, 0x6f9f94c8, 0x3573e328, 0xa672f3f4, 0xd7c4622b, + 0xb1307896, 0xbcfff04a, 0x1fa0f78a, 0x8c00b167, 0xdf1063df, 0xbdc4969f, + 0x26062da4, 0xd514cc23, 0xb5e4f3ca, 0xe9043cef, 0x8d7d0f3b, 0x8b077da3, + 0xda7bf805, 0x37dfd138, 0x74fbd1ba, 0x7e894d1f, 0x3ae282bf, 0xe17df8da, + 0x17efafbd, 0x9dfcb1fd, 0x953e3c91, 0xc35a7449, 0xeba71fb4, 0x2b74ddc5, + 0x53b83c93, 0x0f0f4eab, 0x773e7e45, 0xf74a824f, 0x0475b56f, 0x8eb44ba6, + 0xf75fd96f, 0x595dd23c, 0x5881defc, 0xdbefe897, 0x117e8bae, 0x9301acf2, + 0x1a8e816f, 0xcf91ef81, 0x2e93296c, 0xa10e74c9, 0xbf8bcfbf, 0x35fd1173, + 0xf9493d1c, 0xbdc47b3b, 0xa75c6d70, 0x8a0433ea, 0x3c107ef0, 0xd08f118f, + 0xdf8ca5ca, 0xf5e6d28f, 0x3504017f, 0x7fe05f6a, 0x00007fe0 +}; + +static const u32 csem_int_table_data_e1[] = { + 0x00088b1f, 0x00000000, 0xe733ff00, 0x51f86062, 0x39fbc10f, 0x716e1819, + 0x0143f822, 0xd9433117, 0x1017fa40, 0x606463bf, 0xbc48cf78, 0x040e357e, + 0x033b2f7b, 0x3e200ac3, 0xfef03ec0, 0xc95c481a, 0x4ebb3f4d, 0x622ed1d0, + 0x067e2ef0, 0x0c023d86, 0x1082590c, 0x54417ffe, 0x08fcddf9, 0x651898b6, + 0xf5012976, 0x93320003, 0x038009d3, 0x00000380 +}; + +static const u32 csem_pram_data_e1[] = { + 0x00088b1f, 0x00000000, 0x7dd5ff00, 0xc5547c0b, 0xbddcf8d5, 0xeecddd8f, + 0x21079b26, 0x086e3c21, 0x4bc60a22, 0x9bade102, 0x88b46204, 0x7d608a89, + 0x8420182d, 0x96d22247, 0xedf7ed7e, 0x5ab11062, 0x68db151b, 0x34105db1, + 0x060b28da, 0x2df0980c, 0xaa5694a0, 0xd1f58df1, 0x90cbc8a0, 0xf87e8784, + 0xce7feb69, 0x7bbbb999, 0x7c486eef, 0xfefdfbf4, 0x730ecfe9, 0x3399dee7, + 0x9ce735e7, 0xc92b3339, 0x210cb102, 0xbbf81be4, 0x22ad909c, 0xa46c6421, + 0xe5a22aec, 0x79fc4218, 0x8126c08e, 0xafaed090, 0x4234908e, 0x54cd364e, + 0xec84d9ad, 0x2e8473ce, 0x0327eda7, 0x6d2b0185, 0x76f6de2f, 0x4beb44a2, + 0xb41289b6, 0xf1d9765b, 0x4275cefb, 0xd6d5ea00, 0xd12607b6, 0x9136f77a, + 0x935da06c, 0xd242d390, 0x23623909, 0x61754fec, 0x559dbe7d, 0x7ddfac97, + 0xd9578c2b, 0xfa76256c, 0xd12691fd, 0x9b65f503, 0xe3a10084, 0x8f71d92d, + 0xb7f68032, 0xed042020, 0x7a6fad2a, 0x845d5150, 0xfdebb5dc, 0x212776c4, + 0xa2367c27, 0xca8f382a, 0xaa4228e0, 0x064a5b02, 0x1aabefd0, 0xfb42cd05, + 0xaa775aaf, 0x6aabe013, 0x69102f92, 0x1c1a8b7f, 0xc6c11d44, 0x78c086fe, + 0xbc703b7b, 0x1830f26d, 0x3bebf2af, 0x3cc22215, 0xb77c0f65, 0xf301c284, + 0xe13dc7d6, 0x74f1c7ab, 0x9a792e7c, 0x5bdf478e, 0xc1a09cfa, 0x885a9714, + 0xdce8e017, 0x84fd9f61, 0x52b7e613, 0x9e8aee19, 0x30ed9cc7, 0x7ac0aa8f, + 0xf009c4a5, 0x8fe657ad, 0xa8b7f48a, 0xf846f7e1, 0x7bfa73ea, 0xe5cddaa3, + 0xe9451f09, 0x8abd48f0, 0xf6904f10, 0x5280a44b, 0xf9e4497e, 0xd2324207, + 0x4883517b, 0x7fa45b54, 0xfa42794a, 0x9b7fffd1, 0xc1e293fe, 0x6c0aeadf, + 0x6dd08eca, 0x16681b99, 0x3769dba1, 0x5dd4a3a7, 0x5ebfdd10, 0xa0f4003e, + 0xdcf9d4f0, 0xcbe43e58, 0x4fad72c0, 0xd6fdbc45, 0x7acb0237, 0x1fcf869f, + 0x72c78df3, 0xe583cf9d, 0x58a57c1f, 0xf8657c06, 0x6cdf06de, 0xbcfa372c, + 0x5f49fcf8, 0xbe0d9625, 0x8cfe7c1a, 0x8d96056f, 0x7f3e3f3e, 0xcb06b7ce, + 0xcb0eafa0, 0x5a2f40ad, 0xf802f936, 0x035f76de, 0x20becd96, 0x6be9df3e, + 0x8e7ef2c6, 0xa4c9c4c7, 0x4878a250, 0x253710f4, 0xee99493b, 0x3d699429, + 0xd3d58ca5, 0x2a17f66f, 0xa5ee9eb4, 0x01978a75, 0x5685438b, 0xc3501f5a, + 0x92ff07da, 0x7d68d914, 0x0fb59fb0, 0x6453dfbd, 0x75a1f5a7, 0x3af87dac, + 0xad02517f, 0xf6b00f0f, 0x45431b8b, 0x38bf5a0e, 0x5b73dac8, 0xd693b148, + 0x9eac4373, 0xec53c077, 0x36bcf5a2, 0xc0f82f56, 0xeb489c5f, 0xfbeced05, + 0x51011d89, 0x61d2c675, 0x4edeacab, 0xf9d6ad28, 0x1348f4af, 0xef515d68, + 0x8fc51a24, 0x948f5aff, 0x7b21f149, 0xbfe43db0, 0x149bdb09, 0xe1bfb60f, + 0x76fac0af, 0x87ed8bd9, 0x5d584bfd, 0x17fb62f1, 0xbd629ffe, 0xbb63f659, + 0xd58fa56d, 0x0fb63f15, 0xfb06b958, 0xb00729df, 0x07cad47d, 0x12a77db1, + 0x5687f6c0, 0x4a99e63d, 0xf782b5eb, 0xb48fc0b7, 0xc03924ac, 0x328cc14f, + 0x05ab4fca, 0xf7f81b32, 0x28e980bf, 0x54ceae5f, 0xfeb70e50, 0x9009e0ad, + 0x834bfc5f, 0x7f27fcfa, 0xffdf8d95, 0x6991fb11, 0xfdef623f, 0xde3abde4, + 0xabde4fd0, 0x0d3f7a95, 0xbdad5ef0, 0x7d6cfd6f, 0x9e11a275, 0x7ef4ab57, + 0xae3c20b6, 0xef2bcdbe, 0x7846c9b5, 0xf7ac5b5e, 0x49e113b3, 0x4d3c1bee, + 0xd3f11b6f, 0x3f1876f4, 0x7e9e117b, 0xcc67837d, 0x8cfc463b, 0x9f8c2779, + 0x664fd803, 0x7a69fadf, 0xa69f88c7, 0x79f8c277, 0xa835e71b, 0xf31af36f, + 0x633f11ae, 0xe7e30dde, 0xbb278423, 0xff6cfd6f, 0xed9f88d0, 0x73f1861f, + 0xa0b9fb14, 0xf82af36f, 0x829f88c8, 0xe9f8c28f, 0xea2e7ec6, 0x3fdb3f5b, + 0xfb67e232, 0x7cfc6147, 0xd25cfd89, 0xfc1579b7, 0x829f88c3, 0x63f1847f, + 0xd19fa011, 0xf9a7837d, 0x9a7e2353, 0xc7e30d3f, 0xed8cfd81, 0x8fe33c1b, + 0xfe33f118, 0x693f1848, 0x427dd002, 0x3e69fadf, 0xf34fc462, 0x067e3091, + 0xfa533f61, 0x47f1af36, 0x7f19f88d, 0xe19f8c34, 0x2a42af38, 0xa10f00f7, + 0xee7ab8fd, 0x2349e767, 0x0c9e767e, 0xec52e7e3, 0x27ed1a67, 0x267ef7a7, + 0x33f11a76, 0x9f8c33b1, 0x95cfd8f1, 0x6767eb7d, 0x3b3f11a7, 0x29f8c33b, + 0xdd5cfc44, 0xec4d79b7, 0x6267e232, 0xfe4fc317, 0x89c5355b, 0x85ae9db4, + 0x993f489a, 0x08f1e1d4, 0x59ba2eb4, 0x046b745d, 0xb75112ec, 0x479b4837, + 0x1b3bdfa4, 0x457ef393, 0xa28eeda2, 0x8b979872, 0x76d1635a, 0x04f8d247, + 0xec939d83, 0x53d43149, 0xde18074b, 0xd43657ef, 0xf67fded0, 0x4cf686c5, + 0x9ea19e6f, 0xf0d13955, 0x229aa0fe, 0x8ac87d43, 0x67ef0cab, 0xd435affb, + 0xd8fcd673, 0x7505fef0, 0x17ed0d73, 0xda1957d6, 0x332c0a2f, 0xfc3647d4, + 0x4bfde187, 0xda197782, 0x95fe6d2f, 0xe8747da1, 0x7f3d4321, 0xf78663ff, + 0x306db6c7, 0xf83b8fb4, 0x427da18c, 0x7d4356fb, 0x269db1d2, 0x3ee9cf3b, + 0x45d79232, 0xecc27be0, 0xed054cfe, 0xc14b90bd, 0x89c032ba, 0xd76efc76, + 0xa530f57c, 0x76e7b2af, 0x17d28d35, 0xbae84a68, 0xf2a0385e, 0xfcfa76c2, + 0x17bd13a7, 0x9ff3e9ba, 0xdd4bde2a, 0xca53ec71, 0x80c9020f, 0x6940b552, + 0x6647bf6e, 0xf59458fc, 0xf443f0f5, 0xf74b6afb, 0xb75a64f0, 0xc0f58588, + 0x2c107fbf, 0x2209a7c8, 0x12f781a9, 0x82fd04ac, 0x9e0bb27b, 0xebf147f0, + 0x0e54419a, 0x6bbf4885, 0xd8066f64, 0xbe561b19, 0x643b07ee, 0xaf3a20f5, + 0x213c8401, 0x0ff21ebc, 0x9a0fdfa3, 0xfda5e19f, 0xa76a1559, 0xd0af8f47, + 0xf8e147f1, 0x73fe300d, 0x1d6f8c3d, 0xbe30de3a, 0x61a5706d, 0xc7429b7c, + 0x607b5377, 0x7c7c7be5, 0x8489844a, 0x87bc2f3c, 0x57075be3, 0x28f7f8e2, + 0x1e895fd4, 0x7e3c213f, 0x2ecbc833, 0x9c6c7f18, 0x689d0ff9, 0x2ae0ff9c, + 0x3615fce3, 0x0f2b3dff, 0x7013f1f1, 0x43857bfe, 0xab83fe6c, 0xacadfcd8, + 0x89f8f0df, 0x87effc61, 0xd3dabff9, 0x1b2673fc, 0xb1643fe7, 0x3656fe71, + 0x8f2b1bfe, 0x389df1f3, 0x71c29bfe, 0x8b21ff36, 0xeac57c71, 0x947f80d5, + 0x009a84ac, 0xa40c9f1d, 0xb03fa98a, 0xca071d0b, 0xa9942911, 0x30b5f909, + 0x69f8e114, 0x2fb7e302, 0xa1bf2812, 0x73e3f1be, 0xad9aa012, 0x9c5dfa80, + 0x163517d7, 0xb097a02a, 0xf32bfa9d, 0xcd15a838, 0x5937f222, 0x405c0d6b, + 0x166cede1, 0x58af50fd, 0xfa00253b, 0x6e4adaaf, 0x24ef832b, 0x9fe78212, + 0x86c9723e, 0xcb9979e8, 0x91f27579, 0x0b7928f6, 0x644551fb, 0x6f850d44, + 0xd8c1301a, 0xea63fd48, 0x5fea1107, 0x0cfd407c, 0x13f25942, 0x11f78d99, + 0xdea097f5, 0x6825fd4e, 0x7e256427, 0x2b7bbb47, 0xc65fc283, 0x6258ffe1, + 0xcdf1faf2, 0xe54fc042, 0x8f9f8bf3, 0xb6f53f46, 0xf48a0e15, 0xfc731c08, + 0x9d3a86a9, 0xd4e81f97, 0xd81ac3bd, 0x557e2020, 0x8a3957c0, 0xafb72126, + 0x8eb8a2c9, 0x252effbc, 0xfd45267b, 0xf723c40d, 0xb2dfefa7, 0xa6e4185c, + 0x58f4cee3, 0xe13ad8f3, 0x5ca0b2c9, 0x78cb2c93, 0x1a6dae42, 0x481ed32d, + 0xb8fe47b9, 0xebdc6a3d, 0x99f58d4a, 0xa77ac665, 0x142d91ec, 0x8172ceae, + 0xcefda7ac, 0xd76c6d9a, 0x525a71c7, 0x78f99d18, 0xbe0ce965, 0xc1e65059, + 0x79d23763, 0xab7d9bb6, 0xbb7d53c3, 0xa0585d4c, 0x011fbfa7, 0xf0d3faba, + 0xd9bb1fbd, 0xcef0cdbc, 0x329e6d96, 0x73d9cf3a, 0xb7f000c4, 0xefbffe19, + 0xb92c7872, 0xb0f35cb4, 0xf3b12c4c, 0xa37fc331, 0xa09f3cd7, 0x4df0eb0c, + 0x8ce7e695, 0xfa708e6f, 0x41fc0c7f, 0x1fc0a3cb, 0x9cc3fe14, 0x957a223f, + 0xd5b547f1, 0xa1f8033b, 0x209151fb, 0xdcbf395d, 0x5e65f9c0, 0x082f919d, + 0xc740caf1, 0xbc85b305, 0xc1f1455f, 0x0b07ce2c, 0x737c8dea, 0x99cbf10b, + 0xe372e871, 0x6777f5da, 0xfbf3b1a8, 0x4dcdf390, 0xfc46eff7, 0xd193cec4, + 0xa74e56e9, 0xed8c6a5b, 0xdeba7037, 0xbb3ae9c2, 0xa997c1fe, 0x563f20fa, + 0x7bc83203, 0x7a742ff5, 0xe9e81bb6, 0xc334f4e5, 0xe7a72b79, 0xf4673fad, + 0xcedbc334, 0x7f5ed9e9, 0x63432646, 0x77c335e1, 0xf9988adb, 0x39cf4028, + 0xacf4f8fe, 0x3d4c2e6e, 0x497cf51c, 0xc3d4caf0, 0xa8b67251, 0x5f50dca1, + 0xf0d1b818, 0x39fa82fe, 0x7579f686, 0xb7ed0d0b, 0x50c3b9af, 0xb9ffe39f, + 0x56dbfde1, 0xdfb434ac, 0xa1af7352, 0x07caa6fd, 0xbd1bf50d, 0x9fde1a8f, + 0xa1bd7b35, 0xd3d9667d, 0x4aebf686, 0xe5ea18b7, 0xf7861d9e, 0x870b5d85, + 0xeabae3b4, 0x887f63fd, 0x4567be27, 0x3beb353e, 0xf61e2f5d, 0x88fcf8a9, + 0xc796046f, 0x3f3e1a7c, 0xe58f1be1, 0x74dfd04a, 0x60ecb05d, 0x7343f565, + 0xe2a3b886, 0xdac89f1e, 0xbdb3d060, 0x7dfd43e9, 0x7fa3deb3, 0x14ecf159, + 0x902c5cbd, 0xbb075832, 0x3fad1db8, 0x49d7c53f, 0xb942ee42, 0xb930ac5c, + 0xb335bc5d, 0x3d422488, 0x4e26bc34, 0xcf2c267c, 0x33e70141, 0x00c72eaf, + 0x91fa82e7, 0xe036f826, 0xf9030b38, 0x1a8be786, 0xebbe1926, 0x7c222dd8, + 0x27c6414b, 0xb65672c0, 0x85f002c7, 0xeebe0ef6, 0xb3d78012, 0x4beb02d7, + 0xe7b43f73, 0xa9a57c3a, 0x73c02587, 0x7cc79619, 0xe23cb1b3, 0xd87962f3, + 0xc7e58957, 0xdb2c1abe, 0xfcb02b7d, 0xf2c7e7c8, 0x2c1adf03, 0xc3abeeff, + 0x1eafa0f2, 0x017c77cb, 0x35f2df2c, 0x2f86f960, 0xaf9b6588, 0x9f4ecb19, + 0x5e5d4b07, 0x4865f8a2, 0xe8bf1466, 0x8fd74ffa, 0x9cbf38c7, 0xc7897e00, + 0x7c8c1b17, 0x41ae5471, 0x43eb30be, 0xfacc1d33, 0xc3f2bbef, 0xdbb30b58, + 0x443f2fbe, 0xa2659de8, 0xf46f4e77, 0xbd146226, 0x0cdc5ac7, 0xfbef4e1e, + 0xf638de00, 0xb8b025fa, 0x83b28bf7, 0xff160e3c, 0x6a7a71e5, 0x2ff8b201, + 0xbe96bb1f, 0x52f686db, 0xe3e80460, 0x77fe23d3, 0x4fb7c438, 0x6752b41f, + 0x99f9e7aa, 0x1e23d7e9, 0x86fd0788, 0x28ba01f9, 0xdbb6c7e4, 0xed5e1813, + 0xe84a5216, 0x05ef717a, 0x47736a4f, 0x29225d61, 0x2b407df0, 0x97e9c577, + 0xdf80a0da, 0xeb5af0de, 0xfa1722fa, 0x57d8f23b, 0xb58e5005, 0x61343b30, + 0x30f688af, 0x01a13d09, 0xdefac37e, 0xdc4065aa, 0xc502fbb8, 0xc071eb8d, + 0x9f9fc469, 0xf8220bd6, 0xa8e297bb, 0xbab3d70d, 0xb0dfc40c, 0xf667862f, + 0xe9bd7f01, 0x39f0dec9, 0xdfe03037, 0xf4decf82, 0x8b7a6f57, 0x9ae7d478, + 0x76bbfce9, 0x2bf7925d, 0x50d4f415, 0x80f4ffe6, 0xc7bf7d6f, 0xf0254f0c, + 0xf3bed8f1, 0xceba5771, 0x09836dc7, 0x906de71d, 0xe9ffda17, 0x80930ba6, + 0xb41fb42e, 0x71b7bbbb, 0xba17b9fb, 0xf636cc9e, 0x2fe5cd57, 0x42925fdc, + 0xb8e94b84, 0x4921452e, 0xbd161d74, 0x1bf4442b, 0xf83f76b4, 0x5a1cbbe3, + 0xd8fe0aad, 0x2a435789, 0xdbf468f4, 0x227fef4f, 0x659bfc11, 0xe1f71619, + 0xcbd47438, 0xb76cc125, 0x680fda33, 0xd74fd636, 0xf441a509, 0xeba4d493, + 0xc075812f, 0x0c3c3eed, 0x960672f4, 0x32cb3f7a, 0x54e1f714, 0x23d33fa4, + 0x67a8c98d, 0xf86cf84e, 0x470d0fde, 0xe044fd4f, 0xd09f2268, 0xdf1481ef, + 0x7efcf4e4, 0x9d20728f, 0x485e2055, 0xc02fe45a, 0xffd3b37f, 0xfd0a19be, + 0xfbd7584a, 0x7e8a0ead, 0xbcf0a5eb, 0xfd1e30d1, 0x32f7d54e, 0xe59ebbe1, + 0x7447224d, 0xdb74a77e, 0x175bf7c2, 0x46ddd835, 0x50d930bb, 0x74ce6eaf, + 0xf844ec1b, 0x95c21807, 0xb77c0482, 0x975db398, 0x7c035ce4, 0xe3043f74, + 0xf605df80, 0xbb5b12de, 0x4c5155e2, 0xe72f80da, 0x5ef9d78e, 0xd53ef59d, + 0x915fc74f, 0xf917c809, 0x1055429a, 0xa0ae8fe9, 0xb7eb42c4, 0xa6dcdaf3, + 0xbd61d345, 0xf6616e3a, 0x4b290578, 0x92b37f04, 0x7c4015d4, 0x94b124f2, + 0x249e5c82, 0x47e6246f, 0xa2fbe1c9, 0xbedcf082, 0x531768c6, 0x5f50d97f, + 0xcfac6f50, 0xc3a6d727, 0xb5fcf2be, 0xa0080932, 0xafed8c2f, 0x168e4c88, + 0xb0d59a90, 0xd995afbe, 0x4dd7363a, 0xdf0a2ca4, 0x2f1e1792, 0x1feb4398, + 0xd31ecc8b, 0xa61745f7, 0x82abf830, 0x6d0f15eb, 0xff29a4ff, 0xe879aa06, + 0xb0d581f7, 0x09b7f95e, 0x963526da, 0x7e16df7e, 0xfafabc33, 0xcb3fb31f, + 0x20d258e1, 0xec710278, 0x0ebe6e80, 0x4d2e7aeb, 0x08e21b72, 0xe2a3d42a, + 0x9f99df0c, 0x9f8188d2, 0x36bd17ee, 0x1fe31fa9, 0xa904a7f0, 0x9f7ef15b, + 0xfa6233fe, 0xfec6934f, 0xa40ffd80, 0xfa1817fd, 0xf8507f57, 0x3fc0c587, + 0x4bff5e2a, 0xbb76785e, 0xaa93ea9f, 0x12248fcd, 0x971e3eba, 0x4a35d2ea, + 0xee9bc5df, 0x1f3a044e, 0xc089fc93, 0x6203c7af, 0x7ace2069, 0xe9d25735, + 0x100a71ed, 0xd27f82c7, 0x733c4ffe, 0x5ff7fa1f, 0x18dd926c, 0x86b06a9f, + 0x971e54ac, 0x4e9c2d36, 0x887eb172, 0x2539efd5, 0xc8d9bd42, 0x3d4f557f, + 0x0af90e92, 0xbc785394, 0xecf68426, 0x969f8dd2, 0xba44bae0, 0xdfcc8e51, + 0x52e7f8c1, 0x51cdff50, 0x29db6292, 0x5777e89c, 0x3754bc73, 0x4c4a77dd, + 0xa3b57f84, 0xbf7e6c3f, 0xd7a5db92, 0x23b4ae49, 0xe32704d4, 0x87d038c8, + 0x80483e3a, 0x0be2a5d9, 0x1c42e78f, 0x2be363b2, 0x9e144289, 0x1d3a3974, + 0x3b8ffdbc, 0x6df59ed5, 0x68b39527, 0xaf5f47fb, 0x4f6e66d4, 0xb172b0b7, + 0x449c4a1c, 0xf5e2e0f5, 0x8fa7e6b2, 0xc4fb3f17, 0x5c418f93, 0x76ab3df0, + 0xd17fed01, 0x33bf2fb3, 0x6d17d691, 0xb3a6d391, 0xf4853869, 0xe9aa5d08, + 0x22f22b7f, 0xfe7aa874, 0x84bd4565, 0x4a65ff3d, 0xb68b1e84, 0x25c856ec, + 0x0e28f8b1, 0x9dda56ee, 0x3c12e871, 0x81f60254, 0x153fc2f8, 0x5df1fba0, + 0x1d9fe902, 0x5feb9f07, 0xf01ff5c6, 0x74e47484, 0xf4cdd30a, 0x0ba5357e, + 0x4e9d6be8, 0x5cb1f6e6, 0xea7f40bf, 0xe7e7e428, 0x54fc5276, 0xc1aaddfe, + 0xbb9f2bfc, 0x71e61133, 0x7c61aa54, 0xe9ddf8fd, 0xa56e3a1e, 0x63774fec, + 0xfe579ec9, 0x6fc827e1, 0x49ff5e0b, 0x8867c63a, 0x6b82d327, 0xe6133f8f, + 0x4cdd6f37, 0xe27cdf9c, 0x7cabbe45, 0xfd032c5c, 0x4a44b9f7, 0x8b91c4b7, + 0xe3b31283, 0x06a06e8e, 0x51df9d18, 0x7e60acba, 0xe6221bca, 0x07721129, + 0x09fff901, 0x10b50b9f, 0x8db9feb0, 0xa4b369d1, 0xcad461fb, 0x8dd7e68c, + 0x7d01b4f7, 0xf4f20c4e, 0x6a8b7d87, 0x3e39f922, 0xbf686f84, 0xfad3ebe2, + 0x5550fa33, 0xa3bfc05b, 0x3c317ceb, 0x64dbf787, 0xf0d73d8f, 0x3b26f91d, + 0x3e72fe32, 0x013b853e, 0xe9a3e7d6, 0x4954edf1, 0xdaf87416, 0x457f1448, + 0xf79337c9, 0xf932f78d, 0x503de5d6, 0x67ed0a5e, 0x03f262df, 0x47fac1df, + 0xc7f50ae1, 0x0bd7ddf6, 0x24ac0fa8, 0x37ae4f14, 0x8dae5cca, 0x509f3aed, + 0x292125b8, 0xffa05f8a, 0xee3fc414, 0x4b5fcc57, 0x97d28bbf, 0x625e30d5, + 0xdcba7f6c, 0xfff2e02e, 0xc8ffc826, 0x7593fc88, 0xb67bee4c, 0x17a8fc9f, + 0x2781cb17, 0xa579031f, 0x4157e9f2, 0x9832e55e, 0x7b8d67f7, 0x9531f9df, + 0xba82cf93, 0xa7f51a9c, 0xb72b4e59, 0xe4f1258e, 0x46a733f4, 0x7d29cae2, + 0x9d4e571e, 0xffc7c8ed, 0xc753fa57, 0xfc2657df, 0x27b0fae9, 0x61f59a3c, + 0x3e22a4bd, 0xfe90facd, 0x620a45bd, 0x3be74ff9, 0xfeaadf9d, 0xe80864b4, + 0xea5f309d, 0x4be6177c, 0xe262ef9d, 0x99fc06a1, 0x18865fdb, 0x816b8510, + 0xf032fead, 0x809a6c23, 0x87617e72, 0x6ceef305, 0xbff40463, 0x584bd446, + 0x1ee2dd7f, 0x8ce8760b, 0xf67c2f49, 0xededf273, 0xbe5aefff, 0x307b63e0, + 0x861ca03b, 0x74d14be0, 0xe0c2d71c, 0x02403eac, 0x781f5143, 0x7f28b2c4, + 0xf7970e79, 0x9ad83e17, 0xec2c780f, 0x8ed4951a, 0xfa30727a, 0x6f5cd593, + 0x49abf69c, 0xb74f4fa0, 0x78bfa0e4, 0x8ae8bf7a, 0x34f7ff97, 0x209fefa7, + 0xaecb463e, 0xa44ea48d, 0xba45d6fc, 0x6ff06ed1, 0x714d91b4, 0xcba6aff6, + 0x5f7e2f4c, 0x01fd007c, 0xdbdb4f1f, 0xd8e2ca4b, 0xf9f2b7b1, 0x25f3d8ce, + 0xb7178fae, 0xbd80b7ac, 0x8b46f174, 0x41bfefc1, 0x479d7ce6, 0x67af80f2, + 0xc6bbb1ec, 0x8bf71e00, 0x5649e41a, 0xbc529cb7, 0xf342fc71, 0xb07fa1fc, + 0xdd93eeb7, 0xca2f4fc8, 0x0f01dbc1, 0x11b49e2f, 0xa1db2fd8, 0x078a2dd4, + 0x830a9de7, 0x4661c773, 0x2f0a1f97, 0x50ce5d85, 0x3673c411, 0x58dbe412, + 0xf3e4133a, 0xb0240dd3, 0x2de81b32, 0xc1237ab2, 0xca0a57bc, 0x77c327af, + 0xa35ed35f, 0xe6c2f3e4, 0xe8127f2d, 0x045b4b7b, 0x2fb685b7, 0xe015da95, + 0x64e6ea97, 0x68d8f411, 0x74ffcf55, 0x147d725f, 0x4b27ddff, 0x13bd9788, + 0xf009bc5f, 0x2143a672, 0x79efcfb0, 0x68f31ba9, 0x23e4b4cf, 0xaf34f5bf, + 0xb2e47de7, 0x43f412a9, 0x3a665f10, 0x304c6a8e, 0x7b1527d4, 0x335c0007, + 0xb5cbedac, 0x2bb77838, 0xa1fdeecc, 0xb2b7b3e4, 0x96fbf2cf, 0xb15ebf2e, + 0xfeef8a2c, 0xfdbf2b1e, 0xb2efc9e3, 0x987f6a95, 0x9cd6b2f7, 0x65cf80fe, + 0xc5fb917f, 0x7d67abe3, 0xccdc2fcc, 0x9abb65f3, 0x1a5efca8, 0x544dbf25, + 0x01c4e37e, 0xe581fa5f, 0xdf9059f7, 0x2bbdf038, 0xf2e8fa33, 0x0872db9b, + 0xc9b737e5, 0x7933c862, 0x7d76e655, 0xf42bf28f, 0xea0d3ebb, 0xa388e6b2, + 0x100f01af, 0xe3ccdcc7, 0xc80e30fc, 0x71b8a4b1, 0x63957d9e, 0x8e59bfdf, + 0x98236d97, 0x6f4b1317, 0x76cbc726, 0x80163950, 0x978e4cee, 0xce3952b5, + 0x11df958e, 0xbecbf231, 0xdf621a5f, 0xff673757, 0x5e3a66ee, 0x6cd6479e, + 0x88bcfdf4, 0x968d8f3c, 0x70914967, 0xbcf231be, 0xbcf26fbf, 0x9533cb8d, + 0x1c5aa1d3, 0xc62d6aba, 0x2717acfc, 0x1e7c6d1c, 0x226ff2f8, 0x5baf49fa, + 0xeafb5d98, 0x8063a384, 0x7870a62f, 0x743a7086, 0x7fd8fcfa, 0xd347c4c9, + 0x5f8a4e41, 0xe42dfbaa, 0x28d92f35, 0x4b87d013, 0x1fa10e9b, 0xe8ab8e6a, + 0xbe399576, 0x7311eba2, 0x8351659c, 0xc7c79eb1, 0x11db172f, 0xa89af25e, + 0x77c38a6d, 0xb9c13d79, 0xe71deebf, 0xbd9c0898, 0x79f47dc5, 0x3e9706f4, + 0x970a31af, 0x1f24d197, 0x8f1489e2, 0xbffe2f28, 0x2a87188a, 0x90c0bc2b, + 0xeb913fef, 0xc2bafcc9, 0x944b0862, 0xf80e3e43, 0xec77f551, 0xb1b27d83, + 0x303cd507, 0xb44d27a7, 0x7a9fc17a, 0xf28ddeda, 0x0965d3ac, 0xbc0dcba7, + 0xd407179f, 0x55bf0114, 0x586e0b37, 0x5f43aa77, 0xbd86b9e2, 0x02517e8f, + 0x55b0b47c, 0x0f915b70, 0xe7e0294f, 0x17f5d095, 0xe5bf29f8, 0x0bbdda14, + 0xf8450b5b, 0x010ee17e, 0xc37bd213, 0xb6e95f4f, 0x59e3d388, 0x7009df80, + 0x8d75b376, 0x57b7a7c3, 0xfc037e4b, 0x5b9d8fc5, 0x56e0c59d, 0xde046aad, + 0xe77861b1, 0x3eaf3888, 0xbde3abc2, 0x98977837, 0xe4daf8e8, 0x220f1833, + 0xf27dc92d, 0x5c6dbe6b, 0xa1b49aaa, 0xa7c7a67f, 0xf3bd17ee, 0x951b8864, + 0x8e31920a, 0xedf18ddb, 0x8fffa01f, 0xf83fd7ce, 0x6eba2117, 0x09f1b9fd, + 0x67c9f7c4, 0xba00cd0e, 0x24517a2c, 0xce974a36, 0xe1091746, 0x0140483e, + 0x8935543a, 0x48f78c1e, 0x5ceb82a1, 0x65a8f8d1, 0x42ecd8f8, 0xd5b5583d, + 0xbf4e981a, 0x49fedaaf, 0x9d33d82e, 0xcbef7577, 0x19ffbf02, 0xf898e501, + 0x1f6173db, 0xfb624aa8, 0x6efc663b, 0xd8fad854, 0x1b31c3b1, 0x606841e4, + 0x82aa8be7, 0x946b64b3, 0x457bfc3d, 0x7be971c6, 0x7fe6d798, 0x30bcc05a, + 0x5cfa2f80, 0xd36f9e8b, 0x4bf334f1, 0x00e59aaa, 0x6aaa539c, 0x7109d2d8, + 0x5683aa92, 0x1baad75c, 0xb75c614e, 0xa8b3f378, 0x459bab7f, 0xe31c9f83, + 0x2188369f, 0x4d57f82b, 0x4ece304b, 0x1eb087eb, 0xe9a71f8c, 0xb45a8fcd, + 0x1fbb75b9, 0xa7f9e4e4, 0x529cf112, 0xf444a6db, 0x1fce1b53, 0x47f18a1f, + 0xd79ef783, 0xf9c13d1f, 0x318a6fe3, 0x521a479e, 0xf0a54fd1, 0xb1c59415, + 0xff7cc3d7, 0x807fe7ec, 0xd6c76978, 0xf000fecf, 0x99d7fe2e, 0xe282fc3f, + 0xbbb2ec91, 0x3f55ff41, 0x9bc636f3, 0x728eeff4, 0xf4f9d5bd, 0xeba71853, + 0x41aacf7c, 0x47ad9d6f, 0xaabc4307, 0xe997cb73, 0x6f2c9f60, 0xd6f6869d, + 0xfdc56df2, 0x40fb1c49, 0x036f812f, 0x9a13887d, 0x69b7b5e9, 0xf38060ef, + 0x6c37a524, 0x0be38609, 0x5e2c25c1, 0x42b8f2a3, 0x6c78fc63, 0xe9a11c4c, + 0x8ca66bba, 0x54d65281, 0xc27887d2, 0x978e945b, 0x8d7e81f6, 0x89ef6fcc, + 0x1fe1277e, 0xd5b24e94, 0x9bcfbf48, 0x31f1fde6, 0xed4a6b68, 0xea109e31, + 0x78f4de03, 0xc78a1bef, 0xdaf9056d, 0xdf8c27fa, 0xd3a6dd00, 0xfb3e7689, + 0x938860f9, 0x6fbb931f, 0x56d57dc5, 0x5797ee2b, 0xf28bbeb5, 0x75edb9d3, + 0x8f0937b4, 0xf09276bb, 0xf1938b1f, 0x8dead3dc, 0xe087162e, 0x853887f8, + 0x79cf889a, 0xb1f1823c, 0x29e8a71e, 0x7585713e, 0x6523cf28, 0x1b259471, + 0x298857df, 0x8f8c23ee, 0xd13df3ac, 0x1b83c749, 0x3a2e30f0, 0x0e3f16de, + 0x72cb8e14, 0x20fd017a, 0xa78e16ce, 0x8840fad1, 0x778404af, 0xd07d1c49, + 0xe9c59eb9, 0xfe63653a, 0x2c3e8449, 0xa26456fe, 0xdecf3eb3, 0xe0dea7d6, + 0xc9f8b6ff, 0x6c79c587, 0xbe3a9e2c, 0xe7c7af8e, 0xb7ef8559, 0x98215a5f, + 0x802a6ff7, 0x1d34971f, 0x513f2052, 0xf9f4c75f, 0xbc3b7076, 0xf31119e3, + 0xf707576b, 0xeb371ea2, 0xde70a58b, 0x3fbc0e21, 0x6d2ef0e3, 0xc744eb66, + 0x49c05756, 0xb3d8e9fb, 0x6979f903, 0x4fc521e3, 0xf0d7dbfb, 0x46fcc2bc, + 0x4eb03f26, 0xefe0a204, 0x2e776e78, 0xbb322f8b, 0xddce3cdf, 0xd3a79e56, + 0xea9c7f12, 0x718653c6, 0x0a83f916, 0xff3e97cb, 0xcf242778, 0x44efe82c, + 0x5f204c9b, 0x2c5044f2, 0x593fb78d, 0xdc799569, 0x74958eba, 0x25f3c4bd, + 0x449e762e, 0xde30514c, 0xfe35dcb1, 0x941a5260, 0x507e0a8a, 0x5fb64aed, + 0x5a9ffb5b, 0x36bbd006, 0xc78c06f9, 0xebf099d6, 0xc217734e, 0xd4f71339, + 0xaec031b2, 0xec937d66, 0x5fe018b1, 0xafed2aee, 0xd1573852, 0x275ce07e, + 0xef3c3491, 0x94962622, 0xb7447cc2, 0x138f6dc5, 0x659d9307, 0x17851bc4, + 0x9f3c6dd9, 0x57cebe42, 0x9f7d1fa1, 0x6dadb175, 0x3dba361f, 0xc495f002, + 0xaf0bd5f7, 0xbbbce377, 0x580d051a, 0xd563aa9c, 0x05f2ce9d, 0xdae8dd60, + 0x2e4b949a, 0x87890fc5, 0xfe0e27ae, 0xbddc685c, 0xaad1f41b, 0xa649e244, + 0xaab14672, 0x4e70398a, 0xc84db467, 0xf53d3e01, 0x5fb48bea, 0x60488b7b, + 0xa9cbbf8b, 0x92790be7, 0xe41cce41, 0x010bcc7e, 0x3526fe56, 0x5f39a702, + 0xe92bc084, 0xd3bc7391, 0x39c62744, 0xd113af4e, 0xc5c9159f, 0xfccc9bbf, + 0xf8001273, 0x88b27af9, 0x4a1a79c3, 0xc142bf78, 0x7f05da3c, 0x4420be79, + 0xf1a21d18, 0xf46a5a95, 0x89edeb17, 0x436fb0b9, 0xc8369efc, 0xfde0ae4b, + 0x9e332bf5, 0xe7e2a1f3, 0xcf52fb07, 0x7e6cffd3, 0x7fd07ec9, 0xa8f9de15, + 0x36cffbd7, 0xdb32039e, 0xe42f08ef, 0x7bb9500d, 0xe7b5884c, 0x5c1e5b2b, + 0xb1e0f90d, 0x0464f3fb, 0x91541be4, 0xa1f20d04, 0x077df6cd, 0xf1c84de8, + 0xe0271271, 0xd97d67b1, 0x87db7e0b, 0x98f26eff, 0x0b57e2f3, 0x2e8dfbc1, + 0xf058dfdc, 0x3f51db97, 0xf88c3359, 0xfc46abb5, 0xf198463a, 0x4bb3c468, + 0xb28de233, 0x787ce079, 0x3c6f1a4e, 0xb3c6655f, 0x0e1da844, 0xd0404af6, + 0xf931fe80, 0x11ebcd0f, 0xa6fcdeee, 0x8f5f1b34, 0x5fe95e38, 0xa99d2d99, + 0x533b806c, 0x985ca10a, 0x19cb28e5, 0x83dfe012, 0xf12b02d2, 0x7e85cd2b, + 0x8f9f0649, 0x73bec150, 0x00891c80, 0x047286af, 0xcf402827, 0x6e07c83b, + 0x7c85a7a0, 0xd919be42, 0x2cef3d33, 0x5cd0e97f, 0xe03ad5fa, 0xae514bdf, + 0x14a939d8, 0x06cda812, 0xb0dcd539, 0x367d076e, 0xf38242b5, 0x18ad44e6, + 0xddcce706, 0xc7903e58, 0x451aefde, 0x182c5f30, 0xfa0e9b3a, 0x291e7aa9, + 0x80f7fd03, 0xfc033dd2, 0xccedfbdb, 0xaec8b94f, 0xa5ff3ea0, 0x9cafdf5d, + 0xa9cb97fa, 0xc8b5763c, 0xebc39c2a, 0xbb64d96a, 0x22cdea00, 0x4eaef79e, + 0xc608bbae, 0x19916cef, 0xc0b6155c, 0xb7c7e005, 0x741eb8ca, 0xf3c64c56, + 0xadbb612c, 0x7613ed85, 0x78927cb5, 0xef3e947b, 0x22f87e6c, 0x6a3c3388, + 0x793fbf89, 0x9df2cdbd, 0xfaf0d4fc, 0x3f9314db, 0xe58dbd71, 0x94303c4f, + 0xf96963ce, 0x330ebe69, 0xe9c49879, 0xabfcd2fc, 0x5adbfe70, 0xe74f3fa8, + 0xfcde2251, 0x3ce84ba3, 0x312dbc27, 0xd33c4afd, 0xa3b3a4e7, 0x0efef03c, + 0x3e0065a2, 0x02214c26, 0xf784f3c8, 0x8febee08, 0x7e8f99a9, 0x94898bd5, + 0x4c5f29cf, 0x0b7ca16d, 0x89c3ae7a, 0x36d8fbf6, 0xc997c0c9, 0xc17bbd53, + 0x90771ccf, 0x771dbea0, 0x9e3ed8d0, 0xa71c4404, 0xd27cf8dd, 0xc6bd6331, + 0x1233f7c6, 0xf7f03a49, 0x8445afda, 0x689babab, 0xbb7ed177, 0xfde0062a, + 0xe1675d02, 0xbf2d1494, 0xade34b16, 0x8c6d2bf3, 0x08551e2f, 0xce8f2fae, + 0xc13ee277, 0x9855f99e, 0xcfc5fd27, 0x9de243bd, 0x4bd28bbb, 0xddff6c49, + 0xa7814493, 0x604abd7c, 0x8ccbaef8, 0x4bd297de, 0xbe758f9d, 0x7339f9d6, + 0x5e37827e, 0xcec38ade, 0xf9a29dec, 0xfc050423, 0x01025db2, 0xe5de76bc, + 0x9b5fe435, 0x2bb93f4b, 0x6ea9e00b, 0xb676833e, 0x1e7e25ad, 0x225b06d4, + 0xf2eefbf3, 0x8d7c84af, 0x04a1529f, 0xbf73d8fd, 0x5aafd16b, 0x88534103, + 0xe6ead9eb, 0x79a7b9e0, 0xe201b236, 0xe65d52b0, 0xfbe02eb5, 0x53572be2, + 0xb32b1f78, 0x951f9d20, 0xbfdf8435, 0x2f8c1084, 0x077e4c48, 0xa3eb20ce, + 0xda357fcf, 0xb46d9b0a, 0x1b9b66df, 0x6af54ffb, 0xfdafc002, 0xc1127ff3, + 0x673ae99e, 0xe00e3a45, 0xddfe8ffe, 0xaf66369b, 0x6cf762dd, 0x9527fe05, + 0x9a1f2869, 0x48ad5137, 0x14a07385, 0x4fe271ef, 0xe29a5dba, 0xc28dbaa5, + 0xe0b4e293, 0x78f110be, 0x979eb754, 0x517bf840, 0x024240f2, 0x5d05bc81, + 0x422d0a9f, 0x7ff945c8, 0x0219cd8c, 0x92a5233f, 0x60829bce, 0x5fd63627, + 0x3e11d49b, 0x907986c7, 0x200b2f94, 0xde609df9, 0x415a2403, 0xd59ebaff, + 0x64aaf3f5, 0xd566fa82, 0x96a05283, 0x6a4eb3f6, 0x24fc43b7, 0xc116a3db, + 0xa48a7356, 0x41baf9e2, 0x1d1e4c95, 0x87278f39, 0xec2a15ed, 0xde25ffa3, + 0xef8e2f16, 0x8b757ce6, 0xe03efbdd, 0xf77f773b, 0x346b301e, 0x7b4f1b3b, + 0x79f686d9, 0x3b706f58, 0xbbaf84ac, 0xfb653e13, 0x397424c6, 0x71e863e6, + 0xa0deb37a, 0x08a6f072, 0x44a9f572, 0x87943cf0, 0x4f40affe, 0x1fd288c9, + 0x682c9d7c, 0xb68bd9ae, 0x2f6a389b, 0x57a4e3f0, 0x8c73ecf0, 0xc077191e, + 0x7ef00b5b, 0xe661fd57, 0x2a21d187, 0xa33e9c8f, 0xec173854, 0xfda1d70e, + 0x937d265f, 0x3fa63e56, 0xcf9cb5da, 0xe5d5f8cc, 0x79ef2cda, 0x56bdb42b, + 0x488035ec, 0x84438f30, 0x0e6a1c08, 0x2203a3e8, 0x855df7d8, 0x5c285f94, + 0x28ee411b, 0x0d9f26bf, 0xb37c095c, 0x3b0ae5b6, 0x5e77c7c8, 0xebf4423f, + 0x7fe3b8a8, 0x7681de88, 0x08983f96, 0xfbba5878, 0x423f5f2c, 0x5d30e748, + 0xc7447ca9, 0x37be7443, 0x172eb9f3, 0x394070b5, 0x009b9d87, 0x104288fa, + 0xeb256b09, 0xe8a760dc, 0xd86d75f6, 0x7cc64d9e, 0x366ee5ef, 0xdbacad5e, + 0xe60d9ae5, 0xd455dcbb, 0x2efb7cff, 0xffa8e7d5, 0x5d2f9512, 0x7fa3752d, + 0x214e7d56, 0x81efd481, 0x7a3a16af, 0x455f01ba, 0xf8b17ef6, 0xd472081a, + 0xf9cbffef, 0xcf9e6cdc, 0x3e646a3d, 0xc5f78893, 0x0a17aa76, 0x64cfacee, + 0xcade417c, 0x7e0be688, 0xf927b1de, 0x1be54f1e, 0x7918c7dc, 0x84f1c936, + 0x96c72a16, 0xe4d63958, 0x4827bc32, 0xbea0756b, 0x59f5cb33, 0x076aaf3e, + 0xa24dfbc3, 0x9f3067f7, 0x60f74b6a, 0x955cbbe0, 0xc0a74ea4, 0xe88b36e6, + 0x54b69007, 0xbb123ac3, 0xdc59fbbe, 0x7a07af8a, 0xa668529c, 0xb3e74d7c, + 0x0bbdeec9, 0xcdd6a5e4, 0x58384afc, 0xa3707604, 0x3c377bcd, 0x12d85077, + 0x88c75ce0, 0x838b3650, 0xd4720c84, 0x4c38dc93, 0x490c1172, 0xe9f93eb8, + 0xd08174fa, 0xf6c53c33, 0xd52f0664, 0x0c7f6016, 0xb06c202c, 0xf9f304a5, + 0xf3b2e606, 0xd8f303f8, 0xd84f59fd, 0x91b9bad9, 0xd97a07af, 0x075b2b68, + 0xe2259378, 0x777de6b7, 0x885401b8, 0x7bb26e0b, 0x6cfe831e, 0x479c1ea5, + 0x02689b96, 0x292ca3e5, 0x53fec028, 0x605562ca, 0xd6c240f1, 0x7f692813, + 0x42d5d359, 0x20b28f58, 0x07de0097, 0x9c8e263b, 0xefe5dab4, 0x8e6ac717, + 0xb95ba3b1, 0xe853ec1c, 0xb3a7537c, 0x3c70e43c, 0xf80f8286, 0x80dd74ed, + 0x9cfced93, 0x93f835e5, 0x7ecd9e19, 0xe60c1015, 0xddfaf125, 0x29ec910a, + 0x2df8f7e8, 0x86c59df0, 0x68838f7e, 0x078bd041, 0xce5ceced, 0x035b416a, + 0xdd48dff5, 0x40b7b836, 0x2607ebe7, 0xf449ab5f, 0xa729c495, 0xa517c173, + 0xf026fe7c, 0xd3e4e75b, 0x0ce157c3, 0x7e3307ba, 0xbc8688f3, 0xcd6e9d47, + 0x766e81b2, 0xeb447388, 0x7e829761, 0xa090a77b, 0xb9d39f81, 0x0a706050, + 0x2a179e36, 0x5c2fe319, 0xfdfae9cf, 0xe9bcd82b, 0x8ff1f307, 0x6c567bc6, + 0xd1e00d9a, 0x1b9f0fe1, 0x31eb9d32, 0xc8c9fb9f, 0x3263c709, 0x4cab4f31, + 0xc852bb81, 0xda0716e9, 0x4c89d555, 0xd0fccdae, 0x79c2941f, 0x7c50cbce, + 0xedf4097d, 0x8324d72f, 0xcb7fed1e, 0xafa044e1, 0x825d0f19, 0xd83ef47f, + 0x1c9bfab7, 0x2f5b7f77, 0x94063233, 0x91999d83, 0xfea58199, 0xc529debc, + 0x26a5ef8d, 0x6bb8cf7c, 0x46dbe580, 0x026a6bf1, 0xf7a4efed, 0x283c778d, + 0xf718ddee, 0xf8604fae, 0x3c7457ae, 0x672049aa, 0xc496ba91, 0xb32779ce, + 0x8cdc1c7b, 0xb67d6b9e, 0x7e8a4972, 0x467683cf, 0xf2b9e23f, 0x6b025046, + 0xf909b265, 0xf465c59a, 0xe8aa5c7c, 0x1992fd18, 0x8df5bf5c, 0xff7d872e, + 0x9c6484dc, 0xd3b5d9ef, 0x7274bc70, 0xc5387d97, 0x8b32fceb, 0x939af106, + 0x089eff73, 0x66e6ff47, 0x3c1015b5, 0x1ab35a62, 0x16ffaefc, 0x9409b9bd, + 0x54f5694e, 0x3e32a511, 0x74a3b900, 0x13f712b9, 0xe6e258e7, 0x604d8ddf, + 0x76a7f57e, 0x919b8e37, 0x22bcb831, 0x103eba3f, 0x23f3a4e9, 0x8accc395, + 0x61739131, 0x24a63f94, 0x2ea791c4, 0x7ec33499, 0xd30fae80, 0x7d75fe38, + 0x1a43cbac, 0xefec19c8, 0xa8fd5195, 0x7f2873d3, 0x90e31d35, 0xfcb427f8, + 0xf3b04bf9, 0xa114a713, 0xbff2a3be, 0x0465e506, 0xd076dfd3, 0xc7f151a7, + 0x0777d6ae, 0x87debec1, 0x05c679ff, 0x90ff3bfb, 0x3fa05dba, 0x4df2fd8f, + 0x7c11e417, 0x87164bf8, 0x1fe4d5b8, 0x9e981379, 0xcd94260f, 0xe6dd7982, + 0x378167fb, 0x0ac92f8a, 0x90b15fb6, 0xf3c6bb2e, 0xbcf3c683, 0xf3e6824b, + 0x77ec7ebb, 0x8e3f1489, 0xc3a708fe, 0x4af5c6c2, 0x7be30a96, 0x8f3d0217, + 0x58efff71, 0x4367bb13, 0xe36e6787, 0xa27c0568, 0xf958b47f, 0xcc9b76be, + 0x74cf05d6, 0x72f2a7d8, 0xdce199bc, 0xfd81cbb7, 0x44447bcd, 0x1d0e64bf, + 0xafd5056b, 0x679616de, 0xbcc79e6b, 0x3812d50f, 0x5eef3f2f, 0x785dfd01, + 0x9d7497ff, 0x07b8aef2, 0xf3ccb3f7, 0x603fdf34, 0xfba4b73e, 0xfd380b49, + 0xe517882b, 0xa20f262f, 0x9b3bed85, 0xf7a77ae3, 0xfe6038e7, 0x3f7025f7, + 0x838c80a3, 0xfbad877c, 0x2f9d2687, 0x9f83aacf, 0xf3c13ed7, 0x08f98f33, + 0x5412b396, 0xe5ba2e76, 0xabe012f5, 0xf05bcda5, 0xab6f96be, 0x1cb4966f, + 0x8931fc4f, 0x1f6a1de8, 0x21fe07ae, 0x3760c15e, 0x467f5d2e, 0xc32c7e61, + 0xf9fccdc3, 0xdc5f30cd, 0x72f76527, 0x3e58bcdc, 0xcb9f7d1b, 0x7cc609d3, + 0xf9f08eeb, 0x258f3673, 0x9f481f7c, 0x679f999f, 0x5e78b025, 0xd5f2c6c5, + 0x6b94e803, 0xe60e8f5b, 0xdf300ae7, 0x3317e75a, 0x65202c3f, 0x14429925, + 0x8d7e5bdd, 0xa9f4ea70, 0xe7c39ba8, 0xfbe0cfe3, 0xe710196f, 0xcc0f8de9, + 0xdb94eef4, 0x9a7c8307, 0xc3d9dde9, 0x09adf0f9, 0x50afdd6c, 0xffa0253d, + 0xd5b291e6, 0xe3bb28ee, 0xefb75498, 0x1b372017, 0xad46df19, 0x7b38cca7, + 0x79f5c645, 0x0fed4b99, 0x1d210cf7, 0xbdfec026, 0xe9ef0fd5, 0x79f11ce3, + 0xe01261b4, 0x13cb14b9, 0xd86d32be, 0xfcfb48b0, 0x4224cf47, 0x046bb53c, + 0xa74b78c1, 0xc7ef08cb, 0xf3c22209, 0x62c3a731, 0xef5feda9, 0xd8d9ce83, + 0x47097986, 0x9af1e6be, 0xf1a5adaf, 0xbe4ff9e6, 0x9f7e11fe, 0x6e5cadca, + 0x36e1ff74, 0x5b5bb74e, 0xdcf3bed8, 0x0f48e575, 0x0720fdf3, 0x16497704, + 0x1c1bcaed, 0xcdfd00ad, 0x5da799f4, 0x6bf41c71, 0xfdc89d0c, 0x98bd2f9c, + 0x2f51534f, 0x4cc27c62, 0x9b870abf, 0x35abcde5, 0xea2d6fe8, 0xe55dcf41, + 0xafae7a60, 0x63cf31f3, 0x7a80934e, 0x82ff0ccf, 0x0f572b8d, 0x367f3020, + 0x8479d8bf, 0xe19ea206, 0x55e7d4f3, 0x473c3441, 0xd38fb31a, 0xce89397e, + 0x72d85cab, 0x2ec1e63b, 0x2c27f3a5, 0x1bf183de, 0x5e1d7e1d, 0xc44a3cf3, + 0xf106d90e, 0x068215d6, 0xdef636fa, 0x5ee18f16, 0xbb0d39a8, 0x8efd0207, + 0x21abed48, 0x2fc47bfe, 0xf5d6ffa0, 0xb445c101, 0xfb808d6b, 0xafd23d5e, + 0xf4ede585, 0x051ac74c, 0x58aa39ee, 0xe3a5c427, 0x6d42fa82, 0x59de9458, + 0x1b52b818, 0x88378066, 0x1a8b1c79, 0xa7cf0dca, 0xb8fa8c38, 0x35237937, + 0x74d2f3f1, 0x4de5d2f9, 0x870abf97, 0x52ffe2ca, 0x36565f60, 0xd107e9e8, + 0xf67aa0cf, 0xc38b076a, 0x7d23703c, 0x67a3e965, 0x79fc710c, 0xe67d19e3, + 0x79f1d389, 0xc503eb4f, 0xcedf4183, 0xedf51872, 0x3e8f9df7, 0xf42e5d0f, + 0xc2e599f9, 0xfe3d7f8c, 0x1983a665, 0xd81700ff, 0x1d5a07fb, 0x9004bb81, + 0xbfa70677, 0x76708ed5, 0x70691466, 0x7c00e59e, 0xd2dcf540, 0xfd631fcc, + 0xb96cb126, 0xee34fd03, 0xf3f16907, 0x0ff6c26d, 0xfec463b7, 0x1e301196, + 0xc8341311, 0x2cb3170b, 0xbce95b35, 0x1cb421c4, 0x9ac1e905, 0xeb9fe708, + 0xe1132f8a, 0x7e5a86de, 0xc2d6ba3e, 0xfde96dce, 0x75b071ad, 0x39772f49, + 0x683b56ca, 0x6b5f27ff, 0x78b0702b, 0x3819fa2f, 0x93ee114f, 0xd8317ea4, + 0xcc132fb3, 0x234bcd4f, 0x0ebe817b, 0xf20f19e2, 0x85238cfd, 0xfb655f9f, + 0x0b2ff46c, 0x796acd4a, 0xf908d55e, 0xa6077dfd, 0x5a703dc1, 0x6ccee592, + 0xf1c27f5a, 0x5967ab3a, 0xa9bb64ce, 0x8378edff, 0xce5a47d5, 0xa7f5a50c, + 0x3ab26f1c, 0x0551086c, 0xade3b4f3, 0x3051fe69, 0x3fdf9b8e, 0xf20919e0, + 0x5f985920, 0x3051ed2b, 0xa3efacfe, 0x2c06a2af, 0x00cfaff8, 0xba9f82ff, + 0x0e4fe8b2, 0x7915ef88, 0xbf1fd854, 0xfdb6821f, 0xe3a97bbe, 0xf0587455, + 0x01280a5e, 0x3e385bff, 0x2690ba75, 0x23c848cf, 0x48cf4124, 0xe5d877d8, + 0xdd0136f0, 0x5db40ff3, 0xf4d47206, 0xf00bdfc6, 0xac21ccfe, 0x28ca7c9f, + 0xc9e6df70, 0x8fad0617, 0xe5dbbfde, 0xf401dc28, 0x3b4064a1, 0xe4dd5041, + 0xd4176a66, 0xc95e3f52, 0x68c47f01, 0x7e713787, 0x6ca12d7b, 0xc0d9f237, + 0x8e1fd310, 0x8fd0bdb2, 0x2da4572e, 0xa77c4fa5, 0x4110aee4, 0x3564a63f, + 0x720b9c1f, 0x9cecdff8, 0x60f1e0ac, 0xf0e6dbfe, 0x3f6c20fd, 0xe9fb01dd, + 0x9235afa0, 0x71e74fe1, 0x238f1605, 0xfe510569, 0xfd079f05, 0x37dc2a7e, + 0xf6c1ce32, 0x44bce95b, 0x13461f58, 0x887ccb15, 0x6a00e413, 0x49df58bd, + 0x417f0782, 0xcec87ffb, 0x035b74fc, 0x2c5dc431, 0x5f7eb64e, 0x7dd992e8, + 0x5af0722d, 0xa709e3d0, 0x78f41b88, 0x848ae3d7, 0xfb9218f9, 0xb09fb847, + 0xde0042cf, 0x1b80e4a7, 0x17ddd9e2, 0x1206ea49, 0xd38bafe9, 0x21f7ef5b, + 0xe208bd45, 0xcc5ca31d, 0x90aa78be, 0xf768fe60, 0xfb002571, 0xb659294c, + 0xfabf689a, 0xef7b072b, 0xcfa2a4d6, 0xd6c11e81, 0x8fe30204, 0x440d45db, + 0x353f874a, 0x1f81d9e6, 0x288e0336, 0xeeac521e, 0x94bfa03b, 0x6cde1433, + 0xfc41ee7c, 0x24e8ea4a, 0x5789df8a, 0xbfb85539, 0xf07b29e1, 0x7b9fcc2a, + 0x24f782d6, 0x72b4566d, 0xad3e6fa8, 0xf35e21ba, 0x01307654, 0x05acf3e7, + 0xa139b3e7, 0x1465e2fb, 0x608d5fee, 0x20e4bf7e, 0xe4052d92, 0x83bd48a8, + 0x32704f3e, 0xc2cab87d, 0x938a68e4, 0x0243cfc9, 0xde0f3f1d, 0xd1f9442b, + 0xbaba1bf3, 0x7e8879d9, 0xc089b7d7, 0xbae509c7, 0xc1121e3f, 0x465c9e8f, + 0xec9cfd70, 0x3a2a0394, 0x1ce71e9f, 0x08cbff4a, 0xfb2e1f5b, 0x5fc63160, + 0x82de0529, 0xebd80bdf, 0xf052f7e4, 0x39cb987d, 0xed214c9f, 0x53e7ac22, + 0x442d11ce, 0x9cfcbbc7, 0x9f3d7714, 0x527dfbc6, 0x7d125220, 0x2aacf0af, + 0x1215df01, 0xad3b7ae3, 0xc438e4be, 0xa66d8b7b, 0x235eb0e7, 0xf4091e3c, + 0xb1b734d7, 0xaf93a47d, 0xe0c9834f, 0x3d1abce8, 0x1c4d3e6e, 0x0bda28f5, + 0x78068aa5, 0xbcf4e2d9, 0x7e44fb0b, 0x2f9e26ea, 0x8fa4f33e, 0x388d3fe5, + 0x72f18097, 0xe04e9fca, 0xebeb8b8b, 0xef3a76fc, 0xfeb1878b, 0xaf410f81, + 0x5a78f85c, 0xf7f9e82a, 0x4bd1beb9, 0xbf80ef9d, 0xbf8c49dc, 0xe44697dc, + 0xc49214b3, 0x0de446c6, 0xd9fa0ef8, 0x8a6e0729, 0xa92f7e7b, 0x0fd9d4a8, + 0x4ed041e6, 0x36d32fbe, 0x1f4ce41b, 0xe32701e7, 0x7ab9736b, 0x10ddb2e5, + 0xce7ff707, 0x03a98bd6, 0x5a1e61ce, 0x62488fd8, 0xd6ad567c, 0xf203375d, + 0xc6329c62, 0xf9f9d3bb, 0xc97e68ab, 0x9d17e28c, 0xcc9d3aef, 0xa7f9d68f, + 0x989bc778, 0x39fc5fdf, 0x126cee21, 0xfe7507b6, 0xf8cfccb9, 0x6cfdb2f0, + 0x7f8de89d, 0xa9eedd3c, 0xf8631ea0, 0x9be33f66, 0xf81fca22, 0xf03d10fb, + 0x966f998f, 0x5f37caf5, 0x967e0227, 0x779f16b7, 0x67d9a59f, 0x973393cc, + 0xf3f11c13, 0x624d9f28, 0xa943b1fc, 0xe82e51fb, 0x1a2dab8b, 0x15ca03e8, + 0x3e52d759, 0xdfa091df, 0x03935a7b, 0xd3122df5, 0xac5a5b3f, 0x38b67fa8, + 0x678c5ebd, 0x68f3b065, 0x43b6f244, 0xc036b41e, 0xf3df46a6, 0x8d93a57c, + 0x13439413, 0xf41d828e, 0xf1ff4617, 0x8dc1e757, 0x82b32430, 0x31cc61d1, + 0x0d98bd65, 0x8f853be9, 0x00bd7f00, 0x577e833a, 0x73c1587d, 0x2b0f4bfe, + 0xd85f17a8, 0xc4097af5, 0xcb7cf48d, 0x2f5f3b71, 0xef051a29, 0x9c7b3e33, + 0x8ebd63eb, 0x27a0e7a9, 0x4ea6f74d, 0x997f4c20, 0x032d3def, 0xb48dc9fe, + 0x9d03ef9b, 0xd61e4545, 0xb5db6b9d, 0xcc16a069, 0x0ace81f7, 0xfff6855d, + 0x699e83cc, 0x7dce352e, 0x6e1f9ca0, 0xc1db6d20, 0x4fdf3525, 0x6de7d749, + 0xaf93ff30, 0x2f881484, 0x919a9506, 0x9aeebeec, 0xba3fd01c, 0xc51fe1dc, + 0x11c3f05b, 0xbf68fb86, 0x5fbef3e4, 0x08bdd893, 0xbfee0aed, 0xefb09afc, + 0x7add7c82, 0xdde2c9d3, 0xbb9fcb79, 0x7e61f409, 0xb9f707a5, 0x9f98934a, + 0xb2121bfc, 0x34bd00e5, 0x41c8e309, 0x2a3e2d59, 0x5223de44, 0x0f3808d9, + 0x425fb3b5, 0xb9af8c3e, 0xc138efbc, 0xf7ba90ae, 0x26e377c3, 0xde83e5e6, + 0x955e8e76, 0x0e98eb0a, 0x74ab8537, 0x87023393, 0xbe5ed70e, 0x39ae68ce, + 0xe1fcc0ef, 0xcd43d03b, 0xe0d88e87, 0x820f9d7b, 0xfd18a7ad, 0xe801f8a3, + 0xe107e11f, 0x78eba836, 0x87e707f8, 0xfc6dff2f, 0xf159fd40, 0xfe00fc3c, + 0xe2f7e260, 0xe689ff87, 0xfdaf6a07, 0xaf6519d3, 0xa7961505, 0x3e75d7a5, + 0xc428e458, 0x608534f7, 0x65d905be, 0xe2dfbf67, 0xf038c64d, 0x46366ef3, + 0x064787d7, 0x76e22f83, 0xe37930a5, 0x0e8f5df7, 0x8e576809, 0x66e10aa6, + 0xa206e3b4, 0xbe38d43e, 0x804111c8, 0x1730ac7b, 0xcbec0b37, 0xc5c82a50, + 0x10f4eb68, 0xc756fff0, 0x1f605965, 0xe72639e6, 0x1f6d7f00, 0x5815fcb1, + 0xa80fb6b2, 0x1aa37e7c, 0xbd749fb1, 0xab7797b7, 0xc5c43f8f, 0x0f72e1f8, + 0x7a014f3b, 0x5d0e1a3b, 0x005903ff, 0xcb34210e, 0xf5038df2, 0xe83b4b75, + 0xe2838073, 0x9a40b775, 0xb4283ec0, 0xc18ad278, 0x9217ebce, 0xd6aece00, + 0xbc43072f, 0x9fcb7a68, 0xd3bc020f, 0xcd267df5, 0xb664cfb8, 0x477b75a3, + 0x7b742bf7, 0xd088a248, 0xb76826ed, 0xb86ee7f0, 0xafd61b1f, 0x71cf0d90, + 0xbd5a743e, 0x57e5c3c8, 0xce98f3a2, 0x690d71e7, 0xd7c8b843, 0x99337cdf, + 0xc70667d2, 0x24fdf4c7, 0xed0b9094, 0xf14d5c84, 0xfc44b570, 0xab9c7449, + 0x1c7c8135, 0x8cd727c5, 0xefe1d637, 0x3f48f4b2, 0x5e6fbdbd, 0xe299261f, + 0xdcb7dff1, 0xabe763ef, 0xe763eaff, 0x150e2767, 0xa82c12fd, 0xb9d933e3, + 0xc3c33759, 0x7afe257e, 0xc98b88f5, 0x7b4b44f1, 0xdc1b9c2e, 0x5c2bf3bd, + 0xfcecf71f, 0x13b01dea, 0x08971c27, 0x3c4e01e4, 0xf709263e, 0xe067c73d, + 0x6fde9d3e, 0x0e4da7f5, 0xff239ec2, 0xef82f7e8, 0x1478f0a3, 0xe586cf80, + 0x3d0f1d8b, 0x3d9dfd0c, 0x3ce8912c, 0x3bc512f3, 0x2569e20c, 0x7df87efc, + 0xf497b302, 0x5efc7df6, 0x5972ffe6, 0x9b6b7ef8, 0x625efdc4, 0xd5f3a28d, + 0xe524f354, 0xf57ae845, 0x52e3d2b1, 0xe07d2c6e, 0x0f9d63ef, 0xdc6793cf, + 0x579fa95b, 0x23f8e3ae, 0xf3c3df7b, 0xdd345700, 0x7e7d8121, 0x3c488645, + 0xa95ee351, 0x2a3e0f52, 0x8b8f71ee, 0x76eae5e7, 0x1fa7deca, 0xf706919e, + 0x7a988859, 0xe5b2dd55, 0xb7a85c95, 0x71cf7189, 0x457bf19b, 0xf0121dcb, + 0x262e17ff, 0x3f8dbd1f, 0x27ca62f1, 0x09dd0297, 0x040af3b3, 0x7d332394, + 0x7dfcecf7, 0x9ea8fb6a, 0xfd13ddf1, 0xb17874cd, 0x2ff708a3, 0x9987a37a, + 0x79d1776f, 0x42fce9fa, 0x6a7e9e74, 0xb9f1ed8f, 0x2f92feb1, 0xbf3aeb03, + 0x913eb756, 0xce9cf60a, 0x1952d3a7, 0xf1d84cdf, 0x46712a70, 0xdbc665e8, + 0x66fd395f, 0x0ce66d11, 0x826dcffa, 0xe17d42e6, 0xcf906d27, 0x9c61c652, + 0xda0956f5, 0xcfe7841f, 0x59b1d79b, 0xd7bc28e2, 0xd97bd7ba, 0xa0ca1587, + 0x15ebcd6e, 0x7c0e17dc, 0x4aa75e6d, 0x7049d40f, 0xb48958ad, 0x6e31e99c, + 0x9970eba7, 0x2936fce9, 0x04f479c3, 0xcc0f99a7, 0xb9f6eaf0, 0xc5394f7e, + 0xda14b4c7, 0x216ab5df, 0x1d662fce, 0x69e978e6, 0x5e69edfd, 0x7ffc4d47, + 0xd7d4d8e6, 0xc93dbd00, 0xe66e999b, 0x947f5d76, 0x587900c0, 0xf91ec1fa, + 0xf48e95c2, 0x10a7392d, 0x0f1bec0f, 0xa24f93b4, 0x7d3221d6, 0x9ddbf208, + 0x27acf66e, 0xce7a5b7e, 0x11a9bc42, 0x1f9b93be, 0xeddf0074, 0xb01cea90, + 0x59c533af, 0xf1449b5e, 0xa2d3f535, 0x74bcf1eb, 0xc84085bb, 0xa9cb5a6c, + 0xa84710bd, 0x9f30483e, 0x7765a8ba, 0x4be9f031, 0x51fa1b52, 0x7909675d, + 0x6cceca30, 0x8075a96e, 0xc69cd61d, 0x4bed03ce, 0xcdbc8626, 0xbf191247, + 0x3d3e1f36, 0xfda713c3, 0x8ebf6f00, 0x7172d278, 0xfc61765d, 0x058d64a3, + 0xd0553fe7, 0xbb034e5e, 0x0f7646e5, 0xb8eb5763, 0xbc28d397, 0xa324b79d, + 0x7cd6999e, 0x4a6e1dcf, 0xf33fe088, 0x1cf779f1, 0xdf40db41, 0xac35512b, + 0xe3645497, 0x7fb8f8be, 0x1d375ea5, 0xd194afda, 0x2e2699bf, 0x751e2096, + 0x03c84332, 0xd0a7717f, 0xa77e12be, 0xc6ce5fcd, 0x2a7f6e21, 0x4c6f9ff8, + 0xbf8d1d4f, 0xf5eaa26d, 0x6bf7f00b, 0x5b4fc988, 0x6eccedbe, 0x3e5f6d2b, + 0xc77cc053, 0xe22cee69, 0x929fe28f, 0xf99e9435, 0xfa5b2f94, 0x5f5f0117, + 0x673c6a57, 0x41ccb335, 0x63f1d102, 0xc2c32dc1, 0xb5e78fb3, 0x7efc0b76, + 0x57e72e59, 0x359f7e71, 0x5df0d53b, 0x66766139, 0xdd9136f5, 0x7ec85257, + 0xaf975127, 0xbc39711f, 0x37c7fb8a, 0x700cb37a, 0x0d28874c, 0x693334fd, + 0xd75dda28, 0xe5c76d9c, 0xe0fc5cb9, 0x78e89bad, 0xf2611a3f, 0xabc5c56b, + 0xd8322f90, 0xc84cca7e, 0x6f41122e, 0x66bbdf1a, 0x471eb1bc, 0x27abcf8e, + 0xb3307d74, 0x9bfdc455, 0xcf148599, 0xd3b18902, 0x18beadbf, 0x865ed167, + 0xe7b5d078, 0x04bbf83c, 0x83e2fa31, 0x2fa4efd2, 0x3832a05e, 0xd2f5ca9e, + 0x0fdfee44, 0x6f408322, 0x1f1b134c, 0xa2ea3e06, 0x0e35a6eb, 0x8eebe91f, + 0x5097efee, 0x21be0639, 0x8f18691d, 0x032e769d, 0x7f7449f3, 0xa847ac3f, + 0xb1c5a25d, 0xcc4bee97, 0x1307dc31, 0x76512bd6, 0xfdf05c89, 0xd46992ed, + 0x00f2551e, 0x9fc481be, 0xe30cfa8f, 0x70902592, 0x8cc1f102, 0xa9e71853, + 0x8affa896, 0x4c13f3eb, 0x097fd1cf, 0x30f91129, 0x9c7a2bdb, 0xdba49ad9, + 0x093e4653, 0x97af1bc7, 0xf3a3ee31, 0x13e00949, 0x117affe4, 0xf1bd3ae3, + 0x6f7e3e8d, 0xfaa212fc, 0x0f384928, 0xfbf970bf, 0xbcf2fcb6, 0xc8c327ce, + 0x89f0beb0, 0xbf3a1fce, 0xa609d8c4, 0xeb4f5078, 0xe9894bcd, 0xd69edf88, + 0xc847979b, 0xb37bd7a8, 0x3126766b, 0x744aee3d, 0x5d577f63, 0x7609d334, + 0x11eb958d, 0xc70add7d, 0x9f19eab5, 0x573edcbc, 0x6aa3fd82, 0x11d91fd0, + 0x60f1e83a, 0xae972f9d, 0x9cff1821, 0x6756f5ce, 0x56078b2b, 0x7003154f, + 0xe5b8a284, 0x9d5987c1, 0xd3a2cbdd, 0x27ce6af7, 0x096ed285, 0x1af3777e, + 0xbe20d04d, 0xc4f1e1e4, 0x8094e719, 0xafab1d9a, 0xc75fba74, 0x0bbf07bf, + 0x23c6bfde, 0x1c4ba804, 0x3baecfa3, 0x188aecc7, 0xcfbc2a7b, 0x891e62ab, + 0xeb4e5f99, 0x86421f74, 0x0aed3bfc, 0x76fce921, 0x6f7dfe85, 0x1e064e74, + 0x65ee7a06, 0x1d80aef7, 0xe2be740f, 0x3afd849c, 0xccf18c93, 0xbf791db3, + 0xbf93df41, 0xcdafbe6f, 0xc6de9f3c, 0x17f746ff, 0x8fa0ffb8, 0xcec4957b, + 0x27d79bc7, 0xd75e9c7d, 0x99bdfe23, 0xe293c37e, 0x3eba7ddb, 0xd73fc18e, + 0xafd13dd7, 0xebad7d37, 0xbeb77fc5, 0xd7d7fbd6, 0xb35c7d13, 0x8fc9ef1e, + 0xeaf2f5d4, 0xdf8c16f5, 0xfafee14c, 0x9e2f1e14, 0x6ce2c499, 0xeedeb8b3, + 0x0166dcfa, 0xb3282ebb, 0x6eff30fd, 0x36a1c627, 0xd0f662ef, 0x724e3c9b, + 0x9c6220b7, 0x16b1eee4, 0x17d4dbd4, 0x4b7987ca, 0x808c8445, 0x2c01dcfd, + 0x8528df4e, 0x6bef50ca, 0x6f738112, 0xefdfeaaf, 0xfd04dff1, 0x70f1fddf, + 0xa3c62d4b, 0xc7e06d43, 0x7093cb8f, 0xaad92c5f, 0xb3bafc62, 0x03f78ad5, + 0xd9f8ed75, 0xf9fa196e, 0x5ae0689c, 0x0d6ad4be, 0x1e814bef, 0x101e2699, + 0xaba33f21, 0x59fde09b, 0x8a876793, 0x429b3fc1, 0x0e216ada, 0xf9615130, + 0x3d3c66e8, 0xcc31f7ca, 0x7de114fb, 0x9f665689, 0x7644bb15, 0xfb4f580f, + 0xe60acd12, 0x2fb6f757, 0xa0967851, 0x2fb3169d, 0xd2f4ccd1, 0x9897ddb7, + 0xdf87b808, 0x9ff9d367, 0xc3d227eb, 0x8566c4fe, 0xbf7567ed, 0xbfb0132e, + 0xb8b4b1c9, 0xf6dea371, 0x4aec7629, 0x1d3dc0f0, 0x4deff99b, 0xc035d8ec, + 0xfcf6e6a3, 0x777b6e7e, 0xcda4a811, 0x984ad78d, 0xb9e3c6f7, 0x19a0b8e1, + 0x66ff1caf, 0xc8156e7c, 0x07c4072a, 0xe0a9b45b, 0xbfb8f517, 0x71c1edd3, + 0x5d478afa, 0x491f364e, 0x6f9f00f0, 0x03c0323e, 0xfc003fe3, 0xab59710a, + 0x93f015fb, 0x9d3e1c77, 0x8abcfb80, 0xa4bf0547, 0xb1a6d93b, 0xef8c8973, + 0x03c39983, 0x9abd0fb0, 0x84e6f9f3, 0x4c8ebfee, 0x61afde8b, 0x39fa33fb, + 0x60855aff, 0xc2df883e, 0x78cc41f2, 0xeb66e41b, 0xebc4e6b5, 0xa69c89c3, + 0x35f2f18a, 0x7f9662b5, 0x807e7e60, 0xf03977f3, 0x7147ed01, 0x8956b833, + 0xaeff8465, 0xcef58128, 0xbfe5af5c, 0xc67b4387, 0x1cd565df, 0xed2a3396, + 0x67d278e3, 0x40efc057, 0x3b96f96b, 0x2f70dc73, 0xf2ca5083, 0xb2f92c3c, + 0xc493c846, 0xd6953a52, 0x0ecb922b, 0xb883f526, 0xe40d73b1, 0x479e4333, + 0x2f445a5e, 0x0ad747dc, 0x2e245e5b, 0xbf12b0eb, 0x3d70ec1d, 0x79e79fcf, + 0xfbebb52c, 0x3eecedd1, 0x86fe8aea, 0x850e4e73, 0xbfbf477e, 0x9a3deade, + 0xa14cf984, 0x7dd29544, 0x78698ef9, 0x76e2907f, 0x3e477ce3, 0xf803293f, + 0xd9f5c281, 0xff5c31ff, 0xc82e0f1b, 0x3a71816f, 0x062c8eb6, 0x087231fd, + 0xd08b599c, 0x7c41aa87, 0xbc120f6e, 0x01fff12f, 0x512809c2, 0x00008000, + 0x00088b1f, 0x00000000, 0x5bb5ff00, 0xd554740d, 0x79bfff9d, 0xbe4cdef3, + 0x21264cdf, 0x012f0842, 0x1c424242, 0x61f08062, 0xc4443e1d, 0x602a0320, + 0x43e196eb, 0x9a1af909, 0x7ab76eba, 0x2904930e, 0xb693db02, 0xb654e56e, + 0x28bb560e, 0x82609d89, 0x04ec2681, 0x6eb50314, 0x5b604040, 0x6a445477, + 0xbb8d3243, 0xb29eec54, 0xf7bdffff, 0x60c33325, 0x392dd9e9, 0xddf73739, + 0x7ffdeefb, 0xf75ffefc, 0x595c003e, 0xc9a00392, 0xe7b73aa6, 0x001aa802, + 0x6dbcdc64, 0xa0556052, 0x324e4018, 0x63240a6d, 0xd4da669b, 0x668a6d86, + 0x9aa9e362, 0x70805ace, 0x6c14b2ce, 0xf2ce70b4, 0xc6efbc29, 0xc34b9656, + 0xfdec32c1, 0x45f38a5d, 0xe1d90a9c, 0xfec49e0f, 0x39148ffb, 0x42ff63b7, + 0xa4096a62, 0xe7f2ac01, 0x3fb08535, 0x1b1fe2d5, 0x69ceba44, 0x1a6d2c9e, + 0xfe2dd7c0, 0x7be32089, 0x68529bc9, 0xf005c97d, 0xbab63b1d, 0x22948f06, + 0xd5d02e7d, 0x60a300f1, 0x08a976b7, 0xeb82a900, 0x05f6f1e9, 0x58074c2b, + 0x8eff1339, 0xf19217d8, 0x53d22679, 0x741b9fce, 0xb405fee0, 0x30cf41bf, + 0x5dad901d, 0xeff6024a, 0x96eff63a, 0x8fb81851, 0xdf9313f7, 0xbf8b6122, + 0xa2fd7fd4, 0xbfc3efc9, 0xdb9f6807, 0x792bb669, 0xc43674cd, 0xebf999f6, + 0xeb119946, 0x3e7c1fc3, 0x65092f8d, 0x9015d59d, 0xf33efd8a, 0xd8ab2147, + 0xf4677f07, 0xe327e67a, 0x45ce337b, 0x8175c73f, 0xd62d9fe8, 0x0cbf072d, + 0xa1998f28, 0x61b379e8, 0x5c641fe7, 0xe8e5f677, 0x14b40be7, 0x3467e307, + 0xf8cebe8c, 0xbd70aa43, 0x6f5f2b7a, 0x34bc9de8, 0xcd9bfd40, 0xbb945328, + 0x8e50cbaa, 0x77fa75ed, 0x66fb4017, 0x700f979c, 0xb595b360, 0xeb6b4e53, + 0xcdcefe88, 0xe0152008, 0xd62ce6d0, 0x98c69aaa, 0x561a729c, 0x3ec44943, + 0x90c7df1a, 0x2e39d0e3, 0x82a1a9c7, 0x5f60e6e7, 0xafc055e9, 0x4b39f08f, + 0xb80869c8, 0x9534879c, 0xf1fa79c9, 0xc411dd9f, 0x132c9647, 0x25fc11e8, + 0x17a089e8, 0x0a93f48c, 0xd97d51ec, 0xd5cf8fd0, 0xdfeb8597, 0x714fd621, + 0x075a8e8e, 0xa113f8fc, 0x85f643bf, 0x71f212bd, 0x05657247, 0x9e5693f1, + 0xd96eb517, 0x427ab13b, 0xd3cbe1c1, 0x209fc890, 0xc69fa69e, 0x33f988f1, + 0x00923e1c, 0xfa26ff94, 0x4cb34039, 0x62eb3476, 0x6f27f3f4, 0xc99bb7a6, + 0x9b9e4a13, 0xe5ebf8e3, 0xcb457369, 0xb4517d33, 0xd1dc333c, 0x2ab51cf2, + 0x79b76e5a, 0xa632e5a2, 0xf8d47272, 0x51a54dd8, 0x99df71fd, 0xd73f3515, + 0x3faa2f37, 0xa8e2db7e, 0x979b13f9, 0xed27f547, 0xfcd47afa, 0xa8daff42, + 0x55bda2f1, 0x29ffa4b7, 0x79a8fa81, 0x57d35e24, 0xcef6ffe8, 0xf3ed46ef, + 0x2fffd6b7, 0x9c7ff463, 0xd234d97c, 0xf447fa17, 0xf24a838b, 0xd99f0936, + 0x93f25690, 0xafb7aeb6, 0xbe976849, 0xe88fba79, 0x67062df0, 0x2b3d8e13, + 0x6bf225bb, 0x26d45063, 0x4c5b1bf4, 0xfefe4950, 0x6ad326fb, 0x9d88f277, + 0xb624d71f, 0x982af3fe, 0xf3d1ec13, 0xcc8f1796, 0x14d3da33, 0xf88da61f, + 0xf45bafd9, 0x3df210a6, 0x147ee655, 0xf269ebfd, 0xa7a417af, 0x8a997214, + 0x8a78a7c3, 0xed59bc59, 0x0e06d6c6, 0xb4db1ea9, 0x5faebf11, 0x505ce547, + 0x98ff2ffd, 0x3b213fe8, 0xdffa465f, 0x86dc8125, 0x89bb56bf, 0xc361f3ec, + 0x9a7ae96f, 0x21ae822d, 0x048fa5e4, 0xd0d3d66c, 0xfad0c3e7, 0x9dafccf1, + 0x4805a6ff, 0xce55e7ff, 0xb2ff318f, 0x099f6bf0, 0xfe4fd6bf, 0xbc647f2c, + 0x528fcf72, 0x7ce75c74, 0x440a2c01, 0xe42c29c8, 0x58d06604, 0x75cd99bc, + 0x876aa176, 0xbfae18f2, 0x44d87df2, 0x13fcacfb, 0xef7c8a6c, 0xdec29acf, + 0xb326b3fb, 0x59360576, 0x1815e728, 0xaca56ccb, 0x5db0941f, 0xe40a0bda, + 0xe4f32c01, 0xf794242a, 0x03a679c0, 0xa292b4b7, 0xc107bdf1, 0x3fff90ad, + 0x14dacdfb, 0xcebc379a, 0x4fdd4fdb, 0x8a815d38, 0x7dff61b6, 0x44c94f9b, + 0x53be107f, 0xf711f162, 0xf773d2b1, 0xa69e6323, 0x3c167338, 0xbea0ce57, + 0xad938396, 0x600bac67, 0x1733f28f, 0xe3a60854, 0x160bbe3a, 0x4748cbff, + 0x4561b23d, 0x8f77d4fd, 0xb0647e62, 0x3fad8fea, 0xc7ab79c6, 0x9c52c684, + 0xa7f550be, 0xc3f3d27c, 0x20afd0bb, 0x3d124b6f, 0x118cb619, 0xff5f9c39, + 0x638d0a79, 0x867a65bc, 0xcbe7167d, 0xd8fb7e4c, 0x71bcc67b, 0x6da3b9b6, + 0x5c72e724, 0xf88de664, 0xb00a5a33, 0xa9549f94, 0x177e9ffe, 0x0a1384e9, + 0xcbc0cf5b, 0xfa978146, 0x24547d5c, 0x8653ea5e, 0xf08a32f1, 0xccb2ff52, + 0x3bbea6ec, 0x97280fc1, 0xde770233, 0xfb5ed77d, 0x9e1d4eae, 0xb88c7cef, + 0x9f2711d1, 0x8c746e20, 0x6e229f7b, 0xd90dffa8, 0xfde8953d, 0xa9c7e778, + 0xc1f75a1e, 0x507ba35b, 0x06fd9f0a, 0xc738f7c9, 0x9d0c10fb, 0xbdba7e65, + 0x1d21f750, 0x3b5c0ff3, 0x5d5cf94b, 0x60b745bb, 0x742d8aff, 0x7f9a79ec, + 0x5f9a0250, 0x4e604c17, 0xf25daeab, 0x5578e027, 0x31d6db67, 0x596aafd8, + 0xc3614656, 0xbbc10a9b, 0xe4bf7c68, 0x4bf1c46f, 0x1725839b, 0x87bae027, + 0x75a25dae, 0x75f10e07, 0xe60e6f2f, 0xb0300e53, 0xb407cd7f, 0x05bb4d5e, + 0xb1bf2812, 0xb431d505, 0xa0149b5f, 0x3f032afd, 0xcafd6950, 0xa04d9697, + 0x6f7aa6f4, 0x1109c4cf, 0xc0e06b7e, 0x39475549, 0x60ffb655, 0xc65798a1, + 0xe19f97c3, 0xa37fe0d7, 0x1cdf27bf, 0x6ff13fe9, 0xf093d91f, 0xf216bfbf, + 0xbe35d55f, 0x7e89c489, 0x8979e3a5, 0x84d595f9, 0x5b870ba7, 0xda4bfb7f, + 0x4ebfe0ef, 0xd940dc24, 0xdc1bc9ad, 0xeb17163e, 0xf9703ec4, 0x429dd53d, + 0x452e53f2, 0xff3e73fb, 0x435dcd90, 0x2a9861fb, 0xc48444d8, 0xd0db87e4, + 0x93e4801e, 0x43ecc89b, 0x6bab0e4e, 0xd1ef9e90, 0xacc7a404, 0xd8b5d585, + 0xf31766df, 0x97feacf2, 0xafa46f73, 0xf26666c3, 0x2781e6b1, 0xed186fd2, + 0x3a471a7e, 0xa67de68e, 0x4ebc7086, 0x6e12acbf, 0x53bf82eb, 0xdbdfa475, + 0x5742e1f9, 0x3602f79c, 0x9314afee, 0xd94f72bb, 0x4bd47d88, 0xf089218d, + 0xce92707e, 0x2f9b58f2, 0x48ebe8c4, 0xf98f89d0, 0x3d377e07, 0xefdeb114, + 0x26131f11, 0x7eebf48c, 0x428961f1, 0xc3fd7b72, 0xc8ca7312, 0xe4cc81f3, + 0x3a5c7f4a, 0x3a78bc78, 0xf6997dd5, 0xd1603dad, 0x13be191b, 0x77c2419c, + 0x3d139257, 0x6d5be135, 0xf7c48b2c, 0xbaee8cc3, 0x4889d92e, 0x65ceba87, + 0x3f36069e, 0x906a49c5, 0x08fae73b, 0x66e6b267, 0xc1ff8478, 0xa54710fd, + 0xa3fa37f4, 0xcfcf3695, 0xe4e67f49, 0xbc48c4e0, 0x394299d5, 0xcfe9128d, + 0xc2373cd3, 0x9f64e4fe, 0x7920e8de, 0x7d653ba6, 0x898a7f44, 0x0f4065eb, + 0x8e29daa5, 0x50f5c66d, 0xdfc1031e, 0xb7fc92a5, 0x92b3ae76, 0xa6c77fdd, + 0x55593d31, 0xff61ae9f, 0xbe47d4db, 0x4aeea9b7, 0x996dabb2, 0x0d764089, + 0xef8676d9, 0x01d784bf, 0xbd5457b2, 0xb8a01e02, 0x36f0203a, 0xff981630, + 0x708fdca5, 0x37be5326, 0xa3c8cc9e, 0x676f3cd1, 0x08c5c94f, 0xae0e077e, + 0x4a7d1274, 0x321f7f22, 0xf7635e39, 0xc3814ffd, 0x9b6b4da7, 0xe1c446e7, + 0x15bf79d8, 0x00e43478, 0xab165f66, 0x8cf13107, 0xdb3adf87, 0x1fe433bc, + 0x0bbbb69f, 0x899b0fc8, 0xaea3c230, 0xe703a5c6, 0xcde907ff, 0xc85c7f98, + 0x1a3c5555, 0x214df5c9, 0x33754557, 0xeb61a339, 0xfcc3c764, 0xed71a9e5, + 0xdfc10bec, 0xbd68dcb6, 0x2abbcec7, 0xbe4c53f8, 0xe744b5ac, 0xcdd99961, + 0xfa661ea0, 0x060de637, 0x77fd71af, 0x8bbf7e7d, 0x05773cec, 0xaf67e7c3, + 0x11ca9614, 0xcdb38eeb, 0xffe22ffb, 0x8a0f0313, 0x0ee88b2f, 0xdeb1f0c5, + 0xf892fee6, 0xc83bf236, 0x4e12dc76, 0x4e07d440, 0x3eb0ef11, 0xabe33028, + 0x24e89083, 0xf226deff, 0x19b83360, 0xa9c0924e, 0x05d77ab3, 0xfc8d9abf, + 0x6098f535, 0x9b53763b, 0x8139ca24, 0x9ccd608d, 0x228c9b2a, 0x52c565c2, + 0x0c8c88af, 0xf6ed53c7, 0xbd20b77b, 0xf327c107, 0xfeba39ba, 0x92e49705, + 0x37deeb22, 0xbdd7e2ab, 0x644d3dbb, 0xeea97fd7, 0xad34199d, 0xfafed351, + 0x1d8277fa, 0x1822e8f3, 0xdb27a3ce, 0xa0544675, 0x102fe380, 0x7b33f44c, + 0xf09f54c4, 0x1a7e4fdb, 0x922bf9e5, 0xa553ce29, 0x0dab0281, 0x78eec4a0, + 0xda365b66, 0x3fce04d7, 0xefe89bf5, 0x0c679e5e, 0x4e6fd3d7, 0xfa277966, + 0x93d59921, 0x4625a09a, 0x1f98656f, 0xd88d3a41, 0xe0f1eaa3, 0xc9532fb1, + 0xf5dab6ef, 0x84bd277f, 0xf940cb8f, 0xa439825b, 0xd5d8e2da, 0x3163ca01, + 0xcedc790f, 0x9dac6bcf, 0xfb8fcb92, 0x5017755b, 0xb4d04f7c, 0x7d8472a9, + 0x3625d815, 0x85d8f6af, 0xc7f3151c, 0x5277a62b, 0x9afd718b, 0x74a9fd8e, + 0xfe7d53ac, 0xed4a74d4, 0x0a9ecd8b, 0x4cfbce3b, 0xa56f93da, 0xbf9b70bc, + 0x0813e484, 0xbc51a5e6, 0x9f06629d, 0x7a46f4b9, 0x594abbbc, 0xcbb75591, + 0x5d29dace, 0xbca06c77, 0xfce41bd4, 0x0e0a1ed2, 0xeb027615, 0xd936740f, + 0xbfef3d69, 0xff268f75, 0x56032fb4, 0xf578ff91, 0x7dfcc98b, 0xfe699833, + 0xe04dbb1a, 0xf3a26fdc, 0xdce27da7, 0x130be06a, 0x3fec679b, 0xacae73a5, + 0x838a0e21, 0x0fc847cd, 0x58597424, 0x12f0951e, 0x61747970, 0x38e7477e, + 0x8a01ef87, 0x70368343, 0x9ade384a, 0x4f796618, 0xbfa2dbb8, 0x9adc9128, + 0x55bcec81, 0x214af5e5, 0xf27f7202, 0xbf6373c8, 0xe8e7ae84, 0xe170898c, + 0x6097b8a2, 0x933b866e, 0xc29de523, 0x73b46ee8, 0x0626b53c, 0x9794c94d, + 0x9178044f, 0x274235d1, 0x3a0d7db0, 0x6f7f990b, 0x9e97c355, 0x34ba3074, + 0x702141c2, 0x926ba13a, 0x412dfe4e, 0x123e3173, 0x93e9dd34, 0x5bcba46e, + 0xda178982, 0x611bf7cd, 0xaec98ed8, 0x7d2389bd, 0x6b42da2b, 0xf835c71e, + 0x20b33e16, 0x0e4fa23b, 0xfde47ca6, 0x3ef7ece7, 0x9d9b25b3, 0x5464f917, + 0x29b61275, 0x6753e276, 0x74d7a27c, 0x39729465, 0x494e5138, 0x3c3e3e56, + 0x4c9e711f, 0xcf3e64fd, 0x1692d169, 0x017b32e7, 0x2f2317b2, 0x5e0a5c7b, + 0xb5ed0bba, 0xb4ee07ff, 0xdfabe462, 0x1689e474, 0x35fbf79c, 0xf620fc81, + 0x179ea94f, 0xfc6f9f09, 0x298eed66, 0x155b6fe4, 0x9df90567, 0x2c87ef90, + 0xd1557dff, 0x1dd847b7, 0x09338764, 0x78fbb1bf, 0x90fe37cf, 0x83c1dbf2, + 0xc9d56e92, 0x887386ef, 0x4faebaee, 0xdee7f255, 0x7cb21f83, 0xe7ba6e76, + 0xafea3b35, 0x3e61b3bc, 0x342675c9, 0x2ebf9137, 0x20417912, 0xa193fb8b, + 0x362ff9d3, 0xb4e1e844, 0x7b0837b0, 0xea7c51c6, 0x987af612, 0x3b6c4eea, + 0x4f1e1e7a, 0xba8877eb, 0x01af78d8, 0xb9218c8e, 0xac9bc237, 0x7e378e1d, + 0x59c222f3, 0x6aeb59d1, 0x77fcc457, 0x7abf3ced, 0xbdf3ced7, 0x379ee9f5, + 0x3dd53e49, 0xc4a9a91f, 0x0e40c5e7, 0xac0193d5, 0x7e38b58f, 0x637ed864, + 0x0e6bc9ec, 0x7bdf34ab, 0x415f9819, 0x43496f7d, 0xdb3bedfd, 0x3e0d7939, + 0xa49d40ef, 0x9e709e51, 0x8a1d87d7, 0x6fcd0c7b, 0x84b57338, 0x2201d8fc, + 0xdab9e902, 0xe48e3d5d, 0x979ff886, 0x06d67648, 0x7619afcc, 0x8a764c5a, + 0xfe1317ef, 0xc85fa8cb, 0xdaab72fc, 0x65d998b7, 0x2ec80987, 0x1eccff11, + 0xc51aff10, 0xed0d62e3, 0x893fbd81, 0x9f6b79d9, 0x58f2c5c9, 0x5913ebf4, + 0xd403de7f, 0xa05bed6f, 0x21373b31, 0x5ec94b9e, 0x3ad84783, 0xa4898001, + 0x91dc093a, 0xf60503e7, 0xc337a654, 0xf6174e5f, 0xd3d0281b, 0x9247c89c, + 0x47d9472c, 0x7de49c44, 0x3f5d4711, 0x9e67c7fa, 0xfb4f839d, 0x44d09c44, + 0xfdc73c7c, 0xac45b7fe, 0xd66b7faa, 0xc7ca16d2, 0xf1b32d7f, 0x227ce2c3, + 0x44727028, 0xdc504f9c, 0x6f3f51d0, 0x69d7738a, 0x1fa177d8, 0x34daee9d, + 0xf2aa729f, 0xa947cd45, 0xcc0ee59d, 0xce7154a7, 0x0aa3beaa, 0xc222f337, + 0x7b91fb5f, 0xf7e4cc8b, 0xaefaf3ce, 0x07f0cbfd, 0x9e1ca2af, 0x8ff28c38, + 0x1d90a713, 0xafcc3f86, 0x8dd640c6, 0xe19283e3, 0x4bde7647, 0x97681c78, + 0x4848fa47, 0xfa9b021d, 0x9fdbe919, 0x9fdf61f1, 0x474acaee, 0x78711e79, + 0x9e51d2b2, 0xccbf2783, 0x38ecb324, 0x9bab11fd, 0x115755db, 0x0f3da7e1, + 0x3838cd4b, 0x73f3a735, 0xf44b3294, 0xced18af9, 0x3071e74e, 0x243b07df, + 0x9acb1756, 0x76e6ea9f, 0xfe62a5d9, 0x2b7c1973, 0x11bf9366, 0x828f81e7, + 0x1fc2e7f8, 0xa263cfd4, 0x2be528fb, 0x7b1eb718, 0xaf398956, 0x3c2264db, + 0xe092e86d, 0xe57bc827, 0x1771d8ee, 0xc46a5bcb, 0xf73b1b3a, 0xfa831b1c, + 0x7a297aac, 0x2be50d5e, 0xc03c9cec, 0x169acfea, 0x499f3a25, 0x78cb7917, + 0x0b794f18, 0x07f989e2, 0x16bd0cc5, 0x8745efc4, 0x6b4c90a7, 0x09cb899f, + 0xcbb32afd, 0xb4bf9142, 0x28fee3ce, 0xccfc057c, 0x8e06f66e, 0xb3dd22a6, + 0xb49d725a, 0x1f332cc7, 0xcb99d59f, 0xfd980ce2, 0x445432f2, 0x90b3cbb9, + 0xd73ed3e5, 0x47942ce9, 0xa093f0a5, 0x8daef3f1, 0x914aaf82, 0x47f46dcf, + 0xfc133dd3, 0x86cfb44d, 0xa83392bd, 0x1280f9d3, 0x8af3af37, 0x9d766a75, + 0x7bc7463c, 0x79e881b5, 0x6f1f215e, 0xfdf3f467, 0xd58136c0, 0x347ce2e9, + 0xf9d87207, 0xd5adef78, 0x7857bf53, 0xac4a717e, 0x166f8c63, 0xf243a9b8, + 0x7e35bf48, 0xa9b84fd9, 0x3ca97c94, 0x35e485bf, 0x033af748, 0xa0fe3a2f, + 0xf90bd63c, 0x617813ac, 0xb5fbe17c, 0xdd3f25bb, 0x19dfad2b, 0x81a3ff4d, + 0x0f090b35, 0x6caab8b1, 0x5b7e5851, 0xca549b05, 0x5571636f, 0x66978c35, + 0x2c58e295, 0xd23cea9e, 0x79e6e84d, 0xee95fff9, 0xcec8256a, 0x59ffaa7d, + 0xfe88fa72, 0x74a96ff6, 0x7da378fe, 0x1956fd70, 0xfd7c1138, 0x6f3cfcb5, + 0x4c327fe0, 0x945dfa66, 0x50758b7e, 0xa6dd3e74, 0x3218fb72, 0x0362f3f3, + 0x2fefb13f, 0x3df8f914, 0x57b580bb, 0xa54f3f3a, 0xbec1dff3, 0xad6054a1, + 0x3fc51169, 0xf0884fea, 0x79d2fb3b, 0xeb35b89d, 0xbe53efe3, 0xe29b4f7e, + 0x6a0e4cc4, 0x8a6e2ac6, 0xdf6335d3, 0x11109cca, 0x79d2da57, 0xdb4f79fd, + 0x74098da3, 0xe48af0ce, 0xec1bf324, 0xd423fbfa, 0xce48b5f7, 0xb1fef889, + 0x6777a1be, 0x92b23e93, 0xde7ad3a6, 0x5a8bbbee, 0xc5ec7fb1, 0x75919c3b, + 0xe73b31e5, 0x0ab19eef, 0xa3fd9b8b, 0x41567e93, 0x3dae80e7, 0x0ffb8ecc, + 0x9d92aebd, 0x904ab60f, 0xcb1d1b85, 0x8f9afa3a, 0x27039cea, 0xe7c64a55, + 0x43549fb7, 0x5c0f915f, 0xc82b72c1, 0x559b49ce, 0x1ddc6baa, 0xca21a89f, + 0x90fa5e8f, 0x75553f9d, 0x548fcc4a, 0x3afd96ed, 0xfbb479fe, 0x5470950d, + 0xa8c122d7, 0x8571c8dc, 0xa3bf938d, 0xdc2da7fe, 0x5cf81a7f, 0xe068f02b, + 0x5aebc0d3, 0x6dd667e1, 0x63e3c68b, 0x1a3adae0, 0x65b47fdf, 0xcd794a8d, + 0xfdf1cda3, 0x36afe18c, 0xfe88fd50, 0xe8aec37f, 0x71871b79, 0x387e63e8, + 0x1bf59fd6, 0x42842c38, 0x7050e1c2, 0xe23338ed, 0xaac9eafe, 0x5ee71071, + 0xb7111de4, 0x3379b88d, 0x7e740eb9, 0xf3bc52ae, 0x6eac2b66, 0xb7ff66f0, + 0xab93891a, 0xbb0b2702, 0x53f4c0fe, 0x80b3d5d1, 0x9e025bf6, 0x92ef921a, + 0xf28d24ae, 0xb7108ae0, 0x165dc5db, 0xfa225fbf, 0x2dce2c4c, 0xd216c081, + 0x0b61e0ff, 0x243c773f, 0x84087cb1, 0xe420db1f, 0x77c841bd, 0x6359d603, + 0xe62f294a, 0x82c6f475, 0xa528c73d, 0x6bcf13af, 0x254d1f8e, 0xee062f39, + 0xb8071667, 0x65f4319f, 0xe31b89c4, 0xa49bf861, 0x0b2eeaef, 0xf708f7d0, + 0x5f733f09, 0xe919fa0b, 0xbc1fbb46, 0xc5e1892d, 0x8de9c1d7, 0xed758b8d, + 0x0e4df3d1, 0x890e5f9e, 0x11cf36bc, 0x308aafad, 0x7ae31524, 0xe9d9758b, + 0x99f56f67, 0x12deff69, 0xf5d3dd89, 0x3cd3e3ea, 0x9c38f471, 0xdd7c8b57, + 0xf3a52fe8, 0xd01f9c2d, 0xeb23939a, 0x9e0e9df1, 0x94cd577f, 0x88ff247d, + 0x696965fa, 0x65fadc6e, 0xbfe703a6, 0xe76ebd9d, 0xc5fac8d4, 0x709f27b5, + 0x1facbdf8, 0x7f929455, 0x64fee168, 0x4dd71ca0, 0x581c7ca3, 0xb16deb7e, + 0xf0cea9f8, 0xef288e22, 0x427087ba, 0xdd25d9f6, 0xfcc1384d, 0xcd126eff, + 0x437aba32, 0x627597fe, 0x97e5c63c, 0xc303f82d, 0x9c09f1dd, 0xa8db946f, + 0x5180f578, 0xc17dd407, 0x79e34df3, 0xeac4399d, 0x892eba81, 0xc8fdb6e1, + 0xa45c9cb5, 0x8ffbb077, 0xfdb06b39, 0xa38f0707, 0x1f02f3ed, 0x572077d1, + 0xf371ad5b, 0x2dbf61ca, 0x5276616d, 0x593284a7, 0xf31071de, 0x3f5819bb, + 0xd58cfa9c, 0x1247ed0f, 0xf6b9d356, 0x38cf5ac0, 0xd4f42bed, 0x3f2c8d00, + 0xac2d846d, 0x3225fca5, 0xf1a0db9f, 0x131e4aef, 0x4ffa8ef1, 0xc31fae21, + 0x8d2b5fb9, 0x5b7c17e7, 0xfa374b67, 0xd4afc303, 0x1757bc0a, 0x294ad9ef, + 0x539e6c57, 0x3308ec2b, 0x62df1678, 0x0e9d9bf3, 0x9c08bf91, 0x644a9c36, + 0x71e0eaf9, 0x5d33a359, 0x474feb94, 0x7986fe53, 0x739c5e7a, 0x2e04cfcc, + 0x65fdc5fb, 0xe4ccb943, 0x5bc99a66, 0xf9421f23, 0x9e0cbc31, 0xbe53f64c, + 0x8df8745f, 0xf57fd23c, 0x69179c5e, 0x0f3fa877, 0xcfc7aefb, 0x481b5c70, + 0xc6327762, 0x6fc3bef8, 0x359c264c, 0x9f32fa9c, 0xbe5ae5eb, 0x7d39b8ea, + 0xbc492b46, 0xbc49358e, 0x8730ed8e, 0xf27ea952, 0xfedd941e, 0x7a1a7d08, + 0x476117fe, 0xfaf5e660, 0xface871e, 0x171c5d0d, 0xe2de6ea6, 0x79f82bfe, + 0xbff6c28d, 0xe21e7c61, 0x1ae22be5, 0x7ba85d10, 0xb86612af, 0x31349ef3, + 0x8727bc7a, 0xbbe32332, 0x451dd68f, 0x06a1af7e, 0x02491f98, 0xc7e8b3f2, + 0xdef7547c, 0xe5812e77, 0x76f2c74b, 0x95bf3054, 0xadf90327, 0x4d554e27, + 0xf90f8c8a, 0x27e7990e, 0xca2c8724, 0xfbe59e56, 0xc234390b, 0x73ef5172, + 0xce92bf1c, 0x527580e5, 0x6c71d937, 0xf9ab749d, 0x05b7436e, 0x7bd81ce8, + 0x13bec2c1, 0x81bddab9, 0x85f0e1d5, 0x19f91267, 0xa76e78f0, 0x1bc389f6, + 0xabf3d126, 0xcede3787, 0xc6a52fce, 0x23e5f8a8, 0x2f28b2fa, 0xe3a9933a, + 0x99f76d78, 0xc2ad604c, 0x647ea7e8, 0xc1d77afc, 0x4f60d7e3, 0x90a73b02, + 0x00e38f20, 0x5bad4426, 0xcb16fed3, 0x653a6a23, 0x8c1e2457, 0xf0703ef7, + 0xc223eafc, 0x9013f101, 0x6dcf4c5c, 0x7ce9adbc, 0xad53d19d, 0x1b1e9804, + 0xde3e145a, 0x2fcc5bca, 0xb03e1d19, 0x36fe88fb, 0xf7e6bf3a, 0x02bcec1a, + 0x18fb3267, 0x6ff4282a, 0xe8affec7, 0xc875ca11, 0xdcfe026f, 0x9b83eec2, + 0x11a7c77a, 0x5f7a87ee, 0x178bc477, 0x083dd0ef, 0x97227a92, 0xe3b117d7, + 0x39f8327b, 0xdcf389c2, 0xeb989d8f, 0x9fcf1499, 0xaf1e60f9, 0xef2125b7, + 0xbc516576, 0x3217b4fb, 0xdecf39f8, 0xe209df6c, 0x812dbfa7, 0xdbf5a7dd, + 0xfce8b9f8, 0xe9cdc7fd, 0xa5db7714, 0xaa3f1469, 0x405fde0b, 0x2fd8f8f7, + 0x782b7e63, 0xd61bdd90, 0x742db4b6, 0x2ea3a1c5, 0xc5f1fb83, 0xc8fbfc6a, + 0x7bf8c5db, 0xf510cce0, 0xee130ed1, 0xa2855ef7, 0x8679676d, 0xf436f92b, + 0xff0bf7bf, 0x8512c0fb, 0x81ef25e5, 0x077bf0ae, 0x54b03f7e, 0x85fbd1f8, + 0x1e5a5e5f, 0xed9727ed, 0x7ee9a786, 0xbe2b9960, 0xac487e1f, 0x6c5c1cbf, + 0x451607dd, 0xe4487bcf, 0xa3b90f77, 0x10ca4f9f, 0xf21f37fe, 0x3006ffc9, + 0xebbe901e, 0x5c58130b, 0xc4ca6fbd, 0xb1c179b8, 0xfdeec0cd, 0xbffdc57b, + 0xc286f7a1, 0x3abc59f7, 0x35fe73d1, 0x09dbf31b, 0x5ee71790, 0x195e246b, + 0xd720fef6, 0xa82fb8b7, 0x868d38d5, 0xe560afde, 0x652e7913, 0x90b17de8, + 0x04def57f, 0xaf9ef22d, 0xea8b6036, 0xd36f3b7b, 0xf9f8462e, 0xf46f816a, + 0x73c8e6fd, 0x67b29d8a, 0x0bdd0671, 0x3e59fb58, 0xb8b01c8d, 0x08e57c85, + 0x112c72be, 0x6dcae8f1, 0x77e2e26b, 0x8fbb3f84, 0x6b077dfb, 0xcc2d0a7b, + 0x92036aee, 0x6aa3ee9f, 0xac9ebc83, 0xc9ebc05d, 0x579e76fc, 0xf25078ae, + 0xbee624bb, 0x067d134e, 0x795a967e, 0x327036fc, 0x1f812f2c, 0x7e78a71a, + 0xb1e788bf, 0x7d049a38, 0x779ce90b, 0xd2724ba5, 0x78b171f7, 0xea6abe5a, + 0x6f9ee45b, 0x9bc41f86, 0x16327e42, 0xf0cf3f47, 0x1a632b7c, 0x4c570bab, + 0x144f75c1, 0xb8439a7e, 0xdd89bba9, 0xdb7a14ec, 0x413bec9b, 0xbf66bef1, + 0x5fdf07b8, 0x792219d8, 0xf7cb02f4, 0x5b7d6dfa, 0xcc1e79eb, 0x836bc1ee, + 0xdefa4e09, 0xc92bb6b5, 0xf6fd4099, 0x54c9c486, 0xcec9761f, 0xb457ec24, + 0xf2405c9f, 0xdfe328ac, 0x61a9d465, 0xb4ae6f96, 0x5e92b679, 0xa27b3897, + 0x3a0dbfee, 0x58f3866f, 0x0902f6bf, 0xe76fe327, 0xe0c85e6f, 0xf8feaef1, + 0x719399e7, 0xcf36e9ab, 0xf07ba26e, 0xba5557ad, 0x7e4ef326, 0x4eba6163, + 0x6f3674f3, 0x16cf4b49, 0xe8357e3a, 0xee343b0f, 0x367f155f, 0x6f8b23cb, + 0x86907bed, 0x50976f83, 0x73d03cde, 0xc08d44bc, 0xfa3d7f77, 0x6bfa38e7, + 0x5bb09300, 0x69256b33, 0xb86fc8b9, 0x8fbb7b1d, 0x41b9d266, 0x316fd93f, + 0x295267b5, 0xbdb6d62e, 0xf2913a97, 0x1ade0e8c, 0x92e95deb, 0x87303cd9, + 0x894a1ff2, 0x4669efa4, 0x5f0095df, 0xff942007, 0xf1c894c0, 0xfb6fffa6, + 0xae38413f, 0xeca286b5, 0x561390df, 0x47563eed, 0x7bb0b61e, 0x8927ba75, + 0x92ea9efc, 0x2c0cf5c0, 0x674ec86e, 0x78f0bdd2, 0xf0ccc54a, 0x10cdf508, + 0x9ee9db34, 0xeff32836, 0xff99b2cc, 0x9ff62e9e, 0xd0f60e61, 0xc53396f7, + 0xe82ce2bd, 0x06bef363, 0x40bad661, 0x0f3b5333, 0xb72dac9c, 0x32a3ef06, + 0x901038af, 0x4cc1ff49, 0x9592edb3, 0xf1007f7d, 0x37223df4, 0xe4325c33, + 0x13fdd321, 0x962f5eff, 0x8f02eb9f, 0xefdc5c33, 0xdf412a50, 0x80439659, + 0x09df77dd, 0x1def7121, 0x58d98f9f, 0xd77dd1a7, 0x893b689d, 0x367e1e4c, + 0x23f10e7f, 0x7427e3c7, 0x2c33531f, 0x293e88d0, 0x9eba6998, 0x0c7ceb74, + 0x375b0266, 0xe0785d75, 0xfb91b2c9, 0xdbd76742, 0x50bbe8e7, 0xdf62e5c9, + 0xc9ad3a8d, 0x04975641, 0x7ec3fdcd, 0x39200f2c, 0x66626d73, 0xf777c8c6, + 0x3df601e0, 0xf777ec45, 0xcce5eec4, 0x8cb4ef91, 0xfaf73fef, 0xc426eb97, + 0xd5872ac7, 0x4a3e2329, 0xd07739ad, 0xcd39e0f9, 0x8d399893, 0x996d03be, + 0xfb3116c8, 0x53bcb1a7, 0x5c092ae0, 0xe4bfc4e5, 0x07fbbe32, 0x389f1786, + 0x8265f6bf, 0x9252ae9f, 0x91587c30, 0x43881dae, 0x5fa19dab, 0xe159efa7, + 0xe53af9a9, 0x566d5bb7, 0x166fe527, 0x846937a2, 0xff2b26de, 0x7ef8c1ee, + 0x4d8e562b, 0x663e8328, 0xcb2b4e7f, 0x628fd78b, 0x6b8f34f7, 0xb27fbf9c, + 0xfd10a678, 0x1bcca78f, 0xd16ef945, 0xb164e62f, 0x30e51bfc, 0xe98390c7, + 0x80e7ffc6, 0x3c91977c, 0x817fff63, 0x802a2fc1, 0x72134681, 0x48d7f834, + 0x5c6f143f, 0xbf431fa8, 0xd9722379, 0x57f9c891, 0xf18f4be8, 0xec9d5dec, + 0x836f9634, 0xcf05ffbf, 0x10785073, 0x00107850 +}; + +static const u32 xsem_int_table_data_e1[] = { + 0x00088b1f, 0x00000000, 0x94f3ff00, 0x51f86066, 0x257bc08f, 0x799c1819, + 0x8968c550, 0x1819390b, 0x0bf1030e, 0xda005620, 0xc0c5caeb, 0xfdc406e0, + 0x88013c40, 0x3eb100bf, 0x01830337, 0xd902a710, 0x736e6852, 0x17ba0264, + 0xd8815d88, 0x32bf881d, 0x637c3030, 0x767ede20, 0x623da021, 0x2039fe08, + 0xfd04b2fb, 0xf0d83ffc, 0xdafa655d, 0xc0c2a817, 0x2a83a310, 0x8fc68b16, + 0x466fc1d3, 0x027c9a3c, 0x8f113f1a, 0x5473717e, 0x2a019d7e, 0x8188c93f, + 0x9a920f61, 0x6efc037a, 0x81afc741, 0x3100df7a, 0x74769a00, 0x0003685d, + 0x00000000 +}; + +static const u32 xsem_pram_data_e1[] = { + 0x00088b1f, 0x00000000, 0x7de5ff00, 0x45547809, 0xbedd70b6, 0x4e9def4b, + 0x62585908, 0x81511007, 0x05e42ce9, 0x62d9b1c4, 0x970621f4, 0x66854611, + 0x44749ecb, 0xf9d1c1c6, 0x153610d3, 0xc713309d, 0x60ec44e0, 0x81a0d050, + 0x60241009, 0x3cc0ea03, 0x64ffe31d, 0xb83066dc, 0xc5a4c6b0, 0xfcb8df0d, + 0x4dd54e75, 0x11d37bdf, 0x7fef999c, 0xca3fbff3, 0xfb5ba957, 0x539cead9, + 0x2c922aa7, 0x4222e910, 0xab9f83be, 0x409bf908, 0x4d171908, 0x69e5a909, + 0x24e05295, 0xbfa2e024, 0xe1521366, 0xd3cb4254, 0x43b29909, 0x48955f0e, + 0xc8428df3, 0x7da6f34c, 0x6eef2c56, 0x53b0f960, 0xfe5a11f1, 0xd3cd1371, + 0x8ee6033e, 0xe5a0ae87, 0xd9221d91, 0xb28edd08, 0x21124899, 0xfd842dc7, + 0x0e7cd364, 0x96568521, 0x3fdc68ad, 0xb717da07, 0xf6958999, 0x68bbb157, + 0x5f3415c6, 0x50264874, 0x32d362a5, 0x97cd1065, 0xc8168484, 0xf3664cf7, + 0x4314ee0b, 0x1efd689b, 0xcdd24757, 0x574e420e, 0x2147885b, 0x91d9c6a4, + 0x4268d374, 0xf2db434a, 0xb3695da0, 0x581135e0, 0x5397a6c7, 0x045b5d61, + 0x4843d9af, 0xf13b66d9, 0xf873628c, 0xde3bfe8e, 0xa2af862a, 0x3ae98be5, + 0x88b7ed09, 0x1111e6d4, 0x78a75fc6, 0x9df8519c, 0x38e376ae, 0x0b62be6a, + 0xabb6871d, 0xc2f0567c, 0xc44d2b12, 0xefc742df, 0xf59d6dde, 0xb7d60384, + 0x84e9194c, 0xa056ad75, 0xde68515e, 0xe607ab4e, 0xd1e4a8d7, 0x4686d2f2, + 0xb47470a5, 0x03cdb2bf, 0x1faaf3f4, 0x94d7ec9e, 0xd5d3d31b, 0x46467884, + 0xf884a5f3, 0x44bf685a, 0xc733290a, 0x407fbf44, 0x081909e2, 0x63c48bfd, + 0x214ff689, 0x4783df89, 0x5e14afe8, 0x844ebdc1, 0xc5b78aab, 0x27bbfa6e, + 0x6eb3b78a, 0x9229478e, 0x4d5feda3, 0xd03c021f, 0x9c02d4f9, 0xcf96ba68, + 0x4c9135cf, 0x2eff6892, 0xe903711f, 0x351eb7f5, 0x3cc995ad, 0x185ac742, + 0xc693e31c, 0xee42bcd3, 0x7e425e20, 0x37c722bd, 0x241fe695, 0x6f3039fe, + 0x062fe4d1, 0x92d2113c, 0x4abbf402, 0xfd60b320, 0xd349813f, 0x94a955f2, + 0x6bdc293e, 0x213ce5a7, 0x89ee7c0a, 0xf27c2f90, 0xa7ec74fe, 0x6851fb08, + 0xdfcfc33f, 0x572f3b8f, 0xaf3b8fd7, 0x0aa7ed58, 0x585db1fb, 0x1379b53f, + 0x2bc9f3f4, 0x1bb9fb55, 0xd85d71fb, 0x4f57dcba, 0xeae7cfd4, 0x7e27ec72, + 0x69f897aa, 0x07a5517d, 0x6913e1d2, 0x3e39a3b9, 0xa5a27ef3, 0x812bc98b, + 0x4b949dff, 0x971174b4, 0x61d1d36b, 0x97412fbc, 0x8fb93da7, 0x30f3ce5f, + 0x7c82cb88, 0x50520ca9, 0x641a4c2e, 0x35dcf9c1, 0xe17281c8, 0x4bfe09ae, + 0x301e74dc, 0x79a54936, 0x7723ffc5, 0xf3a6ba0c, 0xa40a4814, 0xc6a4131e, + 0x8332d5f2, 0x5fc1e4c3, 0xdb463c8f, 0x91914c07, 0x4ebf34f1, 0xac38f498, + 0x21311363, 0xa9226c7c, 0x33367a82, 0x3ab4f941, 0xa089e73d, 0x866b4e06, + 0xd10bfc52, 0xfec8d77e, 0x2dafa014, 0xd020e6e4, 0x94a1aadb, 0xf21107c9, + 0x70a6f074, 0x87eda250, 0x3c00a616, 0x6fe50acd, 0x1d0af8ed, 0xff8e347f, + 0x03bf8c1c, 0x77d71fc6, 0x5cb0f37c, 0xb496f8dd, 0x16f8dd62, 0xe94f8e85, + 0x9db9377d, 0x37e14f8f, 0x83e79081, 0xe6f8e1b7, 0x7f1c62b4, 0x758a42b5, + 0xc77adbe3, 0xfdd6017f, 0x1feb7f52, 0xfebf4136, 0xfafd52b4, 0xc3feb615, + 0xdf1f1164, 0x63ffeb86, 0x7f5b2170, 0xbf5b295a, 0x3bdbf599, 0xfe17abbe, + 0x8fbac1af, 0xe1feb7f4, 0xbfebf513, 0x7ebf5ca8, 0x6dff1b33, 0x77c7c152, + 0x04eff8e0, 0x2ffad9cb, 0x15f1c72a, 0x740bdfb3, 0x55b60ca4, 0x64f8e885, + 0x64886508, 0x4c3e5194, 0x42102547, 0x6191d7db, 0x6cbb8708, 0xb0beee8c, + 0x44737a51, 0x51091de5, 0xacf2a28e, 0x597cd392, 0xe40524f3, 0xb953962c, + 0x754f88b7, 0x74889b61, 0xa1ccea4d, 0xbb7ce98b, 0xe420c4db, 0x195dd617, + 0x23bf7112, 0x9da00b73, 0xfdf0c244, 0x6cc787a3, 0x98cbaed4, 0x8f95aa2e, + 0x88f8ea77, 0x993827cd, 0xf3a2aa8c, 0x3044069b, 0x4e3f9a2e, 0xf2a128e5, + 0x472a7df3, 0xd3213d21, 0x0ff7e8f1, 0x8a259ca9, 0xb1966f96, 0xde483c7d, + 0x72049518, 0x971cfd82, 0x2f8fbc18, 0xff004211, 0xa1ddd62f, 0x545a7c80, + 0x8f40a76b, 0xf1c023ce, 0x0e6dd914, 0x9e10146d, 0x2dcf801e, 0xfc848ac8, + 0x9535a295, 0x7ea8b682, 0x6dddae80, 0x8532b424, 0x76b05fd6, 0x5d3750de, + 0xccb3adff, 0x1fec2299, 0x84d837c4, 0x9b064c7c, 0xd5990972, 0x4c1e4eba, + 0x92ccb733, 0xb4d4efdf, 0xe7d7ed9f, 0xe7d62d6f, 0x6c90e5bb, 0x44a37d02, + 0xdfb48d20, 0xe5f4abdb, 0x42f138ea, 0x1f2bc302, 0x6c4927ef, 0x9a43b7be, + 0x88dd9f09, 0xd66e39d7, 0xe04f9d56, 0x7184991e, 0x481cecbf, 0xb103ff10, + 0xd6cddf9e, 0x1cef9c6d, 0xa02be2d9, 0xb77399f3, 0xce34f088, 0xdd9f73bf, + 0xd34b1a67, 0x20654ffa, 0x8c7ae341, 0xd4bb9ff3, 0xea371eb8, 0xc682f361, + 0x8c4e8cef, 0x9b6814f4, 0x4d43e034, 0x6b968abd, 0xa1a87c06, 0x33cdb2af, + 0xd092f975, 0xa2fd5d6c, 0xf2ba79fa, 0xba25b545, 0xee6b05f2, 0x05e7e5d0, + 0x9fd5d6ef, 0xae9974bb, 0xfbaaf6fc, 0x16b7e574, 0x67e5d3af, 0xeaebd7fb, + 0x51ab32df, 0x2bec2e57, 0xe513a8b9, 0x54a2ffaa, 0x36df2bd0, 0x9547a013, + 0x387e55de, 0xe9829d59, 0xa60f6ae9, 0x294f80cb, 0xb3769bff, 0xde71b034, + 0x2aefc045, 0x55c84e9c, 0x464fc069, 0xd3c237ba, 0x67f4df48, 0x487dac70, + 0x5205cb4d, 0x87ae7200, 0xf7eacfef, 0x120e5c73, 0x72d31cb2, 0xf96df185, + 0xc4c9d4f6, 0xc8f0f905, 0xfdff472a, 0xd7011692, 0x1e8b4041, 0xd4a37808, + 0x70ebc3aa, 0xf6bb3cdd, 0x257e388b, 0x0078eef0, 0x0132c155, 0x307c21f8, + 0x3031c6ed, 0xcc72df1f, 0xfdc40db7, 0x7f3aabb7, 0xc01287c0, 0x93d300af, + 0x3d30b3d5, 0xf4c7ed5e, 0x4c62eac3, 0xc2aeafdf, 0x297ab3b4, 0x83ab47a6, + 0x7aa5fe98, 0x54efa60d, 0x56fa62d7, 0x7fa63d75, 0xda610eae, 0x54c3ed5d, + 0x395edba5, 0x4af5c899, 0x1dd3ffae, 0xf967f302, 0x7bfa445a, 0x37a3f207, + 0xacf1f805, 0xa0918be3, 0xcb7d9f37, 0xef2f404c, 0x7a465e0f, 0xc4ae17e8, + 0x61457a87, 0xac870a88, 0x1b56e5be, 0x44d593c3, 0x1b9509f2, 0xa4fc5df7, + 0xcc68fe77, 0xda01244b, 0x9d33bc87, 0x411dfa31, 0xc3e75f10, 0xc645f113, + 0x71f140de, 0xe5bfd1fc, 0xf8e7bf40, 0x283b653e, 0xc2497ee2, 0x5f01784f, + 0xfee1b81a, 0xe5c1d913, 0xf7e079f2, 0x7e1540f1, 0xa684691d, 0xd2370413, + 0x3356d9df, 0xed8e0091, 0xfda110f6, 0x84f43d9c, 0xc5bbf60b, 0x87f72629, + 0xa6a0e031, 0x6ee92d15, 0x689f7687, 0xd6cfe7d3, 0x282df90a, 0x37713d37, + 0x72ba018d, 0x011c3fbb, 0x54c14ff8, 0x8a7167ed, 0x0070fee2, 0x45f18fc2, + 0x29d23c73, 0xdeb0dbb5, 0xfd1e7b3f, 0x479d13f5, 0xb680f92b, 0xf8645b47, + 0x3e91edf9, 0x533e96f8, 0xed4f000a, 0x9fb017f2, 0xefbfe8db, 0x12bf4186, + 0x037ed5e6, 0xfcd0622d, 0xacdef823, 0xf3b68f1b, 0xb43136a8, 0x255e9feb, + 0x27a55c72, 0x0bfeda2a, 0xce3b403a, 0xfdcbd6ea, 0xd03e5d78, 0xedd6ea96, + 0xe50bf003, 0x482c527b, 0x9ce52f40, 0xc7247a7a, 0xefce811a, 0xf461e088, + 0x157ab026, 0xefc54e96, 0x00ec3241, 0xae7e603d, 0x5b9e6f4a, 0xf972a5de, + 0xe4c87fd4, 0x9aff287e, 0xda272ace, 0xc4c0951f, 0x780bf344, 0xd96b7e6e, + 0xa7779074, 0x5e1f6c4c, 0x605c0a48, 0xda931494, 0x3e43d01c, 0xa07ca626, + 0xffc98ffb, 0xec696576, 0x05261181, 0x8d60b3e7, 0xfaa41f7e, 0x545f2e93, + 0x9217cfaf, 0xce80921b, 0x1264eb0b, 0xf51f8012, 0xc62689e5, 0x6aa4450f, + 0x2b0fec15, 0xdf313db8, 0x74c1a44d, 0x1ebb157e, 0xe74799cb, 0xc989b971, + 0x2ebed56f, 0x2ff36049, 0x7c54696d, 0xd683fcb4, 0x415c9fac, 0x15687da0, + 0x3b8219f8, 0x4f26ef04, 0xd0fdfc5f, 0xabe71bf9, 0xec7d1fee, 0x8a8f3e7c, + 0x142f82cd, 0x6f191f63, 0x13fef812, 0x035e3844, 0x99e8d6eb, 0xa8387337, + 0xf28679f9, 0xeffe430a, 0xa244b7a6, 0x8223b7a3, 0x40d366ff, 0x5fa05f46, + 0xf1445209, 0xa7fd23ff, 0x9e7fe9f4, 0xb13fdc69, 0xffb421ff, 0x15ff5d1c, + 0x47fed4ff, 0xddff99f4, 0xd8affab1, 0x906775b5, 0xe7d29bca, 0xba11761e, + 0x6a929cff, 0xff14bc93, 0xba569be5, 0x4a4e0e80, 0xf3d01741, 0x1f9890a9, + 0x3f57618a, 0x3e0f4bd7, 0x0f760087, 0x3ffb4afc, 0x3303f4fd, 0x62f97f60, + 0x7b46ec93, 0x6c39b366, 0xd95afca6, 0x8c9d325a, 0x9631fcc5, 0x0889fd5f, + 0x7d3d36f9, 0x70f53e96, 0x28c7f812, 0x3f7d70a5, 0x6552fa8c, 0xb07947d3, + 0x044804ff, 0x0ed8ccf9, 0x80973fc6, 0x129e71f2, 0xce9cb7d7, 0x00f0f513, + 0xf5a04b87, 0xf0444f81, 0xe64e924d, 0x2fd434a7, 0xc84f7ae6, 0x4e3c4ce4, + 0x6ff23c55, 0x5e40dfe4, 0x2120f0aa, 0xbb88f7a6, 0x760b1b1e, 0x7fd3576b, + 0x9c0d04b8, 0xdb3b3e54, 0xe7f1e0b2, 0xe3cbfd3d, 0x45876e6e, 0x9db085db, + 0x6beb8da7, 0x972d2ced, 0x63f02ec3, 0xdeca3796, 0xbe5cfd20, 0x1f2789f5, + 0x6df23b05, 0xda62f7b3, 0x97d6d97f, 0xe6813cfe, 0x89c9b6cb, 0x1c32d9d3, + 0x2f145242, 0x696ffa01, 0xa50f1466, 0xf1497fbf, 0xefdf618c, 0xa3e2884d, + 0x857edb6c, 0x8f0be98c, 0x95fb2d29, 0xbc0c474e, 0x03cb1cb4, 0xf5dc4abd, + 0x3f78028d, 0xc9204fb5, 0xd9e031e9, 0x07ea12f8, 0x23c42700, 0xde2f53c7, + 0x1403f50c, 0x55cf202f, 0x97cb193c, 0xfd037973, 0x3d234679, 0xf83cfb3f, + 0x7b31df7d, 0xcfc5fd61, 0x7582e9de, 0x18aa909c, 0x32b63f5d, 0x2dc747c9, + 0x6e498396, 0xe2f7d94c, 0x7a433f0d, 0x67fd7a2b, 0xf35ecc49, 0x6f709aa5, + 0xfac2a60a, 0x8cdc3516, 0x7e242beb, 0xc7e2bba4, 0x8f9002c4, 0x7f244b9f, + 0xb8be0c5b, 0x717c6458, 0xb4552362, 0xd04efae8, 0xa0fd076d, 0x6d0c5bff, + 0x1dc57f42, 0x67fff804, 0x2c9affaa, 0x16e7fcc6, 0x4dafa786, 0xb54f9eaa, + 0x36bd2d3c, 0xfc00eead, 0x4bea1e9c, 0x80573f06, 0x0f0e4148, 0xafda3be1, + 0x64b4faf8, 0x91e21f86, 0xaa3b7872, 0xef814c07, 0xf643bf50, 0xdaeac759, + 0xa3d2ef91, 0xe3e12fe3, 0x60db79d3, 0x44913eff, 0xac625b8a, 0xf2a8a66f, + 0x35c7dd3d, 0x6fe1a5f4, 0xf74defc6, 0xf956fe31, 0x1f33343d, 0x837b3fca, + 0x83b40ff1, 0x2bce91fd, 0xfbe58c9c, 0x1e50126f, 0x16384998, 0x9cc9375f, + 0x2ae5f5af, 0x4b79d09d, 0x5e869c42, 0x8404ffa0, 0x0ab7fa3f, 0x8d3b68eb, + 0x78c00cbc, 0xa9fdbeae, 0xf9c45b7c, 0xf9ea23df, 0xbe30349f, 0x0abf5fef, + 0x2e573ee2, 0x147c9e87, 0x67f295f8, 0x2afc03d0, 0xcfbac017, 0xf3fc1f34, + 0x9c9f294f, 0x54f95169, 0x7c8d3f2f, 0x5c7dbc5a, 0xb33d3e4c, 0x9f362336, + 0xf931efd2, 0xd3e32d74, 0x53f25bff, 0xc03e5f85, 0xfc28f2ef, 0x1fd87954, + 0xf0f28d1c, 0xe1079323, 0xf4879469, 0xd3920de7, 0xba54fe97, 0xf4ade953, + 0x408b8a99, 0xa5d2f4ee, 0x74bd774a, 0x1f5dd2a9, 0x7e0e88ff, 0xa004f2c6, + 0x05274a05, 0x0de48fbb, 0x6f2cf8a6, 0xb440e767, 0xa790cbdd, 0x36e1f270, + 0x1e5f6a46, 0x87cda89c, 0x4316f90c, 0x5f219f7d, 0x37efa860, 0xf50cabe4, + 0xd03fcc43, 0x48215076, 0x7d5d6107, 0x3a093979, 0x57b72fc1, 0x87affb44, + 0x6d1579ce, 0x1e9cd3df, 0xb079520a, 0xeaeccad2, 0x156540c8, 0x771eafc8, + 0x790095c4, 0x7b6bd32b, 0x78ae220a, 0xac787e8d, 0xdbf9445d, 0x5af92219, + 0x1f94457f, 0x9d7f106a, 0xe672bfa4, 0x3a269c67, 0x3d8296d2, 0xc17a2b59, + 0xecb85d44, 0x3cb81716, 0x5f87da7a, 0x5f7e8b3f, 0xe3c45874, 0x6b9b1e8b, + 0x048bcc2c, 0xc6aa527d, 0x8249382e, 0x7e089dbf, 0x1f6676c3, 0xd06b5c2c, + 0xa45ac82b, 0x12c7428b, 0xd522e405, 0xfbd7dfe7, 0x977d194d, 0x1b8afef2, + 0x7b6ae5f4, 0x3b023938, 0x5f49b4ad, 0xce76e7ee, 0x67bd2a93, 0x17940c90, + 0x7d80c060, 0x34ebe5cd, 0xb3f5f471, 0x0e7bfc28, 0xe5e80489, 0xf088bb6c, + 0xceccdb3f, 0x20704909, 0x89254df2, 0xe1535ca0, 0xa17c05d4, 0xba772ff4, + 0xe735fc76, 0x7ca55a1e, 0x7f63bbe7, 0x9daed347, 0x03dc8f6f, 0xa66f5df9, + 0xd6fa4bbd, 0x8acfb29f, 0x7d9ed9fe, 0xe94f3c4e, 0xda6afbd9, 0x6ddf903d, + 0x7b3cc2f6, 0x16397df6, 0xb967a7e8, 0x56e418b9, 0x7f8a50cf, 0xfdecd69a, + 0xee276c72, 0x6f102b93, 0xd30a8baf, 0x76ffda73, 0x94844854, 0xfff60aae, + 0x33f4767d, 0xa2b79e04, 0xef67a07f, 0xc77e3997, 0x953d6f3f, 0xc7a4dcfc, + 0x876d6649, 0x7f33c5f9, 0xf8cf6073, 0xb9c19627, 0x657eeb6f, 0xf29f2d01, + 0x416337c2, 0x676cf61e, 0xdcb74d7a, 0x05ce01b9, 0xeef352fe, 0xb9c29932, + 0x1062981b, 0x862bb995, 0x623a0e4c, 0xf41be5c1, 0x3c285c7b, 0x067ffd3e, + 0xf79e021e, 0x433bb795, 0xfdd60116, 0x4177d1d5, 0x2333ec0e, 0x3debaa5d, + 0xf50cb2d3, 0x3badf38e, 0xf5f66241, 0x0b759cff, 0x77590be1, 0x8daff486, + 0x07a25def, 0x83e462f1, 0xf7be74be, 0x756fcc2e, 0x17be717a, 0xff33ef48, + 0x83ffd7c5, 0xe29dbef1, 0x75fe75dd, 0xaf8bfd57, 0x1fbc7fbb, 0xeef1c39e, + 0xc0f57386, 0xfce0df0b, 0xab9ca87e, 0xf7e717fd, 0xeaafd6fe, 0x79307fe7, + 0xf5a0c8de, 0x03ad49f3, 0x2a6b8b14, 0xa0ce1c0e, 0x72187fa5, 0x3be61e30, + 0x18c39f99, 0x125fb7e7, 0xc164fdb0, 0x891d7684, 0xc75db817, 0x5cc1a1ec, + 0xa4bc187f, 0xc190f510, 0x7a641e43, 0x83a9e483, 0xa43fbe73, 0xcc62f02d, + 0xcb7cc902, 0x95f7790f, 0x0bb7af3c, 0x1f10277f, 0x4e0e411c, 0xa043f7fb, + 0x22190e9f, 0x534afea2, 0x745f5bd4, 0xe5efb3e5, 0xb97ece8a, 0x67b7a3c6, + 0x76f512f2, 0xdfde54cf, 0x3fe6c234, 0x428421cd, 0x87930e14, 0xfc1126fe, + 0x962f939c, 0x79f34089, 0xec02bfc4, 0x7d0ea984, 0x19c18f7f, 0x580fc68c, + 0x16bb6964, 0xaf16dffc, 0xd25dfd80, 0x62794265, 0x0e9016c9, 0x984bd546, + 0x1ee4dd7f, 0x719e7007, 0x7733aec5, 0xfa97f013, 0x528f1614, 0x5fdefcc0, + 0x44ddf77f, 0xf0e2e388, 0xaeffa22b, 0x036eff03, 0x7ae8db09, 0x18244917, + 0x4efe0097, 0xf3afbc81, 0xf0f3ea77, 0x68a4e3f3, 0xdfabe73f, 0xb3fe1d1f, + 0xee945dd3, 0xdbb0a7df, 0x1c08e90d, 0x53dad25e, 0xe0ced6ff, 0x84857815, + 0x6ef3b186, 0x2e7340b1, 0xeccca974, 0xd97f5dee, 0xccf6059e, 0x71d19ea4, + 0xa0471f8c, 0xfae0197e, 0x89e259e5, 0x1f803af3, 0x79e1c787, 0x19d121d7, + 0x0b6bde2b, 0x819eb3b7, 0xf69a5073, 0x115a9134, 0x41127df4, 0xc9b05dff, + 0x88c53642, 0x4d94483b, 0xe39c5cfc, 0x3988fe8d, 0xe36787e0, 0xe34da22f, + 0x9aeb78b4, 0xdb1a4a7e, 0xf3f00f17, 0xe21ce6be, 0xd82f851f, 0x2ddf0075, + 0x82bcced6, 0x923b7c18, 0x81c66fc3, 0xbe9ed0af, 0x04d1bdac, 0x93597e7c, + 0x969e7749, 0x3dfd7326, 0xbcc26493, 0x3ab01c66, 0x872f01b3, 0xd9c42f44, + 0x513fda05, 0x83ce31fc, 0xfe84f08c, 0x9b7a8fc1, 0xed7846ec, 0x00165b91, + 0x6c7cf75c, 0xed676021, 0x62cb6a56, 0x0a4ff3cd, 0xd222e79b, 0xf4d8e772, + 0x4ef83d7f, 0x278471ea, 0x44d2bd83, 0xd2fbaf90, 0x3e3a411f, 0x408499bb, + 0x037d831e, 0x336ce172, 0x8280fdc1, 0xd3b041e4, 0xa55fbf28, 0x692fdfb5, + 0xec0cf6db, 0x82ed9523, 0x95cb5c1b, 0xfe02a752, 0xbc5b40b9, 0xc33b7208, + 0xba21c6a3, 0xe1a4dcc7, 0x0964db8b, 0xc2707be1, 0xdc615b9e, 0x0214bb4f, + 0xc5ef9afb, 0xfee40b88, 0xc859eda7, 0xebadfd07, 0xdae4d5f7, 0xc3f412a9, + 0x1e919ae4, 0x74db3746, 0xff442bf9, 0x19afe020, 0xde25cee6, 0x96fbf818, + 0xcb05d9d3, 0x67ffd0b7, 0x550dedf2, 0x02c5f9be, 0x2cbd1f0d, 0x23557db3, + 0xc96392df, 0x2782c5b7, 0x78bee019, 0xc064f0ef, 0xf2c3e2eb, 0x6df258c0, + 0xdf3b356b, 0x8fc78e7a, 0xf952b4f6, 0x7c8d23f6, 0x2df2a56b, 0x8b7ff9c6, + 0xcf5ffaac, 0xff42df23, 0x15b7fc3d, 0xf58c5be4, 0x53f0e41e, 0xf6d8dbe5, + 0xc6df2863, 0x71749ab6, 0xdccbcf96, 0x7cafd99f, 0x04de0613, 0xd921d4fa, + 0x3f418f6b, 0xf6feb95b, 0x819f8f1c, 0x7dce4071, 0xdce503f5, 0xe72a173b, + 0xace09bfe, 0x3bc5b9ca, 0xf69fc608, 0xe72643a5, 0x72a6ef16, 0x647a004e, + 0x5ef16e72, 0x0638fcc2, 0x8faa36f9, 0xbf58237c, 0x07dacc32, 0xb91fd2da, + 0xe997f68d, 0x5a16bd93, 0xef2a333f, 0xdde569c6, 0xbbc9fd57, 0xef261743, + 0x47797076, 0x9030d8e5, 0xf0fa46af, 0x74e3ebb6, 0xd13f8cf7, 0x97e07bfc, + 0x673c4557, 0xcec4dd7a, 0xfe34fe05, 0x57d03644, 0x33e6c281, 0xd7f46142, + 0xfec41d5d, 0xd6c8bca7, 0xf160e157, 0x4cad95bb, 0x166cac3f, 0x6bfa1e42, + 0xf0af84de, 0xaf64a8bc, 0x7e699240, 0x27d599a6, 0x24e7a94f, 0x86867a64, + 0x96e6161e, 0xa1777fa1, 0xbfe02c44, 0x9de4732d, 0x2cb63d02, 0xcb7bf997, + 0xc392f7f8, 0xdfc0ab9d, 0xc05eb259, 0xee353273, 0xecbf8d50, 0xbede5e73, + 0xc681fd0c, 0x3c19f373, 0x33c6664e, 0xc631a842, 0x66d97fb9, 0xa71a7e7d, + 0x276299e7, 0x26bc8bc2, 0xe0c5377a, 0x2f5eb51f, 0x38710e9c, 0x9fb88935, + 0xc289c2f6, 0x17de93cd, 0xd3d3144e, 0x70a29233, 0xae957929, 0xf5ffbb37, + 0xae3370aa, 0x9677f55b, 0x83fa7ef1, 0x3ee70a83, 0x2770e7eb, 0xd2728424, + 0x95ab8f08, 0x16683f5e, 0xba50a7c4, 0xfc133941, 0x0d7188a3, 0xd62e9305, + 0x8eb843dd, 0xed564fd3, 0x8c7029a4, 0x7de2133d, 0xfeaddce1, 0x6e21978e, + 0x9e5bdc6f, 0xaf4ed84c, 0xc3f66098, 0x6b16dbf9, 0x4aa0e504, 0x87408d87, + 0xf0f7ae14, 0xaa0cf67e, 0x61768c9a, 0x3d06e09b, 0x22b61024, 0xae14035c, + 0x20242f70, 0x2806fc31, 0x1dff023d, 0x8305ff5c, 0x03c15ee3, 0x753c80fe, + 0xd0bc02bf, 0x0ced59fa, 0x8090812f, 0x1126c978, 0xd657bbf4, 0xc030de0b, + 0xe111adaf, 0xfa67caa7, 0x49e2d0e3, 0x2c52bf43, 0x9a4ac5fa, 0xd78cb2fd, + 0xfdae619b, 0x8cf3d033, 0x88d264a7, 0x7dffa6e0, 0x279f3d1f, 0xa788c3fe, + 0xb6bc39c7, 0x001d3c02, 0xbbd308b7, 0x3de15fc2, 0x203cb515, 0x9cf07505, + 0xefb9e8f2, 0x1538d785, 0x20c7405e, 0x89e7dadf, 0x136c2f90, 0xbef480c8, + 0x307385eb, 0xec97bf2d, 0x7ffac63d, 0x1892f04c, 0xba60beeb, 0x8b9e87ee, + 0x7f82dd29, 0x36ba3fbd, 0xe151a9c2, 0xe7a726fb, 0xaf23593f, 0xef3d0164, + 0x49cf9015, 0x3ceebc7b, 0xf4c2bf6b, 0x4a562d88, 0x91dd74f7, 0xa377b2c3, + 0xd83cafa7, 0xf60be1ce, 0xd01ef683, 0x8810b0a5, 0xc16cdc0f, 0xc79c2f38, + 0x6a9fa630, 0x2b56f3e5, 0x76537819, 0x7987fdff, 0x47e9fdff, 0x8c0c7e6a, + 0x6dcd7107, 0xd151bc74, 0x83fb8cf1, 0x6f9ff76a, 0x3972af5d, 0x4baef7f7, + 0xc687e71d, 0x074804c1, 0x878d55e2, 0xc7f82239, 0xe5cfa0c8, 0xae3e920b, + 0xd6e5c22c, 0x1fffdc3f, 0x927fafbf, 0x4e7bc6e2, 0xefd5ba77, 0x02cfa46e, + 0x41e7e137, 0x7d84df13, 0x3b1f53ff, 0x9136caf7, 0xff611323, 0xa0132c98, + 0x915f4fab, 0xe9f96fd1, 0x79671654, 0x2507abfd, 0xcf5cdd70, 0xf5c8a162, + 0xb3b404e3, 0xc7ae875e, 0x216e1e83, 0xbf0891be, 0x954fb82c, 0xc53b54d1, + 0x733af943, 0x5206a873, 0xe24894ef, 0x936f009f, 0xeb780244, 0xe2980df0, + 0x3f3bf9a0, 0x32e01922, 0xb601faa3, 0x06443ccf, 0xbe09bd42, 0x8cc66881, + 0x8decfd6f, 0xc63ce91b, 0x3d7a22bf, 0x83ccdeb4, 0xfaa1070e, 0x1306a8f4, + 0x35e06bf1, 0xc06a8481, 0x43fe346f, 0xef308ddf, 0x40efaa62, 0x7b717efc, + 0xf20b8d63, 0x0fb6020d, 0x2e79fd04, 0xf5ad9eba, 0x0e5de49f, 0x83d68172, + 0xac0d026e, 0xf049a05e, 0x616a4842, 0xe5053afb, 0x17809346, 0x0486b6bd, + 0x86fd6162, 0xaddfb42c, 0x367db40d, 0x3db45fec, 0xc9f4dbf4, 0xdc82371b, + 0xf6c4f3a1, 0xb63ceccd, 0x00f3b690, 0x81dd34bf, 0x083495fd, 0x1419ee04, + 0xa97db337, 0x0bd915f8, 0xd7fbade5, 0x9d3b7ee3, 0x0e9a978e, 0x2a7850fb, + 0x12c8d7de, 0x6d8f78dc, 0x5fc450fa, 0x23f8610f, 0x1c984389, 0xdb9e7813, + 0xf7deaa3d, 0xe430f32b, 0x32ef4283, 0xe7ed0065, 0xd303b94f, 0x9f57484d, + 0x7da7a028, 0xa7ede148, 0xc79d7ef0, 0xfdcc1c29, 0xecd4e940, 0xe1e6cd8b, + 0xdb617ed8, 0x5a7f8c24, 0xfcf00a44, 0xa678c67e, 0xa576be6f, 0xbafe0435, + 0x10c8e4d7, 0x4af07ef8, 0xdeef7e33, 0xf770e4ca, 0xcff44ed0, 0x0990689e, + 0x69a82fdc, 0x9c5e5110, 0xbcf19668, 0x464c7c5a, 0x95b45db9, 0x1b071fe9, + 0x4027bf58, 0x393f036f, 0xd17cd394, 0xfbdb8116, 0xf6ab4e4c, 0x9d9ba167, + 0xb772abbb, 0xcfbbaf82, 0x4cb7543e, 0xca359201, 0x8f2e0adb, 0x02a4a94b, + 0xddca3342, 0x7577380a, 0xe31a5f01, 0x3b511c83, 0xfc20e806, 0xe575d215, + 0x3b01322b, 0x2ba0f846, 0x6a7de60f, 0xee7e80af, 0x0f82edf1, 0xdf8bbdce, + 0xff508732, 0xfb9bcd0e, 0xde5fd80b, 0x55081336, 0xa0780e3d, 0x1cd72a72, + 0xe86fcbf9, 0x5baf53f7, 0xd2841220, 0xbb843ccd, 0xbd99df1a, 0x6471c589, + 0x04975ebf, 0xd4c92cf7, 0x8a072801, 0xd7e245ea, 0x825389c8, 0xb29fc6ef, + 0x8dadc1fd, 0x6a56cce3, 0x3d7f610b, 0xd1f2666a, 0xd88649b3, 0xccd2b208, + 0x0fb534e4, 0x64b2fe30, 0x4524baf7, 0x7b250743, 0xf48925d7, 0x071e2afb, + 0x2bfb0351, 0xb0a2576d, 0x09f64a71, 0x38cd46ee, 0xbf6a3f6a, 0x6ed66eca, + 0xf6965ef8, 0xcc097fd7, 0xb9f9d70f, 0xd8c2f202, 0xfbf19f4f, 0x3ff727e9, + 0x7409d5cf, 0x89afb95e, 0xfb9ca418, 0xdae1f4c1, 0x55350073, 0xde7215e3, + 0x069f1130, 0xb17fb97e, 0xdf069f11, 0xdf28e3ad, 0xd75dfc53, 0x02ac8426, + 0x15298fe4, 0x037798d9, 0xff72579f, 0x7654e573, 0xf19ad3be, 0xfbe00afa, + 0xd202d9e9, 0x95fa0903, 0xafa88901, 0xb8ce2079, 0x2fb59b28, 0x1f81eda2, + 0xfe33d75b, 0x03c272a4, 0x61b2a472, 0x6fd61e5d, 0x7fd03c12, 0xd43ce36b, + 0x45738a47, 0xc74de582, 0x6e2a3f50, 0x7c08963b, 0x0eb6f94c, 0x89ca81f4, + 0x71c83766, 0xfe551f95, 0x05c78d7e, 0x0c7b8b13, 0x0067e3c4, 0xcbec0df3, + 0x4c2be2d7, 0x199a07ae, 0x1972063f, 0x55b6bebf, 0x085e1586, 0x9f3f237f, + 0x55f8ccd8, 0x3ce6ec7c, 0xb45ca7b8, 0x1ca7c589, 0x80a2986c, 0x24227d3e, + 0x97d37ee0, 0x6ade99bf, 0x811aefe4, 0x543f7bed, 0x5bf954bf, 0x73fa63e5, + 0x4e578c1d, 0xb5ee14f9, 0x867af919, 0x3be7f2dc, 0x7faf7ce9, 0xce87ae96, + 0xef8fca77, 0xe46a7576, 0x4127cd24, 0x716250be, 0xa95caa3c, 0xd7bc5890, + 0x619f9e0f, 0x7acd1bfc, 0x734ac8ff, 0x6e6b8b3c, 0xcfee9192, 0xf87d9fc7, + 0xf3f902ec, 0x7ceaf942, 0x2f8ea9fc, 0xb3f7d5ee, 0xb19bd392, 0xd70a6ebf, + 0x1feb8530, 0xb8c09f9a, 0x3e9f8fb1, 0x53f00336, 0x39d287b6, 0x93b357d0, + 0x49ce4184, 0x4aafdc21, 0xc61f455b, 0x9ce14abf, 0x3e5a9d1b, 0x653e7166, + 0x9e9139cf, 0x439bb74a, 0xd2fb69d3, 0xc58c1f9d, 0x11e58bb8, 0x3e0a438c, + 0x60e5f5cd, 0x83e058e7, 0x1bc58952, 0x00c2e519, 0xe8673b0b, 0x059f6dda, + 0xb33613eb, 0x2da5fd7b, 0xcd66c8b7, 0x22cd84b9, 0x1cf0f5ab, 0x18e94830, + 0xfcc255ee, 0xd5c9f7b4, 0x2daea338, 0xb6944e4c, 0x960768c9, 0x0dd6de6e, + 0x6fa5a371, 0x15dfd199, 0xc609fcd8, 0x6e794fc1, 0x0253fa2b, 0xfceea26d, + 0xdebc4fac, 0x866c3166, 0x0ad6b378, 0xf9a3ef3c, 0x896f9863, 0xbe7ab71d, + 0xe7b2b2b8, 0x520ceef6, 0xfefd9610, 0x97c81729, 0x5c9b1dd3, 0xf9b7b718, + 0xfb65e3fb, 0xdcb5e7c4, 0x79f1bdf7, 0xca17e1a7, 0x862d1338, 0x03cdc6f8, + 0xf3a48f50, 0x718829cb, 0x97abd1ce, 0x037cfd6f, 0x6d778fc4, 0xe601b33f, + 0xa7edfe5b, 0x887e201b, 0x7ee2b3ec, 0x08fa7817, 0xedaadfc6, 0x7ee1627e, + 0x614f2d8f, 0xdbf772dc, 0xd6f42f66, 0x1a44f7bd, 0x6f758fc4, 0xfc092afb, + 0x4ef64b96, 0x92eebf43, 0x4992531d, 0x4d42fd8c, 0x17436e81, 0xc46d3710, + 0x83d6c1d7, 0x31f4e718, 0xbfc837c5, 0x96cb78de, 0xeabf160a, 0xcd9671e1, + 0xfbd3e3b1, 0xdeb655c4, 0x2095fd78, 0xfe995bf7, 0xcaf8de78, 0x7f1e2837, + 0x6bf80174, 0xb102fd56, 0xfc31f7f1, 0x76e21e32, 0xbcfbf8f5, 0x8fe3d175, + 0x80eb5942, 0xc32be37e, 0x35370017, 0xc5927dfe, 0xbe016d57, 0xc60cfed9, + 0xa6de02b3, 0xf9ff607b, 0x0dee0d3c, 0x7323949c, 0x5ed93ef0, 0x09e21bb3, + 0x89bef74b, 0xe3bdd3fc, 0x1343f475, 0x4dde871e, 0xdc587f7a, 0xd9d7c0b0, + 0x997164e4, 0xb710fe1c, 0x77e171e9, 0xe8c99f1e, 0xecdb8d58, 0xa7735e2f, + 0x6ad9e985, 0xd3457e5c, 0x31fe3cbb, 0x17212f8a, 0x7bec74f0, 0x70a811ef, + 0x1c397370, 0x1d8e3f8d, 0xa71bdb17, 0xf805f1ce, 0x37a87d83, 0x87e698be, + 0xe8dfa264, 0x1e43124d, 0xb8b23774, 0x7f596ee5, 0x1f8a33df, 0xcdbc8f16, + 0x0ba1a7c8, 0xdf3e438b, 0x7c287ffc, 0x33f28236, 0xba9c2fb0, 0xc72d8ebe, + 0xff7ce0df, 0x5967df77, 0xb3ef1828, 0x63d027fc, 0x0531eb45, 0x3b5ee0ec, + 0x8bb7af9b, 0x9ebbd5fb, 0x759e3116, 0x9441cb55, 0x517946e3, 0xc458ef09, + 0x0b71ef98, 0xd8dbc3d7, 0xddb5d13e, 0x7ed07219, 0x46ec0eba, 0x3e6cae7a, + 0xe09c40a6, 0xaf7f9bcb, 0xc629f3b0, 0x844fb03f, 0x7aeff334, 0x1658ff76, + 0xf8fccd6f, 0xe33e71c6, 0x63da04e3, 0xfe68138f, 0x594e3744, 0x3b7145b0, + 0x69de3fce, 0xf40b77c9, 0xe983ba77, 0xc45ba783, 0xb9f758fc, 0x66fbe4de, + 0x743d7bef, 0x4177c4bf, 0x101dec9c, 0xfd4365d1, 0xf7338972, 0x4844b8ad, + 0xa9ef8c15, 0x81e3c659, 0x014de97e, 0xaf38d77c, 0x95df3025, 0x9f8d5f00, + 0x09fb7647, 0x4a72a5e8, 0x15f83641, 0x4946f28c, 0x06909134, 0xf99c4bff, + 0xef3c1ec9, 0x7c010f08, 0x2138cd1e, 0x19efbf43, 0x49ef54fc, 0x9d325564, + 0xc1417bdf, 0x4bf68cbb, 0x6860febe, 0xff6fb381, 0xaf7fde6a, 0x552bf3a8, + 0xc147239a, 0x582f212e, 0xdc41be31, 0x17f7c567, 0xb8ac1b02, 0xbe3b83de, + 0xebf5127c, 0x9d84cdc7, 0x85eb50fb, 0x9b915fd2, 0xc76271f5, 0x06fe1b97, + 0xa63433fa, 0xa06d17e3, 0x686ec1f5, 0xd39da3b6, 0x2c6e3db3, 0x5e8a45f8, + 0xc80667b8, 0xa33b22b3, 0x92e7a2c7, 0xbfb43543, 0xfe5903e3, 0x78a1d6f8, + 0xbb6cbfdf, 0x0f0ce313, 0x0955d8ee, 0x73f752fb, 0x52fb0276, 0xcf5c0bf7, + 0x1fbf867f, 0xb47b2f54, 0x4425c6f1, 0x71ef68f2, 0x959e4194, 0xfc107de3, + 0x047ce1c9, 0x38b6aafe, 0xf541ffbc, 0x1f3f5d5f, 0xbcbb91cb, 0x41c1c748, + 0x784bdeec, 0x6303c810, 0x4afcb53d, 0x8f7e30eb, 0x4473b698, 0x489407eb, + 0x0ed7cb21, 0x03a4f262, 0x656b5feb, 0xf796affc, 0xcfd597ed, 0xd5d30eb7, + 0xf257db53, 0xf48c41f7, 0xe055b37b, 0x2e6fc1fe, 0x45fef589, 0xf7e3f98c, + 0x6824099f, 0x9b653d02, 0x8225df15, 0xdf10f37b, 0xe76153be, 0x30aee55a, + 0x87b23fbe, 0x5b72e3cb, 0x1943df18, 0xf501e7c4, 0x9d2c4f21, 0x56bbe2cf, + 0xde04acbb, 0xc178a9c7, 0x577c03e9, 0xf8f2fcec, 0x8e21b2ef, 0xd4718ecd, + 0x1cfc2f15, 0x1cc2a0e9, 0x10fc039e, 0x1b2666d9, 0x1db7cf81, 0xed7e034e, + 0x0969c392, 0x575e73df, 0xbc3662d1, 0x71d6c01f, 0x0afebaba, 0xdeace7b8, + 0x47ed2ca7, 0x656b3cce, 0x585fe87e, 0x78ad4b7d, 0x677fadae, 0xacf574e7, + 0xaf57b82c, 0xc4b52fd6, 0xad6b8b96, 0x4f763ff2, 0x5ee7d1d8, 0x40eb5ae2, + 0x923a63d0, 0x4953efc0, 0xe7906ef5, 0x87d39ba5, 0x80e09f80, 0xee77bd55, + 0xe8fd8389, 0x7b41ec80, 0x3eed521a, 0x9bdab273, 0xff008d25, 0x892ca8cd, + 0xf1a7a3ae, 0x0441c293, 0xb3ad0ee2, 0x0dbdc962, 0xa3c23b56, 0xc5f662d4, + 0x0cf8d7ba, 0xc107d7a7, 0xc6c71fe8, 0xc750fe03, 0x5087203d, 0x79b70f0e, + 0x2ed43f58, 0x9b65ef82, 0xdee96767, 0xb16a90c5, 0x8453e51e, 0x53a90967, + 0x5bf235b2, 0x6964af1d, 0x05949676, 0xeaffa5df, 0x8a3157a5, 0x444c1267, + 0x30e250bd, 0xbaa97526, 0x5c9204fb, 0x29f80160, 0x892dc0a4, 0xc8b52a40, + 0x82d236ef, 0x5baa83a9, 0x2aa8fdec, 0x64f27202, 0x0417bbef, 0xeebc28d3, + 0x1c1fb946, 0xe9c5c84a, 0x13dfff70, 0xafc0d6e7, 0xf9c2eacd, 0xc22aa598, + 0x3774c5e4, 0xd04223e8, 0xf4a3be4f, 0x9f9d5354, 0x7f48f405, 0x0cff707c, + 0x3f3a0f4d, 0xafe5fb97, 0x74a20f40, 0xfb59deca, 0x50d50931, 0x28f84310, + 0x132755fa, 0x9ad83ef6, 0xded688b7, 0x6fe72bf8, 0x728fdc12, 0x3fa241cc, + 0xb1079a11, 0x26b6f20a, 0x385cdbee, 0x49b87447, 0xbb42f418, 0x34ed8483, + 0x4e968c75, 0x95dff96b, 0x3a1af34d, 0x97d44f75, 0xca82f91b, 0x2db8c335, + 0xefda3f08, 0x3f7e8667, 0xd9fbf433, 0xc2abf5f7, 0xe8d96029, 0x5609f785, + 0xb8701756, 0x1c2cf1b1, 0xa33e146e, 0x62337de0, 0x79f979b2, 0xc6d5c238, + 0xfa866367, 0x6c83af14, 0x07a708e9, 0x2045f6e2, 0xd624966e, 0x577bb013, + 0xa69f6c08, 0x4d0e053f, 0x20b6e23b, 0xc7c7de1f, 0xf4636419, 0xef5bdeae, + 0xe78adf5b, 0x5bea7d1a, 0x8b6fabfb, 0xdfd9df5d, 0xe731ec7c, 0x4ce543f3, + 0xfe6f0be5, 0x7b61ce09, 0x829b8de5, 0x6f274732, 0x9c28d906, 0x7f8fe22a, + 0x985f89db, 0xa21968de, 0xe80d9fc7, 0x6d8fd295, 0x11bbfe84, 0xcbd1fdef, + 0x9a0ebe3c, 0x75d2a477, 0x3f8f94fd, 0x639d89b5, 0xf984b6df, 0xe7b9a8dd, + 0xf2b7fa83, 0x14b53ffa, 0x18e0ffa1, 0xb6e9177f, 0xde17a67a, 0xe788af76, + 0xfdde7dcd, 0xff285f81, 0x0854bedc, 0xbd63d385, 0xe09a4463, 0x3e5cd47e, + 0x205df1be, 0xade4f13f, 0x0bbd6311, 0xbd4ce8c4, 0x6f7c6557, 0xe0292160, + 0xbfe93def, 0x91bab26f, 0xd61e410e, 0x4bee8e8e, 0x8e9475c1, 0x74a49f41, + 0x70ece70c, 0x3ce3063d, 0xf38b0a5c, 0xe78a18e8, 0x3b3caa63, 0xe1c4f1eb, + 0xd34deafe, 0x78b817bd, 0x5e3927bc, 0x73a5af23, 0x2b7bdd36, 0x0537b235, + 0xee7c95e4, 0xa6a1e232, 0x1e8d42af, 0xea9ca68f, 0x10ccc8a1, 0x277284a6, + 0x9c810a45, 0xa405dc93, 0x9958f408, 0x5f5aa7d1, 0x57acbc49, 0xfe8d7c6f, + 0x878801bb, 0x3be2e5d2, 0xd728c93c, 0xe00b05ed, 0xf5cae893, 0xe97d1dfa, + 0xad95b821, 0x9dd606bb, 0x353d77de, 0xfa8bd78a, 0xf7de84f3, 0x3f302c69, + 0xd379ecd1, 0x0ffbf303, 0xa51f8099, 0x27bc7c2f, 0x677e1443, 0xde318343, + 0x3e9b8c43, 0xdf57c612, 0x9d535c45, 0x2bade782, 0x2b897bf8, 0xfe6147aa, + 0xe59efe7e, 0xa60f6aaa, 0xde2cfc2a, 0xcfc77c5a, 0x6ff58232, 0x24fc7371, + 0xfc7c389a, 0x52592fa8, 0xd01cf0aa, 0xc30aaeea, 0x086459fb, 0xda6027dd, + 0x9f845aee, 0x87e826e2, 0x6f31f5a4, 0xe54d3c86, 0x0f88d1fa, 0x8a455dc9, + 0xddbe7968, 0xcdc020ff, 0x7ba419ea, 0x329cd01f, 0x03df7bec, 0xf5a7a5ec, + 0x72262e4c, 0x27c2327a, 0x65ef6151, 0x9fd474aa, 0xe3c3555e, 0xf6ae1f74, + 0xdfc35a62, 0x7781aa81, 0x3d48147f, 0xedc81f98, 0x470a1ac4, 0xdf08fef8, + 0x73aa6b37, 0x972cfcb1, 0xaaa68957, 0x25c032fd, 0x66ff3081, 0xc90c9062, + 0x14042c21, 0xc482527e, 0x9cf57903, 0xe6c69dd0, 0x7441e9cd, 0xdc77864b, + 0x5e008f3c, 0x26cb0eea, 0x4b8b93f0, 0x681f25af, 0xe59c59e8, 0x99bf078b, + 0xb00bf0e8, 0x78003dff, 0x4759f3a5, 0x96ef85e7, 0xc9587a72, 0xd39abef1, + 0x1f407dc3, 0xd3907d34, 0xfae8afc5, 0x65e35f21, 0xe6d601f7, 0xc4b778b3, + 0xc77f130c, 0xf1b44c2c, 0x16def164, 0x2275d0a2, 0xc5307a8f, 0x5bc8ea77, + 0xfb17a466, 0xa113e268, 0x43bbadfc, 0x82c91dec, 0xe337d854, 0x272377d5, + 0xe367e27a, 0xc4b0d545, 0x991373df, 0xf311d1dd, 0xef1ac67d, 0xefd80b01, + 0xeec7cdfd, 0xa4afa5f5, 0xd9ebd9e3, 0xfe01c5bd, 0x688bd982, 0xf54f51de, + 0x8ce5026f, 0xde741d2e, 0xc67d1a45, 0xbffd8fde, 0x51cd7ed4, 0x7be7c51b, + 0xe45141b0, 0xb87ebaff, 0x614be015, 0xc73f01ed, 0x2a4172c3, 0xf1c3fff0, + 0x8735fdb1, 0x83d2326d, 0x1d32fb2b, 0x3ec9d73d, 0x989ee76c, 0x3afba3a9, + 0xa612772e, 0x577dd04e, 0x6defcce5, 0xb12eef4c, 0xbcc2cffb, 0xc5d1ce92, + 0xbc4a7e51, 0xa9dcb621, 0xdc209591, 0xc319afdf, 0xa6705ce4, 0x3eabf4c2, + 0xa7c98472, 0x6f32e4b3, 0x645f4350, 0xf03d4114, 0xee8a998b, 0xc035c1dd, + 0x7e5e941f, 0x057ee9cd, 0xc54d01f0, 0x4dd20a11, 0xda1374c2, 0x5f38aba9, + 0x68f9cfdd, 0x87a3e72d, 0xc2467f80, 0xdf8cae3b, 0x051de224, 0x8b8d48fb, + 0xc0258fbd, 0x8d49b4ff, 0xe85cfe6d, 0xb32de6af, 0x350fe700, 0x11752f92, + 0x977e29e4, 0xef8f307b, 0xedeb06ea, 0xbbf1589e, 0x9293ed4b, 0xc95e14ec, + 0xdfbf8676, 0xfe2167d4, 0x316f6e2c, 0xd8724bac, 0x19afaed0, 0x658e2969, + 0xbdecd81f, 0x53b74ef0, 0x9fc80f78, 0x817f6bd0, 0x666ea17b, 0x37fdc20e, + 0x06399f70, 0x33b18cfd, 0x04864079, 0xff0d08c9, 0xdcf7f1d7, 0x46482788, + 0xf2c0e469, 0xf808f38b, 0x7ff2fa77, 0x136ff23f, 0x02357f93, 0x780c57df, + 0x5531f755, 0xd78049fe, 0xb9e77d01, 0xdd5ca2f2, 0xcb997b3d, 0x3cbd636f, + 0x4f9d9dbb, 0x2fc46f11, 0x70a72df4, 0xce6bb3ca, 0x09c49495, 0x5d95efbd, + 0x461d6315, 0xf61277b9, 0x9225903f, 0x5905df1f, 0x191e78a8, 0x8fe4f20f, + 0x3fa5fe2c, 0xaf1d40fd, 0xee315ce8, 0x72e785f3, 0xae299f71, 0x20fe45cf, + 0xd8d78de0, 0x7e1a2749, 0x9dbc02e6, 0xa3e7e7a8, 0xe208720d, 0xbc6ff652, + 0x14d9a1e7, 0x88370b9e, 0xd7fefeec, 0x6a277ddf, 0xb6481be2, 0xf53af507, + 0xa113b43d, 0x73da5d3b, 0x58dfc2ec, 0xf62fa07d, 0x3614cfb7, 0x6bdfb6c4, + 0x53d057e0, 0x1e801f29, 0x4881f54a, 0x5f85f418, 0x08bdf15b, 0x68dc1f35, + 0x540ef98f, 0x195a7dbe, 0xddbe67d0, 0xc4a42777, 0xfafe8091, 0x8ea1e6fe, + 0xa67c1c7b, 0x28f64e70, 0x70a5b38f, 0x9ff3a99f, 0xe3b273b1, 0x2c421fdc, + 0x78db94fd, 0x729fa7b9, 0x21678b17, 0xeae5d8ee, 0x3b714e7c, 0x7b46e170, + 0xfd8c7968, 0xefbf217c, 0x479f90b7, 0xd53ff8a8, 0xba3137ab, 0x3f2ffb51, + 0xdfe18a37, 0x53c26740, 0x3eae9063, 0x7fa3243d, 0x4aea784d, 0xf2a52f7c, + 0x97eb059c, 0x415fde8b, 0x4d79161c, 0xf3bbba44, 0x873c38f0, 0xc3bc32ea, + 0xb7f387b8, 0x2b9e169a, 0x8599e9d5, 0xec0a05a1, 0x2ae785cb, 0xde211e91, + 0x1397ee11, 0x934bf6f2, 0x13574e24, 0x6991fda0, 0xa2bd69cb, 0x64bf464e, + 0xfd12b062, 0xef768d84, 0xdae431fd, 0xe747bb1e, 0x2cea2837, 0x2389fec7, + 0xe7351248, 0x7bf90bf5, 0xd8e745e1, 0x1dc4847b, 0xcf402924, 0xe944de5c, + 0x6c6eff52, 0xcbe18997, 0xf857deb8, 0x5de95f3a, 0xd67e84ef, 0x5eb663fb, + 0x7517cfbe, 0xf5d61ae6, 0xd6b1f1bb, 0x44cf5d15, 0xdfce5f6c, 0x31372df9, + 0x9fe5abbc, 0xf4d5f1f3, 0xb82cf578, 0xf84a4361, 0xa185903b, 0xff78153b, + 0x3e21b0a8, 0xb3acd041, 0x5d56fea8, 0xfd61495c, 0xaaff7c3c, 0x329e61a8, + 0x7a47235f, 0xecfc14f1, 0xa22349a5, 0x81fcfa78, 0x1dcb699e, 0x1c14afb0, + 0xfe3b3e03, 0xe79cc564, 0xf0cbf409, 0x8e095276, 0x72b942ad, 0x3dd62ba7, + 0x788dcf94, 0x1b78e7ab, 0x35a32411, 0x97c54672, 0x4df1fdb1, 0xf9c17765, + 0xecf5f1f4, 0xe5fe8f75, 0x1a7c6c4c, 0x3076e8e1, 0x71e9a9f8, 0x2ffb2fba, + 0xeb978e08, 0x85fa9be2, 0x0abfc723, 0xd53bf527, 0x1c0eacab, 0xa37bb097, + 0x0417b9f5, 0x8cf8e8bf, 0xbe2a4e3e, 0x7e41eb91, 0x7c093951, 0x07c9ea7a, + 0xe5db6ac6, 0x840d27db, 0x85ed4871, 0x6fdd8f9d, 0xfd41a7f7, 0x21ef64e0, + 0xd15bca0f, 0x5dd7435b, 0x7768f712, 0xdfab5718, 0x935656bf, 0x4a5fc12b, + 0xc12b87ed, 0x05b5436f, 0xe6a8a3d4, 0x847d05e0, 0x7ac5f156, 0x83926a17, + 0x5656b3f9, 0x95bfa157, 0x0dc48258, 0xf8c23d7e, 0x42cc9c92, 0xd0e497ff, + 0xec8a01eb, 0x4dbf8377, 0x6591f7e1, 0x3d26bfc9, 0xc4d9ec1b, 0xbe06a08c, + 0xbc583957, 0xc594dac4, 0xb7438841, 0x38719f80, 0xeace37fa, 0xa517fbec, + 0xdd280385, 0xda7dcfa9, 0xe5cbe846, 0xfe8216c4, 0xbbf4d1b4, 0x74891e76, + 0x4c7dbade, 0xe2c9170f, 0x890f73c2, 0x8715bf70, 0x7282fd07, 0xc3973578, + 0xdc2eedcb, 0x645d567f, 0x8ea0fb42, 0x0b7ec3fb, 0x8b84307e, 0x84327684, + 0x257d40dd, 0xb0eb882e, 0xd0447ac2, 0x7798c3db, 0x22328bc2, 0x4025b13e, + 0x04789e3e, 0xe1200fc8, 0xf687a055, 0x0bbcea4c, 0xfd58a7be, 0x5fbf01b3, + 0x151c76a4, 0xe05a0fc0, 0x5ce004bf, 0x3c33062f, 0x62e3feb4, 0xa5ea0324, + 0x12b7a2d1, 0xc4117a58, 0xe735fb41, 0xce1dec2b, 0x9bec5e68, 0x64a968bf, + 0xfaf86f38, 0x2ff96d12, 0x0762beac, 0xf656fbec, 0x07e24d7e, 0x9ab9ca02, + 0x01773f5e, 0x71a9dbde, 0xd23d7f30, 0x21d5d005, 0x959f4fb6, 0xe809713c, + 0xf5951b3f, 0x5e1e6ea2, 0x76e25e5d, 0x53a5134d, 0xf4ab8bf0, 0x99f24231, + 0xae2e8e80, 0x78b5dfa5, 0xc15fa18c, 0x39fa2338, 0x47e7504f, 0x157a45c7, + 0xfdb0e5cf, 0x7b0f40d6, 0xa0ff3604, 0x0fecced5, 0xaf011412, 0x93c255b3, + 0x3c7cb056, 0xddf07f51, 0x3f55b7cf, 0xf2c15937, 0xcc0b966e, 0xc66ae767, + 0x5f6eccf9, 0xe5fe01dd, 0x0ba9edd9, 0xb6659ce0, 0x208ff2e5, 0x0e4723dd, + 0xfc4e41d8, 0xf9a3bd8c, 0xca2f23d3, 0xbc778a20, 0x43ef11b1, 0x71f9ce3f, + 0x80c8890e, 0x2b713f7f, 0xc21e4fcc, 0x5e27cdf5, 0xc1916f9e, 0x1c2dbd7e, + 0x9a3af9ba, 0xd0c5fdbb, 0xcd5a6075, 0x09791439, 0x716fe6d0, 0x5a2fa1e7, + 0x7de6d76d, 0xbb59e599, 0xdff81c28, 0xb82c90c1, 0x2dbae8ae, 0x9d750708, + 0xa3e226b4, 0xfdfc4e17, 0xbd2e1520, 0x7adfb6eb, 0xfb0bf82d, 0x2db36f93, + 0x71623e63, 0x465e6cb9, 0x45067d38, 0xc3915ef0, 0xf2e807b7, 0x1daf8761, + 0x12dca4f8, 0x21869349, 0x5f2184df, 0x4a2ffa29, 0x78f870a2, 0x8192ffa8, + 0x018e8f00, 0xbe67a417, 0xd5fce9ca, 0x83f7def4, 0xbe99d113, 0x66c1f986, + 0xb55b7a70, 0x9b8c4de3, 0x7b30f8fc, 0xf442a90f, 0xfa0f7f5c, 0x4b1244bf, + 0x57d355ef, 0x2de61fb9, 0x9d1f7a87, 0xc48673ad, 0xd5a33de0, 0x667af78e, + 0xfd3a8b64, 0xc0b6467b, 0xc63ad7e3, 0x4bd3a4de, 0xeeba7057, 0x11c40fdb, + 0xb059fb18, 0x55da3274, 0x24f7153b, 0x0dc1ff90, 0x4c16ce8c, 0x671089f5, + 0x808d613c, 0x1ff188fe, 0x87901276, 0x09e2ea0b, 0xb82f839c, 0xbc16717b, + 0xe1d95097, 0x3904eb69, 0xe0bc1219, 0xef164b47, 0x9d25f8c8, 0xd807c3d7, + 0x3bf90c3e, 0x9f0e9e60, 0x2bf1a1c7, 0x1955c977, 0xdbeba06e, 0x0b903e1d, + 0xbdf26ef3, 0x922d780d, 0x76b5fbc2, 0x3cdbbcc8, 0xf31f40b9, 0x4c3eac5a, + 0x51b2442d, 0x224f36b9, 0x15934816, 0xdf215922, 0xece7d4fe, 0x3bad86b0, + 0xec2c46d9, 0x80afe1fb, 0xacdf2e4e, 0xa63dd6e8, 0x51ff9f45, 0x119f3e9b, + 0x0eb3e7d6, 0x80b7f3e9, 0x87d1a31a, 0xe765ec0e, 0xd86765dc, 0x05e7c13d, + 0x7fc083d8, 0x37b9466a, 0x073daca5, 0x3ccf4dce, 0xf94134eb, 0xfd986f9e, + 0xc562d916, 0xbff6cbf7, 0x44b62363, 0xbad4c778, 0xd8cfca11, 0xffc0725a, + 0xfc63eb44, 0x4735dd03, 0xf3b1fd82, 0x0cced532, 0xcec49c61, 0x7b9c596f, + 0x04398b64, 0x7667b1e7, 0xd02cf53f, 0x832d99dd, 0x5e79ef51, 0xdfa09a08, + 0xaf0c7de0, 0x9d2e6c13, 0xacdb29fc, 0x3846ebb7, 0x73d53e99, 0xf10b994a, + 0xebd4974f, 0x48697dd7, 0x64ed1f9f, 0xd13e67f2, 0x73874f7c, 0x14aacf66, + 0x48278ba0, 0x5983fbcc, 0x9f7f264e, 0xed515a7e, 0x33bf916c, 0xd1493c46, + 0xa27b4f7b, 0x064b3fe7, 0xc0001c43, 0x7bf45862, 0xb55c6199, 0x7cb96fff, + 0xfa7ee44f, 0xc222abc8, 0xb17574e7, 0x57b89cee, 0xa6f6ad3f, 0x33ecd54c, + 0x93fbf585, 0xb85ea1e6, 0xd6be693f, 0x3072db2e, 0x738856e9, 0xdfe12cd9, + 0xfd9f2a4f, 0x121343e4, 0x02d8bbe1, 0x1f7285f3, 0x2f2d1fd8, 0xd51ea0b9, + 0x71b5333f, 0xe3f54523, 0xf66aa652, 0x974a1fd7, 0xbb4aefbd, 0xe5767c19, + 0x1d78dc16, 0x835977c5, 0x656a85e8, 0xfbff372d, 0x837b8018, 0xcb5cf78c, + 0xbef8c9b7, 0x0af1a079, 0x359413f4, 0xef879ebf, 0xe79fade8, 0x48e57985, + 0x44cc40a4, 0x904dc0d7, 0x81df6c9e, 0xfd95d5ef, 0x3c914eb5, 0x7d3d5f30, + 0x3f437a50, 0x7280d517, 0xf01e006e, 0x54f8c32d, 0xae11bbf5, 0x7b7d2125, + 0x17febe23, 0x33fa37a7, 0x63778b4a, 0x83d301bd, 0xca4877f8, 0xa3b95297, + 0x3fca2fb1, 0x38f8c5ac, 0x542838e3, 0xb0d0e735, 0x1f90797f, 0x271f7cad, + 0xc7872582, 0x79670e8f, 0xe80f377c, 0x197fd60b, 0xfb81ea99, 0x7c90378d, + 0xc2179f48, 0xe322890f, 0x6c3bf46b, 0x775f23b5, 0xfc9f3bb9, 0xf343d01d, + 0x18c73c18, 0x767befc4, 0xdef8c279, 0x0ff7faa0, 0x5f2cdcba, 0xf8c56eda, + 0x2b1f338a, 0x4196cf28, 0x7fd4175c, 0xd1326ad6, 0xb6cce67d, 0x4e219301, + 0xbd85abb0, 0x65ba7b2f, 0x7be564c0, 0xff2347f6, 0x31d6fbaa, 0x6fee95f8, + 0x1b7d384f, 0x15df009c, 0x79328e2c, 0x55465540, 0xeda93c0c, 0x0caa9512, + 0xb7221fb0, 0x991bbc3b, 0x720e93be, 0x053facff, 0xdc79f9ed, 0xae37b17f, + 0xd7e819e0, 0xe8faeb49, 0xe24384bf, 0x0fafa046, 0xee5def44, 0xb5f3d1e1, + 0xbc7ed985, 0x30564a4f, 0x4481663b, 0x4fd512c2, 0x1fbc8017, 0x8394798b, + 0x8c041a0b, 0x56b85a2b, 0xef781ebf, 0x0377fb54, 0x5e2fe18a, 0x9138870d, + 0x1b8b4c16, 0xb025e5f4, 0xfe30b87f, 0x4bcfcf03, 0x70e5f49b, 0xbdf41093, + 0xccefe6f2, 0x39f6e0b1, 0x7be7d751, 0x1f93a9c9, 0x8f8fca32, 0x5f5c02c4, + 0x909b5819, 0x702afdf2, 0x42ca6e77, 0xa59ee20a, 0x66165213, 0x04183be1, + 0x1645a7f6, 0xb2657412, 0x8003bc3c, 0xc9fc83ac, 0xf5825bde, 0x9487ef69, + 0xa1e1254d, 0x613ae8ae, 0xf272da7d, 0x5963c306, 0xe31e10bb, 0x8237de8a, + 0x95eb6a75, 0x3797f5f3, 0x837e759b, 0x84f3880a, 0xefd69538, 0x797ebacc, + 0x37dd1cfc, 0xe7e29589, 0x1bb95ee1, 0xfc5634ba, 0xa70e51f9, 0x4c2e6f87, + 0x15fcbe05, 0x388381e8, 0x3da97320, 0x0271c20a, 0x8e85b803, 0xcdeacb63, + 0x72ce7963, 0xf9d4ff96, 0x10fd5e55, 0x7ec9376a, 0x2058573c, 0xf70cbc16, + 0xfdba669a, 0x17fc025f, 0x12697c98, 0x246fa7f2, 0x652e47c6, 0xb3247feb, + 0x18aad2ea, 0xc78aa9f6, 0x782d0adf, 0xcddc17be, 0x76673df6, 0x3bfad644, + 0xee4c5de3, 0xc4e81dc4, 0x0ec8fe78, 0xae11ef01, 0x3de18e17, 0x78d7f5bb, + 0x29cfd808, 0x17206f14, 0x05640bd7, 0xdd9563bc, 0x978ef33a, 0x36d97f00, + 0x5a2a77d4, 0x0e158927, 0x77d33f5c, 0x708d55ec, 0x773c98ce, 0x33d02654, + 0x1bdcf75d, 0x83cbbbe0, 0x183aa5e3, 0x0f2ca41d, 0x0d1e2fa6, 0xf1dc17e3, + 0x18dbf012, 0x4d3fde1b, 0x2672b0a6, 0xf406ba60, 0xb1921497, 0xca77e41f, + 0xf8264f74, 0xb1761f5a, 0xc49a0671, 0xcf4133b9, 0x84f964ca, 0x46df057b, + 0xb875ae24, 0xc93364fe, 0x77c2f987, 0x602d13d0, 0x887963cf, 0x554a79e1, + 0x3c9f8c06, 0x4a89a59c, 0x5e82e318, 0xcedef151, 0xb89673e2, 0x25e3ca09, + 0x4e4a4d5f, 0xe95feda0, 0x952d86a2, 0x510caf53, 0x03b0e1f5, 0x623210f4, + 0xf5cfab14, 0x2c1925e1, 0x4d313dee, 0xbd5857d5, 0x9717d91e, 0x75f3f205, + 0xe67f17a6, 0x9c41c5f0, 0xec4a15da, 0x1c49dbb8, 0x3673814f, 0xfff8d212, + 0xc0beb303, 0x73811c7b, 0xecd2122e, 0x9b2ef007, 0xbcb37e36, 0x17be00f8, + 0x303a415c, 0x45a2b80e, 0x857a6f1f, 0x2ab8f62d, 0x99ce079d, 0x42ed1048, + 0xc0271f0a, 0xce0ab227, 0x057b8271, 0xce06aff4, 0x19a82429, 0x412e703f, + 0x679def9f, 0xad13f612, 0xdaf5f447, 0x247ac4be, 0xe305d3b7, 0x713bbb74, + 0x939c08bf, 0xafba9db0, 0x414c84f4, 0xdd6fea99, 0xc3de561e, 0xeb55a3df, + 0xcf75fdab, 0x977df852, 0x55dbf608, 0x8511054d, 0x9feda3cb, 0xbcb39fa0, + 0x45c23f7d, 0x7c2887a5, 0x81a824ec, 0x474d524f, 0xfb7944d8, 0x584d0fe7, + 0x4a52fa3d, 0x1f38075a, 0xf6ae2707, 0xa2e5a44d, 0xf6d7c749, 0x473e5eec, + 0x49b0f2f1, 0x2bc8fee4, 0xa89d4f57, 0xbdfaf3c9, 0xbe3f83ed, 0x47b3ca1a, + 0x1ecbf6b3, 0xcb0feaba, 0xa25ca8a5, 0x702b48eb, 0x4316f26a, 0x63f341de, + 0xa1b77934, 0x9e50d13c, 0x610fc862, 0xe19cbbf5, 0xc84bd134, 0x5ca687da, + 0x03dfc12d, 0x81cf0d4a, 0xc56bfb9b, 0xefe1abbc, 0xb364562b, 0xd95817bf, + 0x3859782e, 0x655f8313, 0xa76cf9ef, 0xc03460b2, 0x9065e3a1, 0x826de503, + 0x4770f41b, 0xe630b6cb, 0xd3479da1, 0x7bdd85ae, 0x86396f2a, 0x7fedfaed, + 0xf8f90994, 0x63ef51fe, 0x15c5f3bd, 0x78fae991, 0x19e2fef3, 0x26fe088f, + 0x3be8b8d7, 0xdedb5dbd, 0x37bdfe8c, 0x53ba472a, 0x8e51077d, 0x067fee1a, + 0x288e3e60, 0xbc70a89f, 0x7c59d47f, 0x31ddf0b7, 0xdb6047ed, 0x64f92fb7, + 0x7f91e819, 0x0e3138ad, 0xfb782af4, 0xdf8df610, 0x614ba10a, 0xf8947a1f, + 0x6f71852f, 0x3f78b8af, 0x547d913c, 0xde0c7cee, 0x87cffdb5, 0x7f0d5ee6, + 0xb3a8eeef, 0xa9fc2873, 0x52ae239e, 0x81d1c7c4, 0x4292f89d, 0xcb195c66, + 0x6a1ced0f, 0x5db7f9a2, 0xe2fe59eb, 0x2f20c7ce, 0xed632dc4, 0x150e74c7, + 0x2c3260dd, 0x726dfc47, 0x3ff7e6c7, 0xcea33972, 0xbee1eeef, 0xa42e0097, + 0x7037ed9c, 0xe542d0bd, 0xd3d29ce9, 0x7851375b, 0x1d85f9cc, 0xaea6dce5, + 0xfa65af1b, 0xe200b070, 0xbc39928d, 0xb9443f71, 0x90dea12e, 0x42607b0a, + 0xb4ce9f14, 0x17ee0f0e, 0x036d5597, 0xce79207d, 0x1a2fdc68, 0xb8acbe9c, + 0x4374d171, 0xe2b34b22, 0x8bae4cdc, 0x961fbc26, 0xf5138f7c, 0x77f15fa5, + 0x21df29ae, 0x5e38387d, 0xbb3173de, 0xf3173dec, 0x4e741c2b, 0x11de7ec3, + 0x222deb7c, 0x056824a4, 0x50d896bc, 0x91b5b90f, 0xd72a15ca, 0xebbcf8eb, + 0xfe8a5dd6, 0x5fc15b82, 0xfbbe1a3b, 0x47461352, 0x0cbafcf5, 0xed44779a, + 0xbe99bab0, 0xda7bed54, 0x5cac8d75, 0xe9755b95, 0x5fbabdac, 0x71b0d725, + 0xe9757f92, 0x5d875846, 0x8bf5e762, 0xb8dc8d66, 0x1bfff70c, 0x1fc0e2b2, + 0x82a5f3e2, 0xc961fcdd, 0x9fe81330, 0x861a7e2a, 0xd172befb, 0x73f29ff2, + 0xbd4f1516, 0x5b1c65f6, 0xea9102f7, 0x3fbd740f, 0xfd71fb72, 0xcb189f54, + 0x3e99b30e, 0x4cd74591, 0x5225f034, 0xfef838e7, 0x694e083f, 0x147feeb0, + 0xbc777f4e, 0xf73ef4f4, 0xbe61325e, 0xe84f4b15, 0xb870bdef, 0xcb0856ff, + 0xf79ad9c9, 0xb077e848, 0xfa76bf33, 0xce69c7c7, 0x53dce7e7, 0xbaa77a81, + 0x77cffb1e, 0x64dfc3e5, 0x51a7f234, 0x8efa3c2f, 0x3ff82d65, 0x282d2a8e, + 0x4b5e8f8f, 0x51c5fef0, 0xaa941efe, 0xa2fce6d7, 0xd3b015ec, 0x4889c536, + 0xbe09f71f, 0x7dc78054, 0xfee01e94, 0xa28f1ab6, 0xf175c7ee, 0x4085f5a1, + 0xc68f370f, 0x881eef73, 0x4b7a848c, 0x2eb8df99, 0xf0ed13be, 0x371ef1ba, + 0x07d0099d, 0x5b3231e2, 0x5d4fff41, 0xbab3a306, 0x3ef0cb92, 0x2097a505, + 0xe8cd9fb6, 0x41266eae, 0x766ea1bb, 0x959bd20a, 0x9f30ac84, 0xa927e8fe, + 0x10a3c586, 0x7b5637c9, 0x638c1d6e, 0x767b117e, 0x41378ee7, 0x456b5d8f, + 0x8950163d, 0xc9b51de7, 0x074a5f38, 0xaa5748c5, 0xd49bf67d, 0x0f68fdd0, + 0x5feed17a, 0xc3cdf4ed, 0xeed2fff9, 0x5837f981, 0x264b1ac9, 0x05643598, + 0x1f3e49ca, 0xc608fb52, 0x7ae5cc2f, 0x67c57be1, 0xfc7fa09d, 0xff504e3c, + 0xec0fa52e, 0x9584f9f0, 0x7ed7bfcf, 0xf9a9ec0c, 0x6277b2f7, 0x3e699ac9, + 0x9d05f9fd, 0xb9f8126b, 0xc47d4ff9, 0x87e37409, 0xffe82e76, 0xff709cbf, + 0xbb2f7fc6, 0xb4824acf, 0xfb68a8fd, 0xc1df81fb, 0xf9b22e5f, 0x27bb6a93, + 0xf7a0fbd6, 0x44bf71c7, 0xed3e23ed, 0xc638ea78, 0xf8bda97e, 0xc28bc000, + 0x8cf70c3d, 0x7f64bf22, 0xdf38c097, 0xa0f22544, 0xa9cf9695, 0xefe1e316, + 0x3a97fb88, 0x7ceabd71, 0xae4726e7, 0xa1847f44, 0xcaf6e3ff, 0xab67f01c, + 0x57b90ff6, 0x5c21ef63, 0x845e6894, 0xb411f87b, 0xe77cfaa3, 0xeed1b1f6, + 0xb35be424, 0xdc6f5eb6, 0xcc3047be, 0x4795d39f, 0x7e6f0090, 0x28af1e7e, + 0x5ef83991, 0x2ade6194, 0xba73773c, 0x08c2e953, 0xc0fdddef, 0x1ce9513b, + 0x97fafd0a, 0xc64e119a, 0xf4fdd5fe, 0x1fe52b11, 0x82f5774a, 0x7f5af480, + 0xc7f71db7, 0x49e46b1e, 0xefb8d7bc, 0x7777c46a, 0x4103cd89, 0xb5528f5a, + 0xf633cf1d, 0x9e8cf3b1, 0x81239d91, 0x9ae9ba9f, 0xdd3f147d, 0x418d8aaf, + 0xd5049d41, 0x37155e8f, 0xef77fd02, 0xb3f586be, 0x89dececc, 0xbdc30806, + 0xaadfe0c4, 0x81f39fc1, 0x002fbd89, 0x6b458f7f, 0xd1bdc377, 0xbca8cce2, + 0x180281e8, 0x573d4dbf, 0x38e097f2, 0x3df0dab7, 0xe0934a81, 0xb2abbd03, + 0x67bc32f4, 0xd1dff840, 0xa568e551, 0x99a3da89, 0x34afbe51, 0x31723fbd, + 0x491293f3, 0xf5a347e3, 0xb03b045e, 0x03b6b2dc, 0x49bb51ef, 0x6843eff4, + 0x6b95a5fc, 0xf3037ccf, 0xf8356caf, 0x83fe0c11, 0xa53d2d52, 0xf504e947, + 0x531f907e, 0x775bde09, 0xbf3dbcf2, 0x018efd03, 0xf030ce7e, 0xd6d77b00, + 0xc042dd99, 0xc9381aaf, 0xed0996f4, 0x0ec1078d, 0x18efcf8f, 0x700dcb0a, + 0x9ef19f3f, 0x75f6f8c9, 0xaa95d822, 0x6bb1a3be, 0x8c61bd2f, 0x4df76536, + 0xf1864ec1, 0xf013e13a, 0xc9f6c48d, 0xf74803ff, 0x800023ad, 0x00008000, + 0x00088b1f, 0x00000000, 0x7dc5ff00, 0xd554780b, 0x733ef0b5, 0x9992bcce, + 0x9264cce4, 0x0927de4c, 0x27010084, 0xd4500421, 0xe6a2bc21, 0xa2d101da, + 0x3c2438b5, 0xa0992112, 0xf7ad8b95, 0x24844032, 0x111a0804, 0xa284e028, + 0x17edaf62, 0x04c0622c, 0x16c45407, 0x6b5ec5fb, 0x46f7f6d5, 0x485ca008, + 0x6c5cb046, 0xad7bfcb5, 0x67324fbd, 0xde952892, 0x1e9f7cde, 0xecfbd9f6, + 0xaf6b5ac7, 0xa5b3def7, 0x90d74b32, 0x44b44849, 0xc8485488, 0xbb11a6c2, + 0xfe840957, 0x5b6673b9, 0x862a7909, 0x83c9e03c, 0x33c8abb2, 0x72599086, + 0x9e3c8c71, 0xb1722390, 0xf7878e59, 0xda1e9181, 0x08e3f88e, 0x55c84499, + 0xe075bbf8, 0x24203693, 0x625dbfbe, 0x8d7e4d76, 0x0e76e865, 0x83a7fd03, + 0xd8b6d090, 0x8f986ec0, 0xd1796024, 0x0d2df46f, 0x613a3f38, 0x7687df3a, + 0xfe600666, 0x40c9a415, 0x4a5909b2, 0xd2220602, 0x8fe22676, 0xda4fa029, + 0x173e962c, 0x2512356f, 0x55dfe097, 0x40655ffa, 0x6ccd265b, 0xe0a54b5e, + 0x90862111, 0xfb13a425, 0xdb57b259, 0x1234e96e, 0x2afad2b4, 0xc3460913, + 0x5f5b55b3, 0x0f38424d, 0xa355db5f, 0x44d27fa6, 0x36db8508, 0x3b662133, + 0xf99dc9cc, 0xe87f9d38, 0xb76bbd6d, 0x6869c842, 0x870fd492, 0x38e2d88e, + 0xa8947380, 0x568675c3, 0xd3760745, 0x48eb7675, 0xb70a3ec5, 0xc0f2364d, + 0x59ecfa6c, 0x0d8738a9, 0x9d8c7043, 0x3c20663d, 0x2b990e1b, 0x6e7f1402, + 0x55708759, 0xd5895fdf, 0x40cbb963, 0x7d695a2a, 0x5fda6ad1, 0xf57d7f5e, + 0x7c2f163d, 0x70165337, 0xbbe780de, 0x0d64cf00, 0x3ded077e, 0x71a8fc74, + 0x777ea9ec, 0xcdfb5f67, 0xfe14df0c, 0x952dff30, 0x27802d51, 0x0493b922, + 0x04759407, 0x63cf2ee9, 0x0fefd2f0, 0xfd7e7405, 0x5849f40d, 0x31ad7f7b, + 0x97b62cf0, 0xe5a0ade7, 0xb9e69f43, 0x489c281a, 0xd03e7bae, 0x5173d2c1, + 0xf1c1d00a, 0xff5f3f73, 0xf17f5a5b, 0xa4628353, 0x36800bf5, 0x090f1e28, + 0xe7684ade, 0x3c8a37bf, 0x352ddf4b, 0xbb8c3710, 0x8088c0f4, 0x807bf69f, + 0xb0feb196, 0x1a59c715, 0x90b6dde3, 0xa5f4b3f6, 0x40a51778, 0xf03eaaf2, + 0xdf5073c2, 0x4b3d7661, 0xc51a5dfb, 0xa1e971e8, 0xbe7efc14, 0xf014bbd9, + 0xfc0c6c93, 0x7be92fc7, 0xf5d19af2, 0x245c7d2c, 0xff3045c1, 0x0166ad8b, + 0x75849dda, 0xad27d2c5, 0xed5d6013, 0xbfb63c74, 0xefd21692, 0xb227d54e, + 0x9d387175, 0xe91a30da, 0x8d9e8b79, 0x60283fe7, 0xcf7a93fb, 0x3e5a248c, + 0x6bbe72f9, 0xf5eaad15, 0x4a068218, 0x4b4dbe7f, 0x84b1904e, 0x5d94eb94, + 0x38722700, 0xe2abe71a, 0x7171b7c3, 0x1efbd429, 0x124eec7c, 0xf4fef433, + 0x310919b5, 0x0f6bd3f5, 0xfd03a509, 0x6ac8af6f, 0x7b71d20d, 0x44ba47da, + 0xe45275ac, 0x5990fa53, 0x833d6edb, 0x8f43a86b, 0xfb5af4fb, 0xb44af587, + 0x5bfc1f1f, 0xf0dd2784, 0xbc017eea, 0xc1c59787, 0x747f14ca, 0x8943bebd, + 0x7ac8af08, 0x0bbbd5b3, 0x13f553f8, 0x0af1f3ff, 0xf9086f84, 0xc78a6919, + 0x1de7467d, 0xbbefd134, 0x5f7159b7, 0xb4a63c65, 0xf77e0175, 0xb69d70db, + 0x0ad16e69, 0x58991de5, 0x314571be, 0x86c71539, 0xaf940925, 0xa4ffa44c, + 0x49122efd, 0xdf00a9ad, 0xeda36ce7, 0x869cbccf, 0x24645cf8, 0xcfba2675, + 0xebc32349, 0xa7ca1699, 0x8dca7c28, 0xc967c85d, 0xe804087f, 0x85abb685, + 0x20e94b76, 0xe1030549, 0x034b7c06, 0x395840b7, 0xb5abce8b, 0xff742445, + 0xfaa7ca10, 0xcfd59fd6, 0x693f80c7, 0x337f27be, 0x57e8e16a, 0x63ee2df9, + 0x59c4a8ba, 0x51f9fa63, 0x18e7ac47, 0x12c3f3e3, 0x44677e01, 0xf29972ef, + 0x8fc4c5b7, 0x0492b1fc, 0x478ea9f1, 0xbbe32df9, 0xe177c626, 0xfc0d7519, + 0x8ad241f7, 0x380ab37c, 0xf77c60d2, 0xc777ca31, 0x0977cd0e, 0xb807c9a9, + 0xb8b7eefa, 0xf803ce00, 0x2aefe72f, 0x8c0d131e, 0x58f8df0f, 0xfd792440, + 0xeadd7870, 0xcfa0e73e, 0x06e242e8, 0xc0fbe7fe, 0x806e5264, 0x516487b2, + 0x4eb0ecf8, 0xad027ef9, 0x0dc449f7, 0x93ba337c, 0xfbe85bb8, 0x87e2669d, + 0x2826a6fe, 0xc0d38fd8, 0x792f42e8, 0x2fad3e48, 0xea0cee2a, 0x13c49f60, + 0xb5bdf819, 0xd3bff593, 0x802bbf4a, 0xaefc04ef, 0xa9137bef, 0xbefb0a8d, + 0xe91990f8, 0x6b41f2e8, 0xd0f288c0, 0xfda3619b, 0x48d1fc25, 0x873dbd60, + 0x7be7c8ac, 0x2b6e64f4, 0x4910ef6d, 0x73e22b4d, 0xd827f62d, 0x27e9f132, + 0x680429c5, 0x053db857, 0xab2132b6, 0x65575f91, 0xf283de76, 0x81519f76, + 0xd6d97c7d, 0x74ca1cb5, 0xe5a7e23c, 0xdb05652f, 0xcd4ff6f9, 0xef7d09ff, + 0x0c5c58f3, 0xa07cdeba, 0xa3f8a317, 0x6f144c7b, 0x42c7c433, 0x5679d28f, + 0xe06459a5, 0xfe32d3c7, 0xb4bdfef4, 0x3d7ed9fc, 0x9fde0231, 0x64973a9d, + 0x2a27cd0d, 0x5d93fa03, 0x64baf461, 0xd55cb6af, 0xdafb2daa, 0x9b54e5b4, + 0x1a2671d5, 0x2aeba6f7, 0xb1a327a5, 0x3a16d3e6, 0x46abe35f, 0x967f9be4, + 0xe03699bd, 0x31d0ba0b, 0xe331a380, 0xe02f58fc, 0x0173fdb9, 0x1b4a469e, + 0xbe0c799d, 0x9b2eafb0, 0x79c867e7, 0xfe97cf43, 0x47087499, 0x93c189b7, + 0x9b1f07f1, 0xee57dd12, 0xf5d08ecf, 0x251d9a2f, 0xee37c6af, 0xa045f1d2, + 0x891ce0af, 0x9f6deb6f, 0x5db16309, 0x5989f225, 0x579d1db4, 0xb7c656c5, + 0x18ce9297, 0x54d50fd8, 0x145131af, 0x78636c3e, 0x2a1b5258, 0x367fd20a, + 0xc2464bdb, 0x25afa53c, 0x1d7fe00f, 0x87a61bf4, 0xb1d366dd, 0x72cd7bf6, + 0x368e06b7, 0x96d7d94d, 0xed877724, 0xff7c2597, 0x60904513, 0x7af94b3d, + 0x6f782f7e, 0x9955f803, 0xe8530cba, 0xfd7eb7f8, 0xc5efca05, 0x75c6ca2b, + 0xdbd70b8f, 0x1757c88c, 0xf7c5ea3f, 0x399b6faf, 0xcdb7d71f, 0xcfdc00ac, + 0x9e9014ec, 0x025aa717, 0x5bcffa26, 0x5b9f4c6d, 0x8413bf4c, 0x848c7081, + 0x331dd9db, 0x6747409d, 0xdfcf1b09, 0x59e4e4ca, 0x9b2bc299, 0xcefe81b5, + 0xebbe31b6, 0x33f33adb, 0x778b4fe0, 0x67902e8a, 0x1aeac3a4, 0x7d3ca04e, + 0xf40b42e4, 0x0a6e2977, 0x6bbcdf6d, 0x7be22cba, 0xfd8013d1, 0x6f3bb923, + 0x5da5efa5, 0x78df5013, 0xcd91a763, 0x0e7a66d3, 0xd7eb71d6, 0x92c7ea22, + 0x2f41788e, 0x47b8366b, 0x76557ec2, 0xf0033b3c, 0xb2567672, 0x42ffdb0e, + 0xc3c03220, 0xde0122b6, 0x0f24162f, 0xad8acfec, 0x72e1a595, 0x11136cd9, + 0x1e32535f, 0xe0b2e84b, 0xe407ba7e, 0xba4ed554, 0xd9fc607f, 0xaf7fbd1f, + 0x3d3f7c23, 0x6174445c, 0xbfc77672, 0x5fc13d20, 0x34f808b0, 0xeef5c583, + 0xbab4632b, 0x80726a2f, 0x5d5e2e5f, 0xa20f2393, 0x8bedf7bf, 0x8e1f741d, + 0x4d836426, 0xb0755720, 0xfd1aed31, 0xdfbd2876, 0x0373ab92, 0xe22e4ddc, + 0x133e967e, 0xa0bf548d, 0xa025f07c, 0x1a78788f, 0x97d23e10, 0x877ded0f, + 0xcd926bae, 0xc7a053fb, 0x07cee20c, 0xb9212bbc, 0x005baa98, 0xc80fd462, + 0xb7d3230e, 0x6defa624, 0x81cf2789, 0xfb8ea0be, 0x1e2fe84b, 0x1b1ec2f9, + 0xc3e7b7ed, 0x5c018eaf, 0x8fcfd3ab, 0xbbecf905, 0xa14185f2, 0x0bb4b5eb, + 0x2e2dafc8, 0xf17a010f, 0x0b22cfb5, 0xacf9faf2, 0x40e4c5cf, 0x6afebae4, + 0xcfb67a63, 0x4e7ec211, 0x6dfed9db, 0xdcfa31b6, 0x002a22be, 0x23bb75fc, + 0xff498660, 0x7c94fbbd, 0xc538a545, 0xe189a573, 0x57e7b4d9, 0x3be8116e, + 0xa1c3c820, 0xd1fdb0ac, 0x202f315b, 0xdb3e71d2, 0xf2c7ed93, 0x912e29fe, + 0xfcf659d6, 0xe00b2eac, 0x4177a6d4, 0x2bab8b7b, 0xd9f7d606, 0xb031539e, + 0x223d8abe, 0xf022bbae, 0xbcc2c279, 0xbaf0be7e, 0xc00dfde0, 0x4b04388b, + 0x6cf87f38, 0x0584a5cf, 0x98395416, 0x1c1c2c7c, 0x29e4472e, 0x5bb7809d, + 0x3978616f, 0x00630bf7, 0x3339def8, 0xfc615f95, 0xc9959cf6, 0x263693b3, + 0x4d69091f, 0x57d37907, 0x07573fbe, 0x6648ffe3, 0x5a1877eb, 0xfe3f61d3, + 0xe7eda0b7, 0x091d3ac1, 0x595ede50, 0xf9434147, 0x5e17b9d1, 0xff7e0749, + 0xa4afb3d9, 0x2fcd8597, 0x79f53bf2, 0x9aedc6de, 0x26dda7a6, 0x51195e3a, + 0xc2a60bc7, 0xe32e6578, 0x485fc027, 0xdf7774dd, 0xcf62c9be, 0xab64f6f0, + 0xaf60f91b, 0x1d00a8cb, 0x56f5dfaa, 0x804db944, 0xfe426217, 0x062ed657, + 0xdb9fd08d, 0xfa01cc3d, 0x447dfab6, 0x4638aeff, 0x809b424f, 0x5e746976, + 0x77f1f908, 0x2d4ef7e6, 0x7f9e293e, 0x32ae7801, 0x10a58e85, 0xc0030fa4, + 0x916d50cd, 0xac253e40, 0x7a15f461, 0xbffa8744, 0x0169d921, 0x4e6b767e, + 0x6e8ead54, 0xcc544744, 0xa7f54258, 0x6c5ce4b4, 0x74662fef, 0x81204fef, + 0x590c0235, 0x96bf2023, 0x3a9c5e99, 0xb40dc891, 0xd33b3df8, 0xb5c49c57, + 0xbc46cc55, 0x507fe00b, 0x05caa1e1, 0x8fe01fa0, 0xd21304e7, 0xa02ed08f, + 0x5aea289e, 0x43bf41e7, 0x5d9e53d1, 0x3d1953b5, 0x49ff95f5, 0xe76454f4, + 0x9e803bf4, 0x93d20abc, 0x3d3834d3, 0xbbf90229, 0x07bf13da, 0x0e44acec, + 0xef9c4daf, 0x31311e84, 0x19050abf, 0xf794b7ac, 0x04b26a57, 0x2e1f9045, + 0x30aef9fd, 0xd507627b, 0x494ec16f, 0x3e9e7d02, 0x57ccd653, 0xb3a46f10, + 0xe8daec0b, 0x8f942609, 0x999d75eb, 0x8e24afa0, 0x7407d9aa, 0xaf2f3891, + 0x67da0d60, 0x079036a9, 0xbfd15b20, 0xd3d8a2b0, 0x2fa6171d, 0x2fa80874, + 0xc6ea3f54, 0x99db53f7, 0x661be07e, 0xd7d77d40, 0xcf01f826, 0x00431ed5, + 0x817aa0f4, 0x1bfc01f9, 0xefd80acc, 0x156536cd, 0xbff34fd0, 0x5d3f2e29, + 0xf9806f47, 0xd7497a13, 0xbd009fae, 0x3ed05855, 0xb605b66f, 0x7776822d, + 0x03bb61e7, 0xf8d9137f, 0xdf8e09c3, 0x7a8adf9c, 0x0a6df37a, 0xfc7003f3, + 0x2772cf35, 0xa81f40d9, 0xe6e7eed3, 0x9d927716, 0x52b5efbe, 0xcaf1d0c0, + 0x8788cd1a, 0x99c19164, 0xfc989ac4, 0x4c17c819, 0x8984f700, 0x4f4d311c, + 0xb7d3bea3, 0x80a729cf, 0x6faf3272, 0xd0e3a4ce, 0x3cf35879, 0x9f79a099, + 0x3c7e5a6a, 0x024fd28a, 0xc46e87f8, 0xebd07e26, 0x564c61a3, 0x4f70c376, + 0x9244e8e9, 0x86cef6a1, 0xcac39369, 0xf7ff7dbc, 0x69f6efff, 0xfb7728a9, + 0x54da61ea, 0xb765ab1e, 0x9d6bce99, 0xa25ebfb5, 0x4da9aefa, 0xd7fbdf60, + 0x8a9d3edf, 0x1d415ee8, 0x377aceff, 0x44cca9f8, 0xfcf85e33, 0xf5fe88a4, + 0xa28b7fb4, 0x02565fb6, 0xa0553dfd, 0x73aedf96, 0xd26df9d3, 0x9043fb6b, + 0xa0a1eff2, 0x4f8be78e, 0xdc9c686a, 0x3d5017af, 0xdf1f6021, 0xfbac1faf, + 0x06e9b4a8, 0x7cb4563a, 0x577200c9, 0x873ef395, 0xe447fa80, 0xef897d7e, + 0x57ccefd7, 0xba3d5187, 0xbf47a348, 0xdabe4764, 0x24b60335, 0x6f903fb5, + 0x10f31efb, 0x3ea8e7d0, 0xfa8ec072, 0x4733f9c8, 0xeccf7d68, 0x514b1cbf, + 0x79b2dda0, 0xaefaf7a0, 0xbeb74848, 0xa04062bd, 0xfbe26b74, 0xc0f1ca85, + 0x9e9fa170, 0x9d39941e, 0x0744fcda, 0x8c21df74, 0xd57d23f7, 0x714ddfa4, + 0x3ee71299, 0xb7ef8f62, 0xfdd7231b, 0x0fd99d91, 0x6de2dcbe, 0x1effd039, + 0xd09e8081, 0x61327b90, 0x9f4dda01, 0xfb0c2c24, 0x29edb2ae, 0x5ee56784, + 0xfc70a0fd, 0x1c222ec8, 0xecbe0fab, 0x2e71be06, 0xa84f2020, 0x37f50290, + 0x854572d2, 0x5241340e, 0x2f7f9818, 0x35cc8fac, 0x7d74e190, 0x409bd041, + 0x977bda8f, 0x375846ff, 0xafa04ffd, 0xa1167bb6, 0xd73edd3c, 0x30992164, + 0x0865b2cf, 0x0dca3907, 0x2dc86870, 0xaa71824e, 0x4590cd67, 0x1c7aa7a8, + 0x7a3f57d4, 0xd30c405f, 0xf4da1b03, 0x14e7a025, 0x57ee7d51, 0xf669de74, + 0x745c4bdb, 0xfb88a71f, 0xe5a61ff2, 0xf1f0432d, 0x6e4c1c47, 0xff1e0ad4, + 0x5fd10af7, 0x6ffdc247, 0x6f4c6d19, 0x683768bc, 0xed17affc, 0xd9377e12, + 0xc81539df, 0x15d4b0e7, 0x8fb4fa0d, 0xfb073fb8, 0xca2c7899, 0xc62788b3, + 0x152b1c8f, 0x1c992bf4, 0x806feb5d, 0xda12c9fa, 0x7aea442f, 0xa9edc612, + 0x081ab877, 0x7e5007df, 0x9eed0f34, 0xabde71f9, 0x5c454740, 0x3839ed4f, + 0xaf2cbf33, 0x7faaef5f, 0x0d581ad6, 0x3caad4fc, 0xf4fc0251, 0x24f9094b, + 0xa73a8531, 0xff2a7ed2, 0x1b7ec76a, 0x7151bda2, 0xe6f5fe74, 0x81d03d40, + 0x76c445bf, 0x20a6d98e, 0x73d9f3f4, 0x2fd016d6, 0x02268ef5, 0x15cd4c74, + 0x1c9887f4, 0xf2d0a21e, 0x497cff54, 0xa1117900, 0xbf054ccf, 0x0e2bda11, + 0xf3162bf4, 0x529c31fd, 0x6e1319c1, 0x71abda85, 0xf1cdfafd, 0xf048e6af, + 0x747bd552, 0x9de7e626, 0xc08a3736, 0xe86d64f8, 0xcafc0e98, 0x7a024e8e, + 0x80ab5570, 0xbee554e3, 0x65bb0064, 0xdfdb2b49, 0x50676e3e, 0x5e83a5f8, + 0xcd171d91, 0x465acbf5, 0x58f3a4ef, 0x45f9c00a, 0x68424f86, 0xbdb86b3b, + 0xd5d98ab2, 0xf7033fbc, 0xbf715787, 0x58849511, 0xd54e363f, 0x67f35633, + 0x71f27b13, 0x6e9d08b7, 0x2f99e011, 0xeab6fc68, 0xe31c7a73, 0x4347b13b, + 0x86ff6033, 0xff817d28, 0x6b309b68, 0x7d749bd9, 0x728fc6db, 0xa4e60a81, + 0xc01624e4, 0x148a4a7b, 0x9f6d85ee, 0x21ba00cf, 0x6bf70425, 0xb114db75, + 0x400dc78a, 0xae8c485f, 0xc4fa8169, 0x3e517207, 0xfc1f1f83, 0xb87077ff, + 0xff985926, 0x9fdab9ce, 0x8c1e50f9, 0x26f659ef, 0x0a263f8c, 0x148915e3, + 0x3e3b5637, 0xe57fc0eb, 0x4047f924, 0x954b3afe, 0x1a8f9802, 0x89d78a37, + 0x43cacc0f, 0xbb658e3e, 0xa6ef704b, 0x6ce3bbcf, 0xdf6a2eb8, 0xe17cc095, + 0x0ddb807d, 0x4e274760, 0x7187c9ad, 0xcf044e21, 0x84a0a49e, 0xcf2a68fe, + 0x6d3a059f, 0xaf00ca33, 0x3eb7b6d2, 0x6a5b7900, 0xe822ad22, 0x4b7a113f, + 0xf35dcc56, 0x2f7b6e80, 0x38f5d99c, 0x03eeebcc, 0x47e22f2e, 0x7adc8fab, + 0xcfcbd30b, 0x80ad1b3d, 0xf39bb91e, 0xb23faa6d, 0x982fc138, 0x47a9191d, + 0xb5a7123e, 0xffcafa4b, 0xcd923d70, 0xf7e74fcf, 0xf77f186c, 0xb7afbb71, + 0xc80c62e2, 0xf47d55af, 0x517fe546, 0xb6529ebf, 0xd813fa27, 0x45767d67, + 0xb5223e84, 0x840538b0, 0xdaef90d9, 0xe2fe3c0c, 0xff07ce76, 0xf9072d87, + 0xa2e7f1cf, 0x173740fd, 0x97a8cd5b, 0x10433649, 0xb2fb55e6, 0x8013a031, + 0x7578720f, 0x818ab8f0, 0x39ec6bc7, 0x0714280a, 0xfbe41e0c, 0x2cf497fe, + 0x781312ae, 0x5e5a39e1, 0xc789387a, 0xeff6085d, 0xf08d183f, 0xc4a51a5e, + 0x7f4bff42, 0x9e20471d, 0x03c74bd2, 0x7b37cf3c, 0x4d780a7f, 0xc9feb236, + 0xc585466b, 0x36398279, 0x0096870a, 0xe54effd3, 0xba0682ea, 0x17d016ee, + 0x3546dfa0, 0xd9d6c2fe, 0xc58521bb, 0x0119400f, 0xfb9eacbb, 0xcab8d5e9, + 0x2b87e661, 0x5393f1e7, 0x033d17b3, 0xa15ab4a1, 0xb4ec04a6, 0xd0530dcb, + 0x89fcbd6f, 0xaf2cf859, 0x17dbfad3, 0xaf7c1a91, 0x3f5527c6, 0x19711977, + 0xefdcfe98, 0x7d51d43f, 0x8a93a946, 0x12667e41, 0x03c83579, 0x37b14fc5, + 0xe96b3e81, 0x81789413, 0x93b69942, 0x80511dea, 0x3ab575ef, 0x5afe5b94, + 0xa9da1b9d, 0x1c56f2f4, 0x57fd23f3, 0x5097f31c, 0x1c600750, 0xe7ab59f5, + 0xdfde7efe, 0xc20ba22a, 0xe7b02753, 0x192a593a, 0xfdab7e4c, 0x4c6bead5, + 0x4e6f4053, 0xfb3fa1d3, 0x173dc1b2, 0x1cf6c5fd, 0xb5ad53c4, 0xd584aea6, + 0x6cba5ee3, 0xfeb0790e, 0x96298966, 0x3f03b144, 0xfa6388ed, 0x16dc2445, + 0x91cb6936, 0x80ca9071, 0xbc4e5cb6, 0x59b29223, 0x7dfc20dc, 0x9767e707, + 0xbc39321b, 0xbbe0065d, 0xa557faea, 0xd2e9b832, 0xad2b33d8, 0x41d02e78, + 0x3285f816, 0xaafcc9e1, 0xff382574, 0x021d9bac, 0x7cc447d2, 0x9e8c6d6b, + 0x0fccf5fc, 0x3fcef7f9, 0xe367de72, 0x763ef812, 0x56be213b, 0x5e301b2e, + 0x12fead7a, 0xdf6b4393, 0xf1ff95f6, 0xe7b32df6, 0x2fc645eb, 0xa97c8c88, + 0x396b664c, 0x0b9eb825, 0xd50b7bc2, 0xf51d601b, 0x91f00162, 0x705977a9, + 0x2987d51d, 0x55f5a11f, 0x83a5758f, 0xee2eaf5c, 0x80bc81ca, 0x6cc2f848, + 0xd19f9525, 0x6a0e6576, 0x50de808f, 0x0d878da7, 0xd3ba038c, 0xeec1e31c, + 0x2defb539, 0xccfb5f90, 0xbfe8bf28, 0xff61188e, 0xbe44cc1f, 0x3bc589f6, + 0xbe3ee21c, 0xe7aee0a8, 0x618f4133, 0xbb55547a, 0xc4f405b1, 0xf8b0dab2, + 0x51affc1a, 0x75236f1b, 0x93bbf476, 0x8afbed66, 0x0ddf111d, 0x2135bf88, + 0xbc18b65e, 0x53bf6123, 0xf1f18439, 0x023a950b, 0x5d172df8, 0x5d48408b, + 0xf3f56b30, 0xaf86560b, 0xfe550e69, 0xcf0072b8, 0x7801e57d, 0x9e00e576, + 0x1bc475cb, 0xe0154fde, 0x2977e299, 0x9785f3c7, 0x9e00e427, 0x909befcf, + 0xa2de7803, 0xbec3726f, 0x4b7b2599, 0xd3dd8e00, 0x415fa83d, 0xd1f613bc, + 0x7de3d2b5, 0xf464f37d, 0xf390df78, 0x5bf8c7fc, 0x8b8f9286, 0x95a1e6fa, + 0x92830e8f, 0xcca0fc0a, 0x3946fc64, 0xfa837f09, 0xf4464cf3, 0xeafe1c7f, + 0x1bcc46d2, 0x3f511768, 0x2c3bfb51, 0x3f41b379, 0xd381fc3a, 0xee8617e5, + 0x8afc0adf, 0xe0fcffc5, 0x02ed5167, 0xe48cbf55, 0xfbe63fc7, 0xfdc3b37a, + 0xd83bfd99, 0xb8ffaaa7, 0x0531b782, 0x77bd312e, 0xfe62e08f, 0x27f456e3, + 0x97cc7757, 0x69fc5fc1, 0xab8ff980, 0xff47ce5f, 0xf5e06571, 0xdfc80a60, + 0x7b064176, 0x27cf72a4, 0xfd2c8b31, 0x73b52f76, 0x886e809b, 0xfa471b49, + 0xa62a7034, 0x3ef382dc, 0x768ef30d, 0xf7400c84, 0x23fed4d5, 0x52d54974, + 0x5bf418e8, 0x17a820ed, 0xed69b614, 0xb8054a41, 0x031eedee, 0xededddf2, + 0x75f80042, 0x999bc182, 0xa48d720a, 0xe40718ca, 0xc3976cfb, 0xe8f301dd, + 0x03bb6b8f, 0xa33cb08e, 0x48b16dae, 0xe27a5dbf, 0x6d9f8196, 0x267e72b3, + 0xf3fb7f21, 0x21a05b0e, 0x73f86f4c, 0x9509e980, 0x4491be6a, 0xd7c51282, + 0x0fee39a2, 0xefc0df01, 0x3efc1183, 0xa3c6acbc, 0x3cfc4097, 0xde1dee22, + 0x1f8e2fae, 0xf4d6f716, 0x95f26a43, 0x5bdc6d42, 0x7667ef5b, 0x2b0fdd33, + 0x57e9fa0a, 0xbf4a83c5, 0xed1fdcd5, 0x16b938ab, 0x26d7d7e8, 0x2f5f60c8, + 0x5dfa3175, 0xe32fed4a, 0x9dfb81d8, 0x0dfa52b4, 0xed4377e3, 0xe4228fff, + 0x7bff47d1, 0x3b5068f2, 0xf8df74fd, 0xebabdf6c, 0x7df7fd57, 0xd8176ceb, + 0x57588cbe, 0xe91adda4, 0xceed5777, 0x5f87e56b, 0xafc3f045, 0xa1f88ffe, + 0x7e287e29, 0xfc6b8da8, 0x7ff0fcdd, 0x4cf1be39, 0x3a31d3c7, 0x332a2aca, + 0xd7a64efd, 0xe2f135b9, 0xcdc5a219, 0xcb22a6e2, 0xbb8c8897, 0xdc78332b, + 0xd7e7ed9d, 0x5f11165f, 0x5c3e3c55, 0x417561d5, 0x62cb0ad3, 0xc646cf8c, + 0xfb241f4f, 0x228a0066, 0x614ba8e3, 0x7b7f671f, 0x9e3f353c, 0x5ce947c5, + 0xa14f2132, 0xdfcb58a8, 0x8a5cb75f, 0xbbe186f3, 0x021a8f38, 0x49b5d083, + 0xd87b13f2, 0x99e35bfb, 0xcf3afd3e, 0x481a71e7, 0x6ca1e41d, 0xc1bb46b2, + 0x58ea718e, 0x9c4a51be, 0x78fc4a67, 0x9e1cefe0, 0x744fbf07, 0xe8cf2e14, + 0xf89f915b, 0xe02e2cab, 0x471faa7f, 0xf7077fed, 0x9d2b5e83, 0xddaf1bdf, + 0x7fe57df7, 0x572fbed2, 0xe37bfbc7, 0x6c295b76, 0x2081fb34, 0x38809efd, + 0xba40e653, 0xa19faa1d, 0xbc7977e8, 0xee3c5967, 0xcc58f73b, 0xfe46bd9f, + 0x3a185d12, 0xb222fe05, 0x7f80a8df, 0x2825fc13, 0xb8931b17, 0x022aeebd, + 0x2ebe4338, 0x0c7d6be4, 0xb4349cff, 0xb7d8d8fe, 0xd8fe99ff, 0xe907fe57, + 0x9ec8378f, 0xeeceb08d, 0x901cee29, 0x74aceb6f, 0xbe1760fe, 0x768cf2c0, + 0xee7d1998, 0x925d1810, 0xe4d77115, 0xaf13d977, 0x867b9fe5, 0x2efff79c, + 0xa7fd6cff, 0xc4bfcff1, 0xe8751f80, 0x2f2cfc7e, 0xcdd3b8b7, 0x776469e3, + 0x07db7f98, 0xfbf466f9, 0xeabe7c23, 0x2e5c9dfb, 0x47dc125a, 0xff9c1f81, + 0xb12264d0, 0x6429e554, 0x63dab17c, 0x7542f8c1, 0xa97bcb2b, 0xff208c7e, + 0x69ff06ae, 0x6715f81e, 0x26f7d011, 0x0027bcd9, 0xb23eebcf, 0xf058c5f8, + 0xa026cfbb, 0xc87cf5df, 0xbd967fca, 0x7bef509d, 0x19e30bac, 0x61cfb3cd, + 0xd5d155de, 0x0a4b6b4b, 0x47e8be71, 0x4d491870, 0x1afe9e38, 0xd596f2cf, + 0x783e95e7, 0x7fafd1bb, 0x11e582be, 0x196e1cfb, 0x5faa11fc, 0x44e95a3c, + 0x7ef5533f, 0x8915b4a6, 0x27e43d6c, 0xd54f48a9, 0x83e4a7fb, 0x9ab494ff, + 0x2dcf41f3, 0xed05a3fa, 0x268ff3bd, 0xfcc49e63, 0x9859ef38, 0x7030b5af, + 0x19a5e81b, 0x77d01c74, 0x2dbbefcf, 0xf2ade61f, 0x3fe02dbf, 0x58b7eda7, + 0x62717eb5, 0x95ddf962, 0xfea8a7cf, 0xb7f410f3, 0x6243ef85, 0x359a2a69, + 0xf757bec8, 0xc3a8a27b, 0x607f13fe, 0xcab938c2, 0x89e8b60f, 0xcfdd94d7, + 0xcf10fe47, 0x3c1cfbde, 0x167db15f, 0x65e14fcb, 0xf0aa7f0b, 0xfe98ecdc, + 0x1fc79807, 0xcbeba5e2, 0x4b05930b, 0x75eb3c78, 0x7887fbc1, 0x8032cf16, + 0x8a314e7d, 0x2be8967e, 0x92ce7f4c, 0x5647480d, 0x3e30dfba, 0xf408e943, + 0xcea1c9f8, 0x9d74b1a9, 0x93839ac3, 0xaf87be01, 0xd24f10e8, 0x9f1813ac, + 0x78d81589, 0xf55d8dd9, 0x22ffc023, 0xa03377bf, 0x8b926952, 0xc937d421, + 0x404e49e6, 0x2e4d7a7f, 0x7bfc578c, 0xec93cb3d, 0x42bf4688, 0xcc52fa73, + 0xc8f9ec93, 0x489cfe88, 0xfd3ea0f9, 0x45e63564, 0x27fdb566, 0xfbac09c6, + 0xd4dc0d05, 0x0b04f8e7, 0x3bf95f8b, 0xcd6e6067, 0x57f20764, 0x188fe3a9, + 0x25ea969f, 0x56a43ce0, 0x8199d6ef, 0xe822ad7f, 0x2cde1ce7, 0x195f00eb, + 0xf7a62f3c, 0x7ac75ff0, 0xe3514ed1, 0xd7960102, 0x0b5aefa4, 0xaab497f6, + 0xe03f16eb, 0x574dbf63, 0x85fd079d, 0xd2cfd1aa, 0xcf804d11, 0xaf65b467, + 0x339689be, 0x838c64ea, 0x925a1ef5, 0xba557e81, 0xac83e1ce, 0xe5813d33, + 0x18133921, 0xd11d48bd, 0xd267903a, 0xd182e266, 0x32dd6b33, 0xcb8779f8, + 0x25b9d212, 0x70025bc1, 0x807ce68d, 0xb8c288ac, 0x7e6255a2, 0x8f8aeb11, + 0x44e7017e, 0x03f3f176, 0x9e8f0f47, 0x7abdfe8d, 0x5fb80049, 0xc9bcb1b6, + 0x73da0939, 0x3ef0fd07, 0x59a7f98a, 0xe4c9ff1d, 0xfa0b1d17, 0x3e8cf497, + 0x0b477aa4, 0x587711f8, 0x7b6f98bd, 0xc4506d73, 0xfddc9938, 0x66128964, + 0xf2656ccf, 0xb32f7aa4, 0x97ed23bf, 0x5523936f, 0xd2395a09, 0xe927fe57, + 0xae122b27, 0x5a212ed3, 0x4f522e7b, 0x06dfb489, 0xfd11dbe8, 0xa8afa50d, + 0xfdc52779, 0xd9bd30e3, 0x7e43eaaa, 0xb14e5e4d, 0x4c4b8d85, 0xdb27feda, + 0xcc8f9665, 0xd61274f3, 0x9024ab28, 0xd046ff57, 0x0be6a72f, 0x5e598bf9, + 0xf9475f8f, 0x97c4265f, 0x284f309a, 0x01050485, 0x045d66fd, 0x7c844bbe, + 0xe3ddfa21, 0xef385909, 0x2755c49d, 0x04547f22, 0xf219b798, 0x352f304c, + 0x8c116db0, 0xc705b773, 0xc99e4331, 0x70154838, 0x3a7e036f, 0x11c582b5, + 0x05dca992, 0xc61e4dfa, 0x973cd0e8, 0xf9a89be5, 0x87fe6a24, 0x0e62870a, + 0x8b11e4df, 0xd5ef8132, 0x4017de0b, 0x1817a9cf, 0x981bfc7c, 0x46d9a11f, + 0x6e5a68f5, 0xf9851cae, 0xf584bd7e, 0x21d0afef, 0x80f9aa5d, 0x7615c3cd, + 0x226fe53e, 0xf9cdefea, 0x4064bf2c, 0x5c044a1e, 0x6e943cd5, 0xf603b7ab, + 0xe4c8b26d, 0xa2379aa8, 0xfe1849d2, 0xde3a66fc, 0xbfa60ef6, 0x70185717, + 0xb795bd1d, 0xb7b1ffa3, 0xce404752, 0x191bb717, 0xb78c45dd, 0x0481ae7d, + 0x60295fa1, 0x8e79fcc6, 0x5fd36fff, 0xc1735e29, 0x65747bbf, 0x0a6eb8c9, + 0x7a5637e3, 0x166bd9f0, 0xd7c8455a, 0x01e68731, 0xf89cda47, 0x49a43ba3, + 0x4a135790, 0xecc92817, 0x54a0fe70, 0x37a072a2, 0x9431f43e, 0x9c7c4c5f, + 0x76878795, 0xd1fdb409, 0xd8a51da7, 0x9931681e, 0x98253f90, 0xeb96fd4b, + 0x40646f90, 0xc0a7c6be, 0xd748aa87, 0x0bf44eda, 0xc856f971, 0x669921f8, + 0x94bf300c, 0x77b1fe82, 0xee513293, 0xf6b3725b, 0xaa7d4277, 0xb469fd11, + 0xddfde91e, 0xbd5853e1, 0x524ef0c2, 0x836f2cad, 0x9f81f974, 0x05399bbd, + 0xb055d2fd, 0xf4fea81f, 0x057bc5a6, 0xe8417af0, 0xe0fb0e5c, 0x9affe9dd, + 0xe17df407, 0x01864fc0, 0xa06999bf, 0xfc20f97a, 0xe32771e5, 0x4b7abd2f, + 0x79fb409d, 0x1215e2dc, 0xe883f969, 0x95203379, 0x14dc6e7c, 0x200d1c03, + 0xe04417fe, 0x7f1cf177, 0x5f4c39b6, 0x08f34db4, 0xc6b9f790, 0xef11e6cc, + 0xbfa8dc95, 0x7708e778, 0x11aff5d3, 0x94433eb8, 0x143bb458, 0x8eec1625, + 0xc21e2ba5, 0xef916fbc, 0x9bad49e7, 0x7f97d045, 0x4df8f2b7, 0xe5a1b0d2, + 0xf6115df0, 0x1254fa85, 0x8b663ad9, 0x8fa018ca, 0x6fe342b5, 0x3de0934a, + 0x31e9b3a3, 0x5f210a2b, 0x4d74667a, 0x22cdc621, 0xf7d2c7df, 0x23656179, + 0x14d4b76b, 0x3d28974a, 0x61decd3b, 0xf3cb9700, 0xfb0e593f, 0xbbf27977, + 0xc2be431f, 0xd6e27abb, 0xe24d3ec3, 0x1f2a4371, 0x32c7bf01, 0x286e2c6c, + 0x031a9d6f, 0xef866ce5, 0xe30048db, 0xd873a5d4, 0x483bc139, 0x6d176d67, + 0x57a9d337, 0xece8c2ba, 0xbe5b4536, 0x2e5b5723, 0xff1179e5, 0xbfbed2e2, + 0xc0248493, 0x7e26f7ff, 0xfdfc223d, 0x1beecd8f, 0x0aaffe61, 0x3fd28f2c, + 0x87a8c889, 0xe83f043a, 0x495fa305, 0x5926e7e6, 0xb9cfdfbe, 0x44caf31d, + 0x7b09f582, 0x0f21bb4d, 0x8b07f55f, 0x93b47ebc, 0xc8ec3298, 0x84ae508f, + 0xe8379e04, 0x390918c0, 0x7e664cb0, 0x40d6da51, 0x5f3039fb, 0x5824b841, + 0xa016e474, 0xd21342eb, 0x298a5175, 0x28e0e80a, 0x3f1f23a7, 0x55d2a387, + 0x903c4491, 0x9e8740bf, 0xf577cf03, 0xfff011f2, 0x78233ffa, 0x29908a4e, + 0xf231e612, 0x855908b1, 0xbd39a7e5, 0xedf9551e, 0x6fc849bf, 0x701ab4df, + 0x16bf895f, 0x439f805b, 0x5fd6991b, 0xf3851c6c, 0xdd03f753, 0x091cc3bd, + 0xfde672e8, 0x44983a4a, 0x2acaccae, 0x38f862bd, 0x410fe401, 0x738d523d, + 0xbefa99a5, 0x4977c373, 0x74bb9fbc, 0x8a4cde2c, 0xdc9d1c78, 0x3f7cc465, + 0xbfb42f5e, 0xf7e025f5, 0xdc4cc4f1, 0xb7887b74, 0x3446e80b, 0x4ba014b8, + 0xdae5ce95, 0x9d29bf43, 0x79c9eb04, 0xbb73d704, 0xe4f58655, 0x6b9c3252, + 0xae3ba7c7, 0xf461fa00, 0xefb1462e, 0xfb792aef, 0x3e8c2926, 0xec55f7e8, + 0xf7ed68fb, 0x3dbdfa4e, 0xfa18fbec, 0xefc0de7d, 0x72220909, 0xbff3e76e, + 0xee89e79d, 0xba829ab1, 0x917fd0b1, 0x13bf45d2, 0xc3f7d813, 0xe07be862, + 0x7cdab9fb, 0x65d1320c, 0x88de3cc2, 0xc2998bfc, 0xd7404963, 0xdaaa99b7, + 0x6fff68bb, 0xd4ccfc71, 0xf380bf79, 0xcbcd6f66, 0x57fc0379, 0xbfba2625, + 0x055f60b2, 0x7ad202d7, 0xb19f78a7, 0xddfee365, 0x2d5ff401, 0x69d8477a, + 0x69be82f9, 0xdc4cb2d8, 0xe3133b17, 0xc55fce07, 0xa00ebabf, 0x3ea7a003, + 0xb798883a, 0x67722f8a, 0xedac262b, 0x3c087aa4, 0x9084bd55, 0xac9f961a, + 0x8baff5a4, 0x530ccb12, 0x0bd030cd, 0xe3f4aade, 0x7b699dbe, 0x9e97f312, + 0x04bef24f, 0xc37b9df3, 0x3412e9e7, 0x011fce76, 0xdf3a207e, 0xce5ffd5f, + 0x06bfd557, 0x667ee7e4, 0x0ee7e4d0, 0x71d47fb5, 0x8957a07d, 0x82dbc790, + 0x39beb6f9, 0xab9c1716, 0x68be41f0, 0x5079c621, 0x30243aaf, 0x982fd57d, + 0xad741eb8, 0xe984bc79, 0xfa7d554b, 0xbd0f2692, 0xbbcd9f39, 0xfa829979, + 0x6b02abd6, 0x984f9fef, 0xd78b363e, 0x5eb1942f, 0x6e6f57cd, 0xe6b5fe61, + 0xd0284797, 0x50a3d52f, 0xae58931e, 0xfe3265a7, 0x91493cda, 0x44dc0cfd, + 0xafcfe848, 0xfa67a2de, 0xab9d76df, 0x0c41f308, 0xf1623f54, 0x869fc65b, + 0xfd23f1b3, 0xaa275f70, 0xc3f30076, 0x41ff95f5, 0xb259b87e, 0x7f693897, + 0xe9dcf30b, 0x17982cfa, 0xfa51c7f3, 0x2049d1dc, 0x1866ac4d, 0x91b7cde8, + 0xd974f79a, 0x68069f48, 0xa534773f, 0x7d0d6ccf, 0x8cf19d1a, 0x22bcc21f, + 0x1d2441f9, 0x6578c566, 0xd6d9a7e8, 0xd06ac7fa, 0x2e8ddb37, 0xf2ca7f96, + 0x40f922e9, 0x48167cd8, 0x510e3e6c, 0x0738f9c4, 0xecb5cf9b, 0x4cfa7093, + 0x0c3f6c24, 0x25125fb5, 0xf416b7e2, 0x9b1f97ef, 0xbd6023bd, 0x2d66fb7d, + 0xcc062fb3, 0x7d20b45b, 0x8b2f73dd, 0x99a2f837, 0x43b8835c, 0x167f1d12, + 0x7a9eff1f, 0xfcf78746, 0x4b7480d0, 0xf9841fa7, 0xb3f5e6cf, 0xdf30abda, + 0xfd34f668, 0xff0d2ec9, 0xe7bc2375, 0x1c7376f2, 0x02d87af9, 0x71b54a73, + 0xb3f7b985, 0xa4ddc6b8, 0xbdf30f46, 0x9fb68e67, 0x73f1a4b9, 0x7b9a9fc8, + 0x54fdf6bf, 0xc9b9df67, 0x788f1011, 0xbde1db83, 0x7ec0bf74, 0xf17e337a, + 0x7e94658e, 0xaf34fc47, 0xd303fc00, 0x6cf72a13, 0xb7e7e5a6, 0x9bf2c28f, + 0xd1f83f09, 0x2bbf50bb, 0x20d3cb07, 0x08ec0c19, 0x6f208fd8, 0x3dbdee8a, + 0x86fb8e93, 0x8cbbf799, 0xa33bdbe5, 0x68b3cdbc, 0x2cd8e73b, 0xc69c1bcc, + 0x42ef4df9, 0x0dc77f56, 0xfa1a9656, 0xb97e8280, 0x79a15169, 0xf227ff40, + 0x790050ff, 0x78b2d3ac, 0x51d5e0b9, 0xf8437e50, 0x4dd81e7c, 0x0916553d, + 0xcc9d5fe0, 0x73a399fc, 0x0a48e085, 0xde766997, 0x575b157f, 0xc90bc169, + 0x15a63fb0, 0xbb467eb3, 0x4367d4a6, 0x2c45dd3b, 0x629b24f7, 0xfbaa1f80, + 0xfb93996c, 0xe49eb807, 0x15fefbe1, 0x71b527f7, 0x498f5fb4, 0x3d12c170, + 0xfb413f13, 0x39d85894, 0x533b8f2c, 0x54e87f02, 0xdc73cb37, 0x02ac8aba, + 0xcdeb647d, 0xad0d696e, 0x7a226a9f, 0xce946b90, 0x9b7a011f, 0xf4f3e13b, + 0x8b2e2018, 0x3a55ce96, 0xf7d2a59a, 0xd31d2d34, 0xe713f9fd, 0xcfe76ff8, + 0xf7363a1a, 0x7a50f1d3, 0x1d579d39, 0xb49bbfee, 0x9c6faaf2, 0x39187d88, + 0x01fc50ee, 0x67f9c2fe, 0x715afcff, 0xb642a5bf, 0xc7ec3658, 0x6e3f7526, + 0x7418f803, 0x24fe789d, 0xc28d7043, 0xe8439b03, 0xd2fcea15, 0x305927c0, + 0x27f05e70, 0xfb1d7aa9, 0x9b1d8073, 0x77e9ebca, 0x9fef626e, 0x05ff1d17, + 0xd96b7fe4, 0x350a767c, 0xbd709f8c, 0xab7fb55a, 0x69b6f5d5, 0xc5145bd7, + 0xc13b7bce, 0xe93e814f, 0xf37d51fc, 0xa83c06be, 0x3971f1eb, 0xb1e4c73d, + 0xeedae81a, 0xfd2395b6, 0x5ff89f7c, 0xa0e87d06, 0xe6187bc5, 0xefe75479, + 0x2163fb00, 0x925c6371, 0xce6bc7d2, 0x9d42fd30, 0xaa9c246f, 0x919fe087, + 0x4f8489eb, 0x513ade3f, 0x77cf539f, 0x1af7adf5, 0x21eaa9d7, 0x3fd6830e, + 0x1cfee764, 0x00dff73b, 0x2e3c8145, 0xd02e5125, 0x04baa7eb, 0x894a27d4, + 0x6970f909, 0x76df9309, 0x5437d30b, 0xfed43f39, 0x8216f5b8, 0x2974a9fc, + 0xd8c9e7e1, 0x30e922ba, 0x823d7491, 0xd9499e76, 0x39f600b6, 0xff4a25e8, + 0xcc2d4bfc, 0xa9c57bcf, 0xf1aef5ca, 0xcafbd720, 0xd77ae403, 0xf337e078, + 0xa3fc6d44, 0x2ff30af4, 0x7c10afda, 0x193eba96, 0x5edd720f, 0xf81e35d2, + 0xeeb1add6, 0x1f9f012f, 0x361f98eb, 0x24fa8e12, 0xbc5fea9d, 0xdc8cfa26, + 0xe95c6a3f, 0x94d78b4d, 0x1fdfbe34, 0x2ce84171, 0x38ae4682, 0xcdeff799, + 0xf4a63a04, 0xf2897288, 0xc157abc7, 0x837f8398, 0x532c721c, 0x092d9bf9, + 0x2e08dbf8, 0x8f8c3dc7, 0xdb758b9c, 0x0d1c5893, 0x8710f2e1, 0x572e74cb, + 0xd110ee2f, 0x9dcd3f9f, 0xdcb834fb, 0x24f5c77d, 0x8dd7fb80, 0x5f097172, + 0xa53a45d7, 0xd17fb420, 0xe2c67a8a, 0x1e31cbb7, 0x8eab6231, 0x72726128, + 0x734a2064, 0xbde8c47f, 0x4c794d76, 0xfda6b26b, 0x9a596d0d, 0x28e0fcfa, + 0xe3b8fd4d, 0xf8f29a05, 0xed351bce, 0xac507c27, 0xbaea4f29, 0xa6fed35d, + 0xca6b674f, 0xac123014, 0x0283b9fb, 0x7dd74ed9, 0xcd3ee873, 0x7dbdfff7, + 0x0b8871c6, 0x33f6e29e, 0x733bbbf1, 0xa8161c29, 0x4ca57c74, 0x08505fdb, + 0x07c0450a, 0x4682dfd8, 0x853cd796, 0xdfbc2e42, 0x7d5a4d85, 0x6d56f162, + 0xf37da2b9, 0x0395e05a, 0x8a6a21f3, 0x646c88e1, 0x7934c43e, 0x75e80ebe, + 0x2fd51276, 0x91c63040, 0x1ac7c838, 0x1b7fdf6a, 0xb0c873fe, 0x6b3fc36f, + 0x7a80d5bf, 0x7fb7e2fd, 0xafa41455, 0xfe2d4e8c, 0xff168acd, 0xfc5ab9d1, + 0xfc5a5d5b, 0xe2d44ec7, 0xe2d6e6df, 0x8b44ae3f, 0x168f78ff, 0xb57389ff, + 0x6af24ff8, 0xa1529ff1, 0x8d5a7fc5, 0x2b19df16, 0xf4ccf8b4, 0xffbda83f, + 0x2aff0224, 0x7baeccff, 0x149ee228, 0xd185d11d, 0x0b474a81, 0xe798153c, + 0xc7e9bc32, 0xe922719a, 0x3a8dda81, 0xda8b87bc, 0x6b85db71, 0xbdca0fa7, + 0x491a5fd0, 0xf1244f1f, 0xb13b183c, 0xeef9455f, 0x40f8127e, 0xf2a15ea4, + 0x1e3970ad, 0xc50eff6e, 0x27c806cf, 0x290f0f6e, 0x361ec09f, 0x43c3dbf7, + 0x9087e9d1, 0x53fa838d, 0xee8bfa23, 0x2e3cd995, 0xe049abc1, 0xf225fd5f, + 0x04e90fbb, 0x7ef9d227, 0xe3a1eb08, 0x1a35187f, 0x203f18fd, 0x7fcfd441, + 0x74871908, 0x712007b0, 0x13e73e99, 0x5ce59f05, 0x7ee42f5e, 0xdbd9a70e, + 0x16a97006, 0x300919bd, 0x9e276a6e, 0xe227221f, 0x855ee9ae, 0x976fe093, + 0x7f06e908, 0x98f67d3b, 0x519c7d19, 0x289b87f9, 0x9678308e, 0x5172154d, + 0x30a3157f, 0xfbeca80f, 0xb2a5ca02, 0xcecf61ff, 0x4707a624, 0x50acd73e, + 0xf5c4d9e1, 0xfc0fa600, 0xe3c29277, 0x416bc433, 0xe064b9b8, 0xe63fb4fb, + 0xf319feff, 0x4925d193, 0xec78ec57, 0xf80cf10a, 0xa241f386, 0x8c73cd89, + 0xe8574c44, 0x8bc4d1fb, 0x49c7dffa, 0x7aee3859, 0xd632b289, 0xb7e828ef, + 0xefa3c60b, 0x045c5ba7, 0xd3a2bdfc, 0xabffd045, 0xc32b0996, 0xf55bac1f, + 0x7a72a5eb, 0xcc2563d8, 0xe7e1157f, 0x2729114b, 0x3d157c85, 0x94ed0f3b, + 0xf0bb32b6, 0x18ceab98, 0x792a2eb6, 0xed7e706d, 0xc81cf4db, 0x96133d2f, + 0x5ee14e0f, 0x3f1c9833, 0xa8e2cc9e, 0x6e9a566b, 0x0f497886, 0xbe3d078f, + 0xf80cdc92, 0xe6172514, 0x417dc181, 0x0defb0b6, 0xb61f5a0e, 0x498b24df, + 0x3c5bd653, 0xdac65978, 0x17483595, 0xd1af7e7a, 0x6487d4ba, 0x217f986f, + 0x4c4f8f9a, 0x1027227e, 0xbfd2f2ae, 0x5812a74f, 0x674b28af, 0x9feaf634, + 0xdc0146ae, 0xa93d38aa, 0xe93a35f3, 0xdeed6138, 0x2557f4e1, 0xfe601a77, + 0x741c50ef, 0xea413c42, 0x56bde074, 0xffb8e975, 0x37f0e4ef, 0x908217ee, + 0xe0946ff7, 0xd2f4268c, 0xd28e3cd9, 0xf477dae9, 0x6b25e204, 0x7e44cfc7, + 0xb8d7b066, 0x1e4f05a8, 0xeca1677e, 0xea9e041d, 0x2e94e8d3, 0x61a3f387, + 0x9e0edcc9, 0x3e002640, 0xca0f9906, 0xf66587a7, 0x59e3c3cd, 0x3fc3c1be, + 0x4c7f9824, 0xa2bfd056, 0x13c4f87e, 0x1b1bf217, 0xc6cbe109, 0x50037495, + 0xa561b71b, 0xa8737889, 0xa835221c, 0x3710251f, 0xfe6351d2, 0xfd395709, + 0xebf052ce, 0x3787b05c, 0x0d53ff8c, 0x1f45ad94, 0x61b94055, 0x90ad8be4, + 0xb981642b, 0x23bf3038, 0xa2b66700, 0xef7cfd46, 0xef07686a, 0x425f3e21, + 0xacf9d3df, 0x821ed31f, 0x0f63d1f6, 0x51f50a7d, 0x9b29a096, 0x3f75177e, + 0x45b04971, 0xb253855c, 0x4856d3e9, 0x8e28a17b, 0x4f47dfe6, 0xc646fd64, + 0xbb2d1203, 0x93217dd9, 0xb1678f09, 0x1faaec73, 0xbbb2de3e, 0xc6f818a9, + 0x53fd6d30, 0x96711e1c, 0x41678e97, 0xe7612a7d, 0x93fd7957, 0x7966debc, + 0xe598b3a9, 0xdfbe681c, 0xb58ffbcc, 0x50bf18e8, 0xb1b78f08, 0xdebc4dfa, + 0x093bd6ac, 0xfab1a78f, 0xb46f5e7a, 0xba12fcb0, 0xafdf35ad, 0xdc27e3e3, + 0x30de23af, 0x89cc74fa, 0xfa30de22, 0x35da97b0, 0x9d85bd65, 0x25a79523, + 0xfb53be6b, 0x1b8f9c7d, 0xf34b3933, 0x28d8699d, 0x34cefb6d, 0x710f2394, + 0x0b521b38, 0xf9eaf534, 0xb3a7226c, 0x276b3276, 0xf4d46e39, 0x6251517b, + 0x999fff61, 0xcbadd2a4, 0x90fb7404, 0xe2112b35, 0xb99581b4, 0x1f0144a0, + 0x3f994fe1, 0x6674789d, 0xcb054acd, 0xb8bfdc99, 0x2c44e566, 0x0b74a6ef, + 0x74accff5, 0x2d277961, 0x53f9f42b, 0x58950fda, 0x07ed1b64, 0x7ed34fca, + 0xed14f9e0, 0xd24f9e07, 0x337ea0f1, 0x9bca0efd, 0xde507f68, 0xe58dd2b0, + 0xb04b2bf5, 0x83d2bf5c, 0xe72b75e5, 0x95f1f3e2, 0x59ae7c5e, 0xbbf58159, + 0x3beb8593, 0x22485f7f, 0x93bbb9e3, 0xdde7f7c7, 0x16dcf1ab, 0xd476e0c3, + 0x32ffce01, 0x8988e788, 0xa5c63fd1, 0x8f5b1ad2, 0xe719bd80, 0x6a48f861, + 0x5b7ac1ac, 0xfd471b09, 0x24fc388e, 0x331d88b5, 0x5950fc64, 0x230df98d, + 0x7317cb09, 0xc45289fa, 0x9fc25fcf, 0xbcff4214, 0xabe5ab94, 0x71f91199, + 0x9923b3ea, 0xb0e279d9, 0xc72c371a, 0x8413d134, 0xcb8b5e7c, 0x33b1e78b, + 0xa9ced0ae, 0xe57b1cbd, 0x5f80a216, 0xbfab54bf, 0x6815a7da, 0x4af144f4, + 0xa533b635, 0x6769a7de, 0xda699470, 0x5cc92d95, 0xa47804eb, 0x1b1875b0, + 0xbd101157, 0xe3379b0b, 0x999367b8, 0xebd74bbd, 0x3efbff47, 0xeb97ad81, + 0x7ccbcf4d, 0xe446a6bd, 0xac6c23ab, 0xd7eb1398, 0xff3c3f01, 0xafdc58ab, + 0x43a33dcf, 0x1248dfff, 0x46be01d0, 0xf50cf153, 0x96174863, 0x4aee006f, + 0x1144f9cb, 0x848e3ca1, 0x7aa4bed0, 0xb3257fd3, 0x6633d0b8, 0x79a50b88, + 0x23f9679f, 0x392b9441, 0xaa391f1c, 0x8a55b8fe, 0x4e9da7f4, 0x7b56fb46, + 0x5b8d449e, 0x2516b2ae, 0x33d13e82, 0xb44f7e44, 0x169bbef3, 0x27463850, + 0xfaa7c5cd, 0x1ba2bd7e, 0x55e57cf4, 0x4cefaf0e, 0x77c601e7, 0x6afce8c2, + 0x0bbfa532, 0x0c83bf79, 0x2c3d5219, 0x1af0f684, 0x941fcabd, 0xfd0fe058, + 0xe62c5765, 0x2127b473, 0xc199447c, 0xde95b9e7, 0x7fa9249b, 0xf997e29d, + 0xe49be432, 0xbdb67cf0, 0x34dd972b, 0xc75fea4d, 0x5fb614e8, 0xf22b4973, + 0xce875cfb, 0xa735ecc5, 0x0f33bec6, 0x79c3726b, 0x7114715f, 0x48c42e41, + 0x5ee784d2, 0xc889bfc5, 0xb7a3c47f, 0x17ea8511, 0x40807251, 0x2fda873e, + 0x8fe276e1, 0xc2fcbf38, 0x2de70d32, 0x94f7aba6, 0xf9af51b9, 0x90c97642, + 0xb345f2cf, 0x4f123f1e, 0x6573eb6a, 0x4a5e07d7, 0x47f68b97, 0x517a60bb, + 0x5f784db9, 0x204bb89b, 0x83ce02a9, 0x99d9a7e5, 0x5adfaa7e, 0xe0e3fc44, + 0x2e37aed0, 0xa5dae005, 0xc2a9d01c, 0x8aabb69e, 0x3f06ec33, 0x0b8008d4, + 0x2e5873c0, 0x5f2171c2, 0xab95deef, 0x14ee4e10, 0x6935e786, 0x7cf9dc2a, + 0xf70ddb88, 0x566a2dbb, 0x3aed5bed, 0x7f15e7d7, 0x3b6bea0f, 0x8bd3cc45, + 0x9885e784, 0x286263f7, 0x3346cba2, 0xa79d0cff, 0xc129e61b, 0xbe00e3bc, + 0x58b3d704, 0x5ce00436, 0x5ad08f66, 0x31a97182, 0x971e123a, 0x53339f52, + 0x277aff18, 0xb467c659, 0x0b4dde73, 0xef9785c6, 0xc31eba47, 0x122c4fd7, + 0xbb7093cb, 0x5abf7095, 0xf0676a83, 0x3e28ea3c, 0xa0fbbedf, 0x2f3cb146, + 0x0adce90b, 0xd9431779, 0x614c3f11, 0x3b7ef2f1, 0xe806a282, 0xf309bc67, + 0x7cd41a1b, 0x055de514, 0x13e96bf3, 0x9c4c51f2, 0xd959d74e, 0xfaea043d, + 0xbe30a656, 0xa3e392b9, 0x22ecc4d7, 0x27e4db88, 0x6f9f9d84, 0x58fb472f, + 0xb6f4f38d, 0xd552fcb3, 0x49c950ff, 0x060df7a0, 0x221dde87, 0xdb2a77c6, + 0x0ef760ef, 0xf7893c76, 0x14bed235, 0xde7287a0, 0x6b4ebcbe, 0xe3d82f0f, + 0x0ca51b59, 0xc117bbb4, 0x03d9ab7d, 0x3b48eded, 0xae14b1fb, 0x3e48babf, + 0x354e71c4, 0xa28b1f66, 0x126435f3, 0x2297bf3c, 0x6ef784be, 0x09b3ed53, + 0x79243bee, 0x488fbeec, 0x6a92bfbc, 0x15ef3840, 0x5a5b8f08, 0x8ef7fe90, + 0xef7ffb67, 0x0e778b91, 0x93dcfda7, 0x7ea6e0c1, 0xcb064f77, 0x0607dd33, + 0x4adf7d15, 0xf960c948, 0xdc38bb3c, 0x9b9f33bf, 0x5573e5ac, 0xa2c75d6d, + 0x3b77e415, 0x8f7bde81, 0x0f2625fd, 0xef0847f7, 0x833f7f2d, 0x0de607cd, + 0x74fbf479, 0xa70bcf9f, 0x12297d83, 0xfaeeb79f, 0xda698cf4, 0x7bc85d79, + 0x3676e12f, 0x579856af, 0x4264f04f, 0x3ab47e78, 0x83c57daf, 0xfd7cef9f, + 0x9133e77a, 0x5068a7ce, 0x26fd1d38, 0x0c33ed38, 0xf80f9f3e, 0x0de3fe7c, + 0xc0c0ef76, 0xd3d4ebfa, 0xefc04476, 0x807bcec5, 0x7ef9d35d, 0x847a0290, + 0x63013bb3, 0xad7e1c4c, 0x0b3e9c85, 0xa171df39, 0x1f7c444d, 0xa4bcc04d, + 0xfbd58956, 0xab028bec, 0x8ebafd28, 0x7900c82c, 0x88d0fd60, 0x86f8c5f7, + 0x4b8b37c8, 0x97d8eb65, 0x870a0c2c, 0xe47f5e18, 0xb7f61944, 0x012303fe, + 0xf5cb507e, 0xab72f5f4, 0x5501ee09, 0x02e508e1, 0x4219f4fa, 0x2e505c8b, + 0x58a4c2fc, 0xc74f1906, 0xb114dbc6, 0xd4f1d46f, 0x973529a7, 0x3785ddf9, + 0xdea3c844, 0xbc3df934, 0xa15367af, 0x3bf73c84, 0x4b59bfc3, 0xef82172f, + 0xe8c9dc25, 0x7a0a94c5, 0xe63a7094, 0x13ecb47b, 0x03cdbf42, 0xb8bc19f8, + 0x4647df7e, 0x840c22d2, 0x2f4e25d3, 0xf5d4faea, 0xdeb6f3ab, 0xd6f300bc, + 0xf1301f01, 0x7a9d5498, 0xd5f21e2f, 0x60f72e58, 0x2627285d, 0x7d0f2c4b, + 0xdd7884bc, 0x3c46f134, 0xc78fb027, 0x0c93439b, 0x7e43de83, 0xfd7f1f0b, + 0x04ecff95, 0xaedfd5fb, 0x44d9f3c7, 0x45de72ea, 0x8ef7c8e9, 0x52bdf784, + 0xfb812a7a, 0xb89c8e67, 0xdd7a0318, 0x847aa94d, 0x0fc04df3, 0x115c3e41, + 0xff7f304b, 0x18b217c4, 0x5393ff46, 0x7497ae45, 0xfe5e4276, 0x979602c6, + 0x807ae16c, 0x057744e5, 0xf132dfcc, 0x4c2146c7, 0x1aa5e6ce, 0x868dbbf1, + 0xf68b8250, 0x4910ebe7, 0x2e81f510, 0xefab47bc, 0xe0cc91dc, 0x05485d50, + 0x47dc1e4c, 0x9ad7eeca, 0x3e30aa9c, 0x807de74b, 0xf91a8fbe, 0xf50e5c85, + 0xacbc7485, 0x32adeffe, 0x78d467c3, 0xa6c59f76, 0xe193bfc9, 0x8158aefe, + 0xafb43de0, 0x7935eaa4, 0xe8649ffa, 0x9d9dbf78, 0x65f9bfa0, 0x5b09f309, + 0x40990f83, 0xc5f757af, 0x86dd54d3, 0xfdf8eb76, 0xe626ebaa, 0x805ce006, + 0x4a7fc74a, 0x61527af5, 0xbc5f747d, 0xa7577a84, 0x47c22a67, 0xc97c87ce, + 0xef13a431, 0x0685210d, 0xae4be419, 0x6fd9a74e, 0xea6f1c2d, 0xa8a5ea93, + 0x69c23cef, 0x62f79559, 0x39e0898b, 0x62b32ba3, 0xd3152f41, 0x25cf3d54, + 0x6cff1c03, 0xe1fa8399, 0x8d2d37d9, 0xf57cf1e1, 0xb3da9a79, 0x797f4341, + 0x0333cba1, 0xde222fda, 0x2e8fa0b5, 0xe735166a, 0x7df2cfae, 0x144af0be, + 0xf5e98609, 0x87de270b, 0x5e1647e7, 0xaa412189, 0xe7e59d27, 0x3cf2ce7d, + 0x654f7f9f, 0xaf81b2f2, 0x75ea4b67, 0x08aefbea, 0x0ff3b97e, 0x7e3195cf, + 0xf700eff9, 0x00cba12a, 0x8de36e7c, 0xfe3cc17f, 0x0f4ed4d3, 0x3ad37ce6, + 0x6c3048e3, 0x5776be9c, 0x7e9eb84c, 0xff3828bc, 0x105af5fe, 0xfda9a70e, + 0x4c70cdff, 0xbfb1c0d1, 0x1c0d2cff, 0x839ff607, 0x995e9fe3, 0x8ffd2dfb, + 0x457fa21e, 0x7efeff33, 0x3db8e187, 0x8f9ecb47, 0x68e5fba6, 0x57f6f570, + 0xb0ed5f21, 0x272fef11, 0x78c5ad6d, 0x0417e89e, 0x3f2d99cf, 0x90c7e5fc, + 0xb77cb687, 0xf46305c1, 0x5cf343ea, 0x6187c883, 0x7dc3f644, 0x6f73ea3e, + 0x27ae366a, 0x0a49bdf2, 0x666f90c8, 0x55e495ca, 0x9d65e80a, 0x1fb8d581, + 0x549fc84c, 0x6fdab83f, 0x9ea88a6d, 0xad7dc567, 0x10d0dbde, 0x7c00eded, + 0xe6a5167f, 0x8237f91d, 0x67f2ad1f, 0x85eecca2, 0xa21da1b3, 0xe225b1fa, + 0x91a3bf45, 0xe5e40878, 0xdf7865e7, 0x53fefe00, 0xafc006ca, 0xe3d98e2d, + 0xb723ff45, 0x3b9836f7, 0x7e30ae9d, 0xe954fbf7, 0xd6fce4fa, 0xfe333908, + 0x4c82e7fd, 0xe61efcce, 0xfe762551, 0xf2132cb2, 0xbdf8bb08, 0xe3018a3d, + 0xf0c78505, 0xd532afbe, 0x8c8baf5e, 0x40d9a75f, 0xeefd55ff, 0x044f9031, + 0x9646c23a, 0xcd1e5dbf, 0x89bfe5ca, 0x907573c3, 0xf0079fc2, 0xec5d156e, + 0xe119379e, 0xa1af917a, 0x1d31b4d7, 0xe1cbd9e0, 0x75fdb17a, 0x62ee57bc, + 0x7fc470dd, 0xc13f6bf9, 0x25f6a17b, 0x0ea77cf3, 0x729fca2b, 0xee08aba3, + 0xcc97db2d, 0x2956ccf4, 0xa6105318, 0x2d4bae77, 0xbe7abe46, 0xf40eb86e, + 0x7fae1572, 0xa360fce6, 0x4293efea, 0x2ebbf045, 0xbf830be7, 0xdfb7f945, + 0xa267bf8c, 0x1165f03b, 0xd1b76fde, 0x1782f788, 0x65b9181f, 0xcaafad2e, + 0xa59e61d1, 0xe71980ee, 0xdd81a173, 0x82df03af, 0x903aae9c, 0x52c3bf82, + 0x3cc21d1e, 0x5728aaa9, 0xca41c40e, 0xf784dc0f, 0x30da9f7a, 0xe5f81d32, + 0x1d2578c9, 0x40dd35ef, 0x7dd74e81, 0x7b0463b2, 0xcf013f5f, 0x463759ad, + 0x5ff3077b, 0xf22472a8, 0xc97d9efe, 0x006d3df9, 0xd726919f, 0x2d3e5a6e, + 0xeb9c58b8, 0x82b66878, 0x9e171671, 0x9cb72bdf, 0xdbef1afb, 0x7ee4fe6a, + 0x481def82, 0x161daab7, 0x97395e39, 0xa10cfb33, 0x387bf079, 0xdc386be5, + 0xab9f2c0d, 0x839f975c, 0x8df70e65, 0xe65cf711, 0xab7831a5, 0x242753cf, + 0xca8c2fbc, 0x67c874ff, 0x88d8753e, 0xe36a7674, 0xaaaf3c68, 0x614e578e, + 0x797dd322, 0x058caed2, 0x634b8ebc, 0x0d7caafc, 0xf7d52fb3, 0x25cdbae5, + 0x8750e780, 0xbd2bf988, 0xe2062872, 0xb53b6a1c, 0x769eb7dc, 0x65d77f11, + 0xc411f25f, 0x0227a537, 0xcd7ba4f4, 0xf7d5f28a, 0xe037719a, 0xf1217cf3, + 0xfe5c8347, 0xce4efd80, 0xea230ed1, 0x321fbdbd, 0xfdc074bb, 0x3a509649, + 0x7be81fdc, 0x58f9052d, 0x17685a6f, 0xeccd93d3, 0xbd77b55e, 0x2c3c7813, + 0x9647df89, 0xe5d9fa04, 0xf410730e, 0xf8c4fa33, 0x71ec9f86, 0xd1c3fbe2, + 0xf436fc04, 0x53854019, 0xdfc4efd8, 0xfc4d2095, 0x7efc4efb, 0x0477ba79, + 0xd9e5e5f0, 0x7c0b7fb4, 0x2eed8ddf, 0x806f7967, 0xe64bfd32, 0xbf6325e3, + 0x7c0cde69, 0x64e17c2f, 0xc4d0a7bf, 0xdeb13beb, 0xc04ef467, 0x4ad1fc75, + 0xe759065a, 0x55bbdef5, 0x7887169c, 0xe14de754, 0x245efa8c, 0x98d26a5c, + 0x23c2a47e, 0xf0fb2e92, 0x03f32df9, 0x97c009bf, 0x363c33b4, 0x3e30348c, + 0xf51a3f52, 0xa51b525a, 0xd55a13c9, 0xf761cec1, 0x9e22b06c, 0xa7eef57b, + 0xde851e41, 0xaf7613d5, 0xc008d515, 0xf07130bf, 0xe78e72fd, 0xb3d65709, + 0x2f73a27c, 0x6f9f4d9c, 0x678af381, 0x5515e735, 0x24ed1f3f, 0x1628fc06, + 0x96531297, 0x116cf4c7, 0x377ec7e7, 0xc15ea367, 0x6ff207df, 0x847e8918, + 0x00e50653, 0xc3518efe, 0x55d01d18, 0x1ef18bbd, 0x9f5b137f, 0x7a8e5f7a, + 0x7c244def, 0xd9b2d35a, 0xef1091ef, 0xf2877003, 0xf024a249, 0xffde1a60, + 0xa2ff0155, 0xa618afa0, 0x3f919b73, 0x185ca0d4, 0xe196cf78, 0xe83f7e5b, + 0x3fbcb6ff, 0xeb3ae09d, 0x9018fe5d, 0xccca9fab, 0x53d8a3de, 0x6c8bae50, + 0x69a7789d, 0x4f6bc812, 0xd63c5a5b, 0x54fc3f23, 0x9f2af560, 0xa07eb01b, + 0xda07e817, 0xa78ebed1, 0x3219bf31, 0x8ca7b809, 0x8f900df8, 0x9f27caa6, + 0x3ce0e920, 0x894db76d, 0xaeec7a01, 0xbd83b6cf, 0x1253665c, 0xc2e8c20a, + 0x73c106f7, 0x37dc0aa4, 0x5f7e013c, 0xfc163dc2, 0x5aecfb75, 0x7ce4417f, + 0x35d29a5e, 0x77febc2f, 0xedff4c69, 0x8a28fbe2, 0xdf9063c3, 0x2fbc4279, + 0x77af78e6, 0xfb416f79, 0xe2dda231, 0x1e9cb1ad, 0xbd37de22, 0xf798affa, + 0x4f7b43b1, 0x78f8cfdc, 0xf8371e9f, 0x19e01b85, 0x15baf985, 0xab9f199b, + 0xe734bb78, 0xf3c65651, 0x1e5a53d5, 0x58e3dfc7, 0x0e7a7bb0, 0xf10b7c61, + 0x82e3d2a0, 0xe80e7774, 0xa26da171, 0x62a2fb0c, 0xa9f388ab, 0xdb4c9a97, + 0x5b33fbe8, 0x55dfa8f5, 0x499cf9f0, 0xde20c6f5, 0x28192224, 0xde48cfdc, + 0xb75fd418, 0x891ddff1, 0xf76d0758, 0x0830549e, 0xcf0c4c7c, 0x41ec9f08, + 0x1d5de0e8, 0xfc0169e2, 0xa3cc197e, 0xe4bf4045, 0x03ef3499, 0x76a6ee50, + 0xdbffde3b, 0x59f78954, 0x8cfbc244, 0xb9f48bc9, 0x8547af98, 0x2a38e467, + 0x9e017b3c, 0xdf1d2fa0, 0xf7cf728e, 0x4b140894, 0x425fb48e, 0xc74a7a7b, + 0x826f8ff4, 0xdea99bf7, 0xcd9c80a2, 0x400fedfa, 0xf889d5ce, 0x1d65267b, + 0x422409d9, 0x58dd835e, 0x189ccef6, 0xac9c985d, 0x7e31166f, 0x766c3f52, + 0x7f6c42cc, 0xafa04ef1, 0xa12b8a93, 0xe8ddac20, 0x8178bef4, 0x9be55f06, + 0xe3031aff, 0x71ea3454, 0x7a5e2a5d, 0xff909ce9, 0xbfa34536, 0x843537a8, + 0xea78aafd, 0x83c06fa3, 0xddb44f4a, 0x1f32e95d, 0xa8fc8fc7, 0xe45bd33b, + 0x164e841a, 0x85c7493d, 0xf15ab6fe, 0x1d6bc2fe, 0x1f478557, 0xc6bef9be, + 0x5771e032, 0x75bffa26, 0x4c984aef, 0x6669b27d, 0x72e3ec3a, 0xdfc02f2a, + 0x3e842e50, 0x3b247bc6, 0x6b0f788c, 0x0f25e6f9, 0x1fe578c0, 0xdf50751a, + 0x58e6787d, 0x5e04579c, 0x07d29c29, 0xccdef7a3, 0x0c2bba50, 0xc09f547e, + 0x27aeadfd, 0x0f38de6c, 0x7de14f6a, 0x1499bd24, 0x607c619f, 0xbbd33a76, + 0x80d97b68, 0xc3eecdf4, 0x1caf5be9, 0x62395eb1, 0xa411efbd, 0xe2f2e26f, + 0x647c167a, 0x05fbc1d4, 0x0391dc4f, 0x86eeb5fe, 0x6eaeb8a9, 0xec2c7bbb, + 0xda74eeaf, 0x72fc20ff, 0x9d7413c1, 0xceb0df79, 0x6be23326, 0x43da75c8, + 0xac37c8bb, 0x50e9c7d3, 0x4969e75d, 0x2bdfc189, 0xf012283b, 0x3cd2f897, + 0x65626f1b, 0x9f289dfc, 0x6f83d19e, 0x31e63473, 0xfbb3b4f6, 0x403e55c9, + 0x7a46bbc7, 0x743d21d0, 0x265b2b17, 0x106d7d02, 0xed8bc865, 0x5bf7186e, + 0xeeaf1df8, 0x7a0ca28d, 0x83317742, 0x2807e51f, 0x3dd3bbb7, 0xb0f96277, + 0xea8f7f1e, 0xdf5fd354, 0x1de173c7, 0xfae0857a, 0x42e71b3c, 0xf817ce99, + 0x3dcb851a, 0xe3d55f4c, 0x9eebebfa, 0xff7a83aa, 0xfcf01bd6, 0xacf940c3, + 0xa3457385, 0x4487d9a8, 0xdf3c7052, 0xaf782913, 0xca670a83, 0x1ec07361, + 0xe501e152, 0xe1fa6339, 0xa0e7e3e2, 0xf7602f41, 0x067e7120, 0x7262c9f0, + 0x0081ce02, 0x28f3831f, 0x48abc943, 0x47a913fe, 0xaf8fbcfd, 0x6571f968, + 0x3e18efc4, 0x125e5118, 0x469637c1, 0xd44557d4, 0xe77cf953, 0xe4e7fe60, + 0x2b5f2d0c, 0xfd5470e3, 0x041bbda0, 0x24cb43b4, 0xcff600c5, 0x7c98534b, + 0xe988972e, 0xec97dc16, 0x44994b7c, 0xf0058d6a, 0xb70865de, 0xb57f6893, + 0x472d3b46, 0xdb443e31, 0xcac21895, 0xe755bf2a, 0x878701f3, 0x7ecefcfa, + 0xe321d281, 0x8fa41f15, 0x28af181f, 0x757eb310, 0x83abec02, 0xbe95da22, + 0x21fc99b7, 0xf2da5d5f, 0x97ee03a2, 0x30bcc6cd, 0x7091fd75, 0x14bb6dec, + 0xd7ebbf03, 0xe780dc73, 0xe3dacb93, 0xb2fed18a, 0x7b850687, 0xda9f5f0f, + 0x15d48f5f, 0x6f5c2b33, 0xe1315d26, 0xd65aa3bf, 0xd8256976, 0x7e7e14b3, + 0x9f8f8c31, 0x062f88ea, 0xd7fcb2bb, 0x7e70c5c9, 0xdaa196d6, 0x1acfcafd, + 0x341cdf61, 0xe7a23fa2, 0xf83ab9ed, 0x0aede7be, 0xf78e5cfe, 0x3e9cf5b8, + 0xc7e30e95, 0xfee7b4e8, 0x5b6fdc0d, 0xd764fbae, 0x0fffc0cd, 0x09ae6625, + 0xeb9737f3, 0x7e1ed00a, 0x079a1f51, 0x7e7aa6f3, 0xaa57e41d, 0x1432d8fd, + 0xf071af96, 0x0fe02eec, 0x15a636a7, 0x39e95b00, 0xdfed0238, 0xe5c70f9e, + 0x247f68c8, 0xbc2f80b9, 0x339657a8, 0xdaeac57b, 0x1fdfd99d, 0xc671038c, + 0x8a13839e, 0xf3d05fc0, 0x2d2f9b21, 0xb680ffa3, 0xa51e43f3, 0x4e8c6fda, + 0xdd7904d9, 0xb47ad7e4, 0x3afa1e23, 0xb9ee113b, 0x1e0c3188, 0x41bb019f, + 0x1abcd79b, 0xabdeade7, 0x2c57691d, 0x4f961e20, 0xa97f611b, 0xda4773f7, + 0x69a41589, 0xd030976d, 0xb88aa45e, 0xfb009fc9, 0x456bfd5a, 0xef64bf79, + 0xbef6a355, 0x9fdf3f62, 0x65c7e426, 0xa0363f74, 0xfcc029bf, 0xa0e2757b, + 0x65efd771, 0x9e3ae264, 0xbcdbfe8e, 0x9ebc30ae, 0x49c911d4, 0x40d27ae1, + 0xc182ce4c, 0xe9cbc6ec, 0xb40d9f60, 0x1fa2cf17, 0xbefc3ca3, 0x6ed03230, + 0xc01c593c, 0x0d93bdbc, 0xc09efe22, 0x918ddaf5, 0x97bfabdf, 0x2c20c9e0, + 0x6772191f, 0x3764dfed, 0xc2abe76b, 0xc77fccd3, 0xe2fdb222, 0xca37160c, + 0x6e245afd, 0x7a1df7d8, 0xdd13bf3c, 0x1f96c5f2, 0xebb67d00, 0xe3054ce5, + 0x0b7bf82b, 0xf988a0e4, 0xa7edbd7f, 0x39041e62, 0x1e1c7073, 0xd793eb23, + 0x938c4507, 0x4a5db4f4, 0xed0a7880, 0xbec6e307, 0x405ca78e, 0xe3cd43bf, + 0xfaf10cd1, 0x08eef9fc, 0x1f8f28bf, 0xc99cb4f7, 0xf94efe01, 0xb019a3e0, + 0xe2be733f, 0x15756cf7, 0xf9d1fd01, 0x1bdefea1, 0xa5fa8cb8, 0xf41c5da9, + 0x19f5aafe, 0xcfe3eb86, 0x8bf20325, 0xf7c467d6, 0x095ab3cf, 0x7ece4019, + 0xb4c51e5b, 0xc3570b83, 0x4dbd33fd, 0xb77f0b82, 0xb9445db9, 0x3a3da0b5, + 0x4cbc50a0, 0x72c1611b, 0xee764ef9, 0xf9388663, 0x2e6ff07d, 0x7fa220de, + 0xf2cb48f3, 0x6798f5f7, 0xe58327a1, 0x5de7f461, 0xc6147c3c, 0xdc14fc59, + 0xc4ff4312, 0x6fd00dfb, 0x8102d3e5, 0xcc884a9f, 0x779818bf, 0x144f35d1, + 0xc05de607, 0x6907e5f9, 0x466d15bf, 0x3c0faff4, 0x1bc840ef, 0x21f7fd09, + 0xbc6f0ee5, 0x9f6d28ef, 0xf96062db, 0x3e35667f, 0x0ef685d5, 0xd0f3b209, + 0xa74f073d, 0x877d1e03, 0xb1fd07fe, 0xd20fed43, 0x0e3cf2ce, 0x57dfb066, + 0xd2fafdcc, 0xda419e9d, 0x8b3cf237, 0x327f7abd, 0x5b47b1e8, 0xe83f232e, + 0x6cfcc83d, 0xfc4ff643, 0x0aefe666, 0x570fd19a, 0x0edf2ad8, 0x83ea84fb, + 0xeedf5eb0, 0xd377b3b5, 0xbd55f9b2, 0x6f95aa02, 0x0bf705b8, 0xdff08fec, + 0xc9f75203, 0x53a71e5e, 0x791a47f3, 0x3f9a8dbe, 0x4493e6a2, 0x27cd43ce, + 0x7c614c69, 0xf3c32f23, 0x945bd001, 0xe77ecfce, 0x68cf2233, 0xc8a1bca8, + 0x71910773, 0x8ae24182, 0x46c0af2c, 0xc6a06e30, 0xbe540d17, 0x31d647c3, + 0xd06537b3, 0x227bfd7a, 0xc5434fda, 0x1c75d51b, 0x79865139, 0x8b2f5556, + 0xb0bfafe8, 0xbce3cf5f, 0xe9438c21, 0xc8617c4f, 0x7ece7e44, 0xcb47c95f, + 0x5937def0, 0xd28efcd2, 0xe71e1c57, 0xd9f07233, 0x978fb923, 0xe47b7ed2, + 0xf5e80332, 0x4a0b13fa, 0x9de8de40, 0xd7980665, 0xa6c51391, 0x4d9bc04c, + 0xb6b37dc2, 0x53b71d5d, 0x3ffffe86, 0x1f012a80, 0x00008000, 0x00088b1f, + 0x00000000, 0x7db5ff00, 0x55945c0b, 0xe779f8da, 0x380c2b9d, 0xa5117280, + 0x380a0ee1, 0xdb95902a, 0x9784268e, 0x4d32d45a, 0xe5450757, 0xdb698032, + 0xcbbaeee7, 0x5acd4d78, 0xb5aca8dd, 0xbcc0c1be, 0x1a163b60, 0x25a3b614, + 0xb68b9599, 0x3f9b5b99, 0x0286f328, 0xffb9f562, 0xcffebf6d, 0x3af39cf3, + 0x7e988ef3, 0xbf67dfbb, 0xde73877e, 0x73ce7d73, 0x9339cf3f, 0x196e39a6, + 0x9eb19fd3, 0xcadb2d1c, 0xc87b3b18, 0x630d81bc, 0xf7fc07ec, 0xacf2c653, + 0x18036312, 0x319abafb, 0x3e57deaf, 0x7c81fb3f, 0x02d8c196, 0x316358e6, + 0x33235a43, 0xbfd191af, 0x1d1fb01f, 0xf281ee9b, 0x988357f9, 0x5dafc237, + 0xb63d14f4, 0x94357f9b, 0x3d424779, 0x3677af13, 0x4f285204, 0x1872f1c0, + 0x9de912cb, 0x6edf2d22, 0xebf69cb2, 0xa613c2bf, 0xc53557ca, 0xf9a74e58, + 0x47f8e5f2, 0x636ffc0c, 0x98c91646, 0x97627f93, 0xdb74fc5e, 0x913f485c, + 0x5856091c, 0x9ed48557, 0xb10c0f7f, 0xef57ba26, 0x2d3ae330, 0x63f29bcc, + 0x5e608ceb, 0xd5ae71bf, 0xf5a46abb, 0x2566e0f8, 0x6bd6f9b8, 0x5d7c3826, + 0x38137d1d, 0xe8e0aac6, 0x05413feb, 0x4ffbebc7, 0xaebff1a1, 0xff49bb4e, + 0xbfd06f43, 0x5f7f3555, 0xee3449bf, 0x0b0d0caa, 0xa4f486cd, 0x5e00cdc1, + 0xcb235500, 0x1d80cc65, 0x795654c1, 0x66ad19c7, 0x75257b5f, 0x6cb171b1, + 0x946f7c14, 0xfdf0dc0b, 0x25ae6592, 0x985d5219, 0xa1dbb186, 0x705ecebd, + 0x086bf417, 0x41708f0b, 0x89ac133f, 0xc2efaeb4, 0x28301516, 0x08f06eff, + 0x838f15d9, 0xfcc42a2c, 0xf2c541aa, 0xe37f1c7a, 0xb5f70c73, 0x0fc7c8ca, + 0xfc332fd9, 0xba30eece, 0x777ea193, 0x7996c7cb, 0x06dfce30, 0x3ee0e639, + 0xc909f32b, 0x3ee19779, 0x6dc726b3, 0x3d8c2185, 0x0dac616e, 0x50f6daf3, + 0x725eaf5c, 0x405de7fc, 0x06afec0f, 0x77c90f56, 0x25aa4726, 0xcabed7c3, + 0x01f9a7aa, 0x68b2c435, 0xa50d5f5c, 0x08574d55, 0x8916d6ce, 0xaf7ca5d6, + 0x77043d62, 0x8851e586, 0x7d2b5a93, 0x16a4726f, 0x71e6fa66, 0xccf7ffad, + 0x9fd00d2e, 0x433fff61, 0xdadd9e11, 0x906dfb9e, 0x60e45a7a, 0x11aef87f, + 0xf0763974, 0x50ed5937, 0xfaed895e, 0xdbd8f631, 0xf30ca9e5, 0x9c2c9e86, + 0xffb7c1f7, 0xe90ed591, 0x6fcbfb77, 0x50edf2c3, 0x6ef90adf, 0xcda54f7d, + 0x6624bfaf, 0xf9466971, 0x0fb16ad2, 0xf7dbe581, 0xf3881caf, 0xdcc1d068, + 0xa59c61c3, 0x474f2365, 0x9fd83a20, 0xb5b8478e, 0xec3d58e8, 0x54d35747, + 0xe54af919, 0x43058c27, 0xf619bb3e, 0x83d9f207, 0xfb035b99, 0x93ffb953, + 0x955fb8e9, 0x068b7a39, 0xbc341296, 0xbe02bdcd, 0x2d18e507, 0x2c53e212, + 0xeccf5f1f, 0xfb62258c, 0xb7dc08bc, 0x2a310637, 0x41f997ff, 0x6bdbc71d, + 0xbc7bc0fc, 0xabc601b2, 0x47efdb90, 0xa17c003e, 0xf2a5f11e, 0x668e6fa3, + 0x4f46b158, 0x78cfee24, 0xd0f8171c, 0x369fa2c7, 0xac0ee16b, 0xfbe0fdd7, + 0x2de8b06b, 0xf5c0e1c9, 0xb68c62b8, 0x68cfc47a, 0xbf14c277, 0xaacd7d7d, + 0x4ff0f6a1, 0x221dbc42, 0xa07bbae6, 0x22587167, 0x470ee5fe, 0x30d2a87c, + 0x3643f207, 0x077a8009, 0xe66165e2, 0xe9ebcc94, 0xd415b18a, 0x7b56dbdf, + 0x57c735b3, 0x336993ff, 0xd07d1d33, 0xc12a6221, 0x0479ef53, 0x6153d9e7, + 0x7d856db6, 0x827e0bf8, 0x334f2f76, 0x5850e578, 0x56bcce8f, 0x193a3c02, + 0x0075bb3c, 0xd9b57fac, 0x73ae1ef1, 0xd7e343fa, 0x183a5e60, 0x788c5d61, + 0x8b9ed459, 0x726d12fb, 0x3be3807c, 0x22db8e8d, 0x06978961, 0xc1fb523b, + 0x08c2b356, 0x98566f0e, 0xfce7d859, 0x797c7cf9, 0x54b841a6, 0x36f4b808, + 0x7c43f626, 0x5fad7aed, 0x74f98316, 0xca095869, 0xdf312e87, 0x988f2073, + 0x712e9f1f, 0x4117d31f, 0x63bad2fd, 0xeb7eb9fa, 0xeecc60af, 0xfc7eb8c9, + 0x301fb88b, 0xffd785fe, 0xa1afddf8, 0xf76fceab, 0xc004b0a5, 0xad22e913, + 0xc71dbbeb, 0x9df58b66, 0xd63ff5c5, 0x87a713db, 0x073d3975, 0x887f9cf4, + 0x527b69f5, 0x5d7d6c7e, 0xc27cb69a, 0xa5927d8b, 0xaed7de3e, 0x7e58f1a2, + 0x497be02c, 0x9908d85d, 0xe20a59e3, 0x061ba959, 0xa55bc3f1, 0x8b3e051f, + 0x5debbf05, 0x1413e02a, 0x5af2859a, 0xfe328f81, 0xccf800a9, 0xe1e4f6d6, + 0x0b2f663c, 0xea7e70d3, 0xbe51fc26, 0x1eaa59cf, 0x30e22577, 0x1bf5cfcc, + 0x66f34dc9, 0x2b86ff3c, 0xf21ebdcc, 0xbf95cd06, 0x21bd454c, 0xbd436353, + 0xf0104b61, 0xfd8c1180, 0x8bcfec59, 0xe18c1fc0, 0xcb16be54, 0xfb7883a3, + 0xee3567e8, 0x70bed095, 0xe1e1336c, 0x9b6695cb, 0x3115630c, 0x8530ac60, + 0x47aecc79, 0xe63d7fb8, 0x61dbfb1f, 0x1de2839d, 0xfeb0f151, 0xb89a1139, + 0x1c3cd0bf, 0x9c032743, 0xc70e68d8, 0xc207b840, 0xe8b30a7f, 0x36c65fb0, + 0xa7ee9068, 0xe652f858, 0xa78e9c4b, 0xc70ebb32, 0xa839907b, 0xbd2ef1de, + 0x1c1d019d, 0x3060f407, 0x8b9887ef, 0x373067ca, 0x979933a5, 0xb59cffea, + 0x03a15e53, 0xfd39ffc0, 0x8d9ffe39, 0xb26f0992, 0xc7be01e2, 0x2f06b382, + 0x7e4c7585, 0x6199352e, 0x0803359f, 0xf79b373e, 0xb1c38964, 0x1db8eacd, + 0xf05bdfd7, 0xd0354bed, 0x25e8c68f, 0x27c6bbfc, 0x78100dc6, 0xa27ce3f8, + 0x09e397ad, 0x06398390, 0xd8af70e0, 0xe5ed7bd2, 0x8cbd7093, 0xfe9e4859, + 0x9e5fd04c, 0xb3fd666c, 0x6dd97c71, 0xa5d8b9c0, 0xbe42468f, 0xd6cc8c60, + 0x5bde3cc3, 0xbede48ce, 0x13765c37, 0x869f20ae, 0x7e8bf7f6, 0xba998d27, + 0xcbd41faa, 0xdb3dbeff, 0x20c1690b, 0x7eed97dd, 0x7fbe35f8, 0x4830aaed, + 0xcba92427, 0x2d36b227, 0x065275c2, 0xf3f1fb94, 0xf5d5b3fb, 0xe198e00e, + 0x2328db98, 0x0f8ccdfd, 0x18267fe9, 0x90d843b2, 0xbd1f641f, 0x9de9eb28, + 0x0ddf4574, 0xef10d8f3, 0xb2fb8b98, 0x67afbef8, 0x2d33bd23, 0xca2468fb, + 0x5d7ca3a9, 0x00dd025f, 0xd5d3b206, 0x7e80d120, 0x883e80ce, 0xb7a073f9, + 0xdaa17a61, 0xd045e94a, 0x577bf0b3, 0x9ef28db5, 0xec72c2f8, 0xcbdaee77, + 0x4e06475a, 0x6df0852b, 0x36b7c089, 0x8c13578d, 0xb255b4f4, 0x625c7ca1, + 0x0c1b1b6a, 0x1f525bf0, 0x671d836f, 0x569e4d65, 0xb7b17e9c, 0x75b71f30, + 0xad45e1c1, 0x055c5698, 0x6cbd078c, 0x1ff85cae, 0x7f5d0788, 0x7dda72f9, + 0x7ab67e50, 0xbe7f8d14, 0x77e34eda, 0xfa501756, 0x37e3bc7e, 0x4b7b0f38, + 0x15846b47, 0xe132e577, 0x1d0d7dcb, 0xe7c858da, 0xd23b25d9, 0xe676dde1, + 0x6d3d0376, 0xb5b971d6, 0xd216e419, 0x29cc98e5, 0x50ca3e2f, 0xc71e38ae, + 0x509c1ef1, 0xdcfd879a, 0x8b48aa3f, 0x9efa1ef5, 0x1f7888b1, 0x8f0cddde, + 0xbf5f0059, 0x7844b6f4, 0xfd634978, 0xae59ea19, 0x0be93223, 0x2a985abd, + 0x727bdff4, 0x7b05db88, 0x626f78bb, 0xc5b7f214, 0xb8546b3a, 0x0ceb5f1f, + 0xbb9d6be0, 0x97f68f6f, 0x9ee19d77, 0xbe433eef, 0x4be705f4, 0x5e6733b0, + 0x8e65be40, 0x76fee1b6, 0xf404bb09, 0xcf9460c9, 0x47417a95, 0xdf3057c0, + 0x14e6c419, 0xd5f73e42, 0x1748b1d8, 0x7caa1e38, 0x7949df0a, 0x5f84b9f5, + 0x6de37d5b, 0xecffccf7, 0x725fc805, 0x903a5c6b, 0xa7989753, 0x575c4deb, + 0xfa86d99d, 0x0da49a63, 0xea784a5a, 0x934c3a26, 0xc0a5daac, 0xfabc7657, + 0x303fc0e2, 0x1b181bd4, 0xdadfdf05, 0xe77c4c14, 0xd4ed9d2d, 0x22ff6c52, + 0x53caff6f, 0x09b2fcbf, 0x462b27d3, 0x3ef112fc, 0x5ae09c3e, 0x21d2fbfc, + 0x63436788, 0xbfa01b61, 0x5e486f5d, 0x99631653, 0xc4560735, 0x6d867cc0, + 0x840cd0e9, 0xb49d7874, 0x21a1d312, 0xf8658705, 0x95bc5efe, 0x21b231e6, + 0x72458e5e, 0xecfee819, 0xa87fa4a7, 0x9a8c92f5, 0x320763cb, 0x44327e9f, + 0x7dc05cf2, 0x62721959, 0xb63fc904, 0xdbd9fa91, 0x99e3f532, 0x7cd00eb4, + 0x7a45de70, 0xb70bc91b, 0xecf116ab, 0x46cd2392, 0xeba17afa, 0x4bdfdc79, + 0xca1b488e, 0x571a7d8f, 0xff589de8, 0xf9d69694, 0x50b1dd46, 0x35fbe41d, + 0xbe0998ea, 0x21ef0c57, 0xd83159b9, 0xc1dc70ca, 0x805bdd2f, 0xdc6ca9f0, + 0x38fd4b5b, 0xea09368d, 0xd2bdec95, 0x8d94728a, 0xc464b667, 0x7f9e46af, + 0x86dd9c62, 0xf6a4b572, 0x2b6f9e5b, 0x58217ca4, 0x3fac5a13, 0xcf69eb8f, + 0xdac53909, 0x117f88b3, 0xfb7d5aca, 0xc67c04f5, 0x5de39bef, 0x3ecc8b31, + 0xe97206f9, 0x8c59d202, 0x1b6fb79e, 0xe08e333b, 0x49728b72, 0x3d39e7e9, + 0x4e509973, 0xacfcb9ea, 0xf8817e07, 0x17fffd01, 0xd1c8aff6, 0x6cca5958, + 0x3ec77584, 0xb4adb067, 0xd338fade, 0x3921adfb, 0x5575e8aa, 0x89585f42, + 0x36fda055, 0x804e43b3, 0xb90be671, 0x0cd6b4cb, 0x319e43d4, 0xa409b5db, + 0xa3de81d7, 0x4c667921, 0x0658bd40, 0x4fd12f3d, 0xdf8733cf, 0x366b3c92, + 0xfdb143db, 0x2fefd6ad, 0x3157f9e6, 0x444b424f, 0x31c85748, 0xf23de03b, + 0xa127764e, 0xeb0357aa, 0xe790701b, 0x6dfa1213, 0x7aba055a, 0xfa958252, + 0x7c11f801, 0xca19e761, 0x243ca509, 0xb841e39b, 0x47fa48c3, 0xe1a2c454, + 0x9af0fc8b, 0x1123bd69, 0x5bffeb0e, 0xbfa84af6, 0x1bb33ffd, 0xbe7025f1, + 0x3fdc0945, 0xb9890bf1, 0x97578834, 0x45af54f5, 0x8febbed7, 0x34a5aed0, + 0xed7686c3, 0xd821e43e, 0xf49ea84f, 0xe61096a9, 0x99697a42, 0x7d46e91c, + 0xa7b42dec, 0x88661e90, 0x7c4626f6, 0x40c665ba, 0x0d0387e2, 0xf35c1800, + 0xaf6f034a, 0x2641f45b, 0x963cbff6, 0xc94ac7e4, 0xf48136bd, 0xcbe49935, + 0x6a8fc149, 0x6533bcc2, 0x9cb9af28, 0x939c70c2, 0x61569760, 0xa22092bd, + 0x7b309abb, 0x7dd7f20c, 0xdf132dff, 0x790e19ab, 0xf225f133, 0xb64cd4c7, + 0xfe4184c7, 0x351fb161, 0x67faeeb5, 0x69c9bfb1, 0x3281aeb4, 0xe2f5445b, + 0xe99f3f79, 0xfdc73b78, 0xdbd45ac1, 0x20c50241, 0x4e285efc, 0x2a07c866, + 0x44cec613, 0xf7ec52bc, 0x28df82e9, 0x630363fd, 0xfc63ea2e, 0xf5f98cdf, + 0x07aba426, 0x201d4c4b, 0x92c9d839, 0xbf682115, 0xbd90e83e, 0x1e5bd406, + 0xd35fb3c8, 0x7fb0120b, 0xb3c24cfb, 0xf27ec562, 0xbdb843ce, 0xeb6463dd, + 0x7d847f49, 0xdf1ebccd, 0x22633c2a, 0x52c7edfc, 0xf397a703, 0xd7482f38, + 0x714a3b07, 0xe34d55de, 0xcaedfc23, 0x8757f319, 0xf18bdd12, 0x23db562e, + 0x5ea1274e, 0x32a94050, 0xc14e329e, 0xea5da314, 0x818df68f, 0x4239aaf4, + 0x7832ad0f, 0x4dfd21a7, 0xa31e3937, 0x642eca71, 0x7fd8bea1, 0x9c3f5a4a, + 0x32fbf77f, 0x253d3c43, 0x3214f5f6, 0x45a7c46c, 0x4c2f8421, 0x8ebf1de4, + 0xf41cfd20, 0xc737c21a, 0xde5286ef, 0xccc7b7a1, 0x1c5cfc47, 0xca71f84c, + 0x729fbfc2, 0xcd7e1186, 0x87f95dfa, 0xaa7be00c, 0x78784f50, 0x3f2645aa, + 0xca96dfcf, 0xb9c03d5e, 0x67d5ca6b, 0xd75da053, 0x3772afb2, 0xe2beda43, + 0x3f9438f3, 0x4c5456b3, 0xcab376c2, 0xfc8fdd96, 0x3d7446f9, 0x441069cb, + 0x35b6e1cc, 0xd711bec1, 0xd5ca7fd9, 0x03cbe47c, 0xcfcf9dcb, 0x0983f287, + 0xcf88678e, 0x112bdbe8, 0x7d6f951e, 0x73fa8711, 0x7b2bf377, 0x6dfd215a, + 0xfa79e388, 0xf8dee2be, 0xb099d8d5, 0xb0b52abf, 0xb73f805f, 0xc45e3a27, + 0xbce355ef, 0xa2eed829, 0xe11f2dae, 0x9add96c6, 0xa5a17dde, 0x76849f7e, + 0x254b5060, 0x0b3bb2a5, 0x7929d1e7, 0x8444a543, 0xb00be823, 0x6f168bee, + 0xb9e21868, 0xb7cbc3d0, 0x5347d7ab, 0x077e148b, 0x91ee5768, 0xb3d226ed, + 0x6f9c7add, 0x2872fd60, 0x58b77aa7, 0xbc3cc65e, 0xa9e9ac3c, 0x7b7ef8bb, + 0x179fb0bd, 0xc56f2476, 0xf7b4befd, 0x3b7f1495, 0x7ebd3038, 0x17fd7cbe, + 0x8e00bf11, 0x8744a117, 0x5060d5f8, 0x3b5d7fd9, 0xd5f85462, 0xbdd523b5, + 0x762f8fde, 0x6cc1be09, 0x88c9dc9e, 0x2e4f76f7, 0x9f0a55ea, 0x164f4660, + 0x9e696fd9, 0x1457b42c, 0x3d0ac33e, 0xf6ee5429, 0x7dfd60a4, 0x7d9acf68, + 0x8aed96e3, 0xfdcf5dad, 0x364d2e8e, 0xc56e87e6, 0xcdefd2bc, 0x59ba97d6, + 0xbba7caaf, 0x09d3f9d5, 0x73b69fdc, 0x83b15ea7, 0x30476165, 0x568fb2ab, + 0x5c11afae, 0xe057aafe, 0x2e6c68f2, 0xafe00dfa, 0xe7379a04, 0xddb93be3, + 0x23b86fbc, 0x62a9f916, 0x830bef9f, 0x51ca067c, 0xaf256f3e, 0xde7021c0, + 0x20bafe2b, 0x967bfd16, 0x4e508d44, 0x3f88516c, 0x2f9c4d2b, 0xbe81d4ad, + 0x4976819a, 0x5ad3c8c9, 0xd16c57b4, 0x1c1f5ac5, 0x6e1e6c16, 0xb85d3a44, + 0x1fd1b865, 0x1f6e561f, 0xf30ad879, 0x6b5db8bc, 0xd4af29c3, 0x7d429fba, + 0xd976e56c, 0xddf462e3, 0x17fa8768, 0x628f07cd, 0xb85b05bd, 0xbf69429f, + 0x744e7370, 0x873cdfb1, 0x33c3576e, 0x0fcea3d3, 0x07e7526b, 0xf391aea2, + 0xdc376f3f, 0x3c8fceab, 0xfd9fceac, 0x10d3a3cb, 0xd7644aed, 0x87ea3253, + 0x461fe79f, 0xdf6e71b9, 0xdfe4a11b, 0x15b8a2f9, 0x9b85def5, 0x7d8670d5, + 0x701f5093, 0x2e48936d, 0xe903ba96, 0x65ba6fa3, 0xd7e2b96c, 0x93c7f34b, + 0xd56ae632, 0xbf5f5fc6, 0xd9a67993, 0x74b48fd1, 0x23d3c8f1, 0xe1defd7d, + 0x7b47a4d9, 0x1bdc7027, 0xdb3329d1, 0x165f68ad, 0xeedfe28d, 0x7d963a5c, + 0x6d882205, 0xf88f9638, 0x4484f457, 0xf5e8b6f2, 0x2f9177d4, 0x3199ec77, + 0x0569d281, 0xcfc50f04, 0xf245b0b2, 0x32de4086, 0xfcede38a, 0xc19b92cd, + 0x32aee7bc, 0xc541fca8, 0x58f3d41b, 0xbefea350, 0xdfc0e9b0, 0xc4bfe825, + 0xe51e92f8, 0x4316c956, 0xfdcb1f80, 0x65e1ea0e, 0xd9d918e7, 0x183f7565, + 0xcd73f2fa, 0xbae1d657, 0xb8fae19b, 0x07d3e78a, 0xf806634f, 0x857efef8, + 0xfea11233, 0x32b5359d, 0x3982adc2, 0x9224b31e, 0x860de99d, 0x7d002c79, + 0x9069f509, 0x2baeb4b7, 0x0db9fb9b, 0x4cce54f1, 0xb5857e50, 0xbe1ca2e5, + 0xe36218d2, 0x5cb6b0fe, 0x4217e40b, 0xc256e11e, 0x9c7c1236, 0x8e657fc8, + 0xf9bf762f, 0xe7f93ee2, 0x8fae46d9, 0x03deb53b, 0xd6728708, 0xff70ed4e, + 0x6139ebfc, 0x51c3275d, 0xcf6808df, 0xaf0fe46c, 0xdf69eb32, 0x307e9aaa, + 0xec577ff8, 0x512ec500, 0x59ff6dfc, 0xe21070f6, 0xfec96af5, 0xd4c651bc, + 0xf115a7bd, 0x724cd4b8, 0xce5ae1fe, 0xd9d06bcf, 0x6cd7fd02, 0xf37d274a, + 0x829ec961, 0x4c9b65eb, 0x1e810764, 0xdb3abf18, 0x3e81d7a7, 0x9fa132e8, + 0xbdc834b8, 0xe70fbf15, 0x8ccd79f6, 0xde17d214, 0xe45e3c92, 0x3867aec3, + 0xe64cd4bd, 0x64f353f8, 0x0cff7d0c, 0xfa831aa7, 0x6a4bd722, 0x3d72a536, + 0x60f3e656, 0xfe210bbf, 0xe62f1358, 0xf34ac035, 0xc9f5f452, 0x8973c716, + 0x5e2ceb7e, 0xf4247a01, 0x995bfc5f, 0x95829fa1, 0x3c92dc44, 0xaa7217af, + 0x8dc99367, 0x52d3eefe, 0x3f9e2b61, 0x13dfb35c, 0x1dcfdf39, 0xea26df6b, + 0x58bc5f91, 0x4ffd7933, 0x3567bc71, 0x7ef195d6, 0x53dbb7f0, 0xbd3fcf50, + 0xf70234c9, 0xce70d4e9, 0x72c773b7, 0x25d801bf, 0xee90adf6, 0xfca8d449, + 0xb9127bab, 0xd13fb09d, 0x3ce9e94a, 0xc90c47ee, 0x0cff242e, 0xf1f115ec, + 0x17ec75c0, 0x85f58aed, 0xc7d27e47, 0xb0f8147c, 0x4e7f7c71, 0x5c91223f, + 0x58a4f584, 0x7bfb9f20, 0x4e75f913, 0xeca2f90b, 0x0e51e00b, 0xbfc15bc9, + 0x49fc459e, 0x27f014c4, 0x51fc2fbb, 0x60c3c7e3, 0x7f1098ef, 0x1f683f00, + 0x327afc15, 0xf011f693, 0xe7a1f087, 0xf00dd349, 0x285f6d47, 0xe5a9adeb, + 0x5da047f6, 0x3270f801, 0xa0bcefd1, 0x0427ac26, 0x3c14b7cf, 0x8e775a60, + 0x205a39ff, 0xe6c9e41e, 0x4befe434, 0xea1b20a4, 0x7f844bdd, 0x467cc97b, + 0x8b658df3, 0x68d7a424, 0x0ec895e6, 0xec266d66, 0x003d27ef, 0xfc3a3f73, + 0xf32355e9, 0x58637b97, 0x8f7f2a98, 0x3f554631, 0xfaaf12cf, 0xba746f7e, + 0xeb78fbea, 0x627e5570, 0xfaaa1dda, 0xa8c6d9f7, 0x351b3ff2, 0xb27f555e, + 0x6f2ab27d, 0xce2d1667, 0x60baa5bf, 0x6f1fda24, 0x5e921757, 0xd1970810, + 0x5baf8386, 0xea46206d, 0x00b453b4, 0x0efdd1bf, 0x7c87892e, 0x14d33aff, + 0xe8c7e02d, 0xe25783d8, 0xd5a2602d, 0x43eff105, 0x80495e0f, 0x305d747c, + 0xc8c5dfcf, 0x67581f1e, 0x9332e29e, 0x093630bf, 0xeaed3ce0, 0xf66843a2, + 0xca7cb27d, 0x75a478fc, 0x3ff33267, 0x7566d8b7, 0xe53d6184, 0x547f52bb, + 0xefb52152, 0xfcf9ccbe, 0x393fb827, 0x760a7aff, 0xb18fc917, 0xac6c341c, + 0x5be74cd1, 0x78bba8cc, 0x7c0cafcd, 0x8633b253, 0x6a96b9fe, 0xc22d67d8, + 0xb7a948cb, 0xc1e942da, 0xdf4a68ea, 0x62b2b6ad, 0x756b6780, 0xab87a51a, + 0xa47e546d, 0x1fa5147a, 0x3d29db56, 0x69405d5a, 0xa521755b, 0xb34f2812, + 0xb36c6f90, 0x3c21d5ad, 0x33b0da5c, 0xd9fe3e30, 0xe1f2df17, 0x519d96ad, + 0xff2a15f6, 0x4dcf64ca, 0xb20d75a2, 0x945b9f90, 0xa9ffda1f, 0xe8d1f915, + 0xf5e1236c, 0xd59b7368, 0x48f3cd98, 0x99977567, 0xebca1357, 0xf5ebfd69, + 0xfe470cf7, 0xa669da30, 0x50bd497a, 0xbdeb0b2f, 0xf2c5a317, 0xca1b7a45, + 0x3f04e7cb, 0x901cd10e, 0x5e909c71, 0xc834367e, 0x144ef9c0, 0x5df85fa8, + 0xf5d5a3f1, 0x8706f1f2, 0x9df3a22f, 0xc4cdb3c1, 0x15b9147f, 0xc18de11b, + 0xd12ec5f9, 0xe6887953, 0x2efd15b8, 0x09ded55d, 0x84e3af88, 0x67a71f9c, + 0xa60f3869, 0x94f92209, 0x1adf7f27, 0xcdc5f90b, 0x398c70d2, 0xdc286718, + 0x96a1f642, 0x6feb31d3, 0xb6b8fae2, 0xa815f4ad, 0xd6323c77, 0x15a11eb6, + 0x81258fbd, 0x5557959e, 0xf2728190, 0xf448db38, 0x31d43f3d, 0x6a6df10f, + 0x46bdd006, 0x13f40920, 0xfc4c105d, 0x6a7f7bb3, 0x53cdea0e, 0x0cbdd60c, + 0x292ca2e8, 0x4a7ef087, 0x648e6b3f, 0x445dfcc1, 0xaca25327, 0x9e1b257b, + 0x194ce49e, 0x71bfc777, 0xd2493d2e, 0x7ca9c7fa, 0xc31e3922, 0x5c1455f9, + 0xf5f9f3d2, 0xebf89e90, 0xb3f12b24, 0xc9190701, 0x21f19edf, 0x7fd15fc4, + 0x61f918b5, 0xeb073586, 0x427ae9c5, 0xfba0ee31, 0x5dc52d7b, 0x07d0cd40, + 0x2f1efcfc, 0x8c78f0b5, 0x9a1bbc40, 0x554de5cc, 0xaa038f12, 0x291a368c, + 0xcf9cb96d, 0x30a24e28, 0xd036ed09, 0x5794fb1e, 0xdcb99383, 0xe7a35f8b, + 0x49643afe, 0x107b6530, 0x8c2ef253, 0x2c7da907, 0xecee5148, 0xc7a64e00, + 0xe87f9476, 0x5492e3f7, 0xdf58edf5, 0x11d99df7, 0x9dfb4a9c, 0xbf7e9375, + 0x43c62b4a, 0xdcc0597c, 0x7e4084b8, 0xb87245fe, 0xfb411e72, 0x137f62fc, + 0x324993d9, 0x71e037e0, 0xfc87b06c, 0x8e26757f, 0x9e1a49ef, 0x77f869d6, + 0x93e8107d, 0x790c1f90, 0x3efa773c, 0x1e49e1d9, 0x0599ed40, 0xa87bcbdb, + 0xd0f30c7d, 0x28f7ca78, 0x9d435ef4, 0x304f2041, 0xfa6b2d1d, 0xe498db84, + 0x7d211f31, 0xf91f0177, 0x775f8fda, 0xf52e8705, 0x6c4aa7df, 0x376ff66f, + 0xed29da96, 0xd86a962b, 0xffc411d7, 0x922a5f08, 0xb7377634, 0x5095df37, + 0x7a6d604f, 0xbb4a6b94, 0xbeefc013, 0x05ff7806, 0x27a61ff8, 0xf8e1ef81, + 0xc3df019f, 0xf7c06ff4, 0xf014fcb0, 0x81db4c3d, 0x97f961ef, 0x9d30f7c0, + 0x1b243336, 0x69aaa4e9, 0x855afb0c, 0xff873af7, 0x3189ddf9, 0xd9cbe37d, + 0x9ed76e24, 0xfbfbef88, 0x7c71277f, 0xdf37713a, 0xd7906eb7, 0xfe019fa8, + 0xdf84b2ad, 0x87776e58, 0xef9e73f0, 0xd77eb8d2, 0x5ff3c31d, 0x3fa8e926, + 0xc66d86bb, 0xe9a5dff6, 0xe649ef29, 0xf85ba372, 0xa8ff012f, 0xc31e657f, + 0x7aaa4a86, 0x814d24ee, 0xdef98fbb, 0x23c7cc9d, 0x1c3d44fc, 0x0fde31f1, + 0x84ad2b3f, 0xf178819f, 0x249ba085, 0x58bbc703, 0x27c8f1e4, 0xbe744ca3, + 0xe3b5f30a, 0xc49d7479, 0xfc3af1f1, 0xe77b70d4, 0x7e84fc3a, 0xe7804e08, + 0x093fa412, 0x35251fc0, 0x45b77988, 0xe082fc86, 0xa0b3a2dc, 0x3227efff, + 0x6bdb1600, 0x84ce8f7a, 0x10c8d8f2, 0xe41d9e2b, 0xd45e6e3d, 0xebb8ff17, + 0x35ff5ddf, 0xffaf547a, 0x738b75ba, 0x375d5b93, 0x97e413f1, 0xf07d3f88, + 0x1fc82187, 0x33f87c72, 0x849ed926, 0x264b74fd, 0xbb81fa2d, 0x022f1c4d, + 0x1a5dfbd7, 0x3f055fc7, 0x18fc40be, 0xbac3fd80, 0xb9eb7d12, 0x80a0ff36, + 0x14642df5, 0x8fb8110f, 0x5bf15f0a, 0x39c91dd7, 0x2601b83e, 0x041efc92, + 0x71fd1bf2, 0xc70b649e, 0x676701f3, 0x81f9426f, 0xffea0272, 0xfafdc341, + 0x56bedf0a, 0x2673c92e, 0x39f8a867, 0x67b07b43, 0xcbe881bf, 0xaf2561ab, + 0x43825da1, 0x8f59d9f9, 0xf6f5f325, 0xa0d64f4e, 0x9df5d4de, 0x27f145d9, + 0xa14e7b03, 0x59b5d67d, 0x6d3db8c7, 0x3c81249f, 0x057e8f9b, 0x8dc5fa2b, + 0xa17b6e74, 0xd43d991a, 0x853e5cf3, 0xf3d56176, 0xe8023332, 0x9dbfe7e4, + 0x60b2f886, 0x7a82cebf, 0x4fcdcac7, 0x3b7c461f, 0x515928d3, 0xc23577de, + 0x457ea1b2, 0x04db884d, 0x8f21f3f5, 0xf59a17f5, 0x8f1f2b6e, 0x18a74cf4, + 0x65536bef, 0xefa5fa02, 0x70475e79, 0xc783b05e, 0x79b3bc31, 0x9f639d09, + 0x0a2c4b71, 0xcbcbe5da, 0x9fd0635a, 0x3364a2f8, 0x39a73b40, 0xefda3cff, + 0xcd983b65, 0x3d8afe8b, 0xb2be7421, 0x7f1d46a0, 0xa4dee250, 0x64a27d47, + 0xacbcba8b, 0x9d879d4e, 0x6ceb7e21, 0x3c33c750, 0x15e22c92, 0xf270d9d2, + 0x9384d633, 0xd3f0a01e, 0xf631d91b, 0x324f9cc5, 0xfa244df6, 0xdffde549, + 0xe6697dc6, 0xdf22c9f9, 0xdf4bf901, 0xe0517df2, 0xbf9ca952, 0x4f6cb0c7, + 0x99dfc636, 0x55c7682c, 0xca157f36, 0xa82cee30, 0xcfa27efd, 0x538a6537, + 0xbb24d75a, 0x2d15be10, 0x3e3197a6, 0x31ef72af, 0xe10435bd, 0x01e908fe, + 0x1ad732f7, 0x1abcbfb4, 0x3c236b0d, 0x15ff236a, 0x202cf7b3, 0xc9b370bf, + 0x6f3de742, 0x133ada7e, 0x66257bf3, 0xdc1c7dc2, 0xe0b2784e, 0x75ce9979, + 0xb93e6a19, 0x71913c3e, 0x3d9f715f, 0x16bf68fd, 0x3ee3bee2, 0x3ee3bec3, + 0xd89fb8cb, 0xe6ef443e, 0xccedc278, 0xfef9db33, 0x2f9efb2a, 0xdf93d06f, + 0xf3ef96b8, 0x3fd7cf3d, 0xa078441b, 0x680f0263, 0xe16ccfdf, 0xbfdfaefb, + 0xf1103f5a, 0x0f0036b7, 0xf0d70d9a, 0x1d77e700, 0x7fec041e, 0x07cbf0a9, + 0xfee041e2, 0x44f82bdf, 0x10fa3c9e, 0xfe2cd9c6, 0xf1571f05, 0xef0ecd73, + 0xaa0478ac, 0x11ff1a9c, 0x392cdd9a, 0x049635fa, 0xb421bd72, 0xc0f909b0, + 0x86bb09f1, 0xfc099c53, 0x9c524633, 0xddefc11b, 0x053dfd5f, 0x7e3bbfe9, + 0xe23796f2, 0x703aff69, 0xc161dd1d, 0x96ee7e5c, 0x1b9512dc, 0x538006bc, + 0xa451f01e, 0x81b6f643, 0x07ba91ce, 0x31e8f43c, 0x693f77c8, 0x48f6e1b6, + 0x951f6e76, 0x1277bcb7, 0x31ac86fd, 0x9fb2aecf, 0x8e537d84, 0x6f7e15f6, + 0xefcafb00, 0x7cb24e3c, 0x4f3eed44, 0xcaf5a04e, 0xb266db1a, 0x9598ea83, + 0xe3af63ce, 0xbdf88cf7, 0xa1ba07e2, 0xf7c0163e, 0xeb9efc7d, 0x2835cc61, + 0xb14be90c, 0xb47e14b3, 0x0f4bf850, 0x1b44763d, 0x03aceb81, 0xb5bee3b8, + 0x8fea1f00, 0xdb9d3d7e, 0x8dd1f92a, 0xf1167fa8, 0xce78e00a, 0x469f68b5, + 0xd332fc46, 0x0f029d7c, 0x605f112b, 0x07d9659d, 0x775f5142, 0x6ce1fe0a, + 0x497f210e, 0x8f98db19, 0xe30655f8, 0x9bc0fb79, 0x487bedb2, 0xde19bfcf, + 0x655bfa28, 0x3fdebaa3, 0x250c9f90, 0x03f9927e, 0xfc69dfe0, 0x37c7c73b, + 0x7e8ce4f2, 0xcbdc0718, 0x6e90fdac, 0x52d7246f, 0xfb290337, 0x36ee9bf5, + 0xcfcaad32, 0x33e5516f, 0xfaaad13d, 0xaaac9ac3, 0x69bdc3ef, 0x0f23efaa, + 0x9cf954db, 0xfaaa51b6, 0xabb49fb7, 0x17b477f2, 0x75dfeaa8, 0xef9550ae, + 0xfcf580cd, 0xbdd739c8, 0xfeaa92d1, 0xd549ab78, 0x042a683f, 0x6169899f, + 0x335ef2aa, 0xfa8dd387, 0xeea6cfbd, 0x7f6fb157, 0xffdd4a36, 0xdfbabb64, + 0x6d87dd5b, 0xa0b52720, 0xb9076f6f, 0xd04ee989, 0x6fa0b5cb, 0x8e5e8037, + 0x2f4157f9, 0x7a03d4c7, 0x06bf9639, 0x1be6397a, 0xfcc72f41, 0x3023b03e, + 0x405d54df, 0x85d59be9, 0x78337e54, 0x0f718ab5, 0x888f718b, 0xc4db1971, + 0xe04dfee5, 0x7f68a1f2, 0xc36fb454, 0x3c3e49f6, 0xd64828ac, 0x1d3a055c, + 0x8f5e7e13, 0xc5f65ae7, 0xd768f9ed, 0xb32fbcf7, 0xcc2740ad, 0xdd5c3ee1, + 0x0452e51f, 0xec2faf3f, 0x0efd00f9, 0x2d137b95, 0xaeb06e78, 0xf8a3e3e9, + 0xb651abbd, 0x6c1ddd22, 0xfb142afa, 0x141578b9, 0x9e4291bc, 0x77f9de41, + 0xf0f5f946, 0xc7d5e31d, 0x964501ef, 0xe48794e4, 0x2524c5d4, 0x0e7ba6ef, + 0xf47b0d85, 0xb6fe74ed, 0xefbfbe87, 0x6fbfa9d1, 0xb77d55af, 0xf73c7d60, + 0xcec9bad5, 0xf4a4d0be, 0xcefaa5e7, 0xfa8ec924, 0xefed85f1, 0xb738c1ac, + 0x11453d8a, 0xde567e78, 0xde722c70, 0xd2ffc08f, 0xc8195dbe, 0xa19a2bd7, + 0xbfafb33f, 0xc89d668a, 0x933bf9f3, 0x2387e4f6, 0x18906edf, 0x6c8b928a, + 0x950dc523, 0x913bd537, 0xcda7952f, 0x4e39e1d4, 0xf61647b7, 0x73c38f3f, + 0xc7d7185a, 0xe742573c, 0xf27fbf41, 0xe31fba1c, 0xde5bba69, 0xbb71c509, + 0xdf869ef1, 0xc2913efe, 0x5227daf5, 0x8b87bdf8, 0x6284ef8d, 0xcf3ac5fc, + 0x5aee1c3b, 0xa0ffad2f, 0x4a4377c8, 0x69926ef0, 0x3557a5fd, 0x7f4a0fb4, + 0xd4c8a6cf, 0xe4a6f8cf, 0x71d75c10, 0x8dcf1f0f, 0xce3005c1, 0x62a2a4f8, + 0xe891ff9c, 0xe9323919, 0xdc6fdc75, 0x3d62643d, 0x8e7813ea, 0xf5dd97de, + 0x55b7e89a, 0x9fbdf7c4, 0xf22b7af4, 0x110523db, 0x880649c3, 0xb8533b7a, + 0x77af919d, 0x389ca124, 0x1f92b66e, 0x62414579, 0x41efee08, 0xe0bcb14c, + 0x97cbf265, 0x8ef1f235, 0x1142da5b, 0x8e378eef, 0x516f5194, 0x71c3abfa, + 0x6facf8fd, 0x4fb45cdf, 0x335aee25, 0x3fdbe3f6, 0xb14eee5e, 0xee23bb50, + 0x3f50d363, 0x4c169e3a, 0x9eab45fa, 0x37977b9f, 0x78f6fd70, 0xecad6c4b, + 0x16e15e77, 0xa69dd1fb, 0x6aed7da1, 0x337a89d2, 0x9eaa99eb, 0x9d57ef8e, + 0x77163e7a, 0x57a853c7, 0xe9945f3b, 0xb7538eee, 0x7fd71228, 0x7e7a8b76, + 0x4ece0225, 0xd232379d, 0xcd9d5f0f, 0x4cc6e8d7, 0xd0acde78, 0x53f69589, + 0x69e3c7d9, 0x1e3b2f5c, 0x390befcd, 0x5e13d4f7, 0x5b7de4fb, 0xb11dea3c, + 0x4ee3c1ff, 0x2ad7666f, 0x5d9f80fa, 0xd3aed0c4, 0x68e62415, 0x3f727c12, + 0x79fec52b, 0x97b400ca, 0x040ec90a, 0x3f210f64, 0xfdc3ea08, 0xedfeff90, + 0xb7b71c59, 0xd440f411, 0x134d8c83, 0xaf4afef0, 0xe604080d, 0xe745bbdb, + 0x198bf616, 0x4205d2f5, 0x756b3d2f, 0xbe78cae4, 0xeb435cb8, 0x81dd8272, + 0x825d8a71, 0x13da5ddf, 0x07d233ff, 0xb416cb0e, 0x70f1ee67, 0xc0d9d63d, + 0x4f4ad2f5, 0xa346effc, 0xb3a0ddde, 0x535a0559, 0x2fd0ac5c, 0xf5bd08ce, + 0x3d1ef2cc, 0x25fb27d9, 0x5ff434f6, 0xce89b4d2, 0x7e842bab, 0x90372151, + 0xb370b09e, 0xbd002f5a, 0xdf2f9545, 0x0837a81e, 0x5d47907f, 0x7277d8ae, + 0x21fd35ea, 0xd011ed1d, 0x0e90a34b, 0xdcad53a2, 0x93ec266f, 0x28b69925, + 0x5a75f7a4, 0x4fc504eb, 0xdaaaf080, 0xce297aff, 0xb20ceddb, 0xf4b0bd91, + 0xf76b824d, 0xe90edc37, 0x8f04668e, 0xdbe1c66e, 0xbbf1c4dd, 0x8db9274a, + 0x95d01ed8, 0xee4a33fa, 0xba87a8e5, 0x2f89437a, 0xf4805631, 0xb70678b0, + 0x0be8ed37, 0x850bf485, 0x29f9140e, 0x5bbfba71, 0xf9872edb, 0x54e487f1, + 0x138e77ae, 0x424b3b71, 0x06bf246c, 0x9d9eb91a, 0x8e19e257, 0xec1030f8, + 0x9f9f8368, 0x2dd9a07a, 0x52babd61, 0xe45717ee, 0x45ad64f3, 0x7e2bfd87, + 0x4cfce522, 0xb7895fe9, 0x16ff69bf, 0xebecdfe8, 0x0fdde01f, 0xdb257de1, + 0x6e39f246, 0x6d2f72b2, 0xb2a3d111, 0x6f808b9e, 0x1f451fe8, 0x739bee0a, + 0x7e7c81cb, 0xf746ddfe, 0xf943f2cc, 0x5c45f23c, 0x4f107e73, 0xbf72a4c7, + 0x0e54cacc, 0x2a9166b7, 0x549beb7c, 0xc854d8fb, 0xf23aa7b7, 0x42dca953, + 0xdae4b9f8, 0xa88c807d, 0xeef83ef6, 0xbdf88fe2, 0x0f402bbb, 0xbe7e7fc8, + 0xa926b248, 0xe78e22f4, 0xe308bc55, 0x468c4e1f, 0x6decb838, 0xce789169, + 0xce6be9ce, 0xc9359352, 0xec2e4fdf, 0xc4db0c2f, 0xd1529c73, 0x4a52c4be, + 0x4b1c15f7, 0xd7e8ad23, 0x487a42af, 0x07fe39b8, 0xdbfc3de2, 0xc956f882, + 0xde7e360c, 0xa6ddf81e, 0x417b3d45, 0x09c45d00, 0x4875ad3c, 0xfb598e74, + 0xb9fb96bd, 0xd7e44966, 0x790a107a, 0x57a8b7bc, 0xa3e28632, 0x9d2c841e, + 0x17f4d503, 0xe9fdafe7, 0xb101ea7c, 0xdc4507fe, 0x279d21c0, 0x8730fd1e, + 0xcdf9f82a, 0x73a1e60c, 0x8dac59e2, 0x95c113d2, 0xb9d4bd7b, 0xd1da306b, + 0xe40c3a9f, 0xb55da9ff, 0x6bf90435, 0xc1655b16, 0x93202373, 0xbc8c3fed, + 0x78119eb1, 0xbdc4a4be, 0x9edcfb2a, 0xf11ab85a, 0x51ec1ce0, 0xdbeb88f4, + 0x97b27f97, 0x1f3a69e2, 0x43da7d7d, 0x1e9bed0c, 0x5b28778a, 0xee9a3c34, + 0x5b58b855, 0x7f6fae5a, 0xf654fd95, 0xaaacca0f, 0x0cb5857d, 0x674cf802, + 0xe95eb93d, 0xc0a9fbe6, 0x33d74e39, 0xf2094115, 0xe050f88b, 0xaf702b3e, + 0x3dc48b64, 0x674745a0, 0x5787fd40, 0x4fa8ac69, 0x37efb75e, 0x89af1fd9, + 0x4886f27f, 0x68dea764, 0xfa7d94bf, 0x742fb8b9, 0x3bb78c32, 0xfc9973f9, + 0xfbdbff7d, 0x63aa4df5, 0x3bc92a7f, 0x1b749f4b, 0xa237a748, 0x034b39cb, + 0x4e8037e8, 0x0da5d1af, 0x3fdbf3fe, 0xa250d2c7, 0x9d7f6547, 0x517fb056, + 0xd884b5fe, 0xfdfaecdc, 0xe7163b44, 0xb128d653, 0xa15ba417, 0x7bb276d7, + 0x700bf703, 0xe0f28ec5, 0x553a00f3, 0x7c46f1f6, 0x277be14b, 0xbb9e5cf4, + 0xfce9931e, 0x7bc90bf0, 0x2c7c82c8, 0xd7dd38fd, 0xb17fea52, 0x23f06dbc, + 0x6317cfd0, 0xcf427a78, 0xbc94f9e3, 0xe5fb883d, 0xb83188be, 0x485ffd70, + 0x9e5163e9, 0xc7fd217f, 0xa51f3cfd, 0x467e62b7, 0xe40b58d4, 0x3f14e84f, + 0x87c10ade, 0x3c7fdcdd, 0x5471f6e3, 0x32ef624f, 0x2ff5bf7f, 0xcf5bf225, + 0xf38e9601, 0x5cfb1f8b, 0x9f940241, 0x70e255fa, 0xac5b5f3a, 0x62e50fee, + 0xb8fff93c, 0xd5f776dd, 0x86515d1e, 0xf26b9c6f, 0x5e65dc6c, 0xf64c9c5e, + 0xad808941, 0xdb9d3c3d, 0xcf7e6ea9, 0xbd379150, 0xfb375f87, 0x0bcf27fb, + 0x7cb5ee7f, 0xfe7193fa, 0xb6c0eaf2, 0x9fb05227, 0x0b2bbd12, 0xab9f1bef, + 0xca1c43fd, 0x8f6d92f5, 0xb99e90a7, 0xda0a5d6d, 0x9f5b250b, 0x3e53b148, + 0x8af641d8, 0x73bbaf96, 0xaf2f1df7, 0xeb6bd3f7, 0x3f9eb9d3, 0x0f2078cb, + 0x4309cdf5, 0x3f46ad2f, 0x24aff278, 0xd6f44c8b, 0xe0e51ab6, 0xef8e34ec, + 0x7c48c6ac, 0xa2fde199, 0xbefed8fe, 0x47c7e43a, 0x15d2bed2, 0x34ecbd43, + 0x3663c12d, 0x82886f73, 0x64ad6cef, 0xf5fe67a9, 0x6139d307, 0x1f492ad1, + 0x5be51fdd, 0xe3b470d8, 0x68c2d3b2, 0x0ed7731e, 0xd9f2c56f, 0x04f978cb, + 0x38f1bb83, 0x9e9cf3f6, 0x804067e2, 0x9bc7f825, 0x3b71a767, 0x8906ce6a, + 0x9c656bf4, 0x6b2367e4, 0x9d99d7fd, 0x39f3e426, 0xe521f137, 0x65a4db1e, + 0x868ddec7, 0x1d6a0f7e, 0xf7c1a677, 0x499ccfa3, 0x2e333e42, 0xda067cfc, + 0xc77ac919, 0xeeb8a50b, 0xcb8a06ad, 0x958aceca, 0x88fea0a3, 0x8d3cc747, + 0x45659ce9, 0x3fa2942f, 0x3871b375, 0xf3e56f0f, 0x35592c5b, 0x53be3f68, + 0x845cd0fb, 0x8c67b9db, 0xae2f1fa4, 0x3f628d4d, 0x02bfef62, 0x614d6ffb, + 0xfbd8076c, 0x7b02ee98, 0xed4bef1f, 0xfca68eae, 0x94adab1f, 0xbf1ce9b2, + 0x1f385b16, 0x237f51b9, 0x02b78ec1, 0x0b5ec91f, 0x78fe81fd, 0x107f6f46, + 0xa43c99d7, 0xb13aeb62, 0x3f6864ae, 0x0f7f15dc, 0xdd7b21c2, 0x5aa8ad23, + 0xe7e3498e, 0x5f1c1f7a, 0xf1fa471b, 0x4a978eb2, 0xb486fbe1, 0xded8d9c2, + 0xd932e5b8, 0x3f34efef, 0x5de11b3e, 0xd7c0d5b2, 0xee7dd627, 0x17a89499, + 0xfbd77fa0, 0xaba7b23a, 0xb4bc74b6, 0x1b79d20e, 0xe3fbd11e, 0x77aeadfb, + 0xcdcf9896, 0x7046eae8, 0xd5d39ff8, 0x3f447113, 0x32ae815b, 0xaaba75fe, + 0xe09cb65a, 0xe15a5af7, 0x9fc834ea, 0x90e2b9d3, 0xffa5ce9e, 0xb5dcf084, + 0x2bf8225f, 0xbf6955fc, 0x9bdb8d32, 0x06cf1ae5, 0x7f04efd2, 0x3a2c16fd, + 0xe681ef84, 0xdfa829b3, 0xe334db7e, 0xafbdd747, 0xd233bf9a, 0x7ff5f004, + 0x734942c7, 0x1b448ef5, 0xc4572fac, 0xdf7e07dd, 0xce51a69d, 0xe05e48f1, + 0xae2fc93f, 0xd62602a2, 0x92e51c2f, 0x7b420de4, 0xf3dee9aa, 0x379450da, + 0xad52fb12, 0xfd2fb21f, 0xe68dede4, 0x12b4b37b, 0xf8fad1fb, 0x3527edee, + 0xee43f7aa, 0xbd520f68, 0x8ecd71c7, 0x9d3d3280, 0x2ad4c4a3, 0xbf18f6f1, + 0x4e9cd5d3, 0xc5e7fdf1, 0x7daea27d, 0x3f712f60, 0xdefd9309, 0xdcdf3835, + 0x367c8599, 0x6f95bd70, 0x387e1276, 0x4cbf1e9b, 0xf8d364f6, 0x9bacdaf3, + 0xb6c0ffaf, 0xe2677a4e, 0x173daebc, 0x7d2ea2ed, 0x43ee167b, 0x9f9c5be5, + 0xa0e14fff, 0xd5ae9794, 0x649dbf73, 0x4f2efb21, 0x79f648be, 0x9f6e61d7, + 0x4cbf3657, 0x85b7b4fc, 0x34aa47fb, 0xe851f96d, 0xd1d4584f, 0x37acfc8a, + 0x954bdb9a, 0xe8ff9ee2, 0xb5072144, 0xff78713d, 0x9f3892e0, 0x7c34ec55, + 0xb5e90037, 0x5271e34a, 0x305650dc, 0x0b8f73c3, 0x3e50cf48, 0x1afc697b, + 0xee73f3c4, 0x3f902301, 0x8ff5907e, 0xfda7f24a, 0x9322d829, 0xe2ab297e, + 0xc3adaf9a, 0x14c0f32d, 0xc1abe8a6, 0x2adef8aa, 0x6467f5bd, 0xe7e11eef, + 0x3843555e, 0x3937b13d, 0x3aac553d, 0xebf68fa0, 0x9e82afef, 0xc26f3d14, + 0x7441fe9f, 0xfb64cff9, 0xa33f217f, 0x5fd86ffb, 0x24b73f74, 0xbeb97a89, + 0x8b733e73, 0x640bafb0, 0x24d55efa, 0x62ef3c33, 0x1e7421d1, 0x5236c05f, + 0xe604e09c, 0xb17a4d19, 0x7c29fdb6, 0x9fe26587, 0x371891e4, 0x9d2e7a05, + 0x3907e71b, 0xe8ae3092, 0x70124684, 0xf64f64f5, 0xe9396793, 0x968d4e5c, + 0x3d639225, 0xa7a4c131, 0x315e9f8c, 0xfa7f5fcb, 0x4fedc487, 0x26f487e8, + 0xf7e1eee6, 0x593dbc40, 0x4c64effe, 0x22f053fb, 0x93cc8b92, 0x9c6fcd3d, + 0xa71e74fc, 0x9dcf0571, 0x89549f81, 0xf93ccdf3, 0x0ed167fb, 0x9f9fbc5a, + 0xc4d09deb, 0xc9714a7f, 0xc258af78, 0x1efcbbfb, 0xbb307337, 0x7327e91d, + 0xa95fdd00, 0x8c312dda, 0x366cab2f, 0x4d7f456c, 0x123daea5, 0xd35d79f1, + 0xe7c47a27, 0xccef3c2a, 0xb97ff7e4, 0xf742daff, 0x8c2cabb9, 0x534557e4, + 0x47e8a7ea, 0xa5cc38ab, 0x18f68568, 0xb7c8e9d9, 0xc6f2bc71, 0x3b97643d, + 0x72ec9799, 0x6f1a8367, 0xf6fba37a, 0x5ba7e7a3, 0x8c62ef55, 0x63e9ccdf, + 0x9ac3c61a, 0x43f939a9, 0xd54747c7, 0xc9bbdffa, 0xb5f0e74f, 0x51ab9dcb, + 0x904ee98f, 0x4a8ef86c, 0x156b9077, 0x14ae47ea, 0xbf74d7ae, 0x017b2bbd, + 0xf67717f1, 0x077c4cd4, 0xe3b1eb86, 0xcad26ed7, 0xdf19f37e, 0xdd7ffdc2, + 0x1f64ac41, 0x1063bbed, 0x29fdc7ee, 0x39e90585, 0xd1cc7ef4, 0x234fd0bb, + 0xae04e9ee, 0x9f0a68e3, 0xdff411cf, 0x3de6f864, 0xf3963631, 0x3c26e633, + 0x62f7156a, 0xa516f894, 0x578116fd, 0x8917ecd7, 0xc46e9dfb, 0x04bcf05f, + 0xbcf132e3, 0x229dd304, 0x4bcf137e, 0x88aaff30, 0x12f3c4df, 0x12f3c72c, + 0xf88a37cc, 0xc12f3c4d, 0x60979e3c, 0xdf88a6fa, 0xa553823c, 0x1ae6b3b8, + 0xa4568bc4, 0xfcbe81b5, 0xfc80f089, 0x13fd7540, 0x3f3a92e1, 0x8bfaa250, + 0x5c6b9bd2, 0xb4a7e819, 0xfdc57908, 0x1d83eb94, 0x2af840bf, 0x15cf0ef7, + 0xe90fbd3c, 0x8cf85c68, 0xbd5f4859, 0xf90c0dfd, 0xc774aed0, 0xf877ac32, + 0x9b493df0, 0xe89a3f88, 0xc3c4f8fc, 0x05f75543, 0x5c8da4c7, 0x31f90d95, + 0x6bdc4966, 0x50ac38de, 0x5cf0fbb1, 0x5b28a5bc, 0x0582f9cb, 0xd93ce4f5, + 0x2ce38c59, 0x448d318e, 0xd53c3bfe, 0x1fba78f1, 0xb81fcebf, 0xa1f50930, + 0x53f59d56, 0x3eba97f4, 0x9bb431d2, 0x529abf14, 0xe63a90cf, 0x3e376c19, + 0x08d5712d, 0x0c881fec, 0xcf5d9cf9, 0x767e701a, 0xdfc4b04d, 0x916ab08d, + 0xf6233c0f, 0xeb95ac7b, 0x55bd5ec5, 0x76768e1b, 0x78fe98d0, 0xf62ada7e, + 0xdfd8b0f7, 0xf17f6223, 0x969c69bc, 0x8a61379f, 0x2a984de7, 0xd2c75a71, + 0x274a5f0a, 0x21c4f6f8, 0xddbf157c, 0x1a3ee504, 0x9ea1c4f3, 0xd7c099f0, + 0x919f0407, 0x79eb0ad2, 0x2fdd0f3b, 0xb4fe172c, 0xa0be714e, 0xe76953ac, + 0x9dc7cf6b, 0x67f38c32, 0x13dc4fd6, 0x185cc41b, 0x8de53af7, 0x7507f218, + 0xce3df9b9, 0xc8db4029, 0xfc1bd8bf, 0x73459dfc, 0x7af2993a, 0x295bd514, + 0xe1159afc, 0x0718296d, 0x49e825df, 0x76f72bc9, 0xde40462b, 0xafab8bec, + 0x8296d298, 0x925df571, 0x54788349, 0x3f7f95b1, 0x22ade82e, 0xbca7f441, + 0xc4f46087, 0xef743ee1, 0xef0e237f, 0x7b37ad89, 0xef7e7017, 0x98f2f7e5, + 0x84e30537, 0x29cf253a, 0xdfad878c, 0x8c41f939, 0x79d4ed87, 0x8efcc25e, + 0xc41f539d, 0x694ed878, 0xff8b29cf, 0x389e01f7, 0xdfad978c, 0xf7e44539, + 0xf36614bc, 0x3b5eebcb, 0x2bf5df85, 0xf1883ea6, 0xee0d13b3, 0x2f88d5c3, + 0x6578e47f, 0x0cf7bdda, 0x99bca7c2, 0x7763ebeb, 0x1af8bdef, 0x21bde3ca, + 0x55ff6e74, 0x7bc13c7a, 0x1b2bf365, 0xf6bacf10, 0xd60e88e8, 0xd2f27c37, + 0x819ea9af, 0x689b2b9e, 0x6ba364f0, 0x979dd5e4, 0x2771c01f, 0xc1be7b06, + 0xcc869ffc, 0x8c4c79a6, 0xeefc74e0, 0x3107a290, 0xef6bbd9e, 0xee90c7ee, + 0xfc63f626, 0x132ef5de, 0xebd94fed, 0xaed0e3e9, 0x9b690aef, 0xee57fd8d, + 0xfdf3f034, 0xbde8a3d7, 0xee749e88, 0xb21d2e6f, 0xabe50e31, 0xdb1dcde6, + 0xc67e8d7e, 0x6f3a269d, 0xfae70aa9, 0x9b5c995d, 0xdfed08fb, 0x80fedbcb, + 0xa261def3, 0xf452cff3, 0x74be40ad, 0x17bf325b, 0x66afcffe, 0xc9e43ee3, + 0xca7ee85b, 0x0d267537, 0xdeb8e1c2, 0x83ef0fde, 0xc8eb8eb8, 0xf9152cce, + 0x7c1113d2, 0xf9edc13e, 0x37fd7fb4, 0x2d7ca1c6, 0xfde5f88b, 0xf289ef38, + 0xced097c6, 0xf7f0af61, 0x00efcecd, 0xf3bb41b8, 0x0e8a3af5, 0x4211daed, + 0xa53bb6f7, 0xddf1b38d, 0xaf3d570c, 0x48da69d7, 0xa7d574f0, 0x76bdf7f2, + 0xb0c3a740, 0xf95526de, 0xb257faf9, 0xb0bd0ed0, 0xa3d92273, 0xf42b9e0a, + 0x78175652, 0xafdf8c2f, 0x337f132c, 0xfd998b8b, 0xf6174afc, 0x02f5df3d, + 0xd0bfb5f3, 0xc8fba3a0, 0x0ab606a5, 0x7a1571e3, 0xb7bd8b28, 0xa657d700, + 0x7d414da9, 0xfb6474a5, 0xf38ba46c, 0x868c6626, 0x39081f7a, 0x7cb8d655, + 0x37bdea32, 0x431dcf9a, 0x56fa1f38, 0x4db7e1d0, 0x79ffb726, 0xb7fa605f, + 0x50fd666a, 0x7cffcbeb, 0xdc9efa91, 0x138f7a07, 0x70cab3ed, 0x414e3fce, + 0x5fe006fd, 0xfce10fb7, 0x7552ce62, 0x3c218cfd, 0xdf52b10e, 0x4ef2829e, + 0x887d3fe9, 0xda83eb85, 0x2a277a76, 0x5944ddb0, 0xfc5d9bf0, 0xa35969de, + 0x1df741d4, 0x3e91a410, 0x5d199678, 0xe9d38c6e, 0x73a21f6b, 0xbde03ec5, + 0x34f12182, 0x8983595e, 0x07972dee, 0x7ea287b5, 0x0f690ce4, 0xeba7bd45, + 0x8bde994d, 0xafebedc4, 0x1be09ff4, 0x9617f14f, 0x5376747a, 0x72c1e35f, + 0x885e2ed0, 0x3e28037f, 0xeb40921b, 0xe60a692e, 0xed2da4f7, 0xf0386f74, + 0xd3ae211e, 0x5d8f47e2, 0xfa472f4d, 0x87b3e7db, 0x57ff0bc4, 0xf74dd107, + 0x438cbf3f, 0xb0d3283c, 0x785e7855, 0x15f7e241, 0x15f74f20, 0xc773882e, + 0x41ccefb2, 0xbe173f88, 0x771d1275, 0xe7c4ed49, 0x88aabbcc, 0xdae9743f, + 0x4349cf89, 0xae7c417f, 0x367dac2b, 0xd0f32df2, 0x4c7bfc35, 0x4fbc6cfb, + 0xc8886173, 0xf724660f, 0x40daee07, 0xcca264fc, 0xcbd818e3, 0x0bf70b3a, + 0x142f7871, 0xed6c6270, 0x3bb26a89, 0x8fd45674, 0x424a8762, 0xd6fbd7ff, + 0xa9e8fb2f, 0x3777598b, 0xf0967d22, 0x9f406277, 0xf50d786a, 0xf49119be, + 0xdc204dce, 0xfebe7394, 0x805f7fe1, 0x710a64fb, 0xe7821cac, 0x64ed19d5, + 0x93b60057, 0xb6f95efe, 0x6ecbec81, 0xe436cf5d, 0xc7661d5f, 0xa9cf58e3, + 0x2d935b6f, 0xf6fa7de1, 0x9bdf3c56, 0x7be3dca0, 0x575be385, 0x9efccbc6, + 0x7c273882, 0xbe03ec4e, 0xf88b5881, 0x7e7df121, 0x0ff5e9a7, 0xb574df91, + 0x0e9f1225, 0x4df3a7a4, 0x0a7bd34f, 0xbbae4127, 0x93ffecfc, 0x79d0af45, + 0xc38c74fc, 0x3f7f5f30, 0xa9fbf7b5, 0x0db20764, 0x8f88e57e, 0x207cea35, + 0xbd2f105c, 0x11703a2a, 0x5ba78fdc, 0x63a3bbf8, 0x821de8db, 0x9029f96b, + 0x07f2fd97, 0xf501f203, 0xea3b5ef1, 0x2f51c70f, 0xf60e3840, 0x7dbb209e, + 0x5d938f37, 0xf28d7209, 0x9ce9837b, 0xe41bb358, 0xb72e7f56, 0x87945e50, + 0xaabf91b6, 0xce81af6b, 0x9f345637, 0x03f5c38d, 0xa65f923e, 0x488df9bc, + 0x12bfe7b4, 0xc7c80376, 0xd94b8a48, 0xf6891cdb, 0xd4ee5287, 0x7c445278, + 0x0ff2167c, 0xf642bca5, 0x553dd0a6, 0x39de8da9, 0x4de70af8, 0x632f21f5, + 0x9c3ad19e, 0xd67ba712, 0x0a6bdfcc, 0x8213b7dc, 0xa07f019f, 0xbc572777, + 0x0a05fdc9, 0x7c15283f, 0x679620e5, 0x28b7fa70, 0xde7843e7, 0x07df7483, + 0xe140789f, 0xf9116c7b, 0xb10f8e73, 0xf68ab872, 0x37f72fd4, 0xb7b8b8f1, + 0x3212b33a, 0xdaf59db0, 0xfc6b8f7d, 0x5fc7d128, 0x13440f90, 0x8ba1581f, + 0xbd957584, 0x3abbd124, 0xe796b3a5, 0x50b67543, 0xe7bd08fb, 0xae718259, + 0x15e7ebe6, 0x43154788, 0x34ca9c38, 0xdb2eeedc, 0xcf39d126, 0x3f3f1d05, + 0x71437e03, 0x2dc70bf4, 0x9bfa47cf, 0xef42bfdf, 0xacdf1f6f, 0x5beeebff, + 0x1f9e5a2f, 0x979d07d5, 0x3ad4dd2d, 0x5fdf5d80, 0x3f36a3a9, 0xb97d7ad2, + 0x260bef32, 0x75639e65, 0x31e1fc03, 0xbe3e797d, 0xf8d0b8fb, 0xaf83c2af, + 0xc1b342fb, 0xe017728b, 0x77b5e74b, 0xf2a45d5f, 0xbfacdeab, 0x73a6e652, + 0x3fcd1b8f, 0xde4a7530, 0x0ad71413, 0x744f55f4, 0x37e37406, 0x024363de, + 0x452511fc, 0x157bd1b7, 0xfcdba28e, 0x298111fd, 0x1a81ca30, 0x5170d98a, + 0xdb38740a, 0x943c07d6, 0xb94389fa, 0x8131f55f, 0x962703c7, 0x231aff3f, + 0xe86d8e3f, 0xc7df1b80, 0xfff043b8, 0x718fbe5b, 0xb7af304f, 0x574164df, + 0xbffef74b, 0x7bb83f93, 0x3f3a79b5, 0x18b33067, 0x9d1adef8, 0xefdfd5b9, + 0xb7b889fb, 0xe996f780, 0xee9a79fe, 0x1949fdc7, 0x49fcd721, 0x04646fa4, + 0x574af9d3, 0x6f9215d3, 0x16392ddd, 0x6ae9073c, 0xde919b73, 0x5ff9feaa, + 0xbb872891, 0xb8a6be5a, 0xcfefaeb0, 0x3ad8bc52, 0xb077b711, 0xb55bc449, + 0xbcb04359, 0x7cabe0bb, 0xa45eb7ac, 0xf7027f3e, 0xe2a92ba7, 0x9f7bf02f, + 0x1cd0d667, 0xdd6b3f7c, 0x3e30d953, 0x45cc6e33, 0x7376007e, 0x9f0dca38, + 0xf51ac11f, 0xe88bf163, 0x72d24847, 0xe8a6023f, 0xe24a4847, 0xa3cc047e, + 0xf453011f, 0xfa396023, 0x7e8f3011, 0x1fa3cc04, 0x47e8f301, 0x08fd14c0, + 0xb88dfe58, 0x8c0dd12f, 0xcd39fb8b, 0x6097f7c4, 0x6fc030fc, 0x78bf7889, + 0x777f3d49, 0xa04bef07, 0x7e2ebbfc, 0xcfc451a6, 0xf9d13678, 0xd95ed55f, + 0xf7845b86, 0x18295c2a, 0x0873d347, 0x7b553ffd, 0x2b72db24, 0x79a74f96, + 0xf9c96bac, 0xd7961674, 0x5ef86ceb, 0xdf13e016, 0xe2895acf, 0xea5aca98, + 0x2e355fc9, 0xcdc53f6a, 0x0c483557, 0x0cd3acfd, 0x90ae4edc, 0x9d0474a1, + 0x5d1e9297, 0xfb236861, 0x64bb7ca5, 0x5c9fbff5, 0xf132ea35, 0x78dce509, + 0x2ac4ff01, 0xb16b263c, 0x79dace4a, 0x69fe13fc, 0x9137c5f5, 0x17a7e21e, + 0x64f3c02d, 0xa7bf972c, 0x60151b7b, 0x374846e0, 0x6b2a7f8f, 0xe306b3d9, + 0x0e356ea6, 0xe2a1e5ea, 0xbf3878fc, 0x4cf0518f, 0x30bdeef1, 0x0346ef5e, + 0xd2bb29e9, 0xbf113b1d, 0xe4ece90e, 0xdfb4396f, 0xe9d67644, 0x7f2aa94d, + 0x883c9e4b, 0x758b1dfc, 0xe1efc912, 0xb60f0ea9, 0x1e60a7bb, 0x89ee59f9, + 0x563a210e, 0x5a90d0f0, 0x81f21af8, 0xf25699c5, 0xd819e56f, 0x113fa82f, + 0x53eca557, 0xde894ade, 0x36622e4d, 0xc7305fba, 0x5389dfce, 0xc39b75de, + 0x82839c78, 0x49378b57, 0x364eddfc, 0x5b3ce088, 0xcb4e73c0, 0xc74ef47b, + 0x5778833c, 0xbfcfc34e, 0x78f3d763, 0xc2f8f986, 0x8177be11, 0x7c9327d8, + 0xca1dbb7d, 0xe283c11d, 0x8d6f7eb8, 0x8e8bfec2, 0x373e28e8, 0x14beea2f, + 0x71f9c907, 0x7920c714, 0x0c3fca67, 0xa9fe31fd, 0xa438638e, 0xeb841c2b, + 0x253c456e, 0xd2838eff, 0x9425d523, 0x251c7e2a, 0xff7bb06e, 0xfc707b1b, + 0x6efe2abc, 0xc5ef0dec, 0x3f7df505, 0xf027b94c, 0x0e29c619, 0x1f1ff5c0, + 0xc4dbef89, 0xe1b6677e, 0xf6a2f3fa, 0x44aabdd3, 0x933fffd1, 0xfee0cf0b, + 0x0b9943d8, 0xcc39e1db, 0x3e678046, 0x3f42402e, 0xf78ec7b9, 0x4bf67a53, + 0xbe5f8a16, 0x5a6e6f8e, 0x5521f18d, 0x6bbd1249, 0x31b41f9d, 0xcffa122f, + 0x21b7884f, 0xe26aaedf, 0x482ed67e, 0xe5dfbef9, 0x18aaf7a6, 0x826a3f7f, + 0x53fbb7d8, 0x3a1f7f1c, 0x513e57c0, 0xcb7755d0, 0x7bb71e15, 0x1d6c3f73, + 0xf8c73fbd, 0x0ff41f7b, 0xe87135e6, 0x2ac7f260, 0x10dbd378, 0x26f115b5, + 0x9bb78324, 0x0e98eb35, 0xcd2906f5, 0xfc80cc61, 0xabcbe2ec, 0x7d9d6923, + 0xf894c5fb, 0x98bf40f6, 0xbffd7f3f, 0xb0ff6b88, 0x47a5117a, 0xda5297ab, + 0xefa2ed56, 0xcb6e1720, 0x6a7f35b8, 0xfe1f464a, 0xf6b46654, 0xf40ab923, + 0x01d6fdcd, 0x6ba053fe, 0xdf5d1f8d, 0x773612d3, 0x351dea2d, 0x128f7a7a, + 0x98978ce3, 0x32d80f89, 0x2aa3f4fa, 0xdf933370, 0x469997b5, 0xa6c7fc20, + 0xf0356a25, 0x490ccefd, 0x74865e75, 0x3a43eb82, 0x44e914c1, 0x7cefe7eb, + 0x9c240f51, 0x1700f5cd, 0xda2601e9, 0x81cb35d7, 0xeef8487f, 0x3fc5458f, + 0x0ff0062e, 0xa61e5830, 0x062d55fb, 0x8946877a, 0xc90b1cb7, 0xf07d11d5, + 0x27e70f13, 0x3b3c8383, 0x657fbee8, 0x1ef3c510, 0x3afc71d2, 0xc9c78eb4, + 0xfe42b315, 0x7cf5d0de, 0xcccbee85, 0xf539e88b, 0xef3fa807, 0x33e93309, + 0xe416626b, 0x257c3bfe, 0xe0106507, 0x4b2c6b9d, 0x9be0b8c3, 0x03bbcaa5, + 0xd021ded7, 0x271cf78b, 0xaa6a77f0, 0x5953fe84, 0x54fa216c, 0x6a5661ee, + 0xb06b1d3d, 0x1e10ff5e, 0xf465a1ef, 0xcd71c8ce, 0xa9eefe40, 0x13e3b3a0, + 0x1b9fc912, 0xc5e3d2b9, 0x93ee7b7e, 0x71da7de8, 0x831dfcc1, 0xf3a14d3c, + 0xaefef815, 0x7d47df86, 0x9029df11, 0x5fb95f71, 0x93ef77c4, 0x05b169eb, + 0x7fb95b21, 0xb3fbbf98, 0x00fe1252, 0xb74b6ef1, 0x1fdde03b, 0x374aeef1, + 0x08f59c2b, 0xcae981f2, 0x27d68ffb, 0xa6a07cf1, 0xf7788874, 0xcf7fe387, + 0xf90da364, 0x3e70cd59, 0x04d29aff, 0xac948fee, 0xb98e51cb, 0x1c68c37e, + 0x833fbbdf, 0x1fb2bbe9, 0xa72e3bca, 0x43bf1c43, 0x9ef811be, 0xe152b3cb, + 0x4fd8f98c, 0x27af9f26, 0x43e3f399, 0xb93c8633, 0xc838e10d, 0xf87a839a, + 0xb96151dc, 0xac47e012, 0x800cb996, 0xa69be87f, 0x69d66e77, 0xbc602bdd, + 0x2f715a41, 0x3df82b5f, 0x82341974, 0x90f5dbea, 0x217a7a2f, 0x8abca3b3, + 0x6c5ef465, 0x879f9192, 0x29863b43, 0x946469ba, 0x85fb8c83, 0xfef1fa8a, + 0x7b98a28b, 0xd9fd4485, 0x673c4a35, 0x020efe2e, 0xb6173f23, 0xed411d0f, + 0xdede1a5d, 0xb6f485ae, 0x51defe44, 0x9d036acf, 0x3e3d1683, 0xa4e3e498, + 0xedfbeab1, 0x38f067df, 0x985d2505, 0xf9d15569, 0x74e955dc, 0xd577389e, + 0x43d40a8c, 0x74c10d1c, 0x81f3af1f, 0x9df0bb97, 0xbdd972f1, 0x6bb413e0, + 0x216f1d32, 0x5920b95f, 0x0a85ef67, 0x477c1f73, 0x0e31718f, 0x6f4be4cf, + 0xed70dca2, 0xbaef8a39, 0x4c80ffdd, 0xfc67efed, 0x8ab6647d, 0x9f7903bf, + 0x1a36b2eb, 0xb46fbffa, 0x0ef27e44, 0xf50e2593, 0x5fb122ba, 0x14ff82ad, + 0x829c19ad, 0x787df576, 0x9c87dece, 0x3d793291, 0xf76dfbe5, 0x635d9530, + 0x990ddf10, 0x25b7bd7c, 0x6bc5eff2, 0xa1891d0d, 0xa9bcea98, 0x8d86da90, + 0x65f118fd, 0xdfcb0252, 0x25fc708c, 0x987633f7, 0x97ce9798, 0xae0933eb, + 0xf1d3d60e, 0x6ea3ae38, 0x63a3ad28, 0xde8e258c, 0x8aef10bf, 0xfe70b7ce, + 0x8f8631d4, 0x1ed2ca73, 0xe9c19e12, 0x9d17df07, 0xebf4b627, 0xba9f2ba5, + 0x5bcdea1d, 0x927ba466, 0x4a999ff3, 0x1abcca76, 0xb247ee99, 0x45f7ea0d, + 0xe2749e41, 0x0bdf02fc, 0x14177c0d, 0xa0f11cf7, 0x78448378, 0x9b4adb74, + 0x7bdfcf1e, 0x009e8136, 0xdecd8bdf, 0x8a0bd424, 0x0adb266d, 0x43778fa9, + 0xe5b807bf, 0x8ccbbbe2, 0x592126fc, 0x6e38ab8e, 0x7a22c6d1, 0xc33833a7, + 0xdbb0fe41, 0xfd441ec0, 0x4e4c8ee7, 0xbc00933f, 0xb683cef4, 0x9fed063d, + 0xaf1c193d, 0x525b8526, 0x269784cc, 0x3bbbf786, 0x9c149674, 0x936ac75f, + 0x499ef506, 0x027e382b, 0x23b518dd, 0x059fbe30, 0x111efd21, 0xd72d67ed, + 0x7e42d616, 0x90ed8810, 0xe19bc470, 0x0e8f9f84, 0xf119fc73, 0xd86fdcef, + 0xf39fe428, 0xf3e26c36, 0xb4cffb12, 0x9ef0e36d, 0xf8fab9e5, 0xa0571811, + 0xc3a3c3e0, 0xfd325ac6, 0x8901e0f1, 0x73d61ff6, 0x6d8de518, 0xccc8dcd8, + 0x007e5401, 0x58d263f1, 0xe421c52f, 0xe7864ec9, 0x8cd1bdf8, 0x197be9e2, + 0xb5ded7a7, 0x0a6fe25a, 0x01f8509f, 0xef1d83e0, 0xadfb2ac7, 0x2bff85f0, + 0x43e0043d, 0x1be1457c, 0xf0517f0a, 0x8133e14b, 0xc01b3578, 0x6a08f77c, + 0xe14cfc4f, 0xcd0eb863, 0x517f1f08, 0x76b759f6, 0xadfc868c, 0xe4f39f62, + 0x40dfbb8b, 0x49989438, 0x1706b96f, 0x12e091b3, 0xf84d67a7, 0x47caea3e, + 0x402cf70a, 0x416dfc7c, 0x331fea3c, 0x18f7d44b, 0x7d48be7f, 0x52ce717f, + 0x59c5fdf5, 0x843e3f4b, 0x5086a77e, 0xbfdc04c7, 0xf33dbf53, 0xfe50a7e2, + 0x90bdbf9f, 0x8becedcc, 0xb8e1cff5, 0x3cc482cb, 0x96bcf9da, 0xdcbe49e9, + 0xfc30f426, 0x9732fb87, 0x8a2d3a71, 0xf28a3b0f, 0x29c22e6f, 0x611fdf0b, + 0x89bfcf04, 0xf62539fd, 0xf73568a7, 0x24b8743b, 0x5dcc43f2, 0xad74e825, + 0x97f25efa, 0x383dac31, 0xf97f77d1, 0xc4a4dfcb, 0xf72b5d21, 0xf96b1d95, + 0xe969667d, 0x1c5fd261, 0xae50fbca, 0x96a1f780, 0xcf7bf2b6, 0xc4fbeaed, + 0x3d76d9c1, 0xb71829f9, 0x1da6e6a3, 0x1b35f1e4, 0xb28a0b25, 0xbc5e5162, + 0x57dd5256, 0xdf93247b, 0xd0cc6b17, 0xfa0bbf72, 0x1f38949c, 0x7c04be3f, + 0x15cfee83, 0x5fae1c6f, 0xe747c7e0, 0x6979f28a, 0xf2954a1a, 0x571e0cc6, + 0x03448c1a, 0x4b4faefd, 0x7e27cfd0, 0xa8bf2567, 0xda6e7f52, 0x37e83588, + 0x7f01bb98, 0xfed7c79d, 0x6a5a9937, 0x26f428df, 0xfcf80de7, 0xfc2a38b5, + 0x379a0ef3, 0xaf65d3d9, 0xdf157aee, 0xdcfb2fbd, 0x6ca67240, 0xcf5f3898, + 0xa54ee770, 0x9f7e63f3, 0xf7ec52aa, 0x845f5db8, 0xd5509da2, 0x8671dfc8, + 0xcad303b4, 0xef642565, 0x1e80da57, 0xf78fafc2, 0xcfd5f77e, 0xd95fb943, + 0x9f41ab15, 0xa59df888, 0xc8afc6ca, 0xdefca0ef, 0x2abb6052, 0x6e50fbe9, + 0xff985abf, 0xede411ef, 0x549d11d7, 0xb97b7335, 0xf215ef6a, 0x5fed579b, + 0x63e8e91d, 0x13dfd7fd, 0xe8e2abb1, 0xcb86d8ab, 0x06fe0f74, 0x4c9eeaf1, + 0xedc3eef1, 0x538a76ec, 0x2b8a32d7, 0x2ebbf6ba, 0x8d1fe4ee, 0xacdaac8f, + 0x5ea078a1, 0x9e1fb5ad, 0xfb8b75c7, 0xbef58151, 0xd776e4cd, 0x7c23a025, + 0x41bba377, 0xee9df3a6, 0xabbfee06, 0x15ba786c, 0x8256a5ef, 0x5ec30ce1, + 0xd9543fbb, 0x7fa33328, 0x1fc61adc, 0x9e78dc45, 0xe842bbe5, 0x8f52981d, + 0xf987af64, 0x34bd82f4, 0xc73e6fc0, 0x1b955e05, 0x2fb4b93c, 0x0387fe62, + 0x96d29df4, 0x2b9ee9a7, 0xfd22ebd4, 0x8cc18fe4, 0x1cf5939f, 0x6e7679c5, + 0x5ae74919, 0x953d9ea5, 0x086c77e4, 0x0b9578a6, 0xe9bdf53a, 0x53bc6253, + 0xafee3c99, 0xb124e313, 0xe932abfd, 0xa44f38a7, 0x3a920bc7, 0x68b4e38e, + 0x6dc05a77, 0xa54ba09d, 0x23a7a97e, 0x9fea0934, 0xd298fa6d, 0xd4bf512e, + 0x728596dc, 0x30636cf3, 0xdb3d63dd, 0xb7fc87f8, 0x9e4bbc60, 0x3f25fd31, + 0x74b292fa, 0x88b63f7c, 0x08eeb8fb, 0x43c4cf71, 0x886ce9eb, 0xacbed095, + 0x9d5ef110, 0x6a87af8d, 0xff5d7e88, 0x4d5defde, 0xb15deebf, 0xfea046ef, + 0xbd576c62, 0xd5bff62b, 0xff28a57f, 0xe3142a44, 0xb9c5e8f4, 0x101dff30, + 0xe13ba08b, 0xcc3d9d8f, 0x7fde10fa, 0xdff01f65, 0xffbd030d, 0x668fb439, + 0xec8239ff, 0x0ffdfc4f, 0x21f37fcc, 0x3d9b2f3f, 0xe895f052, 0xd7f41cf6, + 0xfd73c477, 0x2816b9c1, 0x0e5a4011, 0xf802e5f8, 0xe61add39, 0x2cd0fc80, + 0x02753f6e, 0xe187ebfe, 0xe58e3cc8, 0xf877d814, 0x35eb8c9e, 0x4cec8e7e, + 0xbde0a6f0, 0x4f114ebe, 0xa6f70ce0, 0x17bf4044, 0xa7389e05, 0xdffc5378, + 0xf56e74a9, 0x45cd3c52, 0xdf873f11, 0x1ce79fd1, 0xc475ebc1, 0xdee8ba5b, + 0x8610dec6, 0x8de6aafa, 0x8ac3c210, 0x0d5b4c57, 0xa8d2767e, 0x5f0fae2c, + 0xad77f3d4, 0x7cf8db5d, 0x5237434a, 0x7e05173f, 0xa46d0697, 0xf7129df9, + 0x3cf54b83, 0xf463a1df, 0x0ecf7c9e, 0x85cf6efe, 0x387db698, 0xe91d85ce, + 0x11da6714, 0x44d05eef, 0x497c79df, 0x17834ed9, 0x477e75e7, 0x2a03dd08, + 0x3a66edf8, 0x33adec5f, 0xceffc848, 0xcf74600f, 0x00fd7ce1, 0x25e7d792, + 0xcf37f92b, 0xfd411fbf, 0xa52f5595, 0xc0652cfb, 0x84ef5026, 0xb5f500b4, + 0xc7cff5f3, 0x7e42fd21, 0x6c1de62d, 0x215fece3, 0x260f6e9d, 0xcec2f33b, + 0x9ffba47f, 0xe06928f7, 0x9fb289b9, 0x59e9f7ca, 0x2e986edc, 0xcb2b34e0, + 0x832dcfc2, 0xd026cf3d, 0x037d38fa, 0x002ec99c, 0x7177a27a, 0x239a794e, + 0xeca7e825, 0xca3b108d, 0x379d0ef7, 0x87040fe5, 0x30bbf160, 0xf3c2ec8c, + 0x2ec822db, 0xfa9a2d07, 0x932dbf39, 0x389543e2, 0xaba84993, 0x12663ed1, + 0x2de4f37c, 0x706ef459, 0xe1c5305d, 0xbb7e3d94, 0x644ee286, 0xbd9777ae, + 0xc8926f3a, 0xa69cf1db, 0x56bf57ec, 0x49fe45e0, 0x29d48e25, 0xe3c568f8, + 0xb8c3f577, 0x9967f65b, 0x68aee3e2, 0x20639c79, 0x0964765c, 0x45efba3e, + 0xe0275ba2, 0x502efe39, 0x2f0388b9, 0x2cfdc9df, 0x7aee6be5, 0x51e3f88e, + 0xdf38c31d, 0x43a79e8b, 0xb4fee1fd, 0xded7c7e8, 0xa1cbf546, 0x41ff6f3e, + 0x9b67cd28, 0x0392e28e, 0xdb96ebf7, 0xa5ff94ef, 0xd01e65f6, 0x0738fa03, + 0x1edac2be, 0x40f91cfb, 0xa2e6c983, 0xd7b71e52, 0xe02cf3a9, 0xc44c19f7, + 0xc4c33a1f, 0xf35689ef, 0x35f281f8, 0x71477f13, 0xd2a7c70a, 0xee85a61d, + 0x36e9cfbe, 0x115cfe0b, 0x7487eb61, 0x41fb0158, 0xbf1f09f7, 0xb375ee8b, + 0x7da8eb3f, 0x131e7ae0, 0xe1d1aeed, 0xdcff1e6e, 0x4bef9039, 0x24a9abe7, + 0x38c23a77, 0xc97cc35e, 0xe30ced4e, 0x60480529, 0xe3858ddc, 0x0f18e743, + 0xd29ddfd9, 0x743b4a1e, 0x52d95dbc, 0x5e177bf1, 0x44e2371e, 0x77c44d9c, + 0xa1b43677, 0x38fc81be, 0x5ea50477, 0xeff5f843, 0x931e0386, 0xc593d77d, + 0x7f129be5, 0x93d6ef43, 0x47a3d35f, 0x7a10ea7e, 0xfae1b39f, 0x7ba033df, + 0xc5120def, 0xe959ff1d, 0x94ffc447, 0xcacf0e73, 0xe39d125d, 0xa47aaf97, + 0x7cbef114, 0x4899a6d1, 0xca3aca0f, 0xed00acb5, 0xa6490eaf, 0x3f5d80f9, + 0xf5c64a67, 0xfdf029e3, 0x513fd04c, 0x8067228e, 0x59654ed6, 0x6d953d15, + 0xab9cfe84, 0x4e340da4, 0xf27762bc, 0xc27029f5, 0x638c1f73, 0x3701fc54, + 0xcf32bf5a, 0x57a7cd1b, 0x788ea1f0, 0xe346efeb, 0x13247f7e, 0xfdf2b93f, + 0x3fe17ec8, 0x2fd1b7a2, 0xe1fd2a59, 0x11d4127d, 0xc8839fa1, 0x046e30cf, + 0x3cc0bb6f, 0x8087e853, 0xd5a6e37c, 0x1a43f3a9, 0x468cf9d4, 0x45ab3e75, + 0xabbdb79d, 0xe3159fce, 0x3b42702a, 0x6c3def18, 0xd01ff717, 0x4bfbc60e, + 0x1e630768, 0xd14c60ed, 0xb472c60e, 0x768f3183, 0x0ed1e630, 0x1db9eab6, + 0xc1da298c, 0x8c359e58, 0xcb59c9c3, 0x0fb090fd, 0x9f8f3a76, 0x026efca1, + 0x8fa885d8, 0xbd220e96, 0xa8be7d0e, 0xedfff437, 0x478805d5, 0xd44710a6, + 0xc38c1cb0, 0x83135b6a, 0x93e203f5, 0x664c239c, 0xafb437f4, 0xd506bb3e, + 0x63b30e90, 0xe257d610, 0xbe962a96, 0xd6efbf43, 0xe7fadcbe, 0x227df29f, + 0xfbf287bf, 0xbef86543, 0x2e7e4cbb, 0x391dff23, 0xf7afb19b, 0x8ce303a3, + 0x22f895fe, 0x368e8abb, 0x53fe5c12, 0x7c8313d7, 0x461dabfe, 0x2bf5677a, + 0x4d931f71, 0xe77ea8b7, 0xde79daf1, 0xcb9d1293, 0x9c2c3ddc, 0x061ef7da, + 0x790fbbfd, 0xd0f3a4aa, 0x9f77ef59, 0x4906de78, 0xa6dce383, 0x276470e7, + 0x1c6f1164, 0x4ea77fca, 0xf51531cc, 0xa7f9bf73, 0xf85483bb, 0x787b7433, + 0x0c35efc0, 0xd61fd554, 0x7bf01094, 0xbfd4430d, 0xf2c0f023, 0x4f676803, + 0x555230dd, 0x6bd20aef, 0x28d5ca36, 0x85c597e2, 0x27c40577, 0x4f7eaa86, + 0xa7ae896f, 0xbfa871e3, 0xc90c6f64, 0xb7986283, 0xf388a47d, 0x49c7a581, + 0xb7c435ae, 0x3dfa256b, 0xde4279b2, 0xf96aa5b0, 0xe7e5a25b, 0x3646f87a, + 0xbdce83ea, 0x84fef451, 0x16258f82, 0x811b0f66, 0x596dbcf1, 0xde1fb45e, + 0xf117397f, 0x8dae42aa, 0x781bdfc3, 0xc36f7254, 0xc217a78b, 0x01de44f7, + 0x38d63fdf, 0x2f0f112a, 0x3a39ce1e, 0xb17ce00a, 0x4b7ba641, 0xe46f3a71, + 0xff0fb308, 0x209674e2, 0x8ddaffdc, 0xf41bfdfc, 0x3ee1c95b, 0x18dda8fc, + 0xf6649411, 0x87c15bad, 0x41def4db, 0xaf5d704b, 0x02af4899, 0xd3e49a3d, + 0xe932c395, 0x2463256f, 0x62b9e917, 0x4b7dca9d, 0x85a73d65, 0x78d2c83d, + 0xef8a8fbf, 0x640fd317, 0xce1d6159, 0x1938a6ea, 0x61a6b8f9, 0x63a40c5b, + 0xc3758e8c, 0xa8efe006, 0xef8a7f25, 0x227d9497, 0xf8ef8c33, 0xd09ee6ba, + 0xdccf503b, 0x824db3ad, 0x5f1be3fc, 0x6595fba6, 0xed1eb75a, 0xb51d92d2, + 0x5ee68f74, 0x82d26ef1, 0x9f6445ed, 0xc88b642f, 0xc4a73cce, 0x94780b9d, + 0x58b6958c, 0x823dde60, 0x7788946f, 0xf1f7942b, 0xefe76cae, 0xb8503f3e, + 0xf5e77e87, 0x902f5165, 0x9c3f7a5e, 0xfd00379a, 0xf6c91e4d, 0x1f4cf763, + 0xc03fa0c4, 0xad57a987, 0x75703e94, 0x9fb9d908, 0xa184afe0, 0xb008c8bc, + 0xf1e43f77, 0xbbf8bd19, 0xef78f148, 0x2a7fdbd2, 0x3adbc3ee, 0xc00a87da, + 0x7823519f, 0x909dc33c, 0xdf568e16, 0x171aa9f7, 0xe9f7c2ac, 0xa08e8fcc, + 0x7c1869bf, 0x607f97ee, 0xfeaaa252, 0x0d0c0f43, 0xbe1187a0, 0x742e74ef, + 0xb44e2aa7, 0x4acb9962, 0xe4f1f4f7, 0xd21cbfce, 0x13678465, 0xd82bed54, + 0x78bd5f14, 0x45ba3bfe, 0x7a6d7f84, 0x344a97b4, 0xba7d6e3c, 0xb79443a3, + 0x442c3953, 0x25b79745, 0x72e53eda, 0x83e3c751, 0x3a7b1f85, 0x97d89dfe, + 0x168d845c, 0xc9efe2e3, 0xa1c1ffa1, 0x54da3bd6, 0x3fc22271, 0xfdc69154, + 0x36ae1543, 0x01df9e3d, 0x00b1b5fc, 0xfc8dca92, 0x6fa8085d, 0xf9e70d8c, + 0x7fae2365, 0xc3fb0f2f, 0x0f2ac877, 0x2f4845cb, 0xf12bdf81, 0x0f9c027d, + 0xe94273fa, 0xbfde719d, 0xcfc157e8, 0xc09438c0, 0xb5f1b27e, 0xdf7a1c9f, + 0x9aa3de8f, 0x89efc85a, 0xf9933d3b, 0x3c00fbbd, 0x15fdf853, 0xfd12cf7c, + 0x43be1fdb, 0x5dbbd678, 0x00b76367, 0xf73b4a8f, 0xdfe20677, 0xbe0f5802, + 0x51a0b86f, 0x5e25b9b2, 0xfff2e10f, 0xf482dc01, 0x00800036, 0x00000000, + 0x00088b1f, 0x00000000, 0x5bcdff00, 0x6595580d, 0xf3be7e9a, 0x700e01c7, + 0x0427e540, 0x094a880f, 0x44101df6, 0x18293b53, 0x54da1595, 0x021f44a2, + 0x9a2824fe, 0x2edb52ed, 0x4c7350c7, 0x4a976867, 0x57a3ab1b, 0xb5accd39, + 0x8cce9a98, 0x7e927bbb, 0xa772b268, 0xa9aeae69, 0x66b663b5, 0x3b448dae, + 0xb5b4d45d, 0xdfbefdcf, 0x23bef9c7, 0xb5cced4c, 0xd7175c3f, 0xfff79e73, + 0xe7defe7d, 0xbbf79e7d, 0xc89132a3, 0x1befe24d, 0xffe56ffe, 0xd5a212ec, + 0x441f9d07, 0xabe5a30a, 0xae0decfb, 0x60fd65cb, 0xcbf5c5da, 0xc32a63f1, + 0x9c284a23, 0xd70770c7, 0x4d5dc69b, 0x27b53edb, 0x97f1ca03, 0x3463fc69, + 0x284a83c3, 0x1e3c5ca4, 0xca8d9055, 0x0c61d689, 0xf1c0d11f, 0x3f685d3b, + 0xaf214bb0, 0xa09d9a22, 0xd41eb974, 0x62bbdeb7, 0xc8614d3e, 0xf5e6cc63, + 0x11741c2d, 0x1b8d1295, 0xe6e5c27f, 0x1487fd7e, 0xbbf70f75, 0xca21d065, + 0x10e41d5b, 0x6a21acfb, 0xf9bdf867, 0x9dc1d117, 0xefeb269d, 0x60f37865, + 0xbb17e8ba, 0xe87a21ce, 0x6e88b9f4, 0x7645c274, 0x798dfed3, 0xa22ff1f5, + 0x71ff4c53, 0x1af6e9e3, 0x0a27510f, 0x7f0cb8b2, 0x8fb90257, 0x86688ca8, + 0xccfa349a, 0xb2efc264, 0xf21e786f, 0xa3d3a0f0, 0x512162ed, 0x8f0c6890, + 0xc7ad22eb, 0xd2593c03, 0xb8e92bd9, 0x48cbe9ce, 0x99dfe22d, 0x3bfa56c9, + 0x3728297c, 0x61d869c6, 0xa3d31f23, 0x3d363eca, 0x8c68e3c2, 0xc8b43e83, + 0x345f036b, 0x1bcdbc7d, 0x4c46e7c7, 0xce4db4fd, 0xb9f6e274, 0xd809461b, + 0x574def10, 0x8361beb9, 0xf0c426bd, 0xa467ef83, 0x7d1cb057, 0x7a39c9b0, + 0xc1f10f3e, 0xa97353dd, 0x80957818, 0x5b8c1fa7, 0xbc5cf214, 0x26d506af, + 0x37fad1e8, 0xf9dae4ef, 0xe3b627e7, 0xfe788bc9, 0x92874d96, 0x559c782b, + 0xf72ade9b, 0x6ddd13e6, 0xde54dad3, 0xf76539ff, 0xe5e82f5e, 0x86a53ddd, + 0x52015dc7, 0xd8ee5f30, 0xdc419554, 0xdeebe5ae, 0x79e3bdc7, 0xe99c1bbd, + 0x8f9f9636, 0x3b276d7f, 0x2759cfcb, 0xe24cbd05, 0x7e52f1b3, 0x18953ecf, + 0x3f7964ea, 0x9e2050ab, 0x5fda57cb, 0x5b718298, 0x75888e3a, 0xbd1db2ac, + 0xb5fff305, 0xc32de79b, 0x99bda1bc, 0x4e0d5798, 0x86dabcc4, 0xd15a2909, + 0xb35afcc8, 0x75d044a3, 0x99f7076f, 0xa8817448, 0xba7b7c1a, 0x9ff02dc3, + 0x59a13076, 0x6475f7d4, 0x0ed9fc0a, 0x1d3d809f, 0xbbbca285, 0xddf92bc8, + 0xc75fefd9, 0x50e704f3, 0x7c079b61, 0x783a14f3, 0x092a77fd, 0xa8029c6a, + 0xf7c17866, 0xff04b327, 0x5d88790c, 0xa27eaccf, 0x5e7c9326, 0x26a6e839, + 0x455efc93, 0xae7c16a9, 0xbed2cb3b, 0xa9679bca, 0x52f33abf, 0x3e35fd4b, + 0xaebf05bf, 0xfda5ba70, 0x1655eaf5, 0x6b8ac6fc, 0x0417ed2c, 0x9bf05816, + 0xed2d6baa, 0xb069ae6f, 0x68badfd4, 0x56bea5a5, 0x97c16b5b, 0xd2dbb8ac, + 0x0db6b6fe, 0x7900fa96, 0x7272c41d, 0x63e3f994, 0xf313ffba, 0xd7cef005, + 0x7ccc7827, 0xd6d7399d, 0xdc8c33d6, 0x32dc861e, 0x07f5de7f, 0xe47c839e, + 0x321ca4d8, 0x53cb100c, 0xf513eaaf, 0x305614d9, 0x2cbd9b0f, 0xbb6c4dc8, + 0x8999fad8, 0x31f33ec7, 0x7ffd730f, 0xf6c1c8b1, 0x63b4e660, 0xbf19e3a5, + 0x916fbfc9, 0xccc8ed83, 0x067d8e2b, 0x19ff0dfc, 0x5dc4df89, 0xf6fef067, + 0xf20a2c37, 0x995e673a, 0x3d654dbf, 0xea9d37a4, 0x7cb23453, 0x0e4ddf62, + 0x30c06fb9, 0x31e023cb, 0x17c04796, 0x0a9b1e59, 0x79665e88, 0x50ebec04, + 0x3b2ff945, 0xde3c042a, 0x8df01011, 0x4f016a8e, 0xf808d474, 0x02458eab, + 0x1343bafe, 0xb1d37efd, 0x3a77c042, 0x6ff944da, 0x7c05da3b, 0xca2823af, + 0xa11557df, 0x8202bcff, 0x0339c2dd, 0xf6ed5df9, 0x2e7ced84, 0xf9e711d0, + 0xfacabb21, 0xeed804ad, 0xdf14dd33, 0xd863aa68, 0x449146d9, 0x91c465e8, + 0x8bf9867a, 0x37edc39f, 0x741d476a, 0x1b8f18c6, 0x381f13df, 0x3442bb07, + 0x31267bd6, 0x1fc07e5a, 0x03e504f8, 0x2539f505, 0x3ebd9fcc, 0xf9f053ed, + 0x4dc692e6, 0xae376c29, 0x09cdaafc, 0x46db7939, 0x8f93862b, 0xb23e5d5e, + 0x638c141d, 0x29b8177e, 0xf0269298, 0x0e618b80, 0x88eec397, 0x0177de3f, + 0x81e43e60, 0xb963e508, 0xb670cdde, 0xf10a793b, 0xe5c394f9, 0x142f2176, + 0xc27ac870, 0xb41e5c78, 0xa9e745a5, 0xdf61241a, 0x84716d66, 0x1c921f60, + 0xc895b614, 0x7225c9f6, 0xdcb3e05e, 0xe5857e3d, 0x478b5664, 0x327ef20d, + 0x2255deb8, 0x0cec07da, 0xf73dfc9f, 0x514c229b, 0xd444a130, 0xbd72f58b, + 0xa0d54758, 0xcff40146, 0xef4e3524, 0x41f596ef, 0x6bc59ff4, 0x30c15f80, + 0x9c79f184, 0x7689d600, 0x185db289, 0xce7c14e3, 0xf49b24f3, 0x9642fec5, + 0xdf65fb83, 0x9f6152e9, 0xe44ed273, 0x3f31eec1, 0xfeb9f9c6, 0xdbd9d4a6, + 0x9a9fcc23, 0x26bfef38, 0xf34a5f32, 0xff9402b4, 0xc13f194a, 0x4c17e60f, + 0xc4935319, 0xe7c6c4f6, 0x39f630e4, 0x3f062f96, 0xf41bba0c, 0x48dbe58d, + 0x4f891afc, 0x1aa9fcb1, 0xf41bd28c, 0x512f991a, 0xff9505fe, 0x754cbe7b, + 0x7ac6ecf4, 0x2adc5ae2, 0x7c6df3d6, 0xe69fbdba, 0x869370a5, 0x80cbdf41, + 0x5eb4f267, 0x5d2351e8, 0x9a0bcf35, 0xe0c5ed79, 0x0bbb6c4f, 0x03e3b423, + 0x779c56f7, 0x6d273e7d, 0x8b5ff9e5, 0xa0a73a67, 0x33f1e03c, 0xf6eae61f, + 0x84da8fa2, 0x2937673d, 0xea54fe08, 0xb45b9aac, 0x9597f85c, 0x36bfab1e, + 0x8d9aabef, 0xe8de7798, 0xcd95ff18, 0x6bd1ce32, 0xa6af71f5, 0xf56e312e, + 0x6bbb6b58, 0xdaf0bf75, 0x5df96b02, 0xcbafdd7e, 0x91d83ca3, 0xbae5524a, + 0xcbf09b68, 0xdc72bd2a, 0xe3af9d6c, 0x099a767d, 0x80e691be, 0x77f17af1, + 0x7bd600ae, 0x7e050535, 0xbc04850d, 0x9c62c28e, 0x01d0d9eb, 0x09c891bf, + 0x9fddc5bc, 0x5e9162eb, 0x87ded76d, 0x8e49f3df, 0xeb852936, 0xfbb5e333, + 0x89bd17a1, 0xe1add437, 0xce96e6f9, 0x63bf402d, 0x2fe13e95, 0x178f731c, + 0xdfe40bfe, 0x8fd51699, 0x17fed957, 0xf97adaf0, 0x897c007c, 0x160287cf, + 0x7cf857f6, 0xe16d7e00, 0x79bf4206, 0xa61c853e, 0xaffd1b7d, 0x4721cef3, + 0xf7f6c8e9, 0x1b3f29ba, 0xbc9cb1ab, 0x92a93a96, 0x55a70192, 0xa5afbf62, + 0x8c24d866, 0x7c580973, 0xff3860b8, 0xe8bf90ca, 0x31c8f37c, 0x1b3a646a, + 0xa7a58d74, 0x813fe741, 0x470dcfae, 0xc4955ed7, 0x3ee03639, 0x313d9ab0, + 0xf6944d6a, 0x89387020, 0xd77e5932, 0xa087b21d, 0x89631f8f, 0xd25f1859, + 0xbfa50a89, 0xef5f5ebe, 0x16341d47, 0x53a7a6f4, 0xba5df944, 0xcfb736cc, + 0xd65cfb10, 0x7dfa215e, 0x88bda719, 0x092f9c75, 0x820f644f, 0x99d5da3e, + 0xf9e7833c, 0x0abb59e4, 0xeec5bbff, 0xd742a6db, 0x4fabb35f, 0x55f4b8f1, + 0xe842ee6f, 0x86a393d3, 0xb8b467bd, 0x7b8d1d25, 0x357957c6, 0xc8ef38bd, + 0xf5299a5b, 0x85e81490, 0x8d8f3e71, 0xf2c2bb63, 0xe125cbbb, 0x7975e748, + 0x12a7db02, 0x49d85ed1, 0x4fdc7f83, 0x4e3cd9e0, 0x0fc8ec39, 0x7e3f8413, + 0x9ef0252e, 0x9256f31f, 0xbf659fc5, 0x81add857, 0xb38e92d1, 0x3323e269, + 0x73ecaf19, 0x07eb8852, 0x1b5da52a, 0xdd85b8f0, 0xd1b57aac, 0xa9dcfb01, + 0x4cb88bdb, 0xf498f7be, 0x4097de3f, 0x26fc933e, 0xf059a616, 0x4b12f524, + 0x7c8a94fb, 0xe06a7d4b, 0xa8fd4b32, 0x3e0b12ea, 0xa58666a6, 0x39a2c67d, + 0xbb4b3c16, 0x7b3ed2d6, 0x6e0b42c5, 0x596ca1d8, 0x8b6d3944, 0xb5c7fd2d, + 0xcfb4b52f, 0xa961de0b, 0x44e060a7, 0xd6aff721, 0xb2df8ffb, 0xe4cf5ace, + 0x2f4395b5, 0x928fdfe4, 0xe614fbab, 0xd967b55f, 0x84e5e87c, 0xebac7bae, + 0xc7657fb1, 0xa29d9039, 0xffa628d0, 0xddab3ed5, 0xe2b4caab, 0x8bff5e95, + 0xaf5cdd60, 0x9fb2eed5, 0xb29e40a7, 0xf2961cdb, 0xddba25b1, 0xc453429c, + 0xf8dbf87d, 0xe1665daf, 0x2ebd2c7f, 0xfe038796, 0xb49bb730, 0x97072ac3, + 0x3072ac86, 0x1cab69f9, 0xe558f714, 0x5623f2e0, 0xad87f039, 0x67da5072, + 0x13b28395, 0xf6983956, 0x0c0e558e, 0xd7e58cf9, 0x3e5588f4, 0xe5345348, + 0x8aebf08f, 0x89f956b3, 0xbf510fe5, 0x8f3cdfe0, 0xfde68f42, 0x185afcf9, + 0xfe21afc3, 0x77e1bd30, 0x4e4f0ece, 0x67d55e01, 0xf7cf10a7, 0xabcfbe98, + 0xf279b727, 0x74ee9ed9, 0xd0257568, 0x3aae5d73, 0x0d5ca4b3, 0x87881df4, + 0x198fafdd, 0x5a59c7ff, 0x1a2fda03, 0x0bae59f5, 0x4dafd1f2, 0x39e97dc2, + 0x1ddd8495, 0xe7c72097, 0x4758b27b, 0xa87b1ef0, 0xd271d793, 0x3ec0a5d6, + 0x2b6b2737, 0xa2f6ffd1, 0x07708536, 0xfe82a0a3, 0x971cfff5, 0x1c7ebc0b, + 0x151e7b89, 0x2416ca45, 0x7d62ed45, 0x7af39736, 0xf7e896d6, 0xb9eb9514, + 0x1912fadf, 0xbd5248b7, 0x290f112e, 0x20e200a2, 0xadc8bd7c, 0x8e3d062f, + 0x3d024fc7, 0x9b2a6dba, 0x7d388a38, 0xf067d829, 0xa53d3b55, 0xfe113f48, + 0x7fee8e5e, 0x4eff5365, 0x0ed273ac, 0x97ab9cb2, 0x30e4dc86, 0xd3f27dd1, + 0xdc5e0b5e, 0x7f696993, 0xa59f11f9, 0xb42e1fde, 0xa9f697d4, 0x44ecbc16, + 0xb4fda585, 0x7c160277, 0xd2daa47a, 0x35b38afe, 0x229c7c16, 0x5f7fafef, + 0xe3e92f92, 0x7de44563, 0xba9fdfd6, 0xf788ab7b, 0xe1ad7bc9, 0x23d7534f, + 0x4ce23701, 0xdec71cba, 0x404c5c87, 0xfec5cff0, 0xb183ce2f, 0x6b47e96e, + 0x294fbaf7, 0xdd3f51c9, 0xff0db3f0, 0x01558295, 0xfdc3b9f3, 0xfba2f9e4, + 0x6d7f86f3, 0x8bd3cdf8, 0x721ce27d, 0x26cabc6e, 0xc911c1e4, 0xc7d79c82, + 0xfdf7b0d1, 0xbde44be7, 0xc6fd7621, 0x9fe762ba, 0xed95ec5e, 0x729f71f5, + 0xc335edd3, 0x5cba33f9, 0x735f1c2d, 0xb8f9f214, 0x79677d53, 0x9e7f7fde, + 0xb3cfa4ce, 0x2e5cde84, 0xb3675fd7, 0x31a3f889, 0x52a991cf, 0x7f380d5e, + 0x7e3bfb0e, 0xe37deea2, 0x1fd87876, 0x21ddbc79, 0x9fc708e2, 0x2c1b515b, + 0x01443f80, 0xef8e338c, 0x7c0fe003, 0xae1fdc0a, 0xfd176a99, 0xbd4897cf, + 0x1265da8b, 0x24807976, 0x5dda07ff, 0x0c317ee2, 0x181c85bf, 0xcc7c41fb, + 0x62e32051, 0x398b8880, 0x062e321c, 0x4031711c, 0xfe50c5c4, 0xf02a875c, + 0x02151d83, 0x2023be7f, 0xd51d23f0, 0xa3bcfe02, 0x721b9446, 0xe32f4b13, + 0x1ff0663e, 0xa373886a, 0xe71e4620, 0xe5f927df, 0xd9aceb5b, 0x6f9c5bc3, + 0x24a56aa3, 0xa6dbcf4a, 0x2dc8794a, 0x3b407495, 0xed48ffe8, 0x2945ecaa, + 0x900ea788, 0x47fbc52f, 0x53ff86e2, 0x6ee830f4, 0xfaa357dc, 0x2461f526, + 0xbfee34bd, 0xd0acfba6, 0x8c7d58bb, 0xba58dbd5, 0xbdeb3f8b, 0x8d7bde59, + 0xa7ae85f8, 0xbd0c5f06, 0x16a45276, 0x605425f6, 0xef7d06ab, 0xd1eab24f, + 0xbe92a5f5, 0x8623d003, 0x74de7ca7, 0x7687ce1b, 0x5607f0af, 0x90ccb6e8, + 0xec87e6d3, 0xf3e27ce2, 0xed37e3d6, 0x7db779b7, 0x6eef9ea8, 0xe215bfbc, + 0x201d9d5c, 0xda5f1f71, 0x737684a5, 0xf5a086bf, 0x2521147c, 0xfae46fae, + 0xe35fb817, 0x33f3d896, 0xf221d620, 0xe6b5bc2c, 0x72fd6b2e, 0x33c91efd, + 0x632760ba, 0x96570af3, 0x4aa0e7ea, 0x5f7237ea, 0xdd105ee2, 0xa1572e97, + 0x873829f1, 0xcbb4af70, 0xce3846b8, 0x21f3af74, 0x8a2a3fce, 0x0a133d33, + 0x746e4e71, 0x177c13a8, 0xcf41a1cb, 0x9e833ca1, 0xeae7184f, 0xe23f753f, + 0x8bc7cf8b, 0x7fcf057b, 0xbe76e823, 0xff40aecf, 0x7a08f287, 0x3b41f3fb, + 0xe73e99d9, 0xba09c60f, 0x7e3b627e, 0x94cfbe4b, 0x5f28b877, 0xb015c941, + 0xa8c6fb1f, 0x65d661c1, 0xfb222d40, 0xe1bf588f, 0x99ee3250, 0xfcc8cf2d, + 0xbd33cb44, 0x7b2605e9, 0x10ea5cd8, 0xa6dbbbfb, 0xff2294b5, 0x8b9ddf60, + 0x5f1dde7b, 0xce00a686, 0xb12de3d7, 0x77b219fb, 0x47211533, 0x613fbc03, + 0xb115aaef, 0x0497b63f, 0x989b7b3d, 0x02ce3c9b, 0x34068f0a, 0x96da00f2, + 0x2307c10a, 0xae10d00f, 0xb9b8fb10, 0x8133b973, 0xde76449b, 0x8be0955b, + 0x392207e6, 0xc7fe08b4, 0x9b827948, 0xde315506, 0x886706f7, 0xcd281e71, + 0xc6d0fe93, 0x1fe16bed, 0x3934f65e, 0x53888741, 0xa74b138e, 0xf3ca943f, + 0x1d3c1320, 0xbadfdd13, 0xe7b08a0d, 0xc02ba0eb, 0x9ec22bb7, 0x5d67f81b, + 0xf1255e3a, 0x3c49373b, 0x516cf4e2, 0x117ee452, 0x013ec02f, 0x6bdc1fb1, + 0x05f1e9f7, 0xfb1003ec, 0x18ec3940, 0xe031d870, 0x61c063b0, 0xc76100c7, + 0x6a94be50, 0x43e71172, 0xacd2a33e, 0xaa6e8327, 0xc825f934, 0xe4719867, + 0x91edcc33, 0x23d730cf, 0x47ae619f, 0x238cc33e, 0x8f6e619f, 0x4719867c, + 0x1edcc33e, 0x8e330cf9, 0x3db9867c, 0x7ae619f2, 0xf5cc33e4, 0x719867c8, + 0xedcc33e4, 0xd730cf91, 0x58aededf, 0xb3b71df2, 0x35dc86f9, 0xf21348ee, + 0xa6af3631, 0x7efe720f, 0x3977d7e2, 0xa3e7c1f3, 0xebb7212b, 0xc954135a, + 0xc96aaee7, 0x3e491b77, 0x3e0ad7f7, 0x7892ebdf, 0x1de19a95, 0x1e422fc6, + 0xe640b2a1, 0x47910011, 0x011e4400, 0x4a847910, 0x0023cc87, 0x72808f22, + 0x910011e4, 0x1e440047, 0x04791001, 0x0011e440, 0x3f404791, 0x910011e4, + 0xf2394047, 0x23c88008, 0xaf24fca0, 0x6304f903, 0x0ba3f05d, 0x963cf72c, + 0xcf3dcb43, 0x47e1c16b, 0x8fc3db9b, 0x8fc3d736, 0x8fc3d736, 0xa3f0e336, + 0x47e1edcd, 0xa957719b, 0xfc17e84f, 0xf83f7369, 0xb8bc66d3, 0x6212f82b, + 0xfaefd744, 0x91808bdd, 0xc571e524, 0x41ec67cb, 0x4f7c8c5a, 0x4dc95e24, + 0x545cf955, 0x192b8b5c, 0x844b06d7, 0x7ea14fde, 0xf22df81b, 0x2d37ccb7, + 0xcde4214c, 0x14c8bf8b, 0x513e46f5, 0xfddf31fc, 0xe7f84907, 0x5d7245dd, + 0xbc957f46, 0x7da34076, 0x5dbe1f14, 0x3b46fcec, 0xeb4d2f61, 0x1f9b0be0, + 0xbdff7cf9, 0x2cad929e, 0x8a6d7b4f, 0xb2f74ff0, 0x1870b59f, 0xf74b34bb, + 0xf6daf69b, 0x7ee04b1f, 0xba8a0dfd, 0xe89e8787, 0x09673ea0, 0x0256d4e8, + 0xd4c2623f, 0xd47f3d54, 0x71616336, 0x3c46dd74, 0x0044ed8f, 0xfd99e779, + 0x79e26ae4, 0xb907fd66, 0xb9cfe19a, 0x7e811fa4, 0x0e4dcfb8, 0x263d812a, + 0xaa7cbef9, 0xe0b4ff3c, 0x5c4d19da, 0xdb5f793e, 0x77f8668c, 0x8fdfb209, + 0x7416489f, 0xb2a361bc, 0x99fbcec7, 0xbb028fb9, 0xbe855db9, 0xbcfbc9ee, + 0xaf3126ae, 0xce6cd5d7, 0x75caefbf, 0xa45f70f9, 0x88a66548, 0x3c842bc5, + 0xde37419d, 0x1fd88bdf, 0xc43ef89b, 0x1d3d5765, 0x24d0fdef, 0xa93dad1f, + 0x91cd7c16, 0x2687ef2c, 0x1f855b39, 0xeec4172c, 0x16adce21, 0xf5abe59d, + 0x9a95b7f2, 0x9e784bcf, 0x0bbf7756, 0x35359bf4, 0x6c346ab5, 0x275251ff, + 0x36a6ee40, 0xebc31a6c, 0xd50142d2, 0xdabd03ee, 0x93f8125e, 0xe2170235, + 0x27d62e53, 0x4149c3ce, 0xa4c89c25, 0xdbb821b8, 0xebf19a36, 0xe99c1b83, + 0x548fbf68, 0xf89303b8, 0x7449767f, 0xc274455f, 0x5e40af16, 0x499477a8, + 0x7c72d8fe, 0x57e2f20f, 0x58f9049d, 0x613af0e0, 0x8dfd626f, 0xec0f77d8, + 0xec2adc7f, 0x21d39f54, 0x3fdd3afc, 0xb5caf06a, 0x29d1b67e, 0x43868ffc, + 0x3ea07fec, 0xde30dfc6, 0xa1dfb043, 0x1f8e7186, 0x720d4ebc, 0xb7dacb55, + 0x7383bbc5, 0xa9bda179, 0xf2e7d72c, 0x0152dff7, 0x0aed90bf, 0x0dfb29ec, + 0xb9654e77, 0x52f4d86b, 0x915dee32, 0x6fe101e0, 0xa1f1b67c, 0x905f1964, + 0x9d2689f9, 0xa6fc464e, 0x9347e759, 0x03e5eefe, 0xa96c5bb6, 0xf186ee71, + 0x2bd7815e, 0x3f588afc, 0x9bfbc891, 0x82bf5c99, 0xb195b3f7, 0x361adbe5, + 0xfec5d267, 0xae6fe1a2, 0xb95de7d2, 0xb7de29d1, 0x3890a0ac, 0xac86560f, + 0xfee957ed, 0xada7aae7, 0xca983fe5, 0xa1f2277e, 0xdfa9df86, 0xdbd4ee93, + 0x7bdebc34, 0xda7bf0b3, 0x5075c89c, 0x07e906dd, 0x4d0a7ed1, 0xb5cf8050, + 0x775e33c5, 0xc32aa028, 0xba9bcdc8, 0x931f343f, 0x0c173d32, 0xb23b0826, + 0x8112f070, 0x299832df, 0x8583ade0, 0x19b11cb2, 0x4aa473e6, 0xe3c7dd09, + 0x41fba5bf, 0x265e0f37, 0x198207ea, 0x58078e42, 0x14c5318e, 0x165d3edd, + 0xd6117a50, 0x36d4ef9e, 0xf9fae18d, 0x95f849bb, 0xe25fc3d7, 0x9ff0458a, + 0x7907a14a, 0x6f9f1855, 0x0f21346f, 0x9756b07a, 0x1203d67b, 0xec202376, + 0x1082e559, 0xd22c93de, 0x6fc0dbf6, 0xe0b5fe43, 0xebf00729, 0x57cb8a83, + 0xe215ee24, 0x77c86cfe, 0x27d41eac, 0x8f26f1ea, 0xc50d278c, 0x5e58b09b, + 0xc5b5051a, 0x47afae01, 0x9d12f06c, 0xa4aa4cb1, 0x77df5922, 0x91bc5b50, + 0x353fbdcf, 0xb367511e, 0xb3f57e09, 0x8a07b79f, 0x32aa274a, 0x94db27a0, + 0xe8bead92, 0x9f289e7a, 0xba665033, 0xf5d52f27, 0x032ef58a, 0xdf758ef7, + 0xc341909f, 0x6c0605f8, 0xbf433a64, 0x772253ea, 0xfeea4c29, 0x64a814a9, + 0xbe92d6d6, 0x79fe244f, 0x3c758b9d, 0xdff6d0f7, 0xfa08f16e, 0xd4fcfc08, + 0x45838b35, 0xac1d867f, 0x77d01c53, 0xadbe0ec3, 0xb7a0e768, 0x3cc8eead, + 0xa8b135f0, 0xc5be05df, 0x6db6e7d2, 0x3127db3d, 0x24cb721d, 0x5d5ceaff, + 0x80b8f14e, 0xd3dc4e42, 0xb9e48b1a, 0xee5f0e42, 0xf11f9112, 0xb19fb889, + 0x6fe00fef, 0xf497430f, 0xc36fe932, 0xa4b9f63f, 0xff080c7f, 0xe04fef18, + 0x7f87031f, 0x18ff080c, 0x818ff0e5, 0x0e063fc3, 0xfc3818ff, 0xc7f84063, + 0x16d87f28, 0xf33f7538, 0x685b51f3, 0xd39661ff, 0xee6b47c7, 0x51ef9e32, + 0x238f92ea, 0x63fb1348, 0x627611b9, 0x7cb13ec8, 0x72a3cbb9, 0xf4fdb4b4, + 0x547e5b21, 0x7cb69a9e, 0xdc29f3ba, 0x841fd983, 0x945b6b3e, 0x9194dc70, + 0x3b89ece5, 0x3cbe8412, 0xd84b8f71, 0x89d73add, 0x5179dc97, 0xfedbbe7a, + 0x27694eb7, 0x3c7c13c3, 0x78b6e2ee, 0x89ff7615, 0xac1c9af2, 0x1548b137, + 0xd9c0197c, 0xb256f88e, 0xa5f28796, 0x4ce5e274, 0x57ff576e, 0x7ea2e7af, + 0x173cd1cd, 0x11c36fec, 0x1f4ce6ff, 0x21136bfa, 0xaf1e0daf, 0xeac5fe0b, + 0xbce2a98d, 0x7190cfad, 0x9140965c, 0x31f83307, 0xdfc64cbb, 0x80ef79fa, + 0x127bf417, 0xc0b9c813, 0x2df24ed2, 0xb88cdf56, 0x2b5c6c62, 0x72795f1a, + 0x22e23e4b, 0xf4ed49a3, 0xc42f4c5d, 0xd1255c3d, 0xfc6c4ab8, 0x5d5f4863, + 0x19e78964, 0x7e994d70, 0xa9efd74f, 0xd4f743cd, 0xf01979a2, 0xbc541fe7, + 0x79373f88, 0x674eb77c, 0x89cfa9bc, 0x3f348817, 0x62cae7cd, 0x8afbffbc, + 0xbdf80f77, 0x56ec2fde, 0xebc2781d, 0x2151da69, 0xc429b6f4, 0xfac8d470, + 0xdec1e4bd, 0x5f619f9c, 0xeb0b80e1, 0x5c06f26c, 0xa77f2669, 0x98094bb1, + 0xf819fddf, 0x8e3265ed, 0x07d7c758, 0xf5b6efd0, 0x88a5ae79, 0x83dbb25b, + 0x746b6ef7, 0x71fa3139, 0x625ef13b, 0x0cbd3e7e, 0x7de7eab9, 0xbe616ec1, + 0x4bf8d312, 0x7e69be31, 0xb5fc2f6e, 0x62496595, 0xef2f06bc, 0x2bd00f3b, + 0x1074c9d6, 0xcedfea74, 0x3cc4f9e3, 0xe18dee82, 0x7ac55390, 0xf1834ef0, + 0x1390dec5, 0xe8dd2cf3, 0x6d7ef117, 0xdb479c9b, 0x862aea92, 0xbaf0e73f, + 0x1e7ecc72, 0xb2e41dcb, 0xd1fa970e, 0x0fc2bd62, 0xa53a626e, 0x634cffc1, + 0x3173d7bf, 0xf5f41abd, 0x5aa57537, 0x07aec6fd, 0xad4fe09d, 0xf2c4ae7e, + 0x8e5d31e1, 0xcabc6e97, 0x08efe845, 0x533ef0b8, 0x6ffde9d3, 0x22b7e36b, + 0xfddb523f, 0xf18f3388, 0x4fd265ed, 0x46740c7d, 0x3c3f383c, 0xfa53ef01, + 0xf78bc6d7, 0x2edeb5b6, 0x7a21dfb1, 0x81f4c43f, 0x11ade25f, 0x093966f4, + 0x535afde2, 0xd1bf95b7, 0x718924f5, 0x841bba9b, 0x68732dfe, 0x1d79af2e, + 0xa0985e3b, 0x596a5d30, 0x3f9c15ef, 0xf2172d5e, 0x5ba1e673, 0x793ec573, + 0x9273a09d, 0xd8879bea, 0x908dcb04, 0xea7e436b, 0x1b3ea54b, 0x932c1df3, + 0x65839cf1, 0xbfe9c7c3, 0xb69b4f4d, 0x71005035, 0x15524cbc, 0xd4f5dbe5, + 0x5f434fd0, 0x6538f56b, 0xa405b6e3, 0x9f0dec99, 0x0dcf6ddf, 0xdd019f43, + 0xf9d62c9e, 0x917cf4c9, 0xf7baf14c, 0xe5d67e74, 0xe31ef55b, 0x7557dc61, + 0x139bafbd, 0x28b6b09e, 0xb798deda, 0x83f64d2e, 0x5ece43fc, 0xf682e9d5, + 0xdd7b44eb, 0xa376e99e, 0xec6ec871, 0xbb0e94db, 0x79115fb1, 0xa5db75ab, + 0x99eeb75f, 0xfadf1124, 0xdf8775f7, 0x9ddb85b8, 0x3d77787b, 0xabac6bf6, + 0x44ed2c29, 0xb053fb33, 0x73f4cb1b, 0x7b58b3bf, 0xc7a4cca7, 0xccf77f4d, + 0xe2c5e844, 0xdf99ff1e, 0x1877d892, 0x67bde6f6, 0x0cf6f17e, 0x357cf45f, + 0xcb74b1f6, 0x3c1b38bf, 0x7dc9ba66, 0x2a5c2d6e, 0x5f8139de, 0x6e357fb8, + 0x81de4454, 0xffc25dda, 0x2b1df834, 0xbfac0d07, 0x1ca89e8d, 0xc91ffc18, + 0xe50d726f, 0x0dff24e7, 0x60721b7e, 0x13e0dbf0, 0xf9359ce1, 0xffbac6fd, + 0xb17bafa0, 0xeb5fbf2e, 0x4578b77a, 0xd0996b9e, 0x23573cf7, 0xafaf5ee4, + 0x0f96b26d, 0x643bc9f1, 0x2f4337df, 0x9f247a06, 0x6539b606, 0x45df721c, + 0xb9c5ca7c, 0xb963ac6f, 0xd66c6f1e, 0x74cb86e3, 0x94f9983f, 0x6a665e54, + 0x53e484f7, 0xffafb3e3, 0x627dcfeb, 0x6d8ed27f, 0xe2fe138f, 0x82fd9ed2, + 0x1e5bb55f, 0xbb71e674, 0x7719729c, 0x6df3b21c, 0xe7e22f7e, 0x76ecb78b, + 0xca73ff42, 0xe562dd25, 0x077f4ebd, 0xe715d06b, 0xf73a628f, 0x7bb0f68c, + 0xf59e79fb, 0xf193e36b, 0x6798c6ae, 0xe394b95e, 0x34d4b6c6, 0xd6d8d7cc, + 0xabdc03f0, 0xab1fbb0c, 0xa5e3a777, 0xf1e52c3e, 0xafa797a0, 0x15d77352, + 0x332f9c5d, 0xc972ace0, 0x79311fb7, 0x3b258ef1, 0xe227e7b1, 0x049ac41d, + 0x82e5f915, 0xf3084882, 0x6eb18e42, 0xbc45db17, 0x89682987, 0x14758a7c, + 0x02ff7c90, 0xf3269498, 0xef8ce91f, 0x305765e1, 0xd84bb7cc, 0x2107d3a8, + 0xe8d3d434, 0x1ff61948, 0xf246b76b, 0x34f90c2b, 0x53b589c6, 0xc96fed23, + 0xe9dfdc77, 0x525e3d3c, 0x79bae6a8, 0x4e1ffade, 0xfa3f1152, 0x12ba7db6, + 0x6869be64, 0x15ac2cbf, 0xb7ecc369, 0x4683de40, 0x55776fde, 0xbdfb30fa, + 0xebac0f28, 0x7bd6f189, 0x25d23f28, 0x15a723f3, 0xdfb8b73e, 0xe2f1b5e9, + 0x2fb199bd, 0x5dff3e23, 0x9477e7df, 0x8b71e9a7, 0xc9fc1248, 0xff5d04ba, + 0xf94712c3, 0x71b95302, 0x46f49fde, 0xf64cd292, 0xfd36c3f9, 0x76c8a43c, + 0x1f6f8311, 0x9c73884f, 0x649d3aec, 0xca7c822b, 0xd6fd19f5, 0xed93d53b, + 0xe29b73b0, 0xf66efbc4, 0x8e23369b, 0x154c1cd4, 0xdadb99f1, 0xe0eccf4b, + 0x98db6e71, 0x5ebf0aad, 0xe997f3f7, 0x7d712ff6, 0x6869e6c3, 0x0bcf23bf, + 0x53d9be3f, 0x2dfc42e3, 0x2b817bb1, 0xf2bdf85f, 0xabe4601e, 0x03542bd6, + 0xfb0e5bfd, 0xbdb2bd08, 0x66f38050, 0xffe90ef9, 0x16d1b7cf, 0x75c73be4, + 0x82cbccd6, 0xa8a9d87d, 0x176927f0, 0x7ee351db, 0x6923b6c6, 0x72cecd4a, + 0x962bebd0, 0x32ff1e3b, 0xec76b19c, 0x7b8027a7, 0x817fb127, 0xa03d60fd, + 0xb4b9564b, 0x4fbb278f, 0xa28af925, 0xbf53fcf4, 0xc2e4317f, 0x23359bc8, + 0xf20a33ee, 0xf90e9751, 0x63f3d268, 0x0ae7bb9b, 0x4df779bc, 0x4e973be2, + 0x647be634, 0x0f5583d3, 0x733e5907, 0xb5347a75, 0x7e01bdce, 0x713d8ad1, + 0xe35ee2a9, 0xfd9ae60c, 0xf7dda6d0, 0xce5eef8b, 0xdf178eee, 0x177a54bd, + 0x3ef2a654, 0xf54aed97, 0xc2e74ddb, 0xddfeba2b, 0xf2d73ad1, 0x8f334afd, + 0x7ff1e5e9, 0xde2893df, 0xa5df192f, 0x8ed6e55c, 0xfbe34ec1, 0xf93ee994, + 0x68964a5d, 0x3e361bef, 0x1d33c06f, 0xd3073bf2, 0xd4373677, 0xd696ff72, + 0x6718c903, 0x956f43d5, 0xd7108533, 0x1a7c037a, 0x8766cefa, 0xf9a6cefc, + 0x77bfe1a1, 0x3e435c81, 0x4b211c57, 0x50b6f17e, 0xb543f08a, 0xef90b930, + 0xfc24bcd6, 0x6a76b3dc, 0xf86eb9c7, 0x44794625, 0x94d9c3a7, 0x7ff05cae, + 0x7247dee5, 0x9c7c6e71, 0xbdbaf124, 0x7612feb7, 0x4e327b48, 0x120edffa, + 0x50636dfe, 0xf7c6cbfa, 0x1baa4453, 0xe573f0f7, 0x95bc6289, 0xc63877fa, + 0x10bfd8ba, 0xa83b1fe5, 0xf7c0eb1a, 0x77e79035, 0xf066e11d, 0x47f65df3, + 0x4578ef91, 0xbb77bf97, 0x7bc4f3ec, 0xf8045622, 0x1d76ef15, 0xd11e4248, + 0xecaac3f0, 0xf0ec05ef, 0x7e290e97, 0x4589c39c, 0x863dc427, 0x6ac978f4, + 0x75b794af, 0xcbce733f, 0x2afc2d1e, 0x08e2d251, 0xd7e386bb, 0x34dfba1d, + 0x2fdc1f84, 0xfb2d65ee, 0xd2d05fa4, 0x05f84a73, 0x7c619f86, 0xdf6ab747, + 0x1827e129, 0x941f56fd, 0x283d6974, 0x6d0a1bcb, 0xa025bc46, 0xacbee014, + 0xd9727c08, 0x38364bfd, 0x25e6f8cc, 0xbd000a1b, 0x5fa43c7a, 0x0b5be5f8, + 0x33ee257f, 0x71f51bad, 0xe69a7719, 0x4636994b, 0xe5c5c77e, 0xefe83de3, + 0x5adfdcb3, 0x50fbca0f, 0x8b6135b8, 0xdabb1778, 0x6cec00e3, 0x7cf388f5, + 0x10ad9b57, 0x4a03c9ef, 0x8ee7f082, 0xc6b9efea, 0x3c4dfaac, 0xd45904e2, + 0x13cb6bdf, 0xa7f2b8ef, 0x14193cf1, 0x8cbaef14, 0xfc2e67ef, 0x18a547e3, + 0xe45c767f, 0x97802200, 0x096c7b4e, 0x53b325f2, 0xf8a0a522, 0x951f87a5, + 0x00e44678, 0x60de50e2, 0xe9ca92f7, 0x695c467f, 0xaf8962be, 0x6568adbf, + 0xe0eb4120, 0x6b8c9779, 0xfe7c8bf4, 0x8e52698c, 0x7be31cc6, 0x5f51ee24, + 0x303dc478, 0xf89b5463, 0x228a8bae, 0x147768a5, 0x823e587d, 0xf084265f, + 0xc93c8c3e, 0x983ccf32, 0xa8ef121f, 0x30df32dc, 0xf02e9fd0, 0xb431ce30, + 0xda2dd4ff, 0x5dd1cac7, 0xa0fde4d3, 0x63e64e26, 0x399c546f, 0x9b9300ff, + 0xfa0b5da7, 0x8bdbe4d5, 0xdef1e3fd, 0xbf03be4e, 0x0d6de7a0, 0xbe8e797f, + 0x9efd1caf, 0xd324bae7, 0x0253fd03, 0xe5ddf101, 0x1ac7457d, 0xfd03ff31, + 0xd0fe426e, 0xa738c778, 0xabde413f, 0xe716a92e, 0x5073e2ab, 0x563fb71d, + 0x1de30b64, 0x16e403ff, 0xc7726579, 0x78b6d9f8, 0x395b1ef1, 0x3817cafa, + 0x9fedb267, 0xfef0a6f6, 0x5152ffb3, 0x07eb8361, 0x26f63cce, 0x3dc1bac3, + 0x7d8fb1fb, 0xf6235ac9, 0xfaa07271, 0x7e24c694, 0x56e3dbc0, 0xe645f9e5, + 0xfbbd1ff5, 0x5b34e48b, 0xfa175d74, 0x78733ccf, 0xc45ba02a, 0xb51ce7a5, + 0xcc5638cb, 0xfa642e7a, 0x6e70bbc4, 0xc17ee827, 0x5ee10b63, 0xef68e738, + 0x1cdf583b, 0x7dc677bc, 0x6f3cedc1, 0x97c8e73e, 0x1af78a93, 0x64df9d30, + 0x1ac0ed47, 0xef4a3cfd, 0x0579bdf4, 0xed57c9ce, 0x73037884, 0x963ff052, + 0x1fc16f7f, 0x699ce3c1, 0x2a36def2, 0x4d3826bf, 0x072863e8, 0x3ed338fa, + 0xd0b53bfc, 0x638f4534, 0xfc1a7e49, 0xf063f832, 0xdd33a0c3, 0x14a5e270, + 0xf8b7d045, 0x3fae9287, 0xe2fd7410, 0x4b5626f8, 0xd70fe4ba, 0x7ffefa0a, + 0xfbc8eba3, 0x0d85df93, 0xde1eefed, 0x7f659e5f, 0xda5ffd3f, 0xeff7d09f, + 0xd613bfbc, 0x8677a5fd, 0x4e4127e3, 0x7f09b21e, 0x28bdf62a, 0x97b09215, + 0x1104f6f5, 0xe412d537, 0x276c06f7, 0x349d825f, 0xeab8e3ec, 0x8afc3148, + 0x638f4493, 0x8f5b115d, 0x5a78ff28, 0xb19390be, 0x7c4b2274, 0x9488e137, + 0x54ed6fc1, 0x76dd3b02, 0x8733c8c0, 0x7a565f61, 0x42edde44, 0xf27416c8, + 0xa1a9ddf8, 0xde78cb9d, 0x448b9bee, 0xd102e51e, 0x1f382394, 0x7f082457, + 0x84953bb4, 0x9daeeadd, 0xe796fc28, 0xc2e7b6bf, 0x4dafed5f, 0x6edbf910, + 0xfc3b647f, 0x3e09eecf, 0x7f4dc835, 0xf844d0a1, 0x6e05c1ab, 0x02f74f31, + 0xb7bb0769, 0x83f7c8e7, 0xf209fa14, 0x48ae8f48, 0xeec17910, 0xc42c81dd, + 0xd24c3ecf, 0x2e1f434e, 0xb873cbb1, 0x19cb8f3b, 0xd4d4ac3e, 0x62bc6336, + 0x6d48eeb9, 0x797bb3c2, 0x3602f894, 0xb27e5c99, 0x6be4493d, 0xe2317d0d, + 0xa782e3d5, 0xc64e8276, 0xebefb677, 0x5dd065f2, 0x0eefc809, 0x721bfa0d, + 0xbba75a36, 0xb794af72, 0xabc7f7a1, 0x1e3fbc49, 0x77c04bcb, 0xaa71f56a, + 0x32be740f, 0xeb12fb45, 0x7ccb5cee, 0x92fd63b1, 0x1df127fe, 0x95fe30e1, + 0xd38f42b3, 0xd45fdfe8, 0xf523b493, 0xed16f7c6, 0x282defd6, 0x79153632, + 0xdc47213b, 0x9abef7ff, 0x8dd80ab8, 0xc125df82, 0x4fff1c6e, 0x80efb0fb, + 0xbcf215bc, 0x296bc4f0, 0xfdfebda2, 0x1f5fe189, 0x83947ff7, 0xdde4e273, + 0xfc058caf, 0xad26a92a, 0x70f5d782, 0x70f3e7ed, 0x159fbd74, 0xbccddf11, + 0x8e65fb5f, 0xfbdfb788, 0xeff7908a, 0x02ffceba, 0xb38b7a5f, 0x000040d0 +}; + +static const u32 tsem_int_table_data_e1h[] = { + 0x00088b1f, 0x00000000, 0x51fbff00, 0x03f0c0cf, 0x33b3af8a, 0x21716830, + 0x9f0143f8, 0x38606664, 0x8167c40d, 0x81859798, 0x818997c1, 0x78898fc1, + 0x10c533fd, 0x0611416c, 0x5e203b06, 0xf0c0c42e, 0xce21044e, 0x10c0ce28, + 0x20c0ca2d, 0xafe10a2b, 0x6266d204, 0x40ff71d4, 0x4c194663, 0x089207b1, + 0x79161336, 0x268ccc64, 0xca8520ef, 0x7fa02167, 0x2517f1a0, 0x22acbe54, + 0x8a846e84, 0x9793457f, 0x432bca83, 0x094df5fd, 0x502ab9bb, 0x1aa00079, + 0x03605f82, 0x00000360 +}; + +static const u32 tsem_pram_data_e1h[] = { + 0x00088b1f, 0x00000000, 0x7dedff00, 0xd554780d, 0x733ee8b5, 0x49999cce, + 0x21264cce, 0x61021309, 0x40a02092, 0x200c7e18, 0xf7f09d78, 0x803aa568, + 0x07515a56, 0x43f21081, 0xbd1f5202, 0x24266bed, 0x1bd568c1, 0xab45a8fa, + 0x68a90076, 0x62348ed1, 0xa80740a8, 0x0db6a85c, 0xc7f42ad6, 0xc405ad1b, + 0x96aa4490, 0x6bb94abe, 0xe64fbdad, 0x4019939c, 0x6f5fb7bd, 0x6fd697bf, + 0x67d9cfb3, 0xdfd7b5ef, 0xb5ed6b5e, 0x897628f7, 0xec650ee5, 0xc75dfe02, + 0x319902d8, 0xf4a27576, 0x0d0ebbc1, 0x07f8adfe, 0xccdd2832, 0x2862b12f, + 0x2f6e2cfd, 0xfc707281, 0xd65e9618, 0xf37e18c9, 0x959905f1, 0x3271e632, + 0xb09417f1, 0xdaf2f5ee, 0x6d87b2b7, 0xd5b28428, 0x6cc653f7, 0x67aaed8c, + 0x44f66181, 0xff57873b, 0x91c17e2e, 0xfa4870cb, 0x877560cb, 0xbb87c187, + 0xb6e2e7a4, 0x8ef58c89, 0x7e2d8161, 0x5dde0718, 0xcffd059b, 0x316dec61, + 0x704605e6, 0x8a50b85c, 0x4b8231df, 0xe73af8fb, 0x0ee76842, 0x00c55fad, + 0x7334cf5e, 0xb9a26d7b, 0xf50d18ee, 0xa5fa8991, 0x6ca603da, 0x881de00c, + 0xed5c03f0, 0xd79a4ef5, 0x81bdeb8f, 0xb6305761, 0xf547dea7, 0x2a7ef57d, + 0xe923f5e3, 0x00fa81f9, 0xb05873d5, 0xeac7f090, 0x66ca2c36, 0x8536f1ac, + 0x7412c7dd, 0x8c3d66f9, 0xfea24577, 0x222cd1a7, 0xa4fee4c3, 0x00423bb0, + 0x132bc36b, 0xbca13a32, 0x7f41db1f, 0x28018d0f, 0x3fda26c6, 0xdce5f6bc, + 0xcb181399, 0xdc91eafb, 0xbde00399, 0x46c616c4, 0xd2ad78e3, 0x9df031bc, + 0xdbd1fbca, 0xeb6325eb, 0xed9a0f88, 0x65afdfc9, 0xf2cf0212, 0x7e60ac0e, + 0x0f6bf437, 0x07013be7, 0x04c644b7, 0xb8c3065b, 0x186bec48, 0x111b32fb, + 0x370e0089, 0x8c799761, 0xf342d0ed, 0x5f1cbbf0, 0x91230a48, 0x299c40c3, + 0x2cab658c, 0x470a4b1c, 0x2b71c103, 0x4b0733fe, 0x0f4bd53f, 0x7ef571f2, + 0xe711b2f4, 0xcee4e507, 0xde2c5b30, 0x77fbe197, 0xe862d242, 0xe7c5d9bf, + 0x736302f3, 0x1249bc70, 0x12b9610b, 0x2dfa1299, 0x312732c7, 0xe5c60aee, + 0x6173bae1, 0x547e8416, 0xc785985f, 0xfc837ef0, 0x6c8ca6fb, 0x1b7f9b9a, + 0xda9443f1, 0x474ddb1b, 0x88b6fcb8, 0xedc7033d, 0x23ed883d, 0xf6c3163e, + 0x39b6682f, 0x3b44b45b, 0x6e499e1d, 0x968b685b, 0x16c82fe8, 0xe5d3fa9b, + 0xbe72764d, 0x81def9d3, 0xda9c809f, 0xc228fbe1, 0x3705983b, 0xbdebc127, + 0x07a5be62, 0x3c06415d, 0xa3542ead, 0xafa9242e, 0x39eb0cb5, 0x0640594b, + 0xe5eb4e1a, 0x0703b8f3, 0x3bcc49c9, 0x37c003e7, 0xfec01d94, 0x08e3e60c, + 0xda03a8b0, 0x826b79ab, 0x1f4f5065, 0x1b02d5cc, 0x3672631c, 0xcdc473c9, + 0x97a1c3fa, 0xfc13c7da, 0x00df1748, 0x0604ef5d, 0x41dba832, 0x78020ca1, + 0xa83b8f1a, 0xe5dc8fff, 0xfd33b143, 0xf1f553bb, 0x3e414b71, 0xa61fd74e, + 0x83beabb2, 0x63faeeca, 0x0f1aa654, 0x26c6d124, 0x60df8c03, 0x5dca2741, + 0x075d12a1, 0xffee37fd, 0x218ff32a, 0x878823f8, 0x2d16cd74, 0x4e665e42, + 0xf815cd59, 0xe12b7c45, 0x8e6ef9bc, 0xbdb3c45f, 0x866d0950, 0x2ad9cf32, + 0x786d1aad, 0xfc40740e, 0xb87c1e97, 0x2ea4f101, 0x855ce365, 0x4f9c2f28, + 0x97c89f11, 0x5f381abb, 0x284efd62, 0x029539af, 0xef1c5def, 0x53a9dada, + 0xc06099df, 0x5c82c29f, 0x28bf39ae, 0x78c77ff0, 0x7b343a80, 0xbde82645, + 0xbc077fbc, 0x9e7d268e, 0x906b95c1, 0x9e2adea1, 0x30ddebac, 0xabd27e23, + 0x5079edc0, 0x97cfac1f, 0xf8897ff9, 0xfa04dcd8, 0xd57eeb09, 0x21fbc2af, + 0x70e0f5a2, 0xca545cc5, 0x1ee7cb5b, 0x62bc6092, 0xa8fde3f9, 0x29d487de, + 0xf41a776f, 0x6042c165, 0x86c622bc, 0x2f3f35ae, 0x30eb988c, 0xf3042d80, + 0x3f316e2f, 0xd9dcce3f, 0x2e19d227, 0x80906e48, 0xbd5af37e, 0x849a45ec, + 0xf58dde95, 0x0dd9ae2c, 0xf427a175, 0xdc99e4ba, 0xadf98119, 0x900592be, + 0x449269c6, 0xefc56c78, 0x141e8f80, 0x7e96fde5, 0xac9952f4, 0x02ef50d9, + 0xf4c983de, 0xd654be58, 0x56bc748b, 0xfd8bde9a, 0xe6312ba6, 0x54bf90d5, + 0xfb6b13e2, 0xf1a14934, 0xa08e94d3, 0x14deeb8c, 0xb6adeebe, 0x9e51c6f7, + 0x03f99756, 0x028f5c11, 0x4cdf9251, 0x5e50b358, 0x363c013f, 0x9363c389, + 0xf5189c68, 0xdb2beb03, 0xbc38e122, 0xfa57d5df, 0x0d4a4459, 0x2d191fe7, + 0x1698ec62, 0x3cfec4ce, 0x709ca492, 0x58d3e826, 0xb36ff451, 0xc372eaa1, + 0x7513abfb, 0x7c739ddf, 0x4379c7c8, 0x772bf4cd, 0x7f2015d6, 0xb3628654, + 0x7a4e7f91, 0x0edeba7e, 0xf602def3, 0x9ff80282, 0x61e50ce4, 0xea8b353f, + 0xf30aa386, 0xe303a2e3, 0x1eb7b26e, 0x39824b07, 0x5ff48859, 0x0175cccb, + 0x67dbde05, 0xf03b712a, 0x01f27da5, 0xac5c57b2, 0xc9c7eb8e, 0x07b43291, + 0xef83239c, 0x455ef0ca, 0xdee78079, 0x75c32b60, 0xbccc39c4, 0x9b3c83ce, + 0xb9b64aea, 0x5ccf4a9e, 0xf8ca5caa, 0x84069efa, 0xb267fc22, 0x995fe228, + 0xf841281c, 0xf3e6bc1e, 0xaa67847e, 0x84a5d7c4, 0xde72e2fe, 0xbfb5ef47, + 0x00361dc8, 0xf972b79f, 0xee4afb5f, 0x8f8809b0, 0x73979a56, 0x0b926ac6, + 0x7323f115, 0x13b90ff9, 0xf878ebdf, 0x961bcf7b, 0xf4979a05, 0x5027f393, + 0x6f3e363f, 0x9f9ea3f7, 0x7e3dbcf1, 0x366bd41d, 0x6df7a44b, 0x9f845cfb, + 0x3d7947ee, 0xd88356ee, 0x5013ccfe, 0x3ad57c07, 0x8a9c1e3a, 0x665e7bf8, + 0x0b3d085b, 0x4ecfa86d, 0x3b68f6e8, 0x78bb97af, 0xfef366b5, 0x8afbf1db, + 0x7d430776, 0xf97bb35c, 0xbea1530d, 0x619db0fc, 0x0d6d9a93, 0xafa820ea, + 0xac314a88, 0xf4e74cf7, 0xa392ec89, 0x8f7da0db, 0x66f723a7, 0x271dd70d, + 0xb8008ff3, 0x37b91ddd, 0x46571f01, 0xdf8d9b9f, 0x0290ee55, 0xc7983140, + 0xf07943b6, 0x5253cd5d, 0x5c7c01c0, 0xf99d3db5, 0x89e5f60d, 0x1d7e3936, + 0x93cc19ca, 0x59cbbf41, 0x4fa46ceb, 0xaa0db6cd, 0xd39f40df, 0xdf9923f5, + 0x3cd7a891, 0x77c0e305, 0x02959f2b, 0x3695c538, 0xef753f6e, 0xaadc2d76, + 0xd41afce1, 0xd79c6ee1, 0x5bb62a3d, 0xcbbc5d1e, 0x36f847e5, 0x7de1b3ab, + 0xd59ba3e5, 0xa85e8372, 0x640a3eda, 0xa6d700c9, 0x24e181e2, 0x0f01237a, + 0x8953c133, 0xedd6867a, 0xa5768aa8, 0x2daa7cfe, 0x6ab1f893, 0x5fea6cbb, + 0xd7e47ba7, 0xc887ec8c, 0x55e1375e, 0x2f6adba7, 0xa08eebe3, 0xa0af59db, + 0x6a5bd2a3, 0x1f2f5fec, 0x50383a44, 0xfca97b5f, 0xca8fbd56, 0xa27ef58d, + 0xbf8843cf, 0xc64edc11, 0x97d760e7, 0x827b2f21, 0xc3ec0bcc, 0xcb06e6b2, + 0x0acf50ec, 0xa2ee7af1, 0xc8bfe4b0, 0xec12f5fc, 0x04e0c5de, 0x7afdfac1, + 0xf63b0150, 0x8abc3521, 0xa6fc6005, 0x04ce08ff, 0x528ff77b, 0x4afa8638, + 0xb82b85b6, 0x287cc5dc, 0xfac5eb77, 0x13f25db3, 0xa9e7d61e, 0xba1f6fa4, + 0x2cab74ad, 0x6366b989, 0xf7fbfcbd, 0xbb3f5215, 0xfa151fa9, 0x3f74be29, + 0x364fb7b9, 0x7b7b93f5, 0x01cfde85, 0xf2ed27ea, 0xf6e879fa, 0xdcf0cc6b, + 0xf3f7a95e, 0xb9e3f532, 0xdee579bc, 0xcf0ccd31, 0xcfd4d51d, 0xd20145c0, + 0x3fceb2b7, 0xb43bd60c, 0x8e647717, 0x5341fa37, 0xc0dfd36d, 0x520dc5f5, + 0x8ca3e465, 0x792669c9, 0x99660cca, 0x0ce603ea, 0x09cfb532, 0x0fde9915, + 0x8595785c, 0x89ef352f, 0x408ea251, 0xf68b43a1, 0xf49520f1, 0x2720d94e, + 0x20f77fc1, 0xddcef48d, 0xe04784d7, 0xa2b08e3a, 0x1ab7737f, 0xea4deb1e, + 0xcc4874c7, 0x86dfa587, 0x3dfdf5a5, 0x9e9c1ec2, 0xb7f0f1ff, 0x5b5afbe0, + 0xa84cf0ef, 0xfb2b6bbf, 0xbcf9e233, 0x3269ffd0, 0x6976c3ab, 0xeffa460e, + 0xadd2c29e, 0x5b5e0311, 0x48bf0086, 0xec5b7e89, 0xa3f21f61, 0x901a9364, + 0x510fd73f, 0xfa041b19, 0x1fdb1d74, 0x9ee73581, 0xc43ee521, 0x2ffd03bf, + 0x8c2af8e3, 0x77c69a3f, 0xb77c60d8, 0x8ef8f92d, 0xf1a6c9a2, 0xa615059d, + 0x8c2a9df1, 0x6991f20f, 0x9df18973, 0xad6617e4, 0x8ef8d273, 0xff1a0a82, + 0x9855951e, 0x1beb4fc6, 0xc60da07f, 0xfee3621d, 0x17f9bf4a, 0x7f9e635d, + 0xfe79a541, 0xa17f9f2a, 0x9f8c532d, 0x5a2ff346, 0x2ff3e5e7, 0x77f3e4a8, + 0xc6fb7ef0, 0x7fe1f4f7, 0x263f8e04, 0xe28ef8c5, 0x0ff9e669, 0xdfcf36ad, + 0x671fc7c1, 0x6be313cb, 0x75f8fe34, 0xa1ff3e3e, 0xeabe34d5, 0x8f900708, + 0xbab4fcd4, 0x8343da28, 0x240dfb41, 0x72a4181d, 0xbb93f724, 0xe38222a4, + 0x77ce34ee, 0xbf01a51f, 0xca7d0969, 0x9e29eba2, 0x74f052b2, 0x35328ed5, + 0x07bc5a3c, 0x00997f7b, 0x4cbb6975, 0x3a36cd7c, 0xbc0057a2, 0xf932eddd, + 0x5e374b3b, 0x3d69951b, 0x1808fee5, 0xfe7c7190, 0xd98f6fc7, 0xb5979c62, + 0x3f6ad65c, 0xab9069d1, 0x9d3efd3e, 0xf803ac8d, 0x535e4836, 0x69e804fd, + 0x06dea674, 0x49e58c7d, 0xf3c0338c, 0xb38f4077, 0x7ffdfd11, 0xd1b5eee8, + 0x0a2faf30, 0x1c284ff8, 0x48d627df, 0x47ffc451, 0xa8a9561b, 0xa6b596cf, + 0x07d3d1a3, 0x53a0ad47, 0xd9076eef, 0x3f4f8055, 0x1216e7e2, 0xbf7ec645, + 0x24870bef, 0x6f967bb0, 0x6efa601a, 0xfb368b11, 0xfb92fda0, 0xc2f10f17, + 0xe85d6ffc, 0x1f932f18, 0x91b7cc18, 0x1b7cb31c, 0xdb0b4ef8, 0xa1f3d836, + 0xbb42cb72, 0x52f94fc9, 0xb5bf5cd8, 0xb6ef5cc2, 0xcf18ed47, 0xb1215eea, + 0x6defd0cd, 0xff8b7675, 0x6159c7c3, 0x08f112cb, 0x8117de3e, 0xe8f07986, + 0xe3c72c36, 0xf5d12f63, 0x56ff2f76, 0x6bf6a787, 0x90547076, 0xe8399d7e, + 0x0e48b347, 0x2f6177f9, 0xde15b79f, 0x60ceeddb, 0xfdb9e008, 0xd3e132ab, + 0xbee77f0a, 0xec0da0f4, 0x7f4dced1, 0x6e7da3b2, 0xfe158f9d, 0xe75ad63b, + 0x7d7155e3, 0x3eb11c58, 0x5aec988f, 0x2f6dacbd, 0x818efadb, 0x9f626a9f, + 0xe18efadb, 0xf3edaabb, 0xd115f54c, 0x2fda992f, 0xf4d8b4df, 0x0aeb597e, + 0x2d25fbd3, 0xc5f54cab, 0xda9aaf91, 0xc1b6b1df, 0xbab6fef4, 0x6fef4d7b, + 0xaa60d8ad, 0xb0fc297f, 0x0b2dfda9, 0x4bde9b37, 0xed0c56fb, 0x1e1abd24, + 0xeb76879a, 0x59f90771, 0xf2ebbf3a, 0x16ec0a70, 0xdd834f2c, 0xca036582, + 0x6dbfc829, 0xb76b2f37, 0x35ea1e2c, 0xed2761f8, 0x4f280575, 0xe2b7be56, + 0xf0dfcad3, 0x1d6c9f97, 0x8c6acbd2, 0x3dbf4143, 0x24393f16, 0x1f1ea0f4, + 0xdcb956ac, 0x9bccef56, 0xb57ffe8e, 0x975e1f1a, 0x93ec4fc4, 0xf34498e7, + 0xe7a56860, 0x5b80dd20, 0xdaab780d, 0xb3826c5e, 0xe34cbf6b, 0x05d944af, + 0x0a5f37fd, 0x88f5c71d, 0x2c160fc5, 0x04f08318, 0xf6f5437f, 0xbb7f5a1c, + 0x7d6ce7ea, 0x0bf88ec7, 0x7eaa7951, 0xea279521, 0x53be54c3, 0xdbe5415f, + 0x765475f5, 0xf2a5afd6, 0x9508facd, 0xa16fabbf, 0xadf537f2, 0xdfab1e54, + 0xf5ebe544, 0xebbb2a51, 0x7cea5483, 0x4327a7db, 0xfe156ec2, 0xb7224805, + 0xe45cc55b, 0x96b8bedc, 0xacf1e50f, 0xb470d1f6, 0x031ecfcb, 0xc6a61722, + 0x521f9597, 0xc90595e2, 0x028f28ae, 0x7ff4079d, 0x74e34aef, 0x1cd8d972, + 0xdee37a06, 0xc01fbe2b, 0x15d41338, 0x47df8596, 0x49dcf303, 0x107f05fa, + 0x3a2975e9, 0xc96f60b1, 0x89c7a07c, 0x8a5afe47, 0x456c86fd, 0x28385edc, + 0xe2c97ad3, 0xaf48035b, 0xe9378a4f, 0x402fbf27, 0xa39339b9, 0x00a3afe3, + 0xb2df04e3, 0xb39fa979, 0x20a60e6d, 0x47a4f71e, 0xf67d2431, 0xae0f56f0, + 0x727dab77, 0xb31f18d4, 0xc2b13596, 0x4f9866a8, 0x7eb9bb6d, 0xc39a55b6, + 0x8cfe69e3, 0x5f20c69b, 0x50efa379, 0xa547d15c, 0x9f6acfde, 0xfee8e34a, + 0x4991db38, 0x217e0a7c, 0x86affbb5, 0x093f5523, 0x1fd8da38, 0x2e287700, + 0xb93f8a17, 0x0f94ce5f, 0xb1bb8c54, 0x708ff63d, 0x7fc0773d, 0x6591d017, + 0x7ef5d50a, 0xc472636b, 0xef9f1631, 0xdf078d30, 0xfb9f75f9, 0xf8c5d142, + 0xf4276155, 0x9b6a8279, 0x0e443e8f, 0x6a2b95f2, 0xa699fbd6, 0x5e7b6d7a, + 0xe00eb4d4, 0x59ee403f, 0x3ae0a485, 0xa8b82d58, 0x245ad147, 0xec8c6f80, + 0xf126fce7, 0x4ece3576, 0xbe47ec35, 0x54e2fc69, 0xa56cb63f, 0x3be15af9, + 0xabd87f5d, 0x5c7e245c, 0x3bbd9f25, 0xffc8bed9, 0x48bef996, 0xd3db8db5, + 0xa0f119cc, 0x117ccabf, 0xe18bc60f, 0x0fc3eb4f, 0x8e304df9, 0xb3f7aea1, + 0x4def6a22, 0xd9764eb6, 0x1d6c9db8, 0x7b8c45b7, 0xdcadfc29, 0xce367471, + 0x95c78adb, 0xb4abefed, 0xffc0a31f, 0xd478134a, 0x0e463bf1, 0xdfc0c8b5, + 0x22dfdb95, 0x3d94f27b, 0x176bfc32, 0xe1fd5bd1, 0xb7147cd7, 0x611de7d5, + 0x9dce381d, 0xff67f17d, 0x7585bf2d, 0xed97ddf1, 0xf62cbe3c, 0x70387437, + 0xf506d0d3, 0x6776a225, 0x9bc5155b, 0x3d75dddf, 0x594b6fd9, 0x644e83c8, + 0x452d6b05, 0xb30cf03b, 0x9d3c41cd, 0x267aaf61, 0x43b4e818, 0x974e4956, + 0x10ed98b4, 0xf54d5fb0, 0xf5cc9be5, 0x173f3672, 0x46f94cf5, 0x344a8b3b, + 0x47fbd33f, 0x7fe12f65, 0x8f5bab39, 0x9da373eb, 0xe9ddb3ef, 0xe83e4a65, + 0x1e179adb, 0xff38c52b, 0x7ebe648f, 0x1593f1ea, 0xab8edc59, 0x31566d8c, + 0xb687ffbe, 0xca9c5f09, 0x7ae8fbf0, 0xcf221f5c, 0xfe6d814b, 0xa4fdf8fe, + 0xd5e15bf0, 0x717eefd7, 0xcd47011c, 0xbc692976, 0x892cbf77, 0x63f39ff5, + 0xbaa5e286, 0x5be7d76e, 0x22c9afea, 0x19332c1e, 0xebc67ee9, 0xe832d88c, + 0xf38e207d, 0x3408e9db, 0x72c2fcc2, 0xf64c98e8, 0x1984bc44, 0x30e585da, + 0x5e92ef3d, 0x93bb4729, 0xb412f129, 0x21ed6123, 0x3f05553e, 0x129e69c8, + 0x31bb778c, 0x67718bbe, 0xd60b6797, 0xe62bbbd7, 0x16b51c62, 0xf7f401f5, + 0x61f66780, 0xb2709fdc, 0xf81078d6, 0xef33e1d7, 0xe6fcb82f, 0x75ea3a7a, + 0x00f877d4, 0x8c02f9f7, 0x23e954e2, 0x01dcedcd, 0x1f6cfd73, 0x5f7ce29e, + 0xf71c589c, 0x0cb8b5c7, 0x4ac9b3e3, 0x54bf9f57, 0x871afe84, 0x5a64ec1f, + 0x7978d6ff, 0x7e2295fb, 0xf4f8e6bf, 0x89175981, 0x939ed547, 0xceb0d458, + 0x2abd2ad4, 0x39ed61f2, 0x6a7f9e85, 0xd587eabd, 0xf357a0d6, 0x929a70e5, + 0xc228f5c3, 0x6138c127, 0xe3809f03, 0xf9ca35ea, 0x7c3f0b08, 0x99b2386a, + 0x918fbf49, 0xe0c9f9c3, 0xfbfdd4f8, 0xe23ff5fa, 0x61ffb4bf, 0x909ffafd, + 0x179affac, 0x8115d99e, 0x87f2a2f5, 0x3300f6df, 0xd69577b3, 0xbdd000dc, + 0x07b35b7a, 0x1294f2e5, 0xdf5d20f1, 0xa273ca8d, 0x52a1f849, 0xa82ef9d1, + 0x3fc4a549, 0x9fa747c4, 0xe80de6fe, 0xcdb47fc7, 0x7eff25ee, 0x00ee23bb, + 0xb6d95ca6, 0x76c7cb82, 0x7ebc5bc7, 0x9fc8fbcf, 0x7d66edb5, 0xb7e4f951, + 0x7eb4fd73, 0x1bff8445, 0xe561ff27, 0x8d9c7f13, 0xeb2d58f6, 0xfd67bd25, + 0x973fc70e, 0x62c2f645, 0x7bffa335, 0x56b21f7d, 0xedb6a5e0, 0x3ee3ef9b, + 0xe7db6d44, 0xe9a1724e, 0xfad1bf24, 0x07f0855d, 0xd9dc556e, 0xc49baf14, + 0xe9bf2126, 0xee516178, 0x3c2fc80f, 0x9cf18256, 0xf65e27ae, 0x7c8da348, + 0xd9dff5ca, 0xfdef92d8, 0xae5a9fd8, 0x1a3f41ba, 0xcedd6eed, 0x3f0bb7f3, + 0xab2f0f66, 0xee0f71ed, 0xb66f541f, 0xf55cbed3, 0xffbf5b33, 0x8e57c608, + 0x4057023b, 0xbccf55ff, 0x5035faf4, 0x9ece7aaf, 0x434f973d, 0xf4137293, + 0xd6ff85a9, 0xa3d04f8e, 0xa92f47f2, 0xcf8d0fb8, 0xa0959ebf, 0xfb73d54b, + 0x3fa63655, 0xf6c4663e, 0x125a9dab, 0x9adec4fa, 0xfc86fe8d, 0xe91579c2, + 0x893eeeff, 0x824c2c0d, 0x912fcdcf, 0x22788cdd, 0xf57a0a7a, 0xbed2cfd1, + 0x7a42e816, 0x6b2f42d1, 0xfe4269bb, 0xa78c5fb1, 0xfb3f7f03, 0xf977dc63, + 0x7880238d, 0x2ef678a8, 0xa4e7ce0f, 0xfcf9c752, 0xcc5ce6b1, 0x47b0a8b3, + 0xf254bd72, 0x7f8f15e7, 0xf96ff885, 0x52e4afd1, 0xf305833c, 0x443b646c, + 0xcb9e70f2, 0xe699bd1e, 0xc4c2ce59, 0xc98f1587, 0xa1f0ff94, 0x973ce6c2, + 0x16de4e44, 0x8b727272, 0x4e859283, 0xfb8242e2, 0xd1caaf10, 0x5bcf146d, + 0xaf92f145, 0x6c47fbe8, 0x743fd535, 0x2bb57a72, 0x4b0c1fba, 0x9f7f9189, + 0xe903a7b8, 0x70487a74, 0x6b81c620, 0xf8111299, 0xbf402e90, 0x0359d1f2, + 0x5f989d39, 0x81df1529, 0xcf819ffe, 0x3d877db1, 0x7d312ae8, 0x26142ec7, + 0xc6235fc6, 0xd0d3b807, 0x0b993dbe, 0xf99260f6, 0x3d25d865, 0x0cc1d46e, + 0x7790667c, 0xdc4fff2e, 0x975de5cb, 0x39bce8ff, 0xd783fef8, 0x77e11cb8, + 0x5c00bf68, 0x7ef481f1, 0xe9124dff, 0x278b0707, 0xec27f393, 0xefcdce42, + 0xf002fcad, 0xf71eb82b, 0x938e0df1, 0xfb207445, 0x7c237cb6, 0x38abd46f, + 0xbf7fa7ae, 0x172f1cba, 0x8af7e0fa, 0xfa100fc8, 0xf5ca3d80, 0x243f6a40, + 0x7b75edc2, 0xa08ffbf4, 0x46bc82fc, 0xf6bf28fc, 0xbdffce10, 0xff5f071d, + 0x7bcdc832, 0xcd6e5d31, 0xb72ad57a, 0x66af3b15, 0x3df6e4c9, 0xca92c02d, + 0x2a4f3c2d, 0xf1275ab7, 0xaf5bdff3, 0xed5478ea, 0xebaabd66, 0xb4f854c9, + 0x8acdc9ea, 0xd56af09f, 0x1af7f093, 0x8fcfed2b, 0xfcea1f3a, 0x9a83f957, + 0xfa8fa8a1, 0xc3e754f8, 0xf9d53e3e, 0xd13c5fb0, 0xfbeb4784, 0x18dc605f, + 0xfbb425f8, 0x81f3b3d7, 0xf87bd5ae, 0x777c2cbe, 0xaf80eb08, 0x5ad37720, + 0x1b67e50f, 0x3d4b51eb, 0xb41f6966, 0xf69643d4, 0xcebd4b61, 0xe3ca3ed2, + 0x5507ed69, 0x37139f9e, 0x63afb7b5, 0xb1c63711, 0xc714caf7, 0xd79801ee, + 0x3b3df7c3, 0xc291a30a, 0x6f5b5e44, 0xf51eba8e, 0xd7b78f59, 0xaf62f683, + 0x7aefc78b, 0x4c9ebd42, 0xd6f69d83, 0x71f4991e, 0x49cd9467, 0x05824fe6, + 0x64ebf44d, 0xb8f3dea9, 0xddda0f7c, 0x592cde30, 0x718b582b, 0xf2995698, + 0xdc369667, 0x8cfcc1e2, 0x37c53d9e, 0xcbe7842e, 0x9b7cc88e, 0xf2541230, + 0x29dc7e0c, 0x9a687916, 0xf7c7fb84, 0xec97fd13, 0xd2dd7ee1, 0x73f393fb, + 0x5caef8a5, 0xdea2a35b, 0x6dec7f04, 0xde83bee3, 0x96a3c54f, 0x17ae7be7, + 0xfdfdcf7c, 0xefcc27ca, 0xb03e22c3, 0x71fbe74c, 0xcff71c6c, 0xae77e519, + 0x96777a16, 0x85c6fa3c, 0xc39e8740, 0x39be4332, 0x3a2647bb, 0xf7c1dd9c, + 0x3ece29ef, 0x97b5f905, 0xaf8e9df4, 0x118f942e, 0xd750f5a9, 0xfd2fbff3, + 0xdea9341a, 0xef92dbf5, 0xebb5d942, 0xb117f0f8, 0x051bc2fe, 0xdbfd65bf, + 0xa2e7d8cf, 0x7d9e8d7d, 0xec87da6e, 0x82f3fbd9, 0xb77d61af, 0xf6708023, + 0x0973fbec, 0x3acf51f2, 0xb1ea0547, 0x1fdc219e, 0xe7fbdc6d, 0x3f5a4e92, + 0x937e789b, 0x67c3fb9d, 0x4df5fcf7, 0x984b1b29, 0xfb07da15, 0xa87f69d2, + 0x8a2ec7f6, 0xfdecf5ab, 0xced1a973, 0x59f3acff, 0x7b1bf629, 0x4ee16cdc, + 0xef932f84, 0x38bed4d3, 0xe6036b65, 0x57edb463, 0x19fbc097, 0x825f393f, + 0x2767b1fa, 0xedba7bb7, 0x7ee38f9d, 0x2fed77da, 0xbd03b3ae, 0x063851ba, + 0x3f529a81, 0x92d11e9e, 0xc53ce5e1, 0x1f172f0b, 0xe0c7ff3b, 0xf57da243, + 0xa8ee3dea, 0xff79c253, 0xa2dfcde5, 0x20e7d83e, 0xfbe7d4be, 0xec81ac5e, + 0xfbcd4b91, 0xbcdd3fe8, 0xcce5f8a5, 0x7c1ff7bb, 0xf26377de, 0xe5fdd5db, + 0xef9f3fa0, 0xcfea9bbd, 0xef0403b8, 0x57bbf265, 0xfd1c7955, 0x9ffe741f, + 0x813bee98, 0xcf4b9eee, 0xf83fec7b, 0xfdd353bc, 0xee82edc8, 0xa947cc5e, + 0x8279c9fd, 0xb9ea93ef, 0xce87ff1b, 0xefd7b75f, 0x315a05b3, 0xbd1d3b2f, + 0xe1e73c01, 0xe182df9e, 0xce46fbc1, 0x28dda2f7, 0x2b4bfd8b, 0xfb95117c, + 0xf3c4b27d, 0x1e10d9d6, 0x4fc263cf, 0xd710f342, 0x272b454f, 0xd6d154bb, + 0x94ccdd93, 0xf0104740, 0x7755df72, 0x87d72806, 0xc6163f8d, 0x0169e0fa, + 0xfc5b578a, 0x058926c5, 0x9557b025, 0x187f3eab, 0x48fb16fd, 0x4251dc5b, + 0xde585be5, 0x7690e223, 0x67f26aaf, 0xbae6d1b4, 0x3bae6fcb, 0xc64e7f44, + 0x58fa77e1, 0xf2d1e314, 0x98bc0795, 0x538f26cf, 0xbb2ea618, 0xfd046b58, + 0xfccf8706, 0x73f422fd, 0xb45bf10d, 0xb060e3db, 0xad8efbfd, 0xf3383f14, + 0x60375bf4, 0xca2f55bf, 0xe97809cc, 0x7166e1de, 0xaa251be4, 0xd9523fa2, + 0xbe290726, 0x174bc4a2, 0x750bf618, 0x87eab17b, 0x72ab826e, 0x173a23a7, + 0xf5dcafbe, 0xb75a1287, 0x3d92f5d7, 0x0a5a791b, 0x3be1a36c, 0xb03f704b, + 0xbe7e4952, 0xe79511e4, 0x4eed751b, 0xbc7e885f, 0x6be79db4, 0xb16ec656, + 0x28790c3b, 0xdebb541b, 0xf228f88e, 0x2cf94494, 0x4f319f08, 0xbb57b750, + 0x7c38929e, 0xe628f6ed, 0x7f6e567d, 0x11e31bae, 0x011cc795, 0xb76b1b74, + 0xeff14fbf, 0xc67c3f19, 0x977e49d3, 0xfb43f26c, 0x65db7ff9, 0xb6caeba2, + 0xa15bb21a, 0x195df44e, 0x27d6fe13, 0x7eaa4ff4, 0x1e1777b8, 0xd1faa894, + 0x778c1e93, 0xe6d8ee9c, 0xfb703f21, 0xfd31e3c5, 0xbdd8bdfc, 0xc2fbdfc2, + 0x54e3e449, 0xfc69defe, 0x3f51d807, 0xf37e2d55, 0xc76401f6, 0xc9a59c02, + 0xfe74c7f6, 0xc3e67aa9, 0xd95e31c7, 0xc7bdf3b5, 0xbfeaee11, 0xb471e9fd, + 0x973ed943, 0x6a2df717, 0xc535fe9f, 0xdeeff477, 0xa25c7954, 0x2927a9fb, + 0xfe0dd63e, 0xbdd6f636, 0xfa0164f7, 0xfdcfdd23, 0xe7fd1725, 0xd1677b35, + 0xcf358ff9, 0x92c818cf, 0x225eb1c8, 0x232f46ff, 0xdba5673e, 0x6483b6c1, + 0xba019f2f, 0xe7d2bfa3, 0x786ac7c7, 0xfc2fc47c, 0xe3c91df7, 0xf5fcfda1, + 0x5e3705b6, 0x6db8f98b, 0x83aa00f6, 0xafedfa4b, 0x5ec73d01, 0x88771d06, + 0x0bec4cf8, 0xcfdbf517, 0x5e803fe0, 0xfc742de7, 0xf7d96db0, 0x6d77c11e, + 0xedfa5203, 0x9fc0cbf1, 0xa23d6f1e, 0x940e9d06, 0xa03f9db7, 0x6fd20978, + 0xfbb84c2e, 0x300b0f99, 0xdeca7d5e, 0xb1e53b7b, 0xd17875ef, 0xfbdcad4f, + 0xf753c906, 0x9e2947f3, 0xb3dc44c9, 0xf1fdf59b, 0xa1c894f8, 0xcdc27dab, + 0x07417dfd, 0x3df8078c, 0xfdf85cf4, 0x78f5af9c, 0x4038aa40, 0xe4f3c1d0, + 0xcd7038f4, 0x7e15bf13, 0xd26e8275, 0x5bd7a464, 0xeb5f8d17, 0x1e22f078, + 0x5ce31926, 0x7d2ee3c9, 0xdd0b2e71, 0x5f56f8f4, 0x83ea0b1c, 0x95119e31, + 0x371648de, 0xe3ccdeed, 0x7376dd63, 0x4e824dfe, 0xd535ee3c, 0xe8d38e61, + 0x2f254df3, 0x6a5edcba, 0x4f149f1e, 0xbb08d0a3, 0xbabe3fba, 0xdfae4e3e, + 0xde5c776f, 0xfdca757e, 0x7592a594, 0xc736e53f, 0xbc3f68d5, 0x57ca32a5, + 0x0c79e5e8, 0xc8b9befa, 0x5a7aec17, 0xfac978a6, 0xefd241d8, 0xefa1fd56, + 0xade159b7, 0x6caef013, 0xd747ebe7, 0x8354774e, 0xec0eba7e, 0xb95ebe26, + 0xfd152de3, 0x7fdb43cf, 0x8b3b72a4, 0x1fae11cb, 0xba7cc351, 0xc25fdd9e, + 0xdf3c7ae3, 0x37ce3ad9, 0xa93edc1c, 0x9c7c93dd, 0x9bef1dda, 0xc48aa9c6, + 0x79ff9e54, 0x2b4ef1f1, 0xbfb05bc1, 0x3a761dd3, 0x263a73cf, 0xbfb649cf, + 0x1761d8bb, 0x2f2b41f6, 0xbca51d61, 0xbcfca3ee, 0xd357c4c5, 0xcd7a0f28, + 0xc5bf39d1, 0x406b8c73, 0x6c4ed1ac, 0xda7ce06b, 0xf9827ff6, 0xa3b6ef48, + 0xfd71965f, 0x35f885da, 0xafa58bd8, 0x8370cdd5, 0x5dfd287e, 0xabb22268, + 0x3a4cef55, 0x0fc13366, 0x75c40ce3, 0xc1fa09a1, 0x9fcc7dfc, 0xcf647842, + 0x8f0839ec, 0x5d79b5ec, 0xed52f249, 0xcaf2885a, 0x5eed7ef5, 0xc338de73, + 0x4fd086f3, 0x5e7a95f7, 0xf1032851, 0xcdc761f4, 0x328674bc, 0x775917bc, + 0xd9bd094e, 0xf1601f55, 0x081cfc11, 0x7e456bd6, 0x839ec570, 0x560f51b3, + 0x2fe624c4, 0xada473c4, 0x763f3724, 0xa573f264, 0x515db351, 0xd457e7b9, + 0xb78db2be, 0x6a3162af, 0x8c45e78f, 0x6c4d5bf6, 0xe11ec582, 0xf223ddfc, + 0x95cfaa42, 0xff21b8b2, 0x9f8267eb, 0x26bdeaba, 0xf08d5f3d, 0xd61afb41, + 0xc4d4e341, 0xd1c69806, 0x9b9cd5db, 0x46afea6a, 0xab7e20e9, 0xf42ff739, + 0xeabe4fbc, 0xd487847d, 0xe09be7fd, 0x853ff44e, 0xeb2427c5, 0xb73d1a7f, + 0xe6fa87e6, 0xde6378f3, 0x882cbd02, 0xe88cfea2, 0xd3ca73e7, 0xbf808da2, + 0x3ff85a23, 0xdcf81f50, 0x625f0b1b, 0x326cde78, 0x709f59e5, 0x0f047c88, + 0x047cf0f3, 0x7583622d, 0xcb6d11f8, 0xf28c6986, 0x8c3b4e0d, 0x5e2c06f9, + 0x6f447a82, 0x25bdefd7, 0x7e30611f, 0x1650aa02, 0xde631670, 0x8d07ac3f, + 0xb05b3cf3, 0x9f9ba8fe, 0xbd602c93, 0x60ff31fb, 0x0a03f0ab, 0xdc58ce31, + 0xa7e4bcff, 0x3d99273d, 0xd0d56ca3, 0x9cb36300, 0xa02a6723, 0x296fb32f, + 0x0bdf2e7b, 0x3d9b1966, 0xb3d0f313, 0x971b2c9f, 0x4b58f507, 0xcbff7f27, + 0x500571b2, 0xe2eae63f, 0xca24abef, 0xbe5b57d3, 0x7da2333b, 0x137d3d06, + 0xa4d4a660, 0x409cb3a7, 0xdfa133cf, 0x1f99717d, 0x557a1ef3, 0xc216678e, + 0x73264376, 0x7ed60dfc, 0x75fa1cf7, 0x0d9d6d43, 0xb7be5fa8, 0x7499cff7, + 0x23f30fde, 0x6b1e9cf0, 0xe11d22f2, 0x170be4d1, 0xe6b3afc9, 0x74fce999, + 0xec5c3b95, 0xdf363a04, 0x23ce9239, 0xde31523e, 0x26e37e89, 0x70f3b791, + 0x3f21be5f, 0x93b57897, 0x44f9f7ef, 0x0fd9d75e, 0x2eb2330a, 0x7d6a1fa2, + 0x0628278b, 0x5e947ab8, 0xf9efb7da, 0x31dbadf8, 0x99eb130f, 0xc499d649, + 0x7be94bf7, 0xf3053e6b, 0x2d9f1366, 0x78867c15, 0xfaf21a73, 0x9511cb97, + 0xc55bda07, 0x8bd337fa, 0xd52297f3, 0x9f5185f2, 0xb4c74f1c, 0xd3c45cf0, + 0xcf299ce7, 0x7a45ce75, 0x6675cf5a, 0xe0374339, 0xe7e57977, 0xfaee500a, + 0xad4a69ce, 0xeb3f4879, 0xf4a64fb9, 0x19f992da, 0xcfb9c45b, 0x710f7054, + 0x71c36f85, 0xdfe27e8a, 0x7fe41879, 0x803552ec, 0xd763a4a9, 0xa4280c4e, + 0x45de789f, 0x3c2be0ad, 0x1ee74eae, 0xcfb466ee, 0x8290e3db, 0xdcf7d7e8, + 0x60bb25e5, 0xe4b9d2f0, 0x17a4f75f, 0xa93f30c6, 0xda7e6be7, 0x427b040f, + 0xb21f3942, 0xf2ee2327, 0x647e9c90, 0xcc8fd391, 0xb71e6972, 0xbdbf82e7, + 0x8af3fa93, 0xcfd0c0fe, 0xee9f9c4d, 0xdf7af991, 0x3827ef53, 0x7ec8b086, + 0x772f1fb4, 0x853bafbc, 0x03e8281d, 0x1186fff8, 0x66c740ff, 0x3a43afac, + 0xc74a4c8e, 0xb47464e6, 0xe49dc79e, 0xfd87df0c, 0x443f2c9c, 0xe7ad72e7, + 0xc9129970, 0xe9593c43, 0x3eb4ab5b, 0xb9d25b8c, 0x3b27de7b, 0xd8dfa746, + 0x4e88e3b5, 0x843e7a06, 0xf3dd8c70, 0xd6e10dbe, 0x291df8e9, 0xc14c1db9, + 0x8ffbabc0, 0xd3b0bb97, 0xbed24e16, 0xf5296d64, 0x82d9f807, 0xf3f018e3, + 0x9fbfd614, 0xe14f3f1a, 0x3f032fbc, 0x7e0e5ecf, 0x4aaf3f74, 0xee1571c8, + 0xff9d015b, 0x5b9f9fe8, 0x96cee304, 0x15d3e235, 0xef8a64db, 0x79b9fb42, + 0x5fb909b9, 0x3f6ea531, 0xf15c579e, 0xb4fc4498, 0x7fbf9c54, 0xb7bf9c4f, + 0x2f9603e6, 0xbd9e908c, 0x94605e74, 0x76d546f4, 0x09c3f3f3, 0x3ca02afe, + 0x89ef715f, 0x15805f7e, 0x213567ff, 0x365d4bd7, 0xfd02bde3, 0x66ceb7e4, + 0x9bcf2bca, 0xf90fd7d1, 0xff9b3efd, 0xfdd38a0d, 0x6e30cecc, 0x27b25414, + 0x131f11c6, 0x6fd899a5, 0xbd2f9099, 0xcd6ba1bf, 0xc4615e76, 0xb8b03e7c, + 0xf03e7cc5, 0xf9f3568a, 0xcc9b11c0, 0x8caf03e7, 0x8e07cf9a, 0x54de3eda, + 0xc6bb131f, 0xfb6c7ed4, 0x5c7d5374, 0xf6a6f3fc, 0x37cf0e13, 0xf8eeafd5, + 0xa4fda9b2, 0xde9a7763, 0x34ace94f, 0x6a7a9fbd, 0x6d7ea9b5, 0xda9abfef, + 0xfd7197c7, 0xe47ea075, 0xfa9e6354, 0xcdaa5581, 0x0d57cf8b, 0x8c4b79b7, + 0xfe8373cf, 0x834b2c12, 0xd2a767e8, 0x579c33b3, 0xf7ae354e, 0xd26ecc65, + 0xe69c333f, 0xe225c7ba, 0x2fc00510, 0x2e01fc40, 0xbc815cb3, 0x1e40bae5, + 0xb5a6ebf2, 0x83c7870c, 0x40cb0c56, 0xcb390279, 0x9c9e5d75, 0x93bb63e5, + 0xb1ebe32b, 0x003eec9e, 0x2ef910b5, 0xb29bf942, 0xe32ff738, 0xfe32173d, + 0xc2a5443f, 0x5e4a1122, 0x7c860167, 0xf5f75d6f, 0x8f8adef5, 0x27c78b80, + 0x04f0fe1d, 0xdc3f2cc5, 0x4c55f0df, 0x92f80c50, 0x76a675bd, 0x499cff0e, + 0xef89f7c6, 0xdfcc9342, 0xa5d5342d, 0x7f2973e5, 0x765c1528, 0x4f5192df, + 0xe7b37e80, 0x7f52a62d, 0x96d0bcde, 0x06f05f34, 0xc3f467d7, 0xc9ff3ca3, + 0x80dddf60, 0xfd933974, 0xf79843ea, 0x2f5172b6, 0x0e79e3f9, 0xd4487eb3, + 0x3a2f3df9, 0xb3d68f3c, 0xebdeb8d1, 0x4196dae7, 0x9a6dd621, 0xf3e3b2ef, + 0x61af3173, 0xfd3f0a70, 0xc79f3101, 0x96a323eb, 0xa7306322, 0x41793ce9, + 0xda3676bc, 0x9e454361, 0xe4b643f6, 0x2e5553f9, 0x440caebe, 0x82f68d45, + 0xc13ed2a6, 0x79dff299, 0x55abf530, 0xff21570e, 0xa3b639de, 0x0ea39f94, + 0x3f7e78f8, 0x77d75b87, 0x21e85a05, 0x60055fd4, 0xfb0bf9b6, 0x517033c3, + 0xbc214e68, 0x05b2ca6f, 0x4af7aa34, 0xebf8de74, 0xbed03320, 0xc1326fe9, + 0x0a6074d7, 0x5aa915e5, 0x27464598, 0x7e44c9e6, 0xf0efbe82, 0xe44df661, + 0xd55d36bf, 0x9188de77, 0x3a85ab3f, 0x370fdfb0, 0xa6dc69da, 0x7de992e9, + 0xeabad681, 0xde51c010, 0x4bf14e96, 0xe40dd365, 0x0e3ea97f, 0x12e3d34f, + 0x3c112c1b, 0xe1eece3c, 0x7c3c00f8, 0x2670f105, 0x4d91f858, 0xafbc349f, + 0xbce950c9, 0x711490e8, 0xfc3a6d8e, 0x3a2691c1, 0xc3308de7, 0xf6fc6f2d, + 0x3f9843aa, 0x807a7cf2, 0x2e3ea4a4, 0x779e6ae8, 0x1bfcf673, 0x1aed04bf, + 0x1e19935f, 0xc277f0f9, 0x91f34f1a, 0x7824d1a3, 0xf006e9d7, 0x957e436f, + 0xf9a6cd37, 0x2f7a0a16, 0x3ae37a07, 0xe685b3e3, 0x6d73fd10, 0x9d6be70c, + 0x07a10ec7, 0x8579719e, 0xf97396fc, 0xf51d2df3, 0x73d204c4, 0x73ffd86d, + 0x73f694ae, 0xdd892b9b, 0x517ba975, 0x1c7617aa, 0xca0e52c2, 0xd427ee01, + 0xcfda370d, 0xe27f1fa0, 0x72cdf832, 0xb04bd7c6, 0xe1d94bdf, 0x65a04ab5, + 0xeda5e178, 0x90cfb434, 0x0cfb750f, 0xe71479e6, 0x9e8b0bf9, 0xa3f5e837, + 0x4499e6c9, 0xed8ebfaf, 0x9e397e4e, 0xbd027ed4, 0x8e64764e, 0x65ff5c9a, + 0xd47a71a4, 0xf946557a, 0x97f62985, 0xedc9696c, 0xdfeb54c6, 0xa290fca5, + 0xc07ee681, 0x847f216e, 0xdfb4ab95, 0xcd83f675, 0x3cc70ef7, 0xf288ad21, + 0x93f55383, 0x04c976bf, 0x22bfcf81, 0x9dfc741e, 0xf015e0b3, 0xeba4d7f9, + 0xd3e03564, 0x4b27c266, 0xf47b0cbb, 0x32bb9fd3, 0x16ea179f, 0xe0758778, + 0x16075a2d, 0xf18a59bc, 0x7f379597, 0xa7c0eb44, 0x39a1671e, 0x0fc7a08e, + 0x21df9c60, 0xfc17ba9e, 0x3b7dc44d, 0xf8d95e29, 0x17ba08fc, 0xaeba66af, + 0x749cea4f, 0x117072ee, 0x2ecce7d1, 0x3ce11047, 0x66e3c593, 0x3a4d7667, + 0xf799f184, 0x19670fea, 0xd9e67ce9, 0xe876a5a3, 0xa3ceccef, 0xf7e90aa5, + 0x9ddee9a8, 0x2abf0b9a, 0x3f5e7f45, 0x77c7d0df, 0xd3ebe4ce, 0x3f3f8275, + 0x5e301e29, 0x0a51fb4f, 0xbbed187b, 0x9b54bc3e, 0x499c15cf, 0xf114b37f, + 0x0eb97800, 0x43d3aee9, 0x332b878f, 0xdc60663a, 0xfc0bf7b6, 0x2e8da93e, + 0xe352a71e, 0xcd769875, 0xe35b879c, 0xc475a658, 0x3b50ef28, 0xd2c711d6, + 0xc41bd9d3, 0x7676a7ed, 0x5fb1e7e7, 0x7eef29ef, 0x06f567ac, 0xd0c7873e, + 0x06afe765, 0xbb7c03bd, 0x71fade71, 0xf7e94fe8, 0xd98af96b, 0xe0b1c2c8, + 0xe25e61bf, 0x2dcb8a58, 0xe607efc0, 0x71c41eda, 0xf37325a5, 0x6c5c8196, + 0x8794a8f2, 0x1c08cca9, 0xf37c23f6, 0xecef8214, 0x17df9961, 0x85b9cf32, + 0xfc67bf9f, 0xfd9b921e, 0xa7d4beb4, 0xc3e3e7e9, 0x2afeb885, 0x1a516cac, + 0x85a707d4, 0xd732c0ef, 0x10fc31d6, 0xf63ae77c, 0x609c029b, 0xd0bfc1e9, + 0xcabb3abd, 0x3f71fb42, 0xe4b777ba, 0xc7fac2df, 0x7e85ebfd, 0x48efcbd0, + 0xef31c775, 0xebbefeac, 0xec7c6166, 0xba3aae3b, 0x82fe05f7, 0xe7f41f4e, + 0x32cadf0a, 0x6a691c61, 0xa16b9cf3, 0xe3f7876e, 0xcd69fbf0, 0x577ed04d, + 0xaf1f3866, 0x534b71c2, 0xc10f0f9a, 0xb5bca33a, 0xcd29b4fa, 0xfe663011, + 0xe3cbcd35, 0x10b85aed, 0xf757d4e9, 0xa86ddd42, 0x85752d3b, 0xd579f5d7, + 0xe50bfc1c, 0xc3dcae95, 0xd9ca2def, 0x1bdf8f33, 0xee8f3ed7, 0x134e6b8d, + 0x9a63447a, 0x58563cf1, 0xf88bdf0e, 0x195e92ea, 0x8f48e5ce, 0x2f78a67b, + 0x59c39ee2, 0x06e3c51d, 0x62eec1e1, 0xbc78cbb4, 0x52f580b3, 0x8aebc7a9, + 0x61ca8058, 0x48e5442c, 0x55e54ad6, 0x68e5462c, 0x096541d6, 0xc032a5eb, + 0xe39632bc, 0x6cca8059, 0x59d1dd5b, 0x667f4fa8, 0x7c3a7d27, 0x8303aafb, + 0x44de9118, 0xc78d66b7, 0x656bd6e9, 0xdcbc1ad9, 0x3f50f828, 0x348d5557, + 0xdb62be03, 0xe87ec8f3, 0xdef63212, 0xf7045b26, 0xf9a3d963, 0x9c5abcf4, + 0x7e3eae47, 0xf7cdec80, 0x60f3c982, 0xbb8bc05f, 0x963ed33e, 0x3ed67f59, + 0x41be11aa, 0x39405f7e, 0x41708959, 0xa0ece6dd, 0x75f69773, 0x3ee907b1, + 0xb4ec67b8, 0x18555abf, 0xbd43b32a, 0xa061776a, 0x7a8720c1, 0x6655703e, + 0x96bc772c, 0xf5888f38, 0xdf825a71, 0x286fb657, 0x77fb7dc0, 0xf5a71ff7, + 0x85e987fe, 0xb69a9f34, 0x4dd86aa3, 0xca2a7efb, 0x7d39bbcd, 0x97d93af6, + 0x0640aecd, 0xfde9779e, 0x4b6fbf39, 0x94f7dfc7, 0xdf71975e, 0x283d70e4, + 0x5ee9b042, 0xf951f7a9, 0x953f7a8b, 0xb2f7ab3f, 0x4700f820, 0x04da9dec, + 0x30ce4f9c, 0x7bfbca2f, 0x432bd8de, 0x7cbe6227, 0xe601bf91, 0xcefd98d7, + 0xded013fd, 0x7401c80c, 0x75eeec0b, 0xf3b42513, 0xcf29f37c, 0xbc6d1ee5, + 0x4f008ff3, 0xe67012a3, 0x6b2fb8c0, 0xa02bb53b, 0x24fcfebc, 0xe5ffce27, + 0x0fcd36ec, 0xddc61bf5, 0x247dc5ec, 0x02e36fe8, 0xfa2ecfea, 0xf6c4ef1b, + 0x5a3f62f7, 0xa2fd9fa2, 0x677bbd7e, 0x543fbe36, 0xebee08cf, 0xb1b2da73, + 0xbd1f7fbf, 0x13f195ec, 0xba477ee9, 0x17caca2f, 0x66cb9fd7, 0xe6cbb041, + 0x41602b9e, 0xd393c7a0, 0xf942aeeb, 0xd1bfd357, 0xa0fd04ec, 0xa255d614, + 0xb7a6f0be, 0x1f413b34, 0x9d01b06c, 0xa59f54bc, 0xcc70095d, 0xb181fae4, + 0xa432e696, 0xc62bb03b, 0xae8fe1e3, 0xfa82399b, 0x7efe1ae3, 0xd79160e6, + 0xf7e3ed00, 0xed0b31bd, 0x918a6ab2, 0x66e6b630, 0xa479f746, 0xce2a37b2, + 0xc1a8b3a5, 0xba61fbae, 0x42a7e49f, 0x4c3ed089, 0xbd0f39c5, 0x5cfefcbf, + 0xfd8873a6, 0xfde8d3fb, 0x7e74abe1, 0x679c520a, 0xdf2273cd, 0x881c15c3, + 0xd763beed, 0xb8f60fe7, 0x57d5f113, 0xcc3e288f, 0xffe7d043, 0x49ffcd28, + 0xef1ef135, 0xf7d81cf5, 0x7fd1059e, 0xea26923e, 0xb7922791, 0x2fb4b34f, + 0x34cfebd2, 0x1fd69ccf, 0x12b8ef9e, 0x57b42775, 0xeafa3bce, 0x9b06df08, + 0x7d2cbfa5, 0xfc69e7fc, 0xb45942aa, 0x5052f7df, 0x723bd031, 0xabef19a8, + 0x78ef454d, 0x9b9b2fda, 0xae23fbe0, 0x5fad1950, 0xbf5a3337, 0x0602ee50, + 0xe34f183d, 0xb9c555fe, 0x247a2651, 0x7a6250e8, 0xd2e4127e, 0x7cbb4fb8, + 0xfe745dc7, 0xe7e69e24, 0x3f08b0fd, 0xb168f557, 0xfff67f69, 0xe169f1c3, + 0xc7014b28, 0x1c33bfcc, 0x3fe49a57, 0xd368c701, 0x387efff3, 0x6380a466, + 0x1c153ff6, 0x2f457b56, 0x2bda2fff, 0xcabda357, 0x9d6c41e3, 0xf7fdce8d, + 0xe52a2a64, 0xc99369ef, 0xe195204e, 0xdf68eea7, 0xcd779f2f, 0x8b1c7bfc, + 0x615f9db1, 0xd478ca2d, 0x11671157, 0x857f87ee, 0x0fcf03f7, 0x8683a02b, + 0x1f693a64, 0x5434bfdb, 0xfe05fb85, 0x5435e585, 0x546eeb7a, 0x587a5f70, + 0xefb438ef, 0x4fd96b36, 0xde933337, 0x2fbad08b, 0xb6bb22ad, 0x9b279be3, + 0x6078df71, 0x68c3dd5a, 0x93914b07, 0x24a787cd, 0xd6f5cf7b, 0xd14fd32f, + 0xce9d14ba, 0x293f42ae, 0x0ec68aea, 0xb59a3d20, 0xf0a3d200, 0x2296d19b, + 0xdaf72ba8, 0xaf000d02, 0xbedd1992, 0x1e57e005, 0x4d764e18, 0xb61ff514, + 0x6e89407f, 0xfa9dfcc1, 0x1bb7c500, 0xa5b47d85, 0xf317ae69, 0x3099ed98, + 0x7ae5204b, 0xd097dd7b, 0x7534d75e, 0xae0a73bd, 0x01968107, 0x01f75e5e, + 0xb1164f5c, 0x78a66722, 0xb46feb0f, 0x1af20d81, 0x6fe97eea, 0xbab79f32, + 0xd70d383e, 0x8c95d5f9, 0xf7087f7f, 0xd2cc9e89, 0xfbdfc2f1, 0x4f5c750d, + 0x7d448694, 0xeb7bcc26, 0xf7df5c63, 0xd1ebaba6, 0x44f987de, 0xc31b8ec8, + 0x630e93e7, 0xf4fe007b, 0xbeb44571, 0xf17d6146, 0x0a71fbe0, 0xf7d2f79d, + 0x6c639c83, 0xed841fb4, 0xc2ea7ee9, 0x742fda22, 0x388163ce, 0x69e703e6, + 0x09517f7c, 0x3b3cc4ce, 0x04bf1f77, 0x8aa6ce29, 0xa26d12fd, 0xad205f39, + 0x99b45be9, 0xfcda369e, 0x5ccc39dc, 0x9dc0b077, 0x60ec8f74, 0x2681be4b, + 0xb00687f6, 0x1457e841, 0x6c3622db, 0xca85da07, 0x76df7851, 0xec811e31, + 0x0c58faa4, 0x31e31691, 0x0c1d3f2b, 0x3282c09b, 0x6486a38f, 0x698e3bf4, + 0x07947ce1, 0x66e2269f, 0x8dbf7883, 0x36ff61a1, 0x8ff14fcb, 0xf5efb47c, + 0xb379c6fa, 0x4a91fe29, 0x889a22be, 0xec36dee7, 0xce9af7a2, 0x19100738, + 0xc68e6ff4, 0x6f6b81f3, 0xd779f7e2, 0x947ee1ee, 0xe8b27efe, 0x9c4536b7, + 0x327ae413, 0xd63df9c2, 0x485edb39, 0x0e7cacf7, 0x75f356e9, 0x6b4fc31b, + 0xdfb9c7e2, 0x53b7b166, 0x158da1e5, 0x5f9f4dfe, 0xf218fc23, 0xc2ce902d, + 0xd2ea597f, 0x4fbe6ee9, 0xa247bf42, 0x4f4dc847, 0xa8c44ab9, 0xea098345, + 0xe9853739, 0x3172821e, 0x654df29f, 0x2c1fe8b9, 0x8225ffdd, 0x79c6d973, + 0x5e4bde2a, 0xe13171be, 0x52ebc745, 0xa7f07f8b, 0x8d1709d6, 0xb4f6e9a7, + 0xfee81fee, 0x484fd580, 0x47e7fdf5, 0xcc3a27ee, 0x3ed195f6, 0x3c1affef, + 0xe07586cf, 0x67de20b6, 0x473ffba5, 0xf98eecec, 0x73655cf8, 0x2ec3f9f0, + 0x54560f7e, 0xd87583dc, 0xdf859c5f, 0x7f3e29cd, 0x3b2f9625, 0xedea1a63, + 0x7a3e3f97, 0x4a0ff903, 0x8d3cc34c, 0xfff70a33, 0xe7633af4, 0x0bf38a64, + 0x7eef5fbc, 0xb867ee95, 0x74f7f0be, 0xfdc6bd3e, 0x3f639d2a, 0x3ca766d3, + 0xb15debbb, 0x1dfde36c, 0xcdee17d7, 0x747e18be, 0x8088e1ff, 0x7bd170f7, + 0x571a6105, 0xb70473e4, 0x53d2174a, 0xe7cd6f7f, 0x3e98ecd8, 0xa669e513, + 0x2ff9e926, 0xcd97c88d, 0xfc9387f3, 0xe89bcf64, 0xf39bfde4, 0xc791b24d, + 0x47cfeeae, 0xef59ff3a, 0xf1235925, 0xe0a9ef73, 0x19b405aa, 0x3dc4d1d7, + 0xef3d2a25, 0x0e86f116, 0x54f6fb1f, 0xac799790, 0x75fb4ece, 0xfd177ee2, + 0x4179975e, 0x2242fdcb, 0xd6242aff, 0x5e4437c3, 0xa7e63cd5, 0x376817ef, + 0x75bf51d9, 0x6e60fb88, 0xf1bb6162, 0x425ea67c, 0xb6bd26bf, 0x7eb98e60, + 0xb75cc873, 0xe7a8a3de, 0xdeb4fccd, 0x89ef153f, 0x999dfbd3, 0xd3ec3f42, + 0xb03c5d3e, 0x67507e2f, 0x71e81f8e, 0x43cc1abf, 0x1e18fda6, 0xe4e59bf7, + 0xbb8f4fe3, 0x56a37f68, 0x16e33753, 0xc5b3ea0c, 0xc6967cf0, 0x8bc60df5, + 0x59a29ef0, 0x6f1f7e8a, 0x80e7bf54, 0xf909cbbe, 0x0ddc6336, 0x5ee930f3, + 0xdf1e70ab, 0xa0721157, 0x0ece19c7, 0x5e6467f3, 0x4db5bf84, 0xba9ee9b2, + 0x13b895fb, 0x00fee0f9, 0xf04ac3cf, 0x6f14d471, 0x49a936d5, 0xebebb7ef, + 0x9e0af407, 0x3ee0724f, 0x01f7d02f, 0xc635e825, 0x887b3423, 0xf4f776ea, + 0xf2f23f0e, 0xe3661b03, 0x988d1055, 0xca760c1f, 0x6957da3b, 0x03db767d, + 0x621ef187, 0xc7e6dbb7, 0xb341b8f5, 0xa357bed1, 0xefeb49cf, 0x8bdaa97a, + 0xebf7a4fc, 0xae0854ee, 0x06515ab3, 0xabff08bb, 0xda334fe0, 0x87df31af, + 0x9e37dff5, 0xddfaed46, 0x0a7075bf, 0x131d59c5, 0x17bc016d, 0xb1ac1d5c, + 0xcfc9243f, 0x936f1bec, 0x549fb492, 0x77494ff8, 0xf507a77b, 0x7c96b743, + 0x2dc8ba3f, 0x3fc2fb89, 0xb22c3ca5, 0x5f33c3c4, 0xefc71e1f, 0x8a1bcea5, + 0x8a3e490b, 0x2b6f20dc, 0xccf59dc7, 0xe47c93f0, 0x2e1c7cf2, 0xabda8db7, + 0x6c379e4e, 0x152da7be, 0x4978ea3f, 0xc8e50785, 0x37e78c5d, 0x7f719986, + 0x43c52dce, 0x4e32d794, 0xb8afba49, 0x51a1e056, 0xcabf1009, 0xb89c86d7, + 0x4f64340e, 0x7ffee277, 0x28cfe2b3, 0x88f0fb44, 0xd66e30cc, 0x8dcb35e4, + 0xfb88b65e, 0x6dbae745, 0x7559ef49, 0xeeff92da, 0xbe6e5dce, 0x9fecb44e, + 0x52dee742, 0xd46809f1, 0xa5a5d910, 0xf3ef178a, 0x5e1ced96, 0x04fc8a57, + 0xfc54dfbd, 0x177eef71, 0x61993dff, 0x659f3a4e, 0x9c49af1d, 0x78026bc3, + 0x1a6dced0, 0x6c7841dc, 0xd178a89a, 0xd3f9768e, 0x5ed0d398, 0xef489cc9, + 0x78d96acf, 0xa5359026, 0x4f1d3be0, 0x9f6db9d7, 0x16c2ff8d, 0x0df9cbfe, + 0xfc0dcbc5, 0xff193ab7, 0x983c875d, 0xde37e1c3, 0xf264a9ab, 0xbc2b3ffd, + 0xde3e7e7a, 0x9fcc6e87, 0x845f052a, 0x1c8e8dc7, 0xec0c3e9a, 0x303abedd, + 0x86d78c38, 0x73fb8e7a, 0xd133a771, 0x647dd1be, 0x75429376, 0xdf07df3a, + 0x6cf7f105, 0x39fdc4da, 0xc1f3a835, 0x45beaa8f, 0x9f585e63, 0xbb2ccaef, + 0xda51e717, 0xab9f8071, 0xf9a1cb69, 0xadef8b57, 0x9c3dc6f0, 0x2f1ee39f, + 0x82c71995, 0x77dfc03f, 0xf348eb68, 0x2db71c63, 0xd639db8b, 0xf5bbceef, + 0xb156873c, 0xfb49d1df, 0xf8333912, 0x3bbbd47a, 0xfea3fc9d, 0xf7e069f8, + 0x8dec5869, 0x94367bbe, 0xd51dd938, 0xc7d0eec2, 0x82c45d2f, 0x2f4bbbf8, + 0x2716b1a5, 0x843b87d8, 0x2df6321c, 0x780a5fb1, 0x7c6fb804, 0x3fed1471, + 0x04bdfde9, 0xcfb612cb, 0x912cedcd, 0x3fc0cfe4, 0x6fba6631, 0x39d9c6ad, + 0xbe47f51c, 0x46edde1c, 0x6758e33f, 0x5edbd62e, 0xe0f64d3d, 0x73f0f0a5, + 0x51c2bf81, 0x571e7dba, 0x35d6718d, 0xf45d95cf, 0xc6355d7c, 0x50fe0c43, + 0xe9b36f02, 0xa17ebf79, 0x1fe8bf3f, 0x8d392be3, 0xa09ae9c9, 0x4c8b3e4f, + 0x0a7d18b8, 0x25d23de8, 0x1fd39a3a, 0xde60f9f7, 0x607fd764, 0x09ef27d1, + 0x9f4ffd7a, 0xae26366f, 0x40e53f01, 0xf188e789, 0x9fbc5bde, 0x6fc794f7, + 0x15b27f5a, 0xcb3553f6, 0x2c6987c0, 0x8dfa84e2, 0xd167ce8e, 0xfaebd3fe, + 0xc7c11bfb, 0x39fd8c9a, 0xf2e91cb9, 0xb928bd5b, 0xedcb7edc, 0x3c0efc21, + 0xbee0f716, 0xfc628bc7, 0xe81fd8b6, 0x76b6b3be, 0x3d4fe199, 0x96145c0c, + 0x4e825ac3, 0xebe1fbfd, 0x60ff2e8f, 0x0b728e4e, 0x4a3947f9, 0x6bfdcb5f, + 0xdfe8cf5d, 0xcfb47915, 0xee8f1f66, 0xc8ac4e77, 0x75724393, 0x05f44308, + 0x7bbdf96b, 0xa2ff0b6f, 0xd39fdc5a, 0x18c7dfa5, 0xde33691c, 0x5a76f5bb, + 0x87fd1441, 0xe5f787b7, 0xed1ae609, 0xf0576aaf, 0x1bbef0df, 0x7ca65476, + 0xc1bc0fd5, 0x9a2fee0c, 0x712ea7fd, 0x3fee8eaf, 0xffdf8b35, 0x7f398362, + 0x1dd24b37, 0x91ffb0f3, 0x72af749d, 0xa75f2e6e, 0xcc7f73f5, 0xf64259d7, + 0x54abe0b7, 0x0f39f77c, 0x83d40f97, 0xad7ca491, 0x0dbf9e9a, 0x70c460eb, + 0x53cee84e, 0xcf1ce8c3, 0x78a01612, 0x749692e6, 0xbde03116, 0xf9e4f1ed, + 0xbe848b35, 0x4ef7136f, 0x5e7cd1b3, 0xf3e7be09, 0x1c975b68, 0xbe0c9eee, + 0xfb89b70e, 0x6094dbc5, 0xd529e23a, 0x078fa13a, 0x3ca74b04, 0x6f07f387, + 0xe6fd71a0, 0xfa257f71, 0xb26ff17d, 0xc0037df8, 0xd827d0a3, 0x9b1e1bfe, + 0xe2bebe49, 0xb3faacf9, 0x24feb4cc, 0x9e933ef0, 0x927d767f, 0x927d0979, + 0xf251ef4d, 0x3a78ced0, 0x7b75efc6, 0xce6db0fa, 0xdb742496, 0xaaf4e424, + 0x3fee851c, 0x76e7151b, 0xb976aa40, 0x639ee259, 0x7c2b4781, 0xf9c9c5d9, + 0xfe0ca5e3, 0x7e74f57d, 0x1bde334f, 0xb285f38f, 0x75fd0020, 0xf422d74d, + 0x6fe25ffc, 0x7ab49c62, 0xbf8fc3a7, 0xd3b5d7cf, 0xa27a8155, 0x62a3a76b, + 0x7e9fd68b, 0x3b663cbb, 0x4ccf99f7, 0xf58c7fbf, 0x705174a0, 0x5fd1cfc2, + 0x3ee99768, 0x927f6b49, 0xecf34dc7, 0xec29e7d3, 0xb9b9afb0, 0xe74ecd3e, + 0xf117b174, 0x572ad475, 0x1d3c8547, 0x2d90f215, 0x75876bee, 0x92eb89c9, + 0x0217eede, 0x2cc393df, 0xe7c17de9, 0xb12e02dd, 0x76bc3c2e, 0x04c3fb06, + 0x08ce7dfc, 0x7eda19c5, 0x7ec02f13, 0xdc78cabb, 0x16fdfac0, 0x998c67c1, + 0x3349eaed, 0xb9e612fd, 0xc5e498b0, 0xfdbd7c7d, 0xb7bf18a4, 0xd3b9fff8, + 0xdbc5ecfb, 0x807bbfc8, 0xf49a2eff, 0x81eb8a53, 0x61b4170d, 0xc18fd15e, + 0x5ff8338e, 0x1de8b2bf, 0x0baf3c2b, 0xefc4da78, 0xeb8d3287, 0xf55d2b61, + 0x779f4c75, 0x1cb300f6, 0xd7ff82c8, 0x9647328a, 0xb9743c68, 0x7d7c591c, + 0x5cc4f9e6, 0x49d2e24f, 0x1e5859cf, 0xbcaf7003, 0x90e6fc43, 0x95dcef88, + 0x31ef3e19, 0xe9da3df0, 0xbb097eb4, 0x6fdc4dbc, 0xa889dba9, 0x466bc74f, + 0x0e0223b8, 0x4ad7d71b, 0xf30d7d72, 0xe2a7bf10, 0xf6127ea6, 0x262bb706, + 0x166dfc0a, 0xb25f51e7, 0x3fb226b1, 0x39749e04, 0x9661951d, 0x7f8ca2d3, + 0xacdd390e, 0xa4727cf2, 0x787d325f, 0x9427ed1e, 0x71c16387, 0x4572c798, + 0x5fa00b48, 0xff31da5a, 0x0cf1e600, 0x943f83df, 0xe1e39093, 0xbfb19f82, + 0x2dfc0645, 0xf09b70c8, 0x7f8cf9f7, 0xf877bb0e, 0xdf37d631, 0x7d7a0cdb, + 0xe5c68655, 0x942ffc00, 0x9a7f8a83, 0xe00e86f9, 0xa06aae39, 0x9d0caa3b, + 0x8b62da3f, 0x3ed0b9d7, 0x6802c63e, 0x16c7775f, 0x7f00c6db, 0xf6e26f74, + 0xdf9e9f63, 0x7a05f1c8, 0xf97a8639, 0xf4c1638a, 0x275f50d1, 0x458ae3f8, + 0x14e7df8c, 0xcfd14773, 0xce44f5d6, 0x7033bd4d, 0x7a6577df, 0xf0cb835d, + 0x3b7dafbc, 0xe84c2fb4, 0x37d46a9b, 0x7df6d4fe, 0x8d3a466b, 0xe209eb87, + 0x733a5665, 0x979e00ba, 0xee32230a, 0x4574be6b, 0xe7bc78e1, 0x785a50fd, + 0x7ef86af4, 0x0e3e1cd2, 0xaf44776b, 0xd2ff1248, 0x88ae75f5, 0x7c8ae54f, + 0x5e34dcef, 0x45f42c7e, 0xc1f39783, 0x9ebcbdaf, 0xcf1e49eb, 0x17ef11ea, + 0xdcef5cc8, 0x2edc9657, 0xc67c6589, 0xb24063f8, 0x1963e3c6, 0x6f9ee239, + 0xeb5f425b, 0x7c4273fc, 0x2edf8fa7, 0x9cfcb5e6, 0xe59fe264, 0xcdf11d4a, + 0x3d0a73f2, 0x1522e5d7, 0x79fbe9ff, 0x78e11d9b, 0xbe7bd406, 0xc60961fe, + 0xe9ef0a0d, 0xf848fbe2, 0x5253407b, 0x1ebe87cb, 0x3d06f4e8, 0x0df186df, + 0x2713f3d0, 0x18f43ad3, 0x9c85975f, 0x1ff4ec1a, 0xb659efe0, 0xd4555c75, + 0xdf6ba060, 0xfee0197a, 0xd95d758c, 0x57c4c980, 0x89d79ea7, 0xa3ef2ccf, + 0x25e1d852, 0xbc3b577f, 0xc93c63b4, 0x578112ed, 0xc7a6de3d, 0x507b18b5, + 0x13f731f8, 0xe4cd277e, 0xdff80df2, 0x9a3ff021, 0x7dbbffe3, 0xec95bff8, + 0x2f2e5684, 0xa52b9db9, 0xfa2f9262, 0xa4ddff4e, 0x52afd3c2, 0x2f78e77e, + 0x13ffe7f7, 0xc9555084, 0x00008000, 0x00088b1f, 0x00000000, 0x7dd5ff00, + 0xd5d47c79, 0xcefdf8b5, 0x3324b677, 0x5f64ccc9, 0x25849308, 0x2126126a, + 0x26504109, 0xc5116109, 0xfb094049, 0x515983b0, 0x2fb5696c, 0x4a444103, + 0x505d8bdf, 0xd101da94, 0x101ac55a, 0x83b06034, 0x6795622c, 0x05b054a4, + 0x2108ee3b, 0xf16b43c9, 0x3dde5a57, 0x999bdee7, 0x006677ef, 0x7e7ebe7d, + 0xdeb8ff0f, 0xdef7cbb9, 0xfb3dce73, 0x3ab3c9bd, 0x21094b25, 0x0b62a21b, + 0x99941c48, 0xc84b125e, 0xbd3e0988, 0xe90844dd, 0x95242448, 0xa423aefe, + 0x475aea0b, 0x2423c932, 0xbd389ead, 0xbed19eb4, 0xfad2d25f, 0x8637f865, + 0xc94ad310, 0xfe9e30b9, 0xd3b694be, 0x3a166ddf, 0x9ed03130, 0x1609ebcc, + 0xd025213b, 0x820d27cf, 0x936f36f9, 0xb4be74b4, 0x62908976, 0x2f13365a, + 0x4b8c0ac9, 0x99efb073, 0x01695e1c, 0xbb48dfed, 0xac849191, 0x59e754d3, + 0x14996812, 0xbfa568e3, 0x07bab06d, 0x4fea7ec0, 0xda667cf9, 0x2ea9c465, + 0x7b8e9bad, 0xb4cceac2, 0x63f60624, 0x24692d97, 0x53989087, 0x366d9d6c, + 0xfb05d732, 0x174cfe23, 0xc63f240c, 0x15b211f5, 0x93289bd7, 0xab46c423, + 0x2f7e87d0, 0xd6ee7569, 0x7d6052f5, 0x6ee23649, 0x49496da7, 0x84d3bdc4, + 0x2291d7fd, 0x7048d7da, 0x87ab493f, 0x059f5d6c, 0xde7179f3, 0x36d71caa, + 0xf92abdf8, 0xfa56a2ba, 0x9f06ce7b, 0xb71d3e76, 0x0266b377, 0x2bcc53ec, + 0x0916d1ca, 0x8c7dd1c7, 0x7d89fd80, 0x9289fba8, 0x5bae0f10, 0xb345d3f4, + 0x5bf685fd, 0x4cc6f385, 0x6d0df060, 0x2f6c77ff, 0x0cc265ff, 0x1afd6f58, + 0x0148313d, 0x75613ff8, 0x4d7002dd, 0x0122df6b, 0xa68c3e6c, 0xf02c3474, + 0x29a30fdd, 0x76b0153d, 0x87f3853b, 0x79474a7a, 0xb48a3a01, 0xb295fafe, + 0xa0f0e173, 0xe23d1afa, 0x2c9e8b69, 0x5e0bcf6d, 0xdf5c6adf, 0xcb068b22, + 0x2cd756a3, 0xc7634f80, 0xfbc07ac3, 0xe81f6db2, 0xcef857dd, 0xee91c2b5, + 0xe296957f, 0xb25daebd, 0x4ae92818, 0xe81392ed, 0xe8d6bea0, 0x6fd47805, + 0xd64b7467, 0xa183bde8, 0xa7c3bede, 0xf7e9eda1, 0xfd321d3b, 0x0efb6eb9, + 0x7c105169, 0x12bdebd3, 0x59a86bac, 0x1e9f2b9c, 0xfe8a95cf, 0x4578510f, + 0x1c3bba51, 0x5a463c45, 0x3c9b9776, 0xb76f8512, 0xfd0f5dce, 0x1c6353ba, + 0xf5efda1e, 0x488fe31d, 0x779adcf4, 0xae507c1a, 0x314d6cd3, 0xd775f6d2, + 0x41ad1deb, 0xbad36774, 0x6b38c176, 0x8ab1d982, 0x206eca7e, 0x9c131645, + 0x47fe2577, 0xc5cecfdc, 0xa32c4b6e, 0xe08a4223, 0x316e3c5c, 0x82893d63, + 0xf7d28cbb, 0xd75b1d61, 0xe1e8c24e, 0x836b9c52, 0x23e3bf05, 0x3ade3a0e, + 0x3a979d81, 0x7e891fba, 0x2ef36eaf, 0x623927dc, 0x6fa7b843, 0x75bbf097, + 0xb9e0b7db, 0x73bb3ace, 0x2ffa1ebf, 0x2451a525, 0x1b9cce98, 0xd5efcf83, + 0x426235f0, 0xade81ebb, 0xf2a1f38e, 0x3e936e5f, 0xafdfda0a, 0xa3c2322d, + 0xfdb6f36e, 0x647bf469, 0xb60cb129, 0x13fdbf63, 0x06b5f7d9, 0x607fc412, + 0x9d6c799d, 0x8ff8828b, 0x3e187fd8, 0xaf585bf4, 0x41d754e9, 0x487c87c6, + 0x6afd628f, 0x7e7076bc, 0x3c4f4e38, 0x93debbf8, 0x1df3a76b, 0xf9c68ece, + 0x73805f04, 0xa5f9c35c, 0x6213d686, 0x5a0eb9e8, 0x9e6f588f, 0x82d3a2b5, + 0x3842e870, 0xe2d66c34, 0xaef4abfa, 0xce83cb41, 0xb9f9efc3, 0xfbda6d79, + 0xfdfd3f7a, 0x83bf2fe7, 0x936869f8, 0x48cfc09c, 0x3bfa3bdb, 0xbfac01f2, + 0x21124991, 0xb7fb0893, 0x7a3bf771, 0xd27dfd3b, 0x86bf862e, 0x0bb43b5d, + 0xccfa014c, 0x1cdafb3a, 0x7686b3a0, 0x00928903, 0x582eee7f, 0x054e9a8f, + 0x8ddf043c, 0x0998cf84, 0x0f128f8c, 0xcf485f3d, 0x731aacee, 0x8a5f6f80, + 0x353a30d3, 0x2dbbdfb1, 0x1fa01eac, 0x974007f7, 0xd78ed155, 0x15545ce0, + 0x02568e49, 0xfb863ceb, 0x7064a848, 0x754f5e0c, 0x997e647e, 0x85e5cf18, + 0x63599fd6, 0x7eaf9c0e, 0xf7c7cfbe, 0xfc995e02, 0x49dfb1f0, 0xb03f2bb6, + 0xd2de356e, 0x0ff612ad, 0x01174f43, 0x26b96a7e, 0xe3e82fd6, 0x0ab59bd7, + 0xeab061f9, 0x55833e71, 0x08dbeb8b, 0x7e72a1f8, 0xcb9d8ea3, 0x5e8cab8d, + 0xc7d31fe4, 0x9f28911d, 0xfbd0cf36, 0x99a43ca0, 0x87ed0f5f, 0xd7f7d8d2, + 0x43773469, 0x136add7d, 0x3a7c4569, 0xa044d68d, 0x4bc4589b, 0x6bdead7d, + 0xfcfcf3a0, 0xeabfc645, 0x012f263d, 0xba9ee83e, 0x8491c610, 0x8053c728, + 0xfd41f737, 0x7a50e61d, 0x6f63d3b2, 0x6a4fbfa7, 0xe04ce767, 0xa451f281, + 0x04bf212b, 0xf4f0035c, 0xc08dce2a, 0x0b38a5c7, 0x2cee5be7, 0x33dd7780, + 0x738fde51, 0x132eb7d9, 0xa2ab4ba0, 0xea91d4de, 0xa818d8fd, 0x00ffc1d7, + 0x52a76c1d, 0x83ae94ad, 0x765d33af, 0x6efb075f, 0xeb0ffa30, 0x4f4b6a28, + 0x8eb9e1f6, 0x2b75b744, 0x98fb4cdf, 0xa57743ea, 0x38a581bc, 0xa56cbaaf, + 0x78e52e3c, 0x9bcbc01f, 0xd41f8cac, 0x79e3b715, 0x19b8fbac, 0x0269b1cf, + 0x53a667e3, 0xc84d7e4a, 0xb2beb84f, 0xc557c701, 0x29938fb4, 0x257eabdc, + 0x64495a59, 0x2244b97e, 0x9fa7902e, 0x3b103e6d, 0xe97be00f, 0x8dfb8cb2, + 0x6c9dfb62, 0xfba8e765, 0xa4700a19, 0x093d66f7, 0x9d6bdfb3, 0x4b8ef88f, + 0x0e3af780, 0x95edeeeb, 0xf4a13f23, 0xce2679e2, 0xdcf7fc01, 0xf83f29f6, + 0x7bbbae84, 0x9b9418db, 0xa42ead09, 0x28c4be9f, 0x3f4a56c7, 0x20993209, + 0x6aafbc51, 0x8a3b103f, 0xb9fcfb8e, 0x8f204561, 0x9e75f117, 0x095e517d, + 0xebfd5970, 0xf6866e17, 0x0f14af3a, 0x99fbbc7c, 0xf813fd5f, 0x4d6dd2fc, + 0xd69149a0, 0xf7a77ee7, 0xef1a7ed3, 0x33fbf616, 0xf7e81671, 0xdf0f93f9, + 0x6d6ef00c, 0xb3f6c56f, 0xfac16e4f, 0xe17ebf6b, 0xf207ffd5, 0x80eb15de, + 0xdc5f677e, 0x77a9788f, 0xdfb09d6b, 0x71bd7448, 0x27c67ec7, 0x39c3ae41, + 0x4bfc65a8, 0xdfa0b5d0, 0x773d7fcf, 0xa87cb064, 0x12195d97, 0x38364ff4, + 0x5e50929e, 0x14389ca0, 0x7451b445, 0xd2d3afff, 0x792acb48, 0xe01d7ef9, + 0x33f18739, 0x790921aa, 0x7f431bed, 0xcc4c7dbf, 0x2f3bd416, 0xcf0833dd, + 0x3ba30c4d, 0xcf918f3a, 0x88798463, 0xf33ea096, 0xa875e676, 0xcd2952d7, + 0xce1249fa, 0x1ba6e873, 0x17b9c2b6, 0x6af985eb, 0x3abda1f2, 0xf889e403, + 0xe75f1d7d, 0xdf2668ba, 0x537e71ce, 0x075a6157, 0xa3e7b9e5, 0x8d3f016a, + 0x2b10ff7a, 0xd18f2fc0, 0x265643f1, 0x97dbea87, 0x384d1aeb, 0x9779e71e, + 0xf32829f2, 0x94fa79e9, 0x6bda579e, 0xf0e1e5db, 0x3e32dfbd, 0x60ca4d19, + 0x7d66d31f, 0x62fc0120, 0x75759af2, 0x58e7d708, 0x7052c53b, 0x760ae97b, + 0xfb74d47e, 0xcfc4d5a4, 0x69b73b0f, 0xec33aabb, 0x8e0cb7c8, 0x53fa41c1, + 0xab7752da, 0xcb7efe99, 0xa643b70a, 0xccf7b774, 0xb4e971b1, 0x695cebfe, + 0x2cabd238, 0x31ec7931, 0x561a77e1, 0xe88f9256, 0xcfc9dfb9, 0x68859275, + 0xe00a2c6f, 0xb44b4aa9, 0x1f7f8426, 0x7586b5f2, 0x636f5e5c, 0xbec624eb, + 0x1c6629cc, 0x16d1ba67, 0x671d0758, 0x2fbd6132, 0x907ccef3, 0x945a9e8f, + 0xae3d768f, 0x5fe0acf7, 0x3b3053c4, 0xa81fc03f, 0x7a06e6de, 0x7b33d24d, + 0xb563f805, 0xf2e6f419, 0x4092d623, 0xdacd1499, 0x6d9270d5, 0x3bae9db4, + 0x7ec4e6df, 0x857899e4, 0x07c48afc, 0x37fe391b, 0x40c5fe4a, 0x513d9e67, + 0xc6eba016, 0x1443fd9b, 0x53870976, 0x9e9ba70f, 0x0e5e8c3d, 0xd81e3469, + 0x37ada1df, 0x4295696c, 0xae50f1e5, 0x4875a79f, 0xda4bc016, 0xfe051ae6, + 0x0ab75ea8, 0x5c86caf4, 0xf7f514a9, 0xbfbfe58e, 0x291bd68e, 0xb8dea0de, + 0xaa4f9f8b, 0xc6ff42a7, 0xf085ea8e, 0x8984f4bd, 0xfd42590e, 0xad3a5c68, + 0x1293d637, 0x071bff38, 0xe3a4f738, 0x94f2243e, 0xd529e41d, 0x269e41ab, + 0xde3ea3e6, 0xfa86dee8, 0x73d5c937, 0xf510b7b9, 0x9994c6f5, 0x215f380e, + 0x2acf627c, 0xed1af7d4, 0xda288ed1, 0x7487527f, 0x4c77d337, 0x7247ad84, + 0x77927d42, 0x73d61794, 0x9447c05e, 0xf039aeba, 0x06dd9efd, 0xafeda1e2, + 0xf28f19ef, 0xf98bd05c, 0x75ca0325, 0x8122d69b, 0xc5ae7e5e, 0x4c1a3e49, + 0x9cb81fc8, 0xdbacf011, 0x7381a59e, 0xc3b79e72, 0x97127b3f, 0xc36bb487, + 0x67d21f42, 0x13dbd73d, 0x7bc2ce0c, 0xf427f082, 0x641d3528, 0xd35e18db, + 0xe0941f36, 0x73f1ab10, 0x6be252cb, 0x65bbeba2, 0xa637c6b3, 0x19abf500, + 0xe957f7c8, 0x742956c9, 0xc63621be, 0x5de2aa2f, 0xab27c085, 0xc11c99a6, + 0xda2aa9fc, 0xd20a89a9, 0x157108f3, 0x26763d83, 0xcff08cc9, 0xeac3d9b7, + 0x79f6a165, 0xb74fda14, 0x480a79b6, 0x155d6d36, 0x92e70b5d, 0xf21363f2, + 0x0f1d0b4d, 0x51d6fdf6, 0xbefb324f, 0xb14de715, 0x8ef9d859, 0x83371577, + 0xb5c7203f, 0xb331c982, 0x8e7edc23, 0x3e1e855a, 0x740350a7, 0x00e4d532, + 0xafe7f2bb, 0x6e91f348, 0xc260543c, 0x38af7179, 0x2bd99136, 0xe23ba00e, + 0xd5bea2d6, 0x86f2ecd8, 0xc7462ba7, 0x02ff548d, 0x15d29c3d, 0x83b1ade2, + 0xf7611fc9, 0xd6089f03, 0x12b9c577, 0x35f816e7, 0x37a08dd0, 0xf5af6e71, + 0xf3f0f67c, 0x1ff743d1, 0xbde69f4c, 0xafd72e8c, 0xfb4397b2, 0x09622afa, + 0x76d557b6, 0x1f0e1d90, 0x8c9fdbad, 0x823cc2f1, 0xbab06dcf, 0xbd60da66, + 0xab58df5b, 0xd4be0125, 0x21a1f7b8, 0x8ccfd257, 0xd19f365a, 0xa60de31b, + 0xb705231f, 0x0f4b08b9, 0x9598e7f0, 0xf723fde1, 0xcf4c4cda, 0x65fab6fb, + 0x7c05a49e, 0x5f32fd09, 0xe36bdf76, 0x08a525fa, 0xe992b992, 0xebc04997, + 0x8d6c1f81, 0x113f02f1, 0x7af5267e, 0x099cfcdc, 0x233b0abc, 0x7ff59629, + 0x359b9f98, 0xbc63dfbc, 0xf05fb20c, 0xee35d83c, 0x591c880f, 0xdf71880e, + 0x7c4bdf95, 0x3523c847, 0x41fac0fd, 0xaa7ec16e, 0x6bf722f3, 0x38edcfdb, + 0xe1ef3d15, 0xe016abe7, 0xbc627a08, 0xe700effb, 0x19c47159, 0xeb3ff14f, + 0x27a40677, 0x0437db92, 0x2d3ad0ec, 0x806c18f1, 0x1fd79d57, 0x78a6b784, + 0x6cd7be36, 0x1cf4c8f4, 0x6f778a5c, 0x153c7987, 0x3d03e1c4, 0x5f9487f6, + 0xbe24b9c0, 0x4d27e012, 0x700b1fc4, 0xdbbac5b4, 0xaee53e91, 0x3b53a84c, + 0xf3be00a6, 0x9fb30c48, 0xbd90defa, 0x2e3c2943, 0x3efffd18, 0xc2e7ae8a, + 0x87871c8a, 0xef7a73ce, 0x99ff779f, 0xfbbf3ef6, 0x7ec101b3, 0xeca346ac, + 0xea07c6d2, 0x6da9123d, 0xbb77c30f, 0x986fcc6c, 0xbbf08375, 0xbadea1f5, + 0x0c99ca22, 0xfb159f7e, 0xa4af93ca, 0xac5d37cf, 0x3f20de24, 0x0f1d135c, + 0x8e2e9ae3, 0xe643dfc3, 0x7c81f3a5, 0x4e98ba68, 0x77d9c33c, 0x30fc6f80, + 0xc0dbf19e, 0x3f6c4cf8, 0xf3fa51ad, 0x3c45e5fa, 0x422ed7c3, 0x1f6b8426, + 0xb5f6cf1a, 0xdf9d9b2b, 0x17924dbe, 0x2bc583ec, 0x82993ecc, 0x19fd3174, + 0x16c5a5f4, 0x0b134f8f, 0xb1f287fc, 0xa9c68861, 0xcc8f6a46, 0xf68cf2e3, + 0x7a068ed3, 0x1cf058f5, 0x9c39f9ba, 0xd7faf1d7, 0xac589fe0, 0x74d1c625, + 0xc746f99e, 0xfbfa74e1, 0xb1b1a627, 0xde162620, 0xe409253b, 0x66acf258, + 0x32122ff4, 0xa9fa02d6, 0x97cb4644, 0x0fa4ae63, 0x458f5169, 0xf074a27a, + 0x2faef16f, 0x1d021d04, 0xf187bacc, 0x49ffd135, 0x17f3869b, 0x1fbe1d25, + 0xc6efdf01, 0xe80afc57, 0xd738c1ec, 0x7bde703f, 0x5ff82bce, 0xfa7fe48f, + 0xe5d3a071, 0x2453c766, 0xc389bc74, 0x4bb0b7bd, 0xdef1fe0f, 0x44c8ffe5, + 0xf5f3b47d, 0x1ba7c093, 0x0c9f268c, 0x5d2ec57a, 0x03ec5fb7, 0x339c62e4, + 0xf38e9e3a, 0xfada383c, 0x9209a529, 0xfdc77f4c, 0xde144ed2, 0xbc191b77, + 0x5b778ddf, 0xee9113e3, 0x757d82e7, 0xb38f68c1, 0xfbe8bd01, 0x2632e3f1, + 0x3243f005, 0x74bc4acc, 0x997881be, 0x01ea746f, 0x2e9c0bfe, 0x38ace75c, + 0x8145895f, 0xf2f93c87, 0x078ed70d, 0xd3eb9f99, 0x730e5fe0, 0xb872861e, + 0xd1fa10fc, 0xa31a74f2, 0x6499d3db, 0xaf284ee9, 0x771d25a7, 0x8bd79b3a, + 0xef087d78, 0x37eac497, 0x5d3dba72, 0xbfa9fac0, 0xceff2773, 0x62cef1bb, + 0xe71d1380, 0x5ebe03d3, 0xbe82f28d, 0x8dd6f94c, 0x7c5e8cf1, 0x55be60d6, + 0xf80437dc, 0xc5096f61, 0xfacfdd1b, 0x13ccbef2, 0x19f657c0, 0x57ed5b2c, + 0xbe64dfc7, 0xc72d6fae, 0x958e541c, 0xe4d8e42a, 0x10c72678, 0x7a25744f, + 0x420d5fa6, 0xc87d20fc, 0x1b9f8ed7, 0xe9dc19a2, 0x478da979, 0x77cbe579, + 0x86f7f105, 0x044e7678, 0xad1d393f, 0x38dfe3c4, 0xfbc79c1f, 0x6616f1c9, + 0x32fa39ef, 0xb6d39e61, 0xbbff78f0, 0x8b1f1fad, 0x1967be81, 0x53c4e6fa, + 0xea93bb7a, 0xc422fa0d, 0x09eb0c87, 0x7cf34fb1, 0xdcf3857f, 0x8099b774, + 0xef866bfc, 0x589e2225, 0x7d97297c, 0x3d4f7297, 0x1f86afd4, 0x52a7d5f0, + 0xf4c9243e, 0x563c3643, 0x1aa71676, 0x16f3c16d, 0xee4fcfd5, 0xfa8f860f, + 0xbe38a7bb, 0xda4bc6d6, 0x0e8f014f, 0x737180e2, 0x3cc2f9de, 0x79c9d29b, + 0xa1a3d18b, 0xbb2dcd72, 0xbb7ec3d7, 0xea06f07f, 0xbef4a7bd, 0x30a66d21, + 0x13df7aed, 0xf681488f, 0x3d91bfb9, 0x778e7a7a, 0x62ff7575, 0xbbbfdd1a, + 0x39c0764b, 0xd7ffdf76, 0x7f4023a3, 0xc039d2e9, 0x75f2a0ac, 0xd1f61683, + 0x53b4f4cc, 0xcffc251a, 0x47694f7d, 0x46f1c33c, 0x33a40af5, 0xf14e0fc1, + 0x6212e5b8, 0x159fba41, 0xea15bb1d, 0x6e4be5fe, 0x7ce63885, 0xa4ec38e2, + 0xeeecfff0, 0x5e77e889, 0x2fc89c44, 0x1f7479e6, 0x05d3f306, 0x45f594eb, + 0xfd3aca6d, 0x92efd222, 0x73bfd547, 0xf865707f, 0x78d1daf8, 0xd39d27a6, + 0xcfdf6f87, 0x7cbdbfdb, 0x837881be, 0x7c8080f4, 0xd5dfc02d, 0x39021ef3, + 0xd390125c, 0x5d373e42, 0x8f308a8c, 0xb73f7f09, 0xdffafc38, 0xe9a37ce6, + 0x79e515a2, 0xfc04f8e8, 0xd8666a9d, 0xe9b5e04f, 0xc4f12a62, 0x3f42ea07, + 0xc0cb8c0c, 0x2c002a76, 0xf804c69f, 0x0b03f080, 0x2240fe3a, 0xdfb454c6, + 0xac7ae61e, 0x52fc00a5, 0xa7bc801f, 0x278f76f8, 0x12e9faaf, 0x3a97dde7, + 0xa01d9b44, 0x283ef573, 0x07f59c3d, 0xe24fb9f1, 0xae7809cd, 0xf0619186, + 0x73a7415d, 0x0715507e, 0xf72ffef2, 0xeb072657, 0x0e7efd63, 0xa897b33d, + 0x2dc85524, 0xf36b92a2, 0x2b1ca83a, 0x0862bd40, 0xf68f8d30, 0xb93e474d, + 0x80923890, 0x19f77b8e, 0xf81fd132, 0x5899e52d, 0x3ccf14cf, 0x1337d31d, + 0xf0d70e50, 0x64e94fef, 0xe8c68dfa, 0xe2fea1d4, 0x124b7624, 0xee4c989a, + 0xa5a2a152, 0x1d449bf5, 0x47d68788, 0x3048cdf3, 0x26ffae9e, 0xeef9925e, + 0x06573814, 0xec0caef8, 0x65029bc8, 0x1d8748eb, 0x4b9231ca, 0xf0c1d6cb, + 0x67348e3c, 0xd18d7f40, 0x89fd332f, 0xc60920ae, 0xbab1ef8b, 0x4cd7d799, + 0x116730bd, 0xe3326efc, 0x75f3d7f9, 0x7ca0490c, 0x246df60c, 0xc1b7d846, + 0xe31cfbe4, 0x54f4bc4b, 0xf52ed1d8, 0x03f41364, 0x02769344, 0xce9935df, + 0x16b3607b, 0x1ea09162, 0xbbe0b965, 0x337f008f, 0x90c33479, 0x009f5dbf, + 0xade96f7e, 0x28ffc0c5, 0xf3802d3f, 0xeb5db11f, 0xf05e7d43, 0x5f5f1b27, + 0xa94fe72b, 0xfec24054, 0x7e9fce65, 0xfc8c5e6a, 0xf6b88129, 0x14da7f03, + 0x53f9013b, 0x7ae37132, 0x156827e2, 0xa5d1267c, 0x6ad727ac, 0x23c87c55, + 0xdd52fac1, 0xe48ddfca, 0xc907ca14, 0x1cb94ae7, 0x2e4a768f, 0x157423f8, + 0x44f51cec, 0xb4fd78b1, 0x9aceb668, 0xbff31b04, 0xfdb8b145, 0x2101f4d5, + 0x017ad5ff, 0xb5da5629, 0x413d368d, 0xb512553f, 0x7ea187a8, 0xf4c09350, + 0xd03df783, 0x5f21f72e, 0x0bfdc13e, 0xaab82753, 0x77df14b4, 0x4ea391e6, + 0x724b2e5a, 0xba5026d7, 0xb9a47e99, 0x6bd69ea1, 0x3ef922df, 0xb18e165a, + 0xf8a76dd4, 0xecdb3b5d, 0x6beb4d58, 0x3dd48ccd, 0x97d40689, 0xda69c808, + 0x829345be, 0xf02691fe, 0xb47e52c7, 0x4011e216, 0xda098317, 0x593f54d3, + 0xb6e3a46b, 0xd658b7ac, 0xd58fc1db, 0x85fc0e37, 0x65888b7d, 0x3e73092b, + 0x4773d12e, 0xd424fcf1, 0x4e255e29, 0x6df7e26f, 0xab0e7bf0, 0x3b05298f, + 0xe9cbfd90, 0xfc0b0ca4, 0x4f2cb937, 0x5cb3a9a0, 0x39eb4897, 0x4fe81d63, + 0x8c4f9c26, 0xe7e1df10, 0x5ce05470, 0xaf217b60, 0xb87cea0f, 0xcbe6092a, + 0xaeee0e23, 0x58239c0b, 0x50fe85ac, 0xe0f1ccca, 0x09237c73, 0x2af983fc, + 0xde23f303, 0x43b6f2c6, 0x76bc59b3, 0x1fb7d684, 0x5e28f9ce, 0xd332f216, + 0x43be5525, 0xe8c8bfe9, 0x0edbb038, 0xb0c97520, 0x43cb52ef, 0x91fdf0ad, + 0x81e277ae, 0x52368daf, 0xd6cb40fe, 0x92c38732, 0x80d6fb83, 0x2747a9ff, + 0x0e3393e4, 0x11606b73, 0x9cd5fbf4, 0x96d6a696, 0xfb0c5edf, 0xec0992eb, + 0x5c1ca22f, 0xc1359329, 0x8be787f2, 0x09fbfa88, 0x207fbfcc, 0x21379c61, + 0x74f82e28, 0x7283d702, 0x8ff02e49, 0x2cfdf3a0, 0xf9775bd0, 0xbfce919b, + 0xff9f9db2, 0x75c39c3b, 0x3e72efa8, 0x8badf820, 0x274cc5e7, 0xa7c01d4e, + 0x01f28a2b, 0xbe563f5a, 0x34c0f90c, 0xdfdfc6e2, 0xa6f060ab, 0x7cc1d788, + 0xf5282653, 0xca5c3b8d, 0xb55ab4fa, 0x9ebf423e, 0x74eef814, 0x46bdb2b7, + 0x941397e8, 0xeface5fa, 0x9ca2b25f, 0xe1ba7e4d, 0x97f040f2, 0x8225d54f, + 0xe793b0df, 0x184a74bb, 0xf9e26a1f, 0x921d4d2e, 0xa9a5df22, 0x8903de73, + 0x8d2ef941, 0x77cb571d, 0x09c8fa61, 0xf83f779d, 0xa32c4fd5, 0x39dfa63b, + 0x0e22f3c0, 0x51445e42, 0x73ccfe80, 0x52909f98, 0x33d1fa33, 0xd00e312c, + 0x8a69d7ab, 0x2eb8afd0, 0xfff0acd6, 0xace55fae, 0x9fc27e82, 0xa65cf228, + 0x3b734819, 0x641d53f3, 0x8fcc5cf9, 0xb4f6e5e4, 0x7e124137, 0xc7e835e1, + 0xc4df9d52, 0x24f28278, 0xfa2e6671, 0x0b3b6b0b, 0x4b5fc18b, 0xb1fa12e5, + 0x1c7609bd, 0x442eeb5f, 0xa62dd73f, 0x683f18e9, 0x5da2dcea, 0xcfd00a68, + 0xc5dd055f, 0xbba01890, 0x4ed1ff7e, 0xdc8ffa03, 0xa06bebb2, 0xafbd7aaf, + 0x12e92880, 0x77248f7f, 0xebbc7096, 0x17d35c2a, 0x1ef4b851, 0xfec03bd5, + 0xe2058aa3, 0x563dc5eb, 0x1ada83e4, 0x4d7efc82, 0xd97e4139, 0x4ff985bb, + 0xbd2eb33e, 0x9afef815, 0xaa72826a, 0xe10e36c7, 0x0f788cbf, 0xa5b8e93b, + 0x053d299b, 0xb6bbfff1, 0xa4f5eb29, 0xfd78f91d, 0x44ba10f6, 0x56f824be, + 0x3acbb103, 0x52ec6b88, 0x9883278e, 0x7870777c, 0x3abe7217, 0xadb18efc, + 0xae1f6f10, 0x2c85fc61, 0xa0d7a474, 0xf2cb34fd, 0xbab01469, 0xe92ba5a7, + 0x33e6bd47, 0x8cc73b32, 0xf9f0967f, 0x84bd7cd5, 0x6b3745eb, 0x1450a1a9, + 0x7f6873d0, 0x74d41fac, 0xc09a29ca, 0x38f98b3a, 0xbe095fa1, 0x5e55f02a, + 0xa5194846, 0x39139bb3, 0x3649b3be, 0x8fce9be0, 0x46412e74, 0xf7e70d8b, + 0x8a343d80, 0x83d28f7f, 0xa3cae807, 0x7e817a31, 0x28cd4ad7, 0x47a08c4f, + 0xe4bd72d3, 0xf2fafe46, 0xf40c8f52, 0x4f349231, 0xf80b35b9, 0xf00c576c, + 0x15274a1f, 0xfa018989, 0xccbe2569, 0x8e82921d, 0xfadbbdb0, 0x123a5866, + 0x1ef7dffc, 0x11260bd3, 0xefd1bfaa, 0xf4c4ff3a, 0x12d28397, 0xc7aa13a4, + 0xe5fd041d, 0xafb30d4d, 0x406dd226, 0x128b2abf, 0x9453e3ff, 0x10f689f5, + 0x013cc0fa, 0xbd3c3f67, 0xa4cf585a, 0xa73f655c, 0xc9445fe0, 0x25c8b2bf, + 0x743f0766, 0xbfb05ef8, 0x5c925663, 0x8d520788, 0x4c3831cf, 0xf13ea5bc, + 0xd7dbf73b, 0xdbf18627, 0x3db8eaf7, 0xc6b3a2a0, 0x6ce767c3, 0x147a0120, + 0xd246e2e7, 0xf850a72c, 0xf163bf49, 0x0e811b91, 0x19945d29, 0x3be81e49, + 0xc3f998a4, 0x7410f9c4, 0x1b6bca57, 0x240d9d04, 0x6ece8103, 0x7f4288ea, + 0x6f408de8, 0xf90b7e94, 0x0b9e42bc, 0x2cb5bdbd, 0xa4b2be84, 0x39eb941c, + 0xae424f40, 0x8f1c970f, 0x7a0597df, 0xf6f507bb, 0x436a7a20, 0x3d28927a, + 0x4427bfa1, 0x55db2a5e, 0x7ef026f4, 0xe5a3eb9c, 0x85ed19a4, 0x4e4cd1a9, + 0x3d99aafa, 0xd224d94f, 0x8c35ebdb, 0x1388aade, 0x289cade9, 0xa8d2a4e9, + 0x91e9abac, 0xa4a3517e, 0x9bd23737, 0xd1234e9a, 0x37a040db, 0xafe32f21, + 0x137b6f4e, 0xff33ff4d, 0xedbd285a, 0x76b92c4d, 0x6c7c137a, 0xd2a59447, + 0xa97c7204, 0xf8617284, 0x50ad41d1, 0x8590da1f, 0xab0ee7fa, 0x37b600e3, + 0x2ee2f6b3, 0x0ef90ca7, 0x7b782b39, 0xea12ab96, 0x3b692b4d, 0x38e4ba9d, + 0x741887cb, 0x5c2f6b3f, 0x0cc07cdd, 0x1b0f2f7e, 0xb5f3f7bf, 0xf76d2c72, + 0xcbe3e5ae, 0xdea12adb, 0xff8d8eb4, 0xc328e20c, 0xdbca8f20, 0xb75fbf0a, + 0xccc1cb21, 0x8ef7a657, 0x21ddfbe1, 0xe3803ced, 0x25b8d8da, 0x04d18d87, + 0xcfa66ced, 0x39f7ccde, 0x67db3366, 0x4cb747c2, 0xa7bf83b0, 0xd8fa83cf, + 0x52fa9aa7, 0xec1173e4, 0x2da972d4, 0xc0f1ca03, 0xbbc064bf, 0xcd9c9d63, + 0xe95b68e2, 0x644abe27, 0x7f110e7e, 0x75773882, 0x55f37e90, 0x8a13f322, + 0x8236497e, 0xcc7912fa, 0x8888768c, 0x211ef98f, 0xd84f9c12, 0x148b8c23, + 0xd39f1b2f, 0xf8c3fa8c, 0xe64e2281, 0xdfa7ced7, 0xc5fcbc2d, 0x987e70b8, + 0xbd32247f, 0xdb8f0ce5, 0x7a97df8b, 0x077f3c59, 0xc01a4910, 0xd626f755, + 0x2b0844ad, 0xbc03290f, 0x46cc7ab2, 0xa8ebc7e9, 0xd344bf91, 0x7080f5ac, + 0xff3094cb, 0xf1177268, 0xae86c5c5, 0xf896bc7f, 0x087f2cf4, 0x55b8bfd7, + 0x8443f98f, 0x383bb5f3, 0xc1e8c8fe, 0x72a7ce78, 0x7124a53c, 0x19387dbb, + 0x0eea7c0e, 0x8d3bb78e, 0xa7263acd, 0xfe2a74db, 0x7a049191, 0xfa88a6cf, + 0xc55db2b8, 0xeff2965f, 0xf87ae62e, 0xfe87d232, 0x1eb94fc2, 0xd313667e, + 0xed22efc3, 0x7dec2fe8, 0x0d9de98c, 0x2f407b74, 0xbe4abccb, 0xb28cf750, + 0xacaed0de, 0x0eb15237, 0xa87537f3, 0xf31e4ef8, 0x6a6ef6c3, 0xdbff0528, + 0xa28f47d2, 0xe0a977df, 0x9f255e33, 0xc67ee421, 0x1eb91e67, 0x7b6a3ffd, + 0xd4e9d85d, 0x0929be3e, 0x999690e3, 0xcc37a0f5, 0x0f796189, 0xf91f29b2, + 0xf688d982, 0xa0be2472, 0x5e8483b6, 0x7f0fae42, 0x3204a85e, 0xe0823ec2, + 0x5fef82ef, 0xb6525ec1, 0xec23f0ab, 0x3f1c1995, 0xe1fe2853, 0x76127f3b, + 0x9f8632d2, 0x0875c4a9, 0x5ddef3f0, 0x6ec23f0c, 0x9276e6fa, 0x93b60e53, + 0xad75bd84, 0xefda92f6, 0xcf5bce2e, 0xdacf6100, 0x026d9ed1, 0xddfe5340, + 0x13c4f7b0, 0xefd02455, 0x68710b58, 0x72f54175, 0x66b57fa5, 0xc852e9d2, + 0xae88cc9f, 0x46e017b8, 0xffd1133a, 0xec2c90d8, 0x34ff3627, 0xe175cf9e, + 0xdb38accb, 0x29c4fc95, 0x836b86f3, 0x6d5ee3ec, 0x43d82c5f, 0xfc2497bd, + 0x61add42e, 0xf18151e2, 0xe87c710b, 0xf7bebbf7, 0x4f73e067, 0xf13c60c4, + 0x2ecc97c2, 0x2879b0bc, 0xe39f15e6, 0x87015771, 0x799f8725, 0x70e70fd5, + 0x10e182e5, 0xbc93aebf, 0x6da6ed5f, 0x9fee8c23, 0xd3adf9c3, 0xbe8cf4f8, + 0xec445c58, 0xd3dfb23b, 0xff4f7c83, 0x7dbf931a, 0x89e63452, 0x0487dfd2, + 0x273687c7, 0xf081f8b3, 0xf93909c7, 0xe56f5e47, 0xa35a9ef7, 0x3f98fec4, + 0xf3bc52e2, 0x1fff8029, 0x57e0fd61, 0xfc87477a, 0x10e6fc1c, 0x9952a4b7, + 0xd742dba4, 0x6df9f105, 0xdf9f10d7, 0xc5e4c499, 0xb08b4a39, 0xe73645be, + 0x33bdf08b, 0x86790e3c, 0xc4ceb1c7, 0xbed6b8b2, 0x7cacfefe, 0x2267979b, + 0xbf45d1c4, 0xae8c5b8f, 0x3ede9435, 0x35ae216c, 0x1fd83e54, 0xde633431, + 0xafb62ccf, 0xcc563dde, 0xfee31513, 0x0e7e5494, 0xd5acf1d6, 0x85ca1875, + 0x347bca6d, 0xd41fb0bd, 0x7abed837, 0xbe2958a3, 0xeaa4a7f7, 0xdecf8073, + 0x67c47ee9, 0xa8a47d7f, 0xdefe70bb, 0x5fc8fc9b, 0x345bf709, 0x2918f3f0, + 0xf8b5760e, 0x3c8e3a97, 0x1e6f9c5b, 0xa6c59e47, 0x1c79b322, 0xac918e79, + 0x73eda74d, 0xffd1933b, 0x33d634be, 0xf6471144, 0x78a37cc4, 0xdec7a0be, + 0xec388101, 0x0e20df63, 0x3be9397b, 0x4e5ec38f, 0x5587130a, 0x025fe9c7, + 0xc01741bd, 0x0616ddc3, 0xbeb92ab7, 0x17a0fc12, 0x8fcc1216, 0x8fd9242e, + 0xec3d068c, 0x91788e88, 0xfa3d326f, 0x744b786a, 0xe15d8869, 0xf6268ebf, + 0xbaa4fda0, 0x6a3a8a6d, 0x877941e6, 0x14d34be9, 0x673407e3, 0x5c0ffa2b, + 0x3da2bd79, 0xa8a453cb, 0x51bbace7, 0x5b707fd1, 0xf43ea285, 0xfd145bd1, + 0x28d6f3af, 0x7fe017ea, 0xc8c9af90, 0x66786ed7, 0x92fc6286, 0xf52c5e37, + 0x7cb9b6c1, 0x8b72e56e, 0x795d9c78, 0x02fdcca5, 0x9f6fc8fb, 0xf89798af, + 0x0a549f24, 0xeff64971, 0x87bb2c5c, 0xc58bb0b1, 0xdc758607, 0x684ef8a5, + 0xa32ed25c, 0x9121d5de, 0xf8d0a4c7, 0x87ced2e4, 0x8ade42d7, 0xffa17f5a, + 0xa0c5b572, 0x3e6344ef, 0xa99f5aa4, 0xa027364a, 0xd24691de, 0xe9ab5d18, + 0x0f0fd4c2, 0x4851f7b8, 0xba323c86, 0x0a174158, 0xa1f851fc, 0x76c2eb7f, + 0x2d35e633, 0xd2016379, 0x494521a3, 0x25765117, 0x2ae4c45d, 0x50ecc2e9, + 0x995c41d2, 0xf0d40e92, 0x74953ab6, 0xbff4fc41, 0x7e3bc02b, 0xd46e9282, + 0x7d222ef0, 0xd80f3187, 0xdf00392b, 0xeb2f786a, 0xbafb82d8, 0x3cb8be9a, + 0x3917c799, 0x741f877c, 0x6e109ab6, 0xf8493f2c, 0xeedc0c03, 0xbf4a0926, + 0x56abd098, 0x8dbd7325, 0xf2fc23cf, 0xda0f256b, 0xb871fdf1, 0x2fa65f32, + 0x66f9ec0b, 0xae43fcc2, 0xc3139207, 0xf7f117fa, 0x0145fe48, 0xff5ca9d7, + 0xff2c23ac, 0xf31478e6, 0xbd5c7d0b, 0x8b42fd0c, 0xd1ea3349, 0x73c66ae7, + 0xfb07a1ff, 0x0219e1a9, 0x529d353f, 0xf904957d, 0x1aa2ef5f, 0x142726b2, + 0xe4a7529e, 0x533dc333, 0x81e429d2, 0x5013dd9b, 0x84e857fa, 0x12bf3052, + 0x5f98b0fa, 0x31f04fc0, 0xfc01af31, 0x540e7032, 0x2ae48d7c, 0xc7f6a2f1, + 0x963031c0, 0xec5bc706, 0xa33e3824, 0xfc04c3f6, 0x84fed42f, 0xacc0e178, + 0x3a07b856, 0x3f44e2dc, 0x9ae9095f, 0xff0bbf09, 0xae21fa0b, 0x887efd23, + 0x2aea7288, 0x1e29ddf1, 0x5678ffc9, 0xc4575c68, 0x3e182989, 0x3c1d33fa, + 0x800fb25a, 0x1decd475, 0x1474089a, 0x9c7497ea, 0x23ce857c, 0xa1e2fa6b, + 0x2824155f, 0x5f7dc507, 0x9fb8fc97, 0x81f3893b, 0x8dddfbe0, 0x4cdc7da4, + 0xf95307f4, 0xf3250b18, 0xb50e915b, 0x7f45adde, 0x04ee86b1, 0x048ebde8, + 0x02b33bc5, 0x439758ed, 0x479ad7eb, 0xc2c53933, 0x3e5809f3, 0x4ffce128, + 0xed9191d8, 0x16fae535, 0x49661698, 0xc105f7f4, 0x7586b8eb, 0xb8097c8a, + 0x90710a27, 0xd7042981, 0xc76c95d3, 0x4fa21bdf, 0x6e84ebbd, 0xc1995dc5, + 0x9e936e7a, 0xb760361a, 0x716064bf, 0xfea576cd, 0xf4c29d1c, 0xe070c8e0, + 0xbb2a59f9, 0x8f7a6ae6, 0x4aeacfc8, 0xf7d628b6, 0x362b9c60, 0xc06f7e85, + 0x92a7ff49, 0x4abe3026, 0xc43cc6ee, 0xde321d0b, 0x89bc6aa7, 0x3dc687f1, + 0x9ea11e32, 0x17de034e, 0x0071da5e, 0x16eea5f5, 0x7ea880ca, 0x7e85b672, + 0xe015f079, 0x246fdaaf, 0x31e4417b, 0x7ee1490d, 0x10520288, 0xf105079c, + 0xf1b094fd, 0x27fcfeff, 0x93e73b65, 0x1c5e7255, 0xcfeda3dc, 0x65f6d16b, + 0x47e104d6, 0xb8af8fbd, 0x73aa525d, 0x70a14f0d, 0x632ba0fb, 0x2557cc23, + 0x034e1e77, 0x1c90acf8, 0x631b7f10, 0x0d1bf760, 0x734772f2, 0xf4379d90, + 0x7105d95e, 0xee2bd3ce, 0x69fdc1b1, 0x4950ef31, 0xa8f0f783, 0x0ffef185, + 0x36ee218b, 0xd69eb1cb, 0x9d981b66, 0x18bdf599, 0x5f3d0e5f, 0xfbb3d3bf, + 0x66ecba5f, 0x67d057bc, 0x976fd195, 0x40b19320, 0xe2bd6217, 0x1df8a2de, + 0xfe4353ee, 0x4c7df8a6, 0xbbf0df6b, 0xb14a6969, 0x187bde2b, 0xbc37d953, + 0xbb8014d9, 0x4c6ad7c8, 0xfd05afd4, 0xeac8c7a8, 0x7a8b99c4, 0x3b230ae4, + 0x3db8a75f, 0xb0b06a76, 0xe0e67da7, 0x28c6a83c, 0x93e61c67, 0xb01323bd, + 0x38b4bf3b, 0x5fb8ace3, 0xc2c79b0b, 0xf9e1e9e6, 0xabde2bc3, 0xb12d7b40, + 0x531e7c35, 0xbbd30a43, 0x8aca2feb, 0xad7aa63c, 0xea91f30f, 0xbf15ea2f, + 0xe2e1487f, 0xf3ea0431, 0x071a0ccf, 0x1c405beb, 0x82ffa16b, 0x13c43175, + 0x3c8897a4, 0x7c3d3566, 0x68dff1cd, 0x30ed12d5, 0xbaec0fbc, 0xfe57bf52, + 0x5fbd8729, 0x468a48f3, 0x1e61a1e4, 0x3037b531, 0xf7eea79e, 0x7cea29ef, + 0xe7de3f33, 0xdb37cfec, 0x77c57e53, 0x962f1a19, 0x1bc1f22b, 0xd71878e9, + 0x2aac7178, 0x4bcf9c1f, 0x029bb3e7, 0xe0916679, 0x5b3275ff, 0x91e42357, + 0xceff07c5, 0x9df029e8, 0xe6179e04, 0xf8f3858f, 0xf78c876c, 0xa23d9f9d, + 0xcc35b099, 0x5c393bba, 0xe2d44fae, 0x47c1b939, 0x7cc25b9c, 0xf713f45f, + 0x3c7dc419, 0x5576faf5, 0xfac0e7f8, 0x7e658c47, 0x2f3cf561, 0x758af870, + 0x7c31b2ef, 0xf14abe34, 0x2c28f981, 0xcd97774f, 0x83f918bf, 0x4fe78945, + 0x763ad992, 0xc4cfe2dd, 0xcc899cfc, 0x0f448eae, 0x7fdd58f7, 0x9a6e3d45, + 0x48d57209, 0xb259b6a9, 0xabb79d04, 0xee0043d1, 0xa1af02b2, 0xbb63d770, + 0x63f3f798, 0x7e7edcec, 0x61539d8c, 0xa8fe7c0f, 0xf401f98c, 0xa0a49b40, + 0x09cffb3c, 0xde7c0b8b, 0x3ffea126, 0x4ac84ddf, 0x6de677ca, 0xe2fa63ab, + 0x7531c353, 0x9fbf7e07, 0x547997f2, 0xcb4cddde, 0xf1546bf9, 0x08576e61, + 0x8370bc39, 0x1b21deca, 0x3cc64bfe, 0x279466cf, 0x1cae7f8b, 0xa4db74bf, + 0xea7be0cf, 0x4afa3638, 0x71fcfda9, 0x4bcbd70a, 0x83c82949, 0x42fa9fbb, + 0x7c8f6b1f, 0x7e50ce1e, 0xf030683b, 0xdd96235d, 0x2f2c162d, 0x41bb38a6, + 0xdd53e83e, 0x7bd7c0bd, 0xbaf061df, 0xc9817f50, 0x39bcb80b, 0x84b9f812, + 0x9330cef2, 0x841f79c5, 0x2e14ec7b, 0xfb930306, 0x35fddc72, 0x5e957193, + 0x7e118ba4, 0xca2b1ccb, 0xd00a4723, 0xe373c27f, 0x13fc0027, 0xc2718b9f, + 0x7b97d6be, 0xc37f069f, 0xe8d155fa, 0x581a35ff, 0x7b67399c, 0xc0ec06b9, + 0xfb4976eb, 0xd4d1dfc1, 0xde172ab9, 0xa3d93017, 0xae213f31, 0x93165e73, + 0x093bec73, 0x801daead, 0x57b804cf, 0x3eb5d747, 0xf8c29bcb, 0x1a83d338, + 0x257bcc39, 0x3dc07ffb, 0x321bcf6b, 0xa0bc83de, 0xd7fcf965, 0x915f8613, + 0x0edf050f, 0x29baf7d6, 0x40d0c8dc, 0xc976fafd, 0x77c58ba7, 0x515e3024, + 0x3497dabf, 0x6fd1e413, 0xe9ef18b4, 0x52efd75f, 0x23ae202b, 0xc94cd0e4, + 0x5c47fcc2, 0xc44e9d9f, 0xaa17163f, 0x9d3274e5, 0x6333b1eb, 0x13e77c18, + 0x9b8c2647, 0x1ab12461, 0x5666947a, 0xfee097b6, 0xd05674ea, 0x237c4407, + 0xde111eb2, 0xb4f8d3ef, 0x94c7dd99, 0x24c086fa, 0x72a7c167, 0x3a37f385, + 0xc69dc995, 0x4b8fcc21, 0xc4271106, 0x1d5f1ad3, 0x72ec05ba, 0xdb8b3443, + 0x8464be52, 0x810e56f7, 0x5efba6bc, 0x7b144af6, 0xc7dc433f, 0xe10b38b6, + 0x4d53637e, 0xb7de1146, 0xef87d93a, 0xfce8f420, 0x297e7899, 0x4ca891bf, + 0xb6d373bc, 0xce94b55b, 0x3ea8d31b, 0x366beb46, 0x0b55bced, 0xfdb2e4f7, + 0xfeb4358b, 0x58b7a6fc, 0x4ffef5fb, 0xa6f2fea1, 0xc8bdac13, 0xf5a658bf, + 0x613e9b63, 0xa4d060ed, 0x4d97f211, 0xe87ab7dd, 0x5cad67fc, 0xf1f871df, + 0xdee36a1e, 0x7f609aa1, 0x8ca99be2, 0x628d9d5f, 0x9166cefd, 0xef0035b9, + 0x5ffdf0dc, 0x24f0d548, 0xc52c368d, 0x9278c57e, 0x22dc7e12, 0xbf196e3e, + 0x86263a87, 0xf1628bac, 0xc52c4f29, 0xa1cec1c3, 0x989b5f18, 0xf370e36a, + 0x62253be3, 0x314f011e, 0x5deef89f, 0xbe599720, 0x9e706d5a, 0x7f1cddfa, + 0xf06b3bf4, 0xec9c833b, 0x464d66fe, 0xe28fe021, 0xa6f1cb4d, 0x7b89bc05, + 0xb5af30df, 0x70fff900, 0xbc1f5bf0, 0x0567fb44, 0x93a6add6, 0xa7c65496, + 0xb8b2b597, 0x07359f62, 0x0c4c69e9, 0x58a2f77f, 0x1c638fb9, 0x5aa66f0e, + 0x01073df9, 0xbf0964af, 0x98e1cad3, 0x93521fe1, 0xfdf7cdff, 0x77cf5f30, + 0x7c20efbd, 0x8afde139, 0x6dd71d83, 0xb1b1fb65, 0xcf4a54bc, 0x1ef3d436, + 0x7677cc56, 0x197c6a95, 0x5fb0903d, 0x7f8e0e5b, 0x2077bf90, 0x7182f3de, + 0x3f4c0559, 0xdc55bd05, 0x9b9e27d3, 0xb4ffb049, 0x3b7e3eff, 0xd81b37bb, + 0x7cc5ade7, 0x4fbe169f, 0x57a7db0b, 0x78e4af41, 0x7354e65f, 0xc3f71d28, + 0xbcbe7fbf, 0xe29f3e22, 0x0f9b879c, 0xbc2475ce, 0xf1aefc1c, 0x82a9d622, + 0x559c3f67, 0x84f013eb, 0xf2e38df3, 0xd6297494, 0xf3a472f9, 0xbf2df59d, + 0x35c6ce57, 0xf7e580fc, 0xae92bb12, 0x6965761b, 0xc62e7e20, 0x2ecf03e5, + 0x3ebdf809, 0x6076e54b, 0x9088c906, 0x352e778f, 0x7f0cbfbc, 0xbd81db57, + 0xacef9656, 0x26f407f6, 0x109cba3a, 0xeecf3a47, 0xf9528f6f, 0xb29e202f, + 0x171814d3, 0xfaca2f90, 0xbf0634c8, 0x1f4bff50, 0x362d2fde, 0x7768bc54, + 0x31eebb50, 0xbfc06dcd, 0xee2ae38b, 0x98f5a2c9, 0xc06ddd34, 0x2bd38bbf, + 0xfca2c8be, 0x67a69cdc, 0xbe2a1bf5, 0x63fa86c8, 0x8c7fd67a, 0xf7e045f3, + 0x6dbfa3c4, 0x8f406a6c, 0xb3b34d88, 0x1a9553fb, 0x5fabff7c, 0x019df97f, + 0xd70117f5, 0x41b16548, 0x4e2e1cd3, 0xe8269c95, 0xca13c581, 0x90ed7fe0, + 0x7cedc4f7, 0xe76156bf, 0xfbb2c6f7, 0xfefbbdb7, 0xb227f786, 0x6919dcd3, + 0x314d5d74, 0x68b273dd, 0xfbcc757d, 0x9c92af18, 0x3f010f54, 0x6642dd87, + 0xdd4af5d1, 0x2fa05deb, 0x461cbb91, 0xfb95c22d, 0x314de07d, 0x5e57bf0a, + 0xe97dcdfd, 0x582e33ec, 0x07ce48c7, 0xfafd5e9a, 0x3673882b, 0xc039359d, + 0x73b23e2d, 0x6fa03dd3, 0xf37cec8d, 0xd987266b, 0xeeb10f7d, 0xa3d7e091, + 0x187597bf, 0x3b23fd70, 0xfd045baf, 0x33a1fd47, 0xa6e4e807, 0x6056be53, + 0x5efbbd0b, 0x1fde574e, 0x798aecfd, 0x4de3118c, 0xe89f1e02, 0x1499e809, + 0x7833371e, 0xab7cc25c, 0x6b63c49e, 0x2b97a8fd, 0xbd50d3ef, 0x17a6e31d, + 0xfc03b448, 0xb35ee2f8, 0xb2785fda, 0xfe8fee9a, 0x5d1f537e, 0x3cde9041, + 0x3291a2e6, 0x9cbd4092, 0x4af51558, 0x7fa2aa63, 0xd14b2595, 0x3ae53e3e, + 0x7b44fb45, 0x293ea2a1, 0xffa2a477, 0x45728e6d, 0x89b2f6fd, 0xced5fe8a, + 0xd0bd456a, 0x3fe8aed7, 0xb28748fc, 0x019138fd, 0x1d27450f, 0xf92ca007, + 0xc76e89d8, 0x07cd33d2, 0x25f91ca0, 0x5fda8703, 0xf6c5e37a, 0xf0bbf003, + 0xc7efaa97, 0x34e9ff08, 0x87d5e4d9, 0x68a693f7, 0xf25e7969, 0x35913f23, + 0x2d8c7eec, 0xe02f7dd6, 0x198fdc4d, 0x8a52fe03, 0xe7b9aa84, 0x59f0bdd9, + 0x12765fcc, 0x69fc0310, 0x7cfd19ba, 0xcfcd7527, 0xbdc599ff, 0xbbdf0007, + 0xb156afa9, 0xdd1731ef, 0x93977d8a, 0x2d3c2a65, 0x2cabd457, 0x1ff4503f, + 0xd14ab29f, 0x90fed13e, 0x2b0f4f0a, 0x3639b7ea, 0x45b4f0a9, 0x28dfa785, + 0x70edfbda, 0x157abfee, 0x1cb44efc, 0x04aaefed, 0xa67cdc3c, 0xd651f10f, + 0x780956d5, 0x3b64f1ba, 0xe7d8abe2, 0x597604aa, 0x00f9a47a, 0x7f6a3e94, + 0x5ad7b8c1, 0xd83cb052, 0xd5ff4762, 0x2c5c96e1, 0xf038b48f, 0x94b7dff7, + 0x8b56f961, 0x6cffcb13, 0x57658099, 0xf6cb0b8b, 0xbfec7696, 0xf983a5b3, + 0xdffbe2bf, 0x7e001815, 0xbf8d1e81, 0x3c56ee11, 0xe434d8f7, 0xfed13d9f, + 0x26afa81e, 0x9636de77, 0x81e78d32, 0xcc9d8089, 0xcee9a3cb, 0xbf94e9d1, + 0xac1c85ed, 0x41fe4092, 0x0859c6bb, 0xb4e1f87a, 0x0ed13f05, 0x5581e420, + 0x958b14ae, 0x8eb48dd5, 0x643186c8, 0x199c4fc1, 0x25105e74, 0x70584c18, + 0xa37bd41b, 0xb4defb58, 0xf279b705, 0x637107fe, 0xe17e4867, 0x7130b4e1, + 0xd8cfe7e3, 0x39cfe0cd, 0x19a86976, 0xfb8c71e0, 0x50a49cb5, 0xe5968f37, + 0xc81d42da, 0xbd2a93d9, 0xe4539444, 0xde61b7f2, 0x0ee38d76, 0x45be6fcc, + 0x6b7e8047, 0x8aef6624, 0x99d3db7e, 0x9b7bd0bd, 0xe3a9ed01, 0xbc22e71a, + 0x3df52717, 0x49ee7001, 0xa9ca3efb, 0x265f735e, 0xed3bafc0, 0xd89eac7b, + 0x08e484f7, 0x7c18ebaa, 0xf7bb4fde, 0xd9cf86bb, 0xf85092b4, 0x5859a6f4, + 0x1ce7c0dc, 0xaf007a80, 0x3676af1f, 0xdcac9c60, 0x71f61839, 0xe76065cc, + 0xfbc665d7, 0x2ceb4413, 0xbfc823b9, 0xc3ae9753, 0xa2e15371, 0x6739f81b, + 0xd5ce78c8, 0x9d287cf0, 0x27481fd9, 0x8f4e6760, 0xb8e0bb41, 0x5737dd86, + 0x9d267ff7, 0x1173d9c9, 0x0dfd83de, 0x94c57b87, 0xd377e786, 0x44577af9, + 0xaebdd4e1, 0xf58fa8a1, 0x9f784b36, 0xf34cf7b7, 0x706ed679, 0xdc609070, + 0x1ffc2672, 0xf3be7f6d, 0x91febf9e, 0x457f7ff6, 0x8865038c, 0xdf847ae5, + 0x7679de0c, 0xa7f511bc, 0x2a0335d9, 0xe4ce2e40, 0x6639b071, 0xc386126d, + 0x3c3d56b4, 0x54d0b89d, 0x904296b8, 0xd6a84e2c, 0x4b4553c3, 0x85af9633, + 0x0f41aef2, 0x9f09e1eb, 0x6b1dbcfa, 0xa06d8d41, 0xf904b847, 0x0b68ff9f, + 0x95dcd75d, 0x73d99db2, 0xeb3aae5c, 0x871e51be, 0x3ce3dfa0, 0x010286af, + 0xd367d5ed, 0xfb7f8525, 0x61af0e59, 0xcc7f5ce9, 0x1eecf927, 0x609c7f51, + 0xeefb9c38, 0x448747d9, 0xdb282388, 0x2ef8feb9, 0xfd56e77f, 0xeef883ee, + 0xc7ef1c73, 0x413294f5, 0xe4c19c9f, 0x17ed4140, 0xfee84bab, 0x1a2d3a0b, + 0x6dcfd38c, 0xb8780dd8, 0xa8f1c1d0, 0x9e701d23, 0xbde678a6, 0xaa4d398f, + 0x9357a17b, 0x4b2e8e97, 0x2cbcb065, 0x832abbf6, 0x5f5965e5, 0x45c8255b, + 0x2d7d1f21, 0x6e3f394b, 0xb07a3e46, 0x0fd62565, 0x3cb078b7, 0xf38eb2d2, + 0x7f6c36e3, 0xce51e5ab, 0x1f9cbd8f, 0x77bf833f, 0xf962d4b6, 0xcb1b8b6a, + 0x33dce307, 0x3e226e00, 0xc6e8d539, 0x9b43d1bc, 0x5fe2040c, 0x980d3a17, + 0xc44f4097, 0x40278f13, 0xef018dde, 0x6ff3a9f5, 0x9fbe7cd4, 0xb7df421e, + 0x189e9c58, 0xfa033794, 0xf4c8c0e2, 0xcdd88c74, 0xedfe97c0, 0x0f9057f1, + 0xcddbb31d, 0xa4b74fa0, 0x38bca277, 0x759bb4e6, 0xbc79eeb4, 0xedbbb593, + 0xafad0366, 0xdac7df4a, 0x1473763d, 0x7c7eafad, 0x12f76b1f, 0xf83f220c, + 0xc7c86bf8, 0x107489ca, 0x31a547ce, 0x17152c6b, 0x1f975e54, 0x3e317384, + 0x3858de65, 0x3d725f17, 0xd57da27d, 0xca4fa841, 0xab85a2dd, 0xe1534edf, + 0x9157181a, 0x7185ad50, 0xaf963363, 0x06e37181, 0x1e0dac3d, 0xc76f2137, + 0xeadfa81a, 0xfd05a2d8, 0xc7ce4bf4, 0x2ea23cc4, 0x169f05da, 0x3ac360f9, + 0x0a0f285d, 0x0f285c3a, 0xa62a5c04, 0x7e003f56, 0xc90ea6c7, 0xa63ac122, + 0x71c1fd4a, 0x846ba5c8, 0xbf2922f7, 0x8efe98de, 0xd71d1579, 0xb11bf504, + 0xa65593fe, 0x6f7f94ef, 0xdf230f4d, 0x0ef3f04e, 0xbbf21ef2, 0x3bd9e84f, + 0x5c035f1d, 0x9b9ef04a, 0x24b5df19, 0xe3fa336e, 0x3d833641, 0xb69e7204, + 0x1965e70f, 0x6453fb97, 0xcef876e7, 0xc3f9918b, 0xabfcfccb, 0x68444dee, + 0x4f61fce7, 0x4bd985ba, 0x06875dfc, 0xd07e86d2, 0xa997e5ab, 0xf9d5a1f3, + 0x59ff2216, 0x4f515f9d, 0xa1307bd8, 0xdeecce79, 0xb39e486e, 0x19a2abb0, + 0x5e05ad3f, 0x78f8e943, 0x0957cf3a, 0xabc9c385, 0x3864e1c0, 0x87ec8438, + 0x2eef3178, 0x74c6ff24, 0xdeacf11c, 0xb2277117, 0x3f8936f7, 0x5d04feec, + 0x8dafee84, 0xe0cb5fc1, 0xb3bbf54f, 0xb9aae780, 0xab7e0266, 0xc7f3fe60, + 0x351ff02b, 0xf8aefb5f, 0x0db9b4e5, 0x5080fdec, 0x1c39763e, 0xc2f7131f, + 0x53d0a5d5, 0xe41a3ee1, 0x343bc201, 0x4befe760, 0x80674776, 0xf7d1567e, + 0xd0ec0695, 0xf37ef604, 0x9cdb9b22, 0xe922e141, 0xc8817e59, 0xf1a33dc3, + 0xb6f416fc, 0xc9e6cdb4, 0xb0832fa8, 0x4ac767a0, 0x7e3fe0eb, 0x878aead6, + 0xafd72471, 0x3a077e0f, 0x7a699e52, 0xa17f9306, 0x5fe45125, 0xfaf96ef6, + 0x8a2fde9a, 0x792a8f04, 0x41ee1fb4, 0x418b285c, 0x112dd9f9, 0xdb3fbc1f, + 0x7a849e5d, 0xbd00f74b, 0xdaefca16, 0x301eee2e, 0xdb57e704, 0x65a9ddc7, + 0x71ddf646, 0xd0eca013, 0x079d1fbb, 0x0691e0fe, 0xcdbc938c, 0xc7270ff3, + 0xb7c3fcb0, 0xc980fdf9, 0x004a5e1f, 0xf65938f9, 0xa1481525, 0x1bf77676, + 0x05ec2ab3, 0xdd36f6a1, 0xefd858ef, 0x976eecd5, 0x6006cbb1, 0xf5dfdb55, + 0x9022bf2b, 0xe56a3de7, 0xe3f90225, 0xbc7b73ff, 0xa4f5132b, 0x9533e4ab, + 0x415b79f5, 0x897318ff, 0x228e39e5, 0x9525ce2c, 0x9bf2c9bd, 0xdbb6a978, + 0xbda868e7, 0xa76a1d9e, 0xa5fd92cf, 0xd421ef50, 0xd809cf5e, 0x374ec2eb, + 0x45bf9610, 0x3806f7ed, 0xddb9e717, 0x8f13314e, 0x7c3f2179, 0xc87dce6f, + 0x9f30a217, 0x8f8ef9e3, 0x7fad6112, 0xc5fc4ae9, 0xbd00f62b, 0x22be5937, + 0xf5fa79c1, 0xc120bf2b, 0x7375bcef, 0x8e9b773f, 0xffaa43dd, 0x8a728ca7, + 0x8075b5ca, 0x9af27aa7, 0x7920eefe, 0xabffda4b, 0x28c3de1f, 0x3586abff, + 0xb4f5bc81, 0x7ed2764c, 0x223edcd5, 0xac76f91e, 0x32927b73, 0x289ed646, + 0xeacbbffa, 0x13ff4403, 0xbbf49d93, 0x9da2a9d5, 0xd78ebf8f, 0x6c76ee89, + 0x0df312cf, 0x6b337565, 0x72f8cb6f, 0x8231e832, 0xe0cc6fbf, 0x47bf91f2, + 0x63fdf944, 0xcc578919, 0x73b651bf, 0x1fde2079, 0xc4e1faaa, 0x6e70a398, + 0xb5cc25db, 0x875fbfab, 0xb673fbfe, 0xf7e082f6, 0x8e9e454a, 0x798cd2ab, + 0x0d2f0d53, 0x22740add, 0x81278f9b, 0xe3c5d2de, 0x09b255f1, 0x36172ee3, + 0x491ebe30, 0xf2bc5bef, 0x42be0515, 0xc0fbf9da, 0xdfa49818, 0x6493ff3b, + 0xa0f33ef6, 0xe80bcc2e, 0xde0c7ce0, 0xc37b847b, 0x212bff22, 0x5ec13887, + 0x8a39784e, 0x71f953bd, 0xc5dbf217, 0x767f332f, 0x2803a6c3, 0x76cbe6df, + 0xc89d27f4, 0xf00abf76, 0x0d7731e9, 0xcaf838c1, 0x3f5d7157, 0xdc785bb2, + 0x182f2fab, 0xe143879e, 0xc0abfbff, 0x4afff7ff, 0xfc82eff8, 0xbb73e032, + 0x4dbed0a3, 0x0ef5fad6, 0x649e6b88, 0xe79e5cef, 0xfaed2b70, 0xf815df10, + 0xd3b30667, 0xdc583ae2, 0x8965e446, 0xc333feef, 0x1e74eccc, 0x79a8691f, + 0x47c4346b, 0xc4c6fe04, 0x77f07690, 0x38383c53, 0x07801c1e, 0x9c40ef01, + 0x0acb8e84, 0xb0aed79e, 0x23dc050f, 0x7d35639d, 0xe3ab7588, 0x0e997706, + 0xef7e0096, 0x847986fa, 0xb0b4cfdf, 0xcc7eb4f9, 0xf011fc13, 0x1e00c4ca, + 0xef940375, 0x46bc5180, 0x22b9280d, 0xffed95de, 0xc35778cb, 0xf3d65d4d, + 0xf7fa9838, 0xff3403a1, 0xbffc70ab, 0xdd9d5fe6, 0x3ed15fbc, 0xd71be577, + 0x7e157fe4, 0x1f957fd1, 0xf5ff9236, 0x16ee992f, 0x2fc9bba0, 0xfc40d12e, + 0xffbdf6e6, 0x8b013bc8, 0x5e303bf7, 0xcbdf0f74, 0xf6ffa317, 0x9e947dfe, + 0x7e6668be, 0x3ffb53a9, 0x43f3d9d7, 0x45f663e9, 0xe8833899, 0x77caf66a, + 0x669f2074, 0x5c22cd53, 0xa70d6a7c, 0xa127cc27, 0x48d6a07c, 0xfcf40974, + 0xf7b2d6d7, 0x10216ba5, 0xe7d2c363, 0xb593eda6, 0xc7ef07c4, 0x3eb49b56, + 0x9487c603, 0xfc0d61f7, 0x686a597d, 0xcac5ee2a, 0x9ef3194e, 0x716328ee, + 0x76a619a5, 0xfd38dfbc, 0xf7f3eac8, 0xe35dd9c1, 0xba796129, 0x9fd27ee2, + 0x5e24df34, 0x37e406b4, 0x1e259ff8, 0xc3ae5c87, 0x5c7aa438, 0xfe7600ed, + 0xcb12cb26, 0xf2c3d837, 0xa479c4d7, 0x28623bfb, 0xf0f37962, 0xb3756ace, + 0x00b437ce, 0xa8fd8ff4, 0xad95347f, 0x353c002a, 0x303e958d, 0xc0f40414, + 0xa25f95a6, 0xc7e6a37e, 0xfd5af2ea, 0x1cb7ef50, 0xfa117a41, 0x1f16a9e2, + 0xa97ed5d6, 0x8c7e6359, 0x5f919c71, 0xd470bd32, 0x1189e725, 0x6f6f6ff6, + 0xd84b3b09, 0x4e3b6a5d, 0x5ef10bf0, 0x0b00fb5c, 0x77c6bb93, 0x5a8ffbd8, + 0x4034be56, 0x5f057729, 0xef767ca5, 0x4a5fe400, 0x87c41bfe, 0xc55ffdb1, + 0xdf740387, 0x4dff00ec, 0x6f7b066d, 0xf5f74d5d, 0xaa7e4c29, 0x94ae5de9, + 0xd3519f51, 0x3bf3a0bb, 0x7fd05b9d, 0xd2c60b37, 0x926acc75, 0xc9d59ef0, + 0xd7bc1e97, 0xddd09748, 0xe29d33fe, 0x486fbc3d, 0xe072a1f7, 0xbe23b463, + 0x5d201cb5, 0x33feecd1, 0xa84f47c3, 0xc0a0bd1c, 0xbd1ca84f, 0x5fc4aff0, + 0xf9cffd98, 0xf0907276, 0xc8bb7f3c, 0x6b239ff3, 0x26dcf7d8, 0x790a0796, + 0x765ebd68, 0x56696c2f, 0x4d7fbe1b, 0xe058b20d, 0xc9f6cb23, 0x778b3d64, + 0xde835368, 0xbe26ea2b, 0xe0494777, 0x9bf9624f, 0xf7b3464b, 0x9a79d43e, + 0x91b3ff22, 0xb4cbbb8f, 0x54788f4b, 0xe62443bd, 0xd443bf51, 0x67fc7a38, + 0xf7e7ff18, 0x0fefd58b, 0xf9e4ca0d, 0x88a4459f, 0xccafc7c5, 0x5e407aa7, + 0x7b8df906, 0xbda0b52e, 0xf4399793, 0x01193c3f, 0x8665177c, 0x99a5d7e8, + 0x94b3d657, 0xfa62ffed, 0xf0dbcd90, 0x4a6f913d, 0xe72c861f, 0x38b75824, + 0xf9e7fd27, 0x679e0315, 0xef713ef1, 0xbdf1e7f2, 0x09afde8f, 0xe6ae87c6, + 0xcdd3199f, 0xf4dd03ae, 0x4cd5b7b1, 0x94ea3ef1, 0x2304fd07, 0xdef1bb8f, + 0x9cb788dc, 0x0a4c8190, 0x5864ba0f, 0x841bd0b7, 0x0be0111e, 0xcf0b7efc, + 0xfe56b8f7, 0xdc4bfff1, 0xe9b3dc43, 0x4e4af9d1, 0x13defc80, 0xef1df615, + 0x2b9a99d5, 0x60f9ffbe, 0xe0357b9c, 0xbfe70a69, 0x2ad01de2, 0x7bdbbd99, + 0x3f464ba1, 0xfd1f8ac5, 0xdb8fb7e1, 0xeb57e743, 0x2f964d67, 0xd247ae50, + 0x2c349bd7, 0xd2a8beaf, 0x605af98e, 0x42df80ff, 0xfdd431f8, 0x7e2bd90f, + 0xf776899e, 0xac272ee8, 0x9eb651e7, 0x5a6af848, 0xbf0a5ff9, 0x37efa449, + 0xccb12bed, 0x7f1f3a0f, 0xfd0494cc, 0x06353e5b, 0x74ad7df0, 0x0ecd7ff1, + 0x8f132c98, 0xbe70e544, 0x257a65e4, 0x2ce5fa61, 0x1ce585d2, 0x9ba587d2, + 0xf9eabcb0, 0x42e581c4, 0x65d3cf7e, 0x0991bf77, 0x1f5d55fe, 0xfe7b53be, + 0xe1e7bfa5, 0x8f37503b, 0xa95c836a, 0xad9fcaef, 0x0b7aafd6, 0x0d38fefb, + 0xbfeec7f8, 0x0f51da67, 0xb377b6b8, 0xd3ce71bd, 0xddfc6199, 0xb32e59ff, + 0xee97157b, 0x5a4def65, 0x363218d8, 0x2574fb11, 0x09f9e167, 0x2de4cdf0, + 0x5c426f82, 0x0d03ff2b, 0x932fcb8b, 0x7505eff0, 0xc47835f8, 0x796517f2, + 0x62efa865, 0x560df9ed, 0x717904af, 0xfb58a323, 0x5dfe2b72, 0x8fc4d9cf, + 0x3c2e72e7, 0x3dc32b65, 0x0b963b09, 0x54d4fbf8, 0xe896cee3, 0x469d45f8, + 0xfc4dcf96, 0x05bf6083, 0xb1849f60, 0xf206cb77, 0xe3367438, 0x542ac3f7, + 0x0fce05fe, 0x3315ec1a, 0xe172d206, 0x48192740, 0xad987ee9, 0x20cffd6b, + 0x86b7606f, 0xcfafbdc0, 0xe300fe46, 0x2fdc622b, 0xe83a15ec, 0xf2c482f7, + 0x0cfb3d8e, 0xa4d4bde2, 0xcbbd3f60, 0xfd03195e, 0xa8b6146c, 0x2b80451f, + 0x572abdfc, 0xe44c7b18, 0x1d030db1, 0x0485fd11, 0x417a25df, 0x819cf562, + 0x4d7dbe3f, 0x3d30fa1e, 0xc2fe87a0, 0x7d80ceee, 0x6213d30c, 0x92fff582, + 0xcd21afdf, 0x5f0f1099, 0x034184f2, 0x547bc67a, 0x833dc31c, 0x167b533f, + 0x2ed4d3ca, 0xd42ff285, 0x03f2852e, 0xf942976a, 0xa14bb511, 0x10b1745c, + 0xbe2224de, 0xd862ce81, 0xa83b888f, 0x903f9bd7, 0xbb06cdc9, 0x1d62867b, + 0x8eb8f4fb, 0x3f5dac17, 0xc75d19fd, 0x6907bb0b, 0x244bbee0, 0xfbeef478, + 0xfe95e65b, 0x7f888d3e, 0xf107dba8, 0xd2ec17ef, 0xe82fdca2, 0x0e2ec7f0, + 0x503157ea, 0x77f3e38f, 0xf30b1c7f, 0xe1fa58f7, 0x56e894ea, 0xbd586b27, + 0x845e57e2, 0x39dd836b, 0xcf4bf603, 0x4fd838f7, 0x7e1fc741, 0xe83af70a, + 0xeda718fc, 0x8236fa95, 0x87dea67e, 0x5f62df7a, 0x61ebff74, 0xb3bb0bfc, + 0xdf942761, 0xf65e7610, 0x437977b1, 0xf70abbf7, 0xafa1bb73, 0xdc2bee18, + 0x9b0e597e, 0x2f60da27, 0xc57f7847, 0x38fed0f5, 0x812ba71c, 0xae7b6faf, + 0xf111f3d5, 0x50f001ee, 0x4ba3c83b, 0x560fa0b1, 0xc76678f3, 0xe36f41ae, + 0x322397fd, 0x385fbf81, 0x773ca6cc, 0x1278e13f, 0xbd3efe65, 0xc2f5f00b, + 0xc1074fbe, 0x3f14a07b, 0xc9efe083, 0x60e068fe, 0xfe7dfe45, 0x031fafc8, + 0xf1fda1fa, 0x274e15ef, 0x6e20aa5b, 0xffb8d33f, 0xb6696c10, 0x882a83e5, + 0x914dcfdb, 0xcf39430e, 0xe20e359e, 0x79df22f5, 0x61f96e41, 0x3ab74a38, + 0x2b8f51aa, 0x2412e607, 0x318d2a17, 0x216051fc, 0xf515e287, 0x8ae929f1, + 0x39ed13fe, 0xb949f68a, 0xfbda2837, 0x8638a1ef, 0x06cf7e07, 0x4365f478, + 0x83ee8d1c, 0xa7b57dfd, 0xca77cc64, 0x96fc7ddf, 0xf27d681b, 0x7be077d3, + 0xf6f02f6f, 0xf12b3bc9, 0x52f59bef, 0x22a9ea78, 0xa1eca675, 0xc9833f8d, + 0xfd42f654, 0xc30f27be, 0xd8dfd0bb, 0x2760885e, 0x97a611d4, 0xd417b246, + 0x9be50276, 0x39be053f, 0x16a9a5ec, 0x617f0fc8, 0x2069d7e4, 0xe40fb697, + 0xfb7066ef, 0xf4fd1221, 0xfec9139f, 0x29fdf076, 0xbf88fd35, 0xc9ca2d6f, + 0xa13dd8c7, 0x3ed7ca6f, 0x7686be01, 0xafdb87b9, 0xcff954bc, 0x6f1de986, + 0x9efe03df, 0x94dc32a3, 0xb5bfbfe8, 0x0e5ffe18, 0xb8593dd0, 0x04d481e5, + 0xfa03ddfc, 0xa7f72370, 0xeb90367d, 0x1ffbf553, 0xb40e2d48, 0x281f1593, + 0xa5fb93fa, 0x9afa8ab5, 0x437d652c, 0xf1e0daf9, 0xc5b1f491, 0xbbd3ce8f, + 0x9f9ee1f3, 0x3aeff614, 0x8127aff6, 0x4b7d87f3, 0xba7edf90, 0xbdfe197f, + 0x46ff7559, 0x01f81f3a, 0xb3904717, 0x974d4f82, 0xeac23bd9, 0xef8abff6, + 0xefdbbe39, 0x8f6147bd, 0x332f5e79, 0x9c5efbf9, 0x13a0af5b, 0xf9eefb3b, + 0xe8ff0f4d, 0xed2b882b, 0x79d57661, 0x051f932b, 0xc0d33ebb, 0x161e8bdf, + 0xc0abe8cd, 0x3dc0d7e2, 0x7e06ff9a, 0x00334c2b, 0x0000334c, 0x00088b1f, + 0x00000000, 0x18adff00, 0xf514707b, 0x7bdbdbf9, 0x79724b92, 0x71211240, + 0xc220572f, 0x4849ac91, 0x92ea4903, 0xf03ea410, 0xa2a21900, 0x799e0fae, + 0x2a93a84a, 0x028d361d, 0xd6d36d52, 0x4f4e2a2a, 0xd1954a2c, 0x2562bc34, + 0x40569478, 0x2f2a7b1d, 0x419cca69, 0xee421923, 0x8cc38a8c, 0xbf7dfa1d, + 0x5eddcddd, 0xc9a75502, 0xf6fbbf1f, 0xcfdef8f7, 0x05048af0, 0x571a0192, + 0x02a62a26, 0xc8dc8280, 0x00b5fb71, 0xbb4c6176, 0x94e00b3d, 0x157004c9, + 0xa5029fd0, 0x30276100, 0xf0efdd38, 0xbdbf423d, 0x225f1c91, 0x9e5eef7e, + 0x77dc2323, 0x4055a560, 0x5dfd12f8, 0x361b5d17, 0x709563df, 0xd480197f, + 0x0fb91ce1, 0x1d300ad0, 0xe7f015df, 0x32a3a458, 0xe784db92, 0xf716faee, + 0x2412fc55, 0x828f9d20, 0x76048f4e, 0x15798f80, 0x0624279e, 0x8df3c49f, + 0x22b07847, 0x3810033f, 0x8ec7077e, 0x004ab339, 0x814fd396, 0x815877be, + 0xc005bf67, 0xefb42bef, 0xdf97cbcb, 0x6f084904, 0xf286f4b1, 0x4970fbd8, + 0x90e30343, 0xaadced7e, 0x9d5bb7bf, 0x78c9feb4, 0xff1e01ae, 0xb5fbc782, + 0xd7ef6410, 0x7b7dc0ed, 0xf5f97ecc, 0x0dfbd39f, 0x0af78cbb, 0xbef4c485, + 0x0a03f4a9, 0xb3ecf12f, 0xb6adf089, 0xf9aaf8ab, 0xb1bc3f6f, 0x837af918, + 0x69f86d17, 0x64c4df68, 0xd98fe2f0, 0x91aca428, 0x8cdc6c72, 0xe145a48f, + 0x5cfc7dc1, 0x47379d3f, 0x1b4fe672, 0x44906f29, 0xb561c913, 0xbab7c54b, + 0x80059be2, 0x9b7756f8, 0xe02bb801, 0x1083c8d9, 0xdba0a783, 0xa33bf3e6, + 0x2a5d87f4, 0x5fdd058f, 0xaaf2cea7, 0x01d12b6b, 0x405e2aed, 0xa67a41bb, + 0x47496071, 0x139f307c, 0xac72e1b7, 0xe492a33b, 0x80838c74, 0xb89ec850, + 0x2df48ed5, 0xefa39f54, 0x1fc5484e, 0xc2667999, 0xcbd340b3, 0x2f77d2c2, + 0x516f7872, 0x4889a2f7, 0x75df1c01, 0x1cd431ef, 0x0c3c152c, 0x2c5062df, + 0x296397a4, 0xa466ecbe, 0xddcf1e73, 0x1c12f3ed, 0xff10e019, 0xae048ab1, + 0x3fef638d, 0x7cebef42, 0xb2f8b31d, 0xb35f189b, 0x37a87d5d, 0x5fc29a4e, + 0x8f29184a, 0xd0cd5ca8, 0x5797eba7, 0x59ec86dd, 0xd7e6afdf, 0x1d31bace, + 0x5c04b8f5, 0x16fba436, 0x610c0d1e, 0xdfe6cb78, 0xe03126e6, 0x5f2819ef, + 0xf44a982e, 0x2d0584fa, 0x68cfde02, 0xd39835f9, 0x5667e462, 0x8fd74efd, + 0xf491cf2e, 0xf9abf8a8, 0x7c84a0f2, 0x98e76d0e, 0xaa88351d, 0x9f94369d, + 0xc462c3fb, 0x45e410df, 0xefa9e90e, 0xe492703a, 0x03aeb1d8, 0xce8016cc, + 0xad6c5d75, 0x7c033bb7, 0xd98fe33e, 0x838d09af, 0xc1a55bf8, 0x74775f8c, + 0x1c7fca3f, 0x3032cbbc, 0xf802e70c, 0x13bf7d93, 0xbf359f90, 0x62d8f2f8, + 0x794376a2, 0xb207f30a, 0xf4a3abb9, 0x9c015817, 0x5b647f48, 0xc32b7f82, + 0xa27eaa23, 0xfeff6dd9, 0x719a2749, 0x0b1dffbf, 0x1583db33, 0x1cfe0f4f, + 0x12db35e1, 0x53fb9c98, 0xfda2c941, 0x0afd93ad, 0x8a6e581e, 0xdc9334f4, + 0x6dc5133b, 0xf3f9ffb8, 0x81dd5f93, 0x2757caf0, 0xf926448a, 0xdf845091, + 0xefa011b3, 0x3dd8b33b, 0xcbbc5590, 0x5fe4ff34, 0x729bf69e, 0x4d397fda, + 0xfeba3c24, 0x90ef3ece, 0x35f5e500, 0x685df204, 0xa538e782, 0xd70f84cf, + 0xe69c769a, 0x36ad3ed0, 0x75e92779, 0x397fb3d5, 0x54fc865e, 0xd3f37cbd, + 0x95be9033, 0x7a058d1f, 0x11d7aa27, 0xe42920f1, 0x51e038a5, 0x9f2680e3, + 0xff0eedda, 0xa57131a7, 0x00c523be, 0xf9657637, 0x47898d3f, 0x18caa0b5, + 0x1f98e7ee, 0x35fe69d5, 0x20df978d, 0x4843d47d, 0xb110938d, 0xf2155d92, + 0x2171449c, 0xc98d84f2, 0x3ecede3f, 0x2ecc4c10, 0x53204ceb, 0x034c2f7c, + 0xaff9267b, 0xfc2fcaac, 0x9bade4c4, 0x42fd3650, 0x93ffeeaa, 0xb58b4c16, + 0x37869ecf, 0xdb373ec9, 0x380e7d98, 0x3c67f980, 0x290b7f9e, 0xfb32fcec, + 0x861fcc57, 0x45cb4bf3, 0xc0c51730, 0xee28905e, 0x4509b615, 0xacdae00f, + 0x964a65e9, 0xadfc442f, 0x9eedf8ea, 0xb73c98f7, 0xf08a783c, 0xfd32761e, + 0xdcaa7bc1, 0xc4d41cc3, 0xf665a9e6, 0x7bff342f, 0x7dcfe0c1, 0x97c89ccf, + 0xddbefdf1, 0xed01f353, 0xd83e5ef9, 0x67ca1cf7, 0xfa783130, 0x0f3b5c61, + 0xf28e387f, 0x75bd3c62, 0xe01a5f2d, 0x478d4e01, 0x7e07c475, 0xbbeb913f, + 0xe181f640, 0xde87c584, 0xfc98d34d, 0x326f79aa, 0x6fdc3fe9, 0x4e9e2fa4, + 0x3e9d7dfd, 0x9cfd7dfd, 0xebeaadd9, 0x9f9835bc, 0xcc9fdf8a, 0xefac1811, + 0xe60a4f9f, 0xbbe938a7, 0x8a973d4b, 0xd5bd8c70, 0x6fd44fd0, 0x37e31d8d, + 0xc35357d2, 0xbec06d89, 0x713f142b, 0x5fb8c80d, 0x26a6f997, 0xd1d9f037, + 0x766916ce, 0x6669e906, 0x82b73bca, 0xb48bd76a, 0x743b7df8, 0xe5fd0058, + 0x67f5a9a4, 0x3a075c76, 0x63916f7e, 0xca72afe3, 0xf7ea6974, 0x254abf8f, + 0x3f1c51e4, 0x3ab272ef, 0x339ba267, 0x90d973b3, 0x5f70e74d, 0x281da00c, + 0x0db1369d, 0xdf7991e9, 0x57bc6e35, 0x93e40d67, 0x64f7e81f, 0x07df665e, + 0x9196f7b8, 0xc81cc1be, 0x8a4ff567, 0x3bac3815, 0xa0c563c2, 0xbe50f284, + 0xe2571606, 0x02d865e3, 0x47489d35, 0xfdd77d05, 0xb8a4ed11, 0xe9d4d4ca, + 0xc65e251c, 0xbd3407c1, 0x9a99a715, 0x8ff1463a, 0xe91f68db, 0x5e0e836b, + 0x7f355ff5, 0xc6726996, 0xd6c7cf84, 0x5c5a0d33, 0x15d9270f, 0xdb2fe91e, + 0xb8407a87, 0x40381ccc, 0xb43d7a2b, 0x42673ea0, 0xcbaf7d40, 0x6729bf18, + 0x78f9612c, 0x33238b2a, 0xe7aef535, 0x68f4809a, 0xeb857ca7, 0xd3c82e26, + 0xb08813fa, 0x99970255, 0x5b3b1456, 0xad8f8367, 0xad89a073, 0xad9da173, + 0x5b074037, 0x5b20826f, 0x0da04a61, 0xeb5ffc58, 0x0c3cc3ea, 0xa26e5d3f, + 0x18bc5c7c, 0x87f3469a, 0x2ebc9ab5, 0xea8c0f2f, 0x1e5c3f25, 0x64ce4073, + 0x2e4e5d74, 0x9d98f213, 0x91b172eb, 0x073de23d, 0xad6933f8, 0x877b1080, + 0x99de925c, 0xe0998205, 0x5c18902a, 0x51e51dfd, 0xb2cd921a, 0x54b91477, + 0x8f276e8d, 0x9171726a, 0xea8d8f0d, 0x605baf6b, 0xcc37aeb0, 0xff1499d0, + 0x7213ea47, 0x84e2ce88, 0x0c052fca, 0x21f77e11, 0x6be3199f, 0xb3655171, + 0xf74ee107, 0xe3199f49, 0x65597168, 0x6ac44591, 0xdf63f5b3, 0x4765846c, + 0x1fa03e52, 0x3bc831d9, 0x87bc3e50, 0xfa54d287, 0x7ca7e39e, 0x101fe369, + 0x07654fc9, 0xadd59040, 0x17e45568, 0xaeef357e, 0xba7aa971, 0x4b3f26d9, + 0x0f6f587e, 0xc3c80924, 0x0cead69a, 0xac1b87ca, 0x8c9fbbea, 0x89bea615, + 0x1e21b172, 0x2f94617b, 0x081c57dc, 0xb9a13887, 0x47a51dc5, 0xf01dffc7, + 0x784af9fe, 0xafca650f, 0x09bf29b9, 0xc61beb22, 0xb3bb796b, 0x97c44cb3, + 0xa3170e90, 0xa9389423, 0x26dc85b9, 0xde97b7cb, 0xf6aa270b, 0x7b6c97b6, + 0x75ed747a, 0xd3ddbb4b, 0xb70f7e47, 0x8027b37e, 0x433f86ef, 0x5def78c4, + 0xce8fbcb7, 0x39429a35, 0x5f97a845, 0x92b69c26, 0xcaf6e83d, 0x209692a1, + 0xf8126ddf, 0xca0fccad, 0x9675c35d, 0xe1ef6a27, 0xca1ef8a5, 0xabe7d8a3, + 0x4a0fb2c2, 0xd20e9a6a, 0x57b72a5a, 0x39e10ee1, 0xf236f442, 0xffa46591, + 0xac8f94c1, 0x9c7f319f, 0x169ddaa0, 0x1ff7baa7, 0x0abc7879, 0xdfc620fa, + 0xbc5ff71a, 0x8f8c2ff0, 0x914e438d, 0x7bed978e, 0x7dea99a6, 0xcab0cfdd, + 0xdd11c433, 0xd97666ef, 0x773b3c02, 0x5f3a52cd, 0x878f51f1, 0x3d75efe2, + 0x832a36a1, 0xc627ddc3, 0xd7aff6ab, 0x3f70dfe9, 0x6e7c4f24, 0xa6487b47, + 0xa7ca8b3c, 0xef37683e, 0xab7f21b7, 0x60d07ea9, 0xf6abf185, 0x58ff7a95, + 0x561fe47f, 0x19f03bea, 0xa95df885, 0xcb62bfd1, 0x5d91377d, 0xfb1bf4ad, + 0x6cafbd41, 0xf6d5ced4, 0x1f13d7f8, 0xe78ddbb5, 0xccafa91a, 0xeb0cfaa7, + 0x75d50f31, 0xaa5bfb71, 0xd8d95f58, 0x1ffefc65, 0x2495f637, 0x81bf2d60, + 0xd72e4756, 0x4e7f10ce, 0xfd59e7d6, 0xf56de436, 0x8ba2cdf3, 0xc8a76ce0, + 0xf5d1ebe2, 0xb61e7b10, 0xd15b31a4, 0x46e575fd, 0xc3c7d58e, 0x364bdffd, + 0x7828e889, 0xbdd58329, 0x7ab3af58, 0xd9881d03, 0x86ca016b, 0x3d7bfb43, + 0x426b9225, 0xe777af3c, 0xff4f5489, 0x67049d75, 0xf4fa512c, 0xdf9abe7a, + 0x3ea56551, 0x93ec7ee9, 0xef210ec8, 0x37bc72e9, 0xfc05b0fd, 0xaa043fb8, + 0x9ace863e, 0xf33e5d58, 0xe49e4ec8, 0xfd518fcf, 0x026996d9, 0x0e1e4621, + 0xa3080c61, 0x4d36f5f4, 0xa979097f, 0xf144fd86, 0xe4fdc32a, 0x7ec35cd2, + 0x2b69239b, 0x0a4501e1, 0x8e284b7a, 0x48a4efab, 0x20f70c53, 0x5fb8ff84, + 0x437189ae, 0x64c39cd2, 0x15ce15cf, 0x3690de6c, 0x9e78d0b7, 0x5f13cb5f, + 0x87b833b6, 0x657f957c, 0xe675e836, 0x7e9e1180, 0x10921db4, 0x39a8e3af, + 0x00a16e6e, 0xc13625d5, 0xd5ca5df8, 0x4c0262ec, 0x861bcc30, 0x961ceee5, + 0x0945d92b, 0xf720c8fc, 0x1ea1b978, 0x3434dd58, 0x422a29c1, 0x7d630f54, + 0xd467f946, 0x259fe518, 0x7e3de51b, 0xd9de5185, 0x5f79464d, 0xab9462dd, + 0xcdca315b, 0xe1a671b3, 0x4af6c4fc, 0xf3793c03, 0xd7f3860d, 0xe01817f8, + 0x376fdba9, 0x71d69f9c, 0xa0bf61af, 0x5f61956b, 0xd9cbb3b7, 0xd581b5c1, + 0x0266f671, 0xa0ec15d3, 0x0643f0e8, 0xff7af17c, 0x12aaf831, 0x47a5ce51, + 0x48c2de51, 0x1484703b, 0x6f1878a0, 0x57faf107, 0xaadff4e2, 0x93f793e5, + 0xee4e3ece, 0x8f412f3a, 0xa0bcda7f, 0xb1fac2dc, 0x55690a7f, 0xcb567489, + 0xaf2d3e6b, 0x644df6c1, 0xa973e024, 0x0f1418b0, 0x3c2b1c52, 0xbb22abe9, + 0x1d350e2c, 0xe4a0f644, 0x32557b6c, 0x7040979d, 0x4b47538d, 0x5296fe74, + 0x72b1cc0e, 0x8f366742, 0xa171ca8b, 0xe327cad2, 0xfd6fb2e1, 0x54ecc96d, + 0xcfa7c33a, 0x3552b87d, 0x1c97cc6f, 0x47918e60, 0x4f9ea945, 0x5d5e8cbc, + 0x089cfaee, 0x52b07deb, 0xfbb26fbd, 0xd5a3dcdb, 0x9e66e237, 0xab325fd5, + 0x32710ec7, 0x6add1f9b, 0x7d90e60f, 0x5f90c99f, 0x317cc5c9, 0x56051268, + 0x36a171bf, 0x8c4c2a62, 0x6e52f251, 0x9f512f9b, 0xcd2aed86, 0x8bf21727, + 0x465e2be7, 0xa2542bbe, 0xb7f4c5b6, 0x99de5727, 0x739e794b, 0xbbc22fad, + 0x973ccfef, 0x9fcc7943, 0xf7a2ed2c, 0x1921e787, 0xd9c617c8, 0x48504990, + 0x1c43ca04, 0xd1ce2feb, 0xfc623323, 0xe585a376, 0xadfad02b, 0xe939353b, + 0x0d12d6fd, 0xb13e2f6f, 0x9df8e302, 0x3c98875d, 0xb407336a, 0x7449ad3e, + 0x4df7fbe1, 0xbf521670, 0xa8915209, 0xff7ae9f6, 0x3eff9e35, 0x57ef5579, + 0x36be772f, 0x07d0dfb3, 0x51b48ec3, 0xf3f18de7, 0xeadf28ac, 0x258fbdfb, + 0xfbd3fcb0, 0x1f9b3658, 0x641fdf46, 0x9b3b8173, 0xc7d8303e, 0x1b1f2ddd, + 0xe51eeeec, 0x287ec313, 0x8f19623d, 0x64f687fc, 0xe503b9cd, 0xadb77e77, + 0xd450fa84, 0x4c6e7f57, 0x627a1c9f, 0xf7c26cf2, 0xc73cf9bf, 0x1759e8e8, + 0x9d34f364, 0x4eebd3cf, 0x2eb43832, 0x3e78d6c4, 0x5f55bef5, 0x3c837fad, + 0xc227ea33, 0x9b47118d, 0xd479d4c3, 0xd667beba, 0xc3ca4ab8, 0xb356d93d, + 0xe1524eba, 0x0abb52ac, 0x6b4b99cf, 0x48dce2d8, 0x070f6b7d, 0xd0f68712, + 0x9785d57b, 0x7744f8ac, 0x50f56c86, 0xb9195a5d, 0x482b7340, 0xe379b10f, + 0x41d954d2, 0x062c39df, 0x9d1952b3, 0x383fa893, 0x035e526b, 0x2f25018c, + 0xf53e71fe, 0xaa498301, 0xf8be27dd, 0xe9057cdc, 0x97c5257e, 0x0a40f74c, + 0x94e76359, 0xfa859cfa, 0xc253ea62, 0xf0cd750e, 0xcc8f8c70, 0x478a75b8, + 0xd3d7578d, 0x9af5ef8a, 0xe47126da, 0x80dacf0f, 0x07e8a7e6, 0x4317d512, + 0x1faa6cfb, 0x70920198, 0xdb6eccff, 0xe3cf640b, 0x5faa6690, 0x7d635ab0, + 0xb65be141, 0x7d09c500, 0x11ee933e, 0xfbc5e57e, 0x6c2d7be9, 0x2898300e, + 0xd77f9094, 0xf5601d27, 0x595c89d7, 0x15f9b0f2, 0x7a3f1448, 0x6eb6d8f7, + 0x3991e752, 0xafff120b, 0x0f12b873, 0x6a4233eb, 0xe1cda95d, 0xf9abbe74, + 0x43df19c7, 0x7c406d9b, 0x7c1a5f9e, 0x4ee6cbca, 0xd9d10e62, 0xd6e9526b, + 0xd3f9d5e9, 0x73be88f9, 0xe7d5bb65, 0xd779d149, 0x07e44986, 0xce754728, + 0x2f7773c7, 0x7dfee518, 0x7cb2beba, 0x558f88f3, 0x2dbcea4d, 0x07f6f7aa, + 0x8ede914f, 0xbb1c5938, 0x3e78fddc, 0x611ff7eb, 0xef3e40f2, 0xf862fe22, + 0x9989e25c, 0x3eef9e0b, 0xf85794f1, 0xb385fce1, 0xf878f9d5, 0x02398b85, + 0x77dfafde, 0xc9d924e8, 0x6e3c1cf0, 0x831b6d8e, 0x68ea657d, 0x0acc6bf3, + 0x4d92f531, 0x6cc13fbf, 0x9f218fbc, 0xfc8bacfc, 0x5d89eb11, 0xf9421f5a, + 0x9eb6e292, 0xb1d9772f, 0xe2df454f, 0xb8b36f42, 0x8ec9784d, 0xcb0a73d7, + 0xa15cfa5b, 0x44bcc38d, 0x599b963a, 0x76afe73c, 0xbba7648a, 0xd482f6d0, + 0x04a59ad7, 0xeb8e3f36, 0xe4dbd76f, 0xd65ec947, 0x4199507c, 0x3be76ffd, + 0x957d6837, 0x6ba64f9a, 0xf09d39f6, 0x64de1f13, 0x358a5796, 0x4dec4afa, + 0x3321d53c, 0xf9d5e140, 0x788f3681, 0x8fd66dec, 0x775717fd, 0x1c70ea99, + 0x00001c70 +}; + +static const u32 usem_int_table_data_e1h[] = { + 0x00088b1f, 0x00000000, 0x51fbff00, 0x03f0c0cf, 0x33a98f8a, 0x32e8f430, + 0x31e8a430, 0x43d4dc30, 0xcf12d388, 0xbf4ca2e1, 0x83030b30, 0x038b1028, + 0x7f1024b1, 0xf8606463, 0x7ebc48ce, 0xbb04115e, 0x81818045, 0x070fc80f, + 0x1905ffd2, 0x330b3e18, 0xf903f030, 0x6dfc80b3, 0x88087c40, 0x376280c3, + 0x2067f480, 0x02c40fbe, 0x17cdf822, 0x417f2024, 0x07ff9508, 0x1042ff8d, + 0x61637ebf, 0x0496f2fc, 0x4de1b1e4, 0x0f8cdc04, 0xef40a77f, 0x6a87e040, + 0x557d7ca8, 0xa02b0606, 0x843a8758, 0x7e4908ff, 0x40cc5016, 0x93e6c215, + 0x05506067, 0x61ab1ff2, 0x281f9737, 0x5f9406af, 0x00073506, 0x15e5ac6f, + 0x00000368 +}; + +static const u32 usem_pram_data_e1h[] = { + 0x00088b1f, 0x00000000, 0x7dedff00, 0x45147809, 0xf4f570da, 0x73264cf4, + 0x10909264, 0xa70930ae, 0xe15c380a, 0x1084ca30, 0xa8ea2416, 0x1388a888, + 0x2e421081, 0xf57175d1, 0x11c3a7fb, 0x9e375941, 0x1d47facb, 0xa22cdc10, + 0x60188806, 0xb200c1c0, 0x1761bb8a, 0xc363d715, 0x01921a0d, 0xe5c58f15, + 0xeaadf7ab, 0x44ceee99, 0xeff3eba2, 0xe3fdfb7e, 0x575453e3, 0xef555bf5, + 0x5dbd6f5d, 0x71024a31, 0x02e426f6, 0xf211c6fc, 0x4908488c, 0xe36d9689, + 0x1749c7c3, 0x92cde442, 0x8840ad6b, 0x343dbaf0, 0xfb21046e, 0x33010956, + 0x587687ad, 0xd3f5a109, 0xcc07d735, 0xd43eb419, 0x9afac1ec, 0xbee7ac1c, + 0x48c3aefa, 0x8aafa5eb, 0x761ba846, 0xdb34729c, 0x37372908, 0x7d05723d, + 0x24557e1e, 0xc450e9ab, 0xb240c535, 0x471e3908, 0xad196fd8, 0x685212a7, + 0x55d2d561, 0x3cc2673b, 0xc4cc1a8a, 0x6e94e142, 0x15ed7b99, 0xaf773eb4, + 0xe94ba044, 0x77534ada, 0x10179f5a, 0x68bea0ea, 0x4e3887c7, 0x545278db, + 0x4f908837, 0x35c471fd, 0x4d1dd680, 0xe7d137a9, 0x130d81c5, 0x7af17fa1, + 0xfda06dc1, 0x7e766b8b, 0xeb8bf004, 0x8522bea5, 0x4ad6bf3f, 0xd8d9035c, + 0x63ac0817, 0xdf30b5ce, 0xc4483fd2, 0xe745eb4c, 0xc01136ef, 0xe4dab191, + 0x8ff8c3b5, 0x18765c9a, 0x51c716a7, 0x7bfa59f0, 0xaf7d0e3a, 0x0dc165ec, + 0x10332b4b, 0x75a7cc1f, 0xf3fa658b, 0xa5575836, 0xbfbc3fa9, 0xf41341e5, + 0xd8281b9b, 0xfcc1716c, 0xc2269956, 0x99566b3c, 0xe145070a, 0x517dafcd, + 0x2be3af33, 0xa9f574fb, 0xa7e5f5da, 0x735a8a7e, 0x884c5eb4, 0xf306cea7, + 0x1fae980e, 0x547e7d1c, 0xcf7a4448, 0x2b8915af, 0x529f0a2e, 0xefcb9f1e, + 0x1f027fd2, 0xd607b76c, 0xb5e94466, 0x8eff09c0, 0x93acebd2, 0xce18cfd3, + 0xca57c352, 0x740e8047, 0x277ed53e, 0xd3f98f96, 0xefc27cb0, 0xe53dbc42, + 0x4ae5881f, 0x3f9f1bbf, 0x658d1fed, 0xe583df8d, 0x5849feb3, 0xec5efc06, + 0x1d3fdab7, 0x1f7e35cb, 0x5fc17f3e, 0xbfad6584, 0xf3af9f02, 0xbd72c42f, + 0x2fe7c65f, 0x596197fb, 0x72c6afe7, 0x96257fa3, 0xf600fef5, 0xd7e9ccdb, + 0xe7c3afe0, 0x580dfd5b, 0x2c21fd06, 0x62f7f877, 0xd5e382b9, 0x8c724d91, + 0x0f0e2f14, 0x20715271, 0x1c9ef949, 0xbc93d689, 0x433a9eac, 0x7ad131ce, + 0x29d68faa, 0x8497ba9e, 0xdeb4cc72, 0xa7b582bd, 0xc7c6403f, 0xccba7ad1, + 0x785733da, 0x3d685bc6, 0xf7b59ab3, 0xc7c791af, 0x00ff7ad3, 0x7d74bf6b, + 0xd695bc68, 0xed63ad2f, 0xd7248243, 0x4243eb46, 0x9f6c3eac, 0xeb4ed727, + 0x3d589ac3, 0xd73923eb, 0xcd59eb41, 0x2db1fdec, 0x5a04dca1, 0xed661b1f, + 0x166f9d57, 0x67f8315d, 0x459be4b3, 0xf2032d28, 0x1bb18f14, 0x777c9bad, + 0x97c53713, 0x1c63d53c, 0xc923f143, 0xbe4bbed8, 0x4c1bdb1d, 0x27bfb632, + 0x56fb6217, 0x27ed8029, 0xdf6c72e5, 0xfb600a6a, 0xac42f2b7, 0xb610a507, + 0xb12b2adb, 0xc214d07f, 0x87caf4f6, 0xd4877db0, 0xcaeeed8c, 0x877db1c7, + 0x1fdb19a9, 0x99e3525b, 0x0b0feb40, 0x2f81a7be, 0x22be0b17, 0xadf807d2, + 0xf94bcd2e, 0xd3204aad, 0x0117bf81, 0xaaf6d253, 0x47d4266e, 0x7ace3f9b, + 0x6f38145e, 0xe17a8176, 0x20650f0b, 0x8e11e79c, 0x1788e144, 0xc9f59387, + 0xac9c0d68, 0x38148a4f, 0xa58e11eb, 0x7f367073, 0x9f3b5632, 0x38158a4f, + 0x149192af, 0xeb73bd8e, 0xb65bfaca, 0x2b7f3e76, 0xc0ece051, 0x6e7624f9, + 0xb4c70d3e, 0x163869f8, 0x389bcfc1, 0xcdce949f, 0x2d71f467, 0x8f1f467e, + 0xe109a7e0, 0x9c1ceb74, 0xfc5ae386, 0xe08f1c34, 0xd38403e7, 0x1aeb73ab, + 0x9f8b427d, 0xf82227d1, 0xc9f88c39, 0xad9c1ce8, 0xd9f8b5a7, 0x9f823a7a, + 0xbf4e10cf, 0x6c6badce, 0x633f16ab, 0xf9f8235b, 0x4975d702, 0x6d6ce0e7, + 0x6b67e2d5, 0xdf3f046b, 0x9dc19c21, 0x36d8d75b, 0xb6c67e2d, 0x1263f045, + 0xced0ce00, 0xa5f827cd, 0x2fc13f16, 0x4049f823, 0x373b2338, 0x5a73ec9f, + 0x8b9f64fc, 0xe10d27e0, 0x9c1ce98c, 0x7e2d39e0, 0xf822e782, 0x573840c9, + 0xd95d6e76, 0x93f1695f, 0x3f0455fd, 0xf7400a97, 0x421f3e1c, 0x863bd8e1, + 0x2d3be3b3, 0x177c767e, 0x9c70cfc1, 0xcf9f1e4f, 0xf55ce045, 0xae7e2d0f, + 0x3f0447fa, 0x726708d9, 0xf8ece0e7, 0x3b3f1687, 0x4fc111fe, 0x9aebae1e, + 0xaaebadce, 0x5cfc5a0b, 0x67e18175, 0xdcbad1d4, 0x6d4eda04, 0xafa45ba3, + 0xf1ef3b8c, 0x3a2eb408, 0xba745d59, 0xa22df809, 0x26908fe2, 0xb7df488f, + 0xf61c4fad, 0x25fb5110, 0x75826fe3, 0xa697a9d9, 0x46124bf6, 0xa0fc6bc7, + 0xa6924f44, 0xbba93c9e, 0x378a7fa6, 0x75ded353, 0xf69aa5fa, 0x9a61be6e, + 0xb1a28f7a, 0x2abdfe9a, 0xbdea6bc6, 0xe9ad5e17, 0xa0df219f, 0x7659f7a9, + 0xbf7fa6ab, 0xed353bea, 0x6b165603, 0x2c092fda, 0xab2fd4d0, 0xffa6a5fd, + 0x9a45bae0, 0x1e1bcbf6, 0x0d0fb4d2, 0x0fa9a63d, 0xa6b4fbdf, 0xd5a6c8ff, + 0x0751f69a, 0xc7da69d7, 0xd4d46f34, 0x55b938af, 0xf0caffd3, 0xb8fa9a1b, + 0xf4d2dfaf, 0x1e7394a7, 0x45d78cbf, 0xfb820b90, 0x099bb902, 0xdd90c5fd, + 0x77537584, 0xd827db1b, 0x29475d0b, 0x9f064ddd, 0x812d0bab, 0xfdda84e6, + 0x0345ee9c, 0xdc5f299a, 0xc037d63b, 0x6bdf9f49, 0x8cee5df2, 0x7e509fe1, + 0x941a4811, 0xfa94032e, 0xc62507f6, 0x9c7be3af, 0xbe887fef, 0xf7086e5f, + 0xbff5a44f, 0xc002721b, 0xd4082fdf, 0x157ca7eb, 0xe80a922f, 0x1e266f17, + 0x3307dfe0, 0x55979eb2, 0x17acbcfc, 0x0a215395, 0x4be49977, 0x5d643f03, + 0xf832bbe5, 0xe8bd5529, 0xf213baba, 0x486ef0a2, 0xefdf4bee, 0xa3e69855, + 0xea26ccf0, 0x37c7abe7, 0xe107f1d1, 0xcfc075f8, 0x94fc619b, 0x339be3f6, + 0x8fc66b47, 0x8cd22f4b, 0xe3a2671f, 0xafbea93b, 0x4f8f98fc, 0x90963289, + 0x38c7c26d, 0x08bd39be, 0x44d07fc7, 0xf1ea3df7, 0x87e323e3, 0x3a7bfd60, + 0x58e67f5a, 0x8bd3faed, 0xb137ebb5, 0x7955bff5, 0x8f1f8f8c, 0x385b7feb, + 0x5e9fd6c6, 0x666fd6cc, 0x3be32370, 0x826ff822, 0xd1d7bff5, 0x6b64fbfa, + 0x44bbdfd7, 0x1b337ebb, 0xa795afff, 0x1c36f8f9, 0x34e143ff, 0x12ef7f5b, + 0xf664df1c, 0x4c7f81b9, 0x022be23d, 0x93d27c74, 0xc0aeae2a, 0x281c742e, + 0xa6512607, 0x2149e427, 0x6f71e713, 0x73b7e33c, 0x50df94f1, 0x9cf8c91f, + 0xa3e6a804, 0xce329cfb, 0xe7d7f3fb, 0x616f4098, 0xccefdd3b, 0xdd9d53e1, + 0x937f2220, 0x7e81cc27, 0x0dadbe74, 0xd9f50ca2, 0x00195c4f, 0x266e58fd, + 0x3de17877, 0xf3c10923, 0x5e0e4f63, 0xbe975ead, 0x1d2d539c, 0x17c8d66f, + 0x9e3c8f9b, 0xf3a0ac0c, 0x182603cb, 0xa71fad19, 0x98d829fb, 0x12fba61e, + 0x74484f28, 0x28fcfa3c, 0x01916fdd, 0xc4a9b96a, 0x79ec88f7, 0xff9d2fb7, + 0x3cfca234, 0x51dbceb8, 0x233c28a4, 0x1af1ffc3, 0x98f40021, 0xf9f74d53, + 0x372ff92a, 0x170ef933, 0x02d58108, 0xff7d2bc7, 0x813efe66, 0x33f851f9, + 0x8f9dec9d, 0x47b35c77, 0xedfdd070, 0x9c0d64ca, 0x6960485b, 0xb6ff7d1a, + 0x62253b15, 0xe828be00, 0xe5f800b5, 0x7084897e, 0x429cda9f, 0xa0667106, + 0x064e7df0, 0xd2e9e6ff, 0x9c1566d1, 0xc79c5299, 0xf333e74b, 0x7be7113e, + 0xdedb4f8b, 0x31eac3bc, 0xcae5a10c, 0x494225cf, 0xb6915b7e, 0x6d0af6fd, + 0xda858efd, 0xee0f5d3a, 0xfd640bf3, 0xba1cba73, 0xeb233bce, 0xf5a70ba6, + 0xd66dbc59, 0xd0d64932, 0x4d736e91, 0x133dbc59, 0x4f104ed0, 0xf69f7ef8, + 0x681f29fd, 0xea5773ea, 0xf8be71e0, 0xdffff4ff, 0x86f2ff4d, 0x5547c59c, + 0x9bad2af3, 0xaaa8f8bc, 0xebdafcdf, 0x8179f535, 0xe7fd345b, 0xb4d02cae, + 0xa79ea9cf, 0xecb59f69, 0x40bd4d2e, 0xffd34fbe, 0x9a95858e, 0x962bdbf6, + 0x2b6fda6b, 0xbf53547a, 0x4d5bf7c5, 0xafa79bff, 0x3b0bb4d2, 0x466ef5e6, + 0xddebe9bb, 0xf4fe928d, 0x7c026607, 0xc2b3f0a6, 0x69fd27ef, 0x77ea7e58, + 0x7a095961, 0xc377ea98, 0xaf965616, 0xfa0de82e, 0x13ffe15c, 0xe83a4552, + 0xeb3f3d4b, 0x4f9eaff5, 0x2c47afe9, 0x4b29433f, 0x3b05e204, 0x64fdc6d6, + 0xdc37f9e5, 0x0ce782ce, 0xc9898965, 0x6ec6c965, 0xea0389e3, 0xb615fea1, + 0x3a92e18e, 0x2041d701, 0x74029a4a, 0x976d41eb, 0x347dae9a, 0x29d96cf3, + 0x2065f8e2, 0xdcc06393, 0x60187778, 0xfa6350fc, 0x3e61838d, 0xdeb1d79e, + 0x56fe8290, 0xe2d27f8b, 0x7f00fda3, 0xfa4f2c5e, 0xdc7963a7, 0xa8f2c3ef, + 0xc3cb08bf, 0x9b2c0afe, 0xfcb10bfd, 0xf9632fc4, 0x96197f91, 0x6357f57f, + 0x12bfd079, 0x01fcf7cb, 0x1efd5b2c, 0xfd3e152c, 0x18eba14f, 0xae9cbfc3, + 0x3ae9a8df, 0xf364e0c6, 0x187d74e1, 0x6fc31be6, 0xc8ce0fee, 0xe23f9548, + 0xdb718c99, 0x4ece3c05, 0xc71624c8, 0xa62f63e5, 0x6fd09ae0, 0x3d040c09, + 0xb7e0767c, 0x7d4e21fd, 0x4a2520f6, 0xd3ebc746, 0x3c43afd3, 0xeffa0f10, + 0x974a0185, 0x96edf6e4, 0x8b578678, 0xc3224c81, 0xefde5908, 0x839df705, + 0x49246eb0, 0x7dc07ef0, 0x5c063dbd, 0x7e020bea, 0xc5d7862f, 0x004373f6, + 0xffa7f1de, 0x18e5059e, 0xe307f303, 0x4bf4451b, 0x3779e849, 0x67a237e0, + 0x8834eecd, 0x99fb86f7, 0x9af7689c, 0x4fe2d6ae, 0xbf835abe, 0x55fc11e5, + 0xfafe21a7, 0xc28ffb9e, 0x8784f11f, 0x8a3830dc, 0xef846fbf, 0x1e729fc7, + 0x36ef1fa3, 0xf883f8d1, 0xc1552db2, 0xa13a536b, 0xf811fce3, 0x5b3fc29f, + 0xf001203f, 0x1173811c, 0x7faf08fa, 0xe8fa0e9c, 0x16c9d034, 0x0e9f7785, + 0xcfbdd9de, 0x5fefc03b, 0x47ca2690, 0x2959e063, 0x6432eb4b, 0x6a4fda9b, + 0x56cfd6d0, 0xd0ea930b, 0x4c25719f, 0xd7fa0c1d, 0x40951f29, 0xa961a64f, + 0x669059c0, 0x7d2871c2, 0x4faf5c98, 0xd4ffb944, 0x7efd871f, 0x047479ea, + 0x7a8f3a27, 0x0fbe8472, 0x4fa17f2c, 0xe43bfdc7, 0x2617e353, 0xa091b388, + 0x97fc0e74, 0x05fffa38, 0x46237838, 0xcb702bac, 0x7cd944eb, 0xaf5f3c39, + 0xe7be8f19, 0x2f06ce52, 0x3c9f7e64, 0x8571c918, 0xa8a9a95f, 0x48d61881, + 0xac8b5be0, 0x35128ff5, 0x6e86f2f5, 0x825fc6b2, 0x4a3d507f, 0xf023048a, + 0x9f67094b, 0x996da336, 0x0bf7e740, 0x3e816208, 0xd2bf5810, 0xcf9366b8, + 0x78b2fc05, 0xe82e15da, 0xd5eb8d59, 0x2fd28fcf, 0x3c7528c3, 0xd9e2f9ff, + 0xe431bd7b, 0xdbd72763, 0x57160625, 0x03b27120, 0x9a48d7ce, 0x8ec1b8ec, + 0xf045b353, 0x3a3b7183, 0x0a0f0a8e, 0x2901799c, 0x995ff5ac, 0x5818b65c, + 0xee3f40bc, 0x94dc619f, 0x6cafe38b, 0xb089fefd, 0xcb1e3d6e, 0x7c98ce1a, + 0xbff45728, 0x151e28ac, 0xf442fefc, 0xeba459fe, 0x843dae2a, 0x9293eafb, + 0xeffeffdc, 0xe7ed8bd1, 0x6e3b4b6f, 0x265bad55, 0x9dce304d, 0xc440f9a3, + 0x5487f375, 0x5b7a9f5f, 0x5d010f22, 0xaa5ed3ce, 0x828f5079, 0xfea2b218, + 0xf3f59dfa, 0x9f7ec1f3, 0xf7053cda, 0xd789b32b, 0x22ca4101, 0xfe059d52, + 0x986269f9, 0x4d3a7804, 0xae18ecfe, 0xd139d3a2, 0xfea1f484, 0xfcf561fb, + 0xa9aeffa8, 0x535dff53, 0xa437242f, 0xe178f9c2, 0x08091213, 0xfb4d3eb8, + 0x7089d171, 0x2a8a92e7, 0x4b1677f0, 0xe9dfaecc, 0x541ec624, 0xf6be979f, + 0xad01564c, 0x7f32277f, 0x9def3944, 0x377b7547, 0xb75c5eda, 0xeda1e4ca, + 0x4f87ea47, 0xfbc082bb, 0x3fb02a81, 0x7b82abf2, 0x7e3dabad, 0xf5fce87f, + 0xa1fc55f3, 0x7ccee776, 0x82b5a51e, 0xcf831027, 0x67c646ac, 0x30f63f0a, + 0x8df1353a, 0x70faba01, 0xae9c7d5d, 0xbde5a3fe, 0xfbc8d10b, 0x00df442f, + 0x6f930a63, 0xc609dfd8, 0x8ff3f230, 0x0ed69f86, 0x149ff0fe, 0x9cad4f7e, + 0x7ee3f851, 0xdb7df852, 0x2c4a7fcd, 0xbdafa5f8, 0xfaa659b4, 0x2795f8a9, + 0xa7ea841d, 0x54eac653, 0xc97fa537, 0xe00ea5da, 0xd9469383, 0x2a7cfc01, + 0xc40a4e20, 0x8c8b77d0, 0x3daff702, 0x6fe20136, 0xff0a4ff0, 0x5f0f75d3, + 0x7387710b, 0xc627256b, 0x21cd6ad5, 0xb2d39533, 0x64f979fa, 0xb10fd608, + 0x446783fa, 0xf96837a8, 0x4f77f8b3, 0x5f50baa6, 0x180c3dca, 0xffa10e3f, + 0xd8e6b65f, 0xe5fbb044, 0xa6728c24, 0xffc60f7f, 0x53ed093a, 0x7da12981, + 0x53e46e3b, 0x2bf67de1, 0x8cf87faf, 0xf27280e8, 0x7427d009, 0x03f184e7, + 0xdc457bfd, 0x68dbbf9f, 0xf3f182ef, 0xe8146451, 0x242f0531, 0xf179fcc0, + 0x408667b5, 0xcd65b51c, 0x85410edb, 0xcede452f, 0x6e7acdd6, 0xbd63abab, + 0x51e54ad9, 0x7e2a47ed, 0xef81ab85, 0x2cac8243, 0xc80e4291, 0x255929ab, + 0xb8fa65b9, 0x5fe7a5e4, 0x9ae21a78, 0xfddd981f, 0x2ff9fc28, 0x2c6f7eed, + 0x20dfcfad, 0xcb67c975, 0x51a909b0, 0xffd394fa, 0xd28b0e17, 0x6ed378a3, + 0x7b306b93, 0x945240fe, 0xec37f32e, 0xedc19134, 0xb75b91f1, 0x8b6cd4d3, + 0x43ba9f41, 0x130fc113, 0x04cefb5f, 0x43b53ff4, 0x62335d20, 0x6ed573e0, + 0x4f00d3f4, 0xaf4e4f48, 0xfd74fd08, 0x405d29cb, 0xa5e9ebaf, 0xf41537ef, + 0x0b830a4b, 0xbf9412f9, 0xf90ade5f, 0xbb357f48, 0x2f450f01, 0xf580eddf, + 0x3056309c, 0x69667f3e, 0x5f8e87aa, 0x4ea9c924, 0xa2f3d92c, 0xfc8e7f67, + 0xcfff7737, 0xcb5c5953, 0xb680cdd3, 0xeb06ee4a, 0x1373539c, 0xf890b3ae, + 0x9e8b0f90, 0x2fa0bd11, 0x499234bf, 0xc9c8621b, 0x4e4e5cb7, 0xa5c4a6ac, + 0xcd413ceb, 0xfce9e610, 0xc5ac0c59, 0x185dfa38, 0x5f39fb37, 0xb0e8f50b, + 0xa31c65fe, 0xc0d19357, 0xeaf52ef5, 0xe6bbfcd5, 0xd3a026c1, 0x5d3cbda7, + 0x9ca5fce1, 0x0f8e6518, 0x2b8502e1, 0xcaebcfee, 0xc65c44e8, 0xf51efe2c, + 0x39e172cb, 0x3c926ff4, 0xf79a2196, 0xe88c85c8, 0xf1f0f7f8, 0xc1e3bce9, + 0x1a913a9f, 0x40305f7b, 0xb502ec52, 0x533e2aeb, 0xff933bc9, 0xbc99cb35, + 0xb81ff22b, 0x7fb4127e, 0x11c98071, 0x92f607bc, 0x15d42bce, 0x154e77db, + 0x49983f50, 0xaf9c9628, 0x6b9cb891, 0x42fcf5db, 0x12146fe7, 0xe3037c54, + 0xd01d2124, 0x827c2a9f, 0xa3d2afbe, 0xa3ae30e5, 0x8e455c3d, 0xf07d72e7, + 0x6b03e825, 0x1a901f54, 0xf63a07a6, 0x53c4657b, 0xe1781489, 0x2a5f9069, + 0xe40bb2af, 0xfac2f257, 0xf8df5b3f, 0x6e54adde, 0xe453ab3e, 0xf557ab56, + 0xf1b45b72, 0x54f804e7, 0xf59fb72f, 0xe53120ac, 0x298f3e96, 0xff9b3db7, + 0xc1557a25, 0xd5a4ba63, 0xec9e8aab, 0x3d7a9f08, 0x42e8c5b9, 0x24f5eabc, + 0x59201dfd, 0xe151f9ed, 0x8aff8543, 0x0ded2c5f, 0xa7c228fa, 0xf8461f0a, + 0xfd43e154, 0xd478b5ba, 0x9e7c63b7, 0xcb778bf2, 0x507b13bb, 0x050496ba, + 0xef85d9b7, 0xc53a81ed, 0x0b6d8797, 0xe8f4f7aa, 0x7407aea2, 0x7f5d3af5, + 0xd5eeae8f, 0xeae9f7f5, 0x01feba15, 0x68694fb6, 0x87e41134, 0xb4bfa690, + 0x9f90c888, 0xe22ede16, 0x9d1b41b9, 0xbf7d1573, 0x40467d6d, 0xa961faa6, + 0xc3dbed85, 0xd02aa629, 0xb0ce6d67, 0x16ea0923, 0xf36b7f16, 0x2a891d86, + 0x5050f1ff, 0x1cdc7d44, 0xed629320, 0x8bc7a85f, 0x1d266bf4, 0x90f3b3b5, + 0x10c778b6, 0xb44f2f18, 0xf8842fa5, 0x86e8b54c, 0x95d98e23, 0x5ce03b37, + 0xe7d82da2, 0xf9f4e9ba, 0x2c883f9c, 0x18f6422d, 0x0df6a9bb, 0x54fc8927, + 0x95f900b6, 0xb3fe902b, 0x311f6c82, 0x7e6c457b, 0x15efe62e, 0x8131eeda, + 0xfffea4de, 0x5f5c7561, 0xa3545381, 0xc29c1e7b, 0x2fed9ef9, 0xdb68d78b, + 0xfa3f7c7d, 0x0fdf0a5f, 0x7ed94325, 0x0838b090, 0xe279bbd7, 0x53a6eba0, + 0x15edb43a, 0xd9cdf009, 0x387488a0, 0x40085ebb, 0x29c88a5c, 0x24653f28, + 0xc14efa8c, 0xc7c80b57, 0x50f58e80, 0x671fabcb, 0x94bb4fdd, 0xc870fe6c, + 0xcb65a5ff, 0x6ffa0fe6, 0xef6bfa83, 0xda487fa7, 0x61ddcff7, 0xb6df73c1, + 0x27cc761d, 0x4efedb6e, 0xdf50fdfa, 0x3cc37662, 0x357c76db, 0x6da8f804, + 0xf408b991, 0xb62f5b58, 0xfdbc59ff, 0x68cd21ab, 0xfd20973f, 0x8b13256a, + 0xfeff04d7, 0x4a05d089, 0x0ff02aba, 0xf9727e78, 0x20804b56, 0x7cb2affc, + 0x3d6e9fb6, 0xbf9cfc65, 0x6fa64ecd, 0xb225f984, 0x6df2ec73, 0xa4af9e63, + 0xefd697e3, 0xeda2cd34, 0x377fafb9, 0x3791f304, 0x55a7bf32, 0xce167e6a, + 0x6f4937b1, 0x9e28922e, 0xba38415b, 0x299d7213, 0xc5b6572e, 0x1877cbc2, + 0x3e2cea97, 0x7ed892de, 0x1f1fdff4, 0x9511e602, 0x3881ed04, 0xcdfdd601, + 0x3e821f27, 0xbe4661d8, 0x59fbd654, 0x23fa255d, 0xa9f75b17, 0xd07c31ff, + 0xa10b75d9, 0xce3bacce, 0xeebdeff4, 0xce172447, 0xed072f4f, 0xbdfb7cf9, + 0xeec97f58, 0x9276f9c6, 0xfe9a07df, 0x237df8c3, 0xe2e3bba5, 0xbfd9feeb, + 0xa63bbaf9, 0x72661ffb, 0x1f213bba, 0xeff5fcac, 0x543f7e70, 0x1ffdcdcf, + 0xbf8af7ca, 0x9b78366e, 0xa6fce872, 0x383b6a93, 0x9ca4b716, 0x73a907dd, + 0x745f5ee6, 0xfc4af981, 0xbf3f51fc, 0xefb62695, 0x997ce093, 0x126e4b8e, + 0xed8f7ef8, 0xfee5ae93, 0x0b3db5c5, 0xd6bd2fd1, 0x6277fcc3, 0x46737af4, + 0x6cd89e40, 0xc943c637, 0xa83e83b0, 0xaf2574df, 0x7f8bf76b, 0xa0478814, + 0xe9b5f9fe, 0x9f82f693, 0x634f5d7a, 0x43caccc8, 0xe0ebbe50, 0xf76b47cf, + 0xb4f8b733, 0x6ba79bf5, 0x787137eb, 0xa2b9c0d3, 0x0af34fe3, 0x4a7f8801, + 0x81489ebd, 0x4734a878, 0xf9008222, 0x614b1524, 0x579370df, 0xb03dfefb, + 0xc5191dcf, 0x82b8bce3, 0x114e70f9, 0x7c405037, 0x4442b75c, 0x4837127d, + 0xd1def840, 0x1e1de612, 0x00b37833, 0x47c3f9cf, 0x8192fd95, 0xe77ac373, + 0x92157c71, 0xc877f40a, 0xb2170bf9, 0x4bee20b3, 0xe79a5fd0, 0xea1ae421, + 0x0b6617b7, 0x63c878a1, 0x61391231, 0x0543c418, 0x0f135872, 0x77e1d6d5, + 0xce146a55, 0xc477fac5, 0xf9753f8f, 0x87ffca37, 0x433fea25, 0x2cf3e789, + 0xb3eca7ae, 0x3c3208ee, 0x81089796, 0x90abe44c, 0xb0cf3ea4, 0xfdff1999, + 0x28e181ed, 0x1ebf3957, 0x7ff6c09c, 0xa0bbf023, 0x9e67ee72, 0x10095d95, + 0xec1b38f7, 0x72d1cfc3, 0xfc18be1d, 0xbbef9fbc, 0x007902fe, 0x209b6cb4, + 0xffe08b54, 0xfbc63093, 0xb21609e4, 0x5cbe4636, 0x8739498b, 0x207dc0af, + 0xa02cc4fc, 0xa5cdfb23, 0xa92426af, 0x9ae2b6e8, 0xed21c653, 0xc3bf00e9, + 0x7e4bce31, 0x3cfb096c, 0x4b7eebc0, 0x8c6f44f3, 0xcb83fef5, 0xdf1bfe6f, + 0x376377e0, 0xc0243304, 0x44130dcb, 0x39eaf9cd, 0x87e3f713, 0xaf30e193, + 0x3b2637fc, 0xf65d00c6, 0x4ef86e8a, 0xc6783cac, 0xce718be4, 0xc027c7a4, + 0xc90073c7, 0x3cf8085d, 0x810b2bf2, 0xfc3bd6fd, 0xe41067dc, 0xadc20f61, + 0x4ce207bd, 0x0b8b3366, 0x713b30cd, 0xe7e6379e, 0xdc742948, 0xa1cef541, + 0x9dd5f470, 0x46019ff7, 0x5124246b, 0x7e94f7b0, 0xbf584bdd, 0x59672643, + 0x113ff5ac, 0x733ae2c7, 0xd1defb89, 0xdd1fbfc2, 0x0f6d7e72, 0x327b078d, + 0xd8e77d81, 0xca09af9e, 0x4249d9c7, 0xec3df400, 0x2f9eb09f, 0xc779bda0, + 0x1be5dac0, 0xf8565e98, 0x11e78f5e, 0xf8cacf1c, 0x0c7d7953, 0xcf052f97, + 0xf3f57e0a, 0x7d53fa55, 0x8f1d4e35, 0xe861aeb8, 0xcb0f60cb, 0x40d38282, + 0x9b199541, 0xe587204d, 0x104a8f0d, 0xc5c5bf8f, 0x307b52e0, 0x3bfe7d44, + 0xe1ceccc3, 0x315d871b, 0xf3e4f813, 0xa12fd415, 0x9f667bef, 0x7ddd8071, + 0x13fee0c7, 0xff29077c, 0xbf6b2451, 0xe87d5f47, 0x904f1677, 0x703370d4, + 0xe496379e, 0xb93e1048, 0xd4a764ad, 0x334fc555, 0xaed849cc, 0xe25eef3c, + 0xe9cf061a, 0xf90f3878, 0x3c813311, 0x4d7541f2, 0x6ddbfdf8, 0x0f8c8915, + 0x9a76ea8b, 0xfd819eb0, 0x7194f195, 0x3534f2f4, 0x341f9b5f, 0x27b9b72b, + 0x1cdf25e0, 0x831dc7ba, 0x95982f4f, 0x681f8873, 0x6f943c27, 0xb22ffc87, + 0x7628f713, 0xaaf259a2, 0x34de49f2, 0xd9573933, 0xecb1ae89, 0x574a82c4, + 0x82c3a057, 0x82ba7ded, 0x43f82c90, 0x3b2c6a5e, 0x9d9faef1, 0xbfcfbe2b, + 0x4a9b6d23, 0x2ae5c4ed, 0x82d5313b, 0x6f7fa27c, 0x7693b983, 0xffdba142, + 0x2ef37d63, 0xf21889d8, 0x4fe38bbd, 0x82d313b1, 0xa6276805, 0xdf35154d, + 0xf3336c5f, 0x76877178, 0x16f52722, 0x6b6e4bac, 0x9779fe0c, 0xf3efc3fb, + 0x07183c3c, 0x5cb7c5ec, 0x46edebff, 0x371d7a47, 0xa13b2335, 0x7845ffd7, + 0x02faf456, 0x339b2fea, 0x4121f162, 0x0b705e7e, 0xf002ebd5, 0x0bebd323, + 0x3171e76e, 0x82f59e9d, 0xd6a11d9e, 0x32fdecb3, 0xe50bb31f, 0x99bf190d, + 0xad6fdb41, 0xb471dc96, 0xbd51adff, 0xbbd6a59b, 0x77a476df, 0xfdde988b, + 0xfd1c383c, 0xf7d68ea7, 0x54b7d731, 0xc775f59f, 0x33e98fe0, 0x77ef9aac, + 0x737d0c8e, 0x979026d0, 0xd73c4477, 0x80fdc63b, 0x1cdf437d, 0xe9eaf101, + 0xbbe44671, 0xad9e9cbe, 0x813c527e, 0x36772fe2, 0xd74ba7f3, 0xb2bf888b, + 0x65ff267a, 0x45c042b5, 0x7d8713eb, 0xfcfa8263, 0x8e7ceced, 0x473f20ae, + 0xeff9ff45, 0x3c415734, 0x012afe78, 0x1f2117cf, 0x9739f01a, 0x3dd0b3e3, + 0xfa2bf71f, 0xf1e5833c, 0x72e4d58e, 0xd3f18784, 0xdf3fde52, 0x72f8c61c, + 0xf704effe, 0x1f3ed22a, 0xd5efb4a1, 0x319f60a7, 0xdcf756bf, 0x11cf1cbd, + 0x718b5fa8, 0x6d3ad2d4, 0x4ff71e7b, 0x41a188e6, 0xf57f609b, 0xcb1dd127, + 0x22fd29de, 0x27fa29f8, 0xe29fb3f1, 0x874fc467, 0x9dc1799f, 0xa1fe5f18, + 0xe3e3d178, 0xbf5c7167, 0x4023230c, 0x3c198f1e, 0xb7e45fa8, 0x9923cc44, + 0xcd3f68fd, 0x7137043d, 0xe0c779be, 0x5f3c82ab, 0x9be58cb9, 0xb0d9adcc, + 0x67d6953b, 0x10a191d4, 0x52bb9e96, 0xf6238f6b, 0xfcc5debf, 0x020d8a82, + 0xe1ce15e4, 0x051509df, 0x1b7bc51e, 0xed485f6e, 0x6b3fed3d, 0xe707d998, + 0x612dfba3, 0xff0a9fd4, 0xf263892e, 0xe3cf88b4, 0x04f0f748, 0x820d53b4, + 0x6432e513, 0xd28b7661, 0x6893ee09, 0x44d5f31c, 0x8f16174e, 0x2c746068, + 0xb90374a7, 0xf5e4189e, 0xde0fe63a, 0xcec33c16, 0x253b82b5, 0x40852f76, + 0xb9df5192, 0xd8acff71, 0xcb673847, 0x77d15549, 0xffc621fb, 0x3e37056b, + 0xfeffd008, 0x4076fa19, 0xe99fc557, 0x3c157d2c, 0x79d1d12d, 0x7f29a5bf, + 0x08d79e38, 0x23a7bc6e, 0x0be78898, 0xbdd9ab47, 0xfe718f13, 0xec05cbd7, + 0x60f7d43f, 0x87130f5c, 0x1649d37c, 0x71c3ebcc, 0xa67f9933, 0xd6508efd, + 0xd0fd01e4, 0xd272953c, 0x34597e84, 0x34e7ccbf, 0x249fdd83, 0x5f79b518, + 0x9ffb9461, 0xdfdbfe00, 0xc5a49f07, 0xdbb97da1, 0xf6369ec9, 0xf4191132, + 0xf90932fb, 0xeb8366e8, 0x2fd06cbd, 0xe404490f, 0x237df3e3, 0x05d19fdf, + 0x8fe445da, 0x97867782, 0x80a48841, 0x829126e5, 0x3a5d98fb, 0x2bffc7c2, + 0x019ed7b5, 0x83f0487c, 0xf80189fd, 0x7baa6cae, 0xe20b9e67, 0x2ff62326, + 0x1bb1f385, 0xbdef9d73, 0xce5c7407, 0xbc395bee, 0x69f7172c, 0xa025df77, + 0xf4a41d9c, 0x4d373802, 0x3def78cd, 0x97dbbf3a, 0xd739e0a5, 0x34ca4f0c, + 0xb19af738, 0x68bb744f, 0xd9d759bf, 0x364e706d, 0x7c48a065, 0x4edcbc2a, + 0x334e309a, 0x9baee2a3, 0xa88a4e40, 0x547b843d, 0xf3fb828a, 0x46bd42ba, + 0x65cbf7c0, 0x9d2ba99f, 0x33cad35f, 0xfc7411a6, 0xd00fda42, 0xfac35e5d, + 0xdc11af95, 0x185baa90, 0x64f5147c, 0x2f011ae1, 0xfea268aa, 0x1b831c6f, + 0x9b70a388, 0xb4fbe86a, 0x07de173e, 0xa7126bb8, 0x395679c1, 0x3fbe279d, + 0x25cf12ba, 0xb47be90b, 0xb9ad3499, 0xabcde10b, 0x6f7c0811, 0xe33a3454, + 0x6f00d191, 0xf686e49f, 0x16fe77f7, 0xd2664af3, 0xf851baf1, 0x3ce6c4b3, + 0x2fddab8c, 0x93bef138, 0xee517dd9, 0x91dcb8da, 0xb9d87d81, 0xef9440b4, + 0xfcea8c7e, 0x96164184, 0xb0b85d07, 0xd5d60ab2, 0x1864a72c, 0x98ce9f90, + 0xa51f8ec0, 0xff51f6f8, 0xe58988f5, 0x47ca343d, 0xfd2acd4c, 0x07d2d939, + 0x437671e5, 0x3999ea0e, 0xe7e78bc4, 0x8fe64abe, 0x096a5a1c, 0x4987e008, + 0xde7874ce, 0xcf8cd4b8, 0x76625f5b, 0x3357b5a7, 0xd44f43c6, 0x87be0448, + 0xe7d35c5a, 0x89e3a029, 0x139e12f5, 0xa848cf8b, 0xc4bee6cf, 0x358d64e2, + 0x5a89ee0c, 0x9f72dfa6, 0xe82269b9, 0x956bb9ed, 0x1ead6573, 0xa315742b, + 0xc2c67a9e, 0x5f5e92f4, 0x5154f5e9, 0x76d8aaf5, 0xb1899ee8, 0x2acf50ed, + 0xc0ecaf16, 0x9b13973e, 0x4186a7a2, 0x6941495e, 0x812b99af, 0x89676f9f, + 0x2da14dde, 0x76093e5f, 0xf78ec4b7, 0x9d199503, 0x3f8c094f, 0x19ffe808, + 0x825f0dc1, 0xb0cd143c, 0xc73ffde0, 0x47201e81, 0xdcf1922b, 0x805030b3, + 0x2ef25778, 0xf2d4aee7, 0x7dce72bb, 0x1e244f8b, 0xb22afdb5, 0xdfaa8f12, + 0xf945fffb, 0x47738e96, 0x08b01083, 0xe7b43f50, 0xeeb023e7, 0xe42d79c4, + 0x3b0ac1fe, 0xf7fbf5f2, 0x7c0a599d, 0x8101f33b, 0x644edf80, 0xc3d8155f, + 0x0b8295b2, 0x1f73b3e2, 0xa5cfef60, 0xdfbcc3ef, 0x2fe32dff, 0x902ee7ca, + 0x479ab283, 0x35ff60f7, 0xbfe00b82, 0xfd00aabf, 0x24592289, 0x10e6bed8, + 0xbda823ee, 0x46a3fcc2, 0x39054c59, 0x76625b28, 0xc2b779c2, 0x1e7f0a4f, + 0x9351dfe2, 0x1b90f738, 0x00e77be9, 0x14be0c48, 0x7b110ba7, 0x2e53fc0a, + 0xf43b7e33, 0x1106e492, 0xb27f38b9, 0xfe1567ef, 0x46ff8113, 0xb1aff944, + 0xfc04d726, 0xe0202278, 0xf02e7cb9, 0xefe7f02f, 0xb10cf895, 0x8ba8fda9, + 0x0f9ea7f1, 0xe51ff1db, 0x0af3d03b, 0xa8fc2a7f, 0x46c3c3e7, 0x7de60d32, + 0xae0b52f7, 0xcb6ab723, 0xce4c85b4, 0xb7273cf0, 0x9054beea, 0xcb2342eb, + 0x5af050fb, 0x4279646a, 0x44f5e6ed, 0x675ba9a5, 0x479ba7e6, 0x2a3d8b37, + 0x63cb220f, 0xde71d109, 0xe63cff5c, 0x775e9dd3, 0x6ff45ae8, 0x003e51b6, + 0x93b7affc, 0x0243ee10, 0xeb8a8fa8, 0x1be60f45, 0x3759431a, 0x4aeff6aa, + 0x57fcc4fe, 0xe2ef88ec, 0x3e40e68d, 0xf378bf7d, 0x8e782191, 0xdff988bd, + 0xfd013af2, 0x0f372263, 0x8a3def81, 0x438f2c8d, 0x613c17ef, 0x96f0fb61, + 0xe0e9d62d, 0xecb509b7, 0xbae2af5e, 0x2ab3259b, 0x45b0fbbe, 0xb9e1fa52, + 0x0ce94c8a, 0xfcc355df, 0x294af7d4, 0xbf2d1bf9, 0xdc57fc67, 0x573fa120, + 0x15a1bb5c, 0x0f8af3f2, 0x5bbf719a, 0xf3067b5e, 0x795f738f, 0xd63fdd89, + 0xb2f26a20, 0xd543e5da, 0x51ce788a, 0x798a5f56, 0xe78eb41c, 0x3c75651d, + 0xe607e8ff, 0x657fcceb, 0xa29966fb, 0xdfa6fe70, 0xb09ef039, 0xfc0eb5a6, + 0xfbf6a54e, 0xe5db13f3, 0xe72dd53f, 0x9cd74ff9, 0x631fa820, 0x0a7d3fe7, + 0x947b80ff, 0x27fcda2c, 0x1bf4cb52, 0xac56679d, 0x7e2213ef, 0x3e5f4bd7, + 0x2dbbf90b, 0x167b3f1b, 0x8ff25de6, 0xbc859fcf, 0x09d00a0c, 0xbaf94a7e, + 0x51df3177, 0x85a0ef79, 0xff7e83ef, 0x6d17cc3b, 0x06ecc0fd, 0x4fdbad68, + 0xd1ff83a4, 0x549be1ba, 0x67bd03c8, 0x77c61e7b, 0xb73579ee, 0x6f15892b, + 0x6ff025e3, 0xaaf913a0, 0xd635ba7a, 0xc8fe6237, 0xd0774a69, 0xb6bc9113, + 0x2f9652ba, 0x6cf9e2e8, 0x07e763eb, 0xab5fcbb7, 0x2bbaf1bf, 0x33d63f41, + 0x79a2e13f, 0x3d28076c, 0x1d04ef2f, 0xc57cf3d7, 0x37be6bba, 0xfc34ed8f, + 0x2bebd283, 0xf01f368b, 0xcf39facb, 0xf56d0d3d, 0xb1e61dc9, 0x3f813a85, + 0xd1b8ff25, 0x83c431e2, 0x117c6d1c, 0x7e8107f3, 0xd7d02ef9, 0xbc43a65f, + 0xc614a4f8, 0xbb7844b8, 0x2b7bbf19, 0xca3efede, 0xfbabeb53, 0xf097bf31, + 0x1256e03c, 0x4d7cb1f9, 0x5f2a031e, 0x6ff96763, 0x1f900e9c, 0x73e072e7, + 0xf8c7079e, 0xeb8fc95a, 0x6c6e2f28, 0xe38b267c, 0xd2e8bcf1, 0x3cf21f35, + 0x84dd28b3, 0x43af40d1, 0xa8779bdf, 0x7809c1e0, 0xfbcea518, 0x18879d8c, + 0xd1d4fbc9, 0x7a09e80d, 0x49d7923c, 0xbf213deb, 0x1fbc202f, 0x75b88f2b, + 0x6d17cb15, 0x93dfb495, 0xf2c4e946, 0xebc64740, 0xb9d036e4, 0xad8bcffc, + 0xa9e287e3, 0xc34bbc5f, 0x5abe0a37, 0xefd6c7ce, 0x7f85e3d3, 0xd9ab7bee, + 0x82fbfe82, 0xfbe1e39b, 0x2643fa82, 0xf18bdf82, 0xddf2957d, 0xb5b78f12, + 0x7f3113ac, 0x11aeaab0, 0x7f5ebbf5, 0x1473f194, 0xe38b7cfd, 0x6b2ade99, + 0x65a3f660, 0xa3603da3, 0xd8de5a70, 0xb65d7c82, 0xf20990fe, 0x6ed4f6b1, + 0x03bcb132, 0x3f604726, 0xb7f9aa02, 0x0873bcbc, 0x9f7e73ea, 0x859c7e91, + 0x60f29c7c, 0xd7ca71ec, 0x338cd19f, 0x3933ae5f, 0xef1f176d, 0x66e7a353, + 0x1369f780, 0xad3ea3f3, 0xfac52713, 0x78b6e6be, 0xababef89, 0x3b50fc99, + 0xd93af78a, 0xa24e3dd9, 0xb2fd1e23, 0x0fa3ec7b, 0xf780fdc2, 0x47984dd8, + 0xe792b8b1, 0x3b97fc5d, 0xd8bde80d, 0xf981357e, 0xaafc052e, 0xd392f7f6, + 0x939fc047, 0xd423bcd2, 0xfcca30e7, 0x240c5d4d, 0xb7bf3ea0, 0xfb0aea4f, + 0x7b946253, 0xcdae3cc2, 0x7608cafc, 0xe2cfc9b1, 0x91fce4fb, 0xc9bcf0be, + 0x4c9ddce8, 0x104d36e1, 0x6d9a10dc, 0x7e0cf7cf, 0xd1e0ce24, 0x39095fde, + 0xb3beb0f8, 0x89fa036e, 0x49c84376, 0xa5bb10bb, 0xb8370d29, 0xa632e22e, + 0xe63cea62, 0x8fe43faf, 0xe7df0beb, 0x5b750839, 0xa8db9fa1, 0x61216fb9, + 0xff7751b4, 0x97d03902, 0xe71b1fda, 0x675e2557, 0x70a6ff67, 0x875ef19b, + 0x12a441c4, 0xdd8577d8, 0xe3c4fe87, 0x5f7e0f0e, 0x21037f46, 0xc48921df, + 0xc1f7d5bb, 0xf73571d0, 0x3571d04c, 0xb68f44f5, 0x78c93c9e, 0x49bd9634, + 0x2898f3e6, 0x890f10da, 0x2fee0679, 0xa5fbf27b, 0x989de746, 0x6821dc42, + 0x7986c6bf, 0x64bc54e3, 0x366c3af5, 0xfce9bced, 0x61227a34, 0x606cb350, + 0x773cd4f3, 0xeb809712, 0xd39f68f7, 0x7fea6af9, 0xcdf6e789, 0xefa08c48, + 0x844d716c, 0x06acffe3, 0xde8c4bdf, 0x4cc254a4, 0x4e93cc26, 0x483fbe13, + 0xe3a0ebe0, 0x213bfa6b, 0xd7c6c07a, 0x9d3d21c2, 0x2f06efea, 0xc6b076e7, + 0xfa0a3dea, 0x0577ab26, 0xa766fa26, 0xc3a39e09, 0x0bb05b69, 0x85cca7ea, + 0xad08e4b9, 0xaf8cd50b, 0x2820aefa, 0x2cc37d37, 0x892c858f, 0x1cd53f47, + 0x30cb6447, 0xc88a1ef8, 0x251830d2, 0x5c9fcfc0, 0x94140c8b, 0x35e51971, + 0x3c305efa, 0x128730de, 0x289a0ea1, 0x9ef143fc, 0xaafc61cf, 0x86697deb, + 0x793cb0a1, 0x946caee9, 0x62204bda, 0xeff4a868, 0x4b257bde, 0x9f7b81f9, + 0x0ddfec88, 0xa95ab876, 0xdf0ec553, 0x47c7576b, 0xaa389eea, 0x5933abef, + 0xbfd8785d, 0x424f5974, 0x0af04b1e, 0x7107d056, 0x3cf14bce, 0xeb84942c, + 0x517d98bf, 0x4d7039e6, 0x11f8c4f3, 0xf70a9e2c, 0x47b3f68a, 0x7b46c7be, + 0xd4a6d6bc, 0xf0bfb843, 0xbd47efd6, 0x1fb75a56, 0xa7500ddb, 0xe6e4ef65, + 0x29123d89, 0x79d5ac56, 0x5f809769, 0xa066905b, 0x5ac4bceb, 0xc1a8dbbd, + 0x3c1a13c3, 0xa63d1718, 0x3f63c3c3, 0x3c970f08, 0xa1e218fc, 0x7ca6ebb3, + 0xe94ad031, 0x80c72537, 0x3a8d37f7, 0x0bf8c368, 0x1ed059fd, 0x3aab3871, + 0xd9568ef8, 0x6e3850a7, 0x97f0a380, 0x57c29ef2, 0x1f4df11d, 0xdd94bce2, + 0x9fe5a7eb, 0x0c67ab02, 0xf56b1bc0, 0xe0a5b31c, 0xeebbf1fa, 0xef02be29, + 0x5f28e484, 0x386f9b13, 0x635c277c, 0x55bc73bd, 0x929daf15, 0xa4cc40b3, + 0x5905cdf3, 0x4f5d1918, 0xd2d942ca, 0xc533ae9f, 0xec3cc063, 0x126fab1a, + 0x1e98e38c, 0x48f5510e, 0x70df005d, 0xa38e8c41, 0x76d547c8, 0x2aaf8fb6, + 0xb1160430, 0xe00160f3, 0x59a3f945, 0xc6611fc7, 0x90870d1f, 0x8782ca3f, + 0x54347f18, 0xe7e78f8e, 0xae8fb06a, 0x40a1e126, 0x57d699f7, 0x28bd8cf2, + 0x55c358df, 0x485f283d, 0xfcbcfaf2, 0x33af104b, 0xcf87d262, 0x4757594b, + 0x9bdeadf4, 0xd820f0f9, 0xe033ee67, 0x37829879, 0x2b62dfa5, 0x661cb3cb, + 0xfc03cdf7, 0xde6e8f95, 0xb8dbe403, 0xd798cff7, 0xc377d8e1, 0x31df784e, + 0x15c85295, 0xdf7ab71d, 0xb7bfbc22, 0x4003ae9a, 0x0cb09026, 0x7c63bd76, + 0xe089f930, 0x419efc03, 0x28438f80, 0x77f8eb2f, 0xf0ee5445, 0x56deda3b, + 0x03c3bf76, 0x52079656, 0xc979156d, 0x7d94b0fc, 0xffb04d67, 0xc0625f2a, + 0x0e5029fe, 0x097faf52, 0x1ab6abf6, 0x0a74f935, 0xa27e155d, 0xf70ad49a, + 0xe8955c44, 0x9fe5ae5b, 0x0aa66b24, 0x23def29e, 0x4d9de27e, 0xaed46519, + 0xbb06ef3b, 0xd0a7f94a, 0x53d3b2aa, 0xc0164b06, 0x287f845b, 0x0fa2c67f, + 0x3037ef7d, 0xfe038c1e, 0x0b5d86c2, 0xe8773844, 0xe0b35d2c, 0x3fda3a1e, + 0x362a4acb, 0x12b3f7d2, 0x64f50968, 0xebcaef5e, 0xe7d9583d, 0xa041b723, + 0xb8f157cf, 0x9e562bec, 0x5e746037, 0xbc5cf70a, 0x9d9af1c2, 0xa0bb4566, + 0xa291adc8, 0x8db5ce0f, 0x333b7cfc, 0xba00699c, 0x0c6c7229, 0x6a76421b, + 0x2e8d32b4, 0xbc39e403, 0xe179f7e5, 0xbd23b0bc, 0xec25f573, 0xf3fd3fbb, + 0x1f9f3e46, 0xdd7f5fed, 0x46e0fbee, 0x5c696fc0, 0xd03723f3, 0x9f25d97a, + 0x91769c63, 0xf50aecb5, 0xd4be9e79, 0xf3adffcf, 0x1fe01c27, 0x9e6d7eb6, + 0xfecfcb14, 0xdffccaca, 0xf8e9febd, 0x2177e29e, 0xab2740a9, 0x63342fbf, + 0x55d57e89, 0x8e80f2a8, 0xec0931b2, 0x99c595ab, 0x2bbee9c6, 0xaec7ce54, + 0x5fb8b10a, 0xe833e816, 0xdd8335df, 0xf335fe57, 0x7fe8e28f, 0xc794ee70, + 0x32dec9cf, 0x69db16fa, 0x3b08b7bf, 0xa84acd6f, 0x93ef8468, 0xcf033988, + 0xf688732b, 0xe4acafbe, 0x8f3809ea, 0x479c0c84, 0xbdae9c6e, 0x40346cab, + 0xcc0c9f7b, 0x2a23cc57, 0x23ce8cbf, 0x78c10fab, 0x29701916, 0x194d85e6, + 0xb79ff948, 0xeccc0e7f, 0x426711b7, 0x764fef54, 0xa09de2dd, 0xddaa5bf1, + 0xfedfc7a0, 0x5623bc4e, 0x3675c5fe, 0xfd7b9fc6, 0x03e42f5e, 0xde3cf1e8, + 0xbbb12c25, 0x8f5be3da, 0x15fe3d4f, 0x98f1eabc, 0x427b91f3, 0xe93c0c52, + 0xbf3d12f1, 0xba00ac0c, 0xd1140de4, 0xd074297e, 0xcbf689e3, 0x5f6f7e87, + 0xf9c1fb42, 0x08c2b8ab, 0x43372f76, 0x457fdc20, 0xc22f36ff, 0x257fcc1f, + 0x3748ed5d, 0xe3db5e3d, 0x979f93d1, 0x1edf5d1a, 0x37e617c0, 0x3e400fb9, + 0xc24da359, 0x1c684971, 0xbc7be751, 0x04e4f102, 0xbbef1e1c, 0xaa40c71b, + 0x5762aef8, 0xff2888e2, 0xeb5afb8c, 0x2705e6e7, 0x39ff029e, 0x04b7c12b, + 0xcc44a6e2, 0x8a3a3cc0, 0x3e5ac3bf, 0xcd6bfce3, 0xf8a13e40, 0x0c43b6d4, + 0x664fde07, 0x5d4e79ed, 0xf4cf8ebb, 0xecf857eb, 0xa6307815, 0x3e14be3d, + 0x7ee3689b, 0x13d27779, 0x5b21e4fc, 0xde802446, 0x98a4c126, 0x075188f1, + 0x9c3811bd, 0x051f915f, 0x773c8be2, 0xf427f9f6, 0x8eb51357, 0x1cc0f8aa, + 0x2d9b77d1, 0xf852fe86, 0xb74e4ae3, 0x13bc892b, 0x12574be2, 0x7d9117e3, + 0xfd744640, 0xde3c6cb3, 0x80f483d2, 0xbab2ee75, 0xaf997ed8, 0xea6eb233, + 0xb3dd0256, 0x71d9f8f9, 0x834efc36, 0x112d8d84, 0xbde267fc, 0x2929b235, + 0xf7890f3a, 0x8415e927, 0xf03371f9, 0x178a5cbe, 0x9d1ac172, 0x609b42c7, + 0xf85c7bc4, 0xc6d74e3c, 0xb6df90c9, 0x003df44e, 0xf6116ceb, 0x19f5c10d, + 0xeec1fd43, 0x6f3fdbe9, 0xed0655d8, 0xf6215fb4, 0x2f9ff3e3, 0x7843b8b2, + 0x3ab039bb, 0x94ff63a3, 0x07da358a, 0xe1b22e45, 0x41cbc8bb, 0xcc22c2ce, + 0x53cfc83b, 0xc2299c76, 0x3887a0fd, 0xe1465c97, 0x113b3eed, 0xa973f9f3, + 0x7a7e81ba, 0xb7f3d7be, 0x90279f9e, 0x4f784cf0, 0x363fc7cf, 0xdff1400f, + 0x90737c22, 0xeeca8df2, 0xf942fc29, 0x5d1b79e7, 0x6388db77, 0xfdbb814f, + 0x53cf88ce, 0xfe29eec1, 0xf10fd479, 0x3afd00bc, 0xff15d3f2, 0xf7cd937c, + 0xc233f412, 0x99fbe87a, 0xf8065d03, 0xcd90fe7e, 0x573c32f3, 0xed8b96fc, + 0x232ec837, 0x3be74819, 0xcea1d393, 0x593ef040, 0xf6808179, 0x961276ec, + 0x2bdbbc60, 0x76becd24, 0xc9fc25a6, 0x587e70fd, 0x99ed0039, 0x14fabe0f, + 0x8f967df1, 0x13bfc55c, 0x0fee1819, 0x163bbefb, 0x43c7df6a, 0xbde8acc2, + 0xbed09f9d, 0x6e0092dd, 0x877c0a73, 0xfb6b205b, 0xd657c7eb, 0x7fab87a1, + 0x63df9caf, 0xbb22f704, 0x9fc2fe55, 0x8d8fcc6c, 0x7e2df7cc, 0x37c5018f, + 0xc1b3d5d8, 0xc50f024b, 0xf4a55fe0, 0x8c7b25c5, 0xe6f5a3c3, 0xb1e9e6ed, + 0xc65117ee, 0x833df051, 0xfcf82934, 0x65ff1636, 0xc01c58fb, 0x734844f0, + 0x7d94af4e, 0xdfd013c3, 0xa0275beb, 0x97525d7f, 0xf1a59863, 0xb83ed9f3, + 0xf70f9f9d, 0xfaff405d, 0xafcfcc9d, 0x42fdc4ab, 0xf7db3d49, 0x5cef82ac, + 0x0c89f3ba, 0xb23fff42, 0xa9bc859f, 0x9047b852, 0x53e087b5, 0xacd53ef5, + 0x897db27f, 0xf611b969, 0xc934bea3, 0x5abfeb4d, 0xf747155e, 0xc419554d, + 0x29bee842, 0x27cb57f1, 0xb54d18ae, 0x20479273, 0xb2af5889, 0xfefce98d, + 0xcb57f939, 0xe36596aa, 0xaede2bbe, 0x2476cfda, 0x2e6de71f, 0xfb4763c4, + 0xbc12c7d8, 0x3c5576c9, 0xb3ff4f42, 0xe004ae71, 0x7f7ce5bf, 0x59c2f57d, + 0x0cb06fb8, 0xf90e9f38, 0xee9cd961, 0xb38f3b2e, 0xdcf7d95a, 0x00f4d6e5, + 0x456ba9e8, 0xd9e60b9f, 0xfef9c6f6, 0x6b7e4710, 0xb7dc11e0, 0x8ebdf905, + 0x5e45fcfb, 0x65fabe75, 0x5f67e676, 0x03a3497d, 0x8cd71df6, 0x677e0bfc, + 0xeec8da7e, 0x6d196b4d, 0x4fb9f8d2, 0x032ef2da, 0xd1494af8, 0xce7e8227, + 0x20ebb11e, 0xec8efbd8, 0x780ed444, 0xe403b004, 0x3c54fefc, 0xeddfaa07, + 0x0b65d880, 0x74fd6eff, 0x9dea637d, 0xf0dd2cb4, 0xb7ec0717, 0xcfccedb2, + 0xc26c6d3b, 0x5e4a747b, 0x079ef115, 0x6dea6e3a, 0x9fae5f10, 0x1b10f595, + 0x076d4e26, 0x43afbf09, 0x8caf07f1, 0x2edc0393, 0xbc4d712a, 0xbd5c63df, + 0xda38b1e8, 0xf7a785fb, 0x0f9e3e66, 0x1b922174, 0xd92325dd, 0x3f227e85, + 0x5dbfa1e7, 0x0ef0af70, 0xfebd795e, 0x40af1bf3, 0x4276a266, 0xd7c93f00, + 0x98ef0585, 0xb7fc563e, 0xe36b5f71, 0x527f7a97, 0x83e33bb1, 0x20f49743, + 0x8dd71780, 0x5ec21df8, 0xe94de623, 0xf0bccdfd, 0xcafc0ec4, 0x363f9147, + 0x02b1f7d6, 0x19d9873d, 0x7fd7965f, 0x94aef78e, 0xb834d091, 0x5eaca6ff, + 0xf7c88674, 0x6f25e9e9, 0x6ac1dfc3, 0xe02e4a0b, 0xeee0b6df, 0x6f5021b8, + 0x561e3110, 0x65f64efe, 0x41ad67c0, 0x291fef09, 0x01cc7edf, 0xf3b140fa, + 0x2f7641ad, 0x08f05b49, 0xb6e0573e, 0x065f2436, 0x818367f6, 0xed773fed, + 0xfa0ad6f9, 0x67f3f5e1, 0xabdf7193, 0xff9d69d8, 0x7377c4ab, 0xbe2462ed, + 0x896ff6ab, 0xf2007d98, 0x2412f2a7, 0x7f510a22, 0xfe9d9db5, 0x93b12c88, + 0x823af6f6, 0x8231e27f, 0x77edeb9c, 0xfb3adf04, 0xfb9d88fd, 0x30c8bd8f, + 0xe1afc7b8, 0xfc7cf27c, 0x756833ee, 0x0cf8c22e, 0x76da4ff3, 0x14d8fa7d, + 0x644fbe78, 0x179ffddf, 0xd8dfef91, 0xb377bf31, 0x2af78d4d, 0x6eb9d7a4, + 0xd1b75a67, 0xc776e7fe, 0xd1b578b3, 0xbbfa997d, 0x00ff6883, 0x3ba857c7, + 0xbb92f73b, 0x3f3b7dc3, 0xb70cffda, 0x45eaffbb, 0xb8d2f790, 0xc35044f0, + 0x990e6bfd, 0xb30c5f40, 0x7a625f7b, 0x7a0acea0, 0x7be32640, 0x516e3a10, + 0xfc0f193c, 0x4e24ae15, 0x757bc3c8, 0x7400c1af, 0x0336b119, 0xf1d664f3, + 0x7579c173, 0x950ca6d5, 0xcfc7997e, 0x724a4e95, 0xf9ea927a, 0x03d30770, + 0x3f177727, 0x03f2fa87, 0xc317e933, 0x983b263e, 0x9264dbbd, 0x7e87aca7, + 0xefb80d87, 0xeb67b5d8, 0x6e0fb81e, 0x50d741de, 0x41a737b0, 0x86bc281e, + 0x20aaeb7d, 0x23e1b6cf, 0xbf5416b0, 0x0d1029af, 0xc46ddc74, 0x0764e2c5, + 0x8dffb80c, 0x278917c4, 0x29f9d619, 0xf6dbbfd7, 0x50e7341a, 0xa43df8db, + 0x39d9da1f, 0x8b3b7ed4, 0x3bdc6d53, 0x944ef93e, 0xd001df43, 0x9b47e5ff, + 0x68ae1cab, 0x97f14d5c, 0x38d81cc6, 0xe7fd3065, 0x13831698, 0xb03aedc8, + 0xbaf5845a, 0x25db524e, 0x13fe7690, 0x1a89f785, 0x0616b6de, 0x0de3ce8f, + 0xff055390, 0x3c3f02d4, 0x35b7d688, 0xbf209319, 0xb2bfc14a, 0x577c650e, + 0xb2acf11d, 0x367928a1, 0x577c4f7e, 0xb87cf7b9, 0xa0f72893, 0xb6ce5f23, + 0x3f195a7b, 0x3f50e9c8, 0xfd1e3bb9, 0x9edc4d92, 0xde82b491, 0x4e853f80, + 0x7f660e09, 0x3474f994, 0xbfa73c7e, 0xbe50fe52, 0x64b9275e, 0x1f7e1be4, + 0xc50e4ba0, 0xae3c81f5, 0x77f83e86, 0xae79545a, 0x47c00ef1, 0xd47e368b, + 0xc0306cd0, 0xdb6558f7, 0x66bc4485, 0x6dfe93a4, 0x758ccf84, 0x070d7fc8, + 0x7171ca09, 0xbe2c5ded, 0xf83d4247, 0x5e7858bd, 0xcfc3f20d, 0xb409bbad, + 0xb55c131c, 0x37e207b8, 0x8ab900e4, 0x0dca89e2, 0x26d51594, 0xf779d7e0, + 0x3f2e72b0, 0xd2b79dff, 0x5859f287, 0xfafbf2c3, 0x7cd8323a, 0x4312bf38, + 0xfbc8777c, 0x7fdb8e78, 0x022fde65, 0xa9fad2df, 0x611bc7fa, 0x975fca5c, + 0xdeee203a, 0x3053e8f0, 0x4f5f855d, 0x4e1091ad, 0x7cf6bc51, 0xd74e72fc, + 0x7e300f57, 0x1a46b31f, 0x8d31f70f, 0xe2138991, 0xacd6dbc5, 0x6f7f4115, + 0x60ce7e03, 0xfd760e72, 0xac87eee4, 0x773b04bf, 0x2e2040c8, 0x8a44c9bd, + 0x62e4a836, 0x34d7aad7, 0x5b5c5bf2, 0xdfe30539, 0xe80249cd, 0x156e4579, + 0xb9326fbc, 0x5ffca327, 0x09ff93ab, 0x0e39fdec, 0xb9c79746, 0x893e3ffc, + 0x947d3fca, 0x005126b8, 0xb14c9b38, 0xf69ae9ef, 0xa22ff923, 0xd3b68f57, + 0x6c1cd3ab, 0x43e8ef5f, 0xe6bb2fc7, 0x23ebee2c, 0xf37ce3f3, 0x6f8504f8, + 0x7fc00432, 0x5f60a535, 0x2bc517c0, 0xaffa33f0, 0x32736fa0, 0xf6a1bef1, + 0x3948b8fc, 0x6dc8d397, 0xf229af54, 0x7a022beb, 0x58a84d67, 0x72767e0c, + 0x7a7c8cbe, 0x4ef5f04a, 0x14ed76a2, 0xbd0c73c8, 0xf4c1d130, 0xa7c939c8, + 0xfdbcafb9, 0xe077483c, 0x63ba22eb, 0x1a917583, 0x51f409c1, 0x6c355dda, + 0xc394b15f, 0xf52b9e53, 0x2ff78d1f, 0x9783c5da, 0x333d983a, 0x7fb056c1, + 0x2233d980, 0x20b9478c, 0x83bbab86, 0x76a3cdbc, 0x1d9556ec, 0x2355253b, + 0xf8782abf, 0x73f7e735, 0x57dd6c89, 0x829679f1, 0x673aa7ef, 0xa3041ba2, + 0x145ae4c0, 0x008bbc98, 0xb1eed4ff, 0xafef9193, 0xf3f7cd89, 0xfe42afd7, + 0xc4e49c4c, 0x371e48ef, 0x83892dba, 0x00e3e962, 0xfed6bb96, 0xc059f706, + 0x1df720c7, 0xc81141c9, 0xffc18901, 0x2affca01, 0x407c29fa, 0x8745e2f9, + 0xf9e84f4a, 0x53df3942, 0x7749b2f0, 0xeb8e783e, 0xba5e46f9, 0x5153c83a, + 0xe9a3f3d6, 0xce8ed2dc, 0x473a306f, 0xade80be5, 0x81df89e8, 0x2c74a59c, + 0x9c12fd67, 0x8faa9f38, 0x485e6167, 0xaa273f35, 0xf329e3e3, 0x42f5c03e, + 0x353ce747, 0x1c5fdf56, 0xd748f3ba, 0xe47f28a0, 0xc176bf71, 0xb39e335a, + 0x9e4c206f, 0x01f15de5, 0x4e9e77f5, 0x294c7523, 0x3e808faa, 0x3856891f, + 0x42d77504, 0xc74be913, 0xb051973d, 0x7e6df20b, 0x0fe724d6, 0x60d8eba6, + 0x835ea792, 0x64f701fb, 0xdf393f80, 0x6f7884e0, 0x4029c7a2, 0x0343023c, + 0xd8fb8720, 0xb8fbc338, 0xab7dc32f, 0xf41c3dcb, 0x2f4e69c1, 0x1e0abe85, + 0x1d77b23a, 0x025fb5d1, 0xede3a73f, 0x26f23d7a, 0x38e79b97, 0x47ae2f1e, + 0xc9e41164, 0x448b7c41, 0xd3367f98, 0x923d1183, 0xd01cf04d, 0x9e55c7c1, + 0x509ff52b, 0x5212388f, 0x74647a54, 0x423d4c73, 0x3fe5317f, 0xf41ccd65, + 0xd8c1c967, 0x027a6cfe, 0x6029c7b3, 0x14bf6947, 0xd33dfd99, 0x503edcd3, + 0xc57cc48e, 0x8c6635ea, 0xc87a2be3, 0x878c9531, 0x00eacfbf, 0xa6bd0bbb, + 0x095e0efa, 0x2669b3e7, 0x9f179c17, 0xf748c292, 0x5cc37453, 0x15e1fc8d, + 0xf431de80, 0x85f88111, 0x2c9ed7fc, 0x51062efe, 0x11e4164e, 0xd6bba3b4, + 0x2abe428e, 0x8014cfca, 0x136b8b6f, 0x9a4f6805, 0xbe8034e0, 0x6a31d652, + 0x49fc88a1, 0x824460e5, 0xe4a31e8a, 0xd5f0110a, 0x2697d93b, 0xd6fdd225, + 0x4cfd57af, 0xd0f1bf1d, 0x68b48afa, 0x1fd686fc, 0x7ceb75b4, 0x213726fc, + 0x3fe420f0, 0xe4f0eadc, 0x5635b8c0, 0x59942e6f, 0xce302b5d, 0x88bcd9db, + 0xe52fcb1f, 0x0e444e3c, 0xcecb8bb4, 0x5c6175ac, 0xa7cc1a76, 0xa7f1fbac, + 0x73de1c00, 0x66efd311, 0xf5c2e8f3, 0x2088f902, 0x2b78ba3d, 0x28978844, + 0x384ee77a, 0xf6a14594, 0xa1ae7008, 0x2de81bc8, 0x3c95a7f0, 0xd95b8808, + 0x401f6e31, 0xc27a823e, 0x5a3ea8b0, 0x79886f91, 0x04c2f15f, 0x9faa4fdb, + 0x9beff049, 0x477ca97f, 0x2d3ca228, 0xebe9504c, 0xa70ff3c7, 0x7608f3b2, + 0x7cdddfaf, 0xb916e78c, 0x4ba034ff, 0xa1867ef4, 0xf90c9366, 0x5c43c4a6, + 0xb1fe554e, 0x76421410, 0x56fd63c8, 0x874a1e20, 0x2c456fb6, 0xde3ffb9f, + 0xcfe01949, 0xd4dc1837, 0x0bfc8233, 0x6f770794, 0xd4a7df82, 0x73127bf1, + 0x091e6d1a, 0x1c421de2, 0xa3da8eff, 0x1d18e73d, 0xdb4f5f4e, 0xf8cd0717, + 0x72dafdb7, 0xe0afbf94, 0x1598efc6, 0xe7790efc, 0xd79881f1, 0x8376ac69, + 0x30b6ad9c, 0x2c2dabf8, 0xa2dab76e, 0x004ae7bc, 0x79d1ddbb, 0x1ec2f67b, + 0xe253ff18, 0x90e1d98d, 0x0cc9f808, 0xc92c0cbb, 0x0c678d8d, 0x72b75c13, + 0xf1c75f0e, 0x46ef69bf, 0xd679ec11, 0xb0c5ea84, 0xf763d9ef, 0x6bfa00bd, + 0xdfd6b66c, 0xf3f0211b, 0xf704c9e1, 0x249c8a4b, 0xe09d9337, 0x6c1e24da, + 0x1a0a80f6, 0x13b3d27b, 0x5e0995f6, 0x553c0022, 0x8006cffe, 0x8478ba4b, + 0xdfc0ba6b, 0xfb7fe5eb, 0xb4d9c390, 0x7200bc77, 0x8269a5df, 0x9ed41ae0, + 0xfec257cf, 0x53cb047b, 0xfb2afa01, 0x5e2fdec2, 0xa5f0013a, 0xfae26ff4, + 0x2f9f0afc, 0x74c64217, 0x7718213d, 0x2340f4cc, 0xaa35495c, 0xb9346e48, + 0x4799eb54, 0x668f5e10, 0xedd1d719, 0xca072fa0, 0x1c44b663, 0x10c9ec77, + 0xad74b7e6, 0x43f69020, 0x401d357a, 0x4557aa3f, 0xdcf40093, 0x9c0df7b4, + 0x5da6cf6f, 0xb5f2e4ac, 0xca05fb91, 0x98d98ebc, 0xcfc63cdd, 0x334eaba9, + 0xc12079bb, 0xca4bf987, 0x7c72aa3a, 0xfe141569, 0x19cbc84a, 0xce5e71d1, + 0xb2930491, 0xd608ffdf, 0x79bd3e57, 0x3ea0f00f, 0xefba907e, 0x7523d230, + 0xaf96db21, 0x0040b7dc, 0x4672b17d, 0xa281f8ec, 0xf8f25637, 0xe5ff2aab, + 0x4f4f5a94, 0x66b24829, 0xf292f4aa, 0xfcd153de, 0xff3c4d97, 0x7bcd03e5, + 0x805a9783, 0x79b2ee9f, 0xe573c0ce, 0xe3ad0bef, 0xd947b77f, 0xbaf82acf, + 0x80fcc9c2, 0x1fd70903, 0xc0247383, 0xf1f29393, 0x3cec4b3a, 0x069dcbf2, + 0x7e3077ee, 0x5f8c4d21, 0xff6a1d60, 0xb001bfeb, 0x00d7432f, 0x0000d743, + 0x00088b1f, 0x00000000, 0x7dedff00, 0xd554780b, 0x733ef0b5, 0xc9332666, + 0xe4cc9924, 0x40275e49, 0x21c40a30, 0xeb141021, 0xef0c0124, 0x02415041, + 0x8042120c, 0x2a941324, 0x8065bd6d, 0x8d520318, 0x8bd4b45e, 0xd7a5783a, + 0x2941b622, 0x84ec1a86, 0x3a0bc157, 0x94b62a28, 0xaa54141b, 0xa5ac4090, + 0xd7f97b96, 0x661f7b5a, 0x962264ce, 0xbfefbf62, 0x767e9fff, 0x67d9cfb3, + 0xfbd7b59f, 0x649ecfb1, 0x1258c4ab, 0xdd3b3763, 0xd8c67a65, 0xc1b758be, + 0x88d8c45a, 0x596edf62, 0xb9786c61, 0xda1eb777, 0x3bbf564c, 0x94061136, + 0x6826c733, 0x3dac1dec, 0xa384da0e, 0xb838ce1d, 0xa36adfdf, 0xacfa6e79, + 0x8c2db98b, 0xab98950d, 0x97631065, 0x60d6eff0, 0x31d56a9b, 0x0627f306, + 0xe306254a, 0x6cb8c436, 0xe961bef8, 0x4001b2f5, 0xf1d66449, 0x03631fac, + 0x2b8d0aad, 0x96ee762c, 0xa7563de1, 0x8b79c64b, 0x9ef4ac63, 0x6a771cc6, + 0x1d3e7f3d, 0x4e89679f, 0x37c02269, 0x5b18bfec, 0xfb6ddd03, 0x1065254b, + 0x6f1467be, 0xc0b67319, 0x056057f8, 0x115970a1, 0x9f7c249e, 0x39ebef44, + 0x4acf3bbf, 0x129ceaf0, 0xa8fc324c, 0xe860c7c5, 0x32f5a5f0, 0x02c89fc2, + 0x6d000312, 0x2312d6d5, 0xc6bd37bc, 0xfe61b921, 0xf95c629b, 0x0e635cf8, + 0x6d0a1c5c, 0x0ab7ce89, 0xe7103b9e, 0xf981653c, 0xf668bf17, 0xfa31349e, + 0xd5ff04bb, 0xfa6824b6, 0xef34d69e, 0x7f60bcc9, 0x0d23fe31, 0x4ccfdbfe, + 0x3563186c, 0x407b16fc, 0xef8cdf76, 0x3c7535a9, 0x75fa173a, 0xc8caf8bf, + 0xae0a4960, 0x6578e017, 0x3dcc417f, 0xa77ae096, 0x9977a4f5, 0xbd27a935, + 0xde824a87, 0x4ade8163, 0xb29f7a4f, 0x3b7a0824, 0xfac107db, 0xc24c5de2, + 0x135f01e7, 0x85dc3d39, 0xb788c1ae, 0x380332a5, 0x587a455e, 0x538f4cae, + 0xa71fce16, 0x2a1e9c2c, 0x38c6e61d, 0x75d2b4ef, 0x96f5ef46, 0xbebc3cb2, + 0xdcae8276, 0x16cf8117, 0xee342d59, 0x05fcf1aa, 0x99e287d3, 0xfb6dfdb5, + 0xc1efa10f, 0xf784cb7f, 0xc0378845, 0x583f5c7b, 0xf84ebff7, 0x53f91928, + 0x203aea67, 0xdb6a3e01, 0x25864564, 0x9c954c0c, 0x5b190b27, 0x89cda0f5, + 0x8b5cf07c, 0xf18288e4, 0x6b14c9cc, 0x22564332, 0x75fd9d62, 0x11bb3e7c, + 0x8360b85a, 0xa334de71, 0xcef2136f, 0x8c33c01e, 0x380824f3, 0x001fe01a, + 0x0555a747, 0x0df749cc, 0x559ff2ec, 0xf851fb82, 0x6a4b982f, 0x80976f69, + 0x998aab70, 0xef7000db, 0x1f89936e, 0xf68c6b9f, 0x2ffcc145, 0x607f396d, + 0x3ffbf426, 0xc165c3a8, 0x27eb04df, 0x53a8f831, 0x1cad04ba, 0xc3d3ca67, + 0xed1c877d, 0x4b7c6190, 0x8b3e5c74, 0x3764ac67, 0x955b3f31, 0x7bc0f30b, + 0xd347b556, 0x82e556fa, 0x1f10e47c, 0xd9f8863c, 0x69646b13, 0xe41bbd70, + 0x670dc706, 0xcc8cef1d, 0xbba9d209, 0xbbd9cbf5, 0x189efd60, 0x2627af3e, + 0xde00c7cb, 0x07175dce, 0x5b8f1f20, 0xca35cf36, 0xd924d8ce, 0xafe91ebd, + 0xde66f73e, 0x6f8871c7, 0x5e0832c6, 0x841c9fa2, 0xacde32ef, 0xac72bf1c, + 0xc9d1d69e, 0xeeb81da2, 0x2193a316, 0x39c7bc9d, 0xad78ab7f, 0xd9d1bc13, + 0x0dd47456, 0x68ee7beb, 0xef9f0386, 0xeb36ed6c, 0xe2cb7de0, 0x75c0bfdd, + 0x715d99c9, 0xcf8841ae, 0x063bebee, 0x097a1e91, 0xfc1f77af, 0x741ee6d8, + 0x86dbeb55, 0x7d695fcf, 0x49a5bd1e, 0x3fc9ef8a, 0xb5207ce1, 0xca55ffb5, + 0xa8613927, 0xcc59bcb7, 0xddd60ab7, 0x93487838, 0xc69e848c, 0xc64f9414, + 0x0c9fac2a, 0x2abbd20c, 0xf107b5de, 0x8cd7caac, 0x843ed778, 0x5e93df0b, + 0x8fdceb40, 0xf343fcfd, 0xabba0d0a, 0xc8e1e75a, 0xfe13f4eb, 0x6a7ac56b, + 0x0cbf164d, 0x866db3f0, 0xf9543a2f, 0x5e13dbec, 0x0e31c7a0, 0x1ba8e3af, + 0x8b7bf9e9, 0x43e21563, 0x62bab01f, 0xf8e3fe09, 0x373c563e, 0x21bbd715, + 0x858f69c6, 0x30579bf1, 0xb4520fce, 0xdc5879e3, 0x68b63dd6, 0xf15593d4, + 0xdf3853ee, 0xb3f3ba0d, 0x02c7685d, 0xdc3ddd2e, 0xd7867c0e, 0x7adddd61, + 0xc65ea382, 0xfd62aff9, 0x71f322e7, 0xd9fc3a0f, 0x54e7a21a, 0xf4148cfc, + 0x41f8891d, 0xffa5dc85, 0xc414c3a2, 0x3d4a048f, 0x3e73d6dd, 0x10b23ac6, + 0x9f1df6de, 0xf980e80e, 0x74f8deea, 0xdd6fca36, 0xb888a26f, 0x7d737ea3, + 0xd9f1f23c, 0xc5bd3612, 0x7e9f53d2, 0xa5debcb1, 0x1ffae607, 0xcbd25f6b, + 0x44602c35, 0xb2db5d3b, 0xd10fa5c4, 0xe93100a7, 0xc08683dd, 0x60ff9c04, + 0x0056cc91, 0x863b75df, 0x7a08b0a7, 0x5adf6d5a, 0xb9955cce, 0xf512fd8c, + 0x8ed7f21c, 0x9784f1a1, 0xe3e91b36, 0x9707f1f0, 0x1946bb57, 0xe0ef9f7a, + 0x1f74f310, 0xcc213f3c, 0x8131b90f, 0xa23195db, 0x44e94505, 0x8f6ccf38, + 0xd2e179f5, 0xe2f78299, 0xcce9e018, 0xbd0b77b6, 0x58672fc0, 0x51d7bee0, + 0x30b4be7e, 0x0c267bf4, 0x4570af79, 0x6ede506c, 0xbf6be629, 0x7143b5e5, + 0xb09f8c0a, 0x37a27775, 0x30b77f04, 0xf99797fd, 0xcbdf0737, 0x1df4c7d7, + 0xec1e9003, 0x0ac9d3f5, 0xec7613b4, 0xa07ce44d, 0x4bce90e8, 0x15fade85, + 0x9c111a5e, 0x3ab2c26f, 0x60c2a8d7, 0x9982f6bf, 0xfafb42f9, 0x5f4d1180, + 0x5d0b05ed, 0x26c427b7, 0xc3e8fe92, 0xf8fea0fa, 0xbf0b78b6, 0xe0ede2ae, + 0x6859d390, 0x239acfbf, 0x62edc9f3, 0x4463b75c, 0x1347fa0a, 0xd6fefe8c, + 0xf318e308, 0x75f0b8d1, 0xeddcb9bd, 0x3bdb951a, 0xcc8de37c, 0x1cafc91d, + 0x9afdc09f, 0x7999876e, 0xdbefae41, 0x743b2068, 0xd307e2e8, 0x9f7e810a, + 0x5758306e, 0x9fab3e02, 0xaff19dd9, 0x487abf70, 0xfe825594, 0x3fbf8aa7, + 0x6782f1f2, 0xfbae1764, 0x25f70dd3, 0x73f683cf, 0x801ac7e0, 0x0346c163, + 0xf8deaf5d, 0x5a7eba7d, 0x6782e9f0, 0x9ea20692, 0x4d67b43f, 0xfab3ae32, + 0x13be1fbf, 0xa356c5f5, 0x6810e075, 0xae48b66b, 0xb1722151, 0xa6b305e8, + 0xaac755bf, 0xbaea1d71, 0x7cbee499, 0xbc78015f, 0xba0fdc09, 0x8f65ff6a, + 0x7f017fd6, 0xfdc09bc5, 0x61534995, 0xdd4575dd, 0xdeee27e4, 0xfc764d17, + 0xfc9916b7, 0xbf90ff01, 0xd08de7fc, 0xbd6ffb2f, 0xc1087c83, 0x5e85a3e7, + 0xf48f2c66, 0xf7899550, 0xc9e876cb, 0x958b289f, 0xd07edf09, 0x08c8a313, + 0x61a32d39, 0xe7d4f7dc, 0x46eb91e4, 0xf1d1b8c0, 0xe27e8606, 0x268bfcf7, + 0xb7efd030, 0xd47fd05e, 0x529eb211, 0x23a3d4e6, 0x9a0cc252, 0xe3a3abeb, + 0x08ff479e, 0x1ea3d326, 0xef69332f, 0xee3fee8f, 0xd1bbda34, 0x5575ed56, + 0x39439e7e, 0x83941818, 0xf4fefbdd, 0x675878c4, 0xfb9941d5, 0x33d05763, + 0x72bae16f, 0x566fde91, 0x0ee7816c, 0xba1cec09, 0x1a4369f8, 0xc4b157f2, + 0xd3ff4256, 0x91e5518b, 0xd54622e4, 0x9ce80c37, 0x44f3a417, 0x7dcbc2c7, + 0xc5c98b14, 0x11f72e4b, 0xefaf6ffe, 0xef2e59be, 0xfbd2304e, 0xb861f5c3, + 0xfa577cfc, 0xbd90c270, 0x6a58de59, 0x17ed8e7f, 0x099eb95b, 0xfae18fd7, + 0x1c2b854f, 0xb20bdade, 0x4f8def46, 0x505c6850, 0xfee919ff, 0x3eb38c35, + 0x6710884b, 0x7c267d81, 0x29e98779, 0xe1ff03be, 0x641b8e0c, 0x0025ec51, + 0x6fb58352, 0x25f5ea0c, 0x5e177716, 0x86e97ecf, 0x0c17e851, 0x43acd2dc, + 0x7129d1fd, 0x88366d7a, 0x8283fb16, 0x045fd071, 0xfa131cdf, 0x53a0e200, + 0x2efb6816, 0xc31f632b, 0xcc4ca2fa, 0xbb202e6b, 0x041435ef, 0x7e023fe7, + 0x8d99c60c, 0x9fc78c25, 0xebffdc09, 0xace8a79b, 0xcbc3ff30, 0xc093cead, + 0xa797abcf, 0xf2f2cb52, 0xfbbf4874, 0x6fd06e04, 0xbbbce7c4, 0xa75d69a2, + 0xca3e5724, 0xbe02c3e5, 0x62dc7a70, 0x35dbf953, 0x9a2fd420, 0x5f591a5f, + 0xd3d36f5f, 0x66a792f8, 0x71dfa164, 0x2ceefdaa, 0x00a7a3d4, 0x41da00de, + 0x9bfe23bd, 0x84c785fc, 0xec223e3c, 0x2788bc45, 0x04e4227f, 0xd5b9c7d8, + 0xd174eb82, 0xa7cbd5fd, 0xf2f8fb53, 0xc63f7465, 0x12fc4396, 0x4095e237, + 0xc9dfa05f, 0x83d932b5, 0x80d746f9, 0x49ef7804, 0xd2e28e93, 0xe52deb8f, + 0x9d782cdb, 0xff337c51, 0x509bf1a9, 0xb5cb2e2e, 0xeb6f4758, 0x7576c5bc, + 0x7596bc7a, 0xba5da1c4, 0x00c78fcc, 0x7e41c93b, 0x6fbb2f9c, 0x3c6115b2, + 0xe38c91d3, 0xc060523c, 0xba060a16, 0xaa3f50b2, 0xe2d57fef, 0x8496c5bc, + 0x881b0ef1, 0xcd12d172, 0x9c384eed, 0x1efd05a3, 0xbe08ae5e, 0x88d6a3c8, + 0xddc624be, 0xe822af68, 0xb9e27195, 0x38e71613, 0x42dfd11b, 0x03ad277e, + 0x38eee5f8, 0x0ebc44e7, 0x6c64c371, 0x3cf0a587, 0x558b29cf, 0xe2538bf0, + 0x9a6bb97e, 0xa71e422d, 0x3841bcb7, 0x3c6d671c, 0x4f9e138f, 0x9f355b50, + 0xe7ac4730, 0x26ab04ab, 0x30b4a3cf, 0x423ca467, 0xe348cd9b, 0x394e9d52, + 0xee5de946, 0xf23fba86, 0x992f98ca, 0x4e281cce, 0xda5b2329, 0x36928f31, + 0xf302b7ca, 0xe1098d2c, 0x6335e872, 0x5bafa57e, 0x7185ec97, 0x897701c9, + 0x1ed8e011, 0xa5f04c9f, 0x4815fab0, 0x1d6ea1af, 0x9ee87a2d, 0x06a49f68, + 0x50a4307b, 0x509047e8, 0x655bca33, 0xa441fbac, 0xfacab0f3, 0xf3054655, + 0xf5195e50, 0x9dc969cb, 0x38fe036d, 0xa23a37bd, 0x9b13f75f, 0x6952fbd0, + 0xef0a961f, 0x7840c179, 0x93c2fa18, 0xa1de11b3, 0x97a6dc2f, 0x5ff5e242, + 0xdf040cd8, 0xb28bbde9, 0x30fe7e29, 0xf4e6e58a, 0xe0a3779c, 0xdf02158b, + 0xf3231aaf, 0xdc6233dd, 0x93e9eb55, 0x6b24e7e0, 0xb633f4f4, 0x5d4cbc90, + 0xd3d279ed, 0xf429b03f, 0xb7d37f9e, 0xf803ebec, 0xe64ab7fc, 0x7a2fbc40, + 0xebe52371, 0x8cb6355e, 0xa9eb82dd, 0x07cc31d3, 0x9bf7d9ec, 0x4fd07d7d, + 0xa08654ac, 0xf9f9707f, 0xf11b9b83, 0xb355bffa, 0x34ff8821, 0xe612e3df, + 0x3732be05, 0xdabebe13, 0xc056c514, 0x6e1e1692, 0xe843fb19, 0x31d1afaf, + 0xebe12bd4, 0x74193786, 0x0dfad8a9, 0x7f4e62ba, 0xdd2a7fd4, 0x488cb181, + 0x886e950f, 0x7b67d43f, 0xf046bd36, 0x8f6d70ab, 0x7a2d70e7, 0xe458eb71, + 0x36353e93, 0x2a34f309, 0x9da8ff5c, 0x33f686b8, 0x2572e820, 0x8e1ef9fb, + 0xe19fb70b, 0xc5897376, 0x5dc71479, 0x15ce7ec9, 0xe847b5fc, 0x8f298561, + 0x1d92be60, 0x27de51d4, 0x6c732e9c, 0x9fa3f23d, 0x3f22aeda, 0x8b66c53a, + 0x6cdd1f98, 0xd9b47ae4, 0x894ce6c6, 0x04130f20, 0x5d75babc, 0x898bb446, + 0xbd44526d, 0xf5c2ca74, 0xafcde812, 0x23d3ee49, 0xf808d5eb, 0xff70ec95, + 0x5dfe2dfa, 0xa120aa38, 0x5dba0c7f, 0x3d9d4f80, 0x8f029f14, 0x7c555e2a, + 0x884be2fa, 0x3f0b365f, 0xa4bc7b73, 0xb3aee389, 0x169ce3ab, 0x2f664f7c, + 0xced13afa, 0xedf8039f, 0xa5c4def8, 0x575f934c, 0xf589eaf3, 0x1438c95e, + 0x3ca302cd, 0xbdddb65c, 0xbae300c2, 0xf3c73046, 0xb0af8fd0, 0xb3bea096, + 0x31da3b55, 0x8678deff, 0x971b37e7, 0x9a4adf30, 0x73fff187, 0x2a7ca5f7, + 0xe965dde2, 0xf5d41769, 0x67eabd81, 0x22e570e7, 0xabd9bd5c, 0x8517286b, + 0x17276ff6, 0xd6e891c5, 0x6bf5cf15, 0xebdff184, 0xe2b7ce85, 0xf9d12bf5, + 0x390f510e, 0xfc853f12, 0x6b3f944d, 0xe1ee907e, 0x918e2cf4, 0x7b7cb1fe, + 0x19dcbc4f, 0x276b2f09, 0xb8f4f2e8, 0x88ed164e, 0xda167764, 0xffbcf3bf, + 0xcf527b42, 0x69fc3fbc, 0x56e7e7fc, 0x0ebede3a, 0xa64b7ce1, 0x1fb9e938, + 0x5f311877, 0x55a7e6ac, 0x4b5f3d78, 0xb9fa09cc, 0x5a996bf3, 0x9b5d7af5, + 0x57718854, 0xe48beec9, 0x7fb6771f, 0x6771fe4d, 0xbeac7f98, 0x4f605ef7, + 0xb2d18f94, 0xfcfff885, 0xcbcf1e06, 0x48e9f94c, 0xdfb3c380, 0xf10a7cc0, + 0xb40ff92f, 0x679fe85e, 0xf1c7e1cc, 0x1ec9625b, 0x8f30382e, 0xac5f1cf0, + 0xbe084a63, 0x4cd19c12, 0xbd97c109, 0x27e9a6dc, 0xc668fab9, 0xabef4ca7, + 0xbee69fb9, 0xbd3f7341, 0xcfd340ba, 0x3349bfac, 0xa9597b3e, 0x1de39fa6, + 0xafdf19a7, 0x3f4d76e9, 0xcd6ef9b7, 0xb8e6cdf8, 0xe00ea9e7, 0xc3fa0675, + 0x7ac52b7a, 0x8f7f5baf, 0x97e639e6, 0x992f58fc, 0xf9fdc82f, 0xb1fb31e6, + 0xf229525e, 0x16fbd713, 0xdf9de669, 0xe82fcdac, 0x74bed759, 0x4f9d5fc0, + 0xbfa1f872, 0xfef6bd60, 0x848dd6c2, 0xed3e85cf, 0x6a2fc5f5, 0xa687f9fb, + 0x4c71c40e, 0x7f442aef, 0x6d76d7ee, 0x748ae2be, 0x55775ef6, 0xd54a8e74, + 0x68acd9d2, 0xbf8e1ce9, 0xd85b3c98, 0x37dff87d, 0xa1d62fe0, 0x0aef8be5, + 0x6bb07f7f, 0x621b9cf3, 0xcf51c7dc, 0x952eb775, 0xcbebe619, 0xbbb23d79, + 0x83fccbf5, 0x7d3c844a, 0xfd3c8f6e, 0xbb10f627, 0x3be9e6a6, 0x2372feb1, + 0x97f516fb, 0x3c457fdd, 0x31e58144, 0x8acdff80, 0xf5cba61d, 0x2f307316, + 0xd4bfae1f, 0x5ff7f416, 0x83d7a4ec, 0xf055aa75, 0xf7f8b0f4, 0x5aa7085d, + 0x9eef18c7, 0x88def04b, 0xff808c80, 0xea9d7c2c, 0x4b87803c, 0x12f8cf38, + 0x51c60c5b, 0x4bdcf75b, 0x4b6b0171, 0x480efae4, 0xc43e3a1e, 0xda3d253f, + 0x234cff82, 0xe44c68bb, 0x1894d176, 0xbf31c712, 0xd857bf8d, 0x51e6dec5, + 0xb5bd18eb, 0xea992ed2, 0x8f585d31, 0xfbd7a089, 0xf683fe26, 0xf91e8be5, + 0x4589bed0, 0xf7c27121, 0x7ea1f7bb, 0x26e7bc07, 0x63627bc2, 0x414a6ec1, + 0x98d3f9bb, 0xaeb79238, 0x3aefb203, 0xa4de70b8, 0x0506dbc4, 0xf0e12deb, + 0x9dd9348e, 0xde7d10fa, 0x66ed6926, 0x43f70163, 0x9db9120a, 0xf8f0b2ad, + 0x7be8ac75, 0x4f76fcc2, 0x414f8f13, 0x42dbaa1a, 0x89b1c1fc, 0x5cfe34b1, + 0x5c58c974, 0xdf1146cf, 0xf448e637, 0x224946be, 0x5f1e5efb, 0x75d7163a, + 0x8e525ec1, 0x3e044ae3, 0x046fa2c7, 0x0e5f736d, 0x0df6228f, 0x13ebf3a8, + 0xb6127c61, 0x4d8ed4a5, 0xc83f0ab4, 0xfbd2037a, 0xde93b444, 0x8d65946b, + 0x93b6a55f, 0x2ebaf912, 0x0a2acda2, 0x2168c9ca, 0x1e846337, 0x1471fcc3, + 0xc2739309, 0xde4d64e8, 0x513188f8, 0x7a258de4, 0xbc7489dc, 0xb7b1d055, + 0xcf33b23c, 0x69d507ba, 0xad791e78, 0xd591e799, 0x3c8f733c, 0xc44c63b2, + 0x21d2323c, 0x879416c6, 0xf5978985, 0x9bea0673, 0x278e9cc6, 0x1c7f23c6, + 0x23cf1d92, 0x31bcc7e8, 0xe2b700f9, 0x91f039d0, 0x4ad81b11, 0x7817f433, + 0x1933ca15, 0x2d8b0e20, 0xc3efca08, 0x9f843989, 0xa6fd47c1, 0xfc3fb87c, + 0xf31dab98, 0x31a603ca, 0x66ffaa1b, 0x87165cd6, 0x1606c4fe, 0x29596e31, + 0x64be39e8, 0x9e728c97, 0x12fc05d4, 0x052b1e81, 0x578e403d, 0x77873d20, + 0xeec9bbb9, 0xaa403d08, 0x3da3e30c, 0xc397f23a, 0x57103f9f, 0x7bd230f6, + 0xbe722fb0, 0xc385a2e4, 0xfd718c61, 0xbc1fe704, 0xfa88c3ad, 0x37aa8166, + 0x0f4c752b, 0xe82a9df4, 0xaf037537, 0x978bb353, 0x9faac92e, 0x867e68c5, + 0xb4c160fa, 0x1fe61f58, 0x78e5b416, 0x44972e09, 0xdb4f15f9, 0x17f61761, + 0xc56a1d0c, 0x7bf9d778, 0x47927d26, 0x7ae31a2e, 0x513ecf47, 0xcfd900f5, + 0xdc5baa44, 0xa2eaf82e, 0x41382145, 0x018daf3f, 0xb0d82c3a, 0x53ee1762, + 0x19dfef78, 0xca8e27d5, 0xb270c35d, 0xcb39003b, 0xb3d5b00a, 0x387c028a, + 0x2699e695, 0x0d7ef1e6, 0xdf0535ef, 0x01db477b, 0x0351cf5a, 0x5f809af3, + 0xa5de773a, 0x98dabfa0, 0xff107264, 0x71d7ba8a, 0x1910fdd9, 0x1d577d0f, + 0x2da33682, 0xd606bac6, 0xb8c8cab1, 0x768bab7f, 0x5a27fe20, 0x2fc4f43a, + 0xc47a5d89, 0x674159e3, 0xdfc9f1f4, 0x2744624f, 0xe9c75d39, 0x7df0ad96, + 0x79b5fd23, 0x751377c0, 0x1902fe42, 0xcc627d78, 0xe0154b3b, 0x2aeb03cc, + 0x7f41e9c7, 0x677f8c4f, 0x0ff40e69, 0x4e3f9bae, 0x313dfc0f, 0x732f9dfd, + 0x5adfd440, 0x0fefc557, 0xbecbe77c, 0x5bac0fd0, 0x4cdfefc0, 0x59decfbc, + 0xf30e3d57, 0xd65eeffb, 0x07fe7c0b, 0x57ef2e64, 0xba51cadb, 0xc67148fa, + 0xcf3544b1, 0x1ef80ccc, 0x8eefdb57, 0xa9759da2, 0x41a770f5, 0x8e470f53, + 0x8dbf0131, 0x12c57c17, 0x8c0ec8e3, 0xaf1bf413, 0x18fed3f7, 0xf84fc99d, + 0x58358ebd, 0x5b006f91, 0xf6152eeb, 0xaed07f7c, 0x724bf969, 0xe80cb632, + 0xe256292d, 0x98cb5593, 0x3f768cdb, 0xf1d78758, 0xe1733c3a, 0xd47855fb, + 0x0b80f7f7, 0x85b7ab48, 0xe681b5c2, 0x1ceae151, 0x7945e512, 0x0aa7ed52, + 0xf5d4a757, 0xb7bf262c, 0x013fbda4, 0xdb19d6e9, 0xff412595, 0x4423a4c5, + 0xaea4cec7, 0x48472567, 0xa8e9c0df, 0x38c5727b, 0x19e7bc2f, 0x024ba9d9, + 0xf91946fc, 0x8c26933e, 0x8f3de057, 0x58bdb924, 0x73be03df, 0x32ef91f8, + 0x4687a48d, 0x27e6d50d, 0xcf9c492c, 0x3a3b459a, 0x30feb9aa, 0x9b67a5f0, + 0x78c056c4, 0x236ec5cf, 0x6d8989da, 0x684e8c27, 0x309db6eb, 0xc3aabea2, + 0xb753cc3e, 0x6f5118c1, 0x7992486d, 0x0fcc329e, 0xe0399bde, 0xc7dc44a1, + 0x45512950, 0x091ddeee, 0xef7fb1a3, 0xf8255c5c, 0x8eb7232d, 0xb966c7c6, + 0x76c21fda, 0x8bd8eb0e, 0x2dc3342c, 0x99d2fc6b, 0xbf1a31d5, 0x5dbd5676, + 0x0cd39fd3, 0x9eb901d4, 0x1b5d2cb3, 0x5b88303f, 0x2c199e01, 0x6dfa87f8, + 0x8ce3a0ba, 0xdc01b5d4, 0x6dc332c7, 0xcc8476f0, 0x856db137, 0xd77086de, + 0xbf520e4b, 0x73e0a65e, 0xa10af933, 0xeb437bd5, 0x795ba362, 0x86aea332, + 0xd815fbfb, 0x5456bc07, 0x42453e4b, 0xbee9183c, 0xfba255a7, 0x47c7d69e, + 0xcf323ee1, 0x26f28952, 0x3c447dc9, 0x1cefec24, 0x51e82b01, 0xf333ce03, + 0xa3b312fb, 0xbefe10de, 0xe99cff0a, 0x3f89a7e5, 0xaeaf9f85, 0x7602ba73, + 0xc9cfae17, 0xfe80c4fe, 0x64efac35, 0xda9f0687, 0x6d7aacfe, 0x6d32ce7f, + 0xf0926a7f, 0x81b207df, 0x93d34f28, 0x55ea3d24, 0xe645ffb5, 0x01f96ffb, + 0x6bb2cd9e, 0x8d67f226, 0xa8f54fd1, 0xfa9bb2cd, 0x5eb87dea, 0xc0ee48c7, + 0x9639201f, 0x19573e48, 0xf412d69c, 0xe2256ba3, 0xc42c99db, 0x8e09c85f, + 0xb3dcbea7, 0xd71268ff, 0xaeccab3b, 0xdb1754a5, 0xc1375929, 0xa77a51a5, + 0x55c0fd1e, 0xc8bce452, 0xdedc4963, 0x8a20c5be, 0x2006b807, 0x9f5da293, + 0xc2f3ef1a, 0x76fc077b, 0xfbfd17ae, 0x07c08501, 0xb73dca0a, 0xbd85e337, + 0x25fe0499, 0xe4037ffa, 0xdfa4e996, 0x495a346f, 0xa43b0bbf, 0x2fe70bea, + 0x7c6876b4, 0x3f8a7ec6, 0x7b5fad26, 0xff62f50e, 0xc782ce7e, 0xcc47be01, + 0xec8ffdfc, 0x2fb87c90, 0x3ed06ea7, 0xc0299fd2, 0xbadef816, 0x5b47a154, + 0x52aefbb5, 0x2e61af50, 0x7a20c27f, 0xe5499a6f, 0x41e92776, 0xbbaa5fc9, + 0x4529fa04, 0x0ca6f7bc, 0xbc95f085, 0x75c245a8, 0x0aef3267, 0x463fe3b4, + 0xb60a4c21, 0x8fcfed57, 0x79fdc292, 0x65e6124b, 0x148c3b52, 0xe32eb1ef, + 0xeba7943f, 0xf2327f39, 0xb0fcf859, 0x0757aa7c, 0x718bf2e3, 0x77b9af98, + 0xdc6fbf67, 0xb49b24ef, 0xaac1b771, 0xe7c7bb8d, 0x44cff569, 0x4cef5687, + 0xb9a7ee2e, 0x5039c53f, 0x796a7f73, 0x877fa6a1, 0xf8cd66eb, 0x6997a6bb, + 0xe3a951fa, 0xda00f2c2, 0x9e4c4afc, 0xeb12bf36, 0xa251e6d0, 0xba7afc0e, + 0x9a317804, 0xc06e1dbc, 0x46c81343, 0x47682db1, 0xa899c606, 0x685d1b48, + 0x34db60b6, 0x7c8fca24, 0xc787d4d2, 0xbe0751e1, 0x7987ea9f, 0x4c5bf14c, + 0x49788a58, 0x8a6295f2, 0x7544d018, 0xd41e1bd5, 0xd3d39bfa, 0xeda95cb8, + 0x99f724b1, 0xbc1bac64, 0x7f73a4a8, 0x89f14036, 0xbf719a29, 0xfc89bb68, + 0xbe4e3522, 0x9465a71c, 0x0eba409c, 0xf549d07a, 0xaccad613, 0xde7c5798, + 0xdba9f228, 0x41dc3ef9, 0x673a1dad, 0x492f7c88, 0x49e0fae6, 0x9c58e957, + 0xac0daebf, 0xfad3ca2c, 0xa7588c8f, 0x8f6b6bac, 0xef967b43, 0x7988c8fa, + 0x6175e0bb, 0xd15df4e7, 0x55f95f58, 0xff711c8b, 0xf7cc92b2, 0x7a13ec6b, + 0x83f7d67d, 0xb0c951f1, 0xb59e7ea0, 0xc32fcbb5, 0x5e8167fb, 0x4a6bf2f3, + 0xfa0d3d24, 0x3ccf1359, 0xa7eea699, 0xc1ec6a71, 0x037ec5dd, 0xed6a9fd9, + 0x78d339f8, 0x5c7a045c, 0x91a33d7b, 0x1d630bf4, 0x815bcc06, 0x8fdcd75e, + 0xd271164b, 0x12e83640, 0xaea381e8, 0x2bb5fbc8, 0xc744f4d3, 0xa232eea3, + 0x4f8093c3, 0xec9f97f4, 0xd78e3f81, 0x65ede12b, 0xfa1081e4, 0x4fab8f85, + 0xcbf47ee3, 0x07ede8bd, 0x979f7d04, 0x54a80502, 0xe268ae3d, 0xb9a699df, + 0xf73f718b, 0x1aafccbe, 0xeb315eb1, 0x7b4312d7, 0x03f687fb, 0xb8cf8fb4, + 0xee326f75, 0xecb4f4af, 0x7fc0664d, 0x05650635, 0x1fc0f3fa, 0xea7ff40e, + 0x7f04fd5a, 0x3b614b6d, 0x956daf5e, 0x3d92a81c, 0xa18dcedb, 0x468eb275, + 0xdf3dffac, 0x93235c0b, 0x5b755fb9, 0x04f3c2b2, 0xda27786e, 0x3e516dfd, + 0x00fc849f, 0xdae109fa, 0xe866b121, 0x14dabf3f, 0xa0fbeeb1, 0xd59ef7c0, + 0x6ab38a46, 0xc75c79e0, 0x467dccbe, 0x56d3f213, 0xeb849758, 0x0c477c38, + 0xc0d4bfce, 0xe150cfd0, 0x3819933b, 0xb0ffeb8e, 0xb81d0212, 0x2652aabe, + 0x54b87f7c, 0x9fe723e4, 0xb8c74c6a, 0x77ef96a6, 0x4dd95ddf, 0xab0fbe79, + 0x36569fb9, 0x397240df, 0x57f70963, 0xe55af9c2, 0x9f05a7db, 0x386ff386, + 0xd7e0f6df, 0xd7e3abea, 0xe6bf20ca, 0xfa07dda3, 0x3e414e8f, 0xeeff01fa, + 0xddc5fa65, 0xbb801486, 0x81d5a36f, 0xcb06bdfb, 0x519287be, 0xf7e6ec6f, + 0x946cd487, 0xee51feb8, 0x37a5f5c6, 0x091ad919, 0xedd389f9, 0x85374101, + 0x14314975, 0xa2fa05ff, 0xbf51ca9e, 0xe9b03087, 0xa73f315b, 0xf067fae7, + 0xd71ba96b, 0x6e6ff084, 0x555be732, 0x32340e2f, 0x07aa56f7, 0x0299f4b4, + 0xe06cbcf3, 0x312c9cf5, 0xaebf6e5f, 0x5da05331, 0xe4f5cc9f, 0xda87010a, + 0x80e4275f, 0xf84ddc65, 0xf8e2689c, 0x5fccb71f, 0x99f8eb81, 0xea30fdd1, + 0xef5909d5, 0x6bdda0d7, 0x20e6fbea, 0x07321fca, 0xbc6ae1f9, 0xa7c47bbe, + 0xf583ee1b, 0x268faf9a, 0x3e779afa, 0x367e456e, 0x714d0ee7, 0xb53fe047, + 0x61c85cf5, 0xd5f03b6e, 0xaad47e85, 0x4ebb29fd, 0x729f691b, 0x2431b9db, + 0xe8d2172f, 0x535cfaba, 0xc1cf971a, 0x9aa83f62, 0xadbd04cf, 0x8e082e2f, + 0x70c0f153, 0xc2115e77, 0xebd102f3, 0x086c25be, 0x4e3fab4f, 0x73599feb, + 0xf30b9a58, 0x1a7065dc, 0xf7ef802c, 0xc62fa7e3, 0x2e6f2ffd, 0x851dcc67, + 0xcc4ceffb, 0x03ee1d7d, 0xb03f52b4, 0xeffa953c, 0xdda8572c, 0x84bd7262, + 0x4f63ba78, 0xabed2e7d, 0x55ca7ccc, 0x3ce9ef0a, 0x053b1068, 0xa827e44d, + 0x36eea1f5, 0x7ee09999, 0xea8936f7, 0xb3fc2a9d, 0x3733a42f, 0xe3df97e8, + 0xdac1e0fb, 0xde92ef65, 0x1b9f5473, 0x90d27183, 0xd88d139a, 0xf3fb2cf7, + 0x8e2ff418, 0x3e413d83, 0xa59fbf03, 0x0e4fa84a, 0x5ddf711b, 0xcd3b05c5, + 0x6baeb2f3, 0xf79dca0c, 0x50ea890d, 0x19cf5bc7, 0x62bdb853, 0x5806ca08, + 0xffe0139f, 0xeb813922, 0x3a21b693, 0xdca1df4e, 0xd0fc11af, 0x71d7c37e, + 0x32d30f48, 0xf19bede5, 0x4332fdf9, 0xda535eb9, 0xa08d6715, 0xbcc28f87, + 0x75c15c98, 0x7f7e1b60, 0xeb9bd1ba, 0xeba6e780, 0xfa9bef22, 0xbe72f92c, + 0xff14e482, 0x0ab7e024, 0x60b36fc1, 0x8a36f149, 0x20d1fc83, 0xcadab3cf, + 0xadb1eb4e, 0xda47d897, 0x147d8cf8, 0xc6f7c7e2, 0xadb6df87, 0x8372f9c3, + 0x59238c7d, 0x71845f88, 0xdfbcd324, 0x994cf3cb, 0x11dc53fd, 0x0e5979d6, + 0x03bfc03a, 0xe381d57a, 0xdf91d8a4, 0x767b5207, 0xca0ac3c7, 0xebba298f, + 0x6c17b429, 0x8ee28e80, 0x1fd6af5a, 0xe5ca963a, 0xc0aa58e1, 0x7e368a5b, + 0x4e493882, 0x1c5271e1, 0xe2438416, 0x14ebf0a7, 0xae50993f, 0x8103bde0, + 0xa244af3e, 0x29a96a4f, 0xabe50925, 0x019cf899, 0x857f239f, 0x229ed3af, + 0xae42d9f2, 0x235ca067, 0xb972b6ff, 0x3bb79f0e, 0xf38ec4b5, 0x5c7dc6ae, + 0x69c6f411, 0xf5daceb1, 0xb3cbe112, 0x3a784ede, 0x4abbd6c3, 0x00cf2f81, + 0xa02fb81c, 0x498ae5d3, 0xdb8d7ac0, 0x04b36315, 0xfadd40f5, 0x756e7a18, + 0x73eddbff, 0xc2979fa1, 0x6b6cfef9, 0x3cf10999, 0x3f973d7b, 0xfdc77df5, + 0x4f28ec33, 0xa32e8645, 0xb467ee03, 0x3f43889d, 0x54c768b0, 0x6f61ca3b, + 0x70a86670, 0xf16fbb2e, 0x07e73b49, 0xf5aa6fcc, 0xbf4acf38, 0x78bff111, + 0x6dfe2319, 0x3a87fedf, 0x6db3e394, 0x87b45631, 0x78c67667, 0xbe77ff51, + 0x49d3e511, 0xe3788714, 0x319daf41, 0x7f224c74, 0xc56c8773, 0xc6f3d1f8, + 0x3ca14fe7, 0xa147b67a, 0xb716c7e7, 0xed0e7c3d, 0xd8db4d5e, 0xda7cfad3, + 0x954ffe87, 0xf765da87, 0xfed57ad3, 0x0a4dcbe7, 0x7ab3d1ea, 0xb71627ae, + 0xeffe4abe, 0xf9dd8be2, 0xb33f0f58, 0x50c36ff3, 0xdb7e79af, 0x99f50c3d, + 0x61eef5e7, 0x5af3df78, 0xbf247d4c, 0xf3c697c5, 0xccbdaa40, 0xe4d7a239, + 0x5d85a28b, 0x2e6869c8, 0x459d7dc7, 0x3039a787, 0x2fdeab9f, 0x7ed1d5ca, + 0x46f7a2fe, 0x3c87e7d9, 0x97d010d7, 0x87a1f5e3, 0x8654c547, 0x41aa65f2, + 0x555e37cd, 0xeaef079e, 0x75e48587, 0x19a73a02, 0xe80eadc6, 0x6adafef9, + 0x06f187c9, 0xcfe12ff8, 0xb9d53f91, 0x435beed0, 0xfc6b827e, 0xcfd8a1e0, + 0x5051ac75, 0xf6f698ad, 0x6697f10f, 0x28fe7404, 0x6de9a3e0, 0xf7f27e51, + 0xd413fa03, 0xecd47e17, 0xe6c69f73, 0x34f21148, 0x468cef79, 0xaf9e1e3d, + 0x8458bf81, 0xdeaff55b, 0xa3f9e34f, 0x0eab7a8c, 0x345667f7, 0xb5e22b30, + 0xfa675e47, 0x0a2f946d, 0x8128efcf, 0x4e7c2675, 0x22b3afe9, 0x8a5faabc, + 0x4116dc74, 0x72a6240f, 0xaf9544bf, 0xe88e8086, 0x352810d3, 0x563687f5, + 0xab36d7c8, 0x68f7be8e, 0x09ba9b68, 0x170d0bf3, 0x0c198aef, 0x723869ef, + 0x3defc33b, 0xa6a5ad3a, 0xe2ee7c5c, 0x063ba66d, 0xfc26f905, 0xb852c77d, + 0x0bfa0cde, 0x21dfed91, 0x59fecfa1, 0x8a40f076, 0xff3de44e, 0x1083b6ef, + 0x7852079f, 0xe7933e7c, 0x1e7c784f, 0xbd543f6e, 0x092bceac, 0xcbd4f73a, + 0x81cfc9a7, 0xb2f49a38, 0xb8d0aa94, 0x7629b68c, 0x4c8faf8a, 0x9e962bb3, + 0x3bd3f7f3, 0x3d41b674, 0x39fd57e7, 0xd7b9d78f, 0x938f7184, 0x4cf323ef, + 0xaddf6893, 0x5c79ffea, 0x9ee5f912, 0xc70f830a, 0xa60570a9, 0x1dec7cf1, + 0x2ccf834e, 0xd544fd05, 0xdf7cbc8f, 0xd57dd121, 0xc7fd54af, 0x77e78b80, + 0xf7e50da7, 0x17dc98b7, 0xf71f2ed0, 0xd17ae99b, 0x319d7e08, 0xab8c5ed7, + 0x6253baee, 0x5f8407a4, 0xb869f2a9, 0xadbe79df, 0xa3ee37df, 0x53f820df, + 0x30acb395, 0x58ed50f9, 0xc7970a5e, 0x85e3b43a, 0xaaffc768, 0xe7c3cff1, + 0x496e3b05, 0x3d18e7a5, 0xbd3df43f, 0xfebc522b, 0x0ca790ac, 0x3d817e95, + 0x266f0825, 0xd83ed00b, 0x7c6becde, 0xded7971a, 0xb909e7ee, 0xdf3c92b9, + 0x3fccf426, 0x52cb9e4b, 0xb5f877ff, 0x5ec3fd97, 0x2cfbc7be, 0x2a4264b5, + 0xae5a35e0, 0xfca0940f, 0x6221a7fd, 0xd85d3add, 0x3577886b, 0x699bd9f4, + 0xe47c61d4, 0x83f9e6a9, 0x6de504a6, 0xc80e638a, 0x317b3fb4, 0xc7e883c4, + 0x4090ba2d, 0xcbfa0d6d, 0xf17cced0, 0x6623d530, 0x6fe16b56, 0x3e2e9cc2, + 0x87c724bf, 0x362cf3fe, 0xb34cf28a, 0xb8ac12da, 0xa929b9df, 0x95ca1f65, + 0x6cac9377, 0x50bf1d0a, 0x79e26f1d, 0xb46965b8, 0xf98592bf, 0xc3eab303, + 0x7fad7efd, 0x1bc8b370, 0xbc27e6f5, 0x7ae66ede, 0x724cbf65, 0xa6f9875e, + 0xb633191b, 0x59e0bd71, 0x7524f3c6, 0x7be82b6d, 0xff715aac, 0xf2807d33, + 0x835f5450, 0x1edba7a1, 0x6479464f, 0xa93d6d4e, 0x48f785f6, 0x95d7865f, + 0x5eb8db6c, 0xa2c8d4f2, 0xc24c348e, 0x93c42d7e, 0x2a5fe829, 0x3bc464ca, + 0x57d9a5c0, 0xcf05faa6, 0xf9d2ba8b, 0x1c531ffd, 0x2f47733a, 0x71a6a475, + 0xf6248ebc, 0x23acf46f, 0xae9bdbed, 0x548eb95c, 0x80d87ad7, 0xea95c5f1, + 0x5ea4cf49, 0xde5127ae, 0xf3cf5b31, 0x926dd9bb, 0xd955f315, 0xc3dd7c6d, + 0x7f934757, 0x958fe63d, 0x2a07d476, 0xe14ece9d, 0xe1fb3df8, 0x75b42597, + 0xab7a8fe0, 0xfaf5d619, 0x4ddf4b87, 0xa4c57de7, 0x634b73e0, 0x3fe9bbe8, + 0xf8831bde, 0xa45a1d7d, 0xf5476bcf, 0xc193f391, 0xa92bf57c, 0xf9167794, + 0xc3d83d6a, 0x275e60d8, 0x855bb9fc, 0x70826bbe, 0x3b9af285, 0x29bfdd78, + 0xfa8e3dcd, 0x36cbeb3f, 0xa4e89f91, 0xc0abf47c, 0x1a3798d7, 0xbac58b08, + 0x59a32ff4, 0x9a91d603, 0x926fdc92, 0xa74cfd1c, 0xf3c11ca0, 0x6ef27f54, + 0x623ec855, 0x3ceb0bea, 0x858046f9, 0x7df03bf6, 0x3a083713, 0x8b3c41a6, + 0x33402571, 0x03d0eb0d, 0x3f27bd45, 0xfe71e99a, 0x35ee0c47, 0xa97d63d7, + 0x4158ef5d, 0x4fb0e042, 0x7759ed89, 0x5ebc9c92, 0xd49fd6ae, 0xf56f79ba, + 0x93df0927, 0xea8ff9cf, 0x9cff624d, 0x7762675a, 0xb5f8a8ba, 0x619eb8aa, + 0x832c3afc, 0xd2faeb5d, 0xd42392df, 0x4c294c7f, 0x7ada67f8, 0x57bc9ae3, + 0xdeff4f88, 0xa96de33a, 0x1efb1fec, 0x0adc07a6, 0x0c322eff, 0xe709a1ee, + 0xfaee2993, 0x91c4bfef, 0x26eb6d9d, 0x15d9d87b, 0x7f9402c5, 0xf779e0ec, + 0x503dfe36, 0x496fc427, 0x7e767621, 0x57779f0a, 0xfff1195b, 0x18a8c0b6, + 0x0a58ff1c, 0x23eac7a7, 0xbfa2a6d3, 0x69e80def, 0x3c630ebf, 0xd016db1e, + 0x72dfa117, 0x9a92e90d, 0xd12e891a, 0xcb853edc, 0x7f6121d1, 0xba72a50f, + 0xe3c87d95, 0x5e52cf30, 0xbd0ab15f, 0x75e7a9e0, 0xc9997df5, 0x4f4f9a92, + 0xd97f5489, 0x637645d1, 0xf68942d6, 0xfadb7ed5, 0x916913cb, 0x5b33f1eb, + 0xbfae444f, 0xfd218f94, 0x3b3e5bd9, 0x4b7d8f3c, 0x0f63c89a, 0x5fec79e6, + 0xbd695aa5, 0x2521fab6, 0xfaeab2c8, 0xbe1d21af, 0x87408b48, 0x5c7f386b, + 0xdf5b77fa, 0x7d5230fd, 0x6fce1af7, 0xe16efe4b, 0xa7e92257, 0xf3bf386b, + 0xfd7f9e3b, 0x8aff3c77, 0x77ff18ef, 0xff9844a5, 0x01fdd5ff, 0xf0fff5e1, + 0xfbe102fd, 0xcc0ea200, 0x87bde2f7, 0x7e5db5a5, 0xdb714d68, 0x07a04ba7, + 0x982f09f5, 0x184e8ed0, 0xab61ebc1, 0x1b7c9947, 0x01bee0a5, 0x832c5f15, + 0x41d611c7, 0xc076bce7, 0x30339673, 0xb2f98eca, 0xe0e28c11, 0x8baf334e, + 0x6d35bd31, 0xb7c3ed0a, 0x7e0edda6, 0xdf2f5349, 0x174e6d33, 0x762f6171, + 0xc9466464, 0xacefa867, 0xd5a5fb61, 0x6aea29d6, 0x0fbe56d6, 0xb495e997, + 0x4abde9db, 0xf143fa1a, 0x38f5f87b, 0x246e733f, 0xdb9c94b8, 0x72541e29, + 0x4427be10, 0x6e36d7fd, 0xa5e60e40, 0x6217e06d, 0xac71f05d, 0x6b3c520f, + 0xfbea71a5, 0xbf87d87e, 0x930309ef, 0xbdeb9eb0, 0x6273ef9e, 0x5d4d6a96, + 0x7fc1a0ef, 0x7544ae72, 0x8c0fb93d, 0x0ff3a43f, 0x30473e7a, 0xd077e031, + 0x1bd52b36, 0x1ff11adf, 0x26bbfc79, 0xcfbbe75e, 0xc6ec87ca, 0xb8e019b8, + 0xf121676f, 0x235dccef, 0xf8c0a83e, 0x2f3f3fa3, 0x295c47a4, 0x454705f2, + 0x17cd43be, 0x63adf5a8, 0x1c724f22, 0x76d02ff3, 0x5a043e60, 0x5aee8fa5, + 0x4fa527db, 0x84f2fd04, 0xde43f3c4, 0x543f3c43, 0x0bf47468, 0xb8394fdd, + 0xb9abe70f, 0x50bf5e7e, 0xc59b3df3, 0x207f0a7a, 0x2fc0a3fb, 0x6c1c6c2d, + 0xd85f3b44, 0x6d8d1998, 0xc3a7d3be, 0xca8cef52, 0x7e953aad, 0xb868f891, + 0xfdeae758, 0x7bdf545d, 0xffeeac35, 0x3f7c3ec3, 0xc7e0b743, 0xd461f61f, + 0xbf572fbf, 0xf8c7dd0a, 0x52395691, 0xc416695d, 0xdce708c5, 0x8ab70e26, + 0xa57e59ef, 0x6273df0c, 0xb623576f, 0x6539d505, 0x39af7794, 0x9bfe88d7, + 0xbef762e7, 0x665f295b, 0x989e3054, 0xbbcda1dd, 0xfe7832d9, 0x7f8955fd, + 0xab1de9af, 0x70b8f8a7, 0xc7f89eac, 0xf14ccb36, 0x64c0cdab, 0x70a7f60b, + 0x3ca0a8bf, 0x6cfb0cb1, 0x83f9025a, 0x8495fb05, 0x798283f9, 0xa5d8db30, + 0x2ba78849, 0x7cd559d5, 0x739316da, 0xeff3d23a, 0x1ed6b3ad, 0x4dfb423c, + 0x78a975d5, 0xbda5eb51, 0x7dd559d5, 0x2ff29e0f, 0x3c34fb35, 0x9831aefa, + 0x79dc2c7f, 0x5ff628c2, 0x8273535a, 0x1dc2d875, 0xaafea8e7, 0xf53d5bd6, + 0x86afc8e7, 0x929ce8e7, 0xfd79cb6d, 0x81c03b75, 0xdbac2b6d, 0x06fcf009, + 0x1b6d8dd6, 0xbfaf1bac, 0x5a8f3cb1, 0xb50772ff, 0x531796bb, 0x93ec085b, + 0xedbac366, 0x2edbaa39, 0xdf63d3ef, 0x36f5d524, 0x2895aecb, 0x3f7521ef, + 0xfdd787ea, 0xaf9e68e4, 0xd037ecf1, 0x839e0c77, 0x25dfd226, 0x31b3736d, + 0xb0eaf83e, 0xaee11b3b, 0x085bbac3, 0x3a759c5f, 0xc66e78cc, 0x8cc39759, + 0xf6c2b6f5, 0x0fdc46d3, 0x180fa753, 0x90061f31, 0x4596e3a7, 0x7c73b6cf, + 0x895b6fdf, 0xc57bf119, 0xffeb58fa, 0x3dfd8faf, 0xa0acb1f5, 0x291e927c, + 0x1b9ce970, 0x34efddb1, 0x13d10fcf, 0x9ebc5dab, 0x5f7fbab2, 0xae75c392, + 0x219509be, 0xf39435f3, 0x6c6d85fc, 0xf5e8737f, 0x1e061925, 0x4239e047, + 0x41ffde11, 0x8e35dd1f, 0xf41fdd5f, 0x9d57e089, 0xefa2643d, 0x2c77da49, + 0xc418eec8, 0x1f343f05, 0x32bcbab7, 0xf7cfbf1b, 0xb9628d1e, 0xc9a75f3c, + 0xbab0b1c7, 0xb9796f5c, 0xa73ae599, 0x750bf699, 0x0edda165, 0x7d319fcf, + 0xebb71657, 0x9e7e74ce, 0x159d3783, 0xb9f51eb3, 0x7bdf33df, 0x8cfc61fd, + 0x0bd91d72, 0x50574eb5, 0x81cb67ae, 0x19960b3f, 0x2b9f547c, 0xfba09fd7, + 0xb06c6e22, 0x9f23a416, 0xb4683f1f, 0x3c2d5e62, 0x7f28e63f, 0x3c2fa9a1, + 0x1c91a8ef, 0xd52bacb8, 0xe07dd4f1, 0x47db5ab3, 0x086dbe63, 0x051a6e6b, + 0xafe90fcf, 0xe9fee2b3, 0xbe3cf59e, 0xf840bbff, 0x3679e139, 0x4bf433e4, + 0x71f0f3c2, 0xe20f9ce9, 0x9cfdb9d2, 0x0a2db480, 0x173ea3ce, 0xd2f33fce, + 0xf0bf75b5, 0xfdc553fb, 0xd582f286, 0x13be91fd, 0x49ed0c74, 0xa9a97943, + 0x397cc87f, 0xdb7f7ce9, 0x4c1f5813, 0xf20fad0c, 0x5d78603a, 0x8573d550, + 0x831d7fed, 0xfa075ef8, 0x2798ed1a, 0x0a0fd795, 0x8fd928df, 0xa708237a, + 0x7a953fd8, 0x04ec7bf9, 0x70c5d7c6, 0xa7779cff, 0x82b9f944, 0x8aee5f09, + 0x81733e81, 0x76bd43dd, 0x0b2affb0, 0xfa09a3ea, 0xc7aefc22, 0xd72e92e3, + 0x349eb099, 0x71eaedf5, 0xe1419df8, 0x230e431d, 0x30a8ee5d, 0xd540fed0, + 0x7b7d4dee, 0x7f7e18fa, 0xbc68cae3, 0xcc39279f, 0x2f2f5e0a, 0xb7e3ebc5, + 0xce9331f8, 0xa0742226, 0x4f0703cf, 0xb66e51ea, 0x1825dc98, 0x114e173f, + 0x6e0aa675, 0x9b68efa7, 0xe7e46062, 0xeee6ed69, 0x1f28afcc, 0x4856ddd4, + 0xee3b23f5, 0xb414187f, 0xc13b8537, 0x3b5ec58e, 0xdd2f363b, 0x11bcf84a, + 0x63c218ec, 0xf4ebc29b, 0x11cff4e1, 0x2ecdeff4, 0xd187a6f5, 0x2b39e0fe, + 0x6a529f28, 0x60ae3b4f, 0xfa3867de, 0xc21e12eb, 0x35ff2bd2, 0xd096fd0b, + 0x4eb73f8b, 0xfbaf7bf0, 0x39ff5aa7, 0xf4e6a675, 0x63751dff, 0xeb52fe35, + 0x76bc6a4d, 0xda81f046, 0x3fed159e, 0x1a037dfc, 0x37df88d7, 0xdf7f22d8, + 0xce85bb30, 0x6fbf5129, 0x25646bd8, 0x3f71135b, 0xc9def8ad, 0xa4fc8537, + 0xbeff4fbd, 0xf88917f1, 0x278493bd, 0x3c3d806b, 0x3d5e764c, 0xedaeaeaf, + 0x6d6f9e73, 0x6bc3fbe1, 0xfb9f235b, 0x77da0372, 0x2728ef78, 0x2b51bd23, + 0xd98edbf6, 0x9744ea26, 0xebf796f3, 0x1e96f343, 0xeea49025, 0xbc51f5e3, + 0xf663cda7, 0x53acb796, 0x96afcfbf, 0xae1f681c, 0x59b70fb4, 0x35edd7ec, + 0xe6fce98f, 0x79e1b97d, 0xb5d3f7cc, 0x69939c75, 0x74ff5a56, 0x36e744b7, + 0x1aae7499, 0x86ffb7da, 0xcfb48d64, 0x87610bfb, 0xc83a8bc6, 0x3f9c8dcf, + 0x44937e7e, 0x77e0dfdf, 0x9ff74878, 0xc3bfc1bf, 0xff0179f9, 0x7bad470e, + 0x5cd7dfa8, 0xd07bac1f, 0x77ea77f7, 0x3677ea39, 0x539d77ea, 0xb9d347d6, + 0x5a188fc5, 0xebdfb952, 0x3a7cbe25, 0xe8fdd19d, 0x491f5628, 0x97a68f5e, + 0x845e9d3c, 0xdc79aee3, 0x423d297b, 0xe30c3bdc, 0x218f7848, 0x3c85e203, + 0x305e2916, 0xe2691465, 0xc787ea05, 0xeeaad70b, 0xcfc0a4f1, 0x6df75c35, + 0x6bc6fc91, 0xdfebff38, 0x45affcf1, 0x732adba2, 0x1f17f3e4, 0xbe8490cc, + 0xce179ed7, 0xc92f7c7a, 0xa4937aed, 0xd533707c, 0x4f540dd3, 0x536af557, + 0xbc7f9f2c, 0x6da9a7c8, 0x0c9b6895, 0x4b65f391, 0x6467fdc4, 0x93e438e7, + 0xf36a2f81, 0xb45b8397, 0x5b1bcbf9, 0x0c88e7b5, 0x09cf6bf1, 0x3dafdc29, + 0xa028a63f, 0xf8663f3d, 0x31f9ed51, 0xe7b43a23, 0x99fcdcc7, 0x5b98fcf6, + 0xcbf9b4ba, 0x1edc2f5b, 0x8fa71df6, 0x9c09479f, 0x995cfa1b, 0xb9d85e69, + 0x73b0ba35, 0xcec3a26b, 0x1f3b09ad, 0xe39bcc45, 0x7e7613ed, 0x367d768d, + 0xba0dc7ac, 0xefdc7afa, 0x1ea228fa, 0xcf8ccfd7, 0xdfde513d, 0xfa9b7e8c, + 0x097ff53d, 0xe1913b3e, 0x71f4815e, 0x875b1caf, 0x22b1d57c, 0x2ef30b2a, + 0x726995ee, 0xfb83f022, 0xa7be8951, 0x46995d2f, 0x35e67bfb, 0xa93f210c, + 0x4fc93980, 0x1167659a, 0x9cd879cf, 0x3decf5c1, 0x8c6606f5, 0x462997c7, + 0x33d0a81d, 0xc35b124d, 0x22658ded, 0xe33561f0, 0xfabb587c, 0xbdd51c70, + 0xc859dd85, 0xebaac151, 0x0e79d017, 0xa8bde7e1, 0xc623c676, 0x6316b0d5, + 0x68bbcc1a, 0x47c93b6d, 0x1e3079f8, 0xea1cf6b6, 0xb096dae1, 0x7db7f5eb, + 0x1ff7f8ca, 0x3c8bf446, 0x2ffbdaad, 0x99ba8864, 0x7e503983, 0x9ac7f7dc, + 0x152ccfd0, 0x56bb99f8, 0x709d62b2, 0xd27b435e, 0xb79fd05d, 0x4bb8a65f, + 0x71eb0fc5, 0x3a20cf4e, 0xfefcfd57, 0xcfa3f25c, 0x8e0a4a2b, 0xb8f1c773, + 0x87bbd241, 0x7659f5e3, 0xe73c70f7, 0x58c3ebac, 0x9d87f6fc, 0xdf9320b8, + 0x3e50be00, 0x96566ff9, 0x9def9a1f, 0x6326b06b, 0xeecbc5be, 0x5378a54d, + 0x7e2abfc4, 0x6788263c, 0xf10fb0e3, 0x749f5f2a, 0x91fa2249, 0xff02eb69, + 0x7e03df08, 0x26b3c510, 0x7e815a66, 0x39a569d0, 0xd7605d19, 0x2ff20643, + 0x4092d9ee, 0x0d3dc5fe, 0x1f3c4665, 0x096d9ee1, 0x79969fb4, 0xbe30479d, + 0xa279e955, 0x2a5f70a1, 0x4b4f7bcc, 0xd2d6438e, 0xd137e4f1, 0x09d35171, + 0x7b277e95, 0x48c9dfa1, 0x69ba03f4, 0x4321ffae, 0x6e8209f8, 0x7d3b41ec, + 0x64b157e7, 0xffe62e6f, 0xe99bd7ce, 0xc67a2bf7, 0x37ae5e05, 0xc4d26f2b, + 0x2e7de53f, 0xbe7475c7, 0x22daf777, 0xdd385fa2, 0xde67ffca, 0x8afefc70, + 0xa1963efd, 0x1fab31ff, 0xc63b739b, 0xb79712c9, 0x96c6ab59, 0xa5f3bfa3, + 0x8b6fcfd0, 0xc630e938, 0xbfd7e049, 0xf412718b, 0xd27113df, 0x41271807, + 0x49c621fb, 0xe7149ed0, 0x0772aa05, 0xfb7c408c, 0xafb790b5, 0x6378d433, + 0xd7e62a69, 0xdde7ffca, 0x5f159d22, 0xa349e3f5, 0xec9b1933, 0xd3d7fad4, + 0xebfd69a7, 0x4c75830e, 0xd581da2a, 0x8f705ebc, 0x78cd66eb, 0x988c57a6, + 0x857960f7, 0x8f64ebc1, 0x3de62314, 0x6bb04c66, 0x94d9dfc6, 0x32dbe9ae, + 0x94f75a15, 0xeb9a7ef2, 0xd40c5777, 0x005ee7f4, 0x5df90cc7, 0x59f92629, + 0xc626e22a, 0xac5d398a, 0xf597ec7c, 0x001e53c3, 0x683cbf78, 0xf4e1fba0, + 0xb95ae950, 0xee7ca65e, 0xf312f5bc, 0x9b278802, 0x7d7c91e7, 0xce96347e, + 0x52dc6991, 0xf43156f8, 0xd0316c4f, 0x0d13b2fe, 0x7cf147f6, 0x925b13eb, + 0x3dbbf0e2, 0xfccca377, 0xa4ad77a4, 0xcb79d577, 0xefd0561a, 0x45f5cc26, + 0xcc0f5039, 0x567de3dd, 0x4ddfa3ed, 0x4e50665b, 0xbf3ec88e, 0x1273f444, + 0x299b377e, 0x8199fe4f, 0x92a7f179, 0xb87075e6, 0x0358933e, 0x8f9b4ff6, + 0xe000780d, 0xb9b13338, 0x957e874a, 0xf489307c, 0x43322be7, 0x6258adbe, + 0x1787f3a0, 0xc46f27be, 0xd20a933e, 0xfa65bd39, 0x39b60f7d, 0x5d67e68a, + 0x6e3021c0, 0x9ea22fe9, 0x5ef2235f, 0x60f5ffd4, 0x9fc11adf, 0x259f47c8, + 0x01026730, 0x7f0ff3cb, 0x75449c3a, 0x7d3e209f, 0xffeeb8f9, 0x64c6bbd0, + 0x54fefd02, 0xfd27cbe5, 0xc91260f6, 0x4fde3855, 0xf2feb91a, 0x41481ca2, + 0x339419bd, 0x3cd5fdfe, 0x41d92383, 0x1a686b7a, 0x6b93adea, 0x6467940d, + 0xaf1c677a, 0x7c42bdcb, 0xa4e7beac, 0xf083195e, 0xa1ca6c9d, 0x59ef0cef, + 0x43fd932b, 0x7de3e3fe, 0x971fff9c, 0x7bbf18dd, 0xc637249b, 0x737ce1ef, + 0xf4e192df, 0x11b3047b, 0xea7a2327, 0xbc69b381, 0x17f6a10e, 0x07bfe4ed, + 0xe87686c0, 0x5d0e0da7, 0x9f7f0347, 0x4e7358bb, 0xdfdf4d79, 0x9c23c71d, + 0x17efefce, 0x9ce9df8f, 0x9f13223e, 0x3cdbee9d, 0xf9e8152c, 0xb0d76e85, + 0xf9ffa007, 0x7a27ef44, 0xfbb46fa4, 0x62ebc43e, 0xfc2cdadd, 0xedb3ba6e, + 0x866f47e3, 0xb2f4fee7, 0xbe6241c1, 0xc7f4892c, 0xb30bcda2, 0x21bbe9bf, + 0x787dfcc6, 0x2699d1de, 0x2b173e01, 0x9f30632d, 0x84b99f30, 0x51f8e23d, + 0x86bcf0b6, 0x73cf1d75, 0xbb145c7c, 0x79b4e306, 0x8f8c7961, 0x8d83f7c5, + 0x6fc69299, 0xf5c99838, 0xe71d3cd7, 0x38b7886f, 0xb1a631bf, 0x5edeaa03, + 0x220fbf8c, 0xaa80ed07, 0x33586bb7, 0xb3fd6b9d, 0xff34becc, 0xbf47c942, + 0x27875223, 0x2af8c354, 0x6b638f2b, 0x51f28c5e, 0xe580aa9c, 0x8e0ff10b, + 0xe7813ea1, 0x7e5f1916, 0x0177d90a, 0x8675f00b, 0xc193fb8d, 0xe9c81557, + 0xacaa7f69, 0x346c1b1b, 0xfb81c1bf, 0x79081719, 0x7c966dad, 0x25075e7e, + 0xcc5f3a3b, 0xd1d85f33, 0xc3d4fb70, 0xa3d9852e, 0x977661f9, 0x2ced6b35, + 0x79e74bc0, 0xc386f0ab, 0x25898ae9, 0xe66a2c3c, 0xdcab3efb, 0x08937dbe, + 0x1401c96e, 0x02cf01ed, 0x80951ae6, 0xc79178eb, 0x85f0e1e9, 0xbc07abaf, + 0x70e19d62, 0xd1ce3957, 0x5b35e5f7, 0xf857c224, 0x847a543a, 0x5d2a71fb, + 0xbf1cbcaa, 0xd1126d55, 0xff65d4f3, 0x50fed190, 0x0b586f95, 0x79e42ffc, + 0x5d608f95, 0x2dbf5093, 0x38fa0758, 0x2d3f27a7, 0xc8712d62, 0xdfcc7537, + 0xd3f72588, 0x473b96fe, 0x4e79e0e4, 0xa9dce987, 0x573f9b0a, 0xeca88097, + 0x96fcb47c, 0xe3879f20, 0xbdf44afb, 0x5131fc5a, 0x00e7a067, 0x905ff35f, + 0x909ffbe9, 0xf63e2271, 0x7b557c92, 0x3fac46bd, 0xb9f9eb57, 0xd3825772, + 0xcbbfe7a3, 0x05784574, 0xdc35af3e, 0x7f5a59d1, 0xe577e839, 0x5bd247c6, + 0x098f3aea, 0x7b45733d, 0xc5dc77af, 0x4927dec8, 0x4de9af98, 0x3b09577f, + 0x3eed1f3f, 0x7fac9fb4, 0x3c6bce95, 0x3a55eeb5, 0xf2f8d59f, 0xf0b7da7c, + 0x8f79fac9, 0x7c4fefe2, 0xd91e65b2, 0xab4f05f9, 0x0c6dde76, 0xd6ca1ff5, + 0x5fee7dcf, 0x345f6f90, 0x6ab95d53, 0x41c45b8f, 0x9c6157a0, 0x51eb9eb2, + 0xd5eb8eb6, 0x070f6805, 0x0ebc3d91, 0xe55fddc7, 0x3ff90ebe, 0xc9d93ae4, + 0x7fb9e7fb, 0xbde613b5, 0x8718a5ff, 0xf56c9697, 0xd5b4bcf3, 0xf6b0f68f, + 0xd38e0fde, 0x07c94bef, 0x6a81fbdf, 0x139e19ff, 0x42ce2ee5, 0xbf761339, + 0x6598de56, 0xec223b45, 0xdf1b3fc4, 0xc9be20f7, 0xfef8e2bf, 0xf9e389a8, + 0xef1cb5e3, 0x51fa5b8d, 0x5351fafc, 0x3eabf23f, 0xf84b92da, 0xf8035cae, + 0xd15abf26, 0x804d55fa, 0x101f8c6f, 0x3dd700df, 0x6f81147b, 0x1377c707, + 0xcb5b33c7, 0x781ecadb, 0xebf9d2f5, 0x947bfff7, 0xcf84fd03, 0x9ff27ecc, + 0xd32adb3e, 0xdfaa6959, 0x7f3dfaa5, 0xa2cfcd66, 0x7be2a67f, 0x3e4080e1, + 0xc78a97ea, 0x7887177f, 0x2795b85f, 0x9be07a4f, 0xbce85339, 0xbfefcbfd, + 0xce2d27ec, 0xbe93f50a, 0x98ea5d25, 0xd72bf68b, 0xf96639e1, 0xd5a2fb21, + 0xdf0b3fdf, 0x7cf0ad07, 0x98731465, 0x464f084c, 0xb9b8eff8, 0xfe8bee19, + 0xecdcf72a, 0xbb8e497b, 0x31c7bf34, 0x780df989, 0x916b019e, 0xed4bbf68, + 0x257125d2, 0xad2dcf0c, 0x67363827, 0x69df3b71, 0x3f22caee, 0xc714676d, + 0x359ba8fb, 0x07a4d1f1, 0x423ff11d, 0x3f20e03f, 0xd79278df, 0x49cef941, + 0xab5243c5, 0xff3ae842, 0xb8d73f02, 0x9cc482ea, 0xc09dfc76, 0x622fb4b1, + 0xda14f37e, 0x6d055007, 0x5ef8e859, 0x9cdbcfbe, 0xc7a2f3c5, 0x78054d71, + 0x1df8939e, 0x1a9e713c, 0x370171d5, 0x3a2ecdc7, 0x9278ef6f, 0xc8cfc1c9, + 0x07dfa78b, 0xc1e85bb8, 0xb47d9699, 0xf1e61c8f, 0x7b9e1b32, 0x0501aeff, + 0xf1d4c2ac, 0x73c68632, 0xbefe3f52, 0xff5b8749, 0xdf22ac1b, 0xbd92edbb, + 0x3a413c27, 0xf381cf6a, 0x8fce4744, 0xfdc59abc, 0xa4e9c929, 0xcc14443a, + 0xdfef0d1d, 0xebf0a59e, 0xdb3bff62, 0xed8cf400, 0x7a9c9e79, 0x39f9799d, + 0xf0a535b2, 0x67189bef, 0xb21bd424, 0x31afd34e, 0x9e87fbf2, 0x5d793d9d, + 0x30ef6306, 0xf43f7ac0, 0xff8f1953, 0x70fbc6e7, 0x3c64d7df, 0xad86ca6f, + 0x76eaf89e, 0x78eaf33d, 0x7ac164db, 0x6a673888, 0x1ddfc092, 0x0f1fccc5, + 0xa03fefbc, 0x2ef16f3d, 0x1d7fcebf, 0x9e3275e0, 0xe78f9767, 0x2b0629d6, + 0x2e55c7bc, 0x52bc6015, 0xc1dbf2b3, 0xc2ecf1db, 0x4246ebc9, 0x70e3a75f, + 0x29e780fe, 0x1efe6266, 0xcf5b30f0, 0x9c05c8f6, 0x8f1788de, 0x207da14d, + 0xda244b5d, 0xede6a2af, 0x090f7a55, 0x8e89ede6, 0x307c0533, 0x3e1c534f, + 0xaf4c8c6f, 0xb8d4b22f, 0xede285ba, 0x173e42c5, 0x45b972ab, 0x6c96972b, + 0x8ff44741, 0x45336f01, 0xf9a4eb0b, 0xd47bc46b, 0xd9cdd773, 0x36737e7c, + 0xf2ffe38f, 0x598fbe77, 0xaa8ef9f8, 0xf146d67c, 0x4ff7d5f9, 0xb6546d16, + 0xe155e68d, 0x7fd7cf09, 0xf91561ba, 0x677fd549, 0xdf443ebe, 0x324c5d50, + 0xea225576, 0x4999efa5, 0x5b1a66ee, 0x3d2deb72, 0x15e7a9c7, 0x8180b056, + 0xbe440fd7, 0xd1a3d84c, 0xbfce85b2, 0xeff890ac, 0xc4967674, 0xe720757a, + 0xbf7cccc7, 0x1ff079e7, 0xc0153df1, 0xef31f817, 0x27fbf8ac, 0x11583fa1, + 0x7b63d467, 0x73cfcccc, 0xb102c39e, 0xfd413939, 0xd32258db, 0xfbcc8739, + 0xafac64f4, 0x213ac2ad, 0xcce63fef, 0xe894aca0, 0xea36f73f, 0x811769a5, + 0x9befa80f, 0xa93884ec, 0xcfb8af73, 0x9df3d236, 0xf67e090f, 0x27fde26e, + 0x279bfbd5, 0xab9df3e3, 0xe4bffbd5, 0xf3a89ffd, 0x61e3fe8b, 0xdd8457f7, + 0xdfef19ff, 0x272fdcf4, 0x2d8fd17b, 0x715dace5, 0xcfbf4493, 0x1bd423f1, + 0x562b0fa0, 0x15cf09fa, 0x2dbc5dba, 0xd0dd7e65, 0xcaab8f2b, 0xed08fd76, + 0x327b1c95, 0x92f5ed16, 0x67f5271c, 0x6747ba66, 0x8a68bb43, 0xbac235e4, + 0xd91f11d9, 0xe8bd498f, 0xbd091fe5, 0xf9f0a55c, 0x3cc37c54, 0xfe8bb293, + 0x9cfe79fe, 0xbb9e63dd, 0x5d9e06ae, 0x66914f08, 0xc0d5f71e, 0x768e5d73, + 0xda1fd51e, 0x23f9d7d3, 0x2edc2b84, 0x23b1fe2e, 0xec53f31e, 0xe29df12d, + 0x42ac96ca, 0x2ff17f98, 0xa1556477, 0x82fc25ff, 0x768bb43a, 0xdb83173c, + 0x3fdbcfc5, 0xb6e5fbe4, 0x60c71bb5, 0x50da001d, 0x0bd358bb, 0xb56cde9c, + 0xaf38ffce, 0xb4f2fe1b, 0x58b9e91e, 0xd3c9f2d7, 0x926fe768, 0x59777e22, + 0xde3b9e2d, 0x3525efcb, 0xe03f7366, 0x87cefea5, 0xb20b6f10, 0xb291e919, + 0x79cf9155, 0xb1e85b7e, 0xe6ff610a, 0x29358b0d, 0x23a2e780, 0x0fb855ee, + 0x4e436aab, 0x978de601, 0x963e9667, 0xd6f98dfd, 0x6d6f9e2e, 0x0ad6f9e3, + 0x2829605b, 0xf666f671, 0x32998f5b, 0xa9fe0fc1, 0xb220672a, 0x94796cf0, + 0x79353fda, 0x0f9e48d4, 0xcfcbfec3, 0xe50c7f1d, 0x83c23f66, 0x83e1f5f9, + 0x743f51a3, 0xace8c4e4, 0x25fe47a0, 0x089bee63, 0xb7e1acc7, 0x929a7ed0, + 0x7301d8a8, 0xf89efe79, 0x5c325fe2, 0x38dd709b, 0x6e24f31e, 0x2ee93fa3, + 0x4dfb8758, 0xbab3f699, 0x91dc63f3, 0x2efff3ea, 0xb666f0f0, 0x3afdda95, + 0x0820b380, 0xf07efa87, 0x600697f7, 0xd32b93be, 0x50f7e086, 0x0e4a3227, + 0xdf051764, 0xbdc3227f, 0xdf53e11d, 0x06c7527f, 0x6df1c860, 0xd05578e1, + 0x0dd200f7, 0xe048d75a, 0xefb890b7, 0x9a3151f6, 0x7609b4fe, 0xe3cd0ce6, + 0xf4d74b4e, 0xd3f457a7, 0x72bbbf8c, 0xc4fee6a0, 0xfad0c0a8, 0x77b7bf10, + 0xf7cbc97f, 0x46c6c4ef, 0x3fbdfee3, 0x7df9fdb6, 0xcee9fdfc, 0xfa076417, + 0x6e770bb6, 0x168f1f7a, 0xb5f40f3e, 0xa1527e53, 0xf69fda7c, 0x839f8ccb, + 0xd687d4e1, 0xc0b0ce91, 0x60a52353, 0xeb6dfb7c, 0x7bad8b47, 0xae0577e8, + 0xf3e8dd55, 0x287f516c, 0x1f680560, 0x47bfd7cf, 0x0b3abd79, 0x1d99e75f, + 0x3c5b9cfc, 0xf012fae7, 0x20f86dfd, 0x40178bfa, 0x97fc83f1, 0x7aa09eb5, + 0xae6c9adb, 0x9632ebaf, 0xf64fd1e8, 0x65f68b40, 0x78ade80c, 0x3b409be0, + 0xf70dbc1b, 0x72c4e5bd, 0x54c2fdff, 0x8fef9bca, 0xfd9ff9e6, 0xfbf409c9, + 0xc69b8bc7, 0x0bbaf5d2, 0xdbff3431, 0xb5f68072, 0xa8935f79, 0x7d31314e, + 0xcf5c4ad6, 0xdf4401ff, 0x80006da0, 0x00008000, 0x00088b1f, 0x00000000, + 0x7dcdff00, 0xd554780b, 0x399ef0b5, 0x67091e67, 0x99212726, 0xe4c21024, + 0x4e010249, 0xaaf08042, 0x9e180903, 0x6831004e, 0x0cfde1d0, 0xaf4a8809, + 0x04819bf4, 0xa86c1808, 0x3bd15014, 0x6ad480a4, 0xa6a3ea6f, 0xd004c7d6, + 0xa0d2941b, 0xdef6b7fe, 0x22c01b5b, 0xda046a28, 0xfad2de9f, 0x3ef6b5af, + 0x82499cc9, 0xbf7b7b72, 0xdbe3ef9f, 0xb3ef6759, 0xd7bdeb1f, 0x6b4cfb5e, + 0x7eef2074, 0xff99b185, 0x1b297b72, 0x97dad8c6, 0x1e609e4c, 0x857bd2c0, + 0xd35ca0eb, 0xbeb19530, 0x5356b308, 0xd731631c, 0x046c61ef, 0x2c018cc1, + 0x64ec728d, 0x435a5031, 0xc3c64fd9, 0x3b43ab33, 0xeaac66ec, 0x37bd147a, + 0x3011d8bd, 0xdbbc7d43, 0xc648d8c4, 0xe953ed2c, 0xcbd7c9fd, 0xfc6bfea8, + 0xfd631b77, 0xaf54e9dc, 0x438496c3, 0xdb0522f2, 0xb4fda89b, 0xaca843eb, + 0xca873ebc, 0x147e7277, 0x84fac3ef, 0x17fa536b, 0x526f1c02, 0x64ac4a71, + 0x628d999c, 0xa33b7eec, 0x47ab577f, 0xaba530c7, 0x72d2c8df, 0xe81e625d, + 0x44dd76cf, 0x8f74c0e5, 0x6c604ee6, 0xd976a6d6, 0xec51eb8e, 0x8034e1ea, + 0xcbddf28b, 0x93debaf2, 0xbab7cd8e, 0x7bfbc287, 0xd03d58ce, 0xe2ca0dbf, + 0xc64afab0, 0xdd794d3c, 0x36e51bc7, 0xdb193ad3, 0x6c2ce54c, 0xcbb3ef07, + 0xef3865df, 0x6f3e557b, 0x912611b6, 0xb60658cc, 0xbf7ae84f, 0x60c1d00d, + 0x6d97815e, 0x77f0c3c1, 0xd4afba51, 0x4db4fd0d, 0x602fe564, 0x6a5b723f, + 0x371fe399, 0x38b799ff, 0xfe6271ff, 0x46d896bf, 0xb7d7efec, 0x81e6d6dd, + 0x3c3cb579, 0xeee48462, 0xb75ef7ea, 0x76abf795, 0xcf4060dc, 0xb8fa37aa, + 0x66fac277, 0xdc208f02, 0xd82dbaf1, 0x99cf4698, 0x5b4b1e29, 0xabea09a3, + 0x5ed91d9c, 0xcdf8bf18, 0x6ff210a8, 0x32519bcb, 0x9f7e7183, 0xe917bbe9, + 0xa0e6fc58, 0x26139312, 0x464d9af9, 0xd036583e, 0xef3e1f73, 0xf1bdbe6d, + 0xd69c6009, 0x535fc911, 0x18814cca, 0x1d5f6fe0, 0x82859397, 0xef5d173f, + 0xc84fb043, 0xc4ead5cf, 0xabb74829, 0xb0d2609b, 0x4c9b458e, 0x75825f43, + 0xcb43b731, 0xeccc3c02, 0x730b60bf, 0x69995ca2, 0xc48733bd, 0xe9a06b06, + 0x06b1eb9a, 0x9ebcabf9, 0xbdaffd46, 0xeb9e97de, 0xc848b672, 0x19f90d87, + 0x9f8225e0, 0x197e45ef, 0x1b8725d3, 0xe28f7dd3, 0x80d667fa, 0xbe78c3bc, + 0x2885c92d, 0x62fc5d47, 0x80af9155, 0x8596925f, 0xcb4d4dc9, 0xf42a987c, + 0x7e25ef1f, 0x71650259, 0xc152fd58, 0x7b789107, 0x65f916ec, 0x48bf68b3, + 0x01996509, 0x28ea960f, 0xe7cc0b6d, 0x0a7bbc4a, 0x0efd65e2, 0x16f5bf8e, + 0xe603b16f, 0x9371febb, 0x8b619406, 0xa8ec3947, 0x587d4687, 0xf185f56d, + 0xc3ebfced, 0x30f01b98, 0x95267ae7, 0x83be01fe, 0xd785feb8, 0x0d3a09e7, + 0x8bb992a3, 0xd8c5cccc, 0x1baba406, 0xe9c45427, 0xad77e62c, 0x43e2747a, + 0x53b5fe30, 0x88bfaa16, 0xa9802d78, 0xe34f027a, 0x9b412cbc, 0x75e61076, + 0x2a02c2d1, 0x7ef169d0, 0xdfa00589, 0x46fa5025, 0xd83d52d0, 0x1481f6ce, + 0xb176c16c, 0x805b13cc, 0xe6f584f8, 0x86be31f0, 0x6d4c97ff, 0xfd410fd9, + 0x961b33e7, 0x81e03399, 0x86412a74, 0x82fe7e75, 0xbe7824c4, 0x2e5bdd72, + 0x94ab1e58, 0x50aaa60e, 0xcc14c1bf, 0x7be280b6, 0x86bdf646, 0xbbd3e07a, + 0x08adfe9b, 0xf0dc7dda, 0xaae913a2, 0x0e49b5e3, 0x4d3f6165, 0xcc00cf80, + 0x2a5ea9bd, 0x6c342a0d, 0x5da1b29f, 0x73f3adfc, 0xbaaf9f24, 0xba78419e, + 0xfa1b6d5a, 0xf031f212, 0xf5d73e2d, 0xae3aeaf1, 0xbefd75d7, 0xcebff056, + 0xd73295d7, 0x4c4a955b, 0x6e169030, 0x13bcca6f, 0x4c72ef91, 0xb70b165a, + 0x8e8f8d37, 0x32f83945, 0x5d61ab5e, 0x839742f6, 0x8049fc57, 0xa47b2ebc, + 0xc7ae81cb, 0xf3aebd75, 0x26af6ebd, 0x2f2fe4fd, 0x79fc3bfe, 0x81d7cd32, + 0xe64d307c, 0xec9a6b76, 0x1c9a3e20, 0xff23265f, 0x79fd7b7c, 0xb3cfe856, + 0xb6b9fd06, 0xc7f9fd17, 0xf387945b, 0xda967f42, 0x3cde7dd8, 0x3b67dfae, + 0x4a2bfaba, 0x834b649f, 0x1334947e, 0xcd47fbb5, 0xf3e3495b, 0xfef3b6f8, + 0x6fceb12f, 0xd303fbd2, 0xa46fd4ac, 0x1fd0679e, 0x5f2ff9ea, 0x1da20dcf, + 0x5d8188f8, 0x5af7bb40, 0x6161f71f, 0x444ec807, 0x666f04c7, 0xb9927e07, + 0xa7e22078, 0x4ee03b07, 0x80ec3bfb, 0xbcba57ce, 0xcba1f2e8, 0xe8fca443, + 0x11fd30f2, 0xa421e62d, 0x30e6200f, 0x781c8fca, 0xe951d70e, 0x728f93ee, + 0xf811cba9, 0xdd672461, 0x9b9083ec, 0xda31392e, 0x742e5d0b, 0xa6e5d139, + 0x52c5c852, 0x3cba1721, 0x1e9a971c, 0x3def0b1b, 0x432be697, 0xb1f2e87c, + 0xbb4885e6, 0x313f2bd0, 0xf1a5a7e4, 0xa9f90cd5, 0x7e70ca12, 0x4fc2f5b2, + 0x9f916ef3, 0x9dbed24a, 0x8d32b11f, 0x40ff11fb, 0xd6995a7e, 0x0ab15fb3, + 0xca7fecf9, 0xfd5ab8af, 0xcc37429b, 0xe8216ae7, 0x7e2eb4d9, 0xe32efe9b, + 0xf806437e, 0x46b450d9, 0x5ab675f3, 0xb06b0407, 0x1aacd7dd, 0x01fba8f1, + 0x7dee914b, 0x27f4f8bb, 0xfe71ff60, 0xc15bfd3a, 0xedf75fff, 0xd9d11df4, + 0xf566df16, 0xdbbd21e4, 0x37bff60c, 0x5bb1f17f, 0x6fe6f3a4, 0x4243e749, + 0xfa0ffc6f, 0xd17a878b, 0x1eff8713, 0x862cceba, 0xfc21fb3f, 0x3c67af7b, + 0x02fbe7d0, 0xa2f39c0e, 0xd22bccbc, 0x3c1bdbeb, 0xe01fa899, 0x8234b1cf, + 0x0f09d987, 0x56db3e02, 0xfe9cf302, 0x007d6758, 0x8f8f27eb, 0x8f33ef11, + 0x3fb57589, 0x5b51f691, 0xd60bda3d, 0xaf8dedc0, 0x0d0ef65d, 0x76010b83, + 0x1145c184, 0xdede01f0, 0x9533b729, 0x972084fc, 0x54dfe82b, 0xfd15f340, + 0x9e65fe09, 0xcf015713, 0xdb1354b3, 0x8aaa7409, 0x55d6f83f, 0x26cd6bd4, + 0xe1877266, 0xebc97021, 0xf6fd0149, 0x9fc0499a, 0x37c079b7, 0x0e25fbb8, + 0xabf0767f, 0xfa2c8086, 0x8d6c7f05, 0xc9a5b740, 0xbfa091e4, 0x60a64535, + 0x7c775a7a, 0x67c9d67f, 0x54c07cfa, 0xd667df1a, 0x1f7b5bf8, 0xa7ef4de9, + 0xdb21fbd3, 0xd77f8c2d, 0xf609e678, 0xd29b0fe0, 0x292c5db9, 0x3eb1e98c, + 0xf8e25d2a, 0x3eb001bf, 0xd39a3c3e, 0x91e5f7c4, 0xf9d363ed, 0xb3666db8, + 0x3763a7c0, 0x559b59f2, 0x1bb2b7c7, 0xb1993df1, 0xbe413e4e, 0x4e09f181, + 0xeaca5469, 0x4f5cbe64, 0xb66ebe04, 0x74d32fde, 0x5f0ba63f, 0xd97a0881, + 0xabef826e, 0x6ddbe03d, 0x33743f7c, 0xdbb9fd7a, 0x576f82fb, 0x31ec7ce8, + 0xec8c7bf0, 0x898cfe25, 0xe001a937, 0xa8deb5c7, 0x742fdc7a, 0x195267c9, + 0x88ca2de1, 0x4bf92ea7, 0xc8512b2e, 0xfdf5123f, 0x7afca377, 0xb9ed9dcd, + 0x0d7cea3c, 0x5e00e7ef, 0xf7c695d1, 0xdbf7a547, 0xbe23c81d, 0xe5827aa0, + 0xca4779b0, 0x3c045363, 0x857e423e, 0x40fe91fc, 0xca78007b, 0x7f16fd42, + 0xe30eead6, 0x7f053b93, 0xe5626e7c, 0x26db4fa8, 0x2db23f71, 0xa40f979d, + 0x02ccb8f3, 0x754b97c1, 0xc30e8a7e, 0x427f9183, 0x5b095fb8, 0x7e69e137, + 0x63cf2ebc, 0xbac066cb, 0x7d78e2da, 0xdda8e355, 0x382e9481, 0x8d75bfb2, + 0x2f10cb63, 0x8a07fd9d, 0x997da0ce, 0x40f6f02f, 0x813398e3, 0x1767413c, + 0x7fda19d9, 0x50047f01, 0x7f22541f, 0xc7f3ba98, 0xfc6ef484, 0xdf788819, + 0xfbc9b963, 0xf7dfddc5, 0x2ccfbc44, 0xbef2b7f1, 0x088cdba0, 0xd04696ba, + 0xae0224b5, 0x41a0e1d0, 0x797aeaff, 0xadeef351, 0xeac7982e, 0x5967a0a3, + 0x2d4f3f38, 0xad5fb943, 0xed3bfcea, 0x176bf20c, 0x3c274f3f, 0xf9d26ecf, + 0xd46ec675, 0x87a865c3, 0x73c176c7, 0x3c110f50, 0x1313ccb3, 0xed66af6e, + 0x57757b46, 0x0efede9d, 0xad777f6a, 0xea979fde, 0xcf423a75, 0x42d74465, + 0x3ecd5edd, 0x5eabf583, 0x4d1fefe3, 0x9026739f, 0x68791379, 0x81cbc088, + 0xd1103808, 0xd837cf7e, 0xf788dab7, 0xd7d44537, 0x23fbc047, 0xfbe33ae0, + 0x4898970b, 0x3f02170e, 0xe5222120, 0x9a3f9232, 0x9cfd3bd3, 0x526e7b4e, + 0xc833bfc8, 0x0e1af4d5, 0x95f74b1f, 0x706129d5, 0x2e32c2e3, 0xf01a3017, + 0x7ff185a5, 0x120373a0, 0x17a583f0, 0x1bd4d9bd, 0xda44e65f, 0x7bff5e7b, + 0xfd1933fc, 0x4bf06665, 0xb8464b8e, 0x0ef31245, 0x90d99d54, 0x78750f87, + 0xa7ee196d, 0xae33efa7, 0xa2b3f60b, 0x49594d7e, 0xd6c45fb8, 0xd6c27994, + 0xf29fb7a9, 0x1c25afd7, 0xd5c6c3ef, 0xbea08765, 0xab285262, 0x5e38cb1a, + 0xd094bd82, 0xf889575e, 0x25d794cd, 0x8acbda2f, 0xfad650e8, 0x35883f70, + 0x5b3ae365, 0x3e88961e, 0x0fa01a81, 0x732169e0, 0x2eced15b, 0x832b1e66, + 0x4c4b5cad, 0xf023c6cc, 0xa587f1de, 0x3fa7688d, 0x85d7d8da, 0x19d1a1fb, + 0x3c717f7c, 0x296ba066, 0xee7d2dc0, 0xb2db7d23, 0xc795327d, 0x0eb6cf24, + 0xdbffb195, 0x929970f8, 0x8431f58b, 0x0fe9aba7, 0xf9066d95, 0x9bba53f8, + 0x538beaf0, 0x6fe8cd5d, 0x8c30b4ef, 0x51a63397, 0x2ee1691c, 0x9c4efe5b, + 0x2e21e6cf, 0xfd173ff4, 0x324a6cb0, 0xd5b45bb4, 0xd51fa1a2, 0x7153566e, + 0x939dbe7e, 0xa4bf58ad, 0xdb819456, 0x6ff37ca9, 0x4271aa3f, 0x4ca78efb, + 0x9fb4235a, 0xdde9ad70, 0xaf2f0061, 0x4490d0cb, 0x33375c6f, 0xb739c615, + 0x0250507f, 0x551f3cbe, 0xde2cf6fd, 0xe5fb619e, 0x67a7dc37, 0x497b6215, + 0x2fed02dd, 0x9ff473c0, 0x1a90ec2f, 0xa72f384d, 0x4b04da23, 0x4657f0ba, + 0x5b0b9cf1, 0xcf8c416d, 0xf77c539d, 0xf671c7ee, 0x67d3d05b, 0xa76e4c17, + 0x9f10f009, 0x292cb3b1, 0x04db9f19, 0x2ec6773d, 0x685f3904, 0xb21fe4ee, + 0x3962cb27, 0x1da3ff1c, 0x1d618765, 0x441f1e17, 0x195dabf1, 0xc00c849e, + 0x1e991df7, 0xa3e79617, 0xf37addb8, 0xe87dd26f, 0xf2f2ffc7, 0x97f21722, + 0xd3cb833b, 0xb917d71b, 0x55f98516, 0x89973ecb, 0xbab4de0f, 0xdf7ce037, + 0xc2601e8c, 0x41f0367d, 0x2f938c5f, 0xe016fb11, 0xf62f8de7, 0x97fd5fe0, + 0x1e5ac7f0, 0x36ef1849, 0xd27ef5f0, 0x00dfb49f, 0x87e33f38, 0xc7c003bb, + 0xb236db1f, 0x9b8c28f3, 0x75dc52fa, 0xe07a1309, 0xee20a8b9, 0x535258ab, + 0xa6fc7876, 0xfb450e53, 0x841c05df, 0x7b41dfd7, 0x2efdf7dc, 0xf08e1ff0, + 0xfdbd0bf3, 0x8023a772, 0x0e27c5ce, 0xf8f48c87, 0xf85ff648, 0xecb7bc2e, + 0x81d90b29, 0x6c254f65, 0x8171c0ea, 0x16ae306f, 0x867f2eb9, 0xabd5d685, + 0x6523b25c, 0xfbe12925, 0xbfa4c395, 0xe9cb937b, 0x0ecb8719, 0x972ef5e5, + 0x9fae55cb, 0xf1653ca6, 0x1f2d3ca2, 0x70d990e9, 0xf53d26c6, 0xcfc461d6, + 0x055175f2, 0xf2f89836, 0xaf446ca7, 0xa0238776, 0xe9cfbd42, 0x9ca16390, + 0xd6f5c19f, 0x3f2e0ca6, 0xed9312c5, 0x62d65405, 0xcc0af5bc, 0x97c02fa7, + 0x77b63e36, 0x29f38c34, 0x0d1bce0b, 0xe1e2bbf8, 0x25e57a7c, 0x4c8ee289, + 0x4133c8f6, 0x5c60ae5f, 0x7c9e544f, 0xfe113ad1, 0x5ff562ac, 0x5c1fb049, + 0x067cbd51, 0x06570bee, 0xc5dae72d, 0xb16bfc5e, 0x55b3d45c, 0x5bd811fc, + 0xfefebd63, 0xfa4ed61a, 0xa229b2a3, 0x4ff6fabe, 0xd5537e30, 0x3ebe7c6c, + 0xa17f11c3, 0x7258c30f, 0x5d8a6001, 0x3364b6a9, 0x0572ea58, 0x5dd60ce4, + 0xf344c07c, 0x0a51be5f, 0xc5fe60da, 0xf8dc797d, 0xc1f03f63, 0x407f5a20, + 0x1ef97805, 0x33967f6e, 0x7f0ed053, 0x1d607ede, 0x0a2f31c5, 0xc4d0b37d, + 0xe7e7c8bc, 0xdc54b4a3, 0x2a7b2fef, 0xfcbcf08a, 0xf6ff95e9, 0xbed7bc38, + 0xf87c6679, 0xf90ebafe, 0xd999e383, 0xf9fabae3, 0x52f7f364, 0xff8a0e51, + 0xb0c9f619, 0xecb1e5de, 0x90d3f3a7, 0x6ea9c96e, 0xf2ddaba5, 0xf3670f2d, + 0x86cfb076, 0x21dc2f75, 0xcbd83ad1, 0x2087b236, 0x3e386af3, 0xb49ed497, + 0x633db95a, 0xd9f84baa, 0xf5e7d46e, 0x7fbc126d, 0x8525ea0e, 0x0f6817f0, + 0x87df978b, 0x3e93257d, 0x2afae1f1, 0x66fba6cc, 0x561d3f53, 0x3317ef94, + 0xd9f45c78, 0x2ee7ee0c, 0xa5eed54c, 0x36a3f438, 0xef1a4b6d, 0xe6251a47, + 0x4abcfb01, 0x3a32db73, 0x8db9fcc7, 0xb5552be2, 0x27289e51, 0x2f3c4bed, + 0x3255bf40, 0xd871ad93, 0x1ae75f2f, 0xf01fd737, 0xcf1943fc, 0x3f5c1c67, + 0xbe02c656, 0x6638ce15, 0xfc4bffe8, 0x97f7832b, 0xfdebac3c, 0x5d4df1ce, + 0x10c3b9f5, 0x95e77d5f, 0x979e3ce3, 0x19017e48, 0x9fa1168f, 0x0234bcf7, + 0x770bd7f7, 0xfa829f1c, 0xf2cff576, 0xe1757c55, 0x7b27df4f, 0xb9d05ab1, + 0xb47dfd1d, 0x0cff001f, 0x7e4253ca, 0x0f8f127c, 0xd0f8129d, 0x57d7ade9, + 0x38f0b0ee, 0x5475e83d, 0x7f9b9524, 0x3a56fd43, 0x6fa85cda, 0x8cb65f2b, + 0x6bfcbd42, 0x5fb43f9c, 0xf8c079b4, 0x167f810f, 0xb4546259, 0x33026b4f, + 0x69af08ad, 0xf5dc1130, 0xf22a425e, 0xafb567e3, 0xce4f9138, 0xd0b28547, + 0x8bac750e, 0x01711ad2, 0x7dcf8f2a, 0x88d59b56, 0x6a259c71, 0xf504c39b, + 0xc464364b, 0x48febea1, 0xfeb1590d, 0x3334a6a3, 0x1d551ec2, 0x1e47b08f, + 0xa067f04e, 0xff049aba, 0x6b59bea0, 0xf35cf4e2, 0x3a6b71dc, 0xac55778c, + 0xdfe7f3f7, 0x4f78c6cf, 0x365b6a65, 0x77a011da, 0xf3c47f76, 0xc3b226b3, + 0x3c939f6b, 0xe8bac351, 0x0de916bd, 0xd04ab5f2, 0xaf4bed79, 0xbf7c843c, + 0xd05de916, 0x6f805f9d, 0x17f3d04f, 0xfc614e0e, 0x17c813fd, 0xb802ddba, + 0x377182d6, 0x09af872b, 0x25e7803e, 0x8f2079fc, 0x11e826f4, 0xf92337f4, + 0xc6fa37bd, 0xb7fb7266, 0xf48db368, 0xe7266c6b, 0x2f1df6fb, 0x9f7e913b, + 0x6dfc7f3f, 0x7ca94f3c, 0xbbb2ac01, 0xf817be07, 0x3bf5c2a8, 0x4fe4fe69, + 0x9d7ae154, 0xe4efeb5d, 0x556f2173, 0x5f4faf8c, 0xd62c956f, 0xf78bd7af, + 0xbc8532e3, 0x97af8130, 0x12f97106, 0x8af284f2, 0x3ebe997e, 0x5f7f1c5f, + 0x4ca2cfe7, 0x62699fce, 0x726d4c9d, 0xbe907e22, 0x7f8067a8, 0x4251d63c, + 0xcf93406f, 0x0ff3067f, 0xff3e97a3, 0xd00f3152, 0xb8d89e6b, 0x9bb63a2e, + 0xce9e8ad9, 0x3933f32f, 0x9add9cdf, 0xf80cda98, 0x59f60cfb, 0xfc006794, + 0xa78d872a, 0x5e3e8df3, 0xa6ca4ff1, 0xffa1bae1, 0x8faff610, 0x8fa051fb, + 0xc47cfd8c, 0xf3e87cb8, 0xb8b2e5d7, 0x7cb4c166, 0xdcfbb627, 0xeb879191, + 0x6697e3e6, 0x07bef4aa, 0xdf7803fd, 0x38a26cd3, 0xafb159f5, 0x15f5bb3f, + 0x2ebca2e7, 0xde229f7e, 0xabb27fc3, 0xfe753cfb, 0x9a67e30b, 0xbbf6f167, + 0xcfac21a6, 0x752f9237, 0xc9fce9bc, 0xdf902536, 0x55a7c912, 0x38ad6729, + 0xdd73e45e, 0x718f397f, 0x5fff9416, 0xff248298, 0x6644ecb5, 0x7f865d98, + 0x65d51b0a, 0xb3af361f, 0x51cb7b51, 0xbd75076e, 0xaaebdbaf, 0xc425cf78, + 0x79328ff7, 0xf56ac91e, 0xf42736c4, 0x36e3e633, 0xfdd60f3a, 0x42d709c5, + 0x95c60c52, 0x082b4a5e, 0x2e6b77b7, 0xadfe209f, 0x70db6d64, 0xc770b3ff, + 0x234733fb, 0x42d8fe9f, 0xb70b2fe7, 0x1fa2b64e, 0xe2f0f2be, 0x73ff4851, + 0x5d9edc75, 0x04791daa, 0x7573e8fd, 0xe716b98f, 0x53c57be1, 0x85f3c2c6, + 0xbe89f3bb, 0x66daa3e7, 0x80f1dc22, 0xbde11ac4, 0x6e478771, 0x71e01bba, + 0xb8b1818e, 0x490e8fce, 0xf8c36325, 0x37530961, 0x9b7e8ddd, 0x7ca2a31c, + 0x5af4247c, 0x6bd3858d, 0xdaffe097, 0x79cb92ce, 0x364d4d71, 0x1c77979e, + 0xf80a7d04, 0x9bbab0a9, 0xebee3842, 0xa80fb489, 0x524b6d82, 0x935b9d1c, + 0xcac2b4df, 0xf405c9ec, 0xcf0c9edc, 0x1eda5a4f, 0x7c9cf5c0, 0x19bf91c0, + 0x18dd2b71, 0xbbfb88b5, 0xe7e03724, 0xbe3af8d2, 0x0bd479f4, 0x4fec8b3e, + 0xfd15bf7f, 0x627fd47c, 0x7f6a97fe, 0xd6ed0f3c, 0x7159a3a5, 0x5e4ffeb8, + 0x3f43aa8f, 0xd70b13e7, 0xe0ff7a67, 0xee1c7d7f, 0x65bf8127, 0x32bfc180, + 0x1f67c0c0, 0x2db5fd1b, 0x33a7af34, 0xce95fe8d, 0xb2eb15af, 0x04f3c262, + 0x99e3f9ba, 0x744796b7, 0x02880fd9, 0x318c5d16, 0xf6ef8c0c, 0x6d8bebf9, + 0xd8378fe8, 0xf3ac1b54, 0x3c77e463, 0xe2597a6f, 0xe73b00fb, 0x1e5f8fff, + 0xdefdc411, 0xf0e4ffb2, 0x105326b2, 0xec4ea553, 0xfb612ede, 0x25ffe0a5, + 0xdbfcc29a, 0x01e7bb3d, 0x9a2bb3db, 0xb4325b6f, 0xe79472bf, 0x12b5403f, + 0x9dbed7e1, 0xf7dffeec, 0xc178f567, 0x6bbc74af, 0xebbc434c, 0x39f7d6f8, + 0x145f026f, 0xefe17415, 0xf20aff0b, 0x7dfb2f67, 0x3a697e54, 0xe438e8fb, + 0x868c4767, 0xe6cbf372, 0x48fea4c7, 0x6ff297f7, 0xac757ee0, 0xfca2a312, + 0x48dfe17e, 0xfd978c87, 0x74ea54d5, 0x1365e3d7, 0xf7a16a5e, 0xf11e68be, + 0xef7838da, 0xeb86250d, 0xf7cf0f6f, 0x646fa488, 0xebfdc7de, 0x73e22746, + 0x7e9f5d7d, 0x9f59d397, 0x1747a7f7, 0x2d5d713b, 0x6d7df64f, 0x4fb7d20c, + 0xdafe8a8c, 0x71f79172, 0x13d73f61, 0x4731ed17, 0x2f9d0066, 0x62e3981e, + 0xb69737a0, 0xcf879dcc, 0x526ebd97, 0x5ed75fd1, 0xfee2732f, 0xbb720fea, + 0xde12c553, 0xe47ce10b, 0x697a84a0, 0x839b296c, 0x6486c7ed, 0xc67e86e6, + 0x32fce0cc, 0xc41cb2e6, 0xe0cf9f83, 0x6e33c539, 0x033c5344, 0xbcc5f5fe, + 0xe0bfa58e, 0xef1d1071, 0x9c6c7efa, 0x1030f758, 0xf177e243, 0x3f88b8bc, + 0x8bc0e4ff, 0x4bbfb0b3, 0xce2a2c87, 0x16438bfb, 0xec157fea, 0xde30cca3, + 0x5f7ca3c5, 0x1a547082, 0x7fdf33ca, 0xfbe26aac, 0x1675ca8f, 0x3ba6358f, + 0xb587165f, 0x3c1efdc3, 0x2bb8e373, 0xfcea1f05, 0xd7c3caba, 0x1cec0ab7, + 0xf89bf7ae, 0x6d359637, 0xc6f5bc43, 0x7f96dfc7, 0xfa8cb333, 0x7b6f93a2, + 0x578117e3, 0x5be47f94, 0xed562f9d, 0x71ece7e7, 0x9113f94d, 0xd13e74ff, + 0x12604bf5, 0x5a7b41cb, 0x98396563, 0x47301397, 0xca17a86b, 0xed05b714, + 0xf6f89cc0, 0x23cf4412, 0x4abf5c59, 0x198f66c5, 0x8d8d51ed, 0x78b747f4, + 0xc7d71677, 0x283e6421, 0x7952ccef, 0xa6ab25be, 0x825e857d, 0xed0032e3, + 0xb89f5976, 0x49a1ba3f, 0xd9c6e1e9, 0xd975f032, 0x3207b8b8, 0x87bcc634, + 0x4478728f, 0xd40b48dc, 0xb333d2cb, 0xccae004b, 0x0ac94cf2, 0xe1d2f7eb, + 0x1eb801c4, 0x9f153e78, 0x37de28ff, 0xea246b23, 0xf9f4857f, 0x618ea697, + 0xdabad31b, 0xf1dd799f, 0x5ddd2fd1, 0xa585bb70, 0xeb08796a, 0x9ee5e5f3, + 0xec1ccf2c, 0x22f9f227, 0xde52b6c6, 0x3f5fe05c, 0xfe04ff44, 0x8f40ed79, + 0x2d5f043b, 0xa4212bb2, 0x5cb3ab33, 0xc037f4ee, 0x8c5a6015, 0x259b748c, + 0x390ee4f8, 0xe7ef82d4, 0x82f55ab2, 0x03a25c9d, 0x5dedf75f, 0xd80603af, + 0xe03fbd05, 0xb02d2f87, 0x136be03e, 0x1046dfb0, 0xb120131d, 0xe998f402, + 0x33fd7fb5, 0x60135bf6, 0xe78451ed, 0x10c2f50a, 0xccface0c, 0xd959435f, + 0xe30c39c7, 0x1c579e1d, 0xb8e80521, 0xc43ef9fe, 0x1f852bff, 0xc4457cc3, + 0xbe541bcf, 0x4b1be61e, 0xe080f6fc, 0xacfc4fb7, 0xf044133a, 0x0bec7673, + 0x70f1e619, 0xc461ef94, 0xa9f31afb, 0x946ef5d4, 0xfa271ad7, 0x54ff9f19, + 0xac3550d2, 0x3b24fe11, 0x5ee42094, 0xf506dd0a, 0x8db969ad, 0x0ab66f68, + 0xc69cb97e, 0xd81c3f68, 0x3fbca36c, 0xea78e376, 0xa69700c3, 0x3ee1aedf, + 0xb6cff2f3, 0x3a052e67, 0x38bd40d9, 0xa1539d61, 0xb75822cf, 0xce896005, + 0x4f448381, 0xe1380fa8, 0xc7b4b6f9, 0x319f3952, 0x4eb5ca2f, 0xddef1d1f, + 0xa34301e8, 0x33b669df, 0x732bee0b, 0xe51501d9, 0x27cba74f, 0xe01bc076, + 0xfe6e327b, 0x7fac1f41, 0xeb7ffb99, 0xa613ac4d, 0xfb374eb8, 0x9ff916f7, + 0x83016e20, 0xf8b0397e, 0xa2c3d9db, 0xe21c5683, 0x81e2ed96, 0xcaf51ee2, + 0x257ae8bf, 0x1f93e59f, 0xf1844b82, 0x93368b96, 0x8cb70aa5, 0x6bb049eb, + 0x9feb17c8, 0xc3bb20ca, 0x8590fc66, 0xfa0763b7, 0x4b6cbf12, 0x2b0e8893, + 0xd7944d9b, 0x3fb9b338, 0x8cd54373, 0x3a54bee6, 0xf3d327af, 0x2dde474b, + 0xd3877ae4, 0x8933e669, 0xe88f2893, 0xea544199, 0xf82f58f3, 0x15f3c74e, + 0x1cb3c72f, 0x1e37ddc8, 0x2d5a13cf, 0x3f26e82c, 0x35cfd784, 0xb4afde11, + 0x7f91979e, 0xb1304ee6, 0xd14b00be, 0x496dcf9c, 0x01eee666, 0x9f4136bf, + 0x73347728, 0x6a0bed87, 0xf88d9ca2, 0xda780b1e, 0x97701f70, 0x2727d768, + 0xa74ed0ce, 0x8e813ce7, 0x331594bb, 0x9ddb1d70, 0xbf915a53, 0xc33f5a1c, + 0xb14936b8, 0xabcc1f20, 0xee63d230, 0x196c235c, 0x5be915ff, 0x73e378cb, + 0x5f08c79b, 0xcb98e9d4, 0x18e9c372, 0xfa0f3f86, 0x363c57e1, 0xdee63f8e, + 0x79e01e37, 0x7cc3f861, 0x32292b96, 0x147b6fe1, 0xade017c7, 0xa63cf911, + 0x58b788c8, 0x7d4f118f, 0x48f88d4b, 0x9bd71af0, 0xa86e9e58, 0x360df64f, + 0x515ff7d4, 0x54078060, 0x1fb4358f, 0x019271b8, 0x334c0b4e, 0x9ba8cfb4, + 0x1ab3806d, 0x1fb436ee, 0xa1917fb4, 0xcab8373e, 0xe8e43f50, 0xb43c037a, + 0xed0c9fe9, 0x316f3787, 0x7687e7d4, 0xb447ea1a, 0x8f00c0fe, 0xd0c27b6c, + 0x8d87f47e, 0xed31fa86, 0xc7ea1acf, 0x00c17c5d, 0xd578e84f, 0xebb6fed0, + 0x44f00cc7, 0x7da1aef6, 0x037dfdb1, 0x0ffd593c, 0x93dbfb43, 0xa7ea1bce, + 0xd4333fba, 0x6ab9cf4f, 0x7f6a6780, 0xb6afb431, 0xa36546fa, 0x265d2aff, + 0xc059aab9, 0xeb4aeae5, 0x71ca3b1c, 0xdff03651, 0x7fc9d610, 0xd29ed0e3, + 0x62a5857e, 0x34b264fc, 0xd9f2443e, 0xdf70d26c, 0xe4af6911, 0x8c1ebccf, + 0x4c57b1ab, 0x06234f74, 0x361c8ecc, 0x0ec7ac7e, 0xb82ec41b, 0x806aa96f, + 0x8649bc13, 0x6ee589f6, 0x2fb27d43, 0x7fdf50c7, 0x07806685, 0xda191754, + 0x31e8dc0f, 0x528169c0, 0x3a8cfb43, 0x6ace01af, 0x1fb43728, 0xa867dfb4, + 0x30ae0dcf, 0x5a390fd4, 0x3687806d, 0x1fb4346d, 0xd4301cde, 0x0cea87e7, + 0x1b5a23f5, 0xb6c8f00c, 0xa3f686fd, 0xea1a0c3f, 0x351fb4c7, 0xd8bb8fd4, + 0x74278064, 0xdfda1b34, 0x80643d76, 0x8693b227, 0x33f6c5f6, 0xfab27806, + 0xdbfb435b, 0xea1ace93, 0x192fbaa7, 0x64ff75ea, 0xc657ce7a, 0x995fc2e7, + 0xf0d9fda9, 0x8792607e, 0x5e047f21, 0x6e356930, 0xa766f6c6, 0xde817f13, + 0xd0928f6e, 0x3e52f1bf, 0xf4261c52, 0x04c65f01, 0xe857c44c, 0x5c5057ea, + 0xafe29e28, 0x98dc5a64, 0x1f760377, 0xb4e67fe3, 0xfb77f434, 0x295df974, + 0xf6f88f5f, 0x6cd1d77e, 0xdb6bf646, 0xa7bca944, 0xd9a3c33c, 0xebf20e3c, + 0xd953df6c, 0xf8bfb809, 0xbbf414d9, 0x36c0b257, 0x2964e79c, 0xde1da62f, + 0x8c651d3b, 0x54e5e863, 0x6c2de03b, 0x1aa3273e, 0xb26e0a52, 0xbf6a9fdf, + 0xfb3bed4c, 0x130df115, 0x587d7fac, 0xbec28fff, 0xadbf0640, 0x05720fc1, + 0xfc0fecbe, 0xfc7bc12a, 0xf5ef0449, 0xefdca9bb, 0x09f2a1cf, 0x07f546bf, + 0x3f0445fc, 0x1c10f7ed, 0xd95297f4, 0xf3d2f7e8, 0x8272fe43, 0x197ec08f, + 0x7fb0a3cb, 0xd859f2c6, 0x73fd6307, 0xf8462fb0, 0x9500fea7, 0x7a3afe4d, + 0x81bf82fe, 0xfbfc97e0, 0x3fb9fe09, 0xffb36548, 0xfaaf9528, 0x35fea89b, + 0x6fc1337f, 0x870443f8, 0x1f04adfc, 0x7c11b7f3, 0xc121ffc2, 0xa9dbfb6f, + 0xa45ff56c, 0x077f1df2, 0x5ff29fd5, 0x9e8bb827, 0x12387f46, 0xf88a9f9f, + 0xe37e132b, 0x2c3fc172, 0xcb8bfb9e, 0xe5b02b38, 0x932d6f82, 0x78c10dc0, + 0x46ecbf60, 0x891d7bcc, 0x7c43957c, 0xfc56ea75, 0x98fdc8f9, 0xf19f025e, + 0x133af4fd, 0x76e8d78f, 0xe817e45e, 0x03c5527e, 0x00bb1f7c, 0x273c5ffc, + 0xee28cff8, 0xb6a95eaf, 0x573fa0e4, 0xf0d68a61, 0xf54ae51c, 0x610fc81f, + 0x220dde78, 0xb66bdf72, 0xf6c33b83, 0xbef01571, 0x4eafde19, 0x54f9a34d, + 0x9d0b56b0, 0x23cccaa3, 0x33dd5c81, 0xf89d77c0, 0x4039807a, 0x98256afb, + 0xff38fb8d, 0xf05fdf00, 0xa5ea95f9, 0x547e136f, 0x670fce8d, 0x770942da, + 0xa4e4fc61, 0xdebff144, 0xf22551f0, 0x7fad7bc8, 0xfa0a52e3, 0x937fa5e5, + 0xd39f487c, 0xc6394716, 0xf8839c13, 0xc839d4be, 0x5263286c, 0x30418e7d, + 0xaa393f9f, 0x0a0335ef, 0x759df4ff, 0xeb4fee47, 0x81df47da, 0x9bf0515b, + 0x42db98cb, 0xf3cc8d79, 0xb85d5e16, 0xbe08f993, 0xfca8058b, 0x35cf8a5e, + 0x0fe62468, 0x8df60905, 0xb4f6a5b5, 0xa579c8ae, 0x207ae20d, 0x50d9906d, + 0xb9f5484e, 0x393fbfb1, 0xd3af343c, 0xc6cf6e63, 0xfaf3e975, 0xdf9baa5e, + 0x4f1d609f, 0xf4fefce3, 0x4c1757fa, 0xe3f9dd19, 0x0a17c01f, 0xc7686f9a, + 0x06a41cf0, 0xafdf0764, 0xf289aef9, 0xa8be75b9, 0xbe2180c0, 0x7944c9b7, + 0x027c5dfe, 0xb0fb81fc, 0xf7ba0ef8, 0x01327c07, 0x8c6ab9d7, 0x5f82b014, + 0xcc1cda79, 0xf2b9d136, 0x15c62b52, 0x7f03c796, 0x07cef7a4, 0x03fdc56b, + 0xd7f039fd, 0x2fcf48ed, 0x073a317e, 0xc6f555f1, 0xabe23718, 0xc0740cc6, + 0x923be37d, 0xb857f3c6, 0x0dc697ea, 0x932678a5, 0x4fe30d35, 0xeb3d6d33, + 0x7f82e5db, 0x4a59274e, 0xf19fd483, 0x413ee5fc, 0x3d04fbb7, 0x64fbafd7, + 0x3ef3048d, 0xdd12ec7d, 0xff36e95f, 0x983c8f8d, 0x55c7c619, 0x78a767cd, + 0x5bdfd07a, 0xdf3a7f44, 0xef875648, 0xaf3e12a0, 0x465e3e4e, 0x7c0b12fc, + 0x7c7c419c, 0x6719cf01, 0x7731dcd9, 0x280ed941, 0xfbe94109, 0x81f69567, + 0xe546988b, 0x72a5e612, 0xf91d9039, 0x6dd81bd6, 0x62af7c45, 0x6d7cf44d, + 0xf21762d1, 0x8fb332f1, 0x306bc9f6, 0x7dcf1753, 0x12494759, 0x36ea4bc6, + 0xe80495bf, 0x7bb0d39b, 0x676fc632, 0x85be1707, 0xd321d965, 0x055bcc05, + 0xce2ef8b9, 0xbd54ddab, 0x7f8c1fb5, 0xb71373f7, 0xb3e787f6, 0xf60f4e24, + 0xae87a72e, 0x0dd72237, 0xe499b072, 0xeb43d633, 0x06a59c92, 0xc2d8a839, + 0xaef8a63c, 0xb94ef9fc, 0xfbfd5a28, 0xe4bfa8fe, 0x54178a0e, 0x438b61bd, + 0xdc62af3a, 0xf479301f, 0x07ee8878, 0xd5f3e230, 0x76c35a2c, 0xfebe0a9f, + 0xbe230074, 0x1b04d4fe, 0xff2e82c2, 0x92faa594, 0xecba320a, 0xb9f99575, + 0xb0278861, 0x9f89fbe7, 0xcb6d37cf, 0x1fbd434f, 0xc4ff454c, 0xab4dacf2, + 0x15d83349, 0xae9f75f6, 0x16a3d738, 0x9c8a871e, 0xede8a997, 0x623fa33f, + 0x9e00b2b3, 0xb35c8083, 0xfdcf2851, 0x355724ac, 0x978c5a88, 0xf9baf24d, + 0xffb1ac39, 0xadbe62d3, 0xdd71e57f, 0xe307ac00, 0xe1c7dd26, 0xdd16ca76, + 0x0de90e35, 0x9a71a317, 0xead19107, 0xed298f1c, 0x37bfe829, 0x8e7efb44, + 0x3fe3d1f4, 0x35b2befa, 0xba4c93ed, 0x52f63697, 0x18f7dd05, 0x80fba363, + 0xd8b88877, 0x2e3c451d, 0x071e8776, 0x07111f1b, 0xb0c7888b, 0xc5c73df1, + 0x98ccbd74, 0xe4f9c166, 0xd7d4ffb2, 0x5d18f14f, 0xabb3760f, 0x8a3690b0, + 0x6e29bb57, 0xc99f19d1, 0x4cf8f2b7, 0xd5c53249, 0xee4f42ad, 0xa4fd72f2, + 0x0e589fbf, 0x3ec3185b, 0x0d32cec2, 0x00d508fb, 0x324ea80f, 0xd1b81fb4, + 0x0b4fa86d, 0x33ea18e4, 0x9c0334ea, 0x686450d5, 0xc7bf683f, 0x4b06e700, + 0x1c87ed0d, 0xa1e01af5, 0xf686e54d, 0x867d9bc3, 0x0ad0fcfa, 0xd688fd43, + 0xb23c036a, 0xfda1a36d, 0x86030fe8, 0x75ed31fa, 0x1771fa86, 0x84f00c1b, + 0xf686fd8e, 0x1a0f5db7, 0x1fb227ea, 0xed8bea1b, 0x93c0333f, 0xda185fd5, + 0xd3ec253f, 0x862d49ed, 0x5c4407e7, 0xa4fbaa62, 0x39e9fde1, 0x53f00c67, + 0x87946f48, 0x879256f9, 0xf783f596, 0x07fd0055, 0x186b37ac, 0xfda999f3, + 0xab2fd0d6, 0x6dfc47ee, 0x52cfe28d, 0x947cb6a4, 0xedcca7db, 0x6d3e5869, + 0x7dc16f72, 0x89f8c66f, 0x2acef614, 0xcb05b859, 0x9b363341, 0x9f40dc13, + 0xa0b707b9, 0x68a90c98, 0x1e00bb31, 0x16ece4ba, 0x8d61d217, 0xfc444a49, + 0xc1ab486f, 0x89a6c472, 0x8fd41252, 0x83585dac, 0xfd71757a, 0x61cb8599, + 0xd837a35e, 0xa09dcd89, 0x3e30da0b, 0x6f887b26, 0xe29b0037, 0x8c8c363a, + 0x5dbbfca6, 0x37191563, 0xba76bb33, 0xb86e316a, 0x1d41676b, 0xafc0db96, + 0xac620e0f, 0x2c7afc0e, 0x1f5f8277, 0x386e8584, 0x945887f3, 0xa9e07553, + 0xdfd73c24, 0xcd53e93e, 0xfb0ae1ac, 0xe3013dcd, 0x8b4427d6, 0x737ec7bc, + 0x7f426627, 0x0f00ab28, 0xdcfa71f8, 0xbe1dd280, 0x2a3bc436, 0x372a1707, + 0xd7bfa1a4, 0xc0c0dfad, 0xc3e227b9, 0xa27805fa, 0xf5fa6dfc, 0x785fb078, + 0xc3de63de, 0x9f6e1ce4, 0xf59ae407, 0xd7ca023c, 0x943a2ee2, 0x80c497e0, + 0xd31fab9e, 0xf80e5bea, 0x136ad595, 0xf71637dd, 0x4da43056, 0x5f1be071, + 0x700f16df, 0x64ef7892, 0x8e0e6f9e, 0x72e380ab, 0x927f8c2e, 0xc61c0096, + 0xbf00fb1f, 0xf35d2ce7, 0x0e67dcb1, 0x2c2fa0c8, 0x069a65c5, 0x20b93ce3, + 0xfb9d369a, 0x22ff46ac, 0xfc9de44b, 0xfbcc473c, 0xfd0d1cc6, 0xf58b9fa2, + 0x8df7ee3c, 0xfd82d8fe, 0x7932a0af, 0x40f98849, 0x579a29cf, 0xcb0ad4c3, + 0x8cda3fd7, 0x07c04ef7, 0x8a3b426a, 0xf98737cf, 0xb8732b1b, 0x5af9625f, + 0xa5baf8a2, 0x85c5abc6, 0x4c916f8d, 0x4fed3dd5, 0x1065e237, 0x5186af7c, + 0x49f8e5bd, 0xac9f4fba, 0x52969835, 0xe786213f, 0x3f884a21, 0x4d05a7ef, + 0x923e004b, 0xff7c36e3, 0x9812dfa1, 0x4fbc787f, 0xbe6136ae, 0x6aa6e242, + 0x5121e213, 0xbe786af5, 0xc35edcc8, 0xc6e275f9, 0x1e3fa3b5, 0x6af6f381, + 0x99610798, 0xc87df3ae, 0x9cb5448e, 0x703262d7, 0xea5ee2dd, 0x1316b755, + 0xf43ac3df, 0xe7e76952, 0x3bd5bd5b, 0xa6a9de0b, 0xc502d7bc, 0x4f58478d, + 0x07e52be5, 0x23b3e07b, 0xa92fdc39, 0xa3e71a77, 0xc217e7e8, 0x19555c6e, + 0x6f425bb7, 0x61cb1fdc, 0xf3fb9fbd, 0xcdd9120b, 0x44dfbbe6, 0x5c3ab1e7, + 0xde20e30f, 0xd8b46fea, 0x98f56f11, 0x8bf64167, 0xfa7add91, 0x77073987, + 0x4ff3ba9a, 0x89003937, 0xbe40298b, 0x01ac1b3c, 0xadf239fc, 0xca69fa1a, + 0xe84ccb83, 0x6ab1240b, 0x4652184a, 0xc3cab496, 0x72bf326e, 0xfa27ff23, + 0x64c1f28c, 0x37dd325f, 0xfdd57410, 0x7474ee82, 0xde206627, 0xe579e5df, + 0x89dcd3eb, 0x5f9d4748, 0x63fc9fd7, 0x0e8c2f94, 0x2e7e081f, 0xca120d62, + 0x44d658eb, 0x46d678e5, 0x075877e5, 0xcaa61e95, 0x1a624e58, 0x4bcc2595, + 0x4d5614e5, 0xa06b2965, 0xa26b1a72, 0xa36b0672, 0x5453f612, 0xfb4a997a, + 0x57e0d9be, 0x79973960, 0xaac79ca9, 0x7c80bca9, 0x672df80e, 0xcddf040d, + 0x066ca89a, 0x841ee03d, 0x953b0971, 0xc59e81af, 0x127f0df2, 0x9bbf2195, + 0x97186db9, 0x84f2a1c8, 0x6df2a35f, 0xad95117f, 0x7bb50f7e, 0xe54a5fc7, + 0xca97bf29, 0x2a72fed3, 0x6a3efcdb, 0x057f9ef7, 0xabf81f95, 0xff37fca9, + 0xf43f2a46, 0x77fca807, 0x59951d7f, 0x06fb4656, 0x9fca1396, 0x3948f40d, + 0x81b8f56f, 0x1cb905ae, 0xe63dc78f, 0xa478dc84, 0xfe30cca7, 0x271c94aa, + 0x66dc5126, 0xe757bfba, 0xa316c63e, 0xfdcd3e3e, 0x83a24748, 0xe1a554fc, + 0xc8bcc304, 0xd4bb5366, 0xcf6b6807, 0xe7b5cff5, 0x8d7f1d82, 0x10d1f6d5, + 0x0763ddae, 0xa5b4f47b, 0x5047faad, 0xf378fd2f, 0xced83b5c, 0x3ef78eb1, + 0x54c3967b, 0xab04e63f, 0xe6760151, 0x5783df6e, 0xa81e70b2, 0xbc7e93f7, + 0x4ce6ee63, 0x27d7279c, 0x500d77b0, 0x853ad5fe, 0x1bf2aff2, 0xa1a3e58e, + 0x14ad531d, 0x6b0bdda0, 0xde8af147, 0xebd645da, 0xe9593def, 0xf50f1092, + 0x01eda07f, 0xe508c94b, 0xbc2c5c63, 0x1bb7f35f, 0x1937499f, 0xe99dbc3f, + 0xcc9dfd26, 0xfee6a4f3, 0x91e7c07f, 0xfaf96dfc, 0x3be8cff8, 0x0a23ac1f, + 0x9631bbe5, 0xf00e9feb, 0x55ff719b, 0xcdfae02f, 0x3747e4e9, 0xdf7379ea, + 0x31bea993, 0x8ad2bb5a, 0x8a4ce6f0, 0x7ac7d487, 0xfdb173a2, 0x43d274d6, + 0xe5187d29, 0xded2edbd, 0x7261dd56, 0xeb97353f, 0x35c2655d, 0x8bea3175, + 0x8f0cc9ef, 0xef7e07da, 0x01dbd683, 0x66adee6f, 0xcc529efa, 0xd14a0f84, + 0xc937042e, 0xf3a124a3, 0x3a2fd518, 0x5dbafb82, 0x1b3a359a, 0x51107ae8, + 0x9d5ffe87, 0x4a5ffe42, 0x7e3e50df, 0xccab6a57, 0xf522d7f3, 0xbe316edd, + 0x86d851d9, 0x6f9fadef, 0xa4bc6377, 0xef58fd37, 0xf9e3e40f, 0xb7da2bb7, + 0xac3c8190, 0x7e3e7dc8, 0x2e15382b, 0x1e6bf727, 0x17363dcc, 0x8bd543ef, + 0xf1add8bc, 0x8adefa66, 0x283ae052, 0x58abf585, 0xb3b26e43, 0x62c72166, + 0x523bf53d, 0xfbb8ef28, 0xd7f68d3c, 0xc23cc1a1, 0x88bd74f4, 0x378e745b, + 0x2941dfa2, 0xd8a7ae2c, 0xa78d1a42, 0xbc7d33db, 0xf1bdff9d, 0x4f7c8976, + 0x28c73c7d, 0xd61cfae3, 0x439f5a36, 0x78fa41f8, 0x3d7d70bb, 0xe37c8de4, + 0xf0beb878, 0xd71b46f1, 0xd1b5b0e7, 0xf7121cfa, 0xdbc73a6b, 0xbd78f3d9, + 0x2237b38d, 0xf72f4fff, 0xdc13ff0a, 0x180e7643, 0xf9c6c534, 0x330b69f9, + 0x92bc039c, 0x1ff3edcb, 0x595f38f2, 0xc97ae36e, 0xfdd2b2e2, 0x8bae89a4, + 0x95af91bb, 0x173a663d, 0x26dfe253, 0x3c4e4b3f, 0xa7da24c5, 0xfe7c26b2, + 0x17bf89b4, 0x98f6b048, 0x5fd7b367, 0x2c333a34, 0x55a89dae, 0x6b6f309b, + 0xe195aba2, 0x6f128039, 0xf12bf5a5, 0xea1460f6, 0xd8098d5f, 0xfe83ec1a, + 0x8bdf50c4, 0x974f30b9, 0x15c5e5c6, 0xf9883d6f, 0xd0e58954, 0x9e3e186f, + 0xe4cc7c16, 0xb0b2b4f6, 0x791d42fb, 0x5cba1f1c, 0xc36fce47, 0xc6878e60, + 0xea2af049, 0x8e3c31cd, 0x3f70fa73, 0x7accc7da, 0xfb83da34, 0x063bd3fc, + 0x73bc1097, 0x9c01e52c, 0x0a763c3e, 0xed666bee, 0xd826669c, 0x3e315ac4, + 0xdde76b33, 0x929e7c66, 0x1dfe88c1, 0x5fa4ad67, 0x255ced67, 0x14d3ffda, + 0x0e645f6c, 0x1ae304fc, 0xed1d0f45, 0xb19b7183, 0x63fa178e, 0xbedcda79, + 0x7477bf01, 0x857eca87, 0x73779bee, 0x7d4d039c, 0x0b748ed9, 0x977ec5c6, + 0xe697cfcb, 0xe7858f30, 0xee29788d, 0xdb68fe30, 0xfc82bc71, 0x628ea69d, + 0x34f76e3c, 0x9cb027ab, 0xc84ad214, 0x9ef56c2d, 0x5b4a72c0, 0xbbba0975, + 0x9c361fa5, 0xb861b2c0, 0xdf8877ef, 0x2a8e0fc3, 0x49c60678, 0x68dceefd, + 0xb7d277f4, 0xa41e4e84, 0xee85b1b8, 0xf22dedb9, 0xde3049d6, 0x8ed7b75e, + 0x7c6f6876, 0x6bf499ba, 0x5a0af56c, 0x866880e7, 0xfaabdceb, 0x6fbfd0a2, + 0xef46e714, 0x2c4731f8, 0x7f3479ec, 0xbfe099fe, 0x1ed7aaad, 0x52a0724b, + 0xfc2283be, 0x49e67ab4, 0x3b284342, 0x1b8c413c, 0x3d70f5ee, 0x7ef8501e, + 0x036f9b19, 0x98ae8ebf, 0x29e8bb9a, 0x7f31b26b, 0xec1bdc1a, 0x50ed1657, + 0x883fa217, 0x06116ed7, 0x13bfc1fb, 0x743db8c4, 0x673a2e28, 0x172fe7d0, + 0x7c617f42, 0xad9ff386, 0x8fa7bd74, 0xf6160eab, 0x5ed3f041, 0x9f4fef1f, + 0xb760ec6f, 0x731b5ef8, 0x923e719b, 0xc3ac0f98, 0xb09f361c, 0xcebeb476, + 0x892d3379, 0x30f59fdf, 0xb996af7e, 0x3bf5b0e5, 0x44bb5e6d, 0x22acd076, + 0x33343aff, 0x28704bdd, 0x04fba73f, 0x1ac8eb91, 0xdf69e3cc, 0x051f6197, + 0x79a699eb, 0xf7e5ca18, 0x55f90f55, 0x78e580b2, 0xe3c987ee, 0xd84b3127, + 0x49f8e57a, 0xb41a6ed4, 0xb4e7f8c7, 0xf21a3ea2, 0x54d674eb, 0xc17df2ab, + 0x5f984c89, 0xfc866316, 0x4fc05974, 0x9650bf96, 0x71abc6e6, 0xe8392d0d, + 0x8cb03d17, 0xd76a8cf2, 0xf9c56b4f, 0x6bace526, 0xef7a8389, 0x2cee9c57, + 0xfb0dc79f, 0x790d91ef, 0x002bc9cb, 0xf75f3f0e, 0x07e06119, 0xaf9d7b43, + 0x8aa95314, 0xcfb9847e, 0x3059dd8d, 0xedc9d97f, 0x6cb87837, 0xf2f10f6e, + 0xf0257c6e, 0xc667d3af, 0xa7c24ce0, 0xb3bc70ac, 0x277ecd0e, 0x1bf113a7, + 0xd5e309fd, 0x3e62d880, 0x14894d7d, 0x8ea1fbc4, 0x012cf6ce, 0xa7491ae9, + 0xeec75b74, 0x957f5c2c, 0x23dbf299, 0xc47e0af1, 0x67c8699d, 0x1ea9e26b, + 0x3abe539e, 0xf6752266, 0x1b04f523, 0xed4df1e9, 0xddc1609f, 0xf8d64f3c, + 0xe0be293c, 0x8a429c9d, 0xcc9c6847, 0x0dacfac6, 0x8c62ba46, 0xa278f509, + 0xb4a182c6, 0xb4e7a75b, 0xa612c6f8, 0xceaba774, 0x7b7d2977, 0x10f2f3d6, + 0xea03b093, 0xf3d41cb4, 0xfff26609, 0x84e609bc, 0xd6f07df0, 0x725f7cc1, + 0xe90a2bdb, 0x4ede766f, 0x50b4eff7, 0x13f41f5b, 0x93335d27, 0xa9d6fe7f, + 0x834d8f63, 0x96aff272, 0xc9bb61d4, 0xbf46edb0, 0x372be862, 0xbf262c46, + 0xe5172da5, 0x3a1655f5, 0xb1f682d9, 0x827142d5, 0x536f9fcd, 0x35fd2127, + 0x7d3e7146, 0xb98323dc, 0x25a5fa9d, 0x9a7d25e0, 0x7e46b326, 0x6be3765e, + 0x3e3c4e9d, 0xb2c77944, 0xabddaf89, 0xbd935755, 0x3663c94c, 0xadb7c78a, + 0x21bc7b24, 0xccbca19a, 0x41ee9b56, 0x1765f678, 0xb37f4333, 0x2165b735, + 0x3f091f9e, 0x59aa8e73, 0x69a96226, 0x3f9db9fc, 0xe87aab9f, 0xc3cd5cf9, + 0xbf7c2b9f, 0x681aa77f, 0x777f43f3, 0xec6e712a, 0xcbcd4eef, 0xa8dbafeb, + 0xffec14fe, 0x47b4efd0, 0xebd45405, 0xfccd170d, 0x4d17ce7c, 0x2955befc, + 0xfce37568, 0x4f74cd0a, 0xba24fc0f, 0xf54bbd5f, 0x7deafdd2, 0x088c97cc, + 0x3670b57e, 0xc6afd1f9, 0xd5fee99b, 0xe5331eab, 0x642a0581, 0xf0521f7e, + 0x29e5abd1, 0x8e967e74, 0xdd7a44c8, 0x643f2763, 0x62441e2b, 0xdc7ef2fb, + 0x7fdcc85e, 0x9e2a3fd8, 0x2c6d3bda, 0xe0f914ae, 0xf2f94cb0, 0xe3cf1fdf, + 0xf4a1f298, 0xae6bfa20, 0xcbbca30a, 0x3f389385, 0x39454c68, 0xc469a198, + 0x987b35f7, 0xdc937666, 0x5740fbd3, 0xc2aee75a, 0x22fa4af7, 0x24d346bc, + 0x7d06182e, 0x1ef85351, 0x4ccf83c7, 0x0abbeff9, 0x49befbc5, 0x5d7c7087, + 0xf90b07ce, 0x774af5d4, 0x3f51a43d, 0xda49d88e, 0xc306804e, 0xfbff2800, + 0xf51cf0ad, 0xf74c9c42, 0xca1706c6, 0x97587521, 0x7e8b27dc, 0x94f90b07, + 0x2ce51a8f, 0x7e1190eb, 0x7eefc85c, 0x62fb9216, 0xce8c0dbf, 0x1837facd, + 0xc7cec1db, 0x522c7a84, 0x3f0baf8e, 0xdd0f1233, 0x79ebecf0, 0x0aeb5d9d, + 0xbad36544, 0x425d7ccc, 0x5b2a65df, 0x2aa679e8, 0x179c6e6b, 0xd70f786b, + 0x0c90ffdf, 0xabd02a0e, 0xe31b3cd0, 0x3202333c, 0xac99bba9, 0x37c5f48d, + 0x88ab7bad, 0x33ae4573, 0x06db7d72, 0x64bf5c4b, 0x37e4bcf8, 0x37e4cb25, + 0x6303d659, 0xe56bc70c, 0x23b79dde, 0xeece875d, 0x59da0433, 0x62a5581f, + 0x7a155a5c, 0xc4b5f2c9, 0x3b61ebf9, 0x7125abf1, 0x7df84e46, 0x24da919b, + 0x51c50875, 0x841c9eaf, 0x2d77c771, 0x3d48ff84, 0xc7086637, 0x637698f3, + 0x8bb8e45e, 0x7c7911d1, 0xdbc8bcc6, 0xc88bf7ae, 0xc888cbe3, 0xa8621be3, + 0x888eac9f, 0x171be3c8, 0x6c57c791, 0x4ce7a780, 0x9be3c88f, 0x28ef8063, + 0xbed0c7ba, 0x50d8b3cc, 0xb574a73f, 0xef4efea1, 0xaef806fd, 0xed0d87f2, + 0x0c6afbe7, 0x78acf7f5, 0xfa0f50c4, 0x73b8c7a2, 0x87ae10f1, 0x6d3c936b, + 0x103081f4, 0xfe0f6f78, 0x1dcaa480, 0xd9c7f6e1, 0x56a2fecb, 0x7d29e3d0, + 0xe248127f, 0x8f116671, 0x10c47705, 0x9d8d0daf, 0x517dc766, 0x444b4d9a, + 0xcd7ecebb, 0x585806ed, 0xc4e6f9c3, 0xdda94b07, 0x3a74d8fa, 0xfc027987, + 0xc0e81f6c, 0x77cf20da, 0x6f0017e9, 0xabf79e1c, 0xf5da1285, 0x78a56ebb, + 0x583ce76e, 0x5577f529, 0xf3ea2f9c, 0x43f18fdc, 0xecdbee1b, 0x54cf3254, + 0xe28e3f1e, 0xe9751eed, 0xc31a96e7, 0xd6451d7e, 0x164be500, 0x30ac5b06, + 0x8fd05adf, 0x97849af8, 0x55dda1ec, 0x3de9bb45, 0x127f1ab0, 0x96520fdd, + 0xe8160284, 0xbf27eab2, 0xf0e3e1f8, 0x1463e2be, 0x27f878a7, 0x7e21fcbf, + 0xc43fc407, 0xc871744d, 0xeefbcf1c, 0x874ba7fd, 0xbac65f51, 0x64625ee8, + 0x9b7de27d, 0x26eb7abe, 0x3c16fbf5, 0x37a5dbf8, 0x8ddeff7b, 0xd586b767, + 0x597f36f7, 0x613cc7e9, 0x356a907c, 0xcbd5c3de, 0xaabe0bef, 0xf8a56b1a, + 0x57c92ce5, 0xe5fcf28f, 0x707affd8, 0x45f7bc3b, 0x717bb5c9, 0xbfcf077f, + 0x1da1cf8f, 0x948bf5e1, 0x3cf8a92b, 0xfff80865, 0x58a36768, 0x6f7cf98f, + 0x8b7ee10c, 0x41d1589c, 0x2b04f3fb, 0xf65c87c5, 0xee3fa3f9, 0x447358cb, + 0xf71ea0bc, 0xf7a760e5, 0x1e88f88a, 0xf4417f2f, 0x92944473, 0x41ce9f3a, + 0xf7403d98, 0xb17f7562, 0x8b383c9b, 0x651bee18, 0xae10be45, 0xac125b17, + 0x54901f14, 0x4b77e52b, 0x2efa28ea, 0x7d1b04a2, 0x2872473c, 0x68cfb46d, + 0xf1451849, 0x86342900, 0x128a0ce2, 0x40defea2, 0x7ee024ba, 0x77dfb8c6, + 0x5d682bd9, 0x3acff7bd, 0xeb49f79f, 0x79889c61, 0x1f5878e0, 0xfc41ce39, + 0x9bda1c2e, 0xe31ef665, 0x4c86d71b, 0x4af48e3c, 0xbeefb5b3, 0xfdf5e51d, + 0x5eb2f59e, 0x307f9e62, 0x86673f0c, 0x605f13a4, 0x6c307f7e, 0x0fe3cc5c, + 0xe8038187, 0x60c1079e, 0x42d8066a, 0xb9f88351, 0x6f578d05, 0x3fc892d5, + 0x7487f304, 0xe7908dfc, 0x61af023f, 0xc3ec57b9, 0x635c83f7, 0x255f84f9, + 0xc800ed3f, 0xfb4fc21f, 0xfd0654dd, 0xfa365439, 0xe43faa35, 0x88f8222f, + 0x51f043df, 0xcf95297f, 0xfcf4bdfa, 0xc1397f39, 0xa8fbf53f, 0xa0aff26c, + 0xabf82fe7, 0xbfc97e09, 0xa39fe091, 0xe785985f, 0xbe547513, 0xfaa06fea, + 0x09fbfcd7, 0xa41fc37e, 0x4a3fe432, 0x9bf98fcf, 0x6fe13e08, 0x7f6df826, + 0x7f56e088, 0xf8ef952b, 0x29f9e8db, 0xa30487ff, 0x45fee23a, 0xe03f19d2, + 0xd9817125, 0xe25e7e8d, 0x4bb34582, 0x2e57de00, 0xd7617dd3, 0x41d2f97c, + 0x34278be0, 0xfb7bf699, 0xee299856, 0xfb95fba3, 0x16c7d62a, 0xaa5cfd53, + 0x268d486f, 0x12ff6cbf, 0x571fdd2b, 0x967f7256, 0xbda8552d, 0xfd532f92, + 0x92e62b13, 0x538f58df, 0xd92ae700, 0x1931d81c, 0x93322ddb, 0x111fdefe, + 0xe3ca4dd7, 0x4f293f76, 0x8faff7e6, 0xcfc20546, 0x629b2b29, 0x7355700d, + 0x30e3e072, 0xc62d59be, 0x1c991b61, 0xcfc7ddfe, 0xaf307ff7, 0x90f9d604, + 0x03ca4be4, 0xe0717c7c, 0x99d83cdc, 0xc3bdb332, 0xcce4f28a, 0x8d4ed9e8, + 0xebcfd3cf, 0xfe224e92, 0xe13269f6, 0x61b69f6f, 0x2fee265a, 0xddf4c816, + 0xf205c48c, 0xe99fb857, 0xfba65f37, 0x994acaa4, 0x816c81e2, 0x0363e059, + 0xfcdfbbad, 0x0eaf54b9, 0x7471453c, 0x6d13cad7, 0x016fd193, 0x1d11657c, + 0x39e2c50e, 0xbb88b26e, 0xa68f8fee, 0xf9c8b6bc, 0xf17bff8c, 0x33f009b3, + 0x8cfc47aa, 0x4f3f09ef, 0xfde3fb88, 0x222277c4, 0x977fa4f1, 0x7df109f5, + 0x1e06c0f2, 0x376c8fbf, 0x731fcc47, 0x2e3be8ce, 0x8fe93295, 0x23b82c03, + 0xf998e31b, 0x7e43dd32, 0xb3aad27c, 0x3f3e6107, 0x91ddf3c8, 0x2c9fed07, + 0x8ea18f91, 0xfde52b8d, 0x1f235c0f, 0x7e02be41, 0xda04795d, 0xe93bbf6d, + 0x7d94364c, 0x8c16ee03, 0x1f463abf, 0xf989f648, 0x161764f6, 0x80fbbf0a, + 0x2b4fc447, 0x651a3df9, 0x13dc9ee5, 0x3805dc7c, 0xb5f52bae, 0x0309f8a9, + 0x930edcf7, 0xf97eca05, 0xcf1c3af2, 0x49d24f76, 0xe0212f1c, 0xc7cbc7d1, + 0x9e2dbef1, 0x925bbf52, 0xf1bdd3d8, 0x37e1f4de, 0x79f5c1e9, 0x7f513ee2, + 0xe0f51fd6, 0x8a7696e3, 0x70ce0753, 0x38b4c83d, 0x3917bfba, 0x27f96f4e, + 0x649f8101, 0x886f3f1b, 0xe7476f7c, 0xf02025be, 0xf28cafd8, 0xe2cb26b4, + 0xf68cfabb, 0x4627ebdb, 0x726f9bab, 0xd403f31e, 0x1eafa0bf, 0x9fa263ce, + 0x1fbca994, 0x0267ef33, 0x44f0475b, 0xe4dc0d45, 0xe88f601c, 0x00fd8fc7, + 0x7bbf1f7e, 0x18adeec5, 0x42d77cb7, 0xc90e74b9, 0xcef49bb7, 0x1fda25af, + 0x2b0dccb9, 0x17f5878f, 0x9fa97c14, 0x48de6043, 0x79d7565e, 0xec055244, + 0xadf0c291, 0x88b8f7bf, 0xe3793fa3, 0x9bca58a1, 0x8510dfc8, 0x663edffe, + 0x2c503e27, 0x0c3f3521, 0x7f898a7f, 0xfe7227cf, 0x7aacf2c7, 0x7132805e, + 0x32239e14, 0xf519cf7e, 0x75fbcc28, 0xb77f939f, 0xd307c169, 0xfe3c0387, + 0x0fe74c9a, 0xfcd1a5ae, 0xcc1ff6fe, 0x86f46794, 0x677e1788, 0x63dd096d, + 0xf712c24b, 0x054fb8a7, 0xa626fc78, 0x9f7df085, 0x09c1fb42, 0xe173e5d7, + 0x0ab2097e, 0x22ee37f6, 0xb8f2f8a3, 0x6f70d90e, 0x6345cc6d, 0x84bfa07b, + 0x76a4dafb, 0xa144bb63, 0x15235dff, 0x7e8ffefa, 0xd7f5d06f, 0x64c5b97d, + 0xff49a227, 0x24c9a93f, 0x2a164fcf, 0x76ddb107, 0xfb84bb3b, 0xbb7cc744, + 0xc5a07a8a, 0x557a4d15, 0xfe4d1119, 0x6394f6f3, 0x9fc076f6, 0x2a07e46d, + 0x6c032bfa, 0xbb1883be, 0xab73edfe, 0x218d25e7, 0x5df5de3d, 0x3bb022e3, + 0xf282f978, 0x9decd699, 0x1579899c, 0xd8eefa66, 0x7ab73c7f, 0x2277f86f, + 0x307524d3, 0x84ec57cf, 0xe0dfa157, 0x418fb9c0, 0x33ea063f, 0xd7c61cf0, + 0x29217a8e, 0xf905babe, 0xb6395eaa, 0x85d0e282, 0x2d57a4f1, 0xea10eabe, + 0xc0ad7a89, 0xbadf2e1e, 0xdcaadc9c, 0xd5ce293f, 0xbffe49be, 0xe4dedfa9, + 0x2e5c95fc, 0x01c5bd77, 0xb77e7df4, 0x5ebec4fe, 0xdfdfc21e, 0xe079f42a, + 0xbd47b5ac, 0xd72866bf, 0xef224517, 0x297c5661, 0x567e7f7d, 0x3cc65da0, + 0x2e50cf50, 0x1c12fb47, 0x2fb0cf94, 0x7e30858d, 0xedcf981e, 0xe20ad903, + 0x538a74a7, 0xd4da9bd5, 0x0a43d200, 0x2e2e91b9, 0xefe187d8, 0x6ddfd478, + 0xf977d20e, 0xfc28be82, 0x63f41e3e, 0x852817d8, 0xe4d5e2dd, 0x6871ebbf, + 0x7e008efc, 0x82b687ff, 0xca3a82e0, 0x9b9df4cd, 0x7426f7c8, 0xaedbe118, + 0xcc89e11b, 0x629abdf8, 0xac9e11bb, 0x43a1e11a, 0xf6e2bef9, 0xa9f3e324, + 0x6fdc236e, 0x9994637e, 0x78a0ffdf, 0x0c147e95, 0xb8c03eff, 0x64017f58, + 0x60f7e20c, 0x21afb7fb, 0xe8ff507d, 0x7eff920c, 0xcae2226b, 0x8195b00c, + 0xf3e36a71, 0x2d859cc4, 0xaaed7e98, 0x87be2390, 0x2ce746d2, 0x73c30f80, + 0xf20b7cfc, 0x9e6ce1ff, 0xdc30d9ff, 0xc8e87937, 0xde1c79ae, 0xcfce9b33, + 0x035f562c, 0x28c74efd, 0x36d2ec99, 0x9b75d399, 0x35ba72a6, 0x5779d327, + 0x60b44aa2, 0x5d5f3645, 0x4723c61a, 0xc91e299a, 0x3df9e21a, 0xd3fae7f4, + 0x2c6241f9, 0xe773439f, 0xfa47dbfe, 0x40d89d97, 0x2afb03e7, 0x788efa64, + 0xf9403db2, 0x2bceb053, 0xce963886, 0x39f9f3b7, 0x50d7ac0a, 0x62bceb0f, + 0x101f97e4, 0xa2f5f49d, 0xf0c206bc, 0x081a7280, 0xbe699b8f, 0x940788e5, + 0x51e7f0d7, 0xba16ed99, 0xd3d62d4f, 0x7aeadc9b, 0x579c48a3, 0xd76c79eb, + 0x1e7a98c4, 0xff9106db, 0xe234ecda, 0x24f95ae1, 0x6b5c338a, 0xebed139b, + 0x2f418e49, 0x2f5c6c04, 0xde1db960, 0x7bdfb943, 0x1c54e163, 0x2044f50f, + 0x16147bec, 0x6dffa7c1, 0xc221b3bf, 0xeffb3f2f, 0xf9186a47, 0x9e208f9d, + 0xe39c072a, 0x77c5edf7, 0xb6782cbc, 0x3ea5cf07, 0xcb7aaf9c, 0xcae9af1b, + 0xbae3b5bf, 0xbfbc88a5, 0x5af8112b, 0xbfa5f02f, 0x274d457f, 0x2d695d3c, + 0x2786f7b6, 0x1327f426, 0x332f13fa, 0xbb3e2ace, 0xec634121, 0x9fdfe799, + 0x671d0327, 0x985b3ead, 0xcf9bf00a, 0xcfc39eff, 0x3fa97d9c, 0xec361d34, + 0x3df879f3, 0x9d8f598c, 0xa1a296bd, 0x85de26dc, 0x8a70c3df, 0xbe7d1973, + 0x092f78fa, 0xf1b5597d, 0x90671e1e, 0x357724bd, 0x01c52f2e, 0x70ef8cbe, + 0x5542f9e2, 0xd16b8742, 0xd57ef44d, 0xfbf97bc6, 0x0a353e98, 0x5cb889f3, + 0xfbf3d6cd, 0xfdf98d4b, 0xd22ae74e, 0x5016367b, 0xd9442f51, 0xeebe743d, + 0x3a26e619, 0x72b4c9dc, 0xceeebe7e, 0x5accfa42, 0x3fd1ea6d, 0xe7aa1d6c, + 0xd5be86fb, 0x2bdc4cb8, 0xda245398, 0xc65fe3a9, 0x7b34ee71, 0xf05fa2b6, + 0x482cc67f, 0xcf41b740, 0x75d21a7f, 0xadd0ef4f, 0x759cffdc, 0x496dc4de, + 0xff278f0c, 0x575f3871, 0xed009c78, 0xf9746f46, 0x3c5d1bac, 0x89ad0714, + 0xa8ba70f3, 0x48cdce1d, 0xd70ed897, 0xd7debc96, 0x113e8ddf, 0xf82ab8f8, + 0xe42bfd1e, 0x9fc26fd7, 0x4f3d1f4e, 0xcee4c6ac, 0x40e67f22, 0x147c437f, + 0xaf6e0236, 0x76fe67a3, 0xc88f7d87, 0x38a5e49a, 0xcb5e2593, 0x9ae67cc1, + 0xe63d49bf, 0xe30f6777, 0x6766f37e, 0xaf17dd34, 0xbee95a71, 0x27738b5a, + 0xaecd3f43, 0x94bc236c, 0xe618eb38, 0xb3a6d5d1, 0x06edfe26, 0xad715e63, + 0xef5e6ef3, 0x9dacb3e2, 0x2e31eba6, 0xb4e7b5cf, 0x8103b418, 0xaf2edfd3, + 0xbfe76e58, 0xbd5bd25b, 0xcf1a6e33, 0x295a762b, 0xb18a58af, 0x5794f756, + 0xc7c117fc, 0x78beb82d, 0xa78f0f5c, 0xbbb2ebe9, 0x3e23fe79, 0xd59a78c7, + 0xafdfa3ed, 0x97ffd7d1, 0x7a2e9ca1, 0x9abb9b7b, 0xac97dea1, 0xacf51b9a, + 0x884fbe24, 0x4c272476, 0xffe3ea5f, 0xef85a869, 0x4a953597, 0x8ddb9db3, + 0x39eebf59, 0x30f47c3f, 0x9dc92dd3, 0xcdb337ce, 0x97466f3c, 0xd58ab9ef, + 0x5cc37e83, 0x7af28925, 0x2fea02e6, 0xffb585c6, 0x1efc5dce, 0x2125acaa, + 0xee3fbd3f, 0x07df97b6, 0x2e983df0, 0xa9bde9e2, 0xf59fba16, 0x7079899e, + 0xb79919eb, 0x4ec6f5e8, 0x1de3edc6, 0xa2d6ce33, 0x620c6638, 0xb0e43f74, + 0x78e762b3, 0xccc3fe46, 0xae60d061, 0xde326caf, 0x9e5d98c7, 0xafb616ff, + 0x8f407612, 0x49f55717, 0x91fe520d, 0x6c339be4, 0x3f8dc624, 0x6242559d, + 0xdf4a91df, 0x4f6aecbd, 0xf6b0e371, 0xd3fb45f3, 0x1d71c469, 0x2b83ddf4, + 0x3e8bb1ea, 0xf287d137, 0x8bf12221, 0x9dff0a74, 0xa07f5d35, 0xfe1167dd, + 0x48fc3879, 0x13dd394c, 0xbd57edd0, 0xf578e7a5, 0xbd0986af, 0x38adcba9, + 0x1f33b087, 0x4c91345d, 0x1ea7ee5e, 0x67d9f67d, 0xea7e5d5d, 0xf49f610e, + 0x8333a27e, 0xf98d1954, 0x549a502a, 0xaca3f10f, 0x60052756, 0xdaffdb9d, + 0x27f7fdf3, 0xf01e7975, 0x2fb61260, 0xb072fb71, 0xdf17cc8c, 0x072cba96, + 0x34db72e5, 0x946aeedd, 0x9cedbe37, 0xbe7437fb, 0x1bcf0efa, 0x9d90196f, + 0x4a517988, 0x59be45ab, 0xe415a65e, 0x3d137dd5, 0x3ff7156e, 0x631b1db7, + 0x36f4f8c7, 0xcf0da0a5, 0xf129b777, 0x536db405, 0xde901e78, 0x5e78515e, + 0x78f1a29e, 0xbcf0a2b7, 0xa77f3d39, 0x84dbc065, 0x03ddbd0f, 0x8d15af82, + 0xd288e3df, 0x5d9da81a, 0xb2f7d2f6, 0xe28cf1ec, 0xff957652, 0xa67450ee, + 0x907bd999, 0x2cc3b5d7, 0xe5b61f64, 0xa24db415, 0x146ec9f9, 0x05496d93, + 0x1147a449, 0x8d7ef0ef, 0x316f13a3, 0x0a9fc788, 0xd4fdebbc, 0xde75f0b4, + 0x417771bb, 0x23f45f49, 0x5f9087bd, 0xec8b29b7, 0x7246ef78, 0xbfb4de14, + 0x432661e6, 0x7f57663e, 0x7f450a97, 0x24fec53f, 0xfd8a8147, 0xbfcf5859, + 0xe8b6f8bb, 0xef3defe7, 0xfa360cc0, 0x226308de, 0xd494268f, 0x2761f9d3, + 0x631cf0fd, 0xfef7f744, 0xbd677edb, 0xfe09de31, 0xbf516fe6, 0x7b9de654, + 0xe13d127b, 0x68d6e6fe, 0xbf742fae, 0xfb795651, 0x0f7e66ad, 0x9abeff55, + 0xb1ca47ee, 0xdd743c46, 0xb874e303, 0xc838f2aa, 0x7c518555, 0xafae5226, + 0xb86e3a9e, 0xd8768147, 0x2c71fc23, 0x0cf4cfd1, 0x2e2973c2, 0xa3dcbadf, + 0xebfd444e, 0x1f7f7728, 0xa8a4abbf, 0x30b7ca66, 0x5f12ff01, 0x9243de77, + 0xc6cff47a, 0x3574e70d, 0x24685625, 0xb7284ae7, 0xe03f3927, 0x728b953a, + 0x1ecba07d, 0x03aeb8ab, 0x1389dce7, 0xbf5ce4c3, 0xbff7a21f, 0x3564e4fe, + 0x74df5d7c, 0x6e79c2ff, 0x8f64fde7, 0xff1edc5d, 0xd8c7df6f, 0x40aeb2ea, + 0x326cdffb, 0xc391e5ea, 0x86d63eb9, 0x75e0f88b, 0xb3b7ee99, 0xe1b4bea1, + 0xd98b3f80, 0xf97a8e5b, 0xdfdf3540, 0x1499b1ca, 0x7eb03987, 0x829e445a, + 0x30f0d06f, 0xb3aa2c79, 0x85abbe92, 0x03ed077d, 0x491ae823, 0x3afe9d2f, + 0xe7e728ec, 0x27bd3a72, 0x91212a26, 0x89fe4c07, 0x09997e2b, 0xdcab9af5, + 0xb039f267, 0x81d91b7d, 0x115ddade, 0xaf6f4ffa, 0xce0aff60, 0x73e280af, + 0xa0e75057, 0xfcf6a49f, 0x51976cfb, 0xec7e0498, 0xb1e72eb0, 0x2bf62aa9, + 0xab793f09, 0x51af6fc8, 0xb09eed0b, 0x42d8a5f7, 0x3e30a4fb, 0xde25e9a9, + 0xc7ae1fe4, 0xefb4439b, 0x4810efd7, 0x9e60d7e8, 0xee5f22a0, 0x7ed0478c, + 0x9df0d4a2, 0xdefc7d45, 0x5f39edcf, 0x690b555f, 0x018f281f, 0x0bfc017f, + 0x8192ec53, 0xbe2d3764, 0xfcc44e7f, 0x28dadf95, 0x2123f79f, 0x3e42ed9f, + 0x0163d37b, 0x2d2e8c76, 0xf027616e, 0x49f008d2, 0x49f20c41, 0x70d98a4d, + 0x9b97a3ae, 0xe26f3ac4, 0xbf0f54e7, 0xc1e73f35, 0x39f83de1, 0x9f84c7e8, + 0xe2ffa3cf, 0xe89bd309, 0xf07a78bf, 0x62cdea73, 0x53ce27ff, 0xcddc5b4f, + 0xd39780ed, 0x3be86213, 0xf87d193f, 0xe8d3df3d, 0x7f8015f7, 0x4cd9ccf7, + 0x532cd624, 0x843a77e7, 0x0608c99f, 0xca276f3f, 0xaef31945, 0xd5bddfc2, + 0xdf8988e5, 0x3a26f9a3, 0xe0dc06cf, 0x3de3b6bc, 0x87ba3cbc, 0x39d3da57, + 0xfe4eb1de, 0xc7a61301, 0x401f08fb, 0x5a38b09d, 0x4460f8b7, 0x31c3103c, + 0x19c5f99d, 0xbf6fdbdd, 0xf9f8a261, 0xe20b1f2e, 0x51dc02ef, 0xbddf8c64, + 0x76d9f225, 0x7f24612d, 0x429a72bb, 0x6a245fe8, 0x65f1e28c, 0x39fb631e, + 0xbddf91a5, 0xeef9c636, 0xe7225af4, 0xebb5df4b, 0x7fd7d627, 0xff8a2acf, + 0x22fdc645, 0x3eb47de3, 0x3c8523b4, 0x1854afee, 0xf51cb8f3, 0xd8bbe833, + 0x714af860, 0x3314ae7d, 0xa3ac38c3, 0x2dcf323c, 0x21ecf020, 0x59e3a665, + 0x92899eff, 0x6bdfe66f, 0xf546dc0d, 0x7e1dbe7a, 0xaba27177, 0x3aca5d6b, + 0x117c9f31, 0xbcf40dcf, 0xd7185dae, 0xbce8bcc4, 0xd084d036, 0xc605ce1f, + 0xf460ae49, 0xb75857bd, 0xf0e25ce1, 0xfa262d9e, 0xa31f0f1d, 0x1e01a1ef, + 0xcc16e78c, 0x5850f147, 0x039ce1bf, 0x238069d6, 0xe4df01f7, 0x93de1fff, + 0xa277e3de, 0x278f52f5, 0x61338b75, 0x2fa48007, 0xbdf38b86, 0xfa286ca1, + 0x06fe4a41, 0x1495c3a2, 0x72cb5f9e, 0xdbdf3e7a, 0xf7e1fd09, 0x72887e93, + 0x01718092, 0x04def866, 0x0f74c8f3, 0xe7c454c0, 0xe5ebea6a, 0x48c79742, + 0xccd16dbe, 0xa684798e, 0xea0f6882, 0x600d9b13, 0xf8852efc, 0xee24b74e, + 0x283ffd3f, 0x00812bd4, 0x0000812b, 0x00088b1f, 0x00000000, 0x9095ff00, + 0x50c34b31, 0x97bf8514, 0x4a36ac46, 0x1056dac1, 0xa8508a09, 0x755a5095, + 0x97375433, 0x221d0e8c, 0x38ba383a, 0xfc5d251b, 0x09f9ce01, 0xe6e284fe, + 0x482ae0e6, 0x22bf8290, 0x26a697de, 0xcbbd0820, 0x77dde779, 0xddf73dce, + 0x2e8dcc2b, 0x5eca7550, 0x75619047, 0x444506d2, 0x9aea1152, 0x47e17536, + 0x3cd6a5a4, 0x7c22c128, 0x4c12092e, 0xecbbaa75, 0xfbd45ab2, 0x5ffed246, + 0x73e4ec6f, 0x7569fd73, 0x27e7cad2, 0x22ff8eba, 0xba77e898, 0x00839d12, + 0xe4e3e1d6, 0x65f68fbd, 0xc8773d13, 0x5f94dcac, 0xd53da3e8, 0x3970079b, + 0x3adf376b, 0xdbe20d46, 0x0aa8f38a, 0xa567047b, 0xfd398f74, 0xed34737e, + 0xb0a56f2d, 0xef37e657, 0xbf89695e, 0xc21b71a5, 0xc1ec8481, 0xc81447a8, + 0xbe0daad1, 0xb9417dcd, 0x3e99cb8b, 0xbf05c593, 0x67eb81f0, 0xf3ba7931, + 0x8416bf0f, 0xcb62bcbf, 0x5f1dd7ff, 0x7f74f68d, 0x6b7d238c, 0xbb92f72c, + 0x50a8dce1, 0xd9f695f8, 0xf4112ed5, 0x738dbcf3, 0xf3e569f1, 0x742b007e, + 0x02505747, 0x00000250 +}; + +static const u32 csem_int_table_data_e1h[] = { + 0x00088b1f, 0x00000000, 0xe24bff00, 0x51f86062, 0x38cfc10f, 0x90981819, + 0x770143f8, 0x01684331, 0x21060616, 0x62636620, 0x22676060, 0x072bbf5e, + 0x9d877d82, 0x1038e181, 0x781f67df, 0x5e240d7f, 0xbb3f4dcd, 0x2ed1d37e, + 0x7e27f062, 0x02af8606, 0x058b0c0c, 0x210b7c21, 0xfccff954, 0x18a47608, + 0x02a57665, 0x150003f5, 0x8051b77b, 0x008051b7 +}; + +static const u32 csem_pram_data_e1h[] = { + 0x00088b1f, 0x00000000, 0x7dddff00, 0x45547c79, 0xbedd70b6, 0x97a7774b, + 0x42c84274, 0x4010dc20, 0x804d8854, 0x024de3b0, 0x10602a31, 0x66b71c11, + 0x04484b0f, 0xd3ce7cde, 0x0831baf9, 0x544e38e8, 0x387c0666, 0xa8d041af, + 0x1a0c1a51, 0x166bc3b0, 0x26665419, 0xb8c38e3a, 0x6c8a89bc, 0xfd011242, + 0x5f283798, 0x3b75539d, 0x4dba6f7d, 0xe3fbe65c, 0x45a7efcb, 0xeab7badd, + 0x9cead9d4, 0x25aaa753, 0xd7a92059, 0xfe197212, 0x48a6f968, 0x51d11908, + 0x1fb715b6, 0x04846927, 0x6dd5915e, 0x7fc22102, 0x0ed722b9, 0x16c8e427, + 0xf5a56821, 0x21075ec8, 0xd3767eb4, 0x9735a0b4, 0x0e057d90, 0xbb3fde0d, + 0x25eb08b5, 0x96e2febb, 0x2ee57b68, 0x65ba8251, 0x8b7729ef, 0x6b2a9093, + 0xe963a3f3, 0x225df6f3, 0x228742d9, 0x490b1281, 0x8db8e427, 0xac8bbfb0, + 0xaacec0be, 0xddf79b95, 0x3456fd05, 0xf69d895a, 0xe17bb953, 0xbeb4b1d4, + 0xe04cb0f0, 0xab6dca95, 0xbeb45e94, 0xa0842828, 0x0fdec0fe, 0x62b69c70, + 0x4c1a1152, 0x8dbf69c8, 0xbad057a8, 0x067d39bb, 0xb838be7d, 0x5fde14a3, + 0x2d782f5c, 0x9bc5fdf4, 0xfe819df6, 0xfdc83717, 0x92ffda45, 0x0751073a, + 0x132fb1b1, 0xa9fcc798, 0x1be56f00, 0x7ad2b132, 0x0a15a5c5, 0xb5491c01, + 0xc60bb94a, 0x5d514c7f, 0x1c61ce30, 0xe567c747, 0xfa1c7473, 0x0497b2dd, + 0x996d4c2f, 0x9e00f885, 0x59f6ddd6, 0x5e613b4f, 0xf08194ab, 0x0ab5eefd, + 0x3830b7bc, 0x0abb15fb, 0x4a566df0, 0x9b4dce01, 0x3b830595, 0xf7525bfa, + 0xe3ae0196, 0x7c32f21b, 0xf2e6ed31, 0xd5109fb4, 0x4c5f51da, 0x02721688, + 0xda6541dc, 0x17e78e90, 0xf7a41484, 0xa8913a92, 0x29fe8eb6, 0x49e90861, + 0xfa17ffff, 0x2683e04f, 0x6e5b7057, 0x7b96bd07, 0x0ed5bfe8, 0x70f39d7a, + 0x85ed49fa, 0xe5ebfdb1, 0x0a0740a3, 0x83dfad4f, 0x4cfee3e5, 0x55fbd72c, + 0xfc6fdbc4, 0xe0dcb083, 0x27f3e2f7, 0xdcb0a3fd, 0xfcb0d7e4, 0xcb0cbf9d, + 0xdf1cbfa0, 0x859fe2db, 0x0fbf56e5, 0xafe33f9f, 0x5fceb2c0, 0xf79fcf8d, + 0xbd658bdf, 0x5fcf803f, 0x32c3aff2, 0x72c5afe4, 0x96037fa7, 0xbe20fe0d, + 0x0ebf8af7, 0x087f46cb, 0x37f1ef9f, 0x47f61962, 0xf40bdcb0, 0xdfc465a5, + 0xff7ee58c, 0xfa0f2c51, 0x43bbf05b, 0x3e5893fe, 0x1eeef1c2, 0x8a248a47, + 0x3c46b737, 0xea485c54, 0xa648ad64, 0x5672d4f5, 0x5023bf4f, 0xba7ad0a4, + 0x1e29d68f, 0x148d2d7b, 0x57bd6959, 0xb9cf6b35, 0x68db149f, 0xdac0273d, + 0x15a23dfb, 0x5fbd69db, 0xb81f6b2d, 0x449c5029, 0xac8303eb, 0x48faaafd, + 0xafd683b1, 0xfcf6b10a, 0xd2712930, 0xd5847e7a, 0x25688e0b, 0x682f5a2e, + 0x0fc2f566, 0x5a6e2503, 0xdf616c2f, 0x2913398f, 0x31f5a649, 0xc27daced, + 0x43d13225, 0x808813eb, 0xd16762f5, 0x2f5a14c4, 0x697ab0f6, 0x1a92d9ef, + 0xcaf6ff87, 0xe509732d, 0x4dc0ba85, 0xeb45949a, 0xe20acb4a, 0xcc0cf8a5, + 0x26447ac2, 0x48fda0f3, 0x8d26b660, 0xac8575a6, 0x0efff684, 0xfdf6c62c, + 0xeded8ab2, 0xbed81581, 0xddb1515f, 0xac7eeab2, 0x6c35941f, 0x20f55b4f, + 0xd1507fbe, 0xaae07db0, 0x487eb147, 0xa8fb61f6, 0xf7c5bf55, 0x6c3e290f, + 0x50757c7f, 0xffeb489b, 0x00b6f821, 0xbe08d75f, 0xfc07920a, 0xa72cca1a, + 0x2046bafc, 0x1e3e40b3, 0xf2a6a606, 0xd14b26b0, 0xfdedbf40, 0x5169f0ba, + 0x069dbce0, 0x3ccf05f5, 0xbcfd8b9c, 0xb4c8fd80, 0x7eebb11f, 0xca337c26, + 0x6f84cfd0, 0x1a7ef42a, 0x7b1abde0, 0xfbd9faf7, 0x3c2318cd, 0xfbd62cdf, + 0x5c7ec269, 0x84d79bdd, 0xf08ce3cb, 0xf7aa5e5c, 0x49fb0873, 0x113c1ee9, + 0x9fa1a479, 0xef50bc88, 0x4fd84fe7, 0xa3c1eecf, 0xfd0da329, 0xbd22ca68, + 0x4fd8a39f, 0x89faf756, 0xf08d6328, 0x7ef44b28, 0xfa7ec63e, 0x9a5e6f74, + 0x1e11bc75, 0xcfdea56b, 0x6e7ba469, 0xefd9faf7, 0xbf67e232, 0xf39f8a2b, + 0xee80cf08, 0x6dd8abcd, 0x3bb14fc4, 0xd84b9f8a, 0xebdd95cf, 0x88dbbf67, + 0x28eefd9f, 0xe601647e, 0xf37ba435, 0xe2364e2a, 0x8a3938a7, 0xf000b71f, + 0x3c1eed0c, 0xf11a7b07, 0x1467b073, 0xcf08193f, 0x33c1ee88, 0x9f88dd31, + 0xfc51e989, 0xe8cf08a8, 0x3073f5ee, 0x839f88dd, 0x5cfc51e9, 0xef8cfd89, + 0x6626bcde, 0x3133f118, 0x029f8a23, 0x57c8a7ec, 0xda10f087, 0x3f712b8f, + 0xf118fa87, 0x144fa873, 0x9fb1633f, 0xbc9fb449, 0xcd29fbae, 0x34a7e231, + 0x899f8a27, 0xbbebe788, 0x1ca1cfd7, 0xe50e7e23, 0x0533f144, 0xbdd299fb, + 0x35f69579, 0x2fb4a7e2, 0xd2b5cfc3, 0xe8675c50, 0xe915e9da, 0x2ef5d727, + 0xbefa04d2, 0xd17561e8, 0xf76025e3, 0x433dba88, 0xbe91359a, 0x294facef, + 0xdac49878, 0x0277c535, 0xcad45c7e, 0x926bb58b, 0xec192547, 0xd52d14a8, + 0xd651ef50, 0xcf7ef0cb, 0xf6867ef2, 0x1957598c, 0x057cb3da, 0xc5767a86, + 0x7dfbc318, 0xf50d8baa, 0x60def7be, 0x70373f78, 0xb79ea1b3, 0xf78627ee, + 0x31ced407, 0x61b15fb4, 0xcafda1b1, 0xfd4372e0, 0x377fbaea, 0xf4243fbc, + 0x9afda180, 0xed0d87c6, 0x1b8f2343, 0x3f0ec3ea, 0x447f7869, 0xfb4316f3, + 0x1bcfa3c8, 0xecb747da, 0x9ec7d434, 0x7f7863dc, 0x437efb7c, 0x6f8bdafd, + 0x222fde1a, 0xdbda367f, 0xef0c0fb6, 0x6a7cf24f, 0xf32ebf68, 0xea9d9373, + 0x9abf1cf4, 0x2b9045d7, 0x20497e82, 0x357b414b, 0xaeb052e2, 0x3f3272f4, + 0x3d40b5c5, 0xd947f946, 0x434d573f, 0xd47fa4be, 0x55ea286e, 0x7d0b4571, + 0xbe31d3fe, 0xf9f43c2b, 0x35df154f, 0x0df6389e, 0x648137e5, 0xa05aa942, + 0x95afb734, 0x6717bf19, 0x31f81a5f, 0xd2cabefd, 0xd685303e, 0x2145897b, + 0x04578f90, 0x49d5da0b, 0xf786a922, 0xfd04ac92, 0x85b9b5a6, 0xe462074f, + 0x6a1f5d61, 0xfd1d0867, 0x997d93ae, 0xfaad4768, 0xce760028, 0x5e743e9a, + 0x4d7908bd, 0xe81228f8, 0xb3efbf4f, 0xfb47d320, 0xcfd42ab3, 0xa15f1d88, + 0xf1c60fe3, 0x870f2023, 0x9d11fc60, 0x1bf6b7c7, 0x96df1865, 0xdf186153, + 0x3df1d0a6, 0xf55c3fd4, 0x129f1f19, 0x6f210c61, 0xf8e19f09, 0x1c0a9cd6, + 0xfd42ad7f, 0x93f1d8ae, 0xc337e3a2, 0x344bdffc, 0x8c637eff, 0x6c59cff3, + 0xe6c2bf9c, 0xb3aafeff, 0x9c24fc7c, 0x59c207ff, 0xc59cff36, 0xd656fe6c, + 0x777c746f, 0x302dff14, 0xe304f1fe, 0x19c6f35b, 0xa977dfe7, 0x3656fe71, + 0x5f55e9fe, 0x389df1f2, 0x97c2e7fe, 0x977dfe6c, 0xd58af8e2, 0x51fe05e7, + 0x83aa93b2, 0x9bd27c74, 0x600cbe2a, 0x940e3a17, 0xd0a95283, 0xe84db210, + 0x34fc7087, 0x57dbf189, 0x50df9449, 0x39f0059f, 0x59cd5209, 0xce46fd48, + 0x8bea4beb, 0xd87bd014, 0xf9adfd4e, 0x8d79d41c, 0x5937f222, 0xa00e0d6f, + 0x8a36b6f0, 0x5bcfa801, 0xfa083e3f, 0xee4acab5, 0x24ef872e, 0x9fe78112, + 0x96c87afd, 0xcb9979d8, 0xf1f2b5f9, 0x8b791896, 0x64c581fa, 0x6f853550, + 0x88c13012, 0xd427fa8e, 0xf8c7038f, 0x10f7ea43, 0x2a7cffea, 0x9bfef1b3, + 0x6f507bfa, 0x3a1efea1, 0x7e1564ce, 0x377bbb47, 0xce5fc293, 0x6244ffe1, + 0x1dc9faf2, 0xe5403042, 0x0d9fabf3, 0xeefaff45, 0xe9141d7b, 0x0ecc701d, + 0xe9d430f4, 0xa74002bc, 0xe0d6ddf6, 0xabf10116, 0xa1a6be02, 0x77321268, + 0x75c5365d, 0xdd7ffbc7, 0xe090e53b, 0xa256e426, 0xfdf419c9, 0x7d0a573b, + 0x19dc743c, 0xad80b59a, 0x05b65a43, 0x5b649ae5, 0x73721146, 0xf69950c3, + 0xf269a640, 0xe3312d27, 0xd6332f4e, 0xeb1b9467, 0x5b26b2ad, 0xd3ad5c28, + 0xf699b204, 0xb196733b, 0xbfa71f5d, 0x99d19525, 0x714e578f, 0xcd1f4592, + 0x1e00b284, 0xb3ce907b, 0x1d5bec3c, 0x32b9aa9e, 0x1f1fa089, 0xae8049e8, + 0xef7c3481, 0x6f361e27, 0x64b3bc33, 0xe74e569b, 0x18b66b39, 0xc336fe04, + 0x875efeff, 0xe5a7c966, 0x626427ba, 0x331f3ce9, 0xccf9b7fc, 0xb0c909f3, + 0x615edfce, 0xe6f8ce7e, 0x27ffa738, 0x3cb41fc0, 0xe141fc01, 0xa3f9c63f, + 0xfe32af43, 0xa6fab2a8, 0x6fb43f02, 0x95d20914, 0x9cadcbf3, 0x1ad7e65f, + 0x9f1082f9, 0x385c740c, 0x3878284b, 0x72660f86, 0xc1b8583e, 0x927737c8, + 0x87159c80, 0xdfadb72e, 0xdaa660fc, 0x711f7e79, 0x91fdb9be, 0xce9f887d, + 0xba7464f3, 0xcee9d38b, 0xadfb636a, 0x7277ae9c, 0xf0daceba, 0x7d54ebd8, + 0x41a89f90, 0xeabde419, 0x2d9e9d3e, 0x38fa7a06, 0xde70cd3d, 0xd779e9c5, + 0xcd3d18cf, 0x7a70b6f0, 0x2f386cb6, 0xe19d7e93, 0xf777c335, 0x83e69dbd, + 0x81d9ad71, 0x6aacf4f8, 0x2c715a2c, 0xe86579e6, 0x62c715fa, 0xdd496ce4, + 0x517d4334, 0xfbc336f0, 0x36cc370b, 0x5dafcfb4, 0xbb9f6864, 0x7d431eee, + 0x8667e076, 0x77beeff7, 0xcefda195, 0xed0c87ea, 0x663c57b7, 0xdbe6dfa8, + 0xe67f7868, 0xf686cdac, 0x19cfe519, 0xed97a7da, 0x69a7d430, 0x0bef0dbb, + 0x6df5177b, 0xf7d575c1, 0xef10199f, 0xf9159bfc, 0x74efacd4, 0xafcc78bd, + 0xfee3f3e2, 0xf49e5841, 0x69f9f17b, 0x572c28ff, 0xeba6fe81, 0x2b376582, + 0xdd9f1eab, 0x9742f817, 0x6f654f8b, 0xaed9e80e, 0xbefea1f4, 0xbfd1ef59, + 0x8a7678ec, 0x48152e5e, 0x6d83ac39, 0x9fd74edc, 0x4ecc2ddb, 0x2c01e420, + 0x6e4c2a97, 0x2accee97, 0x47a86e26, 0x133b5606, 0x02424bf7, 0x6d7e67ce, + 0x85ce019e, 0xc136ae1b, 0x6af905b7, 0xe1987051, 0xb1ba92f9, 0xecceef86, + 0x65be1113, 0x61a3e320, 0xdf7f2b39, 0x7233fa02, 0x10fa6720, 0x00fb5780, + 0xd13d8deb, 0x2fe33b9e, 0x006c715b, 0xcb1cb9e0, 0x5859fe93, 0xb0fbf71e, + 0xc0afe63c, 0x357f13f2, 0x7bfe2d96, 0x7f6ffcb1, 0xfd0fcb00, 0xdf7cb0eb, + 0x51e58b5f, 0xdf2c06ff, 0x7cb107f3, 0xe5875fd7, 0x9610fe3b, 0x2c46fecd, + 0x961afd5b, 0xf0c4bcba, 0x18acdf4b, 0x9ff5d17e, 0x724f1fae, 0xfc0d397e, + 0xb62f8f12, 0x84e2f918, 0x617c8d5c, 0x3a6687d6, 0xf7dff598, 0x3f2987e5, + 0xd0743f12, 0xef44db3b, 0x9de8aebc, 0x7bd0c629, 0xe0c3c58a, 0x05fef4e1, + 0x5ec71bc0, 0xfb8b049f, 0x483b1888, 0xfac0b22b, 0x2fef9cb0, 0x3f5807d0, + 0xa1aec7c7, 0xbda335dd, 0xfa041c14, 0xffa0dcf8, 0xf9f10819, 0x51294773, + 0xcfcf1372, 0x7884bf4c, 0xabe8f180, 0x2e94820b, 0xdbb73a3d, 0xed5e1893, + 0xe8465216, 0x80d0f17a, 0x0673bc67, 0xa9225d63, 0x3bd07df0, 0x5fa715cd, + 0x7e02836a, 0x8d6bc2bb, 0xe87cabeb, 0xff93f8ef, 0x8a72842c, 0x49a1d985, + 0x87b44407, 0x2f69e449, 0xefaa37e0, 0x884cdead, 0x500fb763, 0x931eb83c, + 0x02fe2312, 0x3dfc06c5, 0x8cd47144, 0x266d59eb, 0x57ffafe2, 0x81bab303, + 0x64f4aebf, 0x039cf857, 0xe017fef3, 0xd5fd2bb3, 0x9a22de95, 0x9d2352fa, + 0x21dedb7f, 0x30ab0f05, 0x5be3b7ee, 0xc332b7df, 0x7c8ef813, 0xf3ae96dc, + 0xa10e7371, 0xf2e59ce3, 0x8ae1ae72, 0xb44ba064, 0x29e82e9f, 0x3947d7fc, + 0xe6cebfa0, 0x6b5bfb1a, 0x21592fee, 0x5c7435c2, 0x6490a297, 0xbe885642, + 0x06fd115a, 0xfc004b6f, 0x6f0ebdf1, 0xd8fe0a8d, 0x54463fe9, 0xb7e8d9e8, + 0xb4fc3b9f, 0xe59bfc1b, 0xb1f56299, 0xcbd47438, 0xb56e50ca, 0x680fd633, + 0xd5cfd634, 0x9c21650a, 0xcb7c9a97, 0x3c075810, 0xd064c7d5, 0xea5899cb, + 0x54cf2cfd, 0x7f4a1c70, 0x53ea47a6, 0xf69ccf50, 0x1fbdf0db, 0xfd448e1b, + 0x40d1c074, 0x83dfa53e, 0x4bce5d88, 0x39427efc, 0x10282e90, 0xf961248f, + 0xecdff02b, 0xfdcbbff4, 0xeb095fa0, 0x2155bf7a, 0x06bd6031, 0xc61bd79e, + 0xfaa9dfa3, 0x977c2c1e, 0x7224de58, 0x4a77e75c, 0x7ef837b7, 0x7b3a92f1, + 0x4c2ed1b5, 0x1aabd431, 0x760daab3, 0x0c03fc22, 0x02410ae1, 0x6729777b, + 0xb9c936bf, 0x2b68f80e, 0xdf80fb04, 0xa55ef605, 0xa9f145ad, 0xc0cd2628, + 0xe946739f, 0xfcceaf7c, 0x53a7ea80, 0xe404c96f, 0x50a25c8b, 0x47f47615, + 0xa1625057, 0x36bcb9f5, 0x64c961a7, 0xbd4eaf58, 0xf5da2372, 0x1bb948f3, + 0x520acdfc, 0xcff1085b, 0x0652c4b3, 0xbc967972, 0x23161ee3, 0x0545e787, + 0xcebb99e1, 0x7f531768, 0xb85f50d9, 0x405f58c1, 0x7d874e6e, 0x65eb05f0, + 0x5f401412, 0x153fdb18, 0x242d1c99, 0x7d606bd5, 0x75b32f5f, 0x48878e6c, + 0x555f54d9, 0xe154fabe, 0x1fff5a6c, 0xf42dc591, 0xa945dd7d, 0x1c589fcc, + 0xb468acda, 0x6186d3fd, 0x43cd52b7, 0x81ae0fbf, 0x4bb02af5, 0x3b536ef0, + 0xc2bbefd3, 0x5f57866f, 0x2fed3bff, 0xeb2a3873, 0xc7182d04, 0x0249b00e, + 0x580377f7, 0x863c960e, 0x5328c2b8, 0x53f37bfd, 0xd3f0311a, 0x4aa7d156, + 0x80ff193d, 0xed48253f, 0xf487ef8a, 0xffa9d99f, 0xff6a3fc1, 0x85ff69bd, + 0xfd47fe86, 0xeff7fda8, 0x6944ff04, 0x2bfee744, 0x95f17d5f, 0x8b27d500, + 0x4ddaffb7, 0x4a78fae8, 0x52f74daa, 0xf6dd2efa, 0x7ce81ba0, 0x81b80a52, + 0xc5054f5f, 0xf59c60b2, 0xe0493eea, 0x14e6a2f6, 0xff058e20, 0x7e9ffda4, + 0xdfe817fe, 0xf64db57f, 0xceaa7c60, 0x3952b11a, 0x68b0d65c, 0xfac7c932, + 0xf6beacc7, 0x8dea110b, 0xfc5bfe46, 0x21d3afec, 0x0a7282df, 0xd044d78f, + 0xf5b65d9e, 0x975852b3, 0xca3b48aa, 0x183bf991, 0xea2a62ff, 0x724ad9bf, + 0x270a76e7, 0x1c55ddfa, 0xbf0d552f, 0x437442f8, 0xd009fd79, 0x4043d417, + 0x5dfcd8bf, 0x974fb705, 0xe3b4ae4a, 0x232714d4, 0x8bd048c9, 0x90485e3a, + 0xabe2a7d9, 0x3c43e54f, 0xb7d6ccf2, 0xbe0c42dc, 0x173a7974, 0x7b9ffb9a, + 0xb77ac4d4, 0xac5bca95, 0x5bafa41d, 0xabb7236a, 0x2a5cacc3, 0x1f90dc47, + 0xecb374b3, 0x4bc7d00d, 0x99fa7c5f, 0xf83e2127, 0x0077ab37, 0x8bc97fed, + 0x8637bfaf, 0x90ec97d6, 0x69b326d3, 0x0ef48538, 0xffd154fa, 0xa0e82dee, + 0x5f97e2c7, 0xec21d457, 0x1da9fdf9, 0x63b25974, 0x7486429f, 0x684947c6, + 0x8ce2d29f, 0xc7d09f43, 0x882760a5, 0x00ad7eaf, 0x15ed4ffd, 0x1c6e4648, + 0x1d7e6e7c, 0x13c000ed, 0x2bd393d2, 0xfbd33f4a, 0xa02e9455, 0x32f4cdb7, + 0xf40537bf, 0x2fd608cb, 0xfe502de4, 0xe40f697e, 0xf56fbd15, 0x5e2a1e02, + 0xf986e15a, 0x19aa909c, 0x60f53f9f, 0xafc746ba, 0x1ee90390, 0x8af3d92c, + 0xf21bfddf, 0xffb7c2df, 0x35e31d2d, 0xe0b2cb44, 0x82c8145a, 0x34dfce79, + 0x80b9e703, 0x2b0f90f8, 0x41cb129e, 0x91297e1f, 0xe4711db2, 0x93973ce4, + 0x71285b13, 0xd04f3ce9, 0x6df30665, 0xdb8311de, 0x87beded0, 0x37f83e80, + 0x316a173e, 0x1b4bfd60, 0x921bd7a3, 0xab5197ee, 0xb77f9633, 0x3a066dae, + 0x65a3ee9d, 0x15463ec0, 0x1f1c0291, 0xafda65c2, 0x0ca4f6f8, 0x4aa22746, + 0xba3bfc85, 0x73c097ee, 0xd659bf78, 0xef86f9ec, 0x8edce5c8, 0xf1f257f1, + 0xb049dc29, 0x8f489f5e, 0xb2aab76f, 0xbae807ae, 0x3167c31d, 0x7fe4cef2, + 0xde4c43eb, 0x4e0ff975, 0x0bf6832b, 0x823932ef, 0xa43d60ef, 0xb0324570, + 0x022ddf7d, 0x892b07ea, 0xadf393c4, 0x63739732, 0x285f99bb, 0x1c9092fc, + 0x4e3037c3, 0xf701d22a, 0xa7ac1631, 0xd1e8c7df, 0xddd7182a, 0x8e5d5fb9, + 0xd07d7217, 0x6407d26a, 0x8903d313, 0xae00aaed, 0xe0e54b7f, 0xfc824f33, + 0xa80d7952, 0x3972bf20, 0xfaf3ffcc, 0x84fdef03, 0x21e7cdca, 0x7a8d6e5d, + 0x15b72cd5, 0x7890473b, 0xd3b9fb72, 0x2dcae24b, 0x6e571e7d, 0xcfc82d9d, + 0xaaf5afff, 0x990cc78e, 0x0eeaf1e2, 0x327aea3c, 0x7acd3e11, 0xc6a4a772, + 0xeff493d5, 0x99d8525d, 0xd43e751f, 0x0bf16ff9, 0x1f417d95, 0xe754f945, + 0xea9f28c3, 0x5e29d87c, 0xb9a3c06a, 0xefb0effd, 0xdb62fc01, 0x7518f538, + 0x015e6d21, 0x338afee5, 0xb4afcc16, 0x5f70170d, 0x0906d064, 0x3c5b6feb, + 0x9d4ec023, 0xcfd5f63a, 0xbbbe467f, 0xcb7df07f, 0x3f3e2957, 0x6ec84019, + 0x5f046528, 0xc8e7a58a, 0xeab38330, 0x43f60908, 0xe589a0fd, 0xcff4fe31, + 0xbdf76665, 0x61cee1fa, 0xb6a2c780, 0xa82dc9c1, 0x9fa20737, 0xc8f5c559, + 0x0c9a80b9, 0x385cf5fa, 0x73c9fd0f, 0xbc574587, 0x38e7c6fc, 0xf8805f7d, + 0xb6db2d19, 0xf2915a92, 0x47691b5d, 0xd5b022bb, 0xd9c5b646, 0x9990aadf, + 0xf8a1fc9e, 0x3e03fa00, 0x94b7b39e, 0x73b1c796, 0xbbeb9dff, 0x81fffba9, + 0xe155e6eb, 0xa7b016cd, 0x316adaae, 0xeb9605c4, 0x0a405d7c, 0xeea7af80, + 0x0386bbb7, 0x5e8b0f1e, 0x0aad03c8, 0xe2f8a17f, 0xf9e68df8, 0x8f60ff43, + 0x707b2b3d, 0xd0e4d7dc, 0x6bc3c05c, 0xf6046d67, 0xb52b76d3, 0xf9c1e24b, + 0xb9c1852b, 0xcba318fb, 0xa297858f, 0x18a46736, 0x095b3de2, 0x3a676df2, + 0x73f3e413, 0x2ab82475, 0xb22de817, 0x68353d7a, 0x9414fbe8, 0xef838e5f, + 0x635ed12e, 0xc68af3e4, 0xf4082f1d, 0xc16165bd, 0xcbeda163, 0xf80516a4, + 0x4531aaa5, 0x54367d04, 0x3d5bf3d5, 0xe1896e43, 0x096567bf, 0xcc6079e7, + 0x5e03b76b, 0x08519fce, 0x076801e4, 0xf84f31db, 0xf218787c, 0xbd79a25b, + 0x275327ec, 0x410fd0ca, 0x71d3363e, 0xa1927d70, 0xd7c4b63e, 0x6a9ae00b, + 0x8de9596d, 0x1c01f783, 0x7c963fef, 0x5b765576, 0xe5d5df7e, 0xc79627d7, + 0x9d57ddf0, 0x9e2337e5, 0xa55f2efc, 0x97bcc066, 0x0065e537, 0x21bf973e, + 0x57c78cf7, 0xdf99fa2f, 0x03e79db8, 0xf95035b7, 0x7e4626bd, 0xc6fca81b, + 0xfcb61389, 0x22fbf2c8, 0x7b3c6fc8, 0x9757cf8c, 0xc7f0fcdf, 0x0df9bf28, + 0xca1e4316, 0xefaf9969, 0xe857e509, 0xd41a4b79, 0x8e23af65, 0x403c06be, + 0xdf3b739c, 0x40718007, 0xbbe5558e, 0xfc7ff1c9, 0xf978e58b, 0x3379822e, + 0xe4cde99d, 0x2a6ef978, 0x9dd002c7, 0x26f2f1c9, 0x9db9c72a, 0x275077e5, + 0x2fdf65f9, 0xabefb08b, 0x7b7f731a, 0x40af1d07, 0xfa36bd93, 0x3c87417e, + 0x6795888f, 0xcf204955, 0xcf27bb87, 0x533cb8bb, 0x8de7ed39, 0xd86f5743, + 0xdaf61f98, 0x2ff513e8, 0x41fe5f03, 0x6de9ff44, 0xff73b30b, 0x70c4fa38, + 0x00db8be0, 0x632fca1e, 0xfd5a1d39, 0x74bfec01, 0x9074c6cc, 0xb5839293, + 0xec3c81bf, 0x0132adca, 0xe1acb87d, 0xcd53f463, 0xbedd1771, 0x745fc732, + 0xc38e623d, 0xbd33a92c, 0x9dbe30a7, 0xbc20b626, 0x77a24fe4, 0xd3be1c5b, + 0xe704ebdf, 0x9cf7dae1, 0xece03bc3, 0xcfa42e2a, 0xf4b82ba3, 0x7c2b9579, + 0x864a1bbd, 0xe291bc41, 0xf025e511, 0xaa7188a6, 0x8601a2f2, 0x72b70cf3, + 0x16d58738, 0x62d84095, 0x80ebe41a, 0x9ee1b55f, 0x368fb043, 0x005aa8e2, + 0x31d8f566, 0x57f81f56, 0x51dbd9cf, 0x3cba759e, 0x3964f9c4, 0x5eb5e7ef, + 0x6fc0c5d5, 0x07828d55, 0xc8aa9dd6, 0xc6dcf03f, 0x955f8d81, 0x6a2d1f02, + 0xe4563c12, 0xf0142fc3, 0xfae94afb, 0x2c34fc0b, 0xbfda05fc, 0x448a9a8b, + 0x6ed17ef8, 0xbbe41301, 0xe9774fc2, 0xf7c396b6, 0x04efc022, 0xbad9db38, + 0xdbd3e1c6, 0x0180a4ab, 0x2f2792fe, 0x7066c9ae, 0x03b556ab, 0x785111de, + 0xaf388b67, 0xe3abc26e, 0x1f782bbd, 0xe3deb852, 0xb8d3fc74, 0x222f18f3, + 0xf96e94e1, 0x6e35df37, 0xd19a4555, 0x57e3d35f, 0x2adf455b, 0x6588e219, + 0xf38c6482, 0xfbfc63b6, 0x7fffe847, 0xf07fadbe, 0xdd74222f, 0xd3fd7dfa, + 0xcfb3ef88, 0xe8153c7f, 0x9135e4b2, 0x5a5d28d8, 0x82245deb, 0x054124fb, + 0x41b8b0e8, 0x240e30d4, 0xbba70a45, 0xc351f162, 0x85ddb1f0, 0x4ef1707a, + 0xfd32706b, 0x9f2bf17e, 0xd33d83e6, 0xa1fb40fa, 0x3c03886c, 0x931ca02f, + 0xec3e4b40, 0xd8962d13, 0xbf198dbe, 0x87c58511, 0xcc76eccf, 0xea107902, + 0xc5a9b9d8, 0x35b299a1, 0x557e1ec6, 0x641c5991, 0x15af3b37, 0xbcc04e78, + 0xf62f8031, 0x8f9e8edc, 0xe639e673, 0x946e2c97, 0x6afe7083, 0x568edd71, + 0x3e2c9b88, 0xad75c56a, 0x8c0beeaa, 0x7f6c96fb, 0x6aef9d91, 0x72fe0d14, + 0x4eb53f27, 0xbfc1588c, 0x38c4a86a, 0x8c7fad3c, 0x0bf710f5, 0xb51fa3bf, + 0x2bd37b64, 0x25c28a01, 0xc6eb3f2f, 0xdbcd5873, 0xd6afe8dc, 0xa8dc7b7d, + 0x7a1a5f93, 0x53a5fb88, 0x97df804e, 0xcd3d2fc8, 0x62b4e4f9, 0x7aebeff2, + 0xe14abfa0, 0x638f2c2c, 0xfff947b7, 0x077f2fc5, 0x3b33d571, 0xc01dff3f, + 0xf39bf4bd, 0xe28fbbbf, 0x7bb5ec93, 0x3d560f40, 0x438c17ff, 0x5649dfe9, + 0x7b9fafae, 0xad78e316, 0xa17ab37f, 0x13a6d6b7, 0x6ac71039, 0x748ff1dd, + 0x365653b0, 0x6bbb424d, 0x0c92aee5, 0xd04ec712, 0x60dfe04b, 0x6688e237, + 0x38681dba, 0x9e700390, 0x748774a5, 0x21bc68be, 0x38e2c954, 0xd4338f2a, + 0x76db8fc7, 0x4c342b8a, 0x70fc69bf, 0x4aaf6528, 0x785f11ba, 0x9af3d297, + 0x9eb1d06e, 0x534291c7, 0x70be35be, 0xe941fe16, 0xc6356795, 0x986cbe17, + 0x424f9fff, 0x848f435b, 0x374885f1, 0x85c7a7f0, 0xdf2d14db, 0xf3b9720a, + 0x00eb8c05, 0x09d326fd, 0x65f8beb7, 0x4fd5c40e, 0x6177edca, 0x15935bbe, + 0x3717d7f7, 0xa9e515fd, 0x68dbd775, 0x9f1e127f, 0x3fd1256d, 0xb9e34716, + 0x5d5b55aa, 0xe9c12e2c, 0xd50b7100, 0x7c79cf8d, 0x1eb5f182, 0xaf1448b7, + 0xc7ed6058, 0x5c594ef3, 0x07eb72a5, 0x83c5310a, 0xeb1d5184, 0xe97a227e, + 0x1e00f078, 0xe3c6c646, 0xa287c7e2, 0xdd1338f1, 0x87109e80, 0x68dbc68b, + 0x5dc437bd, 0xe35fc282, 0x375b77c5, 0xab5e38b3, 0xe95bcc6c, 0xcf8b13a0, + 0x5bd136cd, 0xeb576f9f, 0xf8f35756, 0x069a78ae, 0xcecf768b, 0x29733af8, + 0x6d5f7ebe, 0x3ed87e15, 0xbcc13ceb, 0x7c0353ef, 0xb1f0d959, 0xfa8d7902, + 0xf7cfa6fa, 0xcfcfb70c, 0x5e622f3c, 0x01d09aee, 0xfd66efd4, 0x61ce0cb1, + 0x37f781c4, 0x8d65de1c, 0xb338fd6c, 0xd27415d3, 0xdfecce7e, 0xacbd7c8d, + 0x402563fe, 0xf7543bfb, 0x49fcc2b2, 0x7eb04726, 0x3fe06304, 0x7cbed2f3, + 0xfe647f16, 0xad9c7980, 0x85563f5c, 0x55538fe3, 0x9c6185ff, 0xc2908125, + 0x7dbfacf2, 0x3692d3bc, 0xdd3bfa13, 0xb3c8132c, 0xcb121d3c, 0xae6bede2, + 0x5f7ccab5, 0xb9c596b3, 0xe78a3ae9, 0x9cec5c5e, 0x60aa988b, 0x6ba5641c, + 0x5f3851d4, 0xa8a5d2b9, 0xacd51fe0, 0x35bcfb62, 0x0266f73f, 0x6e526bbd, + 0xad6d78c5, 0x349ebf09, 0x7f9c114f, 0x1f2c4cf1, 0xd66aec0e, 0xc59a293b, + 0x574aff00, 0xe14a8659, 0x81fb4d5c, 0xf244a8f3, 0xd11c39e2, 0xf3065a5d, + 0x8f163d11, 0x4c7c4e3d, 0x5f139676, 0x8f645e0c, 0xb90cdcf1, 0x7e854c34, + 0xa5d9fdf4, 0xd843e6b6, 0xe004d1e8, 0xc7ef892b, 0xc1e2dd17, 0x0bd5b779, + 0xaa71605e, 0x3a4f559e, 0x758033cb, 0x72676da4, 0x3f06b93e, 0x5f5d1a24, + 0x50b9fc1c, 0xe81f6fbf, 0xa26ed5a5, 0xa33950a5, 0x3cc55558, 0xd4343f38, + 0x9f01e426, 0xd7c7f17e, 0xb0f6bf68, 0xa0352048, 0x19e7a9cd, 0x67202969, + 0xe608f20e, 0x5f2b0093, 0xa701d1ee, 0xc084cf39, 0x97e7312b, 0x8c4e8927, + 0x24db9c7f, 0x922b9fa2, 0x8e3b7eab, 0x0824edf9, 0x65f5f3f0, 0x1cf38709, + 0xf0231175, 0xe30bbd7e, 0x98df0bf3, 0x7403f28b, 0x8f57c588, 0xb91fa332, + 0x87ceeec1, 0x768d9dfd, 0x492816f7, 0xbc866b40, 0xdfbc79e6, 0x73c6e59e, + 0x030c5448, 0xe7ce7f60, 0x82f9faf2, 0xaf98c3d2, 0x7a805be0, 0xf196633e, + 0xbed9929c, 0x1fb50897, 0x0a0d7d61, 0xb38908de, 0x19b8dfaf, 0xdecaeee1, + 0xb0e8f1d7, 0x3909bd51, 0x04e24e42, 0x97d6263c, 0x65b7e05d, 0x0dc76fe0, + 0xb5f8eeff, 0x6bf11a66, 0x75f88d57, 0xcfe3320c, 0xd7975f88, 0xe6ca2f88, + 0x6fc36fc1, 0xb9e328f2, 0x7e157faf, 0x1db8d987, 0xff4af1c9, 0x4ce96dca, + 0x59dc0365, 0xc2e50452, 0xced9472c, 0xeeff0088, 0x855c1693, 0xe85d795f, + 0xf9f264af, 0x77d8f308, 0x1123900e, 0x1ca2f5e0, 0xd00bc9c1, 0xa1f20ef3, + 0x2169e807, 0x57cb929f, 0x8ae7a627, 0x9e3f0769, 0x04dabf43, 0xf20d7bfc, + 0x955f3b03, 0xb935824a, 0x0f5ea720, 0xbf21dfac, 0x864f3bcd, 0x3bc4f673, + 0xaf9c006f, 0x68f960f7, 0x6dbf7b01, 0x1a73c130, 0x7485c8a1, 0xf3554fd0, + 0xbfe83949, 0xa9f69547, 0x6cbef7e0, 0x1bbdf167, 0xd3ea0aec, 0xae16eda7, + 0x71be2757, 0xb6c7952d, 0xf9c2acb0, 0x36f0b6c0, 0x37a800db, 0xbd6e788a, + 0x4af6a52a, 0x2c35bf18, 0xd9e6b833, 0xbfc00382, 0x3d71926f, 0x0e379d68, + 0xed44c1cf, 0x4fdb30b7, 0xea7f0b6c, 0xcfa31b9e, 0xb89f1b5b, 0x1b0fe212, + 0x31f7f12d, 0xdf2cd857, 0xae8d7fcb, 0xf29d0dbf, 0x58d8562e, 0xfda3c75e, + 0x4d963ce8, 0x61d7c73b, 0x39630f26, 0xb82e0f9d, 0x2bbfe701, 0x3a7cfd4c, + 0x8ef1528f, 0x79d0871b, 0xc48bfe8e, 0x26d12bf4, 0x47674ecf, 0x1afde080, + 0x5fa82fd0, 0x0e2cff6b, 0x44a0b887, 0xf0c45ce0, 0x6fe805ea, 0x7ca6e6bd, + 0x50a2f94e, 0xbe030d0b, 0xc14e189d, 0x3eaa0a7b, 0x8fd76824, 0xfc0c9668, + 0xd5d7c859, 0x9f1616c2, 0xd8d4791f, 0x3245ba3e, 0x8c4141d9, 0x693d8f1f, + 0xf3ab5e7c, 0x03a49bb9, 0x24bfaf9f, 0xd517900a, 0x0fbc4ed6, 0xe6dbb850, + 0xda3842f5, 0x2b29c02e, 0xcb125e5a, 0x9bf7ade2, 0x6b0f2c6d, 0x9d7042a3, + 0x89c0b8d9, 0x17fb08fb, 0xeb3cc62c, 0xebe67eaf, 0x5edcef1b, 0x664a7e8c, + 0x325af5fb, 0xbdfc0519, 0xaf78605a, 0xb7dd8acd, 0x9f9d4bd2, 0xf9d6fe75, + 0x92416b3a, 0xcbde5e2f, 0x7bb33b60, 0x120c178a, 0xf6d7f014, 0xa9fc780a, + 0x219f01f5, 0x065cdb7f, 0x00d903c8, 0x79e3554f, 0xe16dbbb4, 0xfb5479f8, + 0x0fe66e6d, 0x0558103e, 0xa53f1e79, 0x327a09c2, 0xd1ebbf71, 0xa083aadf, + 0xab677c2a, 0xa6e78d9d, 0x16c8dbe6, 0xb54ad388, 0x80bb3759, 0x5fae4bff, + 0xb27de143, 0xebeb82dc, 0xf08bd946, 0xc1092a07, 0xa73f03f8, 0xd92a7bd5, + 0xec7e7b1c, 0xa8e8ad88, 0xa8f7ce8d, 0xeef383cd, 0x000af3e1, 0xffebf7bf, + 0xa6bb06e3, 0xe915a2ed, 0x43fb8bd8, 0x6de777fa, 0xd80f4f0c, 0x7be077b5, + 0x72869152, 0xbdb9f5e2, 0x39c186f3, 0x18f78a55, 0x5fa0ea39, 0xea91e700, + 0xc28e3aa3, 0x20b4ea93, 0x534d125f, 0x031e7a3d, 0xc8c5efe1, 0x04088905, + 0xbd741cf2, 0x8885842a, 0x70c1ca8b, 0x7e02339b, 0x9d056a47, 0x4ec10537, + 0x66bfac6c, 0x1cf44ce9, 0x5251e61c, 0xe4842cbe, 0x12798279, 0xfd05a890, + 0xd756faeb, 0x0853abd3, 0xc7eacbca, 0xed0d60a4, 0x62d49367, 0xae4af887, + 0x56c316a6, 0xe2a4aa74, 0x153ebcf9, 0x1c73f304, 0x44a54f79, 0xf42a16ed, + 0xef11bf43, 0x1fe7178e, 0xe5f1d76a, 0x2be027fb, 0x7efb70ff, 0x76bc6f30, + 0x75f79e36, 0x51e9da1b, 0xb1edc1fd, 0x8efebe52, 0x2bed8cfe, 0x24b5c893, + 0xd66f8e36, 0x327dba1f, 0x03cb7c7a, 0x6feef80e, 0xadda4e0c, 0xe08ddf06, + 0x13ea8df3, 0x0c8e6ebe, 0xbf427d53, 0x3b0f082f, 0x82eef100, 0x771c990f, + 0x038727d2, 0xfbefe022, 0x5f3311ea, 0xb9508d0c, 0x5583ede4, 0x89ecbf38, + 0xafbda1d6, 0xd277a8dd, 0x40cf0da6, 0x9bf3973b, 0x7cbacf19, 0xe0bee59b, + 0x2b01ef5e, 0x60910b83, 0x1d08871e, 0xa079a870, 0x60888e97, 0x5115b7ef, + 0x0eb8503c, 0xb94bf972, 0xe61ebc10, 0x9d7c3ebf, 0x7be4e41d, 0xfa1127af, + 0xf27c4c75, 0xde37d171, 0xdcf8f2ce, 0xfb658780, 0x24f5f02e, 0xca8ef482, + 0xd8939501, 0xffce8978, 0xe5d77e66, 0x3a0e06a3, 0x0bf9e1e7, 0x28aceb02, + 0xbdf0f084, 0x00f26c95, 0xbb7b755e, 0x24b7db86, 0xdff68590, 0xebe10f4a, + 0xf8104e51, 0xedd646a4, 0x362daf75, 0x55d2b53e, 0xfb6df19c, 0xa9175535, + 0x8793167f, 0xa3b5255d, 0x517556ff, 0x1bdfe7c1, 0x450a617f, 0xf37f01ba, + 0xe33b3ded, 0x57c83c6f, 0xe62fffcf, 0xbf3ccab7, 0xfcc76ab5, 0x6bdf12c6, + 0x147f542d, 0xe35758ae, 0x7793f150, 0xeb3b0b33, 0x657cfd05, 0x96603d22, + 0x6b4b91f7, 0xb498600f, 0x72af790b, 0x3212fc70, 0x98d9f41d, 0x725bb508, + 0x05ffcb3b, 0x072abf3e, 0xaddb7bc3, 0x9e4103ed, 0xdfbe8856, 0x16a811d9, + 0x8aec058b, 0x1eed04dd, 0x6e63beef, 0x1ee6f794, 0xb3a7f586, 0xf660105d, + 0xf4475f26, 0x48d0a7b8, 0x738e80e5, 0x0e7beec4, 0x30f1affa, 0x340e14bf, + 0x623a7e81, 0x5e03d5f3, 0x24c6141d, 0x28324f38, 0x28e2cb92, 0x25dc8311, + 0x49873392, 0xde74428e, 0xe805aeb0, 0x484036ba, 0x7b02cf0c, 0xd502230a, + 0xf4b7602e, 0xb06c242e, 0x06f30465, 0x7bb3e77b, 0xb0177a00, 0xb4dec77b, + 0x5bc938b3, 0xcbd11d7c, 0x03f2b623, 0x912cbf00, 0xfbe0b580, 0x42a00dc3, + 0x5d88f17c, 0xb27807db, 0x8f386995, 0x0af10f6c, 0x52d98e94, 0xad7d8048, + 0xc0aaa5d4, 0xad848ae2, 0xfed25043, 0x45ab27b2, 0xfeecf740, 0x6509cf04, + 0x4713fd83, 0xe5d98e6e, 0x6b07161f, 0x1f8764ec, 0x487172e3, 0x31edf3a1, + 0x473fe599, 0x7c1439e3, 0xebab6fc0, 0xeb6c9c56, 0x225f2c97, 0x6cf0c290, + 0x6080cbf6, 0xd7892f30, 0x6488541f, 0x29bf454f, 0xb0197c00, 0x726fd0d8, + 0xef086f10, 0xc7ea4949, 0xbc1145ee, 0x2bfea0eb, 0xf706dda9, 0xa0f2e825, + 0xe3a3f9f3, 0xf44af66e, 0x73f8f755, 0x52d3e0f9, 0xe027ff7e, 0xb9dc75b9, + 0x2671ab81, 0xef8c39ed, 0x6790d134, 0x51afd3a9, 0x0ecfd036, 0xfd5892f1, + 0x810652ed, 0x242ade3d, 0x6a5fc179, 0x7830245d, 0x43cf1b05, 0xccf30c95, + 0xa33f3074, 0xfec5eb8d, 0x0f38b949, 0xf3a09d7d, 0x5d71875b, 0xe7a23cd3, + 0x8ce74c8e, 0x3290e7cc, 0x9df1a2f3, 0x2b07cc2c, 0x184ee057, 0x40ec2e72, + 0xddcaacfb, 0x9ce2439e, 0xb168c993, 0xa6073dc7, 0xfd6f1497, 0x5e427a92, + 0xe80a7561, 0x993b8cd9, 0xa3e3307e, 0x3d0c084d, 0x7f63fb04, 0xa3eee390, + 0xe66665eb, 0xe8f3298d, 0xd75999fb, 0xdf3fa963, 0xc6e294e0, 0x0925c70b, + 0x0c8fcc3f, 0x18df3cb2, 0xf3071dfe, 0xe77beb39, 0xbfc50d3d, 0x1be9e31d, + 0x37de1892, 0x6fbc3124, 0xaa7c7450, 0x1d7f20c9, 0x5f21af75, 0x96dfbd62, + 0x509e4122, 0x73e50b20, 0xbbd187be, 0xed0d7de3, 0xbb449e96, 0x125036fe, + 0x0db265eb, 0x7dc59ef9, 0xdfe0bcf4, 0x994b9ff8, 0xdba7ed48, 0x8d505f38, + 0xc29be8c0, 0x7eb0bee0, 0x4e9b8e12, 0x1481da2d, 0x2dca0bcf, 0x9d07885e, + 0x1bbef39d, 0xc9cdc88e, 0x78242e6e, 0x0d7ab5f4, 0x157f73f8, 0xd125b77d, + 0x5036d27e, 0xf183d545, 0xa525c805, 0x8fb8f5d3, 0x3712db39, 0xc497cfef, + 0x925776fc, 0xccc8e107, 0xea748a9c, 0x014e4fa8, 0xa7ccc37f, 0xe6b35e54, + 0xb738ef0d, 0x1166f946, 0x6f2cd9e0, 0x1469326d, 0x208add70, 0x7674d2be, + 0x975b7ae6, 0x43903497, 0xa72a8fd8, 0x73a7547a, 0x3a6afe3f, 0x4ff13bc6, + 0x1ffeff08, 0xc7b847e0, 0xd45ea317, 0x620c88e5, 0x7a0ede7a, 0xd9ce2637, + 0x3ed7f4d6, 0xd1f89fb0, 0x60bbcfcf, 0x52efe93f, 0xecf40bbb, 0xecfffbc9, + 0x8f863c82, 0x8ef167ee, 0xd7fe4cbb, 0xff4c4923, 0x5e54947f, 0xdbbaf303, + 0x2fa175ff, 0xbdc95f86, 0x51645f6c, 0x6f9d3450, 0xae379e34, 0x17cf990c, + 0x95df1007, 0xfd78fc52, 0xe71624fe, 0x59bf5459, 0x7c6156c9, 0xae81afdf, + 0x797fb927, 0x03dd81b2, 0xa733c3a2, 0x3e02a87e, 0x56c3dfd7, 0x2cdeafbe, + 0x9b43f5b3, 0x3e62fb0c, 0x9c33378e, 0xa4fdf887, 0xa22d7ff3, 0x8e9b33df, + 0xc3d52f75, 0xf3cb30be, 0xfe63cf35, 0x9c296a47, 0x90ff9fe7, 0xbc34fe80, + 0xcf5d3f7f, 0xc5aef77c, 0x3cf333fd, 0xa08fdf3b, 0x90b5dfa1, 0xce7cdbd3, + 0xed98616a, 0x3e23cf6f, 0xf94ecf94, 0x0f966118, 0x9e238e6d, 0x00e79c3b, + 0xf126343c, 0x3242ab7d, 0x762ef212, 0xfc97ee1e, 0x675ef96d, 0xd3f2b9f8, + 0xa4f44f3c, 0x9359609f, 0xdbf3b2a4, 0x814bb7e1, 0xee3596bf, 0xbe657bc0, + 0x0caa3eab, 0x84ff729f, 0x6a25e874, 0xe811fe5f, 0xc1827c48, 0xf9b65cee, + 0x65fcc2bc, 0xf83b9f86, 0x1f003bf3, 0xeececfb8, 0xa963b90f, 0xdef6217c, + 0x8c92f799, 0xa267ebfb, 0x3cd9e4e7, 0x93bef92a, 0x5f333f3e, 0x9b3e70d7, + 0x9ada75b7, 0x35ca745e, 0xf872274d, 0xfbcc0779, 0x2166f9d6, 0x8acd2f29, + 0xbd3a1fc3, 0xfe107ca2, 0xd3abc225, 0x6ced5e69, 0x2640af3e, 0x84cbf7df, + 0x2f9992b8, 0xd76f3aba, 0x80e4b72a, 0xdee99abc, 0xfb3ce09a, 0x3ed893df, + 0x2b553ced, 0x9f38bd05, 0xc4f1af94, 0xa5272bd8, 0x81f743da, 0x7c656d1c, + 0xe06bd51c, 0x7ebe82bc, 0x7cf5c64b, 0x80cd4bb9, 0x1e90917b, 0x87615e70, + 0xe9ef0035, 0x6bf71ce3, 0xf0197f5a, 0x69e5865d, 0x7fd6b97f, 0x82fb4740, + 0x10dde78d, 0x441b6dc7, 0xead3be30, 0x71ebc232, 0xc78f0888, 0xa5bbd6c1, + 0x1f37f352, 0xdada0e80, 0xc711f98c, 0xd0f8f12f, 0xbc596b25, 0x10ed5e79, + 0xdd05f70c, 0xf74ae5c5, 0xf4e6ee3f, 0xf6cc2bbb, 0x9a6ce7bd, 0xdf30f486, + 0xfb847267, 0x041bb32d, 0xfa6623d4, 0x775ef7cc, 0xdcedf40a, 0xdf7e1160, + 0x11e45e89, 0x6e99bba4, 0x761e1deb, 0xad548dbf, 0xc73f7dc0, 0x4fb80937, + 0xde8124b8, 0x8f0777fb, 0x3e737767, 0x822479e6, 0x55d6e17f, 0x98117a6b, + 0xf80550ff, 0x3ebf0cdc, 0x6344f9ff, 0x37cf877a, 0xcb48bcd1, 0x829f2cb5, + 0xc28be3af, 0x65a97eec, 0xaf2c888f, 0x748bc793, 0xcd7875f8, 0x971528f3, + 0xdb6f3e62, 0x09f31106, 0xd7040aef, 0x77cbbdc0, 0x3d7016ad, 0x5d27444d, + 0x32fbe84f, 0x63671acb, 0xf68f957e, 0xdb697603, 0xd9170487, 0xde0275b6, + 0x9e90937f, 0x94579661, 0x30849e88, 0x74a3cdba, 0x7e6e387b, 0x3fd6915c, + 0x78273f76, 0x763fd6bd, 0x3084897f, 0xdd4964af, 0x4af3c334, 0x774f5187, + 0x3aa47f25, 0x2e9cde7e, 0xe9fcba6f, 0x9c1eb8f2, 0xa51fb073, 0x5ceca1e0, + 0xe863cfc0, 0xfbfd50af, 0xff8b0773, 0x7d1b7a3c, 0xf3c6d965, 0xf984fd86, + 0xe6bd18a3, 0x79f1938b, 0xe28375a2, 0xd787a0c1, 0xf87a8c3a, 0x9f47ce87, + 0xfa272e87, 0x6272ccfc, 0x0f4cdefe, 0xa6670e3d, 0x001e998b, 0x470df827, + 0x07c11c9a, 0x04479c28, 0xc9a07706, 0x66b7708e, 0xfe706896, 0xedd65966, + 0x0f811e58, 0x57bd8347, 0xed038cfe, 0x7957ee56, 0x4503e7e3, 0xf76e25ed, + 0x41961988, 0x93111e30, 0x2ec790bc, 0x77aa5b66, 0x7d8a79d2, 0xd2183969, + 0x9c22bd99, 0x992daee7, 0x143dc220, 0x77bcfc35, 0x379d858d, 0xc3dbfbd3, + 0xed97a0f1, 0x8046f28e, 0x9a9fece7, 0xfe2c1d0b, 0xce0afe8c, 0x143dee13, + 0x760dbfa8, 0xf304ebf0, 0xc8d20b69, 0x83b7a001, 0xee40a368, 0x72a4743f, + 0xffed9c3b, 0x286cbfd1, 0xcbcb56bd, 0x3f9097aa, 0x49b3e2fc, 0x37b25f70, + 0x9722b2d9, 0x38e2ffd6, 0xb9ee093d, 0xce5b66f3, 0xfda87ae7, 0xd59cf8ed, + 0xef9cb6af, 0x737feb47, 0xd875619c, 0xf87b82a8, 0x0527671c, 0x1e38c306, + 0xb5eae7a6, 0x243e41ab, 0xa597f30b, 0xc3c60afd, 0xd5fdfdf5, 0x17e0e694, + 0x79f9c87f, 0x17e2aacd, 0x2c67101c, 0x6fd854d6, 0x71be0ade, 0xea5fefcf, + 0x161d1578, 0x4a0367bc, 0x1ca7ffc0, 0x485d3a9f, 0xe4357683, 0x7690923d, + 0xb483ec35, 0x1dc77c3b, 0x91d87db4, 0x572009e6, 0x5fbcef0d, 0xf68df788, + 0xa30cfd65, 0xf3a6e20c, 0x9f6afb39, 0x8afbb1cd, 0xcfa28eed, 0x0c943e81, + 0xaa084768, 0xed41dc87, 0xa88d1a86, 0x31f81e4a, 0x81bdbb46, 0x49d7d9f3, + 0xcf91e7e5, 0x9f50477a, 0x7df0e53c, 0xfd9be305, 0xda9cd211, 0xf253fe2d, + 0x7af8c5ef, 0xd1e3766a, 0xff9f2039, 0x0afdcec5, 0x7af9869a, 0x9ef7a3db, + 0x1df7f410, 0x710bc924, 0x9925e236, 0xb71e7481, 0x4abe30b0, 0x4bf18c2b, + 0xf7e87cf8, 0x951ee113, 0x1fb60e91, 0x8227e74c, 0xa894369f, 0xf8830e58, + 0x9ab01e43, 0x487beb0f, 0xb47de8e8, 0xccedc7ff, 0x11d5b7ef, 0x84675c43, + 0x7707d993, 0x275c58b9, 0x0cdd0e49, 0x0be93dfa, 0xdefd01e2, 0xe12294f6, + 0xb9e4a67e, 0x0e39f711, 0xf82e3059, 0x40f41cac, 0x4afdbd7c, 0x3a42dd49, + 0x74e36bfa, 0x5c7dfbd7, 0x7884af51, 0xb3175cca, 0x222d9e27, 0x7edaf798, + 0xfec2094a, 0xadb66a57, 0xcf4fd63a, 0x4faddfe7, 0xa4e41e2e, 0x8929a865, + 0xf723f8c0, 0xd2928352, 0x02fa85e3, 0x76c5f03b, 0x43c511c0, 0x0f73d5aa, + 0x9e7a97f4, 0xcf8b9bc2, 0xa4afc435, 0xf8a64d0e, 0x5383731d, 0x9e297b85, + 0xc06e87b5, 0x2d17bf3c, 0x76d3ff78, 0xea0d3bc5, 0x1ea9cfdb, 0x9b3d0788, + 0xf9c24a1b, 0xf9c168bc, 0xbf6a4f6c, 0xfb85396a, 0x8e2c41e1, 0x64883920, + 0x2a79054b, 0xcfa1ef56, 0x7d993bc7, 0xe4c2dabb, 0x62a9daa9, 0x8e8171fd, + 0x15ef005f, 0xf9e91ca1, 0xeced6d17, 0x5bcf471c, 0xe7e0459a, 0x3fba69a4, + 0x0fc1111f, 0x704e571f, 0x94e71d5d, 0xad3a2a83, 0x2176739a, 0xd6ceffdc, + 0x2e1f098d, 0x29f2cc9d, 0xefc2efbd, 0xf2701c21, 0xbef836fb, 0x4f9cb5d0, + 0xd11693c6, 0x5fc7db46, 0x2e48de24, 0x8c6af7dc, 0x5a633edf, 0xfef127e7, + 0x44cf76b5, 0x8c445c78, 0x0da4f0eb, 0xae20a7a5, 0x09344c5c, 0x66c4a9f8, + 0xdcf5876a, 0x9ac4f70d, 0xf273c9ee, 0xe4872b75, 0xe8fde6c4, 0xe249fb71, + 0x47688de0, 0xc05e2994, 0xf6a70ecb, 0x0d4fd857, 0xdbf2f750, 0xf8cf3de2, + 0xa0d67e59, 0x57020e8b, 0x74fe50ff, 0xdaae7cc2, 0xd3b01b50, 0x9fd55f79, + 0x087c0ff5, 0xa78ae5fa, 0xbe807ad2, 0xe97a7377, 0xc077cea5, 0xc6649e5f, + 0x3a6b9e5f, 0x273ef3e4, 0xf2e89b8b, 0xfd077c06, 0xb78391ec, 0xa41fdbc7, + 0xf01f7afc, 0x41270eeb, 0x5917fa7b, 0x672059b6, 0x9dfb38fa, 0xe5cdff8c, + 0xf7cb559a, 0x0412efc1, 0xc6eb64be, 0x31175ec4, 0x6eba2e4f, 0xab783327, + 0x53e9dad4, 0x29c76f21, 0x3a4e5e63, 0xcb16373f, 0xfc31592f, 0xab5df3a2, + 0x3adff993, 0xfeec94ff, 0x284b9e33, 0x06fa92f9, 0x376a24b9, 0x2133fcea, + 0xb37dc110, 0x89d98409, 0x99d9fe66, 0x2e8a7f80, 0xade812a8, 0x9873fc4e, + 0xbe224ff1, 0xb048fda1, 0xe7f99a0e, 0xe3b72719, 0x25cff212, 0x6569e037, + 0xeeb7c953, 0x8dfa34ef, 0x72e67cf9, 0xbe7e23b4, 0xef1c67e7, 0x1bda95bb, + 0x4c6f41f3, 0x2f4178b1, 0xbec8ee50, 0x3bbbc299, 0xb5d7bf49, 0x3bea0f3a, + 0x7687a624, 0x87a8ad84, 0x3e7d3876, 0xb2658b8c, 0xf24474f3, 0xb6fe40b5, + 0x8d4d97b7, 0x7efb27bd, 0x39218fce, 0xd804fa32, 0x3e306f45, 0x00a53518, + 0x5921bc6e, 0x185e98f3, 0x0cd9527e, 0xd0b28fbf, 0x9386f455, 0x74067fbe, + 0xc753ac07, 0x60b7bc14, 0xf50531d9, 0xdf7babe3, 0x93b8852e, 0x723a179e, + 0xc5a5dbcf, 0xc67de183, 0xfd736f6f, 0x6531d7aa, 0xe9a5f41e, 0x84d1d85e, + 0xbdf331e9, 0x47c0e5ae, 0xe6ed1df9, 0x49434efb, 0x933d2e2c, 0x0e9bb2a8, + 0xf958fd31, 0x885d7083, 0x99d3def9, 0x4fd01b91, 0x5f5de5b8, 0x394f7bfc, + 0xdfef987f, 0x77c93afc, 0xf95fe61a, 0x985ef342, 0xbad95102, 0xafaa521d, + 0x579ef766, 0xe93f01e7, 0x147f8872, 0x068fa17f, 0xf5ddee19, 0x11e8f5f2, + 0x7beec4af, 0xbf705168, 0x7d8497e7, 0x98ebe217, 0x40f4c5cd, 0x6e97cac1, + 0x55873807, 0x2e800768, 0xf9993bff, 0x1122bfd7, 0xcdd01e5b, 0x3a9c612b, + 0x2725ab24, 0x88f78e84, 0xce083e54, 0x99e9ed75, 0x5fc60c34, 0x5c39f2e8, + 0xed486f60, 0x91bbe187, 0x81860a63, 0x5d0e771e, 0x35d603dd, 0x570a6e1d, + 0x076736d9, 0x175c3a1c, 0x742cbf39, 0x7ab876cd, 0x2f40efb2, 0xdc7c7e35, + 0xfcebdf06, 0x82fa6a10, 0x5f0c41f1, 0xf0741f00, 0xd4377085, 0xf1a43c75, + 0xd8ffaf52, 0x97fba17c, 0xf805f25d, 0xc5efee8f, 0x715c4317, 0x73da82f8, + 0xd9b9e1c3, 0x2c290b9e, 0xfcfccccf, 0xbe114729, 0xe60855ef, 0x76bd9089, + 0xbe3bbbf6, 0xbf2f8c14, 0xb66361ec, 0x073c747d, 0x5ceb957c, 0xf90e4ca9, + 0x2343df3d, 0x439fda02, 0x03b8a2a9, 0xa8debced, 0x7f1cbd27, 0xc020b8e4, + 0x4b985dfd, 0x68760d9c, 0x6bd807a4, 0x2393ad43, 0x1d3b0f20, 0x7ec1b213, + 0xcb8c702c, 0x32bff983, 0xb05be568, 0xabd2bda4, 0x6aade5e2, 0xeba57d87, + 0x5bbc03c3, 0x5d5bfc7d, 0xd5ae3f8c, 0xd010f9d8, 0xe870b1eb, 0x099003eb, + 0x332210e0, 0xa81d972d, 0x142dc3c7, 0x1c02d76f, 0x04fb0f14, 0x43f600d2, + 0x2b4b4591, 0x67b03b01, 0xdb380244, 0x0391fe9a, 0xe1c9a771, 0x78051fdf, + 0x5bfbeb27, 0x96fee35e, 0xedd6ded9, 0xd0ffdd21, 0x228925ed, 0xa0abb742, + 0xa73c047d, 0xbdc0f4f8, 0x45beb0e0, 0xf53e786c, 0x95ea73f1, 0x8967971a, + 0x9f3263ce, 0x19a44dc7, 0x2e9722e1, 0xe9471e5f, 0x63e39533, 0x491261f2, + 0x427687ca, 0xfdc014a6, 0x4c902433, 0x15e299c7, 0x7c3127c8, 0x6328d373, + 0xa426fe1d, 0xd5d3f477, 0x6375e6fb, 0xffce29ac, 0x7ec3cb43, 0x4dfc6e76, + 0x3c173b3f, 0x90189fa6, 0x951dfd60, 0x7b03cecb, 0x2b0e1e18, 0x23b1d7f1, + 0x58c79e5c, 0x3ce1f25a, 0xff3dbee4, 0xff7375c4, 0x07be7f9e, 0x53e8e476, + 0xc63c8112, 0x2786a731, 0x28ebbee3, 0xef4af915, 0x06b3eab7, 0x49cf6107, + 0x87e87dec, 0x15da3c28, 0xcb0d9f00, 0xfe3cced7, 0xe177f404, 0xf3624498, + 0x5f154be4, 0x968f887f, 0x0ff17bf2, 0xd29ecc09, 0xfbf10fdb, 0x78b977a8, + 0x93d28e7c, 0x1ac4c7fb, 0x5429e743, 0x74172513, 0xc9ca75d0, 0x7e5253b2, + 0xdfc0fa67, 0x7e1f3a27, 0x57749e4b, 0xfb0e7ea5, 0x5eb62ef7, 0xc37f0392, + 0x35d70cf3, 0xfd8123dc, 0x48a65d7e, 0xaf7198b4, 0x1fa7a957, 0xebd8f713, + 0x07bfd932, 0x2a627b9e, 0x111e79e4, 0x2aac6531, 0x7cade3bc, 0x718b37a8, + 0xf19ba7cf, 0x1ef85d7b, 0x887ff809, 0x574dc99b, 0x8ab98fe3, 0x4035c9f2, + 0xc0ecc277, 0xc8e50142, 0x7bfddf4c, 0xcb47a3fe, 0x4ef8c4e0, 0x1d337f44, + 0x8c533b5e, 0xd15d21fb, 0x7bb7ccc3, 0x57033ce9, 0xd97aefc0, 0xd77f0048, + 0x83f583cb, 0xebac4cfe, 0xf4d55afc, 0xf3b00f74, 0xd49d3e74, 0xe8cdf183, + 0x20f44fdd, 0x997a0ece, 0x19b826f1, 0x75d976fd, 0x633bc4bb, 0x67f47d2a, + 0xa3210eba, 0xe4334806, 0x587394d9, 0x8a5bbe67, 0xf9e10976, 0x6df5e6ff, + 0x24c778a6, 0xdd5da750, 0x3a8b7f4b, 0xb9f75bbb, 0x95a91d97, 0x952c1d60, + 0xc63d3256, 0x1e1d78ed, 0x42ff9d33, 0x44fe11ca, 0xc0f999f0, 0x68aee70c, + 0xeb86b27e, 0xfb4f7e81, 0x72b9fef4, 0xe8799c6a, 0xd085b8f8, 0xfbaf38f5, + 0xdb8e71eb, 0x4fe7ffc8, 0xa013fc4e, 0x99bc9135, 0xd76e66e9, 0x0c2947f5, + 0x00658050, 0xee2193ec, 0xd2879474, 0x60d10a8b, 0x9db7ba5f, 0x379b1a7c, + 0xe40af93a, 0xf61e15b7, 0x2dbf112c, 0xdf1228bb, 0x93be0eb0, 0x00731f1b, + 0x6a96eddf, 0xf7f45e1d, 0x5324d5a7, 0xacfc4d3c, 0x073c16f8, 0x102162de, + 0xfe149b5a, 0x19c400e2, 0xcc128eaa, 0xef0e2f07, 0x3d3e012b, 0x9fa33528, + 0x908176d5, 0xceec62c7, 0x038d70c6, 0x34c6b2ec, 0x50e99e76, 0x9be4310a, + 0x7d33711e, 0xdcec78dd, 0xbb4e2d54, 0x79f8cc98, 0xf2d2d13a, 0xd74b3fe9, + 0x3f00fe51, 0xe30ba7b8, 0xef051324, 0xb76069eb, 0x9feec6dc, 0xf91a6b6c, + 0xb7851a7a, 0xd414cef5, 0xd71a9333, 0x84a1e3de, 0x0c3d7d08, 0x16cfb79f, + 0x7be85bbc, 0xeb17aaa5, 0xd172f3a5, 0x4df91bef, 0xa193e98f, 0xfd197afd, + 0x52e2499e, 0x6755e209, 0xf0028533, 0x2d08f727, 0xf2f7e0ab, 0x38d8d302, + 0x01e813c4, 0x933be9fe, 0xdfc50c7b, 0xfaf55174, 0x205dfc00, 0x56dff262, + 0xcfbf3aee, 0xce57db4a, 0x733f3010, 0x049b2792, 0x74a7f862, 0xbaf3829d, + 0x0c519c39, 0xccbd3d7c, 0xc22c4e78, 0xe519c9ed, 0xdd8c120e, 0x283c1527, + 0xedec87d7, 0x5cefe2b7, 0xe604c936, 0x0df9cba7, 0xce67df9c, 0x6ef861ea, + 0xa776611a, 0x7237572e, 0xfb81bbf9, 0xb2f9b7cd, 0x1397e30d, 0x81fd0f66, + 0x92044fb4, 0x3cb32794, 0xcdeda9a2, 0x2f0edeef, 0x8047bd89, 0x9071bc3e, + 0x9715efc9, 0xc8be46ae, 0xc780bc14, 0xfb635e29, 0xe74ca34d, 0x6bf24d14, + 0x20330fd6, 0xacec4a3b, 0x307d7427, 0x219449a3, 0x88a3341e, 0x62ed19e2, + 0x95dedda3, 0x949918be, 0x525c5f40, 0xa433041f, 0xb0f8be93, 0x8be97bec, + 0x32dba957, 0x36f5ca8a, 0x21f46f5d, 0x4c6f407d, 0x009feb12, 0xeba36a3e, + 0x1f0e35a6, 0x1e8eebe9, 0x72a52807, 0x0ce07a8c, 0x749e2fcb, 0x86048b31, + 0xa201c475, 0x25da847a, 0xd2f638de, 0x619e777e, 0x57aa23ff, 0xb912ec62, + 0x25db87f0, 0xaa3da893, 0xbd7c0014, 0xc252be11, 0x90a596e2, 0xc3f102c8, + 0x0e302fcc, 0x7f512554, 0xa7e7d716, 0xffa39e99, 0xe43b5212, 0xe8af6cc3, + 0x3c09e871, 0x97e6617e, 0x16f23c68, 0x3a42e319, 0x3e02949f, 0x116ffe41, + 0x2ba09f71, 0x37c7d1be, 0x14c44bf3, 0x5f92ea1f, 0x577ddcb8, 0xe6ed397e, + 0xa4fea1f1, 0x44f8777f, 0x5f9d0fe7, 0x9bcdebcc, 0xa25138a6, 0xb09fe6f5, + 0xbc4cf4de, 0x483ebcde, 0x95debd46, 0x992e735d, 0x6e89f9e9, 0x75773b0f, + 0xd8270ce5, 0x59921335, 0x6ebe817e, 0x1b5de345, 0xdebc9f18, 0x7d824732, + 0x1fd02aa6, 0xd0741db9, 0x5f3ac5e3, 0x60275b2e, 0xd732747c, 0x2c4dad5f, + 0x5135585e, 0x8fd1c20c, 0x4f63f092, 0x6fbb3ab0, 0x14efa746, 0xd24527ce, + 0xff7e093e, 0xe0af26f4, 0xc693b885, 0x35538de3, 0x668de301, 0x44d7b5bd, + 0x1fbce9f7, 0xbbe0bff0, 0x2084ca9b, 0xfd6693f8, 0xb322fd36, 0x53d93a2f, + 0xccd89f7c, 0x7326572f, 0xf497d0fd, 0x15da57fd, 0xddbf92a3, 0xefbfd0ae, + 0xb065ce8a, 0xc0ffa0a6, 0x3b0193ee, 0xdd7ce81e, 0x2dfb0945, 0x49da3649, + 0xfc14ce17, 0xfe4f7d0a, 0x3a1ef9be, 0x1aba7cf3, 0x17f750bf, 0x8fa0ffb8, + 0xcec4837b, 0xa7d79bf7, 0xfe23d72e, 0x775e999d, 0xb5e31b24, 0x3d745d3a, + 0x5cef09dc, 0x5ba2274f, 0xd75a7a57, 0x3d6aff87, 0xafaff7ad, 0x66b8fa23, + 0x7fc89dfd, 0x9af1f5d4, 0xdb8c16cd, 0xfa7ee78c, 0xfe3f1e78, 0x7ee7b705, + 0xdffccc99, 0x166d2fb6, 0x32436f58, 0xec0b27db, 0x69fc6273, 0x07665efb, + 0xbe2a5cd9, 0x6220a0f7, 0x11c1e47c, 0xd4d7d416, 0xf3061a07, 0x19098a96, + 0xbdbdfb04, 0xbd6f7ed8, 0x7d472914, 0x9c0895ef, 0x8c5d13d3, 0x1fdc1e1f, + 0x7ffa1db8, 0x968193f0, 0x474f8c1a, 0x1a5ec19a, 0x7ee12059, 0xc5558a59, + 0x936b7678, 0x6a3bef15, 0xf6bffddb, 0x97cfd0c9, 0xe52e0bc4, 0x746b26c1, + 0xc7f40abf, 0x0888f124, 0xed6d1cf9, 0x1b03ef04, 0x02522b37, 0xd278d97e, + 0xfffe035c, 0xc1e58518, 0x6cd4f19b, 0xfbcca75a, 0x2c4d255d, 0xc5c4a5ff, + 0xed3a5ff3, 0xefe33457, 0x04904f26, 0xbce90d6f, 0xc992f15f, 0xefd8e9df, + 0xd15fb04a, 0x77d1f4c8, 0x0318afdd, 0xde7ca034, 0xd701cba4, 0xbec1244f, + 0xed8576c5, 0xcdbfb577, 0x6993d3ed, 0x5d46e371, 0xdeec5fed, 0x7dc1a49b, + 0xeff9db23, 0xdbdeec6c, 0x13f3534b, 0xd2df9fbf, 0xd8d30c5e, 0x84b37f5e, + 0xbe3c73f9, 0x9a0b8d1b, 0x90e9cbf1, 0x6b481f68, 0xf5041cf4, 0xe7df7095, + 0xaae18a82, 0x5d4f8aef, 0x4f1fb66e, 0xb7ef80d2, 0x01a5ef1f, 0xdc79fb1c, + 0xbcf56bd0, 0xeec2f605, 0x7092e763, 0x54d1583f, 0x53da4ff0, 0xae765e6c, + 0x2841c992, 0xf610606b, 0xeff0f7ab, 0xbfb527b6, 0xec5a7579, 0xbfdb0e7e, + 0xd7d9cfd1, 0x47f30428, 0x3f961602, 0x0cdfc662, 0x3b938f0f, 0x2274faf1, + 0xbc62a9a7, 0x096f503c, 0x3f3057cb, 0xce4c3c97, 0xfdfe2fff, 0x80006684, + 0x00008000, 0x00088b1f, 0x00000000, 0x5bbdff00, 0xd554780d, 0xdceefe99, + 0xf26677b9, 0xfc999933, 0x4dc2fe10, 0x00908102, 0x7e100843, 0x502021d4, + 0x4540647e, 0x043abaec, 0xa1bf9085, 0x56d3ebb1, 0x4126e1f7, 0x27d3e08a, + 0x6796dd6d, 0x57067db5, 0x3b1254b6, 0x770704c1, 0x08a00ec2, 0x80a0db54, + 0x11dae3c2, 0x2486a229, 0xec56bb0d, 0x3befdd6e, 0x6664dce7, 0xecfa5c18, + 0xf8728376, 0x9cf739ee, 0xfbdf7cef, 0xb3739dfd, 0x330001d3, 0x68776e01, + 0xdb00d900, 0x8c802f64, 0xde0820cf, 0x16e91bf4, 0xd305d609, 0x7ae77688, + 0xa9dfe0a7, 0xce1a6ba6, 0x2cb0ef91, 0x7a448f35, 0x42d1e986, 0xc639e7a4, + 0x699e7a72, 0xf806e286, 0xba5bc867, 0xcfc00e68, 0x03875e9c, 0xd257e9d7, + 0x00194876, 0x65049366, 0x528ed859, 0xec373803, 0x65ac0152, 0x3c1daeb8, + 0xaa40174e, 0xd21b7405, 0x54fb360d, 0x1e95f1a0, 0xd11a4b6d, 0x87c43d00, + 0xa5039a39, 0xd336bed8, 0xbe00b304, 0xadc1fb4d, 0x1ef8aaa4, 0xc5a8ffbe, + 0xfb81ce37, 0xec46b7ab, 0x1ff6015a, 0xa40473ba, 0x6c1d7ed1, 0xcf2f25bf, + 0xc60285cb, 0x33ffe157, 0xf8c9655f, 0x75f0a6da, 0x2c940f7a, 0x64bf5c04, + 0x1a5f8a1c, 0x59994fd6, 0x416dcf63, 0xf49f3d00, 0x9095c9e0, 0xeeaa716e, + 0xce34f99d, 0xb6f267d0, 0x21fd4145, 0x69aa725f, 0xce51e90b, 0xc0e96d30, + 0x89874ef6, 0xac58bfcd, 0xb7903003, 0x8e0df51a, 0x5335bc81, 0x96fa4d38, + 0x4881b2e5, 0x9b7f5239, 0x871e7eee, 0x0f8198c2, 0xddfa471e, 0x3bdc4a07, + 0xc290be91, 0x502eb1e5, 0x7a4512d0, 0x363025ba, 0x9d397c82, 0xf7c92f3e, + 0x04c0969b, 0x2db4a786, 0xe4bf34e9, 0xca0ef801, 0x3d104243, 0xf16efb80, + 0x0216a680, 0x1ce7808c, 0x90004b97, 0x332af82b, 0x2560bad9, 0x8737deb9, + 0x1758d5cb, 0x1c856865, 0x3f82a7e4, 0xf5c0f837, 0xc1beb47d, 0x301f10cf, + 0x153971c6, 0x4857cfd8, 0xd33cd1f7, 0x0a321e50, 0xfff3d705, 0xa0b014de, + 0x3ff8fdfc, 0x325f2fd1, 0xc9897405, 0x2cfd6d3d, 0x33ad88f6, 0x9966ade7, + 0x9fe3ab31, 0xecd44c59, 0xbb543ca7, 0xf748ec02, 0xad462f98, 0x37f61d62, + 0x9cf91c6e, 0x7d9fde27, 0x8d30b7c2, 0xc7e2f7da, 0xffa783cd, 0x15fbe320, + 0xe5019010, 0xd09a2732, 0x31fe5a1f, 0x4aef3fcd, 0x77bff3fc, 0x7db167a4, + 0x5f51828d, 0x77227db1, 0x95a35eb8, 0x66f837af, 0xd3e10641, 0xa2d9466c, + 0x864d55fc, 0xa2bf6c0a, 0x3a003b9f, 0x0b38e2b7, 0x56adc1c0, 0xe3394ed6, + 0x84eb40d8, 0x269022b6, 0x35babc02, 0x1d86b597, 0x0f03394d, 0x7598d4c1, + 0x390dde04, 0xe5c7be0e, 0xe93a3d38, 0x5691f3a7, 0xd010284e, 0x5730e586, + 0x5d106bc8, 0xf079e906, 0x475b9a4a, 0xbbc9d67a, 0x4b4fb265, 0x98b409ae, + 0x14b4d9fd, 0xd30d26d0, 0x715c93a9, 0xb8f42cb4, 0x9e7f66cd, 0xf4f742e1, + 0x333ae2e4, 0xeee93ac4, 0x41f37151, 0xe8c4ff00, 0xe2d755f3, 0x67ee1213, + 0x0af55a46, 0x454657da, 0xe5fcdc41, 0xbbcbc66f, 0x091ebc0c, 0x8fbf765f, + 0xb3fbe3fc, 0xcc7f60ce, 0x2b488af8, 0xfbc547c3, 0x5ee7cff1, 0x6f3ba78a, + 0xc99bb7a6, 0x74fea613, 0x2e5fd67e, 0x5e27a74f, 0xe34b999e, 0x8ded99e5, + 0x7588e797, 0xe91af2f1, 0xe8c7978b, 0xfd71c9ea, 0xc594b763, 0x33bee3d1, + 0xbe7c6e37, 0x1747195e, 0x371658ee, 0x9aeb427e, 0xeee27a38, 0x2f8dc66f, + 0xf5c5540e, 0xf9abec97, 0x253ff48b, 0x9e3718d8, 0x1afa6cc4, 0x7d0b4ffd, + 0xbfbd6e2f, 0x9dfffe96, 0xcf7e8ff4, 0x7a44bfd0, 0x42fa499f, 0x1c36593f, + 0x06b89c9f, 0xf8674bf9, 0xda12eb8d, 0xe9a95ea5, 0x0cbebcc4, 0xf7d82ddc, + 0xc895ec8c, 0x51468dbf, 0x6c6fd09b, 0xf9354133, 0x4c981ffd, 0x86d3790f, + 0x94e4dced, 0xaacffcd8, 0x14b8a660, 0xe94d6e3b, 0x4da338f0, 0x78d89a77, + 0xd37edfc3, 0xd144b5a2, 0xb9974e9f, 0x9b3f453f, 0x707f44ee, 0x21427a41, + 0xe964a937, 0xc594af8a, 0xd8bc879d, 0x6a4b213a, 0xd86336c4, 0xa15f6bbf, + 0x81a82e52, 0xfe213fbd, 0xbdeec94f, 0x486fffc8, 0x17492320, 0xef3f166e, + 0xa696fc37, 0xf8633865, 0xe2334c1a, 0xf14196ad, 0x42e1f073, 0x3fced7e6, + 0xf50b4e88, 0xfbe55e7f, 0x115fc631, 0xe153ed7e, 0x9fc97ad7, 0xabfb8659, + 0x5d38fcf7, 0x4fce79c3, 0x18c1a582, 0x390b1539, 0x2c1c1981, 0x3ae3ccee, + 0x4bb350bb, 0xdff388d9, 0xa16c2ef7, 0x13fbee75, 0x6f7d896c, 0xfe6153b6, + 0x6653b671, 0x726c5aed, 0x316bce51, 0x18cb39a6, 0x5db0911d, 0xb2140275, + 0x7cbed5cb, 0x0ef28485, 0xe176cfb8, 0xd1480b92, 0xe03ddef8, 0x9fffc855, + 0x9d3eb07b, 0xf3cd0dc6, 0x117713c6, 0xa2a2d73e, 0xd7792f29, 0xe8392ba9, + 0x936e060f, 0x75c49c58, 0xfbdcf4ac, 0x2927e8c0, 0xdf039cbe, 0xafa8b3d5, + 0xf366e035, 0x7222f319, 0x05ccfce3, 0x38992215, 0x12c17e8f, 0x347c8bd8, + 0xfa825e52, 0xc11eec69, 0xcd7f5fe2, 0x827fdb1f, 0x1d1a1ee3, 0xfaf14b1d, + 0x8a9fcd42, 0xeff7cf48, 0x7d434196, 0x77c5377e, 0x90c0e117, 0xaf87f9c3, + 0xc63f53a5, 0xd867a65d, 0x65ef716f, 0xdecfdbf2, 0x73adc633, 0xde9bb82e, + 0xd0140a83, 0x67f11b9c, 0x496814b4, 0xe06a352e, 0x3e43dfe7, 0xe6c294e1, + 0x59b2f033, 0x5f31a5e0, 0x978b111b, 0xbc21f4c6, 0x71ab7cb0, 0xa6ecccaf, + 0x0016dbb1, 0x8159cb94, 0xebfeff3b, 0x234f7d2f, 0x1f3de782, 0xc4346e21, + 0x3711efc9, 0x8fbdc61a, 0x3f443711, 0x886b7b2a, 0xfe9e8fdf, 0x79a3eec8, + 0xbe35b9ef, 0x7381a5fb, 0x3df2437f, 0x083ef1c9, 0x5f98e783, 0x28d62cef, + 0xf0785baf, 0xebca39fa, 0x9a2d3a1a, 0xceabe905, 0x6967f1e8, 0x680921fc, + 0xc6c4437c, 0xa743559c, 0x7f61b014, 0xfb63a84d, 0xda6ba468, 0xd8539756, + 0x7221dbf0, 0x901ff507, 0x7fd8cd02, 0x7b5eab79, 0xf0b87509, 0x6997ebd5, + 0xf957bede, 0xeab657bc, 0x9013cc1b, 0x03feb03e, 0xd3aeaf9a, 0x6fd43602, + 0x8ea2339f, 0xa43af5a6, 0x1d57ad20, 0xf34aa1fc, 0x7ab0bf57, 0xb539a53c, + 0xc6aa9afb, 0xbebff8c7, 0x0d55a783, 0xf9dd54e5, 0x5c62c5c3, 0x015f0f39, + 0xfec63766, 0x369a0737, 0x2ee36398, 0x7b275bfe, 0x2df77e12, 0xe175ff21, + 0x271216c2, 0x67ae95fa, 0x7657e625, 0xb872bf33, 0x85fedffd, 0x8bf43bd6, + 0x281b8409, 0x837935bf, 0xb1716757, 0x5703ac41, 0x9ea951de, 0x2e54e869, + 0x7c65e7c7, 0x77a735fc, 0xf92673af, 0x85b49855, 0x79f13bd5, 0x25940ee2, + 0x7e7ae1e5, 0x390fb30a, 0x8f5d406d, 0x069f7cfc, 0xc7663f20, 0xf4855a80, + 0x5718970e, 0xcdec0d60, 0x3ebf91bf, 0x67ad99a7, 0xac5f002d, 0xcfda30df, + 0x82b1ff44, 0xd528d54f, 0x9515da17, 0xf910db70, 0x7f90d544, 0xc5c3e87f, + 0x7def249e, 0x6295fc22, 0x29ef56f2, 0x468fb61f, 0x714a39a9, 0x44d0f1aa, + 0xd67a674d, 0x2ebf8ca3, 0x58fb469b, 0x5993f078, 0x3ef998d1, 0x578c7c43, + 0x5f86e986, 0x2155387d, 0xe1fcbdb9, 0xcc7a7354, 0xaad2723e, 0xe0f94903, + 0xbb49e2f1, 0x5bad0af7, 0x35a2d07f, 0xdcdb7c33, 0x3877c211, 0x44668dd5, + 0xcb9b56f8, 0x3f7df163, 0x2c21bbe3, 0xd0e911bb, 0x6bed5a10, 0xddd3e362, + 0xb43906a4, 0xc99c2740, 0x23c32f0e, 0x37ae27fc, 0xfe30e28b, 0x756a3fa0, + 0x78477efa, 0x55e9a731, 0xdaf898e6, 0x35e68a60, 0x5f3fa44b, 0xfb1882eb, + 0xad74d393, 0x99e48b39, 0x61b596e9, 0xae2629fd, 0x6a2d3e97, 0xdb1c5177, + 0xbd91f38a, 0x93b13e44, 0x3687b7fc, 0x3beec958, 0x47ae0e9c, 0x481cd755, + 0x877a09b7, 0xbb26adea, 0xc29391da, 0x2e31b5eb, 0x09ffef86, 0xaf647daf, + 0x3e028eb8, 0x09f77f56, 0x058df5bc, 0xf7297fe6, 0x94c99c23, 0x199215ef, + 0xce341cf9, 0xbdaa6a1f, 0x87976b14, 0x7f1373ee, 0x1f7f0a4a, 0x135e3872, + 0x7175cdd7, 0xaa693d9c, 0x13105d6a, 0xe5c71387, 0xc399b8d0, 0xceb30072, + 0x697001ce, 0xfefc324f, 0x776959c2, 0xde5dfe91, 0xcd87e449, 0x51e118c4, + 0x81f29353, 0xd95cb3e3, 0x2e4de3c3, 0x554f5b07, 0xeb920e7c, 0xad39397f, + 0x67265ea8, 0xec8d6c34, 0x057f6878, 0x9b3b526a, 0x91def82e, 0xc4f7af1f, + 0x38c4d371, 0x56e7a4c5, 0x65879f11, 0xdafd3766, 0x31bfd300, 0x9d723fae, + 0xed7c3feb, 0x79d90f2e, 0xcf865afe, 0x5c597f4f, 0xbbccc726, 0x853959ce, + 0x12e793f6, 0x5cf45078, 0x2ba47be2, 0x733f1f7e, 0x62b8677a, 0x4c601fce, + 0x04e12dd6, 0x16e07d44, 0x83eb0ef1, 0xb57c6649, 0xe4dc521f, 0x1e443bdf, + 0xc32f066c, 0x35b82a49, 0xe07af756, 0x7f70f3d7, 0xb04c472d, 0x1d3b4913, + 0xf3628c72, 0x04d8b079, 0x8a326cbb, 0x4b158f08, 0x323212bd, 0x9ae25fec, + 0xc86d8df6, 0x65d021ef, 0xd7c73f5e, 0x3c91e0c1, 0xfbfd6c52, 0xd5adcd5a, + 0x5af9cfbf, 0xeb13cec8, 0xd31139df, 0x16e3357a, 0x96d7e0ea, 0x1f83ad25, + 0x53d7c574, 0xc634bb0f, 0xc712705c, 0x12923061, 0x3028e7e0, 0x845c7083, + 0xedfa84e1, 0xa555bc39, 0x275649be, 0xf4d733c6, 0x418c76a7, 0xe5cf1b3b, + 0xfd0b7440, 0x8df3ca3b, 0xb5fabaa1, 0x44ff2cc9, 0x7ab3247f, 0x497821d2, + 0xe6395fd0, 0x7118bc49, 0x91e5d5c7, 0xc9da5fe3, 0xb4bbb6ff, 0x067e92df, + 0x7940ca4e, 0x551ccd9c, 0xebec499d, 0x98b3e520, 0xe2e4bc8f, 0x921ad67e, + 0xdf5c013c, 0xe28079aa, 0x98e1cdbc, 0x59d8c72e, 0x85c78b95, 0xf217e3fa, + 0xaf23cc54, 0x97b4de9a, 0x5d75fce2, 0xcc74ec07, 0xedfe7b53, 0xb4147459, + 0x4edbecc8, 0xb4a9fb76, 0xf94ac8a7, 0x54c08ee1, 0x52304f92, 0x77714190, + 0x7374198a, 0xf8fc8dd9, 0x50a6e377, 0x33bb0d86, 0x3c253b59, 0xa7e51363, + 0x2fdf08fe, 0x0ba0a1ad, 0x8c490e2c, 0xb8b50bee, 0xbfff3e68, 0x3f228f76, + 0x9f9b3fb5, 0x45f8be2f, 0x0cdf7f09, 0xacff1a66, 0x1ef029cb, 0xd479d130, + 0xd58e717e, 0xc6cc85f7, 0x094feb19, 0x881d902d, 0xeb48d283, 0x164e7651, + 0xca7cb0b6, 0x797002f6, 0xa3cf3184, 0x4bc39cf3, 0xbf51e280, 0xf612dc13, + 0xb00ca7b7, 0xdba067fc, 0x912f3da2, 0xec815adc, 0x75e55dbd, 0xf602314b, + 0x73f0da40, 0xf85b3d63, 0x44e674a7, 0xfc50f0b8, 0xe15b99b3, 0x7958b4b6, + 0x877933a7, 0xa6c80f29, 0x34a62275, 0x77d1cfca, 0x1af8cf3e, 0xbad813e6, + 0xccc59f06, 0x03abb7cf, 0x62cf1f97, 0x0708397c, 0x84f9c0c5, 0xfc8d44f0, + 0x61e1cd9c, 0x3439b0fb, 0xc8dd2eb7, 0x262a7f97, 0x3f3f6860, 0x7b218668, + 0xa7f6fb26, 0xb456d30c, 0x8e02f685, 0x3c37d06b, 0x0c7e68b5, 0x62a68e4d, + 0xaed3fdf8, 0x1b6d4f8d, 0x748dcec3, 0x8a9ff519, 0xf68bba6d, 0xbd0aedc9, + 0x8cbb27a7, 0x728dc1cb, 0xfef2b54a, 0xf388f1a1, 0xf8d3a234, 0x91c5b738, + 0xd99f2cba, 0x18bd900b, 0xa5b7d9f9, 0x503be5c8, 0xf43fbdb5, 0xbee29466, + 0x1f474d7a, 0x9f71c36b, 0x45160fad, 0x7d50fea8, 0x5f3e13ef, 0xd76abf79, + 0xedbbf214, 0xf9057b8a, 0x23fea89f, 0xa8bf0796, 0xec633b68, 0xe40cc60e, + 0xd7137e10, 0xfe6f9ff1, 0xfdb9e511, 0xaacd2487, 0xc81dff91, 0xc21bbe23, + 0xd7e4ab1f, 0x643e87fd, 0x9913ed79, 0x5eb42bbe, 0x2169a845, 0xb40e75c9, + 0x2edf90b6, 0x3041f911, 0xc193fb97, 0x37cf4533, 0x9ec1e8c5, 0x0edc7129, + 0x9c51c6f8, 0x3d7b0b0a, 0xb627f54c, 0x2fee475d, 0x44bbf9a4, 0xd7bc6c7d, + 0x93474704, 0x35e19bdc, 0x9dc50ed6, 0xe1297980, 0xf59ce4ac, 0x78cc4f21, + 0xbf3f266b, 0x02f58ab5, 0x133fbe99, 0x2e47b5bf, 0xe7da76aa, 0xd51e60a5, + 0x93ac4195, 0xc8fc491d, 0xd826fd90, 0xa03cdf93, 0x15ff78d2, 0xf5057e60, + 0xf5032dbd, 0x685cffb7, 0xde7c7af2, 0xa0c93a85, 0xaf3ce17c, 0xef14bb13, + 0x74df1a68, 0xe4a9f3f6, 0xa82806c7, 0x779f7fe1, 0xb9238ed7, 0x532bfe21, + 0x803acec8, 0x4ec335f9, 0xf14ec94b, 0x7fc252fd, 0xccc5d139, 0x3dabb72f, + 0x765d98cb, 0x12ec8099, 0x01eccff1, 0xb8a0eff1, 0x7b40ea5c, 0x644fef60, + 0x63dede76, 0x167cb0f2, 0x4604fafd, 0x744dde57, 0x0722cf7b, 0xe21373b3, + 0x35ec8cb9, 0x13cd9472, 0xa634a004, 0xec6f025c, 0xcb954139, 0xf86cf0ce, + 0x7ec22dcb, 0x0cb49383, 0x5523ee37, 0x23ece396, 0x5a725e26, 0x7fc7d3c4, + 0x9ea793fc, 0xa78f4f99, 0x10e138f3, 0xce9b5271, 0x22a3fefc, 0x3ebe3556, + 0xe51b5577, 0xacc96fe5, 0xa738b0ff, 0x1c9c0888, 0x1414e715, 0xcfd43437, + 0x75fce26b, 0xf41ed226, 0x5b3cb3a3, 0x556e5216, 0x18f5b4b1, 0xc1bd73b5, + 0xce329485, 0x4c73d75f, 0x425e66e1, 0xfa3cebf8, 0xf933128d, 0xcebcf3bd, + 0xe072fceb, 0x0e511783, 0xf9461d8f, 0xb8538927, 0xcc3f861d, 0xee4346b3, + 0x92fdfd8d, 0xf97e47e1, 0xfa43aa0d, 0x1a61e53a, 0x020363e3, 0x9955e89b, + 0x474a78bf, 0xf4c83ec6, 0x7944c9ac, 0x35bed9ca, 0x9cef9499, 0xcc8732fe, + 0x45ccebb2, 0xaa773f56, 0x4fc2129e, 0x9c960167, 0x7b7a7049, 0x51f4c2a6, + 0x673f896e, 0x84c7da31, 0xb0e9141d, 0xb1f5624b, 0xfd5008ec, 0x547b29dc, + 0x80ae83cc, 0xf91e76be, 0xf81e711b, 0x0f1f8808, 0x6cfd41fe, 0x9423e414, + 0xdadc60b7, 0x77128cf8, 0x2de4673e, 0xb07bc675, 0xdaf844c5, 0x1fe09614, + 0xcfd51651, 0xa3af8fc5, 0xd9e705bc, 0x7c73da1c, 0xe6b5ea34, 0xca7e8485, + 0x79b9d85b, 0x75a3d590, 0xfe5c4a6d, 0x38a658f2, 0x42842c0f, 0x57105fca, + 0x66284fcc, 0x1c416138, 0x6df6c84f, 0x6fdf3b20, 0xff42f2e2, 0x0373ecca, + 0xb79f15e1, 0x34bf7257, 0xcc021570, 0x8f05f67e, 0xb9df91d9, 0x5a6ef96d, + 0xf799ae63, 0xf3e50dcf, 0x40730d7b, 0xa90a8d5e, 0xb316f8f0, 0x9cf75afc, + 0x54b945c9, 0x0e097f0b, 0x59b5fe7e, 0xe45abeec, 0x4a039b77, 0x2fcefcd2, + 0x4081cdc6, 0x69bbad0b, 0x47cec49f, 0x8fc5f76b, 0xd5390bf7, 0x9c7d3eed, + 0x83eafd8e, 0x4e42fd09, 0xf3fc50fe, 0x78727c03, 0x1e5390d6, 0xf373b1e4, + 0x6756b713, 0x7cf0a67d, 0x8f316de3, 0x38161fd1, 0x906dc06a, 0x7202eb7e, + 0x2d547080, 0xf79e76e9, 0xdc7ada42, 0x060306df, 0xb941fe1a, 0xb4e42c3c, + 0xed87e041, 0x7fafdf1f, 0xbdd00a4e, 0xc74fc3d3, 0x5e035ff3, 0xdf3e3475, + 0x952df9d8, 0xf112f5ce, 0xb0a6dd56, 0xc846b7fc, 0x355f1127, 0x5569f843, + 0xe225be29, 0xdd27c1ab, 0xb79e7f84, 0x37f96fff, 0xa6235cf4, 0xec2255a9, + 0x1ff6a89c, 0xddaeb724, 0xfb435f7c, 0x4bfbfb11, 0xd0de75f7, 0xcc9864f7, + 0xf334bdf4, 0xf8a5eb16, 0xe543bb7c, 0xe6683376, 0x9e06cae7, 0x2c5fdf12, + 0xbb25f5f2, 0x357ade79, 0xe74ecd74, 0x833dfdc4, 0x69ad6076, 0xa247c529, + 0xa5f8c7c7, 0x5d79324f, 0xa3f73dbd, 0xbf3e501f, 0x637143a4, 0x637507a6, + 0xf1c52f15, 0xe7afb1ba, 0x2bad8f8c, 0x1d25f8c5, 0xe8db348f, 0x9297e23c, + 0x3fb2cc9b, 0x894777fc, 0xf724dbd6, 0x78ff7c04, 0xe66fe0cf, 0x53725e91, + 0xfe7cd167, 0xda4b3bee, 0xfcfe3e91, 0xfd6c770c, 0xf7c5dc79, 0xc2ac64b7, + 0xa8ef6ae2, 0x415a7fd4, 0x3d9e85e7, 0x5f7bbecc, 0xfb25597d, 0x20976fef, + 0x9e3a1717, 0x1d25ec7b, 0xf07bdde5, 0xfac94ab4, 0x6ad3cec2, 0x85f26bf4, + 0x458e58ab, 0xab6a79d8, 0xb78f754a, 0x946af7eb, 0x3e17a7f2, 0x3554e764, + 0x3e53e794, 0xd01c9cf6, 0xbac79ff0, 0x4f09515f, 0x8c126d0d, 0x57ed8fc8, + 0x41f93f58, 0xe36e3fa2, 0x69c0d4fe, 0x81a5c095, 0x55b70353, 0xd86cffc2, + 0x86971c91, 0x9e08da9f, 0xbe70a3ed, 0xabd6da47, 0xd23d0794, 0x137e3f1a, + 0x68d399d5, 0xa6e5c73c, 0x9bfdf1dd, 0x33a8f087, 0xefe89d3f, 0x1e04b24a, + 0xf098a18b, 0x1aa91838, 0x7fdc4667, 0x1c66ba7e, 0x7947b924, 0x2377c453, + 0xbe4cdebe, 0x2a6ba17d, 0x18ff45c5, 0xfe17d585, 0xc6a1ff31, 0x166665e2, + 0xf0e2cbc7, 0x569e981f, 0xa22c8f84, 0xaf8256f5, 0x32bce48e, 0x7ca0ea9c, + 0xdb944579, 0x25b0b2f1, 0x3f889010, 0x2b878b13, 0x708db821, 0xc2d87fd0, + 0x955f29cf, 0xc204de58, 0x72126dbf, 0xbce424df, 0xd1b1eb09, 0xa883ddf4, + 0xdd441bc7, 0x9ed279bd, 0x340254e3, 0x93bafe88, 0xe724ecc7, 0xcffdc065, + 0x3ff720b2, 0x788cfe86, 0x18f76892, 0xfd241ea9, 0x402d86d7, 0x172c33df, + 0x1b7967fe, 0x46e91ffa, 0x323fd03f, 0xef47e195, 0xc6277ce2, 0xf8ce86cf, + 0x78b20bf1, 0xf2283a3e, 0x712caae0, 0xb6f4203e, 0x4b520062, 0x9a65be71, + 0xb7b00eec, 0xfeb4cc7a, 0x4788a989, 0x5684ff9c, 0xa24be198, 0x8dfda34f, + 0x7a0defc8, 0xe18b9d15, 0x35a3a0f8, 0x7f7eb62d, 0xebd78b2b, 0x9d647335, + 0xef5310f4, 0x4fcb2aac, 0x377cef5a, 0x31bfc70b, 0xd3d3c366, 0xcf1deb63, + 0xe3c2229e, 0xbc7f73f7, 0xf157be82, 0xd2ff71b7, 0x66f38157, 0x2c0efe50, + 0x59b7f61f, 0xf8975402, 0x37544f11, 0x90bc212c, 0x3ba586bd, 0x2f582f09, + 0xaff3493c, 0xdc3b2ba6, 0xc610eaff, 0xf57e9c69, 0xfc303fa2, 0xf7cf1c9d, + 0x911b728d, 0xea307eac, 0x782f8686, 0x6f3c6a7e, 0xfd594730, 0x189610d0, + 0x5e8f3b7e, 0x7e47cbcf, 0x98ffbbfb, 0x50db1eb7, 0x9db38f16, 0xf48bc195, + 0xede7c91d, 0xe879a4d6, 0xb6971f90, 0x50697b31, 0x3f2c39a2, 0xe0f98439, + 0xde37ac6c, 0x1bd594fe, 0x0f6d479d, 0xcab43cb1, 0x35f1ce37, 0x66826a7a, + 0xc336cf96, 0x9e52d636, 0x6dff9b13, 0x52eff072, 0x48388a36, 0xeb8813f4, + 0xf6f6388d, 0x83fd1bb2, 0x05ea6fe1, 0xbe8337ae, 0xa3749e7d, 0x7617a89f, + 0x67ba5b53, 0x8968a53b, 0xb0bd5079, 0x59fccc27, 0x83cc4bdc, 0x6bc04ade, + 0x2c29dbd3, 0x293fedcf, 0x184ce83b, 0x51f3fbe5, 0x7e61ef94, 0x1ce4905f, + 0xcf8153f4, 0xd9ff715e, 0xf9332154, 0xd6f0e699, 0x8e509bc8, 0xa7fd370c, + 0x275402d3, 0xa57e1c94, 0xbb507080, 0xdac5c70f, 0xc7d1ea1f, 0xf00a0fbe, + 0x2a60a573, 0xfa31d3bb, 0x657e1ff7, 0xe9ade132, 0xb88b2fed, 0xa917ae7e, + 0xcfe73759, 0xd7892568, 0xd78926bf, 0xa8e65dbf, 0xff2eea9d, 0x881bd921, + 0xefa1abd1, 0xc08e040f, 0x8bfcebcc, 0x9ba31a59, 0xa61f1cc2, 0xfae2de6e, + 0x8f39f96b, 0xa1bfd6c2, 0xf37112bf, 0x880ef135, 0x5f80c42f, 0xf3f86019, + 0x7e31369f, 0x7307a7fc, 0x4ebee362, 0xff208ef3, 0xcc0754d7, 0xf902a49f, + 0x3a67f45d, 0xdfcbcbd5, 0xea7cb1b3, 0x15aec178, 0xc8157fcc, 0xb1ebfe40, + 0xc6266bb7, 0x598d8bc6, 0x254c3f32, 0x1652e439, 0x5f5f0cf3, 0xd619a1c8, + 0x8e027388, 0xb9338fe7, 0xeafac15f, 0x89cf64cf, 0xe6add5f5, 0x16dd4dc5, + 0xff6473a0, 0xcefb0b05, 0x4deef3e4, 0x2f877eac, 0xdfc9137c, 0x8d37cf80, + 0x6f0ec7da, 0x3fcf489a, 0x1a79bc3f, 0x9a94f73b, 0x4e99e2e3, 0xbe52e5fc, + 0xc3473674, 0xb3eefafe, 0xfab8bbec, 0x4ff1856e, 0xcb3c6c74, 0xefe7e6c8, + 0xec6c47fd, 0x0282437c, 0x1f18038e, 0xe75d6f37, 0xa8bf2ceb, 0x589ec90b, + 0x8def183c, 0xb171e6cb, 0x20e05b30, 0x9e987928, 0x175b783b, 0x53f1997a, + 0x1e9904ab, 0xde14da9b, 0xcc5bcedf, 0x3a1f193b, 0xbfe274b8, 0xf9bfce83, + 0xe73b08bd, 0x3ecc91c0, 0x07152706, 0x6bfd2276, 0x1d72847a, 0x3f80980c, + 0xe4fbb0b7, 0x19851396, 0x13c1fb84, 0x8b25672f, 0x3dd26f1b, 0x54e5420a, + 0x1243af3e, 0xf3652ffb, 0xe75387f3, 0xb53b3fb9, 0x993137c0, 0x92a1d35f, + 0x9092e9d7, 0x34b2a777, 0x45dc7dd9, 0x31bedf31, 0x4fda29fa, 0xdd8d876f, + 0xf93af5c7, 0x03c2ea79, 0x1499cd27, 0x99a53b7f, 0x276a4714, 0xbe88bbbd, + 0x9cba4003, 0xe46d5afc, 0xac77bb10, 0xec58eb6f, 0x4747c249, 0x32dfc736, + 0xe67df935, 0x3bff44b7, 0x7516cee0, 0xae132ed4, 0xc50acef7, 0x1de593b1, + 0xe891b49e, 0x7e12ef87, 0x0a95eef8, 0x01de53cb, 0x16f7e14d, 0x95617efc, + 0x0977b3f0, 0x22aabcff, 0x57be3fb9, 0x39fab3cc, 0x17ee9278, 0xc7e27b56, + 0xbdf22bdd, 0xf361e035, 0xa134bddf, 0xf77de45f, 0xc1f2137a, 0x8b87e16c, + 0x70fc88a0, 0xe903e310, 0xc6d8b1bd, 0x29f2ece2, 0x09e69213, 0xd2ffd1c7, + 0xc42703f7, 0xfe860477, 0x65df8a9b, 0x91d4ebf1, 0x99392ff3, 0x4141b6ff, + 0xe1b1fb92, 0xfdd865f8, 0xe2ef5c3d, 0xc1dea1be, 0x7ff43479, 0xd8a32b15, + 0xff432d73, 0x7f73674f, 0xb6cfbb59, 0xb0bef625, 0xa38ce83e, 0x5b91a1fd, + 0xfbf8c52e, 0x8c73815a, 0x73d8e601, 0xdf641790, 0xf4d9d9d3, 0xcb2f6b3d, + 0x2c0771af, 0xf2bee17e, 0x2cf2bec4, 0xeae97131, 0x7149f5c8, 0x973fbc3c, + 0x167ffdce, 0x5b148f6b, 0x07d5fd98, 0x6bdd00a5, 0x3db847d5, 0xb123dfd6, + 0xcea2c273, 0x857bec23, 0xb7248bb5, 0x33b1bb87, 0xa3819fc4, 0xcf1e5655, + 0xc90cbc0d, 0xfa88e04b, 0x25dfbe29, 0x9e227be2, 0x62cf4226, 0x8f3eff9a, + 0xecefa6e4, 0x75a38a6e, 0x30a75fd3, 0x211c3374, 0x9bf2152e, 0x24fa7889, + 0xf249d7db, 0xed71fac3, 0x54ff9c14, 0x8479c7f1, 0xd89b869f, 0x1d856fd1, + 0x4fd34bed, 0x3baffc51, 0x0fd5ee20, 0x24a28714, 0xf2c01397, 0xcf675ec0, + 0x1f9e46f6, 0xfaf57bb3, 0x0f7d8d88, 0x754e1f58, 0x6cee88db, 0x754c994a, + 0xa7765864, 0xf3a2bd22, 0xdfaa22f4, 0xeff39457, 0x01d41a3c, 0x3ab68796, + 0xbf89277d, 0xb8a6ee95, 0xcf8374fb, 0xd13de19b, 0xe1245dcf, 0xfcf5ff64, + 0x972145cf, 0x72d793c6, 0x9d7e1326, 0x5365dfbe, 0x45fd793c, 0xfcf6ae95, + 0x9c595f93, 0x8d38d1a9, 0x76d95b8d, 0xe31d1b64, 0xcf4ffc1a, 0x4efe3076, + 0x2c318129, 0xb5bd2cbf, 0x0e9a4bef, 0xf29531bd, 0x2723bee9, 0x3831aaa7, + 0x7f446def, 0x4d7f449d, 0x6bf61260, 0xad24ad66, 0xb70ef911, 0xb1f77f67, + 0xe85f3a1c, 0xa52e3b25, 0xe29dacf6, 0x3bc77d64, 0x779409f6, 0x98d6f174, + 0x66586aef, 0x2d1cc0e3, 0x963d37ba, 0x7f1927bf, 0x1e7c8357, 0xddd16880, + 0x5bfb6253, 0x40fdaffe, 0x03f30e7a, 0x603f38d1, 0x7bab09c8, 0x8799d59d, + 0x9e9eec2d, 0xbf625bee, 0xe1ce2acf, 0x1636697e, 0x73af643d, 0x90b99ee8, + 0x3c333352, 0x2219b440, 0x07dd1766, 0xddfe6447, 0xe7e618da, 0x67f58967, + 0xe847239b, 0xe239cdbb, 0xf42e727e, 0xc3b771b0, 0xe03d6b00, 0x095b5330, + 0x5856d66e, 0x6ca9cb23, 0x65060d2f, 0xc7247fd2, 0xe56cbcec, 0x4c90f2bf, + 0x3372c3df, 0x1e4365c3, 0xf163dd32, 0xf712ffef, 0xf1c39953, 0xfdc3db38, + 0xf416a50f, 0x040566dd, 0x6df9fdd9, 0xe8f71510, 0x0f31f7c9, 0x37ba37eb, + 0x99d30dbb, 0x008f2614, 0xf69f3f1b, 0x4fdb2723, 0x33533974, 0x7f10722c, + 0xf4c72452, 0xefadea55, 0xd8073fa3, 0x030df6bc, 0x0f978f7d, 0xc3ba3bdf, + 0xdf47bc6f, 0x0f1e4a99, 0x6dd50efb, 0x1d508b4d, 0x1de8da83, 0xe80563f2, + 0x56aa7337, 0xfe1ccce6, 0xc07c1f9e, 0xfc48cfbe, 0x7bb69f9e, 0xbbf86725, + 0xd27be32f, 0x9a35817d, 0x2eb1f109, 0x1196eacb, 0xbcd6651f, 0x657bec19, + 0xe1256fa7, 0x36d482ea, 0x0e624d81, 0xa87964cc, 0x782a55c0, 0x92ff682a, + 0x027df8c7, 0xc5d17860, 0x039eb7f9, 0x5238f7ec, 0x2bf7fc2d, 0xad0e2176, + 0x8d7e862e, 0x27858fbe, 0xef946a16, 0xdd5a776e, 0x8859cf94, 0x7e61d4df, + 0x3bfcac5b, 0x5e6b168a, 0xf1b8fc80, 0x3ca2585d, 0x3d16505b, 0x56dd0ecc, + 0xfc272f96, 0xc59b47fe, 0xcf922df7, 0x472bd3b7, 0xf25c1e50, 0x2cb9f9ab, + 0xcc79472f, 0xba61e437, 0x7028f7f1, 0xfda1dfff, 0x82fefe27, 0x04546fb1, + 0xc8438f03, 0x838390d3, 0xc77144f4, 0xf4327a83, 0x9f2c305c, 0x0e5c295d, + 0x52417d0a, 0xc8d5dec8, 0x6ff7135e, 0x01bfefec, 0x8f1a3ec3, 0x00003430 +}; + +static const u32 xsem_int_table_data_e1h[] = { + 0x00088b1f, 0x00000000, 0x277bff00, 0xa3f0c0cd, 0xa5fd811e, 0x79ba1818, + 0x8968c550, 0x30327137, 0x303170b0, 0x06710268, 0x2036ded0, 0x17c40edd, + 0x1022f880, 0x3033719b, 0x11710214, 0xf2032f10, 0x56dcd093, 0x50c0c4c1, + 0x4035c405, 0x3ac4075c, 0xba0c0c8c, 0x1fdbc48c, 0xf0c0c42f, 0xd7c10c42, + 0x48606710, 0xff9fa491, 0x54ee1b07, 0xc27dafa1, 0x860c0caa, 0x4662a8ba, + 0x5d637c68, 0xa09866fc, 0xf1a29bc9, 0x17e8f0cd, 0x87e540b4, 0xe3f2a219, + 0x7618198c, 0x3709a922, 0x7416efc4, 0xf7a802fc, 0x00031025, 0x22037beb, + 0x00000368 +}; + +static const u32 xsem_pram_data_e1h[] = { + 0x00088b1f, 0x00000000, 0x7de5ff00, 0xd5547c09, 0x73b9f8b9, 0xc999dee7, + 0xac84992c, 0x5d86f12c, 0x48409c04, 0x5876c443, 0x0622b4a4, 0x30a20a97, + 0x9037d96c, 0xff69f0fa, 0xa5ab0819, 0x68d06a1a, 0x68304ec1, 0x1a0741b0, + 0x01c04830, 0x6a2be2d4, 0x6d8ad3ec, 0x2c3480c5, 0x0dc46486, 0x3ff2d3de, + 0xcdce77df, 0x11337bdc, 0xbffbfb6c, 0x4f169fe5, 0xb7fb3dce, 0xe77cef9d, + 0x92cc5f3b, 0x407e1240, 0xa1f865c8, 0x211318e9, 0x5d245c64, 0x88fdfd6c, + 0xe5227d53, 0xacc8957f, 0x465a48e0, 0x46dbe42a, 0xb213be45, 0xb16feb12, + 0x589346b9, 0xc402d348, 0x93df3f45, 0x84592268, 0xf826e7dc, 0x9bce25b3, + 0x12126426, 0x6f7168de, 0x25dfa74d, 0xd02425c5, 0xb720fd74, 0x4a76805f, + 0xebc3e412, 0x9a56f725, 0x165f5f27, 0xcad9bda1, 0x27e813da, 0xf87c9089, + 0xd221107d, 0xe8f89145, 0x024ba4fc, 0x32245ba6, 0x4fce972f, 0x2646df72, + 0x73f3223a, 0x9392e427, 0x994efbf4, 0x52efd396, 0x37d5ae42, 0x2d7e5232, + 0xe4fe7011, 0x5fec4aeb, 0xfbb56f1d, 0xd717ab36, 0xdfb517eb, 0x5c17dcbb, + 0xcb757df0, 0x2d0fd8ed, 0xc39675c1, 0x9e5a14fc, 0xa6265270, 0x3811ff48, + 0x351c7005, 0x71d0b4af, 0xf08847bf, 0x84ed37ca, 0xb76abbae, 0x5c2858a4, + 0x4296ef26, 0xd2f9a03f, 0x7900213a, 0x211b01d3, 0x9b9d6e14, 0x94e43e59, + 0x7cff50bd, 0x2ed3cd3d, 0x8fad2dca, 0xdd7000dc, 0x38ad922d, 0xe609ae4c, + 0xadc2aedb, 0x6cf3e599, 0x775a5b2c, 0x2fb42e70, 0x1b10b668, 0x6f74afed, + 0x681b8cfe, 0x4488ff3e, 0xb6e94aa0, 0x9a5f7215, 0x41080c2f, 0x224d77c8, + 0x8f7fbe38, 0xeb46d818, 0x935ab977, 0x3c70a4ee, 0xca256957, 0x676f3a30, + 0x141dd26b, 0x9d81450e, 0x515da153, 0x1201e0a3, 0xdb7bbc9a, 0x5db4a9eb, + 0x63c176e9, 0x6e2970a1, 0x386513b0, 0xfa65c39b, 0x0c49bdaf, 0x2f9680fd, + 0xe924eba5, 0xa9ead780, 0x37f18444, 0x02338aca, 0xc39573a7, 0xe4896289, + 0x71d3b74b, 0x17b2bb68, 0xb12c0f04, 0x407c44cc, 0x6d7b9d97, 0xc0719eb3, + 0x43c856fa, 0xb5aeb09d, 0x0fcbd432, 0x5363dfcc, 0xf2757e60, 0xb45e5a54, + 0xd3ce4eb9, 0xe1b8bfe0, 0x3558a23a, 0x941daaf3, 0x630fa5ac, 0x89928e7a, + 0x84453e76, 0x200e8378, 0x533c8083, 0x857d17c3, 0x7177c438, 0x9feba883, + 0x44909242, 0xe8f7dffa, 0xfe5e14af, 0xab844efd, 0x9ca5b78a, 0x5dbc548e, + 0xcc43fce0, 0xff6d2ce1, 0xe008fa6a, 0xbaa7ce81, 0x2fe98dd2, 0xad30532b, + 0x3f1054a9, 0x68fc038f, 0xdbcf81ba, 0x344c8135, 0x5e5d71d3, 0x8b3606e2, + 0x289dee9f, 0x2e7c7cd1, 0xe3dd27cb, 0x596f9413, 0x2e3e9abf, 0x4f03e6f9, + 0xbd53226e, 0x979a54e6, 0x87884b7d, 0xd5be6f8e, 0x213c653b, 0xa3df12af, + 0xe4d17eb0, 0x12bc002b, 0xa5c94c12, 0x50235978, 0xb5e14239, 0xe1491616, + 0xd29526b0, 0xe3d3c533, 0x233d66f7, 0x09ad7c0a, 0xf67bcf90, 0xa7ec74e1, + 0x6991fb16, 0xdcae833f, 0x6cdcd24f, 0x73493f5d, 0xea7ed40b, 0xab989fb0, + 0xb9f1e7eb, 0xccf9fa39, 0x79fb522d, 0xae89ea1e, 0xd2575bab, 0xf9fa09bc, + 0x7ec12bcc, 0x10f1ef92, 0xaa2fad1f, 0xbd5a43f4, 0x34772d22, 0x98798dc6, + 0xd268e968, 0x49cfe81e, 0x474b4ab9, 0x3a31d9b1, 0xc6f38a7e, 0xa67df2eb, + 0x4fd5d5f5, 0x2ba81dcc, 0xc2359e4f, 0x770e9740, 0x0f3c75fb, 0x91597293, + 0x32bee5ef, 0x7d899dca, 0xfbff38ad, 0xee503afb, 0x1be39fdc, 0x86f3a6e6, + 0xff8a12b9, 0xf5df65fb, 0x437428ee, 0x149025d7, 0xa4131548, 0x12b5f2c6, + 0x7ea4db83, 0x413d0f5f, 0xc29b97db, 0xfe68e343, 0x8ff13088, 0x80bfeeb0, + 0x8b78a530, 0xd4054911, 0x9410b18b, 0xb3d36b7f, 0xe06bf19e, 0xa5006eba, + 0xefd22117, 0x0297c93a, 0xafe6d8f4, 0xae7d03f0, 0x60532019, 0x54827212, + 0x6983fc84, 0x297901fb, 0x4c8b7f00, 0x7c7687e5, 0x123f8e99, 0xf1876fc7, + 0xdf197a3b, 0x375b3032, 0x40ad35be, 0xa655be37, 0x08fe53e3, 0xf1f397fb, + 0x0872fc29, 0xc72c94f9, 0x05692df1, 0x995afe38, 0x8fc6e814, 0x4bff1ee9, + 0x186bf718, 0xfaca313f, 0xd7e8e607, 0x5fa4569f, 0x4fd6ccbf, 0xf8f9f856, + 0x417eb831, 0xa7f5b3f0, 0x5bf5b115, 0xe3ddbf58, 0x2fe1babb, 0x875c740b, + 0x07facbd0, 0xffafd04d, 0xfafd129a, 0xf77c6c2d, 0x7c7c758a, 0x271f8e07, + 0xbfeb63ac, 0x97c704a6, 0xd00f3e2d, 0xa62fdc91, 0x69fb0022, 0xc940ca7f, + 0x98bd0328, 0x84278f0e, 0x93df93ca, 0xfb870881, 0x7ddd1863, 0xcde94319, + 0x24a79111, 0xee903940, 0xa69c65c3, 0xca271b8b, 0xe3f67f6c, 0x4f98bebe, + 0x88b35175, 0x2c6a4d74, 0xbe742181, 0x1fa2cd9d, 0x6e6a8bf2, 0x9fb8880c, + 0x98823d32, 0xffbe0849, 0xada8d375, 0xd31975da, 0x7b52d5c5, 0xbaaf869b, + 0x3224fbe5, 0xafce82bc, 0x5c608802, 0xe54edf24, 0xf872a134, 0x90c79524, + 0x5e98969e, 0x71ca8a72, 0x37cb4c32, 0xe25e982b, 0xa70eef27, 0x9f09fff3, + 0xc199bb7f, 0x10997dbb, 0xb97ff800, 0xf20c8971, 0x9db5716c, 0x8f323d02, + 0xf0a78e72, 0xf5004b5e, 0x001dba29, 0x5642ee7c, 0x03c3e424, 0x502ebcb7, + 0xb6bf2d3d, 0x3dddae8f, 0x853ab024, 0x61b85fd6, 0x5d3700fe, 0x96599cff, + 0x4fec2231, 0x84cfdbc4, 0x99fa4c7c, 0xd59909b2, 0x47ea51b4, 0x92cd7733, + 0xda69b64e, 0xf3e9f6cf, 0xf9f40a73, 0x9920294e, 0x14299f40, 0xf7ed1d48, + 0xb97d0ade, 0x2134ce3a, 0x8f95e19e, 0x830a13f7, 0x5ee9fa54, 0x67c0c748, + 0xae75e237, 0xe755b59b, 0x44a0fe53, 0xb71fb842, 0x7fc41225, 0xb9f3d622, + 0xf38dbad9, 0xbd592b9d, 0x733e74b9, 0x9e11101f, 0x1db7f9c6, 0xa34d7bb0, + 0x99fb5a69, 0x5c682404, 0xf3fe718f, 0xe3d71b96, 0x987f6196, 0x677e37ef, + 0xa7a46274, 0x8f89e6f2, 0x53d0d29d, 0x8f47f069, 0x2bb4d29d, 0xcba9986e, + 0xeb660617, 0xced7e7ea, 0xae2f95d7, 0x2f95d42e, 0x9744b75c, 0x407fef9f, + 0xf2de7f57, 0x7bf2ba15, 0xcaebd62b, 0xd46c14e7, 0x9efb67e5, 0x6bbfd5d4, + 0x5cae9d56, 0x4d785038, 0xdf55ca1b, 0xb7a0a935, 0x4021607e, 0xabbd2a8f, + 0xea8670fc, 0xa39e902d, 0x2ba40b7a, 0xff294f80, 0xb4b2f69b, 0x6bfceb7c, + 0xfebd1adc, 0x069154b4, 0x7ba464fc, 0xf48d3c23, 0x45fa7f4d, 0xb4d487db, + 0x20b92044, 0x7ef8bae7, 0x5ebf7eae, 0x647a7130, 0x7e129de7, 0x95d9289e, + 0x3bce093a, 0x68687225, 0x7ef7a385, 0x75c05049, 0x13d2d010, 0x5a946f01, + 0x6e2b7035, 0x679ba418, 0xc71141c7, 0xa5de032f, 0xe4832ff2, 0x0f200b36, + 0x6ed38742, 0xf1f3051f, 0x4cf905ee, 0xff71139a, 0xf69ca8ed, 0xe00929d8, + 0x99e98b97, 0xb69859ca, 0x3d30fa57, 0xe9805955, 0x4c0acac9, 0x63972adb, + 0x8fd2bc7a, 0xd72a5fe9, 0xcaa7fa61, 0x558f4c6a, 0xc7fa62d6, 0x9da600ca, + 0x554c5e95, 0x9396edba, 0xe56f5cb9, 0x81fa0be7, 0x2d7cade9, 0x15bdfd22, + 0x0293d1f9, 0xf1c178fc, 0xcbd050e5, 0x48a31c2f, 0x5e1def4e, 0x15e87a46, + 0x7a8bc4ae, 0xe2805e45, 0x72cf4fb9, 0x93c30c5b, 0x11a644cd, 0x0fd6372a, + 0x60b3d679, 0x24cde624, 0x3c07da1e, 0xfa519d33, 0xe0147ba5, 0x22784aeb, + 0x3868f0de, 0xf53fb70f, 0xefd0599f, 0xb640c2f5, 0x71161e5f, 0x67a124bf, + 0xefaf803c, 0x95e1370a, 0x6f80d30f, 0xf0aa27ce, 0x34234d6b, 0xb1b8225d, + 0x164d0bff, 0xb6380662, 0x847003d8, 0x19e470bd, 0x4b77ec17, 0x53eac453, + 0x57877b63, 0xdabd3069, 0x794f59a1, 0xa17f3eb3, 0xcec6985a, 0x1dec4af9, + 0xdcae80a3, 0x0086a7d5, 0x553053fe, 0x229a59fb, 0xb9ea38e3, 0x21c63496, + 0x2173d29d, 0xcf67fbd6, 0x227eb7a3, 0x1f2268f3, 0xbb01d853, 0xe5741e5c, + 0x7c0f4bf3, 0x73973f9b, 0xd22d4f01, 0xc79fb097, 0x07977fd0, 0xcc66bf42, + 0x0796fdab, 0x7ae5bf45, 0x1ba8def8, 0xd453b68f, 0xebb43733, 0xa4cd5e9d, + 0x15275d5d, 0xdedc196d, 0xab60dc52, 0x38fdcbd6, 0x39bcbe5d, 0x0fb75ab5, + 0xef942fc0, 0x06608149, 0x54e129ba, 0xac7665d4, 0x1cfce813, 0x2dfb0526, + 0x52bd5817, 0x53ec9b6b, 0x415b0c90, 0xad90580f, 0xd7729dd2, 0x3e5ca99f, + 0x3c897bfb, 0xeedce50c, 0x2547f6a2, 0xfcd13130, 0xd05b9e42, 0xe41d3c54, + 0x373dd9dd, 0x88b0fea3, 0x10e0bae4, 0xb3aa4053, 0x4f390f40, 0xee80d34c, + 0xb83f93cf, 0x03ce6ac6, 0xce324c73, 0xfd3ae167, 0x27f5483e, 0x56bf3e5d, + 0xb723cf9f, 0xe79d0125, 0x202448d5, 0xcbea3f00, 0x7e31366f, 0x6b1527c8, + 0xc5587f60, 0xdc0b13cf, 0xf28fdcc4, 0x5b4be97b, 0x79d3e6b2, 0xf931302c, + 0x0bdf9ead, 0x511e99e3, 0xc193ac14, 0xd371f39e, 0x40dc9fd8, 0x0d607da0, + 0xbbfc31d8, 0xa536cf05, 0xebbefe27, 0x55f38dfc, 0x761e8ff7, 0xd28f3e04, + 0x881bc106, 0x98548fb2, 0xf8ffbe04, 0xeb097e99, 0x1b99e8d6, 0x435af90c, + 0xff90debe, 0x812de9bb, 0x61cde8e8, 0x25306df2, 0xfd02fa32, 0x6587304a, + 0x7fd23fdf, 0x6bfe8f4a, 0xf7fda9ff, 0xe967fda7, 0xa7ffaffa, 0xc7b83ff6, + 0xfad183fc, 0xc7697d2f, 0x37953f1e, 0x726e2f45, 0x9cffba11, 0x79275735, + 0xb64bfe28, 0xe2fb46ad, 0x05dfb319, 0x20367cf4, 0x39440b4e, 0x71369f57, + 0x3af125bb, 0xc0f73804, 0x73ffb4af, 0x067cffcf, 0xdcbe5b9c, 0x3cf1b926, + 0x590960d3, 0x35969f28, 0xa3274e15, 0xe5827f31, 0x422a7ed7, 0x9f4f59be, + 0x4a6dcf45, 0xa51bfb02, 0x87efae14, 0xab2a5f50, 0xd854ebff, 0x1849ca7f, + 0x0ed8ccf9, 0x8f18bfc6, 0x1cbe71f2, 0xce9cb3db, 0x72f0f513, 0xa6f2970e, + 0xba2a7f9f, 0x69d1fd20, 0x369317b4, 0xed8d93d4, 0x73feb80a, 0x684ce4cc, + 0xf91eaaa7, 0xc81ef91e, 0x242e154d, 0xf11ff4c0, 0xe1a32da5, 0xff51dafc, + 0x81a0977b, 0x176fca97, 0xfd7f0b82, 0x5cbbd2b2, 0xb1e7e4ee, 0xb600bb48, + 0xdeb99a53, 0x12d2c2d6, 0x7b02e429, 0xe49d4969, 0x25cfd3f1, 0xf6799e3b, + 0x7e4f3829, 0xa10cf160, 0x78ef17fd, 0x34398fed, 0x4a53bc5f, 0x4049ce98, + 0xa7e08a48, 0x3e5bfe9c, 0xa28f8226, 0x2b26bedf, 0x87f7d8a3, 0x297823e2, + 0x265079de, 0x63c27aa3, 0xdca0f072, 0x9f8288e6, 0xa0a989e0, 0x7d2f895f, + 0xcffe0323, 0x7248101e, 0xd678147a, 0x027a86bd, 0xc9f109c0, 0x3f8dd5f1, + 0x8a72fd43, 0x46eb9017, 0xedeb197c, 0xfa05f2e5, 0xa521fb05, 0x065e17ef, + 0x2c9ff33b, 0xc143801e, 0x60b9f70b, 0x15cda73d, 0xacb7ce8c, 0xf1d2f24e, + 0x927f240b, 0xbdf6531b, 0x229fe9e0, 0xf3bfe5fd, 0x7e7624d3, 0x709aa6f3, + 0xc2a7f2af, 0xbe6f173a, 0x4799d713, 0x0587487c, 0x905cc45b, 0xc9985f97, + 0xf8519db4, 0xe4c89e64, 0x14ade9e6, 0xa79d74b9, 0x768436e9, 0x81883fd7, + 0x58bf686d, 0xfc1e4042, 0x9397b554, 0xc2ff98a5, 0x4e35f0ca, 0xaa7ef554, + 0xb7e969f5, 0xe02b6d7e, 0x6f00dce9, 0xcabdd832, 0xe1cfd989, 0xfda65c21, + 0x94dcef8a, 0x1444f0cc, 0x476f1673, 0xf0c982f5, 0x4ab7ea1d, 0x5d68db5e, + 0x3d39723b, 0x3e32fe32, 0x0c779d3e, 0x93a7e7ec, 0xca304148, 0xaa8836fa, + 0xbafba01c, 0xfc34ce86, 0x7ebff8ce, 0x9577e33d, 0xa73303ff, 0xefe7f941, + 0x76823e32, 0x79d25fb0, 0xfcb19285, 0xca021de0, 0x45090b07, 0x897af3e3, + 0xdcbeb9f3, 0xfe742f48, 0x43562166, 0x3c4e3037, 0x5eed01e2, 0xbdb43579, + 0xb8c2ae56, 0xaafd9eae, 0xe5cf9c7c, 0x9522ddc1, 0xe445d707, 0xe4ccd901, + 0x977aef40, 0x2258f11f, 0x0a7d9e05, 0xabf297f8, 0x95fe015f, 0x9ffd6172, + 0xe3fe1e34, 0x3e6f94dd, 0xab7caa09, 0xbe46ab97, 0x2e35d82d, 0xb27edf2a, + 0xdf3a2321, 0xf951efd2, 0xdbe30376, 0x5572d7ff, 0xa8956385, 0x9caaab97, + 0x469e0dec, 0x2a269939, 0x9ca35708, 0x92ef3fa4, 0xa8f49eac, 0x7f4aa1d2, + 0xbd29bf45, 0x3751e406, 0xd874aa9d, 0x1d2aa74d, 0xe89fb0f6, 0xbf2c68e0, + 0xd2826819, 0xf7deee4b, 0x78a3f6a6, 0xf761692d, 0xebddb450, 0xf2f0a790, + 0xaa4736e2, 0xa097ef5f, 0xf90c07cd, 0xd7bea1a0, 0xd435cf90, 0x15f219f7, + 0x6601fa86, 0x2c3e683f, 0x9087a413, 0x92b4beae, 0xb7609df8, 0xdda22fdb, + 0x79ce8bae, 0xd5df6d0d, 0x53f01e98, 0xc6dab0f9, 0x44e18fce, 0xb3c80d79, + 0x15d8772e, 0xd31b790f, 0xc372bb7b, 0xfe8d38ae, 0x4445a278, 0x2016dc79, + 0x8cf6b4d3, 0x21545f08, 0x6f48dafe, 0xd90ecce5, 0x77eec315, 0x691d126f, + 0x59dce1cb, 0x19287a2d, 0xee2b4590, 0xba898172, 0xadd065ab, 0xc5f7e8b3, + 0x5aec886f, 0xa735efc4, 0x670dce6a, 0x09f1ff88, 0x6d97dc02, 0x6c2ffc40, + 0x4588e761, 0x73d3a21b, 0xe7976f11, 0xdc832658, 0x49fffaa4, 0xed559dad, + 0xe1b360a7, 0x9ccdcb7b, 0x3cf1abee, 0x2faf5457, 0xd0f3f1f7, 0x647e5549, + 0x1f940c90, 0xf381d070, 0x37bb9738, 0x9d6f2389, 0x75d0f145, 0x37402444, + 0xc4445a17, 0x764685c3, 0x89fc495f, 0x24653fc8, 0x854ef28c, 0xc7f00757, + 0x50e5deb0, 0xb30feec7, 0x4a55a41e, 0xf479fcf6, 0xb1da68af, 0xfba183e7, + 0xfbd2ff20, 0x3d267f69, 0x603e4feb, 0xd76e3b43, 0xbbde2701, 0x337fed74, + 0xefc841ed, 0xbef078b5, 0xa357c0f9, 0x56ba8e81, 0x8e400a5a, 0xf7600d75, + 0xbffb55f4, 0xfb86dd1a, 0x9fc42ae7, 0x5fceccd3, 0xf3fe5a17, 0x5fb3dc38, + 0x02aba168, 0x1d80e0fd, 0x2fe5e1ed, 0xd08ed0db, 0x2cabffb5, 0xb79fe39f, + 0xbf7e329e, 0xb324e5d2, 0xe2fcc176, 0x7cba5d98, 0x5667f8df, 0xd373fdc0, + 0x2d217941, 0x37cafc9f, 0x763e41a3, 0x4f7a62ed, 0x34f6d4a7, 0xaca41fdc, + 0xa242b4ba, 0xe604ee70, 0xf94f4be8, 0xf92672ab, 0xcb834647, 0xb91f6837, + 0xff5c785a, 0x021e063f, 0xb49623de, 0x01560338, 0xf8e97dd6, 0x1c1e419f, + 0xaa5d20b0, 0xb824fdeb, 0x2b91f502, 0xac067bad, 0xd37ff13b, 0xd5d085ba, + 0xbff4bbac, 0xe33fbe39, 0x0f91a8fb, 0xfef9d27a, 0xc3bf31fb, 0x5ef9c1e9, + 0xe2ffbd25, 0x77de1b7f, 0xaebbbc51, 0xffc6eebc, 0x1deeebe6, 0xe5cc6fef, + 0xfdc37778, 0xdf2bf97b, 0xabbefce0, 0x3ffa3b9c, 0xbeaafd74, 0xf2933bfe, + 0x3fad066e, 0x403b548d, 0xe951f8b1, 0x683237a1, 0x1ffaefe9, 0x4ef9838e, + 0xc635f7e2, 0x66637df9, 0x7049bee7, 0x25c7436f, 0xef3f0271, 0x3f5273b1, + 0x5bf45fae, 0x487a8796, 0x40bffebf, 0x9598827d, 0xfc0fb81a, 0x0f42da5d, + 0x319036fa, 0x77907cc7, 0xfaf3c8df, 0x04afe2f3, 0xcaab85e2, 0x1f37697e, + 0x7fb53d01, 0x58f5117f, 0xfafea29a, 0xfb1a6baa, 0xceeb225e, 0xf4523f33, + 0x09a99be7, 0x14d073fa, 0x844ddfde, 0x8726ffcd, 0x38500810, 0x58f01a4c, + 0x2743d802, 0x4088910d, 0x6f8953f3, 0xa61b9c15, 0x7dfdf438, 0xe3c4f700, + 0xb7cc7022, 0x7f022dee, 0xc047ab3e, 0x987586fe, 0x33589e50, 0xe183a405, + 0xbfcc66b5, 0x038f7263, 0xe1b8cf38, 0x201e4fa5, 0xcaf55760, 0x65cba14c, + 0x2faff1f6, 0x05909e5f, 0x03f66fe7, 0x50b778fe, 0x66d17d7d, 0xeba18a12, + 0xfe266c5d, 0x8bb078d8, 0xcea4e40a, 0xc3cfaa2e, 0x2293f7cf, 0x7ea95cfd, + 0xcff8746f, 0x74a25f4e, 0x2108727f, 0xfbc5217b, 0x53cf662e, 0x6bdf57cf, + 0x3f2af061, 0xd903024a, 0xab98b8bd, 0x2c5a3fb9, 0xe97bba31, 0xc2c6bb2f, + 0xd76266b9, 0x8fc658c8, 0x904fcc99, 0x881797eb, 0x0071eb12, 0xc58a0e3f, + 0xa223b17b, 0xd9df9a33, 0xfade7e76, 0xd297dc0d, 0x549eabb4, 0x93f7a08b, + 0xfcf9da30, 0x2db256f5, 0xae427f8a, 0x382ddaa4, 0x988fe8de, 0x367af605, + 0x34da62fe, 0x8eb78b56, 0xa3cd67e9, 0x7e01e27b, 0x2bee6a4e, 0xc2f851fe, + 0xbbe00ef9, 0x3536d6dd, 0x2edf0a37, 0x633d9890, 0x784ba1c6, 0x52d11ebe, + 0x1f3e0267, 0xddd26f51, 0x712dddbb, 0x190c7dfd, 0x719af303, 0x04cce6c8, + 0x3d111cbc, 0xde57efe0, 0x8beca9f2, 0x84646f72, 0xf60ff427, 0x8dc95ad6, + 0x8293eee3, 0xfbae010b, 0x9c095bce, 0xd5caf6b7, 0xe9e6d1c5, 0x2e79b0b0, + 0x46fbc126, 0x83f7ffa7, 0x472ec4ef, 0x579c1268, 0x75f209ea, 0x4823fa4f, + 0x481a17c7, 0x9c31e400, 0x5c2e406f, 0x1fb82468, 0x02fc9050, 0xdf946bce, + 0xc73da07f, 0xf9de6b0f, 0xca47d81b, 0x9837045a, 0x6dcccba0, 0xcaedd832, + 0x9044e39b, 0xea8a19db, 0x751ee90f, 0x6a2f8687, 0xebc23325, 0x39bece70, + 0x1d67ee30, 0xcd7d8132, 0x05d86afb, 0x96b3ff72, 0xbd07c8b1, 0x95b7ebad, + 0x048a68a4, 0x6ba410fd, 0x6c8c3d23, 0x6fe5d18c, 0x817d7d10, 0xda5866bf, + 0xe0a27996, 0x7c66472f, 0x2df2d57a, 0x7c99fff0, 0x6f95577b, 0xc357313e, + 0xd1992647, 0x25be46bd, 0x4b6f9347, 0xe0192505, 0xa0ff74be, 0xd2ebc064, + 0x68c4a437, 0x25476df2, 0x917b07bb, 0x3576b1fb, 0xbd76f951, 0x5135be46, + 0x4fc516f9, 0xf13243a0, 0xf20aedfd, 0xc35ff02d, 0xbe403b7f, 0xbe67a345, + 0x6df2a83f, 0x9409cb74, 0x4c9ba36f, 0x2fccff3a, 0x84df28af, 0x9f403bc4, + 0xec79223a, 0x0767e851, 0xe45edfd7, 0x0e30367e, 0xb271b9c8, 0x5abfc71b, + 0xb5729739, 0x08bfee72, 0x5b9caace, 0x9fa09bba, 0x643a4f6a, 0x5ee96e72, + 0xa004e72a, 0x96e72647, 0x8ecc27ee, 0xc36f9063, 0x8237c87b, 0xac42cbf5, + 0xfa73797d, 0xfed0f713, 0x8f2578c6, 0x131fd695, 0xb4e37791, 0x6c9c6ef2, + 0x90f73846, 0x4eae4777, 0xf2e6edde, 0x81b1ca8e, 0xf48d5f20, 0xfbd169e1, + 0x7f1beeff, 0xc0b7f1ba, 0x788a6f2f, 0x898ef50f, 0x35bc17dd, 0xd02674fe, + 0xc99906d7, 0x7b971f5f, 0xec7e959d, 0x6cabf27f, 0xec8da57d, 0x1359413d, + 0xeacb0fd3, 0x7f4280c5, 0x09739a9d, 0xf70a93ef, 0xe699240b, 0x1faa5a67, + 0xfd3e8077, 0x3eb8449c, 0x43433d3d, 0x8bb28b0f, 0x655bced1, 0x94256d73, + 0x8999178f, 0xc5b9ec15, 0x4167a98e, 0x66ce2d9f, 0xfe62dff6, 0x544bf55d, + 0xf78d33fd, 0x4bcd79e9, 0x7a47ef5e, 0xb0cfabde, 0x78cebc30, 0x1f800846, + 0xf67bcf61, 0xe285ca00, 0x15f7fd06, 0xc533fd7c, 0x79178436, 0x8b6cf45b, + 0x8c2b3fc2, 0xe1c23a70, 0x83a2e144, 0x0a884053, 0xe9e98a27, 0xb8114919, + 0xb6d9be14, 0x85c0ec06, 0x6f780a4f, 0x0ab75c68, 0x55fae337, 0xd176aa38, + 0x7e5fde62, 0x33be1d4b, 0x8545c231, 0xdd1e11b3, 0xa3c03770, 0xfff6e64a, + 0xfc16320c, 0xa0dd2858, 0x9bfff19c, 0xb90ffe88, 0xdee88713, 0xf2e7ac43, + 0xc4f56c7f, 0x3ddd70c9, 0xe182fc13, 0xc976ae3e, 0x37dfe0eb, 0x063298ee, + 0x721bd3b6, 0x97b83e2c, 0xa30b6edb, 0xf0e9541c, 0xcd874e23, 0xfafbbe1c, + 0x73c24c56, 0x06e0b361, 0x643ca43d, 0x5396b843, 0x2ad1b47a, 0x72fc9f87, + 0x1bab872a, 0xf334bbdf, 0xc1e289fd, 0x751fe704, 0xf7b00abf, 0x185b6331, + 0x181bca5e, 0x1849325e, 0xb565efed, 0xd7442782, 0x04bcd653, 0xf95582fd, + 0x5a1c7f4c, 0x5fa1453c, 0x25fa3473, 0x8acc9c60, 0xbcc59bec, 0xf54b0cde, + 0x3f9ec11f, 0x1d47f283, 0xdffd2192, 0x95f7d0b7, 0xf88c45fc, 0x6dc390fa, + 0x01d5c007, 0xfd330bf0, 0xdf09742b, 0xe5e5a8cd, 0xae0ebf66, 0xc8ba9f93, + 0xa0bf6fe8, 0x1ba51d80, 0xb4cf406e, 0x370a9c7c, 0x43c067a0, 0xf2117ccb, + 0x7dde1479, 0x17ae7bd2, 0x7cb4c7ee, 0x04ffb85f, 0xe08b7feb, 0xfdd65121, + 0x3bfbe99d, 0xfc6f75d2, 0xbe8191fe, 0x8f85b2df, 0xdefa058e, 0x93df202f, + 0x3dfd3896, 0x4dcecc97, 0x0f946ddb, 0x0de61ee0, 0xe955b3c9, 0x1cc21f29, + 0x509e70ce, 0x6b927634, 0x57e02161, 0xff4560d8, 0x40c79c30, 0xe56aafa6, + 0x491b0ef5, 0xf7b323bc, 0xf9c6fffe, 0x497d37ac, 0xf1828fcd, 0xd3368e40, + 0xc64786f1, 0xaa17ee33, 0xeb4ae01d, 0xb1fe5bb2, 0x7ce3a975, 0x7299ff57, + 0x28f78ad2, 0xc38d1faa, 0xe0942be4, 0x304d3afc, 0xc2d1fdeb, 0x70ffcf1c, + 0x2dfcb2ff, 0xab1493fd, 0x4de2fdee, 0x29f883a2, 0x4af33edc, 0xcb542fc8, + 0xec026f78, 0x3ee8931f, 0x8ecf9348, 0x1eff7b8e, 0x5ef1172c, 0xfb37d6e6, + 0xd5bdc294, 0x8a67ccad, 0xa0219adc, 0x740ef0fe, 0x70f41e36, 0xf85af12b, + 0xfb3cb490, 0x7801717b, 0x5f519067, 0x7ca1593d, 0x5021a63d, 0x7267a905, + 0xc02de138, 0x009144d7, 0x7dbd5abe, 0x7bfec326, 0x06495fdf, 0x9ea8ce98, + 0x398cfd80, 0x5ea11242, 0x8f11378e, 0x3e9be333, 0x3a76f77f, 0x4547f1bf, + 0xcdeb428f, 0x0070ec3c, 0x6cdf0d9f, 0x5c0d3e22, 0x0aa04872, 0x4fe347ec, + 0x79076f79, 0x1ef54050, 0x682ff7f0, 0x4172aba9, 0xed80b37e, 0xa9befdcb, + 0x1dbf3a2e, 0xbd4e9fb5, 0xad02e40e, 0x6f94dd07, 0xebcaf566, 0xb2b80f05, + 0x946cb5e6, 0x0bd46e51, 0x476ca0f8, 0xd6562040, 0xfb4ac06f, 0xb699b1dd, + 0x8bfd84cf, 0xeb7e87b6, 0x76f77d3f, 0x9e743b90, 0xdd91bed8, 0x76d1e6cf, + 0xfd49f00a, 0x70afec12, 0x5de040b3, 0xdb234142, 0x4a8e0a9f, 0x3a6f281e, + 0xbbee24f8, 0xa978e9d3, 0x851fb0e9, 0x8efbe0a6, 0xdf1b82b1, 0x43494dd5, + 0x0b05d5b9, 0x01d60686, 0xe05cbeec, 0x51fe7e79, 0x2d37bff5, 0xcf377fcc, + 0x43ee42b3, 0x3b2b79fb, 0xf484dd31, 0xfa0ca9f4, 0x6f0a29da, 0x3bf7851f, + 0x70e17fdc, 0x9b72c7f6, 0x673c7f66, 0xbff48419, 0xfa2279a8, 0xb9262d4b, + 0x633faf78, 0xdf3bd33c, 0x0016d1be, 0x52dbddbb, 0x3f7c3fb8, 0xbf05a37c, + 0x7260ee77, 0x1b4073b8, 0x6f4f69da, 0x47bc0896, 0xa22cdaa8, 0x28dd389c, + 0xb8b5fde1, 0x9db94245, 0x21e983bf, 0x7eb33787, 0xfd30374f, 0x3b96f26d, + 0x9c3ec2a7, 0xefbd4dbf, 0x3d5a7266, 0x0bb9e687, 0x519bfb75, 0xb872aace, + 0xa0a3c394, 0x5fef0eba, 0x54b7728d, 0xf20d0fdd, 0x65ee14b6, 0x8435fef1, + 0x341a547c, 0x983913fa, 0x0d73863c, 0x12e843d0, 0x51d977d2, 0x46b9c089, + 0x2a63b8f8, 0xec2ce7ac, 0x7c7cb4f7, 0xfb85e08b, 0x966382f0, 0x81e3ea00, + 0x15fef3f9, 0x2c0f99f6, 0xbfc05044, 0xca83e29d, 0xf84b6ca9, 0xefd18f2f, + 0x82b1df67, 0x9fa508a7, 0xd57f08f9, 0x1b73342f, 0x7cc8f3f3, 0xde0926a7, + 0x7d29927f, 0xd7e40e50, 0x91a7c48a, 0xef05671b, 0xfdb377ed, 0xfff5adc1, + 0xf3ab94cc, 0x6fed9f60, 0xd951f265, 0xddfbe126, 0x447cfcc3, 0xb7e80bcf, + 0x6377b859, 0x87a1ac92, 0x931bfdc2, 0x6b20e8a8, 0x15447fb8, 0x285bf77f, + 0x0f0a71b3, 0xcd3aee08, 0x6a3f6a38, 0xd65ef2bf, 0x967ed06e, 0x217fd6f6, + 0xf9d70fcc, 0xc3720c85, 0xf18f4fd8, 0xfb27e97b, 0xc0d62fdf, 0xb7eced3b, + 0xce6e7445, 0x20fa78fe, 0x9a80bded, 0x590c7eaa, 0x57889aef, 0xbfecbf03, + 0x06af10c4, 0x28e34ddf, 0xddfc53ff, 0xb9f4ccd2, 0xe42771a6, 0xbbcc4cd2, + 0xb8cbdf81, 0x0a6cba3d, 0xca69efbb, 0xf0156778, 0x014cf4ff, 0x7df881e9, + 0xd4049f72, 0x4ff014df, 0xed64cfce, 0xe07b69f3, 0x1927a6cb, 0xa179529f, + 0xdb293c80, 0xd62a71bc, 0xe81417af, 0x3e6ea9bf, 0xd90525ea, 0xfaf2c122, + 0x1527a813, 0x00489f34, 0x5bfca67e, 0xd940fa03, 0xc41b8b04, 0x2a97cab1, + 0xfdcdbf9f, 0x3dd58989, 0xcbf8fc0a, 0xf0a2a980, 0x709478b7, 0x65f195bd, + 0xdbe33679, 0xb04877b7, 0x73e1abc2, 0x8f956be4, 0xcce3e045, 0xde1f1f08, + 0xbe06593c, 0xd0101d3e, 0xc83262ef, 0xedf3e001, 0x31efb702, 0xf96af63d, + 0x667a4afc, 0xd85fe529, 0x573e552f, 0xcfc8daf9, 0x3bb6e6ad, 0xddf71e60, + 0x4c75c368, 0x3fdefefe, 0x15e4c7de, 0xfe4dd7de, 0x204903fe, 0xccccf31f, + 0x6b8547af, 0x81f999a9, 0xcd5798f5, 0x6af5390a, 0xc79867e6, 0x5ede8b46, + 0xc712d872, 0x25eb9dfc, 0xf12bfba4, 0xbb3e0f67, 0x5abcfe4a, 0x7f12babe, + 0xfb8be3aa, 0x061cfdf5, 0xd9eb8e20, 0x6385275f, 0x77f1c288, 0x5fa0cf8d, + 0x4fe7f9d9, 0x143c00cc, 0x0e74a3ef, 0x24e8d5f4, 0xe6739021, 0x455bee00, + 0xfd17a24d, 0xaca1cd65, 0x3e5a9ddb, 0xc53ffe66, 0x9e913a2f, 0x0259768a, + 0xa2fb69d3, 0x468f1f3d, 0x61958c3f, 0x3ff24ff4, 0x7f65f5cf, 0x83e068db, + 0x43f33322, 0x9985ca32, 0x773fa656, 0x82cfb5ec, 0x2c0d09f5, 0xf05140de, + 0xb9a2c92e, 0x956698a7, 0x2f787ad4, 0x0c74a7e8, 0x7e6131ef, 0xaaee77da, + 0x76c751ff, 0x9a8a2726, 0x2dc400a5, 0xd9d86a28, 0x45a5fe09, 0xff682cc7, + 0x14f86f2a, 0xbf27e7fd, 0x2bed03b8, 0xeea2cde5, 0x3f87ad3e, 0xb218835f, + 0x535a1f80, 0xd1ffde29, 0x07cc09fc, 0x77dcffb9, 0x7e2b37f4, 0x3f1eff71, + 0x6ff16105, 0x7c81739f, 0xcdbad739, 0x0d7d7e85, 0xdb5feedf, 0xb82f7fc3, + 0xddeffb9e, 0xb9e09a72, 0xdeffba26, 0x3285f839, 0xbd5683ca, 0xe8691eff, + 0x9d25fa83, 0x946e5667, 0xfd6e8ffb, 0x4f17c77c, 0xc779ff83, 0x869e4fae, + 0xedfc9779, 0xafc1a7b3, 0xe1b01c88, 0xfcfe57be, 0xabafe87b, 0x6564dbb6, + 0xfdb9da74, 0xee77f439, 0x81e2c0fc, 0x9ff73ade, 0xb2ff034e, 0x92979dce, + 0x6cb99ec0, 0xef684dff, 0x727bb65d, 0x6fb28932, 0x6fd029a8, 0xadfc2ae0, + 0xdc3b788d, 0x9ffd1874, 0x83bc53ce, 0xcbf6ec1c, 0x7f32960c, 0x63fb8557, + 0x6ff74636, 0xd97fe1ef, 0x37adfb74, 0x626ffc82, 0xfd15e4fa, 0xf8a5df30, + 0xf02afebc, 0x6dfdc8d8, 0xab7cb783, 0xf879e61f, 0xc9abe285, 0x9a2fc780, + 0x29faff16, 0xd3ea6b28, 0xe8661fab, 0xfaa7e02a, 0xdeadfbcf, 0x6fc0ac57, + 0xfe837ebb, 0xe9bf80af, 0x5f47ec0a, 0x83fbc1a4, 0x2e785233, 0xfde13fec, + 0x52bf8c16, 0xe47dffb4, 0xefddcea7, 0x709a9da0, 0xd24ef63f, 0x8dfcc3fd, + 0x7adebe05, 0xe4dff327, 0x4eff0078, 0xb9df85c5, 0x6ba3271f, 0x37b3bfd5, + 0xacafcebf, 0xfd56ff4c, 0xffeb4bfa, 0x2324fdcc, 0x01b21378, 0xf5be275f, + 0x070a823d, 0x11cb9737, 0x7ee8e5bf, 0xcb7eddb4, 0x3e01bc06, 0xf6ea9f61, + 0xfef9a64b, 0xf24ed063, 0xf83f347e, 0xefe63ace, 0xdfe929dc, 0xc4f0468f, + 0x0d5823df, 0xab81cbfe, 0xd2be5ff3, 0x9c2bbe3a, 0x3452824e, 0x3abc27ae, + 0xdf2e8ebe, 0x3fc26d13, 0x916d5ef6, 0x931f7c60, 0x7f044b60, 0xcf681390, + 0xf37f3eec, 0xfb7076f5, 0x22f3c77b, 0x09aebffa, 0x6ef9461e, 0x10651f94, + 0x7cca2347, 0xbe98d987, 0xf6ccd65e, 0xce5d8e8f, 0xd3f68380, 0xd22f6871, + 0x09e35975, 0x7bfb4fd9, 0x32b7e1bd, 0x7c62c7bb, 0x4047fb04, 0x178e9eb3, + 0x7e668e0e, 0x6fdeccda, 0x1f1c671c, 0xfa25bca7, 0x9f8de538, 0xf629c6ea, + 0xe3b76507, 0x339de3ca, 0xfe82ef7b, 0x3d32b5ce, 0x9c505cf1, 0x587ded16, + 0xf7e24d8a, 0xa52cd561, 0x25c628fb, 0x2438b271, 0xf5062ba2, 0xecce65ce, + 0x9009b163, 0x5407e8ca, 0x0dfb82b5, 0x0293ccfd, 0xfe72aef8, 0x577cc098, + 0xf6357c03, 0x23edc91f, 0x294aafa0, 0x776099b9, 0x391dca30, 0x1a0244c1, + 0x4e732f7c, 0x5ef0564b, 0xf01fd424, 0xb4e33c79, 0x647efd04, 0x647d5fb0, + 0xe9926b26, 0x0bf23efc, 0x5fb4159e, 0x03c7f5f2, 0xfb3d9d72, 0x87bef357, + 0xa9bd9d44, 0x0e3e12cc, 0x8af215e7, 0xc423ef0d, 0xe78c3603, 0x0db4fe50, + 0xf7787bd7, 0xdea2cf57, 0x610b6bfd, 0x54f443f7, 0xdca47103, 0xbbd38fac, + 0x3ffa7abf, 0xc686af41, 0xa7fcfc74, 0x4f387d69, 0xfcf1da34, 0x762bb5d3, + 0xafcfea34, 0xe403383c, 0xd19dbe5a, 0xc98bfe63, 0x5fda2a81, 0xb7cb227b, + 0xf18018ef, 0x39778a03, 0xf0f11fd1, 0x60ca97ee, 0xd17cea9f, 0xa4066e0e, + 0xffae15f3, 0x3bc786ff, 0xad1495aa, 0x3121725f, 0x2077da2b, 0xe56790c5, + 0x7f049ef8, 0x811f38b2, 0x1639ab1d, 0xbd508fdf, 0x79cfd758, 0x07bf7c29, + 0x97dfd8e9, 0xf5099bbd, 0xac607905, 0x1fff96a7, 0xe5b7931b, 0x11ceda16, + 0x872e5fa9, 0xbabe58f3, 0xad27932f, 0x2ae7ff58, 0x9ef2f39d, 0xebfab2fd, + 0xf575036d, 0x3c65f6d4, 0x7e9188de, 0x16fde71f, 0x2c337c37, 0x288d3c5a, + 0x3fefc7f3, 0x04df8815, 0x1b4ecb7a, 0x778251c6, 0xbf0fe0f8, 0x5ff76647, + 0xc610ae25, 0xe5c7d933, 0x084c4971, 0xe5f4abe3, 0x90fa80f3, 0x17b6d627, + 0x2fa5ef00, 0xe7c408d9, 0xe9c57d29, 0xee977c05, 0x57fdaaf9, 0x66efe099, + 0xe95ebb47, 0x7482ff2b, 0xcd096a50, 0x3b6578c5, 0x99e2042d, 0x237cec75, + 0x43b5f80d, 0x7fc5a50a, 0x695ebdcb, 0x478862d0, 0x52efe7e0, 0x7de18303, + 0xb33efabd, 0xd33917a8, 0xdef76365, 0xbdde6cfb, 0x7d77e436, 0x95739edc, + 0xefb483cd, 0xe8948bb4, 0x9b4df172, 0x69d977f4, 0xa3b8e5bb, 0x37c73bc7, + 0x49e73e61, 0x2018126b, 0x0e3ea8cb, 0x21a8bcf2, 0x0fd83fbd, 0x77d4d90e, + 0xec2c4aec, 0x05248747, 0x0687d9cf, 0xfbb5fd28, 0xab4a99cc, 0xaed09662, + 0xdd576983, 0x097d79a7, 0x66da27f8, 0x1f7b9345, 0x8f08ecd9, 0x1bc5ab22, + 0x07649ded, 0x02deafdf, 0x1b224063, 0x1d43f817, 0x401490f7, 0x4628bc39, + 0x0ff4fd61, 0xb8bdf0c8, 0x2d20ef61, 0xd5cd0a1c, 0x29f28f58, 0xd490b3c2, + 0xf91a99c8, 0xb8578ead, 0xf198a1dc, 0x3ff9ba3d, 0x8c55e9ba, 0xc88d19e0, + 0x7472789a, 0xb33b45c7, 0x2cc0eefa, 0x7e015ae5, 0x9b75c932, 0x6a952045, + 0x1218f7e4, 0xd541d4c4, 0xaabf162e, 0x3c9c8082, 0x83471dd3, 0xd7811a60, + 0xfdf72803, 0x92190803, 0x1286fa0e, 0xefc0d6eb, 0xf385cd92, 0x082b98b1, + 0xddd31793, 0x7e0a7fa0, 0xe94cb91f, 0x61b2aaa9, 0x40f78b10, 0x0d7ef0bc, + 0x3f3a5855, 0x4bf5fb97, 0xd5f907a0, 0x27df70b8, 0x620a2a81, 0xbb453370, + 0xe2c224eb, 0x463bad99, 0xb48fe7b4, 0xffaf8118, 0x0731ca20, 0x6984fc89, + 0xc82ac41e, 0xbfd8aadb, 0x9cfdc365, 0xa0424dc3, 0x241dda1f, 0x63a9a764, + 0x969cf9a4, 0x34995dff, 0xf74ba1af, 0x91b97d04, 0x335ca82f, 0xf8441b8c, + 0x373f7ed1, 0xa1b9fbf4, 0xadbfcfdf, 0xe54e155f, 0x10e941d6, 0x65756087, + 0x8d8dc390, 0xa370e567, 0x710e19f0, 0xc62988d7, 0x11cdefc3, 0x367c31ae, + 0xf14fa816, 0x1d26273a, 0xd8f3f4e1, 0xaff06103, 0x04b50925, 0x04abc3ce, + 0xc922fe35, 0x11da6875, 0x70f915b7, 0x4e671f3d, 0xf577a30c, 0xfacf7c1d, + 0xe8efbc36, 0x5bd6df51, 0xf5e898fd, 0xc7cdbd9d, 0xdf3e751e, 0xbd94ce55, + 0x705bfef2, 0x6f2ddb5f, 0xfa9414dc, 0x6273db77, 0x71a5bf68, 0xc36b7fed, + 0xb46f4c2f, 0x2fe3d7f6, 0xd295e806, 0xfd60cc4f, 0x7bde2377, 0x7cf997a3, + 0x48ef341d, 0x9bbaeba5, 0x9ea53f8f, 0xb3df77dd, 0xe8e3d98c, 0xf50bcff1, + 0x77faf0e7, 0xaed1f35b, 0x87e62270, 0x9ee12718, 0xde17a65a, 0xf78890f3, + 0x08e23dab, 0x7f942fc1, 0x042e5dee, 0xe2d1e942, 0xe3779122, 0xf8f3ff68, + 0x4338c6f8, 0x5d4ca23e, 0x338b4627, 0x7d4ce8c4, 0x5f8c6587, 0xf2e488b0, + 0xeffa51f8, 0x933736ed, 0x5c80e687, 0x2fb2323d, 0x3a5237f9, 0xd2927d06, + 0x8967dc31, 0x712d3dfc, 0xfabfccc9, 0x3c9d788e, 0xb128a0bb, 0xc536bfb8, + 0x2e1be2eb, 0xc724af1d, 0xf9b5e469, 0xbf175da2, 0xa4f24aa5, 0x2e92bc80, + 0xca14475e, 0x3ec5f257, 0x5394d144, 0x1999143d, 0xee5136dc, 0x200398a4, + 0x5ceecce7, 0x6c7a0f92, 0xb54fa31c, 0xa2309cbe, 0x9b7c6f5b, 0x262c7bfe, + 0xe96cf911, 0xc6192512, 0xeb73da09, 0xcae893e1, 0x3d1cf8f6, 0x83bfc1e9, + 0xd60abbad, 0x3d73de9d, 0x83c7b255, 0x774e73fa, 0xcc2b1bbc, 0xef28b44f, + 0xdfbf302b, 0x2aec044b, 0x39e3e13d, 0xbbf0a013, 0x7e87e810, 0xf4ec6221, + 0xc3afe8a1, 0x1075e4f5, 0xf5ca91cf, 0xe3be3c55, 0xf1cf1e2a, 0x737f1e61, + 0xa8f38f0d, 0xa9eacfc2, 0xd68238c6, 0xab7facc1, 0xc127e39b, 0x43e3e1c4, + 0x529ac97d, 0x3684f781, 0xe2084577, 0x74fe9171, 0xbb69809f, 0xb27e11ab, + 0x927da09b, 0x05bcc7d6, 0x6a9534f2, 0xcc1e2247, 0x4f920aee, 0xfbb61fcb, + 0xd9b802de, 0x41bc7d14, 0xc340ca4b, 0x9e01b0bd, 0xc93d3d2a, 0xa70262e4, + 0x127c2327, 0x53df1664, 0xf4dea3a5, 0xcfee2aaa, 0x83d2a9bb, 0x2b8f1569, + 0x84710555, 0x8f294e20, 0xcfc89423, 0x8e145589, 0xbe09fdf0, 0x6655566f, + 0x9da67963, 0xa60953ed, 0xc012838a, 0xbb309e25, 0xf49f8267, 0x55cc22cf, + 0xfc527e14, 0x7abc8144, 0xe7c3588f, 0x7441e9cd, 0xe1710d9b, 0x2f002794, + 0x26486f35, 0x9715e7b8, 0xd63e4cdf, 0xcb38b3d0, 0x3476071b, 0x6013e1d1, + 0xe039fbff, 0x2367ce95, 0x59c6179d, 0x9ab0f4e5, 0xa72d7de3, 0xde3cf587, + 0x5d382fe7, 0x0fd74a3c, 0x7b0f2af9, 0x1a61b037, 0xc84b8bf3, 0x68b8f130, + 0x3bf5a221, 0x8904f38b, 0x3c89d74c, 0x718a60aa, 0x0b31c8ef, 0x247d8bd2, + 0x7e508af1, 0x8b0081ec, 0x0a9b9963, 0x1a9c66fb, 0x128272b7, 0xb61f1b37, + 0x3e3ccc86, 0x1dcec89c, 0x3de351ad, 0x590e7956, 0xdbdefce1, 0xdcce0e7c, + 0xf6bc6043, 0xd20e8851, 0x7b3b97c7, 0x6a3bcd31, 0x7f4dfea9, 0xda5f1eec, + 0x5ae7a06a, 0x373f010b, 0xbe7f9d07, 0xf7b1af46, 0xd9080762, 0xa9d8a47f, + 0x45074b3c, 0x97f7e283, 0x006c83b5, 0x05730a67, 0xa49b1dec, 0x039054dc, + 0xdba2e29b, 0x4cec626d, 0x8e65765f, 0x8d75d1d0, 0xee76c5e4, 0xf4746309, + 0x4fe5c35f, 0xdd1c94fc, 0x7cde5577, 0x0bfac31e, 0x30997dda, 0x998ba4af, + 0xb709bfc8, 0x553f9745, 0x3887ec92, 0x98a35500, 0x94cff3bc, 0x43d59e99, + 0x7539309e, 0xf8f08c81, 0x86467435, 0xbf07d413, 0xe2eb299c, 0x3e03ae19, + 0x63710619, 0x02affd19, 0x38a9a07e, 0x89fa4658, 0xf3c26e9f, 0x5fce1aea, + 0xda7e730f, 0x11e9f9c0, 0xc40b23e0, 0x677c659f, 0xb0e19e26, 0x58b9549f, + 0xfe012ddc, 0xc5549b4f, 0x7187982c, 0x04598f8e, 0x32a89fb8, 0x4317537b, + 0x59e2d6be, 0xe31e60a9, 0xed6bfb01, 0xdf7f344a, 0x2ce27d90, 0x6cd7853b, + 0x6ac7bf8e, 0xacfe22c7, 0xac014f6e, 0xc188eccb, 0x50d57df3, 0x73b4416b, + 0xb33b74c2, 0x2f78508f, 0x4cfa7e84, 0x873ee9cb, 0x66a19981, 0xfdc21666, + 0x1d077831, 0xedca7e85, 0xfd218f4c, 0x46b064fd, 0x38f0d40e, 0x93f14471, + 0xb0791ae1, 0x0254c872, 0x729e9e76, 0xb83917a0, 0x2ac1c98d, 0x062fef81, + 0xf8f156bc, 0x341caadb, 0xc4a35e03, 0x4d7d5ad7, 0xbe7deeb6, 0xb1b8e5c4, + 0x3b3b3ade, 0x9e21ad37, 0x59e84fb0, 0x0eb4e14e, 0x3fd914e0, 0xa0e3ba73, + 0x3aca20fd, 0x0ceff28c, 0x532083ec, 0x338c3ecc, 0x9e5648b2, 0xe5720f18, + 0x4cbf98df, 0x3a827a6f, 0x42c5fe5e, 0x2ef267dc, 0xbffdc78e, 0x213c76a0, + 0x2b02ae70, 0xf69de6bd, 0x753fcde9, 0xd74ede01, 0xcdd3fbf2, 0x57fc0052, + 0x2eaed74e, 0x4db57cc3, 0xfc4c9c01, 0x882e03e5, 0x69e8b2cb, 0xcf53ef11, + 0xd0d3f8c4, 0xcbebefff, 0x7f8d4597, 0xb5ba8ac4, 0x169f2069, 0xef8b5d6d, + 0x7bc4ceec, 0xf26ae687, 0xbd415324, 0x96d38d50, 0x0bc58cf7, 0xfb6f5dfa, + 0xe8e6de52, 0xf82afde7, 0xca5af415, 0x1eb7a02f, 0x4384e574, 0x7e67ff14, + 0xb27d4369, 0x4277f64a, 0x1dab6abe, 0xf8aa905a, 0x1e3ff1e8, 0x0bb4dfb6, + 0x76c3c7e4, 0x89483eef, 0xed4bc583, 0xf8ea3e6d, 0x856b60ed, 0x78a7b77b, + 0xa78a141c, 0x1bbb3a99, 0xe76b77bb, 0xed621476, 0x97863ca5, 0xbb94bd2b, + 0x710c9f98, 0xe7572f47, 0x1f9f9673, 0x07b56d17, 0x03d14656, 0x84f7f116, + 0x867df88b, 0xbb672f4a, 0x67462df5, 0x1725ff6a, 0x62f465af, 0xb9e14ba0, + 0x9f874851, 0x7f70911d, 0x11bb9e11, 0x5d94b4e3, 0x12fd61b4, 0xf828f3d1, + 0x45b79377, 0xdefbd3a4, 0x59f78718, 0x9078861d, 0x09e983a2, 0xb1779a6a, + 0xe69fa758, 0xb0ca1605, 0x2c5de79f, 0xf60c7463, 0x93983867, 0x689b5e6f, + 0x0396f4e6, 0xb4dd2fed, 0x6fcbd692, 0x264ef463, 0xbed0cbf8, 0x3cf76758, + 0x8a0e451c, 0x3717450e, 0x84adbf34, 0x49f873b5, 0x7ffee682, 0x9e8b8f11, + 0x45c5917f, 0x493f6e24, 0xf2e73a01, 0xfa9f4229, 0x261db5f8, 0x7ae32f86, + 0x133af813, 0x437bd7ba, 0x3efdeb2f, 0x0fd72f5b, 0x1bc6dbf2, 0xf1abf5d6, + 0x5915d6d1, 0x5fac04cf, 0x970de3c2, 0xd5de1898, 0x4c1d1bf2, 0x7b69ab0e, + 0xa5e22ce5, 0x8f2151fb, 0xb81798ab, 0xcf3e064f, 0x2f171cdb, 0x5f99d668, + 0xa7e7473b, 0x1f3b5792, 0x6fe570e3, 0xd02f2f9e, 0x9e3755f0, 0x6baf29fc, + 0x86e374f1, 0x3a57533e, 0xbdca1f60, 0x3ee301d6, 0x65f73a5b, 0xbc32fd02, + 0xa3fd919d, 0xdd0e502b, 0xcef68ae7, 0xdbc046e5, 0x387ced38, 0xc9fb06de, + 0xa37bed48, 0x58e3d18b, 0xbe2b6fb6, 0xdbbbee1f, 0x4451649f, 0xd137977a, + 0xe38469f1, 0x59bf0e2c, 0x8e1c70dd, 0x8657547e, 0x7f3a75e3, 0xc8e15ea9, + 0x49c2aff1, 0xb0f54efd, 0x18448e99, 0x57f7b097, 0x0aafe3b5, 0x27f1917e, + 0xa1defaf0, 0xa2fc824f, 0xf4f812f2, 0x1f3fb3ec, 0xb0f76dad, 0x30bde27d, + 0xbabea90e, 0xd83fb57b, 0xdf50797d, 0x0473c93f, 0xadfe6bce, 0xae8aa7a2, + 0xa9f630bb, 0x56ae10ce, 0xaeaddfbf, 0x760e186c, 0x20caaad6, 0x40bb54a6, + 0x8a6a8bbd, 0x685fd01e, 0x78b46f15, 0xbc39eb54, 0x32b65757, 0x4fd5913b, + 0x240f60dc, 0x99c92f8c, 0x333768b1, 0x837af43b, 0x60dcf92c, 0x7bf993a7, + 0x5becc967, 0xe7099e97, 0xbf0c84e0, 0x1d6bbe06, 0x4362ffcc, 0xf83f52ca, + 0x3ec159ed, 0x22ed0839, 0x81767417, 0x9c8bcd57, 0xf0d4ee94, 0xf58331a3, + 0x904252e5, 0x246e1da0, 0x479daefd, 0x2eceab42, 0xd98b846a, 0x12fbc2ea, + 0x2ef6e133, 0xeff50f0e, 0x72e5ac64, 0xcddb86b8, 0x197b071e, 0xbb4adf85, + 0x35a3f70b, 0x39d898d7, 0xf3c66ac3, 0x40f1b835, 0x8fd6397d, 0x7ac1b0eb, + 0x43f3d044, 0xe4427798, 0x7b43111a, 0x238f9009, 0x3ef9008a, 0xf406b424, + 0x6d89aed6, 0xd9f7c3f7, 0xe01d5f36, 0xd6d4cbf7, 0x4fd802e3, 0x00c37d73, + 0x3fa2b5ce, 0x7ff5a143, 0xa033862d, 0x3a2d1a5e, 0x6bd2cf16, 0xa7daafc0, + 0xf16197b9, 0xb1792340, 0xe59afe67, 0xc53dc366, 0xe5b4c3d7, 0x2d946cfb, + 0x7bfcf5c6, 0x0b1f0929, 0x74b6ef28, 0xf173c9db, 0x8e51d07d, 0xa00fa44f, + 0xbf6c23af, 0x625660be, 0x4dfd99e3, 0x67675579, 0x6aaf2ab6, 0xf3f333c6, + 0x57a53d50, 0x74aba7b0, 0x35ecd832, 0xa90d3d01, 0x74b5dfa6, 0x832f4511, + 0x72f70671, 0x0fcea11f, 0x3c0007de, 0x6c598bc5, 0xc5d031bf, 0x25fb6ebe, + 0xb32a7bfb, 0xaf33c255, 0xa238f962, 0xd1fc60fe, 0xe3edba0f, 0xcdde58ab, + 0xd80be572, 0x05a1dc7d, 0xa6d7e8b1, 0xcb7663ce, 0xc3d056da, 0x2ea4b766, + 0xd999fb84, 0x0afeebd6, 0x7c293ee9, 0xe2720ec8, 0xe79e2ca7, 0x2abdefdd, + 0xfbba69d9, 0xdef8addd, 0xcfdf34fa, 0x04b092e6, 0xb711f7f8, 0x01ebeccc, + 0xc405d3e4, 0x0941f3c3, 0x84f7bdce, 0x42de7702, 0x1abef773, 0x628e05b8, + 0x5f848f73, 0x82f97403, 0xc368a9ee, 0x7b35db56, 0xd679675e, 0x66fd7bae, + 0xb227ae2b, 0x5fae2b5e, 0xf6441f5d, 0xb8eef2c4, 0x912e2cc0, 0x0b498f0a, + 0xdb67bad9, 0x7c98fce7, 0xdb39de8b, 0xccafea3a, 0xc7cd887f, 0xa1cf9f08, + 0x4ec5ca88, 0xa4e4d787, 0xe1d0ffeb, 0x5eb49d15, 0x669c3589, 0x62fc881e, + 0xe8997c81, 0xae8926bb, 0xdf00fcff, 0x438044b0, 0xd2ab9f6b, 0xf4e4df2f, + 0xefa726fd, 0xe3bbd337, 0x1ea02718, 0xae024f7d, 0xb3a7066b, 0x47dfbb35, + 0x6ff3cc3f, 0xa54b78b0, 0x83eb72a2, 0x49133768, 0x6aac38b4, 0xdfb726fa, + 0x0e954e28, 0x0dce3c03, 0x4d1997e3, 0x9fbbf476, 0xf4ea2991, 0x029919f0, + 0x1d6b87f7, 0x2f4e877d, 0xd2f5c55d, 0xff80fd9e, 0x859fb181, 0x39e327cb, + 0x9eec8f6c, 0xffdff208, 0x85b3a334, 0x293c2853, 0x13ace5dd, 0xfc70def0, + 0xf20236a9, 0x1c4d6170, 0x85f3fb81, 0x20fbfc0f, 0xd650c788, 0x81b734aa, + 0x1e080c9c, 0x8b25bfb0, 0x467e324b, 0x10e9b5e7, 0xbf2187db, 0xf0e9e604, + 0x3d8d0e2a, 0xc8aa43ba, 0xdf5d0370, 0x3c82f0eb, 0xf7877f98, 0x6fe78c03, + 0x7b041d0e, 0xf99ebab7, 0x00d928f7, 0x9b41f9ff, 0x312b5317, 0x36b950c7, + 0x90ac4cdf, 0x6cc4cb26, 0x73cb7c83, 0x1e4bb05f, 0x18e4eeb6, 0xdfdf6562, + 0x72f404b8, 0x5bac835d, 0x3ea0a8f7, 0x3eb37d7f, 0xe7d2119f, 0xe7d11ec7, + 0x431a83b7, 0xffc395f1, 0xfda1d4ce, 0x877f0216, 0x0b45f8a6, 0x0cbeb3fa, + 0x05fa007b, 0x4dde50da, 0x82c96e2e, 0x5e4fd6fb, 0x9ce09a70, 0xdf9befbf, + 0x786d7de2, 0xc9e31d87, 0x0c53fc1f, 0xc07f0189, 0xa15b6d17, 0x04e298bc, + 0x2fc577ec, 0x0ec0eada, 0x7a8467b2, 0x5fa00d1e, 0x31bf9ec5, 0x76f0f9bf, + 0x6fee004b, 0xdcfbd93f, 0x9f6f400b, 0xfa87ef6c, 0xdf82cbce, 0xd7f9fd04, + 0xc4e67c33, 0x272d7db0, 0xde33d286, 0x75cfebbb, 0x1c993bf7, 0x1e6caf69, + 0x4e59fb01, 0xb47fb33c, 0x011c1e57, 0x8f0e5cfb, 0x49eaae43, 0xbc7e3c39, + 0x274fea9b, 0xe51439d9, 0x0fce70c2, 0xb2058179, 0xd5fa01d7, 0x5390188a, + 0x79e5675d, 0xac358fe0, 0x15470f56, 0xf406d7cf, 0x7cf92bdf, 0xf7cd1016, + 0x56f7b874, 0xbd00a4d6, 0xbea2433d, 0xf9c35c7b, 0x65e7f9e8, 0xf22fbcf5, + 0xd14468f8, 0xc88acfbc, 0x1facb273, 0xbe0025f8, 0x17be4606, 0xfb55c61b, + 0xfffbca9f, 0x92fccacc, 0xce1c3813, 0x7d411e55, 0xaddf5ba0, 0x68a77af4, + 0x07b579f2, 0xfc23e693, 0xd02d260e, 0x1fb6f39e, 0xfe039a4e, 0xfc660d36, + 0xb32553bb, 0x27247d9f, 0x418bbe01, 0x03942798, 0xaf823b1c, 0xd51ea0b9, + 0xfd68c767, 0x6f6bf257, 0xecd14ef2, 0xce95dfd7, 0xbb65e3bb, 0xca5e5c19, + 0x16fdbdce, 0xa2cdbba0, 0x0715aa07, 0x1479bcef, 0x84b37bc0, 0x764b72ef, + 0xbdb7184a, 0xb406eebc, 0xbe371453, 0xffe31533, 0x03df393d, 0x9332caf3, + 0x9a0c715c, 0xf480ee18, 0x8c6ecb4c, 0x61fc57af, 0x60566c8d, 0xa3ba7abe, + 0xa3f08c74, 0x6dd6541a, 0x15de53c0, 0x7eab3fe8, 0x30b7e237, 0xc46f6fa0, + 0x1ba72b53, 0x8b5c33fa, 0x3ebd636f, 0x8ef8fdd3, 0x953964b2, 0x543b1a63, + 0xf46aa9c9, 0x038e33d7, 0xa344da37, 0x7703eca7, 0x1dafe01b, 0xfe836fcc, + 0xee2cd608, 0xe5883ad7, 0xd0200e31, 0x047fac15, 0x3bc0a299, 0x34c8dbcc, + 0xd1b95548, 0x0d1c1d91, 0xda165ff5, 0xf615fd9e, 0xed7e44e7, 0x2e308770, + 0x3efe5f62, 0x796143b5, 0xa83aeff5, 0x362d45e5, 0xe4f8f3f4, 0x71f28cbc, + 0x4197f805, 0x266c17fd, 0x3ebfdd13, 0x1267d9d9, 0x04762df8, 0x73dcbc59, + 0xe4933ec1, 0x8d77d96f, 0x0fdd4172, 0x74afc04f, 0xe9c2fcdf, 0x4b7ec30d, + 0xcebf3156, 0x19153ee4, 0xa4f05115, 0x2b904bb6, 0x123ce032, 0xd9e1d7be, + 0xa7f2708a, 0xc1723ec3, 0x81f68297, 0x121edcf9, 0x06fdceef, 0xbad275fa, + 0xfe2ffa5e, 0xe815b888, 0x73d163eb, 0xe4507bbf, 0xa6516f9e, 0x90f3df0f, + 0xb45cec55, 0x66424cd0, 0x842eefaa, 0xe63463fd, 0xb85bbf71, 0xa6ff4059, + 0xebf41b45, 0xdaad7881, 0x405087bf, 0x22dfb1aa, 0x60b4c412, 0x10bcbeb3, + 0xf81723f6, 0xfc7bb067, 0xb97d7aa2, 0xa4a84efa, 0x1a25b2f1, 0xea20bedc, + 0x2ec9bcfa, 0xb36e179a, 0xdbeefce2, 0x35eecb14, 0x7d85e264, 0x89c9bc30, + 0xf898bc72, 0xbe3f3bd8, 0x303f960f, 0xd288bbdf, 0x85f2d767, 0x307d45de, + 0x7d81077e, 0xf895b16f, 0x1e58635d, 0x0b2017e2, 0x38b29f21, 0xed4eb051, + 0x29e2963b, 0x15c03424, 0x53ac2f59, 0x65de4e5b, 0x116e2cf8, 0xbd60a342, + 0x64427ef0, 0x2bd6d5eb, 0x692870e1, 0x11ece8b4, 0x0a7fe0a5, 0x974d337e, + 0xb97eba2d, 0x8fdd1f3f, 0x69e28d89, 0x0ddcb753, 0x4fcd1b5c, 0xd78738fe, + 0x52f33ba6, 0x051f3f81, 0x072fb33d, 0x173d3668, 0x61cc9083, 0x71d2b780, + 0xe776c662, 0x256b3cb1, 0x647d4fcb, 0x51e90fe0, 0x1bcefe1b, 0x142c6fde, + 0xf7875f73, 0x7db9cf57, 0x71d1763f, 0x69bc9a16, 0xef53e466, 0x5cd7f450, + 0xc4ffd6ce, 0x2b6b8a98, 0x557b9ca2, 0x042e3e7c, 0xbfd1bef1, 0xceabed97, + 0x7da4b0cc, 0xc5c8b45f, 0xa1ec4fe4, 0x10777c36, 0xbbe02dde, 0x138527c7, + 0xc9f02ef8, 0xce04291f, 0x6f1429e5, 0x149f1f20, 0xbf882ac8, 0x7334d995, + 0xbf806bc9, 0xa3d418cc, 0x8a269b4a, 0x3f5c0ea5, 0x15eca3d3, 0x99ef7075, + 0x18f86f3c, 0xeeba6ba0, 0xff01b779, 0x5b8414bb, 0x41d183aa, 0xfa7f4aca, + 0x7e3091d2, 0x80d792ee, 0xe0c546ef, 0x0a64d93b, 0xa63c672b, 0x4a2f40eb, + 0x41071921, 0x574ca78e, 0x772d80c6, 0x938d8b93, 0xcde71268, 0x0c6dfd04, + 0x243fc7cb, 0x7122b778, 0x2575c46d, 0x369fd85b, 0x7fa0ef82, 0x804ec15a, + 0xe78601e5, 0x301915c9, 0x9620f27e, 0xf421c826, 0x8dda3a53, 0xcdea1f77, + 0xe504dccb, 0x134bb2f2, 0xfb69e393, 0xc0f41da3, 0xd1d5e54c, 0x1d9eaafe, + 0x439e8072, 0xf5670f06, 0x2cb15eb9, 0x27e5f983, 0x10faa9a4, 0x7925d7ab, + 0xfc82c763, 0xdbe9877c, 0xb1bc3b9f, 0x837737e0, 0xb80fdd1c, 0xfca9e386, + 0x34049da2, 0xd67cbff2, 0xa4def897, 0xf74ba2fc, 0x69c9e21d, 0x0a4b49fd, + 0xe3dc610e, 0x7e8ad252, 0xbd41a5c9, 0x310debff, 0xe955c7d1, 0x48a2fcbc, + 0x95c751fc, 0xf62fdff5, 0xd13efe21, 0xbfe925ea, 0xf9f4145f, 0x3d78afe6, + 0xd9277e33, 0xc7382e6d, 0x077d874d, 0xe4c049e4, 0xe08fae97, 0xa6ddd3a5, + 0x153a6fdb, 0x71e2ef96, 0xb572d575, 0x3259ceff, 0xc6139f7f, 0xa92a3a71, + 0x79f0a240, 0xb453e5aa, 0x1cb496a3, 0x74a8f844, 0x9d938111, 0x4a7035f8, + 0x990d6aaa, 0xfeff8f28, 0x476b4591, 0x72514b5e, 0x3fb3f388, 0xf297ad6f, + 0x2fc4126f, 0x3db7f0d7, 0x51df9bb3, 0x89326ccc, 0xbf99dedc, 0x4d04ca76, + 0x6eefd79e, 0x21f82fef, 0x648e6794, 0xa47bdfed, 0x072b77f0, 0x5d13e447, + 0x53ae5a47, 0xf21ab793, 0xa51f9a0e, 0xe50dbbc9, 0x14f28609, 0xab3fbe43, + 0xa50ce1df, 0xda421e89, 0x21fd291e, 0x8eb95dfc, 0x885cd0d4, 0xac41b038, + 0xddfc21f8, 0xf64cd2c9, 0x5acb1477, 0xb3730f04, 0xf32bf062, 0x87307bb0, + 0x385e4da7, 0xfad0e012, 0x9283c83a, 0xfa0dc166, 0x33b823be, 0xa7687984, + 0xd905da68, 0xe092ad3b, 0x6bd76c09, 0xc84dc3ff, 0x3f0f0fcf, 0xe4aef589, + 0xeba644ef, 0xf37be0fd, 0x7c9874b3, 0x53df6117, 0xec770ce3, 0x77f23f7c, + 0xcef7e8ed, 0x9461ef54, 0xaaf786a7, 0x471f30e5, 0x38545f84, 0x02fc3c3e, + 0xf3fc5dc6, 0x40f796a8, 0xfb2fb00d, 0x95e80574, 0x1e9e961f, 0xc4167a07, + 0xe3fd846e, 0x2d702171, 0x114f47ec, 0xee30b5df, 0x0e43a5bd, 0x39949fc2, + 0x816db52e, 0x1ec31050, 0x3ff08f5d, 0x001b6cee, 0xdae8927f, 0x4f961ad8, + 0x1008c36c, 0xfd37626b, 0x39fb4cd0, 0x806da03e, 0xc547e689, 0x43e5661e, + 0xfe40b6da, 0xb0dfd8ce, 0x036d51f2, 0x1d1c3744, 0xdb7f111a, 0x3ef9d1dc, + 0x1bc9962d, 0x06437e75, 0x4163537b, 0xfb612a8f, 0xb4873c0e, 0xb73ab952, + 0x6d8edce8, 0xff731e14, 0x6ef28ed5, 0x3fedc75b, 0x3fb1fa66, 0x92a0fc17, + 0x5f71bc39, 0x466ef944, 0xf61521bd, 0x3e08f8c2, 0x0aad699d, 0x2a231bee, + 0x905e8276, 0xee24773c, 0xef4e9d1b, 0x9171d8da, 0x9a048bf4, 0x8dac79d2, + 0x2ef93375, 0x5b3df09a, 0xd44e83f2, 0xf1e51e9f, 0x21df29ba, 0x5e38387d, + 0x8cf5f2c6, 0xa1e7658d, 0xd84dd744, 0xaf5cddcf, 0xd81f59ad, 0xfff0a36e, + 0xde0e7a93, 0x39e4f4c8, 0xc4ee5475, 0x37817f82, 0x1cc9e415, 0x8c8f07b0, + 0xbfbd55e4, 0x1de68326, 0xcd58f391, 0x36aa6f4c, 0x1d4d782e, 0x55e5572b, + 0xaf6b3a4d, 0x55c95bee, 0x8fc93e0c, 0xd615bb5e, 0xff333761, 0x86b3c581, + 0x7a815d6e, 0x5f386dc0, 0xc2a6f5e2, 0xe154fcb9, 0xa3e81340, 0x0da67e2a, + 0xeb82def6, 0x2a38f7e1, 0xd7f1d49e, 0x142f75f2, 0xf6011ea9, 0xe10fb774, + 0xd18af549, 0xe99d72ec, 0x5ae96b15, 0x7c2a1f01, 0x1c6db989, 0x045fff7c, + 0x0cffa5a7, 0x7eddfd38, 0xbc7bd3dc, 0xfd0359c7, 0xad3f2e97, 0xe1c38f7f, + 0x9210b8fe, 0xf1353392, 0x3877e853, 0xf2eade77, 0x735622fd, 0xc1f735bf, + 0xd53fd452, 0xe5ffd8f5, 0x917769a5, 0xd469fc9e, 0xc9ff8f0f, 0x02ec01ba, + 0xca20e5c7, 0x263fe3e3, 0x38e42ef8, 0xeaa5678f, 0x5aff59b7, 0x6dce147c, + 0x222b11ff, 0x7a54d87d, 0xe6777210, 0xa7aef851, 0x3bbc39db, 0xd464fd57, + 0xc786bafd, 0xe079ada1, 0xd1af7c3a, 0x3cf0da45, 0x2826cfee, 0x67cbbb3f, + 0x4a72c50f, 0xc81b7e27, 0x8c18c289, 0x41935fc7, 0xcd497df0, 0x0e5811ec, + 0xc7f458e7, 0x71c56d99, 0x3a32666a, 0x478c29ac, 0x5dc8217b, 0x746f5b80, + 0xecc55494, 0x1decc41f, 0x7f1fbdad, 0xf9f9962f, 0x76db33db, 0xed7a0fbf, + 0xb5ea1b06, 0x57bc4280, 0xf1c64ea9, 0x8fec3d28, 0xcd97fdc5, 0xa963e163, + 0x5c718781, 0xd603da0f, 0x51f3bd3a, 0xaeccfdce, 0xdb37fcc0, 0x18eb3ac8, + 0x5590e638, 0x7cf92f28, 0xe813f548, 0xeb8f3157, 0x5c151f89, 0x721e8270, + 0x1edbb634, 0xf9f385e0, 0x17cac202, 0x013f643c, 0x0f05abe7, 0x64b778b1, + 0xfd5e4ddd, 0x6b9d093d, 0xf9d3d812, 0x09d86d4f, 0x3b41f070, 0x1ffff417, + 0xe41f784e, 0xc3bd887b, 0x7eda7e25, 0x47fda478, 0x9760f7c0, 0x49fcd917, + 0x16895da5, 0x58a3f4e7, 0xfd5397ee, 0x9e3b5784, 0x5fb18e3a, 0x036c8e7a, + 0x0f70a37e, 0xf0a83bc1, 0x59dfd8cf, 0x4137ce30, 0x46c2ff0e, 0x8a56e7cb, + 0x3c292b71, 0xb89dcb7d, 0xf3be755e, 0xa237c392, 0x7fd0c29d, 0x0b2cbdbb, + 0x79eae7ec, 0x39a43c88, 0xe45c21ff, 0xf8845e48, 0x573c6101, 0xcfcef8f5, + 0x2873c6cd, 0x68b37f21, 0x2bbf75eb, 0xfcc30450, 0x82295d39, 0xe3e6f019, + 0x1cb2fef7, 0xeb720b9e, 0x50eb02ff, 0x8000589e, 0x00008000, 0x00088b1f, + 0x00000000, 0x7dc5ff00, 0xd5547c0b, 0x73b9f899, 0x3332bcef, 0x49324cc9, + 0x9b8f2126, 0x80402107, 0x52024c49, 0x1878431f, 0xa4076b35, 0x438b5b16, + 0x921123c2, 0xb175b689, 0x5100cb65, 0x8d042208, 0x41380abc, 0xbb6bba50, + 0x060222c1, 0xb6a2d11a, 0x6eb42fea, 0xfdfeed57, 0x58f88845, 0x16544649, + 0xefffad5b, 0x99b9cefb, 0x514493b9, 0x67f4ddbb, 0x739ee72f, 0x77cef9cf, + 0xcef9f7be, 0xe99a1619, 0xf4662deb, 0xfc3e79f7, 0x33577f87, 0x3034e896, + 0x7cd8ca96, 0x96773599, 0xeb47df44, 0x6d67aa25, 0x34967d5b, 0x0bbc02c6, + 0x66f536e6, 0x607da1fb, 0x694df9b9, 0xeb88bc22, 0x6330b19f, 0xb56d8c15, + 0x993590b2, 0xf4126db1, 0xbbcf0e53, 0x7935e16c, 0x23580d8c, 0xc602b08f, + 0x59afc782, 0x1bfbef80, 0x4d065412, 0x08589876, 0x8ee3a1cb, 0x576c3ef0, + 0x64c45bd4, 0x7c1807a8, 0x24be786e, 0x0d248477, 0x5e9ac608, 0x87acf792, + 0xae47fd76, 0xb2acfde5, 0x41ca0ca9, 0xb8c136a8, 0x575fd0c1, 0xa4c644b2, + 0xff1a1639, 0x6c2921cc, 0x66c3fac6, 0x85e0d3e6, 0xbfe1faff, 0x2f1832fa, + 0x2719086c, 0x102b13c1, 0x8236c38e, 0x40da6603, 0x813f7de3, 0x9bf187ad, + 0x00cf920c, 0x8db74df5, 0xf0e1af0b, 0x67e01858, 0xc9ad0099, 0xe8245ac0, + 0xb5e0532f, 0xe8ba70c9, 0xa75e128e, 0xf8a5bb40, 0x3dda950f, 0xcb9c012b, + 0x647a1b2c, 0xe1399380, 0x0dbfa83f, 0xeba2f3eb, 0xbfe1b4d0, 0x3479c33f, + 0x2db8041d, 0x3d97b851, 0x6dc79fa6, 0x27ad14cc, 0x7eb443b8, 0x2f8e72b6, + 0x47858336, 0x510ebc03, 0x84f755b6, 0xf2c7c465, 0x65ccece9, 0xef44f4d0, + 0xeb1dbf2c, 0x3c2d593b, 0x5f30ef83, 0xda9ee018, 0x28ccf1d5, 0xeeaaef68, + 0x06e9c6c9, 0xa0b1ff97, 0x3ae8b2ef, 0xde5e706b, 0x766659b5, 0x03be8f1a, + 0xec077c50, 0x9cec6ed4, 0xd5cfb109, 0x41aa5df4, 0xebc715be, 0x881957c5, + 0x04865f1c, 0xc8696ce3, 0xdabae037, 0xb0057814, 0xb31b6a2e, 0xd9e11567, + 0xc1c73457, 0xec8983d8, 0xd3e13f56, 0xfe87e95b, 0x2d56751e, 0xe97f4274, + 0x9d5baaae, 0xbf1c7ca9, 0x029fa703, 0x6ba50d40, 0x47e1a9ed, 0xd05e976b, + 0x1f6cda5c, 0xc4db9db9, 0x9ed916f1, 0xf083de14, 0x17951228, 0xb1d8deff, + 0x8853e09e, 0x95d8ee6e, 0xebf84617, 0xe9099b59, 0x9b0b197c, 0x5b178e90, + 0xe8112858, 0x4b343162, 0x6d92e782, 0xacc6a666, 0x5f58435f, 0xae1ced66, + 0xd3f74a65, 0x4dd22252, 0x74b3f50f, 0xb2ddbebf, 0x01dbac19, 0xd6168df5, + 0xa767c36d, 0x4589bebe, 0xe1e08e08, 0xfebacdcf, 0xc3ad1b59, 0xc8632b76, + 0xbe6549a7, 0xfe01bbbc, 0xef460bc8, 0xb7cfa01e, 0x7868bac4, 0x35567648, + 0x64139e20, 0xb233cd03, 0x03de16ca, 0xb033ecf3, 0x4de75c7a, 0x1ceb762e, + 0x64aff678, 0xa12342be, 0x77ae2263, 0x1fd73e3c, 0x7d23d6b5, 0x13f9416c, + 0x38373f43, 0x5ee7848d, 0xbe47ab13, 0xfd0d5ca9, 0xa6a5c8c5, 0xfc01ec9b, + 0x9726976e, 0xc46f9d60, 0xa86b6675, 0x9e91ed8c, 0x4fe32e12, 0x83bdbbed, + 0xa7f337ed, 0x4b7bf9c2, 0xae074243, 0x0cee9453, 0xc4aee88c, 0xf7c00a6f, + 0x583c8547, 0x38fdf960, 0x40a3f7a4, 0xa1f7c808, 0x0b972b4e, 0x72fe738a, + 0xa77d1f28, 0x455ebbc4, 0xe272e0fa, 0xd812f7e8, 0xf9f2186a, 0xdef5fef7, + 0xfcfea197, 0x0cd5263b, 0x46910bf5, 0x4a8f3d60, 0x85e387cc, 0xf787309e, + 0xc065bbc1, 0xb2cf08b6, 0x28c213e3, 0x02990edf, 0x38e117db, 0xfbbd1b8f, + 0x8965bbe0, 0x423c5fe1, 0xa05e19f5, 0x9194f644, 0x88e861d3, 0x109f7f8d, + 0xb95fb7fe, 0x1bdd3eb1, 0xac7bf682, 0x07c81381, 0x09356699, 0x97bf65fb, + 0xbba71f19, 0x3bf805c8, 0x824af38d, 0x38495427, 0xfa83974e, 0x58cafe01, + 0x699cfd04, 0x80f9a74d, 0x38e1f4dc, 0xf79a3667, 0x32dcdca0, 0xed44ae38, + 0xb3fd1b4f, 0xfa7ca032, 0x2aef5289, 0x9bf01aa8, 0x7f404dba, 0x5f4b4dc1, + 0xea17a064, 0xc46eea0c, 0xa36e3b0f, 0x11eb6879, 0x06a4b8dc, 0xadb783eb, + 0xdae501b8, 0x7289fc48, 0xbbc8c59a, 0x41c9167e, 0x9f51dffa, 0xfa8dd9df, + 0x57ac6ba0, 0x2c0f5aa6, 0x9387d03e, 0x7233edb7, 0x198e46fc, 0xb52f4f89, + 0xa50ba47f, 0x1c0feb92, 0x94f20827, 0xf242fc69, 0x0f2ca634, 0x18ebe657, + 0xfc4e9a3c, 0xdb3f5f1f, 0xf908f811, 0xfffee9a7, 0x8ab96379, 0x9e4845e3, + 0xe254b6b1, 0xdbbb8033, 0x6df7df02, 0xe55f1077, 0xf70f50ae, 0x741ebae2, + 0x335d3cd1, 0xcb03b27c, 0x3ca8f33b, 0x1c6dc855, 0xe2c6f516, 0xcaf48c29, + 0x58b59962, 0xd17de8ca, 0xf67f6876, 0xcf5a6c89, 0xceb666c5, 0x36ce7c02, + 0xdb3ffa70, 0xf00a7201, 0x25ee6753, 0x4dfecb39, 0xb518fb62, 0xcb76c16b, + 0xb28c9060, 0xb94378a1, 0x385bc3a5, 0x7ffa0ca6, 0xe907676a, 0x8a720601, + 0x9a05d8c5, 0xa4f9431c, 0xcdfd9efb, 0x4863c7ac, 0xc7c4b793, 0xd9f4a930, + 0x28f2a213, 0x72cfe9d9, 0x30a16055, 0x5677f11d, 0x04e9dc0e, 0x8584b6f9, + 0xb0363e48, 0xe36a7a6e, 0x72e5bc81, 0x2ee5c2d7, 0x412e133e, 0x3ac6defe, + 0xa2366e49, 0xee4e1a44, 0x3bb900ae, 0xcbb96471, 0xe2297358, 0xdd8b7835, + 0x221e788b, 0xd77c857f, 0xc4dd31d6, 0x15d4f0e5, 0x44959961, 0xe89a90f1, + 0x115a969b, 0x57c1abd5, 0x1275162d, 0x1f2cfd96, 0xda63ade5, 0x7d41a7bf, + 0x943e6150, 0xe61eb69b, 0xbbf780eb, 0xf3f5fd84, 0xf1fa9534, 0x185d3898, + 0x852b3f15, 0x9eaacafa, 0x49f2036e, 0xbca2732a, 0xfef0f477, 0xbbe03977, + 0xcb8efc32, 0x2defc1cd, 0xe62125ac, 0x56a3aafb, 0x470ba3a2, 0xe933611c, + 0x0bae40c3, 0xb3fb4bfa, 0xfea4ec99, 0xf3920ea3, 0xaf3646fd, 0xd1bbda13, + 0xbcf5a21e, 0xaefbfa87, 0x219e8f2b, 0x218a3556, 0x8dd74aed, 0xecd65642, + 0x9ebcc683, 0x1edf489b, 0xc7c8ab30, 0x77bd5c17, 0x63c61962, 0xedbf2728, + 0xf05da952, 0x9fd2f4e0, 0xdfa0fbc2, 0x0dd8e5ee, 0x98bd2294, 0x64dd1fe5, + 0x259b7581, 0x05dc88af, 0xdb663670, 0x6787289d, 0x9fd7fee4, 0xbbf2866e, + 0x8ccc8d07, 0xfa6fbeeb, 0xb23f963c, 0x1b08689c, 0xd0c6f74f, 0xfafdd2eb, + 0xbea76372, 0x2fac3c1c, 0xb872e1df, 0xde278ecf, 0xf40e7ef4, 0xbf373664, + 0x9af001d3, 0xdc93329f, 0xf815debc, 0x26e7a467, 0xe224e443, 0xfefb9cd1, + 0x73ae00c4, 0x3e1207d7, 0x3d2640cd, 0xc8bf1c25, 0x0bac1757, 0xd8c39d72, + 0x857b51eb, 0x47840c59, 0x513d06b0, 0x20e410f9, 0xdef95f01, 0xbfe61a7d, + 0x73824e78, 0xd5f1bd35, 0xbda25454, 0xe0b23042, 0x45df6bb6, 0x35da1ebb, + 0x0d989c90, 0xfaae00ed, 0x2f6e5c6d, 0xc8893d63, 0xd7604d0f, 0x7f096058, + 0xb1f4e2e7, 0xd95225b4, 0x4f6cff0d, 0x708b1eae, 0x7e299f2a, 0xd8b5ff5c, + 0xf61d8c6f, 0x1dfb8b90, 0xdb5bf74b, 0xa1f862fa, 0x2ba5d3b1, 0xb4670f07, + 0x5de2c5f5, 0x25533ff0, 0xb6ded625, 0xb90f021b, 0x7b0f9152, 0xfc60d34d, + 0x88fb3fab, 0xe592f7f4, 0x0a9d90cf, 0xedc058f3, 0x728aab36, 0x4f5dc975, + 0x2fcd7bd3, 0x276d9b38, 0xed99e0bf, 0x99765e66, 0x17767ca8, 0x74965bf7, + 0xa79c614a, 0xca62e734, 0xbba79434, 0x1b334e8c, 0x3c78d78a, 0x3ff3bdbe, + 0xf54c1913, 0xfa3a426d, 0x1bb71213, 0x6489cd9c, 0x89cdaa9f, 0xb7051f68, + 0xca2ef35d, 0x64bb25a9, 0x7635ea2f, 0xcd1de1cc, 0xec733cb0, 0xf3f63b22, + 0x8034ca61, 0x4cf77da3, 0x65ef4ca7, 0x48f9187f, 0x0d5cf5f1, 0x93dd95ef, + 0x67b7e455, 0x97f87177, 0x208f2cb8, 0x99fd5d1d, 0x62b2764c, 0xcfb40160, + 0xb1be4dda, 0xceeab7c8, 0x7d70b37d, 0x699d9ede, 0x94bff6a0, 0xe2f11398, + 0xef869e5a, 0x1f8a4897, 0x5b7eb4f9, 0x7eac4d43, 0x1325d5be, 0x5dcb4dbf, + 0x276bd691, 0xf509babe, 0xe02ee355, 0xce7f1c23, 0xd9ba7feb, 0x692be51d, + 0xa61bb6ce, 0x1a8fff62, 0x8377c8bd, 0x3fe7777a, 0x5fe17d11, 0x6dca2577, + 0xca6faf8e, 0xc69b6667, 0x2845cd27, 0x6eac973f, 0x630e722e, 0xc9f20fcf, + 0x6f97ce4e, 0xb7ee24b9, 0xeceb2566, 0x00fc91dd, 0x87c1b17b, 0x9978b7f8, + 0xd33c1f6f, 0x7f430dc1, 0xa159212f, 0x136484fa, 0xe4f949e1, 0xa92ffd8e, + 0x3e071768, 0x65ccfa44, 0x27d452be, 0x9559c46a, 0xec2b7484, 0xdb93b605, + 0x907f6081, 0x9525b5bd, 0xc63eb23d, 0xfe8933ff, 0x8a7c4e40, 0xb5ffa272, + 0x7e224f4f, 0x9fde729b, 0x783afa88, 0x0a9323f1, 0x4977b5f3, 0x5eedbf24, + 0x09ba433f, 0x0b66cd76, 0x3772a24b, 0x217ae5e8, 0x26375e7e, 0x751cb91b, + 0xab9fa847, 0xb73f3852, 0xd3d118bb, 0x6409e58e, 0x8770ee97, 0x57f408ad, + 0x29f65be5, 0xe7587568, 0x675f0b06, 0xfb5fdecb, 0xb0f3a464, 0x658d1ce4, + 0x40c7f395, 0x0cb0fcfd, 0xb7bbbce3, 0x83e54420, 0xd432bcd3, 0xbc3ef7d9, + 0x74f11f2e, 0xf6c5e8d8, 0x226f6f76, 0xbdddefce, 0x7e711267, 0x9a657bf5, + 0x83f87d77, 0x512545b4, 0x2917f139, 0x768c9050, 0xc7b25b82, 0xf7778bca, + 0xd0b6987e, 0xd253fdce, 0xe3c3e597, 0xad35dd25, 0xfabfbf18, 0xef2ebe2a, + 0x461cd2fd, 0x159ef839, 0xfc8c59f4, 0xf5c1cf7d, 0xcd64d4db, 0x41cce8cf, + 0x565833fd, 0xfc701ac6, 0xfcf9391f, 0x1ccea6dd, 0x96ffcbe4, 0xb6dcfdf4, + 0x9061664e, 0x24eb0d4b, 0xff990616, 0xcc9e2fde, 0xeefff941, 0x6a7327be, + 0xff8be063, 0xd0ce7b4e, 0x9af113c6, 0xd78da65a, 0xd5e3859d, 0xa26fcd7a, + 0x66eb619c, 0x26f906fa, 0xdb633f9f, 0x8a3e6db3, 0xd7000ca7, 0xdf6a1d22, + 0xf827d40d, 0xcc2eb82c, 0x4e90c612, 0x6ddc976d, 0xbe7cfec6, 0xdfda3742, + 0xfd71f7da, 0x927a0ab7, 0xa7e44b0e, 0x24224ada, 0xfcb6bf9f, 0x13d7e8f7, + 0x4c98d9d6, 0x72723ff2, 0x30fa2314, 0x4d4cde21, 0x55f50576, 0x5f4e1ada, + 0xc81b1f91, 0x2427701f, 0x3f60644e, 0x763d3299, 0x17576f94, 0x9218b425, + 0x184e7df0, 0x166767db, 0x2aa177d3, 0x34a1ff4e, 0x0c9e7146, 0xff212cd6, + 0x97b72732, 0xe730a6b3, 0x4fee287a, 0x878c76e6, 0x05c9b779, 0xc612feb4, + 0x68bc3425, 0x08e901fa, 0x927be5e5, 0xea48e885, 0x947ec892, 0xb1f39d0d, + 0xeae891df, 0x8ad75c6e, 0x960d5d28, 0xb57441ff, 0x086f1b49, 0xa254055d, + 0x78658f2b, 0xf62552ba, 0x90b3da95, 0x74affd1f, 0x424daf81, 0x6c7e44fe, + 0x4016f1e1, 0x46b7ce19, 0xb16357f4, 0x47a8cb77, 0x63f7c6bc, 0xc13b8fe3, + 0x25ff45ee, 0x787ced03, 0x40b35a8e, 0x3d6375a5, 0xdaefe8bd, 0x5f485b26, + 0xc9e86bde, 0x7d263b43, 0xa401f35c, 0x25f9f48f, 0x6fc86b65, 0x5ea172cb, + 0x714b5d40, 0xfdd3e587, 0x7e808edc, 0x9b668e91, 0xba6b3fc8, 0xdb9f9a6b, + 0x2fc4d511, 0x15560dc1, 0xaef4e0f5, 0xf76455bc, 0x335e60af, 0xf6c771d1, + 0x9c2f18c5, 0xaca2f76b, 0x213c62b3, 0xe7afe705, 0x93a956bb, 0xb5d0f1ec, + 0x5d728bcc, 0xbbb6478b, 0x14ff777a, 0x09437ff5, 0xf183f7f9, 0x7a4642c9, + 0xcbe5dda3, 0x1ebc0648, 0xa78f1bfa, 0x194297b5, 0xf5894f9e, 0xcbed9f6c, + 0x76b94170, 0xdef09583, 0x07ebc1de, 0x49a0801c, 0xfea4a714, 0xeb859258, + 0x81f2a1a1, 0x53699be2, 0x0db7f698, 0xb95a99cb, 0x41d92b6d, 0xe7b7ff1a, + 0x251c7871, 0xc8b43cfe, 0xf1dcdf2f, 0x47f0027c, 0xa68dc61a, 0xb42117d2, + 0xc92e29f7, 0x7cb614cb, 0x648000d0, 0xeb27f162, 0x5b115c67, 0xdfa3ede6, + 0x7ac7af5b, 0xf583bfd0, 0x65e83608, 0x02b3ecad, 0xd11d6b1c, 0x60ec057a, + 0x7c4961cb, 0x3375e4ff, 0x92fe610b, 0x93f43f18, 0xafc61f56, 0x5e374cac, + 0x5c4a7c2c, 0xdfe846ff, 0x77ed6aae, 0x0684cf56, 0xe569960f, 0xb2f9d78f, + 0xbea33fa0, 0xf8a9423f, 0x78da0b1e, 0x63383dcf, 0xa8ac86fd, 0xc2f6007d, + 0x34cf2827, 0xebed613b, 0x60936d35, 0x43f39b2c, 0x4d5fea13, 0x12dd07df, + 0xfcf121d9, 0xbe914b6a, 0x085d7d99, 0xcea575f6, 0x70a5b6be, 0xb2167afb, + 0x2425f824, 0xfc2b83bf, 0xb05bed0c, 0xbeb0924b, 0xcff7b5ff, 0xfdf50d3e, + 0x7272fe73, 0x6eed8a94, 0x557e8f9f, 0xf242a2f0, 0x0e5fb837, 0x9637c04b, + 0x83576e2e, 0xb478a73e, 0x39b73f46, 0x42b8fd05, 0xed6ce30c, 0xa40aa4c7, + 0x73a3f077, 0xf96b03be, 0x665f14a3, 0x9fd4454a, 0x65f79f8c, 0x189e3c29, + 0x5edaae2c, 0x95effd84, 0xeb0bda18, 0x2da74f8b, 0xcdea7f24, 0xdf3145b4, + 0x907e1c35, 0xdfb0d9f0, 0x2f1e2c38, 0x8f09914b, 0xf09e474d, 0x2f78dca1, + 0xa84c912c, 0x68adc257, 0x1bd7d6d7, 0xe56422d0, 0x533705e1, 0x899e7d7c, + 0x65f9868d, 0xdc177d08, 0x2a68637f, 0x93fe1bce, 0xff0ed5e0, 0x3b139262, + 0xb4ec59e6, 0x7b5c514f, 0x99c1e13b, 0xac3c43e0, 0xc0caae2f, 0xcf669a71, + 0x1e5c5272, 0x6fac39ec, 0x147bebba, 0x5ae0d7a7, 0x8d58d87f, 0xd8254ef6, + 0xb806bf75, 0xabaf93b3, 0x8f5f02f6, 0xfe940f92, 0x465bca10, 0xba2fe390, + 0x48b45d39, 0xcbb7d0fe, 0x62c78e29, 0x87b972e3, 0x7d78fdb9, 0x69da898a, + 0x514fafef, 0x8457af08, 0xb923a67a, 0x6d7a571c, 0x99075768, 0xabf403ef, + 0xeeaedf99, 0xf2e275a3, 0xa552bdcb, 0xddc59378, 0xac24ef7b, 0x7f2142bf, + 0x0fbd2986, 0xadfdb8e0, 0x267aef6e, 0x77cb00f8, 0xea1c5095, 0x1e604a68, + 0xb0a56fae, 0x5c8ffb57, 0x125b5a53, 0xf75abfb5, 0x01abc239, 0xf50ead0f, + 0x93946afe, 0x2724289f, 0x33d22599, 0xf869fa1d, 0xfbf5326b, 0x0ea05b07, + 0x86b569fb, 0x420e915b, 0x73b5321d, 0x6374b1cf, 0xe23eef3f, 0xd33b40e8, + 0x48636ee8, 0x50bee0c7, 0xf6e2c49c, 0xd3ca1533, 0x09140b43, 0x5d9c45f5, + 0x49e31d33, 0x29b8b7e4, 0xf82558de, 0xc1503463, 0x42b10b59, 0x5129e7cb, + 0x4ff9e73b, 0x52f82ae7, 0x160c7fb3, 0x319e1f1e, 0xf8e1812f, 0x49c89eec, + 0xdd9bc603, 0xe1ed0c3d, 0xc6894ec6, 0xdc7e2c69, 0xd2cbfe84, 0x41dfce4e, + 0xfe006fe1, 0x58aed072, 0x76136291, 0x77a70b66, 0x147273d6, 0xbe31f9e2, + 0x3b418c9e, 0xb2dfac47, 0xfd69da8a, 0xbc9c4499, 0x4093c451, 0xdafd5213, + 0x58cecd14, 0xc26d9e2d, 0x6ee3e0ce, 0x327c7a91, 0xd254b3e2, 0xe7b573c5, + 0x9277216e, 0x2166444e, 0xbe8046ff, 0x5db4ae30, 0x6ffb7d9a, 0x2bdb7e61, + 0x14d179c6, 0xc93900f3, 0x481ef865, 0x7e5ef011, 0x485983f8, 0x119aac37, + 0x9e1d36bf, 0xfd8a3726, 0xd217b404, 0x581dcd6d, 0x316b7e9f, 0xef8c67e9, + 0x5ec0bee3, 0x3b0cd781, 0x5679eb8f, 0x9f70f287, 0xff84e92d, 0xf8e2dff6, + 0x1f681213, 0xc6d61d23, 0x75cf4c91, 0xb0f2d718, 0x3f51a7d2, 0x32d46a7b, + 0x4fdb4784, 0xd9a8fdc2, 0xa9c72425, 0x7c95ec9c, 0xabf9e07b, 0x01e11714, + 0x846abcfc, 0xed87df17, 0xf4adfdd1, 0x38a5cde9, 0xe11fee2e, 0x5ba33fb3, + 0xeb3538a1, 0xfc8fbddd, 0xf113b37e, 0xb9f87355, 0xd6ff5157, 0xed275858, + 0x2dd9c5f7, 0xf1bc4e3f, 0x03a39449, 0xbeeecee7, 0xcefae11b, 0xd6806f21, + 0x5c8f6f47, 0xcfb7157d, 0x5367dbdf, 0x23dc8ed1, 0x8fd836e4, 0x5fa127c4, + 0xde327f72, 0x45397c8e, 0x960c9fef, 0x2476eeff, 0xf0042f87, 0xef918bed, + 0x0dffe141, 0x444f9fd4, 0x20faf5fd, 0x2bffa03c, 0xed5076a3, 0x2bed1b5e, + 0x7117fa0f, 0x8ff3c8f6, 0x0f4842d8, 0x14ad3be7, 0xfec45477, 0xe44739cc, + 0x8b52444e, 0x284de4eb, 0xbdb7836f, 0xf0032bf7, 0xf7c1d29f, 0xec49143b, + 0x3320bc87, 0x73e37fbe, 0x294feec6, 0x5f1e59ae, 0x3e47ca09, 0x6e2265ef, + 0x48b92cb4, 0x7c32fbe5, 0x62596a5f, 0x53da1177, 0xb43d094f, 0xabef812c, + 0xdd4cb80c, 0xac7baeb8, 0xb429f381, 0x67bfc2ff, 0xb1ab31bf, 0x611d2ffb, + 0x299dd76e, 0x609b7436, 0x1f681d9e, 0xe06dbae0, 0xfb8330fb, 0x1dcdc7d5, + 0x51938266, 0xc455a079, 0x95fdb5eb, 0x571e3ce3, 0xce51f627, 0x10fc59cc, + 0x48b5a96e, 0x9fe8d5cd, 0x8d3f585d, 0xde77d7e2, 0x759e9b3f, 0xf771f4eb, + 0xde99acc5, 0x5a94fb6b, 0x7996bbbc, 0x8e5edc4d, 0x600d11c6, 0x94eba8bf, + 0x7997d42a, 0xe51ab9cc, 0xd5821abf, 0x16cf0c9a, 0x2ed1a278, 0x73b42419, + 0x02775694, 0x16daefae, 0x50a9e903, 0xed87c18b, 0xb8e73c34, 0xd2a91c79, + 0xb01ae3cd, 0x471c6154, 0x4518b67b, 0xb7f45fdc, 0xf1ba198a, 0x73f89069, + 0x1ea953ad, 0xfd6b5f4e, 0x2d9b18b5, 0x648ba718, 0x7dae281b, 0x479be4c1, + 0x22e4e371, 0xb67c0216, 0x55d79a38, 0x9de27af3, 0x9f88d60b, 0xb854afea, + 0x64d4c921, 0x376e9f94, 0xe3c6538f, 0xbe9b516d, 0xd21fbf1c, 0xeb97d610, + 0x464c6058, 0x883fdf01, 0x7376ef7d, 0x7d6175f9, 0xd7b7c09e, 0x9b567284, + 0x8e2caaff, 0x7f364337, 0xcd5767e6, 0x77c83a43, 0x203f2899, 0xabe3c5df, + 0x3f821330, 0x44b74aff, 0x6f0711f4, 0x486d1a0b, 0xdf7cad5f, 0x1fc2abee, + 0xee55f70f, 0x7c1fa134, 0xab67dc1e, 0xdf689a73, 0x24e352f4, 0x72f5bab7, + 0xf7fcb068, 0x9fb967f7, 0x3c8b2ad4, 0xa1c9270e, 0xcb9f275a, 0x48fbc919, + 0x83b7be37, 0x68f3809d, 0x6ed0cb95, 0x9da37e99, 0xdc74d1e6, 0xc6e0714a, + 0xa839bd15, 0x7aaa9bc7, 0x203f308b, 0xad08bf1e, 0x682fc9a2, 0xff06eb57, + 0xd884ed03, 0xc547e476, 0x7efa07ef, 0x3f454ee4, 0xe781cce7, 0xb01d5f50, + 0x7f82be92, 0x38c66d3d, 0xb23c91cb, 0x023ac6a3, 0x305db02b, 0xa3f77ba1, + 0x70b76879, 0xcbb1a9bb, 0x617681dc, 0x3ecc4b6d, 0x06dffe1b, 0x5b1bbefd, + 0x77f14c97, 0x5f7faed6, 0xbbee33bf, 0x6d70fb21, 0x4c5bceb4, 0xefc8b181, + 0x9f6877a0, 0x81835cfc, 0x64ebb7f6, 0xb79462ef, 0x7b7aace7, 0xaf839cfc, + 0x9addcfd7, 0xc22de13d, 0x0f2c1e75, 0x116f6759, 0x819d73ae, 0x69fb6205, + 0xf58675c4, 0xf9d6265d, 0x8b9313dc, 0x3fdf9d70, 0xd708b930, 0xcdb18b79, + 0xa8f37c87, 0x1b90f033, 0xe99bedfa, 0xf70a7b27, 0x2e8f913d, 0xc40f1e95, + 0xff81e3d1, 0xefa47a3d, 0xc787d246, 0xebd0e106, 0xcd49b743, 0x6b507942, + 0x5ea17f31, 0xe361bfc4, 0xc5331678, 0xfa7f8e3b, 0x5047c6e1, 0x64c9740e, + 0x1dfd688f, 0x68050257, 0xd57f1d0f, 0x23490de3, 0xed18bff7, 0x07da0aad, + 0x455c610c, 0x7b3403f3, 0x9f1e5e32, 0xc779f312, 0x7b42abed, 0x8dc6ebfc, + 0x4b3bc5eb, 0xe76e43f8, 0x3cbc95ee, 0x7149dc6e, 0x0b63a6e4, 0x7e27189c, + 0xc6e3cc27, 0x52944f4d, 0xfc21b8dc, 0x2de6374c, 0x89c92eb1, 0xdec347fe, + 0xdb171337, 0xf82e7ea3, 0x5f236fb5, 0x3f7e8b31, 0x99f09de9, 0xc13b3ac4, + 0x71ea157d, 0x42623b9b, 0x7f026fba, 0x9ad4f30f, 0xec49c894, 0x28cdc9b7, + 0xb0fca31f, 0xf2d3ffde, 0x4df876a2, 0x74777724, 0xd7946149, 0x5e40a669, + 0x9635ea16, 0x8b6b3ce5, 0x6ec7d9f2, 0x77f71b9f, 0xbedbfba3, 0xe4c771ff, + 0x4f6ef51b, 0x35edfa22, 0xe5139f32, 0x908776d9, 0xb7c90a67, 0xc2ba778f, + 0xb788ff3c, 0xedcc38ff, 0xef2d0684, 0x0add6148, 0xb9e2d7ac, 0xbd70d7be, + 0xc777de51, 0xb2d8fbc9, 0x14bd2fb6, 0xf6e3d1f7, 0x0ddb63bf, 0xecc7e7ee, + 0x61faeb7f, 0xb96aa5cd, 0x5f5bff7e, 0x327ee21f, 0xb2f2c3f0, 0xeb6afd28, + 0x936fd1a0, 0xeb074388, 0xf483df4f, 0x392c3c1b, 0xe65bbed1, 0x0cbbf4e5, + 0xc4f32dfc, 0x3acefca1, 0x238979f5, 0xaa697ff1, 0xcb07ff9e, 0xeaf8a0ff, + 0x9c9aa915, 0xcdaf7ce4, 0x0fdb8b5f, 0xe24bb3ce, 0xaf37197c, 0x3e353f78, + 0x99f9aede, 0x6f0f2a97, 0xe387841c, 0x0ffcb063, 0xc6b78796, 0xfda465e1, + 0x0f2caf8c, 0x35f797ff, 0x35b63a1e, 0xb40efd11, 0x594fd1e3, 0xf3c8cfb7, + 0xb1fd0023, 0x64b3c5fb, 0x9fef8fbb, 0x7ebd5aca, 0x259d5e1f, 0x5f39e1f6, + 0x4c84f33f, 0xf628d6eb, 0x398f1b89, 0xdeb4d8bc, 0x69f684be, 0x6f4ff7e3, + 0xe1660763, 0xa3efc552, 0x2e7e432e, 0xd4fdf2f8, 0xbcc1d4d6, 0x5bcc3c85, + 0xcbd2aca8, 0x1fec67f9, 0xd66204a6, 0x1c04aabd, 0xdbe86182, 0x725884a2, + 0xa9adfbcc, 0x467eaedc, 0x4c78f7e4, 0xa5e61d6c, 0x7cd8726c, 0x0c78cfe8, + 0x47e8ff3c, 0x28edfe29, 0xc0aa2d17, 0x32ef91eb, 0x21e5e003, 0x95c92763, + 0x8bdda350, 0xdf8b5072, 0x2c7ffd68, 0x592ec1f6, 0xfbd1c7ff, 0x7a65ff81, + 0x53cfc78f, 0x755f78da, 0xe01b6edf, 0x8c17c746, 0xdc45f8e8, 0x4a1bca5f, + 0x33f523bf, 0x9cbf1d12, 0x95217fea, 0x226fa2e4, 0xa25c2be5, 0x4795b19c, + 0x889c60ce, 0x18ab341d, 0x0938c4d7, 0x190dc7e9, 0x5bd26f22, 0x80f29b39, + 0xbf9895bd, 0xf3fe06f5, 0xc8ed91f2, 0xe1f5c1be, 0x88df6476, 0xecf5f3eb, + 0xfe9dbbc8, 0x7d6748b3, 0x6f947cd3, 0xf001d6be, 0x0bf87fa3, 0xd3b4779e, + 0xa773e9ca, 0x2d92e9c4, 0x78a4b94f, 0x7471a7cb, 0x91ffe9f5, 0x8da4b51c, + 0xbdfe5764, 0x125fe8e5, 0x723a7e31, 0xa79e213f, 0x7843d55b, 0xd8931c8b, + 0x76b8989e, 0xe0cff310, 0xaf010cfb, 0xe123fef6, 0xf34c2c37, 0xfbc1a665, + 0x58b35ff7, 0x3e981258, 0x362e5ce5, 0xafb4edf9, 0xf3c9d4d0, 0x30569a5f, + 0x184de392, 0x78c12d37, 0x98b66ce2, 0x428189e2, 0xfb5b93cc, 0x27243dba, + 0x0e7dbc61, 0xffaf3b43, 0xdebe5e35, 0xfec62815, 0x697a2b83, 0xce7da31f, + 0x5587947b, 0xf787f9f9, 0xbc139754, 0x9b704f14, 0x6e25e7f5, 0x0efbe34c, + 0xa69fd3da, 0xe28fbbad, 0xf3d7eff9, 0xdba0e2bc, 0x84b8c4e7, 0xa9b70f16, + 0xd0afb43d, 0x6f1b9074, 0x0f9f3295, 0xd11669fb, 0x69c1d353, 0x653718a5, + 0xb452d69d, 0x6cff2b77, 0xfdefbf27, 0x4f2932bb, 0xe04a68e2, 0x51d7846a, + 0xed16be1e, 0x07185cd3, 0x0ff7deed, 0x708a5b5c, 0x0b6ff26b, 0xfda1cdc6, + 0x1e3e8716, 0xdf3c2cce, 0x51d1e1bb, 0x1abcdc5a, 0xf045b3f1, 0x55b7b321, + 0xef861ece, 0x974f7e35, 0xfa7fd40d, 0x3fb42df7, 0x2d83c9ae, 0x14b01646, + 0x24c8e544, 0x74183f91, 0xaec5fc8b, 0x453f3cd9, 0xa9e2ed94, 0xf71df3e1, + 0xaf3849cc, 0x37ca6949, 0x4a72c7db, 0xac7dd8f6, 0xea0148bf, 0xd0c4f317, + 0xa515874f, 0x22ed8b78, 0x9df3a3b7, 0xc723a226, 0xa7f7c63a, 0x9ed08e80, + 0x33d222bf, 0x59e6093d, 0x057dded8, 0x45f8f7e2, 0x3293ad03, 0x97da45fb, + 0x78f89249, 0x5b7a1b05, 0xc61c60c7, 0xb895caf9, 0xb39b6a94, 0x36f8b70a, + 0xa477fcb9, 0x1737df11, 0xff5578e3, 0x9379e461, 0x5f146cc7, 0x4659cf68, + 0xaffd9379, 0x3ee7759b, 0xb6219fe2, 0xf324f29a, 0xf691ff0f, 0x25071c07, + 0xe7b4de1d, 0xbe76697d, 0x99ea156f, 0x5735b945, 0x2abe49b8, 0x421cfec7, + 0x5569437b, 0x16b0f250, 0x4560cfa3, 0x518ab5f9, 0xbb747f3c, 0x95eb80d3, + 0x0662f22b, 0x6275ff8e, 0x6d15fc80, 0xf3cc203f, 0xf7bd8c9a, 0xaca61fa0, + 0x842abdea, 0x65d071eb, 0xa9b8c268, 0xf144d231, 0x8a366396, 0x2e1ee6af, + 0x282dfd58, 0xd273aee7, 0xd1c0d7fe, 0x6f94b9a5, 0x3d1cf30e, 0x4cef3ccc, + 0xcd4879e3, 0x63945e82, 0x33ea0336, 0xe2f33365, 0x3e2d79e8, 0x7ef802e7, + 0x3a2153b4, 0x0816985f, 0x9e0e7ae3, 0xc09e596f, 0x3c28b7cf, 0xfe58e23e, + 0xdcf12ffa, 0xb7116ec8, 0xfc7c713d, 0xb5f38a1c, 0xfde2122a, 0x51e78b82, + 0x3fa6963e, 0xf7c51087, 0xcd47ca09, 0xae47f63f, 0xf60da0bf, 0x7d3918af, + 0x0eeead28, 0x3bf6278c, 0x7b7f9402, 0x4cb74b65, 0xbece63fb, 0x18d5aa07, + 0xd71b66bf, 0xb9fb4d27, 0xc7ef1e1f, 0xf91e997c, 0xe13ca0ed, 0xfcb0647a, + 0x7a4fb20f, 0x57c7f4e2, 0xde984ff6, 0x53b78baf, 0x21b8fde2, 0x7f5c7776, + 0x5a2bd923, 0x745549be, 0x3b376e1c, 0xa4287b34, 0xb2a9c7cb, 0x166bf38b, + 0x260fff7d, 0x22ff793b, 0x8d6d273f, 0x7d414aba, 0xe28c2ff5, 0x90fe5a73, + 0xaa142f96, 0x213d79e2, 0xb7ce8583, 0xe51b5879, 0xdd628d09, 0xb4714492, + 0xa7df865e, 0x7c10be63, 0xf2d2ffff, 0xcc5dffa9, 0x39264ebb, 0xbf084aa9, + 0x524cf315, 0xf6f0ee10, 0x77de38c5, 0x159e34ec, 0xc8524cf3, 0xcdfe209f, + 0xd4fcf3f4, 0x7f7cf5e9, 0x30f41321, 0x390b3396, 0x99e75a5d, 0xcb555f28, + 0x4cf2d11f, 0x0954bc34, 0x598e677c, 0x5072879c, 0x92d947cb, 0xfb44ade0, + 0x7b0255a7, 0x90d3e71a, 0x784bf220, 0xf90dedbf, 0xaff7a461, 0x8f127f9b, + 0x650f2d67, 0x3d206272, 0x5e7a22bd, 0xd11fcb4e, 0x3d6626e8, 0xc71dae09, + 0x555f3db8, 0x0c79a26f, 0x71475c34, 0x030681c9, 0xd55fbd43, 0x1874e665, + 0x798ede37, 0xfd8dd626, 0xe52b612a, 0xf87a0bd7, 0xd6167b32, 0xbee318b7, + 0x2fee5627, 0x7fde03e8, 0x3d276576, 0xa752ac07, 0x33ce893c, 0x950947ce, + 0x5eb8e9e3, 0x6af31cb9, 0x90123922, 0x0fed84d0, 0x353950d7, 0xa79606f2, + 0x51ae5e7a, 0x8c0c4f40, 0xa096ec8e, 0x2ddb7fbd, 0x99b48cbc, 0x7d3dfa09, + 0xe4a84d76, 0x363be81b, 0x2aa36f24, 0x37e2953d, 0xbc50f4f7, 0x72bbe848, + 0x0cd91f2e, 0xabc79873, 0x9d9b8a54, 0x3b23c8ca, 0x7f9c5ec0, 0xb3eb07b0, + 0x836714cc, 0x53ffa27a, 0x7af1a7a3, 0xcb3faf95, 0x0dfcf072, 0xf9421bd6, + 0x1a6f2a76, 0x911babc5, 0xb29ec03f, 0x7073023b, 0x3d49cf5d, 0x9c3f2277, + 0x25cff99a, 0x0ee7e748, 0xe510b4fd, 0xb02635cf, 0x379187d3, 0xde5c1969, + 0xebed180c, 0x65e7e824, 0xd8fbe07b, 0xf9b6abcf, 0x7cd530b3, 0x1334ca5e, + 0xa1601d1e, 0xff28c85f, 0xb9fac552, 0xd1fb72e6, 0x612fc335, 0x2b1ae81e, + 0xa0352387, 0x099ec8f8, 0x03be95cc, 0x09235ff3, 0x49a986fb, 0x6aa887e4, + 0xcb21fa12, 0x5946b9c4, 0xf82cb7f0, 0x7b2b0ffb, 0xd830150a, 0x2cdcef2e, + 0xdedfe70f, 0x686fe718, 0x5ce94dcf, 0xd591cf4e, 0x6e1f4809, 0xd7df91e3, + 0x26c93ac0, 0xbdf1186f, 0xfb41db26, 0x2a3b4fb7, 0xafd0bd3d, 0xe52ffb94, + 0x26bd5798, 0x71ca5ffb, 0xf64e4d9f, 0xe531fc7a, 0xf52ae94d, 0x21db0337, + 0xe5cd6cfe, 0xbbfd7f18, 0xfd0497f5, 0xfefd7c95, 0x7331fb06, 0x225996b8, + 0xddf00a39, 0x03c0d6cd, 0x16177eb8, 0xb3fb49bc, 0x7a9e6677, 0x4e2bf303, + 0x88cf9919, 0x9c432472, 0x8ebd033f, 0x75cc9ee3, 0xce53f3f1, 0xb113d36d, + 0xf2e9c05c, 0x7da6165a, 0xfcb99af5, 0xacf5e3bc, 0xda17a5a7, 0xaa31e35d, + 0x71fc31bd, 0x5f2faaad, 0xd72fac5f, 0x7f8e3c88, 0xdfdfeaf2, 0xd20a22c0, + 0x7ca7b7e9, 0xfdf62636, 0x2fdf5653, 0x929e8f90, 0xe867de78, 0xfb24e672, + 0xd0852dd9, 0x64ff199e, 0xc9ff38a6, 0x55ff13f3, 0x4e4f5ff8, 0xb69f5461, + 0x82c7b2df, 0x2d9e22f5, 0x1ef1fa8b, 0x264dc966, 0x30fa49b9, 0x473c8922, + 0xb0f1ed37, 0x793bb743, 0x9ada175c, 0x0b439fa0, 0x9a4bc254, 0x42aec0dd, + 0x10b72bfe, 0xbe7469ff, 0x0af40ac6, 0x651ca978, 0x5dfa4049, 0xc36ef463, + 0xb304e4be, 0x5a6ffa8a, 0x96fa85a2, 0xfe90a67f, 0x33356558, 0xdc4f9427, + 0x68654097, 0x44e07247, 0x718c2985, 0xee4235ee, 0x481bf7cb, 0xcc2a567f, + 0xd01b798f, 0x9fdf1bae, 0x3b50b0c8, 0x7c5cd298, 0xf1a8ca7f, 0xf28534d5, + 0x1aec0538, 0xf488c13f, 0x57e0ab7e, 0xb3cdf059, 0xfb8d0700, 0x7141dc82, + 0x05bd5530, 0x632de7cb, 0x70511ce8, 0x629b9cf0, 0x9d8ac1c0, 0xf8bbdf82, + 0x3f8d3339, 0xd2017935, 0x28b710ad, 0x6d0e3125, 0x3ea1a7af, 0x6b5f6466, + 0x07edaafc, 0x76b45b66, 0xcffb0f8a, 0x3cd9df10, 0xdcb84279, 0x47fca668, + 0x7aea5ef1, 0x1fa413ee, 0xaf77af8d, 0x3d7c40bd, 0x3fc5df14, 0x0e75f2a6, + 0x98f7c727, 0x391fe42c, 0xea164c61, 0xaf2e359f, 0x17298fea, 0x4bcff903, + 0x3b407c46, 0x7d58df28, 0x918950aa, 0xe70f36f3, 0x4be76857, 0xb09f7c01, + 0x67c859aa, 0xc8db8cc3, 0x7dfdb5c7, 0xb8c0f5c7, 0x0384eed0, 0x7b7685c6, + 0x436ee6ad, 0x4fe370e2, 0x2fbc7151, 0x6eb1971b, 0x04eb9e22, 0x420e815e, + 0xe13a3718, 0x5e3d1030, 0x4f7bf227, 0x58f1f2a4, 0xa65f3eb1, 0x40d0e810, + 0xfcfa58f9, 0x9da46b98, 0xb6efa82d, 0x20f7135a, 0xe8273ddd, 0x67eda4e2, + 0x3cef6885, 0x59e8bf37, 0x92b3eb94, 0x9120b556, 0x893ac75c, 0x757935ef, + 0x4acde321, 0x1adc832c, 0xbff581e7, 0x7cd4ff33, 0xd759fcec, 0x5fd442d6, + 0x7bc60f20, 0xafc28752, 0x37069fd1, 0xfbd221d2, 0xc1c61d20, 0xbb11d1af, + 0x0b1293a1, 0x88bd8177, 0x047ecd4f, 0x91e7884f, 0xf9d1d9ab, 0xb2cf1101, + 0x3479f334, 0x6bee0884, 0x9e500f5c, 0x0199e5d9, 0x69d6079f, 0x720fa4de, + 0x59ec6c14, 0x76e30630, 0xffb4ef00, 0xede3784b, 0xa7cb2fe5, 0xb58f891e, + 0xfb39a5f1, 0x383a9f29, 0xd5f94ed7, 0x693e45d3, 0x7140deb0, 0xc8abf074, + 0x96626f1e, 0xa9ddca30, 0xf2d5bec2, 0x3c4a8ffc, 0xc27a193e, 0xb18beeac, + 0x59e68793, 0x1dc794ab, 0xb1f3c15a, 0x46e0ed07, 0x9060ec95, 0x0573badb, + 0x765ca5ed, 0xd2aedfb7, 0x24a79979, 0x80b43ede, 0x7db3dc51, 0xe45fa8b6, + 0x58f76b0c, 0x7cd16948, 0x460ef6f7, 0xc8eedff4, 0x594cfaa7, 0x16fdcb9c, + 0x79ed37d7, 0xbf6c4fdc, 0xb7ea88b9, 0x52c78424, 0x87d88f5e, 0xf5fb81df, + 0x7f1fb05f, 0xe3f3479f, 0xb0751c78, 0xa38a77fc, 0xb40cea3e, 0x2a2dfd21, + 0x8118e5f1, 0x3c4cea5e, 0xbaf40a9e, 0x7a6187b3, 0xfa21735f, 0xe6b2d73b, + 0x44050c57, 0x2e905baf, 0x7a078de7, 0xebd1d02d, 0x97054f56, 0x469708db, + 0x5a7483af, 0x17379f1c, 0x76fb6308, 0x9b9fe757, 0x32e83fd0, 0x30de797b, + 0x978c83cf, 0x2cf0310f, 0x6e3c3854, 0xf6782659, 0xc1c4ff13, 0x137c2973, + 0x8ce9a74b, 0xfc48c7f3, 0x90b0ae93, 0x3fca2ca3, 0x4f03594f, 0x7c83b8e2, + 0x0bf70f74, 0xdb2dc087, 0xba6e9e89, 0x0517ef99, 0xe3ef5c6d, 0x8c0651be, + 0x7f8c5b3f, 0x867fab53, 0x96cddb0b, 0xe1ba1e38, 0x1cff007f, 0xabbb3f51, + 0xe6c6f291, 0x8e9e30cc, 0x793473b5, 0xcd53eda9, 0x746fed13, 0x1e6236ce, + 0xfd1adcf7, 0x5bbcd0fe, 0x4dd4fef8, 0xccfdf573, 0xa03e1b63, 0x6cd646fc, + 0xbbcdfc44, 0x8aff5f45, 0x695f7067, 0x3d2bee0c, 0x0329e22b, 0x47c827c0, + 0xb25d4dbf, 0xf3a076f3, 0x292f3f31, 0xcccf38c3, 0x9bbd86b4, 0x8ee8fca1, + 0x6dfe5471, 0x747ff7da, 0x1777eb0a, 0x41867951, 0x90c7e7e2, 0x8acf810f, + 0x2ebe6f2b, 0x89f5112f, 0x4676f7e8, 0x81093def, 0xced0d9f6, 0xf29f3133, + 0xf888673e, 0x5e22c0c0, 0x0724fd7f, 0x55bded4f, 0x8ceaf8a5, 0xe47cc884, + 0xff4b1783, 0x90f30cb3, 0x728be467, 0xb0e353d9, 0xc1f4acfc, 0xfd67d47c, + 0xd705768d, 0xc79329a1, 0x4b17c7a5, 0xe22763dd, 0x7fd12c79, 0x4d579f23, + 0x91322fd9, 0xf154664f, 0xa77bc67e, 0x3b6016b5, 0xf72a79c3, 0x11125a67, + 0x19bf1aff, 0xd9a41f84, 0x27217e8d, 0xd9bdf49e, 0xfafd0292, 0xa717922d, + 0x26f29fe8, 0x9d9817c5, 0xfbf3a79f, 0x6b8c14f2, 0x3cf1f74f, 0xd8ab6dd5, + 0xb6f3b42a, 0xd653e95d, 0x0b74fd40, 0x7a04f5a3, 0xbd206537, 0x2720fe4f, + 0xaecc8911, 0x9e8d77a7, 0x3e746b66, 0xc0cf4f43, 0xfefc76a7, 0x8eb5e4cb, + 0x7a51ad9e, 0x09ce291e, 0xa0646570, 0x5e96f85c, 0x138e0d8f, 0xe3f18fc7, + 0xf027248e, 0x46de562f, 0xbe24ebe1, 0xbfecc2cb, 0x36cbe402, 0xe1c72f8d, + 0x1e864cfc, 0x2b943f3a, 0x01d1c779, 0x0b5e29dc, 0xfe38b9e9, 0xc6cbe0d4, + 0x50d972d8, 0xd14ff0b8, 0xe7fe50ec, 0x9643f8c6, 0x7cef87a8, 0x170a392c, + 0xf1153f8c, 0xf0e1eec0, 0xb99a92ec, 0x867e115c, 0xd268b716, 0x3f587be6, + 0x7e04cadf, 0x7183df8e, 0x285bda26, 0xf708371d, 0x3683ac25, 0xdfd0a09f, + 0x877e2d73, 0x1df6e609, 0xcfd11d57, 0xba834177, 0x811d5d70, 0x279c236f, + 0xe863a10c, 0x3e622d8f, 0xfa065fda, 0x445467f0, 0x37834bd7, 0x234d4f1e, + 0xf9f8d1c8, 0xba27e3c4, 0xf8193d6e, 0x0de7ced4, 0xe712f7ce, 0xb89f6f19, + 0x5f78fa4d, 0x25cb88b2, 0xc570e347, 0x12c35f58, 0xf38714bc, 0xd5bfe44a, + 0x7281bd80, 0x519aa6b9, 0x6ed9243c, 0x669c38a0, 0x27c48c77, 0x48c55f57, + 0x632cd54e, 0x9f205ce2, 0xa63d3c5f, 0x931fdeb3, 0xb7516bff, 0xaf7e442f, + 0xf0f2ebb7, 0x6e3cec6b, 0x1b935ebf, 0xf502b7ac, 0x887960fc, 0x40adef9e, + 0xff7f13b9, 0x1e45cd57, 0x28be4e2f, 0xfbc6b3d1, 0xf9ea0566, 0x0adeeae4, + 0x240f5f94, 0x75c5eef9, 0xe3c0c37d, 0xdcf8f1ea, 0xe2d0619a, 0xa74497c5, + 0x78347cf1, 0xd811dace, 0xf168e381, 0x0f5273a4, 0x38a64f8f, 0x3c81ff45, + 0x4ba067a4, 0x20669a23, 0x1cff3f27, 0x37fc519d, 0xf726ede0, 0x7b9c9aed, + 0x18dce498, 0x5cfdd7a1, 0xbe9cf89e, 0x4e1c19bd, 0x021dcbc2, 0x9e85332f, + 0x2653bf3d, 0xaf86643f, 0xa16e2b78, 0xb2379f04, 0x8fb1f130, 0x8f76a3f4, + 0xa83079d7, 0x63fdb1ba, 0x4bb7d20e, 0xfda3a85e, 0x0cdb31a5, 0x97d18d4c, + 0xba09c363, 0xefc641fb, 0x2795d64f, 0xdaea6674, 0xaf9c3a4f, 0x1eed2fab, + 0xecbfaba7, 0xb95d32f9, 0xaeaa67a2, 0xab57e4fd, 0x7bcbe574, 0x7fb5d3af, + 0xe03df504, 0xccef5bf5, 0xefffbdd1, 0xc79eb31d, 0x232bdcfd, 0x7f7dd3df, + 0x5819c446, 0x0c53d7c8, 0xd1a85ff3, 0xdd5ac5ef, 0x74d660f7, 0x0728954b, + 0x0dc2dff8, 0x1a7d4f3c, 0xbfb62c60, 0x7b7a6d45, 0x508b2662, 0x58535f7e, + 0xcc3376f2, 0x37d7d353, 0xbc20ee1c, 0x013dd97e, 0x0c0bdc63, 0x197d0f48, + 0x858c6760, 0x14b0a47f, 0x891bb3cc, 0xfd6cbfff, 0xd7e1588b, 0x47b37f5a, + 0x5556febf, 0x62b6febf, 0xbc3bfafd, 0x9a4ff5fa, 0x977f5fa2, 0x29febf4f, + 0x4ff5fad5, 0x3fd7ebf5, 0xfd7e9e7d, 0xf5fa0233, 0x5faf551f, 0xfd66ecf7, + 0xd72ee77a, 0xe85e6baf, 0x36fdfd36, 0xd1a07471, 0x0b4f2693, 0x7711ddd6, + 0x19818e1f, 0xa342e862, 0x7afe85b3, 0xdd1a5fca, 0x78dd13f6, 0x8631f4f1, + 0x6fcbbc89, 0x99851f48, 0x7f981740, 0x3f92cc99, 0x1bef3d27, 0xd43a999d, + 0x56e4d0be, 0xf58f3eac, 0x6792478f, 0xf094f443, 0x53d44797, 0xa35b2fe8, + 0x7448f2fe, 0xfd031afa, 0xa06f834a, 0x4ecdd838, 0x0489c70e, 0x887fb76e, + 0x3b439755, 0xe0053368, 0x03e70d7d, 0x3096bfe3, 0xdf1de29e, 0x1c469d63, + 0x43d616f7, 0x422cf9cf, 0xea7300cf, 0x642c7dce, 0x7f88937e, 0x8159975c, + 0x4ade9171, 0x1617a394, 0xf6837a9c, 0xb94c5eb3, 0x4e327ba4, 0x68c97ee3, + 0xb90acec6, 0x26fb87d1, 0x8ab7ee50, 0xa98fa078, 0x9e7c18ee, 0xdacbf115, + 0x57e912e9, 0x7e502726, 0x2577ed57, 0xffb54fd2, 0x99759fc3, 0xff1eae3c, + 0xc35cb35c, 0x0bb09b6b, 0x5f707db8, 0xbbf54aa6, 0xb276aa60, 0x944ebd43, + 0xdf1fd0ff, 0x44d878c7, 0xc2c7b9fe, 0xa29504e1, 0xe3a64c5c, 0xb8eeb474, + 0xcbee78fe, 0x4df0e163, 0x22e59850, 0x02cf1fbc, 0x95de1764, 0xdffd4f99, + 0xe38880ab, 0xfec38ffd, 0x15684a3d, 0xc07fd1c5, 0x5bf471f4, 0xa38a259a, + 0x85e000ff, 0xf5e9c7a7, 0xcad61ea0, 0x33bc05ab, 0x4fbc1db0, 0x184b34f7, + 0xfdbafaff, 0x78c3f60d, 0x7887f83f, 0x59a1e2d7, 0x58668740, 0x603fbdd7, + 0x8f8bcf14, 0x41928e8b, 0x93fe63a2, 0xf7ab9f91, 0x9fb8db28, 0xd4ebd27a, + 0xd1987dc5, 0xbf20e785, 0xbcc2decc, 0xe731b3e5, 0x87bd600c, 0xe9747fbd, + 0xbf2fbe28, 0x31676566, 0x4fd88dd1, 0x7ee57bbc, 0x978acb2a, 0x3ef10af2, + 0xf7cc572a, 0xc7d43726, 0x8762bbf0, 0x90e463ef, 0xcba7eed1, 0xd959ee57, + 0x4678fb43, 0xdad66f71, 0x819c3bac, 0x2fc77898, 0x631d8533, 0x1a673109, + 0xfc37a613, 0xe19d33bd, 0xe54ecafa, 0xcb5fac6c, 0x886c979e, 0xcf4146b7, + 0xd7ba092f, 0x607b36e0, 0x5eb818bc, 0xe8def412, 0x3ce131ec, 0xe8b5825e, + 0xd2b4b8c1, 0xd3fba6e3, 0x1c93716e, 0x83ac41ba, 0x8dd4a0f9, 0x0acc4ae7, + 0x5ec5f99e, 0x832fda7a, 0x64bcf726, 0x76efb864, 0x2435c54f, 0xcdc94d4f, + 0x8fa06ede, 0xc8b4be1f, 0xaf061819, 0x51ecd3da, 0xc5cac42e, 0x5f8532e7, + 0xc64d993e, 0x1e061975, 0x743f93d2, 0x587e6ff2, 0x7e58f3c1, 0xf94603f8, + 0xfc396ced, 0x94f14655, 0xf724bcca, 0x2f422c5c, 0x0604ac37, 0xe8f6031c, + 0x980b0b4a, 0x66b21f41, 0x98d2d3b2, 0x4369e88f, 0x3ade8be9, 0xf65ecef8, + 0xcff462bb, 0xaff8abef, 0x2a3b2c66, 0xf2c7af5f, 0x758fb1fa, 0x1d9a0e62, + 0xde537161, 0xe0af1850, 0xaff7184c, 0x3b6357fb, 0x1f798f7c, 0xe01ef0d5, + 0x574277b9, 0x26dbdb04, 0xeb077d1e, 0x96ddec13, 0xe12ef802, 0x0055e616, + 0xf2dea95f, 0x74f00569, 0xb02f4395, 0xbdf136d4, 0x37ef0a6d, 0xdd26bf7e, + 0x43df87be, 0xfb130573, 0x045efca2, 0xd5233f6d, 0x0aada7be, 0xbea156e5, + 0x8f8141fe, 0xcfe3fb14, 0x303d63e7, 0xad1668dc, 0xbbd4407f, 0x54f78fec, + 0xdd165cf1, 0xff459bf7, 0x97037649, 0xfb132a57, 0x937ebcb6, 0xf56ab7a8, + 0x65f6261e, 0xa8ab7d79, 0xde79db37, 0xeeb7b012, 0xfc62b5fb, 0x2c0c5bb4, + 0xeecf4310, 0x102c09b9, 0x35c91f43, 0xd1b2bac9, 0x3b25cfce, 0xbeea6467, + 0x5bbdfad3, 0x45789b8c, 0x4b3beebe, 0xfb7d38e1, 0xcfa4c9b9, 0x367810ee, + 0xeae99565, 0xacfef3b5, 0xf273b45d, 0xaa7b8a76, 0xaaf3dfae, 0xe072849a, + 0xdd1ae5ec, 0xb7482d7a, 0xd3f23877, 0xbc21bf71, 0xa3353a12, 0xa788b13c, + 0x683d3c53, 0xa553c05c, 0x7b889e72, 0x853959ae, 0x6e807bca, 0x95a1feb1, + 0x82ef2a5e, 0x9fcf0ab2, 0xbc2a3f43, 0x60fd0edf, 0x83f42b79, 0x1fa107cf, + 0xe3003e7c, 0xf866fd61, 0xa09bcb0e, 0xb7df2c3f, 0x7be547d2, 0xb9535657, + 0xca9fa575, 0xa3ce576b, 0x032bdde7, 0xb2b35cf4, 0x8e67ea9e, 0x6bedfae2, + 0xb39405e7, 0x9980bcf8, 0xe7a22aa3, 0x80bcb43a, 0xfef0d30e, 0xb8a3cddc, + 0xfe65cc1c, 0xfe9c2da7, 0xecc89ee9, 0xa34f9d0d, 0xe7e29bdf, 0xa1b191eb, + 0xd55dea99, 0x3bed1c7c, 0xacb10ee6, 0x158c7e4a, 0xea4bf5db, 0x1997ca6a, + 0xcceae3cb, 0x256a6213, 0xfe974ebf, 0x13e90894, 0x5f2f58a5, 0xdfc3ccf3, + 0xe3101d53, 0x3ecd85c8, 0x8a658e9c, 0xc4f31bbf, 0x9d00deed, 0x08bdcfef, + 0x9b1f839d, 0xa62af174, 0xaee2e982, 0xc9d1dbd1, 0x7674ca33, 0x89b17caa, + 0xbeb259da, 0x72676ba7, 0xd5daead7, 0xc7bbcd2e, 0xc518f883, 0xb0de61e7, + 0xb8c0658a, 0xd337da8b, 0xbac5ebb8, 0xbdf97cc1, 0x3e2407d6, 0x3dbf615f, + 0xb5f314ea, 0x3ab9206c, 0x458bc5c6, 0xca032149, 0x9d7ff7c3, 0xc8fafc44, + 0x478a0643, 0x0361658e, 0x5078d7ae, 0x813f58d3, 0x127952f5, 0x9728574a, + 0xf2c65532, 0x7e422c65, 0xab6fd82e, 0xe49b9d71, 0x285643c0, 0x3c0ecb9f, + 0xba91f3ca, 0x8914af49, 0xecd228f5, 0x7c4a6dd8, 0x28dd6f7c, 0xe7f58ff2, + 0x9bf7e295, 0xd32a3957, 0x1fe8fed1, 0xe6cc7f21, 0x42dcf339, 0xe32dbfc0, + 0xef6a7a4d, 0xc30d55ef, 0x787de39e, 0xf2cdf494, 0xfbfac33e, 0x1fde81b8, + 0x2b9c79c6, 0x5e6603f9, 0x08c2a6b1, 0x8c6b09f9, 0x93509c9a, 0xecb63d98, + 0xf331624d, 0xabe56478, 0xec090a05, 0x764de100, 0xe7cc746a, 0xea527f2b, + 0x22a63cc4, 0x7fb93791, 0x8ce14665, 0x7befd1d1, 0xb3141d04, 0xc5ff924e, + 0xfc97836e, 0xe7539f48, 0xdb0b5a77, 0x445e787c, 0x98bcc71e, 0xb5963363, + 0xf96b39d1, 0x23c9326f, 0x4cb5c4f9, 0xc123bb05, 0x7b216619, 0xfc265fb4, + 0xf9091fd7, 0x067d91f9, 0x68e72fc1, 0xc8f9e1f7, 0xe9c8f9de, 0xd49e6275, + 0xfa46ed47, 0xafad3e48, 0x5f7a762f, 0x2e9d000d, 0x22f3683e, 0x6dc50978, + 0xbca03f74, 0x1259625b, 0x20f3c1c1, 0x6cbdb993, 0x42c956dc, 0x1b579eb0, + 0xbf098702, 0x8321eabd, 0x5da1fca6, 0xee898a63, 0x78831f67, 0x6e5e23b1, + 0x43819c2e, 0x1e131617, 0xbf798917, 0x26b1e625, 0x80bfc35b, 0x787cf987, + 0x76e2e09f, 0xcfd6efcd, 0xaa92def3, 0x4b7d636f, 0xa0f94c8f, 0x973cf8f1, + 0x44c4a7f8, 0xf1daf058, 0x70046e3c, 0xa0fc85be, 0x8829dc20, 0xb69fbe5f, + 0xe30a69c4, 0xa97ee039, 0x30f29ab3, 0x7f281827, 0xdf2e9e35, 0xf368f617, + 0x6d3d2728, 0xcf44b39e, 0x73df72d1, 0x7fc8530b, 0xaed67ae0, 0x9f16bcf0, + 0xf78d8d4f, 0x28e2d7ad, 0x413f5f22, 0xdf783bc0, 0x479e38d8, 0xdb3d6768, + 0x24664f30, 0x9590c6bf, 0xc0d7e717, 0x54fd20d2, 0x651f2858, 0xa4e796bd, + 0x8f29529e, 0xe7989e1b, 0xba741164, 0xb9efc1d6, 0x3a37e6d0, 0xd1d1cb8b, + 0x06ff9c59, 0x86de5a2c, 0x2634a6af, 0xabb6bfff, 0x6d75fc8e, 0xc4406a3f, + 0xf4120649, 0x820d47fb, 0x6d9e0614, 0x7dc04aab, 0x1fbe3690, 0x3d75d0d5, + 0xd8f2efbf, 0x285f7403, 0x3d22a9f4, 0x75f689d4, 0xfafef4eb, 0xe201fda2, + 0x4078f8d7, 0x980fffbc, 0x1e5da133, 0x67e7ffef, 0xcbdf7f09, 0xe9bf714a, + 0x938286cc, 0x29b70009, 0xd1b9d18f, 0x74e3f251, 0xa5583bef, 0x26cf786d, + 0xcaf7e12b, 0x0fffafc4, 0x97844db2, 0xdf5f12fd, 0xf13b68d0, 0x2e0afec1, + 0x7d3ff607, 0x28d186fe, 0x7d2572cf, 0x91ae713e, 0x818b77df, 0xc9df787e, + 0xf970f558, 0x0cb23362, 0x5fcf4cdf, 0x8d7b97a1, 0xda4f7b87, 0xd37f9254, + 0x4f3d70b3, 0x84b125fe, 0xf74228f8, 0x83b9a3e6, 0x78dc21e3, 0xe180e36e, + 0xf4b1f983, 0x452cddf0, 0x66f86dc0, 0x1e8678f2, 0xaf2573ae, 0xe1c75da4, + 0xf50b29ba, 0xb4e9f763, 0x0d7c7cd8, 0xc35503ae, 0xf86e2b9f, 0x029a78a6, + 0x8b0e54f0, 0xc22ffaa7, 0xf0d301d3, 0xc04cfcf0, 0xf2cf6ff3, 0xd6862efb, + 0x6dfb437f, 0x1efe1c67, 0xc509b9eb, 0x33fbc036, 0x2fa79fc2, 0x04c2f68d, + 0x05cb3afe, 0xf90b967d, 0x895f25e3, 0x4c9f5f05, 0x0a9d64f9, 0x72c1a94b, + 0x2aef42e5, 0x4a7f7a35, 0xfca010d0, 0x79baf67c, 0x4477f958, 0x990385c8, + 0x3878b0d2, 0xf4f9e628, 0xa8b9b58b, 0xd57dee67, 0xb42e50cc, 0x5efdfb08, + 0xef05a767, 0x88f0d59f, 0x067832e5, 0x5ec5914d, 0x647f972c, 0x8cc3ed51, + 0x6de3e067, 0x6d1be38a, 0xabf9ed3c, 0x0fae62ac, 0xcc6567a5, 0xc574dfdb, + 0xd42f742b, 0x648572a6, 0x7fc6d7ef, 0xce5e9ebb, 0x7692bf75, 0x5f97a703, + 0x4934bd21, 0x1b7e256f, 0xf22941ca, 0xcbee0972, 0xff34029b, 0x43b1e020, + 0xeda78a1a, 0xf9b45e82, 0xe0d7f369, 0x90b95c76, 0x9af1c1d6, 0x41c69499, + 0x17d35ed1, 0xe1ff4249, 0x5c5f48bc, 0x0f73f0a1, 0xfbad0a15, 0xe95329a6, + 0xb101ca5c, 0xdcb91e2f, 0xf83dec34, 0xf76f027d, 0x0f63fc5e, 0x2ea1b5fa, + 0xc00bdd23, 0x8dcf5e94, 0x4bf12f78, 0x0c33dd0a, 0xf78d54f4, 0xe2fd3d1c, + 0xf3b444f9, 0xf2e2ccde, 0x2e2ccdec, 0xca2e070f, 0xe45e74d5, 0x729c8fc5, + 0xce9ffd0c, 0x4d3ec592, 0x039e0f4f, 0xf3c658d9, 0x1ec2eddf, 0x57d8bfb0, + 0xa7dbf08f, 0xc52cc4fc, 0xb21fdbd0, 0x46d704cc, 0x0bcd2453, 0xc98f05fd, + 0x82ec9bac, 0x6dafba5e, 0x939b9cf0, 0xfca9a1e3, 0x8ef68659, 0xe3df8bbd, + 0xe54b3a76, 0x3ee01672, 0xc613ef04, 0xc3ace47e, 0x2f1872fa, 0xc3bdfa3f, + 0xa133d7c9, 0xb2a3df82, 0x383f8ae9, 0x24b89ef1, 0xc7fdd189, 0xea36c83f, + 0x57ada1ce, 0x2cec1cb9, 0x3b41e9ef, 0x2854e42e, 0xfbb3a72f, 0xfbda0b0e, + 0xf2f85f1a, 0x8ad7bcf8, 0x4ed77cfb, 0x39e30e29, 0xd78e8d14, 0x202e0764, + 0xbe046edf, 0xafec9c78, 0xc274ff1e, 0xf314b38f, 0x1eb0275c, 0x9586afba, + 0x87c89c9b, 0x8e8306c5, 0xe6c9aedf, 0x413da374, 0xf3dd93fd, 0x9abb4163, + 0x2c3b97de, 0x7db5cf0c, 0x1276717c, 0xb672a7da, 0x9d79ef66, 0xed8fc788, + 0x7c4ec973, 0x0df6b7fb, 0xda0779b1, 0x73f02df3, 0xcb44c7bb, 0x59febc8b, + 0x0b317ed8, 0xe97683dc, 0x775976e2, 0xc16dffde, 0xda2e8be7, 0x9d8c7758, + 0xf7ca68bf, 0xa2d2bce8, 0xfef4898b, 0xf49f916d, 0x2a4bc8b6, 0x8af0f314, + 0xdfd915e7, 0xc6f7fed0, 0xff5dcbc9, 0x972d48f9, 0xd0d98597, 0x6bd4a36f, + 0xe36a7f42, 0xb9d0bfd4, 0x7fc0b791, 0xd17f36ef, 0x7758533c, 0xed83b8cc, + 0x77595a2e, 0xa8baec4a, 0xbe747704, 0x6b7faa76, 0xf04be7a5, 0xc7874a38, + 0x3a05ff68, 0xbfed0e3c, 0x5adfea88, 0xfd25fc59, 0xffa11f8f, 0xd1fc1d3c, + 0x7de90b7e, 0x47da89ff, 0x272fc06d, 0x78ef57ba, 0x8eebf30a, 0x7cfee99b, + 0x8ab3b876, 0x92fdafce, 0x3bc6b9d1, 0x06f27f8f, 0xb9ddcde6, 0x31c5e4c7, + 0xf9918c06, 0x43f461de, 0xf0867321, 0x79ed291e, 0xcd017643, 0x45bdfe27, + 0x0f313b09, 0x38ac52ce, 0x58593f51, 0xf135784f, 0x93e48583, 0xfad79716, + 0x2672871d, 0xf76a3e46, 0xf62bbc85, 0x0b60ff8d, 0xc0aecc2c, 0x8157f732, + 0x9c623773, 0xd961e1ad, 0x7421efc9, 0xc5a23f91, 0xf3f415bb, 0xe3d4300a, + 0xe3fe7867, 0x4b03723f, 0x0e7e6e91, 0xdfe300e2, 0x01bd84f2, 0xff0a4f8a, + 0x8f6b3eef, 0xf7231bc7, 0xdf2b6456, 0x8b6fdf4c, 0x7f1537d3, 0xeb9ba47a, + 0x8f38159b, 0x57e7b946, 0x8e7879b5, 0x1bdc57a9, 0x5bdd92a5, 0xee927e5b, + 0xfcd5ab97, 0xfbf175f9, 0xb42ed9ec, 0x7cf8b583, 0xa13fe622, 0xf3c8dfbe, + 0xbc6cebef, 0x14fbf75c, 0x4789cf3a, 0xef104a45, 0xdf97b29d, 0xfc24e82b, + 0x0f30179e, 0x20e63658, 0x9e04077e, 0x433d77cf, 0x5f9e18f7, 0xa0e89a37, + 0xa53f37ee, 0x640ec97b, 0x63acfc8a, 0x7543d20e, 0xde256f66, 0x93207793, + 0x4a9d9bdb, 0x8c596277, 0xab36b9fd, 0xfbebe48a, 0xd01b46eb, 0xbaf0d73e, + 0x8d85c853, 0x89503c5a, 0x6dfde254, 0xbf7797ef, 0xa0f07a4c, 0xc6e77e95, + 0x4a93e870, 0xa3714fba, 0xafa5ee99, 0xcb76343a, 0x2c6fa83c, 0xa8be5032, + 0xe09590e1, 0xdf9eb739, 0xa2df84ef, 0x343c6ebe, 0xa80f7e8a, 0xbca116ce, + 0x6f04c6ae, 0xd497ee11, 0xdd16fa1d, 0xbee67f27, 0x372839b1, 0x39aaa74f, + 0x7dee7f74, 0xf7987480, 0xf86363e9, 0x74c9d6fb, 0xd1b1d25e, 0xae2e1816, + 0xf893e9a1, 0x640ea3fb, 0x461ff696, 0x78b58cfc, 0x917940f7, 0xb8b03f76, + 0xf9eeac0f, 0xf3151cc8, 0x557f85ac, 0x33ef7f67, 0xfdadf7ba, 0x3d385bcd, + 0xcd027df3, 0xb71f8b3f, 0x039de84e, 0xfc7cc8a6, 0x35baa67d, 0x9e26ff02, + 0x28675687, 0xd327dfa5, 0xee31bff0, 0x0457d57e, 0x99e7b5de, 0xb7ba1517, + 0x1c81ec0e, 0x733a57dc, 0x76f44cdc, 0x3a78e366, 0x578dad2f, 0x0271b807, + 0x564e9e9f, 0xfefae227, 0xbaafc859, 0xd4efdc35, 0x3619d7de, 0x477ae357, + 0x6f94c98e, 0x248ce033, 0xd6887ee2, 0xce0f2b4e, 0xdfa64ba7, 0xf9903a19, + 0xd03bad34, 0x32ba4315, 0xfa41c6fc, 0xfe1bf836, 0x97ef457b, 0xf50d90b3, + 0xf266abf4, 0x331c4ed3, 0xf03c1d93, 0x3b773f1a, 0x7b2f1ee4, 0xadef0724, + 0x1466fe0c, 0xec81b5c9, 0x376e6ec8, 0xb8dee95b, 0xc9815381, 0x432cff62, + 0x81978bdc, 0x6385daf6, 0xd7b46ed6, 0x20fb49e0, 0x43d7b621, 0xe8db8fef, + 0xd2780ffe, 0x1d260939, 0x9cefd0f4, 0x7df136b0, 0x677f7d0f, 0xca0c604e, + 0xa00b3be9, 0xdf7e3b7f, 0xe42eed47, 0x19612607, 0x78c532fe, 0x766fd499, + 0x4bde9720, 0xeff8791f, 0xfa89b47b, 0x9a0faa1e, 0x1e699303, 0x8eb0767f, + 0x4df9e661, 0x2f7b7fef, 0x9be4853b, 0x99e03706, 0xbc78bfec, 0xe20c7278, + 0x3e385df7, 0x7072e9e2, 0x3e04bf3d, 0x5f90a78c, 0x71d7c5d2, 0x971358fd, + 0xc9e3ad27, 0x431ba5ce, 0x569af262, 0xe89b7b1d, 0xdbe8c072, 0x72297a8a, + 0xbdf8c8ca, 0x6019606a, 0x6f0a619c, 0xfce36757, 0x9ef1c1a4, 0x686e6fc8, + 0xef4f79e5, 0x9cede2fd, 0x273c7605, 0x9ceeb6fb, 0x83f716ac, 0xae31124e, + 0x89aaf762, 0xdedc25b5, 0xfe2e0996, 0x8d1b4dfb, 0x554efd2a, 0x14b1bee8, + 0x5263384f, 0x8ebdd10f, 0x901827eb, 0x5cbd5a9e, 0xf8da84f6, 0x9afbb4bc, + 0xe2977bb4, 0x9cddf2f1, 0x38bbfe02, 0xde2b702c, 0xa99a7dd9, 0x8db36269, + 0xc7ab9fee, 0xebca017f, 0x2b3e0d0b, 0xbd25bfcf, 0x379ef430, 0x8efc97d3, + 0xf96dffd5, 0xe68cb907, 0x250dead9, 0xc77d5ea2, 0x583efdc9, 0xbbf4953d, + 0x7749e7cc, 0xbea066e8, 0x939adff6, 0x0724f54a, 0x7d7891df, 0xf2699d3c, + 0x903e086e, 0xfc5fb06e, 0x3dbefa0e, 0x48d5c787, 0x79bde058, 0x7ba2642c, + 0x0abe8461, 0xcf018a4a, 0xd4b9f775, 0xbecba444, 0x55e482d6, 0x52e0a798, + 0xe862cad3, 0xa32cf824, 0x9e2accf3, 0xbf8c984f, 0x889be273, 0xc903bcf1, + 0x3c4238fa, 0xeb4f8f3c, 0xff5b1f9d, 0x772e1cd3, 0x1fb8735b, 0x261cebf8, + 0x3c78feec, 0x22583a72, 0x1bd5a0e8, 0xcafc8ab8, 0xb64b76b8, 0x88fa0925, + 0xd4f6df7b, 0xcabe533f, 0x85bdfd4e, 0xde3d6235, 0x9214de79, 0x8133e126, + 0x37eb8df2, 0xff577973, 0x5dd14d42, 0xfce74cbc, 0x4ddc75a7, 0x70b30fbf, + 0xc622cccf, 0x8bad17e5, 0x730b9f46, 0xdf68457c, 0x4ecbb645, 0x6dfa93e4, + 0xaad3c132, 0xc3b659b4, 0x8cdbb3fb, 0x0bd5f764, 0x0566ce78, 0x14dd6912, + 0xef0098a6, 0x22409567, 0xc5dbb5d9, 0xcdc4e0ef, 0xa2bdda03, 0x1f830d94, + 0xc2675f0b, 0x7430c14f, 0xeb40ca70, 0x898130b4, 0xe89347df, 0xecd9c79c, + 0xee58adc0, 0xee9e7f03, 0xa06b6e9f, 0xf1e2557b, 0x2012d67d, 0xe6225d7a, + 0x7e33e1a3, 0x039f0d1c, 0x9fb44f88, 0xfa41df9e, 0x8ca0f82f, 0xee9ecc14, + 0xecfc90fa, 0xbe66c769, 0xbf7c2df1, 0x1518ec19, 0xcbfe6df5, 0x077d47df, + 0x98ed0a72, 0x690563da, 0xa36f4e2c, 0xd2fb593f, 0x8c4344dc, 0x976d6cbe, + 0xb5a59f69, 0x22e24e70, 0x06fe7f6a, 0xaad3afa4, 0xa62cad37, 0x9a392bdd, + 0xaf5fa93f, 0x4d7fcdba, 0x37ea71c4, 0xda5e6918, 0x4c000cba, 0x6cdb8724, + 0x81ffa461, 0xabf508ac, 0x7d20d3ad, 0xf4683ae3, 0xcd3eed04, 0x78718a71, + 0x2f2fb6bc, 0x861de950, 0x003f164e, 0xdb7f62e3, 0xe69f741c, 0xe1ab8ea5, + 0x05bd7063, 0xd719535f, 0xc51e7771, 0x14a70dc7, 0xdd3f064a, 0xf20e4d76, + 0x07d81d71, 0x93a88718, 0xbdd06f22, 0x74ccc7a6, 0xe6dd6fef, 0x78e2b7a5, + 0x0d99af75, 0xfc77df58, 0x5704899a, 0x9e02badc, 0xf7a38672, 0x8e48bc81, + 0x607f0637, 0x6b7f1057, 0x9b8189f3, 0x8b3f00e0, 0xc819c5ee, 0x918cf583, + 0xe1cd7f03, 0xef681af1, 0xf37d1134, 0xe706997b, 0xaf9b8ceb, 0xafbe6e33, + 0xe66fa230, 0x167cd00d, 0xe0366ebe, 0x5ff785fb, 0xb771845f, 0x69d3f5be, + 0xbec97d5e, 0x7d5fc889, 0x30ffd039, 0xfde172f2, 0x2f92cf30, 0x959b6798, + 0x79c46bd6, 0xb3764726, 0x27a7982f, 0xb7cf3f57, 0x7e913514, 0xcc88e34f, + 0xcc128e30, 0x16fc6ff6, 0x97efd32f, 0x1e9c8d05, 0x746d9b82, 0x8bbfaa2e, + 0xc9af8fdf, 0x12ef1801, 0xf440c1e9, 0x6ea557d0, 0x75f48299, 0xfdc4ec9f, + 0x97f5be8a, 0x2fbf8cbd, 0x7651b7d7, 0x57d0dda2, 0xf207f1c5, 0x5f78f480, + 0x2a06ff8e, 0xefd2371f, 0xfb699da4, 0x3ee89feb, 0xfa466382, 0x3c81e23d, + 0x5879c6ff, 0xae517806, 0xe26e5e01, 0xe691ab76, 0xc1eebadf, 0xda1f5875, + 0x6fce8936, 0x7ad7d50c, 0x906fd73c, 0x14c87c75, 0xde0bc695, 0x17ee8a3f, + 0x120cf0d1, 0x23fd08b6, 0x9e581f0d, 0x978a213b, 0x8f7f38a0, 0x8fbf0276, + 0xc433c84b, 0x13d73e4f, 0xe5058e78, 0x19a79e18, 0xcbc55f49, 0x7bbd789f, + 0x4fb6ae63, 0x0dc797a9, 0x79afbf71, 0x69795c5b, 0x1658dc9c, 0x5718df57, + 0x86f9fa0f, 0xcfd2e2e1, 0xa2cf8e0c, 0x1a21927e, 0x4fb81d1f, 0x56b4bf22, + 0x07e84d51, 0xeb8d3e3d, 0x59853ae7, 0xe4be22ae, 0x156a73e7, 0xc32e62d6, + 0xac535ef7, 0xb5fd04bf, 0x9ca19398, 0xb410e5c0, 0x94c536ab, 0xc1ab7935, + 0xa3c04ab3, 0x9c76bf3d, 0x7dc466a0, 0x15b9558c, 0xca31f743, 0xbf5ffce4, + 0x11d67e88, 0xe0ccfc99, 0xb0ff5c0b, 0xf2dc3f4f, 0x3bef1b98, 0x323ca02e, + 0x78f1fe6d, 0x61fc381c, 0xe4defd22, 0x5f3a26f3, 0x5295db5e, 0x72587e45, + 0x6fbc5864, 0x44fae5cd, 0xe95fafeb, 0x6b1d9c4d, 0xc4deb347, 0xadf7dfd8, + 0x4ae1fc3d, 0x7f016bf4, 0x8e463921, 0x5a96399f, 0xdd65fe85, 0xf0ab32ef, + 0x5cd1efbc, 0x3ea00e2d, 0xe6f901bc, 0x13e29988, 0x33cc2ffd, 0x2ffdf7e0, + 0x9de78bd4, 0xff609f74, 0x7072675b, 0xfe8344fc, 0xcf7f89be, 0x9d54f6e5, + 0x57ddcde1, 0x9a3ffca2, 0x2626b79e, 0x28675d0e, 0x31f8bf23, 0xc23e6463, + 0x3aff760d, 0xfad503cc, 0x12ab9a39, 0xde47fd1c, 0xe1f28dde, 0x32ecc6cc, + 0x47fd2b14, 0xdc1f90c6, 0x4565daff, 0xff6b5f78, 0x945e197d, 0xd5198f0b, + 0xe2dfb93b, 0x8bc9eef0, 0xe0e387f6, 0x91ff63fe, 0x3f1895c9, 0xc38d7fe8, + 0x278a650b, 0xe610bb40, 0x26fd6a5f, 0x984dd41a, 0x677ece8f, 0x8ee2bf24, + 0xf1d20acf, 0xd344957e, 0xa050f7f0, 0xc3cfa11f, 0xd6f34d5e, 0xfde37df2, + 0x37ff2d0c, 0xeed30fde, 0x17f78f8b, 0x3ddb59eb, 0xef1c9798, 0x6e618237, + 0xdf89a509, 0x4ebfa733, 0xf74bf7d2, 0xdfd66e7f, 0xf6121d9f, 0x71e48580, + 0x7ae3f02d, 0x79853f8a, 0x3c9d6fdc, 0xc5ec7eec, 0x6fa76e5c, 0x7e6dfdb5, + 0x9ebacc6f, 0x03c53036, 0x626d3d78, 0x70d94f16, 0x9c85e3fe, 0xc37b925a, + 0xb1758dfb, 0xa1b1d6f7, 0xaae9e47e, 0x9df9e530, 0xefd32f5e, 0xf5c3c459, + 0xf8c8fd55, 0xebdfb5ef, 0xc4ed04f8, 0x00938c54, 0xe45fc9a4, 0xd5e1eb3f, + 0xbf1569f0, 0x01fff2a3, 0x949113dd, 0x00008000, 0x00088b1f, 0x00000000, + 0x7db5ff00, 0xc5547c0b, 0xbddcf8d5, 0xc3764cfb, 0x083c8426, 0x813bcd84, + 0x44902c24, 0x8f2ed4ac, 0x0310f0c4, 0x5850822a, 0x89de4020, 0xc5b0fd60, + 0x40802166, 0x151a86d1, 0x260dda2b, 0x22ec1208, 0x760d1201, 0x4a888941, + 0xadb45503, 0x202a25f2, 0xd4109204, 0xeb6bfe8f, 0x73339cff, 0xd0820fb3, + 0xcfe8fbf6, 0x99dee64e, 0x7de733b9, 0xfd999cce, 0xf7f87bfe, 0x17bec613, + 0x62a2d9a5, 0xc963106c, 0x2d9990ff, 0x43b2b194, 0x891ae71a, 0xafdac0b1, + 0xf50b999f, 0x398d16ee, 0xf958c2c6, 0x6726d921, 0x659ac630, 0x3e0c4267, + 0x08a822ff, 0x8f3797de, 0x33cccb31, 0x9cb3795e, 0xac654ce7, 0xd86ae9ab, + 0x671a54e2, 0xfd88c5ba, 0xa1dab69f, 0xc2acc834, 0x57b4f465, 0x4c8b58ca, + 0x69de28f3, 0x9932fea8, 0xe1efbfd1, 0xb05752bf, 0x29bcbd4f, 0xbd4bfab2, + 0x7f8c5ea7, 0x367fc244, 0x8c5967a6, 0xec57f095, 0x6187ea72, 0x5dde6053, + 0x1912e7b5, 0xb2a8d12c, 0xa1325ac7, 0x169df89e, 0x67b58ceb, 0x7e6899e5, + 0x67981641, 0x20dbf3b7, 0xb7d2f306, 0xbf9c36c8, 0x2c32fcff, 0xff32c65a, + 0xc2e5f983, 0xf33cc2fc, 0x5864f983, 0x59e67906, 0xb2d1e966, 0x3e879858, + 0xc48d9d28, 0xa369b616, 0xfc22fda0, 0x6a2fde13, 0x058d3c59, 0x79a93631, + 0xe0031ac9, 0xb25abba1, 0x7e79e0ea, 0xf00dc00b, 0x764dbf90, 0x932f005a, + 0x311d5692, 0xd3f17d40, 0xe6ba1ef0, 0xcf4ee3c8, 0x9ecbf686, 0xb87ea990, + 0x1ad391f6, 0x0d36ebc4, 0x031e21d3, 0xef8bb682, 0xa15f9c31, 0xcb615f98, + 0x7c120bd4, 0xd921d96f, 0xf5fec6ea, 0x5f3e2b26, 0x79f341bc, 0x96fad7bb, + 0xde301fe0, 0xd392ad92, 0xa92de30d, 0x95df7df6, 0x38b2d0e9, 0xefd5bfe8, + 0x99faed79, 0x54b14247, 0x51d60933, 0x8f7df4e8, 0xf986deff, 0x77bf8b94, + 0x8c1e6c26, 0x3032e9f8, 0x61f806d6, 0x8630f6ea, 0x1a3dbba5, 0x7cd5d8f1, + 0x58f11a36, 0x24fffafe, 0xa7f07eb2, 0x14c5ac94, 0xe0102e7a, 0xf7d89169, + 0xabfba42a, 0x69faf3d3, 0xe7087a3f, 0xc71a9d8b, 0x3fbc2b60, 0x746dfb52, + 0xb349d23b, 0x1fb9987d, 0x9f1bedfa, 0x08aa0c39, 0x8606dd2c, 0x3ccb8665, + 0x4de4f905, 0xd213798d, 0x33f5f6c7, 0xf0dd43b7, 0x00660686, 0xf12304f5, + 0x12c7f20b, 0x3e1571af, 0xd9b129d9, 0x99426654, 0x6892f38a, 0x930fdf5e, + 0x1e771e88, 0xd09e9dee, 0x69867cdf, 0x21e8dda8, 0x347dda8c, 0xd2356f2c, + 0x11ca805b, 0x3660f884, 0xe014259b, 0xaafa092b, 0xe121595a, 0x4d5608f3, + 0xa2e610e5, 0xecc605f2, 0xaccf6c46, 0x63338466, 0x7e118343, 0x5eb4f3c4, + 0xe6e90abb, 0x9b770267, 0x8e0f4e24, 0x87ace660, 0x3d5ae5bf, 0xa6300793, + 0xd841ed65, 0xf33694c9, 0xbde0c3d7, 0x255943e6, 0x43c8bd01, 0xcd5a7c15, + 0x8c6fdf88, 0xc6f00df7, 0x17f7e1df, 0xa578e2e5, 0x83a665fb, 0x6a372ef1, + 0xed88db98, 0x9da05f81, 0xb5affde6, 0x5a972831, 0xeb009624, 0x3e3a8728, + 0xb6a71f2f, 0x52e0bd39, 0x78f0e16f, 0xf04892da, 0x8edb52e8, 0x33fa434d, + 0x2c3ad22f, 0x2e7e4e38, 0x11347183, 0xaf38b48b, 0xd04fefc3, 0x82de20c7, + 0xeb37c4d5, 0xb6ef945b, 0x64fc7199, 0x78f329d5, 0xa993df78, 0xf1e1db66, + 0xcdc6a3f9, 0xf7ca47c8, 0x3f1c2cba, 0x12812b67, 0x97cf3c92, 0x8397dc64, + 0xfb3297fd, 0xa5a3a47a, 0x7b733235, 0x0d79fdd1, 0x6b92f7c7, 0xc63dcc81, + 0x4cc45fab, 0x6b92d75a, 0xbcfcf441, 0x6f3bb781, 0x9ef174e2, 0xc7c5d385, + 0x885fbbe2, 0xaf2dbffa, 0xeaf2beac, 0xef1f0bf2, 0xd6e5c458, 0xa547487b, + 0x44ce7b52, 0x88fac4f8, 0xf5ca2d5e, 0xe66695b3, 0x3ad0fdd6, 0xd7b73207, + 0x5ddafb77, 0x40f73033, 0x6859b86f, 0x1af59efe, 0xcad9fde9, 0x31c09b88, + 0x9e8e07ca, 0xe07ce3f1, 0x89f8fd78, 0x656cfef4, 0x1fc64df2, 0x63f18371, + 0x19efe67c, 0xaf9e9e37, 0x20b1554d, 0x9fb5aba0, 0x6cc49ce8, 0x74a7ae7a, + 0xbad6ef82, 0xfd2de927, 0x4d83aff0, 0xe163628a, 0x8b9ca37d, 0xbcd97c74, + 0xae7c8cc8, 0x74b90609, 0xd8d7f41b, 0x7180ef72, 0x0321c175, 0x5aaf7e91, + 0xdf5d68e2, 0x1d105706, 0xb4743b7f, 0x8fc188ec, 0x7d61e454, 0x997c90ed, + 0x59fab378, 0x7ae5f392, 0x21d37dfe, 0x9fe44a60, 0xaf42f5db, 0x18bcc9ff, + 0xd43553be, 0xf4c98fae, 0xf994c7cc, 0xb33c4336, 0x9430fb26, 0x819b8f03, + 0x801f896f, 0x5abd61af, 0x3bbbfec9, 0x9fd81f80, 0x8a1eac75, 0x24f60d6f, + 0x471f17b3, 0x09fd70c4, 0x728510dc, 0xa86ac1d1, 0x4aba6f2c, 0xff00b670, + 0xf794bae2, 0xe087ace5, 0xc2cd7c8e, 0x16d52691, 0x4f64df7a, 0xccf34bca, + 0x78eecfa3, 0x0150e8c7, 0xfd0ee9ff, 0xd9e10823, 0x6e99eead, 0x22d5d285, + 0x77c37a07, 0x8fe70c64, 0x4ebf4309, 0x65e7876f, 0xd3e40fd8, 0x27166f23, + 0xd329fca1, 0xbce3a4f5, 0xf7f9bc8f, 0xdff79474, 0x861e2a1e, 0x7b4277cf, + 0x3db413b2, 0xf1af5665, 0xa1d999e2, 0x9329eb1a, 0xef88e263, 0x3cef9ffc, + 0xe7183554, 0x886200d1, 0x5677c085, 0xe5f717be, 0xdb072440, 0x18672853, + 0x0b7a97c8, 0xcaf74dda, 0x3eca5728, 0xea04db02, 0xbf5ccd19, 0x4e650c67, + 0x67da0c55, 0x7c46cd1f, 0xcd6a6595, 0xc04a582a, 0x1ae736a8, 0xa9901f78, + 0x1d1ea337, 0x5f7f843e, 0x0e3cfa8b, 0x440f67fb, 0xe414fdbc, 0x0f247fec, + 0x2becfcea, 0x06b2a9f7, 0xdca95ef8, 0x00e51d3e, 0x31e985c8, 0x07d97e30, + 0xb5489f5f, 0x309e8b60, 0xd0b74fc4, 0xe3127f3f, 0x37931a3c, 0xfbaae913, + 0xe3d777fe, 0xbb2437a3, 0x88e3d71d, 0x5f515bd4, 0xec6708b0, 0xcebc2f4c, + 0xba09518d, 0xba01ee01, 0xb6e62e1d, 0x796bb067, 0x6725e930, 0xb943d208, + 0x1e51d98a, 0xd40069b2, 0xf32e91db, 0xf5a666d2, 0xd0d79fa7, 0x6c62cb78, + 0x4abe708b, 0xcd668ffb, 0xc3f7b34d, 0x04a94887, 0x21ebad4f, 0xa94f679c, + 0xf01dbad1, 0x82be21f0, 0xd2cd2f7e, 0x93b065b9, 0x0dc635ba, 0x27d1d012, + 0x075bf381, 0x184ffac1, 0xceb815ed, 0x5e4c0fd9, 0xc8e9758f, 0xa472cb40, + 0x59ed85cb, 0x06399788, 0xbef8c3fb, 0x161f6f44, 0x3cbc4b06, 0x00349ed4, + 0x40de6a95, 0x97966f0e, 0xfcefd796, 0x753c7cf9, 0x54b7fa46, 0x31b7a5c0, + 0x49d9006e, 0x67480daf, 0x152e9f30, 0xd0fd402b, 0x15fbe625, 0x25e623e8, + 0x279c0ba7, 0x7da10bb5, 0xed49dd61, 0x97f5af22, 0xeae08582, 0x3a7a2ec7, + 0x1745db86, 0xdbfefdf7, 0x9d50c05f, 0x44481cdf, 0xba58b5bb, 0x76faeb44, + 0x62f9c9d7, 0xbeb8d57d, 0xa27b7a47, 0x12aeb0b5, 0x972d61d7, 0xea7d621f, + 0x5a1fc49e, 0x2daa975f, 0x80e2e887, 0xf18fae64, 0x3c6d2bf4, 0xf4051399, + 0x3c17505e, 0x9674e65a, 0xe8567488, 0xd1788f84, 0x028e32b1, 0xde42e59f, + 0xf014aef5, 0xb676e009, 0xfbe51f02, 0x33e0fc67, 0x8d93dd5f, 0x2abf98f3, + 0xa9e5c558, 0x7947e893, 0xefa560bf, 0xfb14ab77, 0x49c931e7, 0x7ebc66f3, + 0xdcec11d0, 0xea9d7504, 0xa2f787ea, 0xb2a690dd, 0x2db0dda2, 0x68c06400, + 0xf028fec6, 0x07c802f3, 0xdf3d087d, 0x0223cf80, 0x6788ff78, 0xe82ace54, + 0x99a1379f, 0x32a5f0e8, 0x6f8655a3, 0x98e0642d, 0x331614c0, 0x67d9d91b, + 0x50fdffc7, 0x68f3ac3b, 0xf08ddd8c, 0x1550305f, 0xc3cd21fd, 0xda06623e, + 0x1c38e36f, 0xfd17b3af, 0x99933fe0, 0xb1e46435, 0xfbe42acd, 0x94be6699, + 0xe3e71225, 0x834d997b, 0xd99fbbdf, 0x2ea9dda9, 0x93fd0dad, 0xc15be853, + 0x0e601fbc, 0x39873e7a, 0xdccb9ca9, 0xaca7fed4, 0x1f0aea9d, 0x082ffd00, + 0x3e7ff4e5, 0xf9ba265c, 0x327de718, 0x4ae87d30, 0x678cc758, 0x5fc81293, + 0xf04419ab, 0x67bcd9b9, 0x8f8e1c48, 0x71dbd8c6, 0x6fdcde9c, 0x7181ac5e, + 0xd1377a54, 0x989c9f5f, 0xe1d04834, 0xb689cb0f, 0xcc7f3ede, 0xb8700918, + 0x2ef4a04b, 0x63f9315b, 0x3991b2d9, 0xe36d3f00, 0x53fa2764, 0x43ab6cc7, + 0x93aa6543, 0xcab36d5e, 0x59dff7a4, 0x50194ccd, 0xc694677f, 0x6b74455a, + 0x5d3c3d23, 0xcd7d978c, 0x7800f6fe, 0x586e5d3e, 0xdcf50c1b, 0x790fe021, + 0xd0e4d5d1, 0xb3e46abd, 0xcfbef129, 0xfafaa5a7, 0x6ab3774d, 0x3d3be119, + 0x61ddb7c3, 0x95d00b84, 0x3ffb962a, 0xfe1b386c, 0x8fe1ecbd, 0x31f9147b, + 0x1bb6aaed, 0xd62631e6, 0xf585886e, 0xecfbbf2f, 0x532efc7c, 0xa0c60fb3, + 0xb3213a5e, 0x73fef04d, 0xd81b13e0, 0x82565f4b, 0x397e0306, 0xd61ff607, + 0x0d3b02bf, 0x16958bcb, 0x5d812f2a, 0x2abbef85, 0x207f54ad, 0x16242f36, + 0xc368bf40, 0xed1db515, 0xfa2ceafe, 0x5f410afe, 0x2ab72a6d, 0xbb67f910, + 0xb87d4564, 0x2136d0c2, 0xa2b6e010, 0x180ac63e, 0xae4d4566, 0xbe7e9c56, + 0xd1072f3b, 0x4558f4b8, 0xd7a5962b, 0xd2076624, 0x8bce417e, 0x3ebbf1c6, + 0xddd67cfc, 0xe57cfcf0, 0x85fefa58, 0xbf7d1b4a, 0xca9732b3, 0x3c7b588a, + 0x74b5b3b6, 0x20b40eb4, 0x7d10ae36, 0xa1d0dddc, 0xb67a828e, 0xdf21b24d, + 0x4e6369dd, 0xab75e027, 0xada9eb86, 0x0f90a7a0, 0x7ccda7c7, 0x7a8661e1, + 0xe38e9ec4, 0x30a53fdc, 0x3e99c71b, 0xdb1aa176, 0x631df03d, 0x743c6303, + 0x65ba3376, 0xf2fc727e, 0xddd1129b, 0x1ee59565, 0xc71cabb4, 0x7a0fb265, + 0x185530d5, 0xe193f7bf, 0x74e0074e, 0x70b8fef9, 0x35cb6794, 0x2f10f096, + 0x27e9d639, 0xdcf73ac7, 0xdfade116, 0xdf5c433a, 0xd0e505fe, 0x810e5c67, + 0xb7ee74a5, 0x118ca728, 0x976fc456, 0x520043f0, 0xcb8fa881, 0x406f82b4, + 0x33bd608e, 0x83c82d80, 0x51abd67a, 0xf00f9013, 0x8f24967b, 0xf57c499c, + 0x585fd8d9, 0xe9dbdf3c, 0xdf97f25a, 0x53b2fd42, 0x5e80d0e5, 0x5d5cccba, + 0xeabae3af, 0x17b4568c, 0xc0752593, 0xefec10ca, 0x964bbe24, 0x2095ea2c, + 0xfabd7647, 0x19e7e0c2, 0x8d8c09da, 0x6c6ff785, 0xf3392409, 0x667ac686, + 0x817ff625, 0xc9f97ff7, 0xc26f3f47, 0xd1d289f2, 0x1059428f, 0xcd70421b, + 0x70e14dff, 0x5111b3a4, 0x6f180680, 0x6dc941f7, 0xad2c6748, 0x489af0e6, + 0x6dc8cf98, 0x50c1aa1d, 0xaa93aa8e, 0xca611cb0, 0xfbc3263d, 0xcd0b58b2, + 0x8c434c63, 0x32ec851c, 0x9f97f9d8, 0x6be1bd90, 0x5cd6a487, 0x79983099, + 0x92e191ec, 0xa5e222eb, 0x347a74ca, 0x4d563be9, 0xb96fece3, 0x69734ff7, + 0xe0e9601d, 0xad6a17bc, 0x8e9c1fa4, 0xcbb3a45a, 0xd92b64f6, 0xe78e79e7, + 0xed97bf10, 0x17d45661, 0xff5fc007, 0xa33fb611, 0xac1e75a6, 0xf184193b, + 0x07e0019b, 0xe97de01b, 0x93d21ea8, 0x0c2d43a5, 0xc5f43bbf, 0x3e1172bb, + 0x6bfb8d65, 0xbd129c69, 0x82d9fd15, 0x515b57fd, 0xccc9b26f, 0xd5f4809a, + 0x9abfebc8, 0x1ea2b364, 0x86fda82d, 0xa8f2dbd7, 0x83de079e, 0xe62fdb1a, + 0x42b3d976, 0x74f6b12f, 0xb2445b92, 0x7ebe0f16, 0xfdf1af05, 0x644718d6, + 0xcfa3d185, 0x416d0f40, 0xf2d488fe, 0xe6136dfe, 0x6e5c1346, 0xe3290f51, + 0x0e65ab3c, 0x2d45ea03, 0x20f597d7, 0x603e902f, 0x7c7117fc, 0xc9466f45, + 0xac235a52, 0x1d59ea3b, 0xf8b7b397, 0xd603d99d, 0xec54de93, 0x1f6172b8, + 0xe8136154, 0xbfb465df, 0x8970f282, 0x6d4cb3d0, 0xe3bb4549, 0x776da333, + 0x6071d92c, 0x7f48a8e7, 0x65eb1efd, 0x7175d832, 0x319d765e, 0x17f496e4, + 0xe3f6d933, 0x7db56e7a, 0x9fe798a8, 0x03433cc5, 0x1d2c9da2, 0x87f80afd, + 0x7858e984, 0x587186d2, 0x447ef1f4, 0xc156eb24, 0xe11d073a, 0x8bb1e3f5, + 0x1b05acb7, 0x77a47dfd, 0x3382470e, 0xfb430050, 0xca6e794c, 0x6210f4e0, + 0x11dd93d7, 0x5462b03e, 0x337d1785, 0xc20c7bb5, 0x653fd363, 0xdb7684b7, + 0xfc5233ff, 0x86de7fc7, 0xfd7fee38, 0x150e624c, 0x2d15d7d2, 0xb4d16bb5, + 0xf43dfeef, 0xb54c296b, 0x007b3fa2, 0x71c7adf0, 0x8ec96a66, 0x05db416a, + 0x09ccb7da, 0x86f7b923, 0xc741cb86, 0xdfde009c, 0xf7c10000, 0x689dc3ab, + 0x55d60da7, 0xe38697bc, 0xdf120557, 0x1b9c68b4, 0xc7fc7162, 0xb2f8d206, + 0xe8e1bdfe, 0xe4227d7f, 0x9ee49551, 0xc76df18b, 0xefc32d15, 0xa3bb04d5, + 0x535ea1ca, 0x7fda9c38, 0xed192a02, 0x5b609ac4, 0x03d9ca24, 0xfe4994ff, + 0xba828cd5, 0xc513e491, 0xd8666a61, 0xfea18322, 0x4d4bc0a0, 0x99feb3ad, + 0x4c9e7c50, 0xb8c60ce3, 0xe18bb61e, 0xc345fce3, 0x07a7d9fb, 0x075ed1aa, + 0xf089144d, 0x027e6dfb, 0xe3c2d2c5, 0x0871c826, 0xcfb7e15f, 0x19477216, + 0xb3e83b1f, 0xffe30ed0, 0x37a92ce6, 0x5fdd7f20, 0x0d00e860, 0x58293ec2, + 0xf5bf4263, 0xd6ecbb7e, 0xf7605c81, 0xecfadb65, 0xdf1c5882, 0xbd21c726, + 0x937e2be5, 0xf5c2317b, 0xdb3d1ecd, 0xe0237644, 0xba7aed35, 0x1fdf80bb, + 0xf8e3fe80, 0xc7fdbca7, 0x9fe71d42, 0x6887480b, 0x43da060f, 0x4de5fe70, + 0xf6f29f93, 0x592ce72b, 0x40724417, 0xa552f77c, 0x132fa9ed, 0xa5c84ed0, + 0xf2aef952, 0x7a99dcbd, 0xfe8a149b, 0x7189ce8d, 0x0ec205c0, 0x67b9d72d, + 0x673e3f21, 0xefa30fb0, 0x474c5d14, 0x6674317b, 0x475c00f2, 0x0e60bbf7, + 0x0233db41, 0x805067cf, 0x4c2b9e23, 0xd44c3744, 0x4818bfed, 0xdf04b9f6, + 0x62fa3a41, 0xda3b698d, 0x2dad7673, 0xd1d20972, 0x47b240f2, 0xc1dc80ce, + 0x0494cf71, 0xfbce1d13, 0xc8fbf175, 0xb4f2676f, 0x5a679f44, 0xe9f7bdb8, + 0x85add94a, 0xbccd77f5, 0xf4224cf6, 0x45f55aeb, 0xdb2856d6, 0x1a35fcd7, + 0x35bcd1f5, 0xdfb0d3a5, 0xd355a2bc, 0xe2374e11, 0x3a2579f3, 0x6e1cccc1, + 0xb76ce353, 0x6742be23, 0x3941cb5e, 0xe4b8b83d, 0x17c18c39, 0xc4efd9c7, + 0xdb6997f5, 0x651e10cb, 0x8d167c6f, 0xf37773f6, 0xa15b7bcb, 0x27d9336c, + 0x35b2bf60, 0xc3acc577, 0x55ff84c1, 0x017c06a6, 0x671e7d1d, 0xe5f7c1cf, + 0xd889dc93, 0x2da692ef, 0x56c6e107, 0x7ddd9add, 0x80fea5b1, 0x40607e84, + 0xb295194b, 0xd1e71d33, 0xa483b929, 0xd8238438, 0x4beeb00f, 0x70507766, + 0xc98d452a, 0xe9de289e, 0x5a9a3ebb, 0x403b8898, 0x6c9762bf, 0x32dd2033, + 0xebe716a7, 0x9e18bedf, 0x7c5bbb53, 0xfc5cc45e, 0x93d37079, 0xab7d2077, + 0x37f71b99, 0xd84aee2e, 0xbcbff88e, 0x6f44e5ff, 0xbcbfd83f, 0xfd7cbe7e, + 0x00be9097, 0x89e0978e, 0x41abe906, 0x75ffe3e7, 0xfa248aed, 0xfd11ef82, + 0x724aed74, 0x8f92f26e, 0x307e425d, 0x066b2bab, 0x95cdbdd2, 0x22967685, + 0x95de982f, 0xb25bfe4e, 0x15fd1d2b, 0x3cb0de45, 0x773d2257, 0xfdb112ba, + 0x8d67f401, 0xed16ef9e, 0xc4ddaa8e, 0x550e8ee3, 0x6c47d606, 0xee32bac7, + 0xb497d6cd, 0x4f53eb55, 0x9fd6fa71, 0x95fcf210, 0x1f8ab457, 0x82bf0b2c, + 0x5a3c1459, 0x7046fdb8, 0x8156b3f9, 0x5951c3cb, 0xbf803718, 0xdcde6962, + 0xfb857e6f, 0xd94607cd, 0x2aae50a3, 0x6081f9fe, 0x5ea2a7a8, 0xea56f3e5, + 0xe7fc1c0a, 0x4bcfe6bd, 0xf7be30a3, 0x1f8f1c46, 0xbcb81955, 0xb97032aa, + 0x1594dab4, 0x34abef8e, 0xa2a6c760, 0xee2c72bf, 0x0e078d4b, 0x366d2ae7, + 0xf57dc110, 0xe9475ba5, 0x6d976f91, 0xa6f7a51b, 0x639daa8f, 0xde60598e, + 0xadaa7697, 0xb52a84b8, 0xd7b449f3, 0x2eca76aa, 0x7af7a307, 0x64bfb41b, + 0xdb02723c, 0xe3c6dd2d, 0x65ff4a16, 0xf96db35b, 0xb11ef35e, 0x69be17d3, + 0xc8fadf2e, 0x51fadf26, 0xfd0645b4, 0xb946fdeb, 0x8e63eb7d, 0x7fcfd6f9, + 0x242cf0f8, 0xf1d902c3, 0xe3f68ca4, 0xa18e735f, 0xc0eaf93e, 0xf78a20c1, + 0x8adf967c, 0xadb2f176, 0x3c0770be, 0x3827684a, 0x77a44876, 0xfcfe9d0b, + 0x031f3fd2, 0x5f389446, 0x14dd37b2, 0x3aab4731, 0x9df6fae6, 0x86cb35cc, + 0x7f95a571, 0x8c72fb8a, 0x5ddbdc67, 0x0fe8b45b, 0x46f77ff9, 0x368ccb7c, + 0x1637c60b, 0x7eefe58e, 0xfb2272b4, 0x7cdbc702, 0x71e90732, 0xd224afe1, + 0x25f70bc3, 0xd3748dbd, 0x14ce77b1, 0x12e5672a, 0xcbb8943c, 0x6dc916b2, + 0x2c79ba82, 0x650fdbeb, 0x6b45ef30, 0xa1f13e75, 0xf3becdfc, 0xfbe35a58, + 0xe1d3597e, 0x6bbee1bf, 0xda45fe81, 0xa6d82ea7, 0x396b8bf3, 0xbd3b42df, + 0x7e462be8, 0xf7dd5178, 0x5ee2feba, 0x143ac44b, 0xee3990fb, 0x6e4eb864, + 0x8edf8202, 0x3d7207ff, 0xc4d76cc4, 0x8dd8f20f, 0x95a9aa3f, 0xcca57e11, + 0x8e3988fe, 0x207751fc, 0x0ea967cc, 0xa4d1b1ec, 0x577d6987, 0x78a00eb7, + 0x06673c07, 0xb5957e78, 0xbe7ea165, 0xf2b268da, 0x965b5938, 0xa0cbea19, + 0x602bf08e, 0x12a704d5, 0xa732cb94, 0xddb79b1b, 0xb3adf4e0, 0x97b76e6a, + 0x1187dda8, 0x9dacc51e, 0xbd1e21fa, 0xbac095db, 0x3b41093e, 0xb33fafc4, + 0xdcbc9c52, 0x95fc25a8, 0xf3af7d37, 0x0bf8af7e, 0xc4a2ff8a, 0xf4577ee1, + 0xb7d20060, 0x3587d846, 0x5b7b9d1b, 0x94eb3d61, 0x0316deb8, 0x6b07a7c9, + 0x7b07bcb9, 0x59d71130, 0xd68525b3, 0x8b64a0fd, 0xf6b68759, 0x7fd13d0c, + 0xd3d8304d, 0x924764a1, 0x237600bd, 0x733dadd9, 0x12edceb4, 0x372e8fda, + 0x4f35c1da, 0xca06f8f3, 0x9f6bb249, 0x527d9030, 0x27db8333, 0xa9c25b35, + 0xca705fff, 0xf2576891, 0x913cd4f9, 0x995dedc6, 0x8ce163f7, 0x65f607e6, + 0x5e6bdea2, 0xb2ff5d8a, 0xf1113ed9, 0x26b7acad, 0xfb84c7b8, 0xe060ac1d, + 0x7af9e92d, 0x007abfa1, 0xff07180e, 0xc56bca52, 0xdda5097d, 0x1f5cf17d, + 0xedb04d64, 0x5e28ed10, 0xb19aaf9e, 0xa79827e9, 0x52ca8cf0, 0x7f05e315, + 0xd7112d9b, 0xc316e5ff, 0x99d3c468, 0x679e5c51, 0x05f1e04d, 0xdb6c5bf0, + 0x5e22ff71, 0xfd7713e5, 0x614ef8a9, 0xf5e685bc, 0x2f8f3665, 0x28f2329a, + 0xdab6038e, 0xf5f6fe82, 0xbef9e30b, 0xef36be68, 0x99fb8ff8, 0x3617028f, + 0x5f17fb89, 0xbe91243e, 0x9a24f584, 0x1bf59ea1, 0xbe7fc503, 0xc1477a14, + 0x2651d007, 0xc72161e9, 0xc67e90c2, 0x19e7e878, 0xa40e1741, 0xfd378b0b, + 0x83c7d2f8, 0x09ecff02, 0x04d69f6e, 0x13cd7af3, 0x9fa03729, 0x650ffdfe, + 0xfcb535bd, 0x01dfbfbd, 0xde36b074, 0x74fe9e0b, 0x4cced4c0, 0x7f35fdef, + 0x8d96c83a, 0x57e728c9, 0xb4560148, 0xfe0857c7, 0x1184b158, 0x0ab1463d, + 0x8235f909, 0x008f29b9, 0xc70181e4, 0xc00f71fb, 0x7f0f8bdc, 0xbccf4d72, + 0x1678dff5, 0xa89f53ec, 0x9f69f48f, 0x79f18e6d, 0x8a44577f, 0x96c9fbcf, + 0xa9f53e51, 0xb4fbb7c9, 0xde3adbbf, 0xd8cf7ea7, 0x67ed3ec9, 0xd4f866d8, + 0xc6accc6d, 0xee54b7f9, 0xcde0fb24, 0x97dc574a, 0x65c3d709, 0x3ec8ee9c, + 0xa6b1958b, 0xaa6707ba, 0x0dc61e81, 0x0622b238, 0xede387ea, 0xe4751ebc, + 0xb1998c6a, 0xf217e2b7, 0x572388fa, 0x347ea163, 0xdfaf117e, 0x7f5fc8c1, + 0x4cf17e27, 0x15c52a47, 0x667e218f, 0x8a38ab5d, 0xab47e16e, 0x41892e67, + 0x24c92f1e, 0x67ecae39, 0x3f6313dc, 0xbcacfc84, 0x8d9fda57, 0xafbbfde7, + 0x7ddff970, 0x2377cb85, 0xfe83291a, 0x32fc12fd, 0x0e04fefa, 0x6f413622, + 0xa62ffda4, 0x8bea5cd7, 0x94fc8343, 0x3c618c6c, 0xf012a5af, 0xd370809d, + 0x34aee953, 0x32a47953, 0x2bb7ca82, 0xe01f2c2d, 0x4c995ada, 0x2b4ab1e5, + 0x395e3f3d, 0x2bf7ca96, 0xa89e546d, 0xadb2a5cc, 0x094a8f32, 0x2879a98c, + 0x3758763f, 0x0e2e1068, 0xbd39f075, 0xc6e52f27, 0xcecd4c72, 0xc685f829, + 0x5f6c186f, 0x31dd93c4, 0x71714cc4, 0xd35bbcf1, 0x73d222f3, 0xc16615d5, + 0xa6c3b87c, 0x9fb416d3, 0x44f532ab, 0x9b4f52ef, 0xb8ebe505, 0xbaaf5e0c, + 0x675166d2, 0xfdea3af0, 0x28d760ee, 0xa5550bd4, 0x189aeb46, 0x448eef7c, + 0xa157197e, 0x387fa2b5, 0x3e67a7a9, 0xa338f1f2, 0xf47a82d6, 0x2df5a9b0, + 0x73ca3df1, 0xdcc2bba9, 0x3457dc2a, 0xe2cc59b4, 0x7c0e383b, 0xc1f50637, + 0xbbe187b8, 0xed056e34, 0x679b8d07, 0xe4aefbec, 0x0ffd5df7, 0xe4a2777f, + 0x5ef8ddf5, 0xff3a6ef8, 0xbbe7c5ae, 0xe5ec996e, 0x0fb26e2b, 0x11ad83ba, + 0xfa955f28, 0x4a9f7c24, 0x33d24271, 0x196e2ce3, 0xe887eff7, 0x070d3cb8, + 0xa5e0d2f3, 0x6278956f, 0x675f2f5d, 0x08bba557, 0xb0926af9, 0x59692657, + 0xa993c232, 0x98fe2802, 0x1ad77f2d, 0xcde5f505, 0x9dcc28d2, 0xdbcba498, + 0x9aae7e46, 0xca161dcb, 0xb75332f5, 0xed0cbe15, 0x5945854e, 0x486adf31, + 0x0f1601c4, 0x3cbb3872, 0xfaf51537, 0xd4df9129, 0x484f641c, 0x9bdc7980, + 0x254a720a, 0xd9f71988, 0xde490372, 0xca4a1f77, 0xa67f7b44, 0x019fb2ce, + 0x3c26a71f, 0x720d5333, 0x4b00e671, 0xfac664a6, 0xb70f5e36, 0xbde097ec, + 0x73333d99, 0xc1ffedd2, 0x4934fafe, 0x381f97ed, 0xadf80136, 0xc8b2f734, + 0xfb21ec57, 0xe498c7f6, 0x77e28834, 0x9ec7a46e, 0x03d226c9, 0x8e5b8f18, + 0x92d53bf2, 0x35a2ed89, 0xff08413d, 0x94d4efee, 0x832d023f, 0xe38af3ee, + 0xf3c2d8bc, 0xe3f9fc4a, 0xabd70272, 0x9f3cf1e5, 0xaf422ca9, 0x4ae5b2a7, + 0x8f7ca30e, 0x3ff478bc, 0x57edeac1, 0x0277febf, 0x598e1fdf, 0x47f1e5af, + 0x6530a114, 0xea53005b, 0xa96bcc0e, 0x3140247d, 0x4e006d46, 0x547ec5a6, + 0x24cdfa6f, 0x1b7b4fb5, 0x67bcf7b6, 0xd29f0436, 0xcf7ea4bf, 0x8bc6d66f, + 0x2cbd21ef, 0x825c4e65, 0x4da9febf, 0x0bfc510c, 0xa10bf3c2, 0xe38bf206, + 0xa057a065, 0x1740a8cf, 0x0ceb33c5, 0xdcc17e9c, 0xc54eb2a0, 0xc0036bdf, + 0x50fa85fe, 0x9a3ee3a8, 0x22bed13b, 0x67f51071, 0xef2fec66, 0x2291fea5, + 0x1f794e6f, 0x1979518e, 0x0cdae9f3, 0x55938e58, 0x4e4dc2fd, 0xc46bff1c, + 0x83a55777, 0x2fd2f59d, 0x2b41815d, 0x8654f1bd, 0xfdde8dfd, 0xa53f5026, + 0xfdd8297f, 0x9c920767, 0x8d297a26, 0x2b3e5157, 0x4b6fcdf8, 0x36b0d768, + 0xa561ea2d, 0xab9069df, 0x410fbdf8, 0x09f962ce, 0xc0b3d7c8, 0x9ca97f9b, + 0x95a7e54d, 0xa67e7a76, 0xf6ca80b2, 0xfe7a0aca, 0x2a4ae579, 0x6535cd67, + 0x37949f20, 0xbd6766ad, 0xa5d4bae8, 0x4bef7bb1, 0x3fdf1e9e, 0xe04aecbd, + 0x98e9dd76, 0x95bbdffe, 0xbc7277f7, 0x817d8375, 0xdfd024f6, 0x8dc8735a, + 0x136e8ced, 0x377abfdf, 0x7773d385, 0x25d7af24, 0x536ea868, 0xffd8adb1, + 0xd12d14dd, 0xc6448aeb, 0x2c7889db, 0xdf8d1fd0, 0x3e54e707, 0x19ced28e, + 0x2fedcaaf, 0xf225984f, 0xe89f4476, 0xc63d202f, 0x9967d178, 0x9fd3e885, + 0x39136a2e, 0x38ebc4df, 0x2ea145dd, 0x708c7dc2, 0x0a731383, 0xdc36be60, + 0x3893af57, 0x9f475e3d, 0x5d9fee2a, 0x0e309f47, 0x5ce809c1, 0x7ec7f282, + 0xef94a3f4, 0x0b6fbe0a, 0xe08cfd33, 0xa331a2dc, 0x0cb1f8be, 0xaafec580, + 0x0f9813de, 0xb266151e, 0xf6489ee0, 0xfe8ac6e3, 0x123fc7e4, 0x6ffd7db8, + 0x1f8fbfaf, 0xdd7fd77d, 0xd07ec5ba, 0xe49baead, 0xa44bca09, 0xc3e47e9f, + 0x3e4504a5, 0x1391fa70, 0x3f50e76d, 0x35064b74, 0x0dbbb3c6, 0x83ae2e9c, + 0x4fa70a5b, 0x056a3e85, 0xbae1447d, 0xe9eb3ce2, 0xdf807f9b, 0xca3196fa, + 0xa3c7f0eb, 0xd6bc5722, 0x2f04f7f5, 0xd818c279, 0x487fd017, 0x09f69189, + 0x099a2457, 0xce83dd7e, 0x6f02dfcf, 0xe27a159f, 0xa7df1579, 0xdf76e450, + 0x305e4973, 0x9e47d523, 0x7a33b433, 0xbf88e90e, 0xf0562adc, 0xf851fa1a, + 0x70bf2f29, 0xef53c0ac, 0xee154cec, 0x6b7d75bf, 0xcd1e5074, 0x68339ee0, + 0x056d7447, 0x7ffc8003, 0xf40934db, 0x878c12d9, 0xafbe3058, 0x8be8fda7, + 0x24b20f60, 0x72bae768, 0xf298ed06, 0x07a664e7, 0x7dcfc9d0, 0x65e90b33, + 0x998d21e9, 0x4fad9aec, 0x3b7a431d, 0x505928d7, 0xc23577df, 0xb39f71b2, + 0x4034e4c6, 0x63a81cfb, 0x653b65fb, 0x03522527, 0x14fe907b, 0x286b3bdf, + 0x777b458b, 0xa33f73e2, 0xb5a5f8fd, 0x71870b12, 0xa2badadf, 0xe7ea1235, + 0xf9fcf1b6, 0x7fcf032a, 0x6b3791cf, 0xb47c6307, 0x312f3f96, 0x7bfe50e6, + 0x75662ed1, 0xaf65bc63, 0xa5f3fc89, 0x1579be35, 0xeb7cdb05, 0x5cbe2285, + 0xbcfbe754, 0x4f37c1a4, 0xc8a24c63, 0xa36148c3, 0x135a5e28, 0x22807642, + 0x77e46f4f, 0x397396d9, 0x61d7d8c9, 0x0f95ef18, 0xb9fd137d, 0x8867d791, + 0x2fd4077a, 0xa2f1c37f, 0xc94ca5c0, 0x1964882b, 0x23cc0cae, 0x3f719834, + 0x8bf9acaa, 0x73f98620, 0x89d3ed01, 0x29975f3f, 0x93636adf, 0xa569fb4c, + 0x3097862d, 0xff6cb0cf, 0x84c5ad49, 0xec887f70, 0x6398bb80, 0x6e8bfa3d, + 0x6fe44a95, 0x8ddc51b7, 0x52967ad9, 0x60d9bb7c, 0xf65afd46, 0x73adc7fa, + 0x625fbeb1, 0xd0e3c406, 0xa593a276, 0x5fb4c9cf, 0xc9f2d0cd, 0x8c89d0f2, + 0xbb3c4578, 0xcf3ed006, 0xe23bc432, 0xe78ef019, 0x34e7e41b, 0xbba5f784, + 0xb55f7a64, 0xed8b4ab5, 0x7e3939cf, 0xc8e7bc15, 0x45cf08ab, 0x4e7c702f, + 0x99feae7c, 0x5d83a400, 0xdf73b21a, 0x79837e82, 0xd03a1f3f, 0x77e3e21e, + 0xdf144bd5, 0x6683a3ea, 0xe01d1f5d, 0x07466f3c, 0x67a49fc0, 0x0607466f, + 0x4fe41794, 0x8a1a3b8f, 0xf8cfedf6, 0x9db8947c, 0x1f9b9712, 0x10fa59d2, + 0xd8884d34, 0x1b2cf647, 0x08955f60, 0xe4cce672, 0x74dc280f, 0x51eeca6a, + 0xff034f94, 0xbf9461f4, 0xfb7cf047, 0x444b7fe7, 0x331dd079, 0x18c1db63, + 0xae0767c2, 0x90383ba7, 0x923dd3eb, 0x3ae7a253, 0x93be0eb7, 0xf915720d, + 0xa3a9bd92, 0xa0f743f8, 0x893e1e07, 0x184f68fb, 0xc92e88ad, 0xe2bafdc6, + 0xc13e7796, 0xcc6b27f8, 0x7df8f9b6, 0x462b2fc2, 0x37df10bf, 0xb5e85f80, + 0x3f9928df, 0x4bbf7ea0, 0xcb75a58c, 0xf256eb2a, 0x0598eadf, 0xe5eb95ed, + 0xaff9233f, 0x686eafc4, 0x01e9f99f, 0x76e7fc8f, 0xf10c7319, 0xe5c0b73b, + 0xf71132d3, 0x71c8fa3d, 0x675c40f5, 0x53373f1d, 0x297202d8, 0xf8a5ce94, + 0xd13297c8, 0x19d23cfe, 0x472bf1c0, 0xec9501c5, 0x9d3e472d, 0xec94e384, + 0x2194e3e2, 0x981c20fd, 0xdc0099fb, 0x28697027, 0x84c4591e, 0x5932695c, + 0xe47e96dd, 0x7aed5d48, 0xe9fd7f34, 0x37ec18a7, 0x1d3f845c, 0xb6fa3595, + 0x97ca03fb, 0xd25f2411, 0x077f47be, 0x23d32369, 0xd4e5b247, 0xf5afe801, + 0xe400cb32, 0xb9e91be3, 0xdac0ada4, 0x38a6e35e, 0xb3ed4cf5, 0xa9f6615f, + 0x7c22b9a7, 0xb26c8fda, 0xe51fbcf8, 0x3f79f64e, 0xa7d598e6, 0xd636d99e, + 0x9f6dfda7, 0xb7ea7cd8, 0xb4fae7b7, 0x3cabe3bf, 0x2a6f7a9f, 0xf607e7ac, + 0x908aeeef, 0xb64fda7c, 0x07c67c18, 0x99f04e0d, 0xf3ec1c9a, 0xe1c8d7bc, + 0xef71a374, 0xab8efab6, 0x8cf7b9f8, 0x867f1df5, 0x5bdc77cd, 0xd00ec3c5, + 0x4d106a9b, 0x628f413b, 0xc0254af9, 0x86f1ec1d, 0xbfaa08ca, 0xd2a1695a, + 0xcf4c9955, 0x52b4ab5f, 0x2c72b1bd, 0x7d800fd5, 0xb026f58f, 0x1d7cb1f7, + 0x7e7c7cec, 0x8ab57833, 0xdf131eef, 0xcbbe2e3d, 0x076e16d8, 0xef2e04dc, + 0x4427fe8b, 0xafec36ff, 0x6961d0f1, 0x1aeaa66e, 0x90f8edf0, 0x2f8c5a0b, + 0xe7b796d8, 0xf3df9fa0, 0x03b6ccae, 0xf3bb305f, 0xea286558, 0x1f3c81a9, + 0x3de7af21, 0xed97178c, 0xfee3338f, 0x3fa6c6c7, 0x5df7c09d, 0x33c5328d, + 0x117d348e, 0xba5ce384, 0x503ecc06, 0x97a837e8, 0xfaa24dfc, 0x798f7826, + 0x82f793f8, 0xcb7a4b61, 0x52eb7a45, 0xd27752bc, 0x86bc8df9, 0xda76dabd, + 0xef4bdc57, 0xf5be05df, 0xd6b3bf79, 0xdb19bde7, 0xdab67ee3, 0xc5f77e49, + 0x373c6526, 0x97892fb5, 0xc5d23ce8, 0xc7ad6f9d, 0xbdd2be7c, 0x3ee2070b, + 0xc9c37160, 0x003fc5b0, 0x7607cbff, 0x2f5ca2a7, 0xf9c5966d, 0x695e3e23, + 0x891e72b3, 0x7e24bfcf, 0xca084e6f, 0x218906ed, 0x6ab12e7a, 0x6e2a8fca, + 0x39412faa, 0x573c9c5a, 0x9721f143, 0x3c01e22c, 0xccc4b0df, 0xbae67db8, + 0x35e7841a, 0x3a3ae0ff, 0xba85f31d, 0xc20ade5b, 0xf9e376ef, 0xdefc2f13, + 0xdcedc493, 0xdfb8927b, 0x2df1a974, 0xd1b93f3a, 0xbb8716f5, 0x3feb4dda, + 0x50ddea22, 0x649bbc12, 0x35e17f5a, 0x8ca0f099, 0x4c9260f7, 0x4a6e4de3, + 0x4ebae130, 0xf2f7f8b9, 0x79fc2c93, 0x9c7cc2fc, 0x3988f1ff, 0x95d93299, + 0x3ddf2e3c, 0xca3d6a7c, 0xe80fcc51, 0x047b0fcf, 0xb5f985c7, 0x77c63c8a, + 0x0eb5f7e3, 0xcf1fb806, 0x748a381d, 0x274fe280, 0x473dfb71, 0x3d478f6b, + 0xa168ca71, 0xdc9af838, 0xf7e21338, 0x3cf89608, 0x57da25f7, 0xdfe46a28, + 0x0b6e653b, 0xd53bba42, 0x3b464638, 0x40af1946, 0xbe8fb77c, 0x20e6f0fb, + 0x6b38153c, 0x078e388d, 0x7e79fc7f, 0x71e69992, 0x167279dc, 0x92a74bda, + 0x68cec903, 0xfcfdf2d5, 0xef6e06e2, 0xaa896a9e, 0x5bf6bd95, 0xba3e05f2, + 0xd7845593, 0x688d26ae, 0xf99eb737, 0x7c70d3b4, 0xc7cef9d5, 0x1278ecec, + 0x1792eced, 0x54933a64, 0xc308a9a2, 0xe6df9ff5, 0x0102bf3b, 0x3b8d12e7, + 0x5e8bcc2c, 0xf8fb9a4b, 0xde7448c6, 0x8589f0ac, 0xf1e0a9f0, 0xc73f3254, + 0x9f822a72, 0x5bd92a83, 0xd1ed744f, 0x19ae3cf7, 0xbf3c5ff5, 0xae7e66f6, + 0xf9780f62, 0x3cfd0c49, 0xa65c6e4d, 0xf7a3d62a, 0xbf6d137b, 0xfe841a4b, + 0x85f91e53, 0x8a26ec40, 0x3c7da08b, 0xa7efe500, 0x7b77e0cf, 0xd879f91b, + 0x11737d52, 0x5af5fbee, 0xbe604181, 0x4e34dbbd, 0xd118cfe1, 0xec2a5d4e, + 0x7b16f3d4, 0xa3fb8c96, 0xaeb455ab, 0x89d90692, 0x425d98f9, 0x1bde5dde, + 0x69d20f73, 0x8cd931c9, 0x5744cdfe, 0x65c7afcc, 0xfb26de90, 0xedc5ccae, + 0x129db2dc, 0x7d8ab5d9, 0x8bec2a51, 0x3d8ec273, 0xdb87bab7, 0xf62487b7, + 0xcec78c54, 0x45761528, 0x3d79bca9, 0x9ffb2be6, 0x396c2daf, 0xfd89e74c, + 0xef16d5cf, 0xba97adf4, 0xbf8aeb7c, 0x9f524ef7, 0xfe82927f, 0x94a7d809, + 0xc0a9f12f, 0xacafe2a7, 0x2386b348, 0x5b546fbf, 0x037128a6, 0xa1f95784, + 0x6f38857d, 0x95804967, 0x6f9587fc, 0xbfbb5c10, 0x77497ee6, 0x77f5a304, + 0xeedf0e33, 0xe5df4e26, 0xc7a9c91a, 0x7023a8fe, 0x5ce4bd3c, 0xa3a8768d, + 0x12e48837, 0xf7c1e1e6, 0xfee1cf96, 0xa3630da7, 0x855a9530, 0x29fd140f, + 0xa9decdce, 0xbd83976e, 0x2495c3e4, 0x124e776e, 0x4c2b48f9, 0x835fd256, + 0xc1ebb9c5, 0x0f6f6e7a, 0x53573b56, 0x6631fe3c, 0xf2714359, 0x4e90a303, + 0xf14eae30, 0x123d55ff, 0xeb1fc3c5, 0x063f9091, 0x7911ad9b, 0xf849f55e, + 0x0763d53e, 0x48f6330c, 0xc7ba9df8, 0xd73af894, 0x66d433ef, 0x894fce0d, + 0x87fb293b, 0x7394fcca, 0xf3e7ff08, 0x8cfcc333, 0xbe01f99e, 0xabff6007, + 0x0fb25619, 0xe72867a2, 0x1e482afd, 0x04bcf028, 0x70093ef4, 0xa41d3185, + 0x876d929b, 0x40fe7873, 0xcbdf9d1b, 0xc8ebe209, 0x39e3f911, 0x941cbc01, + 0x2b35f1cc, 0x9e8bc799, 0x3722a510, 0x85b649df, 0x2fb94325, 0x39322f39, + 0x62ce73d3, 0x9cfc07f9, 0x87bcbf85, 0x574f44e7, 0xee510f81, 0x3242b4fd, + 0x63d8fbc7, 0xf9cabf9c, 0x2a3e3ea3, 0xe225e0fe, 0xb5b0e613, 0x9e618725, + 0x05efe702, 0x78e60d2b, 0x1728be2f, 0xc5a6207e, 0x7297fee2, 0x5cc0be4e, + 0xec40e748, 0xe8ccc32b, 0x97cb9597, 0xafff5e28, 0x93795df2, 0xe06ddd6f, + 0x4936eff4, 0x9edcffe4, 0x13cf67dc, 0xfe0b463f, 0xb44bb5a8, 0x9dfb5c2f, + 0xe6dbc79a, 0xbb5f1449, 0x7cf21e1f, 0x60aed17a, 0xdd9be53c, 0x37da550f, + 0xfb1509ab, 0x9fb4a1d6, 0xf7589f77, 0xe2df22fd, 0x8315c6a8, 0xa5a3a0f1, + 0x3f8e2b7a, 0x7f68b987, 0xa36b1e7d, 0xd96074f2, 0xee0d377e, 0xfcfe8a18, + 0xc51d76c7, 0x6ed76aa1, 0x4f5ca137, 0xb8cd6b67, 0xd8a006cf, 0x5b98fdf9, + 0xf2538fdf, 0x0e2ec189, 0xfc04fa47, 0x7ffc46cf, 0x1889b805, 0xe2ff7d7d, + 0x3e53f68f, 0xfbc3e752, 0xd0c03d66, 0xff21eaaf, 0xb562a8a8, 0x1c4df686, + 0xcb392dac, 0xef055783, 0xf0fade0a, 0x1f16616a, 0x869ac2bc, 0x4be49c20, + 0xfd2e4833, 0x77a8664e, 0x0557866f, 0xf8113fee, 0xe5ccd659, 0x15be3f97, + 0xe7803c3c, 0xdf48e2a3, 0x313c236e, 0x7f4bc91d, 0xbe19b87a, 0xe1e73080, + 0x3aa189ab, 0x54a32ff2, 0x2d469e5c, 0x38be2895, 0xb50fd997, 0xf02b3943, + 0xbbd10d53, 0x813cdbc0, 0xf3998fb7, 0xff98e4ee, 0x93bdbc3d, 0x3c9d579c, + 0xf5be7ae8, 0xf11bd3e7, 0xfac58965, 0x3a5f4547, 0x1fa3f219, 0x6bf1fb3f, + 0xf0ad1e1f, 0xda3c2f3f, 0x5f110657, 0x6e5be1f6, 0x88bd35b8, 0xaa1c607f, + 0x716bdf89, 0x60957e53, 0x57cf8021, 0xa6f57d93, 0x2e053782, 0x9deb8a37, + 0xc23b72d6, 0xfb4c88f1, 0xee499f98, 0x639466a3, 0xfce8a729, 0xb3fed29b, + 0x1f436dd5, 0x1b3e7182, 0x5ad3cbcf, 0xd4a91f9e, 0x3e3c016d, 0xcea459f8, + 0x4cfdeb81, 0xfa80994a, 0xbfe933e2, 0xb87af3a6, 0x39f582d6, 0x50cc13e1, + 0xe251ad3f, 0x7c446b89, 0x67e549c0, 0x449b6e73, 0x36f624ed, 0x3f9f8ef3, + 0x7cfc512a, 0x9c728801, 0x6784cc5f, 0xfeaf3173, 0x46e3cfcc, 0x72df3ed1, + 0x1f50f1df, 0x921c50c7, 0x5e778bfb, 0xf42cd1eb, 0x7a7d3bd2, 0xfe15d270, + 0xce933f3c, 0xd808161b, 0xb85242da, 0xe7e4ec7f, 0xd33d1536, 0xd19f6c7b, + 0x417a4e3b, 0xeafb95c4, 0x7b444f29, 0x3bc3a9eb, 0xe388957e, 0xe91d6814, + 0xabfb7e78, 0xd1a3e7da, 0xf1d8289e, 0xb7d92278, 0xa226363b, 0xfdb0529f, + 0xaa368957, 0x4fc9da07, 0x7775f352, 0xa5fdb9ee, 0xe77a5e4d, 0x6fdce1d1, + 0x9c3fa799, 0x94ee768d, 0x61d79711, 0xe7e13e3c, 0xf387dd12, 0x0eb6d653, + 0x64fcdff5, 0x46acef4e, 0xe199724f, 0x73c02df9, 0x75ddca7d, 0x93c7a7c8, + 0x43e4d0bf, 0x9a8a5d3b, 0x399f33e0, 0x7ee38737, 0x5cc906f6, 0x0fdbbccf, + 0x85cafda5, 0x446d256b, 0xe0b7ea28, 0xea3fe851, 0x1e698252, 0x6a8c368b, + 0x57f3e7c5, 0x7453e7f1, 0x3853c6ce, 0xca5ab3ce, 0x10f90237, 0xafc79deb, + 0xf1e7e14b, 0xc8966c17, 0x93be57ae, 0xad584cf0, 0x29753af7, 0xd4672f42, + 0xce51dc91, 0x755b4e09, 0x1808edf2, 0xbb6a9ff7, 0x39c60529, 0x78b9f4f1, + 0x149f3c37, 0xfd152172, 0xfdad049b, 0xeeb885b7, 0x83ca3aed, 0x928f48cb, + 0xe8fda1c3, 0x853fc787, 0x0b5582e5, 0xf2885b7f, 0x147eab71, 0xf3e6174f, + 0x55592e5b, 0xaadf3f28, 0xc211607d, 0xf5a7abed, 0xaf2f9764, 0xfd670a4d, + 0xbe528ff0, 0x8dc7f80c, 0x7a955d82, 0x9a57772a, 0x9eda3ce9, 0xffaa08ca, + 0x2542d2be, 0x6be9cd9b, 0x8dcb99b9, 0xe6378d1b, 0x80b3205a, 0xc1b19abd, + 0x70632cc0, 0x9c96ce5f, 0x18487002, 0xa37dba5e, 0xa56e1758, 0x4cc4728c, + 0x6c643844, 0x4d15a87c, 0xee14d0da, 0x6a77bd67, 0xedf23443, 0x2f1d55b2, + 0x537ae216, 0x7f6146f2, 0x142bb6fd, 0xf9ab7837, 0xef08f9f1, 0xbe3aed82, + 0xafeeb13e, 0xff0c4e9e, 0x78ef8c2d, 0x7c7e4357, 0x178eb6f9, 0x78b94237, + 0x6f5a43f3, 0xf5d5bf7a, 0xfbe14c8e, 0xabe3379d, 0x5fe1c11b, 0x455fabe7, + 0x7f6cff13, 0xf9e1ee9c, 0x7caaf977, 0xdf826ad5, 0xd9bc94ba, 0x695f5f48, + 0x4fc8d11c, 0x98fca55f, 0x4871dce8, 0xf22bf822, 0x4b3fe955, 0xe558bfc0, + 0xc62e3cda, 0x61bf5f23, 0xc3df0419, 0xd113e7cd, 0x69a6fdae, 0xfbae0fce, + 0xb7bf2540, 0xebe009a5, 0x52882f7d, 0x71ed6966, 0x965f5856, 0xffe0c738, + 0x12a291de, 0x6fdf2cf6, 0x57927fc7, 0x17e8077e, 0x4f9800c7, 0x0ee48b49, + 0xe9ae3f40, 0x20ea0bae, 0xfb1233d4, 0xc91e27dc, 0x7a5ee7d8, 0xbdf346f6, + 0xe3865959, 0xeee47824, 0x7ca89f6d, 0xbdb963ee, 0x7ee7c03d, 0x03ff3e93, + 0x3f69699e, 0x3956b227, 0x4c7980bf, 0x7429cd5d, 0x9682e25e, 0x00ebb1e3, + 0x3e3c39d8, 0x7baf64c3, 0x77342e22, 0xf59ca3a6, 0xebd96f5f, 0x251f449d, + 0x215f8f4d, 0xf269b63f, 0xcdfa7505, 0x47787fd7, 0x71dbdd27, 0x859ed341, + 0xb69754fe, 0x50f11d3d, 0xe79706f6, 0x941c2aff, 0x601b85e7, 0x65e7c021, + 0x24e89e92, 0x7144be5b, 0x3c63ae81, 0xfcd6502e, 0xded3c912, 0x29971e16, + 0x84e5b557, 0xa2a31c63, 0x59e515a3, 0x93f7046f, 0x09bdc4ca, 0x1e84e2e3, + 0xe344f754, 0xd8b70e79, 0x3bfc5627, 0xf90187bc, 0x2ae55cb5, 0xf4a5fca1, + 0x2dfb8640, 0xe19f9117, 0x3195fcf9, 0xbfce91eb, 0x8d1a0e72, 0xf4bdf1f2, + 0x1c5197bf, 0x66810fef, 0xd911ec99, 0x6fbc2f27, 0x27994e1d, 0xaec530c8, + 0x8bc9f409, 0xee5ad72e, 0x38f67b21, 0x1f2b7fdf, 0xbd89f9ce, 0x74a9f9ce, + 0x846d61ed, 0x820d78d7, 0x6efb149f, 0x4efe1fca, 0xd138797c, 0x92f91c76, + 0x78e215ce, 0x929c0311, 0x7965da24, 0x2d8d1bf6, 0x95cfafc2, 0x93797de9, + 0x8e5f70cc, 0x2f289845, 0x53559720, 0xe614e57e, 0x339b471a, 0xf127f6ea, + 0x7fa99b5e, 0xfe60c790, 0xb441f816, 0x60139d7f, 0xa6fcc78f, 0xc0492ad3, + 0xc33195d5, 0x87e99f4b, 0x4e353d73, 0xf58f4896, 0x9d920644, 0xe9767932, + 0x69fb6f3c, 0x83b78ab4, 0x626ec871, 0xae7e1ece, 0xee93ddc6, 0xacc8ef7d, + 0x9056043f, 0x8cae645e, 0x89df5e59, 0xe6f5ce1c, 0x06ffdc55, 0xfb17293a, + 0x77f2d9ac, 0xbd3da0cf, 0x5fdf10fc, 0xf98aad3c, 0xe8b3f318, 0xe784b6dc, + 0x7939f9a3, 0xbc366766, 0x6d2baf67, 0x2a079d10, 0xcc3123df, 0xd66b2b73, + 0x5138c76d, 0x0c3da699, 0xd36379e9, 0xe7a45a47, 0x4d77dc72, 0x79abe7e3, + 0x724f5cdc, 0x48ccdcbc, 0x2536957f, 0xbbf18c7d, 0x8b5c63d2, 0x924faa96, + 0x1b728e7f, 0xb8dc57bf, 0x12f1fc97, 0xbc7f26e6, 0x6e97c1a4, 0x8ffa237a, + 0xb70e47df, 0x3233dcf8, 0x8fe72b79, 0x325ee259, 0x93b0e226, 0xbd6bc223, + 0x0a4531cf, 0xcee4d83c, 0x74c76875, 0xbc564ac7, 0xc03ba697, 0x23ed16b1, + 0x6bb72247, 0x9ddcdfba, 0x8be494b1, 0x34dee333, 0xdb8757bc, 0x6c3793b1, + 0xf35ecb51, 0xe3ee2c99, 0x05600eeb, 0xf6ef0807, 0x908f8821, 0xe1a8bca4, + 0x9e3ee883, 0x7c607713, 0xf27b9c48, 0x446fc75f, 0x38b8e85c, 0x7bcca9bf, + 0x9714546a, 0x7449cc67, 0x19ce2ad4, 0x4a367929, 0x1eb10aff, 0x3d077ec5, + 0xfb43fe1d, 0x934fb825, 0xf269f62f, 0xbe4d3ec5, 0x17c9a7d8, 0x62f934fb, + 0xec5f269f, 0x7d8be4d3, 0x4fb17c9a, 0x69f62f93, 0x0d3ec5f2, 0x54e2c3e5, + 0x11cdff31, 0xd1ea34fb, 0xc1b5e456, 0x10e9fa9e, 0xdf60fabf, 0x2443a7f6, + 0x8960fadf, 0x257c4fda, 0x118769f6, 0x2166a3e3, 0x547c789f, 0x2a79df39, + 0xe1193ed0, 0xfce79cac, 0x03a9f72a, 0x42934fc8, 0xd9bf90e6, 0xca26fe0b, + 0xf6e1caa3, 0xec776c3c, 0x2df8c4d8, 0x140d2724, 0xe0fd3ce7, 0x98739f08, + 0xacc793e3, 0xc6307bc5, 0x7e71251b, 0x9e647abc, 0x38c1ffe2, 0x66165b13, + 0x307cb9a8, 0x2d9cbda3, 0x77e3e497, 0xc61a4796, 0x24d61ca0, 0xf70ee7db, + 0x8339db92, 0x5da3c597, 0x7cb1aad4, 0xc75af18c, 0xbf3a1a07, 0x94f5c4ab, + 0x8d25ef76, 0x937ec42f, 0x8ed6e393, 0xfcf5f1c6, 0x969b38be, 0x6cfce035, + 0xee8940aa, 0x3516616e, 0xe1c283ca, 0x58266e9c, 0xd6ec7db8, 0x1821d45a, + 0x1f18098f, 0xad13798a, 0x04c7cf02, 0x3c0b8f9e, 0xa4d77ee3, 0x85dfbe04, + 0x6177ee25, 0xd58de4a9, 0x1f2de4a5, 0x27b4f24e, 0xc4ace11a, 0xe728a6fd, + 0xee8b98fc, 0xd0517c33, 0xbe70d26d, 0x7261f2cf, 0x09c3a3de, 0xb73a2e3f, + 0x69e22c59, 0x437f629d, 0xcfd2a759, 0xfbf19fd3, 0x0732465c, 0x83b367ee, + 0x08764f22, 0x9f5023d8, 0xe49c3079, 0x7a1e7290, 0x07ee18e6, 0xfce27db0, + 0x13258462, 0xc44aa3f9, 0xfc9cbb53, 0x48696d1c, 0x239e225b, 0xa57c12e8, + 0xd17395d4, 0x6ea1a3a5, 0x284b9cf4, 0x8896d99d, 0x24ba12e7, 0x0dce8a83, + 0x4fefe76f, 0x8d2bbe09, 0xf729e315, 0xd15de84e, 0x43ee8788, 0xbcf1a307, + 0x7ba326dd, 0x6efb9729, 0x2811de7e, 0x3a96f316, 0xcc19d725, 0xf7747dcf, + 0x1e63f71b, 0xf5c6a77d, 0xdb1fd622, 0xcc7ee87d, 0xf694edcf, 0xbf7b319e, + 0xc68ae41f, 0x7747ddfc, 0x83f7f0b7, 0x6c18bef6, 0x5e6baaf5, 0xb5ef833b, + 0x8fdd0e6b, 0x7553bcf9, 0x489563ce, 0x74e7bf2f, 0xffb3d865, 0xb8adc21c, + 0x13eddb99, 0xf4bfecf6, 0xfde5ea1a, 0x3fefda26, 0xe0863c38, 0xf2fcd55d, + 0xaeb3a466, 0xbfde3cbd, 0x17a3e1a9, 0x74ed417f, 0x54dc0d74, 0xc1832b9d, + 0x9eecd677, 0x1a9af34b, 0xeb1afae8, 0x46388d4f, 0x903a98f3, 0x11d6f3f3, + 0xe78fddef, 0xeff6ba01, 0x6ef90479, 0x683000ea, 0xf9bb3e71, 0x7da2a0f9, + 0xbfd09329, 0xcdb532ef, 0x5ecbf1c7, 0xf339d1d1, 0x74e17da2, 0xc3dbc72f, + 0x9939f963, 0xa8d1d5e1, 0xefaf5567, 0x508bf1da, 0xfda0676c, 0x6e10f29e, + 0xb5c915e7, 0xfe110f59, 0x3cf1da5e, 0x81977bce, 0x310b5ff6, 0xc2f502a6, + 0xa714091d, 0x5f1fe37f, 0x643c47cc, 0x7ce8dbcb, 0x0675d7cf, 0x94e1c215, + 0xcf0036d6, 0x694e38d3, 0x142cdfc8, 0xfcd3c2f5, 0x60517dbc, 0x2fe10e7b, + 0xf51a3ab4, 0x47c0d16c, 0xa7bce3a7, 0xa22fd5ca, 0xe65ec3bf, 0xd85dc6f7, + 0x7e837005, 0x9435ea17, 0xcbb5daad, 0x3be2e744, 0x78f9eaa5, 0x9ea3893f, + 0x5434ebb7, 0xf51d3c13, 0xb4defc49, 0x48e8305d, 0xe7c5b76c, 0x97fa85f9, + 0xbd1fd1d3, 0xf254caf8, 0x55fa154b, 0xcea8a5f8, 0x3f1d7cff, 0xfe245ab7, + 0x33076666, 0x2e93c57a, 0xebae781e, 0xffd3ccb7, 0xce868362, 0xd8ea1779, + 0x560fcc5a, 0xea28a1f8, 0x5f5c5cae, 0x1136aa91, 0x31c296ed, 0x2f91f3ed, + 0x3e98182e, 0x27bdda02, 0xe35155f4, 0xff6819ea, 0xa63e68de, 0xbf8f9c11, + 0xeb7ae089, 0xd383269b, 0xbfd1bf7b, 0x9992b4fc, 0xd4f04fdf, 0x7be15a7f, + 0xad3df0de, 0xb4fd04ab, 0x3f2e10b2, 0xbc7b40ce, 0x7c502e93, 0xbf4ac167, + 0x78239273, 0xb699645e, 0x9ef5113d, 0x863ffe32, 0xa85db99b, 0xb7fba76e, + 0x454dfbfc, 0xc8e50473, 0xb79e7e6e, 0xa0ea51a8, 0x52082273, 0x8b667baf, + 0xe6270ef4, 0x8787f509, 0x07812c88, 0x11b9eb18, 0xa28f3431, 0x079d0306, + 0x0f680e2f, 0xc4a93b42, 0xf6841ed4, 0x32ebd74f, 0xe889c3dd, 0x8fc6550b, + 0x894f7cf5, 0x34ba1613, 0xdf7f4336, 0x1c60e583, 0x0dfe1972, 0x047578a0, + 0x682a27df, 0xcfe7e40a, 0x1e74edcd, 0x263cffdb, 0xc5ecd3ae, 0x2f4d5d8f, + 0xe9fb7985, 0x797047a3, 0x10752dd0, 0xe3ff74df, 0x83a468f3, 0x8b5b1522, + 0x251795fb, 0xea022e7e, 0xa2e21e74, 0xfa2cf7d8, 0xf48018d6, 0x129bf173, + 0xa92ee3e2, 0xfb5ce49d, 0x7c933fee, 0x93b4d2e8, 0xc468fb9c, 0xe8fc937f, + 0x8f9f6e0a, 0x447dab72, 0xd91f7f0f, 0x23cf1f3e, 0x7c7589bd, 0x81fff78f, + 0xfddaeffe, 0xefa8fded, 0x8f3ccaa7, 0x31a4bd82, 0x8710f8f3, 0x270132f7, + 0xae9c36c6, 0x6343ff24, 0x2dd0fd41, 0x166f03e8, 0x98fe5e64, 0xcc5d4fc2, + 0xf911a7b2, 0xc7df80b3, 0xc3557603, 0xcdff686b, 0x84fba309, 0xeca6e1fc, + 0xfc868633, 0x69e2296d, 0xc0fec986, 0x69538008, 0x17f93b6a, 0x87a4ed40, + 0x91d4deca, 0xe9add99f, 0x2bf281d9, 0x8b9f64c5, 0x6db44aed, 0xbc2433eb, + 0x15bda0a7, 0xca29fa4d, 0x3997c7f9, 0xbea575bd, 0x884dcfc4, 0x8162ca7d, + 0xb25bbc07, 0xe243e916, 0x69ab7e78, 0x6f28fbdf, 0x48e2daba, 0xd3f3fb4e, + 0xe8a7a685, 0x404f8a9e, 0xe2bc3baf, 0x7c2c9f00, 0x6601f299, 0xf1881e63, + 0xbdbe73fa, 0xfe4bdddf, 0xf5ecdb20, 0xc6b1e91c, 0x170feeb7, 0x0fb74ba4, + 0xde68381f, 0x00df903b, 0xda13c5fe, 0xbe877ee8, 0xcba84cfa, 0x7e23f55e, + 0x78f6bf75, 0x0fda005f, 0x505d843b, 0x9a7dd432, 0x3c3df7fc, 0xf40ab76f, + 0x07f7d51a, 0x6aa57e52, 0x50ade80f, 0x5f50b7ae, 0x51b50714, 0xbf6baadc, + 0xd779f68e, 0xc68f9f34, 0x523d03f5, 0xf9b8a67c, 0x7ccbdd20, 0x4c87fd10, + 0x94618fd2, 0x39bfb317, 0xe510fd0c, 0x95ca8979, 0xd3f5f228, 0xcf287e51, + 0x2277654b, 0xda95f39d, 0x8388fee8, 0x2a25de62, 0x1758cba8, 0xdf3896f3, + 0x2f7e66b3, 0x5ede3f96, 0x76edc119, 0x9f740f90, 0x79d79ae7, 0x079140dc, + 0x1cae4285, 0x9ca9e7c1, 0x3ecacdff, 0x442d7411, 0x4e47efbe, 0x0b308f24, + 0xe282b87f, 0x58463b3a, 0xa7f45d78, 0x89dc7971, 0xd1bd97de, 0x8a9b1e99, + 0x3dca2cfd, 0x14791e5f, 0x282f91e7, 0x0e482207, 0xc184d1ac, 0x945e8aba, + 0xc2a2fee8, 0xa073ab79, 0x7ea65b39, 0x2d49ee88, 0xe35bbcc0, 0xa7f2f3f5, + 0x57b8f1a3, 0xec52f288, 0xe0ed1503, 0x351740fb, 0xe40d1f7c, 0x2ff5e50d, + 0x073ab49b, 0x68496ff9, 0x4fdbd6a9, 0xd7f8d9be, 0x58af5b9d, 0x0fde139d, + 0xdcad179f, 0x5d883ad2, 0xbda15e3f, 0x72cc2736, 0xde6573fd, 0x3cca0d17, + 0x79066827, 0xeaf663c3, 0x734fbc1c, 0x85dffe99, 0xc5f75f07, 0xf51b9d66, + 0xf697c02e, 0x56bcee83, 0xbd5f13e1, 0xcc8578d9, 0x371ffb49, 0x597fbf9a, + 0x534fb922, 0x57f02d5e, 0xf9d9f13d, 0xa0fdef68, 0xf6be4229, 0x160a25c5, + 0x407ba30e, 0x79870bec, 0x4bfc25c7, 0x55839410, 0xa0e23394, 0xbe70f812, + 0x28781fb5, 0x0467ffed, 0x329a4fcf, 0xe0d5f382, 0xbdcfc5a9, 0xa39e28c6, + 0xe3741d4e, 0x54a621f3, 0x7cb74fce, 0x2062643e, 0x60c8776f, 0xf74fb8c6, + 0x5c51bfa1, 0x719d7bb8, 0x306fdf36, 0xdf7848b2, 0xddb6911a, 0x8afbfe3b, + 0xe7814738, 0x7efce9be, 0xe387e6b2, 0xbea6a94a, 0x1bd912b8, 0xcfb481a9, + 0x9574d5d2, 0x4b775bf4, 0x43f719a6, 0x469cdaba, 0x7ff2b7e4, 0xea184ffc, + 0xb396aee1, 0xf5d69794, 0x57ca79dd, 0x06f228db, 0x7c89348f, 0x098b36af, + 0x7ee7779f, 0x36ed8391, 0x5713d289, 0xa53171e0, 0x2565fc54, 0xff75e07e, + 0x6b8428d1, 0x93e379bd, 0xa60f3019, 0x1ddfa6af, 0x0439ff00, 0xae2787f5, + 0xa1ff0960, 0x2b8c4a3c, 0xb8f027c4, 0x57189602, 0xb8f0d788, 0xae31d602, + 0x15c62580, 0x15c639f0, 0x05718eb0, 0x015c63ac, 0xc05718eb, 0xf80ae312, + 0x8e716bfc, 0x378c1ba3, 0x9234f71e, 0xcf515ffc, 0x88576bf7, 0xd457a1fb, + 0x85b7944a, 0x0f5038e7, 0xd3c7975e, 0x5c78f228, 0xb03f685b, 0x456cbf7c, + 0x0f79e154, 0x79f30e87, 0x3c628e7a, 0x64af7ca8, 0xe7c16d5d, 0x1b1e69b3, + 0x9e3f325b, 0x35ebcf87, 0xac97bc56, 0x309be5bb, 0xb515778c, 0x6adc53d4, + 0x2d21f852, 0x6241b9e1, 0xa59d6f18, 0xa9727ee3, 0xd3474f0c, 0xd1d929be, + 0xf236baa5, 0x4a778a5f, 0xddf3ef66, 0x90af63e5, 0x9bcbe89c, 0xf9cc1972, + 0xc6d5fa3e, 0x4ff0aef3, 0x57d88fc4, 0xf49bca5e, 0x3d9159e5, 0x2d1f65e2, + 0x7c64fdc5, 0xe7477f2e, 0xd1c14a4b, 0x93f5281d, 0xcfb7e587, 0x77b2d45c, + 0xe29bde3d, 0x77dcdfbf, 0x9f6fcf5e, 0xd8aa6579, 0xcfc51e4f, 0x9d3ee489, + 0x7c3f67bf, 0x475ab7af, 0x70e54af6, 0x266a657b, 0x28d86be6, 0x90f472ee, + 0x2fadfc81, 0xc4f924b7, 0x21e5b25d, 0xae58f714, 0x6b8f4891, 0xb0ebed92, + 0xc5dcc4df, 0x18996f14, 0x567e2261, 0xa4bdf0e8, 0xfdf1c7bc, 0xc50b34f2, + 0xec75b2bb, 0xc89e3467, 0xf89282ef, 0xa24abb2d, 0x3217a97b, 0x597b9d2b, + 0xf2f7e360, 0x2de8f729, 0x41cf3c60, 0x5be5aba1, 0x282bb224, 0xfb861100, + 0x0b9e1c9d, 0x7ba1de5a, 0xc4eb164f, 0xbe2a7e3d, 0x89b51e1f, 0xc12cbfe7, + 0xdef0a41b, 0x58abd010, 0xb37d9e82, 0x03db9e1d, 0x3b734487, 0xe38e12df, + 0xa1ae3c2f, 0xf0ece13c, 0xa4ed13bb, 0x3e5127ef, 0xf6ef5e03, 0x921f88fd, + 0x0cf9bea3, 0x43793547, 0x48addd70, 0xb1e714a7, 0xb2bc7953, 0x9e254a80, + 0x762fe4a3, 0x17b83a1f, 0xce5d9fbf, 0xe1bde5ef, 0xfe80bd79, 0xe729adcf, + 0xf9145e15, 0x53aa5175, 0x75fcf063, 0x2b46b7d4, 0xfc3b3fae, 0x8af79d10, + 0x4e1fe313, 0xe5037bcc, 0x39882d8a, 0xcbee1fb0, 0x733c0354, 0xc6120170, + 0x3c365dcd, 0x4873d337, 0xf51e5332, 0xcb73f275, 0x29efcc3a, 0xdee8978f, + 0xea809cf0, 0x3f1830ec, 0x8ac63627, 0x89bcbbf2, 0xa0bb5dc7, 0xc3bf78e4, + 0x3181f749, 0x14d73f7e, 0x2490b781, 0x4cd489fb, 0x82a9f3cf, 0xae5bba6f, + 0x9be1fcf2, 0xe8eb65c7, 0xb06613be, 0x21b1f72a, 0x188ea7de, 0x8559f14a, + 0xc21b7a6e, 0x7cdd23b7, 0xbcc3f42e, 0x68352779, 0x6c987c3f, 0x30e10cff, + 0xbacaff3f, 0xff675a30, 0xcf2531f1, 0xa63e3fde, 0xabffedc8, 0x2bf7fafc, + 0x513ca82b, 0xb6ca92b9, 0x07bd074a, 0xea75f0bd, 0xff55c5ad, 0x8ff5f08e, + 0x65bd32ab, 0xe057e900, 0xf6c71e6f, 0x5f02a38b, 0x7af8bcab, 0xa2f04b62, + 0xd47f680d, 0x4ffee968, 0x615e77cc, 0x49a03924, 0xaa9e37eb, 0xf148cdc0, + 0x18665ed7, 0x909ff08d, 0xc156a71c, 0x926901fb, 0xf200fecf, 0xf90fae09, + 0x13e44b04, 0xf3dc57b5, 0x70b02d05, 0x1c07b706, 0x08180f64, 0x8357ebaf, + 0x1ef090fc, 0xfc8fb325, 0x3f27e4b8, 0x907971c0, 0xf0b57dce, 0xef2526fc, + 0xd7140273, 0x4f23f746, 0x0c9e5c5c, 0xc2ed700d, 0x0b2d0cef, 0xa3e2bca0, + 0x475f4e1a, 0xb9bcf237, 0xefc7967c, 0xae5eba6f, 0x163e2104, 0xf339ec0f, + 0xfc5fb43c, 0x35d9232b, 0x669723eb, 0x257227fd, 0xc3c38d20, 0x63258131, + 0xcacdf27e, 0xe045ee7e, 0x314e66f7, 0x2e5b9f91, 0x7cb2a0ec, 0x72a7f133, + 0xed4cb43e, 0xed8f58ea, 0xff3c4d42, 0xbee8cd43, 0xc1aa5396, 0xc1599efc, + 0xc4a6a767, 0x58605e51, 0xa887bf15, 0xee896ee7, 0xc8149e03, 0x56c857ef, + 0x0cbc95e5, 0xb956dfef, 0x54c1efc5, 0x122bf8d3, 0x73d15c79, 0x6bdb951e, + 0xba26b951, 0xbaf6413f, 0xc631a93f, 0x39f45eeb, 0x6ecfbefc, 0x4dff72a7, + 0xa087bcde, 0x7e1ccd5f, 0xb33766cf, 0x03fb813c, 0x7100828e, 0xb5e8127f, + 0x99fdcf0c, 0xedc9fe07, 0x15429ebc, 0x19ad539d, 0xeb8d5965, 0x42cc79aa, + 0x27f73def, 0xe8dcf871, 0x82db9c3e, 0x8369f9ec, 0xe717bfae, 0xce6f2919, + 0x669fec12, 0xe34ff7e4, 0xeed08de5, 0x4fe19ce8, 0x0e3840ec, 0x3da264b1, + 0x706c68be, 0x11f40496, 0x06f306a5, 0xd4630fe8, 0x46d05f74, 0x71f313b5, + 0x7dc5a887, 0xef216a01, 0xd180c861, 0x85a6ded4, 0x96a7c2fa, 0xabea1b31, + 0xf3f74628, 0xfef9ebc6, 0x5863f438, 0x4646b862, 0x7c78c83d, 0x3e00e168, + 0x4670c2fe, 0x45a5cfbf, 0x3bf25016, 0x2677f0b3, 0xb0bbc518, 0xea68d07f, + 0xfef150ef, 0xc3943536, 0x523df8e2, 0xb474eb3d, 0xf1f0ba2f, 0xa71fa4a1, + 0x773df04d, 0xe78d327f, 0xb8e5282d, 0x9f0f8b74, 0x429b5a2f, 0xd68b8bfb, + 0x3b4529ce, 0x4810dec4, 0xef3b02e7, 0xef0ba97b, 0x9d962f71, 0xf5823f4b, + 0x57b74ecc, 0x4a2f7c23, 0xa1fbf996, 0xdffba2c1, 0x8c9e62d2, 0xf2e335dd, + 0x774e50eb, 0xf7813dec, 0x4fbf4de4, 0x19d3fea6, 0xad9a8fbf, 0xde6cf7e5, + 0x8ea2b8ed, 0x1eeff180, 0xbcbc5127, 0x468e60c3, 0xc0a16efb, 0x5c69f3d7, + 0x3f5c2f7e, 0xebfd1134, 0xbddf71bb, 0x5a733d1f, 0x0fde53b4, 0xfc7cc89b, + 0xfbc54f9b, 0xfef8d34f, 0xfe38b0fc, 0xae837f3e, 0x4b082e23, 0x4a093b8d, + 0x4ec2758d, 0x58b4cf5c, 0xe115b396, 0x378f28f8, 0x9b981876, 0x8d3eb1e8, + 0x3d676ae0, 0x3ae38f1d, 0x3ad046ea, 0xa39bc63a, 0x710e5ee9, 0x3312eb7f, + 0xe31d4f97, 0x98ce77f9, 0xa9214ddb, 0x1ef07f9c, 0xa502c5d7, 0x3d565767, + 0x5bb41b79, 0xe74f4abc, 0x7d3c9735, 0x8b2bf92f, 0xa73a646b, 0xdefb36c9, + 0xc4fa0ae3, 0xbff3f38d, 0xdeffd58f, 0xd239c455, 0x8966fe41, 0x955868e8, + 0xf1fb8b55, 0x4ec05b3d, 0x46f9f780, 0x05da3c77, 0x758356f9, 0xbdcfd48d, + 0xdc01dfac, 0x6b9ef0b2, 0xcf93f146, 0xe01fedd3, 0x2f561777, 0x03507ba4, + 0x1714ed53, 0x217e061b, 0x48413fda, 0x69d7003f, 0x7fba5e00, 0x891edd42, + 0x34facffe, 0x9cc43cf1, 0x34ba2468, 0x0ee7e430, 0xe711398d, 0xa0ceb1d7, + 0x6d319942, 0xe04fa70d, 0x347abd1b, 0x0160339e, 0x4bbfbfc8, 0x6f3974e3, + 0x16af3ab5, 0x6d4043ea, 0x6e90429b, 0x4e7d1146, 0x50ebdab6, 0x18f57daf, + 0x73728b1b, 0x7c2de6f1, 0x4cff025e, 0x34e746dd, 0x198faabf, 0x0a06798d, + 0x4eb64c3d, 0x4de69b38, 0x8449f707, 0x31cf587f, 0xeb1a37d4, 0x2f5c4ea2, + 0xf48c3f3c, 0x9b826d31, 0xe5b212f2, 0xbcfdfa12, 0xf74608de, 0xce32f4f2, + 0xd41bbdaf, 0x391467a4, 0xa003c8a1, 0xd39e1b07, 0x7ffdf055, 0xf2287f65, + 0x7243e006, 0x8a1b9145, 0x4be8517c, 0x74fe3391, 0x7cc01f35, 0x4fea68e7, + 0x63914cf2, 0x68d50eb8, 0xf0517c8f, 0x5e30d9ac, 0x81577145, 0xd2f96ce7, + 0x8708839e, 0x2dd92302, 0xea31707d, 0x5ad12e09, 0xcff784d6, 0xb7943d56, + 0xe3d22977, 0xd063732f, 0xe05b98fe, 0xa7f29e7b, 0x28e7be15, 0x3df4ac17, + 0xe56f3947, 0xfc628e9f, 0x0fb00d89, 0x9cfc074b, 0x17b9e5f9, 0xefea863e, + 0x8131797e, 0xea97d9fb, 0xaeefc59f, 0x68f3100a, 0xa55af3e7, 0x4c31bd25, + 0x0ff881d8, 0x7188b2f1, 0x13185d3e, 0xdff5027c, 0x093f105f, 0xf1c1ffb8, + 0x67e04673, 0xe80fc211, 0xae3ae17e, 0x121c3a97, 0xad1623c5, 0xc1ba7c15, + 0xe7f47cf7, 0x303dac91, 0xfa8e73ce, 0xa312c7f3, 0x7395af91, 0xfc0df6d3, + 0xf2b4b55c, 0x762fd918, 0x872d7ee5, 0x2b5afddf, 0xebf9f95b, 0xcd73df76, + 0x2d361981, 0xf7182bc5, 0x1f2516a3, 0xd536f9e1, 0xbbf71992, 0xfcf3c5f3, + 0xb9cf920d, 0x1e749cb9, 0xa698da17, 0xa3b63c26, 0xcaf1429d, 0x0a2fd26a, + 0xa0dc829d, 0xd5f97c73, 0xbd4bb4a3, 0xf122e8e4, 0xcab2717c, 0x36d777e7, + 0xebfdf1a6, 0x181a6476, 0xac725377, 0x3bc90976, 0x9547c50b, 0x47928bf6, + 0xc1b8c7af, 0xebf8cda2, 0x33fe9e47, 0x367cf9d3, 0xdc94f98a, 0xe5f7ce40, + 0xb79fe155, 0x9fc9bcd3, 0xf7757a2e, 0x033bf8ab, 0x91d57f45, 0x291a299e, + 0x9d53d9f6, 0x3ed2f759, 0x55d73f32, 0x693df026, 0xe84167f7, 0xf2379427, + 0xeca1b2fb, 0x556cb2c0, 0x65fbf901, 0x9087e056, 0xdfbff3eb, 0x41aff57e, + 0x88ecbe3c, 0x47ffbf12, 0xd65563bf, 0x1fc505f8, 0x64772ed0, 0x4f9478d0, + 0x5cbfdfee, 0xfb882efa, 0x9704edb1, 0x84df43ec, 0x5ff63cd1, 0xf979b8a5, + 0xf66175a1, 0xdd7dd67e, 0xcf110139, 0x2af81728, 0xe0af9b67, 0xaaf95afe, + 0xc82cf3dc, 0xbf7fbe33, 0xce22e975, 0x8dbb1b70, 0x4cd5d6f2, 0x5ccf7de5, + 0x07e133af, 0xb7cb25f3, 0xbd9d73f2, 0xdc00cb6a, 0xe716eb97, 0x1ddbfcb4, + 0xc37ee74f, 0x0c27e065, 0xc8377444, 0xddd3cfb4, 0x6578e3c0, 0xe2b54f0d, + 0x7032d8f9, 0x959d919c, 0x8d654473, 0xeb7bd332, 0x1a47cc35, 0x1679e378, + 0xfdd136ef, 0xc92e8534, 0xe9f30f56, 0x90697f05, 0x165e7cd7, 0x73ac5574, + 0xcaf8e165, 0x72105ffc, 0xd857694c, 0xb79d14f2, 0x645d7685, 0x903efc9f, + 0x9eb2fdf1, 0xcecf3813, 0x7f68636d, 0xb7b5d0ab, 0x0d8fe28c, 0x72b79481, + 0x7e7be351, 0xdef89f7b, 0x676e74be, 0x24de6274, 0xa6557ff6, 0x13ce19b8, + 0xe4a2f1f9, 0x2cd1cf9b, 0x73a735fa, 0x3a7e653b, 0x7da503e7, 0x2823aba1, + 0x6f9fda1e, 0x6f9513fa, 0x6f7c7b61, 0xbd474b6c, 0x9031be79, 0x6f9ed3ce, + 0x0de73e7c, 0xd765def8, 0x8bc950f8, 0xf3a74ebf, 0x6de5e5f8, 0x73b05ce2, + 0xe26738a0, 0x3674f5a2, 0x5fe84944, 0xaffc8a96, 0x417dc6ce, 0xc75fe22a, + 0x627bf67f, 0xefbbafb3, 0x264c77ac, 0xf76cbf9e, 0x7fecefb9, 0xf132fc6b, + 0x13caa8dc, 0xb7bfe1df, 0x5ddf94ca, 0x4a76f331, 0x48fe763c, 0x0e7803cb, + 0x7fc7bd97, 0xfeec0d97, 0x9a3fd167, 0xe481c7ff, 0xadefe27f, 0xf7ebfd60, + 0xfcd9bef9, 0x44ae4231, 0x4cbe53b4, 0x1fb70c47, 0xcc48364a, 0x062b7006, + 0x680072fa, 0xb3329c4b, 0x231dfde3, 0x2772fef9, 0x2476bfd0, 0x67ca0bc9, + 0x1dfe0339, 0x6bc10efd, 0x24b93f7c, 0xe7889dd6, 0x5e453b03, 0x3b884941, + 0x7b8c2071, 0xc949d049, 0xb7a2774c, 0xddb2537f, 0x9735794d, 0xbe1d3e44, + 0xc95e78c7, 0x23aede68, 0xe745dcc6, 0x189bf638, 0x83aaabda, 0xd2c3a226, + 0xbddb0d97, 0x4699d5cf, 0x92fffb72, 0xee1bdf96, 0x53e7c1d8, 0xe34d5418, + 0x5df4125c, 0xf34d5018, 0x29ce233b, 0xbd796a17, 0xbee8c343, 0xfc5d9efe, + 0x918ba13e, 0x3bf0076d, 0x50a57717, 0x8c4769de, 0xbd136973, 0x452679e7, + 0x38dce8af, 0x4cbb0baf, 0xf7282e74, 0x9f695b97, 0x274eb7b1, 0xc2e1dc61, + 0x1ee74620, 0x220fd42e, 0xb2417d7d, 0xc2f37c50, 0xbc6903bb, 0x7495caa2, + 0xc408a5be, 0x509dda04, 0x76bda2e6, 0x68b9fea1, 0x6fa85fe4, 0x559dbac0, + 0xf239ffcf, 0xbbfe4ee9, 0xf95f1710, 0xbef78a7b, 0xeffa528f, 0x54f8289f, + 0xe48da7de, 0x923698fc, 0x91a8f3f3, 0x3bde7e66, 0x2c4cf5d0, 0x37f38fad, + 0x02fc99c0, 0xafba27e0, 0x39ab8ce7, 0x8a71824c, 0xa86c9a0e, 0xee343bdf, + 0x0e09e7c4, 0x7877e281, 0x1785f918, 0xbf240c76, 0x1a68ac1c, 0x348ec2e7, + 0xf252d3ca, 0xada1a64d, 0x234c7846, 0xdbcb66f8, 0xe5fee9d2, 0xc7ca40ba, + 0x36fc7a29, 0xc89fe515, 0x7a2eeedc, 0x5134f175, 0x4d7ee1b7, 0xa17fcfd1, + 0x93e28bc0, 0x89695e4a, 0x8fa5a390, 0xf30031df, 0x651fd970, 0xaabb93ca, + 0xfe8f79e6, 0x48e5f970, 0xbc0f4721, 0x025b7c40, 0xc3bf8e74, 0xc2f22c54, + 0x71e15f8b, 0x77f5e296, 0xf1f24b3c, 0xde618684, 0x53d725ef, 0x2f70de41, + 0x96e5c918, 0xda95bfa7, 0xde7b4317, 0x9a20bdff, 0xe50d0ecf, 0xebe3fb29, + 0x22bffb96, 0x8bfd5bff, 0xf407605c, 0x957c1fb3, 0x57f23db5, 0x060d0394, + 0xf29e83ab, 0x8d4ebdfc, 0xdf3f296b, 0xd0f92060, 0xaf7e2c19, 0x11e792b5, + 0xfa9faf14, 0x3857ca6b, 0x699d2f75, 0x7fece65a, 0xa474aebf, 0x0f8bef86, + 0x3e400eb4, 0xe07c052c, 0x3a1f8078, 0xa8fece5f, 0xebfefea1, 0xcb923a99, + 0xdc3e3ef5, 0x3ba1f3c3, 0x74bc7307, 0x7a449abe, 0xd39823a7, 0xfc97cc35, + 0x5e60ced4, 0xe604a252, 0x3d3998df, 0x91778e74, 0xed29ddff, 0xc343b2a5, + 0x14ad15fb, 0xe6e22bbf, 0x482523f9, 0xff7871b3, 0xb436e6cf, 0x671e503b, + 0xadd2a68d, 0x1efeb90b, 0xf263a076, 0x7e0a8eef, 0xe870f252, 0xae280177, + 0x3ca2d2e9, 0xafbb0bb5, 0xdffae1a4, 0xefe7e08b, 0xae43ca25, 0xfb29291b, + 0x540794ec, 0x2b3c25cc, 0x9fb44876, 0xa1f6bc5f, 0xe2fba442, 0x91732d8a, + 0x1475941f, 0xfa2e59ab, 0x4c921d49, 0x7ebf01f3, 0xebd4ccc1, 0xf7c0a7bf, + 0x197ccaf7, 0x3d27cfdf, 0x6fb6bc03, 0x53b145a4, 0x578c3559, 0x4cda56b2, + 0xfc5189df, 0x053ebe4e, 0x83efb84e, 0x3c4a8cf9, 0x57eb46e0, 0xf9a379e6, + 0x75e423bc, 0xd7e58c47, 0x1fdf10e3, 0xae4f24c8, 0x4066377e, 0x6dd80fc8, + 0xcaa14bf4, 0x0fff3078, 0x38c11751, 0x56790acf, 0x79c3f30c, 0xfdf36e26, + 0x3ae4807d, 0x06f0fadf, 0xa36a7adf, 0xc5bd3d6f, 0xdb7d6eb7, 0xdf82deb7, + 0x09c0f4cd, 0x073c61fd, 0x879c53b1, 0xcf187f40, 0x8c3fa133, 0xb187f475, + 0x9f187f44, 0x758c3fa3, 0x8eb187f4, 0x8925b0fe, 0xa258c3fb, 0x65cf8c3f, + 0x4953872b, 0x023f8f2d, 0x2fb46c1e, 0x5df9473f, 0xd10bf00a, 0x421c2d1e, + 0x7cc61d76, 0x7e9577e9, 0xd2296d79, 0xfd930cd1, 0xcc4cc8d2, 0x1f5b6ac7, + 0xf2fded89, 0x1b464a94, 0x686f188c, 0x3d7e775f, 0x2629219a, 0xaf6c15fb, + 0xae952fe4, 0x4f7e8b7c, 0xe5b57daf, 0x78e13f8f, 0xf287b8a2, 0x78454f7b, + 0x714cbe4f, 0xf8a33d2e, 0xdfdf559e, 0xf9fedc3d, 0x679ab746, 0x5801fff4, + 0x00db8bbb, 0x0000db8b, 0x00088b1f, 0x00000000, 0x7ccdff00, 0xd594740b, + 0xe6feefbd, 0x49324995, 0x41e42126, 0x21e4cc20, 0x49389311, 0x47114bc8, + 0xa8d53048, 0x684d43c3, 0x4092138c, 0xa3c30480, 0x7b96c4eb, 0xa4401833, + 0x51b78d70, 0xa13a3951, 0xe85de94a, 0xb6950a09, 0x1006739c, 0x4e6d8ac5, + 0xb6abad5b, 0xa9078838, 0x68349687, 0x69edec57, 0xdff7ffef, 0xbef997df, + 0xbc7b5249, 0xacdd77ab, 0x7bfe7ba5, 0xfe3f6fef, 0xeffffdef, 0xfc42108d, + 0xfb5bfe85, 0xdaf08c7c, 0x85fdff05, 0x442fdfff, 0x59cf10b9, 0x0e9d3247, + 0xd77c2e21, 0x4f5c5bbe, 0x1868ac65, 0x06e6a42a, 0x09a449bb, 0xb8df11b1, + 0x5335a884, 0xef0479a7, 0x28c7f651, 0xa4f34c42, 0x885d3108, 0x49f933d1, + 0x05fffa82, 0x2c4f377f, 0xa8cac75b, 0xadde0eb3, 0x6ccf3098, 0x548af09b, + 0x735dfb1a, 0x4f1a05f0, 0xa24d79d4, 0xea4d8842, 0x35ece71a, 0x59105109, + 0x38c1b5ef, 0xbfeb7421, 0x018a60ee, 0x619a1a2e, 0xb1fd7fe8, 0x497b431c, + 0xbda1ae68, 0x13d6f96d, 0x962144e6, 0xf4332eed, 0xbc116abb, 0xa7cfabcf, + 0xea6e0307, 0xf0d1bbe7, 0x3aea109d, 0x936eb29d, 0xc3fce475, 0xd1d37fd4, + 0xe3004f4c, 0x2f0b35ee, 0x8d03b7ed, 0x2b6442a5, 0x4f181d81, 0x179e2a0c, + 0x6a56bc68, 0xe8bb53f7, 0x9d38f3b1, 0x2c3b7e2a, 0x2da4e022, 0x9bf3447d, + 0xd1e77fa9, 0xc256e0f4, 0xc9c61f4b, 0xf0a776a4, 0x6b78d326, 0x87170ee6, + 0x6f359c68, 0xd042bb7e, 0x83ccbb16, 0x215cced9, 0x03c12b36, 0x9f10b34e, + 0xab4e1ca4, 0xd98776a6, 0xf443c8bf, 0xfca67cb9, 0xe78455c7, 0x1ecc87cb, + 0x0d6d93cc, 0x291295a5, 0xab268385, 0x038cec06, 0xcdfb07fd, 0x63a24175, + 0x9cc3ad16, 0xc18fe112, 0x797169fe, 0x35bec88e, 0x0b6d987e, 0x7d84dccd, + 0x79eb1cbd, 0x0a3f8041, 0x9dbc62ef, 0x8fe02b31, 0x80945b8e, 0x3ec8faed, + 0x77e53a37, 0xea3e7eda, 0x7c0632a5, 0xdb3e65e6, 0xbe5fb6ac, 0x8bb144f6, + 0x7bd9d1f6, 0x2c4cdb2c, 0xe874ceb0, 0x01952640, 0xfb19bfbb, 0xffcc18e9, + 0x679a7cc5, 0x61663bed, 0x3efffea6, 0x9ab128b0, 0x8bc9f7f6, 0xc13d4f56, + 0xdb7ff70f, 0xac7da616, 0x1e6d04b5, 0x3bbe3b2a, 0x7952f368, 0xae41c1eb, + 0x65b0755f, 0xb575f831, 0x7d81dee8, 0xbf12b25f, 0xb1d1f0eb, 0xa4e7d950, + 0x31eebf75, 0xc4777f31, 0x6bda3f09, 0xa74ff3cd, 0x95077f62, 0xb97b2c12, + 0x85adb0ef, 0x7ed47bea, 0x7a32f2d1, 0x74ed5976, 0xa43a3fea, 0x92a7de30, + 0xd743bb8f, 0x1b2c7cb2, 0x7cb97373, 0x88213aec, 0xbe11df25, 0xa5744122, + 0x3ef01ab5, 0xfcccd67a, 0x1cdc7a39, 0x8749f414, 0x0cba942d, 0x2b17f874, + 0xf88ba1d3, 0xa4f88aa7, 0x40df7e8b, 0xd9be6fa5, 0xd40fbfc0, 0xbdf81bc4, + 0x88e4e841, 0xcc47bbc6, 0xebcbc030, 0xeffd0d73, 0x945d7e5d, 0xda46943c, + 0x0dfff8cd, 0xbb827691, 0x4a5c04b6, 0xc685a022, 0x30b72a7a, 0xf866dd9f, + 0x8d2c4bbe, 0x3f9f03f4, 0x678c6fff, 0x4b6d8621, 0x26bf688b, 0xafd107a2, + 0xad5e7fc1, 0x6d3d730f, 0xb39720c4, 0x98bf3d73, 0xf2317c4f, 0x47ec55b6, + 0xdf089fc5, 0x7f46e815, 0x20e913b9, 0x9d5a1104, 0xb1d68937, 0xa9c908fe, + 0x618a5f41, 0x06eb17d0, 0x74b6ba1d, 0x2a628bd4, 0xb4059be9, 0xb0c0ae8f, + 0xf8c1dbad, 0x4a1164b7, 0xa22bf7d6, 0xdbfb8527, 0xbc2452b3, 0xac47f505, + 0xf875861f, 0x686378c3, 0x816e633f, 0xafb744bc, 0xac0b7da7, 0x3dfeec47, + 0x2dfad5f4, 0xde631f75, 0xea3cdaf5, 0xae9f1af8, 0xebdf4bde, 0x9e3d1dd6, + 0x72c5c4a3, 0xe1e0f6bd, 0x7e1067d7, 0x4b92f996, 0x439d4720, 0x852dac4b, + 0xd34df913, 0x9a0f57fb, 0xf06e3183, 0xb7e629df, 0x8f5683d1, 0xb2f01bf8, + 0x0f182bde, 0x8ab87cd1, 0xf9a765f6, 0x3c511d57, 0x03f64541, 0xf146d67e, + 0x9acdc627, 0xbe1a6f04, 0xd517f1c6, 0x683f1abe, 0x298fab9d, 0x09cbe841, + 0xa7c68978, 0x3f2acf3a, 0x0aeb90fd, 0xc6a2baf2, 0xf2d15515, 0xfe86c9b8, + 0xe114fba3, 0x1f18be54, 0x2c6cc74b, 0xe573b3df, 0x2a8e47fe, 0xddf4fd9e, + 0xae16633d, 0x1f1fe71f, 0xf214ade1, 0x921f0137, 0x7e527c9f, 0xe34b1eee, + 0x7c5efeef, 0x34fc45f5, 0xefdc573b, 0x7af44473, 0x621e9e44, 0x49294b3e, + 0x5b48bd48, 0xace5dfa0, 0x3b3d541f, 0x4d243e95, 0xfc94facf, 0x71e7e603, + 0xf894e3bb, 0xa57568dc, 0xeb4f8327, 0xd468f68c, 0xd64a4ae2, 0x642d21f9, + 0xc0d35d67, 0xc2d333bf, 0x609f8e34, 0x4f4d57e8, 0x76f1d5fb, 0x0ecdcb6c, + 0x6ff3beeb, 0xea09a6b7, 0x1a75bd9f, 0xceb12d97, 0x9691d834, 0xec1f66ad, + 0xa48f87e3, 0x5f1155a7, 0x9addb87d, 0x7c434f5a, 0x6cbce0f8, 0x96b80451, + 0xc58f0bcb, 0x131d0434, 0x625d55f7, 0xfd747c62, 0xaed8f7f7, 0x3674d6fd, + 0xb77201b1, 0x156268fd, 0xfb6eb38d, 0x649c2acf, 0xfe4c87cf, 0xffda12ba, + 0xdb20ca27, 0x2c1ce173, 0xfc4515f6, 0x6bdbb589, 0x3bf761d3, 0x59ea7cff, + 0x56ff7dd8, 0xf8899a6b, 0x273f37e8, 0x3db0a87b, 0x52e23f63, 0x4be3e4ac, + 0xfb07c42f, 0x292fff88, 0xf54b1bc2, 0x8a27cc6b, 0x7afb069d, 0xffcc1efc, + 0xb79a76cf, 0x0f06f31c, 0x4f5e6064, 0xebcc1ae0, 0xe49f9adf, 0xddfe2bff, + 0x7fa57b03, 0xe7b54077, 0xa0328857, 0x3b5ec1db, 0x97abffc3, 0x88473d10, + 0x0c19bd43, 0xe2ebd4bf, 0x80b7a872, 0x3914d7eb, 0x46fbbd25, 0x3cd2364a, + 0xa0a28581, 0xa3aded9b, 0xdfeb42c0, 0xe079c4a4, 0x3c526c4f, 0xfdd04ee9, + 0xced2c9e7, 0x5e8bf4aa, 0xe4234dcf, 0xf3f8e983, 0x68bb31e6, 0x2deff1d3, + 0x2f00d922, 0xfa1a67b2, 0x86dd3ad7, 0xae335bf6, 0xc57fb435, 0x6f806255, + 0xf436a82f, 0x8b73c3bf, 0xeaabbe01, 0x4bfe862b, 0xf00c4bbc, 0x4346bab2, + 0x2d7dbbff, 0x1b7bf686, 0x1bda18d6, 0xf00c1bfd, 0x341e3b57, 0x7bafbff4, + 0x2bdda1ab, 0xbbd8169c, 0x171f44e3, 0x885ffde1, 0xbd37282e, 0xd3d0ef9d, + 0x5322fe75, 0x7c24d0f7, 0xf48968fb, 0xea517e6f, 0x98fe05dd, 0x487c9265, + 0xc3ae17a5, 0xd427b033, 0x0a42259e, 0x38622bfb, 0xdd137c13, 0x7e7dba2f, + 0x2eabc9fc, 0xf4ada1a2, 0xe90b06c3, 0x2795f98d, 0xbe0972cb, 0x1b6be5f3, + 0xe61fa42d, 0x2af278df, 0xb6951fe0, 0x32fb7235, 0xc345aec1, 0x04376fcb, + 0x6ff39d68, 0x81edd9ce, 0xe913f3df, 0x9fc54cf7, 0xbe5b77d8, 0x10ca37dc, + 0x93ca23f1, 0x5f288fc4, 0xb36c7e23, 0xfc47bf92, 0xaf4cf288, 0xd47feb87, + 0xd9e5c55b, 0x3f972f5e, 0x72e3adee, 0xe5c7d7b8, 0xb81b7b4f, 0x9faf79fc, + 0xb7b77bbf, 0x7af7cb83, 0x97feb9bb, 0xfe5c3dbd, 0xf5c037aa, 0x2c2896af, + 0x0102b4ff, 0x037b05bd, 0x776f5dfe, 0x77a4cc84, 0xe5eb31c5, 0xf24abd71, + 0xdda578ad, 0xa2a95c54, 0x6ebeca89, 0x5c878e11, 0x17c92d86, 0x39f8be89, + 0x7a237ed9, 0xea2e22d4, 0xc61fadfc, 0xaf424f7a, 0xc9d33108, 0xffad58fa, + 0x69ef52a7, 0x15ee5fae, 0x977a7d7a, 0xd023ffdb, 0xb2f71dfb, 0xec3332fc, + 0x24e9f753, 0x24c77a6a, 0x93e3263a, 0x593e5467, 0xc62c4f60, 0x3d816ef9, + 0xb27b083b, 0x83ee12c0, 0x4cfbea1e, 0x3d221eb8, 0xc6c12274, 0x11efa97a, + 0xca13fb0b, 0x9be182a7, 0x7dc30552, 0xa19b0d9f, 0x3d381777, 0x54576c19, + 0x022ecf38, 0xdd722949, 0x4a1e6758, 0xa7cd53c2, 0xf3b045e1, 0x2e6c3937, + 0x5f9c09e8, 0xcf314a62, 0x02bcdabb, 0xd7bd52e3, 0xff3fdf46, 0x68990899, + 0x5fa8b35d, 0x10a5f32c, 0x87d81728, 0x87923ecd, 0x276f5499, 0x9bd51678, + 0x02d7bb65, 0x6c3a7c3a, 0x76a11d86, 0x03db2491, 0x7cc894a6, 0x2c133ada, + 0xeca97e34, 0xe72a5897, 0x39c0bc01, 0x3ad0a254, 0x1e1cbafb, 0x02dd21e0, + 0x5efee7de, 0x543f7f33, 0x3a1e04e2, 0xfb411e1d, 0xe2052c20, 0xaf1fb94a, + 0xd722c133, 0x5fa9f353, 0x432fd178, 0x71d46278, 0x803db2ec, 0x0d4a6e71, + 0x8f805a65, 0x20279b6e, 0x9d62f1c7, 0xfb2f17e8, 0xb93acc85, 0xad03fbcd, + 0xacffec97, 0xf4376194, 0x4c43f12e, 0x2bd4f829, 0x539961f9, 0xa97083f2, + 0x1a1fcab0, 0x4a752cbf, 0xedcafc92, 0x78d29677, 0xafe718be, 0x7fce49e3, + 0x97e6e4aa, 0x512cdf10, 0x1fbff5fd, 0xfd2578bf, 0x7bbd5267, 0xf468df22, + 0xe347f8d1, 0xd23e6883, 0xb7a340f8, 0x7f345df6, 0x3455f345, 0x4bb02d3f, + 0x0f8e833a, 0x49f91329, 0x906874f9, 0x6769dfd7, 0x4fcd16bb, 0x35307cd1, + 0x4e7dc93f, 0xfd08a3e4, 0xcf2f8f81, 0xde6ec347, 0xa4fb66c7, 0x8ff1a47c, + 0x1f1a4fc6, 0x16223fdd, 0xcb535127, 0x9475eb98, 0xcffc727b, 0x8ab48f40, + 0xab33165b, 0xbe45cd38, 0x9efd8984, 0x5bdfa298, 0x501fc4b1, 0x2f73c23c, + 0x2e3381fc, 0x7ec5d8ab, 0x4251d7b6, 0xeaa45bf4, 0x9ba233d1, 0x8fb91ced, + 0x46b5d001, 0xc2a2f125, 0xd77fecd5, 0x2c7e8c38, 0x88fc232c, 0x17efd4db, + 0x0db7c9ff, 0x6a9c58eb, 0x536f6ff4, 0x455be3fd, 0x375f8f3f, 0xf0bdaa33, + 0x6f9bf656, 0x6fd633cb, 0x5efd5528, 0xcf4370b7, 0x5c8f08d6, 0x7ecdd89f, + 0x572a8d6b, 0x72fd2a59, 0x9f31665d, 0xfc2b58f0, 0xd7f72816, 0x62f3677e, + 0x80455bdc, 0x2088afe1, 0x108bb797, 0x1907738f, 0x0977c002, 0x69dc0561, + 0x91b6c91f, 0xfb37ad48, 0xf85f803f, 0x39fe59db, 0xc636c738, 0xcf20fbfa, + 0x6cefe2a7, 0x5be6807a, 0x0f28b654, 0x71ac9ddf, 0xd2753fb1, 0x1dfecb9e, + 0x129ac2e4, 0xc937cf91, 0xfd91e63e, 0x13f6453a, 0x9fb269e5, 0xdec76479, + 0xf809fb20, 0x02ad82b6, 0x29762ddf, 0xb7dba2c2, 0xceedfdf6, 0x6d32c245, + 0x7b74fb6a, 0xfa67f7f1, 0x4adf7f89, 0x1223539e, 0x60d65651, 0xa7256fbf, + 0x6319649b, 0xd5e8b2e3, 0x4ffcc9bc, 0xf322ff8d, 0xa6f9e62d, 0xd786b3c2, + 0x786a7c68, 0x7d7812fe, 0x3ebc3269, 0xced82253, 0x595fda8f, 0x5755b88f, + 0xde6fd4bc, 0x06441357, 0xa3c6eff1, 0x1bfd1cf2, 0xe313312c, 0xf7b53c4b, + 0xe42c28dc, 0x2bdc7f4a, 0xaaf3c002, 0x8fae6a9e, 0xf7898f8e, 0x6bf8616e, + 0xd9572f2a, 0xdde821fd, 0x6ba1a5cb, 0x1f12c3c8, 0xbc4bebef, 0xedf9e681, + 0xce0f664b, 0xd7669d27, 0xace20f6e, 0x2f3d996f, 0x9d3ffbe0, 0x724a5eca, + 0x369f9e25, 0xd3ac39e9, 0x9da8f12e, 0xe39dbec3, 0xce14b963, 0x23c80cb2, + 0x5f9829fd, 0x92665ff3, 0xfe27692f, 0xe59367dd, 0x454cfe54, 0x529fe91c, + 0x50facfee, 0xc77d1fa3, 0x538d1670, 0xeb26fa41, 0xaf3e38d1, 0xf7de9d78, + 0x08d50ed8, 0xc5afbf83, 0x25534623, 0x6b88171e, 0xb03c449e, 0x04558ce6, + 0x82147da9, 0x250cf68f, 0x7a35bd08, 0xfa19aae6, 0x114136b6, 0x542f60d3, + 0x6193127d, 0x3e9d2e12, 0x09c57588, 0xe38f8e97, 0x700c520b, 0xa1866782, + 0x8e55527f, 0x3bd93da1, 0xad3ed0d7, 0x4f00d4ae, 0xe860ddf7, 0xd0b0de9f, + 0x6ffa6700, 0xeacff433, 0x35806a58, 0xab25957d, 0x15eeacc4, 0xf767ef86, + 0x77f434ac, 0xda1ad607, 0xfb8971cd, 0xbc068f59, 0x4e3405c3, 0xee4e3a9d, + 0x7e868dce, 0xaa6dd082, 0xbfc89c80, 0xceeb1267, 0x3acf4428, 0xc87aaac7, + 0xd7ff7e69, 0xd734eb8d, 0xbca9925b, 0x7fd465d5, 0x784619b5, 0x4284e391, + 0x4e458b43, 0xeace1ea3, 0x8ce018b6, 0xd79bd232, 0x51628fd1, 0x2f82f1cc, + 0xae7fbfa2, 0x78d1fe81, 0x84f07e22, 0x69ec9fd0, 0xb37aeb00, 0x8f7b02d5, + 0x1f7e82fc, 0xf1e82fc8, 0x1e82fc80, 0xdf417e46, 0x7d05f91f, 0xfa0bf23b, + 0x4633b2f6, 0x1b0f97fa, 0x9ef95fe9, 0x5f1afe91, 0xeaa7454e, 0x843f91b0, + 0x7f2bf15f, 0x5e374e85, 0x344ff232, 0x37266e7d, 0xf4153927, 0xd7213c50, + 0x9dd7a797, 0xfa22f451, 0xf7c04c04, 0x9f4904cc, 0xa04975d0, 0xb319ed57, + 0x8ffc1208, 0xc77cfb51, 0x23286fe2, 0xab86f03d, 0xebfa0334, 0x147ae166, + 0x9dc5db71, 0x86884f26, 0x7e35115d, 0x7dff0cf5, 0x1a17a465, 0xb6cd5da6, + 0xfc463f81, 0xdc9e7073, 0xd9ddeaa5, 0xc0fc7271, 0x127cc142, 0xd839baf8, + 0x339ee347, 0xcfd02bf5, 0xb7f44fdf, 0x0bfbfbe3, 0xd47f79bb, 0xcdf7c143, + 0x0d931aff, 0xe0b679b8, 0x0c28b073, 0x88492f97, 0x2ce6c5e8, 0xd43b27aa, + 0xe39ea655, 0xdf4ed43c, 0xb8c99775, 0x69c7824e, 0xa15178e3, 0x444e22f0, + 0xe6ecafc7, 0x6ce3e022, 0x63e01cec, 0xde41e4c0, 0x25756c20, 0xde051f41, + 0xbde40b34, 0x9fc217e0, 0x57faa59b, 0x29e46259, 0x5ece73ac, 0xd7abb061, + 0x62c2ed06, 0x0d397fc8, 0x8650d170, 0xc7f5ffa1, 0x92f6865c, 0xbda18150, + 0x00c78cec, 0x19570f97, 0xe7be57fa, 0xe1d5c035, 0x1bff433a, 0xf00cf92f, + 0xef9e456c, 0x239653bf, 0x992e21f3, 0x387e6bdf, 0x6bfa5079, 0xf9afdcf2, + 0x49ffa2d5, 0x38711daf, 0xbf357f95, 0x6da3f35c, 0xcfd04084, 0xf6c2d3b6, + 0xfa5da660, 0xf62dfec9, 0x6827c8f3, 0x57e6bafe, 0x08a9fe6b, 0x76f57ad4, + 0xf693be87, 0x35ebf545, 0x8bf359ff, 0x4c5d8b13, 0xb236eb3f, 0x4b07e0ab, + 0xae761338, 0x1a4c4639, 0x4cb9790f, 0xd7a25b9e, 0x7a2badaf, 0xa762c4fe, + 0xdc7517e4, 0x7ee2ec17, 0xccfe24df, 0xf57caabf, 0x63beb99f, 0xad67cfe0, + 0xbb56f79e, 0xf4f3ebff, 0x1321fc25, 0xf5f352fe, 0x264dfd72, 0xc767c713, + 0xd72e5fd7, 0x0bf595af, 0xd921dfc9, 0x37e2f359, 0x1fc83af7, 0xc2c7b678, + 0xaf339671, 0xe40c6c5c, 0x5e121fc1, 0xfc9b338c, 0x3e07d07c, 0x0b07ce05, + 0xdf3ccdcb, 0x772932a5, 0xcf2cbd11, 0xd242a365, 0xc6c7b47f, 0xe849d479, + 0xeda07ccd, 0x8b43f107, 0x510dc655, 0xc9686e22, 0xc0437197, 0x44a21b88, + 0x2ff510dc, 0x3e187af7, 0xf0c55bd2, 0x0cbd7af7, 0xe3adeb1f, 0x3ebd07f2, + 0x26f8d7ae, 0x79da5f1a, 0xc43fa34b, 0x2f237610, 0x1feb1f8a, 0x6d72f492, + 0xd3f6fab0, 0xa24deb16, 0xe08d294e, 0x8f151ef3, 0x3c49e633, 0x7fe41fa0, + 0xe6b57eaa, 0x9bc424c2, 0xc92b8547, 0xaae257f9, 0x687c2f7f, 0x973f1f78, + 0x949bcb8e, 0x52e4a987, 0xceeb3f3b, 0xd1772cab, 0xb72d18f2, 0x3fe778d1, + 0xfc7bb9dd, 0x53c5ab5c, 0xe8d53954, 0x55b5c9a2, 0x5fa11b84, 0xce267982, + 0x609c3f53, 0xf3c5a394, 0x077f7e24, 0xbcf2a239, 0x326699cb, 0xfdb2f847, + 0x1017f271, 0x4869ef1f, 0x8059e0e4, 0x7dba8fce, 0xd2faf02e, 0x2b7ea06e, + 0xd062ac07, 0xb0757d85, 0x44096d1d, 0xd8471b9f, 0xaddb6c9f, 0x3e469f38, + 0xe7e4e77f, 0xd13fce4a, 0x6fc26d38, 0xfbdbbac3, 0xab56fd8d, 0xfce8cae7, + 0xd53cd54a, 0x878479de, 0x7f351ffd, 0x19f6a1de, 0x6e609fe7, 0x60df1a92, + 0x1432a479, 0xb9bf3ba3, 0x8b28ef90, 0xb8b784c0, 0x6dc3d802, 0x6bbe4f16, + 0x7869bf22, 0x97e7989b, 0xf7c41bf7, 0xa0fcf962, 0x232ff9e5, 0x6afa0fcf, + 0xffb514f9, 0x985980e5, 0x48e0df71, 0x7fa7e70c, 0x4f7b3a6b, 0x7f974b8e, + 0x11b79099, 0x309fb889, 0x27ba687a, 0xb4bac930, 0x1b361fd2, 0x684c91ee, + 0x11347adf, 0x17cec9e7, 0xf3a69e65, 0x796953c5, 0x3cd7bd3a, 0x1bfbc2cf, + 0xe7dbf932, 0x9bdc8f4d, 0x60c7fb58, 0x357aca31, 0x9fbd127e, 0x5f36bd71, + 0xa519fe61, 0xab5eb1fd, 0xa47f7853, 0x49e40517, 0x112fd7cb, 0x5a9454a1, + 0xb3bfc43e, 0xe5a0e99a, 0xd5425a43, 0xfbbb8fbc, 0xa8e35b56, 0x2da9f84b, + 0x48ae71b5, 0x4b3c249e, 0x2a99bfde, 0xac6cb25f, 0x3e5bc784, 0xb38f2376, + 0xe65b9e6d, 0xd9edb64f, 0xee6fff00, 0x1e056141, 0x4e3956c2, 0x553e9e34, + 0xdcb924e5, 0x6e37b7a8, 0x6f6f5855, 0xf796ad84, 0x6b6f587c, 0x157ed5f0, + 0xa6f095ae, 0x5b0e12ed, 0x24953b1d, 0x05c45fb9, 0xd8944fb0, 0x87b1ce0f, + 0xf60238d4, 0x40fb1281, 0x6015f43d, 0xd0c02be8, 0xafa18057, 0xa15f4250, + 0x65f0a57e, 0xbc888e23, 0x4e4e8d4e, 0xd1a9d790, 0xebc81ff9, 0x75e461e8, + 0xd791fdf4, 0xaf23b7d1, 0x5e476fa3, 0xaf230f47, 0xbc8fefa3, 0x5e461e8e, + 0x791fdf47, 0xbc8c3d1d, 0xf23fbe8e, 0xe476fa3a, 0xc8edf475, 0xe461e8eb, + 0x91fdf475, 0xdfb7d1d7, 0xf218a3df, 0x9a93f73e, 0xeeb5df06, 0x71fcc69d, + 0x313bedda, 0x41fbe88f, 0x66bf9ffc, 0x8f9d01cd, 0x6edf01af, 0x48f38aec, + 0x49d7f73a, 0xa4849bba, 0xd32348f3, 0xc24d8b79, 0xe7749eb5, 0xf20ffe24, + 0x99563529, 0x7c89414f, 0x53e44a0a, 0x529f2250, 0x29f32f93, 0x414f9128, + 0x2829f23d, 0x89414f91, 0xe44a0a7c, 0x9f225053, 0x14f91282, 0x0a7c877c, + 0x5053e44a, 0x4a0a7c8f, 0x7f5053e4, 0xbc81d68e, 0xf82eb68a, 0xf38679cb, + 0xe1a1f11c, 0xc034e73c, 0xfdf597f0, 0xdbeb2fe1, 0xdbeb2fe1, 0x61eb2fe1, + 0xfefacbf8, 0xb0f597f0, 0xe58b9e69, 0xfeb37e0c, 0x7acdf83b, 0x703fa8b8, + 0x3ba0b11a, 0x35eefdf6, 0xe504e194, 0xdf49c559, 0x15b7ff97, 0x638583c8, + 0x0f64ec95, 0x0fadbfd9, 0xd821a8ad, 0x2ba7deaf, 0xd0262316, 0x44d8f39b, + 0x04487f37, 0xe8a08f71, 0xd76e4cf3, 0x47fcaaf2, 0x22392f74, 0x535f0fd8, + 0x7da5d724, 0x334e11ef, 0x047fad4a, 0xf45fbc9e, 0xd63f5afc, 0x9075ba97, + 0xfdc12c9d, 0x8e2d9286, 0x4fc45dd2, 0xfb0a4c07, 0x9fc807a1, 0x5e893a5a, + 0xa3fd50aa, 0x27c3a603, 0xa22f70e3, 0xa7ecf145, 0x88b1afa1, 0xe052d633, + 0xfe14bba9, 0xb2797642, 0xdf75afea, 0xda3f7b80, 0x1db8b5ba, 0xf22f09e9, + 0x8447f3ef, 0xb9e68dad, 0x6b6153e9, 0x9366df87, 0xc3be02fe, 0x80baedb9, + 0xe3afdde2, 0x697282ef, 0x0d81fcff, 0xfd51b437, 0x6fba8775, 0x171f8768, + 0xcefbbf27, 0xc78c8973, 0xfb29b73b, 0xf99fb4cd, 0x90778487, 0xcb9495fa, + 0x8775dff3, 0x9e36b69c, 0xd76b69d7, 0x97d843df, 0x5ce1736d, 0x8835c228, + 0x8a7989ff, 0xf0444178, 0x0d7bfb46, 0x4486bbfb, 0x75d7f105, 0x3ffb6307, + 0xd751f1d2, 0x7e01b250, 0xff6658e0, 0x59fe3a47, 0x72441f87, 0xec206e41, + 0xf24aa756, 0xc3bd6af5, 0x79c51be4, 0x623ecba2, 0x9a6efe03, 0x7b8b5c97, + 0xf0b8e26c, 0xe6ef83e4, 0x4e9f6cb5, 0xbd07f2eb, 0xba03dc1e, 0xd3eed3e9, + 0x63ef3f0c, 0x82a7d998, 0x70f6c7d7, 0xc509404e, 0x0cee2a13, 0x09529a0c, + 0xd5b023be, 0x87fe869a, 0x00ee0784, 0xa0b12899, 0x42afb234, 0x558a6c31, + 0xd4e22fc0, 0x91ff1d34, 0x7e0e58e6, 0x0558f129, 0xc58963f8, 0x89be8569, + 0xefa237f6, 0x71ff907f, 0x6867bcaf, 0x6b1ec0b5, 0x538b51fe, 0x36eaf5ae, + 0x2d1ffb2b, 0xd0ffc947, 0xfcd52bdd, 0x085eed0d, 0x109e1df9, 0xdb91f8ec, + 0xb9d42e39, 0x7fbe1de1, 0x783b89f1, 0xfaf89920, 0xf7c39c93, 0xb7e1b954, + 0xc94fac28, 0x272ce86f, 0x3f6cb63c, 0x55f3889d, 0xfb0af038, 0x3db7571b, + 0x08e3289e, 0xa6d11f32, 0xcf8b49e2, 0x68f4abb4, 0x7d01ef53, 0x3bcb7a48, + 0x086eed87, 0xbd6836f7, 0xfb4457ec, 0xb91f9a87, 0x384f1b4e, 0xa45c45df, + 0x8bb7f683, 0x5bbbd5a0, 0x89886476, 0xd53ae3fe, 0xcdb35caf, 0x3a7ef7ca, + 0xc2ed9044, 0x3f54609a, 0xbacfbef5, 0x9dfac683, 0xa7fe51e5, 0xeed22e7a, + 0x7dbcb6e5, 0x7ff66eea, 0x6f9cadba, 0xfd2ada6b, 0x04587121, 0x8bc015f3, + 0x3704b14c, 0x947af51d, 0x27e7f849, 0x1f545faa, 0x2ebc658e, 0x7d678b19, + 0x8b2c74b2, 0x32c67be1, 0x4c77bcb9, 0x8a5c8bde, 0x3bd10c58, 0x9104ab5c, + 0xea99fb4f, 0x7b8ddd0f, 0x2063a092, 0x9479f99d, 0x145319f8, 0xae6a7aab, + 0x77053957, 0xdfeadeb3, 0xf5987b8e, 0xcbfd8283, 0xd137e03b, 0xa3f00df8, + 0xdc1e41a6, 0xb73f7cb5, 0x6ef9114e, 0x9506c3c8, 0x041e49ff, 0xeb2f0feb, + 0x41259ab5, 0xf069afdc, 0xee81361f, 0x03f81c9a, 0xef802de7, 0x57362808, + 0xf8279f21, 0x79f1acbc, 0xc7343cb4, 0x8725f1ab, 0xfb8d1f8c, 0x9d2c58a7, + 0xd7e045bb, 0xded4bc2b, 0x0ce0188c, 0xf7081195, 0xfdb28509, 0xaf5fd1e4, + 0xd3c386d8, 0x343f8c97, 0xaf4c4c99, 0xf6f7f211, 0x70c56043, 0x65e43a6d, + 0xcbba52b7, 0x53cf5915, 0x572f0b95, 0x2bc5cee8, 0xf922f955, 0x63f9c74b, + 0xe9f923e3, 0x40ff1262, 0xcf095b2b, 0xa4e6b390, 0xa214d7f0, 0xc2e527cc, + 0xdb0c435b, 0xe27dd428, 0x73ad0422, 0x7c670a85, 0x9dfdee2f, 0x861f8c85, + 0x5e5f962f, 0xbffc2811, 0x8a4d87d0, 0xab57ef85, 0xfc9871f8, 0xefc3951f, + 0x831787b7, 0x2385f1ae, 0x1a2dd036, 0x1eedf73f, 0xf08733da, 0xe9215190, + 0xb7eb64d7, 0x045179f2, 0xb55f88ad, 0x22fb4a16, 0xafecae2c, 0xc5c43e72, + 0xdf6d3e71, 0x89f7aa1f, 0xace1f1a3, 0x7e027690, 0xf48e6bb2, 0x4fc25193, + 0xf81c7dc6, 0x27e180c9, 0x8c9f84a3, 0x80c9f87a, 0x860327e1, 0x7e180c9f, + 0xc9f84a32, 0xe4c27fa8, 0xd130ff3d, 0xf05369f3, 0xa7c4abf0, 0x4dfaa59f, + 0xa7feb415, 0xd79b8f71, 0x11fde7ef, 0x195eb0df, 0x5fc453d7, 0x1f088af6, + 0x70b9ecad, 0xe11394d4, 0xbf9db6a7, 0xe205ea7f, 0x17e4958f, 0x3bfd9e42, + 0xf14c5095, 0xdcf67cd4, 0x979638da, 0x636ebee7, 0x1b64dbfd, 0x47776d3e, + 0xcf7ef9f0, 0x7d4ab4ff, 0xd177ca19, 0x63ba2bb8, 0x4fffd03d, 0xb1d2fa55, + 0x0f42f8de, 0xad32e5d3, 0x251def89, 0xbf50b3fa, 0x9ebf0c52, 0xbf9afd41, + 0xda3676f1, 0xb6ee381f, 0x1cb70f41, 0xe191d92b, 0x177ef7c2, 0xe1c5b5f8, + 0x58cfc1b4, 0xed992dbf, 0x8cba736e, 0x73c712db, 0x47a34bde, 0xb78c8555, + 0xb829527d, 0x979ea2bc, 0x25d64108, 0x6e927e86, 0xc5a6f2d1, 0x58e3a311, + 0xf3ca7891, 0x0710733b, 0x3e9e1549, 0x217c44d7, 0x8d2b61ce, 0xe3a251c4, + 0x6af2e31d, 0x9df88613, 0x50a9ae56, 0xdbcef70c, 0x85abcfc7, 0xd7e1d38b, + 0x1138a63f, 0xb8736e6f, 0xb826adee, 0x37158ced, 0x8a7d4532, 0xf04996cb, + 0x738a23c8, 0xb9bde83f, 0x1356f584, 0xf78a5268, 0xb72cd50b, 0xcb2a416d, + 0xafef96a6, 0xd66a763e, 0x90afb1f7, 0xb67586d7, 0x14b6bd39, 0xdad3df9d, + 0xf7f578af, 0xb1b83520, 0x9b0dc642, 0xfc0118e8, 0x6dd9b7dd, 0x2538895b, + 0xffb83fb9, 0x13e546b7, 0xc7ea3bed, 0x73ea1ff7, 0xabe0ebc4, 0xf417da11, + 0xd52be616, 0xe312bf8d, 0xfea7e6eb, 0x56b5b7ec, 0x2d78f024, 0x1bb7da4e, + 0x49d793a5, 0x8d3c6078, 0x5cf1a1ec, 0xbde30f3c, 0x7ab41435, 0xbbdc1eb0, + 0x33857820, 0x2b3cc568, 0x7c7095b7, 0xce5bbfdf, 0x6c99dfe3, 0x675f822b, + 0xe966da71, 0x3be23dfd, 0x0e1365f0, 0x5ebca9f7, 0x08db87f6, 0x43f0294f, + 0x75ffc853, 0x8b57c44c, 0xfeb6feba, 0xd8ffa364, 0xf41598ff, 0x4aed5469, + 0x549e1d34, 0xb6e578f9, 0xd7786c5b, 0xf2f166d0, 0x8abf07bb, 0x10df7fef, + 0x90f90bbb, 0xad2781c6, 0xae1f826e, 0x93f67e90, 0xeadf9215, 0xb8f94273, + 0x21b231e7, 0x3721ef96, 0xbf79fb3a, 0x9c7ef8e3, 0xc4ff03f0, 0x137c63e9, + 0x9f70049f, 0x48c06daf, 0x127ac8df, 0x81b6dc78, 0x55bf9616, 0xa9cdbf16, + 0x13dec75f, 0xa5e10af9, 0x815ee491, 0xb3fa71fd, 0x1f173fc1, 0xf79b37bf, + 0x7be4eb49, 0xe2d71e54, 0x37cc798c, 0xff1ad7cc, 0x79499734, 0xa97be6d6, + 0xbdf3c2c2, 0xb4e525f4, 0xdf0b776d, 0x10cd6983, 0x62f9451e, 0x53e4d539, + 0x3546d793, 0x7bbad92e, 0xf4ebf089, 0xeeefd90d, 0xcfc12797, 0x2b9d7565, + 0x3e127a54, 0xb8ba135f, 0x3d2abbdd, 0x728c729b, 0xee30f18f, 0x9bee5529, + 0x37f28616, 0x6bfa4614, 0xc8a536f3, 0xe0ffc0ef, 0xbd2a53b3, 0xf7237fd1, + 0xeaa4f157, 0xbd71d68d, 0x1a7b6871, 0x8561c6f4, 0xf71b54f3, 0xe36ebf48, + 0xe71c098b, 0xaf8d8ffa, 0xea1ef8fe, 0x8313c9f7, 0x13f7facd, 0x27a9216d, + 0x829fc9da, 0xdaa558de, 0xff6286fd, 0x72742b4f, 0x17adf6dc, 0xac5c81af, + 0xf8b92a18, 0x0efbc14b, 0xeafcdf41, 0x73be1fc5, 0x5f622b83, 0xdcac7db5, + 0x16d66ff9, 0x726f1e87, 0x560abb9f, 0x493cef0a, 0x5ac39c2f, 0x1df229b7, + 0xfd8d8f59, 0xd1de8d4f, 0xf242d07c, 0xf088eadb, 0xa9ff4681, 0x78db26fc, + 0x5fd24e3e, 0x07c6b7a3, 0x3a35bd1a, 0x9d297bf1, 0xfbadafff, 0x2b5e9533, + 0x531dfe54, 0x87456ee5, 0xe58ab6db, 0x056b6ddd, 0xb1fa6bdf, 0x4e3f58cd, + 0x7eb8e727, 0xc0b901df, 0x69d022bb, 0xc655b774, 0xa04d0f23, 0xbeec3653, + 0x6ad58eb6, 0x8d5db1dc, 0xfcd2ae1f, 0x4c7f62e0, 0xab4e8ea5, 0x6a74939f, + 0x5fede97d, 0xfbc5c0ff, 0x4f6c7a93, 0x2b8bfb0c, 0xbd330e87, 0x663e771a, + 0xf4bf5375, 0x5f41b74a, 0x389776b7, 0xb15f3711, 0xf90ad073, 0x4d74af4f, + 0xea4defca, 0xaf0d60bd, 0xce8a3fb0, 0xa1fd69ee, 0x3cd30ef7, 0x26c4379b, + 0x368d1ee2, 0xf252b78f, 0x72776b75, 0xed6be60a, 0x381ff96e, 0x3f7a68cf, + 0xc42eee5a, 0x4958794a, 0x2f2e429f, 0xdec9e2dc, 0x3f313858, 0x959595a6, + 0x10cf6e92, 0x256f717a, 0xbbe87e2b, 0x03d643c0, 0x93e41e71, 0x41c2f2f3, + 0xc63e0bcc, 0x17a46dba, 0xaf25ff71, 0xac7bfc33, 0xbe745c83, 0x213282ef, + 0xd23be645, 0x926fde08, 0xcc72b3ef, 0x52afbcb2, 0x0f6a3bda, 0x86a45da1, + 0x68ffb1cb, 0x5f9535bd, 0x36a7f1a1, 0x9a9eb44e, 0x57777f6a, 0xa2fa794a, + 0xab705dfd, 0x4f029371, 0x6de69db6, 0x078e747e, 0xda2fa471, 0xe64e2da7, + 0x4bf7c697, 0x32955acc, 0xe4f37ec9, 0xfdea6839, 0x4da6d40e, 0x7909dfb2, + 0xb44e555f, 0x79e3efbb, 0x27997e92, 0xdd90a0b9, 0x6c2eefa2, 0x65fbe588, + 0x38b4beda, 0x5efadffd, 0x14cac1e1, 0x4e14fe35, 0x14d93f80, 0x487fcaa7, + 0xa25fa8c2, 0xfdecd7ab, 0x21386739, 0x3f9fa745, 0xa1ed56ea, 0x3c81ef08, + 0x815c9e8b, 0xfeb9c778, 0x42a6090b, 0x9f5ca7f0, 0xab66ddf6, 0xf40f5ce7, + 0xbe18f6dc, 0xd37e4eef, 0xda93c40e, 0xa71cc903, 0xeca7afb9, 0xe71a5ee2, + 0xfc596dbe, 0xf3f350de, 0x2ffaa957, 0x8ecb737e, 0xebdff44a, 0x6f8fc276, + 0x886cf877, 0x2c0fc5c3, 0xdfb0e5b1, 0x5a01cf2b, 0x22b36ade, 0x0c9efc7c, + 0x657211fa, 0x7b07913a, 0xf4af7ab3, 0x624debff, 0xb39bf227, 0x338b7cfb, + 0x529e1fa1, 0xc527f03c, 0xdaa3d23e, 0xc7748c79, 0x6fbec587, 0xef68bf41, + 0xc6c2e6ef, 0x219fb19a, 0x829dce2f, 0x07ec0bfc, 0xa65e01eb, 0x6e71fca9, + 0xab827ce0, 0x2fcf8230, 0xe3481efb, 0xd67f2d0b, 0x194ff88e, 0x0d29a3f8, + 0xe6a6d1fc, 0x2c0c76c9, 0x707db862, 0xe9fbbf19, 0x473a6743, 0xfb563db6, + 0xef08a044, 0xda3e2578, 0x09dd16ba, 0x7f63a8bf, 0x35ce324c, 0xb640d6d9, + 0x1b6d0fde, 0x01df987c, 0xe58c1a5d, 0xce354077, 0x67b83525, 0x7c9f6ab3, + 0x3bf5a767, 0xb597eaa1, 0xef0c8b5d, 0x4c69da79, 0xd9ff8d27, 0x5fdf3c50, + 0x04e9ded3, 0x95e3feec, 0x4ebdf2e5, 0xd3be4bb5, 0xaefee4c9, 0x5af4e349, + 0xbe57b179, 0x3bbdd0fb, 0xbe91b3ba, 0x257aecef, 0x7bace311, 0x4e1567fc, + 0xceb7c713, 0x77f1fc60, 0xbbe57b47, 0x27c7f6a3, 0xbe03ff7f, 0x1c767f06, + 0xc6790c53, 0xec4982fb, 0xc243fa87, 0xdfb6fc86, 0xbdcfd829, 0xb03d1664, + 0xa25f9aeb, 0xc552ffd5, 0xfea4a5c3, 0xcd7fd06c, 0x61b32781, 0x20937e37, + 0xf703a6e1, 0xc87a08fe, 0xf48c7cff, 0xfd822dbf, 0xf480d6db, 0x64f7b597, + 0x38ec7842, 0x19547f87, 0x46b9f2cf, 0xada4977d, 0xae0bfc8b, 0xd4458dff, + 0x6f781d61, 0xdf7e7e04, 0x3d076a12, 0x147f27df, 0x2a138f79, 0x6fdfbdff, + 0x87f7cc5e, 0x57e01048, 0x4affdfbc, 0x9a89f202, 0xfe6b561f, 0xb4ef1795, + 0xef951e37, 0x870be381, 0xd4231cf9, 0xa77ac978, 0xdf8db7e4, 0x4ace2eb7, + 0x6b8abf65, 0xdb212d3a, 0xab5af464, 0xf0e34dfa, 0x2e7cc391, 0xfd243ceb, + 0xf3a1ce82, 0x7e6817ec, 0x70bef686, 0xecf3a1dd, 0xaddf6827, 0xd2f1223f, + 0xb7d64475, 0x78b49814, 0xc3c9578b, 0x38615979, 0xb4d2c2bf, 0x9b9b00d5, + 0x3a505ab6, 0x08c878d5, 0x0abbe5fb, 0x99e7ca7e, 0xb8ea6dae, 0xf3755b04, + 0x974d56c5, 0x3ea8daef, 0xa5ef81d7, 0xbbdad73d, 0x50f3c88e, 0x276e2ba8, + 0xef5d83df, 0xebeca0b0, 0xdf3db072, 0xc02a6dd7, 0x12af757d, 0x71dcfec7, + 0xf4d6fef5, 0x22c6ef75, 0x4629904e, 0x7cdc994e, 0x15666b6f, 0x022e9b8d, + 0x7b4b8f7c, 0x9fe5744f, 0xf8c32e3f, 0xafc2620b, 0x5b980220, 0x7909a335, + 0xe1490593, 0xf73c6032, 0xd384ba58, 0x0e20afc3, 0x37240ce5, 0xa5f28f21, + 0x8af54ae3, 0x30eece21, 0x0a07aff9, 0xdb2ec6ba, 0xc4635c64, 0x5799b906, + 0xfa68f925, 0xe2473a49, 0x83b9f51c, 0xd3e981cf, 0x9b9df9ba, 0xa1970c28, + 0x837c71df, 0x8c7f60fb, 0x420eff93, 0xf6f5979e, 0x027558c6, 0x3de99797, + 0xa425aeaa, 0x9f0363e6, 0xf7f8829b, 0xa12b8e04, 0xbcfdeb6f, 0x4f292aee, + 0x979918be, 0xceb14bbd, 0xe4fa27fa, 0x835fdb90, 0xcc72fa75, 0xb8b92545, + 0x7def2b17, 0xb7f3515f, 0x50bcbf9a, 0x7a96769d, 0xc8cdb3ce, 0xb4fe4070, + 0xd78a89fb, 0x1f52efcb, 0x8ad93c2a, 0xc4737f75, 0x1620efce, 0x73c9c48e, + 0xb63a8cd5, 0xd9b17daf, 0x2e283fec, 0xfea2688b, 0x214d0b27, 0xa6ffdfdc, + 0x599e73b0, 0x6dfca3d8, 0xc3df2c53, 0xf1bf8e56, 0x964dec39, 0x92a7f7f9, + 0xff599f68, 0x8ba078a0, 0xfe2f479b, 0x6ca84fe3, 0x187fdb1a, 0xfe4911fb, + 0xb9c3f066, 0x7ef3bad1, 0x9d37f542, 0xb48f7643, 0x8fbf4263, 0x9e7e0fe3, + 0xac8a6298, 0xc5c8caef, 0x879d5f17, 0xe9f1ced2, 0x32cdc785, 0x9eb5159e, + 0xbe2e192b, 0x98fd4e0f, 0xa61c573e, 0x0b87ce20, 0x0f7a9f8f, 0x7b885beb, + 0xd83738ce, 0xf6f597ad, 0x2566b84e, 0x150e7e23, 0x88ac97fa, 0xb540783e, + 0xae7d694b, 0x7b08dc9f, 0x2059a6f9, 0x651440ee, 0x07d6883e, 0x425f833f, + 0xaa37c6fe, 0x07ed79e4, 0x546fbe39, 0x67065cb1, 0x9be72e41, 0xb69fbf27, + 0xe3514aaf, 0xd1ae9259, 0x8ba68b74, 0xe7716f86, 0x8524e9f0, 0xa8f45cf1, + 0xc62eefc4, 0xb767e7ef, 0x198a9893, 0xc636fbff, 0xf86ffff3, 0xca7de2fd, + 0xfbe373f7, 0xd3ed3afc, 0x77e7d86d, 0x93ed1ffe, 0xbcdfc0f5, 0x3ee361cf, + 0xb142fad3, 0x8f37c073, 0x8acfd89b, 0x0a2a37be, 0x66d1eb04, 0x53c71c73, + 0xddf271fd, 0xd3cfe901, 0xde9a9fd0, 0x2e175d9c, 0x4e71bf82, 0xaeb16788, + 0xeb8869b0, 0x30e5562f, 0xc314ccdf, 0xc27efc99, 0x3f872e12, 0x35bfb66b, + 0x4bb223f7, 0x0f048f03, 0xf4e34abf, 0x56a7c129, 0xeddd5f41, 0x95dcfce0, + 0xa56029a0, 0x45920679, 0x7f9a31f1, 0xce5ccd60, 0xaa115cb3, 0xb1b06a9e, + 0xecf6a29e, 0xca37b41e, 0xf9fdeff6, 0xa3f81ec2, 0xf782f923, 0xae225033, + 0xc0f04bd9, 0xff6e0292, 0xf6e7a6a1, 0x97efc824, 0x8193e608, 0xef7c2935, + 0x83a7e9e4, 0x0e8ec2d7, 0x11337a0c, 0xf44cab57, 0x19c74187, 0x079f6966, + 0xe54f54dc, 0xb1af8a13, 0xc914e31d, 0xe31b86f5, 0x43403a5e, 0x2a91e6c5, + 0x3d73faa5, 0xd5cf9c09, 0x638b47e4, 0x7f9c0ecf, 0xded2780a, 0xf2a07f23, + 0xc5778699, 0xa667df2b, 0xe8d678aa, 0x6a5bf1a0, 0xa6cf7c9c, 0x377c916c, + 0xbd791f7e, 0x33c8fbe0, 0x27782969, 0x71e31cd7, 0x4adfdf01, 0xfd618ff2, + 0x3e881b7d, 0xd243ec66, 0x5bde1ce1, 0x997fe24e, 0x7e5a4dab, 0x3463df9f, + 0x9a5fa90b, 0x3d17f7b5, 0x2217f7c6, 0xef19333c, 0xe89f9891, 0x3edd67fb, + 0x5fbe355b, 0xd2fb65ee, 0xd9def2ac, 0x7a4f34ff, 0x5aa9286f, 0x623b95da, + 0x9dfc89fd, 0xf3450efa, 0x7c96cfc3, 0xe4f60b3c, 0xcc6f83dc, 0xa2577944, + 0xf69ab92f, 0x1fe344f3, 0x7dc4c316, 0xf7e61990, 0xfe341f34, 0xe5c71671, + 0xfcc1bcb7, 0x57aeb7ff, 0x01ffc75b, 0x0934e170, 0x000048d0 }; #endif /*__BNX2X_INIT_VALUES_H__*/ diff --git a/drivers/net/bnx2x_link.c b/drivers/net/bnx2x_link.c new file mode 100644 index 000000000000..ff2743db10d9 --- /dev/null +++ b/drivers/net/bnx2x_link.c @@ -0,0 +1,4527 @@ +/* Copyright 2008 Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2, available + * at http://www.gnu.org/licenses/old-licenses/gpl-2.0.html (the "GPL"). + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a + * license other than the GPL, without Broadcom's express prior written + * consent. + * + * Written by Yaniv Rosner + * + */ + +#include <linux/kernel.h> +#include <linux/errno.h> +#include <linux/pci.h> +#include <linux/netdevice.h> +#include <linux/delay.h> +#include <linux/ethtool.h> +#include <linux/mutex.h> +#include <linux/version.h> + +#include "bnx2x_reg.h" +#include "bnx2x_fw_defs.h" +#include "bnx2x_hsi.h" +#include "bnx2x_link.h" +#include "bnx2x.h" + +/********************************************************/ +#define SUPPORT_CL73 0 /* Currently no */ +#define ETH_HLEN 14 +#define ETH_OVREHEAD (ETH_HLEN + 8)/* 8 for CRC + VLAN*/ +#define ETH_MIN_PACKET_SIZE 60 +#define ETH_MAX_PACKET_SIZE 1500 +#define ETH_MAX_JUMBO_PACKET_SIZE 9600 +#define MDIO_ACCESS_TIMEOUT 1000 +#define BMAC_CONTROL_RX_ENABLE 2 +#define MAX_MTU_SIZE 5000 + +/***********************************************************/ +/* Shortcut definitions */ +/***********************************************************/ + +#define NIG_STATUS_XGXS0_LINK10G \ + NIG_STATUS_INTERRUPT_PORT0_REG_STATUS_XGXS0_LINK10G +#define NIG_STATUS_XGXS0_LINK_STATUS \ + NIG_STATUS_INTERRUPT_PORT0_REG_STATUS_XGXS0_LINK_STATUS +#define NIG_STATUS_XGXS0_LINK_STATUS_SIZE \ + NIG_STATUS_INTERRUPT_PORT0_REG_STATUS_XGXS0_LINK_STATUS_SIZE +#define NIG_STATUS_SERDES0_LINK_STATUS \ + NIG_STATUS_INTERRUPT_PORT0_REG_STATUS_SERDES0_LINK_STATUS +#define NIG_MASK_MI_INT \ + NIG_MASK_INTERRUPT_PORT0_REG_MASK_EMAC0_MISC_MI_INT +#define NIG_MASK_XGXS0_LINK10G \ + NIG_MASK_INTERRUPT_PORT0_REG_MASK_XGXS0_LINK10G +#define NIG_MASK_XGXS0_LINK_STATUS \ + NIG_MASK_INTERRUPT_PORT0_REG_MASK_XGXS0_LINK_STATUS +#define NIG_MASK_SERDES0_LINK_STATUS \ + NIG_MASK_INTERRUPT_PORT0_REG_MASK_SERDES0_LINK_STATUS + +#define MDIO_AN_CL73_OR_37_COMPLETE \ + (MDIO_GP_STATUS_TOP_AN_STATUS1_CL73_AUTONEG_COMPLETE | \ + MDIO_GP_STATUS_TOP_AN_STATUS1_CL37_AUTONEG_COMPLETE) + +#define XGXS_RESET_BITS \ + (MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_XGXS0_RSTB_HW | \ + MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_XGXS0_IDDQ | \ + MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_XGXS0_PWRDWN | \ + MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_XGXS0_PWRDWN_SD | \ + MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_XGXS0_TXD_FIFO_RSTB) + +#define SERDES_RESET_BITS \ + (MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_SERDES0_RSTB_HW | \ + MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_SERDES0_IDDQ | \ + MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_SERDES0_PWRDWN | \ + MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_SERDES0_PWRDWN_SD) + +#define AUTONEG_CL37 SHARED_HW_CFG_AN_ENABLE_CL37 +#define AUTONEG_CL73 SHARED_HW_CFG_AN_ENABLE_CL73 +#define AUTONEG_BAM SHARED_HW_CFG_AN_ENABLE_BAM +#define AUTONEG_PARALLEL \ + SHARED_HW_CFG_AN_ENABLE_PARALLEL_DETECTION +#define AUTONEG_SGMII_FIBER_AUTODET \ + SHARED_HW_CFG_AN_EN_SGMII_FIBER_AUTO_DETECT +#define AUTONEG_REMOTE_PHY SHARED_HW_CFG_AN_ENABLE_REMOTE_PHY + +#define GP_STATUS_PAUSE_RSOLUTION_TXSIDE \ + MDIO_GP_STATUS_TOP_AN_STATUS1_PAUSE_RSOLUTION_TXSIDE +#define GP_STATUS_PAUSE_RSOLUTION_RXSIDE \ + MDIO_GP_STATUS_TOP_AN_STATUS1_PAUSE_RSOLUTION_RXSIDE +#define GP_STATUS_SPEED_MASK \ + MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_MASK +#define GP_STATUS_10M MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_10M +#define GP_STATUS_100M MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_100M +#define GP_STATUS_1G MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_1G +#define GP_STATUS_2_5G MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_2_5G +#define GP_STATUS_5G MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_5G +#define GP_STATUS_6G MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_6G +#define GP_STATUS_10G_HIG \ + MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_10G_HIG +#define GP_STATUS_10G_CX4 \ + MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_10G_CX4 +#define GP_STATUS_12G_HIG \ + MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_12G_HIG +#define GP_STATUS_12_5G MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_12_5G +#define GP_STATUS_13G MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_13G +#define GP_STATUS_15G MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_15G +#define GP_STATUS_16G MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_16G +#define GP_STATUS_1G_KX MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_1G_KX +#define GP_STATUS_10G_KX4 \ + MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_10G_KX4 + +#define LINK_10THD LINK_STATUS_SPEED_AND_DUPLEX_10THD +#define LINK_10TFD LINK_STATUS_SPEED_AND_DUPLEX_10TFD +#define LINK_100TXHD LINK_STATUS_SPEED_AND_DUPLEX_100TXHD +#define LINK_100T4 LINK_STATUS_SPEED_AND_DUPLEX_100T4 +#define LINK_100TXFD LINK_STATUS_SPEED_AND_DUPLEX_100TXFD +#define LINK_1000THD LINK_STATUS_SPEED_AND_DUPLEX_1000THD +#define LINK_1000TFD LINK_STATUS_SPEED_AND_DUPLEX_1000TFD +#define LINK_1000XFD LINK_STATUS_SPEED_AND_DUPLEX_1000XFD +#define LINK_2500THD LINK_STATUS_SPEED_AND_DUPLEX_2500THD +#define LINK_2500TFD LINK_STATUS_SPEED_AND_DUPLEX_2500TFD +#define LINK_2500XFD LINK_STATUS_SPEED_AND_DUPLEX_2500XFD +#define LINK_10GTFD LINK_STATUS_SPEED_AND_DUPLEX_10GTFD +#define LINK_10GXFD LINK_STATUS_SPEED_AND_DUPLEX_10GXFD +#define LINK_12GTFD LINK_STATUS_SPEED_AND_DUPLEX_12GTFD +#define LINK_12GXFD LINK_STATUS_SPEED_AND_DUPLEX_12GXFD +#define LINK_12_5GTFD LINK_STATUS_SPEED_AND_DUPLEX_12_5GTFD +#define LINK_12_5GXFD LINK_STATUS_SPEED_AND_DUPLEX_12_5GXFD +#define LINK_13GTFD LINK_STATUS_SPEED_AND_DUPLEX_13GTFD +#define LINK_13GXFD LINK_STATUS_SPEED_AND_DUPLEX_13GXFD +#define LINK_15GTFD LINK_STATUS_SPEED_AND_DUPLEX_15GTFD +#define LINK_15GXFD LINK_STATUS_SPEED_AND_DUPLEX_15GXFD +#define LINK_16GTFD LINK_STATUS_SPEED_AND_DUPLEX_16GTFD +#define LINK_16GXFD LINK_STATUS_SPEED_AND_DUPLEX_16GXFD + +#define PHY_XGXS_FLAG 0x1 +#define PHY_SGMII_FLAG 0x2 +#define PHY_SERDES_FLAG 0x4 + +/**********************************************************/ +/* INTERFACE */ +/**********************************************************/ +#define CL45_WR_OVER_CL22(_bp, _port, _phy_addr, _bank, _addr, _val) \ + bnx2x_cl45_write(_bp, _port, 0, _phy_addr, \ + DEFAULT_PHY_DEV_ADDR, \ + (_bank + (_addr & 0xf)), \ + _val) + +#define CL45_RD_OVER_CL22(_bp, _port, _phy_addr, _bank, _addr, _val) \ + bnx2x_cl45_read(_bp, _port, 0, _phy_addr, \ + DEFAULT_PHY_DEV_ADDR, \ + (_bank + (_addr & 0xf)), \ + _val) + +static void bnx2x_set_phy_mdio(struct link_params *params) +{ + struct bnx2x *bp = params->bp; + REG_WR(bp, NIG_REG_XGXS0_CTRL_MD_ST + + params->port*0x18, 0); + REG_WR(bp, NIG_REG_XGXS0_CTRL_MD_DEVAD + params->port*0x18, + DEFAULT_PHY_DEV_ADDR); +} + +static u32 bnx2x_bits_en(struct bnx2x *bp, u32 reg, u32 bits) +{ + u32 val = REG_RD(bp, reg); + + val |= bits; + REG_WR(bp, reg, val); + return val; +} + +static u32 bnx2x_bits_dis(struct bnx2x *bp, u32 reg, u32 bits) +{ + u32 val = REG_RD(bp, reg); + + val &= ~bits; + REG_WR(bp, reg, val); + return val; +} + +static void bnx2x_emac_init(struct link_params *params, + struct link_vars *vars) +{ + /* reset and unreset the emac core */ + struct bnx2x *bp = params->bp; + u8 port = params->port; + u32 emac_base = port ? GRCBASE_EMAC1 : GRCBASE_EMAC0; + u32 val; + u16 timeout; + + REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_CLEAR, + (MISC_REGISTERS_RESET_REG_2_RST_EMAC0_HARD_CORE << port)); + udelay(5); + REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_SET, + (MISC_REGISTERS_RESET_REG_2_RST_EMAC0_HARD_CORE << port)); + + /* init emac - use read-modify-write */ + /* self clear reset */ + val = REG_RD(bp, emac_base + EMAC_REG_EMAC_MODE); + EMAC_WR(EMAC_REG_EMAC_MODE, (val | EMAC_MODE_RESET)); + + timeout = 200; + do + { + val = REG_RD(bp, emac_base + EMAC_REG_EMAC_MODE); + DP(NETIF_MSG_LINK, "EMAC reset reg is %u\n", val); + if (!timeout) { + DP(NETIF_MSG_LINK, "EMAC timeout!\n"); + return; + } + timeout--; + }while (val & EMAC_MODE_RESET); + + /* Set mac address */ + val = ((params->mac_addr[0] << 8) | + params->mac_addr[1]); + EMAC_WR(EMAC_REG_EMAC_MAC_MATCH, val); + + val = ((params->mac_addr[2] << 24) | + (params->mac_addr[3] << 16) | + (params->mac_addr[4] << 8) | + params->mac_addr[5]); + EMAC_WR(EMAC_REG_EMAC_MAC_MATCH + 4, val); +} + +static u8 bnx2x_emac_enable(struct link_params *params, + struct link_vars *vars, u8 lb) +{ + struct bnx2x *bp = params->bp; + u8 port = params->port; + u32 emac_base = port ? GRCBASE_EMAC1 : GRCBASE_EMAC0; + u32 val; + + DP(NETIF_MSG_LINK, "enabling EMAC\n"); + + /* enable emac and not bmac */ + REG_WR(bp, NIG_REG_EGRESS_EMAC0_PORT + port*4, 1); + + /* for paladium */ + if (CHIP_REV_IS_EMUL(bp)) { + /* Use lane 1 (of lanes 0-3) */ + REG_WR(bp, NIG_REG_XGXS_LANE_SEL_P0 + port*4, 1); + REG_WR(bp, NIG_REG_XGXS_SERDES0_MODE_SEL + + port*4, 1); + } + /* for fpga */ + else + + if (CHIP_REV_IS_FPGA(bp)) { + /* Use lane 1 (of lanes 0-3) */ + DP(NETIF_MSG_LINK, "bnx2x_emac_enable: Setting FPGA\n"); + + REG_WR(bp, NIG_REG_XGXS_LANE_SEL_P0 + port*4, 1); + REG_WR(bp, NIG_REG_XGXS_SERDES0_MODE_SEL + port*4, + 0); + } else + /* ASIC */ + if (vars->phy_flags & PHY_XGXS_FLAG) { + u32 ser_lane = ((params->lane_config & + PORT_HW_CFG_LANE_SWAP_CFG_MASTER_MASK) >> + PORT_HW_CFG_LANE_SWAP_CFG_MASTER_SHIFT); + + DP(NETIF_MSG_LINK, "XGXS\n"); + /* select the master lanes (out of 0-3) */ + REG_WR(bp, NIG_REG_XGXS_LANE_SEL_P0 + + port*4, ser_lane); + /* select XGXS */ + REG_WR(bp, NIG_REG_XGXS_SERDES0_MODE_SEL + + port*4, 1); + + } else { /* SerDes */ + DP(NETIF_MSG_LINK, "SerDes\n"); + /* select SerDes */ + REG_WR(bp, NIG_REG_XGXS_SERDES0_MODE_SEL + + port*4, 0); + } + + /* enable emac */ + REG_WR(bp, NIG_REG_NIG_EMAC0_EN + port*4, 1); + + if (CHIP_REV_IS_SLOW(bp)) { + /* config GMII mode */ + val = REG_RD(bp, emac_base + EMAC_REG_EMAC_MODE); + EMAC_WR(EMAC_REG_EMAC_MODE, + (val | EMAC_MODE_PORT_GMII)); + } else { /* ASIC */ + /* pause enable/disable */ + bnx2x_bits_dis(bp, emac_base + EMAC_REG_EMAC_RX_MODE, + EMAC_RX_MODE_FLOW_EN); + if (vars->flow_ctrl & FLOW_CTRL_RX) + bnx2x_bits_en(bp, emac_base + + EMAC_REG_EMAC_RX_MODE, + EMAC_RX_MODE_FLOW_EN); + + bnx2x_bits_dis(bp, emac_base + EMAC_REG_EMAC_TX_MODE, + EMAC_TX_MODE_EXT_PAUSE_EN); + if (vars->flow_ctrl & FLOW_CTRL_TX) + bnx2x_bits_en(bp, emac_base + + EMAC_REG_EMAC_TX_MODE, + EMAC_TX_MODE_EXT_PAUSE_EN); + } + + /* KEEP_VLAN_TAG, promiscuous */ + val = REG_RD(bp, emac_base + EMAC_REG_EMAC_RX_MODE); + val |= EMAC_RX_MODE_KEEP_VLAN_TAG | EMAC_RX_MODE_PROMISCUOUS; + EMAC_WR(EMAC_REG_EMAC_RX_MODE, val); + + /* Set Loopback */ + val = REG_RD(bp, emac_base + EMAC_REG_EMAC_MODE); + if (lb) + val |= 0x810; + else + val &= ~0x810; + EMAC_WR(EMAC_REG_EMAC_MODE, val); + + /* enable emac for jumbo packets */ + EMAC_WR(EMAC_REG_EMAC_RX_MTU_SIZE, + (EMAC_RX_MTU_SIZE_JUMBO_ENA | + (ETH_MAX_JUMBO_PACKET_SIZE + ETH_OVREHEAD))); + + /* strip CRC */ + REG_WR(bp, NIG_REG_NIG_INGRESS_EMAC0_NO_CRC + port*4, 0x1); + + /* disable the NIG in/out to the bmac */ + REG_WR(bp, NIG_REG_BMAC0_IN_EN + port*4, 0x0); + REG_WR(bp, NIG_REG_BMAC0_PAUSE_OUT_EN + port*4, 0x0); + REG_WR(bp, NIG_REG_BMAC0_OUT_EN + port*4, 0x0); + + /* enable the NIG in/out to the emac */ + REG_WR(bp, NIG_REG_EMAC0_IN_EN + port*4, 0x1); + val = 0; + if (vars->flow_ctrl & FLOW_CTRL_TX) + val = 1; + + REG_WR(bp, NIG_REG_EMAC0_PAUSE_OUT_EN + port*4, val); + REG_WR(bp, NIG_REG_EGRESS_EMAC0_OUT_EN + port*4, 0x1); + + if (CHIP_REV_IS_EMUL(bp)) { + /* take the BigMac out of reset */ + REG_WR(bp, + GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_SET, + (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port)); + + /* enable access for bmac registers */ + REG_WR(bp, NIG_REG_BMAC0_REGS_OUT_EN + port*4, 0x1); + } + + vars->mac_type = MAC_TYPE_EMAC; + return 0; +} + + + +static u8 bnx2x_bmac_enable(struct link_params *params, struct link_vars *vars, + u8 is_lb) +{ + struct bnx2x *bp = params->bp; + u8 port = params->port; + u32 bmac_addr = port ? NIG_REG_INGRESS_BMAC1_MEM : + NIG_REG_INGRESS_BMAC0_MEM; + u32 wb_data[2]; + u32 val; + + DP(NETIF_MSG_LINK, "Enabling BigMAC\n"); + /* reset and unreset the BigMac */ + REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_CLEAR, + (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port)); + msleep(1); + + REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_SET, + (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port)); + + /* enable access for bmac registers */ + REG_WR(bp, NIG_REG_BMAC0_REGS_OUT_EN + port*4, 0x1); + + /* XGXS control */ + wb_data[0] = 0x3c; + wb_data[1] = 0; + REG_WR_DMAE(bp, bmac_addr + + BIGMAC_REGISTER_BMAC_XGXS_CONTROL, + wb_data, 2); + + /* tx MAC SA */ + wb_data[0] = ((params->mac_addr[2] << 24) | + (params->mac_addr[3] << 16) | + (params->mac_addr[4] << 8) | + params->mac_addr[5]); + wb_data[1] = ((params->mac_addr[0] << 8) | + params->mac_addr[1]); + REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_TX_SOURCE_ADDR, + wb_data, 2); + + /* tx control */ + val = 0xc0; + if (vars->flow_ctrl & FLOW_CTRL_TX) + val |= 0x800000; + wb_data[0] = val; + wb_data[1] = 0; + REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_TX_CONTROL, + wb_data, 2); + + /* mac control */ + val = 0x3; + if (is_lb) { + val |= 0x4; + DP(NETIF_MSG_LINK, "enable bmac loopback\n"); + } + wb_data[0] = val; + wb_data[1] = 0; + REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_BMAC_CONTROL, + wb_data, 2); + + + /* set rx mtu */ + wb_data[0] = ETH_MAX_JUMBO_PACKET_SIZE + ETH_OVREHEAD; + wb_data[1] = 0; + REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_RX_MAX_SIZE, + wb_data, 2); + + /* rx control set to don't strip crc */ + val = 0x14; + if (vars->flow_ctrl & FLOW_CTRL_RX) + val |= 0x20; + wb_data[0] = val; + wb_data[1] = 0; + REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_RX_CONTROL, + wb_data, 2); + + /* set tx mtu */ + wb_data[0] = ETH_MAX_JUMBO_PACKET_SIZE + ETH_OVREHEAD; + wb_data[1] = 0; + REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_TX_MAX_SIZE, + wb_data, 2); + + /* set cnt max size */ + wb_data[0] = ETH_MAX_JUMBO_PACKET_SIZE + ETH_OVREHEAD; + wb_data[1] = 0; + REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_CNT_MAX_SIZE, + wb_data, 2); + + /* configure safc */ + wb_data[0] = 0x1000200; + wb_data[1] = 0; + REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_RX_LLFC_MSG_FLDS, + wb_data, 2); + /* fix for emulation */ + if (CHIP_REV_IS_EMUL(bp)) { + wb_data[0] = 0xf000; + wb_data[1] = 0; + REG_WR_DMAE(bp, + bmac_addr + BIGMAC_REGISTER_TX_PAUSE_THRESHOLD, + wb_data, 2); + } + + REG_WR(bp, NIG_REG_XGXS_SERDES0_MODE_SEL + port*4, 0x1); + REG_WR(bp, NIG_REG_XGXS_LANE_SEL_P0 + port*4, 0x0); + REG_WR(bp, NIG_REG_EGRESS_EMAC0_PORT + port*4, 0x0); + val = 0; + if (vars->flow_ctrl & FLOW_CTRL_TX) + val = 1; + REG_WR(bp, NIG_REG_BMAC0_PAUSE_OUT_EN + port*4, val); + REG_WR(bp, NIG_REG_EGRESS_EMAC0_OUT_EN + port*4, 0x0); + REG_WR(bp, NIG_REG_EMAC0_IN_EN + port*4, 0x0); + REG_WR(bp, NIG_REG_EMAC0_PAUSE_OUT_EN + port*4, 0x0); + REG_WR(bp, NIG_REG_BMAC0_IN_EN + port*4, 0x1); + REG_WR(bp, NIG_REG_BMAC0_OUT_EN + port*4, 0x1); + + vars->mac_type = MAC_TYPE_BMAC; + return 0; +} + +static void bnx2x_phy_deassert(struct link_params *params, u8 phy_flags) +{ + struct bnx2x *bp = params->bp; + u32 val; + + if (phy_flags & PHY_XGXS_FLAG) { + DP(NETIF_MSG_LINK, "bnx2x_phy_deassert:XGXS\n"); + val = XGXS_RESET_BITS; + + } else { /* SerDes */ + DP(NETIF_MSG_LINK, "bnx2x_phy_deassert:SerDes\n"); + val = SERDES_RESET_BITS; + } + + val = val << (params->port*16); + + /* reset and unreset the SerDes/XGXS */ + REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_3_CLEAR, + val); + udelay(500); + REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_3_SET, + val); + bnx2x_set_phy_mdio(params); +} + +void bnx2x_link_status_update(struct link_params *params, + struct link_vars *vars) +{ + struct bnx2x *bp = params->bp; + u8 link_10g; + u8 port = params->port; + + if (params->switch_cfg == SWITCH_CFG_1G) + vars->phy_flags = PHY_SERDES_FLAG; + else + vars->phy_flags = PHY_XGXS_FLAG; + vars->link_status = REG_RD(bp, params->shmem_base + + offsetof(struct shmem_region, + port_mb[port].link_status)); + + vars->link_up = (vars->link_status & LINK_STATUS_LINK_UP); + + if (vars->link_up) { + DP(NETIF_MSG_LINK, "phy link up\n"); + + vars->phy_link_up = 1; + vars->duplex = DUPLEX_FULL; + switch (vars->link_status & + LINK_STATUS_SPEED_AND_DUPLEX_MASK) { + case LINK_10THD: + vars->duplex = DUPLEX_HALF; + /* fall thru */ + case LINK_10TFD: + vars->line_speed = SPEED_10; + break; + + case LINK_100TXHD: + vars->duplex = DUPLEX_HALF; + /* fall thru */ + case LINK_100T4: + case LINK_100TXFD: + vars->line_speed = SPEED_100; + break; + + case LINK_1000THD: + vars->duplex = DUPLEX_HALF; + /* fall thru */ + case LINK_1000TFD: + vars->line_speed = SPEED_1000; + break; + + case LINK_2500THD: + vars->duplex = DUPLEX_HALF; + /* fall thru */ + case LINK_2500TFD: + vars->line_speed = SPEED_2500; + break; + + case LINK_10GTFD: + vars->line_speed = SPEED_10000; + break; + + case LINK_12GTFD: + vars->line_speed = SPEED_12000; + break; + + case LINK_12_5GTFD: + vars->line_speed = SPEED_12500; + break; + + case LINK_13GTFD: + vars->line_speed = SPEED_13000; + break; + + case LINK_15GTFD: + vars->line_speed = SPEED_15000; + break; + + case LINK_16GTFD: + vars->line_speed = SPEED_16000; + break; + + default: + break; + } + + if (vars->link_status & LINK_STATUS_TX_FLOW_CONTROL_ENABLED) + vars->flow_ctrl |= FLOW_CTRL_TX; + else + vars->flow_ctrl &= ~FLOW_CTRL_TX; + + if (vars->link_status & LINK_STATUS_RX_FLOW_CONTROL_ENABLED) + vars->flow_ctrl |= FLOW_CTRL_RX; + else + vars->flow_ctrl &= ~FLOW_CTRL_RX; + + if (vars->phy_flags & PHY_XGXS_FLAG) { + if (params->req_line_speed && + ((params->req_line_speed == SPEED_10) || + (params->req_line_speed == SPEED_100))) { + vars->phy_flags |= PHY_SGMII_FLAG; + } else { + vars->phy_flags &= ~PHY_SGMII_FLAG; + } + } + + /* anything 10 and over uses the bmac */ + link_10g = ((vars->line_speed == SPEED_10000) || + (vars->line_speed == SPEED_12000) || + (vars->line_speed == SPEED_12500) || + (vars->line_speed == SPEED_13000) || + (vars->line_speed == SPEED_15000) || + (vars->line_speed == SPEED_16000)); + if (link_10g) + vars->mac_type = MAC_TYPE_BMAC; + else + vars->mac_type = MAC_TYPE_EMAC; + + } else { /* link down */ + DP(NETIF_MSG_LINK, "phy link down\n"); + + vars->phy_link_up = 0; + + vars->line_speed = 0; + vars->duplex = DUPLEX_FULL; + vars->flow_ctrl = FLOW_CTRL_NONE; + + /* indicate no mac active */ + vars->mac_type = MAC_TYPE_NONE; + } + + DP(NETIF_MSG_LINK, "link_status 0x%x phy_link_up %x\n", + vars->link_status, vars->phy_link_up); + DP(NETIF_MSG_LINK, "line_speed %x duplex %x flow_ctrl 0x%x\n", + vars->line_speed, vars->duplex, vars->flow_ctrl); +} + +static void bnx2x_update_mng(struct link_params *params, u32 link_status) +{ + struct bnx2x *bp = params->bp; + REG_WR(bp, params->shmem_base + + offsetof(struct shmem_region, + port_mb[params->port].link_status), + link_status); +} + +static void bnx2x_bmac_rx_disable(struct bnx2x *bp, u8 port) +{ + u32 bmac_addr = port ? NIG_REG_INGRESS_BMAC1_MEM : + NIG_REG_INGRESS_BMAC0_MEM; + u32 wb_data[2]; + u32 nig_bmac_enable = REG_RD(bp, NIG_REG_BMAC0_REGS_OUT_EN + port*4); + + /* Only if the bmac is out of reset */ + if (REG_RD(bp, MISC_REG_RESET_REG_2) & + (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port) && + nig_bmac_enable) { + + /* Clear Rx Enable bit in BMAC_CONTROL register */ + REG_RD_DMAE(bp, bmac_addr + BIGMAC_REGISTER_BMAC_CONTROL, + wb_data, 2); + wb_data[0] &= ~BMAC_CONTROL_RX_ENABLE; + REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_BMAC_CONTROL, + wb_data, 2); + + msleep(1); + } +} + +static u8 bnx2x_pbf_update(struct link_params *params, u32 flow_ctrl, + u32 line_speed) +{ + struct bnx2x *bp = params->bp; + u8 port = params->port; + u32 init_crd, crd; + u32 count = 1000; + u32 pause = 0; + + /* disable port */ + REG_WR(bp, PBF_REG_DISABLE_NEW_TASK_PROC_P0 + port*4, 0x1); + + /* wait for init credit */ + init_crd = REG_RD(bp, PBF_REG_P0_INIT_CRD + port*4); + crd = REG_RD(bp, PBF_REG_P0_CREDIT + port*8); + DP(NETIF_MSG_LINK, "init_crd 0x%x crd 0x%x\n", init_crd, crd); + + while ((init_crd != crd) && count) { + msleep(5); + + crd = REG_RD(bp, PBF_REG_P0_CREDIT + port*8); + count--; + } + crd = REG_RD(bp, PBF_REG_P0_CREDIT + port*8); + if (init_crd != crd) { + DP(NETIF_MSG_LINK, "BUG! init_crd 0x%x != crd 0x%x\n", + init_crd, crd); + return -EINVAL; + } + + if (flow_ctrl & FLOW_CTRL_RX) + pause = 1; + REG_WR(bp, PBF_REG_P0_PAUSE_ENABLE + port*4, pause); + if (pause) { + /* update threshold */ + REG_WR(bp, PBF_REG_P0_ARB_THRSH + port*4, 0); + /* update init credit */ + init_crd = 778; /* (800-18-4) */ + + } else { + u32 thresh = (ETH_MAX_JUMBO_PACKET_SIZE + + ETH_OVREHEAD)/16; + + /* update threshold */ + REG_WR(bp, PBF_REG_P0_ARB_THRSH + port*4, thresh); + /* update init credit */ + switch (line_speed) { + case SPEED_10: + case SPEED_100: + case SPEED_1000: + init_crd = thresh + 55 - 22; + break; + + case SPEED_2500: + init_crd = thresh + 138 - 22; + break; + + case SPEED_10000: + init_crd = thresh + 553 - 22; + break; + + case SPEED_12000: + init_crd = thresh + 664 - 22; + break; + + case SPEED_13000: + init_crd = thresh + 742 - 22; + break; + + case SPEED_16000: + init_crd = thresh + 778 - 22; + break; + default: + DP(NETIF_MSG_LINK, "Invalid line_speed 0x%x\n", + line_speed); + return -EINVAL; + break; + } + } + REG_WR(bp, PBF_REG_P0_INIT_CRD + port*4, init_crd); + DP(NETIF_MSG_LINK, "PBF updated to speed %d credit %d\n", + line_speed, init_crd); + + /* probe the credit changes */ + REG_WR(bp, PBF_REG_INIT_P0 + port*4, 0x1); + msleep(5); + REG_WR(bp, PBF_REG_INIT_P0 + port*4, 0x0); + + /* enable port */ + REG_WR(bp, PBF_REG_DISABLE_NEW_TASK_PROC_P0 + port*4, 0x0); + return 0; +} + +static u32 bnx2x_get_emac_base(u32 ext_phy_type, u8 port) +{ + u32 emac_base; + switch (ext_phy_type) { + case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072: + emac_base = GRCBASE_EMAC0; + break; + case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073: + emac_base = (port) ? GRCBASE_EMAC0: GRCBASE_EMAC1; + break; + default: + emac_base = (port) ? GRCBASE_EMAC1: GRCBASE_EMAC0; + break; + } + return emac_base; + +} + +u8 bnx2x_cl45_write(struct bnx2x *bp, u8 port, u32 ext_phy_type, + u8 phy_addr, u8 devad, u16 reg, u16 val) +{ + u32 tmp, saved_mode; + u8 i, rc = 0; + u32 mdio_ctrl = bnx2x_get_emac_base(ext_phy_type, port); + + /* set clause 45 mode, slow down the MDIO clock to 2.5MHz + * (a value of 49==0x31) and make sure that the AUTO poll is off + */ + saved_mode = REG_RD(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE); + tmp = saved_mode & ~(EMAC_MDIO_MODE_AUTO_POLL | + EMAC_MDIO_MODE_CLOCK_CNT); + tmp |= (EMAC_MDIO_MODE_CLAUSE_45 | + (49 << EMAC_MDIO_MODE_CLOCK_CNT_BITSHIFT)); + REG_WR(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE, tmp); + REG_RD(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE); + udelay(40); + + /* address */ + + tmp = ((phy_addr << 21) | (devad << 16) | reg | + EMAC_MDIO_COMM_COMMAND_ADDRESS | + EMAC_MDIO_COMM_START_BUSY); + REG_WR(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM, tmp); + + for (i = 0; i < 50; i++) { + udelay(10); + + tmp = REG_RD(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM); + if (!(tmp & EMAC_MDIO_COMM_START_BUSY)) { + udelay(5); + break; + } + } + if (tmp & EMAC_MDIO_COMM_START_BUSY) { + DP(NETIF_MSG_LINK, "write phy register failed\n"); + rc = -EFAULT; + } else { + /* data */ + tmp = ((phy_addr << 21) | (devad << 16) | val | + EMAC_MDIO_COMM_COMMAND_WRITE_45 | + EMAC_MDIO_COMM_START_BUSY); + REG_WR(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM, tmp); + + for (i = 0; i < 50; i++) { + udelay(10); + + tmp = REG_RD(bp, mdio_ctrl + + EMAC_REG_EMAC_MDIO_COMM); + if (!(tmp & EMAC_MDIO_COMM_START_BUSY)) { + udelay(5); + break; + } + } + if (tmp & EMAC_MDIO_COMM_START_BUSY) { + DP(NETIF_MSG_LINK, "write phy register failed\n"); + rc = -EFAULT; + } + } + + /* Restore the saved mode */ + REG_WR(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE, saved_mode); + + return rc; +} + +u8 bnx2x_cl45_read(struct bnx2x *bp, u8 port, u32 ext_phy_type, + u8 phy_addr, u8 devad, u16 reg, u16 *ret_val) +{ + u32 val, saved_mode; + u16 i; + u8 rc = 0; + + u32 mdio_ctrl = bnx2x_get_emac_base(ext_phy_type, port); + /* set clause 45 mode, slow down the MDIO clock to 2.5MHz + * (a value of 49==0x31) and make sure that the AUTO poll is off + */ + saved_mode = REG_RD(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE); + val = saved_mode & ((EMAC_MDIO_MODE_AUTO_POLL | + EMAC_MDIO_MODE_CLOCK_CNT)); + val |= (EMAC_MDIO_MODE_CLAUSE_45 | + (49 << EMAC_MDIO_MODE_CLOCK_CNT_BITSHIFT)); + REG_WR(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE, val); + REG_RD(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE); + udelay(40); + + /* address */ + val = ((phy_addr << 21) | (devad << 16) | reg | + EMAC_MDIO_COMM_COMMAND_ADDRESS | + EMAC_MDIO_COMM_START_BUSY); + REG_WR(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM, val); + + for (i = 0; i < 50; i++) { + udelay(10); + + val = REG_RD(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM); + if (!(val & EMAC_MDIO_COMM_START_BUSY)) { + udelay(5); + break; + } + } + if (val & EMAC_MDIO_COMM_START_BUSY) { + DP(NETIF_MSG_LINK, "read phy register failed\n"); + + *ret_val = 0; + rc = -EFAULT; + + } else { + /* data */ + val = ((phy_addr << 21) | (devad << 16) | + EMAC_MDIO_COMM_COMMAND_READ_45 | + EMAC_MDIO_COMM_START_BUSY); + REG_WR(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM, val); + + for (i = 0; i < 50; i++) { + udelay(10); + + val = REG_RD(bp, mdio_ctrl + + EMAC_REG_EMAC_MDIO_COMM); + if (!(val & EMAC_MDIO_COMM_START_BUSY)) { + *ret_val = (u16)(val & EMAC_MDIO_COMM_DATA); + break; + } + } + if (val & EMAC_MDIO_COMM_START_BUSY) { + DP(NETIF_MSG_LINK, "read phy register failed\n"); + + *ret_val = 0; + rc = -EFAULT; + } + } + + /* Restore the saved mode */ + REG_WR(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE, saved_mode); + + return rc; +} + +static void bnx2x_set_aer_mmd(struct link_params *params, + struct link_vars *vars) +{ + struct bnx2x *bp = params->bp; + u32 ser_lane; + u16 offset; + + ser_lane = ((params->lane_config & + PORT_HW_CFG_LANE_SWAP_CFG_MASTER_MASK) >> + PORT_HW_CFG_LANE_SWAP_CFG_MASTER_SHIFT); + + offset = (vars->phy_flags & PHY_XGXS_FLAG) ? + (params->phy_addr + ser_lane) : 0; + + CL45_WR_OVER_CL22(bp, params->port, + params->phy_addr, + MDIO_REG_BANK_AER_BLOCK, + MDIO_AER_BLOCK_AER_REG, 0x3800 + offset); +} + +static void bnx2x_set_master_ln(struct link_params *params) +{ + struct bnx2x *bp = params->bp; + u16 new_master_ln, ser_lane; + ser_lane = ((params->lane_config & + PORT_HW_CFG_LANE_SWAP_CFG_MASTER_MASK) >> + PORT_HW_CFG_LANE_SWAP_CFG_MASTER_SHIFT); + + /* set the master_ln for AN */ + CL45_RD_OVER_CL22(bp, params->port, + params->phy_addr, + MDIO_REG_BANK_XGXS_BLOCK2, + MDIO_XGXS_BLOCK2_TEST_MODE_LANE, + &new_master_ln); + + CL45_WR_OVER_CL22(bp, params->port, + params->phy_addr, + MDIO_REG_BANK_XGXS_BLOCK2 , + MDIO_XGXS_BLOCK2_TEST_MODE_LANE, + (new_master_ln | ser_lane)); +} + +static u8 bnx2x_reset_unicore(struct link_params *params) +{ + struct bnx2x *bp = params->bp; + u16 mii_control; + u16 i; + + CL45_RD_OVER_CL22(bp, params->port, + params->phy_addr, + MDIO_REG_BANK_COMBO_IEEE0, + MDIO_COMBO_IEEE0_MII_CONTROL, &mii_control); + + /* reset the unicore */ + CL45_WR_OVER_CL22(bp, params->port, + params->phy_addr, + MDIO_REG_BANK_COMBO_IEEE0, + MDIO_COMBO_IEEE0_MII_CONTROL, + (mii_control | + MDIO_COMBO_IEEO_MII_CONTROL_RESET)); + + /* wait for the reset to self clear */ + for (i = 0; i < MDIO_ACCESS_TIMEOUT; i++) { + udelay(5); + + /* the reset erased the previous bank value */ + CL45_RD_OVER_CL22(bp, params->port, + params->phy_addr, + MDIO_REG_BANK_COMBO_IEEE0, + MDIO_COMBO_IEEE0_MII_CONTROL, + &mii_control); + + if (!(mii_control & MDIO_COMBO_IEEO_MII_CONTROL_RESET)) { + udelay(5); + return 0; + } + } + + DP(NETIF_MSG_LINK, "BUG! XGXS is still in reset!\n"); + return -EINVAL; + +} + +static void bnx2x_set_swap_lanes(struct link_params *params) +{ + struct bnx2x *bp = params->bp; + /* Each two bits represents a lane number: + No swap is 0123 => 0x1b no need to enable the swap */ + u16 ser_lane, rx_lane_swap, tx_lane_swap; + + ser_lane = ((params->lane_config & + PORT_HW_CFG_LANE_SWAP_CFG_MASTER_MASK) >> + PORT_HW_CFG_LANE_SWAP_CFG_MASTER_SHIFT); + rx_lane_swap = ((params->lane_config & + PORT_HW_CFG_LANE_SWAP_CFG_RX_MASK) >> + PORT_HW_CFG_LANE_SWAP_CFG_RX_SHIFT); + tx_lane_swap = ((params->lane_config & + PORT_HW_CFG_LANE_SWAP_CFG_TX_MASK) >> + PORT_HW_CFG_LANE_SWAP_CFG_TX_SHIFT); + + if (rx_lane_swap != 0x1b) { + CL45_WR_OVER_CL22(bp, params->port, + params->phy_addr, + MDIO_REG_BANK_XGXS_BLOCK2, + MDIO_XGXS_BLOCK2_RX_LN_SWAP, + (rx_lane_swap | + MDIO_XGXS_BLOCK2_RX_LN_SWAP_ENABLE | + MDIO_XGXS_BLOCK2_RX_LN_SWAP_FORCE_ENABLE)); + } else { + CL45_WR_OVER_CL22(bp, params->port, + params->phy_addr, + MDIO_REG_BANK_XGXS_BLOCK2, + MDIO_XGXS_BLOCK2_RX_LN_SWAP, 0); + } + + if (tx_lane_swap != 0x1b) { + CL45_WR_OVER_CL22(bp, params->port, + params->phy_addr, + MDIO_REG_BANK_XGXS_BLOCK2, + MDIO_XGXS_BLOCK2_TX_LN_SWAP, + (tx_lane_swap | + MDIO_XGXS_BLOCK2_TX_LN_SWAP_ENABLE)); + } else { + CL45_WR_OVER_CL22(bp, params->port, + params->phy_addr, + MDIO_REG_BANK_XGXS_BLOCK2, + MDIO_XGXS_BLOCK2_TX_LN_SWAP, 0); + } +} + +static void bnx2x_set_parallel_detection(struct link_params *params, + u8 phy_flags) +{ + struct bnx2x *bp = params->bp; + u16 control2; + + CL45_RD_OVER_CL22(bp, params->port, + params->phy_addr, + MDIO_REG_BANK_SERDES_DIGITAL, + MDIO_SERDES_DIGITAL_A_1000X_CONTROL2, + &control2); + + + control2 |= MDIO_SERDES_DIGITAL_A_1000X_CONTROL2_PRL_DT_EN; + + + CL45_WR_OVER_CL22(bp, params->port, + params->phy_addr, + MDIO_REG_BANK_SERDES_DIGITAL, + MDIO_SERDES_DIGITAL_A_1000X_CONTROL2, + control2); + + if (phy_flags & PHY_XGXS_FLAG) { + DP(NETIF_MSG_LINK, "XGXS\n"); + + CL45_WR_OVER_CL22(bp, params->port, + params->phy_addr, + MDIO_REG_BANK_10G_PARALLEL_DETECT, + MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_LINK, + MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_LINK_CNT); + + CL45_RD_OVER_CL22(bp, params->port, + params->phy_addr, + MDIO_REG_BANK_10G_PARALLEL_DETECT, + MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_CONTROL, + &control2); + + + control2 |= + MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_CONTROL_PARDET10G_EN; + + CL45_WR_OVER_CL22(bp, params->port, + params->phy_addr, + MDIO_REG_BANK_10G_PARALLEL_DETECT, + MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_CONTROL, + control2); + + /* Disable parallel detection of HiG */ + CL45_WR_OVER_CL22(bp, params->port, + params->phy_addr, + MDIO_REG_BANK_XGXS_BLOCK2, + MDIO_XGXS_BLOCK2_UNICORE_MODE_10G, + MDIO_XGXS_BLOCK2_UNICORE_MODE_10G_CX4_XGXS | + MDIO_XGXS_BLOCK2_UNICORE_MODE_10G_HIGIG_XGXS); + } +} + +static void bnx2x_set_autoneg(struct link_params *params, + struct link_vars *vars) +{ + struct bnx2x *bp = params->bp; + u16 reg_val; + + /* CL37 Autoneg */ + + CL45_RD_OVER_CL22(bp, params->port, + params->phy_addr, + MDIO_REG_BANK_COMBO_IEEE0, + MDIO_COMBO_IEEE0_MII_CONTROL, ®_val); + + /* CL37 Autoneg Enabled */ + if (params->req_line_speed == SPEED_AUTO_NEG) + reg_val |= MDIO_COMBO_IEEO_MII_CONTROL_AN_EN; + else /* CL37 Autoneg Disabled */ + reg_val &= ~(MDIO_COMBO_IEEO_MII_CONTROL_AN_EN | + MDIO_COMBO_IEEO_MII_CONTROL_RESTART_AN); + + CL45_WR_OVER_CL22(bp, params->port, + params->phy_addr, + MDIO_REG_BANK_COMBO_IEEE0, + MDIO_COMBO_IEEE0_MII_CONTROL, reg_val); + + /* Enable/Disable Autodetection */ + + CL45_RD_OVER_CL22(bp, params->port, + params->phy_addr, + MDIO_REG_BANK_SERDES_DIGITAL, + MDIO_SERDES_DIGITAL_A_1000X_CONTROL1, ®_val); + reg_val &= ~MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_SIGNAL_DETECT_EN; + if (params->req_line_speed == SPEED_AUTO_NEG) + reg_val |= MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_AUTODET; + else + reg_val &= ~MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_AUTODET; + + CL45_WR_OVER_CL22(bp, params->port, + params->phy_addr, + MDIO_REG_BANK_SERDES_DIGITAL, + MDIO_SERDES_DIGITAL_A_1000X_CONTROL1, reg_val); + + /* Enable TetonII and BAM autoneg */ + CL45_RD_OVER_CL22(bp, params->port, + params->phy_addr, + MDIO_REG_BANK_BAM_NEXT_PAGE, + MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL, + ®_val); + if (params->req_line_speed == SPEED_AUTO_NEG) { + /* Enable BAM aneg Mode and TetonII aneg Mode */ + reg_val |= (MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL_BAM_MODE | + MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL_TETON_AN); + } else { + /* TetonII and BAM Autoneg Disabled */ + reg_val &= ~(MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL_BAM_MODE | + MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL_TETON_AN); + } + CL45_WR_OVER_CL22(bp, params->port, + params->phy_addr, + MDIO_REG_BANK_BAM_NEXT_PAGE, + MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL, + reg_val); + + /* Enable Clause 73 Aneg */ + if ((params->req_line_speed == SPEED_AUTO_NEG) && + (SUPPORT_CL73)) { + /* Enable BAM Station Manager */ + + CL45_WR_OVER_CL22(bp, params->port, + params->phy_addr, + MDIO_REG_BANK_CL73_USERB0, + MDIO_CL73_USERB0_CL73_BAM_CTRL1, + (MDIO_CL73_USERB0_CL73_BAM_CTRL1_BAM_EN | + MDIO_CL73_USERB0_CL73_BAM_CTRL1_BAM_STATION_MNGR_EN | + MDIO_CL73_USERB0_CL73_BAM_CTRL1_BAM_NP_AFTER_BP_EN)); + + /* Merge CL73 and CL37 aneg resolution */ + CL45_RD_OVER_CL22(bp, params->port, + params->phy_addr, + MDIO_REG_BANK_CL73_USERB0, + MDIO_CL73_USERB0_CL73_BAM_CTRL3, + ®_val); + + CL45_WR_OVER_CL22(bp, params->port, + params->phy_addr, + MDIO_REG_BANK_CL73_USERB0, + MDIO_CL73_USERB0_CL73_BAM_CTRL3, + (reg_val | + MDIO_CL73_USERB0_CL73_BAM_CTRL3_USE_CL73_HCD_MR)); + + /* Set the CL73 AN speed */ + + CL45_RD_OVER_CL22(bp, params->port, + params->phy_addr, + MDIO_REG_BANK_CL73_IEEEB1, + MDIO_CL73_IEEEB1_AN_ADV2, ®_val); + /* In the SerDes we support only the 1G. + In the XGXS we support the 10G KX4 + but we currently do not support the KR */ + if (vars->phy_flags & PHY_XGXS_FLAG) { + DP(NETIF_MSG_LINK, "XGXS\n"); + /* 10G KX4 */ + reg_val |= MDIO_CL73_IEEEB1_AN_ADV2_ADVR_10G_KX4; + } else { + DP(NETIF_MSG_LINK, "SerDes\n"); + /* 1000M KX */ + reg_val |= MDIO_CL73_IEEEB1_AN_ADV2_ADVR_1000M_KX; + } + CL45_WR_OVER_CL22(bp, params->port, + params->phy_addr, + MDIO_REG_BANK_CL73_IEEEB1, + MDIO_CL73_IEEEB1_AN_ADV2, reg_val); + + /* CL73 Autoneg Enabled */ + reg_val = MDIO_CL73_IEEEB0_CL73_AN_CONTROL_AN_EN; + } else { + /* CL73 Autoneg Disabled */ + reg_val = 0; + } + CL45_WR_OVER_CL22(bp, params->port, + params->phy_addr, + MDIO_REG_BANK_CL73_IEEEB0, + MDIO_CL73_IEEEB0_CL73_AN_CONTROL, reg_val); +} + +/* program SerDes, forced speed */ +static void bnx2x_program_serdes(struct link_params *params) +{ + struct bnx2x *bp = params->bp; + u16 reg_val; + + /* program duplex, disable autoneg */ + + CL45_RD_OVER_CL22(bp, params->port, + params->phy_addr, + MDIO_REG_BANK_COMBO_IEEE0, + MDIO_COMBO_IEEE0_MII_CONTROL, ®_val); + reg_val &= ~(MDIO_COMBO_IEEO_MII_CONTROL_FULL_DUPLEX | + MDIO_COMBO_IEEO_MII_CONTROL_AN_EN); + if (params->req_duplex == DUPLEX_FULL) + reg_val |= MDIO_COMBO_IEEO_MII_CONTROL_FULL_DUPLEX; + CL45_WR_OVER_CL22(bp, params->port, + params->phy_addr, + MDIO_REG_BANK_COMBO_IEEE0, + MDIO_COMBO_IEEE0_MII_CONTROL, reg_val); + + /* program speed + - needed only if the speed is greater than 1G (2.5G or 10G) */ + if (!((params->req_line_speed == SPEED_1000) || + (params->req_line_speed == SPEED_100) || + (params->req_line_speed == SPEED_10))) { + CL45_RD_OVER_CL22(bp, params->port, + params->phy_addr, + MDIO_REG_BANK_SERDES_DIGITAL, + MDIO_SERDES_DIGITAL_MISC1, ®_val); + /* clearing the speed value before setting the right speed */ + reg_val &= ~MDIO_SERDES_DIGITAL_MISC1_FORCE_SPEED_MASK; + reg_val |= (MDIO_SERDES_DIGITAL_MISC1_REFCLK_SEL_156_25M | + MDIO_SERDES_DIGITAL_MISC1_FORCE_SPEED_SEL); + if (params->req_line_speed == SPEED_10000) + reg_val |= + MDIO_SERDES_DIGITAL_MISC1_FORCE_SPEED_10G_CX4; + if (params->req_line_speed == SPEED_13000) + reg_val |= + MDIO_SERDES_DIGITAL_MISC1_FORCE_SPEED_13G; + CL45_WR_OVER_CL22(bp, params->port, + params->phy_addr, + MDIO_REG_BANK_SERDES_DIGITAL, + MDIO_SERDES_DIGITAL_MISC1, reg_val); + } +} + +static void bnx2x_set_brcm_cl37_advertisment(struct link_params *params) +{ + struct bnx2x *bp = params->bp; + u16 val = 0; + + /* configure the 48 bits for BAM AN */ + + /* set extended capabilities */ + if (params->speed_cap_mask & PORT_HW_CFG_SPEED_CAPABILITY_D0_2_5G) + val |= MDIO_OVER_1G_UP1_2_5G; + if (params->speed_cap_mask & PORT_HW_CFG_SPEED_CAPABILITY_D0_10G) + val |= MDIO_OVER_1G_UP1_10G; + CL45_WR_OVER_CL22(bp, params->port, + params->phy_addr, + MDIO_REG_BANK_OVER_1G, + MDIO_OVER_1G_UP1, val); + + CL45_WR_OVER_CL22(bp, params->port, + params->phy_addr, + MDIO_REG_BANK_OVER_1G, + MDIO_OVER_1G_UP3, 0); +} + +static void bnx2x_set_ieee_aneg_advertisment(struct link_params *params, + u32 *ieee_fc) +{ + struct bnx2x *bp = params->bp; + /* for AN, we are always publishing full duplex */ + u16 an_adv = MDIO_COMBO_IEEE0_AUTO_NEG_ADV_FULL_DUPLEX; + + /* resolve pause mode and advertisement + * Please refer to Table 28B-3 of the 802.3ab-1999 spec */ + + switch (params->req_flow_ctrl) { + case FLOW_CTRL_AUTO: + if (params->mtu <= MAX_MTU_SIZE) { + an_adv |= + MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH; + } else { + an_adv |= + MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC; + } + break; + case FLOW_CTRL_TX: + an_adv |= + MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC; + break; + + case FLOW_CTRL_RX: + case FLOW_CTRL_BOTH: + an_adv |= MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH; + break; + + case FLOW_CTRL_NONE: + default: + an_adv |= MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_NONE; + break; + } + + *ieee_fc = an_adv; + + CL45_WR_OVER_CL22(bp, params->port, + params->phy_addr, + MDIO_REG_BANK_COMBO_IEEE0, + MDIO_COMBO_IEEE0_AUTO_NEG_ADV, an_adv); +} + +static void bnx2x_restart_autoneg(struct link_params *params) +{ + struct bnx2x *bp = params->bp; + DP(NETIF_MSG_LINK, "bnx2x_restart_autoneg\n"); + if (SUPPORT_CL73) { + /* enable and restart clause 73 aneg */ + u16 an_ctrl; + + CL45_RD_OVER_CL22(bp, params->port, + params->phy_addr, + MDIO_REG_BANK_CL73_IEEEB0, + MDIO_CL73_IEEEB0_CL73_AN_CONTROL, + &an_ctrl); + CL45_WR_OVER_CL22(bp, params->port, + params->phy_addr, + MDIO_REG_BANK_CL73_IEEEB0, + MDIO_CL73_IEEEB0_CL73_AN_CONTROL, + (an_ctrl | + MDIO_CL73_IEEEB0_CL73_AN_CONTROL_AN_EN | + MDIO_CL73_IEEEB0_CL73_AN_CONTROL_RESTART_AN)); + + } else { + /* Enable and restart BAM/CL37 aneg */ + u16 mii_control; + + CL45_RD_OVER_CL22(bp, params->port, + params->phy_addr, + MDIO_REG_BANK_COMBO_IEEE0, + MDIO_COMBO_IEEE0_MII_CONTROL, + &mii_control); + DP(NETIF_MSG_LINK, + "bnx2x_restart_autoneg mii_control before = 0x%x\n", + mii_control); + CL45_WR_OVER_CL22(bp, params->port, + params->phy_addr, + MDIO_REG_BANK_COMBO_IEEE0, + MDIO_COMBO_IEEE0_MII_CONTROL, + (mii_control | + MDIO_COMBO_IEEO_MII_CONTROL_AN_EN | + MDIO_COMBO_IEEO_MII_CONTROL_RESTART_AN)); + } +} + +static void bnx2x_initialize_sgmii_process(struct link_params *params) +{ + struct bnx2x *bp = params->bp; + u16 control1; + + /* in SGMII mode, the unicore is always slave */ + + CL45_RD_OVER_CL22(bp, params->port, + params->phy_addr, + MDIO_REG_BANK_SERDES_DIGITAL, + MDIO_SERDES_DIGITAL_A_1000X_CONTROL1, + &control1); + control1 |= MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_INVERT_SIGNAL_DETECT; + /* set sgmii mode (and not fiber) */ + control1 &= ~(MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_FIBER_MODE | + MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_AUTODET | + MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_MSTR_MODE); + CL45_WR_OVER_CL22(bp, params->port, + params->phy_addr, + MDIO_REG_BANK_SERDES_DIGITAL, + MDIO_SERDES_DIGITAL_A_1000X_CONTROL1, + control1); + + /* if forced speed */ + if (!(params->req_line_speed == SPEED_AUTO_NEG)) { + /* set speed, disable autoneg */ + u16 mii_control; + + CL45_RD_OVER_CL22(bp, params->port, + params->phy_addr, + MDIO_REG_BANK_COMBO_IEEE0, + MDIO_COMBO_IEEE0_MII_CONTROL, + &mii_control); + mii_control &= ~(MDIO_COMBO_IEEO_MII_CONTROL_AN_EN | + MDIO_COMBO_IEEO_MII_CONTROL_MAN_SGMII_SP_MASK| + MDIO_COMBO_IEEO_MII_CONTROL_FULL_DUPLEX); + + switch (params->req_line_speed) { + case SPEED_100: + mii_control |= + MDIO_COMBO_IEEO_MII_CONTROL_MAN_SGMII_SP_100; + break; + case SPEED_1000: + mii_control |= + MDIO_COMBO_IEEO_MII_CONTROL_MAN_SGMII_SP_1000; + break; + case SPEED_10: + /* there is nothing to set for 10M */ + break; + default: + /* invalid speed for SGMII */ + DP(NETIF_MSG_LINK, "Invalid req_line_speed 0x%x\n", + params->req_line_speed); + break; + } + + /* setting the full duplex */ + if (params->req_duplex == DUPLEX_FULL) + mii_control |= + MDIO_COMBO_IEEO_MII_CONTROL_FULL_DUPLEX; + CL45_WR_OVER_CL22(bp, params->port, + params->phy_addr, + MDIO_REG_BANK_COMBO_IEEE0, + MDIO_COMBO_IEEE0_MII_CONTROL, + mii_control); + + } else { /* AN mode */ + /* enable and restart AN */ + bnx2x_restart_autoneg(params); + } +} + + +/* + * link management + */ + +static void bnx2x_pause_resolve(struct link_vars *vars, u32 pause_result) +{ + switch (pause_result) { /* ASYM P ASYM P */ + case 0xb: /* 1 0 1 1 */ + vars->flow_ctrl = FLOW_CTRL_TX; + break; + + case 0xe: /* 1 1 1 0 */ + vars->flow_ctrl = FLOW_CTRL_RX; + break; + + case 0x5: /* 0 1 0 1 */ + case 0x7: /* 0 1 1 1 */ + case 0xd: /* 1 1 0 1 */ + case 0xf: /* 1 1 1 1 */ + vars->flow_ctrl = FLOW_CTRL_BOTH; + break; + + default: + break; + } +} + +static u8 bnx2x_ext_phy_resove_fc(struct link_params *params, + struct link_vars *vars) +{ + struct bnx2x *bp = params->bp; + u8 ext_phy_addr; + u16 ld_pause; /* local */ + u16 lp_pause; /* link partner */ + u16 an_complete; /* AN complete */ + u16 pause_result; + u8 ret = 0; + u32 ext_phy_type; + u8 port = params->port; + ext_phy_addr = ((params->ext_phy_config & + PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >> + PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT); + + ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config); + /* read twice */ + + bnx2x_cl45_read(bp, port, + ext_phy_type, + ext_phy_addr, + MDIO_AN_DEVAD, + MDIO_AN_REG_STATUS, &an_complete); + bnx2x_cl45_read(bp, port, + ext_phy_type, + ext_phy_addr, + MDIO_AN_DEVAD, + MDIO_AN_REG_STATUS, &an_complete); + + if (an_complete & MDIO_AN_REG_STATUS_AN_COMPLETE) { + ret = 1; + bnx2x_cl45_read(bp, port, + ext_phy_type, + ext_phy_addr, + MDIO_AN_DEVAD, + MDIO_AN_REG_ADV_PAUSE, &ld_pause); + bnx2x_cl45_read(bp, port, + ext_phy_type, + ext_phy_addr, + MDIO_AN_DEVAD, + MDIO_AN_REG_LP_AUTO_NEG, &lp_pause); + pause_result = (ld_pause & + MDIO_AN_REG_ADV_PAUSE_MASK) >> 8; + pause_result |= (lp_pause & + MDIO_AN_REG_ADV_PAUSE_MASK) >> 10; + DP(NETIF_MSG_LINK, "Ext PHY pause result 0x%x \n", + pause_result); + bnx2x_pause_resolve(vars, pause_result); + } + return ret; +} + + +static void bnx2x_flow_ctrl_resolve(struct link_params *params, + struct link_vars *vars, + u32 gp_status) +{ + struct bnx2x *bp = params->bp; + u16 ld_pause; /* local driver */ + u16 lp_pause; /* link partner */ + u16 pause_result; + + vars->flow_ctrl = FLOW_CTRL_NONE; + + /* resolve from gp_status in case of AN complete and not sgmii */ + if ((params->req_flow_ctrl == FLOW_CTRL_AUTO) && + (gp_status & MDIO_AN_CL73_OR_37_COMPLETE) && + (!(vars->phy_flags & PHY_SGMII_FLAG)) && + (XGXS_EXT_PHY_TYPE(params->ext_phy_config) == + PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT)) { + CL45_RD_OVER_CL22(bp, params->port, + params->phy_addr, + MDIO_REG_BANK_COMBO_IEEE0, + MDIO_COMBO_IEEE0_AUTO_NEG_ADV, + &ld_pause); + CL45_RD_OVER_CL22(bp, params->port, + params->phy_addr, + MDIO_REG_BANK_COMBO_IEEE0, + MDIO_COMBO_IEEE0_AUTO_NEG_LINK_PARTNER_ABILITY1, + &lp_pause); + pause_result = (ld_pause & + MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_MASK)>>5; + pause_result |= (lp_pause & + MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_MASK)>>7; + DP(NETIF_MSG_LINK, "pause_result 0x%x\n", pause_result); + bnx2x_pause_resolve(vars, pause_result); + } else if ((params->req_flow_ctrl == FLOW_CTRL_AUTO) && + (bnx2x_ext_phy_resove_fc(params, vars))) { + return; + } else { + vars->flow_ctrl = params->req_flow_ctrl; + if (vars->flow_ctrl == FLOW_CTRL_AUTO) { + if (params->mtu <= MAX_MTU_SIZE) + vars->flow_ctrl = FLOW_CTRL_BOTH; + else + vars->flow_ctrl = FLOW_CTRL_TX; + } + } + DP(NETIF_MSG_LINK, "flow_ctrl 0x%x\n", vars->flow_ctrl); +} + + +static u8 bnx2x_link_settings_status(struct link_params *params, + struct link_vars *vars, + u32 gp_status) +{ + struct bnx2x *bp = params->bp; + u8 rc = 0; + vars->link_status = 0; + + if (gp_status & MDIO_GP_STATUS_TOP_AN_STATUS1_LINK_STATUS) { + DP(NETIF_MSG_LINK, "phy link up gp_status=0x%x\n", + gp_status); + + vars->phy_link_up = 1; + vars->link_status |= LINK_STATUS_LINK_UP; + + if (gp_status & MDIO_GP_STATUS_TOP_AN_STATUS1_DUPLEX_STATUS) + vars->duplex = DUPLEX_FULL; + else + vars->duplex = DUPLEX_HALF; + + bnx2x_flow_ctrl_resolve(params, vars, gp_status); + + switch (gp_status & GP_STATUS_SPEED_MASK) { + case GP_STATUS_10M: + vars->line_speed = SPEED_10; + if (vars->duplex == DUPLEX_FULL) + vars->link_status |= LINK_10TFD; + else + vars->link_status |= LINK_10THD; + break; + + case GP_STATUS_100M: + vars->line_speed = SPEED_100; + if (vars->duplex == DUPLEX_FULL) + vars->link_status |= LINK_100TXFD; + else + vars->link_status |= LINK_100TXHD; + break; + + case GP_STATUS_1G: + case GP_STATUS_1G_KX: + vars->line_speed = SPEED_1000; + if (vars->duplex == DUPLEX_FULL) + vars->link_status |= LINK_1000TFD; + else + vars->link_status |= LINK_1000THD; + break; + + case GP_STATUS_2_5G: + vars->line_speed = SPEED_2500; + if (vars->duplex == DUPLEX_FULL) + vars->link_status |= LINK_2500TFD; + else + vars->link_status |= LINK_2500THD; + break; + + case GP_STATUS_5G: + case GP_STATUS_6G: + DP(NETIF_MSG_LINK, + "link speed unsupported gp_status 0x%x\n", + gp_status); + return -EINVAL; + break; + case GP_STATUS_10G_KX4: + case GP_STATUS_10G_HIG: + case GP_STATUS_10G_CX4: + vars->line_speed = SPEED_10000; + vars->link_status |= LINK_10GTFD; + break; + + case GP_STATUS_12G_HIG: + vars->line_speed = SPEED_12000; + vars->link_status |= LINK_12GTFD; + break; + + case GP_STATUS_12_5G: + vars->line_speed = SPEED_12500; + vars->link_status |= LINK_12_5GTFD; + break; + + case GP_STATUS_13G: + vars->line_speed = SPEED_13000; + vars->link_status |= LINK_13GTFD; + break; + + case GP_STATUS_15G: + vars->line_speed = SPEED_15000; + vars->link_status |= LINK_15GTFD; + break; + + case GP_STATUS_16G: + vars->line_speed = SPEED_16000; + vars->link_status |= LINK_16GTFD; + break; + + default: + DP(NETIF_MSG_LINK, + "link speed unsupported gp_status 0x%x\n", + gp_status); + return -EINVAL; + break; + } + + vars->link_status |= LINK_STATUS_SERDES_LINK; + + if (params->req_line_speed == SPEED_AUTO_NEG) { + vars->autoneg = AUTO_NEG_ENABLED; + + if (gp_status & MDIO_AN_CL73_OR_37_COMPLETE) { + vars->autoneg |= AUTO_NEG_COMPLETE; + vars->link_status |= + LINK_STATUS_AUTO_NEGOTIATE_COMPLETE; + } + + vars->autoneg |= AUTO_NEG_PARALLEL_DETECTION_USED; + vars->link_status |= + LINK_STATUS_PARALLEL_DETECTION_USED; + + } + if (vars->flow_ctrl & FLOW_CTRL_TX) + vars->link_status |= + LINK_STATUS_TX_FLOW_CONTROL_ENABLED; + + if (vars->flow_ctrl & FLOW_CTRL_RX) + vars->link_status |= + LINK_STATUS_RX_FLOW_CONTROL_ENABLED; + + } else { /* link_down */ + DP(NETIF_MSG_LINK, "phy link down\n"); + + vars->phy_link_up = 0; + vars->line_speed = 0; + vars->duplex = DUPLEX_FULL; + vars->flow_ctrl = FLOW_CTRL_NONE; + vars->autoneg = AUTO_NEG_DISABLED; + vars->mac_type = MAC_TYPE_NONE; + } + + DP(NETIF_MSG_LINK, "gp_status 0x%x phy_link_up %x line_speed %x \n", + gp_status, vars->phy_link_up, vars->line_speed); + DP(NETIF_MSG_LINK, "duplex %x flow_ctrl 0x%x" + " autoneg 0x%x\n", + vars->duplex, + vars->flow_ctrl, vars->autoneg); + DP(NETIF_MSG_LINK, "link_status 0x%x\n", vars->link_status); + + return rc; +} + +static void bnx2x_set_sgmii_tx_driver(struct link_params *params) +{ + struct bnx2x *bp = params->bp; + u16 lp_up2; + u16 tx_driver; + + /* read precomp */ + + CL45_RD_OVER_CL22(bp, params->port, + params->phy_addr, + MDIO_REG_BANK_OVER_1G, + MDIO_OVER_1G_LP_UP2, &lp_up2); + + CL45_RD_OVER_CL22(bp, params->port, + params->phy_addr, + MDIO_REG_BANK_TX0, + MDIO_TX0_TX_DRIVER, &tx_driver); + + /* bits [10:7] at lp_up2, positioned at [15:12] */ + lp_up2 = (((lp_up2 & MDIO_OVER_1G_LP_UP2_PREEMPHASIS_MASK) >> + MDIO_OVER_1G_LP_UP2_PREEMPHASIS_SHIFT) << + MDIO_TX0_TX_DRIVER_PREEMPHASIS_SHIFT); + + if ((lp_up2 != 0) && + (lp_up2 != (tx_driver & MDIO_TX0_TX_DRIVER_PREEMPHASIS_MASK))) { + /* replace tx_driver bits [15:12] */ + tx_driver &= ~MDIO_TX0_TX_DRIVER_PREEMPHASIS_MASK; + tx_driver |= lp_up2; + CL45_WR_OVER_CL22(bp, params->port, + params->phy_addr, + MDIO_REG_BANK_TX0, + MDIO_TX0_TX_DRIVER, tx_driver); + } +} + +static u8 bnx2x_emac_program(struct link_params *params, + u32 line_speed, u32 duplex) +{ + struct bnx2x *bp = params->bp; + u8 port = params->port; + u16 mode = 0; + + DP(NETIF_MSG_LINK, "setting link speed & duplex\n"); + bnx2x_bits_dis(bp, GRCBASE_EMAC0 + port*0x400 + + EMAC_REG_EMAC_MODE, + (EMAC_MODE_25G_MODE | + EMAC_MODE_PORT_MII_10M | + EMAC_MODE_HALF_DUPLEX)); + switch (line_speed) { + case SPEED_10: + mode |= EMAC_MODE_PORT_MII_10M; + break; + + case SPEED_100: + mode |= EMAC_MODE_PORT_MII; + break; + + case SPEED_1000: + mode |= EMAC_MODE_PORT_GMII; + break; + + case SPEED_2500: + mode |= (EMAC_MODE_25G_MODE | EMAC_MODE_PORT_GMII); + break; + + default: + /* 10G not valid for EMAC */ + DP(NETIF_MSG_LINK, "Invalid line_speed 0x%x\n", line_speed); + return -EINVAL; + } + + if (duplex == DUPLEX_HALF) + mode |= EMAC_MODE_HALF_DUPLEX; + bnx2x_bits_en(bp, + GRCBASE_EMAC0 + port*0x400 + EMAC_REG_EMAC_MODE, + mode); + + bnx2x_set_led(bp, params->port, LED_MODE_OPER, + line_speed, params->hw_led_mode, params->chip_id); + return 0; +} + +/*****************************************************************************/ +/* External Phy section */ +/*****************************************************************************/ +static void bnx2x_hw_reset(struct bnx2x *bp) +{ + bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1, + MISC_REGISTERS_GPIO_OUTPUT_LOW); + msleep(1); + bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1, + MISC_REGISTERS_GPIO_OUTPUT_HIGH); +} + +static void bnx2x_ext_phy_reset(struct link_params *params, + struct link_vars *vars) +{ + struct bnx2x *bp = params->bp; + u32 ext_phy_type; + u8 ext_phy_addr = ((params->ext_phy_config & + PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >> + PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT); + DP(NETIF_MSG_LINK, "Port %x: bnx2x_ext_phy_reset\n", params->port); + ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config); + /* The PHY reset is controled by GPIO 1 + * Give it 1ms of reset pulse + */ + if (vars->phy_flags & PHY_XGXS_FLAG) { + + switch (ext_phy_type) { + case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT: + DP(NETIF_MSG_LINK, "XGXS Direct\n"); + break; + + case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705: + case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706: + DP(NETIF_MSG_LINK, "XGXS 8705/8706\n"); + + /* Restore normal power mode*/ + bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2, + MISC_REGISTERS_GPIO_OUTPUT_HIGH); + + /* HW reset */ + bnx2x_hw_reset(bp); + + bnx2x_cl45_write(bp, params->port, + ext_phy_type, + ext_phy_addr, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_CTRL, 0xa040); + break; + case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072: + /* Unset Low Power Mode and SW reset */ + /* Restore normal power mode*/ + bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2, + MISC_REGISTERS_GPIO_OUTPUT_HIGH); + + DP(NETIF_MSG_LINK, "XGXS 8072\n"); + bnx2x_cl45_write(bp, params->port, + ext_phy_type, + ext_phy_addr, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_CTRL, + 1<<15); + break; + case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073: + { + u16 emac_base; + emac_base = (params->port) ? GRCBASE_EMAC0 : + GRCBASE_EMAC1; + + /* Restore normal power mode*/ + bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2, + MISC_REGISTERS_GPIO_OUTPUT_HIGH); + + bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1, + MISC_REGISTERS_GPIO_OUTPUT_HIGH); + + DP(NETIF_MSG_LINK, "XGXS 8073\n"); + bnx2x_cl45_write(bp, + params->port, + ext_phy_type, + ext_phy_addr, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_CTRL, + 1<<15); + } + break; + + case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101: + DP(NETIF_MSG_LINK, "XGXS SFX7101\n"); + + /* Restore normal power mode*/ + bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2, + MISC_REGISTERS_GPIO_OUTPUT_HIGH); + + /* HW reset */ + bnx2x_hw_reset(bp); + + break; + + case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE: + DP(NETIF_MSG_LINK, "XGXS PHY Failure detected\n"); + break; + + default: + DP(NETIF_MSG_LINK, "BAD XGXS ext_phy_config 0x%x\n", + params->ext_phy_config); + break; + } + + } else { /* SerDes */ + ext_phy_type = SERDES_EXT_PHY_TYPE(params->ext_phy_config); + switch (ext_phy_type) { + case PORT_HW_CFG_SERDES_EXT_PHY_TYPE_DIRECT: + DP(NETIF_MSG_LINK, "SerDes Direct\n"); + break; + + case PORT_HW_CFG_SERDES_EXT_PHY_TYPE_BCM5482: + DP(NETIF_MSG_LINK, "SerDes 5482\n"); + bnx2x_hw_reset(bp); + break; + + default: + DP(NETIF_MSG_LINK, + "BAD SerDes ext_phy_config 0x%x\n", + params->ext_phy_config); + break; + } + } +} + +static void bnx2x_bcm8072_external_rom_boot(struct link_params *params) +{ + struct bnx2x *bp = params->bp; + u8 port = params->port; + u8 ext_phy_addr = ((params->ext_phy_config & + PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >> + PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT); + u32 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config); + u16 fw_ver1, fw_ver2; + + /* Need to wait 200ms after reset */ + msleep(200); + /* Boot port from external ROM + * Set ser_boot_ctl bit in the MISC_CTRL1 register + */ + bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_MISC_CTRL1, 0x0001); + + /* Reset internal microprocessor */ + bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_GEN_CTRL, + MDIO_PMA_REG_GEN_CTRL_ROM_RESET_INTERNAL_MP); + /* set micro reset = 0 */ + bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_GEN_CTRL, + MDIO_PMA_REG_GEN_CTRL_ROM_MICRO_RESET); + /* Reset internal microprocessor */ + bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_GEN_CTRL, + MDIO_PMA_REG_GEN_CTRL_ROM_RESET_INTERNAL_MP); + /* wait for 100ms for code download via SPI port */ + msleep(100); + + /* Clear ser_boot_ctl bit */ + bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_MISC_CTRL1, 0x0000); + /* Wait 100ms */ + msleep(100); + + /* Print the PHY FW version */ + bnx2x_cl45_read(bp, port, ext_phy_type, ext_phy_addr, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_ROM_VER1, &fw_ver1); + bnx2x_cl45_read(bp, port, ext_phy_type, ext_phy_addr, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_ROM_VER2, &fw_ver2); + DP(NETIF_MSG_LINK, "8072 FW version 0x%x:0x%x\n", fw_ver1, fw_ver2); +} + +static u8 bnx2x_8073_is_snr_needed(struct link_params *params) +{ + /* This is only required for 8073A1, version 102 only */ + + struct bnx2x *bp = params->bp; + u8 ext_phy_addr = ((params->ext_phy_config & + PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >> + PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT); + u16 val; + + /* Read 8073 HW revision*/ + bnx2x_cl45_read(bp, params->port, + PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073, + ext_phy_addr, + MDIO_PMA_DEVAD, + 0xc801, &val); + + if (val != 1) { + /* No need to workaround in 8073 A1 */ + return 0; + } + + bnx2x_cl45_read(bp, params->port, + PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073, + ext_phy_addr, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_ROM_VER2, &val); + + /* SNR should be applied only for version 0x102 */ + if (val != 0x102) + return 0; + + return 1; +} + +static u8 bnx2x_bcm8073_xaui_wa(struct link_params *params) +{ + struct bnx2x *bp = params->bp; + u8 ext_phy_addr = ((params->ext_phy_config & + PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >> + PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT); + u16 val, cnt, cnt1 ; + + bnx2x_cl45_read(bp, params->port, + PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073, + ext_phy_addr, + MDIO_PMA_DEVAD, + 0xc801, &val); + + if (val > 0) { + /* No need to workaround in 8073 A1 */ + return 0; + } + /* XAUI workaround in 8073 A0: */ + + /* After loading the boot ROM and restarting Autoneg, + poll Dev1, Reg $C820: */ + + for (cnt = 0; cnt < 1000; cnt++) { + bnx2x_cl45_read(bp, params->port, + PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073, + ext_phy_addr, + MDIO_PMA_DEVAD, + 0xc820, &val); + /* If bit [14] = 0 or bit [13] = 0, continue on with + system initialization (XAUI work-around not required, + as these bits indicate 2.5G or 1G link up). */ + if (!(val & (1<<14)) || !(val & (1<<13))) { + DP(NETIF_MSG_LINK, "XAUI work-around not required\n"); + return 0; + } else if (!(val & (1<<15))) { + DP(NETIF_MSG_LINK, "clc bit 15 went off\n"); + /* If bit 15 is 0, then poll Dev1, Reg $C841 until + it's MSB (bit 15) goes to 1 (indicating that the + XAUI workaround has completed), + then continue on with system initialization.*/ + for (cnt1 = 0; cnt1 < 1000; cnt1++) { + bnx2x_cl45_read(bp, params->port, + PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073, + ext_phy_addr, + MDIO_PMA_DEVAD, + 0xc841, &val); + if (val & (1<<15)) { + DP(NETIF_MSG_LINK, + "XAUI workaround has completed\n"); + return 0; + } + msleep(3); + } + break; + } + msleep(3); + } + DP(NETIF_MSG_LINK, "Warning: XAUI work-around timeout !!!\n"); + return -EINVAL; + +} + +static void bnx2x_bcm8073_external_rom_boot(struct link_params *params) +{ + struct bnx2x *bp = params->bp; + u8 port = params->port; + u8 ext_phy_addr = ((params->ext_phy_config & + PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >> + PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT); + u32 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config); + u16 fw_ver1, fw_ver2, val; + /* Need to wait 100ms after reset */ + msleep(100); + /* Boot port from external ROM */ + /* EDC grst */ + bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_GEN_CTRL, + 0x0001); + + /* ucode reboot and rst */ + bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_GEN_CTRL, + 0x008c); + + bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_MISC_CTRL1, 0x0001); + + /* Reset internal microprocessor */ + bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_GEN_CTRL, + MDIO_PMA_REG_GEN_CTRL_ROM_MICRO_RESET); + + /* Release srst bit */ + bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_GEN_CTRL, + MDIO_PMA_REG_GEN_CTRL_ROM_RESET_INTERNAL_MP); + + /* wait for 100ms for code download via SPI port */ + msleep(100); + + /* Clear ser_boot_ctl bit */ + bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_MISC_CTRL1, 0x0000); + + bnx2x_cl45_read(bp, port, ext_phy_type, ext_phy_addr, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_ROM_VER1, &fw_ver1); + bnx2x_cl45_read(bp, port, ext_phy_type, ext_phy_addr, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_ROM_VER2, &fw_ver2); + DP(NETIF_MSG_LINK, "8073 FW version 0x%x:0x%x\n", fw_ver1, fw_ver2); + + /* Only set bit 10 = 1 (Tx power down) */ + bnx2x_cl45_read(bp, port, ext_phy_type, ext_phy_addr, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_TX_POWER_DOWN, &val); + + bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_TX_POWER_DOWN, (val | 1<<10)); + + msleep(600); + /* Release bit 10 (Release Tx power down) */ + bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_TX_POWER_DOWN, (val & (~(1<<10)))); + +} + +static void bnx2x_bcm8073_set_xaui_low_power_mode(struct link_params *params) +{ + struct bnx2x *bp = params->bp; + u8 port = params->port; + u16 val; + u8 ext_phy_addr = ((params->ext_phy_config & + PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >> + PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT); + u32 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config); + + bnx2x_cl45_read(bp, params->port, + PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073, + ext_phy_addr, + MDIO_PMA_DEVAD, + 0xc801, &val); + + if (val == 0) { + /* Mustn't set low power mode in 8073 A0 */ + return; + } + + /* Disable PLL sequencer (use read-modify-write to clear bit 13) */ + bnx2x_cl45_read(bp, port, ext_phy_type, ext_phy_addr, + MDIO_XS_DEVAD, + MDIO_XS_PLL_SEQUENCER, &val); + val &= ~(1<<13); + bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr, + MDIO_XS_DEVAD, MDIO_XS_PLL_SEQUENCER, val); + + /* PLL controls */ + bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr, + MDIO_XS_DEVAD, 0x805E, 0x1077); + bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr, + MDIO_XS_DEVAD, 0x805D, 0x0000); + bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr, + MDIO_XS_DEVAD, 0x805C, 0x030B); + bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr, + MDIO_XS_DEVAD, 0x805B, 0x1240); + bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr, + MDIO_XS_DEVAD, 0x805A, 0x2490); + + /* Tx Controls */ + bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr, + MDIO_XS_DEVAD, 0x80A7, 0x0C74); + bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr, + MDIO_XS_DEVAD, 0x80A6, 0x9041); + bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr, + MDIO_XS_DEVAD, 0x80A5, 0x4640); + + /* Rx Controls */ + bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr, + MDIO_XS_DEVAD, 0x80FE, 0x01C4); + bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr, + MDIO_XS_DEVAD, 0x80FD, 0x9249); + bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr, + MDIO_XS_DEVAD, 0x80FC, 0x2015); + + /* Enable PLL sequencer (use read-modify-write to set bit 13) */ + bnx2x_cl45_read(bp, port, ext_phy_type, ext_phy_addr, + MDIO_XS_DEVAD, + MDIO_XS_PLL_SEQUENCER, &val); + val |= (1<<13); + bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr, + MDIO_XS_DEVAD, MDIO_XS_PLL_SEQUENCER, val); +} +static void bnx2x_bcm807x_force_10G(struct link_params *params) +{ + struct bnx2x *bp = params->bp; + u8 port = params->port; + u8 ext_phy_addr = ((params->ext_phy_config & + PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >> + PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT); + u32 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config); + + /* Force KR or KX */ + bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_CTRL, + 0x2040); + bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_10G_CTRL2, + 0x000b); + bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_BCM_CTRL, + 0x0000); + bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr, + MDIO_AN_DEVAD, + MDIO_AN_REG_CTRL, + 0x0000); +} + +static void bnx2x_ext_phy_set_pause(struct link_params *params, + struct link_vars *vars) +{ + struct bnx2x *bp = params->bp; + u16 val; + u8 ext_phy_addr = ((params->ext_phy_config & + PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >> + PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT); + u32 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config); + + /* read modify write pause advertizing */ + bnx2x_cl45_read(bp, params->port, + ext_phy_type, + ext_phy_addr, + MDIO_AN_DEVAD, + MDIO_AN_REG_ADV_PAUSE, &val); + + val &= ~MDIO_AN_REG_ADV_PAUSE_BOTH; + /* Please refer to Table 28B-3 of 802.3ab-1999 spec. */ + + if (vars->ieee_fc & + MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC) { + val |= MDIO_AN_REG_ADV_PAUSE_ASYMMETRIC; + } + if (vars->ieee_fc & + MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH) { + val |= + MDIO_AN_REG_ADV_PAUSE_PAUSE; + } + DP(NETIF_MSG_LINK, + "Ext phy AN advertize 0x%x\n", val); + bnx2x_cl45_write(bp, params->port, + ext_phy_type, + ext_phy_addr, + MDIO_AN_DEVAD, + MDIO_AN_REG_ADV_PAUSE, val); +} + +static u8 bnx2x_ext_phy_init(struct link_params *params, struct link_vars *vars) +{ + struct bnx2x *bp = params->bp; + u32 ext_phy_type; + u8 ext_phy_addr; + u16 cnt; + u16 ctrl = 0; + u16 val = 0; + u8 rc = 0; + if (vars->phy_flags & PHY_XGXS_FLAG) { + ext_phy_addr = ((params->ext_phy_config & + PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >> + PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT); + + ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config); + /* Make sure that the soft reset is off (expect for the 8072: + * due to the lock, it will be done inside the specific + * handling) + */ + if ((ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT) && + (ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE) && + (ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_NOT_CONN) && + (ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072) && + (ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073)) { + /* Wait for soft reset to get cleared upto 1 sec */ + for (cnt = 0; cnt < 1000; cnt++) { + bnx2x_cl45_read(bp, params->port, + ext_phy_type, + ext_phy_addr, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_CTRL, &ctrl); + if (!(ctrl & (1<<15))) + break; + msleep(1); + } + DP(NETIF_MSG_LINK, "control reg 0x%x (after %d ms)\n", + ctrl, cnt); + } + + switch (ext_phy_type) { + case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT: + DP(NETIF_MSG_LINK, "XGXS Direct\n"); + break; + + case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705: + DP(NETIF_MSG_LINK, "XGXS 8705\n"); + + bnx2x_cl45_write(bp, params->port, + ext_phy_type, + ext_phy_addr, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_MISC_CTRL, + 0x8288); + bnx2x_cl45_write(bp, params->port, + ext_phy_type, + ext_phy_addr, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_PHY_IDENTIFIER, + 0x7fbf); + bnx2x_cl45_write(bp, params->port, + ext_phy_type, + ext_phy_addr, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_CMU_PLL_BYPASS, + 0x0100); + bnx2x_cl45_write(bp, params->port, + ext_phy_type, + ext_phy_addr, + MDIO_WIS_DEVAD, + MDIO_WIS_REG_LASI_CNTL, 0x1); + break; + + case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706: + DP(NETIF_MSG_LINK, "XGXS 8706\n"); + + msleep(10); + /* Force speed */ + /* First enable LASI */ + bnx2x_cl45_write(bp, params->port, + ext_phy_type, + ext_phy_addr, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_RX_ALARM_CTRL, + 0x0400); + bnx2x_cl45_write(bp, params->port, + ext_phy_type, + ext_phy_addr, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_LASI_CTRL, 0x0004); + + if (params->req_line_speed == SPEED_10000) { + DP(NETIF_MSG_LINK, "XGXS 8706 force 10Gbps\n"); + + bnx2x_cl45_write(bp, params->port, + ext_phy_type, + ext_phy_addr, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_DIGITAL_CTRL, + 0x400); + } else { + /* Force 1Gbps using autoneg with 1G + advertisment */ + + /* Allow CL37 through CL73 */ + DP(NETIF_MSG_LINK, "XGXS 8706 AutoNeg\n"); + bnx2x_cl45_write(bp, params->port, + ext_phy_type, + ext_phy_addr, + MDIO_AN_DEVAD, + MDIO_AN_REG_CL37_CL73, + 0x040c); + + /* Enable Full-Duplex advertisment on CL37 */ + bnx2x_cl45_write(bp, params->port, + ext_phy_type, + ext_phy_addr, + MDIO_AN_DEVAD, + MDIO_AN_REG_CL37_FD, + 0x0020); + /* Enable CL37 AN */ + bnx2x_cl45_write(bp, params->port, + ext_phy_type, + ext_phy_addr, + MDIO_AN_DEVAD, + MDIO_AN_REG_CL37_AN, + 0x1000); + /* 1G support */ + bnx2x_cl45_write(bp, params->port, + ext_phy_type, + ext_phy_addr, + MDIO_AN_DEVAD, + MDIO_AN_REG_ADV, (1<<5)); + + /* Enable clause 73 AN */ + bnx2x_cl45_write(bp, params->port, + ext_phy_type, + ext_phy_addr, + MDIO_AN_DEVAD, + MDIO_AN_REG_CTRL, + 0x1200); + + } + + break; + + case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072: + case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073: + { + u16 tmp1; + u16 rx_alarm_ctrl_val; + u16 lasi_ctrl_val; + if (ext_phy_type == + PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072) { + rx_alarm_ctrl_val = 0x400; + lasi_ctrl_val = 0x0004; + } else { + /* In 8073, port1 is directed through emac0 and + * port0 is directed through emac1 + */ + rx_alarm_ctrl_val = (1<<2); + /*lasi_ctrl_val = 0x0005;*/ + lasi_ctrl_val = 0x0004; + } + + /* Wait for soft reset to get cleared upto 1 sec */ + for (cnt = 0; cnt < 1000; cnt++) { + bnx2x_cl45_read(bp, params->port, + ext_phy_type, + ext_phy_addr, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_CTRL, + &ctrl); + if (!(ctrl & (1<<15))) + break; + msleep(1); + } + DP(NETIF_MSG_LINK, + "807x control reg 0x%x (after %d ms)\n", + ctrl, cnt); + + if (ext_phy_type == + PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072){ + bnx2x_bcm8072_external_rom_boot(params); + } else { + bnx2x_bcm8073_external_rom_boot(params); + /* In case of 8073 with long xaui lines, + don't set the 8073 xaui low power*/ + bnx2x_bcm8073_set_xaui_low_power_mode(params); + } + + /* enable LASI */ + bnx2x_cl45_write(bp, params->port, + ext_phy_type, + ext_phy_addr, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_RX_ALARM_CTRL, + rx_alarm_ctrl_val); + + bnx2x_cl45_write(bp, params->port, + ext_phy_type, + ext_phy_addr, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_LASI_CTRL, + lasi_ctrl_val); + + bnx2x_cl45_read(bp, params->port, + ext_phy_type, + ext_phy_addr, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_RX_ALARM, &tmp1); + + DP(NETIF_MSG_LINK, "Before rom RX_ALARM(port1):" + "0x%x\n", tmp1); + + /* If this is forced speed, set to KR or KX + * (all other are not supported) + */ + if (!(params->req_line_speed == SPEED_AUTO_NEG)) { + if (params->req_line_speed == SPEED_10000) { + bnx2x_bcm807x_force_10G(params); + DP(NETIF_MSG_LINK, + "Forced speed 10G on 807X\n"); + break; + } else if (params->req_line_speed == + SPEED_2500) { + val = (1<<5); + /* Note that 2.5G works only + when used with 1G advertisment */ + } else + val = (1<<5); + } else { + + val = 0; + if (params->speed_cap_mask & + PORT_HW_CFG_SPEED_CAPABILITY_D0_10G) + val |= (1<<7); + + if (params->speed_cap_mask & + PORT_HW_CFG_SPEED_CAPABILITY_D0_1G) + val |= (1<<5); + DP(NETIF_MSG_LINK, "807x autoneg val = 0x%x\n", val); + /*val = ((1<<5)|(1<<7));*/ + } + + bnx2x_cl45_write(bp, params->port, + ext_phy_type, + ext_phy_addr, + MDIO_AN_DEVAD, + MDIO_AN_REG_ADV, val); + + if (ext_phy_type == + PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073) { + /* Disable 2.5Ghz */ + bnx2x_cl45_read(bp, params->port, + ext_phy_type, + ext_phy_addr, + MDIO_AN_DEVAD, + 0x8329, &tmp1); +/* SUPPORT_SPEED_CAPABILITY + (Due to the nature of the link order, its not + possible to enable 2.5G within the autoneg + capabilities) + if (params->speed_cap_mask & + PORT_HW_CFG_SPEED_CAPABILITY_D0_2_5G) +*/ + if (params->req_line_speed == SPEED_2500) { + u16 phy_ver; + /* Allow 2.5G for A1 and above */ + bnx2x_cl45_read(bp, params->port, + PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073, + ext_phy_addr, + MDIO_PMA_DEVAD, + 0xc801, &phy_ver); + + if (phy_ver > 0) + tmp1 |= 1; + else + tmp1 &= 0xfffe; + } + else + tmp1 &= 0xfffe; + + bnx2x_cl45_write(bp, params->port, + ext_phy_type, + ext_phy_addr, + MDIO_AN_DEVAD, + 0x8329, tmp1); + } + /* Add support for CL37 (passive mode) I */ + bnx2x_cl45_write(bp, params->port, + ext_phy_type, + ext_phy_addr, + MDIO_AN_DEVAD, + MDIO_AN_REG_CL37_CL73, 0x040c); + /* Add support for CL37 (passive mode) II */ + bnx2x_cl45_write(bp, params->port, + ext_phy_type, + ext_phy_addr, + MDIO_AN_DEVAD, + MDIO_AN_REG_CL37_FD, 0x20); + /* Add support for CL37 (passive mode) III */ + bnx2x_cl45_write(bp, params->port, + ext_phy_type, + ext_phy_addr, + MDIO_AN_DEVAD, + MDIO_AN_REG_CL37_AN, 0x1000); + /* Restart autoneg */ + msleep(500); + + if (ext_phy_type == + PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073) { + + /* The SNR will improve about 2db by changing the + BW and FEE main tap. Rest commands are executed + after link is up*/ + /* Change FFE main cursor to 5 in EDC register */ + if (bnx2x_8073_is_snr_needed(params)) + bnx2x_cl45_write(bp, params->port, + ext_phy_type, + ext_phy_addr, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_EDC_FFE_MAIN, + 0xFB0C); + + /* Enable FEC (Forware Error Correction) + Request in the AN */ + bnx2x_cl45_read(bp, params->port, + ext_phy_type, + ext_phy_addr, + MDIO_AN_DEVAD, + MDIO_AN_REG_ADV2, &tmp1); + + tmp1 |= (1<<15); + + bnx2x_cl45_write(bp, params->port, + ext_phy_type, + ext_phy_addr, + MDIO_AN_DEVAD, + MDIO_AN_REG_ADV2, tmp1); + } + + bnx2x_ext_phy_set_pause(params, vars); + + bnx2x_cl45_write(bp, params->port, + ext_phy_type, + ext_phy_addr, + MDIO_AN_DEVAD, + MDIO_AN_REG_CTRL, 0x1200); + DP(NETIF_MSG_LINK, "807x Autoneg Restart: " + "Advertise 1G=%x, 10G=%x\n", + ((val & (1<<5)) > 0), + ((val & (1<<7)) > 0)); + break; + } + case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101: + DP(NETIF_MSG_LINK, + "Setting the SFX7101 LASI indication\n"); + + bnx2x_cl45_write(bp, params->port, + ext_phy_type, + ext_phy_addr, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_LASI_CTRL, 0x1); + DP(NETIF_MSG_LINK, + "Setting the SFX7101 LED to blink on traffic\n"); + bnx2x_cl45_write(bp, params->port, + ext_phy_type, + ext_phy_addr, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_7107_LED_CNTL, (1<<3)); + + bnx2x_ext_phy_set_pause(params, vars); + /* Restart autoneg */ + bnx2x_cl45_read(bp, params->port, + ext_phy_type, + ext_phy_addr, + MDIO_AN_DEVAD, + MDIO_AN_REG_CTRL, &val); + val |= 0x200; + bnx2x_cl45_write(bp, params->port, + ext_phy_type, + ext_phy_addr, + MDIO_AN_DEVAD, + MDIO_AN_REG_CTRL, val); + break; + case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE: + DP(NETIF_MSG_LINK, + "XGXS PHY Failure detected 0x%x\n", + params->ext_phy_config); + rc = -EINVAL; + break; + default: + DP(NETIF_MSG_LINK, "BAD XGXS ext_phy_config 0x%x\n", + params->ext_phy_config); + rc = -EINVAL; + break; + } + + } else { /* SerDes */ +/* ext_phy_addr = ((bp->ext_phy_config & + PORT_HW_CFG_SERDES_EXT_PHY_ADDR_MASK) >> + PORT_HW_CFG_SERDES_EXT_PHY_ADDR_SHIFT); +*/ + ext_phy_type = SERDES_EXT_PHY_TYPE(params->ext_phy_config); + switch (ext_phy_type) { + case PORT_HW_CFG_SERDES_EXT_PHY_TYPE_DIRECT: + DP(NETIF_MSG_LINK, "SerDes Direct\n"); + break; + + case PORT_HW_CFG_SERDES_EXT_PHY_TYPE_BCM5482: + DP(NETIF_MSG_LINK, "SerDes 5482\n"); + break; + + default: + DP(NETIF_MSG_LINK, "BAD SerDes ext_phy_config 0x%x\n", + params->ext_phy_config); + break; + } + } + return rc; +} + + +static u8 bnx2x_ext_phy_is_link_up(struct link_params *params, + struct link_vars *vars) +{ + struct bnx2x *bp = params->bp; + u32 ext_phy_type; + u8 ext_phy_addr; + u16 val1 = 0, val2; + u16 rx_sd, pcs_status; + u8 ext_phy_link_up = 0; + u8 port = params->port; + if (vars->phy_flags & PHY_XGXS_FLAG) { + ext_phy_addr = ((params->ext_phy_config & + PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >> + PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT); + + ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config); + switch (ext_phy_type) { + case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT: + DP(NETIF_MSG_LINK, "XGXS Direct\n"); + ext_phy_link_up = 1; + break; + + case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705: + DP(NETIF_MSG_LINK, "XGXS 8705\n"); + bnx2x_cl45_read(bp, params->port, ext_phy_type, + ext_phy_addr, + MDIO_WIS_DEVAD, + MDIO_WIS_REG_LASI_STATUS, &val1); + DP(NETIF_MSG_LINK, "8705 LASI status 0x%x\n", val1); + + bnx2x_cl45_read(bp, params->port, ext_phy_type, + ext_phy_addr, + MDIO_WIS_DEVAD, + MDIO_WIS_REG_LASI_STATUS, &val1); + DP(NETIF_MSG_LINK, "8705 LASI status 0x%x\n", val1); + + bnx2x_cl45_read(bp, params->port, ext_phy_type, + ext_phy_addr, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_RX_SD, &rx_sd); + DP(NETIF_MSG_LINK, "8705 rx_sd 0x%x\n", rx_sd); + ext_phy_link_up = (rx_sd & 0x1); + break; + + case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706: + DP(NETIF_MSG_LINK, "XGXS 8706\n"); + bnx2x_cl45_read(bp, params->port, ext_phy_type, + ext_phy_addr, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_LASI_STATUS, &val1); + DP(NETIF_MSG_LINK, "8706 LASI status 0x%x\n", val1); + + bnx2x_cl45_read(bp, params->port, ext_phy_type, + ext_phy_addr, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_LASI_STATUS, &val1); + DP(NETIF_MSG_LINK, "8706 LASI status 0x%x\n", val1); + + bnx2x_cl45_read(bp, params->port, ext_phy_type, + ext_phy_addr, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_RX_SD, &rx_sd); + bnx2x_cl45_read(bp, params->port, ext_phy_type, + ext_phy_addr, + MDIO_PCS_DEVAD, + MDIO_PCS_REG_STATUS, &pcs_status); + + bnx2x_cl45_read(bp, params->port, ext_phy_type, + ext_phy_addr, + MDIO_AN_DEVAD, + MDIO_AN_REG_LINK_STATUS, &val2); + bnx2x_cl45_read(bp, params->port, ext_phy_type, + ext_phy_addr, + MDIO_AN_DEVAD, + MDIO_AN_REG_LINK_STATUS, &val2); + + DP(NETIF_MSG_LINK, "8706 rx_sd 0x%x" + " pcs_status 0x%x 1Gbps link_status 0x%x\n", + rx_sd, pcs_status, val2); + /* link is up if both bit 0 of pmd_rx_sd and + * bit 0 of pcs_status are set, or if the autoneg bit + 1 is set + */ + ext_phy_link_up = ((rx_sd & pcs_status & 0x1) || + (val2 & (1<<1))); + /* clear LASI indication*/ + bnx2x_cl45_read(bp, params->port, ext_phy_type, + ext_phy_addr, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_RX_ALARM, &val2); + break; + + case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072: + case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073: + { + if (ext_phy_type == + PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072) { + bnx2x_cl45_read(bp, params->port, + ext_phy_type, + ext_phy_addr, + MDIO_PCS_DEVAD, + MDIO_PCS_REG_LASI_STATUS, &val1); + bnx2x_cl45_read(bp, params->port, + ext_phy_type, + ext_phy_addr, + MDIO_PCS_DEVAD, + MDIO_PCS_REG_LASI_STATUS, &val2); + DP(NETIF_MSG_LINK, + "870x LASI status 0x%x->0x%x\n", + val1, val2); + + } else { + /* In 8073, port1 is directed through emac0 and + * port0 is directed through emac1 + */ + bnx2x_cl45_read(bp, params->port, + ext_phy_type, + ext_phy_addr, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_LASI_STATUS, &val1); + + bnx2x_cl45_read(bp, params->port, + ext_phy_type, + ext_phy_addr, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_LASI_STATUS, &val2); + DP(NETIF_MSG_LINK, + "8703 LASI status 0x%x->0x%x\n", + val1, val2); + } + + /* clear the interrupt LASI status register */ + bnx2x_cl45_read(bp, params->port, + ext_phy_type, + ext_phy_addr, + MDIO_PCS_DEVAD, + MDIO_PCS_REG_STATUS, &val2); + bnx2x_cl45_read(bp, params->port, + ext_phy_type, + ext_phy_addr, + MDIO_PCS_DEVAD, + MDIO_PCS_REG_STATUS, &val1); + DP(NETIF_MSG_LINK, "807x PCS status 0x%x->0x%x\n", + val2, val1); + /* Check the LASI */ + bnx2x_cl45_read(bp, params->port, + ext_phy_type, + ext_phy_addr, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_RX_ALARM, &val2); + bnx2x_cl45_read(bp, params->port, + ext_phy_type, + ext_phy_addr, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_RX_ALARM, + &val1); + DP(NETIF_MSG_LINK, "KR 0x9003 0x%x->0x%x\n", + val2, val1); + /* Check the link status */ + bnx2x_cl45_read(bp, params->port, + ext_phy_type, + ext_phy_addr, + MDIO_PCS_DEVAD, + MDIO_PCS_REG_STATUS, &val2); + DP(NETIF_MSG_LINK, "KR PCS status 0x%x\n", val2); + + bnx2x_cl45_read(bp, params->port, + ext_phy_type, + ext_phy_addr, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_STATUS, &val2); + bnx2x_cl45_read(bp, params->port, + ext_phy_type, + ext_phy_addr, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_STATUS, &val1); + ext_phy_link_up = ((val1 & 4) == 4); + DP(NETIF_MSG_LINK, "PMA_REG_STATUS=0x%x\n", val1); + if (ext_phy_type == + PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073) { + u16 an1000_status = 0; + if (ext_phy_link_up && + ( + (params->req_line_speed != SPEED_10000) + )) { + if (bnx2x_bcm8073_xaui_wa(params) + != 0) { + ext_phy_link_up = 0; + break; + } + bnx2x_cl45_read(bp, params->port, + ext_phy_type, + ext_phy_addr, + MDIO_XS_DEVAD, + 0x8304, + &an1000_status); + bnx2x_cl45_read(bp, params->port, + ext_phy_type, + ext_phy_addr, + MDIO_XS_DEVAD, + 0x8304, + &an1000_status); + } + /* Check the link status on 1.1.2 */ + bnx2x_cl45_read(bp, params->port, + ext_phy_type, + ext_phy_addr, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_STATUS, &val2); + bnx2x_cl45_read(bp, params->port, + ext_phy_type, + ext_phy_addr, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_STATUS, &val1); + DP(NETIF_MSG_LINK, "KR PMA status 0x%x->0x%x," + "an_link_status=0x%x\n", + val2, val1, an1000_status); + + ext_phy_link_up = (((val1 & 4) == 4) || + (an1000_status & (1<<1))); + if (ext_phy_link_up && + bnx2x_8073_is_snr_needed(params)) { + /* The SNR will improve about 2dbby + changing the BW and FEE main tap.*/ + + /* The 1st write to change FFE main + tap is set before restart AN */ + /* Change PLL Bandwidth in EDC + register */ + bnx2x_cl45_write(bp, port, ext_phy_type, + ext_phy_addr, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_PLL_BANDWIDTH, + 0x26BC); + + /* Change CDR Bandwidth in EDC + register */ + bnx2x_cl45_write(bp, port, ext_phy_type, + ext_phy_addr, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_CDR_BANDWIDTH, + 0x0333); + + } + } + break; + } + case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101: + bnx2x_cl45_read(bp, params->port, ext_phy_type, + ext_phy_addr, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_LASI_STATUS, &val2); + bnx2x_cl45_read(bp, params->port, ext_phy_type, + ext_phy_addr, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_LASI_STATUS, &val1); + DP(NETIF_MSG_LINK, + "10G-base-T LASI status 0x%x->0x%x\n", + val2, val1); + bnx2x_cl45_read(bp, params->port, ext_phy_type, + ext_phy_addr, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_STATUS, &val2); + bnx2x_cl45_read(bp, params->port, ext_phy_type, + ext_phy_addr, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_STATUS, &val1); + DP(NETIF_MSG_LINK, + "10G-base-T PMA status 0x%x->0x%x\n", + val2, val1); + ext_phy_link_up = ((val1 & 4) == 4); + /* if link is up + * print the AN outcome of the SFX7101 PHY + */ + if (ext_phy_link_up) { + bnx2x_cl45_read(bp, params->port, + ext_phy_type, + ext_phy_addr, + MDIO_AN_DEVAD, + MDIO_AN_REG_MASTER_STATUS, + &val2); + DP(NETIF_MSG_LINK, + "SFX7101 AN status 0x%x->Master=%x\n", + val2, + (val2 & (1<<14))); + } + break; + + default: + DP(NETIF_MSG_LINK, "BAD XGXS ext_phy_config 0x%x\n", + params->ext_phy_config); + ext_phy_link_up = 0; + break; + } + + } else { /* SerDes */ + ext_phy_type = SERDES_EXT_PHY_TYPE(params->ext_phy_config); + switch (ext_phy_type) { + case PORT_HW_CFG_SERDES_EXT_PHY_TYPE_DIRECT: + DP(NETIF_MSG_LINK, "SerDes Direct\n"); + ext_phy_link_up = 1; + break; + + case PORT_HW_CFG_SERDES_EXT_PHY_TYPE_BCM5482: + DP(NETIF_MSG_LINK, "SerDes 5482\n"); + ext_phy_link_up = 1; + break; + + default: + DP(NETIF_MSG_LINK, + "BAD SerDes ext_phy_config 0x%x\n", + params->ext_phy_config); + ext_phy_link_up = 0; + break; + } + } + + return ext_phy_link_up; +} + +static void bnx2x_link_int_enable(struct link_params *params) +{ + u8 port = params->port; + u32 ext_phy_type; + u32 mask; + struct bnx2x *bp = params->bp; + /* setting the status to report on link up + for either XGXS or SerDes */ + + if (params->switch_cfg == SWITCH_CFG_10G) { + mask = (NIG_MASK_XGXS0_LINK10G | + NIG_MASK_XGXS0_LINK_STATUS); + DP(NETIF_MSG_LINK, "enabled XGXS interrupt\n"); + ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config); + if ((ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT) && + (ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE) && + (ext_phy_type != + PORT_HW_CFG_XGXS_EXT_PHY_TYPE_NOT_CONN)) { + mask |= NIG_MASK_MI_INT; + DP(NETIF_MSG_LINK, "enabled external phy int\n"); + } + + } else { /* SerDes */ + mask = NIG_MASK_SERDES0_LINK_STATUS; + DP(NETIF_MSG_LINK, "enabled SerDes interrupt\n"); + ext_phy_type = SERDES_EXT_PHY_TYPE(params->ext_phy_config); + if ((ext_phy_type != + PORT_HW_CFG_SERDES_EXT_PHY_TYPE_DIRECT) && + (ext_phy_type != + PORT_HW_CFG_SERDES_EXT_PHY_TYPE_NOT_CONN)) { + mask |= NIG_MASK_MI_INT; + DP(NETIF_MSG_LINK, "enabled external phy int\n"); + } + } + bnx2x_bits_en(bp, + NIG_REG_MASK_INTERRUPT_PORT0 + port*4, + mask); + DP(NETIF_MSG_LINK, "port %x, is_xgxs=%x, int_status 0x%x\n", port, + (params->switch_cfg == SWITCH_CFG_10G), + REG_RD(bp, NIG_REG_STATUS_INTERRUPT_PORT0 + port*4)); + + DP(NETIF_MSG_LINK, " int_mask 0x%x, MI_INT %x, SERDES_LINK %x\n", + REG_RD(bp, NIG_REG_MASK_INTERRUPT_PORT0 + port*4), + REG_RD(bp, NIG_REG_EMAC0_STATUS_MISC_MI_INT + port*0x18), + REG_RD(bp, NIG_REG_SERDES0_STATUS_LINK_STATUS+port*0x3c)); + DP(NETIF_MSG_LINK, " 10G %x, XGXS_LINK %x\n", + REG_RD(bp, NIG_REG_XGXS0_STATUS_LINK10G + port*0x68), + REG_RD(bp, NIG_REG_XGXS0_STATUS_LINK_STATUS + port*0x68)); +} + + +/* + * link management + */ +static void bnx2x_link_int_ack(struct link_params *params, + struct link_vars *vars, u16 is_10g) +{ + struct bnx2x *bp = params->bp; + u8 port = params->port; + + /* first reset all status + * we assume only one line will be change at a time */ + bnx2x_bits_dis(bp, NIG_REG_STATUS_INTERRUPT_PORT0 + port*4, + (NIG_STATUS_XGXS0_LINK10G | + NIG_STATUS_XGXS0_LINK_STATUS | + NIG_STATUS_SERDES0_LINK_STATUS)); + if (vars->phy_link_up) { + if (is_10g) { + /* Disable the 10G link interrupt + * by writing 1 to the status register + */ + DP(NETIF_MSG_LINK, "10G XGXS phy link up\n"); + bnx2x_bits_en(bp, + NIG_REG_STATUS_INTERRUPT_PORT0 + port*4, + NIG_STATUS_XGXS0_LINK10G); + + } else if (params->switch_cfg == SWITCH_CFG_10G) { + /* Disable the link interrupt + * by writing 1 to the relevant lane + * in the status register + */ + u32 ser_lane = ((params->lane_config & + PORT_HW_CFG_LANE_SWAP_CFG_MASTER_MASK) >> + PORT_HW_CFG_LANE_SWAP_CFG_MASTER_SHIFT); + + DP(NETIF_MSG_LINK, "1G XGXS phy link up\n"); + bnx2x_bits_en(bp, + NIG_REG_STATUS_INTERRUPT_PORT0 + port*4, + ((1 << ser_lane) << + NIG_STATUS_XGXS0_LINK_STATUS_SIZE)); + + } else { /* SerDes */ + DP(NETIF_MSG_LINK, "SerDes phy link up\n"); + /* Disable the link interrupt + * by writing 1 to the status register + */ + bnx2x_bits_en(bp, + NIG_REG_STATUS_INTERRUPT_PORT0 + port*4, + NIG_STATUS_SERDES0_LINK_STATUS); + } + + } else { /* link_down */ + } +} + +static u8 bnx2x_format_ver(u32 num, u8 *str, u16 len) +{ + u8 *str_ptr = str; + u32 mask = 0xf0000000; + u8 shift = 8*4; + u8 digit; + if (len < 10) { + /* Need more then 10chars for this format */ + *str_ptr = '\0'; + return -EINVAL; + } + while (shift > 0) { + + shift -= 4; + digit = ((num & mask) >> shift); + if (digit < 0xa) + *str_ptr = digit + '0'; + else + *str_ptr = digit - 0xa + 'a'; + str_ptr++; + mask = mask >> 4; + if (shift == 4*4) { + *str_ptr = ':'; + str_ptr++; + } + } + *str_ptr = '\0'; + return 0; +} + + +static void bnx2x_turn_on_sf(struct bnx2x *bp, u8 port, u8 ext_phy_addr) +{ + u32 cnt = 0; + u16 ctrl = 0; + /* Enable EMAC0 in to enable MDIO */ + REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_SET, + (MISC_REGISTERS_RESET_REG_2_RST_EMAC0_HARD_CORE << port)); + msleep(5); + + /* take ext phy out of reset */ + bnx2x_set_gpio(bp, + MISC_REGISTERS_GPIO_2, + MISC_REGISTERS_GPIO_HIGH); + + bnx2x_set_gpio(bp, + MISC_REGISTERS_GPIO_1, + MISC_REGISTERS_GPIO_HIGH); + + /* wait for 5ms */ + msleep(5); + + for (cnt = 0; cnt < 1000; cnt++) { + msleep(1); + bnx2x_cl45_read(bp, port, + PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101, + ext_phy_addr, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_CTRL, + &ctrl); + if (!(ctrl & (1<<15))) { + DP(NETIF_MSG_LINK, "Reset completed\n\n"); + break; + } + } +} + +static void bnx2x_turn_off_sf(struct bnx2x *bp) +{ + /* put sf to reset */ + bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1, MISC_REGISTERS_GPIO_LOW); + bnx2x_set_gpio(bp, + MISC_REGISTERS_GPIO_2, + MISC_REGISTERS_GPIO_LOW); +} + +u8 bnx2x_get_ext_phy_fw_version(struct link_params *params, u8 driver_loaded, + u8 *version, u16 len) +{ + struct bnx2x *bp = params->bp; + u32 ext_phy_type = 0; + u16 val = 0; + u8 ext_phy_addr = 0 ; + u8 status = 0 ; + u32 ver_num; + + if (version == NULL || params == NULL) + return -EINVAL; + + /* reset the returned value to zero */ + ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config); + ext_phy_addr = ((params->ext_phy_config & + PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >> + PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT); + + switch (ext_phy_type) { + case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101: + + if (len < 5) + return -EINVAL; + + /* Take ext phy out of reset */ + if (!driver_loaded) + bnx2x_turn_on_sf(bp, params->port, ext_phy_addr); + + /* wait for 1ms */ + msleep(1); + + bnx2x_cl45_read(bp, params->port, + ext_phy_type, + ext_phy_addr, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_7101_VER1, &val); + version[2] = (val & 0xFF); + version[3] = ((val & 0xFF00)>>8); + + bnx2x_cl45_read(bp, params->port, + ext_phy_type, + ext_phy_addr, + MDIO_PMA_DEVAD, MDIO_PMA_REG_7101_VER2, + &val); + version[0] = (val & 0xFF); + version[1] = ((val & 0xFF00)>>8); + version[4] = '\0'; + + if (!driver_loaded) + bnx2x_turn_off_sf(bp); + break; + case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072: + case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073: + { + bnx2x_cl45_read(bp, params->port, ext_phy_type, + ext_phy_addr, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_ROM_VER1, &val); + ver_num = val<<16; + bnx2x_cl45_read(bp, params->port, ext_phy_type, + ext_phy_addr, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_ROM_VER2, &val); + ver_num |= val; + status = bnx2x_format_ver(ver_num, version, len); + break; + } + case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705: + case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706: + + bnx2x_cl45_read(bp, params->port, ext_phy_type, + ext_phy_addr, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_ROM_VER1, &val); + ver_num = val<<16; + bnx2x_cl45_read(bp, params->port, ext_phy_type, + ext_phy_addr, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_ROM_VER2, &val); + ver_num |= val; + status = bnx2x_format_ver(ver_num, version, len); + break; + + case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT: + break; + + case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE: + DP(NETIF_MSG_LINK, "bnx2x_get_ext_phy_fw_version:" + " type is FAILURE!\n"); + status = -EINVAL; + break; + + default: + break; + } + return status; +} + +static void bnx2x_set_xgxs_loopback(struct link_params *params, + struct link_vars *vars, + u8 is_10g) +{ + u8 port = params->port; + struct bnx2x *bp = params->bp; + + if (is_10g) { + u32 md_devad; + + DP(NETIF_MSG_LINK, "XGXS 10G loopback enable\n"); + + /* change the uni_phy_addr in the nig */ + md_devad = REG_RD(bp, (NIG_REG_XGXS0_CTRL_MD_DEVAD + + port*0x18)); + + REG_WR(bp, NIG_REG_XGXS0_CTRL_MD_DEVAD + port*0x18, 0x5); + + bnx2x_cl45_write(bp, port, 0, + params->phy_addr, + 5, + (MDIO_REG_BANK_AER_BLOCK + + (MDIO_AER_BLOCK_AER_REG & 0xf)), + 0x2800); + + bnx2x_cl45_write(bp, port, 0, + params->phy_addr, + 5, + (MDIO_REG_BANK_CL73_IEEEB0 + + (MDIO_CL73_IEEEB0_CL73_AN_CONTROL & 0xf)), + 0x6041); + + /* set aer mmd back */ + bnx2x_set_aer_mmd(params, vars); + + /* and md_devad */ + REG_WR(bp, NIG_REG_XGXS0_CTRL_MD_DEVAD + port*0x18, + md_devad); + + } else { + u16 mii_control; + + DP(NETIF_MSG_LINK, "XGXS 1G loopback enable\n"); + + CL45_RD_OVER_CL22(bp, port, + params->phy_addr, + MDIO_REG_BANK_COMBO_IEEE0, + MDIO_COMBO_IEEE0_MII_CONTROL, + &mii_control); + + CL45_WR_OVER_CL22(bp, port, + params->phy_addr, + MDIO_REG_BANK_COMBO_IEEE0, + MDIO_COMBO_IEEE0_MII_CONTROL, + (mii_control | + MDIO_COMBO_IEEO_MII_CONTROL_LOOPBACK)); + } +} + + +static void bnx2x_ext_phy_loopback(struct link_params *params) +{ + struct bnx2x *bp = params->bp; + u8 ext_phy_addr; + u32 ext_phy_type; + + if (params->switch_cfg == SWITCH_CFG_10G) { + ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config); + /* CL37 Autoneg Enabled */ + ext_phy_addr = ((params->ext_phy_config & + PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >> + PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT); + switch (ext_phy_type) { + case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT: + case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_NOT_CONN: + DP(NETIF_MSG_LINK, + "ext_phy_loopback: We should not get here\n"); + break; + case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705: + DP(NETIF_MSG_LINK, "ext_phy_loopback: 8705\n"); + break; + case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706: + DP(NETIF_MSG_LINK, "ext_phy_loopback: 8706\n"); + break; + case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101: + /* SFX7101_XGXS_TEST1 */ + bnx2x_cl45_write(bp, params->port, ext_phy_type, + ext_phy_addr, + MDIO_XS_DEVAD, + MDIO_XS_SFX7101_XGXS_TEST1, + 0x100); + DP(NETIF_MSG_LINK, + "ext_phy_loopback: set ext phy loopback\n"); + break; + case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072: + + break; + } /* switch external PHY type */ + } else { + /* serdes */ + ext_phy_type = SERDES_EXT_PHY_TYPE(params->ext_phy_config); + ext_phy_addr = (params->ext_phy_config & + PORT_HW_CFG_SERDES_EXT_PHY_ADDR_MASK) + >> PORT_HW_CFG_SERDES_EXT_PHY_ADDR_SHIFT; + } +} + + +/* + *------------------------------------------------------------------------ + * bnx2x_override_led_value - + * + * Override the led value of the requsted led + * + *------------------------------------------------------------------------ + */ +u8 bnx2x_override_led_value(struct bnx2x *bp, u8 port, + u32 led_idx, u32 value) +{ + u32 reg_val; + + /* If port 0 then use EMAC0, else use EMAC1*/ + u32 emac_base = (port) ? GRCBASE_EMAC1 : GRCBASE_EMAC0; + + DP(NETIF_MSG_LINK, + "bnx2x_override_led_value() port %x led_idx %d value %d\n", + port, led_idx, value); + + switch (led_idx) { + case 0: /* 10MB led */ + /* Read the current value of the LED register in + the EMAC block */ + reg_val = REG_RD(bp, emac_base + EMAC_REG_EMAC_LED); + /* Set the OVERRIDE bit to 1 */ + reg_val |= EMAC_LED_OVERRIDE; + /* If value is 1, set the 10M_OVERRIDE bit, + otherwise reset it.*/ + reg_val = (value == 1) ? (reg_val | EMAC_LED_10MB_OVERRIDE) : + (reg_val & ~EMAC_LED_10MB_OVERRIDE); + REG_WR(bp, emac_base + EMAC_REG_EMAC_LED, reg_val); + break; + case 1: /*100MB led */ + /*Read the current value of the LED register in + the EMAC block */ + reg_val = REG_RD(bp, emac_base + EMAC_REG_EMAC_LED); + /* Set the OVERRIDE bit to 1 */ + reg_val |= EMAC_LED_OVERRIDE; + /* If value is 1, set the 100M_OVERRIDE bit, + otherwise reset it.*/ + reg_val = (value == 1) ? (reg_val | EMAC_LED_100MB_OVERRIDE) : + (reg_val & ~EMAC_LED_100MB_OVERRIDE); + REG_WR(bp, emac_base + EMAC_REG_EMAC_LED, reg_val); + break; + case 2: /* 1000MB led */ + /* Read the current value of the LED register in the + EMAC block */ + reg_val = REG_RD(bp, emac_base + EMAC_REG_EMAC_LED); + /* Set the OVERRIDE bit to 1 */ + reg_val |= EMAC_LED_OVERRIDE; + /* If value is 1, set the 1000M_OVERRIDE bit, otherwise + reset it. */ + reg_val = (value == 1) ? (reg_val | EMAC_LED_1000MB_OVERRIDE) : + (reg_val & ~EMAC_LED_1000MB_OVERRIDE); + REG_WR(bp, emac_base + EMAC_REG_EMAC_LED, reg_val); + break; + case 3: /* 2500MB led */ + /* Read the current value of the LED register in the + EMAC block*/ + reg_val = REG_RD(bp, emac_base + EMAC_REG_EMAC_LED); + /* Set the OVERRIDE bit to 1 */ + reg_val |= EMAC_LED_OVERRIDE; + /* If value is 1, set the 2500M_OVERRIDE bit, otherwise + reset it.*/ + reg_val = (value == 1) ? (reg_val | EMAC_LED_2500MB_OVERRIDE) : + (reg_val & ~EMAC_LED_2500MB_OVERRIDE); + REG_WR(bp, emac_base + EMAC_REG_EMAC_LED, reg_val); + break; + case 4: /*10G led */ + if (port == 0) { + REG_WR(bp, NIG_REG_LED_10G_P0, + value); + } else { + REG_WR(bp, NIG_REG_LED_10G_P1, + value); + } + break; + case 5: /* TRAFFIC led */ + /* Find if the traffic control is via BMAC or EMAC */ + if (port == 0) + reg_val = REG_RD(bp, NIG_REG_NIG_EMAC0_EN); + else + reg_val = REG_RD(bp, NIG_REG_NIG_EMAC1_EN); + + /* Override the traffic led in the EMAC:*/ + if (reg_val == 1) { + /* Read the current value of the LED register in + the EMAC block */ + reg_val = REG_RD(bp, emac_base + + EMAC_REG_EMAC_LED); + /* Set the TRAFFIC_OVERRIDE bit to 1 */ + reg_val |= EMAC_LED_OVERRIDE; + /* If value is 1, set the TRAFFIC bit, otherwise + reset it.*/ + reg_val = (value == 1) ? (reg_val | EMAC_LED_TRAFFIC) : + (reg_val & ~EMAC_LED_TRAFFIC); + REG_WR(bp, emac_base + EMAC_REG_EMAC_LED, reg_val); + } else { /* Override the traffic led in the BMAC: */ + REG_WR(bp, NIG_REG_LED_CONTROL_OVERRIDE_TRAFFIC_P0 + + port*4, 1); + REG_WR(bp, NIG_REG_LED_CONTROL_TRAFFIC_P0 + port*4, + value); + } + break; + default: + DP(NETIF_MSG_LINK, + "bnx2x_override_led_value() unknown led index %d " + "(should be 0-5)\n", led_idx); + return -EINVAL; + } + + return 0; +} + + +u8 bnx2x_set_led(struct bnx2x *bp, u8 port, u8 mode, u32 speed, + u16 hw_led_mode, u32 chip_id) +{ + u8 rc = 0; + DP(NETIF_MSG_LINK, "bnx2x_set_led: port %x, mode %d\n", port, mode); + DP(NETIF_MSG_LINK, "speed 0x%x, hw_led_mode 0x%x\n", + speed, hw_led_mode); + switch (mode) { + case LED_MODE_OFF: + REG_WR(bp, NIG_REG_LED_10G_P0 + port*4, 0); + REG_WR(bp, NIG_REG_LED_MODE_P0 + port*4, + SHARED_HW_CFG_LED_MAC1); + break; + + case LED_MODE_OPER: + REG_WR(bp, NIG_REG_LED_MODE_P0 + port*4, hw_led_mode); + REG_WR(bp, NIG_REG_LED_CONTROL_OVERRIDE_TRAFFIC_P0 + + port*4, 0); + /* Set blinking rate to ~15.9Hz */ + REG_WR(bp, NIG_REG_LED_CONTROL_BLINK_RATE_P0 + port*4, + LED_BLINK_RATE_VAL); + REG_WR(bp, NIG_REG_LED_CONTROL_BLINK_RATE_ENA_P0 + + port*4, 1); + if (!CHIP_IS_E1H(bp) && + ((speed == SPEED_2500) || + (speed == SPEED_1000) || + (speed == SPEED_100) || + (speed == SPEED_10))) { + /* On Everest 1 Ax chip versions for speeds less than + 10G LED scheme is different */ + REG_WR(bp, NIG_REG_LED_CONTROL_OVERRIDE_TRAFFIC_P0 + + port*4, 1); + REG_WR(bp, NIG_REG_LED_CONTROL_TRAFFIC_P0 + + port*4, 0); + REG_WR(bp, NIG_REG_LED_CONTROL_BLINK_TRAFFIC_P0 + + port*4, 1); + } + break; + + default: + rc = -EINVAL; + DP(NETIF_MSG_LINK, "bnx2x_set_led: Invalid led mode %d\n", + mode); + break; + } + return rc; + +} + +u8 bnx2x_test_link(struct link_params *params, struct link_vars *vars) +{ + struct bnx2x *bp = params->bp; + u16 gp_status = 0; + + CL45_RD_OVER_CL22(bp, params->port, + params->phy_addr, + MDIO_REG_BANK_GP_STATUS, + MDIO_GP_STATUS_TOP_AN_STATUS1, + &gp_status); + /* link is up only if both local phy and external phy are up */ + if ((gp_status & MDIO_GP_STATUS_TOP_AN_STATUS1_LINK_STATUS) && + bnx2x_ext_phy_is_link_up(params, vars)) + return 0; + + return -ESRCH; +} + +static u8 bnx2x_link_initialize(struct link_params *params, + struct link_vars *vars) +{ + struct bnx2x *bp = params->bp; + u8 port = params->port; + u8 rc = 0; + + /* Activate the external PHY */ + bnx2x_ext_phy_reset(params, vars); + + bnx2x_set_aer_mmd(params, vars); + + if (vars->phy_flags & PHY_XGXS_FLAG) + bnx2x_set_master_ln(params); + + rc = bnx2x_reset_unicore(params); + /* reset the SerDes and wait for reset bit return low */ + if (rc != 0) + return rc; + + bnx2x_set_aer_mmd(params, vars); + + /* setting the masterLn_def again after the reset */ + if (vars->phy_flags & PHY_XGXS_FLAG) { + bnx2x_set_master_ln(params); + bnx2x_set_swap_lanes(params); + } + + /* Set Parallel Detect */ + if (params->req_line_speed == SPEED_AUTO_NEG) + bnx2x_set_parallel_detection(params, vars->phy_flags); + + if (vars->phy_flags & PHY_XGXS_FLAG) { + if (params->req_line_speed && + ((params->req_line_speed == SPEED_100) || + (params->req_line_speed == SPEED_10))) { + vars->phy_flags |= PHY_SGMII_FLAG; + } else { + vars->phy_flags &= ~PHY_SGMII_FLAG; + } + } + + if (!(vars->phy_flags & PHY_SGMII_FLAG)) { + u16 bank, rx_eq; + + rx_eq = ((params->serdes_config & + PORT_HW_CFG_SERDES_RX_DRV_EQUALIZER_MASK) >> + PORT_HW_CFG_SERDES_RX_DRV_EQUALIZER_SHIFT); + + DP(NETIF_MSG_LINK, "setting rx eq to 0x%x\n", rx_eq); + for (bank = MDIO_REG_BANK_RX0; bank <= MDIO_REG_BANK_RX_ALL; + bank += (MDIO_REG_BANK_RX1-MDIO_REG_BANK_RX0)) { + CL45_WR_OVER_CL22(bp, port, + params->phy_addr, + bank , + MDIO_RX0_RX_EQ_BOOST, + ((rx_eq & + MDIO_RX0_RX_EQ_BOOST_EQUALIZER_CTRL_MASK) | + MDIO_RX0_RX_EQ_BOOST_OFFSET_CTRL)); + } + + /* forced speed requested? */ + if (params->req_line_speed != SPEED_AUTO_NEG) { + DP(NETIF_MSG_LINK, "not SGMII, no AN\n"); + + /* disable autoneg */ + bnx2x_set_autoneg(params, vars); + + /* program speed and duplex */ + bnx2x_program_serdes(params); + vars->ieee_fc = + MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_NONE; + + } else { /* AN_mode */ + DP(NETIF_MSG_LINK, "not SGMII, AN\n"); + + /* AN enabled */ + bnx2x_set_brcm_cl37_advertisment(params); + + /* program duplex & pause advertisement (for aneg) */ + bnx2x_set_ieee_aneg_advertisment(params, + &vars->ieee_fc); + + /* enable autoneg */ + bnx2x_set_autoneg(params, vars); + + /* enable and restart AN */ + bnx2x_restart_autoneg(params); + } + + } else { /* SGMII mode */ + DP(NETIF_MSG_LINK, "SGMII\n"); + + bnx2x_initialize_sgmii_process(params); + } + + /* init ext phy and enable link state int */ + rc |= bnx2x_ext_phy_init(params, vars); + + bnx2x_bits_dis(bp, NIG_REG_STATUS_INTERRUPT_PORT0 + port*4, + (NIG_STATUS_XGXS0_LINK10G | + NIG_STATUS_XGXS0_LINK_STATUS | + NIG_STATUS_SERDES0_LINK_STATUS)); + + return rc; + +} + + +u8 bnx2x_phy_init(struct link_params *params, struct link_vars *vars) +{ + struct bnx2x *bp = params->bp; + + u32 val; + DP(NETIF_MSG_LINK, "Phy Initialization started\n"); + DP(NETIF_MSG_LINK, "req_speed = %d, req_flowctrl=%d\n", + params->req_line_speed, params->req_flow_ctrl); + vars->link_status = 0; + if (params->switch_cfg == SWITCH_CFG_1G) + vars->phy_flags = PHY_SERDES_FLAG; + else + vars->phy_flags = PHY_XGXS_FLAG; + + /* disable attentions */ + bnx2x_bits_dis(bp, NIG_REG_MASK_INTERRUPT_PORT0 + params->port*4, + (NIG_MASK_XGXS0_LINK_STATUS | + NIG_MASK_XGXS0_LINK10G | + NIG_MASK_SERDES0_LINK_STATUS | + NIG_MASK_MI_INT)); + + bnx2x_emac_init(params, vars); + + if (CHIP_REV_IS_FPGA(bp)) { + vars->link_up = 1; + vars->line_speed = SPEED_10000; + vars->duplex = DUPLEX_FULL; + vars->flow_ctrl = FLOW_CTRL_NONE; + vars->link_status = (LINK_STATUS_LINK_UP | LINK_10GTFD); + /* enable on E1.5 FPGA */ + if (CHIP_IS_E1H(bp)) { + vars->flow_ctrl |= + (FLOW_CTRL_TX | FLOW_CTRL_RX); + vars->link_status |= + (LINK_STATUS_TX_FLOW_CONTROL_ENABLED | + LINK_STATUS_RX_FLOW_CONTROL_ENABLED); + } + + bnx2x_emac_enable(params, vars, 0); + bnx2x_pbf_update(params, vars->flow_ctrl, vars->line_speed); + /* disable drain */ + REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE + + params->port*4, 0); + + /* update shared memory */ + bnx2x_update_mng(params, vars->link_status); + + return 0; + + } else + if (CHIP_REV_IS_EMUL(bp)) { + + vars->link_up = 1; + vars->line_speed = SPEED_10000; + vars->duplex = DUPLEX_FULL; + vars->flow_ctrl = FLOW_CTRL_NONE; + vars->link_status = (LINK_STATUS_LINK_UP | LINK_10GTFD); + + bnx2x_bmac_enable(params, vars, 0); + + bnx2x_pbf_update(params, vars->flow_ctrl, vars->line_speed); + /* Disable drain */ + REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE + + params->port*4, 0); + + /* update shared memory */ + bnx2x_update_mng(params, vars->link_status); + + return 0; + + } else + if (params->loopback_mode == LOOPBACK_BMAC) { + vars->link_up = 1; + vars->line_speed = SPEED_10000; + vars->duplex = DUPLEX_FULL; + vars->flow_ctrl = FLOW_CTRL_NONE; + vars->mac_type = MAC_TYPE_BMAC; + + vars->phy_flags = PHY_XGXS_FLAG; + + bnx2x_phy_deassert(params, vars->phy_flags); + /* set bmac loopback */ + bnx2x_bmac_enable(params, vars, 1); + + REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE + + params->port*4, 0); + } else if (params->loopback_mode == LOOPBACK_EMAC) { + vars->link_up = 1; + vars->line_speed = SPEED_1000; + vars->duplex = DUPLEX_FULL; + vars->flow_ctrl = FLOW_CTRL_NONE; + vars->mac_type = MAC_TYPE_EMAC; + + vars->phy_flags = PHY_XGXS_FLAG; + + bnx2x_phy_deassert(params, vars->phy_flags); + /* set bmac loopback */ + bnx2x_emac_enable(params, vars, 1); + bnx2x_emac_program(params, vars->line_speed, + vars->duplex); + REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE + + params->port*4, 0); + } else if ((params->loopback_mode == LOOPBACK_XGXS_10) || + (params->loopback_mode == LOOPBACK_EXT_PHY)) { + vars->link_up = 1; + vars->line_speed = SPEED_10000; + vars->duplex = DUPLEX_FULL; + vars->flow_ctrl = FLOW_CTRL_NONE; + + vars->phy_flags = PHY_XGXS_FLAG; + + val = REG_RD(bp, + NIG_REG_XGXS0_CTRL_PHY_ADDR+ + params->port*0x18); + params->phy_addr = (u8)val; + + bnx2x_phy_deassert(params, vars->phy_flags); + bnx2x_link_initialize(params, vars); + + vars->mac_type = MAC_TYPE_BMAC; + + bnx2x_bmac_enable(params, vars, 0); + + if (params->loopback_mode == LOOPBACK_XGXS_10) { + /* set 10G XGXS loopback */ + bnx2x_set_xgxs_loopback(params, vars, 1); + } else { + /* set external phy loopback */ + bnx2x_ext_phy_loopback(params); + } + REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE + + params->port*4, 0); + } else + /* No loopback */ + { + + bnx2x_phy_deassert(params, vars->phy_flags); + switch (params->switch_cfg) { + case SWITCH_CFG_1G: + vars->phy_flags |= PHY_SERDES_FLAG; + if ((params->ext_phy_config & + PORT_HW_CFG_SERDES_EXT_PHY_TYPE_MASK) == + PORT_HW_CFG_SERDES_EXT_PHY_TYPE_BCM5482) { + vars->phy_flags |= + PHY_SGMII_FLAG; + } + + val = REG_RD(bp, + NIG_REG_SERDES0_CTRL_PHY_ADDR+ + params->port*0x10); + + params->phy_addr = (u8)val; + + break; + case SWITCH_CFG_10G: + vars->phy_flags |= PHY_XGXS_FLAG; + val = REG_RD(bp, + NIG_REG_XGXS0_CTRL_PHY_ADDR+ + params->port*0x18); + params->phy_addr = (u8)val; + + break; + default: + DP(NETIF_MSG_LINK, "Invalid switch_cfg\n"); + return -EINVAL; + break; + } + + bnx2x_link_initialize(params, vars); + bnx2x_link_int_enable(params); + } + return 0; +} + +u8 bnx2x_link_reset(struct link_params *params, struct link_vars *vars) +{ + + struct bnx2x *bp = params->bp; + u32 ext_phy_config = params->ext_phy_config; + u16 hw_led_mode = params->hw_led_mode; + u32 chip_id = params->chip_id; + u8 port = params->port; + u32 ext_phy_type = XGXS_EXT_PHY_TYPE(ext_phy_config); + /* disable attentions */ + + vars->link_status = 0; + bnx2x_update_mng(params, vars->link_status); + bnx2x_bits_dis(bp, NIG_REG_MASK_INTERRUPT_PORT0 + port*4, + (NIG_MASK_XGXS0_LINK_STATUS | + NIG_MASK_XGXS0_LINK10G | + NIG_MASK_SERDES0_LINK_STATUS | + NIG_MASK_MI_INT)); + + /* activate nig drain */ + REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE + port*4, 1); + + /* disable nig egress interface */ + REG_WR(bp, NIG_REG_BMAC0_OUT_EN + port*4, 0); + REG_WR(bp, NIG_REG_EGRESS_EMAC0_OUT_EN + port*4, 0); + + /* Stop BigMac rx */ + bnx2x_bmac_rx_disable(bp, port); + + /* disable emac */ + REG_WR(bp, NIG_REG_NIG_EMAC0_EN + port*4, 0); + + msleep(10); + /* The PHY reset is controled by GPIO 1 + * Hold it as vars low + */ + /* clear link led */ + bnx2x_set_led(bp, port, LED_MODE_OFF, 0, hw_led_mode, chip_id); + if (ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT) { + if ((ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072) && + (ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073)) { + /* HW reset */ + + bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1, + MISC_REGISTERS_GPIO_OUTPUT_LOW); + + bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2, + MISC_REGISTERS_GPIO_OUTPUT_LOW); + + DP(NETIF_MSG_LINK, "reset external PHY\n"); + } else { + + u8 ext_phy_addr = ((ext_phy_config & + PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >> + PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT); + + /* SW reset */ + bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_CTRL, + 1<<15); + + /* Set Low Power Mode */ + bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_CTRL, + 1<<11); + + + if (ext_phy_type == + PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073) { + DP(NETIF_MSG_LINK, "Setting 8073 port %d into" + "low power mode\n", + port); + bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2, + MISC_REGISTERS_GPIO_OUTPUT_LOW); + } + } + } + /* reset the SerDes/XGXS */ + REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_3_CLEAR, + (0x1ff << (port*16))); + + /* reset BigMac */ + REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_CLEAR, + (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port)); + + /* disable nig ingress interface */ + REG_WR(bp, NIG_REG_BMAC0_IN_EN + port*4, 0); + REG_WR(bp, NIG_REG_EMAC0_IN_EN + port*4, 0); + REG_WR(bp, NIG_REG_BMAC0_OUT_EN + port*4, 0); + REG_WR(bp, NIG_REG_EGRESS_EMAC0_OUT_EN + port*4, 0); + vars->link_up = 0; + return 0; +} + +/* This function should called upon link interrupt */ +/* In case vars->link_up, driver needs to + 1. Update the pbf + 2. Disable drain + 3. Update the shared memory + 4. Indicate link up + 5. Set LEDs + Otherwise, + 1. Update shared memory + 2. Reset BigMac + 3. Report link down + 4. Unset LEDs +*/ +u8 bnx2x_link_update(struct link_params *params, struct link_vars *vars) +{ + struct bnx2x *bp = params->bp; + u8 port = params->port; + u16 i; + u16 gp_status; + u16 link_10g; + u8 rc = 0; + + DP(NETIF_MSG_LINK, "port %x, XGXS?%x, int_status 0x%x\n", + port, + (vars->phy_flags & PHY_XGXS_FLAG), + REG_RD(bp, NIG_REG_STATUS_INTERRUPT_PORT0 + port*4)); + + DP(NETIF_MSG_LINK, "int_mask 0x%x MI_INT %x, SERDES_LINK %x\n", + REG_RD(bp, NIG_REG_MASK_INTERRUPT_PORT0 + port*4), + REG_RD(bp, NIG_REG_EMAC0_STATUS_MISC_MI_INT + port*0x18), + REG_RD(bp, NIG_REG_SERDES0_STATUS_LINK_STATUS + port*0x3c)); + + DP(NETIF_MSG_LINK, " 10G %x, XGXS_LINK %x\n", + REG_RD(bp, NIG_REG_XGXS0_STATUS_LINK10G + port*0x68), + REG_RD(bp, NIG_REG_XGXS0_STATUS_LINK_STATUS + port*0x68)); + + + /* avoid fast toggling */ + for (i = 0; i < 10; i++) { + msleep(10); + CL45_RD_OVER_CL22(bp, port, params->phy_addr, + MDIO_REG_BANK_GP_STATUS, + MDIO_GP_STATUS_TOP_AN_STATUS1, + &gp_status); + } + + rc = bnx2x_link_settings_status(params, vars, gp_status); + if (rc != 0) + return rc; + + /* anything 10 and over uses the bmac */ + link_10g = ((vars->line_speed == SPEED_10000) || + (vars->line_speed == SPEED_12000) || + (vars->line_speed == SPEED_12500) || + (vars->line_speed == SPEED_13000) || + (vars->line_speed == SPEED_15000) || + (vars->line_speed == SPEED_16000)); + + bnx2x_link_int_ack(params, vars, link_10g); + + /* link is up only if both local phy and external phy are up */ + vars->link_up = (vars->phy_link_up && + bnx2x_ext_phy_is_link_up(params, vars)); + + if (!vars->phy_link_up && + REG_RD(bp, NIG_REG_EMAC0_STATUS_MISC_MI_INT + port*0x18)) { + bnx2x_ext_phy_is_link_up(params, vars); /* Clear interrupt */ + } + + if (vars->link_up) { + vars->link_status |= LINK_STATUS_LINK_UP; + if (link_10g) { + bnx2x_bmac_enable(params, vars, 0); + bnx2x_set_led(bp, port, LED_MODE_OPER, + SPEED_10000, params->hw_led_mode, + params->chip_id); + + } else { + bnx2x_emac_enable(params, vars, 0); + rc = bnx2x_emac_program(params, vars->line_speed, + vars->duplex); + + /* AN complete? */ + if (gp_status & MDIO_AN_CL73_OR_37_COMPLETE) { + if (!(vars->phy_flags & + PHY_SGMII_FLAG)) + bnx2x_set_sgmii_tx_driver(params); + } + } + + /* PBF - link up */ + rc |= bnx2x_pbf_update(params, vars->flow_ctrl, + vars->line_speed); + + /* disable drain */ + REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE + port*4, 0); + + /* update shared memory */ + bnx2x_update_mng(params, vars->link_status); + + } else { /* link down */ + DP(NETIF_MSG_LINK, "Port %x: Link is down\n", params->port); + bnx2x_set_led(bp, port, LED_MODE_OFF, + 0, params->hw_led_mode, + params->chip_id); + + /* indicate no mac active */ + vars->mac_type = MAC_TYPE_NONE; + + /* update shared memory */ + vars->link_status = 0; + bnx2x_update_mng(params, vars->link_status); + + /* activate nig drain */ + REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE + port*4, 1); + + /* reset BigMac */ + bnx2x_bmac_rx_disable(bp, params->port); + REG_WR(bp, GRCBASE_MISC + + MISC_REGISTERS_RESET_REG_2_CLEAR, + (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port)); + + } + + return rc; +} + +static void bnx2x_sfx7101_sp_sw_reset(struct bnx2x *bp, u8 port, u8 phy_addr) +{ + u16 val, cnt; + + bnx2x_cl45_read(bp, port, + PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101, + phy_addr, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_7101_RESET, &val); + + for (cnt = 0; cnt < 10; cnt++) { + msleep(50); + /* Writes a self-clearing reset */ + bnx2x_cl45_write(bp, port, + PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101, + phy_addr, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_7101_RESET, + (val | (1<<15))); + /* Wait for clear */ + bnx2x_cl45_read(bp, port, + PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101, + phy_addr, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_7101_RESET, &val); + + if ((val & (1<<15)) == 0) + break; + } +} +#define RESERVED_SIZE 256 +/* max application is 160K bytes - data at end of RAM */ +#define MAX_APP_SIZE 160*1024 - RESERVED_SIZE + +/* Header is 14 bytes */ +#define HEADER_SIZE 14 +#define DATA_OFFSET HEADER_SIZE + +#define SPI_START_TRANSFER(bp, port, ext_phy_addr) \ + bnx2x_cl45_write(bp, port, PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101, \ + ext_phy_addr, \ + MDIO_PCS_DEVAD, \ + MDIO_PCS_REG_7101_SPI_CTRL_ADDR, 1) + +/* Programs an image to DSP's flash via the SPI port*/ +static u8 bnx2x_sfx7101_flash_download(struct bnx2x *bp, u8 port, + u8 ext_phy_addr, + char data[], u32 size) +{ + const u16 num_trans = size/4; /* 4 bytes can be sent at a time */ + /* Doesn't include last trans!*/ + const u16 last_trans_size = size%4; /* Num bytes on last trans */ + u16 trans_cnt, byte_cnt; + u32 data_index; + u16 tmp; + u16 code_started = 0; + u16 image_revision1, image_revision2; + u16 cnt; + + DP(NETIF_MSG_LINK, "bnx2x_sfx7101_flash_download file_size=%d\n", size); + /* Going to flash*/ + if ((size-HEADER_SIZE) > MAX_APP_SIZE) { + /* This very often will be the case, because the image is built + with 160Kbytes size whereas the total image size must actually + be 160Kbytes-RESERVED_SIZE */ + DP(NETIF_MSG_LINK, "Warning, file size was %d bytes " + "truncated to %d bytes\n", size, MAX_APP_SIZE); + size = MAX_APP_SIZE+HEADER_SIZE; + } + DP(NETIF_MSG_LINK, "File version is %c%c\n", data[0x14e], data[0x14f]); + DP(NETIF_MSG_LINK, " %c%c\n", data[0x150], data[0x151]); + /* Put the DSP in download mode by setting FLASH_CFG[2] to 1 + and issuing a reset.*/ + + bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_0, + MISC_REGISTERS_GPIO_HIGH); + + bnx2x_sfx7101_sp_sw_reset(bp, port, ext_phy_addr); + + /* wait 0.5 sec */ + for (cnt = 0; cnt < 100; cnt++) + msleep(5); + + /* Make sure we can access the DSP + And it's in the correct mode (waiting for download) */ + + bnx2x_cl45_read(bp, port, + PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101, + ext_phy_addr, + MDIO_PCS_DEVAD, + MDIO_PCS_REG_7101_DSP_ACCESS, &tmp); + + if (tmp != 0x000A) { + DP(NETIF_MSG_LINK, "DSP is not in waiting on download mode. " + "Expected 0x000A, read 0x%04X\n", tmp); + DP(NETIF_MSG_LINK, "Download failed\n"); + return -EINVAL; + } + + /* Mux the SPI interface away from the internal processor */ + bnx2x_cl45_write(bp, port, + PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101, + ext_phy_addr, + MDIO_PCS_DEVAD, + MDIO_PCS_REG_7101_SPI_MUX, 1); + + /* Reset the SPI port */ + bnx2x_cl45_write(bp, port, + PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101, + ext_phy_addr, + MDIO_PCS_DEVAD, + MDIO_PCS_REG_7101_SPI_CTRL_ADDR, 0); + bnx2x_cl45_write(bp, port, + PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101, + ext_phy_addr, + MDIO_PCS_DEVAD, + MDIO_PCS_REG_7101_SPI_CTRL_ADDR, + (1<<MDIO_PCS_REG_7101_SPI_RESET_BIT)); + bnx2x_cl45_write(bp, port, + PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101, + ext_phy_addr, + MDIO_PCS_DEVAD, + MDIO_PCS_REG_7101_SPI_CTRL_ADDR, 0); + + /* Erase the flash */ + bnx2x_cl45_write(bp, port, + PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101, + ext_phy_addr, + MDIO_PCS_DEVAD, + MDIO_PCS_REG_7101_SPI_FIFO_ADDR, + MDIO_PCS_REG_7101_SPI_FIFO_ADDR_WRITE_ENABLE_CMD); + + bnx2x_cl45_write(bp, port, + PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101, + ext_phy_addr, + MDIO_PCS_DEVAD, + MDIO_PCS_REG_7101_SPI_BYTES_TO_TRANSFER_ADDR, + 1); + + SPI_START_TRANSFER(bp, port, ext_phy_addr); + bnx2x_cl45_write(bp, port, + PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101, + ext_phy_addr, + MDIO_PCS_DEVAD, + MDIO_PCS_REG_7101_SPI_FIFO_ADDR, + MDIO_PCS_REG_7101_SPI_FIFO_ADDR_BULK_ERASE_CMD); + + bnx2x_cl45_write(bp, port, + PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101, + ext_phy_addr, + MDIO_PCS_DEVAD, + MDIO_PCS_REG_7101_SPI_BYTES_TO_TRANSFER_ADDR, + 1); + SPI_START_TRANSFER(bp, port, ext_phy_addr); + + /* Wait 10 seconds, the maximum time for the erase to complete */ + DP(NETIF_MSG_LINK, "Erasing flash, this takes 10 seconds...\n"); + for (cnt = 0; cnt < 1000; cnt++) + msleep(10); + + DP(NETIF_MSG_LINK, "Downloading flash, please wait...\n"); + data_index = 0; + for (trans_cnt = 0; trans_cnt < num_trans; trans_cnt++) { + bnx2x_cl45_write(bp, port, + PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101, + ext_phy_addr, + MDIO_PCS_DEVAD, + MDIO_PCS_REG_7101_SPI_FIFO_ADDR, + MDIO_PCS_REG_7101_SPI_FIFO_ADDR_WRITE_ENABLE_CMD); + + bnx2x_cl45_write(bp, port, + PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101, + ext_phy_addr, + MDIO_PCS_DEVAD, + MDIO_PCS_REG_7101_SPI_BYTES_TO_TRANSFER_ADDR, + 1); + SPI_START_TRANSFER(bp, port, ext_phy_addr); + + bnx2x_cl45_write(bp, port, + PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101, + ext_phy_addr, + MDIO_PCS_DEVAD, + MDIO_PCS_REG_7101_SPI_FIFO_ADDR, + MDIO_PCS_REG_7101_SPI_FIFO_ADDR_PAGE_PROGRAM_CMD); + + /* Bits 23-16 of address */ + bnx2x_cl45_write(bp, port, + PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101, + ext_phy_addr, + MDIO_PCS_DEVAD, + MDIO_PCS_REG_7101_SPI_FIFO_ADDR, + (data_index>>16)); + /* Bits 15-8 of address */ + bnx2x_cl45_write(bp, port, + PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101, + ext_phy_addr, + MDIO_PCS_DEVAD, + MDIO_PCS_REG_7101_SPI_FIFO_ADDR, + (data_index>>8)); + + /* Bits 7-0 of address */ + bnx2x_cl45_write(bp, port, + PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101, + ext_phy_addr, + MDIO_PCS_DEVAD, + MDIO_PCS_REG_7101_SPI_FIFO_ADDR, + ((u16)data_index)); + + byte_cnt = 0; + while (byte_cnt < 4 && data_index < size) { + bnx2x_cl45_write(bp, port, + PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101, + ext_phy_addr, + MDIO_PCS_DEVAD, + MDIO_PCS_REG_7101_SPI_FIFO_ADDR, + data[data_index++]); + byte_cnt++; + } + + bnx2x_cl45_write(bp, port, + PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101, + ext_phy_addr, + MDIO_PCS_DEVAD, + MDIO_PCS_REG_7101_SPI_BYTES_TO_TRANSFER_ADDR, + byte_cnt+4); + + SPI_START_TRANSFER(bp, port, ext_phy_addr); + msleep(5); /* Wait 5 ms minimum between transs */ + + /* Let the user know something's going on.*/ + /* a pacifier ever 4K */ + if ((data_index % 1023) == 0) + DP(NETIF_MSG_LINK, "Download %d%%\n", data_index/size); + } + + DP(NETIF_MSG_LINK, "\n"); + /* Transfer the last block if there is data remaining */ + if (last_trans_size) { + bnx2x_cl45_write(bp, port, + PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101, + ext_phy_addr, + MDIO_PCS_DEVAD, + MDIO_PCS_REG_7101_SPI_FIFO_ADDR, + MDIO_PCS_REG_7101_SPI_FIFO_ADDR_WRITE_ENABLE_CMD); + + bnx2x_cl45_write(bp, port, + PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101, + ext_phy_addr, + MDIO_PCS_DEVAD, + MDIO_PCS_REG_7101_SPI_BYTES_TO_TRANSFER_ADDR, + 1); + + SPI_START_TRANSFER(bp, port, ext_phy_addr); + + bnx2x_cl45_write(bp, port, + PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101, + ext_phy_addr, + MDIO_PCS_DEVAD, + MDIO_PCS_REG_7101_SPI_FIFO_ADDR, + MDIO_PCS_REG_7101_SPI_FIFO_ADDR_PAGE_PROGRAM_CMD); + + /* Bits 23-16 of address */ + bnx2x_cl45_write(bp, port, + PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101, + ext_phy_addr, + MDIO_PCS_DEVAD, + MDIO_PCS_REG_7101_SPI_FIFO_ADDR, + (data_index>>16)); + /* Bits 15-8 of address */ + bnx2x_cl45_write(bp, port, + PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101, + ext_phy_addr, + MDIO_PCS_DEVAD, + MDIO_PCS_REG_7101_SPI_FIFO_ADDR, + (data_index>>8)); + + /* Bits 7-0 of address */ + bnx2x_cl45_write(bp, port, + PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101, + ext_phy_addr, + MDIO_PCS_DEVAD, + MDIO_PCS_REG_7101_SPI_FIFO_ADDR, + ((u16)data_index)); + + byte_cnt = 0; + while (byte_cnt < last_trans_size && data_index < size) { + /* Bits 7-0 of address */ + bnx2x_cl45_write(bp, port, + PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101, + ext_phy_addr, + MDIO_PCS_DEVAD, + MDIO_PCS_REG_7101_SPI_FIFO_ADDR, + data[data_index++]); + byte_cnt++; + } + + bnx2x_cl45_write(bp, port, + PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101, + ext_phy_addr, + MDIO_PCS_DEVAD, + MDIO_PCS_REG_7101_SPI_BYTES_TO_TRANSFER_ADDR, + byte_cnt+4); + + SPI_START_TRANSFER(bp, port, ext_phy_addr); + } + + /* DSP Remove Download Mode */ + bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_0, MISC_REGISTERS_GPIO_LOW); + + bnx2x_sfx7101_sp_sw_reset(bp, port, ext_phy_addr); + + /* wait 0.5 sec to allow it to run */ + for (cnt = 0; cnt < 100; cnt++) + msleep(5); + + bnx2x_hw_reset(bp); + + for (cnt = 0; cnt < 100; cnt++) + msleep(5); + + /* Check that the code is started. In case the download + checksum failed, the code won't be started. */ + bnx2x_cl45_read(bp, port, + PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101, + ext_phy_addr, + MDIO_PCS_DEVAD, + MDIO_PCS_REG_7101_DSP_ACCESS, + &tmp); + + code_started = (tmp & (1<<4)); + if (!code_started) { + DP(NETIF_MSG_LINK, "Download failed. Please check file.\n"); + return -EINVAL; + } + + /* Verify that the file revision is now equal to the image + revision within the DSP */ + bnx2x_cl45_read(bp, port, + PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101, + ext_phy_addr, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_7101_VER1, + &image_revision1); + + bnx2x_cl45_read(bp, port, + PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101, + ext_phy_addr, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_7101_VER2, + &image_revision2); + + if (data[0x14e] != (image_revision2&0xFF) || + data[0x14f] != ((image_revision2&0xFF00)>>8) || + data[0x150] != (image_revision1&0xFF) || + data[0x151] != ((image_revision1&0xFF00)>>8)) { + DP(NETIF_MSG_LINK, "Download failed.\n"); + return -EINVAL; + } + DP(NETIF_MSG_LINK, "Download %d%%\n", data_index/size); + return 0; +} + +u8 bnx2x_flash_download(struct bnx2x *bp, u8 port, u32 ext_phy_config, + u8 driver_loaded, char data[], u32 size) +{ + u8 rc = 0; + u32 ext_phy_type; + u8 ext_phy_addr; + ext_phy_addr = ((ext_phy_config & + PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >> + PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT); + + ext_phy_type = XGXS_EXT_PHY_TYPE(ext_phy_config); + + switch (ext_phy_type) { + case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072: + case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073: + case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705: + case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706: + DP(NETIF_MSG_LINK, + "Flash download not supported for this ext phy\n"); + rc = -EINVAL; + break; + case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101: + /* Take ext phy out of reset */ + if (!driver_loaded) + bnx2x_turn_on_sf(bp, port, ext_phy_addr); + rc = bnx2x_sfx7101_flash_download(bp, port, ext_phy_addr, + data, size); + if (!driver_loaded) + bnx2x_turn_off_sf(bp); + break; + case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT: + case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE: + case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_NOT_CONN: + default: + DP(NETIF_MSG_LINK, "Invalid ext phy type\n"); + rc = -EINVAL; + break; + } + return rc; +} + diff --git a/drivers/net/bnx2x_link.h b/drivers/net/bnx2x_link.h new file mode 100644 index 000000000000..714d37ac95de --- /dev/null +++ b/drivers/net/bnx2x_link.h @@ -0,0 +1,168 @@ +/* Copyright 2008 Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2, available + * at http://www.gnu.org/licenses/old-licenses/gpl-2.0.html (the "GPL"). + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a + * license other than the GPL, without Broadcom's express prior written + * consent. + * + * Written by Yaniv Rosner + * + */ + +#ifndef BNX2X_LINK_H +#define BNX2X_LINK_H + + + +/***********************************************************/ +/* Defines */ +/***********************************************************/ +#define DEFAULT_PHY_DEV_ADDR 3 + + + +#define FLOW_CTRL_AUTO PORT_FEATURE_FLOW_CONTROL_AUTO +#define FLOW_CTRL_TX PORT_FEATURE_FLOW_CONTROL_TX +#define FLOW_CTRL_RX PORT_FEATURE_FLOW_CONTROL_RX +#define FLOW_CTRL_BOTH PORT_FEATURE_FLOW_CONTROL_BOTH +#define FLOW_CTRL_NONE PORT_FEATURE_FLOW_CONTROL_NONE + +#define SPEED_AUTO_NEG 0 +#define SPEED_12000 12000 +#define SPEED_12500 12500 +#define SPEED_13000 13000 +#define SPEED_15000 15000 +#define SPEED_16000 16000 + + +/***********************************************************/ +/* Structs */ +/***********************************************************/ +/* Inputs parameters to the CLC */ +struct link_params { + + u8 port; + + /* Default / User Configuration */ + u8 loopback_mode; +#define LOOPBACK_NONE 0 +#define LOOPBACK_EMAC 1 +#define LOOPBACK_BMAC 2 +#define LOOPBACK_XGXS_10 3 +#define LOOPBACK_EXT_PHY 4 + + u16 req_duplex; + u16 req_flow_ctrl; + u16 req_line_speed; /* Also determine AutoNeg */ + + /* Device parameters */ + u8 mac_addr[6]; + u16 mtu; + + + /* shmem parameters */ + u32 shmem_base; + u32 speed_cap_mask; + u32 switch_cfg; +#define SWITCH_CFG_1G PORT_FEATURE_CON_SWITCH_1G_SWITCH +#define SWITCH_CFG_10G PORT_FEATURE_CON_SWITCH_10G_SWITCH +#define SWITCH_CFG_AUTO_DETECT PORT_FEATURE_CON_SWITCH_AUTO_DETECT + + u16 hw_led_mode; /* part of the hw_config read from the shmem */ + u32 serdes_config; + u32 lane_config; + u32 ext_phy_config; +#define XGXS_EXT_PHY_TYPE(ext_phy_config) (ext_phy_config & \ + PORT_HW_CFG_XGXS_EXT_PHY_TYPE_MASK) +#define SERDES_EXT_PHY_TYPE(ext_phy_config) (ext_phy_config & \ + PORT_HW_CFG_SERDES_EXT_PHY_TYPE_MASK) + /* Phy register parameter */ + u32 chip_id; + + /* phy_addr populated by the CLC */ + u8 phy_addr; + /* Device pointer passed to all callback functions */ + struct bnx2x *bp; +}; + +/* Output parameters */ +struct link_vars { + u8 phy_link_up; /* internal phy link indication */ + u8 link_up; + u16 duplex; + u16 flow_ctrl; + u32 ieee_fc; + u8 mac_type; + +#define MAC_TYPE_NONE 0 +#define MAC_TYPE_EMAC 1 +#define MAC_TYPE_BMAC 2 + u16 line_speed; + u32 autoneg; +#define AUTO_NEG_DISABLED 0x0 +#define AUTO_NEG_ENABLED 0x1 +#define AUTO_NEG_COMPLETE 0x2 +#define AUTO_NEG_PARALLEL_DETECTION_USED 0x3 + + u8 phy_flags; + + /* The same definitions as the shmem parameter */ + u32 link_status; +}; + +/***********************************************************/ +/* Functions */ +/***********************************************************/ + +/* Initialize the phy */ +u8 bnx2x_phy_init(struct link_params *input, struct link_vars *output); + +/* Reset the link. Should be called when driver or interface goes down */ +u8 bnx2x_link_reset(struct link_params *params, struct link_vars *vars); + +/* bnx2x_link_update should be called upon link interrupt */ +u8 bnx2x_link_update(struct link_params *input, struct link_vars *output); + +/* use the following cl45 functions to read/write from external_phy + In order to use it to read/write internal phy registers, use + DEFAULT_PHY_DEV_ADDR as devad, and (_bank + (_addr & 0xf)) as + Use ext_phy_type of 0 in case of cl22 over cl45 + the register */ +u8 bnx2x_cl45_read(struct bnx2x *bp, u8 port, u32 ext_phy_type, + u8 phy_addr, u8 devad, u16 reg, u16 *ret_val); + +u8 bnx2x_cl45_write(struct bnx2x *bp, u8 port, u32 ext_phy_type, + u8 phy_addr, u8 devad, u16 reg, u16 val); + +/* Reads the link_status from the shmem, + and update the link vars accordinaly */ +void bnx2x_link_status_update(struct link_params *input, + struct link_vars *output); +/* returns string representing the fw_version of the external phy */ +u8 bnx2x_get_ext_phy_fw_version(struct link_params *params, u8 driver_loaded, + u8 *version, u16 len); + +/* Set/Unset the led + Basically, the CLC takes care of the led for the link, but in case one needs + to set/unset the led unnatually, set the "mode" to LED_MODE_OPER to + blink the led, and LED_MODE_OFF to set the led off.*/ +u8 bnx2x_set_led(struct bnx2x *bp, u8 port, u8 mode, u32 speed, + u16 hw_led_mode, u32 chip_id); +#define LED_MODE_OFF 0 +#define LED_MODE_OPER 2 + +u8 bnx2x_override_led_value(struct bnx2x *bp, u8 port, u32 led_idx, u32 value); + +u8 bnx2x_flash_download(struct bnx2x *bp, u8 port, u32 ext_phy_config, + u8 driver_loaded, char data[], u32 size); +/* Get the actual link status. In case it returns 0, link is up, + otherwise link is down*/ +u8 bnx2x_test_link(struct link_params *input, struct link_vars *vars); + + +#endif /* BNX2X_LINK_H */ diff --git a/drivers/net/bnx2x_main.c b/drivers/net/bnx2x_main.c new file mode 100644 index 000000000000..0263bef9cc6d --- /dev/null +++ b/drivers/net/bnx2x_main.c @@ -0,0 +1,10294 @@ +/* bnx2x_main.c: Broadcom Everest network driver. + * + * Copyright (c) 2007-2008 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 <eilong@broadcom.com> + * Written by: Eliezer Tamir + * Based on code from Michael Chan's bnx2 driver + * UDP CSUM errata workaround by Arik Gendelman + * Slowpath rework by Vladislav Zolotarov + * Statistics and Link management by Yitchak Gertner + * + */ + +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/kernel.h> +#include <linux/device.h> /* for dev_info() */ +#include <linux/timer.h> +#include <linux/errno.h> +#include <linux/ioport.h> +#include <linux/slab.h> +#include <linux/vmalloc.h> +#include <linux/interrupt.h> +#include <linux/pci.h> +#include <linux/init.h> +#include <linux/netdevice.h> +#include <linux/etherdevice.h> +#include <linux/skbuff.h> +#include <linux/dma-mapping.h> +#include <linux/bitops.h> +#include <linux/irq.h> +#include <linux/delay.h> +#include <asm/byteorder.h> +#include <linux/time.h> +#include <linux/ethtool.h> +#include <linux/mii.h> +#ifdef NETIF_F_HW_VLAN_TX + #include <linux/if_vlan.h> +#endif +#include <net/ip.h> +#include <net/tcp.h> +#include <net/checksum.h> +#include <linux/version.h> +#include <net/ip6_checksum.h> +#include <linux/workqueue.h> +#include <linux/crc32.h> +#include <linux/crc32c.h> +#include <linux/prefetch.h> +#include <linux/zlib.h> +#include <linux/io.h> + +#include "bnx2x_reg.h" +#include "bnx2x_fw_defs.h" +#include "bnx2x_hsi.h" +#include "bnx2x_link.h" +#include "bnx2x.h" +#include "bnx2x_init.h" + +#define DRV_MODULE_VERSION "1.45.6" +#define DRV_MODULE_RELDATE "2008/06/23" +#define BNX2X_BC_VER 0x040200 + +/* Time in jiffies before concluding the transmitter is hung */ +#define TX_TIMEOUT (5*HZ) + +static char version[] __devinitdata = + "Broadcom NetXtreme II 5771x 10Gigabit Ethernet Driver " + DRV_MODULE_NAME " " DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n"; + +MODULE_AUTHOR("Eliezer Tamir"); +MODULE_DESCRIPTION("Broadcom NetXtreme II BCM57710 Driver"); +MODULE_LICENSE("GPL"); +MODULE_VERSION(DRV_MODULE_VERSION); + +static int use_inta; +static int poll; +static int debug; +static int disable_tpa; +static int nomcp; +static int load_count[3]; /* 0-common, 1-port0, 2-port1 */ +static int use_multi; + +module_param(use_inta, int, 0); +module_param(poll, int, 0); +module_param(debug, int, 0); +module_param(disable_tpa, int, 0); +module_param(nomcp, int, 0); +MODULE_PARM_DESC(use_inta, "use INT#A instead of MSI-X"); +MODULE_PARM_DESC(poll, "use polling (for debug)"); +MODULE_PARM_DESC(debug, "default debug msglevel"); +MODULE_PARM_DESC(nomcp, "ignore management CPU"); + +#ifdef BNX2X_MULTI +module_param(use_multi, int, 0); +MODULE_PARM_DESC(use_multi, "use per-CPU queues"); +#endif + +enum bnx2x_board_type { + BCM57710 = 0, + BCM57711 = 1, + BCM57711E = 2, +}; + +/* indexed by board_type, above */ +static struct { + char *name; +} board_info[] __devinitdata = { + { "Broadcom NetXtreme II BCM57710 XGb" }, + { "Broadcom NetXtreme II BCM57711 XGb" }, + { "Broadcom NetXtreme II BCM57711E XGb" } +}; + + +static const struct pci_device_id bnx2x_pci_tbl[] = { + { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_57710, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM57710 }, + { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_57711, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM57711 }, + { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_57711E, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM57711E }, + { 0 } +}; + +MODULE_DEVICE_TABLE(pci, bnx2x_pci_tbl); + +/**************************************************************************** +* General service functions +****************************************************************************/ + +/* used only at init + * locking is done by mcp + */ +static void bnx2x_reg_wr_ind(struct bnx2x *bp, u32 addr, u32 val) +{ + pci_write_config_dword(bp->pdev, PCICFG_GRC_ADDRESS, addr); + pci_write_config_dword(bp->pdev, PCICFG_GRC_DATA, val); + pci_write_config_dword(bp->pdev, PCICFG_GRC_ADDRESS, + PCICFG_VENDOR_ID_OFFSET); +} + +static u32 bnx2x_reg_rd_ind(struct bnx2x *bp, u32 addr) +{ + u32 val; + + pci_write_config_dword(bp->pdev, PCICFG_GRC_ADDRESS, addr); + pci_read_config_dword(bp->pdev, PCICFG_GRC_DATA, &val); + pci_write_config_dword(bp->pdev, PCICFG_GRC_ADDRESS, + PCICFG_VENDOR_ID_OFFSET); + + return val; +} + +static const u32 dmae_reg_go_c[] = { + DMAE_REG_GO_C0, DMAE_REG_GO_C1, DMAE_REG_GO_C2, DMAE_REG_GO_C3, + DMAE_REG_GO_C4, DMAE_REG_GO_C5, DMAE_REG_GO_C6, DMAE_REG_GO_C7, + DMAE_REG_GO_C8, DMAE_REG_GO_C9, DMAE_REG_GO_C10, DMAE_REG_GO_C11, + DMAE_REG_GO_C12, DMAE_REG_GO_C13, DMAE_REG_GO_C14, DMAE_REG_GO_C15 +}; + +/* copy command into DMAE command memory and set DMAE command go */ +static void bnx2x_post_dmae(struct bnx2x *bp, struct dmae_command *dmae, + int idx) +{ + u32 cmd_offset; + int i; + + cmd_offset = (DMAE_REG_CMD_MEM + sizeof(struct dmae_command) * idx); + for (i = 0; i < (sizeof(struct dmae_command)/4); i++) { + REG_WR(bp, cmd_offset + i*4, *(((u32 *)dmae) + i)); + + DP(BNX2X_MSG_OFF, "DMAE cmd[%d].%d (0x%08x) : 0x%08x\n", + idx, i, cmd_offset + i*4, *(((u32 *)dmae) + i)); + } + REG_WR(bp, dmae_reg_go_c[idx], 1); +} + +void bnx2x_write_dmae(struct bnx2x *bp, dma_addr_t dma_addr, u32 dst_addr, + u32 len32) +{ + struct dmae_command *dmae = &bp->init_dmae; + u32 *wb_comp = bnx2x_sp(bp, wb_comp); + int cnt = 200; + + if (!bp->dmae_ready) { + u32 *data = bnx2x_sp(bp, wb_data[0]); + + DP(BNX2X_MSG_OFF, "DMAE is not ready (dst_addr %08x len32 %d)" + " using indirect\n", dst_addr, len32); + bnx2x_init_ind_wr(bp, dst_addr, data, len32); + return; + } + + mutex_lock(&bp->dmae_mutex); + + memset(dmae, 0, sizeof(struct dmae_command)); + + dmae->opcode = (DMAE_CMD_SRC_PCI | DMAE_CMD_DST_GRC | + DMAE_CMD_C_DST_PCI | DMAE_CMD_C_ENABLE | + DMAE_CMD_SRC_RESET | DMAE_CMD_DST_RESET | +#ifdef __BIG_ENDIAN + DMAE_CMD_ENDIANITY_B_DW_SWAP | +#else + DMAE_CMD_ENDIANITY_DW_SWAP | +#endif + (BP_PORT(bp) ? DMAE_CMD_PORT_1 : DMAE_CMD_PORT_0) | + (BP_E1HVN(bp) << DMAE_CMD_E1HVN_SHIFT)); + dmae->src_addr_lo = U64_LO(dma_addr); + dmae->src_addr_hi = U64_HI(dma_addr); + dmae->dst_addr_lo = dst_addr >> 2; + dmae->dst_addr_hi = 0; + dmae->len = len32; + dmae->comp_addr_lo = U64_LO(bnx2x_sp_mapping(bp, wb_comp)); + dmae->comp_addr_hi = U64_HI(bnx2x_sp_mapping(bp, wb_comp)); + dmae->comp_val = DMAE_COMP_VAL; + + DP(BNX2X_MSG_OFF, "dmae: opcode 0x%08x\n" + DP_LEVEL "src_addr [%x:%08x] len [%d *4] " + "dst_addr [%x:%08x (%08x)]\n" + DP_LEVEL "comp_addr [%x:%08x] comp_val 0x%08x\n", + dmae->opcode, dmae->src_addr_hi, dmae->src_addr_lo, + dmae->len, dmae->dst_addr_hi, dmae->dst_addr_lo, dst_addr, + dmae->comp_addr_hi, dmae->comp_addr_lo, dmae->comp_val); + DP(BNX2X_MSG_OFF, "data [0x%08x 0x%08x 0x%08x 0x%08x]\n", + bp->slowpath->wb_data[0], bp->slowpath->wb_data[1], + bp->slowpath->wb_data[2], bp->slowpath->wb_data[3]); + + *wb_comp = 0; + + bnx2x_post_dmae(bp, dmae, INIT_DMAE_C(bp)); + + udelay(5); + + while (*wb_comp != DMAE_COMP_VAL) { + DP(BNX2X_MSG_OFF, "wb_comp 0x%08x\n", *wb_comp); + + /* adjust delay for emulation/FPGA */ + if (CHIP_REV_IS_SLOW(bp)) + msleep(100); + else + udelay(5); + + if (!cnt) { + BNX2X_ERR("dmae timeout!\n"); + break; + } + cnt--; + } + + mutex_unlock(&bp->dmae_mutex); +} + +void bnx2x_read_dmae(struct bnx2x *bp, u32 src_addr, u32 len32) +{ + struct dmae_command *dmae = &bp->init_dmae; + u32 *wb_comp = bnx2x_sp(bp, wb_comp); + int cnt = 200; + + if (!bp->dmae_ready) { + u32 *data = bnx2x_sp(bp, wb_data[0]); + int i; + + DP(BNX2X_MSG_OFF, "DMAE is not ready (src_addr %08x len32 %d)" + " using indirect\n", src_addr, len32); + for (i = 0; i < len32; i++) + data[i] = bnx2x_reg_rd_ind(bp, src_addr + i*4); + return; + } + + mutex_lock(&bp->dmae_mutex); + + memset(bnx2x_sp(bp, wb_data[0]), 0, sizeof(u32) * 4); + memset(dmae, 0, sizeof(struct dmae_command)); + + dmae->opcode = (DMAE_CMD_SRC_GRC | DMAE_CMD_DST_PCI | + DMAE_CMD_C_DST_PCI | DMAE_CMD_C_ENABLE | + DMAE_CMD_SRC_RESET | DMAE_CMD_DST_RESET | +#ifdef __BIG_ENDIAN + DMAE_CMD_ENDIANITY_B_DW_SWAP | +#else + DMAE_CMD_ENDIANITY_DW_SWAP | +#endif + (BP_PORT(bp) ? DMAE_CMD_PORT_1 : DMAE_CMD_PORT_0) | + (BP_E1HVN(bp) << DMAE_CMD_E1HVN_SHIFT)); + dmae->src_addr_lo = src_addr >> 2; + dmae->src_addr_hi = 0; + dmae->dst_addr_lo = U64_LO(bnx2x_sp_mapping(bp, wb_data)); + dmae->dst_addr_hi = U64_HI(bnx2x_sp_mapping(bp, wb_data)); + dmae->len = len32; + dmae->comp_addr_lo = U64_LO(bnx2x_sp_mapping(bp, wb_comp)); + dmae->comp_addr_hi = U64_HI(bnx2x_sp_mapping(bp, wb_comp)); + dmae->comp_val = DMAE_COMP_VAL; + + DP(BNX2X_MSG_OFF, "dmae: opcode 0x%08x\n" + DP_LEVEL "src_addr [%x:%08x] len [%d *4] " + "dst_addr [%x:%08x (%08x)]\n" + DP_LEVEL "comp_addr [%x:%08x] comp_val 0x%08x\n", + dmae->opcode, dmae->src_addr_hi, dmae->src_addr_lo, + dmae->len, dmae->dst_addr_hi, dmae->dst_addr_lo, src_addr, + dmae->comp_addr_hi, dmae->comp_addr_lo, dmae->comp_val); + + *wb_comp = 0; + + bnx2x_post_dmae(bp, dmae, INIT_DMAE_C(bp)); + + udelay(5); + + while (*wb_comp != DMAE_COMP_VAL) { + + /* adjust delay for emulation/FPGA */ + if (CHIP_REV_IS_SLOW(bp)) + msleep(100); + else + udelay(5); + + if (!cnt) { + BNX2X_ERR("dmae timeout!\n"); + break; + } + cnt--; + } + DP(BNX2X_MSG_OFF, "data [0x%08x 0x%08x 0x%08x 0x%08x]\n", + bp->slowpath->wb_data[0], bp->slowpath->wb_data[1], + bp->slowpath->wb_data[2], bp->slowpath->wb_data[3]); + + mutex_unlock(&bp->dmae_mutex); +} + +/* used only for slowpath so not inlined */ +static void bnx2x_wb_wr(struct bnx2x *bp, int reg, u32 val_hi, u32 val_lo) +{ + u32 wb_write[2]; + + wb_write[0] = val_hi; + wb_write[1] = val_lo; + REG_WR_DMAE(bp, reg, wb_write, 2); +} + +#ifdef USE_WB_RD +static u64 bnx2x_wb_rd(struct bnx2x *bp, int reg) +{ + u32 wb_data[2]; + + REG_RD_DMAE(bp, reg, wb_data, 2); + + return HILO_U64(wb_data[0], wb_data[1]); +} +#endif + +static int bnx2x_mc_assert(struct bnx2x *bp) +{ + char last_idx; + int i, rc = 0; + u32 row0, row1, row2, row3; + + /* XSTORM */ + last_idx = REG_RD8(bp, BAR_XSTRORM_INTMEM + + XSTORM_ASSERT_LIST_INDEX_OFFSET); + if (last_idx) + BNX2X_ERR("XSTORM_ASSERT_LIST_INDEX 0x%x\n", last_idx); + + /* print the asserts */ + for (i = 0; i < STROM_ASSERT_ARRAY_SIZE; i++) { + + row0 = REG_RD(bp, BAR_XSTRORM_INTMEM + + XSTORM_ASSERT_LIST_OFFSET(i)); + row1 = REG_RD(bp, BAR_XSTRORM_INTMEM + + XSTORM_ASSERT_LIST_OFFSET(i) + 4); + row2 = REG_RD(bp, BAR_XSTRORM_INTMEM + + XSTORM_ASSERT_LIST_OFFSET(i) + 8); + row3 = REG_RD(bp, BAR_XSTRORM_INTMEM + + XSTORM_ASSERT_LIST_OFFSET(i) + 12); + + if (row0 != COMMON_ASM_INVALID_ASSERT_OPCODE) { + BNX2X_ERR("XSTORM_ASSERT_INDEX 0x%x = 0x%08x" + " 0x%08x 0x%08x 0x%08x\n", + i, row3, row2, row1, row0); + rc++; + } else { + break; + } + } + + /* TSTORM */ + last_idx = REG_RD8(bp, BAR_TSTRORM_INTMEM + + TSTORM_ASSERT_LIST_INDEX_OFFSET); + if (last_idx) + BNX2X_ERR("TSTORM_ASSERT_LIST_INDEX 0x%x\n", last_idx); + + /* print the asserts */ + for (i = 0; i < STROM_ASSERT_ARRAY_SIZE; i++) { + + row0 = REG_RD(bp, BAR_TSTRORM_INTMEM + + TSTORM_ASSERT_LIST_OFFSET(i)); + row1 = REG_RD(bp, BAR_TSTRORM_INTMEM + + TSTORM_ASSERT_LIST_OFFSET(i) + 4); + row2 = REG_RD(bp, BAR_TSTRORM_INTMEM + + TSTORM_ASSERT_LIST_OFFSET(i) + 8); + row3 = REG_RD(bp, BAR_TSTRORM_INTMEM + + TSTORM_ASSERT_LIST_OFFSET(i) + 12); + + if (row0 != COMMON_ASM_INVALID_ASSERT_OPCODE) { + BNX2X_ERR("TSTORM_ASSERT_INDEX 0x%x = 0x%08x" + " 0x%08x 0x%08x 0x%08x\n", + i, row3, row2, row1, row0); + rc++; + } else { + break; + } + } + + /* CSTORM */ + last_idx = REG_RD8(bp, BAR_CSTRORM_INTMEM + + CSTORM_ASSERT_LIST_INDEX_OFFSET); + if (last_idx) + BNX2X_ERR("CSTORM_ASSERT_LIST_INDEX 0x%x\n", last_idx); + + /* print the asserts */ + for (i = 0; i < STROM_ASSERT_ARRAY_SIZE; i++) { + + row0 = REG_RD(bp, BAR_CSTRORM_INTMEM + + CSTORM_ASSERT_LIST_OFFSET(i)); + row1 = REG_RD(bp, BAR_CSTRORM_INTMEM + + CSTORM_ASSERT_LIST_OFFSET(i) + 4); + row2 = REG_RD(bp, BAR_CSTRORM_INTMEM + + CSTORM_ASSERT_LIST_OFFSET(i) + 8); + row3 = REG_RD(bp, BAR_CSTRORM_INTMEM + + CSTORM_ASSERT_LIST_OFFSET(i) + 12); + + if (row0 != COMMON_ASM_INVALID_ASSERT_OPCODE) { + BNX2X_ERR("CSTORM_ASSERT_INDEX 0x%x = 0x%08x" + " 0x%08x 0x%08x 0x%08x\n", + i, row3, row2, row1, row0); + rc++; + } else { + break; + } + } + + /* USTORM */ + last_idx = REG_RD8(bp, BAR_USTRORM_INTMEM + + USTORM_ASSERT_LIST_INDEX_OFFSET); + if (last_idx) + BNX2X_ERR("USTORM_ASSERT_LIST_INDEX 0x%x\n", last_idx); + + /* print the asserts */ + for (i = 0; i < STROM_ASSERT_ARRAY_SIZE; i++) { + + row0 = REG_RD(bp, BAR_USTRORM_INTMEM + + USTORM_ASSERT_LIST_OFFSET(i)); + row1 = REG_RD(bp, BAR_USTRORM_INTMEM + + USTORM_ASSERT_LIST_OFFSET(i) + 4); + row2 = REG_RD(bp, BAR_USTRORM_INTMEM + + USTORM_ASSERT_LIST_OFFSET(i) + 8); + row3 = REG_RD(bp, BAR_USTRORM_INTMEM + + USTORM_ASSERT_LIST_OFFSET(i) + 12); + + if (row0 != COMMON_ASM_INVALID_ASSERT_OPCODE) { + BNX2X_ERR("USTORM_ASSERT_INDEX 0x%x = 0x%08x" + " 0x%08x 0x%08x 0x%08x\n", + i, row3, row2, row1, row0); + rc++; + } else { + break; + } + } + + return rc; +} + +static void bnx2x_fw_dump(struct bnx2x *bp) +{ + u32 mark, offset; + u32 data[9]; + int word; + + mark = REG_RD(bp, MCP_REG_MCPR_SCRATCH + 0xf104); + mark = ((mark + 0x3) & ~0x3); + printk(KERN_ERR PFX "begin fw dump (mark 0x%x)\n" KERN_ERR, mark); + + for (offset = mark - 0x08000000; offset <= 0xF900; offset += 0x8*4) { + for (word = 0; word < 8; word++) + data[word] = htonl(REG_RD(bp, MCP_REG_MCPR_SCRATCH + + offset + 4*word)); + data[8] = 0x0; + printk(KERN_CONT "%s", (char *)data); + } + for (offset = 0xF108; offset <= mark - 0x08000000; offset += 0x8*4) { + for (word = 0; word < 8; word++) + data[word] = htonl(REG_RD(bp, MCP_REG_MCPR_SCRATCH + + offset + 4*word)); + data[8] = 0x0; + printk(KERN_CONT "%s", (char *)data); + } + printk("\n" KERN_ERR PFX "end of fw dump\n"); +} + +static void bnx2x_panic_dump(struct bnx2x *bp) +{ + int i; + u16 j, start, end; + + BNX2X_ERR("begin crash dump -----------------\n"); + + for_each_queue(bp, i) { + struct bnx2x_fastpath *fp = &bp->fp[i]; + struct eth_tx_db_data *hw_prods = fp->hw_tx_prods; + + BNX2X_ERR("queue[%d]: tx_pkt_prod(%x) tx_pkt_cons(%x)" + " tx_bd_prod(%x) tx_bd_cons(%x) *tx_cons_sb(%x)\n", + i, fp->tx_pkt_prod, fp->tx_pkt_cons, fp->tx_bd_prod, + fp->tx_bd_cons, le16_to_cpu(*fp->tx_cons_sb)); + BNX2X_ERR(" rx_comp_prod(%x) rx_comp_cons(%x)" + " *rx_cons_sb(%x) *rx_bd_cons_sb(%x)" + " rx_sge_prod(%x) last_max_sge(%x)\n", + fp->rx_comp_prod, fp->rx_comp_cons, + le16_to_cpu(*fp->rx_cons_sb), + le16_to_cpu(*fp->rx_bd_cons_sb), + fp->rx_sge_prod, fp->last_max_sge); + BNX2X_ERR(" fp_c_idx(%x) fp_u_idx(%x)" + " bd data(%x,%x) rx_alloc_failed(%lx)\n", + fp->fp_c_idx, fp->fp_u_idx, hw_prods->packets_prod, + hw_prods->bds_prod, fp->rx_alloc_failed); + + start = TX_BD(le16_to_cpu(*fp->tx_cons_sb) - 10); + end = TX_BD(le16_to_cpu(*fp->tx_cons_sb) + 245); + for (j = start; j < end; j++) { + struct sw_tx_bd *sw_bd = &fp->tx_buf_ring[j]; + + BNX2X_ERR("packet[%x]=[%p,%x]\n", j, + sw_bd->skb, sw_bd->first_bd); + } + + start = TX_BD(fp->tx_bd_cons - 10); + end = TX_BD(fp->tx_bd_cons + 254); + for (j = start; j < end; j++) { + u32 *tx_bd = (u32 *)&fp->tx_desc_ring[j]; + + BNX2X_ERR("tx_bd[%x]=[%x:%x:%x:%x]\n", + j, tx_bd[0], tx_bd[1], tx_bd[2], tx_bd[3]); + } + + start = RX_BD(le16_to_cpu(*fp->rx_cons_sb) - 10); + end = RX_BD(le16_to_cpu(*fp->rx_cons_sb) + 503); + for (j = start; j < end; j++) { + u32 *rx_bd = (u32 *)&fp->rx_desc_ring[j]; + struct sw_rx_bd *sw_bd = &fp->rx_buf_ring[j]; + + BNX2X_ERR("rx_bd[%x]=[%x:%x] sw_bd=[%p]\n", + j, rx_bd[1], rx_bd[0], sw_bd->skb); + } + + start = 0; + end = RX_SGE_CNT*NUM_RX_SGE_PAGES; + for (j = start; j < end; j++) { + u32 *rx_sge = (u32 *)&fp->rx_sge_ring[j]; + struct sw_rx_page *sw_page = &fp->rx_page_ring[j]; + + BNX2X_ERR("rx_sge[%x]=[%x:%x] sw_page=[%p]\n", + j, rx_sge[1], rx_sge[0], sw_page->page); + } + + start = RCQ_BD(fp->rx_comp_cons - 10); + end = RCQ_BD(fp->rx_comp_cons + 503); + for (j = start; j < end; j++) { + u32 *cqe = (u32 *)&fp->rx_comp_ring[j]; + + BNX2X_ERR("cqe[%x]=[%x:%x:%x:%x]\n", + j, cqe[0], cqe[1], cqe[2], cqe[3]); + } + } + + BNX2X_ERR("def_c_idx(%u) def_u_idx(%u) def_x_idx(%u)" + " def_t_idx(%u) def_att_idx(%u) attn_state(%u)" + " spq_prod_idx(%u)\n", + bp->def_c_idx, bp->def_u_idx, bp->def_x_idx, bp->def_t_idx, + bp->def_att_idx, bp->attn_state, bp->spq_prod_idx); + + bnx2x_fw_dump(bp); + bnx2x_mc_assert(bp); + BNX2X_ERR("end crash dump -----------------\n"); + + bp->stats_state = STATS_STATE_DISABLED; + DP(BNX2X_MSG_STATS, "stats_state - DISABLED\n"); +} + +static void bnx2x_int_enable(struct bnx2x *bp) +{ + int port = BP_PORT(bp); + u32 addr = port ? HC_REG_CONFIG_1 : HC_REG_CONFIG_0; + u32 val = REG_RD(bp, addr); + int msix = (bp->flags & USING_MSIX_FLAG) ? 1 : 0; + + if (msix) { + val &= ~HC_CONFIG_0_REG_SINGLE_ISR_EN_0; + val |= (HC_CONFIG_0_REG_MSI_MSIX_INT_EN_0 | + HC_CONFIG_0_REG_ATTN_BIT_EN_0); + } else { + val |= (HC_CONFIG_0_REG_SINGLE_ISR_EN_0 | + HC_CONFIG_0_REG_MSI_MSIX_INT_EN_0 | + HC_CONFIG_0_REG_INT_LINE_EN_0 | + HC_CONFIG_0_REG_ATTN_BIT_EN_0); + + DP(NETIF_MSG_INTR, "write %x to HC %d (addr 0x%x) MSI-X %d\n", + val, port, addr, msix); + + REG_WR(bp, addr, val); + + val &= ~HC_CONFIG_0_REG_MSI_MSIX_INT_EN_0; + } + + DP(NETIF_MSG_INTR, "write %x to HC %d (addr 0x%x) MSI-X %d\n", + val, port, addr, msix); + + REG_WR(bp, addr, val); + + if (CHIP_IS_E1H(bp)) { + /* init leading/trailing edge */ + if (IS_E1HMF(bp)) { + val = (0xfe0f | (1 << (BP_E1HVN(bp) + 4))); + if (bp->port.pmf) + /* enable nig attention */ + val |= 0x0100; + } else + val = 0xffff; + + REG_WR(bp, HC_REG_TRAILING_EDGE_0 + port*8, val); + REG_WR(bp, HC_REG_LEADING_EDGE_0 + port*8, val); + } +} + +static void bnx2x_int_disable(struct bnx2x *bp) +{ + int port = BP_PORT(bp); + u32 addr = port ? HC_REG_CONFIG_1 : HC_REG_CONFIG_0; + u32 val = REG_RD(bp, addr); + + val &= ~(HC_CONFIG_0_REG_SINGLE_ISR_EN_0 | + HC_CONFIG_0_REG_MSI_MSIX_INT_EN_0 | + HC_CONFIG_0_REG_INT_LINE_EN_0 | + HC_CONFIG_0_REG_ATTN_BIT_EN_0); + + DP(NETIF_MSG_INTR, "write %x to HC %d (addr 0x%x)\n", + val, port, addr); + + REG_WR(bp, addr, val); + if (REG_RD(bp, addr) != val) + BNX2X_ERR("BUG! proper val not read from IGU!\n"); +} + +static void bnx2x_int_disable_sync(struct bnx2x *bp) +{ + int msix = (bp->flags & USING_MSIX_FLAG) ? 1 : 0; + int i; + + /* disable interrupt handling */ + atomic_inc(&bp->intr_sem); + /* prevent the HW from sending interrupts */ + bnx2x_int_disable(bp); + + /* make sure all ISRs are done */ + if (msix) { + for_each_queue(bp, i) + synchronize_irq(bp->msix_table[i].vector); + + /* one more for the Slow Path IRQ */ + synchronize_irq(bp->msix_table[i].vector); + } else + synchronize_irq(bp->pdev->irq); + + /* make sure sp_task is not running */ + cancel_work_sync(&bp->sp_task); +} + +/* fast path */ + +/* + * General service functions + */ + +static inline void bnx2x_ack_sb(struct bnx2x *bp, u8 sb_id, + u8 storm, u16 index, u8 op, u8 update) +{ + u32 igu_addr = (IGU_ADDR_INT_ACK + IGU_FUNC_BASE * BP_FUNC(bp)) * 8; + struct igu_ack_register igu_ack; + + igu_ack.status_block_index = index; + igu_ack.sb_id_and_flags = + ((sb_id << IGU_ACK_REGISTER_STATUS_BLOCK_ID_SHIFT) | + (storm << IGU_ACK_REGISTER_STORM_ID_SHIFT) | + (update << IGU_ACK_REGISTER_UPDATE_INDEX_SHIFT) | + (op << IGU_ACK_REGISTER_INTERRUPT_MODE_SHIFT)); + + DP(BNX2X_MSG_OFF, "write 0x%08x to IGU addr 0x%x\n", + (*(u32 *)&igu_ack), BAR_IGU_INTMEM + igu_addr); + REG_WR(bp, BAR_IGU_INTMEM + igu_addr, (*(u32 *)&igu_ack)); +} + +static inline u16 bnx2x_update_fpsb_idx(struct bnx2x_fastpath *fp) +{ + struct host_status_block *fpsb = fp->status_blk; + u16 rc = 0; + + barrier(); /* status block is written to by the chip */ + if (fp->fp_c_idx != fpsb->c_status_block.status_block_index) { + fp->fp_c_idx = fpsb->c_status_block.status_block_index; + rc |= 1; + } + if (fp->fp_u_idx != fpsb->u_status_block.status_block_index) { + fp->fp_u_idx = fpsb->u_status_block.status_block_index; + rc |= 2; + } + return rc; +} + +static inline int bnx2x_has_work(struct bnx2x_fastpath *fp) +{ + u16 rx_cons_sb = le16_to_cpu(*fp->rx_cons_sb); + + if ((rx_cons_sb & MAX_RCQ_DESC_CNT) == MAX_RCQ_DESC_CNT) + rx_cons_sb++; + + if ((fp->rx_comp_cons != rx_cons_sb) || + (fp->tx_pkt_prod != le16_to_cpu(*fp->tx_cons_sb)) || + (fp->tx_pkt_prod != fp->tx_pkt_cons)) + return 1; + + return 0; +} + +static u16 bnx2x_ack_int(struct bnx2x *bp) +{ + u32 igu_addr = (IGU_ADDR_SIMD_MASK + IGU_FUNC_BASE * BP_FUNC(bp)) * 8; + u32 result = REG_RD(bp, BAR_IGU_INTMEM + igu_addr); + + DP(BNX2X_MSG_OFF, "read 0x%08x from IGU addr 0x%x\n", + result, BAR_IGU_INTMEM + igu_addr); + +#ifdef IGU_DEBUG +#warning IGU_DEBUG active + if (result == 0) { + BNX2X_ERR("read %x from IGU\n", result); + REG_WR(bp, TM_REG_TIMER_SOFT_RST, 0); + } +#endif + return result; +} + + +/* + * fast path service functions + */ + +/* free skb in the packet ring at pos idx + * return idx of last bd freed + */ +static u16 bnx2x_free_tx_pkt(struct bnx2x *bp, struct bnx2x_fastpath *fp, + u16 idx) +{ + struct sw_tx_bd *tx_buf = &fp->tx_buf_ring[idx]; + struct eth_tx_bd *tx_bd; + struct sk_buff *skb = tx_buf->skb; + u16 bd_idx = TX_BD(tx_buf->first_bd), new_cons; + int nbd; + + DP(BNX2X_MSG_OFF, "pkt_idx %d buff @(%p)->skb %p\n", + idx, tx_buf, skb); + + /* unmap first bd */ + DP(BNX2X_MSG_OFF, "free bd_idx %d\n", bd_idx); + tx_bd = &fp->tx_desc_ring[bd_idx]; + pci_unmap_single(bp->pdev, BD_UNMAP_ADDR(tx_bd), + BD_UNMAP_LEN(tx_bd), PCI_DMA_TODEVICE); + + nbd = le16_to_cpu(tx_bd->nbd) - 1; + new_cons = nbd + tx_buf->first_bd; +#ifdef BNX2X_STOP_ON_ERROR + if (nbd > (MAX_SKB_FRAGS + 2)) { + BNX2X_ERR("BAD nbd!\n"); + bnx2x_panic(); + } +#endif + + /* Skip a parse bd and the TSO split header bd + since they have no mapping */ + if (nbd) + bd_idx = TX_BD(NEXT_TX_IDX(bd_idx)); + + if (tx_bd->bd_flags.as_bitfield & (ETH_TX_BD_FLAGS_IP_CSUM | + ETH_TX_BD_FLAGS_TCP_CSUM | + ETH_TX_BD_FLAGS_SW_LSO)) { + if (--nbd) + bd_idx = TX_BD(NEXT_TX_IDX(bd_idx)); + tx_bd = &fp->tx_desc_ring[bd_idx]; + /* is this a TSO split header bd? */ + if (tx_bd->bd_flags.as_bitfield & ETH_TX_BD_FLAGS_SW_LSO) { + if (--nbd) + bd_idx = TX_BD(NEXT_TX_IDX(bd_idx)); + } + } + + /* now free frags */ + while (nbd > 0) { + + DP(BNX2X_MSG_OFF, "free frag bd_idx %d\n", bd_idx); + tx_bd = &fp->tx_desc_ring[bd_idx]; + pci_unmap_page(bp->pdev, BD_UNMAP_ADDR(tx_bd), + BD_UNMAP_LEN(tx_bd), PCI_DMA_TODEVICE); + if (--nbd) + bd_idx = TX_BD(NEXT_TX_IDX(bd_idx)); + } + + /* release skb */ + BUG_TRAP(skb); + dev_kfree_skb(skb); + tx_buf->first_bd = 0; + tx_buf->skb = NULL; + + return new_cons; +} + +static inline u16 bnx2x_tx_avail(struct bnx2x_fastpath *fp) +{ + s16 used; + u16 prod; + u16 cons; + + barrier(); /* Tell compiler that prod and cons can change */ + prod = fp->tx_bd_prod; + cons = fp->tx_bd_cons; + + /* NUM_TX_RINGS = number of "next-page" entries + It will be used as a threshold */ + used = SUB_S16(prod, cons) + (s16)NUM_TX_RINGS; + +#ifdef BNX2X_STOP_ON_ERROR + BUG_TRAP(used >= 0); + BUG_TRAP(used <= fp->bp->tx_ring_size); + BUG_TRAP((fp->bp->tx_ring_size - used) <= MAX_TX_AVAIL); +#endif + + return (s16)(fp->bp->tx_ring_size) - used; +} + +static void bnx2x_tx_int(struct bnx2x_fastpath *fp, int work) +{ + struct bnx2x *bp = fp->bp; + u16 hw_cons, sw_cons, bd_cons = fp->tx_bd_cons; + int done = 0; + +#ifdef BNX2X_STOP_ON_ERROR + if (unlikely(bp->panic)) + return; +#endif + + hw_cons = le16_to_cpu(*fp->tx_cons_sb); + sw_cons = fp->tx_pkt_cons; + + while (sw_cons != hw_cons) { + u16 pkt_cons; + + pkt_cons = TX_BD(sw_cons); + + /* prefetch(bp->tx_buf_ring[pkt_cons].skb); */ + + DP(NETIF_MSG_TX_DONE, "hw_cons %u sw_cons %u pkt_cons %u\n", + hw_cons, sw_cons, pkt_cons); + +/* if (NEXT_TX_IDX(sw_cons) != hw_cons) { + rmb(); + prefetch(fp->tx_buf_ring[NEXT_TX_IDX(sw_cons)].skb); + } +*/ + bd_cons = bnx2x_free_tx_pkt(bp, fp, pkt_cons); + sw_cons++; + done++; + + if (done == work) + break; + } + + fp->tx_pkt_cons = sw_cons; + fp->tx_bd_cons = bd_cons; + + /* Need to make the tx_cons update visible to start_xmit() + * before checking for netif_queue_stopped(). Without the + * memory barrier, there is a small possibility that start_xmit() + * will miss it and cause the queue to be stopped forever. + */ + smp_mb(); + + /* TBD need a thresh? */ + if (unlikely(netif_queue_stopped(bp->dev))) { + + netif_tx_lock(bp->dev); + + if (netif_queue_stopped(bp->dev) && + (bnx2x_tx_avail(fp) >= MAX_SKB_FRAGS + 3)) + netif_wake_queue(bp->dev); + + netif_tx_unlock(bp->dev); + } +} + +static void bnx2x_sp_event(struct bnx2x_fastpath *fp, + union eth_rx_cqe *rr_cqe) +{ + struct bnx2x *bp = fp->bp; + int cid = SW_CID(rr_cqe->ramrod_cqe.conn_and_cmd_data); + int command = CQE_CMD(rr_cqe->ramrod_cqe.conn_and_cmd_data); + + DP(BNX2X_MSG_SP, + "fp %d cid %d got ramrod #%d state is %x type is %d\n", + FP_IDX(fp), cid, command, bp->state, + rr_cqe->ramrod_cqe.ramrod_type); + + bp->spq_left++; + + if (FP_IDX(fp)) { + switch (command | fp->state) { + case (RAMROD_CMD_ID_ETH_CLIENT_SETUP | + BNX2X_FP_STATE_OPENING): + DP(NETIF_MSG_IFUP, "got MULTI[%d] setup ramrod\n", + cid); + fp->state = BNX2X_FP_STATE_OPEN; + break; + + case (RAMROD_CMD_ID_ETH_HALT | BNX2X_FP_STATE_HALTING): + DP(NETIF_MSG_IFDOWN, "got MULTI[%d] halt ramrod\n", + cid); + fp->state = BNX2X_FP_STATE_HALTED; + break; + + default: + BNX2X_ERR("unexpected MC reply (%d) " + "fp->state is %x\n", command, fp->state); + break; + } + mb(); /* force bnx2x_wait_ramrod() to see the change */ + return; + } + + switch (command | bp->state) { + case (RAMROD_CMD_ID_ETH_PORT_SETUP | BNX2X_STATE_OPENING_WAIT4_PORT): + DP(NETIF_MSG_IFUP, "got setup ramrod\n"); + bp->state = BNX2X_STATE_OPEN; + break; + + case (RAMROD_CMD_ID_ETH_HALT | BNX2X_STATE_CLOSING_WAIT4_HALT): + DP(NETIF_MSG_IFDOWN, "got halt ramrod\n"); + bp->state = BNX2X_STATE_CLOSING_WAIT4_DELETE; + fp->state = BNX2X_FP_STATE_HALTED; + break; + + case (RAMROD_CMD_ID_ETH_CFC_DEL | BNX2X_STATE_CLOSING_WAIT4_HALT): + DP(NETIF_MSG_IFDOWN, "got delete ramrod for MULTI[%d]\n", cid); + bnx2x_fp(bp, cid, state) = BNX2X_FP_STATE_CLOSED; + break; + + case (RAMROD_CMD_ID_ETH_SET_MAC | BNX2X_STATE_OPEN): + case (RAMROD_CMD_ID_ETH_SET_MAC | BNX2X_STATE_DIAG): + DP(NETIF_MSG_IFUP, "got set mac ramrod\n"); + bp->set_mac_pending = 0; + break; + + case (RAMROD_CMD_ID_ETH_SET_MAC | BNX2X_STATE_CLOSING_WAIT4_HALT): + DP(NETIF_MSG_IFDOWN, "got (un)set mac ramrod\n"); + break; + + default: + BNX2X_ERR("unexpected MC reply (%d) bp->state is %x\n", + command, bp->state); + break; + } + mb(); /* force bnx2x_wait_ramrod() to see the change */ +} + +static inline void bnx2x_free_rx_sge(struct bnx2x *bp, + struct bnx2x_fastpath *fp, u16 index) +{ + struct sw_rx_page *sw_buf = &fp->rx_page_ring[index]; + struct page *page = sw_buf->page; + struct eth_rx_sge *sge = &fp->rx_sge_ring[index]; + + /* Skip "next page" elements */ + if (!page) + return; + + pci_unmap_page(bp->pdev, pci_unmap_addr(sw_buf, mapping), + BCM_PAGE_SIZE*PAGES_PER_SGE, PCI_DMA_FROMDEVICE); + __free_pages(page, PAGES_PER_SGE_SHIFT); + + sw_buf->page = NULL; + sge->addr_hi = 0; + sge->addr_lo = 0; +} + +static inline void bnx2x_free_rx_sge_range(struct bnx2x *bp, + struct bnx2x_fastpath *fp, int last) +{ + int i; + + for (i = 0; i < last; i++) + bnx2x_free_rx_sge(bp, fp, i); +} + +static inline int bnx2x_alloc_rx_sge(struct bnx2x *bp, + struct bnx2x_fastpath *fp, u16 index) +{ + struct page *page = alloc_pages(GFP_ATOMIC, PAGES_PER_SGE_SHIFT); + struct sw_rx_page *sw_buf = &fp->rx_page_ring[index]; + struct eth_rx_sge *sge = &fp->rx_sge_ring[index]; + dma_addr_t mapping; + + if (unlikely(page == NULL)) + return -ENOMEM; + + mapping = pci_map_page(bp->pdev, page, 0, BCM_PAGE_SIZE*PAGES_PER_SGE, + PCI_DMA_FROMDEVICE); + if (unlikely(dma_mapping_error(mapping))) { + __free_pages(page, PAGES_PER_SGE_SHIFT); + return -ENOMEM; + } + + sw_buf->page = page; + pci_unmap_addr_set(sw_buf, mapping, mapping); + + sge->addr_hi = cpu_to_le32(U64_HI(mapping)); + sge->addr_lo = cpu_to_le32(U64_LO(mapping)); + + return 0; +} + +static inline int bnx2x_alloc_rx_skb(struct bnx2x *bp, + struct bnx2x_fastpath *fp, u16 index) +{ + struct sk_buff *skb; + struct sw_rx_bd *rx_buf = &fp->rx_buf_ring[index]; + struct eth_rx_bd *rx_bd = &fp->rx_desc_ring[index]; + dma_addr_t mapping; + + skb = netdev_alloc_skb(bp->dev, bp->rx_buf_size); + if (unlikely(skb == NULL)) + return -ENOMEM; + + mapping = pci_map_single(bp->pdev, skb->data, bp->rx_buf_use_size, + PCI_DMA_FROMDEVICE); + if (unlikely(dma_mapping_error(mapping))) { + dev_kfree_skb(skb); + return -ENOMEM; + } + + rx_buf->skb = skb; + pci_unmap_addr_set(rx_buf, mapping, mapping); + + rx_bd->addr_hi = cpu_to_le32(U64_HI(mapping)); + rx_bd->addr_lo = cpu_to_le32(U64_LO(mapping)); + + return 0; +} + +/* note that we are not allocating a new skb, + * we are just moving one from cons to prod + * we are not creating a new mapping, + * so there is no need to check for dma_mapping_error(). + */ +static void bnx2x_reuse_rx_skb(struct bnx2x_fastpath *fp, + struct sk_buff *skb, u16 cons, u16 prod) +{ + struct bnx2x *bp = fp->bp; + struct sw_rx_bd *cons_rx_buf = &fp->rx_buf_ring[cons]; + struct sw_rx_bd *prod_rx_buf = &fp->rx_buf_ring[prod]; + struct eth_rx_bd *cons_bd = &fp->rx_desc_ring[cons]; + struct eth_rx_bd *prod_bd = &fp->rx_desc_ring[prod]; + + pci_dma_sync_single_for_device(bp->pdev, + pci_unmap_addr(cons_rx_buf, mapping), + bp->rx_offset + RX_COPY_THRESH, + PCI_DMA_FROMDEVICE); + + prod_rx_buf->skb = cons_rx_buf->skb; + pci_unmap_addr_set(prod_rx_buf, mapping, + pci_unmap_addr(cons_rx_buf, mapping)); + *prod_bd = *cons_bd; +} + +static inline void bnx2x_update_last_max_sge(struct bnx2x_fastpath *fp, + u16 idx) +{ + u16 last_max = fp->last_max_sge; + + if (SUB_S16(idx, last_max) > 0) + fp->last_max_sge = idx; +} + +static void bnx2x_clear_sge_mask_next_elems(struct bnx2x_fastpath *fp) +{ + int i, j; + + for (i = 1; i <= NUM_RX_SGE_PAGES; i++) { + int idx = RX_SGE_CNT * i - 1; + + for (j = 0; j < 2; j++) { + SGE_MASK_CLEAR_BIT(fp, idx); + idx--; + } + } +} + +static void bnx2x_update_sge_prod(struct bnx2x_fastpath *fp, + struct eth_fast_path_rx_cqe *fp_cqe) +{ + struct bnx2x *bp = fp->bp; + u16 sge_len = BCM_PAGE_ALIGN(le16_to_cpu(fp_cqe->pkt_len) - + le16_to_cpu(fp_cqe->len_on_bd)) >> + BCM_PAGE_SHIFT; + u16 last_max, last_elem, first_elem; + u16 delta = 0; + u16 i; + + if (!sge_len) + return; + + /* First mark all used pages */ + for (i = 0; i < sge_len; i++) + SGE_MASK_CLEAR_BIT(fp, RX_SGE(le16_to_cpu(fp_cqe->sgl[i]))); + + DP(NETIF_MSG_RX_STATUS, "fp_cqe->sgl[%d] = %d\n", + sge_len - 1, le16_to_cpu(fp_cqe->sgl[sge_len - 1])); + + /* Here we assume that the last SGE index is the biggest */ + prefetch((void *)(fp->sge_mask)); + bnx2x_update_last_max_sge(fp, le16_to_cpu(fp_cqe->sgl[sge_len - 1])); + + last_max = RX_SGE(fp->last_max_sge); + last_elem = last_max >> RX_SGE_MASK_ELEM_SHIFT; + first_elem = RX_SGE(fp->rx_sge_prod) >> RX_SGE_MASK_ELEM_SHIFT; + + /* If ring is not full */ + if (last_elem + 1 != first_elem) + last_elem++; + + /* Now update the prod */ + for (i = first_elem; i != last_elem; i = NEXT_SGE_MASK_ELEM(i)) { + if (likely(fp->sge_mask[i])) + break; + + fp->sge_mask[i] = RX_SGE_MASK_ELEM_ONE_MASK; + delta += RX_SGE_MASK_ELEM_SZ; + } + + if (delta > 0) { + fp->rx_sge_prod += delta; + /* clear page-end entries */ + bnx2x_clear_sge_mask_next_elems(fp); + } + + DP(NETIF_MSG_RX_STATUS, + "fp->last_max_sge = %d fp->rx_sge_prod = %d\n", + fp->last_max_sge, fp->rx_sge_prod); +} + +static inline void bnx2x_init_sge_ring_bit_mask(struct bnx2x_fastpath *fp) +{ + /* Set the mask to all 1-s: it's faster to compare to 0 than to 0xf-s */ + memset(fp->sge_mask, 0xff, + (NUM_RX_SGE >> RX_SGE_MASK_ELEM_SHIFT)*sizeof(u64)); + + /* Clear the two last indeces in the page to 1: + these are the indeces that correspond to the "next" element, + hence will never be indicated and should be removed from + the calculations. */ + bnx2x_clear_sge_mask_next_elems(fp); +} + +static void bnx2x_tpa_start(struct bnx2x_fastpath *fp, u16 queue, + struct sk_buff *skb, u16 cons, u16 prod) +{ + struct bnx2x *bp = fp->bp; + struct sw_rx_bd *cons_rx_buf = &fp->rx_buf_ring[cons]; + struct sw_rx_bd *prod_rx_buf = &fp->rx_buf_ring[prod]; + struct eth_rx_bd *prod_bd = &fp->rx_desc_ring[prod]; + dma_addr_t mapping; + + /* move empty skb from pool to prod and map it */ + prod_rx_buf->skb = fp->tpa_pool[queue].skb; + mapping = pci_map_single(bp->pdev, fp->tpa_pool[queue].skb->data, + bp->rx_buf_use_size, PCI_DMA_FROMDEVICE); + pci_unmap_addr_set(prod_rx_buf, mapping, mapping); + + /* move partial skb from cons to pool (don't unmap yet) */ + fp->tpa_pool[queue] = *cons_rx_buf; + + /* mark bin state as start - print error if current state != stop */ + if (fp->tpa_state[queue] != BNX2X_TPA_STOP) + BNX2X_ERR("start of bin not in stop [%d]\n", queue); + + fp->tpa_state[queue] = BNX2X_TPA_START; + + /* point prod_bd to new skb */ + prod_bd->addr_hi = cpu_to_le32(U64_HI(mapping)); + prod_bd->addr_lo = cpu_to_le32(U64_LO(mapping)); + +#ifdef BNX2X_STOP_ON_ERROR + fp->tpa_queue_used |= (1 << queue); +#ifdef __powerpc64__ + DP(NETIF_MSG_RX_STATUS, "fp->tpa_queue_used = 0x%lx\n", +#else + DP(NETIF_MSG_RX_STATUS, "fp->tpa_queue_used = 0x%llx\n", +#endif + fp->tpa_queue_used); +#endif +} + +static int bnx2x_fill_frag_skb(struct bnx2x *bp, struct bnx2x_fastpath *fp, + struct sk_buff *skb, + struct eth_fast_path_rx_cqe *fp_cqe, + u16 cqe_idx) +{ + struct sw_rx_page *rx_pg, old_rx_pg; + struct page *sge; + u16 len_on_bd = le16_to_cpu(fp_cqe->len_on_bd); + u32 i, frag_len, frag_size, pages; + int err; + int j; + + frag_size = le16_to_cpu(fp_cqe->pkt_len) - len_on_bd; + pages = BCM_PAGE_ALIGN(frag_size) >> BCM_PAGE_SHIFT; + + /* This is needed in order to enable forwarding support */ + if (frag_size) + skb_shinfo(skb)->gso_size = min((u32)BCM_PAGE_SIZE, + max(frag_size, (u32)len_on_bd)); + +#ifdef BNX2X_STOP_ON_ERROR + if (pages > 8*PAGES_PER_SGE) { + BNX2X_ERR("SGL length is too long: %d. CQE index is %d\n", + pages, cqe_idx); + BNX2X_ERR("fp_cqe->pkt_len = %d fp_cqe->len_on_bd = %d\n", + fp_cqe->pkt_len, len_on_bd); + bnx2x_panic(); + return -EINVAL; + } +#endif + + /* Run through the SGL and compose the fragmented skb */ + for (i = 0, j = 0; i < pages; i += PAGES_PER_SGE, j++) { + u16 sge_idx = RX_SGE(le16_to_cpu(fp_cqe->sgl[j])); + + /* FW gives the indices of the SGE as if the ring is an array + (meaning that "next" element will consume 2 indices) */ + frag_len = min(frag_size, (u32)(BCM_PAGE_SIZE*PAGES_PER_SGE)); + rx_pg = &fp->rx_page_ring[sge_idx]; + sge = rx_pg->page; + old_rx_pg = *rx_pg; + + /* If we fail to allocate a substitute page, we simply stop + where we are and drop the whole packet */ + err = bnx2x_alloc_rx_sge(bp, fp, sge_idx); + if (unlikely(err)) { + fp->rx_alloc_failed++; + return err; + } + + /* Unmap the page as we r going to pass it to the stack */ + pci_unmap_page(bp->pdev, pci_unmap_addr(&old_rx_pg, mapping), + BCM_PAGE_SIZE*PAGES_PER_SGE, PCI_DMA_FROMDEVICE); + + /* Add one frag and update the appropriate fields in the skb */ + skb_fill_page_desc(skb, j, old_rx_pg.page, 0, frag_len); + + skb->data_len += frag_len; + skb->truesize += frag_len; + skb->len += frag_len; + + frag_size -= frag_len; + } + + return 0; +} + +static void bnx2x_tpa_stop(struct bnx2x *bp, struct bnx2x_fastpath *fp, + u16 queue, int pad, int len, union eth_rx_cqe *cqe, + u16 cqe_idx) +{ + struct sw_rx_bd *rx_buf = &fp->tpa_pool[queue]; + struct sk_buff *skb = rx_buf->skb; + /* alloc new skb */ + struct sk_buff *new_skb = netdev_alloc_skb(bp->dev, bp->rx_buf_size); + + /* Unmap skb in the pool anyway, as we are going to change + pool entry status to BNX2X_TPA_STOP even if new skb allocation + fails. */ + pci_unmap_single(bp->pdev, pci_unmap_addr(rx_buf, mapping), + bp->rx_buf_use_size, PCI_DMA_FROMDEVICE); + + /* if alloc failed drop the packet and keep the buffer in the bin */ + if (likely(new_skb)) { + + prefetch(skb); + prefetch(((char *)(skb)) + 128); + + /* else fix ip xsum and give it to the stack */ + /* (no need to map the new skb) */ +#ifdef BNX2X_STOP_ON_ERROR + if (pad + len > bp->rx_buf_size) { + BNX2X_ERR("skb_put is about to fail... " + "pad %d len %d rx_buf_size %d\n", + pad, len, bp->rx_buf_size); + bnx2x_panic(); + return; + } +#endif + + skb_reserve(skb, pad); + skb_put(skb, len); + + skb->protocol = eth_type_trans(skb, bp->dev); + skb->ip_summed = CHECKSUM_UNNECESSARY; + + { + struct iphdr *iph; + + iph = (struct iphdr *)skb->data; + iph->check = 0; + iph->check = ip_fast_csum((u8 *)iph, iph->ihl); + } + + if (!bnx2x_fill_frag_skb(bp, fp, skb, + &cqe->fast_path_cqe, cqe_idx)) { +#ifdef BCM_VLAN + if ((bp->vlgrp != NULL) && + (le16_to_cpu(cqe->fast_path_cqe.pars_flags.flags) & + PARSING_FLAGS_VLAN)) + vlan_hwaccel_receive_skb(skb, bp->vlgrp, + le16_to_cpu(cqe->fast_path_cqe. + vlan_tag)); + else +#endif + netif_receive_skb(skb); + } else { + DP(NETIF_MSG_RX_STATUS, "Failed to allocate new pages" + " - dropping packet!\n"); + dev_kfree_skb(skb); + } + + bp->dev->last_rx = jiffies; + + /* put new skb in bin */ + fp->tpa_pool[queue].skb = new_skb; + + } else { + DP(NETIF_MSG_RX_STATUS, + "Failed to allocate new skb - dropping packet!\n"); + fp->rx_alloc_failed++; + } + + fp->tpa_state[queue] = BNX2X_TPA_STOP; +} + +static inline void bnx2x_update_rx_prod(struct bnx2x *bp, + struct bnx2x_fastpath *fp, + u16 bd_prod, u16 rx_comp_prod, + u16 rx_sge_prod) +{ + struct tstorm_eth_rx_producers rx_prods = {0}; + int i; + + /* Update producers */ + rx_prods.bd_prod = bd_prod; + rx_prods.cqe_prod = rx_comp_prod; + rx_prods.sge_prod = rx_sge_prod; + + for (i = 0; i < sizeof(struct tstorm_eth_rx_producers)/4; i++) + REG_WR(bp, BAR_TSTRORM_INTMEM + + TSTORM_RX_PRODS_OFFSET(BP_PORT(bp), FP_CL_ID(fp)) + i*4, + ((u32 *)&rx_prods)[i]); + + DP(NETIF_MSG_RX_STATUS, + "Wrote: bd_prod %u cqe_prod %u sge_prod %u\n", + bd_prod, rx_comp_prod, rx_sge_prod); +} + +static int bnx2x_rx_int(struct bnx2x_fastpath *fp, int budget) +{ + struct bnx2x *bp = fp->bp; + u16 bd_cons, bd_prod, bd_prod_fw, comp_ring_cons; + u16 hw_comp_cons, sw_comp_cons, sw_comp_prod; + int rx_pkt = 0; + u16 queue; + +#ifdef BNX2X_STOP_ON_ERROR + if (unlikely(bp->panic)) + return 0; +#endif + + /* CQ "next element" is of the size of the regular element, + that's why it's ok here */ + hw_comp_cons = le16_to_cpu(*fp->rx_cons_sb); + if ((hw_comp_cons & MAX_RCQ_DESC_CNT) == MAX_RCQ_DESC_CNT) + hw_comp_cons++; + + bd_cons = fp->rx_bd_cons; + bd_prod = fp->rx_bd_prod; + bd_prod_fw = bd_prod; + sw_comp_cons = fp->rx_comp_cons; + sw_comp_prod = fp->rx_comp_prod; + + /* Memory barrier necessary as speculative reads of the rx + * buffer can be ahead of the index in the status block + */ + rmb(); + + DP(NETIF_MSG_RX_STATUS, + "queue[%d]: hw_comp_cons %u sw_comp_cons %u\n", + FP_IDX(fp), hw_comp_cons, sw_comp_cons); + + while (sw_comp_cons != hw_comp_cons) { + struct sw_rx_bd *rx_buf = NULL; + struct sk_buff *skb; + union eth_rx_cqe *cqe; + u8 cqe_fp_flags; + u16 len, pad; + + comp_ring_cons = RCQ_BD(sw_comp_cons); + bd_prod = RX_BD(bd_prod); + bd_cons = RX_BD(bd_cons); + + cqe = &fp->rx_comp_ring[comp_ring_cons]; + cqe_fp_flags = cqe->fast_path_cqe.type_error_flags; + + DP(NETIF_MSG_RX_STATUS, "CQE type %x err %x status %x" + " queue %x vlan %x len %u\n", CQE_TYPE(cqe_fp_flags), + cqe_fp_flags, cqe->fast_path_cqe.status_flags, + cqe->fast_path_cqe.rss_hash_result, + le16_to_cpu(cqe->fast_path_cqe.vlan_tag), + le16_to_cpu(cqe->fast_path_cqe.pkt_len)); + + /* is this a slowpath msg? */ + if (unlikely(CQE_TYPE(cqe_fp_flags))) { + bnx2x_sp_event(fp, cqe); + goto next_cqe; + + /* this is an rx packet */ + } else { + rx_buf = &fp->rx_buf_ring[bd_cons]; + skb = rx_buf->skb; + len = le16_to_cpu(cqe->fast_path_cqe.pkt_len); + pad = cqe->fast_path_cqe.placement_offset; + + /* If CQE is marked both TPA_START and TPA_END + it is a non-TPA CQE */ + if ((!fp->disable_tpa) && + (TPA_TYPE(cqe_fp_flags) != + (TPA_TYPE_START | TPA_TYPE_END))) { + queue = cqe->fast_path_cqe.queue_index; + + if (TPA_TYPE(cqe_fp_flags) == TPA_TYPE_START) { + DP(NETIF_MSG_RX_STATUS, + "calling tpa_start on queue %d\n", + queue); + + bnx2x_tpa_start(fp, queue, skb, + bd_cons, bd_prod); + goto next_rx; + } + + if (TPA_TYPE(cqe_fp_flags) == TPA_TYPE_END) { + DP(NETIF_MSG_RX_STATUS, + "calling tpa_stop on queue %d\n", + queue); + + if (!BNX2X_RX_SUM_FIX(cqe)) + BNX2X_ERR("STOP on none TCP " + "data\n"); + + /* This is a size of the linear data + on this skb */ + len = le16_to_cpu(cqe->fast_path_cqe. + len_on_bd); + bnx2x_tpa_stop(bp, fp, queue, pad, + len, cqe, comp_ring_cons); +#ifdef BNX2X_STOP_ON_ERROR + if (bp->panic) + return -EINVAL; +#endif + + bnx2x_update_sge_prod(fp, + &cqe->fast_path_cqe); + goto next_cqe; + } + } + + pci_dma_sync_single_for_device(bp->pdev, + pci_unmap_addr(rx_buf, mapping), + pad + RX_COPY_THRESH, + PCI_DMA_FROMDEVICE); + prefetch(skb); + prefetch(((char *)(skb)) + 128); + + /* is this an error packet? */ + if (unlikely(cqe_fp_flags & ETH_RX_ERROR_FALGS)) { + /* do we sometimes forward error packets anyway? */ + DP(NETIF_MSG_RX_ERR, + "ERROR flags %x rx packet %u\n", + cqe_fp_flags, sw_comp_cons); + /* TBD make sure MC counts this as a drop */ + goto reuse_rx; + } + + /* Since we don't have a jumbo ring + * copy small packets if mtu > 1500 + */ + if ((bp->dev->mtu > ETH_MAX_PACKET_SIZE) && + (len <= RX_COPY_THRESH)) { + struct sk_buff *new_skb; + + new_skb = netdev_alloc_skb(bp->dev, + len + pad); + if (new_skb == NULL) { + DP(NETIF_MSG_RX_ERR, + "ERROR packet dropped " + "because of alloc failure\n"); + fp->rx_alloc_failed++; + goto reuse_rx; + } + + /* aligned copy */ + skb_copy_from_linear_data_offset(skb, pad, + new_skb->data + pad, len); + skb_reserve(new_skb, pad); + skb_put(new_skb, len); + + bnx2x_reuse_rx_skb(fp, skb, bd_cons, bd_prod); + + skb = new_skb; + + } else if (bnx2x_alloc_rx_skb(bp, fp, bd_prod) == 0) { + pci_unmap_single(bp->pdev, + pci_unmap_addr(rx_buf, mapping), + bp->rx_buf_use_size, + PCI_DMA_FROMDEVICE); + skb_reserve(skb, pad); + skb_put(skb, len); + + } else { + DP(NETIF_MSG_RX_ERR, + "ERROR packet dropped because " + "of alloc failure\n"); + fp->rx_alloc_failed++; +reuse_rx: + bnx2x_reuse_rx_skb(fp, skb, bd_cons, bd_prod); + goto next_rx; + } + + skb->protocol = eth_type_trans(skb, bp->dev); + + skb->ip_summed = CHECKSUM_NONE; + if (bp->rx_csum && BNX2X_RX_SUM_OK(cqe)) + skb->ip_summed = CHECKSUM_UNNECESSARY; + + /* TBD do we pass bad csum packets in promisc */ + } + +#ifdef BCM_VLAN + if ((bp->vlgrp != NULL) && + (le16_to_cpu(cqe->fast_path_cqe.pars_flags.flags) & + PARSING_FLAGS_VLAN)) + vlan_hwaccel_receive_skb(skb, bp->vlgrp, + le16_to_cpu(cqe->fast_path_cqe.vlan_tag)); + else +#endif + netif_receive_skb(skb); + + bp->dev->last_rx = jiffies; + +next_rx: + rx_buf->skb = NULL; + + bd_cons = NEXT_RX_IDX(bd_cons); + bd_prod = NEXT_RX_IDX(bd_prod); + bd_prod_fw = NEXT_RX_IDX(bd_prod_fw); + rx_pkt++; +next_cqe: + sw_comp_prod = NEXT_RCQ_IDX(sw_comp_prod); + sw_comp_cons = NEXT_RCQ_IDX(sw_comp_cons); + + if (rx_pkt == budget) + break; + } /* while */ + + fp->rx_bd_cons = bd_cons; + fp->rx_bd_prod = bd_prod_fw; + fp->rx_comp_cons = sw_comp_cons; + fp->rx_comp_prod = sw_comp_prod; + + /* Update producers */ + bnx2x_update_rx_prod(bp, fp, bd_prod_fw, sw_comp_prod, + fp->rx_sge_prod); + mmiowb(); /* keep prod updates ordered */ + + fp->rx_pkt += rx_pkt; + fp->rx_calls++; + + return rx_pkt; +} + +static irqreturn_t bnx2x_msix_fp_int(int irq, void *fp_cookie) +{ + struct bnx2x_fastpath *fp = fp_cookie; + struct bnx2x *bp = fp->bp; + struct net_device *dev = bp->dev; + int index = FP_IDX(fp); + + DP(BNX2X_MSG_FP, "got an MSI-X interrupt on IDX:SB [%d:%d]\n", + index, FP_SB_ID(fp)); + bnx2x_ack_sb(bp, FP_SB_ID(fp), USTORM_ID, 0, IGU_INT_DISABLE, 0); + +#ifdef BNX2X_STOP_ON_ERROR + if (unlikely(bp->panic)) + return IRQ_HANDLED; +#endif + + prefetch(fp->rx_cons_sb); + prefetch(fp->tx_cons_sb); + prefetch(&fp->status_blk->c_status_block.status_block_index); + prefetch(&fp->status_blk->u_status_block.status_block_index); + + netif_rx_schedule(dev, &bnx2x_fp(bp, index, napi)); + + return IRQ_HANDLED; +} + +static irqreturn_t bnx2x_interrupt(int irq, void *dev_instance) +{ + struct net_device *dev = dev_instance; + struct bnx2x *bp = netdev_priv(dev); + u16 status = bnx2x_ack_int(bp); + u16 mask; + + /* Return here if interrupt is shared and it's not for us */ + if (unlikely(status == 0)) { + DP(NETIF_MSG_INTR, "not our interrupt!\n"); + return IRQ_NONE; + } + DP(NETIF_MSG_INTR, "got an interrupt status %u\n", status); + +#ifdef BNX2X_STOP_ON_ERROR + if (unlikely(bp->panic)) + return IRQ_HANDLED; +#endif + + /* Return here if interrupt is disabled */ + if (unlikely(atomic_read(&bp->intr_sem) != 0)) { + DP(NETIF_MSG_INTR, "called but intr_sem not 0, returning\n"); + return IRQ_HANDLED; + } + + mask = 0x2 << bp->fp[0].sb_id; + if (status & mask) { + struct bnx2x_fastpath *fp = &bp->fp[0]; + + prefetch(fp->rx_cons_sb); + prefetch(fp->tx_cons_sb); + prefetch(&fp->status_blk->c_status_block.status_block_index); + prefetch(&fp->status_blk->u_status_block.status_block_index); + + netif_rx_schedule(dev, &bnx2x_fp(bp, 0, napi)); + + status &= ~mask; + } + + + if (unlikely(status & 0x1)) { + schedule_work(&bp->sp_task); + + status &= ~0x1; + if (!status) + return IRQ_HANDLED; + } + + if (status) + DP(NETIF_MSG_INTR, "got an unknown interrupt! (status %u)\n", + status); + + return IRQ_HANDLED; +} + +/* end of fast path */ + +static void bnx2x_stats_handle(struct bnx2x *bp, enum bnx2x_stats_event event); + +/* Link */ + +/* + * General service functions + */ + +static int bnx2x_hw_lock(struct bnx2x *bp, u32 resource) +{ + u32 lock_status; + u32 resource_bit = (1 << resource); + u8 port = BP_PORT(bp); + int cnt; + + /* Validating that the resource is within range */ + if (resource > HW_LOCK_MAX_RESOURCE_VALUE) { + DP(NETIF_MSG_HW, + "resource(0x%x) > HW_LOCK_MAX_RESOURCE_VALUE(0x%x)\n", + resource, HW_LOCK_MAX_RESOURCE_VALUE); + return -EINVAL; + } + + /* Validating that the resource is not already taken */ + lock_status = REG_RD(bp, MISC_REG_DRIVER_CONTROL_1 + port*8); + if (lock_status & resource_bit) { + DP(NETIF_MSG_HW, "lock_status 0x%x resource_bit 0x%x\n", + lock_status, resource_bit); + return -EEXIST; + } + + /* Try for 1 second every 5ms */ + for (cnt = 0; cnt < 200; cnt++) { + /* Try to acquire the lock */ + REG_WR(bp, MISC_REG_DRIVER_CONTROL_1 + port*8 + 4, + resource_bit); + lock_status = REG_RD(bp, MISC_REG_DRIVER_CONTROL_1 + port*8); + if (lock_status & resource_bit) + return 0; + + msleep(5); + } + DP(NETIF_MSG_HW, "Timeout\n"); + return -EAGAIN; +} + +static int bnx2x_hw_unlock(struct bnx2x *bp, u32 resource) +{ + u32 lock_status; + u32 resource_bit = (1 << resource); + u8 port = BP_PORT(bp); + + /* Validating that the resource is within range */ + if (resource > HW_LOCK_MAX_RESOURCE_VALUE) { + DP(NETIF_MSG_HW, + "resource(0x%x) > HW_LOCK_MAX_RESOURCE_VALUE(0x%x)\n", + resource, HW_LOCK_MAX_RESOURCE_VALUE); + return -EINVAL; + } + + /* Validating that the resource is currently taken */ + lock_status = REG_RD(bp, MISC_REG_DRIVER_CONTROL_1 + port*8); + if (!(lock_status & resource_bit)) { + DP(NETIF_MSG_HW, "lock_status 0x%x resource_bit 0x%x\n", + lock_status, resource_bit); + return -EFAULT; + } + + REG_WR(bp, MISC_REG_DRIVER_CONTROL_1 + port*8, resource_bit); + return 0; +} + +/* HW Lock for shared dual port PHYs */ +static void bnx2x_phy_hw_lock(struct bnx2x *bp) +{ + u32 ext_phy_type = XGXS_EXT_PHY_TYPE(bp->link_params.ext_phy_config); + + mutex_lock(&bp->port.phy_mutex); + + if ((ext_phy_type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072) || + (ext_phy_type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073)) + bnx2x_hw_lock(bp, HW_LOCK_RESOURCE_8072_MDIO); +} + +static void bnx2x_phy_hw_unlock(struct bnx2x *bp) +{ + u32 ext_phy_type = XGXS_EXT_PHY_TYPE(bp->link_params.ext_phy_config); + + if ((ext_phy_type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072) || + (ext_phy_type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073)) + bnx2x_hw_unlock(bp, HW_LOCK_RESOURCE_8072_MDIO); + + mutex_unlock(&bp->port.phy_mutex); +} + +int bnx2x_set_gpio(struct bnx2x *bp, int gpio_num, u32 mode) +{ + /* The GPIO should be swapped if swap register is set and active */ + int gpio_port = (REG_RD(bp, NIG_REG_PORT_SWAP) && + REG_RD(bp, NIG_REG_STRAP_OVERRIDE)) ^ BP_PORT(bp); + int gpio_shift = gpio_num + + (gpio_port ? MISC_REGISTERS_GPIO_PORT_SHIFT : 0); + u32 gpio_mask = (1 << gpio_shift); + u32 gpio_reg; + + if (gpio_num > MISC_REGISTERS_GPIO_3) { + BNX2X_ERR("Invalid GPIO %d\n", gpio_num); + return -EINVAL; + } + + bnx2x_hw_lock(bp, HW_LOCK_RESOURCE_GPIO); + /* read GPIO and mask except the float bits */ + gpio_reg = (REG_RD(bp, MISC_REG_GPIO) & MISC_REGISTERS_GPIO_FLOAT); + + switch (mode) { + case MISC_REGISTERS_GPIO_OUTPUT_LOW: + DP(NETIF_MSG_LINK, "Set GPIO %d (shift %d) -> output low\n", + gpio_num, gpio_shift); + /* clear FLOAT and set CLR */ + gpio_reg &= ~(gpio_mask << MISC_REGISTERS_GPIO_FLOAT_POS); + gpio_reg |= (gpio_mask << MISC_REGISTERS_GPIO_CLR_POS); + break; + + case MISC_REGISTERS_GPIO_OUTPUT_HIGH: + DP(NETIF_MSG_LINK, "Set GPIO %d (shift %d) -> output high\n", + gpio_num, gpio_shift); + /* clear FLOAT and set SET */ + gpio_reg &= ~(gpio_mask << MISC_REGISTERS_GPIO_FLOAT_POS); + gpio_reg |= (gpio_mask << MISC_REGISTERS_GPIO_SET_POS); + break; + + case MISC_REGISTERS_GPIO_INPUT_HI_Z : + DP(NETIF_MSG_LINK, "Set GPIO %d (shift %d) -> input\n", + gpio_num, gpio_shift); + /* set FLOAT */ + gpio_reg |= (gpio_mask << MISC_REGISTERS_GPIO_FLOAT_POS); + break; + + default: + break; + } + + REG_WR(bp, MISC_REG_GPIO, gpio_reg); + bnx2x_hw_unlock(bp, HW_LOCK_RESOURCE_GPIO); + + return 0; +} + +static int bnx2x_set_spio(struct bnx2x *bp, int spio_num, u32 mode) +{ + u32 spio_mask = (1 << spio_num); + u32 spio_reg; + + if ((spio_num < MISC_REGISTERS_SPIO_4) || + (spio_num > MISC_REGISTERS_SPIO_7)) { + BNX2X_ERR("Invalid SPIO %d\n", spio_num); + return -EINVAL; + } + + bnx2x_hw_lock(bp, HW_LOCK_RESOURCE_SPIO); + /* read SPIO and mask except the float bits */ + spio_reg = (REG_RD(bp, MISC_REG_SPIO) & MISC_REGISTERS_SPIO_FLOAT); + + switch (mode) { + case MISC_REGISTERS_SPIO_OUTPUT_LOW : + DP(NETIF_MSG_LINK, "Set SPIO %d -> output low\n", spio_num); + /* clear FLOAT and set CLR */ + spio_reg &= ~(spio_mask << MISC_REGISTERS_SPIO_FLOAT_POS); + spio_reg |= (spio_mask << MISC_REGISTERS_SPIO_CLR_POS); + break; + + case MISC_REGISTERS_SPIO_OUTPUT_HIGH : + DP(NETIF_MSG_LINK, "Set SPIO %d -> output high\n", spio_num); + /* clear FLOAT and set SET */ + spio_reg &= ~(spio_mask << MISC_REGISTERS_SPIO_FLOAT_POS); + spio_reg |= (spio_mask << MISC_REGISTERS_SPIO_SET_POS); + break; + + case MISC_REGISTERS_SPIO_INPUT_HI_Z: + DP(NETIF_MSG_LINK, "Set SPIO %d -> input\n", spio_num); + /* set FLOAT */ + spio_reg |= (spio_mask << MISC_REGISTERS_SPIO_FLOAT_POS); + break; + + default: + break; + } + + REG_WR(bp, MISC_REG_SPIO, spio_reg); + bnx2x_hw_unlock(bp, HW_LOCK_RESOURCE_SPIO); + + return 0; +} + +static void bnx2x_calc_fc_adv(struct bnx2x *bp) +{ + switch (bp->link_vars.ieee_fc) { + case MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_NONE: + bp->port.advertising &= ~(ADVERTISED_Asym_Pause | + ADVERTISED_Pause); + break; + case MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH: + bp->port.advertising |= (ADVERTISED_Asym_Pause | + ADVERTISED_Pause); + break; + case MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC: + bp->port.advertising |= ADVERTISED_Asym_Pause; + break; + default: + bp->port.advertising &= ~(ADVERTISED_Asym_Pause | + ADVERTISED_Pause); + break; + } +} + +static void bnx2x_link_report(struct bnx2x *bp) +{ + if (bp->link_vars.link_up) { + if (bp->state == BNX2X_STATE_OPEN) + netif_carrier_on(bp->dev); + printk(KERN_INFO PFX "%s NIC Link is Up, ", bp->dev->name); + + printk("%d Mbps ", bp->link_vars.line_speed); + + if (bp->link_vars.duplex == DUPLEX_FULL) + printk("full duplex"); + else + printk("half duplex"); + + if (bp->link_vars.flow_ctrl != FLOW_CTRL_NONE) { + if (bp->link_vars.flow_ctrl & FLOW_CTRL_RX) { + printk(", receive "); + if (bp->link_vars.flow_ctrl & FLOW_CTRL_TX) + printk("& transmit "); + } else { + printk(", transmit "); + } + printk("flow control ON"); + } + printk("\n"); + + } else { /* link_down */ + netif_carrier_off(bp->dev); + printk(KERN_ERR PFX "%s NIC Link is Down\n", bp->dev->name); + } +} + +static u8 bnx2x_initial_phy_init(struct bnx2x *bp) +{ + u8 rc; + + /* Initialize link parameters structure variables */ + bp->link_params.mtu = bp->dev->mtu; + + bnx2x_phy_hw_lock(bp); + rc = bnx2x_phy_init(&bp->link_params, &bp->link_vars); + bnx2x_phy_hw_unlock(bp); + + if (bp->link_vars.link_up) + bnx2x_link_report(bp); + + bnx2x_calc_fc_adv(bp); + + return rc; +} + +static void bnx2x_link_set(struct bnx2x *bp) +{ + bnx2x_phy_hw_lock(bp); + bnx2x_phy_init(&bp->link_params, &bp->link_vars); + bnx2x_phy_hw_unlock(bp); + + bnx2x_calc_fc_adv(bp); +} + +static void bnx2x__link_reset(struct bnx2x *bp) +{ + bnx2x_phy_hw_lock(bp); + bnx2x_link_reset(&bp->link_params, &bp->link_vars); + bnx2x_phy_hw_unlock(bp); +} + +static u8 bnx2x_link_test(struct bnx2x *bp) +{ + u8 rc; + + bnx2x_phy_hw_lock(bp); + rc = bnx2x_test_link(&bp->link_params, &bp->link_vars); + bnx2x_phy_hw_unlock(bp); + + return rc; +} + +/* Calculates the sum of vn_min_rates. + It's needed for further normalizing of the min_rates. + + Returns: + sum of vn_min_rates + or + 0 - if all the min_rates are 0. + In the later case fainess algorithm should be deactivated. + If not all min_rates are zero then those that are zeroes will + be set to 1. + */ +static u32 bnx2x_calc_vn_wsum(struct bnx2x *bp) +{ + int i, port = BP_PORT(bp); + u32 wsum = 0; + int all_zero = 1; + + for (i = 0; i < E1HVN_MAX; i++) { + u32 vn_cfg = + SHMEM_RD(bp, mf_cfg.func_mf_config[2*i + port].config); + u32 vn_min_rate = ((vn_cfg & FUNC_MF_CFG_MIN_BW_MASK) >> + FUNC_MF_CFG_MIN_BW_SHIFT) * 100; + if (!(vn_cfg & FUNC_MF_CFG_FUNC_HIDE)) { + /* If min rate is zero - set it to 1 */ + if (!vn_min_rate) + vn_min_rate = DEF_MIN_RATE; + else + all_zero = 0; + + wsum += vn_min_rate; + } + } + + /* ... only if all min rates are zeros - disable FAIRNESS */ + if (all_zero) + return 0; + + return wsum; +} + +static void bnx2x_init_port_minmax(struct bnx2x *bp, + int en_fness, + u16 port_rate, + struct cmng_struct_per_port *m_cmng_port) +{ + u32 r_param = port_rate / 8; + int port = BP_PORT(bp); + int i; + + memset(m_cmng_port, 0, sizeof(struct cmng_struct_per_port)); + + /* Enable minmax only if we are in e1hmf mode */ + if (IS_E1HMF(bp)) { + u32 fair_periodic_timeout_usec; + u32 t_fair; + + /* Enable rate shaping and fairness */ + m_cmng_port->flags.cmng_vn_enable = 1; + m_cmng_port->flags.fairness_enable = en_fness ? 1 : 0; + m_cmng_port->flags.rate_shaping_enable = 1; + + if (!en_fness) + DP(NETIF_MSG_IFUP, "All MIN values are zeroes" + " fairness will be disabled\n"); + + /* 100 usec in SDM ticks = 25 since each tick is 4 usec */ + m_cmng_port->rs_vars.rs_periodic_timeout = + RS_PERIODIC_TIMEOUT_USEC / 4; + + /* this is the threshold below which no timer arming will occur + 1.25 coefficient is for the threshold to be a little bigger + than the real time, to compensate for timer in-accuracy */ + m_cmng_port->rs_vars.rs_threshold = + (RS_PERIODIC_TIMEOUT_USEC * r_param * 5) / 4; + + /* resolution of fairness timer */ + fair_periodic_timeout_usec = QM_ARB_BYTES / r_param; + /* for 10G it is 1000usec. for 1G it is 10000usec. */ + t_fair = T_FAIR_COEF / port_rate; + + /* this is the threshold below which we won't arm + the timer anymore */ + m_cmng_port->fair_vars.fair_threshold = QM_ARB_BYTES; + + /* we multiply by 1e3/8 to get bytes/msec. + We don't want the credits to pass a credit + of the T_FAIR*FAIR_MEM (algorithm resolution) */ + m_cmng_port->fair_vars.upper_bound = + r_param * t_fair * FAIR_MEM; + /* since each tick is 4 usec */ + m_cmng_port->fair_vars.fairness_timeout = + fair_periodic_timeout_usec / 4; + + } else { + /* Disable rate shaping and fairness */ + m_cmng_port->flags.cmng_vn_enable = 0; + m_cmng_port->flags.fairness_enable = 0; + m_cmng_port->flags.rate_shaping_enable = 0; + + DP(NETIF_MSG_IFUP, + "Single function mode minmax will be disabled\n"); + } + + /* Store it to internal memory */ + for (i = 0; i < sizeof(struct cmng_struct_per_port) / 4; i++) + REG_WR(bp, BAR_XSTRORM_INTMEM + + XSTORM_CMNG_PER_PORT_VARS_OFFSET(port) + i * 4, + ((u32 *)(m_cmng_port))[i]); +} + +static void bnx2x_init_vn_minmax(struct bnx2x *bp, int func, + u32 wsum, u16 port_rate, + struct cmng_struct_per_port *m_cmng_port) +{ + struct rate_shaping_vars_per_vn m_rs_vn; + struct fairness_vars_per_vn m_fair_vn; + u32 vn_cfg = SHMEM_RD(bp, mf_cfg.func_mf_config[func].config); + u16 vn_min_rate, vn_max_rate; + int i; + + /* If function is hidden - set min and max to zeroes */ + if (vn_cfg & FUNC_MF_CFG_FUNC_HIDE) { + vn_min_rate = 0; + vn_max_rate = 0; + + } else { + vn_min_rate = ((vn_cfg & FUNC_MF_CFG_MIN_BW_MASK) >> + FUNC_MF_CFG_MIN_BW_SHIFT) * 100; + /* If FAIRNESS is enabled (not all min rates are zeroes) and + if current min rate is zero - set it to 1. + This is a requirment of the algorithm. */ + if ((vn_min_rate == 0) && wsum) + vn_min_rate = DEF_MIN_RATE; + vn_max_rate = ((vn_cfg & FUNC_MF_CFG_MAX_BW_MASK) >> + FUNC_MF_CFG_MAX_BW_SHIFT) * 100; + } + + DP(NETIF_MSG_IFUP, "func %d: vn_min_rate=%d vn_max_rate=%d " + "wsum=%d\n", func, vn_min_rate, vn_max_rate, wsum); + + memset(&m_rs_vn, 0, sizeof(struct rate_shaping_vars_per_vn)); + memset(&m_fair_vn, 0, sizeof(struct fairness_vars_per_vn)); + + /* global vn counter - maximal Mbps for this vn */ + m_rs_vn.vn_counter.rate = vn_max_rate; + + /* quota - number of bytes transmitted in this period */ + m_rs_vn.vn_counter.quota = + (vn_max_rate * RS_PERIODIC_TIMEOUT_USEC) / 8; + +#ifdef BNX2X_PER_PROT_QOS + /* per protocol counter */ + for (protocol = 0; protocol < NUM_OF_PROTOCOLS; protocol++) { + /* maximal Mbps for this protocol */ + m_rs_vn.protocol_counters[protocol].rate = + protocol_max_rate[protocol]; + /* the quota in each timer period - + number of bytes transmitted in this period */ + m_rs_vn.protocol_counters[protocol].quota = + (u32)(rs_periodic_timeout_usec * + ((double)m_rs_vn. + protocol_counters[protocol].rate/8)); + } +#endif + + if (wsum) { + /* credit for each period of the fairness algorithm: + number of bytes in T_FAIR (the vn share the port rate). + wsum should not be larger than 10000, thus + T_FAIR_COEF / (8 * wsum) will always be grater than zero */ + m_fair_vn.vn_credit_delta = + max((u64)(vn_min_rate * (T_FAIR_COEF / (8 * wsum))), + (u64)(m_cmng_port->fair_vars.fair_threshold * 2)); + DP(NETIF_MSG_IFUP, "m_fair_vn.vn_credit_delta=%d\n", + m_fair_vn.vn_credit_delta); + } + +#ifdef BNX2X_PER_PROT_QOS + do { + u32 protocolWeightSum = 0; + + for (protocol = 0; protocol < NUM_OF_PROTOCOLS; protocol++) + protocolWeightSum += + drvInit.protocol_min_rate[protocol]; + /* per protocol counter - + NOT NEEDED IF NO PER-PROTOCOL CONGESTION MANAGEMENT */ + if (protocolWeightSum > 0) { + for (protocol = 0; + protocol < NUM_OF_PROTOCOLS; protocol++) + /* credit for each period of the + fairness algorithm - number of bytes in + T_FAIR (the protocol share the vn rate) */ + m_fair_vn.protocol_credit_delta[protocol] = + (u32)((vn_min_rate / 8) * t_fair * + protocol_min_rate / protocolWeightSum); + } + } while (0); +#endif + + /* Store it to internal memory */ + for (i = 0; i < sizeof(struct rate_shaping_vars_per_vn)/4; i++) + REG_WR(bp, BAR_XSTRORM_INTMEM + + XSTORM_RATE_SHAPING_PER_VN_VARS_OFFSET(func) + i * 4, + ((u32 *)(&m_rs_vn))[i]); + + for (i = 0; i < sizeof(struct fairness_vars_per_vn)/4; i++) + REG_WR(bp, BAR_XSTRORM_INTMEM + + XSTORM_FAIRNESS_PER_VN_VARS_OFFSET(func) + i * 4, + ((u32 *)(&m_fair_vn))[i]); +} + +/* This function is called upon link interrupt */ +static void bnx2x_link_attn(struct bnx2x *bp) +{ + int vn; + + /* Make sure that we are synced with the current statistics */ + bnx2x_stats_handle(bp, STATS_EVENT_STOP); + + bnx2x_phy_hw_lock(bp); + bnx2x_link_update(&bp->link_params, &bp->link_vars); + bnx2x_phy_hw_unlock(bp); + + if (bp->link_vars.link_up) { + + if (bp->link_vars.mac_type == MAC_TYPE_BMAC) { + struct host_port_stats *pstats; + + pstats = bnx2x_sp(bp, port_stats); + /* reset old bmac stats */ + memset(&(pstats->mac_stx[0]), 0, + sizeof(struct mac_stx)); + } + if ((bp->state == BNX2X_STATE_OPEN) || + (bp->state == BNX2X_STATE_DISABLED)) + bnx2x_stats_handle(bp, STATS_EVENT_LINK_UP); + } + + /* indicate link status */ + bnx2x_link_report(bp); + + if (IS_E1HMF(bp)) { + int func; + + for (vn = VN_0; vn < E1HVN_MAX; vn++) { + if (vn == BP_E1HVN(bp)) + continue; + + func = ((vn << 1) | BP_PORT(bp)); + + /* Set the attention towards other drivers + on the same port */ + REG_WR(bp, MISC_REG_AEU_GENERAL_ATTN_0 + + (LINK_SYNC_ATTENTION_BIT_FUNC_0 + func)*4, 1); + } + } + + if (CHIP_IS_E1H(bp) && (bp->link_vars.line_speed > 0)) { + struct cmng_struct_per_port m_cmng_port; + u32 wsum; + int port = BP_PORT(bp); + + /* Init RATE SHAPING and FAIRNESS contexts */ + wsum = bnx2x_calc_vn_wsum(bp); + bnx2x_init_port_minmax(bp, (int)wsum, + bp->link_vars.line_speed, + &m_cmng_port); + if (IS_E1HMF(bp)) + for (vn = VN_0; vn < E1HVN_MAX; vn++) + bnx2x_init_vn_minmax(bp, 2*vn + port, + wsum, bp->link_vars.line_speed, + &m_cmng_port); + } +} + +static void bnx2x__link_status_update(struct bnx2x *bp) +{ + if (bp->state != BNX2X_STATE_OPEN) + return; + + bnx2x_link_status_update(&bp->link_params, &bp->link_vars); + + if (bp->link_vars.link_up) + bnx2x_stats_handle(bp, STATS_EVENT_LINK_UP); + else + bnx2x_stats_handle(bp, STATS_EVENT_STOP); + + /* indicate link status */ + bnx2x_link_report(bp); +} + +static void bnx2x_pmf_update(struct bnx2x *bp) +{ + int port = BP_PORT(bp); + u32 val; + + bp->port.pmf = 1; + DP(NETIF_MSG_LINK, "pmf %d\n", bp->port.pmf); + + /* enable nig attention */ + val = (0xff0f | (1 << (BP_E1HVN(bp) + 4))); + REG_WR(bp, HC_REG_TRAILING_EDGE_0 + port*8, val); + REG_WR(bp, HC_REG_LEADING_EDGE_0 + port*8, val); + + bnx2x_stats_handle(bp, STATS_EVENT_PMF); +} + +/* end of Link */ + +/* slow path */ + +/* + * General service functions + */ + +/* the slow path queue is odd since completions arrive on the fastpath ring */ +static int bnx2x_sp_post(struct bnx2x *bp, int command, int cid, + u32 data_hi, u32 data_lo, int common) +{ + int func = BP_FUNC(bp); + + DP(BNX2X_MSG_SP/*NETIF_MSG_TIMER*/, + "SPQE (%x:%x) command %d hw_cid %x data (%x:%x) left %x\n", + (u32)U64_HI(bp->spq_mapping), (u32)(U64_LO(bp->spq_mapping) + + (void *)bp->spq_prod_bd - (void *)bp->spq), command, + HW_CID(bp, cid), data_hi, data_lo, bp->spq_left); + +#ifdef BNX2X_STOP_ON_ERROR + if (unlikely(bp->panic)) + return -EIO; +#endif + + spin_lock_bh(&bp->spq_lock); + + if (!bp->spq_left) { + BNX2X_ERR("BUG! SPQ ring full!\n"); + spin_unlock_bh(&bp->spq_lock); + bnx2x_panic(); + return -EBUSY; + } + + /* CID needs port number to be encoded int it */ + bp->spq_prod_bd->hdr.conn_and_cmd_data = + cpu_to_le32(((command << SPE_HDR_CMD_ID_SHIFT) | + HW_CID(bp, cid))); + bp->spq_prod_bd->hdr.type = cpu_to_le16(ETH_CONNECTION_TYPE); + if (common) + bp->spq_prod_bd->hdr.type |= + cpu_to_le16((1 << SPE_HDR_COMMON_RAMROD_SHIFT)); + + bp->spq_prod_bd->data.mac_config_addr.hi = cpu_to_le32(data_hi); + bp->spq_prod_bd->data.mac_config_addr.lo = cpu_to_le32(data_lo); + + bp->spq_left--; + + if (bp->spq_prod_bd == bp->spq_last_bd) { + bp->spq_prod_bd = bp->spq; + bp->spq_prod_idx = 0; + DP(NETIF_MSG_TIMER, "end of spq\n"); + + } else { + bp->spq_prod_bd++; + bp->spq_prod_idx++; + } + + REG_WR(bp, BAR_XSTRORM_INTMEM + XSTORM_SPQ_PROD_OFFSET(func), + bp->spq_prod_idx); + + spin_unlock_bh(&bp->spq_lock); + return 0; +} + +/* acquire split MCP access lock register */ +static int bnx2x_lock_alr(struct bnx2x *bp) +{ + u32 i, j, val; + int rc = 0; + + might_sleep(); + i = 100; + for (j = 0; j < i*10; j++) { + val = (1UL << 31); + REG_WR(bp, GRCBASE_MCP + 0x9c, val); + val = REG_RD(bp, GRCBASE_MCP + 0x9c); + if (val & (1L << 31)) + break; + + msleep(5); + } + if (!(val & (1L << 31))) { + BNX2X_ERR("Cannot acquire nvram interface\n"); + rc = -EBUSY; + } + + return rc; +} + +/* Release split MCP access lock register */ +static void bnx2x_unlock_alr(struct bnx2x *bp) +{ + u32 val = 0; + + REG_WR(bp, GRCBASE_MCP + 0x9c, val); +} + +static inline u16 bnx2x_update_dsb_idx(struct bnx2x *bp) +{ + struct host_def_status_block *def_sb = bp->def_status_blk; + u16 rc = 0; + + barrier(); /* status block is written to by the chip */ + + if (bp->def_att_idx != def_sb->atten_status_block.attn_bits_index) { + bp->def_att_idx = def_sb->atten_status_block.attn_bits_index; + rc |= 1; + } + if (bp->def_c_idx != def_sb->c_def_status_block.status_block_index) { + bp->def_c_idx = def_sb->c_def_status_block.status_block_index; + rc |= 2; + } + if (bp->def_u_idx != def_sb->u_def_status_block.status_block_index) { + bp->def_u_idx = def_sb->u_def_status_block.status_block_index; + rc |= 4; + } + if (bp->def_x_idx != def_sb->x_def_status_block.status_block_index) { + bp->def_x_idx = def_sb->x_def_status_block.status_block_index; + rc |= 8; + } + if (bp->def_t_idx != def_sb->t_def_status_block.status_block_index) { + bp->def_t_idx = def_sb->t_def_status_block.status_block_index; + rc |= 16; + } + return rc; +} + +/* + * slow path service functions + */ + +static void bnx2x_attn_int_asserted(struct bnx2x *bp, u32 asserted) +{ + int port = BP_PORT(bp); + int func = BP_FUNC(bp); + u32 igu_addr = (IGU_ADDR_ATTN_BITS_SET + IGU_FUNC_BASE * func) * 8; + u32 aeu_addr = port ? MISC_REG_AEU_MASK_ATTN_FUNC_1 : + MISC_REG_AEU_MASK_ATTN_FUNC_0; + u32 nig_int_mask_addr = port ? NIG_REG_MASK_INTERRUPT_PORT1 : + NIG_REG_MASK_INTERRUPT_PORT0; + + if (~bp->aeu_mask & (asserted & 0xff)) + BNX2X_ERR("IGU ERROR\n"); + if (bp->attn_state & asserted) + BNX2X_ERR("IGU ERROR\n"); + + DP(NETIF_MSG_HW, "aeu_mask %x newly asserted %x\n", + bp->aeu_mask, asserted); + bp->aeu_mask &= ~(asserted & 0xff); + DP(NETIF_MSG_HW, "after masking: aeu_mask %x\n", bp->aeu_mask); + + REG_WR(bp, aeu_addr, bp->aeu_mask); + + bp->attn_state |= asserted; + + if (asserted & ATTN_HARD_WIRED_MASK) { + if (asserted & ATTN_NIG_FOR_FUNC) { + + /* save nig interrupt mask */ + bp->nig_mask = REG_RD(bp, nig_int_mask_addr); + REG_WR(bp, nig_int_mask_addr, 0); + + bnx2x_link_attn(bp); + + /* handle unicore attn? */ + } + if (asserted & ATTN_SW_TIMER_4_FUNC) + DP(NETIF_MSG_HW, "ATTN_SW_TIMER_4_FUNC!\n"); + + if (asserted & GPIO_2_FUNC) + DP(NETIF_MSG_HW, "GPIO_2_FUNC!\n"); + + if (asserted & GPIO_3_FUNC) + DP(NETIF_MSG_HW, "GPIO_3_FUNC!\n"); + + if (asserted & GPIO_4_FUNC) + DP(NETIF_MSG_HW, "GPIO_4_FUNC!\n"); + + if (port == 0) { + if (asserted & ATTN_GENERAL_ATTN_1) { + DP(NETIF_MSG_HW, "ATTN_GENERAL_ATTN_1!\n"); + REG_WR(bp, MISC_REG_AEU_GENERAL_ATTN_1, 0x0); + } + if (asserted & ATTN_GENERAL_ATTN_2) { + DP(NETIF_MSG_HW, "ATTN_GENERAL_ATTN_2!\n"); + REG_WR(bp, MISC_REG_AEU_GENERAL_ATTN_2, 0x0); + } + if (asserted & ATTN_GENERAL_ATTN_3) { + DP(NETIF_MSG_HW, "ATTN_GENERAL_ATTN_3!\n"); + REG_WR(bp, MISC_REG_AEU_GENERAL_ATTN_3, 0x0); + } + } else { + if (asserted & ATTN_GENERAL_ATTN_4) { + DP(NETIF_MSG_HW, "ATTN_GENERAL_ATTN_4!\n"); + REG_WR(bp, MISC_REG_AEU_GENERAL_ATTN_4, 0x0); + } + if (asserted & ATTN_GENERAL_ATTN_5) { + DP(NETIF_MSG_HW, "ATTN_GENERAL_ATTN_5!\n"); + REG_WR(bp, MISC_REG_AEU_GENERAL_ATTN_5, 0x0); + } + if (asserted & ATTN_GENERAL_ATTN_6) { + DP(NETIF_MSG_HW, "ATTN_GENERAL_ATTN_6!\n"); + REG_WR(bp, MISC_REG_AEU_GENERAL_ATTN_6, 0x0); + } + } + + } /* if hardwired */ + + DP(NETIF_MSG_HW, "about to mask 0x%08x at IGU addr 0x%x\n", + asserted, BAR_IGU_INTMEM + igu_addr); + REG_WR(bp, BAR_IGU_INTMEM + igu_addr, asserted); + + /* now set back the mask */ + if (asserted & ATTN_NIG_FOR_FUNC) + REG_WR(bp, nig_int_mask_addr, bp->nig_mask); +} + +static inline void bnx2x_attn_int_deasserted0(struct bnx2x *bp, u32 attn) +{ + int port = BP_PORT(bp); + int reg_offset; + u32 val; + + reg_offset = (port ? MISC_REG_AEU_ENABLE1_FUNC_1_OUT_0 : + MISC_REG_AEU_ENABLE1_FUNC_0_OUT_0); + + if (attn & AEU_INPUTS_ATTN_BITS_SPIO5) { + + val = REG_RD(bp, reg_offset); + val &= ~AEU_INPUTS_ATTN_BITS_SPIO5; + REG_WR(bp, reg_offset, val); + + BNX2X_ERR("SPIO5 hw attention\n"); + + switch (bp->common.board & SHARED_HW_CFG_BOARD_TYPE_MASK) { + case SHARED_HW_CFG_BOARD_TYPE_BCM957710A1022G: + /* Fan failure attention */ + + /* The PHY reset is controled by GPIO 1 */ + bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1, + MISC_REGISTERS_GPIO_OUTPUT_LOW); + /* Low power mode is controled by GPIO 2 */ + bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2, + MISC_REGISTERS_GPIO_OUTPUT_LOW); + /* mark the failure */ + bp->link_params.ext_phy_config &= + ~PORT_HW_CFG_XGXS_EXT_PHY_TYPE_MASK; + bp->link_params.ext_phy_config |= + PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE; + SHMEM_WR(bp, + dev_info.port_hw_config[port]. + external_phy_config, + bp->link_params.ext_phy_config); + /* log the failure */ + printk(KERN_ERR PFX "Fan Failure on Network" + " Controller %s has caused the driver to" + " shutdown the card to prevent permanent" + " damage. Please contact Dell Support for" + " assistance\n", bp->dev->name); + break; + + default: + break; + } + } + + if (attn & HW_INTERRUT_ASSERT_SET_0) { + + val = REG_RD(bp, reg_offset); + val &= ~(attn & HW_INTERRUT_ASSERT_SET_0); + REG_WR(bp, reg_offset, val); + + BNX2X_ERR("FATAL HW block attention set0 0x%x\n", + (attn & HW_INTERRUT_ASSERT_SET_0)); + bnx2x_panic(); + } +} + +static inline void bnx2x_attn_int_deasserted1(struct bnx2x *bp, u32 attn) +{ + u32 val; + + if (attn & BNX2X_DOORQ_ASSERT) { + + val = REG_RD(bp, DORQ_REG_DORQ_INT_STS_CLR); + BNX2X_ERR("DB hw attention 0x%x\n", val); + /* DORQ discard attention */ + if (val & 0x2) + BNX2X_ERR("FATAL error from DORQ\n"); + } + + if (attn & HW_INTERRUT_ASSERT_SET_1) { + + int port = BP_PORT(bp); + int reg_offset; + + reg_offset = (port ? MISC_REG_AEU_ENABLE1_FUNC_1_OUT_1 : + MISC_REG_AEU_ENABLE1_FUNC_0_OUT_1); + + val = REG_RD(bp, reg_offset); + val &= ~(attn & HW_INTERRUT_ASSERT_SET_1); + REG_WR(bp, reg_offset, val); + + BNX2X_ERR("FATAL HW block attention set1 0x%x\n", + (attn & HW_INTERRUT_ASSERT_SET_1)); + bnx2x_panic(); + } +} + +static inline void bnx2x_attn_int_deasserted2(struct bnx2x *bp, u32 attn) +{ + u32 val; + + if (attn & AEU_INPUTS_ATTN_BITS_CFC_HW_INTERRUPT) { + + val = REG_RD(bp, CFC_REG_CFC_INT_STS_CLR); + BNX2X_ERR("CFC hw attention 0x%x\n", val); + /* CFC error attention */ + if (val & 0x2) + BNX2X_ERR("FATAL error from CFC\n"); + } + + if (attn & AEU_INPUTS_ATTN_BITS_PXP_HW_INTERRUPT) { + + val = REG_RD(bp, PXP_REG_PXP_INT_STS_CLR_0); + BNX2X_ERR("PXP hw attention 0x%x\n", val); + /* RQ_USDMDP_FIFO_OVERFLOW */ + if (val & 0x18000) + BNX2X_ERR("FATAL error from PXP\n"); + } + + if (attn & HW_INTERRUT_ASSERT_SET_2) { + + int port = BP_PORT(bp); + int reg_offset; + + reg_offset = (port ? MISC_REG_AEU_ENABLE1_FUNC_1_OUT_2 : + MISC_REG_AEU_ENABLE1_FUNC_0_OUT_2); + + val = REG_RD(bp, reg_offset); + val &= ~(attn & HW_INTERRUT_ASSERT_SET_2); + REG_WR(bp, reg_offset, val); + + BNX2X_ERR("FATAL HW block attention set2 0x%x\n", + (attn & HW_INTERRUT_ASSERT_SET_2)); + bnx2x_panic(); + } +} + +static inline void bnx2x_attn_int_deasserted3(struct bnx2x *bp, u32 attn) +{ + u32 val; + + if (attn & EVEREST_GEN_ATTN_IN_USE_MASK) { + + if (attn & BNX2X_PMF_LINK_ASSERT) { + int func = BP_FUNC(bp); + + REG_WR(bp, MISC_REG_AEU_GENERAL_ATTN_12 + func*4, 0); + bnx2x__link_status_update(bp); + if (SHMEM_RD(bp, func_mb[func].drv_status) & + DRV_STATUS_PMF) + bnx2x_pmf_update(bp); + + } else if (attn & BNX2X_MC_ASSERT_BITS) { + + BNX2X_ERR("MC assert!\n"); + REG_WR(bp, MISC_REG_AEU_GENERAL_ATTN_10, 0); + REG_WR(bp, MISC_REG_AEU_GENERAL_ATTN_9, 0); + REG_WR(bp, MISC_REG_AEU_GENERAL_ATTN_8, 0); + REG_WR(bp, MISC_REG_AEU_GENERAL_ATTN_7, 0); + bnx2x_panic(); + + } else if (attn & BNX2X_MCP_ASSERT) { + + BNX2X_ERR("MCP assert!\n"); + REG_WR(bp, MISC_REG_AEU_GENERAL_ATTN_11, 0); + bnx2x_fw_dump(bp); + + } else + BNX2X_ERR("Unknown HW assert! (attn 0x%x)\n", attn); + } + + if (attn & EVEREST_LATCHED_ATTN_IN_USE_MASK) { + BNX2X_ERR("LATCHED attention 0x%08x (masked)\n", attn); + if (attn & BNX2X_GRC_TIMEOUT) { + val = CHIP_IS_E1H(bp) ? + REG_RD(bp, MISC_REG_GRC_TIMEOUT_ATTN) : 0; + BNX2X_ERR("GRC time-out 0x%08x\n", val); + } + if (attn & BNX2X_GRC_RSV) { + val = CHIP_IS_E1H(bp) ? + REG_RD(bp, MISC_REG_GRC_RSV_ATTN) : 0; + BNX2X_ERR("GRC reserved 0x%08x\n", val); + } + REG_WR(bp, MISC_REG_AEU_CLR_LATCH_SIGNAL, 0x7ff); + } +} + +static void bnx2x_attn_int_deasserted(struct bnx2x *bp, u32 deasserted) +{ + struct attn_route attn; + struct attn_route group_mask; + int port = BP_PORT(bp); + int index; + u32 reg_addr; + u32 val; + + /* need to take HW lock because MCP or other port might also + try to handle this event */ + bnx2x_lock_alr(bp); + + attn.sig[0] = REG_RD(bp, MISC_REG_AEU_AFTER_INVERT_1_FUNC_0 + port*4); + attn.sig[1] = REG_RD(bp, MISC_REG_AEU_AFTER_INVERT_2_FUNC_0 + port*4); + attn.sig[2] = REG_RD(bp, MISC_REG_AEU_AFTER_INVERT_3_FUNC_0 + port*4); + attn.sig[3] = REG_RD(bp, MISC_REG_AEU_AFTER_INVERT_4_FUNC_0 + port*4); + DP(NETIF_MSG_HW, "attn: %08x %08x %08x %08x\n", + attn.sig[0], attn.sig[1], attn.sig[2], attn.sig[3]); + + for (index = 0; index < MAX_DYNAMIC_ATTN_GRPS; index++) { + if (deasserted & (1 << index)) { + group_mask = bp->attn_group[index]; + + DP(NETIF_MSG_HW, "group[%d]: %08x %08x %08x %08x\n", + index, group_mask.sig[0], group_mask.sig[1], + group_mask.sig[2], group_mask.sig[3]); + + bnx2x_attn_int_deasserted3(bp, + attn.sig[3] & group_mask.sig[3]); + bnx2x_attn_int_deasserted1(bp, + attn.sig[1] & group_mask.sig[1]); + bnx2x_attn_int_deasserted2(bp, + attn.sig[2] & group_mask.sig[2]); + bnx2x_attn_int_deasserted0(bp, + attn.sig[0] & group_mask.sig[0]); + + if ((attn.sig[0] & group_mask.sig[0] & + HW_PRTY_ASSERT_SET_0) || + (attn.sig[1] & group_mask.sig[1] & + HW_PRTY_ASSERT_SET_1) || + (attn.sig[2] & group_mask.sig[2] & + HW_PRTY_ASSERT_SET_2)) + BNX2X_ERR("FATAL HW block parity attention\n"); + } + } + + bnx2x_unlock_alr(bp); + + reg_addr = (IGU_ADDR_ATTN_BITS_CLR + IGU_FUNC_BASE * BP_FUNC(bp)) * 8; + + val = ~deasserted; +/* DP(NETIF_MSG_INTR, "write 0x%08x to IGU addr 0x%x\n", + val, BAR_IGU_INTMEM + reg_addr); */ + REG_WR(bp, BAR_IGU_INTMEM + reg_addr, val); + + if (bp->aeu_mask & (deasserted & 0xff)) + BNX2X_ERR("IGU BUG!\n"); + if (~bp->attn_state & deasserted) + BNX2X_ERR("IGU BUG!\n"); + + reg_addr = port ? MISC_REG_AEU_MASK_ATTN_FUNC_1 : + MISC_REG_AEU_MASK_ATTN_FUNC_0; + + DP(NETIF_MSG_HW, "aeu_mask %x\n", bp->aeu_mask); + bp->aeu_mask |= (deasserted & 0xff); + + DP(NETIF_MSG_HW, "new mask %x\n", bp->aeu_mask); + REG_WR(bp, reg_addr, bp->aeu_mask); + + DP(NETIF_MSG_HW, "attn_state %x\n", bp->attn_state); + bp->attn_state &= ~deasserted; + DP(NETIF_MSG_HW, "new state %x\n", bp->attn_state); +} + +static void bnx2x_attn_int(struct bnx2x *bp) +{ + /* read local copy of bits */ + u32 attn_bits = bp->def_status_blk->atten_status_block.attn_bits; + u32 attn_ack = bp->def_status_blk->atten_status_block.attn_bits_ack; + u32 attn_state = bp->attn_state; + + /* look for changed bits */ + u32 asserted = attn_bits & ~attn_ack & ~attn_state; + u32 deasserted = ~attn_bits & attn_ack & attn_state; + + DP(NETIF_MSG_HW, + "attn_bits %x attn_ack %x asserted %x deasserted %x\n", + attn_bits, attn_ack, asserted, deasserted); + + if (~(attn_bits ^ attn_ack) & (attn_bits ^ attn_state)) + BNX2X_ERR("BAD attention state\n"); + + /* handle bits that were raised */ + if (asserted) + bnx2x_attn_int_asserted(bp, asserted); + + if (deasserted) + bnx2x_attn_int_deasserted(bp, deasserted); +} + +static void bnx2x_sp_task(struct work_struct *work) +{ + struct bnx2x *bp = container_of(work, struct bnx2x, sp_task); + u16 status; + + + /* Return here if interrupt is disabled */ + if (unlikely(atomic_read(&bp->intr_sem) != 0)) { + DP(BNX2X_MSG_SP, "called but intr_sem not 0, returning\n"); + return; + } + + status = bnx2x_update_dsb_idx(bp); +/* if (status == 0) */ +/* BNX2X_ERR("spurious slowpath interrupt!\n"); */ + + DP(BNX2X_MSG_SP, "got a slowpath interrupt (updated %x)\n", status); + + /* HW attentions */ + if (status & 0x1) + bnx2x_attn_int(bp); + + /* CStorm events: query_stats, port delete ramrod */ + if (status & 0x2) + bp->stats_pending = 0; + + bnx2x_ack_sb(bp, DEF_SB_ID, ATTENTION_ID, bp->def_att_idx, + IGU_INT_NOP, 1); + bnx2x_ack_sb(bp, DEF_SB_ID, USTORM_ID, le16_to_cpu(bp->def_u_idx), + IGU_INT_NOP, 1); + bnx2x_ack_sb(bp, DEF_SB_ID, CSTORM_ID, le16_to_cpu(bp->def_c_idx), + IGU_INT_NOP, 1); + bnx2x_ack_sb(bp, DEF_SB_ID, XSTORM_ID, le16_to_cpu(bp->def_x_idx), + IGU_INT_NOP, 1); + bnx2x_ack_sb(bp, DEF_SB_ID, TSTORM_ID, le16_to_cpu(bp->def_t_idx), + IGU_INT_ENABLE, 1); + +} + +static irqreturn_t bnx2x_msix_sp_int(int irq, void *dev_instance) +{ + struct net_device *dev = dev_instance; + struct bnx2x *bp = netdev_priv(dev); + + /* Return here if interrupt is disabled */ + if (unlikely(atomic_read(&bp->intr_sem) != 0)) { + DP(BNX2X_MSG_SP, "called but intr_sem not 0, returning\n"); + return IRQ_HANDLED; + } + + bnx2x_ack_sb(bp, DEF_SB_ID, XSTORM_ID, 0, IGU_INT_DISABLE, 0); + +#ifdef BNX2X_STOP_ON_ERROR + if (unlikely(bp->panic)) + return IRQ_HANDLED; +#endif + + schedule_work(&bp->sp_task); + + return IRQ_HANDLED; +} + +/* end of slow path */ + +/* Statistics */ + +/**************************************************************************** +* Macros +****************************************************************************/ + +/* sum[hi:lo] += add[hi:lo] */ +#define ADD_64(s_hi, a_hi, s_lo, a_lo) \ + do { \ + s_lo += a_lo; \ + s_hi += a_hi + (s_lo < a_lo) ? 1 : 0; \ + } while (0) + +/* difference = minuend - subtrahend */ +#define DIFF_64(d_hi, m_hi, s_hi, d_lo, m_lo, s_lo) \ + do { \ + if (m_lo < s_lo) { \ + /* underflow */ \ + d_hi = m_hi - s_hi; \ + if (d_hi > 0) { \ + /* we can 'loan' 1 */ \ + d_hi--; \ + d_lo = m_lo + (UINT_MAX - s_lo) + 1; \ + } else { \ + /* m_hi <= s_hi */ \ + d_hi = 0; \ + d_lo = 0; \ + } \ + } else { \ + /* m_lo >= s_lo */ \ + if (m_hi < s_hi) { \ + d_hi = 0; \ + d_lo = 0; \ + } else { \ + /* m_hi >= s_hi */ \ + d_hi = m_hi - s_hi; \ + d_lo = m_lo - s_lo; \ + } \ + } \ + } while (0) + +#define UPDATE_STAT64(s, t) \ + do { \ + DIFF_64(diff.hi, new->s##_hi, pstats->mac_stx[0].t##_hi, \ + diff.lo, new->s##_lo, pstats->mac_stx[0].t##_lo); \ + pstats->mac_stx[0].t##_hi = new->s##_hi; \ + pstats->mac_stx[0].t##_lo = new->s##_lo; \ + ADD_64(pstats->mac_stx[1].t##_hi, diff.hi, \ + pstats->mac_stx[1].t##_lo, diff.lo); \ + } while (0) + +#define UPDATE_STAT64_NIG(s, t) \ + do { \ + DIFF_64(diff.hi, new->s##_hi, old->s##_hi, \ + diff.lo, new->s##_lo, old->s##_lo); \ + ADD_64(estats->t##_hi, diff.hi, \ + estats->t##_lo, diff.lo); \ + } while (0) + +/* sum[hi:lo] += add */ +#define ADD_EXTEND_64(s_hi, s_lo, a) \ + do { \ + s_lo += a; \ + s_hi += (s_lo < a) ? 1 : 0; \ + } while (0) + +#define UPDATE_EXTEND_STAT(s) \ + do { \ + ADD_EXTEND_64(pstats->mac_stx[1].s##_hi, \ + pstats->mac_stx[1].s##_lo, \ + new->s); \ + } while (0) + +#define UPDATE_EXTEND_TSTAT(s, t) \ + do { \ + diff = le32_to_cpu(tclient->s) - old_tclient->s; \ + old_tclient->s = le32_to_cpu(tclient->s); \ + ADD_EXTEND_64(fstats->t##_hi, fstats->t##_lo, diff); \ + } while (0) + +#define UPDATE_EXTEND_XSTAT(s, t) \ + do { \ + diff = le32_to_cpu(xclient->s) - old_xclient->s; \ + old_xclient->s = le32_to_cpu(xclient->s); \ + ADD_EXTEND_64(fstats->t##_hi, fstats->t##_lo, diff); \ + } while (0) + +/* + * General service functions + */ + +static inline long bnx2x_hilo(u32 *hiref) +{ + u32 lo = *(hiref + 1); +#if (BITS_PER_LONG == 64) + u32 hi = *hiref; + + return HILO_U64(hi, lo); +#else + return lo; +#endif +} + +/* + * Init service functions + */ + +static void bnx2x_storm_stats_init(struct bnx2x *bp) +{ + int func = BP_FUNC(bp); + + REG_WR(bp, BAR_XSTRORM_INTMEM + XSTORM_STATS_FLAGS_OFFSET(func), 1); + REG_WR(bp, BAR_XSTRORM_INTMEM + + XSTORM_STATS_FLAGS_OFFSET(func) + 4, 0); + + REG_WR(bp, BAR_TSTRORM_INTMEM + TSTORM_STATS_FLAGS_OFFSET(func), 1); + REG_WR(bp, BAR_TSTRORM_INTMEM + + TSTORM_STATS_FLAGS_OFFSET(func) + 4, 0); + + REG_WR(bp, BAR_CSTRORM_INTMEM + CSTORM_STATS_FLAGS_OFFSET(func), 0); + REG_WR(bp, BAR_CSTRORM_INTMEM + + CSTORM_STATS_FLAGS_OFFSET(func) + 4, 0); + + REG_WR(bp, BAR_XSTRORM_INTMEM + + XSTORM_ETH_STATS_QUERY_ADDR_OFFSET(func), + U64_LO(bnx2x_sp_mapping(bp, fw_stats))); + REG_WR(bp, BAR_XSTRORM_INTMEM + + XSTORM_ETH_STATS_QUERY_ADDR_OFFSET(func) + 4, + U64_HI(bnx2x_sp_mapping(bp, fw_stats))); + + REG_WR(bp, BAR_TSTRORM_INTMEM + + TSTORM_ETH_STATS_QUERY_ADDR_OFFSET(func), + U64_LO(bnx2x_sp_mapping(bp, fw_stats))); + REG_WR(bp, BAR_TSTRORM_INTMEM + + TSTORM_ETH_STATS_QUERY_ADDR_OFFSET(func) + 4, + U64_HI(bnx2x_sp_mapping(bp, fw_stats))); +} + +static void bnx2x_storm_stats_post(struct bnx2x *bp) +{ + if (!bp->stats_pending) { + struct eth_query_ramrod_data ramrod_data = {0}; + int rc; + + ramrod_data.drv_counter = bp->stats_counter++; + ramrod_data.collect_port_1b = bp->port.pmf ? 1 : 0; + ramrod_data.ctr_id_vector = (1 << BP_CL_ID(bp)); + + rc = bnx2x_sp_post(bp, RAMROD_CMD_ID_ETH_STAT_QUERY, 0, + ((u32 *)&ramrod_data)[1], + ((u32 *)&ramrod_data)[0], 0); + if (rc == 0) { + /* stats ramrod has it's own slot on the spq */ + bp->spq_left++; + bp->stats_pending = 1; + } + } +} + +static void bnx2x_stats_init(struct bnx2x *bp) +{ + int port = BP_PORT(bp); + + bp->executer_idx = 0; + bp->stats_counter = 0; + + /* port stats */ + if (!BP_NOMCP(bp)) + bp->port.port_stx = SHMEM_RD(bp, port_mb[port].port_stx); + else + bp->port.port_stx = 0; + DP(BNX2X_MSG_STATS, "port_stx 0x%x\n", bp->port.port_stx); + + memset(&(bp->port.old_nig_stats), 0, sizeof(struct nig_stats)); + bp->port.old_nig_stats.brb_discard = + REG_RD(bp, NIG_REG_STAT0_BRB_DISCARD + port*0x38); + REG_RD_DMAE(bp, NIG_REG_STAT0_EGRESS_MAC_PKT0 + port*0x50, + &(bp->port.old_nig_stats.egress_mac_pkt0_lo), 2); + REG_RD_DMAE(bp, NIG_REG_STAT0_EGRESS_MAC_PKT1 + port*0x50, + &(bp->port.old_nig_stats.egress_mac_pkt1_lo), 2); + + /* function stats */ + memset(&bp->dev->stats, 0, sizeof(struct net_device_stats)); + memset(&bp->old_tclient, 0, sizeof(struct tstorm_per_client_stats)); + memset(&bp->old_xclient, 0, sizeof(struct xstorm_per_client_stats)); + memset(&bp->eth_stats, 0, sizeof(struct bnx2x_eth_stats)); + + bp->stats_state = STATS_STATE_DISABLED; + if (IS_E1HMF(bp) && bp->port.pmf && bp->port.port_stx) + bnx2x_stats_handle(bp, STATS_EVENT_PMF); +} + +static void bnx2x_hw_stats_post(struct bnx2x *bp) +{ + struct dmae_command *dmae = &bp->stats_dmae; + u32 *stats_comp = bnx2x_sp(bp, stats_comp); + + *stats_comp = DMAE_COMP_VAL; + + /* loader */ + if (bp->executer_idx) { + int loader_idx = PMF_DMAE_C(bp); + + memset(dmae, 0, sizeof(struct dmae_command)); + + dmae->opcode = (DMAE_CMD_SRC_PCI | DMAE_CMD_DST_GRC | + DMAE_CMD_C_DST_GRC | DMAE_CMD_C_ENABLE | + DMAE_CMD_DST_RESET | +#ifdef __BIG_ENDIAN + DMAE_CMD_ENDIANITY_B_DW_SWAP | +#else + DMAE_CMD_ENDIANITY_DW_SWAP | +#endif + (BP_PORT(bp) ? DMAE_CMD_PORT_1 : + DMAE_CMD_PORT_0) | + (BP_E1HVN(bp) << DMAE_CMD_E1HVN_SHIFT)); + dmae->src_addr_lo = U64_LO(bnx2x_sp_mapping(bp, dmae[0])); + dmae->src_addr_hi = U64_HI(bnx2x_sp_mapping(bp, dmae[0])); + dmae->dst_addr_lo = (DMAE_REG_CMD_MEM + + sizeof(struct dmae_command) * + (loader_idx + 1)) >> 2; + dmae->dst_addr_hi = 0; + dmae->len = sizeof(struct dmae_command) >> 2; + if (CHIP_IS_E1(bp)) + dmae->len--; + dmae->comp_addr_lo = dmae_reg_go_c[loader_idx + 1] >> 2; + dmae->comp_addr_hi = 0; + dmae->comp_val = 1; + + *stats_comp = 0; + bnx2x_post_dmae(bp, dmae, loader_idx); + + } else if (bp->func_stx) { + *stats_comp = 0; + bnx2x_post_dmae(bp, dmae, INIT_DMAE_C(bp)); + } +} + +static int bnx2x_stats_comp(struct bnx2x *bp) +{ + u32 *stats_comp = bnx2x_sp(bp, stats_comp); + int cnt = 10; + + might_sleep(); + while (*stats_comp != DMAE_COMP_VAL) { + msleep(1); + if (!cnt) { + BNX2X_ERR("timeout waiting for stats finished\n"); + break; + } + cnt--; + } + return 1; +} + +/* + * Statistics service functions + */ + +static void bnx2x_stats_pmf_update(struct bnx2x *bp) +{ + struct dmae_command *dmae; + u32 opcode; + int loader_idx = PMF_DMAE_C(bp); + u32 *stats_comp = bnx2x_sp(bp, stats_comp); + + /* sanity */ + if (!IS_E1HMF(bp) || !bp->port.pmf || !bp->port.port_stx) { + BNX2X_ERR("BUG!\n"); + return; + } + + bp->executer_idx = 0; + + opcode = (DMAE_CMD_SRC_GRC | DMAE_CMD_DST_PCI | + DMAE_CMD_C_ENABLE | + DMAE_CMD_SRC_RESET | DMAE_CMD_DST_RESET | +#ifdef __BIG_ENDIAN + DMAE_CMD_ENDIANITY_B_DW_SWAP | +#else + DMAE_CMD_ENDIANITY_DW_SWAP | +#endif + (BP_PORT(bp) ? DMAE_CMD_PORT_1 : DMAE_CMD_PORT_0) | + (BP_E1HVN(bp) << DMAE_CMD_E1HVN_SHIFT)); + + dmae = bnx2x_sp(bp, dmae[bp->executer_idx++]); + dmae->opcode = (opcode | DMAE_CMD_C_DST_GRC); + dmae->src_addr_lo = bp->port.port_stx >> 2; + dmae->src_addr_hi = 0; + dmae->dst_addr_lo = U64_LO(bnx2x_sp_mapping(bp, port_stats)); + dmae->dst_addr_hi = U64_HI(bnx2x_sp_mapping(bp, port_stats)); + dmae->len = DMAE_LEN32_RD_MAX; + dmae->comp_addr_lo = dmae_reg_go_c[loader_idx] >> 2; + dmae->comp_addr_hi = 0; + dmae->comp_val = 1; + + dmae = bnx2x_sp(bp, dmae[bp->executer_idx++]); + dmae->opcode = (opcode | DMAE_CMD_C_DST_PCI); + dmae->src_addr_lo = (bp->port.port_stx >> 2) + DMAE_LEN32_RD_MAX; + dmae->src_addr_hi = 0; + dmae->dst_addr_lo = U64_LO(bnx2x_sp_mapping(bp, port_stats) + + DMAE_LEN32_RD_MAX * 4); + dmae->dst_addr_hi = U64_HI(bnx2x_sp_mapping(bp, port_stats) + + DMAE_LEN32_RD_MAX * 4); + dmae->len = (sizeof(struct host_port_stats) >> 2) - DMAE_LEN32_RD_MAX; + dmae->comp_addr_lo = U64_LO(bnx2x_sp_mapping(bp, stats_comp)); + dmae->comp_addr_hi = U64_HI(bnx2x_sp_mapping(bp, stats_comp)); + dmae->comp_val = DMAE_COMP_VAL; + + *stats_comp = 0; + bnx2x_hw_stats_post(bp); + bnx2x_stats_comp(bp); +} + +static void bnx2x_port_stats_init(struct bnx2x *bp) +{ + struct dmae_command *dmae; + int port = BP_PORT(bp); + int vn = BP_E1HVN(bp); + u32 opcode; + int loader_idx = PMF_DMAE_C(bp); + u32 mac_addr; + u32 *stats_comp = bnx2x_sp(bp, stats_comp); + + /* sanity */ + if (!bp->link_vars.link_up || !bp->port.pmf) { + BNX2X_ERR("BUG!\n"); + return; + } + + bp->executer_idx = 0; + + /* MCP */ + opcode = (DMAE_CMD_SRC_PCI | DMAE_CMD_DST_GRC | + DMAE_CMD_C_DST_GRC | DMAE_CMD_C_ENABLE | + DMAE_CMD_SRC_RESET | DMAE_CMD_DST_RESET | +#ifdef __BIG_ENDIAN + DMAE_CMD_ENDIANITY_B_DW_SWAP | +#else + DMAE_CMD_ENDIANITY_DW_SWAP | +#endif + (port ? DMAE_CMD_PORT_1 : DMAE_CMD_PORT_0) | + (vn << DMAE_CMD_E1HVN_SHIFT)); + + if (bp->port.port_stx) { + + dmae = bnx2x_sp(bp, dmae[bp->executer_idx++]); + dmae->opcode = opcode; + dmae->src_addr_lo = U64_LO(bnx2x_sp_mapping(bp, port_stats)); + dmae->src_addr_hi = U64_HI(bnx2x_sp_mapping(bp, port_stats)); + dmae->dst_addr_lo = bp->port.port_stx >> 2; + dmae->dst_addr_hi = 0; + dmae->len = sizeof(struct host_port_stats) >> 2; + dmae->comp_addr_lo = dmae_reg_go_c[loader_idx] >> 2; + dmae->comp_addr_hi = 0; + dmae->comp_val = 1; + } + + if (bp->func_stx) { + + dmae = bnx2x_sp(bp, dmae[bp->executer_idx++]); + dmae->opcode = opcode; + dmae->src_addr_lo = U64_LO(bnx2x_sp_mapping(bp, func_stats)); + dmae->src_addr_hi = U64_HI(bnx2x_sp_mapping(bp, func_stats)); + dmae->dst_addr_lo = bp->func_stx >> 2; + dmae->dst_addr_hi = 0; + dmae->len = sizeof(struct host_func_stats) >> 2; + dmae->comp_addr_lo = dmae_reg_go_c[loader_idx] >> 2; + dmae->comp_addr_hi = 0; + dmae->comp_val = 1; + } + + /* MAC */ + opcode = (DMAE_CMD_SRC_GRC | DMAE_CMD_DST_PCI | + DMAE_CMD_C_DST_GRC | DMAE_CMD_C_ENABLE | + DMAE_CMD_SRC_RESET | DMAE_CMD_DST_RESET | +#ifdef __BIG_ENDIAN + DMAE_CMD_ENDIANITY_B_DW_SWAP | +#else + DMAE_CMD_ENDIANITY_DW_SWAP | +#endif + (port ? DMAE_CMD_PORT_1 : DMAE_CMD_PORT_0) | + (vn << DMAE_CMD_E1HVN_SHIFT)); + + if (bp->link_vars.mac_type == MAC_TYPE_BMAC) { + + mac_addr = (port ? NIG_REG_INGRESS_BMAC1_MEM : + NIG_REG_INGRESS_BMAC0_MEM); + + /* BIGMAC_REGISTER_TX_STAT_GTPKT .. + BIGMAC_REGISTER_TX_STAT_GTBYT */ + dmae = bnx2x_sp(bp, dmae[bp->executer_idx++]); + dmae->opcode = opcode; + dmae->src_addr_lo = (mac_addr + + BIGMAC_REGISTER_TX_STAT_GTPKT) >> 2; + dmae->src_addr_hi = 0; + dmae->dst_addr_lo = U64_LO(bnx2x_sp_mapping(bp, mac_stats)); + dmae->dst_addr_hi = U64_HI(bnx2x_sp_mapping(bp, mac_stats)); + dmae->len = (8 + BIGMAC_REGISTER_TX_STAT_GTBYT - + BIGMAC_REGISTER_TX_STAT_GTPKT) >> 2; + dmae->comp_addr_lo = dmae_reg_go_c[loader_idx] >> 2; + dmae->comp_addr_hi = 0; + dmae->comp_val = 1; + + /* BIGMAC_REGISTER_RX_STAT_GR64 .. + BIGMAC_REGISTER_RX_STAT_GRIPJ */ + dmae = bnx2x_sp(bp, dmae[bp->executer_idx++]); + dmae->opcode = opcode; + dmae->src_addr_lo = (mac_addr + + BIGMAC_REGISTER_RX_STAT_GR64) >> 2; + dmae->src_addr_hi = 0; + dmae->dst_addr_lo = U64_LO(bnx2x_sp_mapping(bp, mac_stats) + + offsetof(struct bmac_stats, rx_stat_gr64_lo)); + dmae->dst_addr_hi = U64_HI(bnx2x_sp_mapping(bp, mac_stats) + + offsetof(struct bmac_stats, rx_stat_gr64_lo)); + dmae->len = (8 + BIGMAC_REGISTER_RX_STAT_GRIPJ - + BIGMAC_REGISTER_RX_STAT_GR64) >> 2; + dmae->comp_addr_lo = dmae_reg_go_c[loader_idx] >> 2; + dmae->comp_addr_hi = 0; + dmae->comp_val = 1; + + } else if (bp->link_vars.mac_type == MAC_TYPE_EMAC) { + + mac_addr = (port ? GRCBASE_EMAC1 : GRCBASE_EMAC0); + + /* EMAC_REG_EMAC_RX_STAT_AC (EMAC_REG_EMAC_RX_STAT_AC_COUNT)*/ + dmae = bnx2x_sp(bp, dmae[bp->executer_idx++]); + dmae->opcode = opcode; + dmae->src_addr_lo = (mac_addr + + EMAC_REG_EMAC_RX_STAT_AC) >> 2; + dmae->src_addr_hi = 0; + dmae->dst_addr_lo = U64_LO(bnx2x_sp_mapping(bp, mac_stats)); + dmae->dst_addr_hi = U64_HI(bnx2x_sp_mapping(bp, mac_stats)); + dmae->len = EMAC_REG_EMAC_RX_STAT_AC_COUNT; + dmae->comp_addr_lo = dmae_reg_go_c[loader_idx] >> 2; + dmae->comp_addr_hi = 0; + dmae->comp_val = 1; + + /* EMAC_REG_EMAC_RX_STAT_AC_28 */ + dmae = bnx2x_sp(bp, dmae[bp->executer_idx++]); + dmae->opcode = opcode; + dmae->src_addr_lo = (mac_addr + + EMAC_REG_EMAC_RX_STAT_AC_28) >> 2; + dmae->src_addr_hi = 0; + dmae->dst_addr_lo = U64_LO(bnx2x_sp_mapping(bp, mac_stats) + + offsetof(struct emac_stats, rx_stat_falsecarriererrors)); + dmae->dst_addr_hi = U64_HI(bnx2x_sp_mapping(bp, mac_stats) + + offsetof(struct emac_stats, rx_stat_falsecarriererrors)); + dmae->len = 1; + dmae->comp_addr_lo = dmae_reg_go_c[loader_idx] >> 2; + dmae->comp_addr_hi = 0; + dmae->comp_val = 1; + + /* EMAC_REG_EMAC_TX_STAT_AC (EMAC_REG_EMAC_TX_STAT_AC_COUNT)*/ + dmae = bnx2x_sp(bp, dmae[bp->executer_idx++]); + dmae->opcode = opcode; + dmae->src_addr_lo = (mac_addr + + EMAC_REG_EMAC_TX_STAT_AC) >> 2; + dmae->src_addr_hi = 0; + dmae->dst_addr_lo = U64_LO(bnx2x_sp_mapping(bp, mac_stats) + + offsetof(struct emac_stats, tx_stat_ifhcoutoctets)); + dmae->dst_addr_hi = U64_HI(bnx2x_sp_mapping(bp, mac_stats) + + offsetof(struct emac_stats, tx_stat_ifhcoutoctets)); + dmae->len = EMAC_REG_EMAC_TX_STAT_AC_COUNT; + dmae->comp_addr_lo = dmae_reg_go_c[loader_idx] >> 2; + dmae->comp_addr_hi = 0; + dmae->comp_val = 1; + } + + /* NIG */ + dmae = bnx2x_sp(bp, dmae[bp->executer_idx++]); + dmae->opcode = opcode; + dmae->src_addr_lo = (port ? NIG_REG_STAT1_BRB_DISCARD : + NIG_REG_STAT0_BRB_DISCARD) >> 2; + dmae->src_addr_hi = 0; + dmae->dst_addr_lo = U64_LO(bnx2x_sp_mapping(bp, nig_stats)); + dmae->dst_addr_hi = U64_HI(bnx2x_sp_mapping(bp, nig_stats)); + dmae->len = (sizeof(struct nig_stats) - 4*sizeof(u32)) >> 2; + dmae->comp_addr_lo = dmae_reg_go_c[loader_idx] >> 2; + dmae->comp_addr_hi = 0; + dmae->comp_val = 1; + + dmae = bnx2x_sp(bp, dmae[bp->executer_idx++]); + dmae->opcode = opcode; + dmae->src_addr_lo = (port ? NIG_REG_STAT1_EGRESS_MAC_PKT0 : + NIG_REG_STAT0_EGRESS_MAC_PKT0) >> 2; + dmae->src_addr_hi = 0; + dmae->dst_addr_lo = U64_LO(bnx2x_sp_mapping(bp, nig_stats) + + offsetof(struct nig_stats, egress_mac_pkt0_lo)); + dmae->dst_addr_hi = U64_HI(bnx2x_sp_mapping(bp, nig_stats) + + offsetof(struct nig_stats, egress_mac_pkt0_lo)); + dmae->len = (2*sizeof(u32)) >> 2; + dmae->comp_addr_lo = dmae_reg_go_c[loader_idx] >> 2; + dmae->comp_addr_hi = 0; + dmae->comp_val = 1; + + dmae = bnx2x_sp(bp, dmae[bp->executer_idx++]); + dmae->opcode = (DMAE_CMD_SRC_GRC | DMAE_CMD_DST_PCI | + DMAE_CMD_C_DST_PCI | DMAE_CMD_C_ENABLE | + DMAE_CMD_SRC_RESET | DMAE_CMD_DST_RESET | +#ifdef __BIG_ENDIAN + DMAE_CMD_ENDIANITY_B_DW_SWAP | +#else + DMAE_CMD_ENDIANITY_DW_SWAP | +#endif + (port ? DMAE_CMD_PORT_1 : DMAE_CMD_PORT_0) | + (vn << DMAE_CMD_E1HVN_SHIFT)); + dmae->src_addr_lo = (port ? NIG_REG_STAT1_EGRESS_MAC_PKT1 : + NIG_REG_STAT0_EGRESS_MAC_PKT1) >> 2; + dmae->src_addr_hi = 0; + dmae->dst_addr_lo = U64_LO(bnx2x_sp_mapping(bp, nig_stats) + + offsetof(struct nig_stats, egress_mac_pkt1_lo)); + dmae->dst_addr_hi = U64_HI(bnx2x_sp_mapping(bp, nig_stats) + + offsetof(struct nig_stats, egress_mac_pkt1_lo)); + dmae->len = (2*sizeof(u32)) >> 2; + dmae->comp_addr_lo = U64_LO(bnx2x_sp_mapping(bp, stats_comp)); + dmae->comp_addr_hi = U64_HI(bnx2x_sp_mapping(bp, stats_comp)); + dmae->comp_val = DMAE_COMP_VAL; + + *stats_comp = 0; +} + +static void bnx2x_func_stats_init(struct bnx2x *bp) +{ + struct dmae_command *dmae = &bp->stats_dmae; + u32 *stats_comp = bnx2x_sp(bp, stats_comp); + + /* sanity */ + if (!bp->func_stx) { + BNX2X_ERR("BUG!\n"); + return; + } + + bp->executer_idx = 0; + memset(dmae, 0, sizeof(struct dmae_command)); + + dmae->opcode = (DMAE_CMD_SRC_PCI | DMAE_CMD_DST_GRC | + DMAE_CMD_C_DST_PCI | DMAE_CMD_C_ENABLE | + DMAE_CMD_SRC_RESET | DMAE_CMD_DST_RESET | +#ifdef __BIG_ENDIAN + DMAE_CMD_ENDIANITY_B_DW_SWAP | +#else + DMAE_CMD_ENDIANITY_DW_SWAP | +#endif + (BP_PORT(bp) ? DMAE_CMD_PORT_1 : DMAE_CMD_PORT_0) | + (BP_E1HVN(bp) << DMAE_CMD_E1HVN_SHIFT)); + dmae->src_addr_lo = U64_LO(bnx2x_sp_mapping(bp, func_stats)); + dmae->src_addr_hi = U64_HI(bnx2x_sp_mapping(bp, func_stats)); + dmae->dst_addr_lo = bp->func_stx >> 2; + dmae->dst_addr_hi = 0; + dmae->len = sizeof(struct host_func_stats) >> 2; + dmae->comp_addr_lo = U64_LO(bnx2x_sp_mapping(bp, stats_comp)); + dmae->comp_addr_hi = U64_HI(bnx2x_sp_mapping(bp, stats_comp)); + dmae->comp_val = DMAE_COMP_VAL; + + *stats_comp = 0; +} + +static void bnx2x_stats_start(struct bnx2x *bp) +{ + if (bp->port.pmf) + bnx2x_port_stats_init(bp); + + else if (bp->func_stx) + bnx2x_func_stats_init(bp); + + bnx2x_hw_stats_post(bp); + bnx2x_storm_stats_post(bp); +} + +static void bnx2x_stats_pmf_start(struct bnx2x *bp) +{ + bnx2x_stats_comp(bp); + bnx2x_stats_pmf_update(bp); + bnx2x_stats_start(bp); +} + +static void bnx2x_stats_restart(struct bnx2x *bp) +{ + bnx2x_stats_comp(bp); + bnx2x_stats_start(bp); +} + +static void bnx2x_bmac_stats_update(struct bnx2x *bp) +{ + struct bmac_stats *new = bnx2x_sp(bp, mac_stats.bmac_stats); + struct host_port_stats *pstats = bnx2x_sp(bp, port_stats); + struct regpair diff; + + UPDATE_STAT64(rx_stat_grerb, rx_stat_ifhcinbadoctets); + UPDATE_STAT64(rx_stat_grfcs, rx_stat_dot3statsfcserrors); + UPDATE_STAT64(rx_stat_grund, rx_stat_etherstatsundersizepkts); + UPDATE_STAT64(rx_stat_grovr, rx_stat_dot3statsframestoolong); + UPDATE_STAT64(rx_stat_grfrg, rx_stat_etherstatsfragments); + UPDATE_STAT64(rx_stat_grjbr, rx_stat_etherstatsjabbers); + UPDATE_STAT64(rx_stat_grxpf, rx_stat_bmac_xpf); + UPDATE_STAT64(rx_stat_grxcf, rx_stat_bmac_xcf); + UPDATE_STAT64(rx_stat_grxpf, rx_stat_xoffstateentered); + UPDATE_STAT64(rx_stat_grxpf, rx_stat_xoffpauseframesreceived); + UPDATE_STAT64(tx_stat_gtxpf, tx_stat_outxoffsent); + UPDATE_STAT64(tx_stat_gtxpf, tx_stat_flowcontroldone); + UPDATE_STAT64(tx_stat_gt64, tx_stat_etherstatspkts64octets); + UPDATE_STAT64(tx_stat_gt127, + tx_stat_etherstatspkts65octetsto127octets); + UPDATE_STAT64(tx_stat_gt255, + tx_stat_etherstatspkts128octetsto255octets); + UPDATE_STAT64(tx_stat_gt511, + tx_stat_etherstatspkts256octetsto511octets); + UPDATE_STAT64(tx_stat_gt1023, + tx_stat_etherstatspkts512octetsto1023octets); + UPDATE_STAT64(tx_stat_gt1518, + tx_stat_etherstatspkts1024octetsto1522octets); + UPDATE_STAT64(tx_stat_gt2047, tx_stat_bmac_2047); + UPDATE_STAT64(tx_stat_gt4095, tx_stat_bmac_4095); + UPDATE_STAT64(tx_stat_gt9216, tx_stat_bmac_9216); + UPDATE_STAT64(tx_stat_gt16383, tx_stat_bmac_16383); + UPDATE_STAT64(tx_stat_gterr, + tx_stat_dot3statsinternalmactransmiterrors); + UPDATE_STAT64(tx_stat_gtufl, tx_stat_bmac_ufl); +} + +static void bnx2x_emac_stats_update(struct bnx2x *bp) +{ + struct emac_stats *new = bnx2x_sp(bp, mac_stats.emac_stats); + struct host_port_stats *pstats = bnx2x_sp(bp, port_stats); + + UPDATE_EXTEND_STAT(rx_stat_ifhcinbadoctets); + UPDATE_EXTEND_STAT(tx_stat_ifhcoutbadoctets); + UPDATE_EXTEND_STAT(rx_stat_dot3statsfcserrors); + UPDATE_EXTEND_STAT(rx_stat_dot3statsalignmenterrors); + UPDATE_EXTEND_STAT(rx_stat_dot3statscarriersenseerrors); + UPDATE_EXTEND_STAT(rx_stat_falsecarriererrors); + UPDATE_EXTEND_STAT(rx_stat_etherstatsundersizepkts); + UPDATE_EXTEND_STAT(rx_stat_dot3statsframestoolong); + UPDATE_EXTEND_STAT(rx_stat_etherstatsfragments); + UPDATE_EXTEND_STAT(rx_stat_etherstatsjabbers); + UPDATE_EXTEND_STAT(rx_stat_maccontrolframesreceived); + UPDATE_EXTEND_STAT(rx_stat_xoffstateentered); + UPDATE_EXTEND_STAT(rx_stat_xonpauseframesreceived); + UPDATE_EXTEND_STAT(rx_stat_xoffpauseframesreceived); + UPDATE_EXTEND_STAT(tx_stat_outxonsent); + UPDATE_EXTEND_STAT(tx_stat_outxoffsent); + UPDATE_EXTEND_STAT(tx_stat_flowcontroldone); + UPDATE_EXTEND_STAT(tx_stat_etherstatscollisions); + UPDATE_EXTEND_STAT(tx_stat_dot3statssinglecollisionframes); + UPDATE_EXTEND_STAT(tx_stat_dot3statsmultiplecollisionframes); + UPDATE_EXTEND_STAT(tx_stat_dot3statsdeferredtransmissions); + UPDATE_EXTEND_STAT(tx_stat_dot3statsexcessivecollisions); + UPDATE_EXTEND_STAT(tx_stat_dot3statslatecollisions); + UPDATE_EXTEND_STAT(tx_stat_etherstatspkts64octets); + UPDATE_EXTEND_STAT(tx_stat_etherstatspkts65octetsto127octets); + UPDATE_EXTEND_STAT(tx_stat_etherstatspkts128octetsto255octets); + UPDATE_EXTEND_STAT(tx_stat_etherstatspkts256octetsto511octets); + UPDATE_EXTEND_STAT(tx_stat_etherstatspkts512octetsto1023octets); + UPDATE_EXTEND_STAT(tx_stat_etherstatspkts1024octetsto1522octets); + UPDATE_EXTEND_STAT(tx_stat_etherstatspktsover1522octets); + UPDATE_EXTEND_STAT(tx_stat_dot3statsinternalmactransmiterrors); +} + +static int bnx2x_hw_stats_update(struct bnx2x *bp) +{ + struct nig_stats *new = bnx2x_sp(bp, nig_stats); + struct nig_stats *old = &(bp->port.old_nig_stats); + struct host_port_stats *pstats = bnx2x_sp(bp, port_stats); + struct bnx2x_eth_stats *estats = &bp->eth_stats; + struct regpair diff; + + if (bp->link_vars.mac_type == MAC_TYPE_BMAC) + bnx2x_bmac_stats_update(bp); + + else if (bp->link_vars.mac_type == MAC_TYPE_EMAC) + bnx2x_emac_stats_update(bp); + + else { /* unreached */ + BNX2X_ERR("stats updated by dmae but no MAC active\n"); + return -1; + } + + ADD_EXTEND_64(pstats->brb_drop_hi, pstats->brb_drop_lo, + new->brb_discard - old->brb_discard); + + UPDATE_STAT64_NIG(egress_mac_pkt0, + etherstatspkts1024octetsto1522octets); + UPDATE_STAT64_NIG(egress_mac_pkt1, etherstatspktsover1522octets); + + memcpy(old, new, sizeof(struct nig_stats)); + + memcpy(&(estats->rx_stat_ifhcinbadoctets_hi), &(pstats->mac_stx[1]), + sizeof(struct mac_stx)); + estats->brb_drop_hi = pstats->brb_drop_hi; + estats->brb_drop_lo = pstats->brb_drop_lo; + + pstats->host_port_stats_start = ++pstats->host_port_stats_end; + + return 0; +} + +static int bnx2x_storm_stats_update(struct bnx2x *bp) +{ + struct eth_stats_query *stats = bnx2x_sp(bp, fw_stats); + int cl_id = BP_CL_ID(bp); + struct tstorm_per_port_stats *tport = + &stats->tstorm_common.port_statistics; + struct tstorm_per_client_stats *tclient = + &stats->tstorm_common.client_statistics[cl_id]; + struct tstorm_per_client_stats *old_tclient = &bp->old_tclient; + struct xstorm_per_client_stats *xclient = + &stats->xstorm_common.client_statistics[cl_id]; + struct xstorm_per_client_stats *old_xclient = &bp->old_xclient; + struct host_func_stats *fstats = bnx2x_sp(bp, func_stats); + struct bnx2x_eth_stats *estats = &bp->eth_stats; + u32 diff; + + /* are storm stats valid? */ + if ((u16)(le16_to_cpu(tclient->stats_counter) + 1) != + bp->stats_counter) { + DP(BNX2X_MSG_STATS, "stats not updated by tstorm" + " tstorm counter (%d) != stats_counter (%d)\n", + tclient->stats_counter, bp->stats_counter); + return -1; + } + if ((u16)(le16_to_cpu(xclient->stats_counter) + 1) != + bp->stats_counter) { + DP(BNX2X_MSG_STATS, "stats not updated by xstorm" + " xstorm counter (%d) != stats_counter (%d)\n", + xclient->stats_counter, bp->stats_counter); + return -2; + } + + fstats->total_bytes_received_hi = + fstats->valid_bytes_received_hi = + le32_to_cpu(tclient->total_rcv_bytes.hi); + fstats->total_bytes_received_lo = + fstats->valid_bytes_received_lo = + le32_to_cpu(tclient->total_rcv_bytes.lo); + + estats->error_bytes_received_hi = + le32_to_cpu(tclient->rcv_error_bytes.hi); + estats->error_bytes_received_lo = + le32_to_cpu(tclient->rcv_error_bytes.lo); + ADD_64(estats->error_bytes_received_hi, + estats->rx_stat_ifhcinbadoctets_hi, + estats->error_bytes_received_lo, + estats->rx_stat_ifhcinbadoctets_lo); + + ADD_64(fstats->total_bytes_received_hi, + estats->error_bytes_received_hi, + fstats->total_bytes_received_lo, + estats->error_bytes_received_lo); + + UPDATE_EXTEND_TSTAT(rcv_unicast_pkts, total_unicast_packets_received); + UPDATE_EXTEND_TSTAT(rcv_multicast_pkts, + total_multicast_packets_received); + UPDATE_EXTEND_TSTAT(rcv_broadcast_pkts, + total_broadcast_packets_received); + + fstats->total_bytes_transmitted_hi = + le32_to_cpu(xclient->total_sent_bytes.hi); + fstats->total_bytes_transmitted_lo = + le32_to_cpu(xclient->total_sent_bytes.lo); + + UPDATE_EXTEND_XSTAT(unicast_pkts_sent, + total_unicast_packets_transmitted); + UPDATE_EXTEND_XSTAT(multicast_pkts_sent, + total_multicast_packets_transmitted); + UPDATE_EXTEND_XSTAT(broadcast_pkts_sent, + total_broadcast_packets_transmitted); + + memcpy(estats, &(fstats->total_bytes_received_hi), + sizeof(struct host_func_stats) - 2*sizeof(u32)); + + estats->mac_filter_discard = le32_to_cpu(tport->mac_filter_discard); + estats->xxoverflow_discard = le32_to_cpu(tport->xxoverflow_discard); + estats->brb_truncate_discard = + le32_to_cpu(tport->brb_truncate_discard); + estats->mac_discard = le32_to_cpu(tport->mac_discard); + + old_tclient->rcv_unicast_bytes.hi = + le32_to_cpu(tclient->rcv_unicast_bytes.hi); + old_tclient->rcv_unicast_bytes.lo = + le32_to_cpu(tclient->rcv_unicast_bytes.lo); + old_tclient->rcv_broadcast_bytes.hi = + le32_to_cpu(tclient->rcv_broadcast_bytes.hi); + old_tclient->rcv_broadcast_bytes.lo = + le32_to_cpu(tclient->rcv_broadcast_bytes.lo); + old_tclient->rcv_multicast_bytes.hi = + le32_to_cpu(tclient->rcv_multicast_bytes.hi); + old_tclient->rcv_multicast_bytes.lo = + le32_to_cpu(tclient->rcv_multicast_bytes.lo); + old_tclient->total_rcv_pkts = le32_to_cpu(tclient->total_rcv_pkts); + + old_tclient->checksum_discard = le32_to_cpu(tclient->checksum_discard); + old_tclient->packets_too_big_discard = + le32_to_cpu(tclient->packets_too_big_discard); + estats->no_buff_discard = + old_tclient->no_buff_discard = le32_to_cpu(tclient->no_buff_discard); + old_tclient->ttl0_discard = le32_to_cpu(tclient->ttl0_discard); + + old_xclient->total_sent_pkts = le32_to_cpu(xclient->total_sent_pkts); + old_xclient->unicast_bytes_sent.hi = + le32_to_cpu(xclient->unicast_bytes_sent.hi); + old_xclient->unicast_bytes_sent.lo = + le32_to_cpu(xclient->unicast_bytes_sent.lo); + old_xclient->multicast_bytes_sent.hi = + le32_to_cpu(xclient->multicast_bytes_sent.hi); + old_xclient->multicast_bytes_sent.lo = + le32_to_cpu(xclient->multicast_bytes_sent.lo); + old_xclient->broadcast_bytes_sent.hi = + le32_to_cpu(xclient->broadcast_bytes_sent.hi); + old_xclient->broadcast_bytes_sent.lo = + le32_to_cpu(xclient->broadcast_bytes_sent.lo); + + fstats->host_func_stats_start = ++fstats->host_func_stats_end; + + return 0; +} + +static void bnx2x_net_stats_update(struct bnx2x *bp) +{ + struct tstorm_per_client_stats *old_tclient = &bp->old_tclient; + struct bnx2x_eth_stats *estats = &bp->eth_stats; + struct net_device_stats *nstats = &bp->dev->stats; + + nstats->rx_packets = + bnx2x_hilo(&estats->total_unicast_packets_received_hi) + + bnx2x_hilo(&estats->total_multicast_packets_received_hi) + + bnx2x_hilo(&estats->total_broadcast_packets_received_hi); + + nstats->tx_packets = + bnx2x_hilo(&estats->total_unicast_packets_transmitted_hi) + + bnx2x_hilo(&estats->total_multicast_packets_transmitted_hi) + + bnx2x_hilo(&estats->total_broadcast_packets_transmitted_hi); + + nstats->rx_bytes = bnx2x_hilo(&estats->valid_bytes_received_hi); + + nstats->tx_bytes = bnx2x_hilo(&estats->total_bytes_transmitted_hi); + + nstats->rx_dropped = old_tclient->checksum_discard + + estats->mac_discard; + nstats->tx_dropped = 0; + + nstats->multicast = + bnx2x_hilo(&estats->total_multicast_packets_transmitted_hi); + + nstats->collisions = + estats->tx_stat_dot3statssinglecollisionframes_lo + + estats->tx_stat_dot3statsmultiplecollisionframes_lo + + estats->tx_stat_dot3statslatecollisions_lo + + estats->tx_stat_dot3statsexcessivecollisions_lo; + + estats->jabber_packets_received = + old_tclient->packets_too_big_discard + + estats->rx_stat_dot3statsframestoolong_lo; + + nstats->rx_length_errors = + estats->rx_stat_etherstatsundersizepkts_lo + + estats->jabber_packets_received; + nstats->rx_over_errors = estats->brb_drop_lo + + estats->brb_truncate_discard; + nstats->rx_crc_errors = estats->rx_stat_dot3statsfcserrors_lo; + nstats->rx_frame_errors = estats->rx_stat_dot3statsalignmenterrors_lo; + nstats->rx_fifo_errors = old_tclient->no_buff_discard; + nstats->rx_missed_errors = estats->xxoverflow_discard; + + nstats->rx_errors = nstats->rx_length_errors + + nstats->rx_over_errors + + nstats->rx_crc_errors + + nstats->rx_frame_errors + + nstats->rx_fifo_errors + + nstats->rx_missed_errors; + + nstats->tx_aborted_errors = + estats->tx_stat_dot3statslatecollisions_lo + + estats->tx_stat_dot3statsexcessivecollisions_lo; + nstats->tx_carrier_errors = estats->rx_stat_falsecarriererrors_lo; + nstats->tx_fifo_errors = 0; + nstats->tx_heartbeat_errors = 0; + nstats->tx_window_errors = 0; + + nstats->tx_errors = nstats->tx_aborted_errors + + nstats->tx_carrier_errors; +} + +static void bnx2x_stats_update(struct bnx2x *bp) +{ + u32 *stats_comp = bnx2x_sp(bp, stats_comp); + int update = 0; + + if (*stats_comp != DMAE_COMP_VAL) + return; + + if (bp->port.pmf) + update = (bnx2x_hw_stats_update(bp) == 0); + + update |= (bnx2x_storm_stats_update(bp) == 0); + + if (update) + bnx2x_net_stats_update(bp); + + else { + if (bp->stats_pending) { + bp->stats_pending++; + if (bp->stats_pending == 3) { + BNX2X_ERR("stats not updated for 3 times\n"); + bnx2x_panic(); + return; + } + } + } + + if (bp->msglevel & NETIF_MSG_TIMER) { + struct tstorm_per_client_stats *old_tclient = &bp->old_tclient; + struct bnx2x_eth_stats *estats = &bp->eth_stats; + struct net_device_stats *nstats = &bp->dev->stats; + int i; + + printk(KERN_DEBUG "%s:\n", bp->dev->name); + printk(KERN_DEBUG " tx avail (%4x) tx hc idx (%x)" + " tx pkt (%lx)\n", + bnx2x_tx_avail(bp->fp), + le16_to_cpu(*bp->fp->tx_cons_sb), nstats->tx_packets); + printk(KERN_DEBUG " rx usage (%4x) rx hc idx (%x)" + " rx pkt (%lx)\n", + (u16)(le16_to_cpu(*bp->fp->rx_cons_sb) - + bp->fp->rx_comp_cons), + le16_to_cpu(*bp->fp->rx_cons_sb), nstats->rx_packets); + printk(KERN_DEBUG " %s (Xoff events %u) brb drops %u\n", + netif_queue_stopped(bp->dev)? "Xoff" : "Xon", + estats->driver_xoff, estats->brb_drop_lo); + printk(KERN_DEBUG "tstats: checksum_discard %u " + "packets_too_big_discard %u no_buff_discard %u " + "mac_discard %u mac_filter_discard %u " + "xxovrflow_discard %u brb_truncate_discard %u " + "ttl0_discard %u\n", + old_tclient->checksum_discard, + old_tclient->packets_too_big_discard, + old_tclient->no_buff_discard, estats->mac_discard, + estats->mac_filter_discard, estats->xxoverflow_discard, + estats->brb_truncate_discard, + old_tclient->ttl0_discard); + + for_each_queue(bp, i) { + printk(KERN_DEBUG "[%d]: %lu\t%lu\t%lu\n", i, + bnx2x_fp(bp, i, tx_pkt), + bnx2x_fp(bp, i, rx_pkt), + bnx2x_fp(bp, i, rx_calls)); + } + } + + bnx2x_hw_stats_post(bp); + bnx2x_storm_stats_post(bp); +} + +static void bnx2x_port_stats_stop(struct bnx2x *bp) +{ + struct dmae_command *dmae; + u32 opcode; + int loader_idx = PMF_DMAE_C(bp); + u32 *stats_comp = bnx2x_sp(bp, stats_comp); + + bp->executer_idx = 0; + + opcode = (DMAE_CMD_SRC_PCI | DMAE_CMD_DST_GRC | + DMAE_CMD_C_ENABLE | + DMAE_CMD_SRC_RESET | DMAE_CMD_DST_RESET | +#ifdef __BIG_ENDIAN + DMAE_CMD_ENDIANITY_B_DW_SWAP | +#else + DMAE_CMD_ENDIANITY_DW_SWAP | +#endif + (BP_PORT(bp) ? DMAE_CMD_PORT_1 : DMAE_CMD_PORT_0) | + (BP_E1HVN(bp) << DMAE_CMD_E1HVN_SHIFT)); + + if (bp->port.port_stx) { + + dmae = bnx2x_sp(bp, dmae[bp->executer_idx++]); + if (bp->func_stx) + dmae->opcode = (opcode | DMAE_CMD_C_DST_GRC); + else + dmae->opcode = (opcode | DMAE_CMD_C_DST_PCI); + dmae->src_addr_lo = U64_LO(bnx2x_sp_mapping(bp, port_stats)); + dmae->src_addr_hi = U64_HI(bnx2x_sp_mapping(bp, port_stats)); + dmae->dst_addr_lo = bp->port.port_stx >> 2; + dmae->dst_addr_hi = 0; + dmae->len = sizeof(struct host_port_stats) >> 2; + if (bp->func_stx) { + dmae->comp_addr_lo = dmae_reg_go_c[loader_idx] >> 2; + dmae->comp_addr_hi = 0; + dmae->comp_val = 1; + } else { + dmae->comp_addr_lo = + U64_LO(bnx2x_sp_mapping(bp, stats_comp)); + dmae->comp_addr_hi = + U64_HI(bnx2x_sp_mapping(bp, stats_comp)); + dmae->comp_val = DMAE_COMP_VAL; + + *stats_comp = 0; + } + } + + if (bp->func_stx) { + + dmae = bnx2x_sp(bp, dmae[bp->executer_idx++]); + dmae->opcode = (opcode | DMAE_CMD_C_DST_PCI); + dmae->src_addr_lo = U64_LO(bnx2x_sp_mapping(bp, func_stats)); + dmae->src_addr_hi = U64_HI(bnx2x_sp_mapping(bp, func_stats)); + dmae->dst_addr_lo = bp->func_stx >> 2; + dmae->dst_addr_hi = 0; + dmae->len = sizeof(struct host_func_stats) >> 2; + dmae->comp_addr_lo = U64_LO(bnx2x_sp_mapping(bp, stats_comp)); + dmae->comp_addr_hi = U64_HI(bnx2x_sp_mapping(bp, stats_comp)); + dmae->comp_val = DMAE_COMP_VAL; + + *stats_comp = 0; + } +} + +static void bnx2x_stats_stop(struct bnx2x *bp) +{ + int update = 0; + + bnx2x_stats_comp(bp); + + if (bp->port.pmf) + update = (bnx2x_hw_stats_update(bp) == 0); + + update |= (bnx2x_storm_stats_update(bp) == 0); + + if (update) { + bnx2x_net_stats_update(bp); + + if (bp->port.pmf) + bnx2x_port_stats_stop(bp); + + bnx2x_hw_stats_post(bp); + bnx2x_stats_comp(bp); + } +} + +static void bnx2x_stats_do_nothing(struct bnx2x *bp) +{ +} + +static const struct { + void (*action)(struct bnx2x *bp); + enum bnx2x_stats_state next_state; +} bnx2x_stats_stm[STATS_STATE_MAX][STATS_EVENT_MAX] = { +/* state event */ +{ +/* DISABLED PMF */ {bnx2x_stats_pmf_update, STATS_STATE_DISABLED}, +/* LINK_UP */ {bnx2x_stats_start, STATS_STATE_ENABLED}, +/* UPDATE */ {bnx2x_stats_do_nothing, STATS_STATE_DISABLED}, +/* STOP */ {bnx2x_stats_do_nothing, STATS_STATE_DISABLED} +}, +{ +/* ENABLED PMF */ {bnx2x_stats_pmf_start, STATS_STATE_ENABLED}, +/* LINK_UP */ {bnx2x_stats_restart, STATS_STATE_ENABLED}, +/* UPDATE */ {bnx2x_stats_update, STATS_STATE_ENABLED}, +/* STOP */ {bnx2x_stats_stop, STATS_STATE_DISABLED} +} +}; + +static void bnx2x_stats_handle(struct bnx2x *bp, enum bnx2x_stats_event event) +{ + enum bnx2x_stats_state state = bp->stats_state; + + bnx2x_stats_stm[state][event].action(bp); + bp->stats_state = bnx2x_stats_stm[state][event].next_state; + + if ((event != STATS_EVENT_UPDATE) || (bp->msglevel & NETIF_MSG_TIMER)) + DP(BNX2X_MSG_STATS, "state %d -> event %d -> state %d\n", + state, event, bp->stats_state); +} + +static void bnx2x_timer(unsigned long data) +{ + struct bnx2x *bp = (struct bnx2x *) data; + + if (!netif_running(bp->dev)) + return; + + if (atomic_read(&bp->intr_sem) != 0) + goto timer_restart; + + if (poll) { + struct bnx2x_fastpath *fp = &bp->fp[0]; + int rc; + + bnx2x_tx_int(fp, 1000); + rc = bnx2x_rx_int(fp, 1000); + } + + if (!BP_NOMCP(bp)) { + int func = BP_FUNC(bp); + u32 drv_pulse; + u32 mcp_pulse; + + ++bp->fw_drv_pulse_wr_seq; + bp->fw_drv_pulse_wr_seq &= DRV_PULSE_SEQ_MASK; + /* TBD - add SYSTEM_TIME */ + drv_pulse = bp->fw_drv_pulse_wr_seq; + SHMEM_WR(bp, func_mb[func].drv_pulse_mb, drv_pulse); + + mcp_pulse = (SHMEM_RD(bp, func_mb[func].mcp_pulse_mb) & + MCP_PULSE_SEQ_MASK); + /* The delta between driver pulse and mcp response + * should be 1 (before mcp response) or 0 (after mcp response) + */ + if ((drv_pulse != mcp_pulse) && + (drv_pulse != ((mcp_pulse + 1) & MCP_PULSE_SEQ_MASK))) { + /* someone lost a heartbeat... */ + BNX2X_ERR("drv_pulse (0x%x) != mcp_pulse (0x%x)\n", + drv_pulse, mcp_pulse); + } + } + + if ((bp->state == BNX2X_STATE_OPEN) || + (bp->state == BNX2X_STATE_DISABLED)) + bnx2x_stats_handle(bp, STATS_EVENT_UPDATE); + +timer_restart: + mod_timer(&bp->timer, jiffies + bp->current_interval); +} + +/* end of Statistics */ + +/* nic init */ + +/* + * nic init service functions + */ + +static void bnx2x_zero_sb(struct bnx2x *bp, int sb_id) +{ + int port = BP_PORT(bp); + + bnx2x_init_fill(bp, BAR_USTRORM_INTMEM + + USTORM_SB_HOST_STATUS_BLOCK_OFFSET(port, sb_id), 0, + sizeof(struct ustorm_def_status_block)/4); + bnx2x_init_fill(bp, BAR_CSTRORM_INTMEM + + CSTORM_SB_HOST_STATUS_BLOCK_OFFSET(port, sb_id), 0, + sizeof(struct cstorm_def_status_block)/4); +} + +static void bnx2x_init_sb(struct bnx2x *bp, int sb_id, + struct host_status_block *sb, dma_addr_t mapping) +{ + int port = BP_PORT(bp); + int func = BP_FUNC(bp); + int index; + u64 section; + + /* USTORM */ + section = ((u64)mapping) + offsetof(struct host_status_block, + u_status_block); + sb->u_status_block.status_block_id = sb_id; + + REG_WR(bp, BAR_USTRORM_INTMEM + + USTORM_SB_HOST_SB_ADDR_OFFSET(port, sb_id), U64_LO(section)); + REG_WR(bp, BAR_USTRORM_INTMEM + + ((USTORM_SB_HOST_SB_ADDR_OFFSET(port, sb_id)) + 4), + U64_HI(section)); + REG_WR8(bp, BAR_USTRORM_INTMEM + FP_USB_FUNC_OFF + + USTORM_SB_HOST_STATUS_BLOCK_OFFSET(port, sb_id), func); + + for (index = 0; index < HC_USTORM_SB_NUM_INDICES; index++) + REG_WR16(bp, BAR_USTRORM_INTMEM + + USTORM_SB_HC_DISABLE_OFFSET(port, sb_id, index), 1); + + /* CSTORM */ + section = ((u64)mapping) + offsetof(struct host_status_block, + c_status_block); + sb->c_status_block.status_block_id = sb_id; + + REG_WR(bp, BAR_CSTRORM_INTMEM + + CSTORM_SB_HOST_SB_ADDR_OFFSET(port, sb_id), U64_LO(section)); + REG_WR(bp, BAR_CSTRORM_INTMEM + + ((CSTORM_SB_HOST_SB_ADDR_OFFSET(port, sb_id)) + 4), + U64_HI(section)); + REG_WR8(bp, BAR_CSTRORM_INTMEM + FP_CSB_FUNC_OFF + + CSTORM_SB_HOST_STATUS_BLOCK_OFFSET(port, sb_id), func); + + for (index = 0; index < HC_CSTORM_SB_NUM_INDICES; index++) + REG_WR16(bp, BAR_CSTRORM_INTMEM + + CSTORM_SB_HC_DISABLE_OFFSET(port, sb_id, index), 1); + + bnx2x_ack_sb(bp, sb_id, CSTORM_ID, 0, IGU_INT_ENABLE, 0); +} + +static void bnx2x_zero_def_sb(struct bnx2x *bp) +{ + int func = BP_FUNC(bp); + + bnx2x_init_fill(bp, BAR_USTRORM_INTMEM + + USTORM_DEF_SB_HOST_STATUS_BLOCK_OFFSET(func), 0, + sizeof(struct ustorm_def_status_block)/4); + bnx2x_init_fill(bp, BAR_CSTRORM_INTMEM + + CSTORM_DEF_SB_HOST_STATUS_BLOCK_OFFSET(func), 0, + sizeof(struct cstorm_def_status_block)/4); + bnx2x_init_fill(bp, BAR_XSTRORM_INTMEM + + XSTORM_DEF_SB_HOST_STATUS_BLOCK_OFFSET(func), 0, + sizeof(struct xstorm_def_status_block)/4); + bnx2x_init_fill(bp, BAR_TSTRORM_INTMEM + + TSTORM_DEF_SB_HOST_STATUS_BLOCK_OFFSET(func), 0, + sizeof(struct tstorm_def_status_block)/4); +} + +static void bnx2x_init_def_sb(struct bnx2x *bp, + struct host_def_status_block *def_sb, + dma_addr_t mapping, int sb_id) +{ + int port = BP_PORT(bp); + int func = BP_FUNC(bp); + int index, val, reg_offset; + u64 section; + + /* ATTN */ + section = ((u64)mapping) + offsetof(struct host_def_status_block, + atten_status_block); + def_sb->atten_status_block.status_block_id = sb_id; + + bp->def_att_idx = 0; + bp->attn_state = 0; + + reg_offset = (port ? MISC_REG_AEU_ENABLE1_FUNC_1_OUT_0 : + MISC_REG_AEU_ENABLE1_FUNC_0_OUT_0); + + for (index = 0; index < MAX_DYNAMIC_ATTN_GRPS; index++) { + bp->attn_group[index].sig[0] = REG_RD(bp, + reg_offset + 0x10*index); + bp->attn_group[index].sig[1] = REG_RD(bp, + reg_offset + 0x4 + 0x10*index); + bp->attn_group[index].sig[2] = REG_RD(bp, + reg_offset + 0x8 + 0x10*index); + bp->attn_group[index].sig[3] = REG_RD(bp, + reg_offset + 0xc + 0x10*index); + } + + bp->aeu_mask = REG_RD(bp, (port ? MISC_REG_AEU_MASK_ATTN_FUNC_1 : + MISC_REG_AEU_MASK_ATTN_FUNC_0)); + + reg_offset = (port ? HC_REG_ATTN_MSG1_ADDR_L : + HC_REG_ATTN_MSG0_ADDR_L); + + REG_WR(bp, reg_offset, U64_LO(section)); + REG_WR(bp, reg_offset + 4, U64_HI(section)); + + reg_offset = (port ? HC_REG_ATTN_NUM_P1 : HC_REG_ATTN_NUM_P0); + + val = REG_RD(bp, reg_offset); + val |= sb_id; + REG_WR(bp, reg_offset, val); + + /* USTORM */ + section = ((u64)mapping) + offsetof(struct host_def_status_block, + u_def_status_block); + def_sb->u_def_status_block.status_block_id = sb_id; + + bp->def_u_idx = 0; + + REG_WR(bp, BAR_USTRORM_INTMEM + + USTORM_DEF_SB_HOST_SB_ADDR_OFFSET(func), U64_LO(section)); + REG_WR(bp, BAR_USTRORM_INTMEM + + ((USTORM_DEF_SB_HOST_SB_ADDR_OFFSET(func)) + 4), + U64_HI(section)); + REG_WR8(bp, BAR_USTRORM_INTMEM + DEF_USB_FUNC_OFF + + USTORM_DEF_SB_HOST_STATUS_BLOCK_OFFSET(func), func); + REG_WR(bp, BAR_USTRORM_INTMEM + USTORM_HC_BTR_OFFSET(func), + BNX2X_BTR); + + for (index = 0; index < HC_USTORM_DEF_SB_NUM_INDICES; index++) + REG_WR16(bp, BAR_USTRORM_INTMEM + + USTORM_DEF_SB_HC_DISABLE_OFFSET(func, index), 1); + + /* CSTORM */ + section = ((u64)mapping) + offsetof(struct host_def_status_block, + c_def_status_block); + def_sb->c_def_status_block.status_block_id = sb_id; + + bp->def_c_idx = 0; + + REG_WR(bp, BAR_CSTRORM_INTMEM + + CSTORM_DEF_SB_HOST_SB_ADDR_OFFSET(func), U64_LO(section)); + REG_WR(bp, BAR_CSTRORM_INTMEM + + ((CSTORM_DEF_SB_HOST_SB_ADDR_OFFSET(func)) + 4), + U64_HI(section)); + REG_WR8(bp, BAR_CSTRORM_INTMEM + DEF_CSB_FUNC_OFF + + CSTORM_DEF_SB_HOST_STATUS_BLOCK_OFFSET(func), func); + REG_WR(bp, BAR_CSTRORM_INTMEM + CSTORM_HC_BTR_OFFSET(func), + BNX2X_BTR); + + for (index = 0; index < HC_CSTORM_DEF_SB_NUM_INDICES; index++) + REG_WR16(bp, BAR_CSTRORM_INTMEM + + CSTORM_DEF_SB_HC_DISABLE_OFFSET(func, index), 1); + + /* TSTORM */ + section = ((u64)mapping) + offsetof(struct host_def_status_block, + t_def_status_block); + def_sb->t_def_status_block.status_block_id = sb_id; + + bp->def_t_idx = 0; + + REG_WR(bp, BAR_TSTRORM_INTMEM + + TSTORM_DEF_SB_HOST_SB_ADDR_OFFSET(func), U64_LO(section)); + REG_WR(bp, BAR_TSTRORM_INTMEM + + ((TSTORM_DEF_SB_HOST_SB_ADDR_OFFSET(func)) + 4), + U64_HI(section)); + REG_WR8(bp, BAR_TSTRORM_INTMEM + DEF_TSB_FUNC_OFF + + TSTORM_DEF_SB_HOST_STATUS_BLOCK_OFFSET(func), func); + REG_WR(bp, BAR_TSTRORM_INTMEM + TSTORM_HC_BTR_OFFSET(func), + BNX2X_BTR); + + for (index = 0; index < HC_TSTORM_DEF_SB_NUM_INDICES; index++) + REG_WR16(bp, BAR_TSTRORM_INTMEM + + TSTORM_DEF_SB_HC_DISABLE_OFFSET(func, index), 1); + + /* XSTORM */ + section = ((u64)mapping) + offsetof(struct host_def_status_block, + x_def_status_block); + def_sb->x_def_status_block.status_block_id = sb_id; + + bp->def_x_idx = 0; + + REG_WR(bp, BAR_XSTRORM_INTMEM + + XSTORM_DEF_SB_HOST_SB_ADDR_OFFSET(func), U64_LO(section)); + REG_WR(bp, BAR_XSTRORM_INTMEM + + ((XSTORM_DEF_SB_HOST_SB_ADDR_OFFSET(func)) + 4), + U64_HI(section)); + REG_WR8(bp, BAR_XSTRORM_INTMEM + DEF_XSB_FUNC_OFF + + XSTORM_DEF_SB_HOST_STATUS_BLOCK_OFFSET(func), func); + REG_WR(bp, BAR_XSTRORM_INTMEM + XSTORM_HC_BTR_OFFSET(func), + BNX2X_BTR); + + for (index = 0; index < HC_XSTORM_DEF_SB_NUM_INDICES; index++) + REG_WR16(bp, BAR_XSTRORM_INTMEM + + XSTORM_DEF_SB_HC_DISABLE_OFFSET(func, index), 1); + + bp->stats_pending = 0; + + bnx2x_ack_sb(bp, sb_id, CSTORM_ID, 0, IGU_INT_ENABLE, 0); +} + +static void bnx2x_update_coalesce(struct bnx2x *bp) +{ + int port = BP_PORT(bp); + int i; + + for_each_queue(bp, i) { + int sb_id = bp->fp[i].sb_id; + + /* HC_INDEX_U_ETH_RX_CQ_CONS */ + REG_WR8(bp, BAR_USTRORM_INTMEM + + USTORM_SB_HC_TIMEOUT_OFFSET(port, sb_id, + HC_INDEX_U_ETH_RX_CQ_CONS), + bp->rx_ticks/12); + REG_WR16(bp, BAR_USTRORM_INTMEM + + USTORM_SB_HC_DISABLE_OFFSET(port, sb_id, + HC_INDEX_U_ETH_RX_CQ_CONS), + bp->rx_ticks ? 0 : 1); + + /* HC_INDEX_C_ETH_TX_CQ_CONS */ + REG_WR8(bp, BAR_CSTRORM_INTMEM + + CSTORM_SB_HC_TIMEOUT_OFFSET(port, sb_id, + HC_INDEX_C_ETH_TX_CQ_CONS), + bp->tx_ticks/12); + REG_WR16(bp, BAR_CSTRORM_INTMEM + + CSTORM_SB_HC_DISABLE_OFFSET(port, sb_id, + HC_INDEX_C_ETH_TX_CQ_CONS), + bp->tx_ticks ? 0 : 1); + } +} + +static inline void bnx2x_free_tpa_pool(struct bnx2x *bp, + struct bnx2x_fastpath *fp, int last) +{ + int i; + + for (i = 0; i < last; i++) { + struct sw_rx_bd *rx_buf = &(fp->tpa_pool[i]); + struct sk_buff *skb = rx_buf->skb; + + if (skb == NULL) { + DP(NETIF_MSG_IFDOWN, "tpa bin %d empty on free\n", i); + continue; + } + + if (fp->tpa_state[i] == BNX2X_TPA_START) + pci_unmap_single(bp->pdev, + pci_unmap_addr(rx_buf, mapping), + bp->rx_buf_use_size, + PCI_DMA_FROMDEVICE); + + dev_kfree_skb(skb); + rx_buf->skb = NULL; + } +} + +static void bnx2x_init_rx_rings(struct bnx2x *bp) +{ + int func = BP_FUNC(bp); + u16 ring_prod, cqe_ring_prod = 0; + int i, j; + + bp->rx_buf_use_size = bp->dev->mtu; + bp->rx_buf_use_size += bp->rx_offset + ETH_OVREHEAD; + bp->rx_buf_size = bp->rx_buf_use_size + 64; + + if (bp->flags & TPA_ENABLE_FLAG) { + DP(NETIF_MSG_IFUP, + "rx_buf_use_size %d rx_buf_size %d effective_mtu %d\n", + bp->rx_buf_use_size, bp->rx_buf_size, + bp->dev->mtu + ETH_OVREHEAD); + + for_each_queue(bp, j) { + for (i = 0; i < ETH_MAX_AGGREGATION_QUEUES_E1H; i++) { + struct bnx2x_fastpath *fp = &bp->fp[j]; + + fp->tpa_pool[i].skb = + netdev_alloc_skb(bp->dev, bp->rx_buf_size); + if (!fp->tpa_pool[i].skb) { + BNX2X_ERR("Failed to allocate TPA " + "skb pool for queue[%d] - " + "disabling TPA on this " + "queue!\n", j); + bnx2x_free_tpa_pool(bp, fp, i); + fp->disable_tpa = 1; + break; + } + pci_unmap_addr_set((struct sw_rx_bd *) + &bp->fp->tpa_pool[i], + mapping, 0); + fp->tpa_state[i] = BNX2X_TPA_STOP; + } + } + } + + for_each_queue(bp, j) { + struct bnx2x_fastpath *fp = &bp->fp[j]; + + fp->rx_bd_cons = 0; + fp->rx_cons_sb = BNX2X_RX_SB_INDEX; + fp->rx_bd_cons_sb = BNX2X_RX_SB_BD_INDEX; + + /* "next page" elements initialization */ + /* SGE ring */ + for (i = 1; i <= NUM_RX_SGE_PAGES; i++) { + struct eth_rx_sge *sge; + + sge = &fp->rx_sge_ring[RX_SGE_CNT * i - 2]; + sge->addr_hi = + cpu_to_le32(U64_HI(fp->rx_sge_mapping + + BCM_PAGE_SIZE*(i % NUM_RX_SGE_PAGES))); + sge->addr_lo = + cpu_to_le32(U64_LO(fp->rx_sge_mapping + + BCM_PAGE_SIZE*(i % NUM_RX_SGE_PAGES))); + } + + bnx2x_init_sge_ring_bit_mask(fp); + + /* RX BD ring */ + for (i = 1; i <= NUM_RX_RINGS; i++) { + struct eth_rx_bd *rx_bd; + + rx_bd = &fp->rx_desc_ring[RX_DESC_CNT * i - 2]; + rx_bd->addr_hi = + cpu_to_le32(U64_HI(fp->rx_desc_mapping + + BCM_PAGE_SIZE*(i % NUM_RX_RINGS))); + rx_bd->addr_lo = + cpu_to_le32(U64_LO(fp->rx_desc_mapping + + BCM_PAGE_SIZE*(i % NUM_RX_RINGS))); + } + + /* CQ ring */ + for (i = 1; i <= NUM_RCQ_RINGS; i++) { + struct eth_rx_cqe_next_page *nextpg; + + nextpg = (struct eth_rx_cqe_next_page *) + &fp->rx_comp_ring[RCQ_DESC_CNT * i - 1]; + nextpg->addr_hi = + cpu_to_le32(U64_HI(fp->rx_comp_mapping + + BCM_PAGE_SIZE*(i % NUM_RCQ_RINGS))); + nextpg->addr_lo = + cpu_to_le32(U64_LO(fp->rx_comp_mapping + + BCM_PAGE_SIZE*(i % NUM_RCQ_RINGS))); + } + + /* Allocate SGEs and initialize the ring elements */ + for (i = 0, ring_prod = 0; + i < MAX_RX_SGE_CNT*NUM_RX_SGE_PAGES; i++) { + + if (bnx2x_alloc_rx_sge(bp, fp, ring_prod) < 0) { + BNX2X_ERR("was only able to allocate " + "%d rx sges\n", i); + BNX2X_ERR("disabling TPA for queue[%d]\n", j); + /* Cleanup already allocated elements */ + bnx2x_free_rx_sge_range(bp, fp, ring_prod); + bnx2x_free_tpa_pool(bp, fp, + ETH_MAX_AGGREGATION_QUEUES_E1H); + fp->disable_tpa = 1; + ring_prod = 0; + break; + } + ring_prod = NEXT_SGE_IDX(ring_prod); + } + fp->rx_sge_prod = ring_prod; + + /* Allocate BDs and initialize BD ring */ + fp->rx_comp_cons = fp->rx_alloc_failed = 0; + cqe_ring_prod = ring_prod = 0; + for (i = 0; i < bp->rx_ring_size; i++) { + if (bnx2x_alloc_rx_skb(bp, fp, ring_prod) < 0) { + BNX2X_ERR("was only able to allocate " + "%d rx skbs\n", i); + fp->rx_alloc_failed++; + break; + } + ring_prod = NEXT_RX_IDX(ring_prod); + cqe_ring_prod = NEXT_RCQ_IDX(cqe_ring_prod); + BUG_TRAP(ring_prod > i); + } + + fp->rx_bd_prod = ring_prod; + /* must not have more available CQEs than BDs */ + fp->rx_comp_prod = min((u16)(NUM_RCQ_RINGS*RCQ_DESC_CNT), + cqe_ring_prod); + fp->rx_pkt = fp->rx_calls = 0; + + /* Warning! + * this will generate an interrupt (to the TSTORM) + * must only be done after chip is initialized + */ + bnx2x_update_rx_prod(bp, fp, ring_prod, fp->rx_comp_prod, + fp->rx_sge_prod); + if (j != 0) + continue; + + REG_WR(bp, BAR_USTRORM_INTMEM + + USTORM_MEM_WORKAROUND_ADDRESS_OFFSET(func), + U64_LO(fp->rx_comp_mapping)); + REG_WR(bp, BAR_USTRORM_INTMEM + + USTORM_MEM_WORKAROUND_ADDRESS_OFFSET(func) + 4, + U64_HI(fp->rx_comp_mapping)); + } +} + +static void bnx2x_init_tx_ring(struct bnx2x *bp) +{ + int i, j; + + for_each_queue(bp, j) { + struct bnx2x_fastpath *fp = &bp->fp[j]; + + for (i = 1; i <= NUM_TX_RINGS; i++) { + struct eth_tx_bd *tx_bd = + &fp->tx_desc_ring[TX_DESC_CNT * i - 1]; + + tx_bd->addr_hi = + cpu_to_le32(U64_HI(fp->tx_desc_mapping + + BCM_PAGE_SIZE*(i % NUM_TX_RINGS))); + tx_bd->addr_lo = + cpu_to_le32(U64_LO(fp->tx_desc_mapping + + BCM_PAGE_SIZE*(i % NUM_TX_RINGS))); + } + + fp->tx_pkt_prod = 0; + fp->tx_pkt_cons = 0; + fp->tx_bd_prod = 0; + fp->tx_bd_cons = 0; + fp->tx_cons_sb = BNX2X_TX_SB_INDEX; + fp->tx_pkt = 0; + } +} + +static void bnx2x_init_sp_ring(struct bnx2x *bp) +{ + int func = BP_FUNC(bp); + + spin_lock_init(&bp->spq_lock); + + bp->spq_left = MAX_SPQ_PENDING; + bp->spq_prod_idx = 0; + bp->dsb_sp_prod = BNX2X_SP_DSB_INDEX; + bp->spq_prod_bd = bp->spq; + bp->spq_last_bd = bp->spq_prod_bd + MAX_SP_DESC_CNT; + + REG_WR(bp, XSEM_REG_FAST_MEMORY + XSTORM_SPQ_PAGE_BASE_OFFSET(func), + U64_LO(bp->spq_mapping)); + REG_WR(bp, + XSEM_REG_FAST_MEMORY + XSTORM_SPQ_PAGE_BASE_OFFSET(func) + 4, + U64_HI(bp->spq_mapping)); + + REG_WR(bp, XSEM_REG_FAST_MEMORY + XSTORM_SPQ_PROD_OFFSET(func), + bp->spq_prod_idx); +} + +static void bnx2x_init_context(struct bnx2x *bp) +{ + int i; + + for_each_queue(bp, i) { + struct eth_context *context = bnx2x_sp(bp, context[i].eth); + struct bnx2x_fastpath *fp = &bp->fp[i]; + u8 sb_id = FP_SB_ID(fp); + + context->xstorm_st_context.tx_bd_page_base_hi = + U64_HI(fp->tx_desc_mapping); + context->xstorm_st_context.tx_bd_page_base_lo = + U64_LO(fp->tx_desc_mapping); + context->xstorm_st_context.db_data_addr_hi = + U64_HI(fp->tx_prods_mapping); + context->xstorm_st_context.db_data_addr_lo = + U64_LO(fp->tx_prods_mapping); + context->xstorm_st_context.statistics_data = (BP_CL_ID(bp) | + XSTORM_ETH_ST_CONTEXT_STATISTICS_ENABLE); + + context->ustorm_st_context.common.sb_index_numbers = + BNX2X_RX_SB_INDEX_NUM; + context->ustorm_st_context.common.clientId = FP_CL_ID(fp); + context->ustorm_st_context.common.status_block_id = sb_id; + context->ustorm_st_context.common.flags = + USTORM_ETH_ST_CONTEXT_CONFIG_ENABLE_MC_ALIGNMENT; + context->ustorm_st_context.common.mc_alignment_size = 64; + context->ustorm_st_context.common.bd_buff_size = + bp->rx_buf_use_size; + context->ustorm_st_context.common.bd_page_base_hi = + U64_HI(fp->rx_desc_mapping); + context->ustorm_st_context.common.bd_page_base_lo = + U64_LO(fp->rx_desc_mapping); + if (!fp->disable_tpa) { + context->ustorm_st_context.common.flags |= + (USTORM_ETH_ST_CONTEXT_CONFIG_ENABLE_TPA | + USTORM_ETH_ST_CONTEXT_CONFIG_ENABLE_SGE_RING); + context->ustorm_st_context.common.sge_buff_size = + (u16)(BCM_PAGE_SIZE*PAGES_PER_SGE); + context->ustorm_st_context.common.sge_page_base_hi = + U64_HI(fp->rx_sge_mapping); + context->ustorm_st_context.common.sge_page_base_lo = + U64_LO(fp->rx_sge_mapping); + } + + context->cstorm_st_context.sb_index_number = + HC_INDEX_C_ETH_TX_CQ_CONS; + context->cstorm_st_context.status_block_id = sb_id; + + context->xstorm_ag_context.cdu_reserved = + CDU_RSRVD_VALUE_TYPE_A(HW_CID(bp, i), + CDU_REGION_NUMBER_XCM_AG, + ETH_CONNECTION_TYPE); + context->ustorm_ag_context.cdu_usage = + CDU_RSRVD_VALUE_TYPE_A(HW_CID(bp, i), + CDU_REGION_NUMBER_UCM_AG, + ETH_CONNECTION_TYPE); + } +} + +static void bnx2x_init_ind_table(struct bnx2x *bp) +{ + int port = BP_PORT(bp); + int i; + + if (!is_multi(bp)) + return; + + DP(NETIF_MSG_IFUP, "Initializing indirection table\n"); + for (i = 0; i < TSTORM_INDIRECTION_TABLE_SIZE; i++) + REG_WR8(bp, BAR_TSTRORM_INTMEM + + TSTORM_INDIRECTION_TABLE_OFFSET(port) + i, + i % bp->num_queues); + + REG_WR(bp, PRS_REG_A_PRSU_20, 0xf); +} + +static void bnx2x_set_client_config(struct bnx2x *bp) +{ + struct tstorm_eth_client_config tstorm_client = {0}; + int port = BP_PORT(bp); + int i; + + tstorm_client.mtu = bp->dev->mtu + ETH_OVREHEAD; + tstorm_client.statistics_counter_id = 0; + tstorm_client.config_flags = + TSTORM_ETH_CLIENT_CONFIG_STATSITICS_ENABLE; +#ifdef BCM_VLAN + if (bp->rx_mode && bp->vlgrp) { + tstorm_client.config_flags |= + TSTORM_ETH_CLIENT_CONFIG_VLAN_REMOVAL_ENABLE; + DP(NETIF_MSG_IFUP, "vlan removal enabled\n"); + } +#endif + + if (bp->flags & TPA_ENABLE_FLAG) { + tstorm_client.max_sges_for_packet = + BCM_PAGE_ALIGN(tstorm_client.mtu) >> BCM_PAGE_SHIFT; + tstorm_client.max_sges_for_packet = + ((tstorm_client.max_sges_for_packet + + PAGES_PER_SGE - 1) & (~(PAGES_PER_SGE - 1))) >> + PAGES_PER_SGE_SHIFT; + + tstorm_client.config_flags |= + TSTORM_ETH_CLIENT_CONFIG_ENABLE_SGE_RING; + } + + for_each_queue(bp, i) { + REG_WR(bp, BAR_TSTRORM_INTMEM + + TSTORM_CLIENT_CONFIG_OFFSET(port, bp->fp[i].cl_id), + ((u32 *)&tstorm_client)[0]); + REG_WR(bp, BAR_TSTRORM_INTMEM + + TSTORM_CLIENT_CONFIG_OFFSET(port, bp->fp[i].cl_id) + 4, + ((u32 *)&tstorm_client)[1]); + } + + DP(BNX2X_MSG_OFF, "tstorm_client: 0x%08x 0x%08x\n", + ((u32 *)&tstorm_client)[0], ((u32 *)&tstorm_client)[1]); +} + +static void bnx2x_set_storm_rx_mode(struct bnx2x *bp) +{ + struct tstorm_eth_mac_filter_config tstorm_mac_filter = {0}; + int mode = bp->rx_mode; + int mask = (1 << BP_L_ID(bp)); + int func = BP_FUNC(bp); + int i; + + DP(NETIF_MSG_RX_STATUS, "rx mode is %d\n", mode); + + switch (mode) { + case BNX2X_RX_MODE_NONE: /* no Rx */ + tstorm_mac_filter.ucast_drop_all = mask; + tstorm_mac_filter.mcast_drop_all = mask; + tstorm_mac_filter.bcast_drop_all = mask; + break; + case BNX2X_RX_MODE_NORMAL: + tstorm_mac_filter.bcast_accept_all = mask; + break; + case BNX2X_RX_MODE_ALLMULTI: + tstorm_mac_filter.mcast_accept_all = mask; + tstorm_mac_filter.bcast_accept_all = mask; + break; + case BNX2X_RX_MODE_PROMISC: + tstorm_mac_filter.ucast_accept_all = mask; + tstorm_mac_filter.mcast_accept_all = mask; + tstorm_mac_filter.bcast_accept_all = mask; + break; + default: + BNX2X_ERR("BAD rx mode (%d)\n", mode); + break; + } + + for (i = 0; i < sizeof(struct tstorm_eth_mac_filter_config)/4; i++) { + REG_WR(bp, BAR_TSTRORM_INTMEM + + TSTORM_MAC_FILTER_CONFIG_OFFSET(func) + i * 4, + ((u32 *)&tstorm_mac_filter)[i]); + +/* DP(NETIF_MSG_IFUP, "tstorm_mac_filter[%d]: 0x%08x\n", i, + ((u32 *)&tstorm_mac_filter)[i]); */ + } + + if (mode != BNX2X_RX_MODE_NONE) + bnx2x_set_client_config(bp); +} + +static void bnx2x_init_internal(struct bnx2x *bp) +{ + struct tstorm_eth_function_common_config tstorm_config = {0}; + struct stats_indication_flags stats_flags = {0}; + int port = BP_PORT(bp); + int func = BP_FUNC(bp); + int i; + + if (is_multi(bp)) { + tstorm_config.config_flags = MULTI_FLAGS; + tstorm_config.rss_result_mask = MULTI_MASK; + } + + tstorm_config.leading_client_id = BP_L_ID(bp); + + REG_WR(bp, BAR_TSTRORM_INTMEM + + TSTORM_FUNCTION_COMMON_CONFIG_OFFSET(func), + (*(u32 *)&tstorm_config)); + +/* DP(NETIF_MSG_IFUP, "tstorm_config: 0x%08x\n", + (*(u32 *)&tstorm_config)); */ + + bp->rx_mode = BNX2X_RX_MODE_NONE; /* no rx until link is up */ + bnx2x_set_storm_rx_mode(bp); + + stats_flags.collect_eth = 1; + + REG_WR(bp, BAR_XSTRORM_INTMEM + XSTORM_STATS_FLAGS_OFFSET(port), + ((u32 *)&stats_flags)[0]); + REG_WR(bp, BAR_XSTRORM_INTMEM + XSTORM_STATS_FLAGS_OFFSET(port) + 4, + ((u32 *)&stats_flags)[1]); + + REG_WR(bp, BAR_TSTRORM_INTMEM + TSTORM_STATS_FLAGS_OFFSET(port), + ((u32 *)&stats_flags)[0]); + REG_WR(bp, BAR_TSTRORM_INTMEM + TSTORM_STATS_FLAGS_OFFSET(port) + 4, + ((u32 *)&stats_flags)[1]); + + REG_WR(bp, BAR_CSTRORM_INTMEM + CSTORM_STATS_FLAGS_OFFSET(port), + ((u32 *)&stats_flags)[0]); + REG_WR(bp, BAR_CSTRORM_INTMEM + CSTORM_STATS_FLAGS_OFFSET(port) + 4, + ((u32 *)&stats_flags)[1]); + +/* DP(NETIF_MSG_IFUP, "stats_flags: 0x%08x 0x%08x\n", + ((u32 *)&stats_flags)[0], ((u32 *)&stats_flags)[1]); */ + + if (CHIP_IS_E1H(bp)) { + REG_WR8(bp, BAR_XSTRORM_INTMEM + XSTORM_FUNCTION_MODE_OFFSET, + IS_E1HMF(bp)); + REG_WR8(bp, BAR_TSTRORM_INTMEM + TSTORM_FUNCTION_MODE_OFFSET, + IS_E1HMF(bp)); + REG_WR8(bp, BAR_CSTRORM_INTMEM + CSTORM_FUNCTION_MODE_OFFSET, + IS_E1HMF(bp)); + REG_WR8(bp, BAR_USTRORM_INTMEM + USTORM_FUNCTION_MODE_OFFSET, + IS_E1HMF(bp)); + + REG_WR16(bp, BAR_XSTRORM_INTMEM + XSTORM_E1HOV_OFFSET(func), + bp->e1hov); + } + + /* Zero this manualy as its initialization is + currently missing in the initTool */ + for (i = 0; i < USTORM_AGG_DATA_SIZE >> 2; i++) + REG_WR(bp, BAR_USTRORM_INTMEM + + USTORM_AGG_DATA_OFFSET + 4*i, 0); + + for_each_queue(bp, i) { + struct bnx2x_fastpath *fp = &bp->fp[i]; + u16 max_agg_size; + + REG_WR(bp, BAR_USTRORM_INTMEM + + USTORM_CQE_PAGE_BASE_OFFSET(port, FP_CL_ID(fp)), + U64_LO(fp->rx_comp_mapping)); + REG_WR(bp, BAR_USTRORM_INTMEM + + USTORM_CQE_PAGE_BASE_OFFSET(port, FP_CL_ID(fp)) + 4, + U64_HI(fp->rx_comp_mapping)); + + max_agg_size = min((u32)(bp->rx_buf_use_size + + 8*BCM_PAGE_SIZE*PAGES_PER_SGE), + (u32)0xffff); + REG_WR16(bp, BAR_USTRORM_INTMEM + + USTORM_MAX_AGG_SIZE_OFFSET(port, FP_CL_ID(fp)), + max_agg_size); + } +} + +static void bnx2x_nic_init(struct bnx2x *bp) +{ + int i; + + for_each_queue(bp, i) { + struct bnx2x_fastpath *fp = &bp->fp[i]; + + fp->bp = bp; + fp->state = BNX2X_FP_STATE_CLOSED; + fp->index = i; + fp->cl_id = BP_L_ID(bp) + i; + fp->sb_id = fp->cl_id; + DP(NETIF_MSG_IFUP, + "bnx2x_init_sb(%p,%p) index %d cl_id %d sb %d\n", + bp, fp->status_blk, i, FP_CL_ID(fp), FP_SB_ID(fp)); + bnx2x_init_sb(bp, FP_SB_ID(fp), fp->status_blk, + fp->status_blk_mapping); + } + + bnx2x_init_def_sb(bp, bp->def_status_blk, + bp->def_status_blk_mapping, DEF_SB_ID); + bnx2x_update_coalesce(bp); + bnx2x_init_rx_rings(bp); + bnx2x_init_tx_ring(bp); + bnx2x_init_sp_ring(bp); + bnx2x_init_context(bp); + bnx2x_init_internal(bp); + bnx2x_storm_stats_init(bp); + bnx2x_init_ind_table(bp); + bnx2x_int_enable(bp); +} + +/* end of nic init */ + +/* + * gzip service functions + */ + +static int bnx2x_gunzip_init(struct bnx2x *bp) +{ + bp->gunzip_buf = pci_alloc_consistent(bp->pdev, FW_BUF_SIZE, + &bp->gunzip_mapping); + if (bp->gunzip_buf == NULL) + goto gunzip_nomem1; + + bp->strm = kmalloc(sizeof(*bp->strm), GFP_KERNEL); + if (bp->strm == NULL) + goto gunzip_nomem2; + + bp->strm->workspace = kmalloc(zlib_inflate_workspacesize(), + GFP_KERNEL); + if (bp->strm->workspace == NULL) + goto gunzip_nomem3; + + return 0; + +gunzip_nomem3: + kfree(bp->strm); + bp->strm = NULL; + +gunzip_nomem2: + pci_free_consistent(bp->pdev, FW_BUF_SIZE, bp->gunzip_buf, + bp->gunzip_mapping); + bp->gunzip_buf = NULL; + +gunzip_nomem1: + printk(KERN_ERR PFX "%s: Cannot allocate firmware buffer for" + " un-compression\n", bp->dev->name); + return -ENOMEM; +} + +static void bnx2x_gunzip_end(struct bnx2x *bp) +{ + kfree(bp->strm->workspace); + + kfree(bp->strm); + bp->strm = NULL; + + if (bp->gunzip_buf) { + pci_free_consistent(bp->pdev, FW_BUF_SIZE, bp->gunzip_buf, + bp->gunzip_mapping); + bp->gunzip_buf = NULL; + } +} + +static int bnx2x_gunzip(struct bnx2x *bp, u8 *zbuf, int len) +{ + int n, rc; + + /* check gzip header */ + if ((zbuf[0] != 0x1f) || (zbuf[1] != 0x8b) || (zbuf[2] != Z_DEFLATED)) + return -EINVAL; + + n = 10; + +#define FNAME 0x8 + + if (zbuf[3] & FNAME) + while ((zbuf[n++] != 0) && (n < len)); + + 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; + + rc = zlib_inflateInit2(bp->strm, -MAX_WBITS); + if (rc != Z_OK) + return rc; + + rc = zlib_inflate(bp->strm, Z_FINISH); + if ((rc != Z_OK) && (rc != Z_STREAM_END)) + printk(KERN_ERR PFX "%s: Firmware decompression error: %s\n", + bp->dev->name, bp->strm->msg); + + bp->gunzip_outlen = (FW_BUF_SIZE - bp->strm->avail_out); + if (bp->gunzip_outlen & 0x3) + printk(KERN_ERR PFX "%s: Firmware decompression error:" + " gunzip_outlen (%d) not aligned\n", + bp->dev->name, bp->gunzip_outlen); + bp->gunzip_outlen >>= 2; + + zlib_inflateEnd(bp->strm); + + if (rc == Z_STREAM_END) + return 0; + + return rc; +} + +/* nic load/unload */ + +/* + * General service functions + */ + +/* send a NIG loopback debug packet */ +static void bnx2x_lb_pckt(struct bnx2x *bp) +{ + u32 wb_write[3]; + + /* Ethernet source and destination addresses */ + wb_write[0] = 0x55555555; + wb_write[1] = 0x55555555; + wb_write[2] = 0x20; /* SOP */ + REG_WR_DMAE(bp, NIG_REG_DEBUG_PACKET_LB, wb_write, 3); + + /* NON-IP protocol */ + wb_write[0] = 0x09000000; + wb_write[1] = 0x55555555; + wb_write[2] = 0x10; /* EOP, eop_bvalid = 0 */ + REG_WR_DMAE(bp, NIG_REG_DEBUG_PACKET_LB, wb_write, 3); +} + +/* some of the internal memories + * are not directly readable from the driver + * to test them we send debug packets + */ +static int bnx2x_int_mem_test(struct bnx2x *bp) +{ + int factor; + int count, i; + u32 val = 0; + + if (CHIP_REV_IS_FPGA(bp)) + factor = 120; + else if (CHIP_REV_IS_EMUL(bp)) + factor = 200; + else + factor = 1; + + DP(NETIF_MSG_HW, "start part1\n"); + + /* Disable inputs of parser neighbor blocks */ + REG_WR(bp, TSDM_REG_ENABLE_IN1, 0x0); + REG_WR(bp, TCM_REG_PRS_IFEN, 0x0); + REG_WR(bp, CFC_REG_DEBUG0, 0x1); + NIG_WR(NIG_REG_PRS_REQ_IN_EN, 0x0); + + /* Write 0 to parser credits for CFC search request */ + REG_WR(bp, PRS_REG_CFC_SEARCH_INITIAL_CREDIT, 0x0); + + /* send Ethernet packet */ + bnx2x_lb_pckt(bp); + + /* TODO do i reset NIG statistic? */ + /* Wait until NIG register shows 1 packet of size 0x10 */ + count = 1000 * factor; + while (count) { + + bnx2x_read_dmae(bp, NIG_REG_STAT2_BRB_OCTET, 2); + val = *bnx2x_sp(bp, wb_data[0]); + if (val == 0x10) + break; + + msleep(10); + count--; + } + if (val != 0x10) { + BNX2X_ERR("NIG timeout val = 0x%x\n", val); + return -1; + } + + /* Wait until PRS register shows 1 packet */ + count = 1000 * factor; + while (count) { + val = REG_RD(bp, PRS_REG_NUM_OF_PACKETS); + if (val == 1) + break; + + msleep(10); + count--; + } + if (val != 0x1) { + BNX2X_ERR("PRS timeout val = 0x%x\n", val); + return -2; + } + + /* Reset and init BRB, PRS */ + REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_1_CLEAR, 0x03); + 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); + + DP(NETIF_MSG_HW, "part2\n"); + + /* Disable inputs of parser neighbor blocks */ + REG_WR(bp, TSDM_REG_ENABLE_IN1, 0x0); + REG_WR(bp, TCM_REG_PRS_IFEN, 0x0); + REG_WR(bp, CFC_REG_DEBUG0, 0x1); + NIG_WR(NIG_REG_PRS_REQ_IN_EN, 0x0); + + /* Write 0 to parser credits for CFC search request */ + REG_WR(bp, PRS_REG_CFC_SEARCH_INITIAL_CREDIT, 0x0); + + /* send 10 Ethernet packets */ + for (i = 0; i < 10; i++) + bnx2x_lb_pckt(bp); + + /* Wait until NIG register shows 10 + 1 + packets of size 11*0x10 = 0xb0 */ + count = 1000 * factor; + while (count) { + + bnx2x_read_dmae(bp, NIG_REG_STAT2_BRB_OCTET, 2); + val = *bnx2x_sp(bp, wb_data[0]); + if (val == 0xb0) + break; + + msleep(10); + count--; + } + if (val != 0xb0) { + BNX2X_ERR("NIG timeout val = 0x%x\n", val); + return -3; + } + + /* Wait until PRS register shows 2 packets */ + val = REG_RD(bp, PRS_REG_NUM_OF_PACKETS); + if (val != 2) + BNX2X_ERR("PRS timeout val = 0x%x\n", val); + + /* Write 1 to parser credits for CFC search request */ + REG_WR(bp, PRS_REG_CFC_SEARCH_INITIAL_CREDIT, 0x1); + + /* Wait until PRS register shows 3 packets */ + msleep(10 * factor); + /* Wait until NIG register shows 1 packet of size 0x10 */ + val = REG_RD(bp, PRS_REG_NUM_OF_PACKETS); + if (val != 3) + BNX2X_ERR("PRS timeout val = 0x%x\n", val); + + /* clear NIG EOP FIFO */ + for (i = 0; i < 11; i++) + REG_RD(bp, NIG_REG_INGRESS_EOP_LB_FIFO); + val = REG_RD(bp, NIG_REG_INGRESS_EOP_LB_EMPTY); + if (val != 1) { + BNX2X_ERR("clear of NIG failed\n"); + return -4; + } + + /* Reset and init BRB, PRS, NIG */ + REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_1_CLEAR, 0x03); + 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); +#ifndef BCM_ISCSI + /* set NIC mode */ + REG_WR(bp, PRS_REG_NIC_MODE, 1); +#endif + + /* Enable inputs of parser neighbor blocks */ + REG_WR(bp, TSDM_REG_ENABLE_IN1, 0x7fffffff); + REG_WR(bp, TCM_REG_PRS_IFEN, 0x1); + REG_WR(bp, CFC_REG_DEBUG0, 0x0); + NIG_WR(NIG_REG_PRS_REQ_IN_EN, 0x1); + + DP(NETIF_MSG_HW, "done\n"); + + return 0; /* OK */ +} + +static void enable_blocks_attention(struct bnx2x *bp) +{ + REG_WR(bp, PXP_REG_PXP_INT_MASK_0, 0); + REG_WR(bp, PXP_REG_PXP_INT_MASK_1, 0); + REG_WR(bp, DORQ_REG_DORQ_INT_MASK, 0); + REG_WR(bp, CFC_REG_CFC_INT_MASK, 0); + REG_WR(bp, QM_REG_QM_INT_MASK, 0); + REG_WR(bp, TM_REG_TM_INT_MASK, 0); + REG_WR(bp, XSDM_REG_XSDM_INT_MASK_0, 0); + REG_WR(bp, XSDM_REG_XSDM_INT_MASK_1, 0); + REG_WR(bp, XCM_REG_XCM_INT_MASK, 0); +/* REG_WR(bp, XSEM_REG_XSEM_INT_MASK_0, 0); */ +/* REG_WR(bp, XSEM_REG_XSEM_INT_MASK_1, 0); */ + REG_WR(bp, USDM_REG_USDM_INT_MASK_0, 0); + REG_WR(bp, USDM_REG_USDM_INT_MASK_1, 0); + REG_WR(bp, UCM_REG_UCM_INT_MASK, 0); +/* REG_WR(bp, USEM_REG_USEM_INT_MASK_0, 0); */ +/* REG_WR(bp, USEM_REG_USEM_INT_MASK_1, 0); */ + REG_WR(bp, GRCBASE_UPB + PB_REG_PB_INT_MASK, 0); + REG_WR(bp, CSDM_REG_CSDM_INT_MASK_0, 0); + REG_WR(bp, CSDM_REG_CSDM_INT_MASK_1, 0); + REG_WR(bp, CCM_REG_CCM_INT_MASK, 0); +/* REG_WR(bp, CSEM_REG_CSEM_INT_MASK_0, 0); */ +/* REG_WR(bp, CSEM_REG_CSEM_INT_MASK_1, 0); */ + if (CHIP_REV_IS_FPGA(bp)) + REG_WR(bp, PXP2_REG_PXP2_INT_MASK_0, 0x580000); + else + REG_WR(bp, PXP2_REG_PXP2_INT_MASK_0, 0x480000); + REG_WR(bp, TSDM_REG_TSDM_INT_MASK_0, 0); + REG_WR(bp, TSDM_REG_TSDM_INT_MASK_1, 0); + REG_WR(bp, TCM_REG_TCM_INT_MASK, 0); +/* REG_WR(bp, TSEM_REG_TSEM_INT_MASK_0, 0); */ +/* REG_WR(bp, TSEM_REG_TSEM_INT_MASK_1, 0); */ + REG_WR(bp, CDU_REG_CDU_INT_MASK, 0); + REG_WR(bp, DMAE_REG_DMAE_INT_MASK, 0); +/* REG_WR(bp, MISC_REG_MISC_INT_MASK, 0); */ + REG_WR(bp, PBF_REG_PBF_INT_MASK, 0X18); /* bit 3,4 masked */ +} + + +static int bnx2x_init_common(struct bnx2x *bp) +{ + u32 val, i; + + DP(BNX2X_MSG_MCP, "starting common init func %d\n", BP_FUNC(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); + if (CHIP_IS_E1H(bp)) + REG_WR(bp, MISC_REG_E1HMF_MODE, IS_E1HMF(bp)); + + REG_WR(bp, MISC_REG_LCPLL_CTRL_REG_2, 0x100); + msleep(30); + REG_WR(bp, MISC_REG_LCPLL_CTRL_REG_2, 0x0); + + bnx2x_init_block(bp, PXP_COMMON_START, PXP_COMMON_END); + 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_pxp(bp); + +#ifdef __BIG_ENDIAN + REG_WR(bp, PXP2_REG_RQ_QM_ENDIAN_M, 1); + REG_WR(bp, PXP2_REG_RQ_TM_ENDIAN_M, 1); + REG_WR(bp, PXP2_REG_RQ_SRC_ENDIAN_M, 1); + REG_WR(bp, PXP2_REG_RQ_CDU_ENDIAN_M, 1); + REG_WR(bp, PXP2_REG_RQ_DBG_ENDIAN_M, 1); + REG_WR(bp, PXP2_REG_RQ_HC_ENDIAN_M, 1); + +/* REG_WR(bp, PXP2_REG_RD_PBF_SWAP_MODE, 1); */ + REG_WR(bp, PXP2_REG_RD_QM_SWAP_MODE, 1); + REG_WR(bp, PXP2_REG_RD_TM_SWAP_MODE, 1); + REG_WR(bp, PXP2_REG_RD_SRC_SWAP_MODE, 1); + REG_WR(bp, PXP2_REG_RD_CDURD_SWAP_MODE, 1); +#endif + +#ifndef BCM_ISCSI + /* set NIC mode */ + REG_WR(bp, PRS_REG_NIC_MODE, 1); +#endif + + REG_WR(bp, PXP2_REG_RQ_CDU_P_SIZE, 2); +#ifdef BCM_ISCSI + REG_WR(bp, PXP2_REG_RQ_TM_P_SIZE, 5); + REG_WR(bp, PXP2_REG_RQ_QM_P_SIZE, 5); + REG_WR(bp, PXP2_REG_RQ_SRC_P_SIZE, 5); +#endif + + if (CHIP_REV_IS_FPGA(bp) && CHIP_IS_E1H(bp)) + REG_WR(bp, PXP2_REG_PGL_TAGS_LIMIT, 0x1); + + /* let the HW do it's magic ... */ + msleep(100); + /* finish PXP init */ + val = REG_RD(bp, PXP2_REG_RQ_CFG_DONE); + if (val != 1) { + BNX2X_ERR("PXP2 CFG failed\n"); + return -EBUSY; + } + val = REG_RD(bp, PXP2_REG_RD_INIT_DONE); + if (val != 1) { + BNX2X_ERR("PXP2 RD_INIT failed\n"); + return -EBUSY; + } + + 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); + + /* 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_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); + /* 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); +#endif + + bnx2x_init_block(bp, DQ_COMMON_START, DQ_COMMON_END); + 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); + if (CHIP_REV_IS_SLOW(bp)) { + /* fix for emulation and FPGA for no pause */ + REG_WR(bp, BRB1_REG_PAUSE_HIGH_THRESHOLD_0, 513); + REG_WR(bp, BRB1_REG_PAUSE_HIGH_THRESHOLD_1, 513); + REG_WR(bp, BRB1_REG_PAUSE_LOW_THRESHOLD_0, 0); + REG_WR(bp, BRB1_REG_PAUSE_LOW_THRESHOLD_1, 0); + } + + bnx2x_init_block(bp, PRS_COMMON_START, PRS_COMMON_END); + 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); + + if (CHIP_IS_E1H(bp)) { + bnx2x_init_fill(bp, TSTORM_INTMEM_ADDR, 0, + STORM_INTMEM_SIZE_E1H/2); + bnx2x_init_fill(bp, + TSTORM_INTMEM_ADDR + STORM_INTMEM_SIZE_E1H/2, + 0, STORM_INTMEM_SIZE_E1H/2); + bnx2x_init_fill(bp, CSTORM_INTMEM_ADDR, 0, + STORM_INTMEM_SIZE_E1H/2); + bnx2x_init_fill(bp, + CSTORM_INTMEM_ADDR + STORM_INTMEM_SIZE_E1H/2, + 0, STORM_INTMEM_SIZE_E1H/2); + bnx2x_init_fill(bp, XSTORM_INTMEM_ADDR, 0, + STORM_INTMEM_SIZE_E1H/2); + bnx2x_init_fill(bp, + XSTORM_INTMEM_ADDR + STORM_INTMEM_SIZE_E1H/2, + 0, STORM_INTMEM_SIZE_E1H/2); + bnx2x_init_fill(bp, USTORM_INTMEM_ADDR, 0, + STORM_INTMEM_SIZE_E1H/2); + bnx2x_init_fill(bp, + USTORM_INTMEM_ADDR + STORM_INTMEM_SIZE_E1H/2, + 0, STORM_INTMEM_SIZE_E1H/2); + } else { /* E1 */ + bnx2x_init_fill(bp, TSTORM_INTMEM_ADDR, 0, + STORM_INTMEM_SIZE_E1); + bnx2x_init_fill(bp, CSTORM_INTMEM_ADDR, 0, + STORM_INTMEM_SIZE_E1); + bnx2x_init_fill(bp, XSTORM_INTMEM_ADDR, 0, + STORM_INTMEM_SIZE_E1); + bnx2x_init_fill(bp, USTORM_INTMEM_ADDR, 0, + STORM_INTMEM_SIZE_E1); + } + + 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); + + /* sync semi rtc */ + REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_1_CLEAR, + 0x80000000); + 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); + + 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 */ + } + if (CHIP_IS_E1H(bp)) + bnx2x_init_block(bp, SRCH_COMMON_START, SRCH_COMMON_END); + REG_WR(bp, SRC_REG_SOFT_RST, 0); + + if (sizeof(union cdu_context) != 1024) + /* we currently assume that a context is 1024 bytes */ + 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); + val = (4 << 24) + (0 << 12) + 1024; + REG_WR(bp, CDU_REG_CDU_GLOBAL_PARAMS, val); + if (CHIP_IS_E1(bp)) { + /* !!! fix pxp client crdit until excel update */ + REG_WR(bp, CDU_REG_CDU_DEBUG, 0x264); + REG_WR(bp, CDU_REG_CDU_DEBUG, 0); + } + + bnx2x_init_block(bp, CFC_COMMON_START, CFC_COMMON_END); + REG_WR(bp, CFC_REG_INIT_REG, 0x7FF); + + bnx2x_init_block(bp, HC_COMMON_START, HC_COMMON_END); + bnx2x_init_block(bp, MISC_AEU_COMMON_START, MISC_AEU_COMMON_END); + + /* PXPCS COMMON comes here */ + /* Reset PCIE errors for debug */ + REG_WR(bp, 0x2814, 0xffffffff); + REG_WR(bp, 0x3820, 0xffffffff); + + /* EMAC0 COMMON comes here */ + /* EMAC1 COMMON comes here */ + /* DBU COMMON comes here */ + /* DBG COMMON comes here */ + + bnx2x_init_block(bp, NIG_COMMON_START, NIG_COMMON_END); + 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)); + } + + if (CHIP_REV_IS_SLOW(bp)) + msleep(200); + + /* finish CFC init */ + val = reg_poll(bp, CFC_REG_LL_INIT_DONE, 1, 100, 10); + if (val != 1) { + BNX2X_ERR("CFC LL_INIT failed\n"); + return -EBUSY; + } + val = reg_poll(bp, CFC_REG_AC_INIT_DONE, 1, 100, 10); + if (val != 1) { + BNX2X_ERR("CFC AC_INIT failed\n"); + return -EBUSY; + } + val = reg_poll(bp, CFC_REG_CAM_INIT_DONE, 1, 100, 10); + if (val != 1) { + BNX2X_ERR("CFC CAM_INIT failed\n"); + return -EBUSY; + } + REG_WR(bp, CFC_REG_DEBUG0, 0); + + /* read NIG statistic + to see if this is our first up since powerup */ + bnx2x_read_dmae(bp, NIG_REG_STAT2_BRB_OCTET, 2); + val = *bnx2x_sp(bp, wb_data[0]); + + /* do internal memory self test */ + if ((CHIP_IS_E1(bp)) && (val == 0) && bnx2x_int_mem_test(bp)) { + BNX2X_ERR("internal mem self test failed\n"); + return -EBUSY; + } + + switch (bp->common.board & SHARED_HW_CFG_BOARD_TYPE_MASK) { + case SHARED_HW_CFG_BOARD_TYPE_BCM957710A1022G: + /* Fan failure is indicated by SPIO 5 */ + bnx2x_set_spio(bp, MISC_REGISTERS_SPIO_5, + MISC_REGISTERS_SPIO_INPUT_HI_Z); + + /* set to active low mode */ + val = REG_RD(bp, MISC_REG_SPIO_INT); + val |= ((1 << MISC_REGISTERS_SPIO_5) << + MISC_REGISTERS_SPIO_INT_OLD_SET_POS); + REG_WR(bp, MISC_REG_SPIO_INT, val); + + /* enable interrupt to signal the IGU */ + val = REG_RD(bp, MISC_REG_SPIO_EVENT_EN); + val |= (1 << MISC_REGISTERS_SPIO_5); + REG_WR(bp, MISC_REG_SPIO_EVENT_EN, val); + break; + + default: + break; + } + + /* clear PXP2 attentions */ + REG_RD(bp, PXP2_REG_PXP2_INT_STS_CLR_0); + + enable_blocks_attention(bp); + + if (bp->flags & TPA_ENABLE_FLAG) { + struct tstorm_eth_tpa_exist tmp = {0}; + + tmp.tpa_exist = 1; + + REG_WR(bp, BAR_TSTRORM_INTMEM + TSTORM_TPA_EXIST_OFFSET, + ((u32 *)&tmp)[0]); + REG_WR(bp, BAR_TSTRORM_INTMEM + TSTORM_TPA_EXIST_OFFSET + 4, + ((u32 *)&tmp)[1]); + } + + return 0; +} + +static int bnx2x_init_port(struct bnx2x *bp) +{ + int port = BP_PORT(bp); + u32 val; + + DP(BNX2X_MSG_MCP, "starting port init port %x\n", port); + + REG_WR(bp, NIG_REG_MASK_INTERRUPT_PORT0 + port*4, 0); + + /* Port PXP comes here */ + /* Port PXP2 comes here */ +#ifdef BCM_ISCSI + /* Port0 1 + * Port1 385 */ + i++; + wb_write[0] = ONCHIP_ADDR1(bp->timers_mapping); + wb_write[1] = ONCHIP_ADDR2(bp->timers_mapping); + REG_WR_DMAE(bp, PXP2_REG_RQ_ONCHIP_AT + i*8, wb_write, 2); + REG_WR(bp, PXP2_REG_PSWRQ_TM0_L2P + func*4, PXP_ONE_ILT(i)); + + /* Port0 2 + * Port1 386 */ + i++; + wb_write[0] = ONCHIP_ADDR1(bp->qm_mapping); + wb_write[1] = ONCHIP_ADDR2(bp->qm_mapping); + REG_WR_DMAE(bp, PXP2_REG_RQ_ONCHIP_AT + i*8, wb_write, 2); + REG_WR(bp, PXP2_REG_PSWRQ_QM0_L2P + func*4, PXP_ONE_ILT(i)); + + /* Port0 3 + * Port1 387 */ + i++; + wb_write[0] = ONCHIP_ADDR1(bp->t1_mapping); + wb_write[1] = ONCHIP_ADDR2(bp->t1_mapping); + REG_WR_DMAE(bp, PXP2_REG_RQ_ONCHIP_AT + i*8, wb_write, 2); + REG_WR(bp, PXP2_REG_PSWRQ_SRC0_L2P + func*4, PXP_ONE_ILT(i)); +#endif + /* Port CMs come here */ + + /* 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); +#endif + /* Port DQ comes here */ + /* Port BRB1 comes here */ + /* Port PRS comes here */ + /* Port TSDM comes here */ + /* Port CSDM comes here */ + /* Port USDM comes here */ + /* Port XSDM comes here */ + 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); + /* Port UPB comes here */ + /* Port XPB comes here */ + + bnx2x_init_block(bp, port ? PBF_PORT1_START : PBF_PORT0_START, + port ? PBF_PORT1_END : PBF_PORT0_END); + + /* configure PBF to work without PAUSE mtu 9000 */ + REG_WR(bp, PBF_REG_P0_PAUSE_ENABLE + port*4, 0); + + /* update threshold */ + REG_WR(bp, PBF_REG_P0_ARB_THRSH + port*4, (9040/16)); + /* update init credit */ + REG_WR(bp, PBF_REG_P0_INIT_CRD + port*4, (9040/16) + 553 - 22); + + /* probe changes */ + REG_WR(bp, PBF_REG_INIT_P0 + port*4, 1); + msleep(5); + REG_WR(bp, PBF_REG_INIT_P0 + port*4, 0); + +#ifdef BCM_ISCSI + /* tell the searcher where the T2 table is */ + REG_WR(bp, SRC_REG_COUNTFREE0 + func*4, 16*1024/64); + + wb_write[0] = U64_LO(bp->t2_mapping); + wb_write[1] = U64_HI(bp->t2_mapping); + REG_WR_DMAE(bp, SRC_REG_FIRSTFREE0 + func*4, wb_write, 2); + wb_write[0] = U64_LO((u64)bp->t2_mapping + 16*1024 - 64); + wb_write[1] = U64_HI((u64)bp->t2_mapping + 16*1024 - 64); + REG_WR_DMAE(bp, SRC_REG_LASTFREE0 + func*4, wb_write, 2); + + REG_WR(bp, SRC_REG_NUMBER_HASH_BITS0 + func*4, 10); + /* Port SRCH comes here */ +#endif + /* Port CDU comes here */ + /* Port CFC comes here */ + + 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, port ? MISC_AEU_PORT1_START : + MISC_AEU_PORT0_START, + port ? MISC_AEU_PORT1_END : MISC_AEU_PORT0_END); + /* 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 + * bits 4-7 are used for "per vn group attention" */ + REG_WR(bp, MISC_REG_AEU_MASK_ATTN_FUNC_0 + port*4, + (IS_E1HMF(bp) ? 0xF7 : 0x7)); + + /* Port PXPCS comes here */ + /* Port EMAC0 comes here */ + /* Port EMAC1 comes here */ + /* Port DBU comes here */ + /* Port DBG comes here */ + bnx2x_init_block(bp, port ? NIG_PORT1_START : NIG_PORT0_START, + port ? NIG_PORT1_END : NIG_PORT0_END); + + REG_WR(bp, NIG_REG_XGXS_SERDES0_MODE_SEL + port*4, 1); + + if (CHIP_IS_E1H(bp)) { + u32 wsum; + struct cmng_struct_per_port m_cmng_port; + int vn; + + /* 0x2 disable e1hov, 0x1 enable */ + REG_WR(bp, NIG_REG_LLH0_BRB1_DRV_MASK_MF + port*4, + (IS_E1HMF(bp) ? 0x1 : 0x2)); + + /* Init RATE SHAPING and FAIRNESS contexts. + Initialize as if there is 10G link. */ + wsum = bnx2x_calc_vn_wsum(bp); + bnx2x_init_port_minmax(bp, (int)wsum, 10000, &m_cmng_port); + if (IS_E1HMF(bp)) + for (vn = VN_0; vn < E1HVN_MAX; vn++) + bnx2x_init_vn_minmax(bp, 2*vn + port, + wsum, 10000, &m_cmng_port); + } + + /* Port MCP comes here */ + /* Port DMAE comes here */ + + switch (bp->common.board & SHARED_HW_CFG_BOARD_TYPE_MASK) { + case SHARED_HW_CFG_BOARD_TYPE_BCM957710A1022G: + /* add SPIO 5 to group 0 */ + val = REG_RD(bp, MISC_REG_AEU_ENABLE1_FUNC_0_OUT_0); + val |= AEU_INPUTS_ATTN_BITS_SPIO5; + REG_WR(bp, MISC_REG_AEU_ENABLE1_FUNC_0_OUT_0, val); + break; + + default: + break; + } + + bnx2x__link_reset(bp); + + return 0; +} + +#define ILT_PER_FUNC (768/2) +#define FUNC_ILT_BASE(func) (func * ILT_PER_FUNC) +/* the phys address is shifted right 12 bits and has an added + 1=valid bit added to the 53rd bit + then since this is a wide register(TM) + we split it into two 32 bit writes + */ +#define ONCHIP_ADDR1(x) ((u32)(((u64)x >> 12) & 0xFFFFFFFF)) +#define ONCHIP_ADDR2(x) ((u32)((1 << 20) | ((u64)x >> 44))) +#define PXP_ONE_ILT(x) (((x) << 10) | x) +#define PXP_ILT_RANGE(f, l) (((l) << 10) | f) + +#define CNIC_ILT_LINES 0 + +static void bnx2x_ilt_wr(struct bnx2x *bp, u32 index, dma_addr_t addr) +{ + int reg; + + if (CHIP_IS_E1H(bp)) + reg = PXP2_REG_RQ_ONCHIP_AT_B0 + index*8; + else /* E1 */ + reg = PXP2_REG_RQ_ONCHIP_AT + index*8; + + bnx2x_wb_wr(bp, reg, ONCHIP_ADDR1(addr), ONCHIP_ADDR2(addr)); +} + +static int bnx2x_init_func(struct bnx2x *bp) +{ + int port = BP_PORT(bp); + int func = BP_FUNC(bp); + int i; + + DP(BNX2X_MSG_MCP, "starting func init func %x\n", func); + + i = FUNC_ILT_BASE(func); + + bnx2x_ilt_wr(bp, i, bnx2x_sp_mapping(bp, context)); + if (CHIP_IS_E1H(bp)) { + REG_WR(bp, PXP2_REG_RQ_CDU_FIRST_ILT, i); + REG_WR(bp, PXP2_REG_RQ_CDU_LAST_ILT, i + CNIC_ILT_LINES); + } else /* E1 */ + REG_WR(bp, PXP2_REG_PSWRQ_CDU0_L2P + func*4, + PXP_ILT_RANGE(i, i + CNIC_ILT_LINES)); + + + if (CHIP_IS_E1H(bp)) { + for (i = 0; i < 9; i++) + bnx2x_init_block(bp, + cm_start[func][i], cm_end[func][i]); + + REG_WR(bp, NIG_REG_LLH0_FUNC_EN + port*8, 1); + REG_WR(bp, NIG_REG_LLH0_FUNC_VLAN_ID + port*8, bp->e1hov); + } + + /* HC init per function */ + if (CHIP_IS_E1H(bp)) { + REG_WR(bp, MISC_REG_AEU_GENERAL_ATTN_12 + func*4, 0); + + 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]); + + if (CHIP_IS_E1H(bp)) + REG_WR(bp, HC_REG_FUNC_NUM_P0 + port*4, func); + + /* Reset PCIE errors for debug */ + REG_WR(bp, 0x2114, 0xffffffff); + REG_WR(bp, 0x2120, 0xffffffff); + + return 0; +} + +static int bnx2x_init_hw(struct bnx2x *bp, u32 load_code) +{ + int i, rc = 0; + + DP(BNX2X_MSG_MCP, "function %d load_code %x\n", + BP_FUNC(bp), load_code); + + bp->dmae_ready = 0; + mutex_init(&bp->dmae_mutex); + bnx2x_gunzip_init(bp); + + switch (load_code) { + case FW_MSG_CODE_DRV_LOAD_COMMON: + rc = bnx2x_init_common(bp); + if (rc) + goto init_hw_err; + /* no break */ + + case FW_MSG_CODE_DRV_LOAD_PORT: + bp->dmae_ready = 1; + rc = bnx2x_init_port(bp); + if (rc) + goto init_hw_err; + /* no break */ + + case FW_MSG_CODE_DRV_LOAD_FUNCTION: + bp->dmae_ready = 1; + rc = bnx2x_init_func(bp); + if (rc) + goto init_hw_err; + break; + + default: + BNX2X_ERR("Unknown load_code (0x%x) from MCP\n", load_code); + break; + } + + if (!BP_NOMCP(bp)) { + int func = BP_FUNC(bp); + + bp->fw_drv_pulse_wr_seq = + (SHMEM_RD(bp, func_mb[func].drv_pulse_mb) & + DRV_PULSE_SEQ_MASK); + bp->func_stx = SHMEM_RD(bp, func_mb[func].fw_mb_param); + DP(BNX2X_MSG_MCP, "drv_pulse 0x%x func_stx 0x%x\n", + bp->fw_drv_pulse_wr_seq, bp->func_stx); + } else + bp->func_stx = 0; + + /* this needs to be done before gunzip end */ + bnx2x_zero_def_sb(bp); + for_each_queue(bp, i) + bnx2x_zero_sb(bp, BP_L_ID(bp) + i); + +init_hw_err: + bnx2x_gunzip_end(bp); + + return rc; +} + +/* send the MCP a request, block until there is a reply */ +static u32 bnx2x_fw_command(struct bnx2x *bp, u32 command) +{ + int func = BP_FUNC(bp); + u32 seq = ++bp->fw_seq; + u32 rc = 0; + + SHMEM_WR(bp, func_mb[func].drv_mb_header, (command | seq)); + DP(BNX2X_MSG_MCP, "wrote command (%x) to FW MB\n", (command | seq)); + + /* let the FW do it's magic ... */ + msleep(100); /* TBD */ + + if (CHIP_REV_IS_SLOW(bp)) + msleep(900); + + rc = SHMEM_RD(bp, func_mb[func].fw_mb_header); + DP(BNX2X_MSG_MCP, "read (%x) seq is (%x) from FW MB\n", rc, seq); + + /* is this a reply to our command? */ + if (seq == (rc & FW_MSG_SEQ_NUMBER_MASK)) { + rc &= FW_MSG_CODE_MASK; + + } else { + /* FW BUG! */ + BNX2X_ERR("FW failed to respond!\n"); + bnx2x_fw_dump(bp); + rc = 0; + } + + return rc; +} + +static void bnx2x_free_mem(struct bnx2x *bp) +{ + +#define BNX2X_PCI_FREE(x, y, size) \ + do { \ + if (x) { \ + pci_free_consistent(bp->pdev, size, x, y); \ + x = NULL; \ + y = 0; \ + } \ + } while (0) + +#define BNX2X_FREE(x) \ + do { \ + if (x) { \ + vfree(x); \ + x = NULL; \ + } \ + } while (0) + + int i; + + /* fastpath */ + for_each_queue(bp, i) { + + /* Status blocks */ + BNX2X_PCI_FREE(bnx2x_fp(bp, i, status_blk), + bnx2x_fp(bp, i, status_blk_mapping), + sizeof(struct host_status_block) + + sizeof(struct eth_tx_db_data)); + + /* fast path rings: tx_buf tx_desc rx_buf rx_desc rx_comp */ + BNX2X_FREE(bnx2x_fp(bp, i, tx_buf_ring)); + BNX2X_PCI_FREE(bnx2x_fp(bp, i, tx_desc_ring), + bnx2x_fp(bp, i, tx_desc_mapping), + sizeof(struct eth_tx_bd) * NUM_TX_BD); + + BNX2X_FREE(bnx2x_fp(bp, i, rx_buf_ring)); + BNX2X_PCI_FREE(bnx2x_fp(bp, i, rx_desc_ring), + bnx2x_fp(bp, i, rx_desc_mapping), + sizeof(struct eth_rx_bd) * NUM_RX_BD); + + BNX2X_PCI_FREE(bnx2x_fp(bp, i, rx_comp_ring), + bnx2x_fp(bp, i, rx_comp_mapping), + sizeof(struct eth_fast_path_rx_cqe) * + NUM_RCQ_BD); + + /* SGE ring */ + BNX2X_PCI_FREE(bnx2x_fp(bp, i, rx_sge_ring), + bnx2x_fp(bp, i, rx_sge_mapping), + BCM_PAGE_SIZE * NUM_RX_SGE_PAGES); + } + /* end of fastpath */ + + BNX2X_PCI_FREE(bp->def_status_blk, bp->def_status_blk_mapping, + sizeof(struct host_def_status_block)); + + BNX2X_PCI_FREE(bp->slowpath, bp->slowpath_mapping, + sizeof(struct bnx2x_slowpath)); + +#ifdef BCM_ISCSI + BNX2X_PCI_FREE(bp->t1, bp->t1_mapping, 64*1024); + BNX2X_PCI_FREE(bp->t2, bp->t2_mapping, 16*1024); + BNX2X_PCI_FREE(bp->timers, bp->timers_mapping, 8*1024); + BNX2X_PCI_FREE(bp->qm, bp->qm_mapping, 128*1024); +#endif + BNX2X_PCI_FREE(bp->spq, bp->spq_mapping, BCM_PAGE_SIZE); + +#undef BNX2X_PCI_FREE +#undef BNX2X_KFREE +} + +static int bnx2x_alloc_mem(struct bnx2x *bp) +{ + +#define BNX2X_PCI_ALLOC(x, y, size) \ + do { \ + x = pci_alloc_consistent(bp->pdev, size, y); \ + if (x == NULL) \ + goto alloc_mem_err; \ + memset(x, 0, size); \ + } while (0) + +#define BNX2X_ALLOC(x, size) \ + do { \ + x = vmalloc(size); \ + if (x == NULL) \ + goto alloc_mem_err; \ + memset(x, 0, size); \ + } while (0) + + int i; + + /* fastpath */ + for_each_queue(bp, i) { + bnx2x_fp(bp, i, bp) = bp; + + /* Status blocks */ + BNX2X_PCI_ALLOC(bnx2x_fp(bp, i, status_blk), + &bnx2x_fp(bp, i, status_blk_mapping), + sizeof(struct host_status_block) + + sizeof(struct eth_tx_db_data)); + + bnx2x_fp(bp, i, hw_tx_prods) = + (void *)(bnx2x_fp(bp, i, status_blk) + 1); + + bnx2x_fp(bp, i, tx_prods_mapping) = + bnx2x_fp(bp, i, status_blk_mapping) + + sizeof(struct host_status_block); + + /* fast path rings: tx_buf tx_desc rx_buf rx_desc rx_comp */ + BNX2X_ALLOC(bnx2x_fp(bp, i, tx_buf_ring), + sizeof(struct sw_tx_bd) * NUM_TX_BD); + BNX2X_PCI_ALLOC(bnx2x_fp(bp, i, tx_desc_ring), + &bnx2x_fp(bp, i, tx_desc_mapping), + sizeof(struct eth_tx_bd) * NUM_TX_BD); + + BNX2X_ALLOC(bnx2x_fp(bp, i, rx_buf_ring), + sizeof(struct sw_rx_bd) * NUM_RX_BD); + BNX2X_PCI_ALLOC(bnx2x_fp(bp, i, rx_desc_ring), + &bnx2x_fp(bp, i, rx_desc_mapping), + sizeof(struct eth_rx_bd) * NUM_RX_BD); + + BNX2X_PCI_ALLOC(bnx2x_fp(bp, i, rx_comp_ring), + &bnx2x_fp(bp, i, rx_comp_mapping), + sizeof(struct eth_fast_path_rx_cqe) * + NUM_RCQ_BD); + + /* SGE ring */ + BNX2X_ALLOC(bnx2x_fp(bp, i, rx_page_ring), + sizeof(struct sw_rx_page) * NUM_RX_SGE); + BNX2X_PCI_ALLOC(bnx2x_fp(bp, i, rx_sge_ring), + &bnx2x_fp(bp, i, rx_sge_mapping), + BCM_PAGE_SIZE * NUM_RX_SGE_PAGES); + } + /* end of fastpath */ + + BNX2X_PCI_ALLOC(bp->def_status_blk, &bp->def_status_blk_mapping, + sizeof(struct host_def_status_block)); + + BNX2X_PCI_ALLOC(bp->slowpath, &bp->slowpath_mapping, + sizeof(struct bnx2x_slowpath)); + +#ifdef BCM_ISCSI + BNX2X_PCI_ALLOC(bp->t1, &bp->t1_mapping, 64*1024); + + /* Initialize T1 */ + for (i = 0; i < 64*1024; i += 64) { + *(u64 *)((char *)bp->t1 + i + 56) = 0x0UL; + *(u64 *)((char *)bp->t1 + i + 3) = 0x0UL; + } + + /* allocate searcher T2 table + we allocate 1/4 of alloc num for T2 + (which is not entered into the ILT) */ + BNX2X_PCI_ALLOC(bp->t2, &bp->t2_mapping, 16*1024); + + /* Initialize T2 */ + for (i = 0; i < 16*1024; i += 64) + * (u64 *)((char *)bp->t2 + i + 56) = bp->t2_mapping + i + 64; + + /* now fixup the last line in the block to point to the next block */ + *(u64 *)((char *)bp->t2 + 1024*16-8) = bp->t2_mapping; + + /* Timer block array (MAX_CONN*8) phys uncached for now 1024 conns */ + BNX2X_PCI_ALLOC(bp->timers, &bp->timers_mapping, 8*1024); + + /* QM queues (128*MAX_CONN) */ + BNX2X_PCI_ALLOC(bp->qm, &bp->qm_mapping, 128*1024); +#endif + + /* Slow path ring */ + BNX2X_PCI_ALLOC(bp->spq, &bp->spq_mapping, BCM_PAGE_SIZE); + + return 0; + +alloc_mem_err: + bnx2x_free_mem(bp); + return -ENOMEM; + +#undef BNX2X_PCI_ALLOC +#undef BNX2X_ALLOC +} + +static void bnx2x_free_tx_skbs(struct bnx2x *bp) +{ + int i; + + for_each_queue(bp, i) { + struct bnx2x_fastpath *fp = &bp->fp[i]; + + u16 bd_cons = fp->tx_bd_cons; + u16 sw_prod = fp->tx_pkt_prod; + u16 sw_cons = fp->tx_pkt_cons; + + while (sw_cons != sw_prod) { + bd_cons = bnx2x_free_tx_pkt(bp, fp, TX_BD(sw_cons)); + sw_cons++; + } + } +} + +static void bnx2x_free_rx_skbs(struct bnx2x *bp) +{ + int i, j; + + for_each_queue(bp, j) { + struct bnx2x_fastpath *fp = &bp->fp[j]; + + for (i = 0; i < NUM_RX_BD; i++) { + struct sw_rx_bd *rx_buf = &fp->rx_buf_ring[i]; + struct sk_buff *skb = rx_buf->skb; + + if (skb == NULL) + continue; + + pci_unmap_single(bp->pdev, + pci_unmap_addr(rx_buf, mapping), + bp->rx_buf_use_size, + PCI_DMA_FROMDEVICE); + + rx_buf->skb = NULL; + dev_kfree_skb(skb); + } + if (!fp->disable_tpa) + bnx2x_free_tpa_pool(bp, fp, + ETH_MAX_AGGREGATION_QUEUES_E1H); + } +} + +static void bnx2x_free_skbs(struct bnx2x *bp) +{ + bnx2x_free_tx_skbs(bp); + bnx2x_free_rx_skbs(bp); +} + +static void bnx2x_free_msix_irqs(struct bnx2x *bp) +{ + int i, offset = 1; + + free_irq(bp->msix_table[0].vector, bp->dev); + DP(NETIF_MSG_IFDOWN, "released sp irq (%d)\n", + bp->msix_table[0].vector); + + for_each_queue(bp, i) { + DP(NETIF_MSG_IFDOWN, "about to release fp #%d->%d irq " + "state %x\n", i, bp->msix_table[i + offset].vector, + bnx2x_fp(bp, i, state)); + + if (bnx2x_fp(bp, i, state) != BNX2X_FP_STATE_CLOSED) + BNX2X_ERR("IRQ of fp #%d being freed while " + "state != closed\n", i); + + free_irq(bp->msix_table[i + offset].vector, &bp->fp[i]); + } +} + +static void bnx2x_free_irq(struct bnx2x *bp) +{ + if (bp->flags & USING_MSIX_FLAG) { + bnx2x_free_msix_irqs(bp); + pci_disable_msix(bp->pdev); + bp->flags &= ~USING_MSIX_FLAG; + + } else + free_irq(bp->pdev->irq, bp->dev); +} + +static int bnx2x_enable_msix(struct bnx2x *bp) +{ + int i, rc, offset; + + bp->msix_table[0].entry = 0; + offset = 1; + DP(NETIF_MSG_IFUP, "msix_table[0].entry = 0 (slowpath)\n"); + + for_each_queue(bp, i) { + int igu_vec = offset + i + BP_L_ID(bp); + + bp->msix_table[i + offset].entry = igu_vec; + DP(NETIF_MSG_IFUP, "msix_table[%d].entry = %d " + "(fastpath #%u)\n", i + offset, igu_vec, i); + } + + rc = pci_enable_msix(bp->pdev, &bp->msix_table[0], + bp->num_queues + offset); + if (rc) { + DP(NETIF_MSG_IFUP, "MSI-X is not attainable\n"); + return -1; + } + bp->flags |= USING_MSIX_FLAG; + + return 0; +} + +static int bnx2x_req_msix_irqs(struct bnx2x *bp) +{ + int i, rc, offset = 1; + + rc = request_irq(bp->msix_table[0].vector, bnx2x_msix_sp_int, 0, + bp->dev->name, bp->dev); + if (rc) { + BNX2X_ERR("request sp irq failed\n"); + return -EBUSY; + } + + for_each_queue(bp, i) { + rc = request_irq(bp->msix_table[i + offset].vector, + bnx2x_msix_fp_int, 0, + bp->dev->name, &bp->fp[i]); + if (rc) { + BNX2X_ERR("request fp #%d irq failed rc %d\n", + i + offset, rc); + bnx2x_free_msix_irqs(bp); + return -EBUSY; + } + + bnx2x_fp(bp, i, state) = BNX2X_FP_STATE_IRQ; + } + + return 0; +} + +static int bnx2x_req_irq(struct bnx2x *bp) +{ + int rc; + + rc = request_irq(bp->pdev->irq, bnx2x_interrupt, IRQF_SHARED, + bp->dev->name, bp->dev); + if (!rc) + bnx2x_fp(bp, 0, state) = BNX2X_FP_STATE_IRQ; + + return rc; +} + +/* + * Init service functions + */ + +static void bnx2x_set_mac_addr_e1(struct bnx2x *bp) +{ + struct mac_configuration_cmd *config = bnx2x_sp(bp, mac_config); + int port = BP_PORT(bp); + + /* CAM allocation + * unicasts 0-31:port0 32-63:port1 + * multicast 64-127:port0 128-191:port1 + */ + config->hdr.length_6b = 2; + config->hdr.offset = port ? 31 : 0; + config->hdr.client_id = BP_CL_ID(bp); + config->hdr.reserved1 = 0; + + /* primary MAC */ + config->config_table[0].cam_entry.msb_mac_addr = + swab16(*(u16 *)&bp->dev->dev_addr[0]); + config->config_table[0].cam_entry.middle_mac_addr = + swab16(*(u16 *)&bp->dev->dev_addr[2]); + config->config_table[0].cam_entry.lsb_mac_addr = + swab16(*(u16 *)&bp->dev->dev_addr[4]); + config->config_table[0].cam_entry.flags = cpu_to_le16(port); + config->config_table[0].target_table_entry.flags = 0; + config->config_table[0].target_table_entry.client_id = 0; + config->config_table[0].target_table_entry.vlan_id = 0; + + DP(NETIF_MSG_IFUP, "setting MAC (%04x:%04x:%04x)\n", + config->config_table[0].cam_entry.msb_mac_addr, + config->config_table[0].cam_entry.middle_mac_addr, + config->config_table[0].cam_entry.lsb_mac_addr); + + /* broadcast */ + config->config_table[1].cam_entry.msb_mac_addr = 0xffff; + config->config_table[1].cam_entry.middle_mac_addr = 0xffff; + config->config_table[1].cam_entry.lsb_mac_addr = 0xffff; + config->config_table[1].cam_entry.flags = cpu_to_le16(port); + config->config_table[1].target_table_entry.flags = + TSTORM_CAM_TARGET_TABLE_ENTRY_BROADCAST; + config->config_table[1].target_table_entry.client_id = 0; + config->config_table[1].target_table_entry.vlan_id = 0; + + bnx2x_sp_post(bp, RAMROD_CMD_ID_ETH_SET_MAC, 0, + U64_HI(bnx2x_sp_mapping(bp, mac_config)), + U64_LO(bnx2x_sp_mapping(bp, mac_config)), 0); +} + +static void bnx2x_set_mac_addr_e1h(struct bnx2x *bp) +{ + struct mac_configuration_cmd_e1h *config = + (struct mac_configuration_cmd_e1h *)bnx2x_sp(bp, mac_config); + + if (bp->state != BNX2X_STATE_OPEN) { + DP(NETIF_MSG_IFUP, "state is %x, returning\n", bp->state); + return; + } + + /* CAM allocation for E1H + * unicasts: by func number + * multicast: 20+FUNC*20, 20 each + */ + config->hdr.length_6b = 1; + config->hdr.offset = BP_FUNC(bp); + config->hdr.client_id = BP_CL_ID(bp); + config->hdr.reserved1 = 0; + + /* primary MAC */ + config->config_table[0].msb_mac_addr = + swab16(*(u16 *)&bp->dev->dev_addr[0]); + config->config_table[0].middle_mac_addr = + swab16(*(u16 *)&bp->dev->dev_addr[2]); + config->config_table[0].lsb_mac_addr = + swab16(*(u16 *)&bp->dev->dev_addr[4]); + config->config_table[0].client_id = BP_L_ID(bp); + config->config_table[0].vlan_id = 0; + config->config_table[0].e1hov_id = cpu_to_le16(bp->e1hov); + config->config_table[0].flags = BP_PORT(bp); + + DP(NETIF_MSG_IFUP, "setting MAC (%04x:%04x:%04x) E1HOV %d CLID %d\n", + config->config_table[0].msb_mac_addr, + config->config_table[0].middle_mac_addr, + config->config_table[0].lsb_mac_addr, bp->e1hov, BP_L_ID(bp)); + + bnx2x_sp_post(bp, RAMROD_CMD_ID_ETH_SET_MAC, 0, + U64_HI(bnx2x_sp_mapping(bp, mac_config)), + U64_LO(bnx2x_sp_mapping(bp, mac_config)), 0); +} + +static int bnx2x_wait_ramrod(struct bnx2x *bp, int state, int idx, + int *state_p, int poll) +{ + /* can take a while if any port is running */ + int cnt = 500; + + DP(NETIF_MSG_IFUP, "%s for state to become %x on IDX [%d]\n", + poll ? "polling" : "waiting", state, idx); + + might_sleep(); + while (cnt--) { + if (poll) { + bnx2x_rx_int(bp->fp, 10); + /* if index is different from 0 + * the reply for some commands will + * be on the none default queue + */ + if (idx) + bnx2x_rx_int(&bp->fp[idx], 10); + } + mb(); /* state is changed by bnx2x_sp_event() */ + + if (*state_p == state) + return 0; + + msleep(1); + } + + /* timeout! */ + BNX2X_ERR("timeout %s for state %x on IDX [%d]\n", + poll ? "polling" : "waiting", state, idx); +#ifdef BNX2X_STOP_ON_ERROR + bnx2x_panic(); +#endif + + return -EBUSY; +} + +static int bnx2x_setup_leading(struct bnx2x *bp) +{ + int rc; + + /* reset IGU state */ + bnx2x_ack_sb(bp, bp->fp[0].sb_id, CSTORM_ID, 0, IGU_INT_ENABLE, 0); + + /* SETUP ramrod */ + bnx2x_sp_post(bp, RAMROD_CMD_ID_ETH_PORT_SETUP, 0, 0, 0, 0); + + /* Wait for completion */ + rc = bnx2x_wait_ramrod(bp, BNX2X_STATE_OPEN, 0, &(bp->state), 0); + + return rc; +} + +static int bnx2x_setup_multi(struct bnx2x *bp, int index) +{ + /* reset IGU state */ + bnx2x_ack_sb(bp, bp->fp[index].sb_id, CSTORM_ID, 0, IGU_INT_ENABLE, 0); + + /* SETUP ramrod */ + bp->fp[index].state = BNX2X_FP_STATE_OPENING; + bnx2x_sp_post(bp, RAMROD_CMD_ID_ETH_CLIENT_SETUP, index, 0, index, 0); + + /* Wait for completion */ + return bnx2x_wait_ramrod(bp, BNX2X_FP_STATE_OPEN, index, + &(bp->fp[index].state), 0); +} + +static int bnx2x_poll(struct napi_struct *napi, int budget); +static void bnx2x_set_rx_mode(struct net_device *dev); + +/* must be called with rtnl_lock */ +static int bnx2x_nic_load(struct bnx2x *bp, int load_mode) +{ + u32 load_code; + int i, rc; + +#ifdef BNX2X_STOP_ON_ERROR + if (unlikely(bp->panic)) + return -EPERM; +#endif + + bp->state = BNX2X_STATE_OPENING_WAIT4_LOAD; + + /* Send LOAD_REQUEST command to MCP + Returns the type of LOAD command: + if it is the first port to be initialized + common blocks should be initialized, otherwise - not + */ + if (!BP_NOMCP(bp)) { + load_code = bnx2x_fw_command(bp, DRV_MSG_CODE_LOAD_REQ); + if (!load_code) { + BNX2X_ERR("MCP response failure, unloading\n"); + return -EBUSY; + } + if (load_code == FW_MSG_CODE_DRV_LOAD_REFUSED) + return -EBUSY; /* other port in diagnostic mode */ + + } else { + DP(NETIF_MSG_IFUP, "NO MCP load counts before us %d, %d, %d\n", + load_count[0], load_count[1], load_count[2]); + load_count[0]++; + load_count[1 + BP_PORT(bp)]++; + DP(NETIF_MSG_IFUP, "NO MCP new load counts %d, %d, %d\n", + load_count[0], load_count[1], load_count[2]); + if (load_count[0] == 1) + load_code = FW_MSG_CODE_DRV_LOAD_COMMON; + else if (load_count[1 + BP_PORT(bp)] == 1) + load_code = FW_MSG_CODE_DRV_LOAD_PORT; + else + load_code = FW_MSG_CODE_DRV_LOAD_FUNCTION; + } + + if ((load_code == FW_MSG_CODE_DRV_LOAD_COMMON) || + (load_code == FW_MSG_CODE_DRV_LOAD_PORT)) + bp->port.pmf = 1; + else + bp->port.pmf = 0; + DP(NETIF_MSG_LINK, "pmf %d\n", bp->port.pmf); + + /* if we can't use MSI-X we only need one fp, + * so try to enable MSI-X with the requested number of fp's + * and fallback to inta with one fp + */ + if (use_inta) { + bp->num_queues = 1; + + } else { + if ((use_multi > 1) && (use_multi <= BP_MAX_QUEUES(bp))) + /* user requested number */ + bp->num_queues = use_multi; + + else if (use_multi) + bp->num_queues = min_t(u32, num_online_cpus(), + BP_MAX_QUEUES(bp)); + else + bp->num_queues = 1; + + if (bnx2x_enable_msix(bp)) { + /* failed to enable MSI-X */ + bp->num_queues = 1; + if (use_multi) + BNX2X_ERR("Multi requested but failed" + " to enable MSI-X\n"); + } + } + DP(NETIF_MSG_IFUP, + "set number of queues to %d\n", bp->num_queues); + + if (bnx2x_alloc_mem(bp)) + return -ENOMEM; + + for_each_queue(bp, i) + bnx2x_fp(bp, i, disable_tpa) = + ((bp->flags & TPA_ENABLE_FLAG) == 0); + + /* Disable interrupt handling until HW is initialized */ + atomic_set(&bp->intr_sem, 1); + + if (bp->flags & USING_MSIX_FLAG) { + rc = bnx2x_req_msix_irqs(bp); + if (rc) { + pci_disable_msix(bp->pdev); + goto load_error; + } + } else { + bnx2x_ack_int(bp); + rc = bnx2x_req_irq(bp); + if (rc) { + BNX2X_ERR("IRQ request failed, aborting\n"); + goto load_error; + } + } + + for_each_queue(bp, i) + netif_napi_add(bp->dev, &bnx2x_fp(bp, i, napi), + bnx2x_poll, 128); + + /* Initialize HW */ + rc = bnx2x_init_hw(bp, load_code); + if (rc) { + BNX2X_ERR("HW init failed, aborting\n"); + goto load_error; + } + + /* Enable interrupt handling */ + atomic_set(&bp->intr_sem, 0); + + /* Setup NIC internals and enable interrupts */ + bnx2x_nic_init(bp); + + /* Send LOAD_DONE command to MCP */ + if (!BP_NOMCP(bp)) { + load_code = bnx2x_fw_command(bp, DRV_MSG_CODE_LOAD_DONE); + if (!load_code) { + BNX2X_ERR("MCP response failure, unloading\n"); + rc = -EBUSY; + goto load_int_disable; + } + } + + bnx2x_stats_init(bp); + + bp->state = BNX2X_STATE_OPENING_WAIT4_PORT; + + /* Enable Rx interrupt handling before sending the ramrod + as it's completed on Rx FP queue */ + for_each_queue(bp, i) + napi_enable(&bnx2x_fp(bp, i, napi)); + + rc = bnx2x_setup_leading(bp); + if (rc) { +#ifdef BNX2X_STOP_ON_ERROR + bp->panic = 1; +#endif + goto load_stop_netif; + } + + if (CHIP_IS_E1H(bp)) + if (bp->mf_config & FUNC_MF_CFG_FUNC_DISABLED) { + BNX2X_ERR("!!! mf_cfg function disabled\n"); + bp->state = BNX2X_STATE_DISABLED; + } + + if (bp->state == BNX2X_STATE_OPEN) + for_each_nondefault_queue(bp, i) { + rc = bnx2x_setup_multi(bp, i); + if (rc) + goto load_stop_netif; + } + + if (CHIP_IS_E1(bp)) + bnx2x_set_mac_addr_e1(bp); + else + bnx2x_set_mac_addr_e1h(bp); + + if (bp->port.pmf) + bnx2x_initial_phy_init(bp); + + /* Start fast path */ + switch (load_mode) { + case LOAD_NORMAL: + /* Tx queue should be only reenabled */ + netif_wake_queue(bp->dev); + bnx2x_set_rx_mode(bp->dev); + break; + + case LOAD_OPEN: + /* IRQ is only requested from bnx2x_open */ + netif_start_queue(bp->dev); + bnx2x_set_rx_mode(bp->dev); + if (bp->flags & USING_MSIX_FLAG) + printk(KERN_INFO PFX "%s: using MSI-X\n", + bp->dev->name); + break; + + case LOAD_DIAG: + bnx2x_set_rx_mode(bp->dev); + bp->state = BNX2X_STATE_DIAG; + break; + + default: + break; + } + + if (!bp->port.pmf) + bnx2x__link_status_update(bp); + + /* start the timer */ + mod_timer(&bp->timer, jiffies + bp->current_interval); + + + return 0; + +load_stop_netif: + for_each_queue(bp, i) + napi_disable(&bnx2x_fp(bp, i, napi)); + +load_int_disable: + bnx2x_int_disable_sync(bp); + + /* Release IRQs */ + bnx2x_free_irq(bp); + + /* Free SKBs, SGEs, TPA pool and driver internals */ + bnx2x_free_skbs(bp); + for_each_queue(bp, i) + bnx2x_free_rx_sge_range(bp, bp->fp + i, + RX_SGE_CNT*NUM_RX_SGE_PAGES); +load_error: + bnx2x_free_mem(bp); + + /* TBD we really need to reset the chip + if we want to recover from this */ + return rc; +} + +static int bnx2x_stop_multi(struct bnx2x *bp, int index) +{ + int rc; + + /* halt the connection */ + bp->fp[index].state = BNX2X_FP_STATE_HALTING; + bnx2x_sp_post(bp, RAMROD_CMD_ID_ETH_HALT, index, 0, 0, 0); + + /* Wait for completion */ + rc = bnx2x_wait_ramrod(bp, BNX2X_FP_STATE_HALTED, index, + &(bp->fp[index].state), 1); + if (rc) /* timeout */ + return rc; + + /* delete cfc entry */ + bnx2x_sp_post(bp, RAMROD_CMD_ID_ETH_CFC_DEL, index, 0, 0, 1); + + /* Wait for completion */ + rc = bnx2x_wait_ramrod(bp, BNX2X_FP_STATE_CLOSED, index, + &(bp->fp[index].state), 1); + return rc; +} + +static void bnx2x_stop_leading(struct bnx2x *bp) +{ + u16 dsb_sp_prod_idx; + /* if the other port is handling traffic, + this can take a lot of time */ + int cnt = 500; + int rc; + + might_sleep(); + + /* Send HALT ramrod */ + bp->fp[0].state = BNX2X_FP_STATE_HALTING; + bnx2x_sp_post(bp, RAMROD_CMD_ID_ETH_HALT, 0, 0, BP_CL_ID(bp), 0); + + /* Wait for completion */ + rc = bnx2x_wait_ramrod(bp, BNX2X_FP_STATE_HALTED, 0, + &(bp->fp[0].state), 1); + if (rc) /* timeout */ + return; + + dsb_sp_prod_idx = *bp->dsb_sp_prod; + + /* Send PORT_DELETE ramrod */ + bnx2x_sp_post(bp, RAMROD_CMD_ID_ETH_PORT_DEL, 0, 0, 0, 1); + + /* Wait for completion to arrive on default status block + we are going to reset the chip anyway + so there is not much to do if this times out + */ + while (dsb_sp_prod_idx == *bp->dsb_sp_prod) { + msleep(1); + if (!cnt) { + DP(NETIF_MSG_IFDOWN, "timeout waiting for port del " + "dsb_sp_prod 0x%x != dsb_sp_prod_idx 0x%x\n", + *bp->dsb_sp_prod, dsb_sp_prod_idx); +#ifdef BNX2X_STOP_ON_ERROR + bnx2x_panic(); +#endif + break; + } + cnt--; + } + bp->state = BNX2X_STATE_CLOSING_WAIT4_UNLOAD; + bp->fp[0].state = BNX2X_FP_STATE_CLOSED; +} + +static void bnx2x_reset_func(struct bnx2x *bp) +{ + int port = BP_PORT(bp); + int func = BP_FUNC(bp); + int base, i; + + /* Configure IGU */ + REG_WR(bp, HC_REG_LEADING_EDGE_0 + port*8, 0); + REG_WR(bp, HC_REG_TRAILING_EDGE_0 + port*8, 0); + + REG_WR(bp, HC_REG_CONFIG_0 + port*4, 0x1000); + + /* Clear ILT */ + base = FUNC_ILT_BASE(func); + for (i = base; i < base + ILT_PER_FUNC; i++) + bnx2x_ilt_wr(bp, i, 0); +} + +static void bnx2x_reset_port(struct bnx2x *bp) +{ + int port = BP_PORT(bp); + u32 val; + + REG_WR(bp, NIG_REG_MASK_INTERRUPT_PORT0 + port*4, 0); + + /* Do not rcv packets to BRB */ + REG_WR(bp, NIG_REG_LLH0_BRB1_DRV_MASK + port*4, 0x0); + /* Do not direct rcv packets that are not for MCP to the BRB */ + REG_WR(bp, (port ? NIG_REG_LLH1_BRB1_NOT_MCP : + NIG_REG_LLH0_BRB1_NOT_MCP), 0x0); + + /* Configure AEU */ + REG_WR(bp, MISC_REG_AEU_MASK_ATTN_FUNC_0 + port*4, 0); + + msleep(100); + /* Check for BRB port occupancy */ + val = REG_RD(bp, BRB1_REG_PORT_NUM_OCC_BLOCKS_0 + port*4); + if (val) + DP(NETIF_MSG_IFDOWN, + "BRB1 is not empty %d blooks are occupied\n", val); + + /* TODO: Close Doorbell port? */ +} + +static void bnx2x_reset_common(struct bnx2x *bp) +{ + /* reset_common */ + REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_1_CLEAR, + 0xd3ffff7f); + REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_CLEAR, 0x1403); +} + +static void bnx2x_reset_chip(struct bnx2x *bp, u32 reset_code) +{ + DP(BNX2X_MSG_MCP, "function %d reset_code %x\n", + BP_FUNC(bp), reset_code); + + switch (reset_code) { + case FW_MSG_CODE_DRV_UNLOAD_COMMON: + bnx2x_reset_port(bp); + bnx2x_reset_func(bp); + bnx2x_reset_common(bp); + break; + + case FW_MSG_CODE_DRV_UNLOAD_PORT: + bnx2x_reset_port(bp); + bnx2x_reset_func(bp); + break; + + case FW_MSG_CODE_DRV_UNLOAD_FUNCTION: + bnx2x_reset_func(bp); + break; + + default: + BNX2X_ERR("Unknown reset_code (0x%x) from MCP\n", reset_code); + break; + } +} + +/* msut be called with rtnl_lock */ +static int bnx2x_nic_unload(struct bnx2x *bp, int unload_mode) +{ + u32 reset_code = 0; + int i, cnt; + + bp->state = BNX2X_STATE_CLOSING_WAIT4_HALT; + + bp->rx_mode = BNX2X_RX_MODE_NONE; + bnx2x_set_storm_rx_mode(bp); + + if (netif_running(bp->dev)) { + netif_tx_disable(bp->dev); + bp->dev->trans_start = jiffies; /* prevent tx timeout */ + } + + del_timer_sync(&bp->timer); + SHMEM_WR(bp, func_mb[BP_FUNC(bp)].drv_pulse_mb, + (DRV_PULSE_ALWAYS_ALIVE | bp->fw_drv_pulse_wr_seq)); + bnx2x_stats_handle(bp, STATS_EVENT_STOP); + + /* Wait until all fast path tasks complete */ + for_each_queue(bp, i) { + struct bnx2x_fastpath *fp = &bp->fp[i]; + +#ifdef BNX2X_STOP_ON_ERROR +#ifdef __powerpc64__ + DP(NETIF_MSG_RX_STATUS, "fp->tpa_queue_used = 0x%lx\n", +#else + DP(NETIF_MSG_IFDOWN, "fp->tpa_queue_used = 0x%llx\n", +#endif + fp->tpa_queue_used); +#endif + cnt = 1000; + smp_rmb(); + while (bnx2x_has_work(fp)) { + msleep(1); + if (!cnt) { + BNX2X_ERR("timeout waiting for queue[%d]\n", + i); +#ifdef BNX2X_STOP_ON_ERROR + bnx2x_panic(); + return -EBUSY; +#else + break; +#endif + } + cnt--; + smp_rmb(); + } + } + + /* Wait until all slow path tasks complete */ + cnt = 1000; + while ((bp->spq_left != MAX_SPQ_PENDING) && cnt--) + msleep(1); + + for_each_queue(bp, i) + napi_disable(&bnx2x_fp(bp, i, napi)); + /* Disable interrupts after Tx and Rx are disabled on stack level */ + bnx2x_int_disable_sync(bp); + + /* Release IRQs */ + bnx2x_free_irq(bp); + + if (bp->flags & NO_WOL_FLAG) + reset_code = DRV_MSG_CODE_UNLOAD_REQ_WOL_MCP; + + else if (bp->wol) { + u32 emac_base = BP_PORT(bp) ? GRCBASE_EMAC1 : GRCBASE_EMAC0; + u8 *mac_addr = bp->dev->dev_addr; + u32 val; + + /* The mac address is written to entries 1-4 to + preserve entry 0 which is used by the PMF */ + val = (mac_addr[0] << 8) | mac_addr[1]; + EMAC_WR(EMAC_REG_EMAC_MAC_MATCH + (BP_E1HVN(bp) + 1)*8, val); + + val = (mac_addr[2] << 24) | (mac_addr[3] << 16) | + (mac_addr[4] << 8) | mac_addr[5]; + EMAC_WR(EMAC_REG_EMAC_MAC_MATCH + (BP_E1HVN(bp) + 1)*8 + 4, + val); + + reset_code = DRV_MSG_CODE_UNLOAD_REQ_WOL_EN; + + } else + reset_code = DRV_MSG_CODE_UNLOAD_REQ_WOL_DIS; + + /* Close multi and leading connections + Completions for ramrods are collected in a synchronous way */ + for_each_nondefault_queue(bp, i) + if (bnx2x_stop_multi(bp, i)) + goto unload_error; + + if (CHIP_IS_E1H(bp)) + REG_WR(bp, NIG_REG_LLH0_FUNC_EN + BP_PORT(bp)*8, 0); + + bnx2x_stop_leading(bp); +#ifdef BNX2X_STOP_ON_ERROR + /* If ramrod completion timed out - break here! */ + if (bp->panic) { + BNX2X_ERR("Stop leading failed!\n"); + return -EBUSY; + } +#endif + + if ((bp->state != BNX2X_STATE_CLOSING_WAIT4_UNLOAD) || + (bp->fp[0].state != BNX2X_FP_STATE_CLOSED)) { + DP(NETIF_MSG_IFDOWN, "failed to close leading properly! " + "state 0x%x fp[0].state 0x%x\n", + bp->state, bp->fp[0].state); + } + +unload_error: + if (!BP_NOMCP(bp)) + reset_code = bnx2x_fw_command(bp, reset_code); + else { + DP(NETIF_MSG_IFDOWN, "NO MCP load counts %d, %d, %d\n", + load_count[0], load_count[1], load_count[2]); + load_count[0]--; + load_count[1 + BP_PORT(bp)]--; + DP(NETIF_MSG_IFDOWN, "NO MCP new load counts %d, %d, %d\n", + load_count[0], load_count[1], load_count[2]); + if (load_count[0] == 0) + reset_code = FW_MSG_CODE_DRV_UNLOAD_COMMON; + else if (load_count[1 + BP_PORT(bp)] == 0) + reset_code = FW_MSG_CODE_DRV_UNLOAD_PORT; + else + reset_code = FW_MSG_CODE_DRV_UNLOAD_FUNCTION; + } + + if ((reset_code == FW_MSG_CODE_DRV_UNLOAD_COMMON) || + (reset_code == FW_MSG_CODE_DRV_UNLOAD_PORT)) + bnx2x__link_reset(bp); + + /* Reset the chip */ + bnx2x_reset_chip(bp, reset_code); + + /* Report UNLOAD_DONE to MCP */ + if (!BP_NOMCP(bp)) + bnx2x_fw_command(bp, DRV_MSG_CODE_UNLOAD_DONE); + + /* Free SKBs, SGEs, TPA pool and driver internals */ + bnx2x_free_skbs(bp); + for_each_queue(bp, i) + bnx2x_free_rx_sge_range(bp, bp->fp + i, + RX_SGE_CNT*NUM_RX_SGE_PAGES); + bnx2x_free_mem(bp); + + bp->state = BNX2X_STATE_CLOSED; + + netif_carrier_off(bp->dev); + + return 0; +} + +static void bnx2x_reset_task(struct work_struct *work) +{ + struct bnx2x *bp = container_of(work, struct bnx2x, reset_task); + +#ifdef BNX2X_STOP_ON_ERROR + BNX2X_ERR("reset task called but STOP_ON_ERROR defined" + " so reset not done to allow debug dump,\n" + KERN_ERR " you will need to reboot when done\n"); + return; +#endif + + rtnl_lock(); + + if (!netif_running(bp->dev)) + goto reset_task_exit; + + bnx2x_nic_unload(bp, UNLOAD_NORMAL); + bnx2x_nic_load(bp, LOAD_NORMAL); + +reset_task_exit: + rtnl_unlock(); +} + +/* end of nic load/unload */ + +/* ethtool_ops */ + +/* + * Init service functions + */ + +static void __devinit bnx2x_undi_unload(struct bnx2x *bp) +{ + u32 val; + + /* Check if there is any driver already loaded */ + val = REG_RD(bp, MISC_REG_UNPREPARED); + if (val == 0x1) { + /* Check if it is the UNDI driver + * UNDI driver initializes CID offset for normal bell to 0x7 + */ + val = REG_RD(bp, DORQ_REG_NORM_CID_OFST); + if (val == 0x7) { + u32 reset_code = DRV_MSG_CODE_UNLOAD_REQ_WOL_DIS; + /* save our func and fw_seq */ + int func = BP_FUNC(bp); + u16 fw_seq = bp->fw_seq; + + BNX2X_DEV_INFO("UNDI is active! reset device\n"); + + /* try unload UNDI on port 0 */ + bp->func = 0; + bp->fw_seq = (SHMEM_RD(bp, + func_mb[bp->func].drv_mb_header) & + DRV_MSG_SEQ_NUMBER_MASK); + + reset_code = bnx2x_fw_command(bp, reset_code); + bnx2x_fw_command(bp, DRV_MSG_CODE_UNLOAD_DONE); + + /* if UNDI is loaded on the other port */ + if (reset_code != FW_MSG_CODE_DRV_UNLOAD_COMMON) { + + bp->func = 1; + bp->fw_seq = (SHMEM_RD(bp, + func_mb[bp->func].drv_mb_header) & + DRV_MSG_SEQ_NUMBER_MASK); + + bnx2x_fw_command(bp, + DRV_MSG_CODE_UNLOAD_REQ_WOL_DIS); + bnx2x_fw_command(bp, + DRV_MSG_CODE_UNLOAD_DONE); + + /* restore our func and fw_seq */ + bp->func = func; + bp->fw_seq = fw_seq; + } + + /* reset device */ + REG_WR(bp, + GRCBASE_MISC + MISC_REGISTERS_RESET_REG_1_CLEAR, + 0xd3ffff7f); + REG_WR(bp, + GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_CLEAR, + 0x1403); + } + } +} + +static void __devinit bnx2x_get_common_hwinfo(struct bnx2x *bp) +{ + u32 val, val2, val3, val4, id; + + /* Get the chip revision id and number. */ + /* chip num:16-31, rev:12-15, metal:4-11, bond_id:0-3 */ + val = REG_RD(bp, MISC_REG_CHIP_NUM); + id = ((val & 0xffff) << 16); + val = REG_RD(bp, MISC_REG_CHIP_REV); + id |= ((val & 0xf) << 12); + val = REG_RD(bp, MISC_REG_CHIP_METAL); + id |= ((val & 0xff) << 4); + REG_RD(bp, MISC_REG_BOND_ID); + id |= (val & 0xf); + bp->common.chip_id = id; + bp->link_params.chip_id = bp->common.chip_id; + BNX2X_DEV_INFO("chip ID is 0x%x\n", id); + + val = REG_RD(bp, MCP_REG_MCPR_NVM_CFG4); + bp->common.flash_size = (NVRAM_1MB_SIZE << + (val & MCPR_NVM_CFG4_FLASH_SIZE)); + BNX2X_DEV_INFO("flash_size 0x%x (%d)\n", + bp->common.flash_size, bp->common.flash_size); + + bp->common.shmem_base = REG_RD(bp, MISC_REG_SHARED_MEM_ADDR); + bp->link_params.shmem_base = bp->common.shmem_base; + BNX2X_DEV_INFO("shmem offset is 0x%x\n", bp->common.shmem_base); + + if (!bp->common.shmem_base || + (bp->common.shmem_base < 0xA0000) || + (bp->common.shmem_base >= 0xC0000)) { + BNX2X_DEV_INFO("MCP not active\n"); + bp->flags |= NO_MCP_FLAG; + return; + } + + val = SHMEM_RD(bp, validity_map[BP_PORT(bp)]); + if ((val & (SHR_MEM_VALIDITY_DEV_INFO | SHR_MEM_VALIDITY_MB)) + != (SHR_MEM_VALIDITY_DEV_INFO | SHR_MEM_VALIDITY_MB)) + BNX2X_ERR("BAD MCP validity signature\n"); + + bp->common.hw_config = SHMEM_RD(bp, dev_info.shared_hw_config.config); + bp->common.board = SHMEM_RD(bp, dev_info.shared_hw_config.board); + + BNX2X_DEV_INFO("hw_config 0x%08x board 0x%08x\n", + bp->common.hw_config, bp->common.board); + + bp->link_params.hw_led_mode = ((bp->common.hw_config & + SHARED_HW_CFG_LED_MODE_MASK) >> + SHARED_HW_CFG_LED_MODE_SHIFT); + + val = SHMEM_RD(bp, dev_info.bc_rev) >> 8; + bp->common.bc_ver = val; + BNX2X_DEV_INFO("bc_ver %X\n", val); + if (val < BNX2X_BC_VER) { + /* for now only warn + * later we might need to enforce this */ + BNX2X_ERR("This driver needs bc_ver %X but found %X," + " please upgrade BC\n", BNX2X_BC_VER, val); + } + BNX2X_DEV_INFO("%sWoL Capable\n", + (bp->flags & NO_WOL_FLAG)? "Not " : ""); + + val = SHMEM_RD(bp, dev_info.shared_hw_config.part_num); + val2 = SHMEM_RD(bp, dev_info.shared_hw_config.part_num[4]); + val3 = SHMEM_RD(bp, dev_info.shared_hw_config.part_num[8]); + val4 = SHMEM_RD(bp, dev_info.shared_hw_config.part_num[12]); + + printk(KERN_INFO PFX "part number %X-%X-%X-%X\n", + val, val2, val3, val4); +} + +static void __devinit bnx2x_link_settings_supported(struct bnx2x *bp, + u32 switch_cfg) +{ + int port = BP_PORT(bp); + u32 ext_phy_type; + + switch (switch_cfg) { + case SWITCH_CFG_1G: + BNX2X_DEV_INFO("switch_cfg 0x%x (1G)\n", switch_cfg); + + ext_phy_type = + SERDES_EXT_PHY_TYPE(bp->link_params.ext_phy_config); + switch (ext_phy_type) { + case PORT_HW_CFG_SERDES_EXT_PHY_TYPE_DIRECT: + BNX2X_DEV_INFO("ext_phy_type 0x%x (Direct)\n", + ext_phy_type); + + bp->port.supported |= (SUPPORTED_10baseT_Half | + SUPPORTED_10baseT_Full | + SUPPORTED_100baseT_Half | + SUPPORTED_100baseT_Full | + SUPPORTED_1000baseT_Full | + SUPPORTED_2500baseX_Full | + SUPPORTED_TP | + SUPPORTED_FIBRE | + SUPPORTED_Autoneg | + SUPPORTED_Pause | + SUPPORTED_Asym_Pause); + break; + + case PORT_HW_CFG_SERDES_EXT_PHY_TYPE_BCM5482: + BNX2X_DEV_INFO("ext_phy_type 0x%x (5482)\n", + ext_phy_type); + + bp->port.supported |= (SUPPORTED_10baseT_Half | + SUPPORTED_10baseT_Full | + SUPPORTED_100baseT_Half | + SUPPORTED_100baseT_Full | + SUPPORTED_1000baseT_Full | + SUPPORTED_TP | + SUPPORTED_FIBRE | + SUPPORTED_Autoneg | + SUPPORTED_Pause | + SUPPORTED_Asym_Pause); + break; + + default: + BNX2X_ERR("NVRAM config error. " + "BAD SerDes ext_phy_config 0x%x\n", + bp->link_params.ext_phy_config); + return; + } + + bp->port.phy_addr = REG_RD(bp, NIG_REG_SERDES0_CTRL_PHY_ADDR + + port*0x10); + BNX2X_DEV_INFO("phy_addr 0x%x\n", bp->port.phy_addr); + break; + + case SWITCH_CFG_10G: + BNX2X_DEV_INFO("switch_cfg 0x%x (10G)\n", switch_cfg); + + ext_phy_type = + XGXS_EXT_PHY_TYPE(bp->link_params.ext_phy_config); + switch (ext_phy_type) { + case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT: + BNX2X_DEV_INFO("ext_phy_type 0x%x (Direct)\n", + ext_phy_type); + + bp->port.supported |= (SUPPORTED_10baseT_Half | + SUPPORTED_10baseT_Full | + SUPPORTED_100baseT_Half | + SUPPORTED_100baseT_Full | + SUPPORTED_1000baseT_Full | + SUPPORTED_2500baseX_Full | + SUPPORTED_10000baseT_Full | + SUPPORTED_TP | + SUPPORTED_FIBRE | + SUPPORTED_Autoneg | + SUPPORTED_Pause | + SUPPORTED_Asym_Pause); + break; + + case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705: + BNX2X_DEV_INFO("ext_phy_type 0x%x (8705)\n", + ext_phy_type); + + bp->port.supported |= (SUPPORTED_10000baseT_Full | + SUPPORTED_FIBRE | + SUPPORTED_Pause | + SUPPORTED_Asym_Pause); + break; + + case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706: + BNX2X_DEV_INFO("ext_phy_type 0x%x (8706)\n", + ext_phy_type); + + bp->port.supported |= (SUPPORTED_10000baseT_Full | + SUPPORTED_1000baseT_Full | + SUPPORTED_FIBRE | + SUPPORTED_Pause | + SUPPORTED_Asym_Pause); + break; + + case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072: + BNX2X_DEV_INFO("ext_phy_type 0x%x (8072)\n", + ext_phy_type); + + bp->port.supported |= (SUPPORTED_10000baseT_Full | + SUPPORTED_1000baseT_Full | + SUPPORTED_FIBRE | + SUPPORTED_Autoneg | + SUPPORTED_Pause | + SUPPORTED_Asym_Pause); + break; + + case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073: + BNX2X_DEV_INFO("ext_phy_type 0x%x (8073)\n", + ext_phy_type); + + bp->port.supported |= (SUPPORTED_10000baseT_Full | + SUPPORTED_2500baseX_Full | + SUPPORTED_1000baseT_Full | + SUPPORTED_FIBRE | + SUPPORTED_Autoneg | + SUPPORTED_Pause | + SUPPORTED_Asym_Pause); + break; + + case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101: + BNX2X_DEV_INFO("ext_phy_type 0x%x (SFX7101)\n", + ext_phy_type); + + bp->port.supported |= (SUPPORTED_10000baseT_Full | + SUPPORTED_TP | + SUPPORTED_Autoneg | + SUPPORTED_Pause | + SUPPORTED_Asym_Pause); + break; + + case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE: + BNX2X_ERR("XGXS PHY Failure detected 0x%x\n", + bp->link_params.ext_phy_config); + break; + + default: + BNX2X_ERR("NVRAM config error. " + "BAD XGXS ext_phy_config 0x%x\n", + bp->link_params.ext_phy_config); + return; + } + + bp->port.phy_addr = REG_RD(bp, NIG_REG_XGXS0_CTRL_PHY_ADDR + + port*0x18); + BNX2X_DEV_INFO("phy_addr 0x%x\n", bp->port.phy_addr); + + break; + + default: + BNX2X_ERR("BAD switch_cfg link_config 0x%x\n", + bp->port.link_config); + return; + } + bp->link_params.phy_addr = bp->port.phy_addr; + + /* mask what we support according to speed_cap_mask */ + if (!(bp->link_params.speed_cap_mask & + PORT_HW_CFG_SPEED_CAPABILITY_D0_10M_HALF)) + bp->port.supported &= ~SUPPORTED_10baseT_Half; + + if (!(bp->link_params.speed_cap_mask & + PORT_HW_CFG_SPEED_CAPABILITY_D0_10M_FULL)) + bp->port.supported &= ~SUPPORTED_10baseT_Full; + + if (!(bp->link_params.speed_cap_mask & + PORT_HW_CFG_SPEED_CAPABILITY_D0_100M_HALF)) + bp->port.supported &= ~SUPPORTED_100baseT_Half; + + if (!(bp->link_params.speed_cap_mask & + PORT_HW_CFG_SPEED_CAPABILITY_D0_100M_FULL)) + bp->port.supported &= ~SUPPORTED_100baseT_Full; + + if (!(bp->link_params.speed_cap_mask & + PORT_HW_CFG_SPEED_CAPABILITY_D0_1G)) + bp->port.supported &= ~(SUPPORTED_1000baseT_Half | + SUPPORTED_1000baseT_Full); + + if (!(bp->link_params.speed_cap_mask & + PORT_HW_CFG_SPEED_CAPABILITY_D0_2_5G)) + bp->port.supported &= ~SUPPORTED_2500baseX_Full; + + if (!(bp->link_params.speed_cap_mask & + PORT_HW_CFG_SPEED_CAPABILITY_D0_10G)) + bp->port.supported &= ~SUPPORTED_10000baseT_Full; + + BNX2X_DEV_INFO("supported 0x%x\n", bp->port.supported); +} + +static void __devinit bnx2x_link_settings_requested(struct bnx2x *bp) +{ + bp->link_params.req_duplex = DUPLEX_FULL; + + switch (bp->port.link_config & PORT_FEATURE_LINK_SPEED_MASK) { + case PORT_FEATURE_LINK_SPEED_AUTO: + if (bp->port.supported & SUPPORTED_Autoneg) { + bp->link_params.req_line_speed = SPEED_AUTO_NEG; + bp->port.advertising = bp->port.supported; + } else { + u32 ext_phy_type = + XGXS_EXT_PHY_TYPE(bp->link_params.ext_phy_config); + + if ((ext_phy_type == + PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705) || + (ext_phy_type == + PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706)) { + /* force 10G, no AN */ + bp->link_params.req_line_speed = SPEED_10000; + bp->port.advertising = + (ADVERTISED_10000baseT_Full | + ADVERTISED_FIBRE); + break; + } + BNX2X_ERR("NVRAM config error. " + "Invalid link_config 0x%x" + " Autoneg not supported\n", + bp->port.link_config); + return; + } + break; + + case PORT_FEATURE_LINK_SPEED_10M_FULL: + if (bp->port.supported & SUPPORTED_10baseT_Full) { + bp->link_params.req_line_speed = SPEED_10; + bp->port.advertising = (ADVERTISED_10baseT_Full | + ADVERTISED_TP); + } else { + BNX2X_ERR("NVRAM config error. " + "Invalid link_config 0x%x" + " speed_cap_mask 0x%x\n", + bp->port.link_config, + bp->link_params.speed_cap_mask); + return; + } + break; + + case PORT_FEATURE_LINK_SPEED_10M_HALF: + if (bp->port.supported & SUPPORTED_10baseT_Half) { + bp->link_params.req_line_speed = SPEED_10; + bp->link_params.req_duplex = DUPLEX_HALF; + bp->port.advertising = (ADVERTISED_10baseT_Half | + ADVERTISED_TP); + } else { + BNX2X_ERR("NVRAM config error. " + "Invalid link_config 0x%x" + " speed_cap_mask 0x%x\n", + bp->port.link_config, + bp->link_params.speed_cap_mask); + return; + } + break; + + case PORT_FEATURE_LINK_SPEED_100M_FULL: + if (bp->port.supported & SUPPORTED_100baseT_Full) { + bp->link_params.req_line_speed = SPEED_100; + bp->port.advertising = (ADVERTISED_100baseT_Full | + ADVERTISED_TP); + } else { + BNX2X_ERR("NVRAM config error. " + "Invalid link_config 0x%x" + " speed_cap_mask 0x%x\n", + bp->port.link_config, + bp->link_params.speed_cap_mask); + return; + } + break; + + case PORT_FEATURE_LINK_SPEED_100M_HALF: + if (bp->port.supported & SUPPORTED_100baseT_Half) { + bp->link_params.req_line_speed = SPEED_100; + bp->link_params.req_duplex = DUPLEX_HALF; + bp->port.advertising = (ADVERTISED_100baseT_Half | + ADVERTISED_TP); + } else { + BNX2X_ERR("NVRAM config error. " + "Invalid link_config 0x%x" + " speed_cap_mask 0x%x\n", + bp->port.link_config, + bp->link_params.speed_cap_mask); + return; + } + break; + + case PORT_FEATURE_LINK_SPEED_1G: + if (bp->port.supported & SUPPORTED_1000baseT_Full) { + bp->link_params.req_line_speed = SPEED_1000; + bp->port.advertising = (ADVERTISED_1000baseT_Full | + ADVERTISED_TP); + } else { + BNX2X_ERR("NVRAM config error. " + "Invalid link_config 0x%x" + " speed_cap_mask 0x%x\n", + bp->port.link_config, + bp->link_params.speed_cap_mask); + return; + } + break; + + case PORT_FEATURE_LINK_SPEED_2_5G: + if (bp->port.supported & SUPPORTED_2500baseX_Full) { + bp->link_params.req_line_speed = SPEED_2500; + bp->port.advertising = (ADVERTISED_2500baseX_Full | + ADVERTISED_TP); + } else { + BNX2X_ERR("NVRAM config error. " + "Invalid link_config 0x%x" + " speed_cap_mask 0x%x\n", + bp->port.link_config, + bp->link_params.speed_cap_mask); + return; + } + break; + + case PORT_FEATURE_LINK_SPEED_10G_CX4: + case PORT_FEATURE_LINK_SPEED_10G_KX4: + case PORT_FEATURE_LINK_SPEED_10G_KR: + if (bp->port.supported & SUPPORTED_10000baseT_Full) { + bp->link_params.req_line_speed = SPEED_10000; + bp->port.advertising = (ADVERTISED_10000baseT_Full | + ADVERTISED_FIBRE); + } else { + BNX2X_ERR("NVRAM config error. " + "Invalid link_config 0x%x" + " speed_cap_mask 0x%x\n", + bp->port.link_config, + bp->link_params.speed_cap_mask); + return; + } + break; + + default: + BNX2X_ERR("NVRAM config error. " + "BAD link speed link_config 0x%x\n", + bp->port.link_config); + bp->link_params.req_line_speed = SPEED_AUTO_NEG; + bp->port.advertising = bp->port.supported; + break; + } + + bp->link_params.req_flow_ctrl = (bp->port.link_config & + PORT_FEATURE_FLOW_CONTROL_MASK); + if ((bp->link_params.req_flow_ctrl == FLOW_CTRL_AUTO) && + (!bp->port.supported & SUPPORTED_Autoneg)) + bp->link_params.req_flow_ctrl = FLOW_CTRL_NONE; + + BNX2X_DEV_INFO("req_line_speed %d req_duplex %d req_flow_ctrl 0x%x" + " advertising 0x%x\n", + bp->link_params.req_line_speed, + bp->link_params.req_duplex, + bp->link_params.req_flow_ctrl, bp->port.advertising); +} + +static void __devinit bnx2x_get_port_hwinfo(struct bnx2x *bp) +{ + int port = BP_PORT(bp); + u32 val, val2; + + bp->link_params.bp = bp; + bp->link_params.port = port; + + bp->link_params.serdes_config = + SHMEM_RD(bp, dev_info.port_hw_config[port].serdes_config); + bp->link_params.lane_config = + SHMEM_RD(bp, dev_info.port_hw_config[port].lane_config); + bp->link_params.ext_phy_config = + SHMEM_RD(bp, + dev_info.port_hw_config[port].external_phy_config); + bp->link_params.speed_cap_mask = + SHMEM_RD(bp, + dev_info.port_hw_config[port].speed_capability_mask); + + bp->port.link_config = + SHMEM_RD(bp, dev_info.port_feature_config[port].link_config); + + BNX2X_DEV_INFO("serdes_config 0x%08x lane_config 0x%08x\n" + KERN_INFO " ext_phy_config 0x%08x speed_cap_mask 0x%08x" + " link_config 0x%08x\n", + bp->link_params.serdes_config, + bp->link_params.lane_config, + bp->link_params.ext_phy_config, + bp->link_params.speed_cap_mask, bp->port.link_config); + + bp->link_params.switch_cfg = (bp->port.link_config & + PORT_FEATURE_CONNECTED_SWITCH_MASK); + bnx2x_link_settings_supported(bp, bp->link_params.switch_cfg); + + bnx2x_link_settings_requested(bp); + + val2 = SHMEM_RD(bp, dev_info.port_hw_config[port].mac_upper); + val = SHMEM_RD(bp, dev_info.port_hw_config[port].mac_lower); + bp->dev->dev_addr[0] = (u8)(val2 >> 8 & 0xff); + bp->dev->dev_addr[1] = (u8)(val2 & 0xff); + bp->dev->dev_addr[2] = (u8)(val >> 24 & 0xff); + bp->dev->dev_addr[3] = (u8)(val >> 16 & 0xff); + bp->dev->dev_addr[4] = (u8)(val >> 8 & 0xff); + bp->dev->dev_addr[5] = (u8)(val & 0xff); + memcpy(bp->link_params.mac_addr, bp->dev->dev_addr, ETH_ALEN); + memcpy(bp->dev->perm_addr, bp->dev->dev_addr, ETH_ALEN); +} + +static int __devinit bnx2x_get_hwinfo(struct bnx2x *bp) +{ + int func = BP_FUNC(bp); + u32 val, val2; + int rc = 0; + + bnx2x_get_common_hwinfo(bp); + + bp->e1hov = 0; + bp->e1hmf = 0; + if (CHIP_IS_E1H(bp)) { + bp->mf_config = + SHMEM_RD(bp, mf_cfg.func_mf_config[func].config); + + val = + (SHMEM_RD(bp, mf_cfg.func_mf_config[func].e1hov_tag) & + FUNC_MF_CFG_E1HOV_TAG_MASK); + if (val != FUNC_MF_CFG_E1HOV_TAG_DEFAULT) { + + bp->e1hov = val; + bp->e1hmf = 1; + BNX2X_DEV_INFO("MF mode E1HOV for func %d is %d " + "(0x%04x)\n", + func, bp->e1hov, bp->e1hov); + } else { + BNX2X_DEV_INFO("Single function mode\n"); + if (BP_E1HVN(bp)) { + BNX2X_ERR("!!! No valid E1HOV for func %d," + " aborting\n", func); + rc = -EPERM; + } + } + } + + if (!BP_NOMCP(bp)) { + bnx2x_get_port_hwinfo(bp); + + bp->fw_seq = (SHMEM_RD(bp, func_mb[func].drv_mb_header) & + DRV_MSG_SEQ_NUMBER_MASK); + BNX2X_DEV_INFO("fw_seq 0x%08x\n", bp->fw_seq); + } + + if (IS_E1HMF(bp)) { + val2 = SHMEM_RD(bp, mf_cfg.func_mf_config[func].mac_upper); + val = SHMEM_RD(bp, mf_cfg.func_mf_config[func].mac_lower); + if ((val2 != FUNC_MF_CFG_UPPERMAC_DEFAULT) && + (val != FUNC_MF_CFG_LOWERMAC_DEFAULT)) { + bp->dev->dev_addr[0] = (u8)(val2 >> 8 & 0xff); + bp->dev->dev_addr[1] = (u8)(val2 & 0xff); + bp->dev->dev_addr[2] = (u8)(val >> 24 & 0xff); + bp->dev->dev_addr[3] = (u8)(val >> 16 & 0xff); + bp->dev->dev_addr[4] = (u8)(val >> 8 & 0xff); + bp->dev->dev_addr[5] = (u8)(val & 0xff); + memcpy(bp->link_params.mac_addr, bp->dev->dev_addr, + ETH_ALEN); + memcpy(bp->dev->perm_addr, bp->dev->dev_addr, + ETH_ALEN); + } + + return rc; + } + + if (BP_NOMCP(bp)) { + /* only supposed to happen on emulation/FPGA */ + BNX2X_ERR("warning rendom MAC workaround active\n"); + random_ether_addr(bp->dev->dev_addr); + memcpy(bp->dev->perm_addr, bp->dev->dev_addr, ETH_ALEN); + } + + return rc; +} + +static int __devinit bnx2x_init_bp(struct bnx2x *bp) +{ + int func = BP_FUNC(bp); + int rc; + + if (nomcp) + bp->flags |= NO_MCP_FLAG; + + mutex_init(&bp->port.phy_mutex); + + INIT_WORK(&bp->sp_task, bnx2x_sp_task); + INIT_WORK(&bp->reset_task, bnx2x_reset_task); + + rc = bnx2x_get_hwinfo(bp); + + /* need to reset chip if undi was active */ + if (!BP_NOMCP(bp)) + bnx2x_undi_unload(bp); + + if (CHIP_REV_IS_FPGA(bp)) + printk(KERN_ERR PFX "FPGA detected\n"); + + if (BP_NOMCP(bp) && (func == 0)) + printk(KERN_ERR PFX + "MCP disabled, must load devices in order!\n"); + + /* Set TPA flags */ + if (disable_tpa) { + bp->flags &= ~TPA_ENABLE_FLAG; + bp->dev->features &= ~NETIF_F_LRO; + } else { + bp->flags |= TPA_ENABLE_FLAG; + bp->dev->features |= NETIF_F_LRO; + } + + + bp->tx_ring_size = MAX_TX_AVAIL; + bp->rx_ring_size = MAX_RX_AVAIL; + + bp->rx_csum = 1; + bp->rx_offset = 0; + + bp->tx_ticks = 50; + bp->rx_ticks = 25; + + bp->stats_ticks = 1000000 & 0xffff00; + + bp->timer_interval = (CHIP_REV_IS_SLOW(bp) ? 5*HZ : HZ); + bp->current_interval = (poll ? poll : bp->timer_interval); + + init_timer(&bp->timer); + bp->timer.expires = jiffies + bp->current_interval; + bp->timer.data = (unsigned long) bp; + bp->timer.function = bnx2x_timer; + + return rc; +} + +/* + * ethtool service functions + */ + +/* All ethtool functions called with rtnl_lock */ + +static int bnx2x_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) +{ + struct bnx2x *bp = netdev_priv(dev); + + cmd->supported = bp->port.supported; + cmd->advertising = bp->port.advertising; + + if (netif_carrier_ok(dev)) { + cmd->speed = bp->link_vars.line_speed; + cmd->duplex = bp->link_vars.duplex; + } else { + cmd->speed = bp->link_params.req_line_speed; + cmd->duplex = bp->link_params.req_duplex; + } + if (IS_E1HMF(bp)) { + u16 vn_max_rate; + + vn_max_rate = ((bp->mf_config & FUNC_MF_CFG_MAX_BW_MASK) >> + FUNC_MF_CFG_MAX_BW_SHIFT) * 100; + if (vn_max_rate < cmd->speed) + cmd->speed = vn_max_rate; + } + + if (bp->link_params.switch_cfg == SWITCH_CFG_10G) { + u32 ext_phy_type = + XGXS_EXT_PHY_TYPE(bp->link_params.ext_phy_config); + + switch (ext_phy_type) { + case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT: + case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705: + case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706: + case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072: + case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073: + cmd->port = PORT_FIBRE; + break; + + case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101: + cmd->port = PORT_TP; + break; + + case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE: + BNX2X_ERR("XGXS PHY Failure detected 0x%x\n", + bp->link_params.ext_phy_config); + break; + + default: + DP(NETIF_MSG_LINK, "BAD XGXS ext_phy_config 0x%x\n", + bp->link_params.ext_phy_config); + break; + } + } else + cmd->port = PORT_TP; + + cmd->phy_address = bp->port.phy_addr; + cmd->transceiver = XCVR_INTERNAL; + + if (bp->link_params.req_line_speed == SPEED_AUTO_NEG) + cmd->autoneg = AUTONEG_ENABLE; + else + cmd->autoneg = AUTONEG_DISABLE; + + cmd->maxtxpkt = 0; + cmd->maxrxpkt = 0; + + DP(NETIF_MSG_LINK, "ethtool_cmd: cmd %d\n" + DP_LEVEL " supported 0x%x advertising 0x%x speed %d\n" + DP_LEVEL " duplex %d port %d phy_address %d transceiver %d\n" + DP_LEVEL " autoneg %d maxtxpkt %d maxrxpkt %d\n", + cmd->cmd, cmd->supported, cmd->advertising, cmd->speed, + cmd->duplex, cmd->port, cmd->phy_address, cmd->transceiver, + cmd->autoneg, cmd->maxtxpkt, cmd->maxrxpkt); + + return 0; +} + +static int bnx2x_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) +{ + struct bnx2x *bp = netdev_priv(dev); + u32 advertising; + + if (IS_E1HMF(bp)) + return 0; + + DP(NETIF_MSG_LINK, "ethtool_cmd: cmd %d\n" + DP_LEVEL " supported 0x%x advertising 0x%x speed %d\n" + DP_LEVEL " duplex %d port %d phy_address %d transceiver %d\n" + DP_LEVEL " autoneg %d maxtxpkt %d maxrxpkt %d\n", + cmd->cmd, cmd->supported, cmd->advertising, cmd->speed, + cmd->duplex, cmd->port, cmd->phy_address, cmd->transceiver, + cmd->autoneg, cmd->maxtxpkt, cmd->maxrxpkt); + + if (cmd->autoneg == AUTONEG_ENABLE) { + if (!(bp->port.supported & SUPPORTED_Autoneg)) { + DP(NETIF_MSG_LINK, "Autoneg not supported\n"); + return -EINVAL; + } + + /* advertise the requested speed and duplex if supported */ + cmd->advertising &= bp->port.supported; + + bp->link_params.req_line_speed = SPEED_AUTO_NEG; + bp->link_params.req_duplex = DUPLEX_FULL; + bp->port.advertising |= (ADVERTISED_Autoneg | + cmd->advertising); + + } else { /* forced speed */ + /* advertise the requested speed and duplex if supported */ + switch (cmd->speed) { + case SPEED_10: + if (cmd->duplex == DUPLEX_FULL) { + if (!(bp->port.supported & + SUPPORTED_10baseT_Full)) { + DP(NETIF_MSG_LINK, + "10M full not supported\n"); + return -EINVAL; + } + + advertising = (ADVERTISED_10baseT_Full | + ADVERTISED_TP); + } else { + if (!(bp->port.supported & + SUPPORTED_10baseT_Half)) { + DP(NETIF_MSG_LINK, + "10M half not supported\n"); + return -EINVAL; + } + + advertising = (ADVERTISED_10baseT_Half | + ADVERTISED_TP); + } + break; + + case SPEED_100: + if (cmd->duplex == DUPLEX_FULL) { + if (!(bp->port.supported & + SUPPORTED_100baseT_Full)) { + DP(NETIF_MSG_LINK, + "100M full not supported\n"); + return -EINVAL; + } + + advertising = (ADVERTISED_100baseT_Full | + ADVERTISED_TP); + } else { + if (!(bp->port.supported & + SUPPORTED_100baseT_Half)) { + DP(NETIF_MSG_LINK, + "100M half not supported\n"); + return -EINVAL; + } + + advertising = (ADVERTISED_100baseT_Half | + ADVERTISED_TP); + } + break; + + case SPEED_1000: + if (cmd->duplex != DUPLEX_FULL) { + DP(NETIF_MSG_LINK, "1G half not supported\n"); + return -EINVAL; + } + + if (!(bp->port.supported & SUPPORTED_1000baseT_Full)) { + DP(NETIF_MSG_LINK, "1G full not supported\n"); + return -EINVAL; + } + + advertising = (ADVERTISED_1000baseT_Full | + ADVERTISED_TP); + break; + + case SPEED_2500: + if (cmd->duplex != DUPLEX_FULL) { + DP(NETIF_MSG_LINK, + "2.5G half not supported\n"); + return -EINVAL; + } + + if (!(bp->port.supported & SUPPORTED_2500baseX_Full)) { + DP(NETIF_MSG_LINK, + "2.5G full not supported\n"); + return -EINVAL; + } + + advertising = (ADVERTISED_2500baseX_Full | + ADVERTISED_TP); + break; + + case SPEED_10000: + if (cmd->duplex != DUPLEX_FULL) { + DP(NETIF_MSG_LINK, "10G half not supported\n"); + return -EINVAL; + } + + if (!(bp->port.supported & SUPPORTED_10000baseT_Full)) { + DP(NETIF_MSG_LINK, "10G full not supported\n"); + return -EINVAL; + } + + advertising = (ADVERTISED_10000baseT_Full | + ADVERTISED_FIBRE); + break; + + default: + DP(NETIF_MSG_LINK, "Unsupported speed\n"); + return -EINVAL; + } + + bp->link_params.req_line_speed = cmd->speed; + bp->link_params.req_duplex = cmd->duplex; + bp->port.advertising = advertising; + } + + DP(NETIF_MSG_LINK, "req_line_speed %d\n" + DP_LEVEL " req_duplex %d advertising 0x%x\n", + bp->link_params.req_line_speed, bp->link_params.req_duplex, + bp->port.advertising); + + if (netif_running(dev)) { + bnx2x_stats_handle(bp, STATS_EVENT_STOP); + bnx2x_link_set(bp); + } + + return 0; +} + +#define PHY_FW_VER_LEN 10 + +static void bnx2x_get_drvinfo(struct net_device *dev, + struct ethtool_drvinfo *info) +{ + struct bnx2x *bp = netdev_priv(dev); + char phy_fw_ver[PHY_FW_VER_LEN]; + + strcpy(info->driver, DRV_MODULE_NAME); + strcpy(info->version, DRV_MODULE_VERSION); + + phy_fw_ver[0] = '\0'; + if (bp->port.pmf) { + bnx2x_phy_hw_lock(bp); + bnx2x_get_ext_phy_fw_version(&bp->link_params, + (bp->state != BNX2X_STATE_CLOSED), + phy_fw_ver, PHY_FW_VER_LEN); + bnx2x_phy_hw_unlock(bp); + } + + snprintf(info->fw_version, 32, "%d.%d.%d:%d BC:%x%s%s", + BCM_5710_FW_MAJOR_VERSION, BCM_5710_FW_MINOR_VERSION, + BCM_5710_FW_REVISION_VERSION, + BCM_5710_FW_COMPILE_FLAGS, bp->common.bc_ver, + ((phy_fw_ver[0] != '\0')? " PHY:":""), phy_fw_ver); + strcpy(info->bus_info, pci_name(bp->pdev)); + info->n_stats = BNX2X_NUM_STATS; + info->testinfo_len = BNX2X_NUM_TESTS; + info->eedump_len = bp->common.flash_size; + info->regdump_len = 0; +} + +static void bnx2x_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol) +{ + struct bnx2x *bp = netdev_priv(dev); + + if (bp->flags & NO_WOL_FLAG) { + wol->supported = 0; + wol->wolopts = 0; + } else { + wol->supported = WAKE_MAGIC; + if (bp->wol) + wol->wolopts = WAKE_MAGIC; + else + wol->wolopts = 0; + } + memset(&wol->sopass, 0, sizeof(wol->sopass)); +} + +static int bnx2x_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol) +{ + struct bnx2x *bp = netdev_priv(dev); + + if (wol->wolopts & ~WAKE_MAGIC) + return -EINVAL; + + if (wol->wolopts & WAKE_MAGIC) { + if (bp->flags & NO_WOL_FLAG) + return -EINVAL; + + bp->wol = 1; + } else + bp->wol = 0; + + return 0; +} + +static u32 bnx2x_get_msglevel(struct net_device *dev) +{ + struct bnx2x *bp = netdev_priv(dev); + + return bp->msglevel; +} + +static void bnx2x_set_msglevel(struct net_device *dev, u32 level) +{ + struct bnx2x *bp = netdev_priv(dev); + + if (capable(CAP_NET_ADMIN)) + bp->msglevel = level; +} + +static int bnx2x_nway_reset(struct net_device *dev) +{ + struct bnx2x *bp = netdev_priv(dev); + + if (!bp->port.pmf) + return 0; + + if (netif_running(dev)) { + bnx2x_stats_handle(bp, STATS_EVENT_STOP); + bnx2x_link_set(bp); + } + + return 0; +} + +static int bnx2x_get_eeprom_len(struct net_device *dev) +{ + struct bnx2x *bp = netdev_priv(dev); + + return bp->common.flash_size; +} + +static int bnx2x_acquire_nvram_lock(struct bnx2x *bp) +{ + int port = BP_PORT(bp); + int count, i; + u32 val = 0; + + /* adjust timeout for emulation/FPGA */ + count = NVRAM_TIMEOUT_COUNT; + if (CHIP_REV_IS_SLOW(bp)) + count *= 100; + + /* request access to nvram interface */ + REG_WR(bp, MCP_REG_MCPR_NVM_SW_ARB, + (MCPR_NVM_SW_ARB_ARB_REQ_SET1 << port)); + + for (i = 0; i < count*10; i++) { + val = REG_RD(bp, MCP_REG_MCPR_NVM_SW_ARB); + if (val & (MCPR_NVM_SW_ARB_ARB_ARB1 << port)) + break; + + udelay(5); + } + + if (!(val & (MCPR_NVM_SW_ARB_ARB_ARB1 << port))) { + DP(BNX2X_MSG_NVM, "cannot get access to nvram interface\n"); + return -EBUSY; + } + + return 0; +} + +static int bnx2x_release_nvram_lock(struct bnx2x *bp) +{ + int port = BP_PORT(bp); + int count, i; + u32 val = 0; + + /* adjust timeout for emulation/FPGA */ + count = NVRAM_TIMEOUT_COUNT; + if (CHIP_REV_IS_SLOW(bp)) + count *= 100; + + /* relinquish nvram interface */ + REG_WR(bp, MCP_REG_MCPR_NVM_SW_ARB, + (MCPR_NVM_SW_ARB_ARB_REQ_CLR1 << port)); + + for (i = 0; i < count*10; i++) { + val = REG_RD(bp, MCP_REG_MCPR_NVM_SW_ARB); + if (!(val & (MCPR_NVM_SW_ARB_ARB_ARB1 << port))) + break; + + udelay(5); + } + + if (val & (MCPR_NVM_SW_ARB_ARB_ARB1 << port)) { + DP(BNX2X_MSG_NVM, "cannot free access to nvram interface\n"); + return -EBUSY; + } + + return 0; +} + +static void bnx2x_enable_nvram_access(struct bnx2x *bp) +{ + u32 val; + + val = REG_RD(bp, MCP_REG_MCPR_NVM_ACCESS_ENABLE); + + /* enable both bits, even on read */ + REG_WR(bp, MCP_REG_MCPR_NVM_ACCESS_ENABLE, + (val | MCPR_NVM_ACCESS_ENABLE_EN | + MCPR_NVM_ACCESS_ENABLE_WR_EN)); +} + +static void bnx2x_disable_nvram_access(struct bnx2x *bp) +{ + u32 val; + + val = REG_RD(bp, MCP_REG_MCPR_NVM_ACCESS_ENABLE); + + /* disable both bits, even after read */ + REG_WR(bp, MCP_REG_MCPR_NVM_ACCESS_ENABLE, + (val & ~(MCPR_NVM_ACCESS_ENABLE_EN | + MCPR_NVM_ACCESS_ENABLE_WR_EN))); +} + +static int bnx2x_nvram_read_dword(struct bnx2x *bp, u32 offset, u32 *ret_val, + u32 cmd_flags) +{ + int count, i, rc; + u32 val; + + /* build the command word */ + cmd_flags |= MCPR_NVM_COMMAND_DOIT; + + /* need to clear DONE bit separately */ + REG_WR(bp, MCP_REG_MCPR_NVM_COMMAND, MCPR_NVM_COMMAND_DONE); + + /* address of the NVRAM to read from */ + REG_WR(bp, MCP_REG_MCPR_NVM_ADDR, + (offset & MCPR_NVM_ADDR_NVM_ADDR_VALUE)); + + /* issue a read command */ + REG_WR(bp, MCP_REG_MCPR_NVM_COMMAND, cmd_flags); + + /* adjust timeout for emulation/FPGA */ + count = NVRAM_TIMEOUT_COUNT; + if (CHIP_REV_IS_SLOW(bp)) + count *= 100; + + /* wait for completion */ + *ret_val = 0; + rc = -EBUSY; + for (i = 0; i < count; i++) { + udelay(5); + val = REG_RD(bp, MCP_REG_MCPR_NVM_COMMAND); + + if (val & MCPR_NVM_COMMAND_DONE) { + val = REG_RD(bp, MCP_REG_MCPR_NVM_READ); + /* we read nvram data in cpu order + * but ethtool sees it as an array of bytes + * converting to big-endian will do the work */ + val = cpu_to_be32(val); + *ret_val = val; + rc = 0; + break; + } + } + + return rc; +} + +static int bnx2x_nvram_read(struct bnx2x *bp, u32 offset, u8 *ret_buf, + int buf_size) +{ + int rc; + u32 cmd_flags; + u32 val; + + if ((offset & 0x03) || (buf_size & 0x03) || (buf_size == 0)) { + DP(BNX2X_MSG_NVM, + "Invalid parameter: offset 0x%x buf_size 0x%x\n", + offset, buf_size); + return -EINVAL; + } + + if (offset + buf_size > bp->common.flash_size) { + DP(BNX2X_MSG_NVM, "Invalid parameter: offset (0x%x) +" + " buf_size (0x%x) > flash_size (0x%x)\n", + offset, buf_size, bp->common.flash_size); + return -EINVAL; + } + + /* request access to nvram interface */ + rc = bnx2x_acquire_nvram_lock(bp); + if (rc) + return rc; + + /* enable access to nvram interface */ + bnx2x_enable_nvram_access(bp); + + /* read the first word(s) */ + cmd_flags = MCPR_NVM_COMMAND_FIRST; + while ((buf_size > sizeof(u32)) && (rc == 0)) { + rc = bnx2x_nvram_read_dword(bp, offset, &val, cmd_flags); + memcpy(ret_buf, &val, 4); + + /* advance to the next dword */ + offset += sizeof(u32); + ret_buf += sizeof(u32); + buf_size -= sizeof(u32); + cmd_flags = 0; + } + + if (rc == 0) { + cmd_flags |= MCPR_NVM_COMMAND_LAST; + rc = bnx2x_nvram_read_dword(bp, offset, &val, cmd_flags); + memcpy(ret_buf, &val, 4); + } + + /* disable access to nvram interface */ + bnx2x_disable_nvram_access(bp); + bnx2x_release_nvram_lock(bp); + + return rc; +} + +static int bnx2x_get_eeprom(struct net_device *dev, + struct ethtool_eeprom *eeprom, u8 *eebuf) +{ + struct bnx2x *bp = netdev_priv(dev); + int rc; + + DP(BNX2X_MSG_NVM, "ethtool_eeprom: cmd %d\n" + DP_LEVEL " magic 0x%x offset 0x%x (%d) len 0x%x (%d)\n", + eeprom->cmd, eeprom->magic, eeprom->offset, eeprom->offset, + eeprom->len, eeprom->len); + + /* parameters already validated in ethtool_get_eeprom */ + + rc = bnx2x_nvram_read(bp, eeprom->offset, eebuf, eeprom->len); + + return rc; +} + +static int bnx2x_nvram_write_dword(struct bnx2x *bp, u32 offset, u32 val, + u32 cmd_flags) +{ + int count, i, rc; + + /* build the command word */ + cmd_flags |= MCPR_NVM_COMMAND_DOIT | MCPR_NVM_COMMAND_WR; + + /* need to clear DONE bit separately */ + REG_WR(bp, MCP_REG_MCPR_NVM_COMMAND, MCPR_NVM_COMMAND_DONE); + + /* write the data */ + REG_WR(bp, MCP_REG_MCPR_NVM_WRITE, val); + + /* address of the NVRAM to write to */ + REG_WR(bp, MCP_REG_MCPR_NVM_ADDR, + (offset & MCPR_NVM_ADDR_NVM_ADDR_VALUE)); + + /* issue the write command */ + REG_WR(bp, MCP_REG_MCPR_NVM_COMMAND, cmd_flags); + + /* adjust timeout for emulation/FPGA */ + count = NVRAM_TIMEOUT_COUNT; + if (CHIP_REV_IS_SLOW(bp)) + count *= 100; + + /* wait for completion */ + rc = -EBUSY; + for (i = 0; i < count; i++) { + udelay(5); + val = REG_RD(bp, MCP_REG_MCPR_NVM_COMMAND); + if (val & MCPR_NVM_COMMAND_DONE) { + rc = 0; + break; + } + } + + return rc; +} + +#define BYTE_OFFSET(offset) (8 * (offset & 0x03)) + +static int bnx2x_nvram_write1(struct bnx2x *bp, u32 offset, u8 *data_buf, + int buf_size) +{ + int rc; + u32 cmd_flags; + u32 align_offset; + u32 val; + + if (offset + buf_size > bp->common.flash_size) { + DP(BNX2X_MSG_NVM, "Invalid parameter: offset (0x%x) +" + " buf_size (0x%x) > flash_size (0x%x)\n", + offset, buf_size, bp->common.flash_size); + return -EINVAL; + } + + /* request access to nvram interface */ + rc = bnx2x_acquire_nvram_lock(bp); + if (rc) + return rc; + + /* enable access to nvram interface */ + bnx2x_enable_nvram_access(bp); + + cmd_flags = (MCPR_NVM_COMMAND_FIRST | MCPR_NVM_COMMAND_LAST); + align_offset = (offset & ~0x03); + rc = bnx2x_nvram_read_dword(bp, align_offset, &val, cmd_flags); + + if (rc == 0) { + val &= ~(0xff << BYTE_OFFSET(offset)); + val |= (*data_buf << BYTE_OFFSET(offset)); + + /* nvram data is returned as an array of bytes + * convert it back to cpu order */ + val = be32_to_cpu(val); + + rc = bnx2x_nvram_write_dword(bp, align_offset, val, + cmd_flags); + } + + /* disable access to nvram interface */ + bnx2x_disable_nvram_access(bp); + bnx2x_release_nvram_lock(bp); + + return rc; +} + +static int bnx2x_nvram_write(struct bnx2x *bp, u32 offset, u8 *data_buf, + int buf_size) +{ + int rc; + u32 cmd_flags; + u32 val; + u32 written_so_far; + + if (buf_size == 1) /* ethtool */ + return bnx2x_nvram_write1(bp, offset, data_buf, buf_size); + + if ((offset & 0x03) || (buf_size & 0x03) || (buf_size == 0)) { + DP(BNX2X_MSG_NVM, + "Invalid parameter: offset 0x%x buf_size 0x%x\n", + offset, buf_size); + return -EINVAL; + } + + if (offset + buf_size > bp->common.flash_size) { + DP(BNX2X_MSG_NVM, "Invalid parameter: offset (0x%x) +" + " buf_size (0x%x) > flash_size (0x%x)\n", + offset, buf_size, bp->common.flash_size); + return -EINVAL; + } + + /* request access to nvram interface */ + rc = bnx2x_acquire_nvram_lock(bp); + if (rc) + return rc; + + /* enable access to nvram interface */ + bnx2x_enable_nvram_access(bp); + + written_so_far = 0; + cmd_flags = MCPR_NVM_COMMAND_FIRST; + while ((written_so_far < buf_size) && (rc == 0)) { + if (written_so_far == (buf_size - sizeof(u32))) + cmd_flags |= MCPR_NVM_COMMAND_LAST; + else if (((offset + 4) % NVRAM_PAGE_SIZE) == 0) + cmd_flags |= MCPR_NVM_COMMAND_LAST; + else if ((offset % NVRAM_PAGE_SIZE) == 0) + cmd_flags |= MCPR_NVM_COMMAND_FIRST; + + memcpy(&val, data_buf, 4); + + rc = bnx2x_nvram_write_dword(bp, offset, val, cmd_flags); + + /* advance to the next dword */ + offset += sizeof(u32); + data_buf += sizeof(u32); + written_so_far += sizeof(u32); + cmd_flags = 0; + } + + /* disable access to nvram interface */ + bnx2x_disable_nvram_access(bp); + bnx2x_release_nvram_lock(bp); + + return rc; +} + +static int bnx2x_set_eeprom(struct net_device *dev, + struct ethtool_eeprom *eeprom, u8 *eebuf) +{ + struct bnx2x *bp = netdev_priv(dev); + int rc; + + DP(BNX2X_MSG_NVM, "ethtool_eeprom: cmd %d\n" + DP_LEVEL " magic 0x%x offset 0x%x (%d) len 0x%x (%d)\n", + eeprom->cmd, eeprom->magic, eeprom->offset, eeprom->offset, + eeprom->len, eeprom->len); + + /* parameters already validated in ethtool_set_eeprom */ + + /* If the magic number is PHY (0x00504859) upgrade the PHY FW */ + if (eeprom->magic == 0x00504859) + if (bp->port.pmf) { + + bnx2x_phy_hw_lock(bp); + rc = bnx2x_flash_download(bp, BP_PORT(bp), + bp->link_params.ext_phy_config, + (bp->state != BNX2X_STATE_CLOSED), + eebuf, eeprom->len); + if ((bp->state == BNX2X_STATE_OPEN) || + (bp->state == BNX2X_STATE_DISABLED)) { + rc |= bnx2x_link_reset(&bp->link_params, + &bp->link_vars); + rc |= bnx2x_phy_init(&bp->link_params, + &bp->link_vars); + } + bnx2x_phy_hw_unlock(bp); + + } else /* Only the PMF can access the PHY */ + return -EINVAL; + else + rc = bnx2x_nvram_write(bp, eeprom->offset, eebuf, eeprom->len); + + return rc; +} + +static int bnx2x_get_coalesce(struct net_device *dev, + struct ethtool_coalesce *coal) +{ + struct bnx2x *bp = netdev_priv(dev); + + memset(coal, 0, sizeof(struct ethtool_coalesce)); + + coal->rx_coalesce_usecs = bp->rx_ticks; + coal->tx_coalesce_usecs = bp->tx_ticks; + coal->stats_block_coalesce_usecs = bp->stats_ticks; + + return 0; +} + +static int bnx2x_set_coalesce(struct net_device *dev, + struct ethtool_coalesce *coal) +{ + struct bnx2x *bp = netdev_priv(dev); + + bp->rx_ticks = (u16) coal->rx_coalesce_usecs; + if (bp->rx_ticks > 3000) + bp->rx_ticks = 3000; + + bp->tx_ticks = (u16) coal->tx_coalesce_usecs; + if (bp->tx_ticks > 0x3000) + bp->tx_ticks = 0x3000; + + bp->stats_ticks = coal->stats_block_coalesce_usecs; + if (bp->stats_ticks > 0xffff00) + bp->stats_ticks = 0xffff00; + bp->stats_ticks &= 0xffff00; + + if (netif_running(dev)) + bnx2x_update_coalesce(bp); + + return 0; +} + +static int bnx2x_set_flags(struct net_device *dev, u32 data) +{ + struct bnx2x *bp = netdev_priv(dev); + int changed = 0; + int rc = 0; + + if (data & ETH_FLAG_LRO) { + if (!(dev->features & NETIF_F_LRO)) { + dev->features |= NETIF_F_LRO; + bp->flags |= TPA_ENABLE_FLAG; + changed = 1; + } + + } else if (dev->features & NETIF_F_LRO) { + dev->features &= ~NETIF_F_LRO; + bp->flags &= ~TPA_ENABLE_FLAG; + changed = 1; + } + + if (changed && netif_running(dev)) { + bnx2x_nic_unload(bp, UNLOAD_NORMAL); + rc = bnx2x_nic_load(bp, LOAD_NORMAL); + } + + return rc; +} + +static void bnx2x_get_ringparam(struct net_device *dev, + struct ethtool_ringparam *ering) +{ + struct bnx2x *bp = netdev_priv(dev); + + ering->rx_max_pending = MAX_RX_AVAIL; + ering->rx_mini_max_pending = 0; + ering->rx_jumbo_max_pending = 0; + + ering->rx_pending = bp->rx_ring_size; + ering->rx_mini_pending = 0; + ering->rx_jumbo_pending = 0; + + ering->tx_max_pending = MAX_TX_AVAIL; + ering->tx_pending = bp->tx_ring_size; +} + +static int bnx2x_set_ringparam(struct net_device *dev, + struct ethtool_ringparam *ering) +{ + struct bnx2x *bp = netdev_priv(dev); + int rc = 0; + + if ((ering->rx_pending > MAX_RX_AVAIL) || + (ering->tx_pending > MAX_TX_AVAIL) || + (ering->tx_pending <= MAX_SKB_FRAGS + 4)) + return -EINVAL; + + bp->rx_ring_size = ering->rx_pending; + bp->tx_ring_size = ering->tx_pending; + + if (netif_running(dev)) { + bnx2x_nic_unload(bp, UNLOAD_NORMAL); + rc = bnx2x_nic_load(bp, LOAD_NORMAL); + } + + return rc; +} + +static void bnx2x_get_pauseparam(struct net_device *dev, + struct ethtool_pauseparam *epause) +{ + struct bnx2x *bp = netdev_priv(dev); + + epause->autoneg = (bp->link_params.req_flow_ctrl == FLOW_CTRL_AUTO) && + (bp->link_params.req_line_speed == SPEED_AUTO_NEG); + + epause->rx_pause = ((bp->link_vars.flow_ctrl & FLOW_CTRL_RX) == + FLOW_CTRL_RX); + epause->tx_pause = ((bp->link_vars.flow_ctrl & FLOW_CTRL_TX) == + FLOW_CTRL_TX); + + DP(NETIF_MSG_LINK, "ethtool_pauseparam: cmd %d\n" + DP_LEVEL " autoneg %d rx_pause %d tx_pause %d\n", + epause->cmd, epause->autoneg, epause->rx_pause, epause->tx_pause); +} + +static int bnx2x_set_pauseparam(struct net_device *dev, + struct ethtool_pauseparam *epause) +{ + struct bnx2x *bp = netdev_priv(dev); + + if (IS_E1HMF(bp)) + return 0; + + DP(NETIF_MSG_LINK, "ethtool_pauseparam: cmd %d\n" + DP_LEVEL " autoneg %d rx_pause %d tx_pause %d\n", + epause->cmd, epause->autoneg, epause->rx_pause, epause->tx_pause); + + bp->link_params.req_flow_ctrl = FLOW_CTRL_AUTO; + + if (epause->rx_pause) + bp->link_params.req_flow_ctrl |= FLOW_CTRL_RX; + + if (epause->tx_pause) + bp->link_params.req_flow_ctrl |= FLOW_CTRL_TX; + + if (bp->link_params.req_flow_ctrl == FLOW_CTRL_AUTO) + bp->link_params.req_flow_ctrl = FLOW_CTRL_NONE; + + if (epause->autoneg) { + if (!(bp->port.supported & SUPPORTED_Autoneg)) { + DP(NETIF_MSG_LINK, "Autoneg not supported\n"); + return -EINVAL; + } + + if (bp->link_params.req_line_speed == SPEED_AUTO_NEG) + bp->link_params.req_flow_ctrl = FLOW_CTRL_AUTO; + } + + DP(NETIF_MSG_LINK, + "req_flow_ctrl 0x%x\n", bp->link_params.req_flow_ctrl); + + if (netif_running(dev)) { + bnx2x_stats_handle(bp, STATS_EVENT_STOP); + bnx2x_link_set(bp); + } + + return 0; +} + +static u32 bnx2x_get_rx_csum(struct net_device *dev) +{ + struct bnx2x *bp = netdev_priv(dev); + + return bp->rx_csum; +} + +static int bnx2x_set_rx_csum(struct net_device *dev, u32 data) +{ + struct bnx2x *bp = netdev_priv(dev); + + bp->rx_csum = data; + return 0; +} + +static int bnx2x_set_tso(struct net_device *dev, u32 data) +{ + if (data) { + dev->features |= (NETIF_F_TSO | NETIF_F_TSO_ECN); + dev->features |= NETIF_F_TSO6; + } else { + dev->features &= ~(NETIF_F_TSO | NETIF_F_TSO_ECN); + dev->features &= ~NETIF_F_TSO6; + } + + return 0; +} + +static const struct { + char string[ETH_GSTRING_LEN]; +} bnx2x_tests_str_arr[BNX2X_NUM_TESTS] = { + { "register_test (offline)" }, + { "memory_test (offline)" }, + { "loopback_test (offline)" }, + { "nvram_test (online)" }, + { "interrupt_test (online)" }, + { "link_test (online)" }, + { "idle check (online)" }, + { "MC errors (online)" } +}; + +static int bnx2x_self_test_count(struct net_device *dev) +{ + return BNX2X_NUM_TESTS; +} + +static int bnx2x_test_registers(struct bnx2x *bp) +{ + int idx, i, rc = -ENODEV; + u32 wr_val = 0; + static const struct { + u32 offset0; + u32 offset1; + u32 mask; + } reg_tbl[] = { +/* 0 */ { BRB1_REG_PAUSE_LOW_THRESHOLD_0, 4, 0x000003ff }, + { DORQ_REG_DB_ADDR0, 4, 0xffffffff }, + { HC_REG_AGG_INT_0, 4, 0x000003ff }, + { PBF_REG_MAC_IF0_ENABLE, 4, 0x00000001 }, + { PBF_REG_P0_INIT_CRD, 4, 0x000007ff }, + { PRS_REG_CID_PORT_0, 4, 0x00ffffff }, + { PXP2_REG_PSWRQ_CDU0_L2P, 4, 0x000fffff }, + { PXP2_REG_RQ_CDU0_EFIRST_MEM_ADDR, 8, 0x0003ffff }, + { PXP2_REG_PSWRQ_TM0_L2P, 4, 0x000fffff }, + { PXP2_REG_RQ_USDM0_EFIRST_MEM_ADDR, 8, 0x0003ffff }, +/* 10 */ { PXP2_REG_PSWRQ_TSDM0_L2P, 4, 0x000fffff }, + { QM_REG_CONNNUM_0, 4, 0x000fffff }, + { TM_REG_LIN0_MAX_ACTIVE_CID, 4, 0x0003ffff }, + { SRC_REG_KEYRSS0_0, 40, 0xffffffff }, + { SRC_REG_KEYRSS0_7, 40, 0xffffffff }, + { XCM_REG_WU_DA_SET_TMR_CNT_FLG_CMD00, 4, 0x00000001 }, + { XCM_REG_WU_DA_CNT_CMD00, 4, 0x00000003 }, + { XCM_REG_GLB_DEL_ACK_MAX_CNT_0, 4, 0x000000ff }, + { NIG_REG_EGRESS_MNG0_FIFO, 20, 0xffffffff }, + { NIG_REG_LLH0_T_BIT, 4, 0x00000001 }, +/* 20 */ { NIG_REG_EMAC0_IN_EN, 4, 0x00000001 }, + { NIG_REG_BMAC0_IN_EN, 4, 0x00000001 }, + { NIG_REG_XCM0_OUT_EN, 4, 0x00000001 }, + { NIG_REG_BRB0_OUT_EN, 4, 0x00000001 }, + { NIG_REG_LLH0_XCM_MASK, 4, 0x00000007 }, + { NIG_REG_LLH0_ACPI_PAT_6_LEN, 68, 0x000000ff }, + { NIG_REG_LLH0_ACPI_PAT_0_CRC, 68, 0xffffffff }, + { NIG_REG_LLH0_DEST_MAC_0_0, 160, 0xffffffff }, + { NIG_REG_LLH0_DEST_IP_0_1, 160, 0xffffffff }, + { NIG_REG_LLH0_IPV4_IPV6_0, 160, 0x00000001 }, +/* 30 */ { NIG_REG_LLH0_DEST_UDP_0, 160, 0x0000ffff }, + { NIG_REG_LLH0_DEST_TCP_0, 160, 0x0000ffff }, + { NIG_REG_LLH0_VLAN_ID_0, 160, 0x00000fff }, + { NIG_REG_XGXS_SERDES0_MODE_SEL, 4, 0x00000001 }, + { NIG_REG_LED_CONTROL_OVERRIDE_TRAFFIC_P0, 4, 0x00000001 }, + { NIG_REG_STATUS_INTERRUPT_PORT0, 4, 0x07ffffff }, + { NIG_REG_XGXS0_CTRL_EXTREMOTEMDIOST, 24, 0x00000001 }, + { NIG_REG_SERDES0_CTRL_PHY_ADDR, 16, 0x0000001f }, + + { 0xffffffff, 0, 0x00000000 } + }; + + if (!netif_running(bp->dev)) + return rc; + + /* Repeat the test twice: + First by writing 0x00000000, second by writing 0xffffffff */ + for (idx = 0; idx < 2; idx++) { + + switch (idx) { + case 0: + wr_val = 0; + break; + case 1: + wr_val = 0xffffffff; + break; + } + + for (i = 0; reg_tbl[i].offset0 != 0xffffffff; i++) { + u32 offset, mask, save_val, val; + int port = BP_PORT(bp); + + offset = reg_tbl[i].offset0 + port*reg_tbl[i].offset1; + mask = reg_tbl[i].mask; + + save_val = REG_RD(bp, offset); + + REG_WR(bp, offset, wr_val); + val = REG_RD(bp, offset); + + /* Restore the original register's value */ + REG_WR(bp, offset, save_val); + + /* verify that value is as expected value */ + if ((val & mask) != (wr_val & mask)) + goto test_reg_exit; + } + } + + rc = 0; + +test_reg_exit: + return rc; +} + +static int bnx2x_test_memory(struct bnx2x *bp) +{ + int i, j, rc = -ENODEV; + u32 val; + static const struct { + u32 offset; + int size; + } mem_tbl[] = { + { CCM_REG_XX_DESCR_TABLE, CCM_REG_XX_DESCR_TABLE_SIZE }, + { CFC_REG_ACTIVITY_COUNTER, CFC_REG_ACTIVITY_COUNTER_SIZE }, + { CFC_REG_LINK_LIST, CFC_REG_LINK_LIST_SIZE }, + { DMAE_REG_CMD_MEM, DMAE_REG_CMD_MEM_SIZE }, + { TCM_REG_XX_DESCR_TABLE, TCM_REG_XX_DESCR_TABLE_SIZE }, + { UCM_REG_XX_DESCR_TABLE, UCM_REG_XX_DESCR_TABLE_SIZE }, + { XCM_REG_XX_DESCR_TABLE, XCM_REG_XX_DESCR_TABLE_SIZE }, + + { 0xffffffff, 0 } + }; + static const struct { + char *name; + u32 offset; + u32 mask; + } prty_tbl[] = { + { "CCM_REG_CCM_PRTY_STS", CCM_REG_CCM_PRTY_STS, 0 }, + { "CFC_REG_CFC_PRTY_STS", CFC_REG_CFC_PRTY_STS, 0 }, + { "DMAE_REG_DMAE_PRTY_STS", DMAE_REG_DMAE_PRTY_STS, 0 }, + { "TCM_REG_TCM_PRTY_STS", TCM_REG_TCM_PRTY_STS, 0 }, + { "UCM_REG_UCM_PRTY_STS", UCM_REG_UCM_PRTY_STS, 0 }, + { "XCM_REG_XCM_PRTY_STS", XCM_REG_XCM_PRTY_STS, 0x1 }, + + { NULL, 0xffffffff, 0 } + }; + + if (!netif_running(bp->dev)) + return rc; + + /* Go through all the memories */ + for (i = 0; mem_tbl[i].offset != 0xffffffff; i++) + for (j = 0; j < mem_tbl[i].size; j++) + REG_RD(bp, mem_tbl[i].offset + j*4); + + /* Check the parity status */ + for (i = 0; prty_tbl[i].offset != 0xffffffff; i++) { + val = REG_RD(bp, prty_tbl[i].offset); + if (val & ~(prty_tbl[i].mask)) { + DP(NETIF_MSG_HW, + "%s is 0x%x\n", prty_tbl[i].name, val); + goto test_mem_exit; + } + } + + rc = 0; + +test_mem_exit: + return rc; +} + +static void bnx2x_netif_start(struct bnx2x *bp) +{ + int i; + + if (atomic_dec_and_test(&bp->intr_sem)) { + if (netif_running(bp->dev)) { + bnx2x_int_enable(bp); + for_each_queue(bp, i) + napi_enable(&bnx2x_fp(bp, i, napi)); + if (bp->state == BNX2X_STATE_OPEN) + netif_wake_queue(bp->dev); + } + } +} + +static void bnx2x_netif_stop(struct bnx2x *bp) +{ + int i; + + if (netif_running(bp->dev)) { + netif_tx_disable(bp->dev); + bp->dev->trans_start = jiffies; /* prevent tx timeout */ + for_each_queue(bp, i) + napi_disable(&bnx2x_fp(bp, i, napi)); + } + bnx2x_int_disable_sync(bp); +} + +static void bnx2x_wait_for_link(struct bnx2x *bp, u8 link_up) +{ + int cnt = 1000; + + if (link_up) + while (bnx2x_link_test(bp) && cnt--) + msleep(10); +} + +static int bnx2x_run_loopback(struct bnx2x *bp, int loopback_mode, u8 link_up) +{ + unsigned int pkt_size, num_pkts, i; + struct sk_buff *skb; + unsigned char *packet; + struct bnx2x_fastpath *fp = &bp->fp[0]; + u16 tx_start_idx, tx_idx; + u16 rx_start_idx, rx_idx; + u16 pkt_prod; + struct sw_tx_bd *tx_buf; + struct eth_tx_bd *tx_bd; + dma_addr_t mapping; + union eth_rx_cqe *cqe; + u8 cqe_fp_flags; + struct sw_rx_bd *rx_buf; + u16 len; + int rc = -ENODEV; + + if (loopback_mode == BNX2X_MAC_LOOPBACK) { + bp->link_params.loopback_mode = LOOPBACK_BMAC; + bnx2x_phy_hw_lock(bp); + bnx2x_phy_init(&bp->link_params, &bp->link_vars); + bnx2x_phy_hw_unlock(bp); + + } else if (loopback_mode == BNX2X_PHY_LOOPBACK) { + bp->link_params.loopback_mode = LOOPBACK_XGXS_10; + bnx2x_phy_hw_lock(bp); + bnx2x_phy_init(&bp->link_params, &bp->link_vars); + bnx2x_phy_hw_unlock(bp); + /* wait until link state is restored */ + bnx2x_wait_for_link(bp, link_up); + + } else + return -EINVAL; + + pkt_size = 1514; + skb = netdev_alloc_skb(bp->dev, bp->rx_buf_size); + if (!skb) { + rc = -ENOMEM; + goto test_loopback_exit; + } + packet = skb_put(skb, pkt_size); + memcpy(packet, bp->dev->dev_addr, ETH_ALEN); + memset(packet + ETH_ALEN, 0, (ETH_HLEN - ETH_ALEN)); + for (i = ETH_HLEN; i < pkt_size; i++) + packet[i] = (unsigned char) (i & 0xff); + + num_pkts = 0; + tx_start_idx = le16_to_cpu(*fp->tx_cons_sb); + rx_start_idx = le16_to_cpu(*fp->rx_cons_sb); + + pkt_prod = fp->tx_pkt_prod++; + tx_buf = &fp->tx_buf_ring[TX_BD(pkt_prod)]; + tx_buf->first_bd = fp->tx_bd_prod; + tx_buf->skb = skb; + + tx_bd = &fp->tx_desc_ring[TX_BD(fp->tx_bd_prod)]; + mapping = pci_map_single(bp->pdev, skb->data, + skb_headlen(skb), PCI_DMA_TODEVICE); + tx_bd->addr_hi = cpu_to_le32(U64_HI(mapping)); + tx_bd->addr_lo = cpu_to_le32(U64_LO(mapping)); + tx_bd->nbd = cpu_to_le16(1); + tx_bd->nbytes = cpu_to_le16(skb_headlen(skb)); + tx_bd->vlan = cpu_to_le16(pkt_prod); + tx_bd->bd_flags.as_bitfield = (ETH_TX_BD_FLAGS_START_BD | + ETH_TX_BD_FLAGS_END_BD); + tx_bd->general_data = ((UNICAST_ADDRESS << + ETH_TX_BD_ETH_ADDR_TYPE_SHIFT) | 1); + + fp->hw_tx_prods->bds_prod = + cpu_to_le16(le16_to_cpu(fp->hw_tx_prods->bds_prod) + 1); + mb(); /* FW restriction: must not reorder writing nbd and packets */ + fp->hw_tx_prods->packets_prod = + cpu_to_le32(le32_to_cpu(fp->hw_tx_prods->packets_prod) + 1); + DOORBELL(bp, FP_IDX(fp), 0); + + mmiowb(); + + num_pkts++; + fp->tx_bd_prod++; + bp->dev->trans_start = jiffies; + + udelay(100); + + tx_idx = le16_to_cpu(*fp->tx_cons_sb); + if (tx_idx != tx_start_idx + num_pkts) + goto test_loopback_exit; + + rx_idx = le16_to_cpu(*fp->rx_cons_sb); + if (rx_idx != rx_start_idx + num_pkts) + goto test_loopback_exit; + + cqe = &fp->rx_comp_ring[RCQ_BD(fp->rx_comp_cons)]; + cqe_fp_flags = cqe->fast_path_cqe.type_error_flags; + if (CQE_TYPE(cqe_fp_flags) || (cqe_fp_flags & ETH_RX_ERROR_FALGS)) + goto test_loopback_rx_exit; + + len = le16_to_cpu(cqe->fast_path_cqe.pkt_len); + if (len != pkt_size) + goto test_loopback_rx_exit; + + rx_buf = &fp->rx_buf_ring[RX_BD(fp->rx_bd_cons)]; + skb = rx_buf->skb; + skb_reserve(skb, cqe->fast_path_cqe.placement_offset); + for (i = ETH_HLEN; i < pkt_size; i++) + if (*(skb->data + i) != (unsigned char) (i & 0xff)) + goto test_loopback_rx_exit; + + rc = 0; + +test_loopback_rx_exit: + bp->dev->last_rx = jiffies; + + fp->rx_bd_cons = NEXT_RX_IDX(fp->rx_bd_cons); + fp->rx_bd_prod = NEXT_RX_IDX(fp->rx_bd_prod); + fp->rx_comp_cons = NEXT_RCQ_IDX(fp->rx_comp_cons); + fp->rx_comp_prod = NEXT_RCQ_IDX(fp->rx_comp_prod); + + /* Update producers */ + bnx2x_update_rx_prod(bp, fp, fp->rx_bd_prod, fp->rx_comp_prod, + fp->rx_sge_prod); + mmiowb(); /* keep prod updates ordered */ + +test_loopback_exit: + bp->link_params.loopback_mode = LOOPBACK_NONE; + + return rc; +} + +static int bnx2x_test_loopback(struct bnx2x *bp, u8 link_up) +{ + int rc = 0; + + if (!netif_running(bp->dev)) + return BNX2X_LOOPBACK_FAILED; + + bnx2x_netif_stop(bp); + + if (bnx2x_run_loopback(bp, BNX2X_MAC_LOOPBACK, link_up)) { + DP(NETIF_MSG_PROBE, "MAC loopback failed\n"); + rc |= BNX2X_MAC_LOOPBACK_FAILED; + } + + if (bnx2x_run_loopback(bp, BNX2X_PHY_LOOPBACK, link_up)) { + DP(NETIF_MSG_PROBE, "PHY loopback failed\n"); + rc |= BNX2X_PHY_LOOPBACK_FAILED; + } + + bnx2x_netif_start(bp); + + return rc; +} + +#define CRC32_RESIDUAL 0xdebb20e3 + +static int bnx2x_test_nvram(struct bnx2x *bp) +{ + static const struct { + int offset; + int size; + } nvram_tbl[] = { + { 0, 0x14 }, /* bootstrap */ + { 0x14, 0xec }, /* dir */ + { 0x100, 0x350 }, /* manuf_info */ + { 0x450, 0xf0 }, /* feature_info */ + { 0x640, 0x64 }, /* upgrade_key_info */ + { 0x6a4, 0x64 }, + { 0x708, 0x70 }, /* manuf_key_info */ + { 0x778, 0x70 }, + { 0, 0 } + }; + u32 buf[0x350 / 4]; + u8 *data = (u8 *)buf; + int i, rc; + u32 magic, csum; + + rc = bnx2x_nvram_read(bp, 0, data, 4); + if (rc) { + DP(NETIF_MSG_PROBE, "magic value read (rc -%d)\n", -rc); + goto test_nvram_exit; + } + + magic = be32_to_cpu(buf[0]); + if (magic != 0x669955aa) { + DP(NETIF_MSG_PROBE, "magic value (0x%08x)\n", magic); + rc = -ENODEV; + goto test_nvram_exit; + } + + for (i = 0; nvram_tbl[i].size; i++) { + + rc = bnx2x_nvram_read(bp, nvram_tbl[i].offset, data, + nvram_tbl[i].size); + if (rc) { + DP(NETIF_MSG_PROBE, + "nvram_tbl[%d] read data (rc -%d)\n", i, -rc); + goto test_nvram_exit; + } + + csum = ether_crc_le(nvram_tbl[i].size, data); + if (csum != CRC32_RESIDUAL) { + DP(NETIF_MSG_PROBE, + "nvram_tbl[%d] csum value (0x%08x)\n", i, csum); + rc = -ENODEV; + goto test_nvram_exit; + } + } + +test_nvram_exit: + return rc; +} + +static int bnx2x_test_intr(struct bnx2x *bp) +{ + struct mac_configuration_cmd *config = bnx2x_sp(bp, mac_config); + int i, rc; + + if (!netif_running(bp->dev)) + return -ENODEV; + + config->hdr.length_6b = 0; + config->hdr.offset = 0; + config->hdr.client_id = BP_CL_ID(bp); + config->hdr.reserved1 = 0; + + rc = bnx2x_sp_post(bp, RAMROD_CMD_ID_ETH_SET_MAC, 0, + U64_HI(bnx2x_sp_mapping(bp, mac_config)), + U64_LO(bnx2x_sp_mapping(bp, mac_config)), 0); + if (rc == 0) { + bp->set_mac_pending++; + for (i = 0; i < 10; i++) { + if (!bp->set_mac_pending) + break; + msleep_interruptible(10); + } + if (i == 10) + rc = -ENODEV; + } + + return rc; +} + +static void bnx2x_self_test(struct net_device *dev, + struct ethtool_test *etest, u64 *buf) +{ + struct bnx2x *bp = netdev_priv(dev); + + memset(buf, 0, sizeof(u64) * BNX2X_NUM_TESTS); + + if (!netif_running(dev)) + return; + + /* offline tests are not suppoerted in MF mode */ + if (IS_E1HMF(bp)) + etest->flags &= ~ETH_TEST_FL_OFFLINE; + + if (etest->flags & ETH_TEST_FL_OFFLINE) { + u8 link_up; + + link_up = bp->link_vars.link_up; + bnx2x_nic_unload(bp, UNLOAD_NORMAL); + bnx2x_nic_load(bp, LOAD_DIAG); + /* wait until link state is restored */ + bnx2x_wait_for_link(bp, link_up); + + if (bnx2x_test_registers(bp) != 0) { + buf[0] = 1; + etest->flags |= ETH_TEST_FL_FAILED; + } + if (bnx2x_test_memory(bp) != 0) { + buf[1] = 1; + etest->flags |= ETH_TEST_FL_FAILED; + } + buf[2] = bnx2x_test_loopback(bp, link_up); + if (buf[2] != 0) + etest->flags |= ETH_TEST_FL_FAILED; + + bnx2x_nic_unload(bp, UNLOAD_NORMAL); + bnx2x_nic_load(bp, LOAD_NORMAL); + /* wait until link state is restored */ + bnx2x_wait_for_link(bp, link_up); + } + if (bnx2x_test_nvram(bp) != 0) { + buf[3] = 1; + etest->flags |= ETH_TEST_FL_FAILED; + } + if (bnx2x_test_intr(bp) != 0) { + buf[4] = 1; + etest->flags |= ETH_TEST_FL_FAILED; + } + if (bp->port.pmf) + if (bnx2x_link_test(bp) != 0) { + buf[5] = 1; + etest->flags |= ETH_TEST_FL_FAILED; + } + buf[7] = bnx2x_mc_assert(bp); + if (buf[7] != 0) + etest->flags |= ETH_TEST_FL_FAILED; + +#ifdef BNX2X_EXTRA_DEBUG + bnx2x_panic_dump(bp); +#endif +} + +static const struct { + long offset; + int size; + u32 flags; + char string[ETH_GSTRING_LEN]; +} bnx2x_stats_arr[BNX2X_NUM_STATS] = { +/* 1 */ { STATS_OFFSET32(valid_bytes_received_hi), 8, 1, "rx_bytes" }, + { STATS_OFFSET32(error_bytes_received_hi), 8, 1, "rx_error_bytes" }, + { STATS_OFFSET32(total_bytes_transmitted_hi), 8, 1, "tx_bytes" }, + { STATS_OFFSET32(tx_stat_ifhcoutbadoctets_hi), 8, 0, "tx_error_bytes" }, + { STATS_OFFSET32(total_unicast_packets_received_hi), + 8, 1, "rx_ucast_packets" }, + { STATS_OFFSET32(total_multicast_packets_received_hi), + 8, 1, "rx_mcast_packets" }, + { STATS_OFFSET32(total_broadcast_packets_received_hi), + 8, 1, "rx_bcast_packets" }, + { STATS_OFFSET32(total_unicast_packets_transmitted_hi), + 8, 1, "tx_packets" }, + { STATS_OFFSET32(tx_stat_dot3statsinternalmactransmiterrors_hi), + 8, 0, "tx_mac_errors" }, +/* 10 */{ STATS_OFFSET32(rx_stat_dot3statscarriersenseerrors_hi), + 8, 0, "tx_carrier_errors" }, + { STATS_OFFSET32(rx_stat_dot3statsfcserrors_hi), + 8, 0, "rx_crc_errors" }, + { STATS_OFFSET32(rx_stat_dot3statsalignmenterrors_hi), + 8, 0, "rx_align_errors" }, + { STATS_OFFSET32(tx_stat_dot3statssinglecollisionframes_hi), + 8, 0, "tx_single_collisions" }, + { STATS_OFFSET32(tx_stat_dot3statsmultiplecollisionframes_hi), + 8, 0, "tx_multi_collisions" }, + { STATS_OFFSET32(tx_stat_dot3statsdeferredtransmissions_hi), + 8, 0, "tx_deferred" }, + { STATS_OFFSET32(tx_stat_dot3statsexcessivecollisions_hi), + 8, 0, "tx_excess_collisions" }, + { STATS_OFFSET32(tx_stat_dot3statslatecollisions_hi), + 8, 0, "tx_late_collisions" }, + { STATS_OFFSET32(tx_stat_etherstatscollisions_hi), + 8, 0, "tx_total_collisions" }, + { STATS_OFFSET32(rx_stat_etherstatsfragments_hi), + 8, 0, "rx_fragments" }, +/* 20 */{ STATS_OFFSET32(rx_stat_etherstatsjabbers_hi), 8, 0, "rx_jabbers" }, + { STATS_OFFSET32(rx_stat_etherstatsundersizepkts_hi), + 8, 0, "rx_undersize_packets" }, + { STATS_OFFSET32(jabber_packets_received), + 4, 1, "rx_oversize_packets" }, + { STATS_OFFSET32(tx_stat_etherstatspkts64octets_hi), + 8, 0, "tx_64_byte_packets" }, + { STATS_OFFSET32(tx_stat_etherstatspkts65octetsto127octets_hi), + 8, 0, "tx_65_to_127_byte_packets" }, + { STATS_OFFSET32(tx_stat_etherstatspkts128octetsto255octets_hi), + 8, 0, "tx_128_to_255_byte_packets" }, + { STATS_OFFSET32(tx_stat_etherstatspkts256octetsto511octets_hi), + 8, 0, "tx_256_to_511_byte_packets" }, + { STATS_OFFSET32(tx_stat_etherstatspkts512octetsto1023octets_hi), + 8, 0, "tx_512_to_1023_byte_packets" }, + { STATS_OFFSET32(etherstatspkts1024octetsto1522octets_hi), + 8, 0, "tx_1024_to_1522_byte_packets" }, + { STATS_OFFSET32(etherstatspktsover1522octets_hi), + 8, 0, "tx_1523_to_9022_byte_packets" }, +/* 30 */{ STATS_OFFSET32(rx_stat_xonpauseframesreceived_hi), + 8, 0, "rx_xon_frames" }, + { STATS_OFFSET32(rx_stat_xoffpauseframesreceived_hi), + 8, 0, "rx_xoff_frames" }, + { STATS_OFFSET32(tx_stat_outxonsent_hi), 8, 0, "tx_xon_frames" }, + { STATS_OFFSET32(tx_stat_outxoffsent_hi), 8, 0, "tx_xoff_frames" }, + { STATS_OFFSET32(rx_stat_maccontrolframesreceived_hi), + 8, 0, "rx_mac_ctrl_frames" }, + { STATS_OFFSET32(mac_filter_discard), 4, 1, "rx_filtered_packets" }, + { STATS_OFFSET32(no_buff_discard), 4, 1, "rx_discards" }, + { STATS_OFFSET32(xxoverflow_discard), 4, 1, "rx_fw_discards" }, + { STATS_OFFSET32(brb_drop_hi), 8, 1, "brb_discard" }, +/* 39 */{ STATS_OFFSET32(brb_truncate_discard), 8, 1, "brb_truncate" } +}; + +static void bnx2x_get_strings(struct net_device *dev, u32 stringset, u8 *buf) +{ + struct bnx2x *bp = netdev_priv(dev); + int i, j; + + switch (stringset) { + case ETH_SS_STATS: + for (i = 0, j = 0; i < BNX2X_NUM_STATS; i++) { + if (IS_E1HMF(bp) && (!bnx2x_stats_arr[i].flags)) + continue; + strcpy(buf + j*ETH_GSTRING_LEN, + bnx2x_stats_arr[i].string); + j++; + } + break; + + case ETH_SS_TEST: + memcpy(buf, bnx2x_tests_str_arr, sizeof(bnx2x_tests_str_arr)); + break; + } +} + +static int bnx2x_get_stats_count(struct net_device *dev) +{ + struct bnx2x *bp = netdev_priv(dev); + int i, num_stats = 0; + + for (i = 0; i < BNX2X_NUM_STATS; i++) { + if (IS_E1HMF(bp) && (!bnx2x_stats_arr[i].flags)) + continue; + num_stats++; + } + return num_stats; +} + +static void bnx2x_get_ethtool_stats(struct net_device *dev, + struct ethtool_stats *stats, u64 *buf) +{ + struct bnx2x *bp = netdev_priv(dev); + u32 *hw_stats = (u32 *)&bp->eth_stats; + int i, j; + + for (i = 0, j = 0; i < BNX2X_NUM_STATS; i++) { + if (IS_E1HMF(bp) && (!bnx2x_stats_arr[i].flags)) + continue; + + if (bnx2x_stats_arr[i].size == 0) { + /* skip this counter */ + buf[j] = 0; + j++; + continue; + } + if (bnx2x_stats_arr[i].size == 4) { + /* 4-byte counter */ + buf[j] = (u64) *(hw_stats + bnx2x_stats_arr[i].offset); + j++; + continue; + } + /* 8-byte counter */ + buf[j] = HILO_U64(*(hw_stats + bnx2x_stats_arr[i].offset), + *(hw_stats + bnx2x_stats_arr[i].offset + 1)); + j++; + } +} + +static int bnx2x_phys_id(struct net_device *dev, u32 data) +{ + struct bnx2x *bp = netdev_priv(dev); + int port = BP_PORT(bp); + int i; + + if (!netif_running(dev)) + return 0; + + if (!bp->port.pmf) + return 0; + + if (data == 0) + data = 2; + + for (i = 0; i < (data * 2); i++) { + if ((i % 2) == 0) + bnx2x_set_led(bp, port, LED_MODE_OPER, SPEED_1000, + bp->link_params.hw_led_mode, + bp->link_params.chip_id); + else + bnx2x_set_led(bp, port, LED_MODE_OFF, 0, + bp->link_params.hw_led_mode, + bp->link_params.chip_id); + + msleep_interruptible(500); + if (signal_pending(current)) + break; + } + + if (bp->link_vars.link_up) + bnx2x_set_led(bp, port, LED_MODE_OPER, + bp->link_vars.line_speed, + bp->link_params.hw_led_mode, + bp->link_params.chip_id); + + return 0; +} + +static struct ethtool_ops bnx2x_ethtool_ops = { + .get_settings = bnx2x_get_settings, + .set_settings = bnx2x_set_settings, + .get_drvinfo = bnx2x_get_drvinfo, + .get_wol = bnx2x_get_wol, + .set_wol = bnx2x_set_wol, + .get_msglevel = bnx2x_get_msglevel, + .set_msglevel = bnx2x_set_msglevel, + .nway_reset = bnx2x_nway_reset, + .get_link = ethtool_op_get_link, + .get_eeprom_len = bnx2x_get_eeprom_len, + .get_eeprom = bnx2x_get_eeprom, + .set_eeprom = bnx2x_set_eeprom, + .get_coalesce = bnx2x_get_coalesce, + .set_coalesce = bnx2x_set_coalesce, + .get_ringparam = bnx2x_get_ringparam, + .set_ringparam = bnx2x_set_ringparam, + .get_pauseparam = bnx2x_get_pauseparam, + .set_pauseparam = bnx2x_set_pauseparam, + .get_rx_csum = bnx2x_get_rx_csum, + .set_rx_csum = bnx2x_set_rx_csum, + .get_tx_csum = ethtool_op_get_tx_csum, + .set_tx_csum = ethtool_op_set_tx_hw_csum, + .set_flags = bnx2x_set_flags, + .get_flags = ethtool_op_get_flags, + .get_sg = ethtool_op_get_sg, + .set_sg = ethtool_op_set_sg, + .get_tso = ethtool_op_get_tso, + .set_tso = bnx2x_set_tso, + .self_test_count = bnx2x_self_test_count, + .self_test = bnx2x_self_test, + .get_strings = bnx2x_get_strings, + .phys_id = bnx2x_phys_id, + .get_stats_count = bnx2x_get_stats_count, + .get_ethtool_stats = bnx2x_get_ethtool_stats, +}; + +/* end of ethtool_ops */ + +/**************************************************************************** +* General service functions +****************************************************************************/ + +static int bnx2x_set_power_state(struct bnx2x *bp, pci_power_t state) +{ + u16 pmcsr; + + pci_read_config_word(bp->pdev, bp->pm_cap + PCI_PM_CTRL, &pmcsr); + + switch (state) { + case PCI_D0: + pci_write_config_word(bp->pdev, bp->pm_cap + PCI_PM_CTRL, + ((pmcsr & ~PCI_PM_CTRL_STATE_MASK) | + PCI_PM_CTRL_PME_STATUS)); + + if (pmcsr & PCI_PM_CTRL_STATE_MASK) + /* delay required during transition out of D3hot */ + msleep(20); + break; + + case PCI_D3hot: + pmcsr &= ~PCI_PM_CTRL_STATE_MASK; + pmcsr |= 3; + + if (bp->wol) + pmcsr |= PCI_PM_CTRL_PME_ENABLE; + + pci_write_config_word(bp->pdev, bp->pm_cap + PCI_PM_CTRL, + pmcsr); + + /* No more memory access after this point until + * device is brought back to D0. + */ + break; + + default: + return -EINVAL; + } + return 0; +} + +/* + * net_device service functions + */ + +static int bnx2x_poll(struct napi_struct *napi, int budget) +{ + struct bnx2x_fastpath *fp = container_of(napi, struct bnx2x_fastpath, + napi); + struct bnx2x *bp = fp->bp; + int work_done = 0; + +#ifdef BNX2X_STOP_ON_ERROR + if (unlikely(bp->panic)) + goto poll_panic; +#endif + + prefetch(fp->tx_buf_ring[TX_BD(fp->tx_pkt_cons)].skb); + prefetch(fp->rx_buf_ring[RX_BD(fp->rx_bd_cons)].skb); + prefetch((char *)(fp->rx_buf_ring[RX_BD(fp->rx_bd_cons)].skb) + 256); + + bnx2x_update_fpsb_idx(fp); + + if ((fp->tx_pkt_prod != le16_to_cpu(*fp->tx_cons_sb)) || + (fp->tx_pkt_prod != fp->tx_pkt_cons)) + bnx2x_tx_int(fp, budget); + + if (le16_to_cpu(*fp->rx_cons_sb) != fp->rx_comp_cons) + work_done = bnx2x_rx_int(fp, budget); + + rmb(); /* bnx2x_has_work() reads the status block */ + + /* must not complete if we consumed full budget */ + if ((work_done < budget) && !bnx2x_has_work(fp)) { + +#ifdef BNX2X_STOP_ON_ERROR +poll_panic: +#endif + netif_rx_complete(bp->dev, napi); + + bnx2x_ack_sb(bp, FP_SB_ID(fp), USTORM_ID, + le16_to_cpu(fp->fp_u_idx), IGU_INT_NOP, 1); + bnx2x_ack_sb(bp, FP_SB_ID(fp), CSTORM_ID, + le16_to_cpu(fp->fp_c_idx), IGU_INT_ENABLE, 1); + } + return work_done; +} + + +/* we split the first BD into headers and data BDs + * to ease the pain of our fellow micocode engineers + * we use one mapping for both BDs + * So far this has only been observed to happen + * in Other Operating Systems(TM) + */ +static noinline u16 bnx2x_tx_split(struct bnx2x *bp, + struct bnx2x_fastpath *fp, + struct eth_tx_bd **tx_bd, u16 hlen, + u16 bd_prod, int nbd) +{ + struct eth_tx_bd *h_tx_bd = *tx_bd; + struct eth_tx_bd *d_tx_bd; + dma_addr_t mapping; + int old_len = le16_to_cpu(h_tx_bd->nbytes); + + /* first fix first BD */ + h_tx_bd->nbd = cpu_to_le16(nbd); + h_tx_bd->nbytes = cpu_to_le16(hlen); + + DP(NETIF_MSG_TX_QUEUED, "TSO split header size is %d " + "(%x:%x) nbd %d\n", h_tx_bd->nbytes, h_tx_bd->addr_hi, + h_tx_bd->addr_lo, h_tx_bd->nbd); + + /* now get a new data BD + * (after the pbd) and fill it */ + bd_prod = TX_BD(NEXT_TX_IDX(bd_prod)); + d_tx_bd = &fp->tx_desc_ring[bd_prod]; + + mapping = HILO_U64(le32_to_cpu(h_tx_bd->addr_hi), + le32_to_cpu(h_tx_bd->addr_lo)) + hlen; + + d_tx_bd->addr_hi = cpu_to_le32(U64_HI(mapping)); + d_tx_bd->addr_lo = cpu_to_le32(U64_LO(mapping)); + d_tx_bd->nbytes = cpu_to_le16(old_len - hlen); + d_tx_bd->vlan = 0; + /* this marks the BD as one that has no individual mapping + * the FW ignores this flag in a BD not marked start + */ + d_tx_bd->bd_flags.as_bitfield = ETH_TX_BD_FLAGS_SW_LSO; + DP(NETIF_MSG_TX_QUEUED, + "TSO split data size is %d (%x:%x)\n", + d_tx_bd->nbytes, d_tx_bd->addr_hi, d_tx_bd->addr_lo); + + /* update tx_bd for marking the last BD flag */ + *tx_bd = d_tx_bd; + + return bd_prod; +} + +static inline u16 bnx2x_csum_fix(unsigned char *t_header, u16 csum, s8 fix) +{ + if (fix > 0) + csum = (u16) ~csum_fold(csum_sub(csum, + csum_partial(t_header - fix, fix, 0))); + + else if (fix < 0) + csum = (u16) ~csum_fold(csum_add(csum, + csum_partial(t_header, -fix, 0))); + + return swab16(csum); +} + +static inline u32 bnx2x_xmit_type(struct bnx2x *bp, struct sk_buff *skb) +{ + u32 rc; + + if (skb->ip_summed != CHECKSUM_PARTIAL) + rc = XMIT_PLAIN; + + else { + if (skb->protocol == ntohs(ETH_P_IPV6)) { + rc = XMIT_CSUM_V6; + if (ipv6_hdr(skb)->nexthdr == IPPROTO_TCP) + rc |= XMIT_CSUM_TCP; + + } else { + rc = XMIT_CSUM_V4; + if (ip_hdr(skb)->protocol == IPPROTO_TCP) + rc |= XMIT_CSUM_TCP; + } + } + + if (skb_shinfo(skb)->gso_type & SKB_GSO_TCPV4) + rc |= XMIT_GSO_V4; + + else if (skb_shinfo(skb)->gso_type & SKB_GSO_TCPV6) + rc |= XMIT_GSO_V6; + + return rc; +} + +/* check if packet requires linearization (packet is too fragmented) */ +static int bnx2x_pkt_req_lin(struct bnx2x *bp, struct sk_buff *skb, + u32 xmit_type) +{ + int to_copy = 0; + int hlen = 0; + int first_bd_sz = 0; + + /* 3 = 1 (for linear data BD) + 2 (for PBD and last BD) */ + if (skb_shinfo(skb)->nr_frags >= (MAX_FETCH_BD - 3)) { + + if (xmit_type & XMIT_GSO) { + unsigned short lso_mss = skb_shinfo(skb)->gso_size; + /* Check if LSO packet needs to be copied: + 3 = 1 (for headers BD) + 2 (for PBD and last BD) */ + int wnd_size = MAX_FETCH_BD - 3; + /* Number of widnows to check */ + int num_wnds = skb_shinfo(skb)->nr_frags - wnd_size; + int wnd_idx = 0; + int frag_idx = 0; + u32 wnd_sum = 0; + + /* Headers length */ + hlen = (int)(skb_transport_header(skb) - skb->data) + + tcp_hdrlen(skb); + + /* Amount of data (w/o headers) on linear part of SKB*/ + first_bd_sz = skb_headlen(skb) - hlen; + + wnd_sum = first_bd_sz; + + /* Calculate the first sum - it's special */ + for (frag_idx = 0; frag_idx < wnd_size - 1; frag_idx++) + wnd_sum += + skb_shinfo(skb)->frags[frag_idx].size; + + /* If there was data on linear skb data - check it */ + if (first_bd_sz > 0) { + if (unlikely(wnd_sum < lso_mss)) { + to_copy = 1; + goto exit_lbl; + } + + wnd_sum -= first_bd_sz; + } + + /* Others are easier: run through the frag list and + check all windows */ + for (wnd_idx = 0; wnd_idx <= num_wnds; wnd_idx++) { + wnd_sum += + skb_shinfo(skb)->frags[wnd_idx + wnd_size - 1].size; + + if (unlikely(wnd_sum < lso_mss)) { + to_copy = 1; + break; + } + wnd_sum -= + skb_shinfo(skb)->frags[wnd_idx].size; + } + + } else { + /* in non-LSO too fragmented packet should always + be linearized */ + to_copy = 1; + } + } + +exit_lbl: + if (unlikely(to_copy)) + DP(NETIF_MSG_TX_QUEUED, + "Linearization IS REQUIRED for %s packet. " + "num_frags %d hlen %d first_bd_sz %d\n", + (xmit_type & XMIT_GSO) ? "LSO" : "non-LSO", + skb_shinfo(skb)->nr_frags, hlen, first_bd_sz); + + return to_copy; +} + +/* called with netif_tx_lock + * bnx2x_tx_int() runs without netif_tx_lock unless it needs to call + * netif_wake_queue() + */ +static int bnx2x_start_xmit(struct sk_buff *skb, struct net_device *dev) +{ + struct bnx2x *bp = netdev_priv(dev); + struct bnx2x_fastpath *fp; + struct sw_tx_bd *tx_buf; + struct eth_tx_bd *tx_bd; + struct eth_tx_parse_bd *pbd = NULL; + u16 pkt_prod, bd_prod; + int nbd, fp_index; + dma_addr_t mapping; + u32 xmit_type = bnx2x_xmit_type(bp, skb); + int vlan_off = (bp->e1hov ? 4 : 0); + int i; + u8 hlen = 0; + +#ifdef BNX2X_STOP_ON_ERROR + if (unlikely(bp->panic)) + return NETDEV_TX_BUSY; +#endif + + fp_index = (smp_processor_id() % bp->num_queues); + fp = &bp->fp[fp_index]; + + if (unlikely(bnx2x_tx_avail(bp->fp) < + (skb_shinfo(skb)->nr_frags + 3))) { + bp->eth_stats.driver_xoff++, + netif_stop_queue(dev); + BNX2X_ERR("BUG! Tx ring full when queue awake!\n"); + return NETDEV_TX_BUSY; + } + + DP(NETIF_MSG_TX_QUEUED, "SKB: summed %x protocol %x protocol(%x,%x)" + " gso type %x xmit_type %x\n", + skb->ip_summed, skb->protocol, ipv6_hdr(skb)->nexthdr, + ip_hdr(skb)->protocol, skb_shinfo(skb)->gso_type, xmit_type); + + /* First, check if we need to linearaize the skb + (due to FW restrictions) */ + if (bnx2x_pkt_req_lin(bp, skb, xmit_type)) { + /* Statistics of linearization */ + bp->lin_cnt++; + if (skb_linearize(skb) != 0) { + DP(NETIF_MSG_TX_QUEUED, "SKB linearization failed - " + "silently dropping this SKB\n"); + dev_kfree_skb_any(skb); + return 0; + } + } + + /* + Please read carefully. First we use one BD which we mark as start, + then for TSO or xsum we have a parsing info BD, + and only then we have the rest of the TSO BDs. + (don't forget to mark the last one as last, + and to unmap only AFTER you write to the BD ...) + And above all, all pdb sizes are in words - NOT DWORDS! + */ + + pkt_prod = fp->tx_pkt_prod++; + bd_prod = TX_BD(fp->tx_bd_prod); + + /* get a tx_buf and first BD */ + tx_buf = &fp->tx_buf_ring[TX_BD(pkt_prod)]; + tx_bd = &fp->tx_desc_ring[bd_prod]; + + tx_bd->bd_flags.as_bitfield = ETH_TX_BD_FLAGS_START_BD; + tx_bd->general_data = (UNICAST_ADDRESS << + ETH_TX_BD_ETH_ADDR_TYPE_SHIFT); + tx_bd->general_data |= 1; /* header nbd */ + + /* remember the first BD of the packet */ + tx_buf->first_bd = fp->tx_bd_prod; + tx_buf->skb = skb; + + DP(NETIF_MSG_TX_QUEUED, + "sending pkt %u @%p next_idx %u bd %u @%p\n", + pkt_prod, tx_buf, fp->tx_pkt_prod, bd_prod, tx_bd); + + if ((bp->vlgrp != NULL) && vlan_tx_tag_present(skb)) { + tx_bd->vlan = cpu_to_le16(vlan_tx_tag_get(skb)); + tx_bd->bd_flags.as_bitfield |= ETH_TX_BD_FLAGS_VLAN_TAG; + vlan_off += 4; + } else + tx_bd->vlan = cpu_to_le16(pkt_prod); + + if (xmit_type) { + + /* turn on parsing and get a BD */ + bd_prod = TX_BD(NEXT_TX_IDX(bd_prod)); + pbd = (void *)&fp->tx_desc_ring[bd_prod]; + + memset(pbd, 0, sizeof(struct eth_tx_parse_bd)); + } + + if (xmit_type & XMIT_CSUM) { + hlen = (skb_network_header(skb) - skb->data + vlan_off) / 2; + + /* for now NS flag is not used in Linux */ + pbd->global_data = (hlen | + ((skb->protocol == ntohs(ETH_P_8021Q)) << + ETH_TX_PARSE_BD_LLC_SNAP_EN_SHIFT)); + + pbd->ip_hlen = (skb_transport_header(skb) - + skb_network_header(skb)) / 2; + + hlen += pbd->ip_hlen + tcp_hdrlen(skb) / 2; + + pbd->total_hlen = cpu_to_le16(hlen); + hlen = hlen*2 - vlan_off; + + tx_bd->bd_flags.as_bitfield |= ETH_TX_BD_FLAGS_TCP_CSUM; + + if (xmit_type & XMIT_CSUM_V4) + tx_bd->bd_flags.as_bitfield |= + ETH_TX_BD_FLAGS_IP_CSUM; + else + tx_bd->bd_flags.as_bitfield |= ETH_TX_BD_FLAGS_IPV6; + + if (xmit_type & XMIT_CSUM_TCP) { + pbd->tcp_pseudo_csum = swab16(tcp_hdr(skb)->check); + + } else { + s8 fix = SKB_CS_OFF(skb); /* signed! */ + + pbd->global_data |= ETH_TX_PARSE_BD_CS_ANY_FLG; + pbd->cs_offset = fix / 2; + + DP(NETIF_MSG_TX_QUEUED, + "hlen %d offset %d fix %d csum before fix %x\n", + le16_to_cpu(pbd->total_hlen), pbd->cs_offset, fix, + SKB_CS(skb)); + + /* HW bug: fixup the CSUM */ + pbd->tcp_pseudo_csum = + bnx2x_csum_fix(skb_transport_header(skb), + SKB_CS(skb), fix); + + DP(NETIF_MSG_TX_QUEUED, "csum after fix %x\n", + pbd->tcp_pseudo_csum); + } + } + + mapping = pci_map_single(bp->pdev, skb->data, + skb_headlen(skb), PCI_DMA_TODEVICE); + + tx_bd->addr_hi = cpu_to_le32(U64_HI(mapping)); + tx_bd->addr_lo = cpu_to_le32(U64_LO(mapping)); + nbd = skb_shinfo(skb)->nr_frags + ((pbd == NULL)? 1 : 2); + tx_bd->nbd = cpu_to_le16(nbd); + tx_bd->nbytes = cpu_to_le16(skb_headlen(skb)); + + DP(NETIF_MSG_TX_QUEUED, "first bd @%p addr (%x:%x) nbd %d" + " nbytes %d flags %x vlan %x\n", + tx_bd, tx_bd->addr_hi, tx_bd->addr_lo, le16_to_cpu(tx_bd->nbd), + le16_to_cpu(tx_bd->nbytes), tx_bd->bd_flags.as_bitfield, + le16_to_cpu(tx_bd->vlan)); + + if (xmit_type & XMIT_GSO) { + + DP(NETIF_MSG_TX_QUEUED, + "TSO packet len %d hlen %d total len %d tso size %d\n", + skb->len, hlen, skb_headlen(skb), + skb_shinfo(skb)->gso_size); + + tx_bd->bd_flags.as_bitfield |= ETH_TX_BD_FLAGS_SW_LSO; + + if (unlikely(skb_headlen(skb) > hlen)) + bd_prod = bnx2x_tx_split(bp, fp, &tx_bd, hlen, + bd_prod, ++nbd); + + pbd->lso_mss = cpu_to_le16(skb_shinfo(skb)->gso_size); + pbd->tcp_send_seq = swab32(tcp_hdr(skb)->seq); + pbd->tcp_flags = pbd_tcp_flags(skb); + + if (xmit_type & XMIT_GSO_V4) { + pbd->ip_id = swab16(ip_hdr(skb)->id); + pbd->tcp_pseudo_csum = + swab16(~csum_tcpudp_magic(ip_hdr(skb)->saddr, + ip_hdr(skb)->daddr, + 0, IPPROTO_TCP, 0)); + + } else + pbd->tcp_pseudo_csum = + swab16(~csum_ipv6_magic(&ipv6_hdr(skb)->saddr, + &ipv6_hdr(skb)->daddr, + 0, IPPROTO_TCP, 0)); + + pbd->global_data |= ETH_TX_PARSE_BD_PSEUDO_CS_WITHOUT_LEN; + } + + for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { + skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; + + bd_prod = TX_BD(NEXT_TX_IDX(bd_prod)); + tx_bd = &fp->tx_desc_ring[bd_prod]; + + mapping = pci_map_page(bp->pdev, frag->page, frag->page_offset, + frag->size, PCI_DMA_TODEVICE); + + tx_bd->addr_hi = cpu_to_le32(U64_HI(mapping)); + tx_bd->addr_lo = cpu_to_le32(U64_LO(mapping)); + tx_bd->nbytes = cpu_to_le16(frag->size); + tx_bd->vlan = cpu_to_le16(pkt_prod); + tx_bd->bd_flags.as_bitfield = 0; + + DP(NETIF_MSG_TX_QUEUED, + "frag %d bd @%p addr (%x:%x) nbytes %d flags %x\n", + i, tx_bd, tx_bd->addr_hi, tx_bd->addr_lo, + le16_to_cpu(tx_bd->nbytes), tx_bd->bd_flags.as_bitfield); + } + + /* now at last mark the BD as the last BD */ + tx_bd->bd_flags.as_bitfield |= ETH_TX_BD_FLAGS_END_BD; + + DP(NETIF_MSG_TX_QUEUED, "last bd @%p flags %x\n", + tx_bd, tx_bd->bd_flags.as_bitfield); + + bd_prod = TX_BD(NEXT_TX_IDX(bd_prod)); + + /* now send a tx doorbell, counting the next BD + * if the packet contains or ends with it + */ + if (TX_BD_POFF(bd_prod) < nbd) + nbd++; + + if (pbd) + DP(NETIF_MSG_TX_QUEUED, + "PBD @%p ip_data %x ip_hlen %u ip_id %u lso_mss %u" + " tcp_flags %x xsum %x seq %u hlen %u\n", + pbd, pbd->global_data, pbd->ip_hlen, pbd->ip_id, + pbd->lso_mss, pbd->tcp_flags, pbd->tcp_pseudo_csum, + pbd->tcp_send_seq, le16_to_cpu(pbd->total_hlen)); + + DP(NETIF_MSG_TX_QUEUED, "doorbell: nbd %d bd %u\n", nbd, bd_prod); + + fp->hw_tx_prods->bds_prod = + cpu_to_le16(le16_to_cpu(fp->hw_tx_prods->bds_prod) + nbd); + mb(); /* FW restriction: must not reorder writing nbd and packets */ + fp->hw_tx_prods->packets_prod = + cpu_to_le32(le32_to_cpu(fp->hw_tx_prods->packets_prod) + 1); + DOORBELL(bp, FP_IDX(fp), 0); + + mmiowb(); + + fp->tx_bd_prod += nbd; + dev->trans_start = jiffies; + + if (unlikely(bnx2x_tx_avail(fp) < MAX_SKB_FRAGS + 3)) { + netif_stop_queue(dev); + bp->eth_stats.driver_xoff++; + if (bnx2x_tx_avail(fp) >= MAX_SKB_FRAGS + 3) + netif_wake_queue(dev); + } + fp->tx_pkt++; + + return NETDEV_TX_OK; +} + +/* called with rtnl_lock */ +static int bnx2x_open(struct net_device *dev) +{ + struct bnx2x *bp = netdev_priv(dev); + + bnx2x_set_power_state(bp, PCI_D0); + + return bnx2x_nic_load(bp, LOAD_OPEN); +} + +/* called with rtnl_lock */ +static int bnx2x_close(struct net_device *dev) +{ + struct bnx2x *bp = netdev_priv(dev); + + /* Unload the driver, release IRQs */ + bnx2x_nic_unload(bp, UNLOAD_CLOSE); + if (atomic_read(&bp->pdev->enable_cnt) == 1) + if (!CHIP_REV_IS_SLOW(bp)) + bnx2x_set_power_state(bp, PCI_D3hot); + + return 0; +} + +/* called with netif_tx_lock from set_multicast */ +static void bnx2x_set_rx_mode(struct net_device *dev) +{ + struct bnx2x *bp = netdev_priv(dev); + u32 rx_mode = BNX2X_RX_MODE_NORMAL; + int port = BP_PORT(bp); + + if (bp->state != BNX2X_STATE_OPEN) { + DP(NETIF_MSG_IFUP, "state is %x, returning\n", bp->state); + return; + } + + DP(NETIF_MSG_IFUP, "dev->flags = %x\n", dev->flags); + + if (dev->flags & IFF_PROMISC) + rx_mode = BNX2X_RX_MODE_PROMISC; + + else if ((dev->flags & IFF_ALLMULTI) || + ((dev->mc_count > BNX2X_MAX_MULTICAST) && CHIP_IS_E1(bp))) + rx_mode = BNX2X_RX_MODE_ALLMULTI; + + else { /* some multicasts */ + if (CHIP_IS_E1(bp)) { + int i, old, offset; + struct dev_mc_list *mclist; + struct mac_configuration_cmd *config = + bnx2x_sp(bp, mcast_config); + + for (i = 0, mclist = dev->mc_list; + mclist && (i < dev->mc_count); + i++, mclist = mclist->next) { + + config->config_table[i]. + cam_entry.msb_mac_addr = + swab16(*(u16 *)&mclist->dmi_addr[0]); + config->config_table[i]. + cam_entry.middle_mac_addr = + swab16(*(u16 *)&mclist->dmi_addr[2]); + config->config_table[i]. + cam_entry.lsb_mac_addr = + swab16(*(u16 *)&mclist->dmi_addr[4]); + config->config_table[i].cam_entry.flags = + cpu_to_le16(port); + config->config_table[i]. + target_table_entry.flags = 0; + config->config_table[i]. + target_table_entry.client_id = 0; + config->config_table[i]. + target_table_entry.vlan_id = 0; + + DP(NETIF_MSG_IFUP, + "setting MCAST[%d] (%04x:%04x:%04x)\n", i, + config->config_table[i]. + cam_entry.msb_mac_addr, + config->config_table[i]. + cam_entry.middle_mac_addr, + config->config_table[i]. + cam_entry.lsb_mac_addr); + } + old = config->hdr.length_6b; + if (old > i) { + for (; i < old; i++) { + if (CAM_IS_INVALID(config-> + config_table[i])) { + i--; /* already invalidated */ + break; + } + /* invalidate */ + CAM_INVALIDATE(config-> + config_table[i]); + } + } + + if (CHIP_REV_IS_SLOW(bp)) + offset = BNX2X_MAX_EMUL_MULTI*(1 + port); + else + offset = BNX2X_MAX_MULTICAST*(1 + port); + + config->hdr.length_6b = i; + config->hdr.offset = offset; + config->hdr.client_id = BP_CL_ID(bp); + config->hdr.reserved1 = 0; + + bnx2x_sp_post(bp, RAMROD_CMD_ID_ETH_SET_MAC, 0, + U64_HI(bnx2x_sp_mapping(bp, mcast_config)), + U64_LO(bnx2x_sp_mapping(bp, mcast_config)), + 0); + } else { /* E1H */ + /* Accept one or more multicasts */ + struct dev_mc_list *mclist; + u32 mc_filter[MC_HASH_SIZE]; + u32 crc, bit, regidx; + int i; + + memset(mc_filter, 0, 4 * MC_HASH_SIZE); + + for (i = 0, mclist = dev->mc_list; + mclist && (i < dev->mc_count); + i++, mclist = mclist->next) { + + DP(NETIF_MSG_IFUP, "Adding mcast MAC: " + "%02x:%02x:%02x:%02x:%02x:%02x\n", + mclist->dmi_addr[0], mclist->dmi_addr[1], + mclist->dmi_addr[2], mclist->dmi_addr[3], + mclist->dmi_addr[4], mclist->dmi_addr[5]); + + crc = crc32c_le(0, mclist->dmi_addr, ETH_ALEN); + bit = (crc >> 24) & 0xff; + regidx = bit >> 5; + bit &= 0x1f; + mc_filter[regidx] |= (1 << bit); + } + + for (i = 0; i < MC_HASH_SIZE; i++) + REG_WR(bp, MC_HASH_OFFSET(bp, i), + mc_filter[i]); + } + } + + bp->rx_mode = rx_mode; + bnx2x_set_storm_rx_mode(bp); +} + +/* called with rtnl_lock */ +static int bnx2x_change_mac_addr(struct net_device *dev, void *p) +{ + struct sockaddr *addr = p; + struct bnx2x *bp = netdev_priv(dev); + + if (!is_valid_ether_addr((u8 *)(addr->sa_data))) + return -EINVAL; + + memcpy(dev->dev_addr, addr->sa_data, dev->addr_len); + if (netif_running(dev)) { + if (CHIP_IS_E1(bp)) + bnx2x_set_mac_addr_e1(bp); + else + bnx2x_set_mac_addr_e1h(bp); + } + + return 0; +} + +/* called with rtnl_lock */ +static int bnx2x_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) +{ + struct mii_ioctl_data *data = if_mii(ifr); + struct bnx2x *bp = netdev_priv(dev); + int err; + + switch (cmd) { + case SIOCGMIIPHY: + data->phy_id = bp->port.phy_addr; + + /* fallthrough */ + + case SIOCGMIIREG: { + u16 mii_regval; + + if (!netif_running(dev)) + return -EAGAIN; + + mutex_lock(&bp->port.phy_mutex); + err = bnx2x_cl45_read(bp, BP_PORT(bp), 0, bp->port.phy_addr, + DEFAULT_PHY_DEV_ADDR, + (data->reg_num & 0x1f), &mii_regval); + data->val_out = mii_regval; + mutex_unlock(&bp->port.phy_mutex); + return err; + } + + case SIOCSMIIREG: + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + + if (!netif_running(dev)) + return -EAGAIN; + + mutex_lock(&bp->port.phy_mutex); + err = bnx2x_cl45_write(bp, BP_PORT(bp), 0, bp->port.phy_addr, + DEFAULT_PHY_DEV_ADDR, + (data->reg_num & 0x1f), data->val_in); + mutex_unlock(&bp->port.phy_mutex); + return err; + + default: + /* do nothing */ + break; + } + + return -EOPNOTSUPP; +} + +/* called with rtnl_lock */ +static int bnx2x_change_mtu(struct net_device *dev, int new_mtu) +{ + struct bnx2x *bp = netdev_priv(dev); + int rc = 0; + + if ((new_mtu > ETH_MAX_JUMBO_PACKET_SIZE) || + ((new_mtu + ETH_HLEN) < ETH_MIN_PACKET_SIZE)) + return -EINVAL; + + /* This does not race with packet allocation + * because the actual alloc size is + * only updated as part of load + */ + dev->mtu = new_mtu; + + if (netif_running(dev)) { + bnx2x_nic_unload(bp, UNLOAD_NORMAL); + rc = bnx2x_nic_load(bp, LOAD_NORMAL); + } + + return rc; +} + +static void bnx2x_tx_timeout(struct net_device *dev) +{ + struct bnx2x *bp = netdev_priv(dev); + +#ifdef BNX2X_STOP_ON_ERROR + if (!bp->panic) + bnx2x_panic(); +#endif + /* This allows the netif to be shutdown gracefully before resetting */ + schedule_work(&bp->reset_task); +} + +#ifdef BCM_VLAN +/* called with rtnl_lock */ +static void bnx2x_vlan_rx_register(struct net_device *dev, + struct vlan_group *vlgrp) +{ + struct bnx2x *bp = netdev_priv(dev); + + bp->vlgrp = vlgrp; + if (netif_running(dev)) + bnx2x_set_client_config(bp); +} + +#endif + +#if defined(HAVE_POLL_CONTROLLER) || defined(CONFIG_NET_POLL_CONTROLLER) +static void poll_bnx2x(struct net_device *dev) +{ + struct bnx2x *bp = netdev_priv(dev); + + disable_irq(bp->pdev->irq); + bnx2x_interrupt(bp->pdev->irq, dev); + enable_irq(bp->pdev->irq); +} +#endif + +static int __devinit bnx2x_init_dev(struct pci_dev *pdev, + struct net_device *dev) +{ + struct bnx2x *bp; + int rc; + + SET_NETDEV_DEV(dev, &pdev->dev); + bp = netdev_priv(dev); + + bp->dev = dev; + bp->pdev = pdev; + bp->flags = 0; + bp->func = PCI_FUNC(pdev->devfn); + + rc = pci_enable_device(pdev); + if (rc) { + printk(KERN_ERR PFX "Cannot enable PCI device, aborting\n"); + goto err_out; + } + + if (!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM)) { + printk(KERN_ERR PFX "Cannot find PCI device base address," + " aborting\n"); + rc = -ENODEV; + goto err_out_disable; + } + + if (!(pci_resource_flags(pdev, 2) & IORESOURCE_MEM)) { + printk(KERN_ERR PFX "Cannot find second PCI device" + " base address, aborting\n"); + rc = -ENODEV; + goto err_out_disable; + } + + if (atomic_read(&pdev->enable_cnt) == 1) { + rc = pci_request_regions(pdev, DRV_MODULE_NAME); + if (rc) { + printk(KERN_ERR PFX "Cannot obtain PCI resources," + " aborting\n"); + goto err_out_disable; + } + + pci_set_master(pdev); + pci_save_state(pdev); + } + + bp->pm_cap = pci_find_capability(pdev, PCI_CAP_ID_PM); + if (bp->pm_cap == 0) { + printk(KERN_ERR PFX "Cannot find power management" + " capability, aborting\n"); + rc = -EIO; + goto err_out_release; + } + + bp->pcie_cap = pci_find_capability(pdev, PCI_CAP_ID_EXP); + if (bp->pcie_cap == 0) { + printk(KERN_ERR PFX "Cannot find PCI Express capability," + " aborting\n"); + rc = -EIO; + goto err_out_release; + } + + if (pci_set_dma_mask(pdev, DMA_64BIT_MASK) == 0) { + bp->flags |= USING_DAC_FLAG; + if (pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK) != 0) { + printk(KERN_ERR PFX "pci_set_consistent_dma_mask" + " failed, aborting\n"); + rc = -EIO; + goto err_out_release; + } + + } else if (pci_set_dma_mask(pdev, DMA_32BIT_MASK) != 0) { + printk(KERN_ERR PFX "System does not support DMA," + " aborting\n"); + rc = -EIO; + goto err_out_release; + } + + dev->mem_start = pci_resource_start(pdev, 0); + dev->base_addr = dev->mem_start; + dev->mem_end = pci_resource_end(pdev, 0); + + dev->irq = pdev->irq; + + bp->regview = ioremap_nocache(dev->base_addr, + pci_resource_len(pdev, 0)); + if (!bp->regview) { + printk(KERN_ERR PFX "Cannot map register space, aborting\n"); + rc = -ENOMEM; + goto err_out_release; + } + + bp->doorbells = ioremap_nocache(pci_resource_start(pdev, 2), + min_t(u64, BNX2X_DB_SIZE, + pci_resource_len(pdev, 2))); + if (!bp->doorbells) { + printk(KERN_ERR PFX "Cannot map doorbell space, aborting\n"); + rc = -ENOMEM; + goto err_out_unmap; + } + + bnx2x_set_power_state(bp, PCI_D0); + + /* clean indirect addresses */ + pci_write_config_dword(bp->pdev, PCICFG_GRC_ADDRESS, + PCICFG_VENDOR_ID_OFFSET); + REG_WR(bp, PXP2_REG_PGL_ADDR_88_F0 + BP_PORT(bp)*16, 0); + REG_WR(bp, PXP2_REG_PGL_ADDR_8C_F0 + BP_PORT(bp)*16, 0); + REG_WR(bp, PXP2_REG_PGL_ADDR_90_F0 + BP_PORT(bp)*16, 0); + REG_WR(bp, PXP2_REG_PGL_ADDR_94_F0 + BP_PORT(bp)*16, 0); + + dev->hard_start_xmit = bnx2x_start_xmit; + dev->watchdog_timeo = TX_TIMEOUT; + + dev->ethtool_ops = &bnx2x_ethtool_ops; + dev->open = bnx2x_open; + dev->stop = bnx2x_close; + dev->set_multicast_list = bnx2x_set_rx_mode; + dev->set_mac_address = bnx2x_change_mac_addr; + dev->do_ioctl = bnx2x_ioctl; + dev->change_mtu = bnx2x_change_mtu; + dev->tx_timeout = bnx2x_tx_timeout; +#ifdef BCM_VLAN + dev->vlan_rx_register = bnx2x_vlan_rx_register; +#endif +#if defined(HAVE_POLL_CONTROLLER) || defined(CONFIG_NET_POLL_CONTROLLER) + dev->poll_controller = poll_bnx2x; +#endif + dev->features |= NETIF_F_SG; + dev->features |= NETIF_F_HW_CSUM; + if (bp->flags & USING_DAC_FLAG) + dev->features |= NETIF_F_HIGHDMA; +#ifdef BCM_VLAN + dev->features |= (NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX); +#endif + dev->features |= (NETIF_F_TSO | NETIF_F_TSO_ECN); + dev->features |= NETIF_F_TSO6; + + return 0; + +err_out_unmap: + if (bp->regview) { + iounmap(bp->regview); + bp->regview = NULL; + } + if (bp->doorbells) { + iounmap(bp->doorbells); + bp->doorbells = NULL; + } + +err_out_release: + if (atomic_read(&pdev->enable_cnt) == 1) + pci_release_regions(pdev); + +err_out_disable: + pci_disable_device(pdev); + pci_set_drvdata(pdev, NULL); + +err_out: + return rc; +} + +static int __devinit bnx2x_get_pcie_width(struct bnx2x *bp) +{ + u32 val = REG_RD(bp, PCICFG_OFFSET + PCICFG_LINK_CONTROL); + + val = (val & PCICFG_LINK_WIDTH) >> PCICFG_LINK_WIDTH_SHIFT; + return val; +} + +/* return value of 1=2.5GHz 2=5GHz */ +static int __devinit bnx2x_get_pcie_speed(struct bnx2x *bp) +{ + u32 val = REG_RD(bp, PCICFG_OFFSET + PCICFG_LINK_CONTROL); + + val = (val & PCICFG_LINK_SPEED) >> PCICFG_LINK_SPEED_SHIFT; + return val; +} + +static int __devinit bnx2x_init_one(struct pci_dev *pdev, + const struct pci_device_id *ent) +{ + static int version_printed; + struct net_device *dev = NULL; + struct bnx2x *bp; + int rc; + DECLARE_MAC_BUF(mac); + + if (version_printed++ == 0) + printk(KERN_INFO "%s", version); + + /* dev zeroed in init_etherdev */ + dev = alloc_etherdev(sizeof(*bp)); + if (!dev) { + printk(KERN_ERR PFX "Cannot allocate net device\n"); + return -ENOMEM; + } + + netif_carrier_off(dev); + + bp = netdev_priv(dev); + bp->msglevel = debug; + + rc = bnx2x_init_dev(pdev, dev); + if (rc < 0) { + free_netdev(dev); + return rc; + } + + rc = register_netdev(dev); + if (rc) { + dev_err(&pdev->dev, "Cannot register net device\n"); + goto init_one_exit; + } + + pci_set_drvdata(pdev, dev); + + rc = bnx2x_init_bp(bp); + if (rc) { + unregister_netdev(dev); + goto init_one_exit; + } + + bp->common.name = board_info[ent->driver_data].name; + printk(KERN_INFO "%s: %s (%c%d) PCI-E x%d %s found at mem %lx," + " IRQ %d, ", dev->name, bp->common.name, + (CHIP_REV(bp) >> 12) + 'A', (CHIP_METAL(bp) >> 4), + bnx2x_get_pcie_width(bp), + (bnx2x_get_pcie_speed(bp) == 2) ? "5GHz (Gen2)" : "2.5GHz", + dev->base_addr, bp->pdev->irq); + printk(KERN_CONT "node addr %s\n", print_mac(mac, dev->dev_addr)); + return 0; + +init_one_exit: + if (bp->regview) + iounmap(bp->regview); + + if (bp->doorbells) + iounmap(bp->doorbells); + + free_netdev(dev); + + if (atomic_read(&pdev->enable_cnt) == 1) + pci_release_regions(pdev); + + pci_disable_device(pdev); + pci_set_drvdata(pdev, NULL); + + return rc; +} + +static void __devexit bnx2x_remove_one(struct pci_dev *pdev) +{ + struct net_device *dev = pci_get_drvdata(pdev); + struct bnx2x *bp; + + if (!dev) { + printk(KERN_ERR PFX "BAD net device from bnx2x_init_one\n"); + return; + } + bp = netdev_priv(dev); + + unregister_netdev(dev); + + if (bp->regview) + iounmap(bp->regview); + + if (bp->doorbells) + iounmap(bp->doorbells); + + free_netdev(dev); + + if (atomic_read(&pdev->enable_cnt) == 1) + pci_release_regions(pdev); + + pci_disable_device(pdev); + pci_set_drvdata(pdev, NULL); +} + +static int bnx2x_suspend(struct pci_dev *pdev, pm_message_t state) +{ + struct net_device *dev = pci_get_drvdata(pdev); + struct bnx2x *bp; + + if (!dev) { + printk(KERN_ERR PFX "BAD net device from bnx2x_init_one\n"); + return -ENODEV; + } + bp = netdev_priv(dev); + + rtnl_lock(); + + pci_save_state(pdev); + + if (!netif_running(dev)) { + rtnl_unlock(); + return 0; + } + + netif_device_detach(dev); + + bnx2x_nic_unload(bp, UNLOAD_NORMAL); + + bnx2x_set_power_state(bp, pci_choose_state(pdev, state)); + + rtnl_unlock(); + + return 0; +} + +static int bnx2x_resume(struct pci_dev *pdev) +{ + struct net_device *dev = pci_get_drvdata(pdev); + struct bnx2x *bp; + int rc; + + if (!dev) { + printk(KERN_ERR PFX "BAD net device from bnx2x_init_one\n"); + return -ENODEV; + } + bp = netdev_priv(dev); + + rtnl_lock(); + + pci_restore_state(pdev); + + if (!netif_running(dev)) { + rtnl_unlock(); + return 0; + } + + bnx2x_set_power_state(bp, PCI_D0); + netif_device_attach(dev); + + rc = bnx2x_nic_load(bp, LOAD_NORMAL); + + rtnl_unlock(); + + return rc; +} + +/** + * bnx2x_io_error_detected - called when PCI error is detected + * @pdev: Pointer to PCI device + * @state: The current pci connection state + * + * This function is called after a PCI bus error affecting + * this device has been detected. + */ +static pci_ers_result_t bnx2x_io_error_detected(struct pci_dev *pdev, + pci_channel_state_t state) +{ + struct net_device *dev = pci_get_drvdata(pdev); + struct bnx2x *bp = netdev_priv(dev); + + rtnl_lock(); + + netif_device_detach(dev); + + if (netif_running(dev)) + bnx2x_nic_unload(bp, UNLOAD_CLOSE); + + pci_disable_device(pdev); + + rtnl_unlock(); + + /* Request a slot reset */ + return PCI_ERS_RESULT_NEED_RESET; +} + +/** + * bnx2x_io_slot_reset - called after the PCI bus has been reset + * @pdev: Pointer to PCI device + * + * Restart the card from scratch, as if from a cold-boot. + */ +static pci_ers_result_t bnx2x_io_slot_reset(struct pci_dev *pdev) +{ + struct net_device *dev = pci_get_drvdata(pdev); + struct bnx2x *bp = netdev_priv(dev); + + rtnl_lock(); + + if (pci_enable_device(pdev)) { + dev_err(&pdev->dev, + "Cannot re-enable PCI device after reset\n"); + rtnl_unlock(); + return PCI_ERS_RESULT_DISCONNECT; + } + + pci_set_master(pdev); + pci_restore_state(pdev); + + if (netif_running(dev)) + bnx2x_set_power_state(bp, PCI_D0); + + rtnl_unlock(); + + return PCI_ERS_RESULT_RECOVERED; +} + +/** + * bnx2x_io_resume - called when traffic can start flowing again + * @pdev: Pointer to PCI device + * + * This callback is called when the error recovery driver tells us that + * its OK to resume normal operation. + */ +static void bnx2x_io_resume(struct pci_dev *pdev) +{ + struct net_device *dev = pci_get_drvdata(pdev); + struct bnx2x *bp = netdev_priv(dev); + + rtnl_lock(); + + if (netif_running(dev)) + bnx2x_nic_load(bp, LOAD_OPEN); + + netif_device_attach(dev); + + rtnl_unlock(); +} + +static struct pci_error_handlers bnx2x_err_handler = { + .error_detected = bnx2x_io_error_detected, + .slot_reset = bnx2x_io_slot_reset, + .resume = bnx2x_io_resume, +}; + +static struct pci_driver bnx2x_pci_driver = { + .name = DRV_MODULE_NAME, + .id_table = bnx2x_pci_tbl, + .probe = bnx2x_init_one, + .remove = __devexit_p(bnx2x_remove_one), + .suspend = bnx2x_suspend, + .resume = bnx2x_resume, + .err_handler = &bnx2x_err_handler, +}; + +static int __init bnx2x_init(void) +{ + return pci_register_driver(&bnx2x_pci_driver); +} + +static void __exit bnx2x_cleanup(void) +{ + pci_unregister_driver(&bnx2x_pci_driver); +} + +module_init(bnx2x_init); +module_exit(bnx2x_cleanup); + diff --git a/drivers/net/bnx2x_reg.h b/drivers/net/bnx2x_reg.h index 5a1aa0b55044..15c9a9946724 100644 --- a/drivers/net/bnx2x_reg.h +++ b/drivers/net/bnx2x_reg.h @@ -38,21 +38,19 @@ was asserted. */ #define BRB1_REG_NUM_OF_FULL_CYCLES_0 0x600c8 #define BRB1_REG_NUM_OF_FULL_CYCLES_1 0x600cc -#define BRB1_REG_NUM_OF_FULL_CYCLES_2 0x600d0 -#define BRB1_REG_NUM_OF_FULL_CYCLES_3 0x600d4 #define BRB1_REG_NUM_OF_FULL_CYCLES_4 0x600d8 /* [ST 32] The number of cycles that the pause signal towards MAC #0 was asserted. */ #define BRB1_REG_NUM_OF_PAUSE_CYCLES_0 0x600b8 #define BRB1_REG_NUM_OF_PAUSE_CYCLES_1 0x600bc -#define BRB1_REG_NUM_OF_PAUSE_CYCLES_2 0x600c0 -#define BRB1_REG_NUM_OF_PAUSE_CYCLES_3 0x600c4 /* [RW 10] Write client 0: De-assert pause threshold. */ #define BRB1_REG_PAUSE_HIGH_THRESHOLD_0 0x60078 #define BRB1_REG_PAUSE_HIGH_THRESHOLD_1 0x6007c /* [RW 10] Write client 0: Assert pause threshold. */ #define BRB1_REG_PAUSE_LOW_THRESHOLD_0 0x60068 #define BRB1_REG_PAUSE_LOW_THRESHOLD_1 0x6006c +/* [R 24] The number of full blocks occpied by port. */ +#define BRB1_REG_PORT_NUM_OCC_BLOCKS_0 0x60094 /* [RW 1] Reset the design by software. */ #define BRB1_REG_SOFT_RESET 0x600dc /* [R 5] Used to read the value of the XX protection CAM occupancy counter. */ @@ -72,6 +70,8 @@ #define CCM_REG_CCM_INT_MASK 0xd01e4 /* [R 11] Interrupt register #0 read */ #define CCM_REG_CCM_INT_STS 0xd01d8 +/* [R 27] Parity register #0 read */ +#define CCM_REG_CCM_PRTY_STS 0xd01e8 /* [RW 3] The size of AG context region 0 in REG-pairs. Designates the MS REG-pair number (e.g. if region 0 is 6 REG-pairs; the value should be 5). Is used to determine the number of the AG context REG-pairs written back; @@ -190,25 +190,20 @@ weight 8 (the most prioritised); 1 stands for weight 1(least prioritised); 2 stands for weight 2; tc. */ #define CCM_REG_PBF_WEIGHT 0xd00ac -/* [RW 6] The physical queue number of queue number 1 per port index. */ #define CCM_REG_PHYS_QNUM1_0 0xd0134 #define CCM_REG_PHYS_QNUM1_1 0xd0138 -/* [RW 6] The physical queue number of queue number 2 per port index. */ #define CCM_REG_PHYS_QNUM2_0 0xd013c #define CCM_REG_PHYS_QNUM2_1 0xd0140 -/* [RW 6] The physical queue number of queue number 3 per port index. */ #define CCM_REG_PHYS_QNUM3_0 0xd0144 -/* [RW 6] The physical queue number of queue number 0 with QOS equal 0 port - index 0. */ +#define CCM_REG_PHYS_QNUM3_1 0xd0148 #define CCM_REG_QOS_PHYS_QNUM0_0 0xd0114 #define CCM_REG_QOS_PHYS_QNUM0_1 0xd0118 -/* [RW 6] The physical queue number of queue number 0 with QOS equal 1 port - index 0. */ #define CCM_REG_QOS_PHYS_QNUM1_0 0xd011c #define CCM_REG_QOS_PHYS_QNUM1_1 0xd0120 -/* [RW 6] The physical queue number of queue number 0 with QOS equal 2 port - index 0. */ #define CCM_REG_QOS_PHYS_QNUM2_0 0xd0124 +#define CCM_REG_QOS_PHYS_QNUM2_1 0xd0128 +#define CCM_REG_QOS_PHYS_QNUM3_0 0xd012c +#define CCM_REG_QOS_PHYS_QNUM3_1 0xd0130 /* [RW 1] STORM - CM Interface enable. If 0 - the valid input is disregarded; acknowledge output is deasserted; all other signals are treated as usual; if 1 - normal activity. */ @@ -253,6 +248,7 @@ mechanism. The fields are: [5:0] - message length; [12:6] - message pointer; 18:13] - next pointer. */ #define CCM_REG_XX_DESCR_TABLE 0xd0300 +#define CCM_REG_XX_DESCR_TABLE_SIZE 36 /* [R 7] Used to read the value of XX protection Free counter. */ #define CCM_REG_XX_FREE 0xd0184 /* [RW 6] Initial value for the credit counter; responsible for fulfilling @@ -296,6 +292,8 @@ /* [WB 24] MATT ram access. each entry has the following format:{RegionLength[11:0]; egionOffset[11:0]} */ #define CDU_REG_MATT 0x101100 +/* [RW 1] when this bit is set the CDU operates in e1hmf mode */ +#define CDU_REG_MF_MODE 0x101050 /* [R 1] indication the initializing the activity counter by the hardware was done. */ #define CFC_REG_AC_INIT_DONE 0x104078 @@ -330,6 +328,9 @@ field allows changing the priorities of the weighted-round-robin arbiter which selects which CFC load client should be served next */ #define CFC_REG_LCREQ_WEIGHTS 0x104084 +/* [RW 16] Link List ram access; data = {prev_lcid; ext_lcid} */ +#define CFC_REG_LINK_LIST 0x104c00 +#define CFC_REG_LINK_LIST_SIZE 256 /* [R 1] indication the initializing the link list by the hardware was done. */ #define CFC_REG_LL_INIT_DONE 0x104074 /* [R 9] Number of allocated LCIDs which are at empty state */ @@ -342,6 +343,45 @@ #define CFC_REG_NUM_LCIDS_LEAVING 0x104018 /* [RW 8] The event id for aggregated interrupt 0 */ #define CSDM_REG_AGG_INT_EVENT_0 0xc2038 +#define CSDM_REG_AGG_INT_EVENT_1 0xc203c +#define CSDM_REG_AGG_INT_EVENT_10 0xc2060 +#define CSDM_REG_AGG_INT_EVENT_11 0xc2064 +#define CSDM_REG_AGG_INT_EVENT_12 0xc2068 +#define CSDM_REG_AGG_INT_EVENT_13 0xc206c +#define CSDM_REG_AGG_INT_EVENT_14 0xc2070 +#define CSDM_REG_AGG_INT_EVENT_15 0xc2074 +#define CSDM_REG_AGG_INT_EVENT_16 0xc2078 +#define CSDM_REG_AGG_INT_EVENT_17 0xc207c +#define CSDM_REG_AGG_INT_EVENT_18 0xc2080 +#define CSDM_REG_AGG_INT_EVENT_19 0xc2084 +#define CSDM_REG_AGG_INT_EVENT_2 0xc2040 +#define CSDM_REG_AGG_INT_EVENT_20 0xc2088 +#define CSDM_REG_AGG_INT_EVENT_21 0xc208c +#define CSDM_REG_AGG_INT_EVENT_22 0xc2090 +#define CSDM_REG_AGG_INT_EVENT_23 0xc2094 +#define CSDM_REG_AGG_INT_EVENT_24 0xc2098 +#define CSDM_REG_AGG_INT_EVENT_25 0xc209c +#define CSDM_REG_AGG_INT_EVENT_26 0xc20a0 +#define CSDM_REG_AGG_INT_EVENT_27 0xc20a4 +#define CSDM_REG_AGG_INT_EVENT_28 0xc20a8 +#define CSDM_REG_AGG_INT_EVENT_29 0xc20ac +#define CSDM_REG_AGG_INT_EVENT_3 0xc2044 +#define CSDM_REG_AGG_INT_EVENT_30 0xc20b0 +#define CSDM_REG_AGG_INT_EVENT_31 0xc20b4 +#define CSDM_REG_AGG_INT_EVENT_4 0xc2048 +/* [RW 1] The T bit for aggregated interrupt 0 */ +#define CSDM_REG_AGG_INT_T_0 0xc20b8 +#define CSDM_REG_AGG_INT_T_1 0xc20bc +#define CSDM_REG_AGG_INT_T_10 0xc20e0 +#define CSDM_REG_AGG_INT_T_11 0xc20e4 +#define CSDM_REG_AGG_INT_T_12 0xc20e8 +#define CSDM_REG_AGG_INT_T_13 0xc20ec +#define CSDM_REG_AGG_INT_T_14 0xc20f0 +#define CSDM_REG_AGG_INT_T_15 0xc20f4 +#define CSDM_REG_AGG_INT_T_16 0xc20f8 +#define CSDM_REG_AGG_INT_T_17 0xc20fc +#define CSDM_REG_AGG_INT_T_18 0xc2100 +#define CSDM_REG_AGG_INT_T_19 0xc2104 /* [RW 13] The start address in the internal RAM for the cfc_rsp lcid */ #define CSDM_REG_CFC_RSP_START_ADDR 0xc2008 /* [RW 16] The maximum value of the competion counter #0 */ @@ -358,6 +398,9 @@ /* [RW 32] Interrupt mask register #0 read/write */ #define CSDM_REG_CSDM_INT_MASK_0 0xc229c #define CSDM_REG_CSDM_INT_MASK_1 0xc22ac +/* [R 32] Interrupt register #0 read */ +#define CSDM_REG_CSDM_INT_STS_0 0xc2290 +#define CSDM_REG_CSDM_INT_STS_1 0xc22a0 /* [RW 11] Parity mask register #0 read/write */ #define CSDM_REG_CSDM_PRTY_MASK 0xc22bc /* [R 11] Parity register #0 read */ @@ -443,6 +486,9 @@ /* [RW 32] Interrupt mask register #0 read/write */ #define CSEM_REG_CSEM_INT_MASK_0 0x200110 #define CSEM_REG_CSEM_INT_MASK_1 0x200120 +/* [R 32] Interrupt register #0 read */ +#define CSEM_REG_CSEM_INT_STS_0 0x200104 +#define CSEM_REG_CSEM_INT_STS_1 0x200114 /* [RW 32] Parity mask register #0 read/write */ #define CSEM_REG_CSEM_PRTY_MASK_0 0x200130 #define CSEM_REG_CSEM_PRTY_MASK_1 0x200140 @@ -453,9 +499,8 @@ #define CSEM_REG_ENABLE_OUT 0x2000a8 /* [RW 32] This address space contains all registers and memories that are placed in SEM_FAST block. The SEM_FAST registers are described in - appendix B. In order to access the SEM_FAST registers the base address - CSEM_REGISTERS_FAST_MEMORY (Offset: 0x220000) should be added to each - SEM_FAST register offset. */ + appendix B. In order to access the sem_fast registers the base address + ~fast_memory.fast_memory should be added to eachsem_fast register offset. */ #define CSEM_REG_FAST_MEMORY 0x220000 /* [RW 1] Disables input messages from FIC0 May be updated during run_time by the microcode */ @@ -539,13 +584,10 @@ #define DBG_REG_DBG_PRTY_MASK 0xc0a8 /* [R 1] Parity register #0 read */ #define DBG_REG_DBG_PRTY_STS 0xc09c -/* [RW 2] debug only: These bits indicate the credit for PCI request type 4 - interface; MUST be configured AFTER pci_ext_buffer_strt_addr_lsb/msb are - configured */ -#define DBG_REG_PCI_REQ_CREDIT 0xc120 /* [RW 32] Commands memory. The address to command X; row Y is to calculated as 14*X+Y. */ #define DMAE_REG_CMD_MEM 0x102400 +#define DMAE_REG_CMD_MEM_SIZE 224 /* [RW 1] If 0 - the CRC-16c initial value is all zeroes; if 1 - the CRC-16c initial value is all ones. */ #define DMAE_REG_CRC16C_INIT 0x10201c @@ -630,6 +672,8 @@ #define DORQ_REG_AGG_CMD3 0x17006c /* [RW 28] UCM Header. */ #define DORQ_REG_CMHEAD_RX 0x170050 +/* [RW 32] Doorbell address for RBC doorbells (function 0). */ +#define DORQ_REG_DB_ADDR0 0x17008c /* [RW 5] Interrupt mask register #0 read/write */ #define DORQ_REG_DORQ_INT_MASK 0x170180 /* [R 5] Interrupt register #0 read */ @@ -690,75 +734,33 @@ #define HC_CONFIG_0_REG_SINGLE_ISR_EN_0 (0x1<<1) #define HC_REG_AGG_INT_0 0x108050 #define HC_REG_AGG_INT_1 0x108054 -/* [RW 16] attention bit and attention acknowledge bits status for port 0 - and 1 according to the following address map: addr 0 - attn_bit_0; addr 1 - - attn_ack_bit_0; addr 2 - attn_bit_1; addr 3 - attn_ack_bit_1; */ #define HC_REG_ATTN_BIT 0x108120 -/* [RW 16] attn bits status index for attn bit msg; addr 0 - function 0; - addr 1 - functin 1 */ #define HC_REG_ATTN_IDX 0x108100 -/* [RW 32] port 0 lower 32 bits address field for attn messag. */ #define HC_REG_ATTN_MSG0_ADDR_L 0x108018 -/* [RW 32] port 1 lower 32 bits address field for attn messag. */ #define HC_REG_ATTN_MSG1_ADDR_L 0x108020 -/* [RW 8] status block number for attn bit msg - function 0; */ #define HC_REG_ATTN_NUM_P0 0x108038 -/* [RW 8] status block number for attn bit msg - function 1 */ #define HC_REG_ATTN_NUM_P1 0x10803c #define HC_REG_CONFIG_0 0x108000 #define HC_REG_CONFIG_1 0x108004 +#define HC_REG_FUNC_NUM_P0 0x1080ac +#define HC_REG_FUNC_NUM_P1 0x1080b0 /* [RW 3] Parity mask register #0 read/write */ #define HC_REG_HC_PRTY_MASK 0x1080a0 /* [R 3] Parity register #0 read */ #define HC_REG_HC_PRTY_STS 0x108094 -/* [RW 17] status block interrupt mask; one in each bit means unmask; zerow - in each bit means mask; bit 0 - default SB; bit 1 - SB_0; bit 2 - SB_1... - bit 16- SB_15; addr 0 - port 0; addr 1 - port 1 */ #define HC_REG_INT_MASK 0x108108 -/* [RW 16] port 0 attn bit condition monitoring; each bit that is set will - lock a change fron 0 to 1 in the corresponding attention signals that - comes from the AEU */ #define HC_REG_LEADING_EDGE_0 0x108040 #define HC_REG_LEADING_EDGE_1 0x108048 -/* [RW 16] all producer and consumer of port 0 according to the following - addresses; U_prod: 0-15; C_prod: 16-31; U_cons: 32-47; C_cons:48-63; - Defoult_prod: U/C/X/T/Attn-64/65/66/67/68; Defoult_cons: - U/C/X/T/Attn-69/70/71/72/73 */ #define HC_REG_P0_PROD_CONS 0x108200 -/* [RW 16] all producer and consumer of port 1according to the following - addresses; U_prod: 0-15; C_prod: 16-31; U_cons: 32-47; C_cons:48-63; - Defoult_prod: U/C/X/T/Attn-64/65/66/67/68; Defoult_cons: - U/C/X/T/Attn-69/70/71/72/73 */ #define HC_REG_P1_PROD_CONS 0x108400 -/* [W 1] This register is write only and has 4 addresses as follow: 0 = - clear all PBA bits port 0; 1 = clear all pending interrupts request - port0; 2 = clear all PBA bits port 1; 3 = clear all pending interrupts - request port1; here is no meaning for the data in this register */ #define HC_REG_PBA_COMMAND 0x108140 #define HC_REG_PCI_CONFIG_0 0x108010 #define HC_REG_PCI_CONFIG_1 0x108014 -/* [RW 24] all counters acording to the following address: LSB: 0=read; 1= - read_clear; 0-71 = HW counters (the inside order is the same as the - interrupt table in the spec); 72-219 = SW counters 1 (stops after first - consumer upd) the inside order is: 72-103 - U_non_default_p0; 104-135 - C_non_defaul_p0; 36-145 U/C/X/T/Attn_default_p0; 146-177 - U_non_default_p1; 178-209 C_non_defaul_p1; 10-219 U/C/X/T/Attn_default_p1 - ; 220-367 = SW counters 2 (stops when prod=cons) the inside order is: - 220-251 - U_non_default_p0; 252-283 C_non_defaul_p0; 84-293 - U/C/X/T/Attn_default_p0; 294-325 U_non_default_p1; 326-357 - C_non_defaul_p1; 58-367 U/C/X/T/Attn_default_p1 ; 368-515 = mailbox - counters; (the inside order of the mailbox counter is 368-431 U and C - non_default_p0; 432-441 U/C/X/T/Attn_default_p0; 442-505 U and C - non_default_p1; 506-515 U/C/X/T/Attn_default_p1) */ #define HC_REG_STATISTIC_COUNTERS 0x109000 -/* [RW 16] port 0 attn bit condition monitoring; each bit that is set will - lock a change fron 1 to 0 in the corresponding attention signals that - comes from the AEU */ #define HC_REG_TRAILING_EDGE_0 0x108044 #define HC_REG_TRAILING_EDGE_1 0x10804c #define HC_REG_UC_RAM_ADDR_0 0x108028 #define HC_REG_UC_RAM_ADDR_1 0x108030 -/* [RW 16] ustorm address for coalesc now message */ #define HC_REG_USTORM_ADDR_FOR_COALESCE 0x108068 #define HC_REG_VQID_0 0x108008 #define HC_REG_VQID_1 0x10800c @@ -883,14 +885,16 @@ rom_parity; [29] MCP Latched ump_rx_parity; [30] MCP Latched ump_tx_parity; [31] MCP Latched scpad_parity; */ #define MISC_REG_AEU_AFTER_INVERT_4_MCP 0xa458 -/* [W 11] write to this register results with the clear of the latched +/* [W 14] write to this register results with the clear of the latched signals; one in d0 clears RBCR latch; one in d1 clears RBCT latch; one in d2 clears RBCN latch; one in d3 clears RBCU latch; one in d4 clears RBCP latch; one in d5 clears GRC Latched timeout attention; one in d6 clears GRC Latched reserved access attention; one in d7 clears Latched rom_parity; one in d8 clears Latched ump_rx_parity; one in d9 clears - Latched ump_tx_parity; one in d10 clears Latched scpad_parity; read from - this register return zero */ + Latched ump_tx_parity; one in d10 clears Latched scpad_parity (both + ports); one in d11 clears pxpv_misc_mps_attn; one in d12 clears + pxp_misc_exp_rom_attn0; one in d13 clears pxp_misc_exp_rom_attn1; read + from this register return zero */ #define MISC_REG_AEU_CLR_LATCH_SIGNAL 0xa45c /* [RW 32] first 32b for enabling the output for function 0 output0. mapped as follows: [0] NIG attention for function0; [1] NIG attention for @@ -907,7 +911,11 @@ TSEMI Hw interrupt; [30] PBF Parity error; [31] PBF Hw interrupt; */ #define MISC_REG_AEU_ENABLE1_FUNC_0_OUT_0 0xa06c #define MISC_REG_AEU_ENABLE1_FUNC_0_OUT_1 0xa07c +#define MISC_REG_AEU_ENABLE1_FUNC_0_OUT_2 0xa08c #define MISC_REG_AEU_ENABLE1_FUNC_0_OUT_3 0xa09c +#define MISC_REG_AEU_ENABLE1_FUNC_0_OUT_5 0xa0bc +#define MISC_REG_AEU_ENABLE1_FUNC_0_OUT_6 0xa0cc +#define MISC_REG_AEU_ENABLE1_FUNC_0_OUT_7 0xa0dc /* [RW 32] first 32b for enabling the output for function 1 output0. mapped as follows: [0] NIG attention for function0; [1] NIG attention for function1; [2] GPIO1 function 1; [3] GPIO2 function 1; [4] GPIO3 function @@ -923,9 +931,13 @@ TSEMI Hw interrupt; [30] PBF Parity error; [31] PBF Hw interrupt; */ #define MISC_REG_AEU_ENABLE1_FUNC_1_OUT_0 0xa10c #define MISC_REG_AEU_ENABLE1_FUNC_1_OUT_1 0xa11c +#define MISC_REG_AEU_ENABLE1_FUNC_1_OUT_2 0xa12c #define MISC_REG_AEU_ENABLE1_FUNC_1_OUT_3 0xa13c -/* [RW 32] first 32b for enabling the output for close the gate nig 0. - mapped as follows: [0] NIG attention for function0; [1] NIG attention for +#define MISC_REG_AEU_ENABLE1_FUNC_1_OUT_5 0xa15c +#define MISC_REG_AEU_ENABLE1_FUNC_1_OUT_6 0xa16c +#define MISC_REG_AEU_ENABLE1_FUNC_1_OUT_7 0xa17c +/* [RW 32] first 32b for enabling the output for close the gate nig. mapped + as follows: [0] NIG attention for function0; [1] NIG attention for function1; [2] GPIO1 function 0; [3] GPIO2 function 0; [4] GPIO3 function 0; [5] GPIO4 function 0; [6] GPIO1 function 1; [7] GPIO2 function 1; [8] GPIO3 function 1; [9] GPIO4 function 1; [10] PCIE glue/PXP VPD event @@ -939,8 +951,8 @@ TSEMI Hw interrupt; [30] PBF Parity error; [31] PBF Hw interrupt; */ #define MISC_REG_AEU_ENABLE1_NIG_0 0xa0ec #define MISC_REG_AEU_ENABLE1_NIG_1 0xa18c -/* [RW 32] first 32b for enabling the output for close the gate pxp 0. - mapped as follows: [0] NIG attention for function0; [1] NIG attention for +/* [RW 32] first 32b for enabling the output for close the gate pxp. mapped + as follows: [0] NIG attention for function0; [1] NIG attention for function1; [2] GPIO1 function 0; [3] GPIO2 function 0; [4] GPIO3 function 0; [5] GPIO4 function 0; [6] GPIO1 function 1; [7] GPIO2 function 1; [8] GPIO3 function 1; [9] GPIO4 function 1; [10] PCIE glue/PXP VPD event @@ -984,34 +996,34 @@ interrupt; */ #define MISC_REG_AEU_ENABLE2_FUNC_1_OUT_0 0xa110 #define MISC_REG_AEU_ENABLE2_FUNC_1_OUT_1 0xa120 -/* [RW 32] second 32b for enabling the output for close the gate nig 0. - mapped as follows: [0] PBClient Parity error; [1] PBClient Hw interrupt; - [2] QM Parity error; [3] QM Hw interrupt; [4] Timers Parity error; [5] - Timers Hw interrupt; [6] XSDM Parity error; [7] XSDM Hw interrupt; [8] - XCM Parity error; [9] XCM Hw interrupt; [10] XSEMI Parity error; [11] - XSEMI Hw interrupt; [12] DoorbellQ Parity error; [13] DoorbellQ Hw - interrupt; [14] NIG Parity error; [15] NIG Hw interrupt; [16] Vaux PCI - core Parity error; [17] Vaux PCI core Hw interrupt; [18] Debug Parity - error; [19] Debug Hw interrupt; [20] USDM Parity error; [21] USDM Hw - interrupt; [22] UCM Parity error; [23] UCM Hw interrupt; [24] USEMI - Parity error; [25] USEMI Hw interrupt; [26] UPB Parity error; [27] UPB Hw - interrupt; [28] CSDM Parity error; [29] CSDM Hw interrupt; [30] CCM - Parity error; [31] CCM Hw interrupt; */ +/* [RW 32] second 32b for enabling the output for close the gate nig. mapped + as follows: [0] PBClient Parity error; [1] PBClient Hw interrupt; [2] QM + Parity error; [3] QM Hw interrupt; [4] Timers Parity error; [5] Timers Hw + interrupt; [6] XSDM Parity error; [7] XSDM Hw interrupt; [8] XCM Parity + error; [9] XCM Hw interrupt; [10] XSEMI Parity error; [11] XSEMI Hw + interrupt; [12] DoorbellQ Parity error; [13] DoorbellQ Hw interrupt; [14] + NIG Parity error; [15] NIG Hw interrupt; [16] Vaux PCI core Parity error; + [17] Vaux PCI core Hw interrupt; [18] Debug Parity error; [19] Debug Hw + interrupt; [20] USDM Parity error; [21] USDM Hw interrupt; [22] UCM + Parity error; [23] UCM Hw interrupt; [24] USEMI Parity error; [25] USEMI + Hw interrupt; [26] UPB Parity error; [27] UPB Hw interrupt; [28] CSDM + Parity error; [29] CSDM Hw interrupt; [30] CCM Parity error; [31] CCM Hw + interrupt; */ #define MISC_REG_AEU_ENABLE2_NIG_0 0xa0f0 #define MISC_REG_AEU_ENABLE2_NIG_1 0xa190 -/* [RW 32] second 32b for enabling the output for close the gate pxp 0. - mapped as follows: [0] PBClient Parity error; [1] PBClient Hw interrupt; - [2] QM Parity error; [3] QM Hw interrupt; [4] Timers Parity error; [5] - Timers Hw interrupt; [6] XSDM Parity error; [7] XSDM Hw interrupt; [8] - XCM Parity error; [9] XCM Hw interrupt; [10] XSEMI Parity error; [11] - XSEMI Hw interrupt; [12] DoorbellQ Parity error; [13] DoorbellQ Hw - interrupt; [14] NIG Parity error; [15] NIG Hw interrupt; [16] Vaux PCI - core Parity error; [17] Vaux PCI core Hw interrupt; [18] Debug Parity - error; [19] Debug Hw interrupt; [20] USDM Parity error; [21] USDM Hw - interrupt; [22] UCM Parity error; [23] UCM Hw interrupt; [24] USEMI - Parity error; [25] USEMI Hw interrupt; [26] UPB Parity error; [27] UPB Hw - interrupt; [28] CSDM Parity error; [29] CSDM Hw interrupt; [30] CCM - Parity error; [31] CCM Hw interrupt; */ +/* [RW 32] second 32b for enabling the output for close the gate pxp. mapped + as follows: [0] PBClient Parity error; [1] PBClient Hw interrupt; [2] QM + Parity error; [3] QM Hw interrupt; [4] Timers Parity error; [5] Timers Hw + interrupt; [6] XSDM Parity error; [7] XSDM Hw interrupt; [8] XCM Parity + error; [9] XCM Hw interrupt; [10] XSEMI Parity error; [11] XSEMI Hw + interrupt; [12] DoorbellQ Parity error; [13] DoorbellQ Hw interrupt; [14] + NIG Parity error; [15] NIG Hw interrupt; [16] Vaux PCI core Parity error; + [17] Vaux PCI core Hw interrupt; [18] Debug Parity error; [19] Debug Hw + interrupt; [20] USDM Parity error; [21] USDM Hw interrupt; [22] UCM + Parity error; [23] UCM Hw interrupt; [24] USEMI Parity error; [25] USEMI + Hw interrupt; [26] UPB Parity error; [27] UPB Hw interrupt; [28] CSDM + Parity error; [29] CSDM Hw interrupt; [30] CCM Parity error; [31] CCM Hw + interrupt; */ #define MISC_REG_AEU_ENABLE2_PXP_0 0xa100 #define MISC_REG_AEU_ENABLE2_PXP_1 0xa1a0 /* [RW 32] third 32b for enabling the output for function 0 output0. mapped @@ -1044,34 +1056,34 @@ attn1; */ #define MISC_REG_AEU_ENABLE3_FUNC_1_OUT_0 0xa114 #define MISC_REG_AEU_ENABLE3_FUNC_1_OUT_1 0xa124 -/* [RW 32] third 32b for enabling the output for close the gate nig 0. - mapped as follows: [0] CSEMI Parity error; [1] CSEMI Hw interrupt; [2] - PXP Parity error; [3] PXP Hw interrupt; [4] PXPpciClockClient Parity - error; [5] PXPpciClockClient Hw interrupt; [6] CFC Parity error; [7] CFC - Hw interrupt; [8] CDU Parity error; [9] CDU Hw interrupt; [10] DMAE - Parity error; [11] DMAE Hw interrupt; [12] IGU (HC) Parity error; [13] - IGU (HC) Hw interrupt; [14] MISC Parity error; [15] MISC Hw interrupt; - [16] pxp_misc_mps_attn; [17] Flash event; [18] SMB event; [19] MCP attn0; - [20] MCP attn1; [21] SW timers attn_1 func0; [22] SW timers attn_2 func0; - [23] SW timers attn_3 func0; [24] SW timers attn_4 func0; [25] PERST; - [26] SW timers attn_1 func1; [27] SW timers attn_2 func1; [28] SW timers - attn_3 func1; [29] SW timers attn_4 func1; [30] General attn0; [31] - General attn1; */ +/* [RW 32] third 32b for enabling the output for close the gate nig. mapped + as follows: [0] CSEMI Parity error; [1] CSEMI Hw interrupt; [2] PXP + Parity error; [3] PXP Hw interrupt; [4] PXPpciClockClient Parity error; + [5] PXPpciClockClient Hw interrupt; [6] CFC Parity error; [7] CFC Hw + interrupt; [8] CDU Parity error; [9] CDU Hw interrupt; [10] DMAE Parity + error; [11] DMAE Hw interrupt; [12] IGU (HC) Parity error; [13] IGU (HC) + Hw interrupt; [14] MISC Parity error; [15] MISC Hw interrupt; [16] + pxp_misc_mps_attn; [17] Flash event; [18] SMB event; [19] MCP attn0; [20] + MCP attn1; [21] SW timers attn_1 func0; [22] SW timers attn_2 func0; [23] + SW timers attn_3 func0; [24] SW timers attn_4 func0; [25] PERST; [26] SW + timers attn_1 func1; [27] SW timers attn_2 func1; [28] SW timers attn_3 + func1; [29] SW timers attn_4 func1; [30] General attn0; [31] General + attn1; */ #define MISC_REG_AEU_ENABLE3_NIG_0 0xa0f4 #define MISC_REG_AEU_ENABLE3_NIG_1 0xa194 -/* [RW 32] third 32b for enabling the output for close the gate pxp 0. - mapped as follows: [0] CSEMI Parity error; [1] CSEMI Hw interrupt; [2] - PXP Parity error; [3] PXP Hw interrupt; [4] PXPpciClockClient Parity - error; [5] PXPpciClockClient Hw interrupt; [6] CFC Parity error; [7] CFC - Hw interrupt; [8] CDU Parity error; [9] CDU Hw interrupt; [10] DMAE - Parity error; [11] DMAE Hw interrupt; [12] IGU (HC) Parity error; [13] - IGU (HC) Hw interrupt; [14] MISC Parity error; [15] MISC Hw interrupt; - [16] pxp_misc_mps_attn; [17] Flash event; [18] SMB event; [19] MCP attn0; - [20] MCP attn1; [21] SW timers attn_1 func0; [22] SW timers attn_2 func0; - [23] SW timers attn_3 func0; [24] SW timers attn_4 func0; [25] PERST; - [26] SW timers attn_1 func1; [27] SW timers attn_2 func1; [28] SW timers - attn_3 func1; [29] SW timers attn_4 func1; [30] General attn0; [31] - General attn1; */ +/* [RW 32] third 32b for enabling the output for close the gate pxp. mapped + as follows: [0] CSEMI Parity error; [1] CSEMI Hw interrupt; [2] PXP + Parity error; [3] PXP Hw interrupt; [4] PXPpciClockClient Parity error; + [5] PXPpciClockClient Hw interrupt; [6] CFC Parity error; [7] CFC Hw + interrupt; [8] CDU Parity error; [9] CDU Hw interrupt; [10] DMAE Parity + error; [11] DMAE Hw interrupt; [12] IGU (HC) Parity error; [13] IGU (HC) + Hw interrupt; [14] MISC Parity error; [15] MISC Hw interrupt; [16] + pxp_misc_mps_attn; [17] Flash event; [18] SMB event; [19] MCP attn0; [20] + MCP attn1; [21] SW timers attn_1 func0; [22] SW timers attn_2 func0; [23] + SW timers attn_3 func0; [24] SW timers attn_4 func0; [25] PERST; [26] SW + timers attn_1 func1; [27] SW timers attn_2 func1; [28] SW timers attn_3 + func1; [29] SW timers attn_4 func1; [30] General attn0; [31] General + attn1; */ #define MISC_REG_AEU_ENABLE3_PXP_0 0xa104 #define MISC_REG_AEU_ENABLE3_PXP_1 0xa1a4 /* [RW 32] fourth 32b for enabling the output for function 0 output0.mapped @@ -1088,6 +1100,10 @@ Latched ump_tx_parity; [31] MCP Latched scpad_parity; */ #define MISC_REG_AEU_ENABLE4_FUNC_0_OUT_0 0xa078 #define MISC_REG_AEU_ENABLE4_FUNC_0_OUT_2 0xa098 +#define MISC_REG_AEU_ENABLE4_FUNC_0_OUT_4 0xa0b8 +#define MISC_REG_AEU_ENABLE4_FUNC_0_OUT_5 0xa0c8 +#define MISC_REG_AEU_ENABLE4_FUNC_0_OUT_6 0xa0d8 +#define MISC_REG_AEU_ENABLE4_FUNC_0_OUT_7 0xa0e8 /* [RW 32] fourth 32b for enabling the output for function 1 output0.mapped as follows: [0] General attn2; [1] General attn3; [2] General attn4; [3] General attn5; [4] General attn6; [5] General attn7; [6] General attn8; @@ -1102,34 +1118,36 @@ Latched ump_tx_parity; [31] MCP Latched scpad_parity; */ #define MISC_REG_AEU_ENABLE4_FUNC_1_OUT_0 0xa118 #define MISC_REG_AEU_ENABLE4_FUNC_1_OUT_2 0xa138 -/* [RW 32] fourth 32b for enabling the output for close the gate nig - 0.mapped as follows: [0] General attn2; [1] General attn3; [2] General - attn4; [3] General attn5; [4] General attn6; [5] General attn7; [6] - General attn8; [7] General attn9; [8] General attn10; [9] General attn11; - [10] General attn12; [11] General attn13; [12] General attn14; [13] - General attn15; [14] General attn16; [15] General attn17; [16] General - attn18; [17] General attn19; [18] General attn20; [19] General attn21; - [20] Main power interrupt; [21] RBCR Latched attn; [22] RBCT Latched - attn; [23] RBCN Latched attn; [24] RBCU Latched attn; [25] RBCP Latched - attn; [26] GRC Latched timeout attention; [27] GRC Latched reserved - access attention; [28] MCP Latched rom_parity; [29] MCP Latched - ump_rx_parity; [30] MCP Latched ump_tx_parity; [31] MCP Latched - scpad_parity; */ +#define MISC_REG_AEU_ENABLE4_FUNC_1_OUT_4 0xa158 +#define MISC_REG_AEU_ENABLE4_FUNC_1_OUT_5 0xa168 +#define MISC_REG_AEU_ENABLE4_FUNC_1_OUT_6 0xa178 +#define MISC_REG_AEU_ENABLE4_FUNC_1_OUT_7 0xa188 +/* [RW 32] fourth 32b for enabling the output for close the gate nig.mapped + as follows: [0] General attn2; [1] General attn3; [2] General attn4; [3] + General attn5; [4] General attn6; [5] General attn7; [6] General attn8; + [7] General attn9; [8] General attn10; [9] General attn11; [10] General + attn12; [11] General attn13; [12] General attn14; [13] General attn15; + [14] General attn16; [15] General attn17; [16] General attn18; [17] + General attn19; [18] General attn20; [19] General attn21; [20] Main power + interrupt; [21] RBCR Latched attn; [22] RBCT Latched attn; [23] RBCN + Latched attn; [24] RBCU Latched attn; [25] RBCP Latched attn; [26] GRC + Latched timeout attention; [27] GRC Latched reserved access attention; + [28] MCP Latched rom_parity; [29] MCP Latched ump_rx_parity; [30] MCP + Latched ump_tx_parity; [31] MCP Latched scpad_parity; */ #define MISC_REG_AEU_ENABLE4_NIG_0 0xa0f8 #define MISC_REG_AEU_ENABLE4_NIG_1 0xa198 -/* [RW 32] fourth 32b for enabling the output for close the gate pxp - 0.mapped as follows: [0] General attn2; [1] General attn3; [2] General - attn4; [3] General attn5; [4] General attn6; [5] General attn7; [6] - General attn8; [7] General attn9; [8] General attn10; [9] General attn11; - [10] General attn12; [11] General attn13; [12] General attn14; [13] - General attn15; [14] General attn16; [15] General attn17; [16] General - attn18; [17] General attn19; [18] General attn20; [19] General attn21; - [20] Main power interrupt; [21] RBCR Latched attn; [22] RBCT Latched - attn; [23] RBCN Latched attn; [24] RBCU Latched attn; [25] RBCP Latched - attn; [26] GRC Latched timeout attention; [27] GRC Latched reserved - access attention; [28] MCP Latched rom_parity; [29] MCP Latched - ump_rx_parity; [30] MCP Latched ump_tx_parity; [31] MCP Latched - scpad_parity; */ +/* [RW 32] fourth 32b for enabling the output for close the gate pxp.mapped + as follows: [0] General attn2; [1] General attn3; [2] General attn4; [3] + General attn5; [4] General attn6; [5] General attn7; [6] General attn8; + [7] General attn9; [8] General attn10; [9] General attn11; [10] General + attn12; [11] General attn13; [12] General attn14; [13] General attn15; + [14] General attn16; [15] General attn17; [16] General attn18; [17] + General attn19; [18] General attn20; [19] General attn21; [20] Main power + interrupt; [21] RBCR Latched attn; [22] RBCT Latched attn; [23] RBCN + Latched attn; [24] RBCU Latched attn; [25] RBCP Latched attn; [26] GRC + Latched timeout attention; [27] GRC Latched reserved access attention; + [28] MCP Latched rom_parity; [29] MCP Latched ump_rx_parity; [30] MCP + Latched ump_tx_parity; [31] MCP Latched scpad_parity; */ #define MISC_REG_AEU_ENABLE4_PXP_0 0xa108 #define MISC_REG_AEU_ENABLE4_PXP_1 0xa1a8 /* [RW 1] set/clr general attention 0; this will set/clr bit 94 in the aeu @@ -1148,6 +1166,7 @@ #define MISC_REG_AEU_GENERAL_ATTN_19 0xa04c #define MISC_REG_AEU_GENERAL_ATTN_10 0xa028 #define MISC_REG_AEU_GENERAL_ATTN_11 0xa02c +#define MISC_REG_AEU_GENERAL_ATTN_12 0xa030 #define MISC_REG_AEU_GENERAL_ATTN_2 0xa008 #define MISC_REG_AEU_GENERAL_ATTN_20 0xa050 #define MISC_REG_AEU_GENERAL_ATTN_21 0xa054 @@ -1158,6 +1177,7 @@ #define MISC_REG_AEU_GENERAL_ATTN_7 0xa01c #define MISC_REG_AEU_GENERAL_ATTN_8 0xa020 #define MISC_REG_AEU_GENERAL_ATTN_9 0xa024 +#define MISC_REG_AEU_GENERAL_MASK 0xa61c /* [RW 32] first 32b for inverting the input for function 0; for each bit: 0= do not invert; 1= invert; mapped as follows: [0] NIG attention for function0; [1] NIG attention for function1; [2] GPIO1 mcp; [3] GPIO2 mcp; @@ -1189,10 +1209,29 @@ #define MISC_REG_AEU_INVERTER_2_FUNC_0 0xa230 #define MISC_REG_AEU_INVERTER_2_FUNC_1 0xa240 /* [RW 10] [7:0] = mask 8 attention output signals toward IGU function0; - [9:8] = mask close the gates signals of function 0 toward PXP [8] and NIG - [9]. Zero = mask; one = unmask */ + [9:8] = raserved. Zero = mask; one = unmask */ #define MISC_REG_AEU_MASK_ATTN_FUNC_0 0xa060 #define MISC_REG_AEU_MASK_ATTN_FUNC_1 0xa064 +/* [RW 1] If set a system kill occurred */ +#define MISC_REG_AEU_SYS_KILL_OCCURRED 0xa610 +/* [RW 32] Represent the status of the input vector to the AEU when a system + kill occurred. The register is reset in por reset. Mapped as follows: [0] + NIG attention for function0; [1] NIG attention for function1; [2] GPIO1 + mcp; [3] GPIO2 mcp; [4] GPIO3 mcp; [5] GPIO4 mcp; [6] GPIO1 function 1; + [7] GPIO2 function 1; [8] GPIO3 function 1; [9] GPIO4 function 1; [10] + PCIE glue/PXP VPD event function0; [11] PCIE glue/PXP VPD event + function1; [12] PCIE glue/PXP Expansion ROM event0; [13] PCIE glue/PXP + Expansion ROM event1; [14] SPIO4; [15] SPIO5; [16] MSI/X indication for + mcp; [17] MSI/X indication for function 1; [18] BRB Parity error; [19] + BRB Hw interrupt; [20] PRS Parity error; [21] PRS Hw interrupt; [22] SRC + Parity error; [23] SRC Hw interrupt; [24] TSDM Parity error; [25] TSDM Hw + interrupt; [26] TCM Parity error; [27] TCM Hw interrupt; [28] TSEMI + Parity error; [29] TSEMI Hw interrupt; [30] PBF Parity error; [31] PBF Hw + interrupt; */ +#define MISC_REG_AEU_SYS_KILL_STATUS_0 0xa600 +#define MISC_REG_AEU_SYS_KILL_STATUS_1 0xa604 +#define MISC_REG_AEU_SYS_KILL_STATUS_2 0xa608 +#define MISC_REG_AEU_SYS_KILL_STATUS_3 0xa60c /* [R 4] This field indicates the type of the device. '0' - 2 Ports; '1' - 1 Port. */ #define MISC_REG_BOND_ID 0xa400 @@ -1206,8 +1245,80 @@ starts at 0x0 for the A0 tape-out and increments by one for each all-layer tape-out. */ #define MISC_REG_CHIP_REV 0xa40c -/* [RW 32] The following driver registers(1..6) represent 6 drivers and 32 - clients. Each client can be controlled by one driver only. One in each +/* [RW 32] The following driver registers(1...16) represent 16 drivers and + 32 clients. Each client can be controlled by one driver only. One in each + bit represent that this driver control the appropriate client (Ex: bit 5 + is set means this driver control client number 5). addr1 = set; addr0 = + clear; read from both addresses will give the same result = status. write + to address 1 will set a request to control all the clients that their + appropriate bit (in the write command) is set. if the client is free (the + appropriate bit in all the other drivers is clear) one will be written to + that driver register; if the client isn't free the bit will remain zero. + if the appropriate bit is set (the driver request to gain control on a + client it already controls the ~MISC_REGISTERS_INT_STS.GENERIC_SW + interrupt will be asserted). write to address 0 will set a request to + free all the clients that their appropriate bit (in the write command) is + set. if the appropriate bit is clear (the driver request to free a client + it doesn't controls the ~MISC_REGISTERS_INT_STS.GENERIC_SW interrupt will + be asserted). */ +#define MISC_REG_DRIVER_CONTROL_10 0xa3e0 +#define MISC_REG_DRIVER_CONTROL_10_SIZE 2 +/* [RW 32] The following driver registers(1...16) represent 16 drivers and + 32 clients. Each client can be controlled by one driver only. One in each + bit represent that this driver control the appropriate client (Ex: bit 5 + is set means this driver control client number 5). addr1 = set; addr0 = + clear; read from both addresses will give the same result = status. write + to address 1 will set a request to control all the clients that their + appropriate bit (in the write command) is set. if the client is free (the + appropriate bit in all the other drivers is clear) one will be written to + that driver register; if the client isn't free the bit will remain zero. + if the appropriate bit is set (the driver request to gain control on a + client it already controls the ~MISC_REGISTERS_INT_STS.GENERIC_SW + interrupt will be asserted). write to address 0 will set a request to + free all the clients that their appropriate bit (in the write command) is + set. if the appropriate bit is clear (the driver request to free a client + it doesn't controls the ~MISC_REGISTERS_INT_STS.GENERIC_SW interrupt will + be asserted). */ +#define MISC_REG_DRIVER_CONTROL_11 0xa3e8 +#define MISC_REG_DRIVER_CONTROL_11_SIZE 2 +/* [RW 32] The following driver registers(1...16) represent 16 drivers and + 32 clients. Each client can be controlled by one driver only. One in each + bit represent that this driver control the appropriate client (Ex: bit 5 + is set means this driver control client number 5). addr1 = set; addr0 = + clear; read from both addresses will give the same result = status. write + to address 1 will set a request to control all the clients that their + appropriate bit (in the write command) is set. if the client is free (the + appropriate bit in all the other drivers is clear) one will be written to + that driver register; if the client isn't free the bit will remain zero. + if the appropriate bit is set (the driver request to gain control on a + client it already controls the ~MISC_REGISTERS_INT_STS.GENERIC_SW + interrupt will be asserted). write to address 0 will set a request to + free all the clients that their appropriate bit (in the write command) is + set. if the appropriate bit is clear (the driver request to free a client + it doesn't controls the ~MISC_REGISTERS_INT_STS.GENERIC_SW interrupt will + be asserted). */ +#define MISC_REG_DRIVER_CONTROL_12 0xa3f0 +#define MISC_REG_DRIVER_CONTROL_12_SIZE 2 +/* [RW 32] The following driver registers(1...16) represent 16 drivers and + 32 clients. Each client can be controlled by one driver only. One in each + bit represent that this driver control the appropriate client (Ex: bit 5 + is set means this driver control client number 5). addr1 = set; addr0 = + clear; read from both addresses will give the same result = status. write + to address 1 will set a request to control all the clients that their + appropriate bit (in the write command) is set. if the client is free (the + appropriate bit in all the other drivers is clear) one will be written to + that driver register; if the client isn't free the bit will remain zero. + if the appropriate bit is set (the driver request to gain control on a + client it already controls the ~MISC_REGISTERS_INT_STS.GENERIC_SW + interrupt will be asserted). write to address 0 will set a request to + free all the clients that their appropriate bit (in the write command) is + set. if the appropriate bit is clear (the driver request to free a client + it doesn't controls the ~MISC_REGISTERS_INT_STS.GENERIC_SW interrupt will + be asserted). */ +#define MISC_REG_DRIVER_CONTROL_13 0xa3f8 +#define MISC_REG_DRIVER_CONTROL_13_SIZE 2 +/* [RW 32] The following driver registers(1...16) represent 16 drivers and + 32 clients. Each client can be controlled by one driver only. One in each bit represent that this driver control the appropriate client (Ex: bit 5 is set means this driver control client number 5). addr1 = set; addr0 = clear; read from both addresses will give the same result = status. write @@ -1223,6 +1334,47 @@ it doesn't controls the ~MISC_REGISTERS_INT_STS.GENERIC_SW interrupt will be asserted). */ #define MISC_REG_DRIVER_CONTROL_1 0xa510 +#define MISC_REG_DRIVER_CONTROL_14 0xa5e0 +#define MISC_REG_DRIVER_CONTROL_14_SIZE 2 +/* [RW 32] The following driver registers(1...16) represent 16 drivers and + 32 clients. Each client can be controlled by one driver only. One in each + bit represent that this driver control the appropriate client (Ex: bit 5 + is set means this driver control client number 5). addr1 = set; addr0 = + clear; read from both addresses will give the same result = status. write + to address 1 will set a request to control all the clients that their + appropriate bit (in the write command) is set. if the client is free (the + appropriate bit in all the other drivers is clear) one will be written to + that driver register; if the client isn't free the bit will remain zero. + if the appropriate bit is set (the driver request to gain control on a + client it already controls the ~MISC_REGISTERS_INT_STS.GENERIC_SW + interrupt will be asserted). write to address 0 will set a request to + free all the clients that their appropriate bit (in the write command) is + set. if the appropriate bit is clear (the driver request to free a client + it doesn't controls the ~MISC_REGISTERS_INT_STS.GENERIC_SW interrupt will + be asserted). */ +#define MISC_REG_DRIVER_CONTROL_15 0xa5e8 +#define MISC_REG_DRIVER_CONTROL_15_SIZE 2 +/* [RW 32] The following driver registers(1...16) represent 16 drivers and + 32 clients. Each client can be controlled by one driver only. One in each + bit represent that this driver control the appropriate client (Ex: bit 5 + is set means this driver control client number 5). addr1 = set; addr0 = + clear; read from both addresses will give the same result = status. write + to address 1 will set a request to control all the clients that their + appropriate bit (in the write command) is set. if the client is free (the + appropriate bit in all the other drivers is clear) one will be written to + that driver register; if the client isn't free the bit will remain zero. + if the appropriate bit is set (the driver request to gain control on a + client it already controls the ~MISC_REGISTERS_INT_STS.GENERIC_SW + interrupt will be asserted). write to address 0 will set a request to + free all the clients that their appropriate bit (in the write command) is + set. if the appropriate bit is clear (the driver request to free a client + it doesn't controls the ~MISC_REGISTERS_INT_STS.GENERIC_SW interrupt will + be asserted). */ +#define MISC_REG_DRIVER_CONTROL_16 0xa5f0 +#define MISC_REG_DRIVER_CONTROL_16_SIZE 2 +/* [RW 1] e1hmf for WOL. If clr WOL signal o the PXP will be send on bit 0 + only. */ +#define MISC_REG_E1HMF_MODE 0xa5f8 /* [RW 32] GPIO. [31-28] FLOAT port 0; [27-24] FLOAT port 0; When any of these bits is written as a '1'; the corresponding SPIO bit will turn off it's drivers and become an input. This is the reset state of all GPIO @@ -1240,6 +1392,18 @@ This is the result value of the pin; not the drive value. Writing these bits will have not effect. */ #define MISC_REG_GPIO 0xa490 +/* [R 28] this field hold the last information that caused reserved + attention. bits [19:0] - address; [22:20] function; [23] reserved; + [27:24] the master thatcaused the attention - according to the following + encodeing:1 = pxp; 2 = mcp; 3 = usdm; 4 = tsdm; 5 = xsdm; 6 = csdm; 7 = + dbu; 8 = dmae */ +#define MISC_REG_GRC_RSV_ATTN 0xa3c0 +/* [R 28] this field hold the last information that caused timeout + attention. bits [19:0] - address; [22:20] function; [23] reserved; + [27:24] the master thatcaused the attention - according to the following + encodeing:1 = pxp; 2 = mcp; 3 = usdm; 4 = tsdm; 5 = xsdm; 6 = csdm; 7 = + dbu; 8 = dmae */ +#define MISC_REG_GRC_TIMEOUT_ATTN 0xa3c4 /* [RW 1] Setting this bit enables a timer in the GRC block to timeout any access that does not finish within ~misc_registers_grc_timout_val.grc_timeout_val cycles. When this bit is @@ -1282,6 +1446,11 @@ #define MISC_REG_MISC_PRTY_MASK 0xa398 /* [R 1] Parity register #0 read */ #define MISC_REG_MISC_PRTY_STS 0xa38c +#define MISC_REG_NIG_WOL_P0 0xa270 +#define MISC_REG_NIG_WOL_P1 0xa274 +/* [R 1] If set indicate that the pcie_rst_b was asserted without perst + assertion */ +#define MISC_REG_PCIE_HOT_RESET 0xa618 /* [RW 32] 32 LSB of storm PLL first register; reset val = 0x 071d2911. inside order of the bits is: [0] P1 divider[0] (reset value 1); [1] P1 divider[1] (reset value 0); [2] P1 divider[2] (reset value 0); [3] P1 @@ -1303,7 +1472,7 @@ #define MISC_REG_PLL_STORM_CTRL_2 0xa298 #define MISC_REG_PLL_STORM_CTRL_3 0xa29c #define MISC_REG_PLL_STORM_CTRL_4 0xa2a0 -/* [RW 32] reset reg#1; rite/read one = the specific block is out of reset; +/* [RW 32] reset reg#2; rite/read one = the specific block is out of reset; write/read zero = the specific block is in reset; addr 0-wr- the write value will be written to the register; addr 1-set - one will be written to all the bits that have the value of one in the data written (bits that @@ -1311,14 +1480,12 @@ written to all the bits that have the value of one in the data written (bits that have the value of zero will not be change); addr 3-ignore; read ignore from all addr except addr 00; inside order of the bits is: - [0] rst_brb1; [1] rst_prs; [2] rst_src; [3] rst_tsdm; [4] rst_tsem; [5] - rst_tcm; [6] rst_rbcr; [7] rst_nig; [8] rst_usdm; [9] rst_ucm; [10] - rst_usem; [11] rst_upb; [12] rst_ccm; [13] rst_csem; [14] rst_csdm; [15] - rst_rbcu; [16] rst_pbf; [17] rst_qm; [18] rst_tm; [19] rst_dorq; [20] - rst_xcm; [21] rst_xsdm; [22] rst_xsem; [23] rst_rbct; [24] rst_cdu; [25] - rst_cfc; [26] rst_pxp; [27] rst_pxpv; [28] rst_rbcp; [29] rst_hc; [30] - rst_dmae; [31] rst_semi_rtc; */ -#define MISC_REG_RESET_REG_1 0xa580 + [0] rst_bmac0; [1] rst_bmac1; [2] rst_emac0; [3] rst_emac1; [4] rst_grc; + [5] rst_mcp_n_reset_reg_hard_core; [6] rst_ mcp_n_hard_core_rst_b; [7] + rst_ mcp_n_reset_cmn_cpu; [8] rst_ mcp_n_reset_cmn_core; [9] rst_rbcn; + [10] rst_dbg; [11] rst_misc_core; [12] rst_dbue (UART); [13] + Pci_resetmdio_n; [14] rst_emac0_hard_core; [15] rst_emac1_hard_core; 16] + rst_pxp_rq_rd_wr; 31:17] reserved */ #define MISC_REG_RESET_REG_2 0xa590 /* [RW 20] 20 bit GRC address where the scratch-pad of the MCP that is shared with the driver resides */ @@ -1345,7 +1512,7 @@ select VAUX supply. (This is an output pin only; it is not controlled by the SET and CLR fields; it is controlled by the Main Power SM; the FLOAT field is not applicable for this pin; only the VALUE fields is relevant - - it reflects the output value); [3] reserved; [4] spio_4; [5] spio_5; [6] + it reflects the output value); [3] port swap [4] spio_4; [5] spio_5; [6] Bit 0 of UMP device ID select; read by UMP firmware; [7] Bit 1 of UMP device ID select; read by UMP firmware. */ #define MISC_REG_SPIO 0xa4fc @@ -1394,8 +1561,9 @@ #define NIG_REG_BRB1_PAUSE_IN_EN 0x100c8 /* [RW 1] output enable for RX BRB1 LP IF */ #define NIG_REG_BRB_LB_OUT_EN 0x10100 -/* [WB_W 72] Debug packet to LP from RBC; Data spelling:[63:0] data; 64] - error; [67:65]eop_bvalid; [68]eop; [69]sop; [70]port_id; 71]flush */ +/* [WB_W 82] Debug packet to LP from RBC; Data spelling:[63:0] data; 64] + error; [67:65]eop_bvalid; [68]eop; [69]sop; [70]port_id; 71]flush; + 72:73]-vnic_num; 81:74]-sideband_info */ #define NIG_REG_DEBUG_PACKET_LB 0x10800 /* [RW 1] Input enable for TX Debug packet */ #define NIG_REG_EGRESS_DEBUG_IN_EN 0x100dc @@ -1409,6 +1577,8 @@ /* [RW 1] MAC configuration for packets of port0. If 1 - all packet outputs to emac for port0; other way to bmac for port0 */ #define NIG_REG_EGRESS_EMAC0_PORT 0x10058 +/* [RW 32] TX_MNG_FIFO in NIG_TX_PORT0; data[31:0] written in FIFO order. */ +#define NIG_REG_EGRESS_MNG0_FIFO 0x1045c /* [RW 1] Input enable for TX PBF user packet port0 IF */ #define NIG_REG_EGRESS_PBF0_IN_EN 0x100cc /* [RW 1] Input enable for TX PBF user packet port1 IF */ @@ -1438,6 +1608,8 @@ #define NIG_REG_INGRESS_EOP_LB_FIFO 0x104e4 /* [RW 1] led 10g for port 0 */ #define NIG_REG_LED_10G_P0 0x10320 +/* [RW 1] led 10g for port 1 */ +#define NIG_REG_LED_10G_P1 0x10324 /* [RW 1] Port0: This bit is set to enable the use of the ~nig_registers_led_control_blink_rate_p0.led_control_blink_rate_p0 field defined below. If this bit is cleared; then the blink rate will be about @@ -1448,7 +1620,7 @@ is reset to 0x080; giving a default blink period of approximately 8Hz. */ #define NIG_REG_LED_CONTROL_BLINK_RATE_P0 0x10310 /* [RW 1] Port0: If set along with the - nig_registers_led_control_override_traffic_p0.led_control_override_traffic_p0 + ~nig_registers_led_control_override_traffic_p0.led_control_override_traffic_p0 bit and ~nig_registers_led_control_traffic_p0.led_control_traffic_p0 LED bit; the Traffic LED will blink with the blink rate specified in ~nig_registers_led_control_blink_rate_p0.led_control_blink_rate_p0 and @@ -1470,19 +1642,47 @@ /* [RW 4] led mode for port0: 0 MAC; 1-3 PHY1; 4 MAC2; 5-7 PHY4; 8-MAC3; 9-11PHY7; 12 MAC4; 13-15 PHY10; */ #define NIG_REG_LED_MODE_P0 0x102f0 +#define NIG_REG_LLH0_ACPI_PAT_0_CRC 0x1015c +#define NIG_REG_LLH0_ACPI_PAT_6_LEN 0x10154 #define NIG_REG_LLH0_BRB1_DRV_MASK 0x10244 +#define NIG_REG_LLH0_BRB1_DRV_MASK_MF 0x16048 /* [RW 1] send to BRB1 if no match on any of RMP rules. */ #define NIG_REG_LLH0_BRB1_NOT_MCP 0x1025c +/* [RW 2] Determine the classification participants. 0: no classification.1: + classification upon VLAN id. 2: classification upon MAC address. 3: + classification upon both VLAN id & MAC addr. */ +#define NIG_REG_LLH0_CLS_TYPE 0x16080 /* [RW 32] cm header for llh0 */ #define NIG_REG_LLH0_CM_HEADER 0x1007c +#define NIG_REG_LLH0_DEST_IP_0_1 0x101dc +#define NIG_REG_LLH0_DEST_MAC_0_0 0x101c0 +/* [RW 16] destination TCP address 1. The LLH will look for this address in + all incoming packets. */ +#define NIG_REG_LLH0_DEST_TCP_0 0x10220 +/* [RW 16] destination UDP address 1 The LLH will look for this address in + all incoming packets. */ +#define NIG_REG_LLH0_DEST_UDP_0 0x10214 #define NIG_REG_LLH0_ERROR_MASK 0x1008c /* [RW 8] event id for llh0 */ #define NIG_REG_LLH0_EVENT_ID 0x10084 +#define NIG_REG_LLH0_FUNC_EN 0x160fc +#define NIG_REG_LLH0_FUNC_VLAN_ID 0x16100 +/* [RW 1] Determine the IP version to look for in + ~nig_registers_llh0_dest_ip_0.llh0_dest_ip_0. 0 - IPv6; 1-IPv4 */ +#define NIG_REG_LLH0_IPV4_IPV6_0 0x10208 +/* [RW 1] t bit for llh0 */ +#define NIG_REG_LLH0_T_BIT 0x10074 +/* [RW 12] VLAN ID 1. In case of VLAN packet the LLH will look for this ID. */ +#define NIG_REG_LLH0_VLAN_ID_0 0x1022c /* [RW 8] init credit counter for port0 in LLH */ #define NIG_REG_LLH0_XCM_INIT_CREDIT 0x10554 #define NIG_REG_LLH0_XCM_MASK 0x10130 /* [RW 1] send to BRB1 if no match on any of RMP rules. */ #define NIG_REG_LLH1_BRB1_NOT_MCP 0x102dc +/* [RW 2] Determine the classification participants. 0: no classification.1: + classification upon VLAN id. 2: classification upon MAC address. 3: + classification upon both VLAN id & MAC addr. */ +#define NIG_REG_LLH1_CLS_TYPE 0x16084 /* [RW 32] cm header for llh1 */ #define NIG_REG_LLH1_CM_HEADER 0x10080 #define NIG_REG_LLH1_ERROR_MASK 0x10090 @@ -1491,13 +1691,26 @@ /* [RW 8] init credit counter for port1 in LLH */ #define NIG_REG_LLH1_XCM_INIT_CREDIT 0x10564 #define NIG_REG_LLH1_XCM_MASK 0x10134 +/* [RW 1] When this bit is set; the LLH will expect all packets to be with + e1hov */ +#define NIG_REG_LLH_E1HOV_MODE 0x160d8 +/* [RW 1] When this bit is set; the LLH will classify the packet before + sending it to the BRB or calculating WoL on it. */ +#define NIG_REG_LLH_MF_MODE 0x16024 #define NIG_REG_MASK_INTERRUPT_PORT0 0x10330 #define NIG_REG_MASK_INTERRUPT_PORT1 0x10334 /* [RW 1] Output signal from NIG to EMAC0. When set enables the EMAC0 block. */ #define NIG_REG_NIG_EMAC0_EN 0x1003c +/* [RW 1] Output signal from NIG to EMAC1. When set enables the EMAC1 block. */ +#define NIG_REG_NIG_EMAC1_EN 0x10040 /* [RW 1] Output signal from NIG to TX_EMAC0. When set indicates to the EMAC0 to strip the CRC from the ingress packets. */ #define NIG_REG_NIG_INGRESS_EMAC0_NO_CRC 0x10044 +/* [R 32] Interrupt register #0 read */ +#define NIG_REG_NIG_INT_STS_0 0x103b0 +#define NIG_REG_NIG_INT_STS_1 0x103c0 +/* [R 32] Parity register #0 read */ +#define NIG_REG_NIG_PRTY_STS 0x103d0 /* [RW 1] Input enable for RX PBF LP IF */ #define NIG_REG_PBF_LB_IN_EN 0x100b4 /* [RW 1] Value of this register will be transmitted to port swap when @@ -1514,9 +1727,21 @@ /* [R 32] Rx statistics : In user packets discarded due to BRB backpressure for port0 */ #define NIG_REG_STAT0_BRB_DISCARD 0x105f0 +/* [WB_R 36] Tx statistics : Number of packets from emac0 or bmac0 that + between 1024 and 1522 bytes for port0 */ +#define NIG_REG_STAT0_EGRESS_MAC_PKT0 0x10750 +/* [WB_R 36] Tx statistics : Number of packets from emac0 or bmac0 that + between 1523 bytes and above for port0 */ +#define NIG_REG_STAT0_EGRESS_MAC_PKT1 0x10760 /* [R 32] Rx statistics : In user packets discarded due to BRB backpressure for port1 */ #define NIG_REG_STAT1_BRB_DISCARD 0x10628 +/* [WB_R 36] Tx statistics : Number of packets from emac1 or bmac1 that + between 1024 and 1522 bytes for port1 */ +#define NIG_REG_STAT1_EGRESS_MAC_PKT0 0x107a0 +/* [WB_R 36] Tx statistics : Number of packets from emac1 or bmac1 that + between 1523 bytes and above for port1 */ +#define NIG_REG_STAT1_EGRESS_MAC_PKT1 0x107b0 /* [WB_R 64] Rx statistics : User octets received for LP */ #define NIG_REG_STAT2_BRB_OCTET 0x107e0 #define NIG_REG_STATUS_INTERRUPT_PORT0 0x10328 @@ -1529,8 +1754,12 @@ #define NIG_REG_XCM0_OUT_EN 0x100f0 /* [RW 1] output enable for RX_XCM1 IF */ #define NIG_REG_XCM1_OUT_EN 0x100f4 +/* [RW 1] control to xgxs - remote PHY in-band MDIO */ +#define NIG_REG_XGXS0_CTRL_EXTREMOTEMDIOST 0x10348 /* [RW 5] control to xgxs - CL45 DEVAD */ #define NIG_REG_XGXS0_CTRL_MD_DEVAD 0x1033c +/* [RW 1] control to xgxs; 0 - clause 45; 1 - clause 22 */ +#define NIG_REG_XGXS0_CTRL_MD_ST 0x10338 /* [RW 5] control to xgxs - CL22 PHY_ADD and CL45 PRTAD */ #define NIG_REG_XGXS0_CTRL_PHY_ADDR 0x10340 /* [R 1] status from xgxs0 that inputs to interrupt logic of link10g. */ @@ -1626,7 +1855,6 @@ #define PRS_REG_CFC_SEARCH_INITIAL_CREDIT 0x4011c /* [RW 24] CID for port 0 if no match */ #define PRS_REG_CID_PORT_0 0x400fc -#define PRS_REG_CID_PORT_1 0x40100 /* [RW 32] The CM header for flush message where 'load existed' bit in CFC load response is reset and packet type is 0. Used in packet start message to TCM. */ @@ -1658,11 +1886,15 @@ #define PRS_REG_CM_HDR_TYPE_4 0x40088 /* [RW 32] The CM header in case there was not a match on the connection */ #define PRS_REG_CM_NO_MATCH_HDR 0x400b8 +/* [RW 1] Indicates if in e1hov mode. 0=non-e1hov mode; 1=e1hov mode. */ +#define PRS_REG_E1HOV_MODE 0x401c8 /* [RW 8] The 8-bit event ID for a match and packet type 1. Used in packet start message to TCM. */ #define PRS_REG_EVENT_ID_1 0x40054 #define PRS_REG_EVENT_ID_2 0x40058 #define PRS_REG_EVENT_ID_3 0x4005c +/* [RW 16] The Ethernet type value for FCoE */ +#define PRS_REG_FCOE_TYPE 0x401d0 /* [RW 8] Context region for flush packet with packet type 0. Used in CFC load request message. */ #define PRS_REG_FLUSH_REGIONS_TYPE_0 0x40004 @@ -1730,8 +1962,17 @@ #define PXP2_REG_HST_DATA_FIFO_STATUS 0x12047c /* [R 7] Debug only: Number of used entries in the header FIFO */ #define PXP2_REG_HST_HEADER_FIFO_STATUS 0x120478 +#define PXP2_REG_PGL_ADDR_88_F0 0x120534 +#define PXP2_REG_PGL_ADDR_8C_F0 0x120538 +#define PXP2_REG_PGL_ADDR_90_F0 0x12053c +#define PXP2_REG_PGL_ADDR_94_F0 0x120540 #define PXP2_REG_PGL_CONTROL0 0x120490 #define PXP2_REG_PGL_CONTROL1 0x120514 +/* [RW 32] third dword data of expansion rom request. this register is + special. reading from it provides a vector outstanding read requests. if + a bit is zero it means that a read request on the corresponding tag did + not finish yet (not all completions have arrived for it) */ +#define PXP2_REG_PGL_EXP_ROM2 0x120808 /* [RW 32] Inbound interrupt table for CSDM: bits[31:16]-mask; its[15:0]-address */ #define PXP2_REG_PGL_INT_CSDM_0 0x1204f4 @@ -1775,8 +2016,7 @@ /* [R 1] this bit indicates that a read request was blocked because of bus_master_en was deasserted */ #define PXP2_REG_PGL_READ_BLOCKED 0x120568 -/* [R 6] debug only */ -#define PXP2_REG_PGL_TXR_CDTS 0x120528 +#define PXP2_REG_PGL_TAGS_LIMIT 0x1205a8 /* [R 18] debug only */ #define PXP2_REG_PGL_TXW_CDTS 0x12052c /* [R 1] this bit indicates that a write request was blocked because of @@ -1828,12 +2068,14 @@ #define PXP2_REG_PSWRQ_QM0_L2P 0x120038 #define PXP2_REG_PSWRQ_SRC0_L2P 0x120054 #define PXP2_REG_PSWRQ_TM0_L2P 0x12001c -/* [RW 25] Interrupt mask register #0 read/write */ -#define PXP2_REG_PXP2_INT_MASK 0x120578 -/* [R 25] Interrupt register #0 read */ -#define PXP2_REG_PXP2_INT_STS 0x12056c -/* [RC 25] Interrupt register #0 read clear */ -#define PXP2_REG_PXP2_INT_STS_CLR 0x120570 +#define PXP2_REG_PSWRQ_TSDM0_L2P 0x1200e0 +/* [RW 32] Interrupt mask register #0 read/write */ +#define PXP2_REG_PXP2_INT_MASK_0 0x120578 +/* [R 32] Interrupt register #0 read */ +#define PXP2_REG_PXP2_INT_STS_0 0x12056c +#define PXP2_REG_PXP2_INT_STS_1 0x120608 +/* [RC 32] Interrupt register #0 read clear */ +#define PXP2_REG_PXP2_INT_STS_CLR_0 0x120570 /* [RW 32] Parity mask register #0 read/write */ #define PXP2_REG_PXP2_PRTY_MASK_0 0x120588 #define PXP2_REG_PXP2_PRTY_MASK_1 0x120598 @@ -2016,8 +2258,12 @@ #define PXP2_REG_RQ_BW_WR_UBOUND29 0x1202a4 /* [RW 7] Bandwidth upper bound for VQ30 */ #define PXP2_REG_RQ_BW_WR_UBOUND30 0x1202a8 +/* [RW 18] external first_mem_addr field in L2P table for CDU module port 0 */ +#define PXP2_REG_RQ_CDU0_EFIRST_MEM_ADDR 0x120008 /* [RW 2] Endian mode for cdu */ #define PXP2_REG_RQ_CDU_ENDIAN_M 0x1201a0 +#define PXP2_REG_RQ_CDU_FIRST_ILT 0x12061c +#define PXP2_REG_RQ_CDU_LAST_ILT 0x120620 /* [RW 3] page size in L2P table for CDU module; -4k; -8k; -16k; -32k; -64k; -128k */ #define PXP2_REG_RQ_CDU_P_SIZE 0x120018 @@ -2029,14 +2275,26 @@ /* [RW 1] When '1'; requests will enter input buffers but wont get out towards the glue */ #define PXP2_REG_RQ_DISABLE_INPUTS 0x120330 +/* [RW 1] 1 - SR will be aligned by 64B; 0 - SR will be aligned by 8B */ +#define PXP2_REG_RQ_DRAM_ALIGN 0x1205b0 +/* [RW 1] If 1 ILT failiue will not result in ELT access; An interrupt will + be asserted */ +#define PXP2_REG_RQ_ELT_DISABLE 0x12066c /* [RW 2] Endian mode for hc */ #define PXP2_REG_RQ_HC_ENDIAN_M 0x1201a8 +/* [RW 1] when '0' ILT logic will work as in A0; otherwise B0; for back + compatibility needs; Note that different registers are used per mode */ +#define PXP2_REG_RQ_ILT_MODE 0x1205b4 /* [WB 53] Onchip address table */ #define PXP2_REG_RQ_ONCHIP_AT 0x122000 +/* [WB 53] Onchip address table - B0 */ +#define PXP2_REG_RQ_ONCHIP_AT_B0 0x128000 /* [RW 13] Pending read limiter threshold; in Dwords */ #define PXP2_REG_RQ_PDR_LIMIT 0x12033c /* [RW 2] Endian mode for qm */ #define PXP2_REG_RQ_QM_ENDIAN_M 0x120194 +#define PXP2_REG_RQ_QM_FIRST_ILT 0x120634 +#define PXP2_REG_RQ_QM_LAST_ILT 0x120638 /* [RW 3] page size in L2P table for QM module; -4k; -8k; -16k; -32k; -64k; -128k */ #define PXP2_REG_RQ_QM_P_SIZE 0x120050 @@ -2050,16 +2308,22 @@ #define PXP2_REG_RQ_RD_MBS1 0x120168 /* [RW 2] Endian mode for src */ #define PXP2_REG_RQ_SRC_ENDIAN_M 0x12019c +#define PXP2_REG_RQ_SRC_FIRST_ILT 0x12063c +#define PXP2_REG_RQ_SRC_LAST_ILT 0x120640 /* [RW 3] page size in L2P table for SRC module; -4k; -8k; -16k; -32k; -64k; -128k */ #define PXP2_REG_RQ_SRC_P_SIZE 0x12006c /* [RW 2] Endian mode for tm */ #define PXP2_REG_RQ_TM_ENDIAN_M 0x120198 +#define PXP2_REG_RQ_TM_FIRST_ILT 0x120644 +#define PXP2_REG_RQ_TM_LAST_ILT 0x120648 /* [RW 3] page size in L2P table for TM module; -4k; -8k; -16k; -32k; -64k; -128k */ #define PXP2_REG_RQ_TM_P_SIZE 0x120034 /* [R 5] Number of entries in the ufifo; his fifo has l2p completions */ #define PXP2_REG_RQ_UFIFO_NUM_OF_ENTRY 0x12080c +/* [RW 18] external first_mem_addr field in L2P table for USDM module port 0 */ +#define PXP2_REG_RQ_USDM0_EFIRST_MEM_ADDR 0x120094 /* [R 8] Number of entries occupied by vq 0 in pswrq memory */ #define PXP2_REG_RQ_VQ0_ENTRY_CNT 0x120810 /* [R 8] Number of entries occupied by vq 10 in pswrq memory */ @@ -2130,19 +2394,63 @@ /* [RW 3] Max burst size filed for write requests port 1; 000 - 128B; 001:256B; 010: 512B; */ #define PXP2_REG_RQ_WR_MBS1 0x120164 +/* [RW 2] 0 - 128B; - 256B; - 512B; - 1024B; when the payload in the + buffer reaches this number has_payload will be asserted */ +#define PXP2_REG_WR_CDU_MPS 0x1205f0 +/* [RW 2] 0 - 128B; - 256B; - 512B; - 1024B; when the payload in the + buffer reaches this number has_payload will be asserted */ +#define PXP2_REG_WR_CSDM_MPS 0x1205d0 +/* [RW 2] 0 - 128B; - 256B; - 512B; - 1024B; when the payload in the + buffer reaches this number has_payload will be asserted */ +#define PXP2_REG_WR_DBG_MPS 0x1205e8 +/* [RW 2] 0 - 128B; - 256B; - 512B; - 1024B; when the payload in the + buffer reaches this number has_payload will be asserted */ +#define PXP2_REG_WR_DMAE_MPS 0x1205ec /* [RW 10] if Number of entries in dmae fifo will be higer than this threshold then has_payload indication will be asserted; the default value should be equal to > write MBS size! */ #define PXP2_REG_WR_DMAE_TH 0x120368 +/* [RW 2] 0 - 128B; - 256B; - 512B; - 1024B; when the payload in the + buffer reaches this number has_payload will be asserted */ +#define PXP2_REG_WR_HC_MPS 0x1205c8 +/* [RW 2] 0 - 128B; - 256B; - 512B; - 1024B; when the payload in the + buffer reaches this number has_payload will be asserted */ +#define PXP2_REG_WR_QM_MPS 0x1205dc +/* [RW 1] 0 - working in A0 mode; - working in B0 mode */ +#define PXP2_REG_WR_REV_MODE 0x120670 +/* [RW 2] 0 - 128B; - 256B; - 512B; - 1024B; when the payload in the + buffer reaches this number has_payload will be asserted */ +#define PXP2_REG_WR_SRC_MPS 0x1205e4 +/* [RW 2] 0 - 128B; - 256B; - 512B; - 1024B; when the payload in the + buffer reaches this number has_payload will be asserted */ +#define PXP2_REG_WR_TM_MPS 0x1205e0 +/* [RW 2] 0 - 128B; - 256B; - 512B; - 1024B; when the payload in the + buffer reaches this number has_payload will be asserted */ +#define PXP2_REG_WR_TSDM_MPS 0x1205d4 /* [RW 10] if Number of entries in usdmdp fifo will be higer than this threshold then has_payload indication will be asserted; the default value should be equal to > write MBS size! */ #define PXP2_REG_WR_USDMDP_TH 0x120348 +/* [RW 2] 0 - 128B; - 256B; - 512B; - 1024B; when the payload in the + buffer reaches this number has_payload will be asserted */ +#define PXP2_REG_WR_USDM_MPS 0x1205cc +/* [RW 2] 0 - 128B; - 256B; - 512B; - 1024B; when the payload in the + buffer reaches this number has_payload will be asserted */ +#define PXP2_REG_WR_XSDM_MPS 0x1205d8 /* [R 1] debug only: Indication if PSWHST arbiter is idle */ #define PXP_REG_HST_ARB_IS_IDLE 0x103004 /* [R 8] debug only: A bit mask for all PSWHST arbiter clients. '1' means this client is waiting for the arbiter. */ #define PXP_REG_HST_CLIENTS_WAITING_TO_ARB 0x103008 +/* [R 1] debug only: '1' means this PSWHST is discarding doorbells. This bit + should update accoring to 'hst_discard_doorbells' register when the state + machine is idle */ +#define PXP_REG_HST_DISCARD_DOORBELLS_STATUS 0x1030a0 +/* [R 6] debug only: A bit mask for all PSWHST internal write clients. '1' + means this PSWHST is discarding inputs from this client. Each bit should + update accoring to 'hst_discard_internal_writes' register when the state + machine is idle. */ +#define PXP_REG_HST_DISCARD_INTERNAL_WRITES_STATUS 0x10309c /* [WB 160] Used for initialization of the inbound interrupts memory */ #define PXP_REG_HST_INBOUND_INT 0x103800 /* [RW 32] Interrupt mask register #0 read/write */ @@ -2165,18 +2473,25 @@ #define QM_REG_ACTCTRINITVAL_3 0x16804c /* [RW 32] The base logical address (in bytes) of each physical queue. The index I represents the physical queue number. The 12 lsbs are ignore and - considered zero so practically there are only 20 bits in this register. */ + considered zero so practically there are only 20 bits in this register; + queues 63-0 */ #define QM_REG_BASEADDR 0x168900 /* [RW 16] The byte credit cost for each task. This value is for both ports */ #define QM_REG_BYTECRDCOST 0x168234 /* [RW 16] The initial byte credit value for both ports. */ #define QM_REG_BYTECRDINITVAL 0x168238 /* [RW 32] A bit per physical queue. If the bit is cleared then the physical - queue uses port 0 else it uses port 1. */ + queue uses port 0 else it uses port 1; queues 31-0 */ #define QM_REG_BYTECRDPORT_LSB 0x168228 /* [RW 32] A bit per physical queue. If the bit is cleared then the physical - queue uses port 0 else it uses port 1. */ + queue uses port 0 else it uses port 1; queues 95-64 */ +#define QM_REG_BYTECRDPORT_LSB_EXT_A 0x16e520 +/* [RW 32] A bit per physical queue. If the bit is cleared then the physical + queue uses port 0 else it uses port 1; queues 63-32 */ #define QM_REG_BYTECRDPORT_MSB 0x168224 +/* [RW 32] A bit per physical queue. If the bit is cleared then the physical + queue uses port 0 else it uses port 1; queues 127-96 */ +#define QM_REG_BYTECRDPORT_MSB_EXT_A 0x16e51c /* [RW 16] The byte credit value that if above the QM is considered almost full */ #define QM_REG_BYTECREDITAFULLTHR 0x168094 @@ -2203,7 +2518,7 @@ #define QM_REG_CMINTVOQMASK_6 0x16820c #define QM_REG_CMINTVOQMASK_7 0x168210 /* [RW 20] The number of connections divided by 16 which dictates the size - of each queue per port 0 */ + of each queue which belongs to even function number. */ #define QM_REG_CONNNUM_0 0x168020 /* [R 6] Keep the fill level of the fifo from write client 4 */ #define QM_REG_CQM_WRC_FIFOLVL 0x168018 @@ -2216,74 +2531,179 @@ bypass enable */ #define QM_REG_ENBYPVOQMASK 0x16823c /* [RW 32] A bit mask per each physical queue. If a bit is set then the - physical queue uses the byte credit */ + physical queue uses the byte credit; queues 31-0 */ #define QM_REG_ENBYTECRD_LSB 0x168220 /* [RW 32] A bit mask per each physical queue. If a bit is set then the - physical queue uses the byte credit */ + physical queue uses the byte credit; queues 95-64 */ +#define QM_REG_ENBYTECRD_LSB_EXT_A 0x16e518 +/* [RW 32] A bit mask per each physical queue. If a bit is set then the + physical queue uses the byte credit; queues 63-32 */ #define QM_REG_ENBYTECRD_MSB 0x16821c +/* [RW 32] A bit mask per each physical queue. If a bit is set then the + physical queue uses the byte credit; queues 127-96 */ +#define QM_REG_ENBYTECRD_MSB_EXT_A 0x16e514 /* [RW 4] If cleared then the secondary interface will not be served by the RR arbiter */ #define QM_REG_ENSEC 0x1680f0 -/* [RW 32] A bit vector per each physical queue which selects which function - number to use on PCI access for that queue. */ +/* [RW 32] NA */ #define QM_REG_FUNCNUMSEL_LSB 0x168230 -/* [RW 32] A bit vector per each physical queue which selects which function - number to use on PCI access for that queue. */ +/* [RW 32] NA */ #define QM_REG_FUNCNUMSEL_MSB 0x16822c /* [RW 32] A mask register to mask the Almost empty signals which will not - be use for the almost empty indication to the HW block */ + be use for the almost empty indication to the HW block; queues 31:0 */ #define QM_REG_HWAEMPTYMASK_LSB 0x168218 /* [RW 32] A mask register to mask the Almost empty signals which will not - be use for the almost empty indication to the HW block */ + be use for the almost empty indication to the HW block; queues 95-64 */ +#define QM_REG_HWAEMPTYMASK_LSB_EXT_A 0x16e510 +/* [RW 32] A mask register to mask the Almost empty signals which will not + be use for the almost empty indication to the HW block; queues 63:32 */ #define QM_REG_HWAEMPTYMASK_MSB 0x168214 +/* [RW 32] A mask register to mask the Almost empty signals which will not + be use for the almost empty indication to the HW block; queues 127-96 */ +#define QM_REG_HWAEMPTYMASK_MSB_EXT_A 0x16e50c /* [RW 4] The number of outstanding request to CFC */ #define QM_REG_OUTLDREQ 0x168804 /* [RC 1] A flag to indicate that overflow error occurred in one of the queues. */ #define QM_REG_OVFERROR 0x16805c -/* [RC 6] the Q were the qverflow occurs */ +/* [RC 7] the Q were the qverflow occurs */ #define QM_REG_OVFQNUM 0x168058 -/* [R 32] Pause state for physical queues 31-0 */ +/* [R 16] Pause state for physical queues 15-0 */ #define QM_REG_PAUSESTATE0 0x168410 -/* [R 32] Pause state for physical queues 64-32 */ +/* [R 16] Pause state for physical queues 31-16 */ #define QM_REG_PAUSESTATE1 0x168414 +/* [R 16] Pause state for physical queues 47-32 */ +#define QM_REG_PAUSESTATE2 0x16e684 +/* [R 16] Pause state for physical queues 63-48 */ +#define QM_REG_PAUSESTATE3 0x16e688 +/* [R 16] Pause state for physical queues 79-64 */ +#define QM_REG_PAUSESTATE4 0x16e68c +/* [R 16] Pause state for physical queues 95-80 */ +#define QM_REG_PAUSESTATE5 0x16e690 +/* [R 16] Pause state for physical queues 111-96 */ +#define QM_REG_PAUSESTATE6 0x16e694 +/* [R 16] Pause state for physical queues 127-112 */ +#define QM_REG_PAUSESTATE7 0x16e698 /* [RW 2] The PCI attributes field used in the PCI request. */ #define QM_REG_PCIREQAT 0x168054 /* [R 16] The byte credit of port 0 */ #define QM_REG_PORT0BYTECRD 0x168300 /* [R 16] The byte credit of port 1 */ #define QM_REG_PORT1BYTECRD 0x168304 -/* [WB 54] Pointer Table Memory; The mapping is as follow: ptrtbl[53:30] - read pointer; ptrtbl[29:6] write pointer; ptrtbl[5:4] read bank0; - ptrtbl[3:2] read bank 1; ptrtbl[1:0] write bank; */ +/* [RW 3] pci function number of queues 15-0 */ +#define QM_REG_PQ2PCIFUNC_0 0x16e6bc +#define QM_REG_PQ2PCIFUNC_1 0x16e6c0 +#define QM_REG_PQ2PCIFUNC_2 0x16e6c4 +#define QM_REG_PQ2PCIFUNC_3 0x16e6c8 +#define QM_REG_PQ2PCIFUNC_4 0x16e6cc +#define QM_REG_PQ2PCIFUNC_5 0x16e6d0 +#define QM_REG_PQ2PCIFUNC_6 0x16e6d4 +#define QM_REG_PQ2PCIFUNC_7 0x16e6d8 +/* [WB 54] Pointer Table Memory for queues 63-0; The mapping is as follow: + ptrtbl[53:30] read pointer; ptrtbl[29:6] write pointer; ptrtbl[5:4] read + bank0; ptrtbl[3:2] read bank 1; ptrtbl[1:0] write bank; */ #define QM_REG_PTRTBL 0x168a00 +/* [WB 54] Pointer Table Memory for queues 127-64; The mapping is as follow: + ptrtbl[53:30] read pointer; ptrtbl[29:6] write pointer; ptrtbl[5:4] read + bank0; ptrtbl[3:2] read bank 1; ptrtbl[1:0] write bank; */ +#define QM_REG_PTRTBL_EXT_A 0x16e200 /* [RW 2] Interrupt mask register #0 read/write */ #define QM_REG_QM_INT_MASK 0x168444 /* [R 2] Interrupt register #0 read */ #define QM_REG_QM_INT_STS 0x168438 -/* [RW 9] Parity mask register #0 read/write */ +/* [RW 12] Parity mask register #0 read/write */ #define QM_REG_QM_PRTY_MASK 0x168454 -/* [R 9] Parity register #0 read */ +/* [R 12] Parity register #0 read */ #define QM_REG_QM_PRTY_STS 0x168448 /* [R 32] Current queues in pipeline: Queues from 32 to 63 */ #define QM_REG_QSTATUS_HIGH 0x16802c +/* [R 32] Current queues in pipeline: Queues from 96 to 127 */ +#define QM_REG_QSTATUS_HIGH_EXT_A 0x16e408 /* [R 32] Current queues in pipeline: Queues from 0 to 31 */ #define QM_REG_QSTATUS_LOW 0x168028 -/* [R 24] The number of tasks queued for each queue */ +/* [R 32] Current queues in pipeline: Queues from 64 to 95 */ +#define QM_REG_QSTATUS_LOW_EXT_A 0x16e404 +/* [R 24] The number of tasks queued for each queue; queues 63-0 */ #define QM_REG_QTASKCTR_0 0x168308 +/* [R 24] The number of tasks queued for each queue; queues 127-64 */ +#define QM_REG_QTASKCTR_EXT_A_0 0x16e584 /* [RW 4] Queue tied to VOQ */ #define QM_REG_QVOQIDX_0 0x1680f4 #define QM_REG_QVOQIDX_10 0x16811c +#define QM_REG_QVOQIDX_100 0x16e49c +#define QM_REG_QVOQIDX_101 0x16e4a0 +#define QM_REG_QVOQIDX_102 0x16e4a4 +#define QM_REG_QVOQIDX_103 0x16e4a8 +#define QM_REG_QVOQIDX_104 0x16e4ac +#define QM_REG_QVOQIDX_105 0x16e4b0 +#define QM_REG_QVOQIDX_106 0x16e4b4 +#define QM_REG_QVOQIDX_107 0x16e4b8 +#define QM_REG_QVOQIDX_108 0x16e4bc +#define QM_REG_QVOQIDX_109 0x16e4c0 +#define QM_REG_QVOQIDX_100 0x16e49c +#define QM_REG_QVOQIDX_101 0x16e4a0 +#define QM_REG_QVOQIDX_102 0x16e4a4 +#define QM_REG_QVOQIDX_103 0x16e4a8 +#define QM_REG_QVOQIDX_104 0x16e4ac +#define QM_REG_QVOQIDX_105 0x16e4b0 +#define QM_REG_QVOQIDX_106 0x16e4b4 +#define QM_REG_QVOQIDX_107 0x16e4b8 +#define QM_REG_QVOQIDX_108 0x16e4bc +#define QM_REG_QVOQIDX_109 0x16e4c0 #define QM_REG_QVOQIDX_11 0x168120 +#define QM_REG_QVOQIDX_110 0x16e4c4 +#define QM_REG_QVOQIDX_111 0x16e4c8 +#define QM_REG_QVOQIDX_112 0x16e4cc +#define QM_REG_QVOQIDX_113 0x16e4d0 +#define QM_REG_QVOQIDX_114 0x16e4d4 +#define QM_REG_QVOQIDX_115 0x16e4d8 +#define QM_REG_QVOQIDX_116 0x16e4dc +#define QM_REG_QVOQIDX_117 0x16e4e0 +#define QM_REG_QVOQIDX_118 0x16e4e4 +#define QM_REG_QVOQIDX_119 0x16e4e8 +#define QM_REG_QVOQIDX_110 0x16e4c4 +#define QM_REG_QVOQIDX_111 0x16e4c8 +#define QM_REG_QVOQIDX_112 0x16e4cc +#define QM_REG_QVOQIDX_113 0x16e4d0 +#define QM_REG_QVOQIDX_114 0x16e4d4 +#define QM_REG_QVOQIDX_115 0x16e4d8 +#define QM_REG_QVOQIDX_116 0x16e4dc +#define QM_REG_QVOQIDX_117 0x16e4e0 +#define QM_REG_QVOQIDX_118 0x16e4e4 +#define QM_REG_QVOQIDX_119 0x16e4e8 #define QM_REG_QVOQIDX_12 0x168124 +#define QM_REG_QVOQIDX_120 0x16e4ec +#define QM_REG_QVOQIDX_121 0x16e4f0 +#define QM_REG_QVOQIDX_122 0x16e4f4 +#define QM_REG_QVOQIDX_123 0x16e4f8 +#define QM_REG_QVOQIDX_124 0x16e4fc +#define QM_REG_QVOQIDX_125 0x16e500 +#define QM_REG_QVOQIDX_126 0x16e504 +#define QM_REG_QVOQIDX_127 0x16e508 +#define QM_REG_QVOQIDX_120 0x16e4ec +#define QM_REG_QVOQIDX_121 0x16e4f0 +#define QM_REG_QVOQIDX_122 0x16e4f4 +#define QM_REG_QVOQIDX_123 0x16e4f8 +#define QM_REG_QVOQIDX_124 0x16e4fc +#define QM_REG_QVOQIDX_125 0x16e500 +#define QM_REG_QVOQIDX_126 0x16e504 +#define QM_REG_QVOQIDX_127 0x16e508 #define QM_REG_QVOQIDX_13 0x168128 #define QM_REG_QVOQIDX_14 0x16812c #define QM_REG_QVOQIDX_15 0x168130 #define QM_REG_QVOQIDX_16 0x168134 #define QM_REG_QVOQIDX_17 0x168138 #define QM_REG_QVOQIDX_21 0x168148 +#define QM_REG_QVOQIDX_22 0x16814c +#define QM_REG_QVOQIDX_23 0x168150 +#define QM_REG_QVOQIDX_24 0x168154 #define QM_REG_QVOQIDX_25 0x168158 +#define QM_REG_QVOQIDX_26 0x16815c +#define QM_REG_QVOQIDX_27 0x168160 +#define QM_REG_QVOQIDX_28 0x168164 #define QM_REG_QVOQIDX_29 0x168168 +#define QM_REG_QVOQIDX_30 0x16816c +#define QM_REG_QVOQIDX_31 0x168170 #define QM_REG_QVOQIDX_32 0x168174 #define QM_REG_QVOQIDX_33 0x168178 #define QM_REG_QVOQIDX_34 0x16817c @@ -2328,17 +2748,79 @@ #define QM_REG_QVOQIDX_61 0x1681e8 #define QM_REG_QVOQIDX_62 0x1681ec #define QM_REG_QVOQIDX_63 0x1681f0 +#define QM_REG_QVOQIDX_64 0x16e40c +#define QM_REG_QVOQIDX_65 0x16e410 +#define QM_REG_QVOQIDX_66 0x16e414 +#define QM_REG_QVOQIDX_67 0x16e418 +#define QM_REG_QVOQIDX_68 0x16e41c +#define QM_REG_QVOQIDX_69 0x16e420 #define QM_REG_QVOQIDX_60 0x1681e4 #define QM_REG_QVOQIDX_61 0x1681e8 #define QM_REG_QVOQIDX_62 0x1681ec #define QM_REG_QVOQIDX_63 0x1681f0 +#define QM_REG_QVOQIDX_64 0x16e40c +#define QM_REG_QVOQIDX_65 0x16e410 +#define QM_REG_QVOQIDX_69 0x16e420 #define QM_REG_QVOQIDX_7 0x168110 +#define QM_REG_QVOQIDX_70 0x16e424 +#define QM_REG_QVOQIDX_71 0x16e428 +#define QM_REG_QVOQIDX_72 0x16e42c +#define QM_REG_QVOQIDX_73 0x16e430 +#define QM_REG_QVOQIDX_74 0x16e434 +#define QM_REG_QVOQIDX_75 0x16e438 +#define QM_REG_QVOQIDX_76 0x16e43c +#define QM_REG_QVOQIDX_77 0x16e440 +#define QM_REG_QVOQIDX_78 0x16e444 +#define QM_REG_QVOQIDX_79 0x16e448 +#define QM_REG_QVOQIDX_70 0x16e424 +#define QM_REG_QVOQIDX_71 0x16e428 +#define QM_REG_QVOQIDX_72 0x16e42c +#define QM_REG_QVOQIDX_73 0x16e430 +#define QM_REG_QVOQIDX_74 0x16e434 +#define QM_REG_QVOQIDX_75 0x16e438 +#define QM_REG_QVOQIDX_76 0x16e43c +#define QM_REG_QVOQIDX_77 0x16e440 +#define QM_REG_QVOQIDX_78 0x16e444 +#define QM_REG_QVOQIDX_79 0x16e448 #define QM_REG_QVOQIDX_8 0x168114 +#define QM_REG_QVOQIDX_80 0x16e44c +#define QM_REG_QVOQIDX_81 0x16e450 +#define QM_REG_QVOQIDX_82 0x16e454 +#define QM_REG_QVOQIDX_83 0x16e458 +#define QM_REG_QVOQIDX_84 0x16e45c +#define QM_REG_QVOQIDX_85 0x16e460 +#define QM_REG_QVOQIDX_86 0x16e464 +#define QM_REG_QVOQIDX_87 0x16e468 +#define QM_REG_QVOQIDX_88 0x16e46c +#define QM_REG_QVOQIDX_89 0x16e470 +#define QM_REG_QVOQIDX_80 0x16e44c +#define QM_REG_QVOQIDX_81 0x16e450 +#define QM_REG_QVOQIDX_85 0x16e460 +#define QM_REG_QVOQIDX_86 0x16e464 +#define QM_REG_QVOQIDX_87 0x16e468 +#define QM_REG_QVOQIDX_88 0x16e46c +#define QM_REG_QVOQIDX_89 0x16e470 #define QM_REG_QVOQIDX_9 0x168118 -/* [R 24] Remaining pause timeout for port 0 */ -#define QM_REG_REMAINPAUSETM0 0x168418 -/* [R 24] Remaining pause timeout for port 1 */ -#define QM_REG_REMAINPAUSETM1 0x16841c +#define QM_REG_QVOQIDX_90 0x16e474 +#define QM_REG_QVOQIDX_91 0x16e478 +#define QM_REG_QVOQIDX_92 0x16e47c +#define QM_REG_QVOQIDX_93 0x16e480 +#define QM_REG_QVOQIDX_94 0x16e484 +#define QM_REG_QVOQIDX_95 0x16e488 +#define QM_REG_QVOQIDX_96 0x16e48c +#define QM_REG_QVOQIDX_97 0x16e490 +#define QM_REG_QVOQIDX_98 0x16e494 +#define QM_REG_QVOQIDX_99 0x16e498 +#define QM_REG_QVOQIDX_90 0x16e474 +#define QM_REG_QVOQIDX_91 0x16e478 +#define QM_REG_QVOQIDX_92 0x16e47c +#define QM_REG_QVOQIDX_93 0x16e480 +#define QM_REG_QVOQIDX_94 0x16e484 +#define QM_REG_QVOQIDX_95 0x16e488 +#define QM_REG_QVOQIDX_96 0x16e48c +#define QM_REG_QVOQIDX_97 0x16e490 +#define QM_REG_QVOQIDX_98 0x16e494 +#define QM_REG_QVOQIDX_99 0x16e498 /* [RW 1] Initialization bit command */ #define QM_REG_SOFT_RESET 0x168428 /* [RW 8] The credit cost per every task in the QM. A value per each VOQ */ @@ -2372,44 +2854,103 @@ #define QM_REG_VOQINITCREDIT_4 0x168070 #define QM_REG_VOQINITCREDIT_5 0x168074 /* [RW 1] The port of which VOQ belongs */ +#define QM_REG_VOQPORT_0 0x1682a0 #define QM_REG_VOQPORT_1 0x1682a4 #define QM_REG_VOQPORT_10 0x1682c8 #define QM_REG_VOQPORT_11 0x1682cc #define QM_REG_VOQPORT_2 0x1682a8 -/* [RW 32] The physical queue number associated with each VOQ */ +/* [RW 32] The physical queue number associated with each VOQ; queues 31-0 */ #define QM_REG_VOQQMASK_0_LSB 0x168240 -/* [RW 32] The physical queue number associated with each VOQ */ +/* [RW 32] The physical queue number associated with each VOQ; queues 95-64 */ +#define QM_REG_VOQQMASK_0_LSB_EXT_A 0x16e524 +/* [RW 32] The physical queue number associated with each VOQ; queues 63-32 */ #define QM_REG_VOQQMASK_0_MSB 0x168244 -/* [RW 32] The physical queue number associated with each VOQ */ +/* [RW 32] The physical queue number associated with each VOQ; queues 127-96 */ +#define QM_REG_VOQQMASK_0_MSB_EXT_A 0x16e528 +/* [RW 32] The physical queue number associated with each VOQ; queues 31-0 */ +#define QM_REG_VOQQMASK_10_LSB 0x168290 +/* [RW 32] The physical queue number associated with each VOQ; queues 95-64 */ +#define QM_REG_VOQQMASK_10_LSB_EXT_A 0x16e574 +/* [RW 32] The physical queue number associated with each VOQ; queues 63-32 */ +#define QM_REG_VOQQMASK_10_MSB 0x168294 +/* [RW 32] The physical queue number associated with each VOQ; queues 127-96 */ +#define QM_REG_VOQQMASK_10_MSB_EXT_A 0x16e578 +/* [RW 32] The physical queue number associated with each VOQ; queues 31-0 */ +#define QM_REG_VOQQMASK_11_LSB 0x168298 +/* [RW 32] The physical queue number associated with each VOQ; queues 95-64 */ +#define QM_REG_VOQQMASK_11_LSB_EXT_A 0x16e57c +/* [RW 32] The physical queue number associated with each VOQ; queues 63-32 */ +#define QM_REG_VOQQMASK_11_MSB 0x16829c +/* [RW 32] The physical queue number associated with each VOQ; queues 127-96 */ +#define QM_REG_VOQQMASK_11_MSB_EXT_A 0x16e580 +/* [RW 32] The physical queue number associated with each VOQ; queues 31-0 */ +#define QM_REG_VOQQMASK_1_LSB 0x168248 +/* [RW 32] The physical queue number associated with each VOQ; queues 95-64 */ +#define QM_REG_VOQQMASK_1_LSB_EXT_A 0x16e52c +/* [RW 32] The physical queue number associated with each VOQ; queues 63-32 */ #define QM_REG_VOQQMASK_1_MSB 0x16824c -/* [RW 32] The physical queue number associated with each VOQ */ +/* [RW 32] The physical queue number associated with each VOQ; queues 127-96 */ +#define QM_REG_VOQQMASK_1_MSB_EXT_A 0x16e530 +/* [RW 32] The physical queue number associated with each VOQ; queues 31-0 */ #define QM_REG_VOQQMASK_2_LSB 0x168250 -/* [RW 32] The physical queue number associated with each VOQ */ +/* [RW 32] The physical queue number associated with each VOQ; queues 95-64 */ +#define QM_REG_VOQQMASK_2_LSB_EXT_A 0x16e534 +/* [RW 32] The physical queue number associated with each VOQ; queues 63-32 */ #define QM_REG_VOQQMASK_2_MSB 0x168254 -/* [RW 32] The physical queue number associated with each VOQ */ +/* [RW 32] The physical queue number associated with each VOQ; queues 127-96 */ +#define QM_REG_VOQQMASK_2_MSB_EXT_A 0x16e538 +/* [RW 32] The physical queue number associated with each VOQ; queues 31-0 */ #define QM_REG_VOQQMASK_3_LSB 0x168258 -/* [RW 32] The physical queue number associated with each VOQ */ +/* [RW 32] The physical queue number associated with each VOQ; queues 95-64 */ +#define QM_REG_VOQQMASK_3_LSB_EXT_A 0x16e53c +/* [RW 32] The physical queue number associated with each VOQ; queues 127-96 */ +#define QM_REG_VOQQMASK_3_MSB_EXT_A 0x16e540 +/* [RW 32] The physical queue number associated with each VOQ; queues 31-0 */ #define QM_REG_VOQQMASK_4_LSB 0x168260 -/* [RW 32] The physical queue number associated with each VOQ */ +/* [RW 32] The physical queue number associated with each VOQ; queues 95-64 */ +#define QM_REG_VOQQMASK_4_LSB_EXT_A 0x16e544 +/* [RW 32] The physical queue number associated with each VOQ; queues 63-32 */ #define QM_REG_VOQQMASK_4_MSB 0x168264 -/* [RW 32] The physical queue number associated with each VOQ */ +/* [RW 32] The physical queue number associated with each VOQ; queues 127-96 */ +#define QM_REG_VOQQMASK_4_MSB_EXT_A 0x16e548 +/* [RW 32] The physical queue number associated with each VOQ; queues 31-0 */ #define QM_REG_VOQQMASK_5_LSB 0x168268 -/* [RW 32] The physical queue number associated with each VOQ */ +/* [RW 32] The physical queue number associated with each VOQ; queues 95-64 */ +#define QM_REG_VOQQMASK_5_LSB_EXT_A 0x16e54c +/* [RW 32] The physical queue number associated with each VOQ; queues 63-32 */ #define QM_REG_VOQQMASK_5_MSB 0x16826c -/* [RW 32] The physical queue number associated with each VOQ */ +/* [RW 32] The physical queue number associated with each VOQ; queues 127-96 */ +#define QM_REG_VOQQMASK_5_MSB_EXT_A 0x16e550 +/* [RW 32] The physical queue number associated with each VOQ; queues 31-0 */ #define QM_REG_VOQQMASK_6_LSB 0x168270 -/* [RW 32] The physical queue number associated with each VOQ */ +/* [RW 32] The physical queue number associated with each VOQ; queues 95-64 */ +#define QM_REG_VOQQMASK_6_LSB_EXT_A 0x16e554 +/* [RW 32] The physical queue number associated with each VOQ; queues 63-32 */ #define QM_REG_VOQQMASK_6_MSB 0x168274 -/* [RW 32] The physical queue number associated with each VOQ */ +/* [RW 32] The physical queue number associated with each VOQ; queues 127-96 */ +#define QM_REG_VOQQMASK_6_MSB_EXT_A 0x16e558 +/* [RW 32] The physical queue number associated with each VOQ; queues 31-0 */ #define QM_REG_VOQQMASK_7_LSB 0x168278 -/* [RW 32] The physical queue number associated with each VOQ */ +/* [RW 32] The physical queue number associated with each VOQ; queues 95-64 */ +#define QM_REG_VOQQMASK_7_LSB_EXT_A 0x16e55c +/* [RW 32] The physical queue number associated with each VOQ; queues 63-32 */ #define QM_REG_VOQQMASK_7_MSB 0x16827c -/* [RW 32] The physical queue number associated with each VOQ */ +/* [RW 32] The physical queue number associated with each VOQ; queues 127-96 */ +#define QM_REG_VOQQMASK_7_MSB_EXT_A 0x16e560 +/* [RW 32] The physical queue number associated with each VOQ; queues 31-0 */ #define QM_REG_VOQQMASK_8_LSB 0x168280 -/* [RW 32] The physical queue number associated with each VOQ */ +/* [RW 32] The physical queue number associated with each VOQ; queues 95-64 */ +#define QM_REG_VOQQMASK_8_LSB_EXT_A 0x16e564 +/* [RW 32] The physical queue number associated with each VOQ; queues 63-32 */ #define QM_REG_VOQQMASK_8_MSB 0x168284 -/* [RW 32] The physical queue number associated with each VOQ */ +/* [RW 32] The physical queue number associated with each VOQ; queues 127-96 */ +#define QM_REG_VOQQMASK_8_MSB_EXT_A 0x16e568 +/* [RW 32] The physical queue number associated with each VOQ; queues 31-0 */ #define QM_REG_VOQQMASK_9_LSB 0x168288 +/* [RW 32] The physical queue number associated with each VOQ; queues 95-64 */ +#define QM_REG_VOQQMASK_9_LSB_EXT_A 0x16e56c +/* [RW 32] The physical queue number associated with each VOQ; queues 127-96 */ +#define QM_REG_VOQQMASK_9_MSB_EXT_A 0x16e570 /* [RW 32] Wrr weights */ #define QM_REG_WRRWEIGHTS_0 0x16880c #define QM_REG_WRRWEIGHTS_1 0x168810 @@ -2431,14 +2972,78 @@ #define QM_REG_WRRWEIGHTS_15 0x168828 #define QM_REG_WRRWEIGHTS_15_SIZE 1 /* [RW 32] Wrr weights */ +#define QM_REG_WRRWEIGHTS_16 0x16e000 +#define QM_REG_WRRWEIGHTS_16_SIZE 1 +/* [RW 32] Wrr weights */ +#define QM_REG_WRRWEIGHTS_17 0x16e004 +#define QM_REG_WRRWEIGHTS_17_SIZE 1 +/* [RW 32] Wrr weights */ +#define QM_REG_WRRWEIGHTS_18 0x16e008 +#define QM_REG_WRRWEIGHTS_18_SIZE 1 +/* [RW 32] Wrr weights */ +#define QM_REG_WRRWEIGHTS_19 0x16e00c +#define QM_REG_WRRWEIGHTS_19_SIZE 1 +/* [RW 32] Wrr weights */ #define QM_REG_WRRWEIGHTS_10 0x168814 #define QM_REG_WRRWEIGHTS_11 0x168818 #define QM_REG_WRRWEIGHTS_12 0x16881c #define QM_REG_WRRWEIGHTS_13 0x168820 #define QM_REG_WRRWEIGHTS_14 0x168824 #define QM_REG_WRRWEIGHTS_15 0x168828 +#define QM_REG_WRRWEIGHTS_16 0x16e000 +#define QM_REG_WRRWEIGHTS_17 0x16e004 +#define QM_REG_WRRWEIGHTS_18 0x16e008 +#define QM_REG_WRRWEIGHTS_19 0x16e00c #define QM_REG_WRRWEIGHTS_2 0x16882c +#define QM_REG_WRRWEIGHTS_20 0x16e010 +#define QM_REG_WRRWEIGHTS_20_SIZE 1 +/* [RW 32] Wrr weights */ +#define QM_REG_WRRWEIGHTS_21 0x16e014 +#define QM_REG_WRRWEIGHTS_21_SIZE 1 +/* [RW 32] Wrr weights */ +#define QM_REG_WRRWEIGHTS_22 0x16e018 +#define QM_REG_WRRWEIGHTS_22_SIZE 1 +/* [RW 32] Wrr weights */ +#define QM_REG_WRRWEIGHTS_23 0x16e01c +#define QM_REG_WRRWEIGHTS_23_SIZE 1 +/* [RW 32] Wrr weights */ +#define QM_REG_WRRWEIGHTS_24 0x16e020 +#define QM_REG_WRRWEIGHTS_24_SIZE 1 +/* [RW 32] Wrr weights */ +#define QM_REG_WRRWEIGHTS_25 0x16e024 +#define QM_REG_WRRWEIGHTS_25_SIZE 1 +/* [RW 32] Wrr weights */ +#define QM_REG_WRRWEIGHTS_26 0x16e028 +#define QM_REG_WRRWEIGHTS_26_SIZE 1 +/* [RW 32] Wrr weights */ +#define QM_REG_WRRWEIGHTS_27 0x16e02c +#define QM_REG_WRRWEIGHTS_27_SIZE 1 +/* [RW 32] Wrr weights */ +#define QM_REG_WRRWEIGHTS_28 0x16e030 +#define QM_REG_WRRWEIGHTS_28_SIZE 1 +/* [RW 32] Wrr weights */ +#define QM_REG_WRRWEIGHTS_29 0x16e034 +#define QM_REG_WRRWEIGHTS_29_SIZE 1 +/* [RW 32] Wrr weights */ +#define QM_REG_WRRWEIGHTS_20 0x16e010 +#define QM_REG_WRRWEIGHTS_21 0x16e014 +#define QM_REG_WRRWEIGHTS_22 0x16e018 +#define QM_REG_WRRWEIGHTS_23 0x16e01c +#define QM_REG_WRRWEIGHTS_24 0x16e020 +#define QM_REG_WRRWEIGHTS_25 0x16e024 +#define QM_REG_WRRWEIGHTS_26 0x16e028 +#define QM_REG_WRRWEIGHTS_27 0x16e02c +#define QM_REG_WRRWEIGHTS_28 0x16e030 +#define QM_REG_WRRWEIGHTS_29 0x16e034 #define QM_REG_WRRWEIGHTS_3 0x168830 +#define QM_REG_WRRWEIGHTS_30 0x16e038 +#define QM_REG_WRRWEIGHTS_30_SIZE 1 +/* [RW 32] Wrr weights */ +#define QM_REG_WRRWEIGHTS_31 0x16e03c +#define QM_REG_WRRWEIGHTS_31_SIZE 1 +/* [RW 32] Wrr weights */ +#define QM_REG_WRRWEIGHTS_30 0x16e038 +#define QM_REG_WRRWEIGHTS_31 0x16e03c #define QM_REG_WRRWEIGHTS_4 0x168834 #define QM_REG_WRRWEIGHTS_5 0x168838 #define QM_REG_WRRWEIGHTS_6 0x16883c @@ -2447,6 +3052,70 @@ #define QM_REG_WRRWEIGHTS_9 0x168848 /* [R 6] Keep the fill level of the fifo from write client 1 */ #define QM_REG_XQM_WRC_FIFOLVL 0x168000 +#define BRB1_BRB1_INT_STS_REG_ADDRESS_ERROR (0x1<<0) +#define BRB1_BRB1_INT_STS_REG_ADDRESS_ERROR_SIZE 0 +#define BRB1_BRB1_INT_STS_CLR_REG_ADDRESS_ERROR (0x1<<0) +#define BRB1_BRB1_INT_STS_CLR_REG_ADDRESS_ERROR_SIZE 0 +#define BRB1_BRB1_INT_STS_WR_REG_ADDRESS_ERROR (0x1<<0) +#define BRB1_BRB1_INT_STS_WR_REG_ADDRESS_ERROR_SIZE 0 +#define BRB1_BRB1_INT_MASK_REG_ADDRESS_ERROR (0x1<<0) +#define BRB1_BRB1_INT_MASK_REG_ADDRESS_ERROR_SIZE 0 +#define CCM_CCM_INT_STS_REG_ADDRESS_ERROR (0x1<<0) +#define CCM_CCM_INT_STS_REG_ADDRESS_ERROR_SIZE 0 +#define CCM_CCM_INT_STS_CLR_REG_ADDRESS_ERROR (0x1<<0) +#define CCM_CCM_INT_STS_CLR_REG_ADDRESS_ERROR_SIZE 0 +#define CCM_CCM_INT_STS_WR_REG_ADDRESS_ERROR (0x1<<0) +#define CCM_CCM_INT_STS_WR_REG_ADDRESS_ERROR_SIZE 0 +#define CCM_CCM_INT_MASK_REG_ADDRESS_ERROR (0x1<<0) +#define CCM_CCM_INT_MASK_REG_ADDRESS_ERROR_SIZE 0 +#define CDU_CDU_INT_STS_REG_ADDRESS_ERROR (0x1<<0) +#define CDU_CDU_INT_STS_REG_ADDRESS_ERROR_SIZE 0 +#define CDU_CDU_INT_STS_CLR_REG_ADDRESS_ERROR (0x1<<0) +#define CDU_CDU_INT_STS_CLR_REG_ADDRESS_ERROR_SIZE 0 +#define CDU_CDU_INT_STS_WR_REG_ADDRESS_ERROR (0x1<<0) +#define CDU_CDU_INT_STS_WR_REG_ADDRESS_ERROR_SIZE 0 +#define CDU_CDU_INT_MASK_REG_ADDRESS_ERROR (0x1<<0) +#define CDU_CDU_INT_MASK_REG_ADDRESS_ERROR_SIZE 0 +#define CFC_CFC_INT_STS_REG_ADDRESS_ERROR (0x1<<0) +#define CFC_CFC_INT_STS_REG_ADDRESS_ERROR_SIZE 0 +#define CFC_CFC_INT_STS_CLR_REG_ADDRESS_ERROR (0x1<<0) +#define CFC_CFC_INT_STS_CLR_REG_ADDRESS_ERROR_SIZE 0 +#define CFC_CFC_INT_STS_WR_REG_ADDRESS_ERROR (0x1<<0) +#define CFC_CFC_INT_STS_WR_REG_ADDRESS_ERROR_SIZE 0 +#define CFC_CFC_INT_MASK_REG_ADDRESS_ERROR (0x1<<0) +#define CFC_CFC_INT_MASK_REG_ADDRESS_ERROR_SIZE 0 +#define CSDM_CSDM_INT_STS_0_REG_ADDRESS_ERROR (0x1<<0) +#define CSDM_CSDM_INT_STS_0_REG_ADDRESS_ERROR_SIZE 0 +#define CSDM_CSDM_INT_STS_CLR_0_REG_ADDRESS_ERROR (0x1<<0) +#define CSDM_CSDM_INT_STS_CLR_0_REG_ADDRESS_ERROR_SIZE 0 +#define CSDM_CSDM_INT_STS_WR_0_REG_ADDRESS_ERROR (0x1<<0) +#define CSDM_CSDM_INT_STS_WR_0_REG_ADDRESS_ERROR_SIZE 0 +#define CSDM_CSDM_INT_MASK_0_REG_ADDRESS_ERROR (0x1<<0) +#define CSDM_CSDM_INT_MASK_0_REG_ADDRESS_ERROR_SIZE 0 +#define CSEM_CSEM_INT_STS_0_REG_ADDRESS_ERROR (0x1<<0) +#define CSEM_CSEM_INT_STS_0_REG_ADDRESS_ERROR_SIZE 0 +#define CSEM_CSEM_INT_STS_CLR_0_REG_ADDRESS_ERROR (0x1<<0) +#define CSEM_CSEM_INT_STS_CLR_0_REG_ADDRESS_ERROR_SIZE 0 +#define CSEM_CSEM_INT_STS_WR_0_REG_ADDRESS_ERROR (0x1<<0) +#define CSEM_CSEM_INT_STS_WR_0_REG_ADDRESS_ERROR_SIZE 0 +#define CSEM_CSEM_INT_MASK_0_REG_ADDRESS_ERROR (0x1<<0) +#define CSEM_CSEM_INT_MASK_0_REG_ADDRESS_ERROR_SIZE 0 +#define DBG_DBG_INT_STS_REG_ADDRESS_ERROR (0x1<<0) +#define DBG_DBG_INT_STS_REG_ADDRESS_ERROR_SIZE 0 +#define DBG_DBG_INT_STS_CLR_REG_ADDRESS_ERROR (0x1<<0) +#define DBG_DBG_INT_STS_CLR_REG_ADDRESS_ERROR_SIZE 0 +#define DBG_DBG_INT_STS_WR_REG_ADDRESS_ERROR (0x1<<0) +#define DBG_DBG_INT_STS_WR_REG_ADDRESS_ERROR_SIZE 0 +#define DBG_DBG_INT_MASK_REG_ADDRESS_ERROR (0x1<<0) +#define DBG_DBG_INT_MASK_REG_ADDRESS_ERROR_SIZE 0 +#define DMAE_DMAE_INT_STS_REG_ADDRESS_ERROR (0x1<<0) +#define DMAE_DMAE_INT_STS_REG_ADDRESS_ERROR_SIZE 0 +#define DMAE_DMAE_INT_STS_CLR_REG_ADDRESS_ERROR (0x1<<0) +#define DMAE_DMAE_INT_STS_CLR_REG_ADDRESS_ERROR_SIZE 0 +#define DMAE_DMAE_INT_STS_WR_REG_ADDRESS_ERROR (0x1<<0) +#define DMAE_DMAE_INT_STS_WR_REG_ADDRESS_ERROR_SIZE 0 +#define DMAE_DMAE_INT_MASK_REG_ADDRESS_ERROR (0x1<<0) +#define DMAE_DMAE_INT_MASK_REG_ADDRESS_ERROR_SIZE 0 #define DORQ_DORQ_INT_STS_REG_ADDRESS_ERROR (0x1<<0) #define DORQ_DORQ_INT_STS_REG_ADDRESS_ERROR_SIZE 0 #define DORQ_DORQ_INT_STS_CLR_REG_ADDRESS_ERROR (0x1<<0) @@ -2455,6 +3124,22 @@ #define DORQ_DORQ_INT_STS_WR_REG_ADDRESS_ERROR_SIZE 0 #define DORQ_DORQ_INT_MASK_REG_ADDRESS_ERROR (0x1<<0) #define DORQ_DORQ_INT_MASK_REG_ADDRESS_ERROR_SIZE 0 +#define HC_HC_INT_STS_REG_ADDRESS_ERROR (0x1<<0) +#define HC_HC_INT_STS_REG_ADDRESS_ERROR_SIZE 0 +#define HC_HC_INT_STS_CLR_REG_ADDRESS_ERROR (0x1<<0) +#define HC_HC_INT_STS_CLR_REG_ADDRESS_ERROR_SIZE 0 +#define HC_HC_INT_STS_WR_REG_ADDRESS_ERROR (0x1<<0) +#define HC_HC_INT_STS_WR_REG_ADDRESS_ERROR_SIZE 0 +#define HC_HC_INT_MASK_REG_ADDRESS_ERROR (0x1<<0) +#define HC_HC_INT_MASK_REG_ADDRESS_ERROR_SIZE 0 +#define MISC_MISC_INT_STS_REG_ADDRESS_ERROR (0x1<<0) +#define MISC_MISC_INT_STS_REG_ADDRESS_ERROR_SIZE 0 +#define MISC_MISC_INT_STS_CLR_REG_ADDRESS_ERROR (0x1<<0) +#define MISC_MISC_INT_STS_CLR_REG_ADDRESS_ERROR_SIZE 0 +#define MISC_MISC_INT_STS_WR_REG_ADDRESS_ERROR (0x1<<0) +#define MISC_MISC_INT_STS_WR_REG_ADDRESS_ERROR_SIZE 0 +#define MISC_MISC_INT_MASK_REG_ADDRESS_ERROR (0x1<<0) +#define MISC_MISC_INT_MASK_REG_ADDRESS_ERROR_SIZE 0 #define NIG_NIG_INT_STS_0_REG_ADDRESS_ERROR (0x1<<0) #define NIG_NIG_INT_STS_0_REG_ADDRESS_ERROR_SIZE 0 #define NIG_NIG_INT_STS_CLR_0_REG_ADDRESS_ERROR (0x1<<0) @@ -2463,6 +3148,70 @@ #define NIG_NIG_INT_STS_WR_0_REG_ADDRESS_ERROR_SIZE 0 #define NIG_NIG_INT_MASK_0_REG_ADDRESS_ERROR (0x1<<0) #define NIG_NIG_INT_MASK_0_REG_ADDRESS_ERROR_SIZE 0 +#define PBF_PBF_INT_STS_REG_ADDRESS_ERROR (0x1<<0) +#define PBF_PBF_INT_STS_REG_ADDRESS_ERROR_SIZE 0 +#define PBF_PBF_INT_STS_CLR_REG_ADDRESS_ERROR (0x1<<0) +#define PBF_PBF_INT_STS_CLR_REG_ADDRESS_ERROR_SIZE 0 +#define PBF_PBF_INT_STS_WR_REG_ADDRESS_ERROR (0x1<<0) +#define PBF_PBF_INT_STS_WR_REG_ADDRESS_ERROR_SIZE 0 +#define PBF_PBF_INT_MASK_REG_ADDRESS_ERROR (0x1<<0) +#define PBF_PBF_INT_MASK_REG_ADDRESS_ERROR_SIZE 0 +#define PB_PB_INT_STS_REG_ADDRESS_ERROR (0x1<<0) +#define PB_PB_INT_STS_REG_ADDRESS_ERROR_SIZE 0 +#define PB_PB_INT_STS_CLR_REG_ADDRESS_ERROR (0x1<<0) +#define PB_PB_INT_STS_CLR_REG_ADDRESS_ERROR_SIZE 0 +#define PB_PB_INT_STS_WR_REG_ADDRESS_ERROR (0x1<<0) +#define PB_PB_INT_STS_WR_REG_ADDRESS_ERROR_SIZE 0 +#define PB_PB_INT_MASK_REG_ADDRESS_ERROR (0x1<<0) +#define PB_PB_INT_MASK_REG_ADDRESS_ERROR_SIZE 0 +#define PRS_PRS_INT_STS_REG_ADDRESS_ERROR (0x1<<0) +#define PRS_PRS_INT_STS_REG_ADDRESS_ERROR_SIZE 0 +#define PRS_PRS_INT_STS_CLR_REG_ADDRESS_ERROR (0x1<<0) +#define PRS_PRS_INT_STS_CLR_REG_ADDRESS_ERROR_SIZE 0 +#define PRS_PRS_INT_STS_WR_REG_ADDRESS_ERROR (0x1<<0) +#define PRS_PRS_INT_STS_WR_REG_ADDRESS_ERROR_SIZE 0 +#define PRS_PRS_INT_MASK_REG_ADDRESS_ERROR (0x1<<0) +#define PRS_PRS_INT_MASK_REG_ADDRESS_ERROR_SIZE 0 +#define PXP2_PXP2_INT_STS_0_REG_ADDRESS_ERROR (0x1<<0) +#define PXP2_PXP2_INT_STS_0_REG_ADDRESS_ERROR_SIZE 0 +#define PXP2_PXP2_INT_STS_CLR_0_REG_ADDRESS_ERROR (0x1<<0) +#define PXP2_PXP2_INT_STS_CLR_0_REG_ADDRESS_ERROR_SIZE 0 +#define PXP2_PXP2_INT_STS_WR_0_REG_ADDRESS_ERROR (0x1<<0) +#define PXP2_PXP2_INT_STS_WR_0_REG_ADDRESS_ERROR_SIZE 0 +#define PXP2_PXP2_INT_MASK_0_REG_ADDRESS_ERROR (0x1<<0) +#define PXP2_PXP2_INT_MASK_0_REG_ADDRESS_ERROR_SIZE 0 +#define PXP_PXP_INT_STS_0_REG_ADDRESS_ERROR (0x1<<0) +#define PXP_PXP_INT_STS_0_REG_ADDRESS_ERROR_SIZE 0 +#define PXP_PXP_INT_STS_CLR_0_REG_ADDRESS_ERROR (0x1<<0) +#define PXP_PXP_INT_STS_CLR_0_REG_ADDRESS_ERROR_SIZE 0 +#define PXP_PXP_INT_STS_WR_0_REG_ADDRESS_ERROR (0x1<<0) +#define PXP_PXP_INT_STS_WR_0_REG_ADDRESS_ERROR_SIZE 0 +#define PXP_PXP_INT_MASK_0_REG_ADDRESS_ERROR (0x1<<0) +#define PXP_PXP_INT_MASK_0_REG_ADDRESS_ERROR_SIZE 0 +#define QM_QM_INT_STS_REG_ADDRESS_ERROR (0x1<<0) +#define QM_QM_INT_STS_REG_ADDRESS_ERROR_SIZE 0 +#define QM_QM_INT_STS_CLR_REG_ADDRESS_ERROR (0x1<<0) +#define QM_QM_INT_STS_CLR_REG_ADDRESS_ERROR_SIZE 0 +#define QM_QM_INT_STS_WR_REG_ADDRESS_ERROR (0x1<<0) +#define QM_QM_INT_STS_WR_REG_ADDRESS_ERROR_SIZE 0 +#define QM_QM_INT_MASK_REG_ADDRESS_ERROR (0x1<<0) +#define QM_QM_INT_MASK_REG_ADDRESS_ERROR_SIZE 0 +#define SEM_FAST_SEM_FAST_INT_STS_REG_ADDRESS_ERROR (0x1<<0) +#define SEM_FAST_SEM_FAST_INT_STS_REG_ADDRESS_ERROR_SIZE 0 +#define SEM_FAST_SEM_FAST_INT_STS_CLR_REG_ADDRESS_ERROR (0x1<<0) +#define SEM_FAST_SEM_FAST_INT_STS_CLR_REG_ADDRESS_ERROR_SIZE 0 +#define SEM_FAST_SEM_FAST_INT_STS_WR_REG_ADDRESS_ERROR (0x1<<0) +#define SEM_FAST_SEM_FAST_INT_STS_WR_REG_ADDRESS_ERROR_SIZE 0 +#define SEM_FAST_SEM_FAST_INT_MASK_REG_ADDRESS_ERROR (0x1<<0) +#define SEM_FAST_SEM_FAST_INT_MASK_REG_ADDRESS_ERROR_SIZE 0 +#define SRC_SRC_INT_STS_REG_ADDRESS_ERROR (0x1<<0) +#define SRC_SRC_INT_STS_REG_ADDRESS_ERROR_SIZE 0 +#define SRC_SRC_INT_STS_CLR_REG_ADDRESS_ERROR (0x1<<0) +#define SRC_SRC_INT_STS_CLR_REG_ADDRESS_ERROR_SIZE 0 +#define SRC_SRC_INT_STS_WR_REG_ADDRESS_ERROR (0x1<<0) +#define SRC_SRC_INT_STS_WR_REG_ADDRESS_ERROR_SIZE 0 +#define SRC_SRC_INT_MASK_REG_ADDRESS_ERROR (0x1<<0) +#define SRC_SRC_INT_MASK_REG_ADDRESS_ERROR_SIZE 0 #define TCM_TCM_INT_STS_REG_ADDRESS_ERROR (0x1<<0) #define TCM_TCM_INT_STS_REG_ADDRESS_ERROR_SIZE 0 #define TCM_TCM_INT_STS_CLR_REG_ADDRESS_ERROR (0x1<<0) @@ -2471,6 +3220,78 @@ #define TCM_TCM_INT_STS_WR_REG_ADDRESS_ERROR_SIZE 0 #define TCM_TCM_INT_MASK_REG_ADDRESS_ERROR (0x1<<0) #define TCM_TCM_INT_MASK_REG_ADDRESS_ERROR_SIZE 0 +#define TM_TM_INT_STS_REG_ADDRESS_ERROR (0x1<<0) +#define TM_TM_INT_STS_REG_ADDRESS_ERROR_SIZE 0 +#define TM_TM_INT_STS_CLR_REG_ADDRESS_ERROR (0x1<<0) +#define TM_TM_INT_STS_CLR_REG_ADDRESS_ERROR_SIZE 0 +#define TM_TM_INT_STS_WR_REG_ADDRESS_ERROR (0x1<<0) +#define TM_TM_INT_STS_WR_REG_ADDRESS_ERROR_SIZE 0 +#define TM_TM_INT_MASK_REG_ADDRESS_ERROR (0x1<<0) +#define TM_TM_INT_MASK_REG_ADDRESS_ERROR_SIZE 0 +#define TSDM_TSDM_INT_STS_0_REG_ADDRESS_ERROR (0x1<<0) +#define TSDM_TSDM_INT_STS_0_REG_ADDRESS_ERROR_SIZE 0 +#define TSDM_TSDM_INT_STS_CLR_0_REG_ADDRESS_ERROR (0x1<<0) +#define TSDM_TSDM_INT_STS_CLR_0_REG_ADDRESS_ERROR_SIZE 0 +#define TSDM_TSDM_INT_STS_WR_0_REG_ADDRESS_ERROR (0x1<<0) +#define TSDM_TSDM_INT_STS_WR_0_REG_ADDRESS_ERROR_SIZE 0 +#define TSDM_TSDM_INT_MASK_0_REG_ADDRESS_ERROR (0x1<<0) +#define TSDM_TSDM_INT_MASK_0_REG_ADDRESS_ERROR_SIZE 0 +#define TSEM_TSEM_INT_STS_0_REG_ADDRESS_ERROR (0x1<<0) +#define TSEM_TSEM_INT_STS_0_REG_ADDRESS_ERROR_SIZE 0 +#define TSEM_TSEM_INT_STS_CLR_0_REG_ADDRESS_ERROR (0x1<<0) +#define TSEM_TSEM_INT_STS_CLR_0_REG_ADDRESS_ERROR_SIZE 0 +#define TSEM_TSEM_INT_STS_WR_0_REG_ADDRESS_ERROR (0x1<<0) +#define TSEM_TSEM_INT_STS_WR_0_REG_ADDRESS_ERROR_SIZE 0 +#define TSEM_TSEM_INT_MASK_0_REG_ADDRESS_ERROR (0x1<<0) +#define TSEM_TSEM_INT_MASK_0_REG_ADDRESS_ERROR_SIZE 0 +#define UCM_UCM_INT_STS_REG_ADDRESS_ERROR (0x1<<0) +#define UCM_UCM_INT_STS_REG_ADDRESS_ERROR_SIZE 0 +#define UCM_UCM_INT_STS_CLR_REG_ADDRESS_ERROR (0x1<<0) +#define UCM_UCM_INT_STS_CLR_REG_ADDRESS_ERROR_SIZE 0 +#define UCM_UCM_INT_STS_WR_REG_ADDRESS_ERROR (0x1<<0) +#define UCM_UCM_INT_STS_WR_REG_ADDRESS_ERROR_SIZE 0 +#define UCM_UCM_INT_MASK_REG_ADDRESS_ERROR (0x1<<0) +#define UCM_UCM_INT_MASK_REG_ADDRESS_ERROR_SIZE 0 +#define USDM_USDM_INT_STS_0_REG_ADDRESS_ERROR (0x1<<0) +#define USDM_USDM_INT_STS_0_REG_ADDRESS_ERROR_SIZE 0 +#define USDM_USDM_INT_STS_CLR_0_REG_ADDRESS_ERROR (0x1<<0) +#define USDM_USDM_INT_STS_CLR_0_REG_ADDRESS_ERROR_SIZE 0 +#define USDM_USDM_INT_STS_WR_0_REG_ADDRESS_ERROR (0x1<<0) +#define USDM_USDM_INT_STS_WR_0_REG_ADDRESS_ERROR_SIZE 0 +#define USDM_USDM_INT_MASK_0_REG_ADDRESS_ERROR (0x1<<0) +#define USDM_USDM_INT_MASK_0_REG_ADDRESS_ERROR_SIZE 0 +#define USEM_USEM_INT_STS_0_REG_ADDRESS_ERROR (0x1<<0) +#define USEM_USEM_INT_STS_0_REG_ADDRESS_ERROR_SIZE 0 +#define USEM_USEM_INT_STS_CLR_0_REG_ADDRESS_ERROR (0x1<<0) +#define USEM_USEM_INT_STS_CLR_0_REG_ADDRESS_ERROR_SIZE 0 +#define USEM_USEM_INT_STS_WR_0_REG_ADDRESS_ERROR (0x1<<0) +#define USEM_USEM_INT_STS_WR_0_REG_ADDRESS_ERROR_SIZE 0 +#define USEM_USEM_INT_MASK_0_REG_ADDRESS_ERROR (0x1<<0) +#define USEM_USEM_INT_MASK_0_REG_ADDRESS_ERROR_SIZE 0 +#define XCM_XCM_INT_STS_REG_ADDRESS_ERROR (0x1<<0) +#define XCM_XCM_INT_STS_REG_ADDRESS_ERROR_SIZE 0 +#define XCM_XCM_INT_STS_CLR_REG_ADDRESS_ERROR (0x1<<0) +#define XCM_XCM_INT_STS_CLR_REG_ADDRESS_ERROR_SIZE 0 +#define XCM_XCM_INT_STS_WR_REG_ADDRESS_ERROR (0x1<<0) +#define XCM_XCM_INT_STS_WR_REG_ADDRESS_ERROR_SIZE 0 +#define XCM_XCM_INT_MASK_REG_ADDRESS_ERROR (0x1<<0) +#define XCM_XCM_INT_MASK_REG_ADDRESS_ERROR_SIZE 0 +#define XSDM_XSDM_INT_STS_0_REG_ADDRESS_ERROR (0x1<<0) +#define XSDM_XSDM_INT_STS_0_REG_ADDRESS_ERROR_SIZE 0 +#define XSDM_XSDM_INT_STS_CLR_0_REG_ADDRESS_ERROR (0x1<<0) +#define XSDM_XSDM_INT_STS_CLR_0_REG_ADDRESS_ERROR_SIZE 0 +#define XSDM_XSDM_INT_STS_WR_0_REG_ADDRESS_ERROR (0x1<<0) +#define XSDM_XSDM_INT_STS_WR_0_REG_ADDRESS_ERROR_SIZE 0 +#define XSDM_XSDM_INT_MASK_0_REG_ADDRESS_ERROR (0x1<<0) +#define XSDM_XSDM_INT_MASK_0_REG_ADDRESS_ERROR_SIZE 0 +#define XSEM_XSEM_INT_STS_0_REG_ADDRESS_ERROR (0x1<<0) +#define XSEM_XSEM_INT_STS_0_REG_ADDRESS_ERROR_SIZE 0 +#define XSEM_XSEM_INT_STS_CLR_0_REG_ADDRESS_ERROR (0x1<<0) +#define XSEM_XSEM_INT_STS_CLR_0_REG_ADDRESS_ERROR_SIZE 0 +#define XSEM_XSEM_INT_STS_WR_0_REG_ADDRESS_ERROR (0x1<<0) +#define XSEM_XSEM_INT_STS_WR_0_REG_ADDRESS_ERROR_SIZE 0 +#define XSEM_XSEM_INT_MASK_0_REG_ADDRESS_ERROR (0x1<<0) +#define XSEM_XSEM_INT_MASK_0_REG_ADDRESS_ERROR_SIZE 0 #define CFC_DEBUG1_REG_WRITE_AC (0x1<<4) #define CFC_DEBUG1_REG_WRITE_AC_SIZE 4 /* [R 1] debug only: This bit indicates wheter indicates that external @@ -2483,6 +3304,14 @@ ~dbg_registers_debug_target=0 (internal buffer) */ #define DBG_REG_WRAP_ON_INT_BUFFER 0xc128 #define DBG_REG_WRAP_ON_INT_BUFFER_SIZE 1 +#define QM_QM_PRTY_STS_REG_WRBUFF (0x1<<8) +#define QM_QM_PRTY_STS_REG_WRBUFF_SIZE 8 +#define QM_QM_PRTY_STS_CLR_REG_WRBUFF (0x1<<8) +#define QM_QM_PRTY_STS_CLR_REG_WRBUFF_SIZE 8 +#define QM_QM_PRTY_STS_WR_REG_WRBUFF (0x1<<8) +#define QM_QM_PRTY_STS_WR_REG_WRBUFF_SIZE 8 +#define QM_QM_PRTY_MASK_REG_WRBUFF (0x1<<8) +#define QM_QM_PRTY_MASK_REG_WRBUFF_SIZE 8 /* [RW 32] Wrr weights */ #define QM_REG_WRRWEIGHTS_0 0x16880c #define QM_REG_WRRWEIGHTS_0_SIZE 1 @@ -2531,20 +3360,67 @@ /* [RW 32] Wrr weights */ #define QM_REG_WRRWEIGHTS_9 0x168848 #define QM_REG_WRRWEIGHTS_9_SIZE 1 -/* [RW 22] Number of free element in the free list of T2 entries - port 0. */ +/* [RW 32] Wrr weights */ +#define QM_REG_WRRWEIGHTS_16 0x16e000 +#define QM_REG_WRRWEIGHTS_16_SIZE 1 +/* [RW 32] Wrr weights */ +#define QM_REG_WRRWEIGHTS_17 0x16e004 +#define QM_REG_WRRWEIGHTS_17_SIZE 1 +/* [RW 32] Wrr weights */ +#define QM_REG_WRRWEIGHTS_18 0x16e008 +#define QM_REG_WRRWEIGHTS_18_SIZE 1 +/* [RW 32] Wrr weights */ +#define QM_REG_WRRWEIGHTS_19 0x16e00c +#define QM_REG_WRRWEIGHTS_19_SIZE 1 +/* [RW 32] Wrr weights */ +#define QM_REG_WRRWEIGHTS_20 0x16e010 +#define QM_REG_WRRWEIGHTS_20_SIZE 1 +/* [RW 32] Wrr weights */ +#define QM_REG_WRRWEIGHTS_21 0x16e014 +#define QM_REG_WRRWEIGHTS_21_SIZE 1 +/* [RW 32] Wrr weights */ +#define QM_REG_WRRWEIGHTS_22 0x16e018 +#define QM_REG_WRRWEIGHTS_22_SIZE 1 +/* [RW 32] Wrr weights */ +#define QM_REG_WRRWEIGHTS_23 0x16e01c +#define QM_REG_WRRWEIGHTS_23_SIZE 1 +/* [RW 32] Wrr weights */ +#define QM_REG_WRRWEIGHTS_24 0x16e020 +#define QM_REG_WRRWEIGHTS_24_SIZE 1 +/* [RW 32] Wrr weights */ +#define QM_REG_WRRWEIGHTS_25 0x16e024 +#define QM_REG_WRRWEIGHTS_25_SIZE 1 +/* [RW 32] Wrr weights */ +#define QM_REG_WRRWEIGHTS_26 0x16e028 +#define QM_REG_WRRWEIGHTS_26_SIZE 1 +/* [RW 32] Wrr weights */ +#define QM_REG_WRRWEIGHTS_27 0x16e02c +#define QM_REG_WRRWEIGHTS_27_SIZE 1 +/* [RW 32] Wrr weights */ +#define QM_REG_WRRWEIGHTS_28 0x16e030 +#define QM_REG_WRRWEIGHTS_28_SIZE 1 +/* [RW 32] Wrr weights */ +#define QM_REG_WRRWEIGHTS_29 0x16e034 +#define QM_REG_WRRWEIGHTS_29_SIZE 1 +/* [RW 32] Wrr weights */ +#define QM_REG_WRRWEIGHTS_30 0x16e038 +#define QM_REG_WRRWEIGHTS_30_SIZE 1 +/* [RW 32] Wrr weights */ +#define QM_REG_WRRWEIGHTS_31 0x16e03c +#define QM_REG_WRRWEIGHTS_31_SIZE 1 #define SRC_REG_COUNTFREE0 0x40500 -/* [WB 64] First free element in the free list of T2 entries - port 0. */ +/* [RW 1] If clr the searcher is compatible to E1 A0 - support only two + ports. If set the searcher support 8 functions. */ +#define SRC_REG_E1HMF_ENABLE 0x404cc #define SRC_REG_FIRSTFREE0 0x40510 #define SRC_REG_KEYRSS0_0 0x40408 +#define SRC_REG_KEYRSS0_7 0x40424 #define SRC_REG_KEYRSS1_9 0x40454 -/* [WB 64] Last free element in the free list of T2 entries - port 0. */ #define SRC_REG_LASTFREE0 0x40530 -/* [RW 5] The number of hash bits used for the search (h); Values can be 8 - to 24. */ #define SRC_REG_NUMBER_HASH_BITS0 0x40400 /* [RW 1] Reset internal state machines. */ #define SRC_REG_SOFT_RST 0x4049c -/* [R 1] Interrupt register #0 read */ +/* [R 3] Interrupt register #0 read */ #define SRC_REG_SRC_INT_STS 0x404ac /* [RW 3] Parity mask register #0 read/write */ #define SRC_REG_SRC_PRTY_MASK 0x404c8 @@ -2637,11 +3513,14 @@ weight 8 (the most prioritised); 1 stands for weight 1(least prioritised); 2 stands for weight 2; tc. */ #define TCM_REG_PBF_WEIGHT 0x500b4 -/* [RW 6] The physical queue number 0 per port index. */ #define TCM_REG_PHYS_QNUM0_0 0x500e0 #define TCM_REG_PHYS_QNUM0_1 0x500e4 -/* [RW 6] The physical queue number 1 per port index. */ #define TCM_REG_PHYS_QNUM1_0 0x500e8 +#define TCM_REG_PHYS_QNUM1_1 0x500ec +#define TCM_REG_PHYS_QNUM2_0 0x500f0 +#define TCM_REG_PHYS_QNUM2_1 0x500f4 +#define TCM_REG_PHYS_QNUM3_0 0x500f8 +#define TCM_REG_PHYS_QNUM3_1 0x500fc /* [RW 1] Input prs Interface enable. If 0 - the valid input is disregarded; acknowledge output is deasserted; all other signals are treated as usual; if 1 - normal activity. */ @@ -2670,6 +3549,8 @@ #define TCM_REG_TCM_INT_MASK 0x501dc /* [R 11] Interrupt register #0 read */ #define TCM_REG_TCM_INT_STS 0x501d0 +/* [R 27] Parity register #0 read */ +#define TCM_REG_TCM_PRTY_STS 0x501e0 /* [RW 3] The size of AG context region 0 in REG-pairs. Designates the MS REG-pair number (e.g. if region 0 is 6 REG-pairs; the value should be 5). Is used to determine the number of the AG context REG-pairs written back; @@ -2729,6 +3610,7 @@ mechanism. The fields are: [5:0] - length of the message; 15:6] - message pointer; 20:16] - next pointer. */ #define TCM_REG_XX_DESCR_TABLE 0x50280 +#define TCM_REG_XX_DESCR_TABLE_SIZE 32 /* [R 6] Use to read the value of XX protection Free counter. */ #define TCM_REG_XX_FREE 0x50178 /* [RW 6] Initial value for the credit counter; responsible for fulfilling @@ -2780,7 +3662,7 @@ /* [RW 4] Load value for expiration credit cnt. CFC max number of outstanding load requests for timers (expiration) context loading. */ #define TM_REG_EXP_CRDCNT_VAL 0x164238 -/* [RW 18] Linear0 Max active cid. */ +/* [RW 18] Linear0 Max active cid (in banks of 32 entries). */ #define TM_REG_LIN0_MAX_ACTIVE_CID 0x164048 /* [WB 64] Linear0 phy address. */ #define TM_REG_LIN0_PHY_ADDR 0x164270 @@ -2804,6 +3686,21 @@ #define TM_REG_TM_INT_STS 0x1640f0 /* [RW 8] The event id for aggregated interrupt 0 */ #define TSDM_REG_AGG_INT_EVENT_0 0x42038 +#define TSDM_REG_AGG_INT_EVENT_2 0x42040 +#define TSDM_REG_AGG_INT_EVENT_20 0x42088 +#define TSDM_REG_AGG_INT_EVENT_21 0x4208c +#define TSDM_REG_AGG_INT_EVENT_22 0x42090 +#define TSDM_REG_AGG_INT_EVENT_23 0x42094 +#define TSDM_REG_AGG_INT_EVENT_24 0x42098 +#define TSDM_REG_AGG_INT_EVENT_25 0x4209c +#define TSDM_REG_AGG_INT_EVENT_26 0x420a0 +#define TSDM_REG_AGG_INT_EVENT_27 0x420a4 +#define TSDM_REG_AGG_INT_EVENT_28 0x420a8 +#define TSDM_REG_AGG_INT_EVENT_29 0x420ac +#define TSDM_REG_AGG_INT_EVENT_3 0x42044 +#define TSDM_REG_AGG_INT_EVENT_30 0x420b0 +#define TSDM_REG_AGG_INT_EVENT_31 0x420b4 +#define TSDM_REG_AGG_INT_EVENT_4 0x42048 /* [RW 13] The start address in the internal RAM for the cfc_rsp lcid */ #define TSDM_REG_CFC_RSP_START_ADDR 0x42008 /* [RW 16] The maximum value of the competion counter #0 */ @@ -2868,6 +3765,9 @@ /* [RW 32] Interrupt mask register #0 read/write */ #define TSDM_REG_TSDM_INT_MASK_0 0x4229c #define TSDM_REG_TSDM_INT_MASK_1 0x422ac +/* [R 32] Interrupt register #0 read */ +#define TSDM_REG_TSDM_INT_STS_0 0x42290 +#define TSDM_REG_TSDM_INT_STS_1 0x422a0 /* [RW 11] Parity mask register #0 read/write */ #define TSDM_REG_TSDM_PRTY_MASK 0x422bc /* [R 11] Parity register #0 read */ @@ -2908,9 +3808,8 @@ #define TSEM_REG_ENABLE_OUT 0x1800a8 /* [RW 32] This address space contains all registers and memories that are placed in SEM_FAST block. The SEM_FAST registers are described in - appendix B. In order to access the SEM_FAST registers the base address - TSEM_REGISTERS_FAST_MEMORY (Offset: 0x1a0000) should be added to each - SEM_FAST register offset. */ + appendix B. In order to access the sem_fast registers the base address + ~fast_memory.fast_memory should be added to eachsem_fast register offset. */ #define TSEM_REG_FAST_MEMORY 0x1a0000 /* [RW 1] Disables input messages from FIC0 May be updated during run_time by the microcode */ @@ -2993,6 +3892,9 @@ /* [RW 32] Interrupt mask register #0 read/write */ #define TSEM_REG_TSEM_INT_MASK_0 0x180100 #define TSEM_REG_TSEM_INT_MASK_1 0x180110 +/* [R 32] Interrupt register #0 read */ +#define TSEM_REG_TSEM_INT_STS_0 0x1800f4 +#define TSEM_REG_TSEM_INT_STS_1 0x180104 /* [RW 32] Parity mask register #0 read/write */ #define TSEM_REG_TSEM_PRTY_MASK_0 0x180120 #define TSEM_REG_TSEM_PRTY_MASK_1 0x180130 @@ -3088,12 +3990,15 @@ #define UCM_REG_N_SM_CTX_LD_2 0xe005c #define UCM_REG_N_SM_CTX_LD_3 0xe0060 #define UCM_REG_N_SM_CTX_LD_4 0xe0064 -/* [RW 6] The physical queue number 0 per port index (CID[23]) */ +#define UCM_REG_N_SM_CTX_LD_5 0xe0068 #define UCM_REG_PHYS_QNUM0_0 0xe0110 #define UCM_REG_PHYS_QNUM0_1 0xe0114 -/* [RW 6] The physical queue number 1 per port index (CID[23]) */ #define UCM_REG_PHYS_QNUM1_0 0xe0118 #define UCM_REG_PHYS_QNUM1_1 0xe011c +#define UCM_REG_PHYS_QNUM2_0 0xe0120 +#define UCM_REG_PHYS_QNUM2_1 0xe0124 +#define UCM_REG_PHYS_QNUM3_0 0xe0128 +#define UCM_REG_PHYS_QNUM3_1 0xe012c /* [RW 8] The Event ID for Timers formatting in case of stop done. */ #define UCM_REG_STOP_EVNT_ID 0xe00ac /* [RC 1] Set when the message length mismatch (relative to last indication) @@ -3132,6 +4037,8 @@ #define UCM_REG_UCM_INT_MASK 0xe01d4 /* [R 11] Interrupt register #0 read */ #define UCM_REG_UCM_INT_STS 0xe01c8 +/* [R 27] Parity register #0 read */ +#define UCM_REG_UCM_PRTY_STS 0xe01d8 /* [RW 2] The size of AG context region 0 in REG-pairs. Designates the MS REG-pair number (e.g. if region 0 is 6 REG-pairs; the value should be 5). Is used to determine the number of the AG context REG-pairs written back; @@ -3189,6 +4096,7 @@ mechanism. The fields are:[5:0] - message length; 14:6] - message pointer; 19:15] - next pointer. */ #define UCM_REG_XX_DESCR_TABLE 0xe0280 +#define UCM_REG_XX_DESCR_TABLE_SIZE 32 /* [R 6] Use to read the XX protection Free counter. */ #define UCM_REG_XX_FREE 0xe016c /* [RW 6] Initial value for the credit counter; responsible for fulfilling @@ -3218,6 +4126,21 @@ #define USDM_REG_AGG_INT_EVENT_17 0xc407c #define USDM_REG_AGG_INT_EVENT_18 0xc4080 #define USDM_REG_AGG_INT_EVENT_19 0xc4084 +#define USDM_REG_AGG_INT_EVENT_2 0xc4040 +#define USDM_REG_AGG_INT_EVENT_20 0xc4088 +#define USDM_REG_AGG_INT_EVENT_21 0xc408c +#define USDM_REG_AGG_INT_EVENT_22 0xc4090 +#define USDM_REG_AGG_INT_EVENT_23 0xc4094 +#define USDM_REG_AGG_INT_EVENT_24 0xc4098 +#define USDM_REG_AGG_INT_EVENT_25 0xc409c +#define USDM_REG_AGG_INT_EVENT_26 0xc40a0 +#define USDM_REG_AGG_INT_EVENT_27 0xc40a4 +#define USDM_REG_AGG_INT_EVENT_28 0xc40a8 +#define USDM_REG_AGG_INT_EVENT_29 0xc40ac +#define USDM_REG_AGG_INT_EVENT_3 0xc4044 +#define USDM_REG_AGG_INT_EVENT_30 0xc40b0 +#define USDM_REG_AGG_INT_EVENT_31 0xc40b4 +#define USDM_REG_AGG_INT_EVENT_4 0xc4048 /* [RW 1] For each aggregated interrupt index whether the mode is normal (0) or auto-mask-mode (1) */ #define USDM_REG_AGG_INT_MODE_0 0xc41b8 @@ -3298,6 +4221,9 @@ /* [RW 32] Interrupt mask register #0 read/write */ #define USDM_REG_USDM_INT_MASK_0 0xc42a0 #define USDM_REG_USDM_INT_MASK_1 0xc42b0 +/* [R 32] Interrupt register #0 read */ +#define USDM_REG_USDM_INT_STS_0 0xc4294 +#define USDM_REG_USDM_INT_STS_1 0xc42a4 /* [RW 11] Parity mask register #0 read/write */ #define USDM_REG_USDM_PRTY_MASK 0xc42c0 /* [R 11] Parity register #0 read */ @@ -3338,9 +4264,8 @@ #define USEM_REG_ENABLE_OUT 0x3000a8 /* [RW 32] This address space contains all registers and memories that are placed in SEM_FAST block. The SEM_FAST registers are described in - appendix B. In order to access the SEM_FAST registers... the base address - USEM_REGISTERS_FAST_MEMORY (Offset: 0x320000) should be added to each - SEM_FAST register offset. */ + appendix B. In order to access the sem_fast registers the base address + ~fast_memory.fast_memory should be added to eachsem_fast register offset. */ #define USEM_REG_FAST_MEMORY 0x320000 /* [RW 1] Disables input messages from FIC0 May be updated during run_time by the microcode */ @@ -3423,6 +4348,9 @@ /* [RW 32] Interrupt mask register #0 read/write */ #define USEM_REG_USEM_INT_MASK_0 0x300110 #define USEM_REG_USEM_INT_MASK_1 0x300120 +/* [R 32] Interrupt register #0 read */ +#define USEM_REG_USEM_INT_STS_0 0x300104 +#define USEM_REG_USEM_INT_STS_1 0x300114 /* [RW 32] Parity mask register #0 read/write */ #define USEM_REG_USEM_PRTY_MASK_0 0x300130 #define USEM_REG_USEM_PRTY_MASK_1 0x300140 @@ -3491,11 +4419,8 @@ writes the initial credit value; read returns the current value of the credit counter. Must be initialized to 64 at start-up. */ #define XCM_REG_FIC1_INIT_CRD 0x20410 -/* [RW 8] The maximum delayed ACK counter value.Must be at least 2. Per port - value. */ #define XCM_REG_GLB_DEL_ACK_MAX_CNT_0 0x20118 #define XCM_REG_GLB_DEL_ACK_MAX_CNT_1 0x2011c -/* [RW 28] The delayed ACK timeout in ticks. Per port value. */ #define XCM_REG_GLB_DEL_ACK_TMR_VAL_0 0x20108 #define XCM_REG_GLB_DEL_ACK_TMR_VAL_1 0x2010c /* [RW 1] Arbitratiojn between Input Arbiter groups: 0 - fair Round-Robin; 1 @@ -3545,6 +4470,7 @@ #define XCM_REG_N_SM_CTX_LD_2 0x20068 #define XCM_REG_N_SM_CTX_LD_3 0x2006c #define XCM_REG_N_SM_CTX_LD_4 0x20070 +#define XCM_REG_N_SM_CTX_LD_5 0x20074 /* [RW 1] Input pbf Interface enable. If 0 - the valid input is disregarded; acknowledge output is deasserted; all other signals are treated as usual; if 1 - normal activity. */ @@ -3556,6 +4482,8 @@ weight 8 (the most prioritised); 1 stands for weight 1(least prioritised); 2 stands for weight 2; tc. */ #define XCM_REG_PBF_WEIGHT 0x200d0 +#define XCM_REG_PHYS_QNUM3_0 0x20100 +#define XCM_REG_PHYS_QNUM3_1 0x20104 /* [RW 8] The Event ID for Timers formatting in case of stop done. */ #define XCM_REG_STOP_EVNT_ID 0x200b8 /* [RC 1] Set at message length mismatch (relative to last indication) at @@ -3603,53 +4531,17 @@ weight 8 (the most prioritised); 1 stands for weight 1(least prioritised); 2 stands for weight 2; tc. */ #define XCM_REG_USEM_WEIGHT 0x200c8 -/* [RW 2] DA counter command; used in case of window update doorbell.The - first index stands for the value DaEnable of that connection. The second - index stands for port number. */ #define XCM_REG_WU_DA_CNT_CMD00 0x201d4 -/* [RW 2] DA counter command; used in case of window update doorbell.The - first index stands for the value DaEnable of that connection. The second - index stands for port number. */ #define XCM_REG_WU_DA_CNT_CMD01 0x201d8 -/* [RW 2] DA counter command; used in case of window update doorbell.The - first index stands for the value DaEnable of that connection. The second - index stands for port number. */ #define XCM_REG_WU_DA_CNT_CMD10 0x201dc -/* [RW 2] DA counter command; used in case of window update doorbell.The - first index stands for the value DaEnable of that connection. The second - index stands for port number. */ #define XCM_REG_WU_DA_CNT_CMD11 0x201e0 -/* [RW 8] DA counter update value used in case of window update doorbell.The - first index stands for the value DaEnable of that connection. The second - index stands for port number. */ #define XCM_REG_WU_DA_CNT_UPD_VAL00 0x201e4 -/* [RW 8] DA counter update value; used in case of window update - doorbell.The first index stands for the value DaEnable of that - connection. The second index stands for port number. */ #define XCM_REG_WU_DA_CNT_UPD_VAL01 0x201e8 -/* [RW 8] DA counter update value; used in case of window update - doorbell.The first index stands for the value DaEnable of that - connection. The second index stands for port number. */ #define XCM_REG_WU_DA_CNT_UPD_VAL10 0x201ec -/* [RW 8] DA counter update value; used in case of window update - doorbell.The first index stands for the value DaEnable of that - connection. The second index stands for port number. */ #define XCM_REG_WU_DA_CNT_UPD_VAL11 0x201f0 -/* [RW 1] DA timer command; used in case of window update doorbell.The first - index stands for the value DaEnable of that connection. The second index - stands for port number. */ #define XCM_REG_WU_DA_SET_TMR_CNT_FLG_CMD00 0x201c4 -/* [RW 1] DA timer command; used in case of window update doorbell.The first - index stands for the value DaEnable of that connection. The second index - stands for port number. */ #define XCM_REG_WU_DA_SET_TMR_CNT_FLG_CMD01 0x201c8 -/* [RW 1] DA timer command; used in case of window update doorbell.The first - index stands for the value DaEnable of that connection. The second index - stands for port number. */ #define XCM_REG_WU_DA_SET_TMR_CNT_FLG_CMD10 0x201cc -/* [RW 1] DA timer command; used in case of window update doorbell.The first - index stands for the value DaEnable of that connection. The second index - stands for port number. */ #define XCM_REG_WU_DA_SET_TMR_CNT_FLG_CMD11 0x201d0 /* [RW 1] CM - CFC Interface enable. If 0 - the valid input is disregarded; acknowledge output is deasserted; all other signals are treated as usual; @@ -3659,6 +4551,8 @@ #define XCM_REG_XCM_INT_MASK 0x202b4 /* [R 14] Interrupt register #0 read */ #define XCM_REG_XCM_INT_STS 0x202a8 +/* [R 30] Parity register #0 read */ +#define XCM_REG_XCM_PRTY_STS 0x202b8 /* [RW 4] The size of AG context region 0 in REG-pairs. Designates the MS REG-pair number (e.g. if region 0 is 6 REG-pairs; the value should be 5). Is used to determine the number of the AG context REG-pairs written back; @@ -3715,6 +4609,7 @@ mechanism. The fields are: [5:0] - message length; 11:6] - message pointer; 16:12] - next pointer. */ #define XCM_REG_XX_DESCR_TABLE 0x20480 +#define XCM_REG_XX_DESCR_TABLE_SIZE 32 /* [R 6] Used to read the XX protection Free counter. */ #define XCM_REG_XX_FREE 0x20240 /* [RW 6] Initial value for the credit counter; responsible for fulfilling @@ -3728,7 +4623,7 @@ #define XCM_REG_XX_MSG_NUM 0x20428 /* [RW 8] The Event ID; sent to the STORM in case of XX overflow. */ #define XCM_REG_XX_OVFL_EVNT_ID 0x20058 -/* [RW 15] Indirect access to the XX table of the XX protection mechanism. +/* [RW 16] Indirect access to the XX table of the XX protection mechanism. The fields are:[4:0] - tail pointer; 9:5] - Link List size; 14:10] - header pointer. */ #define XCM_REG_XX_TABLE 0x20500 @@ -3745,6 +4640,9 @@ #define XSDM_REG_AGG_INT_EVENT_17 0x16607c #define XSDM_REG_AGG_INT_EVENT_18 0x166080 #define XSDM_REG_AGG_INT_EVENT_19 0x166084 +#define XSDM_REG_AGG_INT_EVENT_10 0x166060 +#define XSDM_REG_AGG_INT_EVENT_11 0x166064 +#define XSDM_REG_AGG_INT_EVENT_12 0x166068 #define XSDM_REG_AGG_INT_EVENT_2 0x166040 #define XSDM_REG_AGG_INT_EVENT_20 0x166088 #define XSDM_REG_AGG_INT_EVENT_21 0x16608c @@ -3756,6 +4654,15 @@ #define XSDM_REG_AGG_INT_EVENT_27 0x1660a4 #define XSDM_REG_AGG_INT_EVENT_28 0x1660a8 #define XSDM_REG_AGG_INT_EVENT_29 0x1660ac +#define XSDM_REG_AGG_INT_EVENT_3 0x166044 +#define XSDM_REG_AGG_INT_EVENT_30 0x1660b0 +#define XSDM_REG_AGG_INT_EVENT_31 0x1660b4 +#define XSDM_REG_AGG_INT_EVENT_4 0x166048 +#define XSDM_REG_AGG_INT_EVENT_5 0x16604c +#define XSDM_REG_AGG_INT_EVENT_6 0x166050 +#define XSDM_REG_AGG_INT_EVENT_7 0x166054 +#define XSDM_REG_AGG_INT_EVENT_8 0x166058 +#define XSDM_REG_AGG_INT_EVENT_9 0x16605c /* [RW 1] For each aggregated interrupt index whether the mode is normal (0) or auto-mask-mode (1) */ #define XSDM_REG_AGG_INT_MODE_0 0x1661b8 @@ -3832,6 +4739,9 @@ /* [RW 32] Interrupt mask register #0 read/write */ #define XSDM_REG_XSDM_INT_MASK_0 0x16629c #define XSDM_REG_XSDM_INT_MASK_1 0x1662ac +/* [R 32] Interrupt register #0 read */ +#define XSDM_REG_XSDM_INT_STS_0 0x166290 +#define XSDM_REG_XSDM_INT_STS_1 0x1662a0 /* [RW 11] Parity mask register #0 read/write */ #define XSDM_REG_XSDM_PRTY_MASK 0x1662bc /* [R 11] Parity register #0 read */ @@ -3872,9 +4782,8 @@ #define XSEM_REG_ENABLE_OUT 0x2800a8 /* [RW 32] This address space contains all registers and memories that are placed in SEM_FAST block. The SEM_FAST registers are described in - appendix B. In order to access the SEM_FAST registers the base address - XSEM_REGISTERS_FAST_MEMORY (Offset: 0x2a0000) should be added to each - SEM_FAST register offset. */ + appendix B. In order to access the sem_fast registers the base address + ~fast_memory.fast_memory should be added to eachsem_fast register offset. */ #define XSEM_REG_FAST_MEMORY 0x2a0000 /* [RW 1] Disables input messages from FIC0 May be updated during run_time by the microcode */ @@ -3957,6 +4866,9 @@ /* [RW 32] Interrupt mask register #0 read/write */ #define XSEM_REG_XSEM_INT_MASK_0 0x280110 #define XSEM_REG_XSEM_INT_MASK_1 0x280120 +/* [R 32] Interrupt register #0 read */ +#define XSEM_REG_XSEM_INT_STS_0 0x280104 +#define XSEM_REG_XSEM_INT_STS_1 0x280114 /* [RW 32] Parity mask register #0 read/write */ #define XSEM_REG_XSEM_PRTY_MASK_0 0x280130 #define XSEM_REG_XSEM_PRTY_MASK_1 0x280140 @@ -3993,10 +4905,14 @@ #define BIGMAC_REGISTER_TX_SOURCE_ADDR (0x08<<3) #define BIGMAC_REGISTER_TX_STAT_GTBYT (0x20<<3) #define BIGMAC_REGISTER_TX_STAT_GTPKT (0x0C<<3) +#define EMAC_LED_1000MB_OVERRIDE (1L<<1) +#define EMAC_LED_100MB_OVERRIDE (1L<<2) +#define EMAC_LED_10MB_OVERRIDE (1L<<3) +#define EMAC_LED_2500MB_OVERRIDE (1L<<12) +#define EMAC_LED_OVERRIDE (1L<<0) +#define EMAC_LED_TRAFFIC (1L<<6) #define EMAC_MDIO_COMM_COMMAND_ADDRESS (0L<<26) -#define EMAC_MDIO_COMM_COMMAND_READ_22 (2L<<26) #define EMAC_MDIO_COMM_COMMAND_READ_45 (3L<<26) -#define EMAC_MDIO_COMM_COMMAND_WRITE_22 (1L<<26) #define EMAC_MDIO_COMM_COMMAND_WRITE_45 (1L<<26) #define EMAC_MDIO_COMM_DATA (0xffffL<<0) #define EMAC_MDIO_COMM_START_BUSY (1L<<29) @@ -4005,14 +4921,12 @@ #define EMAC_MDIO_MODE_CLOCK_CNT (0x3fL<<16) #define EMAC_MDIO_MODE_CLOCK_CNT_BITSHIFT 16 #define EMAC_MODE_25G_MODE (1L<<5) -#define EMAC_MODE_ACPI_RCVD (1L<<20) #define EMAC_MODE_HALF_DUPLEX (1L<<1) -#define EMAC_MODE_MPKT (1L<<18) -#define EMAC_MODE_MPKT_RCVD (1L<<19) #define EMAC_MODE_PORT_GMII (2L<<2) #define EMAC_MODE_PORT_MII (1L<<2) #define EMAC_MODE_PORT_MII_10M (3L<<2) #define EMAC_MODE_RESET (1L<<0) +#define EMAC_REG_EMAC_LED 0xc #define EMAC_REG_EMAC_MAC_MATCH 0x10 #define EMAC_REG_EMAC_MDIO_COMM 0xac #define EMAC_REG_EMAC_MDIO_MODE 0xb4 @@ -4030,14 +4944,16 @@ #define EMAC_RX_MODE_PROMISCUOUS (1L<<8) #define EMAC_RX_MTU_SIZE_JUMBO_ENA (1L<<31) #define EMAC_TX_MODE_EXT_PAUSE_EN (1L<<3) -#define EMAC_TX_MODE_RESET (1L<<0) +#define MISC_REGISTERS_GPIO_0 0 #define MISC_REGISTERS_GPIO_1 1 #define MISC_REGISTERS_GPIO_2 2 #define MISC_REGISTERS_GPIO_3 3 #define MISC_REGISTERS_GPIO_CLR_POS 16 #define MISC_REGISTERS_GPIO_FLOAT (0xffL<<24) #define MISC_REGISTERS_GPIO_FLOAT_POS 24 +#define MISC_REGISTERS_GPIO_HIGH 1 #define MISC_REGISTERS_GPIO_INPUT_HI_Z 2 +#define MISC_REGISTERS_GPIO_LOW 0 #define MISC_REGISTERS_GPIO_OUTPUT_HIGH 1 #define MISC_REGISTERS_GPIO_OUTPUT_LOW 0 #define MISC_REGISTERS_GPIO_PORT_SHIFT 4 @@ -4127,7 +5043,7 @@ #define AEU_INPUTS_ATTN_BITS_XSEMI_PARITY_ERROR (1<<10) #define RESERVED_GENERAL_ATTENTION_BIT_0 0 -#define EVEREST_GEN_ATTN_IN_USE_MASK 0x3e0 +#define EVEREST_GEN_ATTN_IN_USE_MASK 0x3ffe0 #define EVEREST_LATCHED_ATTN_IN_USE_MASK 0xffe00000 #define RESERVED_GENERAL_ATTENTION_BIT_6 6 @@ -4156,6 +5072,17 @@ /* mcp error attention bit */ #define MCP_FATAL_ASSERT_ATTENTION_BIT RESERVED_GENERAL_ATTENTION_BIT_11 +/*E1H NIG status sync attention mapped to group 4-7*/ +#define LINK_SYNC_ATTENTION_BIT_FUNC_0 RESERVED_GENERAL_ATTENTION_BIT_12 +#define LINK_SYNC_ATTENTION_BIT_FUNC_1 RESERVED_GENERAL_ATTENTION_BIT_13 +#define LINK_SYNC_ATTENTION_BIT_FUNC_2 RESERVED_GENERAL_ATTENTION_BIT_14 +#define LINK_SYNC_ATTENTION_BIT_FUNC_3 RESERVED_GENERAL_ATTENTION_BIT_15 +#define LINK_SYNC_ATTENTION_BIT_FUNC_4 RESERVED_GENERAL_ATTENTION_BIT_16 +#define LINK_SYNC_ATTENTION_BIT_FUNC_5 RESERVED_GENERAL_ATTENTION_BIT_17 +#define LINK_SYNC_ATTENTION_BIT_FUNC_6 RESERVED_GENERAL_ATTENTION_BIT_18 +#define LINK_SYNC_ATTENTION_BIT_FUNC_7 RESERVED_GENERAL_ATTENTION_BIT_19 + + #define LATCHED_ATTN_RBCR 23 #define LATCHED_ATTN_RBCT 24 #define LATCHED_ATTN_RBCN 25 @@ -4221,22 +5148,41 @@ #define PCICFG_OFFSET 0x2000 #define PCICFG_VENDOR_ID_OFFSET 0x00 #define PCICFG_DEVICE_ID_OFFSET 0x02 -#define PCICFG_SUBSYSTEM_VENDOR_ID_OFFSET 0x2c -#define PCICFG_SUBSYSTEM_ID_OFFSET 0x2e -#define PCICFG_INT_LINE 0x3c -#define PCICFG_INT_PIN 0x3d +#define PCICFG_COMMAND_OFFSET 0x04 +#define PCICFG_STATUS_OFFSET 0x06 +#define PCICFG_REVESION_ID 0x08 #define PCICFG_CACHE_LINE_SIZE 0x0c #define PCICFG_LATENCY_TIMER 0x0d -#define PCICFG_REVESION_ID 0x08 -#define PCICFG_BAR_1_LOW 0x10 -#define PCICFG_BAR_1_HIGH 0x14 -#define PCICFG_BAR_2_LOW 0x18 -#define PCICFG_BAR_2_HIGH 0x1c -#define PCICFG_GRC_ADDRESS 0x78 -#define PCICFG_GRC_DATA 0x80 +#define PCICFG_BAR_1_LOW 0x10 +#define PCICFG_BAR_1_HIGH 0x14 +#define PCICFG_BAR_2_LOW 0x18 +#define PCICFG_BAR_2_HIGH 0x1c +#define PCICFG_SUBSYSTEM_VENDOR_ID_OFFSET 0x2c +#define PCICFG_SUBSYSTEM_ID_OFFSET 0x2e +#define PCICFG_INT_LINE 0x3c +#define PCICFG_INT_PIN 0x3d +#define PCICFG_PM_CSR_OFFSET 0x4c +#define PCICFG_GRC_ADDRESS 0x78 +#define PCICFG_GRC_DATA 0x80 #define PCICFG_DEVICE_CONTROL 0xb4 #define PCICFG_LINK_CONTROL 0xbc +#define PCICFG_COMMAND_IO_SPACE (1<<0) +#define PCICFG_COMMAND_MEM_SPACE (1<<1) +#define PCICFG_COMMAND_BUS_MASTER (1<<2) +#define PCICFG_COMMAND_SPECIAL_CYCLES (1<<3) +#define PCICFG_COMMAND_MWI_CYCLES (1<<4) +#define PCICFG_COMMAND_VGA_SNOOP (1<<5) +#define PCICFG_COMMAND_PERR_ENA (1<<6) +#define PCICFG_COMMAND_STEPPING (1<<7) +#define PCICFG_COMMAND_SERR_ENA (1<<8) +#define PCICFG_COMMAND_FAST_B2B (1<<9) +#define PCICFG_COMMAND_INT_DISABLE (1<<10) +#define PCICFG_COMMAND_RESERVED (0x1f<<11) + +#define PCICFG_PM_CSR_STATE (0x3<<0) +#define PCICFG_PM_CSR_PME_STATUS (1<<15) + #define BAR_USTRORM_INTMEM 0x400000 #define BAR_CSTRORM_INTMEM 0x410000 #define BAR_XSTRORM_INTMEM 0x420000 @@ -4336,7 +5282,7 @@ #define MDIO_CL73_IEEEB0_CL73_AN_CONTROL_MAIN_RST 0x8000 #define MDIO_REG_BANK_CL73_IEEEB1 0x10 -#define MDIO_CL73_IEEEB1_AN_ADV2 0x01 +#define MDIO_CL73_IEEEB1_AN_ADV2 0x01 #define MDIO_CL73_IEEEB1_AN_ADV2_ADVR_1000M 0x0000 #define MDIO_CL73_IEEEB1_AN_ADV2_ADVR_1000M_KX 0x0020 #define MDIO_CL73_IEEEB1_AN_ADV2_ADVR_10G_KX4 0x0040 @@ -4365,7 +5311,7 @@ #define MDIO_REG_BANK_RX_ALL 0x80f0 #define MDIO_RX_ALL_RX_EQ_BOOST 0x1c #define MDIO_RX_ALL_RX_EQ_BOOST_EQUALIZER_CTRL_MASK 0x7 -#define MDIO_RX_ALL_RX_EQ_BOOST_OFFSET_CTRL 0x10 +#define MDIO_RX_ALL_RX_EQ_BOOST_OFFSET_CTRL 0x10 #define MDIO_REG_BANK_TX0 0x8060 #define MDIO_TX0_TX_DRIVER 0x17 @@ -4392,213 +5338,266 @@ #define MDIO_XGXS_BLOCK2_RX_LN_SWAP 0x10 #define MDIO_XGXS_BLOCK2_RX_LN_SWAP_ENABLE 0x8000 #define MDIO_XGXS_BLOCK2_RX_LN_SWAP_FORCE_ENABLE 0x4000 -#define MDIO_XGXS_BLOCK2_TX_LN_SWAP 0x11 +#define MDIO_XGXS_BLOCK2_TX_LN_SWAP 0x11 #define MDIO_XGXS_BLOCK2_TX_LN_SWAP_ENABLE 0x8000 -#define MDIO_XGXS_BLOCK2_UNICORE_MODE_10G 0x14 +#define MDIO_XGXS_BLOCK2_UNICORE_MODE_10G 0x14 #define MDIO_XGXS_BLOCK2_UNICORE_MODE_10G_CX4_XGXS 0x0001 #define MDIO_XGXS_BLOCK2_UNICORE_MODE_10G_HIGIG_XGXS 0x0010 -#define MDIO_XGXS_BLOCK2_TEST_MODE_LANE 0x15 +#define MDIO_XGXS_BLOCK2_TEST_MODE_LANE 0x15 #define MDIO_REG_BANK_GP_STATUS 0x8120 -#define MDIO_GP_STATUS_TOP_AN_STATUS1 0x1B -#define MDIO_GP_STATUS_TOP_AN_STATUS1_CL73_AUTONEG_COMPLETE 0x0001 -#define MDIO_GP_STATUS_TOP_AN_STATUS1_CL37_AUTONEG_COMPLETE 0x0002 -#define MDIO_GP_STATUS_TOP_AN_STATUS1_LINK_STATUS 0x0004 -#define MDIO_GP_STATUS_TOP_AN_STATUS1_DUPLEX_STATUS 0x0008 -#define MDIO_GP_STATUS_TOP_AN_STATUS1_CL73_MR_LP_NP_AN_ABLE 0x0010 -#define MDIO_GP_STATUS_TOP_AN_STATUS1_CL73_LP_NP_BAM_ABLE 0x0020 - -#define MDIO_GP_STATUS_TOP_AN_STATUS1_PAUSE_RSOLUTION_TXSIDE 0x0040 -#define MDIO_GP_STATUS_TOP_AN_STATUS1_PAUSE_RSOLUTION_RXSIDE 0x0080 -#define MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_MASK 0x3f00 -#define MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_10M 0x0000 -#define MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_100M 0x0100 -#define MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_1G 0x0200 -#define MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_2_5G 0x0300 -#define MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_5G 0x0400 -#define MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_6G 0x0500 -#define MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_10G_HIG 0x0600 -#define MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_10G_CX4 0x0700 -#define MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_12G_HIG 0x0800 -#define MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_12_5G 0x0900 -#define MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_13G 0x0A00 -#define MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_15G 0x0B00 -#define MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_16G 0x0C00 -#define MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_1G_KX 0x0D00 -#define MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_10G_KX4 0x0E00 +#define MDIO_GP_STATUS_TOP_AN_STATUS1 0x1B +#define MDIO_GP_STATUS_TOP_AN_STATUS1_CL73_AUTONEG_COMPLETE 0x0001 +#define MDIO_GP_STATUS_TOP_AN_STATUS1_CL37_AUTONEG_COMPLETE 0x0002 +#define MDIO_GP_STATUS_TOP_AN_STATUS1_LINK_STATUS 0x0004 +#define MDIO_GP_STATUS_TOP_AN_STATUS1_DUPLEX_STATUS 0x0008 +#define MDIO_GP_STATUS_TOP_AN_STATUS1_CL73_MR_LP_NP_AN_ABLE 0x0010 +#define MDIO_GP_STATUS_TOP_AN_STATUS1_CL73_LP_NP_BAM_ABLE 0x0020 +#define MDIO_GP_STATUS_TOP_AN_STATUS1_PAUSE_RSOLUTION_TXSIDE 0x0040 +#define MDIO_GP_STATUS_TOP_AN_STATUS1_PAUSE_RSOLUTION_RXSIDE 0x0080 +#define MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_MASK 0x3f00 +#define MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_10M 0x0000 +#define MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_100M 0x0100 +#define MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_1G 0x0200 +#define MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_2_5G 0x0300 +#define MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_5G 0x0400 +#define MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_6G 0x0500 +#define MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_10G_HIG 0x0600 +#define MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_10G_CX4 0x0700 +#define MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_12G_HIG 0x0800 +#define MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_12_5G 0x0900 +#define MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_13G 0x0A00 +#define MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_15G 0x0B00 +#define MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_16G 0x0C00 +#define MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_1G_KX 0x0D00 +#define MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_10G_KX4 0x0E00 #define MDIO_REG_BANK_10G_PARALLEL_DETECT 0x8130 -#define MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_CONTROL 0x11 -#define MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_CONTROL_PARDET10G_EN 0x1 -#define MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_LINK 0x13 -#define MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_LINK_CNT (0xb71<<1) +#define MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_CONTROL 0x11 +#define MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_CONTROL_PARDET10G_EN 0x1 +#define MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_LINK 0x13 +#define MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_LINK_CNT (0xb71<<1) #define MDIO_REG_BANK_SERDES_DIGITAL 0x8300 -#define MDIO_SERDES_DIGITAL_A_1000X_CONTROL1 0x10 -#define MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_FIBER_MODE 0x0001 -#define MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_TBI_IF 0x0002 -#define MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_SIGNAL_DETECT_EN 0x0004 -#define MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_INVERT_SIGNAL_DETECT 0x0008 -#define MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_AUTODET 0x0010 -#define MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_MSTR_MODE 0x0020 -#define MDIO_SERDES_DIGITAL_A_1000X_CONTROL2 0x11 -#define MDIO_SERDES_DIGITAL_A_1000X_CONTROL2_PRL_DT_EN 0x0001 -#define MDIO_SERDES_DIGITAL_A_1000X_CONTROL2_AN_FST_TMR 0x0040 -#define MDIO_SERDES_DIGITAL_A_1000X_STATUS1 0x14 -#define MDIO_SERDES_DIGITAL_A_1000X_STATUS1_DUPLEX 0x0004 -#define MDIO_SERDES_DIGITAL_A_1000X_STATUS1_SPEED_MASK 0x0018 -#define MDIO_SERDES_DIGITAL_A_1000X_STATUS1_SPEED_SHIFT 3 -#define MDIO_SERDES_DIGITAL_A_1000X_STATUS1_SPEED_2_5G 0x0018 -#define MDIO_SERDES_DIGITAL_A_1000X_STATUS1_SPEED_1G 0x0010 -#define MDIO_SERDES_DIGITAL_A_1000X_STATUS1_SPEED_100M 0x0008 -#define MDIO_SERDES_DIGITAL_A_1000X_STATUS1_SPEED_10M 0x0000 -#define MDIO_SERDES_DIGITAL_MISC1 0x18 -#define MDIO_SERDES_DIGITAL_MISC1_REFCLK_SEL_MASK 0xE000 -#define MDIO_SERDES_DIGITAL_MISC1_REFCLK_SEL_25M 0x0000 -#define MDIO_SERDES_DIGITAL_MISC1_REFCLK_SEL_100M 0x2000 -#define MDIO_SERDES_DIGITAL_MISC1_REFCLK_SEL_125M 0x4000 -#define MDIO_SERDES_DIGITAL_MISC1_REFCLK_SEL_156_25M 0x6000 -#define MDIO_SERDES_DIGITAL_MISC1_REFCLK_SEL_187_5M 0x8000 -#define MDIO_SERDES_DIGITAL_MISC1_FORCE_SPEED_SEL 0x0010 -#define MDIO_SERDES_DIGITAL_MISC1_FORCE_SPEED_MASK 0x000f -#define MDIO_SERDES_DIGITAL_MISC1_FORCE_SPEED_2_5G 0x0000 -#define MDIO_SERDES_DIGITAL_MISC1_FORCE_SPEED_5G 0x0001 -#define MDIO_SERDES_DIGITAL_MISC1_FORCE_SPEED_6G 0x0002 -#define MDIO_SERDES_DIGITAL_MISC1_FORCE_SPEED_10G_HIG 0x0003 -#define MDIO_SERDES_DIGITAL_MISC1_FORCE_SPEED_10G_CX4 0x0004 -#define MDIO_SERDES_DIGITAL_MISC1_FORCE_SPEED_12G 0x0005 -#define MDIO_SERDES_DIGITAL_MISC1_FORCE_SPEED_12_5G 0x0006 -#define MDIO_SERDES_DIGITAL_MISC1_FORCE_SPEED_13G 0x0007 -#define MDIO_SERDES_DIGITAL_MISC1_FORCE_SPEED_15G 0x0008 -#define MDIO_SERDES_DIGITAL_MISC1_FORCE_SPEED_16G 0x0009 +#define MDIO_SERDES_DIGITAL_A_1000X_CONTROL1 0x10 +#define MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_FIBER_MODE 0x0001 +#define MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_TBI_IF 0x0002 +#define MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_SIGNAL_DETECT_EN 0x0004 +#define MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_INVERT_SIGNAL_DETECT 0x0008 +#define MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_AUTODET 0x0010 +#define MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_MSTR_MODE 0x0020 +#define MDIO_SERDES_DIGITAL_A_1000X_CONTROL2 0x11 +#define MDIO_SERDES_DIGITAL_A_1000X_CONTROL2_PRL_DT_EN 0x0001 +#define MDIO_SERDES_DIGITAL_A_1000X_CONTROL2_AN_FST_TMR 0x0040 +#define MDIO_SERDES_DIGITAL_A_1000X_STATUS1 0x14 +#define MDIO_SERDES_DIGITAL_A_1000X_STATUS1_DUPLEX 0x0004 +#define MDIO_SERDES_DIGITAL_A_1000X_STATUS1_SPEED_MASK 0x0018 +#define MDIO_SERDES_DIGITAL_A_1000X_STATUS1_SPEED_SHIFT 3 +#define MDIO_SERDES_DIGITAL_A_1000X_STATUS1_SPEED_2_5G 0x0018 +#define MDIO_SERDES_DIGITAL_A_1000X_STATUS1_SPEED_1G 0x0010 +#define MDIO_SERDES_DIGITAL_A_1000X_STATUS1_SPEED_100M 0x0008 +#define MDIO_SERDES_DIGITAL_A_1000X_STATUS1_SPEED_10M 0x0000 +#define MDIO_SERDES_DIGITAL_MISC1 0x18 +#define MDIO_SERDES_DIGITAL_MISC1_REFCLK_SEL_MASK 0xE000 +#define MDIO_SERDES_DIGITAL_MISC1_REFCLK_SEL_25M 0x0000 +#define MDIO_SERDES_DIGITAL_MISC1_REFCLK_SEL_100M 0x2000 +#define MDIO_SERDES_DIGITAL_MISC1_REFCLK_SEL_125M 0x4000 +#define MDIO_SERDES_DIGITAL_MISC1_REFCLK_SEL_156_25M 0x6000 +#define MDIO_SERDES_DIGITAL_MISC1_REFCLK_SEL_187_5M 0x8000 +#define MDIO_SERDES_DIGITAL_MISC1_FORCE_SPEED_SEL 0x0010 +#define MDIO_SERDES_DIGITAL_MISC1_FORCE_SPEED_MASK 0x000f +#define MDIO_SERDES_DIGITAL_MISC1_FORCE_SPEED_2_5G 0x0000 +#define MDIO_SERDES_DIGITAL_MISC1_FORCE_SPEED_5G 0x0001 +#define MDIO_SERDES_DIGITAL_MISC1_FORCE_SPEED_6G 0x0002 +#define MDIO_SERDES_DIGITAL_MISC1_FORCE_SPEED_10G_HIG 0x0003 +#define MDIO_SERDES_DIGITAL_MISC1_FORCE_SPEED_10G_CX4 0x0004 +#define MDIO_SERDES_DIGITAL_MISC1_FORCE_SPEED_12G 0x0005 +#define MDIO_SERDES_DIGITAL_MISC1_FORCE_SPEED_12_5G 0x0006 +#define MDIO_SERDES_DIGITAL_MISC1_FORCE_SPEED_13G 0x0007 +#define MDIO_SERDES_DIGITAL_MISC1_FORCE_SPEED_15G 0x0008 +#define MDIO_SERDES_DIGITAL_MISC1_FORCE_SPEED_16G 0x0009 #define MDIO_REG_BANK_OVER_1G 0x8320 -#define MDIO_OVER_1G_DIGCTL_3_4 0x14 -#define MDIO_OVER_1G_DIGCTL_3_4_MP_ID_MASK 0xffe0 -#define MDIO_OVER_1G_DIGCTL_3_4_MP_ID_SHIFT 5 -#define MDIO_OVER_1G_UP1 0x19 -#define MDIO_OVER_1G_UP1_2_5G 0x0001 -#define MDIO_OVER_1G_UP1_5G 0x0002 -#define MDIO_OVER_1G_UP1_6G 0x0004 -#define MDIO_OVER_1G_UP1_10G 0x0010 -#define MDIO_OVER_1G_UP1_10GH 0x0008 -#define MDIO_OVER_1G_UP1_12G 0x0020 -#define MDIO_OVER_1G_UP1_12_5G 0x0040 -#define MDIO_OVER_1G_UP1_13G 0x0080 -#define MDIO_OVER_1G_UP1_15G 0x0100 -#define MDIO_OVER_1G_UP1_16G 0x0200 -#define MDIO_OVER_1G_UP2 0x1A -#define MDIO_OVER_1G_UP2_IPREDRIVER_MASK 0x0007 -#define MDIO_OVER_1G_UP2_IDRIVER_MASK 0x0038 -#define MDIO_OVER_1G_UP2_PREEMPHASIS_MASK 0x03C0 -#define MDIO_OVER_1G_UP3 0x1B -#define MDIO_OVER_1G_UP3_HIGIG2 0x0001 -#define MDIO_OVER_1G_LP_UP1 0x1C -#define MDIO_OVER_1G_LP_UP2 0x1D -#define MDIO_OVER_1G_LP_UP2_MR_ADV_OVER_1G_MASK 0x03ff -#define MDIO_OVER_1G_LP_UP2_PREEMPHASIS_MASK 0x0780 -#define MDIO_OVER_1G_LP_UP2_PREEMPHASIS_SHIFT 7 -#define MDIO_OVER_1G_LP_UP3 0x1E +#define MDIO_OVER_1G_DIGCTL_3_4 0x14 +#define MDIO_OVER_1G_DIGCTL_3_4_MP_ID_MASK 0xffe0 +#define MDIO_OVER_1G_DIGCTL_3_4_MP_ID_SHIFT 5 +#define MDIO_OVER_1G_UP1 0x19 +#define MDIO_OVER_1G_UP1_2_5G 0x0001 +#define MDIO_OVER_1G_UP1_5G 0x0002 +#define MDIO_OVER_1G_UP1_6G 0x0004 +#define MDIO_OVER_1G_UP1_10G 0x0010 +#define MDIO_OVER_1G_UP1_10GH 0x0008 +#define MDIO_OVER_1G_UP1_12G 0x0020 +#define MDIO_OVER_1G_UP1_12_5G 0x0040 +#define MDIO_OVER_1G_UP1_13G 0x0080 +#define MDIO_OVER_1G_UP1_15G 0x0100 +#define MDIO_OVER_1G_UP1_16G 0x0200 +#define MDIO_OVER_1G_UP2 0x1A +#define MDIO_OVER_1G_UP2_IPREDRIVER_MASK 0x0007 +#define MDIO_OVER_1G_UP2_IDRIVER_MASK 0x0038 +#define MDIO_OVER_1G_UP2_PREEMPHASIS_MASK 0x03C0 +#define MDIO_OVER_1G_UP3 0x1B +#define MDIO_OVER_1G_UP3_HIGIG2 0x0001 +#define MDIO_OVER_1G_LP_UP1 0x1C +#define MDIO_OVER_1G_LP_UP2 0x1D +#define MDIO_OVER_1G_LP_UP2_MR_ADV_OVER_1G_MASK 0x03ff +#define MDIO_OVER_1G_LP_UP2_PREEMPHASIS_MASK 0x0780 +#define MDIO_OVER_1G_LP_UP2_PREEMPHASIS_SHIFT 7 +#define MDIO_OVER_1G_LP_UP3 0x1E #define MDIO_REG_BANK_BAM_NEXT_PAGE 0x8350 -#define MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL 0x10 -#define MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL_BAM_MODE 0x0001 -#define MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL_TETON_AN 0x0002 +#define MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL 0x10 +#define MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL_BAM_MODE 0x0001 +#define MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL_TETON_AN 0x0002 + +#define MDIO_REG_BANK_CL73_USERB0 0x8370 +#define MDIO_CL73_USERB0_CL73_BAM_CTRL1 0x12 +#define MDIO_CL73_USERB0_CL73_BAM_CTRL1_BAM_EN 0x8000 +#define MDIO_CL73_USERB0_CL73_BAM_CTRL1_BAM_STATION_MNGR_EN 0x4000 +#define MDIO_CL73_USERB0_CL73_BAM_CTRL1_BAM_NP_AFTER_BP_EN 0x2000 +#define MDIO_CL73_USERB0_CL73_BAM_CTRL3 0x14 +#define MDIO_CL73_USERB0_CL73_BAM_CTRL3_USE_CL73_HCD_MR 0x0001 + +#define MDIO_REG_BANK_AER_BLOCK 0xFFD0 +#define MDIO_AER_BLOCK_AER_REG 0x1E + +#define MDIO_REG_BANK_COMBO_IEEE0 0xFFE0 +#define MDIO_COMBO_IEEE0_MII_CONTROL 0x10 +#define MDIO_COMBO_IEEO_MII_CONTROL_MAN_SGMII_SP_MASK 0x2040 +#define MDIO_COMBO_IEEO_MII_CONTROL_MAN_SGMII_SP_10 0x0000 +#define MDIO_COMBO_IEEO_MII_CONTROL_MAN_SGMII_SP_100 0x2000 +#define MDIO_COMBO_IEEO_MII_CONTROL_MAN_SGMII_SP_1000 0x0040 +#define MDIO_COMBO_IEEO_MII_CONTROL_FULL_DUPLEX 0x0100 +#define MDIO_COMBO_IEEO_MII_CONTROL_RESTART_AN 0x0200 +#define MDIO_COMBO_IEEO_MII_CONTROL_AN_EN 0x1000 +#define MDIO_COMBO_IEEO_MII_CONTROL_LOOPBACK 0x4000 +#define MDIO_COMBO_IEEO_MII_CONTROL_RESET 0x8000 +#define MDIO_COMBO_IEEE0_MII_STATUS 0x11 +#define MDIO_COMBO_IEEE0_MII_STATUS_LINK_PASS 0x0004 +#define MDIO_COMBO_IEEE0_MII_STATUS_AUTONEG_COMPLETE 0x0020 +#define MDIO_COMBO_IEEE0_AUTO_NEG_ADV 0x14 +#define MDIO_COMBO_IEEE0_AUTO_NEG_ADV_FULL_DUPLEX 0x0020 +#define MDIO_COMBO_IEEE0_AUTO_NEG_ADV_HALF_DUPLEX 0x0040 +#define MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_MASK 0x0180 +#define MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_NONE 0x0000 +#define MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_SYMMETRIC 0x0080 +#define MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC 0x0100 +#define MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH 0x0180 +#define MDIO_COMBO_IEEE0_AUTO_NEG_ADV_NEXT_PAGE 0x8000 +#define MDIO_COMBO_IEEE0_AUTO_NEG_LINK_PARTNER_ABILITY1 0x15 +#define MDIO_COMBO_IEEE0_AUTO_NEG_LINK_PARTNER_ABILITY1_NEXT_PAGE 0x8000 +#define MDIO_COMBO_IEEE0_AUTO_NEG_LINK_PARTNER_ABILITY1_ACK 0x4000 +#define MDIO_COMBO_IEEE0_AUTO_NEG_LINK_PARTNER_ABILITY1_PAUSE_MASK 0x0180 +#define MDIO_COMBO_IEEE0_AUTO_NEG_LINK_PARTNER_ABILITY1_PAUSE_NONE 0x0000 +#define MDIO_COMBO_IEEE0_AUTO_NEG_LINK_PARTNER_ABILITY1_PAUSE_BOTH 0x0180 +#define MDIO_COMBO_IEEE0_AUTO_NEG_LINK_PARTNER_ABILITY1_HALF_DUP_CAP 0x0040 +#define MDIO_COMBO_IEEE0_AUTO_NEG_LINK_PARTNER_ABILITY1_FULL_DUP_CAP 0x0020 +/*WhenthelinkpartnerisinSGMIImode(bit0=1),then +bit15=link,bit12=duplex,bits11:10=speed,bit14=acknowledge. +Theotherbitsarereservedandshouldbezero*/ +#define MDIO_COMBO_IEEE0_AUTO_NEG_LINK_PARTNER_ABILITY1_SGMII_MODE 0x0001 + + +#define MDIO_PMA_DEVAD 0x1 +/*ieee*/ +#define MDIO_PMA_REG_CTRL 0x0 +#define MDIO_PMA_REG_STATUS 0x1 +#define MDIO_PMA_REG_10G_CTRL2 0x7 +#define MDIO_PMA_REG_RX_SD 0xa +/*bcm*/ +#define MDIO_PMA_REG_BCM_CTRL 0x0096 +#define MDIO_PMA_REG_FEC_CTRL 0x00ab +#define MDIO_PMA_REG_RX_ALARM_CTRL 0x9000 +#define MDIO_PMA_REG_LASI_CTRL 0x9002 +#define MDIO_PMA_REG_RX_ALARM 0x9003 +#define MDIO_PMA_REG_TX_ALARM 0x9004 +#define MDIO_PMA_REG_LASI_STATUS 0x9005 +#define MDIO_PMA_REG_PHY_IDENTIFIER 0xc800 +#define MDIO_PMA_REG_DIGITAL_CTRL 0xc808 +#define MDIO_PMA_REG_DIGITAL_STATUS 0xc809 +#define MDIO_PMA_REG_TX_POWER_DOWN 0xca02 +#define MDIO_PMA_REG_CMU_PLL_BYPASS 0xca09 +#define MDIO_PMA_REG_MISC_CTRL 0xca0a +#define MDIO_PMA_REG_GEN_CTRL 0xca10 +#define MDIO_PMA_REG_GEN_CTRL_ROM_RESET_INTERNAL_MP 0x0188 +#define MDIO_PMA_REG_GEN_CTRL_ROM_MICRO_RESET 0x018a +#define MDIO_PMA_REG_ROM_VER1 0xca19 +#define MDIO_PMA_REG_ROM_VER2 0xca1a +#define MDIO_PMA_REG_EDC_FFE_MAIN 0xca1b +#define MDIO_PMA_REG_PLL_BANDWIDTH 0xca1d +#define MDIO_PMA_REG_CDR_BANDWIDTH 0xca46 +#define MDIO_PMA_REG_MISC_CTRL1 0xca85 + +#define MDIO_PMA_REG_7101_RESET 0xc000 +#define MDIO_PMA_REG_7107_LED_CNTL 0xc007 +#define MDIO_PMA_REG_7101_VER1 0xc026 +#define MDIO_PMA_REG_7101_VER2 0xc027 + + +#define MDIO_WIS_DEVAD 0x2 +/*bcm*/ +#define MDIO_WIS_REG_LASI_CNTL 0x9002 +#define MDIO_WIS_REG_LASI_STATUS 0x9005 + +#define MDIO_PCS_DEVAD 0x3 +#define MDIO_PCS_REG_STATUS 0x0020 +#define MDIO_PCS_REG_LASI_STATUS 0x9005 +#define MDIO_PCS_REG_7101_DSP_ACCESS 0xD000 +#define MDIO_PCS_REG_7101_SPI_MUX 0xD008 +#define MDIO_PCS_REG_7101_SPI_CTRL_ADDR 0xE12A +#define MDIO_PCS_REG_7101_SPI_RESET_BIT (5) +#define MDIO_PCS_REG_7101_SPI_FIFO_ADDR 0xE02A +#define MDIO_PCS_REG_7101_SPI_FIFO_ADDR_WRITE_ENABLE_CMD (6) +#define MDIO_PCS_REG_7101_SPI_FIFO_ADDR_BULK_ERASE_CMD (0xC7) +#define MDIO_PCS_REG_7101_SPI_FIFO_ADDR_PAGE_PROGRAM_CMD (2) +#define MDIO_PCS_REG_7101_SPI_BYTES_TO_TRANSFER_ADDR 0xE028 + -#define MDIO_REG_BANK_CL73_USERB0 0x8370 -#define MDIO_CL73_USERB0_CL73_BAM_CTRL1 0x12 -#define MDIO_CL73_USERB0_CL73_BAM_CTRL1_BAM_EN 0x8000 -#define MDIO_CL73_USERB0_CL73_BAM_CTRL1_BAM_STATION_MNGR_EN 0x4000 -#define MDIO_CL73_USERB0_CL73_BAM_CTRL1_BAM_NP_AFTER_BP_EN 0x2000 -#define MDIO_CL73_USERB0_CL73_BAM_CTRL3 0x14 -#define MDIO_CL73_USERB0_CL73_BAM_CTRL3_USE_CL73_HCD_MR 0x0001 +#define MDIO_XS_DEVAD 0x4 +#define MDIO_XS_PLL_SEQUENCER 0x8000 +#define MDIO_XS_SFX7101_XGXS_TEST1 0xc00a -#define MDIO_REG_BANK_AER_BLOCK 0xFFD0 -#define MDIO_AER_BLOCK_AER_REG 0x1E +#define MDIO_AN_DEVAD 0x7 +/*ieee*/ +#define MDIO_AN_REG_CTRL 0x0000 +#define MDIO_AN_REG_STATUS 0x0001 +#define MDIO_AN_REG_STATUS_AN_COMPLETE 0x0020 +#define MDIO_AN_REG_ADV_PAUSE 0x0010 +#define MDIO_AN_REG_ADV_PAUSE_PAUSE 0x0400 +#define MDIO_AN_REG_ADV_PAUSE_ASYMMETRIC 0x0800 +#define MDIO_AN_REG_ADV_PAUSE_BOTH 0x0C00 +#define MDIO_AN_REG_ADV_PAUSE_MASK 0x0C00 +#define MDIO_AN_REG_ADV 0x0011 +#define MDIO_AN_REG_ADV2 0x0012 +#define MDIO_AN_REG_LP_AUTO_NEG 0x0013 +#define MDIO_AN_REG_MASTER_STATUS 0x0021 +/*bcm*/ +#define MDIO_AN_REG_LINK_STATUS 0x8304 +#define MDIO_AN_REG_CL37_CL73 0x8370 +#define MDIO_AN_REG_CL37_AN 0xffe0 +#define MDIO_AN_REG_CL37_FD 0xffe4 -#define MDIO_REG_BANK_COMBO_IEEE0 0xFFE0 -#define MDIO_COMBO_IEEE0_MII_CONTROL 0x10 -#define MDIO_COMBO_IEEO_MII_CONTROL_MAN_SGMII_SP_MASK 0x2040 -#define MDIO_COMBO_IEEO_MII_CONTROL_MAN_SGMII_SP_10 0x0000 -#define MDIO_COMBO_IEEO_MII_CONTROL_MAN_SGMII_SP_100 0x2000 -#define MDIO_COMBO_IEEO_MII_CONTROL_MAN_SGMII_SP_1000 0x0040 -#define MDIO_COMBO_IEEO_MII_CONTROL_FULL_DUPLEX 0x0100 -#define MDIO_COMBO_IEEO_MII_CONTROL_RESTART_AN 0x0200 -#define MDIO_COMBO_IEEO_MII_CONTROL_AN_EN 0x1000 -#define MDIO_COMBO_IEEO_MII_CONTROL_LOOPBACK 0x4000 -#define MDIO_COMBO_IEEO_MII_CONTROL_RESET 0x8000 -#define MDIO_COMBO_IEEE0_MII_STATUS 0x11 -#define MDIO_COMBO_IEEE0_MII_STATUS_LINK_PASS 0x0004 -#define MDIO_COMBO_IEEE0_MII_STATUS_AUTONEG_COMPLETE 0x0020 -#define MDIO_COMBO_IEEE0_AUTO_NEG_ADV 0x14 -#define MDIO_COMBO_IEEE0_AUTO_NEG_ADV_FULL_DUPLEX 0x0020 -#define MDIO_COMBO_IEEE0_AUTO_NEG_ADV_HALF_DUPLEX 0x0040 -#define MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_MASK 0x0180 -#define MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_NONE 0x0000 -#define MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_SYMMETRIC 0x0080 -#define MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC 0x0100 -#define MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH 0x0180 -#define MDIO_COMBO_IEEE0_AUTO_NEG_ADV_NEXT_PAGE 0x8000 -#define MDIO_COMBO_IEEE0_AUTO_NEG_LINK_PARTNER_ABILITY1 0x15 -#define MDIO_COMBO_IEEE0_AUTO_NEG_LINK_PARTNER_ABILITY1_NEXT_PAGE 0x8000 -#define MDIO_COMBO_IEEE0_AUTO_NEG_LINK_PARTNER_ABILITY1_ACK 0x4000 -#define MDIO_COMBO_IEEE0_AUTO_NEG_LINK_PARTNER_ABILITY1_PAUSE_MASK 0x0180 -#define MDIO_COMBO_IEEE0_AUTO_NEG_LINK_PARTNER_ABILITY1_PAUSE_NONE\ - 0x0000 -#define MDIO_COMBO_IEEE0_AUTO_NEG_LINK_PARTNER_ABILITY1_PAUSE_BOTH\ - 0x0180 -#define MDIO_COMBO_IEEE0_AUTO_NEG_LINK_PARTNER_ABILITY1_HALF_DUP_CAP 0x0040 -#define MDIO_COMBO_IEEE0_AUTO_NEG_LINK_PARTNER_ABILITY1_FULL_DUP_CAP 0x0020 -#define MDIO_COMBO_IEEE0_AUTO_NEG_LINK_PARTNER_ABILITY1_SGMII_MODE 0x0001 +#define IGU_FUNC_BASE 0x0400 -#define EXT_PHY_AUTO_NEG_DEVAD 0x7 -#define EXT_PHY_OPT_PMA_PMD_DEVAD 0x1 -#define EXT_PHY_OPT_WIS_DEVAD 0x2 -#define EXT_PHY_OPT_PCS_DEVAD 0x3 -#define EXT_PHY_OPT_PHY_XS_DEVAD 0x4 -#define EXT_PHY_OPT_CNTL 0x0 -#define EXT_PHY_OPT_CNTL2 0x7 -#define EXT_PHY_OPT_PMD_RX_SD 0xa -#define EXT_PHY_OPT_PMD_MISC_CNTL 0xca0a -#define EXT_PHY_OPT_PHY_IDENTIFIER 0xc800 -#define EXT_PHY_OPT_PMD_DIGITAL_CNT 0xc808 -#define EXT_PHY_OPT_PMD_DIGITAL_SATUS 0xc809 -#define EXT_PHY_OPT_CMU_PLL_BYPASS 0xca09 -#define EXT_PHY_OPT_LASI_CNTL 0x9002 -#define EXT_PHY_OPT_RX_ALARM 0x9003 -#define EXT_PHY_OPT_LASI_STATUS 0x9005 -#define EXT_PHY_OPT_PCS_STATUS 0x0020 -#define EXT_PHY_OPT_XGXS_LANE_STATUS 0x0018 -#define EXT_PHY_OPT_AN_LINK_STATUS 0x8304 -#define EXT_PHY_OPT_AN_CL37_CL73 0x8370 -#define EXT_PHY_OPT_AN_CL37_FD 0xffe4 -#define EXT_PHY_OPT_AN_CL37_AN 0xffe0 -#define EXT_PHY_OPT_AN_ADV 0x11 +#define IGU_ADDR_MSIX 0x0000 +#define IGU_ADDR_INT_ACK 0x0200 +#define IGU_ADDR_PROD_UPD 0x0201 +#define IGU_ADDR_ATTN_BITS_UPD 0x0202 +#define IGU_ADDR_ATTN_BITS_SET 0x0203 +#define IGU_ADDR_ATTN_BITS_CLR 0x0204 +#define IGU_ADDR_COALESCE_NOW 0x0205 +#define IGU_ADDR_SIMD_MASK 0x0206 +#define IGU_ADDR_SIMD_NOMASK 0x0207 +#define IGU_ADDR_MSI_CTL 0x0210 +#define IGU_ADDR_MSI_ADDR_LO 0x0211 +#define IGU_ADDR_MSI_ADDR_HI 0x0212 +#define IGU_ADDR_MSI_DATA 0x0213 -#define EXT_PHY_KR_PMA_PMD_DEVAD 0x1 -#define EXT_PHY_KR_PCS_DEVAD 0x3 -#define EXT_PHY_KR_AUTO_NEG_DEVAD 0x7 -#define EXT_PHY_KR_CTRL 0x0000 -#define EXT_PHY_KR_STATUS 0x0001 -#define EXT_PHY_KR_AUTO_NEG_COMPLETE 0x0020 -#define EXT_PHY_KR_AUTO_NEG_ADVERT 0x0010 -#define EXT_PHY_KR_AUTO_NEG_ADVERT_PAUSE 0x0400 -#define EXT_PHY_KR_AUTO_NEG_ADVERT_PAUSE_ASYMMETRIC 0x0800 -#define EXT_PHY_KR_AUTO_NEG_ADVERT_PAUSE_BOTH 0x0C00 -#define EXT_PHY_KR_AUTO_NEG_ADVERT_PAUSE_MASK 0x0C00 -#define EXT_PHY_KR_LP_AUTO_NEG 0x0013 -#define EXT_PHY_KR_CTRL2 0x0007 -#define EXT_PHY_KR_PCS_STATUS 0x0020 -#define EXT_PHY_KR_PMD_CTRL 0x0096 -#define EXT_PHY_KR_LASI_CNTL 0x9002 -#define EXT_PHY_KR_LASI_STATUS 0x9005 -#define EXT_PHY_KR_MISC_CTRL1 0xca85 -#define EXT_PHY_KR_GEN_CTRL 0xca10 -#define EXT_PHY_KR_ROM_CODE 0xca19 -#define EXT_PHY_KR_ROM_RESET_INTERNAL_MP 0x0188 -#define EXT_PHY_KR_ROM_MICRO_RESET 0x018a +#define IGU_INT_ENABLE 0 +#define IGU_INT_DISABLE 1 +#define IGU_INT_NOP 2 +#define IGU_INT_NOP2 3 -#define EXT_PHY_SFX7101_XGXS_TEST1 0xc00a diff --git a/drivers/net/bonding/bond_alb.c b/drivers/net/bonding/bond_alb.c index 5a673725471c..b211486a0ca3 100644 --- a/drivers/net/bonding/bond_alb.c +++ b/drivers/net/bonding/bond_alb.c @@ -419,8 +419,10 @@ static void rlb_teach_disabled_mac_on_primary(struct bonding *bond, u8 addr[]) } if (!bond->alb_info.primary_is_promisc) { - bond->alb_info.primary_is_promisc = 1; - dev_set_promiscuity(bond->curr_active_slave->dev, 1); + if (!dev_set_promiscuity(bond->curr_active_slave->dev, 1)) + bond->alb_info.primary_is_promisc = 1; + else + bond->alb_info.primary_is_promisc = 0; } bond->alb_info.rlb_promisc_timeout_counter = 0; diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 50a40e433154..9737c06045d6 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -88,6 +88,7 @@ #define BOND_LINK_ARP_INTERV 0 static int max_bonds = BOND_DEFAULT_MAX_BONDS; +static int num_grat_arp = 1; static int miimon = BOND_LINK_MON_INTERV; static int updelay = 0; static int downdelay = 0; @@ -99,11 +100,13 @@ static char *xmit_hash_policy = NULL; static int arp_interval = BOND_LINK_ARP_INTERV; static char *arp_ip_target[BOND_MAX_ARP_TARGETS] = { NULL, }; static char *arp_validate = NULL; -static int fail_over_mac = 0; +static char *fail_over_mac = NULL; struct bond_params bonding_defaults; module_param(max_bonds, int, 0); MODULE_PARM_DESC(max_bonds, "Max number of bonded devices"); +module_param(num_grat_arp, int, 0644); +MODULE_PARM_DESC(num_grat_arp, "Number of gratuitous ARP packets to send on failover event"); module_param(miimon, int, 0); MODULE_PARM_DESC(miimon, "Link check interval in milliseconds"); module_param(updelay, int, 0); @@ -133,8 +136,8 @@ module_param_array(arp_ip_target, charp, NULL, 0); MODULE_PARM_DESC(arp_ip_target, "arp targets in n.n.n.n form"); module_param(arp_validate, charp, 0); MODULE_PARM_DESC(arp_validate, "validate src/dst of ARP probes: none (default), active, backup or all"); -module_param(fail_over_mac, int, 0); -MODULE_PARM_DESC(fail_over_mac, "For active-backup, do not set all slaves to the same MAC. 0 of off (default), 1 for on."); +module_param(fail_over_mac, charp, 0); +MODULE_PARM_DESC(fail_over_mac, "For active-backup, do not set all slaves to the same MAC. none (default), active or follow"); /*----------------------------- Global variables ----------------------------*/ @@ -187,6 +190,13 @@ struct bond_parm_tbl arp_validate_tbl[] = { { NULL, -1}, }; +struct bond_parm_tbl fail_over_mac_tbl[] = { +{ "none", BOND_FOM_NONE}, +{ "active", BOND_FOM_ACTIVE}, +{ "follow", BOND_FOM_FOLLOW}, +{ NULL, -1}, +}; + /*-------------------------- Forward declarations ---------------------------*/ static void bond_send_gratuitous_arp(struct bonding *bond); @@ -261,14 +271,14 @@ static int bond_add_vlan(struct bonding *bond, unsigned short vlan_id) */ static int bond_del_vlan(struct bonding *bond, unsigned short vlan_id) { - struct vlan_entry *vlan, *next; + struct vlan_entry *vlan; int res = -ENODEV; dprintk("bond: %s, vlan id %d\n", bond->dev->name, vlan_id); write_lock_bh(&bond->lock); - list_for_each_entry_safe(vlan, next, &bond->vlan_list, vlan_list) { + list_for_each_entry(vlan, &bond->vlan_list, vlan_list) { if (vlan->vlan_id == vlan_id) { list_del(&vlan->vlan_list); @@ -762,39 +772,49 @@ static struct dev_mc_list *bond_mc_list_find_dmi(struct dev_mc_list *dmi, struct /* * Push the promiscuity flag down to appropriate slaves */ -static void bond_set_promiscuity(struct bonding *bond, int inc) +static int bond_set_promiscuity(struct bonding *bond, int inc) { + int err = 0; if (USES_PRIMARY(bond->params.mode)) { /* write lock already acquired */ if (bond->curr_active_slave) { - dev_set_promiscuity(bond->curr_active_slave->dev, inc); + err = dev_set_promiscuity(bond->curr_active_slave->dev, + inc); } } else { struct slave *slave; int i; bond_for_each_slave(bond, slave, i) { - dev_set_promiscuity(slave->dev, inc); + err = dev_set_promiscuity(slave->dev, inc); + if (err) + return err; } } + return err; } /* * Push the allmulti flag down to all slaves */ -static void bond_set_allmulti(struct bonding *bond, int inc) +static int bond_set_allmulti(struct bonding *bond, int inc) { + int err = 0; if (USES_PRIMARY(bond->params.mode)) { /* write lock already acquired */ if (bond->curr_active_slave) { - dev_set_allmulti(bond->curr_active_slave->dev, inc); + err = dev_set_allmulti(bond->curr_active_slave->dev, + inc); } } else { struct slave *slave; int i; bond_for_each_slave(bond, slave, i) { - dev_set_allmulti(slave->dev, inc); + err = dev_set_allmulti(slave->dev, inc); + if (err) + return err; } } + return err; } /* @@ -955,6 +975,7 @@ static void bond_mc_swap(struct bonding *bond, struct slave *new_active, struct } if (new_active) { + /* FIXME: Signal errors upstream. */ if (bond->dev->flags & IFF_PROMISC) { dev_set_promiscuity(new_active->dev, 1); } @@ -970,6 +991,82 @@ static void bond_mc_swap(struct bonding *bond, struct slave *new_active, struct } } +/* + * bond_do_fail_over_mac + * + * Perform special MAC address swapping for fail_over_mac settings + * + * Called with RTNL, bond->lock for read, curr_slave_lock for write_bh. + */ +static void bond_do_fail_over_mac(struct bonding *bond, + struct slave *new_active, + struct slave *old_active) +{ + u8 tmp_mac[ETH_ALEN]; + struct sockaddr saddr; + int rv; + + switch (bond->params.fail_over_mac) { + case BOND_FOM_ACTIVE: + if (new_active) + memcpy(bond->dev->dev_addr, new_active->dev->dev_addr, + new_active->dev->addr_len); + break; + case BOND_FOM_FOLLOW: + /* + * if new_active && old_active, swap them + * if just old_active, do nothing (going to no active slave) + * if just new_active, set new_active to bond's MAC + */ + if (!new_active) + return; + + write_unlock_bh(&bond->curr_slave_lock); + read_unlock(&bond->lock); + + if (old_active) { + memcpy(tmp_mac, new_active->dev->dev_addr, ETH_ALEN); + memcpy(saddr.sa_data, old_active->dev->dev_addr, + ETH_ALEN); + saddr.sa_family = new_active->dev->type; + } else { + memcpy(saddr.sa_data, bond->dev->dev_addr, ETH_ALEN); + saddr.sa_family = bond->dev->type; + } + + rv = dev_set_mac_address(new_active->dev, &saddr); + if (rv) { + printk(KERN_ERR DRV_NAME + ": %s: Error %d setting MAC of slave %s\n", + bond->dev->name, -rv, new_active->dev->name); + goto out; + } + + if (!old_active) + goto out; + + memcpy(saddr.sa_data, tmp_mac, ETH_ALEN); + saddr.sa_family = old_active->dev->type; + + rv = dev_set_mac_address(old_active->dev, &saddr); + if (rv) + printk(KERN_ERR DRV_NAME + ": %s: Error %d setting MAC of slave %s\n", + bond->dev->name, -rv, new_active->dev->name); +out: + read_lock(&bond->lock); + write_lock_bh(&bond->curr_slave_lock); + break; + default: + printk(KERN_ERR DRV_NAME + ": %s: bond_do_fail_over_mac impossible: bad policy %d\n", + bond->dev->name, bond->params.fail_over_mac); + break; + } + +} + + /** * find_best_interface - select the best available slave to be the active one * @bond: our bonding struct @@ -1037,7 +1134,8 @@ static struct slave *bond_find_best_slave(struct bonding *bond) * because it is apparently the best available slave we have, even though its * updelay hasn't timed out yet. * - * Warning: Caller must hold curr_slave_lock for writing. + * If new_active is not NULL, caller must hold bond->lock for read and + * curr_slave_lock for write_bh. */ void bond_change_active_slave(struct bonding *bond, struct slave *new_active) { @@ -1048,6 +1146,8 @@ void bond_change_active_slave(struct bonding *bond, struct slave *new_active) } 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 @@ -1059,7 +1159,6 @@ void bond_change_active_slave(struct bonding *bond, struct slave *new_active) new_active->delay = 0; new_active->link = BOND_LINK_UP; - new_active->jiffies = jiffies; if (bond->params.mode == BOND_MODE_8023AD) { bond_3ad_handle_link_change(new_active, BOND_LINK_UP); @@ -1101,22 +1200,22 @@ void bond_change_active_slave(struct bonding *bond, struct slave *new_active) if (new_active) { bond_set_slave_active_flags(new_active); - } - /* when bonding does not set the slave MAC address, the bond MAC - * address is the one of the active slave. - */ - if (new_active && bond->params.fail_over_mac) - memcpy(bond->dev->dev_addr, new_active->dev->dev_addr, - new_active->dev->addr_len); - if (bond->curr_active_slave && - test_bit(__LINK_STATE_LINKWATCH_PENDING, - &bond->curr_active_slave->dev->state)) { - dprintk("delaying gratuitous arp on %s\n", - bond->curr_active_slave->dev->name); - bond->send_grat_arp = 1; - } else + if (bond->params.fail_over_mac) + bond_do_fail_over_mac(bond, new_active, + old_active); + + bond->send_grat_arp = bond->params.num_grat_arp; bond_send_gratuitous_arp(bond); + + write_unlock_bh(&bond->curr_slave_lock); + read_unlock(&bond->lock); + + netdev_bonding_change(bond->dev); + + read_lock(&bond->lock); + write_lock_bh(&bond->curr_slave_lock); + } } } @@ -1129,7 +1228,7 @@ void bond_change_active_slave(struct bonding *bond, struct slave *new_active) * - The primary_slave has got its link back. * - A slave has got its link back and there's no old curr_active_slave. * - * Warning: Caller must hold curr_slave_lock for writing. + * Caller must hold bond->lock for read and curr_slave_lock for write_bh. */ void bond_select_active_slave(struct bonding *bond) { @@ -1376,14 +1475,14 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev) printk(KERN_WARNING DRV_NAME ": %s: Warning: The first slave device " "specified does not support setting the MAC " - "address. Enabling the fail_over_mac option.", + "address. Setting fail_over_mac to active.", bond_dev->name); - bond->params.fail_over_mac = 1; - } else if (!bond->params.fail_over_mac) { + bond->params.fail_over_mac = BOND_FOM_ACTIVE; + } else if (bond->params.fail_over_mac != BOND_FOM_ACTIVE) { printk(KERN_ERR DRV_NAME ": %s: Error: The slave device specified " "does not support setting the MAC address, " - "but fail_over_mac is not enabled.\n" + "but fail_over_mac is not set to active.\n" , bond_dev->name); res = -EOPNOTSUPP; goto err_undo_flags; @@ -1456,20 +1555,24 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev) if (!USES_PRIMARY(bond->params.mode)) { /* set promiscuity level to new slave */ if (bond_dev->flags & IFF_PROMISC) { - dev_set_promiscuity(slave_dev, 1); + res = dev_set_promiscuity(slave_dev, 1); + if (res) + goto err_close; } /* set allmulti level to new slave */ if (bond_dev->flags & IFF_ALLMULTI) { - dev_set_allmulti(slave_dev, 1); + res = dev_set_allmulti(slave_dev, 1); + if (res) + goto err_close; } - netif_tx_lock_bh(bond_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); } - netif_tx_unlock_bh(bond_dev); + netif_addr_unlock_bh(bond_dev); } if (bond->params.mode == BOND_MODE_8023AD) { @@ -1490,6 +1593,10 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev) bond_compute_features(bond); + write_unlock_bh(&bond->lock); + + read_lock(&bond->lock); + new_slave->last_arp_rx = jiffies; if (bond->params.miimon && !bond->params.use_carrier) { @@ -1566,6 +1673,8 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev) } } + write_lock_bh(&bond->curr_slave_lock); + switch (bond->params.mode) { case BOND_MODE_ACTIVEBACKUP: bond_set_slave_inactive_flags(new_slave); @@ -1613,9 +1722,11 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev) break; } /* switch(bond_mode) */ + write_unlock_bh(&bond->curr_slave_lock); + bond_set_carrier(bond); - write_unlock_bh(&bond->lock); + read_unlock(&bond->lock); res = bond_create_slave_symlinks(bond_dev, slave_dev); if (res) @@ -1639,6 +1750,10 @@ err_unset_master: err_restore_mac: if (!bond->params.fail_over_mac) { + /* XXX TODO - fom follow mode needs to change master's + * MAC if this slave's MAC is in use by the bond, or at + * least print a warning. + */ memcpy(addr.sa_data, new_slave->perm_hwaddr, ETH_ALEN); addr.sa_family = slave_dev->type; dev_set_mac_address(slave_dev, &addr); @@ -1693,20 +1808,18 @@ int bond_release(struct net_device *bond_dev, struct net_device *slave_dev) return -EINVAL; } - 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 - ": %s: Warning: the permanent HWaddr of %s - " - "%s - is still in use by %s. " - "Set the HWaddr of %s to a different address " - "to avoid conflicts.\n", - bond_dev->name, - slave_dev->name, - print_mac(mac, slave->perm_hwaddr), - bond_dev->name, - slave_dev->name); + if (!bond->params.fail_over_mac) { + 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 + ": %s: Warning: the permanent HWaddr of %s - " + "%s - is still in use by %s. " + "Set the HWaddr of %s to a different address " + "to avoid conflicts.\n", + bond_dev->name, slave_dev->name, + print_mac(mac, slave->perm_hwaddr), + bond_dev->name, slave_dev->name); } /* Inform AD package of unbinding of slave. */ @@ -1823,9 +1936,9 @@ int bond_release(struct net_device *bond_dev, struct net_device *slave_dev) } /* flush master's mc_list from slave */ - netif_tx_lock_bh(bond_dev); + netif_addr_lock_bh(bond_dev); bond_mc_list_flush(bond_dev, slave_dev); - netif_tx_unlock_bh(bond_dev); + netif_addr_unlock_bh(bond_dev); } netdev_set_master(slave_dev, NULL); @@ -1833,7 +1946,7 @@ int bond_release(struct net_device *bond_dev, struct net_device *slave_dev) /* close slave before restoring its mac address */ dev_close(slave_dev); - if (!bond->params.fail_over_mac) { + if (bond->params.fail_over_mac != BOND_FOM_ACTIVE) { /* restore original ("permanent") mac address */ memcpy(addr.sa_data, slave->perm_hwaddr, ETH_ALEN); addr.sa_family = slave_dev->type; @@ -1946,9 +2059,9 @@ static int bond_release_all(struct net_device *bond_dev) } /* flush master's mc_list from slave */ - netif_tx_lock_bh(bond_dev); + netif_addr_lock_bh(bond_dev); bond_mc_list_flush(bond_dev, slave_dev); - netif_tx_unlock_bh(bond_dev); + netif_addr_unlock_bh(bond_dev); } netdev_set_master(slave_dev, NULL); @@ -2136,17 +2249,6 @@ static int __bond_mii_monitor(struct bonding *bond, int have_locks) * program could monitor the link itself if needed. */ - if (bond->send_grat_arp) { - if (bond->curr_active_slave && test_bit(__LINK_STATE_LINKWATCH_PENDING, - &bond->curr_active_slave->dev->state)) - dprintk("Needs to send gratuitous arp but not yet\n"); - else { - dprintk("sending delayed gratuitous arp on on %s\n", - bond->curr_active_slave->dev->name); - bond_send_gratuitous_arp(bond); - bond->send_grat_arp = 0; - } - } read_lock(&bond->curr_slave_lock); oldcurrent = bond->curr_active_slave; read_unlock(&bond->curr_slave_lock); @@ -2387,6 +2489,13 @@ void bond_mii_monitor(struct work_struct *work) read_unlock(&bond->lock); return; } + + if (bond->send_grat_arp) { + read_lock(&bond->curr_slave_lock); + bond_send_gratuitous_arp(bond); + read_unlock(&bond->curr_slave_lock); + } + if (__bond_mii_monitor(bond, 0)) { read_unlock(&bond->lock); rtnl_lock(); @@ -2397,7 +2506,7 @@ void bond_mii_monitor(struct work_struct *work) read_lock(&bond->lock); } - delay = ((bond->params.miimon * HZ) / 1000) ? : 1; + delay = msecs_to_jiffies(bond->params.miimon); read_unlock(&bond->lock); queue_delayed_work(bond->wq, &bond->mii_work, delay); } @@ -2426,37 +2535,14 @@ out: return addr; } -static int bond_has_ip(struct bonding *bond) -{ - struct vlan_entry *vlan, *vlan_next; - - if (bond->master_ip) - return 1; - - if (list_empty(&bond->vlan_list)) - return 0; - - list_for_each_entry_safe(vlan, vlan_next, &bond->vlan_list, - vlan_list) { - if (vlan->vlan_ip) - return 1; - } - - return 0; -} - static int bond_has_this_ip(struct bonding *bond, __be32 ip) { - struct vlan_entry *vlan, *vlan_next; + struct vlan_entry *vlan; if (ip == bond->master_ip) return 1; - if (list_empty(&bond->vlan_list)) - return 0; - - list_for_each_entry_safe(vlan, vlan_next, &bond->vlan_list, - vlan_list) { + list_for_each_entry(vlan, &bond->vlan_list, vlan_list) { if (ip == vlan->vlan_ip) return 1; } @@ -2498,7 +2584,7 @@ static void bond_arp_send_all(struct bonding *bond, struct slave *slave) { int i, vlan_id, rv; __be32 *targets = bond->params.arp_targets; - struct vlan_entry *vlan, *vlan_next; + struct vlan_entry *vlan; struct net_device *vlan_dev; struct flowi fl; struct rtable *rt; @@ -2545,8 +2631,7 @@ static void bond_arp_send_all(struct bonding *bond, struct slave *slave) } vlan_id = 0; - list_for_each_entry_safe(vlan, vlan_next, &bond->vlan_list, - vlan_list) { + list_for_each_entry(vlan, &bond->vlan_list, vlan_list) { vlan_dev = vlan_group_get_device(bond->vlgrp, vlan->vlan_id); if (vlan_dev == rt->u.dst.dev) { vlan_id = vlan->vlan_id; @@ -2576,6 +2661,8 @@ static void bond_arp_send_all(struct bonding *bond, struct slave *slave) /* * Kick out a gratuitous ARP for an IP on the bonding master plus one * for each VLAN above us. + * + * Caller must hold curr_slave_lock for read or better */ static void bond_send_gratuitous_arp(struct bonding *bond) { @@ -2585,9 +2672,13 @@ static void bond_send_gratuitous_arp(struct bonding *bond) dprintk("bond_send_grat_arp: bond %s slave %s\n", bond->dev->name, slave ? slave->dev->name : "NULL"); - if (!slave) + + if (!slave || !bond->send_grat_arp || + test_bit(__LINK_STATE_LINKWATCH_PENDING, &slave->dev->state)) return; + bond->send_grat_arp--; + if (bond->master_ip) { bond_arp_send(slave->dev, ARPOP_REPLY, bond->master_ip, bond->master_ip, 0); @@ -2707,7 +2798,7 @@ void bond_loadbalance_arp_mon(struct work_struct *work) read_lock(&bond->lock); - delta_in_ticks = (bond->params.arp_interval * HZ) / 1000; + delta_in_ticks = msecs_to_jiffies(bond->params.arp_interval); if (bond->kill_timers) { goto out; @@ -2764,8 +2855,7 @@ void bond_loadbalance_arp_mon(struct work_struct *work) * if we don't know our ip yet */ if (time_after_eq(jiffies, slave->dev->trans_start + 2*delta_in_ticks) || - (time_after_eq(jiffies, slave->dev->last_rx + 2*delta_in_ticks) && - bond_has_ip(bond))) { + (time_after_eq(jiffies, slave->dev->last_rx + 2*delta_in_ticks))) { slave->link = BOND_LINK_DOWN; slave->state = BOND_STATE_BACKUP; @@ -2813,246 +2903,305 @@ out: } /* - * When using arp monitoring in active-backup mode, this function is - * called to determine if any backup slaves have went down or a new - * current slave needs to be found. - * The backup slaves never generate traffic, they are considered up by merely - * receiving traffic. If the current slave goes down, each backup slave will - * be given the opportunity to tx/rx an arp before being taken down - this - * prevents all slaves from being taken down due to the current slave not - * sending any traffic for the backups to receive. The arps are not necessarily - * necessary, any tx and rx traffic will keep the current slave up. While any - * rx traffic will keep the backup slaves up, the current slave is responsible - * for generating traffic to keep them up regardless of any other traffic they - * may have received. - * see loadbalance_arp_monitor for arp monitoring in load balancing mode + * Called to inspect slaves for active-backup mode ARP monitor link state + * changes. Sets new_link in slaves to specify what action should take + * place for the slave. Returns 0 if no changes are found, >0 if changes + * to link states must be committed. + * + * Called with bond->lock held for read. */ -void bond_activebackup_arp_mon(struct work_struct *work) +static int bond_ab_arp_inspect(struct bonding *bond, int delta_in_ticks) { - struct bonding *bond = container_of(work, struct bonding, - arp_work.work); struct slave *slave; - int delta_in_ticks; - int i; + int i, commit = 0; - read_lock(&bond->lock); + bond_for_each_slave(bond, slave, i) { + slave->new_link = BOND_LINK_NOCHANGE; - delta_in_ticks = (bond->params.arp_interval * HZ) / 1000; + if (slave->link != BOND_LINK_UP) { + if (time_before_eq(jiffies, slave_last_rx(bond, slave) + + delta_in_ticks)) { + slave->new_link = BOND_LINK_UP; + commit++; + } - if (bond->kill_timers) { - goto out; - } + continue; + } - if (bond->slave_cnt == 0) { - goto re_arm; + /* + * Give slaves 2*delta after being enslaved or made + * active. This avoids bouncing, as the last receive + * times need a full ARP monitor cycle to be updated. + */ + if (!time_after_eq(jiffies, slave->jiffies + + 2 * delta_in_ticks)) + continue; + + /* + * Backup slave is down if: + * - No current_arp_slave AND + * - more than 3*delta since last receive AND + * - the bond has an IP address + * + * Note: a non-null current_arp_slave indicates + * the curr_active_slave went down and we are + * searching for a new one; under this condition + * we only take the curr_active_slave down - this + * gives each slave a chance to tx/rx traffic + * before being taken out + */ + if (slave->state == BOND_STATE_BACKUP && + !bond->current_arp_slave && + time_after(jiffies, slave_last_rx(bond, slave) + + 3 * delta_in_ticks)) { + slave->new_link = BOND_LINK_DOWN; + commit++; + } + + /* + * Active slave is down if: + * - more than 2*delta since transmitting OR + * - (more than 2*delta since receive AND + * the bond has an IP address) + */ + if ((slave->state == BOND_STATE_ACTIVE) && + (time_after_eq(jiffies, slave->dev->trans_start + + 2 * delta_in_ticks) || + (time_after_eq(jiffies, slave_last_rx(bond, slave) + + 2 * delta_in_ticks)))) { + slave->new_link = BOND_LINK_DOWN; + commit++; + } } - /* determine if any slave has come up or any backup slave has - * gone down - * TODO: what about up/down delay in arp mode? it wasn't here before - * so it can wait + read_lock(&bond->curr_slave_lock); + + /* + * Trigger a commit if the primary option setting has changed. */ - bond_for_each_slave(bond, slave, i) { - if (slave->link != BOND_LINK_UP) { - if (time_before_eq(jiffies, - slave_last_rx(bond, slave) + delta_in_ticks)) { + if (bond->primary_slave && + (bond->primary_slave != bond->curr_active_slave) && + (bond->primary_slave->link == BOND_LINK_UP)) + commit++; - slave->link = BOND_LINK_UP; + read_unlock(&bond->curr_slave_lock); - write_lock_bh(&bond->curr_slave_lock); + return commit; +} - if ((!bond->curr_active_slave) && - time_before_eq(jiffies, slave->dev->trans_start + delta_in_ticks)) { - bond_change_active_slave(bond, slave); - bond->current_arp_slave = NULL; - } else if (bond->curr_active_slave != slave) { - /* this slave has just come up but we - * already have a current slave; this - * can also happen if bond_enslave adds - * a new slave that is up while we are - * searching for a new slave - */ - bond_set_slave_inactive_flags(slave); - bond->current_arp_slave = NULL; - } +/* + * Called to commit link state changes noted by inspection step of + * active-backup mode ARP monitor. + * + * Called with RTNL and bond->lock for read. + */ +static void bond_ab_arp_commit(struct bonding *bond, int delta_in_ticks) +{ + struct slave *slave; + int i; - bond_set_carrier(bond); + bond_for_each_slave(bond, slave, i) { + switch (slave->new_link) { + case BOND_LINK_NOCHANGE: + continue; - if (slave == bond->curr_active_slave) { - printk(KERN_INFO DRV_NAME - ": %s: %s is up and now the " - "active interface\n", - bond->dev->name, - slave->dev->name); - netif_carrier_on(bond->dev); - } else { - printk(KERN_INFO DRV_NAME - ": %s: backup interface %s is " - "now up\n", - bond->dev->name, - slave->dev->name); - } + case BOND_LINK_UP: + write_lock_bh(&bond->curr_slave_lock); - write_unlock_bh(&bond->curr_slave_lock); - } - } else { - read_lock(&bond->curr_slave_lock); + if (!bond->curr_active_slave && + time_before_eq(jiffies, slave->dev->trans_start + + delta_in_ticks)) { + slave->link = BOND_LINK_UP; + bond_change_active_slave(bond, slave); + bond->current_arp_slave = NULL; - if ((slave != bond->curr_active_slave) && - (!bond->current_arp_slave) && - (time_after_eq(jiffies, slave_last_rx(bond, slave) + 3*delta_in_ticks) && - bond_has_ip(bond))) { - /* a backup slave has gone down; three times - * the delta allows the current slave to be - * taken out before the backup slave. - * note: a non-null current_arp_slave indicates - * the curr_active_slave went down and we are - * searching for a new one; under this - * condition we only take the curr_active_slave - * down - this gives each slave a chance to - * tx/rx traffic before being taken out + printk(KERN_INFO DRV_NAME + ": %s: %s is up and now the " + "active interface\n", + bond->dev->name, slave->dev->name); + + } else if (bond->curr_active_slave != slave) { + /* this slave has just come up but we + * already have a current slave; this can + * also happen if bond_enslave adds a new + * slave that is up while we are searching + * for a new slave */ + slave->link = BOND_LINK_UP; + bond_set_slave_inactive_flags(slave); + bond->current_arp_slave = NULL; - read_unlock(&bond->curr_slave_lock); + printk(KERN_INFO DRV_NAME + ": %s: backup interface %s is now up\n", + bond->dev->name, slave->dev->name); + } - slave->link = BOND_LINK_DOWN; + write_unlock_bh(&bond->curr_slave_lock); - if (slave->link_failure_count < UINT_MAX) { - slave->link_failure_count++; - } + break; + + case BOND_LINK_DOWN: + if (slave->link_failure_count < UINT_MAX) + slave->link_failure_count++; + + slave->link = BOND_LINK_DOWN; + + if (slave == bond->curr_active_slave) { + printk(KERN_INFO DRV_NAME + ": %s: link status down for active " + "interface %s, disabling it\n", + bond->dev->name, slave->dev->name); bond_set_slave_inactive_flags(slave); + write_lock_bh(&bond->curr_slave_lock); + + bond_select_active_slave(bond); + if (bond->curr_active_slave) + bond->curr_active_slave->jiffies = + jiffies; + + write_unlock_bh(&bond->curr_slave_lock); + + bond->current_arp_slave = NULL; + + } else if (slave->state == BOND_STATE_BACKUP) { printk(KERN_INFO DRV_NAME ": %s: backup interface %s is now down\n", - bond->dev->name, - slave->dev->name); - } else { - read_unlock(&bond->curr_slave_lock); + bond->dev->name, slave->dev->name); + + bond_set_slave_inactive_flags(slave); } + break; + + default: + printk(KERN_ERR DRV_NAME + ": %s: impossible: new_link %d on slave %s\n", + bond->dev->name, slave->new_link, + slave->dev->name); } } - read_lock(&bond->curr_slave_lock); - slave = bond->curr_active_slave; - read_unlock(&bond->curr_slave_lock); - - if (slave) { - /* if we have sent traffic in the past 2*arp_intervals but - * haven't xmit and rx traffic in that time interval, select - * a different slave. slave->jiffies is only updated when - * a slave first becomes the curr_active_slave - not necessarily - * after every arp; this ensures the slave has a full 2*delta - * before being taken out. if a primary is being used, check - * if it is up and needs to take over as the curr_active_slave - */ - if ((time_after_eq(jiffies, slave->dev->trans_start + 2*delta_in_ticks) || - (time_after_eq(jiffies, slave_last_rx(bond, slave) + 2*delta_in_ticks) && - bond_has_ip(bond))) && - time_after_eq(jiffies, slave->jiffies + 2*delta_in_ticks)) { + /* + * No race with changes to primary via sysfs, as we hold rtnl. + */ + if (bond->primary_slave && + (bond->primary_slave != bond->curr_active_slave) && + (bond->primary_slave->link == BOND_LINK_UP)) { + write_lock_bh(&bond->curr_slave_lock); + bond_change_active_slave(bond, bond->primary_slave); + write_unlock_bh(&bond->curr_slave_lock); + } - slave->link = BOND_LINK_DOWN; + bond_set_carrier(bond); +} - if (slave->link_failure_count < UINT_MAX) { - slave->link_failure_count++; - } +/* + * Send ARP probes for active-backup mode ARP monitor. + * + * Called with bond->lock held for read. + */ +static void bond_ab_arp_probe(struct bonding *bond) +{ + struct slave *slave; + int i; - printk(KERN_INFO DRV_NAME - ": %s: link status down for active interface " - "%s, disabling it\n", - bond->dev->name, - slave->dev->name); + read_lock(&bond->curr_slave_lock); - write_lock_bh(&bond->curr_slave_lock); + if (bond->current_arp_slave && bond->curr_active_slave) + printk("PROBE: c_arp %s && cas %s BAD\n", + bond->current_arp_slave->dev->name, + bond->curr_active_slave->dev->name); - bond_select_active_slave(bond); - slave = bond->curr_active_slave; + if (bond->curr_active_slave) { + bond_arp_send_all(bond, bond->curr_active_slave); + read_unlock(&bond->curr_slave_lock); + return; + } - write_unlock_bh(&bond->curr_slave_lock); + read_unlock(&bond->curr_slave_lock); - bond->current_arp_slave = slave; + /* if we don't have a curr_active_slave, search for the next available + * backup slave from the current_arp_slave and make it the candidate + * for becoming the curr_active_slave + */ - if (slave) { - slave->jiffies = jiffies; - } - } else if ((bond->primary_slave) && - (bond->primary_slave != slave) && - (bond->primary_slave->link == BOND_LINK_UP)) { - /* at this point, slave is the curr_active_slave */ - printk(KERN_INFO DRV_NAME - ": %s: changing from interface %s to primary " - "interface %s\n", - bond->dev->name, - slave->dev->name, - bond->primary_slave->dev->name); + if (!bond->current_arp_slave) { + bond->current_arp_slave = bond->first_slave; + if (!bond->current_arp_slave) + return; + } - /* primary is up so switch to it */ - write_lock_bh(&bond->curr_slave_lock); - bond_change_active_slave(bond, bond->primary_slave); - write_unlock_bh(&bond->curr_slave_lock); + bond_set_slave_inactive_flags(bond->current_arp_slave); - slave = bond->primary_slave; + /* search for next candidate */ + bond_for_each_slave_from(bond, slave, i, bond->current_arp_slave->next) { + if (IS_UP(slave->dev)) { + slave->link = BOND_LINK_BACK; + bond_set_slave_active_flags(slave); + bond_arp_send_all(bond, slave); slave->jiffies = jiffies; - } else { - bond->current_arp_slave = NULL; + bond->current_arp_slave = slave; + break; } - /* the current slave must tx an arp to ensure backup slaves - * rx traffic + /* if the link state is up at this point, we + * mark it down - this can happen if we have + * simultaneous link failures and + * reselect_active_interface doesn't make this + * one the current slave so it is still marked + * up when it is actually down */ - if (slave && bond_has_ip(bond)) { - bond_arp_send_all(bond, slave); + if (slave->link == BOND_LINK_UP) { + slave->link = BOND_LINK_DOWN; + if (slave->link_failure_count < UINT_MAX) + slave->link_failure_count++; + + bond_set_slave_inactive_flags(slave); + + printk(KERN_INFO DRV_NAME + ": %s: backup interface %s is now down.\n", + bond->dev->name, slave->dev->name); } } +} - /* if we don't have a curr_active_slave, search for the next available - * backup slave from the current_arp_slave and make it the candidate - * for becoming the curr_active_slave - */ - if (!slave) { - if (!bond->current_arp_slave) { - bond->current_arp_slave = bond->first_slave; - } +void bond_activebackup_arp_mon(struct work_struct *work) +{ + struct bonding *bond = container_of(work, struct bonding, + arp_work.work); + int delta_in_ticks; - if (bond->current_arp_slave) { - bond_set_slave_inactive_flags(bond->current_arp_slave); + read_lock(&bond->lock); - /* search for next candidate */ - bond_for_each_slave_from(bond, slave, i, bond->current_arp_slave->next) { - if (IS_UP(slave->dev)) { - slave->link = BOND_LINK_BACK; - bond_set_slave_active_flags(slave); - bond_arp_send_all(bond, slave); - slave->jiffies = jiffies; - bond->current_arp_slave = slave; - break; - } + if (bond->kill_timers) + goto out; - /* if the link state is up at this point, we - * mark it down - this can happen if we have - * simultaneous link failures and - * reselect_active_interface doesn't make this - * one the current slave so it is still marked - * up when it is actually down - */ - if (slave->link == BOND_LINK_UP) { - slave->link = BOND_LINK_DOWN; - if (slave->link_failure_count < UINT_MAX) { - slave->link_failure_count++; - } + delta_in_ticks = msecs_to_jiffies(bond->params.arp_interval); - bond_set_slave_inactive_flags(slave); + if (bond->slave_cnt == 0) + goto re_arm; - printk(KERN_INFO DRV_NAME - ": %s: backup interface %s is " - "now down.\n", - bond->dev->name, - slave->dev->name); - } - } - } + if (bond->send_grat_arp) { + read_lock(&bond->curr_slave_lock); + bond_send_gratuitous_arp(bond); + read_unlock(&bond->curr_slave_lock); } + if (bond_ab_arp_inspect(bond, delta_in_ticks)) { + read_unlock(&bond->lock); + rtnl_lock(); + read_lock(&bond->lock); + + bond_ab_arp_commit(bond, delta_in_ticks); + + read_unlock(&bond->lock); + rtnl_unlock(); + read_lock(&bond->lock); + } + + bond_ab_arp_probe(bond); + re_arm: if (bond->params.arp_interval) { queue_delayed_work(bond->wq, &bond->arp_work, delta_in_ticks); @@ -3128,7 +3277,8 @@ static void bond_info_show_master(struct seq_file *seq) if (bond->params.mode == BOND_MODE_ACTIVEBACKUP && bond->params.fail_over_mac) - seq_printf(seq, " (fail_over_mac)"); + seq_printf(seq, " (fail_over_mac %s)", + fail_over_mac_tbl[bond->params.fail_over_mac].modename); seq_printf(seq, "\n"); @@ -3500,13 +3650,13 @@ static int bond_inetaddr_event(struct notifier_block *this, unsigned long event, { struct in_ifaddr *ifa = ptr; struct net_device *vlan_dev, *event_dev = ifa->ifa_dev->dev; - struct bonding *bond, *bond_next; - struct vlan_entry *vlan, *vlan_next; + struct bonding *bond; + struct vlan_entry *vlan; if (dev_net(ifa->ifa_dev->dev) != &init_net) return NOTIFY_DONE; - list_for_each_entry_safe(bond, bond_next, &bond_dev_list, bond_list) { + list_for_each_entry(bond, &bond_dev_list, bond_list) { if (bond->dev == event_dev) { switch (event) { case NETDEV_UP: @@ -3520,11 +3670,7 @@ static int bond_inetaddr_event(struct notifier_block *this, unsigned long event, } } - if (list_empty(&bond->vlan_list)) - continue; - - list_for_each_entry_safe(vlan, vlan_next, &bond->vlan_list, - vlan_list) { + list_for_each_entry(vlan, &bond->vlan_list, vlan_list) { vlan_dev = vlan_group_get_device(bond->vlgrp, vlan->vlan_id); if (vlan_dev == event_dev) { switch (event) { @@ -3716,6 +3862,7 @@ static int bond_close(struct net_device *bond_dev) write_lock_bh(&bond->lock); + bond->send_grat_arp = 0; /* signal timers not to re-arm */ bond->kill_timers = 1; @@ -3933,6 +4080,10 @@ 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)) { + /* + * FIXME: Need to handle the error when one of the multi-slaves + * encounters error. + */ bond_set_promiscuity(bond, 1); } @@ -3942,6 +4093,10 @@ static void bond_set_multicast_list(struct net_device *bond_dev) /* set allmulti flag to slaves */ 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); } @@ -4060,10 +4215,10 @@ static int bond_set_mac_address(struct net_device *bond_dev, void *addr) dprintk("bond=%p, name=%s\n", bond, (bond_dev ? bond_dev->name : "None")); /* - * If fail_over_mac is enabled, do nothing and return success. - * Returning an error causes ifenslave to fail. + * If fail_over_mac is set to active, do nothing and return + * success. Returning an error causes ifenslave to fail. */ - if (bond->params.fail_over_mac) + if (bond->params.fail_over_mac == BOND_FOM_ACTIVE) return 0; if (!is_valid_ether_addr(sa->sa_data)) { @@ -4518,9 +4673,9 @@ static void bond_free_all(void) struct net_device *bond_dev = bond->dev; bond_work_cancel_all(bond); - netif_tx_lock_bh(bond_dev); + netif_addr_lock_bh(bond_dev); bond_mc_list_destroy(bond); - netif_tx_unlock_bh(bond_dev); + netif_addr_unlock_bh(bond_dev); /* Release the bonded slaves */ bond_release_all(bond_dev); bond_destroy(bond); @@ -4568,7 +4723,7 @@ int bond_parse_parm(const char *buf, struct bond_parm_tbl *tbl) static int bond_check_params(struct bond_params *params) { - int arp_validate_value; + int arp_validate_value, fail_over_mac_value; /* * Convert string parameters. @@ -4618,11 +4773,11 @@ static int bond_check_params(struct bond_params *params) } } - if (max_bonds < 1 || max_bonds > INT_MAX) { + if (max_bonds < 0 || max_bonds > INT_MAX) { printk(KERN_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, 1, INT_MAX, BOND_DEFAULT_MAX_BONDS); + max_bonds, 0, INT_MAX, BOND_DEFAULT_MAX_BONDS); max_bonds = BOND_DEFAULT_MAX_BONDS; } @@ -4658,6 +4813,13 @@ static int bond_check_params(struct bond_params *params) use_carrier = 1; } + if (num_grat_arp < 0 || num_grat_arp > 255) { + printk(KERN_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; + } + /* reset values for 802.3ad */ if (bond_mode == BOND_MODE_8023AD) { if (!miimon) { @@ -4814,7 +4976,7 @@ static int bond_check_params(struct bond_params *params) printk("\n"); - } else { + } else if (max_bonds) { /* miimon and arp_interval not set, we need one so things * work as expected, see bonding.txt for details */ @@ -4836,15 +4998,29 @@ static int bond_check_params(struct bond_params *params) primary = NULL; } - if (fail_over_mac && (bond_mode != BOND_MODE_ACTIVEBACKUP)) - printk(KERN_WARNING DRV_NAME - ": Warning: fail_over_mac only affects " - "active-backup mode.\n"); + if (fail_over_mac) { + 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 + ": 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 + ": Warning: fail_over_mac only affects " + "active-backup mode.\n"); + } else { + fail_over_mac_value = BOND_FOM_NONE; + } /* fill params struct with the proper values */ params->mode = bond_mode; params->xmit_policy = xmit_hashtype; params->miimon = miimon; + params->num_grat_arp = num_grat_arp; params->arp_interval = arp_interval; params->arp_validate = arp_validate_value; params->updelay = updelay; @@ -4852,7 +5028,7 @@ static int bond_check_params(struct bond_params *params) params->use_carrier = use_carrier; params->lacp_fast = lacp_fast; params->primary[0] = 0; - params->fail_over_mac = fail_over_mac; + params->fail_over_mac = fail_over_mac_value; if (primary) { strncpy(params->primary, primary, IFNAMSIZ); @@ -4866,15 +5042,28 @@ static int bond_check_params(struct bond_params *params) static struct lock_class_key bonding_netdev_xmit_lock_key; +static void bond_set_lockdep_class_one(struct net_device *dev, + struct netdev_queue *txq, + void *_unused) +{ + lockdep_set_class(&txq->_xmit_lock, + &bonding_netdev_xmit_lock_key); +} + +static void bond_set_lockdep_class(struct net_device *dev) +{ + netdev_for_each_tx_queue(dev, bond_set_lockdep_class_one, NULL); +} + /* 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 * set up our sysfs entries. */ -int bond_create(char *name, struct bond_params *params, struct bonding **newbond) +int bond_create(char *name, struct bond_params *params) { struct net_device *bond_dev; - struct bonding *bond, *nxt; + struct bonding *bond; int res; rtnl_lock(); @@ -4882,7 +5071,7 @@ int bond_create(char *name, struct bond_params *params, struct bonding **newbond /* Check to see if the bond already exists. */ if (name) { - list_for_each_entry_safe(bond, nxt, &bond_dev_list, bond_list) + 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", @@ -4923,10 +5112,7 @@ int bond_create(char *name, struct bond_params *params, struct bonding **newbond goto out_bond; } - lockdep_set_class(&bond_dev->_xmit_lock, &bonding_netdev_xmit_lock_key); - - if (newbond) - *newbond = bond_dev->priv; + bond_set_lockdep_class(bond_dev); netif_carrier_off(bond_dev); @@ -4957,7 +5143,7 @@ static int __init bonding_init(void) { int i; int res; - struct bonding *bond, *nxt; + struct bonding *bond; printk(KERN_INFO "%s", version); @@ -4973,7 +5159,7 @@ static int __init bonding_init(void) init_rwsem(&bonding_rwsem); for (i = 0; i < max_bonds; i++) { - res = bond_create(NULL, &bonding_defaults, NULL); + res = bond_create(NULL, &bonding_defaults); if (res) goto err; } @@ -4987,7 +5173,7 @@ static int __init bonding_init(void) goto out; err: - list_for_each_entry_safe(bond, nxt, &bond_dev_list, bond_list) { + list_for_each_entry(bond, &bond_dev_list, bond_list) { bond_work_cancel_all(bond); destroy_workqueue(bond->wq); } diff --git a/drivers/net/bonding/bond_sysfs.c b/drivers/net/bonding/bond_sysfs.c index 08f3d396bcd6..6caac0ffb2f2 100644 --- a/drivers/net/bonding/bond_sysfs.c +++ b/drivers/net/bonding/bond_sysfs.c @@ -50,9 +50,9 @@ extern struct bond_parm_tbl bond_mode_tbl[]; extern struct bond_parm_tbl bond_lacp_tbl[]; extern struct bond_parm_tbl xmit_hashtype_tbl[]; extern struct bond_parm_tbl arp_validate_tbl[]; +extern struct bond_parm_tbl fail_over_mac_tbl[]; static int expected_refcount = -1; -static struct class *netdev_class; /*--------------------------- Data Structures -----------------------------*/ /* Bonding sysfs lock. Why can't we just use the subsystem lock? @@ -111,7 +111,6 @@ static ssize_t bonding_store_bonds(struct class *cls, const char *buffer, size_t char *ifname; int rv, res = count; struct bonding *bond; - struct bonding *nxt; sscanf(buffer, "%16s", command); /* IFNAMSIZ*/ ifname = command + 1; @@ -122,7 +121,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, &bond); + rv = bond_create(ifname, &bonding_defaults); if (rv) { printk(KERN_INFO DRV_NAME ": Bond creation failed.\n"); res = rv; @@ -134,7 +133,7 @@ static ssize_t bonding_store_bonds(struct class *cls, const char *buffer, size_t rtnl_lock(); down_write(&bonding_rwsem); - list_for_each_entry_safe(bond, nxt, &bond_dev_list, bond_list) + 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, @@ -548,42 +547,37 @@ static ssize_t bonding_show_fail_over_mac(struct device *d, struct device_attrib { struct bonding *bond = to_bond(d); - return sprintf(buf, "%d\n", bond->params.fail_over_mac) + 1; + return sprintf(buf, "%s %d\n", + fail_over_mac_tbl[bond->params.fail_over_mac].modename, + 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) { int new_value; - int ret = count; struct bonding *bond = to_bond(d); if (bond->slave_cnt != 0) { printk(KERN_ERR DRV_NAME ": %s: Can't alter fail_over_mac with slaves in bond.\n", bond->dev->name); - ret = -EPERM; - goto out; + return -EPERM; } - if (sscanf(buf, "%d", &new_value) != 1) { + new_value = bond_parse_parm(buf, fail_over_mac_tbl); + if (new_value < 0) { printk(KERN_ERR DRV_NAME - ": %s: no fail_over_mac value specified.\n", - bond->dev->name); - ret = -EINVAL; - goto out; + ": %s: Ignoring invalid fail_over_mac value %s.\n", + bond->dev->name, buf); + return -EINVAL; } - if ((new_value == 0) || (new_value == 1)) { - bond->params.fail_over_mac = new_value; - printk(KERN_INFO DRV_NAME ": %s: Setting fail_over_mac to %d.\n", - bond->dev->name, new_value); - } else { - printk(KERN_INFO DRV_NAME - ": %s: Ignoring invalid fail_over_mac value %d.\n", - bond->dev->name, new_value); - } -out: - return ret; + bond->params.fail_over_mac = new_value; + printk(KERN_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); @@ -952,6 +946,45 @@ out: static DEVICE_ATTR(lacp_rate, S_IRUGO | S_IWUSR, bonding_show_lacp, bonding_store_lacp); /* + * Show and set the number of grat ARP to send after a failover event. + */ +static ssize_t bonding_show_n_grat_arp(struct device *d, + struct device_attribute *attr, + char *buf) +{ + struct bonding *bond = to_bond(d); + + return sprintf(buf, "%d\n", bond->params.num_grat_arp); +} + +static ssize_t bonding_store_n_grat_arp(struct device *d, + struct device_attribute *attr, + const char *buf, size_t count) +{ + int new_value, ret = count; + struct bonding *bond = to_bond(d); + + if (sscanf(buf, "%d", &new_value) != 1) { + printk(KERN_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 + ": %s: Invalid num_grat_arp value %d not in range 0-255; rejected.\n", + bond->dev->name, new_value); + ret = -EINVAL; + goto out; + } else { + bond->params.num_grat_arp = new_value; + } +out: + return ret; +} +static DEVICE_ATTR(num_grat_arp, S_IRUGO | S_IWUSR, bonding_show_n_grat_arp, bonding_store_n_grat_arp); +/* * Show and set the MII monitor interval. There are two tricky bits * here. First, if MII monitoring is activated, then we must disable * ARP monitoring. Second, if the timer isn't running, we must @@ -1388,6 +1421,7 @@ static struct attribute *per_bond_attrs[] = { &dev_attr_updelay.attr, &dev_attr_lacp_rate.attr, &dev_attr_xmit_hash_policy.attr, + &dev_attr_num_grat_arp.attr, &dev_attr_miimon.attr, &dev_attr_primary.attr, &dev_attr_use_carrier.attr, @@ -1412,19 +1446,9 @@ static struct attribute_group bonding_group = { */ int bond_create_sysfs(void) { - int ret = 0; - struct bonding *firstbond; - - /* get the netdev class pointer */ - firstbond = container_of(bond_dev_list.next, struct bonding, bond_list); - if (!firstbond) - return -ENODEV; + int ret; - netdev_class = firstbond->dev->dev.class; - if (!netdev_class) - return -ENODEV; - - ret = class_create_file(netdev_class, &class_attr_bonding_masters); + ret = netdev_class_create_file(&class_attr_bonding_masters); /* * Permit multiple loads of the module by ignoring failures to * create the bonding_masters sysfs file. Bonding devices @@ -1443,10 +1467,6 @@ int bond_create_sysfs(void) printk(KERN_ERR "network device named %s already exists in sysfs", class_attr_bonding_masters.attr.name); - else { - netdev_class = NULL; - return 0; - } } return ret; @@ -1458,8 +1478,7 @@ int bond_create_sysfs(void) */ void bond_destroy_sysfs(void) { - if (netdev_class) - class_remove_file(netdev_class, &class_attr_bonding_masters); + netdev_class_remove_file(&class_attr_bonding_masters); } /* diff --git a/drivers/net/bonding/bonding.h b/drivers/net/bonding/bonding.h index a3c74e20aa53..fb730ec0396f 100644 --- a/drivers/net/bonding/bonding.h +++ b/drivers/net/bonding/bonding.h @@ -22,8 +22,8 @@ #include "bond_3ad.h" #include "bond_alb.h" -#define DRV_VERSION "3.2.5" -#define DRV_RELDATE "March 21, 2008" +#define DRV_VERSION "3.3.0" +#define DRV_RELDATE "June 10, 2008" #define DRV_NAME "bonding" #define DRV_DESCRIPTION "Ethernet Channel Bonding Driver" @@ -125,6 +125,7 @@ struct bond_params { int mode; int xmit_policy; int miimon; + int num_grat_arp; int arp_interval; int arp_validate; int use_carrier; @@ -157,6 +158,7 @@ struct slave { unsigned long jiffies; unsigned long last_arp_rx; s8 link; /* one of BOND_LINK_XXXX */ + s8 new_link; s8 state; /* one of BOND_STATE_XXXX */ u32 original_flags; u32 original_mtu; @@ -169,6 +171,11 @@ struct slave { }; /* + * Link pseudo-state only used internally by monitors + */ +#define BOND_LINK_NOCHANGE -1 + +/* * Here are the locking policies for the two bonding locks: * * 1) Get bond->lock when reading/writing slave list. @@ -241,6 +248,10 @@ static inline struct bonding *bond_get_bond_by_slave(struct slave *slave) return (struct bonding *)slave->dev->master->priv; } +#define BOND_FOM_NONE 0 +#define BOND_FOM_ACTIVE 1 +#define BOND_FOM_FOLLOW 2 + #define BOND_ARP_VALIDATE_NONE 0 #define BOND_ARP_VALIDATE_ACTIVE (1 << BOND_STATE_ACTIVE) #define BOND_ARP_VALIDATE_BACKUP (1 << BOND_STATE_BACKUP) @@ -301,7 +312,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, struct bonding **newbond); +int bond_create(char *name, struct bond_params *params); 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); diff --git a/drivers/net/chelsio/cxgb2.c b/drivers/net/chelsio/cxgb2.c index a509337eab2d..638c9a27a7a6 100644 --- a/drivers/net/chelsio/cxgb2.c +++ b/drivers/net/chelsio/cxgb2.c @@ -1153,9 +1153,7 @@ static int __devinit init_one(struct pci_dev *pdev, #ifdef CONFIG_NET_POLL_CONTROLLER netdev->poll_controller = t1_netpoll; #endif -#ifdef CONFIG_CHELSIO_T1_NAPI netif_napi_add(netdev, &adapter->napi, t1_poll, 64); -#endif SET_ETHTOOL_OPS(netdev, &t1_ethtool_ops); } diff --git a/drivers/net/chelsio/sge.c b/drivers/net/chelsio/sge.c index 8a7efd38e95b..d6c7d2aa761b 100644 --- a/drivers/net/chelsio/sge.c +++ b/drivers/net/chelsio/sge.c @@ -1396,20 +1396,10 @@ static void sge_rx(struct sge *sge, struct freelQ *fl, unsigned int len) if (unlikely(adapter->vlan_grp && p->vlan_valid)) { st->vlan_xtract++; -#ifdef CONFIG_CHELSIO_T1_NAPI - vlan_hwaccel_receive_skb(skb, adapter->vlan_grp, - ntohs(p->vlan)); -#else - vlan_hwaccel_rx(skb, adapter->vlan_grp, - ntohs(p->vlan)); -#endif - } else { -#ifdef CONFIG_CHELSIO_T1_NAPI + vlan_hwaccel_receive_skb(skb, adapter->vlan_grp, + ntohs(p->vlan)); + } else netif_receive_skb(skb); -#else - netif_rx(skb); -#endif - } } /* @@ -1568,7 +1558,6 @@ static inline int responses_pending(const struct adapter *adapter) return (e->GenerationBit == Q->genbit); } -#ifdef CONFIG_CHELSIO_T1_NAPI /* * A simpler version of process_responses() that handles only pure (i.e., * non data-carrying) responses. Such respones are too light-weight to justify @@ -1636,9 +1625,6 @@ int t1_poll(struct napi_struct *napi, int budget) return work_done; } -/* - * NAPI version of the main interrupt handler. - */ irqreturn_t t1_interrupt(int irq, void *data) { struct adapter *adapter = data; @@ -1656,7 +1642,8 @@ irqreturn_t t1_interrupt(int irq, void *data) else { /* no data, no NAPI needed */ writel(sge->respQ.cidx, adapter->regs + A_SG_SLEEPING); - napi_enable(&adapter->napi); /* undo schedule_prep */ + /* undo schedule_prep */ + napi_enable(&adapter->napi); } } return IRQ_HANDLED; @@ -1672,53 +1659,6 @@ irqreturn_t t1_interrupt(int irq, void *data) return IRQ_RETVAL(handled != 0); } -#else -/* - * Main interrupt handler, optimized assuming that we took a 'DATA' - * interrupt. - * - * 1. Clear the interrupt - * 2. Loop while we find valid descriptors and process them; accumulate - * information that can be processed after the loop - * 3. Tell the SGE at which index we stopped processing descriptors - * 4. Bookkeeping; free TX buffers, ring doorbell if there are any - * outstanding TX buffers waiting, replenish RX buffers, potentially - * reenable upper layers if they were turned off due to lack of TX - * resources which are available again. - * 5. If we took an interrupt, but no valid respQ descriptors was found we - * let the slow_intr_handler run and do error handling. - */ -irqreturn_t t1_interrupt(int irq, void *cookie) -{ - int work_done; - struct adapter *adapter = cookie; - struct respQ *Q = &adapter->sge->respQ; - - spin_lock(&adapter->async_lock); - - writel(F_PL_INTR_SGE_DATA, adapter->regs + A_PL_CAUSE); - - if (likely(responses_pending(adapter))) - work_done = process_responses(adapter, -1); - else - work_done = t1_slow_intr_handler(adapter); - - /* - * The unconditional clearing of the PL_CAUSE above may have raced - * with DMA completion and the corresponding generation of a response - * to cause us to miss the resulting data interrupt. The next write - * is also unconditional to recover the missed interrupt and render - * this race harmless. - */ - writel(Q->cidx, adapter->regs + A_SG_SLEEPING); - - if (!work_done) - adapter->sge->stats.unhandled_irqs++; - spin_unlock(&adapter->async_lock); - return IRQ_RETVAL(work_done != 0); -} -#endif - /* * Enqueues the sk_buff onto the cmdQ[qid] and has hardware fetch it. * diff --git a/drivers/net/cpmac.c b/drivers/net/cpmac.c index 7f3f62e1b113..fbd4280c102c 100644 --- a/drivers/net/cpmac.c +++ b/drivers/net/cpmac.c @@ -544,7 +544,7 @@ fatal_error: spin_unlock(&priv->rx_lock); netif_rx_complete(priv->dev, napi); - netif_stop_queue(priv->dev); + netif_tx_stop_all_queues(priv->dev); napi_disable(&priv->napi); atomic_inc(&priv->reset_pending); @@ -569,11 +569,7 @@ static int cpmac_start_xmit(struct sk_buff *skb, struct net_device *dev) len = max(skb->len, ETH_ZLEN); queue = skb_get_queue_mapping(skb); -#ifdef CONFIG_NETDEVICES_MULTIQUEUE netif_stop_subqueue(dev, queue); -#else - netif_stop_queue(dev); -#endif desc = &priv->desc_ring[queue]; if (unlikely(desc->dataflags & CPMAC_OWN)) { @@ -626,24 +622,14 @@ static void cpmac_end_xmit(struct net_device *dev, int queue) dev_kfree_skb_irq(desc->skb); desc->skb = NULL; -#ifdef CONFIG_NETDEVICES_MULTIQUEUE if (netif_subqueue_stopped(dev, queue)) netif_wake_subqueue(dev, queue); -#else - if (netif_queue_stopped(dev)) - netif_wake_queue(dev); -#endif } else { if (netif_msg_tx_err(priv) && net_ratelimit()) printk(KERN_WARNING "%s: end_xmit: spurious interrupt\n", dev->name); -#ifdef CONFIG_NETDEVICES_MULTIQUEUE if (netif_subqueue_stopped(dev, queue)) netif_wake_subqueue(dev, queue); -#else - if (netif_queue_stopped(dev)) - netif_wake_queue(dev); -#endif } } @@ -764,9 +750,7 @@ static void cpmac_hw_error(struct work_struct *work) barrier(); atomic_dec(&priv->reset_pending); - for (i = 0; i < CPMAC_QUEUES; i++) - netif_wake_subqueue(priv->dev, i); - netif_wake_queue(priv->dev); + netif_tx_wake_all_queues(priv->dev); cpmac_write(priv->regs, CPMAC_MAC_INT_ENABLE, 3); } @@ -795,7 +779,7 @@ static void cpmac_check_status(struct net_device *dev) dev->name, tx_code, tx_channel, macstatus); } - netif_stop_queue(dev); + netif_tx_stop_all_queues(dev); cpmac_hw_stop(dev); if (schedule_work(&priv->reset_work)) atomic_inc(&priv->reset_pending); @@ -856,9 +840,7 @@ static void cpmac_tx_timeout(struct net_device *dev) barrier(); atomic_dec(&priv->reset_pending); - netif_wake_queue(priv->dev); - for (i = 0; i < CPMAC_QUEUES; i++) - netif_wake_subqueue(dev, i); + netif_tx_wake_all_queues(priv->dev); } static int cpmac_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) @@ -949,7 +931,7 @@ static void cpmac_adjust_link(struct net_device *dev) spin_lock(&priv->lock); if (priv->phy->link) { - netif_start_queue(dev); + netif_tx_start_all_queues(dev); if (priv->phy->duplex != priv->oldduplex) { new_state = 1; priv->oldduplex = priv->phy->duplex; @@ -963,10 +945,10 @@ static void cpmac_adjust_link(struct net_device *dev) if (!priv->oldlink) { new_state = 1; priv->oldlink = 1; - netif_schedule(dev); + netif_tx_schedule_all(dev); } } else if (priv->oldlink) { - netif_stop_queue(dev); + netif_tx_stop_all_queues(dev); new_state = 1; priv->oldlink = 0; priv->oldspeed = 0; @@ -1086,7 +1068,7 @@ static int cpmac_stop(struct net_device *dev) struct cpmac_priv *priv = netdev_priv(dev); struct resource *mem; - netif_stop_queue(dev); + netif_tx_stop_all_queues(dev); cancel_work_sync(&priv->reset_work); napi_disable(&priv->napi); @@ -1179,7 +1161,6 @@ static int __devinit cpmac_probe(struct platform_device *pdev) dev->set_multicast_list = cpmac_set_multicast_list; dev->tx_timeout = cpmac_tx_timeout; dev->ethtool_ops = &cpmac_ethtool_ops; - dev->features |= NETIF_F_MULTI_QUEUE; netif_napi_add(dev, &priv->napi, cpmac_poll, 64); diff --git a/drivers/net/cxgb3/adapter.h b/drivers/net/cxgb3/adapter.h index acebe431d068..271140433b09 100644 --- a/drivers/net/cxgb3/adapter.h +++ b/drivers/net/cxgb3/adapter.h @@ -42,6 +42,7 @@ #include <linux/cache.h> #include <linux/mutex.h> #include <linux/bitops.h> +#include <linux/inet_lro.h> #include "t3cdev.h" #include <asm/io.h> @@ -92,6 +93,7 @@ struct sge_fl { /* SGE per free-buffer list state */ unsigned int gen; /* free list generation */ struct fl_pg_chunk pg_chunk;/* page chunk cache */ unsigned int use_pages; /* whether FL uses pages or sk_buffs */ + unsigned int order; /* order of page allocations */ struct rx_desc *desc; /* address of HW Rx descriptor ring */ struct rx_sw_desc *sdesc; /* address of SW Rx descriptor ring */ dma_addr_t phys_addr; /* physical address of HW ring start */ @@ -116,12 +118,15 @@ struct sge_rspq { /* state for an SGE response queue */ unsigned int polling; /* is the queue serviced through NAPI? */ unsigned int holdoff_tmr; /* interrupt holdoff timer in 100ns */ unsigned int next_holdoff; /* holdoff time for next interrupt */ + unsigned int rx_recycle_buf; /* whether recycling occurred + within current sop-eop */ struct rsp_desc *desc; /* address of HW response ring */ dma_addr_t phys_addr; /* physical address of the ring */ unsigned int cntxt_id; /* SGE context id for the response q */ spinlock_t lock; /* guards response processing */ struct sk_buff *rx_head; /* offload packet receive queue head */ struct sk_buff *rx_tail; /* offload packet receive queue tail */ + struct sk_buff *pg_skb; /* used to build frag list in napi handler */ unsigned long offload_pkts; unsigned long offload_bundles; @@ -169,16 +174,29 @@ enum { /* per port SGE statistics */ SGE_PSTAT_TX_CSUM, /* # of TX checksum offloads */ SGE_PSTAT_VLANEX, /* # of VLAN tag extractions */ SGE_PSTAT_VLANINS, /* # of VLAN tag insertions */ + SGE_PSTAT_LRO_AGGR, /* # of page chunks added to LRO sessions */ + SGE_PSTAT_LRO_FLUSHED, /* # of flushed LRO sessions */ + SGE_PSTAT_LRO_NO_DESC, /* # of overflown LRO sessions */ SGE_PSTAT_MAX /* must be last */ }; +#define T3_MAX_LRO_SES 8 +#define T3_MAX_LRO_MAX_PKTS 64 + struct sge_qset { /* an SGE queue set */ struct adapter *adap; struct napi_struct napi; struct sge_rspq rspq; struct sge_fl fl[SGE_RXQ_PER_SET]; struct sge_txq txq[SGE_TXQ_PER_SET]; + struct net_lro_mgr lro_mgr; + struct net_lro_desc lro_desc[T3_MAX_LRO_SES]; + struct skb_frag_struct *lro_frag_tbl; + int lro_nfrags; + int lro_enabled; + int lro_frag_len; + void *lro_va; struct net_device *netdev; unsigned long txq_stopped; /* which Tx queues are stopped */ struct timer_list tx_reclaim_timer; /* reclaims TX buffers */ diff --git a/drivers/net/cxgb3/common.h b/drivers/net/cxgb3/common.h index 8e8ebd788537..9ecf8a6dc97f 100644 --- a/drivers/net/cxgb3/common.h +++ b/drivers/net/cxgb3/common.h @@ -351,6 +351,7 @@ struct tp_params { struct qset_params { /* SGE queue set parameters */ unsigned int polling; /* polling/interrupt service for rspq */ + unsigned int lro; /* large receive offload */ unsigned int coalesce_usecs; /* irq coalescing timer */ unsigned int rspq_size; /* # of entries in response queue */ unsigned int fl_size; /* # of entries in regular free list */ diff --git a/drivers/net/cxgb3/cxgb3_ctl_defs.h b/drivers/net/cxgb3/cxgb3_ctl_defs.h index ed0ecd9679cb..6ad92405d9a0 100644 --- a/drivers/net/cxgb3/cxgb3_ctl_defs.h +++ b/drivers/net/cxgb3/cxgb3_ctl_defs.h @@ -111,10 +111,7 @@ struct ulp_iscsi_info { unsigned int llimit; unsigned int ulimit; unsigned int tagmask; - unsigned int pgsz3; - unsigned int pgsz2; - unsigned int pgsz1; - unsigned int pgsz0; + u8 pgsz_factor[4]; unsigned int max_rxsz; unsigned int max_txsz; struct pci_dev *pdev; diff --git a/drivers/net/cxgb3/cxgb3_ioctl.h b/drivers/net/cxgb3/cxgb3_ioctl.h index 0a82fcddf2d8..68200a14065e 100644 --- a/drivers/net/cxgb3/cxgb3_ioctl.h +++ b/drivers/net/cxgb3/cxgb3_ioctl.h @@ -90,6 +90,7 @@ struct ch_qset_params { int32_t fl_size[2]; int32_t intr_lat; int32_t polling; + int32_t lro; int32_t cong_thres; }; diff --git a/drivers/net/cxgb3/cxgb3_main.c b/drivers/net/cxgb3/cxgb3_main.c index 3a3127216791..5447f3e60f07 100644 --- a/drivers/net/cxgb3/cxgb3_main.c +++ b/drivers/net/cxgb3/cxgb3_main.c @@ -1212,6 +1212,9 @@ static char stats_strings[][ETH_GSTRING_LEN] = { "VLANinsertions ", "TxCsumOffload ", "RxCsumGood ", + "LroAggregated ", + "LroFlushed ", + "LroNoDesc ", "RxDrops ", "CheckTXEnToggled ", @@ -1340,6 +1343,9 @@ static void get_stats(struct net_device *dev, struct ethtool_stats *stats, *data++ = collect_sge_port_stats(adapter, pi, SGE_PSTAT_VLANINS); *data++ = collect_sge_port_stats(adapter, pi, SGE_PSTAT_TX_CSUM); *data++ = collect_sge_port_stats(adapter, pi, SGE_PSTAT_RX_CSUM_GOOD); + *data++ = collect_sge_port_stats(adapter, pi, SGE_PSTAT_LRO_AGGR); + *data++ = collect_sge_port_stats(adapter, pi, SGE_PSTAT_LRO_FLUSHED); + *data++ = collect_sge_port_stats(adapter, pi, SGE_PSTAT_LRO_NO_DESC); *data++ = s->rx_cong_drops; *data++ = s->num_toggled; @@ -1558,6 +1564,13 @@ static int set_rx_csum(struct net_device *dev, u32 data) struct port_info *p = netdev_priv(dev); p->rx_csum_offload = data; + if (!data) { + struct adapter *adap = p->adapter; + int i; + + for (i = p->first_qset; i < p->first_qset + p->nqsets; i++) + adap->sge.qs[i].lro_enabled = 0; + } return 0; } @@ -1830,6 +1843,11 @@ static int cxgb_extension_ioctl(struct net_device *dev, void __user *useraddr) } } } + if (t.lro >= 0) { + struct sge_qset *qs = &adapter->sge.qs[t.qset_idx]; + q->lro = t.lro; + qs->lro_enabled = t.lro; + } break; } case CHELSIO_GET_QSET_PARAMS:{ @@ -1849,6 +1867,7 @@ static int cxgb_extension_ioctl(struct net_device *dev, void __user *useraddr) t.fl_size[0] = q->fl_size; t.fl_size[1] = q->jumbo_size; t.polling = q->polling; + t.lro = q->lro; t.intr_lat = q->coalesce_usecs; t.cong_thres = q->cong_thres; diff --git a/drivers/net/cxgb3/cxgb3_offload.c b/drivers/net/cxgb3/cxgb3_offload.c index cf2696873796..c5b3de1bb456 100644 --- a/drivers/net/cxgb3/cxgb3_offload.c +++ b/drivers/net/cxgb3/cxgb3_offload.c @@ -207,6 +207,17 @@ static int cxgb_ulp_iscsi_ctl(struct adapter *adapter, unsigned int req, break; case ULP_ISCSI_SET_PARAMS: t3_write_reg(adapter, A_ULPRX_ISCSI_TAGMASK, uiip->tagmask); + /* set MaxRxData and MaxCoalesceSize to 16224 */ + t3_write_reg(adapter, A_TP_PARA_REG2, 0x3f603f60); + /* program the ddp page sizes */ + { + int i; + unsigned int val = 0; + for (i = 0; i < 4; i++) + val |= (uiip->pgsz_factor[i] & 0xF) << (8 * i); + if (val) + t3_write_reg(adapter, A_ULPRX_ISCSI_PSZ, val); + } break; default: ret = -EOPNOTSUPP; @@ -1255,6 +1266,25 @@ static inline void unregister_tdev(struct t3cdev *tdev) mutex_unlock(&cxgb3_db_lock); } +static inline int adap2type(struct adapter *adapter) +{ + int type = 0; + + switch (adapter->params.rev) { + case T3_REV_A: + type = T3A; + break; + case T3_REV_B: + case T3_REV_B2: + type = T3B; + break; + case T3_REV_C: + type = T3C; + break; + } + return type; +} + void __devinit cxgb3_adapter_ofld(struct adapter *adapter) { struct t3cdev *tdev = &adapter->tdev; @@ -1264,7 +1294,7 @@ void __devinit cxgb3_adapter_ofld(struct adapter *adapter) cxgb3_set_dummy_ops(tdev); tdev->send = t3_offload_tx; tdev->ctl = cxgb_offload_ctl; - tdev->type = adapter->params.rev == 0 ? T3A : T3B; + tdev->type = adap2type(adapter); register_tdev(tdev); } diff --git a/drivers/net/cxgb3/l2t.c b/drivers/net/cxgb3/l2t.c index f510140885ae..825e510bd9ed 100644 --- a/drivers/net/cxgb3/l2t.c +++ b/drivers/net/cxgb3/l2t.c @@ -337,7 +337,7 @@ struct l2t_entry *t3_l2t_get(struct t3cdev *cdev, struct neighbour *neigh, atomic_set(&e->refcnt, 1); neigh_replace(e, neigh); if (neigh->dev->priv_flags & IFF_802_1Q_VLAN) - e->vlan = vlan_dev_info(neigh->dev)->vlan_id; + e->vlan = vlan_dev_vlan_id(neigh->dev); else e->vlan = VLAN_NONE; spin_unlock(&e->lock); diff --git a/drivers/net/cxgb3/regs.h b/drivers/net/cxgb3/regs.h index 567178879345..4bda27c551c9 100644 --- a/drivers/net/cxgb3/regs.h +++ b/drivers/net/cxgb3/regs.h @@ -1517,16 +1517,18 @@ #define A_ULPRX_ISCSI_TAGMASK 0x514 -#define S_HPZ0 0 -#define M_HPZ0 0xf -#define V_HPZ0(x) ((x) << S_HPZ0) -#define G_HPZ0(x) (((x) >> S_HPZ0) & M_HPZ0) +#define A_ULPRX_ISCSI_PSZ 0x518 #define A_ULPRX_TDDP_LLIMIT 0x51c #define A_ULPRX_TDDP_ULIMIT 0x520 #define A_ULPRX_TDDP_PSZ 0x528 +#define S_HPZ0 0 +#define M_HPZ0 0xf +#define V_HPZ0(x) ((x) << S_HPZ0) +#define G_HPZ0(x) (((x) >> S_HPZ0) & M_HPZ0) + #define A_ULPRX_STAG_LLIMIT 0x52c #define A_ULPRX_STAG_ULIMIT 0x530 diff --git a/drivers/net/cxgb3/sge.c b/drivers/net/cxgb3/sge.c index 796eb305cdc3..a96331c875e6 100644 --- a/drivers/net/cxgb3/sge.c +++ b/drivers/net/cxgb3/sge.c @@ -55,6 +55,9 @@ * directly. */ #define FL0_PG_CHUNK_SIZE 2048 +#define FL0_PG_ORDER 0 +#define FL1_PG_CHUNK_SIZE (PAGE_SIZE > 8192 ? 16384 : 8192) +#define FL1_PG_ORDER (PAGE_SIZE > 8192 ? 0 : 1) #define SGE_RX_DROP_THRES 16 @@ -359,7 +362,7 @@ static void free_rx_bufs(struct pci_dev *pdev, struct sge_fl *q) } if (q->pg_chunk.page) { - __free_page(q->pg_chunk.page); + __free_pages(q->pg_chunk.page, q->order); q->pg_chunk.page = NULL; } } @@ -376,13 +379,16 @@ static void free_rx_bufs(struct pci_dev *pdev, struct sge_fl *q) * Add a buffer of the given length to the supplied HW and SW Rx * descriptors. */ -static inline void add_one_rx_buf(void *va, unsigned int len, - struct rx_desc *d, struct rx_sw_desc *sd, - unsigned int gen, struct pci_dev *pdev) +static inline int add_one_rx_buf(void *va, unsigned int len, + struct rx_desc *d, struct rx_sw_desc *sd, + unsigned int gen, struct pci_dev *pdev) { dma_addr_t mapping; mapping = pci_map_single(pdev, va, len, PCI_DMA_FROMDEVICE); + if (unlikely(pci_dma_mapping_error(mapping))) + return -ENOMEM; + pci_unmap_addr_set(sd, dma_addr, mapping); d->addr_lo = cpu_to_be32(mapping); @@ -390,12 +396,14 @@ static inline void add_one_rx_buf(void *va, unsigned int len, wmb(); d->len_gen = cpu_to_be32(V_FLD_GEN1(gen)); d->gen2 = cpu_to_be32(V_FLD_GEN2(gen)); + return 0; } -static int alloc_pg_chunk(struct sge_fl *q, struct rx_sw_desc *sd, gfp_t gfp) +static int alloc_pg_chunk(struct sge_fl *q, struct rx_sw_desc *sd, gfp_t gfp, + unsigned int order) { if (!q->pg_chunk.page) { - q->pg_chunk.page = alloc_page(gfp); + q->pg_chunk.page = alloc_pages(gfp, order); if (unlikely(!q->pg_chunk.page)) return -ENOMEM; q->pg_chunk.va = page_address(q->pg_chunk.page); @@ -404,7 +412,7 @@ static int alloc_pg_chunk(struct sge_fl *q, struct rx_sw_desc *sd, gfp_t gfp) sd->pg_chunk = q->pg_chunk; q->pg_chunk.offset += q->buf_size; - if (q->pg_chunk.offset == PAGE_SIZE) + if (q->pg_chunk.offset == (PAGE_SIZE << order)) q->pg_chunk.page = NULL; else { q->pg_chunk.va += q->buf_size; @@ -424,15 +432,18 @@ static int alloc_pg_chunk(struct sge_fl *q, struct rx_sw_desc *sd, gfp_t gfp) * allocated with the supplied gfp flags. The caller must assure that * @n does not exceed the queue's capacity. */ -static void refill_fl(struct adapter *adap, struct sge_fl *q, int n, gfp_t gfp) +static int refill_fl(struct adapter *adap, struct sge_fl *q, int n, gfp_t gfp) { void *buf_start; struct rx_sw_desc *sd = &q->sdesc[q->pidx]; struct rx_desc *d = &q->desc[q->pidx]; + unsigned int count = 0; while (n--) { + int err; + if (q->use_pages) { - if (unlikely(alloc_pg_chunk(q, sd, gfp))) { + if (unlikely(alloc_pg_chunk(q, sd, gfp, q->order))) { nomem: q->alloc_failed++; break; } @@ -447,8 +458,16 @@ nomem: q->alloc_failed++; buf_start = skb->data; } - add_one_rx_buf(buf_start, q->buf_size, d, sd, q->gen, - adap->pdev); + err = add_one_rx_buf(buf_start, q->buf_size, d, sd, q->gen, + adap->pdev); + if (unlikely(err)) { + if (!q->use_pages) { + kfree_skb(sd->skb); + sd->skb = NULL; + } + break; + } + d++; sd++; if (++q->pidx == q->size) { @@ -458,14 +477,19 @@ nomem: q->alloc_failed++; d = q->desc; } q->credits++; + count++; } wmb(); - t3_write_reg(adap, A_SG_KDOORBELL, V_EGRCNTX(q->cntxt_id)); + if (likely(count)) + t3_write_reg(adap, A_SG_KDOORBELL, V_EGRCNTX(q->cntxt_id)); + + return count; } static inline void __refill_fl(struct adapter *adap, struct sge_fl *fl) { - refill_fl(adap, fl, min(16U, fl->size - fl->credits), GFP_ATOMIC); + refill_fl(adap, fl, min(16U, fl->size - fl->credits), + GFP_ATOMIC | __GFP_COMP); } /** @@ -560,6 +584,8 @@ static void t3_reset_qset(struct sge_qset *q) memset(q->txq, 0, sizeof(struct sge_txq) * SGE_TXQ_PER_SET); q->txq_stopped = 0; memset(&q->tx_reclaim_timer, 0, sizeof(q->tx_reclaim_timer)); + kfree(q->lro_frag_tbl); + q->lro_nfrags = q->lro_frag_len = 0; } @@ -740,19 +766,22 @@ use_orig_buf: * that are page chunks rather than sk_buffs. */ static struct sk_buff *get_packet_pg(struct adapter *adap, struct sge_fl *fl, - unsigned int len, unsigned int drop_thres) + struct sge_rspq *q, unsigned int len, + unsigned int drop_thres) { - struct sk_buff *skb = NULL; + struct sk_buff *newskb, *skb; struct rx_sw_desc *sd = &fl->sdesc[fl->cidx]; - if (len <= SGE_RX_COPY_THRES) { - skb = alloc_skb(len, GFP_ATOMIC); - if (likely(skb != NULL)) { - __skb_put(skb, len); + newskb = skb = q->pg_skb; + + if (!skb && (len <= SGE_RX_COPY_THRES)) { + newskb = alloc_skb(len, GFP_ATOMIC); + if (likely(newskb != NULL)) { + __skb_put(newskb, len); pci_dma_sync_single_for_cpu(adap->pdev, pci_unmap_addr(sd, dma_addr), len, PCI_DMA_FROMDEVICE); - memcpy(skb->data, sd->pg_chunk.va, len); + memcpy(newskb->data, sd->pg_chunk.va, len); pci_dma_sync_single_for_device(adap->pdev, pci_unmap_addr(sd, dma_addr), len, PCI_DMA_FROMDEVICE); @@ -761,14 +790,16 @@ static struct sk_buff *get_packet_pg(struct adapter *adap, struct sge_fl *fl, recycle: fl->credits--; recycle_rx_buf(adap, fl, fl->cidx); - return skb; + q->rx_recycle_buf++; + return newskb; } - if (unlikely(fl->credits <= drop_thres)) + if (unlikely(q->rx_recycle_buf || (!skb && fl->credits <= drop_thres))) goto recycle; - skb = alloc_skb(SGE_RX_PULL_LEN, GFP_ATOMIC); - if (unlikely(!skb)) { + if (!skb) + newskb = alloc_skb(SGE_RX_PULL_LEN, GFP_ATOMIC); + if (unlikely(!newskb)) { if (!drop_thres) return NULL; goto recycle; @@ -776,21 +807,29 @@ recycle: pci_unmap_single(adap->pdev, pci_unmap_addr(sd, dma_addr), fl->buf_size, PCI_DMA_FROMDEVICE); - __skb_put(skb, SGE_RX_PULL_LEN); - memcpy(skb->data, sd->pg_chunk.va, SGE_RX_PULL_LEN); - skb_fill_page_desc(skb, 0, sd->pg_chunk.page, - sd->pg_chunk.offset + SGE_RX_PULL_LEN, - len - SGE_RX_PULL_LEN); - skb->len = len; - skb->data_len = len - SGE_RX_PULL_LEN; - skb->truesize += skb->data_len; + if (!skb) { + __skb_put(newskb, SGE_RX_PULL_LEN); + memcpy(newskb->data, sd->pg_chunk.va, SGE_RX_PULL_LEN); + skb_fill_page_desc(newskb, 0, sd->pg_chunk.page, + sd->pg_chunk.offset + SGE_RX_PULL_LEN, + len - SGE_RX_PULL_LEN); + newskb->len = len; + newskb->data_len = len - SGE_RX_PULL_LEN; + } else { + skb_fill_page_desc(newskb, skb_shinfo(newskb)->nr_frags, + sd->pg_chunk.page, + sd->pg_chunk.offset, len); + newskb->len += len; + newskb->data_len += len; + } + newskb->truesize += newskb->data_len; fl->credits--; /* * We do not refill FLs here, we let the caller do it to overlap a * prefetch. */ - return skb; + return newskb; } /** @@ -1831,9 +1870,10 @@ static void restart_tx(struct sge_qset *qs) * if it was immediate data in a response. */ static void rx_eth(struct adapter *adap, struct sge_rspq *rq, - struct sk_buff *skb, int pad) + struct sk_buff *skb, int pad, int lro) { struct cpl_rx_pkt *p = (struct cpl_rx_pkt *)(skb->data + pad); + struct sge_qset *qs = rspq_to_qset(rq); struct port_info *pi; skb_pull(skb, sizeof(*p) + pad); @@ -1850,18 +1890,202 @@ static void rx_eth(struct adapter *adap, struct sge_rspq *rq, if (unlikely(p->vlan_valid)) { struct vlan_group *grp = pi->vlan_grp; - rspq_to_qset(rq)->port_stats[SGE_PSTAT_VLANEX]++; + qs->port_stats[SGE_PSTAT_VLANEX]++; if (likely(grp)) - __vlan_hwaccel_rx(skb, grp, ntohs(p->vlan), - rq->polling); + if (lro) + lro_vlan_hwaccel_receive_skb(&qs->lro_mgr, skb, + grp, + ntohs(p->vlan), + p); + else + __vlan_hwaccel_rx(skb, grp, ntohs(p->vlan), + rq->polling); else dev_kfree_skb_any(skb); - } else if (rq->polling) - netif_receive_skb(skb); - else + } else if (rq->polling) { + if (lro) + lro_receive_skb(&qs->lro_mgr, skb, p); + else + netif_receive_skb(skb); + } else netif_rx(skb); } +static inline int is_eth_tcp(u32 rss) +{ + return G_HASHTYPE(ntohl(rss)) == RSS_HASH_4_TUPLE; +} + +/** + * lro_frame_ok - check if an ingress packet is eligible for LRO + * @p: the CPL header of the packet + * + * Returns true if a received packet is eligible for LRO. + * The following conditions must be true: + * - packet is TCP/IP Ethernet II (checked elsewhere) + * - not an IP fragment + * - no IP options + * - TCP/IP checksums are correct + * - the packet is for this host + */ +static inline int lro_frame_ok(const struct cpl_rx_pkt *p) +{ + const struct ethhdr *eh = (struct ethhdr *)(p + 1); + const struct iphdr *ih = (struct iphdr *)(eh + 1); + + return (*((u8 *)p + 1) & 0x90) == 0x10 && p->csum == htons(0xffff) && + eh->h_proto == htons(ETH_P_IP) && ih->ihl == (sizeof(*ih) >> 2); +} + +#define TCP_FLAG_MASK (TCP_FLAG_CWR | TCP_FLAG_ECE | TCP_FLAG_URG |\ + TCP_FLAG_ACK | TCP_FLAG_PSH | TCP_FLAG_RST |\ + TCP_FLAG_SYN | TCP_FLAG_FIN) +#define TSTAMP_WORD ((TCPOPT_NOP << 24) | (TCPOPT_NOP << 16) |\ + (TCPOPT_TIMESTAMP << 8) | TCPOLEN_TIMESTAMP) + +/** + * lro_segment_ok - check if a TCP segment is eligible for LRO + * @tcph: the TCP header of the packet + * + * Returns true if a TCP packet is eligible for LRO. This requires that + * the packet have only the ACK flag set and no TCP options besides + * time stamps. + */ +static inline int lro_segment_ok(const struct tcphdr *tcph) +{ + int optlen; + + if (unlikely((tcp_flag_word(tcph) & TCP_FLAG_MASK) != TCP_FLAG_ACK)) + return 0; + + optlen = (tcph->doff << 2) - sizeof(*tcph); + if (optlen) { + const u32 *opt = (const u32 *)(tcph + 1); + + if (optlen != TCPOLEN_TSTAMP_ALIGNED || + *opt != htonl(TSTAMP_WORD) || !opt[2]) + return 0; + } + return 1; +} + +static int t3_get_lro_header(void **eh, void **iph, void **tcph, + u64 *hdr_flags, void *priv) +{ + const struct cpl_rx_pkt *cpl = priv; + + if (!lro_frame_ok(cpl)) + return -1; + + *eh = (struct ethhdr *)(cpl + 1); + *iph = (struct iphdr *)((struct ethhdr *)*eh + 1); + *tcph = (struct tcphdr *)((struct iphdr *)*iph + 1); + + if (!lro_segment_ok(*tcph)) + return -1; + + *hdr_flags = LRO_IPV4 | LRO_TCP; + return 0; +} + +static int t3_get_skb_header(struct sk_buff *skb, + void **iph, void **tcph, u64 *hdr_flags, + void *priv) +{ + void *eh; + + return t3_get_lro_header(&eh, iph, tcph, hdr_flags, priv); +} + +static int t3_get_frag_header(struct skb_frag_struct *frag, void **eh, + void **iph, void **tcph, u64 *hdr_flags, + void *priv) +{ + return t3_get_lro_header(eh, iph, tcph, hdr_flags, priv); +} + +/** + * lro_add_page - add a page chunk to an LRO session + * @adap: the adapter + * @qs: the associated queue set + * @fl: the free list containing the page chunk to add + * @len: packet length + * @complete: Indicates the last fragment of a frame + * + * Add a received packet contained in a page chunk to an existing LRO + * session. + */ +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 cpl_rx_pkt *cpl; + struct skb_frag_struct *rx_frag = qs->lro_frag_tbl; + int nr_frags = qs->lro_nfrags, frag_len = qs->lro_frag_len; + int offset = 0; + + if (!nr_frags) { + offset = 2 + sizeof(struct cpl_rx_pkt); + qs->lro_va = cpl = sd->pg_chunk.va + 2; + } + + fl->credits--; + + len -= offset; + pci_unmap_single(adap->pdev, pci_unmap_addr(sd, dma_addr), + fl->buf_size, PCI_DMA_FROMDEVICE); + + 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_nfrags++; + qs->lro_frag_len = frag_len; + + if (!complete) + return; + + qs->lro_nfrags = qs->lro_frag_len = 0; + cpl = qs->lro_va; + + if (unlikely(cpl->vlan_valid)) { + struct net_device *dev = qs->netdev; + struct port_info *pi = netdev_priv(dev); + struct vlan_group *grp = pi->vlan_grp; + + if (likely(grp != NULL)) { + lro_vlan_hwaccel_receive_frags(&qs->lro_mgr, + qs->lro_frag_tbl, + frag_len, frag_len, + grp, ntohs(cpl->vlan), + cpl, 0); + return; + } + } + lro_receive_frags(&qs->lro_mgr, qs->lro_frag_tbl, + frag_len, frag_len, cpl, 0); +} + +/** + * init_lro_mgr - initialize a LRO manager object + * @lro_mgr: the LRO manager object + */ +static void init_lro_mgr(struct sge_qset *qs, struct net_lro_mgr *lro_mgr) +{ + lro_mgr->dev = qs->netdev; + lro_mgr->features = LRO_F_NAPI; + lro_mgr->ip_summed = CHECKSUM_UNNECESSARY; + lro_mgr->ip_summed_aggr = CHECKSUM_UNNECESSARY; + lro_mgr->max_desc = T3_MAX_LRO_SES; + lro_mgr->lro_arr = qs->lro_desc; + lro_mgr->get_frag_header = t3_get_frag_header; + lro_mgr->get_skb_header = t3_get_skb_header; + lro_mgr->max_aggr = T3_MAX_LRO_MAX_PKTS; + if (lro_mgr->max_aggr > MAX_SKB_FRAGS) + lro_mgr->max_aggr = MAX_SKB_FRAGS; +} + /** * handle_rsp_cntrl_info - handles control information in a response * @qs: the queue set corresponding to the response @@ -1947,6 +2171,12 @@ static inline int is_new_response(const struct rsp_desc *r, return (r->intr_gen & F_RSPD_GEN2) == q->gen; } +static inline void clear_rspq_bufstate(struct sge_rspq * const q) +{ + q->pg_skb = NULL; + q->rx_recycle_buf = 0; +} + #define RSPD_GTS_MASK (F_RSPD_TXQ0_GTS | F_RSPD_TXQ1_GTS) #define RSPD_CTRL_MASK (RSPD_GTS_MASK | \ V_RSPD_TXQ0_CR(M_RSPD_TXQ0_CR) | \ @@ -1984,10 +2214,11 @@ static int process_responses(struct adapter *adap, struct sge_qset *qs, q->next_holdoff = q->holdoff_tmr; while (likely(budget_left && is_new_response(r, q))) { - int eth, ethpad = 2; + int packet_complete, eth, ethpad = 2, lro = qs->lro_enabled; struct sk_buff *skb = NULL; u32 len, flags = ntohl(r->flags); - __be32 rss_hi = *(const __be32 *)r, rss_lo = r->rss_hdr.rss_hash_val; + __be32 rss_hi = *(const __be32 *)r, + rss_lo = r->rss_hdr.rss_hash_val; eth = r->rss_hdr.opcode == CPL_RX_PKT; @@ -2015,6 +2246,9 @@ no_mem: } else if ((len = ntohl(r->len_cq)) != 0) { struct sge_fl *fl; + if (eth) + lro = qs->lro_enabled && is_eth_tcp(rss_hi); + fl = (len & F_RSPD_FLQ) ? &qs->fl[1] : &qs->fl[0]; if (fl->use_pages) { void *addr = fl->sdesc[fl->cidx].pg_chunk.va; @@ -2024,9 +2258,18 @@ no_mem: prefetch(addr + L1_CACHE_BYTES); #endif __refill_fl(adap, fl); + if (lro > 0) { + lro_add_page(adap, qs, fl, + G_RSPD_LEN(len), + flags & F_RSPD_EOP); + goto next_fl; + } - skb = get_packet_pg(adap, fl, G_RSPD_LEN(len), - eth ? SGE_RX_DROP_THRES : 0); + skb = get_packet_pg(adap, fl, q, + G_RSPD_LEN(len), + eth ? + SGE_RX_DROP_THRES : 0); + q->pg_skb = skb; } else skb = get_packet(adap, fl, G_RSPD_LEN(len), eth ? SGE_RX_DROP_THRES : 0); @@ -2036,7 +2279,7 @@ no_mem: q->rx_drops++; } else if (unlikely(r->rss_hdr.opcode == CPL_TRACE_PKT)) __skb_pull(skb, 2); - +next_fl: if (++fl->cidx == fl->size) fl->cidx = 0; } else @@ -2060,9 +2303,13 @@ no_mem: q->credits = 0; } - if (likely(skb != NULL)) { + packet_complete = flags & + (F_RSPD_EOP | F_RSPD_IMM_DATA_VALID | + F_RSPD_ASYNC_NOTIF); + + if (skb != NULL && packet_complete) { if (eth) - rx_eth(adap, q, skb, ethpad); + rx_eth(adap, q, skb, ethpad, lro); else { q->offload_pkts++; /* Preserve the RSS info in csum & priority */ @@ -2072,11 +2319,19 @@ no_mem: offload_skbs, ngathered); } + + if (flags & F_RSPD_EOP) + clear_rspq_bufstate(q); } --budget_left; } deliver_partial_bundle(&adap->tdev, q, offload_skbs, ngathered); + lro_flush_all(&qs->lro_mgr); + qs->port_stats[SGE_PSTAT_LRO_AGGR] = qs->lro_mgr.stats.aggregated; + qs->port_stats[SGE_PSTAT_LRO_FLUSHED] = qs->lro_mgr.stats.flushed; + qs->port_stats[SGE_PSTAT_LRO_NO_DESC] = qs->lro_mgr.stats.no_desc; + if (sleeping) check_ring_db(adap, qs, sleeping); @@ -2618,8 +2873,9 @@ int t3_sge_alloc_qset(struct adapter *adapter, unsigned int id, int nports, int irq_vec_idx, const struct qset_params *p, int ntxq, struct net_device *dev) { - int i, ret = -ENOMEM; + int i, avail, ret = -ENOMEM; struct sge_qset *q = &adapter->sge.qs[id]; + struct net_lro_mgr *lro_mgr = &q->lro_mgr; init_qset_cntxt(q, id); init_timer(&q->tx_reclaim_timer); @@ -2687,11 +2943,23 @@ int t3_sge_alloc_qset(struct adapter *adapter, unsigned int id, int nports, #else q->fl[0].buf_size = SGE_RX_SM_BUF_SIZE + sizeof(struct cpl_rx_data); #endif - q->fl[0].use_pages = FL0_PG_CHUNK_SIZE > 0; +#if FL1_PG_CHUNK_SIZE > 0 + q->fl[1].buf_size = FL1_PG_CHUNK_SIZE; +#else q->fl[1].buf_size = is_offload(adapter) ? (16 * 1024) - SKB_DATA_ALIGN(sizeof(struct skb_shared_info)) : MAX_FRAME_SIZE + 2 + sizeof(struct cpl_rx_pkt); +#endif + q->fl[0].use_pages = FL0_PG_CHUNK_SIZE > 0; + q->fl[1].use_pages = FL1_PG_CHUNK_SIZE > 0; + q->fl[0].order = FL0_PG_ORDER; + q->fl[1].order = FL1_PG_ORDER; + + q->lro_frag_tbl = kcalloc(MAX_FRAME_SIZE / FL1_PG_CHUNK_SIZE + 1, + sizeof(struct skb_frag_struct), + GFP_KERNEL); + q->lro_nfrags = q->lro_frag_len = 0; spin_lock_irq(&adapter->sge.reg_lock); /* FL threshold comparison uses < */ @@ -2742,8 +3010,23 @@ int t3_sge_alloc_qset(struct adapter *adapter, unsigned int id, int nports, q->netdev = dev; t3_update_qset_coalesce(q, p); - refill_fl(adapter, &q->fl[0], q->fl[0].size, GFP_KERNEL); - refill_fl(adapter, &q->fl[1], q->fl[1].size, GFP_KERNEL); + init_lro_mgr(q, lro_mgr); + + avail = refill_fl(adapter, &q->fl[0], q->fl[0].size, + GFP_KERNEL | __GFP_COMP); + if (!avail) { + CH_ALERT(adapter, "free list queue 0 initialization failed\n"); + goto err; + } + if (avail < q->fl[0].size) + CH_WARN(adapter, "free list queue 0 enabled with %d credits\n", + avail); + + avail = refill_fl(adapter, &q->fl[1], q->fl[1].size, + GFP_KERNEL | __GFP_COMP); + if (avail < q->fl[1].size) + CH_WARN(adapter, "free list queue 1 enabled with %d credits\n", + avail); refill_rspq(adapter, &q->rspq, q->rspq.size - 1); t3_write_reg(adapter, A_SG_GTS, V_RSPQ(q->rspq.cntxt_id) | @@ -2752,9 +3035,9 @@ int t3_sge_alloc_qset(struct adapter *adapter, unsigned int id, int nports, mod_timer(&q->tx_reclaim_timer, jiffies + TX_RECLAIM_PERIOD); return 0; - err_unlock: +err_unlock: spin_unlock_irq(&adapter->sge.reg_lock); - err: +err: t3_free_qset(adapter, q); return ret; } @@ -2876,7 +3159,7 @@ void t3_sge_prep(struct adapter *adap, struct sge_params *p) q->coalesce_usecs = 5; q->rspq_size = 1024; q->fl_size = 1024; - q->jumbo_size = 512; + q->jumbo_size = 512; q->txq_size[TXQ_ETH] = 1024; q->txq_size[TXQ_OFLD] = 1024; q->txq_size[TXQ_CTRL] = 256; diff --git a/drivers/net/cxgb3/t3_cpl.h b/drivers/net/cxgb3/t3_cpl.h index b7a1a310dfd4..917970ed24a1 100644 --- a/drivers/net/cxgb3/t3_cpl.h +++ b/drivers/net/cxgb3/t3_cpl.h @@ -174,6 +174,13 @@ enum { /* TCP congestion control algorithms */ CONG_ALG_HIGHSPEED }; +enum { /* RSS hash type */ + RSS_HASH_NONE = 0, + RSS_HASH_2_TUPLE = 1, + RSS_HASH_4_TUPLE = 2, + RSS_HASH_TCPV6 = 3 +}; + union opcode_tid { __be32 opcode_tid; __u8 opcode; @@ -184,6 +191,13 @@ union opcode_tid { #define G_OPCODE(x) (((x) >> S_OPCODE) & 0xFF) #define G_TID(x) ((x) & 0xFFFFFF) +#define S_QNUM 0 +#define G_QNUM(x) (((x) >> S_QNUM) & 0xFFFF) + +#define S_HASHTYPE 22 +#define M_HASHTYPE 0x3 +#define G_HASHTYPE(x) (((x) >> S_HASHTYPE) & M_HASHTYPE) + /* tid is assumed to be 24-bits */ #define MK_OPCODE_TID(opcode, tid) (V_OPCODE(opcode) | (tid)) @@ -768,6 +782,12 @@ struct tx_data_wr { __be32 param; }; +/* tx_data_wr.flags fields */ +#define S_TX_ACK_PAGES 21 +#define M_TX_ACK_PAGES 0x7 +#define V_TX_ACK_PAGES(x) ((x) << S_TX_ACK_PAGES) +#define G_TX_ACK_PAGES(x) (((x) >> S_TX_ACK_PAGES) & M_TX_ACK_PAGES) + /* tx_data_wr.param fields */ #define S_TX_PORT 0 #define M_TX_PORT 0x7 @@ -1441,4 +1461,35 @@ struct cpl_rdma_terminate { #define M_TERM_TID 0xFFFFF #define V_TERM_TID(x) ((x) << S_TERM_TID) #define G_TERM_TID(x) (((x) >> S_TERM_TID) & M_TERM_TID) + +/* ULP_TX opcodes */ +enum { ULP_MEM_READ = 2, ULP_MEM_WRITE = 3, ULP_TXPKT = 4 }; + +#define S_ULPTX_CMD 28 +#define M_ULPTX_CMD 0xF +#define V_ULPTX_CMD(x) ((x) << S_ULPTX_CMD) + +#define S_ULPTX_NFLITS 0 +#define M_ULPTX_NFLITS 0xFF +#define V_ULPTX_NFLITS(x) ((x) << S_ULPTX_NFLITS) + +struct ulp_mem_io { + WR_HDR; + __be32 cmd_lock_addr; + __be32 len; +}; + +/* ulp_mem_io.cmd_lock_addr fields */ +#define S_ULP_MEMIO_ADDR 0 +#define M_ULP_MEMIO_ADDR 0x7FFFFFF +#define V_ULP_MEMIO_ADDR(x) ((x) << S_ULP_MEMIO_ADDR) +#define S_ULP_MEMIO_LOCK 27 +#define V_ULP_MEMIO_LOCK(x) ((x) << S_ULP_MEMIO_LOCK) +#define F_ULP_MEMIO_LOCK V_ULP_MEMIO_LOCK(1U) + +/* ulp_mem_io.len fields */ +#define S_ULP_MEMIO_DATA_LEN 28 +#define M_ULP_MEMIO_DATA_LEN 0xF +#define V_ULP_MEMIO_DATA_LEN(x) ((x) << S_ULP_MEMIO_DATA_LEN) + #endif /* T3_CPL_H */ diff --git a/drivers/net/cxgb3/t3cdev.h b/drivers/net/cxgb3/t3cdev.h index a18c8a140424..0a21cfbd2b21 100644 --- a/drivers/net/cxgb3/t3cdev.h +++ b/drivers/net/cxgb3/t3cdev.h @@ -45,7 +45,8 @@ struct cxgb3_client; enum t3ctype { T3A = 0, - T3B + T3B, + T3C, }; struct t3cdev { @@ -63,6 +64,7 @@ struct t3cdev { void *l3opt; /* optional layer 3 data */ void *l4opt; /* optional layer 4 data */ void *ulp; /* ulp stuff */ + void *ulp_iscsi; /* ulp iscsi */ }; #endif /* _T3CDEV_H_ */ diff --git a/drivers/net/declance.c b/drivers/net/declance.c index 6b1e77cc069e..3e3506411ac0 100644 --- a/drivers/net/declance.c +++ b/drivers/net/declance.c @@ -773,8 +773,6 @@ static irqreturn_t lance_interrupt(int irq, void *dev_id) return IRQ_HANDLED; } -struct net_device *last_dev = 0; - static int lance_open(struct net_device *dev) { volatile u16 *ib = (volatile u16 *)dev->mem_start; @@ -782,8 +780,6 @@ static int lance_open(struct net_device *dev) volatile struct lance_regs *ll = lp->ll; int status = 0; - last_dev = dev; - /* Stop the Lance */ writereg(&ll->rap, LE_CSR0); writereg(&ll->rdp, LE_C0_STOP); diff --git a/drivers/net/dl2k.c b/drivers/net/dl2k.c index e233d04a2132..f8037110a522 100644 --- a/drivers/net/dl2k.c +++ b/drivers/net/dl2k.c @@ -499,7 +499,7 @@ rio_timer (unsigned long data) entry = np->old_rx % RX_RING_SIZE; /* Dropped packets don't need to re-allocate */ if (np->rx_skbuff[entry] == NULL) { - skb = dev_alloc_skb (np->rx_buf_sz); + skb = netdev_alloc_skb (dev, np->rx_buf_sz); if (skb == NULL) { np->rx_ring[entry].fraginfo = 0; printk (KERN_INFO @@ -570,7 +570,7 @@ alloc_list (struct net_device *dev) /* Allocate the rx buffers */ for (i = 0; i < RX_RING_SIZE; i++) { /* Allocated fixed size of skbuff */ - struct sk_buff *skb = dev_alloc_skb (np->rx_buf_sz); + struct sk_buff *skb = netdev_alloc_skb (dev, np->rx_buf_sz); np->rx_skbuff[i] = skb; if (skb == NULL) { printk (KERN_ERR @@ -867,7 +867,7 @@ receive_packet (struct net_device *dev) PCI_DMA_FROMDEVICE); skb_put (skb = np->rx_skbuff[entry], pkt_len); np->rx_skbuff[entry] = NULL; - } else if ((skb = dev_alloc_skb (pkt_len + 2)) != NULL) { + } else if ((skb = netdev_alloc_skb(dev, pkt_len + 2))) { pci_dma_sync_single_for_cpu(np->pdev, desc_to_dma(desc), np->rx_buf_sz, @@ -904,7 +904,7 @@ receive_packet (struct net_device *dev) struct sk_buff *skb; /* Dropped packets don't need to re-allocate */ if (np->rx_skbuff[entry] == NULL) { - skb = dev_alloc_skb (np->rx_buf_sz); + skb = netdev_alloc_skb(dev, np->rx_buf_sz); if (skb == NULL) { np->rx_ring[entry].fraginfo = 0; printk (KERN_INFO @@ -1753,7 +1753,7 @@ rio_close (struct net_device *dev) /* Stop Tx and Rx logics */ writel (TxDisable | RxDisable | StatsDisable, ioaddr + MACCtrl); - synchronize_irq (dev->irq); + free_irq (dev->irq, dev); del_timer_sync (&np->timer); diff --git a/drivers/net/dm9000.c b/drivers/net/dm9000.c index 864295e081b6..952e10d686ec 100644 --- a/drivers/net/dm9000.c +++ b/drivers/net/dm9000.c @@ -44,9 +44,8 @@ #define DM9000_PHY 0x40 /* PHY address 0x01 */ -#define CARDNAME "dm9000" -#define PFX CARDNAME ": " -#define DRV_VERSION "1.30" +#define CARDNAME "dm9000" +#define DRV_VERSION "1.31" #ifdef CONFIG_BLACKFIN #define readsb insb @@ -55,9 +54,6 @@ #define writesb outsb #define writesw outsw #define writesl outsl -#define DEFAULT_TRIGGER IRQF_TRIGGER_HIGH -#else -#define DEFAULT_TRIGGER (0) #endif /* @@ -85,23 +81,36 @@ MODULE_PARM_DESC(watchdog, "transmit timeout in milliseconds"); * these two devices. */ +/* The driver supports the original DM9000E, and now the two newer + * devices, DM9000A and DM9000B. + */ + +enum dm9000_type { + TYPE_DM9000E, /* original DM9000 */ + TYPE_DM9000A, + TYPE_DM9000B +}; + /* Structure/enum declaration ------------------------------- */ typedef struct board_info { - void __iomem *io_addr; /* Register I/O base address */ - void __iomem *io_data; /* Data I/O address */ - u16 irq; /* IRQ */ + void __iomem *io_addr; /* Register I/O base address */ + void __iomem *io_data; /* Data I/O address */ + u16 irq; /* IRQ */ - u16 tx_pkt_cnt; - u16 queue_pkt_len; - u16 queue_start_addr; - u16 dbug_cnt; - u8 io_mode; /* 0:word, 2:byte */ - u8 phy_addr; - unsigned int flags; - unsigned int in_suspend :1; + u16 tx_pkt_cnt; + u16 queue_pkt_len; + u16 queue_start_addr; + u16 dbug_cnt; + u8 io_mode; /* 0:word, 2:byte */ + u8 phy_addr; + u8 imr_all; - int debug_level; + unsigned int flags; + unsigned int in_suspend :1; + int debug_level; + + enum dm9000_type type; void (*inblk)(void __iomem *port, void *data, int length); void (*outblk)(void __iomem *port, void *data, int length); @@ -120,10 +129,10 @@ typedef struct board_info { struct delayed_work phy_poll; struct net_device *ndev; - spinlock_t lock; + spinlock_t lock; struct mii_if_info mii; - u32 msg_enable; + u32 msg_enable; } board_info_t; /* debug code */ @@ -140,26 +149,6 @@ static inline board_info_t *to_dm9000_board(struct net_device *dev) return dev->priv; } -/* function declaration ------------------------------------- */ -static int dm9000_probe(struct platform_device *); -static int dm9000_open(struct net_device *); -static int dm9000_start_xmit(struct sk_buff *, struct net_device *); -static int dm9000_stop(struct net_device *); -static int dm9000_ioctl(struct net_device *dev, struct ifreq *req, int cmd); - -static void dm9000_init_dm9000(struct net_device *); - -static irqreturn_t dm9000_interrupt(int, void *); - -static int dm9000_phy_read(struct net_device *dev, int phyaddr_unsused, int reg); -static void dm9000_phy_write(struct net_device *dev, int phyaddr_unused, int reg, - int value); - -static void dm9000_read_eeprom(board_info_t *, int addr, u8 *to); -static void dm9000_write_eeprom(board_info_t *, int addr, u8 *dp); -static void dm9000_rx(struct net_device *); -static void dm9000_hash_table(struct net_device *); - /* DM9000 network board routine ---------------------------- */ static void @@ -302,52 +291,135 @@ static void dm9000_set_io(struct board_info *db, int byte_width) static void dm9000_schedule_poll(board_info_t *db) { - schedule_delayed_work(&db->phy_poll, HZ * 2); + if (db->type == TYPE_DM9000E) + schedule_delayed_work(&db->phy_poll, HZ * 2); } -/* Our watchdog timed out. Called by the networking layer */ -static void dm9000_timeout(struct net_device *dev) +static int dm9000_ioctl(struct net_device *dev, struct ifreq *req, int cmd) +{ + board_info_t *dm = to_dm9000_board(dev); + + if (!netif_running(dev)) + return -EINVAL; + + return generic_mii_ioctl(&dm->mii, if_mii(req), cmd, NULL); +} + +static unsigned int +dm9000_read_locked(board_info_t *db, int reg) { - board_info_t *db = (board_info_t *) dev->priv; - u8 reg_save; unsigned long flags; + unsigned int ret; - /* Save previous register address */ - reg_save = readb(db->io_addr); - spin_lock_irqsave(&db->lock,flags); + spin_lock_irqsave(&db->lock, flags); + ret = ior(db, reg); + spin_unlock_irqrestore(&db->lock, flags); - netif_stop_queue(dev); - dm9000_reset(db); - dm9000_init_dm9000(dev); - /* We can accept TX packets again */ - dev->trans_start = jiffies; - netif_wake_queue(dev); + return ret; +} - /* Restore previous register address */ - writeb(reg_save, db->io_addr); - spin_unlock_irqrestore(&db->lock,flags); +static int dm9000_wait_eeprom(board_info_t *db) +{ + unsigned int status; + int timeout = 8; /* wait max 8msec */ + + /* The DM9000 data sheets say we should be able to + * poll the ERRE bit in EPCR to wait for the EEPROM + * operation. From testing several chips, this bit + * does not seem to work. + * + * We attempt to use the bit, but fall back to the + * timeout (which is why we do not return an error + * on expiry) to say that the EEPROM operation has + * completed. + */ + + while (1) { + status = dm9000_read_locked(db, DM9000_EPCR); + + if ((status & EPCR_ERRE) == 0) + break; + + msleep(1); + + if (timeout-- < 0) { + dev_dbg(db->dev, "timeout waiting EEPROM\n"); + break; + } + } + + return 0; } -#ifdef CONFIG_NET_POLL_CONTROLLER /* - *Used by netconsole + * Read a word data from EEPROM */ -static void dm9000_poll_controller(struct net_device *dev) +static void +dm9000_read_eeprom(board_info_t *db, int offset, u8 *to) { - disable_irq(dev->irq); - dm9000_interrupt(dev->irq,dev); - enable_irq(dev->irq); + unsigned long flags; + + if (db->flags & DM9000_PLATF_NO_EEPROM) { + to[0] = 0xff; + to[1] = 0xff; + return; + } + + mutex_lock(&db->addr_lock); + + spin_lock_irqsave(&db->lock, flags); + + iow(db, DM9000_EPAR, offset); + iow(db, DM9000_EPCR, EPCR_ERPRR); + + spin_unlock_irqrestore(&db->lock, flags); + + dm9000_wait_eeprom(db); + + /* delay for at-least 150uS */ + msleep(1); + + spin_lock_irqsave(&db->lock, flags); + + iow(db, DM9000_EPCR, 0x0); + + to[0] = ior(db, DM9000_EPDRL); + to[1] = ior(db, DM9000_EPDRH); + + spin_unlock_irqrestore(&db->lock, flags); + + mutex_unlock(&db->addr_lock); } -#endif -static int dm9000_ioctl(struct net_device *dev, struct ifreq *req, int cmd) +/* + * Write a word data to SROM + */ +static void +dm9000_write_eeprom(board_info_t *db, int offset, u8 *data) { - board_info_t *dm = to_dm9000_board(dev); + unsigned long flags; - if (!netif_running(dev)) - return -EINVAL; + if (db->flags & DM9000_PLATF_NO_EEPROM) + return; - return generic_mii_ioctl(&dm->mii, if_mii(req), cmd, NULL); + mutex_lock(&db->addr_lock); + + spin_lock_irqsave(&db->lock, flags); + iow(db, DM9000_EPAR, offset); + iow(db, DM9000_EPDRH, data[1]); + iow(db, DM9000_EPDRL, data[0]); + iow(db, DM9000_EPCR, EPCR_WEP | EPCR_ERPRW); + spin_unlock_irqrestore(&db->lock, flags); + + dm9000_wait_eeprom(db); + + mdelay(1); /* wait at least 150uS to clear */ + + spin_lock_irqsave(&db->lock, flags); + iow(db, DM9000_EPCR, 0); + spin_unlock_irqrestore(&db->lock, flags); + + mutex_unlock(&db->addr_lock); } /* ethtool ops */ @@ -400,7 +472,14 @@ static int dm9000_nway_reset(struct net_device *dev) static u32 dm9000_get_link(struct net_device *dev) { board_info_t *dm = to_dm9000_board(dev); - return mii_link_ok(&dm->mii); + u32 ret; + + if (dm->flags & DM9000_PLATF_EXT_PHY) + ret = mii_link_ok(&dm->mii); + else + ret = dm9000_read_locked(dm, DM9000_NSR) & NSR_LINKST ? 1 : 0; + + return ret; } #define DM_EEPROM_MAGIC (0x444D394B) @@ -472,15 +551,48 @@ static const struct ethtool_ops dm9000_ethtool_ops = { .set_eeprom = dm9000_set_eeprom, }; +static void dm9000_show_carrier(board_info_t *db, + unsigned carrier, unsigned nsr) +{ + struct net_device *ndev = db->ndev; + unsigned ncr = dm9000_read_locked(db, DM9000_NCR); + + if (carrier) + dev_info(db->dev, "%s: link up, %dMbps, %s-duplex, no LPA\n", + ndev->name, (nsr & NSR_SPEED) ? 10 : 100, + (ncr & NCR_FDX) ? "full" : "half"); + else + dev_info(db->dev, "%s: link down\n", ndev->name); +} + static void dm9000_poll_work(struct work_struct *w) { struct delayed_work *dw = container_of(w, struct delayed_work, work); board_info_t *db = container_of(dw, board_info_t, phy_poll); + struct net_device *ndev = db->ndev; + + if (db->flags & DM9000_PLATF_SIMPLE_PHY && + !(db->flags & DM9000_PLATF_EXT_PHY)) { + unsigned nsr = dm9000_read_locked(db, DM9000_NSR); + unsigned old_carrier = netif_carrier_ok(ndev) ? 1 : 0; + unsigned new_carrier; + + new_carrier = (nsr & NSR_LINKST) ? 1 : 0; - mii_check_media(&db->mii, netif_msg_link(db), 0); + if (old_carrier != new_carrier) { + if (netif_msg_link(db)) + dm9000_show_carrier(db, new_carrier, nsr); + + if (!new_carrier) + netif_carrier_off(ndev); + else + netif_carrier_on(ndev); + } + } else + mii_check_media(&db->mii, netif_msg_link(db), 0); - if (netif_running(db->ndev)) + if (netif_running(ndev)) dm9000_schedule_poll(db); } @@ -492,12 +604,6 @@ dm9000_poll_work(struct work_struct *w) static void dm9000_release_board(struct platform_device *pdev, struct board_info *db) { - if (db->data_res == NULL) { - if (db->addr_res != NULL) - release_mem_region((unsigned long)db->io_addr, 4); - return; - } - /* unmap our resources */ iounmap(db->io_addr); @@ -505,288 +611,73 @@ dm9000_release_board(struct platform_device *pdev, struct board_info *db) /* release the resources */ - if (db->data_req != NULL) { - release_resource(db->data_req); - kfree(db->data_req); - } + release_resource(db->data_req); + kfree(db->data_req); - if (db->addr_req != NULL) { - release_resource(db->addr_req); - kfree(db->addr_req); - } + release_resource(db->addr_req); + kfree(db->addr_req); } -#define res_size(_r) (((_r)->end - (_r)->start) + 1) - -/* - * Search DM9000 board, allocate space and register it - */ -static int __devinit -dm9000_probe(struct platform_device *pdev) +static unsigned char dm9000_type_to_char(enum dm9000_type type) { - struct dm9000_plat_data *pdata = pdev->dev.platform_data; - struct board_info *db; /* Point a board information structure */ - struct net_device *ndev; - const unsigned char *mac_src; - unsigned long base; - int ret = 0; - int iosize; - int i; - u32 id_val; - - /* Init network device */ - ndev = alloc_etherdev(sizeof (struct board_info)); - if (!ndev) { - dev_err(&pdev->dev, "could not allocate device.\n"); - return -ENOMEM; - } - - SET_NETDEV_DEV(ndev, &pdev->dev); - - dev_dbg(&pdev->dev, "dm9000_probe()\n"); - - /* setup board info structure */ - db = (struct board_info *) ndev->priv; - memset(db, 0, sizeof (*db)); - - db->dev = &pdev->dev; - db->ndev = ndev; - - spin_lock_init(&db->lock); - mutex_init(&db->addr_lock); - - INIT_DELAYED_WORK(&db->phy_poll, dm9000_poll_work); - - - if (pdev->num_resources < 2) { - ret = -ENODEV; - goto out; - } else if (pdev->num_resources == 2) { - base = pdev->resource[0].start; - - if (!request_mem_region(base, 4, ndev->name)) { - ret = -EBUSY; - goto out; - } - - ndev->base_addr = base; - ndev->irq = pdev->resource[1].start; - db->io_addr = (void __iomem *)base; - db->io_data = (void __iomem *)(base + 4); - - /* ensure at least we have a default set of IO routines */ - dm9000_set_io(db, 2); - - } else { - db->addr_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - db->data_res = platform_get_resource(pdev, IORESOURCE_MEM, 1); - db->irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); - - if (db->addr_res == NULL || db->data_res == NULL || - db->irq_res == NULL) { - dev_err(db->dev, "insufficient resources\n"); - ret = -ENOENT; - goto out; - } - - i = res_size(db->addr_res); - db->addr_req = request_mem_region(db->addr_res->start, i, - pdev->name); - - if (db->addr_req == NULL) { - dev_err(db->dev, "cannot claim address reg area\n"); - ret = -EIO; - goto out; - } - - db->io_addr = ioremap(db->addr_res->start, i); - - if (db->io_addr == NULL) { - dev_err(db->dev, "failed to ioremap address reg\n"); - ret = -EINVAL; - goto out; - } - - iosize = res_size(db->data_res); - db->data_req = request_mem_region(db->data_res->start, iosize, - pdev->name); - - if (db->data_req == NULL) { - dev_err(db->dev, "cannot claim data reg area\n"); - ret = -EIO; - goto out; - } - - db->io_data = ioremap(db->data_res->start, iosize); - - if (db->io_data == NULL) { - dev_err(db->dev,"failed to ioremap data reg\n"); - ret = -EINVAL; - goto out; - } - - /* fill in parameters for net-dev structure */ - - ndev->base_addr = (unsigned long)db->io_addr; - ndev->irq = db->irq_res->start; - - /* ensure at least we have a default set of IO routines */ - dm9000_set_io(db, iosize); + switch (type) { + case TYPE_DM9000E: return 'e'; + case TYPE_DM9000A: return 'a'; + case TYPE_DM9000B: return 'b'; } - /* check to see if anything is being over-ridden */ - if (pdata != NULL) { - /* check to see if the driver wants to over-ride the - * default IO width */ - - if (pdata->flags & DM9000_PLATF_8BITONLY) - dm9000_set_io(db, 1); - - if (pdata->flags & DM9000_PLATF_16BITONLY) - dm9000_set_io(db, 2); - - if (pdata->flags & DM9000_PLATF_32BITONLY) - dm9000_set_io(db, 4); - - /* check to see if there are any IO routine - * over-rides */ - - if (pdata->inblk != NULL) - db->inblk = pdata->inblk; - - if (pdata->outblk != NULL) - db->outblk = pdata->outblk; - - if (pdata->dumpblk != NULL) - db->dumpblk = pdata->dumpblk; - - db->flags = pdata->flags; - } - - dm9000_reset(db); - - /* try two times, DM9000 sometimes gets the first read wrong */ - for (i = 0; i < 8; i++) { - id_val = ior(db, DM9000_VIDL); - id_val |= (u32)ior(db, DM9000_VIDH) << 8; - id_val |= (u32)ior(db, DM9000_PIDL) << 16; - id_val |= (u32)ior(db, DM9000_PIDH) << 24; - - if (id_val == DM9000_ID) - break; - dev_err(db->dev, "read wrong id 0x%08x\n", id_val); - } - - if (id_val != DM9000_ID) { - dev_err(db->dev, "wrong id: 0x%08x\n", id_val); - ret = -ENODEV; - goto out; - } - - /* from this point we assume that we have found a DM9000 */ - - /* 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 - - db->msg_enable = NETIF_MSG_LINK; - db->mii.phy_id_mask = 0x1f; - db->mii.reg_num_mask = 0x1f; - db->mii.force_media = 0; - db->mii.full_duplex = 0; - db->mii.dev = ndev; - db->mii.mdio_read = dm9000_phy_read; - db->mii.mdio_write = dm9000_phy_write; - - mac_src = "eeprom"; - - /* try reading the node address from the attached EEPROM */ - for (i = 0; i < 6; i += 2) - dm9000_read_eeprom(db, i / 2, ndev->dev_addr+i); - - if (!is_valid_ether_addr(ndev->dev_addr)) { - /* try reading from mac */ - - mac_src = "chip"; - for (i = 0; i < 6; i++) - ndev->dev_addr[i] = ior(db, i+DM9000_PAR); - } - - if (!is_valid_ether_addr(ndev->dev_addr)) - dev_warn(db->dev, "%s: Invalid ethernet MAC address. Please " - "set using ifconfig\n", ndev->name); - - platform_set_drvdata(pdev, ndev); - ret = register_netdev(ndev); - - if (ret == 0) { - DECLARE_MAC_BUF(mac); - printk("%s: dm9000 at %p,%p IRQ %d MAC: %s (%s)\n", - ndev->name, db->io_addr, db->io_data, ndev->irq, - print_mac(mac, ndev->dev_addr), mac_src); - } - return 0; - -out: - dev_err(db->dev, "not found (%d).\n", ret); - - dm9000_release_board(pdev, db); - free_netdev(ndev); - - return ret; + return '?'; } /* - * Open the interface. - * The interface is opened whenever "ifconfig" actives it. + * Set DM9000 multicast address */ -static int -dm9000_open(struct net_device *dev) +static void +dm9000_hash_table(struct net_device *dev) { board_info_t *db = (board_info_t *) dev->priv; - unsigned long irqflags = db->irq_res->flags & IRQF_TRIGGER_MASK; + struct dev_mc_list *mcptr = dev->mc_list; + int mc_cnt = dev->mc_count; + int i, oft; + u32 hash_val; + u16 hash_table[4]; + u8 rcr = RCR_DIS_LONG | RCR_DIS_CRC | RCR_RXEN; + unsigned long flags; - if (netif_msg_ifup(db)) - dev_dbg(db->dev, "enabling %s\n", dev->name); + dm9000_dbg(db, 1, "entering %s\n", __func__); - /* If there is no IRQ type specified, default to something that - * may work, and tell the user that this is a problem */ + spin_lock_irqsave(&db->lock, flags); - if (irqflags == IRQF_TRIGGER_NONE) { - dev_warn(db->dev, "WARNING: no IRQ resource flags set.\n"); - irqflags = DEFAULT_TRIGGER; - } - - irqflags |= IRQF_SHARED; + for (i = 0, oft = DM9000_PAR; i < 6; i++, oft++) + iow(db, oft, dev->dev_addr[i]); - if (request_irq(dev->irq, &dm9000_interrupt, irqflags, dev->name, dev)) - return -EAGAIN; + /* Clear Hash Table */ + for (i = 0; i < 4; i++) + hash_table[i] = 0x0; - /* Initialize DM9000 board */ - dm9000_reset(db); - dm9000_init_dm9000(dev); + /* broadcast address */ + hash_table[3] = 0x8000; - /* Init driver variable */ - db->dbug_cnt = 0; + if (dev->flags & IFF_PROMISC) + rcr |= RCR_PRMSC; - mii_check_media(&db->mii, netif_msg_link(db), 1); - netif_start_queue(dev); - - dm9000_schedule_poll(db); + if (dev->flags & IFF_ALLMULTI) + rcr |= RCR_ALL; - return 0; + /* the multicast address in Hash Table : 64 bits */ + for (i = 0; i < mc_cnt; i++, mcptr = mcptr->next) { + hash_val = ether_crc_le(6, mcptr->dmi_addr) & 0x3f; + hash_table[hash_val / 16] |= (u16) 1 << (hash_val % 16); + } + + /* Write the hash table to MAC MD table */ + for (i = 0, oft = DM9000_MAR; i < 4; i++) { + iow(db, oft++, hash_table[i]); + iow(db, oft++, hash_table[i] >> 8); + } + + iow(db, DM9000_RCR, rcr); + spin_unlock_irqrestore(&db->lock, flags); } /* @@ -795,7 +686,8 @@ dm9000_open(struct net_device *dev) static void dm9000_init_dm9000(struct net_device *dev) { - board_info_t *db = (board_info_t *) dev->priv; + board_info_t *db = dev->priv; + unsigned int imr; dm9000_dbg(db, 1, "entering %s\n", __func__); @@ -822,8 +714,14 @@ dm9000_init_dm9000(struct net_device *dev) /* Set address filter table */ dm9000_hash_table(dev); + imr = IMR_PAR | IMR_PTM | IMR_PRM; + if (db->type != TYPE_DM9000E) + imr |= IMR_LNKCHNG; + + db->imr_all = imr; + /* Enable TX/RX interrupt mask */ - iow(db, DM9000_IMR, IMR_PAR | IMR_PTM | IMR_PRM); + iow(db, DM9000_IMR, imr); /* Init Driver variable */ db->tx_pkt_cnt = 0; @@ -831,6 +729,29 @@ dm9000_init_dm9000(struct net_device *dev) dev->trans_start = 0; } +/* Our watchdog timed out. Called by the networking layer */ +static void dm9000_timeout(struct net_device *dev) +{ + board_info_t *db = (board_info_t *) dev->priv; + u8 reg_save; + unsigned long flags; + + /* Save previous register address */ + reg_save = readb(db->io_addr); + spin_lock_irqsave(&db->lock, flags); + + netif_stop_queue(dev); + dm9000_reset(db); + dm9000_init_dm9000(dev); + /* We can accept TX packets again */ + dev->trans_start = jiffies; + netif_wake_queue(dev); + + /* Restore previous register address */ + writeb(reg_save, db->io_addr); + spin_unlock_irqrestore(&db->lock, flags); +} + /* * Hardware start transmission. * Send a packet to media from the upper layer. @@ -839,7 +760,7 @@ static int dm9000_start_xmit(struct sk_buff *skb, struct net_device *dev) { unsigned long flags; - board_info_t *db = (board_info_t *) dev->priv; + board_info_t *db = dev->priv; dm9000_dbg(db, 3, "%s:\n", __func__); @@ -879,50 +800,12 @@ dm9000_start_xmit(struct sk_buff *skb, struct net_device *dev) return 0; } -static void -dm9000_shutdown(struct net_device *dev) -{ - board_info_t *db = (board_info_t *) dev->priv; - - /* RESET device */ - dm9000_phy_write(dev, 0, MII_BMCR, BMCR_RESET); /* PHY RESET */ - iow(db, DM9000_GPR, 0x01); /* Power-Down PHY */ - iow(db, DM9000_IMR, IMR_PAR); /* Disable all interrupt */ - iow(db, DM9000_RCR, 0x00); /* Disable RX */ -} - -/* - * Stop the interface. - * The interface is stopped when it is brought. - */ -static int -dm9000_stop(struct net_device *ndev) -{ - board_info_t *db = (board_info_t *) ndev->priv; - - if (netif_msg_ifdown(db)) - dev_dbg(db->dev, "shutting down %s\n", ndev->name); - - cancel_delayed_work_sync(&db->phy_poll); - - netif_stop_queue(ndev); - netif_carrier_off(ndev); - - /* free interrupt */ - free_irq(ndev->irq, ndev); - - dm9000_shutdown(ndev); - - return 0; -} - /* * DM9000 interrupt handler * receive the packet to upper layer, free the transmitted packet */ -static void -dm9000_tx_done(struct net_device *dev, board_info_t * db) +static void dm9000_tx_done(struct net_device *dev, board_info_t *db) { int tx_status = ior(db, DM9000_NSR); /* Got TX status */ @@ -945,52 +828,6 @@ dm9000_tx_done(struct net_device *dev, board_info_t * db) } } -static irqreturn_t -dm9000_interrupt(int irq, void *dev_id) -{ - struct net_device *dev = dev_id; - board_info_t *db = (board_info_t *) dev->priv; - int int_status; - u8 reg_save; - - dm9000_dbg(db, 3, "entering %s\n", __func__); - - /* A real interrupt coming */ - - spin_lock(&db->lock); - - /* Save previous register address */ - reg_save = readb(db->io_addr); - - /* Disable all interrupts */ - iow(db, DM9000_IMR, IMR_PAR); - - /* Got DM9000 interrupt status */ - int_status = ior(db, DM9000_ISR); /* Got ISR */ - iow(db, DM9000_ISR, int_status); /* Clear ISR status */ - - if (netif_msg_intr(db)) - dev_dbg(db->dev, "interrupt status %02x\n", int_status); - - /* Received the coming packet */ - if (int_status & ISR_PRS) - dm9000_rx(dev); - - /* Trnasmit Interrupt check */ - if (int_status & ISR_PTS) - dm9000_tx_done(dev, db); - - /* Re-enable interrupt mask */ - iow(db, DM9000_IMR, IMR_PAR | IMR_PTM | IMR_PRM); - - /* Restore previous register address */ - writeb(reg_save, db->io_addr); - - spin_unlock(&db->lock); - - return IRQ_HANDLED; -} - struct dm9000_rxhdr { u8 RxPktReady; u8 RxStatus; @@ -1094,173 +931,109 @@ dm9000_rx(struct net_device *dev) } while (rxbyte == DM9000_PKT_RDY); } -static unsigned int -dm9000_read_locked(board_info_t *db, int reg) +static irqreturn_t dm9000_interrupt(int irq, void *dev_id) { - unsigned long flags; - unsigned int ret; + struct net_device *dev = dev_id; + board_info_t *db = dev->priv; + int int_status; + u8 reg_save; - spin_lock_irqsave(&db->lock, flags); - ret = ior(db, reg); - spin_unlock_irqrestore(&db->lock, flags); + dm9000_dbg(db, 3, "entering %s\n", __func__); - return ret; -} + /* A real interrupt coming */ -static int dm9000_wait_eeprom(board_info_t *db) -{ - unsigned int status; - int timeout = 8; /* wait max 8msec */ + spin_lock(&db->lock); - /* The DM9000 data sheets say we should be able to - * poll the ERRE bit in EPCR to wait for the EEPROM - * operation. From testing several chips, this bit - * does not seem to work. - * - * We attempt to use the bit, but fall back to the - * timeout (which is why we do not return an error - * on expiry) to say that the EEPROM operation has - * completed. - */ + /* Save previous register address */ + reg_save = readb(db->io_addr); - while (1) { - status = dm9000_read_locked(db, DM9000_EPCR); + /* Disable all interrupts */ + iow(db, DM9000_IMR, IMR_PAR); - if ((status & EPCR_ERRE) == 0) - break; + /* Got DM9000 interrupt status */ + int_status = ior(db, DM9000_ISR); /* Got ISR */ + iow(db, DM9000_ISR, int_status); /* Clear ISR status */ - if (timeout-- < 0) { - dev_dbg(db->dev, "timeout waiting EEPROM\n"); - break; - } - } + if (netif_msg_intr(db)) + dev_dbg(db->dev, "interrupt status %02x\n", int_status); - return 0; -} + /* Received the coming packet */ + if (int_status & ISR_PRS) + dm9000_rx(dev); -/* - * Read a word data from EEPROM - */ -static void -dm9000_read_eeprom(board_info_t *db, int offset, u8 *to) -{ - unsigned long flags; + /* Trnasmit Interrupt check */ + if (int_status & ISR_PTS) + dm9000_tx_done(dev, db); - if (db->flags & DM9000_PLATF_NO_EEPROM) { - to[0] = 0xff; - to[1] = 0xff; - return; + if (db->type != TYPE_DM9000E) { + if (int_status & ISR_LNKCHNG) { + /* fire a link-change request */ + schedule_delayed_work(&db->phy_poll, 1); + } } - mutex_lock(&db->addr_lock); - - spin_lock_irqsave(&db->lock, flags); - - iow(db, DM9000_EPAR, offset); - iow(db, DM9000_EPCR, EPCR_ERPRR); - - spin_unlock_irqrestore(&db->lock, flags); - - dm9000_wait_eeprom(db); - - /* delay for at-least 150uS */ - msleep(1); - - spin_lock_irqsave(&db->lock, flags); - - iow(db, DM9000_EPCR, 0x0); + /* Re-enable interrupt mask */ + iow(db, DM9000_IMR, db->imr_all); - to[0] = ior(db, DM9000_EPDRL); - to[1] = ior(db, DM9000_EPDRH); + /* Restore previous register address */ + writeb(reg_save, db->io_addr); - spin_unlock_irqrestore(&db->lock, flags); + spin_unlock(&db->lock); - mutex_unlock(&db->addr_lock); + return IRQ_HANDLED; } +#ifdef CONFIG_NET_POLL_CONTROLLER /* - * Write a word data to SROM + *Used by netconsole */ -static void -dm9000_write_eeprom(board_info_t *db, int offset, u8 *data) +static void dm9000_poll_controller(struct net_device *dev) { - unsigned long flags; - - if (db->flags & DM9000_PLATF_NO_EEPROM) - return; - - mutex_lock(&db->addr_lock); - - spin_lock_irqsave(&db->lock, flags); - iow(db, DM9000_EPAR, offset); - iow(db, DM9000_EPDRH, data[1]); - iow(db, DM9000_EPDRL, data[0]); - iow(db, DM9000_EPCR, EPCR_WEP | EPCR_ERPRW); - spin_unlock_irqrestore(&db->lock, flags); - - dm9000_wait_eeprom(db); - - mdelay(1); /* wait at least 150uS to clear */ - - spin_lock_irqsave(&db->lock, flags); - iow(db, DM9000_EPCR, 0); - spin_unlock_irqrestore(&db->lock, flags); - - mutex_unlock(&db->addr_lock); + disable_irq(dev->irq); + dm9000_interrupt(dev->irq, dev); + enable_irq(dev->irq); } +#endif /* - * Set DM9000 multicast address + * Open the interface. + * The interface is opened whenever "ifconfig" actives it. */ -static void -dm9000_hash_table(struct net_device *dev) +static int +dm9000_open(struct net_device *dev) { - board_info_t *db = (board_info_t *) dev->priv; - struct dev_mc_list *mcptr = dev->mc_list; - int mc_cnt = dev->mc_count; - int i, oft; - u32 hash_val; - u16 hash_table[4]; - u8 rcr = RCR_DIS_LONG | RCR_DIS_CRC | RCR_RXEN; - unsigned long flags; - - dm9000_dbg(db, 1, "entering %s\n", __func__); + board_info_t *db = dev->priv; + unsigned long irqflags = db->irq_res->flags & IRQF_TRIGGER_MASK; - spin_lock_irqsave(&db->lock, flags); + if (netif_msg_ifup(db)) + dev_dbg(db->dev, "enabling %s\n", dev->name); - for (i = 0, oft = DM9000_PAR; i < 6; i++, oft++) - iow(db, oft, dev->dev_addr[i]); + /* If there is no IRQ type specified, default to something that + * may work, and tell the user that this is a problem */ - /* Clear Hash Table */ - for (i = 0; i < 4; i++) - hash_table[i] = 0x0; + if (irqflags == IRQF_TRIGGER_NONE) + dev_warn(db->dev, "WARNING: no IRQ resource flags set.\n"); - /* broadcast address */ - hash_table[3] = 0x8000; + irqflags |= IRQF_SHARED; - if (dev->flags & IFF_PROMISC) - rcr |= RCR_PRMSC; + if (request_irq(dev->irq, &dm9000_interrupt, irqflags, dev->name, dev)) + return -EAGAIN; - if (dev->flags & IFF_ALLMULTI) - rcr |= RCR_ALL; + /* Initialize DM9000 board */ + dm9000_reset(db); + dm9000_init_dm9000(dev); - /* the multicast address in Hash Table : 64 bits */ - for (i = 0; i < mc_cnt; i++, mcptr = mcptr->next) { - hash_val = ether_crc_le(6, mcptr->dmi_addr) & 0x3f; - hash_table[hash_val / 16] |= (u16) 1 << (hash_val % 16); - } + /* Init driver variable */ + db->dbug_cnt = 0; - /* Write the hash table to MAC MD table */ - for (i = 0, oft = DM9000_MAR; i < 4; i++) { - iow(db, oft++, hash_table[i]); - iow(db, oft++, hash_table[i] >> 8); - } + mii_check_media(&db->mii, netif_msg_link(db), 1); + netif_start_queue(dev); + + dm9000_schedule_poll(db); - iow(db, DM9000_RCR, rcr); - spin_unlock_irqrestore(&db->lock, flags); + return 0; } - /* * Sleep, either by using msleep() or if we are suspending, then * use mdelay() to sleep. @@ -1323,7 +1096,8 @@ dm9000_phy_read(struct net_device *dev, int phy_reg_unused, int reg) * Write a word to phyxcer */ static void -dm9000_phy_write(struct net_device *dev, int phyaddr_unused, int reg, int value) +dm9000_phy_write(struct net_device *dev, + int phyaddr_unused, int reg, int value) { board_info_t *db = (board_info_t *) dev->priv; unsigned long flags; @@ -1363,6 +1137,273 @@ dm9000_phy_write(struct net_device *dev, int phyaddr_unused, int reg, int value) mutex_unlock(&db->addr_lock); } +static void +dm9000_shutdown(struct net_device *dev) +{ + board_info_t *db = dev->priv; + + /* RESET device */ + dm9000_phy_write(dev, 0, MII_BMCR, BMCR_RESET); /* PHY RESET */ + iow(db, DM9000_GPR, 0x01); /* Power-Down PHY */ + iow(db, DM9000_IMR, IMR_PAR); /* Disable all interrupt */ + iow(db, DM9000_RCR, 0x00); /* Disable RX */ +} + +/* + * Stop the interface. + * The interface is stopped when it is brought. + */ +static int +dm9000_stop(struct net_device *ndev) +{ + board_info_t *db = ndev->priv; + + if (netif_msg_ifdown(db)) + dev_dbg(db->dev, "shutting down %s\n", ndev->name); + + cancel_delayed_work_sync(&db->phy_poll); + + netif_stop_queue(ndev); + netif_carrier_off(ndev); + + /* free interrupt */ + free_irq(ndev->irq, ndev); + + dm9000_shutdown(ndev); + + return 0; +} + +#define res_size(_r) (((_r)->end - (_r)->start) + 1) + +/* + * Search DM9000 board, allocate space and register it + */ +static int __devinit +dm9000_probe(struct platform_device *pdev) +{ + struct dm9000_plat_data *pdata = pdev->dev.platform_data; + struct board_info *db; /* Point a board information structure */ + struct net_device *ndev; + const unsigned char *mac_src; + int ret = 0; + int iosize; + int i; + u32 id_val; + + /* Init network device */ + ndev = alloc_etherdev(sizeof(struct board_info)); + if (!ndev) { + dev_err(&pdev->dev, "could not allocate device.\n"); + return -ENOMEM; + } + + SET_NETDEV_DEV(ndev, &pdev->dev); + + dev_dbg(&pdev->dev, "dm9000_probe()\n"); + + /* setup board info structure */ + db = ndev->priv; + memset(db, 0, sizeof(*db)); + + db->dev = &pdev->dev; + db->ndev = ndev; + + spin_lock_init(&db->lock); + mutex_init(&db->addr_lock); + + INIT_DELAYED_WORK(&db->phy_poll, dm9000_poll_work); + + db->addr_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + db->data_res = platform_get_resource(pdev, IORESOURCE_MEM, 1); + db->irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); + + if (db->addr_res == NULL || db->data_res == NULL || + db->irq_res == NULL) { + dev_err(db->dev, "insufficient resources\n"); + ret = -ENOENT; + goto out; + } + + iosize = res_size(db->addr_res); + db->addr_req = request_mem_region(db->addr_res->start, iosize, + pdev->name); + + if (db->addr_req == NULL) { + dev_err(db->dev, "cannot claim address reg area\n"); + ret = -EIO; + goto out; + } + + db->io_addr = ioremap(db->addr_res->start, iosize); + + if (db->io_addr == NULL) { + dev_err(db->dev, "failed to ioremap address reg\n"); + ret = -EINVAL; + goto out; + } + + iosize = res_size(db->data_res); + db->data_req = request_mem_region(db->data_res->start, iosize, + pdev->name); + + if (db->data_req == NULL) { + dev_err(db->dev, "cannot claim data reg area\n"); + ret = -EIO; + goto out; + } + + db->io_data = ioremap(db->data_res->start, iosize); + + if (db->io_data == NULL) { + dev_err(db->dev, "failed to ioremap data reg\n"); + ret = -EINVAL; + goto out; + } + + /* fill in parameters for net-dev structure */ + ndev->base_addr = (unsigned long)db->io_addr; + ndev->irq = db->irq_res->start; + + /* ensure at least we have a default set of IO routines */ + dm9000_set_io(db, iosize); + + /* check to see if anything is being over-ridden */ + if (pdata != NULL) { + /* check to see if the driver wants to over-ride the + * default IO width */ + + if (pdata->flags & DM9000_PLATF_8BITONLY) + dm9000_set_io(db, 1); + + if (pdata->flags & DM9000_PLATF_16BITONLY) + dm9000_set_io(db, 2); + + if (pdata->flags & DM9000_PLATF_32BITONLY) + dm9000_set_io(db, 4); + + /* check to see if there are any IO routine + * over-rides */ + + if (pdata->inblk != NULL) + db->inblk = pdata->inblk; + + if (pdata->outblk != NULL) + db->outblk = pdata->outblk; + + if (pdata->dumpblk != NULL) + db->dumpblk = pdata->dumpblk; + + db->flags = pdata->flags; + } + +#ifdef CONFIG_DM9000_FORCE_SIMPLE_PHY_POLL + db->flags |= DM9000_PLATF_SIMPLE_PHY; +#endif + + dm9000_reset(db); + + /* try multiple times, DM9000 sometimes gets the read wrong */ + for (i = 0; i < 8; i++) { + id_val = ior(db, DM9000_VIDL); + id_val |= (u32)ior(db, DM9000_VIDH) << 8; + id_val |= (u32)ior(db, DM9000_PIDL) << 16; + id_val |= (u32)ior(db, DM9000_PIDH) << 24; + + if (id_val == DM9000_ID) + break; + dev_err(db->dev, "read wrong id 0x%08x\n", id_val); + } + + if (id_val != DM9000_ID) { + dev_err(db->dev, "wrong id: 0x%08x\n", id_val); + ret = -ENODEV; + goto out; + } + + /* Identify what type of DM9000 we are working on */ + + id_val = ior(db, DM9000_CHIPR); + dev_dbg(db->dev, "dm9000 revision 0x%02x\n", id_val); + + switch (id_val) { + case CHIPR_DM9000A: + db->type = TYPE_DM9000A; + break; + case CHIPR_DM9000B: + db->type = TYPE_DM9000B; + break; + default: + dev_dbg(db->dev, "ID %02x => defaulting to DM9000E\n", id_val); + db->type = TYPE_DM9000E; + } + + /* from this point we assume that we have found a DM9000 */ + + /* 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 + + db->msg_enable = NETIF_MSG_LINK; + db->mii.phy_id_mask = 0x1f; + db->mii.reg_num_mask = 0x1f; + db->mii.force_media = 0; + db->mii.full_duplex = 0; + db->mii.dev = ndev; + db->mii.mdio_read = dm9000_phy_read; + db->mii.mdio_write = dm9000_phy_write; + + mac_src = "eeprom"; + + /* try reading the node address from the attached EEPROM */ + for (i = 0; i < 6; i += 2) + dm9000_read_eeprom(db, i / 2, ndev->dev_addr+i); + + if (!is_valid_ether_addr(ndev->dev_addr)) { + /* try reading from mac */ + + mac_src = "chip"; + for (i = 0; i < 6; i++) + ndev->dev_addr[i] = ior(db, i+DM9000_PAR); + } + + if (!is_valid_ether_addr(ndev->dev_addr)) + dev_warn(db->dev, "%s: Invalid ethernet MAC address. Please " + "set using ifconfig\n", ndev->name); + + platform_set_drvdata(pdev, ndev); + ret = register_netdev(ndev); + + if (ret == 0) { + DECLARE_MAC_BUF(mac); + printk(KERN_INFO "%s: dm9000%c at %p,%p IRQ %d MAC: %s (%s)\n", + ndev->name, dm9000_type_to_char(db->type), + db->io_addr, db->io_data, ndev->irq, + print_mac(mac, ndev->dev_addr), mac_src); + } + return 0; + +out: + dev_err(db->dev, "not found (%d).\n", ret); + + dm9000_release_board(pdev, db); + free_netdev(ndev); + + return ret; +} + static int dm9000_drv_suspend(struct platform_device *dev, pm_message_t state) { @@ -1432,7 +1473,7 @@ dm9000_init(void) { printk(KERN_INFO "%s Ethernet Driver, V%s\n", CARDNAME, DRV_VERSION); - return platform_driver_register(&dm9000_driver); /* search board and register */ + return platform_driver_register(&dm9000_driver); } static void __exit diff --git a/drivers/net/dm9000.h b/drivers/net/dm9000.h index 82cad360bafc..ba25cf541420 100644 --- a/drivers/net/dm9000.h +++ b/drivers/net/dm9000.h @@ -45,6 +45,9 @@ #define DM9000_CHIPR 0x2C #define DM9000_SMCR 0x2F +#define CHIPR_DM9000A 0x19 +#define CHIPR_DM9000B 0x1B + #define DM9000_MRCMDX 0xF0 #define DM9000_MRCMD 0xF2 #define DM9000_MRRL 0xF4 @@ -131,5 +134,13 @@ #define DM9000_PKT_RDY 0x01 /* Packet ready to receive */ #define DM9000_PKT_MAX 1536 /* Received packet max size */ +/* DM9000A / DM9000B definitions */ + +#define IMR_LNKCHNG (1<<5) +#define IMR_UNDERRUN (1<<4) + +#define ISR_LNKCHNG (1<<5) +#define ISR_UNDERRUN (1<<4) + #endif /* _DM9000X_H_ */ diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c index 59579b1d8843..cf12b05cd011 100644 --- a/drivers/net/e1000/e1000_main.c +++ b/drivers/net/e1000/e1000_main.c @@ -47,12 +47,6 @@ static const char e1000_copyright[] = "Copyright (c) 1999-2006 Intel Corporation * Macro expands to... * {PCI_DEVICE(PCI_VENDOR_ID_INTEL, device_id)} */ -#ifdef CONFIG_E1000E_ENABLED - #define PCIE(x) -#else - #define PCIE(x) x, -#endif - static struct pci_device_id e1000_pci_tbl[] = { INTEL_E1000_ETHERNET_DEVICE(0x1000), INTEL_E1000_ETHERNET_DEVICE(0x1001), @@ -79,14 +73,6 @@ static struct pci_device_id e1000_pci_tbl[] = { INTEL_E1000_ETHERNET_DEVICE(0x1026), INTEL_E1000_ETHERNET_DEVICE(0x1027), INTEL_E1000_ETHERNET_DEVICE(0x1028), -PCIE( INTEL_E1000_ETHERNET_DEVICE(0x1049)) -PCIE( INTEL_E1000_ETHERNET_DEVICE(0x104A)) -PCIE( INTEL_E1000_ETHERNET_DEVICE(0x104B)) -PCIE( INTEL_E1000_ETHERNET_DEVICE(0x104C)) -PCIE( INTEL_E1000_ETHERNET_DEVICE(0x104D)) -PCIE( INTEL_E1000_ETHERNET_DEVICE(0x105E)) -PCIE( INTEL_E1000_ETHERNET_DEVICE(0x105F)) -PCIE( INTEL_E1000_ETHERNET_DEVICE(0x1060)) INTEL_E1000_ETHERNET_DEVICE(0x1075), INTEL_E1000_ETHERNET_DEVICE(0x1076), INTEL_E1000_ETHERNET_DEVICE(0x1077), @@ -95,28 +81,9 @@ PCIE( INTEL_E1000_ETHERNET_DEVICE(0x1060)) INTEL_E1000_ETHERNET_DEVICE(0x107A), INTEL_E1000_ETHERNET_DEVICE(0x107B), INTEL_E1000_ETHERNET_DEVICE(0x107C), -PCIE( INTEL_E1000_ETHERNET_DEVICE(0x107D)) -PCIE( INTEL_E1000_ETHERNET_DEVICE(0x107E)) -PCIE( INTEL_E1000_ETHERNET_DEVICE(0x107F)) INTEL_E1000_ETHERNET_DEVICE(0x108A), -PCIE( INTEL_E1000_ETHERNET_DEVICE(0x108B)) -PCIE( INTEL_E1000_ETHERNET_DEVICE(0x108C)) -PCIE( INTEL_E1000_ETHERNET_DEVICE(0x1096)) -PCIE( INTEL_E1000_ETHERNET_DEVICE(0x1098)) INTEL_E1000_ETHERNET_DEVICE(0x1099), -PCIE( INTEL_E1000_ETHERNET_DEVICE(0x109A)) -PCIE( INTEL_E1000_ETHERNET_DEVICE(0x10A4)) -PCIE( INTEL_E1000_ETHERNET_DEVICE(0x10A5)) INTEL_E1000_ETHERNET_DEVICE(0x10B5), -PCIE( INTEL_E1000_ETHERNET_DEVICE(0x10B9)) -PCIE( INTEL_E1000_ETHERNET_DEVICE(0x10BA)) -PCIE( INTEL_E1000_ETHERNET_DEVICE(0x10BB)) -PCIE( INTEL_E1000_ETHERNET_DEVICE(0x10BC)) -PCIE( INTEL_E1000_ETHERNET_DEVICE(0x10C4)) -PCIE( INTEL_E1000_ETHERNET_DEVICE(0x10C5)) -PCIE( INTEL_E1000_ETHERNET_DEVICE(0x10D5)) -PCIE( INTEL_E1000_ETHERNET_DEVICE(0x10D9)) -PCIE( INTEL_E1000_ETHERNET_DEVICE(0x10DA)) /* required last entry */ {0,} }; @@ -1505,6 +1472,8 @@ e1000_open(struct net_device *netdev) e1000_irq_enable(adapter); + netif_start_queue(netdev); + /* fire a link status change interrupt to start the watchdog */ E1000_WRITE_REG(&adapter->hw, ICS, E1000_ICS_LSC); @@ -2510,10 +2479,15 @@ e1000_set_rx_mode(struct net_device *netdev) if (netdev->flags & IFF_PROMISC) { rctl |= (E1000_RCTL_UPE | E1000_RCTL_MPE); - } else if (netdev->flags & IFF_ALLMULTI) { - rctl |= E1000_RCTL_MPE; + rctl &= ~E1000_RCTL_VFE; } else { - rctl &= ~E1000_RCTL_MPE; + if (netdev->flags & IFF_ALLMULTI) { + rctl |= E1000_RCTL_MPE; + } else { + rctl &= ~E1000_RCTL_MPE; + } + if (adapter->hw.mac_type != e1000_ich8lan) + rctl |= E1000_RCTL_VFE; } uc_ptr = NULL; @@ -4310,8 +4284,7 @@ e1000_clean_rx_irq(struct e1000_adapter *adapter, if (unlikely(adapter->vlgrp && (status & E1000_RXD_STAT_VP))) { vlan_hwaccel_receive_skb(skb, adapter->vlgrp, - le16_to_cpu(rx_desc->special) & - E1000_RXD_SPC_VLAN_MASK); + le16_to_cpu(rx_desc->special)); } else { netif_receive_skb(skb); } @@ -4319,8 +4292,7 @@ e1000_clean_rx_irq(struct e1000_adapter *adapter, if (unlikely(adapter->vlgrp && (status & E1000_RXD_STAT_VP))) { vlan_hwaccel_rx(skb, adapter->vlgrp, - le16_to_cpu(rx_desc->special) & - E1000_RXD_SPC_VLAN_MASK); + le16_to_cpu(rx_desc->special)); } else { netif_rx(skb); } @@ -4497,16 +4469,14 @@ copydone: #ifdef CONFIG_E1000_NAPI if (unlikely(adapter->vlgrp && (staterr & E1000_RXD_STAT_VP))) { vlan_hwaccel_receive_skb(skb, adapter->vlgrp, - le16_to_cpu(rx_desc->wb.middle.vlan) & - E1000_RXD_SPC_VLAN_MASK); + le16_to_cpu(rx_desc->wb.middle.vlan)); } else { netif_receive_skb(skb); } #else /* CONFIG_E1000_NAPI */ if (unlikely(adapter->vlgrp && (staterr & E1000_RXD_STAT_VP))) { vlan_hwaccel_rx(skb, adapter->vlgrp, - le16_to_cpu(rx_desc->wb.middle.vlan) & - E1000_RXD_SPC_VLAN_MASK); + le16_to_cpu(rx_desc->wb.middle.vlan)); } else { netif_rx(skb); } @@ -4999,7 +4969,6 @@ e1000_vlan_rx_register(struct net_device *netdev, struct vlan_group *grp) if (adapter->hw.mac_type != e1000_ich8lan) { /* enable VLAN receive filtering */ rctl = E1000_READ_REG(&adapter->hw, RCTL); - rctl |= E1000_RCTL_VFE; rctl &= ~E1000_RCTL_CFIEN; E1000_WRITE_REG(&adapter->hw, RCTL, rctl); e1000_update_mng_vlan(adapter); @@ -5011,10 +4980,6 @@ e1000_vlan_rx_register(struct net_device *netdev, struct vlan_group *grp) E1000_WRITE_REG(&adapter->hw, CTRL, ctrl); if (adapter->hw.mac_type != e1000_ich8lan) { - /* disable VLAN filtering */ - rctl = E1000_READ_REG(&adapter->hw, RCTL); - rctl &= ~E1000_RCTL_VFE; - E1000_WRITE_REG(&adapter->hw, RCTL, rctl); if (adapter->mng_vlan_id != (u16)E1000_MNG_VLAN_NONE) { e1000_vlan_rx_kill_vid(netdev, @@ -5284,7 +5249,6 @@ e1000_netpoll(struct net_device *netdev) disable_irq(adapter->pdev->irq); e1000_intr(adapter->pdev->irq, netdev); - e1000_clean_tx_irq(adapter, adapter->tx_ring); #ifndef CONFIG_E1000_NAPI adapter->clean_rx(adapter, adapter->rx_ring); #endif diff --git a/drivers/net/e1000e/e1000.h b/drivers/net/e1000e/e1000.h index d3bc6f8101fa..4a4f62e002b2 100644 --- a/drivers/net/e1000e/e1000.h +++ b/drivers/net/e1000e/e1000.h @@ -283,6 +283,10 @@ struct e1000_adapter { unsigned long led_status; unsigned int flags; + + /* for ioport free */ + int bars; + int need_ioport; }; struct e1000_info { diff --git a/drivers/net/e1000e/netdev.c b/drivers/net/e1000e/netdev.c index 648a87bbf467..869544b8c05c 100644 --- a/drivers/net/e1000e/netdev.c +++ b/drivers/net/e1000e/netdev.c @@ -98,8 +98,7 @@ static void e1000_receive_skb(struct e1000_adapter *adapter, if (adapter->vlgrp && (status & E1000_RXD_STAT_VP)) vlan_hwaccel_receive_skb(skb, adapter->vlgrp, - le16_to_cpu(vlan) & - E1000_RXD_SPC_VLAN_MASK); + le16_to_cpu(vlan)); else netif_receive_skb(skb); @@ -1793,7 +1792,6 @@ static void e1000_vlan_rx_register(struct net_device *netdev, if (adapter->flags & FLAG_HAS_HW_VLAN_FILTER) { /* enable VLAN receive filtering */ rctl = er32(RCTL); - rctl |= E1000_RCTL_VFE; rctl &= ~E1000_RCTL_CFIEN; ew32(RCTL, rctl); e1000_update_mng_vlan(adapter); @@ -1805,10 +1803,6 @@ static void e1000_vlan_rx_register(struct net_device *netdev, ew32(CTRL, ctrl); if (adapter->flags & FLAG_HAS_HW_VLAN_FILTER) { - /* disable VLAN filtering */ - rctl = er32(RCTL); - rctl &= ~E1000_RCTL_VFE; - ew32(RCTL, rctl); if (adapter->mng_vlan_id != (u16)E1000_MNG_VLAN_NONE) { e1000_vlan_rx_kill_vid(netdev, @@ -2231,11 +2225,16 @@ static void e1000_set_multi(struct net_device *netdev) if (netdev->flags & IFF_PROMISC) { rctl |= (E1000_RCTL_UPE | E1000_RCTL_MPE); - } else if (netdev->flags & IFF_ALLMULTI) { - rctl |= E1000_RCTL_MPE; - rctl &= ~E1000_RCTL_UPE; + rctl &= ~E1000_RCTL_VFE; } else { - rctl &= ~(E1000_RCTL_UPE | E1000_RCTL_MPE); + if (netdev->flags & IFF_ALLMULTI) { + rctl |= E1000_RCTL_MPE; + rctl &= ~E1000_RCTL_UPE; + } else { + rctl &= ~(E1000_RCTL_UPE | E1000_RCTL_MPE); + } + if (adapter->flags & FLAG_HAS_HW_VLAN_FILTER) + rctl |= E1000_RCTL_VFE; } ew32(RCTL, rctl); @@ -2514,7 +2513,7 @@ void e1000e_down(struct e1000_adapter *adapter) ew32(RCTL, rctl & ~E1000_RCTL_EN); /* flush and sleep below */ - netif_stop_queue(netdev); + netif_tx_stop_all_queues(netdev); /* disable transmits in the hardware */ tctl = er32(TCTL); @@ -2664,6 +2663,8 @@ static int e1000_open(struct net_device *netdev) e1000_irq_enable(adapter); + netif_tx_start_all_queues(netdev); + /* fire a link status change interrupt to start the watchdog */ ew32(ICS, E1000_ICS_LSC); @@ -3119,7 +3120,7 @@ static void e1000_watchdog_task(struct work_struct *work) ew32(TCTL, tctl); netif_carrier_on(netdev); - netif_wake_queue(netdev); + netif_tx_wake_all_queues(netdev); if (!test_bit(__E1000_DOWN, &adapter->state)) mod_timer(&adapter->phy_info_timer, @@ -3131,7 +3132,7 @@ static void e1000_watchdog_task(struct work_struct *work) adapter->link_duplex = 0; ndev_info(netdev, "Link is Down\n"); netif_carrier_off(netdev); - netif_stop_queue(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)); @@ -4003,7 +4004,11 @@ static int e1000_resume(struct pci_dev *pdev) pci_set_power_state(pdev, PCI_D0); pci_restore_state(pdev); e1000e_disable_l1aspm(pdev); - err = pci_enable_device(pdev); + + if (adapter->need_ioport) + err = pci_enable_device(pdev); + else + err = pci_enable_device_mem(pdev); if (err) { dev_err(&pdev->dev, "Cannot enable PCI device from suspend\n"); @@ -4104,9 +4109,14 @@ static pci_ers_result_t e1000_io_slot_reset(struct pci_dev *pdev) struct net_device *netdev = pci_get_drvdata(pdev); struct e1000_adapter *adapter = netdev_priv(netdev); struct e1000_hw *hw = &adapter->hw; + int err; e1000e_disable_l1aspm(pdev); - if (pci_enable_device(pdev)) { + if (adapter->need_ioport) + err = pci_enable_device(pdev); + else + err = pci_enable_device_mem(pdev); + if (err) { dev_err(&pdev->dev, "Cannot re-enable PCI device after reset.\n"); return PCI_ERS_RESULT_DISCONNECT; @@ -4185,6 +4195,21 @@ static void e1000_print_device_info(struct e1000_adapter *adapter) } /** + * e1000e_is_need_ioport - determine if an adapter needs ioport resources or not + * @pdev: PCI device information struct + * + * Returns true if an adapters needs ioport resources + **/ +static int e1000e_is_need_ioport(struct pci_dev *pdev) +{ + switch (pdev->device) { + /* Currently there are no adapters that need ioport resources */ + default: + return false; + } +} + +/** * e1000_probe - Device Initialization Routine * @pdev: PCI device information struct * @ent: entry in e1000_pci_tbl @@ -4209,9 +4234,19 @@ static int __devinit e1000_probe(struct pci_dev *pdev, int i, err, pci_using_dac; u16 eeprom_data = 0; u16 eeprom_apme_mask = E1000_EEPROM_APME; + int bars, need_ioport; e1000e_disable_l1aspm(pdev); - err = pci_enable_device(pdev); + + /* do not allocate ioport bars when not needed */ + need_ioport = e1000e_is_need_ioport(pdev); + if (need_ioport) { + bars = pci_select_bars(pdev, IORESOURCE_MEM | IORESOURCE_IO); + err = pci_enable_device(pdev); + } else { + bars = pci_select_bars(pdev, IORESOURCE_MEM); + err = pci_enable_device_mem(pdev); + } if (err) return err; @@ -4234,7 +4269,7 @@ static int __devinit e1000_probe(struct pci_dev *pdev, } } - err = pci_request_regions(pdev, e1000e_driver_name); + err = pci_request_selected_regions(pdev, bars, e1000e_driver_name); if (err) goto err_pci_reg; @@ -4259,6 +4294,8 @@ static int __devinit e1000_probe(struct pci_dev *pdev, adapter->hw.adapter = adapter; adapter->hw.mac.type = ei->mac; adapter->msg_enable = (1 << NETIF_MSG_DRV | NETIF_MSG_PROBE) - 1; + adapter->bars = bars; + adapter->need_ioport = need_ioport; mmio_start = pci_resource_start(pdev, 0); mmio_len = pci_resource_len(pdev, 0); @@ -4344,6 +4381,11 @@ static int __devinit e1000_probe(struct pci_dev *pdev, netdev->features |= NETIF_F_TSO; netdev->features |= NETIF_F_TSO6; + netdev->vlan_features |= NETIF_F_TSO; + netdev->vlan_features |= NETIF_F_TSO6; + netdev->vlan_features |= NETIF_F_HW_CSUM; + netdev->vlan_features |= NETIF_F_SG; + if (pci_using_dac) netdev->features |= NETIF_F_HIGHDMA; @@ -4464,7 +4506,7 @@ static int __devinit e1000_probe(struct pci_dev *pdev, /* tell the stack to leave us alone until e1000_open() is called */ netif_carrier_off(netdev); - netif_stop_queue(netdev); + netif_tx_stop_all_queues(netdev); strcpy(netdev->name, "eth%d"); err = register_netdev(netdev); @@ -4493,7 +4535,7 @@ err_sw_init: err_ioremap: free_netdev(netdev); err_alloc_etherdev: - pci_release_regions(pdev); + pci_release_selected_regions(pdev, bars); err_pci_reg: err_dma: pci_disable_device(pdev); @@ -4541,7 +4583,7 @@ static void __devexit e1000_remove(struct pci_dev *pdev) iounmap(adapter->hw.hw_addr); if (adapter->hw.flash_address) iounmap(adapter->hw.flash_address); - pci_release_regions(pdev); + pci_release_selected_regions(pdev, adapter->bars); free_netdev(netdev); diff --git a/drivers/net/fealnx.c b/drivers/net/fealnx.c index 7bb9c728a1d3..3c1364de2b66 100644 --- a/drivers/net/fealnx.c +++ b/drivers/net/fealnx.c @@ -90,6 +90,7 @@ static int full_duplex[MAX_UNITS] = { -1, -1, -1, -1, -1, -1, -1, -1 }; #include <asm/processor.h> /* Processor type for cache alignment. */ #include <asm/io.h> #include <asm/uaccess.h> +#include <asm/byteorder.h> /* These identify the driver base version and may not be removed. */ static char version[] = @@ -861,40 +862,20 @@ static int netdev_open(struct net_device *dev) Wait the specified 50 PCI cycles after a reset by initializing Tx and Rx queues and the address filter list. FIXME (Ueimor): optimistic for alpha + posted writes ? */ -#if defined(__powerpc__) || defined(__sparc__) -// 89/9/1 modify, -// np->bcrvalue=0x04 | 0x0x38; /* big-endian, 256 burst length */ - np->bcrvalue = 0x04 | 0x10; /* big-endian, tx 8 burst length */ - np->crvalue = 0xe00; /* rx 128 burst length */ -#elif defined(__alpha__) || defined(__x86_64__) -// 89/9/1 modify, -// np->bcrvalue=0x38; /* little-endian, 256 burst length */ - np->bcrvalue = 0x10; /* little-endian, 8 burst length */ - np->crvalue = 0xe00; /* rx 128 burst length */ -#elif defined(__i386__) -#if defined(MODULE) -// 89/9/1 modify, -// np->bcrvalue=0x38; /* little-endian, 256 burst length */ + np->bcrvalue = 0x10; /* little-endian, 8 burst length */ - np->crvalue = 0xe00; /* rx 128 burst length */ -#else - /* When not a module we can work around broken '486 PCI boards. */ -#define x86 boot_cpu_data.x86 -// 89/9/1 modify, -// np->bcrvalue=(x86 <= 4 ? 0x10 : 0x38); - np->bcrvalue = 0x10; - np->crvalue = (x86 <= 4 ? 0xa00 : 0xe00); - if (x86 <= 4) - printk(KERN_INFO "%s: This is a 386/486 PCI system, setting burst " - "length to %x.\n", dev->name, (x86 <= 4 ? 0x10 : 0x38)); +#ifdef __BIG_ENDIAN + np->bcrvalue |= 0x04; /* big-endian */ #endif -#else -// 89/9/1 modify, -// np->bcrvalue=0x38; - np->bcrvalue = 0x10; - np->crvalue = 0xe00; /* rx 128 burst length */ -#warning Processor architecture undefined! + +#if defined(__i386__) && !defined(MODULE) + if (boot_cpu_data.x86 <= 4) + np->crvalue = 0xa00; + else #endif + np->crvalue = 0xe00; /* rx 128 burst length */ + + // 89/12/29 add, // 90/1/16 modify, // np->imrvalue=FBE|TUNF|CNTOVF|RBU|TI|RI; diff --git a/drivers/net/fec_mpc52xx.c b/drivers/net/fec_mpc52xx.c index 329edd9c08fc..ae9ecb7df22b 100644 --- a/drivers/net/fec_mpc52xx.c +++ b/drivers/net/fec_mpc52xx.c @@ -197,7 +197,7 @@ static void mpc52xx_fec_adjust_link(struct net_device *dev) if (priv->link == PHY_DOWN) { new_state = 1; priv->link = phydev->link; - netif_schedule(dev); + netif_tx_schedule_all(dev); netif_carrier_on(dev); netif_start_queue(dev); } diff --git a/drivers/net/forcedeth.c b/drivers/net/forcedeth.c index 20d4fe96a81c..4ed89fa9ae46 100644 --- a/drivers/net/forcedeth.c +++ b/drivers/net/forcedeth.c @@ -426,6 +426,7 @@ union ring_type { #define NV_PCI_REGSZ_VER1 0x270 #define NV_PCI_REGSZ_VER2 0x2d4 #define NV_PCI_REGSZ_VER3 0x604 +#define NV_PCI_REGSZ_MAX 0x604 /* various timeout delays: all in usec */ #define NV_TXRX_RESET_DELAY 4 @@ -784,6 +785,9 @@ struct fe_priv { /* flow control */ u32 pause_flags; + + /* power saved state */ + u32 saved_config_space[NV_PCI_REGSZ_MAX/4]; }; /* @@ -2827,6 +2831,7 @@ static int nv_change_mtu(struct net_device *dev, int new_mtu) */ nv_disable_irq(dev); netif_tx_lock_bh(dev); + netif_addr_lock(dev); spin_lock(&np->lock); /* stop engines */ nv_stop_rxtx(dev); @@ -2851,6 +2856,7 @@ static int nv_change_mtu(struct net_device *dev, int new_mtu) /* restart rx engine */ nv_start_rxtx(dev); spin_unlock(&np->lock); + netif_addr_unlock(dev); netif_tx_unlock_bh(dev); nv_enable_irq(dev); } @@ -2887,6 +2893,7 @@ static int nv_set_mac_address(struct net_device *dev, void *addr) if (netif_running(dev)) { netif_tx_lock_bh(dev); + netif_addr_lock(dev); spin_lock_irq(&np->lock); /* stop rx engine */ @@ -2898,6 +2905,7 @@ static int nv_set_mac_address(struct net_device *dev, void *addr) /* restart rx engine */ nv_start_rx(dev); spin_unlock_irq(&np->lock); + netif_addr_unlock(dev); netif_tx_unlock_bh(dev); } else { nv_copy_mac_to_hw(dev); @@ -3967,6 +3975,7 @@ static void nv_do_nic_poll(unsigned long data) printk(KERN_INFO "forcedeth: MAC in recoverable error state\n"); if (netif_running(dev)) { netif_tx_lock_bh(dev); + netif_addr_lock(dev); spin_lock(&np->lock); /* stop engines */ nv_stop_rxtx(dev); @@ -3991,6 +4000,7 @@ static void nv_do_nic_poll(unsigned long data) /* restart rx engine */ nv_start_rxtx(dev); spin_unlock(&np->lock); + netif_addr_unlock(dev); netif_tx_unlock_bh(dev); } } @@ -4198,6 +4208,7 @@ static int nv_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd) nv_disable_irq(dev); netif_tx_lock_bh(dev); + netif_addr_lock(dev); /* with plain spinlock lockdep complains */ spin_lock_irqsave(&np->lock, flags); /* stop engines */ @@ -4211,6 +4222,7 @@ static int nv_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd) */ nv_stop_rxtx(dev); spin_unlock_irqrestore(&np->lock, flags); + netif_addr_unlock(dev); netif_tx_unlock_bh(dev); } @@ -4356,10 +4368,12 @@ static int nv_nway_reset(struct net_device *dev) if (netif_running(dev)) { nv_disable_irq(dev); netif_tx_lock_bh(dev); + netif_addr_lock(dev); spin_lock(&np->lock); /* stop engines */ nv_stop_rxtx(dev); spin_unlock(&np->lock); + netif_addr_unlock(dev); netif_tx_unlock_bh(dev); printk(KERN_INFO "%s: link down.\n", dev->name); } @@ -4467,6 +4481,7 @@ static int nv_set_ringparam(struct net_device *dev, struct ethtool_ringparam* ri if (netif_running(dev)) { nv_disable_irq(dev); netif_tx_lock_bh(dev); + netif_addr_lock(dev); spin_lock(&np->lock); /* stop engines */ nv_stop_rxtx(dev); @@ -4515,6 +4530,7 @@ static int nv_set_ringparam(struct net_device *dev, struct ethtool_ringparam* ri /* restart engines */ nv_start_rxtx(dev); spin_unlock(&np->lock); + netif_addr_unlock(dev); netif_tx_unlock_bh(dev); nv_enable_irq(dev); } @@ -4552,10 +4568,12 @@ static int nv_set_pauseparam(struct net_device *dev, struct ethtool_pauseparam* if (netif_running(dev)) { nv_disable_irq(dev); netif_tx_lock_bh(dev); + netif_addr_lock(dev); spin_lock(&np->lock); /* stop engines */ nv_stop_rxtx(dev); spin_unlock(&np->lock); + netif_addr_unlock(dev); netif_tx_unlock_bh(dev); } @@ -4942,6 +4960,7 @@ static void nv_self_test(struct net_device *dev, struct ethtool_test *test, u64 napi_disable(&np->napi); #endif netif_tx_lock_bh(dev); + netif_addr_lock(dev); spin_lock_irq(&np->lock); nv_disable_hw_interrupts(dev, np->irqmask); if (!(np->msi_flags & NV_MSI_X_ENABLED)) { @@ -4955,6 +4974,7 @@ static void nv_self_test(struct net_device *dev, struct ethtool_test *test, u64 /* drain rx queue */ nv_drain_rxtx(dev); spin_unlock_irq(&np->lock); + netif_addr_unlock(dev); netif_tx_unlock_bh(dev); } @@ -5566,6 +5586,11 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i /* set mac address */ nv_copy_mac_to_hw(dev); + /* Workaround current PCI init glitch: wakeup bits aren't + * being set from PCI PM capability. + */ + device_init_wakeup(&pci_dev->dev, 1); + /* disable WOL */ writel(0, base + NvRegWakeUpFlags); np->wolenabled = 0; @@ -5816,50 +5841,66 @@ static int nv_suspend(struct pci_dev *pdev, pm_message_t state) { struct net_device *dev = pci_get_drvdata(pdev); struct fe_priv *np = netdev_priv(dev); + u8 __iomem *base = get_hwbase(dev); + int i; - if (!netif_running(dev)) - goto out; - + if (netif_running(dev)) { + // Gross. + nv_close(dev); + } netif_device_detach(dev); - // Gross. - nv_close(dev); + /* save non-pci configuration space */ + for (i = 0;i <= np->register_size/sizeof(u32); i++) + np->saved_config_space[i] = readl(base + i*sizeof(u32)); pci_save_state(pdev); pci_enable_wake(pdev, pci_choose_state(pdev, state), np->wolenabled); + pci_disable_device(pdev); pci_set_power_state(pdev, pci_choose_state(pdev, state)); -out: return 0; } static int nv_resume(struct pci_dev *pdev) { struct net_device *dev = pci_get_drvdata(pdev); + struct fe_priv *np = netdev_priv(dev); u8 __iomem *base = get_hwbase(dev); - int rc = 0; - u32 txreg; - - if (!netif_running(dev)) - goto out; - - netif_device_attach(dev); + int i, rc = 0; pci_set_power_state(pdev, PCI_D0); pci_restore_state(pdev); + /* ack any pending wake events, disable PME */ pci_enable_wake(pdev, PCI_D0, 0); - /* restore mac address reverse flag */ - txreg = readl(base + NvRegTransmitPoll); - txreg |= NVREG_TRANSMITPOLL_MAC_ADDR_REV; - writel(txreg, base + NvRegTransmitPoll); + /* restore non-pci configuration space */ + for (i = 0;i <= np->register_size/sizeof(u32); i++) + writel(np->saved_config_space[i], base+i*sizeof(u32)); - rc = nv_open(dev); - nv_set_multicast(dev); -out: + netif_device_attach(dev); + if (netif_running(dev)) { + rc = nv_open(dev); + nv_set_multicast(dev); + } return rc; } + +static void nv_shutdown(struct pci_dev *pdev) +{ + struct net_device *dev = pci_get_drvdata(pdev); + struct fe_priv *np = netdev_priv(dev); + + if (netif_running(dev)) + nv_close(dev); + + pci_enable_wake(pdev, PCI_D3hot, np->wolenabled); + pci_enable_wake(pdev, PCI_D3cold, np->wolenabled); + pci_disable_device(pdev); + pci_set_power_state(pdev, PCI_D3hot); +} #else #define nv_suspend NULL +#define nv_shutdown NULL #define nv_resume NULL #endif /* CONFIG_PM */ @@ -6030,6 +6071,7 @@ static struct pci_driver driver = { .remove = __devexit_p(nv_remove), .suspend = nv_suspend, .resume = nv_resume, + .shutdown = nv_shutdown, }; static int __init init_nic(void) diff --git a/drivers/net/fs_enet/fs_enet-main.c b/drivers/net/fs_enet/fs_enet-main.c index 352574a3f056..445763e5648e 100644 --- a/drivers/net/fs_enet/fs_enet-main.c +++ b/drivers/net/fs_enet/fs_enet-main.c @@ -43,6 +43,7 @@ #include <asm/uaccess.h> #ifdef CONFIG_PPC_CPM_NEW_BINDING +#include <linux/of_gpio.h> #include <linux/of_platform.h> #endif @@ -737,7 +738,7 @@ static void generic_adjust_link(struct net_device *dev) if (!fep->oldlink) { new_state = 1; fep->oldlink = 1; - netif_schedule(dev); + netif_tx_schedule_all(dev); netif_carrier_on(dev); netif_start_queue(dev); } @@ -1172,8 +1173,7 @@ static int __devinit find_phy(struct device_node *np, struct fs_platform_info *fpi) { struct device_node *phynode, *mdionode; - struct resource res; - int ret = 0, len; + int ret = 0, len, bus_id; const u32 *data; data = of_get_property(np, "fixed-link", NULL); @@ -1190,19 +1190,28 @@ static int __devinit find_phy(struct device_node *np, if (!phynode) return -EINVAL; - mdionode = of_get_parent(phynode); - if (!mdionode) + data = of_get_property(phynode, "reg", &len); + if (!data || len != 4) { + ret = -EINVAL; goto out_put_phy; + } - ret = of_address_to_resource(mdionode, 0, &res); - if (ret) - goto out_put_mdio; + mdionode = of_get_parent(phynode); + if (!mdionode) { + ret = -EINVAL; + goto out_put_phy; + } - data = of_get_property(phynode, "reg", &len); - if (!data || len != 4) - goto out_put_mdio; + 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", res.start, *data); + snprintf(fpi->bus_id, 16, "%x:%02x", bus_id, *data); out_put_mdio: of_node_put(mdionode); diff --git a/drivers/net/gianfar.c b/drivers/net/gianfar.c index 25bdd0832df5..45a63172852f 100644 --- a/drivers/net/gianfar.c +++ b/drivers/net/gianfar.c @@ -44,8 +44,7 @@ * happen immediately, but will wait until either a set number * of frames or amount of time have passed). In NAPI, the * interrupt handler will signal there is work to be done, and - * exit. Without NAPI, the packet(s) will be handled - * immediately. Both methods will start at the last known empty + * exit. This method will start at the last known empty * descriptor, and process every subsequent descriptor until there * are none left with data (NAPI will stop after a set number of * packets to give time to other tasks, but will eventually @@ -101,12 +100,6 @@ #undef BRIEF_GFAR_ERRORS #undef VERBOSE_GFAR_ERRORS -#ifdef CONFIG_GFAR_NAPI -#define RECEIVE(x) netif_receive_skb(x) -#else -#define RECEIVE(x) netif_rx(x) -#endif - const char gfar_driver_name[] = "Gianfar Ethernet"; const char gfar_driver_version[] = "1.3"; @@ -131,9 +124,7 @@ static void free_skb_resources(struct gfar_private *priv); static void gfar_set_multi(struct net_device *dev); static void gfar_set_hash_for_addr(struct net_device *dev, u8 *addr); static void gfar_configure_serdes(struct net_device *dev); -#ifdef CONFIG_GFAR_NAPI static int gfar_poll(struct napi_struct *napi, int budget); -#endif #ifdef CONFIG_NET_POLL_CONTROLLER static void gfar_netpoll(struct net_device *dev); #endif @@ -260,9 +251,7 @@ static int gfar_probe(struct platform_device *pdev) dev->hard_start_xmit = gfar_start_xmit; dev->tx_timeout = gfar_timeout; dev->watchdog_timeo = TX_TIMEOUT; -#ifdef CONFIG_GFAR_NAPI netif_napi_add(dev, &priv->napi, gfar_poll, GFAR_DEV_WEIGHT); -#endif #ifdef CONFIG_NET_POLL_CONTROLLER dev->poll_controller = gfar_netpoll; #endif @@ -363,11 +352,7 @@ static int gfar_probe(struct platform_device *pdev) /* Even more device info helps when determining which kernel */ /* provided which set of benchmarks. */ -#ifdef CONFIG_GFAR_NAPI printk(KERN_INFO "%s: Running with NAPI enabled\n", dev->name); -#else - printk(KERN_INFO "%s: Running with NAPI disabled\n", dev->name); -#endif printk(KERN_INFO "%s: %d/%d RX/TX BD ring size\n", dev->name, priv->rx_ring_size, priv->tx_ring_size); @@ -928,7 +913,7 @@ rx_irq_fail: tx_irq_fail: free_irq(priv->interruptError, dev); err_irq_fail: -err_rxalloc_fail: +err_rxalloc_fail: rx_skb_fail: free_skb_resources(priv); tx_skb_fail: @@ -945,14 +930,10 @@ tx_skb_fail: /* Returns 0 for success. */ static int gfar_enet_open(struct net_device *dev) { -#ifdef CONFIG_GFAR_NAPI struct gfar_private *priv = netdev_priv(dev); -#endif int err; -#ifdef CONFIG_GFAR_NAPI napi_enable(&priv->napi); -#endif /* Initialize a bunch of registers */ init_registers(dev); @@ -962,17 +943,13 @@ static int gfar_enet_open(struct net_device *dev) err = init_phy(dev); if(err) { -#ifdef CONFIG_GFAR_NAPI napi_disable(&priv->napi); -#endif return err; } err = startup_gfar(dev); if (err) { -#ifdef CONFIG_GFAR_NAPI napi_disable(&priv->napi); -#endif return err; } @@ -1128,9 +1105,7 @@ static int gfar_close(struct net_device *dev) { struct gfar_private *priv = netdev_priv(dev); -#ifdef CONFIG_GFAR_NAPI napi_disable(&priv->napi); -#endif stop_gfar(dev); @@ -1259,7 +1234,7 @@ static void gfar_timeout(struct net_device *dev) startup_gfar(dev); } - netif_schedule(dev); + netif_tx_schedule_all(dev); } /* Interrupt Handler for Transmit complete */ @@ -1427,14 +1402,9 @@ irqreturn_t gfar_receive(int irq, void *dev_id) { struct net_device *dev = (struct net_device *) dev_id; struct gfar_private *priv = netdev_priv(dev); -#ifdef CONFIG_GFAR_NAPI u32 tempval; -#else - unsigned long flags; -#endif /* support NAPI */ -#ifdef CONFIG_GFAR_NAPI /* Clear IEVENT, so interrupts aren't called again * because of the packets that have already arrived */ gfar_write(&priv->regs->ievent, IEVENT_RTX_MASK); @@ -1451,38 +1421,10 @@ irqreturn_t gfar_receive(int irq, void *dev_id) dev->name, gfar_read(&priv->regs->ievent), gfar_read(&priv->regs->imask)); } -#else - /* Clear IEVENT, so rx interrupt isn't called again - * because of this interrupt */ - gfar_write(&priv->regs->ievent, IEVENT_RX_MASK); - - spin_lock_irqsave(&priv->rxlock, flags); - gfar_clean_rx_ring(dev, priv->rx_ring_size); - - /* If we are coalescing interrupts, update the timer */ - /* Otherwise, clear it */ - if (likely(priv->rxcoalescing)) { - gfar_write(&priv->regs->rxic, 0); - gfar_write(&priv->regs->rxic, - mk_ic_value(priv->rxcount, priv->rxtime)); - } - - spin_unlock_irqrestore(&priv->rxlock, flags); -#endif return IRQ_HANDLED; } -static inline int gfar_rx_vlan(struct sk_buff *skb, - struct vlan_group *vlgrp, unsigned short vlctl) -{ -#ifdef CONFIG_GFAR_NAPI - return vlan_hwaccel_receive_skb(skb, vlgrp, vlctl); -#else - return vlan_hwaccel_rx(skb, vlgrp, vlctl); -#endif -} - static inline void gfar_rx_checksum(struct sk_buff *skb, struct rxfcb *fcb) { /* If valid headers were found, and valid sums @@ -1539,10 +1481,11 @@ static int gfar_process_frame(struct net_device *dev, struct sk_buff *skb, skb->protocol = eth_type_trans(skb, dev); /* Send the packet up the stack */ - if (unlikely(priv->vlgrp && (fcb->flags & RXFCB_VLN))) - ret = gfar_rx_vlan(skb, priv->vlgrp, fcb->vlctl); - else - ret = RECEIVE(skb); + if (unlikely(priv->vlgrp && (fcb->flags & RXFCB_VLN))) { + ret = vlan_hwaccel_receive_skb(skb, priv->vlgrp, + fcb->vlctl); + } else + ret = netif_receive_skb(skb); if (NET_RX_DROP == ret) priv->extra_stats.kernel_dropped++; @@ -1629,7 +1572,6 @@ int gfar_clean_rx_ring(struct net_device *dev, int rx_work_limit) return howmany; } -#ifdef CONFIG_GFAR_NAPI static int gfar_poll(struct napi_struct *napi, int budget) { struct gfar_private *priv = container_of(napi, struct gfar_private, napi); @@ -1664,7 +1606,6 @@ static int gfar_poll(struct napi_struct *napi, int budget) return howmany; } -#endif #ifdef CONFIG_NET_POLL_CONTROLLER /* @@ -1784,7 +1725,7 @@ static void adjust_link(struct net_device *dev) if (!priv->oldlink) { new_state = 1; priv->oldlink = 1; - netif_schedule(dev); + netif_tx_schedule_all(dev); } } else if (priv->oldlink) { new_state = 1; @@ -2003,11 +1944,6 @@ static irqreturn_t gfar_error(int irq, void *dev_id) gfar_receive(irq, dev_id); -#ifndef CONFIG_GFAR_NAPI - /* Clear the halt bit in RSTAT */ - gfar_write(&priv->regs->rstat, RSTAT_CLEAR_RHALT); -#endif - if (netif_msg_rx_err(priv)) printk(KERN_DEBUG "%s: busy error (rstat: %x)\n", dev->name, gfar_read(&priv->regs->rstat)); diff --git a/drivers/net/gianfar.h b/drivers/net/gianfar.h index 27f37c81e52c..bead71cb2b16 100644 --- a/drivers/net/gianfar.h +++ b/drivers/net/gianfar.h @@ -77,13 +77,8 @@ extern const char gfar_driver_name[]; extern const char gfar_driver_version[]; /* These need to be powers of 2 for this driver */ -#ifdef CONFIG_GFAR_NAPI #define DEFAULT_TX_RING_SIZE 256 #define DEFAULT_RX_RING_SIZE 256 -#else -#define DEFAULT_TX_RING_SIZE 64 -#define DEFAULT_RX_RING_SIZE 64 -#endif #define GFAR_RX_MAX_RING_SIZE 256 #define GFAR_TX_MAX_RING_SIZE 256 @@ -128,14 +123,8 @@ extern const char gfar_driver_version[]; #define DEFAULT_RXTIME 21 -/* Non NAPI Case */ -#ifndef CONFIG_GFAR_NAPI -#define DEFAULT_RX_COALESCE 1 -#define DEFAULT_RXCOUNT 16 -#else #define DEFAULT_RX_COALESCE 0 #define DEFAULT_RXCOUNT 0 -#endif /* CONFIG_GFAR_NAPI */ #define MIIMCFG_INIT_VALUE 0x00000007 #define MIIMCFG_RESET 0x80000000 diff --git a/drivers/net/hamachi.c b/drivers/net/hamachi.c index e5c2380f50ca..3199526bcecb 100644 --- a/drivers/net/hamachi.c +++ b/drivers/net/hamachi.c @@ -1140,11 +1140,11 @@ static void hamachi_tx_timeout(struct net_device *dev) } /* Fill in the Rx buffers. Handle allocation failure gracefully. */ for (i = 0; i < RX_RING_SIZE; i++) { - struct sk_buff *skb = dev_alloc_skb(hmp->rx_buf_sz); + struct sk_buff *skb = netdev_alloc_skb(dev, hmp->rx_buf_sz); hmp->rx_skbuff[i] = skb; if (skb == NULL) break; - skb->dev = dev; /* Mark as being used by this device. */ + skb_reserve(skb, 2); /* 16 byte align the IP header. */ hmp->rx_ring[i].addr = cpu_to_leXX(pci_map_single(hmp->pci_dev, skb->data, hmp->rx_buf_sz, PCI_DMA_FROMDEVICE)); @@ -1178,14 +1178,6 @@ static void hamachi_init_ring(struct net_device *dev) hmp->cur_rx = hmp->cur_tx = 0; hmp->dirty_rx = hmp->dirty_tx = 0; -#if 0 - /* This is wrong. I'm not sure what the original plan was, but this - * is wrong. An MTU of 1 gets you a buffer of 1536, while an MTU - * of 1501 gets a buffer of 1533? -KDU - */ - hmp->rx_buf_sz = (dev->mtu <= 1500 ? PKT_BUF_SZ : dev->mtu + 32); -#endif - /* My attempt at a reasonable correction */ /* +26 gets the maximum ethernet encapsulation, +7 & ~7 because the * card needs room to do 8 byte alignment, +2 so we can reserve * the first 2 bytes, and +16 gets room for the status word from the diff --git a/drivers/net/hamradio/6pack.c b/drivers/net/hamradio/6pack.c index 9d5721287d6f..0f501d2ca935 100644 --- a/drivers/net/hamradio/6pack.c +++ b/drivers/net/hamradio/6pack.c @@ -99,9 +99,6 @@ struct sixpack { unsigned int rx_count; unsigned int rx_count_cooked; - /* 6pack interface statistics. */ - struct net_device_stats stats; - int mtu; /* Our mtu (to spot changes!) */ int buffsize; /* Max buffers sizes */ @@ -237,7 +234,7 @@ static void sp_encaps(struct sixpack *sp, unsigned char *icp, int len) return; out_drop: - sp->stats.tx_dropped++; + sp->dev->stats.tx_dropped++; netif_start_queue(sp->dev); if (net_ratelimit()) printk(KERN_DEBUG "%s: %s - dropped.\n", sp->dev->name, msg); @@ -252,7 +249,7 @@ static int sp_xmit(struct sk_buff *skb, struct net_device *dev) spin_lock_bh(&sp->lock); /* We were not busy, so we are now... :-) */ netif_stop_queue(dev); - sp->stats.tx_bytes += skb->len; + dev->stats.tx_bytes += skb->len; sp_encaps(sp, skb->data, skb->len); spin_unlock_bh(&sp->lock); @@ -298,18 +295,14 @@ static int sp_header(struct sk_buff *skb, struct net_device *dev, return 0; } -static struct net_device_stats *sp_get_stats(struct net_device *dev) -{ - struct sixpack *sp = netdev_priv(dev); - return &sp->stats; -} - static int sp_set_mac_address(struct net_device *dev, void *addr) { struct sockaddr_ax25 *sa = addr; netif_tx_lock_bh(dev); + netif_addr_lock(dev); memcpy(dev->dev_addr, &sa->sax25_call, AX25_ADDR_LEN); + netif_addr_unlock(dev); netif_tx_unlock_bh(dev); return 0; @@ -338,7 +331,6 @@ static void sp_setup(struct net_device *dev) dev->destructor = free_netdev; dev->stop = sp_close; - dev->get_stats = sp_get_stats; dev->set_mac_address = sp_set_mac_address; dev->hard_header_len = AX25_MAX_HEADER_LEN; dev->header_ops = &sp_header_ops; @@ -370,7 +362,7 @@ static void sp_bump(struct sixpack *sp, char cmd) count = sp->rcount + 1; - sp->stats.rx_bytes += count; + sp->dev->stats.rx_bytes += count; if ((skb = dev_alloc_skb(count)) == NULL) goto out_mem; @@ -382,12 +374,12 @@ static void sp_bump(struct sixpack *sp, char cmd) skb->protocol = ax25_type_trans(skb, sp->dev); netif_rx(skb); sp->dev->last_rx = jiffies; - sp->stats.rx_packets++; + sp->dev->stats.rx_packets++; return; out_mem: - sp->stats.rx_dropped++; + sp->dev->stats.rx_dropped++; } @@ -436,7 +428,7 @@ static void sixpack_write_wakeup(struct tty_struct *tty) if (sp->xleft <= 0) { /* Now serial buffer is almost free & we can start * transmission of another packet */ - sp->stats.tx_packets++; + sp->dev->stats.tx_packets++; clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags); sp->tx_enable = 0; netif_wake_queue(sp->dev); @@ -484,7 +476,7 @@ static void sixpack_receive_buf(struct tty_struct *tty, count--; if (fp && *fp++) { if (!test_and_set_bit(SIXPF_ERROR, &sp->flags)) - sp->stats.rx_errors++; + sp->dev->stats.rx_errors++; continue; } } @@ -783,7 +775,7 @@ static int sixpack_ioctl(struct tty_struct *tty, struct file *file, return err; } -static struct tty_ldisc sp_ldisc = { +static struct tty_ldisc_ops sp_ldisc = { .owner = THIS_MODULE, .magic = TTY_LDISC_MAGIC, .name = "6pack", diff --git a/drivers/net/hamradio/bpqether.c b/drivers/net/hamradio/bpqether.c index 5f4b4c6c9f76..b6500b2aacf2 100644 --- a/drivers/net/hamradio/bpqether.c +++ b/drivers/net/hamradio/bpqether.c @@ -124,6 +124,18 @@ static LIST_HEAD(bpq_devices); */ static struct lock_class_key bpq_netdev_xmit_lock_key; +static void bpq_set_lockdep_class_one(struct net_device *dev, + struct netdev_queue *txq, + void *_unused) +{ + lockdep_set_class(&txq->_xmit_lock, &bpq_netdev_xmit_lock_key); +} + +static void bpq_set_lockdep_class(struct net_device *dev) +{ + netdev_for_each_tx_queue(dev, bpq_set_lockdep_class_one, NULL); +} + /* ------------------------------------------------------------------------ */ @@ -523,7 +535,7 @@ static int bpq_new_device(struct net_device *edev) err = register_netdevice(ndev); if (err) goto error; - lockdep_set_class(&ndev->_xmit_lock, &bpq_netdev_xmit_lock_key); + bpq_set_lockdep_class(ndev); /* List protected by RTNL */ list_add_rcu(&bpq->bpq_list, &bpq_devices); diff --git a/drivers/net/hamradio/mkiss.c b/drivers/net/hamradio/mkiss.c index 65166035aca0..3249df5e0f17 100644 --- a/drivers/net/hamradio/mkiss.c +++ b/drivers/net/hamradio/mkiss.c @@ -356,7 +356,9 @@ static int ax_set_mac_address(struct net_device *dev, void *addr) struct sockaddr_ax25 *sa = addr; netif_tx_lock_bh(dev); + netif_addr_lock(dev); memcpy(dev->dev_addr, &sa->sax25_call, AX25_ADDR_LEN); + netif_addr_unlock(dev); netif_tx_unlock_bh(dev); return 0; @@ -969,7 +971,7 @@ out: mkiss_put(ax); } -static struct tty_ldisc ax_ldisc = { +static struct tty_ldisc_ops ax_ldisc = { .owner = THIS_MODULE, .magic = TTY_LDISC_MAGIC, .name = "mkiss", diff --git a/drivers/net/hp.c b/drivers/net/hp.c index c649a8019beb..8281209ededf 100644 --- a/drivers/net/hp.c +++ b/drivers/net/hp.c @@ -103,7 +103,7 @@ static int __init do_hp_probe(struct net_device *dev) #ifndef MODULE struct net_device * __init hp_probe(int unit) { - struct net_device *dev = alloc_ei_netdev(); + struct net_device *dev = alloc_eip_netdev(); int err; if (!dev) @@ -176,7 +176,7 @@ static int __init hp_probe1(struct net_device *dev, int ioaddr) outb_p(irqmap[irq] | HP_RUN, ioaddr + HP_CONFIGURE); outb_p( 0x00 | HP_RUN, ioaddr + HP_CONFIGURE); if (irq == probe_irq_off(cookie) /* It's a good IRQ line! */ - && request_irq (irq, ei_interrupt, 0, DRV_NAME, dev) == 0) { + && request_irq (irq, eip_interrupt, 0, DRV_NAME, dev) == 0) { printk(" selecting IRQ %d.\n", irq); dev->irq = *irqp; break; @@ -191,7 +191,7 @@ static int __init hp_probe1(struct net_device *dev, int ioaddr) } else { if (dev->irq == 2) dev->irq = 9; - if ((retval = request_irq(dev->irq, ei_interrupt, 0, DRV_NAME, dev))) { + if ((retval = request_irq(dev->irq, eip_interrupt, 0, DRV_NAME, dev))) { printk (" unable to get IRQ %d.\n", dev->irq); goto out; } @@ -202,7 +202,7 @@ static int __init hp_probe1(struct net_device *dev, int ioaddr) dev->open = &hp_open; dev->stop = &hp_close; #ifdef CONFIG_NET_POLL_CONTROLLER - dev->poll_controller = ei_poll; + dev->poll_controller = eip_poll; #endif ei_status.name = name; @@ -231,14 +231,14 @@ out: static int hp_open(struct net_device *dev) { - ei_open(dev); + eip_open(dev); return 0; } static int hp_close(struct net_device *dev) { - ei_close(dev); + eip_close(dev); return 0; } @@ -421,7 +421,7 @@ init_module(void) if (this_dev != 0) break; /* only autoprobe 1st one */ printk(KERN_NOTICE "hp.c: Presently autoprobing (not recommended) for a single card.\n"); } - dev = alloc_ei_netdev(); + dev = alloc_eip_netdev(); if (!dev) break; dev->irq = irq[this_dev]; diff --git a/drivers/net/hplance.c b/drivers/net/hplance.c index be6e5bc7c881..2e802634d366 100644 --- a/drivers/net/hplance.c +++ b/drivers/net/hplance.c @@ -220,12 +220,12 @@ static int hplance_close(struct net_device *dev) return 0; } -int __init hplance_init_module(void) +static int __init hplance_init_module(void) { return dio_register_driver(&hplance_driver); } -void __exit hplance_cleanup_module(void) +static void __exit hplance_cleanup_module(void) { dio_unregister_driver(&hplance_driver); } diff --git a/drivers/net/ibm_emac/Kconfig b/drivers/net/ibm_emac/Kconfig deleted file mode 100644 index f61c48047dc0..000000000000 --- a/drivers/net/ibm_emac/Kconfig +++ /dev/null @@ -1,70 +0,0 @@ -config IBM_EMAC - tristate "PowerPC 4xx on-chip Ethernet support" - depends on 4xx && !PPC_MERGE - help - This driver supports the PowerPC 4xx EMAC family of on-chip - Ethernet controllers. - -config IBM_EMAC_RXB - int "Number of receive buffers" - depends on IBM_EMAC - default "128" - -config IBM_EMAC_TXB - int "Number of transmit buffers" - depends on IBM_EMAC - default "64" - -config IBM_EMAC_POLL_WEIGHT - int "MAL NAPI polling weight" - depends on IBM_EMAC - default "32" - -config IBM_EMAC_RX_COPY_THRESHOLD - int "RX skb copy threshold (bytes)" - depends on IBM_EMAC - default "256" - -config IBM_EMAC_RX_SKB_HEADROOM - int "Additional RX skb headroom (bytes)" - depends on IBM_EMAC - default "0" - help - Additional receive skb headroom. Note, that driver - will always reserve at least 2 bytes to make IP header - aligned, so usually there is no need to add any additional - headroom. - - If unsure, set to 0. - -config IBM_EMAC_PHY_RX_CLK_FIX - bool "PHY Rx clock workaround" - depends on IBM_EMAC && (405EP || 440GX || 440EP || 440GR) - help - Enable this if EMAC attached to a PHY which doesn't generate - RX clock if there is no link, if this is the case, you will - see "TX disable timeout" or "RX disable timeout" in the system - log. - - If unsure, say N. - -config IBM_EMAC_DEBUG - bool "Debugging" - depends on IBM_EMAC - default n - -config IBM_EMAC_ZMII - bool - depends on IBM_EMAC && (NP405H || NP405L || 44x) - default y - -config IBM_EMAC_RGMII - bool - depends on IBM_EMAC && 440GX - default y - -config IBM_EMAC_TAH - bool - depends on IBM_EMAC && 440GX - default y - diff --git a/drivers/net/ibm_emac/Makefile b/drivers/net/ibm_emac/Makefile deleted file mode 100644 index f98ddf0e807a..000000000000 --- a/drivers/net/ibm_emac/Makefile +++ /dev/null @@ -1,11 +0,0 @@ -# -# Makefile for the PowerPC 4xx on-chip ethernet driver -# - -obj-$(CONFIG_IBM_EMAC) += ibm_emac.o - -ibm_emac-objs := ibm_emac_mal.o ibm_emac_core.o ibm_emac_phy.o -ibm_emac-$(CONFIG_IBM_EMAC_ZMII) += ibm_emac_zmii.o -ibm_emac-$(CONFIG_IBM_EMAC_RGMII) += ibm_emac_rgmii.o -ibm_emac-$(CONFIG_IBM_EMAC_TAH) += ibm_emac_tah.o -ibm_emac-$(CONFIG_IBM_EMAC_DEBUG) += ibm_emac_debug.o diff --git a/drivers/net/ibm_emac/ibm_emac.h b/drivers/net/ibm_emac/ibm_emac.h deleted file mode 100644 index 97ed22bb4320..000000000000 --- a/drivers/net/ibm_emac/ibm_emac.h +++ /dev/null @@ -1,329 +0,0 @@ -/* - * drivers/net/ibm_emac/ibm_emac.h - * - * Register definitions for PowerPC 4xx on-chip ethernet contoller - * - * Copyright (c) 2004, 2005 Zultys Technologies. - * Eugene Surovegin <eugene.surovegin@zultys.com> or <ebs@ebshome.net> - * - * Based on original work by - * Matt Porter <mporter@kernel.crashing.org> - * Armin Kuster <akuster@mvista.com> - * Copyright 2002-2004 MontaVista Software Inc. - * - * 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. - * - */ -#ifndef __IBM_EMAC_H_ -#define __IBM_EMAC_H_ - -#include <linux/types.h> - -/* This is a simple check to prevent use of this driver on non-tested SoCs */ -#if !defined(CONFIG_405GP) && !defined(CONFIG_405GPR) && !defined(CONFIG_405EP) && \ - !defined(CONFIG_440GP) && !defined(CONFIG_440GX) && !defined(CONFIG_440SP) && \ - !defined(CONFIG_440EP) && !defined(CONFIG_NP405H) && !defined(CONFIG_440SPE) && \ - !defined(CONFIG_440GR) -#error "Unknown SoC. Please, check chip user manual and make sure EMAC defines are OK" -#endif - -/* EMAC registers Write Access rules */ -struct emac_regs { - u32 mr0; /* special */ - u32 mr1; /* Reset */ - u32 tmr0; /* special */ - u32 tmr1; /* special */ - u32 rmr; /* Reset */ - u32 isr; /* Always */ - u32 iser; /* Reset */ - u32 iahr; /* Reset, R, T */ - u32 ialr; /* Reset, R, T */ - u32 vtpid; /* Reset, R, T */ - u32 vtci; /* Reset, R, T */ - u32 ptr; /* Reset, T */ - u32 iaht1; /* Reset, R */ - u32 iaht2; /* Reset, R */ - u32 iaht3; /* Reset, R */ - u32 iaht4; /* Reset, R */ - u32 gaht1; /* Reset, R */ - u32 gaht2; /* Reset, R */ - u32 gaht3; /* Reset, R */ - u32 gaht4; /* Reset, R */ - u32 lsah; - u32 lsal; - u32 ipgvr; /* Reset, T */ - u32 stacr; /* special */ - u32 trtr; /* special */ - u32 rwmr; /* Reset */ - u32 octx; - u32 ocrx; - u32 ipcr; -}; - -#if !defined(CONFIG_IBM_EMAC4) -#define EMAC_ETHTOOL_REGS_VER 0 -#define EMAC_ETHTOOL_REGS_SIZE (sizeof(struct emac_regs) - sizeof(u32)) -#else -#define EMAC_ETHTOOL_REGS_VER 1 -#define EMAC_ETHTOOL_REGS_SIZE sizeof(struct emac_regs) -#endif - -/* EMACx_MR0 */ -#define EMAC_MR0_RXI 0x80000000 -#define EMAC_MR0_TXI 0x40000000 -#define EMAC_MR0_SRST 0x20000000 -#define EMAC_MR0_TXE 0x10000000 -#define EMAC_MR0_RXE 0x08000000 -#define EMAC_MR0_WKE 0x04000000 - -/* EMACx_MR1 */ -#define EMAC_MR1_FDE 0x80000000 -#define EMAC_MR1_ILE 0x40000000 -#define EMAC_MR1_VLE 0x20000000 -#define EMAC_MR1_EIFC 0x10000000 -#define EMAC_MR1_APP 0x08000000 -#define EMAC_MR1_IST 0x01000000 - -#define EMAC_MR1_MF_MASK 0x00c00000 -#define EMAC_MR1_MF_10 0x00000000 -#define EMAC_MR1_MF_100 0x00400000 -#if !defined(CONFIG_IBM_EMAC4) -#define EMAC_MR1_MF_1000 0x00000000 -#define EMAC_MR1_MF_1000GPCS 0x00000000 -#define EMAC_MR1_MF_IPPA(id) 0x00000000 -#else -#define EMAC_MR1_MF_1000 0x00800000 -#define EMAC_MR1_MF_1000GPCS 0x00c00000 -#define EMAC_MR1_MF_IPPA(id) (((id) & 0x1f) << 6) -#endif - -#define EMAC_TX_FIFO_SIZE 2048 - -#if !defined(CONFIG_IBM_EMAC4) -#define EMAC_MR1_RFS_4K 0x00300000 -#define EMAC_MR1_RFS_16K 0x00000000 -#define EMAC_RX_FIFO_SIZE(gige) 4096 -#define EMAC_MR1_TFS_2K 0x00080000 -#define EMAC_MR1_TR0_MULT 0x00008000 -#define EMAC_MR1_JPSM 0x00000000 -#define EMAC_MR1_MWSW_001 0x00000000 -#define EMAC_MR1_BASE(opb) (EMAC_MR1_TFS_2K | EMAC_MR1_TR0_MULT) -#else -#define EMAC_MR1_RFS_4K 0x00180000 -#define EMAC_MR1_RFS_16K 0x00280000 -#define EMAC_RX_FIFO_SIZE(gige) ((gige) ? 16384 : 4096) -#define EMAC_MR1_TFS_2K 0x00020000 -#define EMAC_MR1_TR 0x00008000 -#define EMAC_MR1_MWSW_001 0x00001000 -#define EMAC_MR1_JPSM 0x00000800 -#define EMAC_MR1_OBCI_MASK 0x00000038 -#define EMAC_MR1_OBCI_50 0x00000000 -#define EMAC_MR1_OBCI_66 0x00000008 -#define EMAC_MR1_OBCI_83 0x00000010 -#define EMAC_MR1_OBCI_100 0x00000018 -#define EMAC_MR1_OBCI_100P 0x00000020 -#define EMAC_MR1_OBCI(freq) ((freq) <= 50 ? EMAC_MR1_OBCI_50 : \ - (freq) <= 66 ? EMAC_MR1_OBCI_66 : \ - (freq) <= 83 ? EMAC_MR1_OBCI_83 : \ - (freq) <= 100 ? EMAC_MR1_OBCI_100 : EMAC_MR1_OBCI_100P) -#define EMAC_MR1_BASE(opb) (EMAC_MR1_TFS_2K | EMAC_MR1_TR | \ - EMAC_MR1_OBCI(opb)) -#endif - -/* EMACx_TMR0 */ -#define EMAC_TMR0_GNP 0x80000000 -#if !defined(CONFIG_IBM_EMAC4) -#define EMAC_TMR0_DEFAULT 0x00000000 -#else -#define EMAC_TMR0_TFAE_2_32 0x00000001 -#define EMAC_TMR0_TFAE_4_64 0x00000002 -#define EMAC_TMR0_TFAE_8_128 0x00000003 -#define EMAC_TMR0_TFAE_16_256 0x00000004 -#define EMAC_TMR0_TFAE_32_512 0x00000005 -#define EMAC_TMR0_TFAE_64_1024 0x00000006 -#define EMAC_TMR0_TFAE_128_2048 0x00000007 -#define EMAC_TMR0_DEFAULT EMAC_TMR0_TFAE_2_32 -#endif -#define EMAC_TMR0_XMIT (EMAC_TMR0_GNP | EMAC_TMR0_DEFAULT) - -/* EMACx_TMR1 */ - -/* IBM manuals are not very clear here. - * This is my interpretation of how things are. --ebs - */ -#if defined(CONFIG_40x) -#define EMAC_FIFO_ENTRY_SIZE 8 -#define EMAC_MAL_BURST_SIZE (16 * 4) -#else -#define EMAC_FIFO_ENTRY_SIZE 16 -#define EMAC_MAL_BURST_SIZE (64 * 4) -#endif - -#if !defined(CONFIG_IBM_EMAC4) -#define EMAC_TMR1(l,h) (((l) << 27) | (((h) & 0xff) << 16)) -#else -#define EMAC_TMR1(l,h) (((l) << 27) | (((h) & 0x3ff) << 14)) -#endif - -/* EMACx_RMR */ -#define EMAC_RMR_SP 0x80000000 -#define EMAC_RMR_SFCS 0x40000000 -#define EMAC_RMR_RRP 0x20000000 -#define EMAC_RMR_RFP 0x10000000 -#define EMAC_RMR_ROP 0x08000000 -#define EMAC_RMR_RPIR 0x04000000 -#define EMAC_RMR_PPP 0x02000000 -#define EMAC_RMR_PME 0x01000000 -#define EMAC_RMR_PMME 0x00800000 -#define EMAC_RMR_IAE 0x00400000 -#define EMAC_RMR_MIAE 0x00200000 -#define EMAC_RMR_BAE 0x00100000 -#define EMAC_RMR_MAE 0x00080000 -#if !defined(CONFIG_IBM_EMAC4) -#define EMAC_RMR_BASE 0x00000000 -#else -#define EMAC_RMR_RFAF_2_32 0x00000001 -#define EMAC_RMR_RFAF_4_64 0x00000002 -#define EMAC_RMR_RFAF_8_128 0x00000003 -#define EMAC_RMR_RFAF_16_256 0x00000004 -#define EMAC_RMR_RFAF_32_512 0x00000005 -#define EMAC_RMR_RFAF_64_1024 0x00000006 -#define EMAC_RMR_RFAF_128_2048 0x00000007 -#define EMAC_RMR_BASE EMAC_RMR_RFAF_128_2048 -#endif - -/* EMACx_ISR & EMACx_ISER */ -#if !defined(CONFIG_IBM_EMAC4) -#define EMAC_ISR_TXPE 0x00000000 -#define EMAC_ISR_RXPE 0x00000000 -#define EMAC_ISR_TXUE 0x00000000 -#define EMAC_ISR_RXOE 0x00000000 -#else -#define EMAC_ISR_TXPE 0x20000000 -#define EMAC_ISR_RXPE 0x10000000 -#define EMAC_ISR_TXUE 0x08000000 -#define EMAC_ISR_RXOE 0x04000000 -#endif -#define EMAC_ISR_OVR 0x02000000 -#define EMAC_ISR_PP 0x01000000 -#define EMAC_ISR_BP 0x00800000 -#define EMAC_ISR_RP 0x00400000 -#define EMAC_ISR_SE 0x00200000 -#define EMAC_ISR_ALE 0x00100000 -#define EMAC_ISR_BFCS 0x00080000 -#define EMAC_ISR_PTLE 0x00040000 -#define EMAC_ISR_ORE 0x00020000 -#define EMAC_ISR_IRE 0x00010000 -#define EMAC_ISR_SQE 0x00000080 -#define EMAC_ISR_TE 0x00000040 -#define EMAC_ISR_MOS 0x00000002 -#define EMAC_ISR_MOF 0x00000001 - -/* EMACx_STACR */ -#define EMAC_STACR_PHYD_MASK 0xffff -#define EMAC_STACR_PHYD_SHIFT 16 -#define EMAC_STACR_OC 0x00008000 -#define EMAC_STACR_PHYE 0x00004000 -#define EMAC_STACR_STAC_MASK 0x00003000 -#define EMAC_STACR_STAC_READ 0x00001000 -#define EMAC_STACR_STAC_WRITE 0x00002000 -#if !defined(CONFIG_IBM_EMAC4) -#define EMAC_STACR_OPBC_MASK 0x00000C00 -#define EMAC_STACR_OPBC_50 0x00000000 -#define EMAC_STACR_OPBC_66 0x00000400 -#define EMAC_STACR_OPBC_83 0x00000800 -#define EMAC_STACR_OPBC_100 0x00000C00 -#define EMAC_STACR_OPBC(freq) ((freq) <= 50 ? EMAC_STACR_OPBC_50 : \ - (freq) <= 66 ? EMAC_STACR_OPBC_66 : \ - (freq) <= 83 ? EMAC_STACR_OPBC_83 : EMAC_STACR_OPBC_100) -#define EMAC_STACR_BASE(opb) EMAC_STACR_OPBC(opb) -#else -#define EMAC_STACR_BASE(opb) 0x00000000 -#endif -#define EMAC_STACR_PCDA_MASK 0x1f -#define EMAC_STACR_PCDA_SHIFT 5 -#define EMAC_STACR_PRA_MASK 0x1f - -/* - * For the 440SPe, AMCC inexplicably changed the polarity of - * the "operation complete" bit in the MII control register. - */ -#if defined(CONFIG_440SPE) -static inline int emac_phy_done(u32 stacr) -{ - return !(stacr & EMAC_STACR_OC); -}; -#define EMAC_STACR_START EMAC_STACR_OC - -#else /* CONFIG_440SPE */ -static inline int emac_phy_done(u32 stacr) -{ - return stacr & EMAC_STACR_OC; -}; -#define EMAC_STACR_START 0 -#endif /* !CONFIG_440SPE */ - -/* EMACx_TRTR */ -#if !defined(CONFIG_IBM_EMAC4) -#define EMAC_TRTR_SHIFT 27 -#else -#define EMAC_TRTR_SHIFT 24 -#endif -#define EMAC_TRTR(size) ((((size) >> 6) - 1) << EMAC_TRTR_SHIFT) - -/* EMACx_RWMR */ -#if !defined(CONFIG_IBM_EMAC4) -#define EMAC_RWMR(l,h) (((l) << 23) | ( ((h) & 0x1ff) << 7)) -#else -#define EMAC_RWMR(l,h) (((l) << 22) | ( ((h) & 0x3ff) << 6)) -#endif - -/* EMAC specific TX descriptor control fields (write access) */ -#define EMAC_TX_CTRL_GFCS 0x0200 -#define EMAC_TX_CTRL_GP 0x0100 -#define EMAC_TX_CTRL_ISA 0x0080 -#define EMAC_TX_CTRL_RSA 0x0040 -#define EMAC_TX_CTRL_IVT 0x0020 -#define EMAC_TX_CTRL_RVT 0x0010 -#define EMAC_TX_CTRL_TAH_CSUM 0x000e - -/* EMAC specific TX descriptor status fields (read access) */ -#define EMAC_TX_ST_BFCS 0x0200 -#define EMAC_TX_ST_LCS 0x0080 -#define EMAC_TX_ST_ED 0x0040 -#define EMAC_TX_ST_EC 0x0020 -#define EMAC_TX_ST_LC 0x0010 -#define EMAC_TX_ST_MC 0x0008 -#define EMAC_TX_ST_SC 0x0004 -#define EMAC_TX_ST_UR 0x0002 -#define EMAC_TX_ST_SQE 0x0001 -#if !defined(CONFIG_IBM_EMAC_TAH) -#define EMAC_IS_BAD_TX(v) ((v) & (EMAC_TX_ST_LCS | EMAC_TX_ST_ED | \ - EMAC_TX_ST_EC | EMAC_TX_ST_LC | \ - EMAC_TX_ST_MC | EMAC_TX_ST_UR)) -#else -#define EMAC_IS_BAD_TX(v) ((v) & (EMAC_TX_ST_LCS | EMAC_TX_ST_ED | \ - EMAC_TX_ST_EC | EMAC_TX_ST_LC)) -#endif - -/* EMAC specific RX descriptor status fields (read access) */ -#define EMAC_RX_ST_OE 0x0200 -#define EMAC_RX_ST_PP 0x0100 -#define EMAC_RX_ST_BP 0x0080 -#define EMAC_RX_ST_RP 0x0040 -#define EMAC_RX_ST_SE 0x0020 -#define EMAC_RX_ST_AE 0x0010 -#define EMAC_RX_ST_BFCS 0x0008 -#define EMAC_RX_ST_PTL 0x0004 -#define EMAC_RX_ST_ORE 0x0002 -#define EMAC_RX_ST_IRE 0x0001 -#define EMAC_RX_TAH_BAD_CSUM 0x0003 -#define EMAC_BAD_RX_MASK (EMAC_RX_ST_OE | EMAC_RX_ST_BP | \ - EMAC_RX_ST_RP | EMAC_RX_ST_SE | \ - EMAC_RX_ST_AE | EMAC_RX_ST_BFCS | \ - EMAC_RX_ST_PTL | EMAC_RX_ST_ORE | \ - EMAC_RX_ST_IRE ) -#endif /* __IBM_EMAC_H_ */ diff --git a/drivers/net/ibm_emac/ibm_emac_core.c b/drivers/net/ibm_emac/ibm_emac_core.c deleted file mode 100644 index 73664f226f32..000000000000 --- a/drivers/net/ibm_emac/ibm_emac_core.c +++ /dev/null @@ -1,2263 +0,0 @@ -/* - * drivers/net/ibm_emac/ibm_emac_core.c - * - * Driver for PowerPC 4xx on-chip ethernet controller. - * - * Copyright (c) 2004, 2005 Zultys Technologies. - * Eugene Surovegin <eugene.surovegin@zultys.com> or <ebs@ebshome.net> - * - * Based on original work by - * Matt Porter <mporter@kernel.crashing.org> - * (c) 2003 Benjamin Herrenschmidt <benh@kernel.crashing.org> - * Armin Kuster <akuster@mvista.com> - * Johnnie Peters <jpeters@mvista.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - */ - -#include <linux/module.h> -#include <linux/kernel.h> -#include <linux/string.h> -#include <linux/errno.h> -#include <linux/interrupt.h> -#include <linux/delay.h> -#include <linux/init.h> -#include <linux/types.h> -#include <linux/netdevice.h> -#include <linux/etherdevice.h> -#include <linux/skbuff.h> -#include <linux/crc32.h> -#include <linux/ethtool.h> -#include <linux/mii.h> -#include <linux/bitops.h> - -#include <asm/processor.h> -#include <asm/io.h> -#include <asm/dma.h> -#include <asm/uaccess.h> -#include <asm/ocp.h> - -#include "ibm_emac_core.h" -#include "ibm_emac_debug.h" - -/* - * Lack of dma_unmap_???? calls is intentional. - * - * API-correct usage requires additional support state information to be - * maintained for every RX and TX buffer descriptor (BD). Unfortunately, due to - * EMAC design (e.g. TX buffer passed from network stack can be split into - * several BDs, dma_map_single/dma_map_page can be used to map particular BD), - * maintaining such information will add additional overhead. - * Current DMA API implementation for 4xx processors only ensures cache coherency - * and dma_unmap_???? routines are empty and are likely to stay this way. - * I decided to omit dma_unmap_??? calls because I don't want to add additional - * complexity just for the sake of following some abstract API, when it doesn't - * add any real benefit to the driver. I understand that this decision maybe - * controversial, but I really tried to make code API-correct and efficient - * at the same time and didn't come up with code I liked :(. --ebs - */ - -#define DRV_NAME "emac" -#define DRV_VERSION "3.54" -#define DRV_DESC "PPC 4xx OCP EMAC driver" - -MODULE_DESCRIPTION(DRV_DESC); -MODULE_AUTHOR - ("Eugene Surovegin <eugene.surovegin@zultys.com> or <ebs@ebshome.net>"); -MODULE_LICENSE("GPL"); - -/* minimum number of free TX descriptors required to wake up TX process */ -#define EMAC_TX_WAKEUP_THRESH (NUM_TX_BUFF / 4) - -/* If packet size is less than this number, we allocate small skb and copy packet - * contents into it instead of just sending original big skb up - */ -#define EMAC_RX_COPY_THRESH CONFIG_IBM_EMAC_RX_COPY_THRESHOLD - -/* Since multiple EMACs share MDIO lines in various ways, we need - * to avoid re-using the same PHY ID in cases where the arch didn't - * setup precise phy_map entries - */ -static u32 busy_phy_map; - -#if defined(CONFIG_IBM_EMAC_PHY_RX_CLK_FIX) && \ - (defined(CONFIG_405EP) || defined(CONFIG_440EP) || defined(CONFIG_440GR)) -/* 405EP has "EMAC to PHY Control Register" (CPC0_EPCTL) which can help us - * with PHY RX clock problem. - * 440EP/440GR has more sane SDR0_MFR register implementation than 440GX, which - * also allows controlling each EMAC clock - */ -static inline void EMAC_RX_CLK_TX(int idx) -{ - unsigned long flags; - local_irq_save(flags); - -#if defined(CONFIG_405EP) - mtdcr(0xf3, mfdcr(0xf3) | (1 << idx)); -#else /* CONFIG_440EP || CONFIG_440GR */ - SDR_WRITE(DCRN_SDR_MFR, SDR_READ(DCRN_SDR_MFR) | (0x08000000 >> idx)); -#endif - - local_irq_restore(flags); -} - -static inline void EMAC_RX_CLK_DEFAULT(int idx) -{ - unsigned long flags; - local_irq_save(flags); - -#if defined(CONFIG_405EP) - mtdcr(0xf3, mfdcr(0xf3) & ~(1 << idx)); -#else /* CONFIG_440EP */ - SDR_WRITE(DCRN_SDR_MFR, SDR_READ(DCRN_SDR_MFR) & ~(0x08000000 >> idx)); -#endif - - local_irq_restore(flags); -} -#else -#define EMAC_RX_CLK_TX(idx) ((void)0) -#define EMAC_RX_CLK_DEFAULT(idx) ((void)0) -#endif - -#if defined(CONFIG_IBM_EMAC_PHY_RX_CLK_FIX) && defined(CONFIG_440GX) -/* We can switch Ethernet clock to the internal source through SDR0_MFR[ECS], - * unfortunately this is less flexible than 440EP case, because it's a global - * setting for all EMACs, therefore we do this clock trick only during probe. - */ -#define EMAC_CLK_INTERNAL SDR_WRITE(DCRN_SDR_MFR, \ - SDR_READ(DCRN_SDR_MFR) | 0x08000000) -#define EMAC_CLK_EXTERNAL SDR_WRITE(DCRN_SDR_MFR, \ - SDR_READ(DCRN_SDR_MFR) & ~0x08000000) -#else -#define EMAC_CLK_INTERNAL ((void)0) -#define EMAC_CLK_EXTERNAL ((void)0) -#endif - -/* I don't want to litter system log with timeout errors - * when we have brain-damaged PHY. - */ -static inline void emac_report_timeout_error(struct ocp_enet_private *dev, - const char *error) -{ -#if defined(CONFIG_IBM_EMAC_PHY_RX_CLK_FIX) - DBG("%d: %s" NL, dev->def->index, error); -#else - if (net_ratelimit()) - printk(KERN_ERR "emac%d: %s\n", dev->def->index, error); -#endif -} - -/* PHY polling intervals */ -#define PHY_POLL_LINK_ON HZ -#define PHY_POLL_LINK_OFF (HZ / 5) - -/* Graceful stop timeouts in us. - * We should allow up to 1 frame time (full-duplex, ignoring collisions) - */ -#define STOP_TIMEOUT_10 1230 -#define STOP_TIMEOUT_100 124 -#define STOP_TIMEOUT_1000 13 -#define STOP_TIMEOUT_1000_JUMBO 73 - -/* Please, keep in sync with struct ibm_emac_stats/ibm_emac_error_stats */ -static const char emac_stats_keys[EMAC_ETHTOOL_STATS_COUNT][ETH_GSTRING_LEN] = { - "rx_packets", "rx_bytes", "tx_packets", "tx_bytes", "rx_packets_csum", - "tx_packets_csum", "tx_undo", "rx_dropped_stack", "rx_dropped_oom", - "rx_dropped_error", "rx_dropped_resize", "rx_dropped_mtu", - "rx_stopped", "rx_bd_errors", "rx_bd_overrun", "rx_bd_bad_packet", - "rx_bd_runt_packet", "rx_bd_short_event", "rx_bd_alignment_error", - "rx_bd_bad_fcs", "rx_bd_packet_too_long", "rx_bd_out_of_range", - "rx_bd_in_range", "rx_parity", "rx_fifo_overrun", "rx_overrun", - "rx_bad_packet", "rx_runt_packet", "rx_short_event", - "rx_alignment_error", "rx_bad_fcs", "rx_packet_too_long", - "rx_out_of_range", "rx_in_range", "tx_dropped", "tx_bd_errors", - "tx_bd_bad_fcs", "tx_bd_carrier_loss", "tx_bd_excessive_deferral", - "tx_bd_excessive_collisions", "tx_bd_late_collision", - "tx_bd_multple_collisions", "tx_bd_single_collision", - "tx_bd_underrun", "tx_bd_sqe", "tx_parity", "tx_underrun", "tx_sqe", - "tx_errors" -}; - -static irqreturn_t emac_irq(int irq, void *dev_instance); -static void emac_clean_tx_ring(struct ocp_enet_private *dev); - -static inline int emac_phy_supports_gige(int phy_mode) -{ - return phy_mode == PHY_MODE_GMII || - phy_mode == PHY_MODE_RGMII || - phy_mode == PHY_MODE_TBI || - phy_mode == PHY_MODE_RTBI; -} - -static inline int emac_phy_gpcs(int phy_mode) -{ - return phy_mode == PHY_MODE_TBI || - phy_mode == PHY_MODE_RTBI; -} - -static inline void emac_tx_enable(struct ocp_enet_private *dev) -{ - struct emac_regs __iomem *p = dev->emacp; - unsigned long flags; - u32 r; - - local_irq_save(flags); - - DBG("%d: tx_enable" NL, dev->def->index); - - r = in_be32(&p->mr0); - if (!(r & EMAC_MR0_TXE)) - out_be32(&p->mr0, r | EMAC_MR0_TXE); - local_irq_restore(flags); -} - -static void emac_tx_disable(struct ocp_enet_private *dev) -{ - struct emac_regs __iomem *p = dev->emacp; - unsigned long flags; - u32 r; - - local_irq_save(flags); - - DBG("%d: tx_disable" NL, dev->def->index); - - r = in_be32(&p->mr0); - if (r & EMAC_MR0_TXE) { - int n = dev->stop_timeout; - out_be32(&p->mr0, r & ~EMAC_MR0_TXE); - while (!(in_be32(&p->mr0) & EMAC_MR0_TXI) && n) { - udelay(1); - --n; - } - if (unlikely(!n)) - emac_report_timeout_error(dev, "TX disable timeout"); - } - local_irq_restore(flags); -} - -static void emac_rx_enable(struct ocp_enet_private *dev) -{ - struct emac_regs __iomem *p = dev->emacp; - unsigned long flags; - u32 r; - - local_irq_save(flags); - if (unlikely(dev->commac.rx_stopped)) - goto out; - - DBG("%d: rx_enable" NL, dev->def->index); - - r = in_be32(&p->mr0); - if (!(r & EMAC_MR0_RXE)) { - if (unlikely(!(r & EMAC_MR0_RXI))) { - /* Wait if previous async disable is still in progress */ - int n = dev->stop_timeout; - while (!(r = in_be32(&p->mr0) & EMAC_MR0_RXI) && n) { - udelay(1); - --n; - } - if (unlikely(!n)) - emac_report_timeout_error(dev, - "RX disable timeout"); - } - out_be32(&p->mr0, r | EMAC_MR0_RXE); - } - out: - local_irq_restore(flags); -} - -static void emac_rx_disable(struct ocp_enet_private *dev) -{ - struct emac_regs __iomem *p = dev->emacp; - unsigned long flags; - u32 r; - - local_irq_save(flags); - - DBG("%d: rx_disable" NL, dev->def->index); - - r = in_be32(&p->mr0); - if (r & EMAC_MR0_RXE) { - int n = dev->stop_timeout; - out_be32(&p->mr0, r & ~EMAC_MR0_RXE); - while (!(in_be32(&p->mr0) & EMAC_MR0_RXI) && n) { - udelay(1); - --n; - } - if (unlikely(!n)) - emac_report_timeout_error(dev, "RX disable timeout"); - } - local_irq_restore(flags); -} - -static inline void emac_rx_disable_async(struct ocp_enet_private *dev) -{ - struct emac_regs __iomem *p = dev->emacp; - unsigned long flags; - u32 r; - - local_irq_save(flags); - - DBG("%d: rx_disable_async" NL, dev->def->index); - - r = in_be32(&p->mr0); - if (r & EMAC_MR0_RXE) - out_be32(&p->mr0, r & ~EMAC_MR0_RXE); - local_irq_restore(flags); -} - -static int emac_reset(struct ocp_enet_private *dev) -{ - struct emac_regs __iomem *p = dev->emacp; - unsigned long flags; - int n = 20; - - DBG("%d: reset" NL, dev->def->index); - - local_irq_save(flags); - - if (!dev->reset_failed) { - /* 40x erratum suggests stopping RX channel before reset, - * we stop TX as well - */ - emac_rx_disable(dev); - emac_tx_disable(dev); - } - - out_be32(&p->mr0, EMAC_MR0_SRST); - while ((in_be32(&p->mr0) & EMAC_MR0_SRST) && n) - --n; - local_irq_restore(flags); - - if (n) { - dev->reset_failed = 0; - return 0; - } else { - emac_report_timeout_error(dev, "reset timeout"); - dev->reset_failed = 1; - return -ETIMEDOUT; - } -} - -static void emac_hash_mc(struct ocp_enet_private *dev) -{ - struct emac_regs __iomem *p = dev->emacp; - u16 gaht[4] = { 0 }; - struct dev_mc_list *dmi; - - DBG("%d: hash_mc %d" NL, dev->def->index, dev->ndev->mc_count); - - for (dmi = dev->ndev->mc_list; dmi; dmi = dmi->next) { - int bit; - DECLARE_MAC_BUF(mac); - DBG2("%d: mc %s" NL, - dev->def->index, print_mac(mac, dmi->dmi_addr)); - - bit = 63 - (ether_crc(ETH_ALEN, dmi->dmi_addr) >> 26); - gaht[bit >> 4] |= 0x8000 >> (bit & 0x0f); - } - out_be32(&p->gaht1, gaht[0]); - out_be32(&p->gaht2, gaht[1]); - out_be32(&p->gaht3, gaht[2]); - out_be32(&p->gaht4, gaht[3]); -} - -static inline u32 emac_iff2rmr(struct net_device *ndev) -{ - u32 r = EMAC_RMR_SP | EMAC_RMR_SFCS | EMAC_RMR_IAE | EMAC_RMR_BAE | - EMAC_RMR_BASE; - - if (ndev->flags & IFF_PROMISC) - r |= EMAC_RMR_PME; - else if (ndev->flags & IFF_ALLMULTI || ndev->mc_count > 32) - r |= EMAC_RMR_PMME; - else if (ndev->mc_count > 0) - r |= EMAC_RMR_MAE; - - return r; -} - -static inline int emac_opb_mhz(void) -{ - return (ocp_sys_info.opb_bus_freq + 500000) / 1000000; -} - -/* BHs disabled */ -static int emac_configure(struct ocp_enet_private *dev) -{ - struct emac_regs __iomem *p = dev->emacp; - struct net_device *ndev = dev->ndev; - int gige; - u32 r; - - DBG("%d: configure" NL, dev->def->index); - - if (emac_reset(dev) < 0) - return -ETIMEDOUT; - - tah_reset(dev->tah_dev); - - /* Mode register */ - r = EMAC_MR1_BASE(emac_opb_mhz()) | EMAC_MR1_VLE | EMAC_MR1_IST; - if (dev->phy.duplex == DUPLEX_FULL) - r |= EMAC_MR1_FDE | EMAC_MR1_MWSW_001; - dev->stop_timeout = STOP_TIMEOUT_10; - switch (dev->phy.speed) { - case SPEED_1000: - if (emac_phy_gpcs(dev->phy.mode)) { - r |= EMAC_MR1_MF_1000GPCS | - EMAC_MR1_MF_IPPA(dev->phy.address); - - /* Put some arbitrary OUI, Manuf & Rev IDs so we can - * identify this GPCS PHY later. - */ - out_be32(&p->ipcr, 0xdeadbeef); - } else - r |= EMAC_MR1_MF_1000; - r |= EMAC_MR1_RFS_16K; - gige = 1; - - if (dev->ndev->mtu > ETH_DATA_LEN) { - r |= EMAC_MR1_JPSM; - dev->stop_timeout = STOP_TIMEOUT_1000_JUMBO; - } else - dev->stop_timeout = STOP_TIMEOUT_1000; - break; - case SPEED_100: - r |= EMAC_MR1_MF_100; - dev->stop_timeout = STOP_TIMEOUT_100; - /* Fall through */ - default: - r |= EMAC_MR1_RFS_4K; - gige = 0; - break; - } - - if (dev->rgmii_dev) - rgmii_set_speed(dev->rgmii_dev, dev->rgmii_input, - dev->phy.speed); - else - zmii_set_speed(dev->zmii_dev, dev->zmii_input, dev->phy.speed); - -#if !defined(CONFIG_40x) - /* on 40x erratum forces us to NOT use integrated flow control, - * let's hope it works on 44x ;) - */ - if (dev->phy.duplex == DUPLEX_FULL) { - if (dev->phy.pause) - r |= EMAC_MR1_EIFC | EMAC_MR1_APP; - else if (dev->phy.asym_pause) - r |= EMAC_MR1_APP; - } -#endif - out_be32(&p->mr1, r); - - /* Set individual MAC address */ - out_be32(&p->iahr, (ndev->dev_addr[0] << 8) | ndev->dev_addr[1]); - out_be32(&p->ialr, (ndev->dev_addr[2] << 24) | - (ndev->dev_addr[3] << 16) | (ndev->dev_addr[4] << 8) | - ndev->dev_addr[5]); - - /* VLAN Tag Protocol ID */ - out_be32(&p->vtpid, 0x8100); - - /* Receive mode register */ - r = emac_iff2rmr(ndev); - if (r & EMAC_RMR_MAE) - emac_hash_mc(dev); - out_be32(&p->rmr, r); - - /* FIFOs thresholds */ - r = EMAC_TMR1((EMAC_MAL_BURST_SIZE / EMAC_FIFO_ENTRY_SIZE) + 1, - EMAC_TX_FIFO_SIZE / 2 / EMAC_FIFO_ENTRY_SIZE); - out_be32(&p->tmr1, r); - out_be32(&p->trtr, EMAC_TRTR(EMAC_TX_FIFO_SIZE / 2)); - - /* PAUSE frame is sent when RX FIFO reaches its high-water mark, - there should be still enough space in FIFO to allow the our link - partner time to process this frame and also time to send PAUSE - frame itself. - - Here is the worst case scenario for the RX FIFO "headroom" - (from "The Switch Book") (100Mbps, without preamble, inter-frame gap): - - 1) One maximum-length frame on TX 1522 bytes - 2) One PAUSE frame time 64 bytes - 3) PAUSE frame decode time allowance 64 bytes - 4) One maximum-length frame on RX 1522 bytes - 5) Round-trip propagation delay of the link (100Mb) 15 bytes - ---------- - 3187 bytes - - I chose to set high-water mark to RX_FIFO_SIZE / 4 (1024 bytes) - low-water mark to RX_FIFO_SIZE / 8 (512 bytes) - */ - r = EMAC_RWMR(EMAC_RX_FIFO_SIZE(gige) / 8 / EMAC_FIFO_ENTRY_SIZE, - EMAC_RX_FIFO_SIZE(gige) / 4 / EMAC_FIFO_ENTRY_SIZE); - out_be32(&p->rwmr, r); - - /* Set PAUSE timer to the maximum */ - out_be32(&p->ptr, 0xffff); - - /* IRQ sources */ - out_be32(&p->iser, EMAC_ISR_TXPE | EMAC_ISR_RXPE | /* EMAC_ISR_TXUE | - EMAC_ISR_RXOE | */ EMAC_ISR_OVR | EMAC_ISR_BP | EMAC_ISR_SE | - EMAC_ISR_ALE | EMAC_ISR_BFCS | EMAC_ISR_PTLE | EMAC_ISR_ORE | - EMAC_ISR_IRE | EMAC_ISR_TE); - - /* We need to take GPCS PHY out of isolate mode after EMAC reset */ - if (emac_phy_gpcs(dev->phy.mode)) - mii_reset_phy(&dev->phy); - - return 0; -} - -/* BHs disabled */ -static void emac_reinitialize(struct ocp_enet_private *dev) -{ - DBG("%d: reinitialize" NL, dev->def->index); - - if (!emac_configure(dev)) { - emac_tx_enable(dev); - emac_rx_enable(dev); - } -} - -/* BHs disabled */ -static void emac_full_tx_reset(struct net_device *ndev) -{ - struct ocp_enet_private *dev = ndev->priv; - struct ocp_func_emac_data *emacdata = dev->def->additions; - - DBG("%d: full_tx_reset" NL, dev->def->index); - - emac_tx_disable(dev); - mal_disable_tx_channel(dev->mal, emacdata->mal_tx_chan); - emac_clean_tx_ring(dev); - dev->tx_cnt = dev->tx_slot = dev->ack_slot = 0; - - emac_configure(dev); - - mal_enable_tx_channel(dev->mal, emacdata->mal_tx_chan); - emac_tx_enable(dev); - emac_rx_enable(dev); - - netif_wake_queue(ndev); -} - -static int __emac_mdio_read(struct ocp_enet_private *dev, u8 id, u8 reg) -{ - struct emac_regs __iomem *p = dev->emacp; - u32 r; - int n; - - DBG2("%d: mdio_read(%02x,%02x)" NL, dev->def->index, id, reg); - - /* Enable proper MDIO port */ - zmii_enable_mdio(dev->zmii_dev, dev->zmii_input); - - /* Wait for management interface to become idle */ - n = 10; - while (!emac_phy_done(in_be32(&p->stacr))) { - udelay(1); - if (!--n) - goto to; - } - - /* Issue read command */ - out_be32(&p->stacr, - EMAC_STACR_BASE(emac_opb_mhz()) | EMAC_STACR_STAC_READ | - (reg & EMAC_STACR_PRA_MASK) - | ((id & EMAC_STACR_PCDA_MASK) << EMAC_STACR_PCDA_SHIFT) - | EMAC_STACR_START); - - /* Wait for read to complete */ - n = 100; - while (!emac_phy_done(r = in_be32(&p->stacr))) { - udelay(1); - if (!--n) - goto to; - } - - if (unlikely(r & EMAC_STACR_PHYE)) { - DBG("%d: mdio_read(%02x, %02x) failed" NL, dev->def->index, - id, reg); - return -EREMOTEIO; - } - - r = ((r >> EMAC_STACR_PHYD_SHIFT) & EMAC_STACR_PHYD_MASK); - DBG2("%d: mdio_read -> %04x" NL, dev->def->index, r); - return r; - to: - DBG("%d: MII management interface timeout (read)" NL, dev->def->index); - return -ETIMEDOUT; -} - -static void __emac_mdio_write(struct ocp_enet_private *dev, u8 id, u8 reg, - u16 val) -{ - struct emac_regs __iomem *p = dev->emacp; - int n; - - DBG2("%d: mdio_write(%02x,%02x,%04x)" NL, dev->def->index, id, reg, - val); - - /* Enable proper MDIO port */ - zmii_enable_mdio(dev->zmii_dev, dev->zmii_input); - - /* Wait for management interface to be idle */ - n = 10; - while (!emac_phy_done(in_be32(&p->stacr))) { - udelay(1); - if (!--n) - goto to; - } - - /* Issue write command */ - out_be32(&p->stacr, - EMAC_STACR_BASE(emac_opb_mhz()) | EMAC_STACR_STAC_WRITE | - (reg & EMAC_STACR_PRA_MASK) | - ((id & EMAC_STACR_PCDA_MASK) << EMAC_STACR_PCDA_SHIFT) | - (val << EMAC_STACR_PHYD_SHIFT) | EMAC_STACR_START); - - /* Wait for write to complete */ - n = 100; - while (!emac_phy_done(in_be32(&p->stacr))) { - udelay(1); - if (!--n) - goto to; - } - return; - to: - DBG("%d: MII management interface timeout (write)" NL, dev->def->index); -} - -static int emac_mdio_read(struct net_device *ndev, int id, int reg) -{ - struct ocp_enet_private *dev = ndev->priv; - int res; - - local_bh_disable(); - res = __emac_mdio_read(dev->mdio_dev ? dev->mdio_dev : dev, (u8) id, - (u8) reg); - local_bh_enable(); - return res; -} - -static void emac_mdio_write(struct net_device *ndev, int id, int reg, int val) -{ - struct ocp_enet_private *dev = ndev->priv; - - local_bh_disable(); - __emac_mdio_write(dev->mdio_dev ? dev->mdio_dev : dev, (u8) id, - (u8) reg, (u16) val); - local_bh_enable(); -} - -/* BHs disabled */ -static void emac_set_multicast_list(struct net_device *ndev) -{ - struct ocp_enet_private *dev = ndev->priv; - struct emac_regs __iomem *p = dev->emacp; - u32 rmr = emac_iff2rmr(ndev); - - DBG("%d: multicast %08x" NL, dev->def->index, rmr); - BUG_ON(!netif_running(dev->ndev)); - - /* I decided to relax register access rules here to avoid - * full EMAC reset. - * - * There is a real problem with EMAC4 core if we use MWSW_001 bit - * in MR1 register and do a full EMAC reset. - * One TX BD status update is delayed and, after EMAC reset, it - * never happens, resulting in TX hung (it'll be recovered by TX - * timeout handler eventually, but this is just gross). - * So we either have to do full TX reset or try to cheat here :) - * - * The only required change is to RX mode register, so I *think* all - * we need is just to stop RX channel. This seems to work on all - * tested SoCs. --ebs - */ - emac_rx_disable(dev); - if (rmr & EMAC_RMR_MAE) - emac_hash_mc(dev); - out_be32(&p->rmr, rmr); - emac_rx_enable(dev); -} - -/* BHs disabled */ -static int emac_resize_rx_ring(struct ocp_enet_private *dev, int new_mtu) -{ - struct ocp_func_emac_data *emacdata = dev->def->additions; - int rx_sync_size = emac_rx_sync_size(new_mtu); - int rx_skb_size = emac_rx_skb_size(new_mtu); - int i, ret = 0; - - emac_rx_disable(dev); - mal_disable_rx_channel(dev->mal, emacdata->mal_rx_chan); - - if (dev->rx_sg_skb) { - ++dev->estats.rx_dropped_resize; - dev_kfree_skb(dev->rx_sg_skb); - dev->rx_sg_skb = NULL; - } - - /* Make a first pass over RX ring and mark BDs ready, dropping - * non-processed packets on the way. We need this as a separate pass - * to simplify error recovery in the case of allocation failure later. - */ - for (i = 0; i < NUM_RX_BUFF; ++i) { - if (dev->rx_desc[i].ctrl & MAL_RX_CTRL_FIRST) - ++dev->estats.rx_dropped_resize; - - dev->rx_desc[i].data_len = 0; - dev->rx_desc[i].ctrl = MAL_RX_CTRL_EMPTY | - (i == (NUM_RX_BUFF - 1) ? MAL_RX_CTRL_WRAP : 0); - } - - /* Reallocate RX ring only if bigger skb buffers are required */ - if (rx_skb_size <= dev->rx_skb_size) - goto skip; - - /* Second pass, allocate new skbs */ - for (i = 0; i < NUM_RX_BUFF; ++i) { - struct sk_buff *skb = alloc_skb(rx_skb_size, GFP_ATOMIC); - if (!skb) { - ret = -ENOMEM; - goto oom; - } - - BUG_ON(!dev->rx_skb[i]); - dev_kfree_skb(dev->rx_skb[i]); - - skb_reserve(skb, EMAC_RX_SKB_HEADROOM + 2); - dev->rx_desc[i].data_ptr = - dma_map_single(dev->ldev, skb->data - 2, rx_sync_size, - DMA_FROM_DEVICE) + 2; - dev->rx_skb[i] = skb; - } - skip: - /* Check if we need to change "Jumbo" bit in MR1 */ - if ((new_mtu > ETH_DATA_LEN) ^ (dev->ndev->mtu > ETH_DATA_LEN)) { - /* This is to prevent starting RX channel in emac_rx_enable() */ - dev->commac.rx_stopped = 1; - - dev->ndev->mtu = new_mtu; - emac_full_tx_reset(dev->ndev); - } - - mal_set_rcbs(dev->mal, emacdata->mal_rx_chan, emac_rx_size(new_mtu)); - oom: - /* Restart RX */ - dev->commac.rx_stopped = dev->rx_slot = 0; - mal_enable_rx_channel(dev->mal, emacdata->mal_rx_chan); - emac_rx_enable(dev); - - return ret; -} - -/* Process ctx, rtnl_lock semaphore */ -static int emac_change_mtu(struct net_device *ndev, int new_mtu) -{ - struct ocp_enet_private *dev = ndev->priv; - int ret = 0; - - if (new_mtu < EMAC_MIN_MTU || new_mtu > EMAC_MAX_MTU) - return -EINVAL; - - DBG("%d: change_mtu(%d)" NL, dev->def->index, new_mtu); - - local_bh_disable(); - if (netif_running(ndev)) { - /* Check if we really need to reinitalize RX ring */ - if (emac_rx_skb_size(ndev->mtu) != emac_rx_skb_size(new_mtu)) - ret = emac_resize_rx_ring(dev, new_mtu); - } - - if (!ret) { - ndev->mtu = new_mtu; - dev->rx_skb_size = emac_rx_skb_size(new_mtu); - dev->rx_sync_size = emac_rx_sync_size(new_mtu); - } - local_bh_enable(); - - return ret; -} - -static void emac_clean_tx_ring(struct ocp_enet_private *dev) -{ - int i; - for (i = 0; i < NUM_TX_BUFF; ++i) { - if (dev->tx_skb[i]) { - dev_kfree_skb(dev->tx_skb[i]); - dev->tx_skb[i] = NULL; - if (dev->tx_desc[i].ctrl & MAL_TX_CTRL_READY) - ++dev->estats.tx_dropped; - } - dev->tx_desc[i].ctrl = 0; - dev->tx_desc[i].data_ptr = 0; - } -} - -static void emac_clean_rx_ring(struct ocp_enet_private *dev) -{ - int i; - for (i = 0; i < NUM_RX_BUFF; ++i) - if (dev->rx_skb[i]) { - dev->rx_desc[i].ctrl = 0; - dev_kfree_skb(dev->rx_skb[i]); - dev->rx_skb[i] = NULL; - dev->rx_desc[i].data_ptr = 0; - } - - if (dev->rx_sg_skb) { - dev_kfree_skb(dev->rx_sg_skb); - dev->rx_sg_skb = NULL; - } -} - -static inline int emac_alloc_rx_skb(struct ocp_enet_private *dev, int slot, - gfp_t flags) -{ - struct sk_buff *skb = alloc_skb(dev->rx_skb_size, flags); - if (unlikely(!skb)) - return -ENOMEM; - - dev->rx_skb[slot] = skb; - dev->rx_desc[slot].data_len = 0; - - skb_reserve(skb, EMAC_RX_SKB_HEADROOM + 2); - dev->rx_desc[slot].data_ptr = - dma_map_single(dev->ldev, skb->data - 2, dev->rx_sync_size, - DMA_FROM_DEVICE) + 2; - barrier(); - dev->rx_desc[slot].ctrl = MAL_RX_CTRL_EMPTY | - (slot == (NUM_RX_BUFF - 1) ? MAL_RX_CTRL_WRAP : 0); - - return 0; -} - -static void emac_print_link_status(struct ocp_enet_private *dev) -{ - if (netif_carrier_ok(dev->ndev)) - printk(KERN_INFO "%s: link is up, %d %s%s\n", - dev->ndev->name, dev->phy.speed, - dev->phy.duplex == DUPLEX_FULL ? "FDX" : "HDX", - dev->phy.pause ? ", pause enabled" : - dev->phy.asym_pause ? ", assymetric pause enabled" : ""); - else - printk(KERN_INFO "%s: link is down\n", dev->ndev->name); -} - -/* Process ctx, rtnl_lock semaphore */ -static int emac_open(struct net_device *ndev) -{ - struct ocp_enet_private *dev = ndev->priv; - struct ocp_func_emac_data *emacdata = dev->def->additions; - int err, i; - - DBG("%d: open" NL, dev->def->index); - - /* Setup error IRQ handler */ - err = request_irq(dev->def->irq, emac_irq, 0, "EMAC", dev); - if (err) { - printk(KERN_ERR "%s: failed to request IRQ %d\n", - ndev->name, dev->def->irq); - return err; - } - - /* Allocate RX ring */ - for (i = 0; i < NUM_RX_BUFF; ++i) - if (emac_alloc_rx_skb(dev, i, GFP_KERNEL)) { - printk(KERN_ERR "%s: failed to allocate RX ring\n", - ndev->name); - goto oom; - } - - local_bh_disable(); - dev->tx_cnt = dev->tx_slot = dev->ack_slot = dev->rx_slot = - dev->commac.rx_stopped = 0; - dev->rx_sg_skb = NULL; - - if (dev->phy.address >= 0) { - int link_poll_interval; - if (dev->phy.def->ops->poll_link(&dev->phy)) { - dev->phy.def->ops->read_link(&dev->phy); - EMAC_RX_CLK_DEFAULT(dev->def->index); - netif_carrier_on(dev->ndev); - link_poll_interval = PHY_POLL_LINK_ON; - } else { - EMAC_RX_CLK_TX(dev->def->index); - netif_carrier_off(dev->ndev); - link_poll_interval = PHY_POLL_LINK_OFF; - } - mod_timer(&dev->link_timer, jiffies + link_poll_interval); - emac_print_link_status(dev); - } else - netif_carrier_on(dev->ndev); - - emac_configure(dev); - mal_poll_add(dev->mal, &dev->commac); - mal_enable_tx_channel(dev->mal, emacdata->mal_tx_chan); - mal_set_rcbs(dev->mal, emacdata->mal_rx_chan, emac_rx_size(ndev->mtu)); - mal_enable_rx_channel(dev->mal, emacdata->mal_rx_chan); - emac_tx_enable(dev); - emac_rx_enable(dev); - netif_start_queue(ndev); - local_bh_enable(); - - return 0; - oom: - emac_clean_rx_ring(dev); - free_irq(dev->def->irq, dev); - return -ENOMEM; -} - -/* BHs disabled */ -static int emac_link_differs(struct ocp_enet_private *dev) -{ - u32 r = in_be32(&dev->emacp->mr1); - - int duplex = r & EMAC_MR1_FDE ? DUPLEX_FULL : DUPLEX_HALF; - int speed, pause, asym_pause; - - if (r & EMAC_MR1_MF_1000) - speed = SPEED_1000; - else if (r & EMAC_MR1_MF_100) - speed = SPEED_100; - else - speed = SPEED_10; - - switch (r & (EMAC_MR1_EIFC | EMAC_MR1_APP)) { - case (EMAC_MR1_EIFC | EMAC_MR1_APP): - pause = 1; - asym_pause = 0; - break; - case EMAC_MR1_APP: - pause = 0; - asym_pause = 1; - break; - default: - pause = asym_pause = 0; - } - return speed != dev->phy.speed || duplex != dev->phy.duplex || - pause != dev->phy.pause || asym_pause != dev->phy.asym_pause; -} - -/* BHs disabled */ -static void emac_link_timer(unsigned long data) -{ - struct ocp_enet_private *dev = (struct ocp_enet_private *)data; - int link_poll_interval; - - DBG2("%d: link timer" NL, dev->def->index); - - if (dev->phy.def->ops->poll_link(&dev->phy)) { - if (!netif_carrier_ok(dev->ndev)) { - EMAC_RX_CLK_DEFAULT(dev->def->index); - - /* Get new link parameters */ - dev->phy.def->ops->read_link(&dev->phy); - - if (dev->tah_dev || emac_link_differs(dev)) - emac_full_tx_reset(dev->ndev); - - netif_carrier_on(dev->ndev); - emac_print_link_status(dev); - } - link_poll_interval = PHY_POLL_LINK_ON; - } else { - if (netif_carrier_ok(dev->ndev)) { - EMAC_RX_CLK_TX(dev->def->index); -#if defined(CONFIG_IBM_EMAC_PHY_RX_CLK_FIX) - emac_reinitialize(dev); -#endif - netif_carrier_off(dev->ndev); - emac_print_link_status(dev); - } - - /* Retry reset if the previous attempt failed. - * This is needed mostly for CONFIG_IBM_EMAC_PHY_RX_CLK_FIX - * case, but I left it here because it shouldn't trigger for - * sane PHYs anyway. - */ - if (unlikely(dev->reset_failed)) - emac_reinitialize(dev); - - link_poll_interval = PHY_POLL_LINK_OFF; - } - mod_timer(&dev->link_timer, jiffies + link_poll_interval); -} - -/* BHs disabled */ -static void emac_force_link_update(struct ocp_enet_private *dev) -{ - netif_carrier_off(dev->ndev); - if (timer_pending(&dev->link_timer)) - mod_timer(&dev->link_timer, jiffies + PHY_POLL_LINK_OFF); -} - -/* Process ctx, rtnl_lock semaphore */ -static int emac_close(struct net_device *ndev) -{ - struct ocp_enet_private *dev = ndev->priv; - struct ocp_func_emac_data *emacdata = dev->def->additions; - - DBG("%d: close" NL, dev->def->index); - - local_bh_disable(); - - if (dev->phy.address >= 0) - del_timer_sync(&dev->link_timer); - - netif_stop_queue(ndev); - emac_rx_disable(dev); - emac_tx_disable(dev); - mal_disable_rx_channel(dev->mal, emacdata->mal_rx_chan); - mal_disable_tx_channel(dev->mal, emacdata->mal_tx_chan); - mal_poll_del(dev->mal, &dev->commac); - local_bh_enable(); - - emac_clean_tx_ring(dev); - emac_clean_rx_ring(dev); - free_irq(dev->def->irq, dev); - - return 0; -} - -static inline u16 emac_tx_csum(struct ocp_enet_private *dev, - struct sk_buff *skb) -{ -#if defined(CONFIG_IBM_EMAC_TAH) - if (skb->ip_summed == CHECKSUM_PARTIAL) { - ++dev->stats.tx_packets_csum; - return EMAC_TX_CTRL_TAH_CSUM; - } -#endif - return 0; -} - -static inline int emac_xmit_finish(struct ocp_enet_private *dev, int len) -{ - struct emac_regs __iomem *p = dev->emacp; - struct net_device *ndev = dev->ndev; - - /* Send the packet out */ - out_be32(&p->tmr0, EMAC_TMR0_XMIT); - - if (unlikely(++dev->tx_cnt == NUM_TX_BUFF)) { - netif_stop_queue(ndev); - DBG2("%d: stopped TX queue" NL, dev->def->index); - } - - ndev->trans_start = jiffies; - ++dev->stats.tx_packets; - dev->stats.tx_bytes += len; - - return 0; -} - -/* BHs disabled */ -static int emac_start_xmit(struct sk_buff *skb, struct net_device *ndev) -{ - struct ocp_enet_private *dev = ndev->priv; - unsigned int len = skb->len; - int slot; - - u16 ctrl = EMAC_TX_CTRL_GFCS | EMAC_TX_CTRL_GP | MAL_TX_CTRL_READY | - MAL_TX_CTRL_LAST | emac_tx_csum(dev, skb); - - slot = dev->tx_slot++; - if (dev->tx_slot == NUM_TX_BUFF) { - dev->tx_slot = 0; - ctrl |= MAL_TX_CTRL_WRAP; - } - - DBG2("%d: xmit(%u) %d" NL, dev->def->index, len, slot); - - dev->tx_skb[slot] = skb; - dev->tx_desc[slot].data_ptr = dma_map_single(dev->ldev, skb->data, len, - DMA_TO_DEVICE); - dev->tx_desc[slot].data_len = (u16) len; - barrier(); - dev->tx_desc[slot].ctrl = ctrl; - - return emac_xmit_finish(dev, len); -} - -#if defined(CONFIG_IBM_EMAC_TAH) -static inline int emac_xmit_split(struct ocp_enet_private *dev, int slot, - u32 pd, int len, int last, u16 base_ctrl) -{ - while (1) { - u16 ctrl = base_ctrl; - int chunk = min(len, MAL_MAX_TX_SIZE); - len -= chunk; - - slot = (slot + 1) % NUM_TX_BUFF; - - if (last && !len) - ctrl |= MAL_TX_CTRL_LAST; - if (slot == NUM_TX_BUFF - 1) - ctrl |= MAL_TX_CTRL_WRAP; - - dev->tx_skb[slot] = NULL; - dev->tx_desc[slot].data_ptr = pd; - dev->tx_desc[slot].data_len = (u16) chunk; - dev->tx_desc[slot].ctrl = ctrl; - ++dev->tx_cnt; - - if (!len) - break; - - pd += chunk; - } - return slot; -} - -/* BHs disabled (SG version for TAH equipped EMACs) */ -static int emac_start_xmit_sg(struct sk_buff *skb, struct net_device *ndev) -{ - struct ocp_enet_private *dev = ndev->priv; - int nr_frags = skb_shinfo(skb)->nr_frags; - int len = skb->len, chunk; - int slot, i; - u16 ctrl; - u32 pd; - - /* This is common "fast" path */ - if (likely(!nr_frags && len <= MAL_MAX_TX_SIZE)) - return emac_start_xmit(skb, ndev); - - len -= skb->data_len; - - /* Note, this is only an *estimation*, we can still run out of empty - * slots because of the additional fragmentation into - * MAL_MAX_TX_SIZE-sized chunks - */ - if (unlikely(dev->tx_cnt + nr_frags + mal_tx_chunks(len) > NUM_TX_BUFF)) - goto stop_queue; - - ctrl = EMAC_TX_CTRL_GFCS | EMAC_TX_CTRL_GP | MAL_TX_CTRL_READY | - emac_tx_csum(dev, skb); - slot = dev->tx_slot; - - /* skb data */ - dev->tx_skb[slot] = NULL; - chunk = min(len, MAL_MAX_TX_SIZE); - dev->tx_desc[slot].data_ptr = pd = - dma_map_single(dev->ldev, skb->data, len, DMA_TO_DEVICE); - dev->tx_desc[slot].data_len = (u16) chunk; - len -= chunk; - if (unlikely(len)) - slot = emac_xmit_split(dev, slot, pd + chunk, len, !nr_frags, - ctrl); - /* skb fragments */ - for (i = 0; i < nr_frags; ++i) { - struct skb_frag_struct *frag = &skb_shinfo(skb)->frags[i]; - len = frag->size; - - if (unlikely(dev->tx_cnt + mal_tx_chunks(len) >= NUM_TX_BUFF)) - goto undo_frame; - - pd = dma_map_page(dev->ldev, frag->page, frag->page_offset, len, - DMA_TO_DEVICE); - - slot = emac_xmit_split(dev, slot, pd, len, i == nr_frags - 1, - ctrl); - } - - DBG2("%d: xmit_sg(%u) %d - %d" NL, dev->def->index, skb->len, - dev->tx_slot, slot); - - /* Attach skb to the last slot so we don't release it too early */ - dev->tx_skb[slot] = skb; - - /* Send the packet out */ - if (dev->tx_slot == NUM_TX_BUFF - 1) - ctrl |= MAL_TX_CTRL_WRAP; - barrier(); - dev->tx_desc[dev->tx_slot].ctrl = ctrl; - dev->tx_slot = (slot + 1) % NUM_TX_BUFF; - - return emac_xmit_finish(dev, skb->len); - - undo_frame: - /* Well, too bad. Our previous estimation was overly optimistic. - * Undo everything. - */ - while (slot != dev->tx_slot) { - dev->tx_desc[slot].ctrl = 0; - --dev->tx_cnt; - if (--slot < 0) - slot = NUM_TX_BUFF - 1; - } - ++dev->estats.tx_undo; - - stop_queue: - netif_stop_queue(ndev); - DBG2("%d: stopped TX queue" NL, dev->def->index); - return 1; -} -#else -# define emac_start_xmit_sg emac_start_xmit -#endif /* !defined(CONFIG_IBM_EMAC_TAH) */ - -/* BHs disabled */ -static void emac_parse_tx_error(struct ocp_enet_private *dev, u16 ctrl) -{ - struct ibm_emac_error_stats *st = &dev->estats; - DBG("%d: BD TX error %04x" NL, dev->def->index, ctrl); - - ++st->tx_bd_errors; - if (ctrl & EMAC_TX_ST_BFCS) - ++st->tx_bd_bad_fcs; - if (ctrl & EMAC_TX_ST_LCS) - ++st->tx_bd_carrier_loss; - if (ctrl & EMAC_TX_ST_ED) - ++st->tx_bd_excessive_deferral; - if (ctrl & EMAC_TX_ST_EC) - ++st->tx_bd_excessive_collisions; - if (ctrl & EMAC_TX_ST_LC) - ++st->tx_bd_late_collision; - if (ctrl & EMAC_TX_ST_MC) - ++st->tx_bd_multple_collisions; - if (ctrl & EMAC_TX_ST_SC) - ++st->tx_bd_single_collision; - if (ctrl & EMAC_TX_ST_UR) - ++st->tx_bd_underrun; - if (ctrl & EMAC_TX_ST_SQE) - ++st->tx_bd_sqe; -} - -static void emac_poll_tx(void *param) -{ - struct ocp_enet_private *dev = param; - DBG2("%d: poll_tx, %d %d" NL, dev->def->index, dev->tx_cnt, - dev->ack_slot); - - if (dev->tx_cnt) { - u16 ctrl; - int slot = dev->ack_slot, n = 0; - again: - ctrl = dev->tx_desc[slot].ctrl; - if (!(ctrl & MAL_TX_CTRL_READY)) { - struct sk_buff *skb = dev->tx_skb[slot]; - ++n; - - if (skb) { - dev_kfree_skb(skb); - dev->tx_skb[slot] = NULL; - } - slot = (slot + 1) % NUM_TX_BUFF; - - if (unlikely(EMAC_IS_BAD_TX(ctrl))) - emac_parse_tx_error(dev, ctrl); - - if (--dev->tx_cnt) - goto again; - } - if (n) { - dev->ack_slot = slot; - if (netif_queue_stopped(dev->ndev) && - dev->tx_cnt < EMAC_TX_WAKEUP_THRESH) - netif_wake_queue(dev->ndev); - - DBG2("%d: tx %d pkts" NL, dev->def->index, n); - } - } -} - -static inline void emac_recycle_rx_skb(struct ocp_enet_private *dev, int slot, - int len) -{ - struct sk_buff *skb = dev->rx_skb[slot]; - DBG2("%d: recycle %d %d" NL, dev->def->index, slot, len); - - if (len) - dma_map_single(dev->ldev, skb->data - 2, - EMAC_DMA_ALIGN(len + 2), DMA_FROM_DEVICE); - - dev->rx_desc[slot].data_len = 0; - barrier(); - dev->rx_desc[slot].ctrl = MAL_RX_CTRL_EMPTY | - (slot == (NUM_RX_BUFF - 1) ? MAL_RX_CTRL_WRAP : 0); -} - -static void emac_parse_rx_error(struct ocp_enet_private *dev, u16 ctrl) -{ - struct ibm_emac_error_stats *st = &dev->estats; - DBG("%d: BD RX error %04x" NL, dev->def->index, ctrl); - - ++st->rx_bd_errors; - if (ctrl & EMAC_RX_ST_OE) - ++st->rx_bd_overrun; - if (ctrl & EMAC_RX_ST_BP) - ++st->rx_bd_bad_packet; - if (ctrl & EMAC_RX_ST_RP) - ++st->rx_bd_runt_packet; - if (ctrl & EMAC_RX_ST_SE) - ++st->rx_bd_short_event; - if (ctrl & EMAC_RX_ST_AE) - ++st->rx_bd_alignment_error; - if (ctrl & EMAC_RX_ST_BFCS) - ++st->rx_bd_bad_fcs; - if (ctrl & EMAC_RX_ST_PTL) - ++st->rx_bd_packet_too_long; - if (ctrl & EMAC_RX_ST_ORE) - ++st->rx_bd_out_of_range; - if (ctrl & EMAC_RX_ST_IRE) - ++st->rx_bd_in_range; -} - -static inline void emac_rx_csum(struct ocp_enet_private *dev, - struct sk_buff *skb, u16 ctrl) -{ -#if defined(CONFIG_IBM_EMAC_TAH) - if (!ctrl && dev->tah_dev) { - skb->ip_summed = CHECKSUM_UNNECESSARY; - ++dev->stats.rx_packets_csum; - } -#endif -} - -static inline int emac_rx_sg_append(struct ocp_enet_private *dev, int slot) -{ - if (likely(dev->rx_sg_skb != NULL)) { - int len = dev->rx_desc[slot].data_len; - int tot_len = dev->rx_sg_skb->len + len; - - if (unlikely(tot_len + 2 > dev->rx_skb_size)) { - ++dev->estats.rx_dropped_mtu; - dev_kfree_skb(dev->rx_sg_skb); - dev->rx_sg_skb = NULL; - } else { - cacheable_memcpy(skb_tail_pointer(dev->rx_sg_skb), - dev->rx_skb[slot]->data, len); - skb_put(dev->rx_sg_skb, len); - emac_recycle_rx_skb(dev, slot, len); - return 0; - } - } - emac_recycle_rx_skb(dev, slot, 0); - return -1; -} - -/* BHs disabled */ -static int emac_poll_rx(void *param, int budget) -{ - struct ocp_enet_private *dev = param; - int slot = dev->rx_slot, received = 0; - - DBG2("%d: poll_rx(%d)" NL, dev->def->index, budget); - - again: - while (budget > 0) { - int len; - struct sk_buff *skb; - u16 ctrl = dev->rx_desc[slot].ctrl; - - if (ctrl & MAL_RX_CTRL_EMPTY) - break; - - skb = dev->rx_skb[slot]; - barrier(); - len = dev->rx_desc[slot].data_len; - - if (unlikely(!MAL_IS_SINGLE_RX(ctrl))) - goto sg; - - ctrl &= EMAC_BAD_RX_MASK; - if (unlikely(ctrl && ctrl != EMAC_RX_TAH_BAD_CSUM)) { - emac_parse_rx_error(dev, ctrl); - ++dev->estats.rx_dropped_error; - emac_recycle_rx_skb(dev, slot, 0); - len = 0; - goto next; - } - - if (len && len < EMAC_RX_COPY_THRESH) { - struct sk_buff *copy_skb = - alloc_skb(len + EMAC_RX_SKB_HEADROOM + 2, GFP_ATOMIC); - if (unlikely(!copy_skb)) - goto oom; - - skb_reserve(copy_skb, EMAC_RX_SKB_HEADROOM + 2); - cacheable_memcpy(copy_skb->data - 2, skb->data - 2, - len + 2); - emac_recycle_rx_skb(dev, slot, len); - skb = copy_skb; - } else if (unlikely(emac_alloc_rx_skb(dev, slot, GFP_ATOMIC))) - goto oom; - - skb_put(skb, len); - push_packet: - skb->protocol = eth_type_trans(skb, dev->ndev); - emac_rx_csum(dev, skb, ctrl); - - if (unlikely(netif_receive_skb(skb) == NET_RX_DROP)) - ++dev->estats.rx_dropped_stack; - next: - ++dev->stats.rx_packets; - skip: - dev->stats.rx_bytes += len; - slot = (slot + 1) % NUM_RX_BUFF; - --budget; - ++received; - continue; - sg: - if (ctrl & MAL_RX_CTRL_FIRST) { - BUG_ON(dev->rx_sg_skb); - if (unlikely(emac_alloc_rx_skb(dev, slot, GFP_ATOMIC))) { - DBG("%d: rx OOM %d" NL, dev->def->index, slot); - ++dev->estats.rx_dropped_oom; - emac_recycle_rx_skb(dev, slot, 0); - } else { - dev->rx_sg_skb = skb; - skb_put(skb, len); - } - } else if (!emac_rx_sg_append(dev, slot) && - (ctrl & MAL_RX_CTRL_LAST)) { - - skb = dev->rx_sg_skb; - dev->rx_sg_skb = NULL; - - ctrl &= EMAC_BAD_RX_MASK; - if (unlikely(ctrl && ctrl != EMAC_RX_TAH_BAD_CSUM)) { - emac_parse_rx_error(dev, ctrl); - ++dev->estats.rx_dropped_error; - dev_kfree_skb(skb); - len = 0; - } else - goto push_packet; - } - goto skip; - oom: - DBG("%d: rx OOM %d" NL, dev->def->index, slot); - /* Drop the packet and recycle skb */ - ++dev->estats.rx_dropped_oom; - emac_recycle_rx_skb(dev, slot, 0); - goto next; - } - - if (received) { - DBG2("%d: rx %d BDs" NL, dev->def->index, received); - dev->rx_slot = slot; - } - - if (unlikely(budget && dev->commac.rx_stopped)) { - struct ocp_func_emac_data *emacdata = dev->def->additions; - - barrier(); - if (!(dev->rx_desc[slot].ctrl & MAL_RX_CTRL_EMPTY)) { - DBG2("%d: rx restart" NL, dev->def->index); - received = 0; - goto again; - } - - if (dev->rx_sg_skb) { - DBG2("%d: dropping partial rx packet" NL, - dev->def->index); - ++dev->estats.rx_dropped_error; - dev_kfree_skb(dev->rx_sg_skb); - dev->rx_sg_skb = NULL; - } - - dev->commac.rx_stopped = 0; - mal_enable_rx_channel(dev->mal, emacdata->mal_rx_chan); - emac_rx_enable(dev); - dev->rx_slot = 0; - } - return received; -} - -/* BHs disabled */ -static int emac_peek_rx(void *param) -{ - struct ocp_enet_private *dev = param; - return !(dev->rx_desc[dev->rx_slot].ctrl & MAL_RX_CTRL_EMPTY); -} - -/* BHs disabled */ -static int emac_peek_rx_sg(void *param) -{ - struct ocp_enet_private *dev = param; - int slot = dev->rx_slot; - while (1) { - u16 ctrl = dev->rx_desc[slot].ctrl; - if (ctrl & MAL_RX_CTRL_EMPTY) - return 0; - else if (ctrl & MAL_RX_CTRL_LAST) - return 1; - - slot = (slot + 1) % NUM_RX_BUFF; - - /* I'm just being paranoid here :) */ - if (unlikely(slot == dev->rx_slot)) - return 0; - } -} - -/* Hard IRQ */ -static void emac_rxde(void *param) -{ - struct ocp_enet_private *dev = param; - ++dev->estats.rx_stopped; - emac_rx_disable_async(dev); -} - -/* Hard IRQ */ -static irqreturn_t emac_irq(int irq, void *dev_instance) -{ - struct ocp_enet_private *dev = dev_instance; - struct emac_regs __iomem *p = dev->emacp; - struct ibm_emac_error_stats *st = &dev->estats; - - u32 isr = in_be32(&p->isr); - out_be32(&p->isr, isr); - - DBG("%d: isr = %08x" NL, dev->def->index, isr); - - if (isr & EMAC_ISR_TXPE) - ++st->tx_parity; - if (isr & EMAC_ISR_RXPE) - ++st->rx_parity; - if (isr & EMAC_ISR_TXUE) - ++st->tx_underrun; - if (isr & EMAC_ISR_RXOE) - ++st->rx_fifo_overrun; - if (isr & EMAC_ISR_OVR) - ++st->rx_overrun; - if (isr & EMAC_ISR_BP) - ++st->rx_bad_packet; - if (isr & EMAC_ISR_RP) - ++st->rx_runt_packet; - if (isr & EMAC_ISR_SE) - ++st->rx_short_event; - if (isr & EMAC_ISR_ALE) - ++st->rx_alignment_error; - if (isr & EMAC_ISR_BFCS) - ++st->rx_bad_fcs; - if (isr & EMAC_ISR_PTLE) - ++st->rx_packet_too_long; - if (isr & EMAC_ISR_ORE) - ++st->rx_out_of_range; - if (isr & EMAC_ISR_IRE) - ++st->rx_in_range; - if (isr & EMAC_ISR_SQE) - ++st->tx_sqe; - if (isr & EMAC_ISR_TE) - ++st->tx_errors; - - return IRQ_HANDLED; -} - -static struct net_device_stats *emac_stats(struct net_device *ndev) -{ - struct ocp_enet_private *dev = ndev->priv; - struct ibm_emac_stats *st = &dev->stats; - struct ibm_emac_error_stats *est = &dev->estats; - struct net_device_stats *nst = &dev->nstats; - - DBG2("%d: stats" NL, dev->def->index); - - /* Compute "legacy" statistics */ - local_irq_disable(); - nst->rx_packets = (unsigned long)st->rx_packets; - nst->rx_bytes = (unsigned long)st->rx_bytes; - nst->tx_packets = (unsigned long)st->tx_packets; - nst->tx_bytes = (unsigned long)st->tx_bytes; - nst->rx_dropped = (unsigned long)(est->rx_dropped_oom + - est->rx_dropped_error + - est->rx_dropped_resize + - est->rx_dropped_mtu); - nst->tx_dropped = (unsigned long)est->tx_dropped; - - nst->rx_errors = (unsigned long)est->rx_bd_errors; - nst->rx_fifo_errors = (unsigned long)(est->rx_bd_overrun + - est->rx_fifo_overrun + - est->rx_overrun); - nst->rx_frame_errors = (unsigned long)(est->rx_bd_alignment_error + - est->rx_alignment_error); - nst->rx_crc_errors = (unsigned long)(est->rx_bd_bad_fcs + - est->rx_bad_fcs); - nst->rx_length_errors = (unsigned long)(est->rx_bd_runt_packet + - est->rx_bd_short_event + - est->rx_bd_packet_too_long + - est->rx_bd_out_of_range + - est->rx_bd_in_range + - est->rx_runt_packet + - est->rx_short_event + - est->rx_packet_too_long + - est->rx_out_of_range + - est->rx_in_range); - - nst->tx_errors = (unsigned long)(est->tx_bd_errors + est->tx_errors); - nst->tx_fifo_errors = (unsigned long)(est->tx_bd_underrun + - est->tx_underrun); - nst->tx_carrier_errors = (unsigned long)est->tx_bd_carrier_loss; - nst->collisions = (unsigned long)(est->tx_bd_excessive_deferral + - est->tx_bd_excessive_collisions + - est->tx_bd_late_collision + - est->tx_bd_multple_collisions); - local_irq_enable(); - return nst; -} - -static void emac_remove(struct ocp_device *ocpdev) -{ - struct ocp_enet_private *dev = ocp_get_drvdata(ocpdev); - - DBG("%d: remove" NL, dev->def->index); - - ocp_set_drvdata(ocpdev, NULL); - unregister_netdev(dev->ndev); - - tah_fini(dev->tah_dev); - rgmii_fini(dev->rgmii_dev, dev->rgmii_input); - zmii_fini(dev->zmii_dev, dev->zmii_input); - - emac_dbg_register(dev->def->index, NULL); - - mal_unregister_commac(dev->mal, &dev->commac); - iounmap(dev->emacp); - kfree(dev->ndev); -} - -static struct mal_commac_ops emac_commac_ops = { - .poll_tx = &emac_poll_tx, - .poll_rx = &emac_poll_rx, - .peek_rx = &emac_peek_rx, - .rxde = &emac_rxde, -}; - -static struct mal_commac_ops emac_commac_sg_ops = { - .poll_tx = &emac_poll_tx, - .poll_rx = &emac_poll_rx, - .peek_rx = &emac_peek_rx_sg, - .rxde = &emac_rxde, -}; - -/* Ethtool support */ -static int emac_ethtool_get_settings(struct net_device *ndev, - struct ethtool_cmd *cmd) -{ - struct ocp_enet_private *dev = ndev->priv; - - cmd->supported = dev->phy.features; - cmd->port = PORT_MII; - cmd->phy_address = dev->phy.address; - cmd->transceiver = - dev->phy.address >= 0 ? XCVR_EXTERNAL : XCVR_INTERNAL; - - local_bh_disable(); - cmd->advertising = dev->phy.advertising; - cmd->autoneg = dev->phy.autoneg; - cmd->speed = dev->phy.speed; - cmd->duplex = dev->phy.duplex; - local_bh_enable(); - - return 0; -} - -static int emac_ethtool_set_settings(struct net_device *ndev, - struct ethtool_cmd *cmd) -{ - struct ocp_enet_private *dev = ndev->priv; - u32 f = dev->phy.features; - - DBG("%d: set_settings(%d, %d, %d, 0x%08x)" NL, dev->def->index, - cmd->autoneg, cmd->speed, cmd->duplex, cmd->advertising); - - /* Basic sanity checks */ - if (dev->phy.address < 0) - return -EOPNOTSUPP; - if (cmd->autoneg != AUTONEG_ENABLE && cmd->autoneg != AUTONEG_DISABLE) - return -EINVAL; - if (cmd->autoneg == AUTONEG_ENABLE && cmd->advertising == 0) - return -EINVAL; - if (cmd->duplex != DUPLEX_HALF && cmd->duplex != DUPLEX_FULL) - return -EINVAL; - - if (cmd->autoneg == AUTONEG_DISABLE) { - switch (cmd->speed) { - case SPEED_10: - if (cmd->duplex == DUPLEX_HALF - && !(f & SUPPORTED_10baseT_Half)) - return -EINVAL; - if (cmd->duplex == DUPLEX_FULL - && !(f & SUPPORTED_10baseT_Full)) - return -EINVAL; - break; - case SPEED_100: - if (cmd->duplex == DUPLEX_HALF - && !(f & SUPPORTED_100baseT_Half)) - return -EINVAL; - if (cmd->duplex == DUPLEX_FULL - && !(f & SUPPORTED_100baseT_Full)) - return -EINVAL; - break; - case SPEED_1000: - if (cmd->duplex == DUPLEX_HALF - && !(f & SUPPORTED_1000baseT_Half)) - return -EINVAL; - if (cmd->duplex == DUPLEX_FULL - && !(f & SUPPORTED_1000baseT_Full)) - return -EINVAL; - break; - default: - return -EINVAL; - } - - local_bh_disable(); - dev->phy.def->ops->setup_forced(&dev->phy, cmd->speed, - cmd->duplex); - - } else { - if (!(f & SUPPORTED_Autoneg)) - return -EINVAL; - - local_bh_disable(); - dev->phy.def->ops->setup_aneg(&dev->phy, - (cmd->advertising & f) | - (dev->phy.advertising & - (ADVERTISED_Pause | - ADVERTISED_Asym_Pause))); - } - emac_force_link_update(dev); - local_bh_enable(); - - return 0; -} - -static void emac_ethtool_get_ringparam(struct net_device *ndev, - struct ethtool_ringparam *rp) -{ - rp->rx_max_pending = rp->rx_pending = NUM_RX_BUFF; - rp->tx_max_pending = rp->tx_pending = NUM_TX_BUFF; -} - -static void emac_ethtool_get_pauseparam(struct net_device *ndev, - struct ethtool_pauseparam *pp) -{ - struct ocp_enet_private *dev = ndev->priv; - - local_bh_disable(); - if ((dev->phy.features & SUPPORTED_Autoneg) && - (dev->phy.advertising & (ADVERTISED_Pause | ADVERTISED_Asym_Pause))) - pp->autoneg = 1; - - if (dev->phy.duplex == DUPLEX_FULL) { - if (dev->phy.pause) - pp->rx_pause = pp->tx_pause = 1; - else if (dev->phy.asym_pause) - pp->tx_pause = 1; - } - local_bh_enable(); -} - -static u32 emac_ethtool_get_rx_csum(struct net_device *ndev) -{ - struct ocp_enet_private *dev = ndev->priv; - return dev->tah_dev != 0; -} - -static int emac_get_regs_len(struct ocp_enet_private *dev) -{ - return sizeof(struct emac_ethtool_regs_subhdr) + EMAC_ETHTOOL_REGS_SIZE; -} - -static int emac_ethtool_get_regs_len(struct net_device *ndev) -{ - struct ocp_enet_private *dev = ndev->priv; - return sizeof(struct emac_ethtool_regs_hdr) + - emac_get_regs_len(dev) + mal_get_regs_len(dev->mal) + - zmii_get_regs_len(dev->zmii_dev) + - rgmii_get_regs_len(dev->rgmii_dev) + - tah_get_regs_len(dev->tah_dev); -} - -static void *emac_dump_regs(struct ocp_enet_private *dev, void *buf) -{ - struct emac_ethtool_regs_subhdr *hdr = buf; - - hdr->version = EMAC_ETHTOOL_REGS_VER; - hdr->index = dev->def->index; - memcpy_fromio(hdr + 1, dev->emacp, EMAC_ETHTOOL_REGS_SIZE); - return ((void *)(hdr + 1) + EMAC_ETHTOOL_REGS_SIZE); -} - -static void emac_ethtool_get_regs(struct net_device *ndev, - struct ethtool_regs *regs, void *buf) -{ - struct ocp_enet_private *dev = ndev->priv; - struct emac_ethtool_regs_hdr *hdr = buf; - - hdr->components = 0; - buf = hdr + 1; - - local_irq_disable(); - buf = mal_dump_regs(dev->mal, buf); - buf = emac_dump_regs(dev, buf); - if (dev->zmii_dev) { - hdr->components |= EMAC_ETHTOOL_REGS_ZMII; - buf = zmii_dump_regs(dev->zmii_dev, buf); - } - if (dev->rgmii_dev) { - hdr->components |= EMAC_ETHTOOL_REGS_RGMII; - buf = rgmii_dump_regs(dev->rgmii_dev, buf); - } - if (dev->tah_dev) { - hdr->components |= EMAC_ETHTOOL_REGS_TAH; - buf = tah_dump_regs(dev->tah_dev, buf); - } - local_irq_enable(); -} - -static int emac_ethtool_nway_reset(struct net_device *ndev) -{ - struct ocp_enet_private *dev = ndev->priv; - int res = 0; - - DBG("%d: nway_reset" NL, dev->def->index); - - if (dev->phy.address < 0) - return -EOPNOTSUPP; - - local_bh_disable(); - if (!dev->phy.autoneg) { - res = -EINVAL; - goto out; - } - - dev->phy.def->ops->setup_aneg(&dev->phy, dev->phy.advertising); - emac_force_link_update(dev); - - out: - local_bh_enable(); - return res; -} - -static int emac_get_sset_count(struct net_device *ndev, int sset) -{ - switch (sset) { - case ETH_SS_STATS: - return EMAC_ETHTOOL_STATS_COUNT; - default: - return -EOPNOTSUPP; - } -} - -static void emac_ethtool_get_strings(struct net_device *ndev, u32 stringset, - u8 * buf) -{ - if (stringset == ETH_SS_STATS) - memcpy(buf, &emac_stats_keys, sizeof(emac_stats_keys)); -} - -static void emac_ethtool_get_ethtool_stats(struct net_device *ndev, - struct ethtool_stats *estats, - u64 * tmp_stats) -{ - struct ocp_enet_private *dev = ndev->priv; - local_irq_disable(); - memcpy(tmp_stats, &dev->stats, sizeof(dev->stats)); - tmp_stats += sizeof(dev->stats) / sizeof(u64); - memcpy(tmp_stats, &dev->estats, sizeof(dev->estats)); - local_irq_enable(); -} - -static void emac_ethtool_get_drvinfo(struct net_device *ndev, - struct ethtool_drvinfo *info) -{ - struct ocp_enet_private *dev = ndev->priv; - - strcpy(info->driver, "ibm_emac"); - strcpy(info->version, DRV_VERSION); - info->fw_version[0] = '\0'; - sprintf(info->bus_info, "PPC 4xx EMAC %d", dev->def->index); - info->regdump_len = emac_ethtool_get_regs_len(ndev); -} - -static const struct ethtool_ops emac_ethtool_ops = { - .get_settings = emac_ethtool_get_settings, - .set_settings = emac_ethtool_set_settings, - .get_drvinfo = emac_ethtool_get_drvinfo, - - .get_regs_len = emac_ethtool_get_regs_len, - .get_regs = emac_ethtool_get_regs, - - .nway_reset = emac_ethtool_nway_reset, - - .get_ringparam = emac_ethtool_get_ringparam, - .get_pauseparam = emac_ethtool_get_pauseparam, - - .get_rx_csum = emac_ethtool_get_rx_csum, - - .get_strings = emac_ethtool_get_strings, - .get_sset_count = emac_get_sset_count, - .get_ethtool_stats = emac_ethtool_get_ethtool_stats, - - .get_link = ethtool_op_get_link, -}; - -static int emac_ioctl(struct net_device *ndev, struct ifreq *rq, int cmd) -{ - struct ocp_enet_private *dev = ndev->priv; - uint16_t *data = (uint16_t *) & rq->ifr_ifru; - - DBG("%d: ioctl %08x" NL, dev->def->index, cmd); - - if (dev->phy.address < 0) - return -EOPNOTSUPP; - - switch (cmd) { - case SIOCGMIIPHY: - case SIOCDEVPRIVATE: - data[0] = dev->phy.address; - /* Fall through */ - case SIOCGMIIREG: - case SIOCDEVPRIVATE + 1: - data[3] = emac_mdio_read(ndev, dev->phy.address, data[1]); - return 0; - - case SIOCSMIIREG: - case SIOCDEVPRIVATE + 2: - if (!capable(CAP_NET_ADMIN)) - return -EPERM; - emac_mdio_write(ndev, dev->phy.address, data[1], data[2]); - return 0; - default: - return -EOPNOTSUPP; - } -} - -static int __init emac_probe(struct ocp_device *ocpdev) -{ - struct ocp_func_emac_data *emacdata = ocpdev->def->additions; - struct net_device *ndev; - struct ocp_device *maldev; - struct ocp_enet_private *dev; - int err, i; - DECLARE_MAC_BUF(mac); - - DBG("%d: probe" NL, ocpdev->def->index); - - if (!emacdata) { - printk(KERN_ERR "emac%d: Missing additional data!\n", - ocpdev->def->index); - return -ENODEV; - } - - /* Allocate our net_device structure */ - ndev = alloc_etherdev(sizeof(struct ocp_enet_private)); - if (!ndev) { - printk(KERN_ERR "emac%d: could not allocate ethernet device!\n", - ocpdev->def->index); - return -ENOMEM; - } - dev = ndev->priv; - dev->ndev = ndev; - dev->ldev = &ocpdev->dev; - dev->def = ocpdev->def; - - /* Find MAL device we are connected to */ - maldev = - ocp_find_device(OCP_VENDOR_IBM, OCP_FUNC_MAL, emacdata->mal_idx); - if (!maldev) { - printk(KERN_ERR "emac%d: unknown mal%d device!\n", - dev->def->index, emacdata->mal_idx); - err = -ENODEV; - goto out; - } - dev->mal = ocp_get_drvdata(maldev); - if (!dev->mal) { - printk(KERN_ERR "emac%d: mal%d hasn't been initialized yet!\n", - dev->def->index, emacdata->mal_idx); - err = -ENODEV; - goto out; - } - - /* Register with MAL */ - dev->commac.ops = &emac_commac_ops; - dev->commac.dev = dev; - dev->commac.tx_chan_mask = MAL_CHAN_MASK(emacdata->mal_tx_chan); - dev->commac.rx_chan_mask = MAL_CHAN_MASK(emacdata->mal_rx_chan); - err = mal_register_commac(dev->mal, &dev->commac); - if (err) { - printk(KERN_ERR "emac%d: failed to register with mal%d!\n", - dev->def->index, emacdata->mal_idx); - goto out; - } - dev->rx_skb_size = emac_rx_skb_size(ndev->mtu); - dev->rx_sync_size = emac_rx_sync_size(ndev->mtu); - - /* Get pointers to BD rings */ - dev->tx_desc = - dev->mal->bd_virt + mal_tx_bd_offset(dev->mal, - emacdata->mal_tx_chan); - dev->rx_desc = - dev->mal->bd_virt + mal_rx_bd_offset(dev->mal, - emacdata->mal_rx_chan); - - DBG("%d: tx_desc %p" NL, ocpdev->def->index, dev->tx_desc); - DBG("%d: rx_desc %p" NL, ocpdev->def->index, dev->rx_desc); - - /* Clean rings */ - memset(dev->tx_desc, 0, NUM_TX_BUFF * sizeof(struct mal_descriptor)); - memset(dev->rx_desc, 0, NUM_RX_BUFF * sizeof(struct mal_descriptor)); - - /* If we depend on another EMAC for MDIO, check whether it was probed already */ - if (emacdata->mdio_idx >= 0 && emacdata->mdio_idx != ocpdev->def->index) { - struct ocp_device *mdiodev = - ocp_find_device(OCP_VENDOR_IBM, OCP_FUNC_EMAC, - emacdata->mdio_idx); - if (!mdiodev) { - printk(KERN_ERR "emac%d: unknown emac%d device!\n", - dev->def->index, emacdata->mdio_idx); - err = -ENODEV; - goto out2; - } - dev->mdio_dev = ocp_get_drvdata(mdiodev); - if (!dev->mdio_dev) { - printk(KERN_ERR - "emac%d: emac%d hasn't been initialized yet!\n", - dev->def->index, emacdata->mdio_idx); - err = -ENODEV; - goto out2; - } - } - - /* Attach to ZMII, if needed */ - if ((err = zmii_attach(dev)) != 0) - goto out2; - - /* Attach to RGMII, if needed */ - if ((err = rgmii_attach(dev)) != 0) - goto out3; - - /* Attach to TAH, if needed */ - if ((err = tah_attach(dev)) != 0) - goto out4; - - /* Map EMAC regs */ - dev->emacp = ioremap(dev->def->paddr, sizeof(struct emac_regs)); - if (!dev->emacp) { - printk(KERN_ERR "emac%d: could not ioremap device registers!\n", - dev->def->index); - err = -ENOMEM; - goto out5; - } - - /* Fill in MAC address */ - for (i = 0; i < 6; ++i) - ndev->dev_addr[i] = emacdata->mac_addr[i]; - - /* Set some link defaults before we can find out real parameters */ - dev->phy.speed = SPEED_100; - dev->phy.duplex = DUPLEX_FULL; - dev->phy.autoneg = AUTONEG_DISABLE; - dev->phy.pause = dev->phy.asym_pause = 0; - dev->stop_timeout = STOP_TIMEOUT_100; - init_timer(&dev->link_timer); - dev->link_timer.function = emac_link_timer; - dev->link_timer.data = (unsigned long)dev; - - /* Find PHY if any */ - dev->phy.dev = ndev; - dev->phy.mode = emacdata->phy_mode; - if (emacdata->phy_map != 0xffffffff) { - u32 phy_map = emacdata->phy_map | busy_phy_map; - u32 adv; - - DBG("%d: PHY maps %08x %08x" NL, dev->def->index, - emacdata->phy_map, busy_phy_map); - - EMAC_RX_CLK_TX(dev->def->index); - - dev->phy.mdio_read = emac_mdio_read; - dev->phy.mdio_write = emac_mdio_write; - - /* Configure EMAC with defaults so we can at least use MDIO - * This is needed mostly for 440GX - */ - if (emac_phy_gpcs(dev->phy.mode)) { - /* XXX - * Make GPCS PHY address equal to EMAC index. - * We probably should take into account busy_phy_map - * and/or phy_map here. - */ - dev->phy.address = dev->def->index; - } - - emac_configure(dev); - - for (i = 0; i < 0x20; phy_map >>= 1, ++i) - if (!(phy_map & 1)) { - int r; - busy_phy_map |= 1 << i; - - /* Quick check if there is a PHY at the address */ - r = emac_mdio_read(dev->ndev, i, MII_BMCR); - if (r == 0xffff || r < 0) - continue; - if (!mii_phy_probe(&dev->phy, i)) - break; - } - if (i == 0x20) { - printk(KERN_WARNING "emac%d: can't find PHY!\n", - dev->def->index); - goto out6; - } - - /* Init PHY */ - if (dev->phy.def->ops->init) - dev->phy.def->ops->init(&dev->phy); - - /* Disable any PHY features not supported by the platform */ - dev->phy.def->features &= ~emacdata->phy_feat_exc; - - /* Setup initial link parameters */ - if (dev->phy.features & SUPPORTED_Autoneg) { - adv = dev->phy.features; -#if !defined(CONFIG_40x) - adv |= ADVERTISED_Pause | ADVERTISED_Asym_Pause; -#endif - /* Restart autonegotiation */ - dev->phy.def->ops->setup_aneg(&dev->phy, adv); - } else { - u32 f = dev->phy.def->features; - int speed = SPEED_10, fd = DUPLEX_HALF; - - /* Select highest supported speed/duplex */ - if (f & SUPPORTED_1000baseT_Full) { - speed = SPEED_1000; - fd = DUPLEX_FULL; - } else if (f & SUPPORTED_1000baseT_Half) - speed = SPEED_1000; - else if (f & SUPPORTED_100baseT_Full) { - speed = SPEED_100; - fd = DUPLEX_FULL; - } else if (f & SUPPORTED_100baseT_Half) - speed = SPEED_100; - else if (f & SUPPORTED_10baseT_Full) - fd = DUPLEX_FULL; - - /* Force link parameters */ - dev->phy.def->ops->setup_forced(&dev->phy, speed, fd); - } - } else { - emac_reset(dev); - - /* PHY-less configuration. - * XXX I probably should move these settings to emacdata - */ - dev->phy.address = -1; - dev->phy.features = SUPPORTED_100baseT_Full | SUPPORTED_MII; - dev->phy.pause = 1; - } - - /* Fill in the driver function table */ - ndev->open = &emac_open; - if (dev->tah_dev) { - ndev->hard_start_xmit = &emac_start_xmit_sg; - ndev->features |= NETIF_F_IP_CSUM | NETIF_F_SG; - } else - ndev->hard_start_xmit = &emac_start_xmit; - ndev->tx_timeout = &emac_full_tx_reset; - ndev->watchdog_timeo = 5 * HZ; - ndev->stop = &emac_close; - ndev->get_stats = &emac_stats; - ndev->set_multicast_list = &emac_set_multicast_list; - ndev->do_ioctl = &emac_ioctl; - if (emac_phy_supports_gige(emacdata->phy_mode)) { - ndev->change_mtu = &emac_change_mtu; - dev->commac.ops = &emac_commac_sg_ops; - } - SET_ETHTOOL_OPS(ndev, &emac_ethtool_ops); - - netif_carrier_off(ndev); - netif_stop_queue(ndev); - - err = register_netdev(ndev); - if (err) { - printk(KERN_ERR "emac%d: failed to register net device (%d)!\n", - dev->def->index, err); - goto out6; - } - - ocp_set_drvdata(ocpdev, dev); - - printk("%s: emac%d, MAC %s\n", - ndev->name, dev->def->index, print_mac(mac, ndev->dev_addr)); - - if (dev->phy.address >= 0) - printk("%s: found %s PHY (0x%02x)\n", ndev->name, - dev->phy.def->name, dev->phy.address); - - emac_dbg_register(dev->def->index, dev); - - return 0; - out6: - iounmap(dev->emacp); - out5: - tah_fini(dev->tah_dev); - out4: - rgmii_fini(dev->rgmii_dev, dev->rgmii_input); - out3: - zmii_fini(dev->zmii_dev, dev->zmii_input); - out2: - mal_unregister_commac(dev->mal, &dev->commac); - out: - kfree(ndev); - return err; -} - -static struct ocp_device_id emac_ids[] = { - { .vendor = OCP_VENDOR_IBM, .function = OCP_FUNC_EMAC }, - { .vendor = OCP_VENDOR_INVALID} -}; - -static struct ocp_driver emac_driver = { - .name = "emac", - .id_table = emac_ids, - .probe = emac_probe, - .remove = emac_remove, -}; - -static int __init emac_init(void) -{ - printk(KERN_INFO DRV_DESC ", version " DRV_VERSION "\n"); - - DBG(": init" NL); - - if (mal_init()) - return -ENODEV; - - EMAC_CLK_INTERNAL; - if (ocp_register_driver(&emac_driver)) { - EMAC_CLK_EXTERNAL; - ocp_unregister_driver(&emac_driver); - mal_exit(); - return -ENODEV; - } - EMAC_CLK_EXTERNAL; - - emac_init_debug(); - return 0; -} - -static void __exit emac_exit(void) -{ - DBG(": exit" NL); - ocp_unregister_driver(&emac_driver); - mal_exit(); - emac_fini_debug(); -} - -module_init(emac_init); -module_exit(emac_exit); diff --git a/drivers/net/ibm_emac/ibm_emac_core.h b/drivers/net/ibm_emac/ibm_emac_core.h deleted file mode 100644 index dabb94afeb98..000000000000 --- a/drivers/net/ibm_emac/ibm_emac_core.h +++ /dev/null @@ -1,222 +0,0 @@ -/* - * drivers/net/ibm_emac/ibm_emac_core.h - * - * Driver for PowerPC 4xx on-chip ethernet controller. - * - * Copyright (c) 2004, 2005 Zultys Technologies. - * Eugene Surovegin <eugene.surovegin@zultys.com> or <ebs@ebshome.net> - * - * Based on original work by - * Armin Kuster <akuster@mvista.com> - * Johnnie Peters <jpeters@mvista.com> - * Copyright 2000, 2001 MontaVista Softare Inc. - * - * 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. - * - */ -#ifndef __IBM_EMAC_CORE_H_ -#define __IBM_EMAC_CORE_H_ - -#include <linux/netdevice.h> -#include <linux/dma-mapping.h> -#include <asm/ocp.h> - -#include "ibm_emac.h" -#include "ibm_emac_phy.h" -#include "ibm_emac_zmii.h" -#include "ibm_emac_rgmii.h" -#include "ibm_emac_mal.h" -#include "ibm_emac_tah.h" - -#define NUM_TX_BUFF CONFIG_IBM_EMAC_TXB -#define NUM_RX_BUFF CONFIG_IBM_EMAC_RXB - -/* Simple sanity check */ -#if NUM_TX_BUFF > 256 || NUM_RX_BUFF > 256 -#error Invalid number of buffer descriptors (greater than 256) -#endif - -// XXX -#define EMAC_MIN_MTU 46 -#define EMAC_MAX_MTU 9000 - -/* Maximum L2 header length (VLAN tagged, no FCS) */ -#define EMAC_MTU_OVERHEAD (6 * 2 + 2 + 4) - -/* RX BD size for the given MTU */ -static inline int emac_rx_size(int mtu) -{ - if (mtu > ETH_DATA_LEN) - return MAL_MAX_RX_SIZE; - else - return mal_rx_size(ETH_DATA_LEN + EMAC_MTU_OVERHEAD); -} - -#define EMAC_DMA_ALIGN(x) ALIGN((x), dma_get_cache_alignment()) - -#define EMAC_RX_SKB_HEADROOM \ - EMAC_DMA_ALIGN(CONFIG_IBM_EMAC_RX_SKB_HEADROOM) - -/* Size of RX skb for the given MTU */ -static inline int emac_rx_skb_size(int mtu) -{ - int size = max(mtu + EMAC_MTU_OVERHEAD, emac_rx_size(mtu)); - return EMAC_DMA_ALIGN(size + 2) + EMAC_RX_SKB_HEADROOM; -} - -/* RX DMA sync size */ -static inline int emac_rx_sync_size(int mtu) -{ - return EMAC_DMA_ALIGN(emac_rx_size(mtu) + 2); -} - -/* Driver statistcs is split into two parts to make it more cache friendly: - * - normal statistics (packet count, etc) - * - error statistics - * - * When statistics is requested by ethtool, these parts are concatenated, - * normal one goes first. - * - * Please, keep these structures in sync with emac_stats_keys. - */ - -/* Normal TX/RX Statistics */ -struct ibm_emac_stats { - u64 rx_packets; - u64 rx_bytes; - u64 tx_packets; - u64 tx_bytes; - u64 rx_packets_csum; - u64 tx_packets_csum; -}; - -/* Error statistics */ -struct ibm_emac_error_stats { - u64 tx_undo; - - /* Software RX Errors */ - u64 rx_dropped_stack; - u64 rx_dropped_oom; - u64 rx_dropped_error; - u64 rx_dropped_resize; - u64 rx_dropped_mtu; - u64 rx_stopped; - /* BD reported RX errors */ - u64 rx_bd_errors; - u64 rx_bd_overrun; - u64 rx_bd_bad_packet; - u64 rx_bd_runt_packet; - u64 rx_bd_short_event; - u64 rx_bd_alignment_error; - u64 rx_bd_bad_fcs; - u64 rx_bd_packet_too_long; - u64 rx_bd_out_of_range; - u64 rx_bd_in_range; - /* EMAC IRQ reported RX errors */ - u64 rx_parity; - u64 rx_fifo_overrun; - u64 rx_overrun; - u64 rx_bad_packet; - u64 rx_runt_packet; - u64 rx_short_event; - u64 rx_alignment_error; - u64 rx_bad_fcs; - u64 rx_packet_too_long; - u64 rx_out_of_range; - u64 rx_in_range; - - /* Software TX Errors */ - u64 tx_dropped; - /* BD reported TX errors */ - u64 tx_bd_errors; - u64 tx_bd_bad_fcs; - u64 tx_bd_carrier_loss; - u64 tx_bd_excessive_deferral; - u64 tx_bd_excessive_collisions; - u64 tx_bd_late_collision; - u64 tx_bd_multple_collisions; - u64 tx_bd_single_collision; - u64 tx_bd_underrun; - u64 tx_bd_sqe; - /* EMAC IRQ reported TX errors */ - u64 tx_parity; - u64 tx_underrun; - u64 tx_sqe; - u64 tx_errors; -}; - -#define EMAC_ETHTOOL_STATS_COUNT ((sizeof(struct ibm_emac_stats) + \ - sizeof(struct ibm_emac_error_stats)) \ - / sizeof(u64)) - -struct ocp_enet_private { - struct net_device *ndev; /* 0 */ - struct emac_regs __iomem *emacp; - - struct mal_descriptor *tx_desc; - int tx_cnt; - int tx_slot; - int ack_slot; - - struct mal_descriptor *rx_desc; - int rx_slot; - struct sk_buff *rx_sg_skb; /* 1 */ - int rx_skb_size; - int rx_sync_size; - - struct ibm_emac_stats stats; - struct ocp_device *tah_dev; - - struct ibm_ocp_mal *mal; - struct mal_commac commac; - - struct sk_buff *tx_skb[NUM_TX_BUFF]; - struct sk_buff *rx_skb[NUM_RX_BUFF]; - - struct ocp_device *zmii_dev; - int zmii_input; - struct ocp_enet_private *mdio_dev; - struct ocp_device *rgmii_dev; - int rgmii_input; - - struct ocp_def *def; - - struct mii_phy phy; - struct timer_list link_timer; - int reset_failed; - - int stop_timeout; /* in us */ - - struct ibm_emac_error_stats estats; - struct net_device_stats nstats; - - struct device* ldev; -}; - -/* Ethtool get_regs complex data. - * We want to get not just EMAC registers, but also MAL, ZMII, RGMII, TAH - * when available. - * - * Returned BLOB consists of the ibm_emac_ethtool_regs_hdr, - * MAL registers, EMAC registers and optional ZMII, RGMII, TAH registers. - * Each register component is preceded with emac_ethtool_regs_subhdr. - * Order of the optional headers follows their relative bit posititions - * in emac_ethtool_regs_hdr.components - */ -#define EMAC_ETHTOOL_REGS_ZMII 0x00000001 -#define EMAC_ETHTOOL_REGS_RGMII 0x00000002 -#define EMAC_ETHTOOL_REGS_TAH 0x00000004 - -struct emac_ethtool_regs_hdr { - u32 components; -}; - -struct emac_ethtool_regs_subhdr { - u32 version; - u32 index; -}; - -#endif /* __IBM_EMAC_CORE_H_ */ diff --git a/drivers/net/ibm_emac/ibm_emac_debug.c b/drivers/net/ibm_emac/ibm_emac_debug.c deleted file mode 100644 index 1f70906cfb98..000000000000 --- a/drivers/net/ibm_emac/ibm_emac_debug.c +++ /dev/null @@ -1,211 +0,0 @@ -/* - * drivers/net/ibm_emac/ibm_emac_debug.c - * - * Driver for PowerPC 4xx on-chip ethernet controller, debug print routines. - * - * Copyright (c) 2004, 2005 Zultys Technologies - * Eugene Surovegin <eugene.surovegin@zultys.com> or <ebs@ebshome.net> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - */ -#include <linux/init.h> -#include <linux/module.h> -#include <linux/kernel.h> -#include <linux/netdevice.h> -#include <linux/sysrq.h> -#include <asm/io.h> - -#include "ibm_emac_core.h" - -static void emac_desc_dump(int idx, struct ocp_enet_private *p) -{ - int i; - printk("** EMAC%d TX BDs **\n" - " tx_cnt = %d tx_slot = %d ack_slot = %d\n", - idx, p->tx_cnt, p->tx_slot, p->ack_slot); - for (i = 0; i < NUM_TX_BUFF / 2; ++i) - printk - ("bd[%2d] 0x%08x %c 0x%04x %4u - bd[%2d] 0x%08x %c 0x%04x %4u\n", - i, p->tx_desc[i].data_ptr, p->tx_skb[i] ? 'V' : ' ', - p->tx_desc[i].ctrl, p->tx_desc[i].data_len, - NUM_TX_BUFF / 2 + i, - p->tx_desc[NUM_TX_BUFF / 2 + i].data_ptr, - p->tx_skb[NUM_TX_BUFF / 2 + i] ? 'V' : ' ', - p->tx_desc[NUM_TX_BUFF / 2 + i].ctrl, - p->tx_desc[NUM_TX_BUFF / 2 + i].data_len); - - printk("** EMAC%d RX BDs **\n" - " rx_slot = %d rx_stopped = %d rx_skb_size = %d rx_sync_size = %d\n" - " rx_sg_skb = 0x%p\n", - idx, p->rx_slot, p->commac.rx_stopped, p->rx_skb_size, - p->rx_sync_size, p->rx_sg_skb); - for (i = 0; i < NUM_RX_BUFF / 2; ++i) - printk - ("bd[%2d] 0x%08x %c 0x%04x %4u - bd[%2d] 0x%08x %c 0x%04x %4u\n", - i, p->rx_desc[i].data_ptr, p->rx_skb[i] ? 'V' : ' ', - p->rx_desc[i].ctrl, p->rx_desc[i].data_len, - NUM_RX_BUFF / 2 + i, - p->rx_desc[NUM_RX_BUFF / 2 + i].data_ptr, - p->rx_skb[NUM_RX_BUFF / 2 + i] ? 'V' : ' ', - p->rx_desc[NUM_RX_BUFF / 2 + i].ctrl, - p->rx_desc[NUM_RX_BUFF / 2 + i].data_len); -} - -static void emac_mac_dump(int idx, struct ocp_enet_private *dev) -{ - struct emac_regs __iomem *p = dev->emacp; - - printk("** EMAC%d registers **\n" - "MR0 = 0x%08x MR1 = 0x%08x TMR0 = 0x%08x TMR1 = 0x%08x\n" - "RMR = 0x%08x ISR = 0x%08x ISER = 0x%08x\n" - "IAR = %04x%08x VTPID = 0x%04x VTCI = 0x%04x\n" - "IAHT: 0x%04x 0x%04x 0x%04x 0x%04x " - "GAHT: 0x%04x 0x%04x 0x%04x 0x%04x\n" - "LSA = %04x%08x IPGVR = 0x%04x\n" - "STACR = 0x%08x TRTR = 0x%08x RWMR = 0x%08x\n" - "OCTX = 0x%08x OCRX = 0x%08x IPCR = 0x%08x\n", - idx, in_be32(&p->mr0), in_be32(&p->mr1), - in_be32(&p->tmr0), in_be32(&p->tmr1), - in_be32(&p->rmr), in_be32(&p->isr), in_be32(&p->iser), - in_be32(&p->iahr), in_be32(&p->ialr), in_be32(&p->vtpid), - in_be32(&p->vtci), - in_be32(&p->iaht1), in_be32(&p->iaht2), in_be32(&p->iaht3), - in_be32(&p->iaht4), - in_be32(&p->gaht1), in_be32(&p->gaht2), in_be32(&p->gaht3), - in_be32(&p->gaht4), - in_be32(&p->lsah), in_be32(&p->lsal), in_be32(&p->ipgvr), - in_be32(&p->stacr), in_be32(&p->trtr), in_be32(&p->rwmr), - in_be32(&p->octx), in_be32(&p->ocrx), in_be32(&p->ipcr) - ); - - emac_desc_dump(idx, dev); -} - -static void emac_mal_dump(struct ibm_ocp_mal *mal) -{ - struct ocp_func_mal_data *maldata = mal->def->additions; - int i; - - printk("** MAL%d Registers **\n" - "CFG = 0x%08x ESR = 0x%08x IER = 0x%08x\n" - "TX|CASR = 0x%08x CARR = 0x%08x EOBISR = 0x%08x DEIR = 0x%08x\n" - "RX|CASR = 0x%08x CARR = 0x%08x EOBISR = 0x%08x DEIR = 0x%08x\n", - mal->def->index, - get_mal_dcrn(mal, MAL_CFG), get_mal_dcrn(mal, MAL_ESR), - get_mal_dcrn(mal, MAL_IER), - get_mal_dcrn(mal, MAL_TXCASR), get_mal_dcrn(mal, MAL_TXCARR), - get_mal_dcrn(mal, MAL_TXEOBISR), get_mal_dcrn(mal, MAL_TXDEIR), - get_mal_dcrn(mal, MAL_RXCASR), get_mal_dcrn(mal, MAL_RXCARR), - get_mal_dcrn(mal, MAL_RXEOBISR), get_mal_dcrn(mal, MAL_RXDEIR) - ); - - printk("TX|"); - for (i = 0; i < maldata->num_tx_chans; ++i) { - if (i && !(i % 4)) - printk("\n "); - printk("CTP%d = 0x%08x ", i, get_mal_dcrn(mal, MAL_TXCTPR(i))); - } - printk("\nRX|"); - for (i = 0; i < maldata->num_rx_chans; ++i) { - if (i && !(i % 4)) - printk("\n "); - printk("CTP%d = 0x%08x ", i, get_mal_dcrn(mal, MAL_RXCTPR(i))); - } - printk("\n "); - for (i = 0; i < maldata->num_rx_chans; ++i) { - u32 r = get_mal_dcrn(mal, MAL_RCBS(i)); - if (i && !(i % 3)) - printk("\n "); - printk("RCBS%d = 0x%08x (%d) ", i, r, r * 16); - } - printk("\n"); -} - -static struct ocp_enet_private *__emacs[4]; -static struct ibm_ocp_mal *__mals[1]; - -void emac_dbg_register(int idx, struct ocp_enet_private *dev) -{ - unsigned long flags; - - if (idx >= ARRAY_SIZE(__emacs)) { - printk(KERN_WARNING - "invalid index %d when registering EMAC for debugging\n", - idx); - return; - } - - local_irq_save(flags); - __emacs[idx] = dev; - local_irq_restore(flags); -} - -void mal_dbg_register(int idx, struct ibm_ocp_mal *mal) -{ - unsigned long flags; - - if (idx >= ARRAY_SIZE(__mals)) { - printk(KERN_WARNING - "invalid index %d when registering MAL for debugging\n", - idx); - return; - } - - local_irq_save(flags); - __mals[idx] = mal; - local_irq_restore(flags); -} - -void emac_dbg_dump_all(void) -{ - unsigned int i; - unsigned long flags; - - local_irq_save(flags); - - for (i = 0; i < ARRAY_SIZE(__mals); ++i) - if (__mals[i]) - emac_mal_dump(__mals[i]); - - for (i = 0; i < ARRAY_SIZE(__emacs); ++i) - if (__emacs[i]) - emac_mac_dump(i, __emacs[i]); - - local_irq_restore(flags); -} - -#if defined(CONFIG_MAGIC_SYSRQ) -static void emac_sysrq_handler(int key, struct tty_struct *tty) -{ - emac_dbg_dump_all(); -} - -static struct sysrq_key_op emac_sysrq_op = { - .handler = emac_sysrq_handler, - .help_msg = "emaC", - .action_msg = "Show EMAC(s) status", -}; - -int __init emac_init_debug(void) -{ - return register_sysrq_key('c', &emac_sysrq_op); -} - -void __exit emac_fini_debug(void) -{ - unregister_sysrq_key('c', &emac_sysrq_op); -} - -#else -int __init emac_init_debug(void) -{ - return 0; -} -void __exit emac_fini_debug(void) -{ -} -#endif /* CONFIG_MAGIC_SYSRQ */ diff --git a/drivers/net/ibm_emac/ibm_emac_debug.h b/drivers/net/ibm_emac/ibm_emac_debug.h deleted file mode 100644 index 6c7dccc84bf5..000000000000 --- a/drivers/net/ibm_emac/ibm_emac_debug.h +++ /dev/null @@ -1,62 +0,0 @@ -/* - * drivers/net/ibm_emac/ibm_emac_debug.h - * - * Driver for PowerPC 4xx on-chip ethernet controller, debug print routines. - * - * Copyright (c) 2004, 2005 Zultys Technologies - * Eugene Surovegin <eugene.surovegin@zultys.com> or <ebs@ebshome.net> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - */ -#ifndef __IBM_EMAC_DEBUG_H_ -#define __IBM_EMAC_DEBUG_H_ - -#include <linux/init.h> -#include "ibm_emac_core.h" -#include "ibm_emac_mal.h" - -#if defined(CONFIG_IBM_EMAC_DEBUG) -void emac_dbg_register(int idx, struct ocp_enet_private *dev); -void mal_dbg_register(int idx, struct ibm_ocp_mal *mal); -int emac_init_debug(void) __init; -void emac_fini_debug(void) __exit; -void emac_dbg_dump_all(void); -# define DBG_LEVEL 1 -#else -# define emac_dbg_register(x,y) ((void)0) -# define mal_dbg_register(x,y) ((void)0) -# define emac_init_debug() ((void)0) -# define emac_fini_debug() ((void)0) -# define emac_dbg_dump_all() ((void)0) -# define DBG_LEVEL 0 -#endif - -#if DBG_LEVEL > 0 -# define DBG(f,x...) printk("emac" f, ##x) -# define MAL_DBG(f,x...) printk("mal" f, ##x) -# define ZMII_DBG(f,x...) printk("zmii" f, ##x) -# define RGMII_DBG(f,x...) printk("rgmii" f, ##x) -# define NL "\n" -#else -# define DBG(f,x...) ((void)0) -# define MAL_DBG(f,x...) ((void)0) -# define ZMII_DBG(f,x...) ((void)0) -# define RGMII_DBG(f,x...) ((void)0) -#endif -#if DBG_LEVEL > 1 -# define DBG2(f,x...) DBG(f, ##x) -# define MAL_DBG2(f,x...) MAL_DBG(f, ##x) -# define ZMII_DBG2(f,x...) ZMII_DBG(f, ##x) -# define RGMII_DBG2(f,x...) RGMII_DBG(f, ##x) -#else -# define DBG2(f,x...) ((void)0) -# define MAL_DBG2(f,x...) ((void)0) -# define ZMII_DBG2(f,x...) ((void)0) -# define RGMII_DBG2(f,x...) ((void)0) -#endif - -#endif /* __IBM_EMAC_DEBUG_H_ */ diff --git a/drivers/net/ibm_emac/ibm_emac_mal.c b/drivers/net/ibm_emac/ibm_emac_mal.c deleted file mode 100644 index dcd8826fc749..000000000000 --- a/drivers/net/ibm_emac/ibm_emac_mal.c +++ /dev/null @@ -1,570 +0,0 @@ -/* - * drivers/net/ibm_emac/ibm_emac_mal.c - * - * Memory Access Layer (MAL) support - * - * Copyright (c) 2004, 2005 Zultys Technologies. - * Eugene Surovegin <eugene.surovegin@zultys.com> or <ebs@ebshome.net> - * - * Based on original work by - * Benjamin Herrenschmidt <benh@kernel.crashing.org>, - * David Gibson <hermes@gibson.dropbear.id.au>, - * - * Armin Kuster <akuster@mvista.com> - * Copyright 2002 MontaVista Softare Inc. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - */ -#include <linux/module.h> -#include <linux/kernel.h> -#include <linux/errno.h> -#include <linux/netdevice.h> -#include <linux/init.h> -#include <linux/interrupt.h> -#include <linux/dma-mapping.h> - -#include <asm/ocp.h> - -#include "ibm_emac_core.h" -#include "ibm_emac_mal.h" -#include "ibm_emac_debug.h" - -int __init mal_register_commac(struct ibm_ocp_mal *mal, - struct mal_commac *commac) -{ - unsigned long flags; - local_irq_save(flags); - - MAL_DBG("%d: reg(%08x, %08x)" NL, mal->def->index, - commac->tx_chan_mask, commac->rx_chan_mask); - - /* Don't let multiple commacs claim the same channel(s) */ - if ((mal->tx_chan_mask & commac->tx_chan_mask) || - (mal->rx_chan_mask & commac->rx_chan_mask)) { - local_irq_restore(flags); - printk(KERN_WARNING "mal%d: COMMAC channels conflict!\n", - mal->def->index); - return -EBUSY; - } - - mal->tx_chan_mask |= commac->tx_chan_mask; - mal->rx_chan_mask |= commac->rx_chan_mask; - list_add(&commac->list, &mal->list); - - local_irq_restore(flags); - return 0; -} - -void mal_unregister_commac(struct ibm_ocp_mal *mal, struct mal_commac *commac) -{ - unsigned long flags; - local_irq_save(flags); - - MAL_DBG("%d: unreg(%08x, %08x)" NL, mal->def->index, - commac->tx_chan_mask, commac->rx_chan_mask); - - mal->tx_chan_mask &= ~commac->tx_chan_mask; - mal->rx_chan_mask &= ~commac->rx_chan_mask; - list_del_init(&commac->list); - - local_irq_restore(flags); -} - -int mal_set_rcbs(struct ibm_ocp_mal *mal, int channel, unsigned long size) -{ - struct ocp_func_mal_data *maldata = mal->def->additions; - BUG_ON(channel < 0 || channel >= maldata->num_rx_chans || - size > MAL_MAX_RX_SIZE); - - MAL_DBG("%d: set_rbcs(%d, %lu)" NL, mal->def->index, channel, size); - - if (size & 0xf) { - printk(KERN_WARNING - "mal%d: incorrect RX size %lu for the channel %d\n", - mal->def->index, size, channel); - return -EINVAL; - } - - set_mal_dcrn(mal, MAL_RCBS(channel), size >> 4); - return 0; -} - -int mal_tx_bd_offset(struct ibm_ocp_mal *mal, int channel) -{ - struct ocp_func_mal_data *maldata = mal->def->additions; - BUG_ON(channel < 0 || channel >= maldata->num_tx_chans); - return channel * NUM_TX_BUFF; -} - -int mal_rx_bd_offset(struct ibm_ocp_mal *mal, int channel) -{ - struct ocp_func_mal_data *maldata = mal->def->additions; - BUG_ON(channel < 0 || channel >= maldata->num_rx_chans); - return maldata->num_tx_chans * NUM_TX_BUFF + channel * NUM_RX_BUFF; -} - -void mal_enable_tx_channel(struct ibm_ocp_mal *mal, int channel) -{ - local_bh_disable(); - MAL_DBG("%d: enable_tx(%d)" NL, mal->def->index, channel); - set_mal_dcrn(mal, MAL_TXCASR, - get_mal_dcrn(mal, MAL_TXCASR) | MAL_CHAN_MASK(channel)); - local_bh_enable(); -} - -void mal_disable_tx_channel(struct ibm_ocp_mal *mal, int channel) -{ - set_mal_dcrn(mal, MAL_TXCARR, MAL_CHAN_MASK(channel)); - MAL_DBG("%d: disable_tx(%d)" NL, mal->def->index, channel); -} - -void mal_enable_rx_channel(struct ibm_ocp_mal *mal, int channel) -{ - local_bh_disable(); - MAL_DBG("%d: enable_rx(%d)" NL, mal->def->index, channel); - set_mal_dcrn(mal, MAL_RXCASR, - get_mal_dcrn(mal, MAL_RXCASR) | MAL_CHAN_MASK(channel)); - local_bh_enable(); -} - -void mal_disable_rx_channel(struct ibm_ocp_mal *mal, int channel) -{ - set_mal_dcrn(mal, MAL_RXCARR, MAL_CHAN_MASK(channel)); - MAL_DBG("%d: disable_rx(%d)" NL, mal->def->index, channel); -} - -void mal_poll_add(struct ibm_ocp_mal *mal, struct mal_commac *commac) -{ - local_bh_disable(); - MAL_DBG("%d: poll_add(%p)" NL, mal->def->index, commac); - list_add_tail(&commac->poll_list, &mal->poll_list); - local_bh_enable(); -} - -void mal_poll_del(struct ibm_ocp_mal *mal, struct mal_commac *commac) -{ - local_bh_disable(); - MAL_DBG("%d: poll_del(%p)" NL, mal->def->index, commac); - list_del(&commac->poll_list); - local_bh_enable(); -} - -/* synchronized by mal_poll() */ -static inline void mal_enable_eob_irq(struct ibm_ocp_mal *mal) -{ - MAL_DBG2("%d: enable_irq" NL, mal->def->index); - set_mal_dcrn(mal, MAL_CFG, get_mal_dcrn(mal, MAL_CFG) | MAL_CFG_EOPIE); -} - -/* synchronized by __LINK_STATE_RX_SCHED bit in ndev->state */ -static inline void mal_disable_eob_irq(struct ibm_ocp_mal *mal) -{ - set_mal_dcrn(mal, MAL_CFG, get_mal_dcrn(mal, MAL_CFG) & ~MAL_CFG_EOPIE); - MAL_DBG2("%d: disable_irq" NL, mal->def->index); -} - -static irqreturn_t mal_serr(int irq, void *dev_instance) -{ - struct ibm_ocp_mal *mal = dev_instance; - u32 esr = get_mal_dcrn(mal, MAL_ESR); - - /* Clear the error status register */ - set_mal_dcrn(mal, MAL_ESR, esr); - - MAL_DBG("%d: SERR %08x" NL, mal->def->index, esr); - - if (esr & MAL_ESR_EVB) { - if (esr & MAL_ESR_DE) { - /* We ignore Descriptor error, - * TXDE or RXDE interrupt will be generated anyway. - */ - return IRQ_HANDLED; - } - - if (esr & MAL_ESR_PEIN) { - /* PLB error, it's probably buggy hardware or - * incorrect physical address in BD (i.e. bug) - */ - if (net_ratelimit()) - printk(KERN_ERR - "mal%d: system error, PLB (ESR = 0x%08x)\n", - mal->def->index, esr); - return IRQ_HANDLED; - } - - /* OPB error, it's probably buggy hardware or incorrect EBC setup */ - if (net_ratelimit()) - printk(KERN_ERR - "mal%d: system error, OPB (ESR = 0x%08x)\n", - mal->def->index, esr); - } - return IRQ_HANDLED; -} - -static inline void mal_schedule_poll(struct ibm_ocp_mal *mal) -{ - if (likely(napi_schedule_prep(&mal->napi))) { - MAL_DBG2("%d: schedule_poll" NL, mal->def->index); - mal_disable_eob_irq(mal); - __napi_schedule(&mal->napi); - } else - MAL_DBG2("%d: already in poll" NL, mal->def->index); -} - -static irqreturn_t mal_txeob(int irq, void *dev_instance) -{ - struct ibm_ocp_mal *mal = dev_instance; - u32 r = get_mal_dcrn(mal, MAL_TXEOBISR); - MAL_DBG2("%d: txeob %08x" NL, mal->def->index, r); - mal_schedule_poll(mal); - set_mal_dcrn(mal, MAL_TXEOBISR, r); - return IRQ_HANDLED; -} - -static irqreturn_t mal_rxeob(int irq, void *dev_instance) -{ - struct ibm_ocp_mal *mal = dev_instance; - u32 r = get_mal_dcrn(mal, MAL_RXEOBISR); - MAL_DBG2("%d: rxeob %08x" NL, mal->def->index, r); - mal_schedule_poll(mal); - set_mal_dcrn(mal, MAL_RXEOBISR, r); - return IRQ_HANDLED; -} - -static irqreturn_t mal_txde(int irq, void *dev_instance) -{ - struct ibm_ocp_mal *mal = dev_instance; - u32 deir = get_mal_dcrn(mal, MAL_TXDEIR); - set_mal_dcrn(mal, MAL_TXDEIR, deir); - - MAL_DBG("%d: txde %08x" NL, mal->def->index, deir); - - if (net_ratelimit()) - printk(KERN_ERR - "mal%d: TX descriptor error (TXDEIR = 0x%08x)\n", - mal->def->index, deir); - - return IRQ_HANDLED; -} - -static irqreturn_t mal_rxde(int irq, void *dev_instance) -{ - struct ibm_ocp_mal *mal = dev_instance; - struct list_head *l; - u32 deir = get_mal_dcrn(mal, MAL_RXDEIR); - - MAL_DBG("%d: rxde %08x" NL, mal->def->index, deir); - - list_for_each(l, &mal->list) { - struct mal_commac *mc = list_entry(l, struct mal_commac, list); - if (deir & mc->rx_chan_mask) { - mc->rx_stopped = 1; - mc->ops->rxde(mc->dev); - } - } - - mal_schedule_poll(mal); - set_mal_dcrn(mal, MAL_RXDEIR, deir); - - return IRQ_HANDLED; -} - -static int mal_poll(struct napi_struct *napi, int budget) -{ - struct ibm_ocp_mal *mal = container_of(napi, struct ibm_ocp_mal, napi); - struct list_head *l; - int received = 0; - - MAL_DBG2("%d: poll(%d) %d ->" NL, mal->def->index, *budget, - rx_work_limit); - again: - /* Process TX skbs */ - list_for_each(l, &mal->poll_list) { - struct mal_commac *mc = - list_entry(l, struct mal_commac, poll_list); - mc->ops->poll_tx(mc->dev); - } - - /* Process RX skbs. - * We _might_ need something more smart here to enforce polling fairness. - */ - list_for_each(l, &mal->poll_list) { - struct mal_commac *mc = - list_entry(l, struct mal_commac, poll_list); - int n = mc->ops->poll_rx(mc->dev, budget); - if (n) { - received += n; - budget -= n; - if (budget <= 0) - goto more_work; // XXX What if this is the last one ? - } - } - - /* We need to disable IRQs to protect from RXDE IRQ here */ - local_irq_disable(); - __napi_complete(napi); - mal_enable_eob_irq(mal); - local_irq_enable(); - - /* Check for "rotting" packet(s) */ - list_for_each(l, &mal->poll_list) { - struct mal_commac *mc = - list_entry(l, struct mal_commac, poll_list); - if (unlikely(mc->ops->peek_rx(mc->dev) || mc->rx_stopped)) { - MAL_DBG2("%d: rotting packet" NL, mal->def->index); - if (napi_reschedule(napi)) - mal_disable_eob_irq(mal); - else - MAL_DBG2("%d: already in poll list" NL, - mal->def->index); - - if (budget > 0) - goto again; - else - goto more_work; - } - mc->ops->poll_tx(mc->dev); - } - - more_work: - MAL_DBG2("%d: poll() %d <- %d" NL, mal->def->index, budget, received); - return received; -} - -static void mal_reset(struct ibm_ocp_mal *mal) -{ - int n = 10; - MAL_DBG("%d: reset" NL, mal->def->index); - - set_mal_dcrn(mal, MAL_CFG, MAL_CFG_SR); - - /* Wait for reset to complete (1 system clock) */ - while ((get_mal_dcrn(mal, MAL_CFG) & MAL_CFG_SR) && n) - --n; - - if (unlikely(!n)) - printk(KERN_ERR "mal%d: reset timeout\n", mal->def->index); -} - -int mal_get_regs_len(struct ibm_ocp_mal *mal) -{ - return sizeof(struct emac_ethtool_regs_subhdr) + - sizeof(struct ibm_mal_regs); -} - -void *mal_dump_regs(struct ibm_ocp_mal *mal, void *buf) -{ - struct emac_ethtool_regs_subhdr *hdr = buf; - struct ibm_mal_regs *regs = (struct ibm_mal_regs *)(hdr + 1); - struct ocp_func_mal_data *maldata = mal->def->additions; - int i; - - hdr->version = MAL_VERSION; - hdr->index = mal->def->index; - - regs->tx_count = maldata->num_tx_chans; - regs->rx_count = maldata->num_rx_chans; - - regs->cfg = get_mal_dcrn(mal, MAL_CFG); - regs->esr = get_mal_dcrn(mal, MAL_ESR); - regs->ier = get_mal_dcrn(mal, MAL_IER); - regs->tx_casr = get_mal_dcrn(mal, MAL_TXCASR); - regs->tx_carr = get_mal_dcrn(mal, MAL_TXCARR); - regs->tx_eobisr = get_mal_dcrn(mal, MAL_TXEOBISR); - regs->tx_deir = get_mal_dcrn(mal, MAL_TXDEIR); - regs->rx_casr = get_mal_dcrn(mal, MAL_RXCASR); - regs->rx_carr = get_mal_dcrn(mal, MAL_RXCARR); - regs->rx_eobisr = get_mal_dcrn(mal, MAL_RXEOBISR); - regs->rx_deir = get_mal_dcrn(mal, MAL_RXDEIR); - - for (i = 0; i < regs->tx_count; ++i) - regs->tx_ctpr[i] = get_mal_dcrn(mal, MAL_TXCTPR(i)); - - for (i = 0; i < regs->rx_count; ++i) { - regs->rx_ctpr[i] = get_mal_dcrn(mal, MAL_RXCTPR(i)); - regs->rcbs[i] = get_mal_dcrn(mal, MAL_RCBS(i)); - } - return regs + 1; -} - -static int __init mal_probe(struct ocp_device *ocpdev) -{ - struct ibm_ocp_mal *mal; - struct ocp_func_mal_data *maldata; - int err = 0, i, bd_size; - - MAL_DBG("%d: probe" NL, ocpdev->def->index); - - maldata = ocpdev->def->additions; - if (maldata == NULL) { - printk(KERN_ERR "mal%d: missing additional data!\n", - ocpdev->def->index); - return -ENODEV; - } - - mal = kzalloc(sizeof(struct ibm_ocp_mal), GFP_KERNEL); - if (!mal) { - printk(KERN_ERR - "mal%d: out of memory allocating MAL structure!\n", - ocpdev->def->index); - return -ENOMEM; - } - - /* XXX This only works for native dcr for now */ - mal->dcrhost = dcr_map(NULL, maldata->dcr_base, 0); - - mal->def = ocpdev->def; - - INIT_LIST_HEAD(&mal->poll_list); - mal->napi.weight = CONFIG_IBM_EMAC_POLL_WEIGHT; - mal->napi.poll = mal_poll; - - INIT_LIST_HEAD(&mal->list); - - /* Load power-on reset defaults */ - mal_reset(mal); - - /* Set the MAL configuration register */ - set_mal_dcrn(mal, MAL_CFG, MAL_CFG_DEFAULT | MAL_CFG_PLBB | - MAL_CFG_OPBBL | MAL_CFG_LEA); - - mal_enable_eob_irq(mal); - - /* Allocate space for BD rings */ - BUG_ON(maldata->num_tx_chans <= 0 || maldata->num_tx_chans > 32); - BUG_ON(maldata->num_rx_chans <= 0 || maldata->num_rx_chans > 32); - bd_size = sizeof(struct mal_descriptor) * - (NUM_TX_BUFF * maldata->num_tx_chans + - NUM_RX_BUFF * maldata->num_rx_chans); - mal->bd_virt = - dma_alloc_coherent(&ocpdev->dev, bd_size, &mal->bd_dma, GFP_KERNEL); - - if (!mal->bd_virt) { - printk(KERN_ERR - "mal%d: out of memory allocating RX/TX descriptors!\n", - mal->def->index); - err = -ENOMEM; - goto fail; - } - memset(mal->bd_virt, 0, bd_size); - - for (i = 0; i < maldata->num_tx_chans; ++i) - set_mal_dcrn(mal, MAL_TXCTPR(i), mal->bd_dma + - sizeof(struct mal_descriptor) * - mal_tx_bd_offset(mal, i)); - - for (i = 0; i < maldata->num_rx_chans; ++i) - set_mal_dcrn(mal, MAL_RXCTPR(i), mal->bd_dma + - sizeof(struct mal_descriptor) * - mal_rx_bd_offset(mal, i)); - - err = request_irq(maldata->serr_irq, mal_serr, 0, "MAL SERR", mal); - if (err) - goto fail2; - err = request_irq(maldata->txde_irq, mal_txde, 0, "MAL TX DE", mal); - if (err) - goto fail3; - err = request_irq(maldata->txeob_irq, mal_txeob, 0, "MAL TX EOB", mal); - if (err) - goto fail4; - err = request_irq(maldata->rxde_irq, mal_rxde, 0, "MAL RX DE", mal); - if (err) - goto fail5; - err = request_irq(maldata->rxeob_irq, mal_rxeob, 0, "MAL RX EOB", mal); - if (err) - goto fail6; - - /* Enable all MAL SERR interrupt sources */ - set_mal_dcrn(mal, MAL_IER, MAL_IER_EVENTS); - - /* Advertise this instance to the rest of the world */ - ocp_set_drvdata(ocpdev, mal); - - mal_dbg_register(mal->def->index, mal); - - printk(KERN_INFO "mal%d: initialized, %d TX channels, %d RX channels\n", - mal->def->index, maldata->num_tx_chans, maldata->num_rx_chans); - return 0; - - fail6: - free_irq(maldata->rxde_irq, mal); - fail5: - free_irq(maldata->txeob_irq, mal); - fail4: - free_irq(maldata->txde_irq, mal); - fail3: - free_irq(maldata->serr_irq, mal); - fail2: - dma_free_coherent(&ocpdev->dev, bd_size, mal->bd_virt, mal->bd_dma); - fail: - kfree(mal); - return err; -} - -static void __exit mal_remove(struct ocp_device *ocpdev) -{ - struct ibm_ocp_mal *mal = ocp_get_drvdata(ocpdev); - struct ocp_func_mal_data *maldata = mal->def->additions; - - MAL_DBG("%d: remove" NL, mal->def->index); - - /* Synchronize with scheduled polling */ - napi_disable(&mal->napi); - - if (!list_empty(&mal->list)) { - /* This is *very* bad */ - printk(KERN_EMERG - "mal%d: commac list is not empty on remove!\n", - mal->def->index); - } - - ocp_set_drvdata(ocpdev, NULL); - - free_irq(maldata->serr_irq, mal); - free_irq(maldata->txde_irq, mal); - free_irq(maldata->txeob_irq, mal); - free_irq(maldata->rxde_irq, mal); - free_irq(maldata->rxeob_irq, mal); - - mal_reset(mal); - - mal_dbg_register(mal->def->index, NULL); - - dma_free_coherent(&ocpdev->dev, - sizeof(struct mal_descriptor) * - (NUM_TX_BUFF * maldata->num_tx_chans + - NUM_RX_BUFF * maldata->num_rx_chans), mal->bd_virt, - mal->bd_dma); - - kfree(mal); -} - -/* Structure for a device driver */ -static struct ocp_device_id mal_ids[] = { - { .vendor = OCP_VENDOR_IBM, .function = OCP_FUNC_MAL }, - { .vendor = OCP_VENDOR_INVALID} -}; - -static struct ocp_driver mal_driver = { - .name = "mal", - .id_table = mal_ids, - - .probe = mal_probe, - .remove = mal_remove, -}; - -int __init mal_init(void) -{ - MAL_DBG(": init" NL); - return ocp_register_driver(&mal_driver); -} - -void __exit mal_exit(void) -{ - MAL_DBG(": exit" NL); - ocp_unregister_driver(&mal_driver); -} diff --git a/drivers/net/ibm_emac/ibm_emac_mal.h b/drivers/net/ibm_emac/ibm_emac_mal.h deleted file mode 100644 index b8adbe6d4b01..000000000000 --- a/drivers/net/ibm_emac/ibm_emac_mal.h +++ /dev/null @@ -1,267 +0,0 @@ -/* - * drivers/net/ibm_emac/ibm_emac_mal.h - * - * Memory Access Layer (MAL) support - * - * Copyright (c) 2004, 2005 Zultys Technologies. - * Eugene Surovegin <eugene.surovegin@zultys.com> or <ebs@ebshome.net> - * - * Based on original work by - * Armin Kuster <akuster@mvista.com> - * Copyright 2002 MontaVista Softare Inc. - * - * 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. - * - */ -#ifndef __IBM_EMAC_MAL_H_ -#define __IBM_EMAC_MAL_H_ - -#include <linux/init.h> -#include <linux/list.h> -#include <linux/netdevice.h> - -#include <asm/io.h> -#include <asm/dcr.h> - -/* - * These MAL "versions" probably aren't the real versions IBM uses for these - * MAL cores, I assigned them just to make #ifdefs in this file nicer and - * reflect the fact that 40x and 44x have slightly different MALs. --ebs - */ -#if defined(CONFIG_405GP) || defined(CONFIG_405GPR) || defined(CONFIG_405EP) || \ - defined(CONFIG_440EP) || defined(CONFIG_440GR) || defined(CONFIG_NP405H) -#define MAL_VERSION 1 -#elif defined(CONFIG_440GP) || defined(CONFIG_440GX) || defined(CONFIG_440SP) || \ - defined(CONFIG_440SPE) -#define MAL_VERSION 2 -#else -#error "Unknown SoC, please check chip manual and choose MAL 'version'" -#endif - -/* MALx DCR registers */ -#define MAL_CFG 0x00 -#define MAL_CFG_SR 0x80000000 -#define MAL_CFG_PLBB 0x00004000 -#define MAL_CFG_OPBBL 0x00000080 -#define MAL_CFG_EOPIE 0x00000004 -#define MAL_CFG_LEA 0x00000002 -#define MAL_CFG_SD 0x00000001 -#if MAL_VERSION == 1 -#define MAL_CFG_PLBP_MASK 0x00c00000 -#define MAL_CFG_PLBP_10 0x00800000 -#define MAL_CFG_GA 0x00200000 -#define MAL_CFG_OA 0x00100000 -#define MAL_CFG_PLBLE 0x00080000 -#define MAL_CFG_PLBT_MASK 0x00078000 -#define MAL_CFG_DEFAULT (MAL_CFG_PLBP_10 | MAL_CFG_PLBT_MASK) -#elif MAL_VERSION == 2 -#define MAL_CFG_RPP_MASK 0x00c00000 -#define MAL_CFG_RPP_10 0x00800000 -#define MAL_CFG_RMBS_MASK 0x00300000 -#define MAL_CFG_WPP_MASK 0x000c0000 -#define MAL_CFG_WPP_10 0x00080000 -#define MAL_CFG_WMBS_MASK 0x00030000 -#define MAL_CFG_PLBLE 0x00008000 -#define MAL_CFG_DEFAULT (MAL_CFG_RMBS_MASK | MAL_CFG_WMBS_MASK | \ - MAL_CFG_RPP_10 | MAL_CFG_WPP_10) -#else -#error "Unknown MAL version" -#endif - -#define MAL_ESR 0x01 -#define MAL_ESR_EVB 0x80000000 -#define MAL_ESR_CIDT 0x40000000 -#define MAL_ESR_CID_MASK 0x3e000000 -#define MAL_ESR_CID_SHIFT 25 -#define MAL_ESR_DE 0x00100000 -#define MAL_ESR_OTE 0x00040000 -#define MAL_ESR_OSE 0x00020000 -#define MAL_ESR_PEIN 0x00010000 -#define MAL_ESR_DEI 0x00000010 -#define MAL_ESR_OTEI 0x00000004 -#define MAL_ESR_OSEI 0x00000002 -#define MAL_ESR_PBEI 0x00000001 -#if MAL_VERSION == 1 -#define MAL_ESR_ONE 0x00080000 -#define MAL_ESR_ONEI 0x00000008 -#elif MAL_VERSION == 2 -#define MAL_ESR_PTE 0x00800000 -#define MAL_ESR_PRE 0x00400000 -#define MAL_ESR_PWE 0x00200000 -#define MAL_ESR_PTEI 0x00000080 -#define MAL_ESR_PREI 0x00000040 -#define MAL_ESR_PWEI 0x00000020 -#else -#error "Unknown MAL version" -#endif - -#define MAL_IER 0x02 -#define MAL_IER_DE 0x00000010 -#define MAL_IER_OTE 0x00000004 -#define MAL_IER_OE 0x00000002 -#define MAL_IER_PE 0x00000001 -#if MAL_VERSION == 1 -#define MAL_IER_NWE 0x00000008 -#define MAL_IER_SOC_EVENTS MAL_IER_NWE -#elif MAL_VERSION == 2 -#define MAL_IER_PT 0x00000080 -#define MAL_IER_PRE 0x00000040 -#define MAL_IER_PWE 0x00000020 -#define MAL_IER_SOC_EVENTS (MAL_IER_PT | MAL_IER_PRE | MAL_IER_PWE) -#else -#error "Unknown MAL version" -#endif -#define MAL_IER_EVENTS (MAL_IER_SOC_EVENTS | MAL_IER_OTE | \ - MAL_IER_OTE | MAL_IER_OE | MAL_IER_PE) - -#define MAL_TXCASR 0x04 -#define MAL_TXCARR 0x05 -#define MAL_TXEOBISR 0x06 -#define MAL_TXDEIR 0x07 -#define MAL_RXCASR 0x10 -#define MAL_RXCARR 0x11 -#define MAL_RXEOBISR 0x12 -#define MAL_RXDEIR 0x13 -#define MAL_TXCTPR(n) ((n) + 0x20) -#define MAL_RXCTPR(n) ((n) + 0x40) -#define MAL_RCBS(n) ((n) + 0x60) - -/* In reality MAL can handle TX buffers up to 4095 bytes long, - * but this isn't a good round number :) --ebs - */ -#define MAL_MAX_TX_SIZE 4080 -#define MAL_MAX_RX_SIZE 4080 - -static inline int mal_rx_size(int len) -{ - len = (len + 0xf) & ~0xf; - return len > MAL_MAX_RX_SIZE ? MAL_MAX_RX_SIZE : len; -} - -static inline int mal_tx_chunks(int len) -{ - return (len + MAL_MAX_TX_SIZE - 1) / MAL_MAX_TX_SIZE; -} - -#define MAL_CHAN_MASK(n) (0x80000000 >> (n)) - -/* MAL Buffer Descriptor structure */ -struct mal_descriptor { - u16 ctrl; /* MAL / Commac status control bits */ - u16 data_len; /* Max length is 4K-1 (12 bits) */ - u32 data_ptr; /* pointer to actual data buffer */ -}; - -/* the following defines are for the MadMAL status and control registers. */ -/* MADMAL transmit and receive status/control bits */ -#define MAL_RX_CTRL_EMPTY 0x8000 -#define MAL_RX_CTRL_WRAP 0x4000 -#define MAL_RX_CTRL_CM 0x2000 -#define MAL_RX_CTRL_LAST 0x1000 -#define MAL_RX_CTRL_FIRST 0x0800 -#define MAL_RX_CTRL_INTR 0x0400 -#define MAL_RX_CTRL_SINGLE (MAL_RX_CTRL_LAST | MAL_RX_CTRL_FIRST) -#define MAL_IS_SINGLE_RX(ctrl) (((ctrl) & MAL_RX_CTRL_SINGLE) == MAL_RX_CTRL_SINGLE) - -#define MAL_TX_CTRL_READY 0x8000 -#define MAL_TX_CTRL_WRAP 0x4000 -#define MAL_TX_CTRL_CM 0x2000 -#define MAL_TX_CTRL_LAST 0x1000 -#define MAL_TX_CTRL_INTR 0x0400 - -struct mal_commac_ops { - void (*poll_tx) (void *dev); - int (*poll_rx) (void *dev, int budget); - int (*peek_rx) (void *dev); - void (*rxde) (void *dev); -}; - -struct mal_commac { - struct mal_commac_ops *ops; - void *dev; - struct list_head poll_list; - int rx_stopped; - - u32 tx_chan_mask; - u32 rx_chan_mask; - struct list_head list; -}; - -struct ibm_ocp_mal { - dcr_host_t dcrhost; - - struct list_head poll_list; - struct napi_struct napi; - - struct list_head list; - u32 tx_chan_mask; - u32 rx_chan_mask; - - dma_addr_t bd_dma; - struct mal_descriptor *bd_virt; - - struct ocp_def *def; -}; - -static inline u32 get_mal_dcrn(struct ibm_ocp_mal *mal, int reg) -{ - return dcr_read(mal->dcrhost, reg); -} - -static inline void set_mal_dcrn(struct ibm_ocp_mal *mal, int reg, u32 val) -{ - dcr_write(mal->dcrhost, reg, val); -} - -/* Register MAL devices */ -int mal_init(void) __init; -void mal_exit(void) __exit; - -int mal_register_commac(struct ibm_ocp_mal *mal, - struct mal_commac *commac) __init; -void mal_unregister_commac(struct ibm_ocp_mal *mal, struct mal_commac *commac); -int mal_set_rcbs(struct ibm_ocp_mal *mal, int channel, unsigned long size); - -/* Returns BD ring offset for a particular channel - (in 'struct mal_descriptor' elements) -*/ -int mal_tx_bd_offset(struct ibm_ocp_mal *mal, int channel); -int mal_rx_bd_offset(struct ibm_ocp_mal *mal, int channel); - -void mal_enable_tx_channel(struct ibm_ocp_mal *mal, int channel); -void mal_disable_tx_channel(struct ibm_ocp_mal *mal, int channel); -void mal_enable_rx_channel(struct ibm_ocp_mal *mal, int channel); -void mal_disable_rx_channel(struct ibm_ocp_mal *mal, int channel); - -/* Add/remove EMAC to/from MAL polling list */ -void mal_poll_add(struct ibm_ocp_mal *mal, struct mal_commac *commac); -void mal_poll_del(struct ibm_ocp_mal *mal, struct mal_commac *commac); - -/* Ethtool MAL registers */ -struct ibm_mal_regs { - u32 tx_count; - u32 rx_count; - - u32 cfg; - u32 esr; - u32 ier; - u32 tx_casr; - u32 tx_carr; - u32 tx_eobisr; - u32 tx_deir; - u32 rx_casr; - u32 rx_carr; - u32 rx_eobisr; - u32 rx_deir; - u32 tx_ctpr[32]; - u32 rx_ctpr[32]; - u32 rcbs[32]; -}; - -int mal_get_regs_len(struct ibm_ocp_mal *mal); -void *mal_dump_regs(struct ibm_ocp_mal *mal, void *buf); - -#endif /* __IBM_EMAC_MAL_H_ */ diff --git a/drivers/net/ibm_emac/ibm_emac_phy.c b/drivers/net/ibm_emac/ibm_emac_phy.c deleted file mode 100644 index e57862b34cae..000000000000 --- a/drivers/net/ibm_emac/ibm_emac_phy.c +++ /dev/null @@ -1,398 +0,0 @@ -/* - * drivers/net/ibm_emac/ibm_emac_phy.c - * - * Driver for PowerPC 4xx on-chip ethernet controller, PHY support. - * Borrowed from sungem_phy.c, though I only kept the generic MII - * driver for now. - * - * This file should be shared with other drivers or eventually - * merged as the "low level" part of miilib - * - * (c) 2003, Benjamin Herrenscmidt (benh@kernel.crashing.org) - * (c) 2004-2005, Eugene Surovegin <ebs@ebshome.net> - * - */ -#include <linux/module.h> -#include <linux/kernel.h> -#include <linux/types.h> -#include <linux/netdevice.h> -#include <linux/mii.h> -#include <linux/ethtool.h> -#include <linux/delay.h> - -#include <asm/ocp.h> - -#include "ibm_emac_core.h" -#include "ibm_emac_phy.h" - -static inline int phy_read(struct mii_phy *phy, int reg) -{ - return phy->mdio_read(phy->dev, phy->address, reg); -} - -static inline void phy_write(struct mii_phy *phy, int reg, int val) -{ - phy->mdio_write(phy->dev, phy->address, reg, val); -} - -/* - * polls MII_BMCR until BMCR_RESET bit clears or operation times out. - * - * returns: - * >= 0 => success, value in BMCR returned to caller - * -EBUSY => failure, RESET bit never cleared - * otherwise => failure, lower level PHY read failed - */ -static int mii_spin_reset_complete(struct mii_phy *phy) -{ - int val; - int limit = 10000; - - while (limit--) { - val = phy_read(phy, MII_BMCR); - if (val >= 0 && !(val & BMCR_RESET)) - return val; /* success */ - udelay(10); - } - if (val & BMCR_RESET) - val = -EBUSY; - - if (net_ratelimit()) - printk(KERN_ERR "emac%d: PHY reset timeout (%d)\n", - ((struct ocp_enet_private *)phy->dev->priv)->def->index, - val); - return val; -} - -int mii_reset_phy(struct mii_phy *phy) -{ - int val; - - val = phy_read(phy, MII_BMCR); - val &= ~BMCR_ISOLATE; - val |= BMCR_RESET; - phy_write(phy, MII_BMCR, val); - - udelay(300); - - val = mii_spin_reset_complete(phy); - if (val >= 0 && (val & BMCR_ISOLATE)) - phy_write(phy, MII_BMCR, val & ~BMCR_ISOLATE); - - return val < 0; -} - -static int genmii_setup_aneg(struct mii_phy *phy, u32 advertise) -{ - int ctl, adv; - - phy->autoneg = AUTONEG_ENABLE; - phy->speed = SPEED_10; - phy->duplex = DUPLEX_HALF; - phy->pause = phy->asym_pause = 0; - phy->advertising = advertise; - - /* Setup standard advertise */ - adv = phy_read(phy, MII_ADVERTISE); - if (adv < 0) - return adv; - adv &= ~(ADVERTISE_ALL | ADVERTISE_100BASE4 | ADVERTISE_PAUSE_CAP | - ADVERTISE_PAUSE_ASYM); - if (advertise & ADVERTISED_10baseT_Half) - adv |= ADVERTISE_10HALF; - if (advertise & ADVERTISED_10baseT_Full) - adv |= ADVERTISE_10FULL; - if (advertise & ADVERTISED_100baseT_Half) - adv |= ADVERTISE_100HALF; - if (advertise & ADVERTISED_100baseT_Full) - adv |= ADVERTISE_100FULL; - if (advertise & ADVERTISED_Pause) - adv |= ADVERTISE_PAUSE_CAP; - if (advertise & ADVERTISED_Asym_Pause) - adv |= ADVERTISE_PAUSE_ASYM; - phy_write(phy, MII_ADVERTISE, adv); - - if (phy->features & - (SUPPORTED_1000baseT_Full | SUPPORTED_1000baseT_Half)) { - adv = phy_read(phy, MII_CTRL1000); - if (adv < 0) - return adv; - adv &= ~(ADVERTISE_1000FULL | ADVERTISE_1000HALF); - if (advertise & ADVERTISED_1000baseT_Full) - adv |= ADVERTISE_1000FULL; - if (advertise & ADVERTISED_1000baseT_Half) - adv |= ADVERTISE_1000HALF; - phy_write(phy, MII_CTRL1000, adv); - } - - /* Start/Restart aneg */ - /* on some PHYs (e.g. National DP83843) a write to MII_ADVERTISE - * causes BMCR_RESET to be set on the next read of MII_BMCR, which - * if not checked for causes the PHY to be reset below */ - ctl = mii_spin_reset_complete(phy); - if (ctl < 0) - return ctl; - - ctl |= BMCR_ANENABLE | BMCR_ANRESTART; - phy_write(phy, MII_BMCR, ctl); - - return 0; -} - -static int genmii_setup_forced(struct mii_phy *phy, int speed, int fd) -{ - int ctl; - - phy->autoneg = AUTONEG_DISABLE; - phy->speed = speed; - phy->duplex = fd; - phy->pause = phy->asym_pause = 0; - - /* First reset the PHY */ - mii_reset_phy(phy); - - ctl = phy_read(phy, MII_BMCR); - if (ctl < 0) - return ctl; - ctl &= ~(BMCR_FULLDPLX | BMCR_SPEED100 | BMCR_ANENABLE | BMCR_SPEED1000); - - /* Select speed & duplex */ - switch (speed) { - case SPEED_10: - break; - case SPEED_100: - ctl |= BMCR_SPEED100; - break; - case SPEED_1000: - ctl |= BMCR_SPEED1000; - break; - default: - return -EINVAL; - } - if (fd == DUPLEX_FULL) - ctl |= BMCR_FULLDPLX; - phy_write(phy, MII_BMCR, ctl); - - return 0; -} - -static int genmii_poll_link(struct mii_phy *phy) -{ - int status; - - /* Clear latched value with dummy read */ - phy_read(phy, MII_BMSR); - status = phy_read(phy, MII_BMSR); - if (status < 0 || (status & BMSR_LSTATUS) == 0) - return 0; - if (phy->autoneg == AUTONEG_ENABLE && !(status & BMSR_ANEGCOMPLETE)) - return 0; - return 1; -} - -static int genmii_read_link(struct mii_phy *phy) -{ - if (phy->autoneg == AUTONEG_ENABLE) { - int glpa = 0; - int lpa = phy_read(phy, MII_LPA) & phy_read(phy, MII_ADVERTISE); - if (lpa < 0) - return lpa; - - if (phy->features & - (SUPPORTED_1000baseT_Full | SUPPORTED_1000baseT_Half)) { - int adv = phy_read(phy, MII_CTRL1000); - glpa = phy_read(phy, MII_STAT1000); - - if (glpa < 0 || adv < 0) - return adv; - - glpa &= adv << 2; - } - - phy->speed = SPEED_10; - phy->duplex = DUPLEX_HALF; - phy->pause = phy->asym_pause = 0; - - if (glpa & (LPA_1000FULL | LPA_1000HALF)) { - phy->speed = SPEED_1000; - if (glpa & LPA_1000FULL) - phy->duplex = DUPLEX_FULL; - } else if (lpa & (LPA_100FULL | LPA_100HALF)) { - phy->speed = SPEED_100; - if (lpa & LPA_100FULL) - phy->duplex = DUPLEX_FULL; - } else if (lpa & LPA_10FULL) - phy->duplex = DUPLEX_FULL; - - if (phy->duplex == DUPLEX_FULL) { - phy->pause = lpa & LPA_PAUSE_CAP ? 1 : 0; - phy->asym_pause = lpa & LPA_PAUSE_ASYM ? 1 : 0; - } - } else { - int bmcr = phy_read(phy, MII_BMCR); - if (bmcr < 0) - return bmcr; - - if (bmcr & BMCR_FULLDPLX) - phy->duplex = DUPLEX_FULL; - else - phy->duplex = DUPLEX_HALF; - if (bmcr & BMCR_SPEED1000) - phy->speed = SPEED_1000; - else if (bmcr & BMCR_SPEED100) - phy->speed = SPEED_100; - else - phy->speed = SPEED_10; - - phy->pause = phy->asym_pause = 0; - } - return 0; -} - -/* Generic implementation for most 10/100/1000 PHYs */ -static struct mii_phy_ops generic_phy_ops = { - .setup_aneg = genmii_setup_aneg, - .setup_forced = genmii_setup_forced, - .poll_link = genmii_poll_link, - .read_link = genmii_read_link -}; - -static struct mii_phy_def genmii_phy_def = { - .phy_id = 0x00000000, - .phy_id_mask = 0x00000000, - .name = "Generic MII", - .ops = &generic_phy_ops -}; - -/* CIS8201 */ -#define MII_CIS8201_10BTCSR 0x16 -#define TENBTCSR_ECHO_DISABLE 0x2000 -#define MII_CIS8201_EPCR 0x17 -#define EPCR_MODE_MASK 0x3000 -#define EPCR_GMII_MODE 0x0000 -#define EPCR_RGMII_MODE 0x1000 -#define EPCR_TBI_MODE 0x2000 -#define EPCR_RTBI_MODE 0x3000 -#define MII_CIS8201_ACSR 0x1c -#define ACSR_PIN_PRIO_SELECT 0x0004 - -static int cis8201_init(struct mii_phy *phy) -{ - int epcr; - - epcr = phy_read(phy, MII_CIS8201_EPCR); - if (epcr < 0) - return epcr; - - epcr &= ~EPCR_MODE_MASK; - - switch (phy->mode) { - case PHY_MODE_TBI: - epcr |= EPCR_TBI_MODE; - break; - case PHY_MODE_RTBI: - epcr |= EPCR_RTBI_MODE; - break; - case PHY_MODE_GMII: - epcr |= EPCR_GMII_MODE; - break; - case PHY_MODE_RGMII: - default: - epcr |= EPCR_RGMII_MODE; - } - - phy_write(phy, MII_CIS8201_EPCR, epcr); - - /* MII regs override strap pins */ - phy_write(phy, MII_CIS8201_ACSR, - phy_read(phy, MII_CIS8201_ACSR) | ACSR_PIN_PRIO_SELECT); - - /* Disable TX_EN -> CRS echo mode, otherwise 10/HDX doesn't work */ - phy_write(phy, MII_CIS8201_10BTCSR, - phy_read(phy, MII_CIS8201_10BTCSR) | TENBTCSR_ECHO_DISABLE); - - return 0; -} - -static struct mii_phy_ops cis8201_phy_ops = { - .init = cis8201_init, - .setup_aneg = genmii_setup_aneg, - .setup_forced = genmii_setup_forced, - .poll_link = genmii_poll_link, - .read_link = genmii_read_link -}; - -static struct mii_phy_def cis8201_phy_def = { - .phy_id = 0x000fc410, - .phy_id_mask = 0x000ffff0, - .name = "CIS8201 Gigabit Ethernet", - .ops = &cis8201_phy_ops -}; - -static struct mii_phy_def *mii_phy_table[] = { - &cis8201_phy_def, - &genmii_phy_def, - NULL -}; - -int mii_phy_probe(struct mii_phy *phy, int address) -{ - struct mii_phy_def *def; - int i; - int id; - - phy->autoneg = AUTONEG_DISABLE; - phy->advertising = 0; - phy->address = address; - phy->speed = SPEED_10; - phy->duplex = DUPLEX_HALF; - phy->pause = phy->asym_pause = 0; - - /* Take PHY out of isolate mode and reset it. */ - if (mii_reset_phy(phy)) - return -ENODEV; - - /* Read ID and find matching entry */ - id = (phy_read(phy, MII_PHYSID1) << 16) | phy_read(phy, MII_PHYSID2); - if (id < 0) - return -ENODEV; - for (i = 0; (def = mii_phy_table[i]) != NULL; i++) - if ((id & def->phy_id_mask) == def->phy_id) - break; - /* Should never be NULL (we have a generic entry), but... */ - if (!def) - return -ENODEV; - - phy->def = def; - - /* Determine PHY features if needed */ - phy->features = def->features; - if (!phy->features) { - u16 bmsr = phy_read(phy, MII_BMSR); - if (bmsr & BMSR_ANEGCAPABLE) - phy->features |= SUPPORTED_Autoneg; - if (bmsr & BMSR_10HALF) - phy->features |= SUPPORTED_10baseT_Half; - if (bmsr & BMSR_10FULL) - phy->features |= SUPPORTED_10baseT_Full; - if (bmsr & BMSR_100HALF) - phy->features |= SUPPORTED_100baseT_Half; - if (bmsr & BMSR_100FULL) - phy->features |= SUPPORTED_100baseT_Full; - if (bmsr & BMSR_ESTATEN) { - u16 esr = phy_read(phy, MII_ESTATUS); - if (esr & ESTATUS_1000_TFULL) - phy->features |= SUPPORTED_1000baseT_Full; - if (esr & ESTATUS_1000_THALF) - phy->features |= SUPPORTED_1000baseT_Half; - } - phy->features |= SUPPORTED_MII; - } - - /* Setup default advertising */ - phy->advertising = phy->features; - - return 0; -} - -MODULE_LICENSE("GPL"); diff --git a/drivers/net/ibm_emac/ibm_emac_phy.h b/drivers/net/ibm_emac/ibm_emac_phy.h deleted file mode 100644 index a70e0fea54c4..000000000000 --- a/drivers/net/ibm_emac/ibm_emac_phy.h +++ /dev/null @@ -1,80 +0,0 @@ -/* - * drivers/net/ibm_emac/ibm_emac_phy.h - * - * Driver for PowerPC 4xx on-chip ethernet controller, PHY support - * - * Benjamin Herrenschmidt <benh@kernel.crashing.org> - * February 2003 - * - * Minor additions by Eugene Surovegin <ebs@ebshome.net>, 2004 - * - * 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 file basically duplicates sungem_phy.{c,h} with different PHYs - * supported. I'm looking into merging that in a single mii layer more - * flexible than mii.c - */ - -#ifndef _IBM_OCP_PHY_H_ -#define _IBM_OCP_PHY_H_ - -struct mii_phy; - -/* Operations supported by any kind of PHY */ -struct mii_phy_ops { - int (*init) (struct mii_phy * phy); - int (*suspend) (struct mii_phy * phy, int wol_options); - int (*setup_aneg) (struct mii_phy * phy, u32 advertise); - int (*setup_forced) (struct mii_phy * phy, int speed, int fd); - int (*poll_link) (struct mii_phy * phy); - int (*read_link) (struct mii_phy * phy); -}; - -/* Structure used to statically define an mii/gii based PHY */ -struct mii_phy_def { - u32 phy_id; /* Concatenated ID1 << 16 | ID2 */ - u32 phy_id_mask; /* Significant bits */ - u32 features; /* Ethtool SUPPORTED_* defines or - 0 for autodetect */ - int magic_aneg; /* Autoneg does all speed test for us */ - const char *name; - const struct mii_phy_ops *ops; -}; - -/* An instance of a PHY, partially borrowed from mii_if_info */ -struct mii_phy { - struct mii_phy_def *def; - u32 advertising; /* Ethtool ADVERTISED_* defines */ - u32 features; /* Copied from mii_phy_def.features - or determined automaticaly */ - int address; /* PHY address */ - int mode; /* PHY mode */ - - /* 1: autoneg enabled, 0: disabled */ - int autoneg; - - /* forced speed & duplex (no autoneg) - * partner speed & duplex & pause (autoneg) - */ - int speed; - int duplex; - int pause; - int asym_pause; - - /* Provided by host chip */ - struct net_device *dev; - int (*mdio_read) (struct net_device * dev, int addr, int reg); - void (*mdio_write) (struct net_device * dev, int addr, int reg, - int val); -}; - -/* Pass in a struct mii_phy with dev, mdio_read and mdio_write - * filled, the remaining fields will be filled on return - */ -int mii_phy_probe(struct mii_phy *phy, int address); -int mii_reset_phy(struct mii_phy *phy); - -#endif /* _IBM_OCP_PHY_H_ */ diff --git a/drivers/net/ibm_emac/ibm_emac_rgmii.c b/drivers/net/ibm_emac/ibm_emac_rgmii.c deleted file mode 100644 index 9dbb5e5936c3..000000000000 --- a/drivers/net/ibm_emac/ibm_emac_rgmii.c +++ /dev/null @@ -1,200 +0,0 @@ -/* - * drivers/net/ibm_emac/ibm_emac_rgmii.c - * - * Driver for PowerPC 4xx on-chip ethernet controller, RGMII bridge support. - * - * Copyright (c) 2004, 2005 Zultys Technologies. - * Eugene Surovegin <eugene.surovegin@zultys.com> or <ebs@ebshome.net> - * - * Based on original work by - * Matt Porter <mporter@kernel.crashing.org> - * Copyright 2004 MontaVista Software, Inc. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - */ -#include <linux/kernel.h> -#include <linux/ethtool.h> -#include <asm/io.h> - -#include "ibm_emac_core.h" -#include "ibm_emac_debug.h" - -/* RGMIIx_FER */ -#define RGMII_FER_MASK(idx) (0x7 << ((idx) * 4)) -#define RGMII_FER_RTBI(idx) (0x4 << ((idx) * 4)) -#define RGMII_FER_RGMII(idx) (0x5 << ((idx) * 4)) -#define RGMII_FER_TBI(idx) (0x6 << ((idx) * 4)) -#define RGMII_FER_GMII(idx) (0x7 << ((idx) * 4)) - -/* RGMIIx_SSR */ -#define RGMII_SSR_MASK(idx) (0x7 << ((idx) * 8)) -#define RGMII_SSR_100(idx) (0x2 << ((idx) * 8)) -#define RGMII_SSR_1000(idx) (0x4 << ((idx) * 8)) - -/* RGMII bridge supports only GMII/TBI and RGMII/RTBI PHYs */ -static inline int rgmii_valid_mode(int phy_mode) -{ - return phy_mode == PHY_MODE_GMII || - phy_mode == PHY_MODE_RGMII || - phy_mode == PHY_MODE_TBI || - phy_mode == PHY_MODE_RTBI; -} - -static inline const char *rgmii_mode_name(int mode) -{ - switch (mode) { - case PHY_MODE_RGMII: - return "RGMII"; - case PHY_MODE_TBI: - return "TBI"; - case PHY_MODE_GMII: - return "GMII"; - case PHY_MODE_RTBI: - return "RTBI"; - default: - BUG(); - } -} - -static inline u32 rgmii_mode_mask(int mode, int input) -{ - switch (mode) { - case PHY_MODE_RGMII: - return RGMII_FER_RGMII(input); - case PHY_MODE_TBI: - return RGMII_FER_TBI(input); - case PHY_MODE_GMII: - return RGMII_FER_GMII(input); - case PHY_MODE_RTBI: - return RGMII_FER_RTBI(input); - default: - BUG(); - } -} - -static int __init rgmii_init(struct ocp_device *ocpdev, int input, int mode) -{ - struct ibm_ocp_rgmii *dev = ocp_get_drvdata(ocpdev); - struct rgmii_regs *p; - - RGMII_DBG("%d: init(%d, %d)" NL, ocpdev->def->index, input, mode); - - if (!dev) { - dev = kzalloc(sizeof(struct ibm_ocp_rgmii), GFP_KERNEL); - if (!dev) { - printk(KERN_ERR - "rgmii%d: couldn't allocate device structure!\n", - ocpdev->def->index); - return -ENOMEM; - } - - p = (struct rgmii_regs *)ioremap(ocpdev->def->paddr, - sizeof(struct rgmii_regs)); - if (!p) { - printk(KERN_ERR - "rgmii%d: could not ioremap device registers!\n", - ocpdev->def->index); - kfree(dev); - return -ENOMEM; - } - - dev->base = p; - ocp_set_drvdata(ocpdev, dev); - - /* Disable all inputs by default */ - out_be32(&p->fer, 0); - } else - p = dev->base; - - /* Enable this input */ - out_be32(&p->fer, in_be32(&p->fer) | rgmii_mode_mask(mode, input)); - - printk(KERN_NOTICE "rgmii%d: input %d in %s mode\n", - ocpdev->def->index, input, rgmii_mode_name(mode)); - - ++dev->users; - return 0; -} - -int __init rgmii_attach(void *emac) -{ - struct ocp_enet_private *dev = emac; - struct ocp_func_emac_data *emacdata = dev->def->additions; - - /* Check if we need to attach to a RGMII */ - if (emacdata->rgmii_idx >= 0 && rgmii_valid_mode(emacdata->phy_mode)) { - dev->rgmii_input = emacdata->rgmii_mux; - dev->rgmii_dev = - ocp_find_device(OCP_VENDOR_IBM, OCP_FUNC_RGMII, - emacdata->rgmii_idx); - if (!dev->rgmii_dev) { - printk(KERN_ERR "emac%d: unknown rgmii%d!\n", - dev->def->index, emacdata->rgmii_idx); - return -ENODEV; - } - if (rgmii_init - (dev->rgmii_dev, dev->rgmii_input, emacdata->phy_mode)) { - printk(KERN_ERR - "emac%d: rgmii%d initialization failed!\n", - dev->def->index, emacdata->rgmii_idx); - return -ENODEV; - } - } - return 0; -} - -void rgmii_set_speed(struct ocp_device *ocpdev, int input, int speed) -{ - struct ibm_ocp_rgmii *dev = ocp_get_drvdata(ocpdev); - u32 ssr = in_be32(&dev->base->ssr) & ~RGMII_SSR_MASK(input); - - RGMII_DBG("%d: speed(%d, %d)" NL, ocpdev->def->index, input, speed); - - if (speed == SPEED_1000) - ssr |= RGMII_SSR_1000(input); - else if (speed == SPEED_100) - ssr |= RGMII_SSR_100(input); - - out_be32(&dev->base->ssr, ssr); -} - -void __rgmii_fini(struct ocp_device *ocpdev, int input) -{ - struct ibm_ocp_rgmii *dev = ocp_get_drvdata(ocpdev); - BUG_ON(!dev || dev->users == 0); - - RGMII_DBG("%d: fini(%d)" NL, ocpdev->def->index, input); - - /* Disable this input */ - out_be32(&dev->base->fer, - in_be32(&dev->base->fer) & ~RGMII_FER_MASK(input)); - - if (!--dev->users) { - /* Free everything if this is the last user */ - ocp_set_drvdata(ocpdev, NULL); - iounmap((void *)dev->base); - kfree(dev); - } -} - -int __rgmii_get_regs_len(struct ocp_device *ocpdev) -{ - return sizeof(struct emac_ethtool_regs_subhdr) + - sizeof(struct rgmii_regs); -} - -void *rgmii_dump_regs(struct ocp_device *ocpdev, void *buf) -{ - struct ibm_ocp_rgmii *dev = ocp_get_drvdata(ocpdev); - struct emac_ethtool_regs_subhdr *hdr = buf; - struct rgmii_regs *regs = (struct rgmii_regs *)(hdr + 1); - - hdr->version = 0; - hdr->index = ocpdev->def->index; - memcpy_fromio(regs, dev->base, sizeof(struct rgmii_regs)); - return regs + 1; -} diff --git a/drivers/net/ibm_emac/ibm_emac_rgmii.h b/drivers/net/ibm_emac/ibm_emac_rgmii.h deleted file mode 100644 index 971e45815c6c..000000000000 --- a/drivers/net/ibm_emac/ibm_emac_rgmii.h +++ /dev/null @@ -1,64 +0,0 @@ -/* - * drivers/net/ibm_emac/ibm_emac_rgmii.h - * - * Driver for PowerPC 4xx on-chip ethernet controller, RGMII bridge support. - * - * Based on ocp_zmii.h/ibm_emac_zmii.h - * Armin Kuster akuster@mvista.com - * - * Copyright 2004 MontaVista Software, Inc. - * Matt Porter <mporter@kernel.crashing.org> - * - * Copyright (c) 2004, 2005 Zultys Technologies. - * Eugene Surovegin <eugene.surovegin@zultys.com> or <ebs@ebshome.net> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - */ - -#ifndef _IBM_EMAC_RGMII_H_ -#define _IBM_EMAC_RGMII_H_ - - -/* RGMII bridge */ -struct rgmii_regs { - u32 fer; /* Function enable register */ - u32 ssr; /* Speed select register */ -}; - -/* RGMII device */ -struct ibm_ocp_rgmii { - struct rgmii_regs __iomem *base; - int users; /* number of EMACs using this RGMII bridge */ -}; - -#ifdef CONFIG_IBM_EMAC_RGMII -int rgmii_attach(void *emac) __init; - -void __rgmii_fini(struct ocp_device *ocpdev, int input); -static inline void rgmii_fini(struct ocp_device *ocpdev, int input) -{ - if (ocpdev) - __rgmii_fini(ocpdev, input); -} - -void rgmii_set_speed(struct ocp_device *ocpdev, int input, int speed); - -int __rgmii_get_regs_len(struct ocp_device *ocpdev); -static inline int rgmii_get_regs_len(struct ocp_device *ocpdev) -{ - return ocpdev ? __rgmii_get_regs_len(ocpdev) : 0; -} - -void *rgmii_dump_regs(struct ocp_device *ocpdev, void *buf); -#else -# define rgmii_attach(x) 0 -# define rgmii_fini(x,y) ((void)0) -# define rgmii_set_speed(x,y,z) ((void)0) -# define rgmii_get_regs_len(x) 0 -# define rgmii_dump_regs(x,buf) (buf) -#endif /* !CONFIG_IBM_EMAC_RGMII */ - -#endif /* _IBM_EMAC_RGMII_H_ */ diff --git a/drivers/net/ibm_emac/ibm_emac_tah.c b/drivers/net/ibm_emac/ibm_emac_tah.c deleted file mode 100644 index 3c2d5ba522a1..000000000000 --- a/drivers/net/ibm_emac/ibm_emac_tah.c +++ /dev/null @@ -1,110 +0,0 @@ -/* - * drivers/net/ibm_emac/ibm_emac_tah.c - * - * Driver for PowerPC 4xx on-chip ethernet controller, TAH support. - * - * Copyright 2004 MontaVista Software, Inc. - * Matt Porter <mporter@kernel.crashing.org> - * - * Copyright (c) 2005 Eugene Surovegin <ebs@ebshome.net> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - */ -#include <asm/io.h> - -#include "ibm_emac_core.h" - -static int __init tah_init(struct ocp_device *ocpdev) -{ - struct tah_regs *p; - - if (ocp_get_drvdata(ocpdev)) { - printk(KERN_ERR "tah%d: already in use!\n", ocpdev->def->index); - return -EBUSY; - } - - /* Initialize TAH and enable IPv4 checksum verification, no TSO yet */ - p = (struct tah_regs *)ioremap(ocpdev->def->paddr, sizeof(*p)); - if (!p) { - printk(KERN_ERR "tah%d: could not ioremap device registers!\n", - ocpdev->def->index); - return -ENOMEM; - } - ocp_set_drvdata(ocpdev, p); - __tah_reset(ocpdev); - - return 0; -} - -int __init tah_attach(void *emac) -{ - struct ocp_enet_private *dev = emac; - struct ocp_func_emac_data *emacdata = dev->def->additions; - - /* Check if we need to attach to a TAH */ - if (emacdata->tah_idx >= 0) { - dev->tah_dev = ocp_find_device(OCP_ANY_ID, OCP_FUNC_TAH, - emacdata->tah_idx); - if (!dev->tah_dev) { - printk(KERN_ERR "emac%d: unknown tah%d!\n", - dev->def->index, emacdata->tah_idx); - return -ENODEV; - } - if (tah_init(dev->tah_dev)) { - printk(KERN_ERR - "emac%d: tah%d initialization failed!\n", - dev->def->index, emacdata->tah_idx); - return -ENODEV; - } - } - return 0; -} - -void __tah_fini(struct ocp_device *ocpdev) -{ - struct tah_regs *p = ocp_get_drvdata(ocpdev); - BUG_ON(!p); - ocp_set_drvdata(ocpdev, NULL); - iounmap((void *)p); -} - -void __tah_reset(struct ocp_device *ocpdev) -{ - struct tah_regs *p = ocp_get_drvdata(ocpdev); - int n; - - /* Reset TAH */ - out_be32(&p->mr, TAH_MR_SR); - n = 100; - while ((in_be32(&p->mr) & TAH_MR_SR) && n) - --n; - - if (unlikely(!n)) - printk(KERN_ERR "tah%d: reset timeout\n", ocpdev->def->index); - - /* 10KB TAH TX FIFO accomodates the max MTU of 9000 */ - out_be32(&p->mr, - TAH_MR_CVR | TAH_MR_ST_768 | TAH_MR_TFS_10KB | TAH_MR_DTFP | - TAH_MR_DIG); -} - -int __tah_get_regs_len(struct ocp_device *ocpdev) -{ - return sizeof(struct emac_ethtool_regs_subhdr) + - sizeof(struct tah_regs); -} - -void *tah_dump_regs(struct ocp_device *ocpdev, void *buf) -{ - struct tah_regs *dev = ocp_get_drvdata(ocpdev); - struct emac_ethtool_regs_subhdr *hdr = buf; - struct tah_regs *regs = (struct tah_regs *)(hdr + 1); - - hdr->version = 0; - hdr->index = ocpdev->def->index; - memcpy_fromio(regs, dev, sizeof(struct tah_regs)); - return regs + 1; -} diff --git a/drivers/net/ibm_emac/ibm_emac_tah.h b/drivers/net/ibm_emac/ibm_emac_tah.h deleted file mode 100644 index ccf64915e1e4..000000000000 --- a/drivers/net/ibm_emac/ibm_emac_tah.h +++ /dev/null @@ -1,87 +0,0 @@ -/* - * drivers/net/ibm_emac/ibm_emac_tah.h - * - * Driver for PowerPC 4xx on-chip ethernet controller, TAH support. - * - * Copyright 2004 MontaVista Software, Inc. - * Matt Porter <mporter@kernel.crashing.org> - * - * Copyright (c) 2005 Eugene Surovegin <ebs@ebshome.net> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - */ - -#ifndef _IBM_EMAC_TAH_H -#define _IBM_EMAC_TAH_H - -#include <linux/init.h> -#include <asm/ocp.h> - -/* TAH */ -struct tah_regs { - u32 revid; - u32 pad[3]; - u32 mr; - u32 ssr0; - u32 ssr1; - u32 ssr2; - u32 ssr3; - u32 ssr4; - u32 ssr5; - u32 tsr; -}; - -/* TAH engine */ -#define TAH_MR_CVR 0x80000000 -#define TAH_MR_SR 0x40000000 -#define TAH_MR_ST_256 0x01000000 -#define TAH_MR_ST_512 0x02000000 -#define TAH_MR_ST_768 0x03000000 -#define TAH_MR_ST_1024 0x04000000 -#define TAH_MR_ST_1280 0x05000000 -#define TAH_MR_ST_1536 0x06000000 -#define TAH_MR_TFS_16KB 0x00000000 -#define TAH_MR_TFS_2KB 0x00200000 -#define TAH_MR_TFS_4KB 0x00400000 -#define TAH_MR_TFS_6KB 0x00600000 -#define TAH_MR_TFS_8KB 0x00800000 -#define TAH_MR_TFS_10KB 0x00a00000 -#define TAH_MR_DTFP 0x00100000 -#define TAH_MR_DIG 0x00080000 - -#ifdef CONFIG_IBM_EMAC_TAH -int tah_attach(void *emac) __init; - -void __tah_fini(struct ocp_device *ocpdev); -static inline void tah_fini(struct ocp_device *ocpdev) -{ - if (ocpdev) - __tah_fini(ocpdev); -} - -void __tah_reset(struct ocp_device *ocpdev); -static inline void tah_reset(struct ocp_device *ocpdev) -{ - if (ocpdev) - __tah_reset(ocpdev); -} - -int __tah_get_regs_len(struct ocp_device *ocpdev); -static inline int tah_get_regs_len(struct ocp_device *ocpdev) -{ - return ocpdev ? __tah_get_regs_len(ocpdev) : 0; -} - -void *tah_dump_regs(struct ocp_device *ocpdev, void *buf); -#else -# define tah_attach(x) 0 -# define tah_fini(x) ((void)0) -# define tah_reset(x) ((void)0) -# define tah_get_regs_len(x) 0 -# define tah_dump_regs(x,buf) (buf) -#endif /* !CONFIG_IBM_EMAC_TAH */ - -#endif /* _IBM_EMAC_TAH_H */ diff --git a/drivers/net/ibm_emac/ibm_emac_zmii.c b/drivers/net/ibm_emac/ibm_emac_zmii.c deleted file mode 100644 index 2c0fdb0cabff..000000000000 --- a/drivers/net/ibm_emac/ibm_emac_zmii.c +++ /dev/null @@ -1,253 +0,0 @@ -/* - * drivers/net/ibm_emac/ibm_emac_zmii.c - * - * Driver for PowerPC 4xx on-chip ethernet controller, ZMII bridge support. - * - * Copyright (c) 2004, 2005 Zultys Technologies. - * Eugene Surovegin <eugene.surovegin@zultys.com> or <ebs@ebshome.net> - * - * Based on original work by - * Armin Kuster <akuster@mvista.com> - * Copyright 2001 MontaVista Softare Inc. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - */ -#include <linux/kernel.h> -#include <linux/ethtool.h> -#include <asm/io.h> - -#include "ibm_emac_core.h" -#include "ibm_emac_debug.h" - -/* ZMIIx_FER */ -#define ZMII_FER_MDI(idx) (0x80000000 >> ((idx) * 4)) -#define ZMII_FER_MDI_ALL (ZMII_FER_MDI(0) | ZMII_FER_MDI(1) | \ - ZMII_FER_MDI(2) | ZMII_FER_MDI(3)) - -#define ZMII_FER_SMII(idx) (0x40000000 >> ((idx) * 4)) -#define ZMII_FER_RMII(idx) (0x20000000 >> ((idx) * 4)) -#define ZMII_FER_MII(idx) (0x10000000 >> ((idx) * 4)) - -/* ZMIIx_SSR */ -#define ZMII_SSR_SCI(idx) (0x40000000 >> ((idx) * 4)) -#define ZMII_SSR_FSS(idx) (0x20000000 >> ((idx) * 4)) -#define ZMII_SSR_SP(idx) (0x10000000 >> ((idx) * 4)) - -/* ZMII only supports MII, RMII and SMII - * we also support autodetection for backward compatibility - */ -static inline int zmii_valid_mode(int mode) -{ - return mode == PHY_MODE_MII || - mode == PHY_MODE_RMII || - mode == PHY_MODE_SMII || - mode == PHY_MODE_NA; -} - -static inline const char *zmii_mode_name(int mode) -{ - switch (mode) { - case PHY_MODE_MII: - return "MII"; - case PHY_MODE_RMII: - return "RMII"; - case PHY_MODE_SMII: - return "SMII"; - default: - BUG(); - } -} - -static inline u32 zmii_mode_mask(int mode, int input) -{ - switch (mode) { - case PHY_MODE_MII: - return ZMII_FER_MII(input); - case PHY_MODE_RMII: - return ZMII_FER_RMII(input); - case PHY_MODE_SMII: - return ZMII_FER_SMII(input); - default: - return 0; - } -} - -static int __init zmii_init(struct ocp_device *ocpdev, int input, int *mode) -{ - struct ibm_ocp_zmii *dev = ocp_get_drvdata(ocpdev); - struct zmii_regs __iomem *p; - - ZMII_DBG("%d: init(%d, %d)" NL, ocpdev->def->index, input, *mode); - - if (!dev) { - dev = kzalloc(sizeof(struct ibm_ocp_zmii), GFP_KERNEL); - if (!dev) { - printk(KERN_ERR - "zmii%d: couldn't allocate device structure!\n", - ocpdev->def->index); - return -ENOMEM; - } - dev->mode = PHY_MODE_NA; - - p = ioremap(ocpdev->def->paddr, sizeof(struct zmii_regs)); - if (!p) { - printk(KERN_ERR - "zmii%d: could not ioremap device registers!\n", - ocpdev->def->index); - kfree(dev); - return -ENOMEM; - } - dev->base = p; - ocp_set_drvdata(ocpdev, dev); - - /* We may need FER value for autodetection later */ - dev->fer_save = in_be32(&p->fer); - - /* Disable all inputs by default */ - out_be32(&p->fer, 0); - } else - p = dev->base; - - if (!zmii_valid_mode(*mode)) { - /* Probably an EMAC connected to RGMII, - * but it still may need ZMII for MDIO - */ - goto out; - } - - /* Autodetect ZMII mode if not specified. - * This is only for backward compatibility with the old driver. - * Please, always specify PHY mode in your board port to avoid - * any surprises. - */ - if (dev->mode == PHY_MODE_NA) { - if (*mode == PHY_MODE_NA) { - u32 r = dev->fer_save; - - ZMII_DBG("%d: autodetecting mode, FER = 0x%08x" NL, - ocpdev->def->index, r); - - if (r & (ZMII_FER_MII(0) | ZMII_FER_MII(1))) - dev->mode = PHY_MODE_MII; - else if (r & (ZMII_FER_RMII(0) | ZMII_FER_RMII(1))) - dev->mode = PHY_MODE_RMII; - else - dev->mode = PHY_MODE_SMII; - } else - dev->mode = *mode; - - printk(KERN_NOTICE "zmii%d: bridge in %s mode\n", - ocpdev->def->index, zmii_mode_name(dev->mode)); - } else { - /* All inputs must use the same mode */ - if (*mode != PHY_MODE_NA && *mode != dev->mode) { - printk(KERN_ERR - "zmii%d: invalid mode %d specified for input %d\n", - ocpdev->def->index, *mode, input); - return -EINVAL; - } - } - - /* Report back correct PHY mode, - * it may be used during PHY initialization. - */ - *mode = dev->mode; - - /* Enable this input */ - out_be32(&p->fer, in_be32(&p->fer) | zmii_mode_mask(dev->mode, input)); - out: - ++dev->users; - return 0; -} - -int __init zmii_attach(void *emac) -{ - struct ocp_enet_private *dev = emac; - struct ocp_func_emac_data *emacdata = dev->def->additions; - - if (emacdata->zmii_idx >= 0) { - dev->zmii_input = emacdata->zmii_mux; - dev->zmii_dev = - ocp_find_device(OCP_VENDOR_IBM, OCP_FUNC_ZMII, - emacdata->zmii_idx); - if (!dev->zmii_dev) { - printk(KERN_ERR "emac%d: unknown zmii%d!\n", - dev->def->index, emacdata->zmii_idx); - return -ENODEV; - } - if (zmii_init - (dev->zmii_dev, dev->zmii_input, &emacdata->phy_mode)) { - printk(KERN_ERR - "emac%d: zmii%d initialization failed!\n", - dev->def->index, emacdata->zmii_idx); - return -ENODEV; - } - } - return 0; -} - -void __zmii_enable_mdio(struct ocp_device *ocpdev, int input) -{ - struct ibm_ocp_zmii *dev = ocp_get_drvdata(ocpdev); - u32 fer = in_be32(&dev->base->fer) & ~ZMII_FER_MDI_ALL; - - ZMII_DBG2("%d: mdio(%d)" NL, ocpdev->def->index, input); - - out_be32(&dev->base->fer, fer | ZMII_FER_MDI(input)); -} - -void __zmii_set_speed(struct ocp_device *ocpdev, int input, int speed) -{ - struct ibm_ocp_zmii *dev = ocp_get_drvdata(ocpdev); - u32 ssr = in_be32(&dev->base->ssr); - - ZMII_DBG("%d: speed(%d, %d)" NL, ocpdev->def->index, input, speed); - - if (speed == SPEED_100) - ssr |= ZMII_SSR_SP(input); - else - ssr &= ~ZMII_SSR_SP(input); - - out_be32(&dev->base->ssr, ssr); -} - -void __zmii_fini(struct ocp_device *ocpdev, int input) -{ - struct ibm_ocp_zmii *dev = ocp_get_drvdata(ocpdev); - BUG_ON(!dev || dev->users == 0); - - ZMII_DBG("%d: fini(%d)" NL, ocpdev->def->index, input); - - /* Disable this input */ - out_be32(&dev->base->fer, - in_be32(&dev->base->fer) & ~zmii_mode_mask(dev->mode, input)); - - if (!--dev->users) { - /* Free everything if this is the last user */ - ocp_set_drvdata(ocpdev, NULL); - iounmap(dev->base); - kfree(dev); - } -} - -int __zmii_get_regs_len(struct ocp_device *ocpdev) -{ - return sizeof(struct emac_ethtool_regs_subhdr) + - sizeof(struct zmii_regs); -} - -void *zmii_dump_regs(struct ocp_device *ocpdev, void *buf) -{ - struct ibm_ocp_zmii *dev = ocp_get_drvdata(ocpdev); - struct emac_ethtool_regs_subhdr *hdr = buf; - struct zmii_regs *regs = (struct zmii_regs *)(hdr + 1); - - hdr->version = 0; - hdr->index = ocpdev->def->index; - memcpy_fromio(regs, dev->base, sizeof(struct zmii_regs)); - return regs + 1; -} diff --git a/drivers/net/ibm_emac/ibm_emac_zmii.h b/drivers/net/ibm_emac/ibm_emac_zmii.h deleted file mode 100644 index fad6d8bf983a..000000000000 --- a/drivers/net/ibm_emac/ibm_emac_zmii.h +++ /dev/null @@ -1,82 +0,0 @@ -/* - * drivers/net/ibm_emac/ibm_emac_zmii.h - * - * Driver for PowerPC 4xx on-chip ethernet controller, ZMII bridge support. - * - * Copyright (c) 2004, 2005 Zultys Technologies. - * Eugene Surovegin <eugene.surovegin@zultys.com> or <ebs@ebshome.net> - * - * Based on original work by - * Armin Kuster <akuster@mvista.com> - * Copyright 2001 MontaVista Softare Inc. - * - * 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. - * - */ -#ifndef _IBM_EMAC_ZMII_H_ -#define _IBM_EMAC_ZMII_H_ - -#include <linux/init.h> -#include <asm/ocp.h> - -/* ZMII bridge registers */ -struct zmii_regs { - u32 fer; /* Function enable reg */ - u32 ssr; /* Speed select reg */ - u32 smiirs; /* SMII status reg */ -}; - -/* ZMII device */ -struct ibm_ocp_zmii { - struct zmii_regs __iomem *base; - int mode; /* subset of PHY_MODE_XXXX */ - int users; /* number of EMACs using this ZMII bridge */ - u32 fer_save; /* FER value left by firmware */ -}; - -#ifdef CONFIG_IBM_EMAC_ZMII -int zmii_attach(void *emac) __init; - -void __zmii_fini(struct ocp_device *ocpdev, int input); -static inline void zmii_fini(struct ocp_device *ocpdev, int input) -{ - if (ocpdev) - __zmii_fini(ocpdev, input); -} - -void __zmii_enable_mdio(struct ocp_device *ocpdev, int input); -static inline void zmii_enable_mdio(struct ocp_device *ocpdev, int input) -{ - if (ocpdev) - __zmii_enable_mdio(ocpdev, input); -} - -void __zmii_set_speed(struct ocp_device *ocpdev, int input, int speed); -static inline void zmii_set_speed(struct ocp_device *ocpdev, int input, - int speed) -{ - if (ocpdev) - __zmii_set_speed(ocpdev, input, speed); -} - -int __zmii_get_regs_len(struct ocp_device *ocpdev); -static inline int zmii_get_regs_len(struct ocp_device *ocpdev) -{ - return ocpdev ? __zmii_get_regs_len(ocpdev) : 0; -} - -void *zmii_dump_regs(struct ocp_device *ocpdev, void *buf); - -#else -# define zmii_attach(x) 0 -# define zmii_fini(x,y) ((void)0) -# define zmii_enable_mdio(x,y) ((void)0) -# define zmii_set_speed(x,y,z) ((void)0) -# define zmii_get_regs_len(x) 0 -# define zmii_dump_regs(x,buf) (buf) -#endif /* !CONFIG_IBM_EMAC_ZMII */ - -#endif /* _IBM_EMAC_ZMII_H_ */ diff --git a/drivers/net/ibm_newemac/core.c b/drivers/net/ibm_newemac/core.c index 61af02b4c9d8..2e720f26ca83 100644 --- a/drivers/net/ibm_newemac/core.c +++ b/drivers/net/ibm_newemac/core.c @@ -295,7 +295,9 @@ static void emac_rx_disable(struct emac_instance *dev) static inline void emac_netif_stop(struct emac_instance *dev) { netif_tx_lock_bh(dev->ndev); + netif_addr_lock(dev->ndev); dev->no_mcast = 1; + netif_addr_unlock(dev->ndev); netif_tx_unlock_bh(dev->ndev); dev->ndev->trans_start = jiffies; /* prevent tx timeout */ mal_poll_disable(dev->mal, &dev->commac); @@ -305,9 +307,11 @@ static inline void emac_netif_stop(struct emac_instance *dev) static inline void emac_netif_start(struct emac_instance *dev) { netif_tx_lock_bh(dev->ndev); + netif_addr_lock(dev->ndev); dev->no_mcast = 0; if (dev->mcast_pending && netif_running(dev->ndev)) __emac_set_multicast_list(dev); + netif_addr_unlock(dev->ndev); netif_tx_unlock_bh(dev->ndev); netif_wake_queue(dev->ndev); diff --git a/drivers/net/ifb.c b/drivers/net/ifb.c index af233b591534..0960e69b2da4 100644 --- a/drivers/net/ifb.c +++ b/drivers/net/ifb.c @@ -35,7 +35,6 @@ #include <linux/moduleparam.h> #include <net/pkt_sched.h> #include <net/net_namespace.h> -#include <linux/lockdep.h> #define TX_TIMEOUT (2*HZ) @@ -228,16 +227,6 @@ static struct rtnl_link_ops ifb_link_ops __read_mostly = { module_param(numifbs, int, 0); MODULE_PARM_DESC(numifbs, "Number of ifb devices"); -/* - * dev_ifb->queue_lock is usually taken after dev->ingress_lock, - * reversely to e.g. qdisc_lock_tree(). It should be safe until - * ifb doesn't take dev->queue_lock with dev_ifb->ingress_lock. - * But lockdep should know that ifb has different locks from dev. - */ -static struct lock_class_key ifb_queue_lock_key; -static struct lock_class_key ifb_ingress_lock_key; - - static int __init ifb_init_one(int index) { struct net_device *dev_ifb; @@ -258,9 +247,6 @@ static int __init ifb_init_one(int index) if (err < 0) goto err; - lockdep_set_class(&dev_ifb->queue_lock, &ifb_queue_lock_key); - lockdep_set_class(&dev_ifb->ingress_lock, &ifb_ingress_lock_key); - return 0; err: diff --git a/drivers/net/igb/e1000_82575.c b/drivers/net/igb/e1000_82575.c index cda3ec879090..e098f234770f 100644 --- a/drivers/net/igb/e1000_82575.c +++ b/drivers/net/igb/e1000_82575.c @@ -1,7 +1,7 @@ /******************************************************************************* Intel(R) Gigabit Ethernet Linux driver - Copyright(c) 2007 Intel Corporation. + Copyright(c) 2007 - 2008 Intel Corporation. This program is free software; you can redistribute it and/or modify it under the terms and conditions of the GNU General Public License, @@ -31,6 +31,7 @@ #include <linux/types.h> #include <linux/slab.h> +#include <linux/if_ether.h> #include "e1000_mac.h" #include "e1000_82575.h" @@ -45,7 +46,6 @@ static s32 igb_get_cfg_done_82575(struct e1000_hw *); static s32 igb_init_hw_82575(struct e1000_hw *); static s32 igb_phy_hw_reset_sgmii_82575(struct e1000_hw *); static s32 igb_read_phy_reg_sgmii_82575(struct e1000_hw *, u32, u16 *); -static void igb_rar_set_82575(struct e1000_hw *, u8 *, u32); static s32 igb_reset_hw_82575(struct e1000_hw *); static s32 igb_set_d0_lplu_state_82575(struct e1000_hw *, bool); static s32 igb_setup_copper_link_82575(struct e1000_hw *); @@ -84,6 +84,12 @@ static s32 igb_get_invariants_82575(struct e1000_hw *hw) case E1000_DEV_ID_82575GB_QUAD_COPPER: mac->type = e1000_82575; break; + case E1000_DEV_ID_82576: + case E1000_DEV_ID_82576_FIBER: + case E1000_DEV_ID_82576_SERDES: + case E1000_DEV_ID_82576_QUAD_COPPER: + mac->type = e1000_82576; + break; default: return -E1000_ERR_MAC_INIT; break; @@ -128,6 +134,8 @@ static s32 igb_get_invariants_82575(struct e1000_hw *hw) mac->mta_reg_count = 128; /* Set rar entry count */ mac->rar_entry_count = E1000_RAR_ENTRIES_82575; + if (mac->type == e1000_82576) + mac->rar_entry_count = E1000_RAR_ENTRIES_82576; /* Set if part includes ASF firmware */ mac->asf_firmware_present = true; /* Set if manageability features are enabled. */ @@ -171,6 +179,10 @@ static s32 igb_get_invariants_82575(struct e1000_hw *hw) * for setting word_size. */ size += NVM_WORD_SIZE_BASE_SHIFT; + + /* EEPROM access above 16k is unsupported */ + if (size > 14) + size = 14; nvm->word_size = 1 << size; /* setup PHY parameters */ @@ -222,7 +234,7 @@ static s32 igb_get_invariants_82575(struct e1000_hw *hw) } /** - * e1000_acquire_phy_82575 - Acquire rights to access PHY + * igb_acquire_phy_82575 - Acquire rights to access PHY * @hw: pointer to the HW structure * * Acquire access rights to the correct PHY. This is a @@ -238,7 +250,7 @@ static s32 igb_acquire_phy_82575(struct e1000_hw *hw) } /** - * e1000_release_phy_82575 - Release rights to access PHY + * igb_release_phy_82575 - Release rights to access PHY * @hw: pointer to the HW structure * * A wrapper to release access rights to the correct PHY. This is a @@ -253,7 +265,7 @@ static void igb_release_phy_82575(struct e1000_hw *hw) } /** - * e1000_read_phy_reg_sgmii_82575 - Read PHY register using sgmii + * igb_read_phy_reg_sgmii_82575 - Read PHY register using sgmii * @hw: pointer to the HW structure * @offset: register offset to be read * @data: pointer to the read data @@ -268,7 +280,7 @@ static s32 igb_read_phy_reg_sgmii_82575(struct e1000_hw *hw, u32 offset, u32 i, i2ccmd = 0; if (offset > E1000_MAX_SGMII_PHY_REG_ADDR) { - hw_dbg(hw, "PHY Address %u is out of range\n", offset); + hw_dbg("PHY Address %u is out of range\n", offset); return -E1000_ERR_PARAM; } @@ -291,11 +303,11 @@ static s32 igb_read_phy_reg_sgmii_82575(struct e1000_hw *hw, u32 offset, break; } if (!(i2ccmd & E1000_I2CCMD_READY)) { - hw_dbg(hw, "I2CCMD Read did not complete\n"); + hw_dbg("I2CCMD Read did not complete\n"); return -E1000_ERR_PHY; } if (i2ccmd & E1000_I2CCMD_ERROR) { - hw_dbg(hw, "I2CCMD Error bit set\n"); + hw_dbg("I2CCMD Error bit set\n"); return -E1000_ERR_PHY; } @@ -306,7 +318,7 @@ static s32 igb_read_phy_reg_sgmii_82575(struct e1000_hw *hw, u32 offset, } /** - * e1000_write_phy_reg_sgmii_82575 - Write PHY register using sgmii + * igb_write_phy_reg_sgmii_82575 - Write PHY register using sgmii * @hw: pointer to the HW structure * @offset: register offset to write to * @data: data to write at register offset @@ -322,7 +334,7 @@ static s32 igb_write_phy_reg_sgmii_82575(struct e1000_hw *hw, u32 offset, u16 phy_data_swapped; if (offset > E1000_MAX_SGMII_PHY_REG_ADDR) { - hw_dbg(hw, "PHY Address %d is out of range\n", offset); + hw_dbg("PHY Address %d is out of range\n", offset); return -E1000_ERR_PARAM; } @@ -349,11 +361,11 @@ static s32 igb_write_phy_reg_sgmii_82575(struct e1000_hw *hw, u32 offset, break; } if (!(i2ccmd & E1000_I2CCMD_READY)) { - hw_dbg(hw, "I2CCMD Write did not complete\n"); + hw_dbg("I2CCMD Write did not complete\n"); return -E1000_ERR_PHY; } if (i2ccmd & E1000_I2CCMD_ERROR) { - hw_dbg(hw, "I2CCMD Error bit set\n"); + hw_dbg("I2CCMD Error bit set\n"); return -E1000_ERR_PHY; } @@ -361,10 +373,10 @@ static s32 igb_write_phy_reg_sgmii_82575(struct e1000_hw *hw, u32 offset, } /** - * e1000_get_phy_id_82575 - Retreive PHY addr and id + * igb_get_phy_id_82575 - Retrieve PHY addr and id * @hw: pointer to the HW structure * - * Retreives the PHY address and ID for both PHY's which do and do not use + * Retrieves the PHY address and ID for both PHY's which do and do not use * sgmi interface. **/ static s32 igb_get_phy_id_82575(struct e1000_hw *hw) @@ -393,9 +405,8 @@ static s32 igb_get_phy_id_82575(struct e1000_hw *hw) for (phy->addr = 1; phy->addr < 8; phy->addr++) { ret_val = igb_read_phy_reg_sgmii_82575(hw, PHY_ID1, &phy_id); if (ret_val == 0) { - hw_dbg(hw, "Vendor ID 0x%08X read at address %u\n", - phy_id, - phy->addr); + hw_dbg("Vendor ID 0x%08X read at address %u\n", + phy_id, phy->addr); /* * At the time of this writing, The M88 part is * the only supported SGMII PHY product. @@ -403,8 +414,7 @@ static s32 igb_get_phy_id_82575(struct e1000_hw *hw) if (phy_id == M88_VENDOR) break; } else { - hw_dbg(hw, "PHY address %u was unreadable\n", - phy->addr); + hw_dbg("PHY address %u was unreadable\n", phy->addr); } } @@ -422,7 +432,7 @@ out: } /** - * e1000_phy_hw_reset_sgmii_82575 - Performs a PHY reset + * igb_phy_hw_reset_sgmii_82575 - Performs a PHY reset * @hw: pointer to the HW structure * * Resets the PHY using the serial gigabit media independent interface. @@ -436,7 +446,7 @@ static s32 igb_phy_hw_reset_sgmii_82575(struct e1000_hw *hw) * available to us at this time. */ - hw_dbg(hw, "Soft resetting SGMII attached PHY...\n"); + hw_dbg("Soft resetting SGMII attached PHY...\n"); /* * SFP documentation requires the following to configure the SPF module @@ -453,7 +463,7 @@ out: } /** - * e1000_set_d0_lplu_state_82575 - Set Low Power Linkup D0 state + * igb_set_d0_lplu_state_82575 - Set Low Power Linkup D0 state * @hw: pointer to the HW structure * @active: true to enable LPLU, false to disable * @@ -471,34 +481,29 @@ static s32 igb_set_d0_lplu_state_82575(struct e1000_hw *hw, bool active) s32 ret_val; u16 data; - ret_val = hw->phy.ops.read_phy_reg(hw, IGP02E1000_PHY_POWER_MGMT, - &data); + ret_val = phy->ops.read_phy_reg(hw, IGP02E1000_PHY_POWER_MGMT, &data); if (ret_val) goto out; if (active) { data |= IGP02E1000_PM_D0_LPLU; - ret_val = hw->phy.ops.write_phy_reg(hw, - IGP02E1000_PHY_POWER_MGMT, - data); + ret_val = phy->ops.write_phy_reg(hw, IGP02E1000_PHY_POWER_MGMT, + data); if (ret_val) goto out; /* When LPLU is enabled, we should disable SmartSpeed */ - ret_val = hw->phy.ops.read_phy_reg(hw, - IGP01E1000_PHY_PORT_CONFIG, - &data); + ret_val = phy->ops.read_phy_reg(hw, IGP01E1000_PHY_PORT_CONFIG, + &data); data &= ~IGP01E1000_PSCFR_SMART_SPEED; - ret_val = hw->phy.ops.write_phy_reg(hw, - IGP01E1000_PHY_PORT_CONFIG, - data); + ret_val = phy->ops.write_phy_reg(hw, IGP01E1000_PHY_PORT_CONFIG, + data); if (ret_val) goto out; } else { data &= ~IGP02E1000_PM_D0_LPLU; - ret_val = hw->phy.ops.write_phy_reg(hw, - IGP02E1000_PHY_POWER_MGMT, - data); + ret_val = phy->ops.write_phy_reg(hw, IGP02E1000_PHY_POWER_MGMT, + data); /* * LPLU and SmartSpeed are mutually exclusive. LPLU is used * during Dx states where the power conservation is most @@ -506,29 +511,25 @@ static s32 igb_set_d0_lplu_state_82575(struct e1000_hw *hw, bool active) * SmartSpeed, so performance is maintained. */ if (phy->smart_speed == e1000_smart_speed_on) { - ret_val = hw->phy.ops.read_phy_reg(hw, - IGP01E1000_PHY_PORT_CONFIG, - &data); + ret_val = phy->ops.read_phy_reg(hw, + IGP01E1000_PHY_PORT_CONFIG, &data); if (ret_val) goto out; data |= IGP01E1000_PSCFR_SMART_SPEED; - ret_val = hw->phy.ops.write_phy_reg(hw, - IGP01E1000_PHY_PORT_CONFIG, - data); + ret_val = phy->ops.write_phy_reg(hw, + IGP01E1000_PHY_PORT_CONFIG, data); if (ret_val) goto out; } else if (phy->smart_speed == e1000_smart_speed_off) { - ret_val = hw->phy.ops.read_phy_reg(hw, - IGP01E1000_PHY_PORT_CONFIG, - &data); + ret_val = phy->ops.read_phy_reg(hw, + IGP01E1000_PHY_PORT_CONFIG, &data); if (ret_val) goto out; data &= ~IGP01E1000_PSCFR_SMART_SPEED; - ret_val = hw->phy.ops.write_phy_reg(hw, - IGP01E1000_PHY_PORT_CONFIG, - data); + ret_val = phy->ops.write_phy_reg(hw, + IGP01E1000_PHY_PORT_CONFIG, data); if (ret_val) goto out; } @@ -539,10 +540,10 @@ out: } /** - * e1000_acquire_nvm_82575 - Request for access to EEPROM + * igb_acquire_nvm_82575 - Request for access to EEPROM * @hw: pointer to the HW structure * - * Acquire the necessary semaphores for exclussive access to the EEPROM. + * Acquire the necessary semaphores for exclusive access to the EEPROM. * Set the EEPROM access request bit and wait for EEPROM access grant bit. * Return successful if access grant bit set, else clear the request for * EEPROM access and return -E1000_ERR_NVM (-1). @@ -565,7 +566,7 @@ out: } /** - * e1000_release_nvm_82575 - Release exclusive access to EEPROM + * igb_release_nvm_82575 - Release exclusive access to EEPROM * @hw: pointer to the HW structure * * Stop any current commands to the EEPROM and clear the EEPROM request bit, @@ -578,7 +579,7 @@ static void igb_release_nvm_82575(struct e1000_hw *hw) } /** - * e1000_acquire_swfw_sync_82575 - Acquire SW/FW semaphore + * igb_acquire_swfw_sync_82575 - Acquire SW/FW semaphore * @hw: pointer to the HW structure * @mask: specifies which semaphore to acquire * @@ -613,7 +614,7 @@ static s32 igb_acquire_swfw_sync_82575(struct e1000_hw *hw, u16 mask) } if (i == timeout) { - hw_dbg(hw, "Can't access resource, SW_FW_SYNC timeout.\n"); + hw_dbg("Driver can't access resource, SW_FW_SYNC timeout.\n"); ret_val = -E1000_ERR_SWFW_SYNC; goto out; } @@ -628,7 +629,7 @@ out: } /** - * e1000_release_swfw_sync_82575 - Release SW/FW semaphore + * igb_release_swfw_sync_82575 - Release SW/FW semaphore * @hw: pointer to the HW structure * @mask: specifies which semaphore to acquire * @@ -650,7 +651,7 @@ static void igb_release_swfw_sync_82575(struct e1000_hw *hw, u16 mask) } /** - * e1000_get_cfg_done_82575 - Read config done bit + * igb_get_cfg_done_82575 - Read config done bit * @hw: pointer to the HW structure * * Read the management control register for the config done bit for @@ -675,7 +676,7 @@ static s32 igb_get_cfg_done_82575(struct e1000_hw *hw) timeout--; } if (!timeout) - hw_dbg(hw, "MNG configuration cycle has not completed.\n"); + hw_dbg("MNG configuration cycle has not completed.\n"); /* If EEPROM is not marked present, init the PHY manually */ if (((rd32(E1000_EECD) & E1000_EECD_PRES) == 0) && @@ -686,7 +687,7 @@ static s32 igb_get_cfg_done_82575(struct e1000_hw *hw) } /** - * e1000_check_for_link_82575 - Check for link + * igb_check_for_link_82575 - Check for link * @hw: pointer to the HW structure * * If sgmii is enabled, then use the pcs register to determine link, otherwise @@ -701,20 +702,19 @@ static s32 igb_check_for_link_82575(struct e1000_hw *hw) if ((hw->phy.media_type != e1000_media_type_copper) || (igb_sgmii_active_82575(hw))) ret_val = igb_get_pcs_speed_and_duplex_82575(hw, &speed, - &duplex); + &duplex); else ret_val = igb_check_for_copper_link(hw); return ret_val; } - /** - * e1000_get_pcs_speed_and_duplex_82575 - Retrieve current speed/duplex + * igb_get_pcs_speed_and_duplex_82575 - Retrieve current speed/duplex * @hw: pointer to the HW structure * @speed: stores the current speed * @duplex: stores the current duplex * - * Using the physical coding sub-layer (PCS), retreive the current speed and + * Using the physical coding sub-layer (PCS), retrieve the current speed and * duplex, then store the values in the pointers provided. **/ static s32 igb_get_pcs_speed_and_duplex_82575(struct e1000_hw *hw, u16 *speed, @@ -764,24 +764,135 @@ static s32 igb_get_pcs_speed_and_duplex_82575(struct e1000_hw *hw, u16 *speed, } /** - * e1000_rar_set_82575 - Set receive address register + * igb_init_rx_addrs_82575 - Initialize receive address's * @hw: pointer to the HW structure - * @addr: pointer to the receive address - * @index: receive address array register + * @rar_count: receive address registers * - * Sets the receive address array register at index to the address passed - * in by addr. + * Setups the receive address registers by setting the base receive address + * register to the devices MAC address and clearing all the other receive + * address registers to 0. **/ -static void igb_rar_set_82575(struct e1000_hw *hw, u8 *addr, u32 index) +static void igb_init_rx_addrs_82575(struct e1000_hw *hw, u16 rar_count) { - if (index < E1000_RAR_ENTRIES_82575) - igb_rar_set(hw, addr, index); + u32 i; + u8 addr[6] = {0,0,0,0,0,0}; + /* + * This function is essentially the same as that of + * e1000_init_rx_addrs_generic. However it also takes care + * of the special case where the register offset of the + * second set of RARs begins elsewhere. This is implicitly taken care by + * function e1000_rar_set_generic. + */ + + hw_dbg("e1000_init_rx_addrs_82575"); + + /* Setup the receive address */ + hw_dbg("Programming MAC Address into RAR[0]\n"); + hw->mac.ops.rar_set(hw, hw->mac.addr, 0); + + /* Zero out the other (rar_entry_count - 1) receive addresses */ + hw_dbg("Clearing RAR[1-%u]\n", rar_count-1); + for (i = 1; i < rar_count; i++) + hw->mac.ops.rar_set(hw, addr, i); +} + +/** + * igb_update_mc_addr_list_82575 - Update Multicast addresses + * @hw: pointer to the HW structure + * @mc_addr_list: array of multicast addresses to program + * @mc_addr_count: number of multicast addresses to program + * @rar_used_count: the first RAR register free to program + * @rar_count: total number of supported Receive Address Registers + * + * Updates the Receive Address Registers and Multicast Table Array. + * The caller must have a packed mc_addr_list of multicast addresses. + * The parameter rar_count will usually be hw->mac.rar_entry_count + * unless there are workarounds that change this. + **/ +void igb_update_mc_addr_list_82575(struct e1000_hw *hw, + u8 *mc_addr_list, u32 mc_addr_count, + u32 rar_used_count, u32 rar_count) +{ + u32 hash_value; + u32 i; + u8 addr[6] = {0,0,0,0,0,0}; + /* + * This function is essentially the same as that of + * igb_update_mc_addr_list_generic. However it also takes care + * of the special case where the register offset of the + * second set of RARs begins elsewhere. This is implicitly taken care by + * function e1000_rar_set_generic. + */ + + /* + * Load the first set of multicast addresses into the exact + * filters (RAR). If there are not enough to fill the RAR + * array, clear the filters. + */ + for (i = rar_used_count; i < rar_count; i++) { + if (mc_addr_count) { + igb_rar_set(hw, mc_addr_list, i); + mc_addr_count--; + mc_addr_list += ETH_ALEN; + } else { + igb_rar_set(hw, addr, i); + } + } + + /* Clear the old settings from the MTA */ + hw_dbg("Clearing MTA\n"); + for (i = 0; i < hw->mac.mta_reg_count; i++) { + array_wr32(E1000_MTA, i, 0); + wrfl(); + } + + /* Load any remaining multicast addresses into the hash table. */ + for (; mc_addr_count > 0; mc_addr_count--) { + hash_value = igb_hash_mc_addr(hw, mc_addr_list); + hw_dbg("Hash value = 0x%03X\n", hash_value); + hw->mac.ops.mta_set(hw, hash_value); + mc_addr_list += ETH_ALEN; + } +} + +/** + * igb_shutdown_fiber_serdes_link_82575 - Remove link during power down + * @hw: pointer to the HW structure + * + * In the case of fiber serdes, shut down optics and PCS on driver unload + * when management pass thru is not enabled. + **/ +void igb_shutdown_fiber_serdes_link_82575(struct e1000_hw *hw) +{ + u32 reg; + + if (hw->mac.type != e1000_82576 || + (hw->phy.media_type != e1000_media_type_fiber && + hw->phy.media_type != e1000_media_type_internal_serdes)) + return; + + /* if the management interface is not enabled, then power down */ + if (!igb_enable_mng_pass_thru(hw)) { + /* Disable PCS to turn off link */ + reg = rd32(E1000_PCS_CFG0); + reg &= ~E1000_PCS_CFG_PCS_EN; + wr32(E1000_PCS_CFG0, reg); + + /* shutdown the laser */ + reg = rd32(E1000_CTRL_EXT); + reg |= E1000_CTRL_EXT_SDP7_DATA; + wr32(E1000_CTRL_EXT, reg); + + /* flush the write to verify completion */ + wrfl(); + msleep(1); + } return; } /** - * e1000_reset_hw_82575 - Reset hardware + * igb_reset_hw_82575 - Reset hardware * @hw: pointer to the HW structure * * This resets the hardware into a known state. This is a @@ -798,9 +909,9 @@ static s32 igb_reset_hw_82575(struct e1000_hw *hw) */ ret_val = igb_disable_pcie_master(hw); if (ret_val) - hw_dbg(hw, "PCI-E Master disable polling has failed.\n"); + hw_dbg("PCI-E Master disable polling has failed.\n"); - hw_dbg(hw, "Masking off all interrupts\n"); + hw_dbg("Masking off all interrupts\n"); wr32(E1000_IMC, 0xffffffff); wr32(E1000_RCTL, 0); @@ -811,7 +922,7 @@ static s32 igb_reset_hw_82575(struct e1000_hw *hw) ctrl = rd32(E1000_CTRL); - hw_dbg(hw, "Issuing a global reset to MAC\n"); + hw_dbg("Issuing a global reset to MAC\n"); wr32(E1000_CTRL, ctrl | E1000_CTRL_RST); ret_val = igb_get_auto_rd_done(hw); @@ -821,7 +932,7 @@ static s32 igb_reset_hw_82575(struct e1000_hw *hw) * return with an error. This can happen in situations * where there is no eeprom and prevents getting link. */ - hw_dbg(hw, "Auto Read Done did not complete\n"); + hw_dbg("Auto Read Done did not complete\n"); } /* If EEPROM is not present, run manual init scripts */ @@ -838,7 +949,7 @@ static s32 igb_reset_hw_82575(struct e1000_hw *hw) } /** - * e1000_init_hw_82575 - Initialize hardware + * igb_init_hw_82575 - Initialize hardware * @hw: pointer to the HW structure * * This inits the hardware readying it for operation. @@ -852,18 +963,18 @@ static s32 igb_init_hw_82575(struct e1000_hw *hw) /* Initialize identification LED */ ret_val = igb_id_led_init(hw); if (ret_val) { - hw_dbg(hw, "Error initializing identification LED\n"); + hw_dbg("Error initializing identification LED\n"); /* This is not fatal and we should not stop init due to this */ } /* Disabling VLAN filtering */ - hw_dbg(hw, "Initializing the IEEE VLAN\n"); + hw_dbg("Initializing the IEEE VLAN\n"); igb_clear_vfta(hw); /* Setup the receive address */ - igb_init_rx_addrs(hw, rar_count); + igb_init_rx_addrs_82575(hw, rar_count); /* Zero out the Multicast HASH table */ - hw_dbg(hw, "Zeroing the MTA\n"); + hw_dbg("Zeroing the MTA\n"); for (i = 0; i < mac->mta_reg_count; i++) array_wr32(E1000_MTA, i, 0); @@ -882,7 +993,7 @@ static s32 igb_init_hw_82575(struct e1000_hw *hw) } /** - * e1000_setup_copper_link_82575 - Configure copper link settings + * igb_setup_copper_link_82575 - Configure copper link settings * @hw: pointer to the HW structure * * Configures the link for auto-neg or forced speed and duplex. Then we check @@ -933,10 +1044,10 @@ static s32 igb_setup_copper_link_82575(struct e1000_hw *hw) * PHY will be set to 10H, 10F, 100H or 100F * depending on user settings. */ - hw_dbg(hw, "Forcing Speed and Duplex\n"); + hw_dbg("Forcing Speed and Duplex\n"); ret_val = igb_phy_force_speed_duplex(hw); if (ret_val) { - hw_dbg(hw, "Error Forcing Speed and Duplex\n"); + hw_dbg("Error Forcing Speed and Duplex\n"); goto out; } } @@ -949,20 +1060,17 @@ static s32 igb_setup_copper_link_82575(struct e1000_hw *hw) * Check link status. Wait up to 100 microseconds for link to become * valid. */ - ret_val = igb_phy_has_link(hw, - COPPER_LINK_UP_LIMIT, - 10, - &link); + ret_val = igb_phy_has_link(hw, COPPER_LINK_UP_LIMIT, 10, &link); if (ret_val) goto out; if (link) { - hw_dbg(hw, "Valid link established!!!\n"); + hw_dbg("Valid link established!!!\n"); /* Config the MAC and PHY after link is up */ igb_config_collision_dist(hw); ret_val = igb_config_fc_after_link_up(hw); } else { - hw_dbg(hw, "Unable to establish link!!!\n"); + hw_dbg("Unable to establish link!!!\n"); } out: @@ -970,7 +1078,7 @@ out: } /** - * e1000_setup_fiber_serdes_link_82575 - Setup link for fiber/serdes + * igb_setup_fiber_serdes_link_82575 - Setup link for fiber/serdes * @hw: pointer to the HW structure * * Configures speed and duplex for fiber and serdes links. @@ -1018,7 +1126,7 @@ static s32 igb_setup_fiber_serdes_link_82575(struct e1000_hw *hw) E1000_PCS_LCTL_FDV_FULL | /* SerDes Full duplex */ E1000_PCS_LCTL_AN_ENABLE | /* Enable Autoneg */ E1000_PCS_LCTL_AN_RESTART; /* Restart autoneg */ - hw_dbg(hw, "Configuring Autoneg; PCS_LCTL = 0x%08X\n", reg); + hw_dbg("Configuring Autoneg; PCS_LCTL = 0x%08X\n", reg); } else { /* Set PCS register for forced speed */ reg |= E1000_PCS_LCTL_FLV_LINK_UP | /* Force link up */ @@ -1026,7 +1134,7 @@ static s32 igb_setup_fiber_serdes_link_82575(struct e1000_hw *hw) E1000_PCS_LCTL_FDV_FULL | /* SerDes Full duplex */ E1000_PCS_LCTL_FSD | /* Force Speed */ E1000_PCS_LCTL_FORCE_LINK; /* Force Link */ - hw_dbg(hw, "Configuring Forced Link; PCS_LCTL = 0x%08X\n", reg); + hw_dbg("Configuring Forced Link; PCS_LCTL = 0x%08X\n", reg); } wr32(E1000_PCS_LCTL, reg); @@ -1034,7 +1142,7 @@ static s32 igb_setup_fiber_serdes_link_82575(struct e1000_hw *hw) } /** - * e1000_configure_pcs_link_82575 - Configure PCS link + * igb_configure_pcs_link_82575 - Configure PCS link * @hw: pointer to the HW structure * * Configure the physical coding sub-layer (PCS) link. The PCS link is @@ -1067,7 +1175,7 @@ static s32 igb_configure_pcs_link_82575(struct e1000_hw *hw) */ reg |= E1000_PCS_LCTL_AN_RESTART | E1000_PCS_LCTL_AN_ENABLE; } else { - /* Set PCS regiseter for forced speed */ + /* Set PCS register for forced speed */ /* Turn off bits for full duplex, speed, and autoneg */ reg &= ~(E1000_PCS_LCTL_FSV_1000 | @@ -1088,8 +1196,7 @@ static s32 igb_configure_pcs_link_82575(struct e1000_hw *hw) E1000_PCS_LCTL_FORCE_LINK | E1000_PCS_LCTL_FLV_LINK_UP; - hw_dbg(hw, - "Wrote 0x%08X to PCS_LCTL to configure forced link\n", + hw_dbg("Wrote 0x%08X to PCS_LCTL to configure forced link\n", reg); } wr32(E1000_PCS_LCTL, reg); @@ -1099,7 +1206,7 @@ out: } /** - * e1000_sgmii_active_82575 - Return sgmii state + * igb_sgmii_active_82575 - Return sgmii state * @hw: pointer to the HW structure * * 82575 silicon has a serialized gigabit media independent interface (sgmii) @@ -1125,7 +1232,71 @@ out: } /** - * e1000_reset_init_script_82575 - Inits HW defaults after reset + * igb_translate_register_82576 - Translate the proper register offset + * @reg: e1000 register to be read + * + * Registers in 82576 are located in different offsets than other adapters + * even though they function in the same manner. This function takes in + * the name of the register to read and returns the correct offset for + * 82576 silicon. + **/ +u32 igb_translate_register_82576(u32 reg) +{ + /* + * Some of the Kawela registers are located at different + * offsets than they are in older adapters. + * Despite the difference in location, the registers + * function in the same manner. + */ + switch (reg) { + case E1000_TDBAL(0): + reg = 0x0E000; + break; + case E1000_TDBAH(0): + reg = 0x0E004; + break; + case E1000_TDLEN(0): + reg = 0x0E008; + break; + case E1000_TDH(0): + reg = 0x0E010; + break; + case E1000_TDT(0): + reg = 0x0E018; + break; + case E1000_TXDCTL(0): + reg = 0x0E028; + break; + case E1000_RDBAL(0): + reg = 0x0C000; + break; + case E1000_RDBAH(0): + reg = 0x0C004; + break; + case E1000_RDLEN(0): + reg = 0x0C008; + break; + case E1000_RDH(0): + reg = 0x0C010; + break; + case E1000_RDT(0): + reg = 0x0C018; + break; + case E1000_RXDCTL(0): + reg = 0x0C028; + break; + case E1000_SRRCTL(0): + reg = 0x0C00C; + break; + default: + break; + } + + return reg; +} + +/** + * igb_reset_init_script_82575 - Inits HW defaults after reset * @hw: pointer to the HW structure * * Inits recommended HW defaults after a reset when there is no EEPROM @@ -1134,7 +1305,7 @@ out: static s32 igb_reset_init_script_82575(struct e1000_hw *hw) { if (hw->mac.type == e1000_82575) { - hw_dbg(hw, "Running reset init script for 82575\n"); + hw_dbg("Running reset init script for 82575\n"); /* SerDes configuration via SERDESCTRL */ igb_write_8bit_ctrl_reg(hw, E1000_SCTL, 0x00, 0x0C); igb_write_8bit_ctrl_reg(hw, E1000_SCTL, 0x01, 0x78); @@ -1161,7 +1332,7 @@ static s32 igb_reset_init_script_82575(struct e1000_hw *hw) } /** - * e1000_read_mac_addr_82575 - Read device MAC address + * igb_read_mac_addr_82575 - Read device MAC address * @hw: pointer to the HW structure **/ static s32 igb_read_mac_addr_82575(struct e1000_hw *hw) @@ -1175,7 +1346,7 @@ static s32 igb_read_mac_addr_82575(struct e1000_hw *hw) } /** - * e1000_clear_hw_cntrs_82575 - Clear device specific hardware counters + * igb_clear_hw_cntrs_82575 - Clear device specific hardware counters * @hw: pointer to the HW structure * * Clears the hardware counters by reading the counter registers. @@ -1238,11 +1409,84 @@ static void igb_clear_hw_cntrs_82575(struct e1000_hw *hw) temp = rd32(E1000_SCVPC); } +/** + * igb_rx_fifo_flush_82575 - Clean rx fifo after RX enable + * @hw: pointer to the HW structure + * + * After rx enable if managability is enabled then there is likely some + * bad data at the start of the fifo and possibly in the DMA fifo. This + * function clears the fifos and flushes any packets that came in as rx was + * being enabled. + **/ +void igb_rx_fifo_flush_82575(struct e1000_hw *hw) +{ + u32 rctl, rlpml, rxdctl[4], rfctl, temp_rctl, rx_enabled; + int i, ms_wait; + + if (hw->mac.type != e1000_82575 || + !(rd32(E1000_MANC) & E1000_MANC_RCV_TCO_EN)) + return; + + /* Disable all RX queues */ + for (i = 0; i < 4; i++) { + rxdctl[i] = rd32(E1000_RXDCTL(i)); + wr32(E1000_RXDCTL(i), + rxdctl[i] & ~E1000_RXDCTL_QUEUE_ENABLE); + } + /* Poll all queues to verify they have shut down */ + for (ms_wait = 0; ms_wait < 10; ms_wait++) { + msleep(1); + rx_enabled = 0; + for (i = 0; i < 4; i++) + rx_enabled |= rd32(E1000_RXDCTL(i)); + if (!(rx_enabled & E1000_RXDCTL_QUEUE_ENABLE)) + break; + } + + if (ms_wait == 10) + hw_dbg("Queue disable timed out after 10ms\n"); + + /* Clear RLPML, RCTL.SBP, RFCTL.LEF, and set RCTL.LPE so that all + * incoming packets are rejected. Set enable and wait 2ms so that + * any packet that was coming in as RCTL.EN was set is flushed + */ + rfctl = rd32(E1000_RFCTL); + wr32(E1000_RFCTL, rfctl & ~E1000_RFCTL_LEF); + + rlpml = rd32(E1000_RLPML); + wr32(E1000_RLPML, 0); + + rctl = rd32(E1000_RCTL); + temp_rctl = rctl & ~(E1000_RCTL_EN | E1000_RCTL_SBP); + temp_rctl |= E1000_RCTL_LPE; + + wr32(E1000_RCTL, temp_rctl); + wr32(E1000_RCTL, temp_rctl | E1000_RCTL_EN); + wrfl(); + msleep(2); + + /* Enable RX queues that were previously enabled and restore our + * previous state + */ + for (i = 0; i < 4; i++) + wr32(E1000_RXDCTL(i), rxdctl[i]); + wr32(E1000_RCTL, rctl); + wrfl(); + + wr32(E1000_RLPML, rlpml); + wr32(E1000_RFCTL, rfctl); + + /* Flush receive errors generated by workaround */ + rd32(E1000_ROC); + rd32(E1000_RNBC); + rd32(E1000_MPC); +} + static struct e1000_mac_operations e1000_mac_ops_82575 = { .reset_hw = igb_reset_hw_82575, .init_hw = igb_init_hw_82575, .check_for_link = igb_check_for_link_82575, - .rar_set = igb_rar_set_82575, + .rar_set = igb_rar_set, .read_mac_addr = igb_read_mac_addr_82575, .get_speed_and_duplex = igb_get_speed_and_duplex_copper, }; diff --git a/drivers/net/igb/e1000_82575.h b/drivers/net/igb/e1000_82575.h index 76ea846663db..2f848e578a24 100644 --- a/drivers/net/igb/e1000_82575.h +++ b/drivers/net/igb/e1000_82575.h @@ -1,7 +1,7 @@ /******************************************************************************* Intel(R) Gigabit Ethernet Linux driver - Copyright(c) 2007 Intel Corporation. + Copyright(c) 2007 - 2008 Intel Corporation. This program is free software; you can redistribute it and/or modify it under the terms and conditions of the GNU General Public License, @@ -28,7 +28,13 @@ #ifndef _E1000_82575_H_ #define _E1000_82575_H_ +u32 igb_translate_register_82576(u32 reg); +void igb_update_mc_addr_list_82575(struct e1000_hw*, u8*, u32, u32, u32); +extern void igb_shutdown_fiber_serdes_link_82575(struct e1000_hw *hw); +extern void igb_rx_fifo_flush_82575(struct e1000_hw *hw); + #define E1000_RAR_ENTRIES_82575 16 +#define E1000_RAR_ENTRIES_82576 24 /* SRRCTL bit definitions */ #define E1000_SRRCTL_BSIZEPKT_SHIFT 10 /* Shift _right_ */ @@ -56,7 +62,7 @@ #define E1000_EIMS_RX_QUEUE E1000_EICR_RX_QUEUE #define E1000_EIMS_TX_QUEUE E1000_EICR_TX_QUEUE -/* Immediate Interrupt RX (A.K.A. Low Latency Interrupt) */ +/* Immediate Interrupt Rx (A.K.A. Low Latency Interrupt) */ /* Receive Descriptor - Advanced */ union e1000_adv_rx_desc { @@ -93,6 +99,8 @@ union e1000_adv_rx_desc { /* RSS Hash results */ /* RSS Packet Types as indicated in the receive descriptor */ +#define E1000_RXDADV_PKTTYPE_IPV4 0x00000010 /* IPV4 hdr present */ +#define E1000_RXDADV_PKTTYPE_TCP 0x00000100 /* TCP hdr present */ /* Transmit Descriptor - Advanced */ union e1000_adv_tx_desc { @@ -142,9 +150,25 @@ struct e1000_adv_tx_context_desc { #define E1000_RXDCTL_QUEUE_ENABLE 0x02000000 /* Enable specific Rx Queue */ /* Direct Cache Access (DCA) definitions */ - - - -#define E1000_DCA_TXCTRL_TX_WB_RO_EN (1 << 11) /* TX Desc writeback RO bit */ +#define E1000_DCA_CTRL_DCA_ENABLE 0x00000000 /* DCA Enable */ +#define E1000_DCA_CTRL_DCA_DISABLE 0x00000001 /* DCA Disable */ + +#define E1000_DCA_CTRL_DCA_MODE_CB1 0x00 /* DCA Mode CB1 */ +#define E1000_DCA_CTRL_DCA_MODE_CB2 0x02 /* DCA Mode CB2 */ + +#define E1000_DCA_RXCTRL_CPUID_MASK 0x0000001F /* Rx CPUID Mask */ +#define E1000_DCA_RXCTRL_DESC_DCA_EN (1 << 5) /* DCA Rx Desc enable */ +#define E1000_DCA_RXCTRL_HEAD_DCA_EN (1 << 6) /* DCA Rx Desc header enable */ +#define E1000_DCA_RXCTRL_DATA_DCA_EN (1 << 7) /* DCA Rx Desc payload enable */ + +#define E1000_DCA_TXCTRL_CPUID_MASK 0x0000001F /* Tx CPUID Mask */ +#define E1000_DCA_TXCTRL_DESC_DCA_EN (1 << 5) /* DCA Tx Desc enable */ +#define E1000_DCA_TXCTRL_TX_WB_RO_EN (1 << 11) /* Tx Desc writeback RO bit */ + +/* Additional DCA related definitions, note change in position of CPUID */ +#define E1000_DCA_TXCTRL_CPUID_MASK_82576 0xFF000000 /* Tx CPUID Mask */ +#define E1000_DCA_RXCTRL_CPUID_MASK_82576 0xFF000000 /* Rx CPUID Mask */ +#define E1000_DCA_TXCTRL_CPUID_SHIFT 24 /* Tx CPUID now in the last byte */ +#define E1000_DCA_RXCTRL_CPUID_SHIFT 24 /* Rx CPUID now in the last byte */ #endif diff --git a/drivers/net/igb/e1000_defines.h b/drivers/net/igb/e1000_defines.h index 8da9ffedc425..afdba3c9073c 100644 --- a/drivers/net/igb/e1000_defines.h +++ b/drivers/net/igb/e1000_defines.h @@ -1,7 +1,7 @@ /******************************************************************************* Intel(R) Gigabit Ethernet Linux driver - Copyright(c) 2007 Intel Corporation. + Copyright(c) 2007 - 2008 Intel Corporation. This program is free software; you can redistribute it and/or modify it under the terms and conditions of the GNU General Public License, @@ -90,13 +90,18 @@ #define E1000_I2CCMD_ERROR 0x80000000 #define E1000_MAX_SGMII_PHY_REG_ADDR 255 #define E1000_I2CCMD_PHY_TIMEOUT 200 +#define E1000_IVAR_VALID 0x80 +#define E1000_GPIE_NSICR 0x00000001 +#define E1000_GPIE_MSIX_MODE 0x00000010 +#define E1000_GPIE_EIAME 0x40000000 +#define E1000_GPIE_PBA 0x80000000 -/* Receive Decriptor bit definitions */ +/* Receive Descriptor bit definitions */ #define E1000_RXD_STAT_DD 0x01 /* Descriptor Done */ #define E1000_RXD_STAT_EOP 0x02 /* End of Packet */ #define E1000_RXD_STAT_IXSM 0x04 /* Ignore checksum */ #define E1000_RXD_STAT_VP 0x08 /* IEEE VLAN Packet */ -#define E1000_RXD_STAT_UDPCS 0x10 /* UDP xsum caculated */ +#define E1000_RXD_STAT_UDPCS 0x10 /* UDP xsum calculated */ #define E1000_RXD_STAT_TCPCS 0x20 /* TCP xsum calculated */ #define E1000_RXD_STAT_DYNINT 0x800 /* Pkt caused INT via DYNINT */ #define E1000_RXD_ERR_CE 0x01 /* CRC Error */ @@ -213,6 +218,7 @@ /* Device Control */ #define E1000_CTRL_FD 0x00000001 /* Full duplex.0=half; 1=full */ #define E1000_CTRL_GIO_MASTER_DISABLE 0x00000004 /*Blocks new Master requests */ +#define E1000_CTRL_LRST 0x00000008 /* Link reset. 0=normal,1=reset */ #define E1000_CTRL_ASDE 0x00000020 /* Auto-speed detect enable */ #define E1000_CTRL_SLU 0x00000040 /* Set link up (Force Link) */ #define E1000_CTRL_ILOS 0x00000080 /* Invert Loss-Of Signal */ @@ -244,6 +250,7 @@ */ #define E1000_CONNSW_ENRGSRC 0x4 +#define E1000_PCS_CFG_PCS_EN 8 #define E1000_PCS_LCTL_FLV_LINK_UP 1 #define E1000_PCS_LCTL_FSV_100 2 #define E1000_PCS_LCTL_FSV_1000 4 @@ -253,6 +260,7 @@ #define E1000_PCS_LCTL_AN_ENABLE 0x10000 #define E1000_PCS_LCTL_AN_RESTART 0x20000 #define E1000_PCS_LCTL_AN_TIMEOUT 0x40000 +#define E1000_ENABLE_SERDES_LOOPBACK 0x0410 #define E1000_PCS_LSTS_LINK_OK 1 #define E1000_PCS_LSTS_SPEED_100 2 @@ -340,6 +348,7 @@ #define E1000_RXCSUM_PCSD 0x00002000 /* packet checksum disabled */ /* Header split receive */ +#define E1000_RFCTL_LEF 0x00040000 /* Collision related configuration parameters */ #define E1000_COLLISION_THRESHOLD 15 @@ -359,6 +368,7 @@ #define E1000_PBA_16K 0x0010 /* 16KB, default TX allocation */ #define E1000_PBA_24K 0x0018 #define E1000_PBA_34K 0x0022 +#define E1000_PBA_64K 0x0040 /* 64KB */ #define IFS_MAX 80 #define IFS_MIN 40 @@ -379,7 +389,7 @@ #define E1000_ICR_RXO 0x00000040 /* rx overrun */ #define E1000_ICR_RXT0 0x00000080 /* rx timer intr (ring 0) */ #define E1000_ICR_MDAC 0x00000200 /* MDIO access complete */ -#define E1000_ICR_RXCFG 0x00000400 /* RX /c/ ordered set */ +#define E1000_ICR_RXCFG 0x00000400 /* Rx /c/ ordered set */ #define E1000_ICR_GPI_EN0 0x00000800 /* GP Int 0 */ #define E1000_ICR_GPI_EN1 0x00001000 /* GP Int 1 */ #define E1000_ICR_GPI_EN2 0x00002000 /* GP Int 2 */ @@ -443,12 +453,6 @@ #define E1000_IMS_RXSEQ E1000_ICR_RXSEQ /* rx sequence error */ #define E1000_IMS_RXDMT0 E1000_ICR_RXDMT0 /* rx desc min. threshold */ #define E1000_IMS_RXT0 E1000_ICR_RXT0 /* rx timer intr */ -/* queue 0 Rx descriptor FIFO parity error */ -/* queue 0 Tx descriptor FIFO parity error */ -/* host arb read buffer parity error */ -/* packet buffer parity error */ -/* queue 1 Rx descriptor FIFO parity error */ -/* queue 1 Tx descriptor FIFO parity error */ /* Extended Interrupt Mask Set */ #define E1000_EIMS_TCP_TIMER E1000_EICR_TCP_TIMER /* TCP Timer */ @@ -457,12 +461,6 @@ /* Interrupt Cause Set */ #define E1000_ICS_LSC E1000_ICR_LSC /* Link Status Change */ #define E1000_ICS_RXDMT0 E1000_ICR_RXDMT0 /* rx desc min. threshold */ -/* queue 0 Rx descriptor FIFO parity error */ -/* queue 0 Tx descriptor FIFO parity error */ -/* host arb read buffer parity error */ -/* packet buffer parity error */ -/* queue 1 Rx descriptor FIFO parity error */ -/* queue 1 Tx descriptor FIFO parity error */ /* Extended Interrupt Cause Set */ @@ -539,6 +537,7 @@ /* PHY Control Register */ #define MII_CR_FULL_DUPLEX 0x0100 /* FDX =1, half duplex =0 */ #define MII_CR_RESTART_AUTO_NEG 0x0200 /* Restart auto negotiation */ +#define MII_CR_POWER_DOWN 0x0800 /* Power down */ #define MII_CR_AUTO_NEG_EN 0x1000 /* Auto Neg Enable */ #define MII_CR_LOOPBACK 0x4000 /* 0 = normal, 1 = loopback */ #define MII_CR_RESET 0x8000 /* 0 = normal, 1 = PHY reset */ @@ -567,7 +566,6 @@ /* 1000BASE-T Control Register */ #define CR_1000T_HD_CAPS 0x0100 /* Advertise 1000T HD capability */ #define CR_1000T_FD_CAPS 0x0200 /* Advertise 1000T FD capability */ - /* 0=DTE device */ #define CR_1000T_MS_VALUE 0x0800 /* 1=Configure PHY as Master */ /* 0=Configure PHY as Slave */ #define CR_1000T_MS_ENABLE 0x1000 /* 1=Master/Slave manual config value */ @@ -581,7 +579,7 @@ /* PHY 1000 MII Register/Bit Definitions */ /* PHY Registers defined by IEEE */ #define PHY_CONTROL 0x00 /* Control Register */ -#define PHY_STATUS 0x01 /* Status Regiser */ +#define PHY_STATUS 0x01 /* Status Register */ #define PHY_ID1 0x02 /* Phy Id Reg (word 1) */ #define PHY_ID2 0x03 /* Phy Id Reg (word 2) */ #define PHY_AUTONEG_ADV 0x04 /* Autoneg Advertisement */ @@ -708,8 +706,8 @@ /* Auto crossover enabled all speeds */ #define M88E1000_PSCR_AUTO_X_MODE 0x0060 /* - * 1=Enable Extended 10BASE-T distance (Lower 10BASE-T RX Threshold - * 0=Normal 10BASE-T RX Threshold + * 1=Enable Extended 10BASE-T distance (Lower 10BASE-T Rx Threshold + * 0=Normal 10BASE-T Rx Threshold */ /* 1=5-bit interface in 100BASE-TX, 0=MII interface in 100BASE-TX */ #define M88E1000_PSCR_ASSERT_CRS_ON_TX 0x0800 /* 1=Assert CRS on Transmit */ diff --git a/drivers/net/igb/e1000_hw.h b/drivers/net/igb/e1000_hw.h index 7b2c70a3b8cc..19fa4ee96f2e 100644 --- a/drivers/net/igb/e1000_hw.h +++ b/drivers/net/igb/e1000_hw.h @@ -38,6 +38,10 @@ struct e1000_hw; +#define E1000_DEV_ID_82576 0x10C9 +#define E1000_DEV_ID_82576_FIBER 0x10E6 +#define E1000_DEV_ID_82576_SERDES 0x10E7 +#define E1000_DEV_ID_82576_QUAD_COPPER 0x10E8 #define E1000_DEV_ID_82575EB_COPPER 0x10A7 #define E1000_DEV_ID_82575EB_FIBER_SERDES 0x10A9 #define E1000_DEV_ID_82575GB_QUAD_COPPER 0x10D6 @@ -50,6 +54,7 @@ struct e1000_hw; enum e1000_mac_type { e1000_undefined = 0, e1000_82575, + e1000_82576, e1000_num_macs /* List is 1-based, so subtract 1 for true count. */ }; @@ -410,14 +415,17 @@ struct e1000_mac_operations { s32 (*check_for_link)(struct e1000_hw *); s32 (*reset_hw)(struct e1000_hw *); s32 (*init_hw)(struct e1000_hw *); + bool (*check_mng_mode)(struct e1000_hw *); s32 (*setup_physical_interface)(struct e1000_hw *); void (*rar_set)(struct e1000_hw *, u8 *, u32); s32 (*read_mac_addr)(struct e1000_hw *); s32 (*get_speed_and_duplex)(struct e1000_hw *, u16 *, u16 *); + void (*mta_set)(struct e1000_hw *, u32); }; struct e1000_phy_operations { s32 (*acquire_phy)(struct e1000_hw *); + s32 (*check_reset_block)(struct e1000_hw *); s32 (*force_speed_duplex)(struct e1000_hw *); s32 (*get_cfg_done)(struct e1000_hw *hw); s32 (*get_cable_length)(struct e1000_hw *); @@ -586,14 +594,10 @@ struct e1000_hw { #ifdef DEBUG extern char *igb_get_hw_dev_name(struct e1000_hw *hw); -#define hw_dbg(hw, format, arg...) \ +#define hw_dbg(format, arg...) \ printk(KERN_DEBUG "%s: " format, igb_get_hw_dev_name(hw), ##arg) #else -static inline int __attribute__ ((format (printf, 2, 3))) -hw_dbg(struct e1000_hw *hw, const char *format, ...) -{ - return 0; -} +#define hw_dbg(format, arg...) #endif #endif diff --git a/drivers/net/igb/e1000_mac.c b/drivers/net/igb/e1000_mac.c index 3e84a3f0c1d8..20408aa1f916 100644 --- a/drivers/net/igb/e1000_mac.c +++ b/drivers/net/igb/e1000_mac.c @@ -36,10 +36,9 @@ static s32 igb_set_default_fc(struct e1000_hw *hw); static s32 igb_set_fc_watermarks(struct e1000_hw *hw); -static u32 igb_hash_mc_addr(struct e1000_hw *hw, u8 *mc_addr); /** - * e1000_remove_device - Free device specific structure + * igb_remove_device - Free device specific structure * @hw: pointer to the HW structure * * If a device specific structure was allocated, this function will @@ -73,7 +72,7 @@ static s32 igb_read_pcie_cap_reg(struct e1000_hw *hw, u32 reg, u16 *value) } /** - * e1000_get_bus_info_pcie - Get PCIe bus information + * igb_get_bus_info_pcie - Get PCIe bus information * @hw: pointer to the HW structure * * Determines and stores the system bus information for a particular @@ -113,7 +112,7 @@ s32 igb_get_bus_info_pcie(struct e1000_hw *hw) } /** - * e1000_clear_vfta - Clear VLAN filter table + * igb_clear_vfta - Clear VLAN filter table * @hw: pointer to the HW structure * * Clears the register array which contains the VLAN filter table by @@ -130,7 +129,7 @@ void igb_clear_vfta(struct e1000_hw *hw) } /** - * e1000_write_vfta - Write value to VLAN filter table + * igb_write_vfta - Write value to VLAN filter table * @hw: pointer to the HW structure * @offset: register offset in VLAN filter table * @value: register value written to VLAN filter table @@ -145,7 +144,7 @@ void igb_write_vfta(struct e1000_hw *hw, u32 offset, u32 value) } /** - * e1000_init_rx_addrs - Initialize receive address's + * igb_init_rx_addrs - Initialize receive address's * @hw: pointer to the HW structure * @rar_count: receive address registers * @@ -158,12 +157,12 @@ void igb_init_rx_addrs(struct e1000_hw *hw, u16 rar_count) u32 i; /* Setup the receive address */ - hw_dbg(hw, "Programming MAC Address into RAR[0]\n"); + hw_dbg("Programming MAC Address into RAR[0]\n"); hw->mac.ops.rar_set(hw, hw->mac.addr, 0); /* Zero out the other (rar_entry_count - 1) receive addresses */ - hw_dbg(hw, "Clearing RAR[1-%u]\n", rar_count-1); + hw_dbg("Clearing RAR[1-%u]\n", rar_count-1); for (i = 1; i < rar_count; i++) { array_wr32(E1000_RA, (i << 1), 0); wrfl(); @@ -173,7 +172,7 @@ void igb_init_rx_addrs(struct e1000_hw *hw, u16 rar_count) } /** - * e1000_check_alt_mac_addr - Check for alternate MAC addr + * igb_check_alt_mac_addr - Check for alternate MAC addr * @hw: pointer to the HW structure * * Checks the nvm for an alternate MAC address. An alternate MAC address @@ -193,7 +192,7 @@ s32 igb_check_alt_mac_addr(struct e1000_hw *hw) ret_val = hw->nvm.ops.read_nvm(hw, NVM_ALT_MAC_ADDR_PTR, 1, &nvm_alt_mac_addr_offset); if (ret_val) { - hw_dbg(hw, "NVM Read Error\n"); + hw_dbg("NVM Read Error\n"); goto out; } @@ -209,7 +208,7 @@ s32 igb_check_alt_mac_addr(struct e1000_hw *hw) offset = nvm_alt_mac_addr_offset + (i >> 1); ret_val = hw->nvm.ops.read_nvm(hw, offset, 1, &nvm_data); if (ret_val) { - hw_dbg(hw, "NVM Read Error\n"); + hw_dbg("NVM Read Error\n"); goto out; } @@ -233,7 +232,7 @@ out: } /** - * e1000_rar_set - Set receive address register + * igb_rar_set - Set receive address register * @hw: pointer to the HW structure * @addr: pointer to the receive address * @index: receive address array register @@ -263,7 +262,7 @@ void igb_rar_set(struct e1000_hw *hw, u8 *addr, u32 index) } /** - * e1000_mta_set - Set multicast filter table address + * igb_mta_set - Set multicast filter table address * @hw: pointer to the HW structure * @hash_value: determines the MTA register and bit to set * @@ -298,7 +297,7 @@ static void igb_mta_set(struct e1000_hw *hw, u32 hash_value) } /** - * e1000_update_mc_addr_list - Update Multicast addresses + * igb_update_mc_addr_list - Update Multicast addresses * @hw: pointer to the HW structure * @mc_addr_list: array of multicast addresses to program * @mc_addr_count: number of multicast addresses to program @@ -336,7 +335,7 @@ void igb_update_mc_addr_list(struct e1000_hw *hw, } /* Clear the old settings from the MTA */ - hw_dbg(hw, "Clearing MTA\n"); + hw_dbg("Clearing MTA\n"); for (i = 0; i < hw->mac.mta_reg_count; i++) { array_wr32(E1000_MTA, i, 0); wrfl(); @@ -345,14 +344,14 @@ void igb_update_mc_addr_list(struct e1000_hw *hw, /* Load any remaining multicast addresses into the hash table. */ for (; mc_addr_count > 0; mc_addr_count--) { hash_value = igb_hash_mc_addr(hw, mc_addr_list); - hw_dbg(hw, "Hash value = 0x%03X\n", hash_value); + hw_dbg("Hash value = 0x%03X\n", hash_value); igb_mta_set(hw, hash_value); mc_addr_list += ETH_ALEN; } } /** - * e1000_hash_mc_addr - Generate a multicast hash value + * igb_hash_mc_addr - Generate a multicast hash value * @hw: pointer to the HW structure * @mc_addr: pointer to a multicast address * @@ -360,7 +359,7 @@ void igb_update_mc_addr_list(struct e1000_hw *hw, * the multicast filter table array address and new table value. See * igb_mta_set() **/ -static u32 igb_hash_mc_addr(struct e1000_hw *hw, u8 *mc_addr) +u32 igb_hash_mc_addr(struct e1000_hw *hw, u8 *mc_addr) { u32 hash_value, hash_mask; u8 bit_shift = 0; @@ -423,7 +422,7 @@ static u32 igb_hash_mc_addr(struct e1000_hw *hw, u8 *mc_addr) } /** - * e1000_clear_hw_cntrs_base - Clear base hardware counters + * igb_clear_hw_cntrs_base - Clear base hardware counters * @hw: pointer to the HW structure * * Clears the base hardware counters by reading the counter registers. @@ -472,7 +471,7 @@ void igb_clear_hw_cntrs_base(struct e1000_hw *hw) } /** - * e1000_check_for_copper_link - Check for link (Copper) + * igb_check_for_copper_link - Check for link (Copper) * @hw: pointer to the HW structure * * Checks to see of the link status of the hardware has changed. If a @@ -540,14 +539,14 @@ s32 igb_check_for_copper_link(struct e1000_hw *hw) */ ret_val = igb_config_fc_after_link_up(hw); if (ret_val) - hw_dbg(hw, "Error configuring flow control\n"); + hw_dbg("Error configuring flow control\n"); out: return ret_val; } /** - * e1000_setup_link - Setup flow control and link settings + * igb_setup_link - Setup flow control and link settings * @hw: pointer to the HW structure * * Determines which flow control settings to use, then configures flow @@ -578,7 +577,7 @@ s32 igb_setup_link(struct e1000_hw *hw) */ hw->fc.original_type = hw->fc.type; - hw_dbg(hw, "After fix-ups FlowControl is now = %x\n", hw->fc.type); + hw_dbg("After fix-ups FlowControl is now = %x\n", hw->fc.type); /* Call the necessary media_type subroutine to configure the link. */ ret_val = hw->mac.ops.setup_physical_interface(hw); @@ -591,8 +590,7 @@ s32 igb_setup_link(struct e1000_hw *hw) * control is disabled, because it does not hurt anything to * initialize these registers. */ - hw_dbg(hw, - "Initializing the Flow Control address, type and timer regs\n"); + hw_dbg("Initializing the Flow Control address, type and timer regs\n"); wr32(E1000_FCT, FLOW_CONTROL_TYPE); wr32(E1000_FCAH, FLOW_CONTROL_ADDRESS_HIGH); wr32(E1000_FCAL, FLOW_CONTROL_ADDRESS_LOW); @@ -606,7 +604,7 @@ out: } /** - * e1000_config_collision_dist - Configure collision distance + * igb_config_collision_dist - Configure collision distance * @hw: pointer to the HW structure * * Configures the collision distance to the default value and is used @@ -627,7 +625,7 @@ void igb_config_collision_dist(struct e1000_hw *hw) } /** - * e1000_set_fc_watermarks - Set flow control high/low watermarks + * igb_set_fc_watermarks - Set flow control high/low watermarks * @hw: pointer to the HW structure * * Sets the flow control high/low threshold (watermark) registers. If @@ -665,7 +663,7 @@ static s32 igb_set_fc_watermarks(struct e1000_hw *hw) } /** - * e1000_set_default_fc - Set flow control default values + * igb_set_default_fc - Set flow control default values * @hw: pointer to the HW structure * * Read the EEPROM for the default values for flow control and store the @@ -689,7 +687,7 @@ static s32 igb_set_default_fc(struct e1000_hw *hw) &nvm_data); if (ret_val) { - hw_dbg(hw, "NVM Read Error\n"); + hw_dbg("NVM Read Error\n"); goto out; } @@ -706,7 +704,7 @@ out: } /** - * e1000_force_mac_fc - Force the MAC's flow control settings + * igb_force_mac_fc - Force the MAC's flow control settings * @hw: pointer to the HW structure * * Force the MAC's flow control settings. Sets the TFCE and RFCE bits in the @@ -740,7 +738,7 @@ s32 igb_force_mac_fc(struct e1000_hw *hw) * 3: Both Rx and TX flow control (symmetric) is enabled. * other: No other values should be possible at this point. */ - hw_dbg(hw, "hw->fc.type = %u\n", hw->fc.type); + hw_dbg("hw->fc.type = %u\n", hw->fc.type); switch (hw->fc.type) { case e1000_fc_none: @@ -758,7 +756,7 @@ s32 igb_force_mac_fc(struct e1000_hw *hw) ctrl |= (E1000_CTRL_TFCE | E1000_CTRL_RFCE); break; default: - hw_dbg(hw, "Flow control param set incorrectly\n"); + hw_dbg("Flow control param set incorrectly\n"); ret_val = -E1000_ERR_CONFIG; goto out; } @@ -770,7 +768,7 @@ out: } /** - * e1000_config_fc_after_link_up - Configures flow control after link + * igb_config_fc_after_link_up - Configures flow control after link * @hw: pointer to the HW structure * * Checks the status of auto-negotiation after link up to ensure that the @@ -801,7 +799,7 @@ s32 igb_config_fc_after_link_up(struct e1000_hw *hw) } if (ret_val) { - hw_dbg(hw, "Error forcing flow control settings\n"); + hw_dbg("Error forcing flow control settings\n"); goto out; } @@ -827,7 +825,7 @@ s32 igb_config_fc_after_link_up(struct e1000_hw *hw) goto out; if (!(mii_status_reg & MII_SR_AUTONEG_COMPLETE)) { - hw_dbg(hw, "Copper PHY and Auto Neg " + hw_dbg("Copper PHY and Auto Neg " "has not completed.\n"); goto out; } @@ -893,11 +891,11 @@ s32 igb_config_fc_after_link_up(struct e1000_hw *hw) */ if (hw->fc.original_type == e1000_fc_full) { hw->fc.type = e1000_fc_full; - hw_dbg(hw, "Flow Control = FULL.\r\n"); + hw_dbg("Flow Control = FULL.\r\n"); } else { hw->fc.type = e1000_fc_rx_pause; - hw_dbg(hw, "Flow Control = " - "RX PAUSE frames only.\r\n"); + hw_dbg("Flow Control = " + "RX PAUSE frames only.\r\n"); } } /* @@ -913,7 +911,7 @@ s32 igb_config_fc_after_link_up(struct e1000_hw *hw) (mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE) && (mii_nway_lp_ability_reg & NWAY_LPAR_ASM_DIR)) { hw->fc.type = e1000_fc_tx_pause; - hw_dbg(hw, "Flow Control = TX PAUSE frames only.\r\n"); + hw_dbg("Flow Control = TX PAUSE frames only.\r\n"); } /* * For transmitting PAUSE frames ONLY. @@ -928,7 +926,7 @@ s32 igb_config_fc_after_link_up(struct e1000_hw *hw) !(mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE) && (mii_nway_lp_ability_reg & NWAY_LPAR_ASM_DIR)) { hw->fc.type = e1000_fc_rx_pause; - hw_dbg(hw, "Flow Control = RX PAUSE frames only.\r\n"); + hw_dbg("Flow Control = RX PAUSE frames only.\r\n"); } /* * Per the IEEE spec, at this point flow control should be @@ -955,10 +953,10 @@ s32 igb_config_fc_after_link_up(struct e1000_hw *hw) hw->fc.original_type == e1000_fc_tx_pause) || hw->fc.strict_ieee) { hw->fc.type = e1000_fc_none; - hw_dbg(hw, "Flow Control = NONE.\r\n"); + hw_dbg("Flow Control = NONE.\r\n"); } else { hw->fc.type = e1000_fc_rx_pause; - hw_dbg(hw, "Flow Control = RX PAUSE frames only.\r\n"); + hw_dbg("Flow Control = RX PAUSE frames only.\r\n"); } /* @@ -968,7 +966,7 @@ s32 igb_config_fc_after_link_up(struct e1000_hw *hw) */ ret_val = hw->mac.ops.get_speed_and_duplex(hw, &speed, &duplex); if (ret_val) { - hw_dbg(hw, "Error getting link speed and duplex\n"); + hw_dbg("Error getting link speed and duplex\n"); goto out; } @@ -981,7 +979,7 @@ s32 igb_config_fc_after_link_up(struct e1000_hw *hw) */ ret_val = igb_force_mac_fc(hw); if (ret_val) { - hw_dbg(hw, "Error forcing flow control settings\n"); + hw_dbg("Error forcing flow control settings\n"); goto out; } } @@ -991,7 +989,7 @@ out: } /** - * e1000_get_speed_and_duplex_copper - Retreive current speed/duplex + * igb_get_speed_and_duplex_copper - Retreive current speed/duplex * @hw: pointer to the HW structure * @speed: stores the current speed * @duplex: stores the current duplex @@ -1007,28 +1005,28 @@ s32 igb_get_speed_and_duplex_copper(struct e1000_hw *hw, u16 *speed, status = rd32(E1000_STATUS); if (status & E1000_STATUS_SPEED_1000) { *speed = SPEED_1000; - hw_dbg(hw, "1000 Mbs, "); + hw_dbg("1000 Mbs, "); } else if (status & E1000_STATUS_SPEED_100) { *speed = SPEED_100; - hw_dbg(hw, "100 Mbs, "); + hw_dbg("100 Mbs, "); } else { *speed = SPEED_10; - hw_dbg(hw, "10 Mbs, "); + hw_dbg("10 Mbs, "); } if (status & E1000_STATUS_FD) { *duplex = FULL_DUPLEX; - hw_dbg(hw, "Full Duplex\n"); + hw_dbg("Full Duplex\n"); } else { *duplex = HALF_DUPLEX; - hw_dbg(hw, "Half Duplex\n"); + hw_dbg("Half Duplex\n"); } return 0; } /** - * e1000_get_hw_semaphore - Acquire hardware semaphore + * igb_get_hw_semaphore - Acquire hardware semaphore * @hw: pointer to the HW structure * * Acquire the HW semaphore to access the PHY or NVM @@ -1051,7 +1049,7 @@ s32 igb_get_hw_semaphore(struct e1000_hw *hw) } if (i == timeout) { - hw_dbg(hw, "Driver can't access device - SMBI bit is set.\n"); + hw_dbg("Driver can't access device - SMBI bit is set.\n"); ret_val = -E1000_ERR_NVM; goto out; } @@ -1071,7 +1069,7 @@ s32 igb_get_hw_semaphore(struct e1000_hw *hw) if (i == timeout) { /* Release semaphores */ igb_put_hw_semaphore(hw); - hw_dbg(hw, "Driver can't access the NVM\n"); + hw_dbg("Driver can't access the NVM\n"); ret_val = -E1000_ERR_NVM; goto out; } @@ -1081,7 +1079,7 @@ out: } /** - * e1000_put_hw_semaphore - Release hardware semaphore + * igb_put_hw_semaphore - Release hardware semaphore * @hw: pointer to the HW structure * * Release hardware semaphore used to access the PHY or NVM @@ -1098,7 +1096,7 @@ void igb_put_hw_semaphore(struct e1000_hw *hw) } /** - * e1000_get_auto_rd_done - Check for auto read completion + * igb_get_auto_rd_done - Check for auto read completion * @hw: pointer to the HW structure * * Check EEPROM for Auto Read done bit. @@ -1117,7 +1115,7 @@ s32 igb_get_auto_rd_done(struct e1000_hw *hw) } if (i == AUTO_READ_DONE_TIMEOUT) { - hw_dbg(hw, "Auto read by HW from NVM has not completed.\n"); + hw_dbg("Auto read by HW from NVM has not completed.\n"); ret_val = -E1000_ERR_RESET; goto out; } @@ -1127,7 +1125,7 @@ out: } /** - * e1000_valid_led_default - Verify a valid default LED config + * igb_valid_led_default - Verify a valid default LED config * @hw: pointer to the HW structure * @data: pointer to the NVM (EEPROM) * @@ -1140,7 +1138,7 @@ static s32 igb_valid_led_default(struct e1000_hw *hw, u16 *data) ret_val = hw->nvm.ops.read_nvm(hw, NVM_ID_LED_SETTINGS, 1, data); if (ret_val) { - hw_dbg(hw, "NVM Read Error\n"); + hw_dbg("NVM Read Error\n"); goto out; } @@ -1152,7 +1150,7 @@ out: } /** - * e1000_id_led_init - + * igb_id_led_init - * @hw: pointer to the HW structure * **/ @@ -1217,7 +1215,7 @@ out: } /** - * e1000_cleanup_led - Set LED config to default operation + * igb_cleanup_led - Set LED config to default operation * @hw: pointer to the HW structure * * Remove the current LED configuration and set the LED configuration @@ -1230,7 +1228,7 @@ s32 igb_cleanup_led(struct e1000_hw *hw) } /** - * e1000_blink_led - Blink LED + * igb_blink_led - Blink LED * @hw: pointer to the HW structure * * Blink the led's which are set to be on. @@ -1263,7 +1261,7 @@ s32 igb_blink_led(struct e1000_hw *hw) } /** - * e1000_led_off - Turn LED off + * igb_led_off - Turn LED off * @hw: pointer to the HW structure * * Turn LED off. @@ -1290,7 +1288,7 @@ s32 igb_led_off(struct e1000_hw *hw) } /** - * e1000_disable_pcie_master - Disables PCI-express master access + * igb_disable_pcie_master - Disables PCI-express master access * @hw: pointer to the HW structure * * Returns 0 (0) if successful, else returns -10 @@ -1322,7 +1320,7 @@ s32 igb_disable_pcie_master(struct e1000_hw *hw) } if (!timeout) { - hw_dbg(hw, "Master requests are pending.\n"); + hw_dbg("Master requests are pending.\n"); ret_val = -E1000_ERR_MASTER_REQUESTS_PENDING; goto out; } @@ -1332,7 +1330,7 @@ out: } /** - * e1000_reset_adaptive - Reset Adaptive Interframe Spacing + * igb_reset_adaptive - Reset Adaptive Interframe Spacing * @hw: pointer to the HW structure * * Reset the Adaptive Interframe Spacing throttle to default values. @@ -1342,7 +1340,7 @@ void igb_reset_adaptive(struct e1000_hw *hw) struct e1000_mac_info *mac = &hw->mac; if (!mac->adaptive_ifs) { - hw_dbg(hw, "Not in Adaptive IFS mode!\n"); + hw_dbg("Not in Adaptive IFS mode!\n"); goto out; } @@ -1361,7 +1359,7 @@ out: } /** - * e1000_update_adaptive - Update Adaptive Interframe Spacing + * igb_update_adaptive - Update Adaptive Interframe Spacing * @hw: pointer to the HW structure * * Update the Adaptive Interframe Spacing Throttle value based on the @@ -1372,7 +1370,7 @@ void igb_update_adaptive(struct e1000_hw *hw) struct e1000_mac_info *mac = &hw->mac; if (!mac->adaptive_ifs) { - hw_dbg(hw, "Not in Adaptive IFS mode!\n"); + hw_dbg("Not in Adaptive IFS mode!\n"); goto out; } @@ -1402,7 +1400,7 @@ out: } /** - * e1000_validate_mdi_setting - Verify MDI/MDIx settings + * igb_validate_mdi_setting - Verify MDI/MDIx settings * @hw: pointer to the HW structure * * Verify that when not using auto-negotitation that MDI/MDIx is correctly @@ -1413,7 +1411,7 @@ s32 igb_validate_mdi_setting(struct e1000_hw *hw) s32 ret_val = 0; if (!hw->mac.autoneg && (hw->phy.mdix == 0 || hw->phy.mdix == 3)) { - hw_dbg(hw, "Invalid MDI setting detected\n"); + hw_dbg("Invalid MDI setting detected\n"); hw->phy.mdix = 1; ret_val = -E1000_ERR_CONFIG; goto out; @@ -1424,7 +1422,7 @@ out: } /** - * e1000_write_8bit_ctrl_reg - Write a 8bit CTRL register + * igb_write_8bit_ctrl_reg - Write a 8bit CTRL register * @hw: pointer to the HW structure * @reg: 32bit register offset such as E1000_SCTL * @offset: register offset to write to @@ -1452,7 +1450,7 @@ s32 igb_write_8bit_ctrl_reg(struct e1000_hw *hw, u32 reg, break; } if (!(regvalue & E1000_GEN_CTL_READY)) { - hw_dbg(hw, "Reg %08x did not indicate ready\n", reg); + hw_dbg("Reg %08x did not indicate ready\n", reg); ret_val = -E1000_ERR_PHY; goto out; } @@ -1462,7 +1460,7 @@ out: } /** - * e1000_enable_mng_pass_thru - Enable processing of ARP's + * igb_enable_mng_pass_thru - Enable processing of ARP's * @hw: pointer to the HW structure * * Verifies the hardware needs to allow ARPs to be processed by the host. diff --git a/drivers/net/igb/e1000_mac.h b/drivers/net/igb/e1000_mac.h index 326b6592307b..dc2f8cce15e7 100644 --- a/drivers/net/igb/e1000_mac.h +++ b/drivers/net/igb/e1000_mac.h @@ -94,5 +94,6 @@ enum e1000_mng_mode { #define E1000_HICR_C 0x02 extern void e1000_init_function_pointers_82575(struct e1000_hw *hw); +extern u32 igb_hash_mc_addr(struct e1000_hw *hw, u8 *mc_addr); #endif diff --git a/drivers/net/igb/e1000_nvm.c b/drivers/net/igb/e1000_nvm.c index 2897106fee92..a84e4e429fa7 100644 --- a/drivers/net/igb/e1000_nvm.c +++ b/drivers/net/igb/e1000_nvm.c @@ -32,7 +32,7 @@ #include "e1000_nvm.h" /** - * e1000_raise_eec_clk - Raise EEPROM clock + * igb_raise_eec_clk - Raise EEPROM clock * @hw: pointer to the HW structure * @eecd: pointer to the EEPROM * @@ -47,7 +47,7 @@ static void igb_raise_eec_clk(struct e1000_hw *hw, u32 *eecd) } /** - * e1000_lower_eec_clk - Lower EEPROM clock + * igb_lower_eec_clk - Lower EEPROM clock * @hw: pointer to the HW structure * @eecd: pointer to the EEPROM * @@ -62,7 +62,7 @@ static void igb_lower_eec_clk(struct e1000_hw *hw, u32 *eecd) } /** - * e1000_shift_out_eec_bits - Shift data bits our to the EEPROM + * igb_shift_out_eec_bits - Shift data bits our to the EEPROM * @hw: pointer to the HW structure * @data: data to send to the EEPROM * @count: number of bits to shift out @@ -105,7 +105,7 @@ static void igb_shift_out_eec_bits(struct e1000_hw *hw, u16 data, u16 count) } /** - * e1000_shift_in_eec_bits - Shift data bits in from the EEPROM + * igb_shift_in_eec_bits - Shift data bits in from the EEPROM * @hw: pointer to the HW structure * @count: number of bits to shift in * @@ -143,7 +143,7 @@ static u16 igb_shift_in_eec_bits(struct e1000_hw *hw, u16 count) } /** - * e1000_poll_eerd_eewr_done - Poll for EEPROM read/write completion + * igb_poll_eerd_eewr_done - Poll for EEPROM read/write completion * @hw: pointer to the HW structure * @ee_reg: EEPROM flag for polling * @@ -174,7 +174,7 @@ static s32 igb_poll_eerd_eewr_done(struct e1000_hw *hw, int ee_reg) } /** - * e1000_acquire_nvm - Generic request for access to EEPROM + * igb_acquire_nvm - Generic request for access to EEPROM * @hw: pointer to the HW structure * * Set the EEPROM access request bit and wait for EEPROM access grant bit. @@ -202,7 +202,7 @@ s32 igb_acquire_nvm(struct e1000_hw *hw) if (!timeout) { eecd &= ~E1000_EECD_REQ; wr32(E1000_EECD, eecd); - hw_dbg(hw, "Could not acquire NVM grant\n"); + hw_dbg("Could not acquire NVM grant\n"); ret_val = -E1000_ERR_NVM; } @@ -210,7 +210,7 @@ s32 igb_acquire_nvm(struct e1000_hw *hw) } /** - * e1000_standby_nvm - Return EEPROM to standby state + * igb_standby_nvm - Return EEPROM to standby state * @hw: pointer to the HW structure * * Return the EEPROM to a standby state. @@ -273,7 +273,7 @@ static void e1000_stop_nvm(struct e1000_hw *hw) } /** - * e1000_release_nvm - Release exclusive access to EEPROM + * igb_release_nvm - Release exclusive access to EEPROM * @hw: pointer to the HW structure * * Stop any current commands to the EEPROM and clear the EEPROM request bit. @@ -290,7 +290,7 @@ void igb_release_nvm(struct e1000_hw *hw) } /** - * e1000_ready_nvm_eeprom - Prepares EEPROM for read/write + * igb_ready_nvm_eeprom - Prepares EEPROM for read/write * @hw: pointer to the HW structure * * Setups the EEPROM for reading and writing. @@ -337,7 +337,7 @@ static s32 igb_ready_nvm_eeprom(struct e1000_hw *hw) } if (!timeout) { - hw_dbg(hw, "SPI NVM Status error\n"); + hw_dbg("SPI NVM Status error\n"); ret_val = -E1000_ERR_NVM; goto out; } @@ -348,7 +348,7 @@ out: } /** - * e1000_read_nvm_eerd - Reads EEPROM using EERD register + * igb_read_nvm_eerd - Reads EEPROM using EERD register * @hw: pointer to the HW structure * @offset: offset of word in the EEPROM to read * @words: number of words to read @@ -368,7 +368,7 @@ s32 igb_read_nvm_eerd(struct e1000_hw *hw, u16 offset, u16 words, u16 *data) */ if ((offset >= nvm->word_size) || (words > (nvm->word_size - offset)) || (words == 0)) { - hw_dbg(hw, "nvm parameter(s) out of bounds\n"); + hw_dbg("nvm parameter(s) out of bounds\n"); ret_val = -E1000_ERR_NVM; goto out; } @@ -391,7 +391,7 @@ out: } /** - * e1000_write_nvm_spi - Write to EEPROM using SPI + * igb_write_nvm_spi - Write to EEPROM using SPI * @hw: pointer to the HW structure * @offset: offset within the EEPROM to be written to * @words: number of words to write @@ -414,7 +414,7 @@ s32 igb_write_nvm_spi(struct e1000_hw *hw, u16 offset, u16 words, u16 *data) */ if ((offset >= nvm->word_size) || (words > (nvm->word_size - offset)) || (words == 0)) { - hw_dbg(hw, "nvm parameter(s) out of bounds\n"); + hw_dbg("nvm parameter(s) out of bounds\n"); ret_val = -E1000_ERR_NVM; goto out; } @@ -475,7 +475,7 @@ out: } /** - * e1000_read_part_num - Read device part number + * igb_read_part_num - Read device part number * @hw: pointer to the HW structure * @part_num: pointer to device part number * @@ -489,14 +489,14 @@ s32 igb_read_part_num(struct e1000_hw *hw, u32 *part_num) ret_val = hw->nvm.ops.read_nvm(hw, NVM_PBA_OFFSET_0, 1, &nvm_data); if (ret_val) { - hw_dbg(hw, "NVM Read Error\n"); + hw_dbg("NVM Read Error\n"); goto out; } *part_num = (u32)(nvm_data << 16); ret_val = hw->nvm.ops.read_nvm(hw, NVM_PBA_OFFSET_1, 1, &nvm_data); if (ret_val) { - hw_dbg(hw, "NVM Read Error\n"); + hw_dbg("NVM Read Error\n"); goto out; } *part_num |= nvm_data; @@ -506,7 +506,7 @@ out: } /** - * e1000_read_mac_addr - Read device MAC address + * igb_read_mac_addr - Read device MAC address * @hw: pointer to the HW structure * * Reads the device MAC address from the EEPROM and stores the value. @@ -522,7 +522,7 @@ s32 igb_read_mac_addr(struct e1000_hw *hw) offset = i >> 1; ret_val = hw->nvm.ops.read_nvm(hw, offset, 1, &nvm_data); if (ret_val) { - hw_dbg(hw, "NVM Read Error\n"); + hw_dbg("NVM Read Error\n"); goto out; } hw->mac.perm_addr[i] = (u8)(nvm_data & 0xFF); @@ -541,7 +541,7 @@ out: } /** - * e1000_validate_nvm_checksum - Validate EEPROM checksum + * igb_validate_nvm_checksum - Validate EEPROM checksum * @hw: pointer to the HW structure * * Calculates the EEPROM checksum by reading/adding each word of the EEPROM @@ -556,14 +556,14 @@ s32 igb_validate_nvm_checksum(struct e1000_hw *hw) for (i = 0; i < (NVM_CHECKSUM_REG + 1); i++) { ret_val = hw->nvm.ops.read_nvm(hw, i, 1, &nvm_data); if (ret_val) { - hw_dbg(hw, "NVM Read Error\n"); + hw_dbg("NVM Read Error\n"); goto out; } checksum += nvm_data; } if (checksum != (u16) NVM_SUM) { - hw_dbg(hw, "NVM Checksum Invalid\n"); + hw_dbg("NVM Checksum Invalid\n"); ret_val = -E1000_ERR_NVM; goto out; } @@ -573,7 +573,7 @@ out: } /** - * e1000_update_nvm_checksum - Update EEPROM checksum + * igb_update_nvm_checksum - Update EEPROM checksum * @hw: pointer to the HW structure * * Updates the EEPROM checksum by reading/adding each word of the EEPROM @@ -589,7 +589,7 @@ s32 igb_update_nvm_checksum(struct e1000_hw *hw) for (i = 0; i < NVM_CHECKSUM_REG; i++) { ret_val = hw->nvm.ops.read_nvm(hw, i, 1, &nvm_data); if (ret_val) { - hw_dbg(hw, "NVM Read Error while updating checksum.\n"); + hw_dbg("NVM Read Error while updating checksum.\n"); goto out; } checksum += nvm_data; @@ -597,7 +597,7 @@ s32 igb_update_nvm_checksum(struct e1000_hw *hw) checksum = (u16) NVM_SUM - checksum; ret_val = hw->nvm.ops.write_nvm(hw, NVM_CHECKSUM_REG, 1, &checksum); if (ret_val) - hw_dbg(hw, "NVM Write Error while updating checksum.\n"); + hw_dbg("NVM Write Error while updating checksum.\n"); out: return ret_val; diff --git a/drivers/net/igb/e1000_phy.c b/drivers/net/igb/e1000_phy.c index 08a86b107229..17fddb91c9f5 100644 --- a/drivers/net/igb/e1000_phy.c +++ b/drivers/net/igb/e1000_phy.c @@ -61,7 +61,7 @@ static const u16 e1000_igp_2_cable_length_table[] = sizeof(e1000_igp_2_cable_length_table[0])) /** - * e1000_check_reset_block - Check if PHY reset is blocked + * igb_check_reset_block - Check if PHY reset is blocked * @hw: pointer to the HW structure * * Read the PHY management control register and check whether a PHY reset @@ -79,7 +79,7 @@ s32 igb_check_reset_block(struct e1000_hw *hw) } /** - * e1000_get_phy_id - Retrieve the PHY ID and revision + * igb_get_phy_id - Retrieve the PHY ID and revision * @hw: pointer to the HW structure * * Reads the PHY registers and stores the PHY ID and possibly the PHY @@ -109,7 +109,7 @@ out: } /** - * e1000_phy_reset_dsp - Reset PHY DSP + * igb_phy_reset_dsp - Reset PHY DSP * @hw: pointer to the HW structure * * Reset the digital signal processor. @@ -129,7 +129,7 @@ out: } /** - * e1000_read_phy_reg_mdic - Read MDI control register + * igb_read_phy_reg_mdic - Read MDI control register * @hw: pointer to the HW structure * @offset: register offset to be read * @data: pointer to the read data @@ -144,7 +144,7 @@ static s32 igb_read_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 *data) s32 ret_val = 0; if (offset > MAX_PHY_REG_ADDRESS) { - hw_dbg(hw, "PHY Address %d is out of range\n", offset); + hw_dbg("PHY Address %d is out of range\n", offset); ret_val = -E1000_ERR_PARAM; goto out; } @@ -172,12 +172,12 @@ static s32 igb_read_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 *data) break; } if (!(mdic & E1000_MDIC_READY)) { - hw_dbg(hw, "MDI Read did not complete\n"); + hw_dbg("MDI Read did not complete\n"); ret_val = -E1000_ERR_PHY; goto out; } if (mdic & E1000_MDIC_ERROR) { - hw_dbg(hw, "MDI Error\n"); + hw_dbg("MDI Error\n"); ret_val = -E1000_ERR_PHY; goto out; } @@ -188,7 +188,7 @@ out: } /** - * e1000_write_phy_reg_mdic - Write MDI control register + * igb_write_phy_reg_mdic - Write MDI control register * @hw: pointer to the HW structure * @offset: register offset to write to * @data: data to write to register at offset @@ -202,7 +202,7 @@ static s32 igb_write_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 data) s32 ret_val = 0; if (offset > MAX_PHY_REG_ADDRESS) { - hw_dbg(hw, "PHY Address %d is out of range\n", offset); + hw_dbg("PHY Address %d is out of range\n", offset); ret_val = -E1000_ERR_PARAM; goto out; } @@ -231,12 +231,12 @@ static s32 igb_write_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 data) break; } if (!(mdic & E1000_MDIC_READY)) { - hw_dbg(hw, "MDI Write did not complete\n"); + hw_dbg("MDI Write did not complete\n"); ret_val = -E1000_ERR_PHY; goto out; } if (mdic & E1000_MDIC_ERROR) { - hw_dbg(hw, "MDI Error\n"); + hw_dbg("MDI Error\n"); ret_val = -E1000_ERR_PHY; goto out; } @@ -246,7 +246,7 @@ out: } /** - * e1000_read_phy_reg_igp - Read igp PHY register + * igb_read_phy_reg_igp - Read igp PHY register * @hw: pointer to the HW structure * @offset: register offset to be read * @data: pointer to the read data @@ -284,7 +284,7 @@ out: } /** - * e1000_write_phy_reg_igp - Write igp PHY register + * igb_write_phy_reg_igp - Write igp PHY register * @hw: pointer to the HW structure * @offset: register offset to write to * @data: data to write at register offset @@ -321,7 +321,7 @@ out: } /** - * e1000_copper_link_setup_m88 - Setup m88 PHY's for copper link + * igb_copper_link_setup_m88 - Setup m88 PHY's for copper link * @hw: pointer to the HW structure * * Sets up MDI/MDI-X and polarity for m88 PHY's. If necessary, transmit clock @@ -423,7 +423,7 @@ s32 igb_copper_link_setup_m88(struct e1000_hw *hw) /* Commit the changes. */ ret_val = igb_phy_sw_reset(hw); if (ret_val) { - hw_dbg(hw, "Error committing the PHY changes\n"); + hw_dbg("Error committing the PHY changes\n"); goto out; } @@ -432,7 +432,7 @@ out: } /** - * e1000_copper_link_setup_igp - Setup igp PHY's for copper link + * igb_copper_link_setup_igp - Setup igp PHY's for copper link * @hw: pointer to the HW structure * * Sets up LPLU, MDI/MDI-X, polarity, Smartspeed and Master/Slave config for @@ -451,7 +451,7 @@ s32 igb_copper_link_setup_igp(struct e1000_hw *hw) ret_val = hw->phy.ops.reset_phy(hw); if (ret_val) { - hw_dbg(hw, "Error resetting the PHY.\n"); + hw_dbg("Error resetting the PHY.\n"); goto out; } @@ -467,7 +467,7 @@ s32 igb_copper_link_setup_igp(struct e1000_hw *hw) if (hw->phy.ops.set_d3_lplu_state) ret_val = hw->phy.ops.set_d3_lplu_state(hw, false); if (ret_val) { - hw_dbg(hw, "Error Disabling LPLU D3\n"); + hw_dbg("Error Disabling LPLU D3\n"); goto out; } } @@ -475,7 +475,7 @@ s32 igb_copper_link_setup_igp(struct e1000_hw *hw) /* disable lplu d0 during driver init */ ret_val = hw->phy.ops.set_d0_lplu_state(hw, false); if (ret_val) { - hw_dbg(hw, "Error Disabling LPLU D0\n"); + hw_dbg("Error Disabling LPLU D0\n"); goto out; } /* Configure mdi-mdix settings */ @@ -570,7 +570,7 @@ out: } /** - * e1000_copper_link_autoneg - Setup/Enable autoneg for copper link + * igb_copper_link_autoneg - Setup/Enable autoneg for copper link * @hw: pointer to the HW structure * * Performs initial bounds checking on autoneg advertisement parameter, then @@ -597,13 +597,13 @@ s32 igb_copper_link_autoneg(struct e1000_hw *hw) if (phy->autoneg_advertised == 0) phy->autoneg_advertised = phy->autoneg_mask; - hw_dbg(hw, "Reconfiguring auto-neg advertisement params\n"); + hw_dbg("Reconfiguring auto-neg advertisement params\n"); ret_val = igb_phy_setup_autoneg(hw); if (ret_val) { - hw_dbg(hw, "Error Setting up Auto-Negotiation\n"); + hw_dbg("Error Setting up Auto-Negotiation\n"); goto out; } - hw_dbg(hw, "Restarting Auto-Neg\n"); + hw_dbg("Restarting Auto-Neg\n"); /* * Restart auto-negotiation by setting the Auto Neg Enable bit and @@ -625,8 +625,8 @@ s32 igb_copper_link_autoneg(struct e1000_hw *hw) if (phy->autoneg_wait_to_complete) { ret_val = igb_wait_autoneg(hw); if (ret_val) { - hw_dbg(hw, "Error while waiting for " - "autoneg to complete\n"); + hw_dbg("Error while waiting for " + "autoneg to complete\n"); goto out; } } @@ -638,7 +638,7 @@ out: } /** - * e1000_phy_setup_autoneg - Configure PHY for auto-negotiation + * igb_phy_setup_autoneg - Configure PHY for auto-negotiation * @hw: pointer to the HW structure * * Reads the MII auto-neg advertisement register and/or the 1000T control @@ -689,39 +689,39 @@ static s32 igb_phy_setup_autoneg(struct e1000_hw *hw) NWAY_AR_10T_HD_CAPS); mii_1000t_ctrl_reg &= ~(CR_1000T_HD_CAPS | CR_1000T_FD_CAPS); - hw_dbg(hw, "autoneg_advertised %x\n", phy->autoneg_advertised); + hw_dbg("autoneg_advertised %x\n", phy->autoneg_advertised); /* Do we want to advertise 10 Mb Half Duplex? */ if (phy->autoneg_advertised & ADVERTISE_10_HALF) { - hw_dbg(hw, "Advertise 10mb Half duplex\n"); + hw_dbg("Advertise 10mb Half duplex\n"); mii_autoneg_adv_reg |= NWAY_AR_10T_HD_CAPS; } /* Do we want to advertise 10 Mb Full Duplex? */ if (phy->autoneg_advertised & ADVERTISE_10_FULL) { - hw_dbg(hw, "Advertise 10mb Full duplex\n"); + hw_dbg("Advertise 10mb Full duplex\n"); mii_autoneg_adv_reg |= NWAY_AR_10T_FD_CAPS; } /* Do we want to advertise 100 Mb Half Duplex? */ if (phy->autoneg_advertised & ADVERTISE_100_HALF) { - hw_dbg(hw, "Advertise 100mb Half duplex\n"); + hw_dbg("Advertise 100mb Half duplex\n"); mii_autoneg_adv_reg |= NWAY_AR_100TX_HD_CAPS; } /* Do we want to advertise 100 Mb Full Duplex? */ if (phy->autoneg_advertised & ADVERTISE_100_FULL) { - hw_dbg(hw, "Advertise 100mb Full duplex\n"); + hw_dbg("Advertise 100mb Full duplex\n"); mii_autoneg_adv_reg |= NWAY_AR_100TX_FD_CAPS; } /* We do not allow the Phy to advertise 1000 Mb Half Duplex */ if (phy->autoneg_advertised & ADVERTISE_1000_HALF) - hw_dbg(hw, "Advertise 1000mb Half duplex request denied!\n"); + hw_dbg("Advertise 1000mb Half duplex request denied!\n"); /* Do we want to advertise 1000 Mb Full Duplex? */ if (phy->autoneg_advertised & ADVERTISE_1000_FULL) { - hw_dbg(hw, "Advertise 1000mb Full duplex\n"); + hw_dbg("Advertise 1000mb Full duplex\n"); mii_1000t_ctrl_reg |= CR_1000T_FD_CAPS; } @@ -780,7 +780,7 @@ static s32 igb_phy_setup_autoneg(struct e1000_hw *hw) mii_autoneg_adv_reg |= (NWAY_AR_ASM_DIR | NWAY_AR_PAUSE); break; default: - hw_dbg(hw, "Flow control param set incorrectly\n"); + hw_dbg("Flow control param set incorrectly\n"); ret_val = -E1000_ERR_CONFIG; goto out; } @@ -790,7 +790,7 @@ static s32 igb_phy_setup_autoneg(struct e1000_hw *hw) if (ret_val) goto out; - hw_dbg(hw, "Auto-Neg Advertising %x\n", mii_autoneg_adv_reg); + hw_dbg("Auto-Neg Advertising %x\n", mii_autoneg_adv_reg); if (phy->autoneg_mask & ADVERTISE_1000_FULL) { ret_val = hw->phy.ops.write_phy_reg(hw, @@ -805,7 +805,7 @@ out: } /** - * e1000_phy_force_speed_duplex_igp - Force speed/duplex for igp PHY + * igb_phy_force_speed_duplex_igp - Force speed/duplex for igp PHY * @hw: pointer to the HW structure * * Calls the PHY setup function to force speed and duplex. Clears the @@ -846,13 +846,12 @@ s32 igb_phy_force_speed_duplex_igp(struct e1000_hw *hw) if (ret_val) goto out; - hw_dbg(hw, "IGP PSCR: %X\n", phy_data); + hw_dbg("IGP PSCR: %X\n", phy_data); udelay(1); if (phy->autoneg_wait_to_complete) { - hw_dbg(hw, - "Waiting for forced speed/duplex link on IGP phy.\n"); + hw_dbg("Waiting for forced speed/duplex link on IGP phy.\n"); ret_val = igb_phy_has_link(hw, PHY_FORCE_LIMIT, @@ -862,7 +861,7 @@ s32 igb_phy_force_speed_duplex_igp(struct e1000_hw *hw) goto out; if (!link) - hw_dbg(hw, "Link taking longer than expected.\n"); + hw_dbg("Link taking longer than expected.\n"); /* Try once more */ ret_val = igb_phy_has_link(hw, @@ -878,7 +877,7 @@ out: } /** - * e1000_phy_force_speed_duplex_m88 - Force speed/duplex for m88 PHY + * igb_phy_force_speed_duplex_m88 - Force speed/duplex for m88 PHY * @hw: pointer to the HW structure * * Calls the PHY setup function to force speed and duplex. Clears the @@ -909,7 +908,7 @@ s32 igb_phy_force_speed_duplex_m88(struct e1000_hw *hw) if (ret_val) goto out; - hw_dbg(hw, "M88E1000 PSCR: %X\n", phy_data); + hw_dbg("M88E1000 PSCR: %X\n", phy_data); ret_val = hw->phy.ops.read_phy_reg(hw, PHY_CONTROL, &phy_data); if (ret_val) @@ -927,8 +926,7 @@ s32 igb_phy_force_speed_duplex_m88(struct e1000_hw *hw) udelay(1); if (phy->autoneg_wait_to_complete) { - hw_dbg(hw, - "Waiting for forced speed/duplex link on M88 phy.\n"); + hw_dbg("Waiting for forced speed/duplex link on M88 phy.\n"); ret_val = igb_phy_has_link(hw, PHY_FORCE_LIMIT, @@ -993,7 +991,7 @@ out: } /** - * e1000_phy_force_speed_duplex_setup - Configure forced PHY speed/duplex + * igb_phy_force_speed_duplex_setup - Configure forced PHY speed/duplex * @hw: pointer to the HW structure * @phy_ctrl: pointer to current value of PHY_CONTROL * @@ -1028,11 +1026,11 @@ static void igb_phy_force_speed_duplex_setup(struct e1000_hw *hw, if (mac->forced_speed_duplex & E1000_ALL_HALF_DUPLEX) { ctrl &= ~E1000_CTRL_FD; *phy_ctrl &= ~MII_CR_FULL_DUPLEX; - hw_dbg(hw, "Half Duplex\n"); + hw_dbg("Half Duplex\n"); } else { ctrl |= E1000_CTRL_FD; *phy_ctrl |= MII_CR_FULL_DUPLEX; - hw_dbg(hw, "Full Duplex\n"); + hw_dbg("Full Duplex\n"); } /* Forcing 10mb or 100mb? */ @@ -1040,12 +1038,12 @@ static void igb_phy_force_speed_duplex_setup(struct e1000_hw *hw, ctrl |= E1000_CTRL_SPD_100; *phy_ctrl |= MII_CR_SPEED_100; *phy_ctrl &= ~(MII_CR_SPEED_1000 | MII_CR_SPEED_10); - hw_dbg(hw, "Forcing 100mb\n"); + hw_dbg("Forcing 100mb\n"); } else { ctrl &= ~(E1000_CTRL_SPD_1000 | E1000_CTRL_SPD_100); *phy_ctrl |= MII_CR_SPEED_10; *phy_ctrl &= ~(MII_CR_SPEED_1000 | MII_CR_SPEED_100); - hw_dbg(hw, "Forcing 10mb\n"); + hw_dbg("Forcing 10mb\n"); } igb_config_collision_dist(hw); @@ -1054,7 +1052,7 @@ static void igb_phy_force_speed_duplex_setup(struct e1000_hw *hw, } /** - * e1000_set_d3_lplu_state - Sets low power link up state for D3 + * igb_set_d3_lplu_state - Sets low power link up state for D3 * @hw: pointer to the HW structure * @active: boolean used to enable/disable lplu * @@ -1146,7 +1144,7 @@ out: } /** - * e1000_check_downshift - Checks whether a downshift in speed occured + * igb_check_downshift - Checks whether a downshift in speed occured * @hw: pointer to the HW structure * * Success returns 0, Failure returns 1 @@ -1188,7 +1186,7 @@ out: } /** - * e1000_check_polarity_m88 - Checks the polarity. + * igb_check_polarity_m88 - Checks the polarity. * @hw: pointer to the HW structure * * Success returns 0, Failure returns -E1000_ERR_PHY (-2) @@ -1212,7 +1210,7 @@ static s32 igb_check_polarity_m88(struct e1000_hw *hw) } /** - * e1000_check_polarity_igp - Checks the polarity. + * igb_check_polarity_igp - Checks the polarity. * @hw: pointer to the HW structure * * Success returns 0, Failure returns -E1000_ERR_PHY (-2) @@ -1260,7 +1258,7 @@ out: } /** - * e1000_wait_autoneg - Wait for auto-neg compeletion + * igb_wait_autoneg - Wait for auto-neg compeletion * @hw: pointer to the HW structure * * Waits for auto-negotiation to complete or for the auto-negotiation time @@ -1292,7 +1290,7 @@ static s32 igb_wait_autoneg(struct e1000_hw *hw) } /** - * e1000_phy_has_link - Polls PHY for link + * igb_phy_has_link - Polls PHY for link * @hw: pointer to the HW structure * @iterations: number of times to poll for link * @usec_interval: delay between polling attempts @@ -1332,7 +1330,7 @@ s32 igb_phy_has_link(struct e1000_hw *hw, u32 iterations, } /** - * e1000_get_cable_length_m88 - Determine cable length for m88 PHY + * igb_get_cable_length_m88 - Determine cable length for m88 PHY * @hw: pointer to the HW structure * * Reads the PHY specific status register to retrieve the cable length @@ -1369,7 +1367,7 @@ out: } /** - * e1000_get_cable_length_igp_2 - Determine cable length for igp2 PHY + * igb_get_cable_length_igp_2 - Determine cable length for igp2 PHY * @hw: pointer to the HW structure * * The automatic gain control (agc) normalizes the amplitude of the @@ -1442,7 +1440,7 @@ out: } /** - * e1000_get_phy_info_m88 - Retrieve PHY information + * igb_get_phy_info_m88 - Retrieve PHY information * @hw: pointer to the HW structure * * Valid for only copper links. Read the PHY status register (sticky read) @@ -1459,7 +1457,7 @@ s32 igb_get_phy_info_m88(struct e1000_hw *hw) bool link; if (hw->phy.media_type != e1000_media_type_copper) { - hw_dbg(hw, "Phy info is only valid for copper media\n"); + hw_dbg("Phy info is only valid for copper media\n"); ret_val = -E1000_ERR_CONFIG; goto out; } @@ -1469,7 +1467,7 @@ s32 igb_get_phy_info_m88(struct e1000_hw *hw) goto out; if (!link) { - hw_dbg(hw, "Phy info is only valid if link is up\n"); + hw_dbg("Phy info is only valid if link is up\n"); ret_val = -E1000_ERR_CONFIG; goto out; } @@ -1523,7 +1521,7 @@ out: } /** - * e1000_get_phy_info_igp - Retrieve igp PHY information + * igb_get_phy_info_igp - Retrieve igp PHY information * @hw: pointer to the HW structure * * Read PHY status to determine if link is up. If link is up, then @@ -1543,7 +1541,7 @@ s32 igb_get_phy_info_igp(struct e1000_hw *hw) goto out; if (!link) { - hw_dbg(hw, "Phy info is only valid if link is up\n"); + hw_dbg("Phy info is only valid if link is up\n"); ret_val = -E1000_ERR_CONFIG; goto out; } @@ -1590,7 +1588,7 @@ out: } /** - * e1000_phy_sw_reset - PHY software reset + * igb_phy_sw_reset - PHY software reset * @hw: pointer to the HW structure * * Does a software reset of the PHY by reading the PHY control register and @@ -1617,7 +1615,7 @@ out: } /** - * e1000_phy_hw_reset - PHY hardware reset + * igb_phy_hw_reset - PHY hardware reset * @hw: pointer to the HW structure * * Verify the reset block is not blocking us from resetting. Acquire @@ -1663,7 +1661,7 @@ out: /* Internal function pointers */ /** - * e1000_get_phy_cfg_done - Generic PHY configuration done + * igb_get_phy_cfg_done - Generic PHY configuration done * @hw: pointer to the HW structure * * Return success if silicon family did not implement a family specific @@ -1678,7 +1676,7 @@ static s32 igb_get_phy_cfg_done(struct e1000_hw *hw) } /** - * e1000_release_phy - Generic release PHY + * igb_release_phy - Generic release PHY * @hw: pointer to the HW structure * * Return if silicon family does not require a semaphore when accessing the @@ -1691,7 +1689,7 @@ static void igb_release_phy(struct e1000_hw *hw) } /** - * e1000_acquire_phy - Generic acquire PHY + * igb_acquire_phy - Generic acquire PHY * @hw: pointer to the HW structure * * Return success if silicon family does not require a semaphore when @@ -1706,7 +1704,7 @@ static s32 igb_acquire_phy(struct e1000_hw *hw) } /** - * e1000_phy_force_speed_duplex - Generic force PHY speed/duplex + * igb_phy_force_speed_duplex - Generic force PHY speed/duplex * @hw: pointer to the HW structure * * When the silicon family has not implemented a forced speed/duplex @@ -1721,14 +1719,14 @@ s32 igb_phy_force_speed_duplex(struct e1000_hw *hw) } /** - * e1000_phy_init_script_igp3 - Inits the IGP3 PHY + * igb_phy_init_script_igp3 - Inits the IGP3 PHY * @hw: pointer to the HW structure * * Initializes a Intel Gigabit PHY3 when an EEPROM is not present. **/ s32 igb_phy_init_script_igp3(struct e1000_hw *hw) { - hw_dbg(hw, "Running IGP 3 PHY init script\n"); + hw_dbg("Running IGP 3 PHY init script\n"); /* PHY init IGP 3 */ /* Enable rise/fall, 10-mode work in class-A */ diff --git a/drivers/net/igb/e1000_regs.h b/drivers/net/igb/e1000_regs.h index ff187b73c69e..b95093d24c09 100644 --- a/drivers/net/igb/e1000_regs.h +++ b/drivers/net/igb/e1000_regs.h @@ -56,6 +56,9 @@ #define E1000_EIMC 0x01528 /* Ext. Interrupt Mask Clear - WO */ #define E1000_EIAC 0x0152C /* Ext. Interrupt Auto Clear - RW */ #define E1000_EIAM 0x01530 /* Ext. Interrupt Ack Auto Clear Mask - RW */ +#define E1000_GPIE 0x01514 /* General Purpose Interrupt Enable - RW */ +#define E1000_IVAR0 0x01700 /* Interrupt Vector Allocation (array) - RW */ +#define E1000_IVAR_MISC 0x01740 /* IVAR for "other" causes - RW */ #define E1000_TCTL 0x00400 /* TX Control - RW */ #define E1000_TCTL_EXT 0x00404 /* Extended TX Control - RW */ #define E1000_TIPG 0x00410 /* TX Inter-packet gap -RW */ @@ -217,6 +220,7 @@ #define E1000_RFCTL 0x05008 /* Receive Filter Control*/ #define E1000_MTA 0x05200 /* Multicast Table Array - RW Array */ #define E1000_RA 0x05400 /* Receive Address - RW Array */ +#define E1000_RA2 0x054E0 /* 2nd half of receive address array - RW Array */ #define E1000_VFTA 0x05600 /* VLAN Filter Table Array - RW Array */ #define E1000_VMD_CTL 0x0581C /* VMDq Control - RW */ #define E1000_WUC 0x05800 /* Wakeup Control - RW */ @@ -235,6 +239,8 @@ #define E1000_FACTPS 0x05B30 /* Function Active and Power State to MNG */ #define E1000_SWSM 0x05B50 /* SW Semaphore */ #define E1000_FWSM 0x05B54 /* FW Semaphore */ +#define E1000_DCA_ID 0x05B70 /* DCA Requester ID Information - RO */ +#define E1000_DCA_CTRL 0x05B74 /* DCA Control - RW */ #define E1000_HICR 0x08F00 /* Host Inteface Control */ /* RSS registers */ @@ -256,7 +262,8 @@ #define E1000_RETA(_i) (0x05C00 + ((_i) * 4)) #define E1000_RSSRK(_i) (0x05C80 + ((_i) * 4)) /* RSS Random Key - RW Array */ -#define E1000_REGISTER(a, reg) reg +#define E1000_REGISTER(a, reg) (((a)->mac.type < e1000_82576) \ + ? reg : e1000_translate_register_82576(reg)) #define wr32(reg, value) (writel(value, hw->hw_addr + reg)) #define rd32(reg) (readl(hw->hw_addr + reg)) diff --git a/drivers/net/igb/igb.h b/drivers/net/igb/igb.h index 6b2e7d351d65..4ff6f0567f3f 100644 --- a/drivers/net/igb/igb.h +++ b/drivers/net/igb/igb.h @@ -36,12 +36,20 @@ struct igb_adapter; +#ifdef CONFIG_IGB_LRO +#include <linux/inet_lro.h> +#define MAX_LRO_AGGR 32 +#define MAX_LRO_DESCRIPTORS 8 +#endif + /* Interrupt defines */ #define IGB_MAX_TX_CLEAN 72 #define IGB_MIN_DYN_ITR 3000 #define IGB_MAX_DYN_ITR 96000 -#define IGB_START_ITR 6000 + +/* ((1000000000ns / (6000ints/s * 1024ns)) << 2 = 648 */ +#define IGB_START_ITR 648 #define IGB_DYN_ITR_PACKET_THRESHOLD 2 #define IGB_DYN_ITR_LENGTH_LOW 200 @@ -62,6 +70,7 @@ struct igb_adapter; /* Transmit and receive queues */ #define IGB_MAX_RX_QUEUES 4 +#define IGB_MAX_TX_QUEUES 4 /* RX descriptor control thresholds. * PTHRESH - MAC will consider prefetch if it has fewer than this number of @@ -124,6 +133,7 @@ struct igb_buffer { struct { struct page *page; u64 page_dma; + unsigned int page_offset; }; }; }; @@ -150,24 +160,26 @@ struct igb_ring { u16 itr_register; u16 cpu; + int queue_index; unsigned int total_bytes; unsigned int total_packets; union { /* TX */ struct { - spinlock_t tx_clean_lock; - spinlock_t tx_lock; + struct igb_queue_stats tx_stats; bool detect_tx_hung; }; /* RX */ struct { - /* arrays of page information for packet split */ - struct sk_buff *pending_skb; - int pending_skb_page; - int no_itr_adjust; struct igb_queue_stats rx_stats; struct napi_struct napi; + int set_itr; + struct igb_ring *buddy; +#ifdef CONFIG_IGB_LRO + struct net_lro_mgr lro_mgr; + bool lro_used; +#endif }; }; @@ -210,7 +222,6 @@ struct igb_adapter { u32 itr_setting; u16 tx_itr; u16 rx_itr; - int set_itr; struct work_struct reset_task; struct work_struct watchdog_task; @@ -265,14 +276,34 @@ struct igb_adapter { int msg_enable; struct msix_entry *msix_entries; u32 eims_enable_mask; + u32 eims_other; /* to not mess up cache alignment, always add to the bottom */ unsigned long state; - unsigned int msi_enabled; - + unsigned int flags; u32 eeprom_wol; + + /* for ioport free */ + int bars; + int need_ioport; + + struct igb_ring *multi_tx_table[IGB_MAX_TX_QUEUES]; +#ifdef CONFIG_IGB_LRO + unsigned int lro_max_aggr; + unsigned int lro_aggregated; + unsigned int lro_flushed; + unsigned int lro_no_desc; +#endif }; +#define IGB_FLAG_HAS_MSI (1 << 0) +#define IGB_FLAG_MSI_ENABLE (1 << 1) +#define IGB_FLAG_HAS_DCA (1 << 2) +#define IGB_FLAG_DCA_ENABLED (1 << 3) +#define IGB_FLAG_IN_NETPOLL (1 << 5) +#define IGB_FLAG_QUAD_PORT_A (1 << 6) +#define IGB_FLAG_NEED_CTX_IDX (1 << 7) + enum e1000_state_t { __IGB_TESTING, __IGB_RESETTING, diff --git a/drivers/net/igb/igb_ethtool.c b/drivers/net/igb/igb_ethtool.c index 0447f9bcd27a..11aee1309951 100644 --- a/drivers/net/igb/igb_ethtool.c +++ b/drivers/net/igb/igb_ethtool.c @@ -93,13 +93,16 @@ static const struct igb_stats igb_gstrings_stats[] = { { "tx_smbus", IGB_STAT(stats.mgptc) }, { "rx_smbus", IGB_STAT(stats.mgprc) }, { "dropped_smbus", IGB_STAT(stats.mgpdc) }, +#ifdef CONFIG_IGB_LRO + { "lro_aggregated", IGB_STAT(lro_aggregated) }, + { "lro_flushed", IGB_STAT(lro_flushed) }, + { "lro_no_desc", IGB_STAT(lro_no_desc) }, +#endif }; #define IGB_QUEUE_STATS_LEN \ - ((((((struct igb_adapter *)netdev->priv)->num_rx_queues > 1) ? \ - ((struct igb_adapter *)netdev->priv)->num_rx_queues : 0) + \ - (((((struct igb_adapter *)netdev->priv)->num_tx_queues > 1) ? \ - ((struct igb_adapter *)netdev->priv)->num_tx_queues : 0))) * \ + ((((struct igb_adapter *)netdev->priv)->num_rx_queues + \ + ((struct igb_adapter *)netdev->priv)->num_tx_queues) * \ (sizeof(struct igb_queue_stats) / sizeof(u64))) #define IGB_GLOBAL_STATS_LEN \ sizeof(igb_gstrings_stats) / sizeof(struct igb_stats) @@ -829,8 +832,9 @@ err_setup: /* ethtool register test data */ struct igb_reg_test { u16 reg; - u8 array_len; - u8 test_type; + u16 reg_offset; + u16 array_len; + u16 test_type; u32 mask; u32 write; }; @@ -852,34 +856,72 @@ struct igb_reg_test { #define TABLE64_TEST_LO 5 #define TABLE64_TEST_HI 6 -/* default register test */ +/* 82576 reg test */ +static struct igb_reg_test reg_test_82576[] = { + { E1000_FCAL, 0x100, 1, PATTERN_TEST, 0xFFFFFFFF, 0xFFFFFFFF }, + { E1000_FCAH, 0x100, 1, PATTERN_TEST, 0x0000FFFF, 0xFFFFFFFF }, + { E1000_FCT, 0x100, 1, PATTERN_TEST, 0x0000FFFF, 0xFFFFFFFF }, + { E1000_VET, 0x100, 1, PATTERN_TEST, 0xFFFFFFFF, 0xFFFFFFFF }, + { E1000_RDBAL(0), 0x100, 4, PATTERN_TEST, 0xFFFFFF80, 0xFFFFFFFF }, + { E1000_RDBAH(0), 0x100, 4, PATTERN_TEST, 0xFFFFFFFF, 0xFFFFFFFF }, + { E1000_RDLEN(0), 0x100, 4, PATTERN_TEST, 0x000FFFF0, 0x000FFFFF }, + { E1000_RDBAL(4), 0x40, 8, PATTERN_TEST, 0xFFFFFF80, 0xFFFFFFFF }, + { E1000_RDBAH(4), 0x40, 8, PATTERN_TEST, 0xFFFFFFFF, 0xFFFFFFFF }, + { E1000_RDLEN(4), 0x40, 8, PATTERN_TEST, 0x000FFFF0, 0x000FFFFF }, + /* Enable all four RX queues before testing. */ + { E1000_RXDCTL(0), 0x100, 1, WRITE_NO_TEST, 0, E1000_RXDCTL_QUEUE_ENABLE }, + /* RDH is read-only for 82576, only test RDT. */ + { E1000_RDT(0), 0x100, 4, PATTERN_TEST, 0x0000FFFF, 0x0000FFFF }, + { E1000_RXDCTL(0), 0x100, 4, WRITE_NO_TEST, 0, 0 }, + { E1000_FCRTH, 0x100, 1, PATTERN_TEST, 0x0000FFF0, 0x0000FFF0 }, + { E1000_FCTTV, 0x100, 1, PATTERN_TEST, 0x0000FFFF, 0x0000FFFF }, + { E1000_TIPG, 0x100, 1, PATTERN_TEST, 0x3FFFFFFF, 0x3FFFFFFF }, + { E1000_TDBAL(0), 0x100, 4, PATTERN_TEST, 0xFFFFFF80, 0xFFFFFFFF }, + { E1000_TDBAH(0), 0x100, 4, PATTERN_TEST, 0xFFFFFFFF, 0xFFFFFFFF }, + { E1000_TDLEN(0), 0x100, 4, PATTERN_TEST, 0x000FFFF0, 0x000FFFFF }, + { E1000_TDBAL(4), 0x40, 8, PATTERN_TEST, 0xFFFFFF80, 0xFFFFFFFF }, + { E1000_TDBAH(4), 0x40, 8, PATTERN_TEST, 0xFFFFFFFF, 0xFFFFFFFF }, + { E1000_TDLEN(4), 0x40, 8, PATTERN_TEST, 0x000FFFF0, 0x000FFFFF }, + { E1000_RCTL, 0x100, 1, SET_READ_TEST, 0xFFFFFFFF, 0x00000000 }, + { E1000_RCTL, 0x100, 1, SET_READ_TEST, 0x04CFB0FE, 0x003FFFFB }, + { E1000_RCTL, 0x100, 1, SET_READ_TEST, 0x04CFB0FE, 0xFFFFFFFF }, + { E1000_TCTL, 0x100, 1, SET_READ_TEST, 0xFFFFFFFF, 0x00000000 }, + { E1000_RA, 0, 16, TABLE64_TEST_LO, 0xFFFFFFFF, 0xFFFFFFFF }, + { E1000_RA, 0, 16, TABLE64_TEST_HI, 0x83FFFFFF, 0xFFFFFFFF }, + { E1000_RA2, 0, 8, TABLE64_TEST_LO, 0xFFFFFFFF, 0xFFFFFFFF }, + { E1000_RA2, 0, 8, TABLE64_TEST_HI, 0x83FFFFFF, 0xFFFFFFFF }, + { E1000_MTA, 0, 128,TABLE32_TEST, 0xFFFFFFFF, 0xFFFFFFFF }, + { 0, 0, 0, 0 } +}; + +/* 82575 register test */ static struct igb_reg_test reg_test_82575[] = { - { E1000_FCAL, 1, PATTERN_TEST, 0xFFFFFFFF, 0xFFFFFFFF }, - { E1000_FCAH, 1, PATTERN_TEST, 0x0000FFFF, 0xFFFFFFFF }, - { E1000_FCT, 1, PATTERN_TEST, 0x0000FFFF, 0xFFFFFFFF }, - { E1000_VET, 1, PATTERN_TEST, 0xFFFFFFFF, 0xFFFFFFFF }, - { E1000_RDBAL(0), 4, PATTERN_TEST, 0xFFFFFF80, 0xFFFFFFFF }, - { E1000_RDBAH(0), 4, PATTERN_TEST, 0xFFFFFFFF, 0xFFFFFFFF }, - { E1000_RDLEN(0), 4, PATTERN_TEST, 0x000FFF80, 0x000FFFFF }, + { E1000_FCAL, 0x100, 1, PATTERN_TEST, 0xFFFFFFFF, 0xFFFFFFFF }, + { E1000_FCAH, 0x100, 1, PATTERN_TEST, 0x0000FFFF, 0xFFFFFFFF }, + { E1000_FCT, 0x100, 1, PATTERN_TEST, 0x0000FFFF, 0xFFFFFFFF }, + { E1000_VET, 0x100, 1, PATTERN_TEST, 0xFFFFFFFF, 0xFFFFFFFF }, + { E1000_RDBAL(0), 0x100, 4, PATTERN_TEST, 0xFFFFFF80, 0xFFFFFFFF }, + { E1000_RDBAH(0), 0x100, 4, PATTERN_TEST, 0xFFFFFFFF, 0xFFFFFFFF }, + { E1000_RDLEN(0), 0x100, 4, PATTERN_TEST, 0x000FFF80, 0x000FFFFF }, /* Enable all four RX queues before testing. */ - { E1000_RXDCTL(0), 4, WRITE_NO_TEST, 0, E1000_RXDCTL_QUEUE_ENABLE }, + { E1000_RXDCTL(0), 0x100, 4, WRITE_NO_TEST, 0, E1000_RXDCTL_QUEUE_ENABLE }, /* RDH is read-only for 82575, only test RDT. */ - { E1000_RDT(0), 4, PATTERN_TEST, 0x0000FFFF, 0x0000FFFF }, - { E1000_RXDCTL(0), 4, WRITE_NO_TEST, 0, 0 }, - { E1000_FCRTH, 1, PATTERN_TEST, 0x0000FFF0, 0x0000FFF0 }, - { E1000_FCTTV, 1, PATTERN_TEST, 0x0000FFFF, 0x0000FFFF }, - { E1000_TIPG, 1, PATTERN_TEST, 0x3FFFFFFF, 0x3FFFFFFF }, - { E1000_TDBAL(0), 4, PATTERN_TEST, 0xFFFFFF80, 0xFFFFFFFF }, - { E1000_TDBAH(0), 4, PATTERN_TEST, 0xFFFFFFFF, 0xFFFFFFFF }, - { E1000_TDLEN(0), 4, PATTERN_TEST, 0x000FFF80, 0x000FFFFF }, - { E1000_RCTL, 1, SET_READ_TEST, 0xFFFFFFFF, 0x00000000 }, - { E1000_RCTL, 1, SET_READ_TEST, 0x04CFB3FE, 0x003FFFFB }, - { E1000_RCTL, 1, SET_READ_TEST, 0x04CFB3FE, 0xFFFFFFFF }, - { E1000_TCTL, 1, SET_READ_TEST, 0xFFFFFFFF, 0x00000000 }, - { E1000_TXCW, 1, PATTERN_TEST, 0xC000FFFF, 0x0000FFFF }, - { E1000_RA, 16, TABLE64_TEST_LO, 0xFFFFFFFF, 0xFFFFFFFF }, - { E1000_RA, 16, TABLE64_TEST_HI, 0x800FFFFF, 0xFFFFFFFF }, - { E1000_MTA, 128, TABLE32_TEST, 0xFFFFFFFF, 0xFFFFFFFF }, + { E1000_RDT(0), 0x100, 4, PATTERN_TEST, 0x0000FFFF, 0x0000FFFF }, + { E1000_RXDCTL(0), 0x100, 4, WRITE_NO_TEST, 0, 0 }, + { E1000_FCRTH, 0x100, 1, PATTERN_TEST, 0x0000FFF0, 0x0000FFF0 }, + { E1000_FCTTV, 0x100, 1, PATTERN_TEST, 0x0000FFFF, 0x0000FFFF }, + { E1000_TIPG, 0x100, 1, PATTERN_TEST, 0x3FFFFFFF, 0x3FFFFFFF }, + { E1000_TDBAL(0), 0x100, 4, PATTERN_TEST, 0xFFFFFF80, 0xFFFFFFFF }, + { E1000_TDBAH(0), 0x100, 4, PATTERN_TEST, 0xFFFFFFFF, 0xFFFFFFFF }, + { E1000_TDLEN(0), 0x100, 4, PATTERN_TEST, 0x000FFF80, 0x000FFFFF }, + { E1000_RCTL, 0x100, 1, SET_READ_TEST, 0xFFFFFFFF, 0x00000000 }, + { E1000_RCTL, 0x100, 1, SET_READ_TEST, 0x04CFB3FE, 0x003FFFFB }, + { E1000_RCTL, 0x100, 1, SET_READ_TEST, 0x04CFB3FE, 0xFFFFFFFF }, + { E1000_TCTL, 0x100, 1, SET_READ_TEST, 0xFFFFFFFF, 0x00000000 }, + { E1000_TXCW, 0x100, 1, PATTERN_TEST, 0xC000FFFF, 0x0000FFFF }, + { E1000_RA, 0, 16, TABLE64_TEST_LO, 0xFFFFFFFF, 0xFFFFFFFF }, + { E1000_RA, 0, 16, TABLE64_TEST_HI, 0x800FFFFF, 0xFFFFFFFF }, + { E1000_MTA, 0, 128, TABLE32_TEST, 0xFFFFFFFF, 0xFFFFFFFF }, { 0, 0, 0, 0 } }; @@ -939,7 +981,15 @@ static int igb_reg_test(struct igb_adapter *adapter, u64 *data) u32 i, toggle; toggle = 0x7FFFF3FF; - test = reg_test_82575; + + switch (adapter->hw.mac.type) { + case e1000_82576: + test = reg_test_82576; + break; + default: + test = reg_test_82575; + break; + } /* Because the status register is such a special case, * we handle it separately from the rest of the register @@ -966,19 +1016,19 @@ static int igb_reg_test(struct igb_adapter *adapter, u64 *data) for (i = 0; i < test->array_len; i++) { switch (test->test_type) { case PATTERN_TEST: - REG_PATTERN_TEST(test->reg + (i * 0x100), + REG_PATTERN_TEST(test->reg + (i * test->reg_offset), test->mask, test->write); break; case SET_READ_TEST: - REG_SET_AND_CHECK(test->reg + (i * 0x100), + REG_SET_AND_CHECK(test->reg + (i * test->reg_offset), test->mask, test->write); break; case WRITE_NO_TEST: writel(test->write, (adapter->hw.hw_addr + test->reg) - + (i * 0x100)); + + (i * test->reg_offset)); break; case TABLE32_TEST: REG_PATTERN_TEST(test->reg + (i * 4), @@ -1052,7 +1102,7 @@ static int igb_intr_test(struct igb_adapter *adapter, u64 *data) if (adapter->msix_entries) { /* NOTE: we don't test MSI-X interrupts here, yet */ return 0; - } else if (adapter->msi_enabled) { + } else if (adapter->flags & IGB_FLAG_HAS_MSI) { shared_int = false; if (request_irq(irq, &igb_test_intr, 0, netdev->name, netdev)) { *data = 1; @@ -1394,13 +1444,39 @@ static int igb_set_phy_loopback(struct igb_adapter *adapter) static int igb_setup_loopback_test(struct igb_adapter *adapter) { struct e1000_hw *hw = &adapter->hw; - u32 rctl; + u32 reg; if (hw->phy.media_type == e1000_media_type_fiber || hw->phy.media_type == e1000_media_type_internal_serdes) { - rctl = rd32(E1000_RCTL); - rctl |= E1000_RCTL_LBM_TCVR; - wr32(E1000_RCTL, rctl); + reg = rd32(E1000_RCTL); + reg |= E1000_RCTL_LBM_TCVR; + wr32(E1000_RCTL, reg); + + wr32(E1000_SCTL, E1000_ENABLE_SERDES_LOOPBACK); + + reg = rd32(E1000_CTRL); + reg &= ~(E1000_CTRL_RFCE | + E1000_CTRL_TFCE | + E1000_CTRL_LRST); + reg |= E1000_CTRL_SLU | + E1000_CTRL_FD; + wr32(E1000_CTRL, reg); + + /* Unset switch control to serdes energy detect */ + reg = rd32(E1000_CONNSW); + reg &= ~E1000_CONNSW_ENRGSRC; + wr32(E1000_CONNSW, reg); + + /* Set PCS register for forced speed */ + reg = rd32(E1000_PCS_LCTL); + reg &= ~E1000_PCS_LCTL_AN_ENABLE; /* Disable Autoneg*/ + reg |= E1000_PCS_LCTL_FLV_LINK_UP | /* Force link up */ + E1000_PCS_LCTL_FSV_1000 | /* Force 1000 */ + E1000_PCS_LCTL_FDV_FULL | /* SerDes Full duplex */ + E1000_PCS_LCTL_FSD | /* Force Speed */ + E1000_PCS_LCTL_FORCE_LINK; /* Force Link */ + wr32(E1000_PCS_LCTL, reg); + return 0; } else if (hw->phy.media_type == e1000_media_type_copper) { return igb_set_phy_loopback(adapter); @@ -1660,6 +1736,8 @@ static int igb_wol_exclusion(struct igb_adapter *adapter, wol->supported = 0; break; case E1000_DEV_ID_82575EB_FIBER_SERDES: + case E1000_DEV_ID_82576_FIBER: + case E1000_DEV_ID_82576_SERDES: /* Wake events not supported on port B */ if (rd32(E1000_STATUS) & E1000_STATUS_FUNC_1) { wol->supported = 0; @@ -1668,6 +1746,15 @@ static int igb_wol_exclusion(struct igb_adapter *adapter, /* return success for non excluded adapter ports */ retval = 0; break; + case E1000_DEV_ID_82576_QUAD_COPPER: + /* quad port adapters only support WoL on port A */ + if (!(adapter->flags & IGB_FLAG_QUAD_PORT_A)) { + wol->supported = 0; + break; + } + /* return success for non excluded adapter ports */ + retval = 0; + break; default: /* dual port cards only support WoL on port A from now on * unless it was enabled in the eeprom for port B @@ -1774,6 +1861,8 @@ static int igb_set_coalesce(struct net_device *netdev, struct ethtool_coalesce *ec) { struct igb_adapter *adapter = netdev_priv(netdev); + struct e1000_hw *hw = &adapter->hw; + int i; if ((ec->rx_coalesce_usecs > IGB_MAX_ITR_USECS) || ((ec->rx_coalesce_usecs > 3) && @@ -1782,13 +1871,16 @@ static int igb_set_coalesce(struct net_device *netdev, return -EINVAL; /* convert to rate of irq's per second */ - if (ec->rx_coalesce_usecs <= 3) + if (ec->rx_coalesce_usecs && ec->rx_coalesce_usecs <= 3) { adapter->itr_setting = ec->rx_coalesce_usecs; - else - adapter->itr_setting = (1000000 / ec->rx_coalesce_usecs); + adapter->itr = IGB_START_ITR; + } else { + adapter->itr_setting = ec->rx_coalesce_usecs << 2; + adapter->itr = adapter->itr_setting; + } - if (netif_running(netdev)) - igb_reinit_locked(adapter); + for (i = 0; i < adapter->num_rx_queues; i++) + wr32(adapter->rx_ring[i].itr_register, adapter->itr); return 0; } @@ -1801,7 +1893,7 @@ static int igb_get_coalesce(struct net_device *netdev, if (adapter->itr_setting <= 3) ec->rx_coalesce_usecs = adapter->itr_setting; else - ec->rx_coalesce_usecs = 1000000 / adapter->itr_setting; + ec->rx_coalesce_usecs = adapter->itr_setting >> 2; return 0; } @@ -1835,6 +1927,18 @@ static void igb_get_ethtool_stats(struct net_device *netdev, int stat_count = sizeof(struct igb_queue_stats) / sizeof(u64); int j; int i; +#ifdef CONFIG_IGB_LRO + int aggregated = 0, flushed = 0, no_desc = 0; + + for (i = 0; i < adapter->num_rx_queues; i++) { + aggregated += adapter->rx_ring[i].lro_mgr.stats.aggregated; + flushed += adapter->rx_ring[i].lro_mgr.stats.flushed; + no_desc += adapter->rx_ring[i].lro_mgr.stats.no_desc; + } + adapter->lro_aggregated = aggregated; + adapter->lro_flushed = flushed; + adapter->lro_no_desc = no_desc; +#endif igb_update_stats(adapter); for (i = 0; i < IGB_GLOBAL_STATS_LEN; i++) { @@ -1842,6 +1946,13 @@ static void igb_get_ethtool_stats(struct net_device *netdev, data[i] = (igb_gstrings_stats[i].sizeof_stat == sizeof(u64)) ? *(u64 *)p : *(u32 *)p; } + 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++) + 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; diff --git a/drivers/net/igb/igb_main.c b/drivers/net/igb/igb_main.c index e79a26a886c8..1b7cb29fe68e 100644 --- a/drivers/net/igb/igb_main.c +++ b/drivers/net/igb/igb_main.c @@ -41,22 +41,27 @@ #include <linux/delay.h> #include <linux/interrupt.h> #include <linux/if_ether.h> - +#ifdef CONFIG_DCA +#include <linux/dca.h> +#endif #include "igb.h" -#define DRV_VERSION "1.0.8-k2" +#define DRV_VERSION "1.2.45-k2" char igb_driver_name[] = "igb"; char igb_driver_version[] = DRV_VERSION; static const char igb_driver_string[] = "Intel(R) Gigabit Ethernet Network Driver"; -static const char igb_copyright[] = "Copyright (c) 2007 Intel Corporation."; - +static const char igb_copyright[] = "Copyright (c) 2008 Intel Corporation."; static const struct e1000_info *igb_info_tbl[] = { [board_82575] = &e1000_82575_info, }; static struct pci_device_id igb_pci_tbl[] = { + { PCI_VDEVICE(INTEL, E1000_DEV_ID_82576), board_82575 }, + { PCI_VDEVICE(INTEL, E1000_DEV_ID_82576_FIBER), board_82575 }, + { PCI_VDEVICE(INTEL, E1000_DEV_ID_82576_SERDES), board_82575 }, + { PCI_VDEVICE(INTEL, E1000_DEV_ID_82576_QUAD_COPPER), board_82575 }, { PCI_VDEVICE(INTEL, E1000_DEV_ID_82575EB_COPPER), board_82575 }, { PCI_VDEVICE(INTEL, E1000_DEV_ID_82575EB_FIBER_SERDES), board_82575 }, { PCI_VDEVICE(INTEL, E1000_DEV_ID_82575GB_QUAD_COPPER), board_82575 }, @@ -71,8 +76,8 @@ static int igb_setup_all_tx_resources(struct igb_adapter *); static int igb_setup_all_rx_resources(struct igb_adapter *); static void igb_free_all_tx_resources(struct igb_adapter *); static void igb_free_all_rx_resources(struct igb_adapter *); -static void igb_free_tx_resources(struct igb_adapter *, struct igb_ring *); -static void igb_free_rx_resources(struct igb_adapter *, struct igb_ring *); +static void igb_free_tx_resources(struct igb_ring *); +static void igb_free_rx_resources(struct igb_ring *); void igb_update_stats(struct igb_adapter *); static int igb_probe(struct pci_dev *, const struct pci_device_id *); static void __devexit igb_remove(struct pci_dev *pdev); @@ -84,8 +89,8 @@ static void igb_configure_rx(struct igb_adapter *); static void igb_setup_rctl(struct igb_adapter *); static void igb_clean_all_tx_rings(struct igb_adapter *); static void igb_clean_all_rx_rings(struct igb_adapter *); -static void igb_clean_tx_ring(struct igb_adapter *, struct igb_ring *); -static void igb_clean_rx_ring(struct igb_adapter *, struct igb_ring *); +static void igb_clean_tx_ring(struct igb_ring *); +static void igb_clean_rx_ring(struct igb_ring *); static void igb_set_multi(struct net_device *); static void igb_update_phy_info(unsigned long); static void igb_watchdog(unsigned long); @@ -102,12 +107,18 @@ static irqreturn_t igb_msix_other(int irq, void *); static irqreturn_t igb_msix_rx(int irq, void *); static irqreturn_t igb_msix_tx(int irq, void *); static int igb_clean_rx_ring_msix(struct napi_struct *, int); -static bool igb_clean_tx_irq(struct igb_adapter *, struct igb_ring *); -static int igb_clean(struct napi_struct *, int); -static bool igb_clean_rx_irq_adv(struct igb_adapter *, - struct igb_ring *, int *, int); -static void igb_alloc_rx_buffers_adv(struct igb_adapter *, - struct igb_ring *, int); +#ifdef CONFIG_DCA +static void igb_update_rx_dca(struct igb_ring *); +static void igb_update_tx_dca(struct igb_ring *); +static void igb_setup_dca(struct igb_adapter *); +#endif /* CONFIG_DCA */ +static bool igb_clean_tx_irq(struct igb_ring *); +static int igb_poll(struct napi_struct *, int); +static bool igb_clean_rx_irq_adv(struct igb_ring *, int *, int); +static void igb_alloc_rx_buffers_adv(struct igb_ring *, int); +#ifdef CONFIG_IGB_LRO +static int igb_get_skb_hdr(struct sk_buff *skb, void **, void **, u64 *, void *); +#endif static int igb_ioctl(struct net_device *, struct ifreq *, int cmd); static void igb_tx_timeout(struct net_device *); static void igb_reset_task(struct work_struct *); @@ -121,6 +132,14 @@ static int igb_suspend(struct pci_dev *, pm_message_t); static int igb_resume(struct pci_dev *); #endif static void igb_shutdown(struct pci_dev *); +#ifdef CONFIG_DCA +static int igb_notify_dca(struct notifier_block *, unsigned long, void *); +static struct notifier_block dca_notifier = { + .notifier_call = igb_notify_dca, + .next = NULL, + .priority = 0 +}; +#endif #ifdef CONFIG_NET_POLL_CONTROLLER /* for netdump / net console */ @@ -153,6 +172,8 @@ static struct pci_driver igb_driver = { .err_handler = &igb_err_handler }; +static int global_quad_port_a; /* global quad port a indication */ + MODULE_AUTHOR("Intel Corporation, <e1000-devel@lists.sourceforge.net>"); MODULE_DESCRIPTION("Intel(R) Gigabit Ethernet Network Driver"); MODULE_LICENSE("GPL"); @@ -184,7 +205,12 @@ static int __init igb_init_module(void) printk(KERN_INFO "%s\n", igb_copyright); + global_quad_port_a = 0; + ret = pci_register_driver(&igb_driver); +#ifdef CONFIG_DCA + dca_register_notify(&dca_notifier); +#endif return ret; } @@ -198,6 +224,9 @@ module_init(igb_init_module); **/ static void __exit igb_exit_module(void) { +#ifdef CONFIG_DCA + dca_unregister_notify(&dca_notifier); +#endif pci_unregister_driver(&igb_driver); } @@ -226,25 +255,46 @@ static int igb_alloc_queues(struct igb_adapter *adapter) return -ENOMEM; } + adapter->rx_ring->buddy = adapter->tx_ring; + + for (i = 0; i < adapter->num_tx_queues; i++) { + struct igb_ring *ring = &(adapter->tx_ring[i]); + ring->adapter = adapter; + ring->queue_index = i; + } for (i = 0; i < adapter->num_rx_queues; i++) { struct igb_ring *ring = &(adapter->rx_ring[i]); ring->adapter = adapter; + ring->queue_index = i; ring->itr_register = E1000_ITR; - if (!ring->napi.poll) - netif_napi_add(adapter->netdev, &ring->napi, igb_clean, - adapter->napi.weight / - adapter->num_rx_queues); + /* set a default napi handler for each rx_ring */ + netif_napi_add(adapter->netdev, &ring->napi, igb_poll, 64); } return 0; } +static void igb_free_queues(struct igb_adapter *adapter) +{ + int i; + + for (i = 0; i < adapter->num_rx_queues; i++) + netif_napi_del(&adapter->rx_ring[i].napi); + + kfree(adapter->tx_ring); + kfree(adapter->rx_ring); +} + #define IGB_N0_QUEUE -1 static void igb_assign_vector(struct igb_adapter *adapter, int rx_queue, int tx_queue, int msix_vector) { u32 msixbm = 0; struct e1000_hw *hw = &adapter->hw; + u32 ivar, index; + + switch (hw->mac.type) { + case e1000_82575: /* The 82575 assigns vectors using a bitmask, which matches the bitmask for the EICR/EIMS/EIMC registers. To assign one or more queues to a vector, we write the appropriate bits @@ -259,6 +309,47 @@ static void igb_assign_vector(struct igb_adapter *adapter, int rx_queue, E1000_EICR_TX_QUEUE0 << tx_queue; } array_wr32(E1000_MSIXBM(0), msix_vector, msixbm); + break; + case e1000_82576: + /* Kawela uses a table-based method for assigning vectors. + Each queue has a single entry in the table to which we write + a vector number along with a "valid" bit. Sadly, the layout + of the table is somewhat counterintuitive. */ + if (rx_queue > IGB_N0_QUEUE) { + index = (rx_queue & 0x7); + ivar = array_rd32(E1000_IVAR0, index); + if (rx_queue < 8) { + /* vector goes into low byte of register */ + ivar = ivar & 0xFFFFFF00; + ivar |= msix_vector | E1000_IVAR_VALID; + } else { + /* vector goes into third byte of register */ + ivar = ivar & 0xFF00FFFF; + ivar |= (msix_vector | E1000_IVAR_VALID) << 16; + } + adapter->rx_ring[rx_queue].eims_value= 1 << msix_vector; + array_wr32(E1000_IVAR0, index, ivar); + } + if (tx_queue > IGB_N0_QUEUE) { + index = (tx_queue & 0x7); + ivar = array_rd32(E1000_IVAR0, index); + if (tx_queue < 8) { + /* vector goes into second byte of register */ + ivar = ivar & 0xFFFF00FF; + ivar |= (msix_vector | E1000_IVAR_VALID) << 8; + } else { + /* vector goes into high byte of register */ + ivar = ivar & 0x00FFFFFF; + ivar |= (msix_vector | E1000_IVAR_VALID) << 24; + } + adapter->tx_ring[tx_queue].eims_value= 1 << msix_vector; + array_wr32(E1000_IVAR0, index, ivar); + } + break; + default: + BUG(); + break; + } } /** @@ -274,13 +365,19 @@ static void igb_configure_msix(struct igb_adapter *adapter) struct e1000_hw *hw = &adapter->hw; adapter->eims_enable_mask = 0; + if (hw->mac.type == e1000_82576) + /* Turn on MSI-X capability first, or our settings + * won't stick. And it will take days to debug. */ + wr32(E1000_GPIE, E1000_GPIE_MSIX_MODE | + E1000_GPIE_PBA | E1000_GPIE_EIAME | + E1000_GPIE_NSICR); for (i = 0; i < adapter->num_tx_queues; i++) { struct igb_ring *tx_ring = &adapter->tx_ring[i]; igb_assign_vector(adapter, IGB_N0_QUEUE, i, vector++); adapter->eims_enable_mask |= tx_ring->eims_value; if (tx_ring->itr_val) - writel(1000000000 / (tx_ring->itr_val * 256), + writel(tx_ring->itr_val, hw->hw_addr + tx_ring->itr_register); else writel(1, hw->hw_addr + tx_ring->itr_register); @@ -288,10 +385,11 @@ static void igb_configure_msix(struct igb_adapter *adapter) for (i = 0; i < adapter->num_rx_queues; i++) { struct igb_ring *rx_ring = &adapter->rx_ring[i]; + rx_ring->buddy = 0; igb_assign_vector(adapter, i, IGB_N0_QUEUE, vector++); adapter->eims_enable_mask |= rx_ring->eims_value; if (rx_ring->itr_val) - writel(1000000000 / (rx_ring->itr_val * 256), + writel(rx_ring->itr_val, hw->hw_addr + rx_ring->itr_register); else writel(1, hw->hw_addr + rx_ring->itr_register); @@ -299,12 +397,11 @@ static void igb_configure_msix(struct igb_adapter *adapter) /* set vector for other causes, i.e. link changes */ + switch (hw->mac.type) { + case e1000_82575: array_wr32(E1000_MSIXBM(0), vector++, E1000_EIMS_OTHER); - /* disable IAM for ICR interrupt bits */ - wr32(E1000_IAM, 0); - tmp = rd32(E1000_CTRL_EXT); /* enable MSI-X PBA support*/ tmp |= E1000_CTRL_EXT_PBA_CLR; @@ -315,7 +412,21 @@ static void igb_configure_msix(struct igb_adapter *adapter) wr32(E1000_CTRL_EXT, tmp); adapter->eims_enable_mask |= E1000_EIMS_OTHER; + adapter->eims_other = E1000_EIMS_OTHER; + + break; + + case e1000_82576: + tmp = (vector++ | E1000_IVAR_VALID) << 8; + wr32(E1000_IVAR_MISC, tmp); + adapter->eims_enable_mask = (1 << (vector)) - 1; + adapter->eims_other = 1 << (vector - 1); + break; + default: + /* do nothing, since nothing else supports MSI-X */ + break; + } /* switch (hw->mac.type) */ wrfl(); } @@ -341,7 +452,7 @@ static int igb_request_msix(struct igb_adapter *adapter) if (err) goto out; ring->itr_register = E1000_EITR(0) + (vector << 2); - ring->itr_val = adapter->itr; + ring->itr_val = 976; /* ~4000 ints/sec */ vector++; } for (i = 0; i < adapter->num_rx_queues; i++) { @@ -357,6 +468,9 @@ static int igb_request_msix(struct igb_adapter *adapter) goto out; ring->itr_register = E1000_EITR(0) + (vector << 2); ring->itr_val = adapter->itr; + /* overwrite the poll routine for MSIX, we've already done + * netif_napi_add */ + ring->napi.poll = &igb_clean_rx_ring_msix; vector++; } @@ -365,9 +479,6 @@ static int igb_request_msix(struct igb_adapter *adapter) if (err) goto out; - adapter->napi.poll = igb_clean_rx_ring_msix; - for (i = 0; i < adapter->num_rx_queues; i++) - adapter->rx_ring[i].napi.poll = adapter->napi.poll; igb_configure_msix(adapter); return 0; out: @@ -380,7 +491,7 @@ static void igb_reset_interrupt_capability(struct igb_adapter *adapter) pci_disable_msix(adapter->pdev); kfree(adapter->msix_entries); adapter->msix_entries = NULL; - } else if (adapter->msi_enabled) + } else if (adapter->flags & IGB_FLAG_HAS_MSI) pci_disable_msi(adapter->pdev); return; } @@ -417,8 +528,12 @@ static void igb_set_interrupt_capability(struct igb_adapter *adapter) /* If we can't do MSI-X, try MSI */ msi_only: adapter->num_rx_queues = 1; + adapter->num_tx_queues = 1; if (!pci_enable_msi(adapter->pdev)) - adapter->msi_enabled = 1; + adapter->flags |= IGB_FLAG_HAS_MSI; + + /* Notify the stack of the (possibly) reduced Tx Queue count. */ + adapter->netdev->real_num_tx_queues = adapter->num_tx_queues; return; } @@ -436,29 +551,38 @@ static int igb_request_irq(struct igb_adapter *adapter) if (adapter->msix_entries) { err = igb_request_msix(adapter); - if (!err) { - /* enable IAM, auto-mask, - * DO NOT USE EIAM or IAM in legacy mode */ - wr32(E1000_IAM, IMS_ENABLE_MASK); + if (!err) goto request_done; - } /* fall back to MSI */ igb_reset_interrupt_capability(adapter); if (!pci_enable_msi(adapter->pdev)) - adapter->msi_enabled = 1; + adapter->flags |= IGB_FLAG_HAS_MSI; igb_free_all_tx_resources(adapter); igb_free_all_rx_resources(adapter); adapter->num_rx_queues = 1; igb_alloc_queues(adapter); + } else { + switch (hw->mac.type) { + case e1000_82575: + wr32(E1000_MSIXBM(0), + (E1000_EICR_RX_QUEUE0 | E1000_EIMS_OTHER)); + break; + case e1000_82576: + wr32(E1000_IVAR0, E1000_IVAR_VALID); + break; + default: + break; + } } - if (adapter->msi_enabled) { + + if (adapter->flags & IGB_FLAG_HAS_MSI) { err = request_irq(adapter->pdev->irq, &igb_intr_msi, 0, netdev->name, netdev); if (!err) goto request_done; /* fall back to legacy interrupts */ igb_reset_interrupt_capability(adapter); - adapter->msi_enabled = 0; + adapter->flags &= ~IGB_FLAG_HAS_MSI; } err = request_irq(adapter->pdev->irq, &igb_intr, IRQF_SHARED, @@ -502,9 +626,12 @@ static void igb_irq_disable(struct igb_adapter *adapter) struct e1000_hw *hw = &adapter->hw; if (adapter->msix_entries) { + wr32(E1000_EIAM, 0); wr32(E1000_EIMC, ~0); wr32(E1000_EIAC, 0); } + + wr32(E1000_IAM, 0); wr32(E1000_IMC, ~0); wrfl(); synchronize_irq(adapter->pdev->irq); @@ -519,13 +646,14 @@ static void igb_irq_enable(struct igb_adapter *adapter) struct e1000_hw *hw = &adapter->hw; if (adapter->msix_entries) { - wr32(E1000_EIMS, - adapter->eims_enable_mask); - wr32(E1000_EIAC, - adapter->eims_enable_mask); + wr32(E1000_EIAC, adapter->eims_enable_mask); + wr32(E1000_EIAM, adapter->eims_enable_mask); + wr32(E1000_EIMS, adapter->eims_enable_mask); wr32(E1000_IMS, E1000_IMS_LSC); - } else - wr32(E1000_IMS, IMS_ENABLE_MASK); + } else { + wr32(E1000_IMS, IMS_ENABLE_MASK); + wr32(E1000_IAM, IMS_ENABLE_MASK); + } } static void igb_update_mng_vlan(struct igb_adapter *adapter) @@ -632,12 +760,15 @@ static void igb_configure(struct igb_adapter *adapter) igb_configure_tx(adapter); igb_setup_rctl(adapter); igb_configure_rx(adapter); + + igb_rx_fifo_flush_82575(&adapter->hw); + /* call IGB_DESC_UNUSED which always leaves * at least 1 descriptor unused to make sure * next_to_use != next_to_clean */ for (i = 0; i < adapter->num_rx_queues; i++) { struct igb_ring *ring = &adapter->rx_ring[i]; - igb_alloc_rx_buffers_adv(adapter, ring, IGB_DESC_UNUSED(ring)); + igb_alloc_rx_buffers_adv(ring, IGB_DESC_UNUSED(ring)); } @@ -660,13 +791,10 @@ int igb_up(struct igb_adapter *adapter) clear_bit(__IGB_DOWN, &adapter->state); - napi_enable(&adapter->napi); - - if (adapter->msix_entries) { - for (i = 0; i < adapter->num_rx_queues; i++) - napi_enable(&adapter->rx_ring[i].napi); + for (i = 0; i < adapter->num_rx_queues; i++) + napi_enable(&adapter->rx_ring[i].napi); + if (adapter->msix_entries) igb_configure_msix(adapter); - } /* Clear any pending interrupts. */ rd32(E1000_ICR); @@ -693,7 +821,7 @@ void igb_down(struct igb_adapter *adapter) wr32(E1000_RCTL, rctl & ~E1000_RCTL_EN); /* flush and sleep below */ - netif_stop_queue(netdev); + netif_tx_stop_all_queues(netdev); /* disable transmits in the hardware */ tctl = rd32(E1000_TCTL); @@ -703,11 +831,9 @@ void igb_down(struct igb_adapter *adapter) wrfl(); msleep(10); - napi_disable(&adapter->napi); + for (i = 0; i < adapter->num_rx_queues; i++) + napi_disable(&adapter->rx_ring[i].napi); - if (adapter->msix_entries) - for (i = 0; i < adapter->num_rx_queues; i++) - napi_disable(&adapter->rx_ring[i].napi); igb_irq_disable(adapter); del_timer_sync(&adapter->watchdog_timer); @@ -737,16 +863,23 @@ void igb_reinit_locked(struct igb_adapter *adapter) void igb_reset(struct igb_adapter *adapter) { struct e1000_hw *hw = &adapter->hw; - struct e1000_fc_info *fc = &adapter->hw.fc; + struct e1000_mac_info *mac = &hw->mac; + struct e1000_fc_info *fc = &hw->fc; u32 pba = 0, tx_space, min_tx_space, min_rx_space; u16 hwm; /* Repartition Pba for greater than 9k mtu * To take effect CTRL.RST is required. */ + if (mac->type != e1000_82576) { pba = E1000_PBA_34K; + } + else { + pba = E1000_PBA_64K; + } - if (adapter->max_frame_size > ETH_FRAME_LEN + ETH_FCS_LEN) { + if ((adapter->max_frame_size > ETH_FRAME_LEN + ETH_FCS_LEN) && + (mac->type < e1000_82576)) { /* adjust PBA for jumbo frames */ wr32(E1000_PBA, pba); @@ -785,8 +918,8 @@ void igb_reset(struct igb_adapter *adapter) if (pba < min_rx_space) pba = min_rx_space; } + wr32(E1000_PBA, pba); } - wr32(E1000_PBA, pba); /* flow control settings */ /* The high water mark must be low enough to fit one full frame @@ -795,10 +928,15 @@ void igb_reset(struct igb_adapter *adapter) * - 90% of the Rx FIFO size, or * - the full Rx FIFO size minus one full frame */ 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; + if (mac->type < e1000_82576) { + fc->high_water = hwm & 0xFFF8; /* 8-byte granularity */ + fc->low_water = fc->high_water - 8; + } else { + fc->high_water = hwm & 0xFFF0; /* 16-byte granularity */ + fc->low_water = fc->high_water - 16; + } fc->pause_time = 0xFFFF; fc->send_xon = 1; fc->type = fc->original_type; @@ -821,6 +959,21 @@ void igb_reset(struct igb_adapter *adapter) } /** + * igb_is_need_ioport - determine if an adapter needs ioport resources or not + * @pdev: PCI device information struct + * + * Returns true if an adapter needs ioport resources + **/ +static int igb_is_need_ioport(struct pci_dev *pdev) +{ + switch (pdev->device) { + /* Currently there are no adapters that need ioport resources */ + default: + return false; + } +} + +/** * igb_probe - Device Initialization Routine * @pdev: PCI device information struct * @ent: entry in igb_pci_tbl @@ -839,13 +992,21 @@ static int __devinit igb_probe(struct pci_dev *pdev, struct e1000_hw *hw; const struct e1000_info *ei = igb_info_tbl[ent->driver_data]; unsigned long mmio_start, mmio_len; - static int cards_found; int i, err, pci_using_dac; u16 eeprom_data = 0; u16 eeprom_apme_mask = IGB_EEPROM_APME; u32 part_num; + int bars, need_ioport; - err = pci_enable_device(pdev); + /* do not allocate ioport bars when not needed */ + need_ioport = igb_is_need_ioport(pdev); + if (need_ioport) { + bars = pci_select_bars(pdev, IORESOURCE_MEM | IORESOURCE_IO); + err = pci_enable_device(pdev); + } else { + bars = pci_select_bars(pdev, IORESOURCE_MEM); + err = pci_enable_device_mem(pdev); + } if (err) return err; @@ -867,7 +1028,7 @@ static int __devinit igb_probe(struct pci_dev *pdev, } } - err = pci_request_regions(pdev, igb_driver_name); + err = pci_request_selected_regions(pdev, bars, igb_driver_name); if (err) goto err_pci_reg; @@ -875,7 +1036,7 @@ static int __devinit igb_probe(struct pci_dev *pdev, pci_save_state(pdev); err = -ENOMEM; - netdev = alloc_etherdev(sizeof(struct igb_adapter)); + netdev = alloc_etherdev_mq(sizeof(struct igb_adapter), IGB_MAX_TX_QUEUES); if (!netdev) goto err_alloc_etherdev; @@ -888,6 +1049,8 @@ static int __devinit igb_probe(struct pci_dev *pdev, hw = &adapter->hw; hw->back = adapter; adapter->msg_enable = NETIF_MSG_DRV | NETIF_MSG_PROBE; + adapter->bars = bars; + adapter->need_ioport = need_ioport; mmio_start = pci_resource_start(pdev, 0); mmio_len = pci_resource_len(pdev, 0); @@ -907,7 +1070,6 @@ static int __devinit igb_probe(struct pci_dev *pdev, igb_set_ethtool_ops(netdev); netdev->tx_timeout = &igb_tx_timeout; netdev->watchdog_timeo = 5 * HZ; - netif_napi_add(netdev, &adapter->napi, igb_clean, 64); netdev->vlan_rx_register = igb_vlan_rx_register; netdev->vlan_rx_add_vid = igb_vlan_rx_add_vid; netdev->vlan_rx_kill_vid = igb_vlan_rx_kill_vid; @@ -921,8 +1083,6 @@ static int __devinit igb_probe(struct pci_dev *pdev, netdev->mem_start = mmio_start; netdev->mem_end = mmio_start + mmio_len; - adapter->bd_number = cards_found; - /* PCI config space info */ hw->vendor_id = pdev->vendor; hw->device_id = pdev->device; @@ -947,6 +1107,17 @@ static int __devinit igb_probe(struct pci_dev *pdev, igb_get_bus_info_pcie(hw); + /* set flags */ + switch (hw->mac.type) { + case e1000_82576: + case e1000_82575: + adapter->flags |= IGB_FLAG_HAS_DCA; + adapter->flags |= IGB_FLAG_NEED_CTX_IDX; + break; + default: + break; + } + hw->phy.autoneg_wait_to_complete = false; hw->mac.adaptive_ifs = true; @@ -968,8 +1139,17 @@ static int __devinit igb_probe(struct pci_dev *pdev, NETIF_F_HW_VLAN_FILTER; netdev->features |= NETIF_F_TSO; - netdev->features |= NETIF_F_TSO6; + +#ifdef CONFIG_IGB_LRO + netdev->features |= NETIF_F_LRO; +#endif + + netdev->vlan_features |= NETIF_F_TSO; + netdev->vlan_features |= NETIF_F_TSO6; + netdev->vlan_features |= NETIF_F_HW_CSUM; + netdev->vlan_features |= NETIF_F_SG; + if (pci_using_dac) netdev->features |= NETIF_F_HIGHDMA; @@ -1053,11 +1233,23 @@ static int __devinit igb_probe(struct pci_dev *pdev, adapter->eeprom_wol = 0; break; case E1000_DEV_ID_82575EB_FIBER_SERDES: + case E1000_DEV_ID_82576_FIBER: + case E1000_DEV_ID_82576_SERDES: /* Wake events only supported on port A for dual fiber * regardless of eeprom setting */ if (rd32(E1000_STATUS) & E1000_STATUS_FUNC_1) adapter->eeprom_wol = 0; break; + case E1000_DEV_ID_82576_QUAD_COPPER: + /* if quad port adapter, disable WoL on all but port A */ + if (global_quad_port_a != 0) + adapter->eeprom_wol = 0; + else + adapter->flags |= IGB_FLAG_QUAD_PORT_A; + /* Reset for multiple quad port adapters */ + if (++global_quad_port_a == 4) + global_quad_port_a = 0; + break; } /* initialize the wol settings based on the eeprom settings */ @@ -1072,13 +1264,25 @@ static int __devinit igb_probe(struct pci_dev *pdev, /* tell the stack to leave us alone until igb_open() is called */ netif_carrier_off(netdev); - netif_stop_queue(netdev); + netif_tx_stop_all_queues(netdev); strcpy(netdev->name, "eth%d"); err = register_netdev(netdev); if (err) goto err_register; +#ifdef CONFIG_DCA + if ((adapter->flags & IGB_FLAG_HAS_DCA) && + (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, 2); + igb_setup_dca(adapter); + } +#endif + dev_info(&pdev->dev, "Intel(R) Gigabit Ethernet Network Connection\n"); /* print bus type/speed/width info */ dev_info(&pdev->dev, @@ -1099,10 +1303,9 @@ static int __devinit igb_probe(struct pci_dev *pdev, dev_info(&pdev->dev, "Using %s interrupts. %d rx queue(s), %d tx queue(s)\n", adapter->msix_entries ? "MSI-X" : - adapter->msi_enabled ? "MSI" : "legacy", + (adapter->flags & IGB_FLAG_HAS_MSI) ? "MSI" : "legacy", adapter->num_rx_queues, adapter->num_tx_queues); - cards_found++; return 0; err_register: @@ -1115,15 +1318,14 @@ err_eeprom: iounmap(hw->flash_address); igb_remove_device(hw); - kfree(adapter->tx_ring); - kfree(adapter->rx_ring); + igb_free_queues(adapter); err_sw_init: err_hw_init: iounmap(hw->hw_addr); err_ioremap: free_netdev(netdev); err_alloc_etherdev: - pci_release_regions(pdev); + pci_release_selected_regions(pdev, bars); err_pci_reg: err_dma: pci_disable_device(pdev); @@ -1143,6 +1345,9 @@ static void __devexit igb_remove(struct pci_dev *pdev) { struct net_device *netdev = pci_get_drvdata(pdev); struct igb_adapter *adapter = netdev_priv(netdev); +#ifdef CONFIG_DCA + struct e1000_hw *hw = &adapter->hw; +#endif /* flush_scheduled work may reschedule our watchdog task, so * explicitly disable watchdog tasks from being rescheduled */ @@ -1152,6 +1357,15 @@ static void __devexit igb_remove(struct pci_dev *pdev) flush_scheduled_work(); +#ifdef CONFIG_DCA + if (adapter->flags & IGB_FLAG_DCA_ENABLED) { + dev_info(&pdev->dev, "DCA disabled\n"); + dca_remove_requester(&pdev->dev); + adapter->flags &= ~IGB_FLAG_DCA_ENABLED; + wr32(E1000_DCA_CTRL, 1); + } +#endif + /* Release control of h/w to f/w. If f/w is AMT enabled, this * would have already happened in close and is redundant. */ igb_release_hw_control(adapter); @@ -1164,13 +1378,12 @@ static void __devexit igb_remove(struct pci_dev *pdev) igb_remove_device(&adapter->hw); igb_reset_interrupt_capability(adapter); - kfree(adapter->tx_ring); - kfree(adapter->rx_ring); + igb_free_queues(adapter); iounmap(adapter->hw.hw_addr); if (adapter->hw.flash_address) iounmap(adapter->hw.flash_address); - pci_release_regions(pdev); + pci_release_selected_regions(pdev, adapter->bars); free_netdev(netdev); @@ -1200,9 +1413,11 @@ static int __devinit igb_sw_init(struct igb_adapter *adapter) /* Number of supported queues. */ /* Having more queues than CPUs doesn't make sense. */ - adapter->num_tx_queues = 1; - adapter->num_rx_queues = min(IGB_MAX_RX_QUEUES, num_online_cpus()); + adapter->num_rx_queues = min((u32)IGB_MAX_RX_QUEUES, (u32)num_online_cpus()); + adapter->num_tx_queues = min(IGB_MAX_TX_QUEUES, num_online_cpus()); + /* This call may decrease the number of queues depending on + * interrupt mode. */ igb_set_interrupt_capability(adapter); if (igb_alloc_queues(adapter)) { @@ -1270,15 +1485,16 @@ static int igb_open(struct net_device *netdev) /* From here on the code is the same as igb_up() */ clear_bit(__IGB_DOWN, &adapter->state); - napi_enable(&adapter->napi); - if (adapter->msix_entries) - for (i = 0; i < adapter->num_rx_queues; i++) - napi_enable(&adapter->rx_ring[i].napi); - - igb_irq_enable(adapter); + for (i = 0; i < adapter->num_rx_queues; i++) + napi_enable(&adapter->rx_ring[i].napi); /* Clear any pending interrupts. */ rd32(E1000_ICR); + + igb_irq_enable(adapter); + + netif_tx_start_all_queues(netdev); + /* Fire a link status change interrupt to start the watchdog. */ wr32(E1000_ICS, E1000_ICS_LSC); @@ -1364,8 +1580,6 @@ int igb_setup_tx_resources(struct igb_adapter *adapter, tx_ring->adapter = adapter; tx_ring->next_to_use = 0; tx_ring->next_to_clean = 0; - spin_lock_init(&tx_ring->tx_clean_lock); - spin_lock_init(&tx_ring->tx_lock); return 0; err: @@ -1385,6 +1599,7 @@ err: static int igb_setup_all_tx_resources(struct igb_adapter *adapter) { int i, err = 0; + int r_idx; for (i = 0; i < adapter->num_tx_queues; i++) { err = igb_setup_tx_resources(adapter, &adapter->tx_ring[i]); @@ -1392,12 +1607,15 @@ static int igb_setup_all_tx_resources(struct igb_adapter *adapter) dev_err(&adapter->pdev->dev, "Allocation for Tx Queue %u failed\n", i); for (i--; i >= 0; i--) - igb_free_tx_resources(adapter, - &adapter->tx_ring[i]); + igb_free_tx_resources(&adapter->tx_ring[i]); break; } } + for (i = 0; i < IGB_MAX_TX_QUEUES; i++) { + r_idx = i % adapter->num_tx_queues; + adapter->multi_tx_table[i] = &adapter->tx_ring[r_idx]; + } return err; } @@ -1484,6 +1702,14 @@ int igb_setup_rx_resources(struct igb_adapter *adapter, struct pci_dev *pdev = adapter->pdev; int size, desc_len; +#ifdef CONFIG_IGB_LRO + size = sizeof(struct net_lro_desc) * MAX_LRO_DESCRIPTORS; + rx_ring->lro_mgr.lro_arr = vmalloc(size); + if (!rx_ring->lro_mgr.lro_arr) + goto err; + memset(rx_ring->lro_mgr.lro_arr, 0, size); +#endif + size = sizeof(struct igb_buffer) * rx_ring->count; rx_ring->buffer_info = vmalloc(size); if (!rx_ring->buffer_info) @@ -1504,15 +1730,16 @@ int igb_setup_rx_resources(struct igb_adapter *adapter, rx_ring->next_to_clean = 0; rx_ring->next_to_use = 0; - rx_ring->pending_skb = NULL; rx_ring->adapter = adapter; - /* FIXME: do we want to setup ring->napi->poll here? */ - rx_ring->napi.poll = adapter->napi.poll; return 0; err: +#ifdef CONFIG_IGB_LRO + vfree(rx_ring->lro_mgr.lro_arr); + rx_ring->lro_mgr.lro_arr = NULL; +#endif vfree(rx_ring->buffer_info); dev_err(&adapter->pdev->dev, "Unable to allocate memory for " "the receive descriptor ring\n"); @@ -1536,8 +1763,7 @@ static int igb_setup_all_rx_resources(struct igb_adapter *adapter) dev_err(&adapter->pdev->dev, "Allocation for Rx Queue %u failed\n", i); for (i--; i >= 0; i--) - igb_free_rx_resources(adapter, - &adapter->rx_ring[i]); + igb_free_rx_resources(&adapter->rx_ring[i]); break; } } @@ -1564,10 +1790,12 @@ static void igb_setup_rctl(struct igb_adapter *adapter) E1000_RCTL_LBM_NO | E1000_RCTL_RDMTS_HALF | (adapter->hw.mac.mc_filter_type << E1000_RCTL_MO_SHIFT); - /* disable the stripping of CRC because it breaks - * BMC firmware connected over SMBUS - rctl |= E1000_RCTL_SECRC; + /* + * enable stripping of CRC. It's unlikely this will break BMC + * redirection as it did with e1000. Newer features require + * that the HW strips the CRC. */ + rctl |= E1000_RCTL_SECRC; rctl &= ~E1000_RCTL_SBP; @@ -1597,15 +1825,6 @@ static void igb_setup_rctl(struct igb_adapter *adapter) rctl |= E1000_RCTL_SZ_2048; rctl &= ~E1000_RCTL_BSEX; break; - case IGB_RXBUFFER_4096: - rctl |= E1000_RCTL_SZ_4096; - break; - case IGB_RXBUFFER_8192: - rctl |= E1000_RCTL_SZ_8192; - break; - case IGB_RXBUFFER_16384: - rctl |= E1000_RCTL_SZ_16384; - break; } } else { rctl &= ~E1000_RCTL_BSEX; @@ -1623,10 +1842,8 @@ static void igb_setup_rctl(struct igb_adapter *adapter) * so only enable packet split for jumbo frames */ if (rctl & E1000_RCTL_LPE) { adapter->rx_ps_hdr_size = IGB_RXBUFFER_128; - srrctl = adapter->rx_ps_hdr_size << + srrctl |= adapter->rx_ps_hdr_size << E1000_SRRCTL_BSIZEHDRSIZE_SHIFT; - /* buffer size is ALWAYS one page */ - srrctl |= PAGE_SIZE >> E1000_SRRCTL_BSIZEPKT_SHIFT; srrctl |= E1000_SRRCTL_DESCTYPE_HDR_SPLIT_ALWAYS; } else { adapter->rx_ps_hdr_size = 0; @@ -1660,8 +1877,7 @@ static void igb_configure_rx(struct igb_adapter *adapter) mdelay(10); if (adapter->itr_setting > 3) - wr32(E1000_ITR, - 1000000000 / (adapter->itr * 256)); + wr32(E1000_ITR, adapter->itr); /* Setup the HW Rx Head and Tail Descriptor Pointers and * the Base and Length of the Rx Descriptor Ring */ @@ -1686,6 +1902,16 @@ static void igb_configure_rx(struct igb_adapter *adapter) rxdctl |= IGB_RX_HTHRESH << 8; rxdctl |= IGB_RX_WTHRESH << 16; wr32(E1000_RXDCTL(i), rxdctl); +#ifdef CONFIG_IGB_LRO + /* Intitial LRO Settings */ + ring->lro_mgr.max_aggr = MAX_LRO_AGGR; + ring->lro_mgr.max_desc = MAX_LRO_DESCRIPTORS; + ring->lro_mgr.get_skb_header = igb_get_skb_hdr; + ring->lro_mgr.features = LRO_F_NAPI | LRO_F_EXTRACT_VLAN_ID; + ring->lro_mgr.dev = adapter->netdev; + ring->lro_mgr.ip_summed = CHECKSUM_UNNECESSARY; + ring->lro_mgr.ip_summed_aggr = CHECKSUM_UNNECESSARY; +#endif } if (adapter->num_rx_queues > 1) { @@ -1699,7 +1925,10 @@ static void igb_configure_rx(struct igb_adapter *adapter) get_random_bytes(&random[0], 40); - shift = 6; + if (hw->mac.type >= e1000_82576) + shift = 0; + else + shift = 6; for (j = 0; j < (32 * 4); j++) { reta.bytes[j & 3] = (j % adapter->num_rx_queues) << shift; @@ -1765,12 +1994,11 @@ static void igb_configure_rx(struct igb_adapter *adapter) * * Free all transmit software resources **/ -static void igb_free_tx_resources(struct igb_adapter *adapter, - struct igb_ring *tx_ring) +static void igb_free_tx_resources(struct igb_ring *tx_ring) { - struct pci_dev *pdev = adapter->pdev; + struct pci_dev *pdev = tx_ring->adapter->pdev; - igb_clean_tx_ring(adapter, tx_ring); + igb_clean_tx_ring(tx_ring); vfree(tx_ring->buffer_info); tx_ring->buffer_info = NULL; @@ -1791,7 +2019,7 @@ static void igb_free_all_tx_resources(struct igb_adapter *adapter) int i; for (i = 0; i < adapter->num_tx_queues; i++) - igb_free_tx_resources(adapter, &adapter->tx_ring[i]); + igb_free_tx_resources(&adapter->tx_ring[i]); } static void igb_unmap_and_free_tx_resource(struct igb_adapter *adapter, @@ -1817,9 +2045,9 @@ static void igb_unmap_and_free_tx_resource(struct igb_adapter *adapter, * @adapter: board private structure * @tx_ring: ring to be cleaned **/ -static void igb_clean_tx_ring(struct igb_adapter *adapter, - struct igb_ring *tx_ring) +static void igb_clean_tx_ring(struct igb_ring *tx_ring) { + struct igb_adapter *adapter = tx_ring->adapter; struct igb_buffer *buffer_info; unsigned long size; unsigned int i; @@ -1856,7 +2084,7 @@ static void igb_clean_all_tx_rings(struct igb_adapter *adapter) int i; for (i = 0; i < adapter->num_tx_queues; i++) - igb_clean_tx_ring(adapter, &adapter->tx_ring[i]); + igb_clean_tx_ring(&adapter->tx_ring[i]); } /** @@ -1866,16 +2094,20 @@ static void igb_clean_all_tx_rings(struct igb_adapter *adapter) * * Free all receive software resources **/ -static void igb_free_rx_resources(struct igb_adapter *adapter, - struct igb_ring *rx_ring) +static void igb_free_rx_resources(struct igb_ring *rx_ring) { - struct pci_dev *pdev = adapter->pdev; + struct pci_dev *pdev = rx_ring->adapter->pdev; - igb_clean_rx_ring(adapter, rx_ring); + igb_clean_rx_ring(rx_ring); vfree(rx_ring->buffer_info); rx_ring->buffer_info = NULL; +#ifdef CONFIG_IGB_LRO + vfree(rx_ring->lro_mgr.lro_arr); + rx_ring->lro_mgr.lro_arr = NULL; +#endif + pci_free_consistent(pdev, rx_ring->size, rx_ring->desc, rx_ring->dma); rx_ring->desc = NULL; @@ -1892,7 +2124,7 @@ static void igb_free_all_rx_resources(struct igb_adapter *adapter) int i; for (i = 0; i < adapter->num_rx_queues; i++) - igb_free_rx_resources(adapter, &adapter->rx_ring[i]); + igb_free_rx_resources(&adapter->rx_ring[i]); } /** @@ -1900,9 +2132,9 @@ static void igb_free_all_rx_resources(struct igb_adapter *adapter) * @adapter: board private structure * @rx_ring: ring to free buffers from **/ -static void igb_clean_rx_ring(struct igb_adapter *adapter, - struct igb_ring *rx_ring) +static void igb_clean_rx_ring(struct igb_ring *rx_ring) { + struct igb_adapter *adapter = rx_ring->adapter; struct igb_buffer *buffer_info; struct pci_dev *pdev = adapter->pdev; unsigned long size; @@ -1930,20 +2162,17 @@ static void igb_clean_rx_ring(struct igb_adapter *adapter, buffer_info->skb = NULL; } if (buffer_info->page) { - pci_unmap_page(pdev, buffer_info->page_dma, - PAGE_SIZE, PCI_DMA_FROMDEVICE); + if (buffer_info->page_dma) + pci_unmap_page(pdev, buffer_info->page_dma, + PAGE_SIZE / 2, + PCI_DMA_FROMDEVICE); put_page(buffer_info->page); buffer_info->page = NULL; buffer_info->page_dma = 0; + buffer_info->page_offset = 0; } } - /* there also may be some cached data from a chained receive */ - if (rx_ring->pending_skb) { - dev_kfree_skb(rx_ring->pending_skb); - rx_ring->pending_skb = NULL; - } - size = sizeof(struct igb_buffer) * rx_ring->count; memset(rx_ring->buffer_info, 0, size); @@ -1966,7 +2195,7 @@ static void igb_clean_all_rx_rings(struct igb_adapter *adapter) int i; for (i = 0; i < adapter->num_rx_queues; i++) - igb_clean_rx_ring(adapter, &adapter->rx_ring[i]); + igb_clean_rx_ring(&adapter->rx_ring[i]); } /** @@ -2015,19 +2244,22 @@ static void igb_set_multi(struct net_device *netdev) rctl = rd32(E1000_RCTL); - if (netdev->flags & IFF_PROMISC) + if (netdev->flags & IFF_PROMISC) { rctl |= (E1000_RCTL_UPE | E1000_RCTL_MPE); - else if (netdev->flags & IFF_ALLMULTI) { - rctl |= E1000_RCTL_MPE; - rctl &= ~E1000_RCTL_UPE; - } else - rctl &= ~(E1000_RCTL_UPE | E1000_RCTL_MPE); - + rctl &= ~E1000_RCTL_VFE; + } else { + if (netdev->flags & IFF_ALLMULTI) { + rctl |= E1000_RCTL_MPE; + rctl &= ~E1000_RCTL_UPE; + } else + rctl &= ~(E1000_RCTL_UPE | E1000_RCTL_MPE); + rctl |= E1000_RCTL_VFE; + } wr32(E1000_RCTL, rctl); if (!netdev->mc_count) { /* nothing to program, so clear mc list */ - igb_update_mc_addr_list(hw, NULL, 0, 1, + igb_update_mc_addr_list_82575(hw, NULL, 0, 1, mac->rar_entry_count); return; } @@ -2045,7 +2277,8 @@ static void igb_set_multi(struct net_device *netdev) memcpy(mta_list + (i*ETH_ALEN), mc_ptr->dmi_addr, ETH_ALEN); mc_ptr = mc_ptr->next; } - igb_update_mc_addr_list(hw, mta_list, i, 1, mac->rar_entry_count); + igb_update_mc_addr_list_82575(hw, mta_list, i, 1, + mac->rar_entry_count); kfree(mta_list); } @@ -2135,7 +2368,7 @@ static void igb_watchdog_task(struct work_struct *work) } netif_carrier_on(netdev); - netif_wake_queue(netdev); + netif_tx_wake_all_queues(netdev); if (!test_bit(__IGB_DOWN, &adapter->state)) mod_timer(&adapter->phy_info_timer, @@ -2147,7 +2380,7 @@ static void igb_watchdog_task(struct work_struct *work) adapter->link_duplex = 0; dev_info(&adapter->pdev->dev, "NIC Link is Down\n"); netif_carrier_off(netdev); - netif_stop_queue(netdev); + netif_tx_stop_all_queues(netdev); if (!test_bit(__IGB_DOWN, &adapter->state)) mod_timer(&adapter->phy_info_timer, round_jiffies(jiffies + 2 * HZ)); @@ -2200,38 +2433,60 @@ enum latency_range { }; -static void igb_lower_rx_eitr(struct igb_adapter *adapter, - struct igb_ring *rx_ring) +/** + * igb_update_ring_itr - update the dynamic ITR value based on packet size + * + * Stores a new ITR value based on strictly on packet size. This + * algorithm is less sophisticated than that used in igb_update_itr, + * due to the difficulty of synchronizing statistics across multiple + * receive rings. The divisors and thresholds used by this fuction + * were determined based on theoretical maximum wire speed and testing + * data, in order to minimize response time while increasing bulk + * throughput. + * This functionality is controlled by the InterruptThrottleRate module + * parameter (see igb_param.c) + * NOTE: This function is called only when operating in a multiqueue + * receive environment. + * @rx_ring: pointer to ring + **/ +static void igb_update_ring_itr(struct igb_ring *rx_ring) { - struct e1000_hw *hw = &adapter->hw; - int new_val; + int new_val = rx_ring->itr_val; + int avg_wire_size = 0; + struct igb_adapter *adapter = rx_ring->adapter; - new_val = rx_ring->itr_val / 2; - if (new_val < IGB_MIN_DYN_ITR) - new_val = IGB_MIN_DYN_ITR; + if (!rx_ring->total_packets) + goto clear_counts; /* no packets, so don't do anything */ - if (new_val != rx_ring->itr_val) { - rx_ring->itr_val = new_val; - wr32(rx_ring->itr_register, - 1000000000 / (new_val * 256)); + /* For non-gigabit speeds, just fix the interrupt rate at 4000 + * ints/sec - ITR timer value of 120 ticks. + */ + if (adapter->link_speed != SPEED_1000) { + new_val = 120; + goto set_itr_val; } -} + avg_wire_size = rx_ring->total_bytes / rx_ring->total_packets; -static void igb_raise_rx_eitr(struct igb_adapter *adapter, - struct igb_ring *rx_ring) -{ - struct e1000_hw *hw = &adapter->hw; - int new_val; + /* Add 24 bytes to size to account for CRC, preamble, and gap */ + avg_wire_size += 24; - new_val = rx_ring->itr_val * 2; - if (new_val > IGB_MAX_DYN_ITR) - new_val = IGB_MAX_DYN_ITR; + /* Don't starve jumbo frames */ + avg_wire_size = min(avg_wire_size, 3000); + /* Give a little boost to mid-size frames */ + if ((avg_wire_size > 300) && (avg_wire_size < 1200)) + new_val = avg_wire_size / 3; + else + new_val = avg_wire_size / 2; + +set_itr_val: if (new_val != rx_ring->itr_val) { rx_ring->itr_val = new_val; - wr32(rx_ring->itr_register, - 1000000000 / (new_val * 256)); + rx_ring->set_itr = 1; } +clear_counts: + rx_ring->total_bytes = 0; + rx_ring->total_packets = 0; } /** @@ -2298,8 +2553,7 @@ update_itr_done: return retval; } -static void igb_set_itr(struct igb_adapter *adapter, u16 itr_register, - int rx_only) +static void igb_set_itr(struct igb_adapter *adapter) { u16 current_itr; u32 new_itr = adapter->itr; @@ -2315,26 +2569,23 @@ static void igb_set_itr(struct igb_adapter *adapter, u16 itr_register, adapter->rx_itr, adapter->rx_ring->total_packets, adapter->rx_ring->total_bytes); - /* conservative mode (itr 3) eliminates the lowest_latency setting */ - if (adapter->itr_setting == 3 && adapter->rx_itr == lowest_latency) - adapter->rx_itr = low_latency; - if (!rx_only) { + if (adapter->rx_ring->buddy) { adapter->tx_itr = igb_update_itr(adapter, adapter->tx_itr, adapter->tx_ring->total_packets, adapter->tx_ring->total_bytes); - /* conservative mode (itr 3) eliminates the - * lowest_latency setting */ - if (adapter->itr_setting == 3 && - adapter->tx_itr == lowest_latency) - adapter->tx_itr = low_latency; current_itr = max(adapter->rx_itr, adapter->tx_itr); } else { current_itr = adapter->rx_itr; } + /* conservative mode (itr 3) eliminates the lowest_latency setting */ + if (adapter->itr_setting == 3 && + current_itr == lowest_latency) + current_itr = low_latency; + switch (current_itr) { /* counts and packets in update_itr are dependent on these numbers */ case lowest_latency: @@ -2351,6 +2602,13 @@ static void igb_set_itr(struct igb_adapter *adapter, u16 itr_register, } set_itr_now: + adapter->rx_ring->total_bytes = 0; + adapter->rx_ring->total_packets = 0; + if (adapter->rx_ring->buddy) { + adapter->rx_ring->buddy->total_bytes = 0; + adapter->rx_ring->buddy->total_packets = 0; + } + if (new_itr != adapter->itr) { /* this attempts to bias the interrupt rate towards Bulk * by adding intermediate steps when interrupt rate is @@ -2365,7 +2623,8 @@ set_itr_now: * ends up being correct. */ adapter->itr = new_itr; - adapter->set_itr = 1; + adapter->rx_ring->itr_val = 1000000000 / (new_itr * 256); + adapter->rx_ring->set_itr = 1; } return; @@ -2441,9 +2700,9 @@ static inline int igb_tso_adv(struct igb_adapter *adapter, mss_l4len_idx = (skb_shinfo(skb)->gso_size << E1000_ADVTXD_MSS_SHIFT); mss_l4len_idx |= (l4len << E1000_ADVTXD_L4LEN_SHIFT); - /* Context index must be unique per ring. Luckily, so is the interrupt - * mask value. */ - mss_l4len_idx |= tx_ring->eims_value >> 4; + /* Context index must be unique per ring. */ + if (adapter->flags & IGB_FLAG_NEED_CTX_IDX) + mss_l4len_idx |= tx_ring->queue_index << 4; context_desc->mss_l4len_idx = cpu_to_le32(mss_l4len_idx); context_desc->seqnum_seed = 0; @@ -2507,8 +2766,9 @@ static inline bool igb_tx_csum_adv(struct igb_adapter *adapter, context_desc->type_tucmd_mlhl = cpu_to_le32(tu_cmd); context_desc->seqnum_seed = 0; - context_desc->mss_l4len_idx = - cpu_to_le32(tx_ring->eims_value >> 4); + if (adapter->flags & IGB_FLAG_NEED_CTX_IDX) + context_desc->mss_l4len_idx = + cpu_to_le32(tx_ring->queue_index << 4); buffer_info->time_stamp = jiffies; buffer_info->dma = 0; @@ -2609,9 +2869,10 @@ static inline void igb_tx_queue_adv(struct igb_adapter *adapter, olinfo_status |= E1000_TXD_POPTS_TXSM << 8; } - if (tx_flags & (IGB_TX_FLAGS_CSUM | IGB_TX_FLAGS_TSO | - IGB_TX_FLAGS_VLAN)) - olinfo_status |= tx_ring->eims_value >> 4; + if ((adapter->flags & IGB_FLAG_NEED_CTX_IDX) && + (tx_flags & (IGB_TX_FLAGS_CSUM | IGB_TX_FLAGS_TSO | + IGB_TX_FLAGS_VLAN))) + olinfo_status |= tx_ring->queue_index << 4; olinfo_status |= ((paylen - hdr_len) << E1000_ADVTXD_PAYLEN_SHIFT); @@ -2647,7 +2908,8 @@ static int __igb_maybe_stop_tx(struct net_device *netdev, { struct igb_adapter *adapter = netdev_priv(netdev); - netif_stop_queue(netdev); + netif_stop_subqueue(netdev, tx_ring->queue_index); + /* Herbert's original patch had: * smp_mb__after_netif_stop_queue(); * but since that doesn't exist yet, just open code it. */ @@ -2659,7 +2921,7 @@ static int __igb_maybe_stop_tx(struct net_device *netdev, return -EBUSY; /* A reprieve! */ - netif_start_queue(netdev); + netif_wake_subqueue(netdev, tx_ring->queue_index); ++adapter->restart_queue; return 0; } @@ -2681,7 +2943,6 @@ static int igb_xmit_frame_ring_adv(struct sk_buff *skb, struct igb_adapter *adapter = netdev_priv(netdev); unsigned int tx_flags = 0; unsigned int len; - unsigned long irq_flags; u8 hdr_len = 0; int tso = 0; @@ -2697,10 +2958,6 @@ static int igb_xmit_frame_ring_adv(struct sk_buff *skb, return NETDEV_TX_OK; } - if (!spin_trylock_irqsave(&tx_ring->tx_lock, irq_flags)) - /* Collision - tell upper layer to requeue */ - return NETDEV_TX_LOCKED; - /* need: 1 descriptor per page, * + 2 desc gap to keep tail from touching head, * + 1 desc for skb->data, @@ -2708,21 +2965,23 @@ static int igb_xmit_frame_ring_adv(struct sk_buff *skb, * otherwise try next time */ if (igb_maybe_stop_tx(netdev, tx_ring, skb_shinfo(skb)->nr_frags + 4)) { /* this is a hard error */ - spin_unlock_irqrestore(&tx_ring->tx_lock, irq_flags); return NETDEV_TX_BUSY; } + skb_orphan(skb); if (adapter->vlgrp && vlan_tx_tag_present(skb)) { tx_flags |= IGB_TX_FLAGS_VLAN; tx_flags |= (vlan_tx_tag_get(skb) << IGB_TX_FLAGS_VLAN_SHIFT); } + if (skb->protocol == htons(ETH_P_IP)) + tx_flags |= IGB_TX_FLAGS_IPV4; + tso = skb_is_gso(skb) ? igb_tso_adv(adapter, tx_ring, skb, tx_flags, &hdr_len) : 0; if (tso < 0) { dev_kfree_skb_any(skb); - spin_unlock_irqrestore(&tx_ring->tx_lock, irq_flags); return NETDEV_TX_OK; } @@ -2732,9 +2991,6 @@ static int igb_xmit_frame_ring_adv(struct sk_buff *skb, if (skb->ip_summed == CHECKSUM_PARTIAL) tx_flags |= IGB_TX_FLAGS_CSUM; - if (skb->protocol == htons(ETH_P_IP)) - tx_flags |= IGB_TX_FLAGS_IPV4; - igb_tx_queue_adv(adapter, tx_ring, tx_flags, igb_tx_map_adv(adapter, tx_ring, skb), skb->len, hdr_len); @@ -2744,14 +3000,17 @@ static int igb_xmit_frame_ring_adv(struct sk_buff *skb, /* Make sure there is space in the ring for the next send. */ igb_maybe_stop_tx(netdev, tx_ring, MAX_SKB_FRAGS + 4); - spin_unlock_irqrestore(&tx_ring->tx_lock, irq_flags); return NETDEV_TX_OK; } static int igb_xmit_frame_adv(struct sk_buff *skb, struct net_device *netdev) { struct igb_adapter *adapter = netdev_priv(netdev); - struct igb_ring *tx_ring = &adapter->tx_ring[0]; + struct igb_ring *tx_ring; + + int r_idx = 0; + r_idx = skb->queue_mapping & (IGB_MAX_TX_QUEUES - 1); + tx_ring = adapter->multi_tx_table[r_idx]; /* This goes back to the question of how to logically map a tx queue * to a flow. Right now, performance is impacted slightly negatively @@ -2846,7 +3105,11 @@ static int igb_change_mtu(struct net_device *netdev, int new_mtu) else if (max_frame <= IGB_RXBUFFER_2048) adapter->rx_buffer_len = IGB_RXBUFFER_2048; else - adapter->rx_buffer_len = IGB_RXBUFFER_4096; +#if (PAGE_SIZE / 2) > IGB_RXBUFFER_16384 + adapter->rx_buffer_len = IGB_RXBUFFER_16384; +#else + adapter->rx_buffer_len = PAGE_SIZE / 2; +#endif /* adjust allocation if LPE protects us, and we aren't using SBP */ if ((max_frame == ETH_FRAME_LEN + ETH_FCS_LEN) || (max_frame == MAXIMUM_ETHERNET_VLAN_SIZE)) @@ -3010,26 +3273,19 @@ static irqreturn_t igb_msix_other(int irq, void *data) struct net_device *netdev = data; struct igb_adapter *adapter = netdev_priv(netdev); struct e1000_hw *hw = &adapter->hw; - u32 eicr; - /* disable interrupts from the "other" bit, avoid re-entry */ - wr32(E1000_EIMC, E1000_EIMS_OTHER); - - eicr = rd32(E1000_EICR); - - if (eicr & E1000_EIMS_OTHER) { - u32 icr = rd32(E1000_ICR); - /* reading ICR causes bit 31 of EICR to be cleared */ - if (!(icr & E1000_ICR_LSC)) - goto no_link_interrupt; - hw->mac.get_link_status = 1; - /* guard against interrupt when we're going down */ - if (!test_bit(__IGB_DOWN, &adapter->state)) - mod_timer(&adapter->watchdog_timer, jiffies + 1); - } + u32 icr = rd32(E1000_ICR); + /* reading ICR causes bit 31 of EICR to be cleared */ + if (!(icr & E1000_ICR_LSC)) + goto no_link_interrupt; + hw->mac.get_link_status = 1; + /* guard against interrupt when we're going down */ + if (!test_bit(__IGB_DOWN, &adapter->state)) + mod_timer(&adapter->watchdog_timer, jiffies + 1); + no_link_interrupt: wr32(E1000_IMS, E1000_IMS_LSC); - wr32(E1000_EIMS, E1000_EIMS_OTHER); + wr32(E1000_EIMS, adapter->eims_other); return IRQ_HANDLED; } @@ -3040,44 +3296,186 @@ static irqreturn_t igb_msix_tx(int irq, void *data) struct igb_adapter *adapter = tx_ring->adapter; struct e1000_hw *hw = &adapter->hw; - if (!tx_ring->itr_val) - wr32(E1000_EIMC, tx_ring->eims_value); - +#ifdef CONFIG_DCA + if (adapter->flags & IGB_FLAG_DCA_ENABLED) + igb_update_tx_dca(tx_ring); +#endif tx_ring->total_bytes = 0; tx_ring->total_packets = 0; - if (!igb_clean_tx_irq(adapter, tx_ring)) + + /* auto mask will automatically reenable the interrupt when we write + * EICS */ + if (!igb_clean_tx_irq(tx_ring)) /* Ring was not completely cleaned, so fire another interrupt */ wr32(E1000_EICS, tx_ring->eims_value); - - if (!tx_ring->itr_val) + else wr32(E1000_EIMS, tx_ring->eims_value); + return IRQ_HANDLED; } +static void igb_write_itr(struct igb_ring *ring) +{ + struct e1000_hw *hw = &ring->adapter->hw; + if ((ring->adapter->itr_setting & 3) && ring->set_itr) { + switch (hw->mac.type) { + case e1000_82576: + wr32(ring->itr_register, + ring->itr_val | + 0x80000000); + break; + default: + wr32(ring->itr_register, + ring->itr_val | + (ring->itr_val << 16)); + break; + } + ring->set_itr = 0; + } +} + static irqreturn_t igb_msix_rx(int irq, void *data) { struct igb_ring *rx_ring = data; struct igb_adapter *adapter = rx_ring->adapter; - struct e1000_hw *hw = &adapter->hw; - if (!rx_ring->itr_val) - wr32(E1000_EIMC, rx_ring->eims_value); + /* Write the ITR value calculated at the end of the + * previous interrupt. + */ + + igb_write_itr(rx_ring); - if (netif_rx_schedule_prep(adapter->netdev, &rx_ring->napi)) { - rx_ring->total_bytes = 0; - rx_ring->total_packets = 0; - rx_ring->no_itr_adjust = 0; + if (netif_rx_schedule_prep(adapter->netdev, &rx_ring->napi)) __netif_rx_schedule(adapter->netdev, &rx_ring->napi); - } else { - if (!rx_ring->no_itr_adjust) { - igb_lower_rx_eitr(adapter, rx_ring); - rx_ring->no_itr_adjust = 1; + +#ifdef CONFIG_DCA + if (adapter->flags & IGB_FLAG_DCA_ENABLED) + igb_update_rx_dca(rx_ring); +#endif + return IRQ_HANDLED; +} + +#ifdef CONFIG_DCA +static void igb_update_rx_dca(struct igb_ring *rx_ring) +{ + u32 dca_rxctrl; + struct igb_adapter *adapter = rx_ring->adapter; + struct e1000_hw *hw = &adapter->hw; + int cpu = get_cpu(); + int q = rx_ring - adapter->rx_ring; + + if (rx_ring->cpu != cpu) { + dca_rxctrl = rd32(E1000_DCA_RXCTRL(q)); + if (hw->mac.type == e1000_82576) { + dca_rxctrl &= ~E1000_DCA_RXCTRL_CPUID_MASK_82576; + dca_rxctrl |= dca_get_tag(cpu) << + E1000_DCA_RXCTRL_CPUID_SHIFT; + } else { + dca_rxctrl &= ~E1000_DCA_RXCTRL_CPUID_MASK; + dca_rxctrl |= dca_get_tag(cpu); } + dca_rxctrl |= E1000_DCA_RXCTRL_DESC_DCA_EN; + dca_rxctrl |= E1000_DCA_RXCTRL_HEAD_DCA_EN; + dca_rxctrl |= E1000_DCA_RXCTRL_DATA_DCA_EN; + wr32(E1000_DCA_RXCTRL(q), dca_rxctrl); + rx_ring->cpu = cpu; } + put_cpu(); +} - return IRQ_HANDLED; +static void igb_update_tx_dca(struct igb_ring *tx_ring) +{ + u32 dca_txctrl; + struct igb_adapter *adapter = tx_ring->adapter; + struct e1000_hw *hw = &adapter->hw; + int cpu = get_cpu(); + int q = tx_ring - adapter->tx_ring; + + if (tx_ring->cpu != cpu) { + dca_txctrl = rd32(E1000_DCA_TXCTRL(q)); + if (hw->mac.type == e1000_82576) { + dca_txctrl &= ~E1000_DCA_TXCTRL_CPUID_MASK_82576; + dca_txctrl |= dca_get_tag(cpu) << + E1000_DCA_TXCTRL_CPUID_SHIFT; + } else { + dca_txctrl &= ~E1000_DCA_TXCTRL_CPUID_MASK; + dca_txctrl |= dca_get_tag(cpu); + } + dca_txctrl |= E1000_DCA_TXCTRL_DESC_DCA_EN; + wr32(E1000_DCA_TXCTRL(q), dca_txctrl); + tx_ring->cpu = cpu; + } + put_cpu(); +} + +static void igb_setup_dca(struct igb_adapter *adapter) +{ + int i; + + if (!(adapter->flags & IGB_FLAG_DCA_ENABLED)) + return; + + for (i = 0; i < adapter->num_tx_queues; i++) { + adapter->tx_ring[i].cpu = -1; + igb_update_tx_dca(&adapter->tx_ring[i]); + } + for (i = 0; i < adapter->num_rx_queues; i++) { + adapter->rx_ring[i].cpu = -1; + igb_update_rx_dca(&adapter->rx_ring[i]); + } +} + +static int __igb_notify_dca(struct device *dev, void *data) +{ + struct net_device *netdev = dev_get_drvdata(dev); + struct igb_adapter *adapter = netdev_priv(netdev); + struct e1000_hw *hw = &adapter->hw; + unsigned long event = *(unsigned long *)data; + + if (!(adapter->flags & IGB_FLAG_HAS_DCA)) + goto out; + + switch (event) { + case DCA_PROVIDER_ADD: + /* if already enabled, don't do it again */ + if (adapter->flags & IGB_FLAG_DCA_ENABLED) + break; + adapter->flags |= IGB_FLAG_DCA_ENABLED; + /* Always use CB2 mode, difference is masked + * in the CB driver. */ + wr32(E1000_DCA_CTRL, 2); + if (dca_add_requester(dev) == 0) { + dev_info(&adapter->pdev->dev, "DCA enabled\n"); + igb_setup_dca(adapter); + break; + } + /* Fall Through since DCA is disabled. */ + case DCA_PROVIDER_REMOVE: + if (adapter->flags & IGB_FLAG_DCA_ENABLED) { + /* without this a class_device is left + * hanging around in the sysfs model */ + dca_remove_requester(dev); + dev_info(&adapter->pdev->dev, "DCA disabled\n"); + adapter->flags &= ~IGB_FLAG_DCA_ENABLED; + wr32(E1000_DCA_CTRL, 1); + } + break; + } +out: + return 0; } +static int igb_notify_dca(struct notifier_block *nb, unsigned long event, + void *p) +{ + int ret_val; + + ret_val = driver_for_each_device(&igb_driver.driver, NULL, &event, + __igb_notify_dca); + + return ret_val ? NOTIFY_BAD : NOTIFY_DONE; +} +#endif /* CONFIG_DCA */ /** * igb_intr_msi - Interrupt Handler @@ -3088,34 +3486,19 @@ static irqreturn_t igb_intr_msi(int irq, void *data) { struct net_device *netdev = data; struct igb_adapter *adapter = netdev_priv(netdev); - struct napi_struct *napi = &adapter->napi; struct e1000_hw *hw = &adapter->hw; /* read ICR disables interrupts using IAM */ u32 icr = rd32(E1000_ICR); - /* Write the ITR value calculated at the end of the - * previous interrupt. - */ - if (adapter->set_itr) { - wr32(E1000_ITR, - 1000000000 / (adapter->itr * 256)); - adapter->set_itr = 0; - } + igb_write_itr(adapter->rx_ring); - /* read ICR disables interrupts using IAM */ if (icr & (E1000_ICR_RXSEQ | E1000_ICR_LSC)) { hw->mac.get_link_status = 1; if (!test_bit(__IGB_DOWN, &adapter->state)) mod_timer(&adapter->watchdog_timer, jiffies + 1); } - if (netif_rx_schedule_prep(netdev, napi)) { - adapter->tx_ring->total_bytes = 0; - adapter->tx_ring->total_packets = 0; - adapter->rx_ring->total_bytes = 0; - adapter->rx_ring->total_packets = 0; - __netif_rx_schedule(netdev, napi); - } + netif_rx_schedule(netdev, &adapter->rx_ring[0].napi); return IRQ_HANDLED; } @@ -3129,7 +3512,6 @@ static irqreturn_t igb_intr(int irq, void *data) { struct net_device *netdev = data; struct igb_adapter *adapter = netdev_priv(netdev); - struct napi_struct *napi = &adapter->napi; struct e1000_hw *hw = &adapter->hw; /* Interrupt Auto-Mask...upon reading ICR, interrupts are masked. No * need for the IMC write */ @@ -3138,14 +3520,7 @@ static irqreturn_t igb_intr(int irq, void *data) if (!icr) return IRQ_NONE; /* Not our interrupt */ - /* Write the ITR value calculated at the end of the - * previous interrupt. - */ - if (adapter->set_itr) { - wr32(E1000_ITR, - 1000000000 / (adapter->itr * 256)); - adapter->set_itr = 0; - } + igb_write_itr(adapter->rx_ring); /* IMS will not auto-mask if INT_ASSERTED is not set, and if it is * not set, then the adapter didn't send an interrupt */ @@ -3161,57 +3536,41 @@ static irqreturn_t igb_intr(int irq, void *data) mod_timer(&adapter->watchdog_timer, jiffies + 1); } - if (netif_rx_schedule_prep(netdev, napi)) { - adapter->tx_ring->total_bytes = 0; - adapter->rx_ring->total_bytes = 0; - adapter->tx_ring->total_packets = 0; - adapter->rx_ring->total_packets = 0; - __netif_rx_schedule(netdev, napi); - } + netif_rx_schedule(netdev, &adapter->rx_ring[0].napi); return IRQ_HANDLED; } /** - * igb_clean - NAPI Rx polling callback - * @adapter: board private structure + * igb_poll - NAPI Rx polling callback + * @napi: napi polling structure + * @budget: count of how many packets we should handle **/ -static int igb_clean(struct napi_struct *napi, int budget) +static int igb_poll(struct napi_struct *napi, int budget) { - struct igb_adapter *adapter = container_of(napi, struct igb_adapter, - napi); + struct igb_ring *rx_ring = container_of(napi, struct igb_ring, napi); + struct igb_adapter *adapter = rx_ring->adapter; struct net_device *netdev = adapter->netdev; - int tx_clean_complete = 1, work_done = 0; - int i; - - /* Must NOT use netdev_priv macro here. */ - adapter = netdev->priv; + int tx_clean_complete, work_done = 0; - /* Keep link state information with original netdev */ - if (!netif_carrier_ok(netdev)) - goto quit_polling; - - /* igb_clean is called per-cpu. This lock protects tx_ring[i] from - * being cleaned by multiple cpus simultaneously. A failure obtaining - * the lock means tx_ring[i] is currently being cleaned anyway. */ - for (i = 0; i < adapter->num_tx_queues; i++) { - if (spin_trylock(&adapter->tx_ring[i].tx_clean_lock)) { - tx_clean_complete &= igb_clean_tx_irq(adapter, - &adapter->tx_ring[i]); - spin_unlock(&adapter->tx_ring[i].tx_clean_lock); - } - } + /* this poll routine only supports one tx and one rx queue */ +#ifdef CONFIG_DCA + if (adapter->flags & IGB_FLAG_DCA_ENABLED) + igb_update_tx_dca(&adapter->tx_ring[0]); +#endif + tx_clean_complete = igb_clean_tx_irq(&adapter->tx_ring[0]); - for (i = 0; i < adapter->num_rx_queues; i++) - igb_clean_rx_irq_adv(adapter, &adapter->rx_ring[i], &work_done, - adapter->rx_ring[i].napi.weight); +#ifdef CONFIG_DCA + if (adapter->flags & IGB_FLAG_DCA_ENABLED) + igb_update_rx_dca(&adapter->rx_ring[0]); +#endif + igb_clean_rx_irq_adv(&adapter->rx_ring[0], &work_done, budget); /* If no Tx and not enough Rx work done, exit the polling mode */ if ((tx_clean_complete && (work_done < budget)) || !netif_running(netdev)) { -quit_polling: if (adapter->itr_setting & 3) - igb_set_itr(adapter, E1000_ITR, false); + igb_set_itr(adapter); netif_rx_complete(netdev, napi); if (!test_bit(__IGB_DOWN, &adapter->state)) igb_irq_enable(adapter); @@ -3233,7 +3592,11 @@ static int igb_clean_rx_ring_msix(struct napi_struct *napi, int budget) if (!netif_carrier_ok(netdev)) goto quit_polling; - igb_clean_rx_irq_adv(adapter, rx_ring, &work_done, budget); +#ifdef CONFIG_DCA + if (adapter->flags & IGB_FLAG_DCA_ENABLED) + igb_update_rx_dca(rx_ring); +#endif + igb_clean_rx_irq_adv(rx_ring, &work_done, budget); /* If not enough Rx work done, exit the polling mode */ @@ -3241,16 +3604,16 @@ static int igb_clean_rx_ring_msix(struct napi_struct *napi, int budget) quit_polling: netif_rx_complete(netdev, napi); - wr32(E1000_EIMS, rx_ring->eims_value); - if ((adapter->itr_setting & 3) && !rx_ring->no_itr_adjust && - (rx_ring->total_packets > IGB_DYN_ITR_PACKET_THRESHOLD)) { - int mean_size = rx_ring->total_bytes / - rx_ring->total_packets; - if (mean_size < IGB_DYN_ITR_LENGTH_LOW) - igb_raise_rx_eitr(adapter, rx_ring); - else if (mean_size > IGB_DYN_ITR_LENGTH_HIGH) - igb_lower_rx_eitr(adapter, rx_ring); + if (adapter->itr_setting & 3) { + if (adapter->num_rx_queues == 1) + igb_set_itr(adapter); + else + igb_update_ring_itr(rx_ring); } + + if (!test_bit(__IGB_DOWN, &adapter->state)) + wr32(E1000_EIMS, rx_ring->eims_value); + return 0; } @@ -3268,11 +3631,11 @@ static inline u32 get_head(struct igb_ring *tx_ring) * @adapter: board private structure * returns true if ring is completely cleaned **/ -static bool igb_clean_tx_irq(struct igb_adapter *adapter, - struct igb_ring *tx_ring) +static bool igb_clean_tx_irq(struct igb_ring *tx_ring) { - struct net_device *netdev = adapter->netdev; + struct igb_adapter *adapter = tx_ring->adapter; struct e1000_hw *hw = &adapter->hw; + struct net_device *netdev = adapter->netdev; struct e1000_tx_desc *tx_desc; struct igb_buffer *buffer_info; struct sk_buff *skb; @@ -3334,9 +3697,9 @@ done_cleaning: * sees the new next_to_clean. */ smp_mb(); - if (netif_queue_stopped(netdev) && + if (__netif_subqueue_stopped(netdev, tx_ring->queue_index) && !(test_bit(__IGB_DOWN, &adapter->state))) { - netif_wake_queue(netdev); + netif_wake_subqueue(netdev, tx_ring->queue_index); ++adapter->restart_queue; } } @@ -3355,7 +3718,7 @@ done_cleaning: /* detected Tx unit hang */ dev_err(&adapter->pdev->dev, "Detected Tx Unit Hang\n" - " Tx Queue <%lu>\n" + " Tx Queue <%d>\n" " TDH <%x>\n" " TDT <%x>\n" " next_to_use <%x>\n" @@ -3365,8 +3728,7 @@ done_cleaning: " time_stamp <%lx>\n" " jiffies <%lx>\n" " desc.status <%x>\n", - (unsigned long)((tx_ring - adapter->tx_ring) / - sizeof(struct igb_ring)), + tx_ring->queue_index, readl(adapter->hw.hw_addr + tx_ring->head), readl(adapter->hw.hw_addr + tx_ring->tail), tx_ring->next_to_use, @@ -3375,33 +3737,87 @@ done_cleaning: tx_ring->buffer_info[i].time_stamp, jiffies, tx_desc->upper.fields.status); - netif_stop_queue(netdev); + netif_stop_subqueue(netdev, tx_ring->queue_index); } } tx_ring->total_bytes += total_bytes; tx_ring->total_packets += total_packets; + tx_ring->tx_stats.bytes += total_bytes; + tx_ring->tx_stats.packets += total_packets; adapter->net_stats.tx_bytes += total_bytes; adapter->net_stats.tx_packets += total_packets; return retval; } +#ifdef CONFIG_IGB_LRO + /** + * igb_get_skb_hdr - helper function for LRO header processing + * @skb: pointer to sk_buff to be added to LRO packet + * @iphdr: pointer to ip header structure + * @tcph: pointer to tcp header structure + * @hdr_flags: pointer to header flags + * @priv: pointer to the receive descriptor for the current sk_buff + **/ +static int igb_get_skb_hdr(struct sk_buff *skb, void **iphdr, void **tcph, + u64 *hdr_flags, void *priv) +{ + union e1000_adv_rx_desc *rx_desc = priv; + u16 pkt_type = rx_desc->wb.lower.lo_dword.pkt_info & + (E1000_RXDADV_PKTTYPE_IPV4 | E1000_RXDADV_PKTTYPE_TCP); + + /* Verify that this is a valid IPv4 TCP packet */ + if (pkt_type != (E1000_RXDADV_PKTTYPE_IPV4 | + E1000_RXDADV_PKTTYPE_TCP)) + return -1; + + /* Set network headers */ + skb_reset_network_header(skb); + skb_set_transport_header(skb, ip_hdrlen(skb)); + *iphdr = ip_hdr(skb); + *tcph = tcp_hdr(skb); + *hdr_flags = LRO_IPV4 | LRO_TCP; + + return 0; + +} +#endif /* CONFIG_IGB_LRO */ /** * igb_receive_skb - helper function to handle rx indications - * @adapter: board private structure + * @ring: pointer to receive ring receving this packet * @status: descriptor status field as written by hardware * @vlan: descriptor vlan field as written by hardware (no le/be conversion) * @skb: pointer to sk_buff to be indicated to stack **/ -static void igb_receive_skb(struct igb_adapter *adapter, u8 status, __le16 vlan, - struct sk_buff *skb) +static void igb_receive_skb(struct igb_ring *ring, u8 status, + union e1000_adv_rx_desc * rx_desc, + struct sk_buff *skb) { - if (adapter->vlgrp && (status & E1000_RXD_STAT_VP)) - vlan_hwaccel_receive_skb(skb, adapter->vlgrp, - le16_to_cpu(vlan) & - E1000_RXD_SPC_VLAN_MASK); - else - netif_receive_skb(skb); + struct igb_adapter * adapter = ring->adapter; + bool vlan_extracted = (adapter->vlgrp && (status & E1000_RXD_STAT_VP)); + +#ifdef CONFIG_IGB_LRO + if (adapter->netdev->features & NETIF_F_LRO && + skb->ip_summed == CHECKSUM_UNNECESSARY) { + if (vlan_extracted) + lro_vlan_hwaccel_receive_skb(&ring->lro_mgr, skb, + adapter->vlgrp, + le16_to_cpu(rx_desc->wb.upper.vlan), + rx_desc); + else + lro_receive_skb(&ring->lro_mgr,skb, rx_desc); + ring->lro_used = 1; + } else { +#endif + if (vlan_extracted) + vlan_hwaccel_receive_skb(skb, adapter->vlgrp, + le16_to_cpu(rx_desc->wb.upper.vlan)); + else + + netif_receive_skb(skb); +#ifdef CONFIG_IGB_LRO + } +#endif } @@ -3427,16 +3843,16 @@ static inline void igb_rx_checksum_adv(struct igb_adapter *adapter, adapter->hw_csum_good++; } -static bool igb_clean_rx_irq_adv(struct igb_adapter *adapter, - struct igb_ring *rx_ring, - int *work_done, int budget) +static bool igb_clean_rx_irq_adv(struct igb_ring *rx_ring, + int *work_done, int budget) { + struct igb_adapter *adapter = rx_ring->adapter; struct net_device *netdev = adapter->netdev; struct pci_dev *pdev = adapter->pdev; union e1000_adv_rx_desc *rx_desc , *next_rxd; struct igb_buffer *buffer_info , *next_buffer; struct sk_buff *skb; - unsigned int i, j; + unsigned int i; u32 length, hlen, staterr; bool cleaned = false; int cleaned_count = 0; @@ -3466,64 +3882,48 @@ static bool igb_clean_rx_irq_adv(struct igb_adapter *adapter, cleaned = true; cleaned_count++; - if (rx_ring->pending_skb != NULL) { - skb = rx_ring->pending_skb; - rx_ring->pending_skb = NULL; - j = rx_ring->pending_skb_page; - } else { - skb = buffer_info->skb; - prefetch(skb->data - NET_IP_ALIGN); - buffer_info->skb = NULL; - if (hlen) { - pci_unmap_single(pdev, buffer_info->dma, - adapter->rx_ps_hdr_size + - NET_IP_ALIGN, - PCI_DMA_FROMDEVICE); - skb_put(skb, hlen); - } else { - pci_unmap_single(pdev, buffer_info->dma, - adapter->rx_buffer_len + - NET_IP_ALIGN, - PCI_DMA_FROMDEVICE); - skb_put(skb, length); - goto send_up; - } - j = 0; + skb = buffer_info->skb; + prefetch(skb->data - NET_IP_ALIGN); + buffer_info->skb = NULL; + if (!adapter->rx_ps_hdr_size) { + pci_unmap_single(pdev, buffer_info->dma, + adapter->rx_buffer_len + + NET_IP_ALIGN, + PCI_DMA_FROMDEVICE); + skb_put(skb, length); + goto send_up; + } + + if (!skb_shinfo(skb)->nr_frags) { + pci_unmap_single(pdev, buffer_info->dma, + adapter->rx_ps_hdr_size + + NET_IP_ALIGN, + PCI_DMA_FROMDEVICE); + skb_put(skb, hlen); } - while (length) { + if (length) { pci_unmap_page(pdev, buffer_info->page_dma, - PAGE_SIZE, PCI_DMA_FROMDEVICE); + PAGE_SIZE / 2, PCI_DMA_FROMDEVICE); buffer_info->page_dma = 0; - skb_fill_page_desc(skb, j, buffer_info->page, - 0, length); - buffer_info->page = NULL; + + skb_fill_page_desc(skb, skb_shinfo(skb)->nr_frags++, + buffer_info->page, + buffer_info->page_offset, + length); + + if ((adapter->rx_buffer_len > (PAGE_SIZE / 2)) || + (page_count(buffer_info->page) != 1)) + buffer_info->page = NULL; + else + get_page(buffer_info->page); skb->len += length; skb->data_len += length; - skb->truesize += length; - rx_desc->wb.upper.status_error = 0; - if (staterr & E1000_RXD_STAT_EOP) - break; - j++; - cleaned_count++; - i++; - if (i == rx_ring->count) - i = 0; - - buffer_info = &rx_ring->buffer_info[i]; - rx_desc = E1000_RX_DESC_ADV(*rx_ring, i); - staterr = le32_to_cpu(rx_desc->wb.upper.status_error); - length = le16_to_cpu(rx_desc->wb.upper.length); - if (!(staterr & E1000_RXD_STAT_DD)) { - rx_ring->pending_skb = skb; - rx_ring->pending_skb_page = j; - goto out; - } + skb->truesize += length; } send_up: - pskb_trim(skb, skb->len - 4); i++; if (i == rx_ring->count) i = 0; @@ -3531,11 +3931,16 @@ send_up: prefetch(next_rxd); next_buffer = &rx_ring->buffer_info[i]; + if (!(staterr & E1000_RXD_STAT_EOP)) { + buffer_info->skb = xchg(&next_buffer->skb, skb); + buffer_info->dma = xchg(&next_buffer->dma, 0); + goto next_desc; + } + if (staterr & E1000_RXDEXT_ERR_FRAME_ERR_MASK) { dev_kfree_skb_irq(skb); goto next_desc; } - rx_ring->no_itr_adjust |= (staterr & E1000_RXD_STAT_DYNINT); total_bytes += skb->len; total_packets++; @@ -3544,7 +3949,7 @@ send_up: skb->protocol = eth_type_trans(skb, netdev); - igb_receive_skb(adapter, staterr, rx_desc->wb.upper.vlan, skb); + igb_receive_skb(rx_ring, staterr, rx_desc, skb); netdev->last_rx = jiffies; @@ -3553,8 +3958,7 @@ next_desc: /* return some buffers to hardware, one at a time is too slow */ if (cleaned_count >= IGB_RX_BUFFER_WRITE) { - igb_alloc_rx_buffers_adv(adapter, rx_ring, - cleaned_count); + igb_alloc_rx_buffers_adv(rx_ring, cleaned_count); cleaned_count = 0; } @@ -3564,12 +3968,19 @@ next_desc: staterr = le32_to_cpu(rx_desc->wb.upper.status_error); } -out: + rx_ring->next_to_clean = i; cleaned_count = IGB_DESC_UNUSED(rx_ring); +#ifdef CONFIG_IGB_LRO + if (rx_ring->lro_used) { + lro_flush_all(&rx_ring->lro_mgr); + rx_ring->lro_used = 0; + } +#endif + if (cleaned_count) - igb_alloc_rx_buffers_adv(adapter, rx_ring, cleaned_count); + igb_alloc_rx_buffers_adv(rx_ring, cleaned_count); rx_ring->total_packets += total_packets; rx_ring->total_bytes += total_bytes; @@ -3585,10 +3996,10 @@ out: * igb_alloc_rx_buffers_adv - Replace used receive buffers; packet split * @adapter: address of board private structure **/ -static void igb_alloc_rx_buffers_adv(struct igb_adapter *adapter, - struct igb_ring *rx_ring, +static void igb_alloc_rx_buffers_adv(struct igb_ring *rx_ring, int cleaned_count) { + struct igb_adapter *adapter = rx_ring->adapter; struct net_device *netdev = adapter->netdev; struct pci_dev *pdev = adapter->pdev; union e1000_adv_rx_desc *rx_desc; @@ -3602,16 +4013,22 @@ static void igb_alloc_rx_buffers_adv(struct igb_adapter *adapter, while (cleaned_count--) { rx_desc = E1000_RX_DESC_ADV(*rx_ring, i); - if (adapter->rx_ps_hdr_size && !buffer_info->page) { - buffer_info->page = alloc_page(GFP_ATOMIC); + if (adapter->rx_ps_hdr_size && !buffer_info->page_dma) { if (!buffer_info->page) { - adapter->alloc_rx_buff_failed++; - goto no_buffers; + buffer_info->page = alloc_page(GFP_ATOMIC); + if (!buffer_info->page) { + adapter->alloc_rx_buff_failed++; + goto no_buffers; + } + buffer_info->page_offset = 0; + } else { + buffer_info->page_offset ^= PAGE_SIZE / 2; } buffer_info->page_dma = pci_map_page(pdev, buffer_info->page, - 0, PAGE_SIZE, + buffer_info->page_offset, + PAGE_SIZE / 2, PCI_DMA_FROMDEVICE); } @@ -3746,7 +4163,6 @@ static void igb_vlan_rx_register(struct net_device *netdev, /* enable VLAN receive filtering */ rctl = rd32(E1000_RCTL); - rctl |= E1000_RCTL_VFE; rctl &= ~E1000_RCTL_CFIEN; wr32(E1000_RCTL, rctl); igb_update_mng_vlan(adapter); @@ -3758,10 +4174,6 @@ static void igb_vlan_rx_register(struct net_device *netdev, ctrl &= ~E1000_CTRL_VME; wr32(E1000_CTRL, ctrl); - /* disable VLAN filtering */ - rctl = rd32(E1000_RCTL); - rctl &= ~E1000_RCTL_VFE; - wr32(E1000_RCTL, rctl); if (adapter->mng_vlan_id != (u16)IGB_MNG_VLAN_NONE) { igb_vlan_rx_kill_vid(netdev, adapter->mng_vlan_id); adapter->mng_vlan_id = IGB_MNG_VLAN_NONE; @@ -3878,7 +4290,7 @@ static int igb_suspend(struct pci_dev *pdev, pm_message_t state) struct net_device *netdev = pci_get_drvdata(pdev); struct igb_adapter *adapter = netdev_priv(netdev); struct e1000_hw *hw = &adapter->hw; - u32 ctrl, ctrl_ext, rctl, status; + u32 ctrl, rctl, status; u32 wufc = adapter->wol; #ifdef CONFIG_PM int retval = 0; @@ -3886,11 +4298,12 @@ static int igb_suspend(struct pci_dev *pdev, pm_message_t state) netif_device_detach(netdev); - if (netif_running(netdev)) { - WARN_ON(test_bit(__IGB_RESETTING, &adapter->state)); - igb_down(adapter); - igb_free_irq(adapter); - } + if (netif_running(netdev)) + igb_close(netdev); + + igb_reset_interrupt_capability(adapter); + + igb_free_queues(adapter); #ifdef CONFIG_PM retval = pci_save_state(pdev); @@ -3921,33 +4334,24 @@ static int igb_suspend(struct pci_dev *pdev, pm_message_t state) ctrl |= E1000_CTRL_ADVD3WUC; wr32(E1000_CTRL, ctrl); - if (adapter->hw.phy.media_type == e1000_media_type_fiber || - adapter->hw.phy.media_type == - e1000_media_type_internal_serdes) { - /* keep the laser running in D3 */ - ctrl_ext = rd32(E1000_CTRL_EXT); - ctrl_ext |= E1000_CTRL_EXT_SDP7_DATA; - wr32(E1000_CTRL_EXT, ctrl_ext); - } - /* Allow time for pending master requests to run */ igb_disable_pcie_master(&adapter->hw); wr32(E1000_WUC, E1000_WUC_PME_EN); wr32(E1000_WUFC, wufc); - pci_enable_wake(pdev, PCI_D3hot, 1); - pci_enable_wake(pdev, PCI_D3cold, 1); } else { wr32(E1000_WUC, 0); wr32(E1000_WUFC, 0); - pci_enable_wake(pdev, PCI_D3hot, 0); - pci_enable_wake(pdev, PCI_D3cold, 0); } - /* make sure adapter isn't asleep if manageability is enabled */ - if (adapter->en_mng_pt) { + /* make sure adapter isn't asleep if manageability/wol is enabled */ + if (wufc || adapter->en_mng_pt) { pci_enable_wake(pdev, PCI_D3hot, 1); pci_enable_wake(pdev, PCI_D3cold, 1); + } else { + igb_shutdown_fiber_serdes_link_82575(hw); + pci_enable_wake(pdev, PCI_D3hot, 0); + pci_enable_wake(pdev, PCI_D3cold, 0); } /* Release control of h/w to f/w. If f/w is AMT enabled, this @@ -3971,7 +4375,11 @@ static int igb_resume(struct pci_dev *pdev) pci_set_power_state(pdev, PCI_D0); pci_restore_state(pdev); - err = pci_enable_device(pdev); + + if (adapter->need_ioport) + err = pci_enable_device(pdev); + else + err = pci_enable_device_mem(pdev); if (err) { dev_err(&pdev->dev, "igb: Cannot enable PCI device from suspend\n"); @@ -3982,10 +4390,11 @@ static int igb_resume(struct pci_dev *pdev) pci_enable_wake(pdev, PCI_D3hot, 0); pci_enable_wake(pdev, PCI_D3cold, 0); - if (netif_running(netdev)) { - err = igb_request_irq(adapter); - if (err) - return err; + igb_set_interrupt_capability(adapter); + + if (igb_alloc_queues(adapter)) { + dev_err(&pdev->dev, "Unable to allocate memory for queues\n"); + return -ENOMEM; } /* e1000_power_up_phy(adapter); */ @@ -3993,10 +4402,11 @@ static int igb_resume(struct pci_dev *pdev) igb_reset(adapter); wr32(E1000_WUS, ~0); - igb_init_manageability(adapter); - - if (netif_running(netdev)) - igb_up(adapter); + if (netif_running(netdev)) { + err = igb_open(netdev); + if (err) + return err; + } netif_device_attach(netdev); @@ -4026,14 +4436,17 @@ static void igb_netpoll(struct net_device *netdev) int work_done = 0; igb_irq_disable(adapter); + adapter->flags |= IGB_FLAG_IN_NETPOLL; + for (i = 0; i < adapter->num_tx_queues; i++) - igb_clean_tx_irq(adapter, &adapter->tx_ring[i]); + igb_clean_tx_irq(&adapter->tx_ring[i]); for (i = 0; i < adapter->num_rx_queues; i++) - igb_clean_rx_irq_adv(adapter, &adapter->rx_ring[i], + igb_clean_rx_irq_adv(&adapter->rx_ring[i], &work_done, adapter->rx_ring[i].napi.weight); + adapter->flags &= ~IGB_FLAG_IN_NETPOLL; igb_irq_enable(adapter); } #endif /* CONFIG_NET_POLL_CONTROLLER */ @@ -4074,8 +4487,13 @@ static pci_ers_result_t igb_io_slot_reset(struct pci_dev *pdev) struct net_device *netdev = pci_get_drvdata(pdev); struct igb_adapter *adapter = netdev_priv(netdev); struct e1000_hw *hw = &adapter->hw; + int err; - if (pci_enable_device(pdev)) { + if (adapter->need_ioport) + err = pci_enable_device(pdev); + else + err = pci_enable_device_mem(pdev); + if (err) { dev_err(&pdev->dev, "Cannot re-enable PCI device after reset.\n"); return PCI_ERS_RESULT_DISCONNECT; diff --git a/drivers/net/ipg.c b/drivers/net/ipg.c index 2c03f4e2ccc4..7373dafbb3f7 100644 --- a/drivers/net/ipg.c +++ b/drivers/net/ipg.c @@ -42,7 +42,6 @@ #define ipg_r16(reg) ioread16(ioaddr + (reg)) #define ipg_r8(reg) ioread8(ioaddr + (reg)) -#define JUMBO_FRAME_4k_ONLY enum { netdev_io_size = 128 }; @@ -55,6 +54,14 @@ MODULE_DESCRIPTION("IC Plus IP1000 Gigabit Ethernet Adapter Linux Driver"); MODULE_LICENSE("GPL"); /* + * Defaults + */ +#define IPG_MAX_RXFRAME_SIZE 0x0600 +#define IPG_RXFRAG_SIZE 0x0600 +#define IPG_RXSUPPORT_SIZE 0x0600 +#define IPG_IS_JUMBO false + +/* * Variable record -- index by leading revision/length * Revision/Length(=N*4), Address1, Data1, Address2, Data2,...,AddressN,DataN */ @@ -631,6 +638,7 @@ static void ipg_nic_set_multicast_list(struct net_device *dev) static int ipg_io_config(struct net_device *dev) { + struct ipg_nic_private *sp = netdev_priv(dev); void __iomem *ioaddr = ipg_ioaddr(dev); u32 origmacctrl; u32 restoremacctrl; @@ -670,7 +678,7 @@ static int ipg_io_config(struct net_device *dev) /* Set RECEIVEMODE register. */ ipg_nic_set_multicast_list(dev); - ipg_w16(IPG_MAX_RXFRAME_SIZE, MAX_FRAME_SIZE); + ipg_w16(sp->max_rxframe_size, MAX_FRAME_SIZE); ipg_w8(IPG_RXDMAPOLLPERIOD_VALUE, RX_DMA_POLL_PERIOD); ipg_w8(IPG_RXDMAURGENTTHRESH_VALUE, RX_DMA_URGENT_THRESH); @@ -730,7 +738,7 @@ static int ipg_get_rxbuff(struct net_device *dev, int entry) IPG_DEBUG_MSG("_get_rxbuff\n"); - skb = netdev_alloc_skb(dev, IPG_RXSUPPORT_SIZE + NET_IP_ALIGN); + skb = netdev_alloc_skb(dev, sp->rxsupport_size + NET_IP_ALIGN); if (!skb) { sp->rx_buff[entry] = NULL; return -ENOMEM; @@ -751,7 +759,7 @@ static int ipg_get_rxbuff(struct net_device *dev, int entry) sp->rx_buf_sz, PCI_DMA_FROMDEVICE)); /* Set the RFD fragment length. */ - rxfragsize = IPG_RXFRAG_SIZE; + rxfragsize = sp->rxfrag_size; rxfd->frag_info |= cpu_to_le64((rxfragsize << 48) & IPG_RFI_FRAGLEN); return 0; @@ -1076,8 +1084,6 @@ static int ipg_nic_rxrestore(struct net_device *dev) return 0; } -#ifdef JUMBO_FRAME - /* use jumboindex and jumbosize to control jumbo frame status * initial status is jumboindex=-1 and jumbosize=0 * 1. jumboindex = -1 and jumbosize=0 : previous jumbo frame has been done. @@ -1097,7 +1103,7 @@ enum { FRAME_WITH_START_WITH_END = 11 }; -inline void ipg_nic_rx_free_skb(struct net_device *dev) +static void ipg_nic_rx_free_skb(struct net_device *dev) { struct ipg_nic_private *sp = netdev_priv(dev); unsigned int entry = sp->rx_current % IPG_RFDLIST_LENGTH; @@ -1113,7 +1119,7 @@ inline void ipg_nic_rx_free_skb(struct net_device *dev) } } -inline int ipg_nic_rx_check_frame_type(struct net_device *dev) +static int ipg_nic_rx_check_frame_type(struct net_device *dev) { struct ipg_nic_private *sp = netdev_priv(dev); struct ipg_rx *rxfd = sp->rxd + (sp->rx_current % IPG_RFDLIST_LENGTH); @@ -1126,7 +1132,7 @@ inline int ipg_nic_rx_check_frame_type(struct net_device *dev) return type; } -inline int ipg_nic_rx_check_error(struct net_device *dev) +static int ipg_nic_rx_check_error(struct net_device *dev) { struct ipg_nic_private *sp = netdev_priv(dev); unsigned int entry = sp->rx_current % IPG_RFDLIST_LENGTH; @@ -1209,8 +1215,8 @@ static void ipg_nic_rx_with_start_and_end(struct net_device *dev, /* accept this frame and send to upper layer */ framelen = le64_to_cpu(rxfd->rfs) & IPG_RFS_RXFRAMELEN; - if (framelen > IPG_RXFRAG_SIZE) - framelen = IPG_RXFRAG_SIZE; + if (framelen > sp->rxfrag_size) + framelen = sp->rxfrag_size; skb_put(skb, framelen); skb->protocol = eth_type_trans(skb, dev); @@ -1243,10 +1249,10 @@ static void ipg_nic_rx_with_start(struct net_device *dev, pci_unmap_single(pdev, le64_to_cpu(rxfd->frag_info & ~IPG_RFI_FRAGLEN), sp->rx_buf_sz, PCI_DMA_FROMDEVICE); - skb_put(skb, IPG_RXFRAG_SIZE); + skb_put(skb, sp->rxfrag_size); jumbo->found_start = 1; - jumbo->current_size = IPG_RXFRAG_SIZE; + jumbo->current_size = sp->rxfrag_size; jumbo->skb = skb; sp->rx_buff[entry] = NULL; @@ -1272,11 +1278,7 @@ static void ipg_nic_rx_with_end(struct net_device *dev, framelen = le64_to_cpu(rxfd->rfs) & IPG_RFS_RXFRAMELEN; endframelen = framelen - jumbo->current_size; - /* - if (framelen > IPG_RXFRAG_SIZE) - framelen=IPG_RXFRAG_SIZE; - */ - if (framelen > IPG_RXSUPPORT_SIZE) + if (framelen > sp->rxsupport_size) dev_kfree_skb_irq(jumbo->skb); else { memcpy(skb_put(jumbo->skb, endframelen), @@ -1316,11 +1318,11 @@ static void ipg_nic_rx_no_start_no_end(struct net_device *dev, if (skb) { if (jumbo->found_start) { - jumbo->current_size += IPG_RXFRAG_SIZE; - if (jumbo->current_size <= IPG_RXSUPPORT_SIZE) { + jumbo->current_size += sp->rxfrag_size; + if (jumbo->current_size <= sp->rxsupport_size) { memcpy(skb_put(jumbo->skb, - IPG_RXFRAG_SIZE), - skb->data, IPG_RXFRAG_SIZE); + sp->rxfrag_size), + skb->data, sp->rxfrag_size); } } dev->last_rx = jiffies; @@ -1334,7 +1336,7 @@ static void ipg_nic_rx_no_start_no_end(struct net_device *dev, } } -static int ipg_nic_rx(struct net_device *dev) +static int ipg_nic_rx_jumbo(struct net_device *dev) { struct ipg_nic_private *sp = netdev_priv(dev); unsigned int curr = sp->rx_current; @@ -1382,7 +1384,6 @@ static int ipg_nic_rx(struct net_device *dev) return 0; } -#else static int ipg_nic_rx(struct net_device *dev) { /* Transfer received Ethernet frames to higher network layers. */ @@ -1413,11 +1414,11 @@ static int ipg_nic_rx(struct net_device *dev) /* Check for jumbo frame arrival with too small * RXFRAG_SIZE. */ - if (framelen > IPG_RXFRAG_SIZE) { + if (framelen > sp->rxfrag_size) { IPG_DEBUG_MSG ("RFS FrameLen > allocated fragment size.\n"); - framelen = IPG_RXFRAG_SIZE; + framelen = sp->rxfrag_size; } if ((IPG_DROP_ON_RX_ETH_ERRORS && (le64_to_cpu(rxfd->rfs) & @@ -1556,7 +1557,6 @@ static int ipg_nic_rx(struct net_device *dev) return 0; } -#endif static void ipg_reset_after_host_error(struct work_struct *work) { @@ -1592,9 +1592,9 @@ static irqreturn_t ipg_interrupt_handler(int irq, void *dev_inst) IPG_DEBUG_MSG("_interrupt_handler\n"); -#ifdef JUMBO_FRAME - ipg_nic_rxrestore(dev); -#endif + if (sp->is_jumbo) + ipg_nic_rxrestore(dev); + spin_lock(&sp->lock); /* Get interrupt source information, and acknowledge @@ -1650,7 +1650,10 @@ static irqreturn_t ipg_interrupt_handler(int irq, void *dev_inst) sp->RFDListCheckedCount++; #endif - ipg_nic_rx(dev); + if (sp->is_jumbo) + ipg_nic_rx_jumbo(dev); + else + ipg_nic_rx(dev); } /* If TxDMAComplete interrupt, free used TFDs. */ @@ -1749,7 +1752,7 @@ static int ipg_nic_open(struct net_device *dev) IPG_DEBUG_MSG("_nic_open\n"); - sp->rx_buf_sz = IPG_RXSUPPORT_SIZE; + sp->rx_buf_sz = sp->rxsupport_size; /* Check for interrupt line conflicts, and request interrupt * line for IPG. @@ -1804,13 +1807,10 @@ static int ipg_nic_open(struct net_device *dev) if (ipg_config_autoneg(dev) < 0) printk(KERN_INFO "%s: Auto-negotiation error.\n", dev->name); -#ifdef JUMBO_FRAME /* initialize JUMBO Frame control variable */ sp->jumbo.found_start = 0; sp->jumbo.current_size = 0; sp->jumbo.skb = NULL; - dev->mtu = IPG_TXFRAG_SIZE; -#endif /* Enable transmit and receive operation of the IPG. */ ipg_w32((ipg_r32(MAC_CTRL) | IPG_MC_RX_ENABLE | IPG_MC_TX_ENABLE) & @@ -2119,6 +2119,9 @@ static int ipg_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) static int ipg_nic_change_mtu(struct net_device *dev, int new_mtu) { + struct ipg_nic_private *sp = netdev_priv(dev); + int err; + /* Function to accomodate changes to Maximum Transfer Unit * (or MTU) of IPG NIC. Cannot use default function since * the default will not allow for MTU > 1500 bytes. @@ -2126,16 +2129,33 @@ static int ipg_nic_change_mtu(struct net_device *dev, int new_mtu) IPG_DEBUG_MSG("_nic_change_mtu\n"); - /* Check that the new MTU value is between 68 (14 byte header, 46 - * byte payload, 4 byte FCS) and IPG_MAX_RXFRAME_SIZE, which - * corresponds to the MAXFRAMESIZE register in the IPG. + /* + * Check that the new MTU value is between 68 (14 byte header, 46 byte + * payload, 4 byte FCS) and 10 KB, which is the largest supported MTU. */ - if ((new_mtu < 68) || (new_mtu > IPG_MAX_RXFRAME_SIZE)) + if (new_mtu < 68 || new_mtu > 10240) return -EINVAL; + err = ipg_nic_stop(dev); + if (err) + return err; + dev->mtu = new_mtu; - return 0; + sp->max_rxframe_size = new_mtu; + + sp->rxfrag_size = new_mtu; + if (sp->rxfrag_size > 4088) + sp->rxfrag_size = 4088; + + sp->rxsupport_size = sp->max_rxframe_size; + + if (new_mtu > 0x0600) + sp->is_jumbo = true; + else + sp->is_jumbo = false; + + return ipg_nic_open(dev); } static int ipg_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) @@ -2240,6 +2260,11 @@ static int __devinit ipg_probe(struct pci_dev *pdev, spin_lock_init(&sp->lock); mutex_init(&sp->mii_mutex); + sp->is_jumbo = IPG_IS_JUMBO; + sp->rxfrag_size = IPG_RXFRAG_SIZE; + sp->rxsupport_size = IPG_RXSUPPORT_SIZE; + sp->max_rxframe_size = IPG_MAX_RXFRAME_SIZE; + /* Declare IPG NIC functions for Ethernet device methods. */ dev->open = &ipg_nic_open; diff --git a/drivers/net/ipg.h b/drivers/net/ipg.h index cda53887d4db..e0e718ab4c2e 100644 --- a/drivers/net/ipg.h +++ b/drivers/net/ipg.h @@ -536,83 +536,6 @@ enum ipg_regs { */ #define IPG_FRAMESBETWEENTXDMACOMPLETES 0x1 -#ifdef JUMBO_FRAME - -# ifdef JUMBO_FRAME_SIZE_2K -# define JUMBO_FRAME_SIZE 2048 -# define __IPG_RXFRAG_SIZE 2048 -# else -# ifdef JUMBO_FRAME_SIZE_3K -# define JUMBO_FRAME_SIZE 3072 -# define __IPG_RXFRAG_SIZE 3072 -# else -# ifdef JUMBO_FRAME_SIZE_4K -# define JUMBO_FRAME_SIZE 4096 -# define __IPG_RXFRAG_SIZE 4088 -# else -# ifdef JUMBO_FRAME_SIZE_5K -# define JUMBO_FRAME_SIZE 5120 -# define __IPG_RXFRAG_SIZE 4088 -# else -# ifdef JUMBO_FRAME_SIZE_6K -# define JUMBO_FRAME_SIZE 6144 -# define __IPG_RXFRAG_SIZE 4088 -# else -# ifdef JUMBO_FRAME_SIZE_7K -# define JUMBO_FRAME_SIZE 7168 -# define __IPG_RXFRAG_SIZE 4088 -# else -# ifdef JUMBO_FRAME_SIZE_8K -# define JUMBO_FRAME_SIZE 8192 -# define __IPG_RXFRAG_SIZE 4088 -# else -# ifdef JUMBO_FRAME_SIZE_9K -# define JUMBO_FRAME_SIZE 9216 -# define __IPG_RXFRAG_SIZE 4088 -# else -# ifdef JUMBO_FRAME_SIZE_10K -# define JUMBO_FRAME_SIZE 10240 -# define __IPG_RXFRAG_SIZE 4088 -# else -# define JUMBO_FRAME_SIZE 4096 -# endif -# endif -# endif -# endif -# endif -# endif -# endif -# endif -# endif -#endif - -/* Size of allocated received buffers. Nominally 0x0600. - * Define larger if expecting jumbo frames. - */ -#ifdef JUMBO_FRAME -/* IPG_TXFRAG_SIZE must <= 0x2b00, or TX will crash */ -#define IPG_TXFRAG_SIZE JUMBO_FRAME_SIZE -#endif - -/* Size of allocated received buffers. Nominally 0x0600. - * Define larger if expecting jumbo frames. - */ -#ifdef JUMBO_FRAME -/* 4088 = 4096 - 8 */ -#define IPG_RXFRAG_SIZE __IPG_RXFRAG_SIZE -#define IPG_RXSUPPORT_SIZE IPG_MAX_RXFRAME_SIZE -#else -#define IPG_RXFRAG_SIZE 0x0600 -#define IPG_RXSUPPORT_SIZE IPG_RXFRAG_SIZE -#endif - -/* IPG_MAX_RXFRAME_SIZE <= IPG_RXFRAG_SIZE */ -#ifdef JUMBO_FRAME -#define IPG_MAX_RXFRAME_SIZE JUMBO_FRAME_SIZE -#else -#define IPG_MAX_RXFRAME_SIZE 0x0600 -#endif - #define IPG_RFDLIST_LENGTH 0x100 /* Maximum number of RFDs to process per interrupt. @@ -786,9 +709,11 @@ struct ipg_nic_private { unsigned int tx_dirty; unsigned int rx_current; unsigned int rx_dirty; -#ifdef JUMBO_FRAME + bool is_jumbo; struct ipg_jumbo jumbo; -#endif + unsigned long rxfrag_size; + unsigned long rxsupport_size; + unsigned long max_rxframe_size; unsigned int rx_buf_sz; struct pci_dev *pdev; struct net_device *dev; diff --git a/drivers/net/irda/ali-ircc.h b/drivers/net/irda/ali-ircc.h index 07876578887f..ed35d99763d5 100644 --- a/drivers/net/irda/ali-ircc.h +++ b/drivers/net/irda/ali-ircc.h @@ -219,8 +219,6 @@ struct ali_ircc_cb { int index; /* Instance index */ unsigned char fifo_opti_buf; - - struct pm_dev *dev; }; static inline void switch_bank(int iobase, int bank) diff --git a/drivers/net/irda/au1000_ircc.h b/drivers/net/irda/au1000_ircc.h index 7a31d4659ed6..b4763f24dded 100644 --- a/drivers/net/irda/au1000_ircc.h +++ b/drivers/net/irda/au1000_ircc.h @@ -122,6 +122,5 @@ struct au1k_private { struct timer_list timer; spinlock_t lock; /* For serializing operations */ - struct pm_dev *dev; }; #endif /* AU1000_IRCC_H */ diff --git a/drivers/net/irda/donauboe.c b/drivers/net/irda/donauboe.c index 1257e1a7e819..34ad189fff67 100644 --- a/drivers/net/irda/donauboe.c +++ b/drivers/net/irda/donauboe.c @@ -49,10 +49,6 @@ /* Look at toshoboe.h (currently in include/net/irda) for details of */ /* Where to get documentation on the chip */ - -static char *rcsid = - "$Id: donauboe.c V2.18 ven jan 10 03:14:16 2003$"; - /* See below for a description of the logic in this driver */ /* User servicable parts */ @@ -1677,7 +1673,7 @@ toshoboe_open (struct pci_dev *pci_dev, const struct pci_device_id *pdid) pci_set_drvdata(pci_dev,self); - printk (KERN_INFO DRIVER_NAME ": Using multiple tasks, version %s\n", rcsid); + printk (KERN_INFO DRIVER_NAME ": Using multiple tasks\n"); return 0; diff --git a/drivers/net/irda/irtty-sir.c b/drivers/net/irda/irtty-sir.c index e6f40b7f9041..9e33196f9459 100644 --- a/drivers/net/irda/irtty-sir.c +++ b/drivers/net/irda/irtty-sir.c @@ -533,7 +533,7 @@ static void irtty_close(struct tty_struct *tty) /* ------------------------------------------------------- */ -static struct tty_ldisc irda_ldisc = { +static struct tty_ldisc_ops irda_ldisc = { .magic = TTY_LDISC_MAGIC, .name = "irda", .flags = 0, diff --git a/drivers/net/irda/smsc-ircc2.c b/drivers/net/irda/smsc-ircc2.c index cfe0194fef71..78dc8e7837f0 100644 --- a/drivers/net/irda/smsc-ircc2.c +++ b/drivers/net/irda/smsc-ircc2.c @@ -1,5 +1,4 @@ /********************************************************************* - * $Id: smsc-ircc2.c,v 1.19.2.5 2002/10/27 11:34:26 dip Exp $ * * Description: Driver for the SMC Infrared Communications Controller * Status: Experimental. diff --git a/drivers/net/irda/smsc-ircc2.h b/drivers/net/irda/smsc-ircc2.h index 0c36286d87f7..317b7fd69bb3 100644 --- a/drivers/net/irda/smsc-ircc2.h +++ b/drivers/net/irda/smsc-ircc2.h @@ -1,5 +1,4 @@ /********************************************************************* - * $Id: smsc-ircc2.h,v 1.12.2.1 2002/10/27 10:52:37 dip Exp $ * * Description: Definitions for the SMC IrCC chipset * Status: Experimental. diff --git a/drivers/net/irda/via-ircc.h b/drivers/net/irda/via-ircc.h index 9d012f0dbd30..403c3f77634c 100644 --- a/drivers/net/irda/via-ircc.h +++ b/drivers/net/irda/via-ircc.h @@ -118,7 +118,6 @@ struct via_ircc_cb { int index; /* Instance index */ struct eventflag EventFlag; - struct pm_dev *dev; unsigned int chip_id; /* to remember chip id */ unsigned int RetryCount; unsigned int RxDataReady; diff --git a/drivers/net/ixgb/Makefile b/drivers/net/ixgb/Makefile index 838a5084fa00..0b20c5e62ffe 100644 --- a/drivers/net/ixgb/Makefile +++ b/drivers/net/ixgb/Makefile @@ -1,7 +1,7 @@ ################################################################################ # # Intel PRO/10GbE Linux driver -# Copyright(c) 1999 - 2006 Intel Corporation. +# Copyright(c) 1999 - 2008 Intel Corporation. # # This program is free software; you can redistribute it and/or modify it # under the terms and conditions of the GNU General Public License, diff --git a/drivers/net/ixgb/ixgb.h b/drivers/net/ixgb/ixgb.h index 16f9c756aa46..804698fc6a8f 100644 --- a/drivers/net/ixgb/ixgb.h +++ b/drivers/net/ixgb/ixgb.h @@ -1,7 +1,7 @@ /******************************************************************************* Intel PRO/10GbE Linux driver - Copyright(c) 1999 - 2006 Intel Corporation. + Copyright(c) 1999 - 2008 Intel Corporation. This program is free software; you can redistribute it and/or modify it under the terms and conditions of the GNU General Public License, @@ -89,18 +89,16 @@ struct ixgb_adapter; /* TX/RX descriptor defines */ -#define DEFAULT_TXD 256 -#define MAX_TXD 4096 -#define MIN_TXD 64 +#define DEFAULT_TXD 256 +#define MAX_TXD 4096 +#define MIN_TXD 64 /* hardware cannot reliably support more than 512 descriptors owned by - * hardware descrioptor cache otherwise an unreliable ring under heavy - * recieve load may result */ -/* #define DEFAULT_RXD 1024 */ -/* #define MAX_RXD 4096 */ -#define DEFAULT_RXD 512 -#define MAX_RXD 512 -#define MIN_RXD 64 + * hardware descriptor cache otherwise an unreliable ring under heavy + * receive load may result */ +#define DEFAULT_RXD 512 +#define MAX_RXD 512 +#define MIN_RXD 64 /* Supported Rx Buffer Sizes */ #define IXGB_RXBUFFER_2048 2048 @@ -157,7 +155,6 @@ struct ixgb_adapter { u32 part_num; u16 link_speed; u16 link_duplex; - spinlock_t tx_lock; struct work_struct tx_timeout_task; struct timer_list blink_timer; diff --git a/drivers/net/ixgb/ixgb_ee.c b/drivers/net/ixgb/ixgb_ee.c index 2f7ed52c7502..89ffa7264a12 100644 --- a/drivers/net/ixgb/ixgb_ee.c +++ b/drivers/net/ixgb/ixgb_ee.c @@ -1,7 +1,7 @@ /******************************************************************************* Intel PRO/10GbE Linux driver - Copyright(c) 1999 - 2006 Intel Corporation. + Copyright(c) 1999 - 2008 Intel Corporation. This program is free software; you can redistribute it and/or modify it under the terms and conditions of the GNU General Public License, @@ -108,7 +108,7 @@ ixgb_shift_out_bits(struct ixgb_hw *hw, */ eecd_reg &= ~IXGB_EECD_DI; - if(data & mask) + if (data & mask) eecd_reg |= IXGB_EECD_DI; IXGB_WRITE_REG(hw, EECD, eecd_reg); @@ -120,7 +120,7 @@ ixgb_shift_out_bits(struct ixgb_hw *hw, mask = mask >> 1; - } while(mask); + } while (mask); /* We leave the "DI" bit set to "0" when we leave this routine. */ eecd_reg &= ~IXGB_EECD_DI; @@ -152,14 +152,14 @@ ixgb_shift_in_bits(struct ixgb_hw *hw) eecd_reg &= ~(IXGB_EECD_DO | IXGB_EECD_DI); data = 0; - for(i = 0; i < 16; i++) { + for (i = 0; i < 16; i++) { data = data << 1; ixgb_raise_clock(hw, &eecd_reg); eecd_reg = IXGB_READ_REG(hw, EECD); eecd_reg &= ~(IXGB_EECD_DI); - if(eecd_reg & IXGB_EECD_DO) + if (eecd_reg & IXGB_EECD_DO) data |= 1; ixgb_lower_clock(hw, &eecd_reg); @@ -205,7 +205,7 @@ ixgb_standby_eeprom(struct ixgb_hw *hw) eecd_reg = IXGB_READ_REG(hw, EECD); - /* Deselct EEPROM */ + /* Deselect EEPROM */ eecd_reg &= ~(IXGB_EECD_CS | IXGB_EECD_SK); IXGB_WRITE_REG(hw, EECD, eecd_reg); udelay(50); @@ -293,14 +293,14 @@ ixgb_wait_eeprom_command(struct ixgb_hw *hw) */ ixgb_standby_eeprom(hw); - /* Now read DO repeatedly until is high (equal to '1'). The EEEPROM will + /* Now read DO repeatedly until is high (equal to '1'). The EEPROM will * signal that the command has been completed by raising the DO signal. * If DO does not go high in 10 milliseconds, then error out. */ - for(i = 0; i < 200; i++) { + for (i = 0; i < 200; i++) { eecd_reg = IXGB_READ_REG(hw, EECD); - if(eecd_reg & IXGB_EECD_DO) + if (eecd_reg & IXGB_EECD_DO) return (true); udelay(50); @@ -328,10 +328,10 @@ ixgb_validate_eeprom_checksum(struct ixgb_hw *hw) u16 checksum = 0; u16 i; - for(i = 0; i < (EEPROM_CHECKSUM_REG + 1); i++) + for (i = 0; i < (EEPROM_CHECKSUM_REG + 1); i++) checksum += ixgb_read_eeprom(hw, i); - if(checksum == (u16) EEPROM_SUM) + if (checksum == (u16) EEPROM_SUM) return (true); else return (false); @@ -351,7 +351,7 @@ ixgb_update_eeprom_checksum(struct ixgb_hw *hw) u16 checksum = 0; u16 i; - for(i = 0; i < EEPROM_CHECKSUM_REG; i++) + for (i = 0; i < EEPROM_CHECKSUM_REG; i++) checksum += ixgb_read_eeprom(hw, i); checksum = (u16) EEPROM_SUM - checksum; @@ -365,7 +365,7 @@ ixgb_update_eeprom_checksum(struct ixgb_hw *hw) * * hw - Struct containing variables accessed by shared code * reg - offset within the EEPROM to be written to - * data - 16 bit word to be writen to the EEPROM + * data - 16 bit word to be written to the EEPROM * * If ixgb_update_eeprom_checksum is not called after this function, the * EEPROM will most likely contain an invalid checksum. @@ -472,7 +472,7 @@ ixgb_get_eeprom_data(struct ixgb_hw *hw) ee_map = (struct ixgb_ee_map_type *)hw->eeprom; DEBUGOUT("ixgb_ee: Reading eeprom data\n"); - for(i = 0; i < IXGB_EEPROM_SIZE ; i++) { + for (i = 0; i < IXGB_EEPROM_SIZE ; i++) { u16 ee_data; ee_data = ixgb_read_eeprom(hw, i); checksum += ee_data; diff --git a/drivers/net/ixgb/ixgb_ee.h b/drivers/net/ixgb/ixgb_ee.h index 4b7bd0d4a8a9..7ea12652f471 100644 --- a/drivers/net/ixgb/ixgb_ee.h +++ b/drivers/net/ixgb/ixgb_ee.h @@ -1,7 +1,7 @@ /******************************************************************************* Intel PRO/10GbE Linux driver - Copyright(c) 1999 - 2006 Intel Corporation. + Copyright(c) 1999 - 2008 Intel Corporation. This program is free software; you can redistribute it and/or modify it under the terms and conditions of the GNU General Public License, @@ -34,11 +34,11 @@ #define IXGB_ETH_LENGTH_OF_ADDRESS 6 /* EEPROM Commands */ -#define EEPROM_READ_OPCODE 0x6 /* EERPOM read opcode */ -#define EEPROM_WRITE_OPCODE 0x5 /* EERPOM write opcode */ -#define EEPROM_ERASE_OPCODE 0x7 /* EERPOM erase opcode */ -#define EEPROM_EWEN_OPCODE 0x13 /* EERPOM erase/write enable */ -#define EEPROM_EWDS_OPCODE 0x10 /* EERPOM erast/write disable */ +#define EEPROM_READ_OPCODE 0x6 /* EEPROM read opcode */ +#define EEPROM_WRITE_OPCODE 0x5 /* EEPROM write opcode */ +#define EEPROM_ERASE_OPCODE 0x7 /* EEPROM erase opcode */ +#define EEPROM_EWEN_OPCODE 0x13 /* EEPROM erase/write enable */ +#define EEPROM_EWDS_OPCODE 0x10 /* EEPROM erase/write disable */ /* EEPROM MAP (Word Offsets) */ #define EEPROM_IA_1_2_REG 0x0000 diff --git a/drivers/net/ixgb/ixgb_ethtool.c b/drivers/net/ixgb/ixgb_ethtool.c index 8464d8a013b0..288ee1d0f431 100644 --- a/drivers/net/ixgb/ixgb_ethtool.c +++ b/drivers/net/ixgb/ixgb_ethtool.c @@ -1,7 +1,7 @@ /******************************************************************************* Intel PRO/10GbE Linux driver - Copyright(c) 1999 - 2006 Intel Corporation. + Copyright(c) 1999 - 2008 Intel Corporation. This program is free software; you can redistribute it and/or modify it under the terms and conditions of the GNU General Public License, @@ -95,7 +95,7 @@ ixgb_get_settings(struct net_device *netdev, struct ethtool_cmd *ecmd) ecmd->port = PORT_FIBRE; ecmd->transceiver = XCVR_EXTERNAL; - if(netif_carrier_ok(adapter->netdev)) { + if (netif_carrier_ok(adapter->netdev)) { ecmd->speed = SPEED_10000; ecmd->duplex = DUPLEX_FULL; } else { @@ -122,11 +122,11 @@ ixgb_set_settings(struct net_device *netdev, struct ethtool_cmd *ecmd) { struct ixgb_adapter *adapter = netdev_priv(netdev); - if(ecmd->autoneg == AUTONEG_ENABLE || + if (ecmd->autoneg == AUTONEG_ENABLE || ecmd->speed + ecmd->duplex != SPEED_10000 + DUPLEX_FULL) return -EINVAL; - - if(netif_running(adapter->netdev)) { + + if (netif_running(adapter->netdev)) { ixgb_down(adapter, true); ixgb_reset(adapter); ixgb_up(adapter); @@ -143,14 +143,14 @@ ixgb_get_pauseparam(struct net_device *netdev, { struct ixgb_adapter *adapter = netdev_priv(netdev); struct ixgb_hw *hw = &adapter->hw; - + pause->autoneg = AUTONEG_DISABLE; - - if(hw->fc.type == ixgb_fc_rx_pause) + + if (hw->fc.type == ixgb_fc_rx_pause) pause->rx_pause = 1; - else if(hw->fc.type == ixgb_fc_tx_pause) + else if (hw->fc.type == ixgb_fc_tx_pause) pause->tx_pause = 1; - else if(hw->fc.type == ixgb_fc_full) { + else if (hw->fc.type == ixgb_fc_full) { pause->rx_pause = 1; pause->tx_pause = 1; } @@ -162,26 +162,26 @@ ixgb_set_pauseparam(struct net_device *netdev, { struct ixgb_adapter *adapter = netdev_priv(netdev); struct ixgb_hw *hw = &adapter->hw; - - if(pause->autoneg == AUTONEG_ENABLE) + + if (pause->autoneg == AUTONEG_ENABLE) return -EINVAL; - if(pause->rx_pause && pause->tx_pause) + if (pause->rx_pause && pause->tx_pause) hw->fc.type = ixgb_fc_full; - else if(pause->rx_pause && !pause->tx_pause) + else if (pause->rx_pause && !pause->tx_pause) hw->fc.type = ixgb_fc_rx_pause; - else if(!pause->rx_pause && pause->tx_pause) + else if (!pause->rx_pause && pause->tx_pause) hw->fc.type = ixgb_fc_tx_pause; - else if(!pause->rx_pause && !pause->tx_pause) + else if (!pause->rx_pause && !pause->tx_pause) hw->fc.type = ixgb_fc_none; - if(netif_running(adapter->netdev)) { + if (netif_running(adapter->netdev)) { ixgb_down(adapter, true); ixgb_up(adapter); ixgb_set_speed_duplex(netdev); } else ixgb_reset(adapter); - + return 0; } @@ -200,7 +200,7 @@ ixgb_set_rx_csum(struct net_device *netdev, u32 data) adapter->rx_csum = data; - if(netif_running(netdev)) { + if (netif_running(netdev)) { ixgb_down(adapter, true); ixgb_up(adapter); ixgb_set_speed_duplex(netdev); @@ -208,7 +208,7 @@ ixgb_set_rx_csum(struct net_device *netdev, u32 data) ixgb_reset(adapter); return 0; } - + static u32 ixgb_get_tx_csum(struct net_device *netdev) { @@ -229,12 +229,12 @@ ixgb_set_tx_csum(struct net_device *netdev, u32 data) static int ixgb_set_tso(struct net_device *netdev, u32 data) { - if(data) + if (data) netdev->features |= NETIF_F_TSO; else netdev->features &= ~NETIF_F_TSO; return 0; -} +} static u32 ixgb_get_msglevel(struct net_device *netdev) @@ -251,7 +251,7 @@ ixgb_set_msglevel(struct net_device *netdev, u32 data) } #define IXGB_GET_STAT(_A_, _R_) _A_->stats._R_ -static int +static int ixgb_get_regs_len(struct net_device *netdev) { #define IXGB_REG_DUMP_LEN 136*sizeof(u32) @@ -301,7 +301,7 @@ ixgb_get_regs(struct net_device *netdev, *reg++ = IXGB_READ_REG(hw, RXCSUM); /* 20 */ /* there are 16 RAR entries in hardware, we only use 3 */ - for(i = 0; i < IXGB_ALL_RAR_ENTRIES; i++) { + for (i = 0; i < IXGB_ALL_RAR_ENTRIES; i++) { *reg++ = IXGB_READ_REG_ARRAY(hw, RAL, (i << 1)); /*21,...,51 */ *reg++ = IXGB_READ_REG_ARRAY(hw, RAH, (i << 1)); /*22,...,52 */ } @@ -415,7 +415,7 @@ ixgb_get_eeprom(struct net_device *netdev, int i, max_len, first_word, last_word; int ret_val = 0; - if(eeprom->len == 0) { + if (eeprom->len == 0) { ret_val = -EINVAL; goto geeprom_error; } @@ -424,12 +424,12 @@ ixgb_get_eeprom(struct net_device *netdev, max_len = ixgb_get_eeprom_len(netdev); - if(eeprom->offset > eeprom->offset + eeprom->len) { + if (eeprom->offset > eeprom->offset + eeprom->len) { ret_val = -EINVAL; goto geeprom_error; } - if((eeprom->offset + eeprom->len) > max_len) + if ((eeprom->offset + eeprom->len) > max_len) eeprom->len = (max_len - eeprom->offset); first_word = eeprom->offset >> 1; @@ -437,16 +437,14 @@ ixgb_get_eeprom(struct net_device *netdev, eeprom_buff = kmalloc(sizeof(__le16) * (last_word - first_word + 1), GFP_KERNEL); - if(!eeprom_buff) + if (!eeprom_buff) return -ENOMEM; /* note the eeprom was good because the driver loaded */ - for(i = 0; i <= (last_word - first_word); i++) { + for (i = 0; i <= (last_word - first_word); i++) eeprom_buff[i] = ixgb_get_eeprom_word(hw, (first_word + i)); - } - memcpy(bytes, (u8 *)eeprom_buff + (eeprom->offset & 1), - eeprom->len); + memcpy(bytes, (u8 *)eeprom_buff + (eeprom->offset & 1), eeprom->len); kfree(eeprom_buff); geeprom_error: @@ -464,47 +462,47 @@ ixgb_set_eeprom(struct net_device *netdev, int max_len, first_word, last_word; u16 i; - if(eeprom->len == 0) + if (eeprom->len == 0) return -EINVAL; - if(eeprom->magic != (hw->vendor_id | (hw->device_id << 16))) + if (eeprom->magic != (hw->vendor_id | (hw->device_id << 16))) return -EFAULT; max_len = ixgb_get_eeprom_len(netdev); - if(eeprom->offset > eeprom->offset + eeprom->len) + if (eeprom->offset > eeprom->offset + eeprom->len) return -EINVAL; - if((eeprom->offset + eeprom->len) > max_len) + if ((eeprom->offset + eeprom->len) > max_len) eeprom->len = (max_len - eeprom->offset); first_word = eeprom->offset >> 1; last_word = (eeprom->offset + eeprom->len - 1) >> 1; eeprom_buff = kmalloc(max_len, GFP_KERNEL); - if(!eeprom_buff) + if (!eeprom_buff) return -ENOMEM; ptr = (void *)eeprom_buff; - if(eeprom->offset & 1) { + if (eeprom->offset & 1) { /* need read/modify/write of first changed EEPROM word */ /* only the second byte of the word is being modified */ eeprom_buff[0] = ixgb_read_eeprom(hw, first_word); ptr++; } - if((eeprom->offset + eeprom->len) & 1) { + if ((eeprom->offset + eeprom->len) & 1) { /* need read/modify/write of last changed EEPROM word */ /* only the first byte of the word is being modified */ - eeprom_buff[last_word - first_word] + eeprom_buff[last_word - first_word] = ixgb_read_eeprom(hw, last_word); } memcpy(ptr, bytes, eeprom->len); - for(i = 0; i <= (last_word - first_word); i++) + for (i = 0; i <= (last_word - first_word); i++) ixgb_write_eeprom(hw, first_word + i, eeprom_buff[i]); /* Update the checksum over the first part of the EEPROM if needed */ - if(first_word <= EEPROM_CHECKSUM_REG) + if (first_word <= EEPROM_CHECKSUM_REG) ixgb_update_eeprom_checksum(hw); kfree(eeprom_buff); @@ -534,7 +532,7 @@ ixgb_get_ringparam(struct net_device *netdev, struct ixgb_desc_ring *txdr = &adapter->tx_ring; struct ixgb_desc_ring *rxdr = &adapter->rx_ring; - ring->rx_max_pending = MAX_RXD; + ring->rx_max_pending = MAX_RXD; ring->tx_max_pending = MAX_TXD; ring->rx_mini_max_pending = 0; ring->rx_jumbo_max_pending = 0; @@ -544,7 +542,7 @@ ixgb_get_ringparam(struct net_device *netdev, ring->rx_jumbo_pending = 0; } -static int +static int ixgb_set_ringparam(struct net_device *netdev, struct ethtool_ringparam *ring) { @@ -557,10 +555,10 @@ ixgb_set_ringparam(struct net_device *netdev, tx_old = adapter->tx_ring; rx_old = adapter->rx_ring; - if((ring->rx_mini_pending) || (ring->rx_jumbo_pending)) + if ((ring->rx_mini_pending) || (ring->rx_jumbo_pending)) return -EINVAL; - if(netif_running(adapter->netdev)) + if (netif_running(adapter->netdev)) ixgb_down(adapter, true); rxdr->count = max(ring->rx_pending,(u32)MIN_RXD); @@ -571,11 +569,11 @@ ixgb_set_ringparam(struct net_device *netdev, txdr->count = min(txdr->count,(u32)MAX_TXD); txdr->count = ALIGN(txdr->count, IXGB_REQ_TX_DESCRIPTOR_MULTIPLE); - if(netif_running(adapter->netdev)) { + if (netif_running(adapter->netdev)) { /* Try to get new resources before deleting old */ - if((err = ixgb_setup_rx_resources(adapter))) + if ((err = ixgb_setup_rx_resources(adapter))) goto err_setup_rx; - if((err = ixgb_setup_tx_resources(adapter))) + if ((err = ixgb_setup_tx_resources(adapter))) goto err_setup_tx; /* save the new, restore the old in order to free it, @@ -589,7 +587,7 @@ ixgb_set_ringparam(struct net_device *netdev, ixgb_free_tx_resources(adapter); adapter->rx_ring = rx_new; adapter->tx_ring = tx_new; - if((err = ixgb_up(adapter))) + if ((err = ixgb_up(adapter))) return err; ixgb_set_speed_duplex(netdev); } @@ -615,7 +613,7 @@ ixgb_led_blink_callback(unsigned long data) { struct ixgb_adapter *adapter = (struct ixgb_adapter *)data; - if(test_and_change_bit(IXGB_LED_ON, &adapter->led_status)) + if (test_and_change_bit(IXGB_LED_ON, &adapter->led_status)) ixgb_led_off(&adapter->hw); else ixgb_led_on(&adapter->hw); @@ -631,7 +629,7 @@ ixgb_phys_id(struct net_device *netdev, u32 data) if (!data) data = INT_MAX; - if(!adapter->blink_timer.function) { + if (!adapter->blink_timer.function) { init_timer(&adapter->blink_timer); adapter->blink_timer.function = ixgb_led_blink_callback; adapter->blink_timer.data = (unsigned long)adapter; @@ -647,7 +645,7 @@ ixgb_phys_id(struct net_device *netdev, u32 data) return 0; } -static int +static int ixgb_get_sset_count(struct net_device *netdev, int sset) { switch (sset) { @@ -658,30 +656,30 @@ ixgb_get_sset_count(struct net_device *netdev, int sset) } } -static void -ixgb_get_ethtool_stats(struct net_device *netdev, +static void +ixgb_get_ethtool_stats(struct net_device *netdev, struct ethtool_stats *stats, u64 *data) { struct ixgb_adapter *adapter = netdev_priv(netdev); int i; ixgb_update_stats(adapter); - for(i = 0; i < IXGB_STATS_LEN; i++) { - char *p = (char *)adapter+ixgb_gstrings_stats[i].stat_offset; - data[i] = (ixgb_gstrings_stats[i].sizeof_stat == + for (i = 0; i < IXGB_STATS_LEN; i++) { + char *p = (char *)adapter+ixgb_gstrings_stats[i].stat_offset; + data[i] = (ixgb_gstrings_stats[i].sizeof_stat == sizeof(u64)) ? *(u64 *)p : *(u32 *)p; } } -static void +static void ixgb_get_strings(struct net_device *netdev, u32 stringset, u8 *data) { int i; switch(stringset) { case ETH_SS_STATS: - for(i=0; i < IXGB_STATS_LEN; i++) { - memcpy(data + i * ETH_GSTRING_LEN, + for (i = 0; i < IXGB_STATS_LEN; i++) { + memcpy(data + i * ETH_GSTRING_LEN, ixgb_gstrings_stats[i].stat_string, ETH_GSTRING_LEN); } diff --git a/drivers/net/ixgb/ixgb_hw.c b/drivers/net/ixgb/ixgb_hw.c index 04d2003e24e1..11dcda0f453e 100644 --- a/drivers/net/ixgb/ixgb_hw.c +++ b/drivers/net/ixgb/ixgb_hw.c @@ -1,7 +1,7 @@ /******************************************************************************* Intel PRO/10GbE Linux driver - Copyright(c) 1999 - 2006 Intel Corporation. + Copyright(c) 1999 - 2008 Intel Corporation. This program is free software; you can redistribute it and/or modify it under the terms and conditions of the GNU General Public License, @@ -125,7 +125,7 @@ ixgb_adapter_stop(struct ixgb_hw *hw) /* If we are stopped or resetting exit gracefully and wait to be * started again before accessing the hardware. */ - if(hw->adapter_stopped) { + if (hw->adapter_stopped) { DEBUGOUT("Exiting because the adapter is already stopped!!!\n"); return false; } @@ -347,7 +347,7 @@ ixgb_init_hw(struct ixgb_hw *hw) /* Zero out the Multicast HASH table */ DEBUGOUT("Zeroing the MTA\n"); - for(i = 0; i < IXGB_MC_TBL_SIZE; i++) + for (i = 0; i < IXGB_MC_TBL_SIZE; i++) IXGB_WRITE_REG_ARRAY(hw, MTA, i, 0); /* Zero out the VLAN Filter Table Array */ @@ -371,7 +371,7 @@ ixgb_init_hw(struct ixgb_hw *hw) * hw - Struct containing variables accessed by shared code * * Places the MAC address in receive address register 0 and clears the rest - * of the receive addresss registers. Clears the multicast table. Assumes + * of the receive address registers. Clears the multicast table. Assumes * the receiver is in reset when the routine is called. *****************************************************************************/ static void @@ -413,7 +413,7 @@ ixgb_init_rx_addrs(struct ixgb_hw *hw) /* Zero out the other 15 receive addresses. */ DEBUGOUT("Clearing RAR[1-15]\n"); - for(i = 1; i < IXGB_RAR_ENTRIES; i++) { + for (i = 1; i < IXGB_RAR_ENTRIES; i++) { /* Write high reg first to disable the AV bit first */ IXGB_WRITE_REG_ARRAY(hw, RA, ((i << 1) + 1), 0); IXGB_WRITE_REG_ARRAY(hw, RA, (i << 1), 0); @@ -452,19 +452,18 @@ ixgb_mc_addr_list_update(struct ixgb_hw *hw, /* Clear RAR[1-15] */ DEBUGOUT(" Clearing RAR[1-15]\n"); - for(i = rar_used_count; i < IXGB_RAR_ENTRIES; i++) { + for (i = rar_used_count; i < IXGB_RAR_ENTRIES; i++) { IXGB_WRITE_REG_ARRAY(hw, RA, (i << 1), 0); IXGB_WRITE_REG_ARRAY(hw, RA, ((i << 1) + 1), 0); } /* Clear the MTA */ DEBUGOUT(" Clearing MTA\n"); - for(i = 0; i < IXGB_MC_TBL_SIZE; i++) { + for (i = 0; i < IXGB_MC_TBL_SIZE; i++) IXGB_WRITE_REG_ARRAY(hw, MTA, i, 0); - } /* Add the new addresses */ - for(i = 0; i < mc_addr_count; i++) { + for (i = 0; i < mc_addr_count; i++) { DEBUGOUT(" Adding the multicast addresses:\n"); DEBUGOUT7(" MC Addr #%d =%.2X %.2X %.2X %.2X %.2X %.2X\n", i, mc_addr_list[i * (IXGB_ETH_LENGTH_OF_ADDRESS + pad)], @@ -482,7 +481,7 @@ ixgb_mc_addr_list_update(struct ixgb_hw *hw, /* Place this multicast address in the RAR if there is room, * * else put it in the MTA */ - if(rar_used_count < IXGB_RAR_ENTRIES) { + if (rar_used_count < IXGB_RAR_ENTRIES) { ixgb_rar_set(hw, mc_addr_list + (i * (IXGB_ETH_LENGTH_OF_ADDRESS + pad)), @@ -649,7 +648,7 @@ ixgb_clear_vfta(struct ixgb_hw *hw) { u32 offset; - for(offset = 0; offset < IXGB_VLAN_FILTER_TBL_SIZE; offset++) + for (offset = 0; offset < IXGB_VLAN_FILTER_TBL_SIZE; offset++) IXGB_WRITE_REG_ARRAY(hw, VFTA, offset, 0); return; } @@ -719,9 +718,8 @@ ixgb_setup_fc(struct ixgb_hw *hw) /* Write the new settings */ IXGB_WRITE_REG(hw, CTRL0, ctrl_reg); - if (pap_reg != 0) { + if (pap_reg != 0) IXGB_WRITE_REG(hw, PAP, pap_reg); - } /* Set the flow control receive threshold registers. Normally, * these registers will be set to a default threshold that may be @@ -729,14 +727,14 @@ ixgb_setup_fc(struct ixgb_hw *hw) * ability to transmit pause frames in not enabled, then these * registers will be set to 0. */ - if(!(hw->fc.type & ixgb_fc_tx_pause)) { + if (!(hw->fc.type & ixgb_fc_tx_pause)) { IXGB_WRITE_REG(hw, FCRTL, 0); IXGB_WRITE_REG(hw, FCRTH, 0); } else { /* We need to set up the Receive Threshold high and low water * marks as well as (optionally) enabling the transmission of XON * frames. */ - if(hw->fc.send_xon) { + if (hw->fc.send_xon) { IXGB_WRITE_REG(hw, FCRTL, (hw->fc.low_water | IXGB_FCRTL_XONE)); } else { @@ -791,7 +789,7 @@ ixgb_read_phy_reg(struct ixgb_hw *hw, ** from the CPU Write to the Ready bit assertion. **************************************************************/ - for(i = 0; i < 10; i++) + for (i = 0; i < 10; i++) { udelay(10); @@ -818,7 +816,7 @@ ixgb_read_phy_reg(struct ixgb_hw *hw, ** from the CPU Write to the Ready bit assertion. **************************************************************/ - for(i = 0; i < 10; i++) + for (i = 0; i < 10; i++) { udelay(10); @@ -887,7 +885,7 @@ ixgb_write_phy_reg(struct ixgb_hw *hw, ** from the CPU Write to the Ready bit assertion. **************************************************************/ - for(i = 0; i < 10; i++) + for (i = 0; i < 10; i++) { udelay(10); @@ -914,7 +912,7 @@ ixgb_write_phy_reg(struct ixgb_hw *hw, ** from the CPU Write to the Ready bit assertion. **************************************************************/ - for(i = 0; i < 10; i++) + for (i = 0; i < 10; i++) { udelay(10); @@ -965,7 +963,7 @@ ixgb_check_for_link(struct ixgb_hw *hw) } /****************************************************************************** - * Check for a bad link condition that may have occured. + * Check for a bad link condition that may have occurred. * The indication is that the RFC / LFC registers may be incrementing * continually. A full adapter reset is required to recover. * @@ -1007,7 +1005,7 @@ ixgb_clear_hw_cntrs(struct ixgb_hw *hw) DEBUGFUNC("ixgb_clear_hw_cntrs"); /* if we are stopped or resetting exit gracefully */ - if(hw->adapter_stopped) { + if (hw->adapter_stopped) { DEBUGOUT("Exiting because the adapter is stopped!!!\n"); return; } diff --git a/drivers/net/ixgb/ixgb_hw.h b/drivers/net/ixgb/ixgb_hw.h index 39cfa47bea69..831fe0c58b2b 100644 --- a/drivers/net/ixgb/ixgb_hw.h +++ b/drivers/net/ixgb/ixgb_hw.h @@ -1,7 +1,7 @@ /******************************************************************************* Intel PRO/10GbE Linux driver - Copyright(c) 1999 - 2006 Intel Corporation. + Copyright(c) 1999 - 2008 Intel Corporation. This program is free software; you can redistribute it and/or modify it under the terms and conditions of the GNU General Public License, diff --git a/drivers/net/ixgb/ixgb_ids.h b/drivers/net/ixgb/ixgb_ids.h index 180d20e793a5..2a58847f46e8 100644 --- a/drivers/net/ixgb/ixgb_ids.h +++ b/drivers/net/ixgb/ixgb_ids.h @@ -1,7 +1,7 @@ /******************************************************************************* Intel PRO/10GbE Linux driver - Copyright(c) 1999 - 2006 Intel Corporation. + Copyright(c) 1999 - 2008 Intel Corporation. This program is free software; you can redistribute it and/or modify it under the terms and conditions of the GNU General Public License, @@ -38,11 +38,11 @@ #define SUN_VENDOR_ID 0x108E #define SUN_SUBVENDOR_ID 0x108E -#define IXGB_DEVICE_ID_82597EX 0x1048 -#define IXGB_DEVICE_ID_82597EX_SR 0x1A48 +#define IXGB_DEVICE_ID_82597EX 0x1048 +#define IXGB_DEVICE_ID_82597EX_SR 0x1A48 #define IXGB_DEVICE_ID_82597EX_LR 0x1B48 -#define IXGB_SUBDEVICE_ID_A11F 0xA11F -#define IXGB_SUBDEVICE_ID_A01F 0xA01F +#define IXGB_SUBDEVICE_ID_A11F 0xA11F +#define IXGB_SUBDEVICE_ID_A01F 0xA01F #define IXGB_DEVICE_ID_82597EX_CX4 0x109E #define IXGB_SUBDEVICE_ID_A00C 0xA00C diff --git a/drivers/net/ixgb/ixgb_main.c b/drivers/net/ixgb/ixgb_main.c index cb8daddafa29..aa75385cd6c7 100644 --- a/drivers/net/ixgb/ixgb_main.c +++ b/drivers/net/ixgb/ixgb_main.c @@ -1,7 +1,7 @@ /******************************************************************************* Intel PRO/10GbE Linux driver - Copyright(c) 1999 - 2006 Intel Corporation. + Copyright(c) 1999 - 2008 Intel Corporation. This program is free software; you can redistribute it and/or modify it under the terms and conditions of the GNU General Public License, @@ -31,14 +31,16 @@ char ixgb_driver_name[] = "ixgb"; static char ixgb_driver_string[] = "Intel(R) PRO/10GbE Network Driver"; -#ifndef CONFIG_IXGB_NAPI -#define DRIVERNAPI -#else #define DRIVERNAPI "-NAPI" -#endif -#define DRV_VERSION "1.0.126-k4"DRIVERNAPI +#define DRV_VERSION "1.0.135-k2" DRIVERNAPI const char ixgb_driver_version[] = DRV_VERSION; -static const char ixgb_copyright[] = "Copyright (c) 1999-2006 Intel Corporation."; +static const char ixgb_copyright[] = "Copyright (c) 1999-2008 Intel Corporation."; + +#define IXGB_CB_LENGTH 256 +static unsigned int copybreak __read_mostly = IXGB_CB_LENGTH; +module_param(copybreak, uint, 0644); +MODULE_PARM_DESC(copybreak, + "Maximum size of packet that is copied to a new buffer on receive"); /* ixgb_pci_tbl - PCI Device ID Table * @@ -55,7 +57,7 @@ static struct pci_device_id ixgb_pci_tbl[] = { PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, {INTEL_VENDOR_ID, IXGB_DEVICE_ID_82597EX_SR, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {INTEL_VENDOR_ID, IXGB_DEVICE_ID_82597EX_LR, + {INTEL_VENDOR_ID, IXGB_DEVICE_ID_82597EX_LR, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, /* required last entry */ @@ -65,16 +67,6 @@ static struct pci_device_id ixgb_pci_tbl[] = { MODULE_DEVICE_TABLE(pci, ixgb_pci_tbl); /* Local Function Prototypes */ - -int ixgb_up(struct ixgb_adapter *adapter); -void ixgb_down(struct ixgb_adapter *adapter, bool kill_watchdog); -void ixgb_reset(struct ixgb_adapter *adapter); -int ixgb_setup_tx_resources(struct ixgb_adapter *adapter); -int ixgb_setup_rx_resources(struct ixgb_adapter *adapter); -void ixgb_free_tx_resources(struct ixgb_adapter *adapter); -void ixgb_free_rx_resources(struct ixgb_adapter *adapter); -void ixgb_update_stats(struct ixgb_adapter *adapter); - static int ixgb_init_module(void); static void ixgb_exit_module(void); static int ixgb_probe(struct pci_dev *pdev, const struct pci_device_id *ent); @@ -96,18 +88,15 @@ static int ixgb_set_mac(struct net_device *netdev, void *p); static irqreturn_t ixgb_intr(int irq, void *data); static bool ixgb_clean_tx_irq(struct ixgb_adapter *adapter); -#ifdef CONFIG_IXGB_NAPI -static int ixgb_clean(struct napi_struct *napi, int budget); -static bool ixgb_clean_rx_irq(struct ixgb_adapter *adapter, - int *work_done, int work_to_do); -#else -static bool ixgb_clean_rx_irq(struct ixgb_adapter *adapter); -#endif -static void ixgb_alloc_rx_buffers(struct ixgb_adapter *adapter); +static int ixgb_clean(struct napi_struct *, int); +static bool ixgb_clean_rx_irq(struct ixgb_adapter *, int *, int); +static void ixgb_alloc_rx_buffers(struct ixgb_adapter *, int); + static void ixgb_tx_timeout(struct net_device *dev); static void ixgb_tx_timeout_task(struct work_struct *work); + static void ixgb_vlan_rx_register(struct net_device *netdev, - struct vlan_group *grp); + struct vlan_group *grp); static void ixgb_vlan_rx_add_vid(struct net_device *netdev, u16 vid); static void ixgb_vlan_rx_kill_vid(struct net_device *netdev, u16 vid); static void ixgb_restore_vlan(struct ixgb_adapter *adapter); @@ -118,7 +107,7 @@ static void ixgb_netpoll(struct net_device *dev); #endif static pci_ers_result_t ixgb_io_error_detected (struct pci_dev *pdev, - enum pci_channel_state state); + enum pci_channel_state state); static pci_ers_result_t ixgb_io_slot_reset (struct pci_dev *pdev); static void ixgb_io_resume (struct pci_dev *pdev); @@ -146,14 +135,6 @@ static int debug = DEFAULT_DEBUG_LEVEL_SHIFT; module_param(debug, int, 0); MODULE_PARM_DESC(debug, "Debug level (0=none,...,16=all)"); -/* some defines for controlling descriptor fetches in h/w */ -#define RXDCTL_WTHRESH_DEFAULT 15 /* chip writes back at this many or RXT0 */ -#define RXDCTL_PTHRESH_DEFAULT 0 /* chip considers prefech below - * this */ -#define RXDCTL_HTHRESH_DEFAULT 0 /* chip will only prefetch if tail - * is pushed this many descriptors - * from head */ - /** * ixgb_init_module - Driver Registration Routine * @@ -236,7 +217,7 @@ ixgb_up(struct ixgb_adapter *adapter) ixgb_configure_tx(adapter); ixgb_setup_rctl(adapter); ixgb_configure_rx(adapter); - ixgb_alloc_rx_buffers(adapter); + ixgb_alloc_rx_buffers(adapter, IXGB_DESC_UNUSED(&adapter->rx_ring)); /* disable interrupts and get the hardware into a known state */ IXGB_WRITE_REG(&adapter->hw, IMC, 0xffffffff); @@ -261,7 +242,7 @@ ixgb_up(struct ixgb_adapter *adapter) return err; } - if((hw->max_frame_size != max_frame) || + if ((hw->max_frame_size != max_frame) || (hw->max_frame_size != (IXGB_READ_REG(hw, MFS) >> IXGB_MFS_SHIFT))) { @@ -269,11 +250,11 @@ ixgb_up(struct ixgb_adapter *adapter) IXGB_WRITE_REG(hw, MFS, hw->max_frame_size << IXGB_MFS_SHIFT); - if(hw->max_frame_size > + if (hw->max_frame_size > IXGB_MAX_ENET_FRAME_SIZE_WITHOUT_FCS + ENET_FCS_LENGTH) { u32 ctrl0 = IXGB_READ_REG(hw, CTRL0); - if(!(ctrl0 & IXGB_CTRL0_JFE)) { + if (!(ctrl0 & IXGB_CTRL0_JFE)) { ctrl0 |= IXGB_CTRL0_JFE; IXGB_WRITE_REG(hw, CTRL0, ctrl0); } @@ -282,9 +263,7 @@ ixgb_up(struct ixgb_adapter *adapter) clear_bit(__IXGB_DOWN, &adapter->flags); -#ifdef CONFIG_IXGB_NAPI napi_enable(&adapter->napi); -#endif ixgb_irq_enable(adapter); mod_timer(&adapter->watchdog_timer, jiffies); @@ -300,9 +279,7 @@ ixgb_down(struct ixgb_adapter *adapter, bool kill_watchdog) /* prevent the interrupt handler from restarting watchdog */ set_bit(__IXGB_DOWN, &adapter->flags); -#ifdef CONFIG_IXGB_NAPI napi_disable(&adapter->napi); -#endif /* waiting for NAPI to complete can re-enable interrupts */ ixgb_irq_disable(adapter); free_irq(adapter->pdev->irq, netdev); @@ -310,7 +287,7 @@ ixgb_down(struct ixgb_adapter *adapter, bool kill_watchdog) if (adapter->have_msi) pci_disable_msi(adapter->pdev); - if(kill_watchdog) + if (kill_watchdog) del_timer_sync(&adapter->watchdog_timer); adapter->link_speed = 0; @@ -357,27 +334,25 @@ ixgb_reset(struct ixgb_adapter *adapter) **/ static int __devinit -ixgb_probe(struct pci_dev *pdev, - const struct pci_device_id *ent) +ixgb_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { struct net_device *netdev = NULL; struct ixgb_adapter *adapter; static int cards_found = 0; - unsigned long mmio_start; - int mmio_len; int pci_using_dac; int i; int err; - if((err = pci_enable_device(pdev))) + err = pci_enable_device(pdev); + if (err) return err; - if(!(err = pci_set_dma_mask(pdev, DMA_64BIT_MASK)) && - !(err = pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK))) { + if (!(err = pci_set_dma_mask(pdev, DMA_64BIT_MASK)) && + !(err = pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK))) { pci_using_dac = 1; } else { - if((err = pci_set_dma_mask(pdev, DMA_32BIT_MASK)) || - (err = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK))) { + if ((err = pci_set_dma_mask(pdev, DMA_32BIT_MASK)) || + (err = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK))) { printk(KERN_ERR "ixgb: No usable DMA configuration, aborting\n"); goto err_dma_mask; @@ -385,13 +360,14 @@ ixgb_probe(struct pci_dev *pdev, pci_using_dac = 0; } - if((err = pci_request_regions(pdev, ixgb_driver_name))) + err = pci_request_regions(pdev, ixgb_driver_name); + if (err) goto err_request_regions; pci_set_master(pdev); netdev = alloc_etherdev(sizeof(struct ixgb_adapter)); - if(!netdev) { + if (!netdev) { err = -ENOMEM; goto err_alloc_etherdev; } @@ -405,19 +381,17 @@ ixgb_probe(struct pci_dev *pdev, adapter->hw.back = adapter; adapter->msg_enable = netif_msg_init(debug, DEFAULT_DEBUG_LEVEL_SHIFT); - mmio_start = pci_resource_start(pdev, BAR_0); - mmio_len = pci_resource_len(pdev, BAR_0); - - adapter->hw.hw_addr = ioremap(mmio_start, mmio_len); - if(!adapter->hw.hw_addr) { + adapter->hw.hw_addr = ioremap(pci_resource_start(pdev, BAR_0), + pci_resource_len(pdev, BAR_0)); + if (!adapter->hw.hw_addr) { err = -EIO; goto err_ioremap; } - for(i = BAR_1; i <= BAR_5; i++) { - if(pci_resource_len(pdev, i) == 0) + for (i = BAR_1; i <= BAR_5; i++) { + if (pci_resource_len(pdev, i) == 0) continue; - if(pci_resource_flags(pdev, i) & IORESOURCE_IO) { + if (pci_resource_flags(pdev, i) & IORESOURCE_IO) { adapter->hw.io_base = pci_resource_start(pdev, i); break; } @@ -433,9 +407,7 @@ ixgb_probe(struct pci_dev *pdev, ixgb_set_ethtool_ops(netdev); netdev->tx_timeout = &ixgb_tx_timeout; netdev->watchdog_timeo = 5 * HZ; -#ifdef CONFIG_IXGB_NAPI netif_napi_add(netdev, &adapter->napi, ixgb_clean, 64); -#endif netdev->vlan_rx_register = ixgb_vlan_rx_register; netdev->vlan_rx_add_vid = ixgb_vlan_rx_add_vid; netdev->vlan_rx_kill_vid = ixgb_vlan_rx_kill_vid; @@ -444,9 +416,6 @@ ixgb_probe(struct pci_dev *pdev, #endif strncpy(netdev->name, pci_name(pdev), sizeof(netdev->name) - 1); - netdev->mem_start = mmio_start; - netdev->mem_end = mmio_start + mmio_len; - netdev->base_addr = adapter->hw.io_base; adapter->bd_number = cards_found; adapter->link_speed = 0; @@ -454,7 +423,8 @@ ixgb_probe(struct pci_dev *pdev, /* setup the private structure */ - if((err = ixgb_sw_init(adapter))) + err = ixgb_sw_init(adapter); + if (err) goto err_sw_init; netdev->features = NETIF_F_SG | @@ -463,16 +433,13 @@ ixgb_probe(struct pci_dev *pdev, NETIF_F_HW_VLAN_RX | NETIF_F_HW_VLAN_FILTER; netdev->features |= NETIF_F_TSO; -#ifdef NETIF_F_LLTX - netdev->features |= NETIF_F_LLTX; -#endif - if(pci_using_dac) + if (pci_using_dac) netdev->features |= NETIF_F_HIGHDMA; /* make sure the EEPROM is good */ - if(!ixgb_validate_eeprom_checksum(&adapter->hw)) { + if (!ixgb_validate_eeprom_checksum(&adapter->hw)) { DPRINTK(PROBE, ERR, "The EEPROM Checksum Is Not Valid\n"); err = -EIO; goto err_eeprom; @@ -481,7 +448,7 @@ ixgb_probe(struct pci_dev *pdev, ixgb_get_ee_mac_addr(&adapter->hw, netdev->dev_addr); memcpy(netdev->perm_addr, netdev->dev_addr, netdev->addr_len); - if(!is_valid_ether_addr(netdev->perm_addr)) { + if (!is_valid_ether_addr(netdev->perm_addr)) { DPRINTK(PROBE, ERR, "Invalid MAC Address\n"); err = -EIO; goto err_eeprom; @@ -496,7 +463,8 @@ ixgb_probe(struct pci_dev *pdev, INIT_WORK(&adapter->tx_timeout_task, ixgb_tx_timeout_task); strcpy(netdev->name, "eth%d"); - if((err = register_netdev(netdev))) + err = register_netdev(netdev); + if (err) goto err_register; /* we're going to reset, so assume we have no link for now */ @@ -543,6 +511,8 @@ ixgb_remove(struct pci_dev *pdev) struct net_device *netdev = pci_get_drvdata(pdev); struct ixgb_adapter *adapter = netdev_priv(netdev); + flush_scheduled_work(); + unregister_netdev(netdev); iounmap(adapter->hw.hw_addr); @@ -575,13 +545,13 @@ ixgb_sw_init(struct ixgb_adapter *adapter) hw->subsystem_id = pdev->subsystem_device; hw->max_frame_size = netdev->mtu + ENET_HEADER_SIZE + ENET_FCS_LENGTH; - adapter->rx_buffer_len = hw->max_frame_size; + adapter->rx_buffer_len = hw->max_frame_size + 8; /* + 8 for errata */ - if((hw->device_id == IXGB_DEVICE_ID_82597EX) + if ((hw->device_id == IXGB_DEVICE_ID_82597EX) || (hw->device_id == IXGB_DEVICE_ID_82597EX_CX4) || (hw->device_id == IXGB_DEVICE_ID_82597EX_LR) || (hw->device_id == IXGB_DEVICE_ID_82597EX_SR)) - hw->mac_type = ixgb_82597; + hw->mac_type = ixgb_82597; else { /* should never have loaded on this device */ DPRINTK(PROBE, ERR, "unsupported device id\n"); @@ -590,8 +560,6 @@ ixgb_sw_init(struct ixgb_adapter *adapter) /* enable flow control to be programmed */ hw->fc.send_xon = 1; - spin_lock_init(&adapter->tx_lock); - set_bit(__IXGB_DOWN, &adapter->flags); return 0; } @@ -616,16 +584,18 @@ ixgb_open(struct net_device *netdev) int err; /* allocate transmit descriptors */ - - if((err = ixgb_setup_tx_resources(adapter))) + err = ixgb_setup_tx_resources(adapter); + if (err) goto err_setup_tx; /* allocate receive descriptors */ - if((err = ixgb_setup_rx_resources(adapter))) + err = ixgb_setup_rx_resources(adapter); + if (err) goto err_setup_rx; - if((err = ixgb_up(adapter))) + err = ixgb_up(adapter); + if (err) goto err_up; return 0; @@ -681,7 +651,7 @@ ixgb_setup_tx_resources(struct ixgb_adapter *adapter) size = sizeof(struct ixgb_buffer) * txdr->count; txdr->buffer_info = vmalloc(size); - if(!txdr->buffer_info) { + if (!txdr->buffer_info) { DPRINTK(PROBE, ERR, "Unable to allocate transmit descriptor ring memory\n"); return -ENOMEM; @@ -694,7 +664,7 @@ ixgb_setup_tx_resources(struct ixgb_adapter *adapter) txdr->size = ALIGN(txdr->size, 4096); txdr->desc = pci_alloc_consistent(pdev, txdr->size, &txdr->dma); - if(!txdr->desc) { + if (!txdr->desc) { vfree(txdr->buffer_info); DPRINTK(PROBE, ERR, "Unable to allocate transmit descriptor memory\n"); @@ -723,8 +693,8 @@ ixgb_configure_tx(struct ixgb_adapter *adapter) u32 tctl; struct ixgb_hw *hw = &adapter->hw; - /* Setup the Base and Length of the Tx Descriptor Ring - * tx_ring.dma can be either a 32 or 64 bit value + /* Setup the Base and Length of the Tx Descriptor Ring + * tx_ring.dma can be either a 32 or 64 bit value */ IXGB_WRITE_REG(hw, TDBAL, (tdba & 0x00000000ffffffffULL)); @@ -750,8 +720,8 @@ ixgb_configure_tx(struct ixgb_adapter *adapter) /* Setup Transmit Descriptor Settings for this adapter */ adapter->tx_cmd_type = - IXGB_TX_DESC_TYPE - | (adapter->tx_int_delay_enable ? IXGB_TX_DESC_CMD_IDE : 0); + IXGB_TX_DESC_TYPE | + (adapter->tx_int_delay_enable ? IXGB_TX_DESC_CMD_IDE : 0); } /** @@ -770,7 +740,7 @@ ixgb_setup_rx_resources(struct ixgb_adapter *adapter) size = sizeof(struct ixgb_buffer) * rxdr->count; rxdr->buffer_info = vmalloc(size); - if(!rxdr->buffer_info) { + if (!rxdr->buffer_info) { DPRINTK(PROBE, ERR, "Unable to allocate receive descriptor ring\n"); return -ENOMEM; @@ -784,7 +754,7 @@ ixgb_setup_rx_resources(struct ixgb_adapter *adapter) rxdr->desc = pci_alloc_consistent(pdev, rxdr->size, &rxdr->dma); - if(!rxdr->desc) { + if (!rxdr->desc) { vfree(rxdr->buffer_info); DPRINTK(PROBE, ERR, "Unable to allocate receive descriptors\n"); @@ -813,8 +783,8 @@ ixgb_setup_rctl(struct ixgb_adapter *adapter) rctl &= ~(3 << IXGB_RCTL_MO_SHIFT); rctl |= - IXGB_RCTL_BAM | IXGB_RCTL_RDMTS_1_2 | - IXGB_RCTL_RXEN | IXGB_RCTL_CFF | + IXGB_RCTL_BAM | IXGB_RCTL_RDMTS_1_2 | + IXGB_RCTL_RXEN | IXGB_RCTL_CFF | (adapter->hw.mc_filter_type << IXGB_RCTL_MO_SHIFT); rctl |= IXGB_RCTL_SECRC; @@ -846,7 +816,6 @@ ixgb_configure_rx(struct ixgb_adapter *adapter) struct ixgb_hw *hw = &adapter->hw; u32 rctl; u32 rxcsum; - u32 rxdctl; /* make sure receives are disabled while setting up the descriptors */ @@ -868,18 +837,12 @@ ixgb_configure_rx(struct ixgb_adapter *adapter) IXGB_WRITE_REG(hw, RDH, 0); IXGB_WRITE_REG(hw, RDT, 0); - /* set up pre-fetching of receive buffers so we get some before we - * run out (default hardware behavior is to run out before fetching - * more). This sets up to fetch if HTHRESH rx descriptors are avail - * and the descriptors in hw cache are below PTHRESH. This avoids - * the hardware behavior of fetching <=512 descriptors in a single - * burst that pre-empts all other activity, usually causing fifo - * overflows. */ - /* use WTHRESH to burst write 16 descriptors or burst when RXT0 */ - rxdctl = RXDCTL_WTHRESH_DEFAULT << IXGB_RXDCTL_WTHRESH_SHIFT | - RXDCTL_HTHRESH_DEFAULT << IXGB_RXDCTL_HTHRESH_SHIFT | - RXDCTL_PTHRESH_DEFAULT << IXGB_RXDCTL_PTHRESH_SHIFT; - IXGB_WRITE_REG(hw, RXDCTL, rxdctl); + /* due to the hardware errata with RXDCTL, we are unable to use any of + * the performance enhancing features of it without causing other + * subtle bugs, some of the bugs could include receive length + * corruption at high data rates (WTHRESH > 0) and/or receive + * descriptor ring irregularites (particularly in hardware cache) */ + IXGB_WRITE_REG(hw, RXDCTL, 0); /* Enable Receive Checksum Offload for TCP and UDP */ if (adapter->rx_csum) { @@ -918,7 +881,7 @@ ixgb_free_tx_resources(struct ixgb_adapter *adapter) static void ixgb_unmap_and_free_tx_resource(struct ixgb_adapter *adapter, - struct ixgb_buffer *buffer_info) + struct ixgb_buffer *buffer_info) { struct pci_dev *pdev = adapter->pdev; @@ -926,8 +889,10 @@ ixgb_unmap_and_free_tx_resource(struct ixgb_adapter *adapter, pci_unmap_page(pdev, buffer_info->dma, buffer_info->length, PCI_DMA_TODEVICE); + /* okay to call kfree_skb here instead of kfree_skb_any because + * this is never called in interrupt context */ if (buffer_info->skb) - dev_kfree_skb_any(buffer_info->skb); + dev_kfree_skb(buffer_info->skb); buffer_info->skb = NULL; buffer_info->dma = 0; @@ -952,7 +917,7 @@ ixgb_clean_tx_ring(struct ixgb_adapter *adapter) /* Free all the Tx ring sk_buffs */ - for(i = 0; i < tx_ring->count; i++) { + for (i = 0; i < tx_ring->count; i++) { buffer_info = &tx_ring->buffer_info[i]; ixgb_unmap_and_free_tx_resource(adapter, buffer_info); } @@ -1010,9 +975,9 @@ ixgb_clean_rx_ring(struct ixgb_adapter *adapter) /* Free all the Rx ring sk_buffs */ - for(i = 0; i < rx_ring->count; i++) { + for (i = 0; i < rx_ring->count; i++) { buffer_info = &rx_ring->buffer_info[i]; - if(buffer_info->skb) { + if (buffer_info->skb) { pci_unmap_single(pdev, buffer_info->dma, @@ -1053,7 +1018,7 @@ ixgb_set_mac(struct net_device *netdev, void *p) struct ixgb_adapter *adapter = netdev_priv(netdev); struct sockaddr *addr = p; - if(!is_valid_ether_addr(addr->sa_data)) + if (!is_valid_ether_addr(addr->sa_data)) return -EADDRNOTAVAIL; memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len); @@ -1086,16 +1051,20 @@ ixgb_set_multi(struct net_device *netdev) rctl = IXGB_READ_REG(hw, RCTL); - if(netdev->flags & IFF_PROMISC) { + if (netdev->flags & IFF_PROMISC) { rctl |= (IXGB_RCTL_UPE | IXGB_RCTL_MPE); - } else if(netdev->flags & IFF_ALLMULTI) { - rctl |= IXGB_RCTL_MPE; - rctl &= ~IXGB_RCTL_UPE; + rctl &= ~IXGB_RCTL_VFE; } else { - rctl &= ~(IXGB_RCTL_UPE | IXGB_RCTL_MPE); + if (netdev->flags & IFF_ALLMULTI) { + rctl |= IXGB_RCTL_MPE; + rctl &= ~IXGB_RCTL_UPE; + } else { + rctl &= ~(IXGB_RCTL_UPE | IXGB_RCTL_MPE); + } + rctl |= IXGB_RCTL_VFE; } - if(netdev->mc_count > IXGB_MAX_NUM_MULTICAST_ADDRESSES) { + if (netdev->mc_count > IXGB_MAX_NUM_MULTICAST_ADDRESSES) { rctl |= IXGB_RCTL_MPE; IXGB_WRITE_REG(hw, RCTL, rctl); } else { @@ -1104,10 +1073,11 @@ ixgb_set_multi(struct net_device *netdev) IXGB_WRITE_REG(hw, RCTL, rctl); - for(i = 0, mc_ptr = netdev->mc_list; mc_ptr; - i++, mc_ptr = mc_ptr->next) + for (i = 0, mc_ptr = netdev->mc_list; + mc_ptr; + i++, mc_ptr = mc_ptr->next) memcpy(&mta[i * IXGB_ETH_LENGTH_OF_ADDRESS], - mc_ptr->dmi_addr, IXGB_ETH_LENGTH_OF_ADDRESS); + mc_ptr->dmi_addr, IXGB_ETH_LENGTH_OF_ADDRESS); ixgb_mc_addr_list_update(hw, mta, netdev->mc_count, 0); } @@ -1132,8 +1102,8 @@ ixgb_watchdog(unsigned long data) netif_stop_queue(netdev); } - if(adapter->hw.link_up) { - if(!netif_carrier_ok(netdev)) { + if (adapter->hw.link_up) { + if (!netif_carrier_ok(netdev)) { DPRINTK(LINK, INFO, "NIC Link is Up 10000 Mbps Full Duplex\n"); adapter->link_speed = 10000; @@ -1142,7 +1112,7 @@ ixgb_watchdog(unsigned long data) netif_wake_queue(netdev); } } else { - if(netif_carrier_ok(netdev)) { + if (netif_carrier_ok(netdev)) { adapter->link_speed = 0; adapter->link_duplex = 0; DPRINTK(LINK, INFO, "NIC Link is Down\n"); @@ -1154,8 +1124,8 @@ ixgb_watchdog(unsigned long data) ixgb_update_stats(adapter); - if(!netif_carrier_ok(netdev)) { - if(IXGB_DESC_UNUSED(txdr) + 1 < txdr->count) { + if (!netif_carrier_ok(netdev)) { + if (IXGB_DESC_UNUSED(txdr) + 1 < txdr->count) { /* 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. @@ -1227,7 +1197,7 @@ ixgb_tso(struct ixgb_adapter *adapter, struct sk_buff *skb) context_desc->hdr_len = hdr_len; context_desc->status = 0; context_desc->cmd_type_len = cpu_to_le32( - IXGB_CONTEXT_DESC_TYPE + IXGB_CONTEXT_DESC_TYPE | IXGB_CONTEXT_DESC_CMD_TSE | IXGB_CONTEXT_DESC_CMD_IP | IXGB_CONTEXT_DESC_CMD_TCP @@ -1235,7 +1205,7 @@ ixgb_tso(struct ixgb_adapter *adapter, struct sk_buff *skb) | (skb->len - (hdr_len))); - if(++i == adapter->tx_ring.count) i = 0; + if (++i == adapter->tx_ring.count) i = 0; adapter->tx_ring.next_to_use = i; return 1; @@ -1251,7 +1221,7 @@ ixgb_tx_csum(struct ixgb_adapter *adapter, struct sk_buff *skb) unsigned int i; u8 css, cso; - if(likely(skb->ip_summed == CHECKSUM_PARTIAL)) { + if (likely(skb->ip_summed == CHECKSUM_PARTIAL)) { struct ixgb_buffer *buffer_info; css = skb_transport_offset(skb); cso = css + skb->csum_offset; @@ -1273,7 +1243,7 @@ ixgb_tx_csum(struct ixgb_adapter *adapter, struct sk_buff *skb) cpu_to_le32(IXGB_CONTEXT_DESC_TYPE | IXGB_TX_DESC_CMD_IDE); - if(++i == adapter->tx_ring.count) i = 0; + if (++i == adapter->tx_ring.count) i = 0; adapter->tx_ring.next_to_use = i; return true; @@ -1302,7 +1272,7 @@ ixgb_tx_map(struct ixgb_adapter *adapter, struct sk_buff *skb, i = tx_ring->next_to_use; - while(len) { + while (len) { buffer_info = &tx_ring->buffer_info[i]; size = min(len, IXGB_MAX_DATA_PER_TXD); /* Workaround for premature desc write-backs @@ -1312,28 +1282,28 @@ 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 = pci_map_single(adapter->pdev, skb->data + offset, size, PCI_DMA_TODEVICE); - buffer_info->time_stamp = jiffies; buffer_info->next_to_watch = 0; len -= size; offset += size; count++; - if(++i == tx_ring->count) i = 0; + if (++i == tx_ring->count) i = 0; } - for(f = 0; f < nr_frags; f++) { + for (f = 0; f < nr_frags; f++) { struct skb_frag_struct *frag; frag = &skb_shinfo(skb)->frags[f]; len = frag->size; offset = 0; - while(len) { + while (len) { buffer_info = &tx_ring->buffer_info[i]; size = min(len, IXGB_MAX_DATA_PER_TXD); @@ -1344,19 +1314,19 @@ ixgb_tx_map(struct ixgb_adapter *adapter, struct sk_buff *skb, size -= 4; buffer_info->length = size; + buffer_info->time_stamp = jiffies; buffer_info->dma = pci_map_page(adapter->pdev, frag->page, frag->page_offset + offset, size, PCI_DMA_TODEVICE); - buffer_info->time_stamp = jiffies; buffer_info->next_to_watch = 0; len -= size; offset += size; count++; - if(++i == tx_ring->count) i = 0; + if (++i == tx_ring->count) i = 0; } } i = (i == 0) ? tx_ring->count - 1 : i - 1; @@ -1377,21 +1347,20 @@ ixgb_tx_queue(struct ixgb_adapter *adapter, int count, int vlan_id,int tx_flags) u8 popts = 0; unsigned int i; - if(tx_flags & IXGB_TX_FLAGS_TSO) { + if (tx_flags & IXGB_TX_FLAGS_TSO) { cmd_type_len |= IXGB_TX_DESC_CMD_TSE; popts |= (IXGB_TX_DESC_POPTS_IXSM | IXGB_TX_DESC_POPTS_TXSM); } - if(tx_flags & IXGB_TX_FLAGS_CSUM) + if (tx_flags & IXGB_TX_FLAGS_CSUM) popts |= IXGB_TX_DESC_POPTS_TXSM; - if(tx_flags & IXGB_TX_FLAGS_VLAN) { + if (tx_flags & IXGB_TX_FLAGS_VLAN) cmd_type_len |= IXGB_TX_DESC_CMD_VLE; - } i = tx_ring->next_to_use; - while(count--) { + while (count--) { buffer_info = &tx_ring->buffer_info[i]; tx_desc = IXGB_TX_DESC(*tx_ring, i); tx_desc->buff_addr = cpu_to_le64(buffer_info->dma); @@ -1401,11 +1370,11 @@ ixgb_tx_queue(struct ixgb_adapter *adapter, int count, int vlan_id,int tx_flags) tx_desc->popts = popts; tx_desc->vlan = cpu_to_le16(vlan_id); - if(++i == tx_ring->count) i = 0; + if (++i == tx_ring->count) i = 0; } - tx_desc->cmd_type_len |= cpu_to_le32(IXGB_TX_DESC_CMD_EOP - | IXGB_TX_DESC_CMD_RS ); + tx_desc->cmd_type_len |= + cpu_to_le32(IXGB_TX_DESC_CMD_EOP | IXGB_TX_DESC_CMD_RS); /* Force memory writes to complete before letting h/w * know there are new descriptors to fetch. (Only @@ -1461,7 +1430,6 @@ ixgb_xmit_frame(struct sk_buff *skb, struct net_device *netdev) struct ixgb_adapter *adapter = netdev_priv(netdev); unsigned int first; unsigned int tx_flags = 0; - unsigned long flags; int vlan_id = 0; int tso; @@ -1470,51 +1438,31 @@ ixgb_xmit_frame(struct sk_buff *skb, struct net_device *netdev) return NETDEV_TX_OK; } - if(skb->len <= 0) { - dev_kfree_skb_any(skb); + if (skb->len <= 0) { + dev_kfree_skb(skb); return 0; } -#ifdef NETIF_F_LLTX - if (!spin_trylock_irqsave(&adapter->tx_lock, flags)) { - /* Collision - tell upper layer to requeue */ - local_irq_restore(flags); - return NETDEV_TX_LOCKED; - } -#else - spin_lock_irqsave(&adapter->tx_lock, flags); -#endif - if (unlikely(ixgb_maybe_stop_tx(netdev, &adapter->tx_ring, - DESC_NEEDED))) { - netif_stop_queue(netdev); - spin_unlock_irqrestore(&adapter->tx_lock, flags); + DESC_NEEDED))) return NETDEV_TX_BUSY; - } - -#ifndef NETIF_F_LLTX - spin_unlock_irqrestore(&adapter->tx_lock, flags); -#endif - if(adapter->vlgrp && vlan_tx_tag_present(skb)) { + if (adapter->vlgrp && vlan_tx_tag_present(skb)) { tx_flags |= IXGB_TX_FLAGS_VLAN; vlan_id = vlan_tx_tag_get(skb); } first = adapter->tx_ring.next_to_use; - + tso = ixgb_tso(adapter, skb); if (tso < 0) { - dev_kfree_skb_any(skb); -#ifdef NETIF_F_LLTX - spin_unlock_irqrestore(&adapter->tx_lock, flags); -#endif + dev_kfree_skb(skb); return NETDEV_TX_OK; } if (likely(tso)) tx_flags |= IXGB_TX_FLAGS_TSO; - else if(ixgb_tx_csum(adapter, skb)) + else if (ixgb_tx_csum(adapter, skb)) tx_flags |= IXGB_TX_FLAGS_CSUM; ixgb_tx_queue(adapter, ixgb_tx_map(adapter, skb, first), vlan_id, @@ -1522,13 +1470,9 @@ ixgb_xmit_frame(struct sk_buff *skb, struct net_device *netdev) netdev->trans_start = jiffies; -#ifdef NETIF_F_LLTX /* Make sure there is space in the ring for the next send. */ ixgb_maybe_stop_tx(netdev, &adapter->tx_ring, DESC_NEEDED); - spin_unlock_irqrestore(&adapter->tx_lock, flags); - -#endif return NETDEV_TX_OK; } @@ -1588,21 +1532,25 @@ ixgb_change_mtu(struct net_device *netdev, int new_mtu) int max_frame = new_mtu + ENET_HEADER_SIZE + ENET_FCS_LENGTH; int old_max_frame = netdev->mtu + ENET_HEADER_SIZE + ENET_FCS_LENGTH; - - if((max_frame < IXGB_MIN_ENET_FRAME_SIZE_WITHOUT_FCS + ENET_FCS_LENGTH) - || (max_frame > IXGB_MAX_JUMBO_FRAME_SIZE + ENET_FCS_LENGTH)) { + /* MTU < 68 is an error for IPv4 traffic, just don't allow it */ + if ((new_mtu < 68) || + (max_frame > IXGB_MAX_JUMBO_FRAME_SIZE + ENET_FCS_LENGTH)) { DPRINTK(PROBE, ERR, "Invalid MTU setting %d\n", new_mtu); return -EINVAL; } - adapter->rx_buffer_len = max_frame; + if (old_max_frame == max_frame) + return 0; + + if (netif_running(netdev)) + ixgb_down(adapter, true); + + adapter->rx_buffer_len = max_frame + 8; /* + 8 for errata */ netdev->mtu = new_mtu; - if ((old_max_frame != max_frame) && netif_running(netdev)) { - ixgb_down(adapter, true); + if (netif_running(netdev)) ixgb_up(adapter); - } return 0; } @@ -1622,21 +1570,21 @@ ixgb_update_stats(struct ixgb_adapter *adapter) if (pci_channel_offline(pdev)) return; - if((netdev->flags & IFF_PROMISC) || (netdev->flags & IFF_ALLMULTI) || + if ((netdev->flags & IFF_PROMISC) || (netdev->flags & IFF_ALLMULTI) || (netdev->mc_count > IXGB_MAX_NUM_MULTICAST_ADDRESSES)) { u64 multi = IXGB_READ_REG(&adapter->hw, MPRCL); u32 bcast_l = IXGB_READ_REG(&adapter->hw, BPRCL); u32 bcast_h = IXGB_READ_REG(&adapter->hw, BPRCH); - u64 bcast = ((u64)bcast_h << 32) | bcast_l; + u64 bcast = ((u64)bcast_h << 32) | bcast_l; multi |= ((u64)IXGB_READ_REG(&adapter->hw, MPRCH) << 32); /* fix up multicast stats by removing broadcasts */ - if(multi >= bcast) + if (multi >= bcast) multi -= bcast; - + adapter->stats.mprcl += (multi & 0xFFFFFFFF); adapter->stats.mprch += (multi >> 32); - adapter->stats.bprcl += bcast_l; + adapter->stats.bprcl += bcast_l; adapter->stats.bprch += bcast_h; } else { adapter->stats.mprcl += IXGB_READ_REG(&adapter->hw, MPRCL); @@ -1751,41 +1699,26 @@ ixgb_intr(int irq, void *data) struct ixgb_adapter *adapter = netdev_priv(netdev); struct ixgb_hw *hw = &adapter->hw; u32 icr = IXGB_READ_REG(hw, ICR); -#ifndef CONFIG_IXGB_NAPI - unsigned int i; -#endif - if(unlikely(!icr)) + if (unlikely(!icr)) return IRQ_NONE; /* Not our interrupt */ if (unlikely(icr & (IXGB_INT_RXSEQ | IXGB_INT_LSC))) if (!test_bit(__IXGB_DOWN, &adapter->flags)) mod_timer(&adapter->watchdog_timer, jiffies); -#ifdef CONFIG_IXGB_NAPI if (netif_rx_schedule_prep(netdev, &adapter->napi)) { - /* Disable interrupts and register for poll. The flush + /* Disable interrupts and register for poll. The flush of the posted write is intentionally left out. */ IXGB_WRITE_REG(&adapter->hw, IMC, ~0); __netif_rx_schedule(netdev, &adapter->napi); } -#else - /* yes, that is actually a & and it is meant to make sure that - * every pass through this for loop checks both receive and - * transmit queues for completed descriptors, intended to - * avoid starvation issues and assist tx/rx fairness. */ - for(i = 0; i < IXGB_MAX_INTR; i++) - if(!ixgb_clean_rx_irq(adapter) & - !ixgb_clean_tx_irq(adapter)) - break; -#endif return IRQ_HANDLED; } -#ifdef CONFIG_IXGB_NAPI /** * ixgb_clean - NAPI Rx polling callback * @adapter: board private structure @@ -1804,12 +1737,12 @@ ixgb_clean(struct napi_struct *napi, int budget) /* If budget not fully consumed, exit the polling mode */ if (work_done < budget) { netif_rx_complete(netdev, napi); - ixgb_irq_enable(adapter); + if (!test_bit(__IXGB_DOWN, &adapter->flags)) + ixgb_irq_enable(adapter); } return work_done; } -#endif /** * ixgb_clean_tx_irq - Reclaim resources after transmit completes @@ -1830,15 +1763,15 @@ ixgb_clean_tx_irq(struct ixgb_adapter *adapter) eop = tx_ring->buffer_info[i].next_to_watch; eop_desc = IXGB_TX_DESC(*tx_ring, eop); - while(eop_desc->status & IXGB_TX_DESC_STATUS_DD) { + while (eop_desc->status & IXGB_TX_DESC_STATUS_DD) { for (cleaned = false; !cleaned; ) { tx_desc = IXGB_TX_DESC(*tx_ring, i); buffer_info = &tx_ring->buffer_info[i]; - if (tx_desc->popts - & (IXGB_TX_DESC_POPTS_TXSM | - IXGB_TX_DESC_POPTS_IXSM)) + if (tx_desc->popts & + (IXGB_TX_DESC_POPTS_TXSM | + IXGB_TX_DESC_POPTS_IXSM)) adapter->hw_csum_tx_good++; ixgb_unmap_and_free_tx_resource(adapter, buffer_info); @@ -1846,7 +1779,7 @@ ixgb_clean_tx_irq(struct ixgb_adapter *adapter) *(u32 *)&(tx_desc->status) = 0; cleaned = (i == eop); - if(++i == tx_ring->count) i = 0; + if (++i == tx_ring->count) i = 0; } eop = tx_ring->buffer_info[i].next_to_watch; @@ -1855,15 +1788,20 @@ ixgb_clean_tx_irq(struct ixgb_adapter *adapter) tx_ring->next_to_clean = i; - if (unlikely(netif_queue_stopped(netdev))) { - spin_lock(&adapter->tx_lock); - if (netif_queue_stopped(netdev) && netif_carrier_ok(netdev) && - (IXGB_DESC_UNUSED(tx_ring) >= DESC_NEEDED)) + if (unlikely(cleaned && netif_carrier_ok(netdev) && + IXGB_DESC_UNUSED(tx_ring) >= DESC_NEEDED)) { + /* Make sure that anybody stopping the queue after this + * sees the new next_to_clean. */ + smp_mb(); + + if (netif_queue_stopped(netdev) && + !(test_bit(__IXGB_DOWN, &adapter->flags))) { netif_wake_queue(netdev); - spin_unlock(&adapter->tx_lock); + ++adapter->restart_queue; + } } - if(adapter->detect_tx_hung) { + if (adapter->detect_tx_hung) { /* detect a transmit hang in hardware, this serializes the * check with the clearing of time_stamp and movement of i */ adapter->detect_tx_hung = false; @@ -1906,13 +1844,13 @@ ixgb_clean_tx_irq(struct ixgb_adapter *adapter) static void ixgb_rx_checksum(struct ixgb_adapter *adapter, - struct ixgb_rx_desc *rx_desc, - struct sk_buff *skb) + struct ixgb_rx_desc *rx_desc, + struct sk_buff *skb) { /* Ignore Checksum bit is set OR * TCP Checksum has not been calculated */ - if((rx_desc->status & IXGB_RX_DESC_STATUS_IXSM) || + if ((rx_desc->status & IXGB_RX_DESC_STATUS_IXSM) || (!(rx_desc->status & IXGB_RX_DESC_STATUS_TCPCS))) { skb->ip_summed = CHECKSUM_NONE; return; @@ -1920,7 +1858,7 @@ ixgb_rx_checksum(struct ixgb_adapter *adapter, /* At this point we know the hardware did the TCP checksum */ /* now look at the TCP checksum error bit */ - if(rx_desc->errors & IXGB_RX_DESC_ERRORS_TCPE) { + if (rx_desc->errors & IXGB_RX_DESC_ERRORS_TCPE) { /* let the stack verify checksum errors */ skb->ip_summed = CHECKSUM_NONE; adapter->hw_csum_rx_error++; @@ -1937,11 +1875,7 @@ ixgb_rx_checksum(struct ixgb_adapter *adapter, **/ static bool -#ifdef CONFIG_IXGB_NAPI ixgb_clean_rx_irq(struct ixgb_adapter *adapter, int *work_done, int work_to_do) -#else -ixgb_clean_rx_irq(struct ixgb_adapter *adapter) -#endif { struct ixgb_desc_ring *rx_ring = &adapter->rx_ring; struct net_device *netdev = adapter->netdev; @@ -1950,50 +1884,50 @@ ixgb_clean_rx_irq(struct ixgb_adapter *adapter) struct ixgb_buffer *buffer_info, *next_buffer, *next2_buffer; u32 length; unsigned int i, j; + int cleaned_count = 0; bool cleaned = false; i = rx_ring->next_to_clean; rx_desc = IXGB_RX_DESC(*rx_ring, i); buffer_info = &rx_ring->buffer_info[i]; - while(rx_desc->status & IXGB_RX_DESC_STATUS_DD) { - struct sk_buff *skb, *next_skb; + while (rx_desc->status & IXGB_RX_DESC_STATUS_DD) { + struct sk_buff *skb; u8 status; -#ifdef CONFIG_IXGB_NAPI - if(*work_done >= work_to_do) + if (*work_done >= work_to_do) break; (*work_done)++; -#endif status = rx_desc->status; skb = buffer_info->skb; buffer_info->skb = NULL; - prefetch(skb->data); + prefetch(skb->data - NET_IP_ALIGN); - if(++i == rx_ring->count) i = 0; + if (++i == rx_ring->count) i = 0; next_rxd = IXGB_RX_DESC(*rx_ring, i); prefetch(next_rxd); - if((j = i + 1) == rx_ring->count) j = 0; + if ((j = i + 1) == rx_ring->count) j = 0; next2_buffer = &rx_ring->buffer_info[j]; prefetch(next2_buffer); next_buffer = &rx_ring->buffer_info[i]; - next_skb = next_buffer->skb; - prefetch(next_skb); cleaned = true; + cleaned_count++; pci_unmap_single(pdev, buffer_info->dma, buffer_info->length, PCI_DMA_FROMDEVICE); + buffer_info->dma = 0; length = le16_to_cpu(rx_desc->length); + rx_desc->length = 0; - if(unlikely(!(status & IXGB_RX_DESC_STATUS_EOP))) { + if (unlikely(!(status & IXGB_RX_DESC_STATUS_EOP))) { /* All receives must fit into a single buffer */ @@ -2004,11 +1938,9 @@ ixgb_clean_rx_irq(struct ixgb_adapter *adapter) goto rxdesc_done; } - if (unlikely(rx_desc->errors - & (IXGB_RX_DESC_ERRORS_CE | IXGB_RX_DESC_ERRORS_SE - | IXGB_RX_DESC_ERRORS_P | - IXGB_RX_DESC_ERRORS_RXE))) { - + if (unlikely(rx_desc->errors & + (IXGB_RX_DESC_ERRORS_CE | IXGB_RX_DESC_ERRORS_SE | + IXGB_RX_DESC_ERRORS_P | IXGB_RX_DESC_ERRORS_RXE))) { dev_kfree_skb_irq(skb); goto rxdesc_done; } @@ -2016,8 +1948,7 @@ ixgb_clean_rx_irq(struct ixgb_adapter *adapter) /* code added for copybreak, this should improve * performance for small packets with large amounts * of reassembly being done in the stack */ -#define IXGB_CB_LENGTH 256 - if (length < IXGB_CB_LENGTH) { + if (length < copybreak) { struct sk_buff *new_skb = netdev_alloc_skb(netdev, length + NET_IP_ALIGN); if (new_skb) { @@ -2042,29 +1973,24 @@ ixgb_clean_rx_irq(struct ixgb_adapter *adapter) ixgb_rx_checksum(adapter, rx_desc, skb); skb->protocol = eth_type_trans(skb, netdev); -#ifdef CONFIG_IXGB_NAPI - if(adapter->vlgrp && (status & IXGB_RX_DESC_STATUS_VP)) { + if (adapter->vlgrp && (status & IXGB_RX_DESC_STATUS_VP)) { vlan_hwaccel_receive_skb(skb, adapter->vlgrp, - le16_to_cpu(rx_desc->special) & - IXGB_RX_DESC_SPECIAL_VLAN_MASK); + le16_to_cpu(rx_desc->special)); } else { netif_receive_skb(skb); } -#else /* CONFIG_IXGB_NAPI */ - if(adapter->vlgrp && (status & IXGB_RX_DESC_STATUS_VP)) { - vlan_hwaccel_rx(skb, adapter->vlgrp, - le16_to_cpu(rx_desc->special) & - IXGB_RX_DESC_SPECIAL_VLAN_MASK); - } else { - netif_rx(skb); - } -#endif /* CONFIG_IXGB_NAPI */ netdev->last_rx = jiffies; rxdesc_done: /* clean up descriptor, might be written over by hw */ rx_desc->status = 0; + /* return some buffers to hardware, one at a time is too slow */ + if (unlikely(cleaned_count >= IXGB_RX_BUFFER_WRITE)) { + ixgb_alloc_rx_buffers(adapter, cleaned_count); + cleaned_count = 0; + } + /* use prefetched values */ rx_desc = next_rxd; buffer_info = next_buffer; @@ -2072,7 +1998,9 @@ rxdesc_done: rx_ring->next_to_clean = i; - ixgb_alloc_rx_buffers(adapter); + cleaned_count = IXGB_DESC_UNUSED(rx_ring); + if (cleaned_count) + ixgb_alloc_rx_buffers(adapter, cleaned_count); return cleaned; } @@ -2083,7 +2011,7 @@ rxdesc_done: **/ static void -ixgb_alloc_rx_buffers(struct ixgb_adapter *adapter) +ixgb_alloc_rx_buffers(struct ixgb_adapter *adapter, int cleaned_count) { struct ixgb_desc_ring *rx_ring = &adapter->rx_ring; struct net_device *netdev = adapter->netdev; @@ -2100,7 +2028,7 @@ ixgb_alloc_rx_buffers(struct ixgb_adapter *adapter) /* leave three descriptors unused */ - while(--cleancount > 2) { + while (--cleancount > 2 && cleaned_count--) { /* recycle! its good for you */ skb = buffer_info->skb; if (skb) { @@ -2133,12 +2061,12 @@ map_skb: rx_desc = IXGB_RX_DESC(*rx_ring, i); rx_desc->buff_addr = cpu_to_le64(buffer_info->dma); /* guarantee DD bit not set now before h/w gets descriptor - * this is the rest of the workaround for h/w double + * this is the rest of the workaround for h/w double * writeback. */ rx_desc->status = 0; - if(++i == rx_ring->count) i = 0; + if (++i == rx_ring->count) i = 0; buffer_info = &rx_ring->buffer_info[i]; } @@ -2158,7 +2086,7 @@ map_skb: /** * ixgb_vlan_rx_register - enables or disables vlan tagging/stripping. - * + * * @param netdev network interface device structure * @param grp indicates to enable or disable tagging/stripping **/ @@ -2171,7 +2099,7 @@ ixgb_vlan_rx_register(struct net_device *netdev, struct vlan_group *grp) ixgb_irq_disable(adapter); adapter->vlgrp = grp; - if(grp) { + if (grp) { /* enable VLAN tag insert/strip */ ctrl = IXGB_READ_REG(&adapter->hw, CTRL0); ctrl |= IXGB_CTRL0_VME; @@ -2180,7 +2108,6 @@ ixgb_vlan_rx_register(struct net_device *netdev, struct vlan_group *grp) /* enable VLAN receive filtering */ rctl = IXGB_READ_REG(&adapter->hw, RCTL); - rctl |= IXGB_RCTL_VFE; rctl &= ~IXGB_RCTL_CFIEN; IXGB_WRITE_REG(&adapter->hw, RCTL, rctl); } else { @@ -2189,12 +2116,6 @@ ixgb_vlan_rx_register(struct net_device *netdev, struct vlan_group *grp) ctrl = IXGB_READ_REG(&adapter->hw, CTRL0); ctrl &= ~IXGB_CTRL0_VME; IXGB_WRITE_REG(&adapter->hw, CTRL0, ctrl); - - /* disable VLAN filtering */ - - rctl = IXGB_READ_REG(&adapter->hw, RCTL); - rctl &= ~IXGB_RCTL_VFE; - IXGB_WRITE_REG(&adapter->hw, RCTL, rctl); } /* don't enable interrupts unless we are UP */ @@ -2243,10 +2164,10 @@ ixgb_restore_vlan(struct ixgb_adapter *adapter) { ixgb_vlan_rx_register(adapter->netdev, adapter->vlgrp); - if(adapter->vlgrp) { + if (adapter->vlgrp) { u16 vid; - for(vid = 0; vid < VLAN_GROUP_ARRAY_LEN; vid++) { - if(!vlan_group_get_device(adapter->vlgrp, vid)) + for (vid = 0; vid < VLAN_GROUP_ARRAY_LEN; vid++) { + if (!vlan_group_get_device(adapter->vlgrp, vid)) continue; ixgb_vlan_rx_add_vid(adapter->netdev, vid); } @@ -2278,13 +2199,13 @@ static void ixgb_netpoll(struct net_device *dev) * This callback is called by the PCI subsystem whenever * a PCI bus error is detected. */ -static pci_ers_result_t ixgb_io_error_detected (struct pci_dev *pdev, - enum pci_channel_state state) +static pci_ers_result_t ixgb_io_error_detected(struct pci_dev *pdev, + enum pci_channel_state state) { struct net_device *netdev = pci_get_drvdata(pdev); struct ixgb_adapter *adapter = netdev_priv(netdev); - if(netif_running(netdev)) + if (netif_running(netdev)) ixgb_down(adapter, true); pci_disable_device(pdev); @@ -2297,17 +2218,17 @@ static pci_ers_result_t ixgb_io_error_detected (struct pci_dev *pdev, * ixgb_io_slot_reset - called after the pci bus has been reset. * @pdev pointer to pci device with error * - * This callback is called after the PCI buss has been reset. + * This callback is called after the PCI bus has been reset. * Basically, this tries to restart the card from scratch. * This is a shortened version of the device probe/discovery code, * it resembles the first-half of the ixgb_probe() routine. */ -static pci_ers_result_t ixgb_io_slot_reset (struct pci_dev *pdev) +static pci_ers_result_t ixgb_io_slot_reset(struct pci_dev *pdev) { struct net_device *netdev = pci_get_drvdata(pdev); struct ixgb_adapter *adapter = netdev_priv(netdev); - if(pci_enable_device(pdev)) { + if (pci_enable_device(pdev)) { DPRINTK(PROBE, ERR, "Cannot re-enable PCI device after reset.\n"); return PCI_ERS_RESULT_DISCONNECT; } @@ -2323,14 +2244,14 @@ static pci_ers_result_t ixgb_io_slot_reset (struct pci_dev *pdev) ixgb_reset(adapter); /* Make sure the EEPROM is good */ - if(!ixgb_validate_eeprom_checksum(&adapter->hw)) { + if (!ixgb_validate_eeprom_checksum(&adapter->hw)) { DPRINTK(PROBE, ERR, "After reset, the EEPROM checksum is not valid.\n"); return PCI_ERS_RESULT_DISCONNECT; } ixgb_get_ee_mac_addr(&adapter->hw, netdev->dev_addr); memcpy(netdev->perm_addr, netdev->dev_addr, netdev->addr_len); - if(!is_valid_ether_addr(netdev->perm_addr)) { + if (!is_valid_ether_addr(netdev->perm_addr)) { DPRINTK(PROBE, ERR, "After reset, invalid MAC address.\n"); return PCI_ERS_RESULT_DISCONNECT; } @@ -2346,15 +2267,15 @@ static pci_ers_result_t ixgb_io_slot_reset (struct pci_dev *pdev) * normal operation. Implementation resembles the second-half * of the ixgb_probe() routine. */ -static void ixgb_io_resume (struct pci_dev *pdev) +static void ixgb_io_resume(struct pci_dev *pdev) { struct net_device *netdev = pci_get_drvdata(pdev); struct ixgb_adapter *adapter = netdev_priv(netdev); pci_set_master(pdev); - if(netif_running(netdev)) { - if(ixgb_up(adapter)) { + if (netif_running(netdev)) { + if (ixgb_up(adapter)) { printk ("ixgb: can't bring device back up after reset\n"); return; } diff --git a/drivers/net/ixgb/ixgb_osdep.h b/drivers/net/ixgb/ixgb_osdep.h index 4be1b273e1b8..d92e72bd627a 100644 --- a/drivers/net/ixgb/ixgb_osdep.h +++ b/drivers/net/ixgb/ixgb_osdep.h @@ -1,7 +1,7 @@ /******************************************************************************* Intel PRO/10GbE Linux driver - Copyright(c) 1999 - 2006 Intel Corporation. + Copyright(c) 1999 - 2008 Intel Corporation. This program is free software; you can redistribute it and/or modify it under the terms and conditions of the GNU General Public License, @@ -40,7 +40,7 @@ #include <linux/sched.h> #undef ASSERT -#define ASSERT(x) if(!(x)) BUG() +#define ASSERT(x) if (!(x)) BUG() #define MSGOUT(S, A, B) printk(KERN_DEBUG S "\n", A, B) #ifdef DBG diff --git a/drivers/net/ixgb/ixgb_param.c b/drivers/net/ixgb/ixgb_param.c index 865d14d6e5a7..af35e1ddadd6 100644 --- a/drivers/net/ixgb/ixgb_param.c +++ b/drivers/net/ixgb/ixgb_param.c @@ -1,7 +1,7 @@ /******************************************************************************* Intel PRO/10GbE Linux driver - Copyright(c) 1999 - 2006 Intel Corporation. + Copyright(c) 1999 - 2008 Intel Corporation. This program is free software; you can redistribute it and/or modify it under the terms and conditions of the GNU General Public License, @@ -136,7 +136,7 @@ IXGB_PARAM(RxFCLowThresh, "Receive Flow Control Low Threshold"); /* Flow control request timeout (how long to pause the link partner's tx) * (PAP 15:0) * - * Valid Range: 1 - 65535 + * Valid Range: 1 - 65535 * * Default Value: 65535 (0xffff) (we'll send an xon if we recover) */ @@ -200,7 +200,7 @@ struct ixgb_option { static int __devinit ixgb_validate_option(unsigned int *value, const struct ixgb_option *opt) { - if(*value == OPTION_UNSET) { + if (*value == OPTION_UNSET) { *value = opt->def; return 0; } @@ -217,7 +217,7 @@ ixgb_validate_option(unsigned int *value, const struct ixgb_option *opt) } break; case range_option: - if(*value >= opt->arg.r.min && *value <= opt->arg.r.max) { + if (*value >= opt->arg.r.min && *value <= opt->arg.r.max) { printk(KERN_INFO "%s set to %i\n", opt->name, *value); return 0; } @@ -226,10 +226,10 @@ ixgb_validate_option(unsigned int *value, const struct ixgb_option *opt) int i; struct ixgb_opt_list *ent; - for(i = 0; i < opt->arg.l.nr; i++) { + for (i = 0; i < opt->arg.l.nr; i++) { ent = &opt->arg.l.p[i]; - if(*value == ent->i) { - if(ent->str[0] != '\0') + if (*value == ent->i) { + if (ent->str[0] != '\0') printk(KERN_INFO "%s\n", ent->str); return 0; } @@ -260,7 +260,7 @@ void __devinit ixgb_check_options(struct ixgb_adapter *adapter) { int bd = adapter->bd_number; - if(bd >= IXGB_MAX_NIC) { + if (bd >= IXGB_MAX_NIC) { printk(KERN_NOTICE "Warning: no configuration for board #%i\n", bd); printk(KERN_NOTICE "Using defaults for all values\n"); @@ -277,7 +277,7 @@ ixgb_check_options(struct ixgb_adapter *adapter) }; struct ixgb_desc_ring *tx_ring = &adapter->tx_ring; - if(num_TxDescriptors > bd) { + if (num_TxDescriptors > bd) { tx_ring->count = TxDescriptors[bd]; ixgb_validate_option(&tx_ring->count, &opt); } else { @@ -296,7 +296,7 @@ ixgb_check_options(struct ixgb_adapter *adapter) }; struct ixgb_desc_ring *rx_ring = &adapter->rx_ring; - if(num_RxDescriptors > bd) { + if (num_RxDescriptors > bd) { rx_ring->count = RxDescriptors[bd]; ixgb_validate_option(&rx_ring->count, &opt); } else { @@ -312,7 +312,7 @@ ixgb_check_options(struct ixgb_adapter *adapter) .def = OPTION_ENABLED }; - if(num_XsumRX > bd) { + if (num_XsumRX > bd) { unsigned int rx_csum = XsumRX[bd]; ixgb_validate_option(&rx_csum, &opt); adapter->rx_csum = rx_csum; @@ -338,7 +338,7 @@ ixgb_check_options(struct ixgb_adapter *adapter) .p = fc_list }} }; - if(num_FlowControl > bd) { + if (num_FlowControl > bd) { unsigned int fc = FlowControl[bd]; ixgb_validate_option(&fc, &opt); adapter->hw.fc.type = fc; @@ -356,14 +356,14 @@ ixgb_check_options(struct ixgb_adapter *adapter) .max = MAX_FCRTH}} }; - if(num_RxFCHighThresh > bd) { + if (num_RxFCHighThresh > bd) { adapter->hw.fc.high_water = RxFCHighThresh[bd]; ixgb_validate_option(&adapter->hw.fc.high_water, &opt); } else { adapter->hw.fc.high_water = opt.def; } if (!(adapter->hw.fc.type & ixgb_fc_tx_pause) ) - printk (KERN_INFO + printk(KERN_INFO "Ignoring RxFCHighThresh when no RxFC\n"); } { /* Receive Flow Control Low Threshold */ @@ -376,14 +376,14 @@ ixgb_check_options(struct ixgb_adapter *adapter) .max = MAX_FCRTL}} }; - if(num_RxFCLowThresh > bd) { + if (num_RxFCLowThresh > bd) { adapter->hw.fc.low_water = RxFCLowThresh[bd]; ixgb_validate_option(&adapter->hw.fc.low_water, &opt); } else { adapter->hw.fc.low_water = opt.def; } if (!(adapter->hw.fc.type & ixgb_fc_tx_pause) ) - printk (KERN_INFO + printk(KERN_INFO "Ignoring RxFCLowThresh when no RxFC\n"); } { /* Flow Control Pause Time Request*/ @@ -396,7 +396,7 @@ ixgb_check_options(struct ixgb_adapter *adapter) .max = MAX_FCPAUSE}} }; - if(num_FCReqTimeout > bd) { + if (num_FCReqTimeout > bd) { unsigned int pause_time = FCReqTimeout[bd]; ixgb_validate_option(&pause_time, &opt); adapter->hw.fc.pause_time = pause_time; @@ -404,7 +404,7 @@ ixgb_check_options(struct ixgb_adapter *adapter) adapter->hw.fc.pause_time = opt.def; } if (!(adapter->hw.fc.type & ixgb_fc_tx_pause) ) - printk (KERN_INFO + printk(KERN_INFO "Ignoring FCReqTimeout when no RxFC\n"); } /* high low and spacing check for rx flow control thresholds */ @@ -412,7 +412,7 @@ ixgb_check_options(struct ixgb_adapter *adapter) /* high must be greater than low */ if (adapter->hw.fc.high_water < (adapter->hw.fc.low_water + 8)) { /* set defaults */ - printk (KERN_INFO + printk(KERN_INFO "RxFCHighThresh must be >= (RxFCLowThresh + 8), " "Using Defaults\n"); adapter->hw.fc.high_water = DEFAULT_FCRTH; @@ -429,7 +429,7 @@ ixgb_check_options(struct ixgb_adapter *adapter) .max = MAX_RDTR}} }; - if(num_RxIntDelay > bd) { + if (num_RxIntDelay > bd) { adapter->rx_int_delay = RxIntDelay[bd]; ixgb_validate_option(&adapter->rx_int_delay, &opt); } else { @@ -446,7 +446,7 @@ ixgb_check_options(struct ixgb_adapter *adapter) .max = MAX_TIDV}} }; - if(num_TxIntDelay > bd) { + if (num_TxIntDelay > bd) { adapter->tx_int_delay = TxIntDelay[bd]; ixgb_validate_option(&adapter->tx_int_delay, &opt); } else { @@ -462,7 +462,7 @@ ixgb_check_options(struct ixgb_adapter *adapter) .def = OPTION_ENABLED }; - if(num_IntDelayEnable > bd) { + if (num_IntDelayEnable > bd) { unsigned int ide = IntDelayEnable[bd]; ixgb_validate_option(&ide, &opt); adapter->tx_int_delay_enable = ide; diff --git a/drivers/net/ixgbe/ixgbe.h b/drivers/net/ixgbe/ixgbe.h index d98113472a89..956914a5028d 100644 --- a/drivers/net/ixgbe/ixgbe.h +++ b/drivers/net/ixgbe/ixgbe.h @@ -32,6 +32,7 @@ #include <linux/types.h> #include <linux/pci.h> #include <linux/netdevice.h> +#include <linux/inet_lro.h> #include "ixgbe_type.h" #include "ixgbe_common.h" @@ -100,6 +101,9 @@ #define IXGBE_TX_FLAGS_VLAN_MASK 0xffff0000 #define IXGBE_TX_FLAGS_VLAN_SHIFT 16 +#define IXGBE_MAX_LRO_DESCRIPTORS 8 +#define IXGBE_MAX_LRO_AGGREGATE 32 + /* wrapper around a pointer to a socket buffer, * so a DMA handle can be stored along with the buffer */ struct ixgbe_tx_buffer { @@ -150,6 +154,8 @@ struct ixgbe_ring { /* cpu for tx queue */ int cpu; #endif + struct net_lro_mgr lro_mgr; + bool lro_used; struct ixgbe_queue_stats stats; u8 v_idx; /* maps directly to the index for this ring in the hardware * vector array, can also be used for finding the bit in EICR @@ -287,6 +293,9 @@ struct ixgbe_adapter { unsigned long state; u64 tx_busy; + u64 lro_aggregated; + u64 lro_flushed; + u64 lro_no_desc; }; enum ixbge_state_t { diff --git a/drivers/net/ixgbe/ixgbe_ethtool.c b/drivers/net/ixgbe/ixgbe_ethtool.c index 4e463778bcfd..3efe5dda10af 100644 --- a/drivers/net/ixgbe/ixgbe_ethtool.c +++ b/drivers/net/ixgbe/ixgbe_ethtool.c @@ -90,6 +90,8 @@ static struct ixgbe_stats ixgbe_gstrings_stats[] = { {"rx_header_split", IXGBE_STAT(rx_hdr_split)}, {"alloc_rx_page_failed", IXGBE_STAT(alloc_rx_page_failed)}, {"alloc_rx_buff_failed", IXGBE_STAT(alloc_rx_buff_failed)}, + {"lro_aggregated", IXGBE_STAT(lro_aggregated)}, + {"lro_flushed", IXGBE_STAT(lro_flushed)}, }; #define IXGBE_QUEUE_STATS_LEN \ @@ -250,22 +252,10 @@ static int ixgbe_set_tso(struct net_device *netdev, u32 data) netdev->features |= NETIF_F_TSO; netdev->features |= NETIF_F_TSO6; } else { -#ifdef CONFIG_NETDEVICES_MULTIQUEUE - struct ixgbe_adapter *adapter = netdev_priv(netdev); - int i; -#endif - netif_stop_queue(netdev); -#ifdef CONFIG_NETDEVICES_MULTIQUEUE - for (i = 0; i < adapter->num_tx_queues; i++) - netif_stop_subqueue(netdev, i); -#endif + netif_tx_stop_all_queues(netdev); netdev->features &= ~NETIF_F_TSO; netdev->features &= ~NETIF_F_TSO6; -#ifdef CONFIG_NETDEVICES_MULTIQUEUE - for (i = 0; i < adapter->num_tx_queues; i++) - netif_start_subqueue(netdev, i); -#endif - netif_start_queue(netdev); + netif_tx_start_all_queues(netdev); } return 0; } @@ -787,6 +777,7 @@ static void ixgbe_get_ethtool_stats(struct net_device *netdev, int stat_count = sizeof(struct ixgbe_queue_stats) / sizeof(u64); int j, k; int i; + u64 aggregated = 0, flushed = 0, no_desc = 0; ixgbe_update_stats(adapter); for (i = 0; i < IXGBE_GLOBAL_STATS_LEN; i++) { @@ -801,11 +792,17 @@ static void ixgbe_get_ethtool_stats(struct net_device *netdev, i += k; } for (j = 0; j < adapter->num_rx_queues; j++) { + aggregated += adapter->rx_ring[j].lro_mgr.stats.aggregated; + flushed += adapter->rx_ring[j].lro_mgr.stats.flushed; + no_desc += adapter->rx_ring[j].lro_mgr.stats.no_desc; queue_stat = (u64 *)&adapter->rx_ring[j].stats; for (k = 0; k < stat_count; k++) data[i + k] = queue_stat[k]; i += k; } + adapter->lro_aggregated = aggregated; + adapter->lro_flushed = flushed; + adapter->lro_no_desc = no_desc; } static void ixgbe_get_strings(struct net_device *netdev, u32 stringset, @@ -973,6 +970,8 @@ static struct ethtool_ops ixgbe_ethtool_ops = { .get_ethtool_stats = ixgbe_get_ethtool_stats, .get_coalesce = ixgbe_get_coalesce, .set_coalesce = ixgbe_set_coalesce, + .get_flags = ethtool_op_get_flags, + .set_flags = ethtool_op_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 8f0460901153..be7b723c924f 100644 --- a/drivers/net/ixgbe/ixgbe_main.c +++ b/drivers/net/ixgbe/ixgbe_main.c @@ -266,28 +266,16 @@ static bool ixgbe_clean_tx_irq(struct ixgbe_adapter *adapter, * sees the new next_to_clean. */ smp_mb(); -#ifdef CONFIG_NETDEVICES_MULTIQUEUE if (__netif_subqueue_stopped(netdev, tx_ring->queue_index) && !test_bit(__IXGBE_DOWN, &adapter->state)) { netif_wake_subqueue(netdev, tx_ring->queue_index); adapter->restart_queue++; } -#else - if (netif_queue_stopped(netdev) && - !test_bit(__IXGBE_DOWN, &adapter->state)) { - netif_wake_queue(netdev); - adapter->restart_queue++; - } -#endif } if (adapter->detect_tx_hung) if (ixgbe_check_tx_hang(adapter, tx_ring, eop, eop_desc)) -#ifdef CONFIG_NETDEVICES_MULTIQUEUE netif_stop_subqueue(netdev, tx_ring->queue_index); -#else - netif_stop_queue(netdev); -#endif if (total_tx_packets >= tx_ring->work_limit) IXGBE_WRITE_REG(&adapter->hw, IXGBE_EICS, tx_ring->eims_value); @@ -389,24 +377,39 @@ static int __ixgbe_notify_dca(struct device *dev, void *data) * ixgbe_receive_skb - Send a completed packet up the stack * @adapter: board private structure * @skb: packet to send up - * @is_vlan: packet has a VLAN tag - * @tag: VLAN tag from descriptor + * @status: hardware indication of status of receive + * @rx_ring: rx descriptor ring (for a specific queue) to setup + * @rx_desc: rx descriptor **/ static void ixgbe_receive_skb(struct ixgbe_adapter *adapter, - struct sk_buff *skb, bool is_vlan, - u16 tag) + struct sk_buff *skb, u8 status, + struct ixgbe_ring *ring, + union ixgbe_adv_rx_desc *rx_desc) { - if (!(adapter->flags & IXGBE_FLAG_IN_NETPOLL)) { - if (adapter->vlgrp && is_vlan) - vlan_hwaccel_receive_skb(skb, adapter->vlgrp, tag); - else - netif_receive_skb(skb); - } else { + bool is_vlan = (status & IXGBE_RXD_STAT_VP); + u16 tag = le16_to_cpu(rx_desc->wb.upper.vlan); + if (adapter->netdev->features & NETIF_F_LRO && + skb->ip_summed == CHECKSUM_UNNECESSARY) { if (adapter->vlgrp && is_vlan) - vlan_hwaccel_rx(skb, adapter->vlgrp, tag); + lro_vlan_hwaccel_receive_skb(&ring->lro_mgr, skb, + adapter->vlgrp, tag, + rx_desc); else - netif_rx(skb); + lro_receive_skb(&ring->lro_mgr, skb, rx_desc); + ring->lro_used = true; + } else { + if (!(adapter->flags & IXGBE_FLAG_IN_NETPOLL)) { + if (adapter->vlgrp && is_vlan) + vlan_hwaccel_receive_skb(skb, adapter->vlgrp, tag); + else + netif_receive_skb(skb); + } else { + if (adapter->vlgrp && is_vlan) + vlan_hwaccel_rx(skb, adapter->vlgrp, tag); + else + netif_rx(skb); + } } } @@ -546,8 +549,8 @@ static bool ixgbe_clean_rx_irq(struct ixgbe_adapter *adapter, struct sk_buff *skb; unsigned int i; u32 upper_len, len, staterr; - u16 hdr_info, vlan_tag; - bool is_vlan, cleaned = false; + u16 hdr_info; + bool cleaned = false; int cleaned_count = 0; unsigned int total_rx_bytes = 0, total_rx_packets = 0; @@ -556,8 +559,6 @@ static bool ixgbe_clean_rx_irq(struct ixgbe_adapter *adapter, rx_desc = IXGBE_RX_DESC_ADV(*rx_ring, i); staterr = le32_to_cpu(rx_desc->wb.upper.status_error); rx_buffer_info = &rx_ring->rx_buffer_info[i]; - is_vlan = (staterr & IXGBE_RXD_STAT_VP); - vlan_tag = le16_to_cpu(rx_desc->wb.upper.vlan); while (staterr & IXGBE_RXD_STAT_DD) { if (*work_done >= work_to_do) @@ -635,7 +636,7 @@ static bool ixgbe_clean_rx_irq(struct ixgbe_adapter *adapter, total_rx_packets++; skb->protocol = eth_type_trans(skb, netdev); - ixgbe_receive_skb(adapter, skb, is_vlan, vlan_tag); + ixgbe_receive_skb(adapter, skb, staterr, rx_ring, rx_desc); netdev->last_rx = jiffies; next_desc: @@ -652,8 +653,11 @@ next_desc: rx_buffer_info = next_buffer; staterr = le32_to_cpu(rx_desc->wb.upper.status_error); - is_vlan = (staterr & IXGBE_RXD_STAT_VP); - vlan_tag = le16_to_cpu(rx_desc->wb.upper.vlan); + } + + if (rx_ring->lro_used) { + lro_flush_all(&rx_ring->lro_mgr); + rx_ring->lro_used = false; } rx_ring->next_to_clean = i; @@ -1382,6 +1386,33 @@ static void ixgbe_configure_tx(struct ixgbe_adapter *adapter) #define IXGBE_SRRCTL_BSIZEHDRSIZE_SHIFT 2 /** + * ixgbe_get_skb_hdr - helper function for LRO header processing + * @skb: pointer to sk_buff to be added to LRO packet + * @iphdr: pointer to tcp header structure + * @tcph: pointer to tcp header structure + * @hdr_flags: pointer to header flags + * @priv: private data + **/ +static int ixgbe_get_skb_hdr(struct sk_buff *skb, void **iphdr, void **tcph, + u64 *hdr_flags, void *priv) +{ + union ixgbe_adv_rx_desc *rx_desc = priv; + + /* Verify that this is a valid IPv4 TCP packet */ + if (!(rx_desc->wb.lower.lo_dword.pkt_info & + (IXGBE_RXDADV_PKTTYPE_IPV4 | IXGBE_RXDADV_PKTTYPE_TCP))) + return -1; + + /* Set network headers */ + skb_reset_network_header(skb); + skb_set_transport_header(skb, ip_hdrlen(skb)); + *iphdr = ip_hdr(skb); + *tcph = tcp_hdr(skb); + *hdr_flags = LRO_IPV4 | LRO_TCP; + return 0; +} + +/** * ixgbe_configure_rx - Configure 8254x Receive Unit after Reset * @adapter: board private structure * @@ -1470,6 +1501,17 @@ static void ixgbe_configure_rx(struct ixgbe_adapter *adapter) adapter->rx_ring[i].tail = IXGBE_RDT(i); } + /* Intitial LRO Settings */ + adapter->rx_ring[i].lro_mgr.max_aggr = IXGBE_MAX_LRO_AGGREGATE; + adapter->rx_ring[i].lro_mgr.max_desc = IXGBE_MAX_LRO_DESCRIPTORS; + adapter->rx_ring[i].lro_mgr.get_skb_header = ixgbe_get_skb_hdr; + adapter->rx_ring[i].lro_mgr.features = LRO_F_EXTRACT_VLAN_ID; + if (!(adapter->flags & IXGBE_FLAG_IN_NETPOLL)) + adapter->rx_ring[i].lro_mgr.features |= LRO_F_NAPI; + adapter->rx_ring[i].lro_mgr.dev = adapter->netdev; + adapter->rx_ring[i].lro_mgr.ip_summed = CHECKSUM_UNNECESSARY; + adapter->rx_ring[i].lro_mgr.ip_summed_aggr = CHECKSUM_UNNECESSARY; + if (adapter->flags & IXGBE_FLAG_RSS_ENABLED) { /* Fill out redirection table */ for (i = 0, j = 0; i < 128; i++, j++) { @@ -1532,7 +1574,7 @@ static void ixgbe_vlan_rx_register(struct net_device *netdev, if (grp) { /* enable VLAN tag insert/strip */ ctrl = IXGBE_READ_REG(&adapter->hw, IXGBE_VLNCTRL); - ctrl |= IXGBE_VLNCTRL_VME | IXGBE_VLNCTRL_VFE; + ctrl |= IXGBE_VLNCTRL_VME; ctrl &= ~IXGBE_VLNCTRL_CFIEN; IXGBE_WRITE_REG(&adapter->hw, IXGBE_VLNCTRL, ctrl); } @@ -1603,11 +1645,15 @@ static void ixgbe_set_multi(struct net_device *netdev) if (netdev->flags & IFF_PROMISC) { fctrl |= (IXGBE_FCTRL_UPE | IXGBE_FCTRL_MPE); - } else if (netdev->flags & IFF_ALLMULTI) { - fctrl |= IXGBE_FCTRL_MPE; - fctrl &= ~IXGBE_FCTRL_UPE; + fctrl &= ~IXGBE_VLNCTRL_VFE; } else { - fctrl &= ~(IXGBE_FCTRL_UPE | IXGBE_FCTRL_MPE); + if (netdev->flags & IFF_ALLMULTI) { + fctrl |= IXGBE_FCTRL_MPE; + fctrl &= ~IXGBE_FCTRL_UPE; + } else { + fctrl &= ~(IXGBE_FCTRL_UPE | IXGBE_FCTRL_MPE); + } + fctrl |= IXGBE_VLNCTRL_VFE; } IXGBE_WRITE_REG(hw, IXGBE_FCTRL, fctrl); @@ -1967,7 +2013,7 @@ void ixgbe_down(struct ixgbe_adapter *adapter) del_timer_sync(&adapter->watchdog_timer); netif_carrier_off(netdev); - netif_stop_queue(netdev); + netif_tx_stop_all_queues(netdev); if (!pci_channel_offline(adapter->pdev)) ixgbe_reset(adapter); @@ -2138,11 +2184,7 @@ static void __devinit ixgbe_set_num_queues(struct ixgbe_adapter *adapter) case (IXGBE_FLAG_RSS_ENABLED): rss_m = 0xF; nrq = rss_i; -#ifdef CONFIG_NETDEVICES_MULTIQUEUE ntq = rss_i; -#else - ntq = 1; -#endif break; case 0: default: @@ -2316,10 +2358,8 @@ try_msi: } out: -#ifdef CONFIG_NETDEVICES_MULTIQUEUE /* Notify the stack of the (possibly) reduced Tx Queue count. */ - adapter->netdev->egress_subqueue_count = adapter->num_tx_queues; -#endif + adapter->netdev->real_num_tx_queues = adapter->num_tx_queues; return err; } @@ -2490,12 +2530,18 @@ int ixgbe_setup_rx_resources(struct ixgbe_adapter *adapter, struct pci_dev *pdev = adapter->pdev; int size; + size = sizeof(struct net_lro_desc) * IXGBE_MAX_LRO_DESCRIPTORS; + rxdr->lro_mgr.lro_arr = vmalloc(size); + if (!rxdr->lro_mgr.lro_arr) + return -ENOMEM; + memset(rxdr->lro_mgr.lro_arr, 0, size); + size = sizeof(struct ixgbe_rx_buffer) * rxdr->count; rxdr->rx_buffer_info = vmalloc(size); if (!rxdr->rx_buffer_info) { DPRINTK(PROBE, ERR, "vmalloc allocation failed for the rx desc ring\n"); - return -ENOMEM; + goto alloc_failed; } memset(rxdr->rx_buffer_info, 0, size); @@ -2509,13 +2555,18 @@ int ixgbe_setup_rx_resources(struct ixgbe_adapter *adapter, DPRINTK(PROBE, ERR, "Memory allocation failed for the rx desc ring\n"); vfree(rxdr->rx_buffer_info); - return -ENOMEM; + goto alloc_failed; } rxdr->next_to_clean = 0; rxdr->next_to_use = 0; return 0; + +alloc_failed: + vfree(rxdr->lro_mgr.lro_arr); + rxdr->lro_mgr.lro_arr = NULL; + return -ENOMEM; } /** @@ -2566,6 +2617,9 @@ static void ixgbe_free_rx_resources(struct ixgbe_adapter *adapter, { struct pci_dev *pdev = adapter->pdev; + vfree(rx_ring->lro_mgr.lro_arr); + rx_ring->lro_mgr.lro_arr = NULL; + ixgbe_clean_rx_ring(adapter, rx_ring); vfree(rx_ring->rx_buffer_info); @@ -2711,6 +2765,8 @@ static int ixgbe_open(struct net_device *netdev) if (err) goto err_up; + netif_tx_start_all_queues(netdev); + return 0; err_up: @@ -2842,9 +2898,6 @@ static void ixgbe_watchdog(unsigned long data) struct net_device *netdev = adapter->netdev; bool link_up; u32 link_speed = 0; -#ifdef CONFIG_NETDEVICES_MULTIQUEUE - int i; -#endif adapter->hw.mac.ops.check_link(&adapter->hw, &(link_speed), &link_up); @@ -2865,11 +2918,7 @@ static void ixgbe_watchdog(unsigned long data) (FLOW_TX ? "TX" : "None")))); netif_carrier_on(netdev); - netif_wake_queue(netdev); -#ifdef CONFIG_NETDEVICES_MULTIQUEUE - for (i = 0; i < adapter->num_tx_queues; i++) - netif_wake_subqueue(netdev, i); -#endif + netif_tx_wake_all_queues(netdev); } else { /* Force detection of hung controller */ adapter->detect_tx_hung = true; @@ -2878,7 +2927,7 @@ static void ixgbe_watchdog(unsigned long data) if (netif_carrier_ok(netdev)) { DPRINTK(LINK, INFO, "NIC Link is Down\n"); netif_carrier_off(netdev); - netif_stop_queue(netdev); + netif_tx_stop_all_queues(netdev); } } @@ -3196,11 +3245,7 @@ static int __ixgbe_maybe_stop_tx(struct net_device *netdev, { struct ixgbe_adapter *adapter = netdev_priv(netdev); -#ifdef CONFIG_NETDEVICES_MULTIQUEUE netif_stop_subqueue(netdev, tx_ring->queue_index); -#else - netif_stop_queue(netdev); -#endif /* Herbert's original patch had: * smp_mb__after_netif_stop_queue(); * but since that doesn't exist yet, just open code it. */ @@ -3212,11 +3257,7 @@ static int __ixgbe_maybe_stop_tx(struct net_device *netdev, return -EBUSY; /* A reprieve! - use start_queue because it doesn't call schedule */ -#ifdef CONFIG_NETDEVICES_MULTIQUEUE netif_wake_subqueue(netdev, tx_ring->queue_index); -#else - netif_wake_queue(netdev); -#endif ++adapter->restart_queue; return 0; } @@ -3244,9 +3285,7 @@ static int ixgbe_xmit_frame(struct sk_buff *skb, struct net_device *netdev) unsigned int f; unsigned int nr_frags = skb_shinfo(skb)->nr_frags; len -= skb->data_len; -#ifdef CONFIG_NETDEVICES_MULTIQUEUE r_idx = (adapter->num_tx_queues - 1) & skb->queue_mapping; -#endif tx_ring = &adapter->tx_ring[r_idx]; @@ -3434,11 +3473,7 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev, pci_set_master(pdev); pci_save_state(pdev); -#ifdef CONFIG_NETDEVICES_MULTIQUEUE netdev = alloc_etherdev_mq(sizeof(struct ixgbe_adapter), MAX_TX_QUEUES); -#else - netdev = alloc_etherdev(sizeof(struct ixgbe_adapter)); -#endif if (!netdev) { err = -ENOMEM; goto err_alloc_etherdev; @@ -3518,16 +3553,18 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev, NETIF_F_HW_VLAN_RX | NETIF_F_HW_VLAN_FILTER; + netdev->features |= NETIF_F_LRO; netdev->features |= NETIF_F_TSO; - netdev->features |= NETIF_F_TSO6; + + netdev->vlan_features |= NETIF_F_TSO; + netdev->vlan_features |= NETIF_F_TSO6; + netdev->vlan_features |= NETIF_F_HW_CSUM; + netdev->vlan_features |= NETIF_F_SG; + if (pci_using_dac) netdev->features |= NETIF_F_HIGHDMA; -#ifdef CONFIG_NETDEVICES_MULTIQUEUE - netdev->features |= NETIF_F_MULTI_QUEUE; -#endif - /* make sure the EEPROM is good */ if (ixgbe_validate_eeprom_checksum(hw, NULL) < 0) { dev_err(&pdev->dev, "The EEPROM Checksum Is Not Valid\n"); @@ -3593,11 +3630,7 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev, ixgbe_start_hw(hw); netif_carrier_off(netdev); - netif_stop_queue(netdev); -#ifdef CONFIG_NETDEVICES_MULTIQUEUE - for (i = 0; i < adapter->num_tx_queues; i++) - netif_stop_subqueue(netdev, i); -#endif + netif_tx_stop_all_queues(netdev); ixgbe_napi_add_all(adapter); diff --git a/drivers/net/ixp2000/ixpdev.c b/drivers/net/ixp2000/ixpdev.c index 484cb2ba717f..7111c65f0b30 100644 --- a/drivers/net/ixp2000/ixpdev.c +++ b/drivers/net/ixp2000/ixpdev.c @@ -108,14 +108,14 @@ static int ixpdev_rx(struct net_device *dev, int processed, int budget) if (unlikely(!netif_running(nds[desc->channel]))) goto err; - skb = dev_alloc_skb(desc->pkt_length + 2); + skb = netdev_alloc_skb(dev, desc->pkt_length + 2); if (likely(skb != NULL)) { skb_reserve(skb, 2); skb_copy_to_linear_data(skb, buf, desc->pkt_length); skb_put(skb, desc->pkt_length); skb->protocol = eth_type_trans(skb, nds[desc->channel]); - skb->dev->last_rx = jiffies; + dev->last_rx = jiffies; netif_receive_skb(skb); } diff --git a/drivers/net/lib8390.c b/drivers/net/lib8390.c index 0c5447dac03b..00d59ab2f8ac 100644 --- a/drivers/net/lib8390.c +++ b/drivers/net/lib8390.c @@ -150,19 +150,19 @@ static void __NS8390_init(struct net_device *dev, int startp); * card means that approach caused horrible problems like losing serial data * at 38400 baud on some chips. Remember many 8390 nics on PCI were ISA * chips with FPGA front ends. - * + * * Ok the logic behind the 8390 is very simple: - * + * * Things to know * - IRQ delivery is asynchronous to the PCI bus * - Blocking the local CPU IRQ via spin locks was too slow * - The chip has register windows needing locking work - * + * * So the path was once (I say once as people appear to have changed it * in the mean time and it now looks rather bogus if the changes to use * disable_irq_nosync_irqsave are disabling the local IRQ) - * - * + * + * * Take the page lock * Mask the IRQ on chip * Disable the IRQ (but not mask locally- someone seems to have @@ -170,22 +170,22 @@ static void __NS8390_init(struct net_device *dev, int startp); * [This must be _nosync as the page lock may otherwise * deadlock us] * Drop the page lock and turn IRQs back on - * + * * At this point an existing IRQ may still be running but we can't * get a new one - * + * * Take the lock (so we know the IRQ has terminated) but don't mask * the IRQs on the processor * Set irqlock [for debug] - * + * * Transmit (slow as ****) - * + * * re-enable the IRQ - * - * + * + * * We have to use disable_irq because otherwise you will get delayed * interrupts on the APIC bus deadlocking the transmit path. - * + * * Quite hairy but the chip simply wasn't designed for SMP and you can't * even ACK an interrupt without risking corrupting other parallel * activities on the chip." [lkml, 25 Jul 2007] @@ -265,7 +265,7 @@ static void ei_tx_timeout(struct net_device *dev) int txsr, isr, tickssofar = jiffies - dev->trans_start; unsigned long flags; - ei_local->stat.tx_errors++; + dev->stats.tx_errors++; spin_lock_irqsave(&ei_local->page_lock, flags); txsr = ei_inb(e8390_base+EN0_TSR); @@ -276,7 +276,7 @@ static void ei_tx_timeout(struct net_device *dev) dev->name, (txsr & ENTSR_ABT) ? "excess collisions." : (isr) ? "lost interrupt?" : "cable problem?", txsr, isr, tickssofar); - if (!isr && !ei_local->stat.tx_packets) + if (!isr && !dev->stats.tx_packets) { /* The 8390 probably hasn't gotten on the cable yet. */ ei_local->interface_num ^= 1; /* Try a different xcvr. */ @@ -374,7 +374,7 @@ static int ei_start_xmit(struct sk_buff *skb, struct net_device *dev) ei_outb_p(ENISR_ALL, e8390_base + EN0_IMR); spin_unlock(&ei_local->page_lock); enable_irq_lockdep_irqrestore(dev->irq, &flags); - ei_local->stat.tx_errors++; + dev->stats.tx_errors++; return 1; } @@ -417,7 +417,7 @@ static int ei_start_xmit(struct sk_buff *skb, struct net_device *dev) enable_irq_lockdep_irqrestore(dev->irq, &flags); dev_kfree_skb (skb); - ei_local->stat.tx_bytes += send_length; + dev->stats.tx_bytes += send_length; return 0; } @@ -493,9 +493,9 @@ static irqreturn_t __ei_interrupt(int irq, void *dev_id) if (interrupts & ENISR_COUNTERS) { - ei_local->stat.rx_frame_errors += ei_inb_p(e8390_base + EN0_COUNTER0); - ei_local->stat.rx_crc_errors += ei_inb_p(e8390_base + EN0_COUNTER1); - ei_local->stat.rx_missed_errors+= ei_inb_p(e8390_base + EN0_COUNTER2); + dev->stats.rx_frame_errors += ei_inb_p(e8390_base + EN0_COUNTER0); + dev->stats.rx_crc_errors += ei_inb_p(e8390_base + EN0_COUNTER1); + dev->stats.rx_missed_errors+= ei_inb_p(e8390_base + EN0_COUNTER2); ei_outb_p(ENISR_COUNTERS, e8390_base + EN0_ISR); /* Ack intr. */ } @@ -553,7 +553,8 @@ static void __ei_poll(struct net_device *dev) static void ei_tx_err(struct net_device *dev) { unsigned long e8390_base = dev->base_addr; - struct ei_device *ei_local = (struct ei_device *) netdev_priv(dev); + /* ei_local is used on some platforms via the EI_SHIFT macro */ + struct ei_device *ei_local __maybe_unused = netdev_priv(dev); unsigned char txsr = ei_inb_p(e8390_base+EN0_TSR); unsigned char tx_was_aborted = txsr & (ENTSR_ABT+ENTSR_FU); @@ -578,10 +579,10 @@ static void ei_tx_err(struct net_device *dev) ei_tx_intr(dev); else { - ei_local->stat.tx_errors++; - if (txsr & ENTSR_CRS) ei_local->stat.tx_carrier_errors++; - if (txsr & ENTSR_CDH) ei_local->stat.tx_heartbeat_errors++; - if (txsr & ENTSR_OWC) ei_local->stat.tx_window_errors++; + dev->stats.tx_errors++; + if (txsr & ENTSR_CRS) dev->stats.tx_carrier_errors++; + if (txsr & ENTSR_CDH) dev->stats.tx_heartbeat_errors++; + if (txsr & ENTSR_OWC) dev->stats.tx_window_errors++; } } @@ -645,25 +646,25 @@ static void ei_tx_intr(struct net_device *dev) /* Minimize Tx latency: update the statistics after we restart TXing. */ if (status & ENTSR_COL) - ei_local->stat.collisions++; + dev->stats.collisions++; if (status & ENTSR_PTX) - ei_local->stat.tx_packets++; + dev->stats.tx_packets++; else { - ei_local->stat.tx_errors++; + dev->stats.tx_errors++; if (status & ENTSR_ABT) { - ei_local->stat.tx_aborted_errors++; - ei_local->stat.collisions += 16; + dev->stats.tx_aborted_errors++; + dev->stats.collisions += 16; } if (status & ENTSR_CRS) - ei_local->stat.tx_carrier_errors++; + dev->stats.tx_carrier_errors++; if (status & ENTSR_FU) - ei_local->stat.tx_fifo_errors++; + dev->stats.tx_fifo_errors++; if (status & ENTSR_CDH) - ei_local->stat.tx_heartbeat_errors++; + dev->stats.tx_heartbeat_errors++; if (status & ENTSR_OWC) - ei_local->stat.tx_window_errors++; + dev->stats.tx_window_errors++; } netif_wake_queue(dev); } @@ -730,7 +731,7 @@ static void ei_receive(struct net_device *dev) && rx_frame.next != next_frame + 1 - num_rx_pages) { ei_local->current_page = rxing_page; ei_outb(ei_local->current_page-1, e8390_base+EN0_BOUNDARY); - ei_local->stat.rx_errors++; + dev->stats.rx_errors++; continue; } @@ -740,8 +741,8 @@ static void ei_receive(struct net_device *dev) printk(KERN_DEBUG "%s: bogus packet size: %d, status=%#2x nxpg=%#2x.\n", dev->name, rx_frame.count, rx_frame.status, rx_frame.next); - ei_local->stat.rx_errors++; - ei_local->stat.rx_length_errors++; + dev->stats.rx_errors++; + dev->stats.rx_length_errors++; } else if ((pkt_stat & 0x0F) == ENRSR_RXOK) { @@ -753,7 +754,7 @@ static void ei_receive(struct net_device *dev) if (ei_debug > 1) printk(KERN_DEBUG "%s: Couldn't allocate a sk_buff of size %d.\n", dev->name, pkt_len); - ei_local->stat.rx_dropped++; + dev->stats.rx_dropped++; break; } else @@ -764,10 +765,10 @@ static void ei_receive(struct net_device *dev) skb->protocol=eth_type_trans(skb,dev); netif_rx(skb); dev->last_rx = jiffies; - ei_local->stat.rx_packets++; - ei_local->stat.rx_bytes += pkt_len; + dev->stats.rx_packets++; + dev->stats.rx_bytes += pkt_len; if (pkt_stat & ENRSR_PHY) - ei_local->stat.multicast++; + dev->stats.multicast++; } } else @@ -776,10 +777,10 @@ static void ei_receive(struct net_device *dev) printk(KERN_DEBUG "%s: bogus packet: status=%#2x nxpg=%#2x size=%d\n", dev->name, rx_frame.status, rx_frame.next, rx_frame.count); - ei_local->stat.rx_errors++; + dev->stats.rx_errors++; /* NB: The NIC counts CRC, frame and missed errors. */ if (pkt_stat & ENRSR_FO) - ei_local->stat.rx_fifo_errors++; + dev->stats.rx_fifo_errors++; } next_frame = rx_frame.next; @@ -816,7 +817,8 @@ static void ei_rx_overrun(struct net_device *dev) { unsigned long e8390_base = dev->base_addr; unsigned char was_txing, must_resend = 0; - struct ei_device *ei_local = (struct ei_device *) netdev_priv(dev); + /* ei_local is used on some platforms via the EI_SHIFT macro */ + struct ei_device *ei_local __maybe_unused = netdev_priv(dev); /* * Record whether a Tx was in progress and then issue the @@ -827,7 +829,7 @@ static void ei_rx_overrun(struct net_device *dev) if (ei_debug > 1) printk(KERN_DEBUG "%s: Receiver overrun.\n", dev->name); - ei_local->stat.rx_over_errors++; + dev->stats.rx_over_errors++; /* * Wait a full Tx time (1.2ms) + some guard time, NS says 1.6ms total. @@ -889,16 +891,16 @@ static struct net_device_stats *get_stats(struct net_device *dev) /* If the card is stopped, just return the present stats. */ if (!netif_running(dev)) - return &ei_local->stat; + return &dev->stats; spin_lock_irqsave(&ei_local->page_lock,flags); /* Read the counter registers, assuming we are in page 0. */ - ei_local->stat.rx_frame_errors += ei_inb_p(ioaddr + EN0_COUNTER0); - ei_local->stat.rx_crc_errors += ei_inb_p(ioaddr + EN0_COUNTER1); - ei_local->stat.rx_missed_errors+= ei_inb_p(ioaddr + EN0_COUNTER2); + dev->stats.rx_frame_errors += ei_inb_p(ioaddr + EN0_COUNTER0); + dev->stats.rx_crc_errors += ei_inb_p(ioaddr + EN0_COUNTER1); + dev->stats.rx_missed_errors+= ei_inb_p(ioaddr + EN0_COUNTER2); spin_unlock_irqrestore(&ei_local->page_lock, flags); - return &ei_local->stat; + return &dev->stats; } /* diff --git a/drivers/net/loopback.c b/drivers/net/loopback.c index 41b774baac4d..49f6bc036a92 100644 --- a/drivers/net/loopback.c +++ b/drivers/net/loopback.c @@ -153,7 +153,7 @@ static int loopback_xmit(struct sk_buff *skb, struct net_device *dev) dev->last_rx = jiffies; /* it's OK to use per_cpu_ptr() because BHs are off */ - pcpu_lstats = netdev_priv(dev); + pcpu_lstats = dev->ml_priv; lb_stats = per_cpu_ptr(pcpu_lstats, smp_processor_id()); lb_stats->bytes += skb->len; lb_stats->packets++; @@ -171,7 +171,7 @@ static struct net_device_stats *get_stats(struct net_device *dev) unsigned long packets = 0; int i; - pcpu_lstats = netdev_priv(dev); + pcpu_lstats = dev->ml_priv; for_each_possible_cpu(i) { const struct pcpu_lstats *lb_stats; @@ -207,13 +207,13 @@ static int loopback_dev_init(struct net_device *dev) if (!lstats) return -ENOMEM; - dev->priv = lstats; + dev->ml_priv = lstats; return 0; } static void loopback_dev_free(struct net_device *dev) { - struct pcpu_lstats *lstats = netdev_priv(dev); + struct pcpu_lstats *lstats = dev->ml_priv; free_percpu(lstats); free_netdev(dev); diff --git a/drivers/net/mac8390.c b/drivers/net/mac8390.c index 9e700749bb31..98e3eb2697c9 100644 --- a/drivers/net/mac8390.c +++ b/drivers/net/mac8390.c @@ -117,8 +117,6 @@ enum mac8390_access { ACCESS_16, }; -extern enum mac8390_type mac8390_ident(struct nubus_dev * dev); -extern int mac8390_memsize(unsigned long membase); extern int mac8390_memtest(struct net_device * dev); static int mac8390_initdev(struct net_device * dev, struct nubus_dev * ndev, enum mac8390_type type); @@ -163,7 +161,7 @@ static void slow_sane_block_output(struct net_device *dev, int count, static void word_memcpy_tocard(void *tp, const void *fp, int count); static void word_memcpy_fromcard(void *tp, const void *fp, int count); -enum mac8390_type __init mac8390_ident(struct nubus_dev * dev) +static enum mac8390_type __init mac8390_ident(struct nubus_dev *dev) { switch (dev->dr_sw) { case NUBUS_DRSW_3COM: @@ -234,7 +232,7 @@ enum mac8390_type __init mac8390_ident(struct nubus_dev * dev) return MAC8390_NONE; } -enum mac8390_access __init mac8390_testio(volatile unsigned long membase) +static enum mac8390_access __init mac8390_testio(volatile unsigned long membase) { unsigned long outdata = 0xA5A0B5B0; unsigned long indata = 0x00000000; @@ -252,7 +250,7 @@ enum mac8390_access __init mac8390_testio(volatile unsigned long membase) return ACCESS_UNKNOWN; } -int __init mac8390_memsize(unsigned long membase) +static int __init mac8390_memsize(unsigned long membase) { unsigned long flags; int i, j; diff --git a/drivers/net/macb.c b/drivers/net/macb.c index 0a5745a854c7..0496d16f9de5 100644 --- a/drivers/net/macb.c +++ b/drivers/net/macb.c @@ -80,8 +80,12 @@ static void __init macb_get_hwaddr(struct macb *bp) addr[4] = top & 0xff; addr[5] = (top >> 8) & 0xff; - if (is_valid_ether_addr(addr)) + if (is_valid_ether_addr(addr)) { memcpy(bp->dev->dev_addr, addr, sizeof(addr)); + } else { + dev_info(&bp->pdev->dev, "invalid hw address, using random\n"); + random_ether_addr(bp->dev->dev_addr); + } } static int macb_mdio_read(struct mii_bus *bus, int mii_id, int regnum) @@ -161,7 +165,7 @@ static void macb_handle_link_change(struct net_device *dev) if (phydev->link != bp->link) { if (phydev->link) - netif_schedule(dev); + netif_tx_schedule_all(dev); else { bp->speed = 0; bp->duplex = -1; diff --git a/drivers/net/macsonic.c b/drivers/net/macsonic.c index b267161418ea..e64c2086d33c 100644 --- a/drivers/net/macsonic.c +++ b/drivers/net/macsonic.c @@ -83,9 +83,6 @@ static unsigned int sonic_debug = 1; static int sonic_version_printed; -extern int mac_onboard_sonic_probe(struct net_device* dev); -extern int mac_nubus_sonic_probe(struct net_device* dev); - /* For onboard SONIC */ #define ONBOARD_SONIC_REGISTERS 0x50F0A000 #define ONBOARD_SONIC_PROM_BASE 0x50f08000 @@ -170,7 +167,7 @@ static int macsonic_close(struct net_device* dev) return err; } -int __init macsonic_init(struct net_device* dev) +static int __init macsonic_init(struct net_device *dev) { struct sonic_local* lp = netdev_priv(dev); @@ -218,7 +215,7 @@ int __init macsonic_init(struct net_device* dev) return 0; } -int __init mac_onboard_sonic_ethernet_addr(struct net_device* dev) +static int __init mac_onboard_sonic_ethernet_addr(struct net_device *dev) { struct sonic_local *lp = netdev_priv(dev); const int prom_addr = ONBOARD_SONIC_PROM_BASE; @@ -284,7 +281,7 @@ int __init mac_onboard_sonic_ethernet_addr(struct net_device* dev) } else return 0; } -int __init mac_onboard_sonic_probe(struct net_device* dev) +static int __init mac_onboard_sonic_probe(struct net_device *dev) { /* Bwahahaha */ static int once_is_more_than_enough; @@ -405,9 +402,9 @@ int __init mac_onboard_sonic_probe(struct net_device* dev) return macsonic_init(dev); } -int __init mac_nubus_sonic_ethernet_addr(struct net_device* dev, - unsigned long prom_addr, - int id) +static int __init mac_nubus_sonic_ethernet_addr(struct net_device *dev, + unsigned long prom_addr, + int id) { int i; for(i = 0; i < 6; i++) @@ -420,7 +417,7 @@ int __init mac_nubus_sonic_ethernet_addr(struct net_device* dev, return 0; } -int __init macsonic_ident(struct nubus_dev* ndev) +static int __init macsonic_ident(struct nubus_dev *ndev) { if (ndev->dr_hw == NUBUS_DRHW_ASANTE_LC && ndev->dr_sw == NUBUS_DRSW_SONIC_LC) @@ -445,7 +442,7 @@ int __init macsonic_ident(struct nubus_dev* ndev) return -1; } -int __init mac_nubus_sonic_probe(struct net_device* dev) +static int __init mac_nubus_sonic_probe(struct net_device *dev) { static int slots; struct nubus_dev* ndev = NULL; diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c index 860d75d81f82..efbc15567dd3 100644 --- a/drivers/net/macvlan.c +++ b/drivers/net/macvlan.c @@ -189,12 +189,20 @@ static int macvlan_open(struct net_device *dev) err = dev_unicast_add(lowerdev, dev->dev_addr, ETH_ALEN); if (err < 0) - return err; - if (dev->flags & IFF_ALLMULTI) - dev_set_allmulti(lowerdev, 1); + goto out; + if (dev->flags & IFF_ALLMULTI) { + err = dev_set_allmulti(lowerdev, 1); + if (err < 0) + goto del_unicast; + } hlist_add_head_rcu(&vlan->hlist, &port->vlan_hash[dev->dev_addr[5]]); return 0; + +del_unicast: + dev_unicast_delete(lowerdev, dev->dev_addr, ETH_ALEN); +out: + return err; } static int macvlan_stop(struct net_device *dev) @@ -277,6 +285,19 @@ static struct lock_class_key macvlan_netdev_xmit_lock_key; #define MACVLAN_STATE_MASK \ ((1<<__LINK_STATE_NOCARRIER) | (1<<__LINK_STATE_DORMANT)) +static void macvlan_set_lockdep_class_one(struct net_device *dev, + struct netdev_queue *txq, + void *_unused) +{ + lockdep_set_class(&txq->_xmit_lock, + &macvlan_netdev_xmit_lock_key); +} + +static void macvlan_set_lockdep_class(struct net_device *dev) +{ + netdev_for_each_tx_queue(dev, macvlan_set_lockdep_class_one, NULL); +} + static int macvlan_init(struct net_device *dev) { struct macvlan_dev *vlan = netdev_priv(dev); @@ -287,7 +308,8 @@ static int macvlan_init(struct net_device *dev) dev->features = lowerdev->features & MACVLAN_FEATURES; dev->iflink = lowerdev->ifindex; - lockdep_set_class(&dev->_xmit_lock, &macvlan_netdev_xmit_lock_key); + macvlan_set_lockdep_class(dev); + return 0; } diff --git a/drivers/net/mv643xx_eth.c b/drivers/net/mv643xx_eth.c index b7915cdcc6a5..83a877f3a553 100644 --- a/drivers/net/mv643xx_eth.c +++ b/drivers/net/mv643xx_eth.c @@ -34,406 +34,145 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + #include <linux/init.h> #include <linux/dma-mapping.h> #include <linux/in.h> -#include <linux/ip.h> #include <linux/tcp.h> #include <linux/udp.h> #include <linux/etherdevice.h> - -#include <linux/bitops.h> #include <linux/delay.h> #include <linux/ethtool.h> #include <linux/platform_device.h> - #include <linux/module.h> #include <linux/kernel.h> #include <linux/spinlock.h> #include <linux/workqueue.h> #include <linux/mii.h> - #include <linux/mv643xx_eth.h> - #include <asm/io.h> #include <asm/types.h> -#include <asm/pgtable.h> #include <asm/system.h> -#include <asm/delay.h> -#include <asm/dma-mapping.h> -#define MV643XX_CHECKSUM_OFFLOAD_TX -#define MV643XX_NAPI -#define MV643XX_TX_FAST_REFILL -#undef MV643XX_COAL +static char mv643xx_eth_driver_name[] = "mv643xx_eth"; +static char mv643xx_eth_driver_version[] = "1.1"; -#define MV643XX_TX_COAL 100 -#ifdef MV643XX_COAL -#define MV643XX_RX_COAL 100 -#endif +#define MV643XX_ETH_CHECKSUM_OFFLOAD_TX +#define MV643XX_ETH_NAPI +#define MV643XX_ETH_TX_FAST_REFILL -#ifdef MV643XX_CHECKSUM_OFFLOAD_TX +#ifdef MV643XX_ETH_CHECKSUM_OFFLOAD_TX #define MAX_DESCS_PER_SKB (MAX_SKB_FRAGS + 1) #else #define MAX_DESCS_PER_SKB 1 #endif -#define ETH_VLAN_HLEN 4 -#define ETH_FCS_LEN 4 -#define ETH_HW_IP_ALIGN 2 /* hw aligns IP header */ -#define ETH_WRAPPER_LEN (ETH_HW_IP_ALIGN + ETH_HLEN + \ - ETH_VLAN_HLEN + ETH_FCS_LEN) -#define ETH_RX_SKB_SIZE (dev->mtu + ETH_WRAPPER_LEN + \ - dma_get_cache_alignment()) - /* * Registers shared between all ports. */ -#define PHY_ADDR_REG 0x0000 -#define SMI_REG 0x0004 -#define WINDOW_BASE(i) (0x0200 + ((i) << 3)) -#define WINDOW_SIZE(i) (0x0204 + ((i) << 3)) -#define WINDOW_REMAP_HIGH(i) (0x0280 + ((i) << 2)) -#define WINDOW_BAR_ENABLE 0x0290 -#define WINDOW_PROTECT(i) (0x0294 + ((i) << 4)) +#define PHY_ADDR 0x0000 +#define SMI_REG 0x0004 +#define WINDOW_BASE(w) (0x0200 + ((w) << 3)) +#define WINDOW_SIZE(w) (0x0204 + ((w) << 3)) +#define WINDOW_REMAP_HIGH(w) (0x0280 + ((w) << 2)) +#define WINDOW_BAR_ENABLE 0x0290 +#define WINDOW_PROTECT(w) (0x0294 + ((w) << 4)) /* * Per-port registers. */ -#define PORT_CONFIG_REG(p) (0x0400 + ((p) << 10)) -#define PORT_CONFIG_EXTEND_REG(p) (0x0404 + ((p) << 10)) -#define MAC_ADDR_LOW(p) (0x0414 + ((p) << 10)) -#define MAC_ADDR_HIGH(p) (0x0418 + ((p) << 10)) -#define SDMA_CONFIG_REG(p) (0x041c + ((p) << 10)) -#define PORT_SERIAL_CONTROL_REG(p) (0x043c + ((p) << 10)) -#define PORT_STATUS_REG(p) (0x0444 + ((p) << 10)) -#define TRANSMIT_QUEUE_COMMAND_REG(p) (0x0448 + ((p) << 10)) -#define MAXIMUM_TRANSMIT_UNIT(p) (0x0458 + ((p) << 10)) -#define INTERRUPT_CAUSE_REG(p) (0x0460 + ((p) << 10)) -#define INTERRUPT_CAUSE_EXTEND_REG(p) (0x0464 + ((p) << 10)) -#define INTERRUPT_MASK_REG(p) (0x0468 + ((p) << 10)) -#define INTERRUPT_EXTEND_MASK_REG(p) (0x046c + ((p) << 10)) -#define TX_FIFO_URGENT_THRESHOLD_REG(p) (0x0474 + ((p) << 10)) -#define RX_CURRENT_QUEUE_DESC_PTR_0(p) (0x060c + ((p) << 10)) -#define RECEIVE_QUEUE_COMMAND_REG(p) (0x0680 + ((p) << 10)) -#define TX_CURRENT_QUEUE_DESC_PTR_0(p) (0x06c0 + ((p) << 10)) -#define MIB_COUNTERS_BASE(p) (0x1000 + ((p) << 7)) -#define DA_FILTER_SPECIAL_MULTICAST_TABLE_BASE(p) (0x1400 + ((p) << 10)) -#define DA_FILTER_OTHER_MULTICAST_TABLE_BASE(p) (0x1500 + ((p) << 10)) -#define DA_FILTER_UNICAST_TABLE_BASE(p) (0x1600 + ((p) << 10)) - -/* These macros describe Ethernet Port configuration reg (Px_cR) bits */ -#define UNICAST_NORMAL_MODE (0 << 0) -#define UNICAST_PROMISCUOUS_MODE (1 << 0) -#define DEFAULT_RX_QUEUE(queue) ((queue) << 1) -#define DEFAULT_RX_ARP_QUEUE(queue) ((queue) << 4) -#define RECEIVE_BC_IF_NOT_IP_OR_ARP (0 << 7) -#define REJECT_BC_IF_NOT_IP_OR_ARP (1 << 7) -#define RECEIVE_BC_IF_IP (0 << 8) -#define REJECT_BC_IF_IP (1 << 8) -#define RECEIVE_BC_IF_ARP (0 << 9) -#define REJECT_BC_IF_ARP (1 << 9) -#define TX_AM_NO_UPDATE_ERROR_SUMMARY (1 << 12) -#define CAPTURE_TCP_FRAMES_DIS (0 << 14) -#define CAPTURE_TCP_FRAMES_EN (1 << 14) -#define CAPTURE_UDP_FRAMES_DIS (0 << 15) -#define CAPTURE_UDP_FRAMES_EN (1 << 15) -#define DEFAULT_RX_TCP_QUEUE(queue) ((queue) << 16) -#define DEFAULT_RX_UDP_QUEUE(queue) ((queue) << 19) -#define DEFAULT_RX_BPDU_QUEUE(queue) ((queue) << 22) - -#define PORT_CONFIG_DEFAULT_VALUE \ - UNICAST_NORMAL_MODE | \ - DEFAULT_RX_QUEUE(0) | \ - DEFAULT_RX_ARP_QUEUE(0) | \ - RECEIVE_BC_IF_NOT_IP_OR_ARP | \ - RECEIVE_BC_IF_IP | \ - RECEIVE_BC_IF_ARP | \ - CAPTURE_TCP_FRAMES_DIS | \ - CAPTURE_UDP_FRAMES_DIS | \ - DEFAULT_RX_TCP_QUEUE(0) | \ - DEFAULT_RX_UDP_QUEUE(0) | \ - DEFAULT_RX_BPDU_QUEUE(0) - -/* These macros describe Ethernet Port configuration extend reg (Px_cXR) bits*/ -#define CLASSIFY_EN (1 << 0) -#define SPAN_BPDU_PACKETS_AS_NORMAL (0 << 1) -#define SPAN_BPDU_PACKETS_TO_RX_QUEUE_7 (1 << 1) -#define PARTITION_DISABLE (0 << 2) -#define PARTITION_ENABLE (1 << 2) - -#define PORT_CONFIG_EXTEND_DEFAULT_VALUE \ - SPAN_BPDU_PACKETS_AS_NORMAL | \ - PARTITION_DISABLE - -/* These macros describe Ethernet Port Sdma configuration reg (SDCR) bits */ -#define RIFB (1 << 0) -#define RX_BURST_SIZE_1_64BIT (0 << 1) -#define RX_BURST_SIZE_2_64BIT (1 << 1) +#define PORT_CONFIG(p) (0x0400 + ((p) << 10)) +#define UNICAST_PROMISCUOUS_MODE 0x00000001 +#define PORT_CONFIG_EXT(p) (0x0404 + ((p) << 10)) +#define MAC_ADDR_LOW(p) (0x0414 + ((p) << 10)) +#define MAC_ADDR_HIGH(p) (0x0418 + ((p) << 10)) +#define SDMA_CONFIG(p) (0x041c + ((p) << 10)) +#define PORT_SERIAL_CONTROL(p) (0x043c + ((p) << 10)) +#define PORT_STATUS(p) (0x0444 + ((p) << 10)) +#define TX_FIFO_EMPTY 0x00000400 +#define TXQ_COMMAND(p) (0x0448 + ((p) << 10)) +#define TXQ_FIX_PRIO_CONF(p) (0x044c + ((p) << 10)) +#define TX_BW_RATE(p) (0x0450 + ((p) << 10)) +#define TX_BW_MTU(p) (0x0458 + ((p) << 10)) +#define TX_BW_BURST(p) (0x045c + ((p) << 10)) +#define INT_CAUSE(p) (0x0460 + ((p) << 10)) +#define INT_TX_END 0x07f80000 +#define INT_RX 0x0007fbfc +#define INT_EXT 0x00000002 +#define INT_CAUSE_EXT(p) (0x0464 + ((p) << 10)) +#define INT_EXT_LINK 0x00100000 +#define INT_EXT_PHY 0x00010000 +#define INT_EXT_TX_ERROR_0 0x00000100 +#define INT_EXT_TX_0 0x00000001 +#define INT_EXT_TX 0x0000ffff +#define INT_MASK(p) (0x0468 + ((p) << 10)) +#define INT_MASK_EXT(p) (0x046c + ((p) << 10)) +#define TX_FIFO_URGENT_THRESHOLD(p) (0x0474 + ((p) << 10)) +#define TXQ_FIX_PRIO_CONF_MOVED(p) (0x04dc + ((p) << 10)) +#define TX_BW_RATE_MOVED(p) (0x04e0 + ((p) << 10)) +#define TX_BW_MTU_MOVED(p) (0x04e8 + ((p) << 10)) +#define TX_BW_BURST_MOVED(p) (0x04ec + ((p) << 10)) +#define RXQ_CURRENT_DESC_PTR(p, q) (0x060c + ((p) << 10) + ((q) << 4)) +#define RXQ_COMMAND(p) (0x0680 + ((p) << 10)) +#define TXQ_CURRENT_DESC_PTR(p, q) (0x06c0 + ((p) << 10) + ((q) << 2)) +#define TXQ_BW_TOKENS(p, q) (0x0700 + ((p) << 10) + ((q) << 4)) +#define TXQ_BW_CONF(p, q) (0x0704 + ((p) << 10) + ((q) << 4)) +#define TXQ_BW_WRR_CONF(p, q) (0x0708 + ((p) << 10) + ((q) << 4)) +#define MIB_COUNTERS(p) (0x1000 + ((p) << 7)) +#define SPECIAL_MCAST_TABLE(p) (0x1400 + ((p) << 10)) +#define OTHER_MCAST_TABLE(p) (0x1500 + ((p) << 10)) +#define UNICAST_TABLE(p) (0x1600 + ((p) << 10)) + + +/* + * SDMA configuration register. + */ #define RX_BURST_SIZE_4_64BIT (2 << 1) -#define RX_BURST_SIZE_8_64BIT (3 << 1) -#define RX_BURST_SIZE_16_64BIT (4 << 1) #define BLM_RX_NO_SWAP (1 << 4) -#define BLM_RX_BYTE_SWAP (0 << 4) #define BLM_TX_NO_SWAP (1 << 5) -#define BLM_TX_BYTE_SWAP (0 << 5) -#define DESCRIPTORS_BYTE_SWAP (1 << 6) -#define DESCRIPTORS_NO_SWAP (0 << 6) -#define IPG_INT_RX(value) (((value) & 0x3fff) << 8) -#define TX_BURST_SIZE_1_64BIT (0 << 22) -#define TX_BURST_SIZE_2_64BIT (1 << 22) #define TX_BURST_SIZE_4_64BIT (2 << 22) -#define TX_BURST_SIZE_8_64BIT (3 << 22) -#define TX_BURST_SIZE_16_64BIT (4 << 22) #if defined(__BIG_ENDIAN) #define PORT_SDMA_CONFIG_DEFAULT_VALUE \ RX_BURST_SIZE_4_64BIT | \ - IPG_INT_RX(0) | \ TX_BURST_SIZE_4_64BIT #elif defined(__LITTLE_ENDIAN) #define PORT_SDMA_CONFIG_DEFAULT_VALUE \ RX_BURST_SIZE_4_64BIT | \ BLM_RX_NO_SWAP | \ BLM_TX_NO_SWAP | \ - IPG_INT_RX(0) | \ TX_BURST_SIZE_4_64BIT #else #error One of __BIG_ENDIAN or __LITTLE_ENDIAN must be defined #endif -/* These macros describe Ethernet Port serial control reg (PSCR) bits */ -#define SERIAL_PORT_DISABLE (0 << 0) -#define SERIAL_PORT_ENABLE (1 << 0) -#define DO_NOT_FORCE_LINK_PASS (0 << 1) -#define FORCE_LINK_PASS (1 << 1) -#define ENABLE_AUTO_NEG_FOR_DUPLX (0 << 2) -#define DISABLE_AUTO_NEG_FOR_DUPLX (1 << 2) -#define ENABLE_AUTO_NEG_FOR_FLOW_CTRL (0 << 3) -#define DISABLE_AUTO_NEG_FOR_FLOW_CTRL (1 << 3) -#define ADV_NO_FLOW_CTRL (0 << 4) -#define ADV_SYMMETRIC_FLOW_CTRL (1 << 4) -#define FORCE_FC_MODE_NO_PAUSE_DIS_TX (0 << 5) -#define FORCE_FC_MODE_TX_PAUSE_DIS (1 << 5) -#define FORCE_BP_MODE_NO_JAM (0 << 7) -#define FORCE_BP_MODE_JAM_TX (1 << 7) -#define FORCE_BP_MODE_JAM_TX_ON_RX_ERR (2 << 7) -#define SERIAL_PORT_CONTROL_RESERVED (1 << 9) -#define FORCE_LINK_FAIL (0 << 10) -#define DO_NOT_FORCE_LINK_FAIL (1 << 10) -#define RETRANSMIT_16_ATTEMPTS (0 << 11) -#define RETRANSMIT_FOREVER (1 << 11) -#define ENABLE_AUTO_NEG_SPEED_GMII (0 << 13) -#define DISABLE_AUTO_NEG_SPEED_GMII (1 << 13) -#define DTE_ADV_0 (0 << 14) -#define DTE_ADV_1 (1 << 14) -#define DISABLE_AUTO_NEG_BYPASS (0 << 15) -#define ENABLE_AUTO_NEG_BYPASS (1 << 15) -#define AUTO_NEG_NO_CHANGE (0 << 16) -#define RESTART_AUTO_NEG (1 << 16) -#define MAX_RX_PACKET_1518BYTE (0 << 17) + +/* + * Port serial control register. + */ +#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_1522BYTE (1 << 17) -#define MAX_RX_PACKET_1552BYTE (2 << 17) -#define MAX_RX_PACKET_9022BYTE (3 << 17) -#define MAX_RX_PACKET_9192BYTE (4 << 17) #define MAX_RX_PACKET_9700BYTE (5 << 17) #define MAX_RX_PACKET_MASK (7 << 17) -#define CLR_EXT_LOOPBACK (0 << 20) -#define SET_EXT_LOOPBACK (1 << 20) -#define SET_HALF_DUPLEX_MODE (0 << 21) -#define SET_FULL_DUPLEX_MODE (1 << 21) -#define DISABLE_FLOW_CTRL_TX_RX_IN_FULL_DUPLEX (0 << 22) -#define ENABLE_FLOW_CTRL_TX_RX_IN_FULL_DUPLEX (1 << 22) -#define SET_GMII_SPEED_TO_10_100 (0 << 23) -#define SET_GMII_SPEED_TO_1000 (1 << 23) -#define SET_MII_SPEED_TO_10 (0 << 24) -#define SET_MII_SPEED_TO_100 (1 << 24) +#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 PORT_SERIAL_CONTROL_DEFAULT_VALUE \ - DO_NOT_FORCE_LINK_PASS | \ - ENABLE_AUTO_NEG_FOR_DUPLX | \ - DISABLE_AUTO_NEG_FOR_FLOW_CTRL | \ - ADV_SYMMETRIC_FLOW_CTRL | \ - FORCE_FC_MODE_NO_PAUSE_DIS_TX | \ - FORCE_BP_MODE_NO_JAM | \ - (1 << 9) /* reserved */ | \ - DO_NOT_FORCE_LINK_FAIL | \ - RETRANSMIT_16_ATTEMPTS | \ - ENABLE_AUTO_NEG_SPEED_GMII | \ - DTE_ADV_0 | \ - DISABLE_AUTO_NEG_BYPASS | \ - AUTO_NEG_NO_CHANGE | \ - MAX_RX_PACKET_9700BYTE | \ - CLR_EXT_LOOPBACK | \ - SET_FULL_DUPLEX_MODE | \ - ENABLE_FLOW_CTRL_TX_RX_IN_FULL_DUPLEX - -/* These macros describe Ethernet Serial Status reg (PSR) bits */ -#define PORT_STATUS_MODE_10_BIT (1 << 0) -#define PORT_STATUS_LINK_UP (1 << 1) -#define PORT_STATUS_FULL_DUPLEX (1 << 2) -#define PORT_STATUS_FLOW_CONTROL (1 << 3) -#define PORT_STATUS_GMII_1000 (1 << 4) -#define PORT_STATUS_MII_100 (1 << 5) -/* PSR bit 6 is undocumented */ -#define PORT_STATUS_TX_IN_PROGRESS (1 << 7) -#define PORT_STATUS_AUTONEG_BYPASSED (1 << 8) -#define PORT_STATUS_PARTITION (1 << 9) -#define PORT_STATUS_TX_FIFO_EMPTY (1 << 10) -/* PSR bits 11-31 are reserved */ - -#define PORT_DEFAULT_TRANSMIT_QUEUE_SIZE 800 -#define PORT_DEFAULT_RECEIVE_QUEUE_SIZE 400 - -#define DESC_SIZE 64 - -#define ETH_RX_QUEUES_ENABLED (1 << 0) /* use only Q0 for receive */ -#define ETH_TX_QUEUES_ENABLED (1 << 0) /* use only Q0 for transmit */ - -#define ETH_INT_CAUSE_RX_DONE (ETH_RX_QUEUES_ENABLED << 2) -#define ETH_INT_CAUSE_RX_ERROR (ETH_RX_QUEUES_ENABLED << 9) -#define ETH_INT_CAUSE_RX (ETH_INT_CAUSE_RX_DONE | ETH_INT_CAUSE_RX_ERROR) -#define ETH_INT_CAUSE_EXT 0x00000002 -#define ETH_INT_UNMASK_ALL (ETH_INT_CAUSE_RX | ETH_INT_CAUSE_EXT) - -#define ETH_INT_CAUSE_TX_DONE (ETH_TX_QUEUES_ENABLED << 0) -#define ETH_INT_CAUSE_TX_ERROR (ETH_TX_QUEUES_ENABLED << 8) -#define ETH_INT_CAUSE_TX (ETH_INT_CAUSE_TX_DONE | ETH_INT_CAUSE_TX_ERROR) -#define ETH_INT_CAUSE_PHY 0x00010000 -#define ETH_INT_CAUSE_STATE 0x00100000 -#define ETH_INT_UNMASK_ALL_EXT (ETH_INT_CAUSE_TX | ETH_INT_CAUSE_PHY | \ - ETH_INT_CAUSE_STATE) - -#define ETH_INT_MASK_ALL 0x00000000 -#define ETH_INT_MASK_ALL_EXT 0x00000000 - -#define PHY_WAIT_ITERATIONS 1000 /* 1000 iterations * 10uS = 10mS max */ -#define PHY_WAIT_MICRO_SECONDS 10 - -/* Buffer offset from buffer pointer */ -#define RX_BUF_OFFSET 0x2 - -/* Gigabit Ethernet Unit Global Registers */ - -/* MIB Counters register definitions */ -#define ETH_MIB_GOOD_OCTETS_RECEIVED_LOW 0x0 -#define ETH_MIB_GOOD_OCTETS_RECEIVED_HIGH 0x4 -#define ETH_MIB_BAD_OCTETS_RECEIVED 0x8 -#define ETH_MIB_INTERNAL_MAC_TRANSMIT_ERR 0xc -#define ETH_MIB_GOOD_FRAMES_RECEIVED 0x10 -#define ETH_MIB_BAD_FRAMES_RECEIVED 0x14 -#define ETH_MIB_BROADCAST_FRAMES_RECEIVED 0x18 -#define ETH_MIB_MULTICAST_FRAMES_RECEIVED 0x1c -#define ETH_MIB_FRAMES_64_OCTETS 0x20 -#define ETH_MIB_FRAMES_65_TO_127_OCTETS 0x24 -#define ETH_MIB_FRAMES_128_TO_255_OCTETS 0x28 -#define ETH_MIB_FRAMES_256_TO_511_OCTETS 0x2c -#define ETH_MIB_FRAMES_512_TO_1023_OCTETS 0x30 -#define ETH_MIB_FRAMES_1024_TO_MAX_OCTETS 0x34 -#define ETH_MIB_GOOD_OCTETS_SENT_LOW 0x38 -#define ETH_MIB_GOOD_OCTETS_SENT_HIGH 0x3c -#define ETH_MIB_GOOD_FRAMES_SENT 0x40 -#define ETH_MIB_EXCESSIVE_COLLISION 0x44 -#define ETH_MIB_MULTICAST_FRAMES_SENT 0x48 -#define ETH_MIB_BROADCAST_FRAMES_SENT 0x4c -#define ETH_MIB_UNREC_MAC_CONTROL_RECEIVED 0x50 -#define ETH_MIB_FC_SENT 0x54 -#define ETH_MIB_GOOD_FC_RECEIVED 0x58 -#define ETH_MIB_BAD_FC_RECEIVED 0x5c -#define ETH_MIB_UNDERSIZE_RECEIVED 0x60 -#define ETH_MIB_FRAGMENTS_RECEIVED 0x64 -#define ETH_MIB_OVERSIZE_RECEIVED 0x68 -#define ETH_MIB_JABBER_RECEIVED 0x6c -#define ETH_MIB_MAC_RECEIVE_ERROR 0x70 -#define ETH_MIB_BAD_CRC_EVENT 0x74 -#define ETH_MIB_COLLISION 0x78 -#define ETH_MIB_LATE_COLLISION 0x7c - -/* Port serial status reg (PSR) */ -#define ETH_INTERFACE_PCM 0x00000001 -#define ETH_LINK_IS_UP 0x00000002 -#define ETH_PORT_AT_FULL_DUPLEX 0x00000004 -#define ETH_RX_FLOW_CTRL_ENABLED 0x00000008 -#define ETH_GMII_SPEED_1000 0x00000010 -#define ETH_MII_SPEED_100 0x00000020 -#define ETH_TX_IN_PROGRESS 0x00000080 -#define ETH_BYPASS_ACTIVE 0x00000100 -#define ETH_PORT_AT_PARTITION_STATE 0x00000200 -#define ETH_PORT_TX_FIFO_EMPTY 0x00000400 - -/* SMI reg */ -#define ETH_SMI_BUSY 0x10000000 /* 0 - Write, 1 - Read */ -#define ETH_SMI_READ_VALID 0x08000000 /* 0 - Write, 1 - Read */ -#define ETH_SMI_OPCODE_WRITE 0 /* Completion of Read */ -#define ETH_SMI_OPCODE_READ 0x04000000 /* Operation is in progress */ - -/* Interrupt Cause Register Bit Definitions */ - -/* SDMA command status fields macros */ - -/* Tx & Rx descriptors status */ -#define ETH_ERROR_SUMMARY 0x00000001 - -/* Tx & Rx descriptors command */ -#define ETH_BUFFER_OWNED_BY_DMA 0x80000000 - -/* Tx descriptors status */ -#define ETH_LC_ERROR 0 -#define ETH_UR_ERROR 0x00000002 -#define ETH_RL_ERROR 0x00000004 -#define ETH_LLC_SNAP_FORMAT 0x00000200 - -/* Rx descriptors status */ -#define ETH_OVERRUN_ERROR 0x00000002 -#define ETH_MAX_FRAME_LENGTH_ERROR 0x00000004 -#define ETH_RESOURCE_ERROR 0x00000006 -#define ETH_VLAN_TAGGED 0x00080000 -#define ETH_BPDU_FRAME 0x00100000 -#define ETH_UDP_FRAME_OVER_IP_V_4 0x00200000 -#define ETH_OTHER_FRAME_TYPE 0x00400000 -#define ETH_LAYER_2_IS_ETH_V_2 0x00800000 -#define ETH_FRAME_TYPE_IP_V_4 0x01000000 -#define ETH_FRAME_HEADER_OK 0x02000000 -#define ETH_RX_LAST_DESC 0x04000000 -#define ETH_RX_FIRST_DESC 0x08000000 -#define ETH_UNKNOWN_DESTINATION_ADDR 0x10000000 -#define ETH_RX_ENABLE_INTERRUPT 0x20000000 -#define ETH_LAYER_4_CHECKSUM_OK 0x40000000 - -/* Rx descriptors byte count */ -#define ETH_FRAME_FRAGMENTED 0x00000004 - -/* Tx descriptors command */ -#define ETH_LAYER_4_CHECKSUM_FIRST_DESC 0x00000400 -#define ETH_FRAME_SET_TO_VLAN 0x00008000 -#define ETH_UDP_FRAME 0x00010000 -#define ETH_GEN_TCP_UDP_CHECKSUM 0x00020000 -#define ETH_GEN_IP_V_4_CHECKSUM 0x00040000 -#define ETH_ZERO_PADDING 0x00080000 -#define ETH_TX_LAST_DESC 0x00100000 -#define ETH_TX_FIRST_DESC 0x00200000 -#define ETH_GEN_CRC 0x00400000 -#define ETH_TX_ENABLE_INTERRUPT 0x00800000 -#define ETH_AUTO_MODE 0x40000000 - -#define ETH_TX_IHL_SHIFT 11 - -/* typedefs */ - -typedef enum _eth_func_ret_status { - ETH_OK, /* Returned as expected. */ - ETH_ERROR, /* Fundamental error. */ - ETH_RETRY, /* Could not process request. Try later.*/ - ETH_END_OF_JOB, /* Ring has nothing to process. */ - ETH_QUEUE_FULL, /* Ring resource error. */ - ETH_QUEUE_LAST_RESOURCE /* Ring resources about to exhaust. */ -} ETH_FUNC_RET_STATUS; - -/* These are for big-endian machines. Little endian needs different - * definitions. +#define DEFAULT_RX_QUEUE_SIZE 400 +#define DEFAULT_TX_QUEUE_SIZE 800 + + +/* + * RX/TX descriptors. */ #if defined(__BIG_ENDIAN) -struct eth_rx_desc { +struct rx_desc { u16 byte_cnt; /* Descriptor buffer byte count */ u16 buf_size; /* Buffer size */ u32 cmd_sts; /* Descriptor command status */ @@ -441,7 +180,7 @@ struct eth_rx_desc { u32 buf_ptr; /* Descriptor buffer pointer */ }; -struct eth_tx_desc { +struct tx_desc { u16 byte_cnt; /* buffer byte count */ u16 l4i_chk; /* CPU provided TCP checksum */ u32 cmd_sts; /* Command/status field */ @@ -449,7 +188,7 @@ struct eth_tx_desc { u32 buf_ptr; /* pointer to buffer for this descriptor*/ }; #elif defined(__LITTLE_ENDIAN) -struct eth_rx_desc { +struct rx_desc { u32 cmd_sts; /* Descriptor command status */ u16 buf_size; /* Buffer size */ u16 byte_cnt; /* Descriptor buffer byte count */ @@ -457,7 +196,7 @@ struct eth_rx_desc { u32 next_desc_ptr; /* Next descriptor pointer */ }; -struct eth_tx_desc { +struct tx_desc { u32 cmd_sts; /* Command/status field */ u16 l4i_chk; /* CPU provided TCP checksum */ u16 byte_cnt; /* buffer byte count */ @@ -468,18 +207,59 @@ struct eth_tx_desc { #error One of __BIG_ENDIAN or __LITTLE_ENDIAN must be defined #endif -/* Unified struct for Rx and Tx operations. The user is not required to */ -/* be familier with neither Tx nor Rx descriptors. */ -struct pkt_info { - unsigned short byte_cnt; /* Descriptor buffer byte count */ - unsigned short l4i_chk; /* Tx CPU provided TCP Checksum */ - unsigned int cmd_sts; /* Descriptor command status */ - dma_addr_t buf_ptr; /* Descriptor buffer pointer */ - struct sk_buff *return_info; /* User resource return information */ +/* RX & TX descriptor command */ +#define BUFFER_OWNED_BY_DMA 0x80000000 + +/* RX & TX descriptor status */ +#define ERROR_SUMMARY 0x00000001 + +/* RX descriptor status */ +#define LAYER_4_CHECKSUM_OK 0x40000000 +#define RX_ENABLE_INTERRUPT 0x20000000 +#define RX_FIRST_DESC 0x08000000 +#define RX_LAST_DESC 0x04000000 + +/* TX descriptor command */ +#define TX_ENABLE_INTERRUPT 0x00800000 +#define GEN_CRC 0x00400000 +#define TX_FIRST_DESC 0x00200000 +#define TX_LAST_DESC 0x00100000 +#define ZERO_PADDING 0x00080000 +#define GEN_IP_V4_CHECKSUM 0x00040000 +#define GEN_TCP_UDP_CHECKSUM 0x00020000 +#define UDP_FRAME 0x00010000 + +#define TX_IHL_SHIFT 11 + + +/* global *******************************************************************/ +struct mv643xx_eth_shared_private { + /* + * Ethernet controller base address. + */ + void __iomem *base; + + /* + * Protects access to SMI_REG, which is shared between ports. + */ + spinlock_t phy_lock; + + /* + * Per-port MBUS window access register value. + */ + u32 win_protect; + + /* + * Hardware-specific parameters. + */ + unsigned int t_clk; + int extended_rx_coal_limit; + int tx_bw_control_moved; }; -/* Ethernet port specific information */ -struct mv643xx_mib_counters { + +/* per-port *****************************************************************/ +struct mib_counters { u64 good_octets_received; u32 bad_octets_received; u32 internal_mac_transmit_err; @@ -512,461 +292,282 @@ struct mv643xx_mib_counters { u32 late_collision; }; -struct mv643xx_shared_private { - void __iomem *eth_base; - - /* used to protect SMI_REG, which is shared across ports */ - spinlock_t phy_lock; +struct rx_queue { + int index; - u32 win_protect; - - unsigned int t_clk; -}; - -struct mv643xx_private { - struct mv643xx_shared_private *shared; - int port_num; /* User Ethernet port number */ - - struct mv643xx_shared_private *shared_smi; - - u32 rx_sram_addr; /* Base address of rx sram area */ - u32 rx_sram_size; /* Size of rx sram area */ - u32 tx_sram_addr; /* Base address of tx sram area */ - u32 tx_sram_size; /* Size of tx sram area */ + int rx_ring_size; - int rx_resource_err; /* Rx ring resource error flag */ + int rx_desc_count; + int rx_curr_desc; + int rx_used_desc; - /* Tx/Rx rings managment indexes fields. For driver use */ + struct rx_desc *rx_desc_area; + dma_addr_t rx_desc_dma; + int rx_desc_area_size; + struct sk_buff **rx_skb; - /* Next available and first returning Rx resource */ - int rx_curr_desc_q, rx_used_desc_q; + struct timer_list rx_oom; +}; - /* Next available and first returning Tx resource */ - int tx_curr_desc_q, tx_used_desc_q; +struct tx_queue { + int index; -#ifdef MV643XX_TX_FAST_REFILL - u32 tx_clean_threshold; -#endif + int tx_ring_size; - struct eth_rx_desc *p_rx_desc_area; - dma_addr_t rx_desc_dma; - int rx_desc_area_size; - struct sk_buff **rx_skb; + int tx_desc_count; + int tx_curr_desc; + int tx_used_desc; - struct eth_tx_desc *p_tx_desc_area; + struct tx_desc *tx_desc_area; dma_addr_t tx_desc_dma; int tx_desc_area_size; struct sk_buff **tx_skb; +}; - struct work_struct tx_timeout_task; +struct mv643xx_eth_private { + struct mv643xx_eth_shared_private *shared; + int port_num; struct net_device *dev; - struct napi_struct napi; - struct net_device_stats stats; - struct mv643xx_mib_counters mib_counters; + + struct mv643xx_eth_shared_private *shared_smi; + int phy_addr; + spinlock_t lock; - /* Size of Tx Ring per queue */ - int tx_ring_size; - /* Number of tx descriptors in use */ - int tx_desc_count; - /* Size of Rx Ring per queue */ - int rx_ring_size; - /* Number of rx descriptors in use */ - int rx_desc_count; + + struct mib_counters mib_counters; + struct work_struct tx_timeout_task; + struct mii_if_info mii; /* - * Used in case RX Ring is empty, which can be caused when - * system does not have resources (skb's) + * RX state. */ - struct timer_list timeout; - - u32 rx_int_coal; - u32 tx_int_coal; - struct mii_if_info mii; -}; + int default_rx_ring_size; + unsigned long rx_desc_sram_addr; + int rx_desc_sram_size; + u8 rxq_mask; + int rxq_primary; + struct napi_struct napi; + struct rx_queue rxq[8]; -/* Static function declarations */ -static void eth_port_init(struct mv643xx_private *mp); -static void eth_port_reset(struct mv643xx_private *mp); -static void eth_port_start(struct net_device *dev); - -static void ethernet_phy_reset(struct mv643xx_private *mp); - -static void eth_port_write_smi_reg(struct mv643xx_private *mp, - unsigned int phy_reg, unsigned int value); - -static void eth_port_read_smi_reg(struct mv643xx_private *mp, - unsigned int phy_reg, unsigned int *value); - -static void eth_clear_mib_counters(struct mv643xx_private *mp); - -static ETH_FUNC_RET_STATUS eth_port_receive(struct mv643xx_private *mp, - struct pkt_info *p_pkt_info); -static ETH_FUNC_RET_STATUS eth_rx_return_buff(struct mv643xx_private *mp, - struct pkt_info *p_pkt_info); - -static void eth_port_uc_addr_get(struct mv643xx_private *mp, - unsigned char *p_addr); -static void eth_port_uc_addr_set(struct mv643xx_private *mp, - unsigned char *p_addr); -static void eth_port_set_multicast_list(struct net_device *); -static void mv643xx_eth_port_enable_tx(struct mv643xx_private *mp, - unsigned int queues); -static void mv643xx_eth_port_enable_rx(struct mv643xx_private *mp, - unsigned int queues); -static unsigned int mv643xx_eth_port_disable_tx(struct mv643xx_private *mp); -static unsigned int mv643xx_eth_port_disable_rx(struct mv643xx_private *mp); -static int mv643xx_eth_open(struct net_device *); -static int mv643xx_eth_stop(struct net_device *); -static void eth_port_init_mac_tables(struct mv643xx_private *mp); -#ifdef MV643XX_NAPI -static int mv643xx_poll(struct napi_struct *napi, int budget); + /* + * TX state. + */ + int default_tx_ring_size; + unsigned long tx_desc_sram_addr; + int tx_desc_sram_size; + u8 txq_mask; + int txq_primary; + struct tx_queue txq[8]; +#ifdef MV643XX_ETH_TX_FAST_REFILL + int tx_clean_threshold; #endif -static int ethernet_phy_get(struct mv643xx_private *mp); -static void ethernet_phy_set(struct mv643xx_private *mp, int phy_addr); -static int ethernet_phy_detect(struct mv643xx_private *mp); -static int mv643xx_mdio_read(struct net_device *dev, int phy_id, int location); -static void mv643xx_mdio_write(struct net_device *dev, int phy_id, int location, int val); -static int mv643xx_eth_do_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd); -static const struct ethtool_ops mv643xx_ethtool_ops; +}; -static char mv643xx_driver_name[] = "mv643xx_eth"; -static char mv643xx_driver_version[] = "1.0"; -static inline u32 rdl(struct mv643xx_private *mp, int offset) +/* port register accessors **************************************************/ +static inline u32 rdl(struct mv643xx_eth_private *mp, int offset) { - return readl(mp->shared->eth_base + offset); + return readl(mp->shared->base + offset); } -static inline void wrl(struct mv643xx_private *mp, int offset, u32 data) +static inline void wrl(struct mv643xx_eth_private *mp, int offset, u32 data) { - writel(data, mp->shared->eth_base + offset); + writel(data, mp->shared->base + offset); } -/* - * Changes MTU (maximum transfer unit) of the gigabit ethenret port - * - * Input : pointer to ethernet interface network device structure - * new mtu size - * Output : 0 upon success, -EINVAL upon failure - */ -static int mv643xx_eth_change_mtu(struct net_device *dev, int new_mtu) -{ - if ((new_mtu > 9500) || (new_mtu < 64)) - return -EINVAL; - dev->mtu = new_mtu; - if (!netif_running(dev)) - return 0; - - /* - * Stop and then re-open the interface. This will allocate RX - * skbs of the new MTU. - * There is a possible danger that the open will not succeed, - * due to memory being full, which might fail the open function. - */ - mv643xx_eth_stop(dev); - if (mv643xx_eth_open(dev)) { - printk(KERN_ERR "%s: Fatal error on opening device\n", - dev->name); - } - - return 0; -} - -/* - * mv643xx_eth_rx_refill_descs - * - * Fills / refills RX queue on a certain gigabit ethernet port - * - * Input : pointer to ethernet interface network device structure - * Output : N/A - */ -static void mv643xx_eth_rx_refill_descs(struct net_device *dev) +/* rxq/txq helper functions *************************************************/ +static struct mv643xx_eth_private *rxq_to_mp(struct rx_queue *rxq) { - struct mv643xx_private *mp = netdev_priv(dev); - struct pkt_info pkt_info; - struct sk_buff *skb; - int unaligned; - - while (mp->rx_desc_count < mp->rx_ring_size) { - skb = dev_alloc_skb(ETH_RX_SKB_SIZE + dma_get_cache_alignment()); - if (!skb) - break; - mp->rx_desc_count++; - unaligned = (u32)skb->data & (dma_get_cache_alignment() - 1); - if (unaligned) - skb_reserve(skb, dma_get_cache_alignment() - unaligned); - pkt_info.cmd_sts = ETH_RX_ENABLE_INTERRUPT; - pkt_info.byte_cnt = ETH_RX_SKB_SIZE; - pkt_info.buf_ptr = dma_map_single(NULL, skb->data, - ETH_RX_SKB_SIZE, DMA_FROM_DEVICE); - pkt_info.return_info = skb; - if (eth_rx_return_buff(mp, &pkt_info) != ETH_OK) { - printk(KERN_ERR - "%s: Error allocating RX Ring\n", dev->name); - break; - } - skb_reserve(skb, ETH_HW_IP_ALIGN); - } - /* - * If RX ring is empty of SKB, set a timer to try allocating - * again at a later time. - */ - if (mp->rx_desc_count == 0) { - printk(KERN_INFO "%s: Rx ring is empty\n", dev->name); - mp->timeout.expires = jiffies + (HZ / 10); /* 100 mSec */ - add_timer(&mp->timeout); - } + return container_of(rxq, struct mv643xx_eth_private, rxq[rxq->index]); } -/* - * mv643xx_eth_rx_refill_descs_timer_wrapper - * - * Timer routine to wake up RX queue filling task. This function is - * used only in case the RX queue is empty, and all alloc_skb has - * failed (due to out of memory event). - * - * Input : pointer to ethernet interface network device structure - * Output : N/A - */ -static inline void mv643xx_eth_rx_refill_descs_timer_wrapper(unsigned long data) +static struct mv643xx_eth_private *txq_to_mp(struct tx_queue *txq) { - mv643xx_eth_rx_refill_descs((struct net_device *)data); + return container_of(txq, struct mv643xx_eth_private, txq[txq->index]); } -/* - * mv643xx_eth_update_mac_address - * - * Update the MAC address of the port in the address table - * - * Input : pointer to ethernet interface network device structure - * Output : N/A - */ -static void mv643xx_eth_update_mac_address(struct net_device *dev) +static void rxq_enable(struct rx_queue *rxq) { - struct mv643xx_private *mp = netdev_priv(dev); - - eth_port_init_mac_tables(mp); - eth_port_uc_addr_set(mp, dev->dev_addr); + struct mv643xx_eth_private *mp = rxq_to_mp(rxq); + wrl(mp, RXQ_COMMAND(mp->port_num), 1 << rxq->index); } -/* - * mv643xx_eth_set_rx_mode - * - * Change from promiscuos to regular rx mode - * - * Input : pointer to ethernet interface network device structure - * Output : N/A - */ -static void mv643xx_eth_set_rx_mode(struct net_device *dev) +static void rxq_disable(struct rx_queue *rxq) { - struct mv643xx_private *mp = netdev_priv(dev); - u32 config_reg; + struct mv643xx_eth_private *mp = rxq_to_mp(rxq); + u8 mask = 1 << rxq->index; - config_reg = rdl(mp, PORT_CONFIG_REG(mp->port_num)); - if (dev->flags & IFF_PROMISC) - config_reg |= (u32) UNICAST_PROMISCUOUS_MODE; - else - config_reg &= ~(u32) UNICAST_PROMISCUOUS_MODE; - wrl(mp, PORT_CONFIG_REG(mp->port_num), config_reg); - - eth_port_set_multicast_list(dev); + wrl(mp, RXQ_COMMAND(mp->port_num), mask << 8); + while (rdl(mp, RXQ_COMMAND(mp->port_num)) & mask) + udelay(10); } -/* - * mv643xx_eth_set_mac_address - * - * Change the interface's mac address. - * No special hardware thing should be done because interface is always - * put in promiscuous mode. - * - * Input : pointer to ethernet interface network device structure and - * a pointer to the designated entry to be added to the cache. - * Output : zero upon success, negative upon failure - */ -static int mv643xx_eth_set_mac_address(struct net_device *dev, void *addr) +static void txq_enable(struct tx_queue *txq) { - int i; - - for (i = 0; i < 6; i++) - /* +2 is for the offset of the HW addr type */ - dev->dev_addr[i] = ((unsigned char *)addr)[i + 2]; - mv643xx_eth_update_mac_address(dev); - return 0; + struct mv643xx_eth_private *mp = txq_to_mp(txq); + wrl(mp, TXQ_COMMAND(mp->port_num), 1 << txq->index); } -/* - * mv643xx_eth_tx_timeout - * - * Called upon a timeout on transmitting a packet - * - * Input : pointer to ethernet interface network device structure. - * Output : N/A - */ -static void mv643xx_eth_tx_timeout(struct net_device *dev) +static void txq_disable(struct tx_queue *txq) { - struct mv643xx_private *mp = netdev_priv(dev); - - printk(KERN_INFO "%s: TX timeout ", dev->name); + struct mv643xx_eth_private *mp = txq_to_mp(txq); + u8 mask = 1 << txq->index; - /* Do the reset outside of interrupt context */ - schedule_work(&mp->tx_timeout_task); + wrl(mp, TXQ_COMMAND(mp->port_num), mask << 8); + while (rdl(mp, TXQ_COMMAND(mp->port_num)) & mask) + udelay(10); } -/* - * mv643xx_eth_tx_timeout_task - * - * Actual routine to reset the adapter when a timeout on Tx has occurred - */ -static void mv643xx_eth_tx_timeout_task(struct work_struct *ugly) +static void __txq_maybe_wake(struct tx_queue *txq) { - struct mv643xx_private *mp = container_of(ugly, struct mv643xx_private, - tx_timeout_task); - struct net_device *dev = mp->dev; + struct mv643xx_eth_private *mp = txq_to_mp(txq); - if (!netif_running(dev)) - return; + /* + * netif_{stop,wake}_queue() flow control only applies to + * the primary queue. + */ + BUG_ON(txq->index != mp->txq_primary); - netif_stop_queue(dev); + if (txq->tx_ring_size - txq->tx_desc_count >= MAX_DESCS_PER_SKB) + netif_wake_queue(mp->dev); +} - eth_port_reset(mp); - eth_port_start(dev); - if (mp->tx_ring_size - mp->tx_desc_count >= MAX_DESCS_PER_SKB) - netif_wake_queue(dev); -} +/* rx ***********************************************************************/ +static void txq_reclaim(struct tx_queue *txq, int force); -/** - * mv643xx_eth_free_tx_descs - Free the tx desc data for completed descriptors - * - * If force is non-zero, frees uncompleted descriptors as well - */ -static int mv643xx_eth_free_tx_descs(struct net_device *dev, int force) +static void rxq_refill(struct rx_queue *rxq) { - struct mv643xx_private *mp = netdev_priv(dev); - struct eth_tx_desc *desc; - u32 cmd_sts; - struct sk_buff *skb; + struct mv643xx_eth_private *mp = rxq_to_mp(rxq); unsigned long flags; - int tx_index; - dma_addr_t addr; - int count; - int released = 0; - while (mp->tx_desc_count > 0) { - spin_lock_irqsave(&mp->lock, flags); - - /* tx_desc_count might have changed before acquiring the lock */ - if (mp->tx_desc_count <= 0) { - spin_unlock_irqrestore(&mp->lock, flags); - return released; - } - - tx_index = mp->tx_used_desc_q; - desc = &mp->p_tx_desc_area[tx_index]; - cmd_sts = desc->cmd_sts; + spin_lock_irqsave(&mp->lock, flags); - if (!force && (cmd_sts & ETH_BUFFER_OWNED_BY_DMA)) { - spin_unlock_irqrestore(&mp->lock, flags); - return released; - } + while (rxq->rx_desc_count < rxq->rx_ring_size) { + int skb_size; + struct sk_buff *skb; + int unaligned; + int rx; - mp->tx_used_desc_q = (tx_index + 1) % mp->tx_ring_size; - mp->tx_desc_count--; + /* + * Reserve 2+14 bytes for an ethernet header (the + * hardware automatically prepends 2 bytes of dummy + * data to each received packet), 4 bytes for a VLAN + * header, and 4 bytes for the trailing FCS -- 24 + * bytes total. + */ + skb_size = mp->dev->mtu + 24; - addr = desc->buf_ptr; - count = desc->byte_cnt; - skb = mp->tx_skb[tx_index]; - if (skb) - mp->tx_skb[tx_index] = NULL; + skb = dev_alloc_skb(skb_size + dma_get_cache_alignment() - 1); + if (skb == NULL) + break; - if (cmd_sts & ETH_ERROR_SUMMARY) { - printk("%s: Error in TX\n", dev->name); - dev->stats.tx_errors++; - } + unaligned = (u32)skb->data & (dma_get_cache_alignment() - 1); + if (unaligned) + skb_reserve(skb, dma_get_cache_alignment() - unaligned); - spin_unlock_irqrestore(&mp->lock, flags); + rxq->rx_desc_count++; + rx = rxq->rx_used_desc; + rxq->rx_used_desc = (rx + 1) % rxq->rx_ring_size; - if (cmd_sts & ETH_TX_FIRST_DESC) - dma_unmap_single(NULL, addr, count, DMA_TO_DEVICE); - else - dma_unmap_page(NULL, addr, count, DMA_TO_DEVICE); + rxq->rx_desc_area[rx].buf_ptr = dma_map_single(NULL, skb->data, + skb_size, DMA_FROM_DEVICE); + rxq->rx_desc_area[rx].buf_size = skb_size; + rxq->rx_skb[rx] = skb; + wmb(); + rxq->rx_desc_area[rx].cmd_sts = BUFFER_OWNED_BY_DMA | + RX_ENABLE_INTERRUPT; + wmb(); - if (skb) - dev_kfree_skb_irq(skb); + /* + * The hardware automatically prepends 2 bytes of + * dummy data to each received packet, so that the + * IP header ends up 16-byte aligned. + */ + skb_reserve(skb, 2); + } - released = 1; + if (rxq->rx_desc_count != rxq->rx_ring_size) { + rxq->rx_oom.expires = jiffies + (HZ / 10); + add_timer(&rxq->rx_oom); } - return released; + spin_unlock_irqrestore(&mp->lock, flags); } -static void mv643xx_eth_free_completed_tx_descs(struct net_device *dev) +static inline void rxq_refill_timer_wrapper(unsigned long data) { - struct mv643xx_private *mp = netdev_priv(dev); - - if (mv643xx_eth_free_tx_descs(dev, 0) && - mp->tx_ring_size - mp->tx_desc_count >= MAX_DESCS_PER_SKB) - netif_wake_queue(dev); + rxq_refill((struct rx_queue *)data); } -static void mv643xx_eth_free_all_tx_descs(struct net_device *dev) +static int rxq_process(struct rx_queue *rxq, int budget) { - mv643xx_eth_free_tx_descs(dev, 1); -} + struct mv643xx_eth_private *mp = rxq_to_mp(rxq); + struct net_device_stats *stats = &mp->dev->stats; + int rx; -/* - * mv643xx_eth_receive - * - * This function is forward packets that are received from the port's - * queues toward kernel core or FastRoute them to another interface. - * - * Input : dev - a pointer to the required interface - * max - maximum number to receive (0 means unlimted) - * - * Output : number of served packets - */ -static int mv643xx_eth_receive_queue(struct net_device *dev, int budget) -{ - struct mv643xx_private *mp = netdev_priv(dev); - struct net_device_stats *stats = &dev->stats; - unsigned int received_packets = 0; - struct sk_buff *skb; - struct pkt_info pkt_info; + rx = 0; + while (rx < budget) { + struct rx_desc *rx_desc; + unsigned int cmd_sts; + struct sk_buff *skb; + unsigned long flags; + + spin_lock_irqsave(&mp->lock, flags); + + rx_desc = &rxq->rx_desc_area[rxq->rx_curr_desc]; + + cmd_sts = rx_desc->cmd_sts; + if (cmd_sts & BUFFER_OWNED_BY_DMA) { + spin_unlock_irqrestore(&mp->lock, flags); + break; + } + rmb(); + + skb = rxq->rx_skb[rxq->rx_curr_desc]; + rxq->rx_skb[rxq->rx_curr_desc] = NULL; - while (budget-- > 0 && eth_port_receive(mp, &pkt_info) == ETH_OK) { - dma_unmap_single(NULL, pkt_info.buf_ptr, ETH_RX_SKB_SIZE, - DMA_FROM_DEVICE); - mp->rx_desc_count--; - received_packets++; + rxq->rx_curr_desc = (rxq->rx_curr_desc + 1) % rxq->rx_ring_size; + + spin_unlock_irqrestore(&mp->lock, flags); + + dma_unmap_single(NULL, rx_desc->buf_ptr + 2, + mp->dev->mtu + 24, DMA_FROM_DEVICE); + rxq->rx_desc_count--; + rx++; /* * Update statistics. - * Note byte count includes 4 byte CRC count + * + * Note that the descriptor byte count includes 2 dummy + * bytes automatically inserted by the hardware at the + * start of the packet (which we don't count), and a 4 + * byte CRC at the end of the packet (which we do count). */ stats->rx_packets++; - stats->rx_bytes += pkt_info.byte_cnt; - skb = pkt_info.return_info; + stats->rx_bytes += rx_desc->byte_cnt - 2; + /* - * In case received a packet without first / last bits on OR - * the error summary bit is on, the packets needs to be dropeed. + * In case we received a packet without first / last bits + * on, or the error summary bit is set, the packet needs + * to be dropped. */ - if (((pkt_info.cmd_sts - & (ETH_RX_FIRST_DESC | ETH_RX_LAST_DESC)) != - (ETH_RX_FIRST_DESC | ETH_RX_LAST_DESC)) - || (pkt_info.cmd_sts & ETH_ERROR_SUMMARY)) { + if (((cmd_sts & (RX_FIRST_DESC | RX_LAST_DESC)) != + (RX_FIRST_DESC | RX_LAST_DESC)) + || (cmd_sts & ERROR_SUMMARY)) { stats->rx_dropped++; - if ((pkt_info.cmd_sts & (ETH_RX_FIRST_DESC | - ETH_RX_LAST_DESC)) != - (ETH_RX_FIRST_DESC | ETH_RX_LAST_DESC)) { + + if ((cmd_sts & (RX_FIRST_DESC | RX_LAST_DESC)) != + (RX_FIRST_DESC | RX_LAST_DESC)) { if (net_ratelimit()) - printk(KERN_ERR - "%s: Received packet spread " - "on multiple descriptors\n", - dev->name); + dev_printk(KERN_ERR, &mp->dev->dev, + "received packet spanning " + "multiple descriptors\n"); } - if (pkt_info.cmd_sts & ETH_ERROR_SUMMARY) + + if (cmd_sts & ERROR_SUMMARY) stats->rx_errors++; dev_kfree_skb_irq(skb); @@ -975,2391 +576,2003 @@ static int mv643xx_eth_receive_queue(struct net_device *dev, int budget) * The -4 is for the CRC in the trailer of the * received packet */ - skb_put(skb, pkt_info.byte_cnt - 4); + skb_put(skb, rx_desc->byte_cnt - 2 - 4); - if (pkt_info.cmd_sts & ETH_LAYER_4_CHECKSUM_OK) { + if (cmd_sts & LAYER_4_CHECKSUM_OK) { skb->ip_summed = CHECKSUM_UNNECESSARY; skb->csum = htons( - (pkt_info.cmd_sts & 0x0007fff8) >> 3); + (cmd_sts & 0x0007fff8) >> 3); } - skb->protocol = eth_type_trans(skb, dev); -#ifdef MV643XX_NAPI + skb->protocol = eth_type_trans(skb, mp->dev); +#ifdef MV643XX_ETH_NAPI netif_receive_skb(skb); #else netif_rx(skb); #endif } - dev->last_rx = jiffies; + + mp->dev->last_rx = jiffies; } - mv643xx_eth_rx_refill_descs(dev); /* Fill RX ring with skb's */ - return received_packets; + rxq_refill(rxq); + + return rx; } -/* Set the mv643xx port configuration register for the speed/duplex mode. */ -static void mv643xx_eth_update_pscr(struct net_device *dev, - struct ethtool_cmd *ecmd) +#ifdef MV643XX_ETH_NAPI +static int mv643xx_eth_poll(struct napi_struct *napi, int budget) { - struct mv643xx_private *mp = netdev_priv(dev); - int port_num = mp->port_num; - u32 o_pscr, n_pscr; - unsigned int queues; + struct mv643xx_eth_private *mp; + int rx; + int i; - o_pscr = rdl(mp, PORT_SERIAL_CONTROL_REG(port_num)); - n_pscr = o_pscr; + mp = container_of(napi, struct mv643xx_eth_private, napi); - /* clear speed, duplex and rx buffer size fields */ - n_pscr &= ~(SET_MII_SPEED_TO_100 | - SET_GMII_SPEED_TO_1000 | - SET_FULL_DUPLEX_MODE | - MAX_RX_PACKET_MASK); - - if (ecmd->duplex == DUPLEX_FULL) - n_pscr |= SET_FULL_DUPLEX_MODE; - - if (ecmd->speed == SPEED_1000) - n_pscr |= SET_GMII_SPEED_TO_1000 | - MAX_RX_PACKET_9700BYTE; - else { - if (ecmd->speed == SPEED_100) - n_pscr |= SET_MII_SPEED_TO_100; - n_pscr |= MAX_RX_PACKET_1522BYTE; +#ifdef MV643XX_ETH_TX_FAST_REFILL + if (++mp->tx_clean_threshold > 5) { + mp->tx_clean_threshold = 0; + for (i = 0; i < 8; i++) + if (mp->txq_mask & (1 << i)) + txq_reclaim(mp->txq + i, 0); } +#endif - if (n_pscr != o_pscr) { - if ((o_pscr & SERIAL_PORT_ENABLE) == 0) - wrl(mp, PORT_SERIAL_CONTROL_REG(port_num), n_pscr); - else { - queues = mv643xx_eth_port_disable_tx(mp); - - o_pscr &= ~SERIAL_PORT_ENABLE; - wrl(mp, PORT_SERIAL_CONTROL_REG(port_num), o_pscr); - wrl(mp, PORT_SERIAL_CONTROL_REG(port_num), n_pscr); - wrl(mp, PORT_SERIAL_CONTROL_REG(port_num), n_pscr); - if (queues) - mv643xx_eth_port_enable_tx(mp, queues); - } + rx = 0; + for (i = 7; rx < budget && i >= 0; i--) + if (mp->rxq_mask & (1 << i)) + rx += rxq_process(mp->rxq + i, budget - rx); + + if (rx < budget) { + netif_rx_complete(mp->dev, napi); + wrl(mp, INT_CAUSE(mp->port_num), 0); + wrl(mp, INT_CAUSE_EXT(mp->port_num), 0); + wrl(mp, INT_MASK(mp->port_num), INT_TX_END | INT_RX | INT_EXT); } + + return rx; } +#endif -/* - * mv643xx_eth_int_handler - * - * Main interrupt handler for the gigbit ethernet ports - * - * Input : irq - irq number (not used) - * dev_id - a pointer to the required interface's data structure - * regs - not used - * Output : N/A - */ -static irqreturn_t mv643xx_eth_int_handler(int irq, void *dev_id) +/* tx ***********************************************************************/ +static inline unsigned int has_tiny_unaligned_frags(struct sk_buff *skb) { - struct net_device *dev = (struct net_device *)dev_id; - struct mv643xx_private *mp = netdev_priv(dev); - u32 eth_int_cause, eth_int_cause_ext = 0; - unsigned int port_num = mp->port_num; - - /* Read interrupt cause registers */ - eth_int_cause = rdl(mp, INTERRUPT_CAUSE_REG(port_num)) & - ETH_INT_UNMASK_ALL; - if (eth_int_cause & ETH_INT_CAUSE_EXT) { - eth_int_cause_ext = rdl(mp, - INTERRUPT_CAUSE_EXTEND_REG(port_num)) & - ETH_INT_UNMASK_ALL_EXT; - wrl(mp, INTERRUPT_CAUSE_EXTEND_REG(port_num), - ~eth_int_cause_ext); - } - - /* PHY status changed */ - if (eth_int_cause_ext & (ETH_INT_CAUSE_PHY | ETH_INT_CAUSE_STATE)) { - struct ethtool_cmd cmd; + int frag; - if (mii_link_ok(&mp->mii)) { - mii_ethtool_gset(&mp->mii, &cmd); - mv643xx_eth_update_pscr(dev, &cmd); - mv643xx_eth_port_enable_tx(mp, ETH_TX_QUEUES_ENABLED); - if (!netif_carrier_ok(dev)) { - netif_carrier_on(dev); - if (mp->tx_ring_size - mp->tx_desc_count >= - MAX_DESCS_PER_SKB) - netif_wake_queue(dev); - } - } else if (netif_carrier_ok(dev)) { - netif_stop_queue(dev); - netif_carrier_off(dev); - } + for (frag = 0; frag < skb_shinfo(skb)->nr_frags; frag++) { + skb_frag_t *fragp = &skb_shinfo(skb)->frags[frag]; + if (fragp->size <= 8 && fragp->page_offset & 7) + return 1; } -#ifdef MV643XX_NAPI - if (eth_int_cause & ETH_INT_CAUSE_RX) { - /* schedule the NAPI poll routine to maintain port */ - wrl(mp, INTERRUPT_MASK_REG(port_num), ETH_INT_MASK_ALL); + return 0; +} - /* wait for previous write to complete */ - rdl(mp, INTERRUPT_MASK_REG(port_num)); +static int txq_alloc_desc_index(struct tx_queue *txq) +{ + int tx_desc_curr; - netif_rx_schedule(dev, &mp->napi); - } -#else - if (eth_int_cause & ETH_INT_CAUSE_RX) - mv643xx_eth_receive_queue(dev, INT_MAX); -#endif - if (eth_int_cause_ext & ETH_INT_CAUSE_TX) - mv643xx_eth_free_completed_tx_descs(dev); + BUG_ON(txq->tx_desc_count >= txq->tx_ring_size); - /* - * If no real interrupt occured, exit. - * This can happen when using gigE interrupt coalescing mechanism. - */ - if ((eth_int_cause == 0x0) && (eth_int_cause_ext == 0x0)) - return IRQ_NONE; + tx_desc_curr = txq->tx_curr_desc; + txq->tx_curr_desc = (tx_desc_curr + 1) % txq->tx_ring_size; - return IRQ_HANDLED; -} + BUG_ON(txq->tx_curr_desc == txq->tx_used_desc); -#ifdef MV643XX_COAL + return tx_desc_curr; +} -/* - * eth_port_set_rx_coal - Sets coalescing interrupt mechanism on RX path - * - * DESCRIPTION: - * This routine sets the RX coalescing interrupt mechanism parameter. - * This parameter is a timeout counter, that counts in 64 t_clk - * chunks ; that when timeout event occurs a maskable interrupt - * occurs. - * The parameter is calculated using the tClk of the MV-643xx chip - * , and the required delay of the interrupt in usec. - * - * INPUT: - * struct mv643xx_private *mp Ethernet port - * unsigned int delay Delay in usec - * - * OUTPUT: - * Interrupt coalescing mechanism value is set in MV-643xx chip. - * - * RETURN: - * The interrupt coalescing value set in the gigE port. - * - */ -static unsigned int eth_port_set_rx_coal(struct mv643xx_private *mp, - unsigned int delay) +static void txq_submit_frag_skb(struct tx_queue *txq, struct sk_buff *skb) { - unsigned int port_num = mp->port_num; - unsigned int coal = ((mp->shared->t_clk / 1000000) * delay) / 64; + int nr_frags = skb_shinfo(skb)->nr_frags; + int frag; - /* Set RX Coalescing mechanism */ - wrl(mp, SDMA_CONFIG_REG(port_num), - ((coal & 0x3fff) << 8) | - (rdl(mp, SDMA_CONFIG_REG(port_num)) - & 0xffc000ff)); + for (frag = 0; frag < nr_frags; frag++) { + skb_frag_t *this_frag; + int tx_index; + struct tx_desc *desc; - return coal; -} -#endif + this_frag = &skb_shinfo(skb)->frags[frag]; + tx_index = txq_alloc_desc_index(txq); + desc = &txq->tx_desc_area[tx_index]; -/* - * eth_port_set_tx_coal - Sets coalescing interrupt mechanism on TX path - * - * DESCRIPTION: - * This routine sets the TX coalescing interrupt mechanism parameter. - * This parameter is a timeout counter, that counts in 64 t_clk - * chunks ; that when timeout event occurs a maskable interrupt - * occurs. - * The parameter is calculated using the t_cLK frequency of the - * MV-643xx chip and the required delay in the interrupt in uSec - * - * INPUT: - * struct mv643xx_private *mp Ethernet port - * unsigned int delay Delay in uSeconds - * - * OUTPUT: - * Interrupt coalescing mechanism value is set in MV-643xx chip. - * - * RETURN: - * The interrupt coalescing value set in the gigE port. - * - */ -static unsigned int eth_port_set_tx_coal(struct mv643xx_private *mp, - unsigned int delay) -{ - unsigned int coal = ((mp->shared->t_clk / 1000000) * delay) / 64; + /* + * The last fragment will generate an interrupt + * which will free the skb on TX completion. + */ + if (frag == nr_frags - 1) { + desc->cmd_sts = BUFFER_OWNED_BY_DMA | + ZERO_PADDING | TX_LAST_DESC | + TX_ENABLE_INTERRUPT; + txq->tx_skb[tx_index] = skb; + } else { + desc->cmd_sts = BUFFER_OWNED_BY_DMA; + txq->tx_skb[tx_index] = NULL; + } - /* Set TX Coalescing mechanism */ - wrl(mp, TX_FIFO_URGENT_THRESHOLD_REG(mp->port_num), coal << 4); + desc->l4i_chk = 0; + desc->byte_cnt = this_frag->size; + desc->buf_ptr = dma_map_page(NULL, this_frag->page, + this_frag->page_offset, + this_frag->size, + DMA_TO_DEVICE); + } +} - return coal; +static inline __be16 sum16_as_be(__sum16 sum) +{ + return (__force __be16)sum; } -/* - * ether_init_rx_desc_ring - Curve a Rx chain desc list and buffer in memory. - * - * DESCRIPTION: - * This function prepares a Rx chained list of descriptors and packet - * buffers in a form of a ring. The routine must be called after port - * initialization routine and before port start routine. - * The Ethernet SDMA engine uses CPU bus addresses to access the various - * devices in the system (i.e. DRAM). This function uses the ethernet - * struct 'virtual to physical' routine (set by the user) to set the ring - * with physical addresses. - * - * INPUT: - * struct mv643xx_private *mp Ethernet Port Control srtuct. - * - * OUTPUT: - * The routine updates the Ethernet port control struct with information - * regarding the Rx descriptors and buffers. - * - * RETURN: - * None. - */ -static void ether_init_rx_desc_ring(struct mv643xx_private *mp) +static void txq_submit_skb(struct tx_queue *txq, struct sk_buff *skb) { - volatile struct eth_rx_desc *p_rx_desc; - int rx_desc_num = mp->rx_ring_size; - int i; + int nr_frags = skb_shinfo(skb)->nr_frags; + int tx_index; + struct tx_desc *desc; + u32 cmd_sts; + int length; - /* initialize the next_desc_ptr links in the Rx descriptors ring */ - p_rx_desc = (struct eth_rx_desc *)mp->p_rx_desc_area; - for (i = 0; i < rx_desc_num; i++) { - p_rx_desc[i].next_desc_ptr = mp->rx_desc_dma + - ((i + 1) % rx_desc_num) * sizeof(struct eth_rx_desc); + cmd_sts = TX_FIRST_DESC | GEN_CRC | BUFFER_OWNED_BY_DMA; + + tx_index = txq_alloc_desc_index(txq); + desc = &txq->tx_desc_area[tx_index]; + + if (nr_frags) { + txq_submit_frag_skb(txq, skb); + + length = skb_headlen(skb); + txq->tx_skb[tx_index] = NULL; + } else { + cmd_sts |= ZERO_PADDING | TX_LAST_DESC | TX_ENABLE_INTERRUPT; + length = skb->len; + txq->tx_skb[tx_index] = skb; } - /* Save Rx desc pointer to driver struct. */ - mp->rx_curr_desc_q = 0; - mp->rx_used_desc_q = 0; + desc->byte_cnt = length; + desc->buf_ptr = dma_map_single(NULL, skb->data, length, DMA_TO_DEVICE); - mp->rx_desc_area_size = rx_desc_num * sizeof(struct eth_rx_desc); -} + if (skb->ip_summed == CHECKSUM_PARTIAL) { + BUG_ON(skb->protocol != htons(ETH_P_IP)); -/* - * ether_init_tx_desc_ring - Curve a Tx chain desc list and buffer in memory. - * - * DESCRIPTION: - * This function prepares a Tx chained list of descriptors and packet - * buffers in a form of a ring. The routine must be called after port - * initialization routine and before port start routine. - * The Ethernet SDMA engine uses CPU bus addresses to access the various - * devices in the system (i.e. DRAM). This function uses the ethernet - * struct 'virtual to physical' routine (set by the user) to set the ring - * with physical addresses. - * - * INPUT: - * struct mv643xx_private *mp Ethernet Port Control srtuct. - * - * OUTPUT: - * The routine updates the Ethernet port control struct with information - * regarding the Tx descriptors and buffers. - * - * RETURN: - * None. - */ -static void ether_init_tx_desc_ring(struct mv643xx_private *mp) -{ - int tx_desc_num = mp->tx_ring_size; - struct eth_tx_desc *p_tx_desc; - int i; + cmd_sts |= GEN_TCP_UDP_CHECKSUM | + GEN_IP_V4_CHECKSUM | + ip_hdr(skb)->ihl << TX_IHL_SHIFT; - /* Initialize the next_desc_ptr links in the Tx descriptors ring */ - p_tx_desc = (struct eth_tx_desc *)mp->p_tx_desc_area; - for (i = 0; i < tx_desc_num; i++) { - p_tx_desc[i].next_desc_ptr = mp->tx_desc_dma + - ((i + 1) % tx_desc_num) * sizeof(struct eth_tx_desc); + switch (ip_hdr(skb)->protocol) { + case IPPROTO_UDP: + cmd_sts |= UDP_FRAME; + desc->l4i_chk = ntohs(sum16_as_be(udp_hdr(skb)->check)); + break; + case IPPROTO_TCP: + desc->l4i_chk = ntohs(sum16_as_be(tcp_hdr(skb)->check)); + break; + default: + BUG(); + } + } else { + /* Errata BTS #50, IHL must be 5 if no HW checksum */ + cmd_sts |= 5 << TX_IHL_SHIFT; + desc->l4i_chk = 0; } - mp->tx_curr_desc_q = 0; - mp->tx_used_desc_q = 0; + /* ensure all other descriptors are written before first cmd_sts */ + wmb(); + desc->cmd_sts = cmd_sts; + + /* ensure all descriptors are written before poking hardware */ + wmb(); + txq_enable(txq); - mp->tx_desc_area_size = tx_desc_num * sizeof(struct eth_tx_desc); + txq->tx_desc_count += nr_frags + 1; } -static int mv643xx_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) +static int mv643xx_eth_xmit(struct sk_buff *skb, struct net_device *dev) { - struct mv643xx_private *mp = netdev_priv(dev); - int err; + struct mv643xx_eth_private *mp = netdev_priv(dev); + struct net_device_stats *stats = &dev->stats; + struct tx_queue *txq; + unsigned long flags; - spin_lock_irq(&mp->lock); - err = mii_ethtool_sset(&mp->mii, cmd); - spin_unlock_irq(&mp->lock); + if (has_tiny_unaligned_frags(skb) && __skb_linearize(skb)) { + stats->tx_dropped++; + dev_printk(KERN_DEBUG, &dev->dev, + "failed to linearize skb with tiny " + "unaligned fragment\n"); + return NETDEV_TX_BUSY; + } - return err; -} + spin_lock_irqsave(&mp->lock, flags); -static int mv643xx_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) -{ - struct mv643xx_private *mp = netdev_priv(dev); - int err; + txq = mp->txq + mp->txq_primary; - spin_lock_irq(&mp->lock); - err = mii_ethtool_gset(&mp->mii, cmd); - spin_unlock_irq(&mp->lock); + if (txq->tx_ring_size - txq->tx_desc_count < MAX_DESCS_PER_SKB) { + spin_unlock_irqrestore(&mp->lock, flags); + if (txq->index == mp->txq_primary && net_ratelimit()) + dev_printk(KERN_ERR, &dev->dev, + "primary tx queue full?!\n"); + kfree_skb(skb); + return NETDEV_TX_OK; + } - /* The PHY may support 1000baseT_Half, but the mv643xx does not */ - cmd->supported &= ~SUPPORTED_1000baseT_Half; - cmd->advertising &= ~ADVERTISED_1000baseT_Half; + txq_submit_skb(txq, skb); + stats->tx_bytes += skb->len; + stats->tx_packets++; + dev->trans_start = jiffies; - return err; + if (txq->index == mp->txq_primary) { + int entries_left; + + entries_left = txq->tx_ring_size - txq->tx_desc_count; + if (entries_left < MAX_DESCS_PER_SKB) + netif_stop_queue(dev); + } + + spin_unlock_irqrestore(&mp->lock, flags); + + return NETDEV_TX_OK; } + +/* tx rate control **********************************************************/ /* - * mv643xx_eth_open - * - * This function is called when openning the network device. The function - * should initialize all the hardware, initialize cyclic Rx/Tx - * descriptors chain and buffers and allocate an IRQ to the network - * device. - * - * Input : a pointer to the network device structure - * - * Output : zero of success , nonzero if fails. + * Set total maximum TX rate (shared by all TX queues for this port) + * to 'rate' bits per second, with a maximum burst of 'burst' bytes. */ - -static int mv643xx_eth_open(struct net_device *dev) +static void tx_set_rate(struct mv643xx_eth_private *mp, int rate, int burst) { - struct mv643xx_private *mp = netdev_priv(dev); - unsigned int port_num = mp->port_num; - unsigned int size; - int err; + int token_rate; + int mtu; + int bucket_size; - /* Clear any pending ethernet port interrupts */ - wrl(mp, INTERRUPT_CAUSE_REG(port_num), 0); - wrl(mp, INTERRUPT_CAUSE_EXTEND_REG(port_num), 0); - /* wait for previous write to complete */ - rdl(mp, INTERRUPT_CAUSE_EXTEND_REG(port_num)); + token_rate = ((rate / 1000) * 64) / (mp->shared->t_clk / 1000); + if (token_rate > 1023) + token_rate = 1023; - err = request_irq(dev->irq, mv643xx_eth_int_handler, - IRQF_SHARED | IRQF_SAMPLE_RANDOM, dev->name, dev); - if (err) { - printk(KERN_ERR "%s: Can not assign IRQ\n", dev->name); - return -EAGAIN; - } + mtu = (mp->dev->mtu + 255) >> 8; + if (mtu > 63) + mtu = 63; - eth_port_init(mp); + bucket_size = (burst + 255) >> 8; + if (bucket_size > 65535) + bucket_size = 65535; - memset(&mp->timeout, 0, sizeof(struct timer_list)); - mp->timeout.function = mv643xx_eth_rx_refill_descs_timer_wrapper; - mp->timeout.data = (unsigned long)dev; - - /* Allocate RX and TX skb rings */ - mp->rx_skb = kmalloc(sizeof(*mp->rx_skb) * mp->rx_ring_size, - GFP_KERNEL); - if (!mp->rx_skb) { - printk(KERN_ERR "%s: Cannot allocate Rx skb ring\n", dev->name); - err = -ENOMEM; - goto out_free_irq; - } - mp->tx_skb = kmalloc(sizeof(*mp->tx_skb) * mp->tx_ring_size, - GFP_KERNEL); - if (!mp->tx_skb) { - printk(KERN_ERR "%s: Cannot allocate Tx skb ring\n", dev->name); - err = -ENOMEM; - goto out_free_rx_skb; + if (mp->shared->tx_bw_control_moved) { + wrl(mp, TX_BW_RATE_MOVED(mp->port_num), token_rate); + wrl(mp, TX_BW_MTU_MOVED(mp->port_num), mtu); + wrl(mp, TX_BW_BURST_MOVED(mp->port_num), bucket_size); + } else { + wrl(mp, TX_BW_RATE(mp->port_num), token_rate); + wrl(mp, TX_BW_MTU(mp->port_num), mtu); + wrl(mp, TX_BW_BURST(mp->port_num), bucket_size); } +} - /* Allocate TX ring */ - mp->tx_desc_count = 0; - size = mp->tx_ring_size * sizeof(struct eth_tx_desc); - mp->tx_desc_area_size = size; - - if (mp->tx_sram_size) { - mp->p_tx_desc_area = ioremap(mp->tx_sram_addr, - mp->tx_sram_size); - mp->tx_desc_dma = mp->tx_sram_addr; - } else - mp->p_tx_desc_area = dma_alloc_coherent(NULL, size, - &mp->tx_desc_dma, - GFP_KERNEL); +static void txq_set_rate(struct tx_queue *txq, int rate, int burst) +{ + struct mv643xx_eth_private *mp = txq_to_mp(txq); + int token_rate; + int bucket_size; - if (!mp->p_tx_desc_area) { - printk(KERN_ERR "%s: Cannot allocate Tx Ring (size %d bytes)\n", - dev->name, size); - err = -ENOMEM; - goto out_free_tx_skb; - } - BUG_ON((u32) mp->p_tx_desc_area & 0xf); /* check 16-byte alignment */ - memset((void *)mp->p_tx_desc_area, 0, mp->tx_desc_area_size); - - ether_init_tx_desc_ring(mp); - - /* Allocate RX ring */ - mp->rx_desc_count = 0; - size = mp->rx_ring_size * sizeof(struct eth_rx_desc); - mp->rx_desc_area_size = size; - - if (mp->rx_sram_size) { - mp->p_rx_desc_area = ioremap(mp->rx_sram_addr, - mp->rx_sram_size); - mp->rx_desc_dma = mp->rx_sram_addr; - } else - mp->p_rx_desc_area = dma_alloc_coherent(NULL, size, - &mp->rx_desc_dma, - GFP_KERNEL); + token_rate = ((rate / 1000) * 64) / (mp->shared->t_clk / 1000); + if (token_rate > 1023) + token_rate = 1023; - if (!mp->p_rx_desc_area) { - printk(KERN_ERR "%s: Cannot allocate Rx ring (size %d bytes)\n", - dev->name, size); - printk(KERN_ERR "%s: Freeing previously allocated TX queues...", - dev->name); - if (mp->rx_sram_size) - iounmap(mp->p_tx_desc_area); - else - dma_free_coherent(NULL, mp->tx_desc_area_size, - mp->p_tx_desc_area, mp->tx_desc_dma); - err = -ENOMEM; - goto out_free_tx_skb; - } - memset((void *)mp->p_rx_desc_area, 0, size); + bucket_size = (burst + 255) >> 8; + if (bucket_size > 65535) + bucket_size = 65535; - ether_init_rx_desc_ring(mp); - - mv643xx_eth_rx_refill_descs(dev); /* Fill RX ring with skb's */ + wrl(mp, TXQ_BW_TOKENS(mp->port_num, txq->index), token_rate << 14); + wrl(mp, TXQ_BW_CONF(mp->port_num, txq->index), + (bucket_size << 10) | token_rate); +} -#ifdef MV643XX_NAPI - napi_enable(&mp->napi); -#endif +static void txq_set_fixed_prio_mode(struct tx_queue *txq) +{ + struct mv643xx_eth_private *mp = txq_to_mp(txq); + int off; + u32 val; - eth_port_start(dev); + /* + * Turn on fixed priority mode. + */ + if (mp->shared->tx_bw_control_moved) + off = TXQ_FIX_PRIO_CONF_MOVED(mp->port_num); + else + off = TXQ_FIX_PRIO_CONF(mp->port_num); - /* Interrupt Coalescing */ + val = rdl(mp, off); + val |= 1 << txq->index; + wrl(mp, off, val); +} -#ifdef MV643XX_COAL - mp->rx_int_coal = - eth_port_set_rx_coal(mp, MV643XX_RX_COAL); -#endif +static void txq_set_wrr(struct tx_queue *txq, int weight) +{ + struct mv643xx_eth_private *mp = txq_to_mp(txq); + int off; + u32 val; - mp->tx_int_coal = - eth_port_set_tx_coal(mp, MV643XX_TX_COAL); + /* + * Turn off fixed priority mode. + */ + if (mp->shared->tx_bw_control_moved) + off = TXQ_FIX_PRIO_CONF_MOVED(mp->port_num); + else + off = TXQ_FIX_PRIO_CONF(mp->port_num); - /* Unmask phy and link status changes interrupts */ - wrl(mp, INTERRUPT_EXTEND_MASK_REG(port_num), ETH_INT_UNMASK_ALL_EXT); + val = rdl(mp, off); + val &= ~(1 << txq->index); + wrl(mp, off, val); - /* Unmask RX buffer and TX end interrupt */ - wrl(mp, INTERRUPT_MASK_REG(port_num), ETH_INT_UNMASK_ALL); + /* + * Configure WRR weight for this queue. + */ + off = TXQ_BW_WRR_CONF(mp->port_num, txq->index); - return 0; + val = rdl(mp, off); + val = (val & ~0xff) | (weight & 0xff); + wrl(mp, off, val); +} -out_free_tx_skb: - kfree(mp->tx_skb); -out_free_rx_skb: - kfree(mp->rx_skb); -out_free_irq: - free_irq(dev->irq, dev); - return err; -} +/* mii management interface *************************************************/ +#define SMI_BUSY 0x10000000 +#define SMI_READ_VALID 0x08000000 +#define SMI_OPCODE_READ 0x04000000 +#define SMI_OPCODE_WRITE 0x00000000 -static void mv643xx_eth_free_tx_rings(struct net_device *dev) +static void smi_reg_read(struct mv643xx_eth_private *mp, unsigned int addr, + unsigned int reg, unsigned int *value) { - struct mv643xx_private *mp = netdev_priv(dev); + void __iomem *smi_reg = mp->shared_smi->base + SMI_REG; + unsigned long flags; + int i; - /* Stop Tx Queues */ - mv643xx_eth_port_disable_tx(mp); + /* the SMI register is a shared resource */ + spin_lock_irqsave(&mp->shared_smi->phy_lock, flags); - /* Free outstanding skb's on TX ring */ - mv643xx_eth_free_all_tx_descs(dev); + /* wait for the SMI register to become available */ + for (i = 0; readl(smi_reg) & SMI_BUSY; i++) { + if (i == 1000) { + printk("%s: PHY busy timeout\n", mp->dev->name); + goto out; + } + udelay(10); + } - BUG_ON(mp->tx_used_desc_q != mp->tx_curr_desc_q); + writel(SMI_OPCODE_READ | (reg << 21) | (addr << 16), smi_reg); - /* Free TX ring */ - if (mp->tx_sram_size) - iounmap(mp->p_tx_desc_area); - else - dma_free_coherent(NULL, mp->tx_desc_area_size, - mp->p_tx_desc_area, mp->tx_desc_dma); + /* now wait for the data to be valid */ + for (i = 0; !(readl(smi_reg) & SMI_READ_VALID); i++) { + if (i == 1000) { + printk("%s: PHY read timeout\n", mp->dev->name); + goto out; + } + udelay(10); + } + + *value = readl(smi_reg) & 0xffff; +out: + spin_unlock_irqrestore(&mp->shared_smi->phy_lock, flags); } -static void mv643xx_eth_free_rx_rings(struct net_device *dev) +static void smi_reg_write(struct mv643xx_eth_private *mp, + unsigned int addr, + unsigned int reg, unsigned int value) { - struct mv643xx_private *mp = netdev_priv(dev); - int curr; + void __iomem *smi_reg = mp->shared_smi->base + SMI_REG; + unsigned long flags; + int i; - /* Stop RX Queues */ - mv643xx_eth_port_disable_rx(mp); + /* the SMI register is a shared resource */ + spin_lock_irqsave(&mp->shared_smi->phy_lock, flags); - /* Free preallocated skb's on RX rings */ - for (curr = 0; mp->rx_desc_count && curr < mp->rx_ring_size; curr++) { - if (mp->rx_skb[curr]) { - dev_kfree_skb(mp->rx_skb[curr]); - mp->rx_desc_count--; + /* wait for the SMI register to become available */ + for (i = 0; readl(smi_reg) & SMI_BUSY; i++) { + if (i == 1000) { + printk("%s: PHY busy timeout\n", mp->dev->name); + goto out; } + udelay(10); } - if (mp->rx_desc_count) - printk(KERN_ERR - "%s: Error in freeing Rx Ring. %d skb's still" - " stuck in RX Ring - ignoring them\n", dev->name, - mp->rx_desc_count); - /* Free RX ring */ - if (mp->rx_sram_size) - iounmap(mp->p_rx_desc_area); - else - dma_free_coherent(NULL, mp->rx_desc_area_size, - mp->p_rx_desc_area, mp->rx_desc_dma); + writel(SMI_OPCODE_WRITE | (reg << 21) | + (addr << 16) | (value & 0xffff), smi_reg); +out: + spin_unlock_irqrestore(&mp->shared_smi->phy_lock, flags); } -/* - * mv643xx_eth_stop - * - * This function is used when closing the network device. - * It updates the hardware, - * release all memory that holds buffers and descriptors and release the IRQ. - * Input : a pointer to the device structure - * Output : zero if success , nonzero if fails - */ -static int mv643xx_eth_stop(struct net_device *dev) +/* mib counters *************************************************************/ +static inline u32 mib_read(struct mv643xx_eth_private *mp, int offset) { - struct mv643xx_private *mp = netdev_priv(dev); - unsigned int port_num = mp->port_num; + return rdl(mp, MIB_COUNTERS(mp->port_num) + offset); +} - /* Mask all interrupts on ethernet port */ - wrl(mp, INTERRUPT_MASK_REG(port_num), ETH_INT_MASK_ALL); - /* wait for previous write to complete */ - rdl(mp, INTERRUPT_MASK_REG(port_num)); +static void mib_counters_clear(struct mv643xx_eth_private *mp) +{ + int i; -#ifdef MV643XX_NAPI - napi_disable(&mp->napi); -#endif - netif_carrier_off(dev); - netif_stop_queue(dev); + for (i = 0; i < 0x80; i += 4) + mib_read(mp, i); +} + +static void mib_counters_update(struct mv643xx_eth_private *mp) +{ + struct mib_counters *p = &mp->mib_counters; + + p->good_octets_received += mib_read(mp, 0x00); + p->good_octets_received += (u64)mib_read(mp, 0x04) << 32; + p->bad_octets_received += mib_read(mp, 0x08); + p->internal_mac_transmit_err += mib_read(mp, 0x0c); + p->good_frames_received += mib_read(mp, 0x10); + p->bad_frames_received += mib_read(mp, 0x14); + p->broadcast_frames_received += mib_read(mp, 0x18); + p->multicast_frames_received += mib_read(mp, 0x1c); + p->frames_64_octets += mib_read(mp, 0x20); + p->frames_65_to_127_octets += mib_read(mp, 0x24); + p->frames_128_to_255_octets += mib_read(mp, 0x28); + p->frames_256_to_511_octets += mib_read(mp, 0x2c); + p->frames_512_to_1023_octets += mib_read(mp, 0x30); + p->frames_1024_to_max_octets += mib_read(mp, 0x34); + p->good_octets_sent += mib_read(mp, 0x38); + p->good_octets_sent += (u64)mib_read(mp, 0x3c) << 32; + p->good_frames_sent += mib_read(mp, 0x40); + p->excessive_collision += mib_read(mp, 0x44); + p->multicast_frames_sent += mib_read(mp, 0x48); + p->broadcast_frames_sent += mib_read(mp, 0x4c); + p->unrec_mac_control_received += mib_read(mp, 0x50); + p->fc_sent += mib_read(mp, 0x54); + p->good_fc_received += mib_read(mp, 0x58); + p->bad_fc_received += mib_read(mp, 0x5c); + p->undersize_received += mib_read(mp, 0x60); + p->fragments_received += mib_read(mp, 0x64); + p->oversize_received += mib_read(mp, 0x68); + p->jabber_received += mib_read(mp, 0x6c); + p->mac_receive_error += mib_read(mp, 0x70); + p->bad_crc_event += mib_read(mp, 0x74); + p->collision += mib_read(mp, 0x78); + p->late_collision += mib_read(mp, 0x7c); +} + + +/* ethtool ******************************************************************/ +struct mv643xx_eth_stats { + char stat_string[ETH_GSTRING_LEN]; + int sizeof_stat; + int netdev_off; + int mp_off; +}; + +#define SSTAT(m) \ + { #m, FIELD_SIZEOF(struct net_device_stats, m), \ + offsetof(struct net_device, stats.m), -1 } + +#define MIBSTAT(m) \ + { #m, FIELD_SIZEOF(struct mib_counters, m), \ + -1, offsetof(struct mv643xx_eth_private, mib_counters.m) } + +static const struct mv643xx_eth_stats mv643xx_eth_stats[] = { + SSTAT(rx_packets), + SSTAT(tx_packets), + SSTAT(rx_bytes), + SSTAT(tx_bytes), + SSTAT(rx_errors), + SSTAT(tx_errors), + SSTAT(rx_dropped), + SSTAT(tx_dropped), + MIBSTAT(good_octets_received), + MIBSTAT(bad_octets_received), + MIBSTAT(internal_mac_transmit_err), + MIBSTAT(good_frames_received), + MIBSTAT(bad_frames_received), + MIBSTAT(broadcast_frames_received), + MIBSTAT(multicast_frames_received), + MIBSTAT(frames_64_octets), + MIBSTAT(frames_65_to_127_octets), + MIBSTAT(frames_128_to_255_octets), + MIBSTAT(frames_256_to_511_octets), + MIBSTAT(frames_512_to_1023_octets), + MIBSTAT(frames_1024_to_max_octets), + MIBSTAT(good_octets_sent), + MIBSTAT(good_frames_sent), + MIBSTAT(excessive_collision), + MIBSTAT(multicast_frames_sent), + MIBSTAT(broadcast_frames_sent), + MIBSTAT(unrec_mac_control_received), + MIBSTAT(fc_sent), + MIBSTAT(good_fc_received), + MIBSTAT(bad_fc_received), + MIBSTAT(undersize_received), + MIBSTAT(fragments_received), + MIBSTAT(oversize_received), + MIBSTAT(jabber_received), + MIBSTAT(mac_receive_error), + MIBSTAT(bad_crc_event), + MIBSTAT(collision), + MIBSTAT(late_collision), +}; - eth_port_reset(mp); +static int mv643xx_eth_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) +{ + struct mv643xx_eth_private *mp = netdev_priv(dev); + int err; - mv643xx_eth_free_tx_rings(dev); - mv643xx_eth_free_rx_rings(dev); + spin_lock_irq(&mp->lock); + err = mii_ethtool_gset(&mp->mii, cmd); + spin_unlock_irq(&mp->lock); - free_irq(dev->irq, dev); + /* + * The MAC does not support 1000baseT_Half. + */ + cmd->supported &= ~SUPPORTED_1000baseT_Half; + cmd->advertising &= ~ADVERTISED_1000baseT_Half; + + return err; +} + +static int mv643xx_eth_get_settings_phyless(struct net_device *dev, struct ethtool_cmd *cmd) +{ + cmd->supported = SUPPORTED_MII; + cmd->advertising = ADVERTISED_MII; + cmd->speed = SPEED_1000; + cmd->duplex = DUPLEX_FULL; + cmd->port = PORT_MII; + cmd->phy_address = 0; + cmd->transceiver = XCVR_INTERNAL; + cmd->autoneg = AUTONEG_DISABLE; + cmd->maxtxpkt = 1; + cmd->maxrxpkt = 1; return 0; } -#ifdef MV643XX_NAPI -/* - * mv643xx_poll - * - * This function is used in case of NAPI - */ -static int mv643xx_poll(struct napi_struct *napi, int budget) +static int mv643xx_eth_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) { - struct mv643xx_private *mp = container_of(napi, struct mv643xx_private, napi); - struct net_device *dev = mp->dev; - unsigned int port_num = mp->port_num; - int work_done; + struct mv643xx_eth_private *mp = netdev_priv(dev); + int err; -#ifdef MV643XX_TX_FAST_REFILL - if (++mp->tx_clean_threshold > 5) { - mv643xx_eth_free_completed_tx_descs(dev); - mp->tx_clean_threshold = 0; - } -#endif + /* + * The MAC does not support 1000baseT_Half. + */ + cmd->advertising &= ~ADVERTISED_1000baseT_Half; - work_done = 0; - if ((rdl(mp, RX_CURRENT_QUEUE_DESC_PTR_0(port_num))) - != (u32) mp->rx_used_desc_q) - work_done = mv643xx_eth_receive_queue(dev, budget); + spin_lock_irq(&mp->lock); + err = mii_ethtool_sset(&mp->mii, cmd); + spin_unlock_irq(&mp->lock); - if (work_done < budget) { - netif_rx_complete(dev, napi); - wrl(mp, INTERRUPT_CAUSE_REG(port_num), 0); - wrl(mp, INTERRUPT_CAUSE_EXTEND_REG(port_num), 0); - wrl(mp, INTERRUPT_MASK_REG(port_num), ETH_INT_UNMASK_ALL); - } + return err; +} - return work_done; +static int mv643xx_eth_set_settings_phyless(struct net_device *dev, struct ethtool_cmd *cmd) +{ + return -EINVAL; } -#endif -/** - * has_tiny_unaligned_frags - check if skb has any small, unaligned fragments - * - * Hardware can't handle unaligned fragments smaller than 9 bytes. - * This helper function detects that case. - */ +static void mv643xx_eth_get_drvinfo(struct net_device *dev, + struct ethtool_drvinfo *drvinfo) +{ + strncpy(drvinfo->driver, mv643xx_eth_driver_name, 32); + strncpy(drvinfo->version, mv643xx_eth_driver_version, 32); + strncpy(drvinfo->fw_version, "N/A", 32); + strncpy(drvinfo->bus_info, "platform", 32); + drvinfo->n_stats = ARRAY_SIZE(mv643xx_eth_stats); +} -static inline unsigned int has_tiny_unaligned_frags(struct sk_buff *skb) +static int mv643xx_eth_nway_reset(struct net_device *dev) { - unsigned int frag; - skb_frag_t *fragp; + struct mv643xx_eth_private *mp = netdev_priv(dev); - for (frag = 0; frag < skb_shinfo(skb)->nr_frags; frag++) { - fragp = &skb_shinfo(skb)->frags[frag]; - if (fragp->size <= 8 && fragp->page_offset & 0x7) - return 1; - } - return 0; + return mii_nway_restart(&mp->mii); } -/** - * eth_alloc_tx_desc_index - return the index of the next available tx desc - */ -static int eth_alloc_tx_desc_index(struct mv643xx_private *mp) +static int mv643xx_eth_nway_reset_phyless(struct net_device *dev) { - int tx_desc_curr; - - BUG_ON(mp->tx_desc_count >= mp->tx_ring_size); + return -EINVAL; +} - tx_desc_curr = mp->tx_curr_desc_q; - mp->tx_curr_desc_q = (tx_desc_curr + 1) % mp->tx_ring_size; +static u32 mv643xx_eth_get_link(struct net_device *dev) +{ + struct mv643xx_eth_private *mp = netdev_priv(dev); - BUG_ON(mp->tx_curr_desc_q == mp->tx_used_desc_q); + return mii_link_ok(&mp->mii); +} - return tx_desc_curr; +static u32 mv643xx_eth_get_link_phyless(struct net_device *dev) +{ + return 1; } -/** - * eth_tx_fill_frag_descs - fill tx hw descriptors for an skb's fragments. - * - * Ensure the data for each fragment to be transmitted is mapped properly, - * then fill in descriptors in the tx hw queue. - */ -static void eth_tx_fill_frag_descs(struct mv643xx_private *mp, - struct sk_buff *skb) +static void mv643xx_eth_get_strings(struct net_device *dev, + uint32_t stringset, uint8_t *data) { - int frag; - int tx_index; - struct eth_tx_desc *desc; + int i; - for (frag = 0; frag < skb_shinfo(skb)->nr_frags; frag++) { - skb_frag_t *this_frag = &skb_shinfo(skb)->frags[frag]; - - tx_index = eth_alloc_tx_desc_index(mp); - desc = &mp->p_tx_desc_area[tx_index]; - - desc->cmd_sts = ETH_BUFFER_OWNED_BY_DMA; - /* Last Frag enables interrupt and frees the skb */ - if (frag == (skb_shinfo(skb)->nr_frags - 1)) { - desc->cmd_sts |= ETH_ZERO_PADDING | - ETH_TX_LAST_DESC | - ETH_TX_ENABLE_INTERRUPT; - mp->tx_skb[tx_index] = skb; - } else - mp->tx_skb[tx_index] = NULL; - - desc = &mp->p_tx_desc_area[tx_index]; - desc->l4i_chk = 0; - desc->byte_cnt = this_frag->size; - desc->buf_ptr = dma_map_page(NULL, this_frag->page, - this_frag->page_offset, - this_frag->size, - DMA_TO_DEVICE); + if (stringset == ETH_SS_STATS) { + for (i = 0; i < ARRAY_SIZE(mv643xx_eth_stats); i++) { + memcpy(data + i * ETH_GSTRING_LEN, + mv643xx_eth_stats[i].stat_string, + ETH_GSTRING_LEN); + } } } -static inline __be16 sum16_as_be(__sum16 sum) +static void mv643xx_eth_get_ethtool_stats(struct net_device *dev, + struct ethtool_stats *stats, + uint64_t *data) { - return (__force __be16)sum; -} + struct mv643xx_eth_private *mp = dev->priv; + int i; -/** - * eth_tx_submit_descs_for_skb - submit data from an skb to the tx hw - * - * Ensure the data for an skb to be transmitted is mapped properly, - * then fill in descriptors in the tx hw queue and start the hardware. - */ -static void eth_tx_submit_descs_for_skb(struct mv643xx_private *mp, - struct sk_buff *skb) -{ - int tx_index; - struct eth_tx_desc *desc; - u32 cmd_sts; - int length; - int nr_frags = skb_shinfo(skb)->nr_frags; + mib_counters_update(mp); - cmd_sts = ETH_TX_FIRST_DESC | ETH_GEN_CRC | ETH_BUFFER_OWNED_BY_DMA; + for (i = 0; i < ARRAY_SIZE(mv643xx_eth_stats); i++) { + const struct mv643xx_eth_stats *stat; + void *p; - tx_index = eth_alloc_tx_desc_index(mp); - desc = &mp->p_tx_desc_area[tx_index]; + stat = mv643xx_eth_stats + i; - if (nr_frags) { - eth_tx_fill_frag_descs(mp, skb); + if (stat->netdev_off >= 0) + p = ((void *)mp->dev) + stat->netdev_off; + else + p = ((void *)mp) + stat->mp_off; - length = skb_headlen(skb); - mp->tx_skb[tx_index] = NULL; - } else { - cmd_sts |= ETH_ZERO_PADDING | - ETH_TX_LAST_DESC | - ETH_TX_ENABLE_INTERRUPT; - length = skb->len; - mp->tx_skb[tx_index] = skb; + data[i] = (stat->sizeof_stat == 8) ? + *(uint64_t *)p : *(uint32_t *)p; } +} - desc->byte_cnt = length; - desc->buf_ptr = dma_map_single(NULL, skb->data, length, DMA_TO_DEVICE); +static int mv643xx_eth_get_sset_count(struct net_device *dev, int sset) +{ + if (sset == ETH_SS_STATS) + return ARRAY_SIZE(mv643xx_eth_stats); - if (skb->ip_summed == CHECKSUM_PARTIAL) { - BUG_ON(skb->protocol != htons(ETH_P_IP)); + return -EOPNOTSUPP; +} - cmd_sts |= ETH_GEN_TCP_UDP_CHECKSUM | - ETH_GEN_IP_V_4_CHECKSUM | - ip_hdr(skb)->ihl << ETH_TX_IHL_SHIFT; +static const struct ethtool_ops mv643xx_eth_ethtool_ops = { + .get_settings = mv643xx_eth_get_settings, + .set_settings = mv643xx_eth_set_settings, + .get_drvinfo = mv643xx_eth_get_drvinfo, + .nway_reset = mv643xx_eth_nway_reset, + .get_link = mv643xx_eth_get_link, + .set_sg = ethtool_op_set_sg, + .get_strings = mv643xx_eth_get_strings, + .get_ethtool_stats = mv643xx_eth_get_ethtool_stats, + .get_sset_count = mv643xx_eth_get_sset_count, +}; - switch (ip_hdr(skb)->protocol) { - case IPPROTO_UDP: - cmd_sts |= ETH_UDP_FRAME; - desc->l4i_chk = ntohs(sum16_as_be(udp_hdr(skb)->check)); - break; - case IPPROTO_TCP: - desc->l4i_chk = ntohs(sum16_as_be(tcp_hdr(skb)->check)); - break; - default: - BUG(); - } - } else { - /* Errata BTS #50, IHL must be 5 if no HW checksum */ - cmd_sts |= 5 << ETH_TX_IHL_SHIFT; - desc->l4i_chk = 0; - } +static const struct ethtool_ops mv643xx_eth_ethtool_ops_phyless = { + .get_settings = mv643xx_eth_get_settings_phyless, + .set_settings = mv643xx_eth_set_settings_phyless, + .get_drvinfo = mv643xx_eth_get_drvinfo, + .nway_reset = mv643xx_eth_nway_reset_phyless, + .get_link = mv643xx_eth_get_link_phyless, + .set_sg = ethtool_op_set_sg, + .get_strings = mv643xx_eth_get_strings, + .get_ethtool_stats = mv643xx_eth_get_ethtool_stats, + .get_sset_count = mv643xx_eth_get_sset_count, +}; - /* ensure all other descriptors are written before first cmd_sts */ - wmb(); - desc->cmd_sts = cmd_sts; - /* ensure all descriptors are written before poking hardware */ - wmb(); - mv643xx_eth_port_enable_tx(mp, ETH_TX_QUEUES_ENABLED); +/* address handling *********************************************************/ +static void uc_addr_get(struct mv643xx_eth_private *mp, unsigned char *addr) +{ + unsigned int mac_h; + unsigned int mac_l; + + mac_h = rdl(mp, MAC_ADDR_HIGH(mp->port_num)); + mac_l = rdl(mp, MAC_ADDR_LOW(mp->port_num)); - mp->tx_desc_count += nr_frags + 1; + addr[0] = (mac_h >> 24) & 0xff; + addr[1] = (mac_h >> 16) & 0xff; + addr[2] = (mac_h >> 8) & 0xff; + addr[3] = mac_h & 0xff; + addr[4] = (mac_l >> 8) & 0xff; + addr[5] = mac_l & 0xff; } -/** - * mv643xx_eth_start_xmit - queue an skb to the hardware for transmission - * - */ -static int mv643xx_eth_start_xmit(struct sk_buff *skb, struct net_device *dev) +static void init_mac_tables(struct mv643xx_eth_private *mp) { - struct mv643xx_private *mp = netdev_priv(dev); - struct net_device_stats *stats = &dev->stats; - unsigned long flags; - - BUG_ON(netif_queue_stopped(dev)); + int i; - if (has_tiny_unaligned_frags(skb) && __skb_linearize(skb)) { - stats->tx_dropped++; - printk(KERN_DEBUG "%s: failed to linearize tiny " - "unaligned fragment\n", dev->name); - return NETDEV_TX_BUSY; + for (i = 0; i < 0x100; i += 4) { + wrl(mp, SPECIAL_MCAST_TABLE(mp->port_num) + i, 0); + wrl(mp, OTHER_MCAST_TABLE(mp->port_num) + i, 0); } - spin_lock_irqsave(&mp->lock, flags); + for (i = 0; i < 0x10; i += 4) + wrl(mp, UNICAST_TABLE(mp->port_num) + i, 0); +} - if (mp->tx_ring_size - mp->tx_desc_count < MAX_DESCS_PER_SKB) { - printk(KERN_ERR "%s: transmit with queue full\n", dev->name); - netif_stop_queue(dev); - spin_unlock_irqrestore(&mp->lock, flags); - return NETDEV_TX_BUSY; - } +static void set_filter_table_entry(struct mv643xx_eth_private *mp, + int table, unsigned char entry) +{ + unsigned int table_reg; - eth_tx_submit_descs_for_skb(mp, skb); - stats->tx_bytes += skb->len; - stats->tx_packets++; - dev->trans_start = jiffies; + /* Set "accepts frame bit" at specified table entry */ + table_reg = rdl(mp, table + (entry & 0xfc)); + table_reg |= 0x01 << (8 * (entry & 3)); + wrl(mp, table + (entry & 0xfc), table_reg); +} - if (mp->tx_ring_size - mp->tx_desc_count < MAX_DESCS_PER_SKB) - netif_stop_queue(dev); +static void uc_addr_set(struct mv643xx_eth_private *mp, unsigned char *addr) +{ + unsigned int mac_h; + unsigned int mac_l; + int table; - spin_unlock_irqrestore(&mp->lock, flags); + mac_l = (addr[4] << 8) | addr[5]; + mac_h = (addr[0] << 24) | (addr[1] << 16) | (addr[2] << 8) | addr[3]; - return NETDEV_TX_OK; + wrl(mp, MAC_ADDR_LOW(mp->port_num), mac_l); + wrl(mp, MAC_ADDR_HIGH(mp->port_num), mac_h); + + table = UNICAST_TABLE(mp->port_num); + set_filter_table_entry(mp, table, addr[5] & 0x0f); } -#ifdef CONFIG_NET_POLL_CONTROLLER -static void mv643xx_netpoll(struct net_device *netdev) +static int mv643xx_eth_set_mac_address(struct net_device *dev, void *addr) { - struct mv643xx_private *mp = netdev_priv(netdev); - int port_num = mp->port_num; + struct mv643xx_eth_private *mp = netdev_priv(dev); - wrl(mp, INTERRUPT_MASK_REG(port_num), ETH_INT_MASK_ALL); - /* wait for previous write to complete */ - rdl(mp, INTERRUPT_MASK_REG(port_num)); + /* +2 is for the offset of the HW addr type */ + memcpy(dev->dev_addr, addr + 2, 6); - mv643xx_eth_int_handler(netdev->irq, netdev); + init_mac_tables(mp); + uc_addr_set(mp, dev->dev_addr); - wrl(mp, INTERRUPT_MASK_REG(port_num), ETH_INT_UNMASK_ALL); + return 0; } -#endif -static void mv643xx_init_ethtool_cmd(struct net_device *dev, int phy_address, - int speed, int duplex, - struct ethtool_cmd *cmd) +static int addr_crc(unsigned char *addr) { - struct mv643xx_private *mp = netdev_priv(dev); + int crc = 0; + int i; - memset(cmd, 0, sizeof(*cmd)); + for (i = 0; i < 6; i++) { + int j; - cmd->port = PORT_MII; - cmd->transceiver = XCVR_INTERNAL; - cmd->phy_address = phy_address; - - if (speed == 0) { - cmd->autoneg = AUTONEG_ENABLE; - /* mii lib checks, but doesn't use speed on AUTONEG_ENABLE */ - cmd->speed = SPEED_100; - cmd->advertising = ADVERTISED_10baseT_Half | - ADVERTISED_10baseT_Full | - ADVERTISED_100baseT_Half | - ADVERTISED_100baseT_Full; - if (mp->mii.supports_gmii) - cmd->advertising |= ADVERTISED_1000baseT_Full; - } else { - cmd->autoneg = AUTONEG_DISABLE; - cmd->speed = speed; - cmd->duplex = duplex; + crc = (crc ^ addr[i]) << 8; + for (j = 7; j >= 0; j--) { + if (crc & (0x100 << j)) + crc ^= 0x107 << j; + } } + + return crc; } -/*/ - * mv643xx_eth_probe - * - * First function called after registering the network device. - * It's purpose is to initialize the device as an ethernet device, - * fill the ethernet device structure with pointers * to functions, - * and set the MAC address of the interface - * - * Input : struct device * - * Output : -ENOMEM if failed , 0 if success - */ -static int mv643xx_eth_probe(struct platform_device *pdev) +static void mv643xx_eth_set_rx_mode(struct net_device *dev) { - struct mv643xx_eth_platform_data *pd; - int port_num; - struct mv643xx_private *mp; - struct net_device *dev; - u8 *p; - struct resource *res; - int err; - struct ethtool_cmd cmd; - int duplex = DUPLEX_HALF; - int speed = 0; /* default to auto-negotiation */ - DECLARE_MAC_BUF(mac); + struct mv643xx_eth_private *mp = netdev_priv(dev); + u32 port_config; + struct dev_addr_list *addr; + int i; - pd = pdev->dev.platform_data; - if (pd == NULL) { - printk(KERN_ERR "No mv643xx_eth_platform_data\n"); - return -ENODEV; + port_config = rdl(mp, PORT_CONFIG(mp->port_num)); + if (dev->flags & IFF_PROMISC) + port_config |= UNICAST_PROMISCUOUS_MODE; + else + port_config &= ~UNICAST_PROMISCUOUS_MODE; + wrl(mp, PORT_CONFIG(mp->port_num), port_config); + + if (dev->flags & (IFF_PROMISC | IFF_ALLMULTI)) { + int port_num = mp->port_num; + u32 accept = 0x01010101; + + for (i = 0; i < 0x100; i += 4) { + wrl(mp, SPECIAL_MCAST_TABLE(port_num) + i, accept); + wrl(mp, OTHER_MCAST_TABLE(port_num) + i, accept); + } + return; } - if (pd->shared == NULL) { - printk(KERN_ERR "No mv643xx_eth_platform_data->shared\n"); - return -ENODEV; + for (i = 0; i < 0x100; i += 4) { + wrl(mp, SPECIAL_MCAST_TABLE(mp->port_num) + i, 0); + wrl(mp, OTHER_MCAST_TABLE(mp->port_num) + i, 0); } - dev = alloc_etherdev(sizeof(struct mv643xx_private)); - if (!dev) - return -ENOMEM; + for (addr = dev->mc_list; addr != NULL; addr = addr->next) { + u8 *a = addr->da_addr; + int table; - platform_set_drvdata(pdev, dev); + if (addr->da_addrlen != 6) + continue; - mp = netdev_priv(dev); - mp->dev = dev; -#ifdef MV643XX_NAPI - netif_napi_add(dev, &mp->napi, mv643xx_poll, 64); -#endif + if (memcmp(a, "\x01\x00\x5e\x00\x00", 5) == 0) { + table = SPECIAL_MCAST_TABLE(mp->port_num); + set_filter_table_entry(mp, table, a[5]); + } else { + int crc = addr_crc(a); - res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); - BUG_ON(!res); - dev->irq = res->start; + table = OTHER_MCAST_TABLE(mp->port_num); + set_filter_table_entry(mp, table, crc); + } + } +} - dev->open = mv643xx_eth_open; - dev->stop = mv643xx_eth_stop; - dev->hard_start_xmit = mv643xx_eth_start_xmit; - dev->set_mac_address = mv643xx_eth_set_mac_address; - dev->set_multicast_list = mv643xx_eth_set_rx_mode; - /* No need to Tx Timeout */ - dev->tx_timeout = mv643xx_eth_tx_timeout; +/* rx/tx queue initialisation ***********************************************/ +static int rxq_init(struct mv643xx_eth_private *mp, int index) +{ + struct rx_queue *rxq = mp->rxq + index; + struct rx_desc *rx_desc; + int size; + int i; -#ifdef CONFIG_NET_POLL_CONTROLLER - dev->poll_controller = mv643xx_netpoll; -#endif + rxq->index = index; - dev->watchdog_timeo = 2 * HZ; - dev->base_addr = 0; - dev->change_mtu = mv643xx_eth_change_mtu; - dev->do_ioctl = mv643xx_eth_do_ioctl; - SET_ETHTOOL_OPS(dev, &mv643xx_ethtool_ops); + rxq->rx_ring_size = mp->default_rx_ring_size; -#ifdef MV643XX_CHECKSUM_OFFLOAD_TX -#ifdef MAX_SKB_FRAGS - /* - * Zero copy can only work if we use Discovery II memory. Else, we will - * have to map the buffers to ISA memory which is only 16 MB - */ - dev->features = NETIF_F_SG | NETIF_F_IP_CSUM; -#endif -#endif + rxq->rx_desc_count = 0; + rxq->rx_curr_desc = 0; + rxq->rx_used_desc = 0; - /* Configure the timeout task */ - INIT_WORK(&mp->tx_timeout_task, mv643xx_eth_tx_timeout_task); + size = rxq->rx_ring_size * sizeof(struct rx_desc); - spin_lock_init(&mp->lock); + if (index == mp->rxq_primary && size <= mp->rx_desc_sram_size) { + rxq->rx_desc_area = ioremap(mp->rx_desc_sram_addr, + mp->rx_desc_sram_size); + rxq->rx_desc_dma = mp->rx_desc_sram_addr; + } else { + rxq->rx_desc_area = dma_alloc_coherent(NULL, size, + &rxq->rx_desc_dma, + GFP_KERNEL); + } - mp->shared = platform_get_drvdata(pd->shared); - port_num = mp->port_num = pd->port_number; + if (rxq->rx_desc_area == NULL) { + dev_printk(KERN_ERR, &mp->dev->dev, + "can't allocate rx ring (%d bytes)\n", size); + goto out; + } + memset(rxq->rx_desc_area, 0, size); - if (mp->shared->win_protect) - wrl(mp, WINDOW_PROTECT(port_num), mp->shared->win_protect); + rxq->rx_desc_area_size = size; + rxq->rx_skb = kmalloc(rxq->rx_ring_size * sizeof(*rxq->rx_skb), + GFP_KERNEL); + if (rxq->rx_skb == NULL) { + dev_printk(KERN_ERR, &mp->dev->dev, + "can't allocate rx skb ring\n"); + goto out_free; + } - mp->shared_smi = mp->shared; - if (pd->shared_smi != NULL) - mp->shared_smi = platform_get_drvdata(pd->shared_smi); + rx_desc = (struct rx_desc *)rxq->rx_desc_area; + for (i = 0; i < rxq->rx_ring_size; i++) { + int nexti = (i + 1) % rxq->rx_ring_size; + rx_desc[i].next_desc_ptr = rxq->rx_desc_dma + + nexti * sizeof(struct rx_desc); + } - /* set default config values */ - eth_port_uc_addr_get(mp, dev->dev_addr); - mp->rx_ring_size = PORT_DEFAULT_RECEIVE_QUEUE_SIZE; - mp->tx_ring_size = PORT_DEFAULT_TRANSMIT_QUEUE_SIZE; + init_timer(&rxq->rx_oom); + rxq->rx_oom.data = (unsigned long)rxq; + rxq->rx_oom.function = rxq_refill_timer_wrapper; - if (is_valid_ether_addr(pd->mac_addr)) - memcpy(dev->dev_addr, pd->mac_addr, 6); + return 0; - if (pd->phy_addr || pd->force_phy_addr) - ethernet_phy_set(mp, pd->phy_addr); - if (pd->rx_queue_size) - mp->rx_ring_size = pd->rx_queue_size; +out_free: + if (index == mp->rxq_primary && size <= mp->rx_desc_sram_size) + iounmap(rxq->rx_desc_area); + else + dma_free_coherent(NULL, size, + rxq->rx_desc_area, + rxq->rx_desc_dma); - if (pd->tx_queue_size) - mp->tx_ring_size = pd->tx_queue_size; +out: + return -ENOMEM; +} - if (pd->tx_sram_size) { - mp->tx_sram_size = pd->tx_sram_size; - mp->tx_sram_addr = pd->tx_sram_addr; - } +static void rxq_deinit(struct rx_queue *rxq) +{ + struct mv643xx_eth_private *mp = rxq_to_mp(rxq); + int i; - if (pd->rx_sram_size) { - mp->rx_sram_size = pd->rx_sram_size; - mp->rx_sram_addr = pd->rx_sram_addr; - } + rxq_disable(rxq); - duplex = pd->duplex; - speed = pd->speed; + del_timer_sync(&rxq->rx_oom); - /* Hook up MII support for ethtool */ - mp->mii.dev = dev; - mp->mii.mdio_read = mv643xx_mdio_read; - mp->mii.mdio_write = mv643xx_mdio_write; - mp->mii.phy_id = ethernet_phy_get(mp); - mp->mii.phy_id_mask = 0x3f; - mp->mii.reg_num_mask = 0x1f; + for (i = 0; i < rxq->rx_ring_size; i++) { + if (rxq->rx_skb[i]) { + dev_kfree_skb(rxq->rx_skb[i]); + rxq->rx_desc_count--; + } + } - err = ethernet_phy_detect(mp); - if (err) { - pr_debug("%s: No PHY detected at addr %d\n", - dev->name, ethernet_phy_get(mp)); - goto out; + if (rxq->rx_desc_count) { + dev_printk(KERN_ERR, &mp->dev->dev, + "error freeing rx ring -- %d skbs stuck\n", + rxq->rx_desc_count); } - ethernet_phy_reset(mp); - mp->mii.supports_gmii = mii_check_gmii_support(&mp->mii); - mv643xx_init_ethtool_cmd(dev, mp->mii.phy_id, speed, duplex, &cmd); - mv643xx_eth_update_pscr(dev, &cmd); - mv643xx_set_settings(dev, &cmd); + if (rxq->index == mp->rxq_primary && + rxq->rx_desc_area_size <= mp->rx_desc_sram_size) + iounmap(rxq->rx_desc_area); + else + dma_free_coherent(NULL, rxq->rx_desc_area_size, + rxq->rx_desc_area, rxq->rx_desc_dma); - SET_NETDEV_DEV(dev, &pdev->dev); - err = register_netdev(dev); - if (err) - goto out; + kfree(rxq->rx_skb); +} - p = dev->dev_addr; - printk(KERN_NOTICE - "%s: port %d with MAC address %s\n", - dev->name, port_num, print_mac(mac, p)); +static int txq_init(struct mv643xx_eth_private *mp, int index) +{ + struct tx_queue *txq = mp->txq + index; + struct tx_desc *tx_desc; + int size; + int i; - if (dev->features & NETIF_F_SG) - printk(KERN_NOTICE "%s: Scatter Gather Enabled\n", dev->name); + txq->index = index; - if (dev->features & NETIF_F_IP_CSUM) - printk(KERN_NOTICE "%s: TX TCP/IP Checksumming Supported\n", - dev->name); + txq->tx_ring_size = mp->default_tx_ring_size; -#ifdef MV643XX_CHECKSUM_OFFLOAD_TX - printk(KERN_NOTICE "%s: RX TCP/UDP Checksum Offload ON \n", dev->name); -#endif + txq->tx_desc_count = 0; + txq->tx_curr_desc = 0; + txq->tx_used_desc = 0; -#ifdef MV643XX_COAL - printk(KERN_NOTICE "%s: TX and RX Interrupt Coalescing ON \n", - dev->name); -#endif + size = txq->tx_ring_size * sizeof(struct tx_desc); -#ifdef MV643XX_NAPI - printk(KERN_NOTICE "%s: RX NAPI Enabled \n", dev->name); -#endif + if (index == mp->txq_primary && size <= mp->tx_desc_sram_size) { + txq->tx_desc_area = ioremap(mp->tx_desc_sram_addr, + mp->tx_desc_sram_size); + txq->tx_desc_dma = mp->tx_desc_sram_addr; + } else { + txq->tx_desc_area = dma_alloc_coherent(NULL, size, + &txq->tx_desc_dma, + GFP_KERNEL); + } + + if (txq->tx_desc_area == NULL) { + dev_printk(KERN_ERR, &mp->dev->dev, + "can't allocate tx ring (%d bytes)\n", size); + goto out; + } + memset(txq->tx_desc_area, 0, size); - if (mp->tx_sram_size > 0) - printk(KERN_NOTICE "%s: Using SRAM\n", dev->name); + txq->tx_desc_area_size = size; + txq->tx_skb = kmalloc(txq->tx_ring_size * sizeof(*txq->tx_skb), + GFP_KERNEL); + if (txq->tx_skb == NULL) { + dev_printk(KERN_ERR, &mp->dev->dev, + "can't allocate tx skb ring\n"); + goto out_free; + } + + tx_desc = (struct tx_desc *)txq->tx_desc_area; + for (i = 0; i < txq->tx_ring_size; i++) { + int nexti = (i + 1) % txq->tx_ring_size; + tx_desc[i].next_desc_ptr = txq->tx_desc_dma + + nexti * sizeof(struct tx_desc); + } return 0; -out: - free_netdev(dev); - return err; +out_free: + if (index == mp->txq_primary && size <= mp->tx_desc_sram_size) + iounmap(txq->tx_desc_area); + else + dma_free_coherent(NULL, size, + txq->tx_desc_area, + txq->tx_desc_dma); + +out: + return -ENOMEM; } -static int mv643xx_eth_remove(struct platform_device *pdev) +static void txq_reclaim(struct tx_queue *txq, int force) { - struct net_device *dev = platform_get_drvdata(pdev); + struct mv643xx_eth_private *mp = txq_to_mp(txq); + unsigned long flags; - unregister_netdev(dev); - flush_scheduled_work(); + spin_lock_irqsave(&mp->lock, flags); + while (txq->tx_desc_count > 0) { + int tx_index; + struct tx_desc *desc; + u32 cmd_sts; + struct sk_buff *skb; + dma_addr_t addr; + int count; + + tx_index = txq->tx_used_desc; + desc = &txq->tx_desc_area[tx_index]; + cmd_sts = desc->cmd_sts; - free_netdev(dev); - platform_set_drvdata(pdev, NULL); - return 0; -} + if (!force && (cmd_sts & BUFFER_OWNED_BY_DMA)) + break; -static void mv643xx_eth_conf_mbus_windows(struct mv643xx_shared_private *msp, - struct mbus_dram_target_info *dram) -{ - void __iomem *base = msp->eth_base; - u32 win_enable; - u32 win_protect; - int i; + txq->tx_used_desc = (tx_index + 1) % txq->tx_ring_size; + txq->tx_desc_count--; - for (i = 0; i < 6; i++) { - writel(0, base + WINDOW_BASE(i)); - writel(0, base + WINDOW_SIZE(i)); - if (i < 4) - writel(0, base + WINDOW_REMAP_HIGH(i)); - } + addr = desc->buf_ptr; + count = desc->byte_cnt; + skb = txq->tx_skb[tx_index]; + txq->tx_skb[tx_index] = NULL; - win_enable = 0x3f; - win_protect = 0; + if (cmd_sts & ERROR_SUMMARY) { + dev_printk(KERN_INFO, &mp->dev->dev, "tx error\n"); + mp->dev->stats.tx_errors++; + } - for (i = 0; i < dram->num_cs; i++) { - struct mbus_dram_window *cs = dram->cs + i; + /* + * Drop mp->lock while we free the skb. + */ + spin_unlock_irqrestore(&mp->lock, flags); - writel((cs->base & 0xffff0000) | - (cs->mbus_attr << 8) | - dram->mbus_dram_target_id, base + WINDOW_BASE(i)); - writel((cs->size - 1) & 0xffff0000, base + WINDOW_SIZE(i)); + if (cmd_sts & TX_FIRST_DESC) + dma_unmap_single(NULL, addr, count, DMA_TO_DEVICE); + else + dma_unmap_page(NULL, addr, count, DMA_TO_DEVICE); - win_enable &= ~(1 << i); - win_protect |= 3 << (2 * i); - } + if (skb) + dev_kfree_skb_irq(skb); - writel(win_enable, base + WINDOW_BAR_ENABLE); - msp->win_protect = win_protect; + spin_lock_irqsave(&mp->lock, flags); + } + spin_unlock_irqrestore(&mp->lock, flags); } -static int mv643xx_eth_shared_probe(struct platform_device *pdev) +static void txq_deinit(struct tx_queue *txq) { - static int mv643xx_version_printed = 0; - struct mv643xx_eth_shared_platform_data *pd = pdev->dev.platform_data; - struct mv643xx_shared_private *msp; - struct resource *res; - int ret; + struct mv643xx_eth_private *mp = txq_to_mp(txq); - if (!mv643xx_version_printed++) - printk(KERN_NOTICE "MV-643xx 10/100/1000 Ethernet Driver\n"); + txq_disable(txq); + txq_reclaim(txq, 1); - ret = -EINVAL; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (res == NULL) - goto out; + BUG_ON(txq->tx_used_desc != txq->tx_curr_desc); - ret = -ENOMEM; - msp = kmalloc(sizeof(*msp), GFP_KERNEL); - if (msp == NULL) - goto out; - memset(msp, 0, sizeof(*msp)); + if (txq->index == mp->txq_primary && + txq->tx_desc_area_size <= mp->tx_desc_sram_size) + iounmap(txq->tx_desc_area); + else + dma_free_coherent(NULL, txq->tx_desc_area_size, + txq->tx_desc_area, txq->tx_desc_dma); - msp->eth_base = ioremap(res->start, res->end - res->start + 1); - if (msp->eth_base == NULL) - goto out_free; + kfree(txq->tx_skb); +} - spin_lock_init(&msp->phy_lock); - msp->t_clk = (pd != NULL && pd->t_clk != 0) ? pd->t_clk : 133000000; - platform_set_drvdata(pdev, msp); +/* netdev ops and related ***************************************************/ +static void update_pscr(struct mv643xx_eth_private *mp, int speed, int duplex) +{ + u32 pscr_o; + u32 pscr_n; - /* - * (Re-)program MBUS remapping windows if we are asked to. - */ - if (pd != NULL && pd->dram != NULL) - mv643xx_eth_conf_mbus_windows(msp, pd->dram); + pscr_o = rdl(mp, PORT_SERIAL_CONTROL(mp->port_num)); - return 0; + /* clear speed, duplex and rx buffer size fields */ + pscr_n = pscr_o & ~(SET_MII_SPEED_TO_100 | + SET_GMII_SPEED_TO_1000 | + SET_FULL_DUPLEX_MODE | + MAX_RX_PACKET_MASK); -out_free: - kfree(msp); -out: - return ret; -} + if (speed == SPEED_1000) { + pscr_n |= SET_GMII_SPEED_TO_1000 | MAX_RX_PACKET_9700BYTE; + } else { + if (speed == SPEED_100) + pscr_n |= SET_MII_SPEED_TO_100; + pscr_n |= MAX_RX_PACKET_1522BYTE; + } -static int mv643xx_eth_shared_remove(struct platform_device *pdev) -{ - struct mv643xx_shared_private *msp = platform_get_drvdata(pdev); + if (duplex == DUPLEX_FULL) + pscr_n |= SET_FULL_DUPLEX_MODE; - iounmap(msp->eth_base); - kfree(msp); + if (pscr_n != pscr_o) { + if ((pscr_o & SERIAL_PORT_ENABLE) == 0) + wrl(mp, PORT_SERIAL_CONTROL(mp->port_num), pscr_n); + else { + int i; - return 0; + for (i = 0; i < 8; i++) + if (mp->txq_mask & (1 << i)) + txq_disable(mp->txq + i); + + pscr_o &= ~SERIAL_PORT_ENABLE; + wrl(mp, PORT_SERIAL_CONTROL(mp->port_num), pscr_o); + wrl(mp, PORT_SERIAL_CONTROL(mp->port_num), pscr_n); + wrl(mp, PORT_SERIAL_CONTROL(mp->port_num), pscr_n); + + for (i = 0; i < 8; i++) + if (mp->txq_mask & (1 << i)) + txq_enable(mp->txq + i); + } + } } -static void mv643xx_eth_shutdown(struct platform_device *pdev) +static irqreturn_t mv643xx_eth_irq(int irq, void *dev_id) { - struct net_device *dev = platform_get_drvdata(pdev); - struct mv643xx_private *mp = netdev_priv(dev); - unsigned int port_num = mp->port_num; + struct net_device *dev = (struct net_device *)dev_id; + struct mv643xx_eth_private *mp = netdev_priv(dev); + u32 int_cause; + u32 int_cause_ext; + u32 txq_active; + + int_cause = rdl(mp, INT_CAUSE(mp->port_num)) & + (INT_TX_END | INT_RX | INT_EXT); + if (int_cause == 0) + return IRQ_NONE; - /* Mask all interrupts on ethernet port */ - wrl(mp, INTERRUPT_MASK_REG(port_num), 0); - rdl(mp, INTERRUPT_MASK_REG(port_num)); + int_cause_ext = 0; + if (int_cause & INT_EXT) { + int_cause_ext = rdl(mp, INT_CAUSE_EXT(mp->port_num)) + & (INT_EXT_LINK | INT_EXT_PHY | INT_EXT_TX); + wrl(mp, INT_CAUSE_EXT(mp->port_num), ~int_cause_ext); + } - eth_port_reset(mp); -} + if (int_cause_ext & (INT_EXT_PHY | INT_EXT_LINK)) { + if (mp->phy_addr == -1 || mii_link_ok(&mp->mii)) { + int i; -static struct platform_driver mv643xx_eth_driver = { - .probe = mv643xx_eth_probe, - .remove = mv643xx_eth_remove, - .shutdown = mv643xx_eth_shutdown, - .driver = { - .name = MV643XX_ETH_NAME, - .owner = THIS_MODULE, - }, -}; + if (mp->phy_addr != -1) { + struct ethtool_cmd cmd; -static struct platform_driver mv643xx_eth_shared_driver = { - .probe = mv643xx_eth_shared_probe, - .remove = mv643xx_eth_shared_remove, - .driver = { - .name = MV643XX_ETH_SHARED_NAME, - .owner = THIS_MODULE, - }, -}; + mii_ethtool_gset(&mp->mii, &cmd); + update_pscr(mp, cmd.speed, cmd.duplex); + } -/* - * mv643xx_init_module - * - * Registers the network drivers into the Linux kernel - * - * Input : N/A - * - * Output : N/A - */ -static int __init mv643xx_init_module(void) -{ - int rc; + for (i = 0; i < 8; i++) + if (mp->txq_mask & (1 << i)) + txq_enable(mp->txq + i); - rc = platform_driver_register(&mv643xx_eth_shared_driver); - if (!rc) { - rc = platform_driver_register(&mv643xx_eth_driver); - if (rc) - platform_driver_unregister(&mv643xx_eth_shared_driver); + if (!netif_carrier_ok(dev)) { + netif_carrier_on(dev); + __txq_maybe_wake(mp->txq + mp->txq_primary); + } + } else if (netif_carrier_ok(dev)) { + netif_stop_queue(dev); + netif_carrier_off(dev); + } } - return rc; -} -/* - * mv643xx_cleanup_module - * - * Registers the network drivers into the Linux kernel - * - * Input : N/A - * - * Output : N/A - */ -static void __exit mv643xx_cleanup_module(void) -{ - platform_driver_unregister(&mv643xx_eth_driver); - platform_driver_unregister(&mv643xx_eth_shared_driver); -} + /* + * RxBuffer or RxError set for any of the 8 queues? + */ +#ifdef MV643XX_ETH_NAPI + if (int_cause & INT_RX) { + wrl(mp, INT_MASK(mp->port_num), 0x00000000); + rdl(mp, INT_MASK(mp->port_num)); -module_init(mv643xx_init_module); -module_exit(mv643xx_cleanup_module); + netif_rx_schedule(dev, &mp->napi); + } +#else + if (int_cause & INT_RX) { + int i; -MODULE_LICENSE("GPL"); -MODULE_AUTHOR( "Rabeeh Khoury, Assaf Hoffman, Matthew Dharm, Manish Lachwani" - " and Dale Farnsworth"); -MODULE_DESCRIPTION("Ethernet driver for Marvell MV643XX"); -MODULE_ALIAS("platform:" MV643XX_ETH_NAME); -MODULE_ALIAS("platform:" MV643XX_ETH_SHARED_NAME); + for (i = 7; i >= 0; i--) + if (mp->rxq_mask & (1 << i)) + rxq_process(mp->rxq + i, INT_MAX); + } +#endif -/* - * The second part is the low level driver of the gigE ethernet ports. - */ + txq_active = rdl(mp, TXQ_COMMAND(mp->port_num)); -/* - * Marvell's Gigabit Ethernet controller low level driver - * - * DESCRIPTION: - * This file introduce low level API to Marvell's Gigabit Ethernet - * controller. This Gigabit Ethernet Controller driver API controls - * 1) Operations (i.e. port init, start, reset etc'). - * 2) Data flow (i.e. port send, receive etc'). - * Each Gigabit Ethernet port is controlled via - * struct mv643xx_private. - * This struct includes user configuration information as well as - * driver internal data needed for its operations. - * - * Supported Features: - * - This low level driver is OS independent. Allocating memory for - * the descriptor rings and buffers are not within the scope of - * this driver. - * - The user is free from Rx/Tx queue managing. - * - This low level driver introduce functionality API that enable - * the to operate Marvell's Gigabit Ethernet Controller in a - * convenient way. - * - Simple Gigabit Ethernet port operation API. - * - Simple Gigabit Ethernet port data flow API. - * - Data flow and operation API support per queue functionality. - * - Support cached descriptors for better performance. - * - Enable access to all four DRAM banks and internal SRAM memory - * spaces. - * - PHY access and control API. - * - Port control register configuration API. - * - Full control over Unicast and Multicast MAC configurations. - * - * Operation flow: - * - * Initialization phase - * This phase complete the initialization of the the - * mv643xx_private struct. - * User information regarding port configuration has to be set - * prior to calling the port initialization routine. - * - * In this phase any port Tx/Rx activity is halted, MIB counters - * are cleared, PHY address is set according to user parameter and - * access to DRAM and internal SRAM memory spaces. - * - * Driver ring initialization - * Allocating memory for the descriptor rings and buffers is not - * within the scope of this driver. Thus, the user is required to - * allocate memory for the descriptors ring and buffers. Those - * memory parameters are used by the Rx and Tx ring initialization - * routines in order to curve the descriptor linked list in a form - * of a ring. - * Note: Pay special attention to alignment issues when using - * cached descriptors/buffers. In this phase the driver store - * information in the mv643xx_private struct regarding each queue - * ring. - * - * Driver start - * This phase prepares the Ethernet port for Rx and Tx activity. - * It uses the information stored in the mv643xx_private struct to - * initialize the various port registers. - * - * Data flow: - * All packet references to/from the driver are done using - * struct pkt_info. - * This struct is a unified struct used with Rx and Tx operations. - * This way the user is not required to be familiar with neither - * Tx nor Rx descriptors structures. - * The driver's descriptors rings are management by indexes. - * Those indexes controls the ring resources and used to indicate - * a SW resource error: - * 'current' - * This index points to the current available resource for use. For - * example in Rx process this index will point to the descriptor - * that will be passed to the user upon calling the receive - * routine. In Tx process, this index will point to the descriptor - * that will be assigned with the user packet info and transmitted. - * 'used' - * This index points to the descriptor that need to restore its - * resources. For example in Rx process, using the Rx buffer return - * API will attach the buffer returned in packet info to the - * descriptor pointed by 'used'. In Tx process, using the Tx - * descriptor return will merely return the user packet info with - * the command status of the transmitted buffer pointed by the - * 'used' index. Nevertheless, it is essential to use this routine - * to update the 'used' index. - * 'first' - * This index supports Tx Scatter-Gather. It points to the first - * descriptor of a packet assembled of multiple buffers. For - * example when in middle of Such packet we have a Tx resource - * error the 'curr' index get the value of 'first' to indicate - * that the ring returned to its state before trying to transmit - * this packet. - * - * Receive operation: - * The eth_port_receive API set the packet information struct, - * passed by the caller, with received information from the - * 'current' SDMA descriptor. - * It is the user responsibility to return this resource back - * to the Rx descriptor ring to enable the reuse of this source. - * Return Rx resource is done using the eth_rx_return_buff API. - * - * Prior to calling the initialization routine eth_port_init() the user - * must set the following fields under mv643xx_private struct: - * port_num User Ethernet port number. - * port_config User port configuration value. - * port_config_extend User port config extend value. - * port_sdma_config User port SDMA config value. - * port_serial_control User port serial control value. - * - * This driver data flow is done using the struct pkt_info which - * is a unified struct for Rx and Tx operations: - * - * byte_cnt Tx/Rx descriptor buffer byte count. - * l4i_chk CPU provided TCP Checksum. For Tx operation - * only. - * cmd_sts Tx/Rx descriptor command status. - * buf_ptr Tx/Rx descriptor buffer pointer. - * return_info Tx/Rx user resource return information. - */ + /* + * TxBuffer or TxError set for any of the 8 queues? + */ + if (int_cause_ext & INT_EXT_TX) { + int i; -/* Ethernet Port routines */ -static void eth_port_set_filter_table_entry(struct mv643xx_private *mp, - int table, unsigned char entry); + for (i = 0; i < 8; i++) + if (mp->txq_mask & (1 << i)) + txq_reclaim(mp->txq + i, 0); + } -/* - * eth_port_init - Initialize the Ethernet port driver - * - * DESCRIPTION: - * This function prepares the ethernet port to start its activity: - * 1) Completes the ethernet port driver struct initialization toward port - * start routine. - * 2) Resets the device to a quiescent state in case of warm reboot. - * 3) Enable SDMA access to all four DRAM banks as well as internal SRAM. - * 4) Clean MAC tables. The reset status of those tables is unknown. - * 5) Set PHY address. - * Note: Call this routine prior to eth_port_start routine and after - * setting user values in the user fields of Ethernet port control - * struct. - * - * INPUT: - * struct mv643xx_private *mp Ethernet port control struct - * - * OUTPUT: - * See description. - * - * RETURN: - * None. - */ -static void eth_port_init(struct mv643xx_private *mp) -{ - mp->rx_resource_err = 0; + /* + * Any TxEnd interrupts? + */ + if (int_cause & INT_TX_END) { + int i; + + wrl(mp, INT_CAUSE(mp->port_num), ~(int_cause & INT_TX_END)); + for (i = 0; i < 8; i++) { + struct tx_queue *txq = mp->txq + i; + if (txq->tx_desc_count && !((txq_active >> i) & 1)) + txq_enable(txq); + } + } - eth_port_reset(mp); + /* + * Enough space again in the primary TX queue for a full packet? + */ + if (int_cause_ext & INT_EXT_TX) { + struct tx_queue *txq = mp->txq + mp->txq_primary; + __txq_maybe_wake(txq); + } - eth_port_init_mac_tables(mp); + return IRQ_HANDLED; } -/* - * eth_port_start - Start the Ethernet port activity. - * - * DESCRIPTION: - * This routine prepares the Ethernet port for Rx and Tx activity: - * 1. Initialize Tx and Rx Current Descriptor Pointer for each queue that - * has been initialized a descriptor's ring (using - * ether_init_tx_desc_ring for Tx and ether_init_rx_desc_ring for Rx) - * 2. Initialize and enable the Ethernet configuration port by writing to - * the port's configuration and command registers. - * 3. Initialize and enable the SDMA by writing to the SDMA's - * configuration and command registers. After completing these steps, - * the ethernet port SDMA can starts to perform Rx and Tx activities. - * - * Note: Each Rx and Tx queue descriptor's list must be initialized prior - * to calling this function (use ether_init_tx_desc_ring for Tx queues - * and ether_init_rx_desc_ring for Rx queues). - * - * INPUT: - * dev - a pointer to the required interface - * - * OUTPUT: - * Ethernet port is ready to receive and transmit. - * - * RETURN: - * None. - */ -static void eth_port_start(struct net_device *dev) +static void phy_reset(struct mv643xx_eth_private *mp) { - struct mv643xx_private *mp = netdev_priv(dev); - unsigned int port_num = mp->port_num; - int tx_curr_desc, rx_curr_desc; - u32 pscr; - struct ethtool_cmd ethtool_cmd; - - /* Assignment of Tx CTRP of given queue */ - tx_curr_desc = mp->tx_curr_desc_q; - wrl(mp, TX_CURRENT_QUEUE_DESC_PTR_0(port_num), - (u32)((struct eth_tx_desc *)mp->tx_desc_dma + tx_curr_desc)); - - /* Assignment of Rx CRDP of given queue */ - rx_curr_desc = mp->rx_curr_desc_q; - wrl(mp, RX_CURRENT_QUEUE_DESC_PTR_0(port_num), - (u32)((struct eth_rx_desc *)mp->rx_desc_dma + rx_curr_desc)); + unsigned int data; - /* Add the assigned Ethernet address to the port's address table */ - eth_port_uc_addr_set(mp, dev->dev_addr); + smi_reg_read(mp, mp->phy_addr, 0, &data); + data |= 0x8000; + smi_reg_write(mp, mp->phy_addr, 0, data); - /* Assign port configuration and command. */ - wrl(mp, PORT_CONFIG_REG(port_num), - PORT_CONFIG_DEFAULT_VALUE); - - wrl(mp, PORT_CONFIG_EXTEND_REG(port_num), - PORT_CONFIG_EXTEND_DEFAULT_VALUE); + do { + udelay(1); + smi_reg_read(mp, mp->phy_addr, 0, &data); + } while (data & 0x8000); +} - pscr = rdl(mp, PORT_SERIAL_CONTROL_REG(port_num)); +static void port_start(struct mv643xx_eth_private *mp) +{ + u32 pscr; + int i; + /* + * Configure basic link parameters. + */ + pscr = rdl(mp, PORT_SERIAL_CONTROL(mp->port_num)); pscr &= ~(SERIAL_PORT_ENABLE | FORCE_LINK_PASS); - wrl(mp, PORT_SERIAL_CONTROL_REG(port_num), pscr); - + wrl(mp, PORT_SERIAL_CONTROL(mp->port_num), pscr); pscr |= DISABLE_AUTO_NEG_FOR_FLOW_CTRL | DISABLE_AUTO_NEG_SPEED_GMII | - DISABLE_AUTO_NEG_FOR_DUPLX | - DO_NOT_FORCE_LINK_FAIL | + DISABLE_AUTO_NEG_FOR_DUPLEX | + DO_NOT_FORCE_LINK_FAIL | SERIAL_PORT_CONTROL_RESERVED; + wrl(mp, PORT_SERIAL_CONTROL(mp->port_num), pscr); + pscr |= SERIAL_PORT_ENABLE; + wrl(mp, PORT_SERIAL_CONTROL(mp->port_num), pscr); - wrl(mp, PORT_SERIAL_CONTROL_REG(port_num), pscr); + wrl(mp, SDMA_CONFIG(mp->port_num), PORT_SDMA_CONFIG_DEFAULT_VALUE); - pscr |= SERIAL_PORT_ENABLE; - wrl(mp, PORT_SERIAL_CONTROL_REG(port_num), pscr); + /* + * Perform PHY reset, if there is a PHY. + */ + if (mp->phy_addr != -1) { + struct ethtool_cmd cmd; - /* Assign port SDMA configuration */ - wrl(mp, SDMA_CONFIG_REG(port_num), - PORT_SDMA_CONFIG_DEFAULT_VALUE); + mv643xx_eth_get_settings(mp->dev, &cmd); + phy_reset(mp); + mv643xx_eth_set_settings(mp->dev, &cmd); + } - /* Enable port Rx. */ - mv643xx_eth_port_enable_rx(mp, ETH_RX_QUEUES_ENABLED); + /* + * Configure TX path and queues. + */ + tx_set_rate(mp, 1000000000, 16777216); + for (i = 0; i < 8; i++) { + struct tx_queue *txq = mp->txq + i; + int off = TXQ_CURRENT_DESC_PTR(mp->port_num, i); + u32 addr; - /* Disable port bandwidth limits by clearing MTU register */ - wrl(mp, MAXIMUM_TRANSMIT_UNIT(port_num), 0); + if ((mp->txq_mask & (1 << i)) == 0) + continue; - /* save phy settings across reset */ - mv643xx_get_settings(dev, ðtool_cmd); - ethernet_phy_reset(mp); - mv643xx_set_settings(dev, ðtool_cmd); -} + addr = (u32)txq->tx_desc_dma; + addr += txq->tx_curr_desc * sizeof(struct tx_desc); + wrl(mp, off, addr); -/* - * eth_port_uc_addr_set - Write a MAC address into the port's hw registers - */ -static void eth_port_uc_addr_set(struct mv643xx_private *mp, - unsigned char *p_addr) -{ - unsigned int port_num = mp->port_num; - unsigned int mac_h; - unsigned int mac_l; - int table; + txq_set_rate(txq, 1000000000, 16777216); + txq_set_fixed_prio_mode(txq); + } - mac_l = (p_addr[4] << 8) | (p_addr[5]); - mac_h = (p_addr[0] << 24) | (p_addr[1] << 16) | (p_addr[2] << 8) | - (p_addr[3] << 0); + /* + * Add configured unicast address to address filter table. + */ + uc_addr_set(mp, mp->dev->dev_addr); - wrl(mp, MAC_ADDR_LOW(port_num), mac_l); - wrl(mp, MAC_ADDR_HIGH(port_num), mac_h); + /* + * Receive all unmatched unicast, TCP, UDP, BPDU and broadcast + * frames to RX queue #0. + */ + wrl(mp, PORT_CONFIG(mp->port_num), 0x00000000); - /* Accept frames with this address */ - table = DA_FILTER_UNICAST_TABLE_BASE(port_num); - eth_port_set_filter_table_entry(mp, table, p_addr[5] & 0x0f); -} + /* + * Treat BPDUs as normal multicasts, and disable partition mode. + */ + wrl(mp, PORT_CONFIG_EXT(mp->port_num), 0x00000000); -/* - * eth_port_uc_addr_get - Read the MAC address from the port's hw registers - */ -static void eth_port_uc_addr_get(struct mv643xx_private *mp, - unsigned char *p_addr) -{ - unsigned int port_num = mp->port_num; - unsigned int mac_h; - unsigned int mac_l; + /* + * Enable the receive queues. + */ + for (i = 0; i < 8; i++) { + struct rx_queue *rxq = mp->rxq + i; + int off = RXQ_CURRENT_DESC_PTR(mp->port_num, i); + u32 addr; + + if ((mp->rxq_mask & (1 << i)) == 0) + continue; - mac_h = rdl(mp, MAC_ADDR_HIGH(port_num)); - mac_l = rdl(mp, MAC_ADDR_LOW(port_num)); + addr = (u32)rxq->rx_desc_dma; + addr += rxq->rx_curr_desc * sizeof(struct rx_desc); + wrl(mp, off, addr); - p_addr[0] = (mac_h >> 24) & 0xff; - p_addr[1] = (mac_h >> 16) & 0xff; - p_addr[2] = (mac_h >> 8) & 0xff; - p_addr[3] = mac_h & 0xff; - p_addr[4] = (mac_l >> 8) & 0xff; - p_addr[5] = mac_l & 0xff; + rxq_enable(rxq); + } } -/* - * The entries in each table are indexed by a hash of a packet's MAC - * address. One bit in each entry determines whether the packet is - * accepted. There are 4 entries (each 8 bits wide) in each register - * of the table. The bits in each entry are defined as follows: - * 0 Accept=1, Drop=0 - * 3-1 Queue (ETH_Q0=0) - * 7-4 Reserved = 0; - */ -static void eth_port_set_filter_table_entry(struct mv643xx_private *mp, - int table, unsigned char entry) +static void set_rx_coal(struct mv643xx_eth_private *mp, unsigned int delay) { - unsigned int table_reg; - unsigned int tbl_offset; - unsigned int reg_offset; + unsigned int coal = ((mp->shared->t_clk / 1000000) * delay) / 64; + u32 val; + + val = rdl(mp, SDMA_CONFIG(mp->port_num)); + if (mp->shared->extended_rx_coal_limit) { + if (coal > 0xffff) + coal = 0xffff; + val &= ~0x023fff80; + val |= (coal & 0x8000) << 10; + val |= (coal & 0x7fff) << 7; + } else { + if (coal > 0x3fff) + coal = 0x3fff; + val &= ~0x003fff00; + val |= (coal & 0x3fff) << 8; + } + wrl(mp, SDMA_CONFIG(mp->port_num), val); +} - tbl_offset = (entry / 4) * 4; /* Register offset of DA table entry */ - reg_offset = entry % 4; /* Entry offset within the register */ +static void set_tx_coal(struct mv643xx_eth_private *mp, unsigned int delay) +{ + unsigned int coal = ((mp->shared->t_clk / 1000000) * delay) / 64; - /* Set "accepts frame bit" at specified table entry */ - table_reg = rdl(mp, table + tbl_offset); - table_reg |= 0x01 << (8 * reg_offset); - wrl(mp, table + tbl_offset, table_reg); + if (coal > 0x3fff) + coal = 0x3fff; + wrl(mp, TX_FIFO_URGENT_THRESHOLD(mp->port_num), (coal & 0x3fff) << 4); } -/* - * eth_port_mc_addr - Multicast address settings. - * - * The MV device supports multicast using two tables: - * 1) Special Multicast Table for MAC addresses of the form - * 0x01-00-5E-00-00-XX (where XX is between 0x00 and 0x_FF). - * The MAC DA[7:0] bits are used as a pointer to the Special Multicast - * Table entries in the DA-Filter table. - * 2) Other Multicast Table for multicast of another type. A CRC-8bit - * is used as an index to the Other Multicast Table entries in the - * DA-Filter table. This function calculates the CRC-8bit value. - * In either case, eth_port_set_filter_table_entry() is then called - * to set to set the actual table entry. - */ -static void eth_port_mc_addr(struct mv643xx_private *mp, unsigned char *p_addr) +static int mv643xx_eth_open(struct net_device *dev) { - unsigned int port_num = mp->port_num; - unsigned int mac_h; - unsigned int mac_l; - unsigned char crc_result = 0; - int table; - int mac_array[48]; - int crc[8]; + struct mv643xx_eth_private *mp = netdev_priv(dev); + int err; int i; - if ((p_addr[0] == 0x01) && (p_addr[1] == 0x00) && - (p_addr[2] == 0x5E) && (p_addr[3] == 0x00) && (p_addr[4] == 0x00)) { - table = DA_FILTER_SPECIAL_MULTICAST_TABLE_BASE(port_num); - eth_port_set_filter_table_entry(mp, table, p_addr[5]); - return; + wrl(mp, INT_CAUSE(mp->port_num), 0); + wrl(mp, INT_CAUSE_EXT(mp->port_num), 0); + rdl(mp, INT_CAUSE_EXT(mp->port_num)); + + err = request_irq(dev->irq, mv643xx_eth_irq, + IRQF_SHARED | IRQF_SAMPLE_RANDOM, + dev->name, dev); + if (err) { + dev_printk(KERN_ERR, &dev->dev, "can't assign irq\n"); + return -EAGAIN; } - /* Calculate CRC-8 out of the given address */ - mac_h = (p_addr[0] << 8) | (p_addr[1]); - mac_l = (p_addr[2] << 24) | (p_addr[3] << 16) | - (p_addr[4] << 8) | (p_addr[5] << 0); - - for (i = 0; i < 32; i++) - mac_array[i] = (mac_l >> i) & 0x1; - for (i = 32; i < 48; i++) - mac_array[i] = (mac_h >> (i - 32)) & 0x1; - - crc[0] = mac_array[45] ^ mac_array[43] ^ mac_array[40] ^ mac_array[39] ^ - mac_array[35] ^ mac_array[34] ^ mac_array[31] ^ mac_array[30] ^ - mac_array[28] ^ mac_array[23] ^ mac_array[21] ^ mac_array[19] ^ - mac_array[18] ^ mac_array[16] ^ mac_array[14] ^ mac_array[12] ^ - mac_array[8] ^ mac_array[7] ^ mac_array[6] ^ mac_array[0]; - - crc[1] = mac_array[46] ^ mac_array[45] ^ mac_array[44] ^ mac_array[43] ^ - mac_array[41] ^ mac_array[39] ^ mac_array[36] ^ mac_array[34] ^ - mac_array[32] ^ mac_array[30] ^ mac_array[29] ^ mac_array[28] ^ - mac_array[24] ^ mac_array[23] ^ mac_array[22] ^ mac_array[21] ^ - mac_array[20] ^ mac_array[18] ^ mac_array[17] ^ mac_array[16] ^ - mac_array[15] ^ mac_array[14] ^ mac_array[13] ^ mac_array[12] ^ - mac_array[9] ^ mac_array[6] ^ mac_array[1] ^ mac_array[0]; - - crc[2] = mac_array[47] ^ mac_array[46] ^ mac_array[44] ^ mac_array[43] ^ - mac_array[42] ^ mac_array[39] ^ mac_array[37] ^ mac_array[34] ^ - mac_array[33] ^ mac_array[29] ^ mac_array[28] ^ mac_array[25] ^ - mac_array[24] ^ mac_array[22] ^ mac_array[17] ^ mac_array[15] ^ - mac_array[13] ^ mac_array[12] ^ mac_array[10] ^ mac_array[8] ^ - mac_array[6] ^ mac_array[2] ^ mac_array[1] ^ mac_array[0]; - - crc[3] = mac_array[47] ^ mac_array[45] ^ mac_array[44] ^ mac_array[43] ^ - mac_array[40] ^ mac_array[38] ^ mac_array[35] ^ mac_array[34] ^ - mac_array[30] ^ mac_array[29] ^ mac_array[26] ^ mac_array[25] ^ - mac_array[23] ^ mac_array[18] ^ mac_array[16] ^ mac_array[14] ^ - mac_array[13] ^ mac_array[11] ^ mac_array[9] ^ mac_array[7] ^ - mac_array[3] ^ mac_array[2] ^ mac_array[1]; - - crc[4] = mac_array[46] ^ mac_array[45] ^ mac_array[44] ^ mac_array[41] ^ - mac_array[39] ^ mac_array[36] ^ mac_array[35] ^ mac_array[31] ^ - mac_array[30] ^ mac_array[27] ^ mac_array[26] ^ mac_array[24] ^ - mac_array[19] ^ mac_array[17] ^ mac_array[15] ^ mac_array[14] ^ - mac_array[12] ^ mac_array[10] ^ mac_array[8] ^ mac_array[4] ^ - mac_array[3] ^ mac_array[2]; - - crc[5] = mac_array[47] ^ mac_array[46] ^ mac_array[45] ^ mac_array[42] ^ - mac_array[40] ^ mac_array[37] ^ mac_array[36] ^ mac_array[32] ^ - mac_array[31] ^ mac_array[28] ^ mac_array[27] ^ mac_array[25] ^ - mac_array[20] ^ mac_array[18] ^ mac_array[16] ^ mac_array[15] ^ - mac_array[13] ^ mac_array[11] ^ mac_array[9] ^ mac_array[5] ^ - mac_array[4] ^ mac_array[3]; - - crc[6] = mac_array[47] ^ mac_array[46] ^ mac_array[43] ^ mac_array[41] ^ - mac_array[38] ^ mac_array[37] ^ mac_array[33] ^ mac_array[32] ^ - mac_array[29] ^ mac_array[28] ^ mac_array[26] ^ mac_array[21] ^ - mac_array[19] ^ mac_array[17] ^ mac_array[16] ^ mac_array[14] ^ - mac_array[12] ^ mac_array[10] ^ mac_array[6] ^ mac_array[5] ^ - mac_array[4]; - - crc[7] = mac_array[47] ^ mac_array[44] ^ mac_array[42] ^ mac_array[39] ^ - mac_array[38] ^ mac_array[34] ^ mac_array[33] ^ mac_array[30] ^ - mac_array[29] ^ mac_array[27] ^ mac_array[22] ^ mac_array[20] ^ - mac_array[18] ^ mac_array[17] ^ mac_array[15] ^ mac_array[13] ^ - mac_array[11] ^ mac_array[7] ^ mac_array[6] ^ mac_array[5]; + init_mac_tables(mp); - for (i = 0; i < 8; i++) - crc_result = crc_result | (crc[i] << i); + for (i = 0; i < 8; i++) { + if ((mp->rxq_mask & (1 << i)) == 0) + continue; - table = DA_FILTER_OTHER_MULTICAST_TABLE_BASE(port_num); - eth_port_set_filter_table_entry(mp, table, crc_result); -} + err = rxq_init(mp, i); + if (err) { + while (--i >= 0) + if (mp->rxq_mask & (1 << i)) + rxq_deinit(mp->rxq + i); + goto out; + } -/* - * Set the entire multicast list based on dev->mc_list. - */ -static void eth_port_set_multicast_list(struct net_device *dev) -{ + rxq_refill(mp->rxq + i); + } - struct dev_mc_list *mc_list; - int i; - int table_index; - struct mv643xx_private *mp = netdev_priv(dev); - unsigned int eth_port_num = mp->port_num; + for (i = 0; i < 8; i++) { + if ((mp->txq_mask & (1 << i)) == 0) + continue; - /* If the device is in promiscuous mode or in all multicast mode, - * we will fully populate both multicast tables with accept. - * This is guaranteed to yield a match on all multicast addresses... - */ - if ((dev->flags & IFF_PROMISC) || (dev->flags & IFF_ALLMULTI)) { - for (table_index = 0; table_index <= 0xFC; table_index += 4) { - /* Set all entries in DA filter special multicast - * table (Ex_dFSMT) - * Set for ETH_Q0 for now - * Bits - * 0 Accept=1, Drop=0 - * 3-1 Queue ETH_Q0=0 - * 7-4 Reserved = 0; - */ - wrl(mp, DA_FILTER_SPECIAL_MULTICAST_TABLE_BASE(eth_port_num) + table_index, 0x01010101); - - /* Set all entries in DA filter other multicast - * table (Ex_dFOMT) - * Set for ETH_Q0 for now - * Bits - * 0 Accept=1, Drop=0 - * 3-1 Queue ETH_Q0=0 - * 7-4 Reserved = 0; - */ - wrl(mp, DA_FILTER_OTHER_MULTICAST_TABLE_BASE(eth_port_num) + table_index, 0x01010101); + err = txq_init(mp, i); + if (err) { + while (--i >= 0) + if (mp->txq_mask & (1 << i)) + txq_deinit(mp->txq + i); + goto out_free; } - return; } - /* We will clear out multicast tables every time we get the list. - * Then add the entire new list... - */ - for (table_index = 0; table_index <= 0xFC; table_index += 4) { - /* Clear DA filter special multicast table (Ex_dFSMT) */ - wrl(mp, DA_FILTER_SPECIAL_MULTICAST_TABLE_BASE - (eth_port_num) + table_index, 0); - - /* Clear DA filter other multicast table (Ex_dFOMT) */ - wrl(mp, DA_FILTER_OTHER_MULTICAST_TABLE_BASE - (eth_port_num) + table_index, 0); - } +#ifdef MV643XX_ETH_NAPI + napi_enable(&mp->napi); +#endif + + port_start(mp); - /* Get pointer to net_device multicast list and add each one... */ - for (i = 0, mc_list = dev->mc_list; - (i < 256) && (mc_list != NULL) && (i < dev->mc_count); - i++, mc_list = mc_list->next) - if (mc_list->dmi_addrlen == 6) - eth_port_mc_addr(mp, mc_list->dmi_addr); + set_rx_coal(mp, 0); + set_tx_coal(mp, 0); + + wrl(mp, INT_MASK_EXT(mp->port_num), + INT_EXT_LINK | INT_EXT_PHY | INT_EXT_TX); + + wrl(mp, INT_MASK(mp->port_num), INT_TX_END | INT_RX | INT_EXT); + + return 0; + + +out_free: + for (i = 0; i < 8; i++) + if (mp->rxq_mask & (1 << i)) + rxq_deinit(mp->rxq + i); +out: + free_irq(dev->irq, dev); + + return err; } -/* - * eth_port_init_mac_tables - Clear all entrance in the UC, SMC and OMC tables - * - * DESCRIPTION: - * Go through all the DA filter tables (Unicast, Special Multicast & - * Other Multicast) and set each entry to 0. - * - * INPUT: - * struct mv643xx_private *mp Ethernet Port. - * - * OUTPUT: - * Multicast and Unicast packets are rejected. - * - * RETURN: - * None. - */ -static void eth_port_init_mac_tables(struct mv643xx_private *mp) -{ - unsigned int port_num = mp->port_num; - int table_index; - - /* Clear DA filter unicast table (Ex_dFUT) */ - for (table_index = 0; table_index <= 0xC; table_index += 4) - wrl(mp, DA_FILTER_UNICAST_TABLE_BASE(port_num) + - table_index, 0); - - for (table_index = 0; table_index <= 0xFC; table_index += 4) { - /* Clear DA filter special multicast table (Ex_dFSMT) */ - wrl(mp, DA_FILTER_SPECIAL_MULTICAST_TABLE_BASE(port_num) + - table_index, 0); - /* Clear DA filter other multicast table (Ex_dFOMT) */ - wrl(mp, DA_FILTER_OTHER_MULTICAST_TABLE_BASE(port_num) + - table_index, 0); +static void port_reset(struct mv643xx_eth_private *mp) +{ + unsigned int data; + int i; + + for (i = 0; i < 8; i++) { + if (mp->rxq_mask & (1 << i)) + rxq_disable(mp->rxq + i); + if (mp->txq_mask & (1 << i)) + txq_disable(mp->txq + i); } + while (!(rdl(mp, PORT_STATUS(mp->port_num)) & TX_FIFO_EMPTY)) + udelay(10); + + /* Reset the Enable bit in the Configuration Register */ + data = rdl(mp, PORT_SERIAL_CONTROL(mp->port_num)); + data &= ~(SERIAL_PORT_ENABLE | + DO_NOT_FORCE_LINK_FAIL | + FORCE_LINK_PASS); + wrl(mp, PORT_SERIAL_CONTROL(mp->port_num), data); } -/* - * eth_clear_mib_counters - Clear all MIB counters - * - * DESCRIPTION: - * This function clears all MIB counters of a specific ethernet port. - * A read from the MIB counter will reset the counter. - * - * INPUT: - * struct mv643xx_private *mp Ethernet Port. - * - * OUTPUT: - * After reading all MIB counters, the counters resets. - * - * RETURN: - * MIB counter value. - * - */ -static void eth_clear_mib_counters(struct mv643xx_private *mp) +static int mv643xx_eth_stop(struct net_device *dev) { - unsigned int port_num = mp->port_num; + struct mv643xx_eth_private *mp = netdev_priv(dev); int i; - /* Perform dummy reads from MIB counters */ - for (i = ETH_MIB_GOOD_OCTETS_RECEIVED_LOW; i < ETH_MIB_LATE_COLLISION; - i += 4) - rdl(mp, MIB_COUNTERS_BASE(port_num) + i); + wrl(mp, INT_MASK(mp->port_num), 0x00000000); + rdl(mp, INT_MASK(mp->port_num)); + +#ifdef MV643XX_ETH_NAPI + napi_disable(&mp->napi); +#endif + netif_carrier_off(dev); + netif_stop_queue(dev); + + free_irq(dev->irq, dev); + + port_reset(mp); + mib_counters_update(mp); + + for (i = 0; i < 8; i++) { + if (mp->rxq_mask & (1 << i)) + rxq_deinit(mp->rxq + i); + if (mp->txq_mask & (1 << i)) + txq_deinit(mp->txq + i); + } + + return 0; } -static inline u32 read_mib(struct mv643xx_private *mp, int offset) +static int mv643xx_eth_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) { - return rdl(mp, MIB_COUNTERS_BASE(mp->port_num) + offset); + struct mv643xx_eth_private *mp = netdev_priv(dev); + + if (mp->phy_addr != -1) + return generic_mii_ioctl(&mp->mii, if_mii(ifr), cmd, NULL); + + return -EOPNOTSUPP; } -static void eth_update_mib_counters(struct mv643xx_private *mp) +static int mv643xx_eth_change_mtu(struct net_device *dev, int new_mtu) { - struct mv643xx_mib_counters *p = &mp->mib_counters; - int offset; + struct mv643xx_eth_private *mp = netdev_priv(dev); - p->good_octets_received += - read_mib(mp, ETH_MIB_GOOD_OCTETS_RECEIVED_LOW); - p->good_octets_received += - (u64)read_mib(mp, ETH_MIB_GOOD_OCTETS_RECEIVED_HIGH) << 32; + if (new_mtu < 64 || new_mtu > 9500) + return -EINVAL; - for (offset = ETH_MIB_BAD_OCTETS_RECEIVED; - offset <= ETH_MIB_FRAMES_1024_TO_MAX_OCTETS; - offset += 4) - *(u32 *)((char *)p + offset) += read_mib(mp, offset); + dev->mtu = new_mtu; + tx_set_rate(mp, 1000000000, 16777216); - p->good_octets_sent += read_mib(mp, ETH_MIB_GOOD_OCTETS_SENT_LOW); - p->good_octets_sent += - (u64)read_mib(mp, ETH_MIB_GOOD_OCTETS_SENT_HIGH) << 32; + if (!netif_running(dev)) + return 0; - for (offset = ETH_MIB_GOOD_FRAMES_SENT; - offset <= ETH_MIB_LATE_COLLISION; - offset += 4) - *(u32 *)((char *)p + offset) += read_mib(mp, offset); + /* + * Stop and then re-open the interface. This will allocate RX + * skbs of the new MTU. + * There is a possible danger that the open will not succeed, + * due to memory being full. + */ + mv643xx_eth_stop(dev); + if (mv643xx_eth_open(dev)) { + dev_printk(KERN_ERR, &dev->dev, + "fatal error on re-opening device after " + "MTU change\n"); + } + + return 0; } -/* - * ethernet_phy_detect - Detect whether a phy is present - * - * DESCRIPTION: - * This function tests whether there is a PHY present on - * the specified port. - * - * INPUT: - * struct mv643xx_private *mp Ethernet Port. - * - * OUTPUT: - * None - * - * RETURN: - * 0 on success - * -ENODEV on failure - * - */ -static int ethernet_phy_detect(struct mv643xx_private *mp) +static void tx_timeout_task(struct work_struct *ugly) { - unsigned int phy_reg_data0; - int auto_neg; + struct mv643xx_eth_private *mp; - eth_port_read_smi_reg(mp, 0, &phy_reg_data0); - auto_neg = phy_reg_data0 & 0x1000; - phy_reg_data0 ^= 0x1000; /* invert auto_neg */ - eth_port_write_smi_reg(mp, 0, phy_reg_data0); + mp = container_of(ugly, struct mv643xx_eth_private, tx_timeout_task); + if (netif_running(mp->dev)) { + netif_stop_queue(mp->dev); - eth_port_read_smi_reg(mp, 0, &phy_reg_data0); - if ((phy_reg_data0 & 0x1000) == auto_neg) - return -ENODEV; /* change didn't take */ + port_reset(mp); + port_start(mp); - phy_reg_data0 ^= 0x1000; - eth_port_write_smi_reg(mp, 0, phy_reg_data0); - return 0; + __txq_maybe_wake(mp->txq + mp->txq_primary); + } } -/* - * ethernet_phy_get - Get the ethernet port PHY address. - * - * DESCRIPTION: - * This routine returns the given ethernet port PHY address. - * - * INPUT: - * struct mv643xx_private *mp Ethernet Port. - * - * OUTPUT: - * None. - * - * RETURN: - * PHY address. - * - */ -static int ethernet_phy_get(struct mv643xx_private *mp) +static void mv643xx_eth_tx_timeout(struct net_device *dev) { - unsigned int reg_data; + struct mv643xx_eth_private *mp = netdev_priv(dev); - reg_data = rdl(mp, PHY_ADDR_REG); + dev_printk(KERN_INFO, &dev->dev, "tx timeout\n"); - return ((reg_data >> (5 * mp->port_num)) & 0x1f); + schedule_work(&mp->tx_timeout_task); } -/* - * ethernet_phy_set - Set the ethernet port PHY address. - * - * DESCRIPTION: - * This routine sets the given ethernet port PHY address. - * - * INPUT: - * struct mv643xx_private *mp Ethernet Port. - * int phy_addr PHY address. - * - * OUTPUT: - * None. - * - * RETURN: - * None. - * - */ -static void ethernet_phy_set(struct mv643xx_private *mp, int phy_addr) +#ifdef CONFIG_NET_POLL_CONTROLLER +static void mv643xx_eth_netpoll(struct net_device *dev) { - u32 reg_data; - int addr_shift = 5 * mp->port_num; + struct mv643xx_eth_private *mp = netdev_priv(dev); + + wrl(mp, INT_MASK(mp->port_num), 0x00000000); + rdl(mp, INT_MASK(mp->port_num)); + + mv643xx_eth_irq(dev->irq, dev); - reg_data = rdl(mp, PHY_ADDR_REG); - reg_data &= ~(0x1f << addr_shift); - reg_data |= (phy_addr & 0x1f) << addr_shift; - wrl(mp, PHY_ADDR_REG, reg_data); + wrl(mp, INT_MASK(mp->port_num), INT_TX_END | INT_RX | INT_CAUSE_EXT); } +#endif -/* - * ethernet_phy_reset - Reset Ethernet port PHY. - * - * DESCRIPTION: - * This routine utilizes the SMI interface to reset the ethernet port PHY. - * - * INPUT: - * struct mv643xx_private *mp Ethernet Port. - * - * OUTPUT: - * The PHY is reset. - * - * RETURN: - * None. - * - */ -static void ethernet_phy_reset(struct mv643xx_private *mp) +static int mv643xx_eth_mdio_read(struct net_device *dev, int addr, int reg) { - unsigned int phy_reg_data; + struct mv643xx_eth_private *mp = netdev_priv(dev); + int val; - /* Reset the PHY */ - eth_port_read_smi_reg(mp, 0, &phy_reg_data); - phy_reg_data |= 0x8000; /* Set bit 15 to reset the PHY */ - eth_port_write_smi_reg(mp, 0, phy_reg_data); + smi_reg_read(mp, addr, reg, &val); - /* wait for PHY to come out of reset */ - do { - udelay(1); - eth_port_read_smi_reg(mp, 0, &phy_reg_data); - } while (phy_reg_data & 0x8000); + return val; } -static void mv643xx_eth_port_enable_tx(struct mv643xx_private *mp, - unsigned int queues) +static void mv643xx_eth_mdio_write(struct net_device *dev, int addr, int reg, int val) { - wrl(mp, TRANSMIT_QUEUE_COMMAND_REG(mp->port_num), queues); + struct mv643xx_eth_private *mp = netdev_priv(dev); + smi_reg_write(mp, addr, reg, val); } -static void mv643xx_eth_port_enable_rx(struct mv643xx_private *mp, - unsigned int queues) -{ - wrl(mp, RECEIVE_QUEUE_COMMAND_REG(mp->port_num), queues); -} -static unsigned int mv643xx_eth_port_disable_tx(struct mv643xx_private *mp) +/* platform glue ************************************************************/ +static void +mv643xx_eth_conf_mbus_windows(struct mv643xx_eth_shared_private *msp, + struct mbus_dram_target_info *dram) { - unsigned int port_num = mp->port_num; - u32 queues; + void __iomem *base = msp->base; + u32 win_enable; + u32 win_protect; + int i; - /* Stop Tx port activity. Check port Tx activity. */ - queues = rdl(mp, TRANSMIT_QUEUE_COMMAND_REG(port_num)) & 0xFF; - if (queues) { - /* Issue stop command for active queues only */ - wrl(mp, TRANSMIT_QUEUE_COMMAND_REG(port_num), (queues << 8)); + for (i = 0; i < 6; i++) { + writel(0, base + WINDOW_BASE(i)); + writel(0, base + WINDOW_SIZE(i)); + if (i < 4) + writel(0, base + WINDOW_REMAP_HIGH(i)); + } - /* Wait for all Tx activity to terminate. */ - /* Check port cause register that all Tx queues are stopped */ - while (rdl(mp, TRANSMIT_QUEUE_COMMAND_REG(port_num)) & 0xFF) - udelay(PHY_WAIT_MICRO_SECONDS); + win_enable = 0x3f; + win_protect = 0; - /* Wait for Tx FIFO to empty */ - while (rdl(mp, PORT_STATUS_REG(port_num)) & - ETH_PORT_TX_FIFO_EMPTY) - udelay(PHY_WAIT_MICRO_SECONDS); + for (i = 0; i < dram->num_cs; i++) { + struct mbus_dram_window *cs = dram->cs + i; + + writel((cs->base & 0xffff0000) | + (cs->mbus_attr << 8) | + dram->mbus_dram_target_id, base + WINDOW_BASE(i)); + writel((cs->size - 1) & 0xffff0000, base + WINDOW_SIZE(i)); + + win_enable &= ~(1 << i); + win_protect |= 3 << (2 * i); } - return queues; + writel(win_enable, base + WINDOW_BAR_ENABLE); + msp->win_protect = win_protect; } -static unsigned int mv643xx_eth_port_disable_rx(struct mv643xx_private *mp) +static void infer_hw_params(struct mv643xx_eth_shared_private *msp) { - unsigned int port_num = mp->port_num; - u32 queues; - - /* Stop Rx port activity. Check port Rx activity. */ - queues = rdl(mp, RECEIVE_QUEUE_COMMAND_REG(port_num)) & 0xFF; - if (queues) { - /* Issue stop command for active queues only */ - wrl(mp, RECEIVE_QUEUE_COMMAND_REG(port_num), (queues << 8)); - - /* Wait for all Rx activity to terminate. */ - /* Check port cause register that all Rx queues are stopped */ - while (rdl(mp, RECEIVE_QUEUE_COMMAND_REG(port_num)) & 0xFF) - udelay(PHY_WAIT_MICRO_SECONDS); - } + /* + * Check whether we have a 14-bit coal limit field in bits + * [21:8], or a 16-bit coal limit in bits [25,21:7] of the + * SDMA config register. + */ + writel(0x02000000, msp->base + SDMA_CONFIG(0)); + if (readl(msp->base + SDMA_CONFIG(0)) & 0x02000000) + msp->extended_rx_coal_limit = 1; + else + msp->extended_rx_coal_limit = 0; - return queues; + /* + * Check whether the TX rate control registers are in the + * old or the new place. + */ + writel(1, msp->base + TX_BW_MTU_MOVED(0)); + if (readl(msp->base + TX_BW_MTU_MOVED(0)) & 1) + msp->tx_bw_control_moved = 1; + else + msp->tx_bw_control_moved = 0; } -/* - * eth_port_reset - Reset Ethernet port - * - * DESCRIPTION: - * This routine resets the chip by aborting any SDMA engine activity and - * clearing the MIB counters. The Receiver and the Transmit unit are in - * idle state after this command is performed and the port is disabled. - * - * INPUT: - * struct mv643xx_private *mp Ethernet Port. - * - * OUTPUT: - * Channel activity is halted. - * - * RETURN: - * None. - * - */ -static void eth_port_reset(struct mv643xx_private *mp) +static int mv643xx_eth_shared_probe(struct platform_device *pdev) { - unsigned int port_num = mp->port_num; - unsigned int reg_data; + static int mv643xx_eth_version_printed = 0; + struct mv643xx_eth_shared_platform_data *pd = pdev->dev.platform_data; + struct mv643xx_eth_shared_private *msp; + struct resource *res; + int ret; - mv643xx_eth_port_disable_tx(mp); - mv643xx_eth_port_disable_rx(mp); + if (!mv643xx_eth_version_printed++) + printk(KERN_NOTICE "MV-643xx 10/100/1000 Ethernet Driver\n"); - /* Clear all MIB counters */ - eth_clear_mib_counters(mp); + ret = -EINVAL; + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (res == NULL) + goto out; - /* Reset the Enable bit in the Configuration Register */ - reg_data = rdl(mp, PORT_SERIAL_CONTROL_REG(port_num)); - reg_data &= ~(SERIAL_PORT_ENABLE | - DO_NOT_FORCE_LINK_FAIL | - FORCE_LINK_PASS); - wrl(mp, PORT_SERIAL_CONTROL_REG(port_num), reg_data); -} + ret = -ENOMEM; + msp = kmalloc(sizeof(*msp), GFP_KERNEL); + if (msp == NULL) + goto out; + memset(msp, 0, sizeof(*msp)); + msp->base = ioremap(res->start, res->end - res->start + 1); + if (msp->base == NULL) + goto out_free; -/* - * eth_port_read_smi_reg - Read PHY registers - * - * DESCRIPTION: - * This routine utilize the SMI interface to interact with the PHY in - * order to perform PHY register read. - * - * INPUT: - * struct mv643xx_private *mp Ethernet Port. - * unsigned int phy_reg PHY register address offset. - * unsigned int *value Register value buffer. - * - * OUTPUT: - * Write the value of a specified PHY register into given buffer. - * - * RETURN: - * false if the PHY is busy or read data is not in valid state. - * true otherwise. - * - */ -static void eth_port_read_smi_reg(struct mv643xx_private *mp, - unsigned int phy_reg, unsigned int *value) -{ - void __iomem *smi_reg = mp->shared_smi->eth_base + SMI_REG; - int phy_addr = ethernet_phy_get(mp); - unsigned long flags; - int i; + spin_lock_init(&msp->phy_lock); - /* the SMI register is a shared resource */ - spin_lock_irqsave(&mp->shared_smi->phy_lock, flags); + /* + * (Re-)program MBUS remapping windows if we are asked to. + */ + if (pd != NULL && pd->dram != NULL) + mv643xx_eth_conf_mbus_windows(msp, pd->dram); - /* wait for the SMI register to become available */ - for (i = 0; readl(smi_reg) & ETH_SMI_BUSY; i++) { - if (i == PHY_WAIT_ITERATIONS) { - printk("%s: PHY busy timeout\n", mp->dev->name); - goto out; - } - udelay(PHY_WAIT_MICRO_SECONDS); - } + /* + * Detect hardware parameters. + */ + msp->t_clk = (pd != NULL && pd->t_clk != 0) ? pd->t_clk : 133000000; + infer_hw_params(msp); - writel((phy_addr << 16) | (phy_reg << 21) | ETH_SMI_OPCODE_READ, - smi_reg); + platform_set_drvdata(pdev, msp); - /* now wait for the data to be valid */ - for (i = 0; !(readl(smi_reg) & ETH_SMI_READ_VALID); i++) { - if (i == PHY_WAIT_ITERATIONS) { - printk("%s: PHY read timeout\n", mp->dev->name); - goto out; - } - udelay(PHY_WAIT_MICRO_SECONDS); - } + return 0; - *value = readl(smi_reg) & 0xffff; +out_free: + kfree(msp); out: - spin_unlock_irqrestore(&mp->shared_smi->phy_lock, flags); + return ret; } -/* - * eth_port_write_smi_reg - Write to PHY registers - * - * DESCRIPTION: - * This routine utilize the SMI interface to interact with the PHY in - * order to perform writes to PHY registers. - * - * INPUT: - * struct mv643xx_private *mp Ethernet Port. - * unsigned int phy_reg PHY register address offset. - * unsigned int value Register value. - * - * OUTPUT: - * Write the given value to the specified PHY register. - * - * RETURN: - * false if the PHY is busy. - * true otherwise. - * - */ -static void eth_port_write_smi_reg(struct mv643xx_private *mp, - unsigned int phy_reg, unsigned int value) +static int mv643xx_eth_shared_remove(struct platform_device *pdev) { - void __iomem *smi_reg = mp->shared_smi->eth_base + SMI_REG; - int phy_addr = ethernet_phy_get(mp); - unsigned long flags; - int i; - - /* the SMI register is a shared resource */ - spin_lock_irqsave(&mp->shared_smi->phy_lock, flags); + struct mv643xx_eth_shared_private *msp = platform_get_drvdata(pdev); - /* wait for the SMI register to become available */ - for (i = 0; readl(smi_reg) & ETH_SMI_BUSY; i++) { - if (i == PHY_WAIT_ITERATIONS) { - printk("%s: PHY busy timeout\n", mp->dev->name); - goto out; - } - udelay(PHY_WAIT_MICRO_SECONDS); - } + iounmap(msp->base); + kfree(msp); - writel((phy_addr << 16) | (phy_reg << 21) | - ETH_SMI_OPCODE_WRITE | (value & 0xffff), smi_reg); -out: - spin_unlock_irqrestore(&mp->shared_smi->phy_lock, flags); + return 0; } -/* - * Wrappers for MII support library. - */ -static int mv643xx_mdio_read(struct net_device *dev, int phy_id, int location) +static struct platform_driver mv643xx_eth_shared_driver = { + .probe = mv643xx_eth_shared_probe, + .remove = mv643xx_eth_shared_remove, + .driver = { + .name = MV643XX_ETH_SHARED_NAME, + .owner = THIS_MODULE, + }, +}; + +static void phy_addr_set(struct mv643xx_eth_private *mp, int phy_addr) { - struct mv643xx_private *mp = netdev_priv(dev); - int val; + int addr_shift = 5 * mp->port_num; + u32 data; - eth_port_read_smi_reg(mp, location, &val); - return val; + data = rdl(mp, PHY_ADDR); + data &= ~(0x1f << addr_shift); + data |= (phy_addr & 0x1f) << addr_shift; + wrl(mp, PHY_ADDR, data); } -static void mv643xx_mdio_write(struct net_device *dev, int phy_id, int location, int val) +static int phy_addr_get(struct mv643xx_eth_private *mp) { - struct mv643xx_private *mp = netdev_priv(dev); - eth_port_write_smi_reg(mp, location, val); + unsigned int data; + + data = rdl(mp, PHY_ADDR); + + return (data >> (5 * mp->port_num)) & 0x1f; } -/* - * eth_port_receive - Get received information from Rx ring. - * - * DESCRIPTION: - * This routine returns the received data to the caller. There is no - * data copying during routine operation. All information is returned - * using pointer to packet information struct passed from the caller. - * If the routine exhausts Rx ring resources then the resource error flag - * is set. - * - * INPUT: - * struct mv643xx_private *mp Ethernet Port Control srtuct. - * struct pkt_info *p_pkt_info User packet buffer. - * - * OUTPUT: - * Rx ring current and used indexes are updated. - * - * RETURN: - * ETH_ERROR in case the routine can not access Rx desc ring. - * ETH_QUEUE_FULL if Rx ring resources are exhausted. - * ETH_END_OF_JOB if there is no received data. - * ETH_OK otherwise. - */ -static ETH_FUNC_RET_STATUS eth_port_receive(struct mv643xx_private *mp, - struct pkt_info *p_pkt_info) +static void set_params(struct mv643xx_eth_private *mp, + struct mv643xx_eth_platform_data *pd) { - int rx_next_curr_desc, rx_curr_desc, rx_used_desc; - volatile struct eth_rx_desc *p_rx_desc; - unsigned int command_status; - unsigned long flags; + struct net_device *dev = mp->dev; - /* Do not process Rx ring in case of Rx ring resource error */ - if (mp->rx_resource_err) - return ETH_QUEUE_FULL; + if (is_valid_ether_addr(pd->mac_addr)) + memcpy(dev->dev_addr, pd->mac_addr, 6); + else + uc_addr_get(mp, dev->dev_addr); - spin_lock_irqsave(&mp->lock, flags); + if (pd->phy_addr == -1) { + mp->shared_smi = NULL; + mp->phy_addr = -1; + } else { + mp->shared_smi = mp->shared; + if (pd->shared_smi != NULL) + mp->shared_smi = platform_get_drvdata(pd->shared_smi); - /* Get the Rx Desc ring 'curr and 'used' indexes */ - rx_curr_desc = mp->rx_curr_desc_q; - rx_used_desc = mp->rx_used_desc_q; + if (pd->force_phy_addr || pd->phy_addr) { + mp->phy_addr = pd->phy_addr & 0x3f; + phy_addr_set(mp, mp->phy_addr); + } else { + mp->phy_addr = phy_addr_get(mp); + } + } - p_rx_desc = &mp->p_rx_desc_area[rx_curr_desc]; + mp->default_rx_ring_size = DEFAULT_RX_QUEUE_SIZE; + if (pd->rx_queue_size) + mp->default_rx_ring_size = pd->rx_queue_size; + mp->rx_desc_sram_addr = pd->rx_sram_addr; + mp->rx_desc_sram_size = pd->rx_sram_size; - /* The following parameters are used to save readings from memory */ - command_status = p_rx_desc->cmd_sts; - rmb(); + if (pd->rx_queue_mask) + mp->rxq_mask = pd->rx_queue_mask; + else + mp->rxq_mask = 0x01; + mp->rxq_primary = fls(mp->rxq_mask) - 1; - /* Nothing to receive... */ - if (command_status & (ETH_BUFFER_OWNED_BY_DMA)) { - spin_unlock_irqrestore(&mp->lock, flags); - return ETH_END_OF_JOB; - } + mp->default_tx_ring_size = DEFAULT_TX_QUEUE_SIZE; + if (pd->tx_queue_size) + mp->default_tx_ring_size = pd->tx_queue_size; + mp->tx_desc_sram_addr = pd->tx_sram_addr; + mp->tx_desc_sram_size = pd->tx_sram_size; - p_pkt_info->byte_cnt = (p_rx_desc->byte_cnt) - RX_BUF_OFFSET; - p_pkt_info->cmd_sts = command_status; - p_pkt_info->buf_ptr = (p_rx_desc->buf_ptr) + RX_BUF_OFFSET; - p_pkt_info->return_info = mp->rx_skb[rx_curr_desc]; - p_pkt_info->l4i_chk = p_rx_desc->buf_size; + if (pd->tx_queue_mask) + mp->txq_mask = pd->tx_queue_mask; + else + mp->txq_mask = 0x01; + mp->txq_primary = fls(mp->txq_mask) - 1; +} - /* - * Clean the return info field to indicate that the - * packet has been moved to the upper layers - */ - mp->rx_skb[rx_curr_desc] = NULL; +static int phy_detect(struct mv643xx_eth_private *mp) +{ + unsigned int data; + unsigned int data2; - /* Update current index in data structure */ - rx_next_curr_desc = (rx_curr_desc + 1) % mp->rx_ring_size; - mp->rx_curr_desc_q = rx_next_curr_desc; + smi_reg_read(mp, mp->phy_addr, 0, &data); + smi_reg_write(mp, mp->phy_addr, 0, data ^ 0x1000); - /* Rx descriptors exhausted. Set the Rx ring resource error flag */ - if (rx_next_curr_desc == rx_used_desc) - mp->rx_resource_err = 1; + smi_reg_read(mp, mp->phy_addr, 0, &data2); + if (((data ^ data2) & 0x1000) == 0) + return -ENODEV; - spin_unlock_irqrestore(&mp->lock, flags); + smi_reg_write(mp, mp->phy_addr, 0, data); - return ETH_OK; + return 0; } -/* - * eth_rx_return_buff - Returns a Rx buffer back to the Rx ring. - * - * DESCRIPTION: - * This routine returns a Rx buffer back to the Rx ring. It retrieves the - * next 'used' descriptor and attached the returned buffer to it. - * In case the Rx ring was in "resource error" condition, where there are - * no available Rx resources, the function resets the resource error flag. - * - * INPUT: - * struct mv643xx_private *mp Ethernet Port Control srtuct. - * struct pkt_info *p_pkt_info Information on returned buffer. - * - * OUTPUT: - * New available Rx resource in Rx descriptor ring. - * - * RETURN: - * ETH_ERROR in case the routine can not access Rx desc ring. - * ETH_OK otherwise. - */ -static ETH_FUNC_RET_STATUS eth_rx_return_buff(struct mv643xx_private *mp, - struct pkt_info *p_pkt_info) +static int phy_init(struct mv643xx_eth_private *mp, + struct mv643xx_eth_platform_data *pd) { - int used_rx_desc; /* Where to return Rx resource */ - volatile struct eth_rx_desc *p_used_rx_desc; - unsigned long flags; + struct ethtool_cmd cmd; + int err; - spin_lock_irqsave(&mp->lock, flags); + err = phy_detect(mp); + if (err) { + dev_printk(KERN_INFO, &mp->dev->dev, + "no PHY detected at addr %d\n", mp->phy_addr); + return err; + } + phy_reset(mp); - /* Get 'used' Rx descriptor */ - used_rx_desc = mp->rx_used_desc_q; - p_used_rx_desc = &mp->p_rx_desc_area[used_rx_desc]; + mp->mii.phy_id = mp->phy_addr; + mp->mii.phy_id_mask = 0x3f; + mp->mii.reg_num_mask = 0x1f; + mp->mii.dev = mp->dev; + mp->mii.mdio_read = mv643xx_eth_mdio_read; + mp->mii.mdio_write = mv643xx_eth_mdio_write; - p_used_rx_desc->buf_ptr = p_pkt_info->buf_ptr; - p_used_rx_desc->buf_size = p_pkt_info->byte_cnt; - mp->rx_skb[used_rx_desc] = p_pkt_info->return_info; + mp->mii.supports_gmii = mii_check_gmii_support(&mp->mii); - /* Flush the write pipe */ + memset(&cmd, 0, sizeof(cmd)); + + cmd.port = PORT_MII; + cmd.transceiver = XCVR_INTERNAL; + cmd.phy_address = mp->phy_addr; + if (pd->speed == 0) { + cmd.autoneg = AUTONEG_ENABLE; + cmd.speed = SPEED_100; + cmd.advertising = ADVERTISED_10baseT_Half | + ADVERTISED_10baseT_Full | + ADVERTISED_100baseT_Half | + ADVERTISED_100baseT_Full; + if (mp->mii.supports_gmii) + cmd.advertising |= ADVERTISED_1000baseT_Full; + } else { + cmd.autoneg = AUTONEG_DISABLE; + cmd.speed = pd->speed; + cmd.duplex = pd->duplex; + } - /* Return the descriptor to DMA ownership */ - wmb(); - p_used_rx_desc->cmd_sts = - ETH_BUFFER_OWNED_BY_DMA | ETH_RX_ENABLE_INTERRUPT; - wmb(); + update_pscr(mp, cmd.speed, cmd.duplex); + mv643xx_eth_set_settings(mp->dev, &cmd); - /* Move the used descriptor pointer to the next descriptor */ - mp->rx_used_desc_q = (used_rx_desc + 1) % mp->rx_ring_size; + return 0; +} - /* Any Rx return cancels the Rx resource error status */ - mp->rx_resource_err = 0; +static int mv643xx_eth_probe(struct platform_device *pdev) +{ + struct mv643xx_eth_platform_data *pd; + struct mv643xx_eth_private *mp; + struct net_device *dev; + struct resource *res; + DECLARE_MAC_BUF(mac); + int err; - spin_unlock_irqrestore(&mp->lock, flags); + pd = pdev->dev.platform_data; + if (pd == NULL) { + dev_printk(KERN_ERR, &pdev->dev, + "no mv643xx_eth_platform_data\n"); + return -ENODEV; + } - return ETH_OK; -} + if (pd->shared == NULL) { + dev_printk(KERN_ERR, &pdev->dev, + "no mv643xx_eth_platform_data->shared\n"); + return -ENODEV; + } -/************* Begin ethtool support *************************/ + dev = alloc_etherdev(sizeof(struct mv643xx_eth_private)); + if (!dev) + return -ENOMEM; -struct mv643xx_stats { - char stat_string[ETH_GSTRING_LEN]; - int sizeof_stat; - int stat_offset; -}; + mp = netdev_priv(dev); + platform_set_drvdata(pdev, mp); -#define MV643XX_STAT(m) FIELD_SIZEOF(struct mv643xx_private, m), \ - offsetof(struct mv643xx_private, m) - -static const struct mv643xx_stats mv643xx_gstrings_stats[] = { - { "rx_packets", MV643XX_STAT(stats.rx_packets) }, - { "tx_packets", MV643XX_STAT(stats.tx_packets) }, - { "rx_bytes", MV643XX_STAT(stats.rx_bytes) }, - { "tx_bytes", MV643XX_STAT(stats.tx_bytes) }, - { "rx_errors", MV643XX_STAT(stats.rx_errors) }, - { "tx_errors", MV643XX_STAT(stats.tx_errors) }, - { "rx_dropped", MV643XX_STAT(stats.rx_dropped) }, - { "tx_dropped", MV643XX_STAT(stats.tx_dropped) }, - { "good_octets_received", MV643XX_STAT(mib_counters.good_octets_received) }, - { "bad_octets_received", MV643XX_STAT(mib_counters.bad_octets_received) }, - { "internal_mac_transmit_err", MV643XX_STAT(mib_counters.internal_mac_transmit_err) }, - { "good_frames_received", MV643XX_STAT(mib_counters.good_frames_received) }, - { "bad_frames_received", MV643XX_STAT(mib_counters.bad_frames_received) }, - { "broadcast_frames_received", MV643XX_STAT(mib_counters.broadcast_frames_received) }, - { "multicast_frames_received", MV643XX_STAT(mib_counters.multicast_frames_received) }, - { "frames_64_octets", MV643XX_STAT(mib_counters.frames_64_octets) }, - { "frames_65_to_127_octets", MV643XX_STAT(mib_counters.frames_65_to_127_octets) }, - { "frames_128_to_255_octets", MV643XX_STAT(mib_counters.frames_128_to_255_octets) }, - { "frames_256_to_511_octets", MV643XX_STAT(mib_counters.frames_256_to_511_octets) }, - { "frames_512_to_1023_octets", MV643XX_STAT(mib_counters.frames_512_to_1023_octets) }, - { "frames_1024_to_max_octets", MV643XX_STAT(mib_counters.frames_1024_to_max_octets) }, - { "good_octets_sent", MV643XX_STAT(mib_counters.good_octets_sent) }, - { "good_frames_sent", MV643XX_STAT(mib_counters.good_frames_sent) }, - { "excessive_collision", MV643XX_STAT(mib_counters.excessive_collision) }, - { "multicast_frames_sent", MV643XX_STAT(mib_counters.multicast_frames_sent) }, - { "broadcast_frames_sent", MV643XX_STAT(mib_counters.broadcast_frames_sent) }, - { "unrec_mac_control_received", MV643XX_STAT(mib_counters.unrec_mac_control_received) }, - { "fc_sent", MV643XX_STAT(mib_counters.fc_sent) }, - { "good_fc_received", MV643XX_STAT(mib_counters.good_fc_received) }, - { "bad_fc_received", MV643XX_STAT(mib_counters.bad_fc_received) }, - { "undersize_received", MV643XX_STAT(mib_counters.undersize_received) }, - { "fragments_received", MV643XX_STAT(mib_counters.fragments_received) }, - { "oversize_received", MV643XX_STAT(mib_counters.oversize_received) }, - { "jabber_received", MV643XX_STAT(mib_counters.jabber_received) }, - { "mac_receive_error", MV643XX_STAT(mib_counters.mac_receive_error) }, - { "bad_crc_event", MV643XX_STAT(mib_counters.bad_crc_event) }, - { "collision", MV643XX_STAT(mib_counters.collision) }, - { "late_collision", MV643XX_STAT(mib_counters.late_collision) }, -}; + mp->shared = platform_get_drvdata(pd->shared); + mp->port_num = pd->port_number; -#define MV643XX_STATS_LEN ARRAY_SIZE(mv643xx_gstrings_stats) + mp->dev = dev; +#ifdef MV643XX_ETH_NAPI + netif_napi_add(dev, &mp->napi, mv643xx_eth_poll, 64); +#endif -static void mv643xx_get_drvinfo(struct net_device *netdev, - struct ethtool_drvinfo *drvinfo) -{ - strncpy(drvinfo->driver, mv643xx_driver_name, 32); - strncpy(drvinfo->version, mv643xx_driver_version, 32); - strncpy(drvinfo->fw_version, "N/A", 32); - strncpy(drvinfo->bus_info, "mv643xx", 32); - drvinfo->n_stats = MV643XX_STATS_LEN; -} + set_params(mp, pd); -static int mv643xx_get_sset_count(struct net_device *netdev, int sset) -{ - switch (sset) { - case ETH_SS_STATS: - return MV643XX_STATS_LEN; - default: - return -EOPNOTSUPP; - } -} + spin_lock_init(&mp->lock); -static void mv643xx_get_ethtool_stats(struct net_device *netdev, - struct ethtool_stats *stats, uint64_t *data) -{ - struct mv643xx_private *mp = netdev->priv; - int i; + mib_counters_clear(mp); + INIT_WORK(&mp->tx_timeout_task, tx_timeout_task); - eth_update_mib_counters(mp); + if (mp->phy_addr != -1) { + err = phy_init(mp, pd); + if (err) + goto out; - for (i = 0; i < MV643XX_STATS_LEN; i++) { - char *p = (char *)mp+mv643xx_gstrings_stats[i].stat_offset; - data[i] = (mv643xx_gstrings_stats[i].sizeof_stat == - sizeof(uint64_t)) ? *(uint64_t *)p : *(uint32_t *)p; + SET_ETHTOOL_OPS(dev, &mv643xx_eth_ethtool_ops); + } else { + SET_ETHTOOL_OPS(dev, &mv643xx_eth_ethtool_ops_phyless); } -} -static void mv643xx_get_strings(struct net_device *netdev, uint32_t stringset, - uint8_t *data) -{ - int i; - switch(stringset) { - case ETH_SS_STATS: - for (i=0; i < MV643XX_STATS_LEN; i++) { - memcpy(data + i * ETH_GSTRING_LEN, - mv643xx_gstrings_stats[i].stat_string, - ETH_GSTRING_LEN); - } - break; - } + res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); + BUG_ON(!res); + dev->irq = res->start; + + dev->hard_start_xmit = mv643xx_eth_xmit; + dev->open = mv643xx_eth_open; + dev->stop = mv643xx_eth_stop; + dev->set_multicast_list = mv643xx_eth_set_rx_mode; + dev->set_mac_address = mv643xx_eth_set_mac_address; + dev->do_ioctl = mv643xx_eth_ioctl; + dev->change_mtu = mv643xx_eth_change_mtu; + dev->tx_timeout = mv643xx_eth_tx_timeout; +#ifdef CONFIG_NET_POLL_CONTROLLER + dev->poll_controller = mv643xx_eth_netpoll; +#endif + dev->watchdog_timeo = 2 * HZ; + dev->base_addr = 0; + +#ifdef MV643XX_ETH_CHECKSUM_OFFLOAD_TX + /* + * Zero copy can only work if we use Discovery II memory. Else, we will + * have to map the buffers to ISA memory which is only 16 MB + */ + dev->features = NETIF_F_SG | NETIF_F_IP_CSUM; +#endif + + SET_NETDEV_DEV(dev, &pdev->dev); + + if (mp->shared->win_protect) + wrl(mp, WINDOW_PROTECT(mp->port_num), mp->shared->win_protect); + + err = register_netdev(dev); + if (err) + goto out; + + dev_printk(KERN_NOTICE, &dev->dev, "port %d with MAC address %s\n", + mp->port_num, print_mac(mac, dev->dev_addr)); + + if (dev->features & NETIF_F_SG) + dev_printk(KERN_NOTICE, &dev->dev, "scatter/gather enabled\n"); + + if (dev->features & NETIF_F_IP_CSUM) + dev_printk(KERN_NOTICE, &dev->dev, "tx checksum offload\n"); + +#ifdef MV643XX_ETH_NAPI + dev_printk(KERN_NOTICE, &dev->dev, "napi enabled\n"); +#endif + + if (mp->tx_desc_sram_size > 0) + dev_printk(KERN_NOTICE, &dev->dev, "configured with sram\n"); + + return 0; + +out: + free_netdev(dev); + + return err; } -static u32 mv643xx_eth_get_link(struct net_device *dev) +static int mv643xx_eth_remove(struct platform_device *pdev) { - struct mv643xx_private *mp = netdev_priv(dev); + struct mv643xx_eth_private *mp = platform_get_drvdata(pdev); - return mii_link_ok(&mp->mii); + unregister_netdev(mp->dev); + flush_scheduled_work(); + free_netdev(mp->dev); + + platform_set_drvdata(pdev, NULL); + + return 0; } -static int mv643xx_eth_nway_restart(struct net_device *dev) +static void mv643xx_eth_shutdown(struct platform_device *pdev) { - struct mv643xx_private *mp = netdev_priv(dev); + struct mv643xx_eth_private *mp = platform_get_drvdata(pdev); - return mii_nway_restart(&mp->mii); + /* Mask all interrupts on ethernet port */ + wrl(mp, INT_MASK(mp->port_num), 0); + rdl(mp, INT_MASK(mp->port_num)); + + if (netif_running(mp->dev)) + port_reset(mp); } -static int mv643xx_eth_do_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) +static struct platform_driver mv643xx_eth_driver = { + .probe = mv643xx_eth_probe, + .remove = mv643xx_eth_remove, + .shutdown = mv643xx_eth_shutdown, + .driver = { + .name = MV643XX_ETH_NAME, + .owner = THIS_MODULE, + }, +}; + +static int __init mv643xx_eth_init_module(void) { - struct mv643xx_private *mp = netdev_priv(dev); + int rc; + + rc = platform_driver_register(&mv643xx_eth_shared_driver); + if (!rc) { + rc = platform_driver_register(&mv643xx_eth_driver); + if (rc) + platform_driver_unregister(&mv643xx_eth_shared_driver); + } - return generic_mii_ioctl(&mp->mii, if_mii(ifr), cmd, NULL); + return rc; } +module_init(mv643xx_eth_init_module); -static const struct ethtool_ops mv643xx_ethtool_ops = { - .get_settings = mv643xx_get_settings, - .set_settings = mv643xx_set_settings, - .get_drvinfo = mv643xx_get_drvinfo, - .get_link = mv643xx_eth_get_link, - .set_sg = ethtool_op_set_sg, - .get_sset_count = mv643xx_get_sset_count, - .get_ethtool_stats = mv643xx_get_ethtool_stats, - .get_strings = mv643xx_get_strings, - .nway_reset = mv643xx_eth_nway_restart, -}; +static void __exit mv643xx_eth_cleanup_module(void) +{ + platform_driver_unregister(&mv643xx_eth_driver); + platform_driver_unregister(&mv643xx_eth_shared_driver); +} +module_exit(mv643xx_eth_cleanup_module); -/************* End ethtool support *************************/ +MODULE_AUTHOR("Rabeeh Khoury, Assaf Hoffman, Matthew Dharm, " + "Manish Lachwani, Dale Farnsworth and Lennert Buytenhek"); +MODULE_DESCRIPTION("Ethernet driver for Marvell MV643XX"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:" MV643XX_ETH_SHARED_NAME); +MODULE_ALIAS("platform:" MV643XX_ETH_NAME); diff --git a/drivers/net/myri10ge/myri10ge.c b/drivers/net/myri10ge/myri10ge.c index 823bb6d35334..b3981ed972bf 100644 --- a/drivers/net/myri10ge/myri10ge.c +++ b/drivers/net/myri10ge/myri10ge.c @@ -49,6 +49,7 @@ #include <linux/if_ether.h> #include <linux/if_vlan.h> #include <linux/inet_lro.h> +#include <linux/dca.h> #include <linux/ip.h> #include <linux/inet.h> #include <linux/in.h> @@ -185,11 +186,18 @@ struct myri10ge_slice_state { dma_addr_t fw_stats_bus; int watchdog_tx_done; int watchdog_tx_req; +#ifdef CONFIG_DCA + int cached_dca_tag; + int cpu; + __be32 __iomem *dca_tag; +#endif + char irq_desc[32]; }; struct myri10ge_priv { - struct myri10ge_slice_state ss; + struct myri10ge_slice_state *ss; int tx_boundary; /* boundary transmits cannot cross */ + int num_slices; int running; /* running? */ int csum_flag; /* rx_csums? */ int small_bytes; @@ -208,6 +216,11 @@ struct myri10ge_priv { dma_addr_t cmd_bus; struct pci_dev *pdev; int msi_enabled; + int msix_enabled; + struct msix_entry *msix_vectors; +#ifdef CONFIG_DCA + int dca_enabled; +#endif u32 link_state; unsigned int rdma_tags_available; int intr_coal_delay; @@ -244,6 +257,8 @@ struct myri10ge_priv { static char *myri10ge_fw_unaligned = "myri10ge_ethp_z8e.dat"; static char *myri10ge_fw_aligned = "myri10ge_eth_z8e.dat"; +static char *myri10ge_fw_rss_unaligned = "myri10ge_rss_ethp_z8e.dat"; +static char *myri10ge_fw_rss_aligned = "myri10ge_rss_eth_z8e.dat"; static char *myri10ge_fw_name = NULL; module_param(myri10ge_fw_name, charp, S_IRUGO | S_IWUSR); @@ -321,6 +336,18 @@ static int myri10ge_wcfifo = 0; module_param(myri10ge_wcfifo, int, S_IRUGO); MODULE_PARM_DESC(myri10ge_wcfifo, "Enable WC Fifo when WC is enabled"); +static int myri10ge_max_slices = 1; +module_param(myri10ge_max_slices, int, S_IRUGO); +MODULE_PARM_DESC(myri10ge_max_slices, "Max tx/rx queues"); + +static int myri10ge_rss_hash = MXGEFW_RSS_HASH_TYPE_SRC_PORT; +module_param(myri10ge_rss_hash, int, S_IRUGO); +MODULE_PARM_DESC(myri10ge_rss_hash, "Type of RSS hashing to do"); + +static int myri10ge_dca = 1; +module_param(myri10ge_dca, int, S_IRUGO); +MODULE_PARM_DESC(myri10ge_dca, "Enable DCA if possible"); + #define MYRI10GE_FW_OFFSET 1024*1024 #define MYRI10GE_HIGHPART_TO_U32(X) \ (sizeof (X) == 8) ? ((u32)((u64)(X) >> 32)) : (0) @@ -664,7 +691,7 @@ static int myri10ge_get_firmware_capabilities(struct myri10ge_priv *mgp) return 0; } -static int myri10ge_load_firmware(struct myri10ge_priv *mgp) +static int myri10ge_load_firmware(struct myri10ge_priv *mgp, int adopt) { char __iomem *submit; __be32 buf[16] __attribute__ ((__aligned__(8))); @@ -674,6 +701,8 @@ static int myri10ge_load_firmware(struct myri10ge_priv *mgp) size = 0; status = myri10ge_load_hotplug_firmware(mgp, &size); if (status) { + if (!adopt) + return status; dev_warn(&mgp->pdev->dev, "hotplug firmware loading failed\n"); /* Do not attempt to adopt firmware if there @@ -866,8 +895,12 @@ abort: static int myri10ge_reset(struct myri10ge_priv *mgp) { struct myri10ge_cmd cmd; - int status; + struct myri10ge_slice_state *ss; + int i, status; size_t bytes; +#ifdef CONFIG_DCA + unsigned long dca_tag_off; +#endif /* try to send a reset command to the card to see if it * is alive */ @@ -879,20 +912,74 @@ static int myri10ge_reset(struct myri10ge_priv *mgp) } (void)myri10ge_dma_test(mgp, MXGEFW_DMA_TEST); + /* + * Use non-ndis mcp_slot (eg, 4 bytes total, + * no toeplitz hash value returned. Older firmware will + * not understand this command, but will use the correct + * sized mcp_slot, so we ignore error returns + */ + cmd.data0 = MXGEFW_RSS_MCP_SLOT_TYPE_MIN; + (void)myri10ge_send_cmd(mgp, MXGEFW_CMD_SET_RSS_MCP_SLOT_TYPE, &cmd, 0); /* Now exchange information about interrupts */ - bytes = mgp->max_intr_slots * sizeof(*mgp->ss.rx_done.entry); - memset(mgp->ss.rx_done.entry, 0, bytes); + bytes = mgp->max_intr_slots * sizeof(*mgp->ss[0].rx_done.entry); cmd.data0 = (u32) bytes; status = myri10ge_send_cmd(mgp, MXGEFW_CMD_SET_INTRQ_SIZE, &cmd, 0); - cmd.data0 = MYRI10GE_LOWPART_TO_U32(mgp->ss.rx_done.bus); - cmd.data1 = MYRI10GE_HIGHPART_TO_U32(mgp->ss.rx_done.bus); - status |= myri10ge_send_cmd(mgp, MXGEFW_CMD_SET_INTRQ_DMA, &cmd, 0); + + /* + * Even though we already know how many slices are supported + * via myri10ge_probe_slices() MXGEFW_CMD_GET_MAX_RSS_QUEUES + * has magic side effects, and must be called after a reset. + * It must be called prior to calling any RSS related cmds, + * including assigning an interrupt queue for anything but + * slice 0. It must also be called *after* + * MXGEFW_CMD_SET_INTRQ_SIZE, since the intrq size is used by + * the firmware to compute offsets. + */ + + if (mgp->num_slices > 1) { + + /* ask the maximum number of slices it supports */ + status = myri10ge_send_cmd(mgp, MXGEFW_CMD_GET_MAX_RSS_QUEUES, + &cmd, 0); + if (status != 0) { + dev_err(&mgp->pdev->dev, + "failed to get number of slices\n"); + } + + /* + * MXGEFW_CMD_ENABLE_RSS_QUEUES must be called prior + * to setting up the interrupt queue DMA + */ + + cmd.data0 = mgp->num_slices; + cmd.data1 = 1; /* use MSI-X */ + status = myri10ge_send_cmd(mgp, MXGEFW_CMD_ENABLE_RSS_QUEUES, + &cmd, 0); + if (status != 0) { + dev_err(&mgp->pdev->dev, + "failed to set number of slices\n"); + + return status; + } + } + for (i = 0; i < mgp->num_slices; i++) { + ss = &mgp->ss[i]; + cmd.data0 = MYRI10GE_LOWPART_TO_U32(ss->rx_done.bus); + cmd.data1 = MYRI10GE_HIGHPART_TO_U32(ss->rx_done.bus); + cmd.data2 = i; + status |= myri10ge_send_cmd(mgp, MXGEFW_CMD_SET_INTRQ_DMA, + &cmd, 0); + }; status |= myri10ge_send_cmd(mgp, MXGEFW_CMD_GET_IRQ_ACK_OFFSET, &cmd, 0); - mgp->ss.irq_claim = (__iomem __be32 *) (mgp->sram + cmd.data0); + for (i = 0; i < mgp->num_slices; i++) { + ss = &mgp->ss[i]; + ss->irq_claim = + (__iomem __be32 *) (mgp->sram + cmd.data0 + 8 * i); + } status |= myri10ge_send_cmd(mgp, MXGEFW_CMD_GET_IRQ_DEASSERT_OFFSET, &cmd, 0); mgp->irq_deassert = (__iomem __be32 *) (mgp->sram + cmd.data0); @@ -906,24 +993,116 @@ static int myri10ge_reset(struct myri10ge_priv *mgp) } put_be32(htonl(mgp->intr_coal_delay), mgp->intr_coal_delay_ptr); - memset(mgp->ss.rx_done.entry, 0, bytes); +#ifdef CONFIG_DCA + status = myri10ge_send_cmd(mgp, MXGEFW_CMD_GET_DCA_OFFSET, &cmd, 0); + dca_tag_off = cmd.data0; + for (i = 0; i < mgp->num_slices; i++) { + ss = &mgp->ss[i]; + if (status == 0) { + ss->dca_tag = (__iomem __be32 *) + (mgp->sram + dca_tag_off + 4 * i); + } else { + ss->dca_tag = NULL; + } + } +#endif /* CONFIG_DCA */ /* reset mcp/driver shared state back to 0 */ - mgp->ss.tx.req = 0; - mgp->ss.tx.done = 0; - mgp->ss.tx.pkt_start = 0; - mgp->ss.tx.pkt_done = 0; - mgp->ss.rx_big.cnt = 0; - mgp->ss.rx_small.cnt = 0; - mgp->ss.rx_done.idx = 0; - mgp->ss.rx_done.cnt = 0; + mgp->link_changes = 0; + for (i = 0; i < mgp->num_slices; i++) { + ss = &mgp->ss[i]; + + memset(ss->rx_done.entry, 0, bytes); + ss->tx.req = 0; + ss->tx.done = 0; + ss->tx.pkt_start = 0; + ss->tx.pkt_done = 0; + ss->rx_big.cnt = 0; + ss->rx_small.cnt = 0; + ss->rx_done.idx = 0; + ss->rx_done.cnt = 0; + ss->tx.wake_queue = 0; + ss->tx.stop_queue = 0; + } + status = myri10ge_update_mac_address(mgp, mgp->dev->dev_addr); myri10ge_change_pause(mgp, mgp->pause); myri10ge_set_multicast_list(mgp->dev); return status; } +#ifdef CONFIG_DCA +static void +myri10ge_write_dca(struct myri10ge_slice_state *ss, int cpu, int tag) +{ + ss->cpu = cpu; + ss->cached_dca_tag = tag; + put_be32(htonl(tag), ss->dca_tag); +} + +static inline void myri10ge_update_dca(struct myri10ge_slice_state *ss) +{ + int cpu = get_cpu(); + int tag; + + if (cpu != ss->cpu) { + tag = dca_get_tag(cpu); + if (ss->cached_dca_tag != tag) + myri10ge_write_dca(ss, cpu, tag); + } + put_cpu(); +} + +static void myri10ge_setup_dca(struct myri10ge_priv *mgp) +{ + int err, i; + struct pci_dev *pdev = mgp->pdev; + + if (mgp->ss[0].dca_tag == NULL || mgp->dca_enabled) + return; + if (!myri10ge_dca) { + dev_err(&pdev->dev, "dca disabled by administrator\n"); + return; + } + err = dca_add_requester(&pdev->dev); + if (err) { + dev_err(&pdev->dev, + "dca_add_requester() failed, err=%d\n", err); + return; + } + mgp->dca_enabled = 1; + for (i = 0; i < mgp->num_slices; i++) + myri10ge_write_dca(&mgp->ss[i], -1, 0); +} + +static void myri10ge_teardown_dca(struct myri10ge_priv *mgp) +{ + struct pci_dev *pdev = mgp->pdev; + int err; + + if (!mgp->dca_enabled) + return; + mgp->dca_enabled = 0; + err = dca_remove_requester(&pdev->dev); +} + +static int myri10ge_notify_dca_device(struct device *dev, void *data) +{ + struct myri10ge_priv *mgp; + unsigned long event; + + mgp = dev_get_drvdata(dev); + event = *(unsigned long *)data; + + if (event == DCA_PROVIDER_ADD) + myri10ge_setup_dca(mgp); + else if (event == DCA_PROVIDER_REMOVE) + myri10ge_teardown_dca(mgp); + return 0; +} +#endif /* CONFIG_DCA */ + static inline void myri10ge_submit_8rx(struct mcp_kreq_ether_recv __iomem * dst, struct mcp_kreq_ether_recv *src) @@ -1102,9 +1281,10 @@ myri10ge_rx_done(struct myri10ge_slice_state *ss, struct myri10ge_rx_buf *rx, rx_frags[0].size -= MXGEFW_PAD; len -= MXGEFW_PAD; lro_receive_frags(&ss->rx_done.lro_mgr, rx_frags, - len, len, /* opaque, will come back in get_frag_header */ + len, len, (void *)(__force unsigned long)csum, csum); + return 1; } @@ -1243,7 +1423,7 @@ myri10ge_clean_rx_done(struct myri10ge_slice_state *ss, int budget) static inline void myri10ge_check_statblock(struct myri10ge_priv *mgp) { - struct mcp_irq_data *stats = mgp->ss.fw_stats; + struct mcp_irq_data *stats = mgp->ss[0].fw_stats; if (unlikely(stats->stats_updated)) { unsigned link_up = ntohl(stats->link_up); @@ -1290,6 +1470,11 @@ static int myri10ge_poll(struct napi_struct *napi, int budget) struct net_device *netdev = ss->mgp->dev; int work_done; +#ifdef CONFIG_DCA + if (ss->mgp->dca_enabled) + myri10ge_update_dca(ss); +#endif + /* process as many rx events as NAPI will allow */ work_done = myri10ge_clean_rx_done(ss, budget); @@ -1309,6 +1494,13 @@ static irqreturn_t myri10ge_intr(int irq, void *arg) u32 send_done_count; int i; + /* an interrupt on a non-zero slice is implicitly valid + * since MSI-X irqs are not shared */ + if (ss != mgp->ss) { + netif_rx_schedule(ss->dev, &ss->napi); + return (IRQ_HANDLED); + } + /* make sure it is our IRQ, and that the DMA has finished */ if (unlikely(!stats->valid)) return (IRQ_NONE); @@ -1318,7 +1510,7 @@ static irqreturn_t myri10ge_intr(int irq, void *arg) if (stats->valid & 1) netif_rx_schedule(ss->dev, &ss->napi); - if (!mgp->msi_enabled) { + if (!mgp->msi_enabled && !mgp->msix_enabled) { put_be32(0, mgp->irq_deassert); if (!myri10ge_deassert_wait) stats->valid = 0; @@ -1453,10 +1645,10 @@ myri10ge_get_ringparam(struct net_device *netdev, { struct myri10ge_priv *mgp = netdev_priv(netdev); - ring->rx_mini_max_pending = mgp->ss.rx_small.mask + 1; - ring->rx_max_pending = mgp->ss.rx_big.mask + 1; + 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.rx_small.mask + 1; + ring->tx_max_pending = mgp->ss[0].rx_small.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; @@ -1504,9 +1696,12 @@ static const char myri10ge_gstrings_main_stats[][ETH_GSTRING_LEN] = { "tx_aborted_errors", "tx_carrier_errors", "tx_fifo_errors", "tx_heartbeat_errors", "tx_window_errors", /* device-specific stats */ - "tx_boundary", "WC", "irq", "MSI", + "tx_boundary", "WC", "irq", "MSI", "MSIX", "read_dma_bw_MBs", "write_dma_bw_MBs", "read_write_dma_bw_MBs", "serial_number", "watchdog_resets", +#ifdef CONFIG_DCA + "dca_capable", "dca_enabled", +#endif "link_changes", "link_up", "dropped_link_overflow", "dropped_link_error_or_filtered", "dropped_pause", "dropped_bad_phy", "dropped_bad_crc32", @@ -1531,23 +1726,31 @@ static const char myri10ge_gstrings_slice_stats[][ETH_GSTRING_LEN] = { static void myri10ge_get_strings(struct net_device *netdev, u32 stringset, u8 * data) { + struct myri10ge_priv *mgp = netdev_priv(netdev); + int i; + switch (stringset) { case ETH_SS_STATS: memcpy(data, *myri10ge_gstrings_main_stats, sizeof(myri10ge_gstrings_main_stats)); data += sizeof(myri10ge_gstrings_main_stats); - memcpy(data, *myri10ge_gstrings_slice_stats, - sizeof(myri10ge_gstrings_slice_stats)); - data += sizeof(myri10ge_gstrings_slice_stats); + for (i = 0; i < mgp->num_slices; i++) { + memcpy(data, *myri10ge_gstrings_slice_stats, + sizeof(myri10ge_gstrings_slice_stats)); + data += sizeof(myri10ge_gstrings_slice_stats); + } break; } } static int myri10ge_get_sset_count(struct net_device *netdev, int sset) { + struct myri10ge_priv *mgp = netdev_priv(netdev); + switch (sset) { case ETH_SS_STATS: - return MYRI10GE_MAIN_STATS_LEN + MYRI10GE_SLICE_STATS_LEN; + return MYRI10GE_MAIN_STATS_LEN + + mgp->num_slices * MYRI10GE_SLICE_STATS_LEN; default: return -EOPNOTSUPP; } @@ -1559,6 +1762,7 @@ myri10ge_get_ethtool_stats(struct net_device *netdev, { struct myri10ge_priv *mgp = netdev_priv(netdev); struct myri10ge_slice_state *ss; + int slice; int i; for (i = 0; i < MYRI10GE_NET_STATS_LEN; i++) @@ -1568,15 +1772,20 @@ myri10ge_get_ethtool_stats(struct net_device *netdev, data[i++] = (unsigned int)mgp->wc_enabled; data[i++] = (unsigned int)mgp->pdev->irq; data[i++] = (unsigned int)mgp->msi_enabled; + data[i++] = (unsigned int)mgp->msix_enabled; data[i++] = (unsigned int)mgp->read_dma; data[i++] = (unsigned int)mgp->write_dma; data[i++] = (unsigned int)mgp->read_write_dma; data[i++] = (unsigned int)mgp->serial_number; data[i++] = (unsigned int)mgp->watchdog_resets; +#ifdef CONFIG_DCA + data[i++] = (unsigned int)(mgp->ss[0].dca_tag != NULL); + data[i++] = (unsigned int)(mgp->dca_enabled); +#endif data[i++] = (unsigned int)mgp->link_changes; /* firmware stats are useful only in the first slice */ - ss = &mgp->ss; + ss = &mgp->ss[0]; data[i++] = (unsigned int)ntohl(ss->fw_stats->link_up); data[i++] = (unsigned int)ntohl(ss->fw_stats->dropped_link_overflow); data[i++] = @@ -1592,24 +1801,27 @@ myri10ge_get_ethtool_stats(struct net_device *netdev, data[i++] = (unsigned int)ntohl(ss->fw_stats->dropped_no_small_buffer); data[i++] = (unsigned int)ntohl(ss->fw_stats->dropped_no_big_buffer); - data[i++] = 0; - data[i++] = (unsigned int)ss->tx.pkt_start; - data[i++] = (unsigned int)ss->tx.pkt_done; - data[i++] = (unsigned int)ss->tx.req; - data[i++] = (unsigned int)ss->tx.done; - data[i++] = (unsigned int)ss->rx_small.cnt; - data[i++] = (unsigned int)ss->rx_big.cnt; - data[i++] = (unsigned int)ss->tx.wake_queue; - data[i++] = (unsigned int)ss->tx.stop_queue; - data[i++] = (unsigned int)ss->tx.linearized; - data[i++] = ss->rx_done.lro_mgr.stats.aggregated; - data[i++] = ss->rx_done.lro_mgr.stats.flushed; - if (ss->rx_done.lro_mgr.stats.flushed) - data[i++] = ss->rx_done.lro_mgr.stats.aggregated / - ss->rx_done.lro_mgr.stats.flushed; - else - data[i++] = 0; - data[i++] = ss->rx_done.lro_mgr.stats.no_desc; + for (slice = 0; slice < mgp->num_slices; slice++) { + ss = &mgp->ss[slice]; + data[i++] = slice; + data[i++] = (unsigned int)ss->tx.pkt_start; + data[i++] = (unsigned int)ss->tx.pkt_done; + data[i++] = (unsigned int)ss->tx.req; + data[i++] = (unsigned int)ss->tx.done; + data[i++] = (unsigned int)ss->rx_small.cnt; + data[i++] = (unsigned int)ss->rx_big.cnt; + data[i++] = (unsigned int)ss->tx.wake_queue; + data[i++] = (unsigned int)ss->tx.stop_queue; + data[i++] = (unsigned int)ss->tx.linearized; + data[i++] = ss->rx_done.lro_mgr.stats.aggregated; + data[i++] = ss->rx_done.lro_mgr.stats.flushed; + if (ss->rx_done.lro_mgr.stats.flushed) + data[i++] = ss->rx_done.lro_mgr.stats.aggregated / + ss->rx_done.lro_mgr.stats.flushed; + else + data[i++] = 0; + data[i++] = ss->rx_done.lro_mgr.stats.no_desc; + } } static void myri10ge_set_msglevel(struct net_device *netdev, u32 value) @@ -1652,12 +1864,15 @@ static int myri10ge_allocate_rings(struct myri10ge_slice_state *ss) struct net_device *dev = mgp->dev; int tx_ring_size, rx_ring_size; int tx_ring_entries, rx_ring_entries; - int i, status; + int i, slice, status; size_t bytes; /* get ring sizes */ + slice = ss - mgp->ss; + cmd.data0 = slice; status = myri10ge_send_cmd(mgp, MXGEFW_CMD_GET_SEND_RING_SIZE, &cmd, 0); tx_ring_size = cmd.data0; + cmd.data0 = slice; status |= myri10ge_send_cmd(mgp, MXGEFW_CMD_GET_RX_RING_SIZE, &cmd, 0); if (status != 0) return status; @@ -1722,15 +1937,17 @@ static int myri10ge_allocate_rings(struct myri10ge_slice_state *ss) mgp->small_bytes + MXGEFW_PAD, 0); if (ss->rx_small.fill_cnt < ss->rx_small.mask + 1) { - printk(KERN_ERR "myri10ge: %s: alloced only %d small bufs\n", - dev->name, ss->rx_small.fill_cnt); + printk(KERN_ERR + "myri10ge: %s:slice-%d: alloced only %d small bufs\n", + dev->name, slice, ss->rx_small.fill_cnt); goto abort_with_rx_small_ring; } myri10ge_alloc_rx_pages(mgp, &ss->rx_big, mgp->big_bytes, 0); if (ss->rx_big.fill_cnt < ss->rx_big.mask + 1) { - printk(KERN_ERR "myri10ge: %s: alloced only %d big bufs\n", - dev->name, ss->rx_big.fill_cnt); + printk(KERN_ERR + "myri10ge: %s:slice-%d: alloced only %d big bufs\n", + dev->name, slice, ss->rx_big.fill_cnt); goto abort_with_rx_big_ring; } @@ -1782,6 +1999,10 @@ static void myri10ge_free_rings(struct myri10ge_slice_state *ss) struct myri10ge_tx_buf *tx; int i, len, idx; + /* If not allocated, skip it */ + if (ss->tx.req_list == NULL) + return; + for (i = ss->rx_big.cnt; i < ss->rx_big.fill_cnt; i++) { idx = i & ss->rx_big.mask; if (i == ss->rx_big.fill_cnt - 1) @@ -1844,25 +2065,67 @@ static void myri10ge_free_rings(struct myri10ge_slice_state *ss) static int myri10ge_request_irq(struct myri10ge_priv *mgp) { struct pci_dev *pdev = mgp->pdev; + struct myri10ge_slice_state *ss; + struct net_device *netdev = mgp->dev; + int i; int status; + mgp->msi_enabled = 0; + mgp->msix_enabled = 0; + status = 0; if (myri10ge_msi) { - status = pci_enable_msi(pdev); - if (status != 0) - dev_err(&pdev->dev, - "Error %d setting up MSI; falling back to xPIC\n", - status); - else - mgp->msi_enabled = 1; - } else { - mgp->msi_enabled = 0; + if (mgp->num_slices > 1) { + status = + pci_enable_msix(pdev, mgp->msix_vectors, + mgp->num_slices); + if (status == 0) { + mgp->msix_enabled = 1; + } else { + dev_err(&pdev->dev, + "Error %d setting up MSI-X\n", status); + return status; + } + } + if (mgp->msix_enabled == 0) { + status = pci_enable_msi(pdev); + if (status != 0) { + dev_err(&pdev->dev, + "Error %d setting up MSI; falling back to xPIC\n", + status); + } else { + mgp->msi_enabled = 1; + } + } } - status = request_irq(pdev->irq, myri10ge_intr, IRQF_SHARED, - mgp->dev->name, mgp); - if (status != 0) { - dev_err(&pdev->dev, "failed to allocate IRQ\n"); - if (mgp->msi_enabled) - pci_disable_msi(pdev); + if (mgp->msix_enabled) { + for (i = 0; i < mgp->num_slices; i++) { + ss = &mgp->ss[i]; + snprintf(ss->irq_desc, sizeof(ss->irq_desc), + "%s:slice-%d", netdev->name, i); + status = request_irq(mgp->msix_vectors[i].vector, + myri10ge_intr, 0, ss->irq_desc, + ss); + if (status != 0) { + dev_err(&pdev->dev, + "slice %d failed to allocate IRQ\n", i); + i--; + while (i >= 0) { + free_irq(mgp->msix_vectors[i].vector, + &mgp->ss[i]); + i--; + } + pci_disable_msix(pdev); + return status; + } + } + } else { + status = request_irq(pdev->irq, myri10ge_intr, IRQF_SHARED, + mgp->dev->name, &mgp->ss[0]); + if (status != 0) { + dev_err(&pdev->dev, "failed to allocate IRQ\n"); + if (mgp->msi_enabled) + pci_disable_msi(pdev); + } } return status; } @@ -1870,10 +2133,18 @@ static int myri10ge_request_irq(struct myri10ge_priv *mgp) static void myri10ge_free_irq(struct myri10ge_priv *mgp) { struct pci_dev *pdev = mgp->pdev; + int i; - free_irq(pdev->irq, mgp); + if (mgp->msix_enabled) { + for (i = 0; i < mgp->num_slices; i++) + free_irq(mgp->msix_vectors[i].vector, &mgp->ss[i]); + } else { + free_irq(pdev->irq, &mgp->ss[0]); + } if (mgp->msi_enabled) pci_disable_msi(pdev); + if (mgp->msix_enabled) + pci_disable_msix(pdev); } static int @@ -1935,12 +2206,82 @@ myri10ge_get_frag_header(struct skb_frag_struct *frag, void **mac_hdr, return 0; } +static int myri10ge_get_txrx(struct myri10ge_priv *mgp, int slice) +{ + struct myri10ge_cmd cmd; + struct myri10ge_slice_state *ss; + int status; + + ss = &mgp->ss[slice]; + cmd.data0 = 0; /* single slice for now */ + status = myri10ge_send_cmd(mgp, MXGEFW_CMD_GET_SEND_OFFSET, &cmd, 0); + ss->tx.lanai = (struct mcp_kreq_ether_send __iomem *) + (mgp->sram + cmd.data0); + + cmd.data0 = slice; + status |= myri10ge_send_cmd(mgp, MXGEFW_CMD_GET_SMALL_RX_OFFSET, + &cmd, 0); + ss->rx_small.lanai = (struct mcp_kreq_ether_recv __iomem *) + (mgp->sram + cmd.data0); + + cmd.data0 = slice; + status |= myri10ge_send_cmd(mgp, MXGEFW_CMD_GET_BIG_RX_OFFSET, &cmd, 0); + ss->rx_big.lanai = (struct mcp_kreq_ether_recv __iomem *) + (mgp->sram + cmd.data0); + + if (myri10ge_wcfifo && mgp->wc_enabled) { + ss->tx.wc_fifo = (u8 __iomem *) + mgp->sram + MXGEFW_ETH_SEND_4 + 64 * slice; + ss->rx_small.wc_fifo = (u8 __iomem *) + mgp->sram + MXGEFW_ETH_RECV_SMALL + 64 * slice; + ss->rx_big.wc_fifo = (u8 __iomem *) + mgp->sram + MXGEFW_ETH_RECV_BIG + 64 * slice; + } else { + ss->tx.wc_fifo = NULL; + ss->rx_small.wc_fifo = NULL; + ss->rx_big.wc_fifo = NULL; + } + return status; + +} + +static int myri10ge_set_stats(struct myri10ge_priv *mgp, int slice) +{ + struct myri10ge_cmd cmd; + struct myri10ge_slice_state *ss; + int status; + + ss = &mgp->ss[slice]; + cmd.data0 = MYRI10GE_LOWPART_TO_U32(ss->fw_stats_bus); + cmd.data1 = MYRI10GE_HIGHPART_TO_U32(ss->fw_stats_bus); + cmd.data2 = sizeof(struct mcp_irq_data); + status = myri10ge_send_cmd(mgp, MXGEFW_CMD_SET_STATS_DMA_V2, &cmd, 0); + if (status == -ENOSYS) { + dma_addr_t bus = ss->fw_stats_bus; + if (slice != 0) + return -EINVAL; + bus += offsetof(struct mcp_irq_data, send_done_count); + cmd.data0 = MYRI10GE_LOWPART_TO_U32(bus); + cmd.data1 = MYRI10GE_HIGHPART_TO_U32(bus); + status = myri10ge_send_cmd(mgp, + MXGEFW_CMD_SET_STATS_DMA_OBSOLETE, + &cmd, 0); + /* Firmware cannot support multicast without STATS_DMA_V2 */ + mgp->fw_multicast_support = 0; + } else { + mgp->fw_multicast_support = 1; + } + return 0; +} + static int myri10ge_open(struct net_device *dev) { + struct myri10ge_slice_state *ss; struct myri10ge_priv *mgp = netdev_priv(dev); struct myri10ge_cmd cmd; + int i, status, big_pow2, slice; + u8 *itable; struct net_lro_mgr *lro_mgr; - int status, big_pow2; if (mgp->running != MYRI10GE_ETH_STOPPED) return -EBUSY; @@ -1952,6 +2293,48 @@ static int myri10ge_open(struct net_device *dev) goto abort_with_nothing; } + if (mgp->num_slices > 1) { + cmd.data0 = mgp->num_slices; + cmd.data1 = 1; /* use MSI-X */ + status = myri10ge_send_cmd(mgp, MXGEFW_CMD_ENABLE_RSS_QUEUES, + &cmd, 0); + if (status != 0) { + printk(KERN_ERR + "myri10ge: %s: failed to set number of slices\n", + dev->name); + goto abort_with_nothing; + } + /* setup the indirection table */ + cmd.data0 = mgp->num_slices; + status = myri10ge_send_cmd(mgp, MXGEFW_CMD_SET_RSS_TABLE_SIZE, + &cmd, 0); + + status |= myri10ge_send_cmd(mgp, + MXGEFW_CMD_GET_RSS_TABLE_OFFSET, + &cmd, 0); + if (status != 0) { + printk(KERN_ERR + "myri10ge: %s: failed to setup rss tables\n", + dev->name); + } + + /* just enable an identity mapping */ + itable = mgp->sram + cmd.data0; + for (i = 0; i < mgp->num_slices; i++) + __raw_writeb(i, &itable[i]); + + cmd.data0 = 1; + cmd.data1 = myri10ge_rss_hash; + status = myri10ge_send_cmd(mgp, MXGEFW_CMD_SET_RSS_ENABLE, + &cmd, 0); + if (status != 0) { + printk(KERN_ERR + "myri10ge: %s: failed to enable slices\n", + dev->name); + goto abort_with_nothing; + } + } + status = myri10ge_request_irq(mgp); if (status != 0) goto abort_with_nothing; @@ -1975,41 +2358,6 @@ static int myri10ge_open(struct net_device *dev) if (myri10ge_small_bytes > 0) mgp->small_bytes = myri10ge_small_bytes; - /* get the lanai pointers to the send and receive rings */ - - status |= myri10ge_send_cmd(mgp, MXGEFW_CMD_GET_SEND_OFFSET, &cmd, 0); - mgp->ss.tx.lanai = - (struct mcp_kreq_ether_send __iomem *)(mgp->sram + cmd.data0); - - status |= - myri10ge_send_cmd(mgp, MXGEFW_CMD_GET_SMALL_RX_OFFSET, &cmd, 0); - mgp->ss.rx_small.lanai = - (struct mcp_kreq_ether_recv __iomem *)(mgp->sram + cmd.data0); - - status |= myri10ge_send_cmd(mgp, MXGEFW_CMD_GET_BIG_RX_OFFSET, &cmd, 0); - mgp->ss.rx_big.lanai = - (struct mcp_kreq_ether_recv __iomem *)(mgp->sram + cmd.data0); - - if (status != 0) { - printk(KERN_ERR - "myri10ge: %s: failed to get ring sizes or locations\n", - dev->name); - mgp->running = MYRI10GE_ETH_STOPPED; - goto abort_with_irq; - } - - if (myri10ge_wcfifo && mgp->wc_enabled) { - mgp->ss.tx.wc_fifo = (u8 __iomem *) mgp->sram + MXGEFW_ETH_SEND_4; - mgp->ss.rx_small.wc_fifo = - (u8 __iomem *) mgp->sram + MXGEFW_ETH_RECV_SMALL; - mgp->ss.rx_big.wc_fifo = - (u8 __iomem *) mgp->sram + MXGEFW_ETH_RECV_BIG; - } else { - mgp->ss.tx.wc_fifo = NULL; - mgp->ss.rx_small.wc_fifo = NULL; - mgp->ss.rx_big.wc_fifo = NULL; - } - /* Firmware needs the big buff size as a power of 2. Lie and * tell him the buffer is larger, because we only use 1 * buffer/pkt, and the mtu will prevent overruns. @@ -2024,9 +2372,44 @@ static int myri10ge_open(struct net_device *dev) mgp->big_bytes = big_pow2; } - status = myri10ge_allocate_rings(&mgp->ss); - if (status != 0) - goto abort_with_irq; + /* setup the per-slice data structures */ + for (slice = 0; slice < mgp->num_slices; slice++) { + ss = &mgp->ss[slice]; + + status = myri10ge_get_txrx(mgp, slice); + if (status != 0) { + printk(KERN_ERR + "myri10ge: %s: failed to get ring sizes or locations\n", + dev->name); + goto abort_with_rings; + } + status = myri10ge_allocate_rings(ss); + if (status != 0) + goto abort_with_rings; + if (slice == 0) + status = myri10ge_set_stats(mgp, slice); + if (status) { + printk(KERN_ERR + "myri10ge: %s: Couldn't set stats DMA\n", + dev->name); + goto abort_with_rings; + } + + lro_mgr = &ss->rx_done.lro_mgr; + lro_mgr->dev = dev; + lro_mgr->features = LRO_F_NAPI; + lro_mgr->ip_summed = CHECKSUM_COMPLETE; + lro_mgr->ip_summed_aggr = CHECKSUM_UNNECESSARY; + lro_mgr->max_desc = MYRI10GE_MAX_LRO_DESCRIPTORS; + lro_mgr->lro_arr = ss->rx_done.lro_desc; + lro_mgr->get_frag_header = myri10ge_get_frag_header; + lro_mgr->max_aggr = myri10ge_lro_max_pkts; + if (lro_mgr->max_aggr > MAX_SKB_FRAGS) + lro_mgr->max_aggr = MAX_SKB_FRAGS; + + /* must happen prior to any irq */ + napi_enable(&(ss)->napi); + } /* now give firmware buffers sizes, and MTU */ cmd.data0 = dev->mtu + ETH_HLEN + VLAN_HLEN; @@ -2043,25 +2426,15 @@ static int myri10ge_open(struct net_device *dev) goto abort_with_rings; } - cmd.data0 = MYRI10GE_LOWPART_TO_U32(mgp->ss.fw_stats_bus); - cmd.data1 = MYRI10GE_HIGHPART_TO_U32(mgp->ss.fw_stats_bus); - cmd.data2 = sizeof(struct mcp_irq_data); - status = myri10ge_send_cmd(mgp, MXGEFW_CMD_SET_STATS_DMA_V2, &cmd, 0); - if (status == -ENOSYS) { - dma_addr_t bus = mgp->ss.fw_stats_bus; - bus += offsetof(struct mcp_irq_data, send_done_count); - cmd.data0 = MYRI10GE_LOWPART_TO_U32(bus); - cmd.data1 = MYRI10GE_HIGHPART_TO_U32(bus); - status = myri10ge_send_cmd(mgp, - MXGEFW_CMD_SET_STATS_DMA_OBSOLETE, - &cmd, 0); - /* Firmware cannot support multicast without STATS_DMA_V2 */ - mgp->fw_multicast_support = 0; - } else { - mgp->fw_multicast_support = 1; - } - if (status) { - printk(KERN_ERR "myri10ge: %s: Couldn't set stats DMA\n", + /* + * Set Linux style TSO mode; this is needed only on newer + * firmware versions. Older versions default to Linux + * style TSO + */ + cmd.data0 = 0; + status = myri10ge_send_cmd(mgp, MXGEFW_CMD_SET_TSO_MODE, &cmd, 0); + if (status && status != -ENOSYS) { + printk(KERN_ERR "myri10ge: %s: Couldn't set TSO mode\n", dev->name); goto abort_with_rings; } @@ -2069,21 +2442,6 @@ static int myri10ge_open(struct net_device *dev) mgp->link_state = ~0U; mgp->rdma_tags_available = 15; - lro_mgr = &mgp->ss.rx_done.lro_mgr; - lro_mgr->dev = dev; - lro_mgr->features = LRO_F_NAPI; - lro_mgr->ip_summed = CHECKSUM_COMPLETE; - lro_mgr->ip_summed_aggr = CHECKSUM_UNNECESSARY; - lro_mgr->max_desc = MYRI10GE_MAX_LRO_DESCRIPTORS; - lro_mgr->lro_arr = mgp->ss.rx_done.lro_desc; - lro_mgr->get_frag_header = myri10ge_get_frag_header; - lro_mgr->max_aggr = myri10ge_lro_max_pkts; - lro_mgr->frag_align_pad = 2; - if (lro_mgr->max_aggr > MAX_SKB_FRAGS) - lro_mgr->max_aggr = MAX_SKB_FRAGS; - - napi_enable(&mgp->ss.napi); /* must happen prior to any irq */ - status = myri10ge_send_cmd(mgp, MXGEFW_CMD_ETHERNET_UP, &cmd, 0); if (status) { printk(KERN_ERR "myri10ge: %s: Couldn't bring up link\n", @@ -2091,8 +2449,6 @@ static int myri10ge_open(struct net_device *dev) goto abort_with_rings; } - mgp->ss.tx.wake_queue = 0; - mgp->ss.tx.stop_queue = 0; mgp->running = MYRI10GE_ETH_RUNNING; mgp->watchdog_timer.expires = jiffies + myri10ge_watchdog_timeout * HZ; add_timer(&mgp->watchdog_timer); @@ -2100,9 +2456,9 @@ static int myri10ge_open(struct net_device *dev) return 0; abort_with_rings: - myri10ge_free_rings(&mgp->ss); + for (i = 0; i < mgp->num_slices; i++) + myri10ge_free_rings(&mgp->ss[i]); -abort_with_irq: myri10ge_free_irq(mgp); abort_with_nothing: @@ -2115,16 +2471,19 @@ static int myri10ge_close(struct net_device *dev) struct myri10ge_priv *mgp = netdev_priv(dev); struct myri10ge_cmd cmd; int status, old_down_cnt; + int i; if (mgp->running != MYRI10GE_ETH_RUNNING) return 0; - if (mgp->ss.tx.req_bytes == NULL) + if (mgp->ss[0].tx.req_bytes == NULL) return 0; del_timer_sync(&mgp->watchdog_timer); mgp->running = MYRI10GE_ETH_STOPPING; - napi_disable(&mgp->ss.napi); + for (i = 0; i < mgp->num_slices; i++) { + napi_disable(&mgp->ss[i].napi); + } netif_carrier_off(dev); netif_stop_queue(dev); old_down_cnt = mgp->down_cnt; @@ -2140,7 +2499,8 @@ static int myri10ge_close(struct net_device *dev) netif_tx_disable(dev); myri10ge_free_irq(mgp); - myri10ge_free_rings(&mgp->ss); + for (i = 0; i < mgp->num_slices; i++) + myri10ge_free_rings(&mgp->ss[i]); mgp->running = MYRI10GE_ETH_STOPPED; return 0; @@ -2261,7 +2621,7 @@ static int myri10ge_xmit(struct sk_buff *skb, struct net_device *dev) u8 flags, odd_flag; /* always transmit through slot 0 */ - ss = &mgp->ss; + ss = mgp->ss; tx = &ss->tx; again: req = tx->req_list; @@ -2566,7 +2926,21 @@ drop: static struct net_device_stats *myri10ge_get_stats(struct net_device *dev) { struct myri10ge_priv *mgp = netdev_priv(dev); - return &mgp->stats; + struct myri10ge_slice_netstats *slice_stats; + struct net_device_stats *stats = &mgp->stats; + int i; + + memset(stats, 0, sizeof(*stats)); + for (i = 0; i < mgp->num_slices; i++) { + slice_stats = &mgp->ss[i].stats; + stats->rx_packets += slice_stats->rx_packets; + stats->tx_packets += slice_stats->tx_packets; + stats->rx_bytes += slice_stats->rx_bytes; + stats->tx_bytes += slice_stats->tx_bytes; + stats->rx_dropped += slice_stats->rx_dropped; + stats->tx_dropped += slice_stats->tx_dropped; + } + return stats; } static void myri10ge_set_multicast_list(struct net_device *dev) @@ -2777,10 +3151,10 @@ static void myri10ge_enable_ecrc(struct myri10ge_priv *mgp) * * If the driver can neither enable ECRC nor verify that it has * already been enabled, then it must use a firmware image which works - * around unaligned completion packets (myri10ge_ethp_z8e.dat), and it + * around unaligned completion packets (myri10ge_rss_ethp_z8e.dat), and it * should also ensure that it never gives the device a Read-DMA which is * larger than 2KB by setting the tx_boundary to 2KB. If ECRC is - * enabled, then the driver should use the aligned (myri10ge_eth_z8e.dat) + * enabled, then the driver should use the aligned (myri10ge_rss_eth_z8e.dat) * firmware image, and set tx_boundary to 4KB. */ @@ -2809,7 +3183,7 @@ static void myri10ge_firmware_probe(struct myri10ge_priv *mgp) * completions) in order to see if it works on this host. */ mgp->fw_name = myri10ge_fw_aligned; - status = myri10ge_load_firmware(mgp); + status = myri10ge_load_firmware(mgp, 1); if (status != 0) { goto abort; } @@ -2990,6 +3364,7 @@ static void myri10ge_watchdog(struct work_struct *work) struct myri10ge_tx_buf *tx; u32 reboot; int status; + int i; u16 cmd, vendor; mgp->watchdog_resets++; @@ -3037,20 +3412,26 @@ static void myri10ge_watchdog(struct work_struct *work) printk(KERN_ERR "myri10ge: %s: device timeout, resetting\n", mgp->dev->name); - tx = &mgp->ss.tx; - printk(KERN_INFO "myri10ge: %s: %d %d %d %d %d\n", - mgp->dev->name, tx->req, tx->done, - tx->pkt_start, tx->pkt_done, - (int)ntohl(mgp->ss.fw_stats->send_done_count)); - msleep(2000); - printk(KERN_INFO "myri10ge: %s: %d %d %d %d %d\n", - mgp->dev->name, tx->req, tx->done, - tx->pkt_start, tx->pkt_done, - (int)ntohl(mgp->ss.fw_stats->send_done_count)); + for (i = 0; i < mgp->num_slices; i++) { + tx = &mgp->ss[i].tx; + printk(KERN_INFO + "myri10ge: %s: (%d): %d %d %d %d %d\n", + mgp->dev->name, i, tx->req, tx->done, + tx->pkt_start, tx->pkt_done, + (int)ntohl(mgp->ss[i].fw_stats-> + send_done_count)); + msleep(2000); + printk(KERN_INFO + "myri10ge: %s: (%d): %d %d %d %d %d\n", + mgp->dev->name, i, tx->req, tx->done, + tx->pkt_start, tx->pkt_done, + (int)ntohl(mgp->ss[i].fw_stats-> + send_done_count)); + } } rtnl_lock(); myri10ge_close(mgp->dev); - status = myri10ge_load_firmware(mgp); + status = myri10ge_load_firmware(mgp, 1); if (status != 0) printk(KERN_ERR "myri10ge: %s: failed to load firmware\n", mgp->dev->name); @@ -3070,47 +3451,241 @@ static void myri10ge_watchdog_timer(unsigned long arg) { struct myri10ge_priv *mgp; struct myri10ge_slice_state *ss; + int i, reset_needed; u32 rx_pause_cnt; mgp = (struct myri10ge_priv *)arg; - rx_pause_cnt = ntohl(mgp->ss.fw_stats->dropped_pause); + rx_pause_cnt = ntohl(mgp->ss[0].fw_stats->dropped_pause); + for (i = 0, reset_needed = 0; + i < mgp->num_slices && reset_needed == 0; ++i) { + + ss = &mgp->ss[i]; + if (ss->rx_small.watchdog_needed) { + myri10ge_alloc_rx_pages(mgp, &ss->rx_small, + mgp->small_bytes + MXGEFW_PAD, + 1); + if (ss->rx_small.fill_cnt - ss->rx_small.cnt >= + myri10ge_fill_thresh) + ss->rx_small.watchdog_needed = 0; + } + if (ss->rx_big.watchdog_needed) { + myri10ge_alloc_rx_pages(mgp, &ss->rx_big, + mgp->big_bytes, 1); + if (ss->rx_big.fill_cnt - ss->rx_big.cnt >= + myri10ge_fill_thresh) + ss->rx_big.watchdog_needed = 0; + } - ss = &mgp->ss; - if (ss->rx_small.watchdog_needed) { - myri10ge_alloc_rx_pages(mgp, &ss->rx_small, - mgp->small_bytes + MXGEFW_PAD, 1); - if (ss->rx_small.fill_cnt - ss->rx_small.cnt >= - myri10ge_fill_thresh) - ss->rx_small.watchdog_needed = 0; - } - if (ss->rx_big.watchdog_needed) { - myri10ge_alloc_rx_pages(mgp, &ss->rx_big, mgp->big_bytes, 1); - if (ss->rx_big.fill_cnt - ss->rx_big.cnt >= - myri10ge_fill_thresh) - ss->rx_big.watchdog_needed = 0; - } - - if (ss->tx.req != ss->tx.done && - ss->tx.done == ss->watchdog_tx_done && - ss->watchdog_tx_req != ss->watchdog_tx_done) { - /* nic seems like it might be stuck.. */ - if (rx_pause_cnt != mgp->watchdog_pause) { - if (net_ratelimit()) - printk(KERN_WARNING "myri10ge %s:" - "TX paused, check link partner\n", - mgp->dev->name); - } else { - schedule_work(&mgp->watchdog_work); - return; + if (ss->tx.req != ss->tx.done && + ss->tx.done == ss->watchdog_tx_done && + ss->watchdog_tx_req != ss->watchdog_tx_done) { + /* nic seems like it might be stuck.. */ + if (rx_pause_cnt != mgp->watchdog_pause) { + if (net_ratelimit()) + printk(KERN_WARNING "myri10ge %s:" + "TX paused, check link partner\n", + mgp->dev->name); + } else { + reset_needed = 1; + } } + ss->watchdog_tx_done = ss->tx.done; + ss->watchdog_tx_req = ss->tx.req; } - /* rearm timer */ - mod_timer(&mgp->watchdog_timer, - jiffies + myri10ge_watchdog_timeout * HZ); - ss->watchdog_tx_done = ss->tx.done; - ss->watchdog_tx_req = ss->tx.req; mgp->watchdog_pause = rx_pause_cnt; + + if (reset_needed) { + schedule_work(&mgp->watchdog_work); + } else { + /* rearm timer */ + mod_timer(&mgp->watchdog_timer, + jiffies + myri10ge_watchdog_timeout * HZ); + } +} + +static void myri10ge_free_slices(struct myri10ge_priv *mgp) +{ + struct myri10ge_slice_state *ss; + struct pci_dev *pdev = mgp->pdev; + size_t bytes; + int i; + + if (mgp->ss == NULL) + return; + + for (i = 0; i < mgp->num_slices; i++) { + ss = &mgp->ss[i]; + if (ss->rx_done.entry != NULL) { + bytes = mgp->max_intr_slots * + sizeof(*ss->rx_done.entry); + dma_free_coherent(&pdev->dev, bytes, + ss->rx_done.entry, ss->rx_done.bus); + ss->rx_done.entry = NULL; + } + if (ss->fw_stats != NULL) { + bytes = sizeof(*ss->fw_stats); + dma_free_coherent(&pdev->dev, bytes, + ss->fw_stats, ss->fw_stats_bus); + ss->fw_stats = NULL; + } + } + kfree(mgp->ss); + mgp->ss = NULL; +} + +static int myri10ge_alloc_slices(struct myri10ge_priv *mgp) +{ + struct myri10ge_slice_state *ss; + struct pci_dev *pdev = mgp->pdev; + size_t bytes; + int i; + + bytes = sizeof(*mgp->ss) * mgp->num_slices; + mgp->ss = kzalloc(bytes, GFP_KERNEL); + if (mgp->ss == NULL) { + return -ENOMEM; + } + + for (i = 0; i < mgp->num_slices; i++) { + ss = &mgp->ss[i]; + bytes = mgp->max_intr_slots * sizeof(*ss->rx_done.entry); + ss->rx_done.entry = dma_alloc_coherent(&pdev->dev, bytes, + &ss->rx_done.bus, + GFP_KERNEL); + if (ss->rx_done.entry == NULL) + goto abort; + memset(ss->rx_done.entry, 0, bytes); + bytes = sizeof(*ss->fw_stats); + ss->fw_stats = dma_alloc_coherent(&pdev->dev, bytes, + &ss->fw_stats_bus, + GFP_KERNEL); + if (ss->fw_stats == NULL) + goto abort; + ss->mgp = mgp; + ss->dev = mgp->dev; + netif_napi_add(ss->dev, &ss->napi, myri10ge_poll, + myri10ge_napi_weight); + } + return 0; +abort: + myri10ge_free_slices(mgp); + return -ENOMEM; +} + +/* + * This function determines the number of slices supported. + * The number slices is the minumum of the number of CPUS, + * the number of MSI-X irqs supported, the number of slices + * supported by the firmware + */ +static void myri10ge_probe_slices(struct myri10ge_priv *mgp) +{ + struct myri10ge_cmd cmd; + struct pci_dev *pdev = mgp->pdev; + char *old_fw; + int i, status, ncpus, msix_cap; + + mgp->num_slices = 1; + msix_cap = pci_find_capability(pdev, PCI_CAP_ID_MSIX); + ncpus = num_online_cpus(); + + if (myri10ge_max_slices == 1 || msix_cap == 0 || + (myri10ge_max_slices == -1 && ncpus < 2)) + return; + + /* try to load the slice aware rss firmware */ + old_fw = mgp->fw_name; + if (old_fw == myri10ge_fw_aligned) + mgp->fw_name = myri10ge_fw_rss_aligned; + else + mgp->fw_name = myri10ge_fw_rss_unaligned; + status = myri10ge_load_firmware(mgp, 0); + if (status != 0) { + dev_info(&pdev->dev, "Rss firmware not found\n"); + return; + } + + /* hit the board with a reset to ensure it is alive */ + memset(&cmd, 0, sizeof(cmd)); + status = myri10ge_send_cmd(mgp, MXGEFW_CMD_RESET, &cmd, 0); + if (status != 0) { + dev_err(&mgp->pdev->dev, "failed reset\n"); + goto abort_with_fw; + return; + } + + mgp->max_intr_slots = cmd.data0 / sizeof(struct mcp_slot); + + /* tell it the size of the interrupt queues */ + cmd.data0 = mgp->max_intr_slots * sizeof(struct mcp_slot); + status = myri10ge_send_cmd(mgp, MXGEFW_CMD_SET_INTRQ_SIZE, &cmd, 0); + if (status != 0) { + dev_err(&mgp->pdev->dev, "failed MXGEFW_CMD_SET_INTRQ_SIZE\n"); + goto abort_with_fw; + } + + /* ask the maximum number of slices it supports */ + status = myri10ge_send_cmd(mgp, MXGEFW_CMD_GET_MAX_RSS_QUEUES, &cmd, 0); + if (status != 0) + goto abort_with_fw; + else + mgp->num_slices = cmd.data0; + + /* Only allow multiple slices if MSI-X is usable */ + if (!myri10ge_msi) { + goto abort_with_fw; + } + + /* if the admin did not specify a limit to how many + * slices we should use, cap it automatically to the + * number of CPUs currently online */ + if (myri10ge_max_slices == -1) + myri10ge_max_slices = ncpus; + + if (mgp->num_slices > myri10ge_max_slices) + mgp->num_slices = myri10ge_max_slices; + + /* Now try to allocate as many MSI-X vectors as we have + * slices. We give up on MSI-X if we can only get a single + * vector. */ + + mgp->msix_vectors = kzalloc(mgp->num_slices * + sizeof(*mgp->msix_vectors), GFP_KERNEL); + if (mgp->msix_vectors == NULL) + goto disable_msix; + for (i = 0; i < mgp->num_slices; i++) { + mgp->msix_vectors[i].entry = i; + } + + while (mgp->num_slices > 1) { + /* make sure it is a power of two */ + while (!is_power_of_2(mgp->num_slices)) + mgp->num_slices--; + if (mgp->num_slices == 1) + goto disable_msix; + status = pci_enable_msix(pdev, mgp->msix_vectors, + mgp->num_slices); + if (status == 0) { + pci_disable_msix(pdev); + return; + } + if (status > 0) + mgp->num_slices = status; + else + goto disable_msix; + } + +disable_msix: + if (mgp->msix_vectors != NULL) { + kfree(mgp->msix_vectors); + mgp->msix_vectors = NULL; + } + +abort_with_fw: + mgp->num_slices = 1; + mgp->fw_name = old_fw; + myri10ge_load_firmware(mgp, 0); } static int myri10ge_probe(struct pci_dev *pdev, const struct pci_device_id *ent) @@ -3118,7 +3693,6 @@ static int myri10ge_probe(struct pci_dev *pdev, const struct pci_device_id *ent) struct net_device *netdev; struct myri10ge_priv *mgp; struct device *dev = &pdev->dev; - size_t bytes; int i; int status = -ENXIO; int dac_enabled; @@ -3133,7 +3707,6 @@ static int myri10ge_probe(struct pci_dev *pdev, const struct pci_device_id *ent) mgp = netdev_priv(netdev); mgp->dev = netdev; - netif_napi_add(netdev, &mgp->ss.napi, myri10ge_poll, myri10ge_napi_weight); mgp->pdev = pdev; mgp->csum_flag = MXGEFW_FLAGS_CKSUM; mgp->pause = myri10ge_flow_control; @@ -3179,11 +3752,6 @@ static int myri10ge_probe(struct pci_dev *pdev, const struct pci_device_id *ent) if (mgp->cmd == NULL) goto abort_with_netdev; - mgp->ss.fw_stats = dma_alloc_coherent(&pdev->dev, sizeof(*mgp->ss.fw_stats), - &mgp->ss.fw_stats_bus, GFP_KERNEL); - if (mgp->ss.fw_stats == NULL) - goto abort_with_cmd; - mgp->board_span = pci_resource_len(pdev, 0); mgp->iomem_base = pci_resource_start(pdev, 0); mgp->mtrr = -1; @@ -3220,28 +3788,28 @@ static int myri10ge_probe(struct pci_dev *pdev, const struct pci_device_id *ent) for (i = 0; i < ETH_ALEN; i++) netdev->dev_addr[i] = mgp->mac_addr[i]; - /* allocate rx done ring */ - bytes = mgp->max_intr_slots * sizeof(*mgp->ss.rx_done.entry); - mgp->ss.rx_done.entry = dma_alloc_coherent(&pdev->dev, bytes, - &mgp->ss.rx_done.bus, GFP_KERNEL); - if (mgp->ss.rx_done.entry == NULL) - goto abort_with_ioremap; - memset(mgp->ss.rx_done.entry, 0, bytes); - myri10ge_select_firmware(mgp); - status = myri10ge_load_firmware(mgp); + status = myri10ge_load_firmware(mgp, 1); if (status != 0) { dev_err(&pdev->dev, "failed to load firmware\n"); - goto abort_with_rx_done; + goto abort_with_ioremap; + } + myri10ge_probe_slices(mgp); + status = myri10ge_alloc_slices(mgp); + if (status != 0) { + dev_err(&pdev->dev, "failed to alloc slice state\n"); + goto abort_with_firmware; } status = myri10ge_reset(mgp); if (status != 0) { dev_err(&pdev->dev, "failed reset\n"); - goto abort_with_firmware; + goto abort_with_slices; } - +#ifdef CONFIG_DCA + myri10ge_setup_dca(mgp); +#endif pci_set_drvdata(pdev, mgp); if ((myri10ge_initial_mtu + ETH_HLEN) > MYRI10GE_MAX_ETHER_MTU) myri10ge_initial_mtu = MYRI10GE_MAX_ETHER_MTU - ETH_HLEN; @@ -3284,24 +3852,27 @@ static int myri10ge_probe(struct pci_dev *pdev, const struct pci_device_id *ent) dev_err(&pdev->dev, "register_netdev failed: %d\n", status); goto abort_with_state; } - dev_info(dev, "%s IRQ %d, tx bndry %d, fw %s, WC %s\n", - (mgp->msi_enabled ? "MSI" : "xPIC"), - netdev->irq, mgp->tx_boundary, mgp->fw_name, - (mgp->wc_enabled ? "Enabled" : "Disabled")); + if (mgp->msix_enabled) + dev_info(dev, "%d MSI-X IRQs, tx bndry %d, fw %s, WC %s\n", + mgp->num_slices, mgp->tx_boundary, mgp->fw_name, + (mgp->wc_enabled ? "Enabled" : "Disabled")); + else + dev_info(dev, "%s IRQ %d, tx bndry %d, fw %s, WC %s\n", + mgp->msi_enabled ? "MSI" : "xPIC", + netdev->irq, mgp->tx_boundary, mgp->fw_name, + (mgp->wc_enabled ? "Enabled" : "Disabled")); return 0; abort_with_state: pci_restore_state(pdev); +abort_with_slices: + myri10ge_free_slices(mgp); + abort_with_firmware: myri10ge_dummy_rdma(mgp, 0); -abort_with_rx_done: - bytes = mgp->max_intr_slots * sizeof(*mgp->ss.rx_done.entry); - dma_free_coherent(&pdev->dev, bytes, - mgp->ss.rx_done.entry, mgp->ss.rx_done.bus); - abort_with_ioremap: iounmap(mgp->sram); @@ -3310,10 +3881,6 @@ abort_with_wc: if (mgp->mtrr >= 0) mtrr_del(mgp->mtrr, mgp->iomem_base, mgp->board_span); #endif - dma_free_coherent(&pdev->dev, sizeof(*mgp->ss.fw_stats), - mgp->ss.fw_stats, mgp->ss.fw_stats_bus); - -abort_with_cmd: dma_free_coherent(&pdev->dev, sizeof(*mgp->cmd), mgp->cmd, mgp->cmd_bus); @@ -3334,7 +3901,6 @@ static void myri10ge_remove(struct pci_dev *pdev) { struct myri10ge_priv *mgp; struct net_device *netdev; - size_t bytes; mgp = pci_get_drvdata(pdev); if (mgp == NULL) @@ -3344,24 +3910,23 @@ static void myri10ge_remove(struct pci_dev *pdev) netdev = mgp->dev; unregister_netdev(netdev); +#ifdef CONFIG_DCA + myri10ge_teardown_dca(mgp); +#endif myri10ge_dummy_rdma(mgp, 0); /* avoid a memory leak */ pci_restore_state(pdev); - bytes = mgp->max_intr_slots * sizeof(*mgp->ss.rx_done.entry); - dma_free_coherent(&pdev->dev, bytes, - mgp->ss.rx_done.entry, mgp->ss.rx_done.bus); - iounmap(mgp->sram); #ifdef CONFIG_MTRR if (mgp->mtrr >= 0) mtrr_del(mgp->mtrr, mgp->iomem_base, mgp->board_span); #endif - dma_free_coherent(&pdev->dev, sizeof(*mgp->ss.fw_stats), - mgp->ss.fw_stats, mgp->ss.fw_stats_bus); - + myri10ge_free_slices(mgp); + if (mgp->msix_vectors != NULL) + kfree(mgp->msix_vectors); dma_free_coherent(&pdev->dev, sizeof(*mgp->cmd), mgp->cmd, mgp->cmd_bus); @@ -3390,10 +3955,42 @@ static struct pci_driver myri10ge_driver = { #endif }; +#ifdef CONFIG_DCA +static int +myri10ge_notify_dca(struct notifier_block *nb, unsigned long event, void *p) +{ + int err = driver_for_each_device(&myri10ge_driver.driver, + NULL, &event, + myri10ge_notify_dca_device); + + if (err) + return NOTIFY_BAD; + return NOTIFY_DONE; +} + +static struct notifier_block myri10ge_dca_notifier = { + .notifier_call = myri10ge_notify_dca, + .next = NULL, + .priority = 0, +}; +#endif /* CONFIG_DCA */ + static __init int myri10ge_init_module(void) { printk(KERN_INFO "%s: Version %s\n", myri10ge_driver.name, MYRI10GE_VERSION_STR); + + if (myri10ge_rss_hash > MXGEFW_RSS_HASH_TYPE_SRC_PORT || + myri10ge_rss_hash < MXGEFW_RSS_HASH_TYPE_IPV4) { + printk(KERN_ERR + "%s: Illegal rssh hash type %d, defaulting to source port\n", + myri10ge_driver.name, myri10ge_rss_hash); + myri10ge_rss_hash = MXGEFW_RSS_HASH_TYPE_SRC_PORT; + } +#ifdef CONFIG_DCA + dca_register_notify(&myri10ge_dca_notifier); +#endif + return pci_register_driver(&myri10ge_driver); } @@ -3401,6 +3998,9 @@ module_init(myri10ge_init_module); static __exit void myri10ge_cleanup_module(void) { +#ifdef CONFIG_DCA + dca_unregister_notify(&myri10ge_dca_notifier); +#endif pci_unregister_driver(&myri10ge_driver); } diff --git a/drivers/net/natsemi.c b/drivers/net/natsemi.c index 46119bb3770a..b238ed0e8ace 100644 --- a/drivers/net/natsemi.c +++ b/drivers/net/natsemi.c @@ -664,7 +664,7 @@ static ssize_t natsemi_show_##_name(struct device *dev, \ NATSEMI_ATTR(dspcfg_workaround); static ssize_t natsemi_show_dspcfg_workaround(struct device *dev, - struct device_attribute *attr, + struct device_attribute *attr, char *buf) { struct netdev_private *np = netdev_priv(to_net_dev(dev)); @@ -687,7 +687,7 @@ static ssize_t natsemi_set_dspcfg_workaround(struct device *dev, || !strncmp("0", buf, count - 1)) new_setting = 0; else - return count; + return count; spin_lock_irqsave(&np->lock, flags); diff --git a/drivers/net/ne.c b/drivers/net/ne.c index 874d291cbaed..14126973bd12 100644 --- a/drivers/net/ne.c +++ b/drivers/net/ne.c @@ -217,7 +217,7 @@ static int __init do_ne_probe(struct net_device *dev) #ifndef MODULE struct net_device * __init ne_probe(int unit) { - struct net_device *dev = alloc_ei_netdev(); + struct net_device *dev = alloc_eip_netdev(); int err; if (!dev) @@ -490,7 +490,7 @@ static int __init ne_probe1(struct net_device *dev, unsigned long ioaddr) /* Snarf the interrupt now. There's no point in waiting since we cannot share and the board will usually be enabled. */ - ret = request_irq(dev->irq, ei_interrupt, 0, name, dev); + ret = request_irq(dev->irq, eip_interrupt, 0, name, dev); if (ret) { printk (" unable to get IRQ %d (errno=%d).\n", dev->irq, ret); goto err_out; @@ -534,7 +534,7 @@ static int __init ne_probe1(struct net_device *dev, unsigned long ioaddr) dev->open = &ne_open; dev->stop = &ne_close; #ifdef CONFIG_NET_POLL_CONTROLLER - dev->poll_controller = ei_poll; + dev->poll_controller = eip_poll; #endif NS8390_init(dev, 0); @@ -554,7 +554,7 @@ err_out: static int ne_open(struct net_device *dev) { - ei_open(dev); + eip_open(dev); return 0; } @@ -562,7 +562,7 @@ static int ne_close(struct net_device *dev) { if (ei_debug > 1) printk(KERN_DEBUG "%s: Shutting down ethercard.\n", dev->name); - ei_close(dev); + eip_close(dev); return 0; } @@ -814,7 +814,7 @@ static int __init ne_drv_probe(struct platform_device *pdev) if (!res || irq < 0) return -ENODEV; - dev = alloc_ei_netdev(); + dev = alloc_eip_netdev(); if (!dev) return -ENOMEM; dev->irq = irq; @@ -912,7 +912,7 @@ int __init init_module(void) int plat_found = !ne_init(); for (this_dev = 0; this_dev < MAX_NE_CARDS; this_dev++) { - struct net_device *dev = alloc_ei_netdev(); + struct net_device *dev = alloc_eip_netdev(); if (!dev) break; dev->irq = irq[this_dev]; diff --git a/drivers/net/ne2.c b/drivers/net/ne2.c index f4cd8c7e81ba..8f7256346922 100644 --- a/drivers/net/ne2.c +++ b/drivers/net/ne2.c @@ -280,7 +280,7 @@ static int __init do_ne2_probe(struct net_device *dev) #ifndef MODULE struct net_device * __init ne2_probe(int unit) { - struct net_device *dev = alloc_ei_netdev(); + struct net_device *dev = alloc_eip_netdev(); int err; if (!dev) @@ -457,7 +457,7 @@ static int __init ne2_probe1(struct net_device *dev, int slot) /* Snarf the interrupt now. There's no point in waiting since we cannot share and the board will usually be enabled. */ - retval = request_irq(dev->irq, ei_interrupt, 0, DRV_NAME, dev); + retval = request_irq(dev->irq, eip_interrupt, 0, DRV_NAME, dev); if (retval) { printk (" unable to get IRQ %d (irqval=%d).\n", dev->irq, retval); @@ -497,9 +497,9 @@ static int __init ne2_probe1(struct net_device *dev, int slot) dev->open = &ne_open; dev->stop = &ne_close; #ifdef CONFIG_NET_POLL_CONTROLLER - dev->poll_controller = ei_poll; + dev->poll_controller = eip_poll; #endif - NS8390_init(dev, 0); + NS8390p_init(dev, 0); retval = register_netdev(dev); if (retval) @@ -515,7 +515,7 @@ out: static int ne_open(struct net_device *dev) { - ei_open(dev); + eip_open(dev); return 0; } @@ -523,7 +523,7 @@ static int ne_close(struct net_device *dev) { if (ei_debug > 1) printk("%s: Shutting down ethercard.\n", dev->name); - ei_close(dev); + eip_close(dev); return 0; } @@ -748,7 +748,7 @@ retry: if (time_after(jiffies, dma_start + 2*HZ/100)) { /* 20ms */ printk("%s: timeout waiting for Tx RDC.\n", dev->name); ne_reset_8390(dev); - NS8390_init(dev,1); + NS8390p_init(dev, 1); break; } @@ -781,7 +781,7 @@ int __init init_module(void) int this_dev, found = 0; for (this_dev = 0; this_dev < MAX_NE_CARDS; this_dev++) { - dev = alloc_ei_netdev(); + dev = alloc_eip_netdev(); if (!dev) break; dev->irq = irq[this_dev]; diff --git a/drivers/net/netconsole.c b/drivers/net/netconsole.c index 387a13395015..e13966bb5f77 100644 --- a/drivers/net/netconsole.c +++ b/drivers/net/netconsole.c @@ -585,9 +585,8 @@ static struct config_item_type netconsole_target_type = { * Group operations and type for netconsole_subsys. */ -static int make_netconsole_target(struct config_group *group, - const char *name, - struct config_item **new_item) +static struct config_item *make_netconsole_target(struct config_group *group, + const char *name) { unsigned long flags; struct netconsole_target *nt; @@ -599,7 +598,7 @@ static int make_netconsole_target(struct config_group *group, nt = kzalloc(sizeof(*nt), GFP_KERNEL); if (!nt) { printk(KERN_ERR "netconsole: failed to allocate memory\n"); - return -ENOMEM; + return ERR_PTR(-ENOMEM); } nt->np.name = "netconsole"; @@ -616,8 +615,7 @@ static int make_netconsole_target(struct config_group *group, list_add(&nt->list, &target_list); spin_unlock_irqrestore(&target_list_lock, flags); - *new_item = &nt->item; - return 0; + return &nt->item; } static void drop_netconsole_target(struct config_group *group, diff --git a/drivers/net/niu.c b/drivers/net/niu.c index 918f802fe089..8ee7d7bb951b 100644 --- a/drivers/net/niu.c +++ b/drivers/net/niu.c @@ -3236,10 +3236,14 @@ static int release_tx_packet(struct niu *np, struct tx_ring_info *rp, int idx) static void niu_tx_work(struct niu *np, struct tx_ring_info *rp) { + struct netdev_queue *txq; u16 pkt_cnt, tmp; - int cons; + int cons, index; u64 cs; + index = (rp - np->tx_rings); + txq = netdev_get_tx_queue(np->dev, index); + cs = rp->tx_cs; if (unlikely(!(cs & (TX_CS_MK | TX_CS_MMK)))) goto out; @@ -3262,13 +3266,13 @@ static void niu_tx_work(struct niu *np, struct tx_ring_info *rp) smp_mb(); out: - if (unlikely(netif_queue_stopped(np->dev) && + if (unlikely(netif_tx_queue_stopped(txq) && (niu_tx_avail(rp) > NIU_TX_WAKEUP_THRESH(rp)))) { - netif_tx_lock(np->dev); - if (netif_queue_stopped(np->dev) && + __netif_tx_lock(txq, smp_processor_id()); + if (netif_tx_queue_stopped(txq) && (niu_tx_avail(rp) > NIU_TX_WAKEUP_THRESH(rp))) - netif_wake_queue(np->dev); - netif_tx_unlock(np->dev); + netif_tx_wake_queue(txq); + __netif_tx_unlock(txq); } } @@ -4061,6 +4065,8 @@ static int niu_alloc_channels(struct niu *np) np->num_rx_rings = parent->rxchan_per_port[port]; np->num_tx_rings = parent->txchan_per_port[port]; + np->dev->real_num_tx_queues = np->num_tx_rings; + np->rx_rings = kzalloc(np->num_rx_rings * sizeof(struct rx_ring_info), GFP_KERNEL); err = -ENOMEM; @@ -5686,7 +5692,7 @@ static int niu_open(struct net_device *dev) goto out_free_irq; } - netif_start_queue(dev); + netif_tx_start_all_queues(dev); if (np->link_config.loopback_mode != LOOPBACK_DISABLED) netif_carrier_on(dev); @@ -5710,7 +5716,7 @@ static void niu_full_shutdown(struct niu *np, struct net_device *dev) cancel_work_sync(&np->reset_task); niu_disable_napi(np); - netif_stop_queue(dev); + netif_tx_stop_all_queues(dev); del_timer_sync(&np->timer); @@ -5971,7 +5977,7 @@ static void niu_netif_start(struct niu *np) * so long as all callers are assured to have free tx slots * (such as after niu_init_hw). */ - netif_wake_queue(np->dev); + netif_tx_wake_all_queues(np->dev); niu_enable_napi(np); @@ -6097,15 +6103,11 @@ static u64 niu_compute_tx_flags(struct sk_buff *skb, struct ethhdr *ehdr, return ret; } -static struct tx_ring_info *tx_ring_select(struct niu *np, struct sk_buff *skb) -{ - return &np->tx_rings[0]; -} - static int niu_start_xmit(struct sk_buff *skb, struct net_device *dev) { struct niu *np = netdev_priv(dev); unsigned long align, headroom; + struct netdev_queue *txq; struct tx_ring_info *rp; struct tx_pkt_hdr *tp; unsigned int len, nfg; @@ -6113,10 +6115,12 @@ static int niu_start_xmit(struct sk_buff *skb, struct net_device *dev) int prod, i, tlen; u64 mapping, mrk; - rp = tx_ring_select(np, skb); + i = skb_get_queue_mapping(skb); + rp = &np->tx_rings[i]; + txq = netdev_get_tx_queue(dev, i); if (niu_tx_avail(rp) <= (skb_shinfo(skb)->nr_frags + 1)) { - netif_stop_queue(dev); + netif_tx_stop_queue(txq); dev_err(np->device, PFX "%s: BUG! Tx ring full when " "queue awake!\n", dev->name); rp->tx_errors++; @@ -6215,9 +6219,9 @@ static int niu_start_xmit(struct sk_buff *skb, struct net_device *dev) nw64(TX_RING_KICK(rp->tx_channel), rp->wrap_bit | (prod << 3)); if (unlikely(niu_tx_avail(rp) <= (MAX_SKB_FRAGS + 1))) { - netif_stop_queue(dev); + netif_tx_stop_queue(txq); if (niu_tx_avail(rp) > NIU_TX_WAKEUP_THRESH(rp)) - netif_wake_queue(dev); + netif_tx_wake_queue(txq); } dev->trans_start = jiffies; @@ -6275,7 +6279,7 @@ static int niu_change_mtu(struct net_device *dev, int new_mtu) spin_unlock_irq(&np->lock); if (!err) { - netif_start_queue(dev); + netif_tx_start_all_queues(dev); if (np->link_config.loopback_mode != LOOPBACK_DISABLED) netif_carrier_on(dev); @@ -6385,6 +6389,162 @@ static int niu_get_eeprom(struct net_device *dev, return 0; } +static int niu_ethflow_to_class(int flow_type, u64 *class) +{ + switch (flow_type) { + case TCP_V4_FLOW: + *class = CLASS_CODE_TCP_IPV4; + break; + case UDP_V4_FLOW: + *class = CLASS_CODE_UDP_IPV4; + break; + case AH_ESP_V4_FLOW: + *class = CLASS_CODE_AH_ESP_IPV4; + break; + case SCTP_V4_FLOW: + *class = CLASS_CODE_SCTP_IPV4; + break; + case TCP_V6_FLOW: + *class = CLASS_CODE_TCP_IPV6; + break; + case UDP_V6_FLOW: + *class = CLASS_CODE_UDP_IPV6; + break; + case AH_ESP_V6_FLOW: + *class = CLASS_CODE_AH_ESP_IPV6; + break; + case SCTP_V6_FLOW: + *class = CLASS_CODE_SCTP_IPV6; + break; + default: + return -1; + } + + return 1; +} + +static u64 niu_flowkey_to_ethflow(u64 flow_key) +{ + u64 ethflow = 0; + + if (flow_key & FLOW_KEY_PORT) + ethflow |= RXH_DEV_PORT; + if (flow_key & FLOW_KEY_L2DA) + ethflow |= RXH_L2DA; + if (flow_key & FLOW_KEY_VLAN) + ethflow |= RXH_VLAN; + if (flow_key & FLOW_KEY_IPSA) + ethflow |= RXH_IP_SRC; + if (flow_key & FLOW_KEY_IPDA) + ethflow |= RXH_IP_DST; + if (flow_key & FLOW_KEY_PROTO) + ethflow |= RXH_L3_PROTO; + if (flow_key & (FLOW_KEY_L4_BYTE12 << FLOW_KEY_L4_0_SHIFT)) + ethflow |= RXH_L4_B_0_1; + if (flow_key & (FLOW_KEY_L4_BYTE12 << FLOW_KEY_L4_1_SHIFT)) + ethflow |= RXH_L4_B_2_3; + + return ethflow; + +} + +static int niu_ethflow_to_flowkey(u64 ethflow, u64 *flow_key) +{ + u64 key = 0; + + if (ethflow & RXH_DEV_PORT) + key |= FLOW_KEY_PORT; + if (ethflow & RXH_L2DA) + key |= FLOW_KEY_L2DA; + if (ethflow & RXH_VLAN) + key |= FLOW_KEY_VLAN; + if (ethflow & RXH_IP_SRC) + key |= FLOW_KEY_IPSA; + if (ethflow & RXH_IP_DST) + key |= FLOW_KEY_IPDA; + if (ethflow & RXH_L3_PROTO) + key |= FLOW_KEY_PROTO; + if (ethflow & RXH_L4_B_0_1) + key |= (FLOW_KEY_L4_BYTE12 << FLOW_KEY_L4_0_SHIFT); + if (ethflow & RXH_L4_B_2_3) + key |= (FLOW_KEY_L4_BYTE12 << FLOW_KEY_L4_1_SHIFT); + + *flow_key = key; + + return 1; + +} + +static int niu_get_hash_opts(struct net_device *dev, struct ethtool_rxnfc *cmd) +{ + struct niu *np = netdev_priv(dev); + u64 class; + + cmd->data = 0; + + if (!niu_ethflow_to_class(cmd->flow_type, &class)) + return -EINVAL; + + if (np->parent->tcam_key[class - CLASS_CODE_USER_PROG1] & + TCAM_KEY_DISC) + cmd->data = RXH_DISCARD; + else + + cmd->data = niu_flowkey_to_ethflow(np->parent->flow_key[class - + CLASS_CODE_USER_PROG1]); + return 0; +} + +static int niu_set_hash_opts(struct net_device *dev, struct ethtool_rxnfc *cmd) +{ + struct niu *np = netdev_priv(dev); + u64 class; + u64 flow_key = 0; + unsigned long flags; + + if (!niu_ethflow_to_class(cmd->flow_type, &class)) + return -EINVAL; + + if (class < CLASS_CODE_USER_PROG1 || + class > CLASS_CODE_SCTP_IPV6) + return -EINVAL; + + if (cmd->data & RXH_DISCARD) { + niu_lock_parent(np, flags); + flow_key = np->parent->tcam_key[class - + CLASS_CODE_USER_PROG1]; + flow_key |= TCAM_KEY_DISC; + nw64(TCAM_KEY(class - CLASS_CODE_USER_PROG1), flow_key); + np->parent->tcam_key[class - CLASS_CODE_USER_PROG1] = flow_key; + niu_unlock_parent(np, flags); + return 0; + } else { + /* Discard was set before, but is not set now */ + if (np->parent->tcam_key[class - CLASS_CODE_USER_PROG1] & + TCAM_KEY_DISC) { + niu_lock_parent(np, flags); + flow_key = np->parent->tcam_key[class - + CLASS_CODE_USER_PROG1]; + flow_key &= ~TCAM_KEY_DISC; + nw64(TCAM_KEY(class - CLASS_CODE_USER_PROG1), + flow_key); + np->parent->tcam_key[class - CLASS_CODE_USER_PROG1] = + flow_key; + niu_unlock_parent(np, flags); + } + } + + if (!niu_ethflow_to_flowkey(cmd->data, &flow_key)) + return -EINVAL; + + niu_lock_parent(np, flags); + nw64(FLOW_KEY(class - CLASS_CODE_USER_PROG1), flow_key); + np->parent->flow_key[class - CLASS_CODE_USER_PROG1] = flow_key; + niu_unlock_parent(np, flags); + + return 0; +} + static const struct { const char string[ETH_GSTRING_LEN]; } niu_xmac_stat_keys[] = { @@ -6615,6 +6775,8 @@ static const struct ethtool_ops niu_ethtool_ops = { .get_stats_count = niu_get_stats_count, .get_ethtool_stats = niu_get_ethtool_stats, .phys_id = niu_phys_id, + .get_rxhash = niu_get_hash_opts, + .set_rxhash = niu_set_hash_opts, }; static int niu_ldg_assign_ldn(struct niu *np, struct niu_parent *parent, @@ -8374,9 +8536,10 @@ static struct net_device * __devinit niu_alloc_and_init( struct of_device *op, const struct niu_ops *ops, u8 port) { - struct net_device *dev = alloc_etherdev(sizeof(struct niu)); + struct net_device *dev; struct niu *np; + dev = alloc_etherdev_mq(sizeof(struct niu), NIU_NUM_TXCHAN); if (!dev) { dev_err(gen_dev, PFX "Etherdev alloc failed, aborting.\n"); return NULL; diff --git a/drivers/net/niu.h b/drivers/net/niu.h index 12fd570b9423..c6fa883daa22 100644 --- a/drivers/net/niu.h +++ b/drivers/net/niu.h @@ -281,7 +281,7 @@ #define XMAC_ADDR1 0x000a8UL #define XMAC_ADDR1_ADDR1 0x000000000000ffffULL -#define XMAC_ADDR2 0x000b0UL +#define XMAC_ADDR2 0x000b0UL #define XMAC_ADDR2_ADDR2 0x000000000000ffffULL #define XMAC_ADDR_CMPEN 0x00208UL diff --git a/drivers/net/ns83820.c b/drivers/net/ns83820.c index b42c05f84be1..ff449619f047 100644 --- a/drivers/net/ns83820.c +++ b/drivers/net/ns83820.c @@ -585,16 +585,13 @@ static inline int rx_refill(struct net_device *ndev, gfp_t gfp) for (i=0; i<NR_RX_DESC; i++) { struct sk_buff *skb; long res; + /* extra 16 bytes for alignment */ - skb = __dev_alloc_skb(REAL_RX_BUF_SIZE+16, gfp); + skb = __netdev_alloc_skb(ndev, REAL_RX_BUF_SIZE+16, gfp); if (unlikely(!skb)) break; - res = (long)skb->data & 0xf; - res = 0x10 - res; - res &= 0xf; - skb_reserve(skb, res); - + skb_reserve(skb, skb->data - PTR_ALIGN(skb->data, 16)); if (gfp != GFP_ATOMIC) spin_lock_irqsave(&dev->rx_info.lock, flags); res = ns83820_add_rx_skb(dev, skb); diff --git a/drivers/net/pci-skeleton.c b/drivers/net/pci-skeleton.c index fffc49befe04..53451c3b2c0d 100644 --- a/drivers/net/pci-skeleton.c +++ b/drivers/net/pci-skeleton.c @@ -1739,7 +1739,6 @@ static int netdrv_close (struct net_device *dev) spin_unlock_irqrestore (&tp->lock, flags); - synchronize_irq (dev->irq); free_irq (dev->irq, dev); netdrv_tx_clear (dev); diff --git a/drivers/net/pcmcia/3c574_cs.c b/drivers/net/pcmcia/3c574_cs.c index 3b78a3819bb3..7112fd5e0e1b 100644 --- a/drivers/net/pcmcia/3c574_cs.c +++ b/drivers/net/pcmcia/3c574_cs.c @@ -208,7 +208,6 @@ enum Window4 { /* Window 4: Xcvr/media bits. */ struct el3_private { struct pcmcia_device *p_dev; dev_node_t node; - struct net_device_stats stats; u16 advertising, partner; /* NWay media advertisement */ unsigned char phys; /* MII device address */ unsigned int autoselect:1, default_media:3; /* Read from the EEPROM/Wn3_Config. */ @@ -741,12 +740,11 @@ static int el3_open(struct net_device *dev) static void el3_tx_timeout(struct net_device *dev) { - struct el3_private *lp = netdev_priv(dev); unsigned int ioaddr = dev->base_addr; printk(KERN_NOTICE "%s: Transmit timed out!\n", dev->name); dump_status(dev); - lp->stats.tx_errors++; + dev->stats.tx_errors++; dev->trans_start = jiffies; /* Issue TX_RESET and TX_START commands. */ tc574_wait_for_completion(dev, TxReset); @@ -756,7 +754,6 @@ static void el3_tx_timeout(struct net_device *dev) static void pop_tx_status(struct net_device *dev) { - struct el3_private *lp = netdev_priv(dev); unsigned int ioaddr = dev->base_addr; int i; @@ -772,7 +769,7 @@ static void pop_tx_status(struct net_device *dev) DEBUG(1, "%s: transmit error: status 0x%02x\n", dev->name, tx_status); outw(TxEnable, ioaddr + EL3_CMD); - lp->stats.tx_aborted_errors++; + dev->stats.tx_aborted_errors++; } outb(0x00, ioaddr + TxStatus); /* Pop the status stack. */ } @@ -987,7 +984,7 @@ static struct net_device_stats *el3_get_stats(struct net_device *dev) update_stats(dev); spin_unlock_irqrestore(&lp->window_lock, flags); } - return &lp->stats; + return &dev->stats; } /* Update statistics. @@ -996,7 +993,6 @@ static struct net_device_stats *el3_get_stats(struct net_device *dev) */ static void update_stats(struct net_device *dev) { - struct el3_private *lp = netdev_priv(dev); unsigned int ioaddr = dev->base_addr; u8 rx, tx, up; @@ -1008,15 +1004,15 @@ static void update_stats(struct net_device *dev) /* Unlike the 3c509 we need not turn off stats updates while reading. */ /* Switch to the stats window, and read everything. */ EL3WINDOW(6); - lp->stats.tx_carrier_errors += inb(ioaddr + 0); - lp->stats.tx_heartbeat_errors += inb(ioaddr + 1); + dev->stats.tx_carrier_errors += inb(ioaddr + 0); + dev->stats.tx_heartbeat_errors += inb(ioaddr + 1); /* Multiple collisions. */ inb(ioaddr + 2); - lp->stats.collisions += inb(ioaddr + 3); - lp->stats.tx_window_errors += inb(ioaddr + 4); - lp->stats.rx_fifo_errors += inb(ioaddr + 5); - lp->stats.tx_packets += inb(ioaddr + 6); + dev->stats.collisions += inb(ioaddr + 3); + dev->stats.tx_window_errors += inb(ioaddr + 4); + dev->stats.rx_fifo_errors += inb(ioaddr + 5); + dev->stats.tx_packets += inb(ioaddr + 6); up = inb(ioaddr + 9); - lp->stats.tx_packets += (up&0x30) << 4; + dev->stats.tx_packets += (up&0x30) << 4; /* Rx packets */ inb(ioaddr + 7); /* Tx deferrals */ inb(ioaddr + 8); rx = inw(ioaddr + 10); @@ -1026,14 +1022,13 @@ static void update_stats(struct net_device *dev) /* BadSSD */ inb(ioaddr + 12); up = inb(ioaddr + 13); - lp->stats.tx_bytes += tx + ((up & 0xf0) << 12); + dev->stats.tx_bytes += tx + ((up & 0xf0) << 12); EL3WINDOW(1); } static int el3_rx(struct net_device *dev, int worklimit) { - struct el3_private *lp = netdev_priv(dev); unsigned int ioaddr = dev->base_addr; short rx_status; @@ -1043,14 +1038,14 @@ static int el3_rx(struct net_device *dev, int worklimit) (--worklimit >= 0)) { if (rx_status & 0x4000) { /* Error, update stats. */ short error = rx_status & 0x3800; - lp->stats.rx_errors++; + dev->stats.rx_errors++; switch (error) { - case 0x0000: lp->stats.rx_over_errors++; break; - case 0x0800: lp->stats.rx_length_errors++; break; - case 0x1000: lp->stats.rx_frame_errors++; break; - case 0x1800: lp->stats.rx_length_errors++; break; - case 0x2000: lp->stats.rx_frame_errors++; break; - case 0x2800: lp->stats.rx_crc_errors++; break; + case 0x0000: dev->stats.rx_over_errors++; break; + case 0x0800: dev->stats.rx_length_errors++; break; + case 0x1000: dev->stats.rx_frame_errors++; break; + case 0x1800: dev->stats.rx_length_errors++; break; + case 0x2000: dev->stats.rx_frame_errors++; break; + case 0x2800: dev->stats.rx_crc_errors++; break; } } else { short pkt_len = rx_status & 0x7ff; @@ -1067,12 +1062,12 @@ static int el3_rx(struct net_device *dev, int worklimit) skb->protocol = eth_type_trans(skb, dev); netif_rx(skb); dev->last_rx = jiffies; - lp->stats.rx_packets++; - lp->stats.rx_bytes += pkt_len; + dev->stats.rx_packets++; + dev->stats.rx_bytes += pkt_len; } else { DEBUG(1, "%s: couldn't allocate a sk_buff of" " size %d.\n", dev->name, pkt_len); - lp->stats.rx_dropped++; + dev->stats.rx_dropped++; } } tc574_wait_for_completion(dev, RxDiscard); diff --git a/drivers/net/pcmcia/3c589_cs.c b/drivers/net/pcmcia/3c589_cs.c index 1b1abb19c911..549a64558420 100644 --- a/drivers/net/pcmcia/3c589_cs.c +++ b/drivers/net/pcmcia/3c589_cs.c @@ -107,7 +107,6 @@ enum RxFilter { struct el3_private { struct pcmcia_device *p_dev; dev_node_t node; - struct net_device_stats stats; /* For transceiver monitoring */ struct timer_list media; u16 media_status; @@ -566,12 +565,11 @@ static int el3_open(struct net_device *dev) static void el3_tx_timeout(struct net_device *dev) { - struct el3_private *lp = netdev_priv(dev); unsigned int ioaddr = dev->base_addr; printk(KERN_WARNING "%s: Transmit timed out!\n", dev->name); dump_status(dev); - lp->stats.tx_errors++; + dev->stats.tx_errors++; dev->trans_start = jiffies; /* Issue TX_RESET and TX_START commands. */ tc589_wait_for_completion(dev, TxReset); @@ -581,7 +579,6 @@ static void el3_tx_timeout(struct net_device *dev) static void pop_tx_status(struct net_device *dev) { - struct el3_private *lp = netdev_priv(dev); unsigned int ioaddr = dev->base_addr; int i; @@ -596,7 +593,7 @@ static void pop_tx_status(struct net_device *dev) DEBUG(1, "%s: transmit error: status 0x%02x\n", dev->name, tx_status); outw(TxEnable, ioaddr + EL3_CMD); - lp->stats.tx_aborted_errors++; + dev->stats.tx_aborted_errors++; } outb(0x00, ioaddr + TX_STATUS); /* Pop the status stack. */ } @@ -614,7 +611,7 @@ static int el3_start_xmit(struct sk_buff *skb, struct net_device *dev) spin_lock_irqsave(&priv->lock, flags); - priv->stats.tx_bytes += skb->len; + dev->stats.tx_bytes += skb->len; /* Put out the doubleword header... */ outw(skb->len, ioaddr + TX_FIFO); @@ -764,7 +761,7 @@ static void media_check(unsigned long arg) outw(StatsDisable, ioaddr + EL3_CMD); errs = inb(ioaddr + 0); outw(StatsEnable, ioaddr + EL3_CMD); - lp->stats.tx_carrier_errors += errs; + dev->stats.tx_carrier_errors += errs; if (errs || (lp->media_status & 0x0010)) media |= 0x0010; } @@ -814,7 +811,7 @@ static struct net_device_stats *el3_get_stats(struct net_device *dev) update_stats(dev); spin_unlock_irqrestore(&lp->lock, flags); } - return &lp->stats; + return &dev->stats; } /* @@ -827,7 +824,6 @@ static struct net_device_stats *el3_get_stats(struct net_device *dev) */ static void update_stats(struct net_device *dev) { - struct el3_private *lp = netdev_priv(dev); unsigned int ioaddr = dev->base_addr; DEBUG(2, "%s: updating the statistics.\n", dev->name); @@ -835,13 +831,13 @@ static void update_stats(struct net_device *dev) outw(StatsDisable, ioaddr + EL3_CMD); /* Switch to the stats window, and read everything. */ EL3WINDOW(6); - lp->stats.tx_carrier_errors += inb(ioaddr + 0); - lp->stats.tx_heartbeat_errors += inb(ioaddr + 1); + dev->stats.tx_carrier_errors += inb(ioaddr + 0); + dev->stats.tx_heartbeat_errors += inb(ioaddr + 1); /* Multiple collisions. */ inb(ioaddr + 2); - lp->stats.collisions += inb(ioaddr + 3); - lp->stats.tx_window_errors += inb(ioaddr + 4); - lp->stats.rx_fifo_errors += inb(ioaddr + 5); - lp->stats.tx_packets += inb(ioaddr + 6); + dev->stats.collisions += inb(ioaddr + 3); + dev->stats.tx_window_errors += inb(ioaddr + 4); + dev->stats.rx_fifo_errors += inb(ioaddr + 5); + dev->stats.tx_packets += inb(ioaddr + 6); /* Rx packets */ inb(ioaddr + 7); /* Tx deferrals */ inb(ioaddr + 8); /* Rx octets */ inw(ioaddr + 10); @@ -854,7 +850,6 @@ static void update_stats(struct net_device *dev) static int el3_rx(struct net_device *dev) { - struct el3_private *lp = netdev_priv(dev); unsigned int ioaddr = dev->base_addr; int worklimit = 32; short rx_status; @@ -865,14 +860,14 @@ static int el3_rx(struct net_device *dev) (--worklimit >= 0)) { if (rx_status & 0x4000) { /* Error, update stats. */ short error = rx_status & 0x3800; - lp->stats.rx_errors++; + dev->stats.rx_errors++; switch (error) { - case 0x0000: lp->stats.rx_over_errors++; break; - case 0x0800: lp->stats.rx_length_errors++; break; - case 0x1000: lp->stats.rx_frame_errors++; break; - case 0x1800: lp->stats.rx_length_errors++; break; - case 0x2000: lp->stats.rx_frame_errors++; break; - case 0x2800: lp->stats.rx_crc_errors++; break; + case 0x0000: dev->stats.rx_over_errors++; break; + case 0x0800: dev->stats.rx_length_errors++; break; + case 0x1000: dev->stats.rx_frame_errors++; break; + case 0x1800: dev->stats.rx_length_errors++; break; + case 0x2000: dev->stats.rx_frame_errors++; break; + case 0x2800: dev->stats.rx_crc_errors++; break; } } else { short pkt_len = rx_status & 0x7ff; @@ -889,12 +884,12 @@ static int el3_rx(struct net_device *dev) skb->protocol = eth_type_trans(skb, dev); netif_rx(skb); dev->last_rx = jiffies; - lp->stats.rx_packets++; - lp->stats.rx_bytes += pkt_len; + dev->stats.rx_packets++; + dev->stats.rx_bytes += pkt_len; } else { DEBUG(1, "%s: couldn't allocate a sk_buff of" " size %d.\n", dev->name, pkt_len); - lp->stats.rx_dropped++; + dev->stats.rx_dropped++; } } /* Pop the top of the Rx FIFO */ @@ -929,7 +924,7 @@ static int el3_close(struct net_device *dev) DEBUG(1, "%s: shutting down ethercard.\n", dev->name); if (pcmcia_dev_present(link)) { - /* Turn off statistics ASAP. We update lp->stats below. */ + /* Turn off statistics ASAP. We update dev->stats below. */ outw(StatsDisable, ioaddr + EL3_CMD); /* Disable the receiver and transmitter. */ diff --git a/drivers/net/pcmcia/axnet_cs.c b/drivers/net/pcmcia/axnet_cs.c index 70d012e90dcf..3f682d49a4e6 100644 --- a/drivers/net/pcmcia/axnet_cs.c +++ b/drivers/net/pcmcia/axnet_cs.c @@ -1023,7 +1023,7 @@ static void ei_tx_timeout(struct net_device *dev) int txsr, isr, tickssofar = jiffies - dev->trans_start; unsigned long flags; - ei_local->stat.tx_errors++; + dev->stats.tx_errors++; spin_lock_irqsave(&ei_local->page_lock, flags); txsr = inb(e8390_base+EN0_TSR); @@ -1034,7 +1034,7 @@ static void ei_tx_timeout(struct net_device *dev) dev->name, (txsr & ENTSR_ABT) ? "excess collisions." : (isr) ? "lost interrupt?" : "cable problem?", txsr, isr, tickssofar); - if (!isr && !ei_local->stat.tx_packets) + if (!isr && !dev->stats.tx_packets) { /* The 8390 probably hasn't gotten on the cable yet. */ ei_local->interface_num ^= 1; /* Try a different xcvr. */ @@ -1124,7 +1124,7 @@ static int ei_start_xmit(struct sk_buff *skb, struct net_device *dev) netif_stop_queue(dev); outb_p(ENISR_ALL, e8390_base + EN0_IMR); spin_unlock_irqrestore(&ei_local->page_lock, flags); - ei_local->stat.tx_errors++; + dev->stats.tx_errors++; return 1; } @@ -1172,7 +1172,7 @@ static int ei_start_xmit(struct sk_buff *skb, struct net_device *dev) spin_unlock_irqrestore(&ei_local->page_lock, flags); dev_kfree_skb (skb); - ei_local->stat.tx_bytes += send_length; + dev->stats.tx_bytes += send_length; return 0; } @@ -1264,9 +1264,9 @@ static irqreturn_t ax_interrupt(int irq, void *dev_id) if (interrupts & ENISR_COUNTERS) { - ei_local->stat.rx_frame_errors += inb_p(e8390_base + EN0_COUNTER0); - ei_local->stat.rx_crc_errors += inb_p(e8390_base + EN0_COUNTER1); - ei_local->stat.rx_missed_errors+= inb_p(e8390_base + EN0_COUNTER2); + dev->stats.rx_frame_errors += inb_p(e8390_base + EN0_COUNTER0); + dev->stats.rx_crc_errors += inb_p(e8390_base + EN0_COUNTER1); + dev->stats.rx_missed_errors+= inb_p(e8390_base + EN0_COUNTER2); } } @@ -1311,7 +1311,6 @@ static irqreturn_t ax_interrupt(int irq, void *dev_id) static void ei_tx_err(struct net_device *dev) { long e8390_base = dev->base_addr; - struct ei_device *ei_local = (struct ei_device *) netdev_priv(dev); unsigned char txsr = inb_p(e8390_base+EN0_TSR); unsigned char tx_was_aborted = txsr & (ENTSR_ABT+ENTSR_FU); @@ -1334,10 +1333,10 @@ static void ei_tx_err(struct net_device *dev) ei_tx_intr(dev); else { - ei_local->stat.tx_errors++; - if (txsr & ENTSR_CRS) ei_local->stat.tx_carrier_errors++; - if (txsr & ENTSR_CDH) ei_local->stat.tx_heartbeat_errors++; - if (txsr & ENTSR_OWC) ei_local->stat.tx_window_errors++; + dev->stats.tx_errors++; + if (txsr & ENTSR_CRS) dev->stats.tx_carrier_errors++; + if (txsr & ENTSR_CDH) dev->stats.tx_heartbeat_errors++; + if (txsr & ENTSR_OWC) dev->stats.tx_window_errors++; } } @@ -1399,25 +1398,25 @@ static void ei_tx_intr(struct net_device *dev) /* Minimize Tx latency: update the statistics after we restart TXing. */ if (status & ENTSR_COL) - ei_local->stat.collisions++; + dev->stats.collisions++; if (status & ENTSR_PTX) - ei_local->stat.tx_packets++; + dev->stats.tx_packets++; else { - ei_local->stat.tx_errors++; + dev->stats.tx_errors++; if (status & ENTSR_ABT) { - ei_local->stat.tx_aborted_errors++; - ei_local->stat.collisions += 16; + dev->stats.tx_aborted_errors++; + dev->stats.collisions += 16; } if (status & ENTSR_CRS) - ei_local->stat.tx_carrier_errors++; + dev->stats.tx_carrier_errors++; if (status & ENTSR_FU) - ei_local->stat.tx_fifo_errors++; + dev->stats.tx_fifo_errors++; if (status & ENTSR_CDH) - ei_local->stat.tx_heartbeat_errors++; + dev->stats.tx_heartbeat_errors++; if (status & ENTSR_OWC) - ei_local->stat.tx_window_errors++; + dev->stats.tx_window_errors++; } netif_wake_queue(dev); } @@ -1478,8 +1477,8 @@ static void ei_receive(struct net_device *dev) printk(KERN_DEBUG "%s: bogus packet size: %d, status=%#2x nxpg=%#2x.\n", dev->name, rx_frame.count, rx_frame.status, rx_frame.next); - ei_local->stat.rx_errors++; - ei_local->stat.rx_length_errors++; + dev->stats.rx_errors++; + dev->stats.rx_length_errors++; } else if ((pkt_stat & 0x0F) == ENRSR_RXOK) { @@ -1491,7 +1490,7 @@ static void ei_receive(struct net_device *dev) if (ei_debug > 1) printk(KERN_DEBUG "%s: Couldn't allocate a sk_buff of size %d.\n", dev->name, pkt_len); - ei_local->stat.rx_dropped++; + dev->stats.rx_dropped++; break; } else @@ -1502,10 +1501,10 @@ static void ei_receive(struct net_device *dev) skb->protocol=eth_type_trans(skb,dev); netif_rx(skb); dev->last_rx = jiffies; - ei_local->stat.rx_packets++; - ei_local->stat.rx_bytes += pkt_len; + dev->stats.rx_packets++; + dev->stats.rx_bytes += pkt_len; if (pkt_stat & ENRSR_PHY) - ei_local->stat.multicast++; + dev->stats.multicast++; } } else @@ -1514,10 +1513,10 @@ static void ei_receive(struct net_device *dev) printk(KERN_DEBUG "%s: bogus packet: status=%#2x nxpg=%#2x size=%d\n", dev->name, rx_frame.status, rx_frame.next, rx_frame.count); - ei_local->stat.rx_errors++; + dev->stats.rx_errors++; /* NB: The NIC counts CRC, frame and missed errors. */ if (pkt_stat & ENRSR_FO) - ei_local->stat.rx_fifo_errors++; + dev->stats.rx_fifo_errors++; } next_frame = rx_frame.next; @@ -1552,7 +1551,6 @@ static void ei_rx_overrun(struct net_device *dev) axnet_dev_t *info = PRIV(dev); long e8390_base = dev->base_addr; unsigned char was_txing, must_resend = 0; - struct ei_device *ei_local = (struct ei_device *) netdev_priv(dev); /* * Record whether a Tx was in progress and then issue the @@ -1563,7 +1561,7 @@ static void ei_rx_overrun(struct net_device *dev) if (ei_debug > 1) printk(KERN_DEBUG "%s: Receiver overrun.\n", dev->name); - ei_local->stat.rx_over_errors++; + dev->stats.rx_over_errors++; /* * Wait a full Tx time (1.2ms) + some guard time, NS says 1.6ms total. @@ -1624,16 +1622,16 @@ static struct net_device_stats *get_stats(struct net_device *dev) /* If the card is stopped, just return the present stats. */ if (!netif_running(dev)) - return &ei_local->stat; + return &dev->stats; spin_lock_irqsave(&ei_local->page_lock,flags); /* Read the counter registers, assuming we are in page 0. */ - ei_local->stat.rx_frame_errors += inb_p(ioaddr + EN0_COUNTER0); - ei_local->stat.rx_crc_errors += inb_p(ioaddr + EN0_COUNTER1); - ei_local->stat.rx_missed_errors+= inb_p(ioaddr + EN0_COUNTER2); + dev->stats.rx_frame_errors += inb_p(ioaddr + EN0_COUNTER0); + dev->stats.rx_crc_errors += inb_p(ioaddr + EN0_COUNTER1); + dev->stats.rx_missed_errors+= inb_p(ioaddr + EN0_COUNTER2); spin_unlock_irqrestore(&ei_local->page_lock, flags); - return &ei_local->stat; + return &dev->stats; } /* diff --git a/drivers/net/pcnet32.c b/drivers/net/pcnet32.c index 1c89b97f4e09..ca8c0e037400 100644 --- a/drivers/net/pcnet32.c +++ b/drivers/net/pcnet32.c @@ -1973,7 +1973,7 @@ pcnet32_probe1(unsigned long ioaddr, int shared, struct pci_dev *pdev) err_free_ring: pcnet32_free_ring(dev); err_free_consistent: - pci_free_consistent(lp->pci_dev, sizeof(*lp->init_block), + pci_free_consistent(lp->pci_dev, sizeof(*lp->init_block), lp->init_block, lp->init_dma_addr); err_free_netdev: free_netdev(dev); @@ -2953,7 +2953,7 @@ static void __devexit pcnet32_remove_one(struct pci_dev *pdev) unregister_netdev(dev); pcnet32_free_ring(dev); release_region(dev->base_addr, PCNET32_TOTAL_SIZE); - pci_free_consistent(lp->pci_dev, sizeof(*lp->init_block), + pci_free_consistent(lp->pci_dev, sizeof(*lp->init_block), lp->init_block, lp->init_dma_addr); free_netdev(dev); pci_disable_device(pdev); @@ -3036,7 +3036,7 @@ static void __exit pcnet32_cleanup_module(void) unregister_netdev(pcnet32_dev); pcnet32_free_ring(pcnet32_dev); release_region(pcnet32_dev->base_addr, PCNET32_TOTAL_SIZE); - pci_free_consistent(lp->pci_dev, sizeof(*lp->init_block), + pci_free_consistent(lp->pci_dev, sizeof(*lp->init_block), lp->init_block, lp->init_dma_addr); free_netdev(pcnet32_dev); pcnet32_dev = next_dev; diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig index 6eb2d31d1e34..d55932acd887 100644 --- a/drivers/net/phy/Kconfig +++ b/drivers/net/phy/Kconfig @@ -53,7 +53,8 @@ config SMSC_PHY config BROADCOM_PHY tristate "Drivers for Broadcom PHYs" ---help--- - Currently supports the BCM5411, BCM5421 and BCM5461 PHYs. + Currently supports the BCM5411, BCM5421, BCM5461, BCM5464, BCM5481 + and BCM5482 PHYs. config ICPLUS_PHY tristate "Drivers for ICPlus PHYs" @@ -83,4 +84,10 @@ config MDIO_BITBANG If in doubt, say N. +config MDIO_OF_GPIO + tristate "Support for GPIO lib-based bitbanged MDIO buses" + depends on MDIO_BITBANG && OF_GPIO + ---help--- + Supports GPIO lib-based MDIO busses. + endif # PHYLIB diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile index 5997d6ef702b..eee329fa6f53 100644 --- a/drivers/net/phy/Makefile +++ b/drivers/net/phy/Makefile @@ -15,3 +15,4 @@ obj-$(CONFIG_ICPLUS_PHY) += icplus.o obj-$(CONFIG_REALTEK_PHY) += realtek.o obj-$(CONFIG_FIXED_PHY) += fixed.o obj-$(CONFIG_MDIO_BITBANG) += mdio-bitbang.o +obj-$(CONFIG_MDIO_OF_GPIO) += mdio-ofgpio.o diff --git a/drivers/net/phy/broadcom.c b/drivers/net/phy/broadcom.c index 60c5cfe96918..4b4dc98ad165 100644 --- a/drivers/net/phy/broadcom.c +++ b/drivers/net/phy/broadcom.c @@ -24,6 +24,12 @@ #define MII_BCM54XX_ESR 0x11 /* BCM54xx extended status register */ #define MII_BCM54XX_ESR_IS 0x1000 /* Interrupt status */ +#define MII_BCM54XX_EXP_DATA 0x15 /* Expansion register data */ +#define MII_BCM54XX_EXP_SEL 0x17 /* Expansion register select */ +#define MII_BCM54XX_EXP_SEL_SSD 0x0e00 /* Secondary SerDes select */ +#define MII_BCM54XX_EXP_SEL_ER 0x0f00 /* Expansion register select */ + +#define MII_BCM54XX_AUX_CTL 0x18 /* Auxiliary control register */ #define MII_BCM54XX_ISR 0x1a /* BCM54xx interrupt status register */ #define MII_BCM54XX_IMR 0x1b /* BCM54xx interrupt mask register */ #define MII_BCM54XX_INT_CRCERR 0x0001 /* CRC error */ @@ -42,10 +48,120 @@ #define MII_BCM54XX_INT_MDIX 0x2000 /* MDIX status change */ #define MII_BCM54XX_INT_PSERR 0x4000 /* Pair swap error */ +#define MII_BCM54XX_SHD 0x1c /* 0x1c shadow registers */ +#define MII_BCM54XX_SHD_WRITE 0x8000 +#define MII_BCM54XX_SHD_VAL(x) ((x & 0x1f) << 10) +#define MII_BCM54XX_SHD_DATA(x) ((x & 0x3ff) << 0) + +/* + * Broadcom LED source encodings. These are used in BCM5461, BCM5481, + * BCM5482, and possibly some others. + */ +#define BCM_LED_SRC_LINKSPD1 0x0 +#define BCM_LED_SRC_LINKSPD2 0x1 +#define BCM_LED_SRC_XMITLED 0x2 +#define BCM_LED_SRC_ACTIVITYLED 0x3 +#define BCM_LED_SRC_FDXLED 0x4 +#define BCM_LED_SRC_SLAVE 0x5 +#define BCM_LED_SRC_INTR 0x6 +#define BCM_LED_SRC_QUALITY 0x7 +#define BCM_LED_SRC_RCVLED 0x8 +#define BCM_LED_SRC_MULTICOLOR1 0xa +#define BCM_LED_SRC_OPENSHORT 0xb +#define BCM_LED_SRC_OFF 0xe /* Tied high */ +#define BCM_LED_SRC_ON 0xf /* Tied low */ + +/* + * BCM5482: Shadow registers + * Shadow values go into bits [14:10] of register 0x1c to select a shadow + * register to access. + */ +#define BCM5482_SHD_LEDS1 0x0d /* 01101: LED Selector 1 */ + /* LED3 / ~LINKSPD[2] selector */ +#define BCM5482_SHD_LEDS1_LED3(src) ((src & 0xf) << 4) + /* LED1 / ~LINKSPD[1] selector */ +#define BCM5482_SHD_LEDS1_LED1(src) ((src & 0xf) << 0) +#define BCM5482_SHD_SSD 0x14 /* 10100: Secondary SerDes control */ +#define BCM5482_SHD_SSD_LEDM 0x0008 /* SSD LED Mode enable */ +#define BCM5482_SHD_SSD_EN 0x0001 /* SSD enable */ +#define BCM5482_SHD_MODE 0x1f /* 11111: Mode Control Register */ +#define BCM5482_SHD_MODE_1000BX 0x0001 /* Enable 1000BASE-X registers */ + +/* + * BCM5482: Secondary SerDes registers + */ +#define BCM5482_SSD_1000BX_CTL 0x00 /* 1000BASE-X Control */ +#define BCM5482_SSD_1000BX_CTL_PWRDOWN 0x0800 /* Power-down SSD */ +#define BCM5482_SSD_SGMII_SLAVE 0x15 /* SGMII Slave Register */ +#define BCM5482_SSD_SGMII_SLAVE_EN 0x0002 /* Slave mode enable */ +#define BCM5482_SSD_SGMII_SLAVE_AD 0x0001 /* Slave auto-detection */ + +/* + * Device flags for PHYs that can be configured for different operating + * modes. + */ +#define PHY_BCM_FLAGS_VALID 0x80000000 +#define PHY_BCM_FLAGS_INTF_XAUI 0x00000020 +#define PHY_BCM_FLAGS_INTF_SGMII 0x00000010 +#define PHY_BCM_FLAGS_MODE_1000BX 0x00000002 +#define PHY_BCM_FLAGS_MODE_COPPER 0x00000001 + MODULE_DESCRIPTION("Broadcom PHY driver"); MODULE_AUTHOR("Maciej W. Rozycki"); MODULE_LICENSE("GPL"); +/* + * Indirect register access functions for the 1000BASE-T/100BASE-TX/10BASE-T + * 0x1c shadow registers. + */ +static int bcm54xx_shadow_read(struct phy_device *phydev, u16 shadow) +{ + phy_write(phydev, MII_BCM54XX_SHD, MII_BCM54XX_SHD_VAL(shadow)); + return MII_BCM54XX_SHD_DATA(phy_read(phydev, MII_BCM54XX_SHD)); +} + +static int bcm54xx_shadow_write(struct phy_device *phydev, u16 shadow, u16 val) +{ + return phy_write(phydev, MII_BCM54XX_SHD, + MII_BCM54XX_SHD_WRITE | + MII_BCM54XX_SHD_VAL(shadow) | + MII_BCM54XX_SHD_DATA(val)); +} + +/* + * Indirect register access functions for the Expansion Registers + * and Secondary SerDes registers (when sec_serdes=1). + */ +static int bcm54xx_exp_read(struct phy_device *phydev, + int sec_serdes, u8 regnum) +{ + int val; + + phy_write(phydev, MII_BCM54XX_EXP_SEL, + (sec_serdes ? MII_BCM54XX_EXP_SEL_SSD : + MII_BCM54XX_EXP_SEL_ER) | + regnum); + val = phy_read(phydev, MII_BCM54XX_EXP_DATA); + phy_write(phydev, MII_BCM54XX_EXP_SEL, regnum); + + return val; +} + +static int bcm54xx_exp_write(struct phy_device *phydev, + int sec_serdes, u8 regnum, u16 val) +{ + int ret; + + phy_write(phydev, MII_BCM54XX_EXP_SEL, + (sec_serdes ? MII_BCM54XX_EXP_SEL_SSD : + MII_BCM54XX_EXP_SEL_ER) | + regnum); + ret = phy_write(phydev, MII_BCM54XX_EXP_DATA, val); + phy_write(phydev, MII_BCM54XX_EXP_SEL, regnum); + + return ret; +} + static int bcm54xx_config_init(struct phy_device *phydev) { int reg, err; @@ -70,6 +186,87 @@ static int bcm54xx_config_init(struct phy_device *phydev) return 0; } +static int bcm5482_config_init(struct phy_device *phydev) +{ + int err, reg; + + err = bcm54xx_config_init(phydev); + + if (phydev->dev_flags & PHY_BCM_FLAGS_MODE_1000BX) { + /* + * Enable secondary SerDes and its use as an LED source + */ + reg = bcm54xx_shadow_read(phydev, BCM5482_SHD_SSD); + bcm54xx_shadow_write(phydev, BCM5482_SHD_SSD, + reg | + BCM5482_SHD_SSD_LEDM | + BCM5482_SHD_SSD_EN); + + /* + * Enable SGMII slave mode and auto-detection + */ + reg = bcm54xx_exp_read(phydev, 1, BCM5482_SSD_SGMII_SLAVE); + bcm54xx_exp_write(phydev, 1, BCM5482_SSD_SGMII_SLAVE, + reg | + BCM5482_SSD_SGMII_SLAVE_EN | + BCM5482_SSD_SGMII_SLAVE_AD); + + /* + * Disable secondary SerDes powerdown + */ + reg = bcm54xx_exp_read(phydev, 1, BCM5482_SSD_1000BX_CTL); + bcm54xx_exp_write(phydev, 1, BCM5482_SSD_1000BX_CTL, + reg & ~BCM5482_SSD_1000BX_CTL_PWRDOWN); + + /* + * Select 1000BASE-X register set (primary SerDes) + */ + reg = bcm54xx_shadow_read(phydev, BCM5482_SHD_MODE); + bcm54xx_shadow_write(phydev, BCM5482_SHD_MODE, + reg | BCM5482_SHD_MODE_1000BX); + + /* + * LED1=ACTIVITYLED, LED3=LINKSPD[2] + * (Use LED1 as secondary SerDes ACTIVITY LED) + */ + bcm54xx_shadow_write(phydev, BCM5482_SHD_LEDS1, + BCM5482_SHD_LEDS1_LED1(BCM_LED_SRC_ACTIVITYLED) | + BCM5482_SHD_LEDS1_LED3(BCM_LED_SRC_LINKSPD2)); + + /* + * Auto-negotiation doesn't seem to work quite right + * in this mode, so we disable it and force it to the + * right speed/duplex setting. Only 'link status' + * is important. + */ + phydev->autoneg = AUTONEG_DISABLE; + phydev->speed = SPEED_1000; + phydev->duplex = DUPLEX_FULL; + } + + return err; +} + +static int bcm5482_read_status(struct phy_device *phydev) +{ + int err; + + err = genphy_read_status(phydev); + + if (phydev->dev_flags & PHY_BCM_FLAGS_MODE_1000BX) { + /* + * Only link status matters for 1000Base-X mode, so force + * 1000 Mbit/s full-duplex status + */ + if (phydev->link) { + phydev->speed = SPEED_1000; + phydev->duplex = DUPLEX_FULL; + } + } + + return err; +} + static int bcm54xx_ack_interrupt(struct phy_device *phydev) { int reg; @@ -210,9 +407,9 @@ static struct phy_driver bcm5482_driver = { .name = "Broadcom BCM5482", .features = PHY_GBIT_FEATURES, .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT, - .config_init = bcm54xx_config_init, + .config_init = bcm5482_config_init, .config_aneg = genphy_config_aneg, - .read_status = genphy_read_status, + .read_status = bcm5482_read_status, .ack_interrupt = bcm54xx_ack_interrupt, .config_intr = bcm54xx_config_intr, .driver = { .owner = THIS_MODULE }, diff --git a/drivers/net/phy/mdio-bitbang.c b/drivers/net/phy/mdio-bitbang.c index 2747b1f89ffe..c01b78013ddc 100644 --- a/drivers/net/phy/mdio-bitbang.c +++ b/drivers/net/phy/mdio-bitbang.c @@ -177,6 +177,7 @@ struct mii_bus *alloc_mdio_bitbang(struct mdiobb_ctrl *ctrl) return bus; } +EXPORT_SYMBOL(alloc_mdio_bitbang); void free_mdio_bitbang(struct mii_bus *bus) { @@ -185,5 +186,6 @@ void free_mdio_bitbang(struct mii_bus *bus) module_put(ctrl->ops->owner); kfree(bus); } +EXPORT_SYMBOL(free_mdio_bitbang); MODULE_LICENSE("GPL"); diff --git a/drivers/net/phy/mdio-ofgpio.c b/drivers/net/phy/mdio-ofgpio.c new file mode 100644 index 000000000000..7edfc0c34835 --- /dev/null +++ b/drivers/net/phy/mdio-ofgpio.c @@ -0,0 +1,205 @@ +/* + * OpenFirmware GPIO based MDIO bitbang driver. + * + * Copyright (c) 2008 CSE Semaphore Belgium. + * by Laurent Pinchart <laurentp@cse-semaphore.com> + * + * Based on earlier work by + * + * Copyright (c) 2003 Intracom S.A. + * by Pantelis Antoniou <panto@intracom.gr> + * + * 2005 (c) MontaVista Software, Inc. + * Vitaly Bordug <vbordug@ru.mvista.com> + * + * This file is licensed under the terms of the GNU General Public License + * version 2. This program is licensed "as is" without any warranty of any + * kind, whether express or implied. + */ + +#include <linux/module.h> +#include <linux/slab.h> +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/mdio-bitbang.h> +#include <linux/of_gpio.h> +#include <linux/of_platform.h> + +struct mdio_gpio_info { + struct mdiobb_ctrl ctrl; + int mdc, mdio; +}; + +static void mdio_dir(struct mdiobb_ctrl *ctrl, int dir) +{ + struct mdio_gpio_info *bitbang = + container_of(ctrl, struct mdio_gpio_info, ctrl); + + if (dir) + gpio_direction_output(bitbang->mdio, 1); + else + gpio_direction_input(bitbang->mdio); +} + +static int mdio_read(struct mdiobb_ctrl *ctrl) +{ + struct mdio_gpio_info *bitbang = + container_of(ctrl, struct mdio_gpio_info, ctrl); + + return gpio_get_value(bitbang->mdio); +} + +static void mdio(struct mdiobb_ctrl *ctrl, int what) +{ + struct mdio_gpio_info *bitbang = + container_of(ctrl, struct mdio_gpio_info, ctrl); + + gpio_set_value(bitbang->mdio, what); +} + +static void mdc(struct mdiobb_ctrl *ctrl, int what) +{ + struct mdio_gpio_info *bitbang = + container_of(ctrl, struct mdio_gpio_info, ctrl); + + gpio_set_value(bitbang->mdc, what); +} + +static struct mdiobb_ops mdio_gpio_ops = { + .owner = THIS_MODULE, + .set_mdc = mdc, + .set_mdio_dir = mdio_dir, + .set_mdio_data = mdio, + .get_mdio_data = mdio_read, +}; + +static int __devinit mdio_ofgpio_bitbang_init(struct mii_bus *bus, + struct device_node *np) +{ + struct mdio_gpio_info *bitbang = bus->priv; + + bitbang->mdc = of_get_gpio(np, 0); + bitbang->mdio = of_get_gpio(np, 1); + + if (bitbang->mdc < 0 || bitbang->mdio < 0) + return -ENODEV; + + snprintf(bus->id, MII_BUS_ID_SIZE, "%x", bitbang->mdc); + 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 mdio_ofgpio_probe(struct of_device *ofdev, + const struct of_device_id *match) +{ + struct device_node *np = NULL; + struct mii_bus *new_bus; + struct mdio_gpio_info *bitbang; + int ret = -ENOMEM; + int i; + + bitbang = kzalloc(sizeof(struct mdio_gpio_info), GFP_KERNEL); + if (!bitbang) + goto out; + + bitbang->ctrl.ops = &mdio_gpio_ops; + + new_bus = alloc_mdio_bitbang(&bitbang->ctrl); + if (!new_bus) + goto out_free_priv; + + new_bus->name = "GPIO Bitbanged MII", + + ret = mdio_ofgpio_bitbang_init(new_bus, ofdev->node); + if (ret) + goto out_free_bus; + + 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] = -1; + + while ((np = of_get_next_child(ofdev->node, np))) + if (!strcmp(np->type, "ethernet-phy")) + add_phy(new_bus, np); + + new_bus->dev = &ofdev->dev; + dev_set_drvdata(&ofdev->dev, new_bus); + + ret = mdiobus_register(new_bus); + if (ret) + goto out_free_irqs; + + return 0; + +out_free_irqs: + dev_set_drvdata(&ofdev->dev, NULL); + kfree(new_bus->irq); +out_free_bus: + kfree(new_bus); +out_free_priv: + free_mdio_bitbang(new_bus); +out: + return ret; +} + +static int mdio_ofgpio_remove(struct of_device *ofdev) +{ + struct mii_bus *bus = dev_get_drvdata(&ofdev->dev); + struct mdio_gpio_info *bitbang = bus->priv; + + mdiobus_unregister(bus); + free_mdio_bitbang(bus); + dev_set_drvdata(&ofdev->dev, NULL); + kfree(bus->irq); + kfree(bitbang); + kfree(bus); + + return 0; +} + +static struct of_device_id mdio_ofgpio_match[] = { + { + .compatible = "virtual,mdio-gpio", + }, + {}, +}; + +static struct of_platform_driver mdio_ofgpio_driver = { + .name = "mdio-gpio", + .match_table = mdio_ofgpio_match, + .probe = mdio_ofgpio_probe, + .remove = mdio_ofgpio_remove, +}; + +static int mdio_ofgpio_init(void) +{ + return of_register_platform_driver(&mdio_ofgpio_driver); +} + +static void mdio_ofgpio_exit(void) +{ + of_unregister_platform_driver(&mdio_ofgpio_driver); +} + +module_init(mdio_ofgpio_init); +module_exit(mdio_ofgpio_exit); diff --git a/drivers/net/ppp_async.c b/drivers/net/ppp_async.c index f1a52def1241..451bdb57d6fc 100644 --- a/drivers/net/ppp_async.c +++ b/drivers/net/ppp_async.c @@ -378,7 +378,7 @@ ppp_asynctty_wakeup(struct tty_struct *tty) } -static struct tty_ldisc ppp_ldisc = { +static struct tty_ldisc_ops ppp_ldisc = { .owner = THIS_MODULE, .magic = TTY_LDISC_MAGIC, .name = "ppp", diff --git a/drivers/net/ppp_generic.c b/drivers/net/ppp_generic.c index 83625fdff3dd..6b1d7a8edf15 100644 --- a/drivers/net/ppp_generic.c +++ b/drivers/net/ppp_generic.c @@ -363,7 +363,7 @@ static int ppp_open(struct inode *inode, struct file *file) return 0; } -static int ppp_release(struct inode *inode, struct file *file) +static int ppp_release(struct inode *unused, struct file *file) { struct ppp_file *pf = file->private_data; struct ppp *ppp; @@ -547,8 +547,7 @@ static int get_filter(void __user *arg, struct sock_filter **p) } #endif /* CONFIG_PPP_FILTER */ -static int ppp_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg) +static long ppp_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { struct ppp_file *pf = file->private_data; struct ppp *ppp; @@ -576,24 +575,29 @@ static int ppp_ioctl(struct inode *inode, struct file *file, * this fd and reopening /dev/ppp. */ err = -EINVAL; + lock_kernel(); if (pf->kind == INTERFACE) { ppp = PF_TO_PPP(pf); if (file == ppp->owner) ppp_shutdown_interface(ppp); } if (atomic_read(&file->f_count) <= 2) { - ppp_release(inode, file); + ppp_release(NULL, file); err = 0; } else printk(KERN_DEBUG "PPPIOCDETACH file->f_count=%d\n", atomic_read(&file->f_count)); + unlock_kernel(); return err; } if (pf->kind == CHANNEL) { - struct channel *pch = PF_TO_CHANNEL(pf); + struct channel *pch; struct ppp_channel *chan; + lock_kernel(); + pch = PF_TO_CHANNEL(pf); + switch (cmd) { case PPPIOCCONNECT: if (get_user(unit, p)) @@ -613,6 +617,7 @@ static int ppp_ioctl(struct inode *inode, struct file *file, err = chan->ops->ioctl(chan, cmd, arg); up_read(&pch->chan_sem); } + unlock_kernel(); return err; } @@ -622,6 +627,7 @@ static int ppp_ioctl(struct inode *inode, struct file *file, return -EINVAL; } + lock_kernel(); ppp = PF_TO_PPP(pf); switch (cmd) { case PPPIOCSMRU: @@ -769,7 +775,7 @@ static int ppp_ioctl(struct inode *inode, struct file *file, default: err = -ENOTTY; } - + unlock_kernel(); return err; } @@ -781,6 +787,7 @@ static int ppp_unattached_ioctl(struct ppp_file *pf, struct file *file, struct channel *chan; int __user *p = (int __user *)arg; + lock_kernel(); switch (cmd) { case PPPIOCNEWUNIT: /* Create a new ppp unit */ @@ -829,6 +836,7 @@ static int ppp_unattached_ioctl(struct ppp_file *pf, struct file *file, default: err = -ENOTTY; } + unlock_kernel(); return err; } @@ -837,7 +845,7 @@ static const struct file_operations ppp_device_fops = { .read = ppp_read, .write = ppp_write, .poll = ppp_poll, - .ioctl = ppp_ioctl, + .unlocked_ioctl = ppp_ioctl, .open = ppp_open, .release = ppp_release }; diff --git a/drivers/net/ppp_synctty.c b/drivers/net/ppp_synctty.c index b8f0369a71e7..801d8f99d471 100644 --- a/drivers/net/ppp_synctty.c +++ b/drivers/net/ppp_synctty.c @@ -418,7 +418,7 @@ ppp_sync_wakeup(struct tty_struct *tty) } -static struct tty_ldisc ppp_sync_ldisc = { +static struct tty_ldisc_ops ppp_sync_ldisc = { .owner = THIS_MODULE, .magic = TTY_LDISC_MAGIC, .name = "pppsync", diff --git a/drivers/net/ps3_gelic_net.c b/drivers/net/ps3_gelic_net.c index e365efb3c627..2eb54fd7bed5 100644 --- a/drivers/net/ps3_gelic_net.c +++ b/drivers/net/ps3_gelic_net.c @@ -110,7 +110,7 @@ static void gelic_card_get_ether_port_status(struct gelic_card *card, void gelic_card_up(struct gelic_card *card) { pr_debug("%s: called\n", __func__); - down(&card->updown_lock); + mutex_lock(&card->updown_lock); if (atomic_inc_return(&card->users) == 1) { pr_debug("%s: real do\n", __func__); /* enable irq */ @@ -120,7 +120,7 @@ void gelic_card_up(struct gelic_card *card) napi_enable(&card->napi); } - up(&card->updown_lock); + mutex_unlock(&card->updown_lock); pr_debug("%s: done\n", __func__); } @@ -128,7 +128,7 @@ void gelic_card_down(struct gelic_card *card) { u64 mask; pr_debug("%s: called\n", __func__); - down(&card->updown_lock); + mutex_lock(&card->updown_lock); if (atomic_dec_if_positive(&card->users) == 0) { pr_debug("%s: real do\n", __func__); napi_disable(&card->napi); @@ -146,7 +146,7 @@ void gelic_card_down(struct gelic_card *card) /* stop tx */ gelic_card_disable_txdmac(card); } - up(&card->updown_lock); + mutex_unlock(&card->updown_lock); pr_debug("%s: done\n", __func__); } @@ -1534,7 +1534,7 @@ static struct gelic_card *gelic_alloc_card_net(struct net_device **netdev) INIT_WORK(&card->tx_timeout_task, gelic_net_tx_timeout_task); init_waitqueue_head(&card->waitq); atomic_set(&card->tx_timeout_task_counter, 0); - init_MUTEX(&card->updown_lock); + mutex_init(&card->updown_lock); atomic_set(&card->users, 0); return card; diff --git a/drivers/net/ps3_gelic_net.h b/drivers/net/ps3_gelic_net.h index 520f143c2c09..8b413868bbe2 100644 --- a/drivers/net/ps3_gelic_net.h +++ b/drivers/net/ps3_gelic_net.h @@ -298,7 +298,7 @@ struct gelic_card { wait_queue_head_t waitq; /* only first user should up the card */ - struct semaphore updown_lock; + struct mutex updown_lock; atomic_t users; u64 ether_port_status; diff --git a/drivers/net/ps3_gelic_wireless.c b/drivers/net/ps3_gelic_wireless.c index 1dae1f2ed813..6b2dee0cf3a9 100644 --- a/drivers/net/ps3_gelic_wireless.c +++ b/drivers/net/ps3_gelic_wireless.c @@ -45,7 +45,8 @@ #include "ps3_gelic_wireless.h" -static int gelic_wl_start_scan(struct gelic_wl_info *wl, int always_scan); +static int gelic_wl_start_scan(struct gelic_wl_info *wl, int always_scan, + u8 *essid, size_t essid_len); static int gelic_wl_try_associate(struct net_device *netdev); /* @@ -105,6 +106,7 @@ static const struct eurus_cmd_arg_info cmd_info[GELIC_EURUS_CMD_MAX_INDEX] = { [GELIC_EURUS_CMD_GET_WEP_CFG] = { .post_arg = 1}, [GELIC_EURUS_CMD_GET_WPA_CFG] = { .post_arg = 1}, [GELIC_EURUS_CMD_GET_RSSI_CFG] = { .post_arg = 1}, + [GELIC_EURUS_CMD_START_SCAN] = { .pre_arg = 1}, [GELIC_EURUS_CMD_GET_SCAN] = { .post_arg = 1}, }; @@ -163,7 +165,9 @@ static void gelic_eurus_sync_cmd_worker(struct work_struct *work) card = port_to_card(wl_port(wl)); if (cmd_info[cmd->cmd].pre_arg) { - arg1 = ps3_mm_phys_to_lpar(__pa(cmd->buffer)); + arg1 = (cmd->buffer) ? + ps3_mm_phys_to_lpar(__pa(cmd->buffer)) : + 0; arg2 = cmd->buf_size; } else { arg1 = 0; @@ -240,12 +244,12 @@ static u32 gelic_wl_get_link(struct net_device *netdev) u32 ret; pr_debug("%s: <-\n", __func__); - down(&wl->assoc_stat_lock); + mutex_lock(&wl->assoc_stat_lock); if (wl->assoc_stat == GELIC_WL_ASSOC_STAT_ASSOCIATED) ret = 1; else ret = 0; - up(&wl->assoc_stat_lock); + mutex_unlock(&wl->assoc_stat_lock); pr_debug("%s: ->\n", __func__); return ret; } @@ -350,7 +354,8 @@ static int gelic_wl_get_range(struct net_device *netdev, /* encryption capability */ range->enc_capa = IW_ENC_CAPA_WPA | - IW_ENC_CAPA_CIPHER_TKIP | IW_ENC_CAPA_CIPHER_CCMP; + IW_ENC_CAPA_CIPHER_TKIP | IW_ENC_CAPA_CIPHER_CCMP | + IW_ENC_CAPA_4WAY_HANDSHAKE; if (wpa2_capable()) range->enc_capa |= IW_ENC_CAPA_WPA2; range->encoding_size[0] = 5; /* 40bit WEP */ @@ -359,6 +364,9 @@ static int gelic_wl_get_range(struct net_device *netdev, range->num_encoding_sizes = 3; range->max_encoding_tokens = GELIC_WEP_KEYS; + /* scan capability */ + range->scan_capa = IW_SCAN_CAPA_ESSID; + pr_debug("%s: ->\n", __func__); return 0; @@ -370,8 +378,18 @@ static int gelic_wl_set_scan(struct net_device *netdev, union iwreq_data *wrqu, char *extra) { struct gelic_wl_info *wl = port_wl(netdev_priv(netdev)); - - return gelic_wl_start_scan(wl, 1); + struct iw_scan_req *req; + u8 *essid = NULL; + size_t essid_len = 0; + + if (wrqu->data.length == sizeof(struct iw_scan_req) && + wrqu->data.flags & IW_SCAN_THIS_ESSID) { + req = (struct iw_scan_req*)extra; + essid = req->essid; + essid_len = req->essid_len; + pr_debug("%s: ESSID scan =%s\n", __func__, essid); + } + return gelic_wl_start_scan(wl, 1, essid, essid_len); } #define OUI_LEN 3 @@ -553,6 +571,7 @@ static void gelic_wl_parse_ie(u8 *data, size_t len, * independent format */ static char *gelic_wl_translate_scan(struct net_device *netdev, + struct iw_request_info *info, char *ev, char *stop, struct gelic_wl_scan_info *network) @@ -570,26 +589,26 @@ static char *gelic_wl_translate_scan(struct net_device *netdev, iwe.cmd = SIOCGIWAP; iwe.u.ap_addr.sa_family = ARPHRD_ETHER; memcpy(iwe.u.ap_addr.sa_data, &scan->bssid[2], ETH_ALEN); - ev = iwe_stream_add_event(ev, stop, &iwe, IW_EV_ADDR_LEN); + ev = iwe_stream_add_event(info, ev, stop, &iwe, IW_EV_ADDR_LEN); /* ESSID */ iwe.cmd = SIOCGIWESSID; iwe.u.data.flags = 1; iwe.u.data.length = strnlen(scan->essid, 32); - ev = iwe_stream_add_point(ev, stop, &iwe, scan->essid); + ev = iwe_stream_add_point(info, ev, stop, &iwe, scan->essid); /* FREQUENCY */ iwe.cmd = SIOCGIWFREQ; iwe.u.freq.m = be16_to_cpu(scan->channel); iwe.u.freq.e = 0; /* table value in MHz */ iwe.u.freq.i = 0; - ev = iwe_stream_add_event(ev, stop, &iwe, IW_EV_FREQ_LEN); + ev = iwe_stream_add_event(info, ev, stop, &iwe, IW_EV_FREQ_LEN); /* RATES */ iwe.cmd = SIOCGIWRATE; iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0; /* to stuff multiple values in one event */ - tmp = ev + IW_EV_LCP_LEN; + tmp = ev + iwe_stream_lcp_len(info); /* put them in ascendant order (older is first) */ i = 0; j = 0; @@ -602,16 +621,16 @@ static char *gelic_wl_translate_scan(struct net_device *netdev, else rate = scan->rate[i++] & 0x7f; iwe.u.bitrate.value = rate * 500000; /* 500kbps unit */ - tmp = iwe_stream_add_value(ev, tmp, stop, &iwe, + tmp = iwe_stream_add_value(info, ev, tmp, stop, &iwe, IW_EV_PARAM_LEN); } while (j < network->rate_ext_len) { iwe.u.bitrate.value = (scan->ext_rate[j++] & 0x7f) * 500000; - tmp = iwe_stream_add_value(ev, tmp, stop, &iwe, + tmp = iwe_stream_add_value(info, ev, tmp, stop, &iwe, IW_EV_PARAM_LEN); } /* Check if we added any rate */ - if (IW_EV_LCP_LEN < (tmp - ev)) + if (iwe_stream_lcp_len(info) < (tmp - ev)) ev = tmp; /* ENCODE */ @@ -621,7 +640,7 @@ static char *gelic_wl_translate_scan(struct net_device *netdev, else iwe.u.data.flags = IW_ENCODE_DISABLED; iwe.u.data.length = 0; - ev = iwe_stream_add_point(ev, stop, &iwe, scan->essid); + ev = iwe_stream_add_point(info, ev, stop, &iwe, scan->essid); /* MODE */ iwe.cmd = SIOCGIWMODE; @@ -631,7 +650,7 @@ static char *gelic_wl_translate_scan(struct net_device *netdev, iwe.u.mode = IW_MODE_MASTER; else iwe.u.mode = IW_MODE_ADHOC; - ev = iwe_stream_add_event(ev, stop, &iwe, IW_EV_UINT_LEN); + ev = iwe_stream_add_event(info, ev, stop, &iwe, IW_EV_UINT_LEN); } /* QUAL */ @@ -641,7 +660,7 @@ static char *gelic_wl_translate_scan(struct net_device *netdev, iwe.u.qual.level = be16_to_cpu(scan->rssi); iwe.u.qual.qual = be16_to_cpu(scan->rssi); iwe.u.qual.noise = 0; - ev = iwe_stream_add_event(ev, stop, &iwe, IW_EV_QUAL_LEN); + ev = iwe_stream_add_event(info, ev, stop, &iwe, IW_EV_QUAL_LEN); /* RSN */ memset(&iwe, 0, sizeof(iwe)); @@ -651,7 +670,7 @@ static char *gelic_wl_translate_scan(struct net_device *netdev, if (len) { iwe.cmd = IWEVGENIE; iwe.u.data.length = len; - ev = iwe_stream_add_point(ev, stop, &iwe, buf); + ev = iwe_stream_add_point(info, ev, stop, &iwe, buf); } } else { /* this scan info has IE data */ @@ -666,7 +685,7 @@ static char *gelic_wl_translate_scan(struct net_device *netdev, memcpy(buf, ie_info.wpa.data, ie_info.wpa.len); iwe.cmd = IWEVGENIE; iwe.u.data.length = ie_info.wpa.len; - ev = iwe_stream_add_point(ev, stop, &iwe, buf); + ev = iwe_stream_add_point(info, ev, stop, &iwe, buf); } if (ie_info.rsn.len && (ie_info.rsn.len <= sizeof(buf))) { @@ -674,7 +693,7 @@ static char *gelic_wl_translate_scan(struct net_device *netdev, memcpy(buf, ie_info.rsn.data, ie_info.rsn.len); iwe.cmd = IWEVGENIE; iwe.u.data.length = ie_info.rsn.len; - ev = iwe_stream_add_point(ev, stop, &iwe, buf); + ev = iwe_stream_add_point(info, ev, stop, &iwe, buf); } } @@ -695,7 +714,7 @@ static int gelic_wl_get_scan(struct net_device *netdev, unsigned long this_time = jiffies; pr_debug("%s: <-\n", __func__); - if (down_interruptible(&wl->scan_lock)) + if (mutex_lock_interruptible(&wl->scan_lock)) return -EAGAIN; switch (wl->scan_stat) { @@ -719,7 +738,8 @@ static int gelic_wl_get_scan(struct net_device *netdev, if (wl->scan_age == 0 || time_after(scan_info->last_scanned + wl->scan_age, this_time)) - ev = gelic_wl_translate_scan(netdev, ev, stop, + ev = gelic_wl_translate_scan(netdev, info, + ev, stop, scan_info); else pr_debug("%s:entry too old\n", __func__); @@ -733,7 +753,7 @@ static int gelic_wl_get_scan(struct net_device *netdev, wrqu->data.length = ev - extra; wrqu->data.flags = 0; out: - up(&wl->scan_lock); + mutex_unlock(&wl->scan_lock); pr_debug("%s: -> %d %d\n", __func__, ret, wrqu->data.length); return ret; } @@ -979,7 +999,7 @@ static int gelic_wl_get_essid(struct net_device *netdev, unsigned long irqflag; pr_debug("%s: <- \n", __func__); - down(&wl->assoc_stat_lock); + mutex_lock(&wl->assoc_stat_lock); spin_lock_irqsave(&wl->lock, irqflag); if (test_bit(GELIC_WL_STAT_ESSID_SET, &wl->stat) || wl->assoc_stat == GELIC_WL_ASSOC_STAT_ASSOCIATED) { @@ -989,7 +1009,7 @@ static int gelic_wl_get_essid(struct net_device *netdev, } else data->essid.flags = 0; - up(&wl->assoc_stat_lock); + mutex_unlock(&wl->assoc_stat_lock); spin_unlock_irqrestore(&wl->lock, irqflag); pr_debug("%s: -> len=%d \n", __func__, data->essid.length); @@ -1170,7 +1190,7 @@ static int gelic_wl_get_ap(struct net_device *netdev, unsigned long irqflag; pr_debug("%s: <-\n", __func__); - down(&wl->assoc_stat_lock); + mutex_lock(&wl->assoc_stat_lock); spin_lock_irqsave(&wl->lock, irqflag); if (wl->assoc_stat == GELIC_WL_ASSOC_STAT_ASSOCIATED) { data->ap_addr.sa_family = ARPHRD_ETHER; @@ -1180,7 +1200,7 @@ static int gelic_wl_get_ap(struct net_device *netdev, memset(data->ap_addr.sa_data, 0, ETH_ALEN); spin_unlock_irqrestore(&wl->lock, irqflag); - up(&wl->assoc_stat_lock); + mutex_unlock(&wl->assoc_stat_lock); pr_debug("%s: ->\n", __func__); return 0; } @@ -1256,42 +1276,19 @@ static int gelic_wl_set_encodeext(struct net_device *netdev, set_bit(key_index, &wl->key_enabled); /* remember wep info changed */ set_bit(GELIC_WL_STAT_CONFIGURED, &wl->stat); - } else if ((alg == IW_ENCODE_ALG_TKIP) || (alg == IW_ENCODE_ALG_CCMP)) { - pr_debug("%s: TKIP/CCMP requested alg=%d\n", __func__, alg); - /* check key length */ - if (IW_ENCODING_TOKEN_MAX < ext->key_len) { - pr_info("%s: key is too long %d\n", __func__, - ext->key_len); + } else if (alg == IW_ENCODE_ALG_PMK) { + if (ext->key_len != WPA_PSK_LEN) { + pr_err("%s: PSK length wrong %d\n", __func__, + ext->key_len); ret = -EINVAL; goto done; } - if (alg == IW_ENCODE_ALG_CCMP) { - pr_debug("%s: AES selected\n", __func__); - wl->group_cipher_method = GELIC_WL_CIPHER_AES; - wl->pairwise_cipher_method = GELIC_WL_CIPHER_AES; - wl->wpa_level = GELIC_WL_WPA_LEVEL_WPA2; - } else { - pr_debug("%s: TKIP selected, WPA forced\n", __func__); - wl->group_cipher_method = GELIC_WL_CIPHER_TKIP; - wl->pairwise_cipher_method = GELIC_WL_CIPHER_TKIP; - /* FIXME: how do we do if WPA2 + TKIP? */ - wl->wpa_level = GELIC_WL_WPA_LEVEL_WPA; - } - if (flags & IW_ENCODE_RESTRICTED) - BUG(); - wl->auth_method = GELIC_EURUS_AUTH_OPEN; - /* We should use same key for both and unicast */ - if (ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) - pr_debug("%s: group key \n", __func__); - else - pr_debug("%s: unicast key \n", __func__); - /* OK, update the key */ - wl->key_len[key_index] = ext->key_len; - memset(wl->key[key_index], 0, IW_ENCODING_TOKEN_MAX); - memcpy(wl->key[key_index], ext->key, ext->key_len); - set_bit(key_index, &wl->key_enabled); - /* remember info changed */ - set_bit(GELIC_WL_STAT_CONFIGURED, &wl->stat); + memset(wl->psk, 0, sizeof(wl->psk)); + memcpy(wl->psk, ext->key, ext->key_len); + wl->psk_len = ext->key_len; + wl->psk_type = GELIC_EURUS_WPA_PSK_BIN; + /* remember PSK configured */ + set_bit(GELIC_WL_STAT_WPA_PSK_SET, &wl->stat); } done: spin_unlock_irqrestore(&wl->lock, irqflag); @@ -1397,6 +1394,7 @@ static int gelic_wl_get_mode(struct net_device *netdev, return 0; } +#ifdef CONFIG_GELIC_WIRELESS_OLD_PSK_INTERFACE /* SIOCIWFIRSTPRIV */ static int hex2bin(u8 *str, u8 *bin, unsigned int len) { @@ -1501,6 +1499,7 @@ static int gelic_wl_priv_get_psk(struct net_device *net_dev, pr_debug("%s:-> %d\n", __func__, data->data.length); return 0; } +#endif /* SIOCGIWNICKN */ static int gelic_wl_get_nick(struct net_device *net_dev, @@ -1524,15 +1523,20 @@ static struct iw_statistics *gelic_wl_get_wireless_stats( struct gelic_eurus_cmd *cmd; struct iw_statistics *is; struct gelic_eurus_rssi_info *rssi; + void *buf; pr_debug("%s: <-\n", __func__); + buf = (void *)__get_free_page(GFP_KERNEL); + if (!buf) + return NULL; + is = &wl->iwstat; memset(is, 0, sizeof(*is)); cmd = gelic_eurus_sync_cmd(wl, GELIC_EURUS_CMD_GET_RSSI_CFG, - wl->buf, sizeof(*rssi)); + buf, sizeof(*rssi)); if (cmd && !cmd->status && !cmd->cmd_status) { - rssi = wl->buf; + rssi = buf; is->qual.level = be16_to_cpu(rssi->rssi); is->qual.updated = IW_QUAL_LEVEL_UPDATED | IW_QUAL_QUAL_INVALID | IW_QUAL_NOISE_INVALID; @@ -1541,6 +1545,7 @@ static struct iw_statistics *gelic_wl_get_wireless_stats( is->qual.updated = IW_QUAL_ALL_INVALID; kfree(cmd); + free_page((unsigned long)buf); pr_debug("%s: ->\n", __func__); return is; } @@ -1548,13 +1553,16 @@ static struct iw_statistics *gelic_wl_get_wireless_stats( /* * scanning helpers */ -static int gelic_wl_start_scan(struct gelic_wl_info *wl, int always_scan) +static int gelic_wl_start_scan(struct gelic_wl_info *wl, int always_scan, + u8 *essid, size_t essid_len) { struct gelic_eurus_cmd *cmd; int ret = 0; + void *buf = NULL; + size_t len; pr_debug("%s: <- always=%d\n", __func__, always_scan); - if (down_interruptible(&wl->scan_lock)) + if (mutex_lock_interruptible(&wl->scan_lock)) return -ERESTARTSYS; /* @@ -1574,12 +1582,27 @@ static int gelic_wl_start_scan(struct gelic_wl_info *wl, int always_scan) complete(&wl->scan_done); goto out; } + + /* ESSID scan ? */ + if (essid_len && essid) { + buf = (void *)__get_free_page(GFP_KERNEL); + if (!buf) { + ret = -ENOMEM; + goto out; + } + len = IW_ESSID_MAX_SIZE; /* hypervisor always requires 32 */ + memset(buf, 0, len); + memcpy(buf, essid, essid_len); + pr_debug("%s: essid scan='%s'\n", __func__, (char *)buf); + } else + len = 0; + /* * issue start scan request */ wl->scan_stat = GELIC_WL_SCAN_STAT_SCANNING; cmd = gelic_eurus_sync_cmd(wl, GELIC_EURUS_CMD_START_SCAN, - NULL, 0); + buf, len); if (!cmd || cmd->status || cmd->cmd_status) { wl->scan_stat = GELIC_WL_SCAN_STAT_INIT; complete(&wl->scan_done); @@ -1588,7 +1611,8 @@ static int gelic_wl_start_scan(struct gelic_wl_info *wl, int always_scan) } kfree(cmd); out: - up(&wl->scan_lock); + free_page((unsigned long)buf); + mutex_unlock(&wl->scan_lock); pr_debug("%s: ->\n", __func__); return ret; } @@ -1607,10 +1631,17 @@ static void gelic_wl_scan_complete_event(struct gelic_wl_info *wl) union iwreq_data data; unsigned long this_time = jiffies; unsigned int data_len, i, found, r; + void *buf; DECLARE_MAC_BUF(mac); pr_debug("%s:start\n", __func__); - down(&wl->scan_lock); + mutex_lock(&wl->scan_lock); + + buf = (void *)__get_free_page(GFP_KERNEL); + if (!buf) { + pr_info("%s: scan buffer alloc failed\n", __func__); + goto out; + } if (wl->scan_stat != GELIC_WL_SCAN_STAT_SCANNING) { /* @@ -1622,7 +1653,7 @@ static void gelic_wl_scan_complete_event(struct gelic_wl_info *wl) } cmd = gelic_eurus_sync_cmd(wl, GELIC_EURUS_CMD_GET_SCAN, - wl->buf, PAGE_SIZE); + buf, PAGE_SIZE); if (!cmd || cmd->status || cmd->cmd_status) { wl->scan_stat = GELIC_WL_SCAN_STAT_INIT; pr_info("%s:cmd failed\n", __func__); @@ -1649,7 +1680,7 @@ static void gelic_wl_scan_complete_event(struct gelic_wl_info *wl) } /* put them in the newtork_list */ - for (i = 0, scan_info_size = 0, scan_info = wl->buf; + for (i = 0, scan_info_size = 0, scan_info = buf; scan_info_size < data_len; i++, scan_info_size += be16_to_cpu(scan_info->size), scan_info = (void *)scan_info + be16_to_cpu(scan_info->size)) { @@ -1726,8 +1757,9 @@ static void gelic_wl_scan_complete_event(struct gelic_wl_info *wl) wireless_send_event(port_to_netdev(wl_port(wl)), SIOCGIWSCAN, &data, NULL); out: + free_page((unsigned long)buf); complete(&wl->scan_done); - up(&wl->scan_lock); + mutex_unlock(&wl->scan_lock); pr_debug("%s:end\n", __func__); } @@ -1848,7 +1880,10 @@ static int gelic_wl_do_wep_setup(struct gelic_wl_info *wl) pr_debug("%s: <-\n", __func__); /* we can assume no one should uses the buffer */ - wep = wl->buf; + wep = (struct gelic_eurus_wep_cfg *)__get_free_page(GFP_KERNEL); + if (!wep) + return -ENOMEM; + memset(wep, 0, sizeof(*wep)); if (wl->group_cipher_method == GELIC_WL_CIPHER_WEP) { @@ -1898,6 +1933,7 @@ static int gelic_wl_do_wep_setup(struct gelic_wl_info *wl) kfree(cmd); out: + free_page((unsigned long)wep); pr_debug("%s: ->\n", __func__); return ret; } @@ -1941,7 +1977,10 @@ static int gelic_wl_do_wpa_setup(struct gelic_wl_info *wl) pr_debug("%s: <-\n", __func__); /* we can assume no one should uses the buffer */ - wpa = wl->buf; + wpa = (struct gelic_eurus_wpa_cfg *)__get_free_page(GFP_KERNEL); + if (!wpa) + return -ENOMEM; + memset(wpa, 0, sizeof(*wpa)); if (!test_bit(GELIC_WL_STAT_WPA_PSK_SET, &wl->stat)) @@ -2000,6 +2039,7 @@ static int gelic_wl_do_wpa_setup(struct gelic_wl_info *wl) else if (cmd->status || cmd->cmd_status) ret = -ENXIO; kfree(cmd); + free_page((unsigned long)wpa); pr_debug("%s: --> %d\n", __func__, ret); return ret; } @@ -2018,7 +2058,10 @@ static int gelic_wl_associate_bss(struct gelic_wl_info *wl, pr_debug("%s: <-\n", __func__); /* do common config */ - common = wl->buf; + common = (struct gelic_eurus_common_cfg *)__get_free_page(GFP_KERNEL); + if (!common) + return -ENOMEM; + memset(common, 0, sizeof(*common)); common->bss_type = cpu_to_be16(GELIC_EURUS_BSS_INFRA); common->op_mode = cpu_to_be16(GELIC_EURUS_OPMODE_11BG); @@ -2104,6 +2147,7 @@ static int gelic_wl_associate_bss(struct gelic_wl_info *wl, pr_info("%s: connected\n", __func__); } out: + free_page((unsigned long)common); pr_debug("%s: ->\n", __func__); return ret; } @@ -2151,7 +2195,7 @@ static void gelic_wl_disconnect_event(struct gelic_wl_info *wl, * As it waits with timeout, just leave assoc_done * uncompleted, then it terminates with timeout */ - if (down_trylock(&wl->assoc_stat_lock)) { + if (!mutex_trylock(&wl->assoc_stat_lock)) { pr_debug("%s: already locked\n", __func__); lock = 0; } else { @@ -2170,7 +2214,7 @@ static void gelic_wl_disconnect_event(struct gelic_wl_info *wl, netif_carrier_off(port_to_netdev(wl_port(wl))); if (lock) - up(&wl->assoc_stat_lock); + mutex_unlock(&wl->assoc_stat_lock); } /* * event worker @@ -2255,15 +2299,30 @@ static void gelic_wl_assoc_worker(struct work_struct *work) struct gelic_wl_scan_info *best_bss; int ret; + unsigned long irqflag; + u8 *essid; + size_t essid_len; wl = container_of(work, struct gelic_wl_info, assoc_work.work); - down(&wl->assoc_stat_lock); + mutex_lock(&wl->assoc_stat_lock); if (wl->assoc_stat != GELIC_WL_ASSOC_STAT_DISCONN) goto out; - ret = gelic_wl_start_scan(wl, 0); + spin_lock_irqsave(&wl->lock, irqflag); + if (test_bit(GELIC_WL_STAT_ESSID_SET, &wl->stat)) { + pr_debug("%s: assoc ESSID configured %s\n", __func__, + wl->essid); + essid = wl->essid; + essid_len = wl->essid_len; + } else { + essid = NULL; + essid_len = 0; + } + spin_unlock_irqrestore(&wl->lock, irqflag); + + ret = gelic_wl_start_scan(wl, 0, essid, essid_len); if (ret == -ERESTARTSYS) { pr_debug("%s: scan start failed association\n", __func__); schedule_delayed_work(&wl->assoc_work, HZ/10); /*FIXME*/ @@ -2282,7 +2341,7 @@ static void gelic_wl_assoc_worker(struct work_struct *work) wait_for_completion(&wl->scan_done); pr_debug("%s: scan done\n", __func__); - down(&wl->scan_lock); + mutex_lock(&wl->scan_lock); if (wl->scan_stat != GELIC_WL_SCAN_STAT_GOT_LIST) { gelic_wl_send_iwap_event(wl, NULL); pr_info("%s: no scan list. association failed\n", __func__); @@ -2302,9 +2361,9 @@ static void gelic_wl_assoc_worker(struct work_struct *work) if (ret) pr_info("%s: association failed %d\n", __func__, ret); scan_lock_out: - up(&wl->scan_lock); + mutex_unlock(&wl->scan_lock); out: - up(&wl->assoc_stat_lock); + mutex_unlock(&wl->assoc_stat_lock); } /* * Interrupt handler @@ -2351,6 +2410,7 @@ static const iw_handler gelic_wl_wext_handler[] = IW_IOCTL(SIOCGIWNICKN) = gelic_wl_get_nick, }; +#ifdef CONFIG_GELIC_WIRELESS_OLD_PSK_INTERFACE static struct iw_priv_args gelic_wl_private_args[] = { { @@ -2372,15 +2432,18 @@ static const iw_handler gelic_wl_private_handler[] = gelic_wl_priv_set_psk, gelic_wl_priv_get_psk, }; +#endif static const struct iw_handler_def gelic_wl_wext_handler_def = { .num_standard = ARRAY_SIZE(gelic_wl_wext_handler), .standard = gelic_wl_wext_handler, .get_wireless_stats = gelic_wl_get_wireless_stats, +#ifdef CONFIG_GELIC_WIRELESS_OLD_PSK_INTERFACE .num_private = ARRAY_SIZE(gelic_wl_private_handler), .num_private_args = ARRAY_SIZE(gelic_wl_private_args), .private = gelic_wl_private_handler, .private_args = gelic_wl_private_args, +#endif }; static struct net_device *gelic_wl_alloc(struct gelic_card *card) @@ -2431,8 +2494,8 @@ static struct net_device *gelic_wl_alloc(struct gelic_card *card) INIT_DELAYED_WORK(&wl->event_work, gelic_wl_event_worker); INIT_DELAYED_WORK(&wl->assoc_work, gelic_wl_assoc_worker); - init_MUTEX(&wl->scan_lock); - init_MUTEX(&wl->assoc_stat_lock); + mutex_init(&wl->scan_lock); + mutex_init(&wl->assoc_stat_lock); init_completion(&wl->scan_done); /* for the case that no scan request is issued and stop() is called */ @@ -2446,16 +2509,9 @@ static struct net_device *gelic_wl_alloc(struct gelic_card *card) BUILD_BUG_ON(PAGE_SIZE < sizeof(struct gelic_eurus_scan_info) * GELIC_EURUS_MAX_SCAN); - wl->buf = (void *)get_zeroed_page(GFP_KERNEL); - if (!wl->buf) { - pr_info("%s:buffer allocation failed\n", __func__); - goto fail_getpage; - } pr_debug("%s:end\n", __func__); return netdev; -fail_getpage: - destroy_workqueue(wl->event_queue); fail_event_workqueue: destroy_workqueue(wl->eurus_cmd_queue); fail_cmd_workqueue: @@ -2474,8 +2530,6 @@ static void gelic_wl_free(struct gelic_wl_info *wl) pr_debug("%s: <-\n", __func__); - free_page((unsigned long)wl->buf); - pr_debug("%s: destroy queues\n", __func__); destroy_workqueue(wl->eurus_cmd_queue); destroy_workqueue(wl->event_queue); diff --git a/drivers/net/ps3_gelic_wireless.h b/drivers/net/ps3_gelic_wireless.h index 103697166720..5339e0078d18 100644 --- a/drivers/net/ps3_gelic_wireless.h +++ b/drivers/net/ps3_gelic_wireless.h @@ -241,7 +241,7 @@ enum gelic_wl_assoc_state { #define GELIC_WEP_KEYS 4 struct gelic_wl_info { /* bss list */ - struct semaphore scan_lock; + struct mutex scan_lock; struct list_head network_list; struct list_head network_free_list; struct gelic_wl_scan_info *networks; @@ -266,7 +266,7 @@ struct gelic_wl_info { enum gelic_wl_wpa_level wpa_level; /* wpa/wpa2 */ /* association handling */ - struct semaphore assoc_stat_lock; + struct mutex assoc_stat_lock; struct delayed_work assoc_work; enum gelic_wl_assoc_state assoc_stat; struct completion assoc_done; @@ -288,9 +288,6 @@ struct gelic_wl_info { u8 active_bssid[ETH_ALEN]; /* associated bssid */ unsigned int essid_len; - /* buffer for hypervisor IO */ - void *buf; - struct iw_public_data wireless_data; struct iw_statistics iwstat; }; diff --git a/drivers/net/qla3xxx.c b/drivers/net/qla3xxx.c index bccee68bd48a..e7d48a352beb 100644 --- a/drivers/net/qla3xxx.c +++ b/drivers/net/qla3xxx.c @@ -1437,9 +1437,9 @@ static void ql_phy_start_neg_ex(struct ql3_adapter *qdev) reg &= ~PHY_GIG_ALL_PARAMS; if(portConfiguration & PORT_CONFIG_1000MB_SPEED) { - if(portConfiguration & PORT_CONFIG_FULL_DUPLEX_ENABLED) + if(portConfiguration & PORT_CONFIG_FULL_DUPLEX_ENABLED) reg |= PHY_GIG_ADV_1000F; - else + else reg |= PHY_GIG_ADV_1000H; } diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c index 657242504621..cfe8829ed31f 100644 --- a/drivers/net/r8169.c +++ b/drivers/net/r8169.c @@ -28,13 +28,7 @@ #include <asm/io.h> #include <asm/irq.h> -#ifdef CONFIG_R8169_NAPI -#define NAPI_SUFFIX "-NAPI" -#else -#define NAPI_SUFFIX "" -#endif - -#define RTL8169_VERSION "2.2LK" NAPI_SUFFIX +#define RTL8169_VERSION "2.3LK-NAPI" #define MODULENAME "r8169" #define PFX MODULENAME ": " @@ -57,16 +51,6 @@ #define TX_BUFFS_AVAIL(tp) \ (tp->dirty_tx + NUM_TX_DESC - tp->cur_tx - 1) -#ifdef CONFIG_R8169_NAPI -#define rtl8169_rx_skb netif_receive_skb -#define rtl8169_rx_hwaccel_skb vlan_hwaccel_receive_skb -#define rtl8169_rx_quota(count, quota) min(count, quota) -#else -#define rtl8169_rx_skb netif_rx -#define rtl8169_rx_hwaccel_skb vlan_hwaccel_rx -#define rtl8169_rx_quota(count, quota) count -#endif - /* Maximum events (Rx packets, etc.) to handle at each interrupt. */ static const int max_interrupt_work = 20; @@ -394,9 +378,7 @@ struct rtl8169_private { void __iomem *mmio_addr; /* memory map physical address */ struct pci_dev *pci_dev; /* Index of PCI device */ struct net_device *dev; -#ifdef CONFIG_R8169_NAPI struct napi_struct napi; -#endif spinlock_t lock; /* spin lock flag */ u32 msg_enable; int chipset; @@ -458,10 +440,7 @@ static int rtl8169_rx_interrupt(struct net_device *, struct rtl8169_private *, static int rtl8169_change_mtu(struct net_device *dev, int new_mtu); static void rtl8169_down(struct net_device *dev); static void rtl8169_rx_clear(struct rtl8169_private *tp); - -#ifdef CONFIG_R8169_NAPI static int rtl8169_poll(struct napi_struct *napi, int budget); -#endif static const unsigned int rtl8169_rx_config = (RX_FIFO_THRESH << RxCfgFIFOShift) | (RX_DMA_BURST << RxCfgDMAShift); @@ -843,10 +822,11 @@ static int rtl8169_rx_vlan_skb(struct rtl8169_private *tp, struct RxDesc *desc, struct sk_buff *skb) { u32 opts2 = le32_to_cpu(desc->opts2); + struct vlan_group *vlgrp = tp->vlgrp; int ret; - if (tp->vlgrp && (opts2 & RxVlanTag)) { - rtl8169_rx_hwaccel_skb(skb, tp->vlgrp, swab16(opts2 & 0xffff)); + if (vlgrp && (opts2 & RxVlanTag)) { + vlan_hwaccel_receive_skb(skb, vlgrp, swab16(opts2 & 0xffff)); ret = 0; } else ret = -1; @@ -1764,9 +1744,7 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) dev->change_mtu = rtl8169_change_mtu; dev->set_mac_address = rtl_set_mac_address; -#ifdef CONFIG_R8169_NAPI netif_napi_add(dev, &tp->napi, rtl8169_poll, R8169_NAPI_WEIGHT); -#endif #ifdef CONFIG_R8169_VLAN dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX; @@ -1887,9 +1865,7 @@ static int rtl8169_open(struct net_device *dev) if (retval < 0) goto err_release_ring_2; -#ifdef CONFIG_R8169_NAPI napi_enable(&tp->napi); -#endif rtl_hw_start(dev); @@ -2197,9 +2173,7 @@ static int rtl8169_change_mtu(struct net_device *dev, int new_mtu) if (ret < 0) goto out; -#ifdef CONFIG_R8169_NAPI napi_enable(&tp->napi); -#endif rtl_hw_start(dev); @@ -2391,17 +2365,13 @@ static void rtl8169_wait_for_quiescence(struct net_device *dev) synchronize_irq(dev->irq); /* Wait for any pending NAPI task to complete */ -#ifdef CONFIG_R8169_NAPI napi_disable(&tp->napi); -#endif rtl8169_irq_mask_and_ack(ioaddr); -#ifdef CONFIG_R8169_NAPI tp->intr_mask = 0xffff; RTL_W16(IntrMask, tp->intr_event); napi_enable(&tp->napi); -#endif } static void rtl8169_reinit_task(struct work_struct *work) @@ -2767,7 +2737,7 @@ static int rtl8169_rx_interrupt(struct net_device *dev, cur_rx = tp->cur_rx; rx_left = NUM_RX_DESC + tp->dirty_rx - cur_rx; - rx_left = rtl8169_rx_quota(rx_left, budget); + rx_left = min(rx_left, budget); for (; rx_left > 0; rx_left--, cur_rx++) { unsigned int entry = cur_rx % NUM_RX_DESC; @@ -2829,7 +2799,7 @@ static int rtl8169_rx_interrupt(struct net_device *dev, skb->protocol = eth_type_trans(skb, dev); if (rtl8169_rx_vlan_skb(tp, desc, skb) < 0) - rtl8169_rx_skb(skb); + netif_receive_skb(skb); dev->last_rx = jiffies; dev->stats.rx_bytes += pkt_size; @@ -2869,87 +2839,61 @@ static irqreturn_t rtl8169_interrupt(int irq, void *dev_instance) { struct net_device *dev = dev_instance; struct rtl8169_private *tp = netdev_priv(dev); - int boguscnt = max_interrupt_work; void __iomem *ioaddr = tp->mmio_addr; - int status; int handled = 0; + int status; - do { - status = RTL_R16(IntrStatus); + status = RTL_R16(IntrStatus); - /* hotplug/major error/no more work/shared irq */ - if ((status == 0xFFFF) || !status) - break; + /* hotplug/major error/no more work/shared irq */ + if ((status == 0xffff) || !status) + goto out; - handled = 1; + handled = 1; - if (unlikely(!netif_running(dev))) { - rtl8169_asic_down(ioaddr); - goto out; - } + if (unlikely(!netif_running(dev))) { + rtl8169_asic_down(ioaddr); + goto out; + } - status &= tp->intr_mask; - RTL_W16(IntrStatus, - (status & RxFIFOOver) ? (status | RxOverflow) : status); + status &= tp->intr_mask; + RTL_W16(IntrStatus, + (status & RxFIFOOver) ? (status | RxOverflow) : status); - if (!(status & tp->intr_event)) - break; + if (!(status & tp->intr_event)) + goto out; - /* Work around for rx fifo overflow */ - if (unlikely(status & RxFIFOOver) && - (tp->mac_version == RTL_GIGA_MAC_VER_11)) { - netif_stop_queue(dev); - rtl8169_tx_timeout(dev); - break; - } + /* Work around for rx fifo overflow */ + if (unlikely(status & RxFIFOOver) && + (tp->mac_version == RTL_GIGA_MAC_VER_11)) { + netif_stop_queue(dev); + rtl8169_tx_timeout(dev); + goto out; + } - if (unlikely(status & SYSErr)) { - rtl8169_pcierr_interrupt(dev); - break; - } + if (unlikely(status & SYSErr)) { + rtl8169_pcierr_interrupt(dev); + goto out; + } - if (status & LinkChg) - rtl8169_check_link_status(dev, tp, ioaddr); + if (status & LinkChg) + rtl8169_check_link_status(dev, tp, ioaddr); -#ifdef CONFIG_R8169_NAPI - if (status & tp->napi_event) { - RTL_W16(IntrMask, tp->intr_event & ~tp->napi_event); - tp->intr_mask = ~tp->napi_event; + if (status & tp->napi_event) { + RTL_W16(IntrMask, tp->intr_event & ~tp->napi_event); + tp->intr_mask = ~tp->napi_event; if (likely(netif_rx_schedule_prep(dev, &tp->napi))) __netif_rx_schedule(dev, &tp->napi); - else if (netif_msg_intr(tp)) { - printk(KERN_INFO "%s: interrupt %04x in poll\n", - dev->name, status); - } + else if (netif_msg_intr(tp)) { + printk(KERN_INFO "%s: interrupt %04x in poll\n", + dev->name, status); } - break; -#else - /* Rx interrupt */ - if (status & (RxOK | RxOverflow | RxFIFOOver)) - rtl8169_rx_interrupt(dev, tp, ioaddr, ~(u32)0); - - /* Tx interrupt */ - if (status & (TxOK | TxErr)) - rtl8169_tx_interrupt(dev, tp, ioaddr); -#endif - - boguscnt--; - } while (boguscnt > 0); - - if (boguscnt <= 0) { - if (netif_msg_intr(tp) && net_ratelimit() ) { - printk(KERN_WARNING - "%s: Too much work at interrupt!\n", dev->name); - } - /* Clear all interrupt sources. */ - RTL_W16(IntrStatus, 0xffff); } out: return IRQ_RETVAL(handled); } -#ifdef CONFIG_R8169_NAPI static int rtl8169_poll(struct napi_struct *napi, int budget) { struct rtl8169_private *tp = container_of(napi, struct rtl8169_private, napi); @@ -2975,7 +2919,6 @@ static int rtl8169_poll(struct napi_struct *napi, int budget) return work_done; } -#endif static void rtl8169_down(struct net_device *dev) { @@ -2987,9 +2930,7 @@ static void rtl8169_down(struct net_device *dev) netif_stop_queue(dev); -#ifdef CONFIG_R8169_NAPI napi_disable(&tp->napi); -#endif core_down: spin_lock_irq(&tp->lock); @@ -3098,8 +3039,10 @@ static void rtl_set_rx_mode(struct net_device *dev) (tp->mac_version == RTL_GIGA_MAC_VER_15) || (tp->mac_version == RTL_GIGA_MAC_VER_16) || (tp->mac_version == RTL_GIGA_MAC_VER_17)) { - mc_filter[0] = 0xffffffff; - mc_filter[1] = 0xffffffff; + u32 data = mc_filter[0]; + + mc_filter[0] = swab32(mc_filter[1]); + mc_filter[1] = swab32(data); } RTL_W32(MAR0 + 0, mc_filter[0]); diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c index ae7b697456b4..9dae40ccf048 100644 --- a/drivers/net/s2io.c +++ b/drivers/net/s2io.c @@ -86,7 +86,7 @@ #include "s2io.h" #include "s2io-regs.h" -#define DRV_VERSION "2.0.26.24" +#define DRV_VERSION "2.0.26.25" /* S2io Driver name & version. */ static char s2io_driver_name[] = "Neterion"; @@ -545,91 +545,63 @@ static struct pci_driver s2io_driver = { /* netqueue manipulation helper functions */ static inline void s2io_stop_all_tx_queue(struct s2io_nic *sp) { - int i; -#ifdef CONFIG_NETDEVICES_MULTIQUEUE - if (sp->config.multiq) { - for (i = 0; i < sp->config.tx_fifo_num; i++) - netif_stop_subqueue(sp->dev, i); - } else -#endif - { + if (!sp->config.multiq) { + int i; + for (i = 0; i < sp->config.tx_fifo_num; i++) sp->mac_control.fifos[i].queue_state = FIFO_QUEUE_STOP; - netif_stop_queue(sp->dev); } + netif_tx_stop_all_queues(sp->dev); } static inline void s2io_stop_tx_queue(struct s2io_nic *sp, int fifo_no) { -#ifdef CONFIG_NETDEVICES_MULTIQUEUE - if (sp->config.multiq) - netif_stop_subqueue(sp->dev, fifo_no); - else -#endif - { + if (!sp->config.multiq) sp->mac_control.fifos[fifo_no].queue_state = FIFO_QUEUE_STOP; - netif_stop_queue(sp->dev); - } + + netif_tx_stop_all_queues(sp->dev); } static inline void s2io_start_all_tx_queue(struct s2io_nic *sp) { - int i; -#ifdef CONFIG_NETDEVICES_MULTIQUEUE - if (sp->config.multiq) { - for (i = 0; i < sp->config.tx_fifo_num; i++) - netif_start_subqueue(sp->dev, i); - } else -#endif - { + if (!sp->config.multiq) { + int i; + for (i = 0; i < sp->config.tx_fifo_num; i++) sp->mac_control.fifos[i].queue_state = FIFO_QUEUE_START; - netif_start_queue(sp->dev); } + netif_tx_start_all_queues(sp->dev); } static inline void s2io_start_tx_queue(struct s2io_nic *sp, int fifo_no) { -#ifdef CONFIG_NETDEVICES_MULTIQUEUE - if (sp->config.multiq) - netif_start_subqueue(sp->dev, fifo_no); - else -#endif - { + if (!sp->config.multiq) sp->mac_control.fifos[fifo_no].queue_state = FIFO_QUEUE_START; - netif_start_queue(sp->dev); - } + + netif_tx_start_all_queues(sp->dev); } static inline void s2io_wake_all_tx_queue(struct s2io_nic *sp) { - int i; -#ifdef CONFIG_NETDEVICES_MULTIQUEUE - if (sp->config.multiq) { - for (i = 0; i < sp->config.tx_fifo_num; i++) - netif_wake_subqueue(sp->dev, i); - } else -#endif - { + if (!sp->config.multiq) { + int i; + for (i = 0; i < sp->config.tx_fifo_num; i++) sp->mac_control.fifos[i].queue_state = FIFO_QUEUE_START; - netif_wake_queue(sp->dev); } + netif_tx_wake_all_queues(sp->dev); } static inline void s2io_wake_tx_queue( struct fifo_info *fifo, int cnt, u8 multiq) { -#ifdef CONFIG_NETDEVICES_MULTIQUEUE if (multiq) { if (cnt && __netif_subqueue_stopped(fifo->dev, fifo->fifo_no)) netif_wake_subqueue(fifo->dev, fifo->fifo_no); - } else -#endif - if (cnt && (fifo->queue_state == FIFO_QUEUE_STOP)) { + } else if (cnt && (fifo->queue_state == FIFO_QUEUE_STOP)) { if (netif_queue_stopped(fifo->dev)) { fifo->queue_state = FIFO_QUEUE_START; netif_wake_queue(fifo->dev); @@ -1909,8 +1881,6 @@ static int init_nic(struct s2io_nic *nic) static int s2io_link_fault_indication(struct s2io_nic *nic) { - if (nic->config.intr_type != INTA) - return MAC_RMAC_ERR_TIMER; if (nic->device_type == XFRAME_II_DEVICE) return LINK_UP_DOWN_INTERRUPT; else @@ -1943,7 +1913,9 @@ static void en_dis_err_alarms(struct s2io_nic *nic, u16 mask, int flag) { struct XENA_dev_config __iomem *bar0 = nic->bar0; register u64 gen_int_mask = 0; + u64 interruptible; + writeq(DISABLE_ALL_INTRS, &bar0->general_int_mask); if (mask & TX_DMA_INTR) { gen_int_mask |= TXDMA_INT_M; @@ -2033,10 +2005,12 @@ static void en_dis_err_alarms(struct s2io_nic *nic, u16 mask, int flag) gen_int_mask |= RXMAC_INT_M; do_s2io_write_bits(MAC_INT_STATUS_RMAC_INT, flag, &bar0->mac_int_mask); - do_s2io_write_bits(RMAC_RX_BUFF_OVRN | RMAC_RX_SM_ERR | + interruptible = RMAC_RX_BUFF_OVRN | RMAC_RX_SM_ERR | RMAC_UNUSED_INT | RMAC_SINGLE_ECC_ERR | - RMAC_DOUBLE_ECC_ERR | - RMAC_LINK_STATE_CHANGE_INT, + RMAC_DOUBLE_ECC_ERR; + if (s2io_link_fault_indication(nic) == MAC_RMAC_ERR_TIMER) + interruptible |= RMAC_LINK_STATE_CHANGE_INT; + do_s2io_write_bits(interruptible, flag, &bar0->mac_rmac_err_mask); } @@ -2519,6 +2493,9 @@ static void stop_nic(struct s2io_nic *nic) /** * fill_rx_buffers - Allocates the Rx side skbs * @ring_info: per ring structure + * @from_card_up: If this is true, we will map the buffer to get + * the dma address for buf0 and buf1 to give it to the card. + * Else we will sync the already mapped buffer to give it to the card. * Description: * The function allocates Rx side skbs and puts the physical * address of these buffers into the RxD buffer pointers, so that the NIC @@ -2536,7 +2513,7 @@ static void stop_nic(struct s2io_nic *nic) * SUCCESS on success or an appropriate -ve value on failure. */ -static int fill_rx_buffers(struct ring_info *ring) +static int fill_rx_buffers(struct ring_info *ring, int from_card_up) { struct sk_buff *skb; struct RxD_t *rxdp; @@ -2566,7 +2543,7 @@ static int fill_rx_buffers(struct ring_info *ring) if (block_no) rxd_index += (block_no * ring->rxd_count); - if ((block_no == block_no1) && + if ((block_no == block_no1) && (off == ring->rx_curr_get_info.offset) && (rxdp->Host_Control)) { DBG_PRINT(INTR_DBG, "%s: Get and Put", @@ -2612,7 +2589,7 @@ static int fill_rx_buffers(struct ring_info *ring) first_rxdp->Control_1 |= RXD_OWN_XENA; } stats->mem_alloc_fail_cnt++; - + return -ENOMEM ; } stats->mem_allocated += skb->truesize; @@ -2655,17 +2632,16 @@ static int fill_rx_buffers(struct ring_info *ring) skb->data = (void *) (unsigned long)tmp; skb_reset_tail_pointer(skb); - /* AK: check is wrong. 0 can be valid dma address */ - if (!(rxdp3->Buffer0_ptr)) + if (from_card_up) { rxdp3->Buffer0_ptr = pci_map_single(ring->pdev, ba->ba_0, BUF0_LEN, PCI_DMA_FROMDEVICE); - else + if (pci_dma_mapping_error(rxdp3->Buffer0_ptr)) + goto pci_map_failed; + } else pci_dma_sync_single_for_device(ring->pdev, (dma_addr_t) rxdp3->Buffer0_ptr, BUF0_LEN, PCI_DMA_FROMDEVICE); - if (pci_dma_mapping_error(rxdp3->Buffer0_ptr)) - goto pci_map_failed; rxdp->Control_2 = SET_BUFFER0_SIZE_3(BUF0_LEN); if (ring->rxd_mode == RXD_MODE_3B) { @@ -2682,21 +2658,22 @@ static int fill_rx_buffers(struct ring_info *ring) if (pci_dma_mapping_error(rxdp3->Buffer2_ptr)) goto pci_map_failed; - /* AK: check is wrong */ - if (!rxdp3->Buffer1_ptr) + if (from_card_up) { rxdp3->Buffer1_ptr = pci_map_single(ring->pdev, ba->ba_1, BUF1_LEN, PCI_DMA_FROMDEVICE); - if (pci_dma_mapping_error(rxdp3->Buffer1_ptr)) { - pci_unmap_single - (ring->pdev, - (dma_addr_t)(unsigned long) - skb->data, - ring->mtu + 4, - PCI_DMA_FROMDEVICE); - goto pci_map_failed; + if (pci_dma_mapping_error + (rxdp3->Buffer1_ptr)) { + pci_unmap_single + (ring->pdev, + (dma_addr_t)(unsigned long) + skb->data, + ring->mtu + 4, + PCI_DMA_FROMDEVICE); + goto pci_map_failed; + } } rxdp->Control_2 |= SET_BUFFER1_SIZE_3(1); rxdp->Control_2 |= SET_BUFFER2_SIZE_3 @@ -2831,7 +2808,7 @@ static void free_rx_buffers(struct s2io_nic *sp) static int s2io_chk_rx_buffers(struct ring_info *ring) { - if (fill_rx_buffers(ring) == -ENOMEM) { + if (fill_rx_buffers(ring, 0) == -ENOMEM) { DBG_PRINT(INFO_DBG, "%s:Out of memory", ring->dev->name); DBG_PRINT(INFO_DBG, " in Rx Intr!!\n"); } @@ -2962,7 +2939,7 @@ static void s2io_netpoll(struct net_device *dev) rx_intr_handler(&mac_control->rings[i], 0); for (i = 0; i < config->rx_ring_num; i++) { - if (fill_rx_buffers(&mac_control->rings[i]) == -ENOMEM) { + if (fill_rx_buffers(&mac_control->rings[i], 0) == -ENOMEM) { DBG_PRINT(INFO_DBG, "%s:Out of memory", dev->name); DBG_PRINT(INFO_DBG, " in Rx Netpoll!!\n"); break; @@ -4189,15 +4166,12 @@ static int s2io_xmit(struct sk_buff *skb, struct net_device *dev) return NETDEV_TX_LOCKED; } -#ifdef CONFIG_NETDEVICES_MULTIQUEUE if (sp->config.multiq) { if (__netif_subqueue_stopped(dev, fifo->fifo_no)) { spin_unlock_irqrestore(&fifo->tx_lock, flags); return NETDEV_TX_BUSY; } - } else -#endif - if (unlikely(fifo->queue_state == FIFO_QUEUE_STOP)) { + } else if (unlikely(fifo->queue_state == FIFO_QUEUE_STOP)) { if (netif_queue_stopped(dev)) { spin_unlock_irqrestore(&fifo->tx_lock, flags); return NETDEV_TX_BUSY; @@ -4394,18 +4368,24 @@ static irqreturn_t s2io_msix_fifo_handle(int irq, void *dev_id) /* Nothing much can be done. Get out */ return IRQ_HANDLED; - writeq(S2IO_MINUS_ONE, &bar0->general_int_mask); + if (reason & (GEN_INTR_TXPIC | GEN_INTR_TXTRAFFIC)) { + writeq(S2IO_MINUS_ONE, &bar0->general_int_mask); - if (reason & GEN_INTR_TXTRAFFIC) - writeq(S2IO_MINUS_ONE, &bar0->tx_traffic_int); + if (reason & GEN_INTR_TXPIC) + s2io_txpic_intr_handle(sp); - for (i = 0; i < config->tx_fifo_num; i++) - tx_intr_handler(&fifos[i]); + if (reason & GEN_INTR_TXTRAFFIC) + writeq(S2IO_MINUS_ONE, &bar0->tx_traffic_int); - writeq(sp->general_int_mask, &bar0->general_int_mask); - readl(&bar0->general_int_status); + for (i = 0; i < config->tx_fifo_num; i++) + tx_intr_handler(&fifos[i]); - return IRQ_HANDLED; + writeq(sp->general_int_mask, &bar0->general_int_mask); + readl(&bar0->general_int_status); + return IRQ_HANDLED; + } + /* The interrupt was not raised by us */ + return IRQ_NONE; } static void s2io_txpic_intr_handle(struct s2io_nic *sp) @@ -6988,7 +6968,7 @@ static int rxd_owner_bit_reset(struct s2io_nic *sp) &skb,(u64 *)&temp0_64, (u64 *)&temp1_64, (u64 *)&temp2_64, - size) == ENOMEM) { + size) == -ENOMEM) { return 0; } @@ -7133,6 +7113,9 @@ static void do_s2io_card_down(struct s2io_nic * sp, int do_io) s2io_rem_isr(sp); + /* stop the tx queue, indicate link down */ + s2io_link(sp, LINK_DOWN); + /* Check if the device is Quiescent and then Reset the NIC */ while(do_io) { /* As per the HW requirement we need to replenish the @@ -7204,7 +7187,7 @@ static int s2io_card_up(struct s2io_nic * sp) for (i = 0; i < config->rx_ring_num; i++) { mac_control->rings[i].mtu = dev->mtu; - ret = fill_rx_buffers(&mac_control->rings[i]); + ret = fill_rx_buffers(&mac_control->rings[i], 1); if (ret) { DBG_PRINT(ERR_DBG, "%s: Out of memory in Open\n", dev->name); @@ -7265,17 +7248,19 @@ static int s2io_card_up(struct s2io_nic * sp) S2IO_TIMER_CONF(sp->alarm_timer, s2io_alarm_handle, sp, (HZ/2)); + set_bit(__S2IO_STATE_CARD_UP, &sp->state); + /* Enable select interrupts */ en_dis_err_alarms(sp, ENA_ALL_INTRS, ENABLE_INTRS); - if (sp->config.intr_type != INTA) - en_dis_able_nic_intrs(sp, TX_TRAFFIC_INTR, ENABLE_INTRS); - else { + if (sp->config.intr_type != INTA) { + interruptible = TX_TRAFFIC_INTR | TX_PIC_INTR; + en_dis_able_nic_intrs(sp, interruptible, ENABLE_INTRS); + } else { interruptible = TX_TRAFFIC_INTR | RX_TRAFFIC_INTR; interruptible |= TX_PIC_INTR; en_dis_able_nic_intrs(sp, interruptible, ENABLE_INTRS); } - set_bit(__S2IO_STATE_CARD_UP, &sp->state); return 0; } @@ -7633,12 +7618,6 @@ static int s2io_verify_parm(struct pci_dev *pdev, u8 *dev_intr_type, DBG_PRINT(ERR_DBG, "tx fifos\n"); } -#ifndef CONFIG_NETDEVICES_MULTIQUEUE - if (multiq) { - DBG_PRINT(ERR_DBG, "s2io: Multiqueue support not enabled\n"); - multiq = 0; - } -#endif if (multiq) *dev_multiq = multiq; @@ -7783,12 +7762,10 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) pci_disable_device(pdev); return -ENODEV; } -#ifdef CONFIG_NETDEVICES_MULTIQUEUE if (dev_multiq) dev = alloc_etherdev_mq(sizeof(struct s2io_nic), tx_fifo_num); else -#endif - dev = alloc_etherdev(sizeof(struct s2io_nic)); + dev = alloc_etherdev(sizeof(struct s2io_nic)); if (dev == NULL) { DBG_PRINT(ERR_DBG, "Device allocation failed\n"); pci_disable_device(pdev); @@ -7979,10 +7956,6 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) dev->features |= NETIF_F_UFO; dev->features |= NETIF_F_HW_CSUM; } -#ifdef CONFIG_NETDEVICES_MULTIQUEUE - if (config->multiq) - dev->features |= NETIF_F_MULTI_QUEUE; -#endif dev->tx_timeout = &s2io_tx_watchdog; dev->watchdog_timeo = WATCH_DOG_TIMEOUT; INIT_WORK(&sp->rst_timer_task, s2io_restart_nic); @@ -8708,5 +8681,5 @@ static void s2io_io_resume(struct pci_dev *pdev) } netif_device_attach(netdev); - netif_wake_queue(netdev); + netif_tx_wake_all_queues(netdev); } diff --git a/drivers/net/s2io.h b/drivers/net/s2io.h index 1827b6686c98..6722a2f7d091 100644 --- a/drivers/net/s2io.h +++ b/drivers/net/s2io.h @@ -748,7 +748,7 @@ struct ring_info { /* interface MTU value */ unsigned mtu; - + /* Buffer Address store. */ struct buffAdd **ba; @@ -1107,6 +1107,7 @@ static int init_shared_mem(struct s2io_nic *sp); static void free_shared_mem(struct s2io_nic *sp); static int init_nic(struct s2io_nic *nic); static int rx_intr_handler(struct ring_info *ring_data, int budget); +static void s2io_txpic_intr_handle(struct s2io_nic *sp); static void tx_intr_handler(struct fifo_info *fifo_data); static void s2io_handle_errors(void * dev_id); diff --git a/drivers/net/saa9730.c b/drivers/net/saa9730.c deleted file mode 100644 index c65199df8a7f..000000000000 --- a/drivers/net/saa9730.c +++ /dev/null @@ -1,1139 +0,0 @@ -/* - * Copyright (C) 2000, 2005 MIPS Technologies, Inc. All rights reserved. - * Authors: Carsten Langgaard <carstenl@mips.com> - * Maciej W. Rozycki <macro@mips.com> - * Copyright (C) 2004 Ralf Baechle <ralf@linux-mips.org> - * - * This program is free software; you can distribute 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 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. - * - * SAA9730 ethernet driver. - * - * Changes: - * Angelo Dell'Aera <buffer@antifork.org> : Conversion to the new PCI API - * (pci_driver). - * Conversion to spinlocks. - * Error handling fixes. - */ - -#include <linux/init.h> -#include <linux/netdevice.h> -#include <linux/delay.h> -#include <linux/etherdevice.h> -#include <linux/module.h> -#include <linux/skbuff.h> -#include <linux/pci.h> -#include <linux/spinlock.h> -#include <linux/types.h> - -#include <asm/addrspace.h> -#include <asm/io.h> - -#include <asm/mips-boards/prom.h> - -#include "saa9730.h" - -#ifdef LAN_SAA9730_DEBUG -int lan_saa9730_debug = LAN_SAA9730_DEBUG; -#else -int lan_saa9730_debug; -#endif - -#define DRV_MODULE_NAME "saa9730" - -static struct pci_device_id saa9730_pci_tbl[] = { - { PCI_VENDOR_ID_PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA9730, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, - { 0, } -}; - -MODULE_DEVICE_TABLE(pci, saa9730_pci_tbl); - -/* Non-zero only if the current card is a PCI with BIOS-set IRQ. */ -static unsigned int pci_irq_line; - -static void evm_saa9730_enable_lan_int(struct lan_saa9730_private *lp) -{ - writel(readl(&lp->evm_saa9730_regs->InterruptBlock1) | EVM_LAN_INT, - &lp->evm_saa9730_regs->InterruptBlock1); - writel(readl(&lp->evm_saa9730_regs->InterruptStatus1) | EVM_LAN_INT, - &lp->evm_saa9730_regs->InterruptStatus1); - writel(readl(&lp->evm_saa9730_regs->InterruptEnable1) | EVM_LAN_INT | - EVM_MASTER_EN, &lp->evm_saa9730_regs->InterruptEnable1); -} - -static void evm_saa9730_disable_lan_int(struct lan_saa9730_private *lp) -{ - writel(readl(&lp->evm_saa9730_regs->InterruptBlock1) & ~EVM_LAN_INT, - &lp->evm_saa9730_regs->InterruptBlock1); - writel(readl(&lp->evm_saa9730_regs->InterruptEnable1) & ~EVM_LAN_INT, - &lp->evm_saa9730_regs->InterruptEnable1); -} - -static void evm_saa9730_clear_lan_int(struct lan_saa9730_private *lp) -{ - writel(EVM_LAN_INT, &lp->evm_saa9730_regs->InterruptStatus1); -} - -static void evm_saa9730_block_lan_int(struct lan_saa9730_private *lp) -{ - writel(readl(&lp->evm_saa9730_regs->InterruptBlock1) & ~EVM_LAN_INT, - &lp->evm_saa9730_regs->InterruptBlock1); -} - -static void evm_saa9730_unblock_lan_int(struct lan_saa9730_private *lp) -{ - writel(readl(&lp->evm_saa9730_regs->InterruptBlock1) | EVM_LAN_INT, - &lp->evm_saa9730_regs->InterruptBlock1); -} - -static void __used show_saa9730_regs(struct net_device *dev) -{ - struct lan_saa9730_private *lp = netdev_priv(dev); - int i, j; - - printk("TxmBufferA = %p\n", lp->TxmBuffer[0][0]); - printk("TxmBufferB = %p\n", lp->TxmBuffer[1][0]); - printk("RcvBufferA = %p\n", lp->RcvBuffer[0][0]); - printk("RcvBufferB = %p\n", lp->RcvBuffer[1][0]); - - for (i = 0; i < LAN_SAA9730_BUFFERS; i++) { - for (j = 0; j < LAN_SAA9730_TXM_Q_SIZE; j++) { - printk("TxmBuffer[%d][%d] = %x\n", i, j, - le32_to_cpu(*(unsigned int *) - lp->TxmBuffer[i][j])); - } - } - for (i = 0; i < LAN_SAA9730_BUFFERS; i++) { - for (j = 0; j < LAN_SAA9730_RCV_Q_SIZE; j++) { - printk("RcvBuffer[%d][%d] = %x\n", i, j, - le32_to_cpu(*(unsigned int *) - lp->RcvBuffer[i][j])); - } - } - printk("lp->evm_saa9730_regs->InterruptBlock1 = %x\n", - readl(&lp->evm_saa9730_regs->InterruptBlock1)); - printk("lp->evm_saa9730_regs->InterruptStatus1 = %x\n", - readl(&lp->evm_saa9730_regs->InterruptStatus1)); - printk("lp->evm_saa9730_regs->InterruptEnable1 = %x\n", - readl(&lp->evm_saa9730_regs->InterruptEnable1)); - printk("lp->lan_saa9730_regs->Ok2Use = %x\n", - readl(&lp->lan_saa9730_regs->Ok2Use)); - printk("lp->NextTxmBufferIndex = %x\n", lp->NextTxmBufferIndex); - printk("lp->NextTxmPacketIndex = %x\n", lp->NextTxmPacketIndex); - printk("lp->PendingTxmBufferIndex = %x\n", - lp->PendingTxmBufferIndex); - printk("lp->PendingTxmPacketIndex = %x\n", - lp->PendingTxmPacketIndex); - printk("lp->lan_saa9730_regs->LanDmaCtl = %x\n", - readl(&lp->lan_saa9730_regs->LanDmaCtl)); - printk("lp->lan_saa9730_regs->DmaStatus = %x\n", - readl(&lp->lan_saa9730_regs->DmaStatus)); - printk("lp->lan_saa9730_regs->CamCtl = %x\n", - readl(&lp->lan_saa9730_regs->CamCtl)); - printk("lp->lan_saa9730_regs->TxCtl = %x\n", - readl(&lp->lan_saa9730_regs->TxCtl)); - printk("lp->lan_saa9730_regs->TxStatus = %x\n", - readl(&lp->lan_saa9730_regs->TxStatus)); - printk("lp->lan_saa9730_regs->RxCtl = %x\n", - readl(&lp->lan_saa9730_regs->RxCtl)); - printk("lp->lan_saa9730_regs->RxStatus = %x\n", - readl(&lp->lan_saa9730_regs->RxStatus)); - - for (i = 0; i < LAN_SAA9730_CAM_DWORDS; i++) { - writel(i, &lp->lan_saa9730_regs->CamAddress); - printk("lp->lan_saa9730_regs->CamData = %x\n", - readl(&lp->lan_saa9730_regs->CamData)); - } - - printk("dev->stats.tx_packets = %lx\n", dev->stats.tx_packets); - printk("dev->stats.tx_errors = %lx\n", dev->stats.tx_errors); - printk("dev->stats.tx_aborted_errors = %lx\n", - dev->stats.tx_aborted_errors); - printk("dev->stats.tx_window_errors = %lx\n", - dev->stats.tx_window_errors); - printk("dev->stats.tx_carrier_errors = %lx\n", - dev->stats.tx_carrier_errors); - printk("dev->stats.tx_fifo_errors = %lx\n", - dev->stats.tx_fifo_errors); - printk("dev->stats.tx_heartbeat_errors = %lx\n", - dev->stats.tx_heartbeat_errors); - printk("dev->stats.collisions = %lx\n", dev->stats.collisions); - - printk("dev->stats.rx_packets = %lx\n", dev->stats.rx_packets); - printk("dev->stats.rx_errors = %lx\n", dev->stats.rx_errors); - printk("dev->stats.rx_dropped = %lx\n", dev->stats.rx_dropped); - printk("dev->stats.rx_crc_errors = %lx\n", dev->stats.rx_crc_errors); - printk("dev->stats.rx_frame_errors = %lx\n", - dev->stats.rx_frame_errors); - printk("dev->stats.rx_fifo_errors = %lx\n", - dev->stats.rx_fifo_errors); - printk("dev->stats.rx_length_errors = %lx\n", - dev->stats.rx_length_errors); - - printk("lp->lan_saa9730_regs->DebugPCIMasterAddr = %x\n", - readl(&lp->lan_saa9730_regs->DebugPCIMasterAddr)); - printk("lp->lan_saa9730_regs->DebugLanTxStateMachine = %x\n", - readl(&lp->lan_saa9730_regs->DebugLanTxStateMachine)); - printk("lp->lan_saa9730_regs->DebugLanRxStateMachine = %x\n", - readl(&lp->lan_saa9730_regs->DebugLanRxStateMachine)); - printk("lp->lan_saa9730_regs->DebugLanTxFifoPointers = %x\n", - readl(&lp->lan_saa9730_regs->DebugLanTxFifoPointers)); - printk("lp->lan_saa9730_regs->DebugLanRxFifoPointers = %x\n", - readl(&lp->lan_saa9730_regs->DebugLanRxFifoPointers)); - printk("lp->lan_saa9730_regs->DebugLanCtlStateMachine = %x\n", - readl(&lp->lan_saa9730_regs->DebugLanCtlStateMachine)); -} - -static void lan_saa9730_buffer_init(struct lan_saa9730_private *lp) -{ - int i, j; - - /* Init RX buffers */ - for (i = 0; i < LAN_SAA9730_BUFFERS; i++) { - for (j = 0; j < LAN_SAA9730_RCV_Q_SIZE; j++) { - *(unsigned int *) lp->RcvBuffer[i][j] = - cpu_to_le32(RXSF_READY << - RX_STAT_CTL_OWNER_SHF); - } - } - - /* Init TX buffers */ - for (i = 0; i < LAN_SAA9730_BUFFERS; i++) { - for (j = 0; j < LAN_SAA9730_TXM_Q_SIZE; j++) { - *(unsigned int *) lp->TxmBuffer[i][j] = - cpu_to_le32(TXSF_EMPTY << - TX_STAT_CTL_OWNER_SHF); - } - } -} - -static void lan_saa9730_free_buffers(struct pci_dev *pdev, - struct lan_saa9730_private *lp) -{ - pci_free_consistent(pdev, lp->buffer_size, lp->buffer_start, - lp->dma_addr); -} - -static int lan_saa9730_allocate_buffers(struct pci_dev *pdev, - struct lan_saa9730_private *lp) -{ - void *Pa; - unsigned int i, j, rxoffset, txoffset; - int ret; - - /* Initialize buffer space */ - lp->DmaRcvPackets = LAN_SAA9730_RCV_Q_SIZE; - lp->DmaTxmPackets = LAN_SAA9730_TXM_Q_SIZE; - - /* Initialize Rx Buffer Index */ - lp->NextRcvPacketIndex = 0; - lp->NextRcvBufferIndex = 0; - - /* Set current buffer index & next available packet index */ - lp->NextTxmPacketIndex = 0; - lp->NextTxmBufferIndex = 0; - lp->PendingTxmPacketIndex = 0; - lp->PendingTxmBufferIndex = 0; - - /* - * Allocate all RX and TX packets in one chunk. - * The Rx and Tx packets must be PACKET_SIZE aligned. - */ - lp->buffer_size = ((LAN_SAA9730_RCV_Q_SIZE + LAN_SAA9730_TXM_Q_SIZE) * - LAN_SAA9730_PACKET_SIZE * LAN_SAA9730_BUFFERS) + - LAN_SAA9730_PACKET_SIZE; - lp->buffer_start = pci_alloc_consistent(pdev, lp->buffer_size, - &lp->dma_addr); - if (!lp->buffer_start) { - ret = -ENOMEM; - goto out; - } - - Pa = (void *)ALIGN((unsigned long)lp->buffer_start, - LAN_SAA9730_PACKET_SIZE); - - rxoffset = Pa - lp->buffer_start; - - /* Init RX buffers */ - for (i = 0; i < LAN_SAA9730_BUFFERS; i++) { - for (j = 0; j < LAN_SAA9730_RCV_Q_SIZE; j++) { - *(unsigned int *) Pa = - cpu_to_le32(RXSF_READY << - RX_STAT_CTL_OWNER_SHF); - lp->RcvBuffer[i][j] = Pa; - Pa += LAN_SAA9730_PACKET_SIZE; - } - } - - txoffset = Pa - lp->buffer_start; - - /* Init TX buffers */ - for (i = 0; i < LAN_SAA9730_BUFFERS; i++) { - for (j = 0; j < LAN_SAA9730_TXM_Q_SIZE; j++) { - *(unsigned int *) Pa = - cpu_to_le32(TXSF_EMPTY << - TX_STAT_CTL_OWNER_SHF); - lp->TxmBuffer[i][j] = Pa; - Pa += LAN_SAA9730_PACKET_SIZE; - } - } - - /* - * Set rx buffer A and rx buffer B to point to the first two buffer - * spaces. - */ - writel(lp->dma_addr + rxoffset, &lp->lan_saa9730_regs->RxBuffA); - writel(lp->dma_addr + rxoffset + - LAN_SAA9730_PACKET_SIZE * LAN_SAA9730_RCV_Q_SIZE, - &lp->lan_saa9730_regs->RxBuffB); - - /* - * Set txm_buf_a and txm_buf_b to point to the first two buffer - * space - */ - writel(lp->dma_addr + txoffset, - &lp->lan_saa9730_regs->TxBuffA); - writel(lp->dma_addr + txoffset + - LAN_SAA9730_PACKET_SIZE * LAN_SAA9730_TXM_Q_SIZE, - &lp->lan_saa9730_regs->TxBuffB); - - /* Set packet number */ - writel((lp->DmaRcvPackets << PK_COUNT_RX_A_SHF) | - (lp->DmaRcvPackets << PK_COUNT_RX_B_SHF) | - (lp->DmaTxmPackets << PK_COUNT_TX_A_SHF) | - (lp->DmaTxmPackets << PK_COUNT_TX_B_SHF), - &lp->lan_saa9730_regs->PacketCount); - - return 0; - -out: - return ret; -} - -static int lan_saa9730_cam_load(struct lan_saa9730_private *lp) -{ - unsigned int i; - unsigned char *NetworkAddress; - - NetworkAddress = (unsigned char *) &lp->PhysicalAddress[0][0]; - - for (i = 0; i < LAN_SAA9730_CAM_DWORDS; i++) { - /* First set address to where data is written */ - writel(i, &lp->lan_saa9730_regs->CamAddress); - writel((NetworkAddress[0] << 24) | (NetworkAddress[1] << 16) | - (NetworkAddress[2] << 8) | NetworkAddress[3], - &lp->lan_saa9730_regs->CamData); - NetworkAddress += 4; - } - return 0; -} - -static int lan_saa9730_cam_init(struct net_device *dev) -{ - struct lan_saa9730_private *lp = netdev_priv(dev); - unsigned int i; - - /* Copy MAC-address into all entries. */ - for (i = 0; i < LAN_SAA9730_CAM_ENTRIES; i++) { - memcpy((unsigned char *) lp->PhysicalAddress[i], - (unsigned char *) dev->dev_addr, 6); - } - - return 0; -} - -static int lan_saa9730_mii_init(struct lan_saa9730_private *lp) -{ - int i, l; - - /* Check link status, spin here till station is not busy. */ - i = 0; - while (readl(&lp->lan_saa9730_regs->StationMgmtCtl) & MD_CA_BUSY) { - i++; - if (i > 100) { - printk("Error: lan_saa9730_mii_init: timeout\n"); - return -1; - } - mdelay(1); /* wait 1 ms. */ - } - - /* Now set the control and address register. */ - writel(MD_CA_BUSY | PHY_STATUS | PHY_ADDRESS << MD_CA_PHY_SHF, - &lp->lan_saa9730_regs->StationMgmtCtl); - - /* check link status, spin here till station is not busy */ - i = 0; - while (readl(&lp->lan_saa9730_regs->StationMgmtCtl) & MD_CA_BUSY) { - i++; - if (i > 100) { - printk("Error: lan_saa9730_mii_init: timeout\n"); - return -1; - } - mdelay(1); /* wait 1 ms. */ - } - - /* Wait for 1 ms. */ - mdelay(1); - - /* Check the link status. */ - if (readl(&lp->lan_saa9730_regs->StationMgmtData) & - PHY_STATUS_LINK_UP) { - /* Link is up. */ - return 0; - } else { - /* Link is down, reset the PHY first. */ - - /* set PHY address = 'CONTROL' */ - writel(PHY_ADDRESS << MD_CA_PHY_SHF | MD_CA_WR | PHY_CONTROL, - &lp->lan_saa9730_regs->StationMgmtCtl); - - /* Wait for 1 ms. */ - mdelay(1); - - /* set 'CONTROL' = force reset and renegotiate */ - writel(PHY_CONTROL_RESET | PHY_CONTROL_AUTO_NEG | - PHY_CONTROL_RESTART_AUTO_NEG, - &lp->lan_saa9730_regs->StationMgmtData); - - /* Wait for 50 ms. */ - mdelay(50); - - /* set 'BUSY' to start operation */ - writel(MD_CA_BUSY | PHY_ADDRESS << MD_CA_PHY_SHF | MD_CA_WR | - PHY_CONTROL, &lp->lan_saa9730_regs->StationMgmtCtl); - - /* await completion */ - i = 0; - while (readl(&lp->lan_saa9730_regs->StationMgmtCtl) & - MD_CA_BUSY) { - i++; - if (i > 100) { - printk - ("Error: lan_saa9730_mii_init: timeout\n"); - return -1; - } - mdelay(1); /* wait 1 ms. */ - } - - /* Wait for 1 ms. */ - mdelay(1); - - for (l = 0; l < 2; l++) { - /* set PHY address = 'STATUS' */ - writel(MD_CA_BUSY | PHY_ADDRESS << MD_CA_PHY_SHF | - PHY_STATUS, - &lp->lan_saa9730_regs->StationMgmtCtl); - - /* await completion */ - i = 0; - while (readl(&lp->lan_saa9730_regs->StationMgmtCtl) & - MD_CA_BUSY) { - i++; - if (i > 100) { - printk - ("Error: lan_saa9730_mii_init: timeout\n"); - return -1; - } - mdelay(1); /* wait 1 ms. */ - } - - /* wait for 3 sec. */ - mdelay(3000); - - /* check the link status */ - if (readl(&lp->lan_saa9730_regs->StationMgmtData) & - PHY_STATUS_LINK_UP) { - /* link is up */ - break; - } - } - } - - return 0; -} - -static int lan_saa9730_control_init(struct lan_saa9730_private *lp) -{ - /* Initialize DMA control register. */ - writel((LANMB_ANY << DMA_CTL_MAX_XFER_SHF) | - (LANEND_LITTLE << DMA_CTL_ENDIAN_SHF) | - (LAN_SAA9730_RCV_Q_INT_THRESHOLD << DMA_CTL_RX_INT_COUNT_SHF) - | DMA_CTL_RX_INT_TO_EN | DMA_CTL_RX_INT_EN | - DMA_CTL_MAC_RX_INT_EN | DMA_CTL_MAC_TX_INT_EN, - &lp->lan_saa9730_regs->LanDmaCtl); - - /* Initial MAC control register. */ - writel((MACCM_MII << MAC_CONTROL_CONN_SHF) | MAC_CONTROL_FULL_DUP, - &lp->lan_saa9730_regs->MacCtl); - - /* Initialize CAM control register. */ - writel(CAM_CONTROL_COMP_EN | CAM_CONTROL_BROAD_ACC, - &lp->lan_saa9730_regs->CamCtl); - - /* - * Initialize CAM enable register, only turn on first entry, should - * contain own addr. - */ - writel(0x0001, &lp->lan_saa9730_regs->CamEnable); - - /* Initialize Tx control register */ - writel(TX_CTL_EN_COMP, &lp->lan_saa9730_regs->TxCtl); - - /* Initialize Rcv control register */ - writel(RX_CTL_STRIP_CRC, &lp->lan_saa9730_regs->RxCtl); - - /* Reset DMA engine */ - writel(DMA_TEST_SW_RESET, &lp->lan_saa9730_regs->DmaTest); - - return 0; -} - -static int lan_saa9730_stop(struct lan_saa9730_private *lp) -{ - int i; - - /* Stop DMA first */ - writel(readl(&lp->lan_saa9730_regs->LanDmaCtl) & - ~(DMA_CTL_EN_TX_DMA | DMA_CTL_EN_RX_DMA), - &lp->lan_saa9730_regs->LanDmaCtl); - - /* Set the SW Reset bits in DMA and MAC control registers */ - writel(DMA_TEST_SW_RESET, &lp->lan_saa9730_regs->DmaTest); - writel(readl(&lp->lan_saa9730_regs->MacCtl) | MAC_CONTROL_RESET, - &lp->lan_saa9730_regs->MacCtl); - - /* - * Wait for MAC reset to have finished. The reset bit is auto cleared - * when the reset is done. - */ - i = 0; - while (readl(&lp->lan_saa9730_regs->MacCtl) & MAC_CONTROL_RESET) { - i++; - if (i > 100) { - printk - ("Error: lan_sa9730_stop: MAC reset timeout\n"); - return -1; - } - mdelay(1); /* wait 1 ms. */ - } - - return 0; -} - -static int lan_saa9730_dma_init(struct lan_saa9730_private *lp) -{ - /* Stop lan controller. */ - lan_saa9730_stop(lp); - - writel(LAN_SAA9730_DEFAULT_TIME_OUT_CNT, - &lp->lan_saa9730_regs->Timeout); - - return 0; -} - -static int lan_saa9730_start(struct lan_saa9730_private *lp) -{ - lan_saa9730_buffer_init(lp); - - /* Initialize Rx Buffer Index */ - lp->NextRcvPacketIndex = 0; - lp->NextRcvBufferIndex = 0; - - /* Set current buffer index & next available packet index */ - lp->NextTxmPacketIndex = 0; - lp->NextTxmBufferIndex = 0; - lp->PendingTxmPacketIndex = 0; - lp->PendingTxmBufferIndex = 0; - - writel(readl(&lp->lan_saa9730_regs->LanDmaCtl) | DMA_CTL_EN_TX_DMA | - DMA_CTL_EN_RX_DMA, &lp->lan_saa9730_regs->LanDmaCtl); - - /* For Tx, turn on MAC then DMA */ - writel(readl(&lp->lan_saa9730_regs->TxCtl) | TX_CTL_TX_EN, - &lp->lan_saa9730_regs->TxCtl); - - /* For Rx, turn on DMA then MAC */ - writel(readl(&lp->lan_saa9730_regs->RxCtl) | RX_CTL_RX_EN, - &lp->lan_saa9730_regs->RxCtl); - - /* Set Ok2Use to let hardware own the buffers. */ - writel(OK2USE_RX_A | OK2USE_RX_B, &lp->lan_saa9730_regs->Ok2Use); - - return 0; -} - -static int lan_saa9730_restart(struct lan_saa9730_private *lp) -{ - lan_saa9730_stop(lp); - lan_saa9730_start(lp); - - return 0; -} - -static int lan_saa9730_tx(struct net_device *dev) -{ - struct lan_saa9730_private *lp = netdev_priv(dev); - unsigned int *pPacket; - unsigned int tx_status; - - if (lan_saa9730_debug > 5) - printk("lan_saa9730_tx interrupt\n"); - - /* Clear interrupt. */ - writel(DMA_STATUS_MAC_TX_INT, &lp->lan_saa9730_regs->DmaStatus); - - while (1) { - pPacket = lp->TxmBuffer[lp->PendingTxmBufferIndex] - [lp->PendingTxmPacketIndex]; - - /* Get status of first packet transmitted. */ - tx_status = le32_to_cpu(*pPacket); - - /* Check ownership. */ - if ((tx_status & TX_STAT_CTL_OWNER_MSK) != - (TXSF_HWDONE << TX_STAT_CTL_OWNER_SHF)) break; - - /* Check for error. */ - if (tx_status & TX_STAT_CTL_ERROR_MSK) { - if (lan_saa9730_debug > 1) - printk("lan_saa9730_tx: tx error = %x\n", - tx_status); - - dev->stats.tx_errors++; - if (tx_status & - (TX_STATUS_EX_COLL << TX_STAT_CTL_STATUS_SHF)) - dev->stats.tx_aborted_errors++; - if (tx_status & - (TX_STATUS_LATE_COLL << TX_STAT_CTL_STATUS_SHF)) - dev->stats.tx_window_errors++; - if (tx_status & - (TX_STATUS_L_CARR << TX_STAT_CTL_STATUS_SHF)) - dev->stats.tx_carrier_errors++; - if (tx_status & - (TX_STATUS_UNDER << TX_STAT_CTL_STATUS_SHF)) - dev->stats.tx_fifo_errors++; - if (tx_status & - (TX_STATUS_SQ_ERR << TX_STAT_CTL_STATUS_SHF)) - dev->stats.tx_heartbeat_errors++; - - dev->stats.collisions += - tx_status & TX_STATUS_TX_COLL_MSK; - } - - /* Free buffer. */ - *pPacket = - cpu_to_le32(TXSF_EMPTY << TX_STAT_CTL_OWNER_SHF); - - /* Update pending index pointer. */ - lp->PendingTxmPacketIndex++; - if (lp->PendingTxmPacketIndex >= LAN_SAA9730_TXM_Q_SIZE) { - lp->PendingTxmPacketIndex = 0; - lp->PendingTxmBufferIndex ^= 1; - } - } - - /* The tx buffer is no longer full. */ - netif_wake_queue(dev); - - return 0; -} - -static int lan_saa9730_rx(struct net_device *dev) -{ - struct lan_saa9730_private *lp = netdev_priv(dev); - int len = 0; - struct sk_buff *skb = 0; - unsigned int rx_status; - int BufferIndex; - int PacketIndex; - unsigned int *pPacket; - unsigned char *pData; - - if (lan_saa9730_debug > 5) - printk("lan_saa9730_rx interrupt\n"); - - /* Clear receive interrupts. */ - writel(DMA_STATUS_MAC_RX_INT | DMA_STATUS_RX_INT | - DMA_STATUS_RX_TO_INT, &lp->lan_saa9730_regs->DmaStatus); - - /* Address next packet */ - BufferIndex = lp->NextRcvBufferIndex; - PacketIndex = lp->NextRcvPacketIndex; - pPacket = lp->RcvBuffer[BufferIndex][PacketIndex]; - rx_status = le32_to_cpu(*pPacket); - - /* Process each packet. */ - while ((rx_status & RX_STAT_CTL_OWNER_MSK) == - (RXSF_HWDONE << RX_STAT_CTL_OWNER_SHF)) { - /* Check the rx status. */ - if (rx_status & (RX_STATUS_GOOD << RX_STAT_CTL_STATUS_SHF)) { - /* Received packet is good. */ - len = (rx_status & RX_STAT_CTL_LENGTH_MSK) >> - RX_STAT_CTL_LENGTH_SHF; - - pData = (unsigned char *) pPacket; - pData += 4; - skb = dev_alloc_skb(len + 2); - if (skb == 0) { - printk - ("%s: Memory squeeze, deferring packet.\n", - dev->name); - dev->stats.rx_dropped++; - } else { - dev->stats.rx_bytes += len; - dev->stats.rx_packets++; - skb_reserve(skb, 2); /* 16 byte align */ - skb_put(skb, len); /* make room */ - skb_copy_to_linear_data(skb, - (unsigned char *) pData, - len); - skb->protocol = eth_type_trans(skb, dev); - netif_rx(skb); - dev->last_rx = jiffies; - } - } else { - /* We got an error packet. */ - if (lan_saa9730_debug > 2) - printk - ("lan_saa9730_rx: We got an error packet = %x\n", - rx_status); - - dev->stats.rx_errors++; - if (rx_status & - (RX_STATUS_CRC_ERR << RX_STAT_CTL_STATUS_SHF)) - dev->stats.rx_crc_errors++; - if (rx_status & - (RX_STATUS_ALIGN_ERR << RX_STAT_CTL_STATUS_SHF)) - dev->stats.rx_frame_errors++; - if (rx_status & - (RX_STATUS_OVERFLOW << RX_STAT_CTL_STATUS_SHF)) - dev->stats.rx_fifo_errors++; - if (rx_status & - (RX_STATUS_LONG_ERR << RX_STAT_CTL_STATUS_SHF)) - dev->stats.rx_length_errors++; - } - - /* Indicate we have processed the buffer. */ - *pPacket = cpu_to_le32(RXSF_READY << RX_STAT_CTL_OWNER_SHF); - - /* Make sure A or B is available to hardware as appropriate. */ - writel(BufferIndex ? OK2USE_RX_B : OK2USE_RX_A, - &lp->lan_saa9730_regs->Ok2Use); - - /* Go to next packet in sequence. */ - lp->NextRcvPacketIndex++; - if (lp->NextRcvPacketIndex >= LAN_SAA9730_RCV_Q_SIZE) { - lp->NextRcvPacketIndex = 0; - lp->NextRcvBufferIndex ^= 1; - } - - /* Address next packet */ - BufferIndex = lp->NextRcvBufferIndex; - PacketIndex = lp->NextRcvPacketIndex; - pPacket = lp->RcvBuffer[BufferIndex][PacketIndex]; - rx_status = le32_to_cpu(*pPacket); - } - - return 0; -} - -static irqreturn_t lan_saa9730_interrupt(const int irq, void *dev_id) -{ - struct net_device *dev = dev_id; - struct lan_saa9730_private *lp = netdev_priv(dev); - - if (lan_saa9730_debug > 5) - printk("lan_saa9730_interrupt\n"); - - /* Disable the EVM LAN interrupt. */ - evm_saa9730_block_lan_int(lp); - - /* Clear the EVM LAN interrupt. */ - evm_saa9730_clear_lan_int(lp); - - /* Service pending transmit interrupts. */ - if (readl(&lp->lan_saa9730_regs->DmaStatus) & DMA_STATUS_MAC_TX_INT) - lan_saa9730_tx(dev); - - /* Service pending receive interrupts. */ - if (readl(&lp->lan_saa9730_regs->DmaStatus) & - (DMA_STATUS_MAC_RX_INT | DMA_STATUS_RX_INT | - DMA_STATUS_RX_TO_INT)) lan_saa9730_rx(dev); - - /* Enable the EVM LAN interrupt. */ - evm_saa9730_unblock_lan_int(lp); - - return IRQ_HANDLED; -} - -static int lan_saa9730_open(struct net_device *dev) -{ - struct lan_saa9730_private *lp = netdev_priv(dev); - - /* Associate IRQ with lan_saa9730_interrupt */ - if (request_irq(dev->irq, &lan_saa9730_interrupt, 0, "SAA9730 Eth", - dev)) { - printk("lan_saa9730_open: Can't get irq %d\n", dev->irq); - return -EAGAIN; - } - - /* Enable the Lan interrupt in the event manager. */ - evm_saa9730_enable_lan_int(lp); - - /* Start the LAN controller */ - if (lan_saa9730_start(lp)) - return -1; - - netif_start_queue(dev); - - return 0; -} - -static int lan_saa9730_write(struct lan_saa9730_private *lp, - struct sk_buff *skb, int skblen) -{ - unsigned char *pbData = skb->data; - unsigned int len = skblen; - unsigned char *pbPacketData; - unsigned int tx_status; - int BufferIndex; - int PacketIndex; - - if (lan_saa9730_debug > 5) - printk("lan_saa9730_write: skb=%p\n", skb); - - BufferIndex = lp->NextTxmBufferIndex; - PacketIndex = lp->NextTxmPacketIndex; - - tx_status = le32_to_cpu(*(unsigned int *)lp->TxmBuffer[BufferIndex] - [PacketIndex]); - if ((tx_status & TX_STAT_CTL_OWNER_MSK) != - (TXSF_EMPTY << TX_STAT_CTL_OWNER_SHF)) { - if (lan_saa9730_debug > 4) - printk - ("lan_saa9730_write: Tx buffer not available: tx_status = %x\n", - tx_status); - return -1; - } - - lp->NextTxmPacketIndex++; - if (lp->NextTxmPacketIndex >= LAN_SAA9730_TXM_Q_SIZE) { - lp->NextTxmPacketIndex = 0; - lp->NextTxmBufferIndex ^= 1; - } - - pbPacketData = lp->TxmBuffer[BufferIndex][PacketIndex]; - pbPacketData += 4; - - /* copy the bits */ - memcpy(pbPacketData, pbData, len); - - /* Set transmit status for hardware */ - *(unsigned int *)lp->TxmBuffer[BufferIndex][PacketIndex] = - cpu_to_le32((TXSF_READY << TX_STAT_CTL_OWNER_SHF) | - (TX_STAT_CTL_INT_AFTER_TX << - TX_STAT_CTL_FRAME_SHF) | - (len << TX_STAT_CTL_LENGTH_SHF)); - - /* Make sure A or B is available to hardware as appropriate. */ - writel(BufferIndex ? OK2USE_TX_B : OK2USE_TX_A, - &lp->lan_saa9730_regs->Ok2Use); - - return 0; -} - -static void lan_saa9730_tx_timeout(struct net_device *dev) -{ - struct lan_saa9730_private *lp = netdev_priv(dev); - - /* Transmitter timeout, serious problems */ - dev->stats.tx_errors++; - printk("%s: transmit timed out, reset\n", dev->name); - /*show_saa9730_regs(dev); */ - lan_saa9730_restart(lp); - - dev->trans_start = jiffies; - netif_wake_queue(dev); -} - -static int lan_saa9730_start_xmit(struct sk_buff *skb, - struct net_device *dev) -{ - struct lan_saa9730_private *lp = netdev_priv(dev); - unsigned long flags; - int skblen; - int len; - - if (lan_saa9730_debug > 4) - printk("Send packet: skb=%p\n", skb); - - skblen = skb->len; - - spin_lock_irqsave(&lp->lock, flags); - - len = (skblen <= ETH_ZLEN) ? ETH_ZLEN : skblen; - - if (lan_saa9730_write(lp, skb, skblen)) { - spin_unlock_irqrestore(&lp->lock, flags); - printk("Error when writing packet to controller: skb=%p\n", skb); - netif_stop_queue(dev); - return -1; - } - - dev->stats.tx_bytes += len; - dev->stats.tx_packets++; - - dev->trans_start = jiffies; - netif_wake_queue(dev); - dev_kfree_skb(skb); - - spin_unlock_irqrestore(&lp->lock, flags); - - return 0; -} - -static int lan_saa9730_close(struct net_device *dev) -{ - struct lan_saa9730_private *lp = netdev_priv(dev); - - if (lan_saa9730_debug > 1) - printk("lan_saa9730_close:\n"); - - netif_stop_queue(dev); - - /* Disable the Lan interrupt in the event manager. */ - evm_saa9730_disable_lan_int(lp); - - /* Stop the controller */ - if (lan_saa9730_stop(lp)) - return -1; - - free_irq(dev->irq, (void *) dev); - - return 0; -} - -static void lan_saa9730_set_multicast(struct net_device *dev) -{ - struct lan_saa9730_private *lp = netdev_priv(dev); - - /* Stop the controller */ - lan_saa9730_stop(lp); - - if (dev->flags & IFF_PROMISC) { - /* accept all packets */ - writel(CAM_CONTROL_COMP_EN | CAM_CONTROL_STATION_ACC | - CAM_CONTROL_GROUP_ACC | CAM_CONTROL_BROAD_ACC, - &lp->lan_saa9730_regs->CamCtl); - } else { - if (dev->flags & IFF_ALLMULTI || dev->mc_count) { - /* accept all multicast packets */ - /* - * Will handle the multicast stuff later. -carstenl - */ - writel(CAM_CONTROL_COMP_EN | CAM_CONTROL_GROUP_ACC | - CAM_CONTROL_BROAD_ACC, - &lp->lan_saa9730_regs->CamCtl); - } - } - - lan_saa9730_restart(lp); -} - - -static void __devexit saa9730_remove_one(struct pci_dev *pdev) -{ - struct net_device *dev = pci_get_drvdata(pdev); - struct lan_saa9730_private *lp = netdev_priv(dev); - - if (dev) { - unregister_netdev(dev); - lan_saa9730_free_buffers(pdev, lp); - iounmap(lp->lan_saa9730_regs); - iounmap(lp->evm_saa9730_regs); - free_netdev(dev); - pci_release_regions(pdev); - pci_disable_device(pdev); - pci_set_drvdata(pdev, NULL); - } -} - - -static int lan_saa9730_init(struct net_device *dev, struct pci_dev *pdev, - unsigned long ioaddr, int irq) -{ - struct lan_saa9730_private *lp = netdev_priv(dev); - unsigned char ethernet_addr[6]; - int ret; - - if (get_ethernet_addr(ethernet_addr)) { - ret = -ENODEV; - goto out; - } - - memcpy(dev->dev_addr, ethernet_addr, 6); - dev->base_addr = ioaddr; - dev->irq = irq; - - lp->pci_dev = pdev; - - /* Set SAA9730 LAN base address. */ - lp->lan_saa9730_regs = ioremap(ioaddr + SAA9730_LAN_REGS_ADDR, - SAA9730_LAN_REGS_SIZE); - if (!lp->lan_saa9730_regs) { - ret = -ENOMEM; - goto out; - } - - /* Set SAA9730 EVM base address. */ - lp->evm_saa9730_regs = ioremap(ioaddr + SAA9730_EVM_REGS_ADDR, - SAA9730_EVM_REGS_SIZE); - if (!lp->evm_saa9730_regs) { - ret = -ENOMEM; - goto out_iounmap_lan; - } - - /* Allocate LAN RX/TX frame buffer space. */ - if ((ret = lan_saa9730_allocate_buffers(pdev, lp))) - goto out_iounmap; - - /* Stop LAN controller. */ - if ((ret = lan_saa9730_stop(lp))) - goto out_free_consistent; - - /* Initialize CAM registers. */ - if ((ret = lan_saa9730_cam_init(dev))) - goto out_free_consistent; - - /* Initialize MII registers. */ - if ((ret = lan_saa9730_mii_init(lp))) - goto out_free_consistent; - - /* Initialize control registers. */ - if ((ret = lan_saa9730_control_init(lp))) - goto out_free_consistent; - - /* Load CAM registers. */ - if ((ret = lan_saa9730_cam_load(lp))) - goto out_free_consistent; - - /* Initialize DMA context registers. */ - if ((ret = lan_saa9730_dma_init(lp))) - goto out_free_consistent; - - spin_lock_init(&lp->lock); - - dev->open = lan_saa9730_open; - dev->hard_start_xmit = lan_saa9730_start_xmit; - dev->stop = lan_saa9730_close; - dev->set_multicast_list = lan_saa9730_set_multicast; - dev->tx_timeout = lan_saa9730_tx_timeout; - dev->watchdog_timeo = (HZ >> 1); - dev->dma = 0; - - ret = register_netdev (dev); - if (ret) - goto out_free_consistent; - - return 0; - -out_free_consistent: - lan_saa9730_free_buffers(pdev, lp); -out_iounmap: - iounmap(lp->evm_saa9730_regs); -out_iounmap_lan: - iounmap(lp->lan_saa9730_regs); -out: - return ret; -} - - -static int __devinit saa9730_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) -{ - struct net_device *dev = NULL; - unsigned long pci_ioaddr; - int err; - - if (lan_saa9730_debug > 1) - printk("saa9730.c: PCI bios is present, checking for devices...\n"); - - err = pci_enable_device(pdev); - if (err) { - printk(KERN_ERR "Cannot enable PCI device, aborting.\n"); - goto out; - } - - err = pci_request_regions(pdev, DRV_MODULE_NAME); - if (err) { - printk(KERN_ERR "Cannot obtain PCI resources, aborting.\n"); - goto out_disable_pdev; - } - - pci_irq_line = pdev->irq; - /* LAN base address in located at BAR 1. */ - - pci_ioaddr = pci_resource_start(pdev, 1); - pci_set_master(pdev); - - printk("Found SAA9730 (PCI) at %lx, irq %d.\n", - pci_ioaddr, pci_irq_line); - - dev = alloc_etherdev(sizeof(struct lan_saa9730_private)); - if (!dev) - goto out_disable_pdev; - - err = lan_saa9730_init(dev, pdev, pci_ioaddr, pci_irq_line); - if (err) { - printk("LAN init failed"); - goto out_free_netdev; - } - - pci_set_drvdata(pdev, dev); - SET_NETDEV_DEV(dev, &pdev->dev); - return 0; - -out_free_netdev: - free_netdev(dev); -out_disable_pdev: - pci_disable_device(pdev); -out: - pci_set_drvdata(pdev, NULL); - return err; -} - - -static struct pci_driver saa9730_driver = { - .name = DRV_MODULE_NAME, - .id_table = saa9730_pci_tbl, - .probe = saa9730_init_one, - .remove = __devexit_p(saa9730_remove_one), -}; - - -static int __init saa9730_init(void) -{ - return pci_register_driver(&saa9730_driver); -} - -static void __exit saa9730_cleanup(void) -{ - pci_unregister_driver(&saa9730_driver); -} - -module_init(saa9730_init); -module_exit(saa9730_cleanup); - -MODULE_AUTHOR("Ralf Baechle <ralf@linux-mips.org>"); -MODULE_DESCRIPTION("Philips SAA9730 ethernet driver"); -MODULE_LICENSE("GPL"); diff --git a/drivers/net/saa9730.h b/drivers/net/saa9730.h deleted file mode 100644 index 010a120ea938..000000000000 --- a/drivers/net/saa9730.h +++ /dev/null @@ -1,384 +0,0 @@ -/* - * Copyright (C) 2000, 2005 MIPS Technologies, Inc. All rights reserved. - * Authors: Carsten Langgaard <carstenl@mips.com> - * Maciej W. Rozycki <macro@mips.com> - * - * ######################################################################## - * - * This program is free software; you can distribute 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 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. - * - * ######################################################################## - * - * SAA9730 ethernet driver description. - * - */ -#ifndef _SAA9730_H -#define _SAA9730_H - - -/* Number of 6-byte entries in the CAM. */ -#define LAN_SAA9730_CAM_ENTRIES 10 -#define LAN_SAA9730_CAM_DWORDS ((LAN_SAA9730_CAM_ENTRIES*6)/4) - -/* TX and RX packet size: fixed to 2048 bytes, according to HW requirements. */ -#define LAN_SAA9730_PACKET_SIZE 2048 - -/* - * Number of TX buffers = number of RX buffers = 2, which is fixed according - * to HW requirements. - */ -#define LAN_SAA9730_BUFFERS 2 - -/* Number of RX packets per RX buffer. */ -#define LAN_SAA9730_RCV_Q_SIZE 15 - -/* Number of TX packets per TX buffer. */ -#define LAN_SAA9730_TXM_Q_SIZE 15 - -/* - * We get an interrupt for each LAN_SAA9730_DEFAULT_RCV_Q_INT_THRESHOLD - * packets received. - * If however we receive less than LAN_SAA9730_DEFAULT_RCV_Q_INT_THRESHOLD - * packets, the hardware can timeout after a certain time and still tell - * us packets have arrived. - * The timeout value in unit of 32 PCI clocks (33Mhz). - * The value 200 approximates 0.0002 seconds. - */ -#define LAN_SAA9730_RCV_Q_INT_THRESHOLD 1 -#define LAN_SAA9730_DEFAULT_TIME_OUT_CNT 10 - -#define RXSF_NDIS 0 -#define RXSF_READY 2 -#define RXSF_HWDONE 3 - -#define TXSF_EMPTY 0 -#define TXSF_READY 2 -#define TXSF_HWDONE 3 - -#define LANEND_LITTLE 0 -#define LANEND_BIG_2143 1 -#define LANEND_BIG_4321 2 - -#define LANMB_ANY 0 -#define LANMB_8 1 -#define LANMB_32 2 -#define LANMB_64 3 - -#define MACCM_AUTOMATIC 0 -#define MACCM_10MB 1 -#define MACCM_MII 2 - -/* - * PHY definitions for Basic registers of QS6612 (used on MIPS ATLAS board) - */ -#define PHY_CONTROL 0x0 -#define PHY_STATUS 0x1 -#define PHY_STATUS_LINK_UP 0x4 -#define PHY_CONTROL_RESET 0x8000 -#define PHY_CONTROL_AUTO_NEG 0x1000 -#define PHY_CONTROL_RESTART_AUTO_NEG 0x0200 -#define PHY_ADDRESS 0x0 - -/* PK_COUNT register. */ -#define PK_COUNT_TX_A_SHF 24 -#define PK_COUNT_TX_A_MSK (0xff << PK_COUNT_TX_A_SHF) -#define PK_COUNT_TX_B_SHF 16 -#define PK_COUNT_TX_B_MSK (0xff << PK_COUNT_TX_B_SHF) -#define PK_COUNT_RX_A_SHF 8 -#define PK_COUNT_RX_A_MSK (0xff << PK_COUNT_RX_A_SHF) -#define PK_COUNT_RX_B_SHF 0 -#define PK_COUNT_RX_B_MSK (0xff << PK_COUNT_RX_B_SHF) - -/* OK2USE register. */ -#define OK2USE_TX_A 0x8 -#define OK2USE_TX_B 0x4 -#define OK2USE_RX_A 0x2 -#define OK2USE_RX_B 0x1 - -/* LAN DMA CONTROL register. */ -#define DMA_CTL_BLK_INT 0x80000000 -#define DMA_CTL_MAX_XFER_SHF 18 -#define DMA_CTL_MAX_XFER_MSK (0x3 << LAN_DMA_CTL_MAX_XFER_SHF) -#define DMA_CTL_ENDIAN_SHF 16 -#define DMA_CTL_ENDIAN_MSK (0x3 << LAN_DMA_CTL_ENDIAN_SHF) -#define DMA_CTL_RX_INT_COUNT_SHF 8 -#define DMA_CTL_RX_INT_COUNT_MSK (0xff << LAN_DMA_CTL_RX_INT_COUNT_SHF) -#define DMA_CTL_EN_TX_DMA 0x00000080 -#define DMA_CTL_EN_RX_DMA 0x00000040 -#define DMA_CTL_RX_INT_BUFFUL_EN 0x00000020 -#define DMA_CTL_RX_INT_TO_EN 0x00000010 -#define DMA_CTL_RX_INT_EN 0x00000008 -#define DMA_CTL_TX_INT_EN 0x00000004 -#define DMA_CTL_MAC_TX_INT_EN 0x00000002 -#define DMA_CTL_MAC_RX_INT_EN 0x00000001 - -/* DMA STATUS register. */ -#define DMA_STATUS_BAD_ADDR_SHF 16 -#define DMA_STATUS_BAD_ADDR_MSK (0xf << DMA_STATUS_BAD_ADDR_SHF) -#define DMA_STATUS_RX_PKTS_RECEIVED_SHF 8 -#define DMA_STATUS_RX_PKTS_RECEIVED_MSK (0xff << DMA_STATUS_RX_PKTS_RECEIVED_SHF) -#define DMA_STATUS_TX_EN_SYNC 0x00000080 -#define DMA_STATUS_RX_BUF_A_FUL 0x00000040 -#define DMA_STATUS_RX_BUF_B_FUL 0x00000020 -#define DMA_STATUS_RX_TO_INT 0x00000010 -#define DMA_STATUS_RX_INT 0x00000008 -#define DMA_STATUS_TX_INT 0x00000004 -#define DMA_STATUS_MAC_TX_INT 0x00000002 -#define DMA_STATUS_MAC_RX_INT 0x00000001 - -/* DMA TEST/PANIC SWITHES register. */ -#define DMA_TEST_LOOPBACK 0x01000000 -#define DMA_TEST_SW_RESET 0x00000001 - -/* MAC CONTROL register. */ -#define MAC_CONTROL_EN_MISS_ROLL 0x00002000 -#define MAC_CONTROL_MISS_ROLL 0x00000400 -#define MAC_CONTROL_LOOP10 0x00000080 -#define MAC_CONTROL_CONN_SHF 5 -#define MAC_CONTROL_CONN_MSK (0x3 << MAC_CONTROL_CONN_SHF) -#define MAC_CONTROL_MAC_LOOP 0x00000010 -#define MAC_CONTROL_FULL_DUP 0x00000008 -#define MAC_CONTROL_RESET 0x00000004 -#define MAC_CONTROL_HALT_IMM 0x00000002 -#define MAC_CONTROL_HALT_REQ 0x00000001 - -/* CAM CONTROL register. */ -#define CAM_CONTROL_COMP_EN 0x00000010 -#define CAM_CONTROL_NEG_CAM 0x00000008 -#define CAM_CONTROL_BROAD_ACC 0x00000004 -#define CAM_CONTROL_GROUP_ACC 0x00000002 -#define CAM_CONTROL_STATION_ACC 0x00000001 - -/* TRANSMIT CONTROL register. */ -#define TX_CTL_EN_COMP 0x00004000 -#define TX_CTL_EN_TX_PAR 0x00002000 -#define TX_CTL_EN_LATE_COLL 0x00001000 -#define TX_CTL_EN_EX_COLL 0x00000800 -#define TX_CTL_EN_L_CARR 0x00000400 -#define TX_CTL_EN_EX_DEFER 0x00000200 -#define TX_CTL_EN_UNDER 0x00000100 -#define TX_CTL_MII10 0x00000080 -#define TX_CTL_SD_PAUSE 0x00000040 -#define TX_CTL_NO_EX_DEF0 0x00000020 -#define TX_CTL_F_BACK 0x00000010 -#define TX_CTL_NO_CRC 0x00000008 -#define TX_CTL_NO_PAD 0x00000004 -#define TX_CTL_TX_HALT 0x00000002 -#define TX_CTL_TX_EN 0x00000001 - -/* TRANSMIT STATUS register. */ -#define TX_STATUS_SQ_ERR 0x00010000 -#define TX_STATUS_TX_HALTED 0x00008000 -#define TX_STATUS_COMP 0x00004000 -#define TX_STATUS_TX_PAR 0x00002000 -#define TX_STATUS_LATE_COLL 0x00001000 -#define TX_STATUS_TX10_STAT 0x00000800 -#define TX_STATUS_L_CARR 0x00000400 -#define TX_STATUS_EX_DEFER 0x00000200 -#define TX_STATUS_UNDER 0x00000100 -#define TX_STATUS_IN_TX 0x00000080 -#define TX_STATUS_PAUSED 0x00000040 -#define TX_STATUS_TX_DEFERRED 0x00000020 -#define TX_STATUS_EX_COLL 0x00000010 -#define TX_STATUS_TX_COLL_SHF 0 -#define TX_STATUS_TX_COLL_MSK (0xf << TX_STATUS_TX_COLL_SHF) - -/* RECEIVE CONTROL register. */ -#define RX_CTL_EN_GOOD 0x00004000 -#define RX_CTL_EN_RX_PAR 0x00002000 -#define RX_CTL_EN_LONG_ERR 0x00000800 -#define RX_CTL_EN_OVER 0x00000400 -#define RX_CTL_EN_CRC_ERR 0x00000200 -#define RX_CTL_EN_ALIGN 0x00000100 -#define RX_CTL_IGNORE_CRC 0x00000040 -#define RX_CTL_PASS_CTL 0x00000020 -#define RX_CTL_STRIP_CRC 0x00000010 -#define RX_CTL_SHORT_EN 0x00000008 -#define RX_CTL_LONG_EN 0x00000004 -#define RX_CTL_RX_HALT 0x00000002 -#define RX_CTL_RX_EN 0x00000001 - -/* RECEIVE STATUS register. */ -#define RX_STATUS_RX_HALTED 0x00008000 -#define RX_STATUS_GOOD 0x00004000 -#define RX_STATUS_RX_PAR 0x00002000 -#define RX_STATUS_LONG_ERR 0x00000800 -#define RX_STATUS_OVERFLOW 0x00000400 -#define RX_STATUS_CRC_ERR 0x00000200 -#define RX_STATUS_ALIGN_ERR 0x00000100 -#define RX_STATUS_RX10_STAT 0x00000080 -#define RX_STATUS_INT_RX 0x00000040 -#define RX_STATUS_CTL_RECD 0x00000020 - -/* MD_CA register. */ -#define MD_CA_PRE_SUP 0x00001000 -#define MD_CA_BUSY 0x00000800 -#define MD_CA_WR 0x00000400 -#define MD_CA_PHY_SHF 5 -#define MD_CA_PHY_MSK (0x1f << MD_CA_PHY_SHF) -#define MD_CA_ADDR_SHF 0 -#define MD_CA_ADDR_MSK (0x1f << MD_CA_ADDR_SHF) - -/* Tx Status/Control. */ -#define TX_STAT_CTL_OWNER_SHF 30 -#define TX_STAT_CTL_OWNER_MSK (0x3 << TX_STAT_CTL_OWNER_SHF) -#define TX_STAT_CTL_FRAME_SHF 27 -#define TX_STAT_CTL_FRAME_MSK (0x7 << TX_STAT_CTL_FRAME_SHF) -#define TX_STAT_CTL_STATUS_SHF 11 -#define TX_STAT_CTL_STATUS_MSK (0x1ffff << TX_STAT_CTL_STATUS_SHF) -#define TX_STAT_CTL_LENGTH_SHF 0 -#define TX_STAT_CTL_LENGTH_MSK (0x7ff << TX_STAT_CTL_LENGTH_SHF) - -#define TX_STAT_CTL_ERROR_MSK ((TX_STATUS_SQ_ERR | \ - TX_STATUS_TX_HALTED | \ - TX_STATUS_TX_PAR | \ - TX_STATUS_LATE_COLL | \ - TX_STATUS_L_CARR | \ - TX_STATUS_EX_DEFER | \ - TX_STATUS_UNDER | \ - TX_STATUS_PAUSED | \ - TX_STATUS_TX_DEFERRED | \ - TX_STATUS_EX_COLL | \ - TX_STATUS_TX_COLL_MSK) \ - << TX_STAT_CTL_STATUS_SHF) -#define TX_STAT_CTL_INT_AFTER_TX 0x4 - -/* Rx Status/Control. */ -#define RX_STAT_CTL_OWNER_SHF 30 -#define RX_STAT_CTL_OWNER_MSK (0x3 << RX_STAT_CTL_OWNER_SHF) -#define RX_STAT_CTL_STATUS_SHF 11 -#define RX_STAT_CTL_STATUS_MSK (0xffff << RX_STAT_CTL_STATUS_SHF) -#define RX_STAT_CTL_LENGTH_SHF 0 -#define RX_STAT_CTL_LENGTH_MSK (0x7ff << RX_STAT_CTL_LENGTH_SHF) - - - -/* The SAA9730 (LAN) controller register map, as seen via the PCI-bus. */ -#define SAA9730_LAN_REGS_ADDR 0x20400 -#define SAA9730_LAN_REGS_SIZE 0x00400 - -struct lan_saa9730_regmap { - volatile unsigned int TxBuffA; /* 0x20400 */ - volatile unsigned int TxBuffB; /* 0x20404 */ - volatile unsigned int RxBuffA; /* 0x20408 */ - volatile unsigned int RxBuffB; /* 0x2040c */ - volatile unsigned int PacketCount; /* 0x20410 */ - volatile unsigned int Ok2Use; /* 0x20414 */ - volatile unsigned int LanDmaCtl; /* 0x20418 */ - volatile unsigned int Timeout; /* 0x2041c */ - volatile unsigned int DmaStatus; /* 0x20420 */ - volatile unsigned int DmaTest; /* 0x20424 */ - volatile unsigned char filler20428[0x20430 - 0x20428]; - volatile unsigned int PauseCount; /* 0x20430 */ - volatile unsigned int RemotePauseCount; /* 0x20434 */ - volatile unsigned char filler20438[0x20440 - 0x20438]; - volatile unsigned int MacCtl; /* 0x20440 */ - volatile unsigned int CamCtl; /* 0x20444 */ - volatile unsigned int TxCtl; /* 0x20448 */ - volatile unsigned int TxStatus; /* 0x2044c */ - volatile unsigned int RxCtl; /* 0x20450 */ - volatile unsigned int RxStatus; /* 0x20454 */ - volatile unsigned int StationMgmtData; /* 0x20458 */ - volatile unsigned int StationMgmtCtl; /* 0x2045c */ - volatile unsigned int CamAddress; /* 0x20460 */ - volatile unsigned int CamData; /* 0x20464 */ - volatile unsigned int CamEnable; /* 0x20468 */ - volatile unsigned char filler2046c[0x20500 - 0x2046c]; - volatile unsigned int DebugPCIMasterAddr; /* 0x20500 */ - volatile unsigned int DebugLanTxStateMachine; /* 0x20504 */ - volatile unsigned int DebugLanRxStateMachine; /* 0x20508 */ - volatile unsigned int DebugLanTxFifoPointers; /* 0x2050c */ - volatile unsigned int DebugLanRxFifoPointers; /* 0x20510 */ - volatile unsigned int DebugLanCtlStateMachine; /* 0x20514 */ -}; -typedef volatile struct lan_saa9730_regmap t_lan_saa9730_regmap; - - -/* EVM interrupt control registers. */ -#define EVM_LAN_INT 0x00010000 -#define EVM_MASTER_EN 0x00000001 - -/* The SAA9730 (EVM) controller register map, as seen via the PCI-bus. */ -#define SAA9730_EVM_REGS_ADDR 0x02000 -#define SAA9730_EVM_REGS_SIZE 0x00400 - -struct evm_saa9730_regmap { - volatile unsigned int InterruptStatus1; /* 0x2000 */ - volatile unsigned int InterruptEnable1; /* 0x2004 */ - volatile unsigned int InterruptMonitor1; /* 0x2008 */ - volatile unsigned int Counter; /* 0x200c */ - volatile unsigned int CounterThreshold; /* 0x2010 */ - volatile unsigned int CounterControl; /* 0x2014 */ - volatile unsigned int GpioControl1; /* 0x2018 */ - volatile unsigned int InterruptStatus2; /* 0x201c */ - volatile unsigned int InterruptEnable2; /* 0x2020 */ - volatile unsigned int InterruptMonitor2; /* 0x2024 */ - volatile unsigned int GpioControl2; /* 0x2028 */ - volatile unsigned int InterruptBlock1; /* 0x202c */ - volatile unsigned int InterruptBlock2; /* 0x2030 */ -}; -typedef volatile struct evm_saa9730_regmap t_evm_saa9730_regmap; - - -struct lan_saa9730_private { - /* - * Rx/Tx packet buffers. - * The Rx and Tx packets must be PACKET_SIZE aligned. - */ - void *buffer_start; - unsigned int buffer_size; - - /* - * DMA address of beginning of this object, returned - * by pci_alloc_consistent(). - */ - dma_addr_t dma_addr; - - /* Pointer to the associated pci device structure */ - struct pci_dev *pci_dev; - - /* Pointer for the SAA9730 LAN controller register set. */ - t_lan_saa9730_regmap *lan_saa9730_regs; - - /* Pointer to the SAA9730 EVM register. */ - t_evm_saa9730_regmap *evm_saa9730_regs; - - /* Rcv buffer Index. */ - unsigned char NextRcvPacketIndex; - /* Next buffer index. */ - unsigned char NextRcvBufferIndex; - - /* Index of next packet to use in that buffer. */ - unsigned char NextTxmPacketIndex; - /* Next buffer index. */ - unsigned char NextTxmBufferIndex; - - /* Index of first pending packet ready to send. */ - unsigned char PendingTxmPacketIndex; - /* Pending buffer index. */ - unsigned char PendingTxmBufferIndex; - - unsigned char DmaRcvPackets; - unsigned char DmaTxmPackets; - - void *TxmBuffer[LAN_SAA9730_BUFFERS][LAN_SAA9730_TXM_Q_SIZE]; - void *RcvBuffer[LAN_SAA9730_BUFFERS][LAN_SAA9730_RCV_Q_SIZE]; - unsigned int TxBufferFree[LAN_SAA9730_BUFFERS]; - - unsigned char PhysicalAddress[LAN_SAA9730_CAM_ENTRIES][6]; - - spinlock_t lock; -}; - -#endif /* _SAA9730_H */ diff --git a/drivers/net/sb1250-mac.c b/drivers/net/sb1250-mac.c index 33bb18f810fb..fe41e4ec21ec 100644 --- a/drivers/net/sb1250-mac.c +++ b/drivers/net/sb1250-mac.c @@ -1064,7 +1064,7 @@ static void sbmac_netpoll(struct net_device *netdev) ((M_MAC_INT_EOP_COUNT | M_MAC_INT_EOP_TIMER) << S_MAC_RX_CH0), sc->sbm_imr); #else - __raw_writeq((M_MAC_INT_CHANNEL << S_MAC_TX_CH0) | + __raw_writeq((M_MAC_INT_CHANNEL << S_MAC_TX_CH0) | (M_MAC_INT_CHANNEL << S_MAC_RX_CH0), sc->sbm_imr); #endif } diff --git a/drivers/net/sfc/Kconfig b/drivers/net/sfc/Kconfig index dbad95c295bd..3be13b592b4d 100644 --- a/drivers/net/sfc/Kconfig +++ b/drivers/net/sfc/Kconfig @@ -4,6 +4,8 @@ config SFC select MII select INET_LRO select CRC32 + select I2C + select I2C_ALGOBIT help This driver supports 10-gigabit Ethernet cards based on the Solarflare Communications Solarstorm SFC4000 controller. diff --git a/drivers/net/sfc/Makefile b/drivers/net/sfc/Makefile index 1d2daeec7ac1..c8f5704c8fb1 100644 --- a/drivers/net/sfc/Makefile +++ b/drivers/net/sfc/Makefile @@ -1,5 +1,5 @@ sfc-y += efx.o falcon.o tx.o rx.o falcon_xmac.o \ - i2c-direct.o selftest.o ethtool.o xfp_phy.o \ + selftest.o ethtool.o xfp_phy.o \ mdio_10g.o tenxpress.o boards.o sfe4001.o obj-$(CONFIG_SFC) += sfc.o diff --git a/drivers/net/sfc/boards.c b/drivers/net/sfc/boards.c index 7fc0328dc055..d3d3dd0a1170 100644 --- a/drivers/net/sfc/boards.c +++ b/drivers/net/sfc/boards.c @@ -109,7 +109,7 @@ static struct efx_board_data board_data[] = { [EFX_BOARD_INVALID] = {NULL, NULL, dummy_init}, [EFX_BOARD_SFE4001] = - {"SFE4001", "10GBASE-T adapter", sfe4001_poweron}, + {"SFE4001", "10GBASE-T adapter", sfe4001_init}, [EFX_BOARD_SFE4002] = {"SFE4002", "XFP adapter", sfe4002_init}, }; diff --git a/drivers/net/sfc/boards.h b/drivers/net/sfc/boards.h index 695764dc2e64..e5e844359ce7 100644 --- a/drivers/net/sfc/boards.h +++ b/drivers/net/sfc/boards.h @@ -20,8 +20,7 @@ enum efx_board_type { }; extern int efx_set_board_info(struct efx_nic *efx, u16 revision_info); -extern int sfe4001_poweron(struct efx_nic *efx); -extern void sfe4001_poweroff(struct efx_nic *efx); +extern int sfe4001_init(struct efx_nic *efx); /* Are we putting the PHY into flash config mode */ extern unsigned int sfe4001_phy_flash_cfg; diff --git a/drivers/net/sfc/efx.c b/drivers/net/sfc/efx.c index 449760642e31..7b2015f9e469 100644 --- a/drivers/net/sfc/efx.c +++ b/drivers/net/sfc/efx.c @@ -696,8 +696,8 @@ static void efx_stop_port(struct efx_nic *efx) /* Serialise against efx_set_multicast_list() */ if (efx_dev_registered(efx)) { - netif_tx_lock_bh(efx->net_dev); - netif_tx_unlock_bh(efx->net_dev); + netif_addr_lock_bh(efx->net_dev); + netif_addr_unlock_bh(efx->net_dev); } } @@ -1815,6 +1815,7 @@ static struct efx_board efx_dummy_board_info = { .init = efx_nic_dummy_op_int, .init_leds = efx_port_dummy_op_int, .set_fault_led = efx_port_dummy_op_blink, + .fini = efx_port_dummy_op_void, }; /************************************************************************** @@ -1941,6 +1942,7 @@ static void efx_pci_remove_main(struct efx_nic *efx) efx_fini_port(efx); /* Shutdown the board, then the NIC and board state */ + efx->board_info.fini(efx); falcon_fini_interrupt(efx); efx_fini_napi(efx); diff --git a/drivers/net/sfc/falcon.c b/drivers/net/sfc/falcon.c index 790db89db345..630406e142e5 100644 --- a/drivers/net/sfc/falcon.c +++ b/drivers/net/sfc/falcon.c @@ -13,6 +13,8 @@ #include <linux/pci.h> #include <linux/module.h> #include <linux/seq_file.h> +#include <linux/i2c.h> +#include <linux/i2c-algo-bit.h> #include "net_driver.h" #include "bitfield.h" #include "efx.h" @@ -36,10 +38,12 @@ * struct falcon_nic_data - Falcon NIC state * @next_buffer_table: First available buffer table id * @pci_dev2: The secondary PCI device if present + * @i2c_data: Operations and state for I2C bit-bashing algorithm */ struct falcon_nic_data { unsigned next_buffer_table; struct pci_dev *pci_dev2; + struct i2c_algo_bit_data i2c_data; }; /************************************************************************** @@ -175,39 +179,57 @@ static inline int falcon_event_present(efx_qword_t *event) * ************************************************************************** */ -static void falcon_setsdascl(struct efx_i2c_interface *i2c) +static void falcon_setsda(void *data, int state) { + struct efx_nic *efx = (struct efx_nic *)data; efx_oword_t reg; - falcon_read(i2c->efx, ®, GPIO_CTL_REG_KER); - EFX_SET_OWORD_FIELD(reg, GPIO0_OEN, (i2c->scl ? 0 : 1)); - EFX_SET_OWORD_FIELD(reg, GPIO3_OEN, (i2c->sda ? 0 : 1)); - falcon_write(i2c->efx, ®, GPIO_CTL_REG_KER); + falcon_read(efx, ®, GPIO_CTL_REG_KER); + EFX_SET_OWORD_FIELD(reg, GPIO3_OEN, !state); + falcon_write(efx, ®, GPIO_CTL_REG_KER); } -static int falcon_getsda(struct efx_i2c_interface *i2c) +static void falcon_setscl(void *data, int state) { + struct efx_nic *efx = (struct efx_nic *)data; efx_oword_t reg; - falcon_read(i2c->efx, ®, GPIO_CTL_REG_KER); + falcon_read(efx, ®, GPIO_CTL_REG_KER); + EFX_SET_OWORD_FIELD(reg, GPIO0_OEN, !state); + falcon_write(efx, ®, GPIO_CTL_REG_KER); +} + +static int falcon_getsda(void *data) +{ + struct efx_nic *efx = (struct efx_nic *)data; + efx_oword_t reg; + + falcon_read(efx, ®, GPIO_CTL_REG_KER); return EFX_OWORD_FIELD(reg, GPIO3_IN); } -static int falcon_getscl(struct efx_i2c_interface *i2c) +static int falcon_getscl(void *data) { + struct efx_nic *efx = (struct efx_nic *)data; efx_oword_t reg; - falcon_read(i2c->efx, ®, GPIO_CTL_REG_KER); - return EFX_DWORD_FIELD(reg, GPIO0_IN); + falcon_read(efx, ®, GPIO_CTL_REG_KER); + return EFX_OWORD_FIELD(reg, GPIO0_IN); } -static struct efx_i2c_bit_operations falcon_i2c_bit_operations = { - .setsda = falcon_setsdascl, - .setscl = falcon_setsdascl, +static struct i2c_algo_bit_data falcon_i2c_bit_operations = { + .setsda = falcon_setsda, + .setscl = falcon_setscl, .getsda = falcon_getsda, .getscl = falcon_getscl, - .udelay = 100, - .mdelay = 10, + .udelay = 5, + /* + * This is the number of system clock ticks after which + * i2c-algo-bit gives up waiting for SCL to become high. + * It must be at least 2 since the first tick can happen + * immediately after it starts waiting. + */ + .timeout = 2, }; /************************************************************************** @@ -2405,12 +2427,6 @@ int falcon_probe_nic(struct efx_nic *efx) struct falcon_nic_data *nic_data; int rc; - /* Initialise I2C interface state */ - efx->i2c.efx = efx; - efx->i2c.op = &falcon_i2c_bit_operations; - efx->i2c.sda = 1; - efx->i2c.scl = 1; - /* Allocate storage for hardware specific data */ nic_data = kzalloc(sizeof(*nic_data), GFP_KERNEL); efx->nic_data = nic_data; @@ -2461,6 +2477,18 @@ int falcon_probe_nic(struct efx_nic *efx) if (rc) goto fail5; + /* Initialise I2C adapter */ + efx->i2c_adap.owner = THIS_MODULE; + efx->i2c_adap.class = I2C_CLASS_HWMON; + nic_data->i2c_data = falcon_i2c_bit_operations; + nic_data->i2c_data.data = efx; + efx->i2c_adap.algo_data = &nic_data->i2c_data; + efx->i2c_adap.dev.parent = &efx->pci_dev->dev; + strcpy(efx->i2c_adap.name, "SFC4000 GPIO"); + rc = i2c_bit_add_bus(&efx->i2c_adap); + if (rc) + goto fail5; + return 0; fail5: @@ -2635,6 +2663,10 @@ int falcon_init_nic(struct efx_nic *efx) void falcon_remove_nic(struct efx_nic *efx) { struct falcon_nic_data *nic_data = efx->nic_data; + int rc; + + rc = i2c_del_adapter(&efx->i2c_adap); + BUG_ON(rc); falcon_free_buffer(efx, &efx->irq_status); diff --git a/drivers/net/sfc/i2c-direct.c b/drivers/net/sfc/i2c-direct.c deleted file mode 100644 index b6c62d0ed9c2..000000000000 --- a/drivers/net/sfc/i2c-direct.c +++ /dev/null @@ -1,381 +0,0 @@ -/**************************************************************************** - * Driver for Solarflare Solarstorm network controllers and boards - * Copyright 2005 Fen Systems Ltd. - * Copyright 2006-2008 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 <linux/delay.h> -#include "net_driver.h" -#include "i2c-direct.h" - -/* - * I2C data (SDA) and clock (SCL) line read/writes with appropriate - * delays. - */ - -static inline void setsda(struct efx_i2c_interface *i2c, int state) -{ - udelay(i2c->op->udelay); - i2c->sda = state; - i2c->op->setsda(i2c); - udelay(i2c->op->udelay); -} - -static inline void setscl(struct efx_i2c_interface *i2c, int state) -{ - udelay(i2c->op->udelay); - i2c->scl = state; - i2c->op->setscl(i2c); - udelay(i2c->op->udelay); -} - -static inline int getsda(struct efx_i2c_interface *i2c) -{ - int sda; - - udelay(i2c->op->udelay); - sda = i2c->op->getsda(i2c); - udelay(i2c->op->udelay); - return sda; -} - -static inline int getscl(struct efx_i2c_interface *i2c) -{ - int scl; - - udelay(i2c->op->udelay); - scl = i2c->op->getscl(i2c); - udelay(i2c->op->udelay); - return scl; -} - -/* - * I2C low-level protocol operations - * - */ - -static inline void i2c_release(struct efx_i2c_interface *i2c) -{ - EFX_WARN_ON_PARANOID(!i2c->scl); - EFX_WARN_ON_PARANOID(!i2c->sda); - /* Devices may time out if operations do not end */ - setscl(i2c, 1); - setsda(i2c, 1); - EFX_BUG_ON_PARANOID(getsda(i2c) != 1); - EFX_BUG_ON_PARANOID(getscl(i2c) != 1); -} - -static inline void i2c_start(struct efx_i2c_interface *i2c) -{ - /* We may be restarting immediately after a {send,recv}_bit, - * so SCL will not necessarily already be high. - */ - EFX_WARN_ON_PARANOID(!i2c->sda); - setscl(i2c, 1); - setsda(i2c, 0); - setscl(i2c, 0); - setsda(i2c, 1); -} - -static inline void i2c_send_bit(struct efx_i2c_interface *i2c, int bit) -{ - EFX_WARN_ON_PARANOID(i2c->scl != 0); - setsda(i2c, bit); - setscl(i2c, 1); - setscl(i2c, 0); - setsda(i2c, 1); -} - -static inline int i2c_recv_bit(struct efx_i2c_interface *i2c) -{ - int bit; - - EFX_WARN_ON_PARANOID(i2c->scl != 0); - EFX_WARN_ON_PARANOID(!i2c->sda); - setscl(i2c, 1); - bit = getsda(i2c); - setscl(i2c, 0); - return bit; -} - -static inline void i2c_stop(struct efx_i2c_interface *i2c) -{ - EFX_WARN_ON_PARANOID(i2c->scl != 0); - setsda(i2c, 0); - setscl(i2c, 1); - setsda(i2c, 1); -} - -/* - * I2C mid-level protocol operations - * - */ - -/* Sends a byte via the I2C bus and checks for an acknowledgement from - * the slave device. - */ -static int i2c_send_byte(struct efx_i2c_interface *i2c, u8 byte) -{ - int i; - - /* Send byte */ - for (i = 0; i < 8; i++) { - i2c_send_bit(i2c, !!(byte & 0x80)); - byte <<= 1; - } - - /* Check for acknowledgement from slave */ - return (i2c_recv_bit(i2c) == 0 ? 0 : -EIO); -} - -/* Receives a byte via the I2C bus and sends ACK/NACK to the slave device. */ -static u8 i2c_recv_byte(struct efx_i2c_interface *i2c, int ack) -{ - u8 value = 0; - int i; - - /* Receive byte */ - for (i = 0; i < 8; i++) - value = (value << 1) | i2c_recv_bit(i2c); - - /* Send ACK/NACK */ - i2c_send_bit(i2c, (ack ? 0 : 1)); - - return value; -} - -/* Calculate command byte for a read operation */ -static inline u8 i2c_read_cmd(u8 device_id) -{ - return ((device_id << 1) | 1); -} - -/* Calculate command byte for a write operation */ -static inline u8 i2c_write_cmd(u8 device_id) -{ - return ((device_id << 1) | 0); -} - -int efx_i2c_check_presence(struct efx_i2c_interface *i2c, u8 device_id) -{ - int rc; - - /* If someone is driving the bus low we just give up. */ - if (getsda(i2c) == 0 || getscl(i2c) == 0) { - EFX_ERR(i2c->efx, "%s someone is holding the I2C bus low." - " Giving up.\n", __func__); - return -EFAULT; - } - - /* Pretend to initiate a device write */ - i2c_start(i2c); - rc = i2c_send_byte(i2c, i2c_write_cmd(device_id)); - if (rc) - goto out; - - out: - i2c_stop(i2c); - i2c_release(i2c); - - return rc; -} - -/* This performs a fast read of one or more consecutive bytes from an - * I2C device. Not all devices support consecutive reads of more than - * one byte; for these devices use efx_i2c_read() instead. - */ -int efx_i2c_fast_read(struct efx_i2c_interface *i2c, - u8 device_id, u8 offset, u8 *data, unsigned int len) -{ - int i; - int rc; - - EFX_WARN_ON_PARANOID(getsda(i2c) != 1); - EFX_WARN_ON_PARANOID(getscl(i2c) != 1); - EFX_WARN_ON_PARANOID(data == NULL); - EFX_WARN_ON_PARANOID(len < 1); - - /* Select device and starting offset */ - i2c_start(i2c); - rc = i2c_send_byte(i2c, i2c_write_cmd(device_id)); - if (rc) - goto out; - rc = i2c_send_byte(i2c, offset); - if (rc) - goto out; - - /* Read data from device */ - i2c_start(i2c); - rc = i2c_send_byte(i2c, i2c_read_cmd(device_id)); - if (rc) - goto out; - for (i = 0; i < (len - 1); i++) - /* Read and acknowledge all but the last byte */ - data[i] = i2c_recv_byte(i2c, 1); - /* Read last byte with no acknowledgement */ - data[i] = i2c_recv_byte(i2c, 0); - - out: - i2c_stop(i2c); - i2c_release(i2c); - - return rc; -} - -/* This performs a fast write of one or more consecutive bytes to an - * I2C device. Not all devices support consecutive writes of more - * than one byte; for these devices use efx_i2c_write() instead. - */ -int efx_i2c_fast_write(struct efx_i2c_interface *i2c, - u8 device_id, u8 offset, - const u8 *data, unsigned int len) -{ - int i; - int rc; - - EFX_WARN_ON_PARANOID(getsda(i2c) != 1); - EFX_WARN_ON_PARANOID(getscl(i2c) != 1); - EFX_WARN_ON_PARANOID(len < 1); - - /* Select device and starting offset */ - i2c_start(i2c); - rc = i2c_send_byte(i2c, i2c_write_cmd(device_id)); - if (rc) - goto out; - rc = i2c_send_byte(i2c, offset); - if (rc) - goto out; - - /* Write data to device */ - for (i = 0; i < len; i++) { - rc = i2c_send_byte(i2c, data[i]); - if (rc) - goto out; - } - - out: - i2c_stop(i2c); - i2c_release(i2c); - - return rc; -} - -/* I2C byte-by-byte read */ -int efx_i2c_read(struct efx_i2c_interface *i2c, - u8 device_id, u8 offset, u8 *data, unsigned int len) -{ - int rc; - - /* i2c_fast_read with length 1 is a single byte read */ - for (; len > 0; offset++, data++, len--) { - rc = efx_i2c_fast_read(i2c, device_id, offset, data, 1); - if (rc) - return rc; - } - - return 0; -} - -/* I2C byte-by-byte write */ -int efx_i2c_write(struct efx_i2c_interface *i2c, - u8 device_id, u8 offset, const u8 *data, unsigned int len) -{ - int rc; - - /* i2c_fast_write with length 1 is a single byte write */ - for (; len > 0; offset++, data++, len--) { - rc = efx_i2c_fast_write(i2c, device_id, offset, data, 1); - if (rc) - return rc; - mdelay(i2c->op->mdelay); - } - - return 0; -} - - -/* This is just a slightly neater wrapper round efx_i2c_fast_write - * in the case where the target doesn't take an offset - */ -int efx_i2c_send_bytes(struct efx_i2c_interface *i2c, - u8 device_id, const u8 *data, unsigned int len) -{ - return efx_i2c_fast_write(i2c, device_id, data[0], data + 1, len - 1); -} - -/* I2C receiving of bytes - does not send an offset byte */ -int efx_i2c_recv_bytes(struct efx_i2c_interface *i2c, u8 device_id, - u8 *bytes, unsigned int len) -{ - int i; - int rc; - - EFX_WARN_ON_PARANOID(getsda(i2c) != 1); - EFX_WARN_ON_PARANOID(getscl(i2c) != 1); - EFX_WARN_ON_PARANOID(len < 1); - - /* Select device */ - i2c_start(i2c); - - /* Read data from device */ - rc = i2c_send_byte(i2c, i2c_read_cmd(device_id)); - if (rc) - goto out; - - for (i = 0; i < (len - 1); i++) - /* Read and acknowledge all but the last byte */ - bytes[i] = i2c_recv_byte(i2c, 1); - /* Read last byte with no acknowledgement */ - bytes[i] = i2c_recv_byte(i2c, 0); - - out: - i2c_stop(i2c); - i2c_release(i2c); - - return rc; -} - -/* SMBus and some I2C devices will time out if the I2C clock is - * held low for too long. This is most likely to happen in virtualised - * systems (when the entire domain is descheduled) but could in - * principle happen due to preemption on any busy system (and given the - * potential length of an I2C operation turning preemption off is not - * a sensible option). The following functions deal with the failure by - * retrying up to a fixed number of times. - */ - -#define I2C_MAX_RETRIES (10) - -/* The timeout problem will result in -EIO. If the wrapped function - * returns any other error, pass this up and do not retry. */ -#define RETRY_WRAPPER(_f) \ - int retries = I2C_MAX_RETRIES; \ - int rc; \ - while (retries) { \ - rc = _f; \ - if (rc != -EIO) \ - return rc; \ - retries--; \ - } \ - return rc; \ - -int efx_i2c_check_presence_retry(struct efx_i2c_interface *i2c, u8 device_id) -{ - RETRY_WRAPPER(efx_i2c_check_presence(i2c, device_id)) -} - -int efx_i2c_read_retry(struct efx_i2c_interface *i2c, - u8 device_id, u8 offset, u8 *data, unsigned int len) -{ - RETRY_WRAPPER(efx_i2c_read(i2c, device_id, offset, data, len)) -} - -int efx_i2c_write_retry(struct efx_i2c_interface *i2c, - u8 device_id, u8 offset, const u8 *data, unsigned int len) -{ - RETRY_WRAPPER(efx_i2c_write(i2c, device_id, offset, data, len)) -} diff --git a/drivers/net/sfc/i2c-direct.h b/drivers/net/sfc/i2c-direct.h deleted file mode 100644 index 291e561071f5..000000000000 --- a/drivers/net/sfc/i2c-direct.h +++ /dev/null @@ -1,91 +0,0 @@ -/**************************************************************************** - * Driver for Solarflare Solarstorm network controllers and boards - * Copyright 2005 Fen Systems Ltd. - * 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_I2C_DIRECT_H -#define EFX_I2C_DIRECT_H - -#include "net_driver.h" - -/* - * Direct control of an I2C bus - */ - -struct efx_i2c_interface; - -/** - * struct efx_i2c_bit_operations - I2C bus direct control methods - * - * I2C bus direct control methods. - * - * @setsda: Set state of SDA line - * @setscl: Set state of SCL line - * @getsda: Get state of SDA line - * @getscl: Get state of SCL line - * @udelay: Delay between each bit operation - * @mdelay: Delay between each byte write - */ -struct efx_i2c_bit_operations { - void (*setsda) (struct efx_i2c_interface *i2c); - void (*setscl) (struct efx_i2c_interface *i2c); - int (*getsda) (struct efx_i2c_interface *i2c); - int (*getscl) (struct efx_i2c_interface *i2c); - unsigned int udelay; - unsigned int mdelay; -}; - -/** - * struct efx_i2c_interface - an I2C interface - * - * An I2C interface. - * - * @efx: Attached Efx NIC - * @op: I2C bus control methods - * @sda: Current output state of SDA line - * @scl: Current output state of SCL line - */ -struct efx_i2c_interface { - struct efx_nic *efx; - struct efx_i2c_bit_operations *op; - unsigned int sda:1; - unsigned int scl:1; -}; - -extern int efx_i2c_check_presence(struct efx_i2c_interface *i2c, u8 device_id); -extern int efx_i2c_fast_read(struct efx_i2c_interface *i2c, - u8 device_id, u8 offset, - u8 *data, unsigned int len); -extern int efx_i2c_fast_write(struct efx_i2c_interface *i2c, - u8 device_id, u8 offset, - const u8 *data, unsigned int len); -extern int efx_i2c_read(struct efx_i2c_interface *i2c, - u8 device_id, u8 offset, u8 *data, unsigned int len); -extern int efx_i2c_write(struct efx_i2c_interface *i2c, - u8 device_id, u8 offset, - const u8 *data, unsigned int len); - -extern int efx_i2c_send_bytes(struct efx_i2c_interface *i2c, u8 device_id, - const u8 *bytes, unsigned int len); - -extern int efx_i2c_recv_bytes(struct efx_i2c_interface *i2c, u8 device_id, - u8 *bytes, unsigned int len); - - -/* Versions of the API that retry on failure. */ -extern int efx_i2c_check_presence_retry(struct efx_i2c_interface *i2c, - u8 device_id); - -extern int efx_i2c_read_retry(struct efx_i2c_interface *i2c, - u8 device_id, u8 offset, u8 *data, unsigned int len); - -extern int efx_i2c_write_retry(struct efx_i2c_interface *i2c, - u8 device_id, u8 offset, - const u8 *data, unsigned int len); - -#endif /* EFX_I2C_DIRECT_H */ diff --git a/drivers/net/sfc/net_driver.h b/drivers/net/sfc/net_driver.h index 5e20e7551dae..d803b86c647c 100644 --- a/drivers/net/sfc/net_driver.h +++ b/drivers/net/sfc/net_driver.h @@ -26,10 +26,10 @@ #include <linux/highmem.h> #include <linux/workqueue.h> #include <linux/inet_lro.h> +#include <linux/i2c.h> #include "enum.h" #include "bitfield.h" -#include "i2c-direct.h" #define EFX_MAX_LRO_DESCRIPTORS 8 #define EFX_MAX_LRO_AGGR MAX_SKB_FRAGS @@ -418,7 +418,10 @@ struct efx_blinker { * @init_leds: Sets up board LEDs * @set_fault_led: Turns the fault LED on or off * @blink: Starts/stops blinking + * @fini: Cleanup function * @blinker: used to blink LEDs in software + * @hwmon_client: I2C client for hardware monitor + * @ioexp_client: I2C client for power/port control */ struct efx_board { int type; @@ -431,7 +434,9 @@ struct efx_board { int (*init_leds)(struct efx_nic *efx); void (*set_fault_led) (struct efx_nic *efx, int state); void (*blink) (struct efx_nic *efx, int start); + void (*fini) (struct efx_nic *nic); struct efx_blinker blinker; + struct i2c_client *hwmon_client, *ioexp_client; }; #define STRING_TABLE_LOOKUP(val, member) \ @@ -618,7 +623,7 @@ union efx_multicast_hash { * @membase: Memory BAR value * @biu_lock: BIU (bus interface unit) lock * @interrupt_mode: Interrupt mode - * @i2c: I2C interface + * @i2c_adap: I2C adapter * @board_info: Board-level information * @state: Device state flag. Serialised by the rtnl_lock. * @reset_pending: Pending reset method (normally RESET_TYPE_NONE) @@ -686,7 +691,7 @@ struct efx_nic { spinlock_t biu_lock; enum efx_int_mode interrupt_mode; - struct efx_i2c_interface i2c; + struct i2c_adapter i2c_adap; struct efx_board board_info; enum nic_state state; diff --git a/drivers/net/sfc/sfe4001.c b/drivers/net/sfc/sfe4001.c index 66a0d1442aba..b27849523990 100644 --- a/drivers/net/sfc/sfe4001.c +++ b/drivers/net/sfc/sfe4001.c @@ -106,28 +106,27 @@ static const u8 xgphy_max_temperature = 90; -void sfe4001_poweroff(struct efx_nic *efx) +static void sfe4001_poweroff(struct efx_nic *efx) { - struct efx_i2c_interface *i2c = &efx->i2c; + struct i2c_client *ioexp_client = efx->board_info.ioexp_client; + struct i2c_client *hwmon_client = efx->board_info.hwmon_client; - u8 cfg, out, in; + /* Turn off all power rails and disable outputs */ + i2c_smbus_write_byte_data(ioexp_client, P0_OUT, 0xff); + i2c_smbus_write_byte_data(ioexp_client, P1_CONFIG, 0xff); + i2c_smbus_write_byte_data(ioexp_client, P0_CONFIG, 0xff); - EFX_INFO(efx, "%s\n", __func__); - - /* Turn off all power rails */ - out = 0xff; - efx_i2c_write(i2c, PCA9539, P0_OUT, &out, 1); - - /* Disable port 1 outputs on IO expander */ - cfg = 0xff; - efx_i2c_write(i2c, PCA9539, P1_CONFIG, &cfg, 1); + /* Clear any over-temperature alert */ + i2c_smbus_read_byte_data(hwmon_client, RSL); +} - /* Disable port 0 outputs on IO expander */ - cfg = 0xff; - efx_i2c_write(i2c, PCA9539, P0_CONFIG, &cfg, 1); +static void sfe4001_fini(struct efx_nic *efx) +{ + EFX_INFO(efx, "%s\n", __func__); - /* Clear any over-temperature alert */ - efx_i2c_read(i2c, MAX6647, RSL, &in, 1); + sfe4001_poweroff(efx); + i2c_unregister_device(efx->board_info.ioexp_client); + i2c_unregister_device(efx->board_info.hwmon_client); } /* The P0_EN_3V3X line on SFE4001 boards (from A2 onward) is connected @@ -143,14 +142,26 @@ MODULE_PARM_DESC(phy_flash_cfg, * be turned on before the PHY can be used. * Context: Process context, rtnl lock held */ -int sfe4001_poweron(struct efx_nic *efx) +int sfe4001_init(struct efx_nic *efx) { - struct efx_i2c_interface *i2c = &efx->i2c; + struct i2c_client *hwmon_client, *ioexp_client; unsigned int count; int rc; - u8 out, in, cfg; + u8 out; efx_dword_t reg; + hwmon_client = i2c_new_dummy(&efx->i2c_adap, MAX6647); + if (!hwmon_client) + return -EIO; + efx->board_info.hwmon_client = hwmon_client; + + ioexp_client = i2c_new_dummy(&efx->i2c_adap, PCA9539); + if (!ioexp_client) { + rc = -EIO; + goto fail_hwmon; + } + efx->board_info.ioexp_client = ioexp_client; + /* 10Xpress has fixed-function LED pins, so there is no board-specific * blink code. */ efx->board_info.blink = tenxpress_phy_blink; @@ -166,44 +177,45 @@ int sfe4001_poweron(struct efx_nic *efx) falcon_xmac_writel(efx, ®, XX_PWR_RST_REG_MAC); udelay(10); + efx->board_info.fini = sfe4001_fini; + /* Set DSP over-temperature alert threshold */ EFX_INFO(efx, "DSP cut-out at %dC\n", xgphy_max_temperature); - rc = efx_i2c_write(i2c, MAX6647, WLHO, - &xgphy_max_temperature, 1); + rc = i2c_smbus_write_byte_data(hwmon_client, WLHO, + xgphy_max_temperature); if (rc) - goto fail1; + goto fail_ioexp; /* Read it back and verify */ - rc = efx_i2c_read(i2c, MAX6647, RLHN, &in, 1); - if (rc) - goto fail1; - if (in != xgphy_max_temperature) { + rc = i2c_smbus_read_byte_data(hwmon_client, RLHN); + if (rc < 0) + goto fail_ioexp; + if (rc != xgphy_max_temperature) { rc = -EFAULT; - goto fail1; + goto fail_ioexp; } /* Clear any previous over-temperature alert */ - rc = efx_i2c_read(i2c, MAX6647, RSL, &in, 1); - if (rc) - goto fail1; + rc = i2c_smbus_read_byte_data(hwmon_client, RSL); + if (rc < 0) + goto fail_ioexp; /* Enable port 0 and port 1 outputs on IO expander */ - cfg = 0x00; - rc = efx_i2c_write(i2c, PCA9539, P0_CONFIG, &cfg, 1); + rc = i2c_smbus_write_byte_data(ioexp_client, P0_CONFIG, 0x00); if (rc) - goto fail1; - cfg = 0xff & ~(1 << P1_SPARE_LBN); - rc = efx_i2c_write(i2c, PCA9539, P1_CONFIG, &cfg, 1); + goto fail_ioexp; + rc = i2c_smbus_write_byte_data(ioexp_client, P1_CONFIG, + 0xff & ~(1 << P1_SPARE_LBN)); if (rc) - goto fail2; + goto fail_on; /* Turn all power off then wait 1 sec. This ensures PHY is reset */ out = 0xff & ~((0 << P0_EN_1V2_LBN) | (0 << P0_EN_2V5_LBN) | (0 << P0_EN_3V3X_LBN) | (0 << P0_EN_5V_LBN) | (0 << P0_EN_1V0X_LBN)); - rc = efx_i2c_write(i2c, PCA9539, P0_OUT, &out, 1); + rc = i2c_smbus_write_byte_data(ioexp_client, P0_OUT, out); if (rc) - goto fail3; + goto fail_on; schedule_timeout_uninterruptible(HZ); count = 0; @@ -215,26 +227,26 @@ int sfe4001_poweron(struct efx_nic *efx) if (sfe4001_phy_flash_cfg) out |= 1 << P0_EN_3V3X_LBN; - rc = efx_i2c_write(i2c, PCA9539, P0_OUT, &out, 1); + rc = i2c_smbus_write_byte_data(ioexp_client, P0_OUT, out); if (rc) - goto fail3; + goto fail_on; msleep(10); /* Turn on 1V power rail */ out &= ~(1 << P0_EN_1V0X_LBN); - rc = efx_i2c_write(i2c, PCA9539, P0_OUT, &out, 1); + rc = i2c_smbus_write_byte_data(ioexp_client, P0_OUT, out); if (rc) - goto fail3; + goto fail_on; EFX_INFO(efx, "waiting for power (attempt %d)...\n", count); schedule_timeout_uninterruptible(HZ); /* Check DSP is powered */ - rc = efx_i2c_read(i2c, PCA9539, P1_IN, &in, 1); - if (rc) - goto fail3; - if (in & (1 << P1_AFE_PWD_LBN)) + rc = i2c_smbus_read_byte_data(ioexp_client, P1_IN); + if (rc < 0) + goto fail_on; + if (rc & (1 << P1_AFE_PWD_LBN)) goto done; /* DSP doesn't look powered in flash config mode */ @@ -244,23 +256,17 @@ int sfe4001_poweron(struct efx_nic *efx) EFX_INFO(efx, "timed out waiting for power\n"); rc = -ETIMEDOUT; - goto fail3; + goto fail_on; done: EFX_INFO(efx, "PHY is powered on\n"); return 0; -fail3: - /* Turn off all power rails */ - out = 0xff; - efx_i2c_write(i2c, PCA9539, P0_OUT, &out, 1); - /* Disable port 1 outputs on IO expander */ - out = 0xff; - efx_i2c_write(i2c, PCA9539, P1_CONFIG, &out, 1); -fail2: - /* Disable port 0 outputs on IO expander */ - out = 0xff; - efx_i2c_write(i2c, PCA9539, P0_CONFIG, &out, 1); -fail1: +fail_on: + sfe4001_poweroff(efx); +fail_ioexp: + i2c_unregister_device(ioexp_client); +fail_hwmon: + i2c_unregister_device(hwmon_client); return rc; } diff --git a/drivers/net/sh_eth.c b/drivers/net/sh_eth.c new file mode 100644 index 000000000000..a4bc812aa999 --- /dev/null +++ b/drivers/net/sh_eth.c @@ -0,0 +1,1174 @@ +/* + * SuperH Ethernet device driver + * + * Copyright (C) 2006,2007 Nobuhiro Iwamatsu + * Copyright (C) 2008 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, + * 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". + */ + +#include <linux/version.h> +#include <linux/init.h> +#include <linux/dma-mapping.h> +#include <linux/etherdevice.h> +#include <linux/delay.h> +#include <linux/platform_device.h> +#include <linux/mdio-bitbang.h> +#include <linux/netdevice.h> +#include <linux/phy.h> +#include <linux/cache.h> +#include <linux/io.h> + +#include "sh_eth.h" + +/* + * Program the hardware MAC address from dev->dev_addr. + */ +static void update_mac_address(struct net_device *ndev) +{ + u32 ioaddr = ndev->base_addr; + + ctrl_outl((ndev->dev_addr[0] << 24) | (ndev->dev_addr[1] << 16) | + (ndev->dev_addr[2] << 8) | (ndev->dev_addr[3]), + ioaddr + MAHR); + ctrl_outl((ndev->dev_addr[4] << 8) | (ndev->dev_addr[5]), + ioaddr + MALR); +} + +/* + * Get MAC address from SuperH MAC address register + * + * SuperH's Ethernet device doesn't have 'ROM' to MAC address. + * This driver get MAC address that use by bootloader(U-boot or sh-ipl+g). + * When you want use this device, you must set MAC address in bootloader. + * + */ +static void read_mac_address(struct net_device *ndev) +{ + u32 ioaddr = ndev->base_addr; + + ndev->dev_addr[0] = (ctrl_inl(ioaddr + MAHR) >> 24); + ndev->dev_addr[1] = (ctrl_inl(ioaddr + MAHR) >> 16) & 0xFF; + ndev->dev_addr[2] = (ctrl_inl(ioaddr + MAHR) >> 8) & 0xFF; + ndev->dev_addr[3] = (ctrl_inl(ioaddr + MAHR) & 0xFF); + ndev->dev_addr[4] = (ctrl_inl(ioaddr + MALR) >> 8) & 0xFF; + ndev->dev_addr[5] = (ctrl_inl(ioaddr + MALR) & 0xFF); +} + +struct bb_info { + struct mdiobb_ctrl ctrl; + u32 addr; + u32 mmd_msk;/* MMD */ + u32 mdo_msk; + u32 mdi_msk; + u32 mdc_msk; +}; + +/* PHY bit set */ +static void bb_set(u32 addr, u32 msk) +{ + ctrl_outl(ctrl_inl(addr) | msk, addr); +} + +/* PHY bit clear */ +static void bb_clr(u32 addr, u32 msk) +{ + ctrl_outl((ctrl_inl(addr) & ~msk), addr); +} + +/* PHY bit read */ +static int bb_read(u32 addr, u32 msk) +{ + return (ctrl_inl(addr) & msk) != 0; +} + +/* Data I/O pin control */ +static void sh_mmd_ctrl(struct mdiobb_ctrl *ctrl, int bit) +{ + struct bb_info *bitbang = container_of(ctrl, struct bb_info, ctrl); + if (bit) + bb_set(bitbang->addr, bitbang->mmd_msk); + else + bb_clr(bitbang->addr, bitbang->mmd_msk); +} + +/* Set bit data*/ +static void sh_set_mdio(struct mdiobb_ctrl *ctrl, int bit) +{ + struct bb_info *bitbang = container_of(ctrl, struct bb_info, ctrl); + + if (bit) + bb_set(bitbang->addr, bitbang->mdo_msk); + else + bb_clr(bitbang->addr, bitbang->mdo_msk); +} + +/* Get bit data*/ +static int sh_get_mdio(struct mdiobb_ctrl *ctrl) +{ + struct bb_info *bitbang = container_of(ctrl, struct bb_info, ctrl); + return bb_read(bitbang->addr, bitbang->mdi_msk); +} + +/* MDC pin control */ +static void sh_mdc_ctrl(struct mdiobb_ctrl *ctrl, int bit) +{ + struct bb_info *bitbang = container_of(ctrl, struct bb_info, ctrl); + + if (bit) + bb_set(bitbang->addr, bitbang->mdc_msk); + else + bb_clr(bitbang->addr, bitbang->mdc_msk); +} + +/* mdio bus control struct */ +static struct mdiobb_ops bb_ops = { + .owner = THIS_MODULE, + .set_mdc = sh_mdc_ctrl, + .set_mdio_dir = sh_mmd_ctrl, + .set_mdio_data = sh_set_mdio, + .get_mdio_data = sh_get_mdio, +}; + +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); +} + +/* free skb and descriptor buffer */ +static void sh_eth_ring_free(struct net_device *ndev) +{ + struct sh_eth_private *mdp = netdev_priv(ndev); + int i; + + /* Free Rx skb ringbuffer */ + if (mdp->rx_skbuff) { + for (i = 0; i < RX_RING_SIZE; i++) { + if (mdp->rx_skbuff[i]) + dev_kfree_skb(mdp->rx_skbuff[i]); + } + } + kfree(mdp->rx_skbuff); + + /* Free Tx skb ringbuffer */ + if (mdp->tx_skbuff) { + for (i = 0; i < TX_RING_SIZE; i++) { + if (mdp->tx_skbuff[i]) + dev_kfree_skb(mdp->tx_skbuff[i]); + } + } + kfree(mdp->tx_skbuff); +} + +/* format skb and descriptor buffer */ +static void sh_eth_ring_format(struct net_device *ndev) +{ + struct sh_eth_private *mdp = netdev_priv(ndev); + int i; + struct sk_buff *skb; + struct sh_eth_rxdesc *rxdesc = NULL; + struct sh_eth_txdesc *txdesc = NULL; + int rx_ringsize = sizeof(*rxdesc) * RX_RING_SIZE; + int tx_ringsize = sizeof(*txdesc) * TX_RING_SIZE; + + mdp->cur_rx = mdp->cur_tx = 0; + mdp->dirty_rx = mdp->dirty_tx = 0; + + memset(mdp->rx_ring, 0, rx_ringsize); + + /* build Rx ring buffer */ + for (i = 0; i < RX_RING_SIZE; i++) { + /* skb */ + mdp->rx_skbuff[i] = NULL; + skb = dev_alloc_skb(mdp->rx_buf_sz); + mdp->rx_skbuff[i] = skb; + if (skb == NULL) + break; + skb->dev = ndev; /* Mark as being used by this device. */ + skb_reserve(skb, RX_OFFSET); + + /* RX descriptor */ + rxdesc = &mdp->rx_ring[i]; + rxdesc->addr = (u32)skb->data & ~0x3UL; + rxdesc->status = cpu_to_le32(RD_RACT | RD_RFP); + + /* The size of the buffer is 16 byte boundary. */ + rxdesc->buffer_length = (mdp->rx_buf_sz + 16) & ~0x0F; + } + + mdp->dirty_rx = (u32) (i - RX_RING_SIZE); + + /* Mark the last entry as wrapping the ring. */ + rxdesc->status |= cpu_to_le32(RC_RDEL); + + memset(mdp->tx_ring, 0, tx_ringsize); + + /* build Tx ring buffer */ + for (i = 0; i < TX_RING_SIZE; i++) { + mdp->tx_skbuff[i] = NULL; + txdesc = &mdp->tx_ring[i]; + txdesc->status = cpu_to_le32(TD_TFP); + txdesc->buffer_length = 0; + } + + txdesc->status |= cpu_to_le32(TD_TDLE); +} + +/* Get skb and descriptor buffer */ +static int sh_eth_ring_init(struct net_device *ndev) +{ + struct sh_eth_private *mdp = netdev_priv(ndev); + int rx_ringsize, tx_ringsize, ret = 0; + + /* + * +26 gets the maximum ethernet encapsulation, +7 & ~7 because the + * card needs room to do 8 byte alignment, +2 so we can reserve + * the first 2 bytes, and +16 gets room for the status word from the + * card. + */ + mdp->rx_buf_sz = (ndev->mtu <= 1492 ? PKT_BUF_SZ : + (((ndev->mtu + 26 + 7) & ~7) + 2 + 16)); + + /* Allocate RX and TX skb rings */ + 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); + ret = -ENOMEM; + return ret; + } + + 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); + ret = -ENOMEM; + goto skb_ring_free; + } + + /* Allocate all Rx descriptors. */ + rx_ringsize = sizeof(struct sh_eth_rxdesc) * RX_RING_SIZE; + mdp->rx_ring = dma_alloc_coherent(NULL, rx_ringsize, &mdp->rx_desc_dma, + GFP_KERNEL); + + if (!mdp->rx_ring) { + printk(KERN_ERR "%s: Cannot allocate Rx Ring (size %d bytes)\n", + ndev->name, rx_ringsize); + ret = -ENOMEM; + goto desc_ring_free; + } + + mdp->dirty_rx = 0; + + /* Allocate all Tx descriptors. */ + tx_ringsize = sizeof(struct sh_eth_txdesc) * TX_RING_SIZE; + 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); + ret = -ENOMEM; + goto desc_ring_free; + } + return ret; + +desc_ring_free: + /* free DMA buffer */ + dma_free_coherent(NULL, rx_ringsize, mdp->rx_ring, mdp->rx_desc_dma); + +skb_ring_free: + /* Free Rx and Tx skb ring buffer */ + sh_eth_ring_free(ndev); + + return ret; +} + +static int sh_eth_dev_init(struct net_device *ndev) +{ + int ret = 0; + struct sh_eth_private *mdp = netdev_priv(ndev); + u32 ioaddr = ndev->base_addr; + u_int32_t rx_int_var, tx_int_var; + u32 val; + + /* Soft Reset */ + sh_eth_reset(ndev); + + ctrl_outl(RPADIR_PADS1, ioaddr + RPADIR); /* SH7712-DMA-RX-PAD2 */ + + /* all sh_eth int mask */ + ctrl_outl(0, ioaddr + EESIPR); + + /* FIFO size set */ + ctrl_outl(0, ioaddr + EDMR); /* Endian change */ + + ctrl_outl((FIFO_SIZE_T | FIFO_SIZE_R), ioaddr + FDR); + ctrl_outl(0, ioaddr + TFTR); + + ctrl_outl(0, 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); + + ctrl_outl((FIFO_F_D_RFF | FIFO_F_D_RFD), ioaddr + FCFTR); + ctrl_outl(0, ioaddr + TRIMD); + + /* Descriptor format */ + sh_eth_ring_format(ndev); + + ctrl_outl((u32)mdp->rx_ring, ioaddr + RDLAR); + ctrl_outl((u32)mdp->tx_ring, ioaddr + TDLAR); + + ctrl_outl(ctrl_inl(ioaddr + EESR), ioaddr + EESR); + ctrl_outl((DMAC_M_RFRMER | DMAC_M_ECI | 0x003fffff), ioaddr + EESIPR); + + /* PAUSE Prohibition */ + val = (ctrl_inl(ioaddr + ECMR) & ECMR_DM) | + ECMR_ZPF | (mdp->duplex ? ECMR_DM : 0) | ECMR_TE | ECMR_RE; + + ctrl_outl(val, ioaddr + ECMR); + ctrl_outl(ECSR_BRCRX | ECSR_PSRTO | ECSR_LCHNG | ECSR_ICD | + ECSIPR_MPDIP, ioaddr + ECSR); + ctrl_outl(ECSIPR_BRCRXIP | ECSIPR_PSRTOIP | ECSIPR_LCHNGIP | + ECSIPR_ICDIP | ECSIPR_MPDIP, ioaddr + ECSIPR); + + /* Set MAC address */ + update_mac_address(ndev); + + /* mask reset */ +#if defined(CONFIG_CPU_SUBTYPE_SH7710) + ctrl_outl(APR_AP, ioaddr + APR); + ctrl_outl(MPR_MP, ioaddr + MPR); + ctrl_outl(TPAUSER_UNLIMITED, ioaddr + TPAUSER); + ctrl_outl(BCFR_UNLIMITED, ioaddr + BCFR); +#endif + /* Setting the Rx mode will start the Rx process. */ + ctrl_outl(EDRRR_R, ioaddr + EDRRR); + + netif_start_queue(ndev); + + return ret; +} + +/* free Tx skb function */ +static int sh_eth_txfree(struct net_device *ndev) +{ + struct sh_eth_private *mdp = netdev_priv(ndev); + struct sh_eth_txdesc *txdesc; + int freeNum = 0; + int entry = 0; + + for (; mdp->cur_tx - mdp->dirty_tx > 0; mdp->dirty_tx++) { + entry = mdp->dirty_tx % TX_RING_SIZE; + txdesc = &mdp->tx_ring[entry]; + if (txdesc->status & cpu_to_le32(TD_TACT)) + break; + /* Free the original skb. */ + if (mdp->tx_skbuff[entry]) { + dev_kfree_skb_irq(mdp->tx_skbuff[entry]); + mdp->tx_skbuff[entry] = NULL; + freeNum++; + } + txdesc->status = cpu_to_le32(TD_TFP); + if (entry >= TX_RING_SIZE - 1) + txdesc->status |= cpu_to_le32(TD_TDLE); + + mdp->stats.tx_packets++; + mdp->stats.tx_bytes += txdesc->buffer_length; + } + return freeNum; +} + +/* Packet receive function */ +static int sh_eth_rx(struct net_device *ndev) +{ + struct sh_eth_private *mdp = netdev_priv(ndev); + struct sh_eth_rxdesc *rxdesc; + + int entry = mdp->cur_rx % RX_RING_SIZE; + int boguscnt = (mdp->dirty_rx + RX_RING_SIZE) - mdp->cur_rx; + struct sk_buff *skb; + u16 pkt_len = 0; + u32 desc_status; + + rxdesc = &mdp->rx_ring[entry]; + while (!(rxdesc->status & cpu_to_le32(RD_RACT))) { + desc_status = le32_to_cpu(rxdesc->status); + pkt_len = rxdesc->frame_length; + + if (--boguscnt < 0) + break; + + if (!(desc_status & RDFEND)) + mdp->stats.rx_length_errors++; + + if (desc_status & (RD_RFS1 | RD_RFS2 | RD_RFS3 | RD_RFS4 | + RD_RFS5 | RD_RFS6 | RD_RFS10)) { + mdp->stats.rx_errors++; + if (desc_status & RD_RFS1) + mdp->stats.rx_crc_errors++; + if (desc_status & RD_RFS2) + mdp->stats.rx_frame_errors++; + if (desc_status & RD_RFS3) + mdp->stats.rx_length_errors++; + if (desc_status & RD_RFS4) + mdp->stats.rx_length_errors++; + if (desc_status & RD_RFS6) + mdp->stats.rx_missed_errors++; + if (desc_status & RD_RFS10) + mdp->stats.rx_over_errors++; + } else { + swaps((char *)(rxdesc->addr & ~0x3), pkt_len + 2); + skb = mdp->rx_skbuff[entry]; + mdp->rx_skbuff[entry] = NULL; + skb_put(skb, pkt_len); + skb->protocol = eth_type_trans(skb, ndev); + netif_rx(skb); + ndev->last_rx = jiffies; + mdp->stats.rx_packets++; + mdp->stats.rx_bytes += pkt_len; + } + rxdesc->status |= cpu_to_le32(RD_RACT); + entry = (++mdp->cur_rx) % RX_RING_SIZE; + } + + /* Refill the Rx ring buffers. */ + for (; mdp->cur_rx - mdp->dirty_rx > 0; mdp->dirty_rx++) { + entry = mdp->dirty_rx % RX_RING_SIZE; + rxdesc = &mdp->rx_ring[entry]; + if (mdp->rx_skbuff[entry] == NULL) { + skb = dev_alloc_skb(mdp->rx_buf_sz); + mdp->rx_skbuff[entry] = skb; + if (skb == NULL) + break; /* Better luck next round. */ + skb->dev = ndev; + skb_reserve(skb, RX_OFFSET); + rxdesc->addr = (u32)skb->data & ~0x3UL; + } + /* The size of the buffer is 16 byte boundary. */ + rxdesc->buffer_length = (mdp->rx_buf_sz + 16) & ~0x0F; + if (entry >= RX_RING_SIZE - 1) + rxdesc->status |= + cpu_to_le32(RD_RACT | RD_RFP | RC_RDEL); + else + rxdesc->status |= + cpu_to_le32(RD_RACT | RD_RFP); + } + + /* Restart Rx engine if stopped. */ + /* If we don't need to check status, don't. -KDU */ + ctrl_outl(EDRRR_R, ndev->base_addr + EDRRR); + + return 0; +} + +/* error control function */ +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; + + if (intr_status & EESR_ECI) { + felic_stat = ctrl_inl(ioaddr + ECSR); + ctrl_outl(felic_stat, ioaddr + ECSR); /* clear int */ + if (felic_stat & ECSR_ICD) + mdp->stats.tx_carrier_errors++; + if (felic_stat & ECSR_LCHNG) { + /* Link Changed */ + u32 link_stat = (ctrl_inl(ioaddr + PSR)); + if (!(link_stat & PHY_ST_LINK)) { + /* Link Down : disable tx and rx */ + ctrl_outl(ctrl_inl(ioaddr + ECMR) & + ~(ECMR_RE | ECMR_TE), ioaddr + ECMR); + } else { + /* Link Up */ + ctrl_outl(ctrl_inl(ioaddr + EESIPR) & + ~DMAC_M_ECI, ioaddr + EESIPR); + /*clear int */ + ctrl_outl(ctrl_inl(ioaddr + ECSR), + ioaddr + ECSR); + ctrl_outl(ctrl_inl(ioaddr + EESIPR) | + DMAC_M_ECI, ioaddr + EESIPR); + /* enable tx and rx */ + ctrl_outl(ctrl_inl(ioaddr + ECMR) | + (ECMR_RE | ECMR_TE), ioaddr + ECMR); + } + } + } + + if (intr_status & EESR_TWB) { + /* Write buck end. unused write back interrupt */ + if (intr_status & EESR_TABT) /* Transmit Abort int */ + mdp->stats.tx_aborted_errors++; + } + + if (intr_status & EESR_RABT) { + /* Receive Abort int */ + if (intr_status & EESR_RFRMER) { + /* Receive Frame Overflow int */ + mdp->stats.rx_frame_errors++; + printk(KERN_ERR "Receive Frame Overflow\n"); + } + } + + if (intr_status & EESR_ADE) { + if (intr_status & EESR_TDE) { + if (intr_status & EESR_TFE) + mdp->stats.tx_fifo_errors++; + } + } + + if (intr_status & EESR_RDE) { + /* Receive Descriptor Empty int */ + mdp->stats.rx_over_errors++; + + if (ctrl_inl(ioaddr + EDRRR) ^ EDRRR_R) + ctrl_outl(EDRRR_R, ioaddr + EDRRR); + printk(KERN_ERR "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"); + } + if (intr_status & + (EESR_TWB | EESR_TABT | EESR_ADE | EESR_TDE | EESR_TFE)) { + /* 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", + mdp->dirty_tx, (u32) ndev->state, edtrr); + /* dirty buffer free */ + sh_eth_txfree(ndev); + + /* SH7712 BUG */ + if (edtrr ^ EDTRR_TRNS) { + /* tx dma start */ + ctrl_outl(EDTRR_TRNS, ndev->base_addr + EDTRR); + } + /* wakeup */ + netif_wake_queue(ndev); + } +} + +static irqreturn_t sh_eth_interrupt(int irq, void *netdev) +{ + struct net_device *ndev = netdev; + struct sh_eth_private *mdp = netdev_priv(ndev); + u32 ioaddr, boguscnt = RX_RING_SIZE; + u32 intr_status = 0; + + ioaddr = ndev->base_addr; + spin_lock(&mdp->lock); + + intr_status = ctrl_inl(ioaddr + EESR); + /* Clear interrupt */ + ctrl_outl(intr_status, ioaddr + EESR); + + if (intr_status & (EESR_FRC | EESR_RINT8 | + EESR_RINT5 | EESR_RINT4 | EESR_RINT3 | EESR_RINT2 | + EESR_RINT1)) + sh_eth_rx(ndev); + if (intr_status & (EESR_FTC | + EESR_TINT4 | EESR_TINT3 | EESR_TINT2 | EESR_TINT1)) { + + sh_eth_txfree(ndev); + netif_wake_queue(ndev); + } + + if (intr_status & EESR_ERR_CHECK) + sh_eth_error(ndev, intr_status); + + if (--boguscnt < 0) { + printk(KERN_WARNING + "%s: Too much work at interrupt, status=0x%4.4x.\n", + ndev->name, intr_status); + } + + spin_unlock(&mdp->lock); + + return IRQ_HANDLED; +} + +static void sh_eth_timer(unsigned long data) +{ + struct net_device *ndev = (struct net_device *)data; + struct sh_eth_private *mdp = netdev_priv(ndev); + + mod_timer(&mdp->timer, jiffies + (10 * HZ)); +} + +/* PHY state control function */ +static void sh_eth_adjust_link(struct net_device *ndev) +{ + struct sh_eth_private *mdp = netdev_priv(ndev); + struct phy_device *phydev = mdp->phydev; + u32 ioaddr = ndev->base_addr; + int new_state = 0; + + if (phydev->link != PHY_DOWN) { + if (phydev->duplex != mdp->duplex) { + new_state = 1; + mdp->duplex = phydev->duplex; + } + + if (phydev->speed != mdp->speed) { + new_state = 1; + mdp->speed = phydev->speed; + } + if (mdp->link == PHY_DOWN) { + ctrl_outl((ctrl_inl(ioaddr + ECMR) & ~ECMR_TXF) + | ECMR_DM, ioaddr + ECMR); + new_state = 1; + mdp->link = phydev->link; + netif_tx_schedule_all(ndev); + netif_carrier_on(ndev); + netif_start_queue(ndev); + } + } else if (mdp->link) { + new_state = 1; + mdp->link = PHY_DOWN; + mdp->speed = 0; + mdp->duplex = -1; + netif_stop_queue(ndev); + netif_carrier_off(ndev); + } + + if (new_state) + phy_print_status(phydev); +} + +/* PHY init function */ +static int sh_eth_phy_init(struct net_device *ndev) +{ + struct sh_eth_private *mdp = netdev_priv(ndev); + char phy_id[BUS_ID_SIZE]; + struct phy_device *phydev = NULL; + + snprintf(phy_id, BUS_ID_SIZE, PHY_ID_FMT, + mdp->mii_bus->id , mdp->phy_id); + + mdp->link = PHY_DOWN; + mdp->speed = 0; + mdp->duplex = -1; + + /* Try connect to PHY */ + phydev = phy_connect(ndev, phy_id, &sh_eth_adjust_link, + 0, PHY_INTERFACE_MODE_MII); + if (IS_ERR(phydev)) { + 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); + + mdp->phydev = phydev; + + return 0; +} + +/* PHY control start function */ +static int sh_eth_phy_start(struct net_device *ndev) +{ + struct sh_eth_private *mdp = netdev_priv(ndev); + int ret; + + ret = sh_eth_phy_init(ndev); + if (ret) + return ret; + + /* reset phy - this also wakes it from PDOWN */ + phy_write(mdp->phydev, MII_BMCR, BMCR_RESET); + phy_start(mdp->phydev); + + return 0; +} + +/* network device open function */ +static int sh_eth_open(struct net_device *ndev) +{ + int ret = 0; + struct sh_eth_private *mdp = netdev_priv(ndev); + + ret = request_irq(ndev->irq, &sh_eth_interrupt, 0, ndev->name, ndev); + if (ret) { + printk(KERN_ERR "Can not assign IRQ number to %s\n", CARDNAME); + return ret; + } + + /* Descriptor set */ + ret = sh_eth_ring_init(ndev); + if (ret) + goto out_free_irq; + + /* device init */ + ret = sh_eth_dev_init(ndev); + if (ret) + goto out_free_irq; + + /* PHY control start*/ + ret = sh_eth_phy_start(ndev); + if (ret) + goto out_free_irq; + + /* Set the timer to check for link beat. */ + init_timer(&mdp->timer); + mdp->timer.expires = (jiffies + (24 * HZ)) / 10;/* 2.4 sec. */ + setup_timer(&mdp->timer, sh_eth_timer, ndev); + + return ret; + +out_free_irq: + free_irq(ndev->irq, ndev); + return ret; +} + +/* Timeout function */ +static void sh_eth_tx_timeout(struct net_device *ndev) +{ + struct sh_eth_private *mdp = netdev_priv(ndev); + u32 ioaddr = ndev->base_addr; + struct sh_eth_rxdesc *rxdesc; + int i; + + netif_stop_queue(ndev); + + /* worning message out. */ + printk(KERN_WARNING "%s: transmit timed out, status %8.8x," + " resetting...\n", ndev->name, (int)ctrl_inl(ioaddr + EESR)); + + /* tx_errors count up */ + mdp->stats.tx_errors++; + + /* timer off */ + del_timer_sync(&mdp->timer); + + /* Free all the skbuffs in the Rx queue. */ + for (i = 0; i < RX_RING_SIZE; i++) { + rxdesc = &mdp->rx_ring[i]; + rxdesc->status = 0; + rxdesc->addr = 0xBADF00D0; + if (mdp->rx_skbuff[i]) + dev_kfree_skb(mdp->rx_skbuff[i]); + mdp->rx_skbuff[i] = NULL; + } + for (i = 0; i < TX_RING_SIZE; i++) { + if (mdp->tx_skbuff[i]) + dev_kfree_skb(mdp->tx_skbuff[i]); + mdp->tx_skbuff[i] = NULL; + } + + /* device init */ + sh_eth_dev_init(ndev); + + /* timer on */ + mdp->timer.expires = (jiffies + (24 * HZ)) / 10;/* 2.4 sec. */ + add_timer(&mdp->timer); +} + +/* Packet transmit function */ +static int sh_eth_start_xmit(struct sk_buff *skb, struct net_device *ndev) +{ + struct sh_eth_private *mdp = netdev_priv(ndev); + struct sh_eth_txdesc *txdesc; + u32 entry; + int flags; + + spin_lock_irqsave(&mdp->lock, flags); + if ((mdp->cur_tx - mdp->dirty_tx) >= (TX_RING_SIZE - 4)) { + if (!sh_eth_txfree(ndev)) { + netif_stop_queue(ndev); + spin_unlock_irqrestore(&mdp->lock, flags); + return 1; + } + } + spin_unlock_irqrestore(&mdp->lock, flags); + + entry = mdp->cur_tx % TX_RING_SIZE; + mdp->tx_skbuff[entry] = skb; + txdesc = &mdp->tx_ring[entry]; + txdesc->addr = (u32)(skb->data); + /* soft swap. */ + swaps((char *)(txdesc->addr & ~0x3), skb->len + 2); + /* write back */ + __flush_purge_region(skb->data, skb->len); + if (skb->len < ETHERSMALL) + txdesc->buffer_length = ETHERSMALL; + else + txdesc->buffer_length = skb->len; + + if (entry >= TX_RING_SIZE - 1) + txdesc->status |= cpu_to_le32(TD_TACT | TD_TDLE); + else + txdesc->status |= cpu_to_le32(TD_TACT); + + mdp->cur_tx++; + + ctrl_outl(EDTRR_TRNS, ndev->base_addr + EDTRR); + ndev->trans_start = jiffies; + + return 0; +} + +/* device close function */ +static int sh_eth_close(struct net_device *ndev) +{ + struct sh_eth_private *mdp = netdev_priv(ndev); + u32 ioaddr = ndev->base_addr; + int ringsize; + + netif_stop_queue(ndev); + + /* Disable interrupts by clearing the interrupt mask. */ + ctrl_outl(0x0000, ioaddr + EESIPR); + + /* Stop the chip's Tx and Rx processes. */ + ctrl_outl(0, ioaddr + EDTRR); + ctrl_outl(0, ioaddr + EDRRR); + + /* PHY Disconnect */ + if (mdp->phydev) { + phy_stop(mdp->phydev); + phy_disconnect(mdp->phydev); + } + + free_irq(ndev->irq, ndev); + + del_timer_sync(&mdp->timer); + + /* Free all the skbuffs in the Rx queue. */ + sh_eth_ring_free(ndev); + + /* free DMA buffer */ + ringsize = sizeof(struct sh_eth_rxdesc) * RX_RING_SIZE; + dma_free_coherent(NULL, ringsize, mdp->rx_ring, mdp->rx_desc_dma); + + /* free DMA buffer */ + ringsize = sizeof(struct sh_eth_txdesc) * TX_RING_SIZE; + dma_free_coherent(NULL, ringsize, mdp->tx_ring, mdp->tx_desc_dma); + + return 0; +} + +static struct net_device_stats *sh_eth_get_stats(struct net_device *ndev) +{ + struct sh_eth_private *mdp = netdev_priv(ndev); + u32 ioaddr = ndev->base_addr; + + mdp->stats.tx_dropped += ctrl_inl(ioaddr + TROCR); + ctrl_outl(0, ioaddr + TROCR); /* (write clear) */ + mdp->stats.collisions += ctrl_inl(ioaddr + CDCR); + ctrl_outl(0, ioaddr + CDCR); /* (write clear) */ + mdp->stats.tx_carrier_errors += ctrl_inl(ioaddr + LCCR); + ctrl_outl(0, ioaddr + LCCR); /* (write clear) */ + mdp->stats.tx_carrier_errors += ctrl_inl(ioaddr + CNDCR); + ctrl_outl(0, ioaddr + CNDCR); /* (write clear) */ + + return &mdp->stats; +} + +/* ioctl to device funciotn*/ +static int sh_eth_do_ioctl(struct net_device *ndev, struct ifreq *rq, + int cmd) +{ + struct sh_eth_private *mdp = netdev_priv(ndev); + struct phy_device *phydev = mdp->phydev; + + if (!netif_running(ndev)) + return -EINVAL; + + if (!phydev) + return -ENODEV; + + return phy_mii_ioctl(phydev, if_mii(rq), cmd); +} + + +/* Multicast reception directions set */ +static void sh_eth_set_multicast_list(struct net_device *ndev) +{ + u32 ioaddr = ndev->base_addr; + + if (ndev->flags & IFF_PROMISC) { + /* Set promiscuous. */ + ctrl_outl((ctrl_inl(ioaddr + ECMR) & ~ECMR_MCT) | ECMR_PRM, + ioaddr + ECMR); + } else { + /* Normal, unicast/broadcast-only mode. */ + ctrl_outl((ctrl_inl(ioaddr + ECMR) & ~ECMR_PRM) | ECMR_MCT, + ioaddr + ECMR); + } +} + +/* SuperH's TSU register init function */ +static void sh_eth_tsu_init(u32 ioaddr) +{ + ctrl_outl(0, ioaddr + TSU_FWEN0); /* Disable forward(0->1) */ + ctrl_outl(0, ioaddr + TSU_FWEN1); /* Disable forward(1->0) */ + ctrl_outl(0, ioaddr + TSU_FCM); /* forward fifo 3k-3k */ + ctrl_outl(0xc, ioaddr + TSU_BSYSL0); + ctrl_outl(0xc, ioaddr + TSU_BSYSL1); + ctrl_outl(0, ioaddr + TSU_PRISL0); + ctrl_outl(0, ioaddr + TSU_PRISL1); + ctrl_outl(0, ioaddr + TSU_FWSL0); + ctrl_outl(0, ioaddr + TSU_FWSL1); + ctrl_outl(TSU_FWSLC_POSTENU | TSU_FWSLC_POSTENL, ioaddr + TSU_FWSLC); + ctrl_outl(0, ioaddr + TSU_QTAGM0); /* Disable QTAG(0->1) */ + ctrl_outl(0, ioaddr + TSU_QTAGM1); /* Disable QTAG(1->0) */ + ctrl_outl(0, ioaddr + TSU_FWSR); /* all interrupt status clear */ + ctrl_outl(0, ioaddr + TSU_FWINMK); /* Disable all interrupt */ + ctrl_outl(0, ioaddr + TSU_TEN); /* Disable all CAM entry */ + ctrl_outl(0, ioaddr + TSU_POST1); /* Disable CAM entry [ 0- 7] */ + ctrl_outl(0, ioaddr + TSU_POST2); /* Disable CAM entry [ 8-15] */ + ctrl_outl(0, ioaddr + TSU_POST3); /* Disable CAM entry [16-23] */ + ctrl_outl(0, ioaddr + TSU_POST4); /* Disable CAM entry [24-31] */ +} + +/* MDIO bus release function */ +static int sh_mdio_release(struct net_device *ndev) +{ + struct mii_bus *bus = dev_get_drvdata(&ndev->dev); + + /* unregister mdio bus */ + mdiobus_unregister(bus); + + /* remove mdio bus info from net_device */ + dev_set_drvdata(&ndev->dev, NULL); + + /* free bitbang info */ + free_mdio_bitbang(bus); + + return 0; +} + +/* MDIO bus init function */ +static int sh_mdio_init(struct net_device *ndev, int id) +{ + int ret, i; + struct bb_info *bitbang; + struct sh_eth_private *mdp = netdev_priv(ndev); + + /* create bit control struct for PHY */ + bitbang = kzalloc(sizeof(struct bb_info), GFP_KERNEL); + if (!bitbang) { + ret = -ENOMEM; + goto out; + } + + /* bitbang init */ + bitbang->addr = ndev->base_addr + PIR; + bitbang->mdi_msk = 0x08; + bitbang->mdo_msk = 0x04; + bitbang->mmd_msk = 0x02;/* MMD */ + bitbang->mdc_msk = 0x01; + bitbang->ctrl.ops = &bb_ops; + + /* MII contorller setting */ + mdp->mii_bus = alloc_mdio_bitbang(&bitbang->ctrl); + if (!mdp->mii_bus) { + ret = -ENOMEM; + goto out_free_bitbang; + } + + /* Hook up MII support for ethtool */ + mdp->mii_bus->name = "sh_mii"; + mdp->mii_bus->dev = &ndev->dev; + mdp->mii_bus->id[0] = id; + + /* PHY IRQ */ + mdp->mii_bus->irq = kmalloc(sizeof(int)*PHY_MAX_ADDR, GFP_KERNEL); + if (!mdp->mii_bus->irq) { + ret = -ENOMEM; + goto out_free_bus; + } + + for (i = 0; i < PHY_MAX_ADDR; i++) + mdp->mii_bus->irq[i] = PHY_POLL; + + /* regist mdio bus */ + ret = mdiobus_register(mdp->mii_bus); + if (ret) + goto out_free_irq; + + dev_set_drvdata(&ndev->dev, mdp->mii_bus); + + return 0; + +out_free_irq: + kfree(mdp->mii_bus->irq); + +out_free_bus: + kfree(mdp->mii_bus); + +out_free_bitbang: + kfree(bitbang); + +out: + return ret; +} + +static int sh_eth_drv_probe(struct platform_device *pdev) +{ + int ret, i, devno = 0; + struct resource *res; + struct net_device *ndev = NULL; + struct sh_eth_private *mdp; + + /* get base addr */ + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (unlikely(res == NULL)) { + dev_err(&pdev->dev, "invalid resource\n"); + ret = -EINVAL; + goto out; + } + + ndev = alloc_etherdev(sizeof(struct sh_eth_private)); + if (!ndev) { + printk(KERN_ERR "%s: could not allocate device.\n", CARDNAME); + ret = -ENOMEM; + goto out; + } + + /* The sh Ether-specific entries in the device structure. */ + ndev->base_addr = res->start; + devno = pdev->id; + if (devno < 0) + devno = 0; + + ndev->dma = -1; + ndev->irq = platform_get_irq(pdev, 0); + if (ndev->irq < 0) { + ret = -ENODEV; + goto out_release; + } + + SET_NETDEV_DEV(ndev, &pdev->dev); + + /* Fill in the fields of the device structure with ethernet values. */ + ether_setup(ndev); + + mdp = netdev_priv(ndev); + spin_lock_init(&mdp->lock); + + /* get PHY ID */ + mdp->phy_id = (int)pdev->dev.platform_data; + + /* set function */ + ndev->open = sh_eth_open; + ndev->hard_start_xmit = sh_eth_start_xmit; + ndev->stop = sh_eth_close; + ndev->get_stats = sh_eth_get_stats; + ndev->set_multicast_list = sh_eth_set_multicast_list; + ndev->do_ioctl = sh_eth_do_ioctl; + ndev->tx_timeout = sh_eth_tx_timeout; + ndev->watchdog_timeo = TX_TIMEOUT; + + mdp->post_rx = POST_RX >> (devno << 1); + mdp->post_fw = POST_FW >> (devno << 1); + + /* read and set MAC address */ + read_mac_address(ndev); + + /* First device only init */ + if (!devno) { + /* reset device */ + ctrl_outl(ARSTR_ARSTR, ndev->base_addr + ARSTR); + mdelay(1); + + /* TSU init (Init only)*/ + sh_eth_tsu_init(SH_TSU_ADDR); + } + + /* network device register */ + ret = register_netdev(ndev); + if (ret) + goto out_release; + + /* mdio bus init */ + ret = sh_mdio_init(ndev, pdev->id); + if (ret) + goto out_unregister; + + /* pritnt device infomation */ + printk(KERN_INFO "%s: %s at 0x%x, ", + ndev->name, CARDNAME, (u32) ndev->base_addr); + + for (i = 0; i < 5; i++) + printk(KERN_INFO "%2.2x:", ndev->dev_addr[i]); + printk(KERN_INFO "%2.2x, IRQ %d.\n", ndev->dev_addr[i], ndev->irq); + + platform_set_drvdata(pdev, ndev); + + return ret; + +out_unregister: + unregister_netdev(ndev); + +out_release: + /* net_dev free */ + if (ndev) + free_netdev(ndev); + +out: + return ret; +} + +static int sh_eth_drv_remove(struct platform_device *pdev) +{ + struct net_device *ndev = platform_get_drvdata(pdev); + + sh_mdio_release(ndev); + unregister_netdev(ndev); + flush_scheduled_work(); + + free_netdev(ndev); + platform_set_drvdata(pdev, NULL); + + return 0; +} + +static struct platform_driver sh_eth_driver = { + .probe = sh_eth_drv_probe, + .remove = sh_eth_drv_remove, + .driver = { + .name = CARDNAME, + }, +}; + +static int __init sh_eth_init(void) +{ + return platform_driver_register(&sh_eth_driver); +} + +static void __exit sh_eth_cleanup(void) +{ + platform_driver_unregister(&sh_eth_driver); +} + +module_init(sh_eth_init); +module_exit(sh_eth_cleanup); + +MODULE_AUTHOR("Nobuhiro Iwamatsu, Yoshihiro Shimoda"); +MODULE_DESCRIPTION("Renesas SuperH Ethernet driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/net/sh_eth.h b/drivers/net/sh_eth.h new file mode 100644 index 000000000000..e01e1c347715 --- /dev/null +++ b/drivers/net/sh_eth.h @@ -0,0 +1,464 @@ +/* + * SuperH Ethernet device driver + * + * Copyright (C) 2006-2008 Nobuhiro Iwamatsu + * Copyright (C) 2008 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, + * 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". + */ + +#ifndef __SH_ETH_H__ +#define __SH_ETH_H__ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/spinlock.h> +#include <linux/workqueue.h> +#include <linux/netdevice.h> +#include <linux/phy.h> + +#define CARDNAME "sh-eth" +#define TX_TIMEOUT (5*HZ) + +#define TX_RING_SIZE 128 /* Tx ring size */ +#define RX_RING_SIZE 128 /* Rx ring size */ +#define RX_OFFSET 2 /* skb offset */ +#define ETHERSMALL 60 +#define PKT_BUF_SZ 1538 + +/* Chip Base Address */ +#define SH_TSU_ADDR 0xA7000804 + +/* Chip Registers */ +/* E-DMAC */ +#define EDMR 0x0000 +#define EDTRR 0x0004 +#define EDRRR 0x0008 +#define TDLAR 0x000C +#define RDLAR 0x0010 +#define EESR 0x0014 +#define EESIPR 0x0018 +#define TRSCER 0x001C +#define RMFCR 0x0020 +#define TFTR 0x0024 +#define FDR 0x0028 +#define RMCR 0x002C +#define EDOCR 0x0030 +#define FCFTR 0x0034 +#define RPADIR 0x0038 +#define TRIMD 0x003C +#define RBWAR 0x0040 +#define RDFAR 0x0044 +#define TBRAR 0x004C +#define TDFAR 0x0050 +/* Ether Register */ +#define ECMR 0x0160 +#define ECSR 0x0164 +#define ECSIPR 0x0168 +#define PIR 0x016C +#define MAHR 0x0170 +#define MALR 0x0174 +#define RFLR 0x0178 +#define PSR 0x017C +#define TROCR 0x0180 +#define CDCR 0x0184 +#define LCCR 0x0188 +#define CNDCR 0x018C +#define CEFCR 0x0194 +#define FRECR 0x0198 +#define TSFRCR 0x019C +#define TLFRCR 0x01A0 +#define RFCR 0x01A4 +#define MAFCR 0x01A8 +#define IPGR 0x01B4 +#if defined(CONFIG_CPU_SUBTYPE_SH7710) +#define APR 0x01B8 +#define MPR 0x01BC +#define TPAUSER 0x1C4 +#define BCFR 0x1CC +#endif /* CONFIG_CPU_SH7710 */ + +#define ARSTR 0x0800 + +/* TSU */ +#define TSU_CTRST 0x004 +#define TSU_FWEN0 0x010 +#define TSU_FWEN1 0x014 +#define TSU_FCM 0x018 +#define TSU_BSYSL0 0x020 +#define TSU_BSYSL1 0x024 +#define TSU_PRISL0 0x028 +#define TSU_PRISL1 0x02C +#define TSU_FWSL0 0x030 +#define TSU_FWSL1 0x034 +#define TSU_FWSLC 0x038 +#define TSU_QTAGM0 0x040 +#define TSU_QTAGM1 0x044 +#define TSU_ADQT0 0x048 +#define TSU_ADQT1 0x04C +#define TSU_FWSR 0x050 +#define TSU_FWINMK 0x054 +#define TSU_ADSBSY 0x060 +#define TSU_TEN 0x064 +#define TSU_POST1 0x070 +#define TSU_POST2 0x074 +#define TSU_POST3 0x078 +#define TSU_POST4 0x07C +#define TXNLCR0 0x080 +#define TXALCR0 0x084 +#define RXNLCR0 0x088 +#define RXALCR0 0x08C +#define FWNLCR0 0x090 +#define FWALCR0 0x094 +#define TXNLCR1 0x0A0 +#define TXALCR1 0x0A4 +#define RXNLCR1 0x0A8 +#define RXALCR1 0x0AC +#define FWNLCR1 0x0B0 +#define FWALCR1 0x0B4 + +#define TSU_ADRH0 0x0100 +#define TSU_ADRL0 0x0104 +#define TSU_ADRL31 0x01FC + +/* Register's bits */ + +/* EDMR */ +enum DMAC_M_BIT { + EDMR_DL1 = 0x20, EDMR_DL0 = 0x10, EDMR_SRST = 0x01, +}; + +/* EDTRR */ +enum DMAC_T_BIT { + EDTRR_TRNS = 0x01, +}; + +/* EDRRR*/ +enum EDRRR_R_BIT { + EDRRR_R = 0x01, +}; + +/* TPAUSER */ +enum TPAUSER_BIT { + TPAUSER_TPAUSE = 0x0000ffff, + TPAUSER_UNLIMITED = 0, +}; + +/* BCFR */ +enum BCFR_BIT { + BCFR_RPAUSE = 0x0000ffff, + BCFR_UNLIMITED = 0, +}; + +/* PIR */ +enum PIR_BIT { + PIR_MDI = 0x08, PIR_MDO = 0x04, PIR_MMD = 0x02, PIR_MDC = 0x01, +}; + +/* PSR */ +enum PHY_STATUS_BIT { PHY_ST_LINK = 0x01, }; + +/* EESR */ +enum EESR_BIT { + EESR_TWB = 0x40000000, EESR_TABT = 0x04000000, + EESR_RABT = 0x02000000, EESR_RFRMER = 0x01000000, + EESR_ADE = 0x00800000, EESR_ECI = 0x00400000, + EESR_FTC = 0x00200000, EESR_TDE = 0x00100000, + EESR_TFE = 0x00080000, EESR_FRC = 0x00040000, + EESR_RDE = 0x00020000, EESR_RFE = 0x00010000, + EESR_TINT4 = 0x00000800, EESR_TINT3 = 0x00000400, + EESR_TINT2 = 0x00000200, EESR_TINT1 = 0x00000100, + EESR_RINT8 = 0x00000080, EESR_RINT5 = 0x00000010, + EESR_RINT4 = 0x00000008, EESR_RINT3 = 0x00000004, + EESR_RINT2 = 0x00000002, EESR_RINT1 = 0x00000001, +}; + +#define EESR_ERR_CHECK (EESR_TWB | EESR_TABT | EESR_RABT | EESR_RDE \ + | EESR_RFRMER | EESR_ADE | EESR_TFE | EESR_TDE | EESR_ECI) + +/* EESIPR */ +enum DMAC_IM_BIT { + DMAC_M_TWB = 0x40000000, DMAC_M_TABT = 0x04000000, + DMAC_M_RABT = 0x02000000, + DMAC_M_RFRMER = 0x01000000, DMAC_M_ADF = 0x00800000, + DMAC_M_ECI = 0x00400000, DMAC_M_FTC = 0x00200000, + DMAC_M_TDE = 0x00100000, DMAC_M_TFE = 0x00080000, + DMAC_M_FRC = 0x00040000, DMAC_M_RDE = 0x00020000, + DMAC_M_RFE = 0x00010000, DMAC_M_TINT4 = 0x00000800, + DMAC_M_TINT3 = 0x00000400, DMAC_M_TINT2 = 0x00000200, + DMAC_M_TINT1 = 0x00000100, DMAC_M_RINT8 = 0x00000080, + DMAC_M_RINT5 = 0x00000010, DMAC_M_RINT4 = 0x00000008, + DMAC_M_RINT3 = 0x00000004, DMAC_M_RINT2 = 0x00000002, + DMAC_M_RINT1 = 0x00000001, +}; + +/* Receive descriptor bit */ +enum RD_STS_BIT { + RD_RACT = 0x80000000, RC_RDEL = 0x40000000, + RC_RFP1 = 0x20000000, RC_RFP0 = 0x10000000, + RD_RFE = 0x08000000, RD_RFS10 = 0x00000200, + RD_RFS9 = 0x00000100, RD_RFS8 = 0x00000080, + RD_RFS7 = 0x00000040, RD_RFS6 = 0x00000020, + RD_RFS5 = 0x00000010, RD_RFS4 = 0x00000008, + RD_RFS3 = 0x00000004, RD_RFS2 = 0x00000002, + RD_RFS1 = 0x00000001, +}; +#define RDF1ST RC_RFP1 +#define RDFEND RC_RFP0 +#define RD_RFP (RC_RFP1|RC_RFP0) + +/* FCFTR */ +enum FCFTR_BIT { + FCFTR_RFF2 = 0x00040000, FCFTR_RFF1 = 0x00020000, + FCFTR_RFF0 = 0x00010000, FCFTR_RFD2 = 0x00000004, + FCFTR_RFD1 = 0x00000002, FCFTR_RFD0 = 0x00000001, +}; +#define FIFO_F_D_RFF (FCFTR_RFF2|FCFTR_RFF1|FCFTR_RFF0) +#define FIFO_F_D_RFD (FCFTR_RFD2|FCFTR_RFD1|FCFTR_RFD0) + +/* Transfer descriptor bit */ +enum TD_STS_BIT { + TD_TACT = 0x80000000, TD_TDLE = 0x40000000, TD_TFP1 = 0x20000000, + TD_TFP0 = 0x10000000, +}; +#define TDF1ST TD_TFP1 +#define TDFEND TD_TFP0 +#define TD_TFP (TD_TFP1|TD_TFP0) + +/* RMCR */ +enum RECV_RST_BIT { RMCR_RST = 0x01, }; +/* ECMR */ +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_DM = 0x00000002, + ECMR_PRM = 0x00000001, +}; + +/* ECSR */ +enum ECSR_STATUS_BIT { + ECSR_BRCRX = 0x20, ECSR_PSRTO = 0x10, ECSR_LCHNG = 0x04, + ECSR_MPD = 0x02, ECSR_ICD = 0x01, +}; + +/* ECSIPR */ +enum ECSIPR_STATUS_MASK_BIT { + ECSIPR_BRCRXIP = 0x20, ECSIPR_PSRTOIP = 0x10, ECSIPR_LCHNGIP = 0x04, + ECSIPR_MPDIP = 0x02, ECSIPR_ICDIP = 0x01, +}; + +/* APR */ +enum APR_BIT { + APR_AP = 0x00000001, +}; + +/* MPR */ +enum MPR_BIT { + MPR_MP = 0x00000001, +}; + +/* TRSCER */ +enum DESC_I_BIT { + DESC_I_TINT4 = 0x0800, DESC_I_TINT3 = 0x0400, DESC_I_TINT2 = 0x0200, + DESC_I_TINT1 = 0x0100, DESC_I_RINT8 = 0x0080, DESC_I_RINT5 = 0x0010, + DESC_I_RINT4 = 0x0008, DESC_I_RINT3 = 0x0004, DESC_I_RINT2 = 0x0002, + DESC_I_RINT1 = 0x0001, +}; + +/* RPADIR */ +enum RPADIR_BIT { + RPADIR_PADS1 = 0x20000, RPADIR_PADS0 = 0x10000, + RPADIR_PADR = 0x0003f, +}; + +/* FDR */ +enum FIFO_SIZE_BIT { + FIFO_SIZE_T = 0x00000700, FIFO_SIZE_R = 0x00000007, +}; +enum phy_offsets { + PHY_CTRL = 0, PHY_STAT = 1, PHY_IDT1 = 2, PHY_IDT2 = 3, + PHY_ANA = 4, PHY_ANL = 5, PHY_ANE = 6, + PHY_16 = 16, +}; + +/* PHY_CTRL */ +enum PHY_CTRL_BIT { + PHY_C_RESET = 0x8000, PHY_C_LOOPBK = 0x4000, PHY_C_SPEEDSL = 0x2000, + PHY_C_ANEGEN = 0x1000, PHY_C_PWRDN = 0x0800, PHY_C_ISO = 0x0400, + PHY_C_RANEG = 0x0200, PHY_C_DUPLEX = 0x0100, PHY_C_COLT = 0x0080, +}; +#define DM9161_PHY_C_ANEGEN 0 /* auto nego special */ + +/* PHY_STAT */ +enum PHY_STAT_BIT { + PHY_S_100T4 = 0x8000, PHY_S_100X_F = 0x4000, PHY_S_100X_H = 0x2000, + PHY_S_10T_F = 0x1000, PHY_S_10T_H = 0x0800, PHY_S_ANEGC = 0x0020, + PHY_S_RFAULT = 0x0010, PHY_S_ANEGA = 0x0008, PHY_S_LINK = 0x0004, + PHY_S_JAB = 0x0002, PHY_S_EXTD = 0x0001, +}; + +/* PHY_ANA */ +enum PHY_ANA_BIT { + PHY_A_NP = 0x8000, PHY_A_ACK = 0x4000, PHY_A_RF = 0x2000, + PHY_A_FCS = 0x0400, PHY_A_T4 = 0x0200, PHY_A_FDX = 0x0100, + PHY_A_HDX = 0x0080, PHY_A_10FDX = 0x0040, PHY_A_10HDX = 0x0020, + PHY_A_SEL = 0x001f, +}; +/* PHY_ANL */ +enum PHY_ANL_BIT { + PHY_L_NP = 0x8000, PHY_L_ACK = 0x4000, PHY_L_RF = 0x2000, + PHY_L_FCS = 0x0400, PHY_L_T4 = 0x0200, PHY_L_FDX = 0x0100, + PHY_L_HDX = 0x0080, PHY_L_10FDX = 0x0040, PHY_L_10HDX = 0x0020, + PHY_L_SEL = 0x001f, +}; + +/* PHY_ANE */ +enum PHY_ANE_BIT { + PHY_E_PDF = 0x0010, PHY_E_LPNPA = 0x0008, PHY_E_NPA = 0x0004, + PHY_E_PRX = 0x0002, PHY_E_LPANEGA = 0x0001, +}; + +/* DM9161 */ +enum PHY_16_BIT { + PHY_16_BP4B45 = 0x8000, PHY_16_BPSCR = 0x4000, PHY_16_BPALIGN = 0x2000, + PHY_16_BP_ADPOK = 0x1000, PHY_16_Repeatmode = 0x0800, + PHY_16_TXselect = 0x0400, + PHY_16_Rsvd = 0x0200, PHY_16_RMIIEnable = 0x0100, + PHY_16_Force100LNK = 0x0080, + PHY_16_APDLED_CTL = 0x0040, PHY_16_COLLED_CTL = 0x0020, + PHY_16_RPDCTR_EN = 0x0010, + PHY_16_ResetStMch = 0x0008, PHY_16_PreamSupr = 0x0004, + PHY_16_Sleepmode = 0x0002, + PHY_16_RemoteLoopOut = 0x0001, +}; + +#define POST_RX 0x08 +#define POST_FW 0x04 +#define POST0_RX (POST_RX) +#define POST0_FW (POST_FW) +#define POST1_RX (POST_RX >> 2) +#define POST1_FW (POST_FW >> 2) +#define POST_ALL (POST0_RX | POST0_FW | POST1_RX | POST1_FW) + +/* ARSTR */ +enum ARSTR_BIT { ARSTR_ARSTR = 0x00000001, }; + +/* TSU_FWEN0 */ +enum TSU_FWEN0_BIT { + TSU_FWEN0_0 = 0x00000001, +}; + +/* TSU_ADSBSY */ +enum TSU_ADSBSY_BIT { + TSU_ADSBSY_0 = 0x00000001, +}; + +/* TSU_TEN */ +enum TSU_TEN_BIT { + TSU_TEN_0 = 0x80000000, +}; + +/* TSU_FWSL0 */ +enum TSU_FWSL0_BIT { + TSU_FWSL0_FW50 = 0x1000, TSU_FWSL0_FW40 = 0x0800, + TSU_FWSL0_FW30 = 0x0400, TSU_FWSL0_FW20 = 0x0200, + TSU_FWSL0_FW10 = 0x0100, TSU_FWSL0_RMSA0 = 0x0010, +}; + +/* TSU_FWSLC */ +enum TSU_FWSLC_BIT { + TSU_FWSLC_POSTENU = 0x2000, TSU_FWSLC_POSTENL = 0x1000, + TSU_FWSLC_CAMSEL03 = 0x0080, TSU_FWSLC_CAMSEL02 = 0x0040, + TSU_FWSLC_CAMSEL01 = 0x0020, TSU_FWSLC_CAMSEL00 = 0x0010, + TSU_FWSLC_CAMSEL13 = 0x0008, TSU_FWSLC_CAMSEL12 = 0x0004, + TSU_FWSLC_CAMSEL11 = 0x0002, TSU_FWSLC_CAMSEL10 = 0x0001, +}; + +/* + * The sh ether Tx buffer descriptors. + * This structure should be 20 bytes. + */ +struct sh_eth_txdesc { + u32 status; /* TD0 */ +#if defined(CONFIG_CPU_LITTLE_ENDIAN) + u16 pad0; /* TD1 */ + u16 buffer_length; /* TD1 */ +#else + u16 buffer_length; /* TD1 */ + u16 pad0; /* TD1 */ +#endif + u32 addr; /* TD2 */ + u32 pad1; /* padding data */ +}; + +/* + * The sh ether Rx buffer descriptors. + * This structure should be 20 bytes. + */ +struct sh_eth_rxdesc { + u32 status; /* RD0 */ +#if defined(CONFIG_CPU_LITTLE_ENDIAN) + u16 frame_length; /* RD1 */ + u16 buffer_length; /* RD1 */ +#else + u16 buffer_length; /* RD1 */ + u16 frame_length; /* RD1 */ +#endif + u32 addr; /* RD2 */ + u32 pad0; /* padding data */ +}; + +struct sh_eth_private { + dma_addr_t rx_desc_dma; + dma_addr_t tx_desc_dma; + struct sh_eth_rxdesc *rx_ring; + struct sh_eth_txdesc *tx_ring; + struct sk_buff **rx_skbuff; + struct sk_buff **tx_skbuff; + struct net_device_stats stats; + struct timer_list timer; + spinlock_t lock; + u32 cur_rx, dirty_rx; /* Producer/consumer ring indices */ + u32 cur_tx, dirty_tx; + u32 rx_buf_sz; /* Based on MTU+slack. */ + /* MII transceiver section. */ + u32 phy_id; /* PHY ID */ + struct mii_bus *mii_bus; /* MDIO bus control */ + struct phy_device *phydev; /* PHY device control */ + enum phy_state link; + int msg_enable; + int speed; + int duplex; + u32 rx_int_var, tx_int_var; /* interrupt control variables */ + char post_rx; /* POST receive */ + char post_fw; /* POST forward */ + struct net_device_stats tsu_stats; /* TSU forward status */ +}; + +static void swaps(char *src, int len) +{ +#ifdef __LITTLE_ENDIAN__ + u32 *p = (u32 *)src; + u32 *maxp; + maxp = p + ((len + sizeof(u32) - 1) / sizeof(u32)); + + for (; p < maxp; p++) + *p = swab32(*p); +#endif +} + +#endif diff --git a/drivers/net/sis190.c b/drivers/net/sis190.c index abc63b0663be..3fe01763760e 100644 --- a/drivers/net/sis190.c +++ b/drivers/net/sis190.c @@ -1656,7 +1656,7 @@ static inline void sis190_init_rxfilter(struct net_device *dev) SIS_PCI_COMMIT(); } -static int __devinit sis190_get_mac_addr(struct pci_dev *pdev, +static int __devinit sis190_get_mac_addr(struct pci_dev *pdev, struct net_device *dev) { int rc; diff --git a/drivers/net/sis900.c b/drivers/net/sis900.c index ec95e493ac1c..fa3a460f8e2f 100644 --- a/drivers/net/sis900.c +++ b/drivers/net/sis900.c @@ -1766,7 +1766,7 @@ static int sis900_rx(struct net_device *net_dev) skb = sis_priv->rx_skbuff[entry]; net_dev->stats.rx_dropped++; goto refill_rx_ring; - } + } /* This situation should never happen, but due to some unknow bugs, it is possible that diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index c8a5ef2d75f4..711e4a8948e0 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -51,7 +51,7 @@ #include "sky2.h" #define DRV_NAME "sky2" -#define DRV_VERSION "1.21" +#define DRV_VERSION "1.22" #define PFX DRV_NAME " " /* @@ -98,7 +98,7 @@ static int disable_msi = 0; module_param(disable_msi, int, 0); MODULE_PARM_DESC(disable_msi, "Disable Message Signaled Interrupt (MSI)"); -static const struct pci_device_id sky2_id_table[] = { +static DEFINE_PCI_DEVICE_TABLE(sky2_id_table) = { { PCI_DEVICE(PCI_VENDOR_ID_SYSKONNECT, 0x9000) }, /* SK-9Sxx */ { PCI_DEVICE(PCI_VENDOR_ID_SYSKONNECT, 0x9E00) }, /* SK-9Exx */ { PCI_DEVICE(PCI_VENDOR_ID_DLINK, 0x4b00) }, /* DGE-560T */ @@ -137,6 +137,7 @@ static const struct pci_device_id sky2_id_table[] = { { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x436C) }, /* 88E8072 */ { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x436D) }, /* 88E8055 */ { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4370) }, /* 88E8075 */ + { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4380) }, /* 88E8057 */ { 0 } }; @@ -147,17 +148,6 @@ static const unsigned txqaddr[] = { Q_XA1, Q_XA2 }; static const unsigned rxqaddr[] = { Q_R1, Q_R2 }; static const u32 portirq_msk[] = { Y2_IS_PORT_1, Y2_IS_PORT_2 }; -/* This driver supports yukon2 chipset only */ -static const char *yukon2_name[] = { - "XL", /* 0xb3 */ - "EC Ultra", /* 0xb4 */ - "Extreme", /* 0xb5 */ - "EC", /* 0xb6 */ - "FE", /* 0xb7 */ - "FE+", /* 0xb8 */ - "Supreme", /* 0xb9 */ -}; - static void sky2_set_multicast(struct net_device *dev); /* Access to PHY via serial interconnect */ @@ -285,6 +275,86 @@ static void sky2_power_aux(struct sky2_hw *hw) PC_VAUX_ON | PC_VCC_OFF)); } +static void sky2_power_state(struct sky2_hw *hw, pci_power_t state) +{ + u16 power_control = sky2_pci_read16(hw, hw->pm_cap + PCI_PM_CTRL); + int pex = pci_find_capability(hw->pdev, PCI_CAP_ID_EXP); + u32 reg; + + sky2_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_ON); + + switch (state) { + case PCI_D0: + break; + + case PCI_D1: + power_control |= 1; + break; + + case PCI_D2: + power_control |= 2; + break; + + case PCI_D3hot: + case PCI_D3cold: + power_control |= 3; + if (hw->flags & SKY2_HW_ADV_POWER_CTL) { + /* additional power saving measurements */ + reg = sky2_pci_read32(hw, PCI_DEV_REG4); + + /* set gating core clock for LTSSM in L1 state */ + reg |= P_PEX_LTSSM_STAT(P_PEX_LTSSM_L1_STAT) | + /* auto clock gated scheme controlled by CLKREQ */ + P_ASPM_A1_MODE_SELECT | + /* enable Gate Root Core Clock */ + P_CLK_GATE_ROOT_COR_ENA; + + if (pex && (hw->flags & SKY2_HW_CLK_POWER)) { + /* enable Clock Power Management (CLKREQ) */ + u16 ctrl = sky2_pci_read16(hw, pex + PCI_EXP_DEVCTL); + + ctrl |= PCI_EXP_DEVCTL_AUX_PME; + sky2_pci_write16(hw, pex + PCI_EXP_DEVCTL, ctrl); + } else + /* force CLKREQ Enable in Our4 (A1b only) */ + reg |= P_ASPM_FORCE_CLKREQ_ENA; + + /* set Mask Register for Release/Gate Clock */ + sky2_pci_write32(hw, PCI_DEV_REG5, + P_REL_PCIE_EXIT_L1_ST | P_GAT_PCIE_ENTER_L1_ST | + P_REL_PCIE_RX_EX_IDLE | P_GAT_PCIE_RX_EL_IDLE | + P_REL_GPHY_LINK_UP | P_GAT_GPHY_LINK_DOWN); + } else + sky2_write8(hw, B28_Y2_ASF_STAT_CMD, Y2_ASF_CLK_HALT); + + /* put CPU into reset state */ + sky2_write8(hw, B28_Y2_ASF_STAT_CMD, HCU_CCSR_ASF_RESET); + if (hw->chip_id == CHIP_ID_YUKON_SUPR && hw->chip_rev == CHIP_REV_YU_SU_A0) + /* put CPU into halt state */ + sky2_write8(hw, B28_Y2_ASF_STAT_CMD, HCU_CCSR_ASF_HALTED); + + if (pex && !(hw->flags & SKY2_HW_RAM_BUFFER)) { + reg = sky2_pci_read32(hw, PCI_DEV_REG1); + /* force to PCIe L1 */ + reg |= PCI_FORCE_PEX_L1; + sky2_pci_write32(hw, PCI_DEV_REG1, reg); + } + break; + + default: + dev_warn(&hw->pdev->dev, PFX "Invalid power state (%d) ", + state); + return; + } + + power_control |= PCI_PM_CTRL_PME_ENABLE; + /* Finally, set the new power state. */ + sky2_pci_write32(hw, hw->pm_cap + PCI_PM_CTRL, power_control); + + sky2_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_OFF); + sky2_pci_read32(hw, B0_CTST); +} + static void sky2_gmac_reset(struct sky2_hw *hw, unsigned port) { u16 reg; @@ -579,8 +649,7 @@ static void sky2_phy_init(struct sky2_hw *hw, unsigned port) ledover |= PHY_M_LED_MO_RX(MO_LED_OFF); } - if (hw->chip_id == CHIP_ID_YUKON_EC_U && - hw->chip_rev == CHIP_REV_YU_EC_U_A1) { + if (hw->chip_id == CHIP_ID_YUKON_EC_U || hw->chip_id == CHIP_ID_YUKON_UL_2) { /* apply fixes in PHY AFE */ gm_phy_write(hw, port, PHY_MARV_EXT_ADR, 255); @@ -588,9 +657,11 @@ static void sky2_phy_init(struct sky2_hw *hw, unsigned port) gm_phy_write(hw, port, 0x18, 0xaa99); gm_phy_write(hw, port, 0x17, 0x2011); - /* fix for IEEE A/B Symmetry failure in 1000BASE-T */ - gm_phy_write(hw, port, 0x18, 0xa204); - gm_phy_write(hw, port, 0x17, 0x2002); + if (hw->chip_id == CHIP_ID_YUKON_EC_U) { + /* fix for IEEE A/B Symmetry failure in 1000BASE-T */ + gm_phy_write(hw, port, 0x18, 0xa204); + gm_phy_write(hw, port, 0x17, 0x2002); + } /* set page register to 0 */ gm_phy_write(hw, port, PHY_MARV_EXT_ADR, 0); @@ -599,7 +670,8 @@ static void sky2_phy_init(struct sky2_hw *hw, unsigned port) /* apply workaround for integrated resistors calibration */ gm_phy_write(hw, port, PHY_MARV_PAGE_ADDR, 17); gm_phy_write(hw, port, PHY_MARV_PAGE_DATA, 0x3f60); - } else if (hw->chip_id != CHIP_ID_YUKON_EX) { + } else if (hw->chip_id != CHIP_ID_YUKON_EX && + hw->chip_id < CHIP_ID_YUKON_SUPR) { /* no effect on Yukon-XL */ gm_phy_write(hw, port, PHY_MARV_LED_CTRL, ledctrl); @@ -620,28 +692,71 @@ static void sky2_phy_init(struct sky2_hw *hw, unsigned port) gm_phy_write(hw, port, PHY_MARV_INT_MASK, PHY_M_DEF_MSK); } -static void sky2_phy_power(struct sky2_hw *hw, unsigned port, int onoff) +static const u32 phy_power[] = { PCI_Y2_PHY1_POWD, PCI_Y2_PHY2_POWD }; +static const u32 coma_mode[] = { PCI_Y2_PHY1_COMA, PCI_Y2_PHY2_COMA }; + +static void sky2_phy_power_up(struct sky2_hw *hw, unsigned port) { u32 reg1; - static const u32 phy_power[] = { PCI_Y2_PHY1_POWD, PCI_Y2_PHY2_POWD }; - static const u32 coma_mode[] = { PCI_Y2_PHY1_COMA, PCI_Y2_PHY2_COMA }; sky2_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_ON); reg1 = sky2_pci_read32(hw, PCI_DEV_REG1); - /* Turn on/off phy power saving */ - if (onoff) - reg1 &= ~phy_power[port]; - else - reg1 |= phy_power[port]; + reg1 &= ~phy_power[port]; - if (onoff && hw->chip_id == CHIP_ID_YUKON_XL && hw->chip_rev > 1) + if (hw->chip_id == CHIP_ID_YUKON_XL && hw->chip_rev > 1) reg1 |= coma_mode[port]; sky2_pci_write32(hw, PCI_DEV_REG1, reg1); sky2_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_OFF); sky2_pci_read32(hw, PCI_DEV_REG1); +} + +static void sky2_phy_power_down(struct sky2_hw *hw, unsigned port) +{ + u32 reg1; + u16 ctrl; + + /* release GPHY Control reset */ + sky2_write8(hw, SK_REG(port, GPHY_CTRL), GPC_RST_CLR); + + /* release GMAC reset */ + sky2_write8(hw, SK_REG(port, GMAC_CTRL), GMC_RST_CLR); + + if (hw->flags & SKY2_HW_NEWER_PHY) { + /* select page 2 to access MAC control register */ + gm_phy_write(hw, port, PHY_MARV_EXT_ADR, 2); - udelay(100); + ctrl = gm_phy_read(hw, port, PHY_MARV_PHY_CTRL); + /* allow GMII Power Down */ + ctrl &= ~PHY_M_MAC_GMIF_PUP; + gm_phy_write(hw, port, PHY_MARV_PHY_CTRL, ctrl); + + /* set page register back to 0 */ + gm_phy_write(hw, port, PHY_MARV_EXT_ADR, 0); + } + + /* setup General Purpose Control Register */ + gma_write16(hw, port, GM_GP_CTRL, + GM_GPCR_FL_PASS | GM_GPCR_SPEED_100 | GM_GPCR_AU_ALL_DIS); + + if (hw->chip_id != CHIP_ID_YUKON_EC) { + if (hw->chip_id == CHIP_ID_YUKON_EC_U) { + ctrl = gm_phy_read(hw, port, PHY_MARV_PHY_CTRL); + + /* enable Power Down */ + ctrl |= PHY_M_PC_POW_D_ENA; + gm_phy_write(hw, port, PHY_MARV_PHY_CTRL, ctrl); + } + + /* set IEEE compatible Power Down Mode (dev. #4.99) */ + gm_phy_write(hw, port, PHY_MARV_CTRL, PHY_CT_PDOWN); + } + + sky2_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_ON); + reg1 = sky2_pci_read32(hw, PCI_DEV_REG1); + reg1 |= phy_power[port]; /* set PHY to PowerDown/COMA Mode */ + sky2_pci_write32(hw, PCI_DEV_REG1, reg1); + sky2_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_OFF); } /* Force a renegotiation */ @@ -676,8 +791,11 @@ static void sky2_wol_init(struct sky2_port *sky2) sky2->advertising &= ~(ADVERTISED_1000baseT_Half|ADVERTISED_1000baseT_Full); sky2->flow_mode = FC_NONE; - sky2_phy_power(hw, port, 1); - sky2_phy_reinit(sky2); + + spin_lock_bh(&sky2->phy_lock); + sky2_phy_power_up(hw, port); + sky2_phy_init(hw, port); + spin_unlock_bh(&sky2->phy_lock); sky2->flow_mode = save_mode; sky2->advertising = ctrl; @@ -782,6 +900,7 @@ static void sky2_mac_init(struct sky2_hw *hw, unsigned port) sky2_write8(hw, SK_REG(port, GMAC_IRQ_MSK), GMAC_DEF_MSK); spin_lock_bh(&sky2->phy_lock); + sky2_phy_power_up(hw, port); sky2_phy_init(hw, port); spin_unlock_bh(&sky2->phy_lock); @@ -1386,8 +1505,6 @@ static int sky2_up(struct net_device *dev) if (!sky2->rx_ring) goto err_out; - sky2_phy_power(hw, port, 1); - sky2_mac_init(hw, port); /* Register is number of 4K blocks on internal RAM buffer. */ @@ -1768,7 +1885,7 @@ static int sky2_down(struct net_device *dev) sky2_write8(hw, SK_REG(port, RX_GMF_CTRL_T), GMF_RST_SET); sky2_write8(hw, SK_REG(port, TX_GMF_CTRL_T), GMF_RST_SET); - sky2_phy_power(hw, port, 0); + sky2_phy_power_down(hw, port); netif_carrier_off(dev); @@ -2694,6 +2811,7 @@ static u32 sky2_mhz(const struct sky2_hw *hw) case CHIP_ID_YUKON_EC_U: case CHIP_ID_YUKON_EX: case CHIP_ID_YUKON_SUPR: + case CHIP_ID_YUKON_UL_2: return 125; case CHIP_ID_YUKON_FE: @@ -2742,6 +2860,10 @@ static int __devinit sky2_init(struct sky2_hw *hw) hw->flags = SKY2_HW_GIGABIT | SKY2_HW_NEWER_PHY | SKY2_HW_ADV_POWER_CTL; + + /* check for Rev. A1 dev 4200 */ + if (sky2_read16(hw, Q_ADDR(Q_XA1, Q_WM)) == 0) + hw->flags |= SKY2_HW_CLK_POWER; break; case CHIP_ID_YUKON_EX: @@ -2782,6 +2904,11 @@ static int __devinit sky2_init(struct sky2_hw *hw) | SKY2_HW_ADV_POWER_CTL; break; + case CHIP_ID_YUKON_UL_2: + hw->flags = SKY2_HW_GIGABIT + | SKY2_HW_ADV_POWER_CTL; + break; + default: dev_err(&hw->pdev->dev, "unsupported chip type 0x%x\n", hw->chip_id); @@ -2792,6 +2919,11 @@ static int __devinit sky2_init(struct sky2_hw *hw) if (hw->pmd_type == 'L' || hw->pmd_type == 'S' || hw->pmd_type == 'P') hw->flags |= SKY2_HW_FIBRE_PHY; + hw->pm_cap = pci_find_capability(hw->pdev, PCI_CAP_ID_PM); + if (hw->pm_cap == 0) { + dev_err(&hw->pdev->dev, "cannot find PowerManagement capability\n"); + return -EIO; + } hw->ports = 1; t8 = sky2_read8(hw, B2_Y2_HW_RES); @@ -3379,7 +3511,7 @@ static void sky2_led(struct sky2_port *sky2, enum led_mode mode) gm_phy_write(hw, port, PHY_MARV_EXT_ADR, pg); } else - gm_phy_write(hw, port, PHY_MARV_LED_OVER, + gm_phy_write(hw, port, PHY_MARV_LED_OVER, PHY_M_LED_MO_DUP(mode) | PHY_M_LED_MO_10(mode) | PHY_M_LED_MO_100(mode) | @@ -4132,12 +4264,34 @@ static int __devinit pci_wake_enabled(struct pci_dev *dev) return value & PCI_PM_CTRL_PME_ENABLE; } +/* This driver supports yukon2 chipset only */ +static const char *sky2_name(u8 chipid, char *buf, int sz) +{ + const char *name[] = { + "XL", /* 0xb3 */ + "EC Ultra", /* 0xb4 */ + "Extreme", /* 0xb5 */ + "EC", /* 0xb6 */ + "FE", /* 0xb7 */ + "FE+", /* 0xb8 */ + "Supreme", /* 0xb9 */ + "UL 2", /* 0xba */ + }; + + if (chipid >= CHIP_ID_YUKON_XL && chipid < CHIP_ID_YUKON_UL_2) + strncpy(buf, name[chipid - CHIP_ID_YUKON_XL], sz); + else + snprintf(buf, sz, "(chip %#x)", chipid); + return buf; +} + static int __devinit sky2_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { struct net_device *dev; struct sky2_hw *hw; int err, using_dac = 0, wol_default; + char buf1[16]; err = pci_enable_device(pdev); if (err) { @@ -4208,10 +4362,10 @@ static int __devinit sky2_probe(struct pci_dev *pdev, if (err) goto err_out_iounmap; - dev_info(&pdev->dev, "v%s addr 0x%llx irq %d Yukon-%s (0x%x) rev %d\n", - DRV_VERSION, (unsigned long long)pci_resource_start(pdev, 0), - pdev->irq, yukon2_name[hw->chip_id - CHIP_ID_YUKON_XL], - hw->chip_id, hw->chip_rev); + dev_info(&pdev->dev, "v%s addr 0x%llx irq %d Yukon-2 %s rev %d\n", + DRV_VERSION, (unsigned long long)pci_resource_start(pdev, 0), + pdev->irq, sky2_name(hw->chip_id, buf1, sizeof(buf1)), + hw->chip_rev); sky2_reset(hw); @@ -4363,7 +4517,7 @@ static int sky2_suspend(struct pci_dev *pdev, pm_message_t state) pci_save_state(pdev); pci_enable_wake(pdev, pci_choose_state(pdev, state), wol); - pci_set_power_state(pdev, pci_choose_state(pdev, state)); + sky2_power_state(hw, pci_choose_state(pdev, state)); return 0; } @@ -4376,9 +4530,7 @@ static int sky2_resume(struct pci_dev *pdev) if (!hw) return 0; - err = pci_set_power_state(pdev, PCI_D0); - if (err) - goto out; + sky2_power_state(hw, PCI_D0); err = pci_restore_state(pdev); if (err) @@ -4448,8 +4600,7 @@ static void sky2_shutdown(struct pci_dev *pdev) pci_enable_wake(pdev, PCI_D3cold, wol); pci_disable_device(pdev); - pci_set_power_state(pdev, PCI_D3hot); - + sky2_power_state(hw, PCI_D3hot); } static struct pci_driver sky2_driver = { diff --git a/drivers/net/sky2.h b/drivers/net/sky2.h index c0a5eea20007..4d9c4a19bb85 100644 --- a/drivers/net/sky2.h +++ b/drivers/net/sky2.h @@ -28,6 +28,11 @@ enum pci_dev_reg_1 { PCI_Y2_PHY2_POWD = 1<<27, /* Set PHY 2 to Power Down (YUKON-2) */ PCI_Y2_PHY1_POWD = 1<<26, /* Set PHY 1 to Power Down (YUKON-2) */ PCI_Y2_PME_LEGACY= 1<<15, /* PCI Express legacy power management mode */ + + PCI_PHY_LNK_TIM_MSK= 3L<<8,/* Bit 9.. 8: GPHY Link Trigger Timer */ + PCI_ENA_L1_EVENT = 1<<7, /* Enable PEX L1 Event */ + PCI_ENA_GPHY_LNK = 1<<6, /* Enable PEX L1 on GPHY Link down */ + PCI_FORCE_PEX_L1 = 1<<5, /* Force to PEX L1 */ }; enum pci_dev_reg_2 { @@ -45,7 +50,11 @@ enum pci_dev_reg_2 { /* PCI_OUR_REG_4 32 bit Our Register 4 (Yukon-ECU only) */ enum pci_dev_reg_4 { - /* (Link Training & Status State Machine) */ + /* (Link Training & Status State Machine) */ + P_PEX_LTSSM_STAT_MSK = 0x7fL<<25, /* Bit 31..25: PEX LTSSM Mask */ +#define P_PEX_LTSSM_STAT(x) ((x << 25) & P_PEX_LTSSM_STAT_MSK) + P_PEX_LTSSM_L1_STAT = 0x34, + P_PEX_LTSSM_DET_STAT = 0x01, P_TIMER_VALUE_MSK = 0xffL<<16, /* Bit 23..16: Timer Value Mask */ /* (Active State Power Management) */ P_FORCE_ASPM_REQUEST = 1<<15, /* Force ASPM Request (A1 only) */ @@ -432,6 +441,7 @@ enum { CHIP_ID_YUKON_FE = 0xb7, /* YUKON-2 FE */ CHIP_ID_YUKON_FE_P = 0xb8, /* YUKON-2 FE+ */ CHIP_ID_YUKON_SUPR = 0xb9, /* YUKON-2 Supreme */ + CHIP_ID_YUKON_UL_2 = 0xba, /* YUKON-2 Ultra 2 */ }; enum yukon_ec_rev { CHIP_REV_YU_EC_A1 = 0, /* Chip Rev. for Yukon-EC A1/A0 */ @@ -454,6 +464,9 @@ enum yukon_ex_rev { CHIP_REV_YU_EX_A0 = 1, CHIP_REV_YU_EX_B0 = 2, }; +enum yukon_supr_rev { + CHIP_REV_YU_SU_A0 = 0, +}; /* B2_Y2_CLK_GATE 8 bit Clock Gating (Yukon-2 only) */ @@ -1143,6 +1156,12 @@ enum { PHY_M_PC_ENA_AUTO = 3, /* 11 = Enable Automatic Crossover */ }; +/* for Yukon-EC Ultra Gigabit Ethernet PHY (88E1149 only) */ +enum { + PHY_M_PC_COP_TX_DIS = 1<<3, /* Copper Transmitter Disable */ + PHY_M_PC_POW_D_ENA = 1<<2, /* Power Down Enable */ +}; + /* for 10/100 Fast Ethernet PHY (88E3082 only) */ enum { PHY_M_PC_ENA_DTE_DT = 1<<15, /* Enable Data Terminal Equ. (DTE) Detect */ @@ -1411,6 +1430,7 @@ enum { /***** PHY_MARV_PHY_CTRL (page 2) 16 bit r/w MAC Specific Ctrl *****/ enum { PHY_M_MAC_MD_MSK = 7<<7, /* Bit 9.. 7: Mode Select Mask */ + PHY_M_MAC_GMIF_PUP = 1<<3, /* GMII Power Up (88E1149 only) */ PHY_M_MAC_MD_AUTO = 3,/* Auto Copper/1000Base-X */ PHY_M_MAC_MD_COPPER = 5,/* Copper only */ PHY_M_MAC_MD_1000BX = 7,/* 1000Base-X only */ @@ -2052,7 +2072,9 @@ struct sky2_hw { #define SKY2_HW_NEW_LE 0x00000020 /* new LSOv2 format */ #define SKY2_HW_AUTO_TX_SUM 0x00000040 /* new IP decode for Tx */ #define SKY2_HW_ADV_POWER_CTL 0x00000080 /* additional PHY power regs */ +#define SKY2_HW_CLK_POWER 0x00000100 /* clock power management */ + int pm_cap; u8 chip_id; u8 chip_rev; u8 pmd_type; diff --git a/drivers/net/slip.c b/drivers/net/slip.c index 84af68fdb6c2..1d58991d395b 100644 --- a/drivers/net/slip.c +++ b/drivers/net/slip.c @@ -1301,7 +1301,7 @@ static int sl_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) #endif /* VSV changes end */ -static struct tty_ldisc sl_ldisc = { +static struct tty_ldisc_ops sl_ldisc = { .owner = THIS_MODULE, .magic = TTY_LDISC_MAGIC, .name = "slip", diff --git a/drivers/net/smc911x.c b/drivers/net/smc911x.c index e2ee91a6ae7e..c5871624f972 100644 --- a/drivers/net/smc911x.c +++ b/drivers/net/smc911x.c @@ -106,55 +106,6 @@ MODULE_ALIAS("platform:smc911x"); */ #define POWER_DOWN 1 - -/* store this information for the driver.. */ -struct smc911x_local { - /* - * If I have to wait until the DMA is finished and ready to reload a - * packet, I will store the skbuff here. Then, the DMA will send it - * out and free it. - */ - struct sk_buff *pending_tx_skb; - - /* version/revision of the SMC911x chip */ - u16 version; - u16 revision; - - /* FIFO sizes */ - int tx_fifo_kb; - int tx_fifo_size; - int rx_fifo_size; - int afc_cfg; - - /* Contains the current active receive/phy mode */ - int ctl_rfduplx; - int ctl_rspeed; - - u32 msg_enable; - u32 phy_type; - struct mii_if_info mii; - - /* work queue */ - struct work_struct phy_configure; - - int tx_throttle; - spinlock_t lock; - - struct net_device *netdev; - -#ifdef SMC_USE_DMA - /* DMA needs the physical address of the chip */ - u_long physaddr; - int rxdma; - int txdma; - int rxdma_active; - int txdma_active; - struct sk_buff *current_rx_skb; - struct sk_buff *current_tx_skb; - struct device *dev; -#endif -}; - #if SMC_DEBUG > 0 #define DBG(n, args...) \ do { \ @@ -202,24 +153,24 @@ static void PRINT_PKT(u_char *buf, int length) /* this enables an interrupt in the interrupt mask register */ -#define SMC_ENABLE_INT(x) do { \ +#define SMC_ENABLE_INT(lp, x) do { \ unsigned int __mask; \ unsigned long __flags; \ spin_lock_irqsave(&lp->lock, __flags); \ - __mask = SMC_GET_INT_EN(); \ + __mask = SMC_GET_INT_EN((lp)); \ __mask |= (x); \ - SMC_SET_INT_EN(__mask); \ + SMC_SET_INT_EN((lp), __mask); \ spin_unlock_irqrestore(&lp->lock, __flags); \ } while (0) /* this disables an interrupt from the interrupt mask register */ -#define SMC_DISABLE_INT(x) do { \ +#define SMC_DISABLE_INT(lp, x) do { \ unsigned int __mask; \ unsigned long __flags; \ spin_lock_irqsave(&lp->lock, __flags); \ - __mask = SMC_GET_INT_EN(); \ + __mask = SMC_GET_INT_EN((lp)); \ __mask &= ~(x); \ - SMC_SET_INT_EN(__mask); \ + SMC_SET_INT_EN((lp), __mask); \ spin_unlock_irqrestore(&lp->lock, __flags); \ } while (0) @@ -228,7 +179,6 @@ static void PRINT_PKT(u_char *buf, int length) */ static void smc911x_reset(struct net_device *dev) { - unsigned long ioaddr = dev->base_addr; struct smc911x_local *lp = netdev_priv(dev); unsigned int reg, timeout=0, resets=1; unsigned long flags; @@ -236,13 +186,13 @@ static void smc911x_reset(struct net_device *dev) DBG(SMC_DEBUG_FUNC, "%s: --> %s\n", dev->name, __FUNCTION__); /* Take out of PM setting first */ - if ((SMC_GET_PMT_CTRL() & PMT_CTRL_READY_) == 0) { + if ((SMC_GET_PMT_CTRL(lp) & PMT_CTRL_READY_) == 0) { /* Write to the bytetest will take out of powerdown */ - SMC_SET_BYTE_TEST(0); + SMC_SET_BYTE_TEST(lp, 0); timeout=10; do { udelay(10); - reg = SMC_GET_PMT_CTRL() & PMT_CTRL_READY_; + reg = SMC_GET_PMT_CTRL(lp) & PMT_CTRL_READY_; } while (--timeout && !reg); if (timeout == 0) { PRINTK("%s: smc911x_reset timeout waiting for PM restore\n", dev->name); @@ -252,15 +202,15 @@ static void smc911x_reset(struct net_device *dev) /* Disable all interrupts */ spin_lock_irqsave(&lp->lock, flags); - SMC_SET_INT_EN(0); + SMC_SET_INT_EN(lp, 0); spin_unlock_irqrestore(&lp->lock, flags); while (resets--) { - SMC_SET_HW_CFG(HW_CFG_SRST_); + SMC_SET_HW_CFG(lp, HW_CFG_SRST_); timeout=10; do { udelay(10); - reg = SMC_GET_HW_CFG(); + reg = SMC_GET_HW_CFG(lp); /* If chip indicates reset timeout then try again */ if (reg & HW_CFG_SRST_TO_) { PRINTK("%s: chip reset timeout, retrying...\n", dev->name); @@ -276,7 +226,7 @@ static void smc911x_reset(struct net_device *dev) /* make sure EEPROM has finished loading before setting GPIO_CFG */ timeout=1000; - while ( timeout-- && (SMC_GET_E2P_CMD() & E2P_CMD_EPC_BUSY_)) { + while ( timeout-- && (SMC_GET_E2P_CMD(lp) & E2P_CMD_EPC_BUSY_)) { udelay(10); } if (timeout == 0){ @@ -285,24 +235,24 @@ static void smc911x_reset(struct net_device *dev) } /* Initialize interrupts */ - SMC_SET_INT_EN(0); - SMC_ACK_INT(-1); + SMC_SET_INT_EN(lp, 0); + SMC_ACK_INT(lp, -1); /* Reset the FIFO level and flow control settings */ - SMC_SET_HW_CFG((lp->tx_fifo_kb & 0xF) << 16); + SMC_SET_HW_CFG(lp, (lp->tx_fifo_kb & 0xF) << 16); //TODO: Figure out what appropriate pause time is - SMC_SET_FLOW(FLOW_FCPT_ | FLOW_FCEN_); - SMC_SET_AFC_CFG(lp->afc_cfg); + SMC_SET_FLOW(lp, FLOW_FCPT_ | FLOW_FCEN_); + SMC_SET_AFC_CFG(lp, lp->afc_cfg); /* Set to LED outputs */ - SMC_SET_GPIO_CFG(0x70070000); + SMC_SET_GPIO_CFG(lp, 0x70070000); /* * Deassert IRQ for 1*10us for edge type interrupts * and drive IRQ pin push-pull */ - SMC_SET_IRQ_CFG( (1 << 24) | INT_CFG_IRQ_EN_ | INT_CFG_IRQ_TYPE_ ); + SMC_SET_IRQ_CFG(lp, (1 << 24) | INT_CFG_IRQ_EN_ | INT_CFG_IRQ_TYPE_); /* clear anything saved */ if (lp->pending_tx_skb != NULL) { @@ -318,46 +268,45 @@ static void smc911x_reset(struct net_device *dev) */ static void smc911x_enable(struct net_device *dev) { - unsigned long ioaddr = dev->base_addr; struct smc911x_local *lp = netdev_priv(dev); unsigned mask, cfg, cr; unsigned long flags; DBG(SMC_DEBUG_FUNC, "%s: --> %s\n", dev->name, __FUNCTION__); - SMC_SET_MAC_ADDR(dev->dev_addr); + SMC_SET_MAC_ADDR(lp, dev->dev_addr); /* Enable TX */ - cfg = SMC_GET_HW_CFG(); + cfg = SMC_GET_HW_CFG(lp); cfg &= HW_CFG_TX_FIF_SZ_ | 0xFFF; cfg |= HW_CFG_SF_; - SMC_SET_HW_CFG(cfg); - SMC_SET_FIFO_TDA(0xFF); + SMC_SET_HW_CFG(lp, cfg); + SMC_SET_FIFO_TDA(lp, 0xFF); /* Update TX stats on every 64 packets received or every 1 sec */ - SMC_SET_FIFO_TSL(64); - SMC_SET_GPT_CFG(GPT_CFG_TIMER_EN_ | 10000); + SMC_SET_FIFO_TSL(lp, 64); + SMC_SET_GPT_CFG(lp, GPT_CFG_TIMER_EN_ | 10000); spin_lock_irqsave(&lp->lock, flags); - SMC_GET_MAC_CR(cr); + SMC_GET_MAC_CR(lp, cr); cr |= MAC_CR_TXEN_ | MAC_CR_HBDIS_; - SMC_SET_MAC_CR(cr); - SMC_SET_TX_CFG(TX_CFG_TX_ON_); + SMC_SET_MAC_CR(lp, cr); + SMC_SET_TX_CFG(lp, TX_CFG_TX_ON_); spin_unlock_irqrestore(&lp->lock, flags); /* Add 2 byte padding to start of packets */ - SMC_SET_RX_CFG((2<<8) & RX_CFG_RXDOFF_); + SMC_SET_RX_CFG(lp, (2<<8) & RX_CFG_RXDOFF_); /* Turn on receiver and enable RX */ if (cr & MAC_CR_RXEN_) DBG(SMC_DEBUG_RX, "%s: Receiver already enabled\n", dev->name); spin_lock_irqsave(&lp->lock, flags); - SMC_SET_MAC_CR( cr | MAC_CR_RXEN_ ); + SMC_SET_MAC_CR(lp, cr | MAC_CR_RXEN_); spin_unlock_irqrestore(&lp->lock, flags); /* Interrupt on every received packet */ - SMC_SET_FIFO_RSA(0x01); - SMC_SET_FIFO_RSL(0x00); + SMC_SET_FIFO_RSA(lp, 0x01); + SMC_SET_FIFO_RSL(lp, 0x00); /* now, enable interrupts */ mask = INT_EN_TDFA_EN_ | INT_EN_TSFL_EN_ | INT_EN_RSFL_EN_ | @@ -368,7 +317,7 @@ static void smc911x_enable(struct net_device *dev) else { mask|=INT_EN_RDFO_EN_; } - SMC_ENABLE_INT(mask); + SMC_ENABLE_INT(lp, mask); } /* @@ -376,7 +325,6 @@ static void smc911x_enable(struct net_device *dev) */ static void smc911x_shutdown(struct net_device *dev) { - unsigned long ioaddr = dev->base_addr; struct smc911x_local *lp = netdev_priv(dev); unsigned cr; unsigned long flags; @@ -384,35 +332,35 @@ static void smc911x_shutdown(struct net_device *dev) DBG(SMC_DEBUG_FUNC, "%s: --> %s\n", CARDNAME, __FUNCTION__); /* Disable IRQ's */ - SMC_SET_INT_EN(0); + SMC_SET_INT_EN(lp, 0); /* Turn of Rx and TX */ spin_lock_irqsave(&lp->lock, flags); - SMC_GET_MAC_CR(cr); + SMC_GET_MAC_CR(lp, cr); cr &= ~(MAC_CR_TXEN_ | MAC_CR_RXEN_ | MAC_CR_HBDIS_); - SMC_SET_MAC_CR(cr); - SMC_SET_TX_CFG(TX_CFG_STOP_TX_); + SMC_SET_MAC_CR(lp, cr); + SMC_SET_TX_CFG(lp, TX_CFG_STOP_TX_); spin_unlock_irqrestore(&lp->lock, flags); } static inline void smc911x_drop_pkt(struct net_device *dev) { - unsigned long ioaddr = dev->base_addr; + struct smc911x_local *lp = netdev_priv(dev); unsigned int fifo_count, timeout, reg; DBG(SMC_DEBUG_FUNC | SMC_DEBUG_RX, "%s: --> %s\n", CARDNAME, __FUNCTION__); - fifo_count = SMC_GET_RX_FIFO_INF() & 0xFFFF; + fifo_count = SMC_GET_RX_FIFO_INF(lp) & 0xFFFF; if (fifo_count <= 4) { /* Manually dump the packet data */ while (fifo_count--) - SMC_GET_RX_FIFO(); + SMC_GET_RX_FIFO(lp); } else { /* Fast forward through the bad packet */ - SMC_SET_RX_DP_CTRL(RX_DP_CTRL_FFWD_BUSY_); + SMC_SET_RX_DP_CTRL(lp, RX_DP_CTRL_FFWD_BUSY_); timeout=50; do { udelay(10); - reg = SMC_GET_RX_DP_CTRL() & RX_DP_CTRL_FFWD_BUSY_; + reg = SMC_GET_RX_DP_CTRL(lp) & RX_DP_CTRL_FFWD_BUSY_; } while (--timeout && reg); if (timeout == 0) { PRINTK("%s: timeout waiting for RX fast forward\n", dev->name); @@ -428,14 +376,14 @@ static inline void smc911x_drop_pkt(struct net_device *dev) */ static inline void smc911x_rcv(struct net_device *dev) { - unsigned long ioaddr = dev->base_addr; + struct smc911x_local *lp = netdev_priv(dev); unsigned int pkt_len, status; struct sk_buff *skb; unsigned char *data; DBG(SMC_DEBUG_FUNC | SMC_DEBUG_RX, "%s: --> %s\n", dev->name, __FUNCTION__); - status = SMC_GET_RX_STS_FIFO(); + status = SMC_GET_RX_STS_FIFO(lp); DBG(SMC_DEBUG_RX, "%s: Rx pkt len %d status 0x%08x \n", dev->name, (status & 0x3fff0000) >> 16, status & 0xc000ffff); pkt_len = (status & RX_STS_PKT_LEN_) >> 16; @@ -472,24 +420,23 @@ static inline void smc911x_rcv(struct net_device *dev) skb_put(skb,pkt_len-4); #ifdef SMC_USE_DMA { - struct smc911x_local *lp = netdev_priv(dev); unsigned int fifo; /* Lower the FIFO threshold if possible */ - fifo = SMC_GET_FIFO_INT(); + fifo = SMC_GET_FIFO_INT(lp); if (fifo & 0xFF) fifo--; DBG(SMC_DEBUG_RX, "%s: Setting RX stat FIFO threshold to %d\n", dev->name, fifo & 0xff); - SMC_SET_FIFO_INT(fifo); + SMC_SET_FIFO_INT(lp, fifo); /* Setup RX DMA */ - SMC_SET_RX_CFG(RX_CFG_RX_END_ALGN16_ | ((2<<8) & RX_CFG_RXDOFF_)); + SMC_SET_RX_CFG(lp, RX_CFG_RX_END_ALGN16_ | ((2<<8) & RX_CFG_RXDOFF_)); lp->rxdma_active = 1; lp->current_rx_skb = skb; - SMC_PULL_DATA(data, (pkt_len+2+15) & ~15); + SMC_PULL_DATA(lp, data, (pkt_len+2+15) & ~15); /* Packet processing deferred to DMA RX interrupt */ } #else - SMC_SET_RX_CFG(RX_CFG_RX_END_ALGN4_ | ((2<<8) & RX_CFG_RXDOFF_)); - SMC_PULL_DATA(data, pkt_len+2+3); + SMC_SET_RX_CFG(lp, RX_CFG_RX_END_ALGN4_ | ((2<<8) & RX_CFG_RXDOFF_)); + SMC_PULL_DATA(lp, data, pkt_len+2+3); DBG(SMC_DEBUG_PKTS, "%s: Received packet\n", dev->name); PRINT_PKT(data, ((pkt_len - 4) <= 64) ? pkt_len - 4 : 64); @@ -508,7 +455,6 @@ static inline void smc911x_rcv(struct net_device *dev) static void smc911x_hardware_send_pkt(struct net_device *dev) { struct smc911x_local *lp = netdev_priv(dev); - unsigned long ioaddr = dev->base_addr; struct sk_buff *skb; unsigned int cmdA, cmdB, len; unsigned char *buf; @@ -541,8 +487,8 @@ static void smc911x_hardware_send_pkt(struct net_device *dev) DBG(SMC_DEBUG_TX, "%s: TX PKT LENGTH 0x%04x (%d) BUF 0x%p CMDA 0x%08x CMDB 0x%08x\n", dev->name, len, len, buf, cmdA, cmdB); - SMC_SET_TX_FIFO(cmdA); - SMC_SET_TX_FIFO(cmdB); + SMC_SET_TX_FIFO(lp, cmdA); + SMC_SET_TX_FIFO(lp, cmdB); DBG(SMC_DEBUG_PKTS, "%s: Transmitted packet\n", dev->name); PRINT_PKT(buf, len <= 64 ? len : 64); @@ -550,10 +496,10 @@ static void smc911x_hardware_send_pkt(struct net_device *dev) /* Send pkt via PIO or DMA */ #ifdef SMC_USE_DMA lp->current_tx_skb = skb; - SMC_PUSH_DATA(buf, len); + SMC_PUSH_DATA(lp, buf, len); /* DMA complete IRQ will free buffer and set jiffies */ #else - SMC_PUSH_DATA(buf, len); + SMC_PUSH_DATA(lp, buf, len); dev->trans_start = jiffies; dev_kfree_skb(skb); #endif @@ -562,7 +508,7 @@ static void smc911x_hardware_send_pkt(struct net_device *dev) netif_wake_queue(dev); } spin_unlock_irqrestore(&lp->lock, flags); - SMC_ENABLE_INT(INT_EN_TDFA_EN_ | INT_EN_TSFL_EN_); + SMC_ENABLE_INT(lp, INT_EN_TDFA_EN_ | INT_EN_TSFL_EN_); } /* @@ -574,7 +520,6 @@ static void smc911x_hardware_send_pkt(struct net_device *dev) static int smc911x_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) { struct smc911x_local *lp = netdev_priv(dev); - unsigned long ioaddr = dev->base_addr; unsigned int free; unsigned long flags; @@ -583,7 +528,7 @@ static int smc911x_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) BUG_ON(lp->pending_tx_skb != NULL); - free = SMC_GET_TX_FIFO_INF() & TX_FIFO_INF_TDFREE_; + free = SMC_GET_TX_FIFO_INF(lp) & TX_FIFO_INF_TDFREE_; DBG(SMC_DEBUG_TX, "%s: TX free space %d\n", dev->name, free); /* Turn off the flow when running out of space in FIFO */ @@ -592,7 +537,7 @@ static int smc911x_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) dev->name, free); spin_lock_irqsave(&lp->lock, flags); /* Reenable when at least 1 packet of size MTU present */ - SMC_SET_FIFO_TDA((SMC911X_TX_FIFO_LOW_THRESHOLD)/64); + SMC_SET_FIFO_TDA(lp, (SMC911X_TX_FIFO_LOW_THRESHOLD)/64); lp->tx_throttle = 1; netif_stop_queue(dev); spin_unlock_irqrestore(&lp->lock, flags); @@ -647,7 +592,6 @@ static int smc911x_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) */ static void smc911x_tx(struct net_device *dev) { - unsigned long ioaddr = dev->base_addr; struct smc911x_local *lp = netdev_priv(dev); unsigned int tx_status; @@ -655,11 +599,11 @@ static void smc911x_tx(struct net_device *dev) dev->name, __FUNCTION__); /* Collect the TX status */ - while (((SMC_GET_TX_FIFO_INF() & TX_FIFO_INF_TSUSED_) >> 16) != 0) { + while (((SMC_GET_TX_FIFO_INF(lp) & TX_FIFO_INF_TSUSED_) >> 16) != 0) { DBG(SMC_DEBUG_TX, "%s: Tx stat FIFO used 0x%04x\n", dev->name, - (SMC_GET_TX_FIFO_INF() & TX_FIFO_INF_TSUSED_) >> 16); - tx_status = SMC_GET_TX_STS_FIFO(); + (SMC_GET_TX_FIFO_INF(lp) & TX_FIFO_INF_TSUSED_) >> 16); + tx_status = SMC_GET_TX_STS_FIFO(lp); dev->stats.tx_packets++; dev->stats.tx_bytes+=tx_status>>16; DBG(SMC_DEBUG_TX, "%s: Tx FIFO tag 0x%04x status 0x%04x\n", @@ -697,10 +641,10 @@ static void smc911x_tx(struct net_device *dev) static int smc911x_phy_read(struct net_device *dev, int phyaddr, int phyreg) { - unsigned long ioaddr = dev->base_addr; + struct smc911x_local *lp = netdev_priv(dev); unsigned int phydata; - SMC_GET_MII(phyreg, phyaddr, phydata); + SMC_GET_MII(lp, phyreg, phyaddr, phydata); DBG(SMC_DEBUG_MISC, "%s: phyaddr=0x%x, phyreg=0x%02x, phydata=0x%04x\n", __FUNCTION__, phyaddr, phyreg, phydata); @@ -714,12 +658,12 @@ static int smc911x_phy_read(struct net_device *dev, int phyaddr, int phyreg) static void smc911x_phy_write(struct net_device *dev, int phyaddr, int phyreg, int phydata) { - unsigned long ioaddr = dev->base_addr; + struct smc911x_local *lp = netdev_priv(dev); DBG(SMC_DEBUG_MISC, "%s: phyaddr=0x%x, phyreg=0x%x, phydata=0x%x\n", __FUNCTION__, phyaddr, phyreg, phydata); - SMC_SET_MII(phyreg, phyaddr, phydata); + SMC_SET_MII(lp, phyreg, phyaddr, phydata); } /* @@ -728,7 +672,6 @@ static void smc911x_phy_write(struct net_device *dev, int phyaddr, int phyreg, */ static void smc911x_phy_detect(struct net_device *dev) { - unsigned long ioaddr = dev->base_addr; struct smc911x_local *lp = netdev_priv(dev); int phyaddr; unsigned int cfg, id1, id2; @@ -744,30 +687,30 @@ static void smc911x_phy_detect(struct net_device *dev) switch(lp->version) { case 0x115: case 0x117: - cfg = SMC_GET_HW_CFG(); + cfg = SMC_GET_HW_CFG(lp); if (cfg & HW_CFG_EXT_PHY_DET_) { cfg &= ~HW_CFG_PHY_CLK_SEL_; cfg |= HW_CFG_PHY_CLK_SEL_CLK_DIS_; - SMC_SET_HW_CFG(cfg); + SMC_SET_HW_CFG(lp, cfg); udelay(10); /* Wait for clocks to stop */ cfg |= HW_CFG_EXT_PHY_EN_; - SMC_SET_HW_CFG(cfg); + SMC_SET_HW_CFG(lp, cfg); udelay(10); /* Wait for clocks to stop */ cfg &= ~HW_CFG_PHY_CLK_SEL_; cfg |= HW_CFG_PHY_CLK_SEL_EXT_PHY_; - SMC_SET_HW_CFG(cfg); + SMC_SET_HW_CFG(lp, cfg); udelay(10); /* Wait for clocks to stop */ cfg |= HW_CFG_SMI_SEL_; - SMC_SET_HW_CFG(cfg); + SMC_SET_HW_CFG(lp, cfg); for (phyaddr = 1; phyaddr < 32; ++phyaddr) { /* Read the PHY identifiers */ - SMC_GET_PHY_ID1(phyaddr & 31, id1); - SMC_GET_PHY_ID2(phyaddr & 31, id2); + SMC_GET_PHY_ID1(lp, phyaddr & 31, id1); + SMC_GET_PHY_ID2(lp, phyaddr & 31, id2); /* Make sure it is a valid identifier */ if (id1 != 0x0000 && id1 != 0xffff && @@ -782,8 +725,8 @@ static void smc911x_phy_detect(struct net_device *dev) } default: /* Internal media only */ - SMC_GET_PHY_ID1(1, id1); - SMC_GET_PHY_ID2(1, id2); + SMC_GET_PHY_ID1(lp, 1, id1); + SMC_GET_PHY_ID2(lp, 1, id2); /* Save the PHY's address */ lp->mii.phy_id = 1; lp->phy_type = id1 << 16 | id2; @@ -800,16 +743,15 @@ static void smc911x_phy_detect(struct net_device *dev) static int smc911x_phy_fixed(struct net_device *dev) { struct smc911x_local *lp = netdev_priv(dev); - unsigned long ioaddr = dev->base_addr; int phyaddr = lp->mii.phy_id; int bmcr; DBG(SMC_DEBUG_FUNC, "%s: --> %s\n", dev->name, __FUNCTION__); /* Enter Link Disable state */ - SMC_GET_PHY_BMCR(phyaddr, bmcr); + SMC_GET_PHY_BMCR(lp, phyaddr, bmcr); bmcr |= BMCR_PDOWN; - SMC_SET_PHY_BMCR(phyaddr, bmcr); + SMC_SET_PHY_BMCR(lp, phyaddr, bmcr); /* * Set our fixed capabilities @@ -823,11 +765,11 @@ static int smc911x_phy_fixed(struct net_device *dev) bmcr |= BMCR_SPEED100; /* Write our capabilities to the phy control register */ - SMC_SET_PHY_BMCR(phyaddr, bmcr); + SMC_SET_PHY_BMCR(lp, phyaddr, bmcr); /* Re-Configure the Receive/Phy Control register */ bmcr &= ~BMCR_PDOWN; - SMC_SET_PHY_BMCR(phyaddr, bmcr); + SMC_SET_PHY_BMCR(lp, phyaddr, bmcr); return 1; } @@ -847,7 +789,6 @@ static int smc911x_phy_fixed(struct net_device *dev) static int smc911x_phy_reset(struct net_device *dev, int phy) { struct smc911x_local *lp = netdev_priv(dev); - unsigned long ioaddr = dev->base_addr; int timeout; unsigned long flags; unsigned int reg; @@ -855,15 +796,15 @@ static int smc911x_phy_reset(struct net_device *dev, int phy) DBG(SMC_DEBUG_FUNC, "%s: --> %s()\n", dev->name, __FUNCTION__); spin_lock_irqsave(&lp->lock, flags); - reg = SMC_GET_PMT_CTRL(); + reg = SMC_GET_PMT_CTRL(lp); reg &= ~0xfffff030; reg |= PMT_CTRL_PHY_RST_; - SMC_SET_PMT_CTRL(reg); + SMC_SET_PMT_CTRL(lp, reg); spin_unlock_irqrestore(&lp->lock, flags); for (timeout = 2; timeout; timeout--) { msleep(50); spin_lock_irqsave(&lp->lock, flags); - reg = SMC_GET_PMT_CTRL(); + reg = SMC_GET_PMT_CTRL(lp); spin_unlock_irqrestore(&lp->lock, flags); if (!(reg & PMT_CTRL_PHY_RST_)) { /* extra delay required because the phy may @@ -888,13 +829,13 @@ static int smc911x_phy_reset(struct net_device *dev, int phy) */ static void smc911x_phy_powerdown(struct net_device *dev, int phy) { - unsigned long ioaddr = dev->base_addr; + struct smc911x_local *lp = netdev_priv(dev); unsigned int bmcr; /* Enter Link Disable state */ - SMC_GET_PHY_BMCR(phy, bmcr); + SMC_GET_PHY_BMCR(lp, phy, bmcr); bmcr |= BMCR_PDOWN; - SMC_SET_PHY_BMCR(phy, bmcr); + SMC_SET_PHY_BMCR(lp, phy, bmcr); } /* @@ -908,7 +849,6 @@ static void smc911x_phy_powerdown(struct net_device *dev, int phy) static void smc911x_phy_check_media(struct net_device *dev, int init) { struct smc911x_local *lp = netdev_priv(dev); - unsigned long ioaddr = dev->base_addr; int phyaddr = lp->mii.phy_id; unsigned int bmcr, cr; @@ -916,8 +856,8 @@ static void smc911x_phy_check_media(struct net_device *dev, int init) if (mii_check_media(&lp->mii, netif_msg_link(lp), init)) { /* duplex state has changed */ - SMC_GET_PHY_BMCR(phyaddr, bmcr); - SMC_GET_MAC_CR(cr); + SMC_GET_PHY_BMCR(lp, phyaddr, bmcr); + SMC_GET_MAC_CR(lp, cr); if (lp->mii.full_duplex) { DBG(SMC_DEBUG_MISC, "%s: Configuring for full-duplex mode\n", dev->name); bmcr |= BMCR_FULLDPLX; @@ -927,8 +867,8 @@ static void smc911x_phy_check_media(struct net_device *dev, int init) bmcr &= ~BMCR_FULLDPLX; cr &= ~MAC_CR_RCVOWN_; } - SMC_SET_PHY_BMCR(phyaddr, bmcr); - SMC_SET_MAC_CR(cr); + SMC_SET_PHY_BMCR(lp, phyaddr, bmcr); + SMC_SET_MAC_CR(lp, cr); } } @@ -946,7 +886,6 @@ static void smc911x_phy_configure(struct work_struct *work) struct smc911x_local *lp = container_of(work, struct smc911x_local, phy_configure); struct net_device *dev = lp->netdev; - unsigned long ioaddr = dev->base_addr; int phyaddr = lp->mii.phy_id; int my_phy_caps; /* My PHY capabilities */ int my_ad_caps; /* My Advertised capabilities */ @@ -971,7 +910,7 @@ static void smc911x_phy_configure(struct work_struct *work) * Enable PHY Interrupts (for register 18) * Interrupts listed here are enabled */ - SMC_SET_PHY_INT_MASK(phyaddr, PHY_INT_MASK_ENERGY_ON_ | + SMC_SET_PHY_INT_MASK(lp, phyaddr, PHY_INT_MASK_ENERGY_ON_ | PHY_INT_MASK_ANEG_COMP_ | PHY_INT_MASK_REMOTE_FAULT_ | PHY_INT_MASK_LINK_DOWN_); @@ -982,7 +921,7 @@ static void smc911x_phy_configure(struct work_struct *work) } /* Copy our capabilities from MII_BMSR to MII_ADVERTISE */ - SMC_GET_PHY_BMSR(phyaddr, my_phy_caps); + SMC_GET_PHY_BMSR(lp, phyaddr, my_phy_caps); if (!(my_phy_caps & BMSR_ANEGCAPABLE)) { printk(KERN_INFO "Auto negotiation NOT supported\n"); smc911x_phy_fixed(dev); @@ -1011,7 +950,7 @@ static void smc911x_phy_configure(struct work_struct *work) my_ad_caps &= ~(ADVERTISE_100FULL|ADVERTISE_10FULL); /* Update our Auto-Neg Advertisement Register */ - SMC_SET_PHY_MII_ADV(phyaddr, my_ad_caps); + SMC_SET_PHY_MII_ADV(lp, phyaddr, my_ad_caps); lp->mii.advertising = my_ad_caps; /* @@ -1020,13 +959,13 @@ static void smc911x_phy_configure(struct work_struct *work) * the link does not come up. */ udelay(10); - SMC_GET_PHY_MII_ADV(phyaddr, status); + SMC_GET_PHY_MII_ADV(lp, phyaddr, status); DBG(SMC_DEBUG_MISC, "%s: phy caps=0x%04x\n", dev->name, my_phy_caps); DBG(SMC_DEBUG_MISC, "%s: phy advertised caps=0x%04x\n", dev->name, my_ad_caps); /* Restart auto-negotiation process in order to advertise my caps */ - SMC_SET_PHY_BMCR(phyaddr, BMCR_ANENABLE | BMCR_ANRESTART); + SMC_SET_PHY_BMCR(lp, phyaddr, BMCR_ANENABLE | BMCR_ANRESTART); smc911x_phy_check_media(dev, 1); @@ -1043,7 +982,6 @@ smc911x_phy_configure_exit: static void smc911x_phy_interrupt(struct net_device *dev) { struct smc911x_local *lp = netdev_priv(dev); - unsigned long ioaddr = dev->base_addr; int phyaddr = lp->mii.phy_id; int status; @@ -1054,11 +992,11 @@ static void smc911x_phy_interrupt(struct net_device *dev) smc911x_phy_check_media(dev, 0); /* read to clear status bits */ - SMC_GET_PHY_INT_SRC(phyaddr,status); + SMC_GET_PHY_INT_SRC(lp, phyaddr,status); DBG(SMC_DEBUG_MISC, "%s: PHY interrupt status 0x%04x\n", dev->name, status & 0xffff); DBG(SMC_DEBUG_MISC, "%s: AFC_CFG 0x%08x\n", - dev->name, SMC_GET_AFC_CFG()); + dev->name, SMC_GET_AFC_CFG(lp)); } /*--- END PHY CONTROL AND CONFIGURATION-------------------------------------*/ @@ -1070,7 +1008,6 @@ static void smc911x_phy_interrupt(struct net_device *dev) static irqreturn_t smc911x_interrupt(int irq, void *dev_id) { struct net_device *dev = dev_id; - unsigned long ioaddr = dev->base_addr; struct smc911x_local *lp = netdev_priv(dev); unsigned int status, mask, timeout; unsigned int rx_overrun=0, cr, pkts; @@ -1081,21 +1018,21 @@ static irqreturn_t smc911x_interrupt(int irq, void *dev_id) spin_lock_irqsave(&lp->lock, flags); /* Spurious interrupt check */ - if ((SMC_GET_IRQ_CFG() & (INT_CFG_IRQ_INT_ | INT_CFG_IRQ_EN_)) != + if ((SMC_GET_IRQ_CFG(lp) & (INT_CFG_IRQ_INT_ | INT_CFG_IRQ_EN_)) != (INT_CFG_IRQ_INT_ | INT_CFG_IRQ_EN_)) { spin_unlock_irqrestore(&lp->lock, flags); return IRQ_NONE; } - mask = SMC_GET_INT_EN(); - SMC_SET_INT_EN(0); + mask = SMC_GET_INT_EN(lp); + SMC_SET_INT_EN(lp, 0); /* set a timeout value, so I don't stay here forever */ timeout = 8; do { - status = SMC_GET_INT(); + status = SMC_GET_INT(lp); DBG(SMC_DEBUG_MISC, "%s: INT 0x%08x MASK 0x%08x OUTSIDE MASK 0x%08x\n", dev->name, status, mask, status & ~mask); @@ -1106,53 +1043,53 @@ static irqreturn_t smc911x_interrupt(int irq, void *dev_id) /* Handle SW interrupt condition */ if (status & INT_STS_SW_INT_) { - SMC_ACK_INT(INT_STS_SW_INT_); + SMC_ACK_INT(lp, INT_STS_SW_INT_); mask &= ~INT_EN_SW_INT_EN_; } /* Handle various error conditions */ if (status & INT_STS_RXE_) { - SMC_ACK_INT(INT_STS_RXE_); + SMC_ACK_INT(lp, INT_STS_RXE_); dev->stats.rx_errors++; } if (status & INT_STS_RXDFH_INT_) { - SMC_ACK_INT(INT_STS_RXDFH_INT_); - dev->stats.rx_dropped+=SMC_GET_RX_DROP(); + SMC_ACK_INT(lp, INT_STS_RXDFH_INT_); + dev->stats.rx_dropped+=SMC_GET_RX_DROP(lp); } /* Undocumented interrupt-what is the right thing to do here? */ if (status & INT_STS_RXDF_INT_) { - SMC_ACK_INT(INT_STS_RXDF_INT_); + SMC_ACK_INT(lp, INT_STS_RXDF_INT_); } /* Rx Data FIFO exceeds set level */ if (status & INT_STS_RDFL_) { if (IS_REV_A(lp->revision)) { rx_overrun=1; - SMC_GET_MAC_CR(cr); + SMC_GET_MAC_CR(lp, cr); cr &= ~MAC_CR_RXEN_; - SMC_SET_MAC_CR(cr); + SMC_SET_MAC_CR(lp, cr); DBG(SMC_DEBUG_RX, "%s: RX overrun\n", dev->name); dev->stats.rx_errors++; dev->stats.rx_fifo_errors++; } - SMC_ACK_INT(INT_STS_RDFL_); + SMC_ACK_INT(lp, INT_STS_RDFL_); } if (status & INT_STS_RDFO_) { if (!IS_REV_A(lp->revision)) { - SMC_GET_MAC_CR(cr); + SMC_GET_MAC_CR(lp, cr); cr &= ~MAC_CR_RXEN_; - SMC_SET_MAC_CR(cr); + SMC_SET_MAC_CR(lp, cr); rx_overrun=1; DBG(SMC_DEBUG_RX, "%s: RX overrun\n", dev->name); dev->stats.rx_errors++; dev->stats.rx_fifo_errors++; } - SMC_ACK_INT(INT_STS_RDFO_); + SMC_ACK_INT(lp, INT_STS_RDFO_); } /* Handle receive condition */ if ((status & INT_STS_RSFL_) || rx_overrun) { unsigned int fifo; DBG(SMC_DEBUG_RX, "%s: RX irq\n", dev->name); - fifo = SMC_GET_RX_FIFO_INF(); + fifo = SMC_GET_RX_FIFO_INF(lp); pkts = (fifo & RX_FIFO_INF_RXSUSED_) >> 16; DBG(SMC_DEBUG_RX, "%s: Rx FIFO pkts %d, bytes %d\n", dev->name, pkts, fifo & 0xFFFF ); @@ -1163,61 +1100,61 @@ static irqreturn_t smc911x_interrupt(int irq, void *dev_id) DBG(SMC_DEBUG_RX | SMC_DEBUG_DMA, "%s: RX DMA active\n", dev->name); /* The DMA is already running so up the IRQ threshold */ - fifo = SMC_GET_FIFO_INT() & ~0xFF; + fifo = SMC_GET_FIFO_INT(lp) & ~0xFF; fifo |= pkts & 0xFF; DBG(SMC_DEBUG_RX, "%s: Setting RX stat FIFO threshold to %d\n", dev->name, fifo & 0xff); - SMC_SET_FIFO_INT(fifo); + SMC_SET_FIFO_INT(lp, fifo); } else #endif smc911x_rcv(dev); } - SMC_ACK_INT(INT_STS_RSFL_); + SMC_ACK_INT(lp, INT_STS_RSFL_); } /* Handle transmit FIFO available */ if (status & INT_STS_TDFA_) { DBG(SMC_DEBUG_TX, "%s: TX data FIFO space available irq\n", dev->name); - SMC_SET_FIFO_TDA(0xFF); + SMC_SET_FIFO_TDA(lp, 0xFF); lp->tx_throttle = 0; #ifdef SMC_USE_DMA if (!lp->txdma_active) #endif netif_wake_queue(dev); - SMC_ACK_INT(INT_STS_TDFA_); + SMC_ACK_INT(lp, INT_STS_TDFA_); } /* Handle transmit done condition */ #if 1 if (status & (INT_STS_TSFL_ | INT_STS_GPT_INT_)) { DBG(SMC_DEBUG_TX | SMC_DEBUG_MISC, "%s: Tx stat FIFO limit (%d) /GPT irq\n", - dev->name, (SMC_GET_FIFO_INT() & 0x00ff0000) >> 16); + dev->name, (SMC_GET_FIFO_INT(lp) & 0x00ff0000) >> 16); smc911x_tx(dev); - SMC_SET_GPT_CFG(GPT_CFG_TIMER_EN_ | 10000); - SMC_ACK_INT(INT_STS_TSFL_); - SMC_ACK_INT(INT_STS_TSFL_ | INT_STS_GPT_INT_); + SMC_SET_GPT_CFG(lp, GPT_CFG_TIMER_EN_ | 10000); + SMC_ACK_INT(lp, INT_STS_TSFL_); + SMC_ACK_INT(lp, INT_STS_TSFL_ | INT_STS_GPT_INT_); } #else if (status & INT_STS_TSFL_) { DBG(SMC_DEBUG_TX, "%s: TX status FIFO limit (%d) irq \n", dev->name, ); smc911x_tx(dev); - SMC_ACK_INT(INT_STS_TSFL_); + SMC_ACK_INT(lp, INT_STS_TSFL_); } if (status & INT_STS_GPT_INT_) { DBG(SMC_DEBUG_RX, "%s: IRQ_CFG 0x%08x FIFO_INT 0x%08x RX_CFG 0x%08x\n", dev->name, - SMC_GET_IRQ_CFG(), - SMC_GET_FIFO_INT(), - SMC_GET_RX_CFG()); + SMC_GET_IRQ_CFG(lp), + SMC_GET_FIFO_INT(lp), + SMC_GET_RX_CFG(lp)); DBG(SMC_DEBUG_RX, "%s: Rx Stat FIFO Used 0x%02x " "Data FIFO Used 0x%04x Stat FIFO 0x%08x\n", dev->name, - (SMC_GET_RX_FIFO_INF() & 0x00ff0000) >> 16, - SMC_GET_RX_FIFO_INF() & 0xffff, - SMC_GET_RX_STS_FIFO_PEEK()); - SMC_SET_GPT_CFG(GPT_CFG_TIMER_EN_ | 10000); - SMC_ACK_INT(INT_STS_GPT_INT_); + (SMC_GET_RX_FIFO_INF(lp) & 0x00ff0000) >> 16, + SMC_GET_RX_FIFO_INF(lp) & 0xffff, + SMC_GET_RX_STS_FIFO_PEEK(lp)); + SMC_SET_GPT_CFG(lp, GPT_CFG_TIMER_EN_ | 10000); + SMC_ACK_INT(lp, INT_STS_GPT_INT_); } #endif @@ -1225,12 +1162,12 @@ static irqreturn_t smc911x_interrupt(int irq, void *dev_id) if (status & INT_STS_PHY_INT_) { DBG(SMC_DEBUG_MISC, "%s: PHY irq\n", dev->name); smc911x_phy_interrupt(dev); - SMC_ACK_INT(INT_STS_PHY_INT_); + SMC_ACK_INT(lp, INT_STS_PHY_INT_); } } while (--timeout); /* restore mask state */ - SMC_SET_INT_EN(mask); + SMC_SET_INT_EN(lp, mask); DBG(SMC_DEBUG_MISC, "%s: Interrupt done (%d loops)\n", dev->name, 8-timeout); @@ -1332,22 +1269,21 @@ static void smc911x_poll_controller(struct net_device *dev) static void smc911x_timeout(struct net_device *dev) { struct smc911x_local *lp = netdev_priv(dev); - unsigned long ioaddr = dev->base_addr; int status, mask; unsigned long flags; DBG(SMC_DEBUG_FUNC, "%s: --> %s\n", dev->name, __FUNCTION__); spin_lock_irqsave(&lp->lock, flags); - status = SMC_GET_INT(); - mask = SMC_GET_INT_EN(); + status = SMC_GET_INT(lp); + mask = SMC_GET_INT_EN(lp); spin_unlock_irqrestore(&lp->lock, flags); DBG(SMC_DEBUG_MISC, "%s: INT 0x%02x MASK 0x%02x \n", dev->name, status, mask); /* Dump the current TX FIFO contents and restart */ - mask = SMC_GET_TX_CFG(); - SMC_SET_TX_CFG(mask | TX_CFG_TXS_DUMP_ | TX_CFG_TXD_DUMP_); + mask = SMC_GET_TX_CFG(lp); + SMC_SET_TX_CFG(lp, mask | TX_CFG_TXS_DUMP_ | TX_CFG_TXD_DUMP_); /* * Reconfiguring the PHY doesn't seem like a bad idea here, but * smc911x_phy_configure() calls msleep() which calls schedule_timeout() @@ -1370,7 +1306,6 @@ static void smc911x_timeout(struct net_device *dev) static void smc911x_set_multicast_list(struct net_device *dev) { struct smc911x_local *lp = netdev_priv(dev); - unsigned long ioaddr = dev->base_addr; unsigned int multicast_table[2]; unsigned int mcr, update_multicast = 0; unsigned long flags; @@ -1378,7 +1313,7 @@ static void smc911x_set_multicast_list(struct net_device *dev) DBG(SMC_DEBUG_FUNC, "%s: --> %s\n", dev->name, __FUNCTION__); spin_lock_irqsave(&lp->lock, flags); - SMC_GET_MAC_CR(mcr); + SMC_GET_MAC_CR(lp, mcr); spin_unlock_irqrestore(&lp->lock, flags); if (dev->flags & IFF_PROMISC) { @@ -1455,13 +1390,13 @@ static void smc911x_set_multicast_list(struct net_device *dev) } spin_lock_irqsave(&lp->lock, flags); - SMC_SET_MAC_CR(mcr); + SMC_SET_MAC_CR(lp, mcr); if (update_multicast) { DBG(SMC_DEBUG_MISC, "%s: update mcast hash table 0x%08x 0x%08x\n", dev->name, multicast_table[0], multicast_table[1]); - SMC_SET_HASHL(multicast_table[0]); - SMC_SET_HASHH(multicast_table[1]); + SMC_SET_HASHL(lp, multicast_table[0]); + SMC_SET_HASHH(lp, multicast_table[1]); } spin_unlock_irqrestore(&lp->lock, flags); } @@ -1545,7 +1480,6 @@ static int smc911x_ethtool_getsettings(struct net_device *dev, struct ethtool_cmd *cmd) { struct smc911x_local *lp = netdev_priv(dev); - unsigned long ioaddr = dev->base_addr; int ret, status; unsigned long flags; @@ -1573,7 +1507,7 @@ smc911x_ethtool_getsettings(struct net_device *dev, struct ethtool_cmd *cmd) else cmd->transceiver = XCVR_EXTERNAL; cmd->port = 0; - SMC_GET_PHY_SPECIAL(lp->mii.phy_id, status); + SMC_GET_PHY_SPECIAL(lp, lp->mii.phy_id, status); cmd->duplex = (status & (PHY_SPECIAL_SPD_10FULL_ | PHY_SPECIAL_SPD_100FULL_)) ? DUPLEX_FULL : DUPLEX_HALF; @@ -1654,7 +1588,6 @@ static int smc911x_ethtool_getregslen(struct net_device *dev) static void smc911x_ethtool_getregs(struct net_device *dev, struct ethtool_regs* regs, void *buf) { - unsigned long ioaddr = dev->base_addr; struct smc911x_local *lp = netdev_priv(dev); unsigned long flags; u32 reg,i,j=0; @@ -1662,17 +1595,17 @@ static void smc911x_ethtool_getregs(struct net_device *dev, regs->version = lp->version; for(i=ID_REV;i<=E2P_CMD;i+=4) { - data[j++] = SMC_inl(ioaddr,i); + data[j++] = SMC_inl(lp, i); } for(i=MAC_CR;i<=WUCSR;i++) { spin_lock_irqsave(&lp->lock, flags); - SMC_GET_MAC_CSR(i, reg); + SMC_GET_MAC_CSR(lp, i, reg); spin_unlock_irqrestore(&lp->lock, flags); data[j++] = reg; } for(i=0;i<=31;i++) { spin_lock_irqsave(&lp->lock, flags); - SMC_GET_MII(i, lp->mii.phy_id, reg); + SMC_GET_MII(lp, i, lp->mii.phy_id, reg); spin_unlock_irqrestore(&lp->lock, flags); data[j++] = reg & 0xFFFF; } @@ -1680,11 +1613,11 @@ static void smc911x_ethtool_getregs(struct net_device *dev, static int smc911x_ethtool_wait_eeprom_ready(struct net_device *dev) { - unsigned long ioaddr = dev->base_addr; + struct smc911x_local *lp = netdev_priv(dev); unsigned int timeout; int e2p_cmd; - e2p_cmd = SMC_GET_E2P_CMD(); + e2p_cmd = SMC_GET_E2P_CMD(lp); for(timeout=10;(e2p_cmd & E2P_CMD_EPC_BUSY_) && timeout; timeout--) { if (e2p_cmd & E2P_CMD_EPC_TIMEOUT_) { PRINTK("%s: %s timeout waiting for EEPROM to respond\n", @@ -1692,7 +1625,7 @@ static int smc911x_ethtool_wait_eeprom_ready(struct net_device *dev) return -EFAULT; } mdelay(1); - e2p_cmd = SMC_GET_E2P_CMD(); + e2p_cmd = SMC_GET_E2P_CMD(lp); } if (timeout == 0) { PRINTK("%s: %s timeout waiting for EEPROM CMD not busy\n", @@ -1705,12 +1638,12 @@ static int smc911x_ethtool_wait_eeprom_ready(struct net_device *dev) static inline int smc911x_ethtool_write_eeprom_cmd(struct net_device *dev, int cmd, int addr) { - unsigned long ioaddr = dev->base_addr; + struct smc911x_local *lp = netdev_priv(dev); int ret; if ((ret = smc911x_ethtool_wait_eeprom_ready(dev))!=0) return ret; - SMC_SET_E2P_CMD(E2P_CMD_EPC_BUSY_ | + SMC_SET_E2P_CMD(lp, E2P_CMD_EPC_BUSY_ | ((cmd) & (0x7<<28)) | ((addr) & 0xFF)); return 0; @@ -1719,24 +1652,24 @@ static inline int smc911x_ethtool_write_eeprom_cmd(struct net_device *dev, static inline int smc911x_ethtool_read_eeprom_byte(struct net_device *dev, u8 *data) { - unsigned long ioaddr = dev->base_addr; + struct smc911x_local *lp = netdev_priv(dev); int ret; if ((ret = smc911x_ethtool_wait_eeprom_ready(dev))!=0) return ret; - *data = SMC_GET_E2P_DATA(); + *data = SMC_GET_E2P_DATA(lp); return 0; } static inline int smc911x_ethtool_write_eeprom_byte(struct net_device *dev, u8 data) { - unsigned long ioaddr = dev->base_addr; + struct smc911x_local *lp = netdev_priv(dev); int ret; if ((ret = smc911x_ethtool_wait_eeprom_ready(dev))!=0) return ret; - SMC_SET_E2P_DATA(data); + SMC_SET_E2P_DATA(lp, data); return 0; } @@ -1803,8 +1736,9 @@ static const struct ethtool_ops smc911x_ethtool_ops = { * This routine has a simple purpose -- make the SMC chip generate an * interrupt, so an auto-detect routine can detect it, and find the IRQ, */ -static int __init smc911x_findirq(unsigned long ioaddr) +static int __init smc911x_findirq(struct net_device *dev) { + struct smc911x_local *lp = netdev_priv(dev); int timeout = 20; unsigned long cookie; @@ -1816,7 +1750,7 @@ static int __init smc911x_findirq(unsigned long ioaddr) * Force a SW interrupt */ - SMC_SET_INT_EN(INT_EN_SW_INT_EN_); + SMC_SET_INT_EN(lp, INT_EN_SW_INT_EN_); /* * Wait until positive that the interrupt has been generated @@ -1824,7 +1758,7 @@ static int __init smc911x_findirq(unsigned long ioaddr) do { int int_status; udelay(10); - int_status = SMC_GET_INT_EN(); + int_status = SMC_GET_INT_EN(lp); if (int_status & INT_EN_SW_INT_EN_) break; /* got the interrupt */ } while (--timeout); @@ -1837,7 +1771,7 @@ static int __init smc911x_findirq(unsigned long ioaddr) */ /* and disable all interrupts again */ - SMC_SET_INT_EN(0); + SMC_SET_INT_EN(lp, 0); /* and return what I found */ return probe_irq_off(cookie); @@ -1866,17 +1800,18 @@ static int __init smc911x_findirq(unsigned long ioaddr) * o actually GRAB the irq. * o GRAB the region */ -static int __init smc911x_probe(struct net_device *dev, unsigned long ioaddr) +static int __init smc911x_probe(struct net_device *dev) { struct smc911x_local *lp = netdev_priv(dev); int i, retval; unsigned int val, chip_id, revision; const char *version_string; + unsigned long irq_flags; DBG(SMC_DEBUG_FUNC, "%s: --> %s\n", dev->name, __FUNCTION__); /* First, see if the endian word is recognized */ - val = SMC_GET_BYTE_TEST(); + val = SMC_GET_BYTE_TEST(lp); DBG(SMC_DEBUG_MISC, "%s: endian probe returned 0x%04x\n", CARDNAME, val); if (val != 0x87654321) { printk(KERN_ERR "Invalid chip endian 0x08%x\n",val); @@ -1889,7 +1824,7 @@ static int __init smc911x_probe(struct net_device *dev, unsigned long ioaddr) * recognize. These might need to be added to later, * as future revisions could be added. */ - chip_id = SMC_GET_PN(); + chip_id = SMC_GET_PN(lp); DBG(SMC_DEBUG_MISC, "%s: id probe returned 0x%04x\n", CARDNAME, chip_id); for(i=0;chip_ids[i].id != 0; i++) { if (chip_ids[i].id == chip_id) break; @@ -1901,7 +1836,7 @@ static int __init smc911x_probe(struct net_device *dev, unsigned long ioaddr) } version_string = chip_ids[i].name; - revision = SMC_GET_REV(); + revision = SMC_GET_REV(lp); DBG(SMC_DEBUG_MISC, "%s: revision = 0x%04x\n", CARDNAME, revision); /* At this point I'll assume that the chip is an SMC911x. */ @@ -1915,7 +1850,6 @@ static int __init smc911x_probe(struct net_device *dev, unsigned long ioaddr) } /* fill in some of the fields */ - dev->base_addr = ioaddr; lp->version = chip_ids[i].id; lp->revision = revision; lp->tx_fifo_kb = tx_fifo_kb; @@ -1974,7 +1908,7 @@ static int __init smc911x_probe(struct net_device *dev, unsigned long ioaddr) spin_lock_init(&lp->lock); /* Get the MAC address */ - SMC_GET_MAC_ADDR(dev->dev_addr); + SMC_GET_MAC_ADDR(lp, dev->dev_addr); /* now, reset the chip, and put it into a known state */ smc911x_reset(dev); @@ -1991,7 +1925,7 @@ static int __init smc911x_probe(struct net_device *dev, unsigned long ioaddr) trials = 3; while (trials--) { - dev->irq = smc911x_findirq(ioaddr); + dev->irq = smc911x_findirq(dev); if (dev->irq) break; /* kick the card and try again */ @@ -2039,9 +1973,15 @@ static int __init smc911x_probe(struct net_device *dev, unsigned long ioaddr) lp->ctl_rfduplx = 1; lp->ctl_rspeed = 100; +#ifdef SMC_DYNAMIC_BUS_CONFIG + irq_flags = lp->cfg.irq_flags; +#else + irq_flags = IRQF_SHARED | SMC_IRQ_SENSE; +#endif + /* Grab the IRQ */ retval = request_irq(dev->irq, &smc911x_interrupt, - IRQF_SHARED | SMC_IRQ_SENSE, dev->name, dev); + irq_flags, dev->name, dev); if (retval) goto err_out; @@ -2111,6 +2051,7 @@ err_out: */ static int smc911x_drv_probe(struct platform_device *pdev) { + struct smc91x_platdata *pd = pdev->dev.platform_data; struct net_device *ndev; struct resource *res; struct smc911x_local *lp; @@ -2144,6 +2085,13 @@ static int smc911x_drv_probe(struct platform_device *pdev) ndev->irq = platform_get_irq(pdev, 0); lp = netdev_priv(ndev); lp->netdev = ndev; +#ifdef SMC_DYNAMIC_BUS_CONFIG + if (!pd) { + ret = -EINVAL; + goto release_both; + } + memcpy(&lp->cfg, pd, sizeof(lp->cfg)); +#endif addr = ioremap(res->start, SMC911X_IO_EXTENT); if (!addr) { @@ -2152,7 +2100,9 @@ static int smc911x_drv_probe(struct platform_device *pdev) } platform_set_drvdata(pdev, ndev); - ret = smc911x_probe(ndev, (unsigned long)addr); + lp->base = addr; + ndev->base_addr = res->start; + ret = smc911x_probe(ndev); if (ret != 0) { platform_set_drvdata(pdev, NULL); iounmap(addr); @@ -2176,6 +2126,7 @@ out: static int smc911x_drv_remove(struct platform_device *pdev) { struct net_device *ndev = platform_get_drvdata(pdev); + struct smc911x_local *lp = netdev_priv(ndev); struct resource *res; DBG(SMC_DEBUG_FUNC, "--> %s\n", __FUNCTION__); @@ -2187,7 +2138,6 @@ static int smc911x_drv_remove(struct platform_device *pdev) #ifdef SMC_USE_DMA { - struct smc911x_local *lp = netdev_priv(ndev); if (lp->rxdma != -1) { SMC_DMA_FREE(dev, lp->rxdma); } @@ -2196,7 +2146,7 @@ static int smc911x_drv_remove(struct platform_device *pdev) } } #endif - iounmap((void *)ndev->base_addr); + iounmap(lp->base); res = platform_get_resource(pdev, IORESOURCE_MEM, 0); release_mem_region(res->start, SMC911X_IO_EXTENT); @@ -2207,7 +2157,7 @@ static int smc911x_drv_remove(struct platform_device *pdev) static int smc911x_drv_suspend(struct platform_device *dev, pm_message_t state) { struct net_device *ndev = platform_get_drvdata(dev); - unsigned long ioaddr = ndev->base_addr; + struct smc911x_local *lp = netdev_priv(ndev); DBG(SMC_DEBUG_FUNC, "--> %s\n", __FUNCTION__); if (ndev) { @@ -2216,7 +2166,7 @@ static int smc911x_drv_suspend(struct platform_device *dev, pm_message_t state) smc911x_shutdown(ndev); #if POWER_DOWN /* Set D2 - Energy detect only setting */ - SMC_SET_PMT_CTRL(2<<12); + SMC_SET_PMT_CTRL(lp, 2<<12); #endif } } diff --git a/drivers/net/smc911x.h b/drivers/net/smc911x.h index 7defa63b9c74..76c17c28fab4 100644 --- a/drivers/net/smc911x.h +++ b/drivers/net/smc911x.h @@ -29,6 +29,7 @@ #ifndef _SMC911X_H_ #define _SMC911X_H_ +#include <linux/smc911x.h> /* * Use the DMA feature on PXA chips */ @@ -38,42 +39,160 @@ #define SMC_USE_32BIT 1 #define SMC_IRQ_SENSE IRQF_TRIGGER_FALLING #elif defined(CONFIG_SH_MAGIC_PANEL_R2) - #define SMC_USE_SH_DMA 0 #define SMC_USE_16BIT 0 #define SMC_USE_32BIT 1 #define SMC_IRQ_SENSE IRQF_TRIGGER_LOW +#else +/* + * Default configuration + */ + +#define SMC_DYNAMIC_BUS_CONFIG #endif +/* store this information for the driver.. */ +struct smc911x_local { + /* + * If I have to wait until the DMA is finished and ready to reload a + * packet, I will store the skbuff here. Then, the DMA will send it + * out and free it. + */ + struct sk_buff *pending_tx_skb; + + /* version/revision of the SMC911x chip */ + u16 version; + u16 revision; + + /* FIFO sizes */ + int tx_fifo_kb; + int tx_fifo_size; + int rx_fifo_size; + int afc_cfg; + + /* Contains the current active receive/phy mode */ + int ctl_rfduplx; + int ctl_rspeed; + + u32 msg_enable; + u32 phy_type; + struct mii_if_info mii; + + /* work queue */ + struct work_struct phy_configure; + + int tx_throttle; + spinlock_t lock; + + struct net_device *netdev; + +#ifdef SMC_USE_DMA + /* DMA needs the physical address of the chip */ + u_long physaddr; + int rxdma; + int txdma; + int rxdma_active; + int txdma_active; + struct sk_buff *current_rx_skb; + struct sk_buff *current_tx_skb; + struct device *dev; +#endif + void __iomem *base; +#ifdef SMC_DYNAMIC_BUS_CONFIG + struct smc911x_platdata cfg; +#endif +}; /* * Define the bus width specific IO macros */ +#ifdef SMC_DYNAMIC_BUS_CONFIG +static inline unsigned int SMC_inl(struct smc911x_local *lp, int reg) +{ + void __iomem *ioaddr = lp->base + reg; + + if (lp->cfg.flags & SMC911X_USE_32BIT) + return readl(ioaddr); + + if (lp->cfg.flags & SMC911X_USE_16BIT) + return readw(ioaddr) | (readw(ioaddr + 2) << 16); + + BUG(); +} + +static inline void SMC_outl(unsigned int value, struct smc911x_local *lp, + int reg) +{ + void __iomem *ioaddr = lp->base + reg; + + if (lp->cfg.flags & SMC911X_USE_32BIT) { + writel(value, ioaddr); + return; + } + + if (lp->cfg.flags & SMC911X_USE_16BIT) { + writew(value & 0xffff, ioaddr); + writew(value >> 16, ioaddr + 2); + return; + } + + BUG(); +} + +static inline void SMC_insl(struct smc911x_local *lp, int reg, + void *addr, unsigned int count) +{ + void __iomem *ioaddr = lp->base + reg; + + if (lp->cfg.flags & SMC911X_USE_32BIT) { + readsl(ioaddr, addr, count); + return; + } + + if (lp->cfg.flags & SMC911X_USE_16BIT) { + readsw(ioaddr, addr, count * 2); + return; + } + + BUG(); +} + +static inline void SMC_outsl(struct smc911x_local *lp, int reg, + void *addr, unsigned int count) +{ + void __iomem *ioaddr = lp->base + reg; + + if (lp->cfg.flags & SMC911X_USE_32BIT) { + writesl(ioaddr, addr, count); + return; + } + + if (lp->cfg.flags & SMC911X_USE_16BIT) { + writesw(ioaddr, addr, count * 2); + return; + } + + BUG(); +} +#else #if SMC_USE_16BIT -#define SMC_inb(a, r) readb((a) + (r)) -#define SMC_inw(a, r) readw((a) + (r)) -#define SMC_inl(a, r) ((SMC_inw(a, r) & 0xFFFF)+(SMC_inw(a+2, r)<<16)) -#define SMC_outb(v, a, r) writeb(v, (a) + (r)) -#define SMC_outw(v, a, r) writew(v, (a) + (r)) -#define SMC_outl(v, a, r) \ +#define SMC_inl(lp, r) ((readw((lp)->base + (r)) & 0xFFFF) + (readw((lp)->base + (r) + 2) << 16)) +#define SMC_outl(v, lp, r) \ do{ \ - writel(v & 0xFFFF, (a) + (r)); \ - writel(v >> 16, (a) + (r) + 2); \ + writew(v & 0xFFFF, (lp)->base + (r)); \ + writew(v >> 16, (lp)->base + (r) + 2); \ } while (0) -#define SMC_insl(a, r, p, l) readsw((short*)((a) + (r)), p, l*2) -#define SMC_outsl(a, r, p, l) writesw((short*)((a) + (r)), p, l*2) +#define SMC_insl(lp, r, p, l) readsw((short*)((lp)->base + (r)), p, l*2) +#define SMC_outsl(lp, r, p, l) writesw((short*)((lp)->base + (r)), p, l*2) #elif SMC_USE_32BIT -#define SMC_inb(a, r) readb((a) + (r)) -#define SMC_inw(a, r) readw((a) + (r)) -#define SMC_inl(a, r) readl((a) + (r)) -#define SMC_outb(v, a, r) writeb(v, (a) + (r)) -#define SMC_outl(v, a, r) writel(v, (a) + (r)) -#define SMC_insl(a, r, p, l) readsl((int*)((a) + (r)), p, l) -#define SMC_outsl(a, r, p, l) writesl((int*)((a) + (r)), p, l) +#define SMC_inl(lp, r) readl((lp)->base + (r)) +#define SMC_outl(v, lp, r) writel(v, (lp)->base + (r)) +#define SMC_insl(lp, r, p, l) readsl((int*)((lp)->base + (r)), p, l) +#define SMC_outsl(lp, r, p, l) writesl((int*)((lp)->base + (r)), p, l) #endif /* SMC_USE_16BIT */ - +#endif /* SMC_DYNAMIC_BUS_CONFIG */ #ifdef SMC_USE_PXA_DMA @@ -110,22 +229,22 @@ static int rx_dmalen, tx_dmalen; #ifdef SMC_insl #undef SMC_insl -#define SMC_insl(a, r, p, l) \ - smc_pxa_dma_insl(lp->dev, a, lp->physaddr, r, lp->rxdma, p, l) +#define SMC_insl(lp, r, p, l) \ + smc_pxa_dma_insl(lp, lp->physaddr, r, lp->rxdma, p, l) static inline void -smc_pxa_dma_insl(struct device *dev, u_long ioaddr, u_long physaddr, +smc_pxa_dma_insl(struct smc911x_local *lp, u_long physaddr, int reg, int dma, u_char *buf, int len) { /* 64 bit alignment is required for memory to memory DMA */ if ((long)buf & 4) { - *((u32 *)buf) = SMC_inl(ioaddr, reg); + *((u32 *)buf) = SMC_inl(lp, reg); buf += 4; len--; } len *= 4; - rx_dmabuf = dma_map_single(dev, buf, len, DMA_FROM_DEVICE); + rx_dmabuf = dma_map_single(lp->dev, buf, len, DMA_FROM_DEVICE); rx_dmalen = len; DCSR(dma) = DCSR_NODESC; DTADR(dma) = rx_dmabuf; @@ -136,52 +255,24 @@ smc_pxa_dma_insl(struct device *dev, u_long ioaddr, u_long physaddr, } #endif -#ifdef SMC_insw -#undef SMC_insw -#define SMC_insw(a, r, p, l) \ - smc_pxa_dma_insw(lp->dev, a, lp->physaddr, r, lp->rxdma, p, l) - -static inline void -smc_pxa_dma_insw(struct device *dev, u_long ioaddr, u_long physaddr, - int reg, int dma, u_char *buf, int len) -{ - /* 64 bit alignment is required for memory to memory DMA */ - while ((long)buf & 6) { - *((u16 *)buf) = SMC_inw(ioaddr, reg); - buf += 2; - len--; - } - - len *= 2; - rx_dmabuf = dma_map_single(dev, buf, len, DMA_FROM_DEVICE); - rx_dmalen = len; - DCSR(dma) = DCSR_NODESC; - DTADR(dma) = rx_dmabuf; - DSADR(dma) = physaddr + reg; - DCMD(dma) = (DCMD_INCTRGADDR | DCMD_BURST32 | - DCMD_WIDTH2 | DCMD_ENDIRQEN | (DCMD_LENGTH & rx_dmalen)); - DCSR(dma) = DCSR_NODESC | DCSR_RUN; -} -#endif - #ifdef SMC_outsl #undef SMC_outsl -#define SMC_outsl(a, r, p, l) \ - smc_pxa_dma_outsl(lp->dev, a, lp->physaddr, r, lp->txdma, p, l) +#define SMC_outsl(lp, r, p, l) \ + smc_pxa_dma_outsl(lp, lp->physaddr, r, lp->txdma, p, l) static inline void -smc_pxa_dma_outsl(struct device *dev, u_long ioaddr, u_long physaddr, +smc_pxa_dma_outsl(struct smc911x_local *lp, u_long physaddr, int reg, int dma, u_char *buf, int len) { /* 64 bit alignment is required for memory to memory DMA */ if ((long)buf & 4) { - SMC_outl(*((u32 *)buf), ioaddr, reg); + SMC_outl(*((u32 *)buf), lp, reg); buf += 4; len--; } len *= 4; - tx_dmabuf = dma_map_single(dev, buf, len, DMA_TO_DEVICE); + tx_dmabuf = dma_map_single(lp->dev, buf, len, DMA_TO_DEVICE); tx_dmalen = len; DCSR(dma) = DCSR_NODESC; DSADR(dma) = tx_dmabuf; @@ -191,35 +282,6 @@ smc_pxa_dma_outsl(struct device *dev, u_long ioaddr, u_long physaddr, DCSR(dma) = DCSR_NODESC | DCSR_RUN; } #endif - -#ifdef SMC_outsw -#undef SMC_outsw -#define SMC_outsw(a, r, p, l) \ - smc_pxa_dma_outsw(lp->dev, a, lp->physaddr, r, lp->txdma, p, l) - -static inline void -smc_pxa_dma_outsw(struct device *dev, u_long ioaddr, u_long physaddr, - int reg, int dma, u_char *buf, int len) -{ - /* 64 bit alignment is required for memory to memory DMA */ - while ((long)buf & 6) { - SMC_outw(*((u16 *)buf), ioaddr, reg); - buf += 2; - len--; - } - - len *= 2; - tx_dmabuf = dma_map_single(dev, buf, len, DMA_TO_DEVICE); - tx_dmalen = len; - DCSR(dma) = DCSR_NODESC; - DSADR(dma) = tx_dmabuf; - DTADR(dma) = physaddr + reg; - DCMD(dma) = (DCMD_INCSRCADDR | DCMD_BURST32 | - DCMD_WIDTH2 | DCMD_ENDIRQEN | (DCMD_LENGTH & tx_dmalen)); - DCSR(dma) = DCSR_NODESC | DCSR_RUN; -} -#endif - #endif /* SMC_USE_PXA_DMA */ @@ -629,213 +691,213 @@ static const struct chip_id chip_ids[] = { * capabilities. Please use those and not the in/out primitives. */ /* FIFO read/write macros */ -#define SMC_PUSH_DATA(p, l) SMC_outsl( ioaddr, TX_DATA_FIFO, p, (l) >> 2 ) -#define SMC_PULL_DATA(p, l) SMC_insl ( ioaddr, RX_DATA_FIFO, p, (l) >> 2 ) -#define SMC_SET_TX_FIFO(x) SMC_outl( x, ioaddr, TX_DATA_FIFO ) -#define SMC_GET_RX_FIFO() SMC_inl( ioaddr, RX_DATA_FIFO ) +#define SMC_PUSH_DATA(lp, p, l) SMC_outsl( lp, TX_DATA_FIFO, p, (l) >> 2 ) +#define SMC_PULL_DATA(lp, p, l) SMC_insl ( lp, RX_DATA_FIFO, p, (l) >> 2 ) +#define SMC_SET_TX_FIFO(lp, x) SMC_outl( x, lp, TX_DATA_FIFO ) +#define SMC_GET_RX_FIFO(lp) SMC_inl( lp, RX_DATA_FIFO ) /* I/O mapped register read/write macros */ -#define SMC_GET_TX_STS_FIFO() SMC_inl( ioaddr, TX_STATUS_FIFO ) -#define SMC_GET_RX_STS_FIFO() SMC_inl( ioaddr, RX_STATUS_FIFO ) -#define SMC_GET_RX_STS_FIFO_PEEK() SMC_inl( ioaddr, RX_STATUS_FIFO_PEEK ) -#define SMC_GET_PN() (SMC_inl( ioaddr, ID_REV ) >> 16) -#define SMC_GET_REV() (SMC_inl( ioaddr, ID_REV ) & 0xFFFF) -#define SMC_GET_IRQ_CFG() SMC_inl( ioaddr, INT_CFG ) -#define SMC_SET_IRQ_CFG(x) SMC_outl( x, ioaddr, INT_CFG ) -#define SMC_GET_INT() SMC_inl( ioaddr, INT_STS ) -#define SMC_ACK_INT(x) SMC_outl( x, ioaddr, INT_STS ) -#define SMC_GET_INT_EN() SMC_inl( ioaddr, INT_EN ) -#define SMC_SET_INT_EN(x) SMC_outl( x, ioaddr, INT_EN ) -#define SMC_GET_BYTE_TEST() SMC_inl( ioaddr, BYTE_TEST ) -#define SMC_SET_BYTE_TEST(x) SMC_outl( x, ioaddr, BYTE_TEST ) -#define SMC_GET_FIFO_INT() SMC_inl( ioaddr, FIFO_INT ) -#define SMC_SET_FIFO_INT(x) SMC_outl( x, ioaddr, FIFO_INT ) -#define SMC_SET_FIFO_TDA(x) \ +#define SMC_GET_TX_STS_FIFO(lp) SMC_inl( lp, TX_STATUS_FIFO ) +#define SMC_GET_RX_STS_FIFO(lp) SMC_inl( lp, RX_STATUS_FIFO ) +#define SMC_GET_RX_STS_FIFO_PEEK(lp) SMC_inl( lp, RX_STATUS_FIFO_PEEK ) +#define SMC_GET_PN(lp) (SMC_inl( lp, ID_REV ) >> 16) +#define SMC_GET_REV(lp) (SMC_inl( lp, ID_REV ) & 0xFFFF) +#define SMC_GET_IRQ_CFG(lp) SMC_inl( lp, INT_CFG ) +#define SMC_SET_IRQ_CFG(lp, x) SMC_outl( x, lp, INT_CFG ) +#define SMC_GET_INT(lp) SMC_inl( lp, INT_STS ) +#define SMC_ACK_INT(lp, x) SMC_outl( x, lp, INT_STS ) +#define SMC_GET_INT_EN(lp) SMC_inl( lp, INT_EN ) +#define SMC_SET_INT_EN(lp, x) SMC_outl( x, lp, INT_EN ) +#define SMC_GET_BYTE_TEST(lp) SMC_inl( lp, BYTE_TEST ) +#define SMC_SET_BYTE_TEST(lp, x) SMC_outl( x, lp, BYTE_TEST ) +#define SMC_GET_FIFO_INT(lp) SMC_inl( lp, FIFO_INT ) +#define SMC_SET_FIFO_INT(lp, x) SMC_outl( x, lp, FIFO_INT ) +#define SMC_SET_FIFO_TDA(lp, x) \ do { \ unsigned long __flags; \ int __mask; \ local_irq_save(__flags); \ - __mask = SMC_GET_FIFO_INT() & ~(0xFF<<24); \ - SMC_SET_FIFO_INT( __mask | (x)<<24 ); \ + __mask = SMC_GET_FIFO_INT((lp)) & ~(0xFF<<24); \ + SMC_SET_FIFO_INT( (lp), __mask | (x)<<24 ); \ local_irq_restore(__flags); \ } while (0) -#define SMC_SET_FIFO_TSL(x) \ +#define SMC_SET_FIFO_TSL(lp, x) \ do { \ unsigned long __flags; \ int __mask; \ local_irq_save(__flags); \ - __mask = SMC_GET_FIFO_INT() & ~(0xFF<<16); \ - SMC_SET_FIFO_INT( __mask | (((x) & 0xFF)<<16)); \ + __mask = SMC_GET_FIFO_INT((lp)) & ~(0xFF<<16); \ + SMC_SET_FIFO_INT( (lp), __mask | (((x) & 0xFF)<<16)); \ local_irq_restore(__flags); \ } while (0) -#define SMC_SET_FIFO_RSA(x) \ +#define SMC_SET_FIFO_RSA(lp, x) \ do { \ unsigned long __flags; \ int __mask; \ local_irq_save(__flags); \ - __mask = SMC_GET_FIFO_INT() & ~(0xFF<<8); \ - SMC_SET_FIFO_INT( __mask | (((x) & 0xFF)<<8)); \ + __mask = SMC_GET_FIFO_INT((lp)) & ~(0xFF<<8); \ + SMC_SET_FIFO_INT( (lp), __mask | (((x) & 0xFF)<<8)); \ local_irq_restore(__flags); \ } while (0) -#define SMC_SET_FIFO_RSL(x) \ +#define SMC_SET_FIFO_RSL(lp, x) \ do { \ unsigned long __flags; \ int __mask; \ local_irq_save(__flags); \ - __mask = SMC_GET_FIFO_INT() & ~0xFF; \ - SMC_SET_FIFO_INT( __mask | ((x) & 0xFF)); \ + __mask = SMC_GET_FIFO_INT((lp)) & ~0xFF; \ + SMC_SET_FIFO_INT( (lp),__mask | ((x) & 0xFF)); \ local_irq_restore(__flags); \ } while (0) -#define SMC_GET_RX_CFG() SMC_inl( ioaddr, RX_CFG ) -#define SMC_SET_RX_CFG(x) SMC_outl( x, ioaddr, RX_CFG ) -#define SMC_GET_TX_CFG() SMC_inl( ioaddr, TX_CFG ) -#define SMC_SET_TX_CFG(x) SMC_outl( x, ioaddr, TX_CFG ) -#define SMC_GET_HW_CFG() SMC_inl( ioaddr, HW_CFG ) -#define SMC_SET_HW_CFG(x) SMC_outl( x, ioaddr, HW_CFG ) -#define SMC_GET_RX_DP_CTRL() SMC_inl( ioaddr, RX_DP_CTRL ) -#define SMC_SET_RX_DP_CTRL(x) SMC_outl( x, ioaddr, RX_DP_CTRL ) -#define SMC_GET_PMT_CTRL() SMC_inl( ioaddr, PMT_CTRL ) -#define SMC_SET_PMT_CTRL(x) SMC_outl( x, ioaddr, PMT_CTRL ) -#define SMC_GET_GPIO_CFG() SMC_inl( ioaddr, GPIO_CFG ) -#define SMC_SET_GPIO_CFG(x) SMC_outl( x, ioaddr, GPIO_CFG ) -#define SMC_GET_RX_FIFO_INF() SMC_inl( ioaddr, RX_FIFO_INF ) -#define SMC_SET_RX_FIFO_INF(x) SMC_outl( x, ioaddr, RX_FIFO_INF ) -#define SMC_GET_TX_FIFO_INF() SMC_inl( ioaddr, TX_FIFO_INF ) -#define SMC_SET_TX_FIFO_INF(x) SMC_outl( x, ioaddr, TX_FIFO_INF ) -#define SMC_GET_GPT_CFG() SMC_inl( ioaddr, GPT_CFG ) -#define SMC_SET_GPT_CFG(x) SMC_outl( x, ioaddr, GPT_CFG ) -#define SMC_GET_RX_DROP() SMC_inl( ioaddr, RX_DROP ) -#define SMC_SET_RX_DROP(x) SMC_outl( x, ioaddr, RX_DROP ) -#define SMC_GET_MAC_CMD() SMC_inl( ioaddr, MAC_CSR_CMD ) -#define SMC_SET_MAC_CMD(x) SMC_outl( x, ioaddr, MAC_CSR_CMD ) -#define SMC_GET_MAC_DATA() SMC_inl( ioaddr, MAC_CSR_DATA ) -#define SMC_SET_MAC_DATA(x) SMC_outl( x, ioaddr, MAC_CSR_DATA ) -#define SMC_GET_AFC_CFG() SMC_inl( ioaddr, AFC_CFG ) -#define SMC_SET_AFC_CFG(x) SMC_outl( x, ioaddr, AFC_CFG ) -#define SMC_GET_E2P_CMD() SMC_inl( ioaddr, E2P_CMD ) -#define SMC_SET_E2P_CMD(x) SMC_outl( x, ioaddr, E2P_CMD ) -#define SMC_GET_E2P_DATA() SMC_inl( ioaddr, E2P_DATA ) -#define SMC_SET_E2P_DATA(x) SMC_outl( x, ioaddr, E2P_DATA ) +#define SMC_GET_RX_CFG(lp) SMC_inl( lp, RX_CFG ) +#define SMC_SET_RX_CFG(lp, x) SMC_outl( x, lp, RX_CFG ) +#define SMC_GET_TX_CFG(lp) SMC_inl( lp, TX_CFG ) +#define SMC_SET_TX_CFG(lp, x) SMC_outl( x, lp, TX_CFG ) +#define SMC_GET_HW_CFG(lp) SMC_inl( lp, HW_CFG ) +#define SMC_SET_HW_CFG(lp, x) SMC_outl( x, lp, HW_CFG ) +#define SMC_GET_RX_DP_CTRL(lp) SMC_inl( lp, RX_DP_CTRL ) +#define SMC_SET_RX_DP_CTRL(lp, x) SMC_outl( x, lp, RX_DP_CTRL ) +#define SMC_GET_PMT_CTRL(lp) SMC_inl( lp, PMT_CTRL ) +#define SMC_SET_PMT_CTRL(lp, x) SMC_outl( x, lp, PMT_CTRL ) +#define SMC_GET_GPIO_CFG(lp) SMC_inl( lp, GPIO_CFG ) +#define SMC_SET_GPIO_CFG(lp, x) SMC_outl( x, lp, GPIO_CFG ) +#define SMC_GET_RX_FIFO_INF(lp) SMC_inl( lp, RX_FIFO_INF ) +#define SMC_SET_RX_FIFO_INF(lp, x) SMC_outl( x, lp, RX_FIFO_INF ) +#define SMC_GET_TX_FIFO_INF(lp) SMC_inl( lp, TX_FIFO_INF ) +#define SMC_SET_TX_FIFO_INF(lp, x) SMC_outl( x, lp, TX_FIFO_INF ) +#define SMC_GET_GPT_CFG(lp) SMC_inl( lp, GPT_CFG ) +#define SMC_SET_GPT_CFG(lp, x) SMC_outl( x, lp, GPT_CFG ) +#define SMC_GET_RX_DROP(lp) SMC_inl( lp, RX_DROP ) +#define SMC_SET_RX_DROP(lp, x) SMC_outl( x, lp, RX_DROP ) +#define SMC_GET_MAC_CMD(lp) SMC_inl( lp, MAC_CSR_CMD ) +#define SMC_SET_MAC_CMD(lp, x) SMC_outl( x, lp, MAC_CSR_CMD ) +#define SMC_GET_MAC_DATA(lp) SMC_inl( lp, MAC_CSR_DATA ) +#define SMC_SET_MAC_DATA(lp, x) SMC_outl( x, lp, MAC_CSR_DATA ) +#define SMC_GET_AFC_CFG(lp) SMC_inl( lp, AFC_CFG ) +#define SMC_SET_AFC_CFG(lp, x) SMC_outl( x, lp, AFC_CFG ) +#define SMC_GET_E2P_CMD(lp) SMC_inl( lp, E2P_CMD ) +#define SMC_SET_E2P_CMD(lp, x) SMC_outl( x, lp, E2P_CMD ) +#define SMC_GET_E2P_DATA(lp) SMC_inl( lp, E2P_DATA ) +#define SMC_SET_E2P_DATA(lp, x) SMC_outl( x, lp, E2P_DATA ) /* MAC register read/write macros */ -#define SMC_GET_MAC_CSR(a,v) \ +#define SMC_GET_MAC_CSR(lp,a,v) \ do { \ - while (SMC_GET_MAC_CMD() & MAC_CSR_CMD_CSR_BUSY_); \ - SMC_SET_MAC_CMD(MAC_CSR_CMD_CSR_BUSY_ | \ + while (SMC_GET_MAC_CMD((lp)) & MAC_CSR_CMD_CSR_BUSY_); \ + SMC_SET_MAC_CMD((lp),MAC_CSR_CMD_CSR_BUSY_ | \ MAC_CSR_CMD_R_NOT_W_ | (a) ); \ - while (SMC_GET_MAC_CMD() & MAC_CSR_CMD_CSR_BUSY_); \ - v = SMC_GET_MAC_DATA(); \ + while (SMC_GET_MAC_CMD((lp)) & MAC_CSR_CMD_CSR_BUSY_); \ + v = SMC_GET_MAC_DATA((lp)); \ } while (0) -#define SMC_SET_MAC_CSR(a,v) \ +#define SMC_SET_MAC_CSR(lp,a,v) \ do { \ - while (SMC_GET_MAC_CMD() & MAC_CSR_CMD_CSR_BUSY_); \ - SMC_SET_MAC_DATA(v); \ - SMC_SET_MAC_CMD(MAC_CSR_CMD_CSR_BUSY_ | (a) ); \ - while (SMC_GET_MAC_CMD() & MAC_CSR_CMD_CSR_BUSY_); \ + while (SMC_GET_MAC_CMD((lp)) & MAC_CSR_CMD_CSR_BUSY_); \ + SMC_SET_MAC_DATA((lp), v); \ + SMC_SET_MAC_CMD((lp), MAC_CSR_CMD_CSR_BUSY_ | (a) ); \ + while (SMC_GET_MAC_CMD((lp)) & MAC_CSR_CMD_CSR_BUSY_); \ } while (0) -#define SMC_GET_MAC_CR(x) SMC_GET_MAC_CSR( MAC_CR, x ) -#define SMC_SET_MAC_CR(x) SMC_SET_MAC_CSR( MAC_CR, x ) -#define SMC_GET_ADDRH(x) SMC_GET_MAC_CSR( ADDRH, x ) -#define SMC_SET_ADDRH(x) SMC_SET_MAC_CSR( ADDRH, x ) -#define SMC_GET_ADDRL(x) SMC_GET_MAC_CSR( ADDRL, x ) -#define SMC_SET_ADDRL(x) SMC_SET_MAC_CSR( ADDRL, x ) -#define SMC_GET_HASHH(x) SMC_GET_MAC_CSR( HASHH, x ) -#define SMC_SET_HASHH(x) SMC_SET_MAC_CSR( HASHH, x ) -#define SMC_GET_HASHL(x) SMC_GET_MAC_CSR( HASHL, x ) -#define SMC_SET_HASHL(x) SMC_SET_MAC_CSR( HASHL, x ) -#define SMC_GET_MII_ACC(x) SMC_GET_MAC_CSR( MII_ACC, x ) -#define SMC_SET_MII_ACC(x) SMC_SET_MAC_CSR( MII_ACC, x ) -#define SMC_GET_MII_DATA(x) SMC_GET_MAC_CSR( MII_DATA, x ) -#define SMC_SET_MII_DATA(x) SMC_SET_MAC_CSR( MII_DATA, x ) -#define SMC_GET_FLOW(x) SMC_GET_MAC_CSR( FLOW, x ) -#define SMC_SET_FLOW(x) SMC_SET_MAC_CSR( FLOW, x ) -#define SMC_GET_VLAN1(x) SMC_GET_MAC_CSR( VLAN1, x ) -#define SMC_SET_VLAN1(x) SMC_SET_MAC_CSR( VLAN1, x ) -#define SMC_GET_VLAN2(x) SMC_GET_MAC_CSR( VLAN2, x ) -#define SMC_SET_VLAN2(x) SMC_SET_MAC_CSR( VLAN2, x ) -#define SMC_SET_WUFF(x) SMC_SET_MAC_CSR( WUFF, x ) -#define SMC_GET_WUCSR(x) SMC_GET_MAC_CSR( WUCSR, x ) -#define SMC_SET_WUCSR(x) SMC_SET_MAC_CSR( WUCSR, x ) +#define SMC_GET_MAC_CR(lp, x) SMC_GET_MAC_CSR( (lp), MAC_CR, x ) +#define SMC_SET_MAC_CR(lp, x) SMC_SET_MAC_CSR( (lp), MAC_CR, x ) +#define SMC_GET_ADDRH(lp, x) SMC_GET_MAC_CSR( (lp), ADDRH, x ) +#define SMC_SET_ADDRH(lp, x) SMC_SET_MAC_CSR( (lp), ADDRH, x ) +#define SMC_GET_ADDRL(lp, x) SMC_GET_MAC_CSR( (lp), ADDRL, x ) +#define SMC_SET_ADDRL(lp, x) SMC_SET_MAC_CSR( (lp), ADDRL, x ) +#define SMC_GET_HASHH(lp, x) SMC_GET_MAC_CSR( (lp), HASHH, x ) +#define SMC_SET_HASHH(lp, x) SMC_SET_MAC_CSR( (lp), HASHH, x ) +#define SMC_GET_HASHL(lp, x) SMC_GET_MAC_CSR( (lp), HASHL, x ) +#define SMC_SET_HASHL(lp, x) SMC_SET_MAC_CSR( (lp), HASHL, x ) +#define SMC_GET_MII_ACC(lp, x) SMC_GET_MAC_CSR( (lp), MII_ACC, x ) +#define SMC_SET_MII_ACC(lp, x) SMC_SET_MAC_CSR( (lp), MII_ACC, x ) +#define SMC_GET_MII_DATA(lp, x) SMC_GET_MAC_CSR( (lp), MII_DATA, x ) +#define SMC_SET_MII_DATA(lp, x) SMC_SET_MAC_CSR( (lp), MII_DATA, x ) +#define SMC_GET_FLOW(lp, x) SMC_GET_MAC_CSR( (lp), FLOW, x ) +#define SMC_SET_FLOW(lp, x) SMC_SET_MAC_CSR( (lp), FLOW, x ) +#define SMC_GET_VLAN1(lp, x) SMC_GET_MAC_CSR( (lp), VLAN1, x ) +#define SMC_SET_VLAN1(lp, x) SMC_SET_MAC_CSR( (lp), VLAN1, x ) +#define SMC_GET_VLAN2(lp, x) SMC_GET_MAC_CSR( (lp), VLAN2, x ) +#define SMC_SET_VLAN2(lp, x) SMC_SET_MAC_CSR( (lp), VLAN2, x ) +#define SMC_SET_WUFF(lp, x) SMC_SET_MAC_CSR( (lp), WUFF, x ) +#define SMC_GET_WUCSR(lp, x) SMC_GET_MAC_CSR( (lp), WUCSR, x ) +#define SMC_SET_WUCSR(lp, x) SMC_SET_MAC_CSR( (lp), WUCSR, x ) /* PHY register read/write macros */ -#define SMC_GET_MII(a,phy,v) \ +#define SMC_GET_MII(lp,a,phy,v) \ do { \ u32 __v; \ do { \ - SMC_GET_MII_ACC(__v); \ + SMC_GET_MII_ACC((lp), __v); \ } while ( __v & MII_ACC_MII_BUSY_ ); \ - SMC_SET_MII_ACC( ((phy)<<11) | ((a)<<6) | \ + SMC_SET_MII_ACC( (lp), ((phy)<<11) | ((a)<<6) | \ MII_ACC_MII_BUSY_); \ do { \ - SMC_GET_MII_ACC(__v); \ + SMC_GET_MII_ACC( (lp), __v); \ } while ( __v & MII_ACC_MII_BUSY_ ); \ - SMC_GET_MII_DATA(v); \ + SMC_GET_MII_DATA((lp), v); \ } while (0) -#define SMC_SET_MII(a,phy,v) \ +#define SMC_SET_MII(lp,a,phy,v) \ do { \ u32 __v; \ do { \ - SMC_GET_MII_ACC(__v); \ + SMC_GET_MII_ACC((lp), __v); \ } while ( __v & MII_ACC_MII_BUSY_ ); \ - SMC_SET_MII_DATA(v); \ - SMC_SET_MII_ACC( ((phy)<<11) | ((a)<<6) | \ + SMC_SET_MII_DATA((lp), v); \ + SMC_SET_MII_ACC( (lp), ((phy)<<11) | ((a)<<6) | \ MII_ACC_MII_BUSY_ | \ MII_ACC_MII_WRITE_ ); \ do { \ - SMC_GET_MII_ACC(__v); \ + SMC_GET_MII_ACC((lp), __v); \ } while ( __v & MII_ACC_MII_BUSY_ ); \ } while (0) -#define SMC_GET_PHY_BMCR(phy,x) SMC_GET_MII( MII_BMCR, phy, x ) -#define SMC_SET_PHY_BMCR(phy,x) SMC_SET_MII( MII_BMCR, phy, x ) -#define SMC_GET_PHY_BMSR(phy,x) SMC_GET_MII( MII_BMSR, phy, x ) -#define SMC_GET_PHY_ID1(phy,x) SMC_GET_MII( MII_PHYSID1, phy, x ) -#define SMC_GET_PHY_ID2(phy,x) SMC_GET_MII( MII_PHYSID2, phy, x ) -#define SMC_GET_PHY_MII_ADV(phy,x) SMC_GET_MII( MII_ADVERTISE, phy, x ) -#define SMC_SET_PHY_MII_ADV(phy,x) SMC_SET_MII( MII_ADVERTISE, phy, x ) -#define SMC_GET_PHY_MII_LPA(phy,x) SMC_GET_MII( MII_LPA, phy, x ) -#define SMC_SET_PHY_MII_LPA(phy,x) SMC_SET_MII( MII_LPA, phy, x ) -#define SMC_GET_PHY_CTRL_STS(phy,x) SMC_GET_MII( PHY_MODE_CTRL_STS, phy, x ) -#define SMC_SET_PHY_CTRL_STS(phy,x) SMC_SET_MII( PHY_MODE_CTRL_STS, phy, x ) -#define SMC_GET_PHY_INT_SRC(phy,x) SMC_GET_MII( PHY_INT_SRC, phy, x ) -#define SMC_SET_PHY_INT_SRC(phy,x) SMC_SET_MII( PHY_INT_SRC, phy, x ) -#define SMC_GET_PHY_INT_MASK(phy,x) SMC_GET_MII( PHY_INT_MASK, phy, x ) -#define SMC_SET_PHY_INT_MASK(phy,x) SMC_SET_MII( PHY_INT_MASK, phy, x ) -#define SMC_GET_PHY_SPECIAL(phy,x) SMC_GET_MII( PHY_SPECIAL, phy, x ) +#define SMC_GET_PHY_BMCR(lp,phy,x) SMC_GET_MII( (lp), MII_BMCR, phy, x ) +#define SMC_SET_PHY_BMCR(lp,phy,x) SMC_SET_MII( (lp), MII_BMCR, phy, x ) +#define SMC_GET_PHY_BMSR(lp,phy,x) SMC_GET_MII( (lp), MII_BMSR, phy, x ) +#define SMC_GET_PHY_ID1(lp,phy,x) SMC_GET_MII( (lp), MII_PHYSID1, phy, x ) +#define SMC_GET_PHY_ID2(lp,phy,x) SMC_GET_MII( (lp), MII_PHYSID2, phy, x ) +#define SMC_GET_PHY_MII_ADV(lp,phy,x) SMC_GET_MII( (lp), MII_ADVERTISE, phy, x ) +#define SMC_SET_PHY_MII_ADV(lp,phy,x) SMC_SET_MII( (lp), MII_ADVERTISE, phy, x ) +#define SMC_GET_PHY_MII_LPA(lp,phy,x) SMC_GET_MII( (lp), MII_LPA, phy, x ) +#define SMC_SET_PHY_MII_LPA(lp,phy,x) SMC_SET_MII( (lp), MII_LPA, phy, x ) +#define SMC_GET_PHY_CTRL_STS(lp,phy,x) SMC_GET_MII( (lp), PHY_MODE_CTRL_STS, phy, x ) +#define SMC_SET_PHY_CTRL_STS(lp,phy,x) SMC_SET_MII( (lp), PHY_MODE_CTRL_STS, phy, x ) +#define SMC_GET_PHY_INT_SRC(lp,phy,x) SMC_GET_MII( (lp), PHY_INT_SRC, phy, x ) +#define SMC_SET_PHY_INT_SRC(lp,phy,x) SMC_SET_MII( (lp), PHY_INT_SRC, phy, x ) +#define SMC_GET_PHY_INT_MASK(lp,phy,x) SMC_GET_MII( (lp), PHY_INT_MASK, phy, x ) +#define SMC_SET_PHY_INT_MASK(lp,phy,x) SMC_SET_MII( (lp), PHY_INT_MASK, phy, x ) +#define SMC_GET_PHY_SPECIAL(lp,phy,x) SMC_GET_MII( (lp), PHY_SPECIAL, phy, x ) /* Misc read/write macros */ #ifndef SMC_GET_MAC_ADDR -#define SMC_GET_MAC_ADDR(addr) \ +#define SMC_GET_MAC_ADDR(lp, addr) \ do { \ unsigned int __v; \ \ - SMC_GET_MAC_CSR(ADDRL, __v); \ + SMC_GET_MAC_CSR((lp), ADDRL, __v); \ addr[0] = __v; addr[1] = __v >> 8; \ addr[2] = __v >> 16; addr[3] = __v >> 24; \ - SMC_GET_MAC_CSR(ADDRH, __v); \ + SMC_GET_MAC_CSR((lp), ADDRH, __v); \ addr[4] = __v; addr[5] = __v >> 8; \ } while (0) #endif -#define SMC_SET_MAC_ADDR(addr) \ +#define SMC_SET_MAC_ADDR(lp, addr) \ do { \ - SMC_SET_MAC_CSR(ADDRL, \ + SMC_SET_MAC_CSR((lp), ADDRL, \ addr[0] | \ (addr[1] << 8) | \ (addr[2] << 16) | \ (addr[3] << 24)); \ - SMC_SET_MAC_CSR(ADDRH, addr[4]|(addr[5] << 8));\ + SMC_SET_MAC_CSR((lp), ADDRH, addr[4]|(addr[5] << 8));\ } while (0) -#define SMC_WRITE_EEPROM_CMD(cmd, addr) \ +#define SMC_WRITE_EEPROM_CMD(lp, cmd, addr) \ do { \ - while (SMC_GET_E2P_CMD() & MAC_CSR_CMD_CSR_BUSY_); \ - SMC_SET_MAC_CMD(MAC_CSR_CMD_R_NOT_W_ | a ); \ - while (SMC_GET_MAC_CMD() & MAC_CSR_CMD_CSR_BUSY_); \ + while (SMC_GET_E2P_CMD((lp)) & MAC_CSR_CMD_CSR_BUSY_); \ + SMC_SET_MAC_CMD((lp), MAC_CSR_CMD_R_NOT_W_ | a ); \ + while (SMC_GET_MAC_CMD((lp)) & MAC_CSR_CMD_CSR_BUSY_); \ } while (0) #endif /* _SMC911X_H_ */ diff --git a/drivers/net/spider_net.c b/drivers/net/spider_net.c index 477671606273..00aa0b108cb9 100644 --- a/drivers/net/spider_net.c +++ b/drivers/net/spider_net.c @@ -1704,7 +1704,7 @@ spider_net_poll_controller(struct net_device *netdev) * * spider_net_enable_interrupt enables several interrupts */ -static void +static void spider_net_enable_interrupts(struct spider_net_card *card) { spider_net_write_reg(card, SPIDER_NET_GHIINT0MSK, @@ -1721,7 +1721,7 @@ spider_net_enable_interrupts(struct spider_net_card *card) * * spider_net_disable_interrupts disables all the interrupts */ -static void +static void spider_net_disable_interrupts(struct spider_net_card *card) { spider_net_write_reg(card, SPIDER_NET_GHIINT0MSK, 0); diff --git a/drivers/net/starfire.c b/drivers/net/starfire.c index 7b7b1717b0d1..1d2ef8f47780 100644 --- a/drivers/net/starfire.c +++ b/drivers/net/starfire.c @@ -27,8 +27,8 @@ */ #define DRV_NAME "starfire" -#define DRV_VERSION "2.0" -#define DRV_RELDATE "June 27, 2006" +#define DRV_VERSION "2.1" +#define DRV_RELDATE "July 6, 2008" #include <linux/module.h> #include <linux/kernel.h> @@ -69,10 +69,6 @@ #define VLAN_SUPPORT #endif -#ifndef CONFIG_ADAPTEC_STARFIRE_NAPI -#undef HAVE_NETDEV_POLL -#endif - /* The user-configurable values. These may be modified when a driver module is loaded.*/ @@ -177,44 +173,6 @@ static int full_duplex[MAX_UNITS] = {0, }; #define skb_first_frag_len(skb) skb_headlen(skb) #define skb_num_frags(skb) (skb_shinfo(skb)->nr_frags + 1) -#ifdef HAVE_NETDEV_POLL -#define init_poll(dev, np) \ - netif_napi_add(dev, &np->napi, netdev_poll, max_interrupt_work) -#define netdev_rx(dev, np, ioaddr) \ -do { \ - u32 intr_enable; \ - if (netif_rx_schedule_prep(dev, &np->napi)) { \ - __netif_rx_schedule(dev, &np->napi); \ - intr_enable = readl(ioaddr + IntrEnable); \ - intr_enable &= ~(IntrRxDone | IntrRxEmpty); \ - writel(intr_enable, ioaddr + IntrEnable); \ - readl(ioaddr + IntrEnable); /* flush PCI posting buffers */ \ - } else { \ - /* Paranoia check */ \ - intr_enable = readl(ioaddr + IntrEnable); \ - if (intr_enable & (IntrRxDone | IntrRxEmpty)) { \ - printk(KERN_INFO "%s: interrupt while in polling mode!\n", dev->name); \ - intr_enable &= ~(IntrRxDone | IntrRxEmpty); \ - writel(intr_enable, ioaddr + IntrEnable); \ - } \ - } \ -} while (0) -#define netdev_receive_skb(skb) netif_receive_skb(skb) -#define vlan_netdev_receive_skb(skb, vlgrp, vlid) vlan_hwaccel_receive_skb(skb, vlgrp, vlid) -static int netdev_poll(struct napi_struct *napi, int budget); -#else /* not HAVE_NETDEV_POLL */ -#define init_poll(dev, np) -#define netdev_receive_skb(skb) netif_rx(skb) -#define vlan_netdev_receive_skb(skb, vlgrp, vlid) vlan_hwaccel_rx(skb, vlgrp, vlid) -#define netdev_rx(dev, np, ioaddr) \ -do { \ - int quota = np->dirty_rx + RX_RING_SIZE - np->cur_rx; \ - __netdev_rx(dev, "a);\ -} while (0) -#endif /* not HAVE_NETDEV_POLL */ -/* end of compatibility code */ - - /* These identify the driver base version and may not be removed. */ static char version[] = KERN_INFO "starfire.c:v1.03 7/26/2000 Written by Donald Becker <becker@scyld.com>\n" @@ -635,6 +593,7 @@ static int start_tx(struct sk_buff *skb, struct net_device *dev); static irqreturn_t intr_handler(int irq, void *dev_instance); static void netdev_error(struct net_device *dev, int intr_status); static int __netdev_rx(struct net_device *dev, int *quota); +static int netdev_poll(struct napi_struct *napi, int budget); static void refill_rx_ring(struct net_device *dev); static void netdev_error(struct net_device *dev, int intr_status); static void set_rx_mode(struct net_device *dev); @@ -851,7 +810,7 @@ static int __devinit starfire_init_one(struct pci_dev *pdev, dev->hard_start_xmit = &start_tx; dev->tx_timeout = tx_timeout; dev->watchdog_timeo = TX_TIMEOUT; - init_poll(dev, np); + netif_napi_add(dev, &np->napi, netdev_poll, max_interrupt_work); dev->stop = &netdev_close; dev->get_stats = &get_stats; dev->set_multicast_list = &set_rx_mode; @@ -1054,9 +1013,8 @@ static int netdev_open(struct net_device *dev) writel(np->intr_timer_ctrl, ioaddr + IntrTimerCtrl); -#ifdef HAVE_NETDEV_POLL napi_enable(&np->napi); -#endif + netif_start_queue(dev); if (debug > 1) @@ -1330,8 +1288,28 @@ static irqreturn_t intr_handler(int irq, void *dev_instance) handled = 1; - if (intr_status & (IntrRxDone | IntrRxEmpty)) - netdev_rx(dev, np, ioaddr); + if (intr_status & (IntrRxDone | IntrRxEmpty)) { + u32 enable; + + if (likely(netif_rx_schedule_prep(dev, &np->napi))) { + __netif_rx_schedule(dev, &np->napi); + enable = readl(ioaddr + IntrEnable); + enable &= ~(IntrRxDone | IntrRxEmpty); + writel(enable, ioaddr + IntrEnable); + /* flush PCI posting buffers */ + readl(ioaddr + IntrEnable); + } else { + /* Paranoia check */ + enable = readl(ioaddr + IntrEnable); + if (enable & (IntrRxDone | IntrRxEmpty)) { + printk(KERN_INFO + "%s: interrupt while in poll!\n", + dev->name); + enable &= ~(IntrRxDone | IntrRxEmpty); + writel(enable, ioaddr + IntrEnable); + } + } + } /* Scavenge the skbuff list based on the Tx-done queue. There are redundant checks here that may be cleaned up @@ -1411,8 +1389,10 @@ static irqreturn_t intr_handler(int irq, void *dev_instance) } -/* This routine is logically part of the interrupt/poll handler, but separated - for clarity, code sharing between NAPI/non-NAPI, and better register allocation. */ +/* + * This routine is logically part of the interrupt/poll handler, but separated + * for clarity and better register allocation. + */ static int __netdev_rx(struct net_device *dev, int *quota) { struct netdev_private *np = netdev_priv(dev); @@ -1507,13 +1487,20 @@ static int __netdev_rx(struct net_device *dev, int *quota) } #ifdef VLAN_SUPPORT if (np->vlgrp && le16_to_cpu(desc->status2) & 0x0200) { - if (debug > 4) - printk(KERN_DEBUG " netdev_rx() vlanid = %d\n", le16_to_cpu(desc->vlanid)); - /* vlan_netdev_receive_skb() expects a packet with the VLAN tag stripped out */ - vlan_netdev_receive_skb(skb, np->vlgrp, le16_to_cpu(desc->vlanid) & VLAN_VID_MASK); + u16 vlid = le16_to_cpu(desc->vlanid); + + if (debug > 4) { + printk(KERN_DEBUG " netdev_rx() vlanid = %d\n", + vlid); + } + /* + * vlan_hwaccel_rx expects a packet with the VLAN tag + * stripped out. + */ + vlan_hwaccel_rx(skb, np->vlgrp, vlid); } else #endif /* VLAN_SUPPORT */ - netdev_receive_skb(skb); + netif_receive_skb(skb); dev->last_rx = jiffies; np->stats.rx_packets++; @@ -1532,8 +1519,6 @@ static int __netdev_rx(struct net_device *dev, int *quota) return retcode; } - -#ifdef HAVE_NETDEV_POLL static int netdev_poll(struct napi_struct *napi, int budget) { struct netdev_private *np = container_of(napi, struct netdev_private, napi); @@ -1564,8 +1549,6 @@ static int netdev_poll(struct napi_struct *napi, int budget) /* Restart Rx engine if stopped. */ return budget - quota; } -#endif /* HAVE_NETDEV_POLL */ - static void refill_rx_ring(struct net_device *dev) { @@ -1906,9 +1889,8 @@ static int netdev_close(struct net_device *dev) int i; netif_stop_queue(dev); -#ifdef HAVE_NETDEV_POLL + napi_disable(&np->napi); -#endif if (debug > 1) { printk(KERN_DEBUG "%s: Shutting down ethercard, Intr status %#8.8x.\n", @@ -2044,11 +2026,8 @@ static int __init starfire_init (void) /* when a module, this is printed whether or not devices are found in probe */ #ifdef MODULE printk(version); -#ifdef HAVE_NETDEV_POLL + printk(KERN_INFO DRV_NAME ": polling (NAPI) enabled\n"); -#else - printk(KERN_INFO DRV_NAME ": polling (NAPI) disabled\n"); -#endif #endif /* we can do this test only at run-time... sigh */ diff --git a/drivers/net/sunlance.c b/drivers/net/sunlance.c index 26ade68aeabf..4e994f87469e 100644 --- a/drivers/net/sunlance.c +++ b/drivers/net/sunlance.c @@ -915,15 +915,11 @@ static void build_fake_packet(struct lance_private *lp) lp->tx_new = TX_NEXT(entry); } -struct net_device *last_dev; - static int lance_open(struct net_device *dev) { struct lance_private *lp = netdev_priv(dev); int status = 0; - last_dev = dev; - STOP_LANCE(lp); if (request_irq(dev->irq, &lance_interrupt, IRQF_SHARED, diff --git a/drivers/net/tc35815.c b/drivers/net/tc35815.c index b07b8cbadeaf..41d3ac45685f 100644 --- a/drivers/net/tc35815.c +++ b/drivers/net/tc35815.c @@ -672,7 +672,7 @@ static void tc_handle_link_change(struct net_device *dev) if (dev->flags & IFF_PROMISC) tc35815_set_multicast_list(dev); #endif - netif_schedule(dev); + netif_tx_schedule_all(dev); } else { lp->speed = 0; lp->duplex = -1; diff --git a/drivers/net/tehuti.c b/drivers/net/tehuti.c index 432e837a1760..91f9054a1d95 100644 --- a/drivers/net/tehuti.c +++ b/drivers/net/tehuti.c @@ -1165,7 +1165,7 @@ NETIF_RX_MUX(struct bdx_priv *priv, u32 rxd_val1, u16 rxd_vlan, GET_RXD_VLAN_ID(rxd_vlan))->name); /* NAPI variant of receive functions */ vlan_hwaccel_receive_skb(skb, priv->vlgrp, - GET_RXD_VLAN_ID(rxd_vlan)); + GET_RXD_VLAN_TCI(rxd_vlan)); } else { netif_receive_skb(skb); } diff --git a/drivers/net/tehuti.h b/drivers/net/tehuti.h index efd170f451b4..c66dfc9ec1ec 100644 --- a/drivers/net/tehuti.h +++ b/drivers/net/tehuti.h @@ -309,6 +309,7 @@ struct rxf_desc { #define GET_RXD_PKT_ID(x) GET_BITS_SHIFT((x), 3, 28) #define GET_RXD_VTAG(x) GET_BITS_SHIFT((x), 1, 31) #define GET_RXD_VLAN_ID(x) GET_BITS_SHIFT((x), 12, 0) +#define GET_RXD_VLAN_TCI(x) GET_BITS_SHIFT((x), 16, 0) #define GET_RXD_CFI(x) GET_BITS_SHIFT((x), 1, 12) #define GET_RXD_PRIO(x) GET_BITS_SHIFT((x), 3, 13) diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index cc4bde852542..633c128a6228 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -32,6 +32,8 @@ #include <linux/skbuff.h> #include <linux/ethtool.h> #include <linux/mii.h> +#include <linux/phy.h> +#include <linux/brcmphy.h> #include <linux/if_vlan.h> #include <linux/ip.h> #include <linux/tcp.h> @@ -64,8 +66,8 @@ #define DRV_MODULE_NAME "tg3" #define PFX DRV_MODULE_NAME ": " -#define DRV_MODULE_VERSION "3.92.1" -#define DRV_MODULE_RELDATE "June 9, 2008" +#define DRV_MODULE_VERSION "3.93" +#define DRV_MODULE_RELDATE "May 22, 2008" #define TG3_DEF_MAC_MODE 0 #define TG3_DEF_RX_MODE 0 @@ -203,6 +205,7 @@ static struct pci_device_id tg3_pci_tbl[] = { {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5723)}, {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5761)}, {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5761E)}, + {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5785)}, {PCI_DEVICE(PCI_VENDOR_ID_SYSKONNECT, PCI_DEVICE_ID_SYSKONNECT_9DXX)}, {PCI_DEVICE(PCI_VENDOR_ID_SYSKONNECT, PCI_DEVICE_ID_SYSKONNECT_9MXX)}, {PCI_DEVICE(PCI_VENDOR_ID_ALTIMA, PCI_DEVICE_ID_ALTIMA_AC1000)}, @@ -804,6 +807,569 @@ static int tg3_writephy(struct tg3 *tp, int reg, u32 val) return ret; } +static int tg3_bmcr_reset(struct tg3 *tp) +{ + u32 phy_control; + int limit, err; + + /* OK, reset it, and poll the BMCR_RESET bit until it + * clears or we time out. + */ + phy_control = BMCR_RESET; + err = tg3_writephy(tp, MII_BMCR, phy_control); + if (err != 0) + return -EBUSY; + + limit = 5000; + while (limit--) { + err = tg3_readphy(tp, MII_BMCR, &phy_control); + if (err != 0) + return -EBUSY; + + if ((phy_control & BMCR_RESET) == 0) { + udelay(40); + break; + } + udelay(10); + } + if (limit <= 0) + return -EBUSY; + + return 0; +} + +static int tg3_mdio_read(struct mii_bus *bp, int mii_id, int reg) +{ + struct tg3 *tp = (struct tg3 *)bp->priv; + u32 val; + + if (tp->tg3_flags3 & TG3_FLG3_MDIOBUS_PAUSED) + return -EAGAIN; + + if (tg3_readphy(tp, reg, &val)) + return -EIO; + + return val; +} + +static int tg3_mdio_write(struct mii_bus *bp, int mii_id, int reg, u16 val) +{ + struct tg3 *tp = (struct tg3 *)bp->priv; + + if (tp->tg3_flags3 & TG3_FLG3_MDIOBUS_PAUSED) + return -EAGAIN; + + if (tg3_writephy(tp, reg, val)) + return -EIO; + + return 0; +} + +static int tg3_mdio_reset(struct mii_bus *bp) +{ + return 0; +} + +static void tg3_mdio_config(struct tg3 *tp) +{ + u32 val; + + if (tp->mdio_bus.phy_map[PHY_ADDR]->interface != + PHY_INTERFACE_MODE_RGMII) + return; + + val = tr32(MAC_PHYCFG1) & ~(MAC_PHYCFG1_RGMII_EXT_RX_DEC | + MAC_PHYCFG1_RGMII_SND_STAT_EN); + if (tp->tg3_flags3 & TG3_FLG3_RGMII_STD_IBND_DISABLE) { + if (tp->tg3_flags3 & TG3_FLG3_RGMII_EXT_IBND_RX_EN) + val |= MAC_PHYCFG1_RGMII_EXT_RX_DEC; + if (tp->tg3_flags3 & TG3_FLG3_RGMII_EXT_IBND_TX_EN) + val |= MAC_PHYCFG1_RGMII_SND_STAT_EN; + } + tw32(MAC_PHYCFG1, val | MAC_PHYCFG1_RGMII_INT | MAC_PHYCFG1_TXC_DRV); + + val = tr32(MAC_PHYCFG2) & ~(MAC_PHYCFG2_INBAND_ENABLE); + if (!(tp->tg3_flags3 & TG3_FLG3_RGMII_STD_IBND_DISABLE)) + val |= MAC_PHYCFG2_INBAND_ENABLE; + tw32(MAC_PHYCFG2, val); + + val = tr32(MAC_EXT_RGMII_MODE); + val &= ~(MAC_RGMII_MODE_RX_INT_B | + MAC_RGMII_MODE_RX_QUALITY | + MAC_RGMII_MODE_RX_ACTIVITY | + MAC_RGMII_MODE_RX_ENG_DET | + MAC_RGMII_MODE_TX_ENABLE | + MAC_RGMII_MODE_TX_LOWPWR | + MAC_RGMII_MODE_TX_RESET); + if (tp->tg3_flags3 & TG3_FLG3_RGMII_STD_IBND_DISABLE) { + if (tp->tg3_flags3 & TG3_FLG3_RGMII_EXT_IBND_RX_EN) + val |= MAC_RGMII_MODE_RX_INT_B | + MAC_RGMII_MODE_RX_QUALITY | + MAC_RGMII_MODE_RX_ACTIVITY | + MAC_RGMII_MODE_RX_ENG_DET; + if (tp->tg3_flags3 & TG3_FLG3_RGMII_EXT_IBND_TX_EN) + val |= MAC_RGMII_MODE_TX_ENABLE | + MAC_RGMII_MODE_TX_LOWPWR | + MAC_RGMII_MODE_TX_RESET; + } + tw32(MAC_EXT_RGMII_MODE, val); +} + +static void tg3_mdio_start(struct tg3 *tp) +{ + if (tp->tg3_flags3 & TG3_FLG3_MDIOBUS_INITED) { + mutex_lock(&tp->mdio_bus.mdio_lock); + tp->tg3_flags3 &= ~TG3_FLG3_MDIOBUS_PAUSED; + mutex_unlock(&tp->mdio_bus.mdio_lock); + } + + tp->mi_mode &= ~MAC_MI_MODE_AUTO_POLL; + tw32_f(MAC_MI_MODE, tp->mi_mode); + udelay(80); + + if (tp->tg3_flags3 & TG3_FLG3_MDIOBUS_INITED) + tg3_mdio_config(tp); +} + +static void tg3_mdio_stop(struct tg3 *tp) +{ + if (tp->tg3_flags3 & TG3_FLG3_MDIOBUS_INITED) { + mutex_lock(&tp->mdio_bus.mdio_lock); + tp->tg3_flags3 |= TG3_FLG3_MDIOBUS_PAUSED; + mutex_unlock(&tp->mdio_bus.mdio_lock); + } +} + +static int tg3_mdio_init(struct tg3 *tp) +{ + int i; + u32 reg; + struct phy_device *phydev; + struct mii_bus *mdio_bus = &tp->mdio_bus; + + tg3_mdio_start(tp); + + if (!(tp->tg3_flags3 & TG3_FLG3_USE_PHYLIB) || + (tp->tg3_flags3 & TG3_FLG3_MDIOBUS_INITED)) + return 0; + + memset(mdio_bus, 0, sizeof(*mdio_bus)); + + mdio_bus->name = "tg3 mdio bus"; + snprintf(mdio_bus->id, MII_BUS_ID_SIZE, "%x", + (tp->pdev->bus->number << 8) | tp->pdev->devfn); + mdio_bus->priv = tp; + mdio_bus->dev = &tp->pdev->dev; + mdio_bus->read = &tg3_mdio_read; + mdio_bus->write = &tg3_mdio_write; + mdio_bus->reset = &tg3_mdio_reset; + mdio_bus->phy_mask = ~(1 << PHY_ADDR); + mdio_bus->irq = &tp->mdio_irq[0]; + + for (i = 0; i < PHY_MAX_ADDR; i++) + mdio_bus->irq[i] = PHY_POLL; + + /* The bus registration will look for all the PHYs on the mdio bus. + * Unfortunately, it does not ensure the PHY is powered up before + * accessing the PHY ID registers. A chip reset is the + * quickest way to bring the device back to an operational state.. + */ + if (tg3_readphy(tp, MII_BMCR, ®) || (reg & BMCR_PDOWN)) + tg3_bmcr_reset(tp); + + i = mdiobus_register(mdio_bus); + if (i) { + printk(KERN_WARNING "%s: mdiobus_reg failed (0x%x)\n", + tp->dev->name, i); + return i; + } + + tp->tg3_flags3 |= TG3_FLG3_MDIOBUS_INITED; + + phydev = tp->mdio_bus.phy_map[PHY_ADDR]; + + switch (phydev->phy_id) { + case TG3_PHY_ID_BCM50610: + phydev->interface = PHY_INTERFACE_MODE_RGMII; + if (tp->tg3_flags3 & TG3_FLG3_RGMII_STD_IBND_DISABLE) + phydev->dev_flags |= PHY_BRCM_STD_IBND_DISABLE; + if (tp->tg3_flags3 & TG3_FLG3_RGMII_EXT_IBND_RX_EN) + phydev->dev_flags |= PHY_BRCM_EXT_IBND_RX_ENABLE; + if (tp->tg3_flags3 & TG3_FLG3_RGMII_EXT_IBND_TX_EN) + phydev->dev_flags |= PHY_BRCM_EXT_IBND_TX_ENABLE; + break; + case TG3_PHY_ID_BCMAC131: + phydev->interface = PHY_INTERFACE_MODE_MII; + break; + } + + tg3_mdio_config(tp); + + return 0; +} + +static void tg3_mdio_fini(struct tg3 *tp) +{ + if (tp->tg3_flags3 & TG3_FLG3_MDIOBUS_INITED) { + tp->tg3_flags3 &= ~TG3_FLG3_MDIOBUS_INITED; + mdiobus_unregister(&tp->mdio_bus); + tp->tg3_flags3 &= ~TG3_FLG3_MDIOBUS_PAUSED; + } +} + +/* tp->lock is held. */ +static void tg3_wait_for_event_ack(struct tg3 *tp) +{ + int i; + + /* Wait for up to 2.5 milliseconds */ + for (i = 0; i < 250000; i++) { + if (!(tr32(GRC_RX_CPU_EVENT) & GRC_RX_CPU_DRIVER_EVENT)) + break; + udelay(10); + } +} + +/* tp->lock is held. */ +static void tg3_ump_link_report(struct tg3 *tp) +{ + u32 reg; + u32 val; + + if (!(tp->tg3_flags2 & TG3_FLG2_5780_CLASS) || + !(tp->tg3_flags & TG3_FLAG_ENABLE_ASF)) + return; + + tg3_wait_for_event_ack(tp); + + tg3_write_mem(tp, NIC_SRAM_FW_CMD_MBOX, FWCMD_NICDRV_LINK_UPDATE); + + tg3_write_mem(tp, NIC_SRAM_FW_CMD_LEN_MBOX, 14); + + val = 0; + if (!tg3_readphy(tp, MII_BMCR, ®)) + val = reg << 16; + if (!tg3_readphy(tp, MII_BMSR, ®)) + val |= (reg & 0xffff); + tg3_write_mem(tp, NIC_SRAM_FW_CMD_DATA_MBOX, val); + + val = 0; + if (!tg3_readphy(tp, MII_ADVERTISE, ®)) + val = reg << 16; + if (!tg3_readphy(tp, MII_LPA, ®)) + val |= (reg & 0xffff); + tg3_write_mem(tp, NIC_SRAM_FW_CMD_DATA_MBOX + 4, val); + + val = 0; + if (!(tp->tg3_flags2 & TG3_FLG2_MII_SERDES)) { + if (!tg3_readphy(tp, MII_CTRL1000, ®)) + val = reg << 16; + if (!tg3_readphy(tp, MII_STAT1000, ®)) + val |= (reg & 0xffff); + } + tg3_write_mem(tp, NIC_SRAM_FW_CMD_DATA_MBOX + 8, val); + + if (!tg3_readphy(tp, MII_PHYADDR, ®)) + val = reg << 16; + else + val = 0; + tg3_write_mem(tp, NIC_SRAM_FW_CMD_DATA_MBOX + 12, val); + + val = tr32(GRC_RX_CPU_EVENT); + val |= GRC_RX_CPU_DRIVER_EVENT; + tw32_f(GRC_RX_CPU_EVENT, val); +} + +static void tg3_link_report(struct tg3 *tp) +{ + if (!netif_carrier_ok(tp->dev)) { + if (netif_msg_link(tp)) + printk(KERN_INFO PFX "%s: Link is down.\n", + tp->dev->name); + tg3_ump_link_report(tp); + } else if (netif_msg_link(tp)) { + printk(KERN_INFO PFX "%s: Link is up at %d Mbps, %s duplex.\n", + tp->dev->name, + (tp->link_config.active_speed == SPEED_1000 ? + 1000 : + (tp->link_config.active_speed == SPEED_100 ? + 100 : 10)), + (tp->link_config.active_duplex == DUPLEX_FULL ? + "full" : "half")); + + printk(KERN_INFO PFX + "%s: Flow control is %s for TX and %s for RX.\n", + tp->dev->name, + (tp->link_config.active_flowctrl & TG3_FLOW_CTRL_TX) ? + "on" : "off", + (tp->link_config.active_flowctrl & TG3_FLOW_CTRL_RX) ? + "on" : "off"); + tg3_ump_link_report(tp); + } +} + +static u16 tg3_advert_flowctrl_1000T(u8 flow_ctrl) +{ + u16 miireg; + + if ((flow_ctrl & TG3_FLOW_CTRL_TX) && (flow_ctrl & TG3_FLOW_CTRL_RX)) + miireg = ADVERTISE_PAUSE_CAP; + else if (flow_ctrl & TG3_FLOW_CTRL_TX) + miireg = ADVERTISE_PAUSE_ASYM; + else if (flow_ctrl & TG3_FLOW_CTRL_RX) + miireg = ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM; + else + miireg = 0; + + return miireg; +} + +static u16 tg3_advert_flowctrl_1000X(u8 flow_ctrl) +{ + u16 miireg; + + if ((flow_ctrl & TG3_FLOW_CTRL_TX) && (flow_ctrl & TG3_FLOW_CTRL_RX)) + miireg = ADVERTISE_1000XPAUSE; + else if (flow_ctrl & TG3_FLOW_CTRL_TX) + miireg = ADVERTISE_1000XPSE_ASYM; + else if (flow_ctrl & TG3_FLOW_CTRL_RX) + miireg = ADVERTISE_1000XPAUSE | ADVERTISE_1000XPSE_ASYM; + else + miireg = 0; + + return miireg; +} + +static u8 tg3_resolve_flowctrl_1000T(u16 lcladv, u16 rmtadv) +{ + u8 cap = 0; + + if (lcladv & ADVERTISE_PAUSE_CAP) { + if (lcladv & ADVERTISE_PAUSE_ASYM) { + if (rmtadv & LPA_PAUSE_CAP) + cap = TG3_FLOW_CTRL_TX | TG3_FLOW_CTRL_RX; + else if (rmtadv & LPA_PAUSE_ASYM) + cap = TG3_FLOW_CTRL_RX; + } else { + if (rmtadv & LPA_PAUSE_CAP) + cap = TG3_FLOW_CTRL_TX | TG3_FLOW_CTRL_RX; + } + } else if (lcladv & ADVERTISE_PAUSE_ASYM) { + if ((rmtadv & LPA_PAUSE_CAP) && (rmtadv & LPA_PAUSE_ASYM)) + cap = TG3_FLOW_CTRL_TX; + } + + return cap; +} + +static u8 tg3_resolve_flowctrl_1000X(u16 lcladv, u16 rmtadv) +{ + u8 cap = 0; + + if (lcladv & ADVERTISE_1000XPAUSE) { + if (lcladv & ADVERTISE_1000XPSE_ASYM) { + if (rmtadv & LPA_1000XPAUSE) + cap = TG3_FLOW_CTRL_TX | TG3_FLOW_CTRL_RX; + else if (rmtadv & LPA_1000XPAUSE_ASYM) + cap = TG3_FLOW_CTRL_RX; + } else { + if (rmtadv & LPA_1000XPAUSE) + cap = TG3_FLOW_CTRL_TX | TG3_FLOW_CTRL_RX; + } + } else if (lcladv & ADVERTISE_1000XPSE_ASYM) { + if ((rmtadv & LPA_1000XPAUSE) && (rmtadv & LPA_1000XPAUSE_ASYM)) + cap = TG3_FLOW_CTRL_TX; + } + + return cap; +} + +static void tg3_setup_flow_control(struct tg3 *tp, u32 lcladv, u32 rmtadv) +{ + u8 autoneg; + u8 flowctrl = 0; + u32 old_rx_mode = tp->rx_mode; + u32 old_tx_mode = tp->tx_mode; + + if (tp->tg3_flags3 & TG3_FLG3_USE_PHYLIB) + autoneg = tp->mdio_bus.phy_map[PHY_ADDR]->autoneg; + else + autoneg = tp->link_config.autoneg; + + if (autoneg == AUTONEG_ENABLE && + (tp->tg3_flags & TG3_FLAG_PAUSE_AUTONEG)) { + if (tp->tg3_flags2 & TG3_FLG2_ANY_SERDES) + flowctrl = tg3_resolve_flowctrl_1000X(lcladv, rmtadv); + else + flowctrl = tg3_resolve_flowctrl_1000T(lcladv, rmtadv); + } else + flowctrl = tp->link_config.flowctrl; + + tp->link_config.active_flowctrl = flowctrl; + + if (flowctrl & TG3_FLOW_CTRL_RX) + tp->rx_mode |= RX_MODE_FLOW_CTRL_ENABLE; + else + tp->rx_mode &= ~RX_MODE_FLOW_CTRL_ENABLE; + + if (old_rx_mode != tp->rx_mode) + tw32_f(MAC_RX_MODE, tp->rx_mode); + + if (flowctrl & TG3_FLOW_CTRL_TX) + tp->tx_mode |= TX_MODE_FLOW_CTRL_ENABLE; + else + tp->tx_mode &= ~TX_MODE_FLOW_CTRL_ENABLE; + + if (old_tx_mode != tp->tx_mode) + tw32_f(MAC_TX_MODE, tp->tx_mode); +} + +static void tg3_adjust_link(struct net_device *dev) +{ + u8 oldflowctrl, linkmesg = 0; + u32 mac_mode, lcl_adv, rmt_adv; + struct tg3 *tp = netdev_priv(dev); + struct phy_device *phydev = tp->mdio_bus.phy_map[PHY_ADDR]; + + spin_lock(&tp->lock); + + mac_mode = tp->mac_mode & ~(MAC_MODE_PORT_MODE_MASK | + MAC_MODE_HALF_DUPLEX); + + oldflowctrl = tp->link_config.active_flowctrl; + + if (phydev->link) { + lcl_adv = 0; + rmt_adv = 0; + + if (phydev->speed == SPEED_100 || phydev->speed == SPEED_10) + mac_mode |= MAC_MODE_PORT_MODE_MII; + else + mac_mode |= MAC_MODE_PORT_MODE_GMII; + + if (phydev->duplex == DUPLEX_HALF) + mac_mode |= MAC_MODE_HALF_DUPLEX; + else { + lcl_adv = tg3_advert_flowctrl_1000T( + tp->link_config.flowctrl); + + if (phydev->pause) + rmt_adv = LPA_PAUSE_CAP; + if (phydev->asym_pause) + rmt_adv |= LPA_PAUSE_ASYM; + } + + tg3_setup_flow_control(tp, lcl_adv, rmt_adv); + } else + mac_mode |= MAC_MODE_PORT_MODE_GMII; + + if (mac_mode != tp->mac_mode) { + tp->mac_mode = mac_mode; + tw32_f(MAC_MODE, tp->mac_mode); + udelay(40); + } + + if (phydev->speed == SPEED_1000 && phydev->duplex == DUPLEX_HALF) + tw32(MAC_TX_LENGTHS, + ((2 << TX_LENGTHS_IPG_CRS_SHIFT) | + (6 << TX_LENGTHS_IPG_SHIFT) | + (0xff << TX_LENGTHS_SLOT_TIME_SHIFT))); + else + tw32(MAC_TX_LENGTHS, + ((2 << TX_LENGTHS_IPG_CRS_SHIFT) | + (6 << TX_LENGTHS_IPG_SHIFT) | + (32 << TX_LENGTHS_SLOT_TIME_SHIFT))); + + if ((phydev->link && tp->link_config.active_speed == SPEED_INVALID) || + (!phydev->link && tp->link_config.active_speed != SPEED_INVALID) || + phydev->speed != tp->link_config.active_speed || + phydev->duplex != tp->link_config.active_duplex || + oldflowctrl != tp->link_config.active_flowctrl) + linkmesg = 1; + + tp->link_config.active_speed = phydev->speed; + tp->link_config.active_duplex = phydev->duplex; + + spin_unlock(&tp->lock); + + if (linkmesg) + tg3_link_report(tp); +} + +static int tg3_phy_init(struct tg3 *tp) +{ + struct phy_device *phydev; + + if (tp->tg3_flags3 & TG3_FLG3_PHY_CONNECTED) + return 0; + + /* Bring the PHY back to a known state. */ + tg3_bmcr_reset(tp); + + phydev = tp->mdio_bus.phy_map[PHY_ADDR]; + + /* Attach the MAC to the PHY. */ + phydev = phy_connect(tp->dev, phydev->dev.bus_id, tg3_adjust_link, + phydev->dev_flags, phydev->interface); + if (IS_ERR(phydev)) { + printk(KERN_ERR "%s: Could not attach to PHY\n", tp->dev->name); + return PTR_ERR(phydev); + } + + tp->tg3_flags3 |= TG3_FLG3_PHY_CONNECTED; + + /* Mask with MAC supported features. */ + phydev->supported &= (PHY_GBIT_FEATURES | + SUPPORTED_Pause | + SUPPORTED_Asym_Pause); + + phydev->advertising = phydev->supported; + + printk(KERN_INFO + "%s: attached PHY driver [%s] (mii_bus:phy_addr=%s)\n", + tp->dev->name, phydev->drv->name, phydev->dev.bus_id); + + return 0; +} + +static void tg3_phy_start(struct tg3 *tp) +{ + struct phy_device *phydev; + + if (!(tp->tg3_flags3 & TG3_FLG3_PHY_CONNECTED)) + return; + + phydev = tp->mdio_bus.phy_map[PHY_ADDR]; + + if (tp->link_config.phy_is_low_power) { + tp->link_config.phy_is_low_power = 0; + phydev->speed = tp->link_config.orig_speed; + phydev->duplex = tp->link_config.orig_duplex; + phydev->autoneg = tp->link_config.orig_autoneg; + phydev->advertising = tp->link_config.orig_advertising; + } + + phy_start(phydev); + + phy_start_aneg(phydev); +} + +static void tg3_phy_stop(struct tg3 *tp) +{ + if (!(tp->tg3_flags3 & TG3_FLG3_PHY_CONNECTED)) + return; + + phy_stop(tp->mdio_bus.phy_map[PHY_ADDR]); +} + +static void tg3_phy_fini(struct tg3 *tp) +{ + if (tp->tg3_flags3 & TG3_FLG3_PHY_CONNECTED) { + phy_disconnect(tp->mdio_bus.phy_map[PHY_ADDR]); + tp->tg3_flags3 &= ~TG3_FLG3_PHY_CONNECTED; + } +} + static void tg3_phydsp_write(struct tg3 *tp, u32 reg, u32 val) { tg3_writephy(tp, MII_TG3_DSP_ADDRESS, reg); @@ -861,37 +1427,6 @@ static void tg3_phy_set_wirespeed(struct tg3 *tp) (val | (1 << 15) | (1 << 4))); } -static int tg3_bmcr_reset(struct tg3 *tp) -{ - u32 phy_control; - int limit, err; - - /* OK, reset it, and poll the BMCR_RESET bit until it - * clears or we time out. - */ - phy_control = BMCR_RESET; - err = tg3_writephy(tp, MII_BMCR, phy_control); - if (err != 0) - return -EBUSY; - - limit = 5000; - while (limit--) { - err = tg3_readphy(tp, MII_BMCR, &phy_control); - if (err != 0) - return -EBUSY; - - if ((phy_control & BMCR_RESET) == 0) { - udelay(40); - break; - } - udelay(10); - } - if (limit <= 0) - return -EBUSY; - - return 0; -} - static void tg3_phy_apply_otp(struct tg3 *tp) { u32 otp, phy; @@ -1115,8 +1650,6 @@ static int tg3_phy_reset_5703_4_5(struct tg3 *tp) return err; } -static void tg3_link_report(struct tg3 *); - /* This will reset the tigon3 PHY if there is no valid * link unless the FORCE argument is non-zero. */ @@ -1421,7 +1954,7 @@ static void tg3_power_down_phy(struct tg3 *tp) tw32_f(GRC_MISC_CFG, val | GRC_MISC_CFG_EPHY_IDDQ); udelay(40); return; - } else { + } else if (!(tp->tg3_flags3 & TG3_FLG3_USE_PHYLIB)) { tg3_writephy(tp, MII_TG3_EXT_CTRL, MII_TG3_EXT_CTRL_FORCE_LED_OFF); tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x01b2); @@ -1495,7 +2028,7 @@ static int tg3_set_power_state(struct tg3 *tp, pci_power_t state) "requested.\n", tp->dev->name, state); return -EINVAL; - }; + } power_control |= PCI_PM_CTRL_PME_ENABLE; @@ -1503,18 +2036,55 @@ static int tg3_set_power_state(struct tg3 *tp, pci_power_t state) tw32(TG3PCI_MISC_HOST_CTRL, misc_host_ctrl | MISC_HOST_CTRL_MASK_PCI_INT); - if (tp->link_config.phy_is_low_power == 0) { - tp->link_config.phy_is_low_power = 1; - tp->link_config.orig_speed = tp->link_config.speed; - tp->link_config.orig_duplex = tp->link_config.duplex; - tp->link_config.orig_autoneg = tp->link_config.autoneg; - } + if (tp->tg3_flags3 & TG3_FLG3_USE_PHYLIB) { + if ((tp->tg3_flags3 & TG3_FLG3_PHY_CONNECTED) && + !tp->link_config.phy_is_low_power) { + struct phy_device *phydev; + u32 advertising; + + phydev = tp->mdio_bus.phy_map[PHY_ADDR]; + + tp->link_config.phy_is_low_power = 1; + + tp->link_config.orig_speed = phydev->speed; + tp->link_config.orig_duplex = phydev->duplex; + tp->link_config.orig_autoneg = phydev->autoneg; + tp->link_config.orig_advertising = phydev->advertising; + + advertising = ADVERTISED_TP | + ADVERTISED_Pause | + ADVERTISED_Autoneg | + ADVERTISED_10baseT_Half; + + if ((tp->tg3_flags & TG3_FLAG_ENABLE_ASF) || + (tp->tg3_flags & TG3_FLAG_WOL_ENABLE)) { + if (tp->tg3_flags & TG3_FLAG_WOL_SPEED_100MB) + advertising |= + ADVERTISED_100baseT_Half | + ADVERTISED_100baseT_Full | + ADVERTISED_10baseT_Full; + else + advertising |= ADVERTISED_10baseT_Full; + } - if (!(tp->tg3_flags2 & TG3_FLG2_ANY_SERDES)) { - tp->link_config.speed = SPEED_10; - tp->link_config.duplex = DUPLEX_HALF; - tp->link_config.autoneg = AUTONEG_ENABLE; - tg3_setup_phy(tp, 0); + phydev->advertising = advertising; + + phy_start_aneg(phydev); + } + } else { + if (tp->link_config.phy_is_low_power == 0) { + tp->link_config.phy_is_low_power = 1; + tp->link_config.orig_speed = tp->link_config.speed; + tp->link_config.orig_duplex = tp->link_config.duplex; + tp->link_config.orig_autoneg = tp->link_config.autoneg; + } + + if (!(tp->tg3_flags2 & TG3_FLG2_ANY_SERDES)) { + tp->link_config.speed = SPEED_10; + tp->link_config.duplex = DUPLEX_HALF; + tp->link_config.autoneg = AUTONEG_ENABLE; + tg3_setup_phy(tp, 0); + } } if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) { @@ -1545,8 +2115,10 @@ static int tg3_set_power_state(struct tg3 *tp, pci_power_t state) u32 mac_mode; if (!(tp->tg3_flags2 & TG3_FLG2_PHY_SERDES)) { - tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x5a); - udelay(40); + if (!(tp->tg3_flags3 & TG3_FLG3_USE_PHYLIB)) { + tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x5a); + udelay(40); + } if (tp->tg3_flags2 & TG3_FLG2_MII_SERDES) mac_mode = MAC_MODE_PORT_MODE_GMII; @@ -1671,212 +2243,6 @@ static int tg3_set_power_state(struct tg3 *tp, pci_power_t state) return 0; } -/* tp->lock is held. */ -static void tg3_wait_for_event_ack(struct tg3 *tp) -{ - int i; - - /* Wait for up to 2.5 milliseconds */ - for (i = 0; i < 250000; i++) { - if (!(tr32(GRC_RX_CPU_EVENT) & GRC_RX_CPU_DRIVER_EVENT)) - break; - udelay(10); - } -} - -/* tp->lock is held. */ -static void tg3_ump_link_report(struct tg3 *tp) -{ - u32 reg; - u32 val; - - if (!(tp->tg3_flags2 & TG3_FLG2_5780_CLASS) || - !(tp->tg3_flags & TG3_FLAG_ENABLE_ASF)) - return; - - tg3_wait_for_event_ack(tp); - - tg3_write_mem(tp, NIC_SRAM_FW_CMD_MBOX, FWCMD_NICDRV_LINK_UPDATE); - - tg3_write_mem(tp, NIC_SRAM_FW_CMD_LEN_MBOX, 14); - - val = 0; - if (!tg3_readphy(tp, MII_BMCR, ®)) - val = reg << 16; - if (!tg3_readphy(tp, MII_BMSR, ®)) - val |= (reg & 0xffff); - tg3_write_mem(tp, NIC_SRAM_FW_CMD_DATA_MBOX, val); - - val = 0; - if (!tg3_readphy(tp, MII_ADVERTISE, ®)) - val = reg << 16; - if (!tg3_readphy(tp, MII_LPA, ®)) - val |= (reg & 0xffff); - tg3_write_mem(tp, NIC_SRAM_FW_CMD_DATA_MBOX + 4, val); - - val = 0; - if (!(tp->tg3_flags2 & TG3_FLG2_MII_SERDES)) { - if (!tg3_readphy(tp, MII_CTRL1000, ®)) - val = reg << 16; - if (!tg3_readphy(tp, MII_STAT1000, ®)) - val |= (reg & 0xffff); - } - tg3_write_mem(tp, NIC_SRAM_FW_CMD_DATA_MBOX + 8, val); - - if (!tg3_readphy(tp, MII_PHYADDR, ®)) - val = reg << 16; - else - val = 0; - tg3_write_mem(tp, NIC_SRAM_FW_CMD_DATA_MBOX + 12, val); - - val = tr32(GRC_RX_CPU_EVENT); - val |= GRC_RX_CPU_DRIVER_EVENT; - tw32_f(GRC_RX_CPU_EVENT, val); -} - -static void tg3_link_report(struct tg3 *tp) -{ - if (!netif_carrier_ok(tp->dev)) { - if (netif_msg_link(tp)) - printk(KERN_INFO PFX "%s: Link is down.\n", - tp->dev->name); - tg3_ump_link_report(tp); - } else if (netif_msg_link(tp)) { - printk(KERN_INFO PFX "%s: Link is up at %d Mbps, %s duplex.\n", - tp->dev->name, - (tp->link_config.active_speed == SPEED_1000 ? - 1000 : - (tp->link_config.active_speed == SPEED_100 ? - 100 : 10)), - (tp->link_config.active_duplex == DUPLEX_FULL ? - "full" : "half")); - - printk(KERN_INFO PFX - "%s: Flow control is %s for TX and %s for RX.\n", - tp->dev->name, - (tp->link_config.active_flowctrl & TG3_FLOW_CTRL_TX) ? - "on" : "off", - (tp->link_config.active_flowctrl & TG3_FLOW_CTRL_RX) ? - "on" : "off"); - tg3_ump_link_report(tp); - } -} - -static u16 tg3_advert_flowctrl_1000T(u8 flow_ctrl) -{ - u16 miireg; - - if ((flow_ctrl & TG3_FLOW_CTRL_TX) && (flow_ctrl & TG3_FLOW_CTRL_RX)) - miireg = ADVERTISE_PAUSE_CAP; - else if (flow_ctrl & TG3_FLOW_CTRL_TX) - miireg = ADVERTISE_PAUSE_ASYM; - else if (flow_ctrl & TG3_FLOW_CTRL_RX) - miireg = ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM; - else - miireg = 0; - - return miireg; -} - -static u16 tg3_advert_flowctrl_1000X(u8 flow_ctrl) -{ - u16 miireg; - - if ((flow_ctrl & TG3_FLOW_CTRL_TX) && (flow_ctrl & TG3_FLOW_CTRL_RX)) - miireg = ADVERTISE_1000XPAUSE; - else if (flow_ctrl & TG3_FLOW_CTRL_TX) - miireg = ADVERTISE_1000XPSE_ASYM; - else if (flow_ctrl & TG3_FLOW_CTRL_RX) - miireg = ADVERTISE_1000XPAUSE | ADVERTISE_1000XPSE_ASYM; - else - miireg = 0; - - return miireg; -} - -static u8 tg3_resolve_flowctrl_1000T(u16 lcladv, u16 rmtadv) -{ - u8 cap = 0; - - if (lcladv & ADVERTISE_PAUSE_CAP) { - if (lcladv & ADVERTISE_PAUSE_ASYM) { - if (rmtadv & LPA_PAUSE_CAP) - cap = TG3_FLOW_CTRL_TX | TG3_FLOW_CTRL_RX; - else if (rmtadv & LPA_PAUSE_ASYM) - cap = TG3_FLOW_CTRL_RX; - } else { - if (rmtadv & LPA_PAUSE_CAP) - cap = TG3_FLOW_CTRL_TX | TG3_FLOW_CTRL_RX; - } - } else if (lcladv & ADVERTISE_PAUSE_ASYM) { - if ((rmtadv & LPA_PAUSE_CAP) && (rmtadv & LPA_PAUSE_ASYM)) - cap = TG3_FLOW_CTRL_TX; - } - - return cap; -} - -static u8 tg3_resolve_flowctrl_1000X(u16 lcladv, u16 rmtadv) -{ - u8 cap = 0; - - if (lcladv & ADVERTISE_1000XPAUSE) { - if (lcladv & ADVERTISE_1000XPSE_ASYM) { - if (rmtadv & LPA_1000XPAUSE) - cap = TG3_FLOW_CTRL_TX | TG3_FLOW_CTRL_RX; - else if (rmtadv & LPA_1000XPAUSE_ASYM) - cap = TG3_FLOW_CTRL_RX; - } else { - if (rmtadv & LPA_1000XPAUSE) - cap = TG3_FLOW_CTRL_TX | TG3_FLOW_CTRL_RX; - } - } else if (lcladv & ADVERTISE_1000XPSE_ASYM) { - if ((rmtadv & LPA_1000XPAUSE) && (rmtadv & LPA_1000XPAUSE_ASYM)) - cap = TG3_FLOW_CTRL_TX; - } - - return cap; -} - -static void tg3_setup_flow_control(struct tg3 *tp, u32 local_adv, u32 remote_adv) -{ - u8 new_tg3_flags = 0; - u32 old_rx_mode = tp->rx_mode; - u32 old_tx_mode = tp->tx_mode; - - if (tp->link_config.autoneg == AUTONEG_ENABLE && - (tp->tg3_flags & TG3_FLAG_PAUSE_AUTONEG)) { - if (tp->tg3_flags2 & TG3_FLG2_ANY_SERDES) - new_tg3_flags = tg3_resolve_flowctrl_1000X(local_adv, - remote_adv); - else - new_tg3_flags = tg3_resolve_flowctrl_1000T(local_adv, - remote_adv); - } else { - new_tg3_flags = tp->link_config.flowctrl; - } - - tp->link_config.active_flowctrl = new_tg3_flags; - - if (new_tg3_flags & TG3_FLOW_CTRL_RX) - tp->rx_mode |= RX_MODE_FLOW_CTRL_ENABLE; - else - tp->rx_mode &= ~RX_MODE_FLOW_CTRL_ENABLE; - - if (old_rx_mode != tp->rx_mode) { - tw32_f(MAC_RX_MODE, tp->rx_mode); - } - - if (new_tg3_flags & TG3_FLOW_CTRL_TX) - tp->tx_mode |= TX_MODE_FLOW_CTRL_ENABLE; - else - tp->tx_mode &= ~TX_MODE_FLOW_CTRL_ENABLE; - - if (old_tx_mode != tp->tx_mode) { - tw32_f(MAC_TX_MODE, tp->tx_mode); - } -} - static void tg3_aux_stat_to_speed_duplex(struct tg3 *tp, u32 val, u16 *speed, u8 *duplex) { switch (val & MII_TG3_AUX_STAT_SPDMASK) { @@ -1921,7 +2287,7 @@ static void tg3_aux_stat_to_speed_duplex(struct tg3 *tp, u32 val, u16 *speed, u8 *speed = SPEED_INVALID; *duplex = DUPLEX_INVALID; break; - }; + } } static void tg3_phy_copper_begin(struct tg3 *tp) @@ -2033,7 +2399,7 @@ static void tg3_phy_copper_begin(struct tg3 *tp) case SPEED_1000: bmcr |= TG3_BMCR_SPEED1000; break; - }; + } if (tp->link_config.duplex == DUPLEX_FULL) bmcr |= BMCR_FULLDPLX; @@ -2731,7 +3097,7 @@ static int tg3_fiber_aneg_smachine(struct tg3 *tp, default: ret = ANEG_FAILED; break; - }; + } return ret; } @@ -3572,7 +3938,7 @@ static int tg3_alloc_rx_skb(struct tg3 *tp, u32 opaque_key, default: return -EINVAL; - }; + } /* Do not overwrite any of the map or rp information * until we are sure we can commit to a new buffer. @@ -3632,7 +3998,7 @@ static void tg3_recycle_rx(struct tg3 *tp, u32 opaque_key, default: return; - }; + } dest_map->skb = src_map->skb; pci_unmap_addr_set(dest_map, mapping, @@ -3842,7 +4208,15 @@ static int tg3_poll_work(struct tg3 *tp, int work_done, int budget) sblk->status = SD_STATUS_UPDATED | (sblk->status & ~SD_STATUS_LINK_CHG); spin_lock(&tp->lock); - tg3_setup_phy(tp, 0); + if (tp->tg3_flags3 & TG3_FLG3_USE_PHYLIB) { + tw32_f(MAC_STATUS, + (MAC_STATUS_SYNC_CHANGED | + MAC_STATUS_CFG_CHANGED | + MAC_STATUS_MI_COMPLETION | + MAC_STATUS_LNKSTATE_CHANGED)); + udelay(40); + } else + tg3_setup_phy(tp, 0); spin_unlock(&tp->lock); } } @@ -4130,6 +4504,7 @@ static void tg3_poll_controller(struct net_device *dev) static void tg3_reset_task(struct work_struct *work) { struct tg3 *tp = container_of(work, struct tg3, reset_task); + int err; unsigned int restart_timer; tg3_full_lock(tp, 0); @@ -4141,6 +4516,8 @@ static void tg3_reset_task(struct work_struct *work) tg3_full_unlock(tp); + tg3_phy_stop(tp); + tg3_netif_stop(tp); tg3_full_lock(tp, 1); @@ -4156,7 +4533,8 @@ static void tg3_reset_task(struct work_struct *work) } tg3_halt(tp, RESET_KIND_SHUTDOWN, 0); - if (tg3_init_hw(tp, 1)) + err = tg3_init_hw(tp, 1); + if (err) goto out; tg3_netif_start(tp); @@ -4166,6 +4544,9 @@ static void tg3_reset_task(struct work_struct *work) out: tg3_full_unlock(tp); + + if (!err) + tg3_phy_start(tp); } static void tg3_dump_short_state(struct tg3 *tp) @@ -4669,6 +5050,8 @@ static int tg3_change_mtu(struct net_device *dev, int new_mtu) return 0; } + tg3_phy_stop(tp); + tg3_netif_stop(tp); tg3_full_lock(tp, 1); @@ -4684,6 +5067,9 @@ static int tg3_change_mtu(struct net_device *dev, int new_mtu) tg3_full_unlock(tp); + if (!err) + tg3_phy_start(tp); + return err; } @@ -4975,7 +5361,7 @@ static int tg3_stop_block(struct tg3 *tp, unsigned long ofs, u32 enable_bit, int default: break; - }; + } } val = tr32(ofs); @@ -5217,7 +5603,7 @@ static void tg3_write_sig_pre_reset(struct tg3 *tp, int kind) default: break; - }; + } } if (kind == RESET_KIND_INIT || @@ -5242,7 +5628,7 @@ static void tg3_write_sig_post_reset(struct tg3 *tp, int kind) default: break; - }; + } } if (kind == RESET_KIND_SHUTDOWN) @@ -5271,7 +5657,7 @@ static void tg3_write_sig_legacy(struct tg3 *tp, int kind) default: break; - }; + } } } @@ -5393,6 +5779,8 @@ static int tg3_chip_reset(struct tg3 *tp) tg3_nvram_lock(tp); + tg3_mdio_stop(tp); + /* No matching tg3_nvram_unlock() after this because * chip reset below will undo the nvram lock. */ @@ -5408,7 +5796,8 @@ static int tg3_chip_reset(struct tg3 *tp) GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761) + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785) tw32(GRC_FASTBOOT_PC, 0); /* @@ -5544,6 +5933,8 @@ static int tg3_chip_reset(struct tg3 *tp) tw32_f(MAC_MODE, 0); udelay(40); + tg3_mdio_start(tp); + err = tg3_poll_fw(tp); if (err) return err; @@ -6623,7 +7014,8 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) tg3_abort_hw(tp, 1); } - if (reset_phy) + if (reset_phy && + !(tp->tg3_flags3 & TG3_FLG3_USE_PHYLIB)) tg3_phy_reset(tp); err = tg3_chip_reset(tp); @@ -6699,7 +7091,8 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) return err; 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_5761 && + GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5785) { /* This value is determined during the probe time DMA * engine test, tg3_test_dma. */ @@ -6938,7 +7331,8 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) RDMAC_MODE_FIFOURUN_ENAB | RDMAC_MODE_FIFOOREAD_ENAB | RDMAC_MODE_LNGREAD_ENAB); - if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784) + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785) rdmac_mode |= RDMAC_MODE_BD_SBD_CRPT_ENAB | RDMAC_MODE_MBUF_RBD_CRPT_ENAB | RDMAC_MODE_MBUF_SBD_CRPT_ENAB; @@ -7106,8 +7500,9 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755) || (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787) || (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784) || - (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761)) - val |= (1 << 29); + (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761) || + (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785)) + val |= WDMAC_MODE_STATUS_TAG_FIX; tw32_f(WDMAC_MODE, val); udelay(40); @@ -7168,23 +7563,14 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) tp->rx_mode = RX_MODE_ENABLE; if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761) + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785) tp->rx_mode |= RX_MODE_IPV6_CSUM_ENABLE; tw32_f(MAC_RX_MODE, tp->rx_mode); udelay(10); - if (tp->link_config.phy_is_low_power) { - tp->link_config.phy_is_low_power = 0; - tp->link_config.speed = tp->link_config.orig_speed; - tp->link_config.duplex = tp->link_config.orig_duplex; - tp->link_config.autoneg = tp->link_config.orig_autoneg; - } - - tp->mi_mode &= ~MAC_MI_MODE_AUTO_POLL; - tw32_f(MAC_MI_MODE, tp->mi_mode); - udelay(80); - tw32(MAC_LED_CTRL, tp->led_ctrl); tw32(MAC_MI_STAT, MAC_MI_STAT_LNKSTAT_ATTN_ENAB); @@ -7231,19 +7617,28 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) tw32(GRC_LOCAL_CTRL, tp->grc_local_ctrl); } - err = tg3_setup_phy(tp, 0); - if (err) - return err; + if (!(tp->tg3_flags3 & TG3_FLG3_USE_PHYLIB)) { + if (tp->link_config.phy_is_low_power) { + tp->link_config.phy_is_low_power = 0; + tp->link_config.speed = tp->link_config.orig_speed; + tp->link_config.duplex = tp->link_config.orig_duplex; + tp->link_config.autoneg = tp->link_config.orig_autoneg; + } - if (!(tp->tg3_flags2 & TG3_FLG2_PHY_SERDES) && - GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5906) { - u32 tmp; + err = tg3_setup_phy(tp, 0); + if (err) + return err; - /* Clear CRC stats. */ - if (!tg3_readphy(tp, MII_TG3_TEST1, &tmp)) { - tg3_writephy(tp, MII_TG3_TEST1, - tmp | MII_TG3_TEST1_CRC_EN); - tg3_readphy(tp, 0x14, &tmp); + if (!(tp->tg3_flags2 & TG3_FLG2_PHY_SERDES) && + GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5906) { + u32 tmp; + + /* Clear CRC stats. */ + if (!tg3_readphy(tp, MII_TG3_TEST1, &tmp)) { + tg3_writephy(tp, MII_TG3_TEST1, + tmp | MII_TG3_TEST1_CRC_EN); + tg3_readphy(tp, 0x14, &tmp); + } } } @@ -7296,7 +7691,7 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) default: break; - }; + } if (tp->tg3_flags3 & TG3_FLG3_ENABLE_APE) /* Write our heartbeat update interval to APE. */ @@ -7758,6 +8153,8 @@ static int tg3_open(struct net_device *dev) } } + tg3_phy_start(tp); + tg3_full_lock(tp, 0); add_timer(&tp->timer); @@ -8559,7 +8956,13 @@ static int tg3_set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom, static int tg3_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) { - struct tg3 *tp = netdev_priv(dev); + struct tg3 *tp = netdev_priv(dev); + + if (tp->tg3_flags3 & TG3_FLG3_USE_PHYLIB) { + if (!(tp->tg3_flags3 & TG3_FLG3_PHY_CONNECTED)) + return -EAGAIN; + return phy_ethtool_gset(tp->mdio_bus.phy_map[PHY_ADDR], cmd); + } cmd->supported = (SUPPORTED_Autoneg); @@ -8596,6 +8999,12 @@ static int tg3_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) { struct tg3 *tp = netdev_priv(dev); + if (tp->tg3_flags3 & TG3_FLG3_USE_PHYLIB) { + if (!(tp->tg3_flags3 & TG3_FLG3_PHY_CONNECTED)) + return -EAGAIN; + return phy_ethtool_sset(tp->mdio_bus.phy_map[PHY_ADDR], cmd); + } + if (tp->tg3_flags2 & TG3_FLG2_ANY_SERDES) { /* These are the only valid advertisement bits allowed. */ if (cmd->autoneg == AUTONEG_ENABLE && @@ -8628,7 +9037,7 @@ static int tg3_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) tp->link_config.advertising = 0; tp->link_config.speed = cmd->speed; tp->link_config.duplex = cmd->duplex; - } + } tp->link_config.orig_speed = tp->link_config.speed; tp->link_config.orig_duplex = tp->link_config.duplex; @@ -8711,7 +9120,10 @@ static int tg3_set_tso(struct net_device *dev, u32 value) (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5906)) { if (value) { dev->features |= NETIF_F_TSO6; - if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761) + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761 || + (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 && + GET_CHIP_REV(tp->pci_chip_rev_id) != CHIPREV_5784_AX) || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785) dev->features |= NETIF_F_TSO_ECN; } else dev->features &= ~(NETIF_F_TSO6 | NETIF_F_TSO_ECN); @@ -8722,7 +9134,6 @@ static int tg3_set_tso(struct net_device *dev, u32 value) static int tg3_nway_reset(struct net_device *dev) { struct tg3 *tp = netdev_priv(dev); - u32 bmcr; int r; if (!netif_running(dev)) @@ -8731,17 +9142,25 @@ static int tg3_nway_reset(struct net_device *dev) if (tp->tg3_flags2 & TG3_FLG2_PHY_SERDES) return -EINVAL; - spin_lock_bh(&tp->lock); - r = -EINVAL; - tg3_readphy(tp, MII_BMCR, &bmcr); - if (!tg3_readphy(tp, MII_BMCR, &bmcr) && - ((bmcr & BMCR_ANENABLE) || - (tp->tg3_flags2 & TG3_FLG2_PARALLEL_DETECT))) { - tg3_writephy(tp, MII_BMCR, bmcr | BMCR_ANRESTART | - BMCR_ANENABLE); - r = 0; + if (tp->tg3_flags3 & TG3_FLG3_USE_PHYLIB) { + if (!(tp->tg3_flags3 & TG3_FLG3_PHY_CONNECTED)) + return -EAGAIN; + r = phy_start_aneg(tp->mdio_bus.phy_map[PHY_ADDR]); + } else { + u32 bmcr; + + spin_lock_bh(&tp->lock); + r = -EINVAL; + tg3_readphy(tp, MII_BMCR, &bmcr); + if (!tg3_readphy(tp, MII_BMCR, &bmcr) && + ((bmcr & BMCR_ANENABLE) || + (tp->tg3_flags2 & TG3_FLG2_PARALLEL_DETECT))) { + tg3_writephy(tp, MII_BMCR, bmcr | BMCR_ANRESTART | + BMCR_ANENABLE); + r = 0; + } + spin_unlock_bh(&tp->lock); } - spin_unlock_bh(&tp->lock); return r; } @@ -8783,6 +9202,7 @@ static int tg3_set_ringparam(struct net_device *dev, struct ethtool_ringparam *e return -EINVAL; if (netif_running(dev)) { + tg3_phy_stop(tp); tg3_netif_stop(tp); irq_sync = 1; } @@ -8806,6 +9226,9 @@ static int tg3_set_ringparam(struct net_device *dev, struct ethtool_ringparam *e tg3_full_unlock(tp); + if (irq_sync && !err) + tg3_phy_start(tp); + return err; } @@ -8829,36 +9252,92 @@ static void tg3_get_pauseparam(struct net_device *dev, struct ethtool_pauseparam static int tg3_set_pauseparam(struct net_device *dev, struct ethtool_pauseparam *epause) { struct tg3 *tp = netdev_priv(dev); - int irq_sync = 0, err = 0; + int err = 0; - if (netif_running(dev)) { - tg3_netif_stop(tp); - irq_sync = 1; - } + if (tp->tg3_flags3 & TG3_FLG3_USE_PHYLIB) { + if (!(tp->tg3_flags3 & TG3_FLG3_PHY_CONNECTED)) + return -EAGAIN; - tg3_full_lock(tp, irq_sync); + if (epause->autoneg) { + u32 newadv; + struct phy_device *phydev; - if (epause->autoneg) - tp->tg3_flags |= TG3_FLAG_PAUSE_AUTONEG; - else - tp->tg3_flags &= ~TG3_FLAG_PAUSE_AUTONEG; - if (epause->rx_pause) - tp->link_config.flowctrl |= TG3_FLOW_CTRL_RX; - else - tp->link_config.flowctrl &= ~TG3_FLOW_CTRL_RX; - if (epause->tx_pause) - tp->link_config.flowctrl |= TG3_FLOW_CTRL_TX; - else - tp->link_config.flowctrl &= ~TG3_FLOW_CTRL_TX; + phydev = tp->mdio_bus.phy_map[PHY_ADDR]; - if (netif_running(dev)) { - tg3_halt(tp, RESET_KIND_SHUTDOWN, 1); - err = tg3_restart_hw(tp, 1); - if (!err) - tg3_netif_start(tp); - } + if (epause->rx_pause) { + if (epause->tx_pause) + newadv = ADVERTISED_Pause; + else + newadv = ADVERTISED_Pause | + ADVERTISED_Asym_Pause; + } else if (epause->tx_pause) { + newadv = ADVERTISED_Asym_Pause; + } else + newadv = 0; + + if (tp->tg3_flags3 & TG3_FLG3_PHY_CONNECTED) { + u32 oldadv = phydev->advertising & + (ADVERTISED_Pause | + ADVERTISED_Asym_Pause); + if (oldadv != newadv) { + phydev->advertising &= + ~(ADVERTISED_Pause | + ADVERTISED_Asym_Pause); + phydev->advertising |= newadv; + err = phy_start_aneg(phydev); + } + } else { + tp->link_config.advertising &= + ~(ADVERTISED_Pause | + ADVERTISED_Asym_Pause); + tp->link_config.advertising |= newadv; + } + } else { + if (epause->rx_pause) + tp->link_config.flowctrl |= TG3_FLOW_CTRL_RX; + else + tp->link_config.flowctrl &= ~TG3_FLOW_CTRL_RX; - tg3_full_unlock(tp); + if (epause->tx_pause) + tp->link_config.flowctrl |= TG3_FLOW_CTRL_TX; + else + tp->link_config.flowctrl &= ~TG3_FLOW_CTRL_TX; + + if (netif_running(dev)) + tg3_setup_flow_control(tp, 0, 0); + } + } else { + int irq_sync = 0; + + if (netif_running(dev)) { + tg3_netif_stop(tp); + irq_sync = 1; + } + + tg3_full_lock(tp, irq_sync); + + if (epause->autoneg) + tp->tg3_flags |= TG3_FLAG_PAUSE_AUTONEG; + else + tp->tg3_flags &= ~TG3_FLAG_PAUSE_AUTONEG; + if (epause->rx_pause) + tp->link_config.flowctrl |= TG3_FLOW_CTRL_RX; + else + tp->link_config.flowctrl &= ~TG3_FLOW_CTRL_RX; + if (epause->tx_pause) + tp->link_config.flowctrl |= TG3_FLOW_CTRL_TX; + else + tp->link_config.flowctrl &= ~TG3_FLOW_CTRL_TX; + + if (netif_running(dev)) { + tg3_halt(tp, RESET_KIND_SHUTDOWN, 1); + err = tg3_restart_hw(tp, 1); + if (!err) + tg3_netif_start(tp); + } + + tg3_full_unlock(tp); + } return err; } @@ -8902,7 +9381,8 @@ static int tg3_set_tx_csum(struct net_device *dev, u32 data) if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761) + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785) ethtool_op_set_tx_ipv6_csum(dev, data); else ethtool_op_set_tx_csum(dev, data); @@ -9423,7 +9903,8 @@ static int tg3_test_memory(struct tg3 *tp) if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761) + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785) mem_tbl = mem_tbl_5755; else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) mem_tbl = mem_tbl_5906; @@ -9630,7 +10111,8 @@ static int tg3_test_loopback(struct tg3 *tp) return TG3_LOOPBACK_FAILED; 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_5761 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785) { int i; u32 status; @@ -9658,14 +10140,16 @@ static int tg3_test_loopback(struct tg3 *tp) err |= TG3_MAC_LOOPBACK_FAILED; 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_5761 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785) { tw32(TG3_CPMU_CTRL, cpmuctrl); /* Release the mutex */ tw32(TG3_CPMU_MUTEX_GNT, CPMU_MUTEX_GNT_DRIVER); } - if (!(tp->tg3_flags2 & TG3_FLG2_PHY_SERDES)) { + if (!(tp->tg3_flags2 & TG3_FLG2_PHY_SERDES) && + !(tp->tg3_flags3 & TG3_FLG3_USE_PHYLIB)) { if (tg3_run_loopback(tp, TG3_PHY_LOOPBACK)) err |= TG3_PHY_LOOPBACK_FAILED; } @@ -9692,9 +10176,10 @@ static void tg3_self_test(struct net_device *dev, struct ethtool_test *etest, data[1] = 1; } if (etest->flags & ETH_TEST_FL_OFFLINE) { - int err, irq_sync = 0; + int err, err2 = 0, irq_sync = 0; if (netif_running(dev)) { + tg3_phy_stop(tp); tg3_netif_stop(tp); irq_sync = 1; } @@ -9735,11 +10220,15 @@ static void tg3_self_test(struct net_device *dev, struct ethtool_test *etest, tg3_halt(tp, RESET_KIND_SHUTDOWN, 1); if (netif_running(dev)) { tp->tg3_flags |= TG3_FLAG_INIT_COMPLETE; - if (!tg3_restart_hw(tp, 1)) + err2 = tg3_restart_hw(tp, 1); + if (!err2) tg3_netif_start(tp); } tg3_full_unlock(tp); + + if (irq_sync && !err2) + tg3_phy_start(tp); } if (tp->link_config.phy_is_low_power) tg3_set_power_state(tp, PCI_D3hot); @@ -9752,6 +10241,12 @@ static int tg3_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) struct tg3 *tp = netdev_priv(dev); int err; + if (tp->tg3_flags3 & TG3_FLG3_USE_PHYLIB) { + if (!(tp->tg3_flags3 & TG3_FLG3_PHY_CONNECTED)) + return -EAGAIN; + return phy_mii_ioctl(tp->mdio_bus.phy_map[PHY_ADDR], data, cmd); + } + switch(cmd) { case SIOCGMIIPHY: data->phy_id = PHY_ADDR; @@ -10294,7 +10789,8 @@ static void __devinit tg3_nvram_init(struct tg3 *tp) else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755) tg3_get_5755_nvram_info(tp); else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784) + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785) tg3_get_5787_nvram_info(tp); else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761) tg3_get_5761_nvram_info(tp); @@ -10625,6 +11121,7 @@ static int tg3_nvram_write_block_buffered(struct tg3 *tp, u32 offset, u32 len, (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5787) && (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_5785) && (tp->nvram_jedecnum == JEDEC_ST) && (nvram_cmd & NVRAM_CMD_FIRST)) { @@ -10807,7 +11304,7 @@ static void __devinit tg3_get_eeprom_hw_cfg(struct tg3 *tp) tg3_read_mem(tp, NIC_SRAM_DATA_SIG, &val); if (val == NIC_SRAM_DATA_SIG_MAGIC) { u32 nic_cfg, led_cfg; - u32 nic_phy_id, ver, cfg2 = 0, eeprom_phy_id; + u32 nic_phy_id, ver, cfg2 = 0, cfg4 = 0, eeprom_phy_id; int eeprom_phy_serdes = 0; tg3_read_mem(tp, NIC_SRAM_DATA_CFG, &nic_cfg); @@ -10821,6 +11318,9 @@ static void __devinit tg3_get_eeprom_hw_cfg(struct tg3 *tp) (ver > 0) && (ver < 0x100)) tg3_read_mem(tp, NIC_SRAM_DATA_CFG_2, &cfg2); + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785) + tg3_read_mem(tp, NIC_SRAM_DATA_CFG_4, &cfg4); + if ((nic_cfg & NIC_SRAM_DATA_CFG_PHY_TYPE_MASK) == NIC_SRAM_DATA_CFG_PHY_TYPE_FIBER) eeprom_phy_serdes = 1; @@ -10893,7 +11393,7 @@ static void __devinit tg3_get_eeprom_hw_cfg(struct tg3 *tp) LED_CTRL_MODE_PHY_2); break; - }; + } if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5701) && @@ -10945,6 +11445,13 @@ static void __devinit tg3_get_eeprom_hw_cfg(struct tg3 *tp) if (cfg3 & NIC_SRAM_ASPM_DEBOUNCE) tp->tg3_flags |= TG3_FLAG_ASPM_WORKAROUND; } + + if (cfg4 & NIC_SRAM_RGMII_STD_IBND_DISABLE) + tp->tg3_flags3 |= TG3_FLG3_RGMII_STD_IBND_DISABLE; + if (cfg4 & NIC_SRAM_RGMII_EXT_IBND_RX_EN) + tp->tg3_flags3 |= TG3_FLG3_RGMII_EXT_IBND_RX_EN; + if (cfg4 & NIC_SRAM_RGMII_EXT_IBND_TX_EN) + tp->tg3_flags3 |= TG3_FLG3_RGMII_EXT_IBND_TX_EN; } } @@ -11003,6 +11510,9 @@ static int __devinit tg3_phy_probe(struct tg3 *tp) u32 hw_phy_id, hw_phy_id_masked; int err; + if (tp->tg3_flags3 & TG3_FLG3_USE_PHYLIB) + return tg3_phy_init(tp); + /* Reading the PHY ID register can conflict with ASF * firwmare access to the PHY hardware. */ @@ -11525,6 +12035,7 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787 || 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_5785 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906 || (tp->tg3_flags2 & TG3_FLG2_5780_CLASS)) tp->tg3_flags2 |= TG3_FLG2_5750_PLUS; @@ -11546,6 +12057,7 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787 || 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_5785 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) { tp->tg3_flags2 |= TG3_FLG2_HW_TSO_2; tp->tg3_flags2 |= TG3_FLG2_1SHOT_MSI; @@ -11558,14 +12070,8 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) } } - if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5705 && - GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5750 && - GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5752 && - GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5755 && - GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5787 && - GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5784 && - GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5761 && - GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5906) + if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS) || + (tp->tg3_flags2 & TG3_FLG2_5780_CLASS)) tp->tg3_flags2 |= TG3_FLG2_JUMBO_CAPABLE; pcie_cap = pci_find_capability(tp->pdev, PCI_CAP_ID_EXP); @@ -11754,7 +12260,8 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) } 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_5761 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785) { tp->tg3_flags |= TG3_FLAG_CPMU_PRESENT; if (tp->pci_chip_rev_id == CHIPREV_ID_5784_A0 || @@ -11847,7 +12354,8 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) tp->tg3_flags2 |= TG3_FLG2_PHY_JITTER_BUG; if (tp->pdev->device == PCI_DEVICE_ID_TIGON3_5755M) tp->tg3_flags2 |= TG3_FLG2_PHY_ADJUST_TRIM; - } else if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5906) + } else if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5906 && + GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5785) tp->tg3_flags2 |= TG3_FLG2_PHY_BER_BUG; } @@ -11858,8 +12366,7 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) tp->phy_otp = TG3_OTP_DEFAULT; } - if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761) + if (tp->tg3_flags & TG3_FLAG_CPMU_PRESENT) tp->mi_mode = MAC_MI_MODE_500KHZ_CONST; else tp->mi_mode = MAC_MI_MODE_BASE; @@ -11869,9 +12376,12 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) GET_CHIP_REV(tp->pci_chip_rev_id) != CHIPREV_5700_BX) tp->coalesce_mode |= HOSTCC_MODE_32BYTE; - /* Initialize MAC MI mode, polling disabled. */ - tw32_f(MAC_MI_MODE, tp->mi_mode); - udelay(80); + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785) + tp->tg3_flags3 |= TG3_FLG3_USE_PHYLIB; + + err = tg3_mdio_init(tp); + if (err) + return err; /* Initialize data/descriptor byte/word swapping. */ val = tr32(GRC_MODE); @@ -11952,6 +12462,7 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) printk(KERN_ERR PFX "(%s) phy probe failed, err %d\n", pci_name(tp->pdev), err); /* ... but do not return immediately ... */ + tg3_mdio_fini(tp); } tg3_read_partno(tp); @@ -11999,6 +12510,7 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787 || 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_5785 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) tp->dev->hard_start_xmit = tg3_start_xmit; else @@ -12201,7 +12713,7 @@ static u32 __devinit tg3_calc_dma_bndry(struct tg3 *tp, u32 val) val |= (DMA_RWCTRL_READ_BNDRY_384_PCIX | DMA_RWCTRL_WRITE_BNDRY_384_PCIX); break; - }; + } } else if (tp->tg3_flags2 & TG3_FLG2_PCI_EXPRESS) { switch (cacheline_size) { case 16: @@ -12218,7 +12730,7 @@ static u32 __devinit tg3_calc_dma_bndry(struct tg3 *tp, u32 val) val &= ~DMA_RWCTRL_WRITE_BNDRY_DISAB_PCIE; val |= DMA_RWCTRL_WRITE_BNDRY_128_PCIE; break; - }; + } } else { switch (cacheline_size) { case 16: @@ -12262,7 +12774,7 @@ static u32 __devinit tg3_calc_dma_bndry(struct tg3 *tp, u32 val) val |= (DMA_RWCTRL_READ_BNDRY_1024 | DMA_RWCTRL_WRITE_BNDRY_1024); break; - }; + } } out: @@ -12622,7 +13134,7 @@ static char * __devinit tg3_phy_string(struct tg3 *tp) case PHY_ID_BCM8002: return "8002/serdes"; case 0: return "serdes"; default: return "unknown"; - }; + } } static char * __devinit tg3_bus_string(struct tg3 *tp, char *str) @@ -12923,7 +13435,10 @@ static int __devinit tg3_init_one(struct pci_dev *pdev, if ((tp->tg3_flags2 & TG3_FLG2_HW_TSO_2) && (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5906)) dev->features |= NETIF_F_TSO6; - if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761) + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761 || + (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 && + GET_CHIP_REV(tp->pci_chip_rev_id) != CHIPREV_5784_AX) || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785) dev->features |= NETIF_F_TSO_ECN; } @@ -12989,7 +13504,8 @@ static int __devinit tg3_init_one(struct pci_dev *pdev, if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761) + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785) dev->features |= NETIF_F_IPV6_CSUM; tp->tg3_flags |= TG3_FLAG_RX_CHECKSUMS; @@ -13071,6 +13587,12 @@ static void __devexit tg3_remove_one(struct pci_dev *pdev) struct tg3 *tp = netdev_priv(dev); flush_scheduled_work(); + + if (tp->tg3_flags3 & TG3_FLG3_USE_PHYLIB) { + tg3_phy_fini(tp); + tg3_mdio_fini(tp); + } + unregister_netdev(dev); if (tp->aperegs) { iounmap(tp->aperegs); @@ -13103,6 +13625,7 @@ static int tg3_suspend(struct pci_dev *pdev, pm_message_t state) return 0; flush_scheduled_work(); + tg3_phy_stop(tp); tg3_netif_stop(tp); del_timer_sync(&tp->timer); @@ -13120,10 +13643,13 @@ static int tg3_suspend(struct pci_dev *pdev, pm_message_t state) err = tg3_set_power_state(tp, pci_choose_state(pdev, state)); if (err) { + int err2; + tg3_full_lock(tp, 0); tp->tg3_flags |= TG3_FLAG_INIT_COMPLETE; - if (tg3_restart_hw(tp, 1)) + err2 = tg3_restart_hw(tp, 1); + if (err2) goto out; tp->timer.expires = jiffies + tp->timer_offset; @@ -13134,6 +13660,9 @@ static int tg3_suspend(struct pci_dev *pdev, pm_message_t state) out: tg3_full_unlock(tp); + + if (!err2) + tg3_phy_start(tp); } return err; @@ -13171,6 +13700,9 @@ static int tg3_resume(struct pci_dev *pdev) out: tg3_full_unlock(tp); + if (!err) + tg3_phy_start(tp); + return err; } diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h index 0404f93baa29..df07842172b7 100644 --- a/drivers/net/tg3.h +++ b/drivers/net/tg3.h @@ -128,6 +128,7 @@ #define ASIC_REV_USE_PROD_ID_REG 0x0f #define ASIC_REV_5784 0x5784 #define ASIC_REV_5761 0x5761 +#define ASIC_REV_5785 0x5785 #define GET_CHIP_REV(CHIP_REV_ID) ((CHIP_REV_ID) >> 8) #define CHIPREV_5700_AX 0x70 #define CHIPREV_5700_BX 0x71 @@ -528,7 +529,23 @@ #define MAC_SERDES_CFG 0x00000590 #define MAC_SERDES_CFG_EDGE_SELECT 0x00001000 #define MAC_SERDES_STAT 0x00000594 -/* 0x598 --> 0x5b0 unused */ +/* 0x598 --> 0x5a0 unused */ +#define MAC_PHYCFG1 0x000005a0 +#define MAC_PHYCFG1_RGMII_INT 0x00000001 +#define MAC_PHYCFG1_RGMII_EXT_RX_DEC 0x02000000 +#define MAC_PHYCFG1_RGMII_SND_STAT_EN 0x04000000 +#define MAC_PHYCFG1_TXC_DRV 0x20000000 +#define MAC_PHYCFG2 0x000005a4 +#define MAC_PHYCFG2_INBAND_ENABLE 0x00000001 +#define MAC_EXT_RGMII_MODE 0x000005a8 +#define MAC_RGMII_MODE_TX_ENABLE 0x00000001 +#define MAC_RGMII_MODE_TX_LOWPWR 0x00000002 +#define MAC_RGMII_MODE_TX_RESET 0x00000004 +#define MAC_RGMII_MODE_RX_INT_B 0x00000100 +#define MAC_RGMII_MODE_RX_QUALITY 0x00000200 +#define MAC_RGMII_MODE_RX_ACTIVITY 0x00000400 +#define MAC_RGMII_MODE_RX_ENG_DET 0x00000800 +/* 0x5ac --> 0x5b0 unused */ #define SERDES_RX_CTRL 0x000005b0 /* 5780/5714 only */ #define SERDES_RX_SIG_DETECT 0x00000400 #define SG_DIG_CTRL 0x000005b0 @@ -1109,6 +1126,7 @@ #define WDMAC_MODE_FIFOOREAD_ENAB 0x00000100 #define WDMAC_MODE_LNGREAD_ENAB 0x00000200 #define WDMAC_MODE_RX_ACCEL 0x00000400 +#define WDMAC_MODE_STATUS_TAG_FIX 0x20000000 #define WDMAC_STATUS 0x00004c04 #define WDMAC_STATUS_TGTABORT 0x00000004 #define WDMAC_STATUS_MSTABORT 0x00000008 @@ -1713,6 +1731,12 @@ #define NIC_SRAM_DATA_CFG_3 0x00000d3c #define NIC_SRAM_ASPM_DEBOUNCE 0x00000002 +#define NIC_SRAM_DATA_CFG_4 0x00000d60 +#define NIC_SRAM_GMII_MODE 0x00000002 +#define NIC_SRAM_RGMII_STD_IBND_DISABLE 0x00000004 +#define NIC_SRAM_RGMII_EXT_IBND_RX_EN 0x00000008 +#define NIC_SRAM_RGMII_EXT_IBND_TX_EN 0x00000010 + #define NIC_SRAM_RX_MINI_BUFFER_DESC 0x00001000 #define NIC_SRAM_DMA_DESC_POOL_BASE 0x00002000 @@ -2204,6 +2228,7 @@ struct tg3_link_config { u16 orig_speed; u8 orig_duplex; u8 orig_autoneg; + u32 orig_advertising; }; struct tg3_bufmgr_config { @@ -2479,6 +2504,13 @@ struct tg3 { #define TG3_FLG3_ENABLE_APE 0x00000002 #define TG3_FLG3_5761_5784_AX_FIXES 0x00000004 #define TG3_FLG3_5701_DMA_BUG 0x00000008 +#define TG3_FLG3_USE_PHYLIB 0x00000010 +#define TG3_FLG3_MDIOBUS_INITED 0x00000020 +#define TG3_FLG3_MDIOBUS_PAUSED 0x00000040 +#define TG3_FLG3_PHY_CONNECTED 0x00000080 +#define TG3_FLG3_RGMII_STD_IBND_DISABLE 0x00000100 +#define TG3_FLG3_RGMII_EXT_IBND_RX_EN 0x00000200 +#define TG3_FLG3_RGMII_EXT_IBND_TX_EN 0x00000400 struct timer_list timer; u16 timer_counter; @@ -2519,6 +2551,9 @@ struct tg3 { int msi_cap; int pcix_cap; + struct mii_bus mdio_bus; + int mdio_irq[PHY_MAX_ADDR]; + /* PHY info */ u32 phy_id; #define PHY_ID_MASK 0xfffffff0 @@ -2546,6 +2581,9 @@ struct tg3 { #define PHY_REV_BCM5401_B2 0x3 #define PHY_REV_BCM5401_C0 0x6 #define PHY_REV_BCM5411_X0 0x1 /* Found on Netgear GA302T */ +#define TG3_PHY_ID_BCM50610 0x143bd60 +#define TG3_PHY_ID_BCMAC131 0x143bc70 + u32 led_ctrl; u32 phy_otp; diff --git a/drivers/net/tlan.c b/drivers/net/tlan.c index 0166407d7061..85246ed7cb9c 100644 --- a/drivers/net/tlan.c +++ b/drivers/net/tlan.c @@ -13,8 +13,6 @@ * This software may be used and distributed according to the terms * of the GNU General Public License, incorporated herein by reference. * - ** This file is best viewed/edited with columns>=132. - * ** Useful (if not required) reading: * * Texas Instruments, ThunderLAN Programmer's Guide, @@ -218,9 +216,7 @@ static int bbuf; module_param(bbuf, int, 0); MODULE_PARM_DESC(bbuf, "ThunderLAN use big buffer (0-1)"); -static u8 *TLanPadBuffer; -static dma_addr_t TLanPadBufferDMA; -static char TLanSignature[] = "TLAN"; +static const char TLanSignature[] = "TLAN"; static const char tlan_banner[] = "ThunderLAN driver v1.15\n"; static int tlan_have_pci; static int tlan_have_eisa; @@ -238,9 +234,11 @@ static struct board { { "Compaq Netelligent 10 T PCI UTP", TLAN_ADAPTER_ACTIVITY_LED, 0x83 }, { "Compaq Netelligent 10/100 TX PCI UTP", TLAN_ADAPTER_ACTIVITY_LED, 0x83 }, { "Compaq Integrated NetFlex-3/P", TLAN_ADAPTER_NONE, 0x83 }, - { "Compaq NetFlex-3/P", TLAN_ADAPTER_UNMANAGED_PHY | TLAN_ADAPTER_BIT_RATE_PHY, 0x83 }, + { "Compaq NetFlex-3/P", + TLAN_ADAPTER_UNMANAGED_PHY | TLAN_ADAPTER_BIT_RATE_PHY, 0x83 }, { "Compaq NetFlex-3/P", TLAN_ADAPTER_NONE, 0x83 }, - { "Compaq Netelligent Integrated 10/100 TX UTP", TLAN_ADAPTER_ACTIVITY_LED, 0x83 }, + { "Compaq Netelligent Integrated 10/100 TX UTP", + TLAN_ADAPTER_ACTIVITY_LED, 0x83 }, { "Compaq Netelligent Dual 10/100 TX PCI UTP", TLAN_ADAPTER_NONE, 0x83 }, { "Compaq Netelligent 10/100 TX Embedded UTP", TLAN_ADAPTER_NONE, 0x83 }, { "Olicom OC-2183/2185", TLAN_ADAPTER_USE_INTERN_10, 0x83 }, @@ -248,8 +246,9 @@ static struct board { { "Olicom OC-2326", TLAN_ADAPTER_USE_INTERN_10, 0xF8 }, { "Compaq Netelligent 10/100 TX UTP", TLAN_ADAPTER_ACTIVITY_LED, 0x83 }, { "Compaq Netelligent 10 T/2 PCI UTP/Coax", TLAN_ADAPTER_NONE, 0x83 }, - { "Compaq NetFlex-3/E", TLAN_ADAPTER_ACTIVITY_LED | /* EISA card */ - TLAN_ADAPTER_UNMANAGED_PHY | TLAN_ADAPTER_BIT_RATE_PHY, 0x83 }, + { "Compaq NetFlex-3/E", + TLAN_ADAPTER_ACTIVITY_LED | /* EISA card */ + TLAN_ADAPTER_UNMANAGED_PHY | TLAN_ADAPTER_BIT_RATE_PHY, 0x83 }, { "Compaq NetFlex-3/E", TLAN_ADAPTER_ACTIVITY_LED, 0x83 }, /* EISA card */ }; @@ -294,12 +293,12 @@ static int TLan_Close( struct net_device *); static struct net_device_stats *TLan_GetStats( struct net_device *); static void TLan_SetMulticastList( struct net_device *); static int TLan_ioctl( struct net_device *dev, struct ifreq *rq, int cmd); -static int TLan_probe1( struct pci_dev *pdev, long ioaddr, int irq, int rev, const struct pci_device_id *ent); +static int TLan_probe1( struct pci_dev *pdev, long ioaddr, + int irq, int rev, const struct pci_device_id *ent); static void TLan_tx_timeout( struct net_device *dev); static void TLan_tx_timeout_work(struct work_struct *work); static int tlan_init_one( struct pci_dev *pdev, const struct pci_device_id *ent); -static u32 TLan_HandleInvalid( struct net_device *, u16 ); static u32 TLan_HandleTxEOF( struct net_device *, u16 ); static u32 TLan_HandleStatOverflow( struct net_device *, u16 ); static u32 TLan_HandleRxEOF( struct net_device *, u16 ); @@ -348,29 +347,27 @@ static void TLan_EeReceiveByte( u16, u8 *, int ); static int TLan_EeReadByte( struct net_device *, u8, u8 * ); -static void +static inline void TLan_StoreSKB( struct tlan_list_tag *tag, struct sk_buff *skb) { unsigned long addr = (unsigned long)skb; - tag->buffer[9].address = (u32)addr; - addr >>= 31; /* >>= 32 is undefined for 32bit arch, stupid C */ - addr >>= 1; - tag->buffer[8].address = (u32)addr; + tag->buffer[9].address = addr; + tag->buffer[8].address = upper_32_bits(addr); } -static struct sk_buff * -TLan_GetSKB( struct tlan_list_tag *tag) +static inline struct sk_buff * +TLan_GetSKB( const struct tlan_list_tag *tag) { - unsigned long addr = tag->buffer[8].address; - addr <<= 31; - addr <<= 1; - addr |= tag->buffer[9].address; + unsigned long addr; + + addr = tag->buffer[8].address; + addr |= (tag->buffer[9].address << 16) << 16; return (struct sk_buff *) addr; } static TLanIntVectorFunc *TLanIntVector[TLAN_INT_NUMBER_OF_INTS] = { - TLan_HandleInvalid, + NULL, TLan_HandleTxEOF, TLan_HandleStatOverflow, TLan_HandleRxEOF, @@ -444,7 +441,9 @@ static void __devexit tlan_remove_one( struct pci_dev *pdev) unregister_netdev( dev ); if ( priv->dmaStorage ) { - pci_free_consistent(priv->pciDev, priv->dmaSize, priv->dmaStorage, priv->dmaStorageDMA ); + pci_free_consistent(priv->pciDev, + priv->dmaSize, priv->dmaStorage, + priv->dmaStorageDMA ); } #ifdef CONFIG_PCI @@ -469,16 +468,6 @@ static int __init tlan_probe(void) printk(KERN_INFO "%s", tlan_banner); - TLanPadBuffer = (u8 *) pci_alloc_consistent(NULL, TLAN_MIN_FRAME_SIZE, &TLanPadBufferDMA); - - if (TLanPadBuffer == NULL) { - printk(KERN_ERR "TLAN: Could not allocate memory for pad buffer.\n"); - rc = -ENOMEM; - goto err_out; - } - - memset(TLanPadBuffer, 0, TLAN_MIN_FRAME_SIZE); - TLAN_DBG(TLAN_DEBUG_PROBE, "Starting PCI Probe....\n"); /* Use new style PCI probing. Now the kernel will @@ -506,8 +495,6 @@ static int __init tlan_probe(void) err_out_pci_unreg: pci_unregister_driver(&tlan_driver); err_out_pci_free: - pci_free_consistent(NULL, TLAN_MIN_FRAME_SIZE, TLanPadBuffer, TLanPadBufferDMA); -err_out: return rc; } @@ -539,7 +526,8 @@ static int __devinit tlan_init_one( struct pci_dev *pdev, **************************************************************/ static int __devinit TLan_probe1(struct pci_dev *pdev, - long ioaddr, int irq, int rev, const struct pci_device_id *ent ) + long ioaddr, int irq, int rev, + const struct pci_device_id *ent ) { struct net_device *dev; @@ -625,8 +613,10 @@ static int __devinit TLan_probe1(struct pci_dev *pdev, /* Kernel parameters */ if (dev->mem_start) { priv->aui = dev->mem_start & 0x01; - priv->duplex = ((dev->mem_start & 0x06) == 0x06) ? 0 : (dev->mem_start & 0x06) >> 1; - priv->speed = ((dev->mem_start & 0x18) == 0x18) ? 0 : (dev->mem_start & 0x18) >> 3; + priv->duplex = ((dev->mem_start & 0x06) == 0x06) ? 0 + : (dev->mem_start & 0x06) >> 1; + priv->speed = ((dev->mem_start & 0x18) == 0x18) ? 0 + : (dev->mem_start & 0x18) >> 3; if (priv->speed == 0x1) { priv->speed = TLAN_SPEED_10; @@ -706,7 +696,8 @@ static void TLan_Eisa_Cleanup(void) dev = TLan_Eisa_Devices; priv = netdev_priv(dev); if (priv->dmaStorage) { - pci_free_consistent(priv->pciDev, priv->dmaSize, priv->dmaStorage, priv->dmaStorageDMA ); + pci_free_consistent(priv->pciDev, priv->dmaSize, + priv->dmaStorage, priv->dmaStorageDMA ); } release_region( dev->base_addr, 0x10); unregister_netdev( dev ); @@ -724,8 +715,6 @@ static void __exit tlan_exit(void) if (tlan_have_eisa) TLan_Eisa_Cleanup(); - pci_free_consistent(NULL, TLAN_MIN_FRAME_SIZE, TLanPadBuffer, TLanPadBufferDMA); - } @@ -763,8 +752,10 @@ static void __init TLan_EisaProbe (void) /* Loop through all slots of the EISA bus */ for (ioaddr = 0x1000; ioaddr < 0x9000; ioaddr += 0x1000) { - TLAN_DBG(TLAN_DEBUG_PROBE,"EISA_ID 0x%4x: 0x%4x\n", (int) ioaddr + 0xC80, inw(ioaddr + EISA_ID)); - TLAN_DBG(TLAN_DEBUG_PROBE,"EISA_ID 0x%4x: 0x%4x\n", (int) ioaddr + 0xC82, inw(ioaddr + EISA_ID2)); + TLAN_DBG(TLAN_DEBUG_PROBE,"EISA_ID 0x%4x: 0x%4x\n", + (int) ioaddr + 0xC80, inw(ioaddr + EISA_ID)); + TLAN_DBG(TLAN_DEBUG_PROBE,"EISA_ID 0x%4x: 0x%4x\n", + (int) ioaddr + 0xC82, inw(ioaddr + EISA_ID2)); TLAN_DBG(TLAN_DEBUG_PROBE, "Probing for EISA adapter at IO: 0x%4x : ", @@ -874,7 +865,8 @@ static int TLan_Init( struct net_device *dev ) dma_size = ( TLAN_NUM_RX_LISTS + TLAN_NUM_TX_LISTS ) * ( sizeof(TLanList) ); } - priv->dmaStorage = pci_alloc_consistent(priv->pciDev, dma_size, &priv->dmaStorageDMA); + priv->dmaStorage = pci_alloc_consistent(priv->pciDev, + dma_size, &priv->dmaStorageDMA); priv->dmaSize = dma_size; if ( priv->dmaStorage == NULL ) { @@ -883,16 +875,19 @@ static int TLan_Init( struct net_device *dev ) return -ENOMEM; } memset( priv->dmaStorage, 0, dma_size ); - priv->rxList = (TLanList *) - ( ( ( (u32) priv->dmaStorage ) + 7 ) & 0xFFFFFFF8 ); - priv->rxListDMA = ( ( ( (u32) priv->dmaStorageDMA ) + 7 ) & 0xFFFFFFF8 ); + priv->rxList = (TLanList *) ALIGN((unsigned long)priv->dmaStorage, 8); + priv->rxListDMA = ALIGN(priv->dmaStorageDMA, 8); priv->txList = priv->rxList + TLAN_NUM_RX_LISTS; priv->txListDMA = priv->rxListDMA + sizeof(TLanList) * TLAN_NUM_RX_LISTS; + if ( bbuf ) { priv->rxBuffer = (u8 *) ( priv->txList + TLAN_NUM_TX_LISTS ); - priv->rxBufferDMA =priv->txListDMA + sizeof(TLanList) * TLAN_NUM_TX_LISTS; - priv->txBuffer = priv->rxBuffer + ( TLAN_NUM_RX_LISTS * TLAN_MAX_FRAME_SIZE ); - priv->txBufferDMA = priv->rxBufferDMA + ( TLAN_NUM_RX_LISTS * TLAN_MAX_FRAME_SIZE ); + priv->rxBufferDMA =priv->txListDMA + + sizeof(TLanList) * TLAN_NUM_TX_LISTS; + priv->txBuffer = priv->rxBuffer + + ( TLAN_NUM_RX_LISTS * TLAN_MAX_FRAME_SIZE ); + priv->txBufferDMA = priv->rxBufferDMA + + ( TLAN_NUM_RX_LISTS * TLAN_MAX_FRAME_SIZE ); } err = 0; @@ -952,10 +947,12 @@ static int TLan_Open( struct net_device *dev ) int err; priv->tlanRev = TLan_DioRead8( dev->base_addr, TLAN_DEF_REVISION ); - err = request_irq( dev->irq, TLan_HandleInterrupt, IRQF_SHARED, TLanSignature, dev ); + err = request_irq( dev->irq, TLan_HandleInterrupt, IRQF_SHARED, + dev->name, dev ); if ( err ) { - printk(KERN_ERR "TLAN: Cannot open %s because IRQ %d is already in use.\n", dev->name, dev->irq ); + pr_err("TLAN: Cannot open %s because IRQ %d is already in use.\n", + dev->name, dev->irq ); return err; } @@ -969,7 +966,8 @@ static int TLan_Open( struct net_device *dev ) TLan_ReadAndClearStats( dev, TLAN_IGNORE ); TLan_ResetAdapter( dev ); - TLAN_DBG( TLAN_DEBUG_GNRL, "%s: Opened. TLAN Chip Rev: %x\n", dev->name, priv->tlanRev ); + TLAN_DBG( TLAN_DEBUG_GNRL, "%s: Opened. TLAN Chip Rev: %x\n", + dev->name, priv->tlanRev ); return 0; @@ -1007,14 +1005,16 @@ static int TLan_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) case SIOCGMIIREG: /* Read MII PHY register. */ - TLan_MiiReadReg(dev, data->phy_id & 0x1f, data->reg_num & 0x1f, &data->val_out); + TLan_MiiReadReg(dev, data->phy_id & 0x1f, + data->reg_num & 0x1f, &data->val_out); return 0; case SIOCSMIIREG: /* Write MII PHY register. */ if (!capable(CAP_NET_ADMIN)) return -EPERM; - TLan_MiiWriteReg(dev, data->phy_id & 0x1f, data->reg_num & 0x1f, data->val_in); + TLan_MiiWriteReg(dev, data->phy_id & 0x1f, + data->reg_num & 0x1f, data->val_in); return 0; default: return -EOPNOTSUPP; @@ -1096,20 +1096,25 @@ static int TLan_StartTx( struct sk_buff *skb, struct net_device *dev ) TLanList *tail_list; dma_addr_t tail_list_phys; u8 *tail_buffer; - int pad; unsigned long flags; if ( ! priv->phyOnline ) { - TLAN_DBG( TLAN_DEBUG_TX, "TRANSMIT: %s PHY is not ready\n", dev->name ); + TLAN_DBG( TLAN_DEBUG_TX, "TRANSMIT: %s PHY is not ready\n", + dev->name ); dev_kfree_skb_any(skb); return 0; } + if (skb_padto(skb, TLAN_MIN_FRAME_SIZE)) + return 0; + tail_list = priv->txList + priv->txTail; tail_list_phys = priv->txListDMA + sizeof(TLanList) * priv->txTail; if ( tail_list->cStat != TLAN_CSTAT_UNUSED ) { - TLAN_DBG( TLAN_DEBUG_TX, "TRANSMIT: %s is busy (Head=%d Tail=%d)\n", dev->name, priv->txHead, priv->txTail ); + TLAN_DBG( TLAN_DEBUG_TX, + "TRANSMIT: %s is busy (Head=%d Tail=%d)\n", + dev->name, priv->txHead, priv->txTail ); netif_stop_queue(dev); priv->txBusyCount++; return 1; @@ -1121,37 +1126,34 @@ static int TLan_StartTx( struct sk_buff *skb, struct net_device *dev ) tail_buffer = priv->txBuffer + ( priv->txTail * TLAN_MAX_FRAME_SIZE ); skb_copy_from_linear_data(skb, tail_buffer, skb->len); } else { - tail_list->buffer[0].address = pci_map_single(priv->pciDev, skb->data, skb->len, PCI_DMA_TODEVICE); + tail_list->buffer[0].address = pci_map_single(priv->pciDev, + skb->data, skb->len, + PCI_DMA_TODEVICE); TLan_StoreSKB(tail_list, skb); } - pad = TLAN_MIN_FRAME_SIZE - skb->len; - - if ( pad > 0 ) { - tail_list->frameSize = (u16) skb->len + pad; - tail_list->buffer[0].count = (u32) skb->len; - tail_list->buffer[1].count = TLAN_LAST_BUFFER | (u32) pad; - tail_list->buffer[1].address = TLanPadBufferDMA; - } else { - tail_list->frameSize = (u16) skb->len; - tail_list->buffer[0].count = TLAN_LAST_BUFFER | (u32) skb->len; - tail_list->buffer[1].count = 0; - tail_list->buffer[1].address = 0; - } + tail_list->frameSize = (u16) skb->len; + tail_list->buffer[0].count = TLAN_LAST_BUFFER | (u32) skb->len; + tail_list->buffer[1].count = 0; + tail_list->buffer[1].address = 0; spin_lock_irqsave(&priv->lock, flags); tail_list->cStat = TLAN_CSTAT_READY; if ( ! priv->txInProgress ) { priv->txInProgress = 1; - TLAN_DBG( TLAN_DEBUG_TX, "TRANSMIT: Starting TX on buffer %d\n", priv->txTail ); + TLAN_DBG( TLAN_DEBUG_TX, + "TRANSMIT: Starting TX on buffer %d\n", priv->txTail ); outl( tail_list_phys, dev->base_addr + TLAN_CH_PARM ); outl( TLAN_HC_GO, dev->base_addr + TLAN_HOST_CMD ); } else { - TLAN_DBG( TLAN_DEBUG_TX, "TRANSMIT: Adding buffer %d to TX channel\n", priv->txTail ); + TLAN_DBG( TLAN_DEBUG_TX, "TRANSMIT: Adding buffer %d to TX channel\n", + priv->txTail ); if ( priv->txTail == 0 ) { - ( priv->txList + ( TLAN_NUM_TX_LISTS - 1 ) )->forward = tail_list_phys; + ( priv->txList + ( TLAN_NUM_TX_LISTS - 1 ) )->forward + = tail_list_phys; } else { - ( priv->txList + ( priv->txTail - 1 ) )->forward = tail_list_phys; + ( priv->txList + ( priv->txTail - 1 ) )->forward + = tail_list_phys; } } spin_unlock_irqrestore(&priv->lock, flags); @@ -1191,33 +1193,31 @@ static int TLan_StartTx( struct sk_buff *skb, struct net_device *dev ) static irqreturn_t TLan_HandleInterrupt(int irq, void *dev_id) { - u32 ack; - struct net_device *dev; - u32 host_cmd; + struct net_device *dev = dev_id; + TLanPrivateInfo *priv = netdev_priv(dev); u16 host_int; - int type; - TLanPrivateInfo *priv; - - dev = dev_id; - priv = netdev_priv(dev); + u16 type; spin_lock(&priv->lock); host_int = inw( dev->base_addr + TLAN_HOST_INT ); - outw( host_int, dev->base_addr + TLAN_HOST_INT ); - type = ( host_int & TLAN_HI_IT_MASK ) >> 2; + if ( type ) { + u32 ack; + u32 host_cmd; - ack = TLanIntVector[type]( dev, host_int ); + outw( host_int, dev->base_addr + TLAN_HOST_INT ); + ack = TLanIntVector[type]( dev, host_int ); - if ( ack ) { - host_cmd = TLAN_HC_ACK | ack | ( type << 18 ); - outl( host_cmd, dev->base_addr + TLAN_HOST_CMD ); + if ( ack ) { + host_cmd = TLAN_HC_ACK | ack | ( type << 18 ); + outl( host_cmd, dev->base_addr + TLAN_HOST_CMD ); + } } spin_unlock(&priv->lock); - return IRQ_HANDLED; + return IRQ_RETVAL(type); } /* TLan_HandleInterrupts */ @@ -1286,8 +1286,10 @@ static struct net_device_stats *TLan_GetStats( struct net_device *dev ) /* Should only read stats if open ? */ TLan_ReadAndClearStats( dev, TLAN_RECORD ); - TLAN_DBG( TLAN_DEBUG_RX, "RECEIVE: %s EOC count = %d\n", dev->name, priv->rxEocCount ); - TLAN_DBG( TLAN_DEBUG_TX, "TRANSMIT: %s Busy count = %d\n", dev->name, priv->txBusyCount ); + TLAN_DBG( TLAN_DEBUG_RX, "RECEIVE: %s EOC count = %d\n", dev->name, + priv->rxEocCount ); + TLAN_DBG( TLAN_DEBUG_TX, "TRANSMIT: %s Busy count = %d\n", dev->name, + priv->txBusyCount ); if ( debug & TLAN_DEBUG_GNRL ) { TLan_PrintDio( dev->base_addr ); TLan_PhyPrint( dev ); @@ -1299,7 +1301,7 @@ static struct net_device_stats *TLan_GetStats( struct net_device *dev ) TLan_PrintList( priv->txList + i, "TX", i ); } - return ( &( (TLanPrivateInfo *) netdev_priv(dev) )->stats ); + return &dev->stats; } /* TLan_GetStats */ @@ -1337,10 +1339,12 @@ static void TLan_SetMulticastList( struct net_device *dev ) if ( dev->flags & IFF_PROMISC ) { tmp = TLan_DioRead8( dev->base_addr, TLAN_NET_CMD ); - TLan_DioWrite8( dev->base_addr, TLAN_NET_CMD, tmp | TLAN_NET_CMD_CAF ); + TLan_DioWrite8( dev->base_addr, + TLAN_NET_CMD, tmp | TLAN_NET_CMD_CAF ); } else { tmp = TLan_DioRead8( dev->base_addr, TLAN_NET_CMD ); - TLan_DioWrite8( dev->base_addr, TLAN_NET_CMD, tmp & ~TLAN_NET_CMD_CAF ); + TLan_DioWrite8( dev->base_addr, + TLAN_NET_CMD, tmp & ~TLAN_NET_CMD_CAF ); if ( dev->flags & IFF_ALLMULTI ) { for ( i = 0; i < 3; i++ ) TLan_SetMac( dev, i + 1, NULL ); @@ -1349,7 +1353,8 @@ static void TLan_SetMulticastList( struct net_device *dev ) } else { for ( i = 0; i < dev->mc_count; i++ ) { if ( i < 3 ) { - TLan_SetMac( dev, i + 1, (char *) &dmi->dmi_addr ); + TLan_SetMac( dev, i + 1, + (char *) &dmi->dmi_addr ); } else { offset = TLan_HashFunc( (u8 *) &dmi->dmi_addr ); if ( offset < 32 ) @@ -1383,31 +1388,6 @@ static void TLan_SetMulticastList( struct net_device *dev ) *****************************************************************************/ - /*************************************************************** - * TLan_HandleInvalid - * - * Returns: - * 0 - * Parms: - * dev Device assigned the IRQ that was - * raised. - * host_int The contents of the HOST_INT - * port. - * - * This function handles invalid interrupts. This should - * never happen unless some other adapter is trying to use - * the IRQ line assigned to the device. - * - **************************************************************/ - -static u32 TLan_HandleInvalid( struct net_device *dev, u16 host_int ) -{ - /* printk( "TLAN: Invalid interrupt on %s.\n", dev->name ); */ - return 0; - -} /* TLan_HandleInvalid */ - - /*************************************************************** @@ -1441,14 +1421,16 @@ static u32 TLan_HandleTxEOF( struct net_device *dev, u16 host_int ) u32 ack = 0; u16 tmpCStat; - TLAN_DBG( TLAN_DEBUG_TX, "TRANSMIT: Handling TX EOF (Head=%d Tail=%d)\n", priv->txHead, priv->txTail ); + TLAN_DBG( TLAN_DEBUG_TX, "TRANSMIT: Handling TX EOF (Head=%d Tail=%d)\n", + priv->txHead, priv->txTail ); head_list = priv->txList + priv->txHead; while (((tmpCStat = head_list->cStat ) & TLAN_CSTAT_FRM_CMP) && (ack < 255)) { ack++; if ( ! bbuf ) { struct sk_buff *skb = TLan_GetSKB(head_list); - pci_unmap_single(priv->pciDev, head_list->buffer[0].address, skb->len, PCI_DMA_TODEVICE); + pci_unmap_single(priv->pciDev, head_list->buffer[0].address, + skb->len, PCI_DMA_TODEVICE); dev_kfree_skb_any(skb); head_list->buffer[8].address = 0; head_list->buffer[9].address = 0; @@ -1457,7 +1439,7 @@ static u32 TLan_HandleTxEOF( struct net_device *dev, u16 host_int ) if ( tmpCStat & TLAN_CSTAT_EOC ) eoc = 1; - priv->stats.tx_bytes += head_list->frameSize; + dev->stats.tx_bytes += head_list->frameSize; head_list->cStat = TLAN_CSTAT_UNUSED; netif_start_queue(dev); @@ -1469,7 +1451,9 @@ static u32 TLan_HandleTxEOF( struct net_device *dev, u16 host_int ) printk(KERN_INFO "TLAN: Received interrupt for uncompleted TX frame.\n"); if ( eoc ) { - TLAN_DBG( TLAN_DEBUG_TX, "TRANSMIT: Handling TX EOC (Head=%d Tail=%d)\n", priv->txHead, priv->txTail ); + TLAN_DBG( TLAN_DEBUG_TX, + "TRANSMIT: Handling TX EOC (Head=%d Tail=%d)\n", + priv->txHead, priv->txTail ); head_list = priv->txList + priv->txHead; head_list_phys = priv->txListDMA + sizeof(TLanList) * priv->txHead; if ( ( head_list->cStat & TLAN_CSTAT_READY ) == TLAN_CSTAT_READY ) { @@ -1481,7 +1465,8 @@ static u32 TLan_HandleTxEOF( struct net_device *dev, u16 host_int ) } if ( priv->adapter->flags & TLAN_ADAPTER_ACTIVITY_LED ) { - TLan_DioWrite8( dev->base_addr, TLAN_LED_REG, TLAN_LED_LINK | TLAN_LED_ACT ); + TLan_DioWrite8( dev->base_addr, + TLAN_LED_REG, TLAN_LED_LINK | TLAN_LED_ACT ); if ( priv->timer.function == NULL ) { priv->timer.function = &TLan_Timer; priv->timer.data = (unsigned long) dev; @@ -1563,66 +1548,65 @@ static u32 TLan_HandleRxEOF( struct net_device *dev, u16 host_int ) TLanList *head_list; struct sk_buff *skb; TLanList *tail_list; - void *t; - u32 frameSize; u16 tmpCStat; dma_addr_t head_list_phys; - TLAN_DBG( TLAN_DEBUG_RX, "RECEIVE: Handling RX EOF (Head=%d Tail=%d)\n", priv->rxHead, priv->rxTail ); + TLAN_DBG( TLAN_DEBUG_RX, "RECEIVE: Handling RX EOF (Head=%d Tail=%d)\n", + priv->rxHead, priv->rxTail ); head_list = priv->rxList + priv->rxHead; head_list_phys = priv->rxListDMA + sizeof(TLanList) * priv->rxHead; while (((tmpCStat = head_list->cStat) & TLAN_CSTAT_FRM_CMP) && (ack < 255)) { - frameSize = head_list->frameSize; + dma_addr_t frameDma = head_list->buffer[0].address; + u32 frameSize = head_list->frameSize; ack++; if (tmpCStat & TLAN_CSTAT_EOC) eoc = 1; if (bbuf) { - skb = dev_alloc_skb(frameSize + 7); - if (skb == NULL) - printk(KERN_INFO "TLAN: Couldn't allocate memory for received data.\n"); - else { - head_buffer = priv->rxBuffer + (priv->rxHead * TLAN_MAX_FRAME_SIZE); - skb_reserve(skb, 2); - t = (void *) skb_put(skb, frameSize); - - priv->stats.rx_bytes += head_list->frameSize; - - memcpy( t, head_buffer, frameSize ); - skb->protocol = eth_type_trans( skb, dev ); - netif_rx( skb ); - } + skb = netdev_alloc_skb(dev, frameSize + 7); + if ( !skb ) + goto drop_and_reuse; + + head_buffer = priv->rxBuffer + + (priv->rxHead * TLAN_MAX_FRAME_SIZE); + skb_reserve(skb, 2); + pci_dma_sync_single_for_cpu(priv->pciDev, + frameDma, frameSize, + PCI_DMA_FROMDEVICE); + skb_copy_from_linear_data(skb, head_buffer, frameSize); + skb_put(skb, frameSize); + dev->stats.rx_bytes += frameSize; + + skb->protocol = eth_type_trans( skb, dev ); + netif_rx( skb ); } else { struct sk_buff *new_skb; - /* - * I changed the algorithm here. What we now do - * is allocate the new frame. If this fails we - * simply recycle the frame. - */ + new_skb = netdev_alloc_skb(dev, TLAN_MAX_FRAME_SIZE + 7 ); + if ( !new_skb ) + goto drop_and_reuse; - new_skb = dev_alloc_skb( TLAN_MAX_FRAME_SIZE + 7 ); + skb = TLan_GetSKB(head_list); + pci_unmap_single(priv->pciDev, frameDma, + TLAN_MAX_FRAME_SIZE, PCI_DMA_FROMDEVICE); + skb_put( skb, frameSize ); - if ( new_skb != NULL ) { - skb = TLan_GetSKB(head_list); - pci_unmap_single(priv->pciDev, head_list->buffer[0].address, TLAN_MAX_FRAME_SIZE, PCI_DMA_FROMDEVICE); - skb_trim( skb, frameSize ); + dev->stats.rx_bytes += frameSize; - priv->stats.rx_bytes += frameSize; + skb->protocol = eth_type_trans( skb, dev ); + netif_rx( skb ); - skb->protocol = eth_type_trans( skb, dev ); - netif_rx( skb ); + skb_reserve( new_skb, NET_IP_ALIGN ); + head_list->buffer[0].address = pci_map_single(priv->pciDev, + new_skb->data, + TLAN_MAX_FRAME_SIZE, + PCI_DMA_FROMDEVICE); - skb_reserve( new_skb, 2 ); - t = (void *) skb_put( new_skb, TLAN_MAX_FRAME_SIZE ); - head_list->buffer[0].address = pci_map_single(priv->pciDev, new_skb->data, TLAN_MAX_FRAME_SIZE, PCI_DMA_FROMDEVICE); - head_list->buffer[8].address = (u32) t; - TLan_StoreSKB(head_list, new_skb); - } else - printk(KERN_WARNING "TLAN: Couldn't allocate memory for received data.\n" ); - } + TLan_StoreSKB(head_list, new_skb); + } +drop_and_reuse: head_list->forward = 0; head_list->cStat = 0; tail_list = priv->rxList + priv->rxTail; @@ -1638,10 +1622,10 @@ static u32 TLan_HandleRxEOF( struct net_device *dev, u16 host_int ) printk(KERN_INFO "TLAN: Received interrupt for uncompleted RX frame.\n"); - - if ( eoc ) { - TLAN_DBG( TLAN_DEBUG_RX, "RECEIVE: Handling RX EOC (Head=%d Tail=%d)\n", priv->rxHead, priv->rxTail ); + TLAN_DBG( TLAN_DEBUG_RX, + "RECEIVE: Handling RX EOC (Head=%d Tail=%d)\n", + priv->rxHead, priv->rxTail ); head_list = priv->rxList + priv->rxHead; head_list_phys = priv->rxListDMA + sizeof(TLanList) * priv->rxHead; outl(head_list_phys, dev->base_addr + TLAN_CH_PARM ); @@ -1650,7 +1634,8 @@ static u32 TLan_HandleRxEOF( struct net_device *dev, u16 host_int ) } if ( priv->adapter->flags & TLAN_ADAPTER_ACTIVITY_LED ) { - TLan_DioWrite8( dev->base_addr, TLAN_LED_REG, TLAN_LED_LINK | TLAN_LED_ACT ); + TLan_DioWrite8( dev->base_addr, + TLAN_LED_REG, TLAN_LED_LINK | TLAN_LED_ACT ); if ( priv->timer.function == NULL ) { priv->timer.function = &TLan_Timer; priv->timer.data = (unsigned long) dev; @@ -1728,7 +1713,9 @@ static u32 TLan_HandleTxEOC( struct net_device *dev, u16 host_int ) host_int = 0; if ( priv->tlanRev < 0x30 ) { - TLAN_DBG( TLAN_DEBUG_TX, "TRANSMIT: Handling TX EOC (Head=%d Tail=%d) -- IRQ\n", priv->txHead, priv->txTail ); + TLAN_DBG( TLAN_DEBUG_TX, + "TRANSMIT: Handling TX EOC (Head=%d Tail=%d) -- IRQ\n", + priv->txHead, priv->txTail ); head_list = priv->txList + priv->txHead; head_list_phys = priv->txListDMA + sizeof(TLanList) * priv->txHead; if ( ( head_list->cStat & TLAN_CSTAT_READY ) == TLAN_CSTAT_READY ) { @@ -1796,15 +1783,18 @@ static u32 TLan_HandleStatusCheck( struct net_device *dev, u16 host_int ) net_sts = TLan_DioRead8( dev->base_addr, TLAN_NET_STS ); if ( net_sts ) { TLan_DioWrite8( dev->base_addr, TLAN_NET_STS, net_sts ); - TLAN_DBG( TLAN_DEBUG_GNRL, "%s: Net_Sts = %x\n", dev->name, (unsigned) net_sts ); + TLAN_DBG( TLAN_DEBUG_GNRL, "%s: Net_Sts = %x\n", + dev->name, (unsigned) net_sts ); } if ( ( net_sts & TLAN_NET_STS_MIRQ ) && ( priv->phyNum == 0 ) ) { TLan_MiiReadReg( dev, phy, TLAN_TLPHY_STS, &tlphy_sts ); TLan_MiiReadReg( dev, phy, TLAN_TLPHY_CTL, &tlphy_ctl ); - if ( ! ( tlphy_sts & TLAN_TS_POLOK ) && ! ( tlphy_ctl & TLAN_TC_SWAPOL ) ) { + if ( ! ( tlphy_sts & TLAN_TS_POLOK ) && + ! ( tlphy_ctl & TLAN_TC_SWAPOL ) ) { tlphy_ctl |= TLAN_TC_SWAPOL; TLan_MiiWriteReg( dev, phy, TLAN_TLPHY_CTL, tlphy_ctl); - } else if ( ( tlphy_sts & TLAN_TS_POLOK ) && ( tlphy_ctl & TLAN_TC_SWAPOL ) ) { + } else if ( ( tlphy_sts & TLAN_TS_POLOK ) + && ( tlphy_ctl & TLAN_TC_SWAPOL ) ) { tlphy_ctl &= ~TLAN_TC_SWAPOL; TLan_MiiWriteReg( dev, phy, TLAN_TLPHY_CTL, tlphy_ctl); } @@ -1849,7 +1839,9 @@ static u32 TLan_HandleRxEOC( struct net_device *dev, u16 host_int ) u32 ack = 1; if ( priv->tlanRev < 0x30 ) { - TLAN_DBG( TLAN_DEBUG_RX, "RECEIVE: Handling RX EOC (Head=%d Tail=%d) -- IRQ\n", priv->rxHead, priv->rxTail ); + TLAN_DBG( TLAN_DEBUG_RX, + "RECEIVE: Handling RX EOC (Head=%d Tail=%d) -- IRQ\n", + priv->rxHead, priv->rxTail ); head_list_phys = priv->rxListDMA + sizeof(TLanList) * priv->rxHead; outl( head_list_phys, dev->base_addr + TLAN_CH_PARM ); ack |= TLAN_HC_GO | TLAN_HC_RT; @@ -1940,10 +1932,12 @@ static void TLan_Timer( unsigned long data ) if ( priv->timer.function == NULL ) { elapsed = jiffies - priv->timerSetAt; if ( elapsed >= TLAN_TIMER_ACT_DELAY ) { - TLan_DioWrite8( dev->base_addr, TLAN_LED_REG, TLAN_LED_LINK ); + TLan_DioWrite8( dev->base_addr, + TLAN_LED_REG, TLAN_LED_LINK ); } else { priv->timer.function = &TLan_Timer; - priv->timer.expires = priv->timerSetAt + TLAN_TIMER_ACT_DELAY; + priv->timer.expires = priv->timerSetAt + + TLAN_TIMER_ACT_DELAY; spin_unlock_irqrestore(&priv->lock, flags); add_timer( &priv->timer ); break; @@ -1998,7 +1992,8 @@ static void TLan_ResetLists( struct net_device *dev ) list = priv->txList + i; list->cStat = TLAN_CSTAT_UNUSED; if ( bbuf ) { - list->buffer[0].address = priv->txBufferDMA + ( i * TLAN_MAX_FRAME_SIZE ); + list->buffer[0].address = priv->txBufferDMA + + ( i * TLAN_MAX_FRAME_SIZE ); } else { list->buffer[0].address = 0; } @@ -2017,28 +2012,32 @@ static void TLan_ResetLists( struct net_device *dev ) list->frameSize = TLAN_MAX_FRAME_SIZE; list->buffer[0].count = TLAN_MAX_FRAME_SIZE | TLAN_LAST_BUFFER; if ( bbuf ) { - list->buffer[0].address = priv->rxBufferDMA + ( i * TLAN_MAX_FRAME_SIZE ); + list->buffer[0].address = priv->rxBufferDMA + + ( i * TLAN_MAX_FRAME_SIZE ); } else { - skb = dev_alloc_skb( TLAN_MAX_FRAME_SIZE + 7 ); - if ( skb == NULL ) { - printk( "TLAN: Couldn't allocate memory for received data.\n" ); - /* If this ever happened it would be a problem */ - } else { - skb->dev = dev; - skb_reserve( skb, 2 ); - t = (void *) skb_put( skb, TLAN_MAX_FRAME_SIZE ); + skb = netdev_alloc_skb(dev, TLAN_MAX_FRAME_SIZE + 7 ); + if ( !skb ) { + pr_err("TLAN: out of memory for received data.\n" ); + break; } - list->buffer[0].address = pci_map_single(priv->pciDev, t, TLAN_MAX_FRAME_SIZE, PCI_DMA_FROMDEVICE); - list->buffer[8].address = (u32) t; + + skb_reserve( skb, NET_IP_ALIGN ); + list->buffer[0].address = pci_map_single(priv->pciDev, t, + TLAN_MAX_FRAME_SIZE, + PCI_DMA_FROMDEVICE); TLan_StoreSKB(list, skb); } list->buffer[1].count = 0; list->buffer[1].address = 0; - if ( i < TLAN_NUM_RX_LISTS - 1 ) - list->forward = list_phys + sizeof(TLanList); - else - list->forward = 0; + list->forward = list_phys + sizeof(TLanList); + } + + /* in case ran out of memory early, clear bits */ + while (i < TLAN_NUM_RX_LISTS) { + TLan_StoreSKB(priv->rxList + i, NULL); + ++i; } + list->forward = 0; } /* TLan_ResetLists */ @@ -2055,7 +2054,9 @@ static void TLan_FreeLists( struct net_device *dev ) list = priv->txList + i; skb = TLan_GetSKB(list); if ( skb ) { - pci_unmap_single(priv->pciDev, list->buffer[0].address, skb->len, PCI_DMA_TODEVICE); + pci_unmap_single(priv->pciDev, + list->buffer[0].address, skb->len, + PCI_DMA_TODEVICE); dev_kfree_skb_any( skb ); list->buffer[8].address = 0; list->buffer[9].address = 0; @@ -2066,7 +2067,10 @@ static void TLan_FreeLists( struct net_device *dev ) list = priv->rxList + i; skb = TLan_GetSKB(list); if ( skb ) { - pci_unmap_single(priv->pciDev, list->buffer[0].address, TLAN_MAX_FRAME_SIZE, PCI_DMA_FROMDEVICE); + pci_unmap_single(priv->pciDev, + list->buffer[0].address, + TLAN_MAX_FRAME_SIZE, + PCI_DMA_FROMDEVICE); dev_kfree_skb_any( skb ); list->buffer[8].address = 0; list->buffer[9].address = 0; @@ -2097,7 +2101,8 @@ static void TLan_PrintDio( u16 io_base ) u32 data0, data1; int i; - printk( "TLAN: Contents of internal registers for io base 0x%04hx.\n", io_base ); + printk( "TLAN: Contents of internal registers for io base 0x%04hx.\n", + io_base ); printk( "TLAN: Off. +0 +4\n" ); for ( i = 0; i < 0x4C; i+= 8 ) { data0 = TLan_DioRead32( io_base, i ); @@ -2131,13 +2136,14 @@ static void TLan_PrintList( TLanList *list, char *type, int num) { int i; - printk( "TLAN: %s List %d at 0x%08x\n", type, num, (u32) list ); + printk( "TLAN: %s List %d at %p\n", type, num, list ); printk( "TLAN: Forward = 0x%08x\n", list->forward ); printk( "TLAN: CSTAT = 0x%04hx\n", list->cStat ); printk( "TLAN: Frame Size = 0x%04hx\n", list->frameSize ); /* for ( i = 0; i < 10; i++ ) { */ for ( i = 0; i < 2; i++ ) { - printk( "TLAN: Buffer[%d].count, addr = 0x%08x, 0x%08x\n", i, list->buffer[i].count, list->buffer[i].address ); + printk( "TLAN: Buffer[%d].count, addr = 0x%08x, 0x%08x\n", + i, list->buffer[i].count, list->buffer[i].address ); } } /* TLan_PrintList */ @@ -2165,7 +2171,6 @@ static void TLan_PrintList( TLanList *list, char *type, int num) static void TLan_ReadAndClearStats( struct net_device *dev, int record ) { - TLanPrivateInfo *priv = netdev_priv(dev); u32 tx_good, tx_under; u32 rx_good, rx_over; u32 def_tx, crc, code; @@ -2202,18 +2207,18 @@ static void TLan_ReadAndClearStats( struct net_device *dev, int record ) loss = inb( dev->base_addr + TLAN_DIO_DATA + 2 ); if ( record ) { - priv->stats.rx_packets += rx_good; - priv->stats.rx_errors += rx_over + crc + code; - priv->stats.tx_packets += tx_good; - priv->stats.tx_errors += tx_under + loss; - priv->stats.collisions += multi_col + single_col + excess_col + late_col; + dev->stats.rx_packets += rx_good; + dev->stats.rx_errors += rx_over + crc + code; + dev->stats.tx_packets += tx_good; + dev->stats.tx_errors += tx_under + loss; + dev->stats.collisions += multi_col + single_col + excess_col + late_col; - priv->stats.rx_over_errors += rx_over; - priv->stats.rx_crc_errors += crc; - priv->stats.rx_frame_errors += code; + dev->stats.rx_over_errors += rx_over; + dev->stats.rx_crc_errors += crc; + dev->stats.rx_frame_errors += code; - priv->stats.tx_aborted_errors += tx_under; - priv->stats.tx_carrier_errors += loss; + dev->stats.tx_aborted_errors += tx_under; + dev->stats.tx_carrier_errors += loss; } } /* TLan_ReadAndClearStats */ @@ -2354,14 +2359,16 @@ TLan_FinishReset( struct net_device *dev ) TLan_MiiReadReg( dev, phy, MII_GEN_ID_HI, &tlphy_id1 ); TLan_MiiReadReg( dev, phy, MII_GEN_ID_LO, &tlphy_id2 ); - if ( ( priv->adapter->flags & TLAN_ADAPTER_UNMANAGED_PHY ) || ( priv->aui ) ) { + if ( ( priv->adapter->flags & TLAN_ADAPTER_UNMANAGED_PHY ) || + ( priv->aui ) ) { status = MII_GS_LINK; printk( "TLAN: %s: Link forced.\n", dev->name ); } else { TLan_MiiReadReg( dev, phy, MII_GEN_STS, &status ); udelay( 1000 ); TLan_MiiReadReg( dev, phy, MII_GEN_STS, &status ); - if ( (status & MII_GS_LINK) && /* We only support link info on Nat.Sem. PHY's */ + if ( (status & MII_GS_LINK) && + /* We only support link info on Nat.Sem. PHY's */ (tlphy_id1 == NAT_SEM_ID1) && (tlphy_id2 == NAT_SEM_ID2) ) { TLan_MiiReadReg( dev, phy, MII_AN_LPA, &partner ); @@ -2370,12 +2377,12 @@ TLan_FinishReset( struct net_device *dev ) printk( "TLAN: %s: Link active with ", dev->name ); if (!(tlphy_par & TLAN_PHY_AN_EN_STAT)) { printk( "forced 10%sMbps %s-Duplex\n", - tlphy_par & TLAN_PHY_SPEED_100 ? "" : "0", - tlphy_par & TLAN_PHY_DUPLEX_FULL ? "Full" : "Half"); + tlphy_par & TLAN_PHY_SPEED_100 ? "" : "0", + tlphy_par & TLAN_PHY_DUPLEX_FULL ? "Full" : "Half"); } else { printk( "AutoNegotiation enabled, at 10%sMbps %s-Duplex\n", - tlphy_par & TLAN_PHY_SPEED_100 ? "" : "0", - tlphy_par & TLAN_PHY_DUPLEX_FULL ? "Full" : "Half"); + tlphy_par & TLAN_PHY_SPEED_100 ? "" : "0", + tlphy_par & TLAN_PHY_DUPLEX_FULL ? "Full" : "Half"); printk("TLAN: Partner capability: "); for (i = 5; i <= 10; i++) if (partner & (1<<i)) @@ -2416,7 +2423,8 @@ TLan_FinishReset( struct net_device *dev ) outl( TLAN_HC_GO | TLAN_HC_RT, dev->base_addr + TLAN_HOST_CMD ); netif_carrier_on(dev); } else { - printk( "TLAN: %s: Link inactive, will retry in 10 secs...\n", dev->name ); + printk( "TLAN: %s: Link inactive, will retry in 10 secs...\n", + dev->name ); TLan_SetTimer( dev, (10*HZ), TLAN_TIMER_FINISH_RESET ); return; } @@ -2456,10 +2464,12 @@ static void TLan_SetMac( struct net_device *dev, int areg, char *mac ) if ( mac != NULL ) { for ( i = 0; i < 6; i++ ) - TLan_DioWrite8( dev->base_addr, TLAN_AREG_0 + areg + i, mac[i] ); + TLan_DioWrite8( dev->base_addr, + TLAN_AREG_0 + areg + i, mac[i] ); } else { for ( i = 0; i < 6; i++ ) - TLan_DioWrite8( dev->base_addr, TLAN_AREG_0 + areg + i, 0 ); + TLan_DioWrite8( dev->base_addr, + TLAN_AREG_0 + areg + i, 0 ); } } /* TLan_SetMac */ @@ -2565,9 +2575,13 @@ static void TLan_PhyDetect( struct net_device *dev ) TLan_MiiReadReg( dev, phy, MII_GEN_CTL, &control ); TLan_MiiReadReg( dev, phy, MII_GEN_ID_HI, &hi ); TLan_MiiReadReg( dev, phy, MII_GEN_ID_LO, &lo ); - if ( ( control != 0xFFFF ) || ( hi != 0xFFFF ) || ( lo != 0xFFFF ) ) { - TLAN_DBG( TLAN_DEBUG_GNRL, "PHY found at %02x %04x %04x %04x\n", phy, control, hi, lo ); - if ( ( priv->phy[1] == TLAN_PHY_NONE ) && ( phy != TLAN_PHY_MAX_ADDR ) ) { + if ( ( control != 0xFFFF ) || + ( hi != 0xFFFF ) || ( lo != 0xFFFF ) ) { + TLAN_DBG( TLAN_DEBUG_GNRL, + "PHY found at %02x %04x %04x %04x\n", + phy, control, hi, lo ); + if ( ( priv->phy[1] == TLAN_PHY_NONE ) && + ( phy != TLAN_PHY_MAX_ADDR ) ) { priv->phy[1] = phy; } } @@ -2595,7 +2609,9 @@ static void TLan_PhyPowerDown( struct net_device *dev ) value = MII_GC_PDOWN | MII_GC_LOOPBK | MII_GC_ISOLATE; TLan_MiiSync( dev->base_addr ); TLan_MiiWriteReg( dev, priv->phy[priv->phyNum], MII_GEN_CTL, value ); - if ( ( priv->phyNum == 0 ) && ( priv->phy[1] != TLAN_PHY_NONE ) && ( ! ( priv->adapter->flags & TLAN_ADAPTER_USE_INTERN_10 ) ) ) { + if ( ( priv->phyNum == 0 ) && + ( priv->phy[1] != TLAN_PHY_NONE ) && + ( ! ( priv->adapter->flags & TLAN_ADAPTER_USE_INTERN_10 ) ) ) { TLan_MiiSync( dev->base_addr ); TLan_MiiWriteReg( dev, priv->phy[1], MII_GEN_CTL, value ); } @@ -2768,10 +2784,10 @@ static void TLan_PhyFinishAutoNeg( struct net_device *dev ) * more time. Perhaps we should fail after a while. */ if (!priv->neg_be_verbose++) { - printk(KERN_INFO "TLAN: Giving autonegotiation more time.\n"); - printk(KERN_INFO "TLAN: Please check that your adapter has\n"); - printk(KERN_INFO "TLAN: been properly connected to a HUB or Switch.\n"); - printk(KERN_INFO "TLAN: Trying to establish link in the background...\n"); + pr_info("TLAN: Giving autonegotiation more time.\n"); + pr_info("TLAN: Please check that your adapter has\n"); + pr_info("TLAN: been properly connected to a HUB or Switch.\n"); + pr_info("TLAN: Trying to establish link in the background...\n"); } TLan_SetTimer( dev, (8*HZ), TLAN_TIMER_PHY_FINISH_AN ); return; @@ -2787,7 +2803,9 @@ static void TLan_PhyFinishAutoNeg( struct net_device *dev ) priv->tlanFullDuplex = TRUE; } - if ( ( ! ( mode & 0x0180 ) ) && ( priv->adapter->flags & TLAN_ADAPTER_USE_INTERN_10 ) && ( priv->phyNum != 0 ) ) { + if ( ( ! ( mode & 0x0180 ) ) && + ( priv->adapter->flags & TLAN_ADAPTER_USE_INTERN_10 ) && + ( priv->phyNum != 0 ) ) { priv->phyNum = 0; data = TLAN_NET_CFG_1FRAG | TLAN_NET_CFG_1CHAN | TLAN_NET_CFG_PHY_EN; TLan_DioWrite16( dev->base_addr, TLAN_NET_CONFIG, data ); @@ -2796,12 +2814,14 @@ static void TLan_PhyFinishAutoNeg( struct net_device *dev ) } if ( priv->phyNum == 0 ) { - if ( ( priv->duplex == TLAN_DUPLEX_FULL ) || ( an_adv & an_lpa & 0x0040 ) ) { - TLan_MiiWriteReg( dev, phy, MII_GEN_CTL, MII_GC_AUTOENB | MII_GC_DUPLEX ); - printk( "TLAN: Starting internal PHY with FULL-DUPLEX\n" ); + if ( ( priv->duplex == TLAN_DUPLEX_FULL ) || + ( an_adv & an_lpa & 0x0040 ) ) { + TLan_MiiWriteReg( dev, phy, MII_GEN_CTL, + MII_GC_AUTOENB | MII_GC_DUPLEX ); + pr_info("TLAN: Starting internal PHY with FULL-DUPLEX\n" ); } else { TLan_MiiWriteReg( dev, phy, MII_GEN_CTL, MII_GC_AUTOENB ); - printk( "TLAN: Starting internal PHY with HALF-DUPLEX\n" ); + pr_info( "TLAN: Starting internal PHY with HALF-DUPLEX\n" ); } } @@ -3209,7 +3229,8 @@ static int TLan_EeSendByte( u16 io_base, u8 data, int stop ) TLan_SetBit( TLAN_NET_SIO_ETXEN, sio ); if ( ( ! err ) && stop ) { - TLan_ClearBit( TLAN_NET_SIO_EDATA, sio ); /* STOP, raise data while clock is high */ + /* STOP, raise data while clock is high */ + TLan_ClearBit( TLAN_NET_SIO_EDATA, sio ); TLan_SetBit( TLAN_NET_SIO_ECLOK, sio ); TLan_SetBit( TLAN_NET_SIO_EDATA, sio ); } @@ -3272,7 +3293,8 @@ static void TLan_EeReceiveByte( u16 io_base, u8 *data, int stop ) TLan_SetBit( TLAN_NET_SIO_EDATA, sio ); /* No ack = 1 (?) */ TLan_SetBit( TLAN_NET_SIO_ECLOK, sio ); TLan_ClearBit( TLAN_NET_SIO_ECLOK, sio ); - TLan_ClearBit( TLAN_NET_SIO_EDATA, sio ); /* STOP, raise data while clock is high */ + /* STOP, raise data while clock is high */ + TLan_ClearBit( TLAN_NET_SIO_EDATA, sio ); TLan_SetBit( TLAN_NET_SIO_ECLOK, sio ); TLan_SetBit( TLAN_NET_SIO_EDATA, sio ); } diff --git a/drivers/net/tlan.h b/drivers/net/tlan.h index 41ce0b665937..4b82f283e985 100644 --- a/drivers/net/tlan.h +++ b/drivers/net/tlan.h @@ -13,8 +13,6 @@ * This software may be used and distributed according to the terms * of the GNU General Public License, incorporated herein by reference. * - ** This file is best viewed/edited with tabstop=4, colums>=132 - * * * Dec 10, 1999 Torben Mathiasen <torben.mathiasen@compaq.com> * New Maintainer @@ -45,7 +43,9 @@ #define TLAN_IGNORE 0 #define TLAN_RECORD 1 -#define TLAN_DBG(lvl, format, args...) if (debug&lvl) printk(KERN_DEBUG "TLAN: " format, ##args ); +#define TLAN_DBG(lvl, format, args...) \ + do { if (debug&lvl) printk(KERN_DEBUG "TLAN: " format, ##args ); } while(0) + #define TLAN_DEBUG_GNRL 0x0001 #define TLAN_DEBUG_TX 0x0002 #define TLAN_DEBUG_RX 0x0004 @@ -194,7 +194,6 @@ typedef struct tlan_private_tag { u32 timerSetAt; u32 timerType; struct timer_list timer; - struct net_device_stats stats; struct board *adapter; u32 adapterRev; u32 aui; @@ -205,7 +204,6 @@ typedef struct tlan_private_tag { u32 speed; u8 tlanRev; u8 tlanFullDuplex; - char devName[8]; spinlock_t lock; u8 link; u8 is_eisa; @@ -517,12 +515,18 @@ static inline void TLan_DioWrite32(u16 base_addr, u16 internal_addr, u32 data) * xor( a, xor( b, xor( c, xor( d, xor( e, xor( f, xor( g, h ) ) ) ) ) ) ) * #define DA( a, bit ) ( ( (u8) a[bit/8] ) & ( (u8) ( 1 << bit%8 ) ) ) * - * hash = XOR8( DA(a,0), DA(a, 6), DA(a,12), DA(a,18), DA(a,24), DA(a,30), DA(a,36), DA(a,42) ); - * hash |= XOR8( DA(a,1), DA(a, 7), DA(a,13), DA(a,19), DA(a,25), DA(a,31), DA(a,37), DA(a,43) ) << 1; - * hash |= XOR8( DA(a,2), DA(a, 8), DA(a,14), DA(a,20), DA(a,26), DA(a,32), DA(a,38), DA(a,44) ) << 2; - * hash |= XOR8( DA(a,3), DA(a, 9), DA(a,15), DA(a,21), DA(a,27), DA(a,33), DA(a,39), DA(a,45) ) << 3; - * hash |= XOR8( DA(a,4), DA(a,10), DA(a,16), DA(a,22), DA(a,28), DA(a,34), DA(a,40), DA(a,46) ) << 4; - * hash |= XOR8( DA(a,5), DA(a,11), DA(a,17), DA(a,23), DA(a,29), DA(a,35), DA(a,41), DA(a,47) ) << 5; + * hash = XOR8( DA(a,0), DA(a, 6), DA(a,12), DA(a,18), DA(a,24), + * DA(a,30), DA(a,36), DA(a,42) ); + * hash |= XOR8( DA(a,1), DA(a, 7), DA(a,13), DA(a,19), DA(a,25), + * DA(a,31), DA(a,37), DA(a,43) ) << 1; + * hash |= XOR8( DA(a,2), DA(a, 8), DA(a,14), DA(a,20), DA(a,26), + * DA(a,32), DA(a,38), DA(a,44) ) << 2; + * hash |= XOR8( DA(a,3), DA(a, 9), DA(a,15), DA(a,21), DA(a,27), + * DA(a,33), DA(a,39), DA(a,45) ) << 3; + * hash |= XOR8( DA(a,4), DA(a,10), DA(a,16), DA(a,22), DA(a,28), + * DA(a,34), DA(a,40), DA(a,46) ) << 4; + * hash |= XOR8( DA(a,5), DA(a,11), DA(a,17), DA(a,23), DA(a,29), + * DA(a,35), DA(a,41), DA(a,47) ) << 5; * */ static inline u32 TLan_HashFunc( const u8 *a ) diff --git a/drivers/net/tokenring/3c359.c b/drivers/net/tokenring/3c359.c index 45208a0e69a0..7766cde0d63d 100644 --- a/drivers/net/tokenring/3c359.c +++ b/drivers/net/tokenring/3c359.c @@ -132,7 +132,6 @@ static void xl_dn_comp(struct net_device *dev); static int xl_close(struct net_device *dev); static void xl_set_rx_mode(struct net_device *dev); static irqreturn_t xl_interrupt(int irq, void *dev_id); -static struct net_device_stats * xl_get_stats(struct net_device *dev); static int xl_set_mac_address(struct net_device *dev, void *addr) ; static void xl_arb_cmd(struct net_device *dev); static void xl_asb_cmd(struct net_device *dev) ; @@ -343,7 +342,6 @@ static int __devinit xl_probe(struct pci_dev *pdev, dev->stop=&xl_close; dev->do_ioctl=NULL; dev->set_multicast_list=&xl_set_rx_mode; - dev->get_stats=&xl_get_stats ; dev->set_mac_address=&xl_set_mac_address ; SET_NETDEV_DEV(dev, &pdev->dev); @@ -921,7 +919,7 @@ static void xl_rx(struct net_device *dev) adv_rx_ring(dev) ; adv_rx_ring(dev) ; /* One more time just for luck :) */ - xl_priv->xl_stats.rx_dropped++ ; + dev->stats.rx_dropped++ ; writel(ACK_INTERRUPT | UPCOMPACK | LATCH_ACK , xl_mmio + MMIO_COMMAND) ; return ; @@ -957,7 +955,7 @@ static void xl_rx(struct net_device *dev) if (skb==NULL) { /* Still need to fix the rx ring */ printk(KERN_WARNING "%s: dev_alloc_skb failed in rx, single buffer \n",dev->name) ; adv_rx_ring(dev) ; - xl_priv->xl_stats.rx_dropped++ ; + dev->stats.rx_dropped++ ; writel(ACK_INTERRUPT | UPCOMPACK | LATCH_ACK , xl_mmio + MMIO_COMMAND) ; return ; } @@ -971,8 +969,8 @@ static void xl_rx(struct net_device *dev) xl_priv->xl_rx_ring[xl_priv->rx_ring_tail].upfragaddr = cpu_to_le32(pci_map_single(xl_priv->pdev,skb->data,xl_priv->pkt_buf_sz, PCI_DMA_FROMDEVICE)); xl_priv->xl_rx_ring[xl_priv->rx_ring_tail].upfraglen = cpu_to_le32(xl_priv->pkt_buf_sz) | RXUPLASTFRAG; adv_rx_ring(dev) ; - xl_priv->xl_stats.rx_packets++ ; - xl_priv->xl_stats.rx_bytes += frame_length ; + dev->stats.rx_packets++ ; + dev->stats.rx_bytes += frame_length ; netif_rx(skb2) ; } /* if multiple buffers */ @@ -1182,8 +1180,8 @@ static int xl_xmit(struct sk_buff *skb, struct net_device *dev) txd->buffer = cpu_to_le32(pci_map_single(xl_priv->pdev, skb->data, skb->len, PCI_DMA_TODEVICE)); txd->buffer_length = cpu_to_le32(skb->len) | TXDNFRAGLAST; xl_priv->tx_ring_skb[tx_head] = skb ; - xl_priv->xl_stats.tx_packets++ ; - xl_priv->xl_stats.tx_bytes += skb->len ; + dev->stats.tx_packets++ ; + dev->stats.tx_bytes += skb->len ; /* * Set the nextptr of the previous descriptor equal to this descriptor, add XL_TX_RING_SIZE -1 @@ -1463,12 +1461,6 @@ static void xl_srb_bh(struct net_device *dev) return ; } -static struct net_device_stats * xl_get_stats(struct net_device *dev) -{ - struct xl_private *xl_priv = netdev_priv(dev); - return (struct net_device_stats *) &xl_priv->xl_stats; -} - static int xl_set_mac_address (struct net_device *dev, void *addr) { struct sockaddr *saddr = addr ; diff --git a/drivers/net/tokenring/3c359.h b/drivers/net/tokenring/3c359.h index 74cf8e1a181b..66b1ff603234 100644 --- a/drivers/net/tokenring/3c359.h +++ b/drivers/net/tokenring/3c359.h @@ -273,8 +273,6 @@ struct xl_private { struct wait_queue *srb_wait; volatile int asb_queued; - struct net_device_stats xl_stats ; - u16 mac_buffer ; u16 xl_lan_status ; u8 xl_ring_speed ; diff --git a/drivers/net/tsi108_eth.c b/drivers/net/tsi108_eth.c index 6017d5267d08..43fde99b24ac 100644 --- a/drivers/net/tsi108_eth.c +++ b/drivers/net/tsi108_eth.c @@ -803,7 +803,8 @@ static int tsi108_refill_rx(struct net_device *dev, int budget) int rx = data->rxhead; struct sk_buff *skb; - data->rxskbs[rx] = skb = dev_alloc_skb(TSI108_RXBUF_SIZE + 2); + data->rxskbs[rx] = skb = netdev_alloc_skb(dev, + TSI108_RXBUF_SIZE + 2); if (!skb) break; @@ -1352,8 +1353,9 @@ static int tsi108_open(struct net_device *dev) data->rxhead = 0; for (i = 0; i < TSI108_RXRING_LEN; i++) { - struct sk_buff *skb = dev_alloc_skb(TSI108_RXBUF_SIZE + NET_IP_ALIGN); + struct sk_buff *skb; + skb = netdev_alloc_skb(dev, TSI108_RXBUF_SIZE + NET_IP_ALIGN); if (!skb) { /* Bah. No memory for now, but maybe we'll get * some more later. @@ -1435,7 +1437,6 @@ static int tsi108_close(struct net_device *dev) dev_kfree_skb(skb); } - synchronize_irq(data->irq_num); free_irq(data->irq_num, dev); /* Discard the RX ring. */ @@ -1526,7 +1527,7 @@ static int tsi108_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) struct tsi108_prv_data *data = netdev_priv(dev); unsigned long flags; int rc; - + spin_lock_irqsave(&data->txlock, flags); rc = mii_ethtool_gset(&data->mii_if, cmd); spin_unlock_irqrestore(&data->txlock, flags); @@ -1543,7 +1544,7 @@ static int tsi108_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) spin_lock_irqsave(&data->txlock, flags); rc = mii_ethtool_sset(&data->mii_if, cmd); spin_unlock_irqrestore(&data->txlock, flags); - + return rc; } diff --git a/drivers/net/tulip/21142.c b/drivers/net/tulip/21142.c index 6c400ccd38b4..1210fb3748a7 100644 --- a/drivers/net/tulip/21142.c +++ b/drivers/net/tulip/21142.c @@ -1,7 +1,6 @@ /* drivers/net/tulip/21142.c - Maintained by Valerie Henson <val_henson@linux.intel.com> Copyright 2000,2001 The Linux Kernel Team Written/copyright 1994-2001 by Donald Becker. @@ -9,9 +8,8 @@ of the GNU General Public License, incorporated herein by reference. Please refer to Documentation/DocBook/tulip-user.{pdf,ps,html} - for more information on this driver, or visit the project - Web page at http://sourceforge.net/projects/tulip/ - + for more information on this driver. + Please submit bugs to http://bugzilla.kernel.org/ . */ #include <linux/delay.h> diff --git a/drivers/net/tulip/de2104x.c b/drivers/net/tulip/de2104x.c index 1b5edd646a8c..9281d06d5aaa 100644 --- a/drivers/net/tulip/de2104x.c +++ b/drivers/net/tulip/de2104x.c @@ -124,8 +124,6 @@ MODULE_PARM_DESC (rx_copybreak, "de2104x Breakpoint at which Rx packets are copi /* Time in jiffies before concluding the transmitter is hung. */ #define TX_TIMEOUT (6*HZ) -#define DE_UNALIGNED_16(a) (u16)(get_unaligned((u16 *)(a))) - /* This is a mysterious value that can be written to CSR11 in the 21040 (only) to support a pre-NWay full-duplex signaling mechanism using short frames. No one knows what it should be, but if left at its default value some @@ -1811,7 +1809,7 @@ static void __devinit de21041_get_srom_info (struct de_private *de) goto bad_srom; /* get default media type */ - switch (DE_UNALIGNED_16(&il->default_media)) { + switch (get_unaligned(&il->default_media)) { case 0x0001: de->media_type = DE_MEDIA_BNC; break; case 0x0002: de->media_type = DE_MEDIA_AUI; break; case 0x0204: de->media_type = DE_MEDIA_TP_FD; break; @@ -1875,9 +1873,9 @@ static void __devinit de21041_get_srom_info (struct de_private *de) bufp += sizeof (ib->opts); if (ib->opts & MediaCustomCSRs) { - de->media[idx].csr13 = DE_UNALIGNED_16(&ib->csr13); - de->media[idx].csr14 = DE_UNALIGNED_16(&ib->csr14); - de->media[idx].csr15 = DE_UNALIGNED_16(&ib->csr15); + de->media[idx].csr13 = get_unaligned(&ib->csr13); + de->media[idx].csr14 = get_unaligned(&ib->csr14); + de->media[idx].csr15 = get_unaligned(&ib->csr15); bufp += sizeof(ib->csr13) + sizeof(ib->csr14) + sizeof(ib->csr15); diff --git a/drivers/net/tulip/eeprom.c b/drivers/net/tulip/eeprom.c index da2206f6021d..0dcced1263b9 100644 --- a/drivers/net/tulip/eeprom.c +++ b/drivers/net/tulip/eeprom.c @@ -1,7 +1,6 @@ /* drivers/net/tulip/eeprom.c - Maintained by Valerie Henson <val_henson@linux.intel.com> Copyright 2000,2001 The Linux Kernel Team Written/copyright 1994-2001 by Donald Becker. @@ -9,9 +8,8 @@ of the GNU General Public License, incorporated herein by reference. Please refer to Documentation/DocBook/tulip-user.{pdf,ps,html} - for more information on this driver, or visit the project - Web page at http://sourceforge.net/projects/tulip/ - + for more information on this driver. + Please submit bug reports to http://bugzilla.kernel.org/. */ #include <linux/pci.h> diff --git a/drivers/net/tulip/interrupt.c b/drivers/net/tulip/interrupt.c index 6284afd14bbb..c6bad987d63e 100644 --- a/drivers/net/tulip/interrupt.c +++ b/drivers/net/tulip/interrupt.c @@ -1,7 +1,6 @@ /* drivers/net/tulip/interrupt.c - Maintained by Valerie Henson <val_henson@linux.intel.com> Copyright 2000,2001 The Linux Kernel Team Written/copyright 1994-2001 by Donald Becker. @@ -9,8 +8,8 @@ of the GNU General Public License, incorporated herein by reference. Please refer to Documentation/DocBook/tulip-user.{pdf,ps,html} - for more information on this driver, or visit the project - Web page at http://sourceforge.net/projects/tulip/ + for more information on this driver. + Please submit bugs to http://bugzilla.kernel.org/ . */ diff --git a/drivers/net/tulip/media.c b/drivers/net/tulip/media.c index b56256636543..91cf9c863910 100644 --- a/drivers/net/tulip/media.c +++ b/drivers/net/tulip/media.c @@ -1,7 +1,6 @@ /* drivers/net/tulip/media.c - Maintained by Valerie Henson <val_henson@linux.intel.com> Copyright 2000,2001 The Linux Kernel Team Written/copyright 1994-2001 by Donald Becker. @@ -9,9 +8,9 @@ of the GNU General Public License, incorporated herein by reference. Please refer to Documentation/DocBook/tulip-user.{pdf,ps,html} - for more information on this driver, or visit the project - Web page at http://sourceforge.net/projects/tulip/ + for more information on this driver. + Please submit bugs to http://bugzilla.kernel.org/ . */ #include <linux/kernel.h> diff --git a/drivers/net/tulip/pnic.c b/drivers/net/tulip/pnic.c index be82a2effee3..d3253ed09dfc 100644 --- a/drivers/net/tulip/pnic.c +++ b/drivers/net/tulip/pnic.c @@ -1,7 +1,6 @@ /* drivers/net/tulip/pnic.c - Maintained by Valerie Henson <val_henson@linux.intel.com> Copyright 2000,2001 The Linux Kernel Team Written/copyright 1994-2001 by Donald Becker. @@ -9,9 +8,9 @@ of the GNU General Public License, incorporated herein by reference. Please refer to Documentation/DocBook/tulip-user.{pdf,ps,html} - for more information on this driver, or visit the project - Web page at http://sourceforge.net/projects/tulip/ + for more information on this driver. + Please submit bugs to http://bugzilla.kernel.org/ . */ #include <linux/kernel.h> diff --git a/drivers/net/tulip/pnic2.c b/drivers/net/tulip/pnic2.c index 4e4a879c3fa5..f49579128fb5 100644 --- a/drivers/net/tulip/pnic2.c +++ b/drivers/net/tulip/pnic2.c @@ -1,7 +1,6 @@ /* drivers/net/tulip/pnic2.c - Maintained by Valerie Henson <val_henson@linux.intel.com> Copyright 2000,2001 The Linux Kernel Team Written/copyright 1994-2001 by Donald Becker. Modified to hep support PNIC_II by Kevin B. Hendricks @@ -10,9 +9,9 @@ of the GNU General Public License, incorporated herein by reference. Please refer to Documentation/DocBook/tulip-user.{pdf,ps,html} - for more information on this driver, or visit the project - Web page at http://sourceforge.net/projects/tulip/ + for more information on this driver. + Please submit bugs to http://bugzilla.kernel.org/ . */ diff --git a/drivers/net/tulip/timer.c b/drivers/net/tulip/timer.c index d2c1f42109b0..a0e084223082 100644 --- a/drivers/net/tulip/timer.c +++ b/drivers/net/tulip/timer.c @@ -1,7 +1,6 @@ /* drivers/net/tulip/timer.c - Maintained by Valerie Henson <val_henson@linux.intel.com> Copyright 2000,2001 The Linux Kernel Team Written/copyright 1994-2001 by Donald Becker. @@ -9,11 +8,12 @@ of the GNU General Public License, incorporated herein by reference. Please refer to Documentation/DocBook/tulip-user.{pdf,ps,html} - for more information on this driver, or visit the project - Web page at http://sourceforge.net/projects/tulip/ + for more information on this driver. + Please submit bugs to http://bugzilla.kernel.org/ . */ + #include "tulip.h" diff --git a/drivers/net/tulip/tulip.h b/drivers/net/tulip/tulip.h index 92c68a22f16b..19abbc36b60a 100644 --- a/drivers/net/tulip/tulip.h +++ b/drivers/net/tulip/tulip.h @@ -8,9 +8,9 @@ of the GNU General Public License, incorporated herein by reference. Please refer to Documentation/DocBook/tulip-user.{pdf,ps,html} - for more information on this driver, or visit the project - Web page at http://sourceforge.net/projects/tulip/ + for more information on this driver. + Please submit bugs to http://bugzilla.kernel.org/ . */ #ifndef __NET_TULIP_H__ diff --git a/drivers/net/tulip/tulip_core.c b/drivers/net/tulip/tulip_core.c index af8d2c436efd..cafa89e60167 100644 --- a/drivers/net/tulip/tulip_core.c +++ b/drivers/net/tulip/tulip_core.c @@ -1,7 +1,5 @@ -/* tulip_core.c: A DEC 21x4x-family ethernet driver for Linux. */ +/* tulip_core.c: A DEC 21x4x-family ethernet driver for Linux. -/* - Maintained by Valerie Henson <val_henson@linux.intel.com> Copyright 2000,2001 The Linux Kernel Team Written/copyright 1994-2001 by Donald Becker. @@ -9,9 +7,9 @@ of the GNU General Public License, incorporated herein by reference. Please refer to Documentation/DocBook/tulip-user.{pdf,ps,html} - for more information on this driver, or visit the project - Web page at http://sourceforge.net/projects/tulip/ + for more information on this driver. + Please submit bugs to http://bugzilla.kernel.org/ . */ diff --git a/drivers/net/tun.c b/drivers/net/tun.c index eba1271b9735..a82b32b40131 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c @@ -18,15 +18,11 @@ /* * Changes: * - * Brian Braunstein <linuxkernel@bristyle.com> 2007/03/23 - * Fixed hw address handling. Now net_device.dev_addr is kept consistent - * with tun.dev_addr when the address is set by this module. - * * Mike Kershaw <dragorn@kismetwireless.net> 2005/08/14 * Add TUNSETLINK ioctl to set the link encapsulation * * Mark Smith <markzzzsmith@yahoo.com.au> - * Use random_ether_addr() for tap MAC address. + * Use random_ether_addr() for tap MAC address. * * Harald Roelle <harald.roelle@ifi.lmu.de> 2004/04/20 * Fixes in packet dropping, queue length setting and queue wakeup. @@ -64,6 +60,7 @@ #include <linux/if_tun.h> #include <linux/crc32.h> #include <linux/nsproxy.h> +#include <linux/virtio_net.h> #include <net/net_namespace.h> #include <net/netns/generic.h> @@ -83,9 +80,16 @@ static int debug; #define DBG1( a... ) #endif +#define FLT_EXACT_COUNT 8 +struct tap_filter { + unsigned int count; /* Number of addrs. Zero means disabled */ + u32 mask[2]; /* Mask of the hashed addrs */ + unsigned char addr[FLT_EXACT_COUNT][ETH_ALEN]; +}; + struct tun_struct { struct list_head list; - unsigned long flags; + unsigned int flags; int attached; uid_t owner; gid_t group; @@ -94,19 +98,119 @@ struct tun_struct { struct sk_buff_head readq; struct net_device *dev; + struct fasync_struct *fasync; - struct fasync_struct *fasync; - - unsigned long if_flags; - u8 dev_addr[ETH_ALEN]; - u32 chr_filter[2]; - u32 net_filter[2]; + struct tap_filter txflt; #ifdef TUN_DEBUG int debug; #endif }; +/* TAP filterting */ +static void addr_hash_set(u32 *mask, const u8 *addr) +{ + int n = ether_crc(ETH_ALEN, addr) >> 26; + mask[n >> 5] |= (1 << (n & 31)); +} + +static unsigned int addr_hash_test(const u32 *mask, const u8 *addr) +{ + int n = ether_crc(ETH_ALEN, addr) >> 26; + return mask[n >> 5] & (1 << (n & 31)); +} + +static int update_filter(struct tap_filter *filter, void __user *arg) +{ + struct { u8 u[ETH_ALEN]; } *addr; + struct tun_filter uf; + int err, alen, n, nexact; + + if (copy_from_user(&uf, arg, sizeof(uf))) + return -EFAULT; + + if (!uf.count) { + /* Disabled */ + filter->count = 0; + return 0; + } + + alen = ETH_ALEN * uf.count; + addr = kmalloc(alen, GFP_KERNEL); + if (!addr) + return -ENOMEM; + + if (copy_from_user(addr, arg + sizeof(uf), alen)) { + err = -EFAULT; + goto done; + } + + /* The filter is updated without holding any locks. Which is + * perfectly safe. We disable it first and in the worst + * case we'll accept a few undesired packets. */ + filter->count = 0; + wmb(); + + /* Use first set of addresses as an exact filter */ + for (n = 0; n < uf.count && n < FLT_EXACT_COUNT; n++) + memcpy(filter->addr[n], addr[n].u, ETH_ALEN); + + nexact = n; + + /* The rest is hashed */ + memset(filter->mask, 0, sizeof(filter->mask)); + for (; n < uf.count; n++) + addr_hash_set(filter->mask, addr[n].u); + + /* For ALLMULTI just set the mask to all ones. + * This overrides the mask populated above. */ + if ((uf.flags & TUN_FLT_ALLMULTI)) + memset(filter->mask, ~0, sizeof(filter->mask)); + + /* Now enable the filter */ + wmb(); + filter->count = nexact; + + /* Return the number of exact filters */ + err = nexact; + +done: + kfree(addr); + return err; +} + +/* Returns: 0 - drop, !=0 - accept */ +static int run_filter(struct tap_filter *filter, const struct sk_buff *skb) +{ + /* Cannot use eth_hdr(skb) here because skb_mac_hdr() is incorrect + * at this point. */ + struct ethhdr *eh = (struct ethhdr *) skb->data; + int i; + + /* Exact match */ + for (i = 0; i < filter->count; i++) + if (!compare_ether_addr(eh->h_dest, filter->addr[i])) + return 1; + + /* Inexact match (multicast only) */ + if (is_multicast_ether_addr(eh->h_dest)) + return addr_hash_test(filter->mask, eh->h_dest); + + return 0; +} + +/* + * Checks whether the packet is accepted or not. + * Returns: 0 - drop, !=0 - accept + */ +static int check_filter(struct tap_filter *filter, const struct sk_buff *skb) +{ + if (!filter->count) + return 1; + + return run_filter(filter, skb); +} + /* Network device part of the driver */ static unsigned int tun_net_id; @@ -141,7 +245,12 @@ static int tun_net_xmit(struct sk_buff *skb, struct net_device *dev) if (!tun->attached) goto drop; - /* Packet dropping */ + /* Drop if the filter does not like it. + * This is a noop if the filter is disabled. + * Filter can be enabled only for the TAP devices. */ + if (!check_filter(&tun->txflt, skb)) + goto drop; + if (skb_queue_len(&tun->readq) >= dev->tx_queue_len) { if (!(tun->flags & TUN_ONE_QUEUE)) { /* Normal queueing mode. */ @@ -158,7 +267,7 @@ static int tun_net_xmit(struct sk_buff *skb, struct net_device *dev) } } - /* Queue packet */ + /* Enqueue packet */ skb_queue_tail(&tun->readq, skb); dev->trans_start = jiffies; @@ -174,41 +283,14 @@ drop: return 0; } -/** Add the specified Ethernet address to this multicast filter. */ -static void -add_multi(u32* filter, const u8* addr) +static void tun_net_mclist(struct net_device *dev) { - int bit_nr = ether_crc(ETH_ALEN, addr) >> 26; - filter[bit_nr >> 5] |= 1 << (bit_nr & 31); -} - -/** Remove the specified Ethernet addres from this multicast filter. */ -static void -del_multi(u32* filter, const u8* addr) -{ - int bit_nr = ether_crc(ETH_ALEN, addr) >> 26; - filter[bit_nr >> 5] &= ~(1 << (bit_nr & 31)); -} - -/** Update the list of multicast groups to which the network device belongs. - * This list is used to filter packets being sent from the character device to - * the network device. */ -static void -tun_net_mclist(struct net_device *dev) -{ - struct tun_struct *tun = netdev_priv(dev); - const struct dev_mc_list *mclist; - int i; - DECLARE_MAC_BUF(mac); - DBG(KERN_DEBUG "%s: tun_net_mclist: mc_count %d\n", - dev->name, dev->mc_count); - memset(tun->chr_filter, 0, sizeof tun->chr_filter); - for (i = 0, mclist = dev->mc_list; i < dev->mc_count && mclist != NULL; - i++, mclist = mclist->next) { - add_multi(tun->net_filter, mclist->dmi_addr); - DBG(KERN_DEBUG "%s: tun_net_mclist: %s\n", - dev->name, print_mac(mac, mclist->dmi_addr)); - } + /* + * This callback is supposed to deal with mc filter in + * _rx_ path and has nothing to do with the _tx_ path. + * In rx path we always accept everything userspace gives us. + */ + return; } #define MIN_MTU 68 @@ -244,13 +326,11 @@ static void tun_net_init(struct net_device *dev) case TUN_TAP_DEV: /* Ethernet TAP Device */ - dev->set_multicast_list = tun_net_mclist; - ether_setup(dev); - dev->change_mtu = tun_net_change_mtu; + dev->change_mtu = tun_net_change_mtu; + dev->set_multicast_list = tun_net_mclist; - /* random address already created for us by tun_set_iff, use it */ - memcpy(dev->dev_addr, tun->dev_addr, min(sizeof(tun->dev_addr), sizeof(dev->dev_addr)) ); + random_ether_addr(dev->dev_addr); dev->tx_queue_len = TUN_READQ_SIZE; /* We prefer our own queue length */ break; @@ -284,6 +364,7 @@ static __inline__ ssize_t tun_get_user(struct tun_struct *tun, struct iovec *iv, struct tun_pi pi = { 0, __constant_htons(ETH_P_IP) }; struct sk_buff *skb; size_t len = count, align = 0; + struct virtio_net_hdr gso = { 0 }; if (!(tun->flags & TUN_NO_PI)) { if ((len -= sizeof(pi)) > count) @@ -293,6 +374,17 @@ static __inline__ ssize_t tun_get_user(struct tun_struct *tun, struct iovec *iv, return -EFAULT; } + if (tun->flags & TUN_VNET_HDR) { + if ((len -= sizeof(gso)) > count) + return -EINVAL; + + if (memcpy_fromiovec((void *)&gso, iv, sizeof(gso))) + return -EFAULT; + + if (gso.hdr_len > len) + return -EINVAL; + } + if ((tun->flags & TUN_TYPE_MASK) == TUN_TAP_DEV) { align = NET_IP_ALIGN; if (unlikely(len < ETH_HLEN)) @@ -312,6 +404,16 @@ static __inline__ ssize_t tun_get_user(struct tun_struct *tun, struct iovec *iv, return -EFAULT; } + if (gso.flags & VIRTIO_NET_HDR_F_NEEDS_CSUM) { + if (!skb_partial_csum_set(skb, gso.csum_start, + gso.csum_offset)) { + tun->dev->stats.rx_frame_errors++; + kfree_skb(skb); + return -EINVAL; + } + } else if (tun->flags & TUN_NOCHECKSUM) + skb->ip_summed = CHECKSUM_UNNECESSARY; + switch (tun->flags & TUN_TYPE_MASK) { case TUN_TUN_DEV: if (tun->flags & TUN_NO_PI) { @@ -338,8 +440,35 @@ static __inline__ ssize_t tun_get_user(struct tun_struct *tun, struct iovec *iv, break; }; - if (tun->flags & TUN_NOCHECKSUM) - skb->ip_summed = CHECKSUM_UNNECESSARY; + if (gso.gso_type != VIRTIO_NET_HDR_GSO_NONE) { + pr_debug("GSO!\n"); + switch (gso.gso_type & ~VIRTIO_NET_HDR_GSO_ECN) { + case VIRTIO_NET_HDR_GSO_TCPV4: + skb_shinfo(skb)->gso_type = SKB_GSO_TCPV4; + break; + case VIRTIO_NET_HDR_GSO_TCPV6: + skb_shinfo(skb)->gso_type = SKB_GSO_TCPV6; + break; + default: + tun->dev->stats.rx_frame_errors++; + kfree_skb(skb); + return -EINVAL; + } + + if (gso.gso_type & VIRTIO_NET_HDR_GSO_ECN) + skb_shinfo(skb)->gso_type |= SKB_GSO_TCP_ECN; + + skb_shinfo(skb)->gso_size = gso.gso_size; + if (skb_shinfo(skb)->gso_size == 0) { + tun->dev->stats.rx_frame_errors++; + kfree_skb(skb); + return -EINVAL; + } + + /* Header must be checked, and gso_segs computed. */ + skb_shinfo(skb)->gso_type |= SKB_GSO_DODGY; + skb_shinfo(skb)->gso_segs = 0; + } netif_rx_ni(skb); tun->dev->last_rx = jiffies; @@ -385,6 +514,39 @@ static __inline__ ssize_t tun_put_user(struct tun_struct *tun, total += sizeof(pi); } + if (tun->flags & TUN_VNET_HDR) { + struct virtio_net_hdr gso = { 0 }; /* no info leak */ + if ((len -= sizeof(gso)) < 0) + return -EINVAL; + + if (skb_is_gso(skb)) { + struct skb_shared_info *sinfo = skb_shinfo(skb); + + /* This is a hint as to how much should be linear. */ + gso.hdr_len = skb_headlen(skb); + gso.gso_size = sinfo->gso_size; + if (sinfo->gso_type & SKB_GSO_TCPV4) + gso.gso_type = VIRTIO_NET_HDR_GSO_TCPV4; + else if (sinfo->gso_type & SKB_GSO_TCPV6) + gso.gso_type = VIRTIO_NET_HDR_GSO_TCPV6; + else + BUG(); + if (sinfo->gso_type & SKB_GSO_TCP_ECN) + gso.gso_type |= VIRTIO_NET_HDR_GSO_ECN; + } else + gso.gso_type = VIRTIO_NET_HDR_GSO_NONE; + + if (skb->ip_summed == CHECKSUM_PARTIAL) { + gso.flags = VIRTIO_NET_HDR_F_NEEDS_CSUM; + gso.csum_start = skb->csum_start - skb_headroom(skb); + gso.csum_offset = skb->csum_offset; + } /* else everything is zero */ + + if (unlikely(memcpy_toiovec(iv, (void *)&gso, sizeof(gso)))) + return -EFAULT; + total += sizeof(gso); + } + len = min_t(int, skb->len, len); skb_copy_datagram_iovec(skb, 0, iv, len); @@ -404,7 +566,6 @@ static ssize_t tun_chr_aio_read(struct kiocb *iocb, const struct iovec *iv, DECLARE_WAITQUEUE(wait, current); struct sk_buff *skb; ssize_t len, ret = 0; - DECLARE_MAC_BUF(mac); if (!tun) return -EBADFD; @@ -417,10 +578,6 @@ static ssize_t tun_chr_aio_read(struct kiocb *iocb, const struct iovec *iv, add_wait_queue(&tun->read_wait, &wait); while (len) { - const u8 ones[ ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; - u8 addr[ ETH_ALEN]; - int bit_nr; - current->state = TASK_INTERRUPTIBLE; /* Read frames from the queue */ @@ -440,36 +597,9 @@ static ssize_t tun_chr_aio_read(struct kiocb *iocb, const struct iovec *iv, } netif_wake_queue(tun->dev); - /** Decide whether to accept this packet. This code is designed to - * behave identically to an Ethernet interface. Accept the packet if - * - we are promiscuous. - * - the packet is addressed to us. - * - the packet is broadcast. - * - the packet is multicast and - * - we are multicast promiscous. - * - we belong to the multicast group. - */ - skb_copy_from_linear_data(skb, addr, min_t(size_t, sizeof addr, - skb->len)); - bit_nr = ether_crc(sizeof addr, addr) >> 26; - if ((tun->if_flags & IFF_PROMISC) || - memcmp(addr, tun->dev_addr, sizeof addr) == 0 || - memcmp(addr, ones, sizeof addr) == 0 || - (((addr[0] == 1 && addr[1] == 0 && addr[2] == 0x5e) || - (addr[0] == 0x33 && addr[1] == 0x33)) && - ((tun->if_flags & IFF_ALLMULTI) || - (tun->chr_filter[bit_nr >> 5] & (1 << (bit_nr & 31)))))) { - DBG(KERN_DEBUG "%s: tun_chr_readv: accepted: %s\n", - tun->dev->name, print_mac(mac, addr)); - ret = tun_put_user(tun, skb, (struct iovec *) iv, len); - kfree_skb(skb); - break; - } else { - DBG(KERN_DEBUG "%s: tun_chr_readv: rejected: %s\n", - tun->dev->name, print_mac(mac, addr)); - kfree_skb(skb); - continue; - } + ret = tun_put_user(tun, skb, (struct iovec *) iv, len); + kfree_skb(skb); + break; } current->state = TASK_RUNNING; @@ -565,12 +695,7 @@ static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr) tun = netdev_priv(dev); tun->dev = dev; tun->flags = flags; - /* Be promiscuous by default to maintain previous behaviour. */ - tun->if_flags = IFF_PROMISC; - /* Generate random Ethernet address. */ - *(__be16 *)tun->dev_addr = htons(0x00FF); - get_random_bytes(tun->dev_addr + sizeof(u16), 4); - memset(tun->chr_filter, 0, sizeof tun->chr_filter); + tun->txflt.count = 0; tun_net_init(dev); @@ -599,6 +724,11 @@ static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr) else tun->flags &= ~TUN_ONE_QUEUE; + if (ifr->ifr_flags & IFF_VNET_HDR) + tun->flags |= TUN_VNET_HDR; + else + tun->flags &= ~TUN_VNET_HDR; + file->private_data = tun; tun->attached = 1; get_net(dev_net(tun->dev)); @@ -618,12 +748,53 @@ static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr) return err; } +/* This is like a cut-down ethtool ops, except done via tun fd so no + * privs required. */ +static int set_offload(struct net_device *dev, unsigned long arg) +{ + unsigned int old_features, features; + + old_features = dev->features; + /* Unset features, set them as we chew on the arg. */ + features = (old_features & ~(NETIF_F_HW_CSUM|NETIF_F_SG|NETIF_F_FRAGLIST + |NETIF_F_TSO_ECN|NETIF_F_TSO|NETIF_F_TSO6)); + + if (arg & TUN_F_CSUM) { + features |= NETIF_F_HW_CSUM|NETIF_F_SG|NETIF_F_FRAGLIST; + arg &= ~TUN_F_CSUM; + + if (arg & (TUN_F_TSO4|TUN_F_TSO6)) { + if (arg & TUN_F_TSO_ECN) { + features |= NETIF_F_TSO_ECN; + arg &= ~TUN_F_TSO_ECN; + } + if (arg & TUN_F_TSO4) + features |= NETIF_F_TSO; + if (arg & TUN_F_TSO6) + features |= NETIF_F_TSO6; + arg &= ~(TUN_F_TSO4|TUN_F_TSO6); + } + } + + /* This gives the user a way to test for new features in future by + * trying to set them. */ + if (arg) + return -EINVAL; + + dev->features = features; + if (old_features != dev->features) + netdev_features_change(dev); + + return 0; +} + static int tun_chr_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { struct tun_struct *tun = file->private_data; void __user* argp = (void __user*)arg; struct ifreq ifr; + int ret; DECLARE_MAC_BUF(mac); if (cmd == TUNSETIFF || _IOC_TYPE(cmd) == 0x89) @@ -647,6 +818,15 @@ static int tun_chr_ioctl(struct inode *inode, struct file *file, return 0; } + if (cmd == TUNGETFEATURES) { + /* Currently this just means: "what IFF flags are valid?". + * This is needed because we never checked for invalid flags on + * TUNSETIFF. */ + return put_user(IFF_TUN | IFF_TAP | IFF_NO_PI | IFF_ONE_QUEUE | + IFF_VNET_HDR, + (unsigned int __user*)argp); + } + if (!tun) return -EBADFD; @@ -690,9 +870,6 @@ static int tun_chr_ioctl(struct inode *inode, struct file *file, break; case TUNSETLINK: - { - int ret; - /* Only allow setting the type when the interface is down */ rtnl_lock(); if (tun->dev->flags & IFF_UP) { @@ -706,85 +883,44 @@ static int tun_chr_ioctl(struct inode *inode, struct file *file, } rtnl_unlock(); return ret; - } #ifdef TUN_DEBUG case TUNSETDEBUG: tun->debug = arg; break; #endif + case TUNSETOFFLOAD: + rtnl_lock(); + ret = set_offload(tun->dev, arg); + rtnl_unlock(); + return ret; - case SIOCGIFFLAGS: - ifr.ifr_flags = tun->if_flags; - if (copy_to_user( argp, &ifr, sizeof ifr)) - return -EFAULT; - return 0; - - case SIOCSIFFLAGS: - /** Set the character device's interface flags. Currently only - * IFF_PROMISC and IFF_ALLMULTI are used. */ - tun->if_flags = ifr.ifr_flags; - DBG(KERN_INFO "%s: interface flags 0x%lx\n", - tun->dev->name, tun->if_flags); - return 0; + case TUNSETTXFILTER: + /* Can be set only for TAPs */ + if ((tun->flags & TUN_TYPE_MASK) != TUN_TAP_DEV) + return -EINVAL; + rtnl_lock(); + ret = update_filter(&tun->txflt, (void *) __user arg); + rtnl_unlock(); + return ret; case SIOCGIFHWADDR: - /* Note: the actual net device's address may be different */ - memcpy(ifr.ifr_hwaddr.sa_data, tun->dev_addr, - min(sizeof ifr.ifr_hwaddr.sa_data, sizeof tun->dev_addr)); - if (copy_to_user( argp, &ifr, sizeof ifr)) + /* Get hw addres */ + memcpy(ifr.ifr_hwaddr.sa_data, tun->dev->dev_addr, ETH_ALEN); + ifr.ifr_hwaddr.sa_family = tun->dev->type; + if (copy_to_user(argp, &ifr, sizeof ifr)) return -EFAULT; return 0; case SIOCSIFHWADDR: - { - /* try to set the actual net device's hw address */ - int ret; + /* Set hw address */ + DBG(KERN_DEBUG "%s: set hw address: %s\n", + tun->dev->name, print_mac(mac, ifr.ifr_hwaddr.sa_data)); rtnl_lock(); ret = dev_set_mac_address(tun->dev, &ifr.ifr_hwaddr); rtnl_unlock(); - - if (ret == 0) { - /** Set the character device's hardware address. This is used when - * filtering packets being sent from the network device to the character - * device. */ - memcpy(tun->dev_addr, ifr.ifr_hwaddr.sa_data, - min(sizeof ifr.ifr_hwaddr.sa_data, sizeof tun->dev_addr)); - DBG(KERN_DEBUG "%s: set hardware address: %x:%x:%x:%x:%x:%x\n", - tun->dev->name, - tun->dev_addr[0], tun->dev_addr[1], tun->dev_addr[2], - tun->dev_addr[3], tun->dev_addr[4], tun->dev_addr[5]); - } - - return ret; - } - - case SIOCADDMULTI: - /** Add the specified group to the character device's multicast filter - * list. */ - rtnl_lock(); - netif_tx_lock_bh(tun->dev); - add_multi(tun->chr_filter, ifr.ifr_hwaddr.sa_data); - netif_tx_unlock_bh(tun->dev); - rtnl_unlock(); - - DBG(KERN_DEBUG "%s: add multi: %s\n", - tun->dev->name, print_mac(mac, ifr.ifr_hwaddr.sa_data)); - return 0; - - case SIOCDELMULTI: - /** Remove the specified group from the character device's multicast - * filter list. */ - rtnl_lock(); - netif_tx_lock_bh(tun->dev); - del_multi(tun->chr_filter, ifr.ifr_hwaddr.sa_data); - netif_tx_unlock_bh(tun->dev); - rtnl_unlock(); - - DBG(KERN_DEBUG "%s: del multi: %s\n", - tun->dev->name, print_mac(mac, ifr.ifr_hwaddr.sa_data)); - return 0; + return ret; default: return -EINVAL; diff --git a/drivers/net/typhoon.c b/drivers/net/typhoon.c index c0dd25ba7a18..8549f1159a30 100644 --- a/drivers/net/typhoon.c +++ b/drivers/net/typhoon.c @@ -334,8 +334,6 @@ enum state_values { #define TYPHOON_RESET_TIMEOUT_NOSLEEP ((6 * 1000000) / TYPHOON_UDELAY) #define TYPHOON_WAIT_TIMEOUT ((1000000 / 2) / TYPHOON_UDELAY) -#define typhoon_synchronize_irq(x) synchronize_irq(x) - #if defined(NETIF_F_TSO) #define skb_tso_size(x) (skb_shinfo(x)->gso_size) #define TSO_NUM_DESCRIPTORS 2 @@ -2143,7 +2141,6 @@ typhoon_close(struct net_device *dev) printk(KERN_ERR "%s: unable to stop runtime\n", dev->name); /* Make sure there is no irq handler running on a different CPU. */ - typhoon_synchronize_irq(dev->irq); free_irq(dev->irq, dev); typhoon_free_rx_rings(tp); diff --git a/drivers/net/ucc_geth.c b/drivers/net/ucc_geth.c index 402e81020fb8..756ba10b79d6 100644 --- a/drivers/net/ucc_geth.c +++ b/drivers/net/ucc_geth.c @@ -1588,7 +1588,7 @@ static void adjust_link(struct net_device *dev) if (!ugeth->oldlink) { new_state = 1; ugeth->oldlink = 1; - netif_schedule(dev); + netif_tx_schedule_all(dev); } } else if (ugeth->oldlink) { new_state = 1; @@ -3372,7 +3372,7 @@ static void ucc_geth_timeout(struct net_device *dev) ucc_geth_startup(ugeth); } - netif_schedule(dev); + netif_tx_schedule_all(dev); } /* This is called by the kernel when a frame is ready for transmission. */ @@ -3500,11 +3500,7 @@ static int ucc_geth_rx(struct ucc_geth_private *ugeth, u8 rxQ, int rx_work_limit dev->stats.rx_bytes += length; /* Send the packet up the stack */ -#ifdef CONFIG_UGETH_NAPI netif_receive_skb(skb); -#else - netif_rx(skb); -#endif /* CONFIG_UGETH_NAPI */ } ugeth->dev->last_rx = jiffies; @@ -3580,7 +3576,6 @@ static int ucc_geth_tx(struct net_device *dev, u8 txQ) return 0; } -#ifdef CONFIG_UGETH_NAPI static int ucc_geth_poll(struct napi_struct *napi, int budget) { struct ucc_geth_private *ugeth = container_of(napi, struct ucc_geth_private, napi); @@ -3607,7 +3602,6 @@ static int ucc_geth_poll(struct napi_struct *napi, int budget) return howmany; } -#endif /* CONFIG_UGETH_NAPI */ static irqreturn_t ucc_geth_irq_handler(int irq, void *info) { @@ -3617,9 +3611,6 @@ static irqreturn_t ucc_geth_irq_handler(int irq, void *info) struct ucc_geth_info *ug_info; register u32 ucce; register u32 uccm; -#ifndef CONFIG_UGETH_NAPI - register u32 rx_mask; -#endif register u32 tx_mask; u8 i; @@ -3636,21 +3627,11 @@ static irqreturn_t ucc_geth_irq_handler(int irq, void *info) /* check for receive events that require processing */ if (ucce & UCCE_RX_EVENTS) { -#ifdef CONFIG_UGETH_NAPI if (netif_rx_schedule_prep(dev, &ugeth->napi)) { uccm &= ~UCCE_RX_EVENTS; out_be32(uccf->p_uccm, uccm); __netif_rx_schedule(dev, &ugeth->napi); } -#else - rx_mask = UCCE_RXBF_SINGLE_MASK; - for (i = 0; i < ug_info->numQueuesRx; i++) { - if (ucce & rx_mask) - ucc_geth_rx(ugeth, i, (int)ugeth->ug_info->bdRingLenRx[i]); - ucce &= ~rx_mask; - rx_mask <<= 1; - } -#endif /* CONFIG_UGETH_NAPI */ } /* Tx event processing */ @@ -3720,9 +3701,8 @@ static int ucc_geth_open(struct net_device *dev) return err; } -#ifdef CONFIG_UGETH_NAPI napi_enable(&ugeth->napi); -#endif + err = ucc_geth_startup(ugeth); if (err) { if (netif_msg_ifup(ugeth)) @@ -3783,9 +3763,8 @@ static int ucc_geth_open(struct net_device *dev) return err; out_err: -#ifdef CONFIG_UGETH_NAPI napi_disable(&ugeth->napi); -#endif + return err; } @@ -3796,9 +3775,7 @@ static int ucc_geth_close(struct net_device *dev) ugeth_vdbg("%s: IN", __FUNCTION__); -#ifdef CONFIG_UGETH_NAPI napi_disable(&ugeth->napi); -#endif ucc_geth_stop(ugeth); @@ -4050,9 +4027,7 @@ static int ucc_geth_probe(struct of_device* ofdev, const struct of_device_id *ma dev->hard_start_xmit = ucc_geth_start_xmit; dev->tx_timeout = ucc_geth_timeout; dev->watchdog_timeo = TX_TIMEOUT; -#ifdef CONFIG_UGETH_NAPI netif_napi_add(dev, &ugeth->napi, ucc_geth_poll, UCC_GETH_DEV_WEIGHT); -#endif /* CONFIG_UGETH_NAPI */ #ifdef CONFIG_NET_POLL_CONTROLLER dev->poll_controller = ucc_netpoll; #endif diff --git a/drivers/net/ucc_geth_ethtool.c b/drivers/net/ucc_geth_ethtool.c index f5839c4a5cbd..cfbbfee55836 100644 --- a/drivers/net/ucc_geth_ethtool.c +++ b/drivers/net/ucc_geth_ethtool.c @@ -5,7 +5,7 @@ * * Author: Li Yang <leoli@freescale.com> * - * Limitation: + * Limitation: * Can only get/set setttings of the first queue. * Need to re-open the interface manually after changing some paramters. * @@ -160,7 +160,7 @@ uec_set_pauseparam(struct net_device *netdev, ugeth->ug_info->receiveFlowControl = pause->rx_pause; ugeth->ug_info->transmitFlowControl = pause->tx_pause; - + if (ugeth->phydev->autoneg) { if (netif_running(netdev)) { /* FIXME: automatically restart */ diff --git a/drivers/net/usb/Kconfig b/drivers/net/usb/Kconfig index 0604f3faf043..68e198bd538b 100644 --- a/drivers/net/usb/Kconfig +++ b/drivers/net/usb/Kconfig @@ -154,6 +154,16 @@ config USB_NET_AX8817X This driver creates an interface named "ethX", where X depends on what other networking devices you have in use. +config USB_HSO + tristate "Option USB High Speed Mobile Devices" + depends on USB && RFKILL + default n + help + Choose this option if you have an Option HSDPA/HSUPA card. + These cards support downlink speeds of 7.2Mbps or greater. + + To compile this driver as a module, choose M here: the + module will be called hso. config USB_NET_CDCETHER tristate "CDC Ethernet support (smart devices such as cable modems)" diff --git a/drivers/net/usb/Makefile b/drivers/net/usb/Makefile index 595a539f8384..24800c157f98 100644 --- a/drivers/net/usb/Makefile +++ b/drivers/net/usb/Makefile @@ -6,6 +6,7 @@ obj-$(CONFIG_USB_CATC) += catc.o obj-$(CONFIG_USB_KAWETH) += kaweth.o obj-$(CONFIG_USB_PEGASUS) += pegasus.o obj-$(CONFIG_USB_RTL8150) += rtl8150.o +obj-$(CONFIG_USB_HSO) += hso.o obj-$(CONFIG_USB_NET_AX8817X) += asix.o obj-$(CONFIG_USB_NET_CDCETHER) += cdc_ether.o obj-$(CONFIG_USB_NET_DM9601) += dm9601.o diff --git a/drivers/net/usb/hso.c b/drivers/net/usb/hso.c new file mode 100644 index 000000000000..031d07b105af --- /dev/null +++ b/drivers/net/usb/hso.c @@ -0,0 +1,2836 @@ +/****************************************************************************** + * + * Driver for Option High Speed Mobile Devices. + * + * Copyright (C) 2008 Option International + * Copyright (C) 2007 Andrew Bird (Sphere Systems Ltd) + * <ajb@spheresystems.co.uk> + * Copyright (C) 2008 Greg Kroah-Hartman <gregkh@suse.de> + * Copyright (C) 2008 Novell, 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. + * + * 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 + * + * + *****************************************************************************/ + +/****************************************************************************** + * + * Description of the device: + * + * Interface 0: Contains the IP network interface on the bulk end points. + * The multiplexed serial ports are using the interrupt and + * control endpoints. + * Interrupt contains a bitmap telling which multiplexed + * serialport needs servicing. + * + * Interface 1: Diagnostics port, uses bulk only, do not submit urbs until the + * port is opened, as this have a huge impact on the network port + * throughput. + * + * Interface 2: Standard modem interface - circuit switched interface, should + * not be used. + * + *****************************************************************************/ + +#include <linux/sched.h> +#include <linux/slab.h> +#include <linux/init.h> +#include <linux/delay.h> +#include <linux/netdevice.h> +#include <linux/module.h> +#include <linux/ethtool.h> +#include <linux/usb.h> +#include <linux/timer.h> +#include <linux/tty.h> +#include <linux/tty_driver.h> +#include <linux/tty_flip.h> +#include <linux/kmod.h> +#include <linux/rfkill.h> +#include <linux/ip.h> +#include <linux/uaccess.h> +#include <linux/usb/cdc.h> +#include <net/arp.h> +#include <asm/byteorder.h> + + +#define DRIVER_VERSION "1.2" +#define MOD_AUTHOR "Option Wireless" +#define MOD_DESCRIPTION "USB High Speed Option driver" +#define MOD_LICENSE "GPL" + +#define HSO_MAX_NET_DEVICES 10 +#define HSO__MAX_MTU 2048 +#define DEFAULT_MTU 1500 +#define DEFAULT_MRU 1500 + +#define CTRL_URB_RX_SIZE 1024 +#define CTRL_URB_TX_SIZE 64 + +#define BULK_URB_RX_SIZE 4096 +#define BULK_URB_TX_SIZE 8192 + +#define MUX_BULK_RX_BUF_SIZE HSO__MAX_MTU +#define MUX_BULK_TX_BUF_SIZE HSO__MAX_MTU +#define MUX_BULK_RX_BUF_COUNT 4 +#define USB_TYPE_OPTION_VENDOR 0x20 + +/* These definitions are used with the struct hso_net flags element */ +/* - use *_bit operations on it. (bit indices not values.) */ +#define HSO_NET_RUNNING 0 + +#define HSO_NET_TX_TIMEOUT (HZ*10) + +/* Serial port defines and structs. */ +#define HSO_SERIAL_FLAG_RX_SENT 0 + +#define HSO_SERIAL_MAGIC 0x48534f31 + +/* Number of ttys to handle */ +#define HSO_SERIAL_TTY_MINORS 256 + +#define MAX_RX_URBS 2 + +#define get_serial_by_tty(x) \ + (x ? (struct hso_serial *)x->driver_data : NULL) + +/*****************************************************************************/ +/* Debugging functions */ +/*****************************************************************************/ +#define D__(lvl_, fmt, arg...) \ + do { \ + printk(lvl_ "[%d:%s]: " fmt "\n", \ + __LINE__, __func__, ## arg); \ + } while (0) + +#define D_(lvl, args...) \ + do { \ + if (lvl & debug) \ + D__(KERN_INFO, args); \ + } while (0) + +#define D1(args...) D_(0x01, ##args) +#define D2(args...) D_(0x02, ##args) +#define D3(args...) D_(0x04, ##args) +#define D4(args...) D_(0x08, ##args) +#define D5(args...) D_(0x10, ##args) + +/*****************************************************************************/ +/* Enumerators */ +/*****************************************************************************/ +enum pkt_parse_state { + WAIT_IP, + WAIT_DATA, + WAIT_SYNC +}; + +/*****************************************************************************/ +/* Structs */ +/*****************************************************************************/ + +struct hso_shared_int { + struct usb_endpoint_descriptor *intr_endp; + void *shared_intr_buf; + struct urb *shared_intr_urb; + struct usb_device *usb; + int use_count; + int ref_count; + struct mutex shared_int_lock; +}; + +struct hso_net { + struct hso_device *parent; + struct net_device *net; + struct rfkill *rfkill; + + struct usb_endpoint_descriptor *in_endp; + struct usb_endpoint_descriptor *out_endp; + + struct urb *mux_bulk_rx_urb_pool[MUX_BULK_RX_BUF_COUNT]; + struct urb *mux_bulk_tx_urb; + void *mux_bulk_rx_buf_pool[MUX_BULK_RX_BUF_COUNT]; + void *mux_bulk_tx_buf; + + struct sk_buff *skb_rx_buf; + struct sk_buff *skb_tx_buf; + + enum pkt_parse_state rx_parse_state; + spinlock_t net_lock; + + unsigned short rx_buf_size; + unsigned short rx_buf_missing; + struct iphdr rx_ip_hdr; + + unsigned long flags; +}; + +struct hso_serial { + struct hso_device *parent; + int magic; + u8 minor; + + struct hso_shared_int *shared_int; + + /* rx/tx urb could be either a bulk urb or a control urb depending + on which serial port it is used on. */ + struct urb *rx_urb[MAX_RX_URBS]; + u8 num_rx_urbs; + u8 *rx_data[MAX_RX_URBS]; + u16 rx_data_length; /* should contain allocated length */ + + struct urb *tx_urb; + u8 *tx_data; + u8 *tx_buffer; + u16 tx_data_length; /* should contain allocated length */ + u16 tx_data_count; + u16 tx_buffer_count; + struct usb_ctrlrequest ctrl_req_tx; + struct usb_ctrlrequest ctrl_req_rx; + + struct usb_endpoint_descriptor *in_endp; + struct usb_endpoint_descriptor *out_endp; + + unsigned long flags; + u8 rts_state; + u8 dtr_state; + unsigned tx_urb_used:1; + + /* from usb_serial_port */ + struct tty_struct *tty; + int open_count; + spinlock_t serial_lock; + + int (*write_data) (struct hso_serial *serial); +}; + +struct hso_device { + union { + struct hso_serial *dev_serial; + struct hso_net *dev_net; + } port_data; + + u32 port_spec; + + u8 is_active; + u8 usb_gone; + struct work_struct async_get_intf; + struct work_struct async_put_intf; + + struct usb_device *usb; + struct usb_interface *interface; + + struct device *dev; + struct kref ref; + struct mutex mutex; +}; + +/* Type of interface */ +#define HSO_INTF_MASK 0xFF00 +#define HSO_INTF_MUX 0x0100 +#define HSO_INTF_BULK 0x0200 + +/* Type of port */ +#define HSO_PORT_MASK 0xFF +#define HSO_PORT_NO_PORT 0x0 +#define HSO_PORT_CONTROL 0x1 +#define HSO_PORT_APP 0x2 +#define HSO_PORT_GPS 0x3 +#define HSO_PORT_PCSC 0x4 +#define HSO_PORT_APP2 0x5 +#define HSO_PORT_GPS_CONTROL 0x6 +#define HSO_PORT_MSD 0x7 +#define HSO_PORT_VOICE 0x8 +#define HSO_PORT_DIAG2 0x9 +#define HSO_PORT_DIAG 0x10 +#define HSO_PORT_MODEM 0x11 +#define HSO_PORT_NETWORK 0x12 + +/* Additional device info */ +#define HSO_INFO_MASK 0xFF000000 +#define HSO_INFO_CRC_BUG 0x01000000 + +/*****************************************************************************/ +/* Prototypes */ +/*****************************************************************************/ +/* Serial driver functions */ +static int hso_serial_tiocmset(struct tty_struct *tty, struct file *file, + unsigned int set, unsigned int clear); +static void ctrl_callback(struct urb *urb); +static void put_rxbuf_data(struct urb *urb, struct hso_serial *serial); +static void hso_kick_transmit(struct hso_serial *serial); +/* Helper functions */ +static int hso_mux_submit_intr_urb(struct hso_shared_int *mux_int, + struct usb_device *usb, gfp_t gfp); +static void log_usb_status(int status, const char *function); +static struct usb_endpoint_descriptor *hso_get_ep(struct usb_interface *intf, + int type, int dir); +static int hso_get_mux_ports(struct usb_interface *intf, unsigned char *ports); +static void hso_free_interface(struct usb_interface *intf); +static int hso_start_serial_device(struct hso_device *hso_dev, gfp_t flags); +static int hso_stop_serial_device(struct hso_device *hso_dev); +static int hso_start_net_device(struct hso_device *hso_dev); +static void hso_free_shared_int(struct hso_shared_int *shared_int); +static int hso_stop_net_device(struct hso_device *hso_dev); +static void hso_serial_ref_free(struct kref *ref); +static void async_get_intf(struct work_struct *data); +static void async_put_intf(struct work_struct *data); +static int hso_put_activity(struct hso_device *hso_dev); +static int hso_get_activity(struct hso_device *hso_dev); + +/*****************************************************************************/ +/* Helping functions */ +/*****************************************************************************/ + +/* #define DEBUG */ + +#define dev2net(x) (x->port_data.dev_net) +#define dev2ser(x) (x->port_data.dev_serial) + +/* Debugging functions */ +#ifdef DEBUG +static void dbg_dump(int line_count, const char *func_name, unsigned char *buf, + unsigned int len) +{ + u8 i = 0; + + printk(KERN_DEBUG "[%d:%s]: len %d", line_count, func_name, len); + + for (i = 0; i < len; i++) { + if (!(i % 16)) + printk("\n 0x%03x: ", i); + printk("%02x ", (unsigned char)buf[i]); + } + printk("\n"); +} + +#define DUMP(buf_, len_) \ + dbg_dump(__LINE__, __func__, buf_, len_) + +#define DUMP1(buf_, len_) \ + do { \ + if (0x01 & debug) \ + DUMP(buf_, len_); \ + } while (0) +#else +#define DUMP(buf_, len_) +#define DUMP1(buf_, len_) +#endif + +/* module parameters */ +static int debug; +static int tty_major; +static int disable_net; + +/* driver info */ +static const char driver_name[] = "hso"; +static const char tty_filename[] = "ttyHS"; +static const char *version = __FILE__ ": " DRIVER_VERSION " " MOD_AUTHOR; +/* the usb driver itself (registered in hso_init) */ +static struct usb_driver hso_driver; +/* serial structures */ +static struct tty_driver *tty_drv; +static struct hso_device *serial_table[HSO_SERIAL_TTY_MINORS]; +static struct hso_device *network_table[HSO_MAX_NET_DEVICES]; +static spinlock_t serial_table_lock; +static struct ktermios *hso_serial_termios[HSO_SERIAL_TTY_MINORS]; +static struct ktermios *hso_serial_termios_locked[HSO_SERIAL_TTY_MINORS]; + +static const s32 default_port_spec[] = { + HSO_INTF_MUX | HSO_PORT_NETWORK, + HSO_INTF_BULK | HSO_PORT_DIAG, + HSO_INTF_BULK | HSO_PORT_MODEM, + 0 +}; + +static const s32 icon321_port_spec[] = { + HSO_INTF_MUX | HSO_PORT_NETWORK, + HSO_INTF_BULK | HSO_PORT_DIAG2, + HSO_INTF_BULK | HSO_PORT_MODEM, + HSO_INTF_BULK | HSO_PORT_DIAG, + 0 +}; + +#define default_port_device(vendor, product) \ + USB_DEVICE(vendor, product), \ + .driver_info = (kernel_ulong_t)default_port_spec + +#define icon321_port_device(vendor, product) \ + USB_DEVICE(vendor, product), \ + .driver_info = (kernel_ulong_t)icon321_port_spec + +/* list of devices we support */ +static const struct usb_device_id hso_ids[] = { + {default_port_device(0x0af0, 0x6711)}, + {default_port_device(0x0af0, 0x6731)}, + {default_port_device(0x0af0, 0x6751)}, + {default_port_device(0x0af0, 0x6771)}, + {default_port_device(0x0af0, 0x6791)}, + {default_port_device(0x0af0, 0x6811)}, + {default_port_device(0x0af0, 0x6911)}, + {default_port_device(0x0af0, 0x6951)}, + {default_port_device(0x0af0, 0x6971)}, + {default_port_device(0x0af0, 0x7011)}, + {default_port_device(0x0af0, 0x7031)}, + {default_port_device(0x0af0, 0x7051)}, + {default_port_device(0x0af0, 0x7071)}, + {default_port_device(0x0af0, 0x7111)}, + {default_port_device(0x0af0, 0x7211)}, + {default_port_device(0x0af0, 0x7251)}, + {default_port_device(0x0af0, 0x7271)}, + {default_port_device(0x0af0, 0x7311)}, + {default_port_device(0x0af0, 0xc031)}, /* Icon-Edge */ + {icon321_port_device(0x0af0, 0xd013)}, /* Module HSxPA */ + {icon321_port_device(0x0af0, 0xd031)}, /* Icon-321 */ + {default_port_device(0x0af0, 0xd033)}, /* Icon-322 */ + {USB_DEVICE(0x0af0, 0x7301)}, /* GE40x */ + {USB_DEVICE(0x0af0, 0x7361)}, /* GE40x */ + {USB_DEVICE(0x0af0, 0x7401)}, /* GI 0401 */ + {USB_DEVICE(0x0af0, 0x7501)}, /* GTM 382 */ + {USB_DEVICE(0x0af0, 0x7601)}, /* GE40x */ + {} +}; +MODULE_DEVICE_TABLE(usb, hso_ids); + +/* Sysfs attribute */ +static ssize_t hso_sysfs_show_porttype(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct hso_device *hso_dev = dev->driver_data; + char *port_name; + + if (!hso_dev) + return 0; + + switch (hso_dev->port_spec & HSO_PORT_MASK) { + case HSO_PORT_CONTROL: + port_name = "Control"; + break; + case HSO_PORT_APP: + port_name = "Application"; + break; + case HSO_PORT_APP2: + port_name = "Application2"; + break; + case HSO_PORT_GPS: + port_name = "GPS"; + break; + case HSO_PORT_GPS_CONTROL: + port_name = "GPS Control"; + break; + case HSO_PORT_PCSC: + port_name = "PCSC"; + break; + case HSO_PORT_DIAG: + port_name = "Diagnostic"; + break; + case HSO_PORT_DIAG2: + port_name = "Diagnostic2"; + break; + case HSO_PORT_MODEM: + port_name = "Modem"; + break; + case HSO_PORT_NETWORK: + port_name = "Network"; + break; + default: + port_name = "Unknown"; + break; + } + + return sprintf(buf, "%s\n", port_name); +} +static DEVICE_ATTR(hsotype, S_IRUGO, hso_sysfs_show_porttype, NULL); + +/* converts mux value to a port spec value */ +static u32 hso_mux_to_port(int mux) +{ + u32 result; + + switch (mux) { + case 0x1: + result = HSO_PORT_CONTROL; + break; + case 0x2: + result = HSO_PORT_APP; + break; + case 0x4: + result = HSO_PORT_PCSC; + break; + case 0x8: + result = HSO_PORT_GPS; + break; + case 0x10: + result = HSO_PORT_APP2; + break; + default: + result = HSO_PORT_NO_PORT; + } + return result; +} + +/* converts port spec value to a mux value */ +static u32 hso_port_to_mux(int port) +{ + u32 result; + + switch (port & HSO_PORT_MASK) { + case HSO_PORT_CONTROL: + result = 0x0; + break; + case HSO_PORT_APP: + result = 0x1; + break; + case HSO_PORT_PCSC: + result = 0x2; + break; + case HSO_PORT_GPS: + result = 0x3; + break; + case HSO_PORT_APP2: + result = 0x4; + break; + default: + result = 0x0; + } + return result; +} + +static struct hso_serial *get_serial_by_shared_int_and_type( + struct hso_shared_int *shared_int, + int mux) +{ + int i, port; + + port = hso_mux_to_port(mux); + + for (i = 0; i < HSO_SERIAL_TTY_MINORS; i++) { + if (serial_table[i] + && (dev2ser(serial_table[i])->shared_int == shared_int) + && ((serial_table[i]->port_spec & HSO_PORT_MASK) == port)) { + return dev2ser(serial_table[i]); + } + } + + return NULL; +} + +static struct hso_serial *get_serial_by_index(unsigned index) +{ + struct hso_serial *serial; + unsigned long flags; + + if (!serial_table[index]) + return NULL; + spin_lock_irqsave(&serial_table_lock, flags); + serial = dev2ser(serial_table[index]); + spin_unlock_irqrestore(&serial_table_lock, flags); + + return serial; +} + +static int get_free_serial_index(void) +{ + int index; + unsigned long flags; + + spin_lock_irqsave(&serial_table_lock, flags); + for (index = 0; index < HSO_SERIAL_TTY_MINORS; index++) { + if (serial_table[index] == NULL) { + spin_unlock_irqrestore(&serial_table_lock, flags); + return index; + } + } + spin_unlock_irqrestore(&serial_table_lock, flags); + + printk(KERN_ERR "%s: no free serial devices in table\n", __func__); + return -1; +} + +static void set_serial_by_index(unsigned index, struct hso_serial *serial) +{ + unsigned long flags; + spin_lock_irqsave(&serial_table_lock, flags); + if (serial) + serial_table[index] = serial->parent; + else + serial_table[index] = NULL; + spin_unlock_irqrestore(&serial_table_lock, flags); +} + +/* log a meaningfull explanation of an USB status */ +static void log_usb_status(int status, const char *function) +{ + char *explanation; + + switch (status) { + case -ENODEV: + explanation = "no device"; + break; + case -ENOENT: + explanation = "endpoint not enabled"; + break; + case -EPIPE: + explanation = "endpoint stalled"; + break; + case -ENOSPC: + explanation = "not enough bandwidth"; + break; + case -ESHUTDOWN: + explanation = "device disabled"; + break; + case -EHOSTUNREACH: + explanation = "device suspended"; + break; + case -EINVAL: + case -EAGAIN: + case -EFBIG: + case -EMSGSIZE: + explanation = "internal error"; + break; + default: + explanation = "unknown status"; + break; + } + D1("%s: received USB status - %s (%d)", function, explanation, status); +} + +/* Network interface functions */ + +/* called when net interface is brought up by ifconfig */ +static int hso_net_open(struct net_device *net) +{ + struct hso_net *odev = netdev_priv(net); + unsigned long flags = 0; + + if (!odev) { + dev_err(&net->dev, "No net device !\n"); + return -ENODEV; + } + + odev->skb_tx_buf = NULL; + + /* setup environment */ + spin_lock_irqsave(&odev->net_lock, flags); + odev->rx_parse_state = WAIT_IP; + odev->rx_buf_size = 0; + odev->rx_buf_missing = sizeof(struct iphdr); + spin_unlock_irqrestore(&odev->net_lock, flags); + + hso_start_net_device(odev->parent); + + /* We are up and running. */ + set_bit(HSO_NET_RUNNING, &odev->flags); + + /* Tell the kernel we are ready to start receiving from it */ + netif_start_queue(net); + + return 0; +} + +/* called when interface is brought down by ifconfig */ +static int hso_net_close(struct net_device *net) +{ + struct hso_net *odev = netdev_priv(net); + + /* we don't need the queue anymore */ + netif_stop_queue(net); + /* no longer running */ + clear_bit(HSO_NET_RUNNING, &odev->flags); + + hso_stop_net_device(odev->parent); + + /* done */ + return 0; +} + +/* USB tells is xmit done, we should start the netqueue again */ +static void write_bulk_callback(struct urb *urb) +{ + struct hso_net *odev = urb->context; + int status = urb->status; + + /* Sanity check */ + if (!odev || !test_bit(HSO_NET_RUNNING, &odev->flags)) { + dev_err(&urb->dev->dev, "%s: device not running\n", __func__); + return; + } + + /* Do we still have a valid kernel network device? */ + if (!netif_device_present(odev->net)) { + dev_err(&urb->dev->dev, "%s: net device not present\n", + __func__); + return; + } + + /* log status, but don't act on it, we don't need to resubmit anything + * anyhow */ + if (status) + log_usb_status(status, __func__); + + hso_put_activity(odev->parent); + + /* Tell the network interface we are ready for another frame */ + netif_wake_queue(odev->net); +} + +/* called by kernel when we need to transmit a packet */ +static int hso_net_start_xmit(struct sk_buff *skb, struct net_device *net) +{ + struct hso_net *odev = netdev_priv(net); + int result; + + /* Tell the kernel, "No more frames 'til we are done with this one." */ + netif_stop_queue(net); + if (hso_get_activity(odev->parent) == -EAGAIN) { + odev->skb_tx_buf = skb; + return 0; + } + + /* log if asked */ + DUMP1(skb->data, skb->len); + /* Copy it from kernel memory to OUR memory */ + memcpy(odev->mux_bulk_tx_buf, skb->data, skb->len); + D1("len: %d/%d", skb->len, MUX_BULK_TX_BUF_SIZE); + + /* Fill in the URB for shipping it out. */ + usb_fill_bulk_urb(odev->mux_bulk_tx_urb, + odev->parent->usb, + usb_sndbulkpipe(odev->parent->usb, + odev->out_endp-> + bEndpointAddress & 0x7F), + odev->mux_bulk_tx_buf, skb->len, write_bulk_callback, + odev); + + /* Deal with the Zero Length packet problem, I hope */ + odev->mux_bulk_tx_urb->transfer_flags |= URB_ZERO_PACKET; + + /* Send the URB on its merry way. */ + result = usb_submit_urb(odev->mux_bulk_tx_urb, GFP_ATOMIC); + if (result) { + dev_warn(&odev->parent->interface->dev, + "failed mux_bulk_tx_urb %d", result); + net->stats.tx_errors++; + netif_start_queue(net); + } else { + net->stats.tx_packets++; + net->stats.tx_bytes += skb->len; + /* And tell the kernel when the last transmit started. */ + net->trans_start = jiffies; + } + dev_kfree_skb(skb); + /* we're done */ + return result; +} + +static void hso_get_drvinfo(struct net_device *net, struct ethtool_drvinfo *info) +{ + struct hso_net *odev = netdev_priv(net); + + strncpy(info->driver, driver_name, ETHTOOL_BUSINFO_LEN); + strncpy(info->version, DRIVER_VERSION, ETHTOOL_BUSINFO_LEN); + usb_make_path(odev->parent->usb, info->bus_info, sizeof info->bus_info); +} + +static struct ethtool_ops ops = { + .get_drvinfo = hso_get_drvinfo, + .get_link = ethtool_op_get_link +}; + +/* called when a packet did not ack after watchdogtimeout */ +static void hso_net_tx_timeout(struct net_device *net) +{ + struct hso_net *odev = netdev_priv(net); + + if (!odev) + return; + + /* Tell syslog we are hosed. */ + dev_warn(&net->dev, "Tx timed out.\n"); + + /* Tear the waiting frame off the list */ + if (odev->mux_bulk_tx_urb + && (odev->mux_bulk_tx_urb->status == -EINPROGRESS)) + usb_unlink_urb(odev->mux_bulk_tx_urb); + + /* Update statistics */ + net->stats.tx_errors++; +} + +/* make a real packet from the received USB buffer */ +static void packetizeRx(struct hso_net *odev, unsigned char *ip_pkt, + unsigned int count, unsigned char is_eop) +{ + unsigned short temp_bytes; + unsigned short buffer_offset = 0; + unsigned short frame_len; + unsigned char *tmp_rx_buf; + + /* log if needed */ + D1("Rx %d bytes", count); + DUMP(ip_pkt, min(128, (int)count)); + + while (count) { + switch (odev->rx_parse_state) { + case WAIT_IP: + /* waiting for IP header. */ + /* wanted bytes - size of ip header */ + temp_bytes = + (count < + odev->rx_buf_missing) ? count : odev-> + rx_buf_missing; + + memcpy(((unsigned char *)(&odev->rx_ip_hdr)) + + odev->rx_buf_size, ip_pkt + buffer_offset, + temp_bytes); + + odev->rx_buf_size += temp_bytes; + buffer_offset += temp_bytes; + odev->rx_buf_missing -= temp_bytes; + count -= temp_bytes; + + if (!odev->rx_buf_missing) { + /* header is complete allocate an sk_buffer and + * continue to WAIT_DATA */ + frame_len = ntohs(odev->rx_ip_hdr.tot_len); + + if ((frame_len > DEFAULT_MRU) || + (frame_len < sizeof(struct iphdr))) { + dev_err(&odev->net->dev, + "Invalid frame (%d) length\n", + frame_len); + odev->rx_parse_state = WAIT_SYNC; + continue; + } + /* Allocate an sk_buff */ + odev->skb_rx_buf = dev_alloc_skb(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. */ + tmp_rx_buf = + skb_put(odev->skb_rx_buf, + sizeof(struct iphdr)); + memcpy(tmp_rx_buf, (char *)&(odev->rx_ip_hdr), + sizeof(struct iphdr)); + + /* ETH_HLEN */ + odev->rx_buf_size = sizeof(struct iphdr); + + /* Filip actually use .tot_len */ + odev->rx_buf_missing = + frame_len - sizeof(struct iphdr); + odev->rx_parse_state = WAIT_DATA; + } + break; + + case WAIT_DATA: + temp_bytes = (count < odev->rx_buf_missing) + ? count : odev->rx_buf_missing; + + /* Copy the rest of the bytes that are left in the + * buffer into the waiting sk_buf. */ + /* Make room for temp_bytes after tail. */ + tmp_rx_buf = skb_put(odev->skb_rx_buf, temp_bytes); + memcpy(tmp_rx_buf, ip_pkt + buffer_offset, temp_bytes); + + odev->rx_buf_missing -= temp_bytes; + count -= temp_bytes; + buffer_offset += temp_bytes; + odev->rx_buf_size += temp_bytes; + if (!odev->rx_buf_missing) { + /* Packet is complete. Inject into stack. */ + /* We have IP packet here */ + odev->skb_rx_buf->protocol = + __constant_htons(ETH_P_IP); + /* don't check it */ + odev->skb_rx_buf->ip_summed = + CHECKSUM_UNNECESSARY; + + skb_reset_mac_header(odev->skb_rx_buf); + + /* Ship it off to the kernel */ + netif_rx(odev->skb_rx_buf); + /* No longer our buffer. */ + odev->skb_rx_buf = NULL; + + /* update out statistics */ + odev->net->stats.rx_packets++; + + odev->net->stats.rx_bytes += odev->rx_buf_size; + + odev->rx_buf_size = 0; + odev->rx_buf_missing = sizeof(struct iphdr); + odev->rx_parse_state = WAIT_IP; + } + break; + + case WAIT_SYNC: + D1(" W_S"); + count = 0; + break; + default: + D1(" "); + count--; + break; + } + } + + /* Recovery mechanism for WAIT_SYNC state. */ + if (is_eop) { + if (odev->rx_parse_state == WAIT_SYNC) { + odev->rx_parse_state = WAIT_IP; + odev->rx_buf_size = 0; + odev->rx_buf_missing = sizeof(struct iphdr); + } + } +} + +/* Moving data from usb to kernel (in interrupt state) */ +static void read_bulk_callback(struct urb *urb) +{ + struct hso_net *odev = urb->context; + struct net_device *net; + int result; + int status = urb->status; + + /* is al ok? (Filip: Who's Al ?) */ + if (status) { + log_usb_status(status, __func__); + return; + } + + /* Sanity check */ + if (!odev || !test_bit(HSO_NET_RUNNING, &odev->flags)) { + D1("BULK IN callback but driver is not active!"); + return; + } + usb_mark_last_busy(urb->dev); + + net = odev->net; + + if (!netif_device_present(net)) { + /* Somebody killed our network interface... */ + return; + } + + if (odev->parent->port_spec & HSO_INFO_CRC_BUG) { + u32 rest; + u8 crc_check[4] = { 0xDE, 0xAD, 0xBE, 0xEF }; + rest = urb->actual_length % odev->in_endp->wMaxPacketSize; + if (((rest == 5) || (rest == 6)) + && !memcmp(((u8 *) urb->transfer_buffer) + + urb->actual_length - 4, crc_check, 4)) { + urb->actual_length -= 4; + } + } + + /* do we even have a packet? */ + if (urb->actual_length) { + /* Handle the IP stream, add header and push it onto network + * stack if the packet is complete. */ + spin_lock(&odev->net_lock); + packetizeRx(odev, urb->transfer_buffer, urb->actual_length, + (urb->transfer_buffer_length > + urb->actual_length) ? 1 : 0); + spin_unlock(&odev->net_lock); + } + + /* We are done with this URB, resubmit it. Prep the USB to wait for + * another frame. Reuse same as received. */ + usb_fill_bulk_urb(urb, + odev->parent->usb, + usb_rcvbulkpipe(odev->parent->usb, + odev->in_endp-> + bEndpointAddress & 0x7F), + urb->transfer_buffer, MUX_BULK_RX_BUF_SIZE, + read_bulk_callback, odev); + + /* Give this to the USB subsystem so it can tell us when more data + * arrives. */ + result = usb_submit_urb(urb, GFP_ATOMIC); + if (result) + dev_warn(&odev->parent->interface->dev, + "%s failed submit mux_bulk_rx_urb %d", __func__, + result); +} + +/* Serial driver functions */ + +static void _hso_serial_set_termios(struct tty_struct *tty, + struct ktermios *old) +{ + struct hso_serial *serial = get_serial_by_tty(tty); + struct ktermios *termios; + + if ((!tty) || (!tty->termios) || (!serial)) { + printk(KERN_ERR "%s: no tty structures", __func__); + return; + } + + D4("port %d", serial->minor); + + /* + * The default requirements for this device are: + */ + termios = tty->termios; + termios->c_iflag &= + ~(IGNBRK /* disable ignore break */ + | BRKINT /* disable break causes interrupt */ + | PARMRK /* disable mark parity errors */ + | ISTRIP /* disable clear high bit of input characters */ + | INLCR /* disable translate NL to CR */ + | IGNCR /* disable ignore CR */ + | ICRNL /* disable translate CR to NL */ + | IXON); /* disable enable XON/XOFF flow control */ + + /* disable postprocess output characters */ + termios->c_oflag &= ~OPOST; + + termios->c_lflag &= + ~(ECHO /* disable echo input characters */ + | ECHONL /* disable echo new line */ + | ICANON /* disable erase, kill, werase, and rprnt + special characters */ + | ISIG /* disable interrupt, quit, and suspend special + characters */ + | IEXTEN); /* disable non-POSIX special characters */ + + termios->c_cflag &= + ~(CSIZE /* no size */ + | PARENB /* disable parity bit */ + | CBAUD /* clear current baud rate */ + | CBAUDEX); /* clear current buad rate */ + + termios->c_cflag |= CS8; /* character size 8 bits */ + + /* baud rate 115200 */ + tty_encode_baud_rate(serial->tty, 115200, 115200); + + /* + * Force low_latency on; otherwise the pushes are scheduled; + * this is bad as it opens up the possibility of dropping bytes + * on the floor. We don't want to drop bytes on the floor. :) + */ + serial->tty->low_latency = 1; + return; +} + +/* open the requested serial port */ +static int hso_serial_open(struct tty_struct *tty, struct file *filp) +{ + struct hso_serial *serial = get_serial_by_index(tty->index); + int result; + + /* sanity check */ + if (serial == NULL || serial->magic != HSO_SERIAL_MAGIC) { + tty->driver_data = NULL; + D1("Failed to open port"); + return -ENODEV; + } + + mutex_lock(&serial->parent->mutex); + result = usb_autopm_get_interface(serial->parent->interface); + if (result < 0) + goto err_out; + + D1("Opening %d", serial->minor); + kref_get(&serial->parent->ref); + + /* setup */ + tty->driver_data = serial; + serial->tty = tty; + + /* check for port allready opened, if not set the termios */ + serial->open_count++; + if (serial->open_count == 1) { + tty->low_latency = 1; + serial->flags = 0; + /* Force default termio settings */ + _hso_serial_set_termios(tty, NULL); + result = hso_start_serial_device(serial->parent, GFP_KERNEL); + if (result) { + hso_stop_serial_device(serial->parent); + serial->open_count--; + kref_put(&serial->parent->ref, hso_serial_ref_free); + } + } else { + D1("Port was already open"); + } + + usb_autopm_put_interface(serial->parent->interface); + + /* done */ + if (result) + hso_serial_tiocmset(tty, NULL, TIOCM_RTS | TIOCM_DTR, 0); +err_out: + mutex_unlock(&serial->parent->mutex); + return result; +} + +/* close the requested serial port */ +static void hso_serial_close(struct tty_struct *tty, struct file *filp) +{ + struct hso_serial *serial = tty->driver_data; + u8 usb_gone; + + D1("Closing serial port"); + + mutex_lock(&serial->parent->mutex); + usb_gone = serial->parent->usb_gone; + + if (!usb_gone) + usb_autopm_get_interface(serial->parent->interface); + + /* reset the rts and dtr */ + /* do the actual close */ + serial->open_count--; + if (serial->open_count <= 0) { + kref_put(&serial->parent->ref, hso_serial_ref_free); + serial->open_count = 0; + if (serial->tty) { + serial->tty->driver_data = NULL; + serial->tty = NULL; + } + if (!usb_gone) + hso_stop_serial_device(serial->parent); + } + if (!usb_gone) + usb_autopm_put_interface(serial->parent->interface); + mutex_unlock(&serial->parent->mutex); +} + +/* close the requested serial port */ +static int hso_serial_write(struct tty_struct *tty, const unsigned char *buf, + int count) +{ + struct hso_serial *serial = get_serial_by_tty(tty); + int space, tx_bytes; + unsigned long flags; + + /* sanity check */ + if (serial == NULL) { + printk(KERN_ERR "%s: serial is NULL\n", __func__); + return -ENODEV; + } + + spin_lock_irqsave(&serial->serial_lock, flags); + + space = serial->tx_data_length - serial->tx_buffer_count; + tx_bytes = (count < space) ? count : space; + + if (!tx_bytes) + goto out; + + memcpy(serial->tx_buffer + serial->tx_buffer_count, buf, tx_bytes); + serial->tx_buffer_count += tx_bytes; + +out: + spin_unlock_irqrestore(&serial->serial_lock, flags); + + hso_kick_transmit(serial); + /* done */ + return tx_bytes; +} + +/* how much room is there for writing */ +static int hso_serial_write_room(struct tty_struct *tty) +{ + struct hso_serial *serial = get_serial_by_tty(tty); + int room; + unsigned long flags; + + spin_lock_irqsave(&serial->serial_lock, flags); + room = serial->tx_data_length - serial->tx_buffer_count; + spin_unlock_irqrestore(&serial->serial_lock, flags); + + /* return free room */ + return room; +} + +/* setup the term */ +static void hso_serial_set_termios(struct tty_struct *tty, struct ktermios *old) +{ + struct hso_serial *serial = get_serial_by_tty(tty); + unsigned long flags; + + if (old) + D5("Termios called with: cflags new[%d] - old[%d]", + tty->termios->c_cflag, old->c_cflag); + + /* the actual setup */ + spin_lock_irqsave(&serial->serial_lock, flags); + if (serial->open_count) + _hso_serial_set_termios(tty, old); + else + tty->termios = old; + spin_unlock_irqrestore(&serial->serial_lock, flags); + + /* done */ + return; +} + +/* how many characters in the buffer */ +static int hso_serial_chars_in_buffer(struct tty_struct *tty) +{ + struct hso_serial *serial = get_serial_by_tty(tty); + int chars; + unsigned long flags; + + /* sanity check */ + if (serial == NULL) + return 0; + + spin_lock_irqsave(&serial->serial_lock, flags); + chars = serial->tx_buffer_count; + spin_unlock_irqrestore(&serial->serial_lock, flags); + + return chars; +} + +static int hso_serial_tiocmget(struct tty_struct *tty, struct file *file) +{ + unsigned int value; + struct hso_serial *serial = get_serial_by_tty(tty); + unsigned long flags; + + /* sanity check */ + if (!serial) { + D1("no tty structures"); + return -EINVAL; + } + + spin_lock_irqsave(&serial->serial_lock, flags); + value = ((serial->rts_state) ? TIOCM_RTS : 0) | + ((serial->dtr_state) ? TIOCM_DTR : 0); + spin_unlock_irqrestore(&serial->serial_lock, flags); + + return value; +} + +static int hso_serial_tiocmset(struct tty_struct *tty, struct file *file, + unsigned int set, unsigned int clear) +{ + int val = 0; + unsigned long flags; + int if_num; + struct hso_serial *serial = get_serial_by_tty(tty); + + /* sanity check */ + if (!serial) { + D1("no tty structures"); + return -EINVAL; + } + if_num = serial->parent->interface->altsetting->desc.bInterfaceNumber; + + spin_lock_irqsave(&serial->serial_lock, flags); + if (set & TIOCM_RTS) + serial->rts_state = 1; + if (set & TIOCM_DTR) + serial->dtr_state = 1; + + if (clear & TIOCM_RTS) + serial->rts_state = 0; + if (clear & TIOCM_DTR) + serial->dtr_state = 0; + + if (serial->dtr_state) + val |= 0x01; + if (serial->rts_state) + val |= 0x02; + + spin_unlock_irqrestore(&serial->serial_lock, flags); + + return usb_control_msg(serial->parent->usb, + usb_rcvctrlpipe(serial->parent->usb, 0), 0x22, + 0x21, val, if_num, NULL, 0, + USB_CTRL_SET_TIMEOUT); +} + +/* starts a transmit */ +static void hso_kick_transmit(struct hso_serial *serial) +{ + u8 *temp; + unsigned long flags; + int res; + + spin_lock_irqsave(&serial->serial_lock, flags); + if (!serial->tx_buffer_count) + goto out; + + if (serial->tx_urb_used) + goto out; + + /* Wakeup USB interface if necessary */ + if (hso_get_activity(serial->parent) == -EAGAIN) + goto out; + + /* Switch pointers around to avoid memcpy */ + temp = serial->tx_buffer; + serial->tx_buffer = serial->tx_data; + serial->tx_data = temp; + serial->tx_data_count = serial->tx_buffer_count; + serial->tx_buffer_count = 0; + + /* If temp is set, it means we switched buffers */ + if (temp && serial->write_data) { + res = serial->write_data(serial); + if (res >= 0) + serial->tx_urb_used = 1; + } +out: + spin_unlock_irqrestore(&serial->serial_lock, flags); +} + +/* make a request (for reading and writing data to muxed serial port) */ +static int mux_device_request(struct hso_serial *serial, u8 type, u16 port, + struct urb *ctrl_urb, + struct usb_ctrlrequest *ctrl_req, + u8 *ctrl_urb_data, u32 size) +{ + int result; + int pipe; + + /* Sanity check */ + if (!serial || !ctrl_urb || !ctrl_req) { + printk(KERN_ERR "%s: Wrong arguments\n", __func__); + return -EINVAL; + } + + /* initialize */ + ctrl_req->wValue = 0; + ctrl_req->wIndex = hso_port_to_mux(port); + ctrl_req->wLength = size; + + if (type == USB_CDC_GET_ENCAPSULATED_RESPONSE) { + /* Reading command */ + ctrl_req->bRequestType = USB_DIR_IN | + USB_TYPE_OPTION_VENDOR | + USB_RECIP_INTERFACE; + ctrl_req->bRequest = USB_CDC_GET_ENCAPSULATED_RESPONSE; + pipe = usb_rcvctrlpipe(serial->parent->usb, 0); + } else { + /* Writing command */ + ctrl_req->bRequestType = USB_DIR_OUT | + USB_TYPE_OPTION_VENDOR | + USB_RECIP_INTERFACE; + ctrl_req->bRequest = USB_CDC_SEND_ENCAPSULATED_COMMAND; + pipe = usb_sndctrlpipe(serial->parent->usb, 0); + } + /* syslog */ + D2("%s command (%02x) len: %d, port: %d", + type == USB_CDC_GET_ENCAPSULATED_RESPONSE ? "Read" : "Write", + ctrl_req->bRequestType, ctrl_req->wLength, port); + + /* Load ctrl urb */ + ctrl_urb->transfer_flags = 0; + usb_fill_control_urb(ctrl_urb, + serial->parent->usb, + pipe, + (u8 *) ctrl_req, + ctrl_urb_data, size, ctrl_callback, serial); + /* Send it on merry way */ + result = usb_submit_urb(ctrl_urb, GFP_ATOMIC); + if (result) { + dev_err(&ctrl_urb->dev->dev, + "%s failed submit ctrl_urb %d type %d", __func__, + result, type); + return result; + } + + /* done */ + return size; +} + +/* called by intr_callback when read occurs */ +static int hso_mux_serial_read(struct hso_serial *serial) +{ + if (!serial) + return -EINVAL; + + /* clean data */ + memset(serial->rx_data[0], 0, CTRL_URB_RX_SIZE); + /* make the request */ + + if (serial->num_rx_urbs != 1) { + dev_err(&serial->parent->interface->dev, + "ERROR: mux'd reads with multiple buffers " + "not possible\n"); + return 0; + } + return mux_device_request(serial, + USB_CDC_GET_ENCAPSULATED_RESPONSE, + serial->parent->port_spec & HSO_PORT_MASK, + serial->rx_urb[0], + &serial->ctrl_req_rx, + serial->rx_data[0], serial->rx_data_length); +} + +/* used for muxed serial port callback (muxed serial read) */ +static void intr_callback(struct urb *urb) +{ + struct hso_shared_int *shared_int = urb->context; + struct hso_serial *serial; + unsigned char *port_req; + int status = urb->status; + int i; + + usb_mark_last_busy(urb->dev); + + /* sanity check */ + if (!shared_int) + return; + + /* status check */ + if (status) { + log_usb_status(status, __func__); + return; + } + D4("\n--- Got intr callback 0x%02X ---", status); + + /* what request? */ + port_req = urb->transfer_buffer; + D4(" port_req = 0x%.2X\n", *port_req); + /* loop over all muxed ports to find the one sending this */ + for (i = 0; i < 8; i++) { + /* max 8 channels on MUX */ + if (*port_req & (1 << i)) { + serial = get_serial_by_shared_int_and_type(shared_int, + (1 << i)); + if (serial != NULL) { + D1("Pending read interrupt on port %d\n", i); + if (!test_and_set_bit(HSO_SERIAL_FLAG_RX_SENT, + &serial->flags)) { + /* Setup and send a ctrl req read on + * port i */ + hso_mux_serial_read(serial); + } else { + D1("Already pending a read on " + "port %d\n", i); + } + } + } + } + /* Resubmit interrupt urb */ + hso_mux_submit_intr_urb(shared_int, urb->dev, GFP_ATOMIC); +} + +/* called for writing to muxed serial port */ +static int hso_mux_serial_write_data(struct hso_serial *serial) +{ + if (NULL == serial) + return -EINVAL; + + return mux_device_request(serial, + USB_CDC_SEND_ENCAPSULATED_COMMAND, + serial->parent->port_spec & HSO_PORT_MASK, + serial->tx_urb, + &serial->ctrl_req_tx, + serial->tx_data, serial->tx_data_count); +} + +/* write callback for Diag and CS port */ +static void hso_std_serial_write_bulk_callback(struct urb *urb) +{ + struct hso_serial *serial = urb->context; + int status = urb->status; + + /* sanity check */ + if (!serial) { + D1("serial == NULL"); + return; + } + + spin_lock(&serial->serial_lock); + serial->tx_urb_used = 0; + spin_unlock(&serial->serial_lock); + if (status) { + log_usb_status(status, __func__); + return; + } + hso_put_activity(serial->parent); + tty_wakeup(serial->tty); + hso_kick_transmit(serial); + + D1(" "); + return; +} + +/* called for writing diag or CS serial port */ +static int hso_std_serial_write_data(struct hso_serial *serial) +{ + int count = serial->tx_data_count; + int result; + + usb_fill_bulk_urb(serial->tx_urb, + serial->parent->usb, + usb_sndbulkpipe(serial->parent->usb, + serial->out_endp-> + bEndpointAddress & 0x7F), + serial->tx_data, serial->tx_data_count, + hso_std_serial_write_bulk_callback, serial); + + result = usb_submit_urb(serial->tx_urb, GFP_ATOMIC); + if (result) { + dev_warn(&serial->parent->usb->dev, + "Failed to submit urb - res %d\n", result); + return result; + } + + return count; +} + +/* callback after read or write on muxed serial port */ +static void ctrl_callback(struct urb *urb) +{ + struct hso_serial *serial = urb->context; + struct usb_ctrlrequest *req; + int status = urb->status; + + /* sanity check */ + if (!serial) + return; + + spin_lock(&serial->serial_lock); + serial->tx_urb_used = 0; + spin_unlock(&serial->serial_lock); + if (status) { + log_usb_status(status, __func__); + return; + } + + /* what request? */ + req = (struct usb_ctrlrequest *)(urb->setup_packet); + D4("\n--- Got muxed ctrl callback 0x%02X ---", status); + D4("Actual length of urb = %d\n", urb->actual_length); + DUMP1(urb->transfer_buffer, urb->actual_length); + + if (req->bRequestType == + (USB_DIR_IN | USB_TYPE_OPTION_VENDOR | USB_RECIP_INTERFACE)) { + /* response to a read command */ + if (serial->open_count > 0) { + /* handle RX data the normal way */ + put_rxbuf_data(urb, serial); + } + + /* Re issue a read as long as we receive data. */ + if (urb->actual_length != 0) + hso_mux_serial_read(serial); + else + clear_bit(HSO_SERIAL_FLAG_RX_SENT, &serial->flags); + } else { + hso_put_activity(serial->parent); + tty_wakeup(serial->tty); + /* response to a write command */ + hso_kick_transmit(serial); + } +} + +/* handle RX data for serial port */ +static void put_rxbuf_data(struct urb *urb, struct hso_serial *serial) +{ + struct tty_struct *tty = serial->tty; + + /* Sanity check */ + if (urb == NULL || serial == NULL) { + D1("serial = NULL"); + return; + } + + /* Push data to tty */ + if (tty && urb->actual_length) { + D1("data to push to tty"); + tty_insert_flip_string(tty, urb->transfer_buffer, + urb->actual_length); + tty_flip_buffer_push(tty); + } +} + +/* read callback for Diag and CS port */ +static void hso_std_serial_read_bulk_callback(struct urb *urb) +{ + struct hso_serial *serial = urb->context; + int result; + int status = urb->status; + + /* sanity check */ + if (!serial) { + D1("serial == NULL"); + return; + } else if (status) { + log_usb_status(status, __func__); + return; + } + + D4("\n--- Got serial_read_bulk callback %02x ---", status); + D1("Actual length = %d\n", urb->actual_length); + DUMP1(urb->transfer_buffer, urb->actual_length); + + /* Anyone listening? */ + if (serial->open_count == 0) + return; + + if (status == 0) { + if (serial->parent->port_spec & HSO_INFO_CRC_BUG) { + u32 rest; + u8 crc_check[4] = { 0xDE, 0xAD, 0xBE, 0xEF }; + rest = + urb->actual_length % + serial->in_endp->wMaxPacketSize; + if (((rest == 5) || (rest == 6)) + && !memcmp(((u8 *) urb->transfer_buffer) + + urb->actual_length - 4, crc_check, 4)) { + urb->actual_length -= 4; + } + } + /* Valid data, handle RX data */ + put_rxbuf_data(urb, serial); + } else if (status == -ENOENT || status == -ECONNRESET) { + /* Unlinked - check for throttled port. */ + D2("Port %d, successfully unlinked urb", serial->minor); + } else { + D2("Port %d, status = %d for read urb", serial->minor, status); + return; + } + + usb_mark_last_busy(urb->dev); + + /* We are done with this URB, resubmit it. Prep the USB to wait for + * another frame */ + usb_fill_bulk_urb(urb, serial->parent->usb, + usb_rcvbulkpipe(serial->parent->usb, + serial->in_endp-> + bEndpointAddress & 0x7F), + urb->transfer_buffer, serial->rx_data_length, + hso_std_serial_read_bulk_callback, serial); + /* Give this to the USB subsystem so it can tell us when more data + * arrives. */ + result = usb_submit_urb(urb, GFP_ATOMIC); + if (result) { + dev_err(&urb->dev->dev, "%s failed submit serial rx_urb %d", + __func__, result); + } +} + +/* Base driver functions */ + +static void hso_log_port(struct hso_device *hso_dev) +{ + char *port_type; + char port_dev[20]; + + switch (hso_dev->port_spec & HSO_PORT_MASK) { + case HSO_PORT_CONTROL: + port_type = "Control"; + break; + case HSO_PORT_APP: + port_type = "Application"; + break; + case HSO_PORT_GPS: + port_type = "GPS"; + break; + case HSO_PORT_GPS_CONTROL: + port_type = "GPS control"; + break; + case HSO_PORT_APP2: + port_type = "Application2"; + break; + case HSO_PORT_PCSC: + port_type = "PCSC"; + break; + case HSO_PORT_DIAG: + port_type = "Diagnostic"; + break; + case HSO_PORT_DIAG2: + port_type = "Diagnostic2"; + break; + case HSO_PORT_MODEM: + port_type = "Modem"; + break; + case HSO_PORT_NETWORK: + port_type = "Network"; + break; + default: + port_type = "Unknown"; + break; + } + if ((hso_dev->port_spec & HSO_PORT_MASK) == HSO_PORT_NETWORK) { + sprintf(port_dev, "%s", dev2net(hso_dev)->net->name); + } else + sprintf(port_dev, "/dev/%s%d", tty_filename, + dev2ser(hso_dev)->minor); + + dev_dbg(&hso_dev->interface->dev, "HSO: Found %s port %s\n", + port_type, port_dev); +} + +static int hso_start_net_device(struct hso_device *hso_dev) +{ + int i, result = 0; + struct hso_net *hso_net = dev2net(hso_dev); + + if (!hso_net) + return -ENODEV; + + /* send URBs for all read buffers */ + for (i = 0; i < MUX_BULK_RX_BUF_COUNT; i++) { + + /* Prep a receive URB */ + usb_fill_bulk_urb(hso_net->mux_bulk_rx_urb_pool[i], + hso_dev->usb, + usb_rcvbulkpipe(hso_dev->usb, + hso_net->in_endp-> + bEndpointAddress & 0x7F), + hso_net->mux_bulk_rx_buf_pool[i], + MUX_BULK_RX_BUF_SIZE, read_bulk_callback, + hso_net); + + /* Put it out there so the device can send us stuff */ + result = usb_submit_urb(hso_net->mux_bulk_rx_urb_pool[i], + GFP_NOIO); + if (result) + dev_warn(&hso_dev->usb->dev, + "%s failed mux_bulk_rx_urb[%d] %d\n", __func__, + i, result); + } + + return result; +} + +static int hso_stop_net_device(struct hso_device *hso_dev) +{ + int i; + struct hso_net *hso_net = dev2net(hso_dev); + + if (!hso_net) + return -ENODEV; + + for (i = 0; i < MUX_BULK_RX_BUF_COUNT; i++) { + if (hso_net->mux_bulk_rx_urb_pool[i]) + usb_kill_urb(hso_net->mux_bulk_rx_urb_pool[i]); + + } + if (hso_net->mux_bulk_tx_urb) + usb_kill_urb(hso_net->mux_bulk_tx_urb); + + return 0; +} + +static int hso_start_serial_device(struct hso_device *hso_dev, gfp_t flags) +{ + int i, result = 0; + struct hso_serial *serial = dev2ser(hso_dev); + + if (!serial) + return -ENODEV; + + /* If it is not the MUX port fill in and submit a bulk urb (already + * allocated in hso_serial_start) */ + if (!(serial->parent->port_spec & HSO_INTF_MUX)) { + for (i = 0; i < serial->num_rx_urbs; i++) { + usb_fill_bulk_urb(serial->rx_urb[i], + serial->parent->usb, + usb_rcvbulkpipe(serial->parent->usb, + serial->in_endp-> + bEndpointAddress & + 0x7F), + serial->rx_data[i], + serial->rx_data_length, + hso_std_serial_read_bulk_callback, + serial); + result = usb_submit_urb(serial->rx_urb[i], flags); + if (result) { + dev_warn(&serial->parent->usb->dev, + "Failed to submit urb - res %d\n", + result); + break; + } + } + } else { + mutex_lock(&serial->shared_int->shared_int_lock); + if (!serial->shared_int->use_count) { + result = + hso_mux_submit_intr_urb(serial->shared_int, + hso_dev->usb, flags); + } + serial->shared_int->use_count++; + mutex_unlock(&serial->shared_int->shared_int_lock); + } + + return result; +} + +static int hso_stop_serial_device(struct hso_device *hso_dev) +{ + int i; + struct hso_serial *serial = dev2ser(hso_dev); + + if (!serial) + return -ENODEV; + + for (i = 0; i < serial->num_rx_urbs; i++) { + if (serial->rx_urb[i]) + usb_kill_urb(serial->rx_urb[i]); + } + + if (serial->tx_urb) + usb_kill_urb(serial->tx_urb); + + if (serial->shared_int) { + mutex_lock(&serial->shared_int->shared_int_lock); + if (serial->shared_int->use_count && + (--serial->shared_int->use_count == 0)) { + struct urb *urb; + + urb = serial->shared_int->shared_intr_urb; + if (urb) + usb_kill_urb(urb); + } + mutex_unlock(&serial->shared_int->shared_int_lock); + } + + return 0; +} + +static void hso_serial_common_free(struct hso_serial *serial) +{ + int i; + + if (serial->parent->dev) + device_remove_file(serial->parent->dev, &dev_attr_hsotype); + + tty_unregister_device(tty_drv, serial->minor); + + for (i = 0; i < serial->num_rx_urbs; i++) { + /* unlink and free RX URB */ + usb_free_urb(serial->rx_urb[i]); + /* free the RX buffer */ + kfree(serial->rx_data[i]); + } + + /* unlink and free TX URB */ + usb_free_urb(serial->tx_urb); + kfree(serial->tx_data); +} + +static int hso_serial_common_create(struct hso_serial *serial, int num_urbs, + int rx_size, int tx_size) +{ + struct device *dev; + int minor; + int i; + + minor = get_free_serial_index(); + if (minor < 0) + goto exit; + + /* register our minor number */ + serial->parent->dev = tty_register_device(tty_drv, minor, + &serial->parent->interface->dev); + dev = serial->parent->dev; + dev->driver_data = serial->parent; + i = device_create_file(dev, &dev_attr_hsotype); + + /* fill in specific data for later use */ + serial->minor = minor; + serial->magic = HSO_SERIAL_MAGIC; + spin_lock_init(&serial->serial_lock); + serial->num_rx_urbs = num_urbs; + + /* RX, allocate urb and initialize */ + + /* prepare our RX buffer */ + serial->rx_data_length = rx_size; + for (i = 0; i < serial->num_rx_urbs; i++) { + serial->rx_urb[i] = usb_alloc_urb(0, GFP_KERNEL); + if (!serial->rx_urb[i]) { + dev_err(dev, "Could not allocate urb?\n"); + goto exit; + } + serial->rx_urb[i]->transfer_buffer = NULL; + serial->rx_urb[i]->transfer_buffer_length = 0; + serial->rx_data[i] = kzalloc(serial->rx_data_length, + GFP_KERNEL); + if (!serial->rx_data[i]) { + dev_err(dev, "%s - Out of memory\n", __func__); + goto exit; + } + } + + /* TX, allocate urb and initialize */ + serial->tx_urb = usb_alloc_urb(0, GFP_KERNEL); + if (!serial->tx_urb) { + dev_err(dev, "Could not allocate urb?\n"); + goto exit; + } + serial->tx_urb->transfer_buffer = NULL; + serial->tx_urb->transfer_buffer_length = 0; + /* prepare our TX buffer */ + serial->tx_data_count = 0; + serial->tx_buffer_count = 0; + serial->tx_data_length = tx_size; + serial->tx_data = kzalloc(serial->tx_data_length, GFP_KERNEL); + if (!serial->tx_data) { + dev_err(dev, "%s - Out of memory", __func__); + goto exit; + } + serial->tx_buffer = kzalloc(serial->tx_data_length, GFP_KERNEL); + if (!serial->tx_buffer) { + dev_err(dev, "%s - Out of memory", __func__); + goto exit; + } + + return 0; +exit: + hso_serial_common_free(serial); + return -1; +} + +/* Frees a general hso device */ +static void hso_free_device(struct hso_device *hso_dev) +{ + kfree(hso_dev); +} + +/* Creates a general hso device */ +static struct hso_device *hso_create_device(struct usb_interface *intf, + int port_spec) +{ + struct hso_device *hso_dev; + + hso_dev = kzalloc(sizeof(*hso_dev), GFP_ATOMIC); + if (!hso_dev) + return NULL; + + hso_dev->port_spec = port_spec; + hso_dev->usb = interface_to_usbdev(intf); + hso_dev->interface = intf; + kref_init(&hso_dev->ref); + mutex_init(&hso_dev->mutex); + + INIT_WORK(&hso_dev->async_get_intf, async_get_intf); + INIT_WORK(&hso_dev->async_put_intf, async_put_intf); + + return hso_dev; +} + +/* Removes a network device in the network device table */ +static int remove_net_device(struct hso_device *hso_dev) +{ + int i; + + for (i = 0; i < HSO_MAX_NET_DEVICES; i++) { + if (network_table[i] == hso_dev) { + network_table[i] = NULL; + break; + } + } + if (i == HSO_MAX_NET_DEVICES) + return -1; + return 0; +} + +/* Frees our network device */ +static void hso_free_net_device(struct hso_device *hso_dev) +{ + int i; + struct hso_net *hso_net = dev2net(hso_dev); + + if (!hso_net) + return; + + /* start freeing */ + for (i = 0; i < MUX_BULK_RX_BUF_COUNT; i++) { + usb_free_urb(hso_net->mux_bulk_rx_urb_pool[i]); + kfree(hso_net->mux_bulk_rx_buf_pool[i]); + } + usb_free_urb(hso_net->mux_bulk_tx_urb); + kfree(hso_net->mux_bulk_tx_buf); + + remove_net_device(hso_net->parent); + + if (hso_net->net) { + unregister_netdev(hso_net->net); + free_netdev(hso_net->net); + } + + hso_free_device(hso_dev); +} + +/* initialize the network interface */ +static void hso_net_init(struct net_device *net) +{ + struct hso_net *hso_net = netdev_priv(net); + + D1("sizeof hso_net is %d", (int)sizeof(*hso_net)); + + /* fill in the other fields */ + net->open = hso_net_open; + net->stop = hso_net_close; + net->hard_start_xmit = hso_net_start_xmit; + net->tx_timeout = hso_net_tx_timeout; + net->watchdog_timeo = HSO_NET_TX_TIMEOUT; + net->flags = IFF_POINTOPOINT | IFF_NOARP | IFF_MULTICAST; + net->type = ARPHRD_NONE; + net->mtu = DEFAULT_MTU - 14; + net->tx_queue_len = 10; + SET_ETHTOOL_OPS(net, &ops); + + /* and initialize the semaphore */ + spin_lock_init(&hso_net->net_lock); +} + +/* Adds a network device in the network device table */ +static int add_net_device(struct hso_device *hso_dev) +{ + int i; + + for (i = 0; i < HSO_MAX_NET_DEVICES; i++) { + if (network_table[i] == NULL) { + network_table[i] = hso_dev; + break; + } + } + if (i == HSO_MAX_NET_DEVICES) + return -1; + return 0; +} + +static int hso_radio_toggle(void *data, enum rfkill_state state) +{ + struct hso_device *hso_dev = data; + int enabled = (state == RFKILL_STATE_ON); + int rv; + + mutex_lock(&hso_dev->mutex); + if (hso_dev->usb_gone) + rv = 0; + else + rv = usb_control_msg(hso_dev->usb, usb_rcvctrlpipe(hso_dev->usb, 0), + enabled ? 0x82 : 0x81, 0x40, 0, 0, NULL, 0, + USB_CTRL_SET_TIMEOUT); + mutex_unlock(&hso_dev->mutex); + return rv; +} + +/* Creates and sets up everything for rfkill */ +static void hso_create_rfkill(struct hso_device *hso_dev, + struct usb_interface *interface) +{ + struct hso_net *hso_net = dev2net(hso_dev); + struct device *dev = hso_dev->dev; + char *rfkn; + + hso_net->rfkill = rfkill_allocate(&interface_to_usbdev(interface)->dev, + RFKILL_TYPE_WLAN); + if (!hso_net->rfkill) { + dev_err(dev, "%s - Out of memory", __func__); + return; + } + rfkn = kzalloc(20, GFP_KERNEL); + if (!rfkn) { + rfkill_free(hso_net->rfkill); + dev_err(dev, "%s - Out of memory", __func__); + return; + } + snprintf(rfkn, 20, "hso-%d", + interface->altsetting->desc.bInterfaceNumber); + hso_net->rfkill->name = rfkn; + hso_net->rfkill->state = RFKILL_STATE_ON; + hso_net->rfkill->data = hso_dev; + hso_net->rfkill->toggle_radio = hso_radio_toggle; + if (rfkill_register(hso_net->rfkill) < 0) { + kfree(rfkn); + hso_net->rfkill->name = NULL; + rfkill_free(hso_net->rfkill); + dev_err(dev, "%s - Failed to register rfkill", __func__); + return; + } +} + +/* Creates our network device */ +static struct hso_device *hso_create_net_device(struct usb_interface *interface) +{ + int result, i; + struct net_device *net; + struct hso_net *hso_net; + struct hso_device *hso_dev; + + hso_dev = hso_create_device(interface, HSO_INTF_MUX | HSO_PORT_NETWORK); + if (!hso_dev) + return NULL; + + /* allocate our network device, then we can put in our private data */ + /* call hso_net_init to do the basic initialization */ + net = alloc_netdev(sizeof(struct hso_net), "hso%d", hso_net_init); + if (!net) { + dev_err(&interface->dev, "Unable to create ethernet device\n"); + goto exit; + } + + hso_net = netdev_priv(net); + + hso_dev->port_data.dev_net = hso_net; + hso_net->net = net; + hso_net->parent = hso_dev; + + hso_net->in_endp = hso_get_ep(interface, USB_ENDPOINT_XFER_BULK, + USB_DIR_IN); + if (!hso_net->in_endp) { + dev_err(&interface->dev, "Can't find BULK IN endpoint\n"); + goto exit; + } + hso_net->out_endp = hso_get_ep(interface, USB_ENDPOINT_XFER_BULK, + USB_DIR_OUT); + if (!hso_net->out_endp) { + dev_err(&interface->dev, "Can't find BULK OUT endpoint\n"); + goto exit; + } + SET_NETDEV_DEV(net, &interface->dev); + + /* registering our net device */ + result = register_netdev(net); + if (result) { + dev_err(&interface->dev, "Failed to register device\n"); + goto exit; + } + + /* start allocating */ + for (i = 0; i < MUX_BULK_RX_BUF_COUNT; i++) { + hso_net->mux_bulk_rx_urb_pool[i] = usb_alloc_urb(0, GFP_KERNEL); + if (!hso_net->mux_bulk_rx_urb_pool[i]) { + dev_err(&interface->dev, "Could not allocate rx urb\n"); + goto exit; + } + hso_net->mux_bulk_rx_buf_pool[i] = kzalloc(MUX_BULK_RX_BUF_SIZE, + GFP_KERNEL); + if (!hso_net->mux_bulk_rx_buf_pool[i]) { + dev_err(&interface->dev, "Could not allocate rx buf\n"); + goto exit; + } + } + hso_net->mux_bulk_tx_urb = usb_alloc_urb(0, GFP_KERNEL); + if (!hso_net->mux_bulk_tx_urb) { + dev_err(&interface->dev, "Could not allocate tx urb\n"); + goto exit; + } + hso_net->mux_bulk_tx_buf = kzalloc(MUX_BULK_TX_BUF_SIZE, GFP_KERNEL); + if (!hso_net->mux_bulk_tx_buf) { + dev_err(&interface->dev, "Could not allocate tx buf\n"); + goto exit; + } + + add_net_device(hso_dev); + + hso_log_port(hso_dev); + + hso_create_rfkill(hso_dev, interface); + + return hso_dev; +exit: + hso_free_net_device(hso_dev); + return NULL; +} + +/* Frees an AT channel ( goes for both mux and non-mux ) */ +static void hso_free_serial_device(struct hso_device *hso_dev) +{ + struct hso_serial *serial = dev2ser(hso_dev); + + if (!serial) + return; + set_serial_by_index(serial->minor, NULL); + + hso_serial_common_free(serial); + + if (serial->shared_int) { + mutex_lock(&serial->shared_int->shared_int_lock); + if (--serial->shared_int->ref_count == 0) + hso_free_shared_int(serial->shared_int); + else + mutex_unlock(&serial->shared_int->shared_int_lock); + } + kfree(serial); + hso_free_device(hso_dev); +} + +/* Creates a bulk AT channel */ +static struct hso_device *hso_create_bulk_serial_device( + struct usb_interface *interface, int port) +{ + struct hso_device *hso_dev; + struct hso_serial *serial; + int num_urbs; + + hso_dev = hso_create_device(interface, port); + if (!hso_dev) + return NULL; + + serial = kzalloc(sizeof(*serial), GFP_KERNEL); + if (!serial) + goto exit; + + serial->parent = hso_dev; + hso_dev->port_data.dev_serial = serial; + + if (port & HSO_PORT_MODEM) + num_urbs = 2; + else + num_urbs = 1; + + if (hso_serial_common_create(serial, num_urbs, BULK_URB_RX_SIZE, + BULK_URB_TX_SIZE)) + goto exit; + + serial->in_endp = hso_get_ep(interface, USB_ENDPOINT_XFER_BULK, + USB_DIR_IN); + if (!serial->in_endp) { + dev_err(&interface->dev, "Failed to find BULK IN ep\n"); + goto exit; + } + + if (! + (serial->out_endp = + hso_get_ep(interface, USB_ENDPOINT_XFER_BULK, USB_DIR_OUT))) { + dev_err(&interface->dev, "Failed to find BULK IN ep\n"); + goto exit; + } + + serial->write_data = hso_std_serial_write_data; + + /* and record this serial */ + set_serial_by_index(serial->minor, serial); + + /* setup the proc dirs and files if needed */ + hso_log_port(hso_dev); + + /* done, return it */ + return hso_dev; +exit: + if (hso_dev && serial) + hso_serial_common_free(serial); + kfree(serial); + hso_free_device(hso_dev); + return NULL; +} + +/* Creates a multiplexed AT channel */ +static +struct hso_device *hso_create_mux_serial_device(struct usb_interface *interface, + int port, + struct hso_shared_int *mux) +{ + struct hso_device *hso_dev; + struct hso_serial *serial; + int port_spec; + + port_spec = HSO_INTF_MUX; + port_spec &= ~HSO_PORT_MASK; + + port_spec |= hso_mux_to_port(port); + if ((port_spec & HSO_PORT_MASK) == HSO_PORT_NO_PORT) + return NULL; + + hso_dev = hso_create_device(interface, port_spec); + if (!hso_dev) + return NULL; + + serial = kzalloc(sizeof(*serial), GFP_KERNEL); + if (!serial) + goto exit; + + hso_dev->port_data.dev_serial = serial; + serial->parent = hso_dev; + + if (hso_serial_common_create + (serial, 1, CTRL_URB_RX_SIZE, CTRL_URB_TX_SIZE)) + goto exit; + + serial->tx_data_length--; + serial->write_data = hso_mux_serial_write_data; + + serial->shared_int = mux; + mutex_lock(&serial->shared_int->shared_int_lock); + serial->shared_int->ref_count++; + mutex_unlock(&serial->shared_int->shared_int_lock); + + /* and record this serial */ + set_serial_by_index(serial->minor, serial); + + /* setup the proc dirs and files if needed */ + hso_log_port(hso_dev); + + /* done, return it */ + return hso_dev; + +exit: + if (serial) { + tty_unregister_device(tty_drv, serial->minor); + kfree(serial); + } + if (hso_dev) + hso_free_device(hso_dev); + return NULL; + +} + +static void hso_free_shared_int(struct hso_shared_int *mux) +{ + usb_free_urb(mux->shared_intr_urb); + kfree(mux->shared_intr_buf); + mutex_unlock(&mux->shared_int_lock); + kfree(mux); +} + +static +struct hso_shared_int *hso_create_shared_int(struct usb_interface *interface) +{ + struct hso_shared_int *mux = kzalloc(sizeof(*mux), GFP_KERNEL); + + if (!mux) + return NULL; + + mux->intr_endp = hso_get_ep(interface, USB_ENDPOINT_XFER_INT, + USB_DIR_IN); + if (!mux->intr_endp) { + dev_err(&interface->dev, "Can't find INT IN endpoint\n"); + goto exit; + } + + mux->shared_intr_urb = usb_alloc_urb(0, GFP_KERNEL); + if (!mux->shared_intr_urb) { + dev_err(&interface->dev, "Could not allocate intr urb?"); + goto exit; + } + mux->shared_intr_buf = kzalloc(mux->intr_endp->wMaxPacketSize, + GFP_KERNEL); + if (!mux->shared_intr_buf) { + dev_err(&interface->dev, "Could not allocate intr buf?"); + goto exit; + } + + mutex_init(&mux->shared_int_lock); + + return mux; + +exit: + kfree(mux->shared_intr_buf); + usb_free_urb(mux->shared_intr_urb); + kfree(mux); + return NULL; +} + +/* Gets the port spec for a certain interface */ +static int hso_get_config_data(struct usb_interface *interface) +{ + struct usb_device *usbdev = interface_to_usbdev(interface); + u8 config_data[17]; + u32 if_num = interface->altsetting->desc.bInterfaceNumber; + s32 result; + + if (usb_control_msg(usbdev, usb_rcvctrlpipe(usbdev, 0), + 0x86, 0xC0, 0, 0, config_data, 17, + USB_CTRL_SET_TIMEOUT) != 0x11) { + return -EIO; + } + + switch (config_data[if_num]) { + case 0x0: + result = 0; + break; + case 0x1: + result = HSO_PORT_DIAG; + break; + case 0x2: + result = HSO_PORT_GPS; + break; + case 0x3: + result = HSO_PORT_GPS_CONTROL; + break; + case 0x4: + result = HSO_PORT_APP; + break; + case 0x5: + result = HSO_PORT_APP2; + break; + case 0x6: + result = HSO_PORT_CONTROL; + break; + case 0x7: + result = HSO_PORT_NETWORK; + break; + case 0x8: + result = HSO_PORT_MODEM; + break; + case 0x9: + result = HSO_PORT_MSD; + break; + case 0xa: + result = HSO_PORT_PCSC; + break; + case 0xb: + result = HSO_PORT_VOICE; + break; + default: + result = 0; + } + + if (result) + result |= HSO_INTF_BULK; + + if (config_data[16] & 0x1) + result |= HSO_INFO_CRC_BUG; + + return result; +} + +/* called once for each interface upon device insertion */ +static int hso_probe(struct usb_interface *interface, + const struct usb_device_id *id) +{ + int mux, i, if_num, port_spec; + unsigned char port_mask; + struct hso_device *hso_dev = NULL; + struct hso_shared_int *shared_int; + struct hso_device *tmp_dev = NULL; + + if_num = interface->altsetting->desc.bInterfaceNumber; + + /* Get the interface/port specification from either driver_info or from + * the device itself */ + if (id->driver_info) + port_spec = ((u32 *)(id->driver_info))[if_num]; + else + port_spec = hso_get_config_data(interface); + + if (interface->cur_altsetting->desc.bInterfaceClass != 0xFF) { + dev_err(&interface->dev, "Not our interface\n"); + return -ENODEV; + } + /* Check if we need to switch to alt interfaces prior to port + * configuration */ + if (interface->num_altsetting > 1) + usb_set_interface(interface_to_usbdev(interface), if_num, 1); + interface->needs_remote_wakeup = 1; + + /* Allocate new hso device(s) */ + switch (port_spec & HSO_INTF_MASK) { + case HSO_INTF_MUX: + if ((port_spec & HSO_PORT_MASK) == HSO_PORT_NETWORK) { + /* Create the network device */ + if (!disable_net) { + hso_dev = hso_create_net_device(interface); + if (!hso_dev) + goto exit; + tmp_dev = hso_dev; + } + } + + if (hso_get_mux_ports(interface, &port_mask)) + /* TODO: de-allocate everything */ + goto exit; + + shared_int = hso_create_shared_int(interface); + if (!shared_int) + goto exit; + + for (i = 1, mux = 0; i < 0x100; i = i << 1, mux++) { + if (port_mask & i) { + hso_dev = hso_create_mux_serial_device( + interface, i, shared_int); + if (!hso_dev) + goto exit; + } + } + + if (tmp_dev) + hso_dev = tmp_dev; + break; + + case HSO_INTF_BULK: + /* It's a regular bulk interface */ + if (((port_spec & HSO_PORT_MASK) == HSO_PORT_NETWORK) + && !disable_net) + hso_dev = hso_create_net_device(interface); + else + hso_dev = + hso_create_bulk_serial_device(interface, port_spec); + if (!hso_dev) + goto exit; + break; + default: + goto exit; + } + + usb_driver_claim_interface(&hso_driver, interface, hso_dev); + + /* save our data pointer in this device */ + usb_set_intfdata(interface, hso_dev); + + /* done */ + return 0; +exit: + hso_free_interface(interface); + return -ENODEV; +} + +/* device removed, cleaning up */ +static void hso_disconnect(struct usb_interface *interface) +{ + hso_free_interface(interface); + + /* remove reference of our private data */ + usb_set_intfdata(interface, NULL); + + usb_driver_release_interface(&hso_driver, interface); +} + +static void async_get_intf(struct work_struct *data) +{ + struct hso_device *hso_dev = + container_of(data, struct hso_device, async_get_intf); + usb_autopm_get_interface(hso_dev->interface); +} + +static void async_put_intf(struct work_struct *data) +{ + struct hso_device *hso_dev = + container_of(data, struct hso_device, async_put_intf); + usb_autopm_put_interface(hso_dev->interface); +} + +static int hso_get_activity(struct hso_device *hso_dev) +{ + if (hso_dev->usb->state == USB_STATE_SUSPENDED) { + if (!hso_dev->is_active) { + hso_dev->is_active = 1; + schedule_work(&hso_dev->async_get_intf); + } + } + + if (hso_dev->usb->state != USB_STATE_CONFIGURED) + return -EAGAIN; + + usb_mark_last_busy(hso_dev->usb); + + return 0; +} + +static int hso_put_activity(struct hso_device *hso_dev) +{ + if (hso_dev->usb->state != USB_STATE_SUSPENDED) { + if (hso_dev->is_active) { + hso_dev->is_active = 0; + schedule_work(&hso_dev->async_put_intf); + return -EAGAIN; + } + } + hso_dev->is_active = 0; + return 0; +} + +/* called by kernel when we need to suspend device */ +static int hso_suspend(struct usb_interface *iface, pm_message_t message) +{ + int i, result; + + /* Stop all serial ports */ + for (i = 0; i < HSO_SERIAL_TTY_MINORS; i++) { + if (serial_table[i] && (serial_table[i]->interface == iface)) { + result = hso_stop_serial_device(serial_table[i]); + if (result) + goto out; + } + } + + /* Stop all network ports */ + for (i = 0; i < HSO_MAX_NET_DEVICES; i++) { + if (network_table[i] && + (network_table[i]->interface == iface)) { + result = hso_stop_net_device(network_table[i]); + if (result) + goto out; + } + } + +out: + return 0; +} + +/* called by kernel when we need to resume device */ +static int hso_resume(struct usb_interface *iface) +{ + int i, result = 0; + struct hso_net *hso_net; + + /* Start all serial ports */ + for (i = 0; i < HSO_SERIAL_TTY_MINORS; i++) { + if (serial_table[i] && (serial_table[i]->interface == iface)) { + if (dev2ser(serial_table[i])->open_count) { + result = + hso_start_serial_device(serial_table[i], GFP_NOIO); + hso_kick_transmit(dev2ser(serial_table[i])); + if (result) + goto out; + } + } + } + + /* Start all network ports */ + for (i = 0; i < HSO_MAX_NET_DEVICES; i++) { + if (network_table[i] && + (network_table[i]->interface == iface)) { + hso_net = dev2net(network_table[i]); + /* First transmit any lingering data, then restart the + * device. */ + if (hso_net->skb_tx_buf) { + dev_dbg(&iface->dev, + "Transmitting lingering data\n"); + hso_net_start_xmit(hso_net->skb_tx_buf, + hso_net->net); + } + result = hso_start_net_device(network_table[i]); + if (result) + goto out; + } + } + +out: + return result; +} + +static void hso_serial_ref_free(struct kref *ref) +{ + struct hso_device *hso_dev = container_of(ref, struct hso_device, ref); + + hso_free_serial_device(hso_dev); +} + +static void hso_free_interface(struct usb_interface *interface) +{ + struct hso_serial *hso_dev; + int i; + + for (i = 0; i < HSO_SERIAL_TTY_MINORS; i++) { + if (serial_table[i] + && (serial_table[i]->interface == interface)) { + hso_dev = dev2ser(serial_table[i]); + if (hso_dev->tty) + tty_hangup(hso_dev->tty); + mutex_lock(&hso_dev->parent->mutex); + hso_dev->parent->usb_gone = 1; + mutex_unlock(&hso_dev->parent->mutex); + kref_put(&serial_table[i]->ref, hso_serial_ref_free); + } + } + + for (i = 0; i < HSO_MAX_NET_DEVICES; i++) { + if (network_table[i] + && (network_table[i]->interface == interface)) { + struct rfkill *rfk = dev2net(network_table[i])->rfkill; + /* hso_stop_net_device doesn't stop the net queue since + * traffic needs to start it again when suspended */ + netif_stop_queue(dev2net(network_table[i])->net); + 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) + rfkill_unregister(rfk); + hso_free_net_device(network_table[i]); + } + } +} + +/* Helper functions */ + +/* Get the endpoint ! */ +static struct usb_endpoint_descriptor *hso_get_ep(struct usb_interface *intf, + int type, int dir) +{ + int i; + struct usb_host_interface *iface = intf->cur_altsetting; + struct usb_endpoint_descriptor *endp; + + for (i = 0; i < iface->desc.bNumEndpoints; i++) { + endp = &iface->endpoint[i].desc; + if (((endp->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == dir) && + ((endp->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == type)) + return endp; + } + + return NULL; +} + +/* Get the byte that describes which ports are enabled */ +static int hso_get_mux_ports(struct usb_interface *intf, unsigned char *ports) +{ + int i; + struct usb_host_interface *iface = intf->cur_altsetting; + + if (iface->extralen == 3) { + *ports = iface->extra[2]; + return 0; + } + + for (i = 0; i < iface->desc.bNumEndpoints; i++) { + if (iface->endpoint[i].extralen == 3) { + *ports = iface->endpoint[i].extra[2]; + return 0; + } + } + + return -1; +} + +/* interrupt urb needs to be submitted, used for serial read of muxed port */ +static int hso_mux_submit_intr_urb(struct hso_shared_int *shared_int, + struct usb_device *usb, gfp_t gfp) +{ + int result; + + usb_fill_int_urb(shared_int->shared_intr_urb, usb, + usb_rcvintpipe(usb, + shared_int->intr_endp->bEndpointAddress & 0x7F), + shared_int->shared_intr_buf, + shared_int->intr_endp->wMaxPacketSize, + intr_callback, shared_int, + shared_int->intr_endp->bInterval); + + result = usb_submit_urb(shared_int->shared_intr_urb, gfp); + if (result) + dev_warn(&usb->dev, "%s failed mux_intr_urb %d", __func__, + result); + + return result; +} + +/* operations setup of the serial interface */ +static struct tty_operations hso_serial_ops = { + .open = hso_serial_open, + .close = hso_serial_close, + .write = hso_serial_write, + .write_room = hso_serial_write_room, + .set_termios = hso_serial_set_termios, + .chars_in_buffer = hso_serial_chars_in_buffer, + .tiocmget = hso_serial_tiocmget, + .tiocmset = hso_serial_tiocmset, +}; + +static struct usb_driver hso_driver = { + .name = driver_name, + .probe = hso_probe, + .disconnect = hso_disconnect, + .id_table = hso_ids, + .suspend = hso_suspend, + .resume = hso_resume, + .supports_autosuspend = 1, +}; + +static int __init hso_init(void) +{ + int i; + int result; + + /* put it in the log */ + printk(KERN_INFO "hso: %s\n", version); + + /* Initialise the serial table semaphore and table */ + spin_lock_init(&serial_table_lock); + for (i = 0; i < HSO_SERIAL_TTY_MINORS; i++) + serial_table[i] = NULL; + + /* allocate our driver using the proper amount of supported minors */ + tty_drv = alloc_tty_driver(HSO_SERIAL_TTY_MINORS); + if (!tty_drv) + return -ENOMEM; + + /* fill in all needed values */ + tty_drv->magic = TTY_DRIVER_MAGIC; + tty_drv->owner = THIS_MODULE; + tty_drv->driver_name = driver_name; + tty_drv->name = tty_filename; + + /* if major number is provided as parameter, use that one */ + if (tty_major) + tty_drv->major = tty_major; + + tty_drv->minor_start = 0; + tty_drv->num = HSO_SERIAL_TTY_MINORS; + tty_drv->type = TTY_DRIVER_TYPE_SERIAL; + tty_drv->subtype = SERIAL_TYPE_NORMAL; + tty_drv->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV; + tty_drv->init_termios = tty_std_termios; + tty_drv->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL; + tty_drv->termios = hso_serial_termios; + tty_drv->termios_locked = hso_serial_termios_locked; + tty_set_operations(tty_drv, &hso_serial_ops); + + /* register the tty driver */ + result = tty_register_driver(tty_drv); + if (result) { + printk(KERN_ERR "%s - tty_register_driver failed(%d)\n", + __func__, result); + return result; + } + + /* register this module as an usb driver */ + result = usb_register(&hso_driver); + if (result) { + printk(KERN_ERR "Could not register hso driver? error: %d\n", + result); + /* cleanup serial interface */ + tty_unregister_driver(tty_drv); + return result; + } + + /* done */ + return 0; +} + +static void __exit hso_exit(void) +{ + printk(KERN_INFO "hso: unloaded\n"); + + tty_unregister_driver(tty_drv); + /* deregister the usb driver */ + usb_deregister(&hso_driver); +} + +/* Module definitions */ +module_init(hso_init); +module_exit(hso_exit); + +MODULE_AUTHOR(MOD_AUTHOR); +MODULE_DESCRIPTION(MOD_DESCRIPTION); +MODULE_LICENSE(MOD_LICENSE); +MODULE_INFO(Version, DRIVER_VERSION); + +/* change the debug level (eg: insmod hso.ko debug=0x04) */ +MODULE_PARM_DESC(debug, "Level of debug [0x01 | 0x02 | 0x04 | 0x08 | 0x10]"); +module_param(debug, int, S_IRUGO | S_IWUSR); + +/* set the major tty number (eg: insmod hso.ko tty_major=245) */ +MODULE_PARM_DESC(tty_major, "Set the major tty number"); +module_param(tty_major, int, S_IRUGO | S_IWUSR); + +/* disable network interface (eg: insmod hso.ko disable_net=1) */ +MODULE_PARM_DESC(disable_net, "Disable the network interface"); +module_param(disable_net, int, S_IRUGO | S_IWUSR); diff --git a/drivers/net/usb/rndis_host.c b/drivers/net/usb/rndis_host.c index ae467f182c40..61c98beb4d17 100644 --- a/drivers/net/usb/rndis_host.c +++ b/drivers/net/usb/rndis_host.c @@ -74,7 +74,7 @@ EXPORT_SYMBOL_GPL(rndis_status); * Call context is likely probe(), before interface name is known, * which is why we won't try to use it in the diagnostics. */ -int rndis_command(struct usbnet *dev, struct rndis_msg_hdr *buf) +int rndis_command(struct usbnet *dev, struct rndis_msg_hdr *buf, int buflen) { struct cdc_state *info = (void *) &dev->data; int master_ifnum; @@ -121,7 +121,7 @@ int rndis_command(struct usbnet *dev, struct rndis_msg_hdr *buf) USB_CDC_GET_ENCAPSULATED_RESPONSE, USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE, 0, master_ifnum, - buf, CONTROL_BUFFER_SIZE, + buf, buflen, RNDIS_CONTROL_TIMEOUT_MS); if (likely(retval >= 8)) { msg_len = le32_to_cpu(buf->msg_len); @@ -239,7 +239,7 @@ static int rndis_query(struct usbnet *dev, struct usb_interface *intf, u.get->len = cpu_to_le32(in_len); u.get->offset = ccpu2(20); - retval = rndis_command(dev, u.header); + retval = rndis_command(dev, u.header, CONTROL_BUFFER_SIZE); if (unlikely(retval < 0)) { dev_err(&intf->dev, "RNDIS_MSG_QUERY(0x%08x) failed, %d\n", oid, retval); @@ -328,7 +328,7 @@ generic_rndis_bind(struct usbnet *dev, struct usb_interface *intf, int flags) u.init->max_transfer_size = cpu_to_le32(dev->rx_urb_size); net->change_mtu = NULL; - retval = rndis_command(dev, u.header); + retval = rndis_command(dev, u.header, CONTROL_BUFFER_SIZE); if (unlikely(retval < 0)) { /* it might not even be an RNDIS device!! */ dev_err(&intf->dev, "RNDIS init failed, %d\n", retval); @@ -409,7 +409,7 @@ generic_rndis_bind(struct usbnet *dev, struct usb_interface *intf, int flags) u.set->offset = ccpu2((sizeof *u.set) - 8); *(__le32 *)(u.buf + sizeof *u.set) = RNDIS_DEFAULT_FILTER; - retval = rndis_command(dev, u.header); + retval = rndis_command(dev, u.header, CONTROL_BUFFER_SIZE); if (unlikely(retval < 0)) { dev_err(&intf->dev, "rndis set packet filter, %d\n", retval); goto halt_fail_and_release; @@ -424,7 +424,7 @@ halt_fail_and_release: memset(u.halt, 0, sizeof *u.halt); u.halt->msg_type = RNDIS_MSG_HALT; u.halt->msg_len = ccpu2(sizeof *u.halt); - (void) rndis_command(dev, (void *)u.halt); + (void) rndis_command(dev, (void *)u.halt, CONTROL_BUFFER_SIZE); fail_and_release: usb_set_intfdata(info->data, NULL); usb_driver_release_interface(driver_of(intf), info->data); @@ -449,7 +449,7 @@ void rndis_unbind(struct usbnet *dev, struct usb_interface *intf) if (halt) { halt->msg_type = RNDIS_MSG_HALT; halt->msg_len = ccpu2(sizeof *halt); - (void) rndis_command(dev, (void *)halt); + (void) rndis_command(dev, (void *)halt, CONTROL_BUFFER_SIZE); kfree(halt); } diff --git a/drivers/net/via-rhine.c b/drivers/net/via-rhine.c index 8c9d6ae2bb31..96dff04334b8 100644 --- a/drivers/net/via-rhine.c +++ b/drivers/net/via-rhine.c @@ -73,12 +73,7 @@ static const int multicast_filter_limit = 32; There are no ill effects from too-large receive rings. */ #define TX_RING_SIZE 16 #define TX_QUEUE_LEN 10 /* Limit ring entries actually used. */ -#ifdef CONFIG_VIA_RHINE_NAPI #define RX_RING_SIZE 64 -#else -#define RX_RING_SIZE 16 -#endif - /* Operational parameters that usually are not changed. */ @@ -583,7 +578,6 @@ static void rhine_poll(struct net_device *dev) } #endif -#ifdef CONFIG_VIA_RHINE_NAPI static int rhine_napipoll(struct napi_struct *napi, int budget) { struct rhine_private *rp = container_of(napi, struct rhine_private, napi); @@ -604,7 +598,6 @@ static int rhine_napipoll(struct napi_struct *napi, int budget) } return work_done; } -#endif static void __devinit rhine_hw_init(struct net_device *dev, long pioaddr) { @@ -784,9 +777,8 @@ static int __devinit rhine_init_one(struct pci_dev *pdev, #ifdef CONFIG_NET_POLL_CONTROLLER dev->poll_controller = rhine_poll; #endif -#ifdef CONFIG_VIA_RHINE_NAPI netif_napi_add(dev, &rp->napi, rhine_napipoll, 64); -#endif + if (rp->quirks & rqRhineI) dev->features |= NETIF_F_SG|NETIF_F_HW_CSUM; @@ -1056,9 +1048,7 @@ static void init_registers(struct net_device *dev) rhine_set_rx_mode(dev); -#ifdef CONFIG_VIA_RHINE_NAPI napi_enable(&rp->napi); -#endif /* Enable interrupts by setting the interrupt mask. */ iowrite16(IntrRxDone | IntrRxErr | IntrRxEmpty| IntrRxOverflow | @@ -1193,9 +1183,7 @@ static void rhine_tx_timeout(struct net_device *dev) /* protect against concurrent rx interrupts */ disable_irq(rp->pdev->irq); -#ifdef CONFIG_VIA_RHINE_NAPI napi_disable(&rp->napi); -#endif spin_lock(&rp->lock); @@ -1319,16 +1307,12 @@ static irqreturn_t rhine_interrupt(int irq, void *dev_instance) if (intr_status & (IntrRxDone | IntrRxErr | IntrRxDropped | IntrRxWakeUp | IntrRxEmpty | IntrRxNoBuf)) { -#ifdef CONFIG_VIA_RHINE_NAPI iowrite16(IntrTxAborted | IntrTxDone | IntrTxError | IntrTxUnderrun | IntrPCIErr | IntrStatsMax | IntrLinkChange, ioaddr + IntrEnable); netif_rx_schedule(dev, &rp->napi); -#else - rhine_rx(dev, RX_RING_SIZE); -#endif } if (intr_status & (IntrTxErrSummary | IntrTxDone)) { @@ -1520,11 +1504,7 @@ static int rhine_rx(struct net_device *dev, int limit) PCI_DMA_FROMDEVICE); } skb->protocol = eth_type_trans(skb, dev); -#ifdef CONFIG_VIA_RHINE_NAPI netif_receive_skb(skb); -#else - netif_rx(skb); -#endif dev->last_rx = jiffies; rp->stats.rx_bytes += pkt_len; rp->stats.rx_packets++; @@ -1836,9 +1816,7 @@ static int rhine_close(struct net_device *dev) spin_lock_irq(&rp->lock); netif_stop_queue(dev); -#ifdef CONFIG_VIA_RHINE_NAPI napi_disable(&rp->napi); -#endif if (debug > 1) printk(KERN_DEBUG "%s: Shutting down ethercard, " @@ -1937,9 +1915,8 @@ static int rhine_suspend(struct pci_dev *pdev, pm_message_t state) if (!netif_running(dev)) return 0; -#ifdef CONFIG_VIA_RHINE_NAPI napi_disable(&rp->napi); -#endif + netif_device_detach(dev); pci_save_state(pdev); diff --git a/drivers/net/via-velocity.c b/drivers/net/via-velocity.c index 6b8d882d197b..370ce30f2f45 100644 --- a/drivers/net/via-velocity.c +++ b/drivers/net/via-velocity.c @@ -1102,61 +1102,41 @@ static int __devinit velocity_get_pci_info(struct velocity_info *vptr, struct pc static int velocity_init_rings(struct velocity_info *vptr) { - int i; - unsigned int psize; - unsigned int tsize; + struct velocity_opt *opt = &vptr->options; + const unsigned int rx_ring_size = opt->numrx * sizeof(struct rx_desc); + const unsigned int tx_ring_size = opt->numtx * sizeof(struct tx_desc); + struct pci_dev *pdev = vptr->pdev; dma_addr_t pool_dma; - u8 *pool; - - /* - * Allocate all RD/TD rings a single pool - */ - - psize = vptr->options.numrx * sizeof(struct rx_desc) + - vptr->options.numtx * sizeof(struct tx_desc) * vptr->num_txq; + void *pool; + unsigned int i; /* + * Allocate all RD/TD rings a single pool. + * * pci_alloc_consistent() fulfills the requirement for 64 bytes * alignment */ - pool = pci_alloc_consistent(vptr->pdev, psize, &pool_dma); - - if (pool == NULL) { - printk(KERN_ERR "%s : DMA memory allocation failed.\n", - vptr->dev->name); + pool = pci_alloc_consistent(pdev, tx_ring_size * vptr->num_txq + + rx_ring_size, &pool_dma); + if (!pool) { + dev_err(&pdev->dev, "%s : DMA memory allocation failed.\n", + vptr->dev->name); return -ENOMEM; } - memset(pool, 0, psize); - - vptr->rd_ring = (struct rx_desc *) pool; - + vptr->rd_ring = pool; vptr->rd_pool_dma = pool_dma; - tsize = vptr->options.numtx * PKT_BUF_SZ * vptr->num_txq; - vptr->tx_bufs = pci_alloc_consistent(vptr->pdev, tsize, - &vptr->tx_bufs_dma); + pool += rx_ring_size; + pool_dma += rx_ring_size; - if (vptr->tx_bufs == NULL) { - printk(KERN_ERR "%s: DMA memory allocation failed.\n", - vptr->dev->name); - pci_free_consistent(vptr->pdev, psize, pool, pool_dma); - return -ENOMEM; - } - - memset(vptr->tx_bufs, 0, vptr->options.numtx * PKT_BUF_SZ * vptr->num_txq); - - i = vptr->options.numrx * sizeof(struct rx_desc); - pool += i; - pool_dma += i; for (i = 0; i < vptr->num_txq; i++) { - int offset = vptr->options.numtx * sizeof(struct tx_desc); - + vptr->td_rings[i] = pool; vptr->td_pool_dma[i] = pool_dma; - vptr->td_rings[i] = (struct tx_desc *) pool; - pool += offset; - pool_dma += offset; + pool += tx_ring_size; + pool_dma += tx_ring_size; } + return 0; } @@ -1169,19 +1149,13 @@ static int velocity_init_rings(struct velocity_info *vptr) static void velocity_free_rings(struct velocity_info *vptr) { - int size; - - size = vptr->options.numrx * sizeof(struct rx_desc) + - vptr->options.numtx * sizeof(struct tx_desc) * vptr->num_txq; + const int size = vptr->options.numrx * sizeof(struct rx_desc) + + vptr->options.numtx * sizeof(struct tx_desc) * vptr->num_txq; pci_free_consistent(vptr->pdev, size, vptr->rd_ring, vptr->rd_pool_dma); - - size = vptr->options.numtx * PKT_BUF_SZ * vptr->num_txq; - - pci_free_consistent(vptr->pdev, size, vptr->tx_bufs, vptr->tx_bufs_dma); } -static inline void velocity_give_many_rx_descs(struct velocity_info *vptr) +static void velocity_give_many_rx_descs(struct velocity_info *vptr) { struct mac_regs __iomem *regs = vptr->mac_regs; int avail, dirty, unusable; @@ -1208,7 +1182,7 @@ static inline void velocity_give_many_rx_descs(struct velocity_info *vptr) static int velocity_rx_refill(struct velocity_info *vptr) { - int dirty = vptr->rd_dirty, done = 0, ret = 0; + int dirty = vptr->rd_dirty, done = 0; do { struct rx_desc *rd = vptr->rd_ring + dirty; @@ -1218,8 +1192,7 @@ static int velocity_rx_refill(struct velocity_info *vptr) break; if (!vptr->rd_info[dirty].skb) { - ret = velocity_alloc_rx_buf(vptr, dirty); - if (ret < 0) + if (velocity_alloc_rx_buf(vptr, dirty) < 0) break; } done++; @@ -1229,10 +1202,14 @@ static int velocity_rx_refill(struct velocity_info *vptr) if (done) { vptr->rd_dirty = dirty; vptr->rd_filled += done; - velocity_give_many_rx_descs(vptr); } - return ret; + return done; +} + +static void velocity_set_rxbufsize(struct velocity_info *vptr, int mtu) +{ + vptr->rx_buf_sz = (mtu <= ETH_DATA_LEN) ? PKT_BUF_SZ : mtu + 32; } /** @@ -1245,25 +1222,24 @@ static int velocity_rx_refill(struct velocity_info *vptr) static int velocity_init_rd_ring(struct velocity_info *vptr) { - int ret; - int mtu = vptr->dev->mtu; - - vptr->rx_buf_sz = (mtu <= ETH_DATA_LEN) ? PKT_BUF_SZ : mtu + 32; + int ret = -ENOMEM; vptr->rd_info = kcalloc(vptr->options.numrx, sizeof(struct velocity_rd_info), GFP_KERNEL); if (!vptr->rd_info) - return -ENOMEM; + goto out; vptr->rd_filled = vptr->rd_dirty = vptr->rd_curr = 0; - ret = velocity_rx_refill(vptr); - if (ret < 0) { + if (velocity_rx_refill(vptr) != vptr->options.numrx) { VELOCITY_PRT(MSG_LEVEL_ERR, KERN_ERR "%s: failed to allocate RX buffer.\n", vptr->dev->name); velocity_free_rd_ring(vptr); + goto out; } + ret = 0; +out: return ret; } @@ -1313,10 +1289,8 @@ static void velocity_free_rd_ring(struct velocity_info *vptr) static int velocity_init_td_ring(struct velocity_info *vptr) { - int i, j; dma_addr_t curr; - struct tx_desc *td; - struct velocity_td_info *td_info; + unsigned int j; /* Init the TD ring entries */ for (j = 0; j < vptr->num_txq; j++) { @@ -1331,14 +1305,6 @@ static int velocity_init_td_ring(struct velocity_info *vptr) return -ENOMEM; } - for (i = 0; i < vptr->options.numtx; i++, curr += sizeof(struct tx_desc)) { - td = &(vptr->td_rings[j][i]); - td_info = &(vptr->td_infos[j][i]); - td_info->buf = vptr->tx_bufs + - (j * vptr->options.numtx + i) * PKT_BUF_SZ; - td_info->buf_dma = vptr->tx_bufs_dma + - (j * vptr->options.numtx + i) * PKT_BUF_SZ; - } vptr->td_tail[j] = vptr->td_curr[j] = vptr->td_used[j] = 0; } return 0; @@ -1448,10 +1414,8 @@ static int velocity_rx_srv(struct velocity_info *vptr, int status) vptr->rd_curr = rd_curr; - if (works > 0 && velocity_rx_refill(vptr) < 0) { - VELOCITY_PRT(MSG_LEVEL_ERR, KERN_ERR - "%s: rx buf allocation failure\n", vptr->dev->name); - } + if ((works > 0) && (velocity_rx_refill(vptr) > 0)) + velocity_give_many_rx_descs(vptr); VAR_USED(stats); return works; @@ -1495,24 +1459,18 @@ static inline void velocity_rx_csum(struct rx_desc *rd, struct sk_buff *skb) * enough. This function returns a negative value if the received * packet is too big or if memory is exhausted. */ -static inline int velocity_rx_copy(struct sk_buff **rx_skb, int pkt_size, - struct velocity_info *vptr) +static int velocity_rx_copy(struct sk_buff **rx_skb, int pkt_size, + struct velocity_info *vptr) { int ret = -1; - if (pkt_size < rx_copybreak) { struct sk_buff *new_skb; - new_skb = dev_alloc_skb(pkt_size + 2); + new_skb = netdev_alloc_skb(vptr->dev, pkt_size + 2); if (new_skb) { - new_skb->dev = vptr->dev; new_skb->ip_summed = rx_skb[0]->ip_summed; - - if (vptr->flags & VELOCITY_FLAGS_IP_ALIGN) - skb_reserve(new_skb, 2); - - skb_copy_from_linear_data(rx_skb[0], new_skb->data, - pkt_size); + skb_reserve(new_skb, 2); + skb_copy_from_linear_data(*rx_skb, new_skb->data, pkt_size); *rx_skb = new_skb; ret = 0; } @@ -1533,12 +1491,8 @@ static inline int velocity_rx_copy(struct sk_buff **rx_skb, int pkt_size, static inline void velocity_iph_realign(struct velocity_info *vptr, struct sk_buff *skb, int pkt_size) { - /* FIXME - memmove ? */ if (vptr->flags & VELOCITY_FLAGS_IP_ALIGN) { - int i; - - for (i = pkt_size; i >= 0; i--) - *(skb->data + i + 2) = *(skb->data + i); + memmove(skb->data + 2, skb->data, pkt_size); skb_reserve(skb, 2); } } @@ -1629,7 +1583,7 @@ static int velocity_alloc_rx_buf(struct velocity_info *vptr, int idx) struct rx_desc *rd = &(vptr->rd_ring[idx]); struct velocity_rd_info *rd_info = &(vptr->rd_info[idx]); - rd_info->skb = dev_alloc_skb(vptr->rx_buf_sz + 64); + rd_info->skb = netdev_alloc_skb(vptr->dev, vptr->rx_buf_sz + 64); if (rd_info->skb == NULL) return -ENOMEM; @@ -1638,7 +1592,6 @@ static int velocity_alloc_rx_buf(struct velocity_info *vptr, int idx) * 64byte alignment. */ skb_reserve(rd_info->skb, (unsigned long) rd_info->skb->data & 63); - rd_info->skb->dev = vptr->dev; rd_info->skb_dma = pci_map_single(vptr->pdev, rd_info->skb->data, vptr->rx_buf_sz, PCI_DMA_FROMDEVICE); /* @@ -1878,7 +1831,7 @@ static void velocity_free_tx_buf(struct velocity_info *vptr, struct velocity_td_ /* * Don't unmap the pre-allocated tx_bufs */ - if (tdinfo->skb_dma && (tdinfo->skb_dma[0] != tdinfo->buf_dma)) { + if (tdinfo->skb_dma) { for (i = 0; i < tdinfo->nskb_dma; i++) { #ifdef VELOCITY_ZERO_COPY_SUPPORT @@ -1909,6 +1862,8 @@ static int velocity_open(struct net_device *dev) struct velocity_info *vptr = netdev_priv(dev); int ret; + velocity_set_rxbufsize(vptr, dev->mtu); + ret = velocity_init_rings(vptr); if (ret < 0) goto out; @@ -1924,6 +1879,8 @@ static int velocity_open(struct net_device *dev) /* Ensure chip is running */ pci_set_power_state(vptr->pdev, PCI_D0); + velocity_give_many_rx_descs(vptr); + velocity_init_registers(vptr, VELOCITY_INIT_COLD); ret = request_irq(vptr->pdev->irq, &velocity_intr, IRQF_SHARED, @@ -1988,6 +1945,8 @@ static int velocity_change_mtu(struct net_device *dev, int new_mtu) dev->mtu = new_mtu; + velocity_set_rxbufsize(vptr, new_mtu); + ret = velocity_init_rd_ring(vptr); if (ret < 0) goto out_unlock; @@ -2074,9 +2033,19 @@ static int velocity_xmit(struct sk_buff *skb, struct net_device *dev) struct tx_desc *td_ptr; struct velocity_td_info *tdinfo; unsigned long flags; - int index; int pktlen = skb->len; - __le16 len = cpu_to_le16(pktlen); + __le16 len; + int index; + + + + if (skb->len < ETH_ZLEN) { + if (skb_padto(skb, ETH_ZLEN)) + goto out; + pktlen = ETH_ZLEN; + } + + len = cpu_to_le16(pktlen); #ifdef VELOCITY_ZERO_COPY_SUPPORT if (skb_shinfo(skb)->nr_frags > 6 && __skb_linearize(skb)) { @@ -2094,23 +2063,6 @@ static int velocity_xmit(struct sk_buff *skb, struct net_device *dev) td_ptr->tdesc1.TCR = TCR0_TIC; td_ptr->td_buf[0].size &= ~TD_QUEUE; - /* - * Pad short frames. - */ - if (pktlen < ETH_ZLEN) { - /* Cannot occur until ZC support */ - pktlen = ETH_ZLEN; - len = cpu_to_le16(ETH_ZLEN); - skb_copy_from_linear_data(skb, tdinfo->buf, skb->len); - memset(tdinfo->buf + skb->len, 0, ETH_ZLEN - skb->len); - tdinfo->skb = skb; - tdinfo->skb_dma[0] = tdinfo->buf_dma; - td_ptr->tdesc0.len = len; - td_ptr->td_buf[0].pa_low = cpu_to_le32(tdinfo->skb_dma[0]); - td_ptr->td_buf[0].pa_high = 0; - td_ptr->td_buf[0].size = len; /* queue is 0 anyway */ - tdinfo->nskb_dma = 1; - } else #ifdef VELOCITY_ZERO_COPY_SUPPORT if (skb_shinfo(skb)->nr_frags > 0) { int nfrags = skb_shinfo(skb)->nr_frags; @@ -2202,7 +2154,8 @@ static int velocity_xmit(struct sk_buff *skb, struct net_device *dev) } dev->trans_start = jiffies; spin_unlock_irqrestore(&vptr->lock, flags); - return 0; +out: + return NETDEV_TX_OK; } /** diff --git a/drivers/net/via-velocity.h b/drivers/net/via-velocity.h index 7387be4f428d..86446147284c 100644 --- a/drivers/net/via-velocity.h +++ b/drivers/net/via-velocity.h @@ -236,10 +236,8 @@ struct velocity_rd_info { struct velocity_td_info { struct sk_buff *skb; - u8 *buf; int nskb_dma; dma_addr_t skb_dma[7]; - dma_addr_t buf_dma; }; enum velocity_owner { @@ -1506,9 +1504,6 @@ struct velocity_info { dma_addr_t rd_pool_dma; dma_addr_t td_pool_dma[TX_QUEUE_NO]; - dma_addr_t tx_bufs_dma; - u8 *tx_bufs; - struct vlan_group *vlgrp; u8 ip_addr[4]; enum chip_type chip_id; diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c index 4452306d5328..c28d7cb2035b 100644 --- a/drivers/net/virtio_net.c +++ b/drivers/net/virtio_net.c @@ -550,7 +550,8 @@ static struct virtio_device_id id_table[] = { }; static unsigned int features[] = { - VIRTIO_NET_F_CSUM, VIRTIO_NET_F_GSO, VIRTIO_NET_F_MAC, + VIRTIO_NET_F_CSUM, VIRTIO_NET_F_GUEST_CSUM, + VIRTIO_NET_F_GSO, VIRTIO_NET_F_MAC, VIRTIO_NET_F_HOST_TSO4, VIRTIO_NET_F_HOST_UFO, VIRTIO_NET_F_HOST_TSO6, VIRTIO_NET_F_HOST_ECN, VIRTIO_F_NOTIFY_ON_EMPTY, }; diff --git a/drivers/net/wan/Kconfig b/drivers/net/wan/Kconfig index d5140aed7b79..846be60e7821 100644 --- a/drivers/net/wan/Kconfig +++ b/drivers/net/wan/Kconfig @@ -390,8 +390,7 @@ config WAN_ROUTER_DRIVERS Select driver your card and remember to say Y to "Wan Router." You will need the wan-tools package which is available from - <ftp://ftp.sangoma.com/>. For more information read: - <file:Documentation/networking/wan-router.txt>. + <ftp://ftp.sangoma.com/>. Note that the answer to this question won't directly affect the kernel except for how subordinate drivers may be built: diff --git a/drivers/net/wan/c101.c b/drivers/net/wan/c101.c index c2cc42f723d5..c8e563106a4a 100644 --- a/drivers/net/wan/c101.c +++ b/drivers/net/wan/c101.c @@ -133,9 +133,9 @@ static void sca_msci_intr(port_t *port) sca_out(stat & (ST1_UDRN | ST1_CDCD), MSCI0_OFFSET + ST1, port); if (stat & ST1_UDRN) { - struct net_device_stats *stats = hdlc_stats(port_to_dev(port)); - stats->tx_errors++; /* TX Underrun error detected */ - stats->tx_fifo_errors++; + /* TX Underrun error detected */ + port_to_dev(port)->stats.tx_errors++; + port_to_dev(port)->stats.tx_fifo_errors++; } stat = sca_in(MSCI1_OFFSET + ST1, port); /* read MSCI1 ST1 status */ diff --git a/drivers/net/wan/dscc4.c b/drivers/net/wan/dscc4.c index c6f26e28e376..50ef5b4efd6d 100644 --- a/drivers/net/wan/dscc4.c +++ b/drivers/net/wan/dscc4.c @@ -642,7 +642,6 @@ static inline void dscc4_rx_skb(struct dscc4_dev_priv *dpriv, struct net_device *dev) { struct RxFD *rx_fd = dpriv->rx_fd + dpriv->rx_current%RX_RING_SIZE; - struct net_device_stats *stats = hdlc_stats(dev); struct pci_dev *pdev = dpriv->pci_priv->pdev; struct sk_buff *skb; int pkt_len; @@ -656,8 +655,8 @@ static inline void dscc4_rx_skb(struct dscc4_dev_priv *dpriv, pci_unmap_single(pdev, le32_to_cpu(rx_fd->data), RX_MAX(HDLC_MAX_MRU), PCI_DMA_FROMDEVICE); if ((skb->data[--pkt_len] & FrameOk) == FrameOk) { - stats->rx_packets++; - stats->rx_bytes += pkt_len; + dev->stats.rx_packets++; + dev->stats.rx_bytes += pkt_len; skb_put(skb, pkt_len); if (netif_running(dev)) skb->protocol = hdlc_type_trans(skb, dev); @@ -665,13 +664,13 @@ static inline void dscc4_rx_skb(struct dscc4_dev_priv *dpriv, netif_rx(skb); } else { if (skb->data[pkt_len] & FrameRdo) - stats->rx_fifo_errors++; + dev->stats.rx_fifo_errors++; else if (!(skb->data[pkt_len] | ~FrameCrc)) - stats->rx_crc_errors++; + dev->stats.rx_crc_errors++; else if (!(skb->data[pkt_len] | ~(FrameVfr | FrameRab))) - stats->rx_length_errors++; + dev->stats.rx_length_errors++; else - stats->rx_errors++; + dev->stats.rx_errors++; dev_kfree_skb_irq(skb); } refill: @@ -1569,7 +1568,6 @@ try: if (state & SccEvt) { if (state & Alls) { - struct net_device_stats *stats = hdlc_stats(dev); struct sk_buff *skb; struct TxFD *tx_fd; @@ -1586,8 +1584,8 @@ try: pci_unmap_single(ppriv->pdev, le32_to_cpu(tx_fd->data), skb->len, PCI_DMA_TODEVICE); if (tx_fd->state & FrameEnd) { - stats->tx_packets++; - stats->tx_bytes += skb->len; + dev->stats.tx_packets++; + dev->stats.tx_bytes += skb->len; } dev_kfree_skb_irq(skb); dpriv->tx_skbuff[cur] = NULL; @@ -1698,7 +1696,7 @@ try: } if (state & Err) { printk(KERN_INFO "%s: Tx ERR\n", dev->name); - hdlc_stats(dev)->tx_errors++; + dev->stats.tx_errors++; state &= ~Err; } } @@ -1834,7 +1832,7 @@ try: if (!(rx_fd->state2 & DataComplete)) break; if (rx_fd->state2 & FrameAborted) { - hdlc_stats(dev)->rx_over_errors++; + dev->stats.rx_over_errors++; rx_fd->state1 |= Hold; rx_fd->state2 = 0x00000000; rx_fd->end = cpu_to_le32(0xbabeface); diff --git a/drivers/net/wan/farsync.c b/drivers/net/wan/farsync.c index 547368e9633d..754f00809e3e 100644 --- a/drivers/net/wan/farsync.c +++ b/drivers/net/wan/farsync.c @@ -845,7 +845,6 @@ fst_tx_dma_complete(struct fst_card_info *card, struct fst_port_info *port, int len, int txpos) { struct net_device *dev = port_to_dev(port); - struct net_device_stats *stats = hdlc_stats(dev); /* * Everything is now set, just tell the card to go @@ -853,8 +852,8 @@ fst_tx_dma_complete(struct fst_card_info *card, struct fst_port_info *port, dbg(DBG_TX, "fst_tx_dma_complete\n"); FST_WRB(card, txDescrRing[port->index][txpos].bits, DMA_OWN | TX_STP | TX_ENP); - stats->tx_packets++; - stats->tx_bytes += len; + dev->stats.tx_packets++; + dev->stats.tx_bytes += len; dev->trans_start = jiffies; } @@ -876,7 +875,6 @@ fst_rx_dma_complete(struct fst_card_info *card, struct fst_port_info *port, int len, struct sk_buff *skb, int rxp) { struct net_device *dev = port_to_dev(port); - struct net_device_stats *stats = hdlc_stats(dev); int pi; int rx_status; @@ -888,8 +886,8 @@ fst_rx_dma_complete(struct fst_card_info *card, struct fst_port_info *port, FST_WRB(card, rxDescrRing[pi][rxp].bits, DMA_OWN); /* Update stats */ - stats->rx_packets++; - stats->rx_bytes += len; + dev->stats.rx_packets++; + dev->stats.rx_bytes += len; /* Push upstream */ dbg(DBG_RX, "Pushing the frame up the stack\n"); @@ -900,7 +898,7 @@ fst_rx_dma_complete(struct fst_card_info *card, struct fst_port_info *port, rx_status = netif_rx(skb); fst_process_rx_status(rx_status, port_to_dev(port)->name); if (rx_status == NET_RX_DROP) - stats->rx_dropped++; + dev->stats.rx_dropped++; dev->last_rx = jiffies; } @@ -1163,29 +1161,28 @@ fst_log_rx_error(struct fst_card_info *card, struct fst_port_info *port, unsigned char dmabits, int rxp, unsigned short len) { struct net_device *dev = port_to_dev(port); - struct net_device_stats *stats = hdlc_stats(dev); - /* + /* * Increment the appropriate error counter */ - stats->rx_errors++; + dev->stats.rx_errors++; if (dmabits & RX_OFLO) { - stats->rx_fifo_errors++; + dev->stats.rx_fifo_errors++; dbg(DBG_ASS, "Rx fifo error on card %d port %d buffer %d\n", card->card_no, port->index, rxp); } if (dmabits & RX_CRC) { - stats->rx_crc_errors++; + dev->stats.rx_crc_errors++; dbg(DBG_ASS, "Rx crc error on card %d port %d\n", card->card_no, port->index); } if (dmabits & RX_FRAM) { - stats->rx_frame_errors++; + dev->stats.rx_frame_errors++; dbg(DBG_ASS, "Rx frame error on card %d port %d\n", card->card_no, port->index); } if (dmabits == (RX_STP | RX_ENP)) { - stats->rx_length_errors++; + dev->stats.rx_length_errors++; dbg(DBG_ASS, "Rx length error (%d) on card %d port %d\n", len, card->card_no, port->index); } @@ -1242,7 +1239,6 @@ fst_intr_rx(struct fst_card_info *card, struct fst_port_info *port) unsigned short len; struct sk_buff *skb; struct net_device *dev = port_to_dev(port); - struct net_device_stats *stats = hdlc_stats(dev); /* Check we have a buffer to process */ pi = port->index; @@ -1291,7 +1287,7 @@ fst_intr_rx(struct fst_card_info *card, struct fst_port_info *port) if ((skb = dev_alloc_skb(len)) == NULL) { dbg(DBG_RX, "intr_rx: can't allocate buffer\n"); - stats->rx_dropped++; + dev->stats.rx_dropped++; /* Return descriptor to card */ FST_WRB(card, rxDescrRing[pi][rxp].bits, DMA_OWN); @@ -1316,8 +1312,8 @@ fst_intr_rx(struct fst_card_info *card, struct fst_port_info *port) FST_WRB(card, rxDescrRing[pi][rxp].bits, DMA_OWN); /* Update stats */ - stats->rx_packets++; - stats->rx_bytes += len; + dev->stats.rx_packets++; + dev->stats.rx_bytes += len; /* Push upstream */ dbg(DBG_RX, "Pushing frame up the stack\n"); @@ -1327,9 +1323,8 @@ fst_intr_rx(struct fst_card_info *card, struct fst_port_info *port) skb->protocol = hdlc_type_trans(skb, dev); rx_status = netif_rx(skb); fst_process_rx_status(rx_status, port_to_dev(port)->name); - if (rx_status == NET_RX_DROP) { - stats->rx_dropped++; - } + if (rx_status == NET_RX_DROP) + dev->stats.rx_dropped++; dev->last_rx = jiffies; } else { card->dma_skb_rx = skb; @@ -1361,7 +1356,6 @@ do_bottom_half_tx(struct fst_card_info *card) struct sk_buff *skb; unsigned long flags; struct net_device *dev; - struct net_device_stats *stats; /* * Find a free buffer for the transmit @@ -1373,12 +1367,10 @@ do_bottom_half_tx(struct fst_card_info *card) if (!port->run) continue; - dev = port_to_dev(port); - stats = hdlc_stats(dev); - while (! - (FST_RDB(card, txDescrRing[pi][port->txpos].bits) & - DMA_OWN) - && !(card->dmatx_in_progress)) { + dev = port_to_dev(port); + while (!(FST_RDB(card, txDescrRing[pi][port->txpos].bits) & + DMA_OWN) + && !(card->dmatx_in_progress)) { /* * There doesn't seem to be a txdone event per-se * We seem to have to deduce it, by checking the DMA_OWN @@ -1422,8 +1414,8 @@ do_bottom_half_tx(struct fst_card_info *card) txDescrRing[pi][port->txpos]. bits, DMA_OWN | TX_STP | TX_ENP); - stats->tx_packets++; - stats->tx_bytes += skb->len; + dev->stats.tx_packets++; + dev->stats.tx_bytes += skb->len; dev->trans_start = jiffies; } else { /* Or do it through dma */ @@ -1628,8 +1620,8 @@ fst_intr(int dummy, void *dev_id) * always load up the entire packet for DMA. */ dbg(DBG_TX, "Tx underflow port %d\n", port->index); - hdlc_stats(port_to_dev(port))->tx_errors++; - hdlc_stats(port_to_dev(port))->tx_fifo_errors++; + port_to_dev(port)->stats.tx_errors++; + port_to_dev(port)->stats.tx_fifo_errors++; dbg(DBG_ASS, "Tx underflow on card %d port %d\n", card->card_no, port->index); break; @@ -2292,12 +2284,11 @@ fst_tx_timeout(struct net_device *dev) { struct fst_port_info *port; struct fst_card_info *card; - struct net_device_stats *stats = hdlc_stats(dev); port = dev_to_port(dev); card = port->card; - stats->tx_errors++; - stats->tx_aborted_errors++; + dev->stats.tx_errors++; + dev->stats.tx_aborted_errors++; dbg(DBG_ASS, "Tx timeout card %d port %d\n", card->card_no, port->index); fst_issue_cmd(port, ABORTTX); @@ -2312,7 +2303,6 @@ fst_start_xmit(struct sk_buff *skb, struct net_device *dev) { struct fst_card_info *card; struct fst_port_info *port; - struct net_device_stats *stats = hdlc_stats(dev); unsigned long flags; int txq_length; @@ -2323,8 +2313,8 @@ fst_start_xmit(struct sk_buff *skb, struct net_device *dev) /* Drop packet with error if we don't have carrier */ if (!netif_carrier_ok(dev)) { dev_kfree_skb(skb); - stats->tx_errors++; - stats->tx_carrier_errors++; + dev->stats.tx_errors++; + dev->stats.tx_carrier_errors++; dbg(DBG_ASS, "Tried to transmit but no carrier on card %d port %d\n", card->card_no, port->index); @@ -2336,7 +2326,7 @@ fst_start_xmit(struct sk_buff *skb, struct net_device *dev) dbg(DBG_ASS, "Packet too large %d vs %d\n", skb->len, LEN_TX_BUFFER); dev_kfree_skb(skb); - stats->tx_errors++; + dev->stats.tx_errors++; return 0; } @@ -2368,7 +2358,7 @@ fst_start_xmit(struct sk_buff *skb, struct net_device *dev) * This shouldn't have happened but such is life */ dev_kfree_skb(skb); - stats->tx_errors++; + dev->stats.tx_errors++; dbg(DBG_ASS, "Tx queue overflow card %d port %d\n", card->card_no, port->index); return 0; diff --git a/drivers/net/wan/hd6457x.c b/drivers/net/wan/hd6457x.c index 8d0a1f2f00e5..591fb45a7c68 100644 --- a/drivers/net/wan/hd6457x.c +++ b/drivers/net/wan/hd6457x.c @@ -271,9 +271,9 @@ static inline void sca_msci_intr(port_t *port) sca_out(stat & (ST1_UDRN | ST1_CDCD), msci + ST1, card); if (stat & ST1_UDRN) { - struct net_device_stats *stats = hdlc_stats(port_to_dev(port)); - stats->tx_errors++; /* TX Underrun error detected */ - stats->tx_fifo_errors++; + /* TX Underrun error detected */ + port_to_dev(port)->stats.tx_errors++; + port_to_dev(port)->stats.tx_fifo_errors++; } if (stat & ST1_CDCD) @@ -286,7 +286,6 @@ static inline void sca_msci_intr(port_t *port) static inline void sca_rx(card_t *card, port_t *port, pkt_desc __iomem *desc, u16 rxin) { struct net_device *dev = port_to_dev(port); - struct net_device_stats *stats = hdlc_stats(dev); struct sk_buff *skb; u16 len; u32 buff; @@ -298,7 +297,7 @@ static inline void sca_rx(card_t *card, port_t *port, pkt_desc __iomem *desc, u1 len = readw(&desc->len); skb = dev_alloc_skb(len); if (!skb) { - stats->rx_dropped++; + dev->stats.rx_dropped++; return; } @@ -327,8 +326,8 @@ static inline void sca_rx(card_t *card, port_t *port, pkt_desc __iomem *desc, u1 printk(KERN_DEBUG "%s RX(%i):", dev->name, skb->len); debug_frame(skb); #endif - stats->rx_packets++; - stats->rx_bytes += skb->len; + dev->stats.rx_packets++; + dev->stats.rx_bytes += skb->len; dev->last_rx = jiffies; skb->protocol = hdlc_type_trans(skb, dev); netif_rx(skb); @@ -339,17 +338,18 @@ static inline void sca_rx(card_t *card, port_t *port, pkt_desc __iomem *desc, u1 /* Receive DMA interrupt service */ static inline void sca_rx_intr(port_t *port) { + struct net_device *dev = port_to_dev(port); u16 dmac = get_dmac_rx(port); card_t *card = port_to_card(port); u8 stat = sca_in(DSR_RX(phy_node(port)), card); /* read DMA Status */ - struct net_device_stats *stats = hdlc_stats(port_to_dev(port)); /* Reset DSR status bits */ sca_out((stat & (DSR_EOT | DSR_EOM | DSR_BOF | DSR_COF)) | DSR_DWE, DSR_RX(phy_node(port)), card); if (stat & DSR_BOF) - stats->rx_over_errors++; /* Dropped one or more frames */ + /* Dropped one or more frames */ + dev->stats.rx_over_errors++; while (1) { u32 desc_off = desc_offset(port, port->rxin, 0); @@ -364,12 +364,14 @@ static inline void sca_rx_intr(port_t *port) if (!(stat & ST_RX_EOM)) port->rxpart = 1; /* partial frame received */ else if ((stat & ST_ERROR_MASK) || port->rxpart) { - stats->rx_errors++; - if (stat & ST_RX_OVERRUN) stats->rx_fifo_errors++; + dev->stats.rx_errors++; + if (stat & ST_RX_OVERRUN) + dev->stats.rx_fifo_errors++; else if ((stat & (ST_RX_SHORT | ST_RX_ABORT | ST_RX_RESBIT)) || port->rxpart) - stats->rx_frame_errors++; - else if (stat & ST_RX_CRC) stats->rx_crc_errors++; + dev->stats.rx_frame_errors++; + else if (stat & ST_RX_CRC) + dev->stats.rx_crc_errors++; if (stat & ST_RX_EOM) port->rxpart = 0; /* received last fragment */ } else @@ -390,7 +392,6 @@ static inline void sca_rx_intr(port_t *port) static inline void sca_tx_intr(port_t *port) { struct net_device *dev = port_to_dev(port); - struct net_device_stats *stats = hdlc_stats(dev); u16 dmac = get_dmac_tx(port); card_t* card = port_to_card(port); u8 stat; @@ -412,8 +413,8 @@ static inline void sca_tx_intr(port_t *port) break; /* Transmitter is/will_be sending this frame */ desc = desc_address(port, port->txlast, 1); - stats->tx_packets++; - stats->tx_bytes += readw(&desc->len); + dev->stats.tx_packets++; + dev->stats.tx_bytes += readw(&desc->len); writeb(0, &desc->stat); /* Free descriptor */ port->txlast = next_desc(port, port->txlast, 1); } diff --git a/drivers/net/wan/hdlc.c b/drivers/net/wan/hdlc.c index 7f984895b0d5..e3a536477c7e 100644 --- a/drivers/net/wan/hdlc.c +++ b/drivers/net/wan/hdlc.c @@ -57,7 +57,7 @@ static int hdlc_change_mtu(struct net_device *dev, int new_mtu) static struct net_device_stats *hdlc_get_stats(struct net_device *dev) { - return hdlc_stats(dev); + return &dev->stats; } diff --git a/drivers/net/wan/hdlc_cisco.c b/drivers/net/wan/hdlc_cisco.c index 762d21c1c703..849819c2552d 100644 --- a/drivers/net/wan/hdlc_cisco.c +++ b/drivers/net/wan/hdlc_cisco.c @@ -252,8 +252,8 @@ static int cisco_rx(struct sk_buff *skb) dev_kfree_skb_any(skb); return NET_RX_DROP; - rx_error: - dev_to_hdlc(dev)->stats.rx_errors++; /* Mark error */ +rx_error: + dev->stats.rx_errors++; /* Mark error */ dev_kfree_skb_any(skb); return NET_RX_DROP; } diff --git a/drivers/net/wan/hdlc_fr.c b/drivers/net/wan/hdlc_fr.c index 6d35155c7145..62e93dac6b13 100644 --- a/drivers/net/wan/hdlc_fr.c +++ b/drivers/net/wan/hdlc_fr.c @@ -135,11 +135,6 @@ typedef struct pvc_device_struct { }state; }pvc_device; -struct pvc_desc { - struct net_device_stats stats; - pvc_device *pvc; -}; - struct frad_state { fr_proto settings; pvc_device *first_pvc; @@ -179,15 +174,6 @@ static inline struct frad_state* state(hdlc_device *hdlc) return(struct frad_state *)(hdlc->state); } -static inline struct pvc_desc* pvcdev_to_desc(struct net_device *dev) -{ - return dev->priv; -} - -static inline struct net_device_stats* pvc_get_stats(struct net_device *dev) -{ - return &pvcdev_to_desc(dev)->stats; -} static inline pvc_device* find_pvc(hdlc_device *hdlc, u16 dlci) { @@ -357,7 +343,7 @@ static int fr_hard_header(struct sk_buff **skb_p, u16 dlci) static int pvc_open(struct net_device *dev) { - pvc_device *pvc = pvcdev_to_desc(dev)->pvc; + pvc_device *pvc = dev->priv; if ((pvc->frad->flags & IFF_UP) == 0) return -EIO; /* Frad must be UP in order to activate PVC */ @@ -377,7 +363,7 @@ static int pvc_open(struct net_device *dev) static int pvc_close(struct net_device *dev) { - pvc_device *pvc = pvcdev_to_desc(dev)->pvc; + pvc_device *pvc = dev->priv; if (--pvc->open_count == 0) { hdlc_device *hdlc = dev_to_hdlc(pvc->frad); @@ -396,7 +382,7 @@ static int pvc_close(struct net_device *dev) static int pvc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) { - pvc_device *pvc = pvcdev_to_desc(dev)->pvc; + pvc_device *pvc = dev->priv; fr_proto_pvc_info info; if (ifr->ifr_settings.type == IF_GET_PROTO) { @@ -424,8 +410,7 @@ static int pvc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) static int pvc_xmit(struct sk_buff *skb, struct net_device *dev) { - pvc_device *pvc = pvcdev_to_desc(dev)->pvc; - struct net_device_stats *stats = pvc_get_stats(dev); + pvc_device *pvc = dev->priv; if (pvc->state.active) { if (dev->type == ARPHRD_ETHER) { @@ -435,7 +420,7 @@ static int pvc_xmit(struct sk_buff *skb, struct net_device *dev) if (skb_tailroom(skb) < pad) if (pskb_expand_head(skb, 0, pad, GFP_ATOMIC)) { - stats->tx_dropped++; + dev->stats.tx_dropped++; dev_kfree_skb(skb); return 0; } @@ -445,17 +430,17 @@ static int pvc_xmit(struct sk_buff *skb, struct net_device *dev) skb->protocol = __constant_htons(ETH_P_802_3); } if (!fr_hard_header(&skb, pvc->dlci)) { - stats->tx_bytes += skb->len; - stats->tx_packets++; + dev->stats.tx_bytes += skb->len; + dev->stats.tx_packets++; if (pvc->state.fecn) /* TX Congestion counter */ - stats->tx_compressed++; + dev->stats.tx_compressed++; skb->dev = pvc->frad; dev_queue_xmit(skb); return 0; } } - stats->tx_dropped++; + dev->stats.tx_dropped++; dev_kfree_skb(skb); return 0; } @@ -955,7 +940,7 @@ static int fr_rx(struct sk_buff *skb) if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL) { - dev_to_hdlc(frad)->stats.rx_dropped++; + frad->stats.rx_dropped++; return NET_RX_DROP; } @@ -1003,11 +988,10 @@ static int fr_rx(struct sk_buff *skb) } if (dev) { - struct net_device_stats *stats = pvc_get_stats(dev); - stats->rx_packets++; /* PVC traffic */ - stats->rx_bytes += skb->len; + dev->stats.rx_packets++; /* PVC traffic */ + dev->stats.rx_bytes += skb->len; if (pvc->state.becn) - stats->rx_compressed++; + dev->stats.rx_compressed++; skb->dev = dev; netif_rx(skb); return NET_RX_SUCCESS; @@ -1017,7 +1001,7 @@ static int fr_rx(struct sk_buff *skb) } rx_error: - dev_to_hdlc(frad)->stats.rx_errors++; /* Mark error */ + frad->stats.rx_errors++; /* Mark error */ dev_kfree_skb_any(skb); return NET_RX_DROP; } @@ -1088,7 +1072,7 @@ static void pvc_setup(struct net_device *dev) static int fr_add_pvc(struct net_device *frad, unsigned int dlci, int type) { hdlc_device *hdlc = dev_to_hdlc(frad); - pvc_device *pvc = NULL; + pvc_device *pvc; struct net_device *dev; int result, used; @@ -1104,10 +1088,9 @@ static int fr_add_pvc(struct net_device *frad, unsigned int dlci, int type) used = pvc_is_used(pvc); if (type == ARPHRD_ETHER) - dev = alloc_netdev(sizeof(struct pvc_desc), "pvceth%d", - ether_setup); + dev = alloc_netdev(0, "pvceth%d", ether_setup); else - dev = alloc_netdev(sizeof(struct pvc_desc), "pvc%d", pvc_setup); + dev = alloc_netdev(0, "pvc%d", pvc_setup); if (!dev) { printk(KERN_WARNING "%s: Memory squeeze on fr_pvc()\n", @@ -1123,14 +1106,13 @@ static int fr_add_pvc(struct net_device *frad, unsigned int dlci, int type) dlci_to_q922(dev->broadcast, dlci); } dev->hard_start_xmit = pvc_xmit; - dev->get_stats = pvc_get_stats; dev->open = pvc_open; dev->stop = pvc_close; dev->do_ioctl = pvc_ioctl; dev->change_mtu = pvc_change_mtu; dev->mtu = HDLC_MAX_MTU; dev->tx_queue_len = 0; - pvcdev_to_desc(dev)->pvc = pvc; + dev->priv = pvc; result = dev_alloc_name(dev, dev->name); if (result < 0) { diff --git a/drivers/net/wan/hdlc_raw_eth.c b/drivers/net/wan/hdlc_raw_eth.c index d20c685f6711..26dee600506f 100644 --- a/drivers/net/wan/hdlc_raw_eth.c +++ b/drivers/net/wan/hdlc_raw_eth.c @@ -33,7 +33,7 @@ static int eth_tx(struct sk_buff *skb, struct net_device *dev) int len = skb->len; if (skb_tailroom(skb) < pad) if (pskb_expand_head(skb, 0, pad, GFP_ATOMIC)) { - hdlc_stats(dev)->tx_dropped++; + dev->stats.tx_dropped++; dev_kfree_skb(skb); return 0; } diff --git a/drivers/net/wan/hdlc_x25.c b/drivers/net/wan/hdlc_x25.c index c15cc11e399b..e808720030ef 100644 --- a/drivers/net/wan/hdlc_x25.c +++ b/drivers/net/wan/hdlc_x25.c @@ -164,17 +164,15 @@ static void x25_close(struct net_device *dev) static int x25_rx(struct sk_buff *skb) { - struct hdlc_device *hdlc = dev_to_hdlc(skb->dev); - if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL) { - hdlc->stats.rx_dropped++; + skb->dev->stats.rx_dropped++; return NET_RX_DROP; } if (lapb_data_received(skb->dev, skb) == LAPB_OK) return NET_RX_SUCCESS; - hdlc->stats.rx_errors++; + skb->dev->stats.rx_errors++; dev_kfree_skb_any(skb); return NET_RX_DROP; } diff --git a/drivers/net/wan/pc300_drv.c b/drivers/net/wan/pc300_drv.c index 57914fbd41d3..334170527755 100644 --- a/drivers/net/wan/pc300_drv.c +++ b/drivers/net/wan/pc300_drv.c @@ -285,7 +285,6 @@ static void rx_dma_buf_init(pc300_t *, int); static void tx_dma_buf_check(pc300_t *, int); static void rx_dma_buf_check(pc300_t *, int); static irqreturn_t cpc_intr(int, void *); -static struct net_device_stats *cpc_get_stats(struct net_device *); static int clock_rate_calc(uclong, uclong, int *); static uclong detect_ram(pc300_t *); static void plx_init(pc300_t *); @@ -1775,13 +1774,12 @@ static void cpc_tx_timeout(struct net_device *dev) pc300dev_t *d = (pc300dev_t *) dev->priv; pc300ch_t *chan = (pc300ch_t *) d->chan; pc300_t *card = (pc300_t *) chan->card; - struct net_device_stats *stats = hdlc_stats(dev); int ch = chan->channel; unsigned long flags; ucchar ilar; - stats->tx_errors++; - stats->tx_aborted_errors++; + dev->stats.tx_errors++; + dev->stats.tx_aborted_errors++; CPC_LOCK(card, flags); if ((ilar = cpc_readb(card->hw.scabase + ILAR)) != 0) { printk("%s: ILAR=0x%x\n", dev->name, ilar); @@ -1803,7 +1801,6 @@ static int cpc_queue_xmit(struct sk_buff *skb, struct net_device *dev) pc300dev_t *d = (pc300dev_t *) dev->priv; pc300ch_t *chan = (pc300ch_t *) d->chan; pc300_t *card = (pc300_t *) chan->card; - struct net_device_stats *stats = hdlc_stats(dev); int ch = chan->channel; unsigned long flags; #ifdef PC300_DEBUG_TX @@ -1817,13 +1814,13 @@ static int cpc_queue_xmit(struct sk_buff *skb, struct net_device *dev) } else if (!netif_carrier_ok(dev)) { /* DCD must be OFF: drop packet */ dev_kfree_skb(skb); - stats->tx_errors++; - stats->tx_carrier_errors++; + dev->stats.tx_errors++; + dev->stats.tx_carrier_errors++; return 0; } else if (cpc_readb(card->hw.scabase + M_REG(ST3, ch)) & ST3_DCD) { printk("%s: DCD is OFF. Going administrative down.\n", dev->name); - stats->tx_errors++; - stats->tx_carrier_errors++; + dev->stats.tx_errors++; + dev->stats.tx_carrier_errors++; dev_kfree_skb(skb); netif_carrier_off(dev); CPC_LOCK(card, flags); @@ -1843,8 +1840,8 @@ static int cpc_queue_xmit(struct sk_buff *skb, struct net_device *dev) // printk("%s: write error. Dropping TX packet.\n", dev->name); netif_stop_queue(dev); dev_kfree_skb(skb); - stats->tx_errors++; - stats->tx_dropped++; + dev->stats.tx_errors++; + dev->stats.tx_dropped++; return 0; } #ifdef PC300_DEBUG_TX @@ -1886,7 +1883,6 @@ static void cpc_net_rx(struct net_device *dev) pc300dev_t *d = (pc300dev_t *) dev->priv; pc300ch_t *chan = (pc300ch_t *) d->chan; pc300_t *card = (pc300_t *) chan->card; - struct net_device_stats *stats = hdlc_stats(dev); int ch = chan->channel; #ifdef PC300_DEBUG_RX int i; @@ -1922,24 +1918,24 @@ static void cpc_net_rx(struct net_device *dev) #endif if ((skb == NULL) && (rxb > 0)) { /* rxb > dev->mtu */ - stats->rx_errors++; - stats->rx_length_errors++; + dev->stats.rx_errors++; + dev->stats.rx_length_errors++; continue; } if (rxb < 0) { /* Invalid frame */ rxb = -rxb; if (rxb & DST_OVR) { - stats->rx_errors++; - stats->rx_fifo_errors++; + dev->stats.rx_errors++; + dev->stats.rx_fifo_errors++; } if (rxb & DST_CRC) { - stats->rx_errors++; - stats->rx_crc_errors++; + dev->stats.rx_errors++; + dev->stats.rx_crc_errors++; } if (rxb & (DST_RBIT | DST_SHRT | DST_ABT)) { - stats->rx_errors++; - stats->rx_frame_errors++; + dev->stats.rx_errors++; + dev->stats.rx_frame_errors++; } } if (skb) { @@ -1948,7 +1944,7 @@ static void cpc_net_rx(struct net_device *dev) continue; } - stats->rx_bytes += rxb; + dev->stats.rx_bytes += rxb; #ifdef PC300_DEBUG_RX printk("%s R:", dev->name); @@ -1959,7 +1955,7 @@ static void cpc_net_rx(struct net_device *dev) if (d->trace_on) { cpc_trace(dev, skb, 'R'); } - stats->rx_packets++; + dev->stats.rx_packets++; skb->protocol = hdlc_type_trans(skb, dev); netif_rx(skb); } @@ -1974,16 +1970,15 @@ static void sca_tx_intr(pc300dev_t *dev) pc300_t *card = (pc300_t *)chan->card; int ch = chan->channel; volatile pcsca_bd_t __iomem * ptdescr; - struct net_device_stats *stats = hdlc_stats(dev->dev); /* Clean up descriptors from previous transmission */ ptdescr = (card->hw.rambase + TX_BD_ADDR(ch,chan->tx_first_bd)); - while ((cpc_readl(card->hw.scabase + DTX_REG(CDAL,ch)) != - TX_BD_ADDR(ch,chan->tx_first_bd)) && - (cpc_readb(&ptdescr->status) & DST_OSB)) { - stats->tx_packets++; - stats->tx_bytes += cpc_readw(&ptdescr->len); + while ((cpc_readl(card->hw.scabase + DTX_REG(CDAL,ch)) != + TX_BD_ADDR(ch,chan->tx_first_bd)) && + (cpc_readb(&ptdescr->status) & DST_OSB)) { + dev->dev->stats.tx_packets++; + dev->dev->stats.tx_bytes += cpc_readw(&ptdescr->len); cpc_writeb(&ptdescr->status, DST_OSB); cpc_writew(&ptdescr->len, 0); chan->nfree_tx_bd++; @@ -2048,8 +2043,8 @@ static void sca_intr(pc300_t * card) } cpc_net_rx(dev); /* Discard invalid frames */ - hdlc_stats(dev)->rx_errors++; - hdlc_stats(dev)->rx_over_errors++; + dev->stats.rx_errors++; + dev->stats.rx_over_errors++; chan->rx_first_bd = 0; chan->rx_last_bd = N_DMA_RX_BUF - 1; rx_dma_start(card, ch); @@ -2115,8 +2110,8 @@ static void sca_intr(pc300_t * card) card->hw.cpld_reg2) & ~ (CPLD_REG2_FALC_LED1 << (2 * ch))); } - hdlc_stats(dev)->tx_errors++; - hdlc_stats(dev)->tx_fifo_errors++; + dev->stats.tx_errors++; + dev->stats.tx_fifo_errors++; sca_tx_intr(d); } } @@ -2604,7 +2599,7 @@ static int cpc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) case SIOCGPC300UTILSTATS: { if (!arg) { /* clear statistics */ - memset(hdlc_stats(dev), 0, sizeof(struct net_device_stats)); + memset(&dev->stats, 0, sizeof(dev->stats)); if (card->hw.type == PC300_TE) { memset(&chan->falc, 0, sizeof(falc_t)); } @@ -2615,8 +2610,8 @@ static int cpc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) pc300stats.hw_type = card->hw.type; pc300stats.line_on = card->chan[ch].d.line_on; pc300stats.line_off = card->chan[ch].d.line_off; - memcpy(&pc300stats.gen_stats, hdlc_stats(dev), - sizeof(struct net_device_stats)); + memcpy(&pc300stats.gen_stats, &dev->stats, + sizeof(dev->stats)); if (card->hw.type == PC300_TE) memcpy(&pc300stats.te_stats,&chan->falc,sizeof(falc_t)); if (copy_to_user(arg, &pc300stats, sizeof(pc300stats_t))) @@ -2823,11 +2818,6 @@ static int cpc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) } } -static struct net_device_stats *cpc_get_stats(struct net_device *dev) -{ - return hdlc_stats(dev); -} - static int clock_rate_calc(uclong rate, uclong clock, int *br_io) { int br, tc; @@ -3394,7 +3384,6 @@ static void cpc_init_card(pc300_t * card) dev->stop = cpc_close; dev->tx_timeout = cpc_tx_timeout; dev->watchdog_timeo = PC300_TX_TIMEOUT; - dev->get_stats = cpc_get_stats; dev->set_multicast_list = NULL; dev->set_mac_address = NULL; dev->change_mtu = cpc_change_mtu; diff --git a/drivers/net/wan/pc300_tty.c b/drivers/net/wan/pc300_tty.c index e03eef2f2282..4518d0aa2480 100644 --- a/drivers/net/wan/pc300_tty.c +++ b/drivers/net/wan/pc300_tty.c @@ -458,7 +458,7 @@ static int cpc_tty_write(struct tty_struct *tty, const unsigned char *buf, int c CPC_TTY_DBG("%s: cpc_tty_write data len=%i\n",cpc_tty->name,count); pc300chan = (pc300ch_t *)((pc300dev_t*)cpc_tty->pc300dev)->chan; - stats = hdlc_stats(((pc300dev_t*)cpc_tty->pc300dev)->dev); + stats = &cpc_tty->pc300dev->dev->stats; card = (pc300_t *) pc300chan->card; ch = pc300chan->channel; @@ -688,9 +688,9 @@ static void cpc_tty_rx_work(struct work_struct *work) if (cpc_tty->tty) { ld = tty_ldisc_ref(cpc_tty->tty); if (ld) { - if (ld->receive_buf) { + if (ld->ops->receive_buf) { CPC_TTY_DBG("%s: call line disc. receive_buf\n",cpc_tty->name); - ld->receive_buf(cpc_tty->tty, (char *)(buf->data), &flags, buf->size); + ld->ops->receive_buf(cpc_tty->tty, (char *)(buf->data), &flags, buf->size); } tty_ldisc_deref(ld); } @@ -743,7 +743,7 @@ void cpc_tty_receive(pc300dev_t *pc300dev) pc300_t *card = (pc300_t *)pc300chan->card; int ch = pc300chan->channel; volatile pcsca_bd_t __iomem * ptdescr; - struct net_device_stats *stats = hdlc_stats(pc300dev->dev); + struct net_device_stats *stats = &pc300dev->dev->stats; int rx_len, rx_aux; volatile unsigned char status; unsigned short first_bd = pc300chan->rx_first_bd; @@ -917,7 +917,7 @@ static int cpc_tty_send_to_card(pc300dev_t *dev,void* buf, int len) pc300ch_t *chan = (pc300ch_t *)dev->chan; pc300_t *card = (pc300_t *)chan->card; int ch = chan->channel; - struct net_device_stats *stats = hdlc_stats(dev->dev); + struct net_device_stats *stats = &dev->dev->stats; unsigned long flags; volatile pcsca_bd_t __iomem *ptdescr; int i, nchar; diff --git a/drivers/net/wan/wanxl.c b/drivers/net/wan/wanxl.c index d4aab8a28b61..a8a5ca0ee6c2 100644 --- a/drivers/net/wan/wanxl.c +++ b/drivers/net/wan/wanxl.c @@ -161,7 +161,6 @@ static inline void wanxl_cable_intr(port_t *port) static inline void wanxl_tx_intr(port_t *port) { struct net_device *dev = port->dev; - struct net_device_stats *stats = hdlc_stats(dev); while (1) { desc_t *desc = &get_status(port)->tx_descs[port->tx_in]; struct sk_buff *skb = port->tx_skbs[port->tx_in]; @@ -173,13 +172,13 @@ static inline void wanxl_tx_intr(port_t *port) return; case PACKET_UNDERRUN: - stats->tx_errors++; - stats->tx_fifo_errors++; + dev->stats.tx_errors++; + dev->stats.tx_fifo_errors++; break; default: - stats->tx_packets++; - stats->tx_bytes += skb->len; + dev->stats.tx_packets++; + dev->stats.tx_bytes += skb->len; } desc->stat = PACKET_EMPTY; /* Free descriptor */ pci_unmap_single(port->card->pdev, desc->address, skb->len, @@ -205,10 +204,9 @@ static inline void wanxl_rx_intr(card_t *card) port_t *port = &card->ports[desc->stat & PACKET_PORT_MASK]; struct net_device *dev = port->dev; - struct net_device_stats *stats = hdlc_stats(dev); if (!skb) - stats->rx_dropped++; + dev->stats.rx_dropped++; else { pci_unmap_single(card->pdev, desc->address, BUFFER_LENGTH, @@ -220,8 +218,8 @@ static inline void wanxl_rx_intr(card_t *card) skb->len); debug_frame(skb); #endif - stats->rx_packets++; - stats->rx_bytes += skb->len; + dev->stats.rx_packets++; + dev->stats.rx_bytes += skb->len; dev->last_rx = jiffies; skb->protocol = hdlc_type_trans(skb, dev); netif_rx(skb); @@ -468,13 +466,13 @@ static int wanxl_close(struct net_device *dev) static struct net_device_stats *wanxl_get_stats(struct net_device *dev) { - struct net_device_stats *stats = hdlc_stats(dev); port_t *port = dev_to_port(dev); - stats->rx_over_errors = get_status(port)->rx_overruns; - stats->rx_frame_errors = get_status(port)->rx_frame_errors; - stats->rx_errors = stats->rx_over_errors + stats->rx_frame_errors; - return stats; + dev->stats.rx_over_errors = get_status(port)->rx_overruns; + dev->stats.rx_frame_errors = get_status(port)->rx_frame_errors; + dev->stats.rx_errors = dev->stats.rx_over_errors + + dev->stats.rx_frame_errors; + return &dev->stats; } diff --git a/drivers/net/wan/x25_asy.c b/drivers/net/wan/x25_asy.c index 069f8bb0a99f..2a6c7a60756f 100644 --- a/drivers/net/wan/x25_asy.c +++ b/drivers/net/wan/x25_asy.c @@ -754,7 +754,7 @@ static void x25_asy_setup(struct net_device *dev) dev->flags = IFF_NOARP; } -static struct tty_ldisc x25_ldisc = { +static struct tty_ldisc_ops x25_ldisc = { .owner = THIS_MODULE, .magic = TTY_LDISC_MAGIC, .name = "X.25", diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig index fdf5aa8b8429..91fc2c765d90 100644 --- a/drivers/net/wireless/Kconfig +++ b/drivers/net/wireless/Kconfig @@ -635,14 +635,20 @@ config RTL8180 Thanks to Realtek for their support! config RTL8187 - tristate "Realtek 8187 USB support" + tristate "Realtek 8187 and 8187B USB support" depends on MAC80211 && USB && WLAN_80211 && EXPERIMENTAL select EEPROM_93CX6 ---help--- - This is a driver for RTL8187 based cards. - These are USB based chips found in cards such as: + This is a driver for RTL8187 and RTL8187B based cards. + These are USB based chips found in devices such as: Netgear WG111v2 + Level 1 WNC-0301USB + Micronet SP907GK V5 + Encore ENUWI-G2 + Trendnet TEW-424UB + ASUS P5B Deluxe + Toshiba Satellite Pro series of laptops Thanks to Realtek for their support! @@ -673,6 +679,19 @@ config ADM8211 Thanks to Infineon-ADMtek for their support of this driver. +config MAC80211_HWSIM + tristate "Simulated radio testing tool for mac80211" + depends on MAC80211 && WLAN_80211 + ---help--- + This driver is a developer testing tool that can be used to test + IEEE 802.11 networking stack (mac80211) functionality. This is not + needed for normal wireless LAN usage and is only for testing. See + Documentation/networking/mac80211_hwsim for more information on how + to use this tool. + + To compile this driver as a module, choose M here: the module will be + called mac80211_hwsim. If unsure, say N. + source "drivers/net/wireless/p54/Kconfig" source "drivers/net/wireless/ath5k/Kconfig" source "drivers/net/wireless/iwlwifi/Kconfig" diff --git a/drivers/net/wireless/Makefile b/drivers/net/wireless/Makefile index 2c343aae38d4..54a4f6f1db67 100644 --- a/drivers/net/wireless/Makefile +++ b/drivers/net/wireless/Makefile @@ -62,3 +62,5 @@ obj-$(CONFIG_RT2X00) += rt2x00/ obj-$(CONFIG_P54_COMMON) += p54/ obj-$(CONFIG_ATH5K) += ath5k/ + +obj-$(CONFIG_MAC80211_HWSIM) += mac80211_hwsim.o diff --git a/drivers/net/wireless/adm8211.c b/drivers/net/wireless/adm8211.c index 5c0d2b082750..3333d4596b8d 100644 --- a/drivers/net/wireless/adm8211.c +++ b/drivers/net/wireless/adm8211.c @@ -306,11 +306,10 @@ static int adm8211_get_tx_stats(struct ieee80211_hw *dev, struct ieee80211_tx_queue_stats *stats) { struct adm8211_priv *priv = dev->priv; - struct ieee80211_tx_queue_stats_data *data = &stats->data[0]; - data->len = priv->cur_tx - priv->dirty_tx; - data->limit = priv->tx_ring_size - 2; - data->count = priv->dirty_tx; + stats[0].len = priv->cur_tx - priv->dirty_tx; + stats[0].limit = priv->tx_ring_size - 2; + stats[0].count = priv->dirty_tx; return 0; } @@ -325,7 +324,7 @@ static void adm8211_interrupt_tci(struct ieee80211_hw *dev) for (dirty_tx = priv->dirty_tx; priv->cur_tx - dirty_tx; dirty_tx++) { unsigned int entry = dirty_tx % priv->tx_ring_size; u32 status = le32_to_cpu(priv->tx_ring[entry].status); - struct ieee80211_tx_status tx_status; + struct ieee80211_tx_info *txi; struct adm8211_tx_ring_info *info; struct sk_buff *skb; @@ -335,24 +334,23 @@ static void adm8211_interrupt_tci(struct ieee80211_hw *dev) info = &priv->tx_buffers[entry]; skb = info->skb; + txi = IEEE80211_SKB_CB(skb); /* TODO: check TDES0_STATUS_TUF and TDES0_STATUS_TRO */ pci_unmap_single(priv->pdev, info->mapping, info->skb->len, PCI_DMA_TODEVICE); - memset(&tx_status, 0, sizeof(tx_status)); + memset(&txi->status, 0, sizeof(txi->status)); skb_pull(skb, sizeof(struct adm8211_tx_hdr)); memcpy(skb_push(skb, info->hdrlen), skb->cb, info->hdrlen); - memcpy(&tx_status.control, &info->tx_control, - sizeof(tx_status.control)); - if (!(tx_status.control.flags & IEEE80211_TXCTL_NO_ACK)) { + if (!(txi->flags & IEEE80211_TX_CTL_NO_ACK)) { if (status & TDES0_STATUS_ES) - tx_status.excessive_retries = 1; + txi->status.excessive_retries = 1; else - tx_status.flags |= IEEE80211_TX_STATUS_ACK; + txi->flags |= IEEE80211_TX_STAT_ACK; } - ieee80211_tx_status_irqsafe(dev, skb, &tx_status); + ieee80211_tx_status_irqsafe(dev, skb); info->skb = NULL; } @@ -446,9 +444,9 @@ static void adm8211_interrupt_rci(struct ieee80211_hw *dev) struct ieee80211_rx_status rx_status = {0}; if (priv->pdev->revision < ADM8211_REV_CA) - rx_status.ssi = rssi; + rx_status.signal = rssi; else - rx_status.ssi = 100 - rssi; + rx_status.signal = 100 - rssi; rx_status.rate_idx = rate; @@ -1639,7 +1637,6 @@ static void adm8211_calc_durations(int *dur, int *plcp, size_t payload_len, int /* Transmit skb w/adm8211_tx_hdr (802.11 header created by hardware) */ static void adm8211_tx_raw(struct ieee80211_hw *dev, struct sk_buff *skb, u16 plcp_signal, - struct ieee80211_tx_control *control, size_t hdrlen) { struct adm8211_priv *priv = dev->priv; @@ -1665,7 +1662,6 @@ static void adm8211_tx_raw(struct ieee80211_hw *dev, struct sk_buff *skb, priv->tx_buffers[entry].skb = skb; priv->tx_buffers[entry].mapping = mapping; - memcpy(&priv->tx_buffers[entry].tx_control, control, sizeof(*control)); priv->tx_buffers[entry].hdrlen = hdrlen; priv->tx_ring[entry].buffer1 = cpu_to_le32(mapping); @@ -1686,22 +1682,20 @@ static void adm8211_tx_raw(struct ieee80211_hw *dev, struct sk_buff *skb, } /* Put adm8211_tx_hdr on skb and transmit */ -static int adm8211_tx(struct ieee80211_hw *dev, struct sk_buff *skb, - struct ieee80211_tx_control *control) +static int adm8211_tx(struct ieee80211_hw *dev, struct sk_buff *skb) { struct adm8211_tx_hdr *txhdr; - u16 fc; size_t payload_len, hdrlen; int plcp, dur, len, plcp_signal, short_preamble; struct ieee80211_hdr *hdr; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + struct ieee80211_rate *txrate = ieee80211_get_tx_rate(dev, info); - short_preamble = !!(control->tx_rate->flags & - IEEE80211_TXCTL_SHORT_PREAMBLE); - plcp_signal = control->tx_rate->bitrate; + short_preamble = !!(txrate->flags & IEEE80211_TX_CTL_SHORT_PREAMBLE); + plcp_signal = txrate->bitrate; hdr = (struct ieee80211_hdr *)skb->data; - fc = le16_to_cpu(hdr->frame_control) & ~IEEE80211_FCTL_PROTECTED; - hdrlen = ieee80211_get_hdrlen(fc); + hdrlen = ieee80211_hdrlen(hdr->frame_control); memcpy(skb->cb, skb->data, hdrlen); hdr = (struct ieee80211_hdr *)skb->cb; skb_pull(skb, hdrlen); @@ -1715,8 +1709,6 @@ static int adm8211_tx(struct ieee80211_hw *dev, struct sk_buff *skb, txhdr->frame_control = hdr->frame_control; len = hdrlen + payload_len + FCS_LEN; - if (fc & IEEE80211_FCTL_PROTECTED) - len += 8; txhdr->frag = cpu_to_le16(0x0FFF); adm8211_calc_durations(&dur, &plcp, payload_len, @@ -1731,15 +1723,12 @@ static int adm8211_tx(struct ieee80211_hw *dev, struct sk_buff *skb, if (short_preamble) txhdr->header_control |= cpu_to_le16(ADM8211_TXHDRCTL_SHORT_PREAMBLE); - if (control->flags & IEEE80211_TXCTL_USE_RTS_CTS) + if (info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) txhdr->header_control |= cpu_to_le16(ADM8211_TXHDRCTL_ENABLE_RTS); - if (fc & IEEE80211_FCTL_PROTECTED) - txhdr->header_control |= cpu_to_le16(ADM8211_TXHDRCTL_ENABLE_WEP_ENGINE); + txhdr->retry_limit = info->control.retry_limit; - txhdr->retry_limit = control->retry_limit; - - adm8211_tx_raw(dev, skb, plcp_signal, control, hdrlen); + adm8211_tx_raw(dev, skb, plcp_signal, hdrlen); return NETDEV_TX_OK; } @@ -1894,9 +1883,10 @@ static int __devinit adm8211_probe(struct pci_dev *pdev, dev->extra_tx_headroom = sizeof(struct adm8211_tx_hdr); /* dev->flags = IEEE80211_HW_RX_INCLUDES_FCS in promisc mode */ + dev->flags = IEEE80211_HW_SIGNAL_UNSPEC; dev->channel_change_time = 1000; - dev->max_rssi = 100; /* FIXME: find better value */ + dev->max_signal = 100; /* FIXME: find better value */ dev->queues = 1; /* ADM8211C supports more, maybe ADM8211B too */ @@ -2015,7 +2005,7 @@ static int adm8211_resume(struct pci_dev *pdev) if (priv->mode != IEEE80211_IF_TYPE_INVALID) { adm8211_start(dev); - ieee80211_start_queues(dev); + ieee80211_wake_queues(dev); } return 0; diff --git a/drivers/net/wireless/adm8211.h b/drivers/net/wireless/adm8211.h index 8d7c564b3b04..9b190ee26e90 100644 --- a/drivers/net/wireless/adm8211.h +++ b/drivers/net/wireless/adm8211.h @@ -443,7 +443,6 @@ struct adm8211_rx_ring_info { struct adm8211_tx_ring_info { struct sk_buff *skb; dma_addr_t mapping; - struct ieee80211_tx_control tx_control; size_t hdrlen; }; diff --git a/drivers/net/wireless/airo.c b/drivers/net/wireless/airo.c index 32019fb878d8..b5cd850a4a59 100644 --- a/drivers/net/wireless/airo.c +++ b/drivers/net/wireless/airo.c @@ -85,10 +85,10 @@ static struct pci_driver airo_driver = { /* Include Wireless Extension definition and check version - Jean II */ #include <linux/wireless.h> -#define WIRELESS_SPY // enable iwspy support -#include <net/iw_handler.h> // New driver API +#define WIRELESS_SPY /* enable iwspy support */ +#include <net/iw_handler.h> /* New driver API */ -#define CISCO_EXT // enable Cisco extensions +#define CISCO_EXT /* enable Cisco extensions */ #ifdef CISCO_EXT #include <linux/delay.h> #endif @@ -281,7 +281,7 @@ MODULE_PARM_DESC(proc_perm, "The permission bits of the files in /proc"); /* This is a kind of sloppy hack to get this information to OUT4500 and IN4500. I would be extremely interested in the situation where this doesn't work though!!! */ -static int do8bitIO = 0; +static int do8bitIO /* = 0 */; /* Return codes */ #define SUCCESS 0 @@ -398,8 +398,8 @@ static int do8bitIO = 0; #define MAXTXQ 64 /* BAP selectors */ -#define BAP0 0 // Used for receiving packets -#define BAP1 2 // Used for xmiting packets and working with RIDS +#define BAP0 0 /* Used for receiving packets */ +#define BAP1 2 /* Used for xmiting packets and working with RIDS */ /* Flags */ #define COMMAND_BUSY 0x8000 @@ -1148,7 +1148,6 @@ static u8 airo_dbm_to_pct (tdsRssiEntry *rssi_rid, u8 dbm); static void airo_networks_free(struct airo_info *ai); struct airo_info { - struct net_device_stats stats; struct net_device *dev; struct list_head dev_list; /* Note, we can have MAX_FIDS outstanding. FIDs are 16-bits, so we @@ -1924,7 +1923,7 @@ static int mpi_start_xmit(struct sk_buff *skb, struct net_device *dev) { if (npacks >= MAXTXQ - 1) { netif_stop_queue (dev); if (npacks > MAXTXQ) { - ai->stats.tx_fifo_errors++; + dev->stats.tx_fifo_errors++; return 1; } skb_queue_tail (&ai->txq, skb); @@ -2044,13 +2043,13 @@ static void get_tx_error(struct airo_info *ai, s32 fid) bap_read(ai, &status, 2, BAP0); } if (le16_to_cpu(status) & 2) /* Too many retries */ - ai->stats.tx_aborted_errors++; + ai->dev->stats.tx_aborted_errors++; if (le16_to_cpu(status) & 4) /* Transmit lifetime exceeded */ - ai->stats.tx_heartbeat_errors++; + ai->dev->stats.tx_heartbeat_errors++; if (le16_to_cpu(status) & 8) /* Aid fail */ { } if (le16_to_cpu(status) & 0x10) /* MAC disabled */ - ai->stats.tx_carrier_errors++; + ai->dev->stats.tx_carrier_errors++; if (le16_to_cpu(status) & 0x20) /* Association lost */ { } /* We produce a TXDROP event only for retry or lifetime @@ -2102,7 +2101,7 @@ static void airo_end_xmit(struct net_device *dev) { for (; i < MAX_FIDS / 2 && (priv->fids[i] & 0xffff0000); i++); } else { priv->fids[fid] &= 0xffff; - priv->stats.tx_window_errors++; + dev->stats.tx_window_errors++; } if (i < MAX_FIDS / 2) netif_wake_queue(dev); @@ -2128,7 +2127,7 @@ static int airo_start_xmit(struct sk_buff *skb, struct net_device *dev) { netif_stop_queue(dev); if (i == MAX_FIDS / 2) { - priv->stats.tx_fifo_errors++; + dev->stats.tx_fifo_errors++; return 1; } } @@ -2167,7 +2166,7 @@ static void airo_end_xmit11(struct net_device *dev) { for (; i < MAX_FIDS && (priv->fids[i] & 0xffff0000); i++); } else { priv->fids[fid] &= 0xffff; - priv->stats.tx_window_errors++; + dev->stats.tx_window_errors++; } if (i < MAX_FIDS) netif_wake_queue(dev); @@ -2199,7 +2198,7 @@ static int airo_start_xmit11(struct sk_buff *skb, struct net_device *dev) { netif_stop_queue(dev); if (i == MAX_FIDS) { - priv->stats.tx_fifo_errors++; + dev->stats.tx_fifo_errors++; return 1; } } @@ -2219,8 +2218,9 @@ static int airo_start_xmit11(struct sk_buff *skb, struct net_device *dev) { return 0; } -static void airo_read_stats(struct airo_info *ai) +static void airo_read_stats(struct net_device *dev) { + struct airo_info *ai = dev->priv; StatsRid stats_rid; __le32 *vals = stats_rid.vals; @@ -2232,23 +2232,24 @@ static void airo_read_stats(struct airo_info *ai) readStatsRid(ai, &stats_rid, RID_STATS, 0); up(&ai->sem); - ai->stats.rx_packets = le32_to_cpu(vals[43]) + le32_to_cpu(vals[44]) + + dev->stats.rx_packets = le32_to_cpu(vals[43]) + le32_to_cpu(vals[44]) + le32_to_cpu(vals[45]); - ai->stats.tx_packets = le32_to_cpu(vals[39]) + le32_to_cpu(vals[40]) + + dev->stats.tx_packets = le32_to_cpu(vals[39]) + le32_to_cpu(vals[40]) + le32_to_cpu(vals[41]); - ai->stats.rx_bytes = le32_to_cpu(vals[92]); - ai->stats.tx_bytes = le32_to_cpu(vals[91]); - ai->stats.rx_errors = le32_to_cpu(vals[0]) + le32_to_cpu(vals[2]) + + dev->stats.rx_bytes = le32_to_cpu(vals[92]); + dev->stats.tx_bytes = le32_to_cpu(vals[91]); + dev->stats.rx_errors = le32_to_cpu(vals[0]) + le32_to_cpu(vals[2]) + le32_to_cpu(vals[3]) + le32_to_cpu(vals[4]); - ai->stats.tx_errors = le32_to_cpu(vals[42]) + ai->stats.tx_fifo_errors; - ai->stats.multicast = le32_to_cpu(vals[43]); - ai->stats.collisions = le32_to_cpu(vals[89]); + dev->stats.tx_errors = le32_to_cpu(vals[42]) + + dev->stats.tx_fifo_errors; + dev->stats.multicast = le32_to_cpu(vals[43]); + dev->stats.collisions = le32_to_cpu(vals[89]); /* detailed rx_errors: */ - ai->stats.rx_length_errors = le32_to_cpu(vals[3]); - ai->stats.rx_crc_errors = le32_to_cpu(vals[4]); - ai->stats.rx_frame_errors = le32_to_cpu(vals[2]); - ai->stats.rx_fifo_errors = le32_to_cpu(vals[0]); + dev->stats.rx_length_errors = le32_to_cpu(vals[3]); + dev->stats.rx_crc_errors = le32_to_cpu(vals[4]); + dev->stats.rx_frame_errors = le32_to_cpu(vals[2]); + dev->stats.rx_fifo_errors = le32_to_cpu(vals[0]); } static struct net_device_stats *airo_get_stats(struct net_device *dev) @@ -2261,10 +2262,10 @@ static struct net_device_stats *airo_get_stats(struct net_device *dev) set_bit(JOB_STATS, &local->jobs); wake_up_interruptible(&local->thr_wait); } else - airo_read_stats(local); + airo_read_stats(dev); } - return &local->stats; + return &dev->stats; } static void airo_set_promisc(struct airo_info *ai) { @@ -3093,7 +3094,7 @@ static int airo_thread(void *data) { else if (test_bit(JOB_XMIT11, &ai->jobs)) airo_end_xmit11(dev); else if (test_bit(JOB_STATS, &ai->jobs)) - airo_read_stats(ai); + airo_read_stats(dev); else if (test_bit(JOB_WSTATS, &ai->jobs)) airo_read_wireless_stats(ai); else if (test_bit(JOB_PROMISC, &ai->jobs)) @@ -3289,7 +3290,7 @@ static irqreturn_t airo_interrupt(int irq, void *dev_id) skb = dev_alloc_skb( len + hdrlen + 2 + 2 ); if ( !skb ) { - apriv->stats.rx_dropped++; + dev->stats.rx_dropped++; goto badrx; } skb_reserve(skb, 2); /* This way the IP header is aligned */ @@ -3557,7 +3558,7 @@ static void mpi_receive_802_3(struct airo_info *ai) skb = dev_alloc_skb(len); if (!skb) { - ai->stats.rx_dropped++; + ai->dev->stats.rx_dropped++; goto badrx; } buffer = skb_put(skb,len); @@ -3650,7 +3651,7 @@ void mpi_receive_802_11 (struct airo_info *ai) skb = dev_alloc_skb( len + hdrlen + 2 ); if ( !skb ) { - ai->stats.rx_dropped++; + ai->dev->stats.rx_dropped++; goto badrx; } buffer = (u16*)skb_put (skb, len + hdrlen); @@ -4560,22 +4561,13 @@ static ssize_t proc_read( struct file *file, size_t len, loff_t *offset ) { - loff_t pos = *offset; - struct proc_data *priv = (struct proc_data*)file->private_data; + struct proc_data *priv = file->private_data; if (!priv->rbuffer) return -EINVAL; - if (pos < 0) - return -EINVAL; - if (pos >= priv->readlen) - return 0; - if (len > priv->readlen - pos) - len = priv->readlen - pos; - if (copy_to_user(buffer, priv->rbuffer + pos, len)) - return -EFAULT; - *offset = pos + len; - return len; + return simple_read_from_buffer(buffer, len, offset, priv->rbuffer, + priv->readlen); } /* @@ -5530,11 +5522,13 @@ static int airo_pci_suspend(struct pci_dev *pdev, pm_message_t state) Cmd cmd; Resp rsp; - if ((ai->APList == NULL) && - (ai->APList = kmalloc(sizeof(APListRid), GFP_KERNEL)) == NULL) + if (!ai->APList) + ai->APList = kmalloc(sizeof(APListRid), GFP_KERNEL); + if (!ai->APList) return -ENOMEM; - if ((ai->SSID == NULL) && - (ai->SSID = kmalloc(sizeof(SsidRid), GFP_KERNEL)) == NULL) + if (!ai->SSID) + ai->SSID = kmalloc(sizeof(SsidRid), GFP_KERNEL); + if (!ai->SSID) return -ENOMEM; readAPListRid(ai, ai->APList); readSsidRid(ai, ai->SSID); @@ -5545,7 +5539,7 @@ static int airo_pci_suspend(struct pci_dev *pdev, pm_message_t state) disable_MAC(ai, 0); netif_device_detach(dev); ai->power = state; - cmd.cmd=HOSTSLEEP; + cmd.cmd = HOSTSLEEP; issuecommand(ai, &cmd, &rsp); pci_enable_wake(pdev, pci_choose_state(pdev, state), 1); @@ -5575,7 +5569,7 @@ static int airo_pci_resume(struct pci_dev *pdev) msleep(100); } - set_bit (FLAG_COMMIT, &ai->flags); + set_bit(FLAG_COMMIT, &ai->flags); disable_MAC(ai, 0); msleep(200); if (ai->SSID) { @@ -5602,9 +5596,6 @@ static int airo_pci_resume(struct pci_dev *pdev) static int __init airo_init_module( void ) { int i; -#if 0 - int have_isa_dev = 0; -#endif airo_entry = create_proc_entry("driver/aironet", S_IFDIR | airo_perm, @@ -5615,15 +5606,11 @@ static int __init airo_init_module( void ) airo_entry->gid = proc_gid; } - for( i = 0; i < 4 && io[i] && irq[i]; i++ ) { + for (i = 0; i < 4 && io[i] && irq[i]; i++) { airo_print_info("", "Trying to configure ISA adapter at irq=%d " "io=0x%x", irq[i], io[i] ); if (init_airo_card( irq[i], io[i], 0, NULL )) -#if 0 - have_isa_dev = 1; -#else /* do nothing */ ; -#endif } #ifdef CONFIG_PCI @@ -5669,7 +5656,7 @@ static void __exit airo_cleanup_module( void ) static u8 airo_rssi_to_dbm (tdsRssiEntry *rssi_rid, u8 rssi) { - if( !rssi_rid ) + if (!rssi_rid) return 0; return (0x100 - rssi_rid[rssi].rssidBm); @@ -5679,10 +5666,10 @@ static u8 airo_dbm_to_pct (tdsRssiEntry *rssi_rid, u8 dbm) { int i; - if( !rssi_rid ) + if (!rssi_rid) return 0; - for( i = 0; i < 256; i++ ) + for (i = 0; i < 256; i++) if (rssi_rid[i].rssidBm == dbm) return rssi_rid[i].rssipct; @@ -7164,6 +7151,7 @@ out: * format that the Wireless Tools will understand - Jean II */ static inline char *airo_translate_scan(struct net_device *dev, + struct iw_request_info *info, char *current_ev, char *end_buf, BSSListRid *bss) @@ -7180,7 +7168,8 @@ static inline char *airo_translate_scan(struct net_device *dev, iwe.cmd = SIOCGIWAP; iwe.u.ap_addr.sa_family = ARPHRD_ETHER; memcpy(iwe.u.ap_addr.sa_data, bss->bssid, ETH_ALEN); - current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_ADDR_LEN); + current_ev = iwe_stream_add_event(info, current_ev, end_buf, + &iwe, IW_EV_ADDR_LEN); /* Other entries will be displayed in the order we give them */ @@ -7190,7 +7179,8 @@ static inline char *airo_translate_scan(struct net_device *dev, iwe.u.data.length = 32; iwe.cmd = SIOCGIWESSID; iwe.u.data.flags = 1; - current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, bss->ssid); + current_ev = iwe_stream_add_point(info, current_ev, end_buf, + &iwe, bss->ssid); /* Add mode */ iwe.cmd = SIOCGIWMODE; @@ -7200,7 +7190,8 @@ static inline char *airo_translate_scan(struct net_device *dev, iwe.u.mode = IW_MODE_MASTER; else iwe.u.mode = IW_MODE_ADHOC; - current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_UINT_LEN); + current_ev = iwe_stream_add_event(info, current_ev, end_buf, + &iwe, IW_EV_UINT_LEN); } /* Add frequency */ @@ -7211,7 +7202,8 @@ static inline char *airo_translate_scan(struct net_device *dev, */ iwe.u.freq.m = frequency_list[iwe.u.freq.m - 1] * 100000; iwe.u.freq.e = 1; - current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_FREQ_LEN); + current_ev = iwe_stream_add_event(info, current_ev, end_buf, + &iwe, IW_EV_FREQ_LEN); dBm = le16_to_cpu(bss->dBm); @@ -7231,7 +7223,8 @@ static inline char *airo_translate_scan(struct net_device *dev, | IW_QUAL_DBM; } iwe.u.qual.noise = ai->wstats.qual.noise; - current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_QUAL_LEN); + current_ev = iwe_stream_add_event(info, current_ev, end_buf, + &iwe, IW_EV_QUAL_LEN); /* Add encryption capability */ iwe.cmd = SIOCGIWENCODE; @@ -7240,11 +7233,12 @@ static inline char *airo_translate_scan(struct net_device *dev, else iwe.u.data.flags = IW_ENCODE_DISABLED; iwe.u.data.length = 0; - current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, bss->ssid); + current_ev = iwe_stream_add_point(info, current_ev, end_buf, + &iwe, bss->ssid); /* Rate : stuffing multiple values in a single event require a bit * more of magic - Jean II */ - current_val = current_ev + IW_EV_LCP_LEN; + current_val = current_ev + iwe_stream_lcp_len(info); iwe.cmd = SIOCGIWRATE; /* Those two flags are ignored... */ @@ -7257,10 +7251,12 @@ static inline char *airo_translate_scan(struct net_device *dev, /* Bit rate given in 500 kb/s units (+ 0x80) */ iwe.u.bitrate.value = ((bss->rates[i] & 0x7f) * 500000); /* Add new value to event */ - current_val = iwe_stream_add_value(current_ev, current_val, end_buf, &iwe, IW_EV_PARAM_LEN); + current_val = iwe_stream_add_value(info, current_ev, + current_val, end_buf, + &iwe, IW_EV_PARAM_LEN); } /* Check if we added any event */ - if((current_val - current_ev) > IW_EV_LCP_LEN) + if ((current_val - current_ev) > iwe_stream_lcp_len(info)) current_ev = current_val; /* Beacon interval */ @@ -7269,7 +7265,8 @@ static inline char *airo_translate_scan(struct net_device *dev, iwe.cmd = IWEVCUSTOM; sprintf(buf, "bcn_int=%d", bss->beaconInterval); iwe.u.data.length = strlen(buf); - current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, buf); + current_ev = iwe_stream_add_point(info, current_ev, end_buf, + &iwe, buf); kfree(buf); } @@ -7303,8 +7300,10 @@ static inline char *airo_translate_scan(struct net_device *dev, iwe.cmd = IWEVGENIE; iwe.u.data.length = min(info_element->len + 2, MAX_WPA_IE_LEN); - current_ev = iwe_stream_add_point(current_ev, end_buf, - &iwe, (char *) info_element); + current_ev = iwe_stream_add_point( + info, current_ev, + end_buf, &iwe, + (char *) info_element); } break; @@ -7312,8 +7311,9 @@ static inline char *airo_translate_scan(struct net_device *dev, iwe.cmd = IWEVGENIE; iwe.u.data.length = min(info_element->len + 2, MAX_WPA_IE_LEN); - current_ev = iwe_stream_add_point(current_ev, end_buf, - &iwe, (char *) info_element); + current_ev = iwe_stream_add_point( + info, current_ev, end_buf, + &iwe, (char *) info_element); break; default: @@ -7352,7 +7352,7 @@ static int airo_get_scan(struct net_device *dev, list_for_each_entry (net, &ai->network_list, list) { /* Translate to WE format this entry */ - current_ev = airo_translate_scan(dev, current_ev, + current_ev = airo_translate_scan(dev, info, current_ev, extra + dwrq->length, &net->bss); diff --git a/drivers/net/wireless/arlan-main.c b/drivers/net/wireless/arlan-main.c index dbdfc9e39d20..dec5e874a54d 100644 --- a/drivers/net/wireless/arlan-main.c +++ b/drivers/net/wireless/arlan-main.c @@ -125,7 +125,7 @@ static inline int arlan_drop_tx(struct net_device *dev) { struct arlan_private *priv = netdev_priv(dev); - priv->stats.tx_errors++; + dev->stats.tx_errors++; if (priv->Conf->tx_delay_ms) { priv->tx_done_delayed = jiffies + priv->Conf->tx_delay_ms * HZ / 1000 + 1; @@ -1269,7 +1269,7 @@ static void arlan_tx_done_interrupt(struct net_device *dev, int status) { IFDEBUG(ARLAN_DEBUG_TX_CHAIN) printk("arlan intr: transmit OK\n"); - priv->stats.tx_packets++; + dev->stats.tx_packets++; priv->bad = 0; priv->reset = 0; priv->retransmissions = 0; @@ -1496,7 +1496,7 @@ static void arlan_rx_interrupt(struct net_device *dev, u_char rxStatus, u_short if (skb == NULL) { printk(KERN_ERR "%s: Memory squeeze, dropping packet.\n", dev->name); - priv->stats.rx_dropped++; + dev->stats.rx_dropped++; break; } skb_reserve(skb, 2); @@ -1536,14 +1536,14 @@ static void arlan_rx_interrupt(struct net_device *dev, u_char rxStatus, u_short } netif_rx(skb); dev->last_rx = jiffies; - priv->stats.rx_packets++; - priv->stats.rx_bytes += pkt_len; + dev->stats.rx_packets++; + dev->stats.rx_bytes += pkt_len; } break; default: printk(KERN_ERR "arlan intr: received unknown status\n"); - priv->stats.rx_crc_errors++; + dev->stats.rx_crc_errors++; break; } ARLAN_DEBUG_EXIT("arlan_rx_interrupt"); @@ -1719,23 +1719,23 @@ static struct net_device_stats *arlan_statistics(struct net_device *dev) /* Update the statistics from the device registers. */ - READSHM(priv->stats.collisions, arlan->numReTransmissions, u_int); - READSHM(priv->stats.rx_crc_errors, arlan->numCRCErrors, u_int); - READSHM(priv->stats.rx_dropped, arlan->numFramesDiscarded, u_int); - READSHM(priv->stats.rx_fifo_errors, arlan->numRXBufferOverflows, u_int); - READSHM(priv->stats.rx_frame_errors, arlan->numReceiveFramesLost, u_int); - READSHM(priv->stats.rx_over_errors, arlan->numRXOverruns, u_int); - READSHM(priv->stats.rx_packets, arlan->numDatagramsReceived, u_int); - READSHM(priv->stats.tx_aborted_errors, arlan->numAbortErrors, u_int); - READSHM(priv->stats.tx_carrier_errors, arlan->numStatusTimeouts, u_int); - READSHM(priv->stats.tx_dropped, arlan->numDatagramsDiscarded, u_int); - READSHM(priv->stats.tx_fifo_errors, arlan->numTXUnderruns, u_int); - READSHM(priv->stats.tx_packets, arlan->numDatagramsTransmitted, u_int); - READSHM(priv->stats.tx_window_errors, arlan->numHoldOffs, u_int); + READSHM(dev->stats.collisions, arlan->numReTransmissions, u_int); + READSHM(dev->stats.rx_crc_errors, arlan->numCRCErrors, u_int); + READSHM(dev->stats.rx_dropped, arlan->numFramesDiscarded, u_int); + READSHM(dev->stats.rx_fifo_errors, arlan->numRXBufferOverflows, u_int); + READSHM(dev->stats.rx_frame_errors, arlan->numReceiveFramesLost, u_int); + READSHM(dev->stats.rx_over_errors, arlan->numRXOverruns, u_int); + READSHM(dev->stats.rx_packets, arlan->numDatagramsReceived, u_int); + READSHM(dev->stats.tx_aborted_errors, arlan->numAbortErrors, u_int); + READSHM(dev->stats.tx_carrier_errors, arlan->numStatusTimeouts, u_int); + READSHM(dev->stats.tx_dropped, arlan->numDatagramsDiscarded, u_int); + READSHM(dev->stats.tx_fifo_errors, arlan->numTXUnderruns, u_int); + READSHM(dev->stats.tx_packets, arlan->numDatagramsTransmitted, u_int); + READSHM(dev->stats.tx_window_errors, arlan->numHoldOffs, u_int); ARLAN_DEBUG_EXIT("arlan_statistics"); - return &priv->stats; + return &dev->stats; } diff --git a/drivers/net/wireless/arlan.h b/drivers/net/wireless/arlan.h index 3ed1df75900f..fb3ad51a1caf 100644 --- a/drivers/net/wireless/arlan.h +++ b/drivers/net/wireless/arlan.h @@ -330,7 +330,6 @@ struct TxParam #define TX_RING_SIZE 2 /* Information that need to be kept for each board. */ struct arlan_private { - struct net_device_stats stats; struct arlan_shmem __iomem * card; struct arlan_shmem * conf; diff --git a/drivers/net/wireless/ath5k/Kconfig b/drivers/net/wireless/ath5k/Kconfig index f1f2aea2eab4..75383a5df992 100644 --- a/drivers/net/wireless/ath5k/Kconfig +++ b/drivers/net/wireless/ath5k/Kconfig @@ -1,6 +1,9 @@ config ATH5K tristate "Atheros 5xxx wireless cards support" depends on PCI && MAC80211 && WLAN_80211 && EXPERIMENTAL + select MAC80211_LEDS + select LEDS_CLASS + select NEW_LEDS ---help--- This module adds support for wireless adapters based on Atheros 5xxx chipset. diff --git a/drivers/net/wireless/ath5k/base.c b/drivers/net/wireless/ath5k/base.c index 635b9ac9aaa1..217d506527a9 100644 --- a/drivers/net/wireless/ath5k/base.c +++ b/drivers/net/wireless/ath5k/base.c @@ -58,11 +58,6 @@ #include "reg.h" #include "debug.h" -enum { - ATH_LED_TX, - ATH_LED_RX, -}; - static int ath5k_calinterval = 10; /* Calibrate PHY every 10 secs (TODO: Fixme) */ @@ -167,8 +162,7 @@ static struct pci_driver ath5k_pci_driver = { /* * Prototypes - MAC 802.11 stack related functions */ -static int ath5k_tx(struct ieee80211_hw *hw, struct sk_buff *skb, - struct ieee80211_tx_control *ctl); +static int ath5k_tx(struct ieee80211_hw *hw, struct sk_buff *skb); static int ath5k_reset(struct ieee80211_hw *hw); static int ath5k_start(struct ieee80211_hw *hw); static void ath5k_stop(struct ieee80211_hw *hw); @@ -196,8 +190,7 @@ static int ath5k_get_tx_stats(struct ieee80211_hw *hw, static u64 ath5k_get_tsf(struct ieee80211_hw *hw); static void ath5k_reset_tsf(struct ieee80211_hw *hw); static int ath5k_beacon_update(struct ieee80211_hw *hw, - struct sk_buff *skb, - struct ieee80211_tx_control *ctl); + struct sk_buff *skb); static struct ieee80211_ops ath5k_hw_ops = { .tx = ath5k_tx, @@ -214,7 +207,6 @@ static struct ieee80211_ops ath5k_hw_ops = { .get_tx_stats = ath5k_get_tx_stats, .get_tsf = ath5k_get_tsf, .reset_tsf = ath5k_reset_tsf, - .beacon_update = ath5k_beacon_update, }; /* @@ -251,9 +243,7 @@ static void ath5k_desc_free(struct ath5k_softc *sc, 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, - struct ieee80211_tx_control *ctl); - + struct ath5k_buf *bf); static inline void ath5k_txbuf_free(struct ath5k_softc *sc, struct ath5k_buf *bf) { @@ -289,8 +279,7 @@ static void ath5k_tx_processq(struct ath5k_softc *sc, static void ath5k_tasklet_tx(unsigned long data); /* Beacon handling */ static int ath5k_beacon_setup(struct ath5k_softc *sc, - struct ath5k_buf *bf, - struct ieee80211_tx_control *ctl); + 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); @@ -314,13 +303,10 @@ static void ath5k_tasklet_reset(unsigned long data); static void ath5k_calibrate(unsigned long data); /* LED functions */ -static void ath5k_led_off(unsigned long data); -static void ath5k_led_blink(struct ath5k_softc *sc, - unsigned int on, - unsigned int off); -static void ath5k_led_event(struct ath5k_softc *sc, - int event); - +static int ath5k_init_leds(struct ath5k_softc *sc); +static void ath5k_led_enable(struct ath5k_softc *sc); +static void ath5k_led_off(struct ath5k_softc *sc); +static void ath5k_unregister_leds(struct ath5k_softc *sc); /* * Module init/exit functions @@ -458,13 +444,11 @@ ath5k_pci_probe(struct pci_dev *pdev, /* Initialize driver private data */ SET_IEEE80211_DEV(hw, &pdev->dev); - hw->flags = IEEE80211_HW_RX_INCLUDES_FCS; + hw->flags = IEEE80211_HW_RX_INCLUDES_FCS | + IEEE80211_HW_SIGNAL_DBM | + IEEE80211_HW_NOISE_DBM; hw->extra_tx_headroom = 2; hw->channel_change_time = 5000; - /* these names are misleading */ - hw->max_rssi = -110; /* signal in dBm */ - hw->max_noise = -110; /* noise in dBm */ - hw->max_signal = 100; /* we will provide a percentage based on rssi */ sc = hw->priv; sc->hw = hw; sc->pdev = pdev; @@ -603,8 +587,7 @@ 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; - if (test_bit(ATH_STAT_LEDSOFT, sc->status)) - ath5k_hw_set_gpio(sc->ah, sc->led_pin, 1); + ath5k_led_off(sc); ath5k_stop_hw(sc); pci_save_state(pdev); @@ -639,10 +622,7 @@ ath5k_pci_resume(struct pci_dev *pdev) pci_write_config_byte(pdev, 0x41, 0); ath5k_init(sc); - if (test_bit(ATH_STAT_LEDSOFT, sc->status)) { - ath5k_hw_set_gpio_output(ah, sc->led_pin); - ath5k_hw_set_gpio(ah, sc->led_pin, 0); - } + ath5k_led_enable(sc); /* * Reset the key cache since some parts do not @@ -749,27 +729,6 @@ ath5k_attach(struct pci_dev *pdev, struct ieee80211_hw *hw) tasklet_init(&sc->txtq, ath5k_tasklet_tx, (unsigned long)sc); tasklet_init(&sc->restq, ath5k_tasklet_reset, (unsigned long)sc); setup_timer(&sc->calib_tim, ath5k_calibrate, (unsigned long)sc); - setup_timer(&sc->led_tim, ath5k_led_off, (unsigned long)sc); - - sc->led_on = 0; /* low true */ - /* - * Auto-enable soft led processing for IBM cards and for - * 5211 minipci cards. - */ - if (pdev->device == PCI_DEVICE_ID_ATHEROS_AR5212_IBM || - pdev->device == PCI_DEVICE_ID_ATHEROS_AR5211) { - __set_bit(ATH_STAT_LEDSOFT, sc->status); - sc->led_pin = 0; - } - /* Enable softled on PIN1 on HP Compaq nc6xx, nc4000 & nx5000 laptops */ - if (pdev->subsystem_vendor == PCI_VENDOR_ID_COMPAQ) { - __set_bit(ATH_STAT_LEDSOFT, sc->status); - sc->led_pin = 0; - } - if (test_bit(ATH_STAT_LEDSOFT, sc->status)) { - ath5k_hw_set_gpio_output(ah, sc->led_pin); - ath5k_hw_set_gpio(ah, sc->led_pin, !sc->led_on); - } ath5k_hw_get_lladdr(ah, mac); SET_IEEE80211_PERM_ADDR(hw, mac); @@ -783,6 +742,8 @@ ath5k_attach(struct pci_dev *pdev, struct ieee80211_hw *hw) goto err_queues; } + ath5k_init_leds(sc); + return 0; err_queues: ath5k_txq_release(sc); @@ -816,6 +777,7 @@ ath5k_detach(struct pci_dev *pdev, struct ieee80211_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 @@ -1067,65 +1029,9 @@ ath5k_chan_set(struct ath5k_softc *sc, struct ieee80211_channel *chan) return 0; } -/* - * TODO: CLEAN THIS !!! - */ static void ath5k_setcurmode(struct ath5k_softc *sc, unsigned int mode) { - if (unlikely(test_bit(ATH_STAT_LEDSOFT, sc->status))) { - /* from Atheros NDIS driver, w/ permission */ - static const struct { - u16 rate; /* tx/rx 802.11 rate */ - u16 timeOn; /* LED on time (ms) */ - u16 timeOff; /* LED off time (ms) */ - } blinkrates[] = { - { 108, 40, 10 }, - { 96, 44, 11 }, - { 72, 50, 13 }, - { 48, 57, 14 }, - { 36, 67, 16 }, - { 24, 80, 20 }, - { 22, 100, 25 }, - { 18, 133, 34 }, - { 12, 160, 40 }, - { 10, 200, 50 }, - { 6, 240, 58 }, - { 4, 267, 66 }, - { 2, 400, 100 }, - { 0, 500, 130 } - }; - const struct ath5k_rate_table *rt = - ath5k_hw_get_rate_table(sc->ah, mode); - unsigned int i, j; - - BUG_ON(rt == NULL); - - memset(sc->hwmap, 0, sizeof(sc->hwmap)); - for (i = 0; i < 32; i++) { - u8 ix = rt->rate_code_to_index[i]; - if (ix == 0xff) { - sc->hwmap[i].ledon = msecs_to_jiffies(500); - sc->hwmap[i].ledoff = msecs_to_jiffies(130); - continue; - } - sc->hwmap[i].txflags = IEEE80211_RADIOTAP_F_DATAPAD; - /* receive frames include FCS */ - sc->hwmap[i].rxflags = sc->hwmap[i].txflags | - IEEE80211_RADIOTAP_F_FCS; - /* setup blink rate table to avoid per-packet lookup */ - for (j = 0; j < ARRAY_SIZE(blinkrates) - 1; j++) - if (blinkrates[j].rate == /* XXX why 7f? */ - (rt->rates[ix].dot11_rate&0x7f)) - break; - - sc->hwmap[i].ledon = msecs_to_jiffies(blinkrates[j]. - timeOn); - sc->hwmap[i].ledoff = msecs_to_jiffies(blinkrates[j]. - timeOff); - } - } - sc->curmode = mode; if (mode == AR5K_MODE_11A) { @@ -1297,36 +1203,36 @@ ath5k_rxbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf) } static int -ath5k_txbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf, - struct ieee80211_tx_control *ctl) +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; int ret; flags = AR5K_TXDESC_INTREQ | AR5K_TXDESC_CLRDMASK; - bf->ctl = *ctl; + /* XXX endianness */ bf->skbaddr = pci_map_single(sc->pdev, skb->data, skb->len, PCI_DMA_TODEVICE); - if (ctl->flags & IEEE80211_TXCTL_NO_ACK) + if (info->flags & IEEE80211_TX_CTL_NO_ACK) flags |= AR5K_TXDESC_NOACK; pktlen = skb->len; - if (!(ctl->flags & IEEE80211_TXCTL_DO_NOT_ENCRYPT)) { - keyidx = ctl->key_idx; - pktlen += ctl->icv_len; + if (!(info->flags & IEEE80211_TX_CTL_DO_NOT_ENCRYPT)) { + keyidx = info->control.hw_key->hw_key_idx; + pktlen += info->control.icv_len; } - ret = ah->ah_setup_tx_desc(ah, ds, pktlen, ieee80211_get_hdrlen_from_skb(skb), AR5K_PKT_TYPE_NORMAL, - (sc->power_level * 2), ctl->tx_rate->hw_value, - ctl->retry_limit, keyidx, 0, flags, 0, 0); + (sc->power_level * 2), + ieee80211_get_tx_rate(sc->hw, info)->hw_value, + info->control.retry_limit, keyidx, 0, flags, 0, 0); if (ret) goto err_unmap; @@ -1335,7 +1241,7 @@ ath5k_txbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf, spin_lock_bh(&txq->lock); list_add_tail(&bf->list, &txq->q); - sc->tx_stats.data[txq->qnum].len++; + sc->tx_stats[txq->qnum].len++; if (txq->link == NULL) /* is this first packet? */ ath5k_hw_put_tx_buf(ah, txq->qnum, bf->daddr); else /* no, so only link it */ @@ -1566,7 +1472,7 @@ ath5k_txq_drainq(struct ath5k_softc *sc, struct ath5k_txq *txq) ath5k_txbuf_free(sc, bf); spin_lock_bh(&sc->txbuflock); - sc->tx_stats.data[txq->qnum].len--; + sc->tx_stats[txq->qnum].len--; list_move_tail(&bf->list, &sc->txbuf); sc->txbuf_len++; spin_unlock_bh(&sc->txbuflock); @@ -1601,7 +1507,7 @@ ath5k_txq_cleanup(struct ath5k_softc *sc) sc->txqs[i].link); } } - ieee80211_start_queues(sc->hw); /* XXX move to callers */ + ieee80211_wake_queues(sc->hw); /* XXX move to callers */ for (i = 0; i < ARRAY_SIZE(sc->txqs); i++) if (sc->txqs[i].setup) @@ -1698,9 +1604,9 @@ ath5k_rx_decrypted(struct ath5k_softc *sc, struct ath5k_desc *ds, /* Apparently when a default key is used to decrypt the packet the hw does not set the index used to decrypt. In such cases get the index from the packet. */ - if ((le16_to_cpu(hdr->frame_control) & IEEE80211_FCTL_PROTECTED) && - !(rs->rs_status & AR5K_RXERR_DECRYPT) && - skb->len >= hlen + 4) { + 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)) @@ -1719,10 +1625,7 @@ ath5k_check_ibss_tsf(struct ath5k_softc *sc, struct sk_buff *skb, u32 hw_tu; struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)skb->data; - if ((le16_to_cpu(mgmt->frame_control) & IEEE80211_FCTL_FTYPE) == - IEEE80211_FTYPE_MGMT && - (le16_to_cpu(mgmt->frame_control) & IEEE80211_FCTL_STYPE) == - IEEE80211_STYPE_BEACON && + 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) { /* @@ -1895,20 +1798,9 @@ accept: rxs.freq = sc->curchan->center_freq; rxs.band = sc->curband->band; - /* - * signal quality: - * the names here are misleading and the usage of these - * values by iwconfig makes it even worse - */ - /* noise floor in dBm, from the last noise calibration */ rxs.noise = sc->ah->ah_noise_floor; - /* signal level in dBm */ - rxs.ssi = rxs.noise + rs.rs_rssi; - /* - * "signal" is actually displayed as Link Quality by iwconfig - * we provide a percentage based on rssi (assuming max rssi 64) - */ - rxs.signal = rs.rs_rssi * 100 / 64; + rxs.signal = rxs.noise + rs.rs_rssi; + rxs.qual = rs.rs_rssi * 100 / 64; rxs.antenna = rs.rs_antenna; rxs.rate_idx = ath5k_hw_to_driver_rix(sc, rs.rs_rate); @@ -1921,8 +1813,6 @@ accept: ath5k_check_ibss_tsf(sc, skb, &rxs); __ieee80211_rx(sc->hw, skb, &rxs); - sc->led_rxrate = rs.rs_rate; - ath5k_led_event(sc, ATH_LED_RX); next: list_move_tail(&bf->list, &sc->rxbuf); } while (ath5k_rxbuf_setup(sc, bf) == 0); @@ -1939,11 +1829,11 @@ next: static void ath5k_tx_processq(struct ath5k_softc *sc, struct ath5k_txq *txq) { - struct ieee80211_tx_status txs = {}; struct ath5k_tx_status ts = {}; struct ath5k_buf *bf, *bf0; struct ath5k_desc *ds; struct sk_buff *skb; + struct ieee80211_tx_info *info; int ret; spin_lock(&txq->lock); @@ -1963,28 +1853,29 @@ ath5k_tx_processq(struct ath5k_softc *sc, struct ath5k_txq *txq) } skb = bf->skb; + info = IEEE80211_SKB_CB(skb); bf->skb = NULL; + pci_unmap_single(sc->pdev, bf->skbaddr, skb->len, PCI_DMA_TODEVICE); - txs.control = bf->ctl; - txs.retry_count = ts.ts_shortretry + ts.ts_longretry / 6; + info->status.retry_count = ts.ts_shortretry + ts.ts_longretry / 6; if (unlikely(ts.ts_status)) { sc->ll_stats.dot11ACKFailureCount++; if (ts.ts_status & AR5K_TXERR_XRETRY) - txs.excessive_retries = 1; + info->status.excessive_retries = 1; else if (ts.ts_status & AR5K_TXERR_FILT) - txs.flags |= IEEE80211_TX_STATUS_TX_FILTERED; + info->flags |= IEEE80211_TX_STAT_TX_FILTERED; } else { - txs.flags |= IEEE80211_TX_STATUS_ACK; - txs.ack_signal = ts.ts_rssi; + info->flags |= IEEE80211_TX_STAT_ACK; + info->status.ack_signal = ts.ts_rssi; } - ieee80211_tx_status(sc->hw, skb, &txs); - sc->tx_stats.data[txq->qnum].count++; + ieee80211_tx_status(sc->hw, skb); + sc->tx_stats[txq->qnum].count++; spin_lock(&sc->txbuflock); - sc->tx_stats.data[txq->qnum].len--; + sc->tx_stats[txq->qnum].len--; list_move_tail(&bf->list, &sc->txbuf); sc->txbuf_len++; spin_unlock(&sc->txbuflock); @@ -2002,13 +1893,9 @@ ath5k_tasklet_tx(unsigned long data) struct ath5k_softc *sc = (void *)data; ath5k_tx_processq(sc, sc->txq); - - ath5k_led_event(sc, ATH_LED_TX); } - - /*****************\ * Beacon handling * \*****************/ @@ -2017,10 +1904,10 @@ ath5k_tasklet_tx(unsigned long data) * Setup the beacon frame for transmit. */ static int -ath5k_beacon_setup(struct ath5k_softc *sc, struct ath5k_buf *bf, - struct ieee80211_tx_control *ctl) +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; @@ -2059,7 +1946,8 @@ ath5k_beacon_setup(struct ath5k_softc *sc, struct ath5k_buf *bf, ret = ah->ah_setup_tx_desc(ah, ds, skb->len, ieee80211_get_hdrlen_from_skb(skb), AR5K_PKT_TYPE_BEACON, (sc->power_level * 2), - ctl->tx_rate->hw_value, 1, AR5K_TXKEYIX_INVALID, + ieee80211_get_tx_rate(sc->hw, info)->hw_value, + 1, AR5K_TXKEYIX_INVALID, antenna, flags, 0, 0); if (ret) goto err_unmap; @@ -2382,11 +2270,7 @@ ath5k_stop_locked(struct ath5k_softc *sc) ieee80211_stop_queues(sc->hw); if (!test_bit(ATH_STAT_INVALID, sc->status)) { - if (test_bit(ATH_STAT_LEDSOFT, sc->status)) { - del_timer_sync(&sc->led_tim); - ath5k_hw_set_gpio(ah, sc->led_pin, !sc->led_on); - __clear_bit(ATH_STAT_LEDBLINKING, sc->status); - } + ath5k_led_off(sc); ath5k_hw_set_intr(ah, 0); } ath5k_txq_cleanup(sc); @@ -2582,54 +2466,123 @@ ath5k_calibrate(unsigned long data) \***************/ static void -ath5k_led_off(unsigned long data) +ath5k_led_enable(struct ath5k_softc *sc) { - struct ath5k_softc *sc = (void *)data; - - if (test_bit(ATH_STAT_LEDENDBLINK, sc->status)) - __clear_bit(ATH_STAT_LEDBLINKING, sc->status); - else { - __set_bit(ATH_STAT_LEDENDBLINK, sc->status); - ath5k_hw_set_gpio(sc->ah, sc->led_pin, !sc->led_on); - mod_timer(&sc->led_tim, jiffies + sc->led_off); + if (test_bit(ATH_STAT_LEDSOFT, sc->status)) { + ath5k_hw_set_gpio_output(sc->ah, sc->led_pin); + ath5k_led_off(sc); } } -/* - * Blink the LED according to the specified on/off times. - */ static void -ath5k_led_blink(struct ath5k_softc *sc, unsigned int on, - unsigned int off) +ath5k_led_on(struct ath5k_softc *sc) { - ATH5K_DBG(sc, ATH5K_DEBUG_LED, "on %u off %u\n", on, off); + if (!test_bit(ATH_STAT_LEDSOFT, sc->status)) + return; ath5k_hw_set_gpio(sc->ah, sc->led_pin, sc->led_on); - __set_bit(ATH_STAT_LEDBLINKING, sc->status); - __clear_bit(ATH_STAT_LEDENDBLINK, sc->status); - sc->led_off = off; - mod_timer(&sc->led_tim, jiffies + on); } static void -ath5k_led_event(struct ath5k_softc *sc, int event) +ath5k_led_off(struct ath5k_softc *sc) { - if (likely(!test_bit(ATH_STAT_LEDSOFT, sc->status))) + if (!test_bit(ATH_STAT_LEDSOFT, sc->status)) return; - if (unlikely(test_bit(ATH_STAT_LEDBLINKING, sc->status))) - return; /* don't interrupt active blink */ - switch (event) { - case ATH_LED_TX: - ath5k_led_blink(sc, sc->hwmap[sc->led_txrate].ledon, - sc->hwmap[sc->led_txrate].ledoff); - break; - case ATH_LED_RX: - ath5k_led_blink(sc, sc->hwmap[sc->led_rxrate].ledon, - sc->hwmap[sc->led_rxrate].ledoff); - break; + 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; +} + +static void +ath5k_unregister_leds(struct ath5k_softc *sc) +{ + ath5k_unregister_led(&sc->rx_led); + ath5k_unregister_led(&sc->tx_led); +} + + +static 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]; + + sc->led_on = 0; /* active low */ + /* + * Auto-enable soft led processing for IBM cards and for + * 5211 minipci cards. + */ + if (pdev->device == PCI_DEVICE_ID_ATHEROS_AR5212_IBM || + pdev->device == PCI_DEVICE_ID_ATHEROS_AR5211) { + __set_bit(ATH_STAT_LEDSOFT, sc->status); + sc->led_pin = 0; + } + /* Enable softled on PIN1 on HP Compaq nc6xx, nc4000 & nx5000 laptops */ + if (pdev->subsystem_vendor == PCI_VENDOR_ID_COMPAQ) { + __set_bit(ATH_STAT_LEDSOFT, sc->status); + sc->led_pin = 1; + } + 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; +} /********************\ @@ -2637,8 +2590,7 @@ ath5k_led_event(struct ath5k_softc *sc, int event) \********************/ static int -ath5k_tx(struct ieee80211_hw *hw, struct sk_buff *skb, - struct ieee80211_tx_control *ctl) +ath5k_tx(struct ieee80211_hw *hw, struct sk_buff *skb) { struct ath5k_softc *sc = hw->priv; struct ath5k_buf *bf; @@ -2667,13 +2619,11 @@ ath5k_tx(struct ieee80211_hw *hw, struct sk_buff *skb, memmove(skb->data, skb->data+pad, hdrlen); } - sc->led_txrate = ctl->tx_rate->hw_value; - 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, ctl->queue); + ieee80211_stop_queue(hw, skb_get_queue_mapping(skb)); return -1; } bf = list_first_entry(&sc->txbuf, struct ath5k_buf, list); @@ -2685,7 +2635,7 @@ ath5k_tx(struct ieee80211_hw *hw, struct sk_buff *skb, bf->skb = skb; - if (ath5k_txbuf_setup(sc, bf, ctl)) { + if (ath5k_txbuf_setup(sc, bf)) { bf->skb = NULL; spin_lock_irqsave(&sc->txbuflock, flags); list_add_tail(&bf->list, &sc->txbuf); @@ -2834,6 +2784,18 @@ ath5k_config_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif, * a clean way of letting us retrieve this yet. */ ath5k_hw_set_associd(ah, ah->ah_bssid, 0); } + + if (conf->changed & IEEE80211_IFCC_BEACON && + vif->type == IEEE80211_IF_TYPE_IBSS) { + struct sk_buff *beacon = ieee80211_beacon_get(hw, vif); + if (!beacon) { + ret = -ENOMEM; + goto unlock; + } + /* call old handler for now */ + ath5k_beacon_update(hw, beacon); + } + mutex_unlock(&sc->lock); return ath5k_reset(hw); @@ -3063,8 +3025,7 @@ ath5k_reset_tsf(struct ieee80211_hw *hw) } static int -ath5k_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb, - struct ieee80211_tx_control *ctl) +ath5k_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb) { struct ath5k_softc *sc = hw->priv; int ret; @@ -3080,7 +3041,7 @@ ath5k_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb, ath5k_txbuf_free(sc, sc->bbuf); sc->bbuf->skb = skb; - ret = ath5k_beacon_setup(sc, sc->bbuf, ctl); + ret = ath5k_beacon_setup(sc, sc->bbuf); if (ret) sc->bbuf->skb = NULL; else diff --git a/drivers/net/wireless/ath5k/base.h b/drivers/net/wireless/ath5k/base.h index 3a9755893018..47f414b09e67 100644 --- a/drivers/net/wireless/ath5k/base.h +++ b/drivers/net/wireless/ath5k/base.h @@ -45,6 +45,7 @@ #include <linux/list.h> #include <linux/wireless.h> #include <linux/if_ether.h> +#include <linux/leds.h> #include "ath5k.h" #include "debug.h" @@ -60,7 +61,6 @@ struct ath5k_buf { dma_addr_t daddr; /* physical addr of desc */ struct sk_buff *skb; /* skbuff for buf */ dma_addr_t skbaddr;/* physical addr of skb data */ - struct ieee80211_tx_control ctl; }; /* @@ -80,6 +80,19 @@ struct ath5k_txq { 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 @@ -92,7 +105,8 @@ struct ath5k_softc { struct pci_dev *pdev; /* for dma mapping */ void __iomem *iobase; /* address of the device */ struct mutex lock; /* dev-level lock */ - struct ieee80211_tx_queue_stats tx_stats; + /* 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]; @@ -118,13 +132,11 @@ struct ath5k_softc { size_t desc_len; /* size of TX/RX descriptors */ u16 cachelsz; /* cache line size */ - DECLARE_BITMAP(status, 6); + DECLARE_BITMAP(status, 4); #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_LEDBLINKING 3 /* LED blink operation active */ -#define ATH_STAT_LEDENDBLINK 4 /* finish LED blink operation */ -#define ATH_STAT_LEDSOFT 5 /* enable LED gpio status */ +#define ATH_STAT_LEDSOFT 3 /* enable LED gpio status */ unsigned int filter_flags; /* HW flags, AR5K_RX_FILTER_* */ unsigned int curmode; /* current phy mode */ @@ -132,13 +144,6 @@ struct ath5k_softc { struct ieee80211_vif *vif; - struct { - u8 rxflags; /* radiotap rx flags */ - u8 txflags; /* radiotap tx flags */ - u16 ledon; /* softled on time */ - u16 ledoff; /* softled off time */ - } hwmap[32]; /* h/w rate ix mappings */ - enum ath5k_int imask; /* interrupt mask copy */ DECLARE_BITMAP(keymap, AR5K_KEYCACHE_SIZE); /* key use bit map */ @@ -148,9 +153,6 @@ struct ath5k_softc { unsigned int led_pin, /* GPIO pin for driving LED */ led_on, /* pin setting for LED on */ led_off; /* off time for current blink */ - struct timer_list led_tim; /* led off timer */ - u8 led_rxrate; /* current rx rate for LED */ - u8 led_txrate; /* current tx rate for LED */ struct tasklet_struct restq; /* reset tasklet */ @@ -159,6 +161,7 @@ struct ath5k_softc { 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; @@ -167,6 +170,7 @@ struct ath5k_softc { struct ath5k_txq *txq; /* beacon and tx*/ struct tasklet_struct txtq; /* tx intr tasklet */ + struct ath5k_led tx_led; /* tx led */ struct ath5k_buf *bbuf; /* beacon buffer */ unsigned int bhalq, /* SW q for outgoing beacons */ diff --git a/drivers/net/wireless/ath5k/hw.c b/drivers/net/wireless/ath5k/hw.c index 77990b56860b..c6d12c53bda4 100644 --- a/drivers/net/wireless/ath5k/hw.c +++ b/drivers/net/wireless/ath5k/hw.c @@ -31,14 +31,14 @@ #include "base.h" #include "debug.h" -/*Rate tables*/ +/* Rate tables */ static const struct ath5k_rate_table ath5k_rt_11a = AR5K_RATES_11A; static const struct ath5k_rate_table ath5k_rt_11b = AR5K_RATES_11B; static const struct ath5k_rate_table ath5k_rt_11g = AR5K_RATES_11G; static const struct ath5k_rate_table ath5k_rt_turbo = AR5K_RATES_TURBO; static const struct ath5k_rate_table ath5k_rt_xr = AR5K_RATES_XR; -/*Prototypes*/ +/* Prototypes */ static int ath5k_hw_nic_reset(struct ath5k_hw *, u32); static int ath5k_hw_nic_wakeup(struct ath5k_hw *, int, bool); static int ath5k_hw_setup_4word_tx_desc(struct ath5k_hw *, struct ath5k_desc *, diff --git a/drivers/net/wireless/atmel.c b/drivers/net/wireless/atmel.c index d1acef7e0b14..bd35bb0a1480 100644 --- a/drivers/net/wireless/atmel.c +++ b/drivers/net/wireless/atmel.c @@ -433,7 +433,6 @@ struct atmel_private { struct net_device *dev; struct device *sys_dev; struct iw_statistics wstats; - struct net_device_stats stats; // device stats spinlock_t irqlock, timerlock; // spinlocks enum { BUS_TYPE_PCCARD, BUS_TYPE_PCI } bus_type; enum { @@ -694,9 +693,9 @@ static void tx_done_irq(struct atmel_private *priv) if (type == TX_PACKET_TYPE_DATA) { if (status == TX_STATUS_SUCCESS) - priv->stats.tx_packets++; + priv->dev->stats.tx_packets++; else - priv->stats.tx_errors++; + priv->dev->stats.tx_errors++; netif_wake_queue(priv->dev); } } @@ -792,13 +791,13 @@ static int start_tx(struct sk_buff *skb, struct net_device *dev) if (priv->card && priv->present_callback && !(*priv->present_callback)(priv->card)) { - priv->stats.tx_errors++; + dev->stats.tx_errors++; dev_kfree_skb(skb); return 0; } if (priv->station_state != STATION_STATE_READY) { - priv->stats.tx_errors++; + dev->stats.tx_errors++; dev_kfree_skb(skb); return 0; } @@ -815,7 +814,7 @@ static int start_tx(struct sk_buff *skb, struct net_device *dev) initial + 18 (+30-12) */ if (!(buff = find_tx_buff(priv, len + 18))) { - priv->stats.tx_dropped++; + dev->stats.tx_dropped++; spin_unlock_irqrestore(&priv->irqlock, flags); spin_unlock_bh(&priv->timerlock); netif_stop_queue(dev); @@ -851,7 +850,7 @@ static int start_tx(struct sk_buff *skb, struct net_device *dev) /* low bit of first byte of destination tells us if broadcast */ tx_update_descriptor(priv, *(skb->data) & 0x01, len + 18, buff, TX_PACKET_TYPE_DATA); dev->trans_start = jiffies; - priv->stats.tx_bytes += len; + dev->stats.tx_bytes += len; spin_unlock_irqrestore(&priv->irqlock, flags); spin_unlock_bh(&priv->timerlock); @@ -895,7 +894,7 @@ static void fast_rx_path(struct atmel_private *priv, } if (!(skb = dev_alloc_skb(msdu_size + 14))) { - priv->stats.rx_dropped++; + priv->dev->stats.rx_dropped++; return; } @@ -908,7 +907,7 @@ static void fast_rx_path(struct atmel_private *priv, crc = crc32_le(crc, skbp + 12, msdu_size); atmel_copy_to_host(priv->dev, (void *)&netcrc, rx_packet_loc + 30 + msdu_size, 4); if ((crc ^ 0xffffffff) != netcrc) { - priv->stats.rx_crc_errors++; + priv->dev->stats.rx_crc_errors++; dev_kfree_skb(skb); return; } @@ -924,8 +923,8 @@ static void fast_rx_path(struct atmel_private *priv, skb->protocol = eth_type_trans(skb, priv->dev); skb->ip_summed = CHECKSUM_NONE; netif_rx(skb); - priv->stats.rx_bytes += 12 + msdu_size; - priv->stats.rx_packets++; + priv->dev->stats.rx_bytes += 12 + msdu_size; + priv->dev->stats.rx_packets++; } /* Test to see if the packet in card memory at packet_loc has a valid CRC @@ -991,7 +990,7 @@ static void frag_rx_path(struct atmel_private *priv, crc = crc32_le(crc, &priv->rx_buf[12], msdu_size); atmel_copy_to_host(priv->dev, (void *)&netcrc, rx_packet_loc + msdu_size, 4); if ((crc ^ 0xffffffff) != netcrc) { - priv->stats.rx_crc_errors++; + priv->dev->stats.rx_crc_errors++; memset(priv->frag_source, 0xff, 6); } } @@ -1009,7 +1008,7 @@ static void frag_rx_path(struct atmel_private *priv, msdu_size); atmel_copy_to_host(priv->dev, (void *)&netcrc, rx_packet_loc + msdu_size, 4); if ((crc ^ 0xffffffff) != netcrc) { - priv->stats.rx_crc_errors++; + priv->dev->stats.rx_crc_errors++; memset(priv->frag_source, 0xff, 6); more_frags = 1; /* don't send broken assembly */ } @@ -1021,7 +1020,7 @@ static void frag_rx_path(struct atmel_private *priv, if (!more_frags) { /* last one */ memset(priv->frag_source, 0xff, 6); if (!(skb = dev_alloc_skb(priv->frag_len + 14))) { - priv->stats.rx_dropped++; + priv->dev->stats.rx_dropped++; } else { skb_reserve(skb, 2); memcpy(skb_put(skb, priv->frag_len + 12), @@ -1031,8 +1030,8 @@ static void frag_rx_path(struct atmel_private *priv, skb->protocol = eth_type_trans(skb, priv->dev); skb->ip_summed = CHECKSUM_NONE; netif_rx(skb); - priv->stats.rx_bytes += priv->frag_len + 12; - priv->stats.rx_packets++; + priv->dev->stats.rx_bytes += priv->frag_len + 12; + priv->dev->stats.rx_packets++; } } } else @@ -1057,7 +1056,7 @@ static void rx_done_irq(struct atmel_private *priv) if (status == 0xc1) /* determined by experiment */ priv->wstats.discard.nwid++; else - priv->stats.rx_errors++; + priv->dev->stats.rx_errors++; goto next; } @@ -1065,7 +1064,7 @@ static void rx_done_irq(struct atmel_private *priv) rx_packet_loc = atmel_rmem16(priv, atmel_rx(priv, RX_DESC_MSDU_POS_OFFSET, priv->rx_desc_head)); if (msdu_size < 30) { - priv->stats.rx_errors++; + priv->dev->stats.rx_errors++; goto next; } @@ -1123,7 +1122,7 @@ static void rx_done_irq(struct atmel_private *priv) msdu_size -= 4; crc = crc32_le(crc, (unsigned char *)&priv->rx_buf, msdu_size); if ((crc ^ 0xffffffff) != (*((u32 *)&priv->rx_buf[msdu_size]))) { - priv->stats.rx_crc_errors++; + priv->dev->stats.rx_crc_errors++; goto next; } } @@ -1250,12 +1249,6 @@ static irqreturn_t service_interrupt(int irq, void *dev_id) } } -static struct net_device_stats *atmel_get_stats(struct net_device *dev) -{ - struct atmel_private *priv = netdev_priv(dev); - return &priv->stats; -} - static struct iw_statistics *atmel_get_wireless_stats(struct net_device *dev) { struct atmel_private *priv = netdev_priv(dev); @@ -1518,8 +1511,6 @@ struct net_device *init_atmel_card(unsigned short irq, unsigned long port, priv->crc_ok_cnt = priv->crc_ko_cnt = 0; } else priv->probe_crc = 0; - memset(&priv->stats, 0, sizeof(priv->stats)); - memset(&priv->wstats, 0, sizeof(priv->wstats)); priv->last_qual = jiffies; priv->last_beacon_timestamp = 0; memset(priv->frag_source, 0xff, sizeof(priv->frag_source)); @@ -1568,7 +1559,6 @@ struct net_device *init_atmel_card(unsigned short irq, unsigned long port, dev->change_mtu = atmel_change_mtu; dev->set_mac_address = atmel_set_mac_address; dev->hard_start_xmit = start_tx; - dev->get_stats = atmel_get_stats; dev->wireless_handlers = (struct iw_handler_def *)&atmel_handler_def; dev->do_ioctl = atmel_ioctl; dev->irq = irq; @@ -2320,30 +2310,40 @@ static int atmel_get_scan(struct net_device *dev, iwe.cmd = SIOCGIWAP; iwe.u.ap_addr.sa_family = ARPHRD_ETHER; memcpy(iwe.u.ap_addr.sa_data, priv->BSSinfo[i].BSSID, 6); - current_ev = iwe_stream_add_event(current_ev, extra + IW_SCAN_MAX_DATA, &iwe, IW_EV_ADDR_LEN); + current_ev = iwe_stream_add_event(info, current_ev, + extra + IW_SCAN_MAX_DATA, + &iwe, IW_EV_ADDR_LEN); iwe.u.data.length = priv->BSSinfo[i].SSIDsize; if (iwe.u.data.length > 32) iwe.u.data.length = 32; iwe.cmd = SIOCGIWESSID; iwe.u.data.flags = 1; - current_ev = iwe_stream_add_point(current_ev, extra + IW_SCAN_MAX_DATA, &iwe, priv->BSSinfo[i].SSID); + current_ev = iwe_stream_add_point(info, current_ev, + extra + IW_SCAN_MAX_DATA, + &iwe, priv->BSSinfo[i].SSID); iwe.cmd = SIOCGIWMODE; iwe.u.mode = priv->BSSinfo[i].BSStype; - current_ev = iwe_stream_add_event(current_ev, extra + IW_SCAN_MAX_DATA, &iwe, IW_EV_UINT_LEN); + current_ev = iwe_stream_add_event(info, current_ev, + extra + IW_SCAN_MAX_DATA, + &iwe, IW_EV_UINT_LEN); iwe.cmd = SIOCGIWFREQ; iwe.u.freq.m = priv->BSSinfo[i].channel; iwe.u.freq.e = 0; - current_ev = iwe_stream_add_event(current_ev, extra + IW_SCAN_MAX_DATA, &iwe, IW_EV_FREQ_LEN); + current_ev = iwe_stream_add_event(info, current_ev, + extra + IW_SCAN_MAX_DATA, + &iwe, IW_EV_FREQ_LEN); /* Add quality statistics */ iwe.cmd = IWEVQUAL; iwe.u.qual.level = priv->BSSinfo[i].RSSI; iwe.u.qual.qual = iwe.u.qual.level; /* iwe.u.qual.noise = SOMETHING */ - current_ev = iwe_stream_add_event(current_ev, extra + IW_SCAN_MAX_DATA , &iwe, IW_EV_QUAL_LEN); + current_ev = iwe_stream_add_event(info, current_ev, + extra + IW_SCAN_MAX_DATA, + &iwe, IW_EV_QUAL_LEN); iwe.cmd = SIOCGIWENCODE; @@ -2352,7 +2352,9 @@ static int atmel_get_scan(struct net_device *dev, else iwe.u.data.flags = IW_ENCODE_DISABLED; iwe.u.data.length = 0; - current_ev = iwe_stream_add_point(current_ev, extra + IW_SCAN_MAX_DATA, &iwe, NULL); + current_ev = iwe_stream_add_point(info, current_ev, + extra + IW_SCAN_MAX_DATA, + &iwe, NULL); } /* Length of data */ diff --git a/drivers/net/wireless/b43/b43.h b/drivers/net/wireless/b43/b43.h index d3db298c05fc..edcdfa366452 100644 --- a/drivers/net/wireless/b43/b43.h +++ b/drivers/net/wireless/b43/b43.h @@ -410,8 +410,7 @@ enum { #define B43_IRQ_TIMEOUT 0x80000000 #define B43_IRQ_ALL 0xFFFFFFFF -#define B43_IRQ_MASKTEMPLATE (B43_IRQ_MAC_SUSPENDED | \ - B43_IRQ_TBTT_INDI | \ +#define B43_IRQ_MASKTEMPLATE (B43_IRQ_TBTT_INDI | \ B43_IRQ_ATIM_END | \ B43_IRQ_PMQ | \ B43_IRQ_MAC_TXERR | \ @@ -423,6 +422,28 @@ enum { B43_IRQ_RFKILL | \ B43_IRQ_TX_OK) +/* The firmware register to fetch the debug-IRQ reason from. */ +#define B43_DEBUGIRQ_REASON_REG 63 +/* Debug-IRQ reasons. */ +#define B43_DEBUGIRQ_PANIC 0 /* The firmware panic'ed */ +#define B43_DEBUGIRQ_DUMP_SHM 1 /* Dump shared SHM */ +#define B43_DEBUGIRQ_DUMP_REGS 2 /* Dump the microcode registers */ +#define B43_DEBUGIRQ_MARKER 3 /* A "marker" was thrown by the firmware. */ +#define B43_DEBUGIRQ_ACK 0xFFFF /* The host writes that to ACK the IRQ */ + +/* The firmware register that contains the "marker" line. */ +#define B43_MARKER_ID_REG 2 +#define B43_MARKER_LINE_REG 3 + +/* The firmware register to fetch the panic reason from. */ +#define B43_FWPANIC_REASON_REG 3 +/* Firmware panic reason codes */ +#define B43_FWPANIC_DIE 0 /* Firmware died. Don't auto-restart it. */ +#define B43_FWPANIC_RESTART 1 /* Firmware died. Schedule a controller reset. */ + +/* The firmware register that contains the watchdog counter. */ +#define B43_WATCHDOG_REG 1 + /* Device specific rate values. * The actual values defined here are (rate_in_mbps * 2). * Some code depends on this. Don't change it. */ @@ -733,7 +754,6 @@ struct b43_wl { /* The beacon we are currently using (AP or IBSS mode). * This beacon stuff is protected by the irq_lock. */ struct sk_buff *current_beacon; - struct ieee80211_tx_control beacon_txctl; bool beacon0_uploaded; bool beacon1_uploaded; bool beacon_templates_virgin; /* Never wrote the templates? */ @@ -767,6 +787,13 @@ struct b43_firmware { u16 rev; /* Firmware patchlevel */ u16 patch; + + /* Set to true, if we are using an opensource firmware. */ + bool opensource; + /* Set to true, if the core needs a PCM firmware, but + * we failed to load one. This is always false for + * core rev > 10, as these don't need PCM firmware. */ + bool pcm_request_failed; }; /* Device (802.11 core) initialization status. */ @@ -940,22 +967,6 @@ static inline bool __b43_warn_on_dummy(bool x) { return x; } # define B43_WARN_ON(x) __b43_warn_on_dummy(unlikely(!!(x))) #endif -/** Limit a value between two limits */ -#ifdef limit_value -# undef limit_value -#endif -#define limit_value(value, min, max) \ - ({ \ - typeof(value) __value = (value); \ - typeof(value) __min = (min); \ - typeof(value) __max = (max); \ - if (__value < __min) \ - __value = __min; \ - else if (__value > __max) \ - __value = __max; \ - __value; \ - }) - /* Convert an integer to a Q5.2 value */ #define INT_TO_Q52(i) ((i) << 2) /* Convert a Q5.2 value to an integer (precision loss!) */ diff --git a/drivers/net/wireless/b43/debugfs.c b/drivers/net/wireless/b43/debugfs.c index 7fca2ebc747f..29851bc1101f 100644 --- a/drivers/net/wireless/b43/debugfs.c +++ b/drivers/net/wireless/b43/debugfs.c @@ -74,70 +74,327 @@ struct b43_dfs_file * fops_to_dfs_file(struct b43_wldev *dev, } while (0) -/* wl->irq_lock is locked */ -static ssize_t tsf_read_file(struct b43_wldev *dev, - char *buf, size_t bufsize) +/* The biggest address values for SHM access from the debugfs files. */ +#define B43_MAX_SHM_ROUTING 4 +#define B43_MAX_SHM_ADDR 0xFFFF + +static ssize_t shm16read__read_file(struct b43_wldev *dev, + char *buf, size_t bufsize) { ssize_t count = 0; - u64 tsf; + unsigned int routing, addr; + u16 val; - b43_tsf_read(dev, &tsf); - fappend("0x%08x%08x\n", - (unsigned int)((tsf & 0xFFFFFFFF00000000ULL) >> 32), - (unsigned int)(tsf & 0xFFFFFFFFULL)); + routing = dev->dfsentry->shm16read_routing_next; + addr = dev->dfsentry->shm16read_addr_next; + if ((routing > B43_MAX_SHM_ROUTING) || + (addr > B43_MAX_SHM_ADDR)) + return -EDESTADDRREQ; + + val = b43_shm_read16(dev, routing, addr); + fappend("0x%04X\n", val); return count; } -/* wl->irq_lock is locked */ -static int tsf_write_file(struct b43_wldev *dev, - const char *buf, size_t count) +static int shm16read__write_file(struct b43_wldev *dev, + const char *buf, size_t count) { - u64 tsf; + unsigned int routing, addr; + int res; - if (sscanf(buf, "%llu", (unsigned long long *)(&tsf)) != 1) + res = sscanf(buf, "0x%X 0x%X", &routing, &addr); + if (res != 2) return -EINVAL; - b43_tsf_write(dev, tsf); + if (routing > B43_MAX_SHM_ROUTING) + return -EADDRNOTAVAIL; + if (addr > B43_MAX_SHM_ADDR) + return -EADDRNOTAVAIL; + if (routing == B43_SHM_SHARED) { + if ((addr % 2) != 0) + return -EADDRNOTAVAIL; + } + + dev->dfsentry->shm16read_routing_next = routing; + dev->dfsentry->shm16read_addr_next = addr; return 0; } -/* wl->irq_lock is locked */ -static ssize_t ucode_regs_read_file(struct b43_wldev *dev, +static int shm16write__write_file(struct b43_wldev *dev, + const char *buf, size_t count) +{ + unsigned int routing, addr, mask, set; + u16 val; + int res; + unsigned long flags; + + res = sscanf(buf, "0x%X 0x%X 0x%X 0x%X", + &routing, &addr, &mask, &set); + if (res != 4) + return -EINVAL; + if (routing > B43_MAX_SHM_ROUTING) + return -EADDRNOTAVAIL; + if (addr > B43_MAX_SHM_ADDR) + return -EADDRNOTAVAIL; + if (routing == B43_SHM_SHARED) { + if ((addr % 2) != 0) + return -EADDRNOTAVAIL; + } + if ((mask > 0xFFFF) || (set > 0xFFFF)) + return -E2BIG; + + spin_lock_irqsave(&dev->wl->shm_lock, flags); + if (mask == 0) + val = 0; + else + val = __b43_shm_read16(dev, routing, addr); + val &= mask; + val |= set; + __b43_shm_write16(dev, routing, addr, val); + spin_unlock_irqrestore(&dev->wl->shm_lock, flags); + + return 0; +} + +static ssize_t shm32read__read_file(struct b43_wldev *dev, char *buf, size_t bufsize) { ssize_t count = 0; - int i; + unsigned int routing, addr; + u32 val; + + routing = dev->dfsentry->shm32read_routing_next; + addr = dev->dfsentry->shm32read_addr_next; + if ((routing > B43_MAX_SHM_ROUTING) || + (addr > B43_MAX_SHM_ADDR)) + return -EDESTADDRREQ; + + val = b43_shm_read32(dev, routing, addr); + fappend("0x%08X\n", val); - for (i = 0; i < 64; i++) { - fappend("r%d = 0x%04x\n", i, - b43_shm_read16(dev, B43_SHM_SCRATCH, i)); + return count; +} + +static int shm32read__write_file(struct b43_wldev *dev, + const char *buf, size_t count) +{ + unsigned int routing, addr; + int res; + + res = sscanf(buf, "0x%X 0x%X", &routing, &addr); + if (res != 2) + return -EINVAL; + if (routing > B43_MAX_SHM_ROUTING) + return -EADDRNOTAVAIL; + if (addr > B43_MAX_SHM_ADDR) + return -EADDRNOTAVAIL; + if (routing == B43_SHM_SHARED) { + if ((addr % 2) != 0) + return -EADDRNOTAVAIL; } + dev->dfsentry->shm32read_routing_next = routing; + dev->dfsentry->shm32read_addr_next = addr; + + return 0; +} + +static int shm32write__write_file(struct b43_wldev *dev, + const char *buf, size_t count) +{ + unsigned int routing, addr, mask, set; + u32 val; + int res; + unsigned long flags; + + res = sscanf(buf, "0x%X 0x%X 0x%X 0x%X", + &routing, &addr, &mask, &set); + if (res != 4) + return -EINVAL; + if (routing > B43_MAX_SHM_ROUTING) + return -EADDRNOTAVAIL; + if (addr > B43_MAX_SHM_ADDR) + return -EADDRNOTAVAIL; + if (routing == B43_SHM_SHARED) { + if ((addr % 2) != 0) + return -EADDRNOTAVAIL; + } + if ((mask > 0xFFFFFFFF) || (set > 0xFFFFFFFF)) + return -E2BIG; + + spin_lock_irqsave(&dev->wl->shm_lock, flags); + if (mask == 0) + val = 0; + else + val = __b43_shm_read32(dev, routing, addr); + val &= mask; + val |= set; + __b43_shm_write32(dev, routing, addr, val); + spin_unlock_irqrestore(&dev->wl->shm_lock, flags); + + return 0; +} + +/* The biggest MMIO address that we allow access to from the debugfs files. */ +#define B43_MAX_MMIO_ACCESS (0xF00 - 1) + +static ssize_t mmio16read__read_file(struct b43_wldev *dev, + char *buf, size_t bufsize) +{ + ssize_t count = 0; + unsigned int addr; + u16 val; + + addr = dev->dfsentry->mmio16read_next; + if (addr > B43_MAX_MMIO_ACCESS) + return -EDESTADDRREQ; + + val = b43_read16(dev, addr); + fappend("0x%04X\n", val); + + return count; +} + +static int mmio16read__write_file(struct b43_wldev *dev, + const char *buf, size_t count) +{ + unsigned int addr; + int res; + + res = sscanf(buf, "0x%X", &addr); + if (res != 1) + return -EINVAL; + if (addr > B43_MAX_MMIO_ACCESS) + return -EADDRNOTAVAIL; + if ((addr % 2) != 0) + return -EINVAL; + + dev->dfsentry->mmio16read_next = addr; + + return 0; +} + +static int mmio16write__write_file(struct b43_wldev *dev, + const char *buf, size_t count) +{ + unsigned int addr, mask, set; + int res; + u16 val; + + res = sscanf(buf, "0x%X 0x%X 0x%X", &addr, &mask, &set); + if (res != 3) + return -EINVAL; + if (addr > B43_MAX_MMIO_ACCESS) + return -EADDRNOTAVAIL; + if ((mask > 0xFFFF) || (set > 0xFFFF)) + return -E2BIG; + if ((addr % 2) != 0) + return -EINVAL; + + if (mask == 0) + val = 0; + else + val = b43_read16(dev, addr); + val &= mask; + val |= set; + b43_write16(dev, addr, val); + + return 0; +} + +static ssize_t mmio32read__read_file(struct b43_wldev *dev, + char *buf, size_t bufsize) +{ + ssize_t count = 0; + unsigned int addr; + u32 val; + + addr = dev->dfsentry->mmio32read_next; + if (addr > B43_MAX_MMIO_ACCESS) + return -EDESTADDRREQ; + + val = b43_read32(dev, addr); + fappend("0x%08X\n", val); + return count; } +static int mmio32read__write_file(struct b43_wldev *dev, + const char *buf, size_t count) +{ + unsigned int addr; + int res; + + res = sscanf(buf, "0x%X", &addr); + if (res != 1) + return -EINVAL; + if (addr > B43_MAX_MMIO_ACCESS) + return -EADDRNOTAVAIL; + if ((addr % 4) != 0) + return -EINVAL; + + dev->dfsentry->mmio32read_next = addr; + + return 0; +} + +static int mmio32write__write_file(struct b43_wldev *dev, + const char *buf, size_t count) +{ + unsigned int addr, mask, set; + int res; + u32 val; + + res = sscanf(buf, "0x%X 0x%X 0x%X", &addr, &mask, &set); + if (res != 3) + return -EINVAL; + if (addr > B43_MAX_MMIO_ACCESS) + return -EADDRNOTAVAIL; + if ((mask > 0xFFFFFFFF) || (set > 0xFFFFFFFF)) + return -E2BIG; + if ((addr % 4) != 0) + return -EINVAL; + + if (mask == 0) + val = 0; + else + val = b43_read32(dev, addr); + val &= mask; + val |= set; + b43_write32(dev, addr, val); + + return 0; +} + /* wl->irq_lock is locked */ -static ssize_t shm_read_file(struct b43_wldev *dev, +static ssize_t tsf_read_file(struct b43_wldev *dev, char *buf, size_t bufsize) { ssize_t count = 0; - int i; - u16 tmp; - __le16 *le16buf = (__le16 *)buf; + u64 tsf; - for (i = 0; i < 0x1000; i++) { - if (bufsize < sizeof(tmp)) - break; - tmp = b43_shm_read16(dev, B43_SHM_SHARED, 2 * i); - le16buf[i] = cpu_to_le16(tmp); - count += sizeof(tmp); - bufsize -= sizeof(tmp); - } + b43_tsf_read(dev, &tsf); + fappend("0x%08x%08x\n", + (unsigned int)((tsf & 0xFFFFFFFF00000000ULL) >> 32), + (unsigned int)(tsf & 0xFFFFFFFFULL)); return count; } +/* wl->irq_lock is locked */ +static int tsf_write_file(struct b43_wldev *dev, + const char *buf, size_t count) +{ + u64 tsf; + + if (sscanf(buf, "%llu", (unsigned long long *)(&tsf)) != 1) + return -EINVAL; + b43_tsf_write(dev, tsf); + + return 0; +} + static ssize_t txstat_read_file(struct b43_wldev *dev, char *buf, size_t bufsize) { @@ -270,24 +527,22 @@ static int restart_write_file(struct b43_wldev *dev, return err; } -static ssize_t append_lo_table(ssize_t count, char *buf, const size_t bufsize, - struct b43_loctl table[B43_NR_BB][B43_NR_RF]) +static unsigned long calc_expire_secs(unsigned long now, + unsigned long time, + unsigned long expire) { - unsigned int i, j; - struct b43_loctl *ctl; - - for (i = 0; i < B43_NR_BB; i++) { - for (j = 0; j < B43_NR_RF; j++) { - ctl = &(table[i][j]); - fappend("(bbatt %2u, rfatt %2u) -> " - "(I %+3d, Q %+3d, Used: %d, Calibrated: %d)\n", - i, j, ctl->i, ctl->q, - ctl->used, - b43_loctl_is_calibrated(ctl)); - } + expire = time + expire; + + if (time_after(now, expire)) + return 0; /* expired */ + if (expire < now) { + /* jiffies wrapped */ + expire -= MAX_JIFFY_OFFSET; + now -= MAX_JIFFY_OFFSET; } + B43_WARN_ON(expire < now); - return count; + return (expire - now) / HZ; } static ssize_t loctls_read_file(struct b43_wldev *dev, @@ -296,27 +551,45 @@ static ssize_t loctls_read_file(struct b43_wldev *dev, ssize_t count = 0; struct b43_txpower_lo_control *lo; int i, err = 0; + struct b43_lo_calib *cal; + unsigned long now = jiffies; + struct b43_phy *phy = &dev->phy; - if (dev->phy.type != B43_PHYTYPE_G) { + if (phy->type != B43_PHYTYPE_G) { fappend("Device is not a G-PHY\n"); err = -ENODEV; goto out; } - lo = dev->phy.lo_control; + lo = phy->lo_control; fappend("-- Local Oscillator calibration data --\n\n"); - fappend("Measured: %d, Rebuild: %d, HW-power-control: %d\n", - lo->lo_measured, - lo->rebuild, + fappend("HW-power-control enabled: %d\n", dev->phy.hardware_power_control); - fappend("TX Bias: 0x%02X, TX Magn: 0x%02X\n", - lo->tx_bias, lo->tx_magn); - fappend("Power Vector: 0x%08X%08X\n", + fappend("TX Bias: 0x%02X, TX Magn: 0x%02X (expire in %lu sec)\n", + lo->tx_bias, lo->tx_magn, + calc_expire_secs(now, lo->txctl_measured_time, + B43_LO_TXCTL_EXPIRE)); + fappend("Power Vector: 0x%08X%08X (expires in %lu sec)\n", (unsigned int)((lo->power_vector & 0xFFFFFFFF00000000ULL) >> 32), - (unsigned int)(lo->power_vector & 0x00000000FFFFFFFFULL)); - fappend("\nControl table WITH PADMIX:\n"); - count = append_lo_table(count, buf, bufsize, lo->with_padmix); - fappend("\nControl table WITHOUT PADMIX:\n"); - count = append_lo_table(count, buf, bufsize, lo->no_padmix); + (unsigned int)(lo->power_vector & 0x00000000FFFFFFFFULL), + calc_expire_secs(now, lo->pwr_vec_read_time, + B43_LO_PWRVEC_EXPIRE)); + + fappend("\nCalibrated settings:\n"); + list_for_each_entry(cal, &lo->calib_list, list) { + bool active; + + active = (b43_compare_bbatt(&cal->bbatt, &phy->bbatt) && + b43_compare_rfatt(&cal->rfatt, &phy->rfatt)); + fappend("BB(%d), RF(%d,%d) -> I=%d, Q=%d " + "(expires in %lu sec)%s\n", + cal->bbatt.att, + cal->rfatt.att, cal->rfatt.with_padmix, + cal->ctl.i, cal->ctl.q, + calc_expire_secs(now, cal->calib_time, + B43_LO_CALIB_EXPIRE), + active ? " ACTIVE" : ""); + } + fappend("\nUsed RF attenuation values: Value(WithPadmix flag)\n"); for (i = 0; i < lo->rfatt_list.len; i++) { fappend("%u(%d), ", @@ -351,7 +624,7 @@ static ssize_t b43_debugfs_read(struct file *file, char __user *userbuf, struct b43_dfs_file *dfile; ssize_t uninitialized_var(ret); char *buf; - const size_t bufsize = 1024 * 128; + const size_t bufsize = 1024 * 16; /* 16 kiB buffer */ const size_t buforder = get_order(bufsize); int err = 0; @@ -380,8 +653,6 @@ static ssize_t b43_debugfs_read(struct file *file, char __user *userbuf, err = -ENOMEM; goto out_unlock; } - /* Sparse warns about the following memset, because it has a big - * size value. That warning is bogus, so I will ignore it. --mb */ memset(buf, 0, bufsize); if (dfops->take_irqlock) { spin_lock_irq(&dev->wl->irq_lock); @@ -482,9 +753,15 @@ out_unlock: .take_irqlock = _take_irqlock, \ } +B43_DEBUGFS_FOPS(shm16read, shm16read__read_file, shm16read__write_file, 1); +B43_DEBUGFS_FOPS(shm16write, NULL, shm16write__write_file, 1); +B43_DEBUGFS_FOPS(shm32read, shm32read__read_file, shm32read__write_file, 1); +B43_DEBUGFS_FOPS(shm32write, NULL, shm32write__write_file, 1); +B43_DEBUGFS_FOPS(mmio16read, mmio16read__read_file, mmio16read__write_file, 1); +B43_DEBUGFS_FOPS(mmio16write, NULL, mmio16write__write_file, 1); +B43_DEBUGFS_FOPS(mmio32read, mmio32read__read_file, mmio32read__write_file, 1); +B43_DEBUGFS_FOPS(mmio32write, NULL, mmio32write__write_file, 1); B43_DEBUGFS_FOPS(tsf, tsf_read_file, tsf_write_file, 1); -B43_DEBUGFS_FOPS(ucode_regs, ucode_regs_read_file, NULL, 1); -B43_DEBUGFS_FOPS(shm, shm_read_file, NULL, 1); B43_DEBUGFS_FOPS(txstat, txstat_read_file, NULL, 0); B43_DEBUGFS_FOPS(txpower_g, txpower_g_read_file, txpower_g_write_file, 0); B43_DEBUGFS_FOPS(restart, NULL, restart_write_file, 1); @@ -523,6 +800,8 @@ static void b43_add_dynamic_debug(struct b43_wldev *dev) add_dyn_dbg("debug_dmaverbose", B43_DBG_DMAVERBOSE, 0); add_dyn_dbg("debug_pwork_fast", B43_DBG_PWORK_FAST, 0); add_dyn_dbg("debug_pwork_stop", B43_DBG_PWORK_STOP, 0); + add_dyn_dbg("debug_lo", B43_DBG_LO, 0); + add_dyn_dbg("debug_firmware", B43_DBG_FIRMWARE, 0); #undef add_dyn_dbg } @@ -569,6 +848,13 @@ void b43_debugfs_add_device(struct b43_wldev *dev) return; } + e->mmio16read_next = 0xFFFF; /* invalid address */ + e->mmio32read_next = 0xFFFF; /* invalid address */ + e->shm16read_routing_next = 0xFFFFFFFF; /* invalid routing */ + e->shm16read_addr_next = 0xFFFFFFFF; /* invalid address */ + e->shm32read_routing_next = 0xFFFFFFFF; /* invalid routing */ + e->shm32read_addr_next = 0xFFFFFFFF; /* invalid address */ + #define ADD_FILE(name, mode) \ do { \ struct dentry *d; \ @@ -581,9 +867,15 @@ void b43_debugfs_add_device(struct b43_wldev *dev) } while (0) + ADD_FILE(shm16read, 0600); + ADD_FILE(shm16write, 0200); + ADD_FILE(shm32read, 0600); + ADD_FILE(shm32write, 0200); + ADD_FILE(mmio16read, 0600); + ADD_FILE(mmio16write, 0200); + ADD_FILE(mmio32read, 0600); + ADD_FILE(mmio32write, 0200); ADD_FILE(tsf, 0600); - ADD_FILE(ucode_regs, 0400); - ADD_FILE(shm, 0400); ADD_FILE(txstat, 0400); ADD_FILE(txpower_g, 0600); ADD_FILE(restart, 0200); @@ -605,9 +897,15 @@ void b43_debugfs_remove_device(struct b43_wldev *dev) return; b43_remove_dynamic_debug(dev); + debugfs_remove(e->file_shm16read.dentry); + debugfs_remove(e->file_shm16write.dentry); + debugfs_remove(e->file_shm32read.dentry); + debugfs_remove(e->file_shm32write.dentry); + debugfs_remove(e->file_mmio16read.dentry); + debugfs_remove(e->file_mmio16write.dentry); + debugfs_remove(e->file_mmio32read.dentry); + debugfs_remove(e->file_mmio32write.dentry); debugfs_remove(e->file_tsf.dentry); - debugfs_remove(e->file_ucode_regs.dentry); - debugfs_remove(e->file_shm.dentry); debugfs_remove(e->file_txstat.dentry); debugfs_remove(e->file_txpower_g.dentry); debugfs_remove(e->file_restart.dentry); diff --git a/drivers/net/wireless/b43/debugfs.h b/drivers/net/wireless/b43/debugfs.h index 6eebe858db5a..22ffd02ba554 100644 --- a/drivers/net/wireless/b43/debugfs.h +++ b/drivers/net/wireless/b43/debugfs.h @@ -10,6 +10,8 @@ enum b43_dyndbg { /* Dynamic debugging features */ B43_DBG_DMAVERBOSE, B43_DBG_PWORK_FAST, B43_DBG_PWORK_STOP, + B43_DBG_LO, + B43_DBG_FIRMWARE, __B43_NR_DYNDBG, }; @@ -35,9 +37,15 @@ struct b43_dfsentry { struct b43_wldev *dev; struct dentry *subdir; + struct b43_dfs_file file_shm16read; + struct b43_dfs_file file_shm16write; + struct b43_dfs_file file_shm32read; + struct b43_dfs_file file_shm32write; + struct b43_dfs_file file_mmio16read; + struct b43_dfs_file file_mmio16write; + struct b43_dfs_file file_mmio32read; + struct b43_dfs_file file_mmio32write; struct b43_dfs_file file_tsf; - struct b43_dfs_file file_ucode_regs; - struct b43_dfs_file file_shm; struct b43_dfs_file file_txstat; struct b43_dfs_file file_txpower_g; struct b43_dfs_file file_restart; @@ -45,6 +53,18 @@ struct b43_dfsentry { struct b43_txstatus_log txstatlog; + /* The cached address for the next mmio16read file read */ + u16 mmio16read_next; + /* The cached address for the next mmio32read file read */ + u16 mmio32read_next; + + /* The cached address for the next shm16read file read */ + u32 shm16read_routing_next; + u32 shm16read_addr_next; + /* The cached address for the next shm32read file read */ + u32 shm32read_routing_next; + u32 shm32read_addr_next; + /* Enabled/Disabled list for the dynamic debugging features. */ u32 dyn_debug[__B43_NR_DYNDBG]; /* Dentries for the dynamic debugging entries. */ diff --git a/drivers/net/wireless/b43/dma.c b/drivers/net/wireless/b43/dma.c index e23f2f172bd7..098f886976f6 100644 --- a/drivers/net/wireless/b43/dma.c +++ b/drivers/net/wireless/b43/dma.c @@ -328,11 +328,11 @@ static inline dma_addr_t dmaaddr; if (tx) { - dmaaddr = dma_map_single(ring->dev->dev->dma_dev, - buf, len, DMA_TO_DEVICE); + dmaaddr = ssb_dma_map_single(ring->dev->dev, + buf, len, DMA_TO_DEVICE); } else { - dmaaddr = dma_map_single(ring->dev->dev->dma_dev, - buf, len, DMA_FROM_DEVICE); + dmaaddr = ssb_dma_map_single(ring->dev->dev, + buf, len, DMA_FROM_DEVICE); } return dmaaddr; @@ -343,11 +343,11 @@ static inline dma_addr_t addr, size_t len, int tx) { if (tx) { - dma_unmap_single(ring->dev->dev->dma_dev, - addr, len, DMA_TO_DEVICE); + ssb_dma_unmap_single(ring->dev->dev, + addr, len, DMA_TO_DEVICE); } else { - dma_unmap_single(ring->dev->dev->dma_dev, - addr, len, DMA_FROM_DEVICE); + ssb_dma_unmap_single(ring->dev->dev, + addr, len, DMA_FROM_DEVICE); } } @@ -356,8 +356,8 @@ static inline dma_addr_t addr, size_t len) { B43_WARN_ON(ring->tx); - dma_sync_single_for_cpu(ring->dev->dev->dma_dev, - addr, len, DMA_FROM_DEVICE); + ssb_dma_sync_single_for_cpu(ring->dev->dev, + addr, len, DMA_FROM_DEVICE); } static inline @@ -365,8 +365,8 @@ static inline dma_addr_t addr, size_t len) { B43_WARN_ON(ring->tx); - dma_sync_single_for_device(ring->dev->dev->dma_dev, - addr, len, DMA_FROM_DEVICE); + ssb_dma_sync_single_for_device(ring->dev->dev, + addr, len, DMA_FROM_DEVICE); } static inline @@ -381,7 +381,6 @@ static inline static int alloc_ringmemory(struct b43_dmaring *ring) { - struct device *dma_dev = ring->dev->dev->dma_dev; gfp_t flags = GFP_KERNEL; /* The specs call for 4K buffers for 30- and 32-bit DMA with 4K @@ -392,11 +391,14 @@ static int alloc_ringmemory(struct b43_dmaring *ring) * For unknown reasons - possibly a hardware error - the BCM4311 rev * 02, which uses 64-bit DMA, needs the ring buffer in very low memory, * which accounts for the GFP_DMA flag below. + * + * The flags here must match the flags in free_ringmemory below! */ if (ring->type == B43_DMA_64BIT) flags |= GFP_DMA; - ring->descbase = dma_alloc_coherent(dma_dev, B43_DMA_RINGMEMSIZE, - &(ring->dmabase), flags); + ring->descbase = ssb_dma_alloc_consistent(ring->dev->dev, + B43_DMA_RINGMEMSIZE, + &(ring->dmabase), flags); if (!ring->descbase) { b43err(ring->dev->wl, "DMA ringmemory allocation failed\n"); return -ENOMEM; @@ -408,10 +410,13 @@ static int alloc_ringmemory(struct b43_dmaring *ring) static void free_ringmemory(struct b43_dmaring *ring) { - struct device *dma_dev = ring->dev->dev->dma_dev; + gfp_t flags = GFP_KERNEL; + + if (ring->type == B43_DMA_64BIT) + flags |= GFP_DMA; - dma_free_coherent(dma_dev, B43_DMA_RINGMEMSIZE, - ring->descbase, ring->dmabase); + ssb_dma_free_consistent(ring->dev->dev, B43_DMA_RINGMEMSIZE, + ring->descbase, ring->dmabase, flags); } /* Reset the RX DMA channel */ @@ -518,7 +523,7 @@ static bool b43_dma_mapping_error(struct b43_dmaring *ring, dma_addr_t addr, size_t buffersize, bool dma_to_device) { - if (unlikely(dma_mapping_error(addr))) + if (unlikely(ssb_dma_mapping_error(ring->dev->dev, addr))) return 1; switch (ring->type) { @@ -844,10 +849,10 @@ struct b43_dmaring *b43_setup_dmaring(struct b43_wldev *dev, goto err_kfree_meta; /* test for ability to dma to txhdr_cache */ - dma_test = dma_map_single(dev->dev->dma_dev, - ring->txhdr_cache, - b43_txhdr_size(dev), - DMA_TO_DEVICE); + dma_test = ssb_dma_map_single(dev->dev, + ring->txhdr_cache, + b43_txhdr_size(dev), + DMA_TO_DEVICE); if (b43_dma_mapping_error(ring, dma_test, b43_txhdr_size(dev), 1)) { @@ -859,10 +864,10 @@ struct b43_dmaring *b43_setup_dmaring(struct b43_wldev *dev, if (!ring->txhdr_cache) goto err_kfree_meta; - dma_test = dma_map_single(dev->dev->dma_dev, - ring->txhdr_cache, - b43_txhdr_size(dev), - DMA_TO_DEVICE); + dma_test = ssb_dma_map_single(dev->dev, + ring->txhdr_cache, + b43_txhdr_size(dev), + DMA_TO_DEVICE); if (b43_dma_mapping_error(ring, dma_test, b43_txhdr_size(dev), 1)) { @@ -873,9 +878,9 @@ struct b43_dmaring *b43_setup_dmaring(struct b43_wldev *dev, } } - dma_unmap_single(dev->dev->dma_dev, - dma_test, b43_txhdr_size(dev), - DMA_TO_DEVICE); + ssb_dma_unmap_single(dev->dev, + dma_test, b43_txhdr_size(dev), + DMA_TO_DEVICE); } err = alloc_ringmemory(ring); @@ -1130,10 +1135,10 @@ struct b43_dmaring *parse_cookie(struct b43_wldev *dev, u16 cookie, int *slot) } static int dma_tx_fragment(struct b43_dmaring *ring, - struct sk_buff *skb, - struct ieee80211_tx_control *ctl) + struct sk_buff *skb) { const struct b43_dma_ops *ops = ring->ops; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); u8 *header; int slot, old_top_slot, old_used_slots; int err; @@ -1157,7 +1162,7 @@ static int dma_tx_fragment(struct b43_dmaring *ring, header = &(ring->txhdr_cache[slot * hdrsize]); cookie = generate_cookie(ring, slot); err = b43_generate_txhdr(ring->dev, header, - skb->data, skb->len, ctl, cookie); + skb->data, skb->len, info, cookie); if (unlikely(err)) { ring->current_slot = old_top_slot; ring->used_slots = old_used_slots; @@ -1179,7 +1184,6 @@ static int dma_tx_fragment(struct b43_dmaring *ring, desc = ops->idx2desc(ring, slot, &meta); memset(meta, 0, sizeof(*meta)); - memcpy(&meta->txstat.control, ctl, sizeof(*ctl)); meta->skb = skb; meta->is_last_fragment = 1; @@ -1209,7 +1213,7 @@ static int dma_tx_fragment(struct b43_dmaring *ring, ops->fill_descriptor(ring, desc, meta->dmaaddr, skb->len, 0, 1, 1); - if (ctl->flags & IEEE80211_TXCTL_SEND_AFTER_DTIM) { + if (info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM) { /* Tell the firmware about the cookie of the last * mcast frame, so it can clear the more-data bit in it. */ b43_shm_write16(ring->dev, B43_SHM_SHARED, @@ -1280,16 +1284,16 @@ static struct b43_dmaring * select_ring_by_priority(struct b43_wldev *dev, return ring; } -int b43_dma_tx(struct b43_wldev *dev, - struct sk_buff *skb, struct ieee80211_tx_control *ctl) +int b43_dma_tx(struct b43_wldev *dev, struct sk_buff *skb) { struct b43_dmaring *ring; struct ieee80211_hdr *hdr; int err = 0; unsigned long flags; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); hdr = (struct ieee80211_hdr *)skb->data; - if (ctl->flags & IEEE80211_TXCTL_SEND_AFTER_DTIM) { + if (info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM) { /* The multicast ring will be sent after the DTIM */ ring = dev->dma.tx_ring_mcast; /* Set the more-data bit. Ucode will clear it on @@ -1297,7 +1301,8 @@ int b43_dma_tx(struct b43_wldev *dev, hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_MOREDATA); } else { /* Decide by priority where to put this frame. */ - ring = select_ring_by_priority(dev, ctl->queue); + ring = select_ring_by_priority( + dev, skb_get_queue_mapping(skb)); } spin_lock_irqsave(&ring->lock, flags); @@ -1315,9 +1320,9 @@ int b43_dma_tx(struct b43_wldev *dev, /* Assign the queue number to the ring (if not already done before) * so TX status handling can use it. The queue to ring mapping is * static, so we don't need to store it per frame. */ - ring->queue_prio = ctl->queue; + ring->queue_prio = skb_get_queue_mapping(skb); - err = dma_tx_fragment(ring, skb, ctl); + err = dma_tx_fragment(ring, skb); if (unlikely(err == -ENOKEY)) { /* Drop this packet, as we don't have the encryption key * anymore and must not transmit it unencrypted. */ @@ -1333,7 +1338,7 @@ int b43_dma_tx(struct b43_wldev *dev, if ((free_slots(ring) < SLOTS_PER_PACKET) || should_inject_overflow(ring)) { /* This TX ring is full. */ - ieee80211_stop_queue(dev->wl->hw, ctl->queue); + ieee80211_stop_queue(dev->wl->hw, skb_get_queue_mapping(skb)); ring->stopped = 1; if (b43_debug(dev, B43_DBG_DMAVERBOSE)) { b43dbg(dev->wl, "Stopped TX ring %d\n", ring->index); @@ -1376,13 +1381,19 @@ void b43_dma_handle_txstatus(struct b43_wldev *dev, b43_txhdr_size(dev), 1); if (meta->is_last_fragment) { - B43_WARN_ON(!meta->skb); - /* Call back to inform the ieee80211 subsystem about the - * status of the transmission. - * Some fields of txstat are already filled in dma_tx(). + struct ieee80211_tx_info *info; + + BUG_ON(!meta->skb); + + info = IEEE80211_SKB_CB(meta->skb); + + memset(&info->status, 0, sizeof(info->status)); + + /* + * Call back to inform the ieee80211 subsystem about + * the status of the transmission. */ - frame_succeed = b43_fill_txstatus_report( - &(meta->txstat), status); + frame_succeed = b43_fill_txstatus_report(info, status); #ifdef CONFIG_B43_DEBUG if (frame_succeed) ring->nr_succeed_tx_packets++; @@ -1390,8 +1401,8 @@ void b43_dma_handle_txstatus(struct b43_wldev *dev, ring->nr_failed_tx_packets++; ring->nr_total_packet_tries += status->frame_count; #endif /* DEBUG */ - ieee80211_tx_status_irqsafe(dev->wl->hw, meta->skb, - &(meta->txstat)); + ieee80211_tx_status_irqsafe(dev->wl->hw, meta->skb); + /* skb is freed by ieee80211_tx_status_irqsafe() */ meta->skb = NULL; } else { @@ -1426,18 +1437,16 @@ void b43_dma_get_tx_stats(struct b43_wldev *dev, { const int nr_queues = dev->wl->hw->queues; struct b43_dmaring *ring; - struct ieee80211_tx_queue_stats_data *data; unsigned long flags; int i; for (i = 0; i < nr_queues; i++) { - data = &(stats->data[i]); ring = select_ring_by_priority(dev, i); spin_lock_irqsave(&ring->lock, flags); - data->len = ring->used_slots / SLOTS_PER_PACKET; - data->limit = ring->nr_slots / SLOTS_PER_PACKET; - data->count = ring->nr_tx_packets; + stats[i].len = ring->used_slots / SLOTS_PER_PACKET; + stats[i].limit = ring->nr_slots / SLOTS_PER_PACKET; + stats[i].count = ring->nr_tx_packets; spin_unlock_irqrestore(&ring->lock, flags); } } diff --git a/drivers/net/wireless/b43/dma.h b/drivers/net/wireless/b43/dma.h index 20acf885dba5..d1eb5c0848a5 100644 --- a/drivers/net/wireless/b43/dma.h +++ b/drivers/net/wireless/b43/dma.h @@ -181,7 +181,6 @@ struct b43_dmadesc_meta { dma_addr_t dmaaddr; /* ieee80211 TX status. Only used once per 802.11 frag. */ bool is_last_fragment; - struct ieee80211_tx_status txstat; }; struct b43_dmaring; @@ -285,7 +284,7 @@ void b43_dma_get_tx_stats(struct b43_wldev *dev, struct ieee80211_tx_queue_stats *stats); int b43_dma_tx(struct b43_wldev *dev, - struct sk_buff *skb, struct ieee80211_tx_control *ctl); + struct sk_buff *skb); void b43_dma_handle_txstatus(struct b43_wldev *dev, const struct b43_txstatus *status); diff --git a/drivers/net/wireless/b43/lo.c b/drivers/net/wireless/b43/lo.c index d890f366a23b..9c854d6aae36 100644 --- a/drivers/net/wireless/b43/lo.c +++ b/drivers/net/wireless/b43/lo.c @@ -36,17 +36,28 @@ #include <linux/sched.h> -/* Define to 1 to always calibrate all possible LO control pairs. - * This is a workaround until we fix the partial LO calibration optimization. */ -#define B43_CALIB_ALL_LOCTLS 1 +static struct b43_lo_calib * b43_find_lo_calib(struct b43_txpower_lo_control *lo, + const struct b43_bbatt *bbatt, + const struct b43_rfatt *rfatt) +{ + struct b43_lo_calib *c; + + list_for_each_entry(c, &lo->calib_list, list) { + if (!b43_compare_bbatt(&c->bbatt, bbatt)) + continue; + if (!b43_compare_rfatt(&c->rfatt, rfatt)) + continue; + return c; + } + return NULL; +} /* Write the LocalOscillator Control (adjust) value-pair. */ static void b43_lo_write(struct b43_wldev *dev, struct b43_loctl *control) { struct b43_phy *phy = &dev->phy; u16 value; - u16 reg; if (B43_DEBUG) { if (unlikely(abs(control->i) > 16 || abs(control->q) > 16)) { @@ -56,189 +67,11 @@ static void b43_lo_write(struct b43_wldev *dev, struct b43_loctl *control) return; } } + B43_WARN_ON(phy->type != B43_PHYTYPE_G); value = (u8) (control->q); value |= ((u8) (control->i)) << 8; - - reg = (phy->type == B43_PHYTYPE_B) ? 0x002F : B43_PHY_LO_CTL; - b43_phy_write(dev, reg, value); -} - -static int assert_rfatt_and_bbatt(const struct b43_rfatt *rfatt, - const struct b43_bbatt *bbatt, - struct b43_wldev *dev) -{ - int err = 0; - - /* Check the attenuation values against the LO control array sizes. */ - if (unlikely(rfatt->att >= B43_NR_RF)) { - b43err(dev->wl, "rfatt(%u) >= size of LO array\n", rfatt->att); - err = -EINVAL; - } - if (unlikely(bbatt->att >= B43_NR_BB)) { - b43err(dev->wl, "bbatt(%u) >= size of LO array\n", bbatt->att); - err = -EINVAL; - } - - return err; -} - -#if !B43_CALIB_ALL_LOCTLS -static -struct b43_loctl *b43_get_lo_g_ctl_nopadmix(struct b43_wldev *dev, - const struct b43_rfatt *rfatt, - const struct b43_bbatt *bbatt) -{ - struct b43_phy *phy = &dev->phy; - struct b43_txpower_lo_control *lo = phy->lo_control; - - if (assert_rfatt_and_bbatt(rfatt, bbatt, dev)) - return &(lo->no_padmix[0][0]); /* Just prevent a crash */ - return &(lo->no_padmix[bbatt->att][rfatt->att]); -} -#endif /* !B43_CALIB_ALL_LOCTLS */ - -struct b43_loctl *b43_get_lo_g_ctl(struct b43_wldev *dev, - const struct b43_rfatt *rfatt, - const struct b43_bbatt *bbatt) -{ - struct b43_phy *phy = &dev->phy; - struct b43_txpower_lo_control *lo = phy->lo_control; - - if (assert_rfatt_and_bbatt(rfatt, bbatt, dev)) - return &(lo->no_padmix[0][0]); /* Just prevent a crash */ - if (rfatt->with_padmix) - return &(lo->with_padmix[bbatt->att][rfatt->att]); - return &(lo->no_padmix[bbatt->att][rfatt->att]); -} - -/* Call a function for every possible LO control value-pair. */ -static void b43_call_for_each_loctl(struct b43_wldev *dev, - void (*func) (struct b43_wldev *, - struct b43_loctl *)) -{ - struct b43_phy *phy = &dev->phy; - struct b43_txpower_lo_control *ctl = phy->lo_control; - int i, j; - - for (i = 0; i < B43_NR_BB; i++) { - for (j = 0; j < B43_NR_RF; j++) - func(dev, &(ctl->with_padmix[i][j])); - } - for (i = 0; i < B43_NR_BB; i++) { - for (j = 0; j < B43_NR_RF; j++) - func(dev, &(ctl->no_padmix[i][j])); - } -} - -static u16 lo_b_r15_loop(struct b43_wldev *dev) -{ - int i; - u16 ret = 0; - - for (i = 0; i < 10; i++) { - b43_phy_write(dev, 0x0015, 0xAFA0); - udelay(1); - b43_phy_write(dev, 0x0015, 0xEFA0); - udelay(10); - b43_phy_write(dev, 0x0015, 0xFFA0); - udelay(40); - ret += b43_phy_read(dev, 0x002C); - } - - return ret; -} - -void b43_lo_b_measure(struct b43_wldev *dev) -{ - struct b43_phy *phy = &dev->phy; - u16 regstack[12] = { 0 }; - u16 mls; - u16 fval; - int i, j; - - regstack[0] = b43_phy_read(dev, 0x0015); - regstack[1] = b43_radio_read16(dev, 0x0052) & 0xFFF0; - - if (phy->radio_ver == 0x2053) { - regstack[2] = b43_phy_read(dev, 0x000A); - regstack[3] = b43_phy_read(dev, 0x002A); - regstack[4] = b43_phy_read(dev, 0x0035); - regstack[5] = b43_phy_read(dev, 0x0003); - regstack[6] = b43_phy_read(dev, 0x0001); - regstack[7] = b43_phy_read(dev, 0x0030); - - regstack[8] = b43_radio_read16(dev, 0x0043); - regstack[9] = b43_radio_read16(dev, 0x007A); - regstack[10] = b43_read16(dev, 0x03EC); - regstack[11] = b43_radio_read16(dev, 0x0052) & 0x00F0; - - b43_phy_write(dev, 0x0030, 0x00FF); - b43_write16(dev, 0x03EC, 0x3F3F); - b43_phy_write(dev, 0x0035, regstack[4] & 0xFF7F); - b43_radio_write16(dev, 0x007A, regstack[9] & 0xFFF0); - } - b43_phy_write(dev, 0x0015, 0xB000); - b43_phy_write(dev, 0x002B, 0x0004); - - if (phy->radio_ver == 0x2053) { - b43_phy_write(dev, 0x002B, 0x0203); - b43_phy_write(dev, 0x002A, 0x08A3); - } - - phy->minlowsig[0] = 0xFFFF; - - for (i = 0; i < 4; i++) { - b43_radio_write16(dev, 0x0052, regstack[1] | i); - lo_b_r15_loop(dev); - } - for (i = 0; i < 10; i++) { - b43_radio_write16(dev, 0x0052, regstack[1] | i); - mls = lo_b_r15_loop(dev) / 10; - if (mls < phy->minlowsig[0]) { - phy->minlowsig[0] = mls; - phy->minlowsigpos[0] = i; - } - } - b43_radio_write16(dev, 0x0052, regstack[1] | phy->minlowsigpos[0]); - - phy->minlowsig[1] = 0xFFFF; - - for (i = -4; i < 5; i += 2) { - for (j = -4; j < 5; j += 2) { - if (j < 0) - fval = (0x0100 * i) + j + 0x0100; - else - fval = (0x0100 * i) + j; - b43_phy_write(dev, 0x002F, fval); - mls = lo_b_r15_loop(dev) / 10; - if (mls < phy->minlowsig[1]) { - phy->minlowsig[1] = mls; - phy->minlowsigpos[1] = fval; - } - } - } - phy->minlowsigpos[1] += 0x0101; - - b43_phy_write(dev, 0x002F, phy->minlowsigpos[1]); - if (phy->radio_ver == 0x2053) { - b43_phy_write(dev, 0x000A, regstack[2]); - b43_phy_write(dev, 0x002A, regstack[3]); - b43_phy_write(dev, 0x0035, regstack[4]); - b43_phy_write(dev, 0x0003, regstack[5]); - b43_phy_write(dev, 0x0001, regstack[6]); - b43_phy_write(dev, 0x0030, regstack[7]); - - b43_radio_write16(dev, 0x0043, regstack[8]); - b43_radio_write16(dev, 0x007A, regstack[9]); - - b43_radio_write16(dev, 0x0052, - (b43_radio_read16(dev, 0x0052) & 0x000F) - | regstack[11]); - - b43_write16(dev, 0x03EC, regstack[10]); - } - b43_phy_write(dev, 0x0015, regstack[0]); + b43_phy_write(dev, B43_PHY_LO_CTL, value); } static u16 lo_measure_feedthrough(struct b43_wldev *dev, @@ -366,7 +199,7 @@ static void lo_measure_txctl_values(struct b43_wldev *dev) if (lb_gain > 10) { radio_pctl_reg = 0; pga = abs(10 - lb_gain) / 6; - pga = limit_value(pga, 0, 15); + pga = clamp_val(pga, 0, 15); } else { int cmp_val; int tmp; @@ -438,48 +271,26 @@ static void lo_measure_txctl_values(struct b43_wldev *dev) b43_radio_write16(dev, 0x52, b43_radio_read16(dev, 0x52) & 0xFFF0); /* TX bias == 0 */ } + lo->txctl_measured_time = jiffies; } static void lo_read_power_vector(struct b43_wldev *dev) { struct b43_phy *phy = &dev->phy; struct b43_txpower_lo_control *lo = phy->lo_control; - u16 i; + int i; u64 tmp; u64 power_vector = 0; - int rf_offset, bb_offset; - struct b43_loctl *loctl; for (i = 0; i < 8; i += 2) { tmp = b43_shm_read16(dev, B43_SHM_SHARED, 0x310 + i); - /* Clear the top byte. We get holes in the bitmap... */ - tmp &= 0xFF; power_vector |= (tmp << (i * 8)); /* Clear the vector on the device. */ b43_shm_write16(dev, B43_SHM_SHARED, 0x310 + i, 0); } - if (power_vector) lo->power_vector = power_vector; - power_vector = lo->power_vector; - - for (i = 0; i < 64; i++) { - if (power_vector & ((u64) 1ULL << i)) { - /* Now figure out which b43_loctl corresponds - * to this bit. - */ - rf_offset = i / lo->rfatt_list.len; - bb_offset = i % lo->rfatt_list.len; //FIXME? - loctl = - b43_get_lo_g_ctl(dev, - &lo->rfatt_list.list[rf_offset], - &lo->bbatt_list.list[bb_offset]); - /* And mark it as "used", as the device told us - * through the bitmap it is using it. - */ - loctl->used = 1; - } - } + lo->pwr_vec_read_time = jiffies; } /* 802.11/LO/GPHY/MeasuringGains */ @@ -510,7 +321,7 @@ static void lo_measure_gain_values(struct b43_wldev *dev, phy->lna_lod_gain = 1; trsw_rx_gain -= 8; } - trsw_rx_gain = limit_value(trsw_rx_gain, 0, 0x2D); + trsw_rx_gain = clamp_val(trsw_rx_gain, 0, 0x2D); phy->pga_gain = trsw_rx_gain / 3; if (phy->pga_gain >= 5) { phy->pga_gain -= 5; @@ -609,8 +420,6 @@ static void lo_measure_setup(struct b43_wldev *dev, b43_phy_write(dev, B43_PHY_CCK(0x16), 0x410); b43_phy_write(dev, B43_PHY_CCK(0x17), 0x820); } - if (!lo->rebuild && b43_has_hardware_pctl(phy)) - lo_read_power_vector(dev); if (phy->rev >= 2) { sav->phy_analogover = b43_phy_read(dev, B43_PHY_ANALOGOVER); sav->phy_analogoverval = @@ -691,8 +500,12 @@ static void lo_measure_setup(struct b43_wldev *dev, b43_radio_read16(dev, 0x51); /* dummy read */ if (phy->type == B43_PHYTYPE_G) b43_phy_write(dev, B43_PHY_CCK(0x2F), 0); - if (lo->rebuild) + + /* Re-measure the txctl values, if needed. */ + if (time_before(lo->txctl_measured_time, + jiffies - B43_LO_TXCTL_EXPIRE)) lo_measure_txctl_values(dev); + if (phy->type == B43_PHYTYPE_G && phy->rev >= 3) { b43_phy_write(dev, B43_PHY_LO_MASK, 0xC078); } else { @@ -707,7 +520,6 @@ static void lo_measure_restore(struct b43_wldev *dev, struct lo_g_saved_values *sav) { struct b43_phy *phy = &dev->phy; - struct b43_txpower_lo_control *lo = phy->lo_control; u16 tmp; if (phy->rev >= 2) { @@ -722,14 +534,6 @@ static void lo_measure_restore(struct b43_wldev *dev, tmp = (phy->pga_gain | 0xEFA0); b43_phy_write(dev, B43_PHY_PGACTL, tmp); } - if (b43_has_hardware_pctl(phy)) { - b43_gphy_dc_lt_init(dev); - } else { - if (lo->rebuild) - b43_lo_g_adjust_to(dev, 3, 2, 0); - else - b43_lo_g_adjust(dev); - } if (phy->type == B43_PHYTYPE_G) { if (phy->rev >= 3) b43_phy_write(dev, B43_PHY_CCK(0x2E), 0xC078); @@ -793,7 +597,6 @@ static int lo_probe_possible_loctls(struct b43_wldev *dev, struct b43_lo_g_statemachine *d) { struct b43_phy *phy = &dev->phy; - struct b43_txpower_lo_control *lo = phy->lo_control; struct b43_loctl test_loctl; struct b43_loctl orig_loctl; struct b43_loctl prev_loctl = { @@ -852,7 +655,7 @@ static int lo_probe_possible_loctls(struct b43_wldev *dev, found_lower = 1; d->lowest_feedth = feedth; if ((d->nr_measured < 2) && - (!has_loopback_gain(phy) || lo->rebuild)) + !has_loopback_gain(phy)) break; } } @@ -874,7 +677,6 @@ static void lo_probe_loctls_statemachine(struct b43_wldev *dev, int *max_rx_gain) { struct b43_phy *phy = &dev->phy; - struct b43_txpower_lo_control *lo = phy->lo_control; struct b43_lo_g_statemachine d; u16 feedth; int found_lower; @@ -883,18 +685,18 @@ static void lo_probe_loctls_statemachine(struct b43_wldev *dev, d.nr_measured = 0; d.state_val_multiplier = 1; - if (has_loopback_gain(phy) && !lo->rebuild) + if (has_loopback_gain(phy)) d.state_val_multiplier = 3; memcpy(&d.min_loctl, loctl, sizeof(struct b43_loctl)); - if (has_loopback_gain(phy) && lo->rebuild) + if (has_loopback_gain(phy)) max_repeat = 4; do { b43_lo_write(dev, &d.min_loctl); feedth = lo_measure_feedthrough(dev, phy->lna_gain, phy->pga_gain, phy->trsw_rx_gain); - if (!lo->rebuild && feedth < 0x258) { + if (feedth < 0x258) { if (feedth >= 0x12C) *max_rx_gain += 6; else @@ -944,278 +746,188 @@ static void lo_probe_loctls_statemachine(struct b43_wldev *dev, } while (++repeat_cnt < max_repeat); } -#if B43_CALIB_ALL_LOCTLS -static const struct b43_rfatt b43_full_rfatt_list_items[] = { - { .att = 0, .with_padmix = 0, }, - { .att = 1, .with_padmix = 0, }, - { .att = 2, .with_padmix = 0, }, - { .att = 3, .with_padmix = 0, }, - { .att = 4, .with_padmix = 0, }, - { .att = 5, .with_padmix = 0, }, - { .att = 6, .with_padmix = 0, }, - { .att = 7, .with_padmix = 0, }, - { .att = 8, .with_padmix = 0, }, - { .att = 9, .with_padmix = 0, }, - { .att = 10, .with_padmix = 0, }, - { .att = 11, .with_padmix = 0, }, - { .att = 12, .with_padmix = 0, }, - { .att = 13, .with_padmix = 0, }, - { .att = 14, .with_padmix = 0, }, - { .att = 15, .with_padmix = 0, }, - { .att = 0, .with_padmix = 1, }, - { .att = 1, .with_padmix = 1, }, - { .att = 2, .with_padmix = 1, }, - { .att = 3, .with_padmix = 1, }, - { .att = 4, .with_padmix = 1, }, - { .att = 5, .with_padmix = 1, }, - { .att = 6, .with_padmix = 1, }, - { .att = 7, .with_padmix = 1, }, - { .att = 8, .with_padmix = 1, }, - { .att = 9, .with_padmix = 1, }, - { .att = 10, .with_padmix = 1, }, - { .att = 11, .with_padmix = 1, }, - { .att = 12, .with_padmix = 1, }, - { .att = 13, .with_padmix = 1, }, - { .att = 14, .with_padmix = 1, }, - { .att = 15, .with_padmix = 1, }, -}; -static const struct b43_rfatt_list b43_full_rfatt_list = { - .list = b43_full_rfatt_list_items, - .len = ARRAY_SIZE(b43_full_rfatt_list_items), -}; - -static const struct b43_bbatt b43_full_bbatt_list_items[] = { - { .att = 0, }, - { .att = 1, }, - { .att = 2, }, - { .att = 3, }, - { .att = 4, }, - { .att = 5, }, - { .att = 6, }, - { .att = 7, }, - { .att = 8, }, - { .att = 9, }, - { .att = 10, }, - { .att = 11, }, -}; -static const struct b43_bbatt_list b43_full_bbatt_list = { - .list = b43_full_bbatt_list_items, - .len = ARRAY_SIZE(b43_full_bbatt_list_items), -}; -#endif /* B43_CALIB_ALL_LOCTLS */ - -static void lo_measure(struct b43_wldev *dev) +static +struct b43_lo_calib * b43_calibrate_lo_setting(struct b43_wldev *dev, + const struct b43_bbatt *bbatt, + const struct b43_rfatt *rfatt) { struct b43_phy *phy = &dev->phy; - struct b43_txpower_lo_control *lo = phy->lo_control; struct b43_loctl loctl = { .i = 0, .q = 0, }; - struct b43_loctl *ploctl; int max_rx_gain; - int rfidx, bbidx; - const struct b43_bbatt_list *bbatt_list; - const struct b43_rfatt_list *rfatt_list; - + struct b43_lo_calib *cal; + struct lo_g_saved_values uninitialized_var(saved_regs); /* Values from the "TXCTL Register and Value Table" */ u16 txctl_reg; u16 txctl_value; u16 pad_mix_gain; - bbatt_list = &lo->bbatt_list; - rfatt_list = &lo->rfatt_list; -#if B43_CALIB_ALL_LOCTLS - bbatt_list = &b43_full_bbatt_list; - rfatt_list = &b43_full_rfatt_list; -#endif + saved_regs.old_channel = phy->channel; + b43_mac_suspend(dev); + lo_measure_setup(dev, &saved_regs); txctl_reg = lo_txctl_register_table(dev, &txctl_value, &pad_mix_gain); - for (rfidx = 0; rfidx < rfatt_list->len; rfidx++) { - - b43_radio_write16(dev, 0x43, (b43_radio_read16(dev, 0x43) - & 0xFFF0) | - rfatt_list->list[rfidx].att); - b43_radio_write16(dev, txctl_reg, - (b43_radio_read16(dev, txctl_reg) - & ~txctl_value) - | (rfatt_list->list[rfidx].with_padmix ? - txctl_value : 0)); - - for (bbidx = 0; bbidx < bbatt_list->len; bbidx++) { - if (lo->rebuild) { -#if B43_CALIB_ALL_LOCTLS - ploctl = b43_get_lo_g_ctl(dev, - &rfatt_list->list[rfidx], - &bbatt_list->list[bbidx]); -#else - ploctl = b43_get_lo_g_ctl_nopadmix(dev, - &rfatt_list-> - list[rfidx], - &bbatt_list-> - list[bbidx]); -#endif - } else { - ploctl = b43_get_lo_g_ctl(dev, - &rfatt_list->list[rfidx], - &bbatt_list->list[bbidx]); - if (!ploctl->used) - continue; - } - memcpy(&loctl, ploctl, sizeof(loctl)); - loctl.i = 0; - loctl.q = 0; - - max_rx_gain = rfatt_list->list[rfidx].att * 2; - max_rx_gain += bbatt_list->list[bbidx].att / 2; - if (rfatt_list->list[rfidx].with_padmix) - max_rx_gain -= pad_mix_gain; - if (has_loopback_gain(phy)) - max_rx_gain += phy->max_lb_gain; - lo_measure_gain_values(dev, max_rx_gain, - has_loopback_gain(phy)); - - b43_phy_set_baseband_attenuation(dev, - bbatt_list->list[bbidx].att); - lo_probe_loctls_statemachine(dev, &loctl, &max_rx_gain); - if (phy->type == B43_PHYTYPE_B) { - loctl.i++; - loctl.q++; - } - b43_loctl_set_calibrated(&loctl, 1); - memcpy(ploctl, &loctl, sizeof(loctl)); - } - } -} - -#if B43_DEBUG -static void do_validate_loctl(struct b43_wldev *dev, struct b43_loctl *control) -{ - const int is_initializing = (b43_status(dev) == B43_STAT_UNINIT); - int i = control->i; - int q = control->q; + b43_radio_write16(dev, 0x43, + (b43_radio_read16(dev, 0x43) & 0xFFF0) + | rfatt->att); + b43_radio_write16(dev, txctl_reg, + (b43_radio_read16(dev, txctl_reg) & ~txctl_value) + | (rfatt->with_padmix) ? txctl_value : 0); - if (b43_loctl_is_calibrated(control)) { - if ((abs(i) > 16) || (abs(q) > 16)) - goto error; - } else { - if (control->used) - goto error; - if (dev->phy.lo_control->rebuild) { - control->i = 0; - control->q = 0; - if ((i != B43_LOCTL_POISON) || - (q != B43_LOCTL_POISON)) - goto error; - } + max_rx_gain = rfatt->att * 2; + max_rx_gain += bbatt->att / 2; + if (rfatt->with_padmix) + max_rx_gain -= pad_mix_gain; + if (has_loopback_gain(phy)) + max_rx_gain += phy->max_lb_gain; + lo_measure_gain_values(dev, max_rx_gain, + has_loopback_gain(phy)); + + b43_phy_set_baseband_attenuation(dev, bbatt->att); + lo_probe_loctls_statemachine(dev, &loctl, &max_rx_gain); + + lo_measure_restore(dev, &saved_regs); + b43_mac_enable(dev); + + if (b43_debug(dev, B43_DBG_LO)) { + b43dbg(dev->wl, "LO: Calibrated for BB(%u), RF(%u,%u) " + "=> I=%d Q=%d\n", + bbatt->att, rfatt->att, rfatt->with_padmix, + loctl.i, loctl.q); } - if (is_initializing && control->used) - goto error; - - return; -error: - b43err(dev->wl, "LO control pair validation failed " - "(I: %d, Q: %d, used %u, calib: %u, initing: %d)\n", - i, q, control->used, - b43_loctl_is_calibrated(control), - is_initializing); -} -static void validate_all_loctls(struct b43_wldev *dev) -{ - b43_call_for_each_loctl(dev, do_validate_loctl); -} - -static void do_reset_calib(struct b43_wldev *dev, struct b43_loctl *control) -{ - if (dev->phy.lo_control->rebuild || - control->used) { - b43_loctl_set_calibrated(control, 0); - control->i = B43_LOCTL_POISON; - control->q = B43_LOCTL_POISON; + cal = kmalloc(sizeof(*cal), GFP_KERNEL); + if (!cal) { + b43warn(dev->wl, "LO calib: out of memory\n"); + return NULL; } + memcpy(&cal->bbatt, bbatt, sizeof(*bbatt)); + memcpy(&cal->rfatt, rfatt, sizeof(*rfatt)); + memcpy(&cal->ctl, &loctl, sizeof(loctl)); + cal->calib_time = jiffies; + INIT_LIST_HEAD(&cal->list); + + return cal; } -static void reset_all_loctl_calibration_states(struct b43_wldev *dev) +/* Get a calibrated LO setting for the given attenuation values. + * Might return a NULL pointer under OOM! */ +static +struct b43_lo_calib * b43_get_calib_lo_settings(struct b43_wldev *dev, + const struct b43_bbatt *bbatt, + const struct b43_rfatt *rfatt) { - b43_call_for_each_loctl(dev, do_reset_calib); + struct b43_txpower_lo_control *lo = dev->phy.lo_control; + struct b43_lo_calib *c; + + c = b43_find_lo_calib(lo, bbatt, rfatt); + if (c) + return c; + /* Not in the list of calibrated LO settings. + * Calibrate it now. */ + c = b43_calibrate_lo_setting(dev, bbatt, rfatt); + if (!c) + return NULL; + list_add(&c->list, &lo->calib_list); + + return c; } -#else /* B43_DEBUG */ -static inline void validate_all_loctls(struct b43_wldev *dev) { } -static inline void reset_all_loctl_calibration_states(struct b43_wldev *dev) { } -#endif /* B43_DEBUG */ - -void b43_lo_g_measure(struct b43_wldev *dev) +void b43_gphy_dc_lt_init(struct b43_wldev *dev, bool update_all) { struct b43_phy *phy = &dev->phy; - struct lo_g_saved_values uninitialized_var(sav); - - B43_WARN_ON((phy->type != B43_PHYTYPE_B) && - (phy->type != B43_PHYTYPE_G)); - - sav.old_channel = phy->channel; - lo_measure_setup(dev, &sav); - reset_all_loctl_calibration_states(dev); - lo_measure(dev); - lo_measure_restore(dev, &sav); - - validate_all_loctls(dev); + struct b43_txpower_lo_control *lo = phy->lo_control; + int i; + int rf_offset, bb_offset; + const struct b43_rfatt *rfatt; + const struct b43_bbatt *bbatt; + u64 power_vector; + bool table_changed = 0; - phy->lo_control->lo_measured = 1; - phy->lo_control->rebuild = 0; -} + BUILD_BUG_ON(B43_DC_LT_SIZE != 32); + B43_WARN_ON(lo->rfatt_list.len * lo->bbatt_list.len > 64); -#if B43_DEBUG -static void validate_loctl_calibration(struct b43_wldev *dev, - struct b43_loctl *loctl, - struct b43_rfatt *rfatt, - struct b43_bbatt *bbatt) -{ - if (b43_loctl_is_calibrated(loctl)) - return; - if (!dev->phy.lo_control->lo_measured) { - /* On init we set the attenuation values before we - * calibrated the LO. I guess that's OK. */ - return; + power_vector = lo->power_vector; + if (!update_all && !power_vector) + return; /* Nothing to do. */ + + /* Suspend the MAC now to avoid continuous suspend/enable + * cycles in the loop. */ + b43_mac_suspend(dev); + + for (i = 0; i < B43_DC_LT_SIZE * 2; i++) { + struct b43_lo_calib *cal; + int idx; + u16 val; + + if (!update_all && !(power_vector & (((u64)1ULL) << i))) + continue; + /* Update the table entry for this power_vector bit. + * The table rows are RFatt entries and columns are BBatt. */ + bb_offset = i / lo->rfatt_list.len; + rf_offset = i % lo->rfatt_list.len; + bbatt = &(lo->bbatt_list.list[bb_offset]); + rfatt = &(lo->rfatt_list.list[rf_offset]); + + cal = b43_calibrate_lo_setting(dev, bbatt, rfatt); + if (!cal) { + b43warn(dev->wl, "LO: Could not " + "calibrate DC table entry\n"); + continue; + } + /*FIXME: Is Q really in the low nibble? */ + val = (u8)(cal->ctl.q); + val |= ((u8)(cal->ctl.i)) << 4; + kfree(cal); + + /* Get the index into the hardware DC LT. */ + idx = i / 2; + /* Change the table in memory. */ + if (i % 2) { + /* Change the high byte. */ + lo->dc_lt[idx] = (lo->dc_lt[idx] & 0x00FF) + | ((val & 0x00FF) << 8); + } else { + /* Change the low byte. */ + lo->dc_lt[idx] = (lo->dc_lt[idx] & 0xFF00) + | (val & 0x00FF); + } + table_changed = 1; } - b43err(dev->wl, "Adjusting Local Oscillator to an uncalibrated " - "control pair: rfatt=%u,%spadmix bbatt=%u\n", - rfatt->att, - (rfatt->with_padmix) ? "" : "no-", - bbatt->att); -} -#else -static inline void validate_loctl_calibration(struct b43_wldev *dev, - struct b43_loctl *loctl, - struct b43_rfatt *rfatt, - struct b43_bbatt *bbatt) -{ + if (table_changed) { + /* The table changed in memory. Update the hardware table. */ + for (i = 0; i < B43_DC_LT_SIZE; i++) + b43_phy_write(dev, 0x3A0 + i, lo->dc_lt[i]); + } + b43_mac_enable(dev); } -#endif -static inline void fixup_rfatt_for_txcontrol(struct b43_rfatt *rf, - u8 tx_control) +/* Fixup the RF attenuation value for the case where we are + * using the PAD mixer. */ +static inline void b43_lo_fixup_rfatt(struct b43_rfatt *rf) { - if (tx_control & B43_TXCTL_TXMIX) { - if (rf->att < 5) - rf->att = 4; - } + if (!rf->with_padmix) + return; + if ((rf->att != 1) && (rf->att != 2) && (rf->att != 3)) + rf->att = 4; } void b43_lo_g_adjust(struct b43_wldev *dev) { struct b43_phy *phy = &dev->phy; + struct b43_lo_calib *cal; struct b43_rfatt rf; - struct b43_loctl *loctl; memcpy(&rf, &phy->rfatt, sizeof(rf)); - fixup_rfatt_for_txcontrol(&rf, phy->tx_control); + b43_lo_fixup_rfatt(&rf); - loctl = b43_get_lo_g_ctl(dev, &rf, &phy->bbatt); - validate_loctl_calibration(dev, loctl, &rf, &phy->bbatt); - b43_lo_write(dev, loctl); + cal = b43_get_calib_lo_settings(dev, &phy->bbatt, &rf); + if (!cal) + return; + b43_lo_write(dev, &cal->ctl); } void b43_lo_g_adjust_to(struct b43_wldev *dev, @@ -1223,39 +935,102 @@ void b43_lo_g_adjust_to(struct b43_wldev *dev, { struct b43_rfatt rf; struct b43_bbatt bb; - struct b43_loctl *loctl; + struct b43_lo_calib *cal; memset(&rf, 0, sizeof(rf)); memset(&bb, 0, sizeof(bb)); rf.att = rfatt; bb.att = bbatt; - fixup_rfatt_for_txcontrol(&rf, tx_control); - loctl = b43_get_lo_g_ctl(dev, &rf, &bb); - validate_loctl_calibration(dev, loctl, &rf, &bb); - b43_lo_write(dev, loctl); + b43_lo_fixup_rfatt(&rf); + cal = b43_get_calib_lo_settings(dev, &bb, &rf); + if (!cal) + return; + b43_lo_write(dev, &cal->ctl); } -static void do_mark_unused(struct b43_wldev *dev, struct b43_loctl *control) +/* Periodic LO maintanance work */ +void b43_lo_g_maintanance_work(struct b43_wldev *dev) { - control->used = 0; + struct b43_phy *phy = &dev->phy; + struct b43_txpower_lo_control *lo = phy->lo_control; + unsigned long now; + unsigned long expire; + struct b43_lo_calib *cal, *tmp; + bool current_item_expired = 0; + bool hwpctl; + + if (!lo) + return; + now = jiffies; + hwpctl = b43_has_hardware_pctl(phy); + + if (hwpctl) { + /* Read the power vector and update it, if needed. */ + expire = now - B43_LO_PWRVEC_EXPIRE; + if (time_before(lo->pwr_vec_read_time, expire)) { + lo_read_power_vector(dev); + b43_gphy_dc_lt_init(dev, 0); + } + //FIXME Recalc the whole DC table from time to time? + } + + if (hwpctl) + return; + /* Search for expired LO settings. Remove them. + * Recalibrate the current setting, if expired. */ + expire = now - B43_LO_CALIB_EXPIRE; + list_for_each_entry_safe(cal, tmp, &lo->calib_list, list) { + if (!time_before(cal->calib_time, expire)) + continue; + /* This item expired. */ + if (b43_compare_bbatt(&cal->bbatt, &phy->bbatt) && + b43_compare_rfatt(&cal->rfatt, &phy->rfatt)) { + B43_WARN_ON(current_item_expired); + current_item_expired = 1; + } + if (b43_debug(dev, B43_DBG_LO)) { + b43dbg(dev->wl, "LO: Item BB(%u), RF(%u,%u), " + "I=%d, Q=%d expired\n", + cal->bbatt.att, cal->rfatt.att, + cal->rfatt.with_padmix, + cal->ctl.i, cal->ctl.q); + } + list_del(&cal->list); + kfree(cal); + } + if (current_item_expired || unlikely(list_empty(&lo->calib_list))) { + /* Recalibrate currently used LO setting. */ + if (b43_debug(dev, B43_DBG_LO)) + b43dbg(dev->wl, "LO: Recalibrating current LO setting\n"); + cal = b43_calibrate_lo_setting(dev, &phy->bbatt, &phy->rfatt); + if (cal) { + list_add(&cal->list, &lo->calib_list); + b43_lo_write(dev, &cal->ctl); + } else + b43warn(dev->wl, "Failed to recalibrate current LO setting\n"); + } } -void b43_lo_g_ctl_mark_all_unused(struct b43_wldev *dev) +void b43_lo_g_cleanup(struct b43_wldev *dev) { - struct b43_phy *phy = &dev->phy; - struct b43_txpower_lo_control *lo = phy->lo_control; + struct b43_txpower_lo_control *lo = dev->phy.lo_control; + struct b43_lo_calib *cal, *tmp; - b43_call_for_each_loctl(dev, do_mark_unused); - lo->rebuild = 1; + if (!lo) + return; + list_for_each_entry_safe(cal, tmp, &lo->calib_list, list) { + list_del(&cal->list); + kfree(cal); + } } -void b43_lo_g_ctl_mark_cur_used(struct b43_wldev *dev) +/* LO Initialization */ +void b43_lo_g_init(struct b43_wldev *dev) { struct b43_phy *phy = &dev->phy; - struct b43_rfatt rf; - memcpy(&rf, &phy->rfatt, sizeof(rf)); - fixup_rfatt_for_txcontrol(&rf, phy->tx_control); - - b43_get_lo_g_ctl(dev, &rf, &phy->bbatt)->used = 1; + if (b43_has_hardware_pctl(phy)) { + lo_read_power_vector(dev); + b43_gphy_dc_lt_init(dev, 1); + } } diff --git a/drivers/net/wireless/b43/lo.h b/drivers/net/wireless/b43/lo.h index 455615d1f8c6..1da321cabc12 100644 --- a/drivers/net/wireless/b43/lo.h +++ b/drivers/net/wireless/b43/lo.h @@ -10,82 +10,63 @@ struct b43_loctl { /* Control values. */ s8 i; s8 q; - /* "Used by hardware" flag. */ - bool used; -#ifdef CONFIG_B43_DEBUG - /* Is this lo-control-array entry calibrated? */ - bool calibrated; -#endif }; - /* Debugging: Poison value for i and q values. */ #define B43_LOCTL_POISON 111 -/* loctl->calibrated debugging mechanism */ -#ifdef CONFIG_B43_DEBUG -static inline void b43_loctl_set_calibrated(struct b43_loctl *loctl, - bool calibrated) -{ - loctl->calibrated = calibrated; -} -static inline bool b43_loctl_is_calibrated(struct b43_loctl *loctl) -{ - return loctl->calibrated; -} -#else -static inline void b43_loctl_set_calibrated(struct b43_loctl *loctl, - bool calibrated) -{ -} -static inline bool b43_loctl_is_calibrated(struct b43_loctl *loctl) -{ - return 1; -} -#endif - -/* TX Power LO Control Array. - * Value-pairs to adjust the LocalOscillator are stored - * in this structure. - * There are two different set of values. One for "Flag is Set" - * and one for "Flag is Unset". - * By "Flag" the flag in struct b43_rfatt is meant. - * The Value arrays are two-dimensional. The first index - * is the baseband attenuation and the second index - * is the radio attenuation. - * Use b43_get_lo_g_ctl() to retrieve a value from the lists. - */ +/* This struct holds calibrated LO settings for a set of + * Baseband and RF attenuation settings. */ +struct b43_lo_calib { + /* The set of attenuation values this set of LO + * control values is calibrated for. */ + struct b43_bbatt bbatt; + struct b43_rfatt rfatt; + /* The set of control values for the LO. */ + struct b43_loctl ctl; + /* The time when these settings were calibrated (in jiffies) */ + unsigned long calib_time; + /* List. */ + struct list_head list; +}; + +/* Size of the DC Lookup Table in 16bit words. */ +#define B43_DC_LT_SIZE 32 + +/* Local Oscillator calibration information */ struct b43_txpower_lo_control { -#define B43_NR_BB 12 -#define B43_NR_RF 16 - /* LO Control values, with PAD Mixer */ - struct b43_loctl with_padmix[B43_NR_BB][B43_NR_RF]; - /* LO Control values, without PAD Mixer */ - struct b43_loctl no_padmix[B43_NR_BB][B43_NR_RF]; - - /* Flag to indicate a complete rebuild of the two tables above - * to the LO measuring code. */ - bool rebuild; - - /* Lists of valid RF and BB attenuation values for this device. */ + /* Lists of RF and BB attenuation values for this device. + * Used for building hardware power control tables. */ struct b43_rfatt_list rfatt_list; struct b43_bbatt_list bbatt_list; + /* The DC Lookup Table is cached in memory here. + * Note that this is only used for Hardware Power Control. */ + u16 dc_lt[B43_DC_LT_SIZE]; + + /* List of calibrated control values (struct b43_lo_calib). */ + struct list_head calib_list; + /* Last time the power vector was read (jiffies). */ + unsigned long pwr_vec_read_time; + /* Last time the txctl values were measured (jiffies). */ + unsigned long txctl_measured_time; + /* Current TX Bias value */ u8 tx_bias; /* Current TX Magnification Value (if used by the device) */ u8 tx_magn; - /* GPHY LO is measured. */ - bool lo_measured; - /* Saved device PowerVector */ u64 power_vector; }; -/* Measure the BPHY Local Oscillator. */ -void b43_lo_b_measure(struct b43_wldev *dev); -/* Measure the BPHY/GPHY Local Oscillator. */ -void b43_lo_g_measure(struct b43_wldev *dev); +/* Calibration expire timeouts. + * Timeouts must be multiple of 15 seconds. To make sure + * the item really expired when the 15 second timer hits, we + * subtract two additional seconds from the timeout. */ +#define B43_LO_CALIB_EXPIRE (HZ * (30 - 2)) +#define B43_LO_PWRVEC_EXPIRE (HZ * (30 - 2)) +#define B43_LO_TXCTL_EXPIRE (HZ * (180 - 4)) + /* Adjust the Local Oscillator to the saved attenuation * and txctl values. @@ -95,18 +76,10 @@ void b43_lo_g_adjust(struct b43_wldev *dev); void b43_lo_g_adjust_to(struct b43_wldev *dev, u16 rfatt, u16 bbatt, u16 tx_control); -/* Mark all possible b43_lo_g_ctl as "unused" */ -void b43_lo_g_ctl_mark_all_unused(struct b43_wldev *dev); -/* Mark the b43_lo_g_ctl corresponding to the current - * attenuation values as used. - */ -void b43_lo_g_ctl_mark_cur_used(struct b43_wldev *dev); +void b43_gphy_dc_lt_init(struct b43_wldev *dev, bool update_all); -/* Get a reference to a LO Control value pair in the - * TX Power LO Control Array. - */ -struct b43_loctl *b43_get_lo_g_ctl(struct b43_wldev *dev, - const struct b43_rfatt *rfatt, - const struct b43_bbatt *bbatt); +void b43_lo_g_maintanance_work(struct b43_wldev *dev); +void b43_lo_g_cleanup(struct b43_wldev *dev); +void b43_lo_g_init(struct b43_wldev *dev); #endif /* B43_LO_H_ */ diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index a70827793086..e78319aa47c1 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -373,13 +373,10 @@ static inline void b43_shm_control_word(struct b43_wldev *dev, b43_write32(dev, B43_MMIO_SHM_CONTROL, control); } -u32 b43_shm_read32(struct b43_wldev *dev, u16 routing, u16 offset) +u32 __b43_shm_read32(struct b43_wldev *dev, u16 routing, u16 offset) { - struct b43_wl *wl = dev->wl; - unsigned long flags; u32 ret; - spin_lock_irqsave(&wl->shm_lock, flags); if (routing == B43_SHM_SHARED) { B43_WARN_ON(offset & 0x0001); if (offset & 0x0003) { @@ -397,18 +394,26 @@ u32 b43_shm_read32(struct b43_wldev *dev, u16 routing, u16 offset) b43_shm_control_word(dev, routing, offset); ret = b43_read32(dev, B43_MMIO_SHM_DATA); out: - spin_unlock_irqrestore(&wl->shm_lock, flags); - return ret; } -u16 b43_shm_read16(struct b43_wldev * dev, u16 routing, u16 offset) +u32 b43_shm_read32(struct b43_wldev *dev, u16 routing, u16 offset) { struct b43_wl *wl = dev->wl; unsigned long flags; - u16 ret; + u32 ret; spin_lock_irqsave(&wl->shm_lock, flags); + ret = __b43_shm_read32(dev, routing, offset); + spin_unlock_irqrestore(&wl->shm_lock, flags); + + return ret; +} + +u16 __b43_shm_read16(struct b43_wldev *dev, u16 routing, u16 offset) +{ + u16 ret; + if (routing == B43_SHM_SHARED) { B43_WARN_ON(offset & 0x0001); if (offset & 0x0003) { @@ -423,17 +428,24 @@ u16 b43_shm_read16(struct b43_wldev * dev, u16 routing, u16 offset) b43_shm_control_word(dev, routing, offset); ret = b43_read16(dev, B43_MMIO_SHM_DATA); out: - spin_unlock_irqrestore(&wl->shm_lock, flags); - return ret; } -void b43_shm_write32(struct b43_wldev *dev, u16 routing, u16 offset, u32 value) +u16 b43_shm_read16(struct b43_wldev *dev, u16 routing, u16 offset) { struct b43_wl *wl = dev->wl; unsigned long flags; + u16 ret; spin_lock_irqsave(&wl->shm_lock, flags); + ret = __b43_shm_read16(dev, routing, offset); + spin_unlock_irqrestore(&wl->shm_lock, flags); + + return ret; +} + +void __b43_shm_write32(struct b43_wldev *dev, u16 routing, u16 offset, u32 value) +{ if (routing == B43_SHM_SHARED) { B43_WARN_ON(offset & 0x0001); if (offset & 0x0003) { @@ -443,35 +455,47 @@ void b43_shm_write32(struct b43_wldev *dev, u16 routing, u16 offset, u32 value) (value >> 16) & 0xffff); b43_shm_control_word(dev, routing, (offset >> 2) + 1); b43_write16(dev, B43_MMIO_SHM_DATA, value & 0xffff); - goto out; + return; } offset >>= 2; } b43_shm_control_word(dev, routing, offset); b43_write32(dev, B43_MMIO_SHM_DATA, value); -out: - spin_unlock_irqrestore(&wl->shm_lock, flags); } -void b43_shm_write16(struct b43_wldev *dev, u16 routing, u16 offset, u16 value) +void b43_shm_write32(struct b43_wldev *dev, u16 routing, u16 offset, u32 value) { struct b43_wl *wl = dev->wl; unsigned long flags; spin_lock_irqsave(&wl->shm_lock, flags); + __b43_shm_write32(dev, routing, offset, value); + spin_unlock_irqrestore(&wl->shm_lock, flags); +} + +void __b43_shm_write16(struct b43_wldev *dev, u16 routing, u16 offset, u16 value) +{ if (routing == B43_SHM_SHARED) { B43_WARN_ON(offset & 0x0001); if (offset & 0x0003) { /* Unaligned access */ b43_shm_control_word(dev, routing, offset >> 2); b43_write16(dev, B43_MMIO_SHM_DATA_UNALIGNED, value); - goto out; + return; } offset >>= 2; } b43_shm_control_word(dev, routing, offset); b43_write16(dev, B43_MMIO_SHM_DATA, value); -out: +} + +void b43_shm_write16(struct b43_wldev *dev, u16 routing, u16 offset, u16 value) +{ + struct b43_wl *wl = dev->wl; + unsigned long flags; + + spin_lock_irqsave(&wl->shm_lock, flags); + __b43_shm_write16(dev, routing, offset, value); spin_unlock_irqrestore(&wl->shm_lock, flags); } @@ -1187,10 +1211,10 @@ static void handle_irq_noise(struct b43_wldev *dev) /* Get the noise samples. */ B43_WARN_ON(dev->noisecalc.nr_samples >= 8); i = dev->noisecalc.nr_samples; - noise[0] = limit_value(noise[0], 0, ARRAY_SIZE(phy->nrssi_lt) - 1); - noise[1] = limit_value(noise[1], 0, ARRAY_SIZE(phy->nrssi_lt) - 1); - noise[2] = limit_value(noise[2], 0, ARRAY_SIZE(phy->nrssi_lt) - 1); - noise[3] = limit_value(noise[3], 0, ARRAY_SIZE(phy->nrssi_lt) - 1); + noise[0] = clamp_val(noise[0], 0, ARRAY_SIZE(phy->nrssi_lt) - 1); + noise[1] = clamp_val(noise[1], 0, ARRAY_SIZE(phy->nrssi_lt) - 1); + noise[2] = clamp_val(noise[2], 0, ARRAY_SIZE(phy->nrssi_lt) - 1); + noise[3] = clamp_val(noise[3], 0, ARRAY_SIZE(phy->nrssi_lt) - 1); dev->noisecalc.samples[i][0] = phy->nrssi_lt[noise[0]]; dev->noisecalc.samples[i][1] = phy->nrssi_lt[noise[1]]; dev->noisecalc.samples[i][2] = phy->nrssi_lt[noise[2]]; @@ -1372,18 +1396,18 @@ static void b43_write_beacon_template(struct b43_wldev *dev, 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 b43_plcp_hdr6)); - rate = dev->wl->beacon_txctl.tx_rate->hw_value; + rate = ieee80211_get_tx_rate(dev->wl->hw, info)->hw_value; b43_write_template_common(dev, (const u8 *)bcn, len, ram_offset, shm_size_offset, rate); /* Write the PHY TX control parameters. */ - antenna = b43_antenna_from_ieee80211(dev, - dev->wl->beacon_txctl.antenna_sel_tx); + antenna = b43_antenna_from_ieee80211(dev, info->antenna_sel_tx); antenna = b43_antenna_to_phyctl(antenna); ctl = b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_BEACPHYCTL); /* We can't send beacons with short preamble. Would get PHY errors. */ @@ -1434,11 +1458,17 @@ static void b43_write_beacon_template(struct b43_wldev *dev, i += ie_len + 2; } if (!tim_found) { - b43warn(dev->wl, "Did not find a valid TIM IE in " - "the beacon template packet. AP or IBSS operation " - "may be broken.\n"); - } else - b43dbg(dev->wl, "Updated beacon template\n"); + /* + * If ucode wants to modify TIM do it behind the beacon, this + * will happen, for example, when doing mesh networking. + */ + b43_shm_write16(dev, B43_SHM_SHARED, + B43_SHM_SH_TIMBPOS, + len + sizeof(struct b43_plcp_hdr6)); + b43_shm_write16(dev, B43_SHM_SHARED, + B43_SHM_SH_DTIMPER, 0); + } + b43dbg(dev->wl, "Updated beacon template at 0x%x\n", ram_offset); } static void b43_write_probe_resp_plcp(struct b43_wldev *dev, @@ -1577,7 +1607,8 @@ static void handle_irq_beacon(struct b43_wldev *dev) struct b43_wl *wl = dev->wl; u32 cmd, beacon0_valid, beacon1_valid; - if (!b43_is_mode(wl, IEEE80211_IF_TYPE_AP)) + if (!b43_is_mode(wl, IEEE80211_IF_TYPE_AP) && + !b43_is_mode(wl, IEEE80211_IF_TYPE_MESH_POINT)) return; /* This is the bottom half of the asynchronous beacon update. */ @@ -1644,19 +1675,27 @@ static void b43_beacon_update_trigger_work(struct work_struct *work) /* Asynchronously update the packet templates in template RAM. * Locking: Requires wl->irq_lock to be locked. */ -static void b43_update_templates(struct b43_wl *wl, struct sk_buff *beacon, - const struct ieee80211_tx_control *txctl) +static void b43_update_templates(struct b43_wl *wl) { + struct sk_buff *beacon; + /* This is the top half of the ansynchronous beacon update. * The bottom half is the beacon IRQ. * Beacon update must be asynchronous to avoid sending an * invalid beacon. This can happen for example, if the firmware * transmits a beacon while we are updating it. */ + /* We could modify the existing beacon and set the aid bit in + * the TIM field, but that would probably require resizing and + * moving of data within the beacon template. + * Simply request a new beacon and let mac80211 do the hard work. */ + beacon = ieee80211_beacon_get(wl->hw, wl->vif); + if (unlikely(!beacon)) + return; + if (wl->current_beacon) dev_kfree_skb_any(wl->current_beacon); wl->current_beacon = beacon; - memcpy(&wl->beacon_txctl, txctl, sizeof(wl->beacon_txctl)); wl->beacon0_uploaded = 0; wl->beacon1_uploaded = 0; queue_work(wl->hw->workqueue, &wl->beacon_update_trigger); @@ -1695,9 +1734,100 @@ static void b43_set_beacon_int(struct b43_wldev *dev, u16 beacon_int) b43dbg(dev->wl, "Set beacon interval to %u\n", beacon_int); } +static void b43_handle_firmware_panic(struct b43_wldev *dev) +{ + u16 reason; + + /* Read the register that contains the reason code for the panic. */ + reason = b43_shm_read16(dev, B43_SHM_SCRATCH, B43_FWPANIC_REASON_REG); + b43err(dev->wl, "Whoopsy, firmware panic! Reason: %u\n", reason); + + switch (reason) { + default: + b43dbg(dev->wl, "The panic reason is unknown.\n"); + /* fallthrough */ + case B43_FWPANIC_DIE: + /* Do not restart the controller or firmware. + * The device is nonfunctional from now on. + * Restarting would result in this panic to trigger again, + * so we avoid that recursion. */ + break; + case B43_FWPANIC_RESTART: + b43_controller_restart(dev, "Microcode panic"); + break; + } +} + static void handle_irq_ucode_debug(struct b43_wldev *dev) { - //TODO + unsigned int i, cnt; + u16 reason, marker_id, marker_line; + __le16 *buf; + + /* The proprietary firmware doesn't have this IRQ. */ + if (!dev->fw.opensource) + return; + + /* Read the register that contains the reason code for this IRQ. */ + reason = b43_shm_read16(dev, B43_SHM_SCRATCH, B43_DEBUGIRQ_REASON_REG); + + switch (reason) { + case B43_DEBUGIRQ_PANIC: + b43_handle_firmware_panic(dev); + break; + case B43_DEBUGIRQ_DUMP_SHM: + if (!B43_DEBUG) + break; /* Only with driver debugging enabled. */ + buf = kmalloc(4096, GFP_ATOMIC); + if (!buf) { + b43dbg(dev->wl, "SHM-dump: Failed to allocate memory\n"); + goto out; + } + for (i = 0; i < 4096; i += 2) { + u16 tmp = b43_shm_read16(dev, B43_SHM_SHARED, i); + buf[i / 2] = cpu_to_le16(tmp); + } + b43info(dev->wl, "Shared memory dump:\n"); + print_hex_dump(KERN_INFO, "", DUMP_PREFIX_OFFSET, + 16, 2, buf, 4096, 1); + kfree(buf); + break; + case B43_DEBUGIRQ_DUMP_REGS: + if (!B43_DEBUG) + break; /* Only with driver debugging enabled. */ + b43info(dev->wl, "Microcode register dump:\n"); + for (i = 0, cnt = 0; i < 64; i++) { + u16 tmp = b43_shm_read16(dev, B43_SHM_SCRATCH, i); + if (cnt == 0) + printk(KERN_INFO); + printk("r%02u: 0x%04X ", i, tmp); + cnt++; + if (cnt == 6) { + printk("\n"); + cnt = 0; + } + } + printk("\n"); + break; + case B43_DEBUGIRQ_MARKER: + if (!B43_DEBUG) + break; /* Only with driver debugging enabled. */ + marker_id = b43_shm_read16(dev, B43_SHM_SCRATCH, + B43_MARKER_ID_REG); + marker_line = b43_shm_read16(dev, B43_SHM_SCRATCH, + B43_MARKER_LINE_REG); + b43info(dev->wl, "The firmware just executed the MARKER(%u) " + "at line number %u\n", + marker_id, marker_line); + break; + default: + b43dbg(dev->wl, "Debug-IRQ triggered for unknown reason: %u\n", + reason); + } +out: + /* Acknowledge the debug-IRQ, so the firmware can continue. */ + b43_shm_write16(dev, B43_SHM_SCRATCH, + B43_DEBUGIRQ_REASON_REG, B43_DEBUGIRQ_ACK); } /* Interrupt handler bottom-half */ @@ -1884,7 +2014,8 @@ static void b43_print_fw_helptext(struct b43_wl *wl, bool error) static int do_request_fw(struct b43_wldev *dev, const char *name, - struct b43_firmware_file *fw) + struct b43_firmware_file *fw, + bool silent) { char path[sizeof(modparam_fwpostfix) + 32]; const struct firmware *blob; @@ -1908,9 +2039,15 @@ static int do_request_fw(struct b43_wldev *dev, "b43%s/%s.fw", modparam_fwpostfix, name); err = request_firmware(&blob, path, dev->dev->dev); - if (err) { - b43err(dev->wl, "Firmware file \"%s\" not found " - "or load failed.\n", path); + if (err == -ENOENT) { + if (!silent) { + b43err(dev->wl, "Firmware file \"%s\" not found\n", + path); + } + return err; + } else if (err) { + b43err(dev->wl, "Firmware file \"%s\" request failed (err=%d)\n", + path, err); return err; } if (blob->size < sizeof(struct b43_fw_header)) @@ -1961,7 +2098,7 @@ static int b43_request_firmware(struct b43_wldev *dev) filename = "ucode13"; else goto err_no_ucode; - err = do_request_fw(dev, filename, &fw->ucode); + err = do_request_fw(dev, filename, &fw->ucode, 0); if (err) goto err_load; @@ -1972,8 +2109,13 @@ static int b43_request_firmware(struct b43_wldev *dev) filename = NULL; else goto err_no_pcm; - err = do_request_fw(dev, filename, &fw->pcm); - if (err) + fw->pcm_request_failed = 0; + err = do_request_fw(dev, filename, &fw->pcm, 1); + if (err == -ENOENT) { + /* We did not find a PCM file? Not fatal, but + * core rev <= 10 must do without hwcrypto then. */ + fw->pcm_request_failed = 1; + } else if (err) goto err_load; /* Get initvals */ @@ -1991,7 +2133,7 @@ static int b43_request_firmware(struct b43_wldev *dev) if ((rev >= 5) && (rev <= 10)) filename = "b0g0initvals5"; else if (rev >= 13) - filename = "lp0initvals13"; + filename = "b0g0initvals13"; else goto err_no_initvals; break; @@ -2004,7 +2146,7 @@ static int b43_request_firmware(struct b43_wldev *dev) default: goto err_no_initvals; } - err = do_request_fw(dev, filename, &fw->initvals); + err = do_request_fw(dev, filename, &fw->initvals, 0); if (err) goto err_load; @@ -2038,7 +2180,7 @@ static int b43_request_firmware(struct b43_wldev *dev) default: goto err_no_initvals; } - err = do_request_fw(dev, filename, &fw->initvals_band); + err = do_request_fw(dev, filename, &fw->initvals_band, 0); if (err) goto err_load; @@ -2155,14 +2297,28 @@ static int b43_upload_microcode(struct b43_wldev *dev) err = -EOPNOTSUPP; goto error; } - b43info(dev->wl, "Loading firmware version %u.%u " - "(20%.2i-%.2i-%.2i %.2i:%.2i:%.2i)\n", - fwrev, fwpatch, - (fwdate >> 12) & 0xF, (fwdate >> 8) & 0xF, fwdate & 0xFF, - (fwtime >> 11) & 0x1F, (fwtime >> 5) & 0x3F, fwtime & 0x1F); - dev->fw.rev = fwrev; dev->fw.patch = fwpatch; + dev->fw.opensource = (fwdate == 0xFFFF); + + if (dev->fw.opensource) { + /* 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)" : ""); + } else { + b43info(dev->wl, "Loading firmware version %u.%u " + "(20%.2i-%.2i-%.2i %.2i:%.2i:%.2i)\n", + fwrev, fwpatch, + (fwdate >> 12) & 0xF, (fwdate >> 8) & 0xF, fwdate & 0xFF, + (fwtime >> 11) & 0x1F, (fwtime >> 5) & 0x3F, fwtime & 0x1F); + if (dev->fw.pcm_request_failed) { + b43warn(dev->wl, "No \"pcm5.fw\" firmware file found. " + "Hardware accelerated cryptography is disabled.\n"); + b43_print_fw_helptext(dev->wl, 0); + } + } if (b43_is_old_txhdr_format(dev)) { b43warn(dev->wl, "You are using an old firmware image. " @@ -2339,8 +2495,21 @@ static void b43_gpio_cleanup(struct b43_wldev *dev) } /* http://bcm-specs.sipsolutions.net/EnableMac */ -static void b43_mac_enable(struct b43_wldev *dev) -{ +void b43_mac_enable(struct b43_wldev *dev) +{ + if (b43_debug(dev, B43_DBG_FIRMWARE)) { + u16 fwstate; + + fwstate = b43_shm_read16(dev, B43_SHM_SHARED, + B43_SHM_SH_UCODESTAT); + if ((fwstate != B43_SHM_SH_UCODESTAT_SUSP) && + (fwstate != B43_SHM_SH_UCODESTAT_SLEEP)) { + b43err(dev->wl, "b43_mac_enable(): The firmware " + "should be suspended, but current state is %u\n", + fwstate); + } + } + dev->mac_suspended--; B43_WARN_ON(dev->mac_suspended < 0); if (dev->mac_suspended == 0) { @@ -2353,16 +2522,11 @@ static void b43_mac_enable(struct b43_wldev *dev) b43_read32(dev, B43_MMIO_MACCTL); b43_read32(dev, B43_MMIO_GEN_IRQ_REASON); b43_power_saving_ctl_bits(dev, 0); - - /* Re-enable IRQs. */ - spin_lock_irq(&dev->wl->irq_lock); - b43_interrupt_enable(dev, dev->irq_savedstate); - spin_unlock_irq(&dev->wl->irq_lock); } } /* http://bcm-specs.sipsolutions.net/SuspendMAC */ -static void b43_mac_suspend(struct b43_wldev *dev) +void b43_mac_suspend(struct b43_wldev *dev) { int i; u32 tmp; @@ -2371,14 +2535,6 @@ static void b43_mac_suspend(struct b43_wldev *dev) B43_WARN_ON(dev->mac_suspended < 0); if (dev->mac_suspended == 0) { - /* Mask IRQs before suspending MAC. Otherwise - * the MAC stays busy and won't suspend. */ - spin_lock_irq(&dev->wl->irq_lock); - tmp = b43_interrupt_disable(dev, B43_IRQ_ALL); - spin_unlock_irq(&dev->wl->irq_lock); - b43_synchronize_irq(dev); - dev->irq_savedstate = tmp; - b43_power_saving_ctl_bits(dev, B43_PS_AWAKE); b43_write32(dev, B43_MMIO_MACCTL, b43_read32(dev, B43_MMIO_MACCTL) @@ -2420,7 +2576,8 @@ static void b43_adjust_opmode(struct b43_wldev *dev) ctl &= ~B43_MACCTL_BEACPROMISC; ctl |= B43_MACCTL_INFRA; - if (b43_is_mode(wl, IEEE80211_IF_TYPE_AP)) + if (b43_is_mode(wl, IEEE80211_IF_TYPE_AP) || + b43_is_mode(wl, IEEE80211_IF_TYPE_MESH_POINT)) ctl |= B43_MACCTL_AP; else if (b43_is_mode(wl, IEEE80211_IF_TYPE_IBSS)) ctl &= ~B43_MACCTL_INFRA; @@ -2534,6 +2691,7 @@ static void b43_chip_exit(struct b43_wldev *dev) { b43_radio_turn_off(dev, 1); b43_gpio_cleanup(dev); + b43_lo_g_cleanup(dev); /* firmware is released later */ } @@ -2640,28 +2798,12 @@ err_gpio_clean: return err; } -static void b43_periodic_every120sec(struct b43_wldev *dev) -{ - struct b43_phy *phy = &dev->phy; - - if (phy->type != B43_PHYTYPE_G || phy->rev < 2) - return; - - b43_mac_suspend(dev); - b43_lo_g_measure(dev); - b43_mac_enable(dev); - if (b43_has_hardware_pctl(phy)) - b43_lo_g_ctl_mark_all_unused(dev); -} - static void b43_periodic_every60sec(struct b43_wldev *dev) { struct b43_phy *phy = &dev->phy; if (phy->type != B43_PHYTYPE_G) return; - if (!b43_has_hardware_pctl(phy)) - b43_lo_g_ctl_mark_all_unused(dev); if (dev->dev->bus->sprom.boardflags_lo & B43_BFL_RSSI) { b43_mac_suspend(dev); b43_calc_nrssi_slope(dev); @@ -2688,6 +2830,21 @@ static void b43_periodic_every30sec(struct b43_wldev *dev) static void b43_periodic_every15sec(struct b43_wldev *dev) { struct b43_phy *phy = &dev->phy; + u16 wdr; + + if (dev->fw.opensource) { + /* Check if the firmware is still alive. + * It will reset the watchdog counter to 0 in its idle loop. */ + wdr = b43_shm_read16(dev, B43_SHM_SCRATCH, B43_WATCHDOG_REG); + if (unlikely(wdr)) { + b43err(dev->wl, "Firmware watchdog: The firmware died!\n"); + b43_controller_restart(dev, "Firmware watchdog"); + return; + } else { + b43_shm_write16(dev, B43_SHM_SCRATCH, + B43_WATCHDOG_REG, 1); + } + } if (phy->type == B43_PHYTYPE_G) { //TODO: update_aci_moving_average @@ -2713,6 +2870,7 @@ static void b43_periodic_every15sec(struct b43_wldev *dev) } } b43_phy_xmitpower(dev); //FIXME: unless scanning? + b43_lo_g_maintanance_work(dev); //TODO for APHY (temperature?) atomic_set(&phy->txerr_cnt, B43_PHY_TX_BADNESS_LIMIT); @@ -2724,8 +2882,6 @@ static void do_periodic_work(struct b43_wldev *dev) unsigned int state; state = dev->periodic_state; - if (state % 8 == 0) - b43_periodic_every120sec(dev); if (state % 4 == 0) b43_periodic_every60sec(dev); if (state % 2 == 0) @@ -2873,8 +3029,7 @@ static int b43_rng_init(struct b43_wl *wl) } static int b43_op_tx(struct ieee80211_hw *hw, - struct sk_buff *skb, - struct ieee80211_tx_control *ctl) + struct sk_buff *skb) { struct b43_wl *wl = hw_to_b43_wl(hw); struct b43_wldev *dev = wl->current_dev; @@ -2895,9 +3050,9 @@ static int b43_op_tx(struct ieee80211_hw *hw, err = -ENODEV; if (likely(b43_status(dev) >= B43_STAT_STARTED)) { if (b43_using_pio_transfers(dev)) - err = b43_pio_tx(dev, skb, ctl); + err = b43_pio_tx(dev, skb); else - err = b43_dma_tx(dev, skb, ctl); + err = b43_dma_tx(dev, skb); } read_unlock_irqrestore(&wl->tx_lock, flags); @@ -2918,53 +3073,20 @@ static void b43_qos_params_upload(struct b43_wldev *dev, u16 shm_offset) { u16 params[B43_NR_QOSPARAMS]; - int cw_min, cw_max, aifs, bslots, tmp; + int bslots, tmp; unsigned int i; - const u16 aCWmin = 0x0001; - const u16 aCWmax = 0x03FF; - - /* Calculate the default values for the parameters, if needed. */ - switch (shm_offset) { - case B43_QOS_VOICE: - aifs = (p->aifs == -1) ? 2 : p->aifs; - cw_min = (p->cw_min == 0) ? ((aCWmin + 1) / 4 - 1) : p->cw_min; - cw_max = (p->cw_max == 0) ? ((aCWmin + 1) / 2 - 1) : p->cw_max; - break; - case B43_QOS_VIDEO: - aifs = (p->aifs == -1) ? 2 : p->aifs; - cw_min = (p->cw_min == 0) ? ((aCWmin + 1) / 2 - 1) : p->cw_min; - cw_max = (p->cw_max == 0) ? aCWmin : p->cw_max; - break; - case B43_QOS_BESTEFFORT: - aifs = (p->aifs == -1) ? 3 : p->aifs; - cw_min = (p->cw_min == 0) ? aCWmin : p->cw_min; - cw_max = (p->cw_max == 0) ? aCWmax : p->cw_max; - break; - case B43_QOS_BACKGROUND: - aifs = (p->aifs == -1) ? 7 : p->aifs; - cw_min = (p->cw_min == 0) ? aCWmin : p->cw_min; - cw_max = (p->cw_max == 0) ? aCWmax : p->cw_max; - break; - default: - B43_WARN_ON(1); - return; - } - if (cw_min <= 0) - cw_min = aCWmin; - if (cw_max <= 0) - cw_max = aCWmin; - bslots = b43_read16(dev, B43_MMIO_RNG) % cw_min; + bslots = b43_read16(dev, B43_MMIO_RNG) & p->cw_min; memset(¶ms, 0, sizeof(params)); params[B43_QOSPARAM_TXOP] = p->txop * 32; - params[B43_QOSPARAM_CWMIN] = cw_min; - params[B43_QOSPARAM_CWMAX] = cw_max; - params[B43_QOSPARAM_CWCUR] = cw_min; - params[B43_QOSPARAM_AIFS] = aifs; + params[B43_QOSPARAM_CWMIN] = p->cw_min; + params[B43_QOSPARAM_CWMAX] = p->cw_max; + params[B43_QOSPARAM_CWCUR] = p->cw_min; + params[B43_QOSPARAM_AIFS] = p->aifs; params[B43_QOSPARAM_BSLOTS] = bslots; - params[B43_QOSPARAM_REGGAP] = bslots + aifs; + params[B43_QOSPARAM_REGGAP] = bslots + p->aifs; for (i = 0; i < ARRAY_SIZE(params); i++) { if (i == B43_QOSPARAM_STATUS) { @@ -3060,8 +3182,7 @@ static void b43_qos_update_work(struct work_struct *work) mutex_unlock(&wl->mutex); } -static int b43_op_conf_tx(struct ieee80211_hw *hw, - int _queue, +static int b43_op_conf_tx(struct ieee80211_hw *hw, u16 _queue, const struct ieee80211_tx_queue_params *params) { struct b43_wl *wl = hw_to_b43_wl(hw); @@ -3309,8 +3430,9 @@ static int b43_op_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf) antenna = b43_antenna_from_ieee80211(dev, conf->antenna_sel_rx); b43_set_rx_antenna(dev, antenna); - /* Update templates for AP mode. */ - if (b43_is_mode(wl, IEEE80211_IF_TYPE_AP)) + /* Update templates for AP/mesh mode. */ + if (b43_is_mode(wl, IEEE80211_IF_TYPE_AP) || + b43_is_mode(wl, IEEE80211_IF_TYPE_MESH_POINT)) b43_set_beacon_int(dev, conf->beacon_int); if (!!conf->radio_enabled != phy->radio_on) { @@ -3361,6 +3483,13 @@ 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) { + /* We don't have firmware for the crypto engine. + * Must use software-crypto. */ + err = -EOPNOTSUPP; + goto out_unlock; + } + err = -EINVAL; switch (key->alg) { case ALG_WEP: @@ -3491,13 +3620,16 @@ static int b43_op_config_interface(struct ieee80211_hw *hw, else memset(wl->bssid, 0, ETH_ALEN); if (b43_status(dev) >= B43_STAT_INITIALIZED) { - if (b43_is_mode(wl, IEEE80211_IF_TYPE_AP)) { - B43_WARN_ON(conf->type != IEEE80211_IF_TYPE_AP); - b43_set_ssid(dev, conf->ssid, conf->ssid_len); - if (conf->beacon) { - b43_update_templates(wl, conf->beacon, - conf->beacon_control); - } + if (b43_is_mode(wl, IEEE80211_IF_TYPE_AP) || + b43_is_mode(wl, IEEE80211_IF_TYPE_MESH_POINT)) { + B43_WARN_ON(vif->type != wl->if_type); + if (conf->changed & IEEE80211_IFCC_SSID) + b43_set_ssid(dev, conf->ssid, conf->ssid_len); + if (conf->changed & IEEE80211_IFCC_BEACON) + b43_update_templates(wl); + } else if (b43_is_mode(wl, IEEE80211_IF_TYPE_IBSS)) { + if (conf->changed & IEEE80211_IFCC_BEACON) + b43_update_templates(wl); } b43_write_mac_bssid_templates(dev); } @@ -3562,7 +3694,6 @@ 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); - ieee80211_start_queues(dev->wl->hw); /* Start maintainance work */ b43_periodic_tasks_setup(dev); @@ -3703,8 +3834,8 @@ static void setup_struct_phy_for_init(struct b43_wldev *dev, lo = phy->lo_control; if (lo) { memset(lo, 0, sizeof(*(phy->lo_control))); - lo->rebuild = 1; lo->tx_bias = 0xFF; + INIT_LIST_HEAD(&lo->calib_list); } phy->max_lb_gain = 0; phy->trsw_rx_gain = 0; @@ -4035,6 +4166,7 @@ static int b43_op_add_interface(struct ieee80211_hw *hw, /* TODO: allow WDS/AP devices to coexist */ if (conf->type != IEEE80211_IF_TYPE_AP && + conf->type != IEEE80211_IF_TYPE_MESH_POINT && conf->type != IEEE80211_IF_TYPE_STA && conf->type != IEEE80211_IF_TYPE_WDS && conf->type != IEEE80211_IF_TYPE_IBSS) @@ -4185,33 +4317,10 @@ out_unlock: static int b43_op_beacon_set_tim(struct ieee80211_hw *hw, int aid, int set) { struct b43_wl *wl = hw_to_b43_wl(hw); - struct sk_buff *beacon; - unsigned long flags; - struct ieee80211_tx_control txctl; - - /* We could modify the existing beacon and set the aid bit in - * the TIM field, but that would probably require resizing and - * moving of data within the beacon template. - * Simply request a new beacon and let mac80211 do the hard work. */ - beacon = ieee80211_beacon_get(hw, wl->vif, &txctl); - if (unlikely(!beacon)) - return -ENOMEM; - spin_lock_irqsave(&wl->irq_lock, flags); - b43_update_templates(wl, beacon, &txctl); - spin_unlock_irqrestore(&wl->irq_lock, flags); - - return 0; -} - -static int b43_op_ibss_beacon_update(struct ieee80211_hw *hw, - struct sk_buff *beacon, - struct ieee80211_tx_control *ctl) -{ - struct b43_wl *wl = hw_to_b43_wl(hw); unsigned long flags; spin_lock_irqsave(&wl->irq_lock, flags); - b43_update_templates(wl, beacon, ctl); + b43_update_templates(wl); spin_unlock_irqrestore(&wl->irq_lock, flags); return 0; @@ -4242,7 +4351,6 @@ static const struct ieee80211_ops b43_hw_ops = { .stop = b43_op_stop, .set_retry_limit = b43_op_set_retry_limit, .set_tim = b43_op_beacon_set_tim, - .beacon_update = b43_op_ibss_beacon_update, .sta_notify = b43_op_sta_notify, }; @@ -4538,10 +4646,10 @@ static int b43_wireless_init(struct ssb_device *dev) /* fill hw info */ hw->flags = IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE | - IEEE80211_HW_RX_INCLUDES_FCS; - hw->max_signal = 100; - hw->max_rssi = -110; - hw->max_noise = -110; + IEEE80211_HW_RX_INCLUDES_FCS | + IEEE80211_HW_SIGNAL_DBM | + IEEE80211_HW_NOISE_DBM; + hw->queues = b43_modparam_qos ? 4 : 1; SET_IEEE80211_DEV(hw, dev->dev); if (is_valid_ether_addr(sprom->et1mac)) diff --git a/drivers/net/wireless/b43/main.h b/drivers/net/wireless/b43/main.h index 5230aeca78bf..f871a252cb55 100644 --- a/drivers/net/wireless/b43/main.h +++ b/drivers/net/wireless/b43/main.h @@ -95,9 +95,13 @@ void b43_tsf_read(struct b43_wldev *dev, u64 * tsf); void b43_tsf_write(struct b43_wldev *dev, u64 tsf); u32 b43_shm_read32(struct b43_wldev *dev, u16 routing, u16 offset); +u32 __b43_shm_read32(struct b43_wldev *dev, u16 routing, u16 offset); u16 b43_shm_read16(struct b43_wldev *dev, u16 routing, u16 offset); +u16 __b43_shm_read16(struct b43_wldev *dev, u16 routing, u16 offset); void b43_shm_write32(struct b43_wldev *dev, u16 routing, u16 offset, u32 value); +void __b43_shm_write32(struct b43_wldev *dev, u16 routing, u16 offset, u32 value); void b43_shm_write16(struct b43_wldev *dev, u16 routing, u16 offset, u16 value); +void __b43_shm_write16(struct b43_wldev *dev, u16 routing, u16 offset, u16 value); u64 b43_hf_read(struct b43_wldev *dev); void b43_hf_write(struct b43_wldev *dev, u64 value); @@ -114,4 +118,7 @@ void b43_controller_restart(struct b43_wldev *dev, const char *reason); #define B43_PS_ASLEEP (1 << 3) /* Force device asleep */ void b43_power_saving_ctl_bits(struct b43_wldev *dev, unsigned int ps_flags); +void b43_mac_suspend(struct b43_wldev *dev); +void b43_mac_enable(struct b43_wldev *dev); + #endif /* B43_MAIN_H_ */ diff --git a/drivers/net/wireless/b43/nphy.c b/drivers/net/wireless/b43/nphy.c index 8695eb223476..644eed993bea 100644 --- a/drivers/net/wireless/b43/nphy.c +++ b/drivers/net/wireless/b43/nphy.c @@ -29,8 +29,6 @@ #include "nphy.h" #include "tables_nphy.h" -#include <linux/delay.h> - void b43_nphy_set_rxantenna(struct b43_wldev *dev, int antenna) {//TODO diff --git a/drivers/net/wireless/b43/phy.c b/drivers/net/wireless/b43/phy.c index de024dc03718..305d4cd6fd03 100644 --- a/drivers/net/wireless/b43/phy.c +++ b/drivers/net/wireless/b43/phy.c @@ -28,6 +28,7 @@ #include <linux/delay.h> #include <linux/io.h> #include <linux/types.h> +#include <linux/bitrev.h> #include "b43.h" #include "phy.h" @@ -83,25 +84,9 @@ const u8 b43_radio_channel_codes_bg[] = { 72, 84, }; +#define bitrev4(tmp) (bitrev8(tmp) >> 4) static void b43_phy_initg(struct b43_wldev *dev); -/* Reverse the bits of a 4bit value. - * Example: 1101 is flipped 1011 - */ -static u16 flip_4bit(u16 value) -{ - u16 flipped = 0x0000; - - B43_WARN_ON(value & ~0x000F); - - flipped |= (value & 0x0001) << 3; - flipped |= (value & 0x0002) << 1; - flipped |= (value & 0x0004) >> 1; - flipped |= (value & 0x0008) >> 3; - - return flipped; -} - static void generate_rfatt_list(struct b43_wldev *dev, struct b43_rfatt_list *list) { @@ -145,8 +130,7 @@ static void generate_rfatt_list(struct b43_wldev *dev, {.att = 9,.with_padmix = 1,}, }; - if ((phy->type == B43_PHYTYPE_A && phy->rev < 5) || - (phy->type == B43_PHYTYPE_G && phy->rev < 6)) { + if (!b43_has_hardware_pctl(phy)) { /* Software pctl */ list->list = rfatt_0; list->len = ARRAY_SIZE(rfatt_0); @@ -158,7 +142,7 @@ static void generate_rfatt_list(struct b43_wldev *dev, /* Hardware pctl */ list->list = rfatt_1; list->len = ARRAY_SIZE(rfatt_1); - list->min_val = 2; + list->min_val = 0; list->max_val = 14; return; } @@ -346,6 +330,7 @@ void b43_set_txpower_g(struct b43_wldev *dev, /* Save the values for later */ phy->tx_control = tx_control; memcpy(&phy->rfatt, rfatt, sizeof(*rfatt)); + phy->rfatt.with_padmix = !!(tx_control & B43_TXCTL_TXMIX); memcpy(&phy->bbatt, bbatt, sizeof(*bbatt)); if (b43_debug(dev, B43_DBG_XMITPOWER)) { @@ -559,11 +544,6 @@ static void b43_gphy_gain_lt_init(struct b43_wldev *dev) u16 tmp; u8 rf, bb; - if (!lo->lo_measured) { - b43_phy_write(dev, 0x3FF, 0); - return; - } - for (rf = 0; rf < lo->rfatt_list.len; rf++) { for (bb = 0; bb < lo->bbatt_list.len; bb++) { if (nr_written >= 0x40) @@ -581,42 +561,6 @@ static void b43_gphy_gain_lt_init(struct b43_wldev *dev) } } -/* GPHY_DC_Lookup_Table */ -void b43_gphy_dc_lt_init(struct b43_wldev *dev) -{ - struct b43_phy *phy = &dev->phy; - struct b43_txpower_lo_control *lo = phy->lo_control; - struct b43_loctl *loctl0; - struct b43_loctl *loctl1; - int i; - int rf_offset, bb_offset; - u16 tmp; - - for (i = 0; i < lo->rfatt_list.len + lo->bbatt_list.len; i += 2) { - rf_offset = i / lo->rfatt_list.len; - bb_offset = i % lo->rfatt_list.len; - - loctl0 = b43_get_lo_g_ctl(dev, &lo->rfatt_list.list[rf_offset], - &lo->bbatt_list.list[bb_offset]); - if (i + 1 < lo->rfatt_list.len * lo->bbatt_list.len) { - rf_offset = (i + 1) / lo->rfatt_list.len; - bb_offset = (i + 1) % lo->rfatt_list.len; - - loctl1 = - b43_get_lo_g_ctl(dev, - &lo->rfatt_list.list[rf_offset], - &lo->bbatt_list.list[bb_offset]); - } else - loctl1 = loctl0; - - tmp = ((u16) loctl0->q & 0xF); - tmp |= ((u16) loctl0->i & 0xF) << 4; - tmp |= ((u16) loctl1->q & 0xF) << 8; - tmp |= ((u16) loctl1->i & 0xF) << 12; //FIXME? - b43_phy_write(dev, 0x3A0 + (i / 2), tmp); - } -} - static void hardware_pctl_init_aphy(struct b43_wldev *dev) { //TODO @@ -643,7 +587,7 @@ static void hardware_pctl_init_gphy(struct b43_wldev *dev) b43_phy_write(dev, 0x0801, b43_phy_read(dev, 0x0801) & 0xFFBF); - b43_gphy_dc_lt_init(dev); + b43_gphy_dc_lt_init(dev, 1); } /* HardwarePowerControl init for A and G PHY */ @@ -931,109 +875,6 @@ static void b43_phy_inita(struct b43_wldev *dev) } } -static void b43_phy_initb2(struct b43_wldev *dev) -{ - struct b43_phy *phy = &dev->phy; - u16 offset, val; - - b43_write16(dev, 0x03EC, 0x3F22); - b43_phy_write(dev, 0x0020, 0x301C); - b43_phy_write(dev, 0x0026, 0x0000); - b43_phy_write(dev, 0x0030, 0x00C6); - b43_phy_write(dev, 0x0088, 0x3E00); - val = 0x3C3D; - for (offset = 0x0089; offset < 0x00A7; offset++) { - b43_phy_write(dev, offset, val); - val -= 0x0202; - } - b43_phy_write(dev, 0x03E4, 0x3000); - b43_radio_selectchannel(dev, phy->channel, 0); - if (phy->radio_ver != 0x2050) { - b43_radio_write16(dev, 0x0075, 0x0080); - b43_radio_write16(dev, 0x0079, 0x0081); - } - b43_radio_write16(dev, 0x0050, 0x0020); - b43_radio_write16(dev, 0x0050, 0x0023); - if (phy->radio_ver == 0x2050) { - b43_radio_write16(dev, 0x0050, 0x0020); - b43_radio_write16(dev, 0x005A, 0x0070); - b43_radio_write16(dev, 0x005B, 0x007B); - b43_radio_write16(dev, 0x005C, 0x00B0); - b43_radio_write16(dev, 0x007A, 0x000F); - b43_phy_write(dev, 0x0038, 0x0677); - b43_radio_init2050(dev); - } - b43_phy_write(dev, 0x0014, 0x0080); - b43_phy_write(dev, 0x0032, 0x00CA); - b43_phy_write(dev, 0x0032, 0x00CC); - b43_phy_write(dev, 0x0035, 0x07C2); - b43_lo_b_measure(dev); - b43_phy_write(dev, 0x0026, 0xCC00); - if (phy->radio_ver != 0x2050) - b43_phy_write(dev, 0x0026, 0xCE00); - b43_write16(dev, B43_MMIO_CHANNEL_EXT, 0x1000); - b43_phy_write(dev, 0x002A, 0x88A3); - if (phy->radio_ver != 0x2050) - b43_phy_write(dev, 0x002A, 0x88C2); - b43_set_txpower_g(dev, &phy->bbatt, &phy->rfatt, phy->tx_control); - b43_phy_init_pctl(dev); -} - -static void b43_phy_initb4(struct b43_wldev *dev) -{ - struct b43_phy *phy = &dev->phy; - u16 offset, val; - - b43_write16(dev, 0x03EC, 0x3F22); - b43_phy_write(dev, 0x0020, 0x301C); - b43_phy_write(dev, 0x0026, 0x0000); - b43_phy_write(dev, 0x0030, 0x00C6); - b43_phy_write(dev, 0x0088, 0x3E00); - val = 0x3C3D; - for (offset = 0x0089; offset < 0x00A7; offset++) { - b43_phy_write(dev, offset, val); - val -= 0x0202; - } - b43_phy_write(dev, 0x03E4, 0x3000); - b43_radio_selectchannel(dev, phy->channel, 0); - if (phy->radio_ver != 0x2050) { - b43_radio_write16(dev, 0x0075, 0x0080); - b43_radio_write16(dev, 0x0079, 0x0081); - } - b43_radio_write16(dev, 0x0050, 0x0020); - b43_radio_write16(dev, 0x0050, 0x0023); - if (phy->radio_ver == 0x2050) { - b43_radio_write16(dev, 0x0050, 0x0020); - b43_radio_write16(dev, 0x005A, 0x0070); - b43_radio_write16(dev, 0x005B, 0x007B); - b43_radio_write16(dev, 0x005C, 0x00B0); - b43_radio_write16(dev, 0x007A, 0x000F); - b43_phy_write(dev, 0x0038, 0x0677); - b43_radio_init2050(dev); - } - b43_phy_write(dev, 0x0014, 0x0080); - b43_phy_write(dev, 0x0032, 0x00CA); - if (phy->radio_ver == 0x2050) - b43_phy_write(dev, 0x0032, 0x00E0); - b43_phy_write(dev, 0x0035, 0x07C2); - - b43_lo_b_measure(dev); - - b43_phy_write(dev, 0x0026, 0xCC00); - if (phy->radio_ver == 0x2050) - b43_phy_write(dev, 0x0026, 0xCE00); - b43_write16(dev, B43_MMIO_CHANNEL_EXT, 0x1100); - b43_phy_write(dev, 0x002A, 0x88A3); - if (phy->radio_ver == 0x2050) - b43_phy_write(dev, 0x002A, 0x88C2); - b43_set_txpower_g(dev, &phy->bbatt, &phy->rfatt, phy->tx_control); - if (dev->dev->bus->sprom.boardflags_lo & B43_BFL_RSSI) { - b43_calc_nrssi_slope(dev); - b43_calc_nrssi_threshold(dev); - } - b43_phy_init_pctl(dev); -} - static void b43_phy_initb5(struct b43_wldev *dev) { struct ssb_bus *bus = dev->dev->bus; @@ -1259,19 +1100,9 @@ static void b43_phy_initb6(struct b43_wldev *dev) b43_phy_write(dev, 0x0002, (b43_phy_read(dev, 0x0002) & 0xFFC0) | 0x0004); } - if (phy->type == B43_PHYTYPE_B) { - b43_write16(dev, 0x03E6, 0x8140); - b43_phy_write(dev, 0x0016, 0x0410); - b43_phy_write(dev, 0x0017, 0x0820); - b43_phy_write(dev, 0x0062, 0x0007); - b43_radio_init2050(dev); - b43_lo_g_measure(dev); - if (dev->dev->bus->sprom.boardflags_lo & B43_BFL_RSSI) { - b43_calc_nrssi_slope(dev); - b43_calc_nrssi_threshold(dev); - } - b43_phy_init_pctl(dev); - } else if (phy->type == B43_PHYTYPE_G) + if (phy->type == B43_PHYTYPE_B) + B43_WARN_ON(1); + else if (phy->type == B43_PHYTYPE_G) b43_write16(dev, 0x03E6, 0x0); } @@ -1534,34 +1365,31 @@ static void b43_phy_initg(struct b43_wldev *dev) else b43_radio_write16(dev, 0x0078, phy->initval); } - if (phy->lo_control->tx_bias == 0xFF) { - b43_lo_g_measure(dev); + b43_lo_g_init(dev); + if (has_tx_magnification(phy)) { + b43_radio_write16(dev, 0x52, + (b43_radio_read16(dev, 0x52) & 0xFF00) + | phy->lo_control->tx_bias | phy-> + lo_control->tx_magn); } else { - if (has_tx_magnification(phy)) { - b43_radio_write16(dev, 0x52, - (b43_radio_read16(dev, 0x52) & 0xFF00) - | phy->lo_control->tx_bias | phy-> - lo_control->tx_magn); - } else { - b43_radio_write16(dev, 0x52, - (b43_radio_read16(dev, 0x52) & 0xFFF0) - | phy->lo_control->tx_bias); - } - if (phy->rev >= 6) { - b43_phy_write(dev, B43_PHY_CCK(0x36), - (b43_phy_read(dev, B43_PHY_CCK(0x36)) - & 0x0FFF) | (phy->lo_control-> - tx_bias << 12)); - } - if (dev->dev->bus->sprom.boardflags_lo & B43_BFL_PACTRL) - b43_phy_write(dev, B43_PHY_CCK(0x2E), 0x8075); - else - b43_phy_write(dev, B43_PHY_CCK(0x2E), 0x807F); - if (phy->rev < 2) - b43_phy_write(dev, B43_PHY_CCK(0x2F), 0x101); - else - b43_phy_write(dev, B43_PHY_CCK(0x2F), 0x202); + b43_radio_write16(dev, 0x52, + (b43_radio_read16(dev, 0x52) & 0xFFF0) + | phy->lo_control->tx_bias); } + if (phy->rev >= 6) { + b43_phy_write(dev, B43_PHY_CCK(0x36), + (b43_phy_read(dev, B43_PHY_CCK(0x36)) + & 0x0FFF) | (phy->lo_control-> + tx_bias << 12)); + } + if (dev->dev->bus->sprom.boardflags_lo & B43_BFL_PACTRL) + b43_phy_write(dev, B43_PHY_CCK(0x2E), 0x8075); + else + b43_phy_write(dev, B43_PHY_CCK(0x2E), 0x807F); + if (phy->rev < 2) + b43_phy_write(dev, B43_PHY_CCK(0x2F), 0x101); + else + b43_phy_write(dev, B43_PHY_CCK(0x2F), 0x202); if (phy->gmode || phy->rev >= 2) { b43_lo_g_adjust(dev); b43_phy_write(dev, B43_PHY_LO_MASK, 0x8078); @@ -1572,7 +1400,7 @@ static void b43_phy_initg(struct b43_wldev *dev) * the value 0x7FFFFFFF here. I think that is some weird * compiler optimization in the original driver. * Essentially, what we do here is resetting all NRSSI LT - * entries to -32 (see the limit_value() in nrssi_hw_update()) + * entries to -32 (see the clamp_val() in nrssi_hw_update()) */ b43_nrssi_hw_update(dev, 0xFFFF); //FIXME? b43_calc_nrssi_threshold(dev); @@ -1634,13 +1462,13 @@ static s8 b43_phy_estimate_power_out(struct b43_wldev *dev, s8 tssi) switch (phy->type) { case B43_PHYTYPE_A: tmp += 0x80; - tmp = limit_value(tmp, 0x00, 0xFF); + tmp = clamp_val(tmp, 0x00, 0xFF); dbm = phy->tssi2dbm[tmp]; //TODO: There's a FIXME on the specs break; case B43_PHYTYPE_B: case B43_PHYTYPE_G: - tmp = limit_value(tmp, 0x00, 0x3F); + tmp = clamp_val(tmp, 0x00, 0x3F); dbm = phy->tssi2dbm[tmp]; break; default: @@ -1699,8 +1527,8 @@ void b43_put_attenuation_into_ranges(struct b43_wldev *dev, break; } - *_rfatt = limit_value(rfatt, rf_min, rf_max); - *_bbatt = limit_value(bbatt, bb_min, bb_max); + *_rfatt = clamp_val(rfatt, rf_min, rf_max); + *_bbatt = clamp_val(bbatt, bb_min, bb_max); } /* http://bcm-specs.sipsolutions.net/RecalculateTransmissionPower */ @@ -1795,7 +1623,7 @@ void b43_phy_xmitpower(struct b43_wldev *dev) /* Get desired power (in Q5.2) */ desired_pwr = INT_TO_Q52(phy->power_level); /* And limit it. max_pwr already is Q5.2 */ - desired_pwr = limit_value(desired_pwr, 0, max_pwr); + desired_pwr = clamp_val(desired_pwr, 0, max_pwr); if (b43_debug(dev, B43_DBG_XMITPOWER)) { b43dbg(dev->wl, "Current TX power output: " Q52_FMT @@ -1821,10 +1649,8 @@ void b43_phy_xmitpower(struct b43_wldev *dev) bbatt_delta -= 4 * rfatt_delta; /* So do we finally need to adjust something? */ - if ((rfatt_delta == 0) && (bbatt_delta == 0)) { - b43_lo_g_ctl_mark_cur_used(dev); + if ((rfatt_delta == 0) && (bbatt_delta == 0)) return; - } /* Calculate the new attenuation values. */ bbatt = phy->bbatt.att; @@ -1870,7 +1696,6 @@ void b43_phy_xmitpower(struct b43_wldev *dev) b43_radio_lock(dev); b43_set_txpower_g(dev, &phy->bbatt, &phy->rfatt, phy->tx_control); - b43_lo_g_ctl_mark_cur_used(dev); b43_radio_unlock(dev); b43_phy_unlock(dev); break; @@ -1908,7 +1733,7 @@ static inline f = q; i++; } while (delta >= 2); - entry[index] = limit_value(b43_tssi2dbm_ad(m1 * f, 8192), -127, 128); + entry[index] = clamp_val(b43_tssi2dbm_ad(m1 * f, 8192), -127, 128); return 0; } @@ -2007,24 +1832,6 @@ int b43_phy_init(struct b43_wldev *dev) else unsupported = 1; break; - case B43_PHYTYPE_B: - switch (phy->rev) { - case 2: - b43_phy_initb2(dev); - break; - case 4: - b43_phy_initb4(dev); - break; - case 5: - b43_phy_initb5(dev); - break; - case 6: - b43_phy_initb6(dev); - break; - default: - unsupported = 1; - } - break; case B43_PHYTYPE_G: b43_phy_initg(dev); break; @@ -2452,7 +2259,7 @@ void b43_nrssi_hw_update(struct b43_wldev *dev, u16 val) for (i = 0; i < 64; i++) { tmp = b43_nrssi_hw_read(dev, i); tmp -= val; - tmp = limit_value(tmp, -32, 31); + tmp = clamp_val(tmp, -32, 31); b43_nrssi_hw_write(dev, i, tmp); } } @@ -2469,7 +2276,7 @@ void b43_nrssi_mem_update(struct b43_wldev *dev) tmp = (i - delta) * phy->nrssislope; tmp /= 0x10000; tmp += 0x3A; - tmp = limit_value(tmp, 0, 0x3F); + tmp = clamp_val(tmp, 0, 0x3F); phy->nrssi_lt[i] = tmp; } } @@ -2906,7 +2713,7 @@ void b43_calc_nrssi_threshold(struct b43_wldev *dev) } else threshold = phy->nrssi[1] - 5; - threshold = limit_value(threshold, 0, 0x3E); + threshold = clamp_val(threshold, 0, 0x3E); b43_phy_read(dev, 0x0020); /* dummy read */ b43_phy_write(dev, 0x0020, (((u16) threshold) << 8) | 0x001C); @@ -2957,7 +2764,7 @@ void b43_calc_nrssi_threshold(struct b43_wldev *dev) else a += 32; a = a >> 6; - a = limit_value(a, -31, 31); + a = clamp_val(a, -31, 31); b = b * (phy->nrssi[1] - phy->nrssi[0]); b += (phy->nrssi[0] << 6); @@ -2966,7 +2773,7 @@ void b43_calc_nrssi_threshold(struct b43_wldev *dev) else b += 32; b = b >> 6; - b = limit_value(b, -31, 31); + b = clamp_val(b, -31, 31); tmp_u16 = b43_phy_read(dev, 0x048A) & 0xF000; tmp_u16 |= ((u32) b & 0x0000003F); @@ -3069,13 +2876,13 @@ b43_radio_interference_mitigation_enable(struct b43_wldev *dev, int mode) } radio_stacksave(0x0078); tmp = (b43_radio_read16(dev, 0x0078) & 0x001E); - flipped = flip_4bit(tmp); + B43_WARN_ON(tmp > 15); + flipped = bitrev4(tmp); if (flipped < 10 && flipped >= 8) flipped = 7; else if (flipped >= 10) flipped -= 3; - flipped = flip_4bit(flipped); - flipped = (flipped << 1) | 0x0020; + flipped = (bitrev4(flipped) << 1) | 0x0020; b43_radio_write16(dev, 0x0078, flipped); b43_calc_nrssi_threshold(dev); @@ -3708,7 +3515,7 @@ u16 b43_radio_init2050(struct b43_wldev *dev) tmp1 >>= 9; for (i = 0; i < 16; i++) { - radio78 = ((flip_4bit(i) << 1) | 0x20); + radio78 = (bitrev4(i) << 1) | 0x0020; b43_radio_write16(dev, 0x78, radio78); udelay(10); for (j = 0; j < 16; j++) { diff --git a/drivers/net/wireless/b43/phy.h b/drivers/net/wireless/b43/phy.h index 6d165d822175..4aab10903529 100644 --- a/drivers/net/wireless/b43/phy.h +++ b/drivers/net/wireless/b43/phy.h @@ -225,7 +225,6 @@ int b43_phy_init(struct b43_wldev *dev); void b43_set_rx_antenna(struct b43_wldev *dev, int antenna); void b43_phy_xmitpower(struct b43_wldev *dev); -void b43_gphy_dc_lt_init(struct b43_wldev *dev); /* Returns the boolean whether the board has HardwarePowerControl */ bool b43_has_hardware_pctl(struct b43_phy *phy); @@ -252,6 +251,14 @@ struct b43_rfatt_list { u8 max_val; }; +/* Returns true, if the values are the same. */ +static inline bool b43_compare_rfatt(const struct b43_rfatt *a, + const struct b43_rfatt *b) +{ + return ((a->att == b->att) && + (a->with_padmix == b->with_padmix)); +} + /* Baseband Attenuation */ struct b43_bbatt { u8 att; /* Attenuation value */ @@ -265,6 +272,13 @@ struct b43_bbatt_list { u8 max_val; }; +/* Returns true, if the values are the same. */ +static inline bool b43_compare_bbatt(const struct b43_bbatt *a, + const struct b43_bbatt *b) +{ + return (a->att == b->att); +} + /* tx_control bits. */ #define B43_TXCTL_PA3DB 0x40 /* PA Gain 3dB */ #define B43_TXCTL_PA2DB 0x20 /* PA Gain 2dB */ diff --git a/drivers/net/wireless/b43/pio.c b/drivers/net/wireless/b43/pio.c index fcacafb04346..401591267592 100644 --- a/drivers/net/wireless/b43/pio.c +++ b/drivers/net/wireless/b43/pio.c @@ -446,29 +446,27 @@ static void pio_tx_frame_4byte_queue(struct b43_pio_txpacket *pack, } static int pio_tx_frame(struct b43_pio_txqueue *q, - struct sk_buff *skb, - struct ieee80211_tx_control *ctl) + struct sk_buff *skb) { struct b43_pio_txpacket *pack; struct b43_txhdr txhdr; u16 cookie; int err; unsigned int hdrlen; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); B43_WARN_ON(list_empty(&q->packets_list)); pack = list_entry(q->packets_list.next, struct b43_pio_txpacket, list); - memset(&pack->txstat, 0, sizeof(pack->txstat)); - memcpy(&pack->txstat.control, ctl, sizeof(*ctl)); cookie = generate_cookie(q, pack); hdrlen = b43_txhdr_size(q->dev); err = b43_generate_txhdr(q->dev, (u8 *)&txhdr, skb->data, - skb->len, ctl, cookie); + skb->len, info, cookie); if (err) return err; - if (ctl->flags & IEEE80211_TXCTL_SEND_AFTER_DTIM) { + if (info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM) { /* Tell the firmware about the cookie of the last * mcast frame, so it can clear the more-data bit in it. */ b43_shm_write16(q->dev, B43_SHM_SHARED, @@ -492,17 +490,18 @@ static int pio_tx_frame(struct b43_pio_txqueue *q, return 0; } -int b43_pio_tx(struct b43_wldev *dev, - struct sk_buff *skb, struct ieee80211_tx_control *ctl) +int b43_pio_tx(struct b43_wldev *dev, struct sk_buff *skb) { struct b43_pio_txqueue *q; struct ieee80211_hdr *hdr; unsigned long flags; unsigned int hdrlen, total_len; int err = 0; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); hdr = (struct ieee80211_hdr *)skb->data; - if (ctl->flags & IEEE80211_TXCTL_SEND_AFTER_DTIM) { + + if (info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM) { /* The multicast queue will be sent after the DTIM. */ q = dev->pio.tx_queue_mcast; /* Set the frame More-Data bit. Ucode will clear it @@ -510,7 +509,7 @@ int b43_pio_tx(struct b43_wldev *dev, hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_MOREDATA); } else { /* Decide by priority where to put this frame. */ - q = select_queue_by_priority(dev, ctl->queue); + q = select_queue_by_priority(dev, skb_get_queue_mapping(skb)); } spin_lock_irqsave(&q->lock, flags); @@ -533,7 +532,7 @@ int b43_pio_tx(struct b43_wldev *dev, if (total_len > (q->buffer_size - q->buffer_used)) { /* Not enough memory on the queue. */ err = -EBUSY; - ieee80211_stop_queue(dev->wl->hw, ctl->queue); + ieee80211_stop_queue(dev->wl->hw, skb_get_queue_mapping(skb)); q->stopped = 1; goto out_unlock; } @@ -541,9 +540,9 @@ int b43_pio_tx(struct b43_wldev *dev, /* Assign the queue number to the ring (if not already done before) * so TX status handling can use it. The mac80211-queue to b43-queue * mapping is static, so we don't need to store it per frame. */ - q->queue_prio = ctl->queue; + q->queue_prio = skb_get_queue_mapping(skb); - err = pio_tx_frame(q, skb, ctl); + err = pio_tx_frame(q, skb); if (unlikely(err == -ENOKEY)) { /* Drop this packet, as we don't have the encryption key * anymore and must not transmit it unencrypted. */ @@ -561,7 +560,7 @@ int b43_pio_tx(struct b43_wldev *dev, if (((q->buffer_size - q->buffer_used) < roundup(2 + 2 + 6, 4)) || (q->free_packet_slots == 0)) { /* The queue is full. */ - ieee80211_stop_queue(dev->wl->hw, ctl->queue); + ieee80211_stop_queue(dev->wl->hw, skb_get_queue_mapping(skb)); q->stopped = 1; } @@ -578,6 +577,7 @@ void b43_pio_handle_txstatus(struct b43_wldev *dev, struct b43_pio_txqueue *q; struct b43_pio_txpacket *pack = NULL; unsigned int total_len; + struct ieee80211_tx_info *info; q = parse_cookie(dev, status->cookie, &pack); if (unlikely(!q)) @@ -586,15 +586,17 @@ void b43_pio_handle_txstatus(struct b43_wldev *dev, spin_lock(&q->lock); /* IRQs are already disabled. */ - b43_fill_txstatus_report(&(pack->txstat), status); + info = IEEE80211_SKB_CB(pack->skb); + memset(&info->status, 0, sizeof(info->status)); + + b43_fill_txstatus_report(info, status); total_len = pack->skb->len + b43_txhdr_size(dev); total_len = roundup(total_len, 4); q->buffer_used -= total_len; q->free_packet_slots += 1; - ieee80211_tx_status_irqsafe(dev->wl->hw, pack->skb, - &(pack->txstat)); + ieee80211_tx_status_irqsafe(dev->wl->hw, pack->skb); pack->skb = NULL; list_add(&pack->list, &q->packets_list); @@ -611,18 +613,16 @@ void b43_pio_get_tx_stats(struct b43_wldev *dev, { const int nr_queues = dev->wl->hw->queues; struct b43_pio_txqueue *q; - struct ieee80211_tx_queue_stats_data *data; unsigned long flags; int i; for (i = 0; i < nr_queues; i++) { - data = &(stats->data[i]); q = select_queue_by_priority(dev, i); spin_lock_irqsave(&q->lock, flags); - data->len = B43_PIO_MAX_NR_TXPACKETS - q->free_packet_slots; - data->limit = B43_PIO_MAX_NR_TXPACKETS; - data->count = q->nr_tx_packets; + stats[i].len = B43_PIO_MAX_NR_TXPACKETS - q->free_packet_slots; + stats[i].limit = B43_PIO_MAX_NR_TXPACKETS; + stats[i].count = q->nr_tx_packets; spin_unlock_irqrestore(&q->lock, flags); } } diff --git a/drivers/net/wireless/b43/pio.h b/drivers/net/wireless/b43/pio.h index e2ec676cc9e4..6c174c91ca20 100644 --- a/drivers/net/wireless/b43/pio.h +++ b/drivers/net/wireless/b43/pio.h @@ -62,8 +62,6 @@ struct b43_pio_txpacket { struct b43_pio_txqueue *queue; /* The TX data packet. */ struct sk_buff *skb; - /* The status meta data. */ - struct ieee80211_tx_status txstat; /* Index in the (struct b43_pio_txqueue)->packets array. */ u8 index; @@ -167,8 +165,7 @@ int b43_pio_init(struct b43_wldev *dev); void b43_pio_stop(struct b43_wldev *dev); void b43_pio_free(struct b43_wldev *dev); -int b43_pio_tx(struct b43_wldev *dev, - struct sk_buff *skb, struct ieee80211_tx_control *ctl); +int b43_pio_tx(struct b43_wldev *dev, struct sk_buff *skb); void b43_pio_handle_txstatus(struct b43_wldev *dev, const struct b43_txstatus *status); void b43_pio_get_tx_stats(struct b43_wldev *dev, @@ -193,8 +190,7 @@ static inline void b43_pio_stop(struct b43_wldev *dev) { } static inline int b43_pio_tx(struct b43_wldev *dev, - struct sk_buff *skb, - struct ieee80211_tx_control *ctl) + struct sk_buff *skb) { return 0; } diff --git a/drivers/net/wireless/b43/rfkill.c b/drivers/net/wireless/b43/rfkill.c index 11f53cb1139e..fec5645944a4 100644 --- a/drivers/net/wireless/b43/rfkill.c +++ b/drivers/net/wireless/b43/rfkill.c @@ -43,6 +43,23 @@ static bool b43_is_hw_radio_enabled(struct b43_wldev *dev) return 0; } +/* Update the rfkill state */ +static void b43_rfkill_update_state(struct b43_wldev *dev) +{ + struct b43_rfkill *rfk = &(dev->wl->rfkill); + + if (!dev->radio_hw_enable) { + rfk->rfkill->state = RFKILL_STATE_HARD_BLOCKED; + return; + } + + if (!dev->phy.radio_on) + rfk->rfkill->state = RFKILL_STATE_SOFT_BLOCKED; + else + rfk->rfkill->state = RFKILL_STATE_UNBLOCKED; + +} + /* The poll callback for the hardware button. */ static void b43_rfkill_poll(struct input_polled_dev *poll_dev) { @@ -60,6 +77,7 @@ static void b43_rfkill_poll(struct input_polled_dev *poll_dev) if (unlikely(enabled != dev->radio_hw_enable)) { dev->radio_hw_enable = enabled; report_change = 1; + b43_rfkill_update_state(dev); b43info(wl, "Radio hardware status changed to %s\n", enabled ? "ENABLED" : "DISABLED"); } @@ -88,7 +106,7 @@ static int b43_rfkill_soft_toggle(void *data, enum rfkill_state state) goto out_unlock; err = 0; switch (state) { - case RFKILL_STATE_ON: + case RFKILL_STATE_UNBLOCKED: if (!dev->radio_hw_enable) { /* No luck. We can't toggle the hardware RF-kill * button from software. */ @@ -98,10 +116,13 @@ static int b43_rfkill_soft_toggle(void *data, enum rfkill_state state) if (!dev->phy.radio_on) b43_radio_turn_on(dev); break; - case RFKILL_STATE_OFF: + case RFKILL_STATE_SOFT_BLOCKED: if (dev->phy.radio_on) b43_radio_turn_off(dev, 0); break; + default: + b43warn(wl, "Received unexpected rfkill state %d.\n", state); + break; } out_unlock: mutex_unlock(&wl->mutex); @@ -132,7 +153,7 @@ void b43_rfkill_init(struct b43_wldev *dev) snprintf(rfk->name, sizeof(rfk->name), "b43-%s", wiphy_name(wl->hw->wiphy)); rfk->rfkill->name = rfk->name; - rfk->rfkill->state = RFKILL_STATE_ON; + rfk->rfkill->state = RFKILL_STATE_UNBLOCKED; rfk->rfkill->data = dev; rfk->rfkill->toggle_radio = b43_rfkill_soft_toggle; rfk->rfkill->user_claim_unsupported = 1; diff --git a/drivers/net/wireless/b43/xmit.c b/drivers/net/wireless/b43/xmit.c index 19aefbfb2c93..8d54502222a6 100644 --- a/drivers/net/wireless/b43/xmit.c +++ b/drivers/net/wireless/b43/xmit.c @@ -185,15 +185,15 @@ int b43_generate_txhdr(struct b43_wldev *dev, u8 *_txhdr, const unsigned char *fragment_data, unsigned int fragment_len, - const struct ieee80211_tx_control *txctl, + const struct ieee80211_tx_info *info, u16 cookie) { struct b43_txhdr *txhdr = (struct b43_txhdr *)_txhdr; const struct b43_phy *phy = &dev->phy; const struct ieee80211_hdr *wlhdr = (const struct ieee80211_hdr *)fragment_data; - int use_encryption = (!(txctl->flags & IEEE80211_TXCTL_DO_NOT_ENCRYPT)); - u16 fctl = le16_to_cpu(wlhdr->frame_control); + int use_encryption = (!(info->flags & IEEE80211_TX_CTL_DO_NOT_ENCRYPT)); + __le16 fctl = wlhdr->frame_control; struct ieee80211_rate *fbrate; u8 rate, rate_fb; int rate_ofdm, rate_fb_ofdm; @@ -201,13 +201,14 @@ int b43_generate_txhdr(struct b43_wldev *dev, u32 mac_ctl = 0; u16 phy_ctl = 0; u8 extra_ft = 0; + struct ieee80211_rate *txrate; memset(txhdr, 0, sizeof(*txhdr)); - WARN_ON(!txctl->tx_rate); - rate = txctl->tx_rate ? txctl->tx_rate->hw_value : B43_CCK_RATE_1MB; + txrate = ieee80211_get_tx_rate(dev->wl->hw, info); + rate = txrate ? txrate->hw_value : B43_CCK_RATE_1MB; rate_ofdm = b43_is_ofdm_rate(rate); - fbrate = txctl->alt_retry_rate ? : txctl->tx_rate; + fbrate = ieee80211_get_alt_retry_rate(dev->wl->hw, info) ? : txrate; rate_fb = fbrate->hw_value; rate_fb_ofdm = b43_is_ofdm_rate(rate_fb); @@ -227,15 +228,13 @@ int b43_generate_txhdr(struct b43_wldev *dev, * use the original dur_id field. */ txhdr->dur_fb = wlhdr->duration_id; } else { - txhdr->dur_fb = ieee80211_generic_frame_duration(dev->wl->hw, - txctl->vif, - fragment_len, - fbrate); + txhdr->dur_fb = ieee80211_generic_frame_duration( + dev->wl->hw, info->control.vif, fragment_len, fbrate); } plcp_fragment_len = fragment_len + FCS_LEN; if (use_encryption) { - u8 key_idx = (u16) (txctl->key_idx); + u8 key_idx = info->control.hw_key->hw_key_idx; struct b43_key *key; int wlhdr_len; size_t iv_len; @@ -253,15 +252,15 @@ int b43_generate_txhdr(struct b43_wldev *dev, } /* Hardware appends ICV. */ - plcp_fragment_len += txctl->icv_len; + plcp_fragment_len += info->control.icv_len; key_idx = b43_kidx_to_fw(dev, key_idx); mac_ctl |= (key_idx << B43_TXH_MAC_KEYIDX_SHIFT) & B43_TXH_MAC_KEYIDX; mac_ctl |= (key->algorithm << B43_TXH_MAC_KEYALG_SHIFT) & B43_TXH_MAC_KEYALG; - wlhdr_len = ieee80211_get_hdrlen(fctl); - iv_len = min((size_t) txctl->iv_len, + wlhdr_len = ieee80211_hdrlen(fctl); + iv_len = min((size_t) info->control.iv_len, ARRAY_SIZE(txhdr->iv)); memcpy(txhdr->iv, ((u8 *) wlhdr) + wlhdr_len, iv_len); } @@ -292,10 +291,10 @@ int b43_generate_txhdr(struct b43_wldev *dev, phy_ctl |= B43_TXH_PHY_ENC_OFDM; else phy_ctl |= B43_TXH_PHY_ENC_CCK; - if (txctl->flags & IEEE80211_TXCTL_SHORT_PREAMBLE) + if (info->flags & IEEE80211_TX_CTL_SHORT_PREAMBLE) phy_ctl |= B43_TXH_PHY_SHORTPRMBL; - switch (b43_ieee80211_antenna_sanitize(dev, txctl->antenna_sel_tx)) { + switch (b43_ieee80211_antenna_sanitize(dev, info->antenna_sel_tx)) { case 0: /* Default */ phy_ctl |= B43_TXH_PHY_ANT01AUTO; break; @@ -316,34 +315,36 @@ int b43_generate_txhdr(struct b43_wldev *dev, } /* MAC control */ - if (!(txctl->flags & IEEE80211_TXCTL_NO_ACK)) + if (!(info->flags & IEEE80211_TX_CTL_NO_ACK)) mac_ctl |= B43_TXH_MAC_ACK; - if (!(((fctl & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_CTL) && - ((fctl & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_PSPOLL))) + /* use hardware sequence counter as the non-TID counter */ + if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) mac_ctl |= B43_TXH_MAC_HWSEQ; - if (txctl->flags & IEEE80211_TXCTL_FIRST_FRAGMENT) + if (info->flags & IEEE80211_TX_CTL_FIRST_FRAGMENT) mac_ctl |= B43_TXH_MAC_STMSDU; if (phy->type == B43_PHYTYPE_A) mac_ctl |= B43_TXH_MAC_5GHZ; - if (txctl->flags & IEEE80211_TXCTL_LONG_RETRY_LIMIT) + if (info->flags & IEEE80211_TX_CTL_LONG_RETRY_LIMIT) mac_ctl |= B43_TXH_MAC_LONGFRAME; /* Generate the RTS or CTS-to-self frame */ - if ((txctl->flags & IEEE80211_TXCTL_USE_RTS_CTS) || - (txctl->flags & IEEE80211_TXCTL_USE_CTS_PROTECT)) { + if ((info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) || + (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT)) { unsigned int len; struct ieee80211_hdr *hdr; int rts_rate, rts_rate_fb; int rts_rate_ofdm, rts_rate_fb_ofdm; struct b43_plcp_hdr6 *plcp; + struct ieee80211_rate *rts_cts_rate; - WARN_ON(!txctl->rts_cts_rate); - rts_rate = txctl->rts_cts_rate ? txctl->rts_cts_rate->hw_value : B43_CCK_RATE_1MB; + rts_cts_rate = ieee80211_get_rts_cts_rate(dev->wl->hw, info); + + rts_rate = rts_cts_rate ? rts_cts_rate->hw_value : B43_CCK_RATE_1MB; rts_rate_ofdm = b43_is_ofdm_rate(rts_rate); rts_rate_fb = b43_calc_fallback_rate(rts_rate); rts_rate_fb_ofdm = b43_is_ofdm_rate(rts_rate_fb); - if (txctl->flags & IEEE80211_TXCTL_USE_CTS_PROTECT) { + if (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT) { struct ieee80211_cts *cts; if (b43_is_old_txhdr_format(dev)) { @@ -353,9 +354,9 @@ int b43_generate_txhdr(struct b43_wldev *dev, cts = (struct ieee80211_cts *) (txhdr->new_format.rts_frame); } - ieee80211_ctstoself_get(dev->wl->hw, txctl->vif, + ieee80211_ctstoself_get(dev->wl->hw, info->control.vif, fragment_data, fragment_len, - txctl, cts); + info, cts); mac_ctl |= B43_TXH_MAC_SENDCTS; len = sizeof(struct ieee80211_cts); } else { @@ -368,9 +369,9 @@ int b43_generate_txhdr(struct b43_wldev *dev, rts = (struct ieee80211_rts *) (txhdr->new_format.rts_frame); } - ieee80211_rts_get(dev->wl->hw, txctl->vif, + ieee80211_rts_get(dev->wl->hw, info->control.vif, fragment_data, fragment_len, - txctl, rts); + info, rts); mac_ctl |= B43_TXH_MAC_SENDRTS; len = sizeof(struct ieee80211_rts); } @@ -508,7 +509,7 @@ void b43_rx(struct b43_wldev *dev, struct sk_buff *skb, const void *_rxhdr) struct b43_plcp_hdr6 *plcp; struct ieee80211_hdr *wlhdr; const struct b43_rxhdr_fw4 *rxhdr = _rxhdr; - u16 fctl; + __le16 fctl; u16 phystat0, phystat3, chanstat, mactime; u32 macstat; u16 chanid; @@ -548,7 +549,7 @@ void b43_rx(struct b43_wldev *dev, struct sk_buff *skb, const void *_rxhdr) goto drop; } wlhdr = (struct ieee80211_hdr *)(skb->data); - fctl = le16_to_cpu(wlhdr->frame_control); + fctl = wlhdr->frame_control; if (macstat & B43_RX_MAC_DEC) { unsigned int keyidx; @@ -563,7 +564,7 @@ void b43_rx(struct b43_wldev *dev, struct sk_buff *skb, const void *_rxhdr) B43_WARN_ON(keyidx >= dev->max_nr_keys); if (dev->key[keyidx].algorithm != B43_SEC_ALGO_NONE) { - wlhdr_len = ieee80211_get_hdrlen(fctl); + wlhdr_len = ieee80211_hdrlen(fctl); if (unlikely(skb->len < (wlhdr_len + 3))) { b43dbg(dev->wl, "RX: Packet size underrun (3)\n"); @@ -581,12 +582,11 @@ void b43_rx(struct b43_wldev *dev, struct sk_buff *skb, const void *_rxhdr) // and also find out what the maximum possible value is. // Fill status.ssi and status.signal fields. } else { - status.ssi = b43_rssi_postprocess(dev, rxhdr->jssi, + status.signal = b43_rssi_postprocess(dev, rxhdr->jssi, (phystat0 & B43_RX_PHYST0_OFDM), (phystat0 & B43_RX_PHYST0_GAINCTL), (phystat3 & B43_RX_PHYST3_TRSTATE)); - /* the next line looks wrong, but is what mac80211 wants */ - status.signal = (rxhdr->jssi * 100) / B43_RX_MAX_SSI; + status.qual = (rxhdr->jssi * 100) / B43_RX_MAX_SSI; } if (phystat0 & B43_RX_PHYST0_OFDM) @@ -604,9 +604,7 @@ void b43_rx(struct b43_wldev *dev, struct sk_buff *skb, const void *_rxhdr) * of timestamp, i.e. about 65 milliseconds after the PHY received * the first symbol. */ - if (((fctl & (IEEE80211_FCTL_FTYPE | IEEE80211_FCTL_STYPE)) - == (IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_BEACON)) || - dev->wl->radiotap_enabled) { + if (ieee80211_is_beacon(fctl) || dev->wl->radiotap_enabled) { u16 low_mactime_now; b43_tsf_read(dev, &status.mactime); @@ -685,27 +683,27 @@ void b43_handle_txstatus(struct b43_wldev *dev, /* Fill out the mac80211 TXstatus report based on the b43-specific * txstatus report data. This returns a boolean whether the frame was * successfully transmitted. */ -bool b43_fill_txstatus_report(struct ieee80211_tx_status *report, +bool b43_fill_txstatus_report(struct ieee80211_tx_info *report, const struct b43_txstatus *status) { bool frame_success = 1; if (status->acked) { /* The frame was ACKed. */ - report->flags |= IEEE80211_TX_STATUS_ACK; + report->flags |= IEEE80211_TX_STAT_ACK; } else { /* The frame was not ACKed... */ - if (!(report->control.flags & IEEE80211_TXCTL_NO_ACK)) { + if (!(report->flags & IEEE80211_TX_CTL_NO_ACK)) { /* ...but we expected an ACK. */ frame_success = 0; - report->excessive_retries = 1; + report->status.excessive_retries = 1; } } if (status->frame_count == 0) { /* The frame was not transmitted at all. */ - report->retry_count = 0; + report->status.retry_count = 0; } else - report->retry_count = status->frame_count - 1; + report->status.retry_count = status->frame_count - 1; return frame_success; } diff --git a/drivers/net/wireless/b43/xmit.h b/drivers/net/wireless/b43/xmit.h index b05f44e0d626..0215faf47541 100644 --- a/drivers/net/wireless/b43/xmit.h +++ b/drivers/net/wireless/b43/xmit.h @@ -178,7 +178,7 @@ int b43_generate_txhdr(struct b43_wldev *dev, u8 * txhdr, const unsigned char *fragment_data, unsigned int fragment_len, - const struct ieee80211_tx_control *txctl, u16 cookie); + const struct ieee80211_tx_info *txctl, u16 cookie); /* Transmit Status */ struct b43_txstatus { @@ -294,7 +294,7 @@ void b43_rx(struct b43_wldev *dev, struct sk_buff *skb, const void *_rxhdr); void b43_handle_txstatus(struct b43_wldev *dev, const struct b43_txstatus *status); -bool b43_fill_txstatus_report(struct ieee80211_tx_status *report, +bool b43_fill_txstatus_report(struct ieee80211_tx_info *report, const struct b43_txstatus *status); void b43_tx_suspend(struct b43_wldev *dev); diff --git a/drivers/net/wireless/b43legacy/b43legacy.h b/drivers/net/wireless/b43legacy/b43legacy.h index ded3cd31b3df..c40078e1fff9 100644 --- a/drivers/net/wireless/b43legacy/b43legacy.h +++ b/drivers/net/wireless/b43legacy/b43legacy.h @@ -823,23 +823,6 @@ void b43legacydbg(struct b43legacy_wl *wl, const char *fmt, ...) # define b43legacydbg(wl, fmt...) do { /* nothing */ } while (0) #endif /* DEBUG */ - -/** Limit a value between two limits */ -#ifdef limit_value -# undef limit_value -#endif -#define limit_value(value, min, max) \ - ({ \ - typeof(value) __value = (value); \ - typeof(value) __min = (min); \ - typeof(value) __max = (max); \ - if (__value < __min) \ - __value = __min; \ - else if (__value > __max) \ - __value = __max; \ - __value; \ - }) - /* Macros for printing a value in Q5.2 format */ #define Q52_FMT "%u.%u" #define Q52_ARG(q52) ((q52) / 4), (((q52) & 3) * 100 / 4) diff --git a/drivers/net/wireless/b43legacy/dma.c b/drivers/net/wireless/b43legacy/dma.c index 93ddc1cbcc8b..fb6819e40f38 100644 --- a/drivers/net/wireless/b43legacy/dma.c +++ b/drivers/net/wireless/b43legacy/dma.c @@ -393,13 +393,13 @@ dma_addr_t map_descbuffer(struct b43legacy_dmaring *ring, dma_addr_t dmaaddr; if (tx) - dmaaddr = dma_map_single(ring->dev->dev->dma_dev, - buf, len, - DMA_TO_DEVICE); + dmaaddr = ssb_dma_map_single(ring->dev->dev, + buf, len, + DMA_TO_DEVICE); else - dmaaddr = dma_map_single(ring->dev->dev->dma_dev, - buf, len, - DMA_FROM_DEVICE); + dmaaddr = ssb_dma_map_single(ring->dev->dev, + buf, len, + DMA_FROM_DEVICE); return dmaaddr; } @@ -411,13 +411,13 @@ void unmap_descbuffer(struct b43legacy_dmaring *ring, int tx) { if (tx) - dma_unmap_single(ring->dev->dev->dma_dev, - addr, len, - DMA_TO_DEVICE); + ssb_dma_unmap_single(ring->dev->dev, + addr, len, + DMA_TO_DEVICE); else - dma_unmap_single(ring->dev->dev->dma_dev, - addr, len, - DMA_FROM_DEVICE); + ssb_dma_unmap_single(ring->dev->dev, + addr, len, + DMA_FROM_DEVICE); } static inline @@ -427,8 +427,8 @@ void sync_descbuffer_for_cpu(struct b43legacy_dmaring *ring, { B43legacy_WARN_ON(ring->tx); - dma_sync_single_for_cpu(ring->dev->dev->dma_dev, - addr, len, DMA_FROM_DEVICE); + ssb_dma_sync_single_for_cpu(ring->dev->dev, + addr, len, DMA_FROM_DEVICE); } static inline @@ -438,8 +438,8 @@ void sync_descbuffer_for_device(struct b43legacy_dmaring *ring, { B43legacy_WARN_ON(ring->tx); - dma_sync_single_for_device(ring->dev->dev->dma_dev, - addr, len, DMA_FROM_DEVICE); + ssb_dma_sync_single_for_device(ring->dev->dev, + addr, len, DMA_FROM_DEVICE); } static inline @@ -458,10 +458,11 @@ void free_descriptor_buffer(struct b43legacy_dmaring *ring, static int alloc_ringmemory(struct b43legacy_dmaring *ring) { - struct device *dma_dev = ring->dev->dev->dma_dev; - - ring->descbase = dma_alloc_coherent(dma_dev, B43legacy_DMA_RINGMEMSIZE, - &(ring->dmabase), GFP_KERNEL); + /* GFP flags must match the flags in free_ringmemory()! */ + ring->descbase = ssb_dma_alloc_consistent(ring->dev->dev, + B43legacy_DMA_RINGMEMSIZE, + &(ring->dmabase), + GFP_KERNEL); if (!ring->descbase) { b43legacyerr(ring->dev->wl, "DMA ringmemory allocation" " failed\n"); @@ -474,10 +475,8 @@ static int alloc_ringmemory(struct b43legacy_dmaring *ring) static void free_ringmemory(struct b43legacy_dmaring *ring) { - struct device *dma_dev = ring->dev->dev->dma_dev; - - dma_free_coherent(dma_dev, B43legacy_DMA_RINGMEMSIZE, - ring->descbase, ring->dmabase); + ssb_dma_free_consistent(ring->dev->dev, B43legacy_DMA_RINGMEMSIZE, + ring->descbase, ring->dmabase, GFP_KERNEL); } /* Reset the RX DMA channel */ @@ -589,7 +588,7 @@ static bool b43legacy_dma_mapping_error(struct b43legacy_dmaring *ring, size_t buffersize, bool dma_to_device) { - if (unlikely(dma_mapping_error(addr))) + if (unlikely(ssb_dma_mapping_error(ring->dev->dev, addr))) return 1; switch (ring->type) { @@ -860,6 +859,18 @@ static u64 supported_dma_mask(struct b43legacy_wldev *dev) return DMA_30BIT_MASK; } +static enum b43legacy_dmatype dma_mask_to_engine_type(u64 dmamask) +{ + if (dmamask == DMA_30BIT_MASK) + return B43legacy_DMA_30BIT; + if (dmamask == DMA_32BIT_MASK) + return B43legacy_DMA_32BIT; + if (dmamask == DMA_64BIT_MASK) + return B43legacy_DMA_64BIT; + B43legacy_WARN_ON(1); + return B43legacy_DMA_30BIT; +} + /* Main initialization function. */ static struct b43legacy_dmaring *b43legacy_setup_dmaring(struct b43legacy_wldev *dev, @@ -894,9 +905,9 @@ struct b43legacy_dmaring *b43legacy_setup_dmaring(struct b43legacy_wldev *dev, goto err_kfree_meta; /* test for ability to dma to txhdr_cache */ - dma_test = dma_map_single(dev->dev->dma_dev, ring->txhdr_cache, - sizeof(struct b43legacy_txhdr_fw3), - DMA_TO_DEVICE); + dma_test = ssb_dma_map_single(dev->dev, ring->txhdr_cache, + sizeof(struct b43legacy_txhdr_fw3), + DMA_TO_DEVICE); if (b43legacy_dma_mapping_error(ring, dma_test, sizeof(struct b43legacy_txhdr_fw3), 1)) { @@ -908,7 +919,7 @@ struct b43legacy_dmaring *b43legacy_setup_dmaring(struct b43legacy_wldev *dev, if (!ring->txhdr_cache) goto err_kfree_meta; - dma_test = dma_map_single(dev->dev->dma_dev, + dma_test = ssb_dma_map_single(dev->dev, ring->txhdr_cache, sizeof(struct b43legacy_txhdr_fw3), DMA_TO_DEVICE); @@ -918,9 +929,9 @@ struct b43legacy_dmaring *b43legacy_setup_dmaring(struct b43legacy_wldev *dev, goto err_kfree_txhdr_cache; } - dma_unmap_single(dev->dev->dma_dev, - dma_test, sizeof(struct b43legacy_txhdr_fw3), - DMA_TO_DEVICE); + ssb_dma_unmap_single(dev->dev, dma_test, + sizeof(struct b43legacy_txhdr_fw3), + DMA_TO_DEVICE); } ring->nr_slots = nr_slots; @@ -1019,6 +1030,43 @@ void b43legacy_dma_free(struct b43legacy_wldev *dev) dma->tx_ring0 = NULL; } +static int b43legacy_dma_set_mask(struct b43legacy_wldev *dev, u64 mask) +{ + u64 orig_mask = mask; + bool fallback = 0; + int err; + + /* Try to set the DMA mask. If it fails, try falling back to a + * lower mask, as we can always also support a lower one. */ + while (1) { + err = ssb_dma_set_mask(dev->dev, mask); + if (!err) + break; + if (mask == DMA_64BIT_MASK) { + mask = DMA_32BIT_MASK; + fallback = 1; + continue; + } + if (mask == DMA_32BIT_MASK) { + mask = DMA_30BIT_MASK; + fallback = 1; + continue; + } + b43legacyerr(dev->wl, "The machine/kernel does not support " + "the required %u-bit DMA mask\n", + (unsigned int)dma_mask_to_engine_type(orig_mask)); + return -EOPNOTSUPP; + } + if (fallback) { + b43legacyinfo(dev->wl, "DMA mask fallback from %u-bit to %u-" + "bit\n", + (unsigned int)dma_mask_to_engine_type(orig_mask), + (unsigned int)dma_mask_to_engine_type(mask)); + } + + return 0; +} + int b43legacy_dma_init(struct b43legacy_wldev *dev) { struct b43legacy_dma *dma = &dev->dma; @@ -1028,21 +1076,8 @@ int b43legacy_dma_init(struct b43legacy_wldev *dev) enum b43legacy_dmatype type; dmamask = supported_dma_mask(dev); - switch (dmamask) { - default: - B43legacy_WARN_ON(1); - case DMA_30BIT_MASK: - type = B43legacy_DMA_30BIT; - break; - case DMA_32BIT_MASK: - type = B43legacy_DMA_32BIT; - break; - case DMA_64BIT_MASK: - type = B43legacy_DMA_64BIT; - break; - } - - err = ssb_dma_set_mask(dev->dev, dmamask); + type = dma_mask_to_engine_type(dmamask); + err = b43legacy_dma_set_mask(dev, dmamask); if (err) { #ifdef CONFIG_B43LEGACY_PIO b43legacywarn(dev->wl, "DMA for this device not supported. " @@ -1205,10 +1240,10 @@ struct b43legacy_dmaring *parse_cookie(struct b43legacy_wldev *dev, } static int dma_tx_fragment(struct b43legacy_dmaring *ring, - struct sk_buff *skb, - struct ieee80211_tx_control *ctl) + struct sk_buff *skb) { const struct b43legacy_dma_ops *ops = ring->ops; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); u8 *header; int slot, old_top_slot, old_used_slots; int err; @@ -1231,7 +1266,7 @@ static int dma_tx_fragment(struct b43legacy_dmaring *ring, header = &(ring->txhdr_cache[slot * sizeof( struct b43legacy_txhdr_fw3)]); err = b43legacy_generate_txhdr(ring->dev, header, - skb->data, skb->len, ctl, + skb->data, skb->len, info, generate_cookie(ring, slot)); if (unlikely(err)) { ring->current_slot = old_top_slot; @@ -1255,7 +1290,6 @@ static int dma_tx_fragment(struct b43legacy_dmaring *ring, desc = ops->idx2desc(ring, slot, &meta); memset(meta, 0, sizeof(*meta)); - memcpy(&meta->txstat.control, ctl, sizeof(*ctl)); meta->skb = skb; meta->is_last_fragment = 1; @@ -1323,14 +1357,13 @@ int should_inject_overflow(struct b43legacy_dmaring *ring) } int b43legacy_dma_tx(struct b43legacy_wldev *dev, - struct sk_buff *skb, - struct ieee80211_tx_control *ctl) + struct sk_buff *skb) { struct b43legacy_dmaring *ring; int err = 0; unsigned long flags; - ring = priority_to_txring(dev, ctl->queue); + ring = priority_to_txring(dev, skb_get_queue_mapping(skb)); spin_lock_irqsave(&ring->lock, flags); B43legacy_WARN_ON(!ring->tx); if (unlikely(free_slots(ring) < SLOTS_PER_PACKET)) { @@ -1343,7 +1376,7 @@ int b43legacy_dma_tx(struct b43legacy_wldev *dev, * That would be a mac80211 bug. */ B43legacy_BUG_ON(ring->stopped); - err = dma_tx_fragment(ring, skb, ctl); + err = dma_tx_fragment(ring, skb); if (unlikely(err == -ENOKEY)) { /* Drop this packet, as we don't have the encryption key * anymore and must not transmit it unencrypted. */ @@ -1401,26 +1434,29 @@ void b43legacy_dma_handle_txstatus(struct b43legacy_wldev *dev, 1); if (meta->is_last_fragment) { - B43legacy_WARN_ON(!meta->skb); + struct ieee80211_tx_info *info; + BUG_ON(!meta->skb); + info = IEEE80211_SKB_CB(meta->skb); /* Call back to inform the ieee80211 subsystem about the * status of the transmission. * Some fields of txstat are already filled in dma_tx(). */ + + memset(&info->status, 0, sizeof(info->status)); + if (status->acked) { - meta->txstat.flags |= IEEE80211_TX_STATUS_ACK; + info->flags |= IEEE80211_TX_STAT_ACK; } else { - if (!(meta->txstat.control.flags - & IEEE80211_TXCTL_NO_ACK)) - meta->txstat.excessive_retries = 1; + if (!(info->flags & IEEE80211_TX_CTL_NO_ACK)) + info->status.excessive_retries = 1; } if (status->frame_count == 0) { /* The frame was not transmitted at all. */ - meta->txstat.retry_count = 0; + info->status.retry_count = 0; } else - meta->txstat.retry_count = status->frame_count + info->status.retry_count = status->frame_count - 1; - ieee80211_tx_status_irqsafe(dev->wl->hw, meta->skb, - &(meta->txstat)); + ieee80211_tx_status_irqsafe(dev->wl->hw, meta->skb); /* skb is freed by ieee80211_tx_status_irqsafe() */ meta->skb = NULL; } else { @@ -1455,18 +1491,16 @@ void b43legacy_dma_get_tx_stats(struct b43legacy_wldev *dev, { const int nr_queues = dev->wl->hw->queues; struct b43legacy_dmaring *ring; - struct ieee80211_tx_queue_stats_data *data; unsigned long flags; int i; for (i = 0; i < nr_queues; i++) { - data = &(stats->data[i]); ring = priority_to_txring(dev, i); spin_lock_irqsave(&ring->lock, flags); - data->len = ring->used_slots / SLOTS_PER_PACKET; - data->limit = ring->nr_slots / SLOTS_PER_PACKET; - data->count = ring->nr_tx_packets; + stats[i].len = ring->used_slots / SLOTS_PER_PACKET; + stats[i].limit = ring->nr_slots / SLOTS_PER_PACKET; + stats[i].count = ring->nr_tx_packets; spin_unlock_irqrestore(&ring->lock, flags); } } diff --git a/drivers/net/wireless/b43legacy/dma.h b/drivers/net/wireless/b43legacy/dma.h index 2dd488c5be2d..2f186003c31e 100644 --- a/drivers/net/wireless/b43legacy/dma.h +++ b/drivers/net/wireless/b43legacy/dma.h @@ -195,7 +195,6 @@ struct b43legacy_dmadesc_meta { dma_addr_t dmaaddr; /* ieee80211 TX status. Only used once per 802.11 frag. */ bool is_last_fragment; - struct ieee80211_tx_status txstat; }; struct b43legacy_dmaring; @@ -297,8 +296,7 @@ void b43legacy_dma_get_tx_stats(struct b43legacy_wldev *dev, struct ieee80211_tx_queue_stats *stats); int b43legacy_dma_tx(struct b43legacy_wldev *dev, - struct sk_buff *skb, - struct ieee80211_tx_control *ctl); + struct sk_buff *skb); void b43legacy_dma_handle_txstatus(struct b43legacy_wldev *dev, const struct b43legacy_txstatus *status); @@ -323,8 +321,7 @@ void b43legacy_dma_get_tx_stats(struct b43legacy_wldev *dev, } static inline int b43legacy_dma_tx(struct b43legacy_wldev *dev, - struct sk_buff *skb, - struct ieee80211_tx_control *ctl) + struct sk_buff *skb) { return 0; } diff --git a/drivers/net/wireless/b43legacy/main.c b/drivers/net/wireless/b43legacy/main.c index 3e612d0a13e8..a1b8bf3ee732 100644 --- a/drivers/net/wireless/b43legacy/main.c +++ b/drivers/net/wireless/b43legacy/main.c @@ -846,10 +846,10 @@ static void handle_irq_noise(struct b43legacy_wldev *dev) /* Get the noise samples. */ B43legacy_WARN_ON(dev->noisecalc.nr_samples >= 8); i = dev->noisecalc.nr_samples; - noise[0] = limit_value(noise[0], 0, ARRAY_SIZE(phy->nrssi_lt) - 1); - noise[1] = limit_value(noise[1], 0, ARRAY_SIZE(phy->nrssi_lt) - 1); - noise[2] = limit_value(noise[2], 0, ARRAY_SIZE(phy->nrssi_lt) - 1); - noise[3] = limit_value(noise[3], 0, ARRAY_SIZE(phy->nrssi_lt) - 1); + noise[0] = clamp_val(noise[0], 0, ARRAY_SIZE(phy->nrssi_lt) - 1); + noise[1] = clamp_val(noise[1], 0, ARRAY_SIZE(phy->nrssi_lt) - 1); + noise[2] = clamp_val(noise[2], 0, ARRAY_SIZE(phy->nrssi_lt) - 1); + noise[3] = clamp_val(noise[3], 0, ARRAY_SIZE(phy->nrssi_lt) - 1); dev->noisecalc.samples[i][0] = phy->nrssi_lt[noise[0]]; dev->noisecalc.samples[i][1] = phy->nrssi_lt[noise[1]]; dev->noisecalc.samples[i][2] = phy->nrssi_lt[noise[2]]; @@ -1138,14 +1138,22 @@ static void b43legacy_write_probe_resp_template(struct b43legacy_wldev *dev, /* 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, - struct sk_buff *beacon) +static void b43legacy_update_templates(struct b43legacy_wl *wl) { + struct sk_buff *beacon; /* This is the top half of the ansynchronous beacon update. The bottom * half is the beacon IRQ. Beacon update must be asynchronous to avoid * sending an invalid beacon. This can happen for example, if the * firmware transmits a beacon while we are updating it. */ + /* We could modify the existing beacon and set the aid bit in the TIM + * field, but that would probably require resizing and moving of data + * within the beacon template. Simply request a new beacon and let + * mac80211 do the hard work. */ + beacon = ieee80211_beacon_get(wl->hw, wl->vif); + if (unlikely(!beacon)) + return; + if (wl->current_beacon) dev_kfree_skb_any(wl->current_beacon); wl->current_beacon = beacon; @@ -2358,8 +2366,7 @@ static int b43legacy_rng_init(struct b43legacy_wl *wl) } static int b43legacy_op_tx(struct ieee80211_hw *hw, - struct sk_buff *skb, - struct ieee80211_tx_control *ctl) + struct sk_buff *skb) { struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw); struct b43legacy_wldev *dev = wl->current_dev; @@ -2373,10 +2380,10 @@ static int b43legacy_op_tx(struct ieee80211_hw *hw, /* DMA-TX is done without a global lock. */ if (b43legacy_using_pio(dev)) { spin_lock_irqsave(&wl->irq_lock, flags); - err = b43legacy_pio_tx(dev, skb, ctl); + err = b43legacy_pio_tx(dev, skb); spin_unlock_irqrestore(&wl->irq_lock, flags); } else - err = b43legacy_dma_tx(dev, skb, ctl); + err = b43legacy_dma_tx(dev, skb); out: if (unlikely(err)) { /* Drop the packet. */ @@ -2385,8 +2392,7 @@ out: return NETDEV_TX_OK; } -static int b43legacy_op_conf_tx(struct ieee80211_hw *hw, - int queue, +static int b43legacy_op_conf_tx(struct ieee80211_hw *hw, u16 queue, const struct ieee80211_tx_queue_params *params) { return 0; @@ -2729,10 +2735,13 @@ static int b43legacy_op_config_interface(struct ieee80211_hw *hw, memset(wl->bssid, 0, ETH_ALEN); if (b43legacy_status(dev) >= B43legacy_STAT_INITIALIZED) { if (b43legacy_is_mode(wl, IEEE80211_IF_TYPE_AP)) { - B43legacy_WARN_ON(conf->type != IEEE80211_IF_TYPE_AP); + B43legacy_WARN_ON(vif->type != IEEE80211_IF_TYPE_AP); b43legacy_set_ssid(dev, conf->ssid, conf->ssid_len); - if (conf->beacon) - b43legacy_update_templates(wl, conf->beacon); + if (conf->changed & IEEE80211_IFCC_BEACON) + b43legacy_update_templates(wl); + } else if (b43legacy_is_mode(wl, IEEE80211_IF_TYPE_IBSS)) { + if (conf->changed & IEEE80211_IFCC_BEACON) + b43legacy_update_templates(wl); } b43legacy_write_mac_bssid_templates(dev); } @@ -2797,7 +2806,6 @@ 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); - ieee80211_start_queues(dev->wl->hw); /* Start maintenance work */ b43legacy_periodic_tasks_setup(dev); @@ -3399,32 +3407,10 @@ static int b43legacy_op_beacon_set_tim(struct ieee80211_hw *hw, int aid, int set) { struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw); - struct sk_buff *beacon; - unsigned long flags; - - /* We could modify the existing beacon and set the aid bit in the TIM - * field, but that would probably require resizing and moving of data - * within the beacon template. Simply request a new beacon and let - * mac80211 do the hard work. */ - beacon = ieee80211_beacon_get(hw, wl->vif, NULL); - if (unlikely(!beacon)) - return -ENOMEM; - spin_lock_irqsave(&wl->irq_lock, flags); - b43legacy_update_templates(wl, beacon); - spin_unlock_irqrestore(&wl->irq_lock, flags); - - return 0; -} - -static int b43legacy_op_ibss_beacon_update(struct ieee80211_hw *hw, - struct sk_buff *beacon, - struct ieee80211_tx_control *ctl) -{ - struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw); unsigned long flags; spin_lock_irqsave(&wl->irq_lock, flags); - b43legacy_update_templates(wl, beacon); + b43legacy_update_templates(wl); spin_unlock_irqrestore(&wl->irq_lock, flags); return 0; @@ -3444,7 +3430,6 @@ static const struct ieee80211_ops b43legacy_hw_ops = { .stop = b43legacy_op_stop, .set_retry_limit = b43legacy_op_set_retry_limit, .set_tim = b43legacy_op_beacon_set_tim, - .beacon_update = b43legacy_op_ibss_beacon_update, }; /* Hard-reset the chip. Do not call this directly. @@ -3718,10 +3703,9 @@ static int b43legacy_wireless_init(struct ssb_device *dev) /* fill hw info */ hw->flags = IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE | - IEEE80211_HW_RX_INCLUDES_FCS; - hw->max_signal = 100; - hw->max_rssi = -110; - hw->max_noise = -110; + IEEE80211_HW_RX_INCLUDES_FCS | + IEEE80211_HW_SIGNAL_DBM | + IEEE80211_HW_NOISE_DBM; hw->queues = 1; /* FIXME: hardware has more queues */ SET_IEEE80211_DEV(hw, dev->dev); if (is_valid_ether_addr(sprom->et1mac)) diff --git a/drivers/net/wireless/b43legacy/phy.c b/drivers/net/wireless/b43legacy/phy.c index 8e5c09b81871..768cccb9b1ba 100644 --- a/drivers/net/wireless/b43legacy/phy.c +++ b/drivers/net/wireless/b43legacy/phy.c @@ -1088,7 +1088,7 @@ static void b43legacy_phy_initg(struct b43legacy_wldev *dev) * the value 0x7FFFFFFF here. I think that is some weird * compiler optimization in the original driver. * Essentially, what we do here is resetting all NRSSI LT - * entries to -32 (see the limit_value() in nrssi_hw_update()) + * entries to -32 (see the clamp_val() in nrssi_hw_update()) */ b43legacy_nrssi_hw_update(dev, 0xFFFF); b43legacy_calc_nrssi_threshold(dev); @@ -1756,7 +1756,7 @@ static s8 b43legacy_phy_estimate_power_out(struct b43legacy_wldev *dev, s8 tssi) switch (phy->type) { case B43legacy_PHYTYPE_B: case B43legacy_PHYTYPE_G: - tmp = limit_value(tmp, 0x00, 0x3F); + tmp = clamp_val(tmp, 0x00, 0x3F); dbm = phy->tssi2dbm[tmp]; break; default: @@ -1859,7 +1859,7 @@ void b43legacy_phy_xmitpower(struct b43legacy_wldev *dev) /* find the desired power in Q5.2 - power_level is in dBm * and limit it - max_pwr is already in Q5.2 */ - desired_pwr = limit_value(phy->power_level << 2, 0, max_pwr); + desired_pwr = clamp_val(phy->power_level << 2, 0, max_pwr); if (b43legacy_debug(dev, B43legacy_DBG_XMITPOWER)) b43legacydbg(dev->wl, "Current TX power output: " Q52_FMT " dBm, Desired TX power output: " Q52_FMT @@ -1905,7 +1905,7 @@ void b43legacy_phy_xmitpower(struct b43legacy_wldev *dev) radio_attenuation++; } } - baseband_attenuation = limit_value(baseband_attenuation, 0, 11); + baseband_attenuation = clamp_val(baseband_attenuation, 0, 11); txpower = phy->txctl1; if ((phy->radio_ver == 0x2050) && (phy->radio_rev == 2)) { @@ -1933,8 +1933,8 @@ void b43legacy_phy_xmitpower(struct b43legacy_wldev *dev) } /* Save the control values */ phy->txctl1 = txpower; - baseband_attenuation = limit_value(baseband_attenuation, 0, 11); - radio_attenuation = limit_value(radio_attenuation, 0, 9); + baseband_attenuation = clamp_val(baseband_attenuation, 0, 11); + radio_attenuation = clamp_val(radio_attenuation, 0, 9); phy->rfatt = radio_attenuation; phy->bbatt = baseband_attenuation; @@ -1979,7 +1979,7 @@ s8 b43legacy_tssi2dbm_entry(s8 entry [], u8 index, s16 pab0, s16 pab1, s16 pab2) f = q; i++; } while (delta >= 2); - entry[index] = limit_value(b43legacy_tssi2dbm_ad(m1 * f, 8192), + entry[index] = clamp_val(b43legacy_tssi2dbm_ad(m1 * f, 8192), -127, 128); return 0; } diff --git a/drivers/net/wireless/b43legacy/pio.c b/drivers/net/wireless/b43legacy/pio.c index bcdd54eb2edb..a86c7647fa2d 100644 --- a/drivers/net/wireless/b43legacy/pio.c +++ b/drivers/net/wireless/b43legacy/pio.c @@ -196,7 +196,7 @@ static int pio_tx_write_fragment(struct b43legacy_pioqueue *queue, B43legacy_WARN_ON(skb_shinfo(skb)->nr_frags != 0); err = b43legacy_generate_txhdr(queue->dev, txhdr, skb->data, skb->len, - &packet->txstat.control, + IEEE80211_SKB_CB(skb), generate_cookie(queue, packet)); if (err) return err; @@ -463,8 +463,7 @@ err_destroy0: } int b43legacy_pio_tx(struct b43legacy_wldev *dev, - struct sk_buff *skb, - struct ieee80211_tx_control *ctl) + struct sk_buff *skb) { struct b43legacy_pioqueue *queue = dev->pio.queue1; struct b43legacy_pio_txpacket *packet; @@ -476,9 +475,6 @@ int b43legacy_pio_tx(struct b43legacy_wldev *dev, list); packet->skb = skb; - memset(&packet->txstat, 0, sizeof(packet->txstat)); - memcpy(&packet->txstat.control, ctl, sizeof(*ctl)); - list_move_tail(&packet->list, &queue->txqueue); queue->nr_txfree--; queue->nr_tx_packets++; @@ -494,6 +490,7 @@ void b43legacy_pio_handle_txstatus(struct b43legacy_wldev *dev, { struct b43legacy_pioqueue *queue; struct b43legacy_pio_txpacket *packet; + struct ieee80211_tx_info *info; queue = parse_cookie(dev, status->cookie, &packet); B43legacy_WARN_ON(!queue); @@ -505,11 +502,13 @@ void b43legacy_pio_handle_txstatus(struct b43legacy_wldev *dev, queue->tx_devq_used -= (packet->skb->len + sizeof(struct b43legacy_txhdr_fw3)); + info = IEEE80211_SKB_CB(packet->skb); + memset(&info->status, 0, sizeof(info->status)); + if (status->acked) - packet->txstat.flags |= IEEE80211_TX_STATUS_ACK; - packet->txstat.retry_count = status->frame_count - 1; - ieee80211_tx_status_irqsafe(dev->wl->hw, packet->skb, - &(packet->txstat)); + info->flags |= IEEE80211_TX_STAT_ACK; + info->status.retry_count = status->frame_count - 1; + ieee80211_tx_status_irqsafe(dev->wl->hw, packet->skb); packet->skb = NULL; free_txpacket(packet, 1); @@ -525,13 +524,11 @@ void b43legacy_pio_get_tx_stats(struct b43legacy_wldev *dev, { struct b43legacy_pio *pio = &dev->pio; struct b43legacy_pioqueue *queue; - struct ieee80211_tx_queue_stats_data *data; queue = pio->queue1; - data = &(stats->data[0]); - data->len = B43legacy_PIO_MAXTXPACKETS - queue->nr_txfree; - data->limit = B43legacy_PIO_MAXTXPACKETS; - data->count = queue->nr_tx_packets; + stats[0].len = B43legacy_PIO_MAXTXPACKETS - queue->nr_txfree; + stats[0].limit = B43legacy_PIO_MAXTXPACKETS; + stats[0].count = queue->nr_tx_packets; } static void pio_rx_error(struct b43legacy_pioqueue *queue, diff --git a/drivers/net/wireless/b43legacy/pio.h b/drivers/net/wireless/b43legacy/pio.h index 5bfed0c40030..464fec05a06d 100644 --- a/drivers/net/wireless/b43legacy/pio.h +++ b/drivers/net/wireless/b43legacy/pio.h @@ -41,7 +41,6 @@ struct b43legacy_xmitstatus; struct b43legacy_pio_txpacket { struct b43legacy_pioqueue *queue; struct sk_buff *skb; - struct ieee80211_tx_status txstat; struct list_head list; }; @@ -104,8 +103,7 @@ int b43legacy_pio_init(struct b43legacy_wldev *dev); void b43legacy_pio_free(struct b43legacy_wldev *dev); int b43legacy_pio_tx(struct b43legacy_wldev *dev, - struct sk_buff *skb, - struct ieee80211_tx_control *ctl); + struct sk_buff *skb); void b43legacy_pio_handle_txstatus(struct b43legacy_wldev *dev, const struct b43legacy_txstatus *status); void b43legacy_pio_get_tx_stats(struct b43legacy_wldev *dev, @@ -132,8 +130,7 @@ void b43legacy_pio_free(struct b43legacy_wldev *dev) } static inline int b43legacy_pio_tx(struct b43legacy_wldev *dev, - struct sk_buff *skb, - struct ieee80211_tx_control *ctl) + struct sk_buff *skb) { return 0; } diff --git a/drivers/net/wireless/b43legacy/radio.c b/drivers/net/wireless/b43legacy/radio.c index 955832e8654f..2df545cfad14 100644 --- a/drivers/net/wireless/b43legacy/radio.c +++ b/drivers/net/wireless/b43legacy/radio.c @@ -357,7 +357,7 @@ void b43legacy_nrssi_hw_update(struct b43legacy_wldev *dev, u16 val) for (i = 0; i < 64; i++) { tmp = b43legacy_nrssi_hw_read(dev, i); tmp -= val; - tmp = limit_value(tmp, -32, 31); + tmp = clamp_val(tmp, -32, 31); b43legacy_nrssi_hw_write(dev, i, tmp); } } @@ -375,7 +375,7 @@ void b43legacy_nrssi_mem_update(struct b43legacy_wldev *dev) tmp = (i - delta) * phy->nrssislope; tmp /= 0x10000; tmp += 0x3A; - tmp = limit_value(tmp, 0, 0x3F); + tmp = clamp_val(tmp, 0, 0x3F); phy->nrssi_lt[i] = tmp; } } @@ -839,7 +839,7 @@ void b43legacy_calc_nrssi_threshold(struct b43legacy_wldev *dev) } else threshold = phy->nrssi[1] - 5; - threshold = limit_value(threshold, 0, 0x3E); + threshold = clamp_val(threshold, 0, 0x3E); b43legacy_phy_read(dev, 0x0020); /* dummy read */ b43legacy_phy_write(dev, 0x0020, (((u16)threshold) << 8) | 0x001C); @@ -892,7 +892,7 @@ void b43legacy_calc_nrssi_threshold(struct b43legacy_wldev *dev) else a += 32; a = a >> 6; - a = limit_value(a, -31, 31); + a = clamp_val(a, -31, 31); b = b * (phy->nrssi[1] - phy->nrssi[0]); b += (phy->nrssi[0] << 6); @@ -901,7 +901,7 @@ void b43legacy_calc_nrssi_threshold(struct b43legacy_wldev *dev) else b += 32; b = b >> 6; - b = limit_value(b, -31, 31); + b = clamp_val(b, -31, 31); tmp_u16 = b43legacy_phy_read(dev, 0x048A) & 0xF000; tmp_u16 |= ((u32)b & 0x0000003F); @@ -1905,7 +1905,7 @@ void b43legacy_radio_set_txpower_a(struct b43legacy_wldev *dev, u16 txpower) u16 dac; u16 ilt; - txpower = limit_value(txpower, 0, 63); + txpower = clamp_val(txpower, 0, 63); pamp = b43legacy_get_txgain_freq_power_amp(txpower); pamp <<= 5; diff --git a/drivers/net/wireless/b43legacy/rfkill.c b/drivers/net/wireless/b43legacy/rfkill.c index d178dfbb1c9f..476add97e974 100644 --- a/drivers/net/wireless/b43legacy/rfkill.c +++ b/drivers/net/wireless/b43legacy/rfkill.c @@ -44,6 +44,23 @@ static bool b43legacy_is_hw_radio_enabled(struct b43legacy_wldev *dev) return 0; } +/* Update the rfkill state */ +static void b43legacy_rfkill_update_state(struct b43legacy_wldev *dev) +{ + struct b43legacy_rfkill *rfk = &(dev->wl->rfkill); + + if (!dev->radio_hw_enable) { + rfk->rfkill->state = RFKILL_STATE_HARD_BLOCKED; + return; + } + + if (!dev->phy.radio_on) + rfk->rfkill->state = RFKILL_STATE_SOFT_BLOCKED; + else + rfk->rfkill->state = RFKILL_STATE_UNBLOCKED; + +} + /* The poll callback for the hardware button. */ static void b43legacy_rfkill_poll(struct input_polled_dev *poll_dev) { @@ -61,6 +78,7 @@ static void b43legacy_rfkill_poll(struct input_polled_dev *poll_dev) if (unlikely(enabled != dev->radio_hw_enable)) { dev->radio_hw_enable = enabled; report_change = 1; + b43legacy_rfkill_update_state(dev); b43legacyinfo(wl, "Radio hardware status changed to %s\n", enabled ? "ENABLED" : "DISABLED"); } @@ -90,7 +108,7 @@ static int b43legacy_rfkill_soft_toggle(void *data, enum rfkill_state state) goto out_unlock; err = 0; switch (state) { - case RFKILL_STATE_ON: + case RFKILL_STATE_UNBLOCKED: if (!dev->radio_hw_enable) { /* No luck. We can't toggle the hardware RF-kill * button from software. */ @@ -100,10 +118,14 @@ static int b43legacy_rfkill_soft_toggle(void *data, enum rfkill_state state) if (!dev->phy.radio_on) b43legacy_radio_turn_on(dev); break; - case RFKILL_STATE_OFF: + case RFKILL_STATE_SOFT_BLOCKED: if (dev->phy.radio_on) b43legacy_radio_turn_off(dev, 0); break; + default: + b43legacywarn(wl, "Received unexpected rfkill state %d.\n", + state); + break; } out_unlock: @@ -135,7 +157,7 @@ void b43legacy_rfkill_init(struct b43legacy_wldev *dev) snprintf(rfk->name, sizeof(rfk->name), "b43legacy-%s", wiphy_name(wl->hw->wiphy)); rfk->rfkill->name = rfk->name; - rfk->rfkill->state = RFKILL_STATE_ON; + rfk->rfkill->state = RFKILL_STATE_UNBLOCKED; rfk->rfkill->data = dev; rfk->rfkill->toggle_radio = b43legacy_rfkill_soft_toggle; rfk->rfkill->user_claim_unsupported = 1; diff --git a/drivers/net/wireless/b43legacy/xmit.c b/drivers/net/wireless/b43legacy/xmit.c index dcad2491a606..e969ed8d412d 100644 --- a/drivers/net/wireless/b43legacy/xmit.c +++ b/drivers/net/wireless/b43legacy/xmit.c @@ -188,11 +188,11 @@ static int generate_txhdr_fw3(struct b43legacy_wldev *dev, struct b43legacy_txhdr_fw3 *txhdr, const unsigned char *fragment_data, unsigned int fragment_len, - const struct ieee80211_tx_control *txctl, + const struct ieee80211_tx_info *info, u16 cookie) { const struct ieee80211_hdr *wlhdr; - int use_encryption = (!(txctl->flags & IEEE80211_TXCTL_DO_NOT_ENCRYPT)); + int use_encryption = (!(info->flags & IEEE80211_TX_CTL_DO_NOT_ENCRYPT)); u16 fctl; u8 rate; struct ieee80211_rate *rate_fb; @@ -201,15 +201,18 @@ static int generate_txhdr_fw3(struct b43legacy_wldev *dev, unsigned int plcp_fragment_len; u32 mac_ctl = 0; u16 phy_ctl = 0; + struct ieee80211_rate *tx_rate; wlhdr = (const struct ieee80211_hdr *)fragment_data; fctl = le16_to_cpu(wlhdr->frame_control); memset(txhdr, 0, sizeof(*txhdr)); - rate = txctl->tx_rate->hw_value; + tx_rate = ieee80211_get_tx_rate(dev->wl->hw, info); + + rate = tx_rate->hw_value; rate_ofdm = b43legacy_is_ofdm_rate(rate); - rate_fb = txctl->alt_retry_rate ? : txctl->tx_rate; + rate_fb = ieee80211_get_alt_retry_rate(dev->wl->hw, info) ? : tx_rate; rate_fb_ofdm = b43legacy_is_ofdm_rate(rate_fb->hw_value); txhdr->mac_frame_ctl = wlhdr->frame_control; @@ -225,14 +228,14 @@ static int generate_txhdr_fw3(struct b43legacy_wldev *dev, txhdr->dur_fb = wlhdr->duration_id; } else { txhdr->dur_fb = ieee80211_generic_frame_duration(dev->wl->hw, - txctl->vif, + info->control.vif, fragment_len, rate_fb); } plcp_fragment_len = fragment_len + FCS_LEN; if (use_encryption) { - u8 key_idx = (u16)(txctl->key_idx); + u8 key_idx = info->control.hw_key->hw_key_idx; struct b43legacy_key *key; int wlhdr_len; size_t iv_len; @@ -242,7 +245,7 @@ static int generate_txhdr_fw3(struct b43legacy_wldev *dev, if (key->enabled) { /* Hardware appends ICV. */ - plcp_fragment_len += txctl->icv_len; + plcp_fragment_len += info->control.icv_len; key_idx = b43legacy_kidx_to_fw(dev, key_idx); mac_ctl |= (key_idx << B43legacy_TX4_MAC_KEYIDX_SHIFT) & @@ -251,7 +254,7 @@ static int generate_txhdr_fw3(struct b43legacy_wldev *dev, B43legacy_TX4_MAC_KEYALG_SHIFT) & B43legacy_TX4_MAC_KEYALG; wlhdr_len = ieee80211_get_hdrlen(fctl); - iv_len = min((size_t)txctl->iv_len, + iv_len = min((size_t)info->control.iv_len, ARRAY_SIZE(txhdr->iv)); memcpy(txhdr->iv, ((u8 *)wlhdr) + wlhdr_len, iv_len); } else { @@ -275,7 +278,7 @@ static int generate_txhdr_fw3(struct b43legacy_wldev *dev, phy_ctl |= B43legacy_TX4_PHY_OFDM; if (dev->short_preamble) phy_ctl |= B43legacy_TX4_PHY_SHORTPRMBL; - switch (txctl->antenna_sel_tx) { + switch (info->antenna_sel_tx) { case 0: phy_ctl |= B43legacy_TX4_PHY_ANTLAST; break; @@ -290,21 +293,20 @@ static int generate_txhdr_fw3(struct b43legacy_wldev *dev, } /* MAC control */ - if (!(txctl->flags & IEEE80211_TXCTL_NO_ACK)) + if (!(info->flags & IEEE80211_TX_CTL_NO_ACK)) mac_ctl |= B43legacy_TX4_MAC_ACK; - if (!(((fctl & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_CTL) && - ((fctl & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_PSPOLL))) + if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) mac_ctl |= B43legacy_TX4_MAC_HWSEQ; - if (txctl->flags & IEEE80211_TXCTL_FIRST_FRAGMENT) + if (info->flags & IEEE80211_TX_CTL_FIRST_FRAGMENT) mac_ctl |= B43legacy_TX4_MAC_STMSDU; if (rate_fb_ofdm) mac_ctl |= B43legacy_TX4_MAC_FALLBACKOFDM; - if (txctl->flags & IEEE80211_TXCTL_LONG_RETRY_LIMIT) + if (info->flags & IEEE80211_TX_CTL_LONG_RETRY_LIMIT) mac_ctl |= B43legacy_TX4_MAC_LONGFRAME; /* Generate the RTS or CTS-to-self frame */ - if ((txctl->flags & IEEE80211_TXCTL_USE_RTS_CTS) || - (txctl->flags & IEEE80211_TXCTL_USE_CTS_PROTECT)) { + if ((info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) || + (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT)) { unsigned int len; struct ieee80211_hdr *hdr; int rts_rate; @@ -312,26 +314,26 @@ static int generate_txhdr_fw3(struct b43legacy_wldev *dev, int rts_rate_ofdm; int rts_rate_fb_ofdm; - rts_rate = txctl->rts_cts_rate->hw_value; + rts_rate = ieee80211_get_rts_cts_rate(dev->wl->hw, info)->hw_value; rts_rate_ofdm = b43legacy_is_ofdm_rate(rts_rate); rts_rate_fb = b43legacy_calc_fallback_rate(rts_rate); rts_rate_fb_ofdm = b43legacy_is_ofdm_rate(rts_rate_fb); if (rts_rate_fb_ofdm) mac_ctl |= B43legacy_TX4_MAC_CTSFALLBACKOFDM; - if (txctl->flags & IEEE80211_TXCTL_USE_CTS_PROTECT) { + if (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT) { ieee80211_ctstoself_get(dev->wl->hw, - txctl->vif, + info->control.vif, fragment_data, - fragment_len, txctl, + fragment_len, info, (struct ieee80211_cts *) (txhdr->rts_frame)); mac_ctl |= B43legacy_TX4_MAC_SENDCTS; len = sizeof(struct ieee80211_cts); } else { ieee80211_rts_get(dev->wl->hw, - txctl->vif, - fragment_data, fragment_len, txctl, + info->control.vif, + fragment_data, fragment_len, info, (struct ieee80211_rts *) (txhdr->rts_frame)); mac_ctl |= B43legacy_TX4_MAC_SENDRTS; @@ -362,12 +364,12 @@ int b43legacy_generate_txhdr(struct b43legacy_wldev *dev, u8 *txhdr, const unsigned char *fragment_data, unsigned int fragment_len, - const struct ieee80211_tx_control *txctl, + const struct ieee80211_tx_info *info, u16 cookie) { return generate_txhdr_fw3(dev, (struct b43legacy_txhdr_fw3 *)txhdr, fragment_data, fragment_len, - txctl, cookie); + info, cookie); } static s8 b43legacy_rssi_postprocess(struct b43legacy_wldev *dev, @@ -439,7 +441,7 @@ void b43legacy_rx(struct b43legacy_wldev *dev, struct b43legacy_plcp_hdr6 *plcp; struct ieee80211_hdr *wlhdr; const struct b43legacy_rxhdr_fw3 *rxhdr = _rxhdr; - u16 fctl; + __le16 fctl; u16 phystat0; u16 phystat3; u16 chanstat; @@ -477,7 +479,7 @@ void b43legacy_rx(struct b43legacy_wldev *dev, goto drop; } wlhdr = (struct ieee80211_hdr *)(skb->data); - fctl = le16_to_cpu(wlhdr->frame_control); + fctl = wlhdr->frame_control; if ((macstat & B43legacy_RX_MAC_DEC) && !(macstat & B43legacy_RX_MAC_DECERR)) { @@ -496,11 +498,11 @@ void b43legacy_rx(struct b43legacy_wldev *dev, if (dev->key[keyidx].algorithm != B43legacy_SEC_ALGO_NONE) { /* Remove PROTECTED flag to mark it as decrypted. */ - B43legacy_WARN_ON(!(fctl & IEEE80211_FCTL_PROTECTED)); - fctl &= ~IEEE80211_FCTL_PROTECTED; - wlhdr->frame_control = cpu_to_le16(fctl); + B43legacy_WARN_ON(!ieee80211_has_protected(fctl)); + fctl &= ~cpu_to_le16(IEEE80211_FCTL_PROTECTED); + wlhdr->frame_control = fctl; - wlhdr_len = ieee80211_get_hdrlen(fctl); + wlhdr_len = ieee80211_hdrlen(fctl); if (unlikely(skb->len < (wlhdr_len + 3))) { b43legacydbg(dev->wl, "RX: Packet size" " underrun3\n"); @@ -532,12 +534,12 @@ void b43legacy_rx(struct b43legacy_wldev *dev, } } - status.ssi = b43legacy_rssi_postprocess(dev, jssi, + status.signal = b43legacy_rssi_postprocess(dev, jssi, (phystat0 & B43legacy_RX_PHYST0_OFDM), (phystat0 & B43legacy_RX_PHYST0_GAINCTL), (phystat3 & B43legacy_RX_PHYST3_TRSTATE)); status.noise = dev->stats.link_noise; - status.signal = (jssi * 100) / B43legacy_RX_MAX_SSI; + status.qual = (jssi * 100) / B43legacy_RX_MAX_SSI; /* change to support A PHY */ if (phystat0 & B43legacy_RX_PHYST0_OFDM) status.rate_idx = b43legacy_plcp_get_bitrate_idx_ofdm(plcp, false); @@ -553,9 +555,7 @@ void b43legacy_rx(struct b43legacy_wldev *dev, * of timestamp, i.e. about 65 milliseconds after the PHY received * the first symbol. */ - if (((fctl & (IEEE80211_FCTL_FTYPE | IEEE80211_FCTL_STYPE)) - == (IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_BEACON)) || - dev->wl->radiotap_enabled) { + if (ieee80211_is_beacon(fctl) || dev->wl->radiotap_enabled) { u16 low_mactime_now; b43legacy_tsf_read(dev, &status.mactime); diff --git a/drivers/net/wireless/b43legacy/xmit.h b/drivers/net/wireless/b43legacy/xmit.h index bab47928a0c9..e56777e0feab 100644 --- a/drivers/net/wireless/b43legacy/xmit.h +++ b/drivers/net/wireless/b43legacy/xmit.h @@ -80,7 +80,7 @@ int b43legacy_generate_txhdr(struct b43legacy_wldev *dev, u8 *txhdr, const unsigned char *fragment_data, unsigned int fragment_len, - const struct ieee80211_tx_control *txctl, + const struct ieee80211_tx_info *info, u16 cookie); diff --git a/drivers/net/wireless/hostap/hostap.h b/drivers/net/wireless/hostap/hostap.h index 547ba84dc797..3a386a636cca 100644 --- a/drivers/net/wireless/hostap/hostap.h +++ b/drivers/net/wireless/hostap/hostap.h @@ -67,7 +67,8 @@ void * ap_crypt_get_ptrs(struct ap_data *ap, u8 *addr, int permanent, int prism2_ap_get_sta_qual(local_info_t *local, struct sockaddr addr[], struct iw_quality qual[], int buf_size, int aplist); -int prism2_ap_translate_scan(struct net_device *dev, char *buffer); +int prism2_ap_translate_scan(struct net_device *dev, + struct iw_request_info *info, char *buffer); int prism2_hostapd(struct ap_data *ap, struct prism2_hostapd_param *param); diff --git a/drivers/net/wireless/hostap/hostap_80211_rx.c b/drivers/net/wireless/hostap/hostap_80211_rx.c index 020f450e9dba..f106bc1585a4 100644 --- a/drivers/net/wireless/hostap/hostap_80211_rx.c +++ b/drivers/net/wireless/hostap/hostap_80211_rx.c @@ -78,6 +78,9 @@ int prism2_rx_80211(struct net_device *dev, struct sk_buff *skb, prism_header = 2; phdrlen = sizeof(struct linux_wlan_ng_cap_hdr); } + } else if (dev->type == ARPHRD_IEEE80211_RADIOTAP) { + prism_header = 3; + phdrlen = sizeof(struct hostap_radiotap_rx); } else { prism_header = 0; phdrlen = 0; @@ -165,6 +168,24 @@ hdr->f.status = s; hdr->f.len = l; hdr->f.data = d hdr->ssi_noise = htonl(rx_stats->noise); hdr->preamble = htonl(0); /* unknown */ hdr->encoding = htonl(1); /* cck */ + } else if (prism_header == 3) { + struct hostap_radiotap_rx *hdr; + hdr = (struct hostap_radiotap_rx *)skb_push(skb, phdrlen); + memset(hdr, 0, phdrlen); + hdr->hdr.it_len = cpu_to_le16(phdrlen); + hdr->hdr.it_present = + cpu_to_le32((1 << IEEE80211_RADIOTAP_TSFT) | + (1 << IEEE80211_RADIOTAP_CHANNEL) | + (1 << IEEE80211_RADIOTAP_RATE) | + (1 << IEEE80211_RADIOTAP_DBM_ANTSIGNAL) | + (1 << IEEE80211_RADIOTAP_DBM_ANTNOISE)); + hdr->tsft = cpu_to_le64(rx_stats->mac_time); + hdr->chan_freq = cpu_to_le16(freq_list[local->channel - 1]); + hdr->chan_flags = cpu_to_le16(IEEE80211_CHAN_CCK | + IEEE80211_CHAN_2GHZ); + hdr->rate = rx_stats->rate / 5; + hdr->dbm_antsignal = rx_stats->signal; + hdr->dbm_antnoise = rx_stats->noise; } ret = skb->len - phdrlen; diff --git a/drivers/net/wireless/hostap/hostap_ap.c b/drivers/net/wireless/hostap/hostap_ap.c index ab981afd481d..af3d4ef2a80b 100644 --- a/drivers/net/wireless/hostap/hostap_ap.c +++ b/drivers/net/wireless/hostap/hostap_ap.c @@ -2420,7 +2420,8 @@ int prism2_ap_get_sta_qual(local_info_t *local, struct sockaddr addr[], /* Translate our list of Access Points & Stations to a card independant * format that the Wireless Tools will understand - Jean II */ -int prism2_ap_translate_scan(struct net_device *dev, char *buffer) +int prism2_ap_translate_scan(struct net_device *dev, + struct iw_request_info *info, char *buffer) { struct hostap_interface *iface; local_info_t *local; @@ -2449,8 +2450,8 @@ int prism2_ap_translate_scan(struct net_device *dev, char *buffer) iwe.u.ap_addr.sa_family = ARPHRD_ETHER; memcpy(iwe.u.ap_addr.sa_data, sta->addr, ETH_ALEN); iwe.len = IW_EV_ADDR_LEN; - current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, - IW_EV_ADDR_LEN); + current_ev = iwe_stream_add_event(info, current_ev, end_buf, + &iwe, IW_EV_ADDR_LEN); /* Use the mode to indicate if it's a station or * an Access Point */ @@ -2461,8 +2462,8 @@ int prism2_ap_translate_scan(struct net_device *dev, char *buffer) else iwe.u.mode = IW_MODE_INFRA; iwe.len = IW_EV_UINT_LEN; - current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, - IW_EV_UINT_LEN); + current_ev = iwe_stream_add_event(info, current_ev, end_buf, + &iwe, IW_EV_UINT_LEN); /* Some quality */ memset(&iwe, 0, sizeof(iwe)); @@ -2477,8 +2478,8 @@ int prism2_ap_translate_scan(struct net_device *dev, char *buffer) iwe.u.qual.noise = HFA384X_LEVEL_TO_dBm(sta->last_rx_silence); iwe.u.qual.updated = sta->last_rx_updated; iwe.len = IW_EV_QUAL_LEN; - current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, - IW_EV_QUAL_LEN); + current_ev = iwe_stream_add_event(info, current_ev, end_buf, + &iwe, IW_EV_QUAL_LEN); #ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT if (sta->ap) { @@ -2486,8 +2487,8 @@ int prism2_ap_translate_scan(struct net_device *dev, char *buffer) iwe.cmd = SIOCGIWESSID; iwe.u.data.length = sta->u.ap.ssid_len; iwe.u.data.flags = 1; - current_ev = iwe_stream_add_point(current_ev, end_buf, - &iwe, + current_ev = iwe_stream_add_point(info, current_ev, + end_buf, &iwe, sta->u.ap.ssid); memset(&iwe, 0, sizeof(iwe)); @@ -2497,10 +2498,9 @@ int prism2_ap_translate_scan(struct net_device *dev, char *buffer) IW_ENCODE_ENABLED | IW_ENCODE_NOKEY; else iwe.u.data.flags = IW_ENCODE_DISABLED; - current_ev = iwe_stream_add_point(current_ev, end_buf, - &iwe, - sta->u.ap.ssid - /* 0 byte memcpy */); + current_ev = iwe_stream_add_point(info, current_ev, + end_buf, &iwe, + sta->u.ap.ssid); if (sta->u.ap.channel > 0 && sta->u.ap.channel <= FREQ_COUNT) { @@ -2510,7 +2510,7 @@ int prism2_ap_translate_scan(struct net_device *dev, char *buffer) * 100000; iwe.u.freq.e = 1; current_ev = iwe_stream_add_event( - current_ev, end_buf, &iwe, + info, current_ev, end_buf, &iwe, IW_EV_FREQ_LEN); } @@ -2519,8 +2519,8 @@ int prism2_ap_translate_scan(struct net_device *dev, char *buffer) sprintf(buf, "beacon_interval=%d", sta->listen_interval); iwe.u.data.length = strlen(buf); - current_ev = iwe_stream_add_point(current_ev, end_buf, - &iwe, buf); + current_ev = iwe_stream_add_point(info, current_ev, + end_buf, &iwe, buf); } #endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ diff --git a/drivers/net/wireless/hostap/hostap_hw.c b/drivers/net/wireless/hostap/hostap_hw.c index 936f52e3d95c..13d5882f1f21 100644 --- a/drivers/net/wireless/hostap/hostap_hw.c +++ b/drivers/net/wireless/hostap/hostap_hw.c @@ -3102,6 +3102,18 @@ static void prism2_clear_set_tim_queue(local_info_t *local) */ static struct lock_class_key hostap_netdev_xmit_lock_key; +static void prism2_set_lockdep_class_one(struct net_device *dev, + struct netdev_queue *txq, + void *_unused) +{ + lockdep_set_class(&txq->_xmit_lock, + &hostap_netdev_xmit_lock_key); +} + +static void prism2_set_lockdep_class(struct net_device *dev) +{ + netdev_for_each_tx_queue(dev, prism2_set_lockdep_class_one, NULL); +} static struct net_device * prism2_init_local_data(struct prism2_helper_functions *funcs, int card_idx, @@ -3204,6 +3216,7 @@ prism2_init_local_data(struct prism2_helper_functions *funcs, int card_idx, local->auth_algs = PRISM2_AUTH_OPEN | PRISM2_AUTH_SHARED_KEY; local->sram_type = -1; local->scan_channel_mask = 0xffff; + local->monitor_type = PRISM2_MONITOR_RADIOTAP; /* Initialize task queue structures */ INIT_WORK(&local->reset_queue, handle_reset_queue); @@ -3267,7 +3280,7 @@ while (0) if (ret >= 0) ret = register_netdevice(dev); - lockdep_set_class(&dev->_xmit_lock, &hostap_netdev_xmit_lock_key); + prism2_set_lockdep_class(dev); rtnl_unlock(); if (ret < 0) { printk(KERN_WARNING "%s: register netdevice failed!\n", @@ -3416,7 +3429,7 @@ static void prism2_free_local_data(struct net_device *dev) } -#ifndef PRISM2_PLX +#if (defined(PRISM2_PCI) && defined(CONFIG_PM)) || defined(PRISM2_PCCARD) static void prism2_suspend(struct net_device *dev) { struct hostap_interface *iface; @@ -3435,7 +3448,7 @@ static void prism2_suspend(struct net_device *dev) /* Disable hardware and firmware */ prism2_hw_shutdown(dev, 0); } -#endif /* PRISM2_PLX */ +#endif /* (PRISM2_PCI && CONFIG_PM) || PRISM2_PCCARD */ /* These might at some point be compiled separately and used as separate diff --git a/drivers/net/wireless/hostap/hostap_ioctl.c b/drivers/net/wireless/hostap/hostap_ioctl.c index 0ca0bfeb0ada..3f8b1d7036e5 100644 --- a/drivers/net/wireless/hostap/hostap_ioctl.c +++ b/drivers/net/wireless/hostap/hostap_ioctl.c @@ -897,6 +897,8 @@ static void hostap_monitor_set_type(local_info_t *local) if (local->monitor_type == PRISM2_MONITOR_PRISM || local->monitor_type == PRISM2_MONITOR_CAPHDR) { dev->type = ARPHRD_IEEE80211_PRISM; + } else if (local->monitor_type == PRISM2_MONITOR_RADIOTAP) { + dev->type = ARPHRD_IEEE80211_RADIOTAP; } else { dev->type = ARPHRD_IEEE80211; } @@ -1793,6 +1795,7 @@ static int prism2_ioctl_siwscan(struct net_device *dev, #ifndef PRISM2_NO_STATION_MODES static char * __prism2_translate_scan(local_info_t *local, + struct iw_request_info *info, struct hfa384x_hostscan_result *scan, struct hostap_bss_info *bss, char *current_ev, char *end_buf) @@ -1823,7 +1826,7 @@ static char * __prism2_translate_scan(local_info_t *local, iwe.cmd = SIOCGIWAP; iwe.u.ap_addr.sa_family = ARPHRD_ETHER; memcpy(iwe.u.ap_addr.sa_data, bssid, ETH_ALEN); - current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, + current_ev = iwe_stream_add_event(info, current_ev, end_buf, &iwe, IW_EV_ADDR_LEN); /* Other entries will be displayed in the order we give them */ @@ -1832,7 +1835,8 @@ static char * __prism2_translate_scan(local_info_t *local, iwe.cmd = SIOCGIWESSID; iwe.u.data.length = ssid_len; iwe.u.data.flags = 1; - current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, ssid); + current_ev = iwe_stream_add_point(info, current_ev, end_buf, + &iwe, ssid); memset(&iwe, 0, sizeof(iwe)); iwe.cmd = SIOCGIWMODE; @@ -1847,8 +1851,8 @@ static char * __prism2_translate_scan(local_info_t *local, iwe.u.mode = IW_MODE_MASTER; else iwe.u.mode = IW_MODE_ADHOC; - current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, - IW_EV_UINT_LEN); + current_ev = iwe_stream_add_event(info, current_ev, end_buf, + &iwe, IW_EV_UINT_LEN); } memset(&iwe, 0, sizeof(iwe)); @@ -1864,8 +1868,8 @@ static char * __prism2_translate_scan(local_info_t *local, if (chan > 0) { iwe.u.freq.m = freq_list[chan - 1] * 100000; iwe.u.freq.e = 1; - current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, - IW_EV_FREQ_LEN); + current_ev = iwe_stream_add_event(info, current_ev, end_buf, + &iwe, IW_EV_FREQ_LEN); } if (scan) { @@ -1884,8 +1888,8 @@ static char * __prism2_translate_scan(local_info_t *local, | IW_QUAL_NOISE_UPDATED | IW_QUAL_QUAL_INVALID | IW_QUAL_DBM; - current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, - IW_EV_QUAL_LEN); + current_ev = iwe_stream_add_event(info, current_ev, end_buf, + &iwe, IW_EV_QUAL_LEN); } memset(&iwe, 0, sizeof(iwe)); @@ -1895,13 +1899,13 @@ static char * __prism2_translate_scan(local_info_t *local, else iwe.u.data.flags = IW_ENCODE_DISABLED; iwe.u.data.length = 0; - current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, ""); + current_ev = iwe_stream_add_point(info, current_ev, end_buf, &iwe, ""); /* TODO: add SuppRates into BSS table */ if (scan) { memset(&iwe, 0, sizeof(iwe)); iwe.cmd = SIOCGIWRATE; - current_val = current_ev + IW_EV_LCP_LEN; + current_val = current_ev + iwe_stream_lcp_len(info); pos = scan->sup_rates; for (i = 0; i < sizeof(scan->sup_rates); i++) { if (pos[i] == 0) @@ -1909,11 +1913,11 @@ static char * __prism2_translate_scan(local_info_t *local, /* Bit rate given in 500 kb/s units (+ 0x80) */ iwe.u.bitrate.value = ((pos[i] & 0x7f) * 500000); current_val = iwe_stream_add_value( - current_ev, current_val, end_buf, &iwe, + info, current_ev, current_val, end_buf, &iwe, IW_EV_PARAM_LEN); } /* Check if we added any event */ - if ((current_val - current_ev) > IW_EV_LCP_LEN) + if ((current_val - current_ev) > iwe_stream_lcp_len(info)) current_ev = current_val; } @@ -1924,15 +1928,15 @@ static char * __prism2_translate_scan(local_info_t *local, iwe.cmd = IWEVCUSTOM; sprintf(buf, "bcn_int=%d", le16_to_cpu(scan->beacon_interval)); iwe.u.data.length = strlen(buf); - current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, - buf); + current_ev = iwe_stream_add_point(info, current_ev, end_buf, + &iwe, buf); memset(&iwe, 0, sizeof(iwe)); iwe.cmd = IWEVCUSTOM; sprintf(buf, "resp_rate=%d", le16_to_cpu(scan->rate)); iwe.u.data.length = strlen(buf); - current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, - buf); + current_ev = iwe_stream_add_point(info, current_ev, end_buf, + &iwe, buf); if (local->last_scan_type == PRISM2_HOSTSCAN && (capabilities & WLAN_CAPABILITY_IBSS)) { @@ -1940,8 +1944,8 @@ static char * __prism2_translate_scan(local_info_t *local, iwe.cmd = IWEVCUSTOM; sprintf(buf, "atim=%d", le16_to_cpu(scan->atim)); iwe.u.data.length = strlen(buf); - current_ev = iwe_stream_add_point(current_ev, end_buf, - &iwe, buf); + current_ev = iwe_stream_add_point(info, current_ev, + end_buf, &iwe, buf); } } kfree(buf); @@ -1950,16 +1954,16 @@ static char * __prism2_translate_scan(local_info_t *local, memset(&iwe, 0, sizeof(iwe)); iwe.cmd = IWEVGENIE; iwe.u.data.length = bss->wpa_ie_len; - current_ev = iwe_stream_add_point( - current_ev, end_buf, &iwe, bss->wpa_ie); + current_ev = iwe_stream_add_point(info, current_ev, end_buf, + &iwe, bss->wpa_ie); } if (bss && bss->rsn_ie_len > 0 && bss->rsn_ie_len <= MAX_WPA_IE_LEN) { memset(&iwe, 0, sizeof(iwe)); iwe.cmd = IWEVGENIE; iwe.u.data.length = bss->rsn_ie_len; - current_ev = iwe_stream_add_point( - current_ev, end_buf, &iwe, bss->rsn_ie); + current_ev = iwe_stream_add_point(info, current_ev, end_buf, + &iwe, bss->rsn_ie); } return current_ev; @@ -1969,6 +1973,7 @@ static char * __prism2_translate_scan(local_info_t *local, /* Translate scan data returned from the card to a card independant * format that the Wireless Tools will understand - Jean II */ static inline int prism2_translate_scan(local_info_t *local, + struct iw_request_info *info, char *buffer, int buflen) { struct hfa384x_hostscan_result *scan; @@ -1999,13 +2004,14 @@ static inline int prism2_translate_scan(local_info_t *local, if (memcmp(bss->bssid, scan->bssid, ETH_ALEN) == 0) { bss->included = 1; current_ev = __prism2_translate_scan( - local, scan, bss, current_ev, end_buf); + local, info, scan, bss, current_ev, + end_buf); found++; } } if (!found) { current_ev = __prism2_translate_scan( - local, scan, NULL, current_ev, end_buf); + local, info, scan, NULL, current_ev, end_buf); } /* Check if there is space for one more entry */ if ((end_buf - current_ev) <= IW_EV_ADDR_LEN) { @@ -2023,7 +2029,7 @@ static inline int prism2_translate_scan(local_info_t *local, bss = list_entry(ptr, struct hostap_bss_info, list); if (bss->included) continue; - current_ev = __prism2_translate_scan(local, NULL, bss, + current_ev = __prism2_translate_scan(local, info, NULL, bss, current_ev, end_buf); /* Check if there is space for one more entry */ if ((end_buf - current_ev) <= IW_EV_ADDR_LEN) { @@ -2070,7 +2076,7 @@ static inline int prism2_ioctl_giwscan_sta(struct net_device *dev, } local->scan_timestamp = 0; - res = prism2_translate_scan(local, extra, data->length); + res = prism2_translate_scan(local, info, extra, data->length); if (res >= 0) { data->length = res; @@ -2103,7 +2109,7 @@ static int prism2_ioctl_giwscan(struct net_device *dev, * Jean II */ /* Translate to WE format */ - res = prism2_ap_translate_scan(dev, extra); + res = prism2_ap_translate_scan(dev, info, extra); if (res >= 0) { printk(KERN_DEBUG "Scan result translation succeeded " "(length=%d)\n", res); @@ -2516,7 +2522,8 @@ static int prism2_ioctl_priv_prism2_param(struct net_device *dev, case PRISM2_PARAM_MONITOR_TYPE: if (value != PRISM2_MONITOR_80211 && value != PRISM2_MONITOR_CAPHDR && - value != PRISM2_MONITOR_PRISM) { + value != PRISM2_MONITOR_PRISM && + value != PRISM2_MONITOR_RADIOTAP) { ret = -EINVAL; break; } diff --git a/drivers/net/wireless/hostap/hostap_main.c b/drivers/net/wireless/hostap/hostap_main.c index a38e85f334df..756ab56c1f40 100644 --- a/drivers/net/wireless/hostap/hostap_main.c +++ b/drivers/net/wireless/hostap/hostap_main.c @@ -597,25 +597,7 @@ void hostap_dump_tx_header(const char *name, const struct hfa384x_tx_frame *tx) static int hostap_80211_header_parse(const struct sk_buff *skb, unsigned char *haddr) { - struct hostap_interface *iface = netdev_priv(skb->dev); - local_info_t *local = iface->local; - - if (local->monitor_type == PRISM2_MONITOR_PRISM || - local->monitor_type == PRISM2_MONITOR_CAPHDR) { - const unsigned char *mac = skb_mac_header(skb); - - if (*(u32 *)mac == LWNG_CAP_DID_BASE) { - memcpy(haddr, - mac + sizeof(struct linux_wlan_ng_prism_hdr) + 10, - ETH_ALEN); /* addr2 */ - } else { /* (*(u32 *)mac == htonl(LWNG_CAPHDR_VERSION)) */ - memcpy(haddr, - mac + sizeof(struct linux_wlan_ng_cap_hdr) + 10, - ETH_ALEN); /* addr2 */ - } - } else - memcpy(haddr, skb_mac_header(skb) + 10, ETH_ALEN); /* addr2 */ - + memcpy(haddr, skb_mac_header(skb) + 10, ETH_ALEN); /* addr2 */ return ETH_ALEN; } diff --git a/drivers/net/wireless/hostap/hostap_wlan.h b/drivers/net/wireless/hostap/hostap_wlan.h index 15445bce2ac7..ffdf4876121b 100644 --- a/drivers/net/wireless/hostap/hostap_wlan.h +++ b/drivers/net/wireless/hostap/hostap_wlan.h @@ -5,6 +5,7 @@ #include <linux/netdevice.h> #include <linux/mutex.h> #include <net/iw_handler.h> +#include <net/ieee80211_radiotap.h> #include "hostap_config.h" #include "hostap_common.h" @@ -55,6 +56,17 @@ struct linux_wlan_ng_cap_hdr { __be32 encoding; } __attribute__ ((packed)); +struct hostap_radiotap_rx { + struct ieee80211_radiotap_header hdr; + __le64 tsft; + u8 rate; + u8 padding; + __le16 chan_freq; + __le16 chan_flags; + s8 dbm_antsignal; + s8 dbm_antnoise; +} __attribute__ ((packed)); + #define LWNG_CAP_DID_BASE (4 | (1 << 6)) /* section 4, group 1 */ #define LWNG_CAPHDR_VERSION 0x80211001 @@ -734,7 +746,7 @@ struct local_info { unsigned long scan_timestamp; /* Time started to scan */ enum { PRISM2_MONITOR_80211 = 0, PRISM2_MONITOR_PRISM = 1, - PRISM2_MONITOR_CAPHDR = 2 + PRISM2_MONITOR_CAPHDR = 2, PRISM2_MONITOR_RADIOTAP = 3 } monitor_type; int monitor_allow_fcserr; diff --git a/drivers/net/wireless/iwlwifi/Kconfig b/drivers/net/wireless/iwlwifi/Kconfig index 62fb89d82318..82b66a3d3a5d 100644 --- a/drivers/net/wireless/iwlwifi/Kconfig +++ b/drivers/net/wireless/iwlwifi/Kconfig @@ -8,7 +8,6 @@ config IWLCORE select MAC80211_LEDS if IWLWIFI_LEDS select LEDS_CLASS if IWLWIFI_LEDS select RFKILL if IWLWIFI_RFKILL - select RFKILL_INPUT if IWLWIFI_RFKILL config IWLWIFI_LEDS bool @@ -45,14 +44,6 @@ config IWL4965 say M here and read <file:Documentation/kbuild/modules.txt>. The module will be called iwl4965.ko. -config IWL4965_HT - bool "Enable 802.11n HT features in iwl4965 driver" - depends on EXPERIMENTAL - depends on IWL4965 - ---help--- - This option enables IEEE 802.11n High Throughput features - for the iwl4965 driver. - config IWL4965_LEDS bool "Enable LEDS features in iwl4965 driver" depends on IWL4965 @@ -67,13 +58,6 @@ config IWL4965_SPECTRUM_MEASUREMENT ---help--- This option will enable spectrum measurement for the iwl4965 driver. -config IWL4965_SENSITIVITY - bool "Enable Sensitivity Calibration in iwl4965 driver" - depends on IWL4965 - ---help--- - This option will enable sensitivity calibration for the iwl4965 - driver. - config IWLWIFI_DEBUG bool "Enable full debugging output in iwl4965 driver" depends on IWL4965 @@ -85,13 +69,13 @@ config IWLWIFI_DEBUG control which debug output is sent to the kernel log by setting the value in - /sys/bus/pci/drivers/${DRIVER}/debug_level + /sys/class/net/wlan0/device/debug_level This entry will only exist if this option is enabled. To set a value, simply echo an 8-byte hex value to the same file: - % echo 0x43fff > /sys/bus/pci/drivers/${DRIVER}/debug_level + % echo 0x43fff > /sys/class/net/wlan0/device/debug_level You can find the list of debug mask values in: drivers/net/wireless/iwlwifi/iwl-4965-debug.h @@ -100,6 +84,13 @@ config IWLWIFI_DEBUG as the debug information can assist others in helping you resolve any problems you may encounter. +config IWL5000 + bool "Intel Wireless WiFi 5000AGN" + depends on IWL4965 + ---help--- + This option enables support for Intel Wireless WiFi Link 5000AGN Family + Dependency on 4965 is temporary + config IWLWIFI_DEBUGFS bool "Iwlwifi debugfs support" depends on IWLCORE && IWLWIFI_DEBUG && MAC80211_DEBUGFS @@ -113,6 +104,7 @@ config IWL3945 select IWLWIFI select MAC80211_LEDS if IWL3945_LEDS select LEDS_CLASS if IWL3945_LEDS + select RFKILL if IWL3945_RFKILL ---help--- Select to build the driver supporting the: @@ -135,6 +127,10 @@ config IWL3945 say M here and read <file:Documentation/kbuild/modules.txt>. The module will be called iwl3945.ko. +config IWL3945_RFKILL + bool "Enable RF kill support in iwl3945 drivers" + depends on IWL3945 + config IWL3945_SPECTRUM_MEASUREMENT bool "Enable Spectrum Measurement in iwl3945 drivers" depends on IWL3945 diff --git a/drivers/net/wireless/iwlwifi/Makefile b/drivers/net/wireless/iwlwifi/Makefile index ec6187b75c3b..1f52b92f08b5 100644 --- a/drivers/net/wireless/iwlwifi/Makefile +++ b/drivers/net/wireless/iwlwifi/Makefile @@ -1,5 +1,7 @@ obj-$(CONFIG_IWLCORE) += iwlcore.o -iwlcore-objs := iwl-core.o iwl-eeprom.o iwl-hcmd.o +iwlcore-objs := iwl-core.o iwl-eeprom.o iwl-hcmd.o iwl-power.o +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 @@ -9,5 +11,10 @@ iwl3945-objs := iwl3945-base.o iwl-3945.o iwl-3945-rs.o iwl3945-$(CONFIG_IWL3945_LEDS) += iwl-3945-led.o obj-$(CONFIG_IWL4965) += iwl4965.o -iwl4965-objs := iwl4965-base.o iwl-4965.o iwl-4965-rs.o iwl-sta.o +iwl4965-objs := iwl4965-base.o iwl-4965.o iwl-4965-rs.o + +ifeq ($(CONFIG_IWL5000),y) + iwl4965-objs += iwl-5000.o +endif + diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-hw.h b/drivers/net/wireless/iwlwifi/iwl-3945-hw.h index ad612a8719f4..644bd9e08052 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945-hw.h +++ b/drivers/net/wireless/iwlwifi/iwl-3945-hw.h @@ -126,7 +126,7 @@ enum { EEPROM_CHANNEL_ACTIVE = (1 << 3), /* active scanning allowed */ EEPROM_CHANNEL_RADAR = (1 << 4), /* radar detection required */ EEPROM_CHANNEL_WIDE = (1 << 5), /* 20 MHz channel okay */ - EEPROM_CHANNEL_NARROW = (1 << 6), /* 10 MHz channel (not used) */ + /* Bit 6 Reserved (was Narrow Channel) */ EEPROM_CHANNEL_DFS = (1 << 7), /* dynamic freq selection candidate */ }; @@ -289,17 +289,6 @@ struct iwl3945_eeprom { #define PCI_REG_WUM8 0x0E8 #define PCI_CFG_PMC_PME_FROM_D3COLD_SUPPORT (0x80000000) -/* SCD (3945 Tx Frame Scheduler) */ -#define SCD_BASE (CSR_BASE + 0x2E00) - -#define SCD_MODE_REG (SCD_BASE + 0x000) -#define SCD_ARASTAT_REG (SCD_BASE + 0x004) -#define SCD_TXFACT_REG (SCD_BASE + 0x010) -#define SCD_TXF4MF_REG (SCD_BASE + 0x014) -#define SCD_TXF5MF_REG (SCD_BASE + 0x020) -#define SCD_SBYP_MODE_1_REG (SCD_BASE + 0x02C) -#define SCD_SBYP_MODE_2_REG (SCD_BASE + 0x030) - /*=== FH (data Flow Handler) ===*/ #define FH_BASE (0x800) diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-led.c b/drivers/net/wireless/iwlwifi/iwl-3945-led.c index 8b1528e52d43..6be1fe13fa57 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945-led.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945-led.c @@ -42,14 +42,11 @@ #include "iwl-3945.h" #include "iwl-helpers.h" -#define IWL_1MB_RATE (128 * 1024) -#define IWL_LED_THRESHOLD (16) -#define IWL_MAX_BLINK_TBL (10) static const struct { u16 brightness; u8 on_time; - u8 of_time; + u8 off_time; } blink_tbl[] = { {300, 25, 25}, @@ -61,9 +58,16 @@ static const struct { {15, 95, 95 }, {10, 110, 110}, {5, 130, 130}, - {0, 167, 167} + {0, 167, 167}, + /*SOLID_ON*/ + {-1, IWL_LED_SOLID, 0} }; +#define IWL_1MB_RATE (128 * 1024) +#define IWL_LED_THRESHOLD (16) +#define IWL_MAX_BLINK_TBL (ARRAY_SIZE(blink_tbl) - 1) /*Exclude Solid on*/ +#define IWL_SOLID_BLINK_IDX (ARRAY_SIZE(blink_tbl) - 1) + static int iwl3945_led_cmd_callback(struct iwl3945_priv *priv, struct iwl3945_cmd *cmd, struct sk_buff *skb) @@ -71,6 +75,10 @@ static int iwl3945_led_cmd_callback(struct iwl3945_priv *priv, return 1; } +static inline int iwl3945_brightness_to_idx(enum led_brightness brightness) +{ + return fls(0x000000FF & (u32)brightness); +} /* Send led command */ static int iwl_send_led_cmd(struct iwl3945_priv *priv, @@ -81,49 +89,45 @@ static int iwl_send_led_cmd(struct iwl3945_priv *priv, .len = sizeof(struct iwl3945_led_cmd), .data = led_cmd, .meta.flags = CMD_ASYNC, - .meta.u.callback = iwl3945_led_cmd_callback + .meta.u.callback = iwl3945_led_cmd_callback, }; return iwl3945_send_cmd(priv, &cmd); } + /* Set led on command */ -static int iwl3945_led_on(struct iwl3945_priv *priv, int led_id) +static int iwl3945_led_pattern(struct iwl3945_priv *priv, int led_id, + unsigned int idx) { struct iwl3945_led_cmd led_cmd = { .id = led_id, - .on = IWL_LED_SOLID, - .off = 0, .interval = IWL_DEF_LED_INTRVL }; + + BUG_ON(idx > IWL_MAX_BLINK_TBL); + + led_cmd.on = blink_tbl[idx].on_time; + led_cmd.off = blink_tbl[idx].off_time; + return iwl_send_led_cmd(priv, &led_cmd); } + +#if 1 /* Set led on command */ -static int iwl3945_led_pattern(struct iwl3945_priv *priv, int led_id, - enum led_brightness brightness) +static int iwl3945_led_on(struct iwl3945_priv *priv, int led_id) { struct iwl3945_led_cmd led_cmd = { .id = led_id, - .on = brightness, - .off = brightness, + .on = IWL_LED_SOLID, + .off = 0, .interval = IWL_DEF_LED_INTRVL }; - if (brightness == LED_FULL) { - led_cmd.on = IWL_LED_SOLID; - led_cmd.off = 0; - } return iwl_send_led_cmd(priv, &led_cmd); } -/* Set led register off */ -static int iwl3945_led_on_reg(struct iwl3945_priv *priv, int led_id) -{ - IWL_DEBUG_LED("led on %d\n", led_id); - return iwl3945_led_on(priv, led_id); -} - /* Set led off command */ static int iwl3945_led_off(struct iwl3945_priv *priv, int led_id) { @@ -136,27 +140,7 @@ static int iwl3945_led_off(struct iwl3945_priv *priv, int led_id) IWL_DEBUG_LED("led off %d\n", led_id); return iwl_send_led_cmd(priv, &led_cmd); } - -/* Set led register off */ -static int iwl3945_led_off_reg(struct iwl3945_priv *priv, int led_id) -{ - iwl3945_led_off(priv, led_id); - return 0; -} - -/* Set led blink command */ -static int iwl3945_led_not_solid(struct iwl3945_priv *priv, int led_id, - u8 brightness) -{ - struct iwl3945_led_cmd led_cmd = { - .id = led_id, - .on = brightness, - .off = brightness, - .interval = IWL_DEF_LED_INTRVL - }; - - return iwl_send_led_cmd(priv, &led_cmd); -} +#endif /* @@ -206,8 +190,10 @@ static void iwl3945_led_brightness_set(struct led_classdev *led_cdev, led->led_off(priv, IWL_LED_LINK); break; default: - if (led->led_pattern) - led->led_pattern(priv, IWL_LED_LINK, brightness); + if (led->led_pattern) { + int idx = iwl3945_brightness_to_idx(brightness); + led->led_pattern(priv, IWL_LED_LINK, idx); + } break; } } @@ -252,24 +238,20 @@ static int iwl3945_led_register_led(struct iwl3945_priv *priv, static inline u8 get_blink_rate(struct iwl3945_priv *priv) { int index; - u8 blink_rate; - - if (priv->rxtxpackets < IWL_LED_THRESHOLD) - index = 10; - else { - for (index = 0; index < IWL_MAX_BLINK_TBL; index++) { - if (priv->rxtxpackets > (blink_tbl[index].brightness * - IWL_1MB_RATE)) - break; - } - } - /* if 0 frame is transfered */ - if ((index == IWL_MAX_BLINK_TBL) || !priv->allow_blinking) - blink_rate = IWL_LED_SOLID; - else - blink_rate = blink_tbl[index].on_time; + u64 current_tpt = priv->rxtxpackets; + s64 tpt = current_tpt - priv->led_tpt; - return blink_rate; + if (tpt < 0) + tpt = -tpt; + priv->led_tpt = current_tpt; + + if (!priv->allow_blinking) + index = IWL_MAX_BLINK_TBL; + else + 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 iwl3945_priv *priv) @@ -285,7 +267,7 @@ static inline int is_rf_kill(struct iwl3945_priv *priv) */ void iwl3945_led_background(struct iwl3945_priv *priv) { - u8 blink_rate; + u8 blink_idx; if (test_bit(STATUS_EXIT_PENDING, &priv->status)) { priv->last_blink_time = 0; @@ -298,9 +280,10 @@ void iwl3945_led_background(struct iwl3945_priv *priv) if (!priv->allow_blinking) { priv->last_blink_time = 0; - if (priv->last_blink_rate != IWL_LED_SOLID) { - priv->last_blink_rate = IWL_LED_SOLID; - iwl3945_led_on(priv, IWL_LED_LINK); + if (priv->last_blink_rate != IWL_SOLID_BLINK_IDX) { + priv->last_blink_rate = IWL_SOLID_BLINK_IDX; + iwl3945_led_pattern(priv, IWL_LED_LINK, + IWL_SOLID_BLINK_IDX); } return; } @@ -309,21 +292,14 @@ void iwl3945_led_background(struct iwl3945_priv *priv) msecs_to_jiffies(1000))) return; - blink_rate = get_blink_rate(priv); + blink_idx = get_blink_rate(priv); /* call only if blink rate change */ - if (blink_rate != priv->last_blink_rate) { - if (blink_rate != IWL_LED_SOLID) { - priv->last_blink_time = jiffies + - msecs_to_jiffies(1000); - iwl3945_led_not_solid(priv, IWL_LED_LINK, blink_rate); - } else { - priv->last_blink_time = 0; - iwl3945_led_on(priv, IWL_LED_LINK); - } - } + if (blink_idx != priv->last_blink_rate) + iwl3945_led_pattern(priv, IWL_LED_LINK, blink_idx); - priv->last_blink_rate = blink_rate; + priv->last_blink_time = jiffies; + priv->last_blink_rate = blink_idx; priv->rxtxpackets = 0; } @@ -337,6 +313,7 @@ int iwl3945_led_register(struct iwl3945_priv *priv) priv->last_blink_rate = 0; priv->rxtxpackets = 0; + priv->led_tpt = 0; priv->last_blink_time = 0; priv->allow_blinking = 0; @@ -344,8 +321,8 @@ int iwl3945_led_register(struct iwl3945_priv *priv) snprintf(name, sizeof(name), "iwl-%s:radio", wiphy_name(priv->hw->wiphy)); - priv->led[IWL_LED_TRG_RADIO].led_on = iwl3945_led_on_reg; - priv->led[IWL_LED_TRG_RADIO].led_off = iwl3945_led_off_reg; + priv->led[IWL_LED_TRG_RADIO].led_on = iwl3945_led_on; + priv->led[IWL_LED_TRG_RADIO].led_off = iwl3945_led_off; priv->led[IWL_LED_TRG_RADIO].led_pattern = NULL; ret = iwl3945_led_register_led(priv, @@ -364,8 +341,8 @@ int iwl3945_led_register(struct iwl3945_priv *priv) IWL_LED_TRG_ASSOC, 0, name, trigger); /* for assoc always turn led on */ - priv->led[IWL_LED_TRG_ASSOC].led_on = iwl3945_led_on_reg; - priv->led[IWL_LED_TRG_ASSOC].led_off = iwl3945_led_on_reg; + 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_pattern = NULL; if (ret) @@ -391,6 +368,7 @@ int iwl3945_led_register(struct iwl3945_priv *priv) trigger = ieee80211_get_tx_led_name(priv->hw); snprintf(name, sizeof(name), "iwl-%s:TX", wiphy_name(priv->hw->wiphy)); + ret = iwl3945_led_register_led(priv, &priv->led[IWL_LED_TRG_TX], IWL_LED_TRG_TX, 0, diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-led.h b/drivers/net/wireless/iwlwifi/iwl-3945-led.h index b1d2f6b8b259..47b7e0bac802 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945-led.h +++ b/drivers/net/wireless/iwlwifi/iwl-3945-led.h @@ -54,7 +54,7 @@ struct iwl3945_led { int (*led_on) (struct iwl3945_priv *priv, int led_id); int (*led_off) (struct iwl3945_priv *priv, int led_id); int (*led_pattern) (struct iwl3945_priv *priv, int led_id, - enum led_brightness brightness); + unsigned int idx); enum led_type type; unsigned int registered; diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-rs.c b/drivers/net/wireless/iwlwifi/iwl-3945-rs.c index 85c22641542d..10c64bdb314c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945-rs.c @@ -29,7 +29,6 @@ #include <linux/skbuff.h> #include <linux/wireless.h> #include <net/mac80211.h> -#include <net/ieee80211.h> #include <linux/netdevice.h> #include <linux/etherdevice.h> @@ -446,8 +445,7 @@ static int rs_adjust_next_rate(struct iwl3945_priv *priv, int rate) */ static void rs_tx_status(void *priv_rate, struct net_device *dev, - struct sk_buff *skb, - struct ieee80211_tx_status *tx_resp) + struct sk_buff *skb) { u8 retries, current_count; int scale_rate_index, first_index, last_index; @@ -458,14 +456,15 @@ static void rs_tx_status(void *priv_rate, struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); struct iwl3945_rs_sta *rs_sta; struct ieee80211_supported_band *sband; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); IWL_DEBUG_RATE("enter\n"); sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; - retries = tx_resp->retry_count; - first_index = tx_resp->control.tx_rate->hw_value; + retries = info->status.retry_count; + first_index = sband->bitrates[info->tx_rate_idx].hw_value; if ((first_index < 0) || (first_index >= IWL_RATE_COUNT)) { IWL_DEBUG_RATE("leave: Rate out of bounds: %d\n", first_index); return; @@ -526,11 +525,11 @@ static void rs_tx_status(void *priv_rate, /* Update the last index window with success/failure based on ACK */ IWL_DEBUG_RATE("Update rate %d with %s.\n", last_index, - (tx_resp->flags & IEEE80211_TX_STATUS_ACK) ? + (info->flags & IEEE80211_TX_STAT_ACK) ? "success" : "failure"); iwl3945_collect_tx_data(rs_sta, &rs_sta->win[last_index], - tx_resp->flags & IEEE80211_TX_STATUS_ACK, 1); + info->flags & IEEE80211_TX_STAT_ACK, 1); /* We updated the rate scale window -- if its been more than * flush_time since the last run, schedule the flush @@ -670,7 +669,7 @@ static void rs_get_rate(void *priv_rate, struct net_device *dev, is_multicast_ether_addr(hdr->addr1) || !sta || !sta->rate_ctrl_priv) { IWL_DEBUG_RATE("leave: No STA priv data to update!\n"); - sel->rate = rate_lowest(local, sband, sta); + sel->rate_idx = rate_lowest_index(local, sband, sta); rcu_read_unlock(); return; } @@ -814,7 +813,7 @@ static void rs_get_rate(void *priv_rate, struct net_device *dev, IWL_DEBUG_RATE("leave: %d\n", index); - sel->rate = &sband->bitrates[sta->txrate_idx]; + sel->rate_idx = sta->txrate_idx; } static struct rate_control_ops rs_ops = { diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c index 55ac850744b3..c2a76785b665 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945.c @@ -283,8 +283,7 @@ static void iwl3945_tx_queue_reclaim(struct iwl3945_priv *priv, q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd)) { tx_info = &txq->txb[txq->q.read_ptr]; - ieee80211_tx_status_irqsafe(priv->hw, tx_info->skb[0], - &tx_info->status); + ieee80211_tx_status_irqsafe(priv->hw, tx_info->skb[0]); tx_info->skb[0] = NULL; iwl3945_hw_txq_free_tfd(priv, txq); } @@ -306,7 +305,7 @@ static void iwl3945_rx_reply_tx(struct iwl3945_priv *priv, int txq_id = SEQ_TO_QUEUE(sequence); int index = SEQ_TO_INDEX(sequence); struct iwl3945_tx_queue *txq = &priv->txq[txq_id]; - struct ieee80211_tx_status *tx_status; + struct ieee80211_tx_info *info; struct iwl3945_tx_resp *tx_resp = (void *)&pkt->u.raw[0]; u32 status = le32_to_cpu(tx_resp->status); int rate_idx; @@ -319,19 +318,22 @@ static void iwl3945_rx_reply_tx(struct iwl3945_priv *priv, return; } - tx_status = &(txq->txb[txq->q.read_ptr].status); + info = IEEE80211_SKB_CB(txq->txb[txq->q.read_ptr].skb[0]); + memset(&info->status, 0, sizeof(info->status)); - tx_status->retry_count = tx_resp->failure_frame; + info->status.retry_count = tx_resp->failure_frame; /* tx_status->rts_retry_count = tx_resp->failure_rts; */ - tx_status->flags = ((status & TX_STATUS_MSK) == TX_STATUS_SUCCESS) ? - IEEE80211_TX_STATUS_ACK : 0; + info->flags |= ((status & TX_STATUS_MSK) == TX_STATUS_SUCCESS) ? + IEEE80211_TX_STAT_ACK : 0; IWL_DEBUG_TX("Tx queue %d Status %s (0x%08x) plcp rate %d retries %d\n", txq_id, iwl3945_get_tx_fail_reason(status), status, tx_resp->rate, tx_resp->failure_frame); rate_idx = iwl3945_hwrate_to_plcp_idx(tx_resp->rate); - tx_status->control.tx_rate = &priv->ieee_rates[rate_idx]; + if (info->band == IEEE80211_BAND_5GHZ) + rate_idx -= IWL_FIRST_OFDM_RATE; + info->tx_rate_idx = rate_idx; IWL_DEBUG_TX_REPLY("Tx queue reclaim %d\n", index); iwl3945_tx_queue_reclaim(priv, txq_id, index); @@ -386,7 +388,7 @@ static void iwl3945_dbg_report_frame(struct iwl3945_priv *priv, u32 print_dump = 0; /* set to 1 to dump all frames' contents */ u32 hundred = 0; u32 dataframe = 0; - u16 fc; + __le16 fc; u16 seq_ctl; u16 channel; u16 phy_flags; @@ -405,7 +407,7 @@ static void iwl3945_dbg_report_frame(struct iwl3945_priv *priv, u8 *data = IWL_RX_DATA(pkt); /* MAC header */ - fc = le16_to_cpu(header->frame_control); + fc = header->frame_control; seq_ctl = le16_to_cpu(header->seq_ctrl); /* metadata */ @@ -429,8 +431,8 @@ static void iwl3945_dbg_report_frame(struct iwl3945_priv *priv, /* if data frame is to us and all is good, * (optionally) print summary for only 1 out of every 100 */ - if (to_us && (fc & ~IEEE80211_FCTL_PROTECTED) == - (IEEE80211_FCTL_FROMDS | IEEE80211_FTYPE_DATA)) { + if (to_us && (fc & ~cpu_to_le16(IEEE80211_FCTL_PROTECTED)) == + cpu_to_le16(IEEE80211_FCTL_FROMDS | IEEE80211_FTYPE_DATA)) { dataframe = 1; if (!group100) print_summary = 1; /* print each frame */ @@ -453,13 +455,13 @@ static void iwl3945_dbg_report_frame(struct iwl3945_priv *priv, if (hundred) title = "100Frames"; - else if (fc & IEEE80211_FCTL_RETRY) + else if (ieee80211_has_retry(fc)) title = "Retry"; - else if (ieee80211_is_assoc_response(fc)) + else if (ieee80211_is_assoc_resp(fc)) title = "AscRsp"; - else if (ieee80211_is_reassoc_response(fc)) + else if (ieee80211_is_reassoc_resp(fc)) title = "RasRsp"; - else if (ieee80211_is_probe_response(fc)) { + else if (ieee80211_is_probe_resp(fc)) { title = "PrbRsp"; print_dump = 1; /* dump frame contents */ } else if (ieee80211_is_beacon(fc)) { @@ -488,14 +490,14 @@ static void iwl3945_dbg_report_frame(struct iwl3945_priv *priv, if (dataframe) IWL_DEBUG_RX("%s: mhd=0x%04x, dst=0x%02x, " "len=%u, rssi=%d, chnl=%d, rate=%d, \n", - title, fc, header->addr1[5], + title, le16_to_cpu(fc), header->addr1[5], length, rssi, channel, rate); else { /* src/dst addresses assume managed mode */ IWL_DEBUG_RX("%s: 0x%04x, dst=0x%02x, " "src=0x%02x, rssi=%u, tim=%lu usec, " "phy=0x%02x, chnl=%d\n", - title, fc, header->addr1[5], + title, le16_to_cpu(fc), header->addr1[5], header->addr3[5], rssi, tsf_low - priv->scan_start_tsf, phy_flags, channel); @@ -512,6 +514,23 @@ static inline void iwl3945_dbg_report_frame(struct iwl3945_priv *priv, } #endif +/* This is necessary only for a number of statistics, see the caller. */ +static int iwl3945_is_network_packet(struct iwl3945_priv *priv, + struct ieee80211_hdr *header) +{ + /* Filter incoming packets to determine if they are targeted toward + * this network, discarding packets coming from ourselves */ + switch (priv->iw_mode) { + case IEEE80211_IF_TYPE_IBSS: /* Header: Dest. | Source | BSSID */ + /* packets to our IBSS update information */ + return !compare_ether_addr(header->addr3, priv->bssid); + case IEEE80211_IF_TYPE_STA: /* Header: Dest. | AP{BSSID} | Source */ + /* packets to our IBSS update information */ + return !compare_ether_addr(header->addr2, priv->bssid); + default: + return 1; + } +} static void iwl3945_add_radiotap(struct iwl3945_priv *priv, struct sk_buff *skb, @@ -520,7 +539,7 @@ static void iwl3945_add_radiotap(struct iwl3945_priv *priv, { /* First cache any information we need before we overwrite * the information provided in the skb from the hardware */ - s8 signal = stats->ssi; + s8 signal = stats->signal; s8 noise = 0; int rate = stats->rate_idx; u64 tsf = stats->mactime; @@ -606,12 +625,12 @@ static void iwl3945_add_radiotap(struct iwl3945_priv *priv, stats->flag |= RX_FLAG_RADIOTAP; } -static void iwl3945_handle_data_packet(struct iwl3945_priv *priv, int is_data, +static void iwl3945_pass_packet_to_mac80211(struct iwl3945_priv *priv, struct iwl3945_rx_mem_buffer *rxb, struct ieee80211_rx_status *stats) { - struct ieee80211_hdr *hdr; struct iwl3945_rx_packet *pkt = (struct iwl3945_rx_packet *)rxb->skb->data; + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)IWL_RX_DATA(pkt); struct iwl3945_rx_frame_hdr *rx_hdr = IWL_RX_HDR(pkt); struct iwl3945_rx_frame_end *rx_end = IWL_RX_END(pkt); short len = le16_to_cpu(rx_hdr->len); @@ -633,8 +652,6 @@ static void iwl3945_handle_data_packet(struct iwl3945_priv *priv, int is_data, /* Set the size of the skb to the size of the frame */ skb_put(rxb->skb, le16_to_cpu(rx_hdr->len)); - hdr = (void *)rxb->skb->data; - if (iwl3945_param_hwcrypto) iwl3945_set_decrypted_flag(priv, rxb->skb, le32_to_cpu(rx_end->status), stats); @@ -643,7 +660,7 @@ static void iwl3945_handle_data_packet(struct iwl3945_priv *priv, int is_data, iwl3945_add_radiotap(priv, rxb->skb, rx_hdr, stats); #ifdef CONFIG_IWL3945_LEDS - if (is_data) + if (ieee80211_is_data(hdr->frame_control)) priv->rxtxpackets += len; #endif ieee80211_rx_irqsafe(priv->hw, rxb->skb, stats); @@ -692,12 +709,12 @@ static void iwl3945_rx_reply_rx(struct iwl3945_priv *priv, } if (priv->iw_mode == IEEE80211_IF_TYPE_MNTR) { - iwl3945_handle_data_packet(priv, 1, rxb, &rx_status); + iwl3945_pass_packet_to_mac80211(priv, rxb, &rx_status); return; } /* Convert 3945's rssi indicator to dBm */ - rx_status.ssi = rx_stats->rssi - IWL_RSSI_OFFSET; + rx_status.signal = rx_stats->rssi - IWL_RSSI_OFFSET; /* Set default noise value to -127 */ if (priv->last_rx_noise == 0) @@ -716,21 +733,21 @@ static void iwl3945_rx_reply_rx(struct iwl3945_priv *priv, * Calculate rx_status.signal (quality indicator in %) based on SNR. */ if (rx_stats_noise_diff) { snr = rx_stats_sig_avg / rx_stats_noise_diff; - rx_status.noise = rx_status.ssi - + rx_status.noise = rx_status.signal - iwl3945_calc_db_from_ratio(snr); - rx_status.signal = iwl3945_calc_sig_qual(rx_status.ssi, + rx_status.qual = iwl3945_calc_sig_qual(rx_status.signal, rx_status.noise); /* If noise info not available, calculate signal quality indicator (%) * using just the dBm signal level. */ } else { rx_status.noise = priv->last_rx_noise; - rx_status.signal = iwl3945_calc_sig_qual(rx_status.ssi, 0); + rx_status.qual = iwl3945_calc_sig_qual(rx_status.signal, 0); } IWL_DEBUG_STATS("Rssi %d noise %d qual %d sig_avg %d noise_diff %d\n", - rx_status.ssi, rx_status.noise, rx_status.signal, + rx_status.signal, rx_status.noise, rx_status.qual, rx_stats_sig_avg, rx_stats_noise_diff); header = (struct ieee80211_hdr *)IWL_RX_DATA(pkt); @@ -740,8 +757,8 @@ static void iwl3945_rx_reply_rx(struct iwl3945_priv *priv, IWL_DEBUG_STATS_LIMIT("[%c] %d RSSI:%d Signal:%u, Noise:%u, Rate:%u\n", network_packet ? '*' : ' ', le16_to_cpu(rx_hdr->channel), - rx_status.ssi, rx_status.ssi, - rx_status.ssi, rx_status.rate_idx); + rx_status.signal, rx_status.signal, + rx_status.noise, rx_status.rate_idx); #ifdef CONFIG_IWL3945_DEBUG if (iwl3945_debug_level & (IWL_DL_RX)) @@ -752,7 +769,7 @@ static void iwl3945_rx_reply_rx(struct iwl3945_priv *priv, if (network_packet) { priv->last_beacon_time = le32_to_cpu(rx_end->beacon_timestamp); priv->last_tsf = le64_to_cpu(rx_end->timestamp); - priv->last_rx_rssi = rx_status.ssi; + priv->last_rx_rssi = rx_status.signal; priv->last_rx_noise = rx_status.noise; } @@ -840,27 +857,12 @@ static void iwl3945_rx_reply_rx(struct iwl3945_priv *priv, } } - iwl3945_handle_data_packet(priv, 0, rxb, &rx_status); - break; - - case IEEE80211_FTYPE_CTL: - break; - - case IEEE80211_FTYPE_DATA: { - DECLARE_MAC_BUF(mac1); - DECLARE_MAC_BUF(mac2); - DECLARE_MAC_BUF(mac3); - - if (unlikely(iwl3945_is_duplicate_packet(priv, header))) - IWL_DEBUG_DROP("Dropping (dup): %s, %s, %s\n", - print_mac(mac1, header->addr1), - print_mac(mac2, header->addr2), - print_mac(mac3, header->addr3)); - else - iwl3945_handle_data_packet(priv, 1, rxb, &rx_status); + case IEEE80211_FTYPE_DATA: + /* fall through */ + default: + iwl3945_pass_packet_to_mac80211(priv, rxb, &rx_status); break; } - } } int iwl3945_hw_txq_attach_buf_to_tfd(struct iwl3945_priv *priv, void *ptr, @@ -962,23 +964,24 @@ u8 iwl3945_hw_find_station(struct iwl3945_priv *priv, const u8 *addr) */ void iwl3945_hw_build_tx_cmd_rate(struct iwl3945_priv *priv, struct iwl3945_cmd *cmd, - struct ieee80211_tx_control *ctrl, + struct ieee80211_tx_info *info, struct ieee80211_hdr *hdr, int sta_id, int tx_id) { unsigned long flags; - u16 rate_index = min(ctrl->tx_rate->hw_value & 0xffff, IWL_RATE_COUNT - 1); + u16 hw_value = ieee80211_get_tx_rate(priv->hw, info)->hw_value; + u16 rate_index = min(hw_value & 0xffff, IWL_RATE_COUNT - 1); u16 rate_mask; int rate; u8 rts_retry_limit; u8 data_retry_limit; __le32 tx_flags; - u16 fc = le16_to_cpu(hdr->frame_control); + __le16 fc = hdr->frame_control; rate = iwl3945_rates[rate_index].plcp; tx_flags = cmd->cmd.tx.tx_flags; /* We need to figure out how to get the sta->supp_rates while - * in this running context; perhaps encoding into ctrl->tx_rate? */ + * in this running context */ rate_mask = IWL_RATES_MASK; spin_lock_irqsave(&priv->sta_lock, flags); @@ -997,7 +1000,7 @@ void iwl3945_hw_build_tx_cmd_rate(struct iwl3945_priv *priv, else rts_retry_limit = 7; - if (ieee80211_is_probe_response(fc)) { + if (ieee80211_is_probe_resp(fc)) { data_retry_limit = 3; if (data_retry_limit < rts_retry_limit) rts_retry_limit = data_retry_limit; @@ -1007,12 +1010,12 @@ void iwl3945_hw_build_tx_cmd_rate(struct iwl3945_priv *priv, if (priv->data_retry_limit != -1) data_retry_limit = priv->data_retry_limit; - if ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT) { - switch (fc & IEEE80211_FCTL_STYPE) { - case IEEE80211_STYPE_AUTH: - case IEEE80211_STYPE_DEAUTH: - case IEEE80211_STYPE_ASSOC_REQ: - case IEEE80211_STYPE_REASSOC_REQ: + if (ieee80211_is_mgmt(fc)) { + switch (fc & cpu_to_le16(IEEE80211_FCTL_STYPE)) { + case cpu_to_le16(IEEE80211_STYPE_AUTH): + case cpu_to_le16(IEEE80211_STYPE_DEAUTH): + case cpu_to_le16(IEEE80211_STYPE_ASSOC_REQ): + case cpu_to_le16(IEEE80211_STYPE_REASSOC_REQ): if (tx_flags & TX_CMD_FLG_RTS_MSK) { tx_flags &= ~TX_CMD_FLG_RTS_MSK; tx_flags |= TX_CMD_FLG_CTS_MSK; @@ -1233,7 +1236,7 @@ int iwl3945_hw_nic_init(struct iwl3945_priv *priv) iwl3945_power_init_handle(priv); spin_lock_irqsave(&priv->lock, flags); - iwl3945_set_bit(priv, CSR_ANA_PLL_CFG, (1 << 24)); + iwl3945_set_bit(priv, CSR_ANA_PLL_CFG, CSR39_ANA_PLL_CFG_VAL); iwl3945_set_bit(priv, CSR_GIO_CHICKEN_BITS, CSR_GIO_CHICKEN_BITS_REG_BIT_L1A_NO_L0S_RX); diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.h b/drivers/net/wireless/iwlwifi/iwl-3945.h index c7695a215a39..fa81ba1af3d3 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.h +++ b/drivers/net/wireless/iwlwifi/iwl-3945.h @@ -36,6 +36,10 @@ #include <linux/kernel.h> #include <net/ieee80211_radiotap.h> +/*used for rfkill*/ +#include <linux/rfkill.h> +#include <linux/input.h> + /* Hardware specific file defines the PCI IDs table for that hardware module */ extern struct pci_device_id iwl3945_hw_card_ids[]; @@ -124,7 +128,6 @@ int iwl3945_x2_queue_used(const struct iwl3945_queue *q, int i); /* One for each TFD */ struct iwl3945_tx_info { - struct ieee80211_tx_status status; struct sk_buff *skb[MAX_NUM_OF_TBS]; }; @@ -507,8 +510,6 @@ struct iwl3945_ucode { u8 data[0]; /* data in same order as "size" elements */ }; -#define IWL_IBSS_MAC_HASH_SIZE 32 - struct iwl3945_ibss_seq { u8 mac[ETH_ALEN]; u16 seq_num; @@ -566,17 +567,8 @@ extern int iwl3945_send_add_station(struct iwl3945_priv *priv, struct iwl3945_addsta_cmd *sta, u8 flags); extern u8 iwl3945_add_station(struct iwl3945_priv *priv, const u8 *bssid, int is_ap, u8 flags); -extern int iwl3945_is_network_packet(struct iwl3945_priv *priv, - struct ieee80211_hdr *header); extern int iwl3945_power_init_handle(struct iwl3945_priv *priv); extern int iwl3945_eeprom_init(struct iwl3945_priv *priv); -extern void iwl3945_handle_data_packet_monitor(struct iwl3945_priv *priv, - struct iwl3945_rx_mem_buffer *rxb, - void *data, short len, - struct ieee80211_rx_status *stats, - u16 phy_flags); -extern int iwl3945_is_duplicate_packet(struct iwl3945_priv *priv, - struct ieee80211_hdr *header); extern int iwl3945_rx_queue_alloc(struct iwl3945_priv *priv); extern void iwl3945_rx_queue_reset(struct iwl3945_priv *priv, struct iwl3945_rx_queue *rxq); @@ -645,7 +637,7 @@ extern unsigned int iwl3945_hw_get_beacon_cmd(struct iwl3945_priv *priv, extern int iwl3945_hw_get_rx_read(struct iwl3945_priv *priv); extern void iwl3945_hw_build_tx_cmd_rate(struct iwl3945_priv *priv, struct iwl3945_cmd *cmd, - struct ieee80211_tx_control *ctrl, + struct ieee80211_tx_info *info, struct ieee80211_hdr *hdr, int sta_id, int tx_id); extern int iwl3945_hw_reg_send_txpower(struct iwl3945_priv *priv); @@ -687,6 +679,18 @@ enum { #endif +#ifdef CONFIG_IWL3945_RFKILL +struct iwl3945_priv; + +void iwl3945_rfkill_set_hw_state(struct iwl3945_priv *priv); +void iwl3945_rfkill_unregister(struct iwl3945_priv *priv); +int iwl3945_rfkill_init(struct iwl3945_priv *priv); +#else +static inline void iwl3945_rfkill_set_hw_state(struct iwl3945_priv *priv) {} +static inline void iwl3945_rfkill_unregister(struct iwl3945_priv *priv) {} +static inline int iwl3945_rfkill_init(struct iwl3945_priv *priv) { return 0; } +#endif + #define IWL_MAX_NUM_QUEUES IWL39_MAX_NUM_QUEUES struct iwl3945_priv { @@ -780,12 +784,17 @@ struct iwl3945_priv { struct iwl3945_init_alive_resp card_alive_init; struct iwl3945_alive_resp card_alive; +#ifdef CONFIG_IWL3945_RFKILL + struct rfkill *rfkill; +#endif + #ifdef CONFIG_IWL3945_LEDS struct iwl3945_led led[IWL_LED_TRG_MAX]; unsigned long last_blink_time; u8 last_blink_rate; u8 allow_blinking; unsigned int rxtxpackets; + u64 led_tpt; #endif @@ -836,20 +845,10 @@ struct iwl3945_priv { u8 mac80211_registered; - u32 notif_missed_beacons; - /* Rx'd packet timing information */ u32 last_beacon_time; u64 last_tsf; - /* Duplicate packet detection */ - u16 last_seq_num; - u16 last_frag_num; - unsigned long last_packet_time; - - /* Hash table for finding stations in IBSS network */ - struct list_head ibss_mac_hash[IWL_IBSS_MAC_HASH_SIZE]; - /* eeprom */ struct iwl3945_eeprom eeprom; @@ -886,6 +885,7 @@ struct iwl3945_priv { struct work_struct report_work; struct work_struct request_scan; struct work_struct beacon_update; + struct work_struct set_monitor; struct tasklet_struct irq_tasklet; @@ -924,11 +924,6 @@ static inline int is_channel_valid(const struct iwl3945_channel_info *ch_info) return (ch_info->flags & EEPROM_CHANNEL_VALID) ? 1 : 0; } -static inline int is_channel_narrow(const struct iwl3945_channel_info *ch_info) -{ - return (ch_info->flags & EEPROM_CHANNEL_NARROW) ? 1 : 0; -} - static inline int is_channel_radar(const struct iwl3945_channel_info *ch_info) { return (ch_info->flags & EEPROM_CHANNEL_RADAR) ? 1 : 0; diff --git a/drivers/net/wireless/iwlwifi/iwl-4965-hw.h b/drivers/net/wireless/iwlwifi/iwl-4965-hw.h index 1a66b508a8ea..fce950f4163c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965-hw.h +++ b/drivers/net/wireless/iwlwifi/iwl-4965-hw.h @@ -62,13 +62,18 @@ *****************************************************************************/ /* * Please use this file (iwl-4965-hw.h) only for hardware-related definitions. - * Use iwl-4965-commands.h for uCode API definitions. - * Use iwl-4965.h for driver implementation definitions. + * Use iwl-commands.h for uCode API definitions. + * Use iwl-dev.h for driver implementation definitions. */ #ifndef __iwl_4965_hw_h__ #define __iwl_4965_hw_h__ +#include "iwl-fh.h" + +/* EERPROM */ +#define IWL4965_EEPROM_IMG_SIZE 1024 + /* * uCode queue management definitions ... * Queue #4 is the command queue for 3945 and 4965; map it to Tx FIFO chnl 4. @@ -77,7 +82,7 @@ */ #define IWL_CMD_QUEUE_NUM 4 #define IWL_CMD_FIFO_NUM 4 -#define IWL_BACK_QUEUE_FIRST_ID 7 +#define IWL49_FIRST_AMPDU_QUEUE 7 /* Tx rates */ #define IWL_CCK_RATES 4 @@ -93,11 +98,16 @@ #define IWL_RSSI_OFFSET 44 -#include "iwl-4965-commands.h" +#include "iwl-commands.h" -#define PCI_LINK_CTRL 0x0F0 +/* PCI registers */ +#define PCI_LINK_CTRL 0x0F0 /* 1 byte */ #define PCI_POWER_SOURCE 0x0C8 #define PCI_REG_WUM8 0x0E8 + +/* PCI register values */ +#define PCI_LINK_VAL_L0S_EN 0x01 +#define PCI_LINK_VAL_L1_EN 0x02 #define PCI_CFG_PMC_PME_FROM_D3COLD_SUPPORT (0x80000000) #define TFD_QUEUE_SIZE_MAX (256) @@ -131,10 +141,8 @@ #define RTC_DATA_LOWER_BOUND (0x800000) #define IWL49_RTC_DATA_UPPER_BOUND (0x80A000) -#define IWL49_RTC_INST_SIZE \ - (IWL49_RTC_INST_UPPER_BOUND - RTC_INST_LOWER_BOUND) -#define IWL49_RTC_DATA_SIZE \ - (IWL49_RTC_DATA_UPPER_BOUND - RTC_DATA_LOWER_BOUND) +#define IWL49_RTC_INST_SIZE (IWL49_RTC_INST_UPPER_BOUND - RTC_INST_LOWER_BOUND) +#define IWL49_RTC_DATA_SIZE (IWL49_RTC_DATA_UPPER_BOUND - RTC_DATA_LOWER_BOUND) #define IWL_MAX_INST_SIZE IWL49_RTC_INST_SIZE #define IWL_MAX_DATA_SIZE IWL49_RTC_DATA_SIZE @@ -785,585 +793,6 @@ enum { /********************* END TXPOWER *****************************************/ -/****************************/ -/* Flow Handler Definitions */ -/****************************/ - -/** - * This I/O area is directly read/writable by driver (e.g. Linux uses writel()) - * Addresses are offsets from device's PCI hardware base address. - */ -#define FH_MEM_LOWER_BOUND (0x1000) -#define FH_MEM_UPPER_BOUND (0x1EF0) - -/** - * Keep-Warm (KW) buffer base address. - * - * Driver must allocate a 4KByte buffer that is used by 4965 for keeping the - * host DRAM powered on (via dummy accesses to DRAM) to maintain low-latency - * DRAM access when 4965 is Txing or Rxing. The dummy accesses prevent host - * from going into a power-savings mode that would cause higher DRAM latency, - * and possible data over/under-runs, before all Tx/Rx is complete. - * - * Driver loads IWL_FH_KW_MEM_ADDR_REG with the physical address (bits 35:4) - * of the buffer, which must be 4K aligned. Once this is set up, the 4965 - * automatically invokes keep-warm accesses when normal accesses might not - * be sufficient to maintain fast DRAM response. - * - * Bit fields: - * 31-0: Keep-warm buffer physical base address [35:4], must be 4K aligned - */ -#define IWL_FH_KW_MEM_ADDR_REG (FH_MEM_LOWER_BOUND + 0x97C) - - -/** - * TFD Circular Buffers Base (CBBC) addresses - * - * 4965 has 16 base pointer registers, one for each of 16 host-DRAM-resident - * circular buffers (CBs/queues) containing Transmit Frame Descriptors (TFDs) - * (see struct iwl_tfd_frame). These 16 pointer registers are offset by 0x04 - * bytes from one another. Each TFD circular buffer in DRAM must be 256-byte - * aligned (address bits 0-7 must be 0). - * - * Bit fields in each pointer register: - * 27-0: TFD CB physical base address [35:8], must be 256-byte aligned - */ -#define FH_MEM_CBBC_LOWER_BOUND (FH_MEM_LOWER_BOUND + 0x9D0) -#define FH_MEM_CBBC_UPPER_BOUND (FH_MEM_LOWER_BOUND + 0xA10) - -/* Find TFD CB base pointer for given queue (range 0-15). */ -#define FH_MEM_CBBC_QUEUE(x) (FH_MEM_CBBC_LOWER_BOUND + (x) * 0x4) - - -/** - * Rx SRAM Control and Status Registers (RSCSR) - * - * These registers provide handshake between driver and 4965 for the Rx queue - * (this queue handles *all* command responses, notifications, Rx data, etc. - * sent from 4965 uCode to host driver). Unlike Tx, there is only one Rx - * queue, and only one Rx DMA/FIFO channel. Also unlike Tx, which can - * concatenate up to 20 DRAM buffers to form a Tx frame, each Receive Buffer - * Descriptor (RBD) points to only one Rx Buffer (RB); there is a 1:1 - * mapping between RBDs and RBs. - * - * Driver must allocate host DRAM memory for the following, and set the - * physical address of each into 4965 registers: - * - * 1) Receive Buffer Descriptor (RBD) circular buffer (CB), typically with 256 - * entries (although any power of 2, up to 4096, is selectable by driver). - * Each entry (1 dword) points to a receive buffer (RB) of consistent size - * (typically 4K, although 8K or 16K are also selectable by driver). - * Driver sets up RB size and number of RBDs in the CB via Rx config - * register FH_MEM_RCSR_CHNL0_CONFIG_REG. - * - * Bit fields within one RBD: - * 27-0: Receive Buffer physical address bits [35:8], 256-byte aligned - * - * Driver sets physical address [35:8] of base of RBD circular buffer - * into FH_RSCSR_CHNL0_RBDCB_BASE_REG [27:0]. - * - * 2) Rx status buffer, 8 bytes, in which 4965 indicates which Rx Buffers - * (RBs) have been filled, via a "write pointer", actually the index of - * the RB's corresponding RBD within the circular buffer. Driver sets - * physical address [35:4] into FH_RSCSR_CHNL0_STTS_WPTR_REG [31:0]. - * - * Bit fields in lower dword of Rx status buffer (upper dword not used - * by driver; see struct iwl4965_shared, val0): - * 31-12: Not used by driver - * 11- 0: Index of last filled Rx buffer descriptor - * (4965 writes, driver reads this value) - * - * As the driver prepares Receive Buffers (RBs) for 4965 to fill, driver must - * enter pointers to these RBs into contiguous RBD circular buffer entries, - * and update the 4965's "write" index register, FH_RSCSR_CHNL0_RBDCB_WPTR_REG. - * - * This "write" index corresponds to the *next* RBD that the driver will make - * available, i.e. one RBD past the tail of the ready-to-fill RBDs within - * the circular buffer. This value should initially be 0 (before preparing any - * RBs), should be 8 after preparing the first 8 RBs (for example), and must - * wrap back to 0 at the end of the circular buffer (but don't wrap before - * "read" index has advanced past 1! See below). - * NOTE: 4965 EXPECTS THE WRITE INDEX TO BE INCREMENTED IN MULTIPLES OF 8. - * - * As the 4965 fills RBs (referenced from contiguous RBDs within the circular - * buffer), it updates the Rx status buffer in host DRAM, 2) described above, - * to tell the driver the index of the latest filled RBD. The driver must - * read this "read" index from DRAM after receiving an Rx interrupt from 4965. - * - * The driver must also internally keep track of a third index, which is the - * next RBD to process. When receiving an Rx interrupt, driver should process - * all filled but unprocessed RBs up to, but not including, the RB - * corresponding to the "read" index. For example, if "read" index becomes "1", - * driver may process the RB pointed to by RBD 0. Depending on volume of - * traffic, there may be many RBs to process. - * - * If read index == write index, 4965 thinks there is no room to put new data. - * Due to this, the maximum number of filled RBs is 255, instead of 256. To - * be safe, make sure that there is a gap of at least 2 RBDs between "write" - * and "read" indexes; that is, make sure that there are no more than 254 - * buffers waiting to be filled. - */ -#define FH_MEM_RSCSR_LOWER_BOUND (FH_MEM_LOWER_BOUND + 0xBC0) -#define FH_MEM_RSCSR_UPPER_BOUND (FH_MEM_LOWER_BOUND + 0xC00) -#define FH_MEM_RSCSR_CHNL0 (FH_MEM_RSCSR_LOWER_BOUND) - -/** - * Physical base address of 8-byte Rx Status buffer. - * Bit fields: - * 31-0: Rx status buffer physical base address [35:4], must 16-byte aligned. - */ -#define FH_RSCSR_CHNL0_STTS_WPTR_REG (FH_MEM_RSCSR_CHNL0) - -/** - * Physical base address of Rx Buffer Descriptor Circular Buffer. - * Bit fields: - * 27-0: RBD CD physical base address [35:8], must be 256-byte aligned. - */ -#define FH_RSCSR_CHNL0_RBDCB_BASE_REG (FH_MEM_RSCSR_CHNL0 + 0x004) - -/** - * Rx write pointer (index, really!). - * Bit fields: - * 11-0: Index of driver's most recent prepared-to-be-filled RBD, + 1. - * NOTE: For 256-entry circular buffer, use only bits [7:0]. - */ -#define FH_RSCSR_CHNL0_RBDCB_WPTR_REG (FH_MEM_RSCSR_CHNL0 + 0x008) -#define FH_RSCSR_CHNL0_WPTR (FH_RSCSR_CHNL0_RBDCB_WPTR_REG) - - -/** - * Rx Config/Status Registers (RCSR) - * Rx Config Reg for channel 0 (only channel used) - * - * Driver must initialize FH_MEM_RCSR_CHNL0_CONFIG_REG as follows for - * normal operation (see bit fields). - * - * Clearing FH_MEM_RCSR_CHNL0_CONFIG_REG to 0 turns off Rx DMA. - * Driver should poll FH_MEM_RSSR_RX_STATUS_REG for - * FH_RSSR_CHNL0_RX_STATUS_CHNL_IDLE (bit 24) before continuing. - * - * Bit fields: - * 31-30: Rx DMA channel enable: '00' off/pause, '01' pause at end of frame, - * '10' operate normally - * 29-24: reserved - * 23-20: # RBDs in circular buffer = 2^value; use "8" for 256 RBDs (normal), - * min "5" for 32 RBDs, max "12" for 4096 RBDs. - * 19-18: reserved - * 17-16: size of each receive buffer; '00' 4K (normal), '01' 8K, - * '10' 12K, '11' 16K. - * 15-14: reserved - * 13-12: IRQ destination; '00' none, '01' host driver (normal operation) - * 11- 4: timeout for closing Rx buffer and interrupting host (units 32 usec) - * typical value 0x10 (about 1/2 msec) - * 3- 0: reserved - */ -#define FH_MEM_RCSR_LOWER_BOUND (FH_MEM_LOWER_BOUND + 0xC00) -#define FH_MEM_RCSR_UPPER_BOUND (FH_MEM_LOWER_BOUND + 0xCC0) -#define FH_MEM_RCSR_CHNL0 (FH_MEM_RCSR_LOWER_BOUND) - -#define FH_MEM_RCSR_CHNL0_CONFIG_REG (FH_MEM_RCSR_CHNL0) - -#define FH_RCSR_CHNL0_RX_CONFIG_RB_TIMEOUT_MASK (0x00000FF0) /* bit 4-11 */ -#define FH_RCSR_CHNL0_RX_CONFIG_IRQ_DEST_MASK (0x00001000) /* bit 12 */ -#define FH_RCSR_CHNL0_RX_CONFIG_SINGLE_FRAME_MASK (0x00008000) /* bit 15 */ -#define FH_RCSR_CHNL0_RX_CONFIG_RB_SIZE_MASK (0x00030000) /* bits 16-17 */ -#define FH_RCSR_CHNL0_RX_CONFIG_RBDBC_SIZE_MASK (0x00F00000) /* bits 20-23 */ -#define FH_RCSR_CHNL0_RX_CONFIG_DMA_CHNL_EN_MASK (0xC0000000) /* bits 30-31 */ - -#define FH_RCSR_RX_CONFIG_RBDCB_SIZE_BITSHIFT (20) -#define FH_RCSR_RX_CONFIG_REG_IRQ_RBTH_BITSHIFT (4) -#define RX_RB_TIMEOUT (0x10) - -#define FH_RCSR_RX_CONFIG_CHNL_EN_PAUSE_VAL (0x00000000) -#define FH_RCSR_RX_CONFIG_CHNL_EN_PAUSE_EOF_VAL (0x40000000) -#define FH_RCSR_RX_CONFIG_CHNL_EN_ENABLE_VAL (0x80000000) - -#define FH_RCSR_RX_CONFIG_REG_VAL_RB_SIZE_4K (0x00000000) -#define FH_RCSR_RX_CONFIG_REG_VAL_RB_SIZE_8K (0x00010000) -#define FH_RCSR_RX_CONFIG_REG_VAL_RB_SIZE_12K (0x00020000) -#define FH_RCSR_RX_CONFIG_REG_VAL_RB_SIZE_16K (0x00030000) - -#define FH_RCSR_CHNL0_RX_CONFIG_IRQ_DEST_NO_INT_VAL (0x00000000) -#define FH_RCSR_CHNL0_RX_CONFIG_IRQ_DEST_INT_HOST_VAL (0x00001000) - - -/** - * Rx Shared Status Registers (RSSR) - * - * After stopping Rx DMA channel (writing 0 to FH_MEM_RCSR_CHNL0_CONFIG_REG), - * driver must poll FH_MEM_RSSR_RX_STATUS_REG until Rx channel is idle. - * - * Bit fields: - * 24: 1 = Channel 0 is idle - * - * FH_MEM_RSSR_SHARED_CTRL_REG and FH_MEM_RSSR_RX_ENABLE_ERR_IRQ2DRV contain - * default values that should not be altered by the driver. - */ -#define FH_MEM_RSSR_LOWER_BOUND (FH_MEM_LOWER_BOUND + 0xC40) -#define FH_MEM_RSSR_UPPER_BOUND (FH_MEM_LOWER_BOUND + 0xD00) - -#define FH_MEM_RSSR_SHARED_CTRL_REG (FH_MEM_RSSR_LOWER_BOUND) -#define FH_MEM_RSSR_RX_STATUS_REG (FH_MEM_RSSR_LOWER_BOUND + 0x004) -#define FH_MEM_RSSR_RX_ENABLE_ERR_IRQ2DRV (FH_MEM_RSSR_LOWER_BOUND + 0x008) - -#define FH_RSSR_CHNL0_RX_STATUS_CHNL_IDLE (0x01000000) - - -/** - * Transmit DMA Channel Control/Status Registers (TCSR) - * - * 4965 has one configuration register for each of 8 Tx DMA/FIFO channels - * supported in hardware (don't confuse these with the 16 Tx queues in DRAM, - * which feed the DMA/FIFO channels); config regs are separated by 0x20 bytes. - * - * To use a Tx DMA channel, driver must initialize its - * IWL_FH_TCSR_CHNL_TX_CONFIG_REG(chnl) with: - * - * IWL_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE | - * IWL_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_ENABLE_VAL - * - * All other bits should be 0. - * - * Bit fields: - * 31-30: Tx DMA channel enable: '00' off/pause, '01' pause at end of frame, - * '10' operate normally - * 29- 4: Reserved, set to "0" - * 3: Enable internal DMA requests (1, normal operation), disable (0) - * 2- 0: Reserved, set to "0" - */ -#define IWL_FH_TCSR_LOWER_BOUND (FH_MEM_LOWER_BOUND + 0xD00) -#define IWL_FH_TCSR_UPPER_BOUND (FH_MEM_LOWER_BOUND + 0xE60) - -/* Find Control/Status reg for given Tx DMA/FIFO channel */ -#define IWL_FH_TCSR_CHNL_TX_CONFIG_REG(_chnl) \ - (IWL_FH_TCSR_LOWER_BOUND + 0x20 * _chnl) - -#define IWL_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_DISABLE_VAL (0x00000000) -#define IWL_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_ENABLE_VAL (0x00000008) - -#define IWL_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_PAUSE (0x00000000) -#define IWL_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_PAUSE_EOF (0x40000000) -#define IWL_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE (0x80000000) - -/** - * Tx Shared Status Registers (TSSR) - * - * After stopping Tx DMA channel (writing 0 to - * IWL_FH_TCSR_CHNL_TX_CONFIG_REG(chnl)), driver must poll - * IWL_FH_TSSR_TX_STATUS_REG until selected Tx channel is idle - * (channel's buffers empty | no pending requests). - * - * Bit fields: - * 31-24: 1 = Channel buffers empty (channel 7:0) - * 23-16: 1 = No pending requests (channel 7:0) - */ -#define IWL_FH_TSSR_LOWER_BOUND (FH_MEM_LOWER_BOUND + 0xEA0) -#define IWL_FH_TSSR_UPPER_BOUND (FH_MEM_LOWER_BOUND + 0xEC0) - -#define IWL_FH_TSSR_TX_STATUS_REG (IWL_FH_TSSR_LOWER_BOUND + 0x010) - -#define IWL_FH_TSSR_TX_STATUS_REG_BIT_BUFS_EMPTY(_chnl) \ - ((1 << (_chnl)) << 24) -#define IWL_FH_TSSR_TX_STATUS_REG_BIT_NO_PEND_REQ(_chnl) \ - ((1 << (_chnl)) << 16) - -#define IWL_FH_TSSR_TX_STATUS_REG_MSK_CHNL_IDLE(_chnl) \ - (IWL_FH_TSSR_TX_STATUS_REG_BIT_BUFS_EMPTY(_chnl) | \ - IWL_FH_TSSR_TX_STATUS_REG_BIT_NO_PEND_REQ(_chnl)) - - -/********************* START TX SCHEDULER *************************************/ - -/** - * 4965 Tx Scheduler - * - * The Tx Scheduler selects the next frame to be transmitted, chosing TFDs - * (Transmit Frame Descriptors) from up to 16 circular Tx queues resident in - * host DRAM. It steers each frame's Tx command (which contains the frame - * data) into one of up to 7 prioritized Tx DMA FIFO channels within the - * device. A queue maps to only one (selectable by driver) Tx DMA channel, - * but one DMA channel may take input from several queues. - * - * Tx DMA channels have dedicated purposes. For 4965, they are used as follows: - * - * 0 -- EDCA BK (background) frames, lowest priority - * 1 -- EDCA BE (best effort) frames, normal priority - * 2 -- EDCA VI (video) frames, higher priority - * 3 -- EDCA VO (voice) and management frames, highest priority - * 4 -- Commands (e.g. RXON, etc.) - * 5 -- HCCA short frames - * 6 -- HCCA long frames - * 7 -- not used by driver (device-internal only) - * - * Driver should normally map queues 0-6 to Tx DMA/FIFO channels 0-6. - * In addition, driver can map queues 7-15 to Tx DMA/FIFO channels 0-3 to - * support 11n aggregation via EDCA DMA channels. - * - * The driver sets up each queue to work in one of two modes: - * - * 1) Scheduler-Ack, in which the scheduler automatically supports a - * block-ack (BA) window of up to 64 TFDs. In this mode, each queue - * contains TFDs for a unique combination of Recipient Address (RA) - * and Traffic Identifier (TID), that is, traffic of a given - * Quality-Of-Service (QOS) priority, destined for a single station. - * - * In scheduler-ack mode, the scheduler keeps track of the Tx status of - * each frame within the BA window, including whether it's been transmitted, - * and whether it's been acknowledged by the receiving station. The device - * automatically processes block-acks received from the receiving STA, - * and reschedules un-acked frames to be retransmitted (successful - * Tx completion may end up being out-of-order). - * - * The driver must maintain the queue's Byte Count table in host DRAM - * (struct iwl4965_sched_queue_byte_cnt_tbl) for this mode. - * This mode does not support fragmentation. - * - * 2) FIFO (a.k.a. non-Scheduler-ACK), in which each TFD is processed in order. - * The device may automatically retry Tx, but will retry only one frame - * at a time, until receiving ACK from receiving station, or reaching - * retry limit and giving up. - * - * The command queue (#4) must use this mode! - * This mode does not require use of the Byte Count table in host DRAM. - * - * Driver controls scheduler operation via 3 means: - * 1) Scheduler registers - * 2) Shared scheduler data base in internal 4956 SRAM - * 3) Shared data in host DRAM - * - * Initialization: - * - * When loading, driver should allocate memory for: - * 1) 16 TFD circular buffers, each with space for (typically) 256 TFDs. - * 2) 16 Byte Count circular buffers in 16 KBytes contiguous memory - * (1024 bytes for each queue). - * - * After receiving "Alive" response from uCode, driver must initialize - * the scheduler (especially for queue #4, the command queue, otherwise - * the driver can't issue commands!): - */ - -/** - * Max Tx window size is the max number of contiguous TFDs that the scheduler - * can keep track of at one time when creating block-ack chains of frames. - * Note that "64" matches the number of ack bits in a block-ack packet. - * Driver should use SCD_WIN_SIZE and SCD_FRAME_LIMIT values to initialize - * SCD_CONTEXT_QUEUE_OFFSET(x) values. - */ -#define SCD_WIN_SIZE 64 -#define SCD_FRAME_LIMIT 64 - -/* SCD registers are internal, must be accessed via HBUS_TARG_PRPH regs */ -#define SCD_START_OFFSET 0xa02c00 - -/* - * 4965 tells driver SRAM address for internal scheduler structs via this reg. - * Value is valid only after "Alive" response from uCode. - */ -#define SCD_SRAM_BASE_ADDR (SCD_START_OFFSET + 0x0) - -/* - * Driver may need to update queue-empty bits after changing queue's - * write and read pointers (indexes) during (re-)initialization (i.e. when - * scheduler is not tracking what's happening). - * Bit fields: - * 31-16: Write mask -- 1: update empty bit, 0: don't change empty bit - * 15-00: Empty state, one for each queue -- 1: empty, 0: non-empty - * NOTE: This register is not used by Linux driver. - */ -#define SCD_EMPTY_BITS (SCD_START_OFFSET + 0x4) - -/* - * Physical base address of array of byte count (BC) circular buffers (CBs). - * Each Tx queue has a BC CB in host DRAM to support Scheduler-ACK mode. - * This register points to BC CB for queue 0, must be on 1024-byte boundary. - * Others are spaced by 1024 bytes. - * Each BC CB is 2 bytes * (256 + 64) = 740 bytes, followed by 384 bytes pad. - * (Index into a queue's BC CB) = (index into queue's TFD CB) = (SSN & 0xff). - * Bit fields: - * 25-00: Byte Count CB physical address [35:10], must be 1024-byte aligned. - */ -#define SCD_DRAM_BASE_ADDR (SCD_START_OFFSET + 0x10) - -/* - * Enables any/all Tx DMA/FIFO channels. - * Scheduler generates requests for only the active channels. - * Set this to 0xff to enable all 8 channels (normal usage). - * Bit fields: - * 7- 0: Enable (1), disable (0), one bit for each channel 0-7 - */ -#define SCD_TXFACT (SCD_START_OFFSET + 0x1c) - -/* Mask to enable contiguous Tx DMA/FIFO channels between "lo" and "hi". */ -#define SCD_TXFACT_REG_TXFIFO_MASK(lo, hi) \ - ((1 << (hi)) | ((1 << (hi)) - (1 << (lo)))) - -/* - * Queue (x) Write Pointers (indexes, really!), one for each Tx queue. - * Initialized and updated by driver as new TFDs are added to queue. - * NOTE: If using Block Ack, index must correspond to frame's - * Start Sequence Number; index = (SSN & 0xff) - * NOTE: Alternative to HBUS_TARG_WRPTR, which is what Linux driver uses? - */ -#define SCD_QUEUE_WRPTR(x) (SCD_START_OFFSET + 0x24 + (x) * 4) - -/* - * Queue (x) Read Pointers (indexes, really!), one for each Tx queue. - * For FIFO mode, index indicates next frame to transmit. - * For Scheduler-ACK mode, index indicates first frame in Tx window. - * Initialized by driver, updated by scheduler. - */ -#define SCD_QUEUE_RDPTR(x) (SCD_START_OFFSET + 0x64 + (x) * 4) - -/* - * Select which queues work in chain mode (1) vs. not (0). - * Use chain mode to build chains of aggregated frames. - * Bit fields: - * 31-16: Reserved - * 15-00: Mode, one bit for each queue -- 1: Chain mode, 0: one-at-a-time - * NOTE: If driver sets up queue for chain mode, it should be also set up - * Scheduler-ACK mode as well, via SCD_QUEUE_STATUS_BITS(x). - */ -#define SCD_QUEUECHAIN_SEL (SCD_START_OFFSET + 0xd0) - -/* - * Select which queues interrupt driver when scheduler increments - * a queue's read pointer (index). - * Bit fields: - * 31-16: Reserved - * 15-00: Interrupt enable, one bit for each queue -- 1: enabled, 0: disabled - * NOTE: This functionality is apparently a no-op; driver relies on interrupts - * from Rx queue to read Tx command responses and update Tx queues. - */ -#define SCD_INTERRUPT_MASK (SCD_START_OFFSET + 0xe4) - -/* - * Queue search status registers. One for each queue. - * Sets up queue mode and assigns queue to Tx DMA channel. - * Bit fields: - * 19-10: Write mask/enable bits for bits 0-9 - * 9: Driver should init to "0" - * 8: Scheduler-ACK mode (1), non-Scheduler-ACK (i.e. FIFO) mode (0). - * Driver should init to "1" for aggregation mode, or "0" otherwise. - * 7-6: Driver should init to "0" - * 5: Window Size Left; indicates whether scheduler can request - * another TFD, based on window size, etc. Driver should init - * this bit to "1" for aggregation mode, or "0" for non-agg. - * 4-1: Tx FIFO to use (range 0-7). - * 0: Queue is active (1), not active (0). - * Other bits should be written as "0" - * - * NOTE: If enabling Scheduler-ACK mode, chain mode should also be enabled - * via SCD_QUEUECHAIN_SEL. - */ -#define SCD_QUEUE_STATUS_BITS(x) (SCD_START_OFFSET + 0x104 + (x) * 4) - -/* Bit field positions */ -#define SCD_QUEUE_STTS_REG_POS_ACTIVE (0) -#define SCD_QUEUE_STTS_REG_POS_TXF (1) -#define SCD_QUEUE_STTS_REG_POS_WSL (5) -#define SCD_QUEUE_STTS_REG_POS_SCD_ACK (8) - -/* Write masks */ -#define SCD_QUEUE_STTS_REG_POS_SCD_ACT_EN (10) -#define SCD_QUEUE_STTS_REG_MSK (0x0007FC00) - -/** - * 4965 internal SRAM structures for scheduler, shared with driver ... - * - * Driver should clear and initialize the following areas after receiving - * "Alive" response from 4965 uCode, i.e. after initial - * uCode load, or after a uCode load done for error recovery: - * - * SCD_CONTEXT_DATA_OFFSET (size 128 bytes) - * SCD_TX_STTS_BITMAP_OFFSET (size 256 bytes) - * SCD_TRANSLATE_TBL_OFFSET (size 32 bytes) - * - * Driver accesses SRAM via HBUS_TARG_MEM_* registers. - * Driver reads base address of this scheduler area from SCD_SRAM_BASE_ADDR. - * All OFFSET values must be added to this base address. - */ - -/* - * Queue context. One 8-byte entry for each of 16 queues. - * - * Driver should clear this entire area (size 0x80) to 0 after receiving - * "Alive" notification from uCode. Additionally, driver should init - * each queue's entry as follows: - * - * LS Dword bit fields: - * 0-06: Max Tx window size for Scheduler-ACK. Driver should init to 64. - * - * MS Dword bit fields: - * 16-22: Frame limit. Driver should init to 10 (0xa). - * - * Driver should init all other bits to 0. - * - * Init must be done after driver receives "Alive" response from 4965 uCode, - * and when setting up queue for aggregation. - */ -#define SCD_CONTEXT_DATA_OFFSET 0x380 -#define SCD_CONTEXT_QUEUE_OFFSET(x) (SCD_CONTEXT_DATA_OFFSET + ((x) * 8)) - -#define SCD_QUEUE_CTX_REG1_WIN_SIZE_POS (0) -#define SCD_QUEUE_CTX_REG1_WIN_SIZE_MSK (0x0000007F) -#define SCD_QUEUE_CTX_REG2_FRAME_LIMIT_POS (16) -#define SCD_QUEUE_CTX_REG2_FRAME_LIMIT_MSK (0x007F0000) - -/* - * Tx Status Bitmap - * - * Driver should clear this entire area (size 0x100) to 0 after receiving - * "Alive" notification from uCode. Area is used only by device itself; - * no other support (besides clearing) is required from driver. - */ -#define SCD_TX_STTS_BITMAP_OFFSET 0x400 - -/* - * RAxTID to queue translation mapping. - * - * When queue is in Scheduler-ACK mode, frames placed in a that queue must be - * for only one combination of receiver address (RA) and traffic ID (TID), i.e. - * one QOS priority level destined for one station (for this wireless link, - * not final destination). The SCD_TRANSLATE_TABLE area provides 16 16-bit - * mappings, one for each of the 16 queues. If queue is not in Scheduler-ACK - * mode, the device ignores the mapping value. - * - * Bit fields, for each 16-bit map: - * 15-9: Reserved, set to 0 - * 8-4: Index into device's station table for recipient station - * 3-0: Traffic ID (tid), range 0-15 - * - * Driver should clear this entire area (size 32 bytes) to 0 after receiving - * "Alive" notification from uCode. To update a 16-bit map value, driver - * must read a dword-aligned value from device SRAM, replace the 16-bit map - * value of interest, and write the dword value back into device SRAM. - */ -#define SCD_TRANSLATE_TBL_OFFSET 0x500 - -/* Find translation table dword to read/write for given queue */ -#define SCD_TRANSLATE_TBL_OFFSET_QUEUE(x) \ - ((SCD_TRANSLATE_TBL_OFFSET + ((x) * 2)) & 0xfffffffc) - -#define SCD_TXFIFO_POS_TID (0) -#define SCD_TXFIFO_POS_RA (4) -#define SCD_QUEUE_RA_TID_MAP_RATID_MSK (0x01FF) - -/*********************** END TX SCHEDULER *************************************/ - -static inline u8 iwl4965_hw_get_rate(__le32 rate_n_flags) -{ - return le32_to_cpu(rate_n_flags) & 0xFF; -} -static inline u16 iwl4965_hw_get_rate_n_flags(__le32 rate_n_flags) -{ - return le32_to_cpu(rate_n_flags) & 0xFFFF; -} -static inline __le32 iwl4965_hw_set_rate_n_flags(u8 rate, u16 flags) -{ - return cpu_to_le32(flags|(u16)rate); -} - /** * Tx/Rx Queues @@ -1385,14 +814,15 @@ static inline __le32 iwl4965_hw_set_rate_n_flags(u8 rate, u16 flags) * up to 7 DMA channels (FIFOs). Each Tx queue is supported by a circular array * in DRAM containing 256 Transmit Frame Descriptors (TFDs). */ -#define IWL4965_MAX_WIN_SIZE 64 -#define IWL4965_QUEUE_SIZE 256 -#define IWL4965_NUM_FIFOS 7 -#define IWL4965_MAX_NUM_QUEUES 16 - +#define IWL49_MAX_WIN_SIZE 64 +#define IWL49_QUEUE_SIZE 256 +#define IWL49_NUM_FIFOS 7 +#define IWL49_CMD_FIFO_NUM 4 +#define IWL49_NUM_QUEUES 16 +#define IWL49_NUM_AMPDU_QUEUES 8 /** - * struct iwl4965_tfd_frame_data + * struct iwl_tfd_frame_data * * Describes up to 2 buffers containing (contiguous) portions of a Tx frame. * Each buffer must be on dword boundary. @@ -1411,7 +841,7 @@ static inline __le32 iwl4965_hw_set_rate_n_flags(u8 rate, u16 flags) * 31-20: Tx buffer 2 length (bytes) * 19- 0: Tx buffer 2 address bits [35:16] */ -struct iwl4965_tfd_frame_data { +struct iwl_tfd_frame_data { __le32 tb1_addr; __le32 val1; @@ -1441,7 +871,7 @@ struct iwl4965_tfd_frame_data { /** - * struct iwl4965_tfd_frame + * struct iwl_tfd_frame * * Transmit Frame Descriptor (TFD) * @@ -1468,7 +898,7 @@ struct iwl4965_tfd_frame_data { * * A maximum of 255 (not 256!) TFDs may be on a queue waiting for Tx. */ -struct iwl4965_tfd_frame { +struct iwl_tfd_frame { __le32 val0; /* __le32 rsvd1:24; */ /* __le32 num_tbs:5; */ @@ -1477,7 +907,7 @@ struct iwl4965_tfd_frame { #define IWL_num_tbs_SYM val0 /* __le32 rsvd2:1; */ /* __le32 padding:2; */ - struct iwl4965_tfd_frame_data pa[10]; + struct iwl_tfd_frame_data pa[10]; __le32 reserved; } __attribute__ ((packed)); @@ -1520,10 +950,10 @@ struct iwl4965_queue_byte_cnt_entry { * 4965 assumes tables are separated by 1024 bytes. */ struct iwl4965_sched_queue_byte_cnt_tbl { - struct iwl4965_queue_byte_cnt_entry tfd_offset[IWL4965_QUEUE_SIZE + - IWL4965_MAX_WIN_SIZE]; + struct iwl4965_queue_byte_cnt_entry tfd_offset[IWL49_QUEUE_SIZE + + IWL49_MAX_WIN_SIZE]; u8 dont_care[1024 - - (IWL4965_QUEUE_SIZE + IWL4965_MAX_WIN_SIZE) * + (IWL49_QUEUE_SIZE + IWL49_MAX_WIN_SIZE) * sizeof(__le16)]; } __attribute__ ((packed)); @@ -1553,7 +983,7 @@ struct iwl4965_sched_queue_byte_cnt_tbl { */ struct iwl4965_shared { struct iwl4965_sched_queue_byte_cnt_tbl - queues_byte_cnt_tbls[IWL4965_MAX_NUM_QUEUES]; + queues_byte_cnt_tbls[IWL49_NUM_QUEUES]; __le32 rb_closed; /* __le32 rb_closed_stts_rb_num:12; */ diff --git a/drivers/net/wireless/iwlwifi/iwl-4965-rs.c b/drivers/net/wireless/iwlwifi/iwl-4965-rs.c index 3a7f0cb710ec..3ccb84aa5dbc 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965-rs.c @@ -28,7 +28,6 @@ #include <linux/skbuff.h> #include <linux/wireless.h> #include <net/mac80211.h> -#include <net/ieee80211.h> #include <linux/netdevice.h> #include <linux/etherdevice.h> @@ -38,13 +37,14 @@ #include "../net/mac80211/rate.h" -#include "iwl-4965.h" +#include "iwl-dev.h" +#include "iwl-sta.h" #include "iwl-core.h" #include "iwl-helpers.h" #define RS_NAME "iwl-4965-rs" -#define NUM_TRY_BEFORE_ANTENNA_TOGGLE 1 +#define NUM_TRY_BEFORE_ANT_TOGGLE 1 #define IWL_NUMBER_TRY 1 #define IWL_HT_NUMBER_TRY 3 @@ -65,9 +65,16 @@ static u8 rs_ht_to_legacy[] = { IWL_RATE_48M_INDEX, IWL_RATE_54M_INDEX }; -struct iwl4965_rate { - u32 rate_n_flags; -} __attribute__ ((packed)); +static const u8 ant_toggle_lookup[] = { + /*ANT_NONE -> */ ANT_NONE, + /*ANT_A -> */ ANT_B, + /*ANT_B -> */ ANT_C, + /*ANT_AB -> */ ANT_BC, + /*ANT_C -> */ ANT_A, + /*ANT_AC -> */ ANT_AB, + /*ANT_BC -> */ ANT_AC, + /*ANT_ABC -> */ ANT_ABC, +}; /** * struct iwl4965_rate_scale_data -- tx success history for one rate @@ -88,19 +95,17 @@ struct iwl4965_rate_scale_data { * one for "active", and one for "search". */ struct iwl4965_scale_tbl_info { - enum iwl4965_table_type lq_type; - enum iwl4965_antenna_type antenna_type; + enum iwl_table_type lq_type; + u8 ant_type; u8 is_SGI; /* 1 = short guard interval */ u8 is_fat; /* 1 = 40 MHz channel width */ u8 is_dup; /* 1 = duplicated data streams */ u8 action; /* change modulation; IWL_[LEGACY/SISO/MIMO]_SWITCH_* */ s32 *expected_tpt; /* throughput metrics; expected_tpt_G, etc. */ - struct iwl4965_rate current_rate; /* rate_n_flags, uCode API format */ + u32 current_rate; /* rate_n_flags, uCode API format */ struct iwl4965_rate_scale_data win[IWL_RATE_COUNT]; /* rate histories */ }; -#ifdef CONFIG_IWL4965_HT - struct iwl4965_traffic_load { unsigned long time_stamp; /* age of the oldest statistics */ u32 packet_count[TID_QUEUE_MAX_SIZE]; /* packet count in this time @@ -112,8 +117,6 @@ struct iwl4965_traffic_load { u8 head; /* start of the circular buffer */ }; -#endif /* CONFIG_IWL4965_HT */ - /** * struct iwl4965_lq_sta -- driver's rate scaling private structure * @@ -136,8 +139,6 @@ struct iwl4965_lq_sta { u32 flush_timer; /* time staying in mode before new search */ u8 action_counter; /* # mode-switch actions tried */ - u8 antenna; - u8 valid_antenna; u8 is_green; u8 is_dup; enum ieee80211_band band; @@ -145,24 +146,21 @@ struct iwl4965_lq_sta { /* The following are bitmaps of rates; IWL_RATE_6M_MASK, etc. */ u32 supp_rates; - u16 active_rate; + u16 active_legacy_rate; u16 active_siso_rate; - u16 active_mimo_rate; + u16 active_mimo2_rate; + u16 active_mimo3_rate; u16 active_rate_basic; struct iwl_link_quality_cmd lq; struct iwl4965_scale_tbl_info lq_info[LQ_SIZE]; /* "active", "search" */ -#ifdef CONFIG_IWL4965_HT struct iwl4965_traffic_load load[TID_MAX_LOAD_COUNT]; u8 tx_agg_tid_en; -#endif #ifdef CONFIG_MAC80211_DEBUGFS struct dentry *rs_sta_dbgfs_scale_table_file; struct dentry *rs_sta_dbgfs_stats_table_file; -#ifdef CONFIG_IWL4965_HT struct dentry *rs_sta_dbgfs_tx_agg_tid_en_file; -#endif - struct iwl4965_rate dbg_fixed; + u32 dbg_fixed_rate; #endif struct iwl_priv *drv; }; @@ -171,17 +169,17 @@ static void rs_rate_scale_perform(struct iwl_priv *priv, struct net_device *dev, struct ieee80211_hdr *hdr, struct sta_info *sta); -static void rs_fill_link_cmd(struct iwl4965_lq_sta *lq_sta, - struct iwl4965_rate *tx_mcs, - struct iwl_link_quality_cmd *tbl); +static void rs_fill_link_cmd(const struct iwl_priv *priv, + struct iwl4965_lq_sta *lq_sta, + u32 rate_n_flags); #ifdef CONFIG_MAC80211_DEBUGFS static void rs_dbgfs_set_mcs(struct iwl4965_lq_sta *lq_sta, - struct iwl4965_rate *mcs, int index); + u32 *rate_n_flags, int index); #else static void rs_dbgfs_set_mcs(struct iwl4965_lq_sta *lq_sta, - struct iwl4965_rate *mcs, int index) + u32 *rate_n_flags, int index) {} #endif @@ -190,6 +188,7 @@ static void rs_dbgfs_set_mcs(struct iwl4965_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 spearate 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 }; @@ -230,7 +229,7 @@ static s32 expected_tpt_mimo40MHzSGI[IWL_RATE_COUNT] = { 0, 0, 0, 0, 131, 131, 191, 222, 242, 270, 284, 289, 293 }; -static inline u8 iwl4965_rate_get_rate(u32 rate_n_flags) +static inline u8 rs_extract_rate(u32 rate_n_flags) { return (u8)(rate_n_flags & 0xFF); } @@ -245,7 +244,11 @@ static void rs_rate_scale_clear_window(struct iwl4965_rate_scale_data *window) window->stamp = 0; } -#ifdef CONFIG_IWL4965_HT +static inline u8 rs_is_valid_ant(u8 valid_antenna, u8 ant_type) +{ + return ((ant_type & valid_antenna) == ant_type); +} + /* * removes the old data from the statistics. All data that is older than * TID_MAX_TIME_DIFF, will be deleted. @@ -271,15 +274,21 @@ static void rs_tl_rm_old_stats(struct iwl4965_traffic_load *tl, u32 curr_time) * increment traffic load value for tid and also remove * any old values if passed the certain time period */ -static void rs_tl_add_packet(struct iwl4965_lq_sta *lq_data, u8 tid) +static u8 rs_tl_add_packet(struct iwl4965_lq_sta *lq_data, + struct ieee80211_hdr *hdr) { u32 curr_time = jiffies_to_msecs(jiffies); u32 time_diff; s32 index; struct iwl4965_traffic_load *tl = NULL; + __le16 fc = hdr->frame_control; + u8 tid; - if (tid >= TID_MAX_LOAD_COUNT) - return; + if (ieee80211_is_data_qos(fc)) { + u8 *qc = ieee80211_get_qos_ctl(hdr); + tid = qc[0] & 0xf; + } else + return MAX_TID_COUNT; tl = &lq_data->load[tid]; @@ -292,7 +301,7 @@ static void rs_tl_add_packet(struct iwl4965_lq_sta *lq_data, u8 tid) tl->queue_count = 1; tl->head = 0; tl->packet_count[0] = 1; - return; + return MAX_TID_COUNT; } time_diff = TIME_WRAP_AROUND(tl->time_stamp, curr_time); @@ -309,6 +318,8 @@ static void rs_tl_add_packet(struct iwl4965_lq_sta *lq_data, u8 tid) if ((index + 1) > tl->queue_count) tl->queue_count = index + 1; + + return tid; } /* @@ -349,9 +360,9 @@ static void rs_tl_turn_on_agg_for_tid(struct iwl_priv *priv, unsigned long state; DECLARE_MAC_BUF(mac); - spin_lock_bh(&sta->ampdu_mlme.ampdu_tx); + spin_lock_bh(&sta->lock); state = sta->ampdu_mlme.tid_state_tx[tid]; - spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx); + spin_unlock_bh(&sta->lock); if (state == HT_AGG_STATE_IDLE && rs_tl_get_load(lq_data, tid) > IWL_AGG_LOAD_THRESHOLD) { @@ -372,7 +383,12 @@ static void rs_tl_turn_on_agg(struct iwl_priv *priv, u8 tid, rs_tl_turn_on_agg_for_tid(priv, lq_data, tid, sta); } -#endif /* CONFIG_IWLWIFI_HT */ +static inline int get_num_of_ant_from_rate(u32 rate_n_flags) +{ + return (!!(rate_n_flags & RATE_MCS_ANT_A_MSK) + + !!(rate_n_flags & RATE_MCS_ANT_B_MSK) + + !!(rate_n_flags & RATE_MCS_ANT_C_MSK)); +} /** * rs_collect_tx_data - Update the success/failure sliding window @@ -386,8 +402,7 @@ static int rs_collect_tx_data(struct iwl4965_rate_scale_data *windows, int successes) { struct iwl4965_rate_scale_data *window = NULL; - u64 mask; - u8 win_size = IWL_RATE_MAX_WINDOW; + static const u64 mask = (((u64)1) << (IWL_RATE_MAX_WINDOW - 1)); s32 fail_count; if (scale_index < 0 || scale_index >= IWL_RATE_COUNT) @@ -405,14 +420,14 @@ static int rs_collect_tx_data(struct iwl4965_rate_scale_data *windows, * we keep these bitmaps!). */ while (retries > 0) { - if (window->counter >= win_size) { - window->counter = win_size - 1; - mask = 1; - mask = (mask << (win_size - 1)); + if (window->counter >= IWL_RATE_MAX_WINDOW) { + + /* remove earliest */ + window->counter = IWL_RATE_MAX_WINDOW - 1; + if (window->data & mask) { window->data &= ~mask; - window->success_counter = - window->success_counter - 1; + window->success_counter--; } } @@ -422,10 +437,9 @@ static int rs_collect_tx_data(struct iwl4965_rate_scale_data *windows, /* Shift bitmap by one frame (throw away oldest history), * OR in "1", and increment "success" if this * frame was successful. */ - mask = window->data; - window->data = (mask << 1); + window->data <<= 1;; if (successes > 0) { - window->success_counter = window->success_counter + 1; + window->success_counter++; window->data |= 0x1; successes--; } @@ -458,168 +472,162 @@ static int rs_collect_tx_data(struct iwl4965_rate_scale_data *windows, /* * Fill uCode API rate_n_flags field, based on "search" or "active" table. */ -static void rs_mcs_from_tbl(struct iwl4965_rate *mcs_rate, - struct iwl4965_scale_tbl_info *tbl, - int index, u8 use_green) +/* FIXME:RS:remove this function and put the flags statically in the table */ +static u32 rate_n_flags_from_tbl(struct iwl4965_scale_tbl_info *tbl, + int index, u8 use_green) { + u32 rate_n_flags = 0; + if (is_legacy(tbl->lq_type)) { - mcs_rate->rate_n_flags = iwl4965_rates[index].plcp; + rate_n_flags = iwl_rates[index].plcp; if (index >= IWL_FIRST_CCK_RATE && index <= IWL_LAST_CCK_RATE) - mcs_rate->rate_n_flags |= RATE_MCS_CCK_MSK; + rate_n_flags |= RATE_MCS_CCK_MSK; - } else if (is_siso(tbl->lq_type)) { - if (index > IWL_LAST_OFDM_RATE) + } else if (is_Ht(tbl->lq_type)) { + if (index > IWL_LAST_OFDM_RATE) { + IWL_ERROR("invalid HT rate index %d\n", index); index = IWL_LAST_OFDM_RATE; - mcs_rate->rate_n_flags = iwl4965_rates[index].plcp_siso | - RATE_MCS_HT_MSK; - } else { - if (index > IWL_LAST_OFDM_RATE) - index = IWL_LAST_OFDM_RATE; - mcs_rate->rate_n_flags = iwl4965_rates[index].plcp_mimo | - RATE_MCS_HT_MSK; - } - - switch (tbl->antenna_type) { - case ANT_BOTH: - mcs_rate->rate_n_flags |= RATE_MCS_ANT_AB_MSK; - break; - case ANT_MAIN: - mcs_rate->rate_n_flags |= RATE_MCS_ANT_A_MSK; - break; - case ANT_AUX: - mcs_rate->rate_n_flags |= RATE_MCS_ANT_B_MSK; - break; - case ANT_NONE: - break; - } - - if (is_legacy(tbl->lq_type)) - return; + } + rate_n_flags = RATE_MCS_HT_MSK; - if (tbl->is_fat) { - if (tbl->is_dup) - mcs_rate->rate_n_flags |= RATE_MCS_DUP_MSK; + if (is_siso(tbl->lq_type)) + rate_n_flags |= iwl_rates[index].plcp_siso; + else if (is_mimo2(tbl->lq_type)) + rate_n_flags |= iwl_rates[index].plcp_mimo2; else - mcs_rate->rate_n_flags |= RATE_MCS_FAT_MSK; + rate_n_flags |= iwl_rates[index].plcp_mimo3; + } else { + IWL_ERROR("Invalid tbl->lq_type %d\n", tbl->lq_type); } - if (tbl->is_SGI) - mcs_rate->rate_n_flags |= RATE_MCS_SGI_MSK; - if (use_green) { - mcs_rate->rate_n_flags |= RATE_MCS_GF_MSK; - if (is_siso(tbl->lq_type)) - mcs_rate->rate_n_flags &= ~RATE_MCS_SGI_MSK; + rate_n_flags |= ((tbl->ant_type << RATE_MCS_ANT_POS) & + RATE_MCS_ANT_ABC_MSK); + + if (is_Ht(tbl->lq_type)) { + if (tbl->is_fat) { + if (tbl->is_dup) + rate_n_flags |= RATE_MCS_DUP_MSK; + else + rate_n_flags |= RATE_MCS_FAT_MSK; + } + if (tbl->is_SGI) + rate_n_flags |= RATE_MCS_SGI_MSK; + + if (use_green) { + rate_n_flags |= RATE_MCS_GF_MSK; + if (is_siso(tbl->lq_type) && tbl->is_SGI) { + rate_n_flags &= ~RATE_MCS_SGI_MSK; + IWL_ERROR("GF was set with SGI:SISO\n"); + } + } } + return rate_n_flags; } /* * Interpret uCode API's rate_n_flags format, * fill "search" or "active" tx mode table. */ -static int rs_get_tbl_info_from_mcs(const struct iwl4965_rate *mcs_rate, +static int rs_get_tbl_info_from_mcs(const u32 rate_n_flags, enum ieee80211_band band, struct iwl4965_scale_tbl_info *tbl, int *rate_idx) { - int index; - u32 ant_msk; + u32 ant_msk = (rate_n_flags & RATE_MCS_ANT_ABC_MSK); + u8 num_of_ant = get_num_of_ant_from_rate(rate_n_flags); + u8 mcs; - index = iwl4965_hwrate_to_plcp_idx(mcs_rate->rate_n_flags); + *rate_idx = iwl_hwrate_to_plcp_idx(rate_n_flags); - if (index == IWL_RATE_INVALID) { + if (*rate_idx == IWL_RATE_INVALID) { *rate_idx = -1; return -EINVAL; } tbl->is_SGI = 0; /* default legacy setup */ tbl->is_fat = 0; tbl->is_dup = 0; - tbl->antenna_type = ANT_BOTH; /* default MIMO setup */ + tbl->ant_type = (ant_msk >> RATE_MCS_ANT_POS); + tbl->lq_type = LQ_NONE; /* legacy rate format */ - if (!(mcs_rate->rate_n_flags & RATE_MCS_HT_MSK)) { - ant_msk = (mcs_rate->rate_n_flags & RATE_MCS_ANT_AB_MSK); - - if (ant_msk == RATE_MCS_ANT_AB_MSK) - tbl->lq_type = LQ_NONE; - else { - + if (!(rate_n_flags & RATE_MCS_HT_MSK)) { + if (num_of_ant == 1) { if (band == IEEE80211_BAND_5GHZ) tbl->lq_type = LQ_A; else tbl->lq_type = LQ_G; - - if (mcs_rate->rate_n_flags & RATE_MCS_ANT_A_MSK) - tbl->antenna_type = ANT_MAIN; - else - tbl->antenna_type = ANT_AUX; - } - *rate_idx = index; - - /* HT rate format, SISO (might be 20 MHz legacy or 40 MHz fat width) */ - } else if (iwl4965_rate_get_rate(mcs_rate->rate_n_flags) - <= IWL_RATE_SISO_60M_PLCP) { - tbl->lq_type = LQ_SISO; - - ant_msk = (mcs_rate->rate_n_flags & RATE_MCS_ANT_AB_MSK); - if (ant_msk == RATE_MCS_ANT_AB_MSK) - tbl->lq_type = LQ_NONE; - else { - if (mcs_rate->rate_n_flags & RATE_MCS_ANT_A_MSK) - tbl->antenna_type = ANT_MAIN; - else - tbl->antenna_type = ANT_AUX; } - if (mcs_rate->rate_n_flags & RATE_MCS_SGI_MSK) - tbl->is_SGI = 1; - - if ((mcs_rate->rate_n_flags & RATE_MCS_FAT_MSK) || - (mcs_rate->rate_n_flags & RATE_MCS_DUP_MSK)) - tbl->is_fat = 1; - - if (mcs_rate->rate_n_flags & RATE_MCS_DUP_MSK) - tbl->is_dup = 1; - - *rate_idx = index; - - /* HT rate format, MIMO (might be 20 MHz legacy or 40 MHz fat width) */ + /* HT rate format */ } else { - tbl->lq_type = LQ_MIMO; - if (mcs_rate->rate_n_flags & RATE_MCS_SGI_MSK) + if (rate_n_flags & RATE_MCS_SGI_MSK) tbl->is_SGI = 1; - if ((mcs_rate->rate_n_flags & RATE_MCS_FAT_MSK) || - (mcs_rate->rate_n_flags & RATE_MCS_DUP_MSK)) + if ((rate_n_flags & RATE_MCS_FAT_MSK) || + (rate_n_flags & RATE_MCS_DUP_MSK)) tbl->is_fat = 1; - if (mcs_rate->rate_n_flags & RATE_MCS_DUP_MSK) + if (rate_n_flags & RATE_MCS_DUP_MSK) tbl->is_dup = 1; - *rate_idx = index; + + mcs = rs_extract_rate(rate_n_flags); + + /* SISO */ + if (mcs <= IWL_RATE_SISO_60M_PLCP) { + if (num_of_ant == 1) + tbl->lq_type = LQ_SISO; /*else NONE*/ + /* MIMO2 */ + } else if (mcs <= IWL_RATE_MIMO2_60M_PLCP) { + if (num_of_ant == 2) + tbl->lq_type = LQ_MIMO2; + /* MIMO3 */ + } else { + if (num_of_ant == 3) + tbl->lq_type = LQ_MIMO3; + } } return 0; } -static inline void rs_toggle_antenna(struct iwl4965_rate *new_rate, - struct iwl4965_scale_tbl_info *tbl) +/* switch to another antenna/antennas and return 1 */ +/* if no other valid antenna found, return 0 */ +static int rs_toggle_antenna(u32 valid_ant, u32 *rate_n_flags, + struct iwl4965_scale_tbl_info *tbl) { - if (tbl->antenna_type == ANT_AUX) { - tbl->antenna_type = ANT_MAIN; - new_rate->rate_n_flags &= ~RATE_MCS_ANT_B_MSK; - new_rate->rate_n_flags |= RATE_MCS_ANT_A_MSK; - } else { - tbl->antenna_type = ANT_AUX; - new_rate->rate_n_flags &= ~RATE_MCS_ANT_A_MSK; - new_rate->rate_n_flags |= RATE_MCS_ANT_B_MSK; - } + u8 new_ant_type; + + if (!tbl->ant_type || tbl->ant_type > ANT_ABC) + return 0; + + if (!rs_is_valid_ant(valid_ant, tbl->ant_type)) + return 0; + + new_ant_type = ant_toggle_lookup[tbl->ant_type]; + + while ((new_ant_type != tbl->ant_type) && + !rs_is_valid_ant(valid_ant, new_ant_type)) + new_ant_type = ant_toggle_lookup[new_ant_type]; + + if (new_ant_type == tbl->ant_type) + return 0; + + tbl->ant_type = new_ant_type; + *rate_n_flags &= ~RATE_MCS_ANT_ABC_MSK; + *rate_n_flags |= new_ant_type << RATE_MCS_ANT_POS; + return 1; } -static inline u8 rs_use_green(struct iwl_priv *priv, - struct ieee80211_conf *conf) +/* 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) { -#ifdef CONFIG_IWL4965_HT return ((conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE) && priv->current_ht_config.is_green_field && !priv->current_ht_config.non_GF_STA_present); -#endif /* CONFIG_IWL4965_HT */ +} +#endif +static inline u8 rs_use_green(struct iwl_priv *priv, struct ieee80211_conf *conf) +{ return 0; } @@ -630,27 +638,28 @@ static inline u8 rs_use_green(struct iwl_priv *priv, * basic available rates. * */ -static void rs_get_supported_rates(struct iwl4965_lq_sta *lq_sta, +static u16 rs_get_supported_rates(struct iwl4965_lq_sta *lq_sta, struct ieee80211_hdr *hdr, - enum iwl4965_table_type rate_type, - u16 *data_rate) + enum iwl_table_type rate_type) { - if (is_legacy(rate_type)) - *data_rate = lq_sta->active_rate; - else { + if (hdr && is_multicast_ether_addr(hdr->addr1) && + lq_sta->active_rate_basic) + return lq_sta->active_rate_basic; + + if (is_legacy(rate_type)) { + return lq_sta->active_legacy_rate; + } else { if (is_siso(rate_type)) - *data_rate = lq_sta->active_siso_rate; + return lq_sta->active_siso_rate; + else if (is_mimo2(rate_type)) + return lq_sta->active_mimo2_rate; else - *data_rate = lq_sta->active_mimo_rate; - } - - if (hdr && is_multicast_ether_addr(hdr->addr1) && - lq_sta->active_rate_basic) { - *data_rate = lq_sta->active_rate_basic; + return lq_sta->active_mimo3_rate; } } -static u16 rs_get_adjacent_rate(u8 index, u16 rate_mask, int rate_type) +static u16 rs_get_adjacent_rate(struct iwl_priv *priv, u8 index, u16 rate_mask, + int rate_type) { u8 high = IWL_RATE_INVALID; u8 low = IWL_RATE_INVALID; @@ -684,7 +693,7 @@ static u16 rs_get_adjacent_rate(u8 index, u16 rate_mask, int rate_type) low = index; while (low != IWL_RATE_INVALID) { - low = iwl4965_rates[low].prev_rs; + low = iwl_rates[low].prev_rs; if (low == IWL_RATE_INVALID) break; if (rate_mask & (1 << low)) @@ -694,7 +703,7 @@ static u16 rs_get_adjacent_rate(u8 index, u16 rate_mask, int rate_type) high = index; while (high != IWL_RATE_INVALID) { - high = iwl4965_rates[high].next_rs; + high = iwl_rates[high].next_rs; if (high == IWL_RATE_INVALID) break; if (rate_mask & (1 << high)) @@ -705,9 +714,9 @@ static u16 rs_get_adjacent_rate(u8 index, u16 rate_mask, int rate_type) return (high << 8) | low; } -static void rs_get_lower_rate(struct iwl4965_lq_sta *lq_sta, +static u32 rs_get_lower_rate(struct iwl4965_lq_sta *lq_sta, struct iwl4965_scale_tbl_info *tbl, u8 scale_index, - u8 ht_possible, struct iwl4965_rate *mcs_rate) + u8 ht_possible) { s32 low; u16 rate_mask; @@ -726,15 +735,14 @@ static void rs_get_lower_rate(struct iwl4965_lq_sta *lq_sta, else tbl->lq_type = LQ_G; - if ((tbl->antenna_type == ANT_BOTH) || - (tbl->antenna_type == ANT_NONE)) - tbl->antenna_type = ANT_MAIN; + if (num_of_ant(tbl->ant_type) > 1) + tbl->ant_type = ANT_A;/*FIXME:RS*/ tbl->is_fat = 0; tbl->is_SGI = 0; } - rs_get_supported_rates(lq_sta, NULL, tbl->lq_type, &rate_mask); + rate_mask = rs_get_supported_rates(lq_sta, NULL, tbl->lq_type); /* Mask with station rate restriction */ if (is_legacy(tbl->lq_type)) { @@ -748,25 +756,26 @@ static void rs_get_lower_rate(struct iwl4965_lq_sta *lq_sta, /* If we switched from HT to legacy, check current rate */ if (switch_to_legacy && (rate_mask & (1 << scale_index))) { - rs_mcs_from_tbl(mcs_rate, tbl, scale_index, is_green); - return; + low = scale_index; + goto out; } - high_low = rs_get_adjacent_rate(scale_index, rate_mask, tbl->lq_type); + high_low = rs_get_adjacent_rate(lq_sta->drv, scale_index, rate_mask, + tbl->lq_type); low = high_low & 0xff; - if (low != IWL_RATE_INVALID) - rs_mcs_from_tbl(mcs_rate, tbl, low, is_green); - else - rs_mcs_from_tbl(mcs_rate, tbl, scale_index, is_green); + if (low == IWL_RATE_INVALID) + low = scale_index; + +out: + return rate_n_flags_from_tbl(tbl, low, is_green); } /* * mac80211 sends us Tx status */ static void rs_tx_status(void *priv_rate, struct net_device *dev, - struct sk_buff *skb, - struct ieee80211_tx_status *tx_resp) + struct sk_buff *skb) { int status; u8 retries; @@ -778,13 +787,14 @@ static void rs_tx_status(void *priv_rate, struct net_device *dev, struct iwl_priv *priv = (struct iwl_priv *)priv_rate; struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); struct ieee80211_hw *hw = local_to_hw(local); + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct iwl4965_rate_scale_data *window = NULL; struct iwl4965_rate_scale_data *search_win = NULL; - struct iwl4965_rate tx_mcs; + u32 tx_rate; struct iwl4965_scale_tbl_info tbl_type; struct iwl4965_scale_tbl_info *curr_tbl, *search_tbl; u8 active_index = 0; - u16 fc = le16_to_cpu(hdr->frame_control); + __le16 fc = hdr->frame_control; s32 tpt = 0; IWL_DEBUG_RATE_LIMIT("get frame ack response, update rate scale window\n"); @@ -793,11 +803,11 @@ static void rs_tx_status(void *priv_rate, struct net_device *dev, return; /* This packet was aggregated but doesn't carry rate scale info */ - if ((tx_resp->control.flags & IEEE80211_TXCTL_AMPDU) && - !(tx_resp->flags & IEEE80211_TX_STATUS_AMPDU)) + if ((info->flags & IEEE80211_TX_CTL_AMPDU) && + !(info->flags & IEEE80211_TX_STAT_AMPDU)) return; - retries = tx_resp->retry_count; + retries = info->status.retry_count; if (retries > 15) retries = 15; @@ -812,9 +822,6 @@ static void rs_tx_status(void *priv_rate, struct net_device *dev, lq_sta = (struct iwl4965_lq_sta *)sta->rate_ctrl_priv; - if (!priv->lq_mngr.lq_ready) - goto out; - if ((priv->iw_mode == IEEE80211_IF_TYPE_IBSS) && !lq_sta->ibss_sta_added) goto out; @@ -822,15 +829,6 @@ static void rs_tx_status(void *priv_rate, struct net_device *dev, table = &lq_sta->lq; active_index = lq_sta->active_tbl; - /* Get mac80211 antenna info */ - lq_sta->antenna = - (lq_sta->valid_antenna & local->hw.conf.antenna_sel_tx); - if (!lq_sta->antenna) - lq_sta->antenna = lq_sta->valid_antenna; - - /* Ignore mac80211 antenna info for now */ - lq_sta->antenna = lq_sta->valid_antenna; - curr_tbl = &(lq_sta->lq_info[active_index]); search_tbl = &(lq_sta->lq_info[(1 - active_index)]); window = (struct iwl4965_rate_scale_data *) @@ -846,28 +844,26 @@ static void rs_tx_status(void *priv_rate, struct net_device *dev, * to check "search" mode, or a prior "search" mode after we've moved * to a new "search" mode (which might become the new "active" mode). */ - tx_mcs.rate_n_flags = le32_to_cpu(table->rs_table[0].rate_n_flags); - rs_get_tbl_info_from_mcs(&tx_mcs, priv->band, &tbl_type, &rs_index); + tx_rate = le32_to_cpu(table->rs_table[0].rate_n_flags); + rs_get_tbl_info_from_mcs(tx_rate, priv->band, &tbl_type, &rs_index); if (priv->band == IEEE80211_BAND_5GHZ) rs_index -= IWL_FIRST_OFDM_RATE; - if ((tx_resp->control.tx_rate == NULL) || + if ((info->tx_rate_idx < 0) || (tbl_type.is_SGI ^ - !!(tx_resp->control.flags & IEEE80211_TXCTL_SHORT_GI)) || + !!(info->flags & IEEE80211_TX_CTL_SHORT_GI)) || (tbl_type.is_fat ^ - !!(tx_resp->control.flags & IEEE80211_TXCTL_40_MHZ_WIDTH)) || + !!(info->flags & IEEE80211_TX_CTL_40_MHZ_WIDTH)) || (tbl_type.is_dup ^ - !!(tx_resp->control.flags & IEEE80211_TXCTL_DUP_DATA)) || - (tbl_type.antenna_type ^ - tx_resp->control.antenna_sel_tx) || - (!!(tx_mcs.rate_n_flags & RATE_MCS_HT_MSK) ^ - !!(tx_resp->control.flags & IEEE80211_TXCTL_OFDM_HT)) || - (!!(tx_mcs.rate_n_flags & RATE_MCS_GF_MSK) ^ - !!(tx_resp->control.flags & IEEE80211_TXCTL_GREEN_FIELD)) || + !!(info->flags & IEEE80211_TX_CTL_DUP_DATA)) || + (tbl_type.ant_type ^ info->antenna_sel_tx) || + (!!(tx_rate & RATE_MCS_HT_MSK) ^ + !!(info->flags & IEEE80211_TX_CTL_OFDM_HT)) || + (!!(tx_rate & RATE_MCS_GF_MSK) ^ + !!(info->flags & IEEE80211_TX_CTL_GREEN_FIELD)) || (hw->wiphy->bands[priv->band]->bitrates[rs_index].bitrate != - tx_resp->control.tx_rate->bitrate)) { - IWL_DEBUG_RATE("initial rate does not match 0x%x\n", - tx_mcs.rate_n_flags); + hw->wiphy->bands[info->band]->bitrates[info->tx_rate_idx].bitrate)) { + IWL_DEBUG_RATE("initial rate does not match 0x%x\n", tx_rate); goto out; } @@ -875,15 +871,14 @@ static void rs_tx_status(void *priv_rate, struct net_device *dev, while (retries) { /* Look up the rate and other info used for each tx attempt. * Each tx attempt steps one entry deeper in the rate table. */ - tx_mcs.rate_n_flags = - le32_to_cpu(table->rs_table[index].rate_n_flags); - rs_get_tbl_info_from_mcs(&tx_mcs, priv->band, + tx_rate = le32_to_cpu(table->rs_table[index].rate_n_flags); + rs_get_tbl_info_from_mcs(tx_rate, priv->band, &tbl_type, &rs_index); /* If type matches "search" table, * add failure to "search" history */ if ((tbl_type.lq_type == search_tbl->lq_type) && - (tbl_type.antenna_type == search_tbl->antenna_type) && + (tbl_type.ant_type == search_tbl->ant_type) && (tbl_type.is_SGI == search_tbl->is_SGI)) { if (search_tbl->expected_tpt) tpt = search_tbl->expected_tpt[rs_index]; @@ -894,7 +889,7 @@ static void rs_tx_status(void *priv_rate, struct net_device *dev, /* Else if type matches "current/active" table, * add failure to "current/active" history */ } else if ((tbl_type.lq_type == curr_tbl->lq_type) && - (tbl_type.antenna_type == curr_tbl->antenna_type) && + (tbl_type.ant_type == curr_tbl->ant_type) && (tbl_type.is_SGI == curr_tbl->is_SGI)) { if (curr_tbl->expected_tpt) tpt = curr_tbl->expected_tpt[rs_index]; @@ -917,44 +912,41 @@ static void rs_tx_status(void *priv_rate, struct net_device *dev, * if Tx was successful first try, use original rate, * else look up the rate that was, finally, successful. */ - tx_mcs.rate_n_flags = le32_to_cpu(table->rs_table[index].rate_n_flags); - rs_get_tbl_info_from_mcs(&tx_mcs, priv->band, &tbl_type, &rs_index); + tx_rate = le32_to_cpu(table->rs_table[index].rate_n_flags); + rs_get_tbl_info_from_mcs(tx_rate, priv->band, &tbl_type, &rs_index); /* Update frame history window with "success" if Tx got ACKed ... */ - if (tx_resp->flags & IEEE80211_TX_STATUS_ACK) - status = 1; - else - status = 0; + status = !!(info->flags & IEEE80211_TX_STAT_ACK); /* If type matches "search" table, * add final tx status to "search" history */ if ((tbl_type.lq_type == search_tbl->lq_type) && - (tbl_type.antenna_type == search_tbl->antenna_type) && + (tbl_type.ant_type == search_tbl->ant_type) && (tbl_type.is_SGI == search_tbl->is_SGI)) { if (search_tbl->expected_tpt) tpt = search_tbl->expected_tpt[rs_index]; else tpt = 0; - if (tx_resp->control.flags & IEEE80211_TXCTL_AMPDU) + if (info->flags & IEEE80211_TX_CTL_AMPDU) rs_collect_tx_data(search_win, rs_index, tpt, - tx_resp->ampdu_ack_len, - tx_resp->ampdu_ack_map); + info->status.ampdu_ack_len, + info->status.ampdu_ack_map); else rs_collect_tx_data(search_win, rs_index, tpt, 1, status); /* Else if type matches "current/active" table, * add final tx status to "current/active" history */ } else if ((tbl_type.lq_type == curr_tbl->lq_type) && - (tbl_type.antenna_type == curr_tbl->antenna_type) && + (tbl_type.ant_type == curr_tbl->ant_type) && (tbl_type.is_SGI == curr_tbl->is_SGI)) { if (curr_tbl->expected_tpt) tpt = curr_tbl->expected_tpt[rs_index]; else tpt = 0; - if (tx_resp->control.flags & IEEE80211_TXCTL_AMPDU) + if (info->flags & IEEE80211_TX_CTL_AMPDU) rs_collect_tx_data(window, rs_index, tpt, - tx_resp->ampdu_ack_len, - tx_resp->ampdu_ack_map); + info->status.ampdu_ack_len, + info->status.ampdu_ack_map); else rs_collect_tx_data(window, rs_index, tpt, 1, status); @@ -963,10 +955,10 @@ static void rs_tx_status(void *priv_rate, struct net_device *dev, /* If not searching for new mode, increment success/failed counter * ... these help determine when to start searching again */ if (lq_sta->stay_in_tbl) { - if (tx_resp->control.flags & IEEE80211_TXCTL_AMPDU) { - lq_sta->total_success += tx_resp->ampdu_ack_map; + if (info->flags & IEEE80211_TX_CTL_AMPDU) { + lq_sta->total_success += info->status.ampdu_ack_map; lq_sta->total_failed += - (tx_resp->ampdu_ack_len - tx_resp->ampdu_ack_map); + (info->status.ampdu_ack_len - info->status.ampdu_ack_map); } else { if (status) lq_sta->total_success++; @@ -982,30 +974,6 @@ out: return; } -static u8 rs_is_ant_connected(u8 valid_antenna, - enum iwl4965_antenna_type antenna_type) -{ - if (antenna_type == ANT_AUX) - return ((valid_antenna & 0x2) ? 1:0); - else if (antenna_type == ANT_MAIN) - return ((valid_antenna & 0x1) ? 1:0); - else if (antenna_type == ANT_BOTH) - return ((valid_antenna & 0x3) == 0x3); - - return 1; -} - -static u8 rs_is_other_ant_connected(u8 valid_antenna, - enum iwl4965_antenna_type antenna_type) -{ - if (antenna_type == ANT_AUX) - return rs_is_ant_connected(valid_antenna, ANT_MAIN); - else - return rs_is_ant_connected(valid_antenna, ANT_AUX); - - return 0; -} - /* * Begin a period of staying with a selected modulation mode. * Set "stay_in_tbl" flag to prevent any mode switches. @@ -1014,10 +982,10 @@ static u8 rs_is_other_ant_connected(u8 valid_antenna, * These control how long we stay using same modulation mode before * searching for a new mode. */ -static void rs_set_stay_in_table(u8 is_legacy, +static void rs_set_stay_in_table(struct iwl_priv *priv, u8 is_legacy, struct iwl4965_lq_sta *lq_sta) { - IWL_DEBUG_HT("we are staying in the same table\n"); + IWL_DEBUG_RATE("we are staying in the same table\n"); lq_sta->stay_in_tbl = 1; /* only place this gets set */ if (is_legacy) { lq_sta->table_count_limit = IWL_LEGACY_TABLE_COUNT; @@ -1036,7 +1004,7 @@ static void rs_set_stay_in_table(u8 is_legacy, /* * Find correct throughput table for given mode of modulation */ -static void rs_get_expected_tpt_table(struct iwl4965_lq_sta *lq_sta, +static void rs_set_expected_tpt_table(struct iwl4965_lq_sta *lq_sta, struct iwl4965_scale_tbl_info *tbl) { if (is_legacy(tbl->lq_type)) { @@ -1055,7 +1023,7 @@ static void rs_get_expected_tpt_table(struct iwl4965_lq_sta *lq_sta, else tbl->expected_tpt = expected_tpt_siso20MHz; - } else if (is_mimo(tbl->lq_type)) { + } else if (is_mimo(tbl->lq_type)) { /* FIXME:need to separate mimo2/3 */ if (tbl->is_fat && !lq_sta->is_dup) if (tbl->is_SGI) tbl->expected_tpt = expected_tpt_mimo40MHzSGI; @@ -1069,7 +1037,6 @@ static void rs_get_expected_tpt_table(struct iwl4965_lq_sta *lq_sta, tbl->expected_tpt = expected_tpt_G; } -#ifdef CONFIG_IWL4965_HT /* * Find starting rate for new "search" high-throughput mode of modulation. * Goal is to find lowest expected rate (under perfect conditions) that is @@ -1085,7 +1052,7 @@ static void rs_get_expected_tpt_table(struct iwl4965_lq_sta *lq_sta, static s32 rs_get_best_rate(struct iwl_priv *priv, struct iwl4965_lq_sta *lq_sta, struct iwl4965_scale_tbl_info *tbl, /* "search" */ - u16 rate_mask, s8 index, s8 rate) + u16 rate_mask, s8 index) { /* "active" values */ struct iwl4965_scale_tbl_info *active_tbl = @@ -1098,11 +1065,13 @@ static s32 rs_get_best_rate(struct iwl_priv *priv, s32 new_rate, high, low, start_hi; u16 high_low; + s8 rate = index; new_rate = high = low = start_hi = IWL_RATE_INVALID; for (; ;) { - high_low = rs_get_adjacent_rate(rate, rate_mask, tbl->lq_type); + high_low = rs_get_adjacent_rate(priv, rate, rate_mask, + tbl->lq_type); low = high_low & 0xff; high = (high_low >> 8) & 0xff; @@ -1169,23 +1138,16 @@ static s32 rs_get_best_rate(struct iwl_priv *priv, return new_rate; } -#endif /* CONFIG_IWL4965_HT */ - -static inline u8 rs_is_both_ant_supp(u8 valid_antenna) -{ - return (rs_is_ant_connected(valid_antenna, ANT_BOTH)); -} /* * Set up search table for MIMO */ -static int rs_switch_to_mimo(struct iwl_priv *priv, +static int rs_switch_to_mimo2(struct iwl_priv *priv, struct iwl4965_lq_sta *lq_sta, struct ieee80211_conf *conf, struct sta_info *sta, struct iwl4965_scale_tbl_info *tbl, int index) { -#ifdef CONFIG_IWL4965_HT u16 rate_mask; s32 rate; s8 is_green = lq_sta->is_green; @@ -1194,26 +1156,27 @@ static int rs_switch_to_mimo(struct iwl_priv *priv, !sta->ht_info.ht_supported) return -1; - IWL_DEBUG_HT("LQ: try to switch to MIMO\n"); - tbl->lq_type = LQ_MIMO; - rs_get_supported_rates(lq_sta, NULL, tbl->lq_type, - &rate_mask); - if (priv->current_ht_config.tx_mimo_ps_mode == IWL_MIMO_PS_STATIC) return -1; /* Need both Tx chains/antennas to support MIMO */ - if (!rs_is_both_ant_supp(lq_sta->antenna)) + if (priv->hw_params.tx_chains_num < 2) return -1; + IWL_DEBUG_RATE("LQ: try to switch to MIMO2\n"); + + tbl->lq_type = LQ_MIMO2; tbl->is_dup = lq_sta->is_dup; tbl->action = 0; + rate_mask = lq_sta->active_mimo2_rate; + if (priv->current_ht_config.supported_chan_width - == IWL_CHANNEL_WIDTH_40MHZ) + == 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; @@ -1223,22 +1186,24 @@ static int rs_switch_to_mimo(struct iwl_priv *priv, tbl->is_SGI = 1; else tbl->is_SGI = 0; + */ + + rs_set_expected_tpt_table(lq_sta, tbl); - rs_get_expected_tpt_table(lq_sta, tbl); + rate = rs_get_best_rate(priv, lq_sta, tbl, rate_mask, index); - rate = rs_get_best_rate(priv, lq_sta, tbl, rate_mask, index, index); + IWL_DEBUG_RATE("LQ: MIMO2 best rate %d mask %X\n", rate, rate_mask); - IWL_DEBUG_HT("LQ: MIMO best rate %d mask %X\n", rate, rate_mask); - if ((rate == IWL_RATE_INVALID) || !((1 << rate) & rate_mask)) + if ((rate == IWL_RATE_INVALID) || !((1 << rate) & rate_mask)) { + IWL_DEBUG_RATE("Can't switch with index %d rate mask %x\n", + rate, rate_mask); return -1; - rs_mcs_from_tbl(&tbl->current_rate, tbl, rate, is_green); + } + tbl->current_rate = rate_n_flags_from_tbl(tbl, rate, is_green); - IWL_DEBUG_HT("LQ: Switch to new mcs %X index is green %X\n", - tbl->current_rate.rate_n_flags, is_green); + IWL_DEBUG_RATE("LQ: Switch to new mcs %X index is green %X\n", + tbl->current_rate, is_green); return 0; -#else - return -1; -#endif /*CONFIG_IWL4965_HT */ } /* @@ -1250,21 +1215,20 @@ static int rs_switch_to_siso(struct iwl_priv *priv, struct sta_info *sta, struct iwl4965_scale_tbl_info *tbl, int index) { -#ifdef CONFIG_IWL4965_HT u16 rate_mask; u8 is_green = lq_sta->is_green; s32 rate; - IWL_DEBUG_HT("LQ: try to switch to SISO\n"); if (!(conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE) || !sta->ht_info.ht_supported) return -1; + IWL_DEBUG_RATE("LQ: try to switch to SISO\n"); + tbl->is_dup = lq_sta->is_dup; tbl->lq_type = LQ_SISO; tbl->action = 0; - rs_get_supported_rates(lq_sta, NULL, tbl->lq_type, - &rate_mask); + rate_mask = lq_sta->active_siso_rate; if (priv->current_ht_config.supported_chan_width == IWL_CHANNEL_WIDTH_40MHZ) @@ -1272,6 +1236,7 @@ static int rs_switch_to_siso(struct iwl_priv *priv, 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; @@ -1281,27 +1246,24 @@ static int rs_switch_to_siso(struct iwl_priv *priv, tbl->is_SGI = 1; else tbl->is_SGI = 0; + */ if (is_green) - tbl->is_SGI = 0; + tbl->is_SGI = 0; /*11n spec: no SGI in SISO+Greenfield*/ - rs_get_expected_tpt_table(lq_sta, tbl); - rate = rs_get_best_rate(priv, lq_sta, tbl, rate_mask, index, index); + rs_set_expected_tpt_table(lq_sta, tbl); + rate = rs_get_best_rate(priv, lq_sta, tbl, rate_mask, index); - IWL_DEBUG_HT("LQ: get best rate %d mask %X\n", rate, rate_mask); + IWL_DEBUG_RATE("LQ: get best rate %d mask %X\n", rate, rate_mask); if ((rate == IWL_RATE_INVALID) || !((1 << rate) & rate_mask)) { - IWL_DEBUG_HT("can not switch with index %d rate mask %x\n", + IWL_DEBUG_RATE("can not switch with index %d rate mask %x\n", rate, rate_mask); return -1; } - rs_mcs_from_tbl(&tbl->current_rate, tbl, rate, is_green); - IWL_DEBUG_HT("LQ: Switch to new mcs %X index is green %X\n", - tbl->current_rate.rate_n_flags, is_green); + tbl->current_rate = rate_n_flags_from_tbl(tbl, rate, is_green); + IWL_DEBUG_RATE("LQ: Switch to new mcs %X index is green %X\n", + tbl->current_rate, is_green); return 0; -#else - return -1; - -#endif /*CONFIG_IWL4965_HT */ } /* @@ -1313,7 +1275,6 @@ static int rs_move_legacy_other(struct iwl_priv *priv, struct sta_info *sta, int index) { - int ret = 0; struct iwl4965_scale_tbl_info *tbl = &(lq_sta->lq_info[lq_sta->active_tbl]); struct iwl4965_scale_tbl_info *search_tbl = @@ -1322,41 +1283,35 @@ static int rs_move_legacy_other(struct iwl_priv *priv, u32 sz = (sizeof(struct iwl4965_scale_tbl_info) - (sizeof(struct iwl4965_rate_scale_data) * IWL_RATE_COUNT)); u8 start_action = tbl->action; + u8 valid_tx_ant = priv->hw_params.valid_tx_ant; + int ret = 0; for (; ;) { switch (tbl->action) { case IWL_LEGACY_SWITCH_ANTENNA: - IWL_DEBUG_HT("LQ Legacy switch Antenna\n"); + IWL_DEBUG_RATE("LQ: Legacy toggle Antenna\n"); - search_tbl->lq_type = LQ_NONE; lq_sta->action_counter++; /* Don't change antenna if success has been great */ if (window->success_ratio >= IWL_RS_GOOD_RATIO) break; - /* Don't change antenna if other one is not connected */ - if (!rs_is_other_ant_connected(lq_sta->antenna, - tbl->antenna_type)) - break; - /* Set up search table to try other antenna */ memcpy(search_tbl, tbl, sz); - rs_toggle_antenna(&(search_tbl->current_rate), - search_tbl); - rs_get_expected_tpt_table(lq_sta, search_tbl); - lq_sta->search_better_tbl = 1; - goto out; - + if (rs_toggle_antenna(valid_tx_ant, + &search_tbl->current_rate, search_tbl)) { + lq_sta->search_better_tbl = 1; + goto out; + } + break; case IWL_LEGACY_SWITCH_SISO: - IWL_DEBUG_HT("LQ: Legacy switch to SISO\n"); + IWL_DEBUG_RATE("LQ: Legacy switch to SISO\n"); /* Set up search table to try SISO */ memcpy(search_tbl, tbl, sz); - search_tbl->lq_type = LQ_SISO; search_tbl->is_SGI = 0; - search_tbl->is_fat = 0; ret = rs_switch_to_siso(priv, lq_sta, conf, sta, search_tbl, index); if (!ret) { @@ -1366,16 +1321,15 @@ static int rs_move_legacy_other(struct iwl_priv *priv, } break; - case IWL_LEGACY_SWITCH_MIMO: - IWL_DEBUG_HT("LQ: Legacy switch MIMO\n"); + case IWL_LEGACY_SWITCH_MIMO2: + IWL_DEBUG_RATE("LQ: Legacy switch to MIMO2\n"); /* Set up search table to try MIMO */ memcpy(search_tbl, tbl, sz); - search_tbl->lq_type = LQ_MIMO; search_tbl->is_SGI = 0; - search_tbl->is_fat = 0; - search_tbl->antenna_type = ANT_BOTH; - ret = rs_switch_to_mimo(priv, lq_sta, conf, sta, + search_tbl->ant_type = ANT_AB;/*FIXME:RS*/ + /*FIXME:RS:need to check ant validity*/ + ret = rs_switch_to_mimo2(priv, lq_sta, conf, sta, search_tbl, index); if (!ret) { lq_sta->search_better_tbl = 1; @@ -1385,7 +1339,7 @@ static int rs_move_legacy_other(struct iwl_priv *priv, break; } tbl->action++; - if (tbl->action > IWL_LEGACY_SWITCH_MIMO) + if (tbl->action > IWL_LEGACY_SWITCH_MIMO2) tbl->action = IWL_LEGACY_SWITCH_ANTENNA; if (tbl->action == start_action) @@ -1396,7 +1350,7 @@ static int rs_move_legacy_other(struct iwl_priv *priv, out: tbl->action++; - if (tbl->action > IWL_LEGACY_SWITCH_MIMO) + if (tbl->action > IWL_LEGACY_SWITCH_MIMO2) tbl->action = IWL_LEGACY_SWITCH_ANTENNA; return 0; @@ -1411,7 +1365,6 @@ static int rs_move_siso_to_other(struct iwl_priv *priv, struct sta_info *sta, int index) { - int ret; u8 is_green = lq_sta->is_green; struct iwl4965_scale_tbl_info *tbl = &(lq_sta->lq_info[lq_sta->active_tbl]); @@ -1421,35 +1374,30 @@ static int rs_move_siso_to_other(struct iwl_priv *priv, u32 sz = (sizeof(struct iwl4965_scale_tbl_info) - (sizeof(struct iwl4965_rate_scale_data) * IWL_RATE_COUNT)); u8 start_action = tbl->action; + u8 valid_tx_ant = priv->hw_params.valid_tx_ant; + int ret; for (;;) { lq_sta->action_counter++; switch (tbl->action) { case IWL_SISO_SWITCH_ANTENNA: - IWL_DEBUG_HT("LQ: SISO SWITCH ANTENNA SISO\n"); - search_tbl->lq_type = LQ_NONE; + IWL_DEBUG_RATE("LQ: SISO toggle Antenna\n"); if (window->success_ratio >= IWL_RS_GOOD_RATIO) break; - if (!rs_is_other_ant_connected(lq_sta->antenna, - tbl->antenna_type)) - break; memcpy(search_tbl, tbl, sz); - search_tbl->action = IWL_SISO_SWITCH_MIMO; - rs_toggle_antenna(&(search_tbl->current_rate), - search_tbl); - lq_sta->search_better_tbl = 1; - - goto out; - - case IWL_SISO_SWITCH_MIMO: - IWL_DEBUG_HT("LQ: SISO SWITCH TO MIMO FROM SISO\n"); + if (rs_toggle_antenna(valid_tx_ant, + &search_tbl->current_rate, search_tbl)) { + lq_sta->search_better_tbl = 1; + goto out; + } + break; + case IWL_SISO_SWITCH_MIMO2: + IWL_DEBUG_RATE("LQ: SISO switch to MIMO2\n"); memcpy(search_tbl, tbl, sz); - search_tbl->lq_type = LQ_MIMO; search_tbl->is_SGI = 0; - search_tbl->is_fat = 0; - search_tbl->antenna_type = ANT_BOTH; - ret = rs_switch_to_mimo(priv, lq_sta, conf, sta, + search_tbl->ant_type = ANT_AB; /*FIXME:RS*/ + ret = rs_switch_to_mimo2(priv, lq_sta, conf, sta, search_tbl, index); if (!ret) { lq_sta->search_better_tbl = 1; @@ -1457,29 +1405,34 @@ static int rs_move_siso_to_other(struct iwl_priv *priv, } break; case IWL_SISO_SWITCH_GI: - IWL_DEBUG_HT("LQ: SISO SWITCH TO GI\n"); + 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("LQ: SISO toggle SGI/NGI\n"); memcpy(search_tbl, tbl, sz); - search_tbl->action = 0; - if (search_tbl->is_SGI) - search_tbl->is_SGI = 0; - else if (!is_green) - search_tbl->is_SGI = 1; - else - break; - lq_sta->search_better_tbl = 1; - if ((tbl->lq_type == LQ_SISO) && - (tbl->is_SGI)) { + if (is_green) { + if (!tbl->is_SGI) + break; + else + IWL_ERROR("SGI was set in GF+SISO\n"); + } + search_tbl->is_SGI = !tbl->is_SGI; + rs_set_expected_tpt_table(lq_sta, search_tbl); + if (tbl->is_SGI) { s32 tpt = lq_sta->last_tpt / 100; - if (((!tbl->is_fat) && - (tpt >= expected_tpt_siso20MHz[index])) || - ((tbl->is_fat) && - (tpt >= expected_tpt_siso40MHz[index]))) - lq_sta->search_better_tbl = 0; + if (tpt >= search_tbl->expected_tpt[index]) + break; } - rs_get_expected_tpt_table(lq_sta, search_tbl); - rs_mcs_from_tbl(&search_tbl->current_rate, - search_tbl, index, is_green); + search_tbl->current_rate = rate_n_flags_from_tbl( + search_tbl, index, is_green); + lq_sta->search_better_tbl = 1; goto out; } tbl->action++; @@ -1507,7 +1460,6 @@ static int rs_move_mimo_to_other(struct iwl_priv *priv, struct sta_info *sta, int index) { - int ret; s8 is_green = lq_sta->is_green; struct iwl4965_scale_tbl_info *tbl = &(lq_sta->lq_info[lq_sta->active_tbl]); @@ -1516,24 +1468,24 @@ static int rs_move_mimo_to_other(struct iwl_priv *priv, u32 sz = (sizeof(struct iwl4965_scale_tbl_info) - (sizeof(struct iwl4965_rate_scale_data) * IWL_RATE_COUNT)); u8 start_action = tbl->action; + /*u8 valid_tx_ant = priv->hw_params.valid_tx_ant;*/ + int ret; for (;;) { lq_sta->action_counter++; switch (tbl->action) { case IWL_MIMO_SWITCH_ANTENNA_A: case IWL_MIMO_SWITCH_ANTENNA_B: - IWL_DEBUG_HT("LQ: MIMO SWITCH TO SISO\n"); - + IWL_DEBUG_RATE("LQ: MIMO2 switch to SISO\n"); /* Set up new search table for SISO */ memcpy(search_tbl, tbl, sz); - search_tbl->lq_type = LQ_SISO; - search_tbl->is_SGI = 0; - search_tbl->is_fat = 0; + + /*FIXME:RS:need to check ant validity + C*/ if (tbl->action == IWL_MIMO_SWITCH_ANTENNA_A) - search_tbl->antenna_type = ANT_MAIN; + search_tbl->ant_type = ANT_A; else - search_tbl->antenna_type = ANT_AUX; + search_tbl->ant_type = ANT_B; ret = rs_switch_to_siso(priv, lq_sta, conf, sta, search_tbl, index); @@ -1544,37 +1496,35 @@ static int rs_move_mimo_to_other(struct iwl_priv *priv, break; case IWL_MIMO_SWITCH_GI: - IWL_DEBUG_HT("LQ: MIMO SWITCH TO GI\n"); + 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("LQ: MIMO toggle SGI/NGI\n"); /* Set up new search table for MIMO */ memcpy(search_tbl, tbl, sz); - search_tbl->lq_type = LQ_MIMO; - search_tbl->antenna_type = ANT_BOTH; - search_tbl->action = 0; - if (search_tbl->is_SGI) - search_tbl->is_SGI = 0; - else - search_tbl->is_SGI = 1; - lq_sta->search_better_tbl = 1; - + 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->lq_type == LQ_MIMO) && - (tbl->is_SGI)) { + if (tbl->is_SGI) { s32 tpt = lq_sta->last_tpt / 100; - if (((!tbl->is_fat) && - (tpt >= expected_tpt_mimo20MHz[index])) || - ((tbl->is_fat) && - (tpt >= expected_tpt_mimo40MHz[index]))) - lq_sta->search_better_tbl = 0; + if (tpt >= search_tbl->expected_tpt[index]) + break; } - rs_get_expected_tpt_table(lq_sta, search_tbl); - rs_mcs_from_tbl(&search_tbl->current_rate, - search_tbl, index, is_green); + search_tbl->current_rate = rate_n_flags_from_tbl( + search_tbl, index, is_green); + lq_sta->search_better_tbl = 1; goto out; } @@ -1608,7 +1558,9 @@ static void rs_stay_in_table(struct iwl4965_lq_sta *lq_sta) int i; int active_tbl; int flush_interval_passed = 0; + struct iwl_priv *priv; + priv = lq_sta->drv; active_tbl = lq_sta->active_tbl; tbl = &(lq_sta->lq_info[active_tbl]); @@ -1623,9 +1575,6 @@ static void rs_stay_in_table(struct iwl4965_lq_sta *lq_sta) (unsigned long)(lq_sta->flush_timer + IWL_RATE_SCALE_FLUSH_INTVL)); - /* For now, disable the elapsed time criterion */ - flush_interval_passed = 0; - /* * Check if we should allow search for new modulation mode. * If many frames have failed or succeeded, or we've used @@ -1638,7 +1587,7 @@ static void rs_stay_in_table(struct iwl4965_lq_sta *lq_sta) (lq_sta->total_success > lq_sta->max_success_limit) || ((!lq_sta->search_better_tbl) && (lq_sta->flush_timer) && (flush_interval_passed))) { - IWL_DEBUG_HT("LQ: stay is expired %d %d %d\n:", + IWL_DEBUG_RATE("LQ: stay is expired %d %d %d\n:", lq_sta->total_failed, lq_sta->total_success, flush_interval_passed); @@ -1661,7 +1610,7 @@ static void rs_stay_in_table(struct iwl4965_lq_sta *lq_sta) lq_sta->table_count_limit) { lq_sta->table_count = 0; - IWL_DEBUG_HT("LQ: stay in table clear win\n"); + IWL_DEBUG_RATE("LQ: stay in table clear win\n"); for (i = 0; i < IWL_RATE_COUNT; i++) rs_rate_scale_clear_window( &(tbl->win[i])); @@ -1699,24 +1648,23 @@ static void rs_rate_scale_perform(struct iwl_priv *priv, int high_tpt = IWL_INVALID_VALUE; u32 fail_count; s8 scale_action = 0; - u16 fc, rate_mask; + __le16 fc; + u16 rate_mask; u8 update_lq = 0; struct iwl4965_lq_sta *lq_sta; struct iwl4965_scale_tbl_info *tbl, *tbl1; u16 rate_scale_index_msk = 0; - struct iwl4965_rate mcs_rate; + u32 rate; u8 is_green = 0; u8 active_tbl = 0; u8 done_search = 0; u16 high_low; -#ifdef CONFIG_IWL4965_HT + s32 sr; u8 tid = MAX_TID_COUNT; - __le16 *qc; -#endif IWL_DEBUG_RATE("rate scale calculate new rate for skb\n"); - fc = le16_to_cpu(hdr->frame_control); + fc = hdr->frame_control; if (!ieee80211_is_data(fc) || is_multicast_ether_addr(hdr->addr1)) { /* Send management frames and broadcast/multicast data using * lowest rate. */ @@ -1727,19 +1675,10 @@ static void rs_rate_scale_perform(struct iwl_priv *priv, if (!sta || !sta->rate_ctrl_priv) return; - if (!priv->lq_mngr.lq_ready) { - IWL_DEBUG_RATE("still rate scaling not ready\n"); - return; - } lq_sta = (struct iwl4965_lq_sta *)sta->rate_ctrl_priv; -#ifdef CONFIG_IWL4965_HT - qc = ieee80211_get_qos_ctrl(hdr); - if (qc) { - tid = (u8)(le16_to_cpu(*qc) & 0xf); - rs_tl_add_packet(lq_sta, tid); - } -#endif + tid = rs_tl_add_packet(lq_sta, hdr); + /* * Select rate-scale / modulation-mode table to work with in * the rest of this function: "search" if searching for better @@ -1760,8 +1699,7 @@ static void rs_rate_scale_perform(struct iwl_priv *priv, tbl->lq_type); /* rates available for this association, and for modulation mode */ - rs_get_supported_rates(lq_sta, hdr, tbl->lq_type, - &rate_mask); + rate_mask = rs_get_supported_rates(lq_sta, hdr, tbl->lq_type); IWL_DEBUG_RATE("mask 0x%04X \n", rate_mask); @@ -1781,27 +1719,16 @@ static void rs_rate_scale_perform(struct iwl_priv *priv, if (!rate_scale_index_msk) rate_scale_index_msk = rate_mask; - /* If current rate is no longer supported on current association, - * or user changed preferences for rates, find a new supported rate. */ - if (index < 0 || !((1 << index) & rate_scale_index_msk)) { - index = IWL_INVALID_VALUE; - update_lq = 1; - - /* get the highest available rate */ - for (i = 0; i <= IWL_RATE_COUNT; i++) { - if ((1 << i) & rate_scale_index_msk) - index = i; - } - - if (index == IWL_INVALID_VALUE) { - IWL_WARNING("Can not find a suitable rate\n"); - return; - } + if (!((1 << index) & rate_scale_index_msk)) { + IWL_ERROR("Current Rate is not valid\n"); + return; } /* Get expected throughput table and history window for current rate */ - if (!tbl->expected_tpt) - rs_get_expected_tpt_table(lq_sta, tbl); + if (!tbl->expected_tpt) { + IWL_ERROR("tbl->expected_tpt is NULL\n"); + return; + } window = &(tbl->win[index]); @@ -1813,10 +1740,9 @@ static void rs_rate_scale_perform(struct iwl_priv *priv, * in current association (use new rate found above). */ fail_count = window->counter - window->success_counter; - if (((fail_count < IWL_RATE_MIN_FAILURE_TH) && - (window->success_counter < IWL_RATE_MIN_SUCCESS_TH)) - || (tbl->expected_tpt == NULL)) { - IWL_DEBUG_RATE("LQ: still below TH succ %d total %d " + if ((fail_count < IWL_RATE_MIN_FAILURE_TH) && + (window->success_counter < IWL_RATE_MIN_SUCCESS_TH)) { + IWL_DEBUG_RATE("LQ: still below TH. succ=%d total=%d " "for index %d\n", window->success_counter, window->counter, index); @@ -1827,44 +1753,51 @@ static void rs_rate_scale_perform(struct iwl_priv *priv, * or search for a new one? */ rs_stay_in_table(lq_sta); - /* Set up new rate table in uCode, if needed */ - if (update_lq) { - rs_mcs_from_tbl(&mcs_rate, tbl, index, is_green); - rs_fill_link_cmd(lq_sta, &mcs_rate, &lq_sta->lq); - iwl_send_lq_cmd(priv, &lq_sta->lq, CMD_ASYNC); - } goto out; /* Else we have enough samples; calculate estimate of * actual average throughput */ - } else - window->average_tpt = ((window->success_ratio * + } else { + /*FIXME:RS remove this else if we don't get this error*/ + if (window->average_tpt != ((window->success_ratio * + tbl->expected_tpt[index] + 64) / 128)) { + IWL_ERROR("expected_tpt should have been calculated" + " by now\n"); + window->average_tpt = ((window->success_ratio * tbl->expected_tpt[index] + 64) / 128); + } + } /* If we are searching for better modulation mode, check success. */ if (lq_sta->search_better_tbl) { - int success_limit = IWL_RATE_SCALE_SWITCH; /* If good success, continue using the "search" mode; * no need to send new link quality command, since we're * continuing to use the setup that we've been trying. */ - if ((window->success_ratio > success_limit) || - (window->average_tpt > lq_sta->last_tpt)) { - if (!is_legacy(tbl->lq_type)) { - IWL_DEBUG_HT("LQ: we are switching to HT" - " rate suc %d current tpt %d" - " old tpt %d\n", - window->success_ratio, - window->average_tpt, - lq_sta->last_tpt); + if (window->average_tpt > lq_sta->last_tpt) { + + IWL_DEBUG_RATE("LQ: SWITCHING TO CURRENT TABLE " + "suc=%d cur-tpt=%d old-tpt=%d\n", + window->success_ratio, + window->average_tpt, + lq_sta->last_tpt); + + if (!is_legacy(tbl->lq_type)) lq_sta->enable_counter = 1; - } + /* Swap tables; "search" becomes "active" */ lq_sta->active_tbl = active_tbl; current_tpt = window->average_tpt; /* Else poor success; go back to mode in "active" table */ } else { + + IWL_DEBUG_RATE("LQ: GOING BACK TO THE OLD TABLE " + "suc=%d cur-tpt=%d old-tpt=%d\n", + window->success_ratio, + window->average_tpt, + lq_sta->last_tpt); + /* Nullify "search" table */ tbl->lq_type = LQ_NONE; @@ -1873,13 +1806,11 @@ static void rs_rate_scale_perform(struct iwl_priv *priv, tbl = &(lq_sta->lq_info[active_tbl]); /* Revert to "active" rate and throughput info */ - index = iwl4965_hwrate_to_plcp_idx( - tbl->current_rate.rate_n_flags); + index = iwl_hwrate_to_plcp_idx(tbl->current_rate); current_tpt = lq_sta->last_tpt; /* Need to set up a new rate table in uCode */ update_lq = 1; - IWL_DEBUG_HT("XXY GO BACK TO OLD TABLE\n"); } /* Either way, we've made a decision; modulation mode @@ -1891,11 +1822,13 @@ static void rs_rate_scale_perform(struct iwl_priv *priv, /* (Else) not in search of better modulation mode, try for better * starting rate, while staying in this mode. */ - high_low = rs_get_adjacent_rate(index, rate_scale_index_msk, + high_low = rs_get_adjacent_rate(priv, index, rate_scale_index_msk, tbl->lq_type); low = high_low & 0xff; high = (high_low >> 8) & 0xff; + sr = window->success_ratio; + /* Collect measured throughputs for current and adjacent rates */ current_tpt = window->average_tpt; if (low != IWL_RATE_INVALID) @@ -1903,19 +1836,22 @@ static void rs_rate_scale_perform(struct iwl_priv *priv, if (high != IWL_RATE_INVALID) high_tpt = tbl->win[high].average_tpt; - /* Assume rate increase */ - scale_action = 1; + scale_action = 0; /* Too many failures, decrease rate */ - if ((window->success_ratio <= IWL_RATE_DECREASE_TH) || - (current_tpt == 0)) { + if ((sr <= IWL_RATE_DECREASE_TH) || (current_tpt == 0)) { IWL_DEBUG_RATE("decrease rate because of low success_ratio\n"); scale_action = -1; /* No throughput measured yet for adjacent rates; try increase. */ } else if ((low_tpt == IWL_INVALID_VALUE) && - (high_tpt == IWL_INVALID_VALUE)) - scale_action = 1; + (high_tpt == IWL_INVALID_VALUE)) { + + if (high != IWL_RATE_INVALID && sr >= IWL_RATE_INCREASE_TH) + scale_action = 1; + else if (low != IWL_RATE_INVALID) + scale_action = -1; + } /* Both adjacent throughputs are measured, but neither one has better * throughput; we're using the best rate, don't change it! */ @@ -1931,9 +1867,10 @@ static void rs_rate_scale_perform(struct iwl_priv *priv, /* Higher adjacent rate's throughput is measured */ if (high_tpt != IWL_INVALID_VALUE) { /* Higher rate has better throughput */ - if (high_tpt > current_tpt) + if (high_tpt > current_tpt && + sr >= IWL_RATE_INCREASE_TH) { scale_action = 1; - else { + } else { IWL_DEBUG_RATE ("decrease rate because of high tpt\n"); scale_action = -1; @@ -1946,23 +1883,17 @@ static void rs_rate_scale_perform(struct iwl_priv *priv, IWL_DEBUG_RATE ("decrease rate because of low tpt\n"); scale_action = -1; - } else + } else if (sr >= IWL_RATE_INCREASE_TH) { scale_action = 1; + } } } /* Sanity check; asked for decrease, but success rate or throughput * has been good at old rate. Don't change it. */ - if (scale_action == -1) { - if ((low != IWL_RATE_INVALID) && - ((window->success_ratio > IWL_RATE_HIGH_TH) || + if ((scale_action == -1) && (low != IWL_RATE_INVALID) && + ((sr > IWL_RATE_HIGH_TH) || (current_tpt > (100 * tbl->expected_tpt[low])))) - scale_action = 0; - - /* Sanity check; asked for increase, but success rate has not been great - * even at old rate, higher rate will be worse. Don't change it. */ - } else if ((scale_action == 1) && - (window->success_ratio < IWL_RATE_INCREASE_TH)) scale_action = 0; switch (scale_action) { @@ -1987,15 +1918,15 @@ static void rs_rate_scale_perform(struct iwl_priv *priv, break; } - IWL_DEBUG_HT("choose rate scale index %d action %d low %d " + IWL_DEBUG_RATE("choose rate scale index %d action %d low %d " "high %d type %d\n", index, scale_action, low, high, tbl->lq_type); - lq_update: +lq_update: /* Replace uCode's rate table for the destination station. */ if (update_lq) { - rs_mcs_from_tbl(&mcs_rate, tbl, index, is_green); - rs_fill_link_cmd(lq_sta, &mcs_rate, &lq_sta->lq); + rate = rate_n_flags_from_tbl(tbl, index, is_green); + rs_fill_link_cmd(priv, lq_sta, rate); iwl_send_lq_cmd(priv, &lq_sta->lq, CMD_ASYNC); } @@ -2029,13 +1960,11 @@ static void rs_rate_scale_perform(struct iwl_priv *priv, rs_rate_scale_clear_window(&(tbl->win[i])); /* Use new "search" start rate */ - index = iwl4965_hwrate_to_plcp_idx( - tbl->current_rate.rate_n_flags); + index = iwl_hwrate_to_plcp_idx(tbl->current_rate); - IWL_DEBUG_HT("Switch current mcs: %X index: %d\n", - tbl->current_rate.rate_n_flags, index); - rs_fill_link_cmd(lq_sta, &tbl->current_rate, - &lq_sta->lq); + IWL_DEBUG_RATE("Switch current mcs: %X index: %d\n", + tbl->current_rate, index); + rs_fill_link_cmd(priv, lq_sta, tbl->current_rate); iwl_send_lq_cmd(priv, &lq_sta->lq, CMD_ASYNC); } @@ -2046,13 +1975,11 @@ static void rs_rate_scale_perform(struct iwl_priv *priv, * before next round of mode comparisons. */ tbl1 = &(lq_sta->lq_info[lq_sta->active_tbl]); if (is_legacy(tbl1->lq_type) && -#ifdef CONFIG_IWL4965_HT (!(conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE)) && -#endif (lq_sta->action_counter >= 1)) { lq_sta->action_counter = 0; - IWL_DEBUG_HT("LQ: STAY in legacy table\n"); - rs_set_stay_in_table(1, lq_sta); + IWL_DEBUG_RATE("LQ: STAY in legacy table\n"); + rs_set_stay_in_table(priv, 1, lq_sta); } /* If we're in an HT mode, and all 3 mode switch actions @@ -2060,16 +1987,14 @@ static void rs_rate_scale_perform(struct iwl_priv *priv, * mode for a while before next round of mode comparisons. */ if (lq_sta->enable_counter && (lq_sta->action_counter >= IWL_ACTION_LIMIT)) { -#ifdef CONFIG_IWL4965_HT if ((lq_sta->last_tpt > IWL_AGG_TPT_THREHOLD) && (lq_sta->tx_agg_tid_en & (1 << tid)) && (tid != MAX_TID_COUNT)) { - IWL_DEBUG_HT("try to aggregate tid %d\n", tid); + IWL_DEBUG_RATE("try to aggregate tid %d\n", tid); rs_tl_turn_on_agg(priv, tid, lq_sta, sta); } -#endif /*CONFIG_IWL4965_HT */ lq_sta->action_counter = 0; - rs_set_stay_in_table(0, lq_sta); + rs_set_stay_in_table(priv, 0, lq_sta); } /* @@ -2085,7 +2010,7 @@ static void rs_rate_scale_perform(struct iwl_priv *priv, } out: - rs_mcs_from_tbl(&tbl->current_rate, tbl, index, is_green); + tbl->current_rate = rate_n_flags_from_tbl(tbl, index, is_green); i = index; sta->last_txrate_idx = i; @@ -2105,13 +2030,14 @@ static void rs_initialize_lq(struct iwl_priv *priv, struct ieee80211_conf *conf, struct sta_info *sta) { - int i; struct iwl4965_lq_sta *lq_sta; struct iwl4965_scale_tbl_info *tbl; - u8 active_tbl = 0; int rate_idx; + int i; + u32 rate; u8 use_green = rs_use_green(priv, conf); - struct iwl4965_rate mcs_rate; + u8 active_tbl = 0; + u8 valid_tx_ant; if (!sta || !sta->rate_ctrl_priv) goto out; @@ -2123,6 +2049,8 @@ static void rs_initialize_lq(struct iwl_priv *priv, (priv->iw_mode == IEEE80211_IF_TYPE_IBSS)) goto out; + valid_tx_ant = priv->hw_params.valid_tx_ant; + if (!lq_sta->search_better_tbl) active_tbl = lq_sta->active_tbl; else @@ -2133,22 +2061,23 @@ static void rs_initialize_lq(struct iwl_priv *priv, if ((i < 0) || (i >= IWL_RATE_COUNT)) i = 0; - mcs_rate.rate_n_flags = iwl4965_rates[i].plcp ; - mcs_rate.rate_n_flags |= RATE_MCS_ANT_B_MSK; - mcs_rate.rate_n_flags &= ~RATE_MCS_ANT_A_MSK; + /* FIXME:RS: This is also wrong in 4965 */ + rate = iwl_rates[i].plcp; + rate |= RATE_MCS_ANT_B_MSK; + rate &= ~RATE_MCS_ANT_A_MSK; if (i >= IWL_FIRST_CCK_RATE && i <= IWL_LAST_CCK_RATE) - mcs_rate.rate_n_flags |= RATE_MCS_CCK_MSK; + rate |= RATE_MCS_CCK_MSK; - tbl->antenna_type = ANT_AUX; - rs_get_tbl_info_from_mcs(&mcs_rate, priv->band, tbl, &rate_idx); - if (!rs_is_ant_connected(priv->valid_antenna, tbl->antenna_type)) - rs_toggle_antenna(&mcs_rate, tbl); + tbl->ant_type = ANT_B; + rs_get_tbl_info_from_mcs(rate, priv->band, tbl, &rate_idx); + if (!rs_is_valid_ant(valid_tx_ant, tbl->ant_type)) + rs_toggle_antenna(valid_tx_ant, &rate, tbl); - rs_mcs_from_tbl(&mcs_rate, tbl, rate_idx, use_green); - tbl->current_rate.rate_n_flags = mcs_rate.rate_n_flags; - rs_get_expected_tpt_table(lq_sta, tbl); - rs_fill_link_cmd(lq_sta, &mcs_rate, &lq_sta->lq); + rate = rate_n_flags_from_tbl(tbl, rate_idx, use_green); + tbl->current_rate = rate; + rs_set_expected_tpt_table(lq_sta, tbl); + rs_fill_link_cmd(NULL, lq_sta, rate); iwl_send_lq_cmd(priv, &lq_sta->lq, CMD_ASYNC); out: return; @@ -2165,7 +2094,7 @@ static void rs_get_rate(void *priv_rate, struct net_device *dev, struct ieee80211_conf *conf = &local->hw.conf; struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; struct sta_info *sta; - u16 fc; + __le16 fc; struct iwl_priv *priv = (struct iwl_priv *)priv_rate; struct iwl4965_lq_sta *lq_sta; @@ -2177,10 +2106,10 @@ static void rs_get_rate(void *priv_rate, struct net_device *dev, /* Send management frames and broadcast/multicast data using lowest * rate. */ - fc = le16_to_cpu(hdr->frame_control); + fc = hdr->frame_control; if (!ieee80211_is_data(fc) || is_multicast_ether_addr(hdr->addr1) || !sta || !sta->rate_ctrl_priv) { - sel->rate = rate_lowest(local, sband, sta); + sel->rate_idx = rate_lowest_index(local, sband, sta); goto out; } @@ -2189,13 +2118,13 @@ static void rs_get_rate(void *priv_rate, struct net_device *dev, if ((priv->iw_mode == IEEE80211_IF_TYPE_IBSS) && !lq_sta->ibss_sta_added) { - u8 sta_id = iwl4965_hw_find_station(priv, hdr->addr1); + u8 sta_id = iwl_find_station(priv, hdr->addr1); DECLARE_MAC_BUF(mac); if (sta_id == IWL_INVALID_STATION) { IWL_DEBUG_RATE("LQ: ADD station %s\n", print_mac(mac, hdr->addr1)); - sta_id = iwl4965_add_station_flags(priv, hdr->addr1, + sta_id = iwl_add_station_flags(priv, hdr->addr1, 0, CMD_ASYNC, NULL); } if ((sta_id != IWL_INVALID_STATION)) { @@ -2204,26 +2133,27 @@ static void rs_get_rate(void *priv_rate, struct net_device *dev, lq_sta->ibss_sta_added = 1; rs_initialize_lq(priv, conf, sta); } - if (!lq_sta->ibss_sta_added) - goto done; } -done: if ((i < 0) || (i > IWL_RATE_COUNT)) { - sel->rate = rate_lowest(local, sband, sta); + sel->rate_idx = rate_lowest_index(local, sband, sta); goto out; } - sel->rate = &priv->ieee_rates[i]; + if (sband->band == IEEE80211_BAND_5GHZ) + i -= IWL_FIRST_OFDM_RATE; + sel->rate_idx = i; out: rcu_read_unlock(); } -static void *rs_alloc_sta(void *priv, gfp_t gfp) +static void *rs_alloc_sta(void *priv_rate, gfp_t gfp) { struct iwl4965_lq_sta *lq_sta; + struct iwl_priv *priv; int i, j; + priv = (struct iwl_priv *)priv_rate; IWL_DEBUG_RATE("create station rate scale window\n"); lq_sta = kzalloc(sizeof(struct iwl4965_lq_sta), gfp); @@ -2259,7 +2189,7 @@ static void rs_rate_init(void *priv_rate, void *priv_sta, for (i = 0; i < IWL_RATE_COUNT; i++) rs_rate_scale_clear_window(&(lq_sta->lq_info[j].win[i])); - IWL_DEBUG_RATE("rate scale global init\n"); + IWL_DEBUG_RATE("LQ: *** rate scale global init ***\n"); /* TODO: what is a good starting rate for STA? About middle? Maybe not * the lowest or the highest rate.. Could consider using RSSI from * previous packets? Need to have IEEE 802.1X auth succeed immediately @@ -2267,17 +2197,17 @@ static void rs_rate_init(void *priv_rate, void *priv_sta, lq_sta->ibss_sta_added = 0; if (priv->iw_mode == IEEE80211_IF_TYPE_AP) { - u8 sta_id = iwl4965_hw_find_station(priv, sta->addr); + u8 sta_id = iwl_find_station(priv, sta->addr); DECLARE_MAC_BUF(mac); /* for IBSS the call are from tasklet */ - IWL_DEBUG_HT("LQ: ADD station %s\n", + IWL_DEBUG_RATE("LQ: ADD station %s\n", print_mac(mac, sta->addr)); if (sta_id == IWL_INVALID_STATION) { IWL_DEBUG_RATE("LQ: ADD station %s\n", print_mac(mac, sta->addr)); - sta_id = iwl4965_add_station_flags(priv, sta->addr, + sta_id = iwl_add_station_flags(priv, sta->addr, 0, CMD_ASYNC, NULL); } if ((sta_id != IWL_INVALID_STATION)) { @@ -2300,92 +2230,95 @@ static void rs_rate_init(void *priv_rate, void *priv_sta, sta->last_txrate_idx += IWL_FIRST_OFDM_RATE; lq_sta->is_dup = 0; - lq_sta->valid_antenna = priv->valid_antenna; - lq_sta->antenna = priv->antenna; lq_sta->is_green = rs_use_green(priv, conf); - lq_sta->active_rate = priv->active_rate; - lq_sta->active_rate &= ~(0x1000); + lq_sta->active_legacy_rate = priv->active_rate & ~(0x1000); lq_sta->active_rate_basic = priv->active_rate_basic; lq_sta->band = priv->band; -#ifdef CONFIG_IWL4965_HT /* * active_siso_rate mask includes 9 MBits (bit 5), and CCK (bits 0-3), * supp_rates[] does not; shift to convert format, force 9 MBits off. */ - lq_sta->active_siso_rate = (priv->current_ht_config.supp_mcs_set[0] << 1); - lq_sta->active_siso_rate |= - (priv->current_ht_config.supp_mcs_set[0] & 0x1); + lq_sta->active_siso_rate = conf->ht_conf.supp_mcs_set[0] << 1; + lq_sta->active_siso_rate |= conf->ht_conf.supp_mcs_set[0] & 0x1; lq_sta->active_siso_rate &= ~((u16)0x2); - lq_sta->active_siso_rate = - lq_sta->active_siso_rate << IWL_FIRST_OFDM_RATE; + lq_sta->active_siso_rate <<= IWL_FIRST_OFDM_RATE; /* Same here */ - lq_sta->active_mimo_rate = (priv->current_ht_config.supp_mcs_set[1] << 1); - lq_sta->active_mimo_rate |= - (priv->current_ht_config.supp_mcs_set[1] & 0x1); - lq_sta->active_mimo_rate &= ~((u16)0x2); - lq_sta->active_mimo_rate = - lq_sta->active_mimo_rate << IWL_FIRST_OFDM_RATE; - IWL_DEBUG_HT("SISO RATE 0x%X MIMO RATE 0x%X\n", + lq_sta->active_mimo2_rate = conf->ht_conf.supp_mcs_set[1] << 1; + lq_sta->active_mimo2_rate |= conf->ht_conf.supp_mcs_set[1] & 0x1; + lq_sta->active_mimo2_rate &= ~((u16)0x2); + lq_sta->active_mimo2_rate <<= IWL_FIRST_OFDM_RATE; + + lq_sta->active_mimo3_rate = conf->ht_conf.supp_mcs_set[2] << 1; + lq_sta->active_mimo3_rate |= conf->ht_conf.supp_mcs_set[2] & 0x1; + lq_sta->active_mimo3_rate &= ~((u16)0x2); + lq_sta->active_mimo3_rate <<= IWL_FIRST_OFDM_RATE; + + IWL_DEBUG_RATE("SISO-RATE=%X MIMO2-RATE=%X MIMO3-RATE=%X\n", lq_sta->active_siso_rate, - lq_sta->active_mimo_rate); + lq_sta->active_mimo2_rate, + lq_sta->active_mimo3_rate); + + /* These values will be overriden later */ + lq_sta->lq.general_params.single_stream_ant_msk = ANT_A; + lq_sta->lq.general_params.dual_stream_ant_msk = ANT_AB; + /* as default allow aggregation for all tids */ lq_sta->tx_agg_tid_en = IWL_AGG_ALL_TID; -#endif /*CONFIG_IWL4965_HT*/ -#ifdef CONFIG_MAC80211_DEBUGFS lq_sta->drv = priv; -#endif - - if (priv->assoc_station_added) - priv->lq_mngr.lq_ready = 1; rs_initialize_lq(priv, conf, sta); } -static void rs_fill_link_cmd(struct iwl4965_lq_sta *lq_sta, - struct iwl4965_rate *tx_mcs, - struct iwl_link_quality_cmd *lq_cmd) +static void rs_fill_link_cmd(const struct iwl_priv *priv, + struct iwl4965_lq_sta *lq_sta, + u32 new_rate) { + struct iwl4965_scale_tbl_info tbl_type; int index = 0; int rate_idx; int repeat_rate = 0; - u8 ant_toggle_count = 0; + u8 ant_toggle_cnt = 0; u8 use_ht_possible = 1; - struct iwl4965_rate new_rate; - struct iwl4965_scale_tbl_info tbl_type = { 0 }; + u8 valid_tx_ant = 0; + struct iwl_link_quality_cmd *lq_cmd = &lq_sta->lq; /* Override starting rate (index 0) if needed for debug purposes */ - rs_dbgfs_set_mcs(lq_sta, tx_mcs, index); + rs_dbgfs_set_mcs(lq_sta, &new_rate, index); - /* Interpret rate_n_flags */ - rs_get_tbl_info_from_mcs(tx_mcs, lq_sta->band, + /* Interpret new_rate (rate_n_flags) */ + memset(&tbl_type, 0, sizeof(tbl_type)); + rs_get_tbl_info_from_mcs(new_rate, lq_sta->band, &tbl_type, &rate_idx); /* How many times should we repeat the initial rate? */ if (is_legacy(tbl_type.lq_type)) { - ant_toggle_count = 1; + ant_toggle_cnt = 1; repeat_rate = IWL_NUMBER_TRY; - } else + } else { repeat_rate = IWL_HT_NUMBER_TRY; + } lq_cmd->general_params.mimo_delimiter = is_mimo(tbl_type.lq_type) ? 1 : 0; /* Fill 1st table entry (index 0) */ - lq_cmd->rs_table[index].rate_n_flags = - cpu_to_le32(tx_mcs->rate_n_flags); - new_rate.rate_n_flags = tx_mcs->rate_n_flags; + lq_cmd->rs_table[index].rate_n_flags = cpu_to_le32(new_rate); - if (is_mimo(tbl_type.lq_type) || (tbl_type.antenna_type == ANT_MAIN)) - lq_cmd->general_params.single_stream_ant_msk - = LINK_QUAL_ANT_A_MSK; - else - lq_cmd->general_params.single_stream_ant_msk - = LINK_QUAL_ANT_B_MSK; + if (num_of_ant(tbl_type.ant_type) == 1) { + lq_cmd->general_params.single_stream_ant_msk = + tbl_type.ant_type; + } else if (num_of_ant(tbl_type.ant_type) == 2) { + lq_cmd->general_params.dual_stream_ant_msk = + tbl_type.ant_type; + } /* otherwise we don't modify the existing value */ index++; repeat_rate--; + if (priv) + valid_tx_ant = priv->hw_params.valid_tx_ant; + /* Fill rest of rate table */ while (index < LINK_QUAL_MAX_RETRY_NUM) { /* Repeat initial/next rate. @@ -2393,26 +2326,25 @@ static void rs_fill_link_cmd(struct iwl4965_lq_sta *lq_sta, * For HT IWL_HT_NUMBER_TRY == 3, this executes twice. */ while (repeat_rate > 0 && (index < LINK_QUAL_MAX_RETRY_NUM)) { if (is_legacy(tbl_type.lq_type)) { - if (ant_toggle_count < - NUM_TRY_BEFORE_ANTENNA_TOGGLE) - ant_toggle_count++; - else { - rs_toggle_antenna(&new_rate, &tbl_type); - ant_toggle_count = 1; - } - } + if (ant_toggle_cnt < NUM_TRY_BEFORE_ANT_TOGGLE) + ant_toggle_cnt++; + else if (priv && + rs_toggle_antenna(valid_tx_ant, + &new_rate, &tbl_type)) + ant_toggle_cnt = 1; +} /* Override next rate if needed for debug purposes */ rs_dbgfs_set_mcs(lq_sta, &new_rate, index); /* Fill next table entry */ lq_cmd->rs_table[index].rate_n_flags = - cpu_to_le32(new_rate.rate_n_flags); + cpu_to_le32(new_rate); repeat_rate--; index++; } - rs_get_tbl_info_from_mcs(&new_rate, lq_sta->band, &tbl_type, + rs_get_tbl_info_from_mcs(new_rate, lq_sta->band, &tbl_type, &rate_idx); /* Indicate to uCode which entries might be MIMO. @@ -2422,20 +2354,22 @@ static void rs_fill_link_cmd(struct iwl4965_lq_sta *lq_sta, lq_cmd->general_params.mimo_delimiter = index; /* Get next rate */ - rs_get_lower_rate(lq_sta, &tbl_type, rate_idx, - use_ht_possible, &new_rate); + new_rate = rs_get_lower_rate(lq_sta, &tbl_type, rate_idx, + use_ht_possible); /* How many times should we repeat the next rate? */ if (is_legacy(tbl_type.lq_type)) { - if (ant_toggle_count < NUM_TRY_BEFORE_ANTENNA_TOGGLE) - ant_toggle_count++; - else { - rs_toggle_antenna(&new_rate, &tbl_type); - ant_toggle_count = 1; - } + if (ant_toggle_cnt < NUM_TRY_BEFORE_ANT_TOGGLE) + ant_toggle_cnt++; + else if (priv && + rs_toggle_antenna(valid_tx_ant, + &new_rate, &tbl_type)) + ant_toggle_cnt = 1; + repeat_rate = IWL_NUMBER_TRY; - } else + } else { repeat_rate = IWL_HT_NUMBER_TRY; + } /* Don't allow HT rates after next pass. * rs_get_lower_rate() will change type to LQ_A or LQ_G. */ @@ -2445,14 +2379,13 @@ static void rs_fill_link_cmd(struct iwl4965_lq_sta *lq_sta, rs_dbgfs_set_mcs(lq_sta, &new_rate, index); /* Fill next table entry */ - lq_cmd->rs_table[index].rate_n_flags = - cpu_to_le32(new_rate.rate_n_flags); + lq_cmd->rs_table[index].rate_n_flags = cpu_to_le32(new_rate); index++; repeat_rate--; } - lq_cmd->general_params.dual_stream_ant_msk = 3; + 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); } @@ -2473,15 +2406,17 @@ static void rs_clear(void *priv_rate) IWL_DEBUG_RATE("enter\n"); - priv->lq_mngr.lq_ready = 0; + /* TODO - add rate scale state reset */ IWL_DEBUG_RATE("leave\n"); } -static void rs_free_sta(void *priv, void *priv_sta) +static void rs_free_sta(void *priv_rate, void *priv_sta) { struct iwl4965_lq_sta *lq_sta = priv_sta; + struct iwl_priv *priv; + priv = (struct iwl_priv *)priv_rate; IWL_DEBUG_RATE("enter\n"); kfree(lq_sta); IWL_DEBUG_RATE("leave\n"); @@ -2495,54 +2430,56 @@ static int open_file_generic(struct inode *inode, struct file *file) return 0; } static void rs_dbgfs_set_mcs(struct iwl4965_lq_sta *lq_sta, - struct iwl4965_rate *mcs, int index) + u32 *rate_n_flags, int index) { - u32 base_rate; + struct iwl_priv *priv; - if (lq_sta->band == IEEE80211_BAND_5GHZ) - base_rate = 0x800D; - else - base_rate = 0x820A; - - if (lq_sta->dbg_fixed.rate_n_flags) { - if (index < 12) - mcs->rate_n_flags = lq_sta->dbg_fixed.rate_n_flags; - else - mcs->rate_n_flags = base_rate; + priv = lq_sta->drv; + if (lq_sta->dbg_fixed_rate) { + if (index < 12) { + *rate_n_flags = lq_sta->dbg_fixed_rate; + } else { + if (lq_sta->band == IEEE80211_BAND_5GHZ) + *rate_n_flags = 0x800D; + else + *rate_n_flags = 0x820A; + } IWL_DEBUG_RATE("Fixed rate ON\n"); - return; + } else { + IWL_DEBUG_RATE("Fixed rate OFF\n"); } - - IWL_DEBUG_RATE("Fixed rate OFF\n"); } static ssize_t rs_sta_dbgfs_scale_table_write(struct file *file, const char __user *user_buf, size_t count, loff_t *ppos) { struct iwl4965_lq_sta *lq_sta = file->private_data; + struct iwl_priv *priv; char buf[64]; int buf_size; u32 parsed_rate; + priv = lq_sta->drv; 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", &parsed_rate) == 1) - lq_sta->dbg_fixed.rate_n_flags = parsed_rate; + lq_sta->dbg_fixed_rate = parsed_rate; else - lq_sta->dbg_fixed.rate_n_flags = 0; + lq_sta->dbg_fixed_rate = 0; - lq_sta->active_rate = 0x0FFF; /* 1 - 54 MBits, includes CCK */ - lq_sta->active_siso_rate = 0x1FD0; /* 6 - 60 MBits, no 9, no CCK */ - lq_sta->active_mimo_rate = 0x1FD0; /* 6 - 60 MBits, no 9, no CCK */ + lq_sta->active_legacy_rate = 0x0FFF; /* 1 - 54 MBits, includes CCK */ + lq_sta->active_siso_rate = 0x1FD0; /* 6 - 60 MBits, no 9, no CCK */ + lq_sta->active_mimo2_rate = 0x1FD0; /* 6 - 60 MBits, no 9, no CCK */ + lq_sta->active_mimo3_rate = 0x1FD0; /* 6 - 60 MBits, no 9, no CCK */ IWL_DEBUG_RATE("sta_id %d rate 0x%X\n", - lq_sta->lq.sta_id, lq_sta->dbg_fixed.rate_n_flags); + lq_sta->lq.sta_id, lq_sta->dbg_fixed_rate); - if (lq_sta->dbg_fixed.rate_n_flags) { - rs_fill_link_cmd(lq_sta, &lq_sta->dbg_fixed, &lq_sta->lq); + if (lq_sta->dbg_fixed_rate) { + rs_fill_link_cmd(NULL, lq_sta, lq_sta->dbg_fixed_rate); iwl_send_lq_cmd(lq_sta->drv, &lq_sta->lq, CMD_ASYNC); } @@ -2561,9 +2498,9 @@ static ssize_t rs_sta_dbgfs_scale_table_read(struct file *file, desc += sprintf(buff+desc, "sta_id %d\n", lq_sta->lq.sta_id); desc += sprintf(buff+desc, "failed=%d success=%d rate=0%X\n", lq_sta->total_failed, lq_sta->total_success, - lq_sta->active_rate); + lq_sta->active_legacy_rate); desc += sprintf(buff+desc, "fixed rate 0x%X\n", - lq_sta->dbg_fixed.rate_n_flags); + lq_sta->dbg_fixed_rate); 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, @@ -2613,7 +2550,7 @@ static ssize_t rs_sta_dbgfs_stats_table_read(struct file *file, lq_sta->lq_info[i].is_SGI, lq_sta->lq_info[i].is_fat, lq_sta->lq_info[i].is_dup, - lq_sta->lq_info[i].current_rate.rate_n_flags); + lq_sta->lq_info[i].current_rate); for (j = 0; j < IWL_RATE_COUNT; j++) { desc += sprintf(buff+desc, "counter=%d success=%d %%=%d\n", @@ -2640,11 +2577,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); -#ifdef CONFIG_IWL4965_HT 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); -#endif } @@ -2653,9 +2588,7 @@ static void rs_remove_debugfs(void *priv, void *priv_sta) struct iwl4965_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); -#ifdef CONFIG_IWL4965_HT debugfs_remove(lq_sta->rs_sta_dbgfs_tx_agg_tid_en_file); -#endif } #endif @@ -2703,7 +2636,7 @@ int iwl4965_fill_rs_info(struct ieee80211_hw *hw, char *buf, u8 sta_id) lq_sta = (void *)sta->rate_ctrl_priv; lq_type = lq_sta->lq_info[lq_sta->active_tbl].lq_type; - antenna = lq_sta->lq_info[lq_sta->active_tbl].antenna_type; + antenna = lq_sta->lq_info[lq_sta->active_tbl].ant_type; if (is_legacy(lq_type)) i = IWL_RATE_54M_INDEX; @@ -2715,7 +2648,7 @@ int iwl4965_fill_rs_info(struct ieee80211_hw *hw, char *buf, u8 sta_id) int active = lq_sta->active_tbl; cnt += - sprintf(&buf[cnt], " %2dMbs: ", iwl4965_rates[i].ieee / 2); + sprintf(&buf[cnt], " %2dMbs: ", iwl_rates[i].ieee / 2); mask = (1ULL << (IWL_RATE_MAX_WINDOW - 1)); for (j = 0; j < IWL_RATE_MAX_WINDOW; j++, mask >>= 1) @@ -2726,7 +2659,7 @@ int iwl4965_fill_rs_info(struct ieee80211_hw *hw, char *buf, u8 sta_id) samples += lq_sta->lq_info[active].win[i].counter; good += lq_sta->lq_info[active].win[i].success_counter; success += lq_sta->lq_info[active].win[i].success_counter * - iwl4965_rates[i].ieee; + iwl_rates[i].ieee; if (lq_sta->lq_info[active].win[i].stamp) { int delta = @@ -2746,10 +2679,11 @@ int iwl4965_fill_rs_info(struct ieee80211_hw *hw, char *buf, u8 sta_id) i = j; } - /* Display the average rate of all samples taken. - * - * NOTE: We multiply # of samples by 2 since the IEEE measurement - * added from iwl4965_rates is actually 2X the rate */ + /* + * Display the average rate of all samples taken. + * NOTE: We multiply # of samples by 2 since the IEEE measurement + * added from iwl_rates is actually 2X the rate. + */ if (samples) cnt += sprintf(&buf[cnt], "\nAverage rate is %3d.%02dMbs over last %4dms\n" @@ -2767,13 +2701,6 @@ int iwl4965_fill_rs_info(struct ieee80211_hw *hw, char *buf, u8 sta_id) return cnt; } -void iwl4965_rate_scale_init(struct ieee80211_hw *hw, s32 sta_id) -{ - struct iwl_priv *priv = hw->priv; - - priv->lq_mngr.lq_ready = 1; -} - int iwl4965_rate_control_register(void) { return ieee80211_rate_control_register(&rs_ops); diff --git a/drivers/net/wireless/iwlwifi/iwl-4965-rs.h b/drivers/net/wireless/iwlwifi/iwl-4965-rs.h index 866e378aa385..9b9972885aa5 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965-rs.h +++ b/drivers/net/wireless/iwlwifi/iwl-4965-rs.h @@ -27,12 +27,13 @@ #ifndef __iwl_4965_rs_h__ #define __iwl_4965_rs_h__ -#include "iwl-4965.h" +#include "iwl-dev.h" -struct iwl4965_rate_info { +struct iwl_rate_info { u8 plcp; /* uCode API: IWL_RATE_6M_PLCP, etc. */ u8 plcp_siso; /* uCode API: IWL_RATE_SISO_6M_PLCP, etc. */ - u8 plcp_mimo; /* uCode API: IWL_RATE_MIMO_6M_PLCP, etc. */ + u8 plcp_mimo2; /* uCode API: IWL_RATE_MIMO2_6M_PLCP, etc. */ + u8 plcp_mimo3; /* uCode API: IWL_RATE_MIMO3_6M_PLCP, etc. */ u8 ieee; /* MAC header: IWL_RATE_6M_IEEE, etc. */ u8 prev_ieee; /* previous rate in IEEE speeds */ u8 next_ieee; /* next rate in IEEE speeds */ @@ -44,7 +45,7 @@ struct iwl4965_rate_info { /* * These serve as indexes into - * struct iwl4965_rate_info iwl4965_rates[IWL_RATE_COUNT]; + * struct iwl_rate_info iwl_rates[IWL_RATE_COUNT]; */ enum { IWL_RATE_1M_INDEX = 0, @@ -60,9 +61,9 @@ enum { IWL_RATE_48M_INDEX, IWL_RATE_54M_INDEX, IWL_RATE_60M_INDEX, - IWL_RATE_COUNT, + IWL_RATE_COUNT, /*FIXME:RS:change to IWL_RATE_INDEX_COUNT,*/ IWL_RATE_INVM_INDEX = IWL_RATE_COUNT, - IWL_RATE_INVALID = IWL_RATE_INVM_INDEX + IWL_RATE_INVALID = IWL_RATE_COUNT, }; enum { @@ -97,11 +98,13 @@ enum { IWL_RATE_36M_PLCP = 11, IWL_RATE_48M_PLCP = 1, IWL_RATE_54M_PLCP = 3, - IWL_RATE_60M_PLCP = 3, + IWL_RATE_60M_PLCP = 3,/*FIXME:RS:should be removed*/ IWL_RATE_1M_PLCP = 10, IWL_RATE_2M_PLCP = 20, IWL_RATE_5M_PLCP = 55, IWL_RATE_11M_PLCP = 110, + /*FIXME:RS:change to IWL_RATE_LEGACY_??M_PLCP */ + /*FIXME:RS:add IWL_RATE_LEGACY_INVM_PLCP = 0,*/ }; /* 4965 uCode API values for OFDM high-throughput (HT) bit rates */ @@ -114,16 +117,25 @@ enum { IWL_RATE_SISO_48M_PLCP = 5, IWL_RATE_SISO_54M_PLCP = 6, IWL_RATE_SISO_60M_PLCP = 7, - IWL_RATE_MIMO_6M_PLCP = 0x8, - IWL_RATE_MIMO_12M_PLCP = 0x9, - IWL_RATE_MIMO_18M_PLCP = 0xa, - IWL_RATE_MIMO_24M_PLCP = 0xb, - IWL_RATE_MIMO_36M_PLCP = 0xc, - IWL_RATE_MIMO_48M_PLCP = 0xd, - IWL_RATE_MIMO_54M_PLCP = 0xe, - IWL_RATE_MIMO_60M_PLCP = 0xf, + IWL_RATE_MIMO2_6M_PLCP = 0x8, + IWL_RATE_MIMO2_12M_PLCP = 0x9, + IWL_RATE_MIMO2_18M_PLCP = 0xa, + IWL_RATE_MIMO2_24M_PLCP = 0xb, + IWL_RATE_MIMO2_36M_PLCP = 0xc, + IWL_RATE_MIMO2_48M_PLCP = 0xd, + IWL_RATE_MIMO2_54M_PLCP = 0xe, + IWL_RATE_MIMO2_60M_PLCP = 0xf, + IWL_RATE_MIMO3_6M_PLCP = 0x10, + IWL_RATE_MIMO3_12M_PLCP = 0x11, + IWL_RATE_MIMO3_18M_PLCP = 0x12, + IWL_RATE_MIMO3_24M_PLCP = 0x13, + IWL_RATE_MIMO3_36M_PLCP = 0x14, + IWL_RATE_MIMO3_48M_PLCP = 0x15, + IWL_RATE_MIMO3_54M_PLCP = 0x16, + IWL_RATE_MIMO3_60M_PLCP = 0x17, IWL_RATE_SISO_INVM_PLCP, - IWL_RATE_MIMO_INVM_PLCP = IWL_RATE_SISO_INVM_PLCP, + IWL_RATE_MIMO2_INVM_PLCP = IWL_RATE_SISO_INVM_PLCP, + IWL_RATE_MIMO3_INVM_PLCP = IWL_RATE_SISO_INVM_PLCP, }; /* MAC header values for bit rates */ @@ -196,11 +208,11 @@ enum { /* possible actions when in legacy mode */ #define IWL_LEGACY_SWITCH_ANTENNA 0 #define IWL_LEGACY_SWITCH_SISO 1 -#define IWL_LEGACY_SWITCH_MIMO 2 +#define IWL_LEGACY_SWITCH_MIMO2 2 /* possible actions when in siso mode */ #define IWL_SISO_SWITCH_ANTENNA 0 -#define IWL_SISO_SWITCH_MIMO 1 +#define IWL_SISO_SWITCH_MIMO2 1 #define IWL_SISO_SWITCH_GI 2 /* possible actions when in mimo mode */ @@ -208,6 +220,10 @@ enum { #define IWL_MIMO_SWITCH_ANTENNA_B 1 #define IWL_MIMO_SWITCH_GI 2 +/*FIXME:RS:separate MIMO2/3 transitions*/ + +/*FIXME:RS:add posible acctions for MIMO3*/ + #define IWL_ACTION_LIMIT 3 /* # possible actions */ #define LQ_SIZE 2 /* 2 mode tables: "Active" and "Search" */ @@ -224,43 +240,52 @@ enum { #define TID_MAX_TIME_DIFF ((TID_QUEUE_MAX_SIZE - 1) * TID_QUEUE_CELL_SPACING) #define TIME_WRAP_AROUND(x, y) (((y) > (x)) ? (y) - (x) : (0-(x)) + (y)) -extern const struct iwl4965_rate_info iwl4965_rates[IWL_RATE_COUNT]; +extern const struct iwl_rate_info iwl_rates[IWL_RATE_COUNT]; -enum iwl4965_table_type { +enum iwl_table_type { LQ_NONE, LQ_G, /* legacy types */ LQ_A, LQ_SISO, /* high-throughput types */ - LQ_MIMO, + LQ_MIMO2, + LQ_MIMO3, LQ_MAX, }; #define is_legacy(tbl) (((tbl) == LQ_G) || ((tbl) == LQ_A)) -#define is_siso(tbl) (((tbl) == LQ_SISO)) -#define is_mimo(tbl) (((tbl) == LQ_MIMO)) +#define is_siso(tbl) ((tbl) == LQ_SISO) +#define is_mimo2(tbl) ((tbl) == LQ_MIMO2) +#define is_mimo3(tbl) ((tbl) == LQ_MIMO3) +#define is_mimo(tbl) (is_mimo2(tbl) || is_mimo3(tbl)) #define is_Ht(tbl) (is_siso(tbl) || is_mimo(tbl)) -#define is_a_band(tbl) (((tbl) == LQ_A)) -#define is_g_and(tbl) (((tbl) == LQ_G)) - -/* 4965 has 2 antennas/chains for Tx (but 3 for Rx) */ -enum iwl4965_antenna_type { - ANT_NONE, - ANT_MAIN, - ANT_AUX, - ANT_BOTH, -}; +#define is_a_band(tbl) ((tbl) == LQ_A) +#define is_g_and(tbl) ((tbl) == LQ_G) + +#define ANT_NONE 0x0 +#define ANT_A BIT(0) +#define ANT_B BIT(1) +#define ANT_AB (ANT_A | ANT_B) +#define ANT_C BIT(2) +#define ANT_AC (ANT_A | ANT_C) +#define ANT_BC (ANT_B | ANT_C) +#define ANT_ABC (ANT_AB | ANT_C) + +static inline u8 num_of_ant(u8 mask) +{ + return !!((mask) & ANT_A) + + !!((mask) & ANT_B) + + !!((mask) & ANT_C); +} static inline u8 iwl4965_get_prev_ieee_rate(u8 rate_index) { - u8 rate = iwl4965_rates[rate_index].prev_ieee; + u8 rate = iwl_rates[rate_index].prev_ieee; if (rate == IWL_RATE_INVALID) rate = rate_index; return rate; } -extern int iwl4965_hwrate_to_plcp_idx(u32 rate_n_flags); - /** * iwl4965_fill_rs_info - Fill an output text buffer with the rate representation * @@ -271,14 +296,6 @@ extern int iwl4965_hwrate_to_plcp_idx(u32 rate_n_flags); extern int iwl4965_fill_rs_info(struct ieee80211_hw *, char *buf, u8 sta_id); /** - * iwl4965_rate_scale_init - Initialize the rate scale table based on assoc info - * - * The specific throughput table used is based on the type of network - * the associated with, including A, B, G, and G w/ TGG protection - */ -extern void iwl4965_rate_scale_init(struct ieee80211_hw *hw, s32 sta_id); - -/** * iwl4965_rate_control_register - Register the rate control algorithm callbacks * * Since the rate control algorithm is hardware specific, there is no need diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index de330ae0ca95..9afecb813716 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -39,81 +39,33 @@ #include <asm/unaligned.h> #include "iwl-eeprom.h" -#include "iwl-4965.h" +#include "iwl-dev.h" #include "iwl-core.h" #include "iwl-io.h" #include "iwl-helpers.h" +#include "iwl-calib.h" +#include "iwl-sta.h" + +static int iwl4965_send_tx_power(struct iwl_priv *priv); +static int iwl4965_hw_get_temperature(const struct iwl_priv *priv); + +/* Change firmware file name, using "-" and incrementing number, + * *only* when uCode interface or architecture changes so that it + * is not compatible with earlier drivers. + * This number will also appear in << 8 position of 1st dword of uCode file */ +#define IWL4965_UCODE_API "-2" + /* module parameters */ static struct iwl_mod_params iwl4965_mod_params = { - .num_of_queues = IWL4965_MAX_NUM_QUEUES, + .num_of_queues = IWL49_NUM_QUEUES, + .num_of_ampdu_queues = IWL49_NUM_AMPDU_QUEUES, .enable_qos = 1, .amsdu_size_8K = 1, + .restart_fw = 1, /* the rest are 0 by default */ }; -static void iwl4965_hw_card_show_info(struct iwl_priv *priv); - -#define IWL_DECLARE_RATE_INFO(r, s, ip, in, rp, rn, pp, np) \ - [IWL_RATE_##r##M_INDEX] = { IWL_RATE_##r##M_PLCP, \ - IWL_RATE_SISO_##s##M_PLCP, \ - IWL_RATE_MIMO_##s##M_PLCP, \ - IWL_RATE_##r##M_IEEE, \ - IWL_RATE_##ip##M_INDEX, \ - IWL_RATE_##in##M_INDEX, \ - IWL_RATE_##rp##M_INDEX, \ - IWL_RATE_##rn##M_INDEX, \ - IWL_RATE_##pp##M_INDEX, \ - IWL_RATE_##np##M_INDEX } - -/* - * Parameter order: - * rate, ht rate, prev rate, next rate, prev tgg rate, next tgg rate - * - * If there isn't a valid next or previous rate then INV is used which - * maps to IWL_RATE_INVALID - * - */ -const struct iwl4965_rate_info iwl4965_rates[IWL_RATE_COUNT] = { - IWL_DECLARE_RATE_INFO(1, INV, INV, 2, INV, 2, INV, 2), /* 1mbps */ - IWL_DECLARE_RATE_INFO(2, INV, 1, 5, 1, 5, 1, 5), /* 2mbps */ - IWL_DECLARE_RATE_INFO(5, INV, 2, 6, 2, 11, 2, 11), /*5.5mbps */ - IWL_DECLARE_RATE_INFO(11, INV, 9, 12, 9, 12, 5, 18), /* 11mbps */ - IWL_DECLARE_RATE_INFO(6, 6, 5, 9, 5, 11, 5, 11), /* 6mbps */ - IWL_DECLARE_RATE_INFO(9, 6, 6, 11, 6, 11, 5, 11), /* 9mbps */ - IWL_DECLARE_RATE_INFO(12, 12, 11, 18, 11, 18, 11, 18), /* 12mbps */ - IWL_DECLARE_RATE_INFO(18, 18, 12, 24, 12, 24, 11, 24), /* 18mbps */ - IWL_DECLARE_RATE_INFO(24, 24, 18, 36, 18, 36, 18, 36), /* 24mbps */ - IWL_DECLARE_RATE_INFO(36, 36, 24, 48, 24, 48, 24, 48), /* 36mbps */ - IWL_DECLARE_RATE_INFO(48, 48, 36, 54, 36, 54, 36, 54), /* 48mbps */ - IWL_DECLARE_RATE_INFO(54, 54, 48, INV, 48, INV, 48, INV),/* 54mbps */ - IWL_DECLARE_RATE_INFO(60, 60, 48, INV, 48, INV, 48, INV),/* 60mbps */ -}; - -#ifdef CONFIG_IWL4965_HT - -static const u16 default_tid_to_tx_fifo[] = { - IWL_TX_FIFO_AC1, - IWL_TX_FIFO_AC0, - IWL_TX_FIFO_AC0, - IWL_TX_FIFO_AC1, - IWL_TX_FIFO_AC2, - IWL_TX_FIFO_AC2, - IWL_TX_FIFO_AC3, - IWL_TX_FIFO_AC3, - IWL_TX_FIFO_NONE, - IWL_TX_FIFO_NONE, - IWL_TX_FIFO_NONE, - IWL_TX_FIFO_NONE, - IWL_TX_FIFO_NONE, - IWL_TX_FIFO_NONE, - IWL_TX_FIFO_NONE, - IWL_TX_FIFO_NONE, - IWL_TX_FIFO_AC3 -}; - -#endif /*CONFIG_IWL4965_HT */ - /* check contents of special bootstrap uCode SRAM */ static int iwl4965_verify_bsm(struct iwl_priv *priv) { @@ -192,15 +144,18 @@ static int iwl4965_load_bsm(struct iwl_priv *priv) IWL_DEBUG_INFO("Begin load bsm\n"); + priv->ucode_type = UCODE_RT; + /* make sure bootstrap program is no larger than BSM's SRAM size */ if (len > IWL_MAX_BSM_SIZE) return -EINVAL; /* Tell bootstrap uCode where to find the "Initialize" uCode * in host DRAM ... host DRAM physical address bits 35:4 for 4965. - * NOTE: iwl4965_initialize_alive_start() will replace these values, + * NOTE: iwl_init_alive_start() will replace these values, * after the "initialize" uCode has run, to point to - * runtime/protocol instructions and backup data cache. */ + * runtime/protocol instructions and backup data cache. + */ pinst = priv->ucode_init.p_addr >> 4; pdata = priv->ucode_init_data.p_addr >> 4; inst_len = priv->ucode_init.len; @@ -259,271 +214,134 @@ static int iwl4965_load_bsm(struct iwl_priv *priv) return 0; } -static int iwl4965_init_drv(struct iwl_priv *priv) +/** + * iwl4965_set_ucode_ptrs - Set uCode address location + * + * Tell initialization uCode where to find runtime uCode. + * + * BSM registers initially contain pointers to initialization uCode. + * We need to replace them to load runtime uCode inst and data, + * and to save runtime data when powering down. + */ +static int iwl4965_set_ucode_ptrs(struct iwl_priv *priv) { - int ret; - int i; - - priv->antenna = (enum iwl4965_antenna)priv->cfg->mod_params->antenna; - priv->retry_rate = 1; - 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); - spin_lock_init(&priv->lq_mngr.lock); - - priv->shared_virt = pci_alloc_consistent(priv->pci_dev, - sizeof(struct iwl4965_shared), - &priv->shared_phys); - - if (!priv->shared_virt) { - ret = -ENOMEM; - goto err; - } - - memset(priv->shared_virt, 0, sizeof(struct iwl4965_shared)); - - - for (i = 0; i < IWL_IBSS_MAC_HASH_SIZE; i++) - INIT_LIST_HEAD(&priv->ibss_mac_hash[i]); - - INIT_LIST_HEAD(&priv->free_frames); - - mutex_init(&priv->mutex); - - /* Clear the driver's (not device's) station table */ - iwlcore_clear_stations_table(priv); - - priv->data_retry_limit = -1; - priv->ieee_channels = NULL; - priv->ieee_rates = NULL; - priv->band = IEEE80211_BAND_2GHZ; - - priv->iw_mode = IEEE80211_IF_TYPE_STA; - - priv->use_ant_b_for_management_frame = 1; /* start with ant B */ - priv->valid_antenna = 0x7; /* assume all 3 connected */ - priv->ps_mode = IWL_MIMO_PS_NONE; - - /* Choose which receivers/antennas to use */ - iwl4965_set_rxon_chain(priv); - - iwlcore_reset_qos(priv); - - priv->qos_data.qos_active = 0; - priv->qos_data.qos_cap.val = 0; - - iwlcore_set_rxon_channel(priv, IEEE80211_BAND_2GHZ, 6); + dma_addr_t pinst; + dma_addr_t pdata; + unsigned long flags; + int ret = 0; - priv->rates_mask = IWL_RATES_MASK; - /* If power management is turned on, default to AC mode */ - priv->power_mode = IWL_POWER_AC; - priv->user_txpower_limit = IWL_DEFAULT_TX_POWER; + /* bits 35:4 for 4965 */ + pinst = priv->ucode_code.p_addr >> 4; + pdata = priv->ucode_data_backup.p_addr >> 4; - ret = iwl_init_channel_map(priv); + spin_lock_irqsave(&priv->lock, flags); + ret = iwl_grab_nic_access(priv); if (ret) { - IWL_ERROR("initializing regulatory failed: %d\n", ret); - goto err; + spin_unlock_irqrestore(&priv->lock, flags); + return ret; } - ret = iwl4965_init_geos(priv); - if (ret) { - IWL_ERROR("initializing geos failed: %d\n", ret); - goto err_free_channel_map; - } + /* 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); + iwl_write_prph(priv, BSM_DRAM_DATA_BYTECOUNT_REG, + priv->ucode_data.len); - ret = ieee80211_register_hw(priv->hw); - if (ret) { - IWL_ERROR("Failed to register network device (error %d)\n", - ret); - goto err_free_geos; - } + /* Inst bytecount must be last to set up, bit 31 signals uCode + * 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); - priv->hw->conf.beacon_int = 100; - priv->mac80211_registered = 1; + spin_unlock_irqrestore(&priv->lock, flags); - return 0; + IWL_DEBUG_INFO("Runtime uCode pointers are set.\n"); -err_free_geos: - iwl4965_free_geos(priv); -err_free_channel_map: - iwl_free_channel_map(priv); -err: return ret; } -static int is_fat_channel(__le32 rxon_flags) -{ - return (rxon_flags & RXON_FLG_CHANNEL_MODE_PURE_40_MSK) || - (rxon_flags & RXON_FLG_CHANNEL_MODE_MIXED_MSK); -} - -static u8 is_single_stream(struct iwl_priv *priv) -{ -#ifdef CONFIG_IWL4965_HT - if (!priv->current_ht_config.is_ht || - (priv->current_ht_config.supp_mcs_set[1] == 0) || - (priv->ps_mode == IWL_MIMO_PS_STATIC)) - return 1; -#else - return 1; -#endif /*CONFIG_IWL4965_HT */ - return 0; -} - -int iwl4965_hwrate_to_plcp_idx(u32 rate_n_flags) -{ - int idx = 0; - - /* 4965 HT rate format */ - if (rate_n_flags & RATE_MCS_HT_MSK) { - idx = (rate_n_flags & 0xff); - - if (idx >= IWL_RATE_MIMO_6M_PLCP) - idx = idx - IWL_RATE_MIMO_6M_PLCP; - - idx += IWL_FIRST_OFDM_RATE; - /* skip 9M not supported in ht*/ - if (idx >= IWL_RATE_9M_INDEX) - idx += 1; - if ((idx >= IWL_FIRST_OFDM_RATE) && (idx <= IWL_LAST_OFDM_RATE)) - return idx; - - /* 4965 legacy rate format, search for match in table */ - } else { - for (idx = 0; idx < ARRAY_SIZE(iwl4965_rates); idx++) - if (iwl4965_rates[idx].plcp == (rate_n_flags & 0xFF)) - return idx; +/** + * iwl4965_init_alive_start - Called after REPLY_ALIVE notification received + * + * Called after REPLY_ALIVE notification received from "initialize" uCode. + * + * The 4965 "initialize" ALIVE reply contains calibration data for: + * Voltage, temperature, and MIMO tx gain correction, now stored in priv + * (3945 does not contain this data). + * + * Tell "initialize" uCode to go ahead and load the runtime uCode. +*/ +static void iwl4965_init_alive_start(struct iwl_priv *priv) +{ + /* Check alive response for "valid" sign from uCode */ + if (priv->card_alive_init.is_valid != UCODE_VALID_OK) { + /* We had an error bringing up the hardware, so take it + * all the way back down so we can try again */ + IWL_DEBUG_INFO("Initialize Alive failed.\n"); + goto restart; + } + + /* Bootstrap uCode has loaded initialize uCode ... verify inst image. + * This is a paranoid check, because we would not have gotten the + * "initialize" alive if code weren't properly loaded. */ + if (iwl_verify_ucode(priv)) { + /* Runtime instruction load was bad; + * take it all the way back down so we can try again */ + IWL_DEBUG_INFO("Bad \"initialize\" uCode load.\n"); + goto restart; + } + + /* Calculate temperature */ + priv->temperature = iwl4965_hw_get_temperature(priv); + + /* Send pointers to protocol/runtime uCode image ... init code will + * load and launch runtime uCode, which will send us another "Alive" + * notification. */ + IWL_DEBUG_INFO("Initialization Alive received.\n"); + if (iwl4965_set_ucode_ptrs(priv)) { + /* Runtime instruction load won't happen; + * take it all the way back down so we can try again */ + IWL_DEBUG_INFO("Couldn't set up uCode pointers.\n"); + goto restart; } + return; - return -1; +restart: + queue_work(priv->workqueue, &priv->restart); } -/** - * translate ucode response to mac80211 tx status control values - */ -void iwl4965_hwrate_to_tx_control(struct iwl_priv *priv, u32 rate_n_flags, - struct ieee80211_tx_control *control) +static int is_fat_channel(__le32 rxon_flags) { - int rate_index; - - control->antenna_sel_tx = - ((rate_n_flags & RATE_MCS_ANT_AB_MSK) >> RATE_MCS_ANT_POS); - if (rate_n_flags & RATE_MCS_HT_MSK) - control->flags |= IEEE80211_TXCTL_OFDM_HT; - if (rate_n_flags & RATE_MCS_GF_MSK) - control->flags |= IEEE80211_TXCTL_GREEN_FIELD; - if (rate_n_flags & RATE_MCS_FAT_MSK) - control->flags |= IEEE80211_TXCTL_40_MHZ_WIDTH; - if (rate_n_flags & RATE_MCS_DUP_MSK) - control->flags |= IEEE80211_TXCTL_DUP_DATA; - if (rate_n_flags & RATE_MCS_SGI_MSK) - control->flags |= IEEE80211_TXCTL_SHORT_GI; - /* since iwl4965_hwrate_to_plcp_idx is band indifferent, we always use - * IEEE80211_BAND_2GHZ band as it contains all the rates */ - rate_index = iwl4965_hwrate_to_plcp_idx(rate_n_flags); - if (rate_index == -1) - control->tx_rate = NULL; - else - control->tx_rate = - &priv->bands[IEEE80211_BAND_2GHZ].bitrates[rate_index]; + return (rxon_flags & RXON_FLG_CHANNEL_MODE_PURE_40_MSK) || + (rxon_flags & RXON_FLG_CHANNEL_MODE_MIXED_MSK); } /* - * Determine how many receiver/antenna chains to use. - * More provides better reception via diversity. Fewer saves power. - * MIMO (dual stream) requires at least 2, but works better with 3. - * This does not determine *which* chains to use, just how many. + * EEPROM handlers */ -static int iwl4965_get_rx_chain_counter(struct iwl_priv *priv, - u8 *idle_state, u8 *rx_state) -{ - u8 is_single = is_single_stream(priv); - u8 is_cam = test_bit(STATUS_POWER_PMI, &priv->status) ? 0 : 1; - - /* # of Rx chains to use when expecting MIMO. */ - if (is_single || (!is_cam && (priv->ps_mode == IWL_MIMO_PS_STATIC))) - *rx_state = 2; - else - *rx_state = 3; - - /* # Rx chains when idling and maybe trying to save power */ - switch (priv->ps_mode) { - case IWL_MIMO_PS_STATIC: - case IWL_MIMO_PS_DYNAMIC: - *idle_state = (is_cam) ? 2 : 1; - break; - case IWL_MIMO_PS_NONE: - *idle_state = (is_cam) ? *rx_state : 1; - break; - default: - *idle_state = 1; - break; - } - return 0; -} - -int iwl4965_hw_rxq_stop(struct iwl_priv *priv) +static int iwl4965_eeprom_check_version(struct iwl_priv *priv) { - int rc; - unsigned long flags; + u16 eeprom_ver; + u16 calib_ver; - spin_lock_irqsave(&priv->lock, flags); - rc = iwl_grab_nic_access(priv); - if (rc) { - spin_unlock_irqrestore(&priv->lock, flags); - return rc; - } + eeprom_ver = iwl_eeprom_query16(priv, EEPROM_VERSION); - /* stop Rx DMA */ - iwl_write_direct32(priv, FH_MEM_RCSR_CHNL0_CONFIG_REG, 0); - rc = iwl_poll_direct_bit(priv, FH_MEM_RSSR_RX_STATUS_REG, - (1 << 24), 1000); - if (rc < 0) - IWL_ERROR("Can't stop Rx DMA.\n"); + calib_ver = iwl_eeprom_query16(priv, EEPROM_4965_CALIB_VERSION_OFFSET); - iwl_release_nic_access(priv); - spin_unlock_irqrestore(&priv->lock, flags); + if (eeprom_ver < EEPROM_4965_EEPROM_VERSION || + calib_ver < EEPROM_4965_TX_POWER_VERSION) + goto err; return 0; -} - -u8 iwl4965_hw_find_station(struct iwl_priv *priv, const u8 *addr) -{ - int i; - int start = 0; - int ret = IWL_INVALID_STATION; - unsigned long flags; - DECLARE_MAC_BUF(mac); - - if ((priv->iw_mode == IEEE80211_IF_TYPE_IBSS) || - (priv->iw_mode == IEEE80211_IF_TYPE_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[i].used) && - (!compare_ether_addr - (priv->stations[i].sta.sta.addr, addr))) { - ret = i; - goto out; - } - - IWL_DEBUG_ASSOC_LIMIT("can not find STA %s total %d\n", - print_mac(mac, addr), priv->num_stations); +err: + IWL_ERROR("Unsuported EEPROM VER=0x%x < 0x%x CALIB=0x%x < 0x%x\n", + eeprom_ver, EEPROM_4965_EEPROM_VERSION, + calib_ver, EEPROM_4965_TX_POWER_VERSION); + return -EINVAL; - out: - spin_unlock_irqrestore(&priv->sta_lock, flags); - return ret; } - -static int iwl4965_nic_set_pwr_src(struct iwl_priv *priv, int pwr_max) +int iwl4965_set_pwr_src(struct iwl_priv *priv, enum iwl_pwr_src src) { int ret; unsigned long flags; @@ -535,340 +353,130 @@ static int iwl4965_nic_set_pwr_src(struct iwl_priv *priv, int pwr_max) return ret; } - if (!pwr_max) { + if (src == IWL_PWR_SRC_VAUX) { u32 val; - ret = pci_read_config_dword(priv->pci_dev, PCI_POWER_SOURCE, - &val); + &val); - if (val & PCI_CFG_PMC_PME_FROM_D3COLD_SUPPORT) + if (val & PCI_CFG_PMC_PME_FROM_D3COLD_SUPPORT) { iwl_set_bits_mask_prph(priv, APMG_PS_CTRL_REG, - APMG_PS_CTRL_VAL_PWR_SRC_VAUX, - ~APMG_PS_CTRL_MSK_PWR_SRC); - } else + APMG_PS_CTRL_VAL_PWR_SRC_VAUX, + ~APMG_PS_CTRL_MSK_PWR_SRC); + } + } 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); - spin_unlock_irqrestore(&priv->lock, flags); - - return ret; -} - -static int iwl4965_rx_init(struct iwl_priv *priv, struct iwl4965_rx_queue *rxq) -{ - int ret; - unsigned long flags; - unsigned int rb_size; - - spin_lock_irqsave(&priv->lock, flags); - ret = iwl_grab_nic_access(priv); - if (ret) { - spin_unlock_irqrestore(&priv->lock, flags); - return ret; + APMG_PS_CTRL_VAL_PWR_SRC_VMAIN, + ~APMG_PS_CTRL_MSK_PWR_SRC); } - if (priv->cfg->mod_params->amsdu_size_8K) - rb_size = FH_RCSR_RX_CONFIG_REG_VAL_RB_SIZE_8K; - else - rb_size = FH_RCSR_RX_CONFIG_REG_VAL_RB_SIZE_4K; - - /* Stop Rx DMA */ - iwl_write_direct32(priv, FH_MEM_RCSR_CHNL0_CONFIG_REG, 0); - - /* Reset driver's Rx queue write index */ - iwl_write_direct32(priv, FH_RSCSR_CHNL0_RBDCB_WPTR_REG, 0); - - /* Tell device where to find RBD circular buffer in DRAM */ - iwl_write_direct32(priv, FH_RSCSR_CHNL0_RBDCB_BASE_REG, - rxq->dma_addr >> 8); - - /* Tell device where in DRAM to update its Rx status */ - iwl_write_direct32(priv, FH_RSCSR_CHNL0_STTS_WPTR_REG, - (priv->shared_phys + - offsetof(struct iwl4965_shared, rb_closed)) >> 4); - - /* Enable Rx DMA, enable host interrupt, Rx buffer size 4k, 256 RBDs */ - iwl_write_direct32(priv, FH_MEM_RCSR_CHNL0_CONFIG_REG, - FH_RCSR_RX_CONFIG_CHNL_EN_ENABLE_VAL | - FH_RCSR_CHNL0_RX_CONFIG_IRQ_DEST_INT_HOST_VAL | - rb_size | - /* 0x10 << 4 | */ - (RX_QUEUE_SIZE_LOG << - FH_RCSR_RX_CONFIG_RBDCB_SIZE_BITSHIFT)); - - /* - * iwl_write32(priv,CSR_INT_COAL_REG,0); - */ - - iwl_release_nic_access(priv); - spin_unlock_irqrestore(&priv->lock, flags); - - return 0; -} - -/* Tell 4965 where to find the "keep warm" buffer */ -static int iwl4965_kw_init(struct iwl_priv *priv) -{ - unsigned long flags; - int rc; - - spin_lock_irqsave(&priv->lock, flags); - rc = iwl_grab_nic_access(priv); - if (rc) - goto out; - - iwl_write_direct32(priv, IWL_FH_KW_MEM_ADDR_REG, - priv->kw.dma_addr >> 4); iwl_release_nic_access(priv); -out: spin_unlock_irqrestore(&priv->lock, flags); - return rc; -} - -static int iwl4965_kw_alloc(struct iwl_priv *priv) -{ - struct pci_dev *dev = priv->pci_dev; - struct iwl4965_kw *kw = &priv->kw; - - kw->size = IWL4965_KW_SIZE; /* TBW need set somewhere else */ - kw->v_addr = pci_alloc_consistent(dev, kw->size, &kw->dma_addr); - if (!kw->v_addr) - return -ENOMEM; - return 0; + return ret; } -/** - * iwl4965_kw_free - Free the "keep warm" buffer +/* + * Activate/Deactivat Tx DMA/FIFO channels according tx fifos mask + * must be called under priv->lock and mac access */ -static void iwl4965_kw_free(struct iwl_priv *priv) +static void iwl4965_txq_set_sched(struct iwl_priv *priv, u32 mask) { - struct pci_dev *dev = priv->pci_dev; - struct iwl4965_kw *kw = &priv->kw; - - if (kw->v_addr) { - pci_free_consistent(dev, kw->size, kw->v_addr, kw->dma_addr); - memset(kw, 0, sizeof(*kw)); - } + iwl_write_prph(priv, IWL49_SCD_TXFACT, mask); } -/** - * iwl4965_txq_ctx_reset - Reset TX queue context - * Destroys all DMA structures and initialise them again - * - * @param priv - * @return error code - */ -static int iwl4965_txq_ctx_reset(struct iwl_priv *priv) +static int iwl4965_apm_init(struct iwl_priv *priv) { - int rc = 0; - int txq_id, slots_num; - unsigned long flags; - - iwl4965_kw_free(priv); - - /* Free all tx/cmd queues and keep-warm buffer */ - iwl4965_hw_txq_ctx_free(priv); - - /* Alloc keep-warm buffer */ - rc = iwl4965_kw_alloc(priv); - if (rc) { - IWL_ERROR("Keep Warm allocation failed"); - goto error_kw; - } - - spin_lock_irqsave(&priv->lock, flags); - - rc = iwl_grab_nic_access(priv); - if (unlikely(rc)) { - IWL_ERROR("TX reset failed"); - spin_unlock_irqrestore(&priv->lock, flags); - goto error_reset; - } - - /* Turn off all Tx DMA channels */ - iwl_write_prph(priv, IWL49_SCD_TXFACT, 0); - iwl_release_nic_access(priv); - spin_unlock_irqrestore(&priv->lock, flags); - - /* Tell 4965 where to find the keep-warm buffer */ - rc = iwl4965_kw_init(priv); - if (rc) { - IWL_ERROR("kw_init failed\n"); - goto error_reset; - } - - /* Alloc and init all (default 16) Tx queues, - * including the command queue (#4) */ - for (txq_id = 0; txq_id < priv->hw_params.max_txq_num; txq_id++) { - slots_num = (txq_id == IWL_CMD_QUEUE_NUM) ? - TFD_CMD_SLOTS : TFD_TX_CMD_SLOTS; - rc = iwl4965_tx_queue_init(priv, &priv->txq[txq_id], slots_num, - txq_id); - if (rc) { - IWL_ERROR("Tx %d queue init failed\n", txq_id); - goto error; - } - } - - return rc; - - error: - iwl4965_hw_txq_ctx_free(priv); - error_reset: - iwl4965_kw_free(priv); - error_kw: - return rc; -} - -int iwl4965_hw_nic_init(struct iwl_priv *priv) -{ - int rc; - unsigned long flags; - struct iwl4965_rx_queue *rxq = &priv->rxq; - u8 rev_id; - u32 val; - u8 val_link; - - iwl4965_power_init_handle(priv); + int ret = 0; - /* nic_init */ - spin_lock_irqsave(&priv->lock, flags); + iwl_set_bit(priv, CSR_GIO_CHICKEN_BITS, + CSR_GIO_CHICKEN_BITS_REG_BIT_DIS_L0S_EXIT_TIMER); + /* disable L0s without affecting L1 :don't wait for ICH L0s bug W/A) */ iwl_set_bit(priv, CSR_GIO_CHICKEN_BITS, - CSR_GIO_CHICKEN_BITS_REG_BIT_DIS_L0S_EXIT_TIMER); + CSR_GIO_CHICKEN_BITS_REG_BIT_L1A_NO_L0S_RX); + /* set "initialization complete" bit to move adapter + * D0U* --> D0A* state */ iwl_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE); - rc = iwl_poll_bit(priv, CSR_GP_CNTRL, - CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, - CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000); - if (rc < 0) { - spin_unlock_irqrestore(&priv->lock, flags); - IWL_DEBUG_INFO("Failed to init the card\n"); - return rc; - } - rc = iwl_grab_nic_access(priv); - if (rc) { - spin_unlock_irqrestore(&priv->lock, flags); - return rc; + /* wait for clock stabilization */ + ret = iwl_poll_bit(priv, CSR_GP_CNTRL, + CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, + CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000); + if (ret < 0) { + IWL_DEBUG_INFO("Failed to init the card\n"); + goto out; } - iwl_read_prph(priv, APMG_CLK_CTRL_REG); + ret = iwl_grab_nic_access(priv); + if (ret) + goto out; - iwl_write_prph(priv, APMG_CLK_CTRL_REG, - APMG_CLK_VAL_DMA_CLK_RQT | APMG_CLK_VAL_BSM_CLK_RQT); - iwl_read_prph(priv, APMG_CLK_CTRL_REG); + /* enable DMA */ + iwl_write_prph(priv, APMG_CLK_CTRL_REG, APMG_CLK_VAL_DMA_CLK_RQT | + APMG_CLK_VAL_BSM_CLK_RQT); udelay(20); + /* disable L1-Active */ iwl_set_bits_prph(priv, APMG_PCIDEV_STT_REG, - APMG_PCIDEV_STT_VAL_L1_ACT_DIS); + APMG_PCIDEV_STT_VAL_L1_ACT_DIS); iwl_release_nic_access(priv); - iwl_write32(priv, CSR_INT_COALESCING, 512 / 32); - spin_unlock_irqrestore(&priv->lock, flags); +out: + return ret; +} - /* Determine HW type */ - rc = pci_read_config_byte(priv->pci_dev, PCI_REVISION_ID, &rev_id); - if (rc) - return rc; - IWL_DEBUG_INFO("HW Revision ID = 0x%X\n", rev_id); +static void iwl4965_nic_config(struct iwl_priv *priv) +{ + unsigned long flags; + u32 val; + u16 radio_cfg; + u8 val_link; - iwl4965_nic_set_pwr_src(priv, 1); spin_lock_irqsave(&priv->lock, flags); - if ((rev_id & 0x80) == 0x80 && (rev_id & 0x7f) < 8) { + if ((priv->rev_id & 0x80) == 0x80 && (priv->rev_id & 0x7f) < 8) { pci_read_config_dword(priv->pci_dev, PCI_REG_WUM8, &val); /* Enable No Snoop field */ pci_write_config_dword(priv->pci_dev, PCI_REG_WUM8, val & ~(1 << 11)); } - spin_unlock_irqrestore(&priv->lock, flags); - - if (priv->eeprom.calib_version < EEPROM_TX_POWER_VERSION_NEW) { - IWL_ERROR("Older EEPROM detected! Aborting.\n"); - return -EINVAL; - } - pci_read_config_byte(priv->pci_dev, PCI_LINK_CTRL, &val_link); - /* disable L1 entry -- workaround for pre-B1 */ - pci_write_config_byte(priv->pci_dev, PCI_LINK_CTRL, val_link & ~0x02); + /* L1 is enabled by BIOS */ + if ((val_link & PCI_LINK_VAL_L1_EN) == PCI_LINK_VAL_L1_EN) + /* diable L0S disabled L1A enabled */ + iwl_set_bit(priv, CSR_GIO_REG, CSR_GIO_REG_VAL_L0S_ENABLED); + else + /* L0S enabled L1A disabled */ + iwl_clear_bit(priv, CSR_GIO_REG, CSR_GIO_REG_VAL_L0S_ENABLED); - spin_lock_irqsave(&priv->lock, flags); + radio_cfg = iwl_eeprom_query16(priv, EEPROM_RADIO_CONFIG); - /* set CSR_HW_CONFIG_REG for uCode use */ + /* write radio config values to register */ + if (EEPROM_RF_CFG_TYPE_MSK(radio_cfg) == EEPROM_4965_RF_CFG_TYPE_MAX) + iwl_set_bit(priv, CSR_HW_IF_CONFIG_REG, + EEPROM_RF_CFG_TYPE_MSK(radio_cfg) | + EEPROM_RF_CFG_STEP_MSK(radio_cfg) | + EEPROM_RF_CFG_DASH_MSK(radio_cfg)); + /* set CSR_HW_CONFIG_REG for uCode use */ iwl_set_bit(priv, CSR_HW_IF_CONFIG_REG, - CSR49_HW_IF_CONFIG_REG_BIT_4965_R | - CSR49_HW_IF_CONFIG_REG_BIT_RADIO_SI | - CSR49_HW_IF_CONFIG_REG_BIT_MAC_SI); + CSR_HW_IF_CONFIG_REG_BIT_RADIO_SI | + CSR_HW_IF_CONFIG_REG_BIT_MAC_SI); - rc = iwl_grab_nic_access(priv); - if (rc < 0) { - spin_unlock_irqrestore(&priv->lock, flags); - IWL_DEBUG_INFO("Failed to init the card\n"); - return rc; - } + priv->calib_info = (struct iwl_eeprom_calib_info *) + iwl_eeprom_query_addr(priv, EEPROM_4965_CALIB_TXPOWER_OFFSET); - iwl_read_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, APMG_PS_CTRL_VAL_RESET_REQ); - - iwl_release_nic_access(priv); spin_unlock_irqrestore(&priv->lock, flags); - - iwl4965_hw_card_show_info(priv); - - /* end nic_init */ - - /* Allocate the RX queue, or reset if it is already allocated */ - if (!rxq->bd) { - rc = iwl4965_rx_queue_alloc(priv); - if (rc) { - IWL_ERROR("Unable to initialize Rx queue\n"); - return -ENOMEM; - } - } else - iwl4965_rx_queue_reset(priv, rxq); - - iwl4965_rx_replenish(priv); - - iwl4965_rx_init(priv, rxq); - - spin_lock_irqsave(&priv->lock, flags); - - rxq->need_update = 1; - iwl4965_rx_queue_update_write_ptr(priv, rxq); - - spin_unlock_irqrestore(&priv->lock, flags); - - /* Allocate and init all Tx and Command queues */ - rc = iwl4965_txq_ctx_reset(priv); - if (rc) - return rc; - - if (priv->eeprom.sku_cap & EEPROM_SKU_CAP_SW_RF_KILL_ENABLE) - IWL_DEBUG_RF_KILL("SW RF KILL supported in EEPROM.\n"); - - if (priv->eeprom.sku_cap & EEPROM_SKU_CAP_HW_RF_KILL_ENABLE) - IWL_DEBUG_RF_KILL("HW RF KILL supported in EEPROM.\n"); - - set_bit(STATUS_INIT, &priv->status); - - return 0; } -int iwl4965_hw_nic_stop_master(struct iwl_priv *priv) +static int iwl4965_apm_stop_master(struct iwl_priv *priv) { - int rc = 0; - u32 reg_val; + int ret = 0; unsigned long flags; spin_lock_irqsave(&priv->lock, flags); @@ -876,64 +484,24 @@ int iwl4965_hw_nic_stop_master(struct iwl_priv *priv) /* set stop master bit */ iwl_set_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_STOP_MASTER); - reg_val = iwl_read32(priv, CSR_GP_CNTRL); - - if (CSR_GP_CNTRL_REG_FLAG_MAC_POWER_SAVE == - (reg_val & CSR_GP_CNTRL_REG_MSK_POWER_SAVE_TYPE)) - IWL_DEBUG_INFO("Card in power save, master is already " - "stopped\n"); - else { - rc = iwl_poll_bit(priv, CSR_RESET, + ret = iwl_poll_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_MASTER_DISABLED, CSR_RESET_REG_FLAG_MASTER_DISABLED, 100); - if (rc < 0) { - spin_unlock_irqrestore(&priv->lock, flags); - return rc; - } - } + if (ret < 0) + goto out; +out: spin_unlock_irqrestore(&priv->lock, flags); IWL_DEBUG_INFO("stop master\n"); - return rc; -} - -/** - * iwl4965_hw_txq_ctx_stop - Stop all Tx DMA channels, free Tx queue memory - */ -void iwl4965_hw_txq_ctx_stop(struct iwl_priv *priv) -{ - - int txq_id; - unsigned long flags; - - /* Stop each Tx DMA channel, and wait for it to be idle */ - for (txq_id = 0; txq_id < priv->hw_params.max_txq_num; txq_id++) { - spin_lock_irqsave(&priv->lock, flags); - if (iwl_grab_nic_access(priv)) { - spin_unlock_irqrestore(&priv->lock, flags); - continue; - } - - iwl_write_direct32(priv, - IWL_FH_TCSR_CHNL_TX_CONFIG_REG(txq_id), 0x0); - iwl_poll_direct_bit(priv, IWL_FH_TSSR_TX_STATUS_REG, - IWL_FH_TSSR_TX_STATUS_REG_MSK_CHNL_IDLE - (txq_id), 200); - iwl_release_nic_access(priv); - spin_unlock_irqrestore(&priv->lock, flags); - } - - /* Deallocate memory for all Tx queues */ - iwl4965_hw_txq_ctx_free(priv); + return ret; } -int iwl4965_hw_nic_reset(struct iwl_priv *priv) +static void iwl4965_apm_stop(struct iwl_priv *priv) { - int rc = 0; unsigned long flags; - iwl4965_hw_nic_stop_master(priv); + iwl4965_apm_stop_master(priv); spin_lock_irqsave(&priv->lock, flags); @@ -942,508 +510,66 @@ int iwl4965_hw_nic_reset(struct iwl_priv *priv) udelay(10); iwl_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE); - rc = iwl_poll_bit(priv, CSR_RESET, - CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, - CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25); - - udelay(10); - - rc = iwl_grab_nic_access(priv); - if (!rc) { - 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_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); - spin_unlock_irqrestore(&priv->lock, flags); - - return rc; - } -#define REG_RECALIB_PERIOD (60) - -/** - * iwl4965_bg_statistics_periodic - Timer callback to queue statistics - * - * This callback is provided in order to send a statistics request. - * - * This timer function is continually reset to execute within - * REG_RECALIB_PERIOD seconds since the last STATISTICS_NOTIFICATION - * was received. We need to ensure we receive the statistics in order - * to update the temperature used for calibrating the TXPOWER. - */ -static void iwl4965_bg_statistics_periodic(unsigned long data) +static int iwl4965_apm_reset(struct iwl_priv *priv) { - struct iwl_priv *priv = (struct iwl_priv *)data; - - if (test_bit(STATUS_EXIT_PENDING, &priv->status)) - return; - - iwl_send_statistics_request(priv, CMD_ASYNC); -} - -#define CT_LIMIT_CONST 259 -#define TM_CT_KILL_THRESHOLD 110 - -void iwl4965_rf_kill_ct_config(struct iwl_priv *priv) -{ - struct iwl4965_ct_kill_config cmd; - u32 R1, R2, R3; - u32 temp_th; - u32 crit_temperature; - unsigned long flags; int ret = 0; + unsigned long flags; - spin_lock_irqsave(&priv->lock, flags); - iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, - CSR_UCODE_DRV_GP1_REG_BIT_CT_KILL_EXIT); - spin_unlock_irqrestore(&priv->lock, flags); - - if (priv->statistics.flag & STATISTICS_REPLY_FLG_FAT_MODE_MSK) { - R1 = (s32)le32_to_cpu(priv->card_alive_init.therm_r1[1]); - R2 = (s32)le32_to_cpu(priv->card_alive_init.therm_r2[1]); - R3 = (s32)le32_to_cpu(priv->card_alive_init.therm_r3[1]); - } else { - R1 = (s32)le32_to_cpu(priv->card_alive_init.therm_r1[0]); - R2 = (s32)le32_to_cpu(priv->card_alive_init.therm_r2[0]); - R3 = (s32)le32_to_cpu(priv->card_alive_init.therm_r3[0]); - } - - temp_th = CELSIUS_TO_KELVIN(TM_CT_KILL_THRESHOLD); - - crit_temperature = ((temp_th * (R3-R1))/CT_LIMIT_CONST) + R2; - cmd.critical_temperature_R = cpu_to_le32(crit_temperature); - ret = iwl_send_cmd_pdu(priv, REPLY_CT_KILL_CONFIG_CMD, - sizeof(cmd), &cmd); - if (ret) - IWL_ERROR("REPLY_CT_KILL_CONFIG_CMD failed\n"); - else - IWL_DEBUG_INFO("REPLY_CT_KILL_CONFIG_CMD succeeded\n"); -} - -#ifdef CONFIG_IWL4965_SENSITIVITY - -/* "false alarms" are signals that our DSP tries to lock onto, - * but then determines that they are either noise, or transmissions - * from a distant wireless network (also "noise", really) that get - * "stepped on" by stronger transmissions within our own network. - * This algorithm attempts to set a sensitivity level that is high - * enough to receive all of our own network traffic, but not so - * high that our DSP gets too busy trying to lock onto non-network - * activity/noise. */ -static int iwl4965_sens_energy_cck(struct iwl_priv *priv, - u32 norm_fa, - u32 rx_enable_time, - struct statistics_general_data *rx_info) -{ - u32 max_nrg_cck = 0; - int i = 0; - u8 max_silence_rssi = 0; - u32 silence_ref = 0; - u8 silence_rssi_a = 0; - u8 silence_rssi_b = 0; - u8 silence_rssi_c = 0; - u32 val; - - /* "false_alarms" values below are cross-multiplications to assess the - * numbers of false alarms within the measured period of actual Rx - * (Rx is off when we're txing), vs the min/max expected false alarms - * (some should be expected if rx is sensitive enough) in a - * hypothetical listening period of 200 time units (TU), 204.8 msec: - * - * MIN_FA/fixed-time < false_alarms/actual-rx-time < MAX_FA/beacon-time - * - * */ - u32 false_alarms = norm_fa * 200 * 1024; - u32 max_false_alarms = MAX_FA_CCK * rx_enable_time; - u32 min_false_alarms = MIN_FA_CCK * rx_enable_time; - struct iwl4965_sensitivity_data *data = NULL; - - data = &(priv->sensitivity_data); - - data->nrg_auto_corr_silence_diff = 0; - - /* Find max silence rssi among all 3 receivers. - * This is background noise, which may include transmissions from other - * networks, measured during silence before our network's beacon */ - silence_rssi_a = (u8)((rx_info->beacon_silence_rssi_a & - ALL_BAND_FILTER) >> 8); - silence_rssi_b = (u8)((rx_info->beacon_silence_rssi_b & - ALL_BAND_FILTER) >> 8); - silence_rssi_c = (u8)((rx_info->beacon_silence_rssi_c & - ALL_BAND_FILTER) >> 8); - - val = max(silence_rssi_b, silence_rssi_c); - max_silence_rssi = max(silence_rssi_a, (u8) val); - - /* Store silence rssi in 20-beacon history table */ - data->nrg_silence_rssi[data->nrg_silence_idx] = max_silence_rssi; - data->nrg_silence_idx++; - if (data->nrg_silence_idx >= NRG_NUM_PREV_STAT_L) - data->nrg_silence_idx = 0; - - /* Find max silence rssi across 20 beacon history */ - for (i = 0; i < NRG_NUM_PREV_STAT_L; i++) { - val = data->nrg_silence_rssi[i]; - silence_ref = max(silence_ref, val); - } - IWL_DEBUG_CALIB("silence a %u, b %u, c %u, 20-bcn max %u\n", - silence_rssi_a, silence_rssi_b, silence_rssi_c, - silence_ref); - - /* Find max rx energy (min value!) among all 3 receivers, - * measured during beacon frame. - * Save it in 10-beacon history table. */ - i = data->nrg_energy_idx; - val = min(rx_info->beacon_energy_b, rx_info->beacon_energy_c); - data->nrg_value[i] = min(rx_info->beacon_energy_a, val); - - data->nrg_energy_idx++; - if (data->nrg_energy_idx >= 10) - data->nrg_energy_idx = 0; - - /* Find min rx energy (max value) across 10 beacon history. - * This is the minimum signal level that we want to receive well. - * Add backoff (margin so we don't miss slightly lower energy frames). - * This establishes an upper bound (min value) for energy threshold. */ - max_nrg_cck = data->nrg_value[0]; - for (i = 1; i < 10; i++) - max_nrg_cck = (u32) max(max_nrg_cck, (data->nrg_value[i])); - max_nrg_cck += 6; - - IWL_DEBUG_CALIB("rx energy a %u, b %u, c %u, 10-bcn max/min %u\n", - rx_info->beacon_energy_a, rx_info->beacon_energy_b, - rx_info->beacon_energy_c, max_nrg_cck - 6); - - /* Count number of consecutive beacons with fewer-than-desired - * false alarms. */ - if (false_alarms < min_false_alarms) - data->num_in_cck_no_fa++; - else - data->num_in_cck_no_fa = 0; - IWL_DEBUG_CALIB("consecutive bcns with few false alarms = %u\n", - data->num_in_cck_no_fa); - - /* If we got too many false alarms this time, reduce sensitivity */ - if (false_alarms > max_false_alarms) { - IWL_DEBUG_CALIB("norm FA %u > max FA %u\n", - false_alarms, max_false_alarms); - IWL_DEBUG_CALIB("... reducing sensitivity\n"); - data->nrg_curr_state = IWL_FA_TOO_MANY; - - if (data->auto_corr_cck > AUTO_CORR_MAX_TH_CCK) { - /* Store for "fewer than desired" on later beacon */ - data->nrg_silence_ref = silence_ref; - - /* increase energy threshold (reduce nrg value) - * to decrease sensitivity */ - if (data->nrg_th_cck > (NRG_MAX_CCK + NRG_STEP_CCK)) - data->nrg_th_cck = data->nrg_th_cck - - NRG_STEP_CCK; - } - - /* increase auto_corr values to decrease sensitivity */ - if (data->auto_corr_cck < AUTO_CORR_MAX_TH_CCK) - data->auto_corr_cck = AUTO_CORR_MAX_TH_CCK + 1; - else { - val = data->auto_corr_cck + AUTO_CORR_STEP_CCK; - data->auto_corr_cck = min((u32)AUTO_CORR_MAX_CCK, val); - } - val = data->auto_corr_cck_mrc + AUTO_CORR_STEP_CCK; - data->auto_corr_cck_mrc = min((u32)AUTO_CORR_MAX_CCK_MRC, val); - - /* Else if we got fewer than desired, increase sensitivity */ - } else if (false_alarms < min_false_alarms) { - data->nrg_curr_state = IWL_FA_TOO_FEW; - - /* Compare silence level with silence level for most recent - * healthy number or too many false alarms */ - data->nrg_auto_corr_silence_diff = (s32)data->nrg_silence_ref - - (s32)silence_ref; - - IWL_DEBUG_CALIB("norm FA %u < min FA %u, silence diff %d\n", - false_alarms, min_false_alarms, - data->nrg_auto_corr_silence_diff); - - /* Increase value to increase sensitivity, but only if: - * 1a) previous beacon did *not* have *too many* false alarms - * 1b) AND there's a significant difference in Rx levels - * from a previous beacon with too many, or healthy # FAs - * OR 2) We've seen a lot of beacons (100) with too few - * false alarms */ - if ((data->nrg_prev_state != IWL_FA_TOO_MANY) && - ((data->nrg_auto_corr_silence_diff > NRG_DIFF) || - (data->num_in_cck_no_fa > MAX_NUMBER_CCK_NO_FA))) { - - IWL_DEBUG_CALIB("... increasing sensitivity\n"); - /* Increase nrg value to increase sensitivity */ - val = data->nrg_th_cck + NRG_STEP_CCK; - data->nrg_th_cck = min((u32)NRG_MIN_CCK, val); - - /* Decrease auto_corr values to increase sensitivity */ - val = data->auto_corr_cck - AUTO_CORR_STEP_CCK; - data->auto_corr_cck = max((u32)AUTO_CORR_MIN_CCK, val); - - val = data->auto_corr_cck_mrc - AUTO_CORR_STEP_CCK; - data->auto_corr_cck_mrc = - max((u32)AUTO_CORR_MIN_CCK_MRC, val); - - } else - IWL_DEBUG_CALIB("... but not changing sensitivity\n"); - - /* Else we got a healthy number of false alarms, keep status quo */ - } else { - IWL_DEBUG_CALIB(" FA in safe zone\n"); - data->nrg_curr_state = IWL_FA_GOOD_RANGE; - - /* Store for use in "fewer than desired" with later beacon */ - data->nrg_silence_ref = silence_ref; - - /* If previous beacon had too many false alarms, - * give it some extra margin by reducing sensitivity again - * (but don't go below measured energy of desired Rx) */ - if (IWL_FA_TOO_MANY == data->nrg_prev_state) { - IWL_DEBUG_CALIB("... increasing margin\n"); - data->nrg_th_cck -= NRG_MARGIN; - } - } - - /* Make sure the energy threshold does not go above the measured - * energy of the desired Rx signals (reduced by backoff margin), - * or else we might start missing Rx frames. - * Lower value is higher energy, so we use max()! - */ - data->nrg_th_cck = max(max_nrg_cck, data->nrg_th_cck); - IWL_DEBUG_CALIB("new nrg_th_cck %u\n", data->nrg_th_cck); - - data->nrg_prev_state = data->nrg_curr_state; - - return 0; -} - - -static int iwl4965_sens_auto_corr_ofdm(struct iwl_priv *priv, - u32 norm_fa, - u32 rx_enable_time) -{ - u32 val; - u32 false_alarms = norm_fa * 200 * 1024; - u32 max_false_alarms = MAX_FA_OFDM * rx_enable_time; - u32 min_false_alarms = MIN_FA_OFDM * rx_enable_time; - struct iwl4965_sensitivity_data *data = NULL; - - data = &(priv->sensitivity_data); - - /* If we got too many false alarms this time, reduce sensitivity */ - if (false_alarms > max_false_alarms) { - - IWL_DEBUG_CALIB("norm FA %u > max FA %u)\n", - false_alarms, max_false_alarms); - - val = data->auto_corr_ofdm + AUTO_CORR_STEP_OFDM; - data->auto_corr_ofdm = - min((u32)AUTO_CORR_MAX_OFDM, val); - - val = data->auto_corr_ofdm_mrc + AUTO_CORR_STEP_OFDM; - data->auto_corr_ofdm_mrc = - min((u32)AUTO_CORR_MAX_OFDM_MRC, val); - - val = data->auto_corr_ofdm_x1 + AUTO_CORR_STEP_OFDM; - data->auto_corr_ofdm_x1 = - min((u32)AUTO_CORR_MAX_OFDM_X1, val); - - val = data->auto_corr_ofdm_mrc_x1 + AUTO_CORR_STEP_OFDM; - data->auto_corr_ofdm_mrc_x1 = - min((u32)AUTO_CORR_MAX_OFDM_MRC_X1, val); - } - - /* Else if we got fewer than desired, increase sensitivity */ - else if (false_alarms < min_false_alarms) { - - IWL_DEBUG_CALIB("norm FA %u < min FA %u\n", - false_alarms, min_false_alarms); - - val = data->auto_corr_ofdm - AUTO_CORR_STEP_OFDM; - data->auto_corr_ofdm = - max((u32)AUTO_CORR_MIN_OFDM, val); - - val = data->auto_corr_ofdm_mrc - AUTO_CORR_STEP_OFDM; - data->auto_corr_ofdm_mrc = - max((u32)AUTO_CORR_MIN_OFDM_MRC, val); - - val = data->auto_corr_ofdm_x1 - AUTO_CORR_STEP_OFDM; - data->auto_corr_ofdm_x1 = - max((u32)AUTO_CORR_MIN_OFDM_X1, val); - - val = data->auto_corr_ofdm_mrc_x1 - AUTO_CORR_STEP_OFDM; - data->auto_corr_ofdm_mrc_x1 = - max((u32)AUTO_CORR_MIN_OFDM_MRC_X1, val); - } + iwl4965_apm_stop_master(priv); - else - IWL_DEBUG_CALIB("min FA %u < norm FA %u < max FA %u OK\n", - min_false_alarms, false_alarms, max_false_alarms); + spin_lock_irqsave(&priv->lock, flags); - return 0; -} + iwl_set_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET); -static int iwl4965_sensitivity_callback(struct iwl_priv *priv, - struct iwl_cmd *cmd, struct sk_buff *skb) -{ - /* We didn't cache the SKB; let the caller free it */ - return 1; -} + udelay(10); -/* Prepare a SENSITIVITY_CMD, send to uCode if values have changed */ -static int iwl4965_sensitivity_write(struct iwl_priv *priv, u8 flags) -{ - struct iwl4965_sensitivity_cmd cmd ; - struct iwl4965_sensitivity_data *data = NULL; - struct iwl_host_cmd cmd_out = { - .id = SENSITIVITY_CMD, - .len = sizeof(struct iwl4965_sensitivity_cmd), - .meta.flags = flags, - .data = &cmd, - }; - int ret; + /* FIXME: put here L1A -L0S w/a */ - data = &(priv->sensitivity_data); - - memset(&cmd, 0, sizeof(cmd)); - - cmd.table[HD_AUTO_CORR32_X4_TH_ADD_MIN_INDEX] = - cpu_to_le16((u16)data->auto_corr_ofdm); - cmd.table[HD_AUTO_CORR32_X4_TH_ADD_MIN_MRC_INDEX] = - cpu_to_le16((u16)data->auto_corr_ofdm_mrc); - cmd.table[HD_AUTO_CORR32_X1_TH_ADD_MIN_INDEX] = - cpu_to_le16((u16)data->auto_corr_ofdm_x1); - cmd.table[HD_AUTO_CORR32_X1_TH_ADD_MIN_MRC_INDEX] = - cpu_to_le16((u16)data->auto_corr_ofdm_mrc_x1); - - cmd.table[HD_AUTO_CORR40_X4_TH_ADD_MIN_INDEX] = - cpu_to_le16((u16)data->auto_corr_cck); - cmd.table[HD_AUTO_CORR40_X4_TH_ADD_MIN_MRC_INDEX] = - cpu_to_le16((u16)data->auto_corr_cck_mrc); - - cmd.table[HD_MIN_ENERGY_CCK_DET_INDEX] = - cpu_to_le16((u16)data->nrg_th_cck); - cmd.table[HD_MIN_ENERGY_OFDM_DET_INDEX] = - cpu_to_le16((u16)data->nrg_th_ofdm); - - cmd.table[HD_BARKER_CORR_TH_ADD_MIN_INDEX] = - __constant_cpu_to_le16(190); - cmd.table[HD_BARKER_CORR_TH_ADD_MIN_MRC_INDEX] = - __constant_cpu_to_le16(390); - cmd.table[HD_OFDM_ENERGY_TH_IN_INDEX] = - __constant_cpu_to_le16(62); - - IWL_DEBUG_CALIB("ofdm: ac %u mrc %u x1 %u mrc_x1 %u thresh %u\n", - data->auto_corr_ofdm, data->auto_corr_ofdm_mrc, - data->auto_corr_ofdm_x1, data->auto_corr_ofdm_mrc_x1, - data->nrg_th_ofdm); - - IWL_DEBUG_CALIB("cck: ac %u mrc %u thresh %u\n", - data->auto_corr_cck, data->auto_corr_cck_mrc, - data->nrg_th_cck); - - /* Update uCode's "work" table, and copy it to DSP */ - cmd.control = SENSITIVITY_CMD_CONTROL_WORK_TABLE; - - if (flags & CMD_ASYNC) - cmd_out.meta.u.callback = iwl4965_sensitivity_callback; - - /* Don't send command to uCode if nothing has changed */ - if (!memcmp(&cmd.table[0], &(priv->sensitivity_tbl[0]), - sizeof(u16)*HD_TABLE_SIZE)) { - IWL_DEBUG_CALIB("No change in SENSITIVITY_CMD\n"); - return 0; - } + iwl_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE); - /* Copy table for comparison next time */ - memcpy(&(priv->sensitivity_tbl[0]), &(cmd.table[0]), - sizeof(u16)*HD_TABLE_SIZE); + ret = iwl_poll_bit(priv, CSR_RESET, + CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, + CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25); - ret = iwl_send_cmd(priv, &cmd_out); if (ret) - IWL_ERROR("SENSITIVITY_CMD failed\n"); - - return ret; -} - -void iwl4965_init_sensitivity(struct iwl_priv *priv, u8 flags, u8 force) -{ - struct iwl4965_sensitivity_data *data = NULL; - int i; - int ret = 0; - - IWL_DEBUG_CALIB("Start iwl4965_init_sensitivity\n"); - - if (force) - memset(&(priv->sensitivity_tbl[0]), 0, - sizeof(u16)*HD_TABLE_SIZE); - - /* Clear driver's sensitivity algo data */ - data = &(priv->sensitivity_data); - memset(data, 0, sizeof(struct iwl4965_sensitivity_data)); + goto out; - data->num_in_cck_no_fa = 0; - data->nrg_curr_state = IWL_FA_TOO_MANY; - data->nrg_prev_state = IWL_FA_TOO_MANY; - data->nrg_silence_ref = 0; - data->nrg_silence_idx = 0; - data->nrg_energy_idx = 0; + udelay(10); - for (i = 0; i < 10; i++) - data->nrg_value[i] = 0; + 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); - for (i = 0; i < NRG_NUM_PREV_STAT_L; i++) - data->nrg_silence_rssi[i] = 0; + udelay(10); - data->auto_corr_ofdm = 90; - data->auto_corr_ofdm_mrc = 170; - data->auto_corr_ofdm_x1 = 105; - data->auto_corr_ofdm_mrc_x1 = 220; - data->auto_corr_cck = AUTO_CORR_CCK_MIN_VAL_DEF; - data->auto_corr_cck_mrc = 200; - data->nrg_th_cck = 100; - data->nrg_th_ofdm = 100; + /* disable L1A */ + iwl_set_bits_prph(priv, APMG_PCIDEV_STT_REG, + APMG_PCIDEV_STT_VAL_L1_ACT_DIS); - data->last_bad_plcp_cnt_ofdm = 0; - data->last_fa_cnt_ofdm = 0; - data->last_bad_plcp_cnt_cck = 0; - data->last_fa_cnt_cck = 0; + iwl_release_nic_access(priv); - /* Clear prior Sensitivity command data to force send to uCode */ - if (force) - memset(&(priv->sensitivity_tbl[0]), 0, - sizeof(u16)*HD_TABLE_SIZE); + clear_bit(STATUS_HCMD_ACTIVE, &priv->status); + wake_up_interruptible(&priv->wait_command_queue); - ret |= iwl4965_sensitivity_write(priv, flags); - IWL_DEBUG_CALIB("<<return 0x%X\n", ret); +out: + spin_unlock_irqrestore(&priv->lock, flags); - return; + return ret; } - /* Reset differential Rx gains in NIC to prepare for chain noise calibration. * Called after every association, but this runs only once! * ... once chain noise is calibrated the first time, it's good forever. */ -void iwl4965_chain_noise_reset(struct iwl_priv *priv) +static void iwl4965_chain_noise_reset(struct iwl_priv *priv) { - struct iwl4965_chain_noise_data *data = NULL; + struct iwl_chain_noise_data *data = &(priv->chain_noise_data); - data = &(priv->chain_noise_data); if ((data->state == IWL_CHAIN_NOISE_ALIVE) && iwl_is_associated(priv)) { struct iwl4965_calibration_cmd cmd; @@ -1452,388 +578,89 @@ void iwl4965_chain_noise_reset(struct iwl_priv *priv) cmd.diff_gain_a = 0; cmd.diff_gain_b = 0; cmd.diff_gain_c = 0; - iwl_send_cmd_pdu_async(priv, REPLY_PHY_CALIBRATION_CMD, - sizeof(cmd), &cmd, NULL); - msleep(4); + if (iwl_send_cmd_pdu(priv, REPLY_PHY_CALIBRATION_CMD, + sizeof(cmd), &cmd)) + IWL_ERROR("Could not send REPLY_PHY_CALIBRATION_CMD\n"); data->state = IWL_CHAIN_NOISE_ACCUMULATE; IWL_DEBUG_CALIB("Run chain_noise_calibrate\n"); } - return; } -/* - * Accumulate 20 beacons of signal and noise statistics for each of - * 3 receivers/antennas/rx-chains, then figure out: - * 1) Which antennas are connected. - * 2) Differential rx gain settings to balance the 3 receivers. - */ -static void iwl4965_noise_calibration(struct iwl_priv *priv, - struct iwl4965_notif_statistics *stat_resp) +static void iwl4965_gain_computation(struct iwl_priv *priv, + u32 *average_noise, + u16 min_average_noise_antenna_i, + u32 min_average_noise) { - struct iwl4965_chain_noise_data *data = NULL; - int ret = 0; - - u32 chain_noise_a; - u32 chain_noise_b; - u32 chain_noise_c; - u32 chain_sig_a; - u32 chain_sig_b; - u32 chain_sig_c; - u32 average_sig[NUM_RX_CHAINS] = {INITIALIZATION_VALUE}; - u32 average_noise[NUM_RX_CHAINS] = {INITIALIZATION_VALUE}; - u32 max_average_sig; - u16 max_average_sig_antenna_i; - u32 min_average_noise = MIN_AVERAGE_NOISE_MAX_VALUE; - u16 min_average_noise_antenna_i = INITIALIZATION_VALUE; - u16 i = 0; - u16 chan_num = INITIALIZATION_VALUE; - u32 band = INITIALIZATION_VALUE; - u32 active_chains = 0; - unsigned long flags; - struct statistics_rx_non_phy *rx_info = &(stat_resp->rx.general); - - data = &(priv->chain_noise_data); - - /* Accumulate just the first 20 beacons after the first association, - * then we're done forever. */ - if (data->state != IWL_CHAIN_NOISE_ACCUMULATE) { - if (data->state == IWL_CHAIN_NOISE_ALIVE) - IWL_DEBUG_CALIB("Wait for noise calib reset\n"); - return; - } - - spin_lock_irqsave(&priv->lock, flags); - if (rx_info->interference_data_flag != INTERFERENCE_DATA_AVAILABLE) { - IWL_DEBUG_CALIB(" << Interference data unavailable\n"); - spin_unlock_irqrestore(&priv->lock, flags); - return; - } - - band = (priv->staging_rxon.flags & RXON_FLG_BAND_24G_MSK) ? 0 : 1; - chan_num = le16_to_cpu(priv->staging_rxon.channel); - - /* Make sure we accumulate data for just the associated channel - * (even if scanning). */ - if ((chan_num != (le32_to_cpu(stat_resp->flag) >> 16)) || - ((STATISTICS_REPLY_FLG_BAND_24G_MSK == - (stat_resp->flag & STATISTICS_REPLY_FLG_BAND_24G_MSK)) && band)) { - IWL_DEBUG_CALIB("Stats not from chan=%d, band=%d\n", - chan_num, band); - spin_unlock_irqrestore(&priv->lock, flags); - return; - } - - /* Accumulate beacon statistics values across 20 beacons */ - chain_noise_a = le32_to_cpu(rx_info->beacon_silence_rssi_a) & - IN_BAND_FILTER; - chain_noise_b = le32_to_cpu(rx_info->beacon_silence_rssi_b) & - IN_BAND_FILTER; - chain_noise_c = le32_to_cpu(rx_info->beacon_silence_rssi_c) & - IN_BAND_FILTER; - - chain_sig_a = le32_to_cpu(rx_info->beacon_rssi_a) & IN_BAND_FILTER; - chain_sig_b = le32_to_cpu(rx_info->beacon_rssi_b) & IN_BAND_FILTER; - chain_sig_c = le32_to_cpu(rx_info->beacon_rssi_c) & IN_BAND_FILTER; - - spin_unlock_irqrestore(&priv->lock, flags); - - data->beacon_count++; - - data->chain_noise_a = (chain_noise_a + data->chain_noise_a); - data->chain_noise_b = (chain_noise_b + data->chain_noise_b); - data->chain_noise_c = (chain_noise_c + data->chain_noise_c); - - data->chain_signal_a = (chain_sig_a + data->chain_signal_a); - data->chain_signal_b = (chain_sig_b + data->chain_signal_b); - data->chain_signal_c = (chain_sig_c + data->chain_signal_c); - - IWL_DEBUG_CALIB("chan=%d, band=%d, beacon=%d\n", chan_num, band, - data->beacon_count); - IWL_DEBUG_CALIB("chain_sig: a %d b %d c %d\n", - chain_sig_a, chain_sig_b, chain_sig_c); - IWL_DEBUG_CALIB("chain_noise: a %d b %d c %d\n", - chain_noise_a, chain_noise_b, chain_noise_c); - - /* If this is the 20th beacon, determine: - * 1) Disconnected antennas (using signal strengths) - * 2) Differential gain (using silence noise) to balance receivers */ - if (data->beacon_count == CAL_NUM_OF_BEACONS) { - - /* Analyze signal for disconnected antenna */ - average_sig[0] = (data->chain_signal_a) / CAL_NUM_OF_BEACONS; - average_sig[1] = (data->chain_signal_b) / CAL_NUM_OF_BEACONS; - average_sig[2] = (data->chain_signal_c) / CAL_NUM_OF_BEACONS; - - if (average_sig[0] >= average_sig[1]) { - max_average_sig = average_sig[0]; - max_average_sig_antenna_i = 0; - active_chains = (1 << max_average_sig_antenna_i); - } else { - max_average_sig = average_sig[1]; - max_average_sig_antenna_i = 1; - active_chains = (1 << max_average_sig_antenna_i); - } - - if (average_sig[2] >= max_average_sig) { - max_average_sig = average_sig[2]; - max_average_sig_antenna_i = 2; - active_chains = (1 << max_average_sig_antenna_i); - } - - IWL_DEBUG_CALIB("average_sig: a %d b %d c %d\n", - average_sig[0], average_sig[1], average_sig[2]); - IWL_DEBUG_CALIB("max_average_sig = %d, antenna %d\n", - max_average_sig, max_average_sig_antenna_i); - - /* Compare signal strengths for all 3 receivers. */ - for (i = 0; i < NUM_RX_CHAINS; i++) { - if (i != max_average_sig_antenna_i) { - s32 rssi_delta = (max_average_sig - - average_sig[i]); - - /* If signal is very weak, compared with - * strongest, mark it as disconnected. */ - if (rssi_delta > MAXIMUM_ALLOWED_PATHLOSS) - data->disconn_array[i] = 1; - else - active_chains |= (1 << i); - IWL_DEBUG_CALIB("i = %d rssiDelta = %d " - "disconn_array[i] = %d\n", - i, rssi_delta, data->disconn_array[i]); - } - } - - /*If both chains A & B are disconnected - - * connect B and leave A as is */ - if (data->disconn_array[CHAIN_A] && - data->disconn_array[CHAIN_B]) { - data->disconn_array[CHAIN_B] = 0; - active_chains |= (1 << CHAIN_B); - IWL_DEBUG_CALIB("both A & B chains are disconnected! " - "W/A - declare B as connected\n"); - } + int i, ret; + struct iwl_chain_noise_data *data = &priv->chain_noise_data; - IWL_DEBUG_CALIB("active_chains (bitwise) = 0x%x\n", - active_chains); + data->delta_gain_code[min_average_noise_antenna_i] = 0; - /* Save for use within RXON, TX, SCAN commands, etc. */ - priv->valid_antenna = active_chains; + for (i = 0; i < NUM_RX_CHAINS; i++) { + s32 delta_g = 0; - /* Analyze noise for rx balance */ - average_noise[0] = ((data->chain_noise_a)/CAL_NUM_OF_BEACONS); - average_noise[1] = ((data->chain_noise_b)/CAL_NUM_OF_BEACONS); - average_noise[2] = ((data->chain_noise_c)/CAL_NUM_OF_BEACONS); - - for (i = 0; i < NUM_RX_CHAINS; i++) { - if (!(data->disconn_array[i]) && - (average_noise[i] <= min_average_noise)) { - /* This means that chain i is active and has - * lower noise values so far: */ - min_average_noise = average_noise[i]; - min_average_noise_antenna_i = i; - } - } - - data->delta_gain_code[min_average_noise_antenna_i] = 0; - - IWL_DEBUG_CALIB("average_noise: a %d b %d c %d\n", - average_noise[0], average_noise[1], - average_noise[2]); - - IWL_DEBUG_CALIB("min_average_noise = %d, antenna %d\n", - min_average_noise, min_average_noise_antenna_i); - - for (i = 0; i < NUM_RX_CHAINS; i++) { - s32 delta_g = 0; - - if (!(data->disconn_array[i]) && - (data->delta_gain_code[i] == + if (!(data->disconn_array[i]) && + (data->delta_gain_code[i] == CHAIN_NOISE_DELTA_GAIN_INIT_VAL)) { - delta_g = average_noise[i] - min_average_noise; - data->delta_gain_code[i] = (u8)((delta_g * - 10) / 15); - if (CHAIN_NOISE_MAX_DELTA_GAIN_CODE < - data->delta_gain_code[i]) - data->delta_gain_code[i] = - CHAIN_NOISE_MAX_DELTA_GAIN_CODE; - - data->delta_gain_code[i] = - (data->delta_gain_code[i] | (1 << 2)); - } else - data->delta_gain_code[i] = 0; - } - IWL_DEBUG_CALIB("delta_gain_codes: a %d b %d c %d\n", - data->delta_gain_code[0], - data->delta_gain_code[1], - data->delta_gain_code[2]); - - /* Differential gain gets sent to uCode only once */ - if (!data->radio_write) { - struct iwl4965_calibration_cmd cmd; - data->radio_write = 1; - - memset(&cmd, 0, sizeof(cmd)); - cmd.opCode = PHY_CALIBRATE_DIFF_GAIN_CMD; - cmd.diff_gain_a = data->delta_gain_code[0]; - cmd.diff_gain_b = data->delta_gain_code[1]; - cmd.diff_gain_c = data->delta_gain_code[2]; - ret = iwl_send_cmd_pdu(priv, REPLY_PHY_CALIBRATION_CMD, - sizeof(cmd), &cmd); - if (ret) - IWL_DEBUG_CALIB("fail sending cmd " - "REPLY_PHY_CALIBRATION_CMD \n"); - - /* TODO we might want recalculate - * rx_chain in rxon cmd */ - - /* Mark so we run this algo only once! */ - data->state = IWL_CHAIN_NOISE_CALIBRATED; + delta_g = average_noise[i] - min_average_noise; + data->delta_gain_code[i] = (u8)((delta_g * 10) / 15); + data->delta_gain_code[i] = + min(data->delta_gain_code[i], + (u8) CHAIN_NOISE_MAX_DELTA_GAIN_CODE); + + data->delta_gain_code[i] = + (data->delta_gain_code[i] | (1 << 2)); + } else { + data->delta_gain_code[i] = 0; } - data->chain_noise_a = 0; - data->chain_noise_b = 0; - data->chain_noise_c = 0; - data->chain_signal_a = 0; - data->chain_signal_b = 0; - data->chain_signal_c = 0; - data->beacon_count = 0; - } - return; -} - -static void iwl4965_sensitivity_calibration(struct iwl_priv *priv, - struct iwl4965_notif_statistics *resp) -{ - u32 rx_enable_time; - u32 fa_cck; - u32 fa_ofdm; - u32 bad_plcp_cck; - u32 bad_plcp_ofdm; - u32 norm_fa_ofdm; - u32 norm_fa_cck; - struct iwl4965_sensitivity_data *data = NULL; - struct statistics_rx_non_phy *rx_info = &(resp->rx.general); - struct statistics_rx *statistics = &(resp->rx); - unsigned long flags; - struct statistics_general_data statis; - int ret; - - data = &(priv->sensitivity_data); - - if (!iwl_is_associated(priv)) { - IWL_DEBUG_CALIB("<< - not associated\n"); - return; } + IWL_DEBUG_CALIB("delta_gain_codes: a %d b %d c %d\n", + data->delta_gain_code[0], + data->delta_gain_code[1], + data->delta_gain_code[2]); - spin_lock_irqsave(&priv->lock, flags); - if (rx_info->interference_data_flag != INTERFERENCE_DATA_AVAILABLE) { - IWL_DEBUG_CALIB("<< invalid data.\n"); - spin_unlock_irqrestore(&priv->lock, flags); - return; - } - - /* Extract Statistics: */ - rx_enable_time = le32_to_cpu(rx_info->channel_load); - fa_cck = le32_to_cpu(statistics->cck.false_alarm_cnt); - fa_ofdm = le32_to_cpu(statistics->ofdm.false_alarm_cnt); - bad_plcp_cck = le32_to_cpu(statistics->cck.plcp_err); - bad_plcp_ofdm = le32_to_cpu(statistics->ofdm.plcp_err); - - statis.beacon_silence_rssi_a = - le32_to_cpu(statistics->general.beacon_silence_rssi_a); - statis.beacon_silence_rssi_b = - le32_to_cpu(statistics->general.beacon_silence_rssi_b); - statis.beacon_silence_rssi_c = - le32_to_cpu(statistics->general.beacon_silence_rssi_c); - statis.beacon_energy_a = - le32_to_cpu(statistics->general.beacon_energy_a); - statis.beacon_energy_b = - le32_to_cpu(statistics->general.beacon_energy_b); - statis.beacon_energy_c = - le32_to_cpu(statistics->general.beacon_energy_c); - - spin_unlock_irqrestore(&priv->lock, flags); - - IWL_DEBUG_CALIB("rx_enable_time = %u usecs\n", rx_enable_time); - - if (!rx_enable_time) { - IWL_DEBUG_CALIB("<< RX Enable Time == 0! \n"); - return; - } - - /* These statistics increase monotonically, and do not reset - * at each beacon. Calculate difference from last value, or just - * use the new statistics value if it has reset or wrapped around. */ - if (data->last_bad_plcp_cnt_cck > bad_plcp_cck) - data->last_bad_plcp_cnt_cck = bad_plcp_cck; - else { - bad_plcp_cck -= data->last_bad_plcp_cnt_cck; - data->last_bad_plcp_cnt_cck += bad_plcp_cck; - } + /* Differential gain gets sent to uCode only once */ + if (!data->radio_write) { + struct iwl4965_calibration_cmd cmd; + data->radio_write = 1; - if (data->last_bad_plcp_cnt_ofdm > bad_plcp_ofdm) - data->last_bad_plcp_cnt_ofdm = bad_plcp_ofdm; - else { - bad_plcp_ofdm -= data->last_bad_plcp_cnt_ofdm; - data->last_bad_plcp_cnt_ofdm += bad_plcp_ofdm; - } + memset(&cmd, 0, sizeof(cmd)); + cmd.opCode = PHY_CALIBRATE_DIFF_GAIN_CMD; + cmd.diff_gain_a = data->delta_gain_code[0]; + cmd.diff_gain_b = data->delta_gain_code[1]; + cmd.diff_gain_c = data->delta_gain_code[2]; + ret = iwl_send_cmd_pdu(priv, REPLY_PHY_CALIBRATION_CMD, + sizeof(cmd), &cmd); + if (ret) + IWL_DEBUG_CALIB("fail sending cmd " + "REPLY_PHY_CALIBRATION_CMD \n"); - if (data->last_fa_cnt_ofdm > fa_ofdm) - data->last_fa_cnt_ofdm = fa_ofdm; - else { - fa_ofdm -= data->last_fa_cnt_ofdm; - data->last_fa_cnt_ofdm += fa_ofdm; - } + /* TODO we might want recalculate + * rx_chain in rxon cmd */ - if (data->last_fa_cnt_cck > fa_cck) - data->last_fa_cnt_cck = fa_cck; - else { - fa_cck -= data->last_fa_cnt_cck; - data->last_fa_cnt_cck += fa_cck; + /* Mark so we run this algo only once! */ + data->state = IWL_CHAIN_NOISE_CALIBRATED; } - - /* Total aborted signal locks */ - norm_fa_ofdm = fa_ofdm + bad_plcp_ofdm; - norm_fa_cck = fa_cck + bad_plcp_cck; - - IWL_DEBUG_CALIB("cck: fa %u badp %u ofdm: fa %u badp %u\n", fa_cck, - bad_plcp_cck, fa_ofdm, bad_plcp_ofdm); - - iwl4965_sens_auto_corr_ofdm(priv, norm_fa_ofdm, rx_enable_time); - iwl4965_sens_energy_cck(priv, norm_fa_cck, rx_enable_time, &statis); - ret = iwl4965_sensitivity_write(priv, CMD_ASYNC); - - return; + data->chain_noise_a = 0; + data->chain_noise_b = 0; + data->chain_noise_c = 0; + data->chain_signal_a = 0; + data->chain_signal_b = 0; + data->chain_signal_c = 0; + data->beacon_count = 0; } -static void iwl4965_bg_sensitivity_work(struct work_struct *work) +static void iwl4965_rts_tx_cmd_flag(struct ieee80211_tx_info *info, + __le32 *tx_flags) { - struct iwl_priv *priv = container_of(work, struct iwl_priv, - sensitivity_work); - - mutex_lock(&priv->mutex); - - if (test_bit(STATUS_EXIT_PENDING, &priv->status) || - test_bit(STATUS_SCANNING, &priv->status)) { - mutex_unlock(&priv->mutex); - return; - } - - if (priv->start_calib) { - iwl4965_noise_calibration(priv, &priv->statistics); - - if (priv->sensitivity_data.state == - IWL_SENS_CALIB_NEED_REINIT) { - iwl4965_init_sensitivity(priv, CMD_ASYNC, 0); - priv->sensitivity_data.state = IWL_SENS_CALIB_ALLOWED; - } else - iwl4965_sensitivity_calibration(priv, - &priv->statistics); + if (info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) { + *tx_flags |= TX_CMD_FLG_RTS_MSK; + *tx_flags &= ~TX_CMD_FLG_CTS_MSK; + } else if (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT) { + *tx_flags &= ~TX_CMD_FLG_RTS_MSK; + *tx_flags |= TX_CMD_FLG_CTS_MSK; } - - mutex_unlock(&priv->mutex); - return; } -#endif /*CONFIG_IWL4965_SENSITIVITY*/ static void iwl4965_bg_txpower_work(struct work_struct *work) { @@ -1853,7 +680,7 @@ static void iwl4965_bg_txpower_work(struct work_struct *work) /* Regardless of if we are assocaited, we must reconfigure the * TX power since frames can be sent on non-radar channels while * not associated */ - iwl4965_hw_reg_send_txpower(priv); + iwl4965_send_tx_power(priv); /* Update last_temperature to keep is_calib_needed from running * when it isn't needed... */ @@ -1880,7 +707,7 @@ static void iwl4965_set_wr_ptrs(struct iwl_priv *priv, int txq_id, u32 index) * NOTE: Acquire priv->lock before calling this function ! */ static void iwl4965_tx_queue_set_status(struct iwl_priv *priv, - struct iwl4965_tx_queue *txq, + struct iwl_tx_queue *txq, int tx_fifo_id, int scd_retry) { int txq_id = txq->q.id; @@ -1890,11 +717,11 @@ static void iwl4965_tx_queue_set_status(struct iwl_priv *priv, /* Set up and activate */ iwl_write_prph(priv, IWL49_SCD_QUEUE_STATUS_BITS(txq_id), - (active << SCD_QUEUE_STTS_REG_POS_ACTIVE) | - (tx_fifo_id << SCD_QUEUE_STTS_REG_POS_TXF) | - (scd_retry << SCD_QUEUE_STTS_REG_POS_WSL) | - (scd_retry << SCD_QUEUE_STTS_REG_POS_SCD_ACK) | - SCD_QUEUE_STTS_REG_MSK); + (active << IWL49_SCD_QUEUE_STTS_REG_POS_ACTIVE) | + (tx_fifo_id << IWL49_SCD_QUEUE_STTS_REG_POS_TXF) | + (scd_retry << IWL49_SCD_QUEUE_STTS_REG_POS_WSL) | + (scd_retry << IWL49_SCD_QUEUE_STTS_REG_POS_SCD_ACK) | + IWL49_SCD_QUEUE_STTS_REG_MSK); txq->sched_retry = scd_retry; @@ -1908,22 +735,12 @@ static const u16 default_queue_to_tx_fifo[] = { IWL_TX_FIFO_AC2, IWL_TX_FIFO_AC1, IWL_TX_FIFO_AC0, - IWL_CMD_FIFO_NUM, + IWL49_CMD_FIFO_NUM, IWL_TX_FIFO_HCCA_1, IWL_TX_FIFO_HCCA_2 }; -static inline void iwl4965_txq_ctx_activate(struct iwl_priv *priv, int txq_id) -{ - set_bit(txq_id, &priv->txq_ctx_active_msk); -} - -static inline void iwl4965_txq_ctx_deactivate(struct iwl_priv *priv, int txq_id) -{ - clear_bit(txq_id, &priv->txq_ctx_active_msk); -} - -int iwl4965_alive_notify(struct iwl_priv *priv) +static int iwl4965_alive_notify(struct iwl_priv *priv) { u32 a; int i = 0; @@ -1932,15 +749,6 @@ int iwl4965_alive_notify(struct iwl_priv *priv) spin_lock_irqsave(&priv->lock, flags); -#ifdef CONFIG_IWL4965_SENSITIVITY - memset(&(priv->sensitivity_data), 0, - sizeof(struct iwl4965_sensitivity_data)); - memset(&(priv->chain_noise_data), 0, - sizeof(struct iwl4965_chain_noise_data)); - for (i = 0; i < NUM_RX_CHAINS; i++) - priv->chain_noise_data.delta_gain_code[i] = - CHAIN_NOISE_DELTA_GAIN_INIT_VAL; -#endif /* CONFIG_IWL4965_SENSITIVITY*/ ret = iwl_grab_nic_access(priv); if (ret) { spin_unlock_irqrestore(&priv->lock, flags); @@ -1949,10 +757,10 @@ int iwl4965_alive_notify(struct iwl_priv *priv) /* 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 + SCD_CONTEXT_DATA_OFFSET; - for (; a < priv->scd_base_addr + SCD_TX_STTS_BITMAP_OFFSET; a += 4) + a = priv->scd_base_addr + IWL49_SCD_CONTEXT_DATA_OFFSET; + for (; a < priv->scd_base_addr + IWL49_SCD_TX_STTS_BITMAP_OFFSET; a += 4) iwl_write_targ_mem(priv, a, 0); - for (; a < priv->scd_base_addr + SCD_TRANSLATE_TBL_OFFSET; a += 4) + for (; a < priv->scd_base_addr + IWL49_SCD_TRANSLATE_TBL_OFFSET; a += 4) iwl_write_targ_mem(priv, a, 0); for (; a < sizeof(u16) * priv->hw_params.max_txq_num; a += 4) iwl_write_targ_mem(priv, a, 0); @@ -1974,160 +782,109 @@ int iwl4965_alive_notify(struct iwl_priv *priv) /* Max Tx Window size for Scheduler-ACK mode */ iwl_write_targ_mem(priv, priv->scd_base_addr + - SCD_CONTEXT_QUEUE_OFFSET(i), - (SCD_WIN_SIZE << - SCD_QUEUE_CTX_REG1_WIN_SIZE_POS) & - SCD_QUEUE_CTX_REG1_WIN_SIZE_MSK); + IWL49_SCD_CONTEXT_QUEUE_OFFSET(i), + (SCD_WIN_SIZE << + IWL49_SCD_QUEUE_CTX_REG1_WIN_SIZE_POS) & + IWL49_SCD_QUEUE_CTX_REG1_WIN_SIZE_MSK); /* Frame limit */ iwl_write_targ_mem(priv, priv->scd_base_addr + - SCD_CONTEXT_QUEUE_OFFSET(i) + - sizeof(u32), - (SCD_FRAME_LIMIT << - SCD_QUEUE_CTX_REG2_FRAME_LIMIT_POS) & - SCD_QUEUE_CTX_REG2_FRAME_LIMIT_MSK); + IWL49_SCD_CONTEXT_QUEUE_OFFSET(i) + + sizeof(u32), + (SCD_FRAME_LIMIT << + IWL49_SCD_QUEUE_CTX_REG2_FRAME_LIMIT_POS) & + IWL49_SCD_QUEUE_CTX_REG2_FRAME_LIMIT_MSK); } iwl_write_prph(priv, IWL49_SCD_INTERRUPT_MASK, (1 << priv->hw_params.max_txq_num) - 1); /* Activate all Tx DMA/FIFO channels */ - iwl_write_prph(priv, IWL49_SCD_TXFACT, - SCD_TXFACT_REG_TXFIFO_MASK(0, 7)); + priv->cfg->ops->lib->txq_set_sched(priv, IWL_MASK(0, 7)); iwl4965_set_wr_ptrs(priv, IWL_CMD_QUEUE_NUM, 0); /* Map each Tx/cmd queue to its corresponding fifo */ for (i = 0; i < ARRAY_SIZE(default_queue_to_tx_fifo); i++) { int ac = default_queue_to_tx_fifo[i]; - iwl4965_txq_ctx_activate(priv, i); + iwl_txq_ctx_activate(priv, i); iwl4965_tx_queue_set_status(priv, &priv->txq[i], ac, 0); } iwl_release_nic_access(priv); spin_unlock_irqrestore(&priv->lock, flags); - /* Ask for statistics now, the uCode will send statistics notification - * periodically after association */ - iwl_send_statistics_request(priv, CMD_ASYNC); return ret; } +static struct iwl_sensitivity_ranges iwl4965_sensitivity = { + .min_nrg_cck = 97, + .max_nrg_cck = 0, + + .auto_corr_min_ofdm = 85, + .auto_corr_min_ofdm_mrc = 170, + .auto_corr_min_ofdm_x1 = 105, + .auto_corr_min_ofdm_mrc_x1 = 220, + + .auto_corr_max_ofdm = 120, + .auto_corr_max_ofdm_mrc = 210, + .auto_corr_max_ofdm_x1 = 140, + .auto_corr_max_ofdm_mrc_x1 = 270, + + .auto_corr_min_cck = 125, + .auto_corr_max_cck = 200, + .auto_corr_min_cck_mrc = 200, + .auto_corr_max_cck_mrc = 400, + + .nrg_th_cck = 100, + .nrg_th_ofdm = 100, +}; + /** * iwl4965_hw_set_hw_params * * Called when initializing driver */ -int iwl4965_hw_set_hw_params(struct iwl_priv *priv) +static int iwl4965_hw_set_hw_params(struct iwl_priv *priv) { - if ((priv->cfg->mod_params->num_of_queues > IWL4965_MAX_NUM_QUEUES) || + if ((priv->cfg->mod_params->num_of_queues > IWL49_NUM_QUEUES) || (priv->cfg->mod_params->num_of_queues < IWL_MIN_NUM_QUEUES)) { IWL_ERROR("invalid queues_num, should be between %d and %d\n", - IWL_MIN_NUM_QUEUES, IWL4965_MAX_NUM_QUEUES); + IWL_MIN_NUM_QUEUES, IWL49_NUM_QUEUES); return -EINVAL; } priv->hw_params.max_txq_num = priv->cfg->mod_params->num_of_queues; - priv->hw_params.tx_cmd_len = sizeof(struct iwl4965_tx_cmd); - priv->hw_params.max_rxq_size = RX_QUEUE_SIZE; - priv->hw_params.max_rxq_log = RX_QUEUE_SIZE_LOG; - if (priv->cfg->mod_params->amsdu_size_8K) - priv->hw_params.rx_buf_size = IWL_RX_BUF_SIZE_8K; - else - priv->hw_params.rx_buf_size = IWL_RX_BUF_SIZE_4K; - priv->hw_params.max_pkt_size = priv->hw_params.rx_buf_size - 256; + priv->hw_params.first_ampdu_q = IWL49_FIRST_AMPDU_QUEUE; priv->hw_params.max_stations = IWL4965_STATION_COUNT; priv->hw_params.bcast_sta_id = IWL4965_BROADCAST_ID; + priv->hw_params.max_data_size = IWL49_RTC_DATA_SIZE; + priv->hw_params.max_inst_size = IWL49_RTC_INST_SIZE; + priv->hw_params.max_bsm_size = BSM_SRAM_SIZE; + priv->hw_params.fat_channel = BIT(IEEE80211_BAND_5GHZ); priv->hw_params.tx_chains_num = 2; priv->hw_params.rx_chains_num = 2; - priv->hw_params.valid_tx_ant = (IWL_ANTENNA_MAIN | IWL_ANTENNA_AUX); - priv->hw_params.valid_rx_ant = (IWL_ANTENNA_MAIN | IWL_ANTENNA_AUX); - - return 0; -} - -/** - * iwl4965_hw_txq_ctx_free - Free TXQ Context - * - * Destroy all TX DMA queues and structures - */ -void iwl4965_hw_txq_ctx_free(struct iwl_priv *priv) -{ - int txq_id; - - /* Tx queues */ - for (txq_id = 0; txq_id < priv->hw_params.max_txq_num; txq_id++) - iwl4965_tx_queue_free(priv, &priv->txq[txq_id]); - - /* Keep-warm buffer */ - iwl4965_kw_free(priv); -} - -/** - * iwl4965_hw_txq_free_tfd - Free all chunks referenced by TFD [txq->q.read_ptr] - * - * Does NOT advance any TFD circular buffer read/write indexes - * Does NOT free the TFD itself (which is within circular buffer) - */ -int iwl4965_hw_txq_free_tfd(struct iwl_priv *priv, struct iwl4965_tx_queue *txq) -{ - struct iwl4965_tfd_frame *bd_tmp = (struct iwl4965_tfd_frame *)&txq->bd[0]; - struct iwl4965_tfd_frame *bd = &bd_tmp[txq->q.read_ptr]; - struct pci_dev *dev = priv->pci_dev; - int i; - int counter = 0; - int index, is_odd; + 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); - /* Host command buffers stay mapped in memory, nothing to clean */ - if (txq->q.id == IWL_CMD_QUEUE_NUM) - return 0; - - /* Sanity check on number of chunks */ - counter = IWL_GET_BITS(*bd, num_tbs); - if (counter > MAX_NUM_OF_TBS) { - IWL_ERROR("Too many chunks: %i\n", counter); - /* @todo issue fatal error, it is quite serious situation */ - return 0; - } + priv->hw_params.sens = &iwl4965_sensitivity; - /* Unmap chunks, if any. - * TFD info for odd chunks is different format than for even chunks. */ - for (i = 0; i < counter; i++) { - index = i / 2; - is_odd = i & 0x1; - - if (is_odd) - pci_unmap_single( - dev, - IWL_GET_BITS(bd->pa[index], tb2_addr_lo16) | - (IWL_GET_BITS(bd->pa[index], - tb2_addr_hi20) << 16), - IWL_GET_BITS(bd->pa[index], tb2_len), - PCI_DMA_TODEVICE); - - else if (i > 0) - pci_unmap_single(dev, - le32_to_cpu(bd->pa[index].tb1_addr), - IWL_GET_BITS(bd->pa[index], tb1_len), - PCI_DMA_TODEVICE); - - /* Free SKB, if any, for this chunk */ - if (txq->txb[txq->q.read_ptr].skb[i]) { - struct sk_buff *skb = txq->txb[txq->q.read_ptr].skb[i]; - - dev_kfree_skb(skb); - txq->txb[txq->q.read_ptr].skb[i] = NULL; - } - } return 0; } -int iwl4965_hw_reg_set_txpower(struct iwl_priv *priv, s8 power) +/* set card power command */ +static int iwl4965_set_power(struct iwl_priv *priv, + void *cmd) { - IWL_ERROR("TODO: Implement iwl4965_hw_reg_set_txpower!\n"); - return -EINVAL; + int ret = 0; + + ret = iwl_send_cmd_pdu_async(priv, POWER_TABLE_CMD, + sizeof(struct iwl4965_powertable_cmd), + cmd, NULL); + return ret; } static s32 iwl4965_math_div_round(s32 num, s32 denom, s32 *res) @@ -2179,20 +936,6 @@ static s32 iwl4965_get_voltage_compensation(s32 eeprom_voltage, return comp; } -static const struct iwl_channel_info * -iwl4965_get_channel_txpower_info(struct iwl_priv *priv, - enum ieee80211_band band, u16 channel) -{ - const struct iwl_channel_info *ch_info; - - ch_info = iwl_get_channel_info(priv, band, channel); - - if (!is_channel_valid(ch_info)) - return NULL; - - return ch_info; -} - static s32 iwl4965_get_tx_atten_grp(u16 channel) { if (channel >= CALIB_IWL_TX_ATTEN_GR5_FCH && @@ -2224,11 +967,11 @@ static u32 iwl4965_get_sub_band(const struct iwl_priv *priv, u32 channel) s32 b = -1; for (b = 0; b < EEPROM_TX_POWER_BANDS; b++) { - if (priv->eeprom.calib_info.band_info[b].ch_from == 0) + if (priv->calib_info->band_info[b].ch_from == 0) continue; - if ((channel >= priv->eeprom.calib_info.band_info[b].ch_from) - && (channel <= priv->eeprom.calib_info.band_info[b].ch_to)) + if ((channel >= priv->calib_info->band_info[b].ch_from) + && (channel <= priv->calib_info->band_info[b].ch_to)) break; } @@ -2256,14 +999,14 @@ static s32 iwl4965_interpolate_value(s32 x, s32 x1, s32 y1, s32 x2, s32 y2) * in channel number. */ static int iwl4965_interpolate_chan(struct iwl_priv *priv, u32 channel, - struct iwl4965_eeprom_calib_ch_info *chan_info) + struct iwl_eeprom_calib_ch_info *chan_info) { s32 s = -1; u32 c; u32 m; - const struct iwl4965_eeprom_calib_measure *m1; - const struct iwl4965_eeprom_calib_measure *m2; - struct iwl4965_eeprom_calib_measure *omeas; + const struct iwl_eeprom_calib_measure *m1; + const struct iwl_eeprom_calib_measure *m2; + struct iwl_eeprom_calib_measure *omeas; u32 ch_i1; u32 ch_i2; @@ -2273,8 +1016,8 @@ static int iwl4965_interpolate_chan(struct iwl_priv *priv, u32 channel, return -1; } - ch_i1 = priv->eeprom.calib_info.band_info[s].ch1.ch_num; - ch_i2 = priv->eeprom.calib_info.band_info[s].ch2.ch_num; + ch_i1 = priv->calib_info->band_info[s].ch1.ch_num; + ch_i2 = priv->calib_info->band_info[s].ch2.ch_num; chan_info->ch_num = (u8) channel; IWL_DEBUG_TXPOWER("channel %d subband %d factory cal ch %d & %d\n", @@ -2282,9 +1025,9 @@ static int iwl4965_interpolate_chan(struct iwl_priv *priv, u32 channel, for (c = 0; c < EEPROM_TX_POWER_TX_CHAINS; c++) { for (m = 0; m < EEPROM_TX_POWER_MEASUREMENTS; m++) { - m1 = &(priv->eeprom.calib_info.band_info[s].ch1. + m1 = &(priv->calib_info->band_info[s].ch1. measurements[c][m]); - m2 = &(priv->eeprom.calib_info.band_info[s].ch2. + m2 = &(priv->calib_info->band_info[s].ch2. measurements[c][m]); omeas = &(chan_info->measurements[c][m]); @@ -2603,8 +1346,8 @@ static int iwl4965_fill_txpower_tbl(struct iwl_priv *priv, u8 band, u16 channel, int i; int c; const struct iwl_channel_info *ch_info = NULL; - struct iwl4965_eeprom_calib_ch_info ch_eeprom_info; - const struct iwl4965_eeprom_calib_measure *measurement; + struct iwl_eeprom_calib_ch_info ch_eeprom_info; + const struct iwl_eeprom_calib_measure *measurement; s16 voltage; s32 init_voltage; s32 voltage_compensation; @@ -2616,30 +1359,17 @@ static int iwl4965_fill_txpower_tbl(struct iwl_priv *priv, u8 band, u16 channel, s32 factory_actual_pwr[2]; s32 power_index; - /* Sanity check requested level (dBm) */ - if (priv->user_txpower_limit < IWL_TX_POWER_TARGET_POWER_MIN) { - IWL_WARNING("Requested user TXPOWER %d below limit.\n", - priv->user_txpower_limit); - return -EINVAL; - } - if (priv->user_txpower_limit > IWL_TX_POWER_TARGET_POWER_MAX) { - IWL_WARNING("Requested user TXPOWER %d above limit.\n", - priv->user_txpower_limit); - return -EINVAL; - } - /* user_txpower_limit is in dBm, convert to half-dBm (half-dB units * are used for indexing into txpower table) */ - user_target_power = 2 * priv->user_txpower_limit; + user_target_power = 2 * priv->tx_power_user_lmt; /* Get current (RXON) channel, band, width */ - ch_info = - iwl4965_get_channel_txpower_info(priv, priv->band, channel); - IWL_DEBUG_TXPOWER("chan %d band %d is_fat %d\n", channel, band, is_fat); - if (!ch_info) + ch_info = iwl_get_channel_info(priv, priv->band, channel); + + if (!is_channel_valid(ch_info)) return -EINVAL; /* get txatten group, used to select 1) thermal txpower adjustment @@ -2661,9 +1391,9 @@ static int iwl4965_fill_txpower_tbl(struct iwl_priv *priv, u8 band, u16 channel, /* hardware txpower limits ... * saturation (clipping distortion) txpowers are in half-dBm */ if (band) - saturation_power = priv->eeprom.calib_info.saturation_power24; + saturation_power = priv->calib_info->saturation_power24; else - saturation_power = priv->eeprom.calib_info.saturation_power52; + saturation_power = priv->calib_info->saturation_power52; if (saturation_power < IWL_TX_POWER_SATURATION_MIN || saturation_power > IWL_TX_POWER_SATURATION_MAX) { @@ -2693,7 +1423,7 @@ static int iwl4965_fill_txpower_tbl(struct iwl_priv *priv, u8 band, u16 channel, iwl4965_interpolate_chan(priv, channel, &ch_eeprom_info); /* calculate tx gain adjustment based on power supply voltage */ - voltage = priv->eeprom.calib_info.voltage; + voltage = priv->calib_info->voltage; init_voltage = (s32)le32_to_cpu(priv->card_alive_init.voltage); voltage_compensation = iwl4965_get_voltage_compensation(voltage, init_voltage); @@ -2840,12 +1570,12 @@ static int iwl4965_fill_txpower_tbl(struct iwl_priv *priv, u8 band, u16 channel, } /** - * iwl4965_hw_reg_send_txpower - Configure the TXPOWER level user limit + * iwl4965_send_tx_power - Configure the TXPOWER level user limit * * Uses the active RXON for channel, band, and characteristics (fat, high) - * The power limit is taken from priv->user_txpower_limit. + * The power limit is taken from priv->tx_power_user_lmt. */ -int iwl4965_hw_reg_send_txpower(struct iwl_priv *priv) +static int iwl4965_send_tx_power(struct iwl_priv *priv) { struct iwl4965_txpowertable_cmd cmd = { 0 }; int ret; @@ -2888,8 +1618,8 @@ static int iwl4965_send_rxon_assoc(struct iwl_priv *priv) { int ret = 0; struct iwl4965_rxon_assoc_cmd rxon_assoc; - const struct iwl4965_rxon_cmd *rxon1 = &priv->staging_rxon; - const struct iwl4965_rxon_cmd *rxon2 = &priv->active_rxon; + 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) && @@ -2965,89 +1695,14 @@ int iwl4965_hw_channel_switch(struct iwl_priv *priv, u16 channel) return rc; } -#define RTS_HCCA_RETRY_LIMIT 3 -#define RTS_DFAULT_RETRY_LIMIT 60 - -void iwl4965_hw_build_tx_cmd_rate(struct iwl_priv *priv, - struct iwl_cmd *cmd, - struct ieee80211_tx_control *ctrl, - struct ieee80211_hdr *hdr, int sta_id, - int is_hcca) -{ - struct iwl4965_tx_cmd *tx = &cmd->cmd.tx; - u8 rts_retry_limit = 0; - u8 data_retry_limit = 0; - u16 fc = le16_to_cpu(hdr->frame_control); - u8 rate_plcp; - u16 rate_flags = 0; - int rate_idx = min(ctrl->tx_rate->hw_value & 0xffff, IWL_RATE_COUNT - 1); - - rate_plcp = iwl4965_rates[rate_idx].plcp; - - rts_retry_limit = (is_hcca) ? - RTS_HCCA_RETRY_LIMIT : RTS_DFAULT_RETRY_LIMIT; - - if ((rate_idx >= IWL_FIRST_CCK_RATE) && (rate_idx <= IWL_LAST_CCK_RATE)) - rate_flags |= RATE_MCS_CCK_MSK; - - - if (ieee80211_is_probe_response(fc)) { - data_retry_limit = 3; - if (data_retry_limit < rts_retry_limit) - rts_retry_limit = data_retry_limit; - } else - data_retry_limit = IWL_DEFAULT_TX_RETRY; - - if (priv->data_retry_limit != -1) - data_retry_limit = priv->data_retry_limit; - - - if (ieee80211_is_data(fc)) { - tx->initial_rate_index = 0; - tx->tx_flags |= TX_CMD_FLG_STA_RATE_MSK; - } else { - switch (fc & IEEE80211_FCTL_STYPE) { - case IEEE80211_STYPE_AUTH: - case IEEE80211_STYPE_DEAUTH: - case IEEE80211_STYPE_ASSOC_REQ: - case IEEE80211_STYPE_REASSOC_REQ: - if (tx->tx_flags & TX_CMD_FLG_RTS_MSK) { - tx->tx_flags &= ~TX_CMD_FLG_RTS_MSK; - tx->tx_flags |= TX_CMD_FLG_CTS_MSK; - } - break; - default: - break; - } - - /* Alternate between antenna A and B for successive frames */ - if (priv->use_ant_b_for_management_frame) { - priv->use_ant_b_for_management_frame = 0; - rate_flags |= RATE_MCS_ANT_B_MSK; - } else { - priv->use_ant_b_for_management_frame = 1; - rate_flags |= RATE_MCS_ANT_A_MSK; - } - } - - tx->rts_retry_limit = rts_retry_limit; - tx->data_retry_limit = data_retry_limit; - tx->rate_n_flags = iwl4965_hw_set_rate_n_flags(rate_plcp, rate_flags); -} - -int iwl4965_hw_get_rx_read(struct iwl_priv *priv) +static int iwl4965_shared_mem_rx_idx(struct iwl_priv *priv) { struct iwl4965_shared *s = priv->shared_virt; return le32_to_cpu(s->rb_closed) & 0xFFF; } -int iwl4965_hw_get_temperature(struct iwl_priv *priv) -{ - return priv->temperature; -} - unsigned int iwl4965_hw_get_beacon_cmd(struct iwl_priv *priv, - struct iwl4965_frame *frame, u8 rate) + struct iwl_frame *frame, u8 rate) { struct iwl4965_tx_beacon_cmd *tx_beacon_cmd; unsigned int frame_size; @@ -3060,7 +1715,7 @@ unsigned int iwl4965_hw_get_beacon_cmd(struct iwl_priv *priv, frame_size = iwl4965_fill_beacon_frame(priv, tx_beacon_cmd->frame, - iwl4965_broadcast_addr, + iwl_bcast_addr, sizeof(frame->u) - sizeof(*tx_beacon_cmd)); BUG_ON(frame_size > MAX_MPDU_SIZE); @@ -3068,105 +1723,45 @@ unsigned int iwl4965_hw_get_beacon_cmd(struct iwl_priv *priv, if ((rate == IWL_RATE_1M_PLCP) || (rate >= IWL_RATE_2M_PLCP)) tx_beacon_cmd->tx.rate_n_flags = - iwl4965_hw_set_rate_n_flags(rate, RATE_MCS_CCK_MSK); + iwl_hw_set_rate_n_flags(rate, RATE_MCS_CCK_MSK); else tx_beacon_cmd->tx.rate_n_flags = - iwl4965_hw_set_rate_n_flags(rate, 0); + iwl_hw_set_rate_n_flags(rate, 0); tx_beacon_cmd->tx.tx_flags = (TX_CMD_FLG_SEQ_CTL_MSK | TX_CMD_FLG_TSF_MSK | TX_CMD_FLG_STA_RATE_MSK); return (sizeof(*tx_beacon_cmd) + frame_size); } -/* - * Tell 4965 where to find circular buffer of Tx Frame Descriptors for - * given Tx queue, and enable the DMA channel used for that queue. - * - * 4965 supports up to 16 Tx queues in DRAM, mapped to up to 8 Tx DMA - * channels supported in hardware. - */ -int iwl4965_hw_tx_queue_init(struct iwl_priv *priv, struct iwl4965_tx_queue *txq) -{ - int rc; - unsigned long flags; - int txq_id = txq->q.id; - - spin_lock_irqsave(&priv->lock, flags); - rc = iwl_grab_nic_access(priv); - if (rc) { - spin_unlock_irqrestore(&priv->lock, flags); - return rc; - } - - /* Circular buffer (TFD queue in DRAM) physical base address */ - iwl_write_direct32(priv, FH_MEM_CBBC_QUEUE(txq_id), - txq->q.dma_addr >> 8); - - /* Enable DMA channel, using same id as for TFD queue */ - iwl_write_direct32( - priv, IWL_FH_TCSR_CHNL_TX_CONFIG_REG(txq_id), - IWL_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE | - IWL_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_ENABLE_VAL); - iwl_release_nic_access(priv); - spin_unlock_irqrestore(&priv->lock, flags); - - return 0; -} - -int iwl4965_hw_txq_attach_buf_to_tfd(struct iwl_priv *priv, void *ptr, - dma_addr_t addr, u16 len) +static int iwl4965_alloc_shared_mem(struct iwl_priv *priv) { - int index, is_odd; - struct iwl4965_tfd_frame *tfd = ptr; - u32 num_tbs = IWL_GET_BITS(*tfd, num_tbs); - - /* Each TFD can point to a maximum 20 Tx buffers */ - if ((num_tbs >= MAX_NUM_OF_TBS) || (num_tbs < 0)) { - IWL_ERROR("Error can not send more than %d chunks\n", - MAX_NUM_OF_TBS); - return -EINVAL; - } - - index = num_tbs / 2; - is_odd = num_tbs & 0x1; + priv->shared_virt = pci_alloc_consistent(priv->pci_dev, + sizeof(struct iwl4965_shared), + &priv->shared_phys); + if (!priv->shared_virt) + return -ENOMEM; - if (!is_odd) { - tfd->pa[index].tb1_addr = cpu_to_le32(addr); - IWL_SET_BITS(tfd->pa[index], tb1_addr_hi, - iwl_get_dma_hi_address(addr)); - IWL_SET_BITS(tfd->pa[index], tb1_len, len); - } else { - IWL_SET_BITS(tfd->pa[index], tb2_addr_lo16, - (u32) (addr & 0xffff)); - IWL_SET_BITS(tfd->pa[index], tb2_addr_hi20, addr >> 16); - IWL_SET_BITS(tfd->pa[index], tb2_len, len); - } + memset(priv->shared_virt, 0, sizeof(struct iwl4965_shared)); - IWL_SET_BITS(*tfd, num_tbs, num_tbs + 1); + priv->rb_closed_offset = offsetof(struct iwl4965_shared, rb_closed); return 0; } -static void iwl4965_hw_card_show_info(struct iwl_priv *priv) +static void iwl4965_free_shared_mem(struct iwl_priv *priv) { - u16 hw_version = priv->eeprom.board_revision_4965; - - IWL_DEBUG_INFO("4965ABGN HW Version %u.%u.%u\n", - ((hw_version >> 8) & 0x0F), - ((hw_version >> 8) >> 4), (hw_version & 0x00FF)); - - IWL_DEBUG_INFO("4965ABGN PBA Number %.16s\n", - priv->eeprom.board_pba_number_4965); + if (priv->shared_virt) + pci_free_consistent(priv->pci_dev, + sizeof(struct iwl4965_shared), + priv->shared_virt, + priv->shared_phys); } -#define IWL_TX_CRC_SIZE 4 -#define IWL_TX_DELIMITER_SIZE 4 - /** * iwl4965_txq_update_byte_cnt_tbl - Set up entry in Tx byte-count array */ static void iwl4965_txq_update_byte_cnt_tbl(struct iwl_priv *priv, - struct iwl4965_tx_queue *txq, + struct iwl_tx_queue *txq, u16 byte_cnt) { int len; @@ -3180,50 +1775,13 @@ static void iwl4965_txq_update_byte_cnt_tbl(struct iwl_priv *priv, tfd_offset[txq->q.write_ptr], byte_cnt, len); /* If within first 64 entries, duplicate at end */ - if (txq->q.write_ptr < IWL4965_MAX_WIN_SIZE) + if (txq->q.write_ptr < IWL49_MAX_WIN_SIZE) IWL_SET_BITS16(shared_data->queues_byte_cnt_tbls[txq_id]. - tfd_offset[IWL4965_QUEUE_SIZE + txq->q.write_ptr], + tfd_offset[IWL49_QUEUE_SIZE + txq->q.write_ptr], byte_cnt, len); } /** - * iwl4965_set_rxon_chain - Set up Rx chain usage in "staging" RXON image - * - * Selects how many and which Rx receivers/antennas/chains to use. - * This should not be used for scan command ... it puts data in wrong place. - */ -void iwl4965_set_rxon_chain(struct iwl_priv *priv) -{ - u8 is_single = is_single_stream(priv); - u8 idle_state, rx_state; - - priv->staging_rxon.rx_chain = 0; - rx_state = idle_state = 3; - - /* Tell uCode which antennas are actually connected. - * Before first association, we assume all antennas are connected. - * Just after first association, iwl4965_noise_calibration() - * checks which antennas actually *are* connected. */ - priv->staging_rxon.rx_chain |= - cpu_to_le16(priv->valid_antenna << RXON_RX_CHAIN_VALID_POS); - - /* How many receivers should we use? */ - iwl4965_get_rx_chain_counter(priv, &idle_state, &rx_state); - priv->staging_rxon.rx_chain |= - cpu_to_le16(rx_state << RXON_RX_CHAIN_MIMO_CNT_POS); - priv->staging_rxon.rx_chain |= - cpu_to_le16(idle_state << RXON_RX_CHAIN_CNT_POS); - - if (!is_single && (rx_state >= 2) && - !test_bit(STATUS_POWER_PMI, &priv->status)) - priv->staging_rxon.rx_chain |= RXON_RX_CHAIN_MIMO_FORCE_MSK; - else - priv->staging_rxon.rx_chain &= ~RXON_RX_CHAIN_MIMO_FORCE_MSK; - - IWL_DEBUG_ASSOC("rx chain %X\n", priv->staging_rxon.rx_chain); -} - -/** * sign_extend - Sign extend a value using specified bit as sign-bit * * Example: sign_extend(9, 3) would return -7 as bit3 of 1001b is 1 @@ -3240,12 +1798,12 @@ static s32 sign_extend(u32 oper, int index) } /** - * iwl4965_get_temperature - return the calibrated temperature (in Kelvin) + * iwl4965_hw_get_temperature - return the calibrated temperature (in Kelvin) * @statistics: Provides the temperature reading from the uCode * * A return of <0 indicates bogus data in the statistics */ -int iwl4965_get_temperature(const struct iwl_priv *priv) +static int iwl4965_hw_get_temperature(const struct iwl_priv *priv) { s32 temperature; s32 vt; @@ -3280,8 +1838,7 @@ int iwl4965_get_temperature(const struct iwl_priv *priv) vt = sign_extend( le32_to_cpu(priv->statistics.general.temperature), 23); - IWL_DEBUG_TEMP("Calib values R[1-3]: %d %d %d R4: %d\n", - R1, R2, R3, vt); + IWL_DEBUG_TEMP("Calib values R[1-3]: %d %d %d R4: %d\n", R1, R2, R3, vt); if (R3 == R1) { IWL_ERROR("Calibration conflict R1 == R3\n"); @@ -3292,11 +1849,10 @@ int iwl4965_get_temperature(const struct iwl_priv *priv) * Add offset to center the adjustment around 0 degrees Centigrade. */ temperature = TEMPERATURE_CALIB_A_VAL * (vt - R2); temperature /= (R3 - R1); - temperature = (temperature * 97) / 100 + - TEMPERATURE_CALIB_KELVIN_OFFSET; + temperature = (temperature * 97) / 100 + TEMPERATURE_CALIB_KELVIN_OFFSET; - IWL_DEBUG_TEMP("Calibrated temperature: %dK, %dC\n", temperature, - KELVIN_TO_CELSIUS(temperature)); + IWL_DEBUG_TEMP("Calibrated temperature: %dK, %dC\n", + temperature, KELVIN_TO_CELSIUS(temperature)); return temperature; } @@ -3343,89 +1899,11 @@ static int iwl4965_is_temp_calib_needed(struct iwl_priv *priv) return 1; } -/* Calculate noise level, based on measurements during network silence just - * before arriving beacon. This measurement can be done only if we know - * exactly when to expect beacons, therefore only when we're associated. */ -static void iwl4965_rx_calc_noise(struct iwl_priv *priv) -{ - struct statistics_rx_non_phy *rx_info - = &(priv->statistics.rx.general); - int num_active_rx = 0; - int total_silence = 0; - int bcn_silence_a = - le32_to_cpu(rx_info->beacon_silence_rssi_a) & IN_BAND_FILTER; - int bcn_silence_b = - le32_to_cpu(rx_info->beacon_silence_rssi_b) & IN_BAND_FILTER; - int bcn_silence_c = - le32_to_cpu(rx_info->beacon_silence_rssi_c) & IN_BAND_FILTER; - - if (bcn_silence_a) { - total_silence += bcn_silence_a; - num_active_rx++; - } - if (bcn_silence_b) { - total_silence += bcn_silence_b; - num_active_rx++; - } - if (bcn_silence_c) { - total_silence += bcn_silence_c; - num_active_rx++; - } - - /* Average among active antennas */ - if (num_active_rx) - priv->last_rx_noise = (total_silence / num_active_rx) - 107; - else - priv->last_rx_noise = IWL_NOISE_MEAS_NOT_AVAILABLE; - - IWL_DEBUG_CALIB("inband silence a %u, b %u, c %u, dBm %d\n", - bcn_silence_a, bcn_silence_b, bcn_silence_c, - priv->last_rx_noise); -} - -void iwl4965_hw_rx_statistics(struct iwl_priv *priv, struct iwl4965_rx_mem_buffer *rxb) +static void iwl4965_temperature_calib(struct iwl_priv *priv) { - struct iwl4965_rx_packet *pkt = (void *)rxb->skb->data; - int change; s32 temp; - IWL_DEBUG_RX("Statistics notification received (%d vs %d).\n", - (int)sizeof(priv->statistics), pkt->len); - - change = ((priv->statistics.general.temperature != - pkt->u.stats.general.temperature) || - ((priv->statistics.flag & - STATISTICS_REPLY_FLG_FAT_MODE_MSK) != - (pkt->u.stats.flag & STATISTICS_REPLY_FLG_FAT_MODE_MSK))); - - memcpy(&priv->statistics, &pkt->u.stats, sizeof(priv->statistics)); - - set_bit(STATUS_STATISTICS, &priv->status); - - /* Reschedule the statistics timer to occur in - * REG_RECALIB_PERIOD seconds to ensure we get a - * thermal update even if the uCode doesn't give - * us one */ - mod_timer(&priv->statistics_periodic, jiffies + - msecs_to_jiffies(REG_RECALIB_PERIOD * 1000)); - - if (unlikely(!test_bit(STATUS_SCANNING, &priv->status)) && - (pkt->hdr.cmd == STATISTICS_NOTIFICATION)) { - iwl4965_rx_calc_noise(priv); -#ifdef CONFIG_IWL4965_SENSITIVITY - queue_work(priv->workqueue, &priv->sensitivity_work); -#endif - } - - iwl_leds_background(priv); - - /* If the hardware hasn't reported a change in - * temperature then don't bother computing a - * calibrated temperature value */ - if (!change) - return; - - temp = iwl4965_get_temperature(priv); + temp = iwl4965_hw_get_temperature(priv); if (temp < 0) return; @@ -3444,810 +1922,12 @@ void iwl4965_hw_rx_statistics(struct iwl_priv *priv, struct iwl4965_rx_mem_buffe priv->temperature = temp; set_bit(STATUS_TEMPERATURE, &priv->status); - if (unlikely(!test_bit(STATUS_SCANNING, &priv->status)) && - iwl4965_is_temp_calib_needed(priv)) + if (!priv->disable_tx_power_cal && + unlikely(!test_bit(STATUS_SCANNING, &priv->status)) && + iwl4965_is_temp_calib_needed(priv)) queue_work(priv->workqueue, &priv->txpower_work); } -static void iwl4965_add_radiotap(struct iwl_priv *priv, - struct sk_buff *skb, - struct iwl4965_rx_phy_res *rx_start, - struct ieee80211_rx_status *stats, - u32 ampdu_status) -{ - s8 signal = stats->ssi; - s8 noise = 0; - int rate = stats->rate_idx; - u64 tsf = stats->mactime; - __le16 antenna; - __le16 phy_flags_hw = rx_start->phy_flags; - struct iwl4965_rt_rx_hdr { - struct ieee80211_radiotap_header rt_hdr; - __le64 rt_tsf; /* TSF */ - u8 rt_flags; /* radiotap packet flags */ - u8 rt_rate; /* rate in 500kb/s */ - __le16 rt_channelMHz; /* channel in MHz */ - __le16 rt_chbitmask; /* channel bitfield */ - s8 rt_dbmsignal; /* signal in dBm, kluged to signed */ - s8 rt_dbmnoise; - u8 rt_antenna; /* antenna number */ - } __attribute__ ((packed)) *iwl4965_rt; - - /* TODO: We won't have enough headroom for HT frames. Fix it later. */ - if (skb_headroom(skb) < sizeof(*iwl4965_rt)) { - if (net_ratelimit()) - printk(KERN_ERR "not enough headroom [%d] for " - "radiotap head [%zd]\n", - skb_headroom(skb), sizeof(*iwl4965_rt)); - return; - } - - /* put radiotap header in front of 802.11 header and data */ - iwl4965_rt = (void *)skb_push(skb, sizeof(*iwl4965_rt)); - - /* initialise radiotap header */ - iwl4965_rt->rt_hdr.it_version = PKTHDR_RADIOTAP_VERSION; - iwl4965_rt->rt_hdr.it_pad = 0; - - /* total header + data */ - put_unaligned(cpu_to_le16(sizeof(*iwl4965_rt)), - &iwl4965_rt->rt_hdr.it_len); - - /* Indicate all the fields we add to the radiotap header */ - put_unaligned(cpu_to_le32((1 << IEEE80211_RADIOTAP_TSFT) | - (1 << IEEE80211_RADIOTAP_FLAGS) | - (1 << IEEE80211_RADIOTAP_RATE) | - (1 << IEEE80211_RADIOTAP_CHANNEL) | - (1 << IEEE80211_RADIOTAP_DBM_ANTSIGNAL) | - (1 << IEEE80211_RADIOTAP_DBM_ANTNOISE) | - (1 << IEEE80211_RADIOTAP_ANTENNA)), - &iwl4965_rt->rt_hdr.it_present); - - /* Zero the flags, we'll add to them as we go */ - iwl4965_rt->rt_flags = 0; - - put_unaligned(cpu_to_le64(tsf), &iwl4965_rt->rt_tsf); - - iwl4965_rt->rt_dbmsignal = signal; - iwl4965_rt->rt_dbmnoise = noise; - - /* Convert the channel frequency and set the flags */ - put_unaligned(cpu_to_le16(stats->freq), &iwl4965_rt->rt_channelMHz); - if (!(phy_flags_hw & RX_RES_PHY_FLAGS_BAND_24_MSK)) - put_unaligned(cpu_to_le16(IEEE80211_CHAN_OFDM | - IEEE80211_CHAN_5GHZ), - &iwl4965_rt->rt_chbitmask); - else if (phy_flags_hw & RX_RES_PHY_FLAGS_MOD_CCK_MSK) - put_unaligned(cpu_to_le16(IEEE80211_CHAN_CCK | - IEEE80211_CHAN_2GHZ), - &iwl4965_rt->rt_chbitmask); - else /* 802.11g */ - put_unaligned(cpu_to_le16(IEEE80211_CHAN_OFDM | - IEEE80211_CHAN_2GHZ), - &iwl4965_rt->rt_chbitmask); - - if (rate == -1) - iwl4965_rt->rt_rate = 0; - else { - if (stats->band == IEEE80211_BAND_5GHZ) - rate += IWL_FIRST_OFDM_RATE; - - iwl4965_rt->rt_rate = iwl4965_rates[rate].ieee; - } - - /* - * "antenna number" - * - * It seems that the antenna field in the phy flags value - * is actually a bitfield. This is undefined by radiotap, - * it wants an actual antenna number but I always get "7" - * for most legacy frames I receive indicating that the - * same frame was received on all three RX chains. - * - * I think this field should be removed in favour of a - * new 802.11n radiotap field "RX chains" that is defined - * as a bitmask. - */ - antenna = phy_flags_hw & RX_RES_PHY_FLAGS_ANTENNA_MSK; - iwl4965_rt->rt_antenna = le16_to_cpu(antenna) >> 4; - - /* set the preamble flag if appropriate */ - if (phy_flags_hw & RX_RES_PHY_FLAGS_SHORT_PREAMBLE_MSK) - iwl4965_rt->rt_flags |= IEEE80211_RADIOTAP_F_SHORTPRE; - - stats->flag |= RX_FLAG_RADIOTAP; -} - -static void iwl_update_rx_stats(struct iwl_priv *priv, u16 fc, u16 len) -{ - /* 0 - mgmt, 1 - cnt, 2 - data */ - int idx = (fc & IEEE80211_FCTL_FTYPE) >> 2; - priv->rx_stats[idx].cnt++; - priv->rx_stats[idx].bytes += len; -} - -static u32 iwl4965_translate_rx_status(u32 decrypt_in) -{ - u32 decrypt_out = 0; - - if ((decrypt_in & RX_RES_STATUS_STATION_FOUND) == - RX_RES_STATUS_STATION_FOUND) - decrypt_out |= (RX_RES_STATUS_STATION_FOUND | - RX_RES_STATUS_NO_STATION_INFO_MISMATCH); - - decrypt_out |= (decrypt_in & RX_RES_STATUS_SEC_TYPE_MSK); - - /* packet was not encrypted */ - if ((decrypt_in & RX_RES_STATUS_SEC_TYPE_MSK) == - RX_RES_STATUS_SEC_TYPE_NONE) - return decrypt_out; - - /* packet was encrypted with unknown alg */ - if ((decrypt_in & RX_RES_STATUS_SEC_TYPE_MSK) == - RX_RES_STATUS_SEC_TYPE_ERR) - return decrypt_out; - - /* decryption was not done in HW */ - if ((decrypt_in & RX_MPDU_RES_STATUS_DEC_DONE_MSK) != - RX_MPDU_RES_STATUS_DEC_DONE_MSK) - return decrypt_out; - - switch (decrypt_in & RX_RES_STATUS_SEC_TYPE_MSK) { - - case RX_RES_STATUS_SEC_TYPE_CCMP: - /* alg is CCM: check MIC only */ - if (!(decrypt_in & RX_MPDU_RES_STATUS_MIC_OK)) - /* Bad MIC */ - decrypt_out |= RX_RES_STATUS_BAD_ICV_MIC; - else - decrypt_out |= RX_RES_STATUS_DECRYPT_OK; - - break; - - case RX_RES_STATUS_SEC_TYPE_TKIP: - if (!(decrypt_in & RX_MPDU_RES_STATUS_TTAK_OK)) { - /* Bad TTAK */ - decrypt_out |= RX_RES_STATUS_BAD_KEY_TTAK; - break; - } - /* fall through if TTAK OK */ - default: - if (!(decrypt_in & RX_MPDU_RES_STATUS_ICV_OK)) - decrypt_out |= RX_RES_STATUS_BAD_ICV_MIC; - else - decrypt_out |= RX_RES_STATUS_DECRYPT_OK; - break; - }; - - IWL_DEBUG_RX("decrypt_in:0x%x decrypt_out = 0x%x\n", - decrypt_in, decrypt_out); - - return decrypt_out; -} - -static void iwl4965_handle_data_packet(struct iwl_priv *priv, int is_data, - int include_phy, - struct iwl4965_rx_mem_buffer *rxb, - struct ieee80211_rx_status *stats) -{ - struct iwl4965_rx_packet *pkt = (struct iwl4965_rx_packet *)rxb->skb->data; - struct iwl4965_rx_phy_res *rx_start = (include_phy) ? - (struct iwl4965_rx_phy_res *)&(pkt->u.raw[0]) : NULL; - struct ieee80211_hdr *hdr; - u16 len; - __le32 *rx_end; - unsigned int skblen; - u32 ampdu_status; - u32 ampdu_status_legacy; - - if (!include_phy && priv->last_phy_res[0]) - rx_start = (struct iwl4965_rx_phy_res *)&priv->last_phy_res[1]; - - if (!rx_start) { - IWL_ERROR("MPDU frame without a PHY data\n"); - return; - } - if (include_phy) { - hdr = (struct ieee80211_hdr *)((u8 *) & rx_start[1] + - rx_start->cfg_phy_cnt); - - len = le16_to_cpu(rx_start->byte_count); - - rx_end = (__le32 *) ((u8 *) & pkt->u.raw[0] + - sizeof(struct iwl4965_rx_phy_res) + - rx_start->cfg_phy_cnt + len); - - } else { - struct iwl4965_rx_mpdu_res_start *amsdu = - (struct iwl4965_rx_mpdu_res_start *)pkt->u.raw; - - hdr = (struct ieee80211_hdr *)(pkt->u.raw + - sizeof(struct iwl4965_rx_mpdu_res_start)); - len = le16_to_cpu(amsdu->byte_count); - rx_start->byte_count = amsdu->byte_count; - rx_end = (__le32 *) (((u8 *) hdr) + len); - } - if (len > priv->hw_params.max_pkt_size || len < 16) { - IWL_WARNING("byte count out of range [16,4K] : %d\n", len); - return; - } - - ampdu_status = le32_to_cpu(*rx_end); - skblen = ((u8 *) rx_end - (u8 *) & pkt->u.raw[0]) + sizeof(u32); - - if (!include_phy) { - /* New status scheme, need to translate */ - ampdu_status_legacy = ampdu_status; - ampdu_status = iwl4965_translate_rx_status(ampdu_status); - } - - /* start from MAC */ - skb_reserve(rxb->skb, (void *)hdr - (void *)pkt); - skb_put(rxb->skb, len); /* end where data ends */ - - /* We only process data packets if the interface is open */ - if (unlikely(!priv->is_open)) { - IWL_DEBUG_DROP_LIMIT - ("Dropping packet while interface is not open.\n"); - return; - } - - stats->flag = 0; - hdr = (struct ieee80211_hdr *)rxb->skb->data; - - if (!priv->cfg->mod_params->sw_crypto) - iwl4965_set_decrypted_flag(priv, rxb->skb, ampdu_status, stats); - - if (priv->add_radiotap) - iwl4965_add_radiotap(priv, rxb->skb, rx_start, stats, ampdu_status); - - iwl_update_rx_stats(priv, le16_to_cpu(hdr->frame_control), len); - ieee80211_rx_irqsafe(priv->hw, rxb->skb, stats); - priv->alloc_rxb_skb--; - rxb->skb = NULL; -} - -/* Calc max signal level (dBm) among 3 possible receivers */ -static int iwl4965_calc_rssi(struct iwl4965_rx_phy_res *rx_resp) -{ - /* data from PHY/DSP regarding signal strength, etc., - * contents are always there, not configurable by host. */ - struct iwl4965_rx_non_cfg_phy *ncphy = - (struct iwl4965_rx_non_cfg_phy *)rx_resp->non_cfg_phy; - u32 agc = (le16_to_cpu(ncphy->agc_info) & IWL_AGC_DB_MASK) - >> IWL_AGC_DB_POS; - - u32 valid_antennae = - (le16_to_cpu(rx_resp->phy_flags) & RX_PHY_FLAGS_ANTENNAE_MASK) - >> RX_PHY_FLAGS_ANTENNAE_OFFSET; - u8 max_rssi = 0; - u32 i; - - /* Find max rssi among 3 possible receivers. - * These values are measured by the digital signal processor (DSP). - * They should stay fairly constant even as the signal strength varies, - * if the radio's automatic gain control (AGC) is working right. - * AGC value (see below) will provide the "interesting" info. */ - for (i = 0; i < 3; i++) - if (valid_antennae & (1 << i)) - max_rssi = max(ncphy->rssi_info[i << 1], max_rssi); - - IWL_DEBUG_STATS("Rssi In A %d B %d C %d Max %d AGC dB %d\n", - ncphy->rssi_info[0], ncphy->rssi_info[2], ncphy->rssi_info[4], - max_rssi, agc); - - /* dBm = max_rssi dB - agc dB - constant. - * Higher AGC (higher radio gain) means lower signal. */ - return (max_rssi - agc - IWL_RSSI_OFFSET); -} - -#ifdef CONFIG_IWL4965_HT - -void iwl4965_init_ht_hw_capab(struct iwl_priv *priv, - struct ieee80211_ht_info *ht_info, - enum ieee80211_band band) -{ - ht_info->cap = 0; - memset(ht_info->supp_mcs_set, 0, 16); - - ht_info->ht_supported = 1; - - if (band == IEEE80211_BAND_5GHZ) { - ht_info->cap |= (u16)IEEE80211_HT_CAP_SUP_WIDTH; - ht_info->cap |= (u16)IEEE80211_HT_CAP_SGI_40; - ht_info->supp_mcs_set[4] = 0x01; - } - ht_info->cap |= (u16)IEEE80211_HT_CAP_GRN_FLD; - ht_info->cap |= (u16)IEEE80211_HT_CAP_SGI_20; - ht_info->cap |= (u16)(IEEE80211_HT_CAP_MIMO_PS & - (IWL_MIMO_PS_NONE << 2)); - - if (priv->cfg->mod_params->amsdu_size_8K) - ht_info->cap |= (u16)IEEE80211_HT_CAP_MAX_AMSDU; - - ht_info->ampdu_factor = CFG_HT_RX_AMPDU_FACTOR_DEF; - ht_info->ampdu_density = CFG_HT_MPDU_DENSITY_DEF; - - ht_info->supp_mcs_set[0] = 0xFF; - ht_info->supp_mcs_set[1] = 0xFF; -} -#endif /* CONFIG_IWL4965_HT */ - -static void iwl4965_sta_modify_ps_wake(struct iwl_priv *priv, int sta_id) -{ - unsigned long flags; - - spin_lock_irqsave(&priv->sta_lock, flags); - priv->stations[sta_id].sta.station_flags &= ~STA_FLG_PWR_SAVE_MSK; - priv->stations[sta_id].sta.station_flags_msk = STA_FLG_PWR_SAVE_MSK; - priv->stations[sta_id].sta.sta.modify_mask = 0; - priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK; - spin_unlock_irqrestore(&priv->sta_lock, flags); - - iwl4965_send_add_station(priv, &priv->stations[sta_id].sta, CMD_ASYNC); -} - -static void iwl4965_update_ps_mode(struct iwl_priv *priv, u16 ps_bit, u8 *addr) -{ - /* FIXME: need locking over ps_status ??? */ - u8 sta_id = iwl4965_hw_find_station(priv, addr); - - if (sta_id != IWL_INVALID_STATION) { - u8 sta_awake = priv->stations[sta_id]. - ps_status == STA_PS_STATUS_WAKE; - - if (sta_awake && ps_bit) - priv->stations[sta_id].ps_status = STA_PS_STATUS_SLEEP; - else if (!sta_awake && !ps_bit) { - iwl4965_sta_modify_ps_wake(priv, sta_id); - priv->stations[sta_id].ps_status = STA_PS_STATUS_WAKE; - } - } -} -#ifdef CONFIG_IWLWIFI_DEBUG - -/** - * iwl4965_dbg_report_frame - dump frame to syslog during debug sessions - * - * You may hack this function to show different aspects of received frames, - * including selective frame dumps. - * group100 parameter selects whether to show 1 out of 100 good frames. - * - * TODO: This was originally written for 3945, need to audit for - * proper operation with 4965. - */ -static void iwl4965_dbg_report_frame(struct iwl_priv *priv, - struct iwl4965_rx_packet *pkt, - struct ieee80211_hdr *header, int group100) -{ - u32 to_us; - u32 print_summary = 0; - u32 print_dump = 0; /* set to 1 to dump all frames' contents */ - u32 hundred = 0; - u32 dataframe = 0; - u16 fc; - u16 seq_ctl; - u16 channel; - u16 phy_flags; - int rate_sym; - u16 length; - u16 status; - u16 bcn_tmr; - u32 tsf_low; - u64 tsf; - u8 rssi; - u8 agc; - u16 sig_avg; - u16 noise_diff; - struct iwl4965_rx_frame_stats *rx_stats = IWL_RX_STATS(pkt); - struct iwl4965_rx_frame_hdr *rx_hdr = IWL_RX_HDR(pkt); - struct iwl4965_rx_frame_end *rx_end = IWL_RX_END(pkt); - u8 *data = IWL_RX_DATA(pkt); - - if (likely(!(iwl_debug_level & IWL_DL_RX))) - return; - - /* MAC header */ - fc = le16_to_cpu(header->frame_control); - seq_ctl = le16_to_cpu(header->seq_ctrl); - - /* metadata */ - channel = le16_to_cpu(rx_hdr->channel); - phy_flags = le16_to_cpu(rx_hdr->phy_flags); - rate_sym = rx_hdr->rate; - length = le16_to_cpu(rx_hdr->len); - - /* end-of-frame status and timestamp */ - status = le32_to_cpu(rx_end->status); - bcn_tmr = le32_to_cpu(rx_end->beacon_timestamp); - tsf_low = le64_to_cpu(rx_end->timestamp) & 0x0ffffffff; - tsf = le64_to_cpu(rx_end->timestamp); - - /* signal statistics */ - rssi = rx_stats->rssi; - agc = rx_stats->agc; - sig_avg = le16_to_cpu(rx_stats->sig_avg); - noise_diff = le16_to_cpu(rx_stats->noise_diff); - - to_us = !compare_ether_addr(header->addr1, priv->mac_addr); - - /* if data frame is to us and all is good, - * (optionally) print summary for only 1 out of every 100 */ - if (to_us && (fc & ~IEEE80211_FCTL_PROTECTED) == - (IEEE80211_FCTL_FROMDS | IEEE80211_FTYPE_DATA)) { - dataframe = 1; - if (!group100) - print_summary = 1; /* print each frame */ - else if (priv->framecnt_to_us < 100) { - priv->framecnt_to_us++; - print_summary = 0; - } else { - priv->framecnt_to_us = 0; - print_summary = 1; - hundred = 1; - } - } else { - /* print summary for all other frames */ - print_summary = 1; - } - - if (print_summary) { - char *title; - int rate_idx; - u32 bitrate; - - if (hundred) - title = "100Frames"; - else if (fc & IEEE80211_FCTL_RETRY) - title = "Retry"; - else if (ieee80211_is_assoc_response(fc)) - title = "AscRsp"; - else if (ieee80211_is_reassoc_response(fc)) - title = "RasRsp"; - else if (ieee80211_is_probe_response(fc)) { - title = "PrbRsp"; - print_dump = 1; /* dump frame contents */ - } else if (ieee80211_is_beacon(fc)) { - title = "Beacon"; - print_dump = 1; /* dump frame contents */ - } else if (ieee80211_is_atim(fc)) - title = "ATIM"; - else if (ieee80211_is_auth(fc)) - title = "Auth"; - else if (ieee80211_is_deauth(fc)) - title = "DeAuth"; - else if (ieee80211_is_disassoc(fc)) - title = "DisAssoc"; - else - title = "Frame"; - - rate_idx = iwl4965_hwrate_to_plcp_idx(rate_sym); - if (unlikely(rate_idx == -1)) - bitrate = 0; - else - bitrate = iwl4965_rates[rate_idx].ieee / 2; - - /* print frame summary. - * MAC addresses show just the last byte (for brevity), - * but you can hack it to show more, if you'd like to. */ - if (dataframe) - IWL_DEBUG_RX("%s: mhd=0x%04x, dst=0x%02x, " - "len=%u, rssi=%d, chnl=%d, rate=%u, \n", - title, fc, header->addr1[5], - length, rssi, channel, bitrate); - else { - /* src/dst addresses assume managed mode */ - IWL_DEBUG_RX("%s: 0x%04x, dst=0x%02x, " - "src=0x%02x, rssi=%u, tim=%lu usec, " - "phy=0x%02x, chnl=%d\n", - title, fc, header->addr1[5], - header->addr3[5], rssi, - tsf_low - priv->scan_start_tsf, - phy_flags, channel); - } - } - if (print_dump) - iwl_print_hex_dump(IWL_DL_RX, data, length); -} -#else -static inline void iwl4965_dbg_report_frame(struct iwl_priv *priv, - struct iwl4965_rx_packet *pkt, - struct ieee80211_hdr *header, - int group100) -{ -} -#endif - - - -/* Called for REPLY_RX (legacy ABG frames), or - * REPLY_RX_MPDU_CMD (HT high-throughput N frames). */ -static void iwl4965_rx_reply_rx(struct iwl_priv *priv, - struct iwl4965_rx_mem_buffer *rxb) -{ - struct ieee80211_hdr *header; - struct ieee80211_rx_status rx_status; - struct iwl4965_rx_packet *pkt = (void *)rxb->skb->data; - /* Use phy data (Rx signal strength, etc.) contained within - * this rx packet for legacy frames, - * or phy data cached from REPLY_RX_PHY_CMD for HT frames. */ - int include_phy = (pkt->hdr.cmd == REPLY_RX); - struct iwl4965_rx_phy_res *rx_start = (include_phy) ? - (struct iwl4965_rx_phy_res *)&(pkt->u.raw[0]) : - (struct iwl4965_rx_phy_res *)&priv->last_phy_res[1]; - __le32 *rx_end; - unsigned int len = 0; - u16 fc; - u8 network_packet; - - rx_status.mactime = le64_to_cpu(rx_start->timestamp); - rx_status.freq = - ieee80211_channel_to_frequency(le16_to_cpu(rx_start->channel)); - rx_status.band = (rx_start->phy_flags & RX_RES_PHY_FLAGS_BAND_24_MSK) ? - IEEE80211_BAND_2GHZ : IEEE80211_BAND_5GHZ; - rx_status.rate_idx = - iwl4965_hwrate_to_plcp_idx(le32_to_cpu(rx_start->rate_n_flags)); - if (rx_status.band == IEEE80211_BAND_5GHZ) - rx_status.rate_idx -= IWL_FIRST_OFDM_RATE; - - rx_status.antenna = 0; - rx_status.flag = 0; - - if ((unlikely(rx_start->cfg_phy_cnt > 20))) { - IWL_DEBUG_DROP("dsp size out of range [0,20]: %d/n", - rx_start->cfg_phy_cnt); - return; - } - - if (!include_phy) { - if (priv->last_phy_res[0]) - rx_start = (struct iwl4965_rx_phy_res *) - &priv->last_phy_res[1]; - else - rx_start = NULL; - } - - if (!rx_start) { - IWL_ERROR("MPDU frame without a PHY data\n"); - return; - } - - if (include_phy) { - header = (struct ieee80211_hdr *)((u8 *) & rx_start[1] - + rx_start->cfg_phy_cnt); - - len = le16_to_cpu(rx_start->byte_count); - rx_end = (__le32 *)(pkt->u.raw + rx_start->cfg_phy_cnt + - sizeof(struct iwl4965_rx_phy_res) + len); - } else { - struct iwl4965_rx_mpdu_res_start *amsdu = - (struct iwl4965_rx_mpdu_res_start *)pkt->u.raw; - - header = (void *)(pkt->u.raw + - sizeof(struct iwl4965_rx_mpdu_res_start)); - len = le16_to_cpu(amsdu->byte_count); - rx_end = (__le32 *) (pkt->u.raw + - sizeof(struct iwl4965_rx_mpdu_res_start) + len); - } - - if (!(*rx_end & RX_RES_STATUS_NO_CRC32_ERROR) || - !(*rx_end & RX_RES_STATUS_NO_RXE_OVERFLOW)) { - IWL_DEBUG_RX("Bad CRC or FIFO: 0x%08X.\n", - le32_to_cpu(*rx_end)); - return; - } - - priv->ucode_beacon_time = le32_to_cpu(rx_start->beacon_time_stamp); - - /* Find max signal strength (dBm) among 3 antenna/receiver chains */ - rx_status.ssi = iwl4965_calc_rssi(rx_start); - - /* Meaningful noise values are available only from beacon statistics, - * which are gathered only when associated, and indicate noise - * only for the associated network channel ... - * Ignore these noise values while scanning (other channels) */ - if (iwl_is_associated(priv) && - !test_bit(STATUS_SCANNING, &priv->status)) { - rx_status.noise = priv->last_rx_noise; - rx_status.signal = iwl4965_calc_sig_qual(rx_status.ssi, - rx_status.noise); - } else { - rx_status.noise = IWL_NOISE_MEAS_NOT_AVAILABLE; - rx_status.signal = iwl4965_calc_sig_qual(rx_status.ssi, 0); - } - - /* Reset beacon noise level if not associated. */ - if (!iwl_is_associated(priv)) - priv->last_rx_noise = IWL_NOISE_MEAS_NOT_AVAILABLE; - - /* Set "1" to report good data frames in groups of 100 */ - /* FIXME: need to optimze the call: */ - iwl4965_dbg_report_frame(priv, pkt, header, 1); - - IWL_DEBUG_STATS_LIMIT("Rssi %d, noise %d, qual %d, TSF %llu\n", - rx_status.ssi, rx_status.noise, rx_status.signal, - (unsigned long long)rx_status.mactime); - - network_packet = iwl4965_is_network_packet(priv, header); - if (network_packet) { - priv->last_rx_rssi = rx_status.ssi; - priv->last_beacon_time = priv->ucode_beacon_time; - priv->last_tsf = le64_to_cpu(rx_start->timestamp); - } - - fc = le16_to_cpu(header->frame_control); - switch (fc & IEEE80211_FCTL_FTYPE) { - case IEEE80211_FTYPE_MGMT: - if (priv->iw_mode == IEEE80211_IF_TYPE_AP) - iwl4965_update_ps_mode(priv, fc & IEEE80211_FCTL_PM, - header->addr2); - iwl4965_handle_data_packet(priv, 0, include_phy, rxb, &rx_status); - break; - - case IEEE80211_FTYPE_CTL: -#ifdef CONFIG_IWL4965_HT - switch (fc & IEEE80211_FCTL_STYPE) { - case IEEE80211_STYPE_BACK_REQ: - IWL_DEBUG_HT("IEEE80211_STYPE_BACK_REQ arrived\n"); - iwl4965_handle_data_packet(priv, 0, include_phy, - rxb, &rx_status); - break; - default: - break; - } -#endif - break; - - case IEEE80211_FTYPE_DATA: { - DECLARE_MAC_BUF(mac1); - DECLARE_MAC_BUF(mac2); - DECLARE_MAC_BUF(mac3); - - if (priv->iw_mode == IEEE80211_IF_TYPE_AP) - iwl4965_update_ps_mode(priv, fc & IEEE80211_FCTL_PM, - header->addr2); - - if (unlikely(!network_packet)) - IWL_DEBUG_DROP("Dropping (non network): " - "%s, %s, %s\n", - print_mac(mac1, header->addr1), - print_mac(mac2, header->addr2), - print_mac(mac3, header->addr3)); - else if (unlikely(iwl4965_is_duplicate_packet(priv, header))) - IWL_DEBUG_DROP("Dropping (dup): %s, %s, %s\n", - print_mac(mac1, header->addr1), - print_mac(mac2, header->addr2), - print_mac(mac3, header->addr3)); - else - iwl4965_handle_data_packet(priv, 1, include_phy, rxb, - &rx_status); - break; - } - default: - break; - - } -} - -/* Cache phy data (Rx signal strength, etc) for HT frame (REPLY_RX_PHY_CMD). - * This will be used later in iwl4965_rx_reply_rx() for REPLY_RX_MPDU_CMD. */ -static void iwl4965_rx_reply_rx_phy(struct iwl_priv *priv, - struct iwl4965_rx_mem_buffer *rxb) -{ - struct iwl4965_rx_packet *pkt = (void *)rxb->skb->data; - priv->last_phy_res[0] = 1; - memcpy(&priv->last_phy_res[1], &(pkt->u.raw[0]), - sizeof(struct iwl4965_rx_phy_res)); -} -static void iwl4965_rx_missed_beacon_notif(struct iwl_priv *priv, - struct iwl4965_rx_mem_buffer *rxb) - -{ -#ifdef CONFIG_IWL4965_SENSITIVITY - struct iwl4965_rx_packet *pkt = (void *)rxb->skb->data; - struct iwl4965_missed_beacon_notif *missed_beacon; - - missed_beacon = &pkt->u.missed_beacon; - if (le32_to_cpu(missed_beacon->consequtive_missed_beacons) > 5) { - IWL_DEBUG_CALIB("missed bcn cnsq %d totl %d rcd %d expctd %d\n", - le32_to_cpu(missed_beacon->consequtive_missed_beacons), - le32_to_cpu(missed_beacon->total_missed_becons), - le32_to_cpu(missed_beacon->num_recvd_beacons), - le32_to_cpu(missed_beacon->num_expected_beacons)); - priv->sensitivity_data.state = IWL_SENS_CALIB_NEED_REINIT; - if (unlikely(!test_bit(STATUS_SCANNING, &priv->status))) - queue_work(priv->workqueue, &priv->sensitivity_work); - } -#endif /*CONFIG_IWL4965_SENSITIVITY*/ -} -#ifdef CONFIG_IWL4965_HT - -/** - * iwl4965_sta_modify_enable_tid_tx - Enable Tx for this TID in station table - */ -static void iwl4965_sta_modify_enable_tid_tx(struct iwl_priv *priv, - int sta_id, int tid) -{ - unsigned long flags; - - /* Remove "disable" flag, to enable Tx for this TID */ - spin_lock_irqsave(&priv->sta_lock, flags); - priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_TID_DISABLE_TX; - priv->stations[sta_id].sta.tid_disable_tx &= cpu_to_le16(~(1 << tid)); - priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK; - spin_unlock_irqrestore(&priv->sta_lock, flags); - - iwl4965_send_add_station(priv, &priv->stations[sta_id].sta, CMD_ASYNC); -} - -/** - * iwl4965_tx_status_reply_compressed_ba - Update tx status from block-ack - * - * Go through block-ack's bitmap of ACK'd frames, update driver's record of - * ACK vs. not. This gets sent to mac80211, then to rate scaling algo. - */ -static int iwl4965_tx_status_reply_compressed_ba(struct iwl_priv *priv, - struct iwl4965_ht_agg *agg, - struct iwl4965_compressed_ba_resp* - ba_resp) - -{ - int i, sh, ack; - u16 seq_ctl = le16_to_cpu(ba_resp->seq_ctl); - u16 scd_flow = le16_to_cpu(ba_resp->scd_flow); - u64 bitmap; - int successes = 0; - struct ieee80211_tx_status *tx_status; - - if (unlikely(!agg->wait_for_ba)) { - IWL_ERROR("Received BA when not expected\n"); - return -EINVAL; - } - - /* Mark that the expected block-ack response arrived */ - agg->wait_for_ba = 0; - IWL_DEBUG_TX_REPLY("BA %d %d\n", agg->start_idx, ba_resp->seq_ctl); - - /* Calculate shift to align block-ack bits with our Tx window bits */ - sh = agg->start_idx - SEQ_TO_INDEX(seq_ctl>>4); - if (sh < 0) /* tbw something is wrong with indices */ - sh += 0x100; - - /* don't use 64-bit values for now */ - bitmap = le64_to_cpu(ba_resp->bitmap) >> sh; - - if (agg->frame_count > (64 - sh)) { - IWL_DEBUG_TX_REPLY("more frames than bitmap size"); - return -1; - } - - /* check for success or failure according to the - * transmitted bitmap and block-ack bitmap */ - bitmap &= agg->bitmap; - - /* For each frame attempted in aggregation, - * update driver's record of tx frame's status. */ - for (i = 0; i < agg->frame_count ; i++) { - ack = bitmap & (1 << i); - successes += !!ack; - IWL_DEBUG_TX_REPLY("%s ON i=%d idx=%d raw=%d\n", - ack? "ACK":"NACK", i, (agg->start_idx + i) & 0xff, - agg->start_idx + i); - } - - tx_status = &priv->txq[scd_flow].txb[agg->start_idx].status; - tx_status->flags = IEEE80211_TX_STATUS_ACK; - tx_status->flags |= IEEE80211_TX_STATUS_AMPDU; - tx_status->ampdu_ack_map = successes; - tx_status->ampdu_ack_len = agg->frame_count; - iwl4965_hwrate_to_tx_control(priv, agg->rate_n_flags, - &tx_status->control); - - IWL_DEBUG_TX_REPLY("Bitmap %llx\n", (unsigned long long)bitmap); - - return 0; -} - /** * iwl4965_tx_queue_stop_scheduler - Stop queue, but keep configuration */ @@ -4258,22 +1938,24 @@ static void iwl4965_tx_queue_stop_scheduler(struct iwl_priv *priv, * the SCD_ACT_EN bit is the write-enable mask for the ACTIVE bit. */ iwl_write_prph(priv, IWL49_SCD_QUEUE_STATUS_BITS(txq_id), - (0 << SCD_QUEUE_STTS_REG_POS_ACTIVE)| - (1 << SCD_QUEUE_STTS_REG_POS_SCD_ACT_EN)); + (0 << IWL49_SCD_QUEUE_STTS_REG_POS_ACTIVE)| + (1 << IWL49_SCD_QUEUE_STTS_REG_POS_SCD_ACT_EN)); } /** - * txq_id must be greater than IWL_BACK_QUEUE_FIRST_ID + * txq_id must be greater than IWL49_FIRST_AMPDU_QUEUE * priv->lock must be held by the caller */ -static int iwl4965_tx_queue_agg_disable(struct iwl_priv *priv, u16 txq_id, - u16 ssn_idx, u8 tx_fifo) +static int iwl4965_txq_agg_disable(struct iwl_priv *priv, u16 txq_id, + u16 ssn_idx, u8 tx_fifo) { int ret = 0; - if (IWL_BACK_QUEUE_FIRST_ID > txq_id) { - IWL_WARNING("queue number too small: %d, must be > %d\n", - txq_id, IWL_BACK_QUEUE_FIRST_ID); + if ((IWL49_FIRST_AMPDU_QUEUE > txq_id) || + (IWL49_FIRST_AMPDU_QUEUE + IWL49_NUM_AMPDU_QUEUES <= txq_id)) { + IWL_WARNING("queue number out of range: %d, must be %d to %d\n", + txq_id, IWL49_FIRST_AMPDU_QUEUE, + IWL49_FIRST_AMPDU_QUEUE + IWL49_NUM_AMPDU_QUEUES - 1); return -EINVAL; } @@ -4291,7 +1973,7 @@ static int iwl4965_tx_queue_agg_disable(struct iwl_priv *priv, u16 txq_id, iwl4965_set_wr_ptrs(priv, txq_id, ssn_idx); iwl_clear_bits_prph(priv, IWL49_SCD_INTERRUPT_MASK, (1 << txq_id)); - iwl4965_txq_ctx_deactivate(priv, 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); @@ -4299,121 +1981,6 @@ static int iwl4965_tx_queue_agg_disable(struct iwl_priv *priv, u16 txq_id, return 0; } -int iwl4965_check_empty_hw_queue(struct iwl_priv *priv, int sta_id, - u8 tid, int txq_id) -{ - struct iwl4965_queue *q = &priv->txq[txq_id].q; - u8 *addr = priv->stations[sta_id].sta.sta.addr; - struct iwl4965_tid_data *tid_data = &priv->stations[sta_id].tid[tid]; - - switch (priv->stations[sta_id].tid[tid].agg.state) { - case IWL_EMPTYING_HW_QUEUE_DELBA: - /* We are reclaiming the last packet of the */ - /* aggregated HW queue */ - if (txq_id == tid_data->agg.txq_id && - q->read_ptr == q->write_ptr) { - u16 ssn = SEQ_TO_SN(tid_data->seq_number); - int tx_fifo = default_tid_to_tx_fifo[tid]; - IWL_DEBUG_HT("HW queue empty: continue DELBA flow\n"); - iwl4965_tx_queue_agg_disable(priv, txq_id, - ssn, tx_fifo); - tid_data->agg.state = IWL_AGG_OFF; - ieee80211_stop_tx_ba_cb_irqsafe(priv->hw, addr, tid); - } - break; - case IWL_EMPTYING_HW_QUEUE_ADDBA: - /* We are reclaiming the last packet of the queue */ - if (tid_data->tfds_in_queue == 0) { - IWL_DEBUG_HT("HW queue empty: continue ADDBA flow\n"); - tid_data->agg.state = IWL_AGG_ON; - ieee80211_start_tx_ba_cb_irqsafe(priv->hw, addr, tid); - } - break; - } - return 0; -} - -/** - * iwl4965_queue_dec_wrap - Decrement queue index, wrap back to end if needed - * @index -- current index - * @n_bd -- total number of entries in queue (s/b power of 2) - */ -static inline int iwl4965_queue_dec_wrap(int index, int n_bd) -{ - return (index == 0) ? n_bd - 1 : index - 1; -} - -/** - * iwl4965_rx_reply_compressed_ba - Handler for REPLY_COMPRESSED_BA - * - * Handles block-acknowledge notification from device, which reports success - * of frames sent via aggregation. - */ -static void iwl4965_rx_reply_compressed_ba(struct iwl_priv *priv, - struct iwl4965_rx_mem_buffer *rxb) -{ - struct iwl4965_rx_packet *pkt = (void *)rxb->skb->data; - struct iwl4965_compressed_ba_resp *ba_resp = &pkt->u.compressed_ba; - int index; - struct iwl4965_tx_queue *txq = NULL; - struct iwl4965_ht_agg *agg; - DECLARE_MAC_BUF(mac); - - /* "flow" corresponds to Tx queue */ - u16 scd_flow = le16_to_cpu(ba_resp->scd_flow); - - /* "ssn" is start of block-ack Tx window, corresponds to index - * (in Tx queue's circular buffer) of first TFD/frame in window */ - u16 ba_resp_scd_ssn = le16_to_cpu(ba_resp->scd_ssn); - - if (scd_flow >= priv->hw_params.max_txq_num) { - IWL_ERROR("BUG_ON scd_flow is bigger than number of queues"); - return; - } - - txq = &priv->txq[scd_flow]; - agg = &priv->stations[ba_resp->sta_id].tid[ba_resp->tid].agg; - - /* Find index just before block-ack window */ - index = iwl4965_queue_dec_wrap(ba_resp_scd_ssn & 0xff, txq->q.n_bd); - - /* TODO: Need to get this copy more safely - now good for debug */ - - IWL_DEBUG_TX_REPLY("REPLY_COMPRESSED_BA [%d]Received from %s, " - "sta_id = %d\n", - agg->wait_for_ba, - print_mac(mac, (u8*) &ba_resp->sta_addr_lo32), - ba_resp->sta_id); - IWL_DEBUG_TX_REPLY("TID = %d, SeqCtl = %d, bitmap = 0x%llx, scd_flow = " - "%d, scd_ssn = %d\n", - ba_resp->tid, - ba_resp->seq_ctl, - (unsigned long long)le64_to_cpu(ba_resp->bitmap), - ba_resp->scd_flow, - ba_resp->scd_ssn); - IWL_DEBUG_TX_REPLY("DAT start_idx = %d, bitmap = 0x%llx \n", - agg->start_idx, - (unsigned long long)agg->bitmap); - - /* Update driver's record of ACK vs. not for each frame in window */ - iwl4965_tx_status_reply_compressed_ba(priv, agg, ba_resp); - - /* Release all TFDs before the SSN, i.e. all TFDs in front of - * block-ack window (we assume that they've been successfully - * transmitted ... if not, it's too late anyway). */ - if (txq->q.read_ptr != (ba_resp_scd_ssn & 0xff)) { - int freed = iwl4965_tx_queue_reclaim(priv, scd_flow, index); - priv->stations[ba_resp->sta_id]. - tid[ba_resp->tid].tfds_in_queue -= freed; - if (iwl4965_queue_space(&txq->q) > txq->q.low_mark && - priv->mac80211_registered && - agg->state != IWL_EMPTYING_HW_QUEUE_DELBA) - ieee80211_wake_queue(priv->hw, scd_flow); - iwl4965_check_empty_hw_queue(priv, ba_resp->sta_id, - ba_resp->tid, scd_flow); - } -} - /** * iwl4965_tx_queue_set_q2ratid - Map unique receiver/tid combination to a queue */ @@ -4424,10 +1991,10 @@ static int iwl4965_tx_queue_set_q2ratid(struct iwl_priv *priv, u16 ra_tid, u32 tbl_dw; u16 scd_q2ratid; - scd_q2ratid = ra_tid & SCD_QUEUE_RA_TID_MAP_RATID_MSK; + scd_q2ratid = ra_tid & IWL_SCD_QUEUE_RA_TID_MAP_RATID_MSK; tbl_dw_addr = priv->scd_base_addr + - SCD_TRANSLATE_TBL_OFFSET_QUEUE(txq_id); + IWL49_SCD_TRANSLATE_TBL_OFFSET_QUEUE(txq_id); tbl_dw = iwl_read_targ_mem(priv, tbl_dw_addr); @@ -4445,31 +2012,34 @@ static int iwl4965_tx_queue_set_q2ratid(struct iwl_priv *priv, u16 ra_tid, /** * iwl4965_tx_queue_agg_enable - Set up & enable aggregation for selected queue * - * NOTE: txq_id must be greater than IWL_BACK_QUEUE_FIRST_ID, + * NOTE: txq_id must be greater than IWL49_FIRST_AMPDU_QUEUE, * i.e. it must be one of the higher queues used for aggregation */ -static int iwl4965_tx_queue_agg_enable(struct iwl_priv *priv, int txq_id, - int tx_fifo, int sta_id, int tid, - u16 ssn_idx) +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 rc; + int ret; u16 ra_tid; - if (IWL_BACK_QUEUE_FIRST_ID > txq_id) - IWL_WARNING("queue number too small: %d, must be > %d\n", - txq_id, IWL_BACK_QUEUE_FIRST_ID); + if ((IWL49_FIRST_AMPDU_QUEUE > txq_id) || + (IWL49_FIRST_AMPDU_QUEUE + IWL49_NUM_AMPDU_QUEUES <= txq_id)) { + IWL_WARNING("queue number out of range: %d, must be %d to %d\n", + txq_id, IWL49_FIRST_AMPDU_QUEUE, + IWL49_FIRST_AMPDU_QUEUE + IWL49_NUM_AMPDU_QUEUES - 1); + return -EINVAL; + } ra_tid = BUILD_RAxTID(sta_id, tid); /* Modify device's station table to Tx this TID */ - iwl4965_sta_modify_enable_tid_tx(priv, sta_id, tid); + iwl_sta_modify_enable_tid_tx(priv, sta_id, tid); spin_lock_irqsave(&priv->lock, flags); - rc = iwl_grab_nic_access(priv); - if (rc) { + ret = iwl_grab_nic_access(priv); + if (ret) { spin_unlock_irqrestore(&priv->lock, flags); - return rc; + return ret; } /* Stop this Tx queue before configuring it */ @@ -4489,14 +2059,14 @@ static int iwl4965_tx_queue_agg_enable(struct iwl_priv *priv, int txq_id, /* Set up Tx window size and frame limit for this queue */ iwl_write_targ_mem(priv, - priv->scd_base_addr + SCD_CONTEXT_QUEUE_OFFSET(txq_id), - (SCD_WIN_SIZE << SCD_QUEUE_CTX_REG1_WIN_SIZE_POS) & - SCD_QUEUE_CTX_REG1_WIN_SIZE_MSK); + priv->scd_base_addr + IWL49_SCD_CONTEXT_QUEUE_OFFSET(txq_id), + (SCD_WIN_SIZE << IWL49_SCD_QUEUE_CTX_REG1_WIN_SIZE_POS) & + IWL49_SCD_QUEUE_CTX_REG1_WIN_SIZE_MSK); iwl_write_targ_mem(priv, priv->scd_base_addr + - SCD_CONTEXT_QUEUE_OFFSET(txq_id) + sizeof(u32), - (SCD_FRAME_LIMIT << SCD_QUEUE_CTX_REG2_FRAME_LIMIT_POS) - & SCD_QUEUE_CTX_REG2_FRAME_LIMIT_MSK); + IWL49_SCD_CONTEXT_QUEUE_OFFSET(txq_id) + sizeof(u32), + (SCD_FRAME_LIMIT << IWL49_SCD_QUEUE_CTX_REG2_FRAME_LIMIT_POS) + & IWL49_SCD_QUEUE_CTX_REG2_FRAME_LIMIT_MSK); iwl_set_bits_prph(priv, IWL49_SCD_INTERRUPT_MASK, (1 << txq_id)); @@ -4509,444 +2079,313 @@ static int iwl4965_tx_queue_agg_enable(struct iwl_priv *priv, int txq_id, return 0; } -#endif /* CONFIG_IWL4965_HT */ - -/** - * iwl4965_add_station - Initialize a station's hardware rate table - * - * The uCode's station table contains a table of fallback rates - * for automatic fallback during transmission. - * - * NOTE: This sets up a default set of values. These will be replaced later - * if the driver's iwl-4965-rs rate scaling algorithm is used, instead of - * rc80211_simple. - * - * NOTE: Run REPLY_ADD_STA command to set up station table entry, before - * calling this function (which runs REPLY_TX_LINK_QUALITY_CMD, - * which requires station table entry to exist). - */ -void iwl4965_add_station(struct iwl_priv *priv, const u8 *addr, int is_ap) -{ - int i, r; - struct iwl_link_quality_cmd link_cmd = { - .reserved1 = 0, - }; - u16 rate_flags; - - /* Set up the rate scaling to start at selected rate, fall back - * all the way down to 1M in IEEE order, and then spin on 1M */ - if (is_ap) - r = IWL_RATE_54M_INDEX; - else if (priv->band == IEEE80211_BAND_5GHZ) - r = IWL_RATE_6M_INDEX; - else - r = IWL_RATE_1M_INDEX; - - for (i = 0; i < LINK_QUAL_MAX_RETRY_NUM; i++) { - rate_flags = 0; - if (r >= IWL_FIRST_CCK_RATE && r <= IWL_LAST_CCK_RATE) - rate_flags |= RATE_MCS_CCK_MSK; - - /* Use Tx antenna B only */ - rate_flags |= RATE_MCS_ANT_B_MSK; - rate_flags &= ~RATE_MCS_ANT_A_MSK; - - link_cmd.rs_table[i].rate_n_flags = - iwl4965_hw_set_rate_n_flags(iwl4965_rates[r].plcp, rate_flags); - r = iwl4965_get_prev_ieee_rate(r); - } - - link_cmd.general_params.single_stream_ant_msk = 2; - 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); - - /* 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; - - iwl_send_cmd_pdu_async(priv, REPLY_TX_LINK_QUALITY_CMD, - sizeof(link_cmd), &link_cmd, NULL); -} - -#ifdef CONFIG_IWL4965_HT - -static u8 iwl4965_is_channel_extension(struct iwl_priv *priv, - enum ieee80211_band band, - u16 channel, u8 extension_chan_offset) -{ - const struct iwl_channel_info *ch_info; - - ch_info = iwl_get_channel_info(priv, band, channel); - if (!is_channel_valid(ch_info)) - return 0; - - if (extension_chan_offset == IWL_EXT_CHANNEL_OFFSET_NONE) - return 0; - - if ((ch_info->fat_extension_channel == extension_chan_offset) || - (ch_info->fat_extension_channel == HT_IE_EXT_CHANNEL_MAX)) - return 1; - - return 0; -} - -static u8 iwl4965_is_fat_tx_allowed(struct iwl_priv *priv, - struct ieee80211_ht_info *sta_ht_inf) -{ - 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 == IWL_EXT_CHANNEL_OFFSET_NONE)) - return 0; - - if (sta_ht_inf) { - if ((!sta_ht_inf->ht_supported) || - (!(sta_ht_inf->cap & IEEE80211_HT_CAP_SUP_WIDTH))) - return 0; - } - - return (iwl4965_is_channel_extension(priv, priv->band, - iwl_ht_conf->control_channel, - iwl_ht_conf->extension_chan_offset)); -} - -void iwl4965_set_rxon_ht(struct iwl_priv *priv, struct iwl_ht_info *ht_info) +int iwl4965_mac_ampdu_action(struct ieee80211_hw *hw, + enum ieee80211_ampdu_mlme_action action, + const u8 *addr, u16 tid, u16 *ssn) { - struct iwl4965_rxon_cmd *rxon = &priv->staging_rxon; - u32 val; + struct iwl_priv *priv = hw->priv; + DECLARE_MAC_BUF(mac); - if (!ht_info->is_ht) - return; + IWL_DEBUG_HT("A-MPDU action on addr %s tid %d\n", + print_mac(mac, addr), tid); - /* Set up channel bandwidth: 20 MHz only, or 20/40 mixed if fat ok */ - if (iwl4965_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); - - if (le16_to_cpu(rxon->channel) != ht_info->control_channel) { - IWL_DEBUG_ASSOC("control diff than current %d %d\n", - le16_to_cpu(rxon->channel), - ht_info->control_channel); - rxon->channel = cpu_to_le16(ht_info->control_channel); - return; - } + if (!(priv->cfg->sku & IWL_SKU_N)) + return -EACCES; - /* Note: control channel is opposite of extension channel */ - switch (ht_info->extension_chan_offset) { - case IWL_EXT_CHANNEL_OFFSET_ABOVE: - rxon->flags &= ~(RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK); - break; - case IWL_EXT_CHANNEL_OFFSET_BELOW: - rxon->flags |= RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK; - break; - case IWL_EXT_CHANNEL_OFFSET_NONE: + switch (action) { + case IEEE80211_AMPDU_RX_START: + IWL_DEBUG_HT("start Rx\n"); + return iwl_rx_agg_start(priv, addr, tid, *ssn); + case IEEE80211_AMPDU_RX_STOP: + IWL_DEBUG_HT("stop Rx\n"); + return iwl_rx_agg_stop(priv, addr, tid); + case IEEE80211_AMPDU_TX_START: + IWL_DEBUG_HT("start Tx\n"); + return iwl_tx_agg_start(priv, addr, tid, ssn); + case IEEE80211_AMPDU_TX_STOP: + IWL_DEBUG_HT("stop Tx\n"); + return iwl_tx_agg_stop(priv, addr, tid); default: - rxon->flags &= ~RXON_FLG_CHANNEL_MODE_MIXED_MSK; + IWL_DEBUG_HT("unknown\n"); + return -EINVAL; break; } - - val = ht_info->ht_protection; - - rxon->flags |= cpu_to_le32(val << RXON_FLG_HT_OPERATING_MODE_POS); - - iwl4965_set_rxon_chain(priv); - - IWL_DEBUG_ASSOC("supported HT rate 0x%X %X " - "rxon flags 0x%X operation mode :0x%X " - "extension channel offset 0x%x " - "control chan %d\n", - ht_info->supp_mcs_set[0], ht_info->supp_mcs_set[1], - le32_to_cpu(rxon->flags), ht_info->ht_protection, - ht_info->extension_chan_offset, - ht_info->control_channel); - return; + return 0; } -void iwl4965_set_ht_add_station(struct iwl_priv *priv, u8 index, - struct ieee80211_ht_info *sta_ht_inf) +static u16 iwl4965_get_hcmd_size(u8 cmd_id, u16 len) { - __le32 sta_flags; - u8 mimo_ps_mode; - - if (!sta_ht_inf || !sta_ht_inf->ht_supported) - goto done; - - mimo_ps_mode = (sta_ht_inf->cap & IEEE80211_HT_CAP_MIMO_PS) >> 2; - - sta_flags = priv->stations[index].sta.station_flags; - - sta_flags &= ~(STA_FLG_RTS_MIMO_PROT_MSK | STA_FLG_MIMO_DIS_MSK); - - switch (mimo_ps_mode) { - case WLAN_HT_CAP_MIMO_PS_STATIC: - sta_flags |= STA_FLG_MIMO_DIS_MSK; - break; - case WLAN_HT_CAP_MIMO_PS_DYNAMIC: - sta_flags |= STA_FLG_RTS_MIMO_PROT_MSK; - break; - case WLAN_HT_CAP_MIMO_PS_DISABLED: - break; + switch (cmd_id) { + case REPLY_RXON: + return (u16) sizeof(struct iwl4965_rxon_cmd); default: - IWL_WARNING("Invalid MIMO PS mode %d", mimo_ps_mode); - break; + return len; } - - sta_flags |= cpu_to_le32( - (u32)sta_ht_inf->ampdu_factor << STA_FLG_MAX_AGG_SIZE_POS); - - sta_flags |= cpu_to_le32( - (u32)sta_ht_inf->ampdu_density << STA_FLG_AGG_MPDU_DENSITY_POS); - - if (iwl4965_is_fat_tx_allowed(priv, sta_ht_inf)) - sta_flags |= STA_FLG_FAT_EN_MSK; - else - sta_flags &= ~STA_FLG_FAT_EN_MSK; - - priv->stations[index].sta.station_flags = sta_flags; - done: - return; } -static void iwl4965_sta_modify_add_ba_tid(struct iwl_priv *priv, - int sta_id, int tid, u16 ssn) +static u16 iwl4965_build_addsta_hcmd(const struct iwl_addsta_cmd *cmd, u8 *data) { - unsigned long flags; - - spin_lock_irqsave(&priv->sta_lock, flags); - priv->stations[sta_id].sta.station_flags_msk = 0; - priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_ADDBA_TID_MSK; - priv->stations[sta_id].sta.add_immediate_ba_tid = (u8)tid; - priv->stations[sta_id].sta.add_immediate_ba_ssn = cpu_to_le16(ssn); - priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK; - spin_unlock_irqrestore(&priv->sta_lock, flags); + struct iwl4965_addsta_cmd *addsta = (struct iwl4965_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 = cmd->tid_disable_tx; + 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; + addsta->reserved1 = __constant_cpu_to_le16(0); + addsta->reserved2 = __constant_cpu_to_le32(0); - iwl4965_send_add_station(priv, &priv->stations[sta_id].sta, CMD_ASYNC); + return (u16)sizeof(struct iwl4965_addsta_cmd); } -static void iwl4965_sta_modify_del_ba_tid(struct iwl_priv *priv, - int sta_id, int tid) +static inline u32 iwl4965_get_scd_ssn(struct iwl4965_tx_resp *tx_resp) { - unsigned long flags; - - spin_lock_irqsave(&priv->sta_lock, flags); - priv->stations[sta_id].sta.station_flags_msk = 0; - priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_DELBA_TID_MSK; - priv->stations[sta_id].sta.remove_immediate_ba_tid = (u8)tid; - priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK; - spin_unlock_irqrestore(&priv->sta_lock, flags); - - iwl4965_send_add_station(priv, &priv->stations[sta_id].sta, CMD_ASYNC); + return le32_to_cpup(&tx_resp->u.status + tx_resp->frame_count) & MAX_SN; } -/* - * Find first available (lowest unused) Tx Queue, mark it "active". - * Called only when finding queue for aggregation. - * Should never return anything < 7, because they should already - * be in use as EDCA AC (0-3), Command (4), HCCA (5, 6). +/** + * iwl4965_tx_status_reply_tx - Handle Tx rspnse for frames in aggregation queue */ -static int iwl4965_txq_ctx_activate_free(struct iwl_priv *priv) -{ - int txq_id; - - for (txq_id = 0; txq_id < priv->hw_params.max_txq_num; txq_id++) - if (!test_and_set_bit(txq_id, &priv->txq_ctx_active_msk)) - return txq_id; - return -1; -} - -static int iwl4965_mac_ht_tx_agg_start(struct ieee80211_hw *hw, const u8 *da, - u16 tid, u16 *start_seq_num) +static int iwl4965_tx_status_reply_tx(struct iwl_priv *priv, + struct iwl_ht_agg *agg, + struct iwl4965_tx_resp *tx_resp, + int txq_id, u16 start_idx) { - struct iwl_priv *priv = hw->priv; - int sta_id; - int tx_fifo; - int txq_id; - int ssn = -1; - int ret = 0; - unsigned long flags; - struct iwl4965_tid_data *tid_data; - DECLARE_MAC_BUF(mac); - - if (likely(tid < ARRAY_SIZE(default_tid_to_tx_fifo))) - tx_fifo = default_tid_to_tx_fifo[tid]; - else - return -EINVAL; - - IWL_WARNING("%s on da = %s tid = %d\n", - __func__, print_mac(mac, da), tid); - - sta_id = iwl4965_hw_find_station(priv, da); - if (sta_id == IWL_INVALID_STATION) - return -ENXIO; - - if (priv->stations[sta_id].tid[tid].agg.state != IWL_AGG_OFF) { - IWL_ERROR("Start AGG when state is not IWL_AGG_OFF !\n"); - return -ENXIO; - } - - txq_id = iwl4965_txq_ctx_activate_free(priv); - if (txq_id == -1) - return -ENXIO; + u16 status; + struct agg_tx_status *frame_status = tx_resp->u.agg_status; + struct ieee80211_tx_info *info = NULL; + struct ieee80211_hdr *hdr = NULL; + u32 rate_n_flags = le32_to_cpu(tx_resp->rate_n_flags); + int i, sh, idx; + u16 seq; + if (agg->wait_for_ba) + IWL_DEBUG_TX_REPLY("got tx response w/o block-ack\n"); + + agg->frame_count = tx_resp->frame_count; + agg->start_idx = start_idx; + agg->rate_n_flags = rate_n_flags; + agg->bitmap = 0; + + /* # frames attempted by Tx command */ + if (agg->frame_count == 1) { + /* Only one frame was attempted; no block-ack will arrive */ + status = le16_to_cpu(frame_status[0].status); + idx = start_idx; + + /* FIXME: code repetition */ + IWL_DEBUG_TX_REPLY("FrameCnt = %d, StartIdx=%d idx=%d\n", + agg->frame_count, agg->start_idx, idx); + + info = IEEE80211_SKB_CB(priv->txq[txq_id].txb[idx].skb[0]); + info->status.retry_count = tx_resp->failure_frame; + info->flags &= ~IEEE80211_TX_CTL_AMPDU; + info->flags |= iwl_is_tx_success(status)? + IEEE80211_TX_STAT_ACK : 0; + iwl_hwrate_to_tx_control(priv, rate_n_flags, info); + /* FIXME: code repetition end */ + + IWL_DEBUG_TX_REPLY("1 Frame 0x%x failure :%d\n", + status & 0xff, tx_resp->failure_frame); + IWL_DEBUG_TX_REPLY("Rate Info rate_n_flags=%x\n", rate_n_flags); + + agg->wait_for_ba = 0; + } else { + /* Two or more frames were attempted; expect block-ack */ + u64 bitmap = 0; + int start = agg->start_idx; + + /* Construct bit-map of pending frames within Tx window */ + for (i = 0; i < agg->frame_count; i++) { + u16 sc; + status = le16_to_cpu(frame_status[i].status); + seq = le16_to_cpu(frame_status[i].sequence); + idx = SEQ_TO_INDEX(seq); + txq_id = SEQ_TO_QUEUE(seq); + + if (status & (AGG_TX_STATE_FEW_BYTES_MSK | + AGG_TX_STATE_ABORT_MSK)) + continue; + + IWL_DEBUG_TX_REPLY("FrameCnt = %d, txq_id=%d idx=%d\n", + agg->frame_count, txq_id, idx); + + hdr = iwl_tx_queue_get_hdr(priv, txq_id, idx); + + sc = le16_to_cpu(hdr->seq_ctrl); + if (idx != (SEQ_TO_SN(sc) & 0xff)) { + IWL_ERROR("BUG_ON idx doesn't match seq control" + " idx=%d, seq_idx=%d, seq=%d\n", + idx, SEQ_TO_SN(sc), + hdr->seq_ctrl); + return -1; + } - spin_lock_irqsave(&priv->sta_lock, flags); - tid_data = &priv->stations[sta_id].tid[tid]; - ssn = SEQ_TO_SN(tid_data->seq_number); - tid_data->agg.txq_id = txq_id; - spin_unlock_irqrestore(&priv->sta_lock, flags); + IWL_DEBUG_TX_REPLY("AGG Frame i=%d idx %d seq=%d\n", + i, idx, SEQ_TO_SN(sc)); + + sh = idx - start; + if (sh > 64) { + sh = (start - idx) + 0xff; + bitmap = bitmap << sh; + sh = 0; + start = idx; + } else if (sh < -64) + sh = 0xff - (start - idx); + else if (sh < 0) { + sh = start - idx; + start = idx; + bitmap = bitmap << sh; + sh = 0; + } + bitmap |= (1 << sh); + IWL_DEBUG_TX_REPLY("start=%d bitmap=0x%x\n", + start, (u32)(bitmap & 0xFFFFFFFF)); + } - *start_seq_num = ssn; - ret = iwl4965_tx_queue_agg_enable(priv, txq_id, tx_fifo, - sta_id, tid, ssn); - if (ret) - return ret; + agg->bitmap = bitmap; + agg->start_idx = start; + IWL_DEBUG_TX_REPLY("Frames %d start_idx=%d bitmap=0x%llx\n", + agg->frame_count, agg->start_idx, + (unsigned long long)agg->bitmap); - ret = 0; - if (tid_data->tfds_in_queue == 0) { - printk(KERN_ERR "HW queue is empty\n"); - tid_data->agg.state = IWL_AGG_ON; - ieee80211_start_tx_ba_cb_irqsafe(hw, da, tid); - } else { - IWL_DEBUG_HT("HW queue is NOT empty: %d packets in HW queue\n", - tid_data->tfds_in_queue); - tid_data->agg.state = IWL_EMPTYING_HW_QUEUE_ADDBA; + if (bitmap) + agg->wait_for_ba = 1; } - return ret; + return 0; } -static int iwl4965_mac_ht_tx_agg_stop(struct ieee80211_hw *hw, const u8 *da, - u16 tid) -{ - - struct iwl_priv *priv = hw->priv; - int tx_fifo_id, txq_id, sta_id, ssn = -1; - struct iwl4965_tid_data *tid_data; - int ret, write_ptr, read_ptr; - unsigned long flags; - DECLARE_MAC_BUF(mac); +/** + * iwl4965_rx_reply_tx - Handle standard (non-aggregation) Tx response + */ +static void iwl4965_rx_reply_tx(struct iwl_priv *priv, + struct iwl_rx_mem_buffer *rxb) +{ + struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; + u16 sequence = le16_to_cpu(pkt->hdr.sequence); + int txq_id = SEQ_TO_QUEUE(sequence); + int index = SEQ_TO_INDEX(sequence); + struct iwl_tx_queue *txq = &priv->txq[txq_id]; + struct ieee80211_tx_info *info; + struct iwl4965_tx_resp *tx_resp = (void *)&pkt->u.raw[0]; + u32 status = le32_to_cpu(tx_resp->u.status); + int tid = MAX_TID_COUNT, sta_id = IWL_INVALID_STATION; + __le16 fc; + struct ieee80211_hdr *hdr; + u8 *qc = NULL; - if (!da) { - IWL_ERROR("da = NULL\n"); - return -EINVAL; + if ((index >= txq->q.n_bd) || (iwl_queue_used(&txq->q, index) == 0)) { + IWL_ERROR("Read index for DMA queue txq_id (%d) index %d " + "is out of range [0-%d] %d %d\n", txq_id, + index, txq->q.n_bd, txq->q.write_ptr, + txq->q.read_ptr); + return; } - if (likely(tid < ARRAY_SIZE(default_tid_to_tx_fifo))) - tx_fifo_id = default_tid_to_tx_fifo[tid]; - else - return -EINVAL; - - sta_id = iwl4965_hw_find_station(priv, da); - - if (sta_id == IWL_INVALID_STATION) - return -ENXIO; - - if (priv->stations[sta_id].tid[tid].agg.state != IWL_AGG_ON) - IWL_WARNING("Stopping AGG while state not IWL_AGG_ON\n"); + info = IEEE80211_SKB_CB(txq->txb[txq->q.read_ptr].skb[0]); + memset(&info->status, 0, sizeof(info->status)); - tid_data = &priv->stations[sta_id].tid[tid]; - ssn = (tid_data->seq_number & IEEE80211_SCTL_SEQ) >> 4; - txq_id = tid_data->agg.txq_id; - write_ptr = priv->txq[txq_id].q.write_ptr; - read_ptr = priv->txq[txq_id].q.read_ptr; + hdr = iwl_tx_queue_get_hdr(priv, txq_id, index); + fc = hdr->frame_control; + if (ieee80211_is_data_qos(fc)) { + qc = ieee80211_get_qos_ctl(hdr); + tid = qc[0] & 0xf; + } - /* The queue is not empty */ - if (write_ptr != read_ptr) { - IWL_DEBUG_HT("Stopping a non empty AGG HW QUEUE\n"); - priv->stations[sta_id].tid[tid].agg.state = - IWL_EMPTYING_HW_QUEUE_DELBA; - return 0; + sta_id = iwl_get_ra_sta_id(priv, hdr); + if (txq->sched_retry && unlikely(sta_id == IWL_INVALID_STATION)) { + IWL_ERROR("Station not known\n"); + return; } - IWL_DEBUG_HT("HW queue empty\n");; - priv->stations[sta_id].tid[tid].agg.state = IWL_AGG_OFF; + if (txq->sched_retry) { + const u32 scd_ssn = iwl4965_get_scd_ssn(tx_resp); + struct iwl_ht_agg *agg = NULL; - spin_lock_irqsave(&priv->lock, flags); - ret = iwl4965_tx_queue_agg_disable(priv, txq_id, ssn, tx_fifo_id); - spin_unlock_irqrestore(&priv->lock, flags); + if (!qc) + return; - if (ret) - return ret; + agg = &priv->stations[sta_id].tid[tid].agg; - ieee80211_stop_tx_ba_cb_irqsafe(priv->hw, da, tid); + iwl4965_tx_status_reply_tx(priv, agg, tx_resp, txq_id, index); - IWL_DEBUG_INFO("iwl4965_mac_ht_tx_agg_stop on da=%s tid=%d\n", - print_mac(mac, da), tid); + /* check if BAR is needed */ + if ((tx_resp->frame_count == 1) && !iwl_is_tx_success(status)) + info->flags |= IEEE80211_TX_STAT_AMPDU_NO_BACK; - return 0; -} + if (txq->q.read_ptr != (scd_ssn & 0xff)) { + int freed, ampdu_q; + index = iwl_queue_dec_wrap(scd_ssn & 0xff, txq->q.n_bd); + IWL_DEBUG_TX_REPLY("Retry scheduler reclaim scd_ssn " + "%d index %d\n", scd_ssn , index); + freed = iwl_tx_queue_reclaim(priv, txq_id, index); + priv->stations[sta_id].tid[tid].tfds_in_queue -= freed; -int iwl4965_mac_ampdu_action(struct ieee80211_hw *hw, - enum ieee80211_ampdu_mlme_action action, - const u8 *addr, u16 tid, u16 *ssn) -{ - struct iwl_priv *priv = hw->priv; - int sta_id; - DECLARE_MAC_BUF(mac); - - IWL_DEBUG_HT("A-MPDU action on da=%s tid=%d ", - print_mac(mac, addr), tid); - sta_id = iwl4965_hw_find_station(priv, addr); - switch (action) { - case IEEE80211_AMPDU_RX_START: - IWL_DEBUG_HT("start Rx\n"); - iwl4965_sta_modify_add_ba_tid(priv, sta_id, tid, *ssn); - break; - case IEEE80211_AMPDU_RX_STOP: - IWL_DEBUG_HT("stop Rx\n"); - iwl4965_sta_modify_del_ba_tid(priv, sta_id, tid); - break; - case IEEE80211_AMPDU_TX_START: - IWL_DEBUG_HT("start Tx\n"); - return iwl4965_mac_ht_tx_agg_start(hw, addr, tid, ssn); - case IEEE80211_AMPDU_TX_STOP: - IWL_DEBUG_HT("stop Tx\n"); - return iwl4965_mac_ht_tx_agg_stop(hw, addr, tid); - default: - IWL_DEBUG_HT("unknown\n"); - return -EINVAL; - break; + if (iwl_queue_space(&txq->q) > txq->q.low_mark && + txq_id >= 0 && priv->mac80211_registered && + agg->state != IWL_EMPTYING_HW_QUEUE_DELBA) { + /* calculate mac80211 ampdu sw queue to wake */ + ampdu_q = txq_id - IWL49_FIRST_AMPDU_QUEUE + + priv->hw->queues; + if (agg->state == IWL_AGG_OFF) + ieee80211_wake_queue(priv->hw, txq_id); + else + ieee80211_wake_queue(priv->hw, ampdu_q); + } + iwl_txq_check_empty(priv, sta_id, tid, txq_id); + } + } else { + info->status.retry_count = tx_resp->failure_frame; + info->flags |= + iwl_is_tx_success(status) ? IEEE80211_TX_STAT_ACK : 0; + iwl_hwrate_to_tx_control(priv, + le32_to_cpu(tx_resp->rate_n_flags), + info); + + IWL_DEBUG_TX("Tx queue %d Status %s (0x%08x) rate_n_flags " + "0x%x retries %d\n", txq_id, + iwl_get_tx_fail_reason(status), + status, le32_to_cpu(tx_resp->rate_n_flags), + tx_resp->failure_frame); + + IWL_DEBUG_TX_REPLY("Tx queue reclaim %d\n", index); + + if (index != -1) { + int freed = iwl_tx_queue_reclaim(priv, txq_id, index); + if (tid != MAX_TID_COUNT) + priv->stations[sta_id].tid[tid].tfds_in_queue -= freed; + if (iwl_queue_space(&txq->q) > txq->q.low_mark && + (txq_id >= 0) && priv->mac80211_registered) + ieee80211_wake_queue(priv->hw, txq_id); + if (tid != MAX_TID_COUNT) + iwl_txq_check_empty(priv, sta_id, tid, txq_id); + } } - return 0; + + if (iwl_check_bits(status, TX_ABORT_REQUIRED_MSK)) + IWL_ERROR("TODO: Implement Tx ABORT REQUIRED!!!\n"); } -#endif /* CONFIG_IWL4965_HT */ /* Set up 4965-specific Rx frame reply handlers */ -void iwl4965_hw_rx_handler_setup(struct iwl_priv *priv) +static void iwl4965_rx_handler_setup(struct iwl_priv *priv) { /* Legacy Rx frames */ - priv->rx_handlers[REPLY_RX] = iwl4965_rx_reply_rx; - - /* High-throughput (HT) Rx frames */ - priv->rx_handlers[REPLY_RX_PHY_CMD] = iwl4965_rx_reply_rx_phy; - priv->rx_handlers[REPLY_RX_MPDU_CMD] = iwl4965_rx_reply_rx; - - priv->rx_handlers[MISSED_BEACONS_NOTIFICATION] = - iwl4965_rx_missed_beacon_notif; - -#ifdef CONFIG_IWL4965_HT - priv->rx_handlers[REPLY_COMPRESSED_BA] = iwl4965_rx_reply_compressed_ba; -#endif /* CONFIG_IWL4965_HT */ + priv->rx_handlers[REPLY_RX] = iwl_rx_reply_rx; + /* Tx response */ + priv->rx_handlers[REPLY_TX] = iwl4965_rx_reply_tx; } -void iwl4965_hw_setup_deferred_work(struct iwl_priv *priv) +static void iwl4965_setup_deferred_work(struct iwl_priv *priv) { INIT_WORK(&priv->txpower_work, iwl4965_bg_txpower_work); -#ifdef CONFIG_IWL4965_SENSITIVITY - INIT_WORK(&priv->sensitivity_work, iwl4965_bg_sensitivity_work); -#endif - init_timer(&priv->statistics_periodic); - priv->statistics_periodic.data = (unsigned long)priv; - priv->statistics_periodic.function = iwl4965_bg_statistics_periodic; } -void iwl4965_hw_cancel_deferred_work(struct iwl_priv *priv) +static void iwl4965_cancel_deferred_work(struct iwl_priv *priv) { - del_timer_sync(&priv->statistics_periodic); - - cancel_delayed_work(&priv->init_alive_start); + cancel_work_sync(&priv->txpower_work); } @@ -4955,23 +2394,56 @@ static struct iwl_hcmd_ops iwl4965_hcmd = { }; static struct iwl_hcmd_utils_ops iwl4965_hcmd_utils = { - .enqueue_hcmd = iwl4965_enqueue_hcmd, + .get_hcmd_size = iwl4965_get_hcmd_size, + .build_addsta_hcmd = iwl4965_build_addsta_hcmd, + .chain_noise_reset = iwl4965_chain_noise_reset, + .gain_computation = iwl4965_gain_computation, + .rts_tx_cmd_flag = iwl4965_rts_tx_cmd_flag, }; static struct iwl_lib_ops iwl4965_lib = { - .init_drv = iwl4965_init_drv, .set_hw_params = iwl4965_hw_set_hw_params, + .alloc_shared_mem = iwl4965_alloc_shared_mem, + .free_shared_mem = iwl4965_free_shared_mem, + .shared_mem_rx_idx = iwl4965_shared_mem_rx_idx, .txq_update_byte_cnt_tbl = iwl4965_txq_update_byte_cnt_tbl, - .hw_nic_init = iwl4965_hw_nic_init, + .txq_set_sched = iwl4965_txq_set_sched, + .txq_agg_enable = iwl4965_txq_agg_enable, + .txq_agg_disable = iwl4965_txq_agg_disable, + .rx_handler_setup = iwl4965_rx_handler_setup, + .setup_deferred_work = iwl4965_setup_deferred_work, + .cancel_deferred_work = iwl4965_cancel_deferred_work, .is_valid_rtc_data_addr = iwl4965_hw_valid_rtc_data_addr, .alive_notify = iwl4965_alive_notify, + .init_alive_start = iwl4965_init_alive_start, .load_ucode = iwl4965_load_bsm, + .apm_ops = { + .init = iwl4965_apm_init, + .reset = iwl4965_apm_reset, + .stop = iwl4965_apm_stop, + .config = iwl4965_nic_config, + .set_pwr_src = iwl4965_set_pwr_src, + }, .eeprom_ops = { + .regulatory_bands = { + EEPROM_REGULATORY_BAND_1_CHANNELS, + EEPROM_REGULATORY_BAND_2_CHANNELS, + EEPROM_REGULATORY_BAND_3_CHANNELS, + EEPROM_REGULATORY_BAND_4_CHANNELS, + EEPROM_REGULATORY_BAND_5_CHANNELS, + EEPROM_4965_REGULATORY_BAND_24_FAT_CHANNELS, + EEPROM_4965_REGULATORY_BAND_52_FAT_CHANNELS + }, .verify_signature = iwlcore_eeprom_verify_signature, .acquire_semaphore = iwlcore_eeprom_acquire_semaphore, .release_semaphore = iwlcore_eeprom_release_semaphore, + .check_version = iwl4965_eeprom_check_version, + .query_addr = iwlcore_eeprom_query_addr, }, - .radio_kill_sw = iwl4965_radio_kill_sw, + .set_power = iwl4965_set_power, + .send_tx_power = iwl4965_send_tx_power, + .update_chain_flags = iwl4965_update_chain_flags, + .temperature = iwl4965_temperature_calib, }; static struct iwl_ops iwl4965_ops = { @@ -4984,10 +2456,14 @@ struct iwl_cfg iwl4965_agn_cfg = { .name = "4965AGN", .fw_name = "iwlwifi-4965" IWL4965_UCODE_API ".ucode", .sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N, + .eeprom_size = IWL4965_EEPROM_IMG_SIZE, .ops = &iwl4965_ops, .mod_params = &iwl4965_mod_params, }; +/* Module firmware */ +MODULE_FIRMWARE("iwlwifi-4965" IWL4965_UCODE_API ".ucode"); + 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); @@ -5002,10 +2478,14 @@ MODULE_PARM_DESC(disable_hw_scan, "disable hardware scanning (default 0)"); module_param_named(queues_num, iwl4965_mod_params.num_of_queues, int, 0444); MODULE_PARM_DESC(queues_num, "number of hw queues."); - /* QoS */ module_param_named(qos_enable, iwl4965_mod_params.enable_qos, int, 0444); MODULE_PARM_DESC(qos_enable, "enable all QoS functionality"); +/* 11n */ +module_param_named(11n_disable, iwl4965_mod_params.disable_11n, int, 0444); +MODULE_PARM_DESC(11n_disable, "disable 11n functionality"); module_param_named(amsdu_size_8K, iwl4965_mod_params.amsdu_size_8K, int, 0444); MODULE_PARM_DESC(amsdu_size_8K, "enable 8K amsdu size"); +module_param_named(fw_restart4965, iwl4965_mod_params.restart_fw, int, 0444); +MODULE_PARM_DESC(fw_restart4965, "restart firmware in case of error"); diff --git a/drivers/net/wireless/iwlwifi/iwl-5000-hw.h b/drivers/net/wireless/iwlwifi/iwl-5000-hw.h new file mode 100644 index 000000000000..17d4f31c5934 --- /dev/null +++ b/drivers/net/wireless/iwlwifi/iwl-5000-hw.h @@ -0,0 +1,134 @@ +/****************************************************************************** + * + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * Copyright(c) 2007 - 2008 Intel Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, + * USA + * + * The full GNU General Public License is included in this distribution + * in the file called LICENSE.GPL. + * + * Contact Information: + * James P. Ketrenos <ipw2100-admin@linux.intel.com> + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + * + * BSD LICENSE + * + * Copyright(c) 2005 - 2008 Intel Corporation. All rights reserved. + * 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 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. + * + *****************************************************************************/ +/* + * Please use this file (iwl-5000-hw.h) only for hardware-related definitions. + * Use iwl-5000-commands.h for uCode API definitions. + */ + +#ifndef __iwl_5000_hw_h__ +#define __iwl_5000_hw_h__ + +#define IWL50_RTC_INST_UPPER_BOUND (0x020000) +#define IWL50_RTC_DATA_UPPER_BOUND (0x80C000) +#define IWL50_RTC_INST_SIZE (IWL50_RTC_INST_UPPER_BOUND - RTC_INST_LOWER_BOUND) +#define IWL50_RTC_DATA_SIZE (IWL50_RTC_DATA_UPPER_BOUND - RTC_DATA_LOWER_BOUND) + +/* EERPROM */ +#define IWL_5000_EEPROM_IMG_SIZE 2048 + + +#define IWL50_MAX_WIN_SIZE 64 +#define IWL50_QUEUE_SIZE 256 +#define IWL50_CMD_FIFO_NUM 7 +#define IWL50_NUM_QUEUES 20 +#define IWL50_NUM_AMPDU_QUEUES 10 +#define IWL50_FIRST_AMPDU_QUEUE 10 + +#define IWL_sta_id_POS 12 +#define IWL_sta_id_LEN 4 +#define IWL_sta_id_SYM val + +/* Fixed (non-configurable) rx data from phy */ + +/* Base physical address of iwl5000_shared is provided to SCD_DRAM_BASE_ADDR + * and &iwl5000_shared.val0 is provided to FH_RSCSR_CHNL0_STTS_WPTR_REG */ +struct iwl5000_sched_queue_byte_cnt_tbl { + struct iwl4965_queue_byte_cnt_entry tfd_offset[IWL50_QUEUE_SIZE + + IWL50_MAX_WIN_SIZE]; +} __attribute__ ((packed)); + +struct iwl5000_shared { + struct iwl5000_sched_queue_byte_cnt_tbl + queues_byte_cnt_tbls[IWL50_NUM_QUEUES]; + __le32 rb_closed; + + /* __le32 rb_closed_stts_rb_num:12; */ +#define IWL_rb_closed_stts_rb_num_POS 0 +#define IWL_rb_closed_stts_rb_num_LEN 12 +#define IWL_rb_closed_stts_rb_num_SYM rb_closed + /* __le32 rsrv1:4; */ + /* __le32 rb_closed_stts_rx_frame_num:12; */ +#define IWL_rb_closed_stts_rx_frame_num_POS 16 +#define IWL_rb_closed_stts_rx_frame_num_LEN 12 +#define IWL_rb_closed_stts_rx_frame_num_SYM rb_closed + /* __le32 rsrv2:4; */ + + __le32 frm_finished; + /* __le32 frame_finished_stts_rb_num:12; */ +#define IWL_frame_finished_stts_rb_num_POS 0 +#define IWL_frame_finished_stts_rb_num_LEN 12 +#define IWL_frame_finished_stts_rb_num_SYM frm_finished + /* __le32 rsrv3:4; */ + /* __le32 frame_finished_stts_rx_frame_num:12; */ +#define IWL_frame_finished_stts_rx_frame_num_POS 16 +#define IWL_frame_finished_stts_rx_frame_num_LEN 12 +#define IWL_frame_finished_stts_rx_frame_num_SYM frm_finished + /* __le32 rsrv4:4; */ + + __le32 padding1; /* so that allocation will be aligned to 16B */ + __le32 padding2; +} __attribute__ ((packed)); + + +#endif /* __iwl_5000_hw_h__ */ + diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c new file mode 100644 index 000000000000..878d6193b232 --- /dev/null +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -0,0 +1,1580 @@ +/****************************************************************************** + * + * Copyright(c) 2007-2008 Intel Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + * + *****************************************************************************/ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/version.h> +#include <linux/init.h> +#include <linux/pci.h> +#include <linux/dma-mapping.h> +#include <linux/delay.h> +#include <linux/skbuff.h> +#include <linux/netdevice.h> +#include <linux/wireless.h> +#include <net/mac80211.h> +#include <linux/etherdevice.h> +#include <asm/unaligned.h> + +#include "iwl-eeprom.h" +#include "iwl-dev.h" +#include "iwl-core.h" +#include "iwl-io.h" +#include "iwl-sta.h" +#include "iwl-helpers.h" +#include "iwl-5000-hw.h" + +#define IWL5000_UCODE_API "-1" + +static const u16 iwl5000_default_queue_to_tx_fifo[] = { + IWL_TX_FIFO_AC3, + IWL_TX_FIFO_AC2, + IWL_TX_FIFO_AC1, + IWL_TX_FIFO_AC0, + IWL50_CMD_FIFO_NUM, + IWL_TX_FIFO_HCCA_1, + IWL_TX_FIFO_HCCA_2 +}; + +/* FIXME: same implementation as 4965 */ +static int iwl5000_apm_stop_master(struct iwl_priv *priv) +{ + int ret = 0; + unsigned long flags; + + spin_lock_irqsave(&priv->lock, flags); + + /* set stop master bit */ + iwl_set_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_STOP_MASTER); + + ret = iwl_poll_bit(priv, CSR_RESET, + CSR_RESET_REG_FLAG_MASTER_DISABLED, + CSR_RESET_REG_FLAG_MASTER_DISABLED, 100); + if (ret < 0) + goto out; + +out: + spin_unlock_irqrestore(&priv->lock, flags); + IWL_DEBUG_INFO("stop master\n"); + + return ret; +} + + +static int iwl5000_apm_init(struct iwl_priv *priv) +{ + int ret = 0; + + iwl_set_bit(priv, CSR_GIO_CHICKEN_BITS, + CSR_GIO_CHICKEN_BITS_REG_BIT_DIS_L0S_EXIT_TIMER); + + /* disable L0s without affecting L1 :don't wait for ICH L0s bug W/A) */ + iwl_set_bit(priv, CSR_GIO_CHICKEN_BITS, + CSR_GIO_CHICKEN_BITS_REG_BIT_L1A_NO_L0S_RX); + + iwl_set_bit(priv, CSR_ANA_PLL_CFG, CSR50_ANA_PLL_CFG_VAL); + + /* set "initialization complete" bit to move adapter + * D0U* --> D0A* state */ + iwl_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE); + + /* wait for clock stabilization */ + ret = iwl_poll_bit(priv, CSR_GP_CNTRL, + CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, + CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000); + if (ret < 0) { + IWL_DEBUG_INFO("Failed to init the card\n"); + 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); + + udelay(20); + + /* disable L1-Active */ + iwl_set_bits_prph(priv, APMG_PCIDEV_STT_REG, + APMG_PCIDEV_STT_VAL_L1_ACT_DIS); + + iwl_release_nic_access(priv); + + return ret; +} + +/* FIXME: this is indentical to 4965 */ +static void iwl5000_apm_stop(struct iwl_priv *priv) +{ + 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); + + iwl_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE); + + spin_unlock_irqrestore(&priv->lock, flags); +} + + +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); + + + /* FIXME: put here L1A -L0S w/a */ + + iwl_set_bit(priv, CSR_ANA_PLL_CFG, CSR50_ANA_PLL_CFG_VAL); + + /* set "initialization complete" bit to move adapter + * D0U* --> D0A* state */ + iwl_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE); + + /* wait for clock stabilization */ + ret = iwl_poll_bit(priv, CSR_GP_CNTRL, + CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, + CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000); + if (ret < 0) { + IWL_DEBUG_INFO("Failed to init the card\n"); + 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); + + udelay(20); + + /* 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; +} + + +static void iwl5000_nic_config(struct iwl_priv *priv) +{ + unsigned long flags; + u16 radio_cfg; + u8 val_link; + + spin_lock_irqsave(&priv->lock, flags); + + pci_read_config_byte(priv->pci_dev, PCI_LINK_CTRL, &val_link); + + /* L1 is enabled by BIOS */ + if ((val_link & PCI_LINK_VAL_L1_EN) == PCI_LINK_VAL_L1_EN) + /* diable L0S disabled L1A enabled */ + iwl_set_bit(priv, CSR_GIO_REG, CSR_GIO_REG_VAL_L0S_ENABLED); + else + /* L0S enabled L1A disabled */ + iwl_clear_bit(priv, CSR_GIO_REG, CSR_GIO_REG_VAL_L0S_ENABLED); + + radio_cfg = iwl_eeprom_query16(priv, EEPROM_RADIO_CONFIG); + + /* write radio config values to register */ + if (EEPROM_RF_CFG_TYPE_MSK(radio_cfg) < EEPROM_5000_RF_CFG_TYPE_MAX) + iwl_set_bit(priv, CSR_HW_IF_CONFIG_REG, + EEPROM_RF_CFG_TYPE_MSK(radio_cfg) | + EEPROM_RF_CFG_STEP_MSK(radio_cfg) | + EEPROM_RF_CFG_DASH_MSK(radio_cfg)); + + /* set CSR_HW_CONFIG_REG for uCode use */ + iwl_set_bit(priv, CSR_HW_IF_CONFIG_REG, + CSR_HW_IF_CONFIG_REG_BIT_RADIO_SI | + CSR_HW_IF_CONFIG_REG_BIT_MAC_SI); + + spin_unlock_irqrestore(&priv->lock, flags); +} + + + +/* + * EEPROM + */ +static u32 eeprom_indirect_address(const struct iwl_priv *priv, u32 address) +{ + u16 offset = 0; + + if ((address & INDIRECT_ADDRESS) == 0) + return address; + + switch (address & INDIRECT_TYPE_MSK) { + case INDIRECT_HOST: + offset = iwl_eeprom_query16(priv, EEPROM_5000_LINK_HOST); + break; + case INDIRECT_GENERAL: + offset = iwl_eeprom_query16(priv, EEPROM_5000_LINK_GENERAL); + break; + case INDIRECT_REGULATORY: + offset = iwl_eeprom_query16(priv, EEPROM_5000_LINK_REGULATORY); + break; + case INDIRECT_CALIBRATION: + offset = iwl_eeprom_query16(priv, EEPROM_5000_LINK_CALIBRATION); + break; + case INDIRECT_PROCESS_ADJST: + offset = iwl_eeprom_query16(priv, EEPROM_5000_LINK_PROCESS_ADJST); + break; + case INDIRECT_OTHERS: + offset = iwl_eeprom_query16(priv, EEPROM_5000_LINK_OTHERS); + break; + default: + IWL_ERROR("illegal indirect type: 0x%X\n", + address & INDIRECT_TYPE_MSK); + break; + } + + /* translate the offset from words to byte */ + return (address & ADDRESS_MSK) + (offset << 1); +} + +static int iwl5000_eeprom_check_version(struct iwl_priv *priv) +{ + u16 eeprom_ver; + struct iwl_eeprom_calib_hdr { + u8 version; + u8 pa_type; + u16 voltage; + } *hdr; + + eeprom_ver = iwl_eeprom_query16(priv, EEPROM_VERSION); + + hdr = (struct iwl_eeprom_calib_hdr *)iwl_eeprom_query_addr(priv, + EEPROM_5000_CALIB_ALL); + + if (eeprom_ver < EEPROM_5000_EEPROM_VERSION || + hdr->version < EEPROM_5000_TX_POWER_VERSION) + goto err; + + return 0; +err: + IWL_ERROR("Unsuported EEPROM VER=0x%x < 0x%x CALIB=0x%x < 0x%x\n", + eeprom_ver, EEPROM_5000_EEPROM_VERSION, + hdr->version, EEPROM_5000_TX_POWER_VERSION); + return -EINVAL; + +} + +static void iwl5000_gain_computation(struct iwl_priv *priv, + u32 average_noise[NUM_RX_CHAINS], + u16 min_average_noise_antenna_i, + u32 min_average_noise) +{ + int i; + s32 delta_g; + struct iwl_chain_noise_data *data = &priv->chain_noise_data; + + /* Find Gain Code for the antennas B and C */ + for (i = 1; i < NUM_RX_CHAINS; i++) { + if ((data->disconn_array[i])) { + data->delta_gain_code[i] = 0; + continue; + } + delta_g = (1000 * ((s32)average_noise[0] - + (s32)average_noise[i])) / 1500; + /* bound gain by 2 bits value max, 3rd bit is sign */ + data->delta_gain_code[i] = + min(abs(delta_g), CHAIN_NOISE_MAX_DELTA_GAIN_CODE); + + if (delta_g < 0) + /* set negative sign */ + data->delta_gain_code[i] |= (1 << 2); + } + + IWL_DEBUG_CALIB("Delta gains: ANT_B = %d ANT_C = %d\n", + data->delta_gain_code[1], data->delta_gain_code[2]); + + if (!data->radio_write) { + struct iwl5000_calibration_chain_noise_gain_cmd cmd; + memset(&cmd, 0, sizeof(cmd)); + + cmd.op_code = IWL5000_PHY_CALIBRATE_CHAIN_NOISE_GAIN_CMD; + cmd.delta_gain_1 = data->delta_gain_code[1]; + cmd.delta_gain_2 = data->delta_gain_code[2]; + iwl_send_cmd_pdu_async(priv, REPLY_PHY_CALIBRATION_CMD, + sizeof(cmd), &cmd, NULL); + + data->radio_write = 1; + data->state = IWL_CHAIN_NOISE_CALIBRATED; + } + + data->chain_noise_a = 0; + data->chain_noise_b = 0; + data->chain_noise_c = 0; + data->chain_signal_a = 0; + data->chain_signal_b = 0; + data->chain_signal_c = 0; + data->beacon_count = 0; +} + +static void iwl5000_chain_noise_reset(struct iwl_priv *priv) +{ + struct iwl_chain_noise_data *data = &priv->chain_noise_data; + + if ((data->state == IWL_CHAIN_NOISE_ALIVE) && iwl_is_associated(priv)) { + struct iwl5000_calibration_chain_noise_reset_cmd cmd; + + memset(&cmd, 0, sizeof(cmd)); + cmd.op_code = IWL5000_PHY_CALIBRATE_CHAIN_NOISE_RESET_CMD; + if (iwl_send_cmd_pdu(priv, REPLY_PHY_CALIBRATION_CMD, + sizeof(cmd), &cmd)) + IWL_ERROR("Could not send REPLY_PHY_CALIBRATION_CMD\n"); + data->state = IWL_CHAIN_NOISE_ACCUMULATE; + IWL_DEBUG_CALIB("Run chain_noise_calibrate\n"); + } +} + +static void iwl5000_rts_tx_cmd_flag(struct ieee80211_tx_info *info, + __le32 *tx_flags) +{ + if ((info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) || + (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT)) + *tx_flags |= TX_CMD_FLG_RTS_CTS_MSK; + else + *tx_flags &= ~TX_CMD_FLG_RTS_CTS_MSK; +} + +static struct iwl_sensitivity_ranges iwl5000_sensitivity = { + .min_nrg_cck = 95, + .max_nrg_cck = 0, + .auto_corr_min_ofdm = 90, + .auto_corr_min_ofdm_mrc = 170, + .auto_corr_min_ofdm_x1 = 120, + .auto_corr_min_ofdm_mrc_x1 = 240, + + .auto_corr_max_ofdm = 120, + .auto_corr_max_ofdm_mrc = 210, + .auto_corr_max_ofdm_x1 = 155, + .auto_corr_max_ofdm_mrc_x1 = 290, + + .auto_corr_min_cck = 125, + .auto_corr_max_cck = 200, + .auto_corr_min_cck_mrc = 170, + .auto_corr_max_cck_mrc = 400, + .nrg_th_cck = 95, + .nrg_th_ofdm = 95, +}; + +static const u8 *iwl5000_eeprom_query_addr(const struct iwl_priv *priv, + size_t offset) +{ + u32 address = eeprom_indirect_address(priv, offset); + BUG_ON(address >= priv->cfg->eeprom_size); + return &priv->eeprom[address]; +} + +/* + * Calibration + */ +static int iwl5000_send_Xtal_calib(struct iwl_priv *priv) +{ + u16 *xtal_calib = (u16 *)iwl_eeprom_query_addr(priv, EEPROM_5000_XTAL); + + struct iwl5000_calibration cal_cmd = { + .op_code = IWL5000_PHY_CALIBRATE_CRYSTAL_FRQ_CMD, + .data = { + (u8)xtal_calib[0], + (u8)xtal_calib[1], + } + }; + + return iwl_send_cmd_pdu(priv, REPLY_PHY_CALIBRATION_CMD, + sizeof(cal_cmd), &cal_cmd); +} + +static int iwl5000_send_calib_results(struct iwl_priv *priv) +{ + int ret = 0; + + struct iwl_host_cmd hcmd = { + .id = REPLY_PHY_CALIBRATION_CMD, + .meta.flags = CMD_SIZE_HUGE, + }; + + if (priv->calib_results.lo_res) { + hcmd.len = priv->calib_results.lo_res_len; + hcmd.data = priv->calib_results.lo_res; + ret = iwl_send_cmd_sync(priv, &hcmd); + + if (ret) + goto err; + } + + if (priv->calib_results.tx_iq_res) { + hcmd.len = priv->calib_results.tx_iq_res_len; + hcmd.data = priv->calib_results.tx_iq_res; + ret = iwl_send_cmd_sync(priv, &hcmd); + + if (ret) + goto err; + } + + if (priv->calib_results.tx_iq_perd_res) { + hcmd.len = priv->calib_results.tx_iq_perd_res_len; + hcmd.data = priv->calib_results.tx_iq_perd_res; + ret = iwl_send_cmd_sync(priv, &hcmd); + + if (ret) + goto err; + } + + return 0; +err: + IWL_ERROR("Error %d\n", ret); + return ret; +} + +static int iwl5000_send_calib_cfg(struct iwl_priv *priv) +{ + struct iwl5000_calib_cfg_cmd calib_cfg_cmd; + struct iwl_host_cmd cmd = { + .id = CALIBRATION_CFG_CMD, + .len = sizeof(struct iwl5000_calib_cfg_cmd), + .data = &calib_cfg_cmd, + }; + + memset(&calib_cfg_cmd, 0, sizeof(calib_cfg_cmd)); + calib_cfg_cmd.ucd_calib_cfg.once.is_enable = IWL_CALIB_INIT_CFG_ALL; + calib_cfg_cmd.ucd_calib_cfg.once.start = IWL_CALIB_INIT_CFG_ALL; + calib_cfg_cmd.ucd_calib_cfg.once.send_res = IWL_CALIB_INIT_CFG_ALL; + calib_cfg_cmd.ucd_calib_cfg.flags = IWL_CALIB_INIT_CFG_ALL; + + return iwl_send_cmd(priv, &cmd); +} + +static void iwl5000_rx_calib_result(struct iwl_priv *priv, + struct iwl_rx_mem_buffer *rxb) +{ + struct iwl_rx_packet *pkt = (void *)rxb->skb->data; + struct iwl5000_calib_hdr *hdr = (struct iwl5000_calib_hdr *)pkt->u.raw; + int len = le32_to_cpu(pkt->len) & FH_RSCSR_FRAME_SIZE_MSK; + + iwl_free_calib_results(priv); + + /* reduce the size of the length field itself */ + len -= 4; + + switch (hdr->op_code) { + case IWL5000_PHY_CALIBRATE_LO_CMD: + priv->calib_results.lo_res = kzalloc(len, GFP_ATOMIC); + priv->calib_results.lo_res_len = len; + memcpy(priv->calib_results.lo_res, pkt->u.raw, len); + break; + case IWL5000_PHY_CALIBRATE_TX_IQ_CMD: + priv->calib_results.tx_iq_res = kzalloc(len, GFP_ATOMIC); + priv->calib_results.tx_iq_res_len = len; + memcpy(priv->calib_results.tx_iq_res, pkt->u.raw, len); + break; + case IWL5000_PHY_CALIBRATE_TX_IQ_PERD_CMD: + priv->calib_results.tx_iq_perd_res = kzalloc(len, GFP_ATOMIC); + priv->calib_results.tx_iq_perd_res_len = len; + memcpy(priv->calib_results.tx_iq_perd_res, pkt->u.raw, len); + break; + default: + IWL_ERROR("Unknown calibration notification %d\n", + hdr->op_code); + return; + } +} + +static void iwl5000_rx_calib_complete(struct iwl_priv *priv, + struct iwl_rx_mem_buffer *rxb) +{ + IWL_DEBUG_INFO("Init. calibration is completed, restarting fw.\n"); + queue_work(priv->workqueue, &priv->restart); +} + +/* + * ucode + */ +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); + + iwl_write_direct32(priv, + FH_SRVC_CHNL_SRAM_ADDR_REG(FH_SRVC_CHNL), dst_addr); + + iwl_write_direct32(priv, + FH_TFDIB_CTRL0_REG(FH_SRVC_CHNL), + phy_addr & FH_MEM_TFDIB_DRAM_ADDR_LSB_MSK); + + /* FIME: write the MSB of the phy_addr in CTRL1 + * iwl_write_direct32(priv, + IWL_FH_TFDIB_CTRL1_REG(IWL_FH_SRVC_CHNL), + ((phy_addr & MSB_MSK) + << FH_MEM_TFDIB_REG1_ADDR_BITSHIFT) | byte_count); + */ + iwl_write_direct32(priv, + FH_TFDIB_CTRL1_REG(FH_SRVC_CHNL), byte_cnt); + iwl_write_direct32(priv, + FH_TCSR_CHNL_TX_BUF_STS_REG(FH_SRVC_CHNL), + 1 << FH_TCSR_CHNL_TX_BUF_STS_REG_POS_TB_NUM | + 1 << FH_TCSR_CHNL_TX_BUF_STS_REG_POS_TB_IDX | + FH_TCSR_CHNL_TX_BUF_STS_REG_VAL_TFDB_VALID); + + iwl_write_direct32(priv, + FH_TCSR_CHNL_TX_CONFIG_REG(FH_SRVC_CHNL), + FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE | + FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_DISABLE_VAL | + FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_HOST_ENDTFD); + + iwl_release_nic_access(priv); + spin_unlock_irqrestore(&priv->lock, flags); + return 0; +} + +static int iwl5000_load_given_ucode(struct iwl_priv *priv, + struct fw_desc *inst_image, + struct fw_desc *data_image) +{ + int ret = 0; + + ret = iwl5000_load_section( + priv, inst_image, RTC_INST_LOWER_BOUND); + if (ret) + return ret; + + IWL_DEBUG_INFO("INST uCode section being loaded...\n"); + ret = wait_event_interruptible_timeout(priv->wait_command_queue, + priv->ucode_write_complete, 5 * HZ); + if (ret == -ERESTARTSYS) { + IWL_ERROR("Could not load the INST uCode section due " + "to interrupt\n"); + return ret; + } + if (!ret) { + IWL_ERROR("Could not load the INST uCode section\n"); + return -ETIMEDOUT; + } + + priv->ucode_write_complete = 0; + + ret = iwl5000_load_section( + priv, data_image, RTC_DATA_LOWER_BOUND); + if (ret) + return ret; + + IWL_DEBUG_INFO("DATA uCode section being loaded...\n"); + + ret = wait_event_interruptible_timeout(priv->wait_command_queue, + priv->ucode_write_complete, 5 * HZ); + if (ret == -ERESTARTSYS) { + IWL_ERROR("Could not load the INST uCode section due " + "to interrupt\n"); + return ret; + } else if (!ret) { + IWL_ERROR("Could not load the DATA uCode section\n"); + return -ETIMEDOUT; + } else + ret = 0; + + priv->ucode_write_complete = 0; + + return ret; +} + +static int iwl5000_load_ucode(struct iwl_priv *priv) +{ + int ret = 0; + + /* check whether init ucode should be loaded, or rather runtime ucode */ + if (priv->ucode_init.len && (priv->ucode_type == UCODE_NONE)) { + IWL_DEBUG_INFO("Init ucode found. Loading init ucode...\n"); + ret = iwl5000_load_given_ucode(priv, + &priv->ucode_init, &priv->ucode_init_data); + if (!ret) { + IWL_DEBUG_INFO("Init ucode load complete.\n"); + priv->ucode_type = UCODE_INIT; + } + } else { + IWL_DEBUG_INFO("Init ucode not found, or already loaded. " + "Loading runtime ucode...\n"); + ret = iwl5000_load_given_ucode(priv, + &priv->ucode_code, &priv->ucode_data); + if (!ret) { + IWL_DEBUG_INFO("Runtime ucode load complete.\n"); + priv->ucode_type = UCODE_RT; + } + } + + return ret; +} + +static void iwl5000_init_alive_start(struct iwl_priv *priv) +{ + int ret = 0; + + /* Check alive response for "valid" sign from uCode */ + if (priv->card_alive_init.is_valid != UCODE_VALID_OK) { + /* We had an error bringing up the hardware, so take it + * all the way back down so we can try again */ + IWL_DEBUG_INFO("Initialize Alive failed.\n"); + goto restart; + } + + /* initialize uCode was loaded... verify inst image. + * This is a paranoid check, because we would not have gotten the + * "initialize" alive if code weren't properly loaded. */ + if (iwl_verify_ucode(priv)) { + /* Runtime instruction load was bad; + * take it all the way back down so we can try again */ + IWL_DEBUG_INFO("Bad \"initialize\" uCode load.\n"); + goto restart; + } + + iwl_clear_stations_table(priv); + ret = priv->cfg->ops->lib->alive_notify(priv); + if (ret) { + IWL_WARNING("Could not complete ALIVE transition: %d\n", ret); + goto restart; + } + + iwl5000_send_calib_cfg(priv); + return; + +restart: + /* real restart (first load init_ucode) */ + queue_work(priv->workqueue, &priv->restart); +} + +static void iwl5000_set_wr_ptrs(struct iwl_priv *priv, + int txq_id, u32 index) +{ + iwl_write_direct32(priv, HBUS_TARG_WRPTR, + (index & 0xff) | (txq_id << 8)); + iwl_write_prph(priv, IWL50_SCD_QUEUE_RDPTR(txq_id), index); +} + +static void iwl5000_tx_queue_set_status(struct iwl_priv *priv, + struct iwl_tx_queue *txq, + int tx_fifo_id, int scd_retry) +{ + int txq_id = txq->q.id; + int active = test_bit(txq_id, &priv->txq_ctx_active_msk)?1:0; + + iwl_write_prph(priv, IWL50_SCD_QUEUE_STATUS_BITS(txq_id), + (active << IWL50_SCD_QUEUE_STTS_REG_POS_ACTIVE) | + (tx_fifo_id << IWL50_SCD_QUEUE_STTS_REG_POS_TXF) | + (1 << IWL50_SCD_QUEUE_STTS_REG_POS_WSL) | + IWL50_SCD_QUEUE_STTS_REG_MSK); + + txq->sched_retry = scd_retry; + + IWL_DEBUG_INFO("%s %s Queue %d on AC %d\n", + active ? "Activate" : "Deactivate", + scd_retry ? "BA" : "AC", txq_id, tx_fifo_id); +} + +static int iwl5000_send_wimax_coex(struct iwl_priv *priv) +{ + struct iwl_wimax_coex_cmd coex_cmd; + + memset(&coex_cmd, 0, sizeof(coex_cmd)); + + return iwl_send_cmd_pdu(priv, COEX_PRIORITY_TABLE_CMD, + sizeof(coex_cmd), &coex_cmd); +} + +static int iwl5000_alive_notify(struct iwl_priv *priv) +{ + u32 a; + int i = 0; + unsigned long flags; + int ret; + + 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; + a += 4) + iwl_write_targ_mem(priv, a, 0); + for (; a < priv->scd_base_addr + IWL50_SCD_TRANSLATE_TBL_OFFSET; + a += 4) + iwl_write_targ_mem(priv, a, 0); + for (; a < sizeof(u16) * priv->hw_params.max_txq_num; a += 4) + iwl_write_targ_mem(priv, a, 0); + + iwl_write_prph(priv, IWL50_SCD_DRAM_BASE_ADDR, + (priv->shared_phys + + offsetof(struct iwl5000_shared, queues_byte_cnt_tbls)) >> 10); + iwl_write_prph(priv, IWL50_SCD_QUEUECHAIN_SEL, + IWL50_SCD_QUEUECHAIN_SEL_ALL( + priv->hw_params.max_txq_num)); + iwl_write_prph(priv, IWL50_SCD_AGGR_SEL, 0); + + /* initiate the queues */ + for (i = 0; i < priv->hw_params.max_txq_num; i++) { + iwl_write_prph(priv, IWL50_SCD_QUEUE_RDPTR(i), 0); + iwl_write_direct32(priv, HBUS_TARG_WRPTR, 0 | (i << 8)); + iwl_write_targ_mem(priv, priv->scd_base_addr + + IWL50_SCD_CONTEXT_QUEUE_OFFSET(i), 0); + iwl_write_targ_mem(priv, priv->scd_base_addr + + IWL50_SCD_CONTEXT_QUEUE_OFFSET(i) + + sizeof(u32), + ((SCD_WIN_SIZE << + IWL50_SCD_QUEUE_CTX_REG2_WIN_SIZE_POS) & + IWL50_SCD_QUEUE_CTX_REG2_WIN_SIZE_MSK) | + ((SCD_FRAME_LIMIT << + IWL50_SCD_QUEUE_CTX_REG2_FRAME_LIMIT_POS) & + IWL50_SCD_QUEUE_CTX_REG2_FRAME_LIMIT_MSK)); + } + + iwl_write_prph(priv, IWL50_SCD_INTERRUPT_MASK, + IWL_MASK(0, priv->hw_params.max_txq_num)); + + /* Activate all Tx DMA/FIFO channels */ + priv->cfg->ops->lib->txq_set_sched(priv, IWL_MASK(0, 7)); + + iwl5000_set_wr_ptrs(priv, IWL_CMD_QUEUE_NUM, 0); + /* map qos queues to fifos one-to-one */ + for (i = 0; i < ARRAY_SIZE(iwl5000_default_queue_to_tx_fifo); i++) { + int ac = iwl5000_default_queue_to_tx_fifo[i]; + iwl_txq_ctx_activate(priv, i); + iwl5000_tx_queue_set_status(priv, &priv->txq[i], ac, 0); + } + /* TODO - need to initialize those FIFOs inside the loop above, + * not only mark them as active */ + iwl_txq_ctx_activate(priv, 4); + iwl_txq_ctx_activate(priv, 7); + iwl_txq_ctx_activate(priv, 8); + iwl_txq_ctx_activate(priv, 9); + + iwl_release_nic_access(priv); + spin_unlock_irqrestore(&priv->lock, flags); + + + iwl5000_send_wimax_coex(priv); + + iwl5000_send_Xtal_calib(priv); + + if (priv->ucode_type == UCODE_RT) + iwl5000_send_calib_results(priv); + + return 0; +} + +static int iwl5000_hw_set_hw_params(struct iwl_priv *priv) +{ + if ((priv->cfg->mod_params->num_of_queues > IWL50_NUM_QUEUES) || + (priv->cfg->mod_params->num_of_queues < IWL_MIN_NUM_QUEUES)) { + IWL_ERROR("invalid queues_num, should be between %d and %d\n", + IWL_MIN_NUM_QUEUES, IWL50_NUM_QUEUES); + return -EINVAL; + } + + priv->hw_params.max_txq_num = priv->cfg->mod_params->num_of_queues; + priv->hw_params.first_ampdu_q = IWL50_FIRST_AMPDU_QUEUE; + priv->hw_params.max_stations = IWL5000_STATION_COUNT; + priv->hw_params.bcast_sta_id = IWL5000_BROADCAST_ID; + priv->hw_params.max_data_size = IWL50_RTC_DATA_SIZE; + priv->hw_params.max_inst_size = IWL50_RTC_INST_SIZE; + priv->hw_params.max_bsm_size = 0; + priv->hw_params.fat_channel = BIT(IEEE80211_BAND_2GHZ) | + BIT(IEEE80211_BAND_5GHZ); + priv->hw_params.sens = &iwl5000_sensitivity; + + switch (priv->hw_rev & CSR_HW_REV_TYPE_MSK) { + case CSR_HW_REV_TYPE_5100: + case CSR_HW_REV_TYPE_5150: + priv->hw_params.tx_chains_num = 1; + priv->hw_params.rx_chains_num = 2; + /* FIXME: move to ANT_A, ANT_B, ANT_C enum */ + priv->hw_params.valid_tx_ant = ANT_A; + priv->hw_params.valid_rx_ant = ANT_AB; + break; + case CSR_HW_REV_TYPE_5300: + case CSR_HW_REV_TYPE_5350: + priv->hw_params.tx_chains_num = 3; + priv->hw_params.rx_chains_num = 3; + priv->hw_params.valid_tx_ant = ANT_ABC; + priv->hw_params.valid_rx_ant = ANT_ABC; + break; + } + + switch (priv->hw_rev & CSR_HW_REV_TYPE_MSK) { + case CSR_HW_REV_TYPE_5100: + case CSR_HW_REV_TYPE_5300: + /* 5X00 wants in Celsius */ + priv->hw_params.ct_kill_threshold = CT_KILL_THRESHOLD; + break; + case CSR_HW_REV_TYPE_5150: + case CSR_HW_REV_TYPE_5350: + /* 5X50 wants in Kelvin */ + priv->hw_params.ct_kill_threshold = + CELSIUS_TO_KELVIN(CT_KILL_THRESHOLD); + break; + } + + return 0; +} + +static int iwl5000_alloc_shared_mem(struct iwl_priv *priv) +{ + priv->shared_virt = pci_alloc_consistent(priv->pci_dev, + sizeof(struct iwl5000_shared), + &priv->shared_phys); + if (!priv->shared_virt) + return -ENOMEM; + + memset(priv->shared_virt, 0, sizeof(struct iwl5000_shared)); + + priv->rb_closed_offset = offsetof(struct iwl5000_shared, rb_closed); + + return 0; +} + +static void iwl5000_free_shared_mem(struct iwl_priv *priv) +{ + if (priv->shared_virt) + pci_free_consistent(priv->pci_dev, + sizeof(struct iwl5000_shared), + priv->shared_virt, + priv->shared_phys); +} + +static int iwl5000_shared_mem_rx_idx(struct iwl_priv *priv) +{ + struct iwl5000_shared *s = priv->shared_virt; + return le32_to_cpu(s->rb_closed) & 0xFFF; +} + +/** + * iwl5000_txq_update_byte_cnt_tbl - Set up entry in Tx byte-count array + */ +static void iwl5000_txq_update_byte_cnt_tbl(struct iwl_priv *priv, + struct iwl_tx_queue *txq, + u16 byte_cnt) +{ + struct iwl5000_shared *shared_data = priv->shared_virt; + int txq_id = txq->q.id; + u8 sec_ctl = 0; + u8 sta = 0; + int len; + + len = byte_cnt + IWL_TX_CRC_SIZE + IWL_TX_DELIMITER_SIZE; + + if (txq_id != IWL_CMD_QUEUE_NUM) { + sta = txq->cmd[txq->q.write_ptr].cmd.tx.sta_id; + sec_ctl = txq->cmd[txq->q.write_ptr].cmd.tx.sec_ctl; + + switch (sec_ctl & TX_CMD_SEC_MSK) { + case TX_CMD_SEC_CCM: + len += CCMP_MIC_LEN; + break; + case TX_CMD_SEC_TKIP: + len += TKIP_ICV_LEN; + break; + case TX_CMD_SEC_WEP: + len += WEP_IV_LEN + WEP_ICV_LEN; + break; + } + } + + IWL_SET_BITS16(shared_data->queues_byte_cnt_tbls[txq_id]. + tfd_offset[txq->q.write_ptr], byte_cnt, len); + + IWL_SET_BITS16(shared_data->queues_byte_cnt_tbls[txq_id]. + tfd_offset[txq->q.write_ptr], sta_id, sta); + + if (txq->q.write_ptr < IWL50_MAX_WIN_SIZE) { + IWL_SET_BITS16(shared_data->queues_byte_cnt_tbls[txq_id]. + tfd_offset[IWL50_QUEUE_SIZE + txq->q.write_ptr], + byte_cnt, len); + IWL_SET_BITS16(shared_data->queues_byte_cnt_tbls[txq_id]. + tfd_offset[IWL50_QUEUE_SIZE + txq->q.write_ptr], + sta_id, sta); + } +} + +static void iwl5000_txq_inval_byte_cnt_tbl(struct iwl_priv *priv, + struct iwl_tx_queue *txq) +{ + int txq_id = txq->q.id; + struct iwl5000_shared *shared_data = priv->shared_virt; + u8 sta = 0; + + if (txq_id != IWL_CMD_QUEUE_NUM) + sta = txq->cmd[txq->q.read_ptr].cmd.tx.sta_id; + + shared_data->queues_byte_cnt_tbls[txq_id].tfd_offset[txq->q.read_ptr]. + val = cpu_to_le16(1 | (sta << 12)); + + if (txq->q.write_ptr < IWL50_MAX_WIN_SIZE) { + shared_data->queues_byte_cnt_tbls[txq_id]. + tfd_offset[IWL50_QUEUE_SIZE + txq->q.read_ptr]. + val = cpu_to_le16(1 | (sta << 12)); + } +} + +static int iwl5000_tx_queue_set_q2ratid(struct iwl_priv *priv, u16 ra_tid, + u16 txq_id) +{ + u32 tbl_dw_addr; + u32 tbl_dw; + u16 scd_q2ratid; + + scd_q2ratid = ra_tid & IWL_SCD_QUEUE_RA_TID_MAP_RATID_MSK; + + tbl_dw_addr = priv->scd_base_addr + + IWL50_SCD_TRANSLATE_TBL_OFFSET_QUEUE(txq_id); + + tbl_dw = iwl_read_targ_mem(priv, tbl_dw_addr); + + if (txq_id & 0x1) + tbl_dw = (scd_q2ratid << 16) | (tbl_dw & 0x0000FFFF); + else + tbl_dw = scd_q2ratid | (tbl_dw & 0xFFFF0000); + + iwl_write_targ_mem(priv, tbl_dw_addr, tbl_dw); + + return 0; +} +static void iwl5000_tx_queue_stop_scheduler(struct iwl_priv *priv, u16 txq_id) +{ + /* Simply stop the queue, but don't change any configuration; + * the SCD_ACT_EN bit is the write-enable mask for the ACTIVE bit. */ + iwl_write_prph(priv, + IWL50_SCD_QUEUE_STATUS_BITS(txq_id), + (0 << IWL50_SCD_QUEUE_STTS_REG_POS_ACTIVE)| + (1 << IWL50_SCD_QUEUE_STTS_REG_POS_SCD_ACT_EN)); +} + +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) || + (IWL50_FIRST_AMPDU_QUEUE + IWL50_NUM_AMPDU_QUEUES <= txq_id)) { + IWL_WARNING("queue number out of range: %d, must be %d to %d\n", + txq_id, IWL50_FIRST_AMPDU_QUEUE, + IWL50_FIRST_AMPDU_QUEUE + IWL50_NUM_AMPDU_QUEUES - 1); + return -EINVAL; + } + + ra_tid = BUILD_RAxTID(sta_id, tid); + + /* Modify device's station table to Tx this TID */ + iwl_sta_modify_enable_tid_tx(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); + + /* Map receiver-address / traffic-ID to this queue */ + iwl5000_tx_queue_set_q2ratid(priv, ra_tid, txq_id); + + /* Set this queue as a chain-building queue */ + iwl_set_bits_prph(priv, IWL50_SCD_QUEUECHAIN_SEL, (1<<txq_id)); + + /* enable aggregations for the queue */ + iwl_set_bits_prph(priv, IWL50_SCD_AGGR_SEL, (1<<txq_id)); + + /* Place first TFD at index corresponding to start sequence number. + * Assumes that ssn_idx is valid (!= 0xFFF) */ + priv->txq[txq_id].q.read_ptr = (ssn_idx & 0xff); + priv->txq[txq_id].q.write_ptr = (ssn_idx & 0xff); + iwl5000_set_wr_ptrs(priv, txq_id, ssn_idx); + + /* Set up Tx window size and frame limit for this queue */ + iwl_write_targ_mem(priv, priv->scd_base_addr + + IWL50_SCD_CONTEXT_QUEUE_OFFSET(txq_id) + + sizeof(u32), + ((SCD_WIN_SIZE << + IWL50_SCD_QUEUE_CTX_REG2_WIN_SIZE_POS) & + IWL50_SCD_QUEUE_CTX_REG2_WIN_SIZE_MSK) | + ((SCD_FRAME_LIMIT << + IWL50_SCD_QUEUE_CTX_REG2_FRAME_LIMIT_POS) & + IWL50_SCD_QUEUE_CTX_REG2_FRAME_LIMIT_MSK)); + + iwl_set_bits_prph(priv, IWL50_SCD_INTERRUPT_MASK, (1 << 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; +} + +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_WARNING("queue number out of range: %d, must be %d to %d\n", + txq_id, IWL50_FIRST_AMPDU_QUEUE, + IWL50_FIRST_AMPDU_QUEUE + IWL50_NUM_AMPDU_QUEUES - 1); + 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)); + + priv->txq[txq_id].q.read_ptr = (ssn_idx & 0xff); + priv->txq[txq_id].q.write_ptr = (ssn_idx & 0xff); + /* supposes that ssn_idx is valid (!= 0xFFF) */ + iwl5000_set_wr_ptrs(priv, txq_id, ssn_idx); + + iwl_clear_bits_prph(priv, IWL50_SCD_INTERRUPT_MASK, (1 << 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; +} + +static 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); + return size; +} + + +/* + * Activate/Deactivat Tx DMA/FIFO channels according tx fifos mask + * must be called under priv->lock and mac access + */ +static void iwl5000_txq_set_sched(struct iwl_priv *priv, u32 mask) +{ + iwl_write_prph(priv, IWL50_SCD_TXFACT, mask); +} + + +static inline u32 iwl5000_get_scd_ssn(struct iwl5000_tx_resp *tx_resp) +{ + return le32_to_cpup((__le32*)&tx_resp->status + + tx_resp->frame_count) & MAX_SN; +} + +static int iwl5000_tx_status_reply_tx(struct iwl_priv *priv, + struct iwl_ht_agg *agg, + struct iwl5000_tx_resp *tx_resp, + int txq_id, u16 start_idx) +{ + u16 status; + struct agg_tx_status *frame_status = &tx_resp->status; + struct ieee80211_tx_info *info = NULL; + struct ieee80211_hdr *hdr = NULL; + u32 rate_n_flags = le32_to_cpu(tx_resp->rate_n_flags); + int i, sh, idx; + u16 seq; + + if (agg->wait_for_ba) + IWL_DEBUG_TX_REPLY("got tx response w/o block-ack\n"); + + agg->frame_count = tx_resp->frame_count; + agg->start_idx = start_idx; + agg->rate_n_flags = rate_n_flags; + agg->bitmap = 0; + + /* # frames attempted by Tx command */ + if (agg->frame_count == 1) { + /* Only one frame was attempted; no block-ack will arrive */ + status = le16_to_cpu(frame_status[0].status); + idx = start_idx; + + /* FIXME: code repetition */ + IWL_DEBUG_TX_REPLY("FrameCnt = %d, StartIdx=%d idx=%d\n", + agg->frame_count, agg->start_idx, idx); + + info = IEEE80211_SKB_CB(priv->txq[txq_id].txb[idx].skb[0]); + info->status.retry_count = tx_resp->failure_frame; + info->flags &= ~IEEE80211_TX_CTL_AMPDU; + info->flags |= iwl_is_tx_success(status)? + IEEE80211_TX_STAT_ACK : 0; + iwl_hwrate_to_tx_control(priv, rate_n_flags, info); + + /* FIXME: code repetition end */ + + IWL_DEBUG_TX_REPLY("1 Frame 0x%x failure :%d\n", + status & 0xff, tx_resp->failure_frame); + IWL_DEBUG_TX_REPLY("Rate Info rate_n_flags=%x\n", rate_n_flags); + + agg->wait_for_ba = 0; + } else { + /* Two or more frames were attempted; expect block-ack */ + u64 bitmap = 0; + int start = agg->start_idx; + + /* Construct bit-map of pending frames within Tx window */ + for (i = 0; i < agg->frame_count; i++) { + u16 sc; + status = le16_to_cpu(frame_status[i].status); + seq = le16_to_cpu(frame_status[i].sequence); + idx = SEQ_TO_INDEX(seq); + txq_id = SEQ_TO_QUEUE(seq); + + if (status & (AGG_TX_STATE_FEW_BYTES_MSK | + AGG_TX_STATE_ABORT_MSK)) + continue; + + IWL_DEBUG_TX_REPLY("FrameCnt = %d, txq_id=%d idx=%d\n", + agg->frame_count, txq_id, idx); + + hdr = iwl_tx_queue_get_hdr(priv, txq_id, idx); + + sc = le16_to_cpu(hdr->seq_ctrl); + if (idx != (SEQ_TO_SN(sc) & 0xff)) { + IWL_ERROR("BUG_ON idx doesn't match seq control" + " idx=%d, seq_idx=%d, seq=%d\n", + idx, SEQ_TO_SN(sc), + hdr->seq_ctrl); + return -1; + } + + IWL_DEBUG_TX_REPLY("AGG Frame i=%d idx %d seq=%d\n", + i, idx, SEQ_TO_SN(sc)); + + sh = idx - start; + if (sh > 64) { + sh = (start - idx) + 0xff; + bitmap = bitmap << sh; + sh = 0; + start = idx; + } else if (sh < -64) + sh = 0xff - (start - idx); + else if (sh < 0) { + sh = start - idx; + start = idx; + bitmap = bitmap << sh; + sh = 0; + } + bitmap |= (1 << sh); + IWL_DEBUG_TX_REPLY("start=%d bitmap=0x%x\n", + start, (u32)(bitmap & 0xFFFFFFFF)); + } + + agg->bitmap = bitmap; + agg->start_idx = start; + IWL_DEBUG_TX_REPLY("Frames %d start_idx=%d bitmap=0x%llx\n", + agg->frame_count, agg->start_idx, + (unsigned long long)agg->bitmap); + + if (bitmap) + agg->wait_for_ba = 1; + } + return 0; +} + +static void iwl5000_rx_reply_tx(struct iwl_priv *priv, + struct iwl_rx_mem_buffer *rxb) +{ + struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; + u16 sequence = le16_to_cpu(pkt->hdr.sequence); + int txq_id = SEQ_TO_QUEUE(sequence); + int index = SEQ_TO_INDEX(sequence); + struct iwl_tx_queue *txq = &priv->txq[txq_id]; + struct ieee80211_tx_info *info; + struct iwl5000_tx_resp *tx_resp = (void *)&pkt->u.raw[0]; + u32 status = le16_to_cpu(tx_resp->status.status); + int tid = MAX_TID_COUNT, sta_id = IWL_INVALID_STATION; + struct ieee80211_hdr *hdr; + u8 *qc = NULL; + + if ((index >= txq->q.n_bd) || (iwl_queue_used(&txq->q, index) == 0)) { + IWL_ERROR("Read index for DMA queue txq_id (%d) index %d " + "is out of range [0-%d] %d %d\n", txq_id, + index, txq->q.n_bd, txq->q.write_ptr, + txq->q.read_ptr); + return; + } + + info = IEEE80211_SKB_CB(txq->txb[txq->q.read_ptr].skb[0]); + memset(&info->status, 0, sizeof(info->status)); + + hdr = iwl_tx_queue_get_hdr(priv, txq_id, index); + if (ieee80211_is_data_qos(hdr->frame_control)) { + qc = ieee80211_get_qos_ctl(hdr); + tid = qc[0] & 0xf; + } + + sta_id = iwl_get_ra_sta_id(priv, hdr); + if (txq->sched_retry && unlikely(sta_id == IWL_INVALID_STATION)) { + IWL_ERROR("Station not known\n"); + return; + } + + if (txq->sched_retry) { + const u32 scd_ssn = iwl5000_get_scd_ssn(tx_resp); + struct iwl_ht_agg *agg = NULL; + + if (!qc) + return; + + agg = &priv->stations[sta_id].tid[tid].agg; + + iwl5000_tx_status_reply_tx(priv, agg, tx_resp, txq_id, index); + + /* check if BAR is needed */ + if ((tx_resp->frame_count == 1) && !iwl_is_tx_success(status)) + info->flags |= IEEE80211_TX_STAT_AMPDU_NO_BACK; + + if (txq->q.read_ptr != (scd_ssn & 0xff)) { + int freed, ampdu_q; + index = iwl_queue_dec_wrap(scd_ssn & 0xff, txq->q.n_bd); + IWL_DEBUG_TX_REPLY("Retry scheduler reclaim scd_ssn " + "%d index %d\n", scd_ssn , index); + freed = iwl_tx_queue_reclaim(priv, txq_id, index); + priv->stations[sta_id].tid[tid].tfds_in_queue -= freed; + + if (iwl_queue_space(&txq->q) > txq->q.low_mark && + txq_id >= 0 && priv->mac80211_registered && + agg->state != IWL_EMPTYING_HW_QUEUE_DELBA) { + /* calculate mac80211 ampdu sw queue to wake */ + ampdu_q = txq_id - IWL50_FIRST_AMPDU_QUEUE + + priv->hw->queues; + if (agg->state == IWL_AGG_OFF) + ieee80211_wake_queue(priv->hw, txq_id); + else + ieee80211_wake_queue(priv->hw, ampdu_q); + } + iwl_txq_check_empty(priv, sta_id, tid, txq_id); + } + } else { + info->status.retry_count = tx_resp->failure_frame; + info->flags = + iwl_is_tx_success(status) ? IEEE80211_TX_STAT_ACK : 0; + iwl_hwrate_to_tx_control(priv, + le32_to_cpu(tx_resp->rate_n_flags), + info); + + IWL_DEBUG_TX("Tx queue %d Status %s (0x%08x) rate_n_flags " + "0x%x retries %d\n", txq_id, + iwl_get_tx_fail_reason(status), + status, le32_to_cpu(tx_resp->rate_n_flags), + tx_resp->failure_frame); + + IWL_DEBUG_TX_REPLY("Tx queue reclaim %d\n", index); + if (index != -1) { + int freed = iwl_tx_queue_reclaim(priv, txq_id, index); + if (tid != MAX_TID_COUNT) + priv->stations[sta_id].tid[tid].tfds_in_queue -= freed; + if (iwl_queue_space(&txq->q) > txq->q.low_mark && + (txq_id >= 0) && priv->mac80211_registered) + ieee80211_wake_queue(priv->hw, txq_id); + if (tid != MAX_TID_COUNT) + iwl_txq_check_empty(priv, sta_id, tid, txq_id); + } + } + + if (iwl_check_bits(status, TX_ABORT_REQUIRED_MSK)) + IWL_ERROR("TODO: Implement Tx ABORT REQUIRED!!!\n"); +} + +/* Currently 5000 is the supperset of everything */ +static u16 iwl5000_get_hcmd_size(u8 cmd_id, u16 len) +{ + return len; +} + +static void iwl5000_setup_deferred_work(struct iwl_priv *priv) +{ + /* in 5000 the tx power calibration is done in uCode */ + priv->disable_tx_power_cal = 1; +} + +static void iwl5000_rx_handler_setup(struct iwl_priv *priv) +{ + /* init calibration handlers */ + priv->rx_handlers[CALIBRATION_RES_NOTIFICATION] = + iwl5000_rx_calib_result; + priv->rx_handlers[CALIBRATION_COMPLETE_NOTIFICATION] = + iwl5000_rx_calib_complete; + priv->rx_handlers[REPLY_TX] = iwl5000_rx_reply_tx; +} + + +static int iwl5000_hw_valid_rtc_data_addr(u32 addr) +{ + return (addr >= RTC_DATA_LOWER_BOUND) && + (addr < IWL50_RTC_DATA_UPPER_BOUND); +} + +static int iwl5000_send_rxon_assoc(struct iwl_priv *priv) +{ + int ret = 0; + struct iwl5000_rxon_assoc_cmd 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_ht_single_stream_basic_rates == + rxon2->ofdm_ht_single_stream_basic_rates) && + (rxon1->ofdm_ht_dual_stream_basic_rates == + rxon2->ofdm_ht_dual_stream_basic_rates) && + (rxon1->ofdm_ht_triple_stream_basic_rates == + rxon2->ofdm_ht_triple_stream_basic_rates) && + (rxon1->acquisition_data == rxon2->acquisition_data) && + (rxon1->rx_chain == rxon2->rx_chain) && + (rxon1->ofdm_basic_rates == rxon2->ofdm_basic_rates)) { + IWL_DEBUG_INFO("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.reserved1 = 0; + rxon_assoc.reserved2 = 0; + rxon_assoc.reserved3 = 0; + rxon_assoc.ofdm_ht_single_stream_basic_rates = + priv->staging_rxon.ofdm_ht_single_stream_basic_rates; + rxon_assoc.ofdm_ht_dual_stream_basic_rates = + priv->staging_rxon.ofdm_ht_dual_stream_basic_rates; + rxon_assoc.rx_chain_select_flags = priv->staging_rxon.rx_chain; + rxon_assoc.ofdm_ht_triple_stream_basic_rates = + priv->staging_rxon.ofdm_ht_triple_stream_basic_rates; + rxon_assoc.acquisition_data = priv->staging_rxon.acquisition_data; + + ret = iwl_send_cmd_pdu_async(priv, REPLY_RXON_ASSOC, + sizeof(rxon_assoc), &rxon_assoc, NULL); + if (ret) + return ret; + + return ret; +} +static int iwl5000_send_tx_power(struct iwl_priv *priv) +{ + struct iwl5000_tx_power_dbm_cmd tx_power_cmd; + + /* half dBm need to multiply */ + tx_power_cmd.global_lmt = (s8)(2 * priv->tx_power_user_lmt); + tx_power_cmd.flags = IWL50_TX_POWER_NO_CLOSED; + tx_power_cmd.srv_chan_lmt = IWL50_TX_POWER_AUTO; + return iwl_send_cmd_pdu_async(priv, REPLY_TX_POWER_DBM_CMD, + sizeof(tx_power_cmd), &tx_power_cmd, + NULL); +} + +static void iwl5000_temperature(struct iwl_priv *priv) +{ + /* store temperature from statistics (in Celsius) */ + priv->temperature = le32_to_cpu(priv->statistics.general.temperature); +} + +static struct iwl_hcmd_ops iwl5000_hcmd = { + .rxon_assoc = iwl5000_send_rxon_assoc, +}; + +static struct iwl_hcmd_utils_ops iwl5000_hcmd_utils = { + .get_hcmd_size = iwl5000_get_hcmd_size, + .build_addsta_hcmd = iwl5000_build_addsta_hcmd, + .gain_computation = iwl5000_gain_computation, + .chain_noise_reset = iwl5000_chain_noise_reset, + .rts_tx_cmd_flag = iwl5000_rts_tx_cmd_flag, +}; + +static struct iwl_lib_ops iwl5000_lib = { + .set_hw_params = iwl5000_hw_set_hw_params, + .alloc_shared_mem = iwl5000_alloc_shared_mem, + .free_shared_mem = iwl5000_free_shared_mem, + .shared_mem_rx_idx = iwl5000_shared_mem_rx_idx, + .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, + .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, + .temperature = iwl5000_temperature, + .apm_ops = { + .init = iwl5000_apm_init, + .reset = iwl5000_apm_reset, + .stop = iwl5000_apm_stop, + .config = iwl5000_nic_config, + .set_pwr_src = iwl4965_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, + .check_version = iwl5000_eeprom_check_version, + .query_addr = iwl5000_eeprom_query_addr, + }, +}; + +static struct iwl_ops iwl5000_ops = { + .lib = &iwl5000_lib, + .hcmd = &iwl5000_hcmd, + .utils = &iwl5000_hcmd_utils, +}; + +static struct iwl_mod_params iwl50_mod_params = { + .num_of_queues = IWL50_NUM_QUEUES, + .num_of_ampdu_queues = IWL50_NUM_AMPDU_QUEUES, + .enable_qos = 1, + .amsdu_size_8K = 1, + .restart_fw = 1, + /* the rest are 0 by default */ +}; + + +struct iwl_cfg iwl5300_agn_cfg = { + .name = "5300AGN", + .fw_name = "iwlwifi-5000" IWL5000_UCODE_API ".ucode", + .sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N, + .ops = &iwl5000_ops, + .eeprom_size = IWL_5000_EEPROM_IMG_SIZE, + .mod_params = &iwl50_mod_params, +}; + +struct iwl_cfg iwl5100_bg_cfg = { + .name = "5100BG", + .fw_name = "iwlwifi-5000" IWL5000_UCODE_API ".ucode", + .sku = IWL_SKU_G, + .ops = &iwl5000_ops, + .eeprom_size = IWL_5000_EEPROM_IMG_SIZE, + .mod_params = &iwl50_mod_params, +}; + +struct iwl_cfg iwl5100_abg_cfg = { + .name = "5100ABG", + .fw_name = "iwlwifi-5000" IWL5000_UCODE_API ".ucode", + .sku = IWL_SKU_A|IWL_SKU_G, + .ops = &iwl5000_ops, + .eeprom_size = IWL_5000_EEPROM_IMG_SIZE, + .mod_params = &iwl50_mod_params, +}; + +struct iwl_cfg iwl5100_agn_cfg = { + .name = "5100AGN", + .fw_name = "iwlwifi-5000" IWL5000_UCODE_API ".ucode", + .sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N, + .ops = &iwl5000_ops, + .eeprom_size = IWL_5000_EEPROM_IMG_SIZE, + .mod_params = &iwl50_mod_params, +}; + +struct iwl_cfg iwl5350_agn_cfg = { + .name = "5350AGN", + .fw_name = "iwlwifi-5000" IWL5000_UCODE_API ".ucode", + .sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N, + .ops = &iwl5000_ops, + .eeprom_size = IWL_5000_EEPROM_IMG_SIZE, + .mod_params = &iwl50_mod_params, +}; + +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"); +module_param_named(debug50, iwl50_mod_params.debug, int, 0444); +MODULE_PARM_DESC(debug50, "50XX debug output mask"); +module_param_named(queues_num50, iwl50_mod_params.num_of_queues, int, 0444); +MODULE_PARM_DESC(queues_num50, "number of hw queues in 50xx series"); +module_param_named(qos_enable50, iwl50_mod_params.enable_qos, int, 0444); +MODULE_PARM_DESC(qos_enable50, "enable all 50XX QoS functionality"); +module_param_named(11n_disable50, iwl50_mod_params.disable_11n, int, 0444); +MODULE_PARM_DESC(11n_disable50, "disable 50XX 11n functionality"); +module_param_named(amsdu_size_8K50, iwl50_mod_params.amsdu_size_8K, int, 0444); +MODULE_PARM_DESC(amsdu_size_8K50, "enable 8K amsdu size in 50XX series"); +module_param_named(fw_restart50, iwl50_mod_params.restart_fw, int, 0444); +MODULE_PARM_DESC(fw_restart50, "restart firmware in case of error"); diff --git a/drivers/net/wireless/iwlwifi/iwl-calib.c b/drivers/net/wireless/iwlwifi/iwl-calib.c new file mode 100644 index 000000000000..ef49440bd7f6 --- /dev/null +++ b/drivers/net/wireless/iwlwifi/iwl-calib.c @@ -0,0 +1,802 @@ +/****************************************************************************** + * + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * Copyright(c) 2008 Intel Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, + * USA + * + * The full GNU General Public License is included in this distribution + * in the file called LICENSE.GPL. + * + * Contact Information: + * Tomas Winkler <tomas.winkler@intel.com> + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + * + * BSD LICENSE + * + * Copyright(c) 2005 - 2008 Intel Corporation. All rights reserved. + * 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 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. + *****************************************************************************/ + +#include <net/mac80211.h> + +#include "iwl-dev.h" +#include "iwl-core.h" +#include "iwl-calib.h" + +/* "false alarms" are signals that our DSP tries to lock onto, + * but then determines that they are either noise, or transmissions + * from a distant wireless network (also "noise", really) that get + * "stepped on" by stronger transmissions within our own network. + * This algorithm attempts to set a sensitivity level that is high + * enough to receive all of our own network traffic, but not so + * high that our DSP gets too busy trying to lock onto non-network + * activity/noise. */ +static int iwl_sens_energy_cck(struct iwl_priv *priv, + u32 norm_fa, + u32 rx_enable_time, + struct statistics_general_data *rx_info) +{ + u32 max_nrg_cck = 0; + int i = 0; + u8 max_silence_rssi = 0; + u32 silence_ref = 0; + u8 silence_rssi_a = 0; + u8 silence_rssi_b = 0; + u8 silence_rssi_c = 0; + u32 val; + + /* "false_alarms" values below are cross-multiplications to assess the + * numbers of false alarms within the measured period of actual Rx + * (Rx is off when we're txing), vs the min/max expected false alarms + * (some should be expected if rx is sensitive enough) in a + * hypothetical listening period of 200 time units (TU), 204.8 msec: + * + * MIN_FA/fixed-time < false_alarms/actual-rx-time < MAX_FA/beacon-time + * + * */ + u32 false_alarms = norm_fa * 200 * 1024; + u32 max_false_alarms = MAX_FA_CCK * rx_enable_time; + u32 min_false_alarms = MIN_FA_CCK * rx_enable_time; + struct iwl_sensitivity_data *data = NULL; + const struct iwl_sensitivity_ranges *ranges = priv->hw_params.sens; + + data = &(priv->sensitivity_data); + + data->nrg_auto_corr_silence_diff = 0; + + /* Find max silence rssi among all 3 receivers. + * This is background noise, which may include transmissions from other + * networks, measured during silence before our network's beacon */ + silence_rssi_a = (u8)((rx_info->beacon_silence_rssi_a & + ALL_BAND_FILTER) >> 8); + silence_rssi_b = (u8)((rx_info->beacon_silence_rssi_b & + ALL_BAND_FILTER) >> 8); + silence_rssi_c = (u8)((rx_info->beacon_silence_rssi_c & + ALL_BAND_FILTER) >> 8); + + val = max(silence_rssi_b, silence_rssi_c); + max_silence_rssi = max(silence_rssi_a, (u8) val); + + /* Store silence rssi in 20-beacon history table */ + data->nrg_silence_rssi[data->nrg_silence_idx] = max_silence_rssi; + data->nrg_silence_idx++; + if (data->nrg_silence_idx >= NRG_NUM_PREV_STAT_L) + data->nrg_silence_idx = 0; + + /* Find max silence rssi across 20 beacon history */ + for (i = 0; i < NRG_NUM_PREV_STAT_L; i++) { + val = data->nrg_silence_rssi[i]; + silence_ref = max(silence_ref, val); + } + IWL_DEBUG_CALIB("silence a %u, b %u, c %u, 20-bcn max %u\n", + silence_rssi_a, silence_rssi_b, silence_rssi_c, + silence_ref); + + /* Find max rx energy (min value!) among all 3 receivers, + * measured during beacon frame. + * Save it in 10-beacon history table. */ + i = data->nrg_energy_idx; + val = min(rx_info->beacon_energy_b, rx_info->beacon_energy_c); + data->nrg_value[i] = min(rx_info->beacon_energy_a, val); + + data->nrg_energy_idx++; + if (data->nrg_energy_idx >= 10) + data->nrg_energy_idx = 0; + + /* Find min rx energy (max value) across 10 beacon history. + * This is the minimum signal level that we want to receive well. + * Add backoff (margin so we don't miss slightly lower energy frames). + * This establishes an upper bound (min value) for energy threshold. */ + max_nrg_cck = data->nrg_value[0]; + for (i = 1; i < 10; i++) + max_nrg_cck = (u32) max(max_nrg_cck, (data->nrg_value[i])); + max_nrg_cck += 6; + + IWL_DEBUG_CALIB("rx energy a %u, b %u, c %u, 10-bcn max/min %u\n", + rx_info->beacon_energy_a, rx_info->beacon_energy_b, + rx_info->beacon_energy_c, max_nrg_cck - 6); + + /* Count number of consecutive beacons with fewer-than-desired + * false alarms. */ + if (false_alarms < min_false_alarms) + data->num_in_cck_no_fa++; + else + data->num_in_cck_no_fa = 0; + IWL_DEBUG_CALIB("consecutive bcns with few false alarms = %u\n", + data->num_in_cck_no_fa); + + /* If we got too many false alarms this time, reduce sensitivity */ + if ((false_alarms > max_false_alarms) && + (data->auto_corr_cck > AUTO_CORR_MAX_TH_CCK)) { + IWL_DEBUG_CALIB("norm FA %u > max FA %u\n", + false_alarms, max_false_alarms); + IWL_DEBUG_CALIB("... reducing sensitivity\n"); + data->nrg_curr_state = IWL_FA_TOO_MANY; + /* Store for "fewer than desired" on later beacon */ + data->nrg_silence_ref = silence_ref; + + /* increase energy threshold (reduce nrg value) + * to decrease sensitivity */ + if (data->nrg_th_cck > + (ranges->max_nrg_cck + NRG_STEP_CCK)) + data->nrg_th_cck = data->nrg_th_cck + - NRG_STEP_CCK; + else + data->nrg_th_cck = ranges->max_nrg_cck; + /* Else if we got fewer than desired, increase sensitivity */ + } else if (false_alarms < min_false_alarms) { + data->nrg_curr_state = IWL_FA_TOO_FEW; + + /* Compare silence level with silence level for most recent + * healthy number or too many false alarms */ + data->nrg_auto_corr_silence_diff = (s32)data->nrg_silence_ref - + (s32)silence_ref; + + IWL_DEBUG_CALIB("norm FA %u < min FA %u, silence diff %d\n", + false_alarms, min_false_alarms, + data->nrg_auto_corr_silence_diff); + + /* Increase value to increase sensitivity, but only if: + * 1a) previous beacon did *not* have *too many* false alarms + * 1b) AND there's a significant difference in Rx levels + * from a previous beacon with too many, or healthy # FAs + * OR 2) We've seen a lot of beacons (100) with too few + * false alarms */ + if ((data->nrg_prev_state != IWL_FA_TOO_MANY) && + ((data->nrg_auto_corr_silence_diff > NRG_DIFF) || + (data->num_in_cck_no_fa > MAX_NUMBER_CCK_NO_FA))) { + + IWL_DEBUG_CALIB("... increasing sensitivity\n"); + /* Increase nrg value to increase sensitivity */ + val = data->nrg_th_cck + NRG_STEP_CCK; + data->nrg_th_cck = min((u32)ranges->min_nrg_cck, val); + } else { + IWL_DEBUG_CALIB("... but not changing sensitivity\n"); + } + + /* Else we got a healthy number of false alarms, keep status quo */ + } else { + IWL_DEBUG_CALIB(" FA in safe zone\n"); + data->nrg_curr_state = IWL_FA_GOOD_RANGE; + + /* Store for use in "fewer than desired" with later beacon */ + data->nrg_silence_ref = silence_ref; + + /* If previous beacon had too many false alarms, + * give it some extra margin by reducing sensitivity again + * (but don't go below measured energy of desired Rx) */ + if (IWL_FA_TOO_MANY == data->nrg_prev_state) { + IWL_DEBUG_CALIB("... increasing margin\n"); + if (data->nrg_th_cck > (max_nrg_cck + NRG_MARGIN)) + data->nrg_th_cck -= NRG_MARGIN; + else + data->nrg_th_cck = max_nrg_cck; + } + } + + /* Make sure the energy threshold does not go above the measured + * energy of the desired Rx signals (reduced by backoff margin), + * or else we might start missing Rx frames. + * Lower value is higher energy, so we use max()! + */ + data->nrg_th_cck = max(max_nrg_cck, data->nrg_th_cck); + IWL_DEBUG_CALIB("new nrg_th_cck %u\n", data->nrg_th_cck); + + data->nrg_prev_state = data->nrg_curr_state; + + /* Auto-correlation CCK algorithm */ + if (false_alarms > min_false_alarms) { + + /* increase auto_corr values to decrease sensitivity + * so the DSP won't be disturbed by the noise + */ + if (data->auto_corr_cck < AUTO_CORR_MAX_TH_CCK) + data->auto_corr_cck = AUTO_CORR_MAX_TH_CCK + 1; + else { + val = data->auto_corr_cck + AUTO_CORR_STEP_CCK; + data->auto_corr_cck = + min((u32)ranges->auto_corr_max_cck, val); + } + val = data->auto_corr_cck_mrc + AUTO_CORR_STEP_CCK; + data->auto_corr_cck_mrc = + min((u32)ranges->auto_corr_max_cck_mrc, val); + } else if ((false_alarms < min_false_alarms) && + ((data->nrg_auto_corr_silence_diff > NRG_DIFF) || + (data->num_in_cck_no_fa > MAX_NUMBER_CCK_NO_FA))) { + + /* Decrease auto_corr values to increase sensitivity */ + val = data->auto_corr_cck - AUTO_CORR_STEP_CCK; + data->auto_corr_cck = + max((u32)ranges->auto_corr_min_cck, val); + val = data->auto_corr_cck_mrc - AUTO_CORR_STEP_CCK; + data->auto_corr_cck_mrc = + max((u32)ranges->auto_corr_min_cck_mrc, val); + } + + return 0; +} + + +static int iwl_sens_auto_corr_ofdm(struct iwl_priv *priv, + u32 norm_fa, + u32 rx_enable_time) +{ + u32 val; + u32 false_alarms = norm_fa * 200 * 1024; + u32 max_false_alarms = MAX_FA_OFDM * rx_enable_time; + u32 min_false_alarms = MIN_FA_OFDM * rx_enable_time; + struct iwl_sensitivity_data *data = NULL; + const struct iwl_sensitivity_ranges *ranges = priv->hw_params.sens; + + data = &(priv->sensitivity_data); + + /* If we got too many false alarms this time, reduce sensitivity */ + if (false_alarms > max_false_alarms) { + + IWL_DEBUG_CALIB("norm FA %u > max FA %u)\n", + false_alarms, max_false_alarms); + + val = data->auto_corr_ofdm + AUTO_CORR_STEP_OFDM; + data->auto_corr_ofdm = + min((u32)ranges->auto_corr_max_ofdm, val); + + val = data->auto_corr_ofdm_mrc + AUTO_CORR_STEP_OFDM; + data->auto_corr_ofdm_mrc = + min((u32)ranges->auto_corr_max_ofdm_mrc, val); + + val = data->auto_corr_ofdm_x1 + AUTO_CORR_STEP_OFDM; + data->auto_corr_ofdm_x1 = + min((u32)ranges->auto_corr_max_ofdm_x1, val); + + val = data->auto_corr_ofdm_mrc_x1 + AUTO_CORR_STEP_OFDM; + data->auto_corr_ofdm_mrc_x1 = + min((u32)ranges->auto_corr_max_ofdm_mrc_x1, val); + } + + /* Else if we got fewer than desired, increase sensitivity */ + else if (false_alarms < min_false_alarms) { + + IWL_DEBUG_CALIB("norm FA %u < min FA %u\n", + false_alarms, min_false_alarms); + + val = data->auto_corr_ofdm - AUTO_CORR_STEP_OFDM; + data->auto_corr_ofdm = + max((u32)ranges->auto_corr_min_ofdm, val); + + val = data->auto_corr_ofdm_mrc - AUTO_CORR_STEP_OFDM; + data->auto_corr_ofdm_mrc = + max((u32)ranges->auto_corr_min_ofdm_mrc, val); + + val = data->auto_corr_ofdm_x1 - AUTO_CORR_STEP_OFDM; + data->auto_corr_ofdm_x1 = + max((u32)ranges->auto_corr_min_ofdm_x1, val); + + val = data->auto_corr_ofdm_mrc_x1 - AUTO_CORR_STEP_OFDM; + data->auto_corr_ofdm_mrc_x1 = + max((u32)ranges->auto_corr_min_ofdm_mrc_x1, val); + } else { + IWL_DEBUG_CALIB("min FA %u < norm FA %u < max FA %u OK\n", + min_false_alarms, false_alarms, max_false_alarms); + } + return 0; +} + +/* Prepare a SENSITIVITY_CMD, send to uCode if values have changed */ +static int iwl_sensitivity_write(struct iwl_priv *priv) +{ + int ret = 0; + struct iwl_sensitivity_cmd cmd ; + struct iwl_sensitivity_data *data = NULL; + struct iwl_host_cmd cmd_out = { + .id = SENSITIVITY_CMD, + .len = sizeof(struct iwl_sensitivity_cmd), + .meta.flags = CMD_ASYNC, + .data = &cmd, + }; + + data = &(priv->sensitivity_data); + + memset(&cmd, 0, sizeof(cmd)); + + cmd.table[HD_AUTO_CORR32_X4_TH_ADD_MIN_INDEX] = + cpu_to_le16((u16)data->auto_corr_ofdm); + cmd.table[HD_AUTO_CORR32_X4_TH_ADD_MIN_MRC_INDEX] = + cpu_to_le16((u16)data->auto_corr_ofdm_mrc); + cmd.table[HD_AUTO_CORR32_X1_TH_ADD_MIN_INDEX] = + cpu_to_le16((u16)data->auto_corr_ofdm_x1); + cmd.table[HD_AUTO_CORR32_X1_TH_ADD_MIN_MRC_INDEX] = + cpu_to_le16((u16)data->auto_corr_ofdm_mrc_x1); + + cmd.table[HD_AUTO_CORR40_X4_TH_ADD_MIN_INDEX] = + cpu_to_le16((u16)data->auto_corr_cck); + cmd.table[HD_AUTO_CORR40_X4_TH_ADD_MIN_MRC_INDEX] = + cpu_to_le16((u16)data->auto_corr_cck_mrc); + + cmd.table[HD_MIN_ENERGY_CCK_DET_INDEX] = + cpu_to_le16((u16)data->nrg_th_cck); + cmd.table[HD_MIN_ENERGY_OFDM_DET_INDEX] = + cpu_to_le16((u16)data->nrg_th_ofdm); + + cmd.table[HD_BARKER_CORR_TH_ADD_MIN_INDEX] = + __constant_cpu_to_le16(190); + cmd.table[HD_BARKER_CORR_TH_ADD_MIN_MRC_INDEX] = + __constant_cpu_to_le16(390); + cmd.table[HD_OFDM_ENERGY_TH_IN_INDEX] = + __constant_cpu_to_le16(62); + + IWL_DEBUG_CALIB("ofdm: ac %u mrc %u x1 %u mrc_x1 %u thresh %u\n", + data->auto_corr_ofdm, data->auto_corr_ofdm_mrc, + data->auto_corr_ofdm_x1, data->auto_corr_ofdm_mrc_x1, + data->nrg_th_ofdm); + + IWL_DEBUG_CALIB("cck: ac %u mrc %u thresh %u\n", + data->auto_corr_cck, data->auto_corr_cck_mrc, + data->nrg_th_cck); + + /* Update uCode's "work" table, and copy it to DSP */ + cmd.control = SENSITIVITY_CMD_CONTROL_WORK_TABLE; + + /* Don't send command to uCode if nothing has changed */ + if (!memcmp(&cmd.table[0], &(priv->sensitivity_tbl[0]), + sizeof(u16)*HD_TABLE_SIZE)) { + IWL_DEBUG_CALIB("No change in SENSITIVITY_CMD\n"); + return 0; + } + + /* Copy table for comparison next time */ + memcpy(&(priv->sensitivity_tbl[0]), &(cmd.table[0]), + sizeof(u16)*HD_TABLE_SIZE); + + ret = iwl_send_cmd(priv, &cmd_out); + if (ret) + IWL_ERROR("SENSITIVITY_CMD failed\n"); + + return ret; +} + +void iwl_init_sensitivity(struct iwl_priv *priv) +{ + int ret = 0; + int i; + struct iwl_sensitivity_data *data = NULL; + const struct iwl_sensitivity_ranges *ranges = priv->hw_params.sens; + + if (priv->disable_sens_cal) + return; + + IWL_DEBUG_CALIB("Start iwl_init_sensitivity\n"); + + /* Clear driver's sensitivity algo data */ + data = &(priv->sensitivity_data); + + if (ranges == NULL) + return; + + memset(data, 0, sizeof(struct iwl_sensitivity_data)); + + data->num_in_cck_no_fa = 0; + data->nrg_curr_state = IWL_FA_TOO_MANY; + data->nrg_prev_state = IWL_FA_TOO_MANY; + data->nrg_silence_ref = 0; + data->nrg_silence_idx = 0; + data->nrg_energy_idx = 0; + + for (i = 0; i < 10; i++) + data->nrg_value[i] = 0; + + for (i = 0; i < NRG_NUM_PREV_STAT_L; i++) + data->nrg_silence_rssi[i] = 0; + + data->auto_corr_ofdm = 90; + data->auto_corr_ofdm_mrc = ranges->auto_corr_min_ofdm_mrc; + data->auto_corr_ofdm_x1 = ranges->auto_corr_min_ofdm_x1; + data->auto_corr_ofdm_mrc_x1 = ranges->auto_corr_min_ofdm_mrc_x1; + data->auto_corr_cck = AUTO_CORR_CCK_MIN_VAL_DEF; + data->auto_corr_cck_mrc = ranges->auto_corr_min_cck_mrc; + data->nrg_th_cck = ranges->nrg_th_cck; + data->nrg_th_ofdm = ranges->nrg_th_ofdm; + + data->last_bad_plcp_cnt_ofdm = 0; + data->last_fa_cnt_ofdm = 0; + data->last_bad_plcp_cnt_cck = 0; + data->last_fa_cnt_cck = 0; + + ret |= iwl_sensitivity_write(priv); + IWL_DEBUG_CALIB("<<return 0x%X\n", ret); +} +EXPORT_SYMBOL(iwl_init_sensitivity); + +void iwl_sensitivity_calibration(struct iwl_priv *priv, + struct iwl_notif_statistics *resp) +{ + u32 rx_enable_time; + u32 fa_cck; + u32 fa_ofdm; + u32 bad_plcp_cck; + u32 bad_plcp_ofdm; + u32 norm_fa_ofdm; + u32 norm_fa_cck; + struct iwl_sensitivity_data *data = NULL; + struct statistics_rx_non_phy *rx_info = &(resp->rx.general); + struct statistics_rx *statistics = &(resp->rx); + unsigned long flags; + struct statistics_general_data statis; + + if (priv->disable_sens_cal) + return; + + data = &(priv->sensitivity_data); + + if (!iwl_is_associated(priv)) { + IWL_DEBUG_CALIB("<< - not associated\n"); + return; + } + + spin_lock_irqsave(&priv->lock, flags); + if (rx_info->interference_data_flag != INTERFERENCE_DATA_AVAILABLE) { + IWL_DEBUG_CALIB("<< invalid data.\n"); + spin_unlock_irqrestore(&priv->lock, flags); + return; + } + + /* Extract Statistics: */ + rx_enable_time = le32_to_cpu(rx_info->channel_load); + fa_cck = le32_to_cpu(statistics->cck.false_alarm_cnt); + fa_ofdm = le32_to_cpu(statistics->ofdm.false_alarm_cnt); + bad_plcp_cck = le32_to_cpu(statistics->cck.plcp_err); + bad_plcp_ofdm = le32_to_cpu(statistics->ofdm.plcp_err); + + statis.beacon_silence_rssi_a = + le32_to_cpu(statistics->general.beacon_silence_rssi_a); + statis.beacon_silence_rssi_b = + le32_to_cpu(statistics->general.beacon_silence_rssi_b); + statis.beacon_silence_rssi_c = + le32_to_cpu(statistics->general.beacon_silence_rssi_c); + statis.beacon_energy_a = + le32_to_cpu(statistics->general.beacon_energy_a); + statis.beacon_energy_b = + le32_to_cpu(statistics->general.beacon_energy_b); + statis.beacon_energy_c = + le32_to_cpu(statistics->general.beacon_energy_c); + + spin_unlock_irqrestore(&priv->lock, flags); + + IWL_DEBUG_CALIB("rx_enable_time = %u usecs\n", rx_enable_time); + + if (!rx_enable_time) { + IWL_DEBUG_CALIB("<< RX Enable Time == 0! \n"); + return; + } + + /* These statistics increase monotonically, and do not reset + * at each beacon. Calculate difference from last value, or just + * use the new statistics value if it has reset or wrapped around. */ + if (data->last_bad_plcp_cnt_cck > bad_plcp_cck) + data->last_bad_plcp_cnt_cck = bad_plcp_cck; + else { + bad_plcp_cck -= data->last_bad_plcp_cnt_cck; + data->last_bad_plcp_cnt_cck += bad_plcp_cck; + } + + if (data->last_bad_plcp_cnt_ofdm > bad_plcp_ofdm) + data->last_bad_plcp_cnt_ofdm = bad_plcp_ofdm; + else { + bad_plcp_ofdm -= data->last_bad_plcp_cnt_ofdm; + data->last_bad_plcp_cnt_ofdm += bad_plcp_ofdm; + } + + if (data->last_fa_cnt_ofdm > fa_ofdm) + data->last_fa_cnt_ofdm = fa_ofdm; + else { + fa_ofdm -= data->last_fa_cnt_ofdm; + data->last_fa_cnt_ofdm += fa_ofdm; + } + + if (data->last_fa_cnt_cck > fa_cck) + data->last_fa_cnt_cck = fa_cck; + else { + fa_cck -= data->last_fa_cnt_cck; + data->last_fa_cnt_cck += fa_cck; + } + + /* Total aborted signal locks */ + norm_fa_ofdm = fa_ofdm + bad_plcp_ofdm; + norm_fa_cck = fa_cck + bad_plcp_cck; + + IWL_DEBUG_CALIB("cck: fa %u badp %u ofdm: fa %u badp %u\n", fa_cck, + bad_plcp_cck, fa_ofdm, bad_plcp_ofdm); + + iwl_sens_auto_corr_ofdm(priv, norm_fa_ofdm, rx_enable_time); + iwl_sens_energy_cck(priv, norm_fa_cck, rx_enable_time, &statis); + iwl_sensitivity_write(priv); + + return; +} +EXPORT_SYMBOL(iwl_sensitivity_calibration); + +/* + * Accumulate 20 beacons of signal and noise statistics for each of + * 3 receivers/antennas/rx-chains, then figure out: + * 1) Which antennas are connected. + * 2) Differential rx gain settings to balance the 3 receivers. + */ +void iwl_chain_noise_calibration(struct iwl_priv *priv, + struct iwl_notif_statistics *stat_resp) +{ + struct iwl_chain_noise_data *data = NULL; + + u32 chain_noise_a; + u32 chain_noise_b; + u32 chain_noise_c; + u32 chain_sig_a; + u32 chain_sig_b; + u32 chain_sig_c; + u32 average_sig[NUM_RX_CHAINS] = {INITIALIZATION_VALUE}; + u32 average_noise[NUM_RX_CHAINS] = {INITIALIZATION_VALUE}; + u32 max_average_sig; + u16 max_average_sig_antenna_i; + u32 min_average_noise = MIN_AVERAGE_NOISE_MAX_VALUE; + u16 min_average_noise_antenna_i = INITIALIZATION_VALUE; + u16 i = 0; + u16 rxon_chnum = INITIALIZATION_VALUE; + u16 stat_chnum = INITIALIZATION_VALUE; + u8 rxon_band24; + u8 stat_band24; + u32 active_chains = 0; + u8 num_tx_chains; + unsigned long flags; + struct statistics_rx_non_phy *rx_info = &(stat_resp->rx.general); + + if (priv->disable_chain_noise_cal) + return; + + data = &(priv->chain_noise_data); + + /* Accumulate just the first 20 beacons after the first association, + * then we're done forever. */ + if (data->state != IWL_CHAIN_NOISE_ACCUMULATE) { + if (data->state == IWL_CHAIN_NOISE_ALIVE) + IWL_DEBUG_CALIB("Wait for noise calib reset\n"); + return; + } + + spin_lock_irqsave(&priv->lock, flags); + if (rx_info->interference_data_flag != INTERFERENCE_DATA_AVAILABLE) { + IWL_DEBUG_CALIB(" << Interference data unavailable\n"); + spin_unlock_irqrestore(&priv->lock, flags); + return; + } + + rxon_band24 = !!(priv->staging_rxon.flags & RXON_FLG_BAND_24G_MSK); + rxon_chnum = le16_to_cpu(priv->staging_rxon.channel); + stat_band24 = !!(stat_resp->flag & STATISTICS_REPLY_FLG_BAND_24G_MSK); + stat_chnum = le32_to_cpu(stat_resp->flag) >> 16; + + /* Make sure we accumulate data for just the associated channel + * (even if scanning). */ + if ((rxon_chnum != stat_chnum) || (rxon_band24 != stat_band24)) { + IWL_DEBUG_CALIB("Stats not from chan=%d, band24=%d\n", + rxon_chnum, rxon_band24); + spin_unlock_irqrestore(&priv->lock, flags); + return; + } + + /* Accumulate beacon statistics values across 20 beacons */ + chain_noise_a = le32_to_cpu(rx_info->beacon_silence_rssi_a) & + IN_BAND_FILTER; + chain_noise_b = le32_to_cpu(rx_info->beacon_silence_rssi_b) & + IN_BAND_FILTER; + chain_noise_c = le32_to_cpu(rx_info->beacon_silence_rssi_c) & + IN_BAND_FILTER; + + chain_sig_a = le32_to_cpu(rx_info->beacon_rssi_a) & IN_BAND_FILTER; + chain_sig_b = le32_to_cpu(rx_info->beacon_rssi_b) & IN_BAND_FILTER; + chain_sig_c = le32_to_cpu(rx_info->beacon_rssi_c) & IN_BAND_FILTER; + + spin_unlock_irqrestore(&priv->lock, flags); + + data->beacon_count++; + + data->chain_noise_a = (chain_noise_a + data->chain_noise_a); + data->chain_noise_b = (chain_noise_b + data->chain_noise_b); + data->chain_noise_c = (chain_noise_c + data->chain_noise_c); + + data->chain_signal_a = (chain_sig_a + data->chain_signal_a); + data->chain_signal_b = (chain_sig_b + data->chain_signal_b); + data->chain_signal_c = (chain_sig_c + data->chain_signal_c); + + IWL_DEBUG_CALIB("chan=%d, band24=%d, beacon=%d\n", + rxon_chnum, rxon_band24, data->beacon_count); + IWL_DEBUG_CALIB("chain_sig: a %d b %d c %d\n", + chain_sig_a, chain_sig_b, chain_sig_c); + IWL_DEBUG_CALIB("chain_noise: a %d b %d c %d\n", + chain_noise_a, chain_noise_b, chain_noise_c); + + /* If this is the 20th beacon, determine: + * 1) Disconnected antennas (using signal strengths) + * 2) Differential gain (using silence noise) to balance receivers */ + if (data->beacon_count != CAL_NUM_OF_BEACONS) + return; + + /* Analyze signal for disconnected antenna */ + average_sig[0] = (data->chain_signal_a) / CAL_NUM_OF_BEACONS; + average_sig[1] = (data->chain_signal_b) / CAL_NUM_OF_BEACONS; + average_sig[2] = (data->chain_signal_c) / CAL_NUM_OF_BEACONS; + + if (average_sig[0] >= average_sig[1]) { + max_average_sig = average_sig[0]; + max_average_sig_antenna_i = 0; + active_chains = (1 << max_average_sig_antenna_i); + } else { + max_average_sig = average_sig[1]; + max_average_sig_antenna_i = 1; + active_chains = (1 << max_average_sig_antenna_i); + } + + if (average_sig[2] >= max_average_sig) { + max_average_sig = average_sig[2]; + max_average_sig_antenna_i = 2; + active_chains = (1 << max_average_sig_antenna_i); + } + + IWL_DEBUG_CALIB("average_sig: a %d b %d c %d\n", + average_sig[0], average_sig[1], average_sig[2]); + IWL_DEBUG_CALIB("max_average_sig = %d, antenna %d\n", + max_average_sig, max_average_sig_antenna_i); + + /* Compare signal strengths for all 3 receivers. */ + for (i = 0; i < NUM_RX_CHAINS; i++) { + if (i != max_average_sig_antenna_i) { + s32 rssi_delta = (max_average_sig - average_sig[i]); + + /* If signal is very weak, compared with + * strongest, mark it as disconnected. */ + if (rssi_delta > MAXIMUM_ALLOWED_PATHLOSS) + data->disconn_array[i] = 1; + else + active_chains |= (1 << i); + IWL_DEBUG_CALIB("i = %d rssiDelta = %d " + "disconn_array[i] = %d\n", + i, rssi_delta, data->disconn_array[i]); + } + } + + num_tx_chains = 0; + for (i = 0; i < NUM_RX_CHAINS; i++) { + /* loops on all the bits of + * priv->hw_setting.valid_tx_ant */ + u8 ant_msk = (1 << i); + if (!(priv->hw_params.valid_tx_ant & ant_msk)) + continue; + + num_tx_chains++; + if (data->disconn_array[i] == 0) + /* there is a Tx antenna connected */ + break; + if (num_tx_chains == priv->hw_params.tx_chains_num && + data->disconn_array[i]) { + /* This is the last TX antenna and is also + * disconnected connect it anyway */ + data->disconn_array[i] = 0; + active_chains |= ant_msk; + IWL_DEBUG_CALIB("All Tx chains are disconnected W/A - " + "declare %d as connected\n", i); + break; + } + } + + IWL_DEBUG_CALIB("active_chains (bitwise) = 0x%x\n", + active_chains); + + /* Save for use within RXON, TX, SCAN commands, etc. */ + /*priv->valid_antenna = active_chains;*/ + /*FIXME: should be reflected in RX chains in RXON */ + + /* Analyze noise for rx balance */ + average_noise[0] = ((data->chain_noise_a)/CAL_NUM_OF_BEACONS); + average_noise[1] = ((data->chain_noise_b)/CAL_NUM_OF_BEACONS); + average_noise[2] = ((data->chain_noise_c)/CAL_NUM_OF_BEACONS); + + for (i = 0; i < NUM_RX_CHAINS; i++) { + if (!(data->disconn_array[i]) && + (average_noise[i] <= min_average_noise)) { + /* This means that chain i is active and has + * lower noise values so far: */ + min_average_noise = average_noise[i]; + min_average_noise_antenna_i = i; + } + } + + IWL_DEBUG_CALIB("average_noise: a %d b %d c %d\n", + average_noise[0], average_noise[1], + average_noise[2]); + + IWL_DEBUG_CALIB("min_average_noise = %d, antenna %d\n", + min_average_noise, min_average_noise_antenna_i); + + priv->cfg->ops->utils->gain_computation(priv, average_noise, + min_average_noise_antenna_i, min_average_noise); +} +EXPORT_SYMBOL(iwl_chain_noise_calibration); + + +void iwl_reset_run_time_calib(struct iwl_priv *priv) +{ + int i; + memset(&(priv->sensitivity_data), 0, + sizeof(struct iwl_sensitivity_data)); + memset(&(priv->chain_noise_data), 0, + sizeof(struct iwl_chain_noise_data)); + for (i = 0; i < NUM_RX_CHAINS; i++) + priv->chain_noise_data.delta_gain_code[i] = + CHAIN_NOISE_DELTA_GAIN_INIT_VAL; + + /* Ask for statistics now, the uCode will send notification + * periodically after association */ + iwl_send_statistics_request(priv, CMD_ASYNC); +} +EXPORT_SYMBOL(iwl_reset_run_time_calib); + diff --git a/drivers/net/wireless/iwlwifi/iwl-calib.h b/drivers/net/wireless/iwlwifi/iwl-calib.h new file mode 100644 index 000000000000..94c8e316382a --- /dev/null +++ b/drivers/net/wireless/iwlwifi/iwl-calib.h @@ -0,0 +1,84 @@ +/****************************************************************************** + * + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * Copyright(c) 2008 Intel Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, + * USA + * + * The full GNU General Public License is included in this distribution + * in the file called LICENSE.GPL. + * + * Contact Information: + * Tomas Winkler <tomas.winkler@intel.com> + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + * + * BSD LICENSE + * + * Copyright(c) 2005 - 2008 Intel Corporation. All rights reserved. + * 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 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. + *****************************************************************************/ +#ifndef __iwl_calib_h__ +#define __iwl_calib_h__ + +#include "iwl-dev.h" +#include "iwl-core.h" +#include "iwl-commands.h" + +void iwl_chain_noise_calibration(struct iwl_priv *priv, + struct iwl_notif_statistics *stat_resp); +void iwl_sensitivity_calibration(struct iwl_priv *priv, + struct iwl_notif_statistics *resp); + +void iwl_init_sensitivity(struct iwl_priv *priv); +void iwl_reset_run_time_calib(struct iwl_priv *priv); +static inline void iwl_chain_noise_reset(struct iwl_priv *priv) +{ + + if (!priv->disable_chain_noise_cal && + priv->cfg->ops->utils->chain_noise_reset) + priv->cfg->ops->utils->chain_noise_reset(priv); +} + +#endif /* __iwl_calib_h__ */ diff --git a/drivers/net/wireless/iwlwifi/iwl-4965-commands.h b/drivers/net/wireless/iwlwifi/iwl-commands.h index 3bcd107e2d71..e9bb1de0ce3f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965-commands.h +++ b/drivers/net/wireless/iwlwifi/iwl-commands.h @@ -61,9 +61,9 @@ * *****************************************************************************/ /* - * Please use this file (iwl-4965-commands.h) only for uCode API definitions. + * Please use this file (iwl-commands.h) only for uCode API definitions. * Please use iwl-4965-hw.h for hardware-related definitions. - * Please use iwl-4965.h for driver implementation definitions. + * Please use iwl-dev.h for driver implementation definitions. */ #ifndef __iwl4965_commands_h__ @@ -93,6 +93,11 @@ enum { REPLY_LEDS_CMD = 0x48, REPLY_TX_LINK_QUALITY_CMD = 0x4e, /* 4965 only */ + /* WiMAX coexistence */ + COEX_PRIORITY_TABLE_CMD = 0x5a, /*5000 only */ + COEX_MEDIUM_NOTIFICATION = 0x5b, + COEX_EVENT_CMD = 0x5c, + /* 802.11h related */ RADAR_NOTIFICATION = 0x70, /* not used */ REPLY_QUIET_CMD = 0x71, /* not used */ @@ -121,6 +126,7 @@ enum { /* Miscellaneous commands */ QUIET_NOTIFICATION = 0x96, /* not used */ REPLY_TX_PWR_TABLE_CMD = 0x97, + REPLY_TX_POWER_DBM_CMD = 0x98, MEASURE_ABORT_NOTIFICATION = 0x99, /* not used */ /* Bluetooth device coexistance config command */ @@ -269,21 +275,13 @@ struct iwl_cmd_header { * 10 B active, A inactive * 11 Both active */ -#define RATE_MCS_ANT_POS 14 -#define RATE_MCS_ANT_A_MSK 0x04000 -#define RATE_MCS_ANT_B_MSK 0x08000 -#define RATE_MCS_ANT_AB_MSK 0x0C000 +#define RATE_MCS_ANT_POS 14 +#define RATE_MCS_ANT_A_MSK 0x04000 +#define RATE_MCS_ANT_B_MSK 0x08000 +#define RATE_MCS_ANT_C_MSK 0x10000 +#define RATE_MCS_ANT_ABC_MSK 0x1C000 - -/** - * struct iwl4965_tx_power - txpower format used in REPLY_SCAN_CMD - * - * Scan uses only one transmitter, so only one analog/dsp gain pair is needed. - */ -struct iwl4965_tx_power { - u8 tx_gain; /* gain for analog radio */ - u8 dsp_atten; /* gain for DSP */ -} __attribute__ ((packed)); +#define RATE_MCS_ANT_INIT_IND 1 #define POWER_TABLE_NUM_ENTRIES 33 #define POWER_TABLE_NUM_HT_OFDM_ENTRIES 32 @@ -333,6 +331,19 @@ struct iwl4965_tx_power_db { struct tx_power_dual_stream power_tbl[POWER_TABLE_NUM_ENTRIES]; } __attribute__ ((packed)); +/** + * Commad REPLY_TX_POWER_DBM_CMD = 0x98 + * struct iwl5000_tx_power_dbm_cmd + */ +#define IWL50_TX_POWER_AUTO 0x7f +#define IWL50_TX_POWER_NO_CLOSED (0x1 << 6) + +struct iwl5000_tx_power_dbm_cmd { + s8 global_lmt; /*in half-dBm (e.g. 30 = 15 dBm) */ + u8 flags; + s8 srv_chan_lmt; /*in half-dBm (e.g. 30 = 15 dBm) */ + u8 reserved; +} __attribute__ ((packed)); /****************************************************************************** * (0a) @@ -367,7 +378,7 @@ struct iwl4965_tx_power_db { * 3) Tx gain compensation to balance 4965's 2 Tx chains for MIMO operation, * for each of 5 frequency ranges. */ -struct iwl4965_init_alive_resp { +struct iwl_init_alive_resp { u8 ucode_minor; u8 ucode_major; __le16 reserved1; @@ -443,7 +454,7 @@ struct iwl4965_init_alive_resp { * The Linux driver can print both logs to the system log when a uCode error * occurs. */ -struct iwl4965_alive_resp { +struct iwl_alive_resp { u8 ucode_minor; u8 ucode_major; __le16 reserved1; @@ -467,7 +478,7 @@ union tsf { /* * REPLY_ERROR = 0x2 (response only, not a command) */ -struct iwl4965_error_resp { +struct iwl_error_resp { __le32 error_type; u8 cmd_id; u8 reserved1; @@ -545,6 +556,8 @@ enum { #define RXON_FLG_CHANNEL_MODE_MSK __constant_cpu_to_le32(0x3 << 25) #define RXON_FLG_CHANNEL_MODE_PURE_40_MSK __constant_cpu_to_le32(0x1 << 25) #define RXON_FLG_CHANNEL_MODE_MIXED_MSK __constant_cpu_to_le32(0x2 << 25) +/* CTS to self (if spec allows) flag */ +#define RXON_FLG_SELF_CTS_EN __constant_cpu_to_le32(0x1<<30) /* rx_config filter flags */ /* accept all data frames */ @@ -599,6 +612,46 @@ struct iwl4965_rxon_cmd { u8 ofdm_ht_dual_stream_basic_rates; } __attribute__ ((packed)); +/* 5000 HW just extend this cmmand */ +struct iwl_rxon_cmd { + u8 node_addr[6]; + __le16 reserved1; + u8 bssid_addr[6]; + __le16 reserved2; + u8 wlap_bssid_addr[6]; + __le16 reserved3; + u8 dev_type; + u8 air_propagation; + __le16 rx_chain; + u8 ofdm_basic_rates; + u8 cck_basic_rates; + __le16 assoc_id; + __le32 flags; + __le32 filter_flags; + __le16 channel; + u8 ofdm_ht_single_stream_basic_rates; + u8 ofdm_ht_dual_stream_basic_rates; + u8 ofdm_ht_triple_stream_basic_rates; + u8 reserved5; + __le16 acquisition_data; + __le16 reserved6; +} __attribute__ ((packed)); + +struct iwl5000_rxon_assoc_cmd { + __le32 flags; + __le32 filter_flags; + u8 ofdm_basic_rates; + u8 cck_basic_rates; + __le16 reserved1; + u8 ofdm_ht_single_stream_basic_rates; + u8 ofdm_ht_dual_stream_basic_rates; + u8 ofdm_ht_triple_stream_basic_rates; + u8 reserved2; + __le16 rx_chain_select_flags; + __le16 acquisition_data; + __le32 reserved3; +} __attribute__ ((packed)); + /* * REPLY_RXON_ASSOC = 0x11 (command, has simple generic response) */ @@ -613,6 +666,9 @@ struct iwl4965_rxon_assoc_cmd { __le16 reserved; } __attribute__ ((packed)); + + + /* * REPLY_RXON_TIMING = 0x14 (command, has simple generic response) */ @@ -669,7 +725,7 @@ struct iwl4965_csa_notification { * transmission retry. Device uses cw_max as a bit mask, ANDed with new CW * value, to cap the CW value. */ -struct iwl4965_ac_qos { +struct iwl_ac_qos { __le16 cw_min; __le16 cw_max; u8 aifsn; @@ -691,9 +747,9 @@ struct iwl4965_ac_qos { * This command sets up timings for each of the 4 prioritized EDCA Tx FIFOs * 0: Background, 1: Best Effort, 2: Video, 3: Voice. */ -struct iwl4965_qosparam_cmd { +struct iwl_qosparam_cmd { __le32 qos_flags; - struct iwl4965_ac_qos ac[AC_NUM]; + struct iwl_ac_qos ac[AC_NUM]; } __attribute__ ((packed)); /****************************************************************************** @@ -711,6 +767,8 @@ struct iwl4965_qosparam_cmd { #define IWL_STA_ID 2 #define IWL4965_BROADCAST_ID 31 #define IWL4965_STATION_COUNT 32 +#define IWL5000_BROADCAST_ID 15 +#define IWL5000_STATION_COUNT 16 #define IWL_STATION_COUNT 32 /* MAX(3945,4965)*/ #define IWL_INVALID_STATION 255 @@ -766,6 +824,20 @@ struct iwl4965_keyinfo { u8 key[16]; /* 16-byte unicast decryption key */ } __attribute__ ((packed)); +/* 5000 */ +struct iwl_keyinfo { + __le16 key_flags; + u8 tkip_rx_tsc_byte2; /* TSC[2] for key mix ph1 detection */ + u8 reserved1; + __le16 tkip_rx_ttak[5]; /* 10-byte unicast TKIP TTAK */ + u8 key_offset; + u8 reserved2; + u8 key[16]; /* 16-byte unicast decryption key */ + __le64 tx_secur_seq_cnt; + __le64 hw_tkip_mic_rx_key; + __le64 hw_tkip_mic_tx_key; +} __attribute__ ((packed)); + /** * struct sta_id_modify * @addr[ETH_ALEN]: station's MAC address @@ -841,6 +913,38 @@ struct iwl4965_addsta_cmd { __le32 reserved2; } __attribute__ ((packed)); +/* 5000 */ +struct iwl_addsta_cmd { + u8 mode; /* 1: modify existing, 0: add new station */ + u8 reserved[3]; + struct sta_id_modify sta; + struct iwl_keyinfo key; + __le32 station_flags; /* STA_FLG_* */ + __le32 station_flags_msk; /* STA_FLG_* */ + + /* bit field to disable (1) or enable (0) Tx for Traffic ID (TID) + * corresponding to bit (e.g. bit 5 controls TID 5). + * Set modify_mask bit STA_MODIFY_TID_DISABLE_TX to use this field. */ + __le16 tid_disable_tx; + + __le16 reserved1; + + /* TID for which to add block-ack support. + * Set modify_mask bit STA_MODIFY_ADDBA_TID_MSK to use this field. */ + u8 add_immediate_ba_tid; + + /* TID for which to remove block-ack support. + * Set modify_mask bit STA_MODIFY_DELBA_TID_MSK to use this field. */ + u8 remove_immediate_ba_tid; + + /* Starting Sequence Number for added block-ack support. + * Set modify_mask bit STA_MODIFY_ADDBA_TID_MSK to use this field. */ + __le16 add_immediate_ba_ssn; + + __le32 reserved2; +} __attribute__ ((packed)); + + #define ADD_STA_SUCCESS_MSK 0x1 #define ADD_STA_NO_ROOM_IN_TABLE 0x2 #define ADD_STA_NO_BLOCK_ACK_RESOURCE 0x4 @@ -848,10 +952,28 @@ struct iwl4965_addsta_cmd { /* * REPLY_ADD_STA = 0x18 (response) */ -struct iwl4965_add_sta_resp { +struct iwl_add_sta_resp { u8 status; /* ADD_STA_* */ } __attribute__ ((packed)); +#define REM_STA_SUCCESS_MSK 0x1 +/* + * REPLY_REM_STA = 0x19 (response) + */ +struct iwl_rem_sta_resp { + u8 status; +} __attribute__ ((packed)); + +/* + * REPLY_REM_STA = 0x19 (command) + */ +struct iwl_rem_sta_cmd { + u8 num_sta; /* number of removed stations */ + u8 reserved[3]; + u8 addr[ETH_ALEN]; /* MAC addr of the first station */ + u8 reserved2[2]; +} __attribute__ ((packed)); + /* * REPLY_WEP_KEY = 0x20 */ @@ -875,6 +997,7 @@ struct iwl_wep_cmd { #define WEP_KEY_WEP_TYPE 1 #define WEP_KEYS_MAX 4 #define WEP_INVALID_OFFSET 0xff +#define WEP_KEY_LEN_64 5 #define WEP_KEY_LEN_128 13 /****************************************************************************** @@ -1018,6 +1141,11 @@ struct iwl4965_rx_mpdu_res_start { /* REPLY_TX Tx flags field */ +/* 1: Use RTS/CTS protocol or CTS-to-self if spec alows it + * before this frame. if CTS-to-self required check + * RXON_FLG_SELF_CTS_EN status. */ +#define TX_CMD_FLG_RTS_CTS_MSK __constant_cpu_to_le32(1 << 0) + /* 1: Use Request-To-Send protocol before this frame. * Mutually exclusive vs. TX_CMD_FLG_CTS_MSK. */ #define TX_CMD_FLG_RTS_MSK __constant_cpu_to_le32(1 << 1) @@ -1100,6 +1228,14 @@ struct iwl4965_rx_mpdu_res_start { #define TX_CMD_SEC_KEY128 0x08 /* + * security overhead sizes + */ +#define WEP_IV_LEN 4 +#define WEP_ICV_LEN 4 +#define CCMP_MIC_LEN 8 +#define TKIP_ICV_LEN 4 + +/* * 4965 uCode updates these Tx attempt count values in host DRAM. * Used for managing Tx retries when expecting block-acks. * Driver should set these fields to 0. @@ -1113,7 +1249,7 @@ struct iwl4965_dram_scratch { /* * REPLY_TX = 0x1c (command) */ -struct iwl4965_tx_cmd { +struct iwl_tx_cmd { /* * MPDU byte count: * MAC header (24/26/30/32 bytes) + 2 bytes pad if 26/30 header size, @@ -1259,6 +1395,15 @@ enum { TX_ABORT_REQUIRED_MSK = 0x80000000, /* bits 31:31 */ }; +static inline int iwl_is_tx_success(u32 status) +{ + status &= TX_STATUS_MSK; + return (status == TX_STATUS_SUCCESS) + || (status == TX_STATUS_DIRECT_DONE); +} + + + /* ******************************* * TX aggregation status ******************************* */ @@ -1313,6 +1458,11 @@ enum { * within the sending station (this 4965), rather than whether it was * received successfully by the destination station. */ +struct agg_tx_status { + __le16 status; + __le16 sequence; +} __attribute__ ((packed)); + struct iwl4965_tx_resp { u8 frame_count; /* 1 no aggregation, >1 aggregation */ u8 bt_kill_count; /* # blocked by bluetooth (unused for agg) */ @@ -1344,34 +1494,56 @@ struct iwl4965_tx_resp { * table entry used for all frames in the new agg. * 31-16: Sequence # for this frame's Tx cmd (not SSN!) */ - __le32 status; /* TX status (for aggregation status of 1st frame) */ + union { + __le32 status; + struct agg_tx_status agg_status[0]; /* for each agg frame */ + } u; } __attribute__ ((packed)); -struct agg_tx_status { - __le16 status; - __le16 sequence; -} __attribute__ ((packed)); +struct iwl5000_tx_resp { + u8 frame_count; /* 1 no aggregation, >1 aggregation */ + u8 bt_kill_count; /* # blocked by bluetooth (unused for agg) */ + u8 failure_rts; /* # failures due to unsuccessful RTS */ + u8 failure_frame; /* # failures due to no ACK (unused for agg) */ -struct iwl4965_tx_resp_agg { - u8 frame_count; /* 1 no aggregation, >1 aggregation */ - u8 reserved1; - u8 failure_rts; - u8 failure_frame; - __le32 rate_n_flags; - __le16 wireless_media_time; - __le16 reserved3; - __le32 pa_power1; + /* For non-agg: Rate at which frame was successful. + * For agg: Rate at which all frames were transmitted. */ + __le32 rate_n_flags; /* RATE_MCS_* */ + + /* For non-agg: RTS + CTS + frame tx attempts time + ACK. + * For agg: RTS + CTS + aggregation tx time + block-ack time. */ + __le16 wireless_media_time; /* uSecs */ + + __le16 reserved; + __le32 pa_power1; /* RF power amplifier measurement (not used) */ __le32 pa_power2; - struct agg_tx_status status; /* TX status (for aggregation status */ - /* of 1st frame) */ -} __attribute__ ((packed)); + __le32 tfd_info; + __le16 seq_ctl; + __le16 byte_cnt; + __le32 tlc_info; + /* + * For non-agg: frame status TX_STATUS_* + * For agg: status of 1st frame, AGG_TX_STATE_*; other frame status + * fields follow this one, up to frame_count. + * Bit fields: + * 11- 0: AGG_TX_STATE_* status code + * 15-12: Retry count for 1st frame in aggregation (retries + * occur if tx failed for this frame when it was a + * member of a previous aggregation block). If rate + * scaling is used, retry count indicates the rate + * table entry used for all frames in the new agg. + * 31-16: Sequence # for this frame's Tx cmd (not SSN!) + */ + struct agg_tx_status status; /* TX status (in aggregation - + * status of 1st frame) */ +} __attribute__ ((packed)); /* * REPLY_COMPRESSED_BA = 0xc5 (response only, not a command) * * Reports Block-Acknowledge from recipient station */ -struct iwl4965_compressed_ba_resp { +struct iwl_compressed_ba_resp { __le32 sta_addr_lo32; __le16 sta_addr_hi16; __le16 reserved; @@ -1853,6 +2025,7 @@ struct iwl4965_spectrum_notification { #define IWL_POWER_DRIVER_ALLOW_SLEEP_MSK __constant_cpu_to_le16(1 << 0) #define IWL_POWER_SLEEP_OVER_DTIM_MSK __constant_cpu_to_le16(1 << 2) #define IWL_POWER_PCI_PM_MSK __constant_cpu_to_le16(1 << 3) +#define IWL_POWER_FAST_PD __constant_cpu_to_le16(1 << 4) struct iwl4965_powertable_cmd { __le16 flags; @@ -1914,7 +2087,7 @@ struct iwl4965_card_state_notif { #define RF_CARD_DISABLED 0x04 #define RXON_CARD_DISABLED 0x10 -struct iwl4965_ct_kill_config { +struct iwl_ct_kill_config { __le32 reserved; __le32 critical_temperature_M; __le32 critical_temperature_R; @@ -1926,8 +2099,11 @@ struct iwl4965_ct_kill_config { * *****************************************************************************/ +#define SCAN_CHANNEL_TYPE_PASSIVE __constant_cpu_to_le32(0) +#define SCAN_CHANNEL_TYPE_ACTIVE __constant_cpu_to_le32(1) + /** - * struct iwl4965_scan_channel - entry in REPLY_SCAN_CMD channel table + * struct iwl_scan_channel - entry in REPLY_SCAN_CMD channel table * * One for each channel in the scan list. * Each channel can independently select: @@ -1937,7 +2113,7 @@ struct iwl4965_ct_kill_config { * quiet_plcp_th, good_CRC_th) * * To avoid uCode errors, make sure the following are true (see comments - * under struct iwl4965_scan_cmd about max_out_time and quiet_time): + * under struct iwl_scan_cmd about max_out_time and quiet_time): * 1) If using passive_dwell (i.e. passive_dwell != 0): * active_dwell <= passive_dwell (< max_out_time if max_out_time != 0) * 2) quiet_time <= active_dwell @@ -1945,37 +2121,38 @@ struct iwl4965_ct_kill_config { * passive_dwell < max_out_time * active_dwell < max_out_time */ -struct iwl4965_scan_channel { +struct iwl_scan_channel { /* * type is defined as: * 0:0 1 = active, 0 = passive - * 1:4 SSID direct bit map; if a bit is set, then corresponding + * 1:20 SSID direct bit map; if a bit is set, then corresponding * SSID IE is transmitted in probe request. - * 5:7 reserved + * 21:31 reserved */ - u8 type; - u8 channel; /* band is selected by iwl4965_scan_cmd "flags" field */ - struct iwl4965_tx_power tpc; + __le32 type; + __le16 channel; /* band is selected by iwl_scan_cmd "flags" field */ + u8 tx_gain; /* gain for analog radio */ + u8 dsp_atten; /* gain for DSP */ __le16 active_dwell; /* in 1024-uSec TU (time units), typ 5-50 */ __le16 passive_dwell; /* in 1024-uSec TU (time units), typ 20-500 */ } __attribute__ ((packed)); /** - * struct iwl4965_ssid_ie - directed scan network information element + * struct iwl_ssid_ie - directed scan network information element * * Up to 4 of these may appear in REPLY_SCAN_CMD, selected by "type" field * in struct iwl4965_scan_channel; each channel may select different ssids from * among the 4 entries. SSID IEs get transmitted in reverse order of entry. */ -struct iwl4965_ssid_ie { +struct iwl_ssid_ie { u8 id; u8 len; u8 ssid[32]; } __attribute__ ((packed)); -#define PROBE_OPTION_MAX 0x4 +#define PROBE_OPTION_MAX 0x14 #define TX_CMD_LIFE_TIME_INFINITE __constant_cpu_to_le32(0xFFFFFFFF) -#define IWL_GOOD_CRC_TH __constant_cpu_to_le16(1) +#define IWL_GOOD_CRC_TH __constant_cpu_to_le16(1) #define IWL_MAX_SCAN_SIZE 1024 /* @@ -2028,9 +2205,9 @@ struct iwl4965_ssid_ie { * Driver must use separate scan commands for 2.4 vs. 5 GHz bands. * * To avoid uCode errors, see timing restrictions described under - * struct iwl4965_scan_channel. + * struct iwl_scan_channel. */ -struct iwl4965_scan_cmd { +struct iwl_scan_cmd { __le16 len; u8 reserved0; u8 channel_count; /* # channels in channel list */ @@ -2051,10 +2228,10 @@ struct iwl4965_scan_cmd { /* For active scans (set to all-0s for passive scans). * Does not include payload. Must specify Tx rate; no rate scaling. */ - struct iwl4965_tx_cmd tx_cmd; + struct iwl_tx_cmd tx_cmd; /* For directed active scans (set to all-0s otherwise) */ - struct iwl4965_ssid_ie direct_scan[PROBE_OPTION_MAX]; + struct iwl_ssid_ie direct_scan[PROBE_OPTION_MAX]; /* * Probe request frame, followed by channel list. @@ -2082,14 +2259,14 @@ struct iwl4965_scan_cmd { /* * REPLY_SCAN_CMD = 0x80 (response) */ -struct iwl4965_scanreq_notification { +struct iwl_scanreq_notification { __le32 status; /* 1: okay, 2: cannot fulfill request */ } __attribute__ ((packed)); /* * SCAN_START_NOTIFICATION = 0x82 (notification only, not a command) */ -struct iwl4965_scanstart_notification { +struct iwl_scanstart_notification { __le32 tsf_low; __le32 tsf_high; __le32 beacon_timer; @@ -2106,7 +2283,7 @@ struct iwl4965_scanstart_notification { /* * SCAN_RESULTS_NOTIFICATION = 0x83 (notification only, not a command) */ -struct iwl4965_scanresults_notification { +struct iwl_scanresults_notification { u8 channel; u8 band; u8 reserved[2]; @@ -2118,7 +2295,7 @@ struct iwl4965_scanresults_notification { /* * SCAN_COMPLETE_NOTIFICATION = 0x84 (notification only, not a command) */ -struct iwl4965_scancomplete_notification { +struct iwl_scancomplete_notification { u8 scanned_channels; u8 status; u8 reserved; @@ -2148,7 +2325,7 @@ struct iwl4965_beacon_notif { * REPLY_TX_BEACON = 0x91 (command, has simple generic response) */ struct iwl4965_tx_beacon_cmd { - struct iwl4965_tx_cmd tx; + struct iwl_tx_cmd tx; __le16 tim_idx; u8 tim_size; u8 reserved1; @@ -2339,7 +2516,7 @@ struct statistics_general { */ #define IWL_STATS_CONF_CLEAR_STATS __constant_cpu_to_le32(0x1) /* see above */ #define IWL_STATS_CONF_DISABLE_NOTIF __constant_cpu_to_le32(0x2)/* see above */ -struct iwl4965_statistics_cmd { +struct iwl_statistics_cmd { __le32 configuration_flags; /* IWL_STATS_CONF_* */ } __attribute__ ((packed)); @@ -2360,7 +2537,7 @@ struct iwl4965_statistics_cmd { */ #define STATISTICS_REPLY_FLG_BAND_24G_MSK __constant_cpu_to_le32(0x2) #define STATISTICS_REPLY_FLG_FAT_MODE_MSK __constant_cpu_to_le32(0x8) -struct iwl4965_notif_statistics { +struct iwl_notif_statistics { __le32 flag; struct statistics_rx rx; struct statistics_tx tx; @@ -2559,7 +2736,7 @@ struct iwl4965_missed_beacon_notif { */ /* - * Table entries in SENSITIVITY_CMD (struct iwl4965_sensitivity_cmd) + * Table entries in SENSITIVITY_CMD (struct iwl_sensitivity_cmd) */ #define HD_TABLE_SIZE (11) /* number of entries */ #define HD_MIN_ENERGY_CCK_DET_INDEX (0) /* table indexes */ @@ -2574,18 +2751,18 @@ struct iwl4965_missed_beacon_notif { #define HD_AUTO_CORR40_X4_TH_ADD_MIN_INDEX (9) #define HD_OFDM_ENERGY_TH_IN_INDEX (10) -/* Control field in struct iwl4965_sensitivity_cmd */ +/* Control field in struct iwl_sensitivity_cmd */ #define SENSITIVITY_CMD_CONTROL_DEFAULT_TABLE __constant_cpu_to_le16(0) #define SENSITIVITY_CMD_CONTROL_WORK_TABLE __constant_cpu_to_le16(1) /** - * struct iwl4965_sensitivity_cmd + * struct iwl_sensitivity_cmd * @control: (1) updates working table, (0) updates default table * @table: energy threshold values, use HD_* as index into table * * Always use "1" in "control" to update uCode's working table and DSP. */ -struct iwl4965_sensitivity_cmd { +struct iwl_sensitivity_cmd { __le16 control; /* always use "1" */ __le16 table[HD_TABLE_SIZE]; /* use HD_* as index */ } __attribute__ ((packed)); @@ -2659,6 +2836,86 @@ struct iwl4965_calibration_cmd { u8 reserved1; } __attribute__ ((packed)); +/* Phy calibration command for 5000 series */ + +enum { + IWL5000_PHY_CALIBRATE_DC_CMD = 8, + IWL5000_PHY_CALIBRATE_LO_CMD = 9, + IWL5000_PHY_CALIBRATE_RX_BB_CMD = 10, + IWL5000_PHY_CALIBRATE_TX_IQ_CMD = 11, + IWL5000_PHY_CALIBRATE_RX_IQ_CMD = 12, + IWL5000_PHY_CALIBRATION_NOISE_CMD = 13, + IWL5000_PHY_CALIBRATE_AGC_TABLE_CMD = 14, + IWL5000_PHY_CALIBRATE_CRYSTAL_FRQ_CMD = 15, + IWL5000_PHY_CALIBRATE_BASE_BAND_CMD = 16, + IWL5000_PHY_CALIBRATE_TX_IQ_PERD_CMD = 17, + IWL5000_PHY_CALIBRATE_CHAIN_NOISE_RESET_CMD = 18, + IWL5000_PHY_CALIBRATE_CHAIN_NOISE_GAIN_CMD = 19, +}; + +enum { + CALIBRATION_CFG_CMD = 0x65, + CALIBRATION_RES_NOTIFICATION = 0x66, + CALIBRATION_COMPLETE_NOTIFICATION = 0x67 +}; + +struct iwl_cal_crystal_freq_cmd { + u8 cap_pin1; + u8 cap_pin2; +} __attribute__ ((packed)); + +struct iwl5000_calibration { + u8 op_code; + u8 first_group; + u8 num_groups; + u8 all_data_valid; + struct iwl_cal_crystal_freq_cmd data; +} __attribute__ ((packed)); + +#define IWL_CALIB_INIT_CFG_ALL __constant_cpu_to_le32(0xffffffff) + +struct iwl_calib_cfg_elmnt_s { + __le32 is_enable; + __le32 start; + __le32 send_res; + __le32 apply_res; + __le32 reserved; +} __attribute__ ((packed)); + +struct iwl_calib_cfg_status_s { + struct iwl_calib_cfg_elmnt_s once; + struct iwl_calib_cfg_elmnt_s perd; + __le32 flags; +} __attribute__ ((packed)); + +struct iwl5000_calib_cfg_cmd { + struct iwl_calib_cfg_status_s ucd_calib_cfg; + struct iwl_calib_cfg_status_s drv_calib_cfg; + __le32 reserved1; +} __attribute__ ((packed)); + +struct iwl5000_calib_hdr { + u8 op_code; + u8 first_group; + u8 groups_num; + u8 data_valid; +} __attribute__ ((packed)); + +struct iwl5000_calibration_chain_noise_reset_cmd { + u8 op_code; /* IWL5000_PHY_CALIBRATE_CHAIN_NOISE_RESET_CMD */ + u8 flags; /* not used */ + __le16 reserved; +} __attribute__ ((packed)); + +struct iwl5000_calibration_chain_noise_gain_cmd { + u8 op_code; /* IWL5000_PHY_CALIBRATE_CHAIN_NOISE_GAIN_CMD */ + u8 flags; /* not used */ + __le16 reserved; + u8 delta_gain_1; + u8 delta_gain_2; + __le16 reserved1; +} __attribute__ ((packed)); + /****************************************************************************** * (12) * Miscellaneous Commands: @@ -2672,7 +2929,7 @@ struct iwl4965_calibration_cmd { * For each of 3 possible LEDs (Activity/Link/Tech, selected by "id" field), * this command turns it on or off, or sets up a periodic blinking cycle. */ -struct iwl4965_led_cmd { +struct iwl_led_cmd { __le32 interval; /* "interval" in uSec */ u8 id; /* 1: Activity, 2: Link, 3: Tech */ u8 off; /* # intervals off while blinking; @@ -2682,30 +2939,81 @@ struct iwl4965_led_cmd { u8 reserved; } __attribute__ ((packed)); +/* + * Coexistence WIFI/WIMAX Command + * COEX_PRIORITY_TABLE_CMD = 0x5a + * + */ +enum { + COEX_UNASSOC_IDLE = 0, + COEX_UNASSOC_MANUAL_SCAN = 1, + COEX_UNASSOC_AUTO_SCAN = 2, + COEX_CALIBRATION = 3, + COEX_PERIODIC_CALIBRATION = 4, + COEX_CONNECTION_ESTAB = 5, + COEX_ASSOCIATED_IDLE = 6, + COEX_ASSOC_MANUAL_SCAN = 7, + COEX_ASSOC_AUTO_SCAN = 8, + COEX_ASSOC_ACTIVE_LEVEL = 9, + COEX_RF_ON = 10, + COEX_RF_OFF = 11, + COEX_STAND_ALONE_DEBUG = 12, + COEX_IPAN_ASSOC_LEVEL = 13, + COEX_RSRVD1 = 14, + COEX_RSRVD2 = 15, + COEX_NUM_OF_EVENTS = 16 +}; + +struct iwl_wimax_coex_event_entry { + u8 request_prio; + u8 win_medium_prio; + u8 reserved; + u8 flags; +} __attribute__ ((packed)); + +/* COEX flag masks */ + +/* Staion table is valid */ +#define COEX_FLAGS_STA_TABLE_VALID_MSK (0x1) +/* UnMask wakeup src at unassociated sleep */ +#define COEX_FLAGS_UNASSOC_WA_UNMASK_MSK (0x4) +/* UnMask wakeup src at associated sleep */ +#define COEX_FLAGS_ASSOC_WA_UNMASK_MSK (0x8) +/* Enable CoEx feature. */ +#define COEX_FLAGS_COEX_ENABLE_MSK (0x80) + +struct iwl_wimax_coex_cmd { + u8 flags; + u8 reserved[3]; + struct iwl_wimax_coex_event_entry sta_prio[COEX_NUM_OF_EVENTS]; +} __attribute__ ((packed)); + /****************************************************************************** * (13) * Union of all expected notifications/responses: * *****************************************************************************/ -struct iwl4965_rx_packet { +struct iwl_rx_packet { __le32 len; struct iwl_cmd_header hdr; union { - struct iwl4965_alive_resp alive_frame; + struct iwl_alive_resp alive_frame; struct iwl4965_rx_frame rx_frame; struct iwl4965_tx_resp tx_resp; struct iwl4965_spectrum_notification spectrum_notif; struct iwl4965_csa_notification csa_notif; - struct iwl4965_error_resp err_resp; + struct iwl_error_resp err_resp; struct iwl4965_card_state_notif card_state_notif; struct iwl4965_beacon_notif beacon_status; - struct iwl4965_add_sta_resp add_sta; + struct iwl_add_sta_resp add_sta; + struct iwl_rem_sta_resp rem_sta; struct iwl4965_sleep_notification sleep_notif; struct iwl4965_spectrum_resp spectrum; - struct iwl4965_notif_statistics stats; - struct iwl4965_compressed_ba_resp compressed_ba; + struct iwl_notif_statistics stats; + struct iwl_compressed_ba_resp compressed_ba; struct iwl4965_missed_beacon_notif missed_beacon; + struct iwl5000_calibration calib; __le32 status; u8 raw[0]; } u; diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 2dfd982d7d1f..a44188bf4459 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -34,9 +34,11 @@ struct iwl_priv; /* FIXME: remove */ #include "iwl-debug.h" #include "iwl-eeprom.h" -#include "iwl-4965.h" /* FIXME: remove */ +#include "iwl-dev.h" /* FIXME: remove */ #include "iwl-core.h" +#include "iwl-io.h" #include "iwl-rfkill.h" +#include "iwl-power.h" MODULE_DESCRIPTION("iwl core"); @@ -44,10 +46,106 @@ MODULE_VERSION(IWLWIFI_VERSION); MODULE_AUTHOR(DRV_COPYRIGHT); MODULE_LICENSE("GPL"); -#ifdef CONFIG_IWLWIFI_DEBUG -u32 iwl_debug_level; -EXPORT_SYMBOL(iwl_debug_level); -#endif +#define IWL_DECLARE_RATE_INFO(r, s, ip, in, rp, rn, pp, np) \ + [IWL_RATE_##r##M_INDEX] = { IWL_RATE_##r##M_PLCP, \ + IWL_RATE_SISO_##s##M_PLCP, \ + IWL_RATE_MIMO2_##s##M_PLCP,\ + IWL_RATE_MIMO3_##s##M_PLCP,\ + IWL_RATE_##r##M_IEEE, \ + IWL_RATE_##ip##M_INDEX, \ + IWL_RATE_##in##M_INDEX, \ + IWL_RATE_##rp##M_INDEX, \ + IWL_RATE_##rn##M_INDEX, \ + IWL_RATE_##pp##M_INDEX, \ + IWL_RATE_##np##M_INDEX } + +/* + * Parameter order: + * rate, ht rate, prev rate, next rate, prev tgg rate, next tgg rate + * + * If there isn't a valid next or previous rate then INV is used which + * maps to IWL_RATE_INVALID + * + */ +const struct iwl_rate_info iwl_rates[IWL_RATE_COUNT] = { + IWL_DECLARE_RATE_INFO(1, INV, INV, 2, INV, 2, INV, 2), /* 1mbps */ + IWL_DECLARE_RATE_INFO(2, INV, 1, 5, 1, 5, 1, 5), /* 2mbps */ + IWL_DECLARE_RATE_INFO(5, INV, 2, 6, 2, 11, 2, 11), /*5.5mbps */ + IWL_DECLARE_RATE_INFO(11, INV, 9, 12, 9, 12, 5, 18), /* 11mbps */ + IWL_DECLARE_RATE_INFO(6, 6, 5, 9, 5, 11, 5, 11), /* 6mbps */ + IWL_DECLARE_RATE_INFO(9, 6, 6, 11, 6, 11, 5, 11), /* 9mbps */ + IWL_DECLARE_RATE_INFO(12, 12, 11, 18, 11, 18, 11, 18), /* 12mbps */ + IWL_DECLARE_RATE_INFO(18, 18, 12, 24, 12, 24, 11, 24), /* 18mbps */ + IWL_DECLARE_RATE_INFO(24, 24, 18, 36, 18, 36, 18, 36), /* 24mbps */ + IWL_DECLARE_RATE_INFO(36, 36, 24, 48, 24, 48, 24, 48), /* 36mbps */ + IWL_DECLARE_RATE_INFO(48, 48, 36, 54, 36, 54, 36, 54), /* 48mbps */ + IWL_DECLARE_RATE_INFO(54, 54, 48, INV, 48, INV, 48, INV),/* 54mbps */ + IWL_DECLARE_RATE_INFO(60, 60, 48, INV, 48, INV, 48, INV),/* 60mbps */ + /* FIXME:RS: ^^ should be INV (legacy) */ +}; +EXPORT_SYMBOL(iwl_rates); + +/** + * translate ucode response to mac80211 tx status control values + */ +void iwl_hwrate_to_tx_control(struct iwl_priv *priv, u32 rate_n_flags, + struct ieee80211_tx_info *control) +{ + int rate_index; + + control->antenna_sel_tx = + ((rate_n_flags & RATE_MCS_ANT_ABC_MSK) >> RATE_MCS_ANT_POS); + if (rate_n_flags & RATE_MCS_HT_MSK) + control->flags |= IEEE80211_TX_CTL_OFDM_HT; + if (rate_n_flags & RATE_MCS_GF_MSK) + control->flags |= IEEE80211_TX_CTL_GREEN_FIELD; + if (rate_n_flags & RATE_MCS_FAT_MSK) + control->flags |= IEEE80211_TX_CTL_40_MHZ_WIDTH; + if (rate_n_flags & RATE_MCS_DUP_MSK) + control->flags |= IEEE80211_TX_CTL_DUP_DATA; + if (rate_n_flags & RATE_MCS_SGI_MSK) + control->flags |= IEEE80211_TX_CTL_SHORT_GI; + rate_index = iwl_hwrate_to_plcp_idx(rate_n_flags); + if (control->band == IEEE80211_BAND_5GHZ) + rate_index -= IWL_FIRST_OFDM_RATE; + control->tx_rate_idx = rate_index; +} +EXPORT_SYMBOL(iwl_hwrate_to_tx_control); + +int iwl_hwrate_to_plcp_idx(u32 rate_n_flags) +{ + int idx = 0; + + /* HT rate format */ + if (rate_n_flags & RATE_MCS_HT_MSK) { + idx = (rate_n_flags & 0xff); + + if (idx >= IWL_RATE_MIMO2_6M_PLCP) + idx = idx - IWL_RATE_MIMO2_6M_PLCP; + + idx += IWL_FIRST_OFDM_RATE; + /* skip 9M not supported in ht*/ + if (idx >= IWL_RATE_9M_INDEX) + idx += 1; + if ((idx >= IWL_FIRST_OFDM_RATE) && (idx <= IWL_LAST_OFDM_RATE)) + return idx; + + /* legacy rate format, search for match in table */ + } else { + for (idx = 0; idx < ARRAY_SIZE(iwl_rates); idx++) + if (iwl_rates[idx].plcp == (rate_n_flags & 0xFF)) + return idx; + } + + return -1; +} +EXPORT_SYMBOL(iwl_hwrate_to_plcp_idx); + + + +const u8 iwl_bcast_addr[ETH_ALEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; +EXPORT_SYMBOL(iwl_bcast_addr); + /* This function both allocates and initializes hw and priv. */ struct ieee80211_hw *iwl_alloc_all(struct iwl_cfg *cfg, @@ -72,25 +170,132 @@ out: } EXPORT_SYMBOL(iwl_alloc_all); +void iwl_hw_detect(struct iwl_priv *priv) +{ + priv->hw_rev = _iwl_read32(priv, CSR_HW_REV); + priv->hw_wa_rev = _iwl_read32(priv, CSR_HW_REV_WA_REG); + pci_read_config_byte(priv->pci_dev, PCI_REVISION_ID, &priv->rev_id); +} +EXPORT_SYMBOL(iwl_hw_detect); + +/* Tell nic where to find the "keep warm" buffer */ +int iwl_kw_init(struct iwl_priv *priv) +{ + unsigned long flags; + int ret; + + spin_lock_irqsave(&priv->lock, flags); + ret = iwl_grab_nic_access(priv); + if (ret) + goto out; + + iwl_write_direct32(priv, FH_KW_MEM_ADDR_REG, + priv->kw.dma_addr >> 4); + iwl_release_nic_access(priv); +out: + spin_unlock_irqrestore(&priv->lock, flags); + return ret; +} + +int iwl_kw_alloc(struct iwl_priv *priv) +{ + struct pci_dev *dev = priv->pci_dev; + struct iwl_kw *kw = &priv->kw; + + kw->size = IWL_KW_SIZE; + kw->v_addr = pci_alloc_consistent(dev, kw->size, &kw->dma_addr); + if (!kw->v_addr) + return -ENOMEM; + + return 0; +} + +/** + * iwl_kw_free - Free the "keep warm" buffer + */ +void iwl_kw_free(struct iwl_priv *priv) +{ + struct pci_dev *dev = priv->pci_dev; + struct iwl_kw *kw = &priv->kw; + + if (kw->v_addr) { + pci_free_consistent(dev, kw->size, kw->v_addr, kw->dma_addr); + memset(kw, 0, sizeof(*kw)); + } +} + +int iwl_hw_nic_init(struct iwl_priv *priv) +{ + unsigned long flags; + struct iwl_rx_queue *rxq = &priv->rxq; + int ret; + + /* nic_init */ + spin_lock_irqsave(&priv->lock, flags); + priv->cfg->ops->lib->apm_ops.init(priv); + iwl_write32(priv, CSR_INT_COALESCING, 512 / 32); + spin_unlock_irqrestore(&priv->lock, flags); + + ret = priv->cfg->ops->lib->apm_ops.set_pwr_src(priv, IWL_PWR_SRC_VMAIN); + + priv->cfg->ops->lib->apm_ops.config(priv); + + /* Allocate the RX queue, or reset if it is already allocated */ + if (!rxq->bd) { + ret = iwl_rx_queue_alloc(priv); + if (ret) { + IWL_ERROR("Unable to initialize Rx queue\n"); + return -ENOMEM; + } + } else + iwl_rx_queue_reset(priv, rxq); + + iwl_rx_replenish(priv); + + iwl_rx_init(priv, rxq); + + spin_lock_irqsave(&priv->lock, flags); + + rxq->need_update = 1; + iwl_rx_queue_update_write_ptr(priv, rxq); + + spin_unlock_irqrestore(&priv->lock, flags); + + /* Allocate and init all Tx and Command queues */ + ret = iwl_txq_ctx_reset(priv); + if (ret) + return ret; + + set_bit(STATUS_INIT, &priv->status); + + return 0; +} +EXPORT_SYMBOL(iwl_hw_nic_init); + /** - * iwlcore_clear_stations_table - Clear the driver's station table + * iwl_clear_stations_table - Clear the driver's station table * * NOTE: This does not clear or otherwise alter the device's station table. */ -void iwlcore_clear_stations_table(struct iwl_priv *priv) +void iwl_clear_stations_table(struct iwl_priv *priv) { unsigned long flags; spin_lock_irqsave(&priv->sta_lock, flags); + if (iwl_is_alive(priv) && + !test_bit(STATUS_EXIT_PENDING, &priv->status) && + iwl_send_cmd_pdu_async(priv, REPLY_REMOVE_ALL_STA, 0, NULL, NULL)) + IWL_ERROR("Couldn't clear the station table\n"); + priv->num_stations = 0; memset(priv->stations, 0, sizeof(priv->stations)); spin_unlock_irqrestore(&priv->sta_lock, flags); } -EXPORT_SYMBOL(iwlcore_clear_stations_table); +EXPORT_SYMBOL(iwl_clear_stations_table); -void iwlcore_reset_qos(struct iwl_priv *priv) +void iwl_reset_qos(struct iwl_priv *priv) { u16 cw_min = 15; u16 cw_max = 1023; @@ -176,7 +381,397 @@ void iwlcore_reset_qos(struct iwl_priv *priv) spin_unlock_irqrestore(&priv->lock, flags); } -EXPORT_SYMBOL(iwlcore_reset_qos); +EXPORT_SYMBOL(iwl_reset_qos); + +#define MAX_BIT_RATE_40_MHZ 0x96; /* 150 Mbps */ +#define MAX_BIT_RATE_20_MHZ 0x48; /* 72 Mbps */ +static void iwlcore_init_ht_hw_capab(const struct iwl_priv *priv, + struct ieee80211_ht_info *ht_info, + enum ieee80211_band band) +{ + u16 max_bit_rate = 0; + u8 rx_chains_num = priv->hw_params.rx_chains_num; + u8 tx_chains_num = priv->hw_params.tx_chains_num; + + ht_info->cap = 0; + memset(ht_info->supp_mcs_set, 0, 16); + + ht_info->ht_supported = 1; + + ht_info->cap |= (u16)IEEE80211_HT_CAP_GRN_FLD; + ht_info->cap |= (u16)IEEE80211_HT_CAP_SGI_20; + ht_info->cap |= (u16)(IEEE80211_HT_CAP_MIMO_PS & + (IWL_MIMO_PS_NONE << 2)); + + max_bit_rate = MAX_BIT_RATE_20_MHZ; + if (priv->hw_params.fat_channel & BIT(band)) { + ht_info->cap |= (u16)IEEE80211_HT_CAP_SUP_WIDTH; + ht_info->cap |= (u16)IEEE80211_HT_CAP_SGI_40; + ht_info->supp_mcs_set[4] = 0x01; + max_bit_rate = MAX_BIT_RATE_40_MHZ; + } + + if (priv->cfg->mod_params->amsdu_size_8K) + ht_info->cap |= (u16)IEEE80211_HT_CAP_MAX_AMSDU; + + ht_info->ampdu_factor = CFG_HT_RX_AMPDU_FACTOR_DEF; + ht_info->ampdu_density = CFG_HT_MPDU_DENSITY_DEF; + + ht_info->supp_mcs_set[0] = 0xFF; + if (rx_chains_num >= 2) + ht_info->supp_mcs_set[1] = 0xFF; + if (rx_chains_num >= 3) + ht_info->supp_mcs_set[2] = 0xFF; + + /* Highest supported Rx data rate */ + max_bit_rate *= rx_chains_num; + ht_info->supp_mcs_set[10] = (u8)(max_bit_rate & 0x00FF); + ht_info->supp_mcs_set[11] = (u8)((max_bit_rate & 0xFF00) >> 8); + + /* Tx MCS capabilities */ + ht_info->supp_mcs_set[12] = IEEE80211_HT_CAP_MCS_TX_DEFINED; + if (tx_chains_num != rx_chains_num) { + ht_info->supp_mcs_set[12] |= IEEE80211_HT_CAP_MCS_TX_RX_DIFF; + ht_info->supp_mcs_set[12] |= ((tx_chains_num - 1) << 2); + } +} + +static void iwlcore_init_hw_rates(struct iwl_priv *priv, + struct ieee80211_rate *rates) +{ + int i; + + for (i = 0; i < IWL_RATE_COUNT; i++) { + rates[i].bitrate = iwl_rates[i].ieee * 5; + rates[i].hw_value = i; /* Rate scaling will work on indexes */ + rates[i].hw_value_short = i; + rates[i].flags = 0; + if ((i > IWL_LAST_OFDM_RATE) || (i < IWL_FIRST_OFDM_RATE)) { + /* + * If CCK != 1M then set short preamble rate flag. + */ + rates[i].flags |= + (iwl_rates[i].plcp == IWL_RATE_1M_PLCP) ? + 0 : IEEE80211_RATE_SHORT_PREAMBLE; + } + } +} + +/** + * iwlcore_init_geos - Initialize mac80211's geo/channel info based from eeprom + */ +static int iwlcore_init_geos(struct iwl_priv *priv) +{ + struct iwl_channel_info *ch; + struct ieee80211_supported_band *sband; + struct ieee80211_channel *channels; + struct ieee80211_channel *geo_ch; + struct ieee80211_rate *rates; + int i = 0; + + if (priv->bands[IEEE80211_BAND_2GHZ].n_bitrates || + priv->bands[IEEE80211_BAND_5GHZ].n_bitrates) { + IWL_DEBUG_INFO("Geography modes already initialized.\n"); + set_bit(STATUS_GEO_CONFIGURED, &priv->status); + return 0; + } + + channels = kzalloc(sizeof(struct ieee80211_channel) * + priv->channel_count, GFP_KERNEL); + if (!channels) + return -ENOMEM; + + rates = kzalloc((sizeof(struct ieee80211_rate) * (IWL_RATE_COUNT + 1)), + GFP_KERNEL); + if (!rates) { + kfree(channels); + return -ENOMEM; + } + + /* 5.2GHz channels start after the 2.4GHz channels */ + sband = &priv->bands[IEEE80211_BAND_5GHZ]; + sband->channels = &channels[ARRAY_SIZE(iwl_eeprom_band_1)]; + /* just OFDM */ + sband->bitrates = &rates[IWL_FIRST_OFDM_RATE]; + sband->n_bitrates = IWL_RATE_COUNT - IWL_FIRST_OFDM_RATE; + + if (priv->cfg->sku & IWL_SKU_N) + iwlcore_init_ht_hw_capab(priv, &sband->ht_info, + IEEE80211_BAND_5GHZ); + + sband = &priv->bands[IEEE80211_BAND_2GHZ]; + sband->channels = channels; + /* OFDM & CCK */ + sband->bitrates = rates; + sband->n_bitrates = IWL_RATE_COUNT; + + if (priv->cfg->sku & IWL_SKU_N) + iwlcore_init_ht_hw_capab(priv, &sband->ht_info, + IEEE80211_BAND_2GHZ); + + priv->ieee_channels = channels; + priv->ieee_rates = rates; + + iwlcore_init_hw_rates(priv, rates); + + for (i = 0; i < priv->channel_count; i++) { + ch = &priv->channel_info[i]; + + /* FIXME: might be removed if scan is OK */ + if (!is_channel_valid(ch)) + continue; + + if (is_channel_a_band(ch)) + sband = &priv->bands[IEEE80211_BAND_5GHZ]; + else + sband = &priv->bands[IEEE80211_BAND_2GHZ]; + + geo_ch = &sband->channels[sband->n_channels++]; + + geo_ch->center_freq = + ieee80211_channel_to_frequency(ch->channel); + geo_ch->max_power = ch->max_power_avg; + geo_ch->max_antenna_gain = 0xff; + geo_ch->hw_value = ch->channel; + + if (is_channel_valid(ch)) { + if (!(ch->flags & EEPROM_CHANNEL_IBSS)) + geo_ch->flags |= IEEE80211_CHAN_NO_IBSS; + + if (!(ch->flags & EEPROM_CHANNEL_ACTIVE)) + geo_ch->flags |= IEEE80211_CHAN_PASSIVE_SCAN; + + if (ch->flags & EEPROM_CHANNEL_RADAR) + geo_ch->flags |= IEEE80211_CHAN_RADAR; + + geo_ch->flags |= ch->fat_extension_channel; + + if (ch->max_power_avg > priv->tx_power_channel_lmt) + priv->tx_power_channel_lmt = ch->max_power_avg; + } else { + geo_ch->flags |= IEEE80211_CHAN_DISABLED; + } + + /* Save flags for reg domain usage */ + geo_ch->orig_flags = geo_ch->flags; + + IWL_DEBUG_INFO("Channel %d Freq=%d[%sGHz] %s flag=0x%X\n", + ch->channel, geo_ch->center_freq, + is_channel_a_band(ch) ? "5.2" : "2.4", + geo_ch->flags & IEEE80211_CHAN_DISABLED ? + "restricted" : "valid", + geo_ch->flags); + } + + if ((priv->bands[IEEE80211_BAND_5GHZ].n_channels == 0) && + priv->cfg->sku & IWL_SKU_A) { + printk(KERN_INFO DRV_NAME + ": Incorrectly detected BG card as ABG. Please send " + "your PCI ID 0x%04X:0x%04X to maintainer.\n", + priv->pci_dev->device, priv->pci_dev->subsystem_device); + priv->cfg->sku &= ~IWL_SKU_A; + } + + printk(KERN_INFO DRV_NAME + ": Tunable channels: %d 802.11bg, %d 802.11a channels\n", + priv->bands[IEEE80211_BAND_2GHZ].n_channels, + priv->bands[IEEE80211_BAND_5GHZ].n_channels); + + + set_bit(STATUS_GEO_CONFIGURED, &priv->status); + + return 0; +} + +/* + * iwlcore_free_geos - undo allocations in iwlcore_init_geos + */ +static void iwlcore_free_geos(struct iwl_priv *priv) +{ + kfree(priv->ieee_channels); + kfree(priv->ieee_rates); + clear_bit(STATUS_GEO_CONFIGURED, &priv->status); +} + +static u8 is_single_rx_stream(struct iwl_priv *priv) +{ + return !priv->current_ht_config.is_ht || + ((priv->current_ht_config.supp_mcs_set[1] == 0) && + (priv->current_ht_config.supp_mcs_set[2] == 0)) || + priv->ps_mode == IWL_MIMO_PS_STATIC; +} + +static u8 iwl_is_channel_extension(struct iwl_priv *priv, + enum ieee80211_band band, + u16 channel, u8 extension_chan_offset) +{ + const struct iwl_channel_info *ch_info; + + ch_info = iwl_get_channel_info(priv, band, channel); + if (!is_channel_valid(ch_info)) + return 0; + + if (extension_chan_offset == IEEE80211_HT_IE_CHA_SEC_ABOVE) + return !(ch_info->fat_extension_channel & + IEEE80211_CHAN_NO_FAT_ABOVE); + else if (extension_chan_offset == IEEE80211_HT_IE_CHA_SEC_BELOW) + return !(ch_info->fat_extension_channel & + IEEE80211_CHAN_NO_FAT_BELOW); + + return 0; +} + +u8 iwl_is_fat_tx_allowed(struct iwl_priv *priv, + struct ieee80211_ht_info *sta_ht_inf) +{ + 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_IE_CHA_SEC_NONE)) + return 0; + + if (sta_ht_inf) { + if ((!sta_ht_inf->ht_supported) || + (!(sta_ht_inf->cap & IEEE80211_HT_CAP_SUP_WIDTH))) + return 0; + } + + return iwl_is_channel_extension(priv, priv->band, + iwl_ht_conf->control_channel, + iwl_ht_conf->extension_chan_offset); +} +EXPORT_SYMBOL(iwl_is_fat_tx_allowed); + +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) + 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); + + if (le16_to_cpu(rxon->channel) != ht_info->control_channel) { + IWL_DEBUG_ASSOC("control diff than current %d %d\n", + le16_to_cpu(rxon->channel), + ht_info->control_channel); + return; + } + + /* Note: control channel is opposite of extension channel */ + switch (ht_info->extension_chan_offset) { + case IEEE80211_HT_IE_CHA_SEC_ABOVE: + rxon->flags &= ~(RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK); + break; + case IEEE80211_HT_IE_CHA_SEC_BELOW: + rxon->flags |= RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK; + break; + case IEEE80211_HT_IE_CHA_SEC_NONE: + default: + rxon->flags &= ~RXON_FLG_CHANNEL_MODE_MIXED_MSK; + break; + } + + val = ht_info->ht_protection; + + rxon->flags |= cpu_to_le32(val << RXON_FLG_HT_OPERATING_MODE_POS); + + iwl_set_rxon_chain(priv); + + IWL_DEBUG_ASSOC("supported HT rate 0x%X 0x%X 0x%X " + "rxon flags 0x%X operation mode :0x%X " + "extension channel offset 0x%x " + "control chan %d\n", + ht_info->supp_mcs_set[0], + ht_info->supp_mcs_set[1], + ht_info->supp_mcs_set[2], + le32_to_cpu(rxon->flags), ht_info->ht_protection, + ht_info->extension_chan_offset, + ht_info->control_channel); + return; +} +EXPORT_SYMBOL(iwl_set_rxon_ht); + +/* + * Determine how many receiver/antenna chains to use. + * More provides better reception via diversity. Fewer saves power. + * MIMO (dual stream) requires at least 2, but works better with 3. + * This does not determine *which* chains to use, just how many. + */ +static int iwlcore_get_rx_chain_counter(struct iwl_priv *priv, + u8 *idle_state, u8 *rx_state) +{ + u8 is_single = is_single_rx_stream(priv); + u8 is_cam = test_bit(STATUS_POWER_PMI, &priv->status) ? 0 : 1; + + /* # of Rx chains to use when expecting MIMO. */ + if (is_single || (!is_cam && (priv->ps_mode == IWL_MIMO_PS_STATIC))) + *rx_state = 2; + else + *rx_state = 3; + + /* # Rx chains when idling and maybe trying to save power */ + switch (priv->ps_mode) { + case IWL_MIMO_PS_STATIC: + case IWL_MIMO_PS_DYNAMIC: + *idle_state = (is_cam) ? 2 : 1; + break; + case IWL_MIMO_PS_NONE: + *idle_state = (is_cam) ? *rx_state : 1; + break; + default: + *idle_state = 1; + break; + } + + return 0; +} + +/** + * iwl_set_rxon_chain - Set up Rx chain usage in "staging" RXON image + * + * Selects how many and which Rx receivers/antennas/chains to use. + * This should not be used for scan command ... it puts data in wrong place. + */ +void iwl_set_rxon_chain(struct iwl_priv *priv) +{ + u8 is_single = is_single_rx_stream(priv); + u8 idle_state, rx_state; + + priv->staging_rxon.rx_chain = 0; + rx_state = idle_state = 3; + + /* Tell uCode which antennas are actually connected. + * Before first association, we assume all antennas are connected. + * Just after first association, iwl_chain_noise_calibration() + * checks which antennas actually *are* connected. */ + priv->staging_rxon.rx_chain |= + cpu_to_le16(priv->hw_params.valid_rx_ant << + RXON_RX_CHAIN_VALID_POS); + + /* How many receivers should we use? */ + iwlcore_get_rx_chain_counter(priv, &idle_state, &rx_state); + priv->staging_rxon.rx_chain |= + cpu_to_le16(rx_state << RXON_RX_CHAIN_MIMO_CNT_POS); + priv->staging_rxon.rx_chain |= + cpu_to_le16(idle_state << RXON_RX_CHAIN_CNT_POS); + + if (!is_single && (rx_state >= 2) && + !test_bit(STATUS_POWER_PMI, &priv->status)) + priv->staging_rxon.rx_chain |= RXON_RX_CHAIN_MIMO_FORCE_MSK; + else + priv->staging_rxon.rx_chain &= ~RXON_RX_CHAIN_MIMO_FORCE_MSK; + + IWL_DEBUG_ASSOC("rx chain %X\n", priv->staging_rxon.rx_chain); +} +EXPORT_SYMBOL(iwl_set_rxon_chain); /** * iwlcore_set_rxon_channel - Set the phymode and channel values in staging RXON @@ -188,7 +783,7 @@ EXPORT_SYMBOL(iwlcore_reset_qos); * NOTE: Does not commit to the hardware; it sets appropriate bit fields * in the staging RXON flag structure based on the phymode */ -int iwlcore_set_rxon_channel(struct iwl_priv *priv, +int iwl_set_rxon_channel(struct iwl_priv *priv, enum ieee80211_band band, u16 channel) { @@ -214,68 +809,185 @@ int iwlcore_set_rxon_channel(struct iwl_priv *priv, return 0; } -EXPORT_SYMBOL(iwlcore_set_rxon_channel); +EXPORT_SYMBOL(iwl_set_rxon_channel); -static void iwlcore_init_hw(struct iwl_priv *priv) +int iwl_setup_mac(struct iwl_priv *priv) { + int ret; struct ieee80211_hw *hw = priv->hw; hw->rate_control_algorithm = "iwl-4965-rs"; - /* Tell mac80211 and its clients (e.g. Wireless Extensions) - * the range of signal quality values that we'll provide. - * Negative values for level/noise indicate that we'll provide dBm. - * For WE, at least, non-0 values here *enable* display of values - * in app (iwconfig). */ - hw->max_rssi = -20; /* signal level, negative indicates dBm */ - hw->max_noise = -20; /* noise level, negative indicates dBm */ - hw->max_signal = 100; /* link quality indication (%) */ - - /* Tell mac80211 our Tx characteristics */ - hw->flags = IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE; - + /* Tell mac80211 our characteristics */ + hw->flags = IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE | + IEEE80211_HW_SIGNAL_DBM | + IEEE80211_HW_NOISE_DBM; /* Default value; 4 EDCA QOS priorities */ hw->queues = 4; -#ifdef CONFIG_IWL4965_HT - /* Enhanced value; more queues, to support 11n aggregation */ - hw->queues = 16; -#endif /* CONFIG_IWL4965_HT */ + /* queues to support 11n aggregation */ + if (priv->cfg->sku & IWL_SKU_N) + hw->ampdu_queues = priv->cfg->mod_params->num_of_ampdu_queues; + + 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]; + if (priv->bands[IEEE80211_BAND_5GHZ].n_channels) + priv->hw->wiphy->bands[IEEE80211_BAND_5GHZ] = + &priv->bands[IEEE80211_BAND_5GHZ]; + + ret = ieee80211_register_hw(priv->hw); + if (ret) { + IWL_ERROR("Failed to register hw (error %d)\n", ret); + return ret; + } + priv->mac80211_registered = 1; + + return 0; } +EXPORT_SYMBOL(iwl_setup_mac); -int iwl_setup(struct iwl_priv *priv) +int iwl_set_hw_params(struct iwl_priv *priv) { - int ret = 0; - iwlcore_init_hw(priv); - ret = priv->cfg->ops->lib->init_drv(priv); - return ret; + priv->hw_params.sw_crypto = priv->cfg->mod_params->sw_crypto; + priv->hw_params.max_rxq_size = RX_QUEUE_SIZE; + priv->hw_params.max_rxq_log = RX_QUEUE_SIZE_LOG; + if (priv->cfg->mod_params->amsdu_size_8K) + priv->hw_params.rx_buf_size = IWL_RX_BUF_SIZE_8K; + else + priv->hw_params.rx_buf_size = IWL_RX_BUF_SIZE_4K; + priv->hw_params.max_pkt_size = priv->hw_params.rx_buf_size - 256; + + if (priv->cfg->mod_params->disable_11n) + priv->cfg->sku &= ~IWL_SKU_N; + + /* Device-specific setup */ + return priv->cfg->ops->lib->set_hw_params(priv); } -EXPORT_SYMBOL(iwl_setup); +EXPORT_SYMBOL(iwl_set_hw_params); -/* Low level driver call this function to update iwlcore with - * driver status. - */ -int iwlcore_low_level_notify(struct iwl_priv *priv, - enum iwlcore_card_notify notify) +int iwl_init_drv(struct iwl_priv *priv) { int ret; - switch (notify) { - case IWLCORE_INIT_EVT: - ret = iwl_rfkill_init(priv); - if (ret) - IWL_ERROR("Unable to initialize RFKILL system. " - "Ignoring error: %d\n", ret); - break; - case IWLCORE_START_EVT: - break; - case IWLCORE_STOP_EVT: - break; - case IWLCORE_REMOVE_EVT: - iwl_rfkill_unregister(priv); - break; + + priv->retry_rate = 1; + 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); + spin_lock_init(&priv->lq_mngr.lock); + + INIT_LIST_HEAD(&priv->free_frames); + + mutex_init(&priv->mutex); + + /* Clear the driver's (not device's) station table */ + iwl_clear_stations_table(priv); + + priv->data_retry_limit = -1; + priv->ieee_channels = NULL; + priv->ieee_rates = NULL; + priv->band = IEEE80211_BAND_2GHZ; + + priv->iw_mode = IEEE80211_IF_TYPE_STA; + + priv->use_ant_b_for_management_frame = 1; /* start with ant B */ + priv->ps_mode = IWL_MIMO_PS_NONE; + + /* Choose which receivers/antennas to use */ + iwl_set_rxon_chain(priv); + iwl_init_scan_params(priv); + + if (priv->cfg->mod_params->enable_qos) + priv->qos_data.qos_enable = 1; + + iwl_reset_qos(priv); + + priv->qos_data.qos_active = 0; + priv->qos_data.qos_cap.val = 0; + + iwl_set_rxon_channel(priv, IEEE80211_BAND_2GHZ, 6); + + priv->rates_mask = IWL_RATES_MASK; + /* If power management is turned on, default to AC mode */ + priv->power_mode = IWL_POWER_AC; + priv->tx_power_user_lmt = IWL_TX_POWER_TARGET_POWER_MAX; + + ret = iwl_init_channel_map(priv); + if (ret) { + IWL_ERROR("initializing regulatory failed: %d\n", ret); + goto err; + } + + ret = iwlcore_init_geos(priv); + if (ret) { + IWL_ERROR("initializing geos failed: %d\n", ret); + goto err_free_channel_map; } return 0; + +err_free_channel_map: + iwl_free_channel_map(priv); +err: + return ret; +} +EXPORT_SYMBOL(iwl_init_drv); + +void iwl_free_calib_results(struct iwl_priv *priv) +{ + kfree(priv->calib_results.lo_res); + priv->calib_results.lo_res = NULL; + priv->calib_results.lo_res_len = 0; + + kfree(priv->calib_results.tx_iq_res); + priv->calib_results.tx_iq_res = NULL; + priv->calib_results.tx_iq_res_len = 0; + + kfree(priv->calib_results.tx_iq_perd_res); + priv->calib_results.tx_iq_perd_res = NULL; + priv->calib_results.tx_iq_perd_res_len = 0; +} +EXPORT_SYMBOL(iwl_free_calib_results); + +int iwl_set_tx_power(struct iwl_priv *priv, s8 tx_power, bool force) +{ + int ret = 0; + if (tx_power < IWL_TX_POWER_TARGET_POWER_MIN) { + IWL_WARNING("Requested user TXPOWER %d below limit.\n", + priv->tx_power_user_lmt); + return -EINVAL; + } + + if (tx_power > IWL_TX_POWER_TARGET_POWER_MAX) { + IWL_WARNING("Requested user TXPOWER %d above limit.\n", + priv->tx_power_user_lmt); + return -EINVAL; + } + + if (priv->tx_power_user_lmt != tx_power) + force = true; + + priv->tx_power_user_lmt = tx_power; + + if (force && priv->cfg->ops->lib->send_tx_power) + ret = priv->cfg->ops->lib->send_tx_power(priv); + + return ret; +} +EXPORT_SYMBOL(iwl_set_tx_power); + + +void iwl_uninit_drv(struct iwl_priv *priv) +{ + iwl_free_calib_results(priv); + iwlcore_free_geos(priv); + iwl_free_channel_map(priv); + kfree(priv->scan); } -EXPORT_SYMBOL(iwlcore_low_level_notify); +EXPORT_SYMBOL(iwl_uninit_drv); int iwl_send_statistics_request(struct iwl_priv *priv, u8 flags) { @@ -290,3 +1002,440 @@ int iwl_send_statistics_request(struct iwl_priv *priv, u8 flags) } EXPORT_SYMBOL(iwl_send_statistics_request); +/** + * iwl_verify_inst_sparse - verify runtime uCode image in card vs. host, + * using sample data 100 bytes apart. If these sample points are good, + * it's a pretty good bet that everything between them is good, too. + */ +static int iwlcore_verify_inst_sparse(struct iwl_priv *priv, __le32 *image, u32 len) +{ + u32 val; + int ret = 0; + u32 errcnt = 0; + u32 i; + + IWL_DEBUG_INFO("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 + * if IWL_DL_IO is set */ + iwl_write_direct32(priv, HBUS_TARG_MEM_RADDR, + i + RTC_INST_LOWER_BOUND); + val = _iwl_read_direct32(priv, HBUS_TARG_MEM_RDAT); + if (val != le32_to_cpu(*image)) { + ret = -EIO; + errcnt++; + if (errcnt >= 3) + break; + } + } + + iwl_release_nic_access(priv); + + return ret; +} + +/** + * iwlcore_verify_inst_full - verify runtime uCode image in card vs. host, + * looking at all data. + */ +static int iwl_verify_inst_full(struct iwl_priv *priv, __le32 *image, + u32 len) +{ + u32 val; + u32 save_len = len; + int ret = 0; + u32 errcnt; + + IWL_DEBUG_INFO("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, RTC_INST_LOWER_BOUND); + + errcnt = 0; + for (; len > 0; len -= sizeof(u32), image++) { + /* read data comes through single port, auto-incr addr */ + /* NOTE: Use the debugless read so we don't flood kernel log + * if IWL_DL_IO is set */ + val = _iwl_read_direct32(priv, HBUS_TARG_MEM_RDAT); + if (val != le32_to_cpu(*image)) { + IWL_ERROR("uCode INST section is invalid at " + "offset 0x%x, is 0x%x, s/b 0x%x\n", + save_len - len, val, le32_to_cpu(*image)); + ret = -EIO; + errcnt++; + if (errcnt >= 20) + break; + } + } + + iwl_release_nic_access(priv); + + if (!errcnt) + IWL_DEBUG_INFO + ("ucode image in INSTRUCTION memory is good\n"); + + return ret; +} + +/** + * iwl_verify_ucode - determine which instruction image is in SRAM, + * and verify its contents + */ +int iwl_verify_ucode(struct iwl_priv *priv) +{ + __le32 *image; + u32 len; + int ret; + + /* Try bootstrap */ + image = (__le32 *)priv->ucode_boot.v_addr; + len = priv->ucode_boot.len; + ret = iwlcore_verify_inst_sparse(priv, image, len); + if (!ret) { + IWL_DEBUG_INFO("Bootstrap uCode is good in inst SRAM\n"); + return 0; + } + + /* Try initialize */ + image = (__le32 *)priv->ucode_init.v_addr; + len = priv->ucode_init.len; + ret = iwlcore_verify_inst_sparse(priv, image, len); + if (!ret) { + IWL_DEBUG_INFO("Initialize uCode is good in inst SRAM\n"); + return 0; + } + + /* Try runtime/protocol */ + image = (__le32 *)priv->ucode_code.v_addr; + len = priv->ucode_code.len; + ret = iwlcore_verify_inst_sparse(priv, image, len); + if (!ret) { + IWL_DEBUG_INFO("Runtime uCode is good in inst SRAM\n"); + return 0; + } + + IWL_ERROR("NO VALID UCODE IMAGE IN INSTRUCTION SRAM!!\n"); + + /* Since nothing seems to match, show first several data entries in + * instruction SRAM, so maybe visual inspection will give a clue. + * Selection of bootstrap image (vs. other images) is arbitrary. */ + image = (__le32 *)priv->ucode_boot.v_addr; + len = priv->ucode_boot.len; + ret = iwl_verify_inst_full(priv, image, len); + + return ret; +} +EXPORT_SYMBOL(iwl_verify_ucode); + + +static const char *desc_lookup(int i) +{ + switch (i) { + case 1: + return "FAIL"; + case 2: + return "BAD_PARAM"; + case 3: + return "BAD_CHECKSUM"; + case 4: + return "NMI_INTERRUPT"; + case 5: + return "SYSASSERT"; + case 6: + return "FATAL_ERROR"; + } + + return "UNKNOWN"; +} + +#define ERROR_START_OFFSET (1 * sizeof(u32)) +#define ERROR_ELEM_SIZE (7 * sizeof(u32)) + +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); + else + base = le32_to_cpu(priv->card_alive.error_event_table_ptr); + + if (!priv->cfg->ops->lib->is_valid_rtc_data_addr(base)) { + IWL_ERROR("Not valid error log pointer 0x%08X\n", base); + return; + } + + ret = iwl_grab_nic_access(priv); + if (ret) { + IWL_WARNING("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) { + IWL_ERROR("Start IWL Error Log Dump:\n"); + IWL_ERROR("Status: 0x%08lX, count: %d\n", priv->status, count); + } + + desc = iwl_read_targ_mem(priv, base + 1 * sizeof(u32)); + blink1 = iwl_read_targ_mem(priv, base + 3 * sizeof(u32)); + blink2 = iwl_read_targ_mem(priv, base + 4 * sizeof(u32)); + ilink1 = iwl_read_targ_mem(priv, base + 5 * sizeof(u32)); + ilink2 = iwl_read_targ_mem(priv, base + 6 * sizeof(u32)); + data1 = iwl_read_targ_mem(priv, base + 7 * sizeof(u32)); + data2 = iwl_read_targ_mem(priv, base + 8 * sizeof(u32)); + line = iwl_read_targ_mem(priv, base + 9 * sizeof(u32)); + time = iwl_read_targ_mem(priv, base + 11 * sizeof(u32)); + + IWL_ERROR("Desc Time " + "data1 data2 line\n"); + IWL_ERROR("%-13s (#%d) %010u 0x%08X 0x%08X %u\n", + desc_lookup(desc), desc, time, data1, data2, line); + IWL_ERROR("blink1 blink2 ilink1 ilink2\n"); + IWL_ERROR("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); + +#define EVENT_START_OFFSET (4 * sizeof(u32)) + +/** + * iwl_print_event_log - Dump error event log to syslog + * + * NOTE: Must be called with iwl4965_grab_nic_access() already obtained! + */ +void iwl_print_event_log(struct iwl_priv *priv, u32 start_idx, + u32 num_events, u32 mode) +{ + u32 i; + u32 base; /* SRAM byte address of event log header */ + u32 event_size; /* 2 u32s, or 3 u32s if timestamp recorded */ + u32 ptr; /* SRAM byte address of log data */ + u32 ev, time, data; /* event log data */ + + if (num_events == 0) + return; + if (priv->ucode_type == UCODE_INIT) + base = le32_to_cpu(priv->card_alive_init.log_event_table_ptr); + else + base = le32_to_cpu(priv->card_alive.log_event_table_ptr); + + if (mode == 0) + event_size = 2 * sizeof(u32); + else + event_size = 3 * sizeof(u32); + + ptr = base + EVENT_START_OFFSET + (start_idx * event_size); + + /* "time" is actually "data" for mode 0 (no timestamp). + * place event id # at far right for easier visual parsing. */ + for (i = 0; i < num_events; i++) { + ev = iwl_read_targ_mem(priv, ptr); + ptr += sizeof(u32); + time = iwl_read_targ_mem(priv, ptr); + ptr += sizeof(u32); + if (mode == 0) { + /* data, ev */ + IWL_ERROR("EVT_LOG:0x%08x:%04u\n", time, ev); + } else { + data = iwl_read_targ_mem(priv, ptr); + ptr += sizeof(u32); + IWL_ERROR("EVT_LOGT:%010u:0x%08x:%04u\n", + time, data, ev); + } + } +} +EXPORT_SYMBOL(iwl_print_event_log); + + +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 */ + u32 num_wraps; /* # times uCode wrapped to top of log */ + u32 next_entry; /* index of next entry to be written by uCode */ + u32 size; /* # entries that we'll print */ + + if (priv->ucode_type == UCODE_INIT) + base = le32_to_cpu(priv->card_alive_init.log_event_table_ptr); + else + base = le32_to_cpu(priv->card_alive.log_event_table_ptr); + + if (!priv->cfg->ops->lib->is_valid_rtc_data_addr(base)) { + IWL_ERROR("Invalid event log pointer 0x%08X\n", base); + return; + } + + ret = iwl_grab_nic_access(priv); + if (ret) { + IWL_WARNING("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))); + num_wraps = iwl_read_targ_mem(priv, base + (2 * sizeof(u32))); + next_entry = iwl_read_targ_mem(priv, base + (3 * sizeof(u32))); + + size = num_wraps ? capacity : next_entry; + + /* bail out if nothing in log */ + if (size == 0) { + IWL_ERROR("Start IWL Event Log Dump: nothing in log\n"); + iwl_release_nic_access(priv); + return; + } + + IWL_ERROR("Start IWL Event Log Dump: display count %d, wraps %d\n", + size, num_wraps); + + /* if uCode has wrapped back to top of log, start at the oldest entry, + * i.e the next one that uCode would fill. */ + if (num_wraps) + iwl_print_event_log(priv, next_entry, + capacity - next_entry, mode); + /* (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); + +void iwl_rf_kill_ct_config(struct iwl_priv *priv) +{ + struct iwl_ct_kill_config cmd; + unsigned long flags; + int ret = 0; + + spin_lock_irqsave(&priv->lock, flags); + iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, + CSR_UCODE_DRV_GP1_REG_BIT_CT_KILL_EXIT); + spin_unlock_irqrestore(&priv->lock, flags); + + cmd.critical_temperature_R = + cpu_to_le32(priv->hw_params.ct_kill_threshold); + + ret = iwl_send_cmd_pdu(priv, REPLY_CT_KILL_CONFIG_CMD, + sizeof(cmd), &cmd); + if (ret) + IWL_ERROR("REPLY_CT_KILL_CONFIG_CMD failed\n"); + else + IWL_DEBUG_INFO("REPLY_CT_KILL_CONFIG_CMD succeeded, " + "critical temperature is %d\n", + cmd.critical_temperature_R); +} +EXPORT_SYMBOL(iwl_rf_kill_ct_config); + +/* + * CARD_STATE_CMD + * + * Use: Sets the device's internal card state to enable, disable, or halt + * + * When in the 'enable' state the card operates as normal. + * When in the 'disable' state, the card enters into a low power mode. + * When in the 'halt' state, the card is shut down and must be fully + * restarted to come back on. + */ +static int iwl_send_card_state(struct iwl_priv *priv, u32 flags, u8 meta_flag) +{ + struct iwl_host_cmd cmd = { + .id = REPLY_CARD_STATE_CMD, + .len = sizeof(u32), + .data = &flags, + .meta.flags = meta_flag, + }; + + return iwl_send_cmd(priv, &cmd); +} + +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("Manual SW RF KILL set to: RADIO OFF\n"); + + iwl_scan_cancel(priv); + /* FIXME: This is a workaround for AP */ + if (priv->iw_mode != IEEE80211_IF_TYPE_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("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); + + spin_lock_irqsave(&priv->lock, flags); + iwl_read32(priv, CSR_UCODE_DRV_GP1); + if (!iwl_grab_nic_access(priv)) + iwl_release_nic_access(priv); + spin_unlock_irqrestore(&priv->lock, flags); + + if (test_bit(STATUS_RF_KILL_HW, &priv->status)) { + IWL_DEBUG_RF_KILL("Can not turn radio back on - " + "disabled by HW switch\n"); + return 0; + } + + /* 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); diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index 7193d97630dc..db66114f1e56 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -70,7 +70,7 @@ struct iwl_host_cmd; struct iwl_cmd; -#define IWLWIFI_VERSION "1.2.26k" +#define IWLWIFI_VERSION "1.3.27k" #define DRV_COPYRIGHT "Copyright(c) 2003-2008 Intel Corporation" #define IWL_PCI_DEVICE(dev, subdev, cfg) \ @@ -86,28 +86,63 @@ struct iwl_hcmd_ops { int (*rxon_assoc)(struct iwl_priv *priv); }; struct iwl_hcmd_utils_ops { - int (*enqueue_hcmd)(struct iwl_priv *priv, struct iwl_host_cmd *cmd); + u16 (*get_hcmd_size)(u8 cmd_id, u16 len); + u16 (*build_addsta_hcmd)(const struct iwl_addsta_cmd *cmd, u8 *data); + void (*gain_computation)(struct iwl_priv *priv, + u32 *average_noise, + u16 min_average_noise_antennat_i, + u32 min_average_noise); + void (*chain_noise_reset)(struct iwl_priv *priv); + void (*rts_tx_cmd_flag)(struct ieee80211_tx_info *info, + __le32 *tx_flags); }; struct iwl_lib_ops { - /* iwlwifi driver (priv) init */ - int (*init_drv)(struct iwl_priv *priv); /* set hw dependant perameters */ int (*set_hw_params)(struct iwl_priv *priv); - + /* ucode shared memory */ + int (*alloc_shared_mem)(struct iwl_priv *priv); + void (*free_shared_mem)(struct iwl_priv *priv); + int (*shared_mem_rx_idx)(struct iwl_priv *priv); + /* Handling TX */ void (*txq_update_byte_cnt_tbl)(struct iwl_priv *priv, - struct iwl4965_tx_queue *txq, + struct iwl_tx_queue *txq, u16 byte_cnt); - /* nic init */ - int (*hw_nic_init)(struct iwl_priv *priv); + void (*txq_inval_byte_cnt_tbl)(struct iwl_priv *priv, + struct iwl_tx_queue *txq); + void (*txq_set_sched)(struct iwl_priv *priv, u32 mask); + /* aggregations */ + int (*txq_agg_enable)(struct iwl_priv *priv, int txq_id, int tx_fifo, + int sta_id, int tid, u16 ssn_idx); + int (*txq_agg_disable)(struct iwl_priv *priv, u16 txq_id, u16 ssn_idx, + u8 tx_fifo); + /* setup Rx handler */ + void (*rx_handler_setup)(struct iwl_priv *priv); + /* setup deferred work */ + void (*setup_deferred_work)(struct iwl_priv *priv); + /* cancel deferred work */ + void (*cancel_deferred_work)(struct iwl_priv *priv); + /* alive notification after init uCode load */ + void (*init_alive_start)(struct iwl_priv *priv); /* alive notification */ int (*alive_notify)(struct iwl_priv *priv); /* check validity of rtc data address */ int (*is_valid_rtc_data_addr)(u32 addr); /* 1st ucode load */ int (*load_ucode)(struct iwl_priv *priv); - /* rfkill */ - void (*radio_kill_sw)(struct iwl_priv *priv, int disable_radio); + /* 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 */ + int (*set_power)(struct iwl_priv *priv, void *cmd); + int (*send_tx_power) (struct iwl_priv *priv); + void (*update_chain_flags)(struct iwl_priv *priv); + void (*temperature) (struct iwl_priv *priv); /* eeprom operations (as defined in iwl-eeprom.h) */ struct iwl_eeprom_ops eeprom_ops; }; @@ -124,15 +159,19 @@ struct iwl_mod_params { int debug; /* def: 0 = minimal debug log messages */ 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 enable_qos; /* def: 1 = use quality of service */ + int disable_11n; /* def: 0 = disable 11n capabilities */ 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 */ }; struct iwl_cfg { const char *name; const char *fw_name; unsigned int sku; + int eeprom_size; const struct iwl_ops *ops; const struct iwl_mod_params *mod_params; }; @@ -143,14 +182,113 @@ struct iwl_cfg { struct ieee80211_hw *iwl_alloc_all(struct iwl_cfg *cfg, struct ieee80211_ops *hw_ops); +void iwl_hw_detect(struct iwl_priv *priv); -void iwlcore_clear_stations_table(struct iwl_priv *priv); -void iwlcore_reset_qos(struct iwl_priv *priv); -int iwlcore_set_rxon_channel(struct iwl_priv *priv, +void iwl_clear_stations_table(struct iwl_priv *priv); +void iwl_free_calib_results(struct iwl_priv *priv); +void iwl_reset_qos(struct iwl_priv *priv); +void iwl_set_rxon_chain(struct iwl_priv *priv); +int iwl_set_rxon_channel(struct iwl_priv *priv, enum ieee80211_band band, u16 channel); +void iwl_set_rxon_ht(struct iwl_priv *priv, struct iwl_ht_info *ht_info); +u8 iwl_is_fat_tx_allowed(struct iwl_priv *priv, + struct ieee80211_ht_info *sta_ht_inf); +int iwl_hw_nic_init(struct iwl_priv *priv); +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); +/* "keep warm" functions */ +int iwl_kw_init(struct iwl_priv *priv); +int iwl_kw_alloc(struct iwl_priv *priv); +void iwl_kw_free(struct iwl_priv *priv); + +/***************************************************** +* RX +******************************************************/ +void iwl_rx_queue_free(struct iwl_priv *priv, struct iwl_rx_queue *rxq); +int iwl_rx_queue_alloc(struct iwl_priv *priv); +void iwl_rx_handle(struct iwl_priv *priv); +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); +int iwl_rx_init(struct iwl_priv *priv, struct iwl_rx_queue *rxq); +int iwl_rx_agg_start(struct iwl_priv *priv, const u8 *addr, int tid, u16 ssn); +int iwl_rx_agg_stop(struct iwl_priv *priv, const u8 *addr, int tid); +/* FIXME: remove when TX is moved to iwl core */ +int iwl_rx_queue_restock(struct iwl_priv *priv); +int iwl_rx_queue_space(const struct iwl_rx_queue *q); +void iwl_rx_allocate(struct iwl_priv *priv); +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 */ +void iwl_rx_missed_beacon_notif(struct iwl_priv *priv, + struct iwl_rx_mem_buffer *rxb); +void iwl_rx_statistics(struct iwl_priv *priv, + struct iwl_rx_mem_buffer *rxb); + +/* TX helpers */ + +/***************************************************** +* TX +******************************************************/ +int iwl_txq_ctx_reset(struct iwl_priv *priv); +int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb); +/* FIXME: remove when free Tx is fully merged into iwlcore */ +int iwl_hw_txq_free_tfd(struct iwl_priv *priv, struct iwl_tx_queue *txq); +void iwl_hw_txq_ctx_free(struct iwl_priv *priv); +int iwl_hw_txq_attach_buf_to_tfd(struct iwl_priv *priv, void *tfd, + dma_addr_t addr, u16 len); +int iwl_txq_update_write_ptr(struct iwl_priv *priv, struct iwl_tx_queue *txq); +int iwl_tx_agg_start(struct iwl_priv *priv, const u8 *ra, u16 tid, u16 *ssn); +int iwl_tx_agg_stop(struct iwl_priv *priv , const u8 *ra, u16 tid); +int iwl_txq_check_empty(struct iwl_priv *priv, int sta_id, u8 tid, int txq_id); + +/***************************************************** + * TX power + ****************************************************/ +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_radio_kill_sw_disable_radio(struct iwl_priv *priv); +int iwl_radio_kill_sw_enable_radio(struct iwl_priv *priv); + +/******************************************************************************* + * Rate + ******************************************************************************/ + +void iwl_hwrate_to_tx_control(struct iwl_priv *priv, u32 rate_n_flags, + struct ieee80211_tx_info *info); +int iwl_hwrate_to_plcp_idx(u32 rate_n_flags); + +static inline u8 iwl_hw_get_rate(__le32 rate_n_flags) +{ + return le32_to_cpu(rate_n_flags) & 0xFF; +} +static inline u32 iwl_hw_get_rate_n_flags(__le32 rate_n_flags) +{ + return le32_to_cpu(rate_n_flags) & 0x1FFFF; +} +static inline __le32 iwl_hw_set_rate_n_flags(u8 rate, u32 flags) +{ + return cpu_to_le32(flags|(u32)rate); +} -int iwl_setup(struct iwl_priv *priv); +/******************************************************************************* + * Scanning + ******************************************************************************/ +void iwl_init_scan_params(struct iwl_priv *priv); +int iwl_scan_cancel(struct iwl_priv *priv); +int iwl_scan_cancel_timeout(struct iwl_priv *priv, unsigned long ms); +const char *iwl_escape_essid(const char *essid, u8 essid_len); +int iwl_scan_initiate(struct iwl_priv *priv); +void iwl_setup_rx_scan_handlers(struct iwl_priv *priv); +void iwl_setup_scan_deferred_work(struct iwl_priv *priv); /***************************************************** * S e n d i n g H o s t C o m m a n d s * @@ -167,6 +305,17 @@ int iwl_send_cmd_pdu_async(struct iwl_priv *priv, u8 id, u16 len, int (*callback)(struct iwl_priv *priv, struct iwl_cmd *cmd, struct sk_buff *skb)); + +int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd); + +/***************************************************** +* Error Handling Debugging +******************************************************/ +void iwl_print_event_log(struct iwl_priv *priv, u32 start_idx, + u32 num_events, u32 mode); +void iwl_dump_nic_error_log(struct iwl_priv *priv); +void iwl_dump_nic_event_log(struct iwl_priv *priv); + /*************** DRIVER STATUS FUNCTIONS *****/ #define STATUS_HCMD_ACTIVE 0 /* host command in progress */ @@ -188,6 +337,7 @@ int iwl_send_cmd_pdu_async(struct iwl_priv *priv, u8 id, u16 len, #define STATUS_POWER_PMI 16 #define STATUS_FW_ERROR 17 #define STATUS_CONF_PENDING 18 +#define STATUS_MODE_PENDING 19 static inline int iwl_is_ready(struct iwl_priv *priv) @@ -209,10 +359,19 @@ 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); +} + static inline int iwl_is_rfkill(struct iwl_priv *priv) { - return test_bit(STATUS_RF_KILL_HW, &priv->status) || - test_bit(STATUS_RF_KILL_SW, &priv->status); + return iwl_is_rfkill_hw(priv) || iwl_is_rfkill_sw(priv); } static inline int iwl_is_ready_rf(struct iwl_priv *priv) @@ -224,23 +383,27 @@ static inline int iwl_is_ready_rf(struct iwl_priv *priv) return iwl_is_ready(priv); } - -enum iwlcore_card_notify { - IWLCORE_INIT_EVT = 0, - IWLCORE_START_EVT = 1, - IWLCORE_STOP_EVT = 2, - IWLCORE_REMOVE_EVT = 3, -}; - -int iwlcore_low_level_notify(struct iwl_priv *priv, - enum iwlcore_card_notify notify); +extern void iwl_rf_kill_ct_config(struct iwl_priv *priv); extern int iwl_send_statistics_request(struct iwl_priv *priv, u8 flags); -int iwl_send_lq_cmd(struct iwl_priv *priv, - struct iwl_link_quality_cmd *lq, u8 flags); +extern int iwl_verify_ucode(struct iwl_priv *priv); +extern int iwl_send_lq_cmd(struct iwl_priv *priv, + struct iwl_link_quality_cmd *lq, u8 flags); +extern void iwl_rx_reply_rx(struct iwl_priv *priv, + struct iwl_rx_mem_buffer *rxb); +extern void iwl_rx_reply_rx_phy(struct iwl_priv *priv, + struct iwl_rx_mem_buffer *rxb); +void iwl_rx_reply_compressed_ba(struct iwl_priv *priv, + struct iwl_rx_mem_buffer *rxb); static inline int iwl_send_rxon_assoc(struct iwl_priv *priv) { return priv->cfg->ops->hcmd->rxon_assoc(priv); } +static inline const struct ieee80211_supported_band *iwl_get_hw_mode( + struct iwl_priv *priv, enum ieee80211_band band) +{ + return priv->hw->wiphy->bands[band]; +} + #endif /* __iwl_core_h__ */ diff --git a/drivers/net/wireless/iwlwifi/iwl-csr.h b/drivers/net/wireless/iwlwifi/iwl-csr.h index 12725796ea5f..545ed692d889 100644 --- a/drivers/net/wireless/iwlwifi/iwl-csr.h +++ b/drivers/net/wireless/iwlwifi/iwl-csr.h @@ -87,16 +87,16 @@ /* EEPROM reads */ #define CSR_EEPROM_REG (CSR_BASE+0x02c) #define CSR_EEPROM_GP (CSR_BASE+0x030) +#define CSR_GIO_REG (CSR_BASE+0x03C) #define CSR_GP_UCODE (CSR_BASE+0x044) #define CSR_UCODE_DRV_GP1 (CSR_BASE+0x054) #define CSR_UCODE_DRV_GP1_SET (CSR_BASE+0x058) #define CSR_UCODE_DRV_GP1_CLR (CSR_BASE+0x05c) #define CSR_UCODE_DRV_GP2 (CSR_BASE+0x060) -#define CSR_GIO_CHICKEN_BITS (CSR_BASE+0x100) #define CSR_LED_REG (CSR_BASE+0x094) +#define CSR_GIO_CHICKEN_BITS (CSR_BASE+0x100) -/* Analog phase-lock-loop configuration (3945 only) - * Set bit 24. */ +/* Analog phase-lock-loop configuration */ #define CSR_ANA_PLL_CFG (CSR_BASE+0x20c) /* * Indicates hardware rev, to determine CCK backoff for txpower calculation. @@ -107,9 +107,9 @@ /* Bits for CSR_HW_IF_CONFIG_REG */ #define CSR49_HW_IF_CONFIG_REG_BIT_4965_R (0x00000010) -#define CSR49_HW_IF_CONFIG_REG_MSK_BOARD_VER (0x00000C00) -#define CSR49_HW_IF_CONFIG_REG_BIT_MAC_SI (0x00000100) -#define CSR49_HW_IF_CONFIG_REG_BIT_RADIO_SI (0x00000200) +#define CSR_HW_IF_CONFIG_REG_MSK_BOARD_VER (0x00000C00) +#define CSR_HW_IF_CONFIG_REG_BIT_MAC_SI (0x00000100) +#define CSR_HW_IF_CONFIG_REG_BIT_RADIO_SI (0x00000200) #define CSR39_HW_IF_CONFIG_REG_BIT_3945_MB (0x00000100) #define CSR39_HW_IF_CONFIG_REG_BIT_3945_MM (0x00000200) @@ -170,6 +170,10 @@ #define CSR49_FH_INT_TX_MASK (CSR_FH_INT_BIT_TX_CHNL1 | \ CSR_FH_INT_BIT_TX_CHNL0) +/* GPIO */ +#define CSR_GPIO_IN_BIT_AUX_POWER (0x00000200) +#define CSR_GPIO_IN_VAL_VAUX_PWR_SRC (0x00000000) +#define CSR_GPIO_IN_VAL_VMAIN_PWR_SRC (0x00000200) /* RESET */ #define CSR_RESET_REG_FLAG_NEVO_RESET (0x00000001) @@ -191,6 +195,16 @@ #define CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW (0x08000000) +/* HW REV */ +#define CSR_HW_REV_TYPE_MSK (0x00000F0) +#define CSR_HW_REV_TYPE_3945 (0x00000D0) +#define CSR_HW_REV_TYPE_4965 (0x0000000) +#define CSR_HW_REV_TYPE_5300 (0x0000020) +#define CSR_HW_REV_TYPE_5350 (0x0000030) +#define CSR_HW_REV_TYPE_5100 (0x0000050) +#define CSR_HW_REV_TYPE_5150 (0x0000040) +#define CSR_HW_REV_TYPE_NONE (0x00000F0) + /* EEPROM REG */ #define CSR_EEPROM_REG_READ_VALID_MSK (0x00000001) #define CSR_EEPROM_REG_BIT_CMD (0x00000002) @@ -200,17 +214,15 @@ #define CSR_EEPROM_GP_BAD_SIGNATURE (0x00000000) #define CSR_EEPROM_GP_IF_OWNER_MSK (0x00000180) +/* CSR GIO */ +#define CSR_GIO_REG_VAL_L0S_ENABLED (0x00000002) + /* UCODE DRV GP */ #define CSR_UCODE_DRV_GP1_BIT_MAC_SLEEP (0x00000001) #define CSR_UCODE_SW_BIT_RFKILL (0x00000002) #define CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED (0x00000004) #define CSR_UCODE_DRV_GP1_REG_BIT_CT_KILL_EXIT (0x00000008) -/* GPIO */ -#define CSR_GPIO_IN_BIT_AUX_POWER (0x00000200) -#define CSR_GPIO_IN_VAL_VAUX_PWR_SRC (0x00000000) -#define CSR_GPIO_IN_VAL_VMAIN_PWR_SRC CSR_GPIO_IN_BIT_AUX_POWER - /* GI Chicken Bits */ #define CSR_GIO_CHICKEN_BITS_REG_BIT_L1A_NO_L0S_RX (0x00800000) #define CSR_GIO_CHICKEN_BITS_REG_BIT_DIS_L0S_EXIT_TIMER (0x20000000) @@ -220,6 +232,10 @@ #define CSR_LED_REG_TRUN_ON (0x78) #define CSR_LED_REG_TRUN_OFF (0x38) +/* ANA_PLL */ +#define CSR39_ANA_PLL_CFG_VAL (0x01000000) +#define CSR50_ANA_PLL_CFG_VAL (0x00880300) + /*=== HBUS (Host-side Bus) ===*/ #define HBUS_BASE (0x400) /* diff --git a/drivers/net/wireless/iwlwifi/iwl-debug.h b/drivers/net/wireless/iwlwifi/iwl-debug.h index c60724c21db8..58384805a494 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debug.h +++ b/drivers/net/wireless/iwlwifi/iwl-debug.h @@ -30,37 +30,35 @@ #define __iwl_debug_h__ #ifdef CONFIG_IWLWIFI_DEBUG -extern u32 iwl_debug_level; #define IWL_DEBUG(level, fmt, args...) \ -do { if (iwl_debug_level & (level)) \ - printk(KERN_ERR DRV_NAME": %c %s " fmt, \ +do { if (priv->debug_level & (level)) \ + dev_printk(KERN_ERR, &(priv->hw->wiphy->dev), "%c %s " fmt, \ in_interrupt() ? 'I' : 'U', __FUNCTION__ , ## args); } while (0) #define IWL_DEBUG_LIMIT(level, fmt, args...) \ -do { if ((iwl_debug_level & (level)) && net_ratelimit()) \ - printk(KERN_ERR DRV_NAME": %c %s " fmt, \ +do { if ((priv->debug_level & (level)) && net_ratelimit()) \ + dev_printk(KERN_ERR, &(priv->hw->wiphy->dev), "%c %s " fmt, \ in_interrupt() ? 'I' : 'U', __FUNCTION__ , ## args); } while (0) -static inline void iwl_print_hex_dump(int level, void *p, u32 len) -{ - if (!(iwl_debug_level & level)) - return; - - print_hex_dump(KERN_DEBUG, "iwl data: ", DUMP_PREFIX_OFFSET, 16, 1, - p, len, 1); -} - #ifdef CONFIG_IWLWIFI_DEBUGFS struct iwl_debugfs { const char *name; struct dentry *dir_drv; struct dentry *dir_data; - struct dir_data_files{ + struct dentry *dir_rf; + struct dir_data_files { struct dentry *file_sram; + struct dentry *file_eeprom; struct dentry *file_stations; struct dentry *file_rx_statistics; struct dentry *file_tx_statistics; + struct dentry *file_log_event; } dbgfs_data_files; + struct dir_rf_files { + struct dentry *file_disable_sensitivity; + struct dentry *file_disable_chain_noise; + struct dentry *file_disable_tx_power; + } dbgfs_rf_files; u32 sram_offset; u32 sram_len; }; @@ -76,9 +74,6 @@ static inline void IWL_DEBUG(int level, const char *fmt, ...) static inline void IWL_DEBUG_LIMIT(int level, const char *fmt, ...) { } -static inline void iwl_print_hex_dump(int level, void *p, u32 len) -{ -} #endif /* CONFIG_IWLWIFI_DEBUG */ diff --git a/drivers/net/wireless/iwlwifi/iwl-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-debugfs.c index 9a30e1df311d..ed948dc59b3d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debugfs.c +++ b/drivers/net/wireless/iwlwifi/iwl-debugfs.c @@ -34,7 +34,7 @@ #include <net/mac80211.h> -#include "iwl-4965.h" +#include "iwl-dev.h" #include "iwl-debug.h" #include "iwl-core.h" #include "iwl-io.h" @@ -55,6 +55,13 @@ goto err; \ } while (0) +#define DEBUGFS_ADD_BOOL(name, parent, ptr) do { \ + dbgfs->dbgfs_##parent##_files.file_##name = \ + debugfs_create_bool(#name, 0644, dbgfs->dir_##parent, ptr); \ + if (IS_ERR(dbgfs->dbgfs_##parent##_files.file_##name)) \ + goto err; \ +} while (0) + #define DEBUGFS_REMOVE(name) do { \ debugfs_remove(name); \ name = NULL; \ @@ -85,6 +92,14 @@ static const struct file_operations iwl_dbgfs_##name##_ops = { \ .open = iwl_dbgfs_open_file_generic, \ }; +#define DEBUGFS_WRITE_FILE_OPS(name) \ + DEBUGFS_WRITE_FUNC(name); \ +static const struct file_operations iwl_dbgfs_##name##_ops = { \ + .write = iwl_dbgfs_##name##_write, \ + .open = iwl_dbgfs_open_file_generic, \ +}; + + #define DEBUGFS_READ_WRITE_FILE_OPS(name) \ DEBUGFS_READ_FUNC(name); \ DEBUGFS_WRITE_FUNC(name); \ @@ -206,7 +221,7 @@ static ssize_t iwl_dbgfs_stations_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { struct iwl_priv *priv = (struct iwl_priv *)file->private_data; - struct iwl4965_station_entry *station; + struct iwl_station_entry *station; int max_sta = priv->hw_params.max_stations; char *buf; int i, j, pos = 0; @@ -240,21 +255,18 @@ static ssize_t iwl_dbgfs_stations_read(struct file *file, char __user *user_buf, pos += scnprintf(buf + pos, bufsz - pos, "tid data:\n"); pos += scnprintf(buf + pos, bufsz - pos, "seq_num\t\ttxq_id"); -#ifdef CONFIG_IWL4965_HT pos += scnprintf(buf + pos, bufsz - pos, "\tframe_count\twait_for_ba\t"); pos += scnprintf(buf + pos, bufsz - pos, "start_idx\tbitmap0\t"); pos += scnprintf(buf + pos, bufsz - pos, "bitmap1\trate_n_flags"); -#endif pos += scnprintf(buf + pos, bufsz - pos, "\n"); for (j = 0; j < MAX_TID_COUNT; j++) { pos += scnprintf(buf + pos, bufsz - pos, "[%d]:\t\t%u", j, station->tid[j].seq_number); -#ifdef CONFIG_IWL4965_HT pos += scnprintf(buf + pos, bufsz - pos, "\t%u\t\t%u\t\t%u\t\t", station->tid[j].agg.txq_id, @@ -265,7 +277,6 @@ static ssize_t iwl_dbgfs_stations_read(struct file *file, char __user *user_buf, station->tid[j].agg.start_idx, (unsigned long long)station->tid[j].agg.bitmap, station->tid[j].agg.rate_n_flags); -#endif pos += scnprintf(buf + pos, bufsz - pos, "\n"); } pos += scnprintf(buf + pos, bufsz - pos, "\n"); @@ -277,8 +288,70 @@ 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, + char __user *user_buf, + size_t count, + loff_t *ppos) +{ + ssize_t ret; + struct iwl_priv *priv = (struct iwl_priv *)file->private_data; + int pos = 0, ofs = 0, buf_size = 0; + const u8 *ptr; + char *buf; + size_t eeprom_len = priv->cfg->eeprom_size; + buf_size = 4 * eeprom_len + 256; + + if (eeprom_len % 16) { + IWL_ERROR("EEPROM size is not multiple of 16.\n"); + return -ENODATA; + } + + /* 4 characters for byte 0xYY */ + buf = kzalloc(buf_size, GFP_KERNEL); + if (!buf) { + IWL_ERROR("Can not allocate Buffer\n"); + return -ENOMEM; + } + + ptr = priv->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, + buf_size - pos, 0); + pos += strlen(buf); + if (buf_size - pos > 0) + buf[pos++] = '\n'; + } + + ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); + kfree(buf); + return ret; +} + +static ssize_t iwl_dbgfs_log_event_write(struct file *file, + const char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct iwl_priv *priv = file->private_data; + u32 event_log_flag; + char buf[8]; + int buf_size; + + 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, "%d", &event_log_flag) != 1) + return -EFAULT; + if (event_log_flag == 1) + iwl_dump_nic_event_log(priv); + + return count; +} DEBUGFS_READ_WRITE_FILE_OPS(sram); +DEBUGFS_WRITE_FILE_OPS(log_event); +DEBUGFS_READ_FILE_OPS(eeprom); DEBUGFS_READ_FILE_OPS(stations); DEBUGFS_READ_FILE_OPS(rx_statistics); DEBUGFS_READ_FILE_OPS(tx_statistics); @@ -290,6 +363,7 @@ DEBUGFS_READ_FILE_OPS(tx_statistics); int iwl_dbgfs_register(struct iwl_priv *priv, const char *name) { struct iwl_debugfs *dbgfs; + struct dentry *phyd = priv->hw->wiphy->debugfsdir; dbgfs = kzalloc(sizeof(struct iwl_debugfs), GFP_KERNEL); if (!dbgfs) { @@ -298,17 +372,23 @@ int iwl_dbgfs_register(struct iwl_priv *priv, const char *name) priv->dbgfs = dbgfs; dbgfs->name = name; - dbgfs->dir_drv = debugfs_create_dir(name, NULL); + dbgfs->dir_drv = debugfs_create_dir(name, phyd); if (!dbgfs->dir_drv || IS_ERR(dbgfs->dir_drv)){ goto err; } DEBUGFS_ADD_DIR(data, dbgfs->dir_drv); + DEBUGFS_ADD_DIR(rf, dbgfs->dir_drv); + DEBUGFS_ADD_FILE(eeprom, data); DEBUGFS_ADD_FILE(sram, data); + DEBUGFS_ADD_FILE(log_event, data); DEBUGFS_ADD_FILE(stations, data); DEBUGFS_ADD_FILE(rx_statistics, data); DEBUGFS_ADD_FILE(tx_statistics, data); - + DEBUGFS_ADD_BOOL(disable_sensitivity, rf, &priv->disable_sens_cal); + DEBUGFS_ADD_BOOL(disable_chain_noise, rf, + &priv->disable_chain_noise_cal); + DEBUGFS_ADD_BOOL(disable_tx_power, rf, &priv->disable_tx_power_cal); return 0; err: @@ -327,11 +407,17 @@ 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_rx_statistics); DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_tx_statistics); DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_sram); + DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_log_event); DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_stations); 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); + DEBUGFS_REMOVE(priv->dbgfs->dbgfs_rf_files.file_disable_tx_power); + DEBUGFS_REMOVE(priv->dbgfs->dir_rf); DEBUGFS_REMOVE(priv->dbgfs->dir_drv); kfree(priv->dbgfs); priv->dbgfs = NULL; @@ -339,3 +425,4 @@ void iwl_dbgfs_unregister(struct iwl_priv *priv) EXPORT_SYMBOL(iwl_dbgfs_unregister); + diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 581b98556c86..4d789e353e3a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -24,13 +24,13 @@ * *****************************************************************************/ /* - * Please use this file (iwl-4965.h) for driver implementation definitions. - * Please use iwl-4965-commands.h for uCode API definitions. + * Please use this file (iwl-dev.h) for driver implementation definitions. + * Please use iwl-commands.h for uCode API definitions. * Please use iwl-4965-hw.h for hardware-related definitions. */ -#ifndef __iwl_4965_h__ -#define __iwl_4965_h__ +#ifndef __iwl_dev_h__ +#define __iwl_dev_h__ #include <linux/pci.h> /* for struct pci_device_id */ #include <linux/kernel.h> @@ -44,16 +44,18 @@ #include "iwl-prph.h" #include "iwl-debug.h" #include "iwl-led.h" +#include "iwl-power.h" /* configuration for the iwl4965 */ extern struct iwl_cfg iwl4965_agn_cfg; +extern struct iwl_cfg iwl5300_agn_cfg; +extern struct iwl_cfg iwl5100_agn_cfg; +extern struct iwl_cfg iwl5350_agn_cfg; +extern struct iwl_cfg iwl5100_bg_cfg; +extern struct iwl_cfg iwl5100_abg_cfg; -/* Change firmware file name, using "-" and incrementing number, - * *only* when uCode interface or architecture changes so that it - * is not compatible with earlier drivers. - * This number will also appear in << 8 position of 1st dword of uCode file */ -#define IWL4965_UCODE_API "-1" - +/* CT-KILL constants */ +#define CT_KILL_THRESHOLD 110 /* in Celsius */ /* Default noise level to report when noise measurement is not available. * This may be because we're: @@ -68,12 +70,6 @@ extern struct iwl_cfg iwl4965_agn_cfg; * averages within an s8's (used in some apps) range of negative values. */ #define IWL_NOISE_MEAS_NOT_AVAILABLE (-127) -enum iwl4965_antenna { - IWL_ANTENNA_DIVERSITY, - IWL_ANTENNA_MAIN, - IWL_ANTENNA_AUX -}; - /* * RTS threshold here is total size [2347] minus 4 FCS bytes * Per spec: @@ -91,7 +87,7 @@ enum iwl4965_antenna { #define DEFAULT_SHORT_RETRY_LIMIT 7U #define DEFAULT_LONG_RETRY_LIMIT 4U -struct iwl4965_rx_mem_buffer { +struct iwl_rx_mem_buffer { dma_addr_t dma_addr; struct sk_buff *skb; struct list_head list; @@ -102,7 +98,7 @@ struct iwl4965_rx_mem_buffer { * * Contains common data for Rx and Tx queues */ -struct iwl4965_queue { +struct iwl_queue { int n_bd; /* number of BDs in this queue */ int write_ptr; /* 1-st empty entry (index) host_w*/ int read_ptr; /* last used entry (index) host_r*/ @@ -118,13 +114,12 @@ struct iwl4965_queue { #define MAX_NUM_OF_TBS (20) /* One for each TFD */ -struct iwl4965_tx_info { - struct ieee80211_tx_status status; +struct iwl_tx_info { struct sk_buff *skb[MAX_NUM_OF_TBS]; }; /** - * struct iwl4965_tx_queue - Tx Queue for DMA + * struct iwl_tx_queue - Tx Queue for DMA * @q: generic Rx/Tx queue descriptor * @bd: base of circular buffer of TFDs * @cmd: array of command/Tx buffers @@ -136,12 +131,12 @@ struct iwl4965_tx_info { * A Tx queue consists of circular buffer of BDs (a.k.a. TFDs, transmit frame * descriptors) and required locking structures. */ -struct iwl4965_tx_queue { - struct iwl4965_queue q; - struct iwl4965_tfd_frame *bd; +struct iwl_tx_queue { + struct iwl_queue q; + struct iwl_tfd_frame *bd; struct iwl_cmd *cmd; dma_addr_t dma_addr_cmd; - struct iwl4965_tx_info *txb; + struct iwl_tx_info *txb; int need_update; int sched_retry; int active; @@ -158,50 +153,17 @@ struct iwl4965_channel_tgh_info { s64 last_radar_time; }; -/* current Tx power values to use, one for each rate for each channel. - * requested power is limited by: - * -- regulatory EEPROM limits for this channel - * -- hardware capabilities (clip-powers) - * -- spectrum management - * -- user preference (e.g. iwconfig) - * when requested power is set, base power index must also be set. */ -struct iwl4965_channel_power_info { - struct iwl4965_tx_power tpc; /* actual radio and DSP gain settings */ - s8 power_table_index; /* actual (compenst'd) index into gain table */ - s8 base_power_index; /* gain index for power at factory temp. */ - s8 requested_power; /* power (dBm) requested for this chnl/rate */ -}; - -/* current scan Tx power values to use, one for each scan rate for each - * channel. */ -struct iwl4965_scan_power_info { - struct iwl4965_tx_power tpc; /* actual radio and DSP gain settings */ - s8 power_table_index; /* actual (compenst'd) index into gain table */ - s8 requested_power; /* scan pwr (dBm) requested for chnl/rate */ -}; - -/* For fat_extension_channel */ -enum { - HT_IE_EXT_CHANNEL_NONE = 0, - HT_IE_EXT_CHANNEL_ABOVE, - HT_IE_EXT_CHANNEL_INVALID, - HT_IE_EXT_CHANNEL_BELOW, - HT_IE_EXT_CHANNEL_MAX -}; - /* * One for each channel, holds all channel setup data * Some of the fields (e.g. eeprom and flags/max_power_avg) are redundant * with one another! */ -#define IWL4965_MAX_RATE (33) - struct iwl_channel_info { struct iwl4965_channel_tgd_info tgd; struct iwl4965_channel_tgh_info tgh; - struct iwl4965_eeprom_channel eeprom; /* EEPROM regulatory limit */ - struct iwl4965_eeprom_channel fat_eeprom; /* EEPROM regulatory limit for - * FAT channel */ + struct iwl_eeprom_channel eeprom; /* EEPROM regulatory limit */ + struct iwl_eeprom_channel fat_eeprom; /* EEPROM regulatory limit for + * FAT channel */ u8 channel; /* channel number */ u8 flags; /* flags copied from EEPROM */ @@ -214,11 +176,6 @@ struct iwl_channel_info { u8 band_index; /* 0-4, maps channel to band1/2/3/4/5 */ enum ieee80211_band band; - /* Radio/DSP gain settings for each "normal" data Tx rate. - * These include, in addition to RF and DSP gain, a few fields for - * remembering/modifying gain settings (indexes). */ - struct iwl4965_channel_power_info power_info[IWL4965_MAX_RATE]; - /* FAT channel info */ s8 fat_max_power_avg; /* (dBm) regul. eeprom, normal Tx, any rate */ s8 fat_curr_txpow; /* (dBm) regulatory/spectrum/user (not h/w) */ @@ -226,9 +183,6 @@ struct iwl_channel_info { s8 fat_scan_power; /* (dBm) eeprom, direct scans, any rate */ u8 fat_flags; /* flags copied from EEPROM */ u8 fat_extension_channel; /* HT_IE_EXT_CHANNEL_* */ - - /* Radio/DSP gain settings for each scan rate, for directed scans. */ - struct iwl4965_scan_power_info scan_pwr_info[IWL_NUM_SCAN_RATES]; }; struct iwl4965_clip_group { @@ -252,29 +206,9 @@ struct iwl4965_clip_group { /* Power management (not Tx power) structures */ -struct iwl4965_power_vec_entry { - struct iwl4965_powertable_cmd cmd; - u8 no_dtim; -}; -#define IWL_POWER_RANGE_0 (0) -#define IWL_POWER_RANGE_1 (1) - -#define IWL_POWER_MODE_CAM 0x00 /* Continuously Aware Mode, always on */ -#define IWL_POWER_INDEX_3 0x03 -#define IWL_POWER_INDEX_5 0x05 -#define IWL_POWER_AC 0x06 -#define IWL_POWER_BATTERY 0x07 -#define IWL_POWER_LIMIT 0x07 -#define IWL_POWER_MASK 0x0F -#define IWL_POWER_ENABLED 0x10 -#define IWL_POWER_LEVEL(x) ((x) & IWL_POWER_MASK) - -struct iwl4965_power_mgr { - spinlock_t lock; - struct iwl4965_power_vec_entry pwr_range_0[IWL_POWER_AC]; - struct iwl4965_power_vec_entry pwr_range_1[IWL_POWER_AC]; - u8 active_index; - u32 dtim_val; +enum iwl_pwr_src { + IWL_PWR_SRC_VMAIN, + IWL_PWR_SRC_VAUX, }; #define IEEE80211_DATA_LEN 2304 @@ -282,7 +216,7 @@ struct iwl4965_power_mgr { #define IEEE80211_HLEN (IEEE80211_4ADDR_LEN) #define IEEE80211_FRAME_LEN (IEEE80211_DATA_LEN + IEEE80211_HLEN) -struct iwl4965_frame { +struct iwl_frame { union { struct ieee80211_hdr frame; struct iwl4965_tx_beacon_cmd beacon; @@ -328,6 +262,8 @@ struct iwl_cmd_meta { } __attribute__ ((packed)); +#define IWL_CMD_MAX_PAYLOAD 320 + /** * struct iwl_cmd * @@ -339,8 +275,8 @@ struct iwl_cmd { struct iwl_cmd_meta meta; /* driver data */ struct iwl_cmd_header hdr; /* uCode API */ union { - struct iwl4965_addsta_cmd addsta; - struct iwl4965_led_cmd led; + struct iwl_addsta_cmd addsta; + struct iwl_led_cmd led; u32 flags; u8 val8; u16 val16; @@ -348,12 +284,13 @@ struct iwl_cmd { struct iwl4965_bt_cmd bt; struct iwl4965_rxon_time_cmd rxon_time; struct iwl4965_powertable_cmd powertable; - struct iwl4965_qosparam_cmd qosparam; - struct iwl4965_tx_cmd tx; + struct iwl_qosparam_cmd qosparam; + struct iwl_tx_cmd tx; struct iwl4965_tx_beacon_cmd tx_beacon; struct iwl4965_rxon_assoc_cmd rxon_assoc; + struct iwl_rem_sta_cmd rm_sta; u8 *indirect; - u8 payload[360]; + u8 payload[IWL_CMD_MAX_PAYLOAD]; } __attribute__ ((packed)) cmd; } __attribute__ ((packed)); @@ -378,7 +315,7 @@ struct iwl_host_cmd { #define SUP_RATE_11G_MAX_NUM_CHANNELS 12 /** - * struct iwl4965_rx_queue - Rx queue + * struct iwl_rx_queue - Rx queue * @processed: Internal index to last handled Rx packet * @read: Shared index to newest available Rx buffer * @write: Shared index to oldest written Rx packet @@ -387,13 +324,13 @@ struct iwl_host_cmd { * @rx_used: List of Rx buffers with no SKB * @need_update: flag to indicate we need to update read/write index * - * NOTE: rx_free and rx_used are used as a FIFO for iwl4965_rx_mem_buffers + * NOTE: rx_free and rx_used are used as a FIFO for iwl_rx_mem_buffers */ -struct iwl4965_rx_queue { +struct iwl_rx_queue { __le32 *bd; dma_addr_t dma_addr; - struct iwl4965_rx_mem_buffer pool[RX_QUEUE_SIZE + RX_FREE_BUFFERS]; - struct iwl4965_rx_mem_buffer *queue[RX_QUEUE_SIZE]; + struct iwl_rx_mem_buffer pool[RX_QUEUE_SIZE + RX_FREE_BUFFERS]; + struct iwl_rx_mem_buffer *queue[RX_QUEUE_SIZE]; u32 processed; u32 read; u32 write; @@ -419,9 +356,8 @@ struct iwl4965_rx_queue { #define IWL_INVALID_RATE 0xFF #define IWL_INVALID_VALUE -1 -#ifdef CONFIG_IWL4965_HT /** - * struct iwl4965_ht_agg -- aggregation status while waiting for block-ack + * struct iwl_ht_agg -- aggregation status while waiting for block-ack * @txq_id: Tx queue used for Tx attempt * @frame_count: # frames attempted by Tx command * @wait_for_ba: Expect block-ack before next Tx reply @@ -434,7 +370,7 @@ struct iwl4965_rx_queue { * for block ack (REPLY_COMPRESSED_BA). This struct stores tx reply info * until block ack arrives. */ -struct iwl4965_ht_agg { +struct iwl_ht_agg { u16 txq_id; u16 frame_count; u16 wait_for_ba; @@ -448,21 +384,17 @@ struct iwl4965_ht_agg { u8 state; }; -#endif /* CONFIG_IWL4965_HT */ -struct iwl4965_tid_data { +struct iwl_tid_data { u16 seq_number; u16 tfds_in_queue; -#ifdef CONFIG_IWL4965_HT - struct iwl4965_ht_agg agg; -#endif /* CONFIG_IWL4965_HT */ + struct iwl_ht_agg agg; }; -struct iwl4965_hw_key { +struct iwl_hw_key { enum ieee80211_key_alg alg; int keylen; u8 keyidx; - struct ieee80211_key_conf *conf; u8 key[32]; }; @@ -474,7 +406,6 @@ union iwl4965_ht_rate_supp { }; }; -#ifdef CONFIG_IWL4965_HT #define CFG_HT_RX_AMPDU_FACTOR_DEF (0x3) #define CFG_HT_MPDU_DENSITY_2USEC (0x5) #define CFG_HT_MPDU_DENSITY_DEF CFG_HT_MPDU_DENSITY_2USEC @@ -497,9 +428,8 @@ struct iwl_ht_info { u8 ht_protection; u8 non_GF_STA_present; }; -#endif /*CONFIG_IWL4965_HT */ -union iwl4965_qos_capabity { +union iwl_qos_capabity { struct { u8 edca_count:4; /* bit 0-3 */ u8 q_ack:1; /* bit 4 */ @@ -520,22 +450,22 @@ union iwl4965_qos_capabity { }; /* QoS structures */ -struct iwl4965_qos_info { +struct iwl_qos_info { int qos_enable; int qos_active; - union iwl4965_qos_capabity qos_cap; - struct iwl4965_qosparam_cmd def_qos_parm; + union iwl_qos_capabity qos_cap; + struct iwl_qosparam_cmd def_qos_parm; }; #define STA_PS_STATUS_WAKE 0 #define STA_PS_STATUS_SLEEP 1 -struct iwl4965_station_entry { - struct iwl4965_addsta_cmd sta; - struct iwl4965_tid_data tid[MAX_TID_COUNT]; +struct iwl_station_entry { + struct iwl_addsta_cmd sta; + struct iwl_tid_data tid[MAX_TID_COUNT]; u8 used; u8 ps_status; - struct iwl4965_hw_key keyinfo; + struct iwl_hw_key keyinfo; }; /* one for each uCode image (inst/data, boot/init/runtime) */ @@ -546,7 +476,7 @@ struct fw_desc { }; /* uCode file layout */ -struct iwl4965_ucode { +struct iwl_ucode { __le32 ver; /* major/minor/subminor */ __le32 inst_size; /* bytes of runtime instructions */ __le32 data_size; /* bytes of runtime data */ @@ -556,8 +486,6 @@ struct iwl4965_ucode { u8 data[0]; /* data in same order as "size" elements */ }; -#define IWL_IBSS_MAC_HASH_SIZE 32 - struct iwl4965_ibss_seq { u8 mac[ETH_ALEN]; u16 seq_num; @@ -566,20 +494,52 @@ struct iwl4965_ibss_seq { struct list_head list; }; +struct iwl_sensitivity_ranges { + u16 min_nrg_cck; + u16 max_nrg_cck; + + u16 nrg_th_cck; + u16 nrg_th_ofdm; + + u16 auto_corr_min_ofdm; + u16 auto_corr_min_ofdm_mrc; + u16 auto_corr_min_ofdm_x1; + u16 auto_corr_min_ofdm_mrc_x1; + + u16 auto_corr_max_ofdm; + u16 auto_corr_max_ofdm_mrc; + u16 auto_corr_max_ofdm_x1; + u16 auto_corr_max_ofdm_mrc_x1; + + u16 auto_corr_max_cck; + u16 auto_corr_max_cck_mrc; + u16 auto_corr_min_cck; + u16 auto_corr_min_cck_mrc; +}; + + +#define IWL_FAT_CHANNEL_52 BIT(IEEE80211_BAND_5GHZ) + /** * struct iwl_hw_params * @max_txq_num: Max # Tx queues supported - * @tx_cmd_len: Size of Tx command (but not including frame itself) - * @tx_ant_num: Number of TX antennas + * @tx/rx_chains_num: Number of TX/RX chains + * @valid_tx/rx_ant: usable antennas * @max_rxq_size: Max # Rx frames in Rx queue (must be power-of-2) - * @rx_buffer_size: * @max_rxq_log: Log-base-2 of max_rxq_size + * @rx_buf_size: Rx buffer size * @max_stations: * @bcast_sta_id: + * @fat_channel: is 40MHz width possible in band 2.4 + * BIT(IEEE80211_BAND_5GHZ) BIT(IEEE80211_BAND_5GHZ) + * @sw_crypto: 0 for hw, 1 for sw + * @max_xxx_size: for ucode uses + * @ct_kill_threshold: temperature threshold + * @struct iwl_sensitivity_ranges: range of sensitivity values + * @first_ampdu_q: first HW queue available for ampdu */ struct iwl_hw_params { u16 max_txq_num; - u16 tx_cmd_len; u8 tx_chains_num; u8 rx_chains_num; u8 valid_tx_ant; @@ -590,10 +550,18 @@ struct iwl_hw_params { u32 max_pkt_size; u8 max_stations; u8 bcast_sta_id; + u8 fat_channel; + u8 sw_crypto; + u32 max_inst_size; + u32 max_data_size; + u32 max_bsm_size; + u32 ct_kill_threshold; /* value in hw-dependent units */ + const struct iwl_sensitivity_ranges *sens; + u8 first_ampdu_q; }; -#define HT_SHORT_GI_20MHZ_ONLY (1 << 0) -#define HT_SHORT_GI_40MHZ_ONLY (1 << 1) +#define HT_SHORT_GI_20MHZ (1 << 0) +#define HT_SHORT_GI_40MHZ (1 << 1) #define IWL_RX_HDR(x) ((struct iwl4965_rx_frame_hdr *)(\ @@ -612,51 +580,18 @@ struct iwl_hw_params { * for use by iwl-*.c * *****************************************************************************/ -struct iwl4965_addsta_cmd; -extern int iwl4965_send_add_station(struct iwl_priv *priv, - struct iwl4965_addsta_cmd *sta, u8 flags); -extern u8 iwl4965_add_station_flags(struct iwl_priv *priv, const u8 *addr, - int is_ap, u8 flags, void *ht_data); -extern int iwl4965_is_network_packet(struct iwl_priv *priv, - struct ieee80211_hdr *header); -extern int iwl4965_power_init_handle(struct iwl_priv *priv); -extern void iwl4965_handle_data_packet_monitor(struct iwl_priv *priv, - struct iwl4965_rx_mem_buffer *rxb, - void *data, short len, - struct ieee80211_rx_status *stats, - u16 phy_flags); -extern int iwl4965_is_duplicate_packet(struct iwl_priv *priv, - struct ieee80211_hdr *header); -extern int iwl4965_rx_queue_alloc(struct iwl_priv *priv); -extern void iwl4965_rx_queue_reset(struct iwl_priv *priv, - struct iwl4965_rx_queue *rxq); -extern int iwl4965_calc_db_from_ratio(int sig_ratio); -extern int iwl4965_calc_sig_qual(int rssi_dbm, int noise_dbm); -extern int iwl4965_tx_queue_init(struct iwl_priv *priv, - struct iwl4965_tx_queue *txq, int count, u32 id); -extern void iwl4965_rx_replenish(void *data); -extern void iwl4965_tx_queue_free(struct iwl_priv *priv, struct iwl4965_tx_queue *txq); +struct iwl_addsta_cmd; +extern int iwl_send_add_sta(struct iwl_priv *priv, + struct iwl_addsta_cmd *sta, u8 flags); +u8 iwl_add_station_flags(struct iwl_priv *priv, const u8 *addr, int is_ap, + u8 flags, struct ieee80211_ht_info *ht_info); extern unsigned int iwl4965_fill_beacon_frame(struct iwl_priv *priv, struct ieee80211_hdr *hdr, const u8 *dest, int left); -extern int iwl4965_rx_queue_update_write_ptr(struct iwl_priv *priv, - struct iwl4965_rx_queue *q); -extern void iwl4965_set_decrypted_flag(struct iwl_priv *priv, struct sk_buff *skb, - u32 decrypt_res, - struct ieee80211_rx_status *stats); -extern __le16 *ieee80211_get_qos_ctrl(struct ieee80211_hdr *hdr); -int iwl4965_init_geos(struct iwl_priv *priv); -void iwl4965_free_geos(struct iwl_priv *priv); - -extern const u8 iwl4965_broadcast_addr[ETH_ALEN]; -int iwl4965_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd); +extern void iwl4965_update_chain_flags(struct iwl_priv *priv); +int iwl4965_set_pwr_src(struct iwl_priv *priv, enum iwl_pwr_src src); -/* - * Currently used by iwl-3945-rs... look at restructuring so that it doesn't - * call this... todo... fix that. -*/ -extern u8 iwl4965_sync_station(struct iwl_priv *priv, int sta_id, - u16 tx_rate, u8 flags); +extern const u8 iwl_bcast_addr[ETH_ALEN]; /****************************************************************************** * @@ -674,96 +609,51 @@ extern u8 iwl4965_sync_station(struct iwl_priv *priv, int sta_id, * iwl4965_mac_ <-- mac80211 callback * ****************************************************************************/ -extern void iwl4965_hw_rx_handler_setup(struct iwl_priv *priv); -extern void iwl4965_hw_setup_deferred_work(struct iwl_priv *priv); -extern void iwl4965_hw_cancel_deferred_work(struct iwl_priv *priv); -extern int iwl4965_hw_rxq_stop(struct iwl_priv *priv); -extern int iwl4965_hw_set_hw_params(struct iwl_priv *priv); -extern int iwl4965_hw_nic_init(struct iwl_priv *priv); -extern int iwl4965_hw_nic_stop_master(struct iwl_priv *priv); -extern void iwl4965_hw_txq_ctx_free(struct iwl_priv *priv); -extern void iwl4965_hw_txq_ctx_stop(struct iwl_priv *priv); -extern int iwl4965_hw_nic_reset(struct iwl_priv *priv); -extern int iwl4965_hw_txq_attach_buf_to_tfd(struct iwl_priv *priv, void *tfd, - dma_addr_t addr, u16 len); -extern int iwl4965_hw_txq_free_tfd(struct iwl_priv *priv, struct iwl4965_tx_queue *txq); -extern int iwl4965_hw_get_temperature(struct iwl_priv *priv); -extern int iwl4965_hw_tx_queue_init(struct iwl_priv *priv, - struct iwl4965_tx_queue *txq); +extern int iwl_rxq_stop(struct iwl_priv *priv); +extern void iwl_txq_ctx_stop(struct iwl_priv *priv); extern unsigned int iwl4965_hw_get_beacon_cmd(struct iwl_priv *priv, - struct iwl4965_frame *frame, u8 rate); -extern int iwl4965_hw_get_rx_read(struct iwl_priv *priv); -extern void iwl4965_hw_build_tx_cmd_rate(struct iwl_priv *priv, - struct iwl_cmd *cmd, - struct ieee80211_tx_control *ctrl, - struct ieee80211_hdr *hdr, - int sta_id, int tx_id); -extern int iwl4965_hw_reg_send_txpower(struct iwl_priv *priv); -extern int iwl4965_hw_reg_set_txpower(struct iwl_priv *priv, s8 power); -extern void iwl4965_hw_rx_statistics(struct iwl_priv *priv, - struct iwl4965_rx_mem_buffer *rxb); + struct iwl_frame *frame, u8 rate); extern void iwl4965_disable_events(struct iwl_priv *priv); -extern int iwl4965_get_temperature(const struct iwl_priv *priv); - -/** - * iwl4965_hw_find_station - Find station id for a given BSSID - * @bssid: MAC address of station ID to find - * - * NOTE: This should not be hardware specific but the code has - * not yet been merged into a single common layer for managing the - * station tables. - */ -extern u8 iwl4965_hw_find_station(struct iwl_priv *priv, const u8 *bssid); extern int iwl4965_hw_channel_switch(struct iwl_priv *priv, u16 channel); -extern int iwl4965_tx_queue_reclaim(struct iwl_priv *priv, int txq_id, int index); -extern int iwl4965_queue_space(const struct iwl4965_queue *q); +extern int iwl_queue_space(const struct iwl_queue *q); +static inline int iwl_queue_used(const struct iwl_queue *q, int i) +{ + return q->write_ptr > q->read_ptr ? + (i >= q->read_ptr && i < q->write_ptr) : + !(i < q->read_ptr && i >= q->write_ptr); +} + + +static inline u8 get_cmd_index(struct iwl_queue *q, u32 index, int is_huge) +{ + /* This is for scan command, the big buffer at end of command array */ + if (is_huge) + return q->n_window; /* must be power of 2 */ + + /* Otherwise, use normal size buffers */ + return index & (q->n_window - 1); +} + + struct iwl_priv; -extern void iwl4965_radio_kill_sw(struct iwl_priv *priv, int disable_radio); /* * Forward declare iwl-4965.c functions for iwl-base.c */ -extern int iwl4965_tx_queue_update_wr_ptr(struct iwl_priv *priv, - struct iwl4965_tx_queue *txq, - u16 byte_cnt); -extern void iwl4965_add_station(struct iwl_priv *priv, const u8 *addr, - int is_ap); -extern void iwl4965_set_rxon_chain(struct iwl_priv *priv); -extern int iwl4965_alive_notify(struct iwl_priv *priv); -extern void iwl4965_update_rate_scaling(struct iwl_priv *priv, u8 mode); -extern void iwl4965_chain_noise_reset(struct iwl_priv *priv); -extern void iwl4965_init_sensitivity(struct iwl_priv *priv, u8 flags, - u8 force); extern void iwl4965_rf_kill_ct_config(struct iwl_priv *priv); -extern void iwl4965_hwrate_to_tx_control(struct iwl_priv *priv, - u32 rate_n_flags, - struct ieee80211_tx_control *control); - -#ifdef CONFIG_IWL4965_HT -void iwl4965_init_ht_hw_capab(struct iwl_priv *priv, - struct ieee80211_ht_info *ht_info, - enum ieee80211_band band); -void iwl4965_set_rxon_ht(struct iwl_priv *priv, - struct iwl_ht_info *ht_info); -void iwl4965_set_ht_add_station(struct iwl_priv *priv, u8 index, - struct ieee80211_ht_info *sta_ht_inf); + int iwl4965_mac_ampdu_action(struct ieee80211_hw *hw, enum ieee80211_ampdu_mlme_action action, const u8 *addr, u16 tid, u16 *ssn); int iwl4965_check_empty_hw_queue(struct iwl_priv *priv, int sta_id, u8 tid, int txq_id); -#else -static inline void iwl4965_init_ht_hw_capab(struct iwl_priv *priv, - struct ieee80211_ht_info *ht_info, - enum ieee80211_band band) {} -#endif /*CONFIG_IWL4965_HT */ /* Structures, enum, and defines specific to the 4965 */ -#define IWL4965_KW_SIZE 0x1000 /*4k */ +#define IWL_KW_SIZE 0x1000 /*4k */ -struct iwl4965_kw { +struct iwl_kw { dma_addr_t dma_addr; void *v_addr; size_t size; @@ -782,13 +672,8 @@ struct iwl4965_kw { #define IWL_OPERATION_MODE_MIXED 2 #define IWL_OPERATION_MODE_20MHZ 3 -#define IWL_EXT_CHANNEL_OFFSET_NONE 0 -#define IWL_EXT_CHANNEL_OFFSET_ABOVE 1 -#define IWL_EXT_CHANNEL_OFFSET_RESERVE1 2 -#define IWL_EXT_CHANNEL_OFFSET_BELOW 3 - -#define NRG_NUM_PREV_STAT_L 20 -#define NUM_RX_CHAINS (3) +#define IWL_TX_CRC_SIZE 4 +#define IWL_TX_DELIMITER_SIZE 4 #define TX_POWER_IWL_ILLEGAL_VOLTAGE -10000 @@ -802,7 +687,6 @@ struct iwl4965_lq_mngr { unsigned long stamp_last; u32 flush_time; u32 tx_packets; - u8 lq_ready; }; /* Sensitivity and chain noise calibration */ @@ -818,23 +702,8 @@ struct iwl4965_lq_mngr { #define MAX_FA_CCK 50 #define MIN_FA_CCK 5 -#define NRG_MIN_CCK 97 -#define NRG_MAX_CCK 0 - -#define AUTO_CORR_MIN_OFDM 85 -#define AUTO_CORR_MIN_OFDM_MRC 170 -#define AUTO_CORR_MIN_OFDM_X1 105 -#define AUTO_CORR_MIN_OFDM_MRC_X1 220 -#define AUTO_CORR_MAX_OFDM 120 -#define AUTO_CORR_MAX_OFDM_MRC 210 -#define AUTO_CORR_MAX_OFDM_X1 140 -#define AUTO_CORR_MAX_OFDM_MRC_X1 270 #define AUTO_CORR_STEP_OFDM 1 -#define AUTO_CORR_MIN_CCK (125) -#define AUTO_CORR_MAX_CCK (200) -#define AUTO_CORR_MIN_CCK_MRC 200 -#define AUTO_CORR_MAX_CCK_MRC 400 #define AUTO_CORR_STEP_CCK 3 #define AUTO_CORR_MAX_TH_CCK 160 @@ -853,6 +722,9 @@ struct iwl4965_lq_mngr { #define IN_BAND_FILTER 0xFF #define MIN_AVERAGE_NOISE_MAX_VALUE 0xFFFFFFFF +#define NRG_NUM_PREV_STAT_L 20 +#define NUM_RX_CHAINS 3 + enum iwl4965_false_alarm_state { IWL_FA_TOO_MANY = 0, IWL_FA_TOO_FEW = 1, @@ -865,11 +737,6 @@ enum iwl4965_chain_noise_state { IWL_CHAIN_NOISE_CALIBRATED = 2, }; -enum iwl4965_sensitivity_state { - IWL_SENS_CALIB_ALLOWED = 0, - IWL_SENS_CALIB_NEED_REINIT = 1, -}; - enum iwl4965_calib_enabled_state { IWL_CALIB_DISABLED = 0, /* must be 0 */ IWL_CALIB_ENABLED = 1, @@ -884,8 +751,23 @@ struct statistics_general_data { u32 beacon_energy_c; }; +struct iwl_calib_results { + void *tx_iq_res; + void *tx_iq_perd_res; + void *lo_res; + u32 tx_iq_res_len; + u32 tx_iq_perd_res_len; + u32 lo_res_len; +}; + +enum ucode_type { + UCODE_NONE = 0, + UCODE_INIT, + UCODE_RT +}; + /* Sensitivity calib data */ -struct iwl4965_sensitivity_data { +struct iwl_sensitivity_data { u32 auto_corr_ofdm; u32 auto_corr_ofdm_mrc; u32 auto_corr_ofdm_x1; @@ -909,12 +791,10 @@ struct iwl4965_sensitivity_data { s32 nrg_auto_corr_silence_diff; u32 num_in_cck_no_fa; u32 nrg_th_ofdm; - - u8 state; }; /* Chain noise (differential Rx gain) calib data */ -struct iwl4965_chain_noise_data { +struct iwl_chain_noise_data { u8 state; u16 beacon_count; u32 chain_noise_a; @@ -960,7 +840,7 @@ struct iwl_priv { bool add_radiotap; void (*rx_handlers[REPLY_MAX])(struct iwl_priv *priv, - struct iwl4965_rx_mem_buffer *rxb); + struct iwl_rx_mem_buffer *rxb); struct ieee80211_supported_band bands[IEEE80211_NUM_BANDS]; @@ -985,6 +865,9 @@ struct iwl_priv { s32 temperature; /* degrees Kelvin */ s32 last_temperature; + /* init calibration results */ + struct iwl_calib_results calib_results; + /* Scan related variables */ unsigned long last_scan_jiffies; unsigned long next_scan_jiffies; @@ -995,7 +878,8 @@ struct iwl_priv { int one_direct_scan; u8 direct_ssid_len; u8 direct_ssid[IW_ESSID_MAX_SIZE]; - struct iwl4965_scan_cmd *scan; + struct iwl_scan_cmd *scan; + u32 scan_tx_ant[IEEE80211_NUM_BANDS]; /* spinlock */ spinlock_t lock; /* protect general shared data */ @@ -1007,6 +891,9 @@ struct iwl_priv { /* pci hardware address support */ void __iomem *hw_base; + u32 hw_rev; + u32 hw_wa_rev; + u8 rev_id; /* uCode images, save to reload in case of failure */ struct fw_desc ucode_code; /* runtime inst */ @@ -1015,6 +902,8 @@ struct iwl_priv { struct fw_desc ucode_init; /* initialization inst */ struct fw_desc ucode_init_data; /* initialization data */ struct fw_desc ucode_boot; /* bootstrap inst */ + enum ucode_type ucode_type; + u8 ucode_write_complete; /* the image write is complete */ struct iwl4965_rxon_time_cmd rxon_timing; @@ -1023,22 +912,22 @@ struct iwl_priv { * changed via explicit cast within the * routines that actually update the physical * hardware */ - const struct iwl4965_rxon_cmd active_rxon; - struct iwl4965_rxon_cmd staging_rxon; + const struct iwl_rxon_cmd active_rxon; + struct iwl_rxon_cmd staging_rxon; int error_recovering; - struct iwl4965_rxon_cmd recovery_rxon; + struct iwl_rxon_cmd recovery_rxon; /* 1st responses from initialize and runtime uCode images. * 4965's initialize alive response contains some calibration data. */ - struct iwl4965_init_alive_resp card_alive_init; - struct iwl4965_alive_resp card_alive; + struct iwl_init_alive_resp card_alive_init; + struct iwl_alive_resp card_alive; #ifdef CONFIG_IWLWIFI_RFKILL - struct iwl_rfkill_mngr rfkill_mngr; + struct rfkill *rfkill; #endif #ifdef CONFIG_IWLWIFI_LEDS - struct iwl4965_led led[IWL_LED_TRG_MAX]; + struct iwl_led led[IWL_LED_TRG_MAX]; unsigned long last_blink_time; u8 last_blink_rate; u8 allow_blinking; @@ -1050,17 +939,12 @@ struct iwl_priv { u8 assoc_station_added; u8 use_ant_b_for_management_frame; /* Tx antenna selection */ - u8 valid_antenna; /* Bit mask of antennas actually connected */ -#ifdef CONFIG_IWL4965_SENSITIVITY - struct iwl4965_sensitivity_data sensitivity_data; - struct iwl4965_chain_noise_data chain_noise_data; u8 start_calib; + struct iwl_sensitivity_data sensitivity_data; + struct iwl_chain_noise_data chain_noise_data; __le16 sensitivity_tbl[HD_TABLE_SIZE]; -#endif /*CONFIG_IWL4965_SENSITIVITY*/ -#ifdef CONFIG_IWL4965_HT struct iwl_ht_info current_ht_config; -#endif u8 last_phy_res[100]; /* Rate scaling data */ @@ -1075,10 +959,10 @@ struct iwl_priv { int activity_timer_active; /* Rx and Tx DMA processing queues */ - struct iwl4965_rx_queue rxq; - struct iwl4965_tx_queue txq[IWL_MAX_NUM_QUEUES]; + struct iwl_rx_queue rxq; + struct iwl_tx_queue txq[IWL_MAX_NUM_QUEUES]; unsigned long txq_ctx_active_msk; - struct iwl4965_kw kw; /* keep warm address */ + struct iwl_kw kw; /* keep warm address */ u32 scd_base_addr; /* scheduler sram base address */ unsigned long status; @@ -1092,9 +976,9 @@ struct iwl_priv { u64 bytes; } tx_stats[3], rx_stats[3]; - struct iwl4965_power_mgr power_data; + struct iwl_power_mgr power_data; - struct iwl4965_notif_statistics statistics; + struct iwl_notif_statistics statistics; unsigned long last_statistics_time; /* context information */ @@ -1111,7 +995,7 @@ struct iwl_priv { /*station table variables */ spinlock_t sta_lock; int num_stations; - struct iwl4965_station_entry stations[IWL_STATION_COUNT]; + struct iwl_station_entry stations[IWL_STATION_COUNT]; struct iwl_wep_key wep_keys[WEP_KEYS_MAX]; u8 default_wep_key; u8 key_mapping_key; @@ -1122,22 +1006,13 @@ struct iwl_priv { u8 mac80211_registered; - u32 notif_missed_beacons; - /* Rx'd packet timing information */ u32 last_beacon_time; u64 last_tsf; - /* Duplicate packet detection */ - u16 last_seq_num; - u16 last_frag_num; - unsigned long last_packet_time; - - /* Hash table for finding stations in IBSS network */ - struct list_head ibss_mac_hash[IWL_IBSS_MAC_HASH_SIZE]; - /* eeprom */ - struct iwl4965_eeprom eeprom; + u8 *eeprom; + struct iwl_eeprom_calib_info *calib_info; enum ieee80211_if_types iw_mode; @@ -1151,6 +1026,7 @@ struct iwl_priv { struct iwl_hw_params hw_params; /* driver/uCode shared Tx Byte Counts and Rx status */ void *shared_virt; + int rb_closed_offset; /* Physical Pointer to Tx Byte Counts and Rx status */ dma_addr_t shared_phys; @@ -1160,7 +1036,7 @@ struct iwl_priv { u16 assoc_capability; u8 ps_mode; - struct iwl4965_qos_info qos_data; + struct iwl_qos_info qos_data; struct workqueue_struct *workqueue; @@ -1176,20 +1052,16 @@ struct iwl_priv { struct work_struct report_work; struct work_struct request_scan; struct work_struct beacon_update; + struct work_struct set_monitor; struct tasklet_struct irq_tasklet; struct delayed_work init_alive_start; struct delayed_work alive_start; - struct delayed_work activity_timer; - struct delayed_work thermal_periodic; - struct delayed_work gather_stats; struct delayed_work scan_check; - struct delayed_work post_associate; - -#define IWL_DEFAULT_TX_POWER 0x0F - s8 user_txpower_limit; - s8 max_channel_txpower_limit; + /* TX Power */ + s8 tx_power_user_lmt; + s8 tx_power_channel_lmt; #ifdef CONFIG_PM u32 pm_state[16]; @@ -1197,6 +1069,7 @@ struct iwl_priv { #ifdef CONFIG_IWLWIFI_DEBUG /* debugging info */ + u32 debug_level; u32 framecnt_to_us; atomic_t restrict_refcnt; #ifdef CONFIG_IWLWIFI_DEBUGFS @@ -1206,12 +1079,40 @@ struct iwl_priv { #endif /* CONFIG_IWLWIFI_DEBUG */ struct work_struct txpower_work; -#ifdef CONFIG_IWL4965_SENSITIVITY - struct work_struct sensitivity_work; -#endif + u32 disable_sens_cal; + u32 disable_chain_noise_cal; + u32 disable_tx_power_cal; + struct work_struct run_time_calib_work; struct timer_list statistics_periodic; }; /*iwl_priv */ +static inline void iwl_txq_ctx_activate(struct iwl_priv *priv, int txq_id) +{ + set_bit(txq_id, &priv->txq_ctx_active_msk); +} + +static inline void iwl_txq_ctx_deactivate(struct iwl_priv *priv, int txq_id) +{ + clear_bit(txq_id, &priv->txq_ctx_active_msk); +} + +#ifdef CONFIG_IWLWIFI_DEBUG +const char *iwl_get_tx_fail_reason(u32 status); +#else +static inline const char *iwl_get_tx_fail_reason(u32 status) { return ""; } +#endif + + +static inline struct ieee80211_hdr *iwl_tx_queue_get_hdr(struct iwl_priv *priv, + int txq_id, int idx) +{ + if (priv->txq[txq_id].txb[idx].skb[0]) + return (struct ieee80211_hdr *)priv->txq[txq_id]. + txb[idx].skb[0]->data; + return NULL; +} + + static inline int iwl_is_associated(struct iwl_priv *priv) { return (priv->active_rxon.filter_flags & RXON_FILTER_ASSOC_MSK) ? 1 : 0; @@ -1224,11 +1125,6 @@ static inline int is_channel_valid(const struct iwl_channel_info *ch_info) return (ch_info->flags & EEPROM_CHANNEL_VALID) ? 1 : 0; } -static inline int is_channel_narrow(const struct iwl_channel_info *ch_info) -{ - return (ch_info->flags & EEPROM_CHANNEL_NARROW) ? 1 : 0; -} - static inline int is_channel_radar(const struct iwl_channel_info *ch_info) { return (ch_info->flags & EEPROM_CHANNEL_RADAR) ? 1 : 0; @@ -1254,9 +1150,26 @@ static inline int is_channel_ibss(const struct iwl_channel_info *ch) return ((ch->flags & EEPROM_CHANNEL_IBSS)) ? 1 : 0; } +#ifdef CONFIG_IWLWIFI_DEBUG +static inline void iwl_print_hex_dump(struct iwl_priv *priv, int level, + void *p, u32 len) +{ + if (!(priv->debug_level & level)) + return; + + print_hex_dump(KERN_DEBUG, "iwl data: ", DUMP_PREFIX_OFFSET, 16, 1, + p, len, 1); +} +#else +static inline void iwl_print_hex_dump(struct iwl_priv *priv, int level, + void *p, u32 len) +{ +} +#endif + extern const struct iwl_channel_info *iwl_get_channel_info( const struct iwl_priv *priv, enum ieee80211_band band, u16 channel); /* Requires full declaration of iwl_priv before including */ -#endif /* __iwl4965_4965_h__ */ +#endif /* __iwl_dev_h__ */ diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.c b/drivers/net/wireless/iwlwifi/iwl-eeprom.c index a07d5dcb7abc..4a08a1b50979 100644 --- a/drivers/net/wireless/iwlwifi/iwl-eeprom.c +++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.c @@ -68,8 +68,8 @@ #include <net/mac80211.h> -#include "iwl-4965-commands.h" -#include "iwl-4965.h" +#include "iwl-commands.h" +#include "iwl-dev.h" #include "iwl-core.h" #include "iwl-debug.h" #include "iwl-eeprom.h" @@ -193,6 +193,12 @@ void iwlcore_eeprom_release_semaphore(struct iwl_priv *priv) } EXPORT_SYMBOL(iwlcore_eeprom_release_semaphore); +const u8 *iwlcore_eeprom_query_addr(const struct iwl_priv *priv, size_t offset) +{ + BUG_ON(offset >= priv->cfg->eeprom_size); + return &priv->eeprom[offset]; +} +EXPORT_SYMBOL(iwlcore_eeprom_query_addr); /** * iwl_eeprom_init - read EEPROM contents @@ -203,30 +209,35 @@ EXPORT_SYMBOL(iwlcore_eeprom_release_semaphore); */ int iwl_eeprom_init(struct iwl_priv *priv) { - u16 *e = (u16 *)&priv->eeprom; + u16 *e; u32 gp = iwl_read32(priv, CSR_EEPROM_GP); u32 r; - int sz = sizeof(priv->eeprom); + int sz = priv->cfg->eeprom_size; int ret; int i; u16 addr; - /* The EEPROM structure has several padding buffers within it - * and when adding new EEPROM maps is subject to programmer errors - * which may be very difficult to identify without explicitly - * checking the resulting size of the eeprom map. */ - BUILD_BUG_ON(sizeof(priv->eeprom) != IWL_EEPROM_IMAGE_SIZE); + /* allocate eeprom */ + priv->eeprom = kzalloc(sz, GFP_KERNEL); + if (!priv->eeprom) { + ret = -ENOMEM; + goto alloc_err; + } + e = (u16 *)priv->eeprom; - if ((gp & CSR_EEPROM_GP_VALID_MSK) == CSR_EEPROM_GP_BAD_SIGNATURE) { + ret = priv->cfg->ops->lib->eeprom_ops.verify_signature(priv); + if (ret < 0) { IWL_ERROR("EEPROM not found, EEPROM_GP=0x%08x", gp); - return -ENOENT; + ret = -ENOENT; + goto err; } /* Make sure driver (instead of uCode) is allowed to read EEPROM */ ret = priv->cfg->ops->lib->eeprom_ops.acquire_semaphore(priv); if (ret < 0) { IWL_ERROR("Failed to acquire EEPROM semaphore.\n"); - return -ENOENT; + ret = -ENOENT; + goto err; } /* eeprom is an array of 16bit values */ @@ -250,61 +261,98 @@ int iwl_eeprom_init(struct iwl_priv *priv) 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); +alloc_err: return ret; } EXPORT_SYMBOL(iwl_eeprom_init); +void iwl_eeprom_free(struct iwl_priv *priv) +{ + if(priv->eeprom) + kfree(priv->eeprom); + priv->eeprom = NULL; +} +EXPORT_SYMBOL(iwl_eeprom_free); + +int iwl_eeprom_check_version(struct iwl_priv *priv) +{ + return priv->cfg->ops->lib->eeprom_ops.check_version(priv); +} +EXPORT_SYMBOL(iwl_eeprom_check_version); + +const u8 *iwl_eeprom_query_addr(const struct iwl_priv *priv, size_t offset) +{ + return priv->cfg->ops->lib->eeprom_ops.query_addr(priv, offset); +} +EXPORT_SYMBOL(iwl_eeprom_query_addr); + +u16 iwl_eeprom_query16(const struct iwl_priv *priv, size_t offset) +{ + return (u16)priv->eeprom[offset] | ((u16)priv->eeprom[offset + 1] << 8); +} +EXPORT_SYMBOL(iwl_eeprom_query16); void iwl_eeprom_get_mac(const struct iwl_priv *priv, u8 *mac) { - memcpy(mac, priv->eeprom.mac_address, 6); + const u8 *addr = priv->cfg->ops->lib->eeprom_ops.query_addr(priv, + EEPROM_MAC_ADDRESS); + memcpy(mac, addr, ETH_ALEN); } EXPORT_SYMBOL(iwl_eeprom_get_mac); static void iwl_init_band_reference(const struct iwl_priv *priv, - int band, - int *eeprom_ch_count, - const struct iwl4965_eeprom_channel - **eeprom_ch_info, - const u8 **eeprom_ch_index) + int eep_band, int *eeprom_ch_count, + const struct iwl_eeprom_channel **eeprom_ch_info, + const u8 **eeprom_ch_index) { - switch (band) { + u32 offset = priv->cfg->ops->lib-> + eeprom_ops.regulatory_bands[eep_band - 1]; + switch (eep_band) { case 1: /* 2.4GHz band */ *eeprom_ch_count = ARRAY_SIZE(iwl_eeprom_band_1); - *eeprom_ch_info = priv->eeprom.band_1_channels; + *eeprom_ch_info = (struct iwl_eeprom_channel *) + iwl_eeprom_query_addr(priv, offset); *eeprom_ch_index = iwl_eeprom_band_1; break; case 2: /* 4.9GHz band */ *eeprom_ch_count = ARRAY_SIZE(iwl_eeprom_band_2); - *eeprom_ch_info = priv->eeprom.band_2_channels; + *eeprom_ch_info = (struct iwl_eeprom_channel *) + iwl_eeprom_query_addr(priv, offset); *eeprom_ch_index = iwl_eeprom_band_2; break; case 3: /* 5.2GHz band */ *eeprom_ch_count = ARRAY_SIZE(iwl_eeprom_band_3); - *eeprom_ch_info = priv->eeprom.band_3_channels; + *eeprom_ch_info = (struct iwl_eeprom_channel *) + iwl_eeprom_query_addr(priv, offset); *eeprom_ch_index = iwl_eeprom_band_3; break; case 4: /* 5.5GHz band */ *eeprom_ch_count = ARRAY_SIZE(iwl_eeprom_band_4); - *eeprom_ch_info = priv->eeprom.band_4_channels; + *eeprom_ch_info = (struct iwl_eeprom_channel *) + iwl_eeprom_query_addr(priv, offset); *eeprom_ch_index = iwl_eeprom_band_4; break; case 5: /* 5.7GHz band */ *eeprom_ch_count = ARRAY_SIZE(iwl_eeprom_band_5); - *eeprom_ch_info = priv->eeprom.band_5_channels; + *eeprom_ch_info = (struct iwl_eeprom_channel *) + iwl_eeprom_query_addr(priv, offset); *eeprom_ch_index = iwl_eeprom_band_5; break; case 6: /* 2.4GHz FAT channels */ *eeprom_ch_count = ARRAY_SIZE(iwl_eeprom_band_6); - *eeprom_ch_info = priv->eeprom.band_24_channels; + *eeprom_ch_info = (struct iwl_eeprom_channel *) + iwl_eeprom_query_addr(priv, offset); *eeprom_ch_index = iwl_eeprom_band_6; break; case 7: /* 5 GHz FAT channels */ *eeprom_ch_count = ARRAY_SIZE(iwl_eeprom_band_7); - *eeprom_ch_info = priv->eeprom.band_52_channels; + *eeprom_ch_info = (struct iwl_eeprom_channel *) + iwl_eeprom_query_addr(priv, offset); *eeprom_ch_index = iwl_eeprom_band_7; break; default: @@ -317,13 +365,13 @@ static void iwl_init_band_reference(const struct iwl_priv *priv, ? # x " " : "") /** - * iwl4965_set_fat_chan_info - Copy fat channel info into driver's priv. + * iwl_set_fat_chan_info - Copy fat channel info into driver's priv. * * Does not set up a command, or touch hardware. */ -static int iwl4965_set_fat_chan_info(struct iwl_priv *priv, +static int iwl_set_fat_chan_info(struct iwl_priv *priv, enum ieee80211_band band, u16 channel, - const struct iwl4965_eeprom_channel *eeprom_ch, + const struct iwl_eeprom_channel *eeprom_ch, u8 fat_extension_channel) { struct iwl_channel_info *ch_info; @@ -334,8 +382,8 @@ static int iwl4965_set_fat_chan_info(struct iwl_priv *priv, if (!is_channel_valid(ch_info)) return -1; - IWL_DEBUG_INFO("FAT Ch. %d [%sGHz] %s%s%s%s%s%s(0x%02x" - " %ddBm): Ad-Hoc %ssupported\n", + IWL_DEBUG_INFO("FAT Ch. %d [%sGHz] %s%s%s%s%s(0x%02x %ddBm):" + " Ad-Hoc %ssupported\n", ch_info->channel, is_channel_a_band(ch_info) ? "5.2" : "2.4", @@ -343,7 +391,6 @@ static int iwl4965_set_fat_chan_info(struct iwl_priv *priv, CHECK_AND_PRINT(ACTIVE), CHECK_AND_PRINT(RADAR), CHECK_AND_PRINT(WIDE), - CHECK_AND_PRINT(NARROW), CHECK_AND_PRINT(DFS), eeprom_ch->flags, eeprom_ch->max_power_avg, @@ -372,7 +419,7 @@ int iwl_init_channel_map(struct iwl_priv *priv) { int eeprom_ch_count = 0; const u8 *eeprom_ch_index = NULL; - const struct iwl4965_eeprom_channel *eeprom_ch_info = NULL; + const struct iwl_eeprom_channel *eeprom_ch_info = NULL; int band, ch; struct iwl_channel_info *ch_info; @@ -381,12 +428,6 @@ int iwl_init_channel_map(struct iwl_priv *priv) return 0; } - if (priv->eeprom.version < 0x2f) { - IWL_WARNING("Unsupported EEPROM version: 0x%04X\n", - priv->eeprom.version); - return -EINVAL; - } - IWL_DEBUG_INFO("Initializing regulatory info from EEPROM\n"); priv->channel_count = @@ -429,6 +470,11 @@ int iwl_init_channel_map(struct iwl_priv *priv) /* Copy the run-time flags so they are there even on * invalid channels */ ch_info->flags = eeprom_ch_info[ch].flags; + /* 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); if (!(is_channel_valid(ch_info))) { IWL_DEBUG_INFO("Ch. %d Flags %x [%sGHz] - " @@ -447,8 +493,8 @@ int iwl_init_channel_map(struct iwl_priv *priv) ch_info->scan_power = eeprom_ch_info[ch].max_power_avg; ch_info->min_power = 0; - IWL_DEBUG_INFO("Ch. %d [%sGHz] %s%s%s%s%s%s%s(0x%02x" - " %ddBm): Ad-Hoc %ssupported\n", + IWL_DEBUG_INFO("Ch. %d [%sGHz] %s%s%s%s%s%s(0x%02x %ddBm):" + " Ad-Hoc %ssupported\n", ch_info->channel, is_channel_a_band(ch_info) ? "5.2" : "2.4", @@ -457,7 +503,6 @@ int iwl_init_channel_map(struct iwl_priv *priv) CHECK_AND_PRINT_I(ACTIVE), CHECK_AND_PRINT_I(RADAR), CHECK_AND_PRINT_I(WIDE), - CHECK_AND_PRINT_I(NARROW), CHECK_AND_PRINT_I(DFS), eeprom_ch_info[ch].flags, eeprom_ch_info[ch].max_power_avg, @@ -470,8 +515,8 @@ int iwl_init_channel_map(struct iwl_priv *priv) /* Set the user_txpower_limit to the highest power * supported by any channel */ if (eeprom_ch_info[ch].max_power_avg > - priv->user_txpower_limit) - priv->user_txpower_limit = + priv->tx_power_user_lmt) + priv->tx_power_user_lmt = eeprom_ch_info[ch].max_power_avg; ch_info++; @@ -494,24 +539,26 @@ int iwl_init_channel_map(struct iwl_priv *priv) for (ch = 0; ch < eeprom_ch_count; ch++) { if ((band == 6) && - ((eeprom_ch_index[ch] == 5) || - (eeprom_ch_index[ch] == 6) || - (eeprom_ch_index[ch] == 7))) - fat_extension_chan = HT_IE_EXT_CHANNEL_MAX; + ((eeprom_ch_index[ch] == 5) || + (eeprom_ch_index[ch] == 6) || + (eeprom_ch_index[ch] == 7))) + /* both are allowed: above and below */ + fat_extension_chan = 0; else - fat_extension_chan = HT_IE_EXT_CHANNEL_ABOVE; + fat_extension_chan = + IEEE80211_CHAN_NO_FAT_BELOW; /* Set up driver's info for lower half */ - iwl4965_set_fat_chan_info(priv, ieeeband, - eeprom_ch_index[ch], - &(eeprom_ch_info[ch]), - fat_extension_chan); + iwl_set_fat_chan_info(priv, ieeeband, + eeprom_ch_index[ch], + &(eeprom_ch_info[ch]), + fat_extension_chan); /* Set up driver's info for upper half */ - iwl4965_set_fat_chan_info(priv, ieeeband, - (eeprom_ch_index[ch] + 4), - &(eeprom_ch_info[ch]), - HT_IE_EXT_CHANNEL_BELOW); + iwl_set_fat_chan_info(priv, ieeeband, + (eeprom_ch_index[ch] + 4), + &(eeprom_ch_info[ch]), + IEEE80211_CHAN_NO_FAT_ABOVE); } } @@ -520,23 +567,21 @@ int iwl_init_channel_map(struct iwl_priv *priv) EXPORT_SYMBOL(iwl_init_channel_map); /* - * iwl_free_channel_map - undo allocations in iwl4965_init_channel_map + * iwl_free_channel_map - undo allocations in iwl_init_channel_map */ void iwl_free_channel_map(struct iwl_priv *priv) { kfree(priv->channel_info); priv->channel_count = 0; } -EXPORT_SYMBOL(iwl_free_channel_map); /** * iwl_get_channel_info - Find driver's private channel info * * Based on band and channel number. */ -const struct iwl_channel_info *iwl_get_channel_info( - const struct iwl_priv *priv, - enum ieee80211_band band, u16 channel) +const struct iwl_channel_info *iwl_get_channel_info(const struct iwl_priv *priv, + enum ieee80211_band band, u16 channel) { int i; diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.h b/drivers/net/wireless/iwlwifi/iwl-eeprom.h index bd0a042ca77f..d3a2a5b4ac56 100644 --- a/drivers/net/wireless/iwlwifi/iwl-eeprom.h +++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.h @@ -106,7 +106,7 @@ enum { EEPROM_CHANNEL_ACTIVE = (1 << 3), /* active scanning allowed */ EEPROM_CHANNEL_RADAR = (1 << 4), /* radar detection required */ EEPROM_CHANNEL_WIDE = (1 << 5), /* 20 MHz channel okay */ - EEPROM_CHANNEL_NARROW = (1 << 6), /* 10 MHz channel (not used) */ + /* Bit 6 Reserved (was Narrow Channel) */ EEPROM_CHANNEL_DFS = (1 << 7), /* dynamic freq selection candidate */ }; @@ -116,7 +116,7 @@ enum { /* *regulatory* channel data format in eeprom, one for each channel. * There are separate entries for FAT (40 MHz) vs. normal (20 MHz) channels. */ -struct iwl4965_eeprom_channel { +struct iwl_eeprom_channel { u8 flags; /* EEPROM_CHANNEL_* flags copied from EEPROM */ s8 max_power_avg; /* max power (dBm) on this chnl, limit 31 */ } __attribute__ ((packed)); @@ -131,17 +131,55 @@ struct iwl4965_eeprom_channel { * each of 3 target output levels */ #define EEPROM_TX_POWER_MEASUREMENTS (3) -#define EEPROM_4965_TX_POWER_VERSION (2) +/* 4965 Specific */ +/* 4965 driver does not work with txpower calibration version < 5 */ +#define EEPROM_4965_TX_POWER_VERSION (5) +#define EEPROM_4965_EEPROM_VERSION (0x2f) +#define EEPROM_4965_CALIB_VERSION_OFFSET (2*0xB6) /* 2 bytes */ +#define EEPROM_4965_CALIB_TXPOWER_OFFSET (2*0xE8) /* 48 bytes */ +#define EEPROM_4965_BOARD_REVISION (2*0x4F) /* 2 bytes */ +#define EEPROM_4965_BOARD_PBA (2*0x56+1) /* 9 bytes */ + +/* 5000 Specific */ +#define EEPROM_5000_TX_POWER_VERSION (4) +#define EEPROM_5000_EEPROM_VERSION (0x11A) + +/*5000 calibrations */ +#define EEPROM_5000_CALIB_ALL (INDIRECT_ADDRESS | INDIRECT_CALIBRATION) +#define EEPROM_5000_XTAL ((2*0x128) | EEPROM_5000_CALIB_ALL) + +/* 5000 links */ +#define EEPROM_5000_LINK_HOST (2*0x64) +#define EEPROM_5000_LINK_GENERAL (2*0x65) +#define EEPROM_5000_LINK_REGULATORY (2*0x66) +#define EEPROM_5000_LINK_CALIBRATION (2*0x67) +#define EEPROM_5000_LINK_PROCESS_ADJST (2*0x68) +#define EEPROM_5000_LINK_OTHERS (2*0x69) + +/* 5000 regulatory - indirect access */ +#define EEPROM_5000_REG_SKU_ID ((0x02)\ + | INDIRECT_ADDRESS | INDIRECT_REGULATORY) /* 4 bytes */ +#define EEPROM_5000_REG_BAND_1_CHANNELS ((0x08)\ + | INDIRECT_ADDRESS | INDIRECT_REGULATORY) /* 28 bytes */ +#define EEPROM_5000_REG_BAND_2_CHANNELS ((0x26)\ + | INDIRECT_ADDRESS | INDIRECT_REGULATORY) /* 26 bytes */ +#define EEPROM_5000_REG_BAND_3_CHANNELS ((0x42)\ + | INDIRECT_ADDRESS | INDIRECT_REGULATORY) /* 24 bytes */ +#define EEPROM_5000_REG_BAND_4_CHANNELS ((0x5C)\ + | INDIRECT_ADDRESS | INDIRECT_REGULATORY) /* 22 bytes */ +#define EEPROM_5000_REG_BAND_5_CHANNELS ((0x74)\ + | INDIRECT_ADDRESS | INDIRECT_REGULATORY) /* 12 bytes */ +#define EEPROM_5000_REG_BAND_24_FAT_CHANNELS ((0x82)\ + | INDIRECT_ADDRESS | INDIRECT_REGULATORY) /* 14 bytes */ +#define EEPROM_5000_REG_BAND_52_FAT_CHANNELS ((0x92)\ + | INDIRECT_ADDRESS | INDIRECT_REGULATORY) /* 22 bytes */ -/* 4965 driver does not work with txpower calibration version < 5. - * Look for this in calib_version member of struct iwl4965_eeprom. */ -#define EEPROM_TX_POWER_VERSION_NEW (5) /* 2.4 GHz */ extern const u8 iwl_eeprom_band_1[14]; /* - * 4965 factory calibration data for one txpower level, on one channel, + * factory calibration data for one txpower level, on one channel, * measured on one of the 2 tx chains (radio transmitter and associated * antenna). EEPROM contains: * @@ -154,7 +192,7 @@ extern const u8 iwl_eeprom_band_1[14]; * * 4) RF power amplifier detector level measurement (not used). */ -struct iwl4965_eeprom_calib_measure { +struct iwl_eeprom_calib_measure { u8 temperature; /* Device temperature (Celsius) */ u8 gain_idx; /* Index into gain table */ u8 actual_pow; /* Measured RF output power, half-dBm */ @@ -163,22 +201,22 @@ struct iwl4965_eeprom_calib_measure { /* - * 4965 measurement set for one channel. EEPROM contains: + * measurement set for one channel. EEPROM contains: * * 1) Channel number measured * * 2) Measurements for each of 3 power levels for each of 2 radio transmitters * (a.k.a. "tx chains") (6 measurements altogether) */ -struct iwl4965_eeprom_calib_ch_info { +struct iwl_eeprom_calib_ch_info { u8 ch_num; - struct iwl4965_eeprom_calib_measure + struct iwl_eeprom_calib_measure measurements[EEPROM_TX_POWER_TX_CHAINS] [EEPROM_TX_POWER_MEASUREMENTS]; } __attribute__ ((packed)); /* - * 4965 txpower subband info. + * txpower subband info. * * For each frequency subband, EEPROM contains the following: * @@ -187,16 +225,16 @@ struct iwl4965_eeprom_calib_ch_info { * * 2) Sample measurement sets for 2 channels close to the range endpoints. */ -struct iwl4965_eeprom_calib_subband_info { +struct iwl_eeprom_calib_subband_info { u8 ch_from; /* channel number of lowest channel in subband */ u8 ch_to; /* channel number of highest channel in subband */ - struct iwl4965_eeprom_calib_ch_info ch1; - struct iwl4965_eeprom_calib_ch_info ch2; + struct iwl_eeprom_calib_ch_info ch1; + struct iwl_eeprom_calib_ch_info ch2; } __attribute__ ((packed)); /* - * 4965 txpower calibration info. EEPROM contains: + * txpower calibration info. EEPROM contains: * * 1) Factory-measured saturation power levels (maximum levels at which * tx power amplifier can output a signal without too much distortion). @@ -212,55 +250,58 @@ struct iwl4965_eeprom_calib_subband_info { * characteristics of the analog radio circuitry vary with frequency. * * Not all sets need to be filled with data; - * struct iwl4965_eeprom_calib_subband_info contains range of channels + * struct iwl_eeprom_calib_subband_info contains range of channels * (0 if unused) for each set of data. */ -struct iwl4965_eeprom_calib_info { +struct iwl_eeprom_calib_info { u8 saturation_power24; /* half-dBm (e.g. "34" = 17 dBm) */ u8 saturation_power52; /* half-dBm */ s16 voltage; /* signed */ - struct iwl4965_eeprom_calib_subband_info + struct iwl_eeprom_calib_subband_info band_info[EEPROM_TX_POWER_BANDS]; } __attribute__ ((packed)); - -/* - * 4965 EEPROM map - */ -struct iwl4965_eeprom { - u8 reserved0[16]; - u16 device_id; /* abs.ofs: 16 */ - u8 reserved1[2]; - u16 pmc; /* abs.ofs: 20 */ - u8 reserved2[20]; - u8 mac_address[6]; /* abs.ofs: 42 */ - u8 reserved3[58]; - u16 board_revision; /* abs.ofs: 106 */ - u8 reserved4[11]; - u8 board_pba_number[9]; /* abs.ofs: 119 */ - u8 reserved5[8]; - u16 version; /* abs.ofs: 136 */ - u8 sku_cap; /* abs.ofs: 138 */ - u8 leds_mode; /* abs.ofs: 139 */ - u16 oem_mode; - u16 wowlan_mode; /* abs.ofs: 142 */ - u16 leds_time_interval; /* abs.ofs: 144 */ - u8 leds_off_time; /* abs.ofs: 146 */ - u8 leds_on_time; /* abs.ofs: 147 */ - u8 almgor_m_version; /* abs.ofs: 148 */ - u8 antenna_switch_type; /* abs.ofs: 149 */ - u8 reserved6[8]; - u16 board_revision_4965; /* abs.ofs: 158 */ - u8 reserved7[13]; - u8 board_pba_number_4965[9]; /* abs.ofs: 173 */ - u8 reserved8[10]; - u8 sku_id[4]; /* abs.ofs: 192 */ +#define ADDRESS_MSK 0x0000FFFF +#define INDIRECT_TYPE_MSK 0x000F0000 +#define INDIRECT_HOST 0x00010000 +#define INDIRECT_GENERAL 0x00020000 +#define INDIRECT_REGULATORY 0x00030000 +#define INDIRECT_CALIBRATION 0x00040000 +#define INDIRECT_PROCESS_ADJST 0x00050000 +#define INDIRECT_OTHERS 0x00060000 +#define INDIRECT_ADDRESS 0x00100000 + +/* General */ +#define EEPROM_DEVICE_ID (2*0x08) /* 2 bytes */ +#define EEPROM_MAC_ADDRESS (2*0x15) /* 6 bytes */ +#define EEPROM_BOARD_REVISION (2*0x35) /* 2 bytes */ +#define EEPROM_BOARD_PBA_NUMBER (2*0x3B+1) /* 9 bytes */ +#define EEPROM_VERSION (2*0x44) /* 2 bytes */ +#define EEPROM_SKU_CAP (2*0x45) /* 1 bytes */ +#define EEPROM_LEDS_MODE (2*0x45+1) /* 1 bytes */ +#define EEPROM_OEM_MODE (2*0x46) /* 2 bytes */ +#define EEPROM_WOWLAN_MODE (2*0x47) /* 2 bytes */ +#define EEPROM_RADIO_CONFIG (2*0x48) /* 2 bytes */ +#define EEPROM_3945_M_VERSION (2*0x4A) /* 1 bytes */ +#define EEPROM_ANTENNA_SWITCH_TYPE (2*0x4A+1) /* 1 bytes */ + +/* The following masks are to be applied on EEPROM_RADIO_CONFIG */ +#define EEPROM_RF_CFG_TYPE_MSK(x) (x & 0x3) /* bits 0-1 */ +#define EEPROM_RF_CFG_STEP_MSK(x) ((x >> 2) & 0x3) /* bits 2-3 */ +#define EEPROM_RF_CFG_DASH_MSK(x) ((x >> 4) & 0x3) /* bits 4-5 */ +#define EEPROM_RF_CFG_PNUM_MSK(x) ((x >> 6) & 0x3) /* bits 6-7 */ +#define EEPROM_RF_CFG_TX_ANT_MSK(x) ((x >> 8) & 0xF) /* bits 8-11 */ +#define EEPROM_RF_CFG_RX_ANT_MSK(x) ((x >> 12) & 0xF) /* bits 12-15 */ + +#define EEPROM_3945_RF_CFG_TYPE_MAX 0x0 +#define EEPROM_4965_RF_CFG_TYPE_MAX 0x1 +#define EEPROM_5000_RF_CFG_TYPE_MAX 0x3 /* * Per-channel regulatory data. * - * Each channel that *might* be supported by 3945 or 4965 has a fixed location + * Each channel that *might* be supported by iwl has a fixed location * in EEPROM containing EEPROM_CHANNEL_* usage flags (LSB) and max regulatory * txpower (MSB). * @@ -269,40 +310,38 @@ struct iwl4965_eeprom { * * 2.4 GHz channels 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14 */ - u16 band_1_count; /* abs.ofs: 196 */ - struct iwl4965_eeprom_channel band_1_channels[14]; /* abs.ofs: 196 */ +#define EEPROM_REGULATORY_SKU_ID (2*0x60) /* 4 bytes */ +#define EEPROM_REGULATORY_BAND_1 (2*0x62) /* 2 bytes */ +#define EEPROM_REGULATORY_BAND_1_CHANNELS (2*0x63) /* 28 bytes */ /* * 4.9 GHz channels 183, 184, 185, 187, 188, 189, 192, 196, * 5.0 GHz channels 7, 8, 11, 12, 16 * (4915-5080MHz) (none of these is ever supported) */ - u16 band_2_count; /* abs.ofs: 226 */ - struct iwl4965_eeprom_channel band_2_channels[13]; /* abs.ofs: 228 */ +#define EEPROM_REGULATORY_BAND_2 (2*0x71) /* 2 bytes */ +#define EEPROM_REGULATORY_BAND_2_CHANNELS (2*0x72) /* 26 bytes */ /* * 5.2 GHz channels 34, 36, 38, 40, 42, 44, 46, 48, 52, 56, 60, 64 * (5170-5320MHz) */ - u16 band_3_count; /* abs.ofs: 254 */ - struct iwl4965_eeprom_channel band_3_channels[12]; /* abs.ofs: 256 */ +#define EEPROM_REGULATORY_BAND_3 (2*0x7F) /* 2 bytes */ +#define EEPROM_REGULATORY_BAND_3_CHANNELS (2*0x80) /* 24 bytes */ /* * 5.5 GHz channels 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140 * (5500-5700MHz) */ - u16 band_4_count; /* abs.ofs: 280 */ - struct iwl4965_eeprom_channel band_4_channels[11]; /* abs.ofs: 282 */ +#define EEPROM_REGULATORY_BAND_4 (2*0x8C) /* 2 bytes */ +#define EEPROM_REGULATORY_BAND_4_CHANNELS (2*0x8D) /* 22 bytes */ /* * 5.7 GHz channels 145, 149, 153, 157, 161, 165 * (5725-5825MHz) */ - u16 band_5_count; /* abs.ofs: 304 */ - struct iwl4965_eeprom_channel band_5_channels[6]; /* abs.ofs: 306 */ - - u8 reserved10[2]; - +#define EEPROM_REGULATORY_BAND_5 (2*0x98) /* 2 bytes */ +#define EEPROM_REGULATORY_BAND_5_CHANNELS (2*0x99) /* 12 bytes */ /* * 2.4 GHz FAT channels 1 (5), 2 (6), 3 (7), 4 (8), 5 (9), 6 (10), 7 (11) @@ -319,52 +358,35 @@ struct iwl4965_eeprom { * * NOTE: 4965 does not support FAT channels on 2.4 GHz. */ - struct iwl4965_eeprom_channel band_24_channels[7]; /* abs.ofs: 320 */ - u8 reserved11[2]; +#define EEPROM_4965_REGULATORY_BAND_24_FAT_CHANNELS (2*0xA0) /* 14 bytes */ /* * 5.2 GHz FAT channels 36 (40), 44 (48), 52 (56), 60 (64), * 100 (104), 108 (112), 116 (120), 124 (128), 132 (136), 149 (153), 157 (161) */ - struct iwl4965_eeprom_channel band_52_channels[11]; /* abs.ofs: 336 */ - u8 reserved12[6]; - -/* - * 4965 driver requires txpower calibration format version 5 or greater. - * Driver does not work with txpower calibration version < 5. - * This value is simply a 16-bit number, no major/minor versions here. - */ - u16 calib_version; /* abs.ofs: 364 */ - u8 reserved13[2]; - u8 reserved14[96]; /* abs.ofs: 368 */ - -/* - * 4965 Txpower calibration data. - */ - struct iwl4965_eeprom_calib_info calib_info; /* abs.ofs: 464 */ - - u8 reserved16[140]; /* fill out to full 1024 byte block */ - - -} __attribute__ ((packed)); - -#define IWL_EEPROM_IMAGE_SIZE 1024 - -/* End of EEPROM */ +#define EEPROM_4965_REGULATORY_BAND_52_FAT_CHANNELS (2*0xA8) /* 22 bytes */ struct iwl_eeprom_ops { + const u32 regulatory_bands[7]; int (*verify_signature) (struct iwl_priv *priv); int (*acquire_semaphore) (struct iwl_priv *priv); void (*release_semaphore) (struct iwl_priv *priv); + int (*check_version) (struct iwl_priv *priv); + const u8* (*query_addr) (const struct iwl_priv *priv, size_t offset); }; void iwl_eeprom_get_mac(const struct iwl_priv *priv, u8 *mac); int iwl_eeprom_init(struct iwl_priv *priv); +void iwl_eeprom_free(struct iwl_priv *priv); +int iwl_eeprom_check_version(struct iwl_priv *priv); +const u8 *iwl_eeprom_query_addr(const struct iwl_priv *priv, size_t offset); +u16 iwl_eeprom_query16(const struct iwl_priv *priv, size_t offset); int iwlcore_eeprom_verify_signature(struct iwl_priv *priv); int iwlcore_eeprom_acquire_semaphore(struct iwl_priv *priv); void iwlcore_eeprom_release_semaphore(struct iwl_priv *priv); +const u8 *iwlcore_eeprom_query_addr(const struct iwl_priv *priv, size_t offset); int iwl_init_channel_map(struct iwl_priv *priv); void iwl_free_channel_map(struct iwl_priv *priv); diff --git a/drivers/net/wireless/iwlwifi/iwl-fh.h b/drivers/net/wireless/iwlwifi/iwl-fh.h new file mode 100644 index 000000000000..944642450d3d --- /dev/null +++ b/drivers/net/wireless/iwlwifi/iwl-fh.h @@ -0,0 +1,391 @@ +/****************************************************************************** + * + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * Copyright(c) 2005 - 2008 Intel Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, + * USA + * + * The full GNU General Public License is included in this distribution + * in the file called LICENSE.GPL. + * + * Contact Information: + * James P. Ketrenos <ipw2100-admin@linux.intel.com> + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + * + * BSD LICENSE + * + * Copyright(c) 2005 - 2008 Intel Corporation. All rights reserved. + * 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 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. + * + *****************************************************************************/ + +/****************************/ +/* Flow Handler Definitions */ +/****************************/ + +/** + * This I/O area is directly read/writable by driver (e.g. Linux uses writel()) + * Addresses are offsets from device's PCI hardware base address. + */ +#define FH_MEM_LOWER_BOUND (0x1000) +#define FH_MEM_UPPER_BOUND (0x1EF0) + +/** + * Keep-Warm (KW) buffer base address. + * + * Driver must allocate a 4KByte buffer that is used by 4965 for keeping the + * host DRAM powered on (via dummy accesses to DRAM) to maintain low-latency + * DRAM access when 4965 is Txing or Rxing. The dummy accesses prevent host + * from going into a power-savings mode that would cause higher DRAM latency, + * and possible data over/under-runs, before all Tx/Rx is complete. + * + * Driver loads FH_KW_MEM_ADDR_REG with the physical address (bits 35:4) + * of the buffer, which must be 4K aligned. Once this is set up, the 4965 + * automatically invokes keep-warm accesses when normal accesses might not + * be sufficient to maintain fast DRAM response. + * + * Bit fields: + * 31-0: Keep-warm buffer physical base address [35:4], must be 4K aligned + */ +#define FH_KW_MEM_ADDR_REG (FH_MEM_LOWER_BOUND + 0x97C) + + +/** + * TFD Circular Buffers Base (CBBC) addresses + * + * 4965 has 16 base pointer registers, one for each of 16 host-DRAM-resident + * circular buffers (CBs/queues) containing Transmit Frame Descriptors (TFDs) + * (see struct iwl_tfd_frame). These 16 pointer registers are offset by 0x04 + * bytes from one another. Each TFD circular buffer in DRAM must be 256-byte + * aligned (address bits 0-7 must be 0). + * + * Bit fields in each pointer register: + * 27-0: TFD CB physical base address [35:8], must be 256-byte aligned + */ +#define FH_MEM_CBBC_LOWER_BOUND (FH_MEM_LOWER_BOUND + 0x9D0) +#define FH_MEM_CBBC_UPPER_BOUND (FH_MEM_LOWER_BOUND + 0xA10) + +/* Find TFD CB base pointer for given queue (range 0-15). */ +#define FH_MEM_CBBC_QUEUE(x) (FH_MEM_CBBC_LOWER_BOUND + (x) * 0x4) + + +/** + * Rx SRAM Control and Status Registers (RSCSR) + * + * These registers provide handshake between driver and 4965 for the Rx queue + * (this queue handles *all* command responses, notifications, Rx data, etc. + * sent from 4965 uCode to host driver). Unlike Tx, there is only one Rx + * queue, and only one Rx DMA/FIFO channel. Also unlike Tx, which can + * concatenate up to 20 DRAM buffers to form a Tx frame, each Receive Buffer + * Descriptor (RBD) points to only one Rx Buffer (RB); there is a 1:1 + * mapping between RBDs and RBs. + * + * Driver must allocate host DRAM memory for the following, and set the + * physical address of each into 4965 registers: + * + * 1) Receive Buffer Descriptor (RBD) circular buffer (CB), typically with 256 + * entries (although any power of 2, up to 4096, is selectable by driver). + * Each entry (1 dword) points to a receive buffer (RB) of consistent size + * (typically 4K, although 8K or 16K are also selectable by driver). + * Driver sets up RB size and number of RBDs in the CB via Rx config + * register FH_MEM_RCSR_CHNL0_CONFIG_REG. + * + * Bit fields within one RBD: + * 27-0: Receive Buffer physical address bits [35:8], 256-byte aligned + * + * Driver sets physical address [35:8] of base of RBD circular buffer + * into FH_RSCSR_CHNL0_RBDCB_BASE_REG [27:0]. + * + * 2) Rx status buffer, 8 bytes, in which 4965 indicates which Rx Buffers + * (RBs) have been filled, via a "write pointer", actually the index of + * the RB's corresponding RBD within the circular buffer. Driver sets + * physical address [35:4] into FH_RSCSR_CHNL0_STTS_WPTR_REG [31:0]. + * + * Bit fields in lower dword of Rx status buffer (upper dword not used + * by driver; see struct iwl4965_shared, val0): + * 31-12: Not used by driver + * 11- 0: Index of last filled Rx buffer descriptor + * (4965 writes, driver reads this value) + * + * As the driver prepares Receive Buffers (RBs) for 4965 to fill, driver must + * enter pointers to these RBs into contiguous RBD circular buffer entries, + * and update the 4965's "write" index register, + * FH_RSCSR_CHNL0_RBDCB_WPTR_REG. + * + * This "write" index corresponds to the *next* RBD that the driver will make + * available, i.e. one RBD past the tail of the ready-to-fill RBDs within + * the circular buffer. This value should initially be 0 (before preparing any + * RBs), should be 8 after preparing the first 8 RBs (for example), and must + * wrap back to 0 at the end of the circular buffer (but don't wrap before + * "read" index has advanced past 1! See below). + * NOTE: 4965 EXPECTS THE WRITE INDEX TO BE INCREMENTED IN MULTIPLES OF 8. + * + * As the 4965 fills RBs (referenced from contiguous RBDs within the circular + * buffer), it updates the Rx status buffer in host DRAM, 2) described above, + * to tell the driver the index of the latest filled RBD. The driver must + * read this "read" index from DRAM after receiving an Rx interrupt from 4965. + * + * The driver must also internally keep track of a third index, which is the + * next RBD to process. When receiving an Rx interrupt, driver should process + * all filled but unprocessed RBs up to, but not including, the RB + * corresponding to the "read" index. For example, if "read" index becomes "1", + * driver may process the RB pointed to by RBD 0. Depending on volume of + * traffic, there may be many RBs to process. + * + * If read index == write index, 4965 thinks there is no room to put new data. + * Due to this, the maximum number of filled RBs is 255, instead of 256. To + * be safe, make sure that there is a gap of at least 2 RBDs between "write" + * and "read" indexes; that is, make sure that there are no more than 254 + * buffers waiting to be filled. + */ +#define FH_MEM_RSCSR_LOWER_BOUND (FH_MEM_LOWER_BOUND + 0xBC0) +#define FH_MEM_RSCSR_UPPER_BOUND (FH_MEM_LOWER_BOUND + 0xC00) +#define FH_MEM_RSCSR_CHNL0 (FH_MEM_RSCSR_LOWER_BOUND) + +/** + * Physical base address of 8-byte Rx Status buffer. + * Bit fields: + * 31-0: Rx status buffer physical base address [35:4], must 16-byte aligned. + */ +#define FH_RSCSR_CHNL0_STTS_WPTR_REG (FH_MEM_RSCSR_CHNL0) + +/** + * Physical base address of Rx Buffer Descriptor Circular Buffer. + * Bit fields: + * 27-0: RBD CD physical base address [35:8], must be 256-byte aligned. + */ +#define FH_RSCSR_CHNL0_RBDCB_BASE_REG (FH_MEM_RSCSR_CHNL0 + 0x004) + +/** + * Rx write pointer (index, really!). + * Bit fields: + * 11-0: Index of driver's most recent prepared-to-be-filled RBD, + 1. + * NOTE: For 256-entry circular buffer, use only bits [7:0]. + */ +#define FH_RSCSR_CHNL0_RBDCB_WPTR_REG (FH_MEM_RSCSR_CHNL0 + 0x008) +#define FH_RSCSR_CHNL0_WPTR (FH_RSCSR_CHNL0_RBDCB_WPTR_REG) + + +/** + * Rx Config/Status Registers (RCSR) + * Rx Config Reg for channel 0 (only channel used) + * + * Driver must initialize FH_MEM_RCSR_CHNL0_CONFIG_REG as follows for + * normal operation (see bit fields). + * + * Clearing FH_MEM_RCSR_CHNL0_CONFIG_REG to 0 turns off Rx DMA. + * Driver should poll FH_MEM_RSSR_RX_STATUS_REG for + * FH_RSSR_CHNL0_RX_STATUS_CHNL_IDLE (bit 24) before continuing. + * + * Bit fields: + * 31-30: Rx DMA channel enable: '00' off/pause, '01' pause at end of frame, + * '10' operate normally + * 29-24: reserved + * 23-20: # RBDs in circular buffer = 2^value; use "8" for 256 RBDs (normal), + * min "5" for 32 RBDs, max "12" for 4096 RBDs. + * 19-18: reserved + * 17-16: size of each receive buffer; '00' 4K (normal), '01' 8K, + * '10' 12K, '11' 16K. + * 15-14: reserved + * 13-12: IRQ destination; '00' none, '01' host driver (normal operation) + * 11- 4: timeout for closing Rx buffer and interrupting host (units 32 usec) + * typical value 0x10 (about 1/2 msec) + * 3- 0: reserved + */ +#define FH_MEM_RCSR_LOWER_BOUND (FH_MEM_LOWER_BOUND + 0xC00) +#define FH_MEM_RCSR_UPPER_BOUND (FH_MEM_LOWER_BOUND + 0xCC0) +#define FH_MEM_RCSR_CHNL0 (FH_MEM_RCSR_LOWER_BOUND) + +#define FH_MEM_RCSR_CHNL0_CONFIG_REG (FH_MEM_RCSR_CHNL0) + +#define FH_RCSR_CHNL0_RX_CONFIG_RB_TIMEOUT_MSK (0x00000FF0) /* bits 4-11 */ +#define FH_RCSR_CHNL0_RX_CONFIG_IRQ_DEST_MSK (0x00001000) /* bits 12 */ +#define FH_RCSR_CHNL0_RX_CONFIG_SINGLE_FRAME_MSK (0x00008000) /* bit 15 */ +#define FH_RCSR_CHNL0_RX_CONFIG_RB_SIZE_MSK (0x00030000) /* bits 16-17 */ +#define FH_RCSR_CHNL0_RX_CONFIG_RBDBC_SIZE_MSK (0x00F00000) /* bits 20-23 */ +#define FH_RCSR_CHNL0_RX_CONFIG_DMA_CHNL_EN_MSK (0xC0000000) /* bits 30-31*/ + +#define FH_RCSR_RX_CONFIG_RBDCB_SIZE_BITSHIFT (20) +#define FH_RCSR_RX_CONFIG_REG_IRQ_RBTH_BITSHIFT (4) +#define RX_RB_TIMEOUT (0x10) + +#define FH_RCSR_RX_CONFIG_CHNL_EN_PAUSE_VAL (0x00000000) +#define FH_RCSR_RX_CONFIG_CHNL_EN_PAUSE_EOF_VAL (0x40000000) +#define FH_RCSR_RX_CONFIG_CHNL_EN_ENABLE_VAL (0x80000000) + +#define FH_RCSR_RX_CONFIG_REG_VAL_RB_SIZE_4K (0x00000000) +#define FH_RCSR_RX_CONFIG_REG_VAL_RB_SIZE_8K (0x00010000) +#define FH_RCSR_RX_CONFIG_REG_VAL_RB_SIZE_12K (0x00020000) +#define FH_RCSR_RX_CONFIG_REG_VAL_RB_SIZE_16K (0x00030000) + +#define FH_RCSR_CHNL0_RX_CONFIG_IRQ_DEST_NO_INT_VAL (0x00000000) +#define FH_RCSR_CHNL0_RX_CONFIG_IRQ_DEST_INT_HOST_VAL (0x00001000) + + +/** + * Rx Shared Status Registers (RSSR) + * + * After stopping Rx DMA channel (writing 0 to + * FH_MEM_RCSR_CHNL0_CONFIG_REG), driver must poll + * FH_MEM_RSSR_RX_STATUS_REG until Rx channel is idle. + * + * Bit fields: + * 24: 1 = Channel 0 is idle + * + * FH_MEM_RSSR_SHARED_CTRL_REG and FH_MEM_RSSR_RX_ENABLE_ERR_IRQ2DRV + * contain default values that should not be altered by the driver. + */ +#define FH_MEM_RSSR_LOWER_BOUND (FH_MEM_LOWER_BOUND + 0xC40) +#define FH_MEM_RSSR_UPPER_BOUND (FH_MEM_LOWER_BOUND + 0xD00) + +#define FH_MEM_RSSR_SHARED_CTRL_REG (FH_MEM_RSSR_LOWER_BOUND) +#define FH_MEM_RSSR_RX_STATUS_REG (FH_MEM_RSSR_LOWER_BOUND + 0x004) +#define FH_MEM_RSSR_RX_ENABLE_ERR_IRQ2DRV\ + (FH_MEM_RSSR_LOWER_BOUND + 0x008) + +#define FH_RSSR_CHNL0_RX_STATUS_CHNL_IDLE (0x01000000) + + +/** + * Transmit DMA Channel Control/Status Registers (TCSR) + * + * 4965 has one configuration register for each of 8 Tx DMA/FIFO channels + * supported in hardware (don't confuse these with the 16 Tx queues in DRAM, + * which feed the DMA/FIFO channels); config regs are separated by 0x20 bytes. + * + * To use a Tx DMA channel, driver must initialize its + * FH_TCSR_CHNL_TX_CONFIG_REG(chnl) with: + * + * FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE | + * FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_ENABLE_VAL + * + * All other bits should be 0. + * + * Bit fields: + * 31-30: Tx DMA channel enable: '00' off/pause, '01' pause at end of frame, + * '10' operate normally + * 29- 4: Reserved, set to "0" + * 3: Enable internal DMA requests (1, normal operation), disable (0) + * 2- 0: Reserved, set to "0" + */ +#define FH_TCSR_LOWER_BOUND (FH_MEM_LOWER_BOUND + 0xD00) +#define FH_TCSR_UPPER_BOUND (FH_MEM_LOWER_BOUND + 0xE60) + +/* Find Control/Status reg for given Tx DMA/FIFO channel */ +#define FH_TCSR_CHNL_TX_CONFIG_REG(_chnl) \ + (FH_TCSR_LOWER_BOUND + 0x20 * _chnl) + +#define FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_DISABLE_VAL (0x00000000) +#define FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_ENABLE_VAL (0x00000008) + +#define FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_PAUSE (0x00000000) +#define FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_PAUSE_EOF (0x40000000) +#define FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE (0x80000000) + +#define FH_TCSR_CHNL_NUM (7) + +#define FH_TCSR_CHNL_TX_BUF_STS_REG_VAL_TFDB_EMPTY (0x00000000) +#define FH_TCSR_CHNL_TX_BUF_STS_REG_VAL_TFDB_WAIT (0x00002000) +#define FH_TCSR_CHNL_TX_BUF_STS_REG_VAL_TFDB_VALID (0x00000003) + +#define FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_HOST_NOINT (0x00000000) +#define FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_HOST_ENDTFD (0x00100000) +#define FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_HOST_IFTFD (0x00200000) + +#define FH_TCSR_CHNL_TX_BUF_STS_REG_POS_TB_NUM (20) +#define FH_TCSR_CHNL_TX_BUF_STS_REG_POS_TB_IDX (12) +#define FH_TCSR_CHNL_TX_CONFIG_REG(_chnl) \ + (FH_TCSR_LOWER_BOUND + 0x20 * _chnl) +#define FH_TCSR_CHNL_TX_CREDIT_REG(_chnl) \ + (FH_TCSR_LOWER_BOUND + 0x20 * _chnl + 0x4) +#define FH_TCSR_CHNL_TX_BUF_STS_REG(_chnl) \ + (FH_TCSR_LOWER_BOUND + 0x20 * _chnl + 0x8) + +/** + * Tx Shared Status Registers (TSSR) + * + * After stopping Tx DMA channel (writing 0 to + * FH_TCSR_CHNL_TX_CONFIG_REG(chnl)), driver must poll + * FH_TSSR_TX_STATUS_REG until selected Tx channel is idle + * (channel's buffers empty | no pending requests). + * + * Bit fields: + * 31-24: 1 = Channel buffers empty (channel 7:0) + * 23-16: 1 = No pending requests (channel 7:0) + */ +#define FH_TSSR_LOWER_BOUND (FH_MEM_LOWER_BOUND + 0xEA0) +#define FH_TSSR_UPPER_BOUND (FH_MEM_LOWER_BOUND + 0xEC0) + +#define FH_TSSR_TX_STATUS_REG (FH_TSSR_LOWER_BOUND + 0x010) + +#define FH_TSSR_TX_STATUS_REG_BIT_BUFS_EMPTY(_chnl) ((1 << (_chnl)) << 24) +#define FH_TSSR_TX_STATUS_REG_BIT_NO_PEND_REQ(_chnl) ((1 << (_chnl)) << 16) + +#define FH_TSSR_TX_STATUS_REG_MSK_CHNL_IDLE(_chnl) \ + (FH_TSSR_TX_STATUS_REG_BIT_BUFS_EMPTY(_chnl) | \ + FH_TSSR_TX_STATUS_REG_BIT_NO_PEND_REQ(_chnl)) + + + +#define FH_REGS_LOWER_BOUND (0x1000) +#define FH_REGS_UPPER_BOUND (0x2000) + +/* Tx service channels */ +#define FH_SRVC_CHNL (9) +#define FH_SRVC_LOWER_BOUND (FH_REGS_LOWER_BOUND + 0x9C8) +#define FH_SRVC_UPPER_BOUND (FH_REGS_LOWER_BOUND + 0x9D0) +#define FH_SRVC_CHNL_SRAM_ADDR_REG(_chnl) \ + (FH_SRVC_LOWER_BOUND + ((_chnl) - 9) * 0x4) + +/* TFDB Area - TFDs buffer table */ +#define FH_MEM_TFDIB_DRAM_ADDR_LSB_MSK (0xFFFFFFFF) +#define FH_TFDIB_LOWER_BOUND (FH_REGS_LOWER_BOUND + 0x900) +#define FH_TFDIB_UPPER_BOUND (FH_REGS_LOWER_BOUND + 0x958) +#define FH_TFDIB_CTRL0_REG(_chnl) (FH_TFDIB_LOWER_BOUND + 0x8 * (_chnl)) +#define FH_TFDIB_CTRL1_REG(_chnl) (FH_TFDIB_LOWER_BOUND + 0x8 * (_chnl) + 0x4) + +/* TCSR: tx_config register values */ +#define FH_RSCSR_FRAME_SIZE_MSK (0x00003FFF) /* bits 0-13 */ + diff --git a/drivers/net/wireless/iwlwifi/iwl-hcmd.c b/drivers/net/wireless/iwlwifi/iwl-hcmd.c index fdb27f1cdc08..8fa991b7202a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-hcmd.c +++ b/drivers/net/wireless/iwlwifi/iwl-hcmd.c @@ -31,7 +31,7 @@ #include <linux/version.h> #include <net/mac80211.h> -#include "iwl-4965.h" /* FIXME: remove */ +#include "iwl-dev.h" /* FIXME: remove */ #include "iwl-debug.h" #include "iwl-eeprom.h" #include "iwl-core.h" @@ -56,6 +56,7 @@ const char *get_cmd_string(u8 cmd) IWL_CMD(REPLY_RATE_SCALE); IWL_CMD(REPLY_LEDS_CMD); IWL_CMD(REPLY_TX_LINK_QUALITY_CMD); + IWL_CMD(COEX_PRIORITY_TABLE_CMD); IWL_CMD(RADAR_NOTIFICATION); IWL_CMD(REPLY_QUIET_CMD); IWL_CMD(REPLY_CHANNEL_SWITCH); @@ -89,6 +90,10 @@ const char *get_cmd_string(u8 cmd) IWL_CMD(REPLY_RX_MPDU_CMD); IWL_CMD(REPLY_RX); IWL_CMD(REPLY_COMPRESSED_BA); + IWL_CMD(CALIBRATION_CFG_CMD); + IWL_CMD(CALIBRATION_RES_NOTIFICATION); + IWL_CMD(CALIBRATION_COMPLETE_NOTIFICATION); + IWL_CMD(REPLY_TX_POWER_DBM_CMD); default: return "UNKNOWN"; @@ -101,7 +106,7 @@ EXPORT_SYMBOL(get_cmd_string); static int iwl_generic_cmd_callback(struct iwl_priv *priv, struct iwl_cmd *cmd, struct sk_buff *skb) { - struct iwl4965_rx_packet *pkt = NULL; + struct iwl_rx_packet *pkt = NULL; if (!skb) { IWL_ERROR("Error: Response NULL in %s.\n", @@ -109,7 +114,7 @@ static int iwl_generic_cmd_callback(struct iwl_priv *priv, return 1; } - pkt = (struct iwl4965_rx_packet *)skb->data; + pkt = (struct iwl_rx_packet *)skb->data; if (pkt->hdr.flags & IWL_CMD_FAILED_MSK) { IWL_ERROR("Bad return from %s (0x%08X)\n", get_cmd_string(cmd->hdr.cmd), pkt->hdr.flags); @@ -139,7 +144,7 @@ static int iwl_send_cmd_async(struct iwl_priv *priv, struct iwl_host_cmd *cmd) if (test_bit(STATUS_EXIT_PENDING, &priv->status)) return -EBUSY; - ret = priv->cfg->ops->utils->enqueue_hcmd(priv, cmd); + ret = iwl_enqueue_hcmd(priv, cmd); if (ret < 0) { IWL_ERROR("Error sending %s: enqueue_hcmd failed: %d\n", get_cmd_string(cmd->id), ret); @@ -170,7 +175,7 @@ int iwl_send_cmd_sync(struct iwl_priv *priv, struct iwl_host_cmd *cmd) if (cmd->meta.flags & CMD_WANT_SKB) cmd->meta.source = &cmd->meta; - cmd_idx = priv->cfg->ops->utils->enqueue_hcmd(priv, cmd); + cmd_idx = iwl_enqueue_hcmd(priv, cmd); if (cmd_idx < 0) { ret = cmd_idx; IWL_ERROR("Error sending %s: enqueue_hcmd failed: %d\n", diff --git a/drivers/net/wireless/iwlwifi/iwl-helpers.h b/drivers/net/wireless/iwlwifi/iwl-helpers.h index a443472bea62..41eed6793328 100644 --- a/drivers/net/wireless/iwlwifi/iwl-helpers.h +++ b/drivers/net/wireless/iwlwifi/iwl-helpers.h @@ -136,8 +136,8 @@ static inline void iwl_set_bits16(__le16 *dst, u8 pos, u8 len, int val) #define KELVIN_TO_CELSIUS(x) ((x)-273) #define CELSIUS_TO_KELVIN(x) ((x)+273) +#define IWL_MASK(lo, hi) ((1 << (hi)) | ((1 << (hi)) - (1 << (lo)))) -#define IEEE80211_CHAN_W_RADAR_DETECT 0x00000010 static inline struct ieee80211_conf *ieee80211_get_hw_conf( struct ieee80211_hw *hw) @@ -145,96 +145,6 @@ static inline struct ieee80211_conf *ieee80211_get_hw_conf( return &hw->conf; } -#define QOS_CONTROL_LEN 2 - - -static inline int ieee80211_is_management(u16 fc) -{ - return (fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT; -} - -static inline int ieee80211_is_control(u16 fc) -{ - return (fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_CTL; -} - -static inline int ieee80211_is_data(u16 fc) -{ - return (fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA; -} - -static inline int ieee80211_is_back_request(u16 fc) -{ - return ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_CTL) && - ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_BACK_REQ); -} - -static inline int ieee80211_is_probe_response(u16 fc) -{ - return ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT) && - ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_PROBE_RESP); -} - -static inline int ieee80211_is_probe_request(u16 fc) -{ - return ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT) && - ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_PROBE_REQ); -} - -static inline int ieee80211_is_beacon(u16 fc) -{ - return ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT) && - ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_BEACON); -} - -static inline int ieee80211_is_atim(u16 fc) -{ - return ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT) && - ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_ATIM); -} - -static inline int ieee80211_is_assoc_request(u16 fc) -{ - return ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT) && - ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_ASSOC_REQ); -} - -static inline int ieee80211_is_assoc_response(u16 fc) -{ - return ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT) && - ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_ASSOC_RESP); -} - -static inline int ieee80211_is_auth(u16 fc) -{ - return ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT) && - ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_ASSOC_REQ); -} - -static inline int ieee80211_is_deauth(u16 fc) -{ - return ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT) && - ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_ASSOC_REQ); -} - -static inline int ieee80211_is_disassoc(u16 fc) -{ - return ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT) && - ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_ASSOC_REQ); -} - -static inline int ieee80211_is_reassoc_request(u16 fc) -{ - return ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT) && - ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_REASSOC_REQ); -} - -static inline int ieee80211_is_reassoc_response(u16 fc) -{ - return ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT) && - ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_REASSOC_RESP); -} - static inline int iwl_check_bits(unsigned long field, unsigned long mask) { return ((field & mask) == mask) ? 1 : 0; diff --git a/drivers/net/wireless/iwlwifi/iwl-led.c b/drivers/net/wireless/iwlwifi/iwl-led.c index 03fdf5b434a1..899d7a2567a8 100644 --- a/drivers/net/wireless/iwlwifi/iwl-led.c +++ b/drivers/net/wireless/iwlwifi/iwl-led.c @@ -39,19 +39,26 @@ #include <linux/etherdevice.h> #include <asm/unaligned.h> -#include "iwl-4965.h" +#include "iwl-dev.h" #include "iwl-core.h" #include "iwl-io.h" #include "iwl-helpers.h" -#define IWL_1MB_RATE (128 * 1024) -#define IWL_LED_THRESHOLD (16) -#define IWL_MAX_BLINK_TBL (10) +#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 tpt; u8 on_time; - u8 of_time; + u8 off_time; } blink_tbl[] = { {300, 25, 25}, @@ -63,26 +70,31 @@ static const struct { {15, 95, 95 }, {10, 110, 110}, {5, 130, 130}, - {0, 167, 167} + {0, 167, 167}, +/* SOLID_ON */ + {-1, IWL_LED_SOLID, 0} }; -static int iwl_led_cmd_callback(struct iwl_priv *priv, - struct iwl_cmd *cmd, struct sk_buff *skb) +#define IWL_1MB_RATE (128 * 1024) +#define IWL_LED_THRESHOLD (16) +#define IWL_MAX_BLINK_TBL (ARRAY_SIZE(blink_tbl) - 1) /* exclude SOLID_ON */ +#define IWL_SOLID_BLINK_IDX (ARRAY_SIZE(blink_tbl) - 1) + +/* [0-256] -> [0..8] FIXME: we need [0..10] */ +static inline int iwl_brightness_to_idx(enum led_brightness brightness) { - return 1; + return fls(0x000000FF & (u32)brightness); } - /* Send led command */ -static int iwl_send_led_cmd(struct iwl_priv *priv, - struct iwl4965_led_cmd *led_cmd) +static int iwl_send_led_cmd(struct iwl_priv *priv, struct iwl_led_cmd *led_cmd) { struct iwl_host_cmd cmd = { .id = REPLY_LEDS_CMD, - .len = sizeof(struct iwl4965_led_cmd), + .len = sizeof(struct iwl_led_cmd), .data = led_cmd, .meta.flags = CMD_ASYNC, - .meta.u.callback = iwl_led_cmd_callback + .meta.u.callback = NULL, }; u32 reg; @@ -93,33 +105,20 @@ static int iwl_send_led_cmd(struct iwl_priv *priv, return iwl_send_cmd(priv, &cmd); } - -/* Set led on command */ -static int iwl4965_led_on(struct iwl_priv *priv, int led_id) -{ - struct iwl4965_led_cmd led_cmd = { - .id = led_id, - .on = IWL_LED_SOLID, - .off = 0, - .interval = IWL_DEF_LED_INTRVL - }; - return iwl_send_led_cmd(priv, &led_cmd); -} - -/* Set led on command */ +/* Set led pattern command */ static int iwl4965_led_pattern(struct iwl_priv *priv, int led_id, - enum led_brightness brightness) + unsigned int idx) { - struct iwl4965_led_cmd led_cmd = { + struct iwl_led_cmd led_cmd = { .id = led_id, - .on = brightness, - .off = brightness, .interval = IWL_DEF_LED_INTRVL }; - if (brightness == LED_FULL) { - led_cmd.on = IWL_LED_SOLID; - led_cmd.off = 0; - } + + BUG_ON(idx > IWL_MAX_BLINK_TBL); + + led_cmd.on = blink_tbl[idx].on_time; + led_cmd.off = blink_tbl[idx].off_time; + return iwl_send_led_cmd(priv, &led_cmd); } @@ -132,10 +131,22 @@ static int iwl4965_led_on_reg(struct iwl_priv *priv, int led_id) } #if 0 +/* Set led on command */ +static int iwl4965_led_on(struct iwl_priv *priv, int led_id) +{ + struct iwl_led_cmd led_cmd = { + .id = led_id, + .on = IWL_LED_SOLID, + .off = 0, + .interval = IWL_DEF_LED_INTRVL + }; + return iwl_send_led_cmd(priv, &led_cmd); +} + /* Set led off command */ int iwl4965_led_off(struct iwl_priv *priv, int led_id) { - struct iwl4965_led_cmd led_cmd = { + struct iwl_led_cmd led_cmd = { .id = led_id, .on = 0, .off = 0, @@ -155,25 +166,10 @@ static int iwl4965_led_off_reg(struct iwl_priv *priv, int led_id) return 0; } -/* Set led blink command */ -static int iwl4965_led_not_solid(struct iwl_priv *priv, int led_id, - u8 brightness) -{ - struct iwl4965_led_cmd led_cmd = { - .id = led_id, - .on = brightness, - .off = brightness, - .interval = IWL_DEF_LED_INTRVL - }; - - return iwl_send_led_cmd(priv, &led_cmd); -} - - /* * brightness call back function for Tx/Rx LED */ -static int iwl4965_led_associated(struct iwl_priv *priv, int led_id) +static int iwl_led_associated(struct iwl_priv *priv, int led_id) { if (test_bit(STATUS_EXIT_PENDING, &priv->status) || !test_bit(STATUS_READY, &priv->status)) @@ -189,16 +185,18 @@ static int iwl4965_led_associated(struct iwl_priv *priv, int led_id) /* * brightness call back for association and radio */ -static void iwl4965_led_brightness_set(struct led_classdev *led_cdev, +static void iwl_led_brightness_set(struct led_classdev *led_cdev, enum led_brightness brightness) { - struct iwl4965_led *led = container_of(led_cdev, - struct iwl4965_led, led_dev); + struct iwl_led *led = container_of(led_cdev, struct iwl_led, led_dev); struct iwl_priv *priv = led->priv; if (test_bit(STATUS_EXIT_PENDING, &priv->status)) return; + + IWL_DEBUG_LED("Led type = %s brightness = %d\n", + led_type_str[led->type], brightness); switch (brightness) { case LED_FULL: if (led->type == IWL_LED_TRG_ASSOC) @@ -215,8 +213,10 @@ static void iwl4965_led_brightness_set(struct led_classdev *led_cdev, led->led_off(priv, IWL_LED_LINK); break; default: - if (led->led_pattern) - led->led_pattern(priv, IWL_LED_LINK, brightness); + if (led->led_pattern) { + int idx = iwl_brightness_to_idx(brightness); + led->led_pattern(priv, IWL_LED_LINK, idx); + } break; } } @@ -226,8 +226,7 @@ static void iwl4965_led_brightness_set(struct led_classdev *led_cdev, /* * Register led class with the system */ -static int iwl_leds_register_led(struct iwl_priv *priv, - struct iwl4965_led *led, +static int iwl_leds_register_led(struct iwl_priv *priv, struct iwl_led *led, enum led_type type, u8 set_led, const char *name, char *trigger) { @@ -235,7 +234,7 @@ static int iwl_leds_register_led(struct iwl_priv *priv, int ret; led->led_dev.name = name; - led->led_dev.brightness_set = iwl4965_led_brightness_set; + led->led_dev.brightness_set = iwl_led_brightness_set; led->led_dev.default_trigger = trigger; led->priv = priv; @@ -259,32 +258,28 @@ static int iwl_leds_register_led(struct iwl_priv *priv, /* * calculate blink rate according to last 2 sec Tx/Rx activities */ -static inline u8 get_blink_rate(struct iwl_priv *priv) +static int iwl_get_blink_rate(struct iwl_priv *priv) { int i; - u8 blink_rate; - u64 current_tpt = priv->tx_stats[2].bytes + priv->rx_stats[2].bytes; + u64 current_tpt = priv->tx_stats[2].bytes; + /* FIXME: + priv->rx_stats[2].bytes; */ s64 tpt = current_tpt - priv->led_tpt; if (tpt < 0) /* wrapparound */ tpt = -tpt; + IWL_DEBUG_LED("tpt %lld current_tpt %lld\n", tpt, current_tpt); priv->led_tpt = current_tpt; - if (tpt < IWL_LED_THRESHOLD) { + if (!priv->allow_blinking) i = IWL_MAX_BLINK_TBL; - } else { + else for (i = 0; i < IWL_MAX_BLINK_TBL; i++) if (tpt > (blink_tbl[i].tpt * IWL_1MB_RATE)) break; - } - /* if 0 frame is transfered */ - if ((i == IWL_MAX_BLINK_TBL) || !priv->allow_blinking) - blink_rate = IWL_LED_SOLID; - else - blink_rate = blink_tbl[i].on_time; - return blink_rate; + IWL_DEBUG_LED("LED BLINK IDX=%d", i); + return i; } static inline int is_rf_kill(struct iwl_priv *priv) @@ -300,7 +295,7 @@ static inline int is_rf_kill(struct iwl_priv *priv) */ void iwl_leds_background(struct iwl_priv *priv) { - u8 blink_rate; + u8 blink_idx; if (test_bit(STATUS_EXIT_PENDING, &priv->status)) { priv->last_blink_time = 0; @@ -313,9 +308,10 @@ void iwl_leds_background(struct iwl_priv *priv) if (!priv->allow_blinking) { priv->last_blink_time = 0; - if (priv->last_blink_rate != IWL_LED_SOLID) { - priv->last_blink_rate = IWL_LED_SOLID; - iwl4965_led_on(priv, IWL_LED_LINK); + if (priv->last_blink_rate != IWL_SOLID_BLINK_IDX) { + priv->last_blink_rate = IWL_SOLID_BLINK_IDX; + iwl4965_led_pattern(priv, IWL_LED_LINK, + IWL_SOLID_BLINK_IDX); } return; } @@ -324,21 +320,14 @@ void iwl_leds_background(struct iwl_priv *priv) msecs_to_jiffies(1000))) return; - blink_rate = get_blink_rate(priv); + blink_idx = iwl_get_blink_rate(priv); /* call only if blink rate change */ - if (blink_rate != priv->last_blink_rate) { - if (blink_rate != IWL_LED_SOLID) { - priv->last_blink_time = jiffies + - msecs_to_jiffies(1000); - iwl4965_led_not_solid(priv, IWL_LED_LINK, blink_rate); - } else { - priv->last_blink_time = 0; - iwl4965_led_on(priv, IWL_LED_LINK); - } - } + if (blink_idx != priv->last_blink_rate) + iwl4965_led_pattern(priv, IWL_LED_LINK, blink_idx); - priv->last_blink_rate = blink_rate; + priv->last_blink_time = jiffies; + priv->last_blink_rate = blink_idx; } EXPORT_SYMBOL(iwl_leds_background); @@ -362,10 +351,8 @@ int iwl_leds_register(struct iwl_priv *priv) priv->led[IWL_LED_TRG_RADIO].led_off = iwl4965_led_off_reg; priv->led[IWL_LED_TRG_RADIO].led_pattern = NULL; - ret = iwl_leds_register_led(priv, - &priv->led[IWL_LED_TRG_RADIO], - IWL_LED_TRG_RADIO, 1, - name, trigger); + ret = iwl_leds_register_led(priv, &priv->led[IWL_LED_TRG_RADIO], + IWL_LED_TRG_RADIO, 1, name, trigger); if (ret) goto exit_fail; @@ -373,10 +360,9 @@ int iwl_leds_register(struct iwl_priv *priv) snprintf(name, sizeof(name), "iwl-%s:assoc", wiphy_name(priv->hw->wiphy)); - ret = iwl_leds_register_led(priv, - &priv->led[IWL_LED_TRG_ASSOC], - IWL_LED_TRG_ASSOC, 0, - name, trigger); + ret = iwl_leds_register_led(priv, &priv->led[IWL_LED_TRG_ASSOC], + IWL_LED_TRG_ASSOC, 0, name, trigger); + /* for assoc always turn led on */ priv->led[IWL_LED_TRG_ASSOC].led_on = iwl4965_led_on_reg; priv->led[IWL_LED_TRG_ASSOC].led_off = iwl4965_led_on_reg; @@ -386,31 +372,26 @@ int iwl_leds_register(struct iwl_priv *priv) goto exit_fail; trigger = ieee80211_get_rx_led_name(priv->hw); - snprintf(name, sizeof(name), "iwl-%s:RX", - wiphy_name(priv->hw->wiphy)); + snprintf(name, sizeof(name), "iwl-%s:RX", wiphy_name(priv->hw->wiphy)); - ret = iwl_leds_register_led(priv, - &priv->led[IWL_LED_TRG_RX], - IWL_LED_TRG_RX, 0, - name, trigger); + ret = iwl_leds_register_led(priv, &priv->led[IWL_LED_TRG_RX], + IWL_LED_TRG_RX, 0, name, trigger); - priv->led[IWL_LED_TRG_RX].led_on = iwl4965_led_associated; - priv->led[IWL_LED_TRG_RX].led_off = iwl4965_led_associated; + priv->led[IWL_LED_TRG_RX].led_on = iwl_led_associated; + priv->led[IWL_LED_TRG_RX].led_off = iwl_led_associated; priv->led[IWL_LED_TRG_RX].led_pattern = iwl4965_led_pattern; if (ret) goto exit_fail; trigger = ieee80211_get_tx_led_name(priv->hw); - snprintf(name, sizeof(name), "iwl-%s:TX", - wiphy_name(priv->hw->wiphy)); - ret = iwl_leds_register_led(priv, - &priv->led[IWL_LED_TRG_TX], - IWL_LED_TRG_TX, 0, - name, trigger); - priv->led[IWL_LED_TRG_TX].led_on = iwl4965_led_associated; - priv->led[IWL_LED_TRG_TX].led_off = iwl4965_led_associated; + snprintf(name, sizeof(name), "iwl-%s:TX", wiphy_name(priv->hw->wiphy)); + ret = iwl_leds_register_led(priv, &priv->led[IWL_LED_TRG_TX], + IWL_LED_TRG_TX, 0, name, trigger); + + priv->led[IWL_LED_TRG_TX].led_on = iwl_led_associated; + priv->led[IWL_LED_TRG_TX].led_off = iwl_led_associated; priv->led[IWL_LED_TRG_TX].led_pattern = iwl4965_led_pattern; if (ret) @@ -425,7 +406,7 @@ exit_fail: EXPORT_SYMBOL(iwl_leds_register); /* unregister led class */ -static void iwl_leds_unregister_led(struct iwl4965_led *led, u8 set_led) +static void iwl_leds_unregister_led(struct iwl_led *led, u8 set_led) { if (!led->registered) return; diff --git a/drivers/net/wireless/iwlwifi/iwl-led.h b/drivers/net/wireless/iwlwifi/iwl-led.h index 5bb04128cd65..1980ae5a7e82 100644 --- a/drivers/net/wireless/iwlwifi/iwl-led.h +++ b/drivers/net/wireless/iwlwifi/iwl-led.h @@ -49,14 +49,13 @@ enum led_type { }; -struct iwl4965_led { +struct iwl_led { struct iwl_priv *priv; struct led_classdev led_dev; int (*led_on) (struct iwl_priv *priv, int led_id); int (*led_off) (struct iwl_priv *priv, int led_id); - int (*led_pattern) (struct iwl_priv *priv, int led_id, - enum led_brightness brightness); + int (*led_pattern) (struct iwl_priv *priv, int led_id, unsigned int idx); enum led_type type; unsigned int registered; diff --git a/drivers/net/wireless/iwlwifi/iwl-power.c b/drivers/net/wireless/iwlwifi/iwl-power.c new file mode 100644 index 000000000000..2e71803e09ba --- /dev/null +++ b/drivers/net/wireless/iwlwifi/iwl-power.c @@ -0,0 +1,423 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2008 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: + * James P. Ketrenos <ipw2100-admin@linux.intel.com> + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + *****************************************************************************/ + + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/version.h> +#include <linux/init.h> + +#include <net/mac80211.h> + +#include "iwl-eeprom.h" +#include "iwl-dev.h" +#include "iwl-core.h" +#include "iwl-commands.h" +#include "iwl-debug.h" +#include "iwl-power.h" +#include "iwl-helpers.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 + * + * 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. + * + */ + +#define MSEC_TO_USEC 1024 +#define IWL_POWER_RANGE_0_MAX (2) +#define IWL_POWER_RANGE_1_MAX (10) + + +#define NOSLP __constant_cpu_to_le16(0), 0, 0 +#define SLP IWL_POWER_DRIVER_ALLOW_SLEEP_MSK, 0, 0 +#define SLP_TOUT(T) __constant_cpu_to_le32((T) * MSEC_TO_USEC) +#define SLP_VEC(X0, X1, X2, X3, X4) {__constant_cpu_to_le32(X0), \ + __constant_cpu_to_le32(X1), \ + __constant_cpu_to_le32(X2), \ + __constant_cpu_to_le32(X3), \ + __constant_cpu_to_le32(X4)} + +#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 + +/* default power management (not Tx power) table values */ +/* for tim 0-10 */ +static struct iwl_power_vec_entry range_0[IWL_POWER_AC] = { + {{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}, + {{SLP, SLP_TOUT(50), SLP_TOUT(100), SLP_VEC(2, 2, 2, 2, 0xFF)}, 0}, + {{SLP, SLP_TOUT(50), SLP_TOUT(25), SLP_VEC(2, 2, 4, 4, 0xFF)}, 1}, + {{SLP, SLP_TOUT(25), SLP_TOUT(25), SLP_VEC(2, 2, 4, 6, 0xFF)}, 2} +}; + + +/* for tim = 3-10 */ +static struct iwl_power_vec_entry range_1[IWL_POWER_AC] = { + {{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}, + {{SLP, SLP_TOUT(50), SLP_TOUT(100), SLP_VEC(2, 4, 6, 7, 9)}, 0}, + {{SLP, SLP_TOUT(50), SLP_TOUT(25), SLP_VEC(2, 4, 6, 9, 10)}, 1}, + {{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_AC] = { + {{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}, + {{SLP, SLP_TOUT(50), SLP_TOUT(100), SLP_VEC(2, 7, 9, 9, 0xFF)}, 0}, + {{SLP, SLP_TOUT(50), SLP_TOUT(25), SLP_VEC(2, 7, 9, 9, 0xFF)}, 0}, + {{SLP, SLP_TOUT(25), SLP_TOUT(25), SLP_VEC(4, 7, 10, 10, 0xFF)}, 0} +}; + +/* 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 = priv->power_data.user_power_setting; + + 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; + case IWL_POWER_BATTERY: + mode = IWL_POWER_INDEX_3; + break; + case IWL_POWER_AC: + mode = IWL_POWER_MODE_CAM; + break; + } + return mode; +} + +/* initialize to default */ +static int iwl_power_init_handle(struct iwl_priv *priv) +{ + int ret = 0, i; + struct iwl_power_mgr *pow_data; + int size = sizeof(struct iwl_power_vec_entry) * IWL_POWER_AC; + u16 pci_pm; + + IWL_DEBUG_POWER("Initialize power \n"); + + pow_data = &(priv->power_data); + + memset(pow_data, 0, sizeof(*pow_data)); + + memcpy(&pow_data->pwr_range_0[0], &range_0[0], size); + memcpy(&pow_data->pwr_range_1[0], &range_1[0], size); + memcpy(&pow_data->pwr_range_2[0], &range_2[0], size); + + ret = pci_read_config_word(priv->pci_dev, + PCI_LINK_CTRL, &pci_pm); + if (ret != 0) + return 0; + else { + struct iwl4965_powertable_cmd *cmd; + + IWL_DEBUG_POWER("adjust power command flags\n"); + + for (i = 0; i < IWL_POWER_AC; i++) { + cmd = &pow_data->pwr_range_0[i].cmd; + + if (pci_pm & 0x1) + cmd->flags &= ~IWL_POWER_PCI_PM_MSK; + else + cmd->flags |= IWL_POWER_PCI_PM_MSK; + } + } + return ret; +} + +/* adjust power command according to dtim period and power level*/ +static int iwl_update_power_command(struct iwl_priv *priv, + struct iwl4965_powertable_cmd *cmd, + u16 mode) +{ + int ret = 0, i; + u8 skip; + u32 max_sleep = 0; + struct iwl_power_vec_entry *range; + u8 period = 0; + struct iwl_power_mgr *pow_data; + + if (mode > IWL_POWER_INDEX_5) { + IWL_DEBUG_POWER("Error invalid power mode \n"); + return -1; + } + pow_data = &(priv->power_data); + + if (pow_data->dtim_period <= IWL_POWER_RANGE_0_MAX) + range = &pow_data->pwr_range_0[0]; + else if (pow_data->dtim_period <= IWL_POWER_RANGE_1_MAX) + range = &pow_data->pwr_range_1[0]; + else + range = &pow_data->pwr_range_2[0]; + + period = pow_data->dtim_period; + memcpy(cmd, &range[mode].cmd, sizeof(struct iwl4965_powertable_cmd)); + + if (period == 0) { + period = 1; + skip = 0; + } else + skip = range[mode].no_dtim; + + if (skip == 0) { + max_sleep = period; + cmd->flags &= ~IWL_POWER_SLEEP_OVER_DTIM_MSK; + } else { + __le32 slp_itrvl = cmd->sleep_interval[IWL_POWER_VEC_SIZE - 1]; + max_sleep = le32_to_cpu(slp_itrvl); + if (max_sleep == 0xFF) + max_sleep = period * (skip + 1); + else if (max_sleep > period) + max_sleep = (le32_to_cpu(slp_itrvl) / period) * period; + cmd->flags |= IWL_POWER_SLEEP_OVER_DTIM_MSK; + } + + for (i = 0; i < IWL_POWER_VEC_SIZE; i++) { + if (le32_to_cpu(cmd->sleep_interval[i]) > max_sleep) + cmd->sleep_interval[i] = cpu_to_le32(max_sleep); + } + + IWL_DEBUG_POWER("Flags value = 0x%08X\n", cmd->flags); + IWL_DEBUG_POWER("Tx timeout = %u\n", le32_to_cpu(cmd->tx_data_timeout)); + IWL_DEBUG_POWER("Rx timeout = %u\n", le32_to_cpu(cmd->rx_data_timeout)); + IWL_DEBUG_POWER("Sleep interval vector = { %d , %d , %d , %d , %d }\n", + le32_to_cpu(cmd->sleep_interval[0]), + le32_to_cpu(cmd->sleep_interval[1]), + le32_to_cpu(cmd->sleep_interval[2]), + le32_to_cpu(cmd->sleep_interval[3]), + le32_to_cpu(cmd->sleep_interval[4])); + + return ret; +} + + +/* + * calucaute the final power mode index + */ +int iwl_power_update_mode(struct iwl_priv *priv, u8 refresh) +{ + struct iwl_power_mgr *setting = &(priv->power_data); + int ret = 0; + u16 uninitialized_var(final_mode); + + /* If on battery, set to 3, + * if plugged into AC power, set to CAM ("continuously aware mode"), + * else user level */ + + switch (setting->system_power_setting) { + case IWL_POWER_AUTO: + final_mode = iwl_get_auto_power_mode(priv); + break; + case IWL_POWER_BATTERY: + final_mode = IWL_POWER_INDEX_3; + break; + case IWL_POWER_AC: + final_mode = IWL_POWER_MODE_CAM; + break; + default: + final_mode = setting->system_power_setting; + } + + if (setting->critical_power_setting > final_mode) + final_mode = setting->critical_power_setting; + + /* driver only support CAM for non STA network */ + if (priv->iw_mode != IEEE80211_IF_TYPE_STA) + final_mode = IWL_POWER_MODE_CAM; + + if (!iwl_is_rfkill(priv) && !setting->power_disabled && + ((setting->power_mode != final_mode) || refresh)) { + struct iwl4965_powertable_cmd cmd; + + if (final_mode != IWL_POWER_MODE_CAM) + set_bit(STATUS_POWER_PMI, &priv->status); + + iwl_update_power_command(priv, &cmd, final_mode); + cmd.keep_alive_beacons = 0; + + if (final_mode == IWL_POWER_INDEX_5) + cmd.flags |= IWL_POWER_FAST_PD; + + if (priv->cfg->ops->lib->set_power) + ret = priv->cfg->ops->lib->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) + priv->cfg->ops->lib->update_chain_flags(priv); + + if (!ret) + setting->power_mode = final_mode; + } + + return ret; +} +EXPORT_SYMBOL(iwl_power_update_mode); + +/* Allow other iwl code to disable/enable power management active + * this will be usefull for rate scale to disable PM during heavy + * Tx/Rx activities + */ +int iwl_power_disable_management(struct iwl_priv *priv) +{ + 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; + + return ret; +} +EXPORT_SYMBOL(iwl_power_disable_management); + +/* Allow other iwl code to disable/enable power management active + * this will be usefull for rate scale to disable PM during hight + * valume 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) +{ + int ret = 0; + + if (mode > IWL_POWER_LIMIT) + return -EINVAL; + + priv->power_data.user_power_setting = mode; + + ret = iwl_power_update_mode(priv, 0); + + return ret; +} +EXPORT_SYMBOL(iwl_power_set_user_mode); + + +/* set system_power_setting. This should be set by over all + * PM application. + */ +int iwl_power_set_system_mode(struct iwl_priv *priv, u16 mode) +{ + int ret = 0; + + if (mode > IWL_POWER_LIMIT) + return -EINVAL; + + priv->power_data.system_power_setting = mode; + + ret = iwl_power_update_mode(priv, 0); + + return ret; +} +EXPORT_SYMBOL(iwl_power_set_system_mode); + +/* initilize 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.power_disabled = 0; + priv->power_data.system_power_setting = IWL_POWER_AUTO; + priv->power_data.is_battery_active = 0; + priv->power_data.power_disabled = 0; + priv->power_data.critical_power_setting = 0; +} +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; + u16 new_critical = priv->power_data.critical_power_setting; + s32 temperature = KELVIN_TO_CELSIUS(priv->last_temperature); + + 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); diff --git a/drivers/net/wireless/iwlwifi/iwl-power.h b/drivers/net/wireless/iwlwifi/iwl-power.h new file mode 100644 index 000000000000..b066724a1c2b --- /dev/null +++ b/drivers/net/wireless/iwlwifi/iwl-power.h @@ -0,0 +1,76 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2008 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: + * James P. Ketrenos <ipw2100-admin@linux.intel.com> + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + *****************************************************************************/ +#ifndef __iwl_power_setting_h__ +#define __iwl_power_setting_h__ + +#include <net/mac80211.h> +#include "iwl-commands.h" + +struct iwl_priv; + +#define IWL_POWER_MODE_CAM 0x00 /* Continuously Aware Mode, always on */ +#define IWL_POWER_INDEX_3 0x03 +#define IWL_POWER_INDEX_5 0x05 +#define IWL_POWER_AC 0x06 +#define IWL_POWER_BATTERY 0x07 +#define IWL_POWER_AUTO 0x08 +#define IWL_POWER_LIMIT 0x08 +#define IWL_POWER_MASK 0x0F +#define IWL_POWER_ENABLED 0x10 + +/* Power management (not Tx power) structures */ + +struct iwl_power_vec_entry { + struct iwl4965_powertable_cmd cmd; + u8 no_dtim; +}; + +struct iwl_power_mgr { + spinlock_t lock; + struct iwl_power_vec_entry pwr_range_0[IWL_POWER_AC]; + struct iwl_power_vec_entry pwr_range_1[IWL_POWER_AC]; + struct iwl_power_vec_entry pwr_range_2[IWL_POWER_AC]; + 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 syatem tools */ + u8 critical_power_setting; /* set if driver over heated */ + u8 is_battery_active; /* DC/AC power */ + u8 power_disabled; /* flag to disable using power saving level */ +}; + +int iwl_power_update_mode(struct iwl_priv *priv, u8 refresh); +int iwl_power_disable_management(struct iwl_priv *priv); +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/iwl-prph.h b/drivers/net/wireless/iwlwifi/iwl-prph.h index c9cf8eef1a90..70d9c7568b98 100644 --- a/drivers/net/wireless/iwlwifi/iwl-prph.h +++ b/drivers/net/wireless/iwlwifi/iwl-prph.h @@ -239,40 +239,307 @@ #define ALM_SCD_SBYP_MODE_1_REG (ALM_SCD_BASE + 0x02C) #define ALM_SCD_SBYP_MODE_2_REG (ALM_SCD_BASE + 0x030) +/** + * Tx Scheduler + * + * The Tx Scheduler selects the next frame to be transmitted, chosing TFDs + * (Transmit Frame Descriptors) from up to 16 circular Tx queues resident in + * host DRAM. It steers each frame's Tx command (which contains the frame + * data) into one of up to 7 prioritized Tx DMA FIFO channels within the + * device. A queue maps to only one (selectable by driver) Tx DMA channel, + * but one DMA channel may take input from several queues. + * + * Tx DMA channels have dedicated purposes. For 4965, they are used as follows: + * + * 0 -- EDCA BK (background) frames, lowest priority + * 1 -- EDCA BE (best effort) frames, normal priority + * 2 -- EDCA VI (video) frames, higher priority + * 3 -- EDCA VO (voice) and management frames, highest priority + * 4 -- Commands (e.g. RXON, etc.) + * 5 -- HCCA short frames + * 6 -- HCCA long frames + * 7 -- not used by driver (device-internal only) + * + * Driver should normally map queues 0-6 to Tx DMA/FIFO channels 0-6. + * In addition, driver can map queues 7-15 to Tx DMA/FIFO channels 0-3 to + * support 11n aggregation via EDCA DMA channels. + * + * The driver sets up each queue to work in one of two modes: + * + * 1) Scheduler-Ack, in which the scheduler automatically supports a + * block-ack (BA) window of up to 64 TFDs. In this mode, each queue + * contains TFDs for a unique combination of Recipient Address (RA) + * and Traffic Identifier (TID), that is, traffic of a given + * Quality-Of-Service (QOS) priority, destined for a single station. + * + * In scheduler-ack mode, the scheduler keeps track of the Tx status of + * each frame within the BA window, including whether it's been transmitted, + * and whether it's been acknowledged by the receiving station. The device + * automatically processes block-acks received from the receiving STA, + * and reschedules un-acked frames to be retransmitted (successful + * Tx completion may end up being out-of-order). + * + * The driver must maintain the queue's Byte Count table in host DRAM + * (struct iwl4965_sched_queue_byte_cnt_tbl) for this mode. + * This mode does not support fragmentation. + * + * 2) FIFO (a.k.a. non-Scheduler-ACK), in which each TFD is processed in order. + * The device may automatically retry Tx, but will retry only one frame + * at a time, until receiving ACK from receiving station, or reaching + * retry limit and giving up. + * + * The command queue (#4) must use this mode! + * This mode does not require use of the Byte Count table in host DRAM. + * + * Driver controls scheduler operation via 3 means: + * 1) Scheduler registers + * 2) Shared scheduler data base in internal 4956 SRAM + * 3) Shared data in host DRAM + * + * Initialization: + * + * When loading, driver should allocate memory for: + * 1) 16 TFD circular buffers, each with space for (typically) 256 TFDs. + * 2) 16 Byte Count circular buffers in 16 KBytes contiguous memory + * (1024 bytes for each queue). + * + * After receiving "Alive" response from uCode, driver must initialize + * the scheduler (especially for queue #4, the command queue, otherwise + * the driver can't issue commands!): + */ + +/** + * Max Tx window size is the max number of contiguous TFDs that the scheduler + * can keep track of at one time when creating block-ack chains of frames. + * Note that "64" matches the number of ack bits in a block-ack packet. + * Driver should use SCD_WIN_SIZE and SCD_FRAME_LIMIT values to initialize + * IWL49_SCD_CONTEXT_QUEUE_OFFSET(x) values. + */ +#define SCD_WIN_SIZE 64 +#define SCD_FRAME_LIMIT 64 + +/* SCD registers are internal, must be accessed via HBUS_TARG_PRPH regs */ +#define IWL49_SCD_START_OFFSET 0xa02c00 + +/* + * 4965 tells driver SRAM address for internal scheduler structs via this reg. + * Value is valid only after "Alive" response from uCode. + */ +#define IWL49_SCD_SRAM_BASE_ADDR (IWL49_SCD_START_OFFSET + 0x0) + +/* + * Driver may need to update queue-empty bits after changing queue's + * write and read pointers (indexes) during (re-)initialization (i.e. when + * scheduler is not tracking what's happening). + * Bit fields: + * 31-16: Write mask -- 1: update empty bit, 0: don't change empty bit + * 15-00: Empty state, one for each queue -- 1: empty, 0: non-empty + * NOTE: This register is not used by Linux driver. + */ +#define IWL49_SCD_EMPTY_BITS (IWL49_SCD_START_OFFSET + 0x4) + +/* + * Physical base address of array of byte count (BC) circular buffers (CBs). + * Each Tx queue has a BC CB in host DRAM to support Scheduler-ACK mode. + * This register points to BC CB for queue 0, must be on 1024-byte boundary. + * Others are spaced by 1024 bytes. + * Each BC CB is 2 bytes * (256 + 64) = 740 bytes, followed by 384 bytes pad. + * (Index into a queue's BC CB) = (index into queue's TFD CB) = (SSN & 0xff). + * Bit fields: + * 25-00: Byte Count CB physical address [35:10], must be 1024-byte aligned. + */ +#define IWL49_SCD_DRAM_BASE_ADDR (IWL49_SCD_START_OFFSET + 0x10) + +/* + * Enables any/all Tx DMA/FIFO channels. + * Scheduler generates requests for only the active channels. + * Set this to 0xff to enable all 8 channels (normal usage). + * Bit fields: + * 7- 0: Enable (1), disable (0), one bit for each channel 0-7 + */ +#define IWL49_SCD_TXFACT (IWL49_SCD_START_OFFSET + 0x1c) +/* + * Queue (x) Write Pointers (indexes, really!), one for each Tx queue. + * Initialized and updated by driver as new TFDs are added to queue. + * NOTE: If using Block Ack, index must correspond to frame's + * Start Sequence Number; index = (SSN & 0xff) + * NOTE: Alternative to HBUS_TARG_WRPTR, which is what Linux driver uses? + */ +#define IWL49_SCD_QUEUE_WRPTR(x) (IWL49_SCD_START_OFFSET + 0x24 + (x) * 4) + +/* + * Queue (x) Read Pointers (indexes, really!), one for each Tx queue. + * For FIFO mode, index indicates next frame to transmit. + * For Scheduler-ACK mode, index indicates first frame in Tx window. + * Initialized by driver, updated by scheduler. + */ +#define IWL49_SCD_QUEUE_RDPTR(x) (IWL49_SCD_START_OFFSET + 0x64 + (x) * 4) + +/* + * Select which queues work in chain mode (1) vs. not (0). + * Use chain mode to build chains of aggregated frames. + * Bit fields: + * 31-16: Reserved + * 15-00: Mode, one bit for each queue -- 1: Chain mode, 0: one-at-a-time + * NOTE: If driver sets up queue for chain mode, it should be also set up + * Scheduler-ACK mode as well, via SCD_QUEUE_STATUS_BITS(x). + */ +#define IWL49_SCD_QUEUECHAIN_SEL (IWL49_SCD_START_OFFSET + 0xd0) + +/* + * Select which queues interrupt driver when scheduler increments + * a queue's read pointer (index). + * Bit fields: + * 31-16: Reserved + * 15-00: Interrupt enable, one bit for each queue -- 1: enabled, 0: disabled + * NOTE: This functionality is apparently a no-op; driver relies on interrupts + * from Rx queue to read Tx command responses and update Tx queues. + */ +#define IWL49_SCD_INTERRUPT_MASK (IWL49_SCD_START_OFFSET + 0xe4) + +/* + * Queue search status registers. One for each queue. + * Sets up queue mode and assigns queue to Tx DMA channel. + * Bit fields: + * 19-10: Write mask/enable bits for bits 0-9 + * 9: Driver should init to "0" + * 8: Scheduler-ACK mode (1), non-Scheduler-ACK (i.e. FIFO) mode (0). + * Driver should init to "1" for aggregation mode, or "0" otherwise. + * 7-6: Driver should init to "0" + * 5: Window Size Left; indicates whether scheduler can request + * another TFD, based on window size, etc. Driver should init + * this bit to "1" for aggregation mode, or "0" for non-agg. + * 4-1: Tx FIFO to use (range 0-7). + * 0: Queue is active (1), not active (0). + * Other bits should be written as "0" + * + * NOTE: If enabling Scheduler-ACK mode, chain mode should also be enabled + * via SCD_QUEUECHAIN_SEL. + */ +#define IWL49_SCD_QUEUE_STATUS_BITS(x)\ + (IWL49_SCD_START_OFFSET + 0x104 + (x) * 4) + +/* Bit field positions */ +#define IWL49_SCD_QUEUE_STTS_REG_POS_ACTIVE (0) +#define IWL49_SCD_QUEUE_STTS_REG_POS_TXF (1) +#define IWL49_SCD_QUEUE_STTS_REG_POS_WSL (5) +#define IWL49_SCD_QUEUE_STTS_REG_POS_SCD_ACK (8) + +/* Write masks */ +#define IWL49_SCD_QUEUE_STTS_REG_POS_SCD_ACT_EN (10) +#define IWL49_SCD_QUEUE_STTS_REG_MSK (0x0007FC00) + +/** + * 4965 internal SRAM structures for scheduler, shared with driver ... + * + * Driver should clear and initialize the following areas after receiving + * "Alive" response from 4965 uCode, i.e. after initial + * uCode load, or after a uCode load done for error recovery: + * + * SCD_CONTEXT_DATA_OFFSET (size 128 bytes) + * SCD_TX_STTS_BITMAP_OFFSET (size 256 bytes) + * SCD_TRANSLATE_TBL_OFFSET (size 32 bytes) + * + * Driver accesses SRAM via HBUS_TARG_MEM_* registers. + * Driver reads base address of this scheduler area from SCD_SRAM_BASE_ADDR. + * All OFFSET values must be added to this base address. + */ + +/* + * Queue context. One 8-byte entry for each of 16 queues. + * + * Driver should clear this entire area (size 0x80) to 0 after receiving + * "Alive" notification from uCode. Additionally, driver should init + * each queue's entry as follows: + * + * LS Dword bit fields: + * 0-06: Max Tx window size for Scheduler-ACK. Driver should init to 64. + * + * MS Dword bit fields: + * 16-22: Frame limit. Driver should init to 10 (0xa). + * + * Driver should init all other bits to 0. + * + * Init must be done after driver receives "Alive" response from 4965 uCode, + * and when setting up queue for aggregation. + */ +#define IWL49_SCD_CONTEXT_DATA_OFFSET 0x380 +#define IWL49_SCD_CONTEXT_QUEUE_OFFSET(x) \ + (IWL49_SCD_CONTEXT_DATA_OFFSET + ((x) * 8)) + +#define IWL49_SCD_QUEUE_CTX_REG1_WIN_SIZE_POS (0) +#define IWL49_SCD_QUEUE_CTX_REG1_WIN_SIZE_MSK (0x0000007F) +#define IWL49_SCD_QUEUE_CTX_REG2_FRAME_LIMIT_POS (16) +#define IWL49_SCD_QUEUE_CTX_REG2_FRAME_LIMIT_MSK (0x007F0000) + +/* + * Tx Status Bitmap + * + * Driver should clear this entire area (size 0x100) to 0 after receiving + * "Alive" notification from uCode. Area is used only by device itself; + * no other support (besides clearing) is required from driver. + */ +#define IWL49_SCD_TX_STTS_BITMAP_OFFSET 0x400 + /* - * 4965 Tx Scheduler registers. - * Details are documented in iwl-4965-hw.h + * RAxTID to queue translation mapping. + * + * When queue is in Scheduler-ACK mode, frames placed in a that queue must be + * for only one combination of receiver address (RA) and traffic ID (TID), i.e. + * one QOS priority level destined for one station (for this wireless link, + * not final destination). The SCD_TRANSLATE_TABLE area provides 16 16-bit + * mappings, one for each of the 16 queues. If queue is not in Scheduler-ACK + * mode, the device ignores the mapping value. + * + * Bit fields, for each 16-bit map: + * 15-9: Reserved, set to 0 + * 8-4: Index into device's station table for recipient station + * 3-0: Traffic ID (tid), range 0-15 + * + * Driver should clear this entire area (size 32 bytes) to 0 after receiving + * "Alive" notification from uCode. To update a 16-bit map value, driver + * must read a dword-aligned value from device SRAM, replace the 16-bit map + * value of interest, and write the dword value back into device SRAM. */ -#define IWL49_SCD_BASE (PRPH_BASE + 0xa02c00) - -#define IWL49_SCD_SRAM_BASE_ADDR (IWL49_SCD_BASE + 0x0) -#define IWL49_SCD_EMPTY_BITS (IWL49_SCD_BASE + 0x4) -#define IWL49_SCD_DRAM_BASE_ADDR (IWL49_SCD_BASE + 0x10) -#define IWL49_SCD_AIT (IWL49_SCD_BASE + 0x18) -#define IWL49_SCD_TXFACT (IWL49_SCD_BASE + 0x1c) -#define IWL49_SCD_QUEUE_WRPTR(x) (IWL49_SCD_BASE + 0x24 + (x) * 4) -#define IWL49_SCD_QUEUE_RDPTR(x) (IWL49_SCD_BASE + 0x64 + (x) * 4) -#define IWL49_SCD_SETQUEUENUM (IWL49_SCD_BASE + 0xa4) -#define IWL49_SCD_SET_TXSTAT_TXED (IWL49_SCD_BASE + 0xa8) -#define IWL49_SCD_SET_TXSTAT_DONE (IWL49_SCD_BASE + 0xac) -#define IWL49_SCD_SET_TXSTAT_NOT_SCHD (IWL49_SCD_BASE + 0xb0) -#define IWL49_SCD_DECREASE_CREDIT (IWL49_SCD_BASE + 0xb4) -#define IWL49_SCD_DECREASE_SCREDIT (IWL49_SCD_BASE + 0xb8) -#define IWL49_SCD_LOAD_CREDIT (IWL49_SCD_BASE + 0xbc) -#define IWL49_SCD_LOAD_SCREDIT (IWL49_SCD_BASE + 0xc0) -#define IWL49_SCD_BAR (IWL49_SCD_BASE + 0xc4) -#define IWL49_SCD_BAR_DW0 (IWL49_SCD_BASE + 0xc8) -#define IWL49_SCD_BAR_DW1 (IWL49_SCD_BASE + 0xcc) -#define IWL49_SCD_QUEUECHAIN_SEL (IWL49_SCD_BASE + 0xd0) -#define IWL49_SCD_QUERY_REQ (IWL49_SCD_BASE + 0xd8) -#define IWL49_SCD_QUERY_RES (IWL49_SCD_BASE + 0xdc) -#define IWL49_SCD_PENDING_FRAMES (IWL49_SCD_BASE + 0xe0) -#define IWL49_SCD_INTERRUPT_MASK (IWL49_SCD_BASE + 0xe4) -#define IWL49_SCD_INTERRUPT_THRESHOLD (IWL49_SCD_BASE + 0xe8) -#define IWL49_SCD_QUERY_MIN_FRAME_SIZE (IWL49_SCD_BASE + 0x100) -#define IWL49_SCD_QUEUE_STATUS_BITS(x) (IWL49_SCD_BASE + 0x104 + (x) * 4) - -/* SP SCD */ +#define IWL49_SCD_TRANSLATE_TBL_OFFSET 0x500 + +/* Find translation table dword to read/write for given queue */ +#define IWL49_SCD_TRANSLATE_TBL_OFFSET_QUEUE(x) \ + ((IWL49_SCD_TRANSLATE_TBL_OFFSET + ((x) * 2)) & 0xfffffffc) + +#define IWL_SCD_TXFIFO_POS_TID (0) +#define IWL_SCD_TXFIFO_POS_RA (4) +#define IWL_SCD_QUEUE_RA_TID_MAP_RATID_MSK (0x01FF) + +/* 5000 SCD */ +#define IWL50_SCD_QUEUE_STTS_REG_POS_TXF (0) +#define IWL50_SCD_QUEUE_STTS_REG_POS_ACTIVE (3) +#define IWL50_SCD_QUEUE_STTS_REG_POS_WSL (4) +#define IWL50_SCD_QUEUE_STTS_REG_POS_SCD_ACT_EN (19) +#define IWL50_SCD_QUEUE_STTS_REG_MSK (0x00FF0000) + +#define IWL50_SCD_QUEUE_CTX_REG1_CREDIT_POS (8) +#define IWL50_SCD_QUEUE_CTX_REG1_CREDIT_MSK (0x00FFFF00) +#define IWL50_SCD_QUEUE_CTX_REG1_SUPER_CREDIT_POS (24) +#define IWL50_SCD_QUEUE_CTX_REG1_SUPER_CREDIT_MSK (0xFF000000) +#define IWL50_SCD_QUEUE_CTX_REG2_WIN_SIZE_POS (0) +#define IWL50_SCD_QUEUE_CTX_REG2_WIN_SIZE_MSK (0x0000007F) +#define IWL50_SCD_QUEUE_CTX_REG2_FRAME_LIMIT_POS (16) +#define IWL50_SCD_QUEUE_CTX_REG2_FRAME_LIMIT_MSK (0x007F0000) + +#define IWL50_SCD_CONTEXT_DATA_OFFSET (0x600) +#define IWL50_SCD_TX_STTS_BITMAP_OFFSET (0x7B1) +#define IWL50_SCD_TRANSLATE_TBL_OFFSET (0x7E0) + +#define IWL50_SCD_CONTEXT_QUEUE_OFFSET(x)\ + (IWL50_SCD_CONTEXT_DATA_OFFSET + ((x) * 8)) + +#define IWL50_SCD_TRANSLATE_TBL_OFFSET_QUEUE(x) \ + ((IWL50_SCD_TRANSLATE_TBL_OFFSET + ((x) * 2)) & 0xfffc) + +#define IWL50_SCD_QUEUECHAIN_SEL_ALL(x) (((1<<(x)) - 1) &\ + (~(1<<IWL_CMD_QUEUE_NUM))) + #define IWL50_SCD_BASE (PRPH_BASE + 0xa02c00) #define IWL50_SCD_SRAM_BASE_ADDR (IWL50_SCD_BASE + 0x0) @@ -287,4 +554,6 @@ #define IWL50_SCD_INTERRUPT_MASK (IWL50_SCD_BASE + 0x108) #define IWL50_SCD_QUEUE_STATUS_BITS(x) (IWL50_SCD_BASE + 0x10c + (x) * 4) +/*********************** END TX SCHEDULER *************************************/ + #endif /* __iwl_prph_h__ */ diff --git a/drivers/net/wireless/iwlwifi/iwl-rfkill.c b/drivers/net/wireless/iwlwifi/iwl-rfkill.c index 5980a5621cb8..e5e5846e9f25 100644 --- a/drivers/net/wireless/iwlwifi/iwl-rfkill.c +++ b/drivers/net/wireless/iwlwifi/iwl-rfkill.c @@ -33,7 +33,7 @@ #include <net/mac80211.h> #include "iwl-eeprom.h" -#include "iwl-4965.h" +#include "iwl-dev.h" #include "iwl-core.h" #include "iwl-helpers.h" @@ -44,28 +44,31 @@ static int iwl_rfkill_soft_rf_kill(void *data, enum rfkill_state state) struct iwl_priv *priv = data; int err = 0; - if (!priv->rfkill_mngr.rfkill) + if (!priv->rfkill) return 0; if (test_bit(STATUS_EXIT_PENDING, &priv->status)) return 0; - IWL_DEBUG_RF_KILL("we recieved soft RFKILL set to state %d\n", state); + IWL_DEBUG_RF_KILL("we received soft RFKILL set to state %d\n", state); mutex_lock(&priv->mutex); switch (state) { - case RFKILL_STATE_ON: - priv->cfg->ops->lib->radio_kill_sw(priv, 0); - /* if HW rf-kill is set dont allow ON state */ - if (iwl_is_rfkill(priv)) + case RFKILL_STATE_UNBLOCKED: + if (iwl_is_rfkill_hw(priv)) { err = -EBUSY; + goto out_unlock; + } + iwl_radio_kill_sw_enable_radio(priv); break; - case RFKILL_STATE_OFF: - priv->cfg->ops->lib->radio_kill_sw(priv, 1); - if (!iwl_is_rfkill(priv)) - err = -EBUSY; + case RFKILL_STATE_SOFT_BLOCKED: + iwl_radio_kill_sw_disable_radio(priv); + break; + default: + IWL_WARNING("we recieved unexpected RFKILL state %d\n", state); break; } +out_unlock: mutex_unlock(&priv->mutex); return err; @@ -79,64 +82,35 @@ int iwl_rfkill_init(struct iwl_priv *priv) BUG_ON(device == NULL); IWL_DEBUG_RF_KILL("Initializing RFKILL.\n"); - priv->rfkill_mngr.rfkill = rfkill_allocate(device, RFKILL_TYPE_WLAN); - if (!priv->rfkill_mngr.rfkill) { + priv->rfkill = rfkill_allocate(device, RFKILL_TYPE_WLAN); + if (!priv->rfkill) { IWL_ERROR("Unable to allocate rfkill device.\n"); ret = -ENOMEM; goto error; } - priv->rfkill_mngr.rfkill->name = priv->cfg->name; - priv->rfkill_mngr.rfkill->data = priv; - priv->rfkill_mngr.rfkill->state = RFKILL_STATE_ON; - priv->rfkill_mngr.rfkill->toggle_radio = iwl_rfkill_soft_rf_kill; - priv->rfkill_mngr.rfkill->user_claim_unsupported = 1; + 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->user_claim_unsupported = 1; - priv->rfkill_mngr.rfkill->dev.class->suspend = NULL; - priv->rfkill_mngr.rfkill->dev.class->resume = NULL; + priv->rfkill->dev.class->suspend = NULL; + priv->rfkill->dev.class->resume = NULL; - priv->rfkill_mngr.input_dev = input_allocate_device(); - if (!priv->rfkill_mngr.input_dev) { - IWL_ERROR("Unable to allocate rfkill input device.\n"); - ret = -ENOMEM; - goto freed_rfkill; - } - - priv->rfkill_mngr.input_dev->name = priv->cfg->name; - priv->rfkill_mngr.input_dev->phys = wiphy_name(priv->hw->wiphy); - priv->rfkill_mngr.input_dev->id.bustype = BUS_HOST; - priv->rfkill_mngr.input_dev->id.vendor = priv->pci_dev->vendor; - priv->rfkill_mngr.input_dev->dev.parent = device; - priv->rfkill_mngr.input_dev->evbit[0] = BIT(EV_KEY); - set_bit(KEY_WLAN, priv->rfkill_mngr.input_dev->keybit); - - ret = rfkill_register(priv->rfkill_mngr.rfkill); + ret = rfkill_register(priv->rfkill); if (ret) { IWL_ERROR("Unable to register rfkill: %d\n", ret); - goto free_input_dev; - } - - ret = input_register_device(priv->rfkill_mngr.input_dev); - if (ret) { - IWL_ERROR("Unable to register rfkill input device: %d\n", ret); - goto unregister_rfkill; + goto free_rfkill; } IWL_DEBUG_RF_KILL("RFKILL initialization complete.\n"); return ret; -unregister_rfkill: - rfkill_unregister(priv->rfkill_mngr.rfkill); - priv->rfkill_mngr.rfkill = NULL; - -free_input_dev: - input_free_device(priv->rfkill_mngr.input_dev); - priv->rfkill_mngr.input_dev = NULL; - -freed_rfkill: - if (priv->rfkill_mngr.rfkill != NULL) - rfkill_free(priv->rfkill_mngr.rfkill); - priv->rfkill_mngr.rfkill = NULL; +free_rfkill: + if (priv->rfkill != NULL) + rfkill_free(priv->rfkill); + priv->rfkill = NULL; error: IWL_DEBUG_RF_KILL("RFKILL initialization complete.\n"); @@ -147,27 +121,27 @@ EXPORT_SYMBOL(iwl_rfkill_init); void iwl_rfkill_unregister(struct iwl_priv *priv) { - if (priv->rfkill_mngr.input_dev) - input_unregister_device(priv->rfkill_mngr.input_dev); + if (priv->rfkill) + rfkill_unregister(priv->rfkill); - if (priv->rfkill_mngr.rfkill) - rfkill_unregister(priv->rfkill_mngr.rfkill); - - priv->rfkill_mngr.input_dev = NULL; - priv->rfkill_mngr.rfkill = NULL; + priv->rfkill = NULL; } EXPORT_SYMBOL(iwl_rfkill_unregister); /* set rf-kill to the right state. */ void iwl_rfkill_set_hw_state(struct iwl_priv *priv) { + if (!priv->rfkill) + return; - if (!priv->rfkill_mngr.rfkill) + if (iwl_is_rfkill_hw(priv)) { + rfkill_force_state(priv->rfkill, RFKILL_STATE_HARD_BLOCKED); return; + } - if (!iwl_is_rfkill(priv)) - priv->rfkill_mngr.rfkill->state = RFKILL_STATE_ON; + if (!iwl_is_rfkill_sw(priv)) + rfkill_force_state(priv->rfkill, RFKILL_STATE_UNBLOCKED); else - priv->rfkill_mngr.rfkill->state = RFKILL_STATE_OFF; + rfkill_force_state(priv->rfkill, RFKILL_STATE_SOFT_BLOCKED); } 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 index a7f04b855403..402fd4c781da 100644 --- a/drivers/net/wireless/iwlwifi/iwl-rfkill.h +++ b/drivers/net/wireless/iwlwifi/iwl-rfkill.h @@ -31,14 +31,8 @@ struct iwl_priv; #include <linux/rfkill.h> -#include <linux/input.h> - #ifdef CONFIG_IWLWIFI_RFKILL -struct iwl_rfkill_mngr { - struct rfkill *rfkill; - struct input_dev *input_dev; -}; void iwl_rfkill_set_hw_state(struct iwl_priv *priv); void iwl_rfkill_unregister(struct iwl_priv *priv); diff --git a/drivers/net/wireless/iwlwifi/iwl-rx.c b/drivers/net/wireless/iwlwifi/iwl-rx.c new file mode 100644 index 000000000000..e2d9afba38a5 --- /dev/null +++ b/drivers/net/wireless/iwlwifi/iwl-rx.c @@ -0,0 +1,1321 @@ +/****************************************************************************** + * + * Copyright(c) 2003 - 2008 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: + * James P. Ketrenos <ipw2100-admin@linux.intel.com> + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + * + *****************************************************************************/ + +#include <linux/etherdevice.h> +#include <net/mac80211.h> +#include <asm/unaligned.h> +#include "iwl-eeprom.h" +#include "iwl-dev.h" +#include "iwl-core.h" +#include "iwl-sta.h" +#include "iwl-io.h" +#include "iwl-calib.h" +#include "iwl-helpers.h" +/************************** RX-FUNCTIONS ****************************/ +/* + * Rx theory of operation + * + * Driver allocates a circular buffer of Receive Buffer Descriptors (RBDs), + * each of which point to Receive Buffers to be filled by the NIC. These get + * used not only for Rx frames, but for any command response or notification + * from the NIC. The driver and NIC manage the Rx buffers by means + * of indexes into the circular buffer. + * + * Rx Queue Indexes + * The host/firmware share two index registers for managing the Rx buffers. + * + * The READ index maps to the first position that the firmware may be writing + * to -- the driver can read up to (but not including) this position and get + * good data. + * The READ index is managed by the firmware once the card is enabled. + * + * The WRITE index maps to the last position the driver has read from -- the + * position preceding WRITE is the last slot the firmware can place a packet. + * + * The queue is empty (no good data) if WRITE = READ - 1, and is full if + * WRITE = READ. + * + * During initialization, the host sets up the READ queue position to the first + * INDEX position, and WRITE to the last (READ - 1 wrapped) + * + * When the firmware places a packet in a buffer, it will advance the READ index + * and fire the RX interrupt. The driver can then query the READ index and + * process as many packets as possible, moving the WRITE index forward as it + * resets the Rx queue buffers with new memory. + * + * The management in the driver is as follows: + * + A list of pre-allocated SKBs is stored in iwl->rxq->rx_free. When + * iwl->rxq->free_count drops to or below RX_LOW_WATERMARK, work is scheduled + * to replenish the iwl->rxq->rx_free. + * + In iwl_rx_replenish (scheduled) if 'processed' != 'read' then the + * iwl->rxq is replenished and the READ INDEX is updated (updating the + * 'processed' and 'read' driver indexes as well) + * + A received packet is processed and handed to the kernel network stack, + * detached from the iwl->rxq. The driver 'processed' index is updated. + * + The Host/Firmware iwl->rxq is replenished at tasklet time from the rx_free + * list. If there are no allocated buffers in iwl->rxq->rx_free, the READ + * INDEX is not incremented and iwl->status(RX_STALLED) is set. If there + * were enough free buffers and RX_STALLED is set it is cleared. + * + * + * Driver sequence: + * + * iwl_rx_queue_alloc() Allocates rx_free + * iwl_rx_replenish() Replenishes rx_free list from rx_used, and calls + * iwl_rx_queue_restock + * iwl_rx_queue_restock() Moves available buffers from rx_free into Rx + * queue, updates firmware pointers, and updates + * the WRITE index. If insufficient rx_free buffers + * are available, schedules iwl_rx_replenish + * + * -- enable interrupts -- + * ISR - iwl_rx() Detach iwl_rx_mem_buffers from pool up to the + * READ INDEX, detaching the SKB from the pool. + * Moves the packet buffer from queue to rx_used. + * Calls iwl_rx_queue_restock to refill any empty + * slots. + * ... + * + */ + +/** + * iwl_rx_queue_space - Return number of free slots available in queue. + */ +int iwl_rx_queue_space(const struct iwl_rx_queue *q) +{ + int s = q->read - q->write; + if (s <= 0) + s += RX_QUEUE_SIZE; + /* keep some buffer to not confuse full and empty queue */ + s -= 2; + if (s < 0) + s = 0; + return s; +} +EXPORT_SYMBOL(iwl_rx_queue_space); + +/** + * iwl_rx_queue_update_write_ptr - Update the write pointer for the RX queue + */ +int iwl_rx_queue_update_write_ptr(struct iwl_priv *priv, struct iwl_rx_queue *q) +{ + u32 reg = 0; + int ret = 0; + unsigned long flags; + + spin_lock_irqsave(&q->lock, flags); + + if (q->need_update == 0) + goto exit_unlock; + + /* If power-saving is in use, make sure device is awake */ + if (test_bit(STATUS_POWER_PMI, &priv->status)) { + reg = iwl_read32(priv, CSR_UCODE_DRV_GP1); + + if (reg & CSR_UCODE_DRV_GP1_BIT_MAC_SLEEP) { + iwl_set_bit(priv, CSR_GP_CNTRL, + CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); + goto exit_unlock; + } + + ret = iwl_grab_nic_access(priv); + if (ret) + goto exit_unlock; + + /* Device expects a multiple of 8 */ + iwl_write_direct32(priv, FH_RSCSR_CHNL0_WPTR, + q->write & ~0x7); + iwl_release_nic_access(priv); + + /* Else device is assumed to be awake */ + } else + /* Device expects a multiple of 8 */ + iwl_write32(priv, FH_RSCSR_CHNL0_WPTR, q->write & ~0x7); + + + q->need_update = 0; + + exit_unlock: + spin_unlock_irqrestore(&q->lock, flags); + return ret; +} +EXPORT_SYMBOL(iwl_rx_queue_update_write_ptr); +/** + * iwl_dma_addr2rbd_ptr - convert a DMA address to a uCode read buffer ptr + */ +static inline __le32 iwl_dma_addr2rbd_ptr(struct iwl_priv *priv, + dma_addr_t dma_addr) +{ + return cpu_to_le32((u32)(dma_addr >> 8)); +} + +/** + * iwl_rx_queue_restock - refill RX queue from pre-allocated pool + * + * If there are slots in the RX queue that need to be restocked, + * and we have free pre-allocated buffers, fill the ranks as much + * as we can, pulling from rx_free. + * + * This moves the 'write' index forward to catch up with 'processed', and + * also updates the memory address in the firmware to reference the new + * target buffer. + */ +int iwl_rx_queue_restock(struct iwl_priv *priv) +{ + struct iwl_rx_queue *rxq = &priv->rxq; + struct list_head *element; + struct iwl_rx_mem_buffer *rxb; + unsigned long flags; + int write; + int ret = 0; + + spin_lock_irqsave(&rxq->lock, flags); + write = rxq->write & ~0x7; + while ((iwl_rx_queue_space(rxq) > 0) && (rxq->free_count)) { + /* Get next free Rx buffer, remove from free list */ + element = rxq->rx_free.next; + rxb = list_entry(element, struct iwl_rx_mem_buffer, list); + list_del(element); + + /* Point to Rx buffer via next RBD in circular buffer */ + rxq->bd[rxq->write] = iwl_dma_addr2rbd_ptr(priv, rxb->dma_addr); + rxq->queue[rxq->write] = rxb; + rxq->write = (rxq->write + 1) & RX_QUEUE_MASK; + rxq->free_count--; + } + spin_unlock_irqrestore(&rxq->lock, flags); + /* If the pre-allocated buffer pool is dropping low, schedule to + * refill it */ + if (rxq->free_count <= RX_LOW_WATERMARK) + queue_work(priv->workqueue, &priv->rx_replenish); + + + /* 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)) + || (abs(rxq->write - rxq->read) > 7)) { + spin_lock_irqsave(&rxq->lock, flags); + rxq->need_update = 1; + spin_unlock_irqrestore(&rxq->lock, flags); + ret = iwl_rx_queue_update_write_ptr(priv, rxq); + } + + return ret; +} +EXPORT_SYMBOL(iwl_rx_queue_restock); + + +/** + * iwl_rx_replenish - Move all used packet from rx_used to rx_free + * + * When moving to rx_free an SKB is allocated for the slot. + * + * 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) +{ + struct iwl_rx_queue *rxq = &priv->rxq; + 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)) { + element = rxq->rx_used.next; + rxb = list_entry(element, struct iwl_rx_mem_buffer, list); + + /* Alloc a new receive buffer */ + rxb->skb = alloc_skb(priv->hw_params.rx_buf_size, + __GFP_NOWARN | GFP_ATOMIC); + if (!rxb->skb) { + if (net_ratelimit()) + printk(KERN_CRIT DRV_NAME + ": Can not allocate SKB buffers\n"); + /* We don't reschedule replenish work here -- we will + * call the restock method and if it still needs + * more buffers it will schedule replenish */ + break; + } + priv->alloc_rxb_skb++; + list_del(element); + + /* Get physical address of RB/SKB */ + rxb->dma_addr = + pci_map_single(priv->pci_dev, rxb->skb->data, + priv->hw_params.rx_buf_size, PCI_DMA_FROMDEVICE); + list_add_tail(&rxb->list, &rxq->rx_free); + rxq->free_count++; + } + spin_unlock_irqrestore(&rxq->lock, flags); +} +EXPORT_SYMBOL(iwl_rx_allocate); + +void iwl_rx_replenish(struct iwl_priv *priv) +{ + unsigned long flags; + + iwl_rx_allocate(priv); + + spin_lock_irqsave(&priv->lock, flags); + iwl_rx_queue_restock(priv); + spin_unlock_irqrestore(&priv->lock, flags); +} +EXPORT_SYMBOL(iwl_rx_replenish); + + +/* 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 + * non NULL it is unmapped and freed + */ +void iwl_rx_queue_free(struct iwl_priv *priv, struct iwl_rx_queue *rxq) +{ + int i; + for (i = 0; i < RX_QUEUE_SIZE + RX_FREE_BUFFERS; i++) { + if (rxq->pool[i].skb != NULL) { + pci_unmap_single(priv->pci_dev, + rxq->pool[i].dma_addr, + priv->hw_params.rx_buf_size, + PCI_DMA_FROMDEVICE); + dev_kfree_skb(rxq->pool[i].skb); + } + } + + pci_free_consistent(priv->pci_dev, 4 * RX_QUEUE_SIZE, rxq->bd, + rxq->dma_addr); + rxq->bd = NULL; +} +EXPORT_SYMBOL(iwl_rx_queue_free); + +int iwl_rx_queue_alloc(struct iwl_priv *priv) +{ + struct iwl_rx_queue *rxq = &priv->rxq; + struct pci_dev *dev = priv->pci_dev; + int i; + + spin_lock_init(&rxq->lock); + INIT_LIST_HEAD(&rxq->rx_free); + INIT_LIST_HEAD(&rxq->rx_used); + + /* Alloc the circular buffer of Read Buffer Descriptors (RBDs) */ + rxq->bd = pci_alloc_consistent(dev, 4 * RX_QUEUE_SIZE, &rxq->dma_addr); + if (!rxq->bd) + return -ENOMEM; + + /* Fill the rx_used queue with _all_ of the Rx buffers */ + for (i = 0; i < RX_FREE_BUFFERS + RX_QUEUE_SIZE; i++) + list_add_tail(&rxq->pool[i].list, &rxq->rx_used); + + /* 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->free_count = 0; + rxq->need_update = 0; + return 0; +} +EXPORT_SYMBOL(iwl_rx_queue_alloc); + +void iwl_rx_queue_reset(struct iwl_priv *priv, struct iwl_rx_queue *rxq) +{ + unsigned long flags; + int i; + spin_lock_irqsave(&rxq->lock, flags); + INIT_LIST_HEAD(&rxq->rx_free); + INIT_LIST_HEAD(&rxq->rx_used); + /* Fill the rx_used queue with _all_ of the Rx buffers */ + for (i = 0; i < RX_FREE_BUFFERS + RX_QUEUE_SIZE; i++) { + /* In the reset function, these buffers may have been allocated + * to an SKB, so we need to unmap and free potential storage */ + if (rxq->pool[i].skb != NULL) { + pci_unmap_single(priv->pci_dev, + rxq->pool[i].dma_addr, + priv->hw_params.rx_buf_size, + PCI_DMA_FROMDEVICE); + priv->alloc_rxb_skb--; + dev_kfree_skb(rxq->pool[i].skb); + rxq->pool[i].skb = NULL; + } + list_add_tail(&rxq->pool[i].list, &rxq->rx_used); + } + + /* 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->free_count = 0; + spin_unlock_irqrestore(&rxq->lock, flags); +} +EXPORT_SYMBOL(iwl_rx_queue_reset); + +int iwl_rx_init(struct iwl_priv *priv, struct iwl_rx_queue *rxq) +{ + int ret; + unsigned long flags; + unsigned int rb_size; + + 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 + rb_size = FH_RCSR_RX_CONFIG_REG_VAL_RB_SIZE_4K; + + /* Stop Rx DMA */ + iwl_write_direct32(priv, FH_MEM_RCSR_CHNL0_CONFIG_REG, 0); + + /* Reset driver's Rx queue write index */ + iwl_write_direct32(priv, FH_RSCSR_CHNL0_RBDCB_WPTR_REG, 0); + + /* Tell device where to find RBD circular buffer in DRAM */ + iwl_write_direct32(priv, FH_RSCSR_CHNL0_RBDCB_BASE_REG, + rxq->dma_addr >> 8); + + /* Tell device where in DRAM to update its Rx status */ + iwl_write_direct32(priv, FH_RSCSR_CHNL0_STTS_WPTR_REG, + (priv->shared_phys + priv->rb_closed_offset) >> 4); + + /* Enable Rx DMA, enable host interrupt, Rx buffer size 4k, 256 RBDs */ + iwl_write_direct32(priv, FH_MEM_RCSR_CHNL0_CONFIG_REG, + FH_RCSR_RX_CONFIG_CHNL_EN_ENABLE_VAL | + FH_RCSR_CHNL0_RX_CONFIG_IRQ_DEST_INT_HOST_VAL | + rb_size | + /* 0x10 << 4 | */ + (RX_QUEUE_SIZE_LOG << + FH_RCSR_RX_CONFIG_RBDCB_SIZE_BITSHIFT)); + + /* + * iwl_write32(priv,CSR_INT_COAL_REG,0); + */ + + iwl_release_nic_access(priv); + 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); + ret = iwl_poll_direct_bit(priv, FH_MEM_RSSR_RX_STATUS_REG, + (1 << 24), 1000); + if (ret < 0) + IWL_ERROR("Can't stop Rx DMA.\n"); + + iwl_release_nic_access(priv); + spin_unlock_irqrestore(&priv->lock, flags); + + return 0; +} +EXPORT_SYMBOL(iwl_rxq_stop); + +void iwl_rx_missed_beacon_notif(struct iwl_priv *priv, + struct iwl_rx_mem_buffer *rxb) + +{ + struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; + struct iwl4965_missed_beacon_notif *missed_beacon; + + missed_beacon = &pkt->u.missed_beacon; + if (le32_to_cpu(missed_beacon->consequtive_missed_beacons) > 5) { + IWL_DEBUG_CALIB("missed bcn cnsq %d totl %d rcd %d expctd %d\n", + le32_to_cpu(missed_beacon->consequtive_missed_beacons), + le32_to_cpu(missed_beacon->total_missed_becons), + le32_to_cpu(missed_beacon->num_recvd_beacons), + le32_to_cpu(missed_beacon->num_expected_beacons)); + if (!test_bit(STATUS_SCANNING, &priv->status)) + iwl_init_sensitivity(priv); + } +} +EXPORT_SYMBOL(iwl_rx_missed_beacon_notif); + +int iwl_rx_agg_start(struct iwl_priv *priv, const u8 *addr, int tid, u16 ssn) +{ + unsigned long flags; + int sta_id; + + sta_id = iwl_find_station(priv, addr); + if (sta_id == IWL_INVALID_STATION) + return -ENXIO; + + spin_lock_irqsave(&priv->sta_lock, flags); + priv->stations[sta_id].sta.station_flags_msk = 0; + priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_ADDBA_TID_MSK; + priv->stations[sta_id].sta.add_immediate_ba_tid = (u8)tid; + priv->stations[sta_id].sta.add_immediate_ba_ssn = cpu_to_le16(ssn); + priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK; + spin_unlock_irqrestore(&priv->sta_lock, flags); + + return iwl_send_add_sta(priv, &priv->stations[sta_id].sta, + CMD_ASYNC); +} +EXPORT_SYMBOL(iwl_rx_agg_start); + +int iwl_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); + if (sta_id == IWL_INVALID_STATION) + return -ENXIO; + + spin_lock_irqsave(&priv->sta_lock, flags); + priv->stations[sta_id].sta.station_flags_msk = 0; + priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_DELBA_TID_MSK; + priv->stations[sta_id].sta.remove_immediate_ba_tid = (u8)tid; + priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK; + spin_unlock_irqrestore(&priv->sta_lock, flags); + + return iwl_send_add_sta(priv, &priv->stations[sta_id].sta, + CMD_ASYNC); +} +EXPORT_SYMBOL(iwl_rx_agg_stop); + + +/* Calculate noise level, based on measurements during network silence just + * before arriving beacon. This measurement can be done only if we know + * exactly when to expect beacons, therefore only when we're associated. */ +static void iwl_rx_calc_noise(struct iwl_priv *priv) +{ + struct statistics_rx_non_phy *rx_info + = &(priv->statistics.rx.general); + int num_active_rx = 0; + int total_silence = 0; + int bcn_silence_a = + le32_to_cpu(rx_info->beacon_silence_rssi_a) & IN_BAND_FILTER; + int bcn_silence_b = + le32_to_cpu(rx_info->beacon_silence_rssi_b) & IN_BAND_FILTER; + int bcn_silence_c = + le32_to_cpu(rx_info->beacon_silence_rssi_c) & IN_BAND_FILTER; + + if (bcn_silence_a) { + total_silence += bcn_silence_a; + num_active_rx++; + } + if (bcn_silence_b) { + total_silence += bcn_silence_b; + num_active_rx++; + } + if (bcn_silence_c) { + total_silence += bcn_silence_c; + num_active_rx++; + } + + /* Average among active antennas */ + if (num_active_rx) + priv->last_rx_noise = (total_silence / num_active_rx) - 107; + else + priv->last_rx_noise = IWL_NOISE_MEAS_NOT_AVAILABLE; + + IWL_DEBUG_CALIB("inband silence a %u, b %u, c %u, dBm %d\n", + bcn_silence_a, bcn_silence_b, bcn_silence_c, + priv->last_rx_noise); +} + +#define REG_RECALIB_PERIOD (60) + +void iwl_rx_statistics(struct iwl_priv *priv, + struct iwl_rx_mem_buffer *rxb) +{ + int change; + struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; + + IWL_DEBUG_RX("Statistics notification received (%d vs %d).\n", + (int)sizeof(priv->statistics), pkt->len); + + change = ((priv->statistics.general.temperature != + pkt->u.stats.general.temperature) || + ((priv->statistics.flag & + STATISTICS_REPLY_FLG_FAT_MODE_MSK) != + (pkt->u.stats.flag & STATISTICS_REPLY_FLG_FAT_MODE_MSK))); + + memcpy(&priv->statistics, &pkt->u.stats, sizeof(priv->statistics)); + + set_bit(STATUS_STATISTICS, &priv->status); + + /* Reschedule the statistics timer to occur in + * REG_RECALIB_PERIOD seconds to ensure we get a + * thermal update even if the uCode doesn't give + * us one */ + mod_timer(&priv->statistics_periodic, jiffies + + msecs_to_jiffies(REG_RECALIB_PERIOD * 1000)); + + if (unlikely(!test_bit(STATUS_SCANNING, &priv->status)) && + (pkt->hdr.cmd == STATISTICS_NOTIFICATION)) { + iwl_rx_calc_noise(priv); + queue_work(priv->workqueue, &priv->run_time_calib_work); + } + + iwl_leds_background(priv); + + if (priv->cfg->ops->lib->temperature && change) + priv->cfg->ops->lib->temperature(priv); +} +EXPORT_SYMBOL(iwl_rx_statistics); + +#define PERFECT_RSSI (-20) /* dBm */ +#define WORST_RSSI (-95) /* dBm */ +#define RSSI_RANGE (PERFECT_RSSI - WORST_RSSI) + +/* Calculate an indication of rx signal quality (a percentage, not dBm!). + * See http://www.ces.clemson.edu/linux/signal_quality.shtml for info + * about formulas used below. */ +static int iwl_calc_sig_qual(int rssi_dbm, int noise_dbm) +{ + int sig_qual; + int degradation = PERFECT_RSSI - rssi_dbm; + + /* If we get a noise measurement, use signal-to-noise ratio (SNR) + * as indicator; formula is (signal dbm - noise dbm). + * SNR at or above 40 is a great signal (100%). + * Below that, scale to fit SNR of 0 - 40 dB within 0 - 100% indicator. + * Weakest usable signal is usually 10 - 15 dB SNR. */ + if (noise_dbm) { + if (rssi_dbm - noise_dbm >= 40) + return 100; + else if (rssi_dbm < noise_dbm) + return 0; + sig_qual = ((rssi_dbm - noise_dbm) * 5) / 2; + + /* Else use just the signal level. + * This formula is a least squares fit of data points collected and + * compared with a reference system that had a percentage (%) display + * for signal quality. */ + } else + sig_qual = (100 * (RSSI_RANGE * RSSI_RANGE) - degradation * + (15 * RSSI_RANGE + 62 * degradation)) / + (RSSI_RANGE * RSSI_RANGE); + + if (sig_qual > 100) + sig_qual = 100; + else if (sig_qual < 1) + sig_qual = 0; + + return sig_qual; +} + +#ifdef CONFIG_IWLWIFI_DEBUG + +/** + * iwl_dbg_report_frame - dump frame to syslog during debug sessions + * + * You may hack this function to show different aspects of received frames, + * including selective frame dumps. + * group100 parameter selects whether to show 1 out of 100 good frames. + * + * TODO: This was originally written for 3945, need to audit for + * proper operation with 4965. + */ +static void iwl_dbg_report_frame(struct iwl_priv *priv, + struct iwl_rx_packet *pkt, + struct ieee80211_hdr *header, int group100) +{ + u32 to_us; + u32 print_summary = 0; + u32 print_dump = 0; /* set to 1 to dump all frames' contents */ + u32 hundred = 0; + u32 dataframe = 0; + __le16 fc; + u16 seq_ctl; + u16 channel; + u16 phy_flags; + int rate_sym; + u16 length; + u16 status; + u16 bcn_tmr; + u32 tsf_low; + u64 tsf; + u8 rssi; + u8 agc; + u16 sig_avg; + u16 noise_diff; + struct iwl4965_rx_frame_stats *rx_stats = IWL_RX_STATS(pkt); + struct iwl4965_rx_frame_hdr *rx_hdr = IWL_RX_HDR(pkt); + struct iwl4965_rx_frame_end *rx_end = IWL_RX_END(pkt); + u8 *data = IWL_RX_DATA(pkt); + + if (likely(!(priv->debug_level & IWL_DL_RX))) + return; + + /* MAC header */ + fc = header->frame_control; + seq_ctl = le16_to_cpu(header->seq_ctrl); + + /* metadata */ + channel = le16_to_cpu(rx_hdr->channel); + phy_flags = le16_to_cpu(rx_hdr->phy_flags); + rate_sym = rx_hdr->rate; + length = le16_to_cpu(rx_hdr->len); + + /* end-of-frame status and timestamp */ + status = le32_to_cpu(rx_end->status); + bcn_tmr = le32_to_cpu(rx_end->beacon_timestamp); + tsf_low = le64_to_cpu(rx_end->timestamp) & 0x0ffffffff; + tsf = le64_to_cpu(rx_end->timestamp); + + /* signal statistics */ + rssi = rx_stats->rssi; + agc = rx_stats->agc; + sig_avg = le16_to_cpu(rx_stats->sig_avg); + noise_diff = le16_to_cpu(rx_stats->noise_diff); + + to_us = !compare_ether_addr(header->addr1, priv->mac_addr); + + /* if data frame is to us and all is good, + * (optionally) print summary for only 1 out of every 100 */ + if (to_us && (fc & ~cpu_to_le16(IEEE80211_FCTL_PROTECTED)) == + cpu_to_le16(IEEE80211_FCTL_FROMDS | IEEE80211_FTYPE_DATA)) { + dataframe = 1; + if (!group100) + print_summary = 1; /* print each frame */ + else if (priv->framecnt_to_us < 100) { + priv->framecnt_to_us++; + print_summary = 0; + } else { + priv->framecnt_to_us = 0; + print_summary = 1; + hundred = 1; + } + } else { + /* print summary for all other frames */ + print_summary = 1; + } + + if (print_summary) { + char *title; + int rate_idx; + u32 bitrate; + + if (hundred) + title = "100Frames"; + else if (ieee80211_has_retry(fc)) + title = "Retry"; + else if (ieee80211_is_assoc_resp(fc)) + title = "AscRsp"; + else if (ieee80211_is_reassoc_resp(fc)) + title = "RasRsp"; + else if (ieee80211_is_probe_resp(fc)) { + title = "PrbRsp"; + print_dump = 1; /* dump frame contents */ + } else if (ieee80211_is_beacon(fc)) { + title = "Beacon"; + print_dump = 1; /* dump frame contents */ + } else if (ieee80211_is_atim(fc)) + title = "ATIM"; + else if (ieee80211_is_auth(fc)) + title = "Auth"; + else if (ieee80211_is_deauth(fc)) + title = "DeAuth"; + else if (ieee80211_is_disassoc(fc)) + title = "DisAssoc"; + else + title = "Frame"; + + rate_idx = iwl_hwrate_to_plcp_idx(rate_sym); + if (unlikely(rate_idx == -1)) + bitrate = 0; + else + bitrate = iwl_rates[rate_idx].ieee / 2; + + /* print frame summary. + * MAC addresses show just the last byte (for brevity), + * but you can hack it to show more, if you'd like to. */ + if (dataframe) + IWL_DEBUG_RX("%s: mhd=0x%04x, dst=0x%02x, " + "len=%u, rssi=%d, chnl=%d, rate=%u, \n", + title, le16_to_cpu(fc), header->addr1[5], + length, rssi, channel, bitrate); + else { + /* src/dst addresses assume managed mode */ + IWL_DEBUG_RX("%s: 0x%04x, dst=0x%02x, " + "src=0x%02x, rssi=%u, tim=%lu usec, " + "phy=0x%02x, chnl=%d\n", + title, le16_to_cpu(fc), header->addr1[5], + header->addr3[5], rssi, + tsf_low - priv->scan_start_tsf, + phy_flags, channel); + } + } + if (print_dump) + iwl_print_hex_dump(priv, IWL_DL_RX, data, length); +} +#else +static inline void iwl_dbg_report_frame(struct iwl_priv *priv, + struct iwl_rx_packet *pkt, + struct ieee80211_hdr *header, + int group100) +{ +} +#endif + +static void iwl_add_radiotap(struct iwl_priv *priv, + struct sk_buff *skb, + struct iwl4965_rx_phy_res *rx_start, + struct ieee80211_rx_status *stats, + u32 ampdu_status) +{ + s8 signal = stats->signal; + s8 noise = 0; + int rate = stats->rate_idx; + u64 tsf = stats->mactime; + __le16 antenna; + __le16 phy_flags_hw = rx_start->phy_flags; + struct iwl4965_rt_rx_hdr { + struct ieee80211_radiotap_header rt_hdr; + __le64 rt_tsf; /* TSF */ + u8 rt_flags; /* radiotap packet flags */ + u8 rt_rate; /* rate in 500kb/s */ + __le16 rt_channelMHz; /* channel in MHz */ + __le16 rt_chbitmask; /* channel bitfield */ + s8 rt_dbmsignal; /* signal in dBm, kluged to signed */ + s8 rt_dbmnoise; + u8 rt_antenna; /* antenna number */ + } __attribute__ ((packed)) *iwl4965_rt; + + /* TODO: We won't have enough headroom for HT frames. Fix it later. */ + if (skb_headroom(skb) < sizeof(*iwl4965_rt)) { + if (net_ratelimit()) + printk(KERN_ERR "not enough headroom [%d] for " + "radiotap head [%zd]\n", + skb_headroom(skb), sizeof(*iwl4965_rt)); + return; + } + + /* put radiotap header in front of 802.11 header and data */ + iwl4965_rt = (void *)skb_push(skb, sizeof(*iwl4965_rt)); + + /* initialise radiotap header */ + iwl4965_rt->rt_hdr.it_version = PKTHDR_RADIOTAP_VERSION; + iwl4965_rt->rt_hdr.it_pad = 0; + + /* total header + data */ + put_unaligned_le16(sizeof(*iwl4965_rt), &iwl4965_rt->rt_hdr.it_len); + + /* Indicate all the fields we add to the radiotap header */ + put_unaligned_le32((1 << IEEE80211_RADIOTAP_TSFT) | + (1 << IEEE80211_RADIOTAP_FLAGS) | + (1 << IEEE80211_RADIOTAP_RATE) | + (1 << IEEE80211_RADIOTAP_CHANNEL) | + (1 << IEEE80211_RADIOTAP_DBM_ANTSIGNAL) | + (1 << IEEE80211_RADIOTAP_DBM_ANTNOISE) | + (1 << IEEE80211_RADIOTAP_ANTENNA), + &(iwl4965_rt->rt_hdr.it_present)); + + /* Zero the flags, we'll add to them as we go */ + iwl4965_rt->rt_flags = 0; + + put_unaligned_le64(tsf, &iwl4965_rt->rt_tsf); + + iwl4965_rt->rt_dbmsignal = signal; + iwl4965_rt->rt_dbmnoise = noise; + + /* Convert the channel frequency and set the flags */ + put_unaligned(cpu_to_le16(stats->freq), &iwl4965_rt->rt_channelMHz); + if (!(phy_flags_hw & RX_RES_PHY_FLAGS_BAND_24_MSK)) + put_unaligned_le16(IEEE80211_CHAN_OFDM | IEEE80211_CHAN_5GHZ, + &iwl4965_rt->rt_chbitmask); + else if (phy_flags_hw & RX_RES_PHY_FLAGS_MOD_CCK_MSK) + put_unaligned_le16(IEEE80211_CHAN_CCK | IEEE80211_CHAN_2GHZ, + &iwl4965_rt->rt_chbitmask); + else /* 802.11g */ + put_unaligned_le16(IEEE80211_CHAN_OFDM | IEEE80211_CHAN_2GHZ, + &iwl4965_rt->rt_chbitmask); + + if (rate == -1) + iwl4965_rt->rt_rate = 0; + else + iwl4965_rt->rt_rate = iwl_rates[rate].ieee; + + /* + * "antenna number" + * + * It seems that the antenna field in the phy flags value + * is actually a bitfield. This is undefined by radiotap, + * it wants an actual antenna number but I always get "7" + * for most legacy frames I receive indicating that the + * same frame was received on all three RX chains. + * + * I think this field should be removed in favour of a + * new 802.11n radiotap field "RX chains" that is defined + * as a bitmask. + */ + antenna = phy_flags_hw & RX_RES_PHY_FLAGS_ANTENNA_MSK; + iwl4965_rt->rt_antenna = le16_to_cpu(antenna) >> 4; + + /* set the preamble flag if appropriate */ + if (phy_flags_hw & RX_RES_PHY_FLAGS_SHORT_PREAMBLE_MSK) + iwl4965_rt->rt_flags |= IEEE80211_RADIOTAP_F_SHORTPRE; + + stats->flag |= RX_FLAG_RADIOTAP; +} + +static void iwl_update_rx_stats(struct iwl_priv *priv, u16 fc, u16 len) +{ + /* 0 - mgmt, 1 - cnt, 2 - data */ + int idx = (fc & IEEE80211_FCTL_FTYPE) >> 2; + priv->rx_stats[idx].cnt++; + priv->rx_stats[idx].bytes += len; +} + +/* + * returns non-zero if packet should be dropped + */ +static int iwl_set_decrypted_flag(struct iwl_priv *priv, + struct ieee80211_hdr *hdr, + u32 decrypt_res, + struct ieee80211_rx_status *stats) +{ + u16 fc = le16_to_cpu(hdr->frame_control); + + if (priv->active_rxon.filter_flags & RXON_FILTER_DIS_DECRYPT_MSK) + return 0; + + if (!(fc & IEEE80211_FCTL_PROTECTED)) + return 0; + + IWL_DEBUG_RX("decrypt_res:0x%x\n", decrypt_res); + switch (decrypt_res & RX_RES_STATUS_SEC_TYPE_MSK) { + case RX_RES_STATUS_SEC_TYPE_TKIP: + /* The uCode has got a bad phase 1 Key, pushes the packet. + * Decryption will be done in SW. */ + if ((decrypt_res & RX_RES_STATUS_DECRYPT_TYPE_MSK) == + RX_RES_STATUS_BAD_KEY_TTAK) + break; + + case RX_RES_STATUS_SEC_TYPE_WEP: + if ((decrypt_res & RX_RES_STATUS_DECRYPT_TYPE_MSK) == + RX_RES_STATUS_BAD_ICV_MIC) { + /* bad ICV, the packet is destroyed since the + * decryption is inplace, drop it */ + IWL_DEBUG_RX("Packet destroyed\n"); + return -1; + } + case RX_RES_STATUS_SEC_TYPE_CCMP: + if ((decrypt_res & RX_RES_STATUS_DECRYPT_TYPE_MSK) == + RX_RES_STATUS_DECRYPT_OK) { + IWL_DEBUG_RX("hw decrypt successfully!!!\n"); + stats->flag |= RX_FLAG_DECRYPTED; + } + break; + + default: + break; + } + return 0; +} + +static u32 iwl_translate_rx_status(struct iwl_priv *priv, u32 decrypt_in) +{ + u32 decrypt_out = 0; + + if ((decrypt_in & RX_RES_STATUS_STATION_FOUND) == + RX_RES_STATUS_STATION_FOUND) + decrypt_out |= (RX_RES_STATUS_STATION_FOUND | + RX_RES_STATUS_NO_STATION_INFO_MISMATCH); + + decrypt_out |= (decrypt_in & RX_RES_STATUS_SEC_TYPE_MSK); + + /* packet was not encrypted */ + if ((decrypt_in & RX_RES_STATUS_SEC_TYPE_MSK) == + RX_RES_STATUS_SEC_TYPE_NONE) + return decrypt_out; + + /* packet was encrypted with unknown alg */ + if ((decrypt_in & RX_RES_STATUS_SEC_TYPE_MSK) == + RX_RES_STATUS_SEC_TYPE_ERR) + return decrypt_out; + + /* decryption was not done in HW */ + if ((decrypt_in & RX_MPDU_RES_STATUS_DEC_DONE_MSK) != + RX_MPDU_RES_STATUS_DEC_DONE_MSK) + return decrypt_out; + + switch (decrypt_in & RX_RES_STATUS_SEC_TYPE_MSK) { + + case RX_RES_STATUS_SEC_TYPE_CCMP: + /* alg is CCM: check MIC only */ + if (!(decrypt_in & RX_MPDU_RES_STATUS_MIC_OK)) + /* Bad MIC */ + decrypt_out |= RX_RES_STATUS_BAD_ICV_MIC; + else + decrypt_out |= RX_RES_STATUS_DECRYPT_OK; + + break; + + case RX_RES_STATUS_SEC_TYPE_TKIP: + if (!(decrypt_in & RX_MPDU_RES_STATUS_TTAK_OK)) { + /* Bad TTAK */ + decrypt_out |= RX_RES_STATUS_BAD_KEY_TTAK; + break; + } + /* fall through if TTAK OK */ + default: + if (!(decrypt_in & RX_MPDU_RES_STATUS_ICV_OK)) + decrypt_out |= RX_RES_STATUS_BAD_ICV_MIC; + else + decrypt_out |= RX_RES_STATUS_DECRYPT_OK; + break; + }; + + IWL_DEBUG_RX("decrypt_in:0x%x decrypt_out = 0x%x\n", + decrypt_in, decrypt_out); + + return decrypt_out; +} + +static void iwl_pass_packet_to_mac80211(struct iwl_priv *priv, + int include_phy, + struct iwl_rx_mem_buffer *rxb, + struct ieee80211_rx_status *stats) +{ + struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; + struct iwl4965_rx_phy_res *rx_start = (include_phy) ? + (struct iwl4965_rx_phy_res *)&(pkt->u.raw[0]) : NULL; + struct ieee80211_hdr *hdr; + u16 len; + __le32 *rx_end; + unsigned int skblen; + u32 ampdu_status; + u32 ampdu_status_legacy; + + if (!include_phy && priv->last_phy_res[0]) + rx_start = (struct iwl4965_rx_phy_res *)&priv->last_phy_res[1]; + + if (!rx_start) { + IWL_ERROR("MPDU frame without a PHY data\n"); + return; + } + if (include_phy) { + hdr = (struct ieee80211_hdr *)((u8 *) &rx_start[1] + + rx_start->cfg_phy_cnt); + + len = le16_to_cpu(rx_start->byte_count); + + rx_end = (__le32 *) ((u8 *) &pkt->u.raw[0] + + sizeof(struct iwl4965_rx_phy_res) + + rx_start->cfg_phy_cnt + len); + + } else { + struct iwl4965_rx_mpdu_res_start *amsdu = + (struct iwl4965_rx_mpdu_res_start *)pkt->u.raw; + + hdr = (struct ieee80211_hdr *)(pkt->u.raw + + sizeof(struct iwl4965_rx_mpdu_res_start)); + len = le16_to_cpu(amsdu->byte_count); + rx_start->byte_count = amsdu->byte_count; + rx_end = (__le32 *) (((u8 *) hdr) + len); + } + + ampdu_status = le32_to_cpu(*rx_end); + skblen = ((u8 *) rx_end - (u8 *) &pkt->u.raw[0]) + sizeof(u32); + + if (!include_phy) { + /* New status scheme, need to translate */ + ampdu_status_legacy = ampdu_status; + ampdu_status = iwl_translate_rx_status(priv, ampdu_status); + } + + /* start from MAC */ + skb_reserve(rxb->skb, (void *)hdr - (void *)pkt); + skb_put(rxb->skb, len); /* end where data ends */ + + /* We only process data packets if the interface is open */ + if (unlikely(!priv->is_open)) { + IWL_DEBUG_DROP_LIMIT + ("Dropping packet while interface is not open.\n"); + return; + } + + hdr = (struct ieee80211_hdr *)rxb->skb->data; + + /* in case of HW accelerated crypto and bad decryption, drop */ + if (!priv->hw_params.sw_crypto && + iwl_set_decrypted_flag(priv, hdr, ampdu_status, stats)) + return; + + if (priv->add_radiotap) + iwl_add_radiotap(priv, rxb->skb, rx_start, stats, ampdu_status); + + iwl_update_rx_stats(priv, le16_to_cpu(hdr->frame_control), len); + ieee80211_rx_irqsafe(priv->hw, rxb->skb, stats); + priv->alloc_rxb_skb--; + rxb->skb = NULL; +} + +/* Calc max signal level (dBm) among 3 possible receivers */ +static int iwl_calc_rssi(struct iwl_priv *priv, + struct iwl4965_rx_phy_res *rx_resp) +{ + /* data from PHY/DSP regarding signal strength, etc., + * contents are always there, not configurable by host. */ + struct iwl4965_rx_non_cfg_phy *ncphy = + (struct iwl4965_rx_non_cfg_phy *)rx_resp->non_cfg_phy; + u32 agc = (le16_to_cpu(ncphy->agc_info) & IWL_AGC_DB_MASK) + >> IWL_AGC_DB_POS; + + u32 valid_antennae = + (le16_to_cpu(rx_resp->phy_flags) & RX_PHY_FLAGS_ANTENNAE_MASK) + >> RX_PHY_FLAGS_ANTENNAE_OFFSET; + u8 max_rssi = 0; + u32 i; + + /* Find max rssi among 3 possible receivers. + * These values are measured by the digital signal processor (DSP). + * They should stay fairly constant even as the signal strength varies, + * if the radio's automatic gain control (AGC) is working right. + * AGC value (see below) will provide the "interesting" info. */ + for (i = 0; i < 3; i++) + if (valid_antennae & (1 << i)) + max_rssi = max(ncphy->rssi_info[i << 1], max_rssi); + + IWL_DEBUG_STATS("Rssi In A %d B %d C %d Max %d AGC dB %d\n", + ncphy->rssi_info[0], ncphy->rssi_info[2], ncphy->rssi_info[4], + max_rssi, agc); + + /* dBm = max_rssi dB - agc dB - constant. + * Higher AGC (higher radio gain) means lower signal. */ + return max_rssi - agc - IWL_RSSI_OFFSET; +} + +static void iwl_sta_modify_ps_wake(struct iwl_priv *priv, int sta_id) +{ + unsigned long flags; + + spin_lock_irqsave(&priv->sta_lock, flags); + priv->stations[sta_id].sta.station_flags &= ~STA_FLG_PWR_SAVE_MSK; + priv->stations[sta_id].sta.station_flags_msk = STA_FLG_PWR_SAVE_MSK; + priv->stations[sta_id].sta.sta.modify_mask = 0; + priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK; + spin_unlock_irqrestore(&priv->sta_lock, flags); + + iwl_send_add_sta(priv, &priv->stations[sta_id].sta, CMD_ASYNC); +} + +static 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); + + if (sta_id != IWL_INVALID_STATION) { + u8 sta_awake = priv->stations[sta_id]. + ps_status == STA_PS_STATUS_WAKE; + + if (sta_awake && ps_bit) + priv->stations[sta_id].ps_status = STA_PS_STATUS_SLEEP; + else if (!sta_awake && !ps_bit) { + iwl_sta_modify_ps_wake(priv, sta_id); + priv->stations[sta_id].ps_status = STA_PS_STATUS_WAKE; + } + } +} + +/* This is necessary only for a number of statistics, see the caller. */ +static int iwl_is_network_packet(struct iwl_priv *priv, + struct ieee80211_hdr *header) +{ + /* Filter incoming packets to determine if they are targeted toward + * this network, discarding packets coming from ourselves */ + switch (priv->iw_mode) { + case IEEE80211_IF_TYPE_IBSS: /* Header: Dest. | Source | BSSID */ + /* packets to our IBSS update information */ + return !compare_ether_addr(header->addr3, priv->bssid); + case IEEE80211_IF_TYPE_STA: /* Header: Dest. | AP{BSSID} | Source */ + /* packets to our IBSS update information */ + return !compare_ether_addr(header->addr2, priv->bssid); + default: + return 1; + } +} + +/* Called for REPLY_RX (legacy ABG frames), or + * REPLY_RX_MPDU_CMD (HT high-throughput N frames). */ +void iwl_rx_reply_rx(struct iwl_priv *priv, + struct iwl_rx_mem_buffer *rxb) +{ + struct ieee80211_hdr *header; + struct ieee80211_rx_status rx_status; + struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; + /* Use phy data (Rx signal strength, etc.) contained within + * this rx packet for legacy frames, + * or phy data cached from REPLY_RX_PHY_CMD for HT frames. */ + int include_phy = (pkt->hdr.cmd == REPLY_RX); + struct iwl4965_rx_phy_res *rx_start = (include_phy) ? + (struct iwl4965_rx_phy_res *)&(pkt->u.raw[0]) : + (struct iwl4965_rx_phy_res *)&priv->last_phy_res[1]; + __le32 *rx_end; + unsigned int len = 0; + u16 fc; + u8 network_packet; + + rx_status.mactime = le64_to_cpu(rx_start->timestamp); + rx_status.freq = + ieee80211_channel_to_frequency(le16_to_cpu(rx_start->channel)); + rx_status.band = (rx_start->phy_flags & RX_RES_PHY_FLAGS_BAND_24_MSK) ? + IEEE80211_BAND_2GHZ : IEEE80211_BAND_5GHZ; + rx_status.rate_idx = + iwl_hwrate_to_plcp_idx(le32_to_cpu(rx_start->rate_n_flags)); + if (rx_status.band == IEEE80211_BAND_5GHZ) + rx_status.rate_idx -= IWL_FIRST_OFDM_RATE; + + rx_status.antenna = 0; + rx_status.flag = 0; + rx_status.flag |= RX_FLAG_TSFT; + + if ((unlikely(rx_start->cfg_phy_cnt > 20))) { + IWL_DEBUG_DROP("dsp size out of range [0,20]: %d/n", + rx_start->cfg_phy_cnt); + return; + } + + if (!include_phy) { + if (priv->last_phy_res[0]) + rx_start = (struct iwl4965_rx_phy_res *) + &priv->last_phy_res[1]; + else + rx_start = NULL; + } + + if (!rx_start) { + IWL_ERROR("MPDU frame without a PHY data\n"); + return; + } + + if (include_phy) { + header = (struct ieee80211_hdr *)((u8 *) &rx_start[1] + + rx_start->cfg_phy_cnt); + + len = le16_to_cpu(rx_start->byte_count); + rx_end = (__le32 *)(pkt->u.raw + rx_start->cfg_phy_cnt + + sizeof(struct iwl4965_rx_phy_res) + len); + } else { + struct iwl4965_rx_mpdu_res_start *amsdu = + (struct iwl4965_rx_mpdu_res_start *)pkt->u.raw; + + header = (void *)(pkt->u.raw + + sizeof(struct iwl4965_rx_mpdu_res_start)); + len = le16_to_cpu(amsdu->byte_count); + rx_end = (__le32 *) (pkt->u.raw + + sizeof(struct iwl4965_rx_mpdu_res_start) + len); + } + + if (!(*rx_end & RX_RES_STATUS_NO_CRC32_ERROR) || + !(*rx_end & RX_RES_STATUS_NO_RXE_OVERFLOW)) { + IWL_DEBUG_RX("Bad CRC or FIFO: 0x%08X.\n", + le32_to_cpu(*rx_end)); + return; + } + + priv->ucode_beacon_time = le32_to_cpu(rx_start->beacon_time_stamp); + + /* Find max signal strength (dBm) among 3 antenna/receiver chains */ + rx_status.signal = iwl_calc_rssi(priv, rx_start); + + /* Meaningful noise values are available only from beacon statistics, + * which are gathered only when associated, and indicate noise + * only for the associated network channel ... + * Ignore these noise values while scanning (other channels) */ + if (iwl_is_associated(priv) && + !test_bit(STATUS_SCANNING, &priv->status)) { + rx_status.noise = priv->last_rx_noise; + rx_status.qual = iwl_calc_sig_qual(rx_status.signal, + rx_status.noise); + } else { + rx_status.noise = IWL_NOISE_MEAS_NOT_AVAILABLE; + rx_status.qual = iwl_calc_sig_qual(rx_status.signal, 0); + } + + /* Reset beacon noise level if not associated. */ + if (!iwl_is_associated(priv)) + priv->last_rx_noise = IWL_NOISE_MEAS_NOT_AVAILABLE; + + /* Set "1" to report good data frames in groups of 100 */ + /* FIXME: need to optimze the call: */ + iwl_dbg_report_frame(priv, pkt, header, 1); + + IWL_DEBUG_STATS_LIMIT("Rssi %d, noise %d, qual %d, TSF %llu\n", + rx_status.signal, rx_status.noise, rx_status.signal, + (unsigned long long)rx_status.mactime); + + /* Take shortcut when only in monitor mode */ + if (priv->iw_mode == IEEE80211_IF_TYPE_MNTR) { + 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; + priv->last_beacon_time = priv->ucode_beacon_time; + priv->last_tsf = le64_to_cpu(rx_start->timestamp); + } + + fc = le16_to_cpu(header->frame_control); + switch (fc & IEEE80211_FCTL_FTYPE) { + case IEEE80211_FTYPE_MGMT: + case IEEE80211_FTYPE_DATA: + if (priv->iw_mode == IEEE80211_IF_TYPE_AP) + iwl_update_ps_mode(priv, fc & IEEE80211_FCTL_PM, + header->addr2); + /* fall through */ + default: + iwl_pass_packet_to_mac80211(priv, include_phy, rxb, + &rx_status); + break; + + } +} +EXPORT_SYMBOL(iwl_rx_reply_rx); + +/* Cache phy data (Rx signal strength, etc) for HT frame (REPLY_RX_PHY_CMD). + * This will be used later in iwl_rx_reply_rx() for REPLY_RX_MPDU_CMD. */ +void iwl_rx_reply_rx_phy(struct iwl_priv *priv, + struct iwl_rx_mem_buffer *rxb) +{ + struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; + priv->last_phy_res[0] = 1; + memcpy(&priv->last_phy_res[1], &(pkt->u.raw[0]), + sizeof(struct iwl4965_rx_phy_res)); +} +EXPORT_SYMBOL(iwl_rx_reply_rx_phy); diff --git a/drivers/net/wireless/iwlwifi/iwl-scan.c b/drivers/net/wireless/iwlwifi/iwl-scan.c new file mode 100644 index 000000000000..efc750d2fc5c --- /dev/null +++ b/drivers/net/wireless/iwlwifi/iwl-scan.c @@ -0,0 +1,931 @@ +/****************************************************************************** + * + * GPL LICENSE SUMMARY + * + * Copyright(c) 2008 Intel Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, + * USA + * + * The full GNU General Public License is included in this distribution + * in the file called LICENSE.GPL. + * + * Contact Information: + * Tomas Winkler <tomas.winkler@intel.com> + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + *****************************************************************************/ +#include <net/mac80211.h> +#include <linux/etherdevice.h> + +#include "iwl-eeprom.h" +#include "iwl-dev.h" +#include "iwl-core.h" +#include "iwl-sta.h" +#include "iwl-io.h" +#include "iwl-helpers.h" + +/* For active scan, listen ACTIVE_DWELL_TIME (msec) on each channel after + * sending probe req. This should be set long enough to hear probe responses + * from more than one AP. */ +#define IWL_ACTIVE_DWELL_TIME_24 (30) /* all times in msec */ +#define IWL_ACTIVE_DWELL_TIME_52 (20) + +#define IWL_ACTIVE_DWELL_FACTOR_24GHZ (3) +#define IWL_ACTIVE_DWELL_FACTOR_52GHZ (2) + +/* For faster active scanning, scan will move to the next channel if fewer than + * PLCP_QUIET_THRESH packets are heard on this channel within + * ACTIVE_QUIET_TIME after sending probe request. This shortens the dwell + * time if it's a quiet channel (nothing responded to our probe, and there's + * no other traffic). + * Disable "quiet" feature by setting PLCP_QUIET_THRESH to 0. */ +#define IWL_PLCP_QUIET_THRESH __constant_cpu_to_le16(1) /* packets */ +#define IWL_ACTIVE_QUIET_TIME __constant_cpu_to_le16(10) /* msec */ + +/* For passive scan, listen PASSIVE_DWELL_TIME (msec) on each channel. + * Must be set longer than active dwell time. + * For the most reliable scan, set > AP beacon interval (typically 100msec). */ +#define IWL_PASSIVE_DWELL_TIME_24 (20) /* all times in msec */ +#define IWL_PASSIVE_DWELL_TIME_52 (10) +#define IWL_PASSIVE_DWELL_BASE (100) +#define IWL_CHANNEL_TUNE_TIME 5 + +#define IWL_SCAN_PROBE_MASK(n) cpu_to_le32((BIT(n) | (BIT(n) - BIT(1)))) + + +static int scan_tx_ant[3] = { + RATE_MCS_ANT_A_MSK, RATE_MCS_ANT_B_MSK, RATE_MCS_ANT_C_MSK +}; + + + +static int iwl_is_empty_essid(const char *essid, int essid_len) +{ + /* Single white space is for Linksys APs */ + if (essid_len == 1 && essid[0] == ' ') + return 1; + + /* Otherwise, if the entire essid is 0, we assume it is hidden */ + while (essid_len) { + essid_len--; + if (essid[essid_len] != '\0') + return 0; + } + + return 1; +} + + + +const char *iwl_escape_essid(const char *essid, u8 essid_len) +{ + static char escaped[IW_ESSID_MAX_SIZE * 2 + 1]; + const char *s = essid; + char *d = escaped; + + if (iwl_is_empty_essid(essid, essid_len)) { + memcpy(escaped, "<hidden>", sizeof("<hidden>")); + return escaped; + } + + essid_len = min(essid_len, (u8) IW_ESSID_MAX_SIZE); + while (essid_len--) { + if (*s == '\0') { + *d++ = '\\'; + *d++ = '0'; + s++; + } else + *d++ = *s++; + } + *d = '\0'; + return escaped; +} +EXPORT_SYMBOL(iwl_escape_essid); + +/** + * iwl_scan_cancel - Cancel any currently executing HW scan + * + * NOTE: priv->mutex is not required before calling this function + */ +int iwl_scan_cancel(struct iwl_priv *priv) +{ + if (!test_bit(STATUS_SCAN_HW, &priv->status)) { + clear_bit(STATUS_SCANNING, &priv->status); + return 0; + } + + if (test_bit(STATUS_SCANNING, &priv->status)) { + if (!test_bit(STATUS_SCAN_ABORTING, &priv->status)) { + IWL_DEBUG_SCAN("Queuing scan abort.\n"); + set_bit(STATUS_SCAN_ABORTING, &priv->status); + queue_work(priv->workqueue, &priv->abort_scan); + + } else + IWL_DEBUG_SCAN("Scan abort already in progress.\n"); + + return test_bit(STATUS_SCANNING, &priv->status); + } + + return 0; +} +EXPORT_SYMBOL(iwl_scan_cancel); +/** + * iwl_scan_cancel_timeout - Cancel any currently executing HW scan + * @ms: amount of time to wait (in milliseconds) for scan to abort + * + * NOTE: priv->mutex must be held before calling this function + */ +int iwl_scan_cancel_timeout(struct iwl_priv *priv, unsigned long ms) +{ + unsigned long now = jiffies; + int ret; + + ret = iwl_scan_cancel(priv); + if (ret && ms) { + mutex_unlock(&priv->mutex); + while (!time_after(jiffies, now + msecs_to_jiffies(ms)) && + test_bit(STATUS_SCANNING, &priv->status)) + msleep(1); + mutex_lock(&priv->mutex); + + return test_bit(STATUS_SCANNING, &priv->status); + } + + return ret; +} +EXPORT_SYMBOL(iwl_scan_cancel_timeout); + +static int iwl_send_scan_abort(struct iwl_priv *priv) +{ + int ret = 0; + struct iwl_rx_packet *res; + struct iwl_host_cmd cmd = { + .id = REPLY_SCAN_ABORT_CMD, + .meta.flags = CMD_WANT_SKB, + }; + + /* If there isn't a scan actively going on in the hardware + * then we are in between scan bands and not actually + * actively scanning, so don't send the abort command */ + if (!test_bit(STATUS_SCAN_HW, &priv->status)) { + clear_bit(STATUS_SCAN_ABORTING, &priv->status); + return 0; + } + + ret = iwl_send_cmd_sync(priv, &cmd); + if (ret) { + clear_bit(STATUS_SCAN_ABORTING, &priv->status); + return ret; + } + + res = (struct iwl_rx_packet *)cmd.meta.u.skb->data; + if (res->u.status != CAN_ABORT_STATUS) { + /* The scan abort will return 1 for success or + * 2 for "failure". A failure condition can be + * due to simply not being in an active scan which + * can occur if we send the scan abort before we + * the microcode has notified us that a scan is + * completed. */ + IWL_DEBUG_INFO("SCAN_ABORT returned %d.\n", res->u.status); + clear_bit(STATUS_SCAN_ABORTING, &priv->status); + clear_bit(STATUS_SCAN_HW, &priv->status); + } + + dev_kfree_skb_any(cmd.meta.u.skb); + + return ret; +} + + +/* Service response to REPLY_SCAN_CMD (0x80) */ +static void iwl_rx_reply_scan(struct iwl_priv *priv, + struct iwl_rx_mem_buffer *rxb) +{ +#ifdef CONFIG_IWLWIFI_DEBUG + struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; + struct iwl_scanreq_notification *notif = + (struct iwl_scanreq_notification *)pkt->u.raw; + + IWL_DEBUG_RX("Scan request status = 0x%x\n", notif->status); +#endif +} + +/* Service SCAN_START_NOTIFICATION (0x82) */ +static void iwl_rx_scan_start_notif(struct iwl_priv *priv, + struct iwl_rx_mem_buffer *rxb) +{ + struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; + struct iwl_scanstart_notification *notif = + (struct iwl_scanstart_notification *)pkt->u.raw; + priv->scan_start_tsf = le32_to_cpu(notif->tsf_low); + IWL_DEBUG_SCAN("Scan start: " + "%d [802.11%s] " + "(TSF: 0x%08X:%08X) - %d (beacon timer %u)\n", + notif->channel, + notif->band ? "bg" : "a", + le32_to_cpu(notif->tsf_high), + le32_to_cpu(notif->tsf_low), + notif->status, notif->beacon_timer); +} + +/* Service SCAN_RESULTS_NOTIFICATION (0x83) */ +static void iwl_rx_scan_results_notif(struct iwl_priv *priv, + struct iwl_rx_mem_buffer *rxb) +{ +#ifdef CONFIG_IWLWIFI_DEBUG + struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; + struct iwl_scanresults_notification *notif = + (struct iwl_scanresults_notification *)pkt->u.raw; + + IWL_DEBUG_SCAN("Scan ch.res: " + "%d [802.11%s] " + "(TSF: 0x%08X:%08X) - %d " + "elapsed=%lu usec (%dms since last)\n", + notif->channel, + notif->band ? "bg" : "a", + le32_to_cpu(notif->tsf_high), + le32_to_cpu(notif->tsf_low), + le32_to_cpu(notif->statistics[0]), + le32_to_cpu(notif->tsf_low) - priv->scan_start_tsf, + jiffies_to_msecs(elapsed_jiffies + (priv->last_scan_jiffies, jiffies))); +#endif + + priv->last_scan_jiffies = jiffies; + priv->next_scan_jiffies = 0; +} + +/* Service SCAN_COMPLETE_NOTIFICATION (0x84) */ +static void iwl_rx_scan_complete_notif(struct iwl_priv *priv, + struct iwl_rx_mem_buffer *rxb) +{ + struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; + struct iwl_scancomplete_notification *scan_notif = (void *)pkt->u.raw; + + IWL_DEBUG_SCAN("Scan complete: %d channels (TSF 0x%08X:%08X) - %d\n", + scan_notif->scanned_channels, + scan_notif->tsf_low, + scan_notif->tsf_high, scan_notif->status); + + /* The HW is no longer scanning */ + clear_bit(STATUS_SCAN_HW, &priv->status); + + /* The scan completion notification came in, so kill that timer... */ + cancel_delayed_work(&priv->scan_check); + + IWL_DEBUG_INFO("Scan pass on %sGHz took %dms\n", + (priv->scan_bands & BIT(IEEE80211_BAND_2GHZ)) ? + "2.4" : "5.2", + jiffies_to_msecs(elapsed_jiffies + (priv->scan_pass_start, jiffies))); + + /* Remove this scanned band from the list of pending + * bands to scan, band G precedes A in order of scanning + * as seen in iwl_bg_request_scan */ + if (priv->scan_bands & BIT(IEEE80211_BAND_2GHZ)) + priv->scan_bands &= ~BIT(IEEE80211_BAND_2GHZ); + else if (priv->scan_bands & BIT(IEEE80211_BAND_5GHZ)) + priv->scan_bands &= ~BIT(IEEE80211_BAND_5GHZ); + + /* If a request to abort was given, or the scan did not succeed + * then we reset the scan state machine and terminate, + * re-queuing another scan if one has been requested */ + if (test_bit(STATUS_SCAN_ABORTING, &priv->status)) { + IWL_DEBUG_INFO("Aborted scan completed.\n"); + clear_bit(STATUS_SCAN_ABORTING, &priv->status); + } else { + /* If there are more bands on this scan pass reschedule */ + if (priv->scan_bands) + goto reschedule; + } + + priv->last_scan_jiffies = jiffies; + priv->next_scan_jiffies = 0; + IWL_DEBUG_INFO("Setting scan to off\n"); + + clear_bit(STATUS_SCANNING, &priv->status); + + IWL_DEBUG_INFO("Scan took %dms\n", + jiffies_to_msecs(elapsed_jiffies(priv->scan_start, jiffies))); + + queue_work(priv->workqueue, &priv->scan_completed); + + return; + +reschedule: + priv->scan_pass_start = jiffies; + queue_work(priv->workqueue, &priv->request_scan); +} + +void iwl_setup_rx_scan_handlers(struct iwl_priv *priv) +{ + /* scan handlers */ + priv->rx_handlers[REPLY_SCAN_CMD] = iwl_rx_reply_scan; + priv->rx_handlers[SCAN_START_NOTIFICATION] = iwl_rx_scan_start_notif; + priv->rx_handlers[SCAN_RESULTS_NOTIFICATION] = + iwl_rx_scan_results_notif; + priv->rx_handlers[SCAN_COMPLETE_NOTIFICATION] = + iwl_rx_scan_complete_notif; +} +EXPORT_SYMBOL(iwl_setup_rx_scan_handlers); + +static inline u16 iwl_get_active_dwell_time(struct iwl_priv *priv, + enum ieee80211_band band, + u8 n_probes) +{ + if (band == IEEE80211_BAND_5GHZ) + return IWL_ACTIVE_DWELL_TIME_52 + + IWL_ACTIVE_DWELL_FACTOR_52GHZ * (n_probes + 1); + else + return IWL_ACTIVE_DWELL_TIME_24 + + IWL_ACTIVE_DWELL_FACTOR_24GHZ * (n_probes + 1); +} + +static u16 iwl_get_passive_dwell_time(struct iwl_priv *priv, + enum ieee80211_band band) +{ + u16 passive = (band == IEEE80211_BAND_2GHZ) ? + IWL_PASSIVE_DWELL_BASE + IWL_PASSIVE_DWELL_TIME_24 : + IWL_PASSIVE_DWELL_BASE + IWL_PASSIVE_DWELL_TIME_52; + + if (iwl_is_associated(priv)) { + /* If we're associated, we clamp the maximum passive + * dwell time to be 98% of the beacon interval (minus + * 2 * channel tune time) */ + passive = priv->beacon_int; + if ((passive > IWL_PASSIVE_DWELL_BASE) || !passive) + passive = IWL_PASSIVE_DWELL_BASE; + passive = (passive * 98) / 100 - IWL_CHANNEL_TUNE_TIME * 2; + } + + return passive; +} + +static int iwl_get_channels_for_scan(struct iwl_priv *priv, + enum ieee80211_band band, + u8 is_active, u8 n_probes, + struct iwl_scan_channel *scan_ch) +{ + const struct ieee80211_channel *channels = NULL; + const struct ieee80211_supported_band *sband; + const struct iwl_channel_info *ch_info; + u16 passive_dwell = 0; + u16 active_dwell = 0; + int added, i; + u16 channel; + + sband = iwl_get_hw_mode(priv, band); + if (!sband) + return 0; + + channels = sband->channels; + + active_dwell = iwl_get_active_dwell_time(priv, band, n_probes); + passive_dwell = iwl_get_passive_dwell_time(priv, band); + + if (passive_dwell <= active_dwell) + passive_dwell = active_dwell + 1; + + for (i = 0, added = 0; i < sband->n_channels; i++) { + if (channels[i].flags & IEEE80211_CHAN_DISABLED) + continue; + + channel = + ieee80211_frequency_to_channel(channels[i].center_freq); + scan_ch->channel = cpu_to_le16(channel); + + ch_info = iwl_get_channel_info(priv, band, channel); + if (!is_channel_valid(ch_info)) { + IWL_DEBUG_SCAN("Channel %d is INVALID for this band.\n", + channel); + continue; + } + + if (!is_active || is_channel_passive(ch_info) || + (channels[i].flags & IEEE80211_CHAN_PASSIVE_SCAN)) + scan_ch->type = SCAN_CHANNEL_TYPE_PASSIVE; + else + scan_ch->type = SCAN_CHANNEL_TYPE_ACTIVE; + + if ((scan_ch->type & SCAN_CHANNEL_TYPE_ACTIVE) && n_probes) + scan_ch->type |= IWL_SCAN_PROBE_MASK(n_probes); + + scan_ch->active_dwell = cpu_to_le16(active_dwell); + scan_ch->passive_dwell = cpu_to_le16(passive_dwell); + + /* Set txpower levels to defaults */ + scan_ch->dsp_atten = 110; + + /* NOTE: if we were doing 6Mb OFDM for scans we'd use + * power level: + * scan_ch->tx_gain = ((1 << 5) | (2 << 3)) | 3; + */ + if (band == IEEE80211_BAND_5GHZ) + scan_ch->tx_gain = ((1 << 5) | (3 << 3)) | 3; + else + scan_ch->tx_gain = ((1 << 5) | (5 << 3)); + + IWL_DEBUG_SCAN("Scanning ch=%d prob=0x%X [%s %d]\n", + channel, le32_to_cpu(scan_ch->type), + (scan_ch->type & SCAN_CHANNEL_TYPE_ACTIVE) ? + "ACTIVE" : "PASSIVE", + (scan_ch->type & SCAN_CHANNEL_TYPE_ACTIVE) ? + active_dwell : passive_dwell); + + scan_ch++; + added++; + } + + IWL_DEBUG_SCAN("total channels to scan %d \n", added); + return added; +} + +void iwl_init_scan_params(struct iwl_priv *priv) +{ + if (!priv->scan_tx_ant[IEEE80211_BAND_5GHZ]) + priv->scan_tx_ant[IEEE80211_BAND_5GHZ] = RATE_MCS_ANT_INIT_IND; + if (!priv->scan_tx_ant[IEEE80211_BAND_2GHZ]) + priv->scan_tx_ant[IEEE80211_BAND_2GHZ] = RATE_MCS_ANT_INIT_IND; +} + +int iwl_scan_initiate(struct iwl_priv *priv) +{ + if (priv->iw_mode == IEEE80211_IF_TYPE_AP) { + IWL_ERROR("APs don't scan.\n"); + return 0; + } + + if (!iwl_is_ready_rf(priv)) { + IWL_DEBUG_SCAN("Aborting scan due to not ready.\n"); + return -EIO; + } + + if (test_bit(STATUS_SCANNING, &priv->status)) { + IWL_DEBUG_SCAN("Scan already in progress.\n"); + return -EAGAIN; + } + + if (test_bit(STATUS_SCAN_ABORTING, &priv->status)) { + IWL_DEBUG_SCAN("Scan request while abort pending. " + "Queuing.\n"); + return -EAGAIN; + } + + IWL_DEBUG_INFO("Starting scan...\n"); + if (priv->cfg->sku & IWL_SKU_G) + priv->scan_bands |= BIT(IEEE80211_BAND_2GHZ); + if (priv->cfg->sku & IWL_SKU_A) + priv->scan_bands |= BIT(IEEE80211_BAND_5GHZ); + set_bit(STATUS_SCANNING, &priv->status); + priv->scan_start = jiffies; + priv->scan_pass_start = priv->scan_start; + + queue_work(priv->workqueue, &priv->request_scan); + + return 0; +} +EXPORT_SYMBOL(iwl_scan_initiate); + +#define IWL_SCAN_CHECK_WATCHDOG (7 * HZ) + +static void iwl_bg_scan_check(struct work_struct *data) +{ + struct iwl_priv *priv = + container_of(data, struct iwl_priv, scan_check.work); + + if (test_bit(STATUS_EXIT_PENDING, &priv->status)) + return; + + mutex_lock(&priv->mutex); + if (test_bit(STATUS_SCANNING, &priv->status) || + test_bit(STATUS_SCAN_ABORTING, &priv->status)) { + IWL_DEBUG(IWL_DL_SCAN, "Scan completion watchdog resetting " + "adapter (%dms)\n", + jiffies_to_msecs(IWL_SCAN_CHECK_WATCHDOG)); + + if (!test_bit(STATUS_EXIT_PENDING, &priv->status)) + iwl_send_scan_abort(priv); + } + mutex_unlock(&priv->mutex); +} +/** + * 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_info.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_info.cap); + memcpy(ht_cap->supp_mcs_set, sband->ht_info.supp_mcs_set, 16); + ht_cap->ampdu_params_info = + (sband->ht_info.ampdu_factor & IEEE80211_HT_CAP_AMPDU_FACTOR) | + ((sband->ht_info.ampdu_density << 2) & + IEEE80211_HT_CAP_AMPDU_DENSITY); + *left -= sizeof(struct ieee80211_ht_cap); +} + +/** + * iwl_fill_probe_req - fill in all required fields and IE for probe request + */ + +static u16 iwl_fill_probe_req(struct iwl_priv *priv, + enum ieee80211_band band, + struct ieee80211_mgmt *frame, + 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 */ + left -= 24; + if (left < 0) + return 0; + + frame->frame_control = cpu_to_le16(IEEE80211_STYPE_PROBE_REQ); + memcpy(frame->da, iwl_bcast_addr, ETH_ALEN); + memcpy(frame->sa, priv->mac_addr, ETH_ALEN); + memcpy(frame->bssid, iwl_bcast_addr, ETH_ALEN); + frame->seq_ctrl = 0; + + len += 24; + + /* ...next IE... */ + pos = &frame->u.probe_req.variable[0]; + + /* fill in our indirect SSID IE */ + left -= 2; + if (left < 0) + return 0; + *pos++ = WLAN_EID_SSID; + *pos++ = 0; + + 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; + + 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; + + return (u16)len; +} + +static u32 iwl_scan_tx_ant(struct iwl_priv *priv, enum ieee80211_band band) +{ + int i, ind; + + ind = priv->scan_tx_ant[band]; + for (i = 0; i < priv->hw_params.tx_chains_num; i++) { + ind = (ind+1) >= priv->hw_params.tx_chains_num ? 0 : ind+1; + if (priv->hw_params.valid_tx_ant & (1 << ind)) { + priv->scan_tx_ant[band] = ind; + break; + } + } + IWL_DEBUG_SCAN("select TX ANT = %c\n", 'A' + ind); + return scan_tx_ant[ind]; +} + + +static void iwl_bg_request_scan(struct work_struct *data) +{ + struct iwl_priv *priv = + container_of(data, struct iwl_priv, request_scan); + struct iwl_host_cmd cmd = { + .id = REPLY_SCAN_CMD, + .len = sizeof(struct iwl_scan_cmd), + .meta.flags = CMD_SIZE_HUGE, + }; + struct iwl_scan_cmd *scan; + struct ieee80211_conf *conf = NULL; + int ret = 0; + u32 tx_ant; + u16 cmd_len; + enum ieee80211_band band; + u8 n_probes = 2; + u8 rx_chain = 0x7; /* bitmap: ABC chains */ + + conf = ieee80211_get_hw_conf(priv->hw); + + mutex_lock(&priv->mutex); + + if (!iwl_is_ready(priv)) { + IWL_WARNING("request scan called when driver not ready.\n"); + goto done; + } + + /* Make sure the scan wasn't cancelled before this queued work + * was given the chance to run... */ + if (!test_bit(STATUS_SCANNING, &priv->status)) + goto done; + + /* This should never be called or scheduled if there is currently + * a scan active in the hardware. */ + if (test_bit(STATUS_SCAN_HW, &priv->status)) { + IWL_DEBUG_INFO("Multiple concurrent scan requests in parallel. " + "Ignoring second request.\n"); + ret = -EIO; + goto done; + } + + if (test_bit(STATUS_EXIT_PENDING, &priv->status)) { + IWL_DEBUG_SCAN("Aborting scan due to device shutdown\n"); + goto done; + } + + if (test_bit(STATUS_SCAN_ABORTING, &priv->status)) { + IWL_DEBUG_HC("Scan request while abort pending. Queuing.\n"); + goto done; + } + + if (iwl_is_rfkill(priv)) { + IWL_DEBUG_HC("Aborting scan due to RF Kill activation\n"); + goto done; + } + + if (!test_bit(STATUS_READY, &priv->status)) { + IWL_DEBUG_HC("Scan request while uninitialized. Queuing.\n"); + goto done; + } + + if (!priv->scan_bands) { + IWL_DEBUG_HC("Aborting scan due to no requested bands\n"); + goto done; + } + + if (!priv->scan) { + priv->scan = kmalloc(sizeof(struct iwl_scan_cmd) + + IWL_MAX_SCAN_SIZE, GFP_KERNEL); + if (!priv->scan) { + ret = -ENOMEM; + goto done; + } + } + scan = priv->scan; + memset(scan, 0, sizeof(struct iwl_scan_cmd) + IWL_MAX_SCAN_SIZE); + + scan->quiet_plcp_th = IWL_PLCP_QUIET_THRESH; + scan->quiet_time = IWL_ACTIVE_QUIET_TIME; + + if (iwl_is_associated(priv)) { + u16 interval = 0; + u32 extra; + u32 suspend_time = 100; + u32 scan_suspend_time = 100; + unsigned long flags; + + IWL_DEBUG_INFO("Scanning while associated...\n"); + + spin_lock_irqsave(&priv->lock, flags); + interval = priv->beacon_int; + spin_unlock_irqrestore(&priv->lock, flags); + + scan->suspend_time = 0; + scan->max_out_time = cpu_to_le32(200 * 1024); + if (!interval) + interval = suspend_time; + + extra = (suspend_time / interval) << 22; + scan_suspend_time = (extra | + ((suspend_time % interval) * 1024)); + scan->suspend_time = cpu_to_le32(scan_suspend_time); + IWL_DEBUG_SCAN("suspend_time 0x%X beacon interval %d\n", + scan_suspend_time, interval); + } + + /* We should add the ability for user to lock to PASSIVE ONLY */ + if (priv->one_direct_scan) { + IWL_DEBUG_SCAN("Start direct scan for '%s'\n", + iwl_escape_essid(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 if (!iwl_is_associated(priv) && priv->essid_len) { + IWL_DEBUG_SCAN("Start direct scan for '%s' (not associated)\n", + iwl_escape_essid(priv->essid, priv->essid_len)); + scan->direct_scan[0].id = WLAN_EID_SSID; + scan->direct_scan[0].len = priv->essid_len; + memcpy(scan->direct_scan[0].ssid, priv->essid, priv->essid_len); + n_probes++; + } else { + IWL_DEBUG_SCAN("Start indirect scan.\n"); + } + + scan->tx_cmd.tx_flags = TX_CMD_FLG_SEQ_CTL_MSK; + scan->tx_cmd.sta_id = priv->hw_params.bcast_sta_id; + scan->tx_cmd.stop_time.life_time = TX_CMD_LIFE_TIME_INFINITE; + + + if (priv->scan_bands & BIT(IEEE80211_BAND_2GHZ)) { + band = IEEE80211_BAND_2GHZ; + scan->flags = RXON_FLG_BAND_24G_MSK | RXON_FLG_AUTO_DETECT_MSK; + tx_ant = iwl_scan_tx_ant(priv, band); + if (priv->active_rxon.flags & RXON_FLG_CHANNEL_MODE_PURE_40_MSK) + scan->tx_cmd.rate_n_flags = + iwl_hw_set_rate_n_flags(IWL_RATE_6M_PLCP, + tx_ant); + else + scan->tx_cmd.rate_n_flags = + iwl_hw_set_rate_n_flags(IWL_RATE_1M_PLCP, + tx_ant | + RATE_MCS_CCK_MSK); + scan->good_CRC_th = 0; + } else if (priv->scan_bands & BIT(IEEE80211_BAND_5GHZ)) { + band = IEEE80211_BAND_5GHZ; + tx_ant = iwl_scan_tx_ant(priv, band); + scan->tx_cmd.rate_n_flags = + iwl_hw_set_rate_n_flags(IWL_RATE_6M_PLCP, + tx_ant); + scan->good_CRC_th = IWL_GOOD_CRC_TH; + + /* Force use of chains B and C (0x6) for scan Rx for 4965 + * Avoid A (0x1) because of its off-channel reception on A-band. + * MIMO is not used here, but value is required */ + if ((priv->hw_rev & CSR_HW_REV_TYPE_MSK) == CSR_HW_REV_TYPE_4965) + rx_chain = 0x6; + } else { + IWL_WARNING("Invalid scan band count\n"); + goto done; + } + + 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)); + + cmd_len = iwl_fill_probe_req(priv, band, + (struct ieee80211_mgmt *)scan->data, + IWL_MAX_SCAN_SIZE - sizeof(*scan)); + + scan->tx_cmd.len = cpu_to_le16(cmd_len); + + if (priv->iw_mode == IEEE80211_IF_TYPE_MNTR) + scan->filter_flags = RXON_FILTER_PROMISC_MSK; + + scan->filter_flags |= (RXON_FILTER_ACCEPT_GRP_MSK | + RXON_FILTER_BCON_AWARE_MSK); + + scan->channel_count = + iwl_get_channels_for_scan(priv, band, 1, /* active */ + n_probes, + (void *)&scan->data[le16_to_cpu(scan->tx_cmd.len)]); + + if (scan->channel_count == 0) { + IWL_DEBUG_SCAN("channel count %d\n", scan->channel_count); + goto done; + } + + cmd.len += le16_to_cpu(scan->tx_cmd.len) + + scan->channel_count * sizeof(struct iwl_scan_channel); + cmd.data = scan; + scan->len = cpu_to_le16(cmd.len); + + set_bit(STATUS_SCAN_HW, &priv->status); + ret = iwl_send_cmd_sync(priv, &cmd); + if (ret) + goto done; + + queue_delayed_work(priv->workqueue, &priv->scan_check, + IWL_SCAN_CHECK_WATCHDOG); + + mutex_unlock(&priv->mutex); + return; + + done: + /* inform mac80211 scan aborted */ + queue_work(priv->workqueue, &priv->scan_completed); + mutex_unlock(&priv->mutex); +} + +static void iwl_bg_abort_scan(struct work_struct *work) +{ + struct iwl_priv *priv = container_of(work, struct iwl_priv, abort_scan); + + if (!iwl_is_ready(priv)) + return; + + mutex_lock(&priv->mutex); + + set_bit(STATUS_SCAN_ABORTING, &priv->status); + iwl_send_scan_abort(priv); + + mutex_unlock(&priv->mutex); +} + +void iwl_setup_scan_deferred_work(struct iwl_priv *priv) +{ + /* FIXME: move here when resolved PENDING + * INIT_WORK(&priv->scan_completed, iwl_bg_scan_completed); */ + INIT_WORK(&priv->request_scan, iwl_bg_request_scan); + INIT_WORK(&priv->abort_scan, iwl_bg_abort_scan); + INIT_DELAYED_WORK(&priv->scan_check, iwl_bg_scan_check); +} +EXPORT_SYMBOL(iwl_setup_scan_deferred_work); + diff --git a/drivers/net/wireless/iwlwifi/iwl-sta.c b/drivers/net/wireless/iwlwifi/iwl-sta.c index e4fdfaa2b9b2..6d1467d0bd9d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-sta.c +++ b/drivers/net/wireless/iwlwifi/iwl-sta.c @@ -28,17 +28,446 @@ *****************************************************************************/ #include <net/mac80211.h> +#include <linux/etherdevice.h> -#include "iwl-eeprom.h" -#include "iwl-4965.h" +#include "iwl-dev.h" #include "iwl-core.h" #include "iwl-sta.h" -#include "iwl-io.h" #include "iwl-helpers.h" -#include "iwl-4965.h" -#include "iwl-sta.h" -int iwl_get_free_ucode_key_index(struct iwl_priv *priv) + +#define IWL_STA_DRIVER_ACTIVE BIT(0) /* driver entry is active */ +#define IWL_STA_UCODE_ACTIVE BIT(1) /* ucode entry is active */ + +u8 iwl_find_station(struct iwl_priv *priv, const u8 *addr) +{ + int i; + int start = 0; + int ret = IWL_INVALID_STATION; + unsigned long flags; + DECLARE_MAC_BUF(mac); + + if ((priv->iw_mode == IEEE80211_IF_TYPE_IBSS) || + (priv->iw_mode == IEEE80211_IF_TYPE_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[i].used && + (!compare_ether_addr(priv->stations[i].sta.sta.addr, + addr))) { + ret = i; + goto out; + } + + IWL_DEBUG_ASSOC_LIMIT("can not find STA %s total %d\n", + print_mac(mac, addr), priv->num_stations); + + out: + spin_unlock_irqrestore(&priv->sta_lock, flags); + return ret; +} +EXPORT_SYMBOL(iwl_find_station); + +int iwl_get_ra_sta_id(struct iwl_priv *priv, struct ieee80211_hdr *hdr) +{ + if (priv->iw_mode == IEEE80211_IF_TYPE_STA) { + return IWL_AP_ID; + } else { + u8 *da = ieee80211_get_DA(hdr); + return iwl_find_station(priv, da); + } +} +EXPORT_SYMBOL(iwl_get_ra_sta_id); + +static void iwl_sta_ucode_activate(struct iwl_priv *priv, u8 sta_id) +{ + unsigned long flags; + DECLARE_MAC_BUF(mac); + + spin_lock_irqsave(&priv->sta_lock, flags); + + if (!(priv->stations[sta_id].used & IWL_STA_DRIVER_ACTIVE)) + IWL_ERROR("ACTIVATE a non DRIVER active station %d\n", sta_id); + + priv->stations[sta_id].used |= IWL_STA_UCODE_ACTIVE; + IWL_DEBUG_ASSOC("Added STA to Ucode: %s\n", + print_mac(mac, priv->stations[sta_id].sta.sta.addr)); + + spin_unlock_irqrestore(&priv->sta_lock, flags); +} + +static int iwl_add_sta_callback(struct iwl_priv *priv, + struct iwl_cmd *cmd, struct sk_buff *skb) +{ + struct iwl_rx_packet *res = NULL; + u8 sta_id = cmd->cmd.addsta.sta.sta_id; + + if (!skb) { + IWL_ERROR("Error: Response NULL in REPLY_ADD_STA.\n"); + return 1; + } + + res = (struct iwl_rx_packet *)skb->data; + if (res->hdr.flags & IWL_CMD_FAILED_MSK) { + IWL_ERROR("Bad return from REPLY_ADD_STA (0x%08X)\n", + res->hdr.flags); + return 1; + } + + switch (res->u.add_sta.status) { + case ADD_STA_SUCCESS_MSK: + iwl_sta_ucode_activate(priv, sta_id); + /* fall through */ + default: + IWL_DEBUG_HC("Received REPLY_ADD_STA:(0x%08X)\n", + res->u.add_sta.status); + break; + } + + /* We didn't cache the SKB; let the caller free it */ + return 1; +} + +int iwl_send_add_sta(struct iwl_priv *priv, + struct iwl_addsta_cmd *sta, u8 flags) +{ + struct iwl_rx_packet *res = NULL; + int ret = 0; + u8 data[sizeof(*sta)]; + struct iwl_host_cmd cmd = { + .id = REPLY_ADD_STA, + .meta.flags = flags, + .data = data, + }; + + if (flags & CMD_ASYNC) + cmd.meta.u.callback = iwl_add_sta_callback; + else + cmd.meta.flags |= CMD_WANT_SKB; + + cmd.len = priv->cfg->ops->utils->build_addsta_hcmd(sta, data); + ret = iwl_send_cmd(priv, &cmd); + + if (ret || (flags & CMD_ASYNC)) + return ret; + + res = (struct iwl_rx_packet *)cmd.meta.u.skb->data; + if (res->hdr.flags & IWL_CMD_FAILED_MSK) { + IWL_ERROR("Bad return from REPLY_ADD_STA (0x%08X)\n", + res->hdr.flags); + ret = -EIO; + } + + if (ret == 0) { + switch (res->u.add_sta.status) { + case ADD_STA_SUCCESS_MSK: + iwl_sta_ucode_activate(priv, sta->sta.sta_id); + IWL_DEBUG_INFO("REPLY_ADD_STA PASSED\n"); + break; + default: + ret = -EIO; + IWL_WARNING("REPLY_ADD_STA failed\n"); + break; + } + } + + priv->alloc_rxb_skb--; + dev_kfree_skb_any(cmd.meta.u.skb); + + return ret; +} +EXPORT_SYMBOL(iwl_send_add_sta); + +static void iwl_set_ht_add_station(struct iwl_priv *priv, u8 index, + struct ieee80211_ht_info *sta_ht_inf) +{ + __le32 sta_flags; + u8 mimo_ps_mode; + + if (!sta_ht_inf || !sta_ht_inf->ht_supported) + goto done; + + mimo_ps_mode = (sta_ht_inf->cap & IEEE80211_HT_CAP_MIMO_PS) >> 2; + + sta_flags = priv->stations[index].sta.station_flags; + + sta_flags &= ~(STA_FLG_RTS_MIMO_PROT_MSK | STA_FLG_MIMO_DIS_MSK); + + switch (mimo_ps_mode) { + case WLAN_HT_CAP_MIMO_PS_STATIC: + sta_flags |= STA_FLG_MIMO_DIS_MSK; + break; + case WLAN_HT_CAP_MIMO_PS_DYNAMIC: + sta_flags |= STA_FLG_RTS_MIMO_PROT_MSK; + break; + case WLAN_HT_CAP_MIMO_PS_DISABLED: + break; + default: + IWL_WARNING("Invalid MIMO PS mode %d", mimo_ps_mode); + break; + } + + sta_flags |= cpu_to_le32( + (u32)sta_ht_inf->ampdu_factor << STA_FLG_MAX_AGG_SIZE_POS); + + sta_flags |= cpu_to_le32( + (u32)sta_ht_inf->ampdu_density << STA_FLG_AGG_MPDU_DENSITY_POS); + + if (iwl_is_fat_tx_allowed(priv, sta_ht_inf)) + sta_flags |= STA_FLG_FAT_EN_MSK; + else + sta_flags &= ~STA_FLG_FAT_EN_MSK; + + priv->stations[index].sta.station_flags = sta_flags; + done: + return; +} + +/** + * iwl_add_station_flags - 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_ht_info *ht_info) +{ + int i; + int sta_id = IWL_INVALID_STATION; + struct iwl_station_entry *station; + unsigned long flags_spin; + DECLARE_MAC_BUF(mac); + + spin_lock_irqsave(&priv->sta_lock, flags_spin); + if (is_ap) + sta_id = IWL_AP_ID; + else if (is_broadcast_ether_addr(addr)) + sta_id = 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[i].sta.sta.addr, + addr)) { + sta_id = i; + break; + } + + if (!priv->stations[i].used && + sta_id == IWL_INVALID_STATION) + sta_id = i; + } + + /* These two conditions have the same outcome, but keep them separate + since they have different meanings */ + if (unlikely(sta_id == IWL_INVALID_STATION)) { + spin_unlock_irqrestore(&priv->sta_lock, flags_spin); + return sta_id; + } + + if (priv->stations[sta_id].used && + !compare_ether_addr(priv->stations[sta_id].sta.sta.addr, addr)) { + spin_unlock_irqrestore(&priv->sta_lock, flags_spin); + return sta_id; + } + + + station = &priv->stations[sta_id]; + station->used = IWL_STA_DRIVER_ACTIVE; + IWL_DEBUG_ASSOC("Add STA to driver ID %d: %s\n", + sta_id, print_mac(mac, addr)); + priv->num_stations++; + + /* Set up the REPLY_ADD_STA command to send to device */ + memset(&station->sta, 0, sizeof(struct iwl_addsta_cmd)); + memcpy(station->sta.sta.addr, addr, ETH_ALEN); + station->sta.mode = 0; + station->sta.sta.sta_id = sta_id; + station->sta.station_flags = 0; + + /* BCAST station and IBSS stations do not work in HT mode */ + if (sta_id != priv->hw_params.bcast_sta_id && + priv->iw_mode != IEEE80211_IF_TYPE_IBSS) + iwl_set_ht_add_station(priv, sta_id, ht_info); + + spin_unlock_irqrestore(&priv->sta_lock, flags_spin); + + /* Add station to device's station table */ + iwl_send_add_sta(priv, &station->sta, flags); + return sta_id; + +} +EXPORT_SYMBOL(iwl_add_station_flags); + +static void iwl_sta_ucode_deactivate(struct iwl_priv *priv, const char *addr) +{ + unsigned long flags; + DECLARE_MAC_BUF(mac); + + u8 sta_id = iwl_find_station(priv, addr); + + BUG_ON(sta_id == IWL_INVALID_STATION); + + IWL_DEBUG_ASSOC("Removed STA from Ucode: %s\n", + print_mac(mac, addr)); + + spin_lock_irqsave(&priv->sta_lock, flags); + + /* Ucode must be active and driver must be non active */ + if (priv->stations[sta_id].used != IWL_STA_UCODE_ACTIVE) + IWL_ERROR("removed non active STA %d\n", sta_id); + + priv->stations[sta_id].used &= ~IWL_STA_UCODE_ACTIVE; + + memset(&priv->stations[sta_id], 0, sizeof(struct iwl_station_entry)); + spin_unlock_irqrestore(&priv->sta_lock, flags); +} + +static int iwl_remove_sta_callback(struct iwl_priv *priv, + struct iwl_cmd *cmd, struct sk_buff *skb) +{ + struct iwl_rx_packet *res = NULL; + const char *addr = cmd->cmd.rm_sta.addr; + + if (!skb) { + IWL_ERROR("Error: Response NULL in REPLY_REMOVE_STA.\n"); + return 1; + } + + res = (struct iwl_rx_packet *)skb->data; + if (res->hdr.flags & IWL_CMD_FAILED_MSK) { + IWL_ERROR("Bad return from REPLY_REMOVE_STA (0x%08X)\n", + res->hdr.flags); + return 1; + } + + switch (res->u.rem_sta.status) { + case REM_STA_SUCCESS_MSK: + iwl_sta_ucode_deactivate(priv, addr); + break; + default: + IWL_ERROR("REPLY_REMOVE_STA failed\n"); + break; + } + + /* We didn't cache the SKB; let the caller free it */ + return 1; +} + +static int iwl_send_remove_station(struct iwl_priv *priv, const u8 *addr, + u8 flags) +{ + struct iwl_rx_packet *res = NULL; + int ret; + + struct iwl_rem_sta_cmd rm_sta_cmd; + + struct iwl_host_cmd cmd = { + .id = REPLY_REMOVE_STA, + .len = sizeof(struct iwl_rem_sta_cmd), + .meta.flags = flags, + .data = &rm_sta_cmd, + }; + + memset(&rm_sta_cmd, 0, sizeof(rm_sta_cmd)); + rm_sta_cmd.num_sta = 1; + memcpy(&rm_sta_cmd.addr, addr , ETH_ALEN); + + if (flags & CMD_ASYNC) + cmd.meta.u.callback = iwl_remove_sta_callback; + else + cmd.meta.flags |= CMD_WANT_SKB; + ret = iwl_send_cmd(priv, &cmd); + + if (ret || (flags & CMD_ASYNC)) + return ret; + + res = (struct iwl_rx_packet *)cmd.meta.u.skb->data; + if (res->hdr.flags & IWL_CMD_FAILED_MSK) { + IWL_ERROR("Bad return from REPLY_REMOVE_STA (0x%08X)\n", + res->hdr.flags); + ret = -EIO; + } + + if (!ret) { + switch (res->u.rem_sta.status) { + case REM_STA_SUCCESS_MSK: + iwl_sta_ucode_deactivate(priv, addr); + IWL_DEBUG_ASSOC("REPLY_REMOVE_STA PASSED\n"); + break; + default: + ret = -EIO; + IWL_ERROR("REPLY_REMOVE_STA failed\n"); + break; + } + } + + priv->alloc_rxb_skb--; + dev_kfree_skb_any(cmd.meta.u.skb); + + return ret; +} + +/** + * iwl_remove_station - Remove driver's knowledge of station. + */ +int iwl_remove_station(struct iwl_priv *priv, const u8 *addr, int is_ap) +{ + int sta_id = IWL_INVALID_STATION; + int i, ret = -EINVAL; + unsigned long flags; + DECLARE_MAC_BUF(mac); + + spin_lock_irqsave(&priv->sta_lock, flags); + + if (is_ap) + sta_id = IWL_AP_ID; + else if (is_broadcast_ether_addr(addr)) + sta_id = priv->hw_params.bcast_sta_id; + else + for (i = IWL_STA_ID; i < priv->hw_params.max_stations; i++) + if (priv->stations[i].used && + !compare_ether_addr(priv->stations[i].sta.sta.addr, + addr)) { + sta_id = i; + break; + } + + if (unlikely(sta_id == IWL_INVALID_STATION)) + goto out; + + IWL_DEBUG_ASSOC("Removing STA from driver:%d %s\n", + sta_id, print_mac(mac, addr)); + + if (!(priv->stations[sta_id].used & IWL_STA_DRIVER_ACTIVE)) { + IWL_ERROR("Removing %s but non DRIVER active\n", + print_mac(mac, addr)); + goto out; + } + + if (!(priv->stations[sta_id].used & IWL_STA_UCODE_ACTIVE)) { + IWL_ERROR("Removing %s but non UCODE active\n", + print_mac(mac, addr)); + goto out; + } + + + priv->stations[sta_id].used &= ~IWL_STA_DRIVER_ACTIVE; + + priv->num_stations--; + + BUG_ON(priv->num_stations < 0); + + spin_unlock_irqrestore(&priv->sta_lock, flags); + + ret = iwl_send_remove_station(priv, addr, CMD_ASYNC); + return ret; +out: + spin_unlock_irqrestore(&priv->sta_lock, flags); + return ret; +} +EXPORT_SYMBOL(iwl_remove_station); + +static int iwl_get_free_ucode_key_index(struct iwl_priv *priv) { int i; @@ -91,6 +520,7 @@ int iwl_send_static_wepkey_cmd(struct iwl_priv *priv, u8 send_if_empty) else return 0; } +EXPORT_SYMBOL(iwl_send_static_wepkey_cmd); int iwl_remove_default_wep_key(struct iwl_priv *priv, struct ieee80211_key_conf *keyconf) @@ -107,10 +537,13 @@ int iwl_remove_default_wep_key(struct iwl_priv *priv, priv->default_wep_key--; memset(&priv->wep_keys[keyconf->keyidx], 0, sizeof(priv->wep_keys[0])); ret = iwl_send_static_wepkey_cmd(priv, 1); + IWL_DEBUG_WEP("Remove default WEP key: idx=%d ret=%d\n", + keyconf->keyidx, ret); spin_unlock_irqrestore(&priv->sta_lock, flags); return ret; } +EXPORT_SYMBOL(iwl_remove_default_wep_key); int iwl_set_default_wep_key(struct iwl_priv *priv, struct ieee80211_key_conf *keyconf) @@ -118,8 +551,14 @@ int iwl_set_default_wep_key(struct iwl_priv *priv, int ret; unsigned long flags; + if (keyconf->keylen != WEP_KEY_LEN_128 && + keyconf->keylen != WEP_KEY_LEN_64) { + IWL_DEBUG_WEP("Bad WEP key length %d\n", keyconf->keylen); + return -EINVAL; + } + keyconf->flags &= ~IEEE80211_KEY_FLAG_GENERATE_IV; - keyconf->hw_key_idx = keyconf->keyidx; + keyconf->hw_key_idx = HW_KEY_DEFAULT; priv->stations[IWL_AP_ID].keyinfo.alg = ALG_WEP; spin_lock_irqsave(&priv->sta_lock, flags); @@ -134,10 +573,13 @@ int iwl_set_default_wep_key(struct iwl_priv *priv, keyconf->keylen); ret = iwl_send_static_wepkey_cmd(priv, 0); + IWL_DEBUG_WEP("Set default WEP key: len=%d idx=%d ret=%d\n", + keyconf->keylen, keyconf->keyidx, ret); spin_unlock_irqrestore(&priv->sta_lock, flags); return ret; } +EXPORT_SYMBOL(iwl_set_default_wep_key); static int iwl_set_wep_dynamic_key_info(struct iwl_priv *priv, struct ieee80211_key_conf *keyconf, @@ -148,7 +590,6 @@ static int iwl_set_wep_dynamic_key_info(struct iwl_priv *priv, int ret; keyconf->flags &= ~IEEE80211_KEY_FLAG_GENERATE_IV; - keyconf->hw_key_idx = keyconf->keyidx; key_flags |= (STA_KEY_FLG_WEP | STA_KEY_FLG_MAP_KEY_MSK); key_flags |= cpu_to_le16(keyconf->keyidx << STA_KEY_FLG_KEYID_POS); @@ -172,15 +613,18 @@ static int iwl_set_wep_dynamic_key_info(struct iwl_priv *priv, memcpy(&priv->stations[sta_id].sta.key.key[3], keyconf->key, keyconf->keylen); - priv->stations[sta_id].sta.key.key_offset = + if ((priv->stations[sta_id].sta.key.key_flags & STA_KEY_FLG_ENCRYPT_MSK) + == STA_KEY_FLG_NO_ENC) + priv->stations[sta_id].sta.key.key_offset = iwl_get_free_ucode_key_index(priv); - priv->stations[sta_id].sta.key.key_flags = key_flags; + /* else, we are overriding an existing key => no need to allocated room + * in uCode. */ + 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; - ret = iwl4965_send_add_station(priv, - &priv->stations[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); @@ -202,7 +646,6 @@ static int iwl_set_ccmp_dynamic_key_info(struct iwl_priv *priv, key_flags |= STA_KEY_MULTICAST_MSK; keyconf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; - keyconf->hw_key_idx = keyconf->keyidx; spin_lock_irqsave(&priv->sta_lock, flags); priv->stations[sta_id].keyinfo.alg = keyconf->alg; @@ -214,8 +657,13 @@ static int iwl_set_ccmp_dynamic_key_info(struct iwl_priv *priv, memcpy(priv->stations[sta_id].sta.key.key, keyconf->key, keyconf->keylen); - priv->stations[sta_id].sta.key.key_offset = - iwl_get_free_ucode_key_index(priv); + if ((priv->stations[sta_id].sta.key.key_flags & STA_KEY_FLG_ENCRYPT_MSK) + == STA_KEY_FLG_NO_ENC) + 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. */ + 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; @@ -223,8 +671,7 @@ static int iwl_set_ccmp_dynamic_key_info(struct iwl_priv *priv, spin_unlock_irqrestore(&priv->sta_lock, flags); IWL_DEBUG_INFO("hwcrypto: modify ucode station key info\n"); - return iwl4965_send_add_station(priv, - &priv->stations[sta_id].sta, CMD_ASYNC); + return iwl_send_add_sta(priv, &priv->stations[sta_id].sta, CMD_ASYNC); } static int iwl_set_tkip_dynamic_key_info(struct iwl_priv *priv, @@ -236,15 +683,18 @@ static int iwl_set_tkip_dynamic_key_info(struct iwl_priv *priv, keyconf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; keyconf->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC; - keyconf->hw_key_idx = keyconf->keyidx; spin_lock_irqsave(&priv->sta_lock, flags); priv->stations[sta_id].keyinfo.alg = keyconf->alg; - priv->stations[sta_id].keyinfo.conf = keyconf; priv->stations[sta_id].keyinfo.keylen = 16; - priv->stations[sta_id].sta.key.key_offset = + + if ((priv->stations[sta_id].sta.key.key_flags & STA_KEY_FLG_ENCRYPT_MSK) + == STA_KEY_FLG_NO_ENC) + 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. */ /* This copy is acutally not needed: we get the key with each TX */ memcpy(priv->stations[sta_id].keyinfo.key, keyconf->key, 16); @@ -256,54 +706,84 @@ static int iwl_set_tkip_dynamic_key_info(struct iwl_priv *priv, return ret; } -int iwl_remove_dynamic_key(struct iwl_priv *priv, u8 sta_id) +int iwl_remove_dynamic_key(struct iwl_priv *priv, + struct ieee80211_key_conf *keyconf, + u8 sta_id) { unsigned long flags; + int ret = 0; + u16 key_flags; + u8 keyidx; - priv->key_mapping_key = 0; + priv->key_mapping_key--; spin_lock_irqsave(&priv->sta_lock, flags); + key_flags = le16_to_cpu(priv->stations[sta_id].sta.key.key_flags); + keyidx = (key_flags >> STA_KEY_FLG_KEYID_POS) & 0x3; + + IWL_DEBUG_WEP("Remove dynamic key: idx=%d sta=%d\n", + keyconf->keyidx, sta_id); + + if (keyconf->keyidx != keyidx) { + /* We need to remove a key with index different that the one + * in the uCode. This means that the key we need to remove has + * been replaced by another one with different index. + * Don't do anything and return ok + */ + spin_unlock_irqrestore(&priv->sta_lock, flags); + return 0; + } + if (!test_and_clear_bit(priv->stations[sta_id].sta.key.key_offset, &priv->ucode_key_table)) IWL_ERROR("index %d not used in uCode key table.\n", priv->stations[sta_id].sta.key.key_offset); memset(&priv->stations[sta_id].keyinfo, 0, - sizeof(struct iwl4965_hw_key)); + sizeof(struct iwl_hw_key)); memset(&priv->stations[sta_id].sta.key, 0, sizeof(struct iwl4965_keyinfo)); - priv->stations[sta_id].sta.key.key_flags = STA_KEY_FLG_NO_ENC; + priv->stations[sta_id].sta.key.key_flags = + STA_KEY_FLG_NO_ENC | STA_KEY_FLG_INVALID; + priv->stations[sta_id].sta.key.key_offset = WEP_INVALID_OFFSET; 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("hwcrypto: clear ucode station key info\n"); - return iwl4965_send_add_station(priv, &priv->stations[sta_id].sta, 0); + ret = iwl_send_add_sta(priv, &priv->stations[sta_id].sta, CMD_ASYNC); + spin_unlock_irqrestore(&priv->sta_lock, flags); + return ret; } +EXPORT_SYMBOL(iwl_remove_dynamic_key); int iwl_set_dynamic_key(struct iwl_priv *priv, - struct ieee80211_key_conf *key, u8 sta_id) + struct ieee80211_key_conf *keyconf, u8 sta_id) { int ret; - priv->key_mapping_key = 1; + priv->key_mapping_key++; + keyconf->hw_key_idx = HW_KEY_DYNAMIC; - switch (key->alg) { + switch (keyconf->alg) { case ALG_CCMP: - ret = iwl_set_ccmp_dynamic_key_info(priv, key, sta_id); + ret = iwl_set_ccmp_dynamic_key_info(priv, keyconf, sta_id); break; case ALG_TKIP: - ret = iwl_set_tkip_dynamic_key_info(priv, key, sta_id); + ret = iwl_set_tkip_dynamic_key_info(priv, keyconf, sta_id); break; case ALG_WEP: - ret = iwl_set_wep_dynamic_key_info(priv, key, sta_id); + ret = iwl_set_wep_dynamic_key_info(priv, keyconf, sta_id); break; default: - IWL_ERROR("Unknown alg: %s alg = %d\n", __func__, key->alg); + IWL_ERROR("Unknown alg: %s alg = %d\n", __func__, keyconf->alg); ret = -EINVAL; } + IWL_DEBUG_WEP("Set dynamic key: alg= %d len=%d idx=%d sta=%d ret=%d\n", + keyconf->alg, keyconf->keylen, keyconf->keyidx, + sta_id, ret); + return ret; } +EXPORT_SYMBOL(iwl_set_dynamic_key); #ifdef CONFIG_IWLWIFI_DEBUG static void iwl_dump_lq_cmd(struct iwl_priv *priv, @@ -345,11 +825,171 @@ int iwl_send_lq_cmd(struct iwl_priv *priv, iwl_dump_lq_cmd(priv,lq); - if (iwl_is_associated(priv) && priv->assoc_station_added && - priv->lq_mngr.lq_ready) + if (iwl_is_associated(priv) && priv->assoc_station_added) return iwl_send_cmd(priv, &cmd); return 0; } EXPORT_SYMBOL(iwl_send_lq_cmd); +/** + * iwl_sta_init_lq - Initialize a station's hardware rate table + * + * The uCode's station table contains a table of fallback rates + * for automatic fallback during transmission. + * + * NOTE: This sets up a default set of values. These will be replaced later + * if the driver's iwl-4965-rs rate scaling algorithm is used, instead of + * rc80211_simple. + * + * NOTE: Run REPLY_ADD_STA command to set up station table entry, before + * 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) +{ + int i, r; + struct iwl_link_quality_cmd link_cmd = { + .reserved1 = 0, + }; + u16 rate_flags; + + /* Set up the rate scaling to start at selected rate, fall back + * all the way down to 1M in IEEE order, and then spin on 1M */ + if (is_ap) + r = IWL_RATE_54M_INDEX; + else if (priv->band == IEEE80211_BAND_5GHZ) + r = IWL_RATE_6M_INDEX; + else + r = IWL_RATE_1M_INDEX; + + for (i = 0; i < LINK_QUAL_MAX_RETRY_NUM; i++) { + rate_flags = 0; + if (r >= IWL_FIRST_CCK_RATE && r <= IWL_LAST_CCK_RATE) + rate_flags |= RATE_MCS_CCK_MSK; + + /* Use Tx antenna B only */ + rate_flags |= RATE_MCS_ANT_B_MSK; /*FIXME:RS*/ + + link_cmd.rs_table[i].rate_n_flags = + iwl_hw_set_rate_n_flags(iwl_rates[r].plcp, rate_flags); + r = iwl4965_get_prev_ieee_rate(r); + } + + link_cmd.general_params.single_stream_ant_msk = 2; + 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); + + /* 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; + + iwl_send_cmd_pdu_async(priv, REPLY_TX_LINK_QUALITY_CMD, + sizeof(link_cmd), &link_cmd, NULL); +} + +/** + * iwl_rxon_add_station - add station into station table. + * + * there is only one AP station with id= IWL_AP_ID + * NOTE: mutex must be held before calling this fnction + */ +int iwl_rxon_add_station(struct iwl_priv *priv, const u8 *addr, int is_ap) +{ + u8 sta_id; + + /* Add station to device's station table */ + struct ieee80211_conf *conf = &priv->hw->conf; + struct ieee80211_ht_info *cur_ht_config = &conf->ht_conf; + + if ((is_ap) && + (conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE) && + (priv->iw_mode == IEEE80211_IF_TYPE_STA)) + sta_id = iwl_add_station_flags(priv, addr, is_ap, + 0, cur_ht_config); + else + sta_id = iwl_add_station_flags(priv, addr, is_ap, + 0, NULL); + + /* Set up default rate scaling table in device's station table */ + iwl_sta_init_lq(priv, addr, is_ap); + + return sta_id; +} +EXPORT_SYMBOL(iwl_rxon_add_station); + +/** + * iwl_get_sta_id - Find station's index within station table + * + * If new IBSS station, create new entry in station table + */ +int iwl_get_sta_id(struct iwl_priv *priv, struct ieee80211_hdr *hdr) +{ + int sta_id; + u16 fc = le16_to_cpu(hdr->frame_control); + DECLARE_MAC_BUF(mac); + + /* 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 IEEE80211_IF_TYPE_STA: + return IWL_AP_ID; + + /* If we are an AP, then find the station, or use BCAST */ + case IEEE80211_IF_TYPE_AP: + sta_id = iwl_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 IEEE80211_IF_TYPE_IBSS: + sta_id = iwl_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, + 0, CMD_ASYNC, NULL); + + if (sta_id != IWL_INVALID_STATION) + return sta_id; + + IWL_DEBUG_DROP("Station %s not in station map. " + "Defaulting to broadcast...\n", + print_mac(mac, hdr->addr1)); + iwl_print_hex_dump(priv, IWL_DL_DROP, (u8 *) hdr, sizeof(*hdr)); + return priv->hw_params.bcast_sta_id; + + default: + IWL_WARNING("Unknown mode of operation: %d", priv->iw_mode); + return priv->hw_params.bcast_sta_id; + } +} +EXPORT_SYMBOL(iwl_get_sta_id); + +/** + * iwl_sta_modify_enable_tid_tx - Enable Tx for this TID in station table + */ +void iwl_sta_modify_enable_tid_tx(struct iwl_priv *priv, int sta_id, int tid) +{ + unsigned long flags; + + /* Remove "disable" flag, to enable Tx for this TID */ + spin_lock_irqsave(&priv->sta_lock, flags); + priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_TID_DISABLE_TX; + priv->stations[sta_id].sta.tid_disable_tx &= cpu_to_le16(~(1 << tid)); + priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK; + spin_unlock_irqrestore(&priv->sta_lock, flags); + + iwl_send_add_sta(priv, &priv->stations[sta_id].sta, CMD_ASYNC); +} +EXPORT_SYMBOL(iwl_sta_modify_enable_tid_tx); + diff --git a/drivers/net/wireless/iwlwifi/iwl-sta.h b/drivers/net/wireless/iwlwifi/iwl-sta.h index 44f272ecc827..221b93e670a6 100644 --- a/drivers/net/wireless/iwlwifi/iwl-sta.h +++ b/drivers/net/wireless/iwlwifi/iwl-sta.h @@ -29,21 +29,27 @@ #ifndef __iwl_sta_h__ #define __iwl_sta_h__ -#include <net/mac80211.h> +#define HW_KEY_DYNAMIC 0 +#define HW_KEY_DEFAULT 1 -#include "iwl-eeprom.h" -#include "iwl-core.h" -#include "iwl-4965.h" -#include "iwl-io.h" -#include "iwl-helpers.h" +/** + * iwl_find_station - Find station id for a given BSSID + * @bssid: MAC address of station ID to find + */ +u8 iwl_find_station(struct iwl_priv *priv, const u8 *bssid); -int iwl_get_free_ucode_key_index(struct iwl_priv *priv); int iwl_send_static_wepkey_cmd(struct iwl_priv *priv, u8 send_if_empty); int iwl_remove_default_wep_key(struct iwl_priv *priv, - struct ieee80211_key_conf *key); + struct ieee80211_key_conf *key); int iwl_set_default_wep_key(struct iwl_priv *priv, - struct ieee80211_key_conf *key); -int iwl_remove_dynamic_key(struct iwl_priv *priv, u8 sta_id); + struct ieee80211_key_conf *key); int iwl_set_dynamic_key(struct iwl_priv *priv, - struct ieee80211_key_conf *key, u8 sta_id); + struct ieee80211_key_conf *key, u8 sta_id); +int iwl_remove_dynamic_key(struct iwl_priv *priv, + struct ieee80211_key_conf *key, u8 sta_id); +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_get_sta_id(struct iwl_priv *priv, struct ieee80211_hdr *hdr); +void iwl_sta_modify_enable_tid_tx(struct iwl_priv *priv, int sta_id, int tid); +int iwl_get_ra_sta_id(struct iwl_priv *priv, struct ieee80211_hdr *hdr); #endif /* __iwl_sta_h__ */ diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c new file mode 100644 index 000000000000..9b50b1052b09 --- /dev/null +++ b/drivers/net/wireless/iwlwifi/iwl-tx.c @@ -0,0 +1,1519 @@ +/****************************************************************************** + * + * Copyright(c) 2003 - 2008 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: + * James P. Ketrenos <ipw2100-admin@linux.intel.com> + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + * + *****************************************************************************/ + +#include <linux/etherdevice.h> +#include <net/mac80211.h> +#include "iwl-eeprom.h" +#include "iwl-dev.h" +#include "iwl-core.h" +#include "iwl-sta.h" +#include "iwl-io.h" +#include "iwl-helpers.h" + +static const u16 default_tid_to_tx_fifo[] = { + IWL_TX_FIFO_AC1, + IWL_TX_FIFO_AC0, + IWL_TX_FIFO_AC0, + IWL_TX_FIFO_AC1, + IWL_TX_FIFO_AC2, + IWL_TX_FIFO_AC2, + IWL_TX_FIFO_AC3, + IWL_TX_FIFO_AC3, + IWL_TX_FIFO_NONE, + IWL_TX_FIFO_NONE, + IWL_TX_FIFO_NONE, + IWL_TX_FIFO_NONE, + IWL_TX_FIFO_NONE, + IWL_TX_FIFO_NONE, + IWL_TX_FIFO_NONE, + IWL_TX_FIFO_NONE, + IWL_TX_FIFO_AC3 +}; + + +/** + * iwl_hw_txq_free_tfd - Free all chunks referenced by TFD [txq->q.read_ptr] + * + * Does NOT advance any TFD circular buffer read/write indexes + * Does NOT free the TFD itself (which is within circular buffer) + */ +int iwl_hw_txq_free_tfd(struct iwl_priv *priv, struct iwl_tx_queue *txq) +{ + struct iwl_tfd_frame *bd_tmp = (struct iwl_tfd_frame *)&txq->bd[0]; + struct iwl_tfd_frame *bd = &bd_tmp[txq->q.read_ptr]; + struct pci_dev *dev = priv->pci_dev; + int i; + int counter = 0; + int index, is_odd; + + /* Host command buffers stay mapped in memory, nothing to clean */ + if (txq->q.id == IWL_CMD_QUEUE_NUM) + return 0; + + /* Sanity check on number of chunks */ + counter = IWL_GET_BITS(*bd, num_tbs); + if (counter > MAX_NUM_OF_TBS) { + IWL_ERROR("Too many chunks: %i\n", counter); + /* @todo issue fatal error, it is quite serious situation */ + return 0; + } + + /* Unmap chunks, if any. + * TFD info for odd chunks is different format than for even chunks. */ + for (i = 0; i < counter; i++) { + index = i / 2; + is_odd = i & 0x1; + + if (is_odd) + pci_unmap_single( + dev, + IWL_GET_BITS(bd->pa[index], tb2_addr_lo16) | + (IWL_GET_BITS(bd->pa[index], + tb2_addr_hi20) << 16), + IWL_GET_BITS(bd->pa[index], tb2_len), + PCI_DMA_TODEVICE); + + else if (i > 0) + pci_unmap_single(dev, + le32_to_cpu(bd->pa[index].tb1_addr), + IWL_GET_BITS(bd->pa[index], tb1_len), + PCI_DMA_TODEVICE); + + /* Free SKB, if any, for this chunk */ + if (txq->txb[txq->q.read_ptr].skb[i]) { + struct sk_buff *skb = txq->txb[txq->q.read_ptr].skb[i]; + + dev_kfree_skb(skb); + txq->txb[txq->q.read_ptr].skb[i] = NULL; + } + } + return 0; +} +EXPORT_SYMBOL(iwl_hw_txq_free_tfd); + + +int iwl_hw_txq_attach_buf_to_tfd(struct iwl_priv *priv, void *ptr, + dma_addr_t addr, u16 len) +{ + int index, is_odd; + struct iwl_tfd_frame *tfd = ptr; + u32 num_tbs = IWL_GET_BITS(*tfd, num_tbs); + + /* Each TFD can point to a maximum 20 Tx buffers */ + if ((num_tbs >= MAX_NUM_OF_TBS) || (num_tbs < 0)) { + IWL_ERROR("Error can not send more than %d chunks\n", + MAX_NUM_OF_TBS); + return -EINVAL; + } + + index = num_tbs / 2; + is_odd = num_tbs & 0x1; + + if (!is_odd) { + tfd->pa[index].tb1_addr = cpu_to_le32(addr); + IWL_SET_BITS(tfd->pa[index], tb1_addr_hi, + iwl_get_dma_hi_address(addr)); + IWL_SET_BITS(tfd->pa[index], tb1_len, len); + } else { + IWL_SET_BITS(tfd->pa[index], tb2_addr_lo16, + (u32) (addr & 0xffff)); + IWL_SET_BITS(tfd->pa[index], tb2_addr_hi20, addr >> 16); + IWL_SET_BITS(tfd->pa[index], tb2_len, len); + } + + IWL_SET_BITS(*tfd, num_tbs, num_tbs + 1); + + return 0; +} +EXPORT_SYMBOL(iwl_hw_txq_attach_buf_to_tfd); + +/** + * iwl_txq_update_write_ptr - Send new write index to hardware + */ +int iwl_txq_update_write_ptr(struct iwl_priv *priv, struct iwl_tx_queue *txq) +{ + u32 reg = 0; + int ret = 0; + int txq_id = txq->q.id; + + if (txq->need_update == 0) + return ret; + + /* if we're trying to save power */ + if (test_bit(STATUS_POWER_PMI, &priv->status)) { + /* wake up nic if it's powered down ... + * uCode will wake up, and interrupt us again, so next + * time we'll skip this part. */ + reg = iwl_read32(priv, CSR_UCODE_DRV_GP1); + + if (reg & CSR_UCODE_DRV_GP1_BIT_MAC_SLEEP) { + IWL_DEBUG_INFO("Requesting wakeup, GP1 = 0x%x\n", reg); + iwl_set_bit(priv, CSR_GP_CNTRL, + CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); + 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). */ + } else + iwl_write32(priv, HBUS_TARG_WRPTR, + txq->q.write_ptr | (txq_id << 8)); + + txq->need_update = 0; + + return ret; +} +EXPORT_SYMBOL(iwl_txq_update_write_ptr); + + +/** + * iwl_tx_queue_free - Deallocate DMA queue. + * @txq: Transmit queue to deallocate. + * + * Empty queue by removing and destroying all BD's. + * Free all buffers. + * 0-fill, but do not free "txq" descriptor structure. + */ +static void iwl_tx_queue_free(struct iwl_priv *priv, struct iwl_tx_queue *txq) +{ + struct iwl_queue *q = &txq->q; + struct pci_dev *dev = priv->pci_dev; + int len; + + if (q->n_bd == 0) + return; + + /* first, empty all BD's */ + for (; q->write_ptr != q->read_ptr; + q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd)) + iwl_hw_txq_free_tfd(priv, txq); + + len = sizeof(struct iwl_cmd) * q->n_window; + if (q->id == IWL_CMD_QUEUE_NUM) + len += IWL_MAX_SCAN_SIZE; + + /* De-alloc array of command/tx buffers */ + pci_free_consistent(dev, len, txq->cmd, txq->dma_addr_cmd); + + /* De-alloc circular buffer of TFDs */ + if (txq->q.n_bd) + pci_free_consistent(dev, sizeof(struct iwl_tfd_frame) * + txq->q.n_bd, txq->bd, txq->q.dma_addr); + + /* De-alloc array of per-TFD driver data */ + kfree(txq->txb); + txq->txb = NULL; + + /* 0-fill queue descriptor structure */ + memset(txq, 0, sizeof(*txq)); +} + +/*************** DMA-QUEUE-GENERAL-FUNCTIONS ***** + * DMA services + * + * Theory of operation + * + * A Tx or Rx queue resides in host DRAM, and is comprised of a circular buffer + * of buffer descriptors, each of which points to one or more data buffers for + * the device to read from or fill. Driver and device exchange status of each + * queue via "read" and "write" pointers. Driver keeps minimum of 2 empty + * entries in each circular buffer, to protect against confusing empty and full + * queue states. + * + * The device reads or writes the data in the queues via the device's several + * DMA/FIFO channels. Each queue is mapped to a single DMA channel. + * + * For Tx queue, there are low mark and high mark limits. If, after queuing + * the packet for Tx, free space become < low mark, Tx queue stopped. When + * reclaiming packets (on 'tx done IRQ), if free space become > high mark, + * Tx queue resumed. + * + * See more detailed info in iwl-4965-hw.h. + ***************************************************/ + +int iwl_queue_space(const struct iwl_queue *q) +{ + int s = q->read_ptr - q->write_ptr; + + if (q->read_ptr > q->write_ptr) + s -= q->n_bd; + + if (s <= 0) + s += q->n_window; + /* keep some reserve to not confuse empty and full situations */ + s -= 2; + if (s < 0) + s = 0; + return s; +} +EXPORT_SYMBOL(iwl_queue_space); + + +/** + * iwl_queue_init - Initialize queue's high/low-water and read/write indexes + */ +static int iwl_queue_init(struct iwl_priv *priv, struct iwl_queue *q, + int count, int slots_num, u32 id) +{ + q->n_bd = count; + q->n_window = slots_num; + q->id = id; + + /* count must be power-of-two size, otherwise iwl_queue_inc_wrap + * and iwl_queue_dec_wrap are broken. */ + BUG_ON(!is_power_of_2(count)); + + /* slots_num must be power-of-two size, otherwise + * get_cmd_index is broken. */ + BUG_ON(!is_power_of_2(slots_num)); + + q->low_mark = q->n_window / 4; + if (q->low_mark < 4) + q->low_mark = 4; + + q->high_mark = q->n_window / 8; + if (q->high_mark < 2) + q->high_mark = 2; + + q->write_ptr = q->read_ptr = 0; + + return 0; +} + +/** + * iwl_tx_queue_alloc - Alloc driver data and TFD CB for one Tx/cmd queue + */ +static int iwl_tx_queue_alloc(struct iwl_priv *priv, + struct iwl_tx_queue *txq, u32 id) +{ + struct pci_dev *dev = priv->pci_dev; + + /* Driver private data, only for Tx (not command) queues, + * not shared with device. */ + if (id != IWL_CMD_QUEUE_NUM) { + txq->txb = kmalloc(sizeof(txq->txb[0]) * + TFD_QUEUE_SIZE_MAX, GFP_KERNEL); + if (!txq->txb) { + IWL_ERROR("kmalloc for auxiliary BD " + "structures failed\n"); + goto error; + } + } else + txq->txb = NULL; + + /* Circular buffer of transmit frame descriptors (TFDs), + * shared with device */ + txq->bd = pci_alloc_consistent(dev, + sizeof(txq->bd[0]) * TFD_QUEUE_SIZE_MAX, + &txq->q.dma_addr); + + if (!txq->bd) { + IWL_ERROR("pci_alloc_consistent(%zd) failed\n", + sizeof(txq->bd[0]) * TFD_QUEUE_SIZE_MAX); + goto error; + } + txq->q.id = id; + + return 0; + + error: + kfree(txq->txb); + txq->txb = NULL; + + return -ENOMEM; +} + +/* + * Tell nic where to find circular buffer of Tx Frame Descriptors for + * given Tx queue, and enable the DMA channel used for that queue. + * + * 4965 supports up to 16 Tx queues in DRAM, mapped to up to 8 Tx DMA + * channels supported in hardware. + */ +static int iwl_hw_tx_queue_init(struct iwl_priv *priv, + struct iwl_tx_queue *txq) +{ + int rc; + unsigned long flags; + int txq_id = txq->q.id; + + spin_lock_irqsave(&priv->lock, flags); + rc = iwl_grab_nic_access(priv); + if (rc) { + spin_unlock_irqrestore(&priv->lock, flags); + return rc; + } + + /* Circular buffer (TFD queue in DRAM) physical base address */ + iwl_write_direct32(priv, FH_MEM_CBBC_QUEUE(txq_id), + txq->q.dma_addr >> 8); + + /* Enable DMA channel, using same id as for TFD queue */ + iwl_write_direct32( + priv, FH_TCSR_CHNL_TX_CONFIG_REG(txq_id), + FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE | + FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_ENABLE_VAL); + iwl_release_nic_access(priv); + spin_unlock_irqrestore(&priv->lock, flags); + + return 0; +} + +/** + * iwl_tx_queue_init - Allocate and initialize one tx/cmd queue + */ +static int iwl_tx_queue_init(struct iwl_priv *priv, + struct iwl_tx_queue *txq, + int slots_num, u32 txq_id) +{ + struct pci_dev *dev = priv->pci_dev; + int len; + int rc = 0; + + /* + * Alloc buffer array for commands (Tx or other types of commands). + * For the command queue (#4), allocate command space + one big + * command for scan, since scan command is very huge; the system will + * not have two scans at the same time, so only one is needed. + * For normal Tx queues (all other queues), no super-size command + * space is needed. + */ + len = sizeof(struct iwl_cmd) * slots_num; + if (txq_id == IWL_CMD_QUEUE_NUM) + len += IWL_MAX_SCAN_SIZE; + txq->cmd = pci_alloc_consistent(dev, len, &txq->dma_addr_cmd); + if (!txq->cmd) + return -ENOMEM; + + /* Alloc driver data array and TFD circular buffer */ + rc = iwl_tx_queue_alloc(priv, txq, txq_id); + if (rc) { + pci_free_consistent(dev, len, txq->cmd, txq->dma_addr_cmd); + + return -ENOMEM; + } + txq->need_update = 0; + + /* TFD_QUEUE_SIZE_MAX must be power-of-two size, otherwise + * iwl_queue_inc_wrap and iwl_queue_dec_wrap are broken. */ + BUILD_BUG_ON(TFD_QUEUE_SIZE_MAX & (TFD_QUEUE_SIZE_MAX - 1)); + + /* Initialize queue's high/low-water marks, and head/tail indexes */ + iwl_queue_init(priv, &txq->q, TFD_QUEUE_SIZE_MAX, slots_num, txq_id); + + /* Tell device where to find queue */ + iwl_hw_tx_queue_init(priv, txq); + + return 0; +} +/** + * iwl_hw_txq_ctx_free - Free TXQ Context + * + * Destroy all TX DMA queues and structures + */ +void iwl_hw_txq_ctx_free(struct iwl_priv *priv) +{ + int txq_id; + + /* Tx queues */ + for (txq_id = 0; txq_id < priv->hw_params.max_txq_num; txq_id++) + iwl_tx_queue_free(priv, &priv->txq[txq_id]); + + /* Keep-warm buffer */ + iwl_kw_free(priv); +} +EXPORT_SYMBOL(iwl_hw_txq_ctx_free); + + +/** + * iwl_txq_ctx_reset - Reset TX queue context + * Destroys all DMA structures and initialise them again + * + * @param priv + * @return error code + */ +int iwl_txq_ctx_reset(struct iwl_priv *priv) +{ + int ret = 0; + int txq_id, slots_num; + unsigned long flags; + + iwl_kw_free(priv); + + /* Free all tx/cmd queues and keep-warm buffer */ + iwl_hw_txq_ctx_free(priv); + + /* Alloc keep-warm buffer */ + ret = iwl_kw_alloc(priv); + if (ret) { + IWL_ERROR("Keep Warm allocation failed"); + 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); + + iwl_release_nic_access(priv); + spin_unlock_irqrestore(&priv->lock, flags); + + + /* Tell nic where to find the keep-warm buffer */ + ret = iwl_kw_init(priv); + if (ret) { + IWL_ERROR("kw_init failed\n"); + goto error_reset; + } + + /* Alloc and init all Tx queues, including the command queue (#4) */ + for (txq_id = 0; txq_id < priv->hw_params.max_txq_num; txq_id++) { + slots_num = (txq_id == IWL_CMD_QUEUE_NUM) ? + TFD_CMD_SLOTS : TFD_TX_CMD_SLOTS; + ret = iwl_tx_queue_init(priv, &priv->txq[txq_id], slots_num, + txq_id); + if (ret) { + IWL_ERROR("Tx %d queue init failed\n", txq_id); + goto error; + } + } + + return ret; + + error: + iwl_hw_txq_ctx_free(priv); + error_reset: + iwl_kw_free(priv); + error_kw: + return ret; +} +/** + * iwl_txq_ctx_stop - Stop all Tx DMA channels, free Tx queue memory + */ +void iwl_txq_ctx_stop(struct iwl_priv *priv) +{ + + int txq_id; + unsigned long flags; + + + /* 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); + + /* Stop each Tx DMA channel, and wait for it to be idle */ + for (txq_id = 0; txq_id < priv->hw_params.max_txq_num; txq_id++) { + iwl_write_direct32(priv, + FH_TCSR_CHNL_TX_CONFIG_REG(txq_id), 0x0); + iwl_poll_direct_bit(priv, FH_TSSR_TX_STATUS_REG, + FH_TSSR_TX_STATUS_REG_MSK_CHNL_IDLE + (txq_id), 200); + } + iwl_release_nic_access(priv); + spin_unlock_irqrestore(&priv->lock, flags); + + /* Deallocate memory for all Tx queues */ + iwl_hw_txq_ctx_free(priv); +} +EXPORT_SYMBOL(iwl_txq_ctx_stop); + +/* + * handle build REPLY_TX command notification. + */ +static void iwl_tx_cmd_build_basic(struct iwl_priv *priv, + struct iwl_tx_cmd *tx_cmd, + struct ieee80211_tx_info *info, + struct ieee80211_hdr *hdr, + int is_unicast, u8 std_id) +{ + __le16 fc = hdr->frame_control; + __le32 tx_flags = tx_cmd->tx_flags; + + tx_cmd->stop_time.life_time = TX_CMD_LIFE_TIME_INFINITE; + if (!(info->flags & IEEE80211_TX_CTL_NO_ACK)) { + tx_flags |= TX_CMD_FLG_ACK_MSK; + if (ieee80211_is_mgmt(fc)) + tx_flags |= TX_CMD_FLG_SEQ_CTL_MSK; + if (ieee80211_is_probe_resp(fc) && + !(le16_to_cpu(hdr->seq_ctrl) & 0xf)) + tx_flags |= TX_CMD_FLG_TSF_MSK; + } else { + tx_flags &= (~TX_CMD_FLG_ACK_MSK); + tx_flags |= TX_CMD_FLG_SEQ_CTL_MSK; + } + + if (ieee80211_is_back_req(fc)) + tx_flags |= TX_CMD_FLG_ACK_MSK | TX_CMD_FLG_IMM_BA_RSP_MASK; + + + tx_cmd->sta_id = std_id; + if (ieee80211_has_morefrags(fc)) + tx_flags |= TX_CMD_FLG_MORE_FRAG_MSK; + + if (ieee80211_is_data_qos(fc)) { + u8 *qc = ieee80211_get_qos_ctl(hdr); + tx_cmd->tid_tspec = qc[0] & 0xf; + tx_flags &= ~TX_CMD_FLG_SEQ_CTL_MSK; + } else { + tx_flags |= TX_CMD_FLG_SEQ_CTL_MSK; + } + + priv->cfg->ops->utils->rts_tx_cmd_flag(info, &tx_flags); + + if ((tx_flags & TX_CMD_FLG_RTS_MSK) || (tx_flags & TX_CMD_FLG_CTS_MSK)) + tx_flags |= TX_CMD_FLG_FULL_TXOP_PROT_MSK; + + tx_flags &= ~(TX_CMD_FLG_ANT_SEL_MSK); + if (ieee80211_is_mgmt(fc)) { + if (ieee80211_is_assoc_req(fc) || ieee80211_is_reassoc_req(fc)) + tx_cmd->timeout.pm_frame_timeout = cpu_to_le16(3); + else + tx_cmd->timeout.pm_frame_timeout = cpu_to_le16(2); + } else { + tx_cmd->timeout.pm_frame_timeout = 0; + } + + tx_cmd->driver_txop = 0; + tx_cmd->tx_flags = tx_flags; + tx_cmd->next_frame_len = 0; +} + +#define RTS_HCCA_RETRY_LIMIT 3 +#define RTS_DFAULT_RETRY_LIMIT 60 + +static void iwl_tx_cmd_build_rate(struct iwl_priv *priv, + struct iwl_tx_cmd *tx_cmd, + struct ieee80211_tx_info *info, + __le16 fc, int sta_id, + int is_hcca) +{ + u8 rts_retry_limit = 0; + u8 data_retry_limit = 0; + u8 rate_plcp; + u16 rate_flags = 0; + int rate_idx; + + rate_idx = min(ieee80211_get_tx_rate(priv->hw, info)->hw_value & 0xffff, + IWL_RATE_COUNT - 1); + + rate_plcp = iwl_rates[rate_idx].plcp; + + rts_retry_limit = (is_hcca) ? + RTS_HCCA_RETRY_LIMIT : RTS_DFAULT_RETRY_LIMIT; + + if ((rate_idx >= IWL_FIRST_CCK_RATE) && (rate_idx <= IWL_LAST_CCK_RATE)) + rate_flags |= RATE_MCS_CCK_MSK; + + + if (ieee80211_is_probe_resp(fc)) { + data_retry_limit = 3; + if (data_retry_limit < rts_retry_limit) + rts_retry_limit = data_retry_limit; + } else + data_retry_limit = IWL_DEFAULT_TX_RETRY; + + if (priv->data_retry_limit != -1) + data_retry_limit = priv->data_retry_limit; + + + if (ieee80211_is_data(fc)) { + tx_cmd->initial_rate_index = 0; + tx_cmd->tx_flags |= TX_CMD_FLG_STA_RATE_MSK; + } else { + switch (fc & cpu_to_le16(IEEE80211_FCTL_STYPE)) { + case cpu_to_le16(IEEE80211_STYPE_AUTH): + case cpu_to_le16(IEEE80211_STYPE_DEAUTH): + case cpu_to_le16(IEEE80211_STYPE_ASSOC_REQ): + case cpu_to_le16(IEEE80211_STYPE_REASSOC_REQ): + if (tx_cmd->tx_flags & TX_CMD_FLG_RTS_MSK) { + tx_cmd->tx_flags &= ~TX_CMD_FLG_RTS_MSK; + tx_cmd->tx_flags |= TX_CMD_FLG_CTS_MSK; + } + break; + default: + break; + } + + /* Alternate between antenna A and B for successive frames */ + if (priv->use_ant_b_for_management_frame) { + priv->use_ant_b_for_management_frame = 0; + rate_flags |= RATE_MCS_ANT_B_MSK; + } else { + priv->use_ant_b_for_management_frame = 1; + rate_flags |= RATE_MCS_ANT_A_MSK; + } + } + + tx_cmd->rts_retry_limit = rts_retry_limit; + tx_cmd->data_retry_limit = data_retry_limit; + tx_cmd->rate_n_flags = iwl_hw_set_rate_n_flags(rate_plcp, rate_flags); +} + +static void iwl_tx_cmd_build_hwcrypto(struct iwl_priv *priv, + struct ieee80211_tx_info *info, + struct iwl_tx_cmd *tx_cmd, + struct sk_buff *skb_frag, + int sta_id) +{ + struct ieee80211_key_conf *keyconf = info->control.hw_key; + + switch (keyconf->alg) { + case ALG_CCMP: + tx_cmd->sec_ctl = TX_CMD_SEC_CCM; + memcpy(tx_cmd->key, keyconf->key, keyconf->keylen); + if (info->flags & IEEE80211_TX_CTL_AMPDU) + tx_cmd->tx_flags |= TX_CMD_FLG_AGG_CCMP_MSK; + IWL_DEBUG_TX("tx_cmd with aes hwcrypto\n"); + break; + + case ALG_TKIP: + tx_cmd->sec_ctl = TX_CMD_SEC_TKIP; + ieee80211_get_tkip_key(keyconf, skb_frag, + IEEE80211_TKIP_P2_KEY, tx_cmd->key); + IWL_DEBUG_TX("tx_cmd with tkip hwcrypto\n"); + break; + + case ALG_WEP: + tx_cmd->sec_ctl |= (TX_CMD_SEC_WEP | + (keyconf->keyidx & TX_CMD_SEC_MSK) << TX_CMD_SEC_SHIFT); + + if (keyconf->keylen == WEP_KEY_LEN_128) + tx_cmd->sec_ctl |= TX_CMD_SEC_KEY128; + + memcpy(&tx_cmd->key[3], keyconf->key, keyconf->keylen); + + IWL_DEBUG_TX("Configuring packet for WEP encryption " + "with key %d\n", keyconf->keyidx); + break; + + default: + printk(KERN_ERR "Unknown encode alg %d\n", keyconf->alg); + break; + } +} + +static void iwl_update_tx_stats(struct iwl_priv *priv, u16 fc, u16 len) +{ + /* 0 - mgmt, 1 - cnt, 2 - data */ + int idx = (fc & IEEE80211_FCTL_FTYPE) >> 2; + priv->tx_stats[idx].cnt++; + priv->tx_stats[idx].bytes += len; +} + +/* + * start REPLY_TX command process + */ +int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) +{ + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + struct iwl_tfd_frame *tfd; + u32 *control_flags; + int txq_id = skb_get_queue_mapping(skb); + struct iwl_tx_queue *txq = NULL; + struct iwl_queue *q = NULL; + dma_addr_t phys_addr; + dma_addr_t txcmd_phys; + dma_addr_t scratch_phys; + struct iwl_cmd *out_cmd = NULL; + struct iwl_tx_cmd *tx_cmd; + u16 len, idx, len_org; + u16 seq_number = 0; + u8 id, hdr_len, unicast; + u8 sta_id; + __le16 fc; + u8 wait_write_ptr = 0; + u8 tid = 0; + u8 *qc = NULL; + unsigned long flags; + int ret; + + spin_lock_irqsave(&priv->lock, flags); + if (iwl_is_rfkill(priv)) { + IWL_DEBUG_DROP("Dropping - RF KILL\n"); + goto drop_unlock; + } + + if (!priv->vif) { + IWL_DEBUG_DROP("Dropping - !priv->vif\n"); + goto drop_unlock; + } + + if ((ieee80211_get_tx_rate(priv->hw, info)->hw_value & 0xFF) == + IWL_INVALID_RATE) { + IWL_ERROR("ERROR: No TX rate available.\n"); + goto drop_unlock; + } + + unicast = !is_multicast_ether_addr(hdr->addr1); + id = 0; + + fc = hdr->frame_control; + +#ifdef CONFIG_IWLWIFI_DEBUG + if (ieee80211_is_auth(fc)) + IWL_DEBUG_TX("Sending AUTH frame\n"); + else if (ieee80211_is_assoc_req(fc)) + IWL_DEBUG_TX("Sending ASSOC frame\n"); + else if (ieee80211_is_reassoc_req(fc)) + IWL_DEBUG_TX("Sending REASSOC frame\n"); +#endif + + /* drop all data frame if we are not associated */ + if (ieee80211_is_data(fc) && + (!iwl_is_associated(priv) || + ((priv->iw_mode == IEEE80211_IF_TYPE_STA) && !priv->assoc_id) || + !priv->assoc_station_added)) { + IWL_DEBUG_DROP("Dropping - !iwl_is_associated\n"); + goto drop_unlock; + } + + spin_unlock_irqrestore(&priv->lock, flags); + + hdr_len = ieee80211_get_hdrlen(le16_to_cpu(fc)); + + /* Find (or create) index into station table for destination station */ + sta_id = iwl_get_sta_id(priv, hdr); + if (sta_id == IWL_INVALID_STATION) { + DECLARE_MAC_BUF(mac); + + IWL_DEBUG_DROP("Dropping - INVALID STATION: %s\n", + print_mac(mac, hdr->addr1)); + goto drop; + } + + IWL_DEBUG_TX("station Id %d\n", sta_id); + + if (ieee80211_is_data_qos(fc)) { + qc = ieee80211_get_qos_ctl(hdr); + tid = qc[0] & 0xf; + seq_number = priv->stations[sta_id].tid[tid].seq_number & + IEEE80211_SCTL_SEQ; + hdr->seq_ctrl = cpu_to_le16(seq_number) | + (hdr->seq_ctrl & + __constant_cpu_to_le16(IEEE80211_SCTL_FRAG)); + seq_number += 0x10; + /* aggregation is on for this <sta,tid> */ + if (info->flags & IEEE80211_TX_CTL_AMPDU) + txq_id = priv->stations[sta_id].tid[tid].agg.txq_id; + priv->stations[sta_id].tid[tid].tfds_in_queue++; + } + + /* Descriptor for chosen Tx queue */ + txq = &priv->txq[txq_id]; + q = &txq->q; + + spin_lock_irqsave(&priv->lock, flags); + + /* Set up first empty TFD within this queue's circular TFD buffer */ + tfd = &txq->bd[q->write_ptr]; + memset(tfd, 0, sizeof(*tfd)); + control_flags = (u32 *) tfd; + idx = get_cmd_index(q, q->write_ptr, 0); + + /* Set up driver data for this TFD */ + memset(&(txq->txb[q->write_ptr]), 0, sizeof(struct iwl_tx_info)); + txq->txb[q->write_ptr].skb[0] = skb; + + /* Set up first empty entry in queue's array of Tx/cmd buffers */ + out_cmd = &txq->cmd[idx]; + tx_cmd = &out_cmd->cmd.tx; + memset(&out_cmd->hdr, 0, sizeof(out_cmd->hdr)); + memset(tx_cmd, 0, sizeof(struct iwl_tx_cmd)); + + /* + * Set up the Tx-command (not MAC!) header. + * Store the chosen Tx queue and TFD index within the sequence field; + * after Tx, uCode's Tx response will return this value so driver can + * locate the frame within the tx queue and do post-tx processing. + */ + out_cmd->hdr.cmd = REPLY_TX; + out_cmd->hdr.sequence = cpu_to_le16((u16)(QUEUE_TO_SEQ(txq_id) | + INDEX_TO_SEQ(q->write_ptr))); + + /* Copy MAC header from skb into command buffer */ + memcpy(tx_cmd->hdr, hdr, hdr_len); + + /* + * Use the first empty entry in this queue's command buffer array + * to contain the Tx command and MAC header concatenated together + * (payload data will be in another buffer). + * Size of this varies, due to varying MAC header length. + * If end is not dword aligned, we'll have 2 extra bytes at the end + * of the MAC header (device reads on dword boundaries). + * We'll tell device about this padding later. + */ + len = sizeof(struct iwl_tx_cmd) + + sizeof(struct iwl_cmd_header) + hdr_len; + + len_org = len; + len = (len + 3) & ~3; + + if (len_org != len) + len_org = 1; + else + len_org = 0; + + /* Physical address of this Tx command's header (not MAC header!), + * within command buffer array. */ + txcmd_phys = txq->dma_addr_cmd + sizeof(struct iwl_cmd) * idx + + offsetof(struct iwl_cmd, hdr); + + /* Add buffer containing Tx command and MAC(!) header to TFD's + * first entry */ + iwl_hw_txq_attach_buf_to_tfd(priv, tfd, txcmd_phys, len); + + if (!(info->flags & IEEE80211_TX_CTL_DO_NOT_ENCRYPT)) + iwl_tx_cmd_build_hwcrypto(priv, info, tx_cmd, skb, sta_id); + + /* Set up TFD's 2nd entry to point directly to remainder of skb, + * if any (802.11 null frames have no payload). */ + len = skb->len - hdr_len; + if (len) { + phys_addr = pci_map_single(priv->pci_dev, skb->data + hdr_len, + len, PCI_DMA_TODEVICE); + iwl_hw_txq_attach_buf_to_tfd(priv, tfd, phys_addr, len); + } + + /* Tell NIC about any 2-byte padding after MAC header */ + if (len_org) + tx_cmd->tx_flags |= TX_CMD_FLG_MH_PAD_MSK; + + /* Total # bytes to be transmitted */ + len = (u16)skb->len; + tx_cmd->len = cpu_to_le16(len); + /* TODO need this for burst mode later on */ + iwl_tx_cmd_build_basic(priv, tx_cmd, info, hdr, unicast, sta_id); + + /* set is_hcca to 0; it probably will never be implemented */ + iwl_tx_cmd_build_rate(priv, tx_cmd, info, fc, sta_id, 0); + + iwl_update_tx_stats(priv, le16_to_cpu(fc), len); + + scratch_phys = txcmd_phys + sizeof(struct iwl_cmd_header) + + offsetof(struct iwl_tx_cmd, scratch); + tx_cmd->dram_lsb_ptr = cpu_to_le32(scratch_phys); + tx_cmd->dram_msb_ptr = iwl_get_dma_hi_address(scratch_phys); + + if (!ieee80211_has_morefrags(hdr->frame_control)) { + txq->need_update = 1; + if (qc) + priv->stations[sta_id].tid[tid].seq_number = seq_number; + } else { + wait_write_ptr = 1; + txq->need_update = 0; + } + + iwl_print_hex_dump(priv, IWL_DL_TX, (u8 *)tx_cmd, sizeof(*tx_cmd)); + + iwl_print_hex_dump(priv, IWL_DL_TX, (u8 *)tx_cmd->hdr, hdr_len); + + /* Set up entry for this TFD in Tx byte-count array */ + priv->cfg->ops->lib->txq_update_byte_cnt_tbl(priv, txq, len); + + /* Tell device the write index *just past* this latest filled TFD */ + q->write_ptr = iwl_queue_inc_wrap(q->write_ptr, q->n_bd); + ret = iwl_txq_update_write_ptr(priv, txq); + spin_unlock_irqrestore(&priv->lock, flags); + + if (ret) + return ret; + + if ((iwl_queue_space(q) < q->high_mark) + && priv->mac80211_registered) { + if (wait_write_ptr) { + spin_lock_irqsave(&priv->lock, flags); + txq->need_update = 1; + iwl_txq_update_write_ptr(priv, txq); + spin_unlock_irqrestore(&priv->lock, flags); + } + + ieee80211_stop_queue(priv->hw, skb_get_queue_mapping(skb)); + } + + return 0; + +drop_unlock: + spin_unlock_irqrestore(&priv->lock, flags); +drop: + return -1; +} +EXPORT_SYMBOL(iwl_tx_skb); + +/*************** HOST COMMAND QUEUE FUNCTIONS *****/ + +/** + * iwl_enqueue_hcmd - enqueue a uCode command + * @priv: device private data point + * @cmd: a point to the ucode command structure + * + * The function returns < 0 values to indicate the operation is + * failed. On success, it turns the index (> 0) of command in the + * command queue. + */ +int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd) +{ + struct iwl_tx_queue *txq = &priv->txq[IWL_CMD_QUEUE_NUM]; + struct iwl_queue *q = &txq->q; + struct iwl_tfd_frame *tfd; + u32 *control_flags; + struct iwl_cmd *out_cmd; + u32 idx; + u16 fix_size; + dma_addr_t phys_addr; + int ret; + unsigned long flags; + + cmd->len = priv->cfg->ops->utils->get_hcmd_size(cmd->id, cmd->len); + fix_size = (u16)(cmd->len + sizeof(out_cmd->hdr)); + + /* If any of the command structures end up being larger than + * the TFD_MAX_PAYLOAD_SIZE, and it sent as a 'small' command then + * we will need to increase the size of the TFD entries */ + BUG_ON((fix_size > TFD_MAX_PAYLOAD_SIZE) && + !(cmd->meta.flags & CMD_SIZE_HUGE)); + + if (iwl_is_rfkill(priv)) { + IWL_DEBUG_INFO("Not sending command - RF KILL"); + return -EIO; + } + + if (iwl_queue_space(q) < ((cmd->meta.flags & CMD_ASYNC) ? 2 : 1)) { + IWL_ERROR("No space for Tx\n"); + return -ENOSPC; + } + + spin_lock_irqsave(&priv->hcmd_lock, flags); + + tfd = &txq->bd[q->write_ptr]; + memset(tfd, 0, sizeof(*tfd)); + + control_flags = (u32 *) tfd; + + idx = get_cmd_index(q, q->write_ptr, cmd->meta.flags & CMD_SIZE_HUGE); + out_cmd = &txq->cmd[idx]; + + out_cmd->hdr.cmd = cmd->id; + memcpy(&out_cmd->meta, &cmd->meta, sizeof(cmd->meta)); + memcpy(&out_cmd->cmd.payload, cmd->data, cmd->len); + + /* At this point, the out_cmd now has all of the incoming cmd + * information */ + + out_cmd->hdr.flags = 0; + out_cmd->hdr.sequence = cpu_to_le16(QUEUE_TO_SEQ(IWL_CMD_QUEUE_NUM) | + INDEX_TO_SEQ(q->write_ptr)); + if (out_cmd->meta.flags & CMD_SIZE_HUGE) + out_cmd->hdr.sequence |= cpu_to_le16(SEQ_HUGE_FRAME); + + phys_addr = txq->dma_addr_cmd + sizeof(txq->cmd[0]) * idx + + offsetof(struct iwl_cmd, hdr); + iwl_hw_txq_attach_buf_to_tfd(priv, tfd, phys_addr, fix_size); + + IWL_DEBUG_HC("Sending command %s (#%x), seq: 0x%04X, " + "%d bytes at %d[%d]:%d\n", + get_cmd_string(out_cmd->hdr.cmd), + out_cmd->hdr.cmd, le16_to_cpu(out_cmd->hdr.sequence), + fix_size, q->write_ptr, idx, IWL_CMD_QUEUE_NUM); + + txq->need_update = 1; + + /* Set up entry in queue's byte count circular buffer */ + priv->cfg->ops->lib->txq_update_byte_cnt_tbl(priv, txq, 0); + + /* Increment and update queue's write index */ + q->write_ptr = iwl_queue_inc_wrap(q->write_ptr, q->n_bd); + ret = iwl_txq_update_write_ptr(priv, txq); + + spin_unlock_irqrestore(&priv->hcmd_lock, flags); + return ret ? ret : idx; +} + +int iwl_tx_queue_reclaim(struct iwl_priv *priv, int txq_id, int index) +{ + struct iwl_tx_queue *txq = &priv->txq[txq_id]; + struct iwl_queue *q = &txq->q; + struct iwl_tx_info *tx_info; + int nfreed = 0; + + if ((index >= q->n_bd) || (iwl_queue_used(q, index) == 0)) { + IWL_ERROR("Read index for DMA queue txq id (%d), index %d, " + "is out of range [0-%d] %d %d.\n", txq_id, + index, q->n_bd, q->write_ptr, q->read_ptr); + return 0; + } + + for (index = iwl_queue_inc_wrap(index, q->n_bd); q->read_ptr != index; + q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd)) { + + tx_info = &txq->txb[txq->q.read_ptr]; + ieee80211_tx_status_irqsafe(priv->hw, tx_info->skb[0]); + tx_info->skb[0] = NULL; + + if (priv->cfg->ops->lib->txq_inval_byte_cnt_tbl) + priv->cfg->ops->lib->txq_inval_byte_cnt_tbl(priv, txq); + + iwl_hw_txq_free_tfd(priv, txq); + nfreed++; + } + return nfreed; +} +EXPORT_SYMBOL(iwl_tx_queue_reclaim); + + +/** + * iwl_hcmd_queue_reclaim - Reclaim TX command queue entries already Tx'd + * + * When FW advances 'R' index, all entries between old and new 'R' index + * need to be reclaimed. As result, some free space forms. If there is + * enough free space (> low mark), wake the stack that feeds us. + */ +static void iwl_hcmd_queue_reclaim(struct iwl_priv *priv, int txq_id, int index) +{ + struct iwl_tx_queue *txq = &priv->txq[txq_id]; + struct iwl_queue *q = &txq->q; + int nfreed = 0; + + if ((index >= q->n_bd) || (iwl_queue_used(q, index) == 0)) { + IWL_ERROR("Read index for DMA queue txq id (%d), index %d, " + "is out of range [0-%d] %d %d.\n", txq_id, + index, q->n_bd, q->write_ptr, q->read_ptr); + return; + } + + for (index = iwl_queue_inc_wrap(index, q->n_bd); q->read_ptr != index; + q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd)) { + + if (nfreed > 1) { + IWL_ERROR("HCMD skipped: index (%d) %d %d\n", index, + q->write_ptr, q->read_ptr); + queue_work(priv->workqueue, &priv->restart); + } + nfreed++; + } +} + +/** + * iwl_tx_cmd_complete - Pull unused buffers off the queue and reclaim them + * @rxb: Rx buffer to reclaim + * + * If an Rx buffer has an async callback associated with it the callback + * will be executed. The attached skb (if present) will only be freed + * if the callback returns 1 + */ +void iwl_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) +{ + struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; + u16 sequence = le16_to_cpu(pkt->hdr.sequence); + int txq_id = SEQ_TO_QUEUE(sequence); + int index = SEQ_TO_INDEX(sequence); + int huge = sequence & SEQ_HUGE_FRAME; + int cmd_index; + struct iwl_cmd *cmd; + + /* If a Tx command is being handled and it isn't in the actual + * command queue then there a command routing bug has been introduced + * in the queue management code. */ + if (txq_id != IWL_CMD_QUEUE_NUM) + IWL_ERROR("Error wrong command queue %d command id 0x%X\n", + txq_id, pkt->hdr.cmd); + BUG_ON(txq_id != IWL_CMD_QUEUE_NUM); + + cmd_index = get_cmd_index(&priv->txq[IWL_CMD_QUEUE_NUM].q, index, huge); + cmd = &priv->txq[IWL_CMD_QUEUE_NUM].cmd[cmd_index]; + + /* Input error checking is done when commands are added to queue. */ + if (cmd->meta.flags & CMD_WANT_SKB) { + cmd->meta.source->u.skb = rxb->skb; + rxb->skb = NULL; + } else if (cmd->meta.u.callback && + !cmd->meta.u.callback(priv, cmd, rxb->skb)) + rxb->skb = NULL; + + iwl_hcmd_queue_reclaim(priv, txq_id, index); + + if (!(cmd->meta.flags & CMD_ASYNC)) { + clear_bit(STATUS_HCMD_ACTIVE, &priv->status); + wake_up_interruptible(&priv->wait_command_queue); + } +} +EXPORT_SYMBOL(iwl_tx_cmd_complete); + +/* + * Find first available (lowest unused) Tx Queue, mark it "active". + * Called only when finding queue for aggregation. + * Should never return anything < 7, because they should already + * be in use as EDCA AC (0-3), Command (4), HCCA (5, 6). + */ +static int iwl_txq_ctx_activate_free(struct iwl_priv *priv) +{ + int txq_id; + + for (txq_id = 0; txq_id < priv->hw_params.max_txq_num; txq_id++) + if (!test_and_set_bit(txq_id, &priv->txq_ctx_active_msk)) + return txq_id; + return -1; +} + +int iwl_tx_agg_start(struct iwl_priv *priv, const u8 *ra, u16 tid, u16 *ssn) +{ + int sta_id; + int tx_fifo; + int txq_id; + int ret; + unsigned long flags; + struct iwl_tid_data *tid_data; + DECLARE_MAC_BUF(mac); + + if (likely(tid < ARRAY_SIZE(default_tid_to_tx_fifo))) + tx_fifo = default_tid_to_tx_fifo[tid]; + else + return -EINVAL; + + IWL_WARNING("%s on ra = %s tid = %d\n", + __func__, print_mac(mac, ra), tid); + + sta_id = iwl_find_station(priv, ra); + if (sta_id == IWL_INVALID_STATION) + return -ENXIO; + + if (priv->stations[sta_id].tid[tid].agg.state != IWL_AGG_OFF) { + IWL_ERROR("Start AGG when state is not IWL_AGG_OFF !\n"); + return -ENXIO; + } + + txq_id = iwl_txq_ctx_activate_free(priv); + if (txq_id == -1) + return -ENXIO; + + spin_lock_irqsave(&priv->sta_lock, flags); + tid_data = &priv->stations[sta_id].tid[tid]; + *ssn = SEQ_TO_SN(tid_data->seq_number); + tid_data->agg.txq_id = txq_id; + spin_unlock_irqrestore(&priv->sta_lock, flags); + + ret = priv->cfg->ops->lib->txq_agg_enable(priv, txq_id, tx_fifo, + sta_id, tid, *ssn); + if (ret) + return ret; + + if (tid_data->tfds_in_queue == 0) { + printk(KERN_ERR "HW queue is empty\n"); + tid_data->agg.state = IWL_AGG_ON; + ieee80211_start_tx_ba_cb_irqsafe(priv->hw, ra, tid); + } else { + IWL_DEBUG_HT("HW queue is NOT empty: %d packets in HW queue\n", + tid_data->tfds_in_queue); + tid_data->agg.state = IWL_EMPTYING_HW_QUEUE_ADDBA; + } + return ret; +} +EXPORT_SYMBOL(iwl_tx_agg_start); + +int iwl_tx_agg_stop(struct iwl_priv *priv , const u8 *ra, u16 tid) +{ + int tx_fifo_id, txq_id, sta_id, ssn = -1; + struct iwl_tid_data *tid_data; + int ret, write_ptr, read_ptr; + unsigned long flags; + DECLARE_MAC_BUF(mac); + + if (!ra) { + IWL_ERROR("ra = NULL\n"); + return -EINVAL; + } + + if (likely(tid < ARRAY_SIZE(default_tid_to_tx_fifo))) + tx_fifo_id = default_tid_to_tx_fifo[tid]; + else + return -EINVAL; + + sta_id = iwl_find_station(priv, ra); + + if (sta_id == IWL_INVALID_STATION) + return -ENXIO; + + if (priv->stations[sta_id].tid[tid].agg.state != IWL_AGG_ON) + IWL_WARNING("Stopping AGG while state not IWL_AGG_ON\n"); + + tid_data = &priv->stations[sta_id].tid[tid]; + ssn = (tid_data->seq_number & IEEE80211_SCTL_SEQ) >> 4; + txq_id = tid_data->agg.txq_id; + write_ptr = priv->txq[txq_id].q.write_ptr; + read_ptr = priv->txq[txq_id].q.read_ptr; + + /* The queue is not empty */ + if (write_ptr != read_ptr) { + IWL_DEBUG_HT("Stopping a non empty AGG HW QUEUE\n"); + priv->stations[sta_id].tid[tid].agg.state = + IWL_EMPTYING_HW_QUEUE_DELBA; + return 0; + } + + IWL_DEBUG_HT("HW queue is empty\n"); + priv->stations[sta_id].tid[tid].agg.state = IWL_AGG_OFF; + + spin_lock_irqsave(&priv->lock, flags); + ret = priv->cfg->ops->lib->txq_agg_disable(priv, txq_id, ssn, + tx_fifo_id); + spin_unlock_irqrestore(&priv->lock, flags); + + if (ret) + return ret; + + ieee80211_stop_tx_ba_cb_irqsafe(priv->hw, ra, tid); + + return 0; +} +EXPORT_SYMBOL(iwl_tx_agg_stop); + +int iwl_txq_check_empty(struct iwl_priv *priv, int sta_id, u8 tid, int txq_id) +{ + struct iwl_queue *q = &priv->txq[txq_id].q; + u8 *addr = priv->stations[sta_id].sta.sta.addr; + struct iwl_tid_data *tid_data = &priv->stations[sta_id].tid[tid]; + + switch (priv->stations[sta_id].tid[tid].agg.state) { + case IWL_EMPTYING_HW_QUEUE_DELBA: + /* We are reclaiming the last packet of the */ + /* aggregated HW queue */ + if (txq_id == tid_data->agg.txq_id && + q->read_ptr == q->write_ptr) { + u16 ssn = SEQ_TO_SN(tid_data->seq_number); + int tx_fifo = default_tid_to_tx_fifo[tid]; + IWL_DEBUG_HT("HW queue empty: continue DELBA flow\n"); + priv->cfg->ops->lib->txq_agg_disable(priv, txq_id, + ssn, tx_fifo); + tid_data->agg.state = IWL_AGG_OFF; + ieee80211_stop_tx_ba_cb_irqsafe(priv->hw, addr, tid); + } + break; + case IWL_EMPTYING_HW_QUEUE_ADDBA: + /* We are reclaiming the last packet of the queue */ + if (tid_data->tfds_in_queue == 0) { + IWL_DEBUG_HT("HW queue empty: continue ADDBA flow\n"); + tid_data->agg.state = IWL_AGG_ON; + ieee80211_start_tx_ba_cb_irqsafe(priv->hw, addr, tid); + } + break; + } + return 0; +} +EXPORT_SYMBOL(iwl_txq_check_empty); + +/** + * iwl_tx_status_reply_compressed_ba - Update tx status from block-ack + * + * Go through block-ack's bitmap of ACK'd frames, update driver's record of + * ACK vs. not. This gets sent to mac80211, then to rate scaling algo. + */ +static int iwl_tx_status_reply_compressed_ba(struct iwl_priv *priv, + struct iwl_ht_agg *agg, + struct iwl_compressed_ba_resp *ba_resp) + +{ + int i, sh, ack; + u16 seq_ctl = le16_to_cpu(ba_resp->seq_ctl); + u16 scd_flow = le16_to_cpu(ba_resp->scd_flow); + u64 bitmap; + int successes = 0; + struct ieee80211_tx_info *info; + + if (unlikely(!agg->wait_for_ba)) { + IWL_ERROR("Received BA when not expected\n"); + return -EINVAL; + } + + /* Mark that the expected block-ack response arrived */ + agg->wait_for_ba = 0; + IWL_DEBUG_TX_REPLY("BA %d %d\n", agg->start_idx, ba_resp->seq_ctl); + + /* Calculate shift to align block-ack bits with our Tx window bits */ + sh = agg->start_idx - SEQ_TO_INDEX(seq_ctl>>4); + if (sh < 0) /* tbw something is wrong with indices */ + sh += 0x100; + + /* don't use 64-bit values for now */ + bitmap = le64_to_cpu(ba_resp->bitmap) >> sh; + + if (agg->frame_count > (64 - sh)) { + IWL_DEBUG_TX_REPLY("more frames than bitmap size"); + return -1; + } + + /* check for success or failure according to the + * transmitted bitmap and block-ack bitmap */ + bitmap &= agg->bitmap; + + /* For each frame attempted in aggregation, + * update driver's record of tx frame's status. */ + for (i = 0; i < agg->frame_count ; i++) { + ack = bitmap & (1 << i); + successes += !!ack; + IWL_DEBUG_TX_REPLY("%s ON i=%d idx=%d raw=%d\n", + ack? "ACK":"NACK", i, (agg->start_idx + i) & 0xff, + agg->start_idx + i); + } + + info = IEEE80211_SKB_CB(priv->txq[scd_flow].txb[agg->start_idx].skb[0]); + memset(&info->status, 0, sizeof(info->status)); + info->flags = IEEE80211_TX_STAT_ACK; + info->flags |= IEEE80211_TX_STAT_AMPDU; + info->status.ampdu_ack_map = successes; + info->status.ampdu_ack_len = agg->frame_count; + iwl_hwrate_to_tx_control(priv, agg->rate_n_flags, info); + + IWL_DEBUG_TX_REPLY("Bitmap %llx\n", (unsigned long long)bitmap); + + return 0; +} + +/** + * iwl_rx_reply_compressed_ba - Handler for REPLY_COMPRESSED_BA + * + * Handles block-acknowledge notification from device, which reports success + * of frames sent via aggregation. + */ +void iwl_rx_reply_compressed_ba(struct iwl_priv *priv, + struct iwl_rx_mem_buffer *rxb) +{ + struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; + struct iwl_compressed_ba_resp *ba_resp = &pkt->u.compressed_ba; + int index; + struct iwl_tx_queue *txq = NULL; + struct iwl_ht_agg *agg; + DECLARE_MAC_BUF(mac); + + /* "flow" corresponds to Tx queue */ + u16 scd_flow = le16_to_cpu(ba_resp->scd_flow); + + /* "ssn" is start of block-ack Tx window, corresponds to index + * (in Tx queue's circular buffer) of first TFD/frame in window */ + u16 ba_resp_scd_ssn = le16_to_cpu(ba_resp->scd_ssn); + + if (scd_flow >= priv->hw_params.max_txq_num) { + IWL_ERROR("BUG_ON scd_flow is bigger than number of queues"); + return; + } + + txq = &priv->txq[scd_flow]; + agg = &priv->stations[ba_resp->sta_id].tid[ba_resp->tid].agg; + + /* Find index just before block-ack window */ + index = iwl_queue_dec_wrap(ba_resp_scd_ssn & 0xff, txq->q.n_bd); + + /* TODO: Need to get this copy more safely - now good for debug */ + + IWL_DEBUG_TX_REPLY("REPLY_COMPRESSED_BA [%d]Received from %s, " + "sta_id = %d\n", + agg->wait_for_ba, + print_mac(mac, (u8 *) &ba_resp->sta_addr_lo32), + ba_resp->sta_id); + IWL_DEBUG_TX_REPLY("TID = %d, SeqCtl = %d, bitmap = 0x%llx, scd_flow = " + "%d, scd_ssn = %d\n", + ba_resp->tid, + ba_resp->seq_ctl, + (unsigned long long)le64_to_cpu(ba_resp->bitmap), + ba_resp->scd_flow, + ba_resp->scd_ssn); + IWL_DEBUG_TX_REPLY("DAT start_idx = %d, bitmap = 0x%llx \n", + agg->start_idx, + (unsigned long long)agg->bitmap); + + /* Update driver's record of ACK vs. not for each frame in window */ + iwl_tx_status_reply_compressed_ba(priv, agg, ba_resp); + + /* Release all TFDs before the SSN, i.e. all TFDs in front of + * block-ack window (we assume that they've been successfully + * transmitted ... if not, it's too late anyway). */ + if (txq->q.read_ptr != (ba_resp_scd_ssn & 0xff)) { + /* calculate mac80211 ampdu sw queue to wake */ + int ampdu_q = + scd_flow - priv->hw_params.first_ampdu_q + priv->hw->queues; + int freed = iwl_tx_queue_reclaim(priv, scd_flow, index); + priv->stations[ba_resp->sta_id]. + tid[ba_resp->tid].tfds_in_queue -= freed; + if (iwl_queue_space(&txq->q) > txq->q.low_mark && + priv->mac80211_registered && + agg->state != IWL_EMPTYING_HW_QUEUE_DELBA) + ieee80211_wake_queue(priv->hw, ampdu_q); + + iwl_txq_check_empty(priv, ba_resp->sta_id, + ba_resp->tid, scd_flow); + } +} +EXPORT_SYMBOL(iwl_rx_reply_compressed_ba); + +#ifdef CONFIG_IWLWIFI_DEBUG +#define TX_STATUS_ENTRY(x) case TX_STATUS_FAIL_ ## x: return #x + +const char *iwl_get_tx_fail_reason(u32 status) +{ + switch (status & TX_STATUS_MSK) { + case TX_STATUS_SUCCESS: + return "SUCCESS"; + TX_STATUS_ENTRY(SHORT_LIMIT); + TX_STATUS_ENTRY(LONG_LIMIT); + TX_STATUS_ENTRY(FIFO_UNDERRUN); + TX_STATUS_ENTRY(MGMNT_ABORT); + TX_STATUS_ENTRY(NEXT_FRAG); + TX_STATUS_ENTRY(LIFE_EXPIRE); + TX_STATUS_ENTRY(DEST_PS); + TX_STATUS_ENTRY(ABORTED); + TX_STATUS_ENTRY(BT_RETRY); + TX_STATUS_ENTRY(STA_INVALID); + TX_STATUS_ENTRY(FRAG_DROPPED); + TX_STATUS_ENTRY(TID_DISABLE); + TX_STATUS_ENTRY(FRAME_FLUSHED); + TX_STATUS_ENTRY(INSUFFICIENT_CF_POLL); + TX_STATUS_ENTRY(TX_LOCKED); + TX_STATUS_ENTRY(NO_BEACON_ON_RADAR); + } + + return "UNKNOWN"; +} +EXPORT_SYMBOL(iwl_get_tx_fail_reason); +#endif /* CONFIG_IWLWIFI_DEBUG */ diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index 6027e1119c3f..4a22d3fba75b 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -102,16 +102,6 @@ MODULE_VERSION(DRV_VERSION); MODULE_AUTHOR(DRV_COPYRIGHT); MODULE_LICENSE("GPL"); -static __le16 *ieee80211_get_qos_ctrl(struct ieee80211_hdr *hdr) -{ - u16 fc = le16_to_cpu(hdr->frame_control); - int hdr_len = ieee80211_get_hdrlen(fc); - - if ((fc & 0x00cc) == (IEEE80211_STYPE_QOS_DATA | IEEE80211_FTYPE_DATA)) - return (__le16 *) ((u8 *) hdr + hdr_len - QOS_CONTROL_LEN); - return NULL; -} - static const struct ieee80211_supported_band *iwl3945_get_band( struct iwl3945_priv *priv, enum ieee80211_band band) { @@ -547,10 +537,20 @@ static inline int iwl3945_is_init(struct iwl3945_priv *priv) return test_bit(STATUS_INIT, &priv->status); } +static inline int iwl3945_is_rfkill_sw(struct iwl3945_priv *priv) +{ + return test_bit(STATUS_RF_KILL_SW, &priv->status); +} + +static inline int iwl3945_is_rfkill_hw(struct iwl3945_priv *priv) +{ + return test_bit(STATUS_RF_KILL_HW, &priv->status); +} + static inline int iwl3945_is_rfkill(struct iwl3945_priv *priv) { - return test_bit(STATUS_RF_KILL_HW, &priv->status) || - test_bit(STATUS_RF_KILL_SW, &priv->status); + return iwl3945_is_rfkill_hw(priv) || + iwl3945_is_rfkill_sw(priv); } static inline int iwl3945_is_ready_rf(struct iwl3945_priv *priv) @@ -980,7 +980,7 @@ static int iwl3945_full_rxon_required(struct iwl3945_priv *priv) { /* These items are only settable from the full RXON command */ - if (!(priv->active_rxon.filter_flags & RXON_FILTER_ASSOC_MSK) || + if (!(iwl3945_is_associated(priv)) || compare_ether_addr(priv->staging_rxon.bssid_addr, priv->active_rxon.bssid_addr) || compare_ether_addr(priv->staging_rxon.node_addr, @@ -2035,36 +2035,6 @@ static int iwl3945_send_power_mode(struct iwl3945_priv *priv, u32 mode) return rc; } -int iwl3945_is_network_packet(struct iwl3945_priv *priv, struct ieee80211_hdr *header) -{ - /* Filter incoming packets to determine if they are targeted toward - * this network, discarding packets coming from ourselves */ - switch (priv->iw_mode) { - case IEEE80211_IF_TYPE_IBSS: /* Header: Dest. | Source | BSSID */ - /* packets from our adapter are dropped (echo) */ - if (!compare_ether_addr(header->addr2, priv->mac_addr)) - return 0; - /* {broad,multi}cast packets to our IBSS go through */ - if (is_multicast_ether_addr(header->addr1)) - return !compare_ether_addr(header->addr3, priv->bssid); - /* packets to our adapter go through */ - return !compare_ether_addr(header->addr1, priv->mac_addr); - case IEEE80211_IF_TYPE_STA: /* Header: Dest. | AP{BSSID} | Source */ - /* packets from our adapter are dropped (echo) */ - if (!compare_ether_addr(header->addr3, priv->mac_addr)) - return 0; - /* {broad,multi}cast packets to our BSS go through */ - if (is_multicast_ether_addr(header->addr1)) - return !compare_ether_addr(header->addr2, priv->bssid); - /* packets to our adapter go through */ - return !compare_ether_addr(header->addr1, priv->mac_addr); - default: - return 1; - } - - return 1; -} - /** * iwl3945_scan_cancel - Cancel any currently executing HW scan * @@ -2117,20 +2087,6 @@ static int iwl3945_scan_cancel_timeout(struct iwl3945_priv *priv, unsigned long return ret; } -static void iwl3945_sequence_reset(struct iwl3945_priv *priv) -{ - /* Reset ieee stats */ - - /* We don't reset the net_device_stats (ieee->stats) on - * re-association */ - - priv->last_seq_num = -1; - priv->last_frag_num = -1; - priv->last_packet_time = 0; - - iwl3945_scan_cancel(priv); -} - #define MAX_UCODE_BEACON_INTERVAL 1024 #define INTEL_CONN_LISTEN_INTERVAL __constant_cpu_to_le16(0xA) @@ -2322,7 +2278,7 @@ static void iwl3945_connection_init_rx_config(struct iwl3945_priv *priv) #endif ch_info = iwl3945_get_channel_info(priv, priv->band, - le16_to_cpu(priv->staging_rxon.channel)); + le16_to_cpu(priv->active_rxon.channel)); if (!ch_info) ch_info = &priv->channel_info[0]; @@ -2389,12 +2345,13 @@ static int iwl3945_set_mode(struct iwl3945_priv *priv, int mode) } static void iwl3945_build_tx_cmd_hwcrypto(struct iwl3945_priv *priv, - struct ieee80211_tx_control *ctl, + struct ieee80211_tx_info *info, struct iwl3945_cmd *cmd, struct sk_buff *skb_frag, int last_frag) { - struct iwl3945_hw_key *keyinfo = &priv->stations[ctl->key_idx].keyinfo; + struct iwl3945_hw_key *keyinfo = + &priv->stations[info->control.hw_key->hw_key_idx].keyinfo; switch (keyinfo->alg) { case ALG_CCMP: @@ -2417,7 +2374,7 @@ static void iwl3945_build_tx_cmd_hwcrypto(struct iwl3945_priv *priv, case ALG_WEP: cmd->cmd.tx.sec_ctl = TX_CMD_SEC_WEP | - (ctl->key_idx & TX_CMD_SEC_MSK) << TX_CMD_SEC_SHIFT; + (info->control.hw_key->hw_key_idx & TX_CMD_SEC_MSK) << TX_CMD_SEC_SHIFT; if (keyinfo->keylen == 13) cmd->cmd.tx.sec_ctl |= TX_CMD_SEC_KEY128; @@ -2425,7 +2382,7 @@ static void iwl3945_build_tx_cmd_hwcrypto(struct iwl3945_priv *priv, memcpy(&cmd->cmd.tx.key[3], keyinfo->key, keyinfo->keylen); IWL_DEBUG_TX("Configuring packet for WEP encryption " - "with key %d\n", ctl->key_idx); + "with key %d\n", info->control.hw_key->hw_key_idx); break; default: @@ -2439,20 +2396,19 @@ static void iwl3945_build_tx_cmd_hwcrypto(struct iwl3945_priv *priv, */ static void iwl3945_build_tx_cmd_basic(struct iwl3945_priv *priv, struct iwl3945_cmd *cmd, - struct ieee80211_tx_control *ctrl, + struct ieee80211_tx_info *info, struct ieee80211_hdr *hdr, int is_unicast, u8 std_id) { - __le16 *qc; - u16 fc = le16_to_cpu(hdr->frame_control); + __le16 fc = hdr->frame_control; __le32 tx_flags = cmd->cmd.tx.tx_flags; cmd->cmd.tx.stop_time.life_time = TX_CMD_LIFE_TIME_INFINITE; - if (!(ctrl->flags & IEEE80211_TXCTL_NO_ACK)) { + if (!(info->flags & IEEE80211_TX_CTL_NO_ACK)) { tx_flags |= TX_CMD_FLG_ACK_MSK; - if ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT) + if (ieee80211_is_mgmt(fc)) tx_flags |= TX_CMD_FLG_SEQ_CTL_MSK; - if (ieee80211_is_probe_response(fc) && + if (ieee80211_is_probe_resp(fc) && !(le16_to_cpu(hdr->seq_ctrl) & 0xf)) tx_flags |= TX_CMD_FLG_TSF_MSK; } else { @@ -2461,20 +2417,21 @@ static void iwl3945_build_tx_cmd_basic(struct iwl3945_priv *priv, } cmd->cmd.tx.sta_id = std_id; - if (ieee80211_get_morefrag(hdr)) + if (ieee80211_has_morefrags(fc)) tx_flags |= TX_CMD_FLG_MORE_FRAG_MSK; - qc = ieee80211_get_qos_ctrl(hdr); - if (qc) { - cmd->cmd.tx.tid_tspec = (u8) (le16_to_cpu(*qc) & 0xf); + if (ieee80211_is_data_qos(fc)) { + u8 *qc = ieee80211_get_qos_ctl(hdr); + cmd->cmd.tx.tid_tspec = qc[0] & 0xf; tx_flags &= ~TX_CMD_FLG_SEQ_CTL_MSK; - } else + } else { tx_flags |= TX_CMD_FLG_SEQ_CTL_MSK; + } - if (ctrl->flags & IEEE80211_TXCTL_USE_RTS_CTS) { + if (info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) { tx_flags |= TX_CMD_FLG_RTS_MSK; tx_flags &= ~TX_CMD_FLG_CTS_MSK; - } else if (ctrl->flags & IEEE80211_TXCTL_USE_CTS_PROTECT) { + } else if (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT) { tx_flags &= ~TX_CMD_FLG_RTS_MSK; tx_flags |= TX_CMD_FLG_CTS_MSK; } @@ -2483,9 +2440,8 @@ static void iwl3945_build_tx_cmd_basic(struct iwl3945_priv *priv, tx_flags |= TX_CMD_FLG_FULL_TXOP_PROT_MSK; tx_flags &= ~(TX_CMD_FLG_ANT_SEL_MSK); - if ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT) { - if ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_ASSOC_REQ || - (fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_REASSOC_REQ) + if (ieee80211_is_mgmt(fc)) { + if (ieee80211_is_assoc_req(fc) || ieee80211_is_reassoc_req(fc)) cmd->cmd.tx.timeout.pm_frame_timeout = cpu_to_le16(3); else cmd->cmd.tx.timeout.pm_frame_timeout = cpu_to_le16(2); @@ -2549,6 +2505,11 @@ static int iwl3945_get_sta_id(struct iwl3945_priv *priv, struct ieee80211_hdr *h iwl3945_print_hex_dump(IWL_DL_DROP, (u8 *) hdr, sizeof(*hdr)); return priv->hw_setting.bcast_sta_id; } + /* If we are in monitor mode, use BCAST. This is required for + * packet injection. */ + case IEEE80211_IF_TYPE_MNTR: + return priv->hw_setting.bcast_sta_id; + default: IWL_WARNING("Unknown mode of operation: %d", priv->iw_mode); return priv->hw_setting.bcast_sta_id; @@ -2558,25 +2519,27 @@ static int iwl3945_get_sta_id(struct iwl3945_priv *priv, struct ieee80211_hdr *h /* * start REPLY_TX command process */ -static int iwl3945_tx_skb(struct iwl3945_priv *priv, - struct sk_buff *skb, struct ieee80211_tx_control *ctl) +static int iwl3945_tx_skb(struct iwl3945_priv *priv, struct sk_buff *skb) { struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct iwl3945_tfd_frame *tfd; u32 *control_flags; - int txq_id = ctl->queue; + int txq_id = skb_get_queue_mapping(skb); struct iwl3945_tx_queue *txq = NULL; struct iwl3945_queue *q = NULL; dma_addr_t phys_addr; dma_addr_t txcmd_phys; struct iwl3945_cmd *out_cmd = NULL; - u16 len, idx, len_org; - u8 id, hdr_len, unicast; + u16 len, idx, len_org, hdr_len; + u8 id; + u8 unicast; u8 sta_id; + u8 tid = 0; u16 seq_number = 0; - u16 fc; - __le16 *qc; + __le16 fc; u8 wait_write_ptr = 0; + u8 *qc = NULL; unsigned long flags; int rc; @@ -2586,12 +2549,7 @@ static int iwl3945_tx_skb(struct iwl3945_priv *priv, goto drop_unlock; } - if (!priv->vif) { - IWL_DEBUG_DROP("Dropping - !priv->vif\n"); - goto drop_unlock; - } - - if ((ctl->tx_rate->hw_value & 0xFF) == IWL_INVALID_RATE) { + if ((ieee80211_get_tx_rate(priv->hw, info)->hw_value & 0xFF) == IWL_INVALID_RATE) { IWL_ERROR("ERROR: No TX rate available.\n"); goto drop_unlock; } @@ -2599,28 +2557,29 @@ static int iwl3945_tx_skb(struct iwl3945_priv *priv, unicast = !is_multicast_ether_addr(hdr->addr1); id = 0; - fc = le16_to_cpu(hdr->frame_control); + fc = hdr->frame_control; #ifdef CONFIG_IWL3945_DEBUG if (ieee80211_is_auth(fc)) IWL_DEBUG_TX("Sending AUTH frame\n"); - else if (ieee80211_is_assoc_request(fc)) + else if (ieee80211_is_assoc_req(fc)) IWL_DEBUG_TX("Sending ASSOC frame\n"); - else if (ieee80211_is_reassoc_request(fc)) + else if (ieee80211_is_reassoc_req(fc)) IWL_DEBUG_TX("Sending REASSOC frame\n"); #endif /* drop all data frame if we are not associated */ - if ((!iwl3945_is_associated(priv) || - ((priv->iw_mode == IEEE80211_IF_TYPE_STA) && !priv->assoc_id)) && - ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA)) { + if (ieee80211_is_data(fc) && + (priv->iw_mode != IEEE80211_IF_TYPE_MNTR) && /* packet injection */ + (!iwl3945_is_associated(priv) || + ((priv->iw_mode == IEEE80211_IF_TYPE_STA) && !priv->assoc_id))) { IWL_DEBUG_DROP("Dropping - !iwl3945_is_associated\n"); goto drop_unlock; } spin_unlock_irqrestore(&priv->lock, flags); - hdr_len = ieee80211_get_hdrlen(fc); + hdr_len = ieee80211_get_hdrlen(le16_to_cpu(fc)); /* Find (or create) index into station table for destination station */ sta_id = iwl3945_get_sta_id(priv, hdr); @@ -2634,9 +2593,9 @@ static int iwl3945_tx_skb(struct iwl3945_priv *priv, IWL_DEBUG_RATE("station Id %d\n", sta_id); - qc = ieee80211_get_qos_ctrl(hdr); - if (qc) { - u8 tid = (u8)(le16_to_cpu(*qc) & 0xf); + if (ieee80211_is_data_qos(fc)) { + qc = ieee80211_get_qos_ctl(hdr); + tid = qc[0] & 0xf; seq_number = priv->stations[sta_id].tid[tid].seq_number & IEEE80211_SCTL_SEQ; hdr->seq_ctrl = cpu_to_le16(seq_number) | @@ -2660,8 +2619,6 @@ static int iwl3945_tx_skb(struct iwl3945_priv *priv, /* Set up driver data for this TFD */ memset(&(txq->txb[q->write_ptr]), 0, sizeof(struct iwl3945_tx_info)); txq->txb[q->write_ptr].skb[0] = skb; - memcpy(&(txq->txb[q->write_ptr].status.control), - ctl, sizeof(struct ieee80211_tx_control)); /* Init first empty entry in queue's array of Tx/cmd buffers */ out_cmd = &txq->cmd[idx]; @@ -2710,8 +2667,8 @@ static int iwl3945_tx_skb(struct iwl3945_priv *priv, * first entry */ iwl3945_hw_txq_attach_buf_to_tfd(priv, tfd, txcmd_phys, len); - if (!(ctl->flags & IEEE80211_TXCTL_DO_NOT_ENCRYPT)) - iwl3945_build_tx_cmd_hwcrypto(priv, ctl, out_cmd, skb, 0); + if (!(info->flags & IEEE80211_TX_CTL_DO_NOT_ENCRYPT)) + iwl3945_build_tx_cmd_hwcrypto(priv, info, out_cmd, skb, 0); /* Set up TFD's 2nd entry to point directly to remainder of skb, * if any (802.11 null frames have no payload). */ @@ -2736,18 +2693,17 @@ static int iwl3945_tx_skb(struct iwl3945_priv *priv, out_cmd->cmd.tx.len = cpu_to_le16(len); /* TODO need this for burst mode later on */ - iwl3945_build_tx_cmd_basic(priv, out_cmd, ctl, hdr, unicast, sta_id); + iwl3945_build_tx_cmd_basic(priv, out_cmd, info, hdr, unicast, sta_id); /* set is_hcca to 0; it probably will never be implemented */ - iwl3945_hw_build_tx_cmd_rate(priv, out_cmd, ctl, hdr, sta_id, 0); + iwl3945_hw_build_tx_cmd_rate(priv, out_cmd, info, hdr, sta_id, 0); out_cmd->cmd.tx.tx_flags &= ~TX_CMD_FLG_ANT_A_MSK; out_cmd->cmd.tx.tx_flags &= ~TX_CMD_FLG_ANT_B_MSK; - if (!ieee80211_get_morefrag(hdr)) { + if (!ieee80211_has_morefrags(hdr->frame_control)) { txq->need_update = 1; if (qc) { - u8 tid = (u8)(le16_to_cpu(*qc) & 0xf); priv->stations[sta_id].tid[tid].seq_number = seq_number; } } else { @@ -2759,7 +2715,7 @@ static int iwl3945_tx_skb(struct iwl3945_priv *priv, sizeof(out_cmd->cmd.tx)); iwl3945_print_hex_dump(IWL_DL_TX, (u8 *)out_cmd->cmd.tx.hdr, - ieee80211_get_hdrlen(fc)); + ieee80211_get_hdrlen(le16_to_cpu(fc))); /* Tell device the write index *just past* this latest filled TFD */ q->write_ptr = iwl_queue_inc_wrap(q->write_ptr, q->n_bd); @@ -2778,7 +2734,7 @@ static int iwl3945_tx_skb(struct iwl3945_priv *priv, spin_unlock_irqrestore(&priv->lock, flags); } - ieee80211_stop_queue(priv->hw, ctl->queue); + ieee80211_stop_queue(priv->hw, skb_get_queue_mapping(skb)); } return 0; @@ -2888,7 +2844,8 @@ static void iwl3945_radio_kill_sw(struct iwl3945_priv *priv, int disable_radio) return; } - queue_work(priv->workqueue, &priv->restart); + if (priv->is_open) + queue_work(priv->workqueue, &priv->restart); return; } @@ -2924,72 +2881,6 @@ void iwl3945_set_decrypted_flag(struct iwl3945_priv *priv, struct sk_buff *skb, } } -#define IWL_PACKET_RETRY_TIME HZ - -int iwl3945_is_duplicate_packet(struct iwl3945_priv *priv, struct ieee80211_hdr *header) -{ - u16 sc = le16_to_cpu(header->seq_ctrl); - u16 seq = (sc & IEEE80211_SCTL_SEQ) >> 4; - u16 frag = sc & IEEE80211_SCTL_FRAG; - u16 *last_seq, *last_frag; - unsigned long *last_time; - - switch (priv->iw_mode) { - case IEEE80211_IF_TYPE_IBSS:{ - struct list_head *p; - struct iwl3945_ibss_seq *entry = NULL; - u8 *mac = header->addr2; - int index = mac[5] & (IWL_IBSS_MAC_HASH_SIZE - 1); - - __list_for_each(p, &priv->ibss_mac_hash[index]) { - entry = list_entry(p, struct iwl3945_ibss_seq, list); - if (!compare_ether_addr(entry->mac, mac)) - break; - } - if (p == &priv->ibss_mac_hash[index]) { - entry = kzalloc(sizeof(*entry), GFP_ATOMIC); - if (!entry) { - IWL_ERROR("Cannot malloc new mac entry\n"); - return 0; - } - memcpy(entry->mac, mac, ETH_ALEN); - entry->seq_num = seq; - entry->frag_num = frag; - entry->packet_time = jiffies; - list_add(&entry->list, &priv->ibss_mac_hash[index]); - return 0; - } - last_seq = &entry->seq_num; - last_frag = &entry->frag_num; - last_time = &entry->packet_time; - break; - } - case IEEE80211_IF_TYPE_STA: - last_seq = &priv->last_seq_num; - last_frag = &priv->last_frag_num; - last_time = &priv->last_packet_time; - break; - default: - return 0; - } - if ((*last_seq == seq) && - time_after(*last_time + IWL_PACKET_RETRY_TIME, jiffies)) { - if (*last_frag == frag) - goto drop; - if (*last_frag + 1 != frag) - /* out-of-order fragment */ - goto drop; - } else - *last_seq = seq; - - *last_frag = frag; - *last_time = jiffies; - return 0; - - drop: - return 1; -} - #ifdef CONFIG_IWL3945_SPECTRUM_MEASUREMENT #include "iwl-spectrum.h" @@ -3241,7 +3132,7 @@ static void iwl3945_bg_beacon_update(struct work_struct *work) struct sk_buff *beacon; /* Pull updated AP beacon from mac80211. will fail if not in AP mode */ - beacon = ieee80211_beacon_get(priv->hw, priv->vif, NULL); + beacon = ieee80211_beacon_get(priv->hw, priv->vif); if (!beacon) { IWL_ERROR("update beacon failed\n"); @@ -4848,7 +4739,7 @@ static int iwl3945_init_channel_map(struct iwl3945_priv *priv) ch_info->scan_power = eeprom_ch_info[ch].max_power_avg; ch_info->min_power = 0; - IWL_DEBUG_INFO("Ch. %d [%sGHz] %s%s%s%s%s%s%s(0x%02x" + IWL_DEBUG_INFO("Ch. %d [%sGHz] %s%s%s%s%s%s(0x%02x" " %ddBm): Ad-Hoc %ssupported\n", ch_info->channel, is_channel_a_band(ch_info) ? @@ -4858,7 +4749,6 @@ static int iwl3945_init_channel_map(struct iwl3945_priv *priv) CHECK_AND_PRINT(ACTIVE), CHECK_AND_PRINT(RADAR), CHECK_AND_PRINT(WIDE), - CHECK_AND_PRINT(NARROW), CHECK_AND_PRINT(DFS), eeprom_ch_info[ch].flags, eeprom_ch_info[ch].max_power_avg, @@ -4994,9 +4884,6 @@ static int iwl3945_get_channels_for_scan(struct iwl3945_priv *priv, if (scan_ch->type & 1) scan_ch->type |= (direct_mask << 1); - if (is_channel_narrow(ch_info)) - scan_ch->type |= (1 << 7); - scan_ch->active_dwell = cpu_to_le16(active_dwell); scan_ch->passive_dwell = cpu_to_le16(passive_dwell); @@ -5843,7 +5730,7 @@ static void iwl3945_alive_start(struct iwl3945_priv *priv) if (iwl3945_is_rfkill(priv)) return; - ieee80211_start_queues(priv->hw); + ieee80211_wake_queues(priv->hw); priv->active_rate = priv->rates_mask; priv->active_rate_basic = priv->rates_mask & IWL_BASIC_RATES_MASK; @@ -5869,9 +5756,6 @@ static void iwl3945_alive_start(struct iwl3945_priv *priv) /* Configure the adapter for unassociated operation */ iwl3945_commit_rxon(priv); - /* At this point, the NIC is initialized and operational */ - priv->notif_missed_beacons = 0; - iwl3945_reg_txpower_periodic(priv); iwl3945_led_register(priv); @@ -5938,7 +5822,9 @@ static void __iwl3945_down(struct iwl3945_priv *priv) test_bit(STATUS_GEO_CONFIGURED, &priv->status) << STATUS_GEO_CONFIGURED | test_bit(STATUS_IN_SUSPEND, &priv->status) << - STATUS_IN_SUSPEND; + STATUS_IN_SUSPEND | + test_bit(STATUS_EXIT_PENDING, &priv->status) << + STATUS_EXIT_PENDING; goto exit; } @@ -5953,7 +5839,9 @@ static void __iwl3945_down(struct iwl3945_priv *priv) test_bit(STATUS_IN_SUSPEND, &priv->status) << STATUS_IN_SUSPEND | test_bit(STATUS_FW_ERROR, &priv->status) << - STATUS_FW_ERROR; + STATUS_FW_ERROR | + test_bit(STATUS_EXIT_PENDING, &priv->status) << + STATUS_EXIT_PENDING; spin_lock_irqsave(&priv->lock, flags); iwl3945_clear_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); @@ -6085,6 +5973,7 @@ static int __iwl3945_up(struct iwl3945_priv *priv) set_bit(STATUS_EXIT_PENDING, &priv->status); __iwl3945_down(priv); + clear_bit(STATUS_EXIT_PENDING, &priv->status); /* tried to restart and config the device for as long as our * patience could withstand */ @@ -6152,6 +6041,26 @@ static void iwl3945_bg_rf_kill(struct work_struct *work) "Kill switch must be turned off for " "wireless networking to work.\n"); } + + mutex_unlock(&priv->mutex); + iwl3945_rfkill_set_hw_state(priv); +} + +static void iwl3945_bg_set_monitor(struct work_struct *work) +{ + struct iwl3945_priv *priv = container_of(work, + struct iwl3945_priv, set_monitor); + + IWL_DEBUG(IWL_DL_STATE, "setting monitor mode\n"); + + mutex_lock(&priv->mutex); + + if (!iwl3945_is_ready(priv)) + IWL_DEBUG(IWL_DL_STATE, "leave - not ready\n"); + else + if (iwl3945_set_mode(priv, IEEE80211_IF_TYPE_MNTR) != 0) + IWL_ERROR("iwl3945_set_mode() failed\n"); + mutex_unlock(&priv->mutex); } @@ -6388,6 +6297,7 @@ static void iwl3945_bg_up(struct work_struct *data) mutex_lock(&priv->mutex); __iwl3945_up(priv); mutex_unlock(&priv->mutex); + iwl3945_rfkill_set_hw_state(priv); } static void iwl3945_bg_restart(struct work_struct *data) @@ -6511,8 +6421,6 @@ static void iwl3945_bg_post_associate(struct work_struct *data) break; } - iwl3945_sequence_reset(priv); - iwl3945_activate_qos(priv, 0); /* we have just associated, don't start scan too early */ @@ -6608,6 +6516,8 @@ static int iwl3945_mac_start(struct ieee80211_hw *hw) mutex_unlock(&priv->mutex); + iwl3945_rfkill_set_hw_state(priv); + if (ret) goto out_release_irq; @@ -6678,8 +6588,7 @@ static void iwl3945_mac_stop(struct ieee80211_hw *hw) IWL_DEBUG_MAC80211("leave\n"); } -static int iwl3945_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb, - struct ieee80211_tx_control *ctl) +static int iwl3945_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb) { struct iwl3945_priv *priv = hw->priv; @@ -6692,9 +6601,9 @@ static int iwl3945_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb, } IWL_DEBUG_TX("dev->xmit(%d bytes) at rate 0x%02x\n", skb->len, - ctl->tx_rate->bitrate); + ieee80211_get_tx_rate(hw, IEEE80211_SKB_CB(skb))->bitrate); - if (iwl3945_tx_skb(priv, skb, ctl)) + if (iwl3945_tx_skb(priv, skb)) dev_kfree_skb_any(skb); IWL_DEBUG_MAC80211("leave\n"); @@ -6837,7 +6746,7 @@ static void iwl3945_config_ap(struct iwl3945_priv *priv) return; /* The following should be done only at AP bring up */ - if ((priv->active_rxon.filter_flags & RXON_FILTER_ASSOC_MSK) == 0) { + if (!(iwl3945_is_associated(priv))) { /* RXON - unassoc (to set timing command) */ priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK; @@ -6886,6 +6795,9 @@ static void iwl3945_config_ap(struct iwl3945_priv *priv) * clear sta table, add BCAST sta... */ } +/* temporary */ +static int iwl3945_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb); + static int iwl3945_mac_config_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_if_conf *conf) @@ -6903,10 +6815,21 @@ static int iwl3945_mac_config_interface(struct ieee80211_hw *hw, return 0; } + /* handle this temporarily here */ + if (priv->iw_mode == IEEE80211_IF_TYPE_IBSS && + conf->changed & IEEE80211_IFCC_BEACON) { + struct sk_buff *beacon = ieee80211_beacon_get(hw, vif); + if (!beacon) + return -ENOMEM; + rc = iwl3945_mac_beacon_update(hw, beacon); + if (rc) + return rc; + } + /* XXX: this MUST use conf->mac_addr */ if ((priv->iw_mode == IEEE80211_IF_TYPE_AP) && - (!conf->beacon || !conf->ssid_len)) { + (!conf->ssid_len)) { IWL_DEBUG_MAC80211 ("Leaving in AP mode because HostAPD is not ready.\n"); return 0; @@ -6938,7 +6861,7 @@ static int iwl3945_mac_config_interface(struct ieee80211_hw *hw, if (priv->ibss_beacon) dev_kfree_skb(priv->ibss_beacon); - priv->ibss_beacon = conf->beacon; + priv->ibss_beacon = ieee80211_beacon_get(hw, vif); } if (iwl3945_is_rfkill(priv)) @@ -6999,11 +6922,18 @@ static void iwl3945_configure_filter(struct ieee80211_hw *hw, unsigned int *total_flags, int mc_count, struct dev_addr_list *mc_list) { - /* - * XXX: dummy - * see also iwl3945_connection_init_rx_config - */ - *total_flags = 0; + struct iwl3945_priv *priv = hw->priv; + + if (changed_flags & (*total_flags) & FIF_OTHER_BSS) { + IWL_DEBUG_MAC80211("Enter: type %d (0x%x, 0x%x)\n", + IEEE80211_IF_TYPE_MNTR, + changed_flags, *total_flags); + /* queue work 'cuz mac80211 is holding a lock which + * prevents us from issuing (synchronous) f/w cmds */ + queue_work(priv->workqueue, &priv->set_monitor); + } + *total_flags &= FIF_OTHER_BSS | FIF_ALLMULTI | + FIF_BCN_PRBRESP_PROMISC | FIF_CONTROL; } static void iwl3945_mac_remove_interface(struct ieee80211_hw *hw, @@ -7061,9 +6991,10 @@ static int iwl3945_mac_hw_scan(struct ieee80211_hw *hw, u8 *ssid, size_t len) rc = -EAGAIN; goto out_unlock; } - /* if we just finished scan ask for delay */ - if (priv->last_scan_jiffies && time_after(priv->last_scan_jiffies + - IWL_DELAY_NEXT_SCAN, jiffies)) { + /* if we just finished scan ask for delay for a broadcast scan */ + if ((len == 0) && priv->last_scan_jiffies && + time_after(priv->last_scan_jiffies + IWL_DELAY_NEXT_SCAN, + jiffies)) { rc = -EAGAIN; goto out_unlock; } @@ -7150,7 +7081,7 @@ static int iwl3945_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, return rc; } -static int iwl3945_mac_conf_tx(struct ieee80211_hw *hw, int queue, +static int iwl3945_mac_conf_tx(struct ieee80211_hw *hw, u16 queue, const struct ieee80211_tx_queue_params *params) { struct iwl3945_priv *priv = hw->priv; @@ -7224,9 +7155,9 @@ static int iwl3945_mac_get_tx_stats(struct ieee80211_hw *hw, q = &txq->q; avail = iwl3945_queue_space(q); - stats->data[i].len = q->n_window - avail; - stats->data[i].limit = q->n_window - q->high_mark; - stats->data[i].count = q->n_window; + 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); @@ -7315,8 +7246,7 @@ 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 ieee80211_tx_control *control) +static int iwl3945_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb) { struct iwl3945_priv *priv = hw->priv; unsigned long flags; @@ -7398,37 +7328,6 @@ static DRIVER_ATTR(debug_level, S_IWUSR | S_IRUGO, #endif /* CONFIG_IWL3945_DEBUG */ -static ssize_t show_rf_kill(struct device *d, - struct device_attribute *attr, char *buf) -{ - /* - * 0 - RF kill not enabled - * 1 - SW based RF kill active (sysfs) - * 2 - HW based RF kill active - * 3 - Both HW and SW based RF kill active - */ - struct iwl3945_priv *priv = (struct iwl3945_priv *)d->driver_data; - int val = (test_bit(STATUS_RF_KILL_SW, &priv->status) ? 0x1 : 0x0) | - (test_bit(STATUS_RF_KILL_HW, &priv->status) ? 0x2 : 0x0); - - return sprintf(buf, "%i\n", val); -} - -static ssize_t store_rf_kill(struct device *d, - struct device_attribute *attr, - const char *buf, size_t count) -{ - struct iwl3945_priv *priv = (struct iwl3945_priv *)d->driver_data; - - mutex_lock(&priv->mutex); - iwl3945_radio_kill_sw(priv, buf[0] == '1'); - mutex_unlock(&priv->mutex); - - return count; -} - -static DEVICE_ATTR(rf_kill, S_IWUSR | S_IRUGO, show_rf_kill, store_rf_kill); - static ssize_t show_temperature(struct device *d, struct device_attribute *attr, char *buf) { @@ -7879,6 +7778,7 @@ static void iwl3945_setup_deferred_work(struct iwl3945_priv *priv) INIT_WORK(&priv->abort_scan, iwl3945_bg_abort_scan); INIT_WORK(&priv->rf_kill, iwl3945_bg_rf_kill); INIT_WORK(&priv->beacon_update, iwl3945_bg_beacon_update); + INIT_WORK(&priv->set_monitor, iwl3945_bg_set_monitor); INIT_DELAYED_WORK(&priv->post_associate, iwl3945_bg_post_associate); INIT_DELAYED_WORK(&priv->init_alive_start, iwl3945_bg_init_alive_start); INIT_DELAYED_WORK(&priv->alive_start, iwl3945_bg_alive_start); @@ -7913,7 +7813,6 @@ static struct attribute *iwl3945_sysfs_entries[] = { #endif &dev_attr_power_level.attr, &dev_attr_retry_rate.attr, - &dev_attr_rf_kill.attr, &dev_attr_rs_window.attr, &dev_attr_statistics.attr, &dev_attr_status.attr, @@ -7943,7 +7842,6 @@ static struct ieee80211_ops iwl3945_hw_ops = { .conf_tx = iwl3945_mac_conf_tx, .get_tsf = iwl3945_mac_get_tsf, .reset_tsf = iwl3945_mac_reset_tsf, - .beacon_update = iwl3945_mac_beacon_update, .hw_scan = iwl3945_mac_hw_scan }; @@ -7953,7 +7851,6 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e struct iwl3945_priv *priv; struct ieee80211_hw *hw; struct iwl_3945_cfg *cfg = (struct iwl_3945_cfg *)(ent->driver_data); - int i; unsigned long flags; DECLARE_MAC_BUF(mac); @@ -8001,17 +7898,10 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e priv->ibss_beacon = NULL; - /* Tell mac80211 and its clients (e.g. Wireless Extensions) - * the range of signal quality values that we'll provide. - * Negative values for level/noise indicate that we'll provide dBm. - * For WE, at least, non-0 values here *enable* display of values - * in app (iwconfig). */ - hw->max_rssi = -20; /* signal level, negative indicates dBm */ - hw->max_noise = -20; /* noise level, negative indicates dBm */ - hw->max_signal = 100; /* link quality indication (%) */ - - /* Tell mac80211 our Tx characteristics */ - hw->flags = IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE; + /* Tell mac80211 our characteristics */ + hw->flags = IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE | + IEEE80211_HW_SIGNAL_DBM | + IEEE80211_HW_NOISE_DBM; /* 4 EDCA QOS priorities */ hw->queues = 4; @@ -8021,9 +7911,6 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e spin_lock_init(&priv->sta_lock); spin_lock_init(&priv->hcmd_lock); - for (i = 0; i < IWL_IBSS_MAC_HASH_SIZE; i++) - INIT_LIST_HEAD(&priv->ibss_mac_hash[i]); - INIT_LIST_HEAD(&priv->free_frames); mutex_init(&priv->mutex); @@ -8161,6 +8048,11 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e pci_save_state(pdev); pci_disable_device(pdev); + err = iwl3945_rfkill_init(priv); + if (err) + IWL_ERROR("Unable to initialize RFKILL system. " + "Ignoring error: %d\n", err); + return 0; out_free_geos: @@ -8191,8 +8083,6 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e static void __devexit iwl3945_pci_remove(struct pci_dev *pdev) { struct iwl3945_priv *priv = pci_get_drvdata(pdev); - struct list_head *p, *q; - int i; unsigned long flags; if (!priv) @@ -8213,16 +8103,9 @@ static void __devexit iwl3945_pci_remove(struct pci_dev *pdev) iwl_synchronize_irq(priv); - /* Free MAC hash list for ADHOC */ - for (i = 0; i < IWL_IBSS_MAC_HASH_SIZE; i++) { - list_for_each_safe(p, q, &priv->ibss_mac_hash[i]) { - list_del(p); - kfree(list_entry(p, struct iwl3945_ibss_seq, list)); - } - } - sysfs_remove_group(&pdev->dev.kobj, &iwl3945_attribute_group); + iwl3945_rfkill_unregister(priv); iwl3945_dealloc_ucode_pci(priv); if (priv->rxq.bd) @@ -8252,7 +8135,7 @@ static void __devexit iwl3945_pci_remove(struct pci_dev *pdev) iwl3945_free_channel_map(priv); iwl3945_free_geos(priv); - + kfree(priv->scan); if (priv->ibss_beacon) dev_kfree_skb(priv->ibss_beacon); @@ -8291,6 +8174,114 @@ static int iwl3945_pci_resume(struct pci_dev *pdev) #endif /* CONFIG_PM */ +/*************** RFKILL FUNCTIONS **********/ +#ifdef CONFIG_IWL3945_RFKILL +/* software rf-kill from user */ +static int iwl3945_rfkill_soft_rf_kill(void *data, enum rfkill_state state) +{ + struct iwl3945_priv *priv = data; + int err = 0; + + if (!priv->rfkill) + return 0; + + if (test_bit(STATUS_EXIT_PENDING, &priv->status)) + return 0; + + IWL_DEBUG_RF_KILL("we recieved soft RFKILL set to state %d\n", state); + mutex_lock(&priv->mutex); + + switch (state) { + case RFKILL_STATE_UNBLOCKED: + if (iwl3945_is_rfkill_hw(priv)) { + err = -EBUSY; + goto out_unlock; + } + iwl3945_radio_kill_sw(priv, 0); + break; + case RFKILL_STATE_SOFT_BLOCKED: + iwl3945_radio_kill_sw(priv, 1); + break; + default: + IWL_WARNING("we recieved unexpected RFKILL state %d\n", state); + break; + } +out_unlock: + mutex_unlock(&priv->mutex); + + return err; +} + +int iwl3945_rfkill_init(struct iwl3945_priv *priv) +{ + struct device *device = wiphy_dev(priv->hw->wiphy); + int ret = 0; + + BUG_ON(device == NULL); + + IWL_DEBUG_RF_KILL("Initializing RFKILL.\n"); + priv->rfkill = rfkill_allocate(device, RFKILL_TYPE_WLAN); + if (!priv->rfkill) { + IWL_ERROR("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 = iwl3945_rfkill_soft_rf_kill; + priv->rfkill->user_claim_unsupported = 1; + + priv->rfkill->dev.class->suspend = NULL; + priv->rfkill->dev.class->resume = NULL; + + ret = rfkill_register(priv->rfkill); + if (ret) { + IWL_ERROR("Unable to register rfkill: %d\n", ret); + goto freed_rfkill; + } + + IWL_DEBUG_RF_KILL("RFKILL initialization complete.\n"); + return ret; + +freed_rfkill: + if (priv->rfkill != NULL) + rfkill_free(priv->rfkill); + priv->rfkill = NULL; + +error: + IWL_DEBUG_RF_KILL("RFKILL initialization complete.\n"); + return ret; +} + +void iwl3945_rfkill_unregister(struct iwl3945_priv *priv) +{ + if (priv->rfkill) + rfkill_unregister(priv->rfkill); + + priv->rfkill = NULL; +} + +/* set rf-kill to the right state. */ +void iwl3945_rfkill_set_hw_state(struct iwl3945_priv *priv) +{ + + if (!priv->rfkill) + return; + + if (iwl3945_is_rfkill_hw(priv)) { + rfkill_force_state(priv->rfkill, RFKILL_STATE_HARD_BLOCKED); + return; + } + + if (!iwl3945_is_rfkill_sw(priv)) + rfkill_force_state(priv->rfkill, RFKILL_STATE_UNBLOCKED); + else + rfkill_force_state(priv->rfkill, RFKILL_STATE_SOFT_BLOCKED); +} +#endif + /***************************************************************************** * * driver and module entry point diff --git a/drivers/net/wireless/iwlwifi/iwl4965-base.c b/drivers/net/wireless/iwlwifi/iwl4965-base.c index 0bd55bb19739..71f5da3fe5c4 100644 --- a/drivers/net/wireless/iwlwifi/iwl4965-base.c +++ b/drivers/net/wireless/iwlwifi/iwl4965-base.c @@ -46,14 +46,13 @@ #include <asm/div64.h> #include "iwl-eeprom.h" -#include "iwl-4965.h" +#include "iwl-dev.h" #include "iwl-core.h" #include "iwl-io.h" #include "iwl-helpers.h" #include "iwl-sta.h" +#include "iwl-calib.h" -static int iwl4965_tx_queue_update_write_ptr(struct iwl_priv *priv, - struct iwl4965_tx_queue *txq); /****************************************************************************** * @@ -88,292 +87,6 @@ MODULE_VERSION(DRV_VERSION); MODULE_AUTHOR(DRV_COPYRIGHT); MODULE_LICENSE("GPL"); -__le16 *ieee80211_get_qos_ctrl(struct ieee80211_hdr *hdr) -{ - u16 fc = le16_to_cpu(hdr->frame_control); - int hdr_len = ieee80211_get_hdrlen(fc); - - if ((fc & 0x00cc) == (IEEE80211_STYPE_QOS_DATA | IEEE80211_FTYPE_DATA)) - return (__le16 *) ((u8 *) hdr + hdr_len - QOS_CONTROL_LEN); - return NULL; -} - -static const struct ieee80211_supported_band *iwl4965_get_hw_mode( - struct iwl_priv *priv, enum ieee80211_band band) -{ - return priv->hw->wiphy->bands[band]; -} - -static int iwl4965_is_empty_essid(const char *essid, int essid_len) -{ - /* Single white space is for Linksys APs */ - if (essid_len == 1 && essid[0] == ' ') - return 1; - - /* Otherwise, if the entire essid is 0, we assume it is hidden */ - while (essid_len) { - essid_len--; - if (essid[essid_len] != '\0') - return 0; - } - - return 1; -} - -static const char *iwl4965_escape_essid(const char *essid, u8 essid_len) -{ - static char escaped[IW_ESSID_MAX_SIZE * 2 + 1]; - const char *s = essid; - char *d = escaped; - - if (iwl4965_is_empty_essid(essid, essid_len)) { - memcpy(escaped, "<hidden>", sizeof("<hidden>")); - return escaped; - } - - essid_len = min(essid_len, (u8) IW_ESSID_MAX_SIZE); - while (essid_len--) { - if (*s == '\0') { - *d++ = '\\'; - *d++ = '0'; - s++; - } else - *d++ = *s++; - } - *d = '\0'; - return escaped; -} - -/*************** DMA-QUEUE-GENERAL-FUNCTIONS ***** - * DMA services - * - * Theory of operation - * - * A Tx or Rx queue resides in host DRAM, and is comprised of a circular buffer - * of buffer descriptors, each of which points to one or more data buffers for - * the device to read from or fill. Driver and device exchange status of each - * queue via "read" and "write" pointers. Driver keeps minimum of 2 empty - * entries in each circular buffer, to protect against confusing empty and full - * queue states. - * - * The device reads or writes the data in the queues via the device's several - * DMA/FIFO channels. Each queue is mapped to a single DMA channel. - * - * For Tx queue, there are low mark and high mark limits. If, after queuing - * the packet for Tx, free space become < low mark, Tx queue stopped. When - * reclaiming packets (on 'tx done IRQ), if free space become > high mark, - * Tx queue resumed. - * - * The 4965 operates with up to 17 queues: One receive queue, one transmit - * queue (#4) for sending commands to the device firmware, and 15 other - * Tx queues that may be mapped to prioritized Tx DMA/FIFO channels. - * - * See more detailed info in iwl-4965-hw.h. - ***************************************************/ - -int iwl4965_queue_space(const struct iwl4965_queue *q) -{ - int s = q->read_ptr - q->write_ptr; - - if (q->read_ptr > q->write_ptr) - s -= q->n_bd; - - if (s <= 0) - s += q->n_window; - /* keep some reserve to not confuse empty and full situations */ - s -= 2; - if (s < 0) - s = 0; - return s; -} - - -static inline int x2_queue_used(const struct iwl4965_queue *q, int i) -{ - return q->write_ptr > q->read_ptr ? - (i >= q->read_ptr && i < q->write_ptr) : - !(i < q->read_ptr && i >= q->write_ptr); -} - -static inline u8 get_cmd_index(struct iwl4965_queue *q, u32 index, int is_huge) -{ - /* This is for scan command, the big buffer at end of command array */ - if (is_huge) - return q->n_window; /* must be power of 2 */ - - /* Otherwise, use normal size buffers */ - return index & (q->n_window - 1); -} - -/** - * iwl4965_queue_init - Initialize queue's high/low-water and read/write indexes - */ -static int iwl4965_queue_init(struct iwl_priv *priv, struct iwl4965_queue *q, - int count, int slots_num, u32 id) -{ - q->n_bd = count; - q->n_window = slots_num; - q->id = id; - - /* count must be power-of-two size, otherwise iwl_queue_inc_wrap - * and iwl_queue_dec_wrap are broken. */ - BUG_ON(!is_power_of_2(count)); - - /* slots_num must be power-of-two size, otherwise - * get_cmd_index is broken. */ - BUG_ON(!is_power_of_2(slots_num)); - - q->low_mark = q->n_window / 4; - if (q->low_mark < 4) - q->low_mark = 4; - - q->high_mark = q->n_window / 8; - if (q->high_mark < 2) - q->high_mark = 2; - - q->write_ptr = q->read_ptr = 0; - - return 0; -} - -/** - * iwl4965_tx_queue_alloc - Alloc driver data and TFD CB for one Tx/cmd queue - */ -static int iwl4965_tx_queue_alloc(struct iwl_priv *priv, - struct iwl4965_tx_queue *txq, u32 id) -{ - struct pci_dev *dev = priv->pci_dev; - - /* Driver private data, only for Tx (not command) queues, - * not shared with device. */ - if (id != IWL_CMD_QUEUE_NUM) { - txq->txb = kmalloc(sizeof(txq->txb[0]) * - TFD_QUEUE_SIZE_MAX, GFP_KERNEL); - if (!txq->txb) { - IWL_ERROR("kmalloc for auxiliary BD " - "structures failed\n"); - goto error; - } - } else - txq->txb = NULL; - - /* Circular buffer of transmit frame descriptors (TFDs), - * shared with device */ - txq->bd = pci_alloc_consistent(dev, - sizeof(txq->bd[0]) * TFD_QUEUE_SIZE_MAX, - &txq->q.dma_addr); - - if (!txq->bd) { - IWL_ERROR("pci_alloc_consistent(%zd) failed\n", - sizeof(txq->bd[0]) * TFD_QUEUE_SIZE_MAX); - goto error; - } - txq->q.id = id; - - return 0; - - error: - if (txq->txb) { - kfree(txq->txb); - txq->txb = NULL; - } - - return -ENOMEM; -} - -/** - * iwl4965_tx_queue_init - Allocate and initialize one tx/cmd queue - */ -int iwl4965_tx_queue_init(struct iwl_priv *priv, - struct iwl4965_tx_queue *txq, int slots_num, u32 txq_id) -{ - struct pci_dev *dev = priv->pci_dev; - int len; - int rc = 0; - - /* - * Alloc buffer array for commands (Tx or other types of commands). - * For the command queue (#4), allocate command space + one big - * command for scan, since scan command is very huge; the system will - * not have two scans at the same time, so only one is needed. - * For normal Tx queues (all other queues), no super-size command - * space is needed. - */ - len = sizeof(struct iwl_cmd) * slots_num; - if (txq_id == IWL_CMD_QUEUE_NUM) - len += IWL_MAX_SCAN_SIZE; - txq->cmd = pci_alloc_consistent(dev, len, &txq->dma_addr_cmd); - if (!txq->cmd) - return -ENOMEM; - - /* Alloc driver data array and TFD circular buffer */ - rc = iwl4965_tx_queue_alloc(priv, txq, txq_id); - if (rc) { - pci_free_consistent(dev, len, txq->cmd, txq->dma_addr_cmd); - - return -ENOMEM; - } - txq->need_update = 0; - - /* TFD_QUEUE_SIZE_MAX must be power-of-two size, otherwise - * iwl_queue_inc_wrap and iwl_queue_dec_wrap are broken. */ - BUILD_BUG_ON(TFD_QUEUE_SIZE_MAX & (TFD_QUEUE_SIZE_MAX - 1)); - - /* Initialize queue's high/low-water marks, and head/tail indexes */ - iwl4965_queue_init(priv, &txq->q, TFD_QUEUE_SIZE_MAX, slots_num, txq_id); - - /* Tell device where to find queue */ - iwl4965_hw_tx_queue_init(priv, txq); - - return 0; -} - -/** - * iwl4965_tx_queue_free - Deallocate DMA queue. - * @txq: Transmit queue to deallocate. - * - * Empty queue by removing and destroying all BD's. - * Free all buffers. - * 0-fill, but do not free "txq" descriptor structure. - */ -void iwl4965_tx_queue_free(struct iwl_priv *priv, struct iwl4965_tx_queue *txq) -{ - struct iwl4965_queue *q = &txq->q; - struct pci_dev *dev = priv->pci_dev; - int len; - - if (q->n_bd == 0) - return; - - /* first, empty all BD's */ - for (; q->write_ptr != q->read_ptr; - q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd)) - iwl4965_hw_txq_free_tfd(priv, txq); - - len = sizeof(struct iwl_cmd) * q->n_window; - if (q->id == IWL_CMD_QUEUE_NUM) - len += IWL_MAX_SCAN_SIZE; - - /* De-alloc array of command/tx buffers */ - pci_free_consistent(dev, len, txq->cmd, txq->dma_addr_cmd); - - /* De-alloc circular buffer of TFDs */ - if (txq->q.n_bd) - pci_free_consistent(dev, sizeof(struct iwl4965_tfd_frame) * - txq->q.n_bd, txq->bd, txq->q.dma_addr); - - /* De-alloc array of per-TFD driver data */ - if (txq->txb) { - kfree(txq->txb); - txq->txb = NULL; - } - - /* 0-fill queue descriptor structure */ - memset(txq, 0, sizeof(*txq)); -} - -const u8 iwl4965_broadcast_addr[ETH_ALEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; - /*************** STATION TABLE MANAGEMENT **** * mac80211 should be examined to determine if sta_info is duplicating * the functionality provided here @@ -381,213 +94,11 @@ const u8 iwl4965_broadcast_addr[ETH_ALEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF /**************************************************************/ -#if 0 /* temporary disable till we add real remove station */ -/** - * iwl4965_remove_station - Remove driver's knowledge of station. - * - * NOTE: This does not remove station from device's station table. - */ -static u8 iwl4965_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[i].used && - !compare_ether_addr(priv->stations[i].sta.sta.addr, - addr)) { - index = i; - break; - } - - if (unlikely(index == IWL_INVALID_STATION)) - goto out; - - if (priv->stations[index].used) { - priv->stations[index].used = 0; - priv->num_stations--; - } - - BUG_ON(priv->num_stations < 0); - -out: - spin_unlock_irqrestore(&priv->sta_lock, flags); - return 0; -} -#endif - -/** - * iwl4965_add_station_flags - Add station to tables in driver and device - */ -u8 iwl4965_add_station_flags(struct iwl_priv *priv, const u8 *addr, - int is_ap, u8 flags, void *ht_data) -{ - int i; - int index = IWL_INVALID_STATION; - struct iwl4965_station_entry *station; - unsigned long flags_spin; - DECLARE_MAC_BUF(mac); - - 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[i].sta.sta.addr, - addr)) { - index = i; - break; - } - - if (!priv->stations[i].used && - index == IWL_INVALID_STATION) - index = i; - } - - - /* These two conditions have the same outcome, but keep them separate - since they have different meanings */ - if (unlikely(index == IWL_INVALID_STATION)) { - spin_unlock_irqrestore(&priv->sta_lock, flags_spin); - return index; - } - - if (priv->stations[index].used && - !compare_ether_addr(priv->stations[index].sta.sta.addr, addr)) { - spin_unlock_irqrestore(&priv->sta_lock, flags_spin); - return index; - } - - - IWL_DEBUG_ASSOC("Add STA ID %d: %s\n", index, print_mac(mac, addr)); - station = &priv->stations[index]; - station->used = 1; - priv->num_stations++; - - /* Set up the REPLY_ADD_STA command to send to device */ - memset(&station->sta, 0, sizeof(struct iwl4965_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; - -#ifdef CONFIG_IWL4965_HT - /* BCAST station and IBSS stations do not work in HT mode */ - if (index != priv->hw_params.bcast_sta_id && - priv->iw_mode != IEEE80211_IF_TYPE_IBSS) - iwl4965_set_ht_add_station(priv, index, - (struct ieee80211_ht_info *) ht_data); -#endif /*CONFIG_IWL4965_HT*/ - - spin_unlock_irqrestore(&priv->sta_lock, flags_spin); - - /* Add station to device's station table */ - iwl4965_send_add_station(priv, &station->sta, flags); - return index; - -} - - - -/*************** HOST COMMAND QUEUE FUNCTIONS *****/ - -/** - * iwl4965_enqueue_hcmd - enqueue a uCode command - * @priv: device private data point - * @cmd: a point to the ucode command structure - * - * The function returns < 0 values to indicate the operation is - * failed. On success, it turns the index (> 0) of command in the - * command queue. - */ -int iwl4965_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd) -{ - struct iwl4965_tx_queue *txq = &priv->txq[IWL_CMD_QUEUE_NUM]; - struct iwl4965_queue *q = &txq->q; - struct iwl4965_tfd_frame *tfd; - u32 *control_flags; - struct iwl_cmd *out_cmd; - u32 idx; - u16 fix_size = (u16)(cmd->len + sizeof(out_cmd->hdr)); - dma_addr_t phys_addr; - int ret; - unsigned long flags; - - /* If any of the command structures end up being larger than - * the TFD_MAX_PAYLOAD_SIZE, and it sent as a 'small' command then - * we will need to increase the size of the TFD entries */ - BUG_ON((fix_size > TFD_MAX_PAYLOAD_SIZE) && - !(cmd->meta.flags & CMD_SIZE_HUGE)); - - if (iwl_is_rfkill(priv)) { - IWL_DEBUG_INFO("Not sending command - RF KILL"); - return -EIO; - } - - if (iwl4965_queue_space(q) < ((cmd->meta.flags & CMD_ASYNC) ? 2 : 1)) { - IWL_ERROR("No space for Tx\n"); - return -ENOSPC; - } - - spin_lock_irqsave(&priv->hcmd_lock, flags); - - tfd = &txq->bd[q->write_ptr]; - memset(tfd, 0, sizeof(*tfd)); - - control_flags = (u32 *) tfd; - idx = get_cmd_index(q, q->write_ptr, cmd->meta.flags & CMD_SIZE_HUGE); - out_cmd = &txq->cmd[idx]; - - out_cmd->hdr.cmd = cmd->id; - memcpy(&out_cmd->meta, &cmd->meta, sizeof(cmd->meta)); - memcpy(&out_cmd->cmd.payload, cmd->data, cmd->len); - - /* At this point, the out_cmd now has all of the incoming cmd - * information */ - - out_cmd->hdr.flags = 0; - out_cmd->hdr.sequence = cpu_to_le16(QUEUE_TO_SEQ(IWL_CMD_QUEUE_NUM) | - INDEX_TO_SEQ(q->write_ptr)); - if (out_cmd->meta.flags & CMD_SIZE_HUGE) - out_cmd->hdr.sequence |= cpu_to_le16(SEQ_HUGE_FRAME); - - phys_addr = txq->dma_addr_cmd + sizeof(txq->cmd[0]) * idx + - offsetof(struct iwl_cmd, hdr); - iwl4965_hw_txq_attach_buf_to_tfd(priv, tfd, phys_addr, fix_size); - - IWL_DEBUG_HC("Sending command %s (#%x), seq: 0x%04X, " - "%d bytes at %d[%d]:%d\n", - get_cmd_string(out_cmd->hdr.cmd), - out_cmd->hdr.cmd, le16_to_cpu(out_cmd->hdr.sequence), - fix_size, q->write_ptr, idx, IWL_CMD_QUEUE_NUM); - - txq->need_update = 1; - - /* Set up entry in queue's byte count circular buffer */ - priv->cfg->ops->lib->txq_update_byte_cnt_tbl(priv, txq, 0); - - /* Increment and update queue's write index */ - q->write_ptr = iwl_queue_inc_wrap(q->write_ptr, q->n_bd); - ret = iwl4965_tx_queue_update_write_ptr(priv, txq); - - spin_unlock_irqrestore(&priv->hcmd_lock, flags); - return ret ? ret : idx; -} static void iwl4965_set_rxon_hwcrypto(struct iwl_priv *priv, int hw_decrypt) { - struct iwl4965_rxon_cmd *rxon = &priv->staging_rxon; + struct iwl_rxon_cmd *rxon = &priv->staging_rxon; if (hw_decrypt) rxon->filter_flags &= ~RXON_FILTER_DIS_DECRYPT_MSK; @@ -597,45 +108,13 @@ static void iwl4965_set_rxon_hwcrypto(struct iwl_priv *priv, int hw_decrypt) } /** - * iwl4965_rxon_add_station - add station into station table. - * - * there is only one AP station with id= IWL_AP_ID - * NOTE: mutex must be held before calling this fnction - */ -static int iwl4965_rxon_add_station(struct iwl_priv *priv, - const u8 *addr, int is_ap) -{ - u8 sta_id; - - /* Add station to device's station table */ -#ifdef CONFIG_IWL4965_HT - struct ieee80211_conf *conf = &priv->hw->conf; - struct ieee80211_ht_info *cur_ht_config = &conf->ht_conf; - - if ((is_ap) && - (conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE) && - (priv->iw_mode == IEEE80211_IF_TYPE_STA)) - sta_id = iwl4965_add_station_flags(priv, addr, is_ap, - 0, cur_ht_config); - else -#endif /* CONFIG_IWL4965_HT */ - sta_id = iwl4965_add_station_flags(priv, addr, is_ap, - 0, NULL); - - /* Set up default rate scaling table in device's station table */ - iwl4965_add_station(priv, addr, is_ap); - - return sta_id; -} - -/** * iwl4965_check_rxon_cmd - validate RXON structure is valid * * NOTE: This is really only useful during development and can eventually * be #ifdef'd out once the driver is stable and folks aren't actively * making changes */ -static int iwl4965_check_rxon_cmd(struct iwl4965_rxon_cmd *rxon) +static int iwl4965_check_rxon_cmd(struct iwl_rxon_cmd *rxon) { int error = 0; int counter = 1; @@ -713,7 +192,7 @@ static int iwl4965_full_rxon_required(struct iwl_priv *priv) { /* These items are only settable from the full RXON command */ - if (!(priv->active_rxon.filter_flags & RXON_FILTER_ASSOC_MSK) || + if (!(iwl_is_associated(priv)) || compare_ether_addr(priv->staging_rxon.bssid_addr, priv->active_rxon.bssid_addr) || compare_ether_addr(priv->staging_rxon.node_addr, @@ -760,18 +239,23 @@ static int iwl4965_full_rxon_required(struct iwl_priv *priv) static int iwl4965_commit_rxon(struct iwl_priv *priv) { /* cast away the const for active_rxon in this function */ - struct iwl4965_rxon_cmd *active_rxon = (void *)&priv->active_rxon; + struct iwl_rxon_cmd *active_rxon = (void *)&priv->active_rxon; DECLARE_MAC_BUF(mac); - int rc = 0; + int ret; + bool new_assoc = + !!(priv->staging_rxon.filter_flags & RXON_FILTER_ASSOC_MSK); if (!iwl_is_alive(priv)) - return -1; + return -EBUSY; /* always get timestamp with Rx frame */ priv->staging_rxon.flags |= RXON_FLG_TSF2HOST_MSK; + /* allow CTS-to-self if possible. this is relevant only for + * 5000, but will not damage 4965 */ + priv->staging_rxon.flags |= RXON_FLG_SELF_CTS_EN; - rc = iwl4965_check_rxon_cmd(&priv->staging_rxon); - if (rc) { + ret = iwl4965_check_rxon_cmd(&priv->staging_rxon); + if (ret) { IWL_ERROR("Invalid RXON configuration. Not committing.\n"); return -EINVAL; } @@ -780,49 +264,37 @@ static int iwl4965_commit_rxon(struct iwl_priv *priv) * iwl4965_rxon_assoc_cmd which is used to reconfigure filter * and other flags for the current radio configuration. */ if (!iwl4965_full_rxon_required(priv)) { - rc = iwl_send_rxon_assoc(priv); - if (rc) { - IWL_ERROR("Error setting RXON_ASSOC " - "configuration (%d).\n", rc); - return rc; + ret = iwl_send_rxon_assoc(priv); + if (ret) { + IWL_ERROR("Error setting RXON_ASSOC (%d)\n", ret); + return ret; } memcpy(active_rxon, &priv->staging_rxon, sizeof(*active_rxon)); - return 0; } /* station table will be cleared */ priv->assoc_station_added = 0; -#ifdef CONFIG_IWL4965_SENSITIVITY - priv->sensitivity_data.state = IWL_SENS_CALIB_NEED_REINIT; - if (!priv->error_recovering) - priv->start_calib = 0; - - iwl4965_init_sensitivity(priv, CMD_ASYNC, 1); -#endif /* CONFIG_IWL4965_SENSITIVITY */ - /* 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) && - (priv->staging_rxon.filter_flags & RXON_FILTER_ASSOC_MSK)) { + if (iwl_is_associated(priv) && new_assoc) { IWL_DEBUG_INFO("Toggling associated bit on current RXON\n"); active_rxon->filter_flags &= ~RXON_FILTER_ASSOC_MSK; - rc = iwl_send_cmd_pdu(priv, REPLY_RXON, - sizeof(struct iwl4965_rxon_cmd), + ret = iwl_send_cmd_pdu(priv, REPLY_RXON, + sizeof(struct iwl_rxon_cmd), &priv->active_rxon); /* If the mask clearing failed then we set * active_rxon back to what it was previously */ - if (rc) { + if (ret) { active_rxon->filter_flags |= RXON_FILTER_ASSOC_MSK; - IWL_ERROR("Error clearing ASSOC_MSK on current " - "configuration (%d).\n", rc); - return rc; + IWL_ERROR("Error clearing ASSOC_MSK (%d)\n", ret); + return ret; } } @@ -830,65 +302,87 @@ static int iwl4965_commit_rxon(struct iwl_priv *priv) "* with%s RXON_FILTER_ASSOC_MSK\n" "* channel = %d\n" "* bssid = %s\n", - ((priv->staging_rxon.filter_flags & - RXON_FILTER_ASSOC_MSK) ? "" : "out"), + (new_assoc ? "" : "out"), le16_to_cpu(priv->staging_rxon.channel), print_mac(mac, priv->staging_rxon.bssid_addr)); - iwl4965_set_rxon_hwcrypto(priv, !priv->cfg->mod_params->sw_crypto); - /* Apply the new configuration */ - rc = iwl_send_cmd_pdu(priv, REPLY_RXON, - sizeof(struct iwl4965_rxon_cmd), &priv->staging_rxon); - if (rc) { - IWL_ERROR("Error setting new configuration (%d).\n", rc); - return rc; + iwl4965_set_rxon_hwcrypto(priv, !priv->hw_params.sw_crypto); + + /* Apply the new configuration + * RXON unassoc clears the station table in uCode, send it before + * we add the bcast station. If assoc bit is set, we will send RXON + * after having added the bcast and bssid station. + */ + if (!new_assoc) { + ret = iwl_send_cmd_pdu(priv, REPLY_RXON, + sizeof(struct iwl_rxon_cmd), &priv->staging_rxon); + if (ret) { + IWL_ERROR("Error setting new RXON (%d)\n", ret); + return ret; + } + memcpy(active_rxon, &priv->staging_rxon, sizeof(*active_rxon)); } - iwlcore_clear_stations_table(priv); + iwl_clear_stations_table(priv); -#ifdef CONFIG_IWL4965_SENSITIVITY if (!priv->error_recovering) priv->start_calib = 0; - priv->sensitivity_data.state = IWL_SENS_CALIB_NEED_REINIT; - iwl4965_init_sensitivity(priv, CMD_ASYNC, 1); -#endif /* CONFIG_IWL4965_SENSITIVITY */ - - memcpy(active_rxon, &priv->staging_rxon, sizeof(*active_rxon)); - - /* 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 = iwl4965_hw_reg_send_txpower(priv); - if (rc) { - IWL_ERROR("Error setting Tx power (%d).\n", rc); - return rc; - } - /* Add the broadcast address so we can send broadcast frames */ - if (iwl4965_rxon_add_station(priv, iwl4965_broadcast_addr, 0) == - IWL_INVALID_STATION) { + if (iwl_rxon_add_station(priv, iwl_bcast_addr, 0) == + IWL_INVALID_STATION) { IWL_ERROR("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 == IEEE80211_IF_TYPE_STA)) { - if (iwl4965_rxon_add_station(priv, priv->active_rxon.bssid_addr, 1) - == IWL_INVALID_STATION) { - IWL_ERROR("Error adding AP address for transmit.\n"); - return -EIO; + if (new_assoc) { + if (priv->iw_mode == IEEE80211_IF_TYPE_STA) { + ret = iwl_rxon_add_station(priv, + priv->active_rxon.bssid_addr, 1); + if (ret == IWL_INVALID_STATION) { + IWL_ERROR("Error adding AP address for TX.\n"); + return -EIO; + } + priv->assoc_station_added = 1; + if (priv->default_wep_key && + iwl_send_static_wepkey_cmd(priv, 0)) + IWL_ERROR("Could not send WEP static key.\n"); } - priv->assoc_station_added = 1; - if (priv->default_wep_key && - iwl_send_static_wepkey_cmd(priv, 0)) - IWL_ERROR("Could not send WEP static key.\n"); + + /* Apply the new configuration + * RXON assoc doesn't clear the station table in uCode, + */ + ret = iwl_send_cmd_pdu(priv, REPLY_RXON, + sizeof(struct iwl_rxon_cmd), &priv->staging_rxon); + if (ret) { + IWL_ERROR("Error setting new RXON (%d)\n", ret); + return ret; + } + memcpy(active_rxon, &priv->staging_rxon, sizeof(*active_rxon)); + } + + iwl_init_sensitivity(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 */ + ret = iwl_set_tx_power(priv, priv->tx_power_user_lmt, true); + if (ret) { + IWL_ERROR("Error sending TX power (%d)\n", ret); + return ret; } return 0; } +void iwl4965_update_chain_flags(struct iwl_priv *priv) +{ + + iwl_set_rxon_chain(priv); + iwl4965_commit_rxon(priv); +} + static int iwl4965_send_bt_config(struct iwl_priv *priv) { struct iwl4965_bt_cmd bt_cmd = { @@ -903,155 +397,7 @@ static int iwl4965_send_bt_config(struct iwl_priv *priv) sizeof(struct iwl4965_bt_cmd), &bt_cmd); } -static int iwl4965_send_scan_abort(struct iwl_priv *priv) -{ - int rc = 0; - struct iwl4965_rx_packet *res; - struct iwl_host_cmd cmd = { - .id = REPLY_SCAN_ABORT_CMD, - .meta.flags = CMD_WANT_SKB, - }; - - /* If there isn't a scan actively going on in the hardware - * then we are in between scan bands and not actually - * actively scanning, so don't send the abort command */ - if (!test_bit(STATUS_SCAN_HW, &priv->status)) { - clear_bit(STATUS_SCAN_ABORTING, &priv->status); - return 0; - } - - rc = iwl_send_cmd_sync(priv, &cmd); - if (rc) { - clear_bit(STATUS_SCAN_ABORTING, &priv->status); - return rc; - } - - res = (struct iwl4965_rx_packet *)cmd.meta.u.skb->data; - if (res->u.status != CAN_ABORT_STATUS) { - /* The scan abort will return 1 for success or - * 2 for "failure". A failure condition can be - * due to simply not being in an active scan which - * can occur if we send the scan abort before we - * the microcode has notified us that a scan is - * completed. */ - IWL_DEBUG_INFO("SCAN_ABORT returned %d.\n", res->u.status); - clear_bit(STATUS_SCAN_ABORTING, &priv->status); - clear_bit(STATUS_SCAN_HW, &priv->status); - } - - dev_kfree_skb_any(cmd.meta.u.skb); - - return rc; -} - -static int iwl4965_card_state_sync_callback(struct iwl_priv *priv, - struct iwl_cmd *cmd, - struct sk_buff *skb) -{ - return 1; -} - -/* - * CARD_STATE_CMD - * - * Use: Sets the device's internal card state to enable, disable, or halt - * - * When in the 'enable' state the card operates as normal. - * When in the 'disable' state, the card enters into a low power mode. - * When in the 'halt' state, the card is shut down and must be fully - * restarted to come back on. - */ -static int iwl4965_send_card_state(struct iwl_priv *priv, u32 flags, u8 meta_flag) -{ - struct iwl_host_cmd cmd = { - .id = REPLY_CARD_STATE_CMD, - .len = sizeof(u32), - .data = &flags, - .meta.flags = meta_flag, - }; - - if (meta_flag & CMD_ASYNC) - cmd.meta.u.callback = iwl4965_card_state_sync_callback; - - return iwl_send_cmd(priv, &cmd); -} - -static int iwl4965_add_sta_sync_callback(struct iwl_priv *priv, - struct iwl_cmd *cmd, struct sk_buff *skb) -{ - struct iwl4965_rx_packet *res = NULL; - - if (!skb) { - IWL_ERROR("Error: Response NULL in REPLY_ADD_STA.\n"); - return 1; - } - - res = (struct iwl4965_rx_packet *)skb->data; - if (res->hdr.flags & IWL_CMD_FAILED_MSK) { - IWL_ERROR("Bad return from REPLY_ADD_STA (0x%08X)\n", - res->hdr.flags); - return 1; - } - - switch (res->u.add_sta.status) { - case ADD_STA_SUCCESS_MSK: - break; - default: - break; - } - - /* We didn't cache the SKB; let the caller free it */ - return 1; -} - -int iwl4965_send_add_station(struct iwl_priv *priv, - struct iwl4965_addsta_cmd *sta, u8 flags) -{ - struct iwl4965_rx_packet *res = NULL; - int rc = 0; - struct iwl_host_cmd cmd = { - .id = REPLY_ADD_STA, - .len = sizeof(struct iwl4965_addsta_cmd), - .meta.flags = flags, - .data = sta, - }; - - if (flags & CMD_ASYNC) - cmd.meta.u.callback = iwl4965_add_sta_sync_callback; - else - cmd.meta.flags |= CMD_WANT_SKB; - - rc = iwl_send_cmd(priv, &cmd); - - if (rc || (flags & CMD_ASYNC)) - return rc; - - res = (struct iwl4965_rx_packet *)cmd.meta.u.skb->data; - if (res->hdr.flags & IWL_CMD_FAILED_MSK) { - IWL_ERROR("Bad return from REPLY_ADD_STA (0x%08X)\n", - res->hdr.flags); - rc = -EIO; - } - - if (rc == 0) { - switch (res->u.add_sta.status) { - case ADD_STA_SUCCESS_MSK: - IWL_DEBUG_INFO("REPLY_ADD_STA PASSED\n"); - break; - default: - rc = -EIO; - IWL_WARNING("REPLY_ADD_STA failed\n"); - break; - } - } - - priv->alloc_rxb_skb--; - dev_kfree_skb_any(cmd.meta.u.skb); - - return rc; -} - -static void iwl4965_clear_free_frames(struct iwl_priv *priv) +static void iwl_clear_free_frames(struct iwl_priv *priv) { struct list_head *element; @@ -1061,7 +407,7 @@ static void iwl4965_clear_free_frames(struct iwl_priv *priv) while (!list_empty(&priv->free_frames)) { element = priv->free_frames.next; list_del(element); - kfree(list_entry(element, struct iwl4965_frame, list)); + kfree(list_entry(element, struct iwl_frame, list)); priv->frames_count--; } @@ -1072,9 +418,9 @@ static void iwl4965_clear_free_frames(struct iwl_priv *priv) } } -static struct iwl4965_frame *iwl4965_get_free_frame(struct iwl_priv *priv) +static struct iwl_frame *iwl_get_free_frame(struct iwl_priv *priv) { - struct iwl4965_frame *frame; + struct iwl_frame *frame; struct list_head *element; if (list_empty(&priv->free_frames)) { frame = kzalloc(sizeof(*frame), GFP_KERNEL); @@ -1089,10 +435,10 @@ static struct iwl4965_frame *iwl4965_get_free_frame(struct iwl_priv *priv) element = priv->free_frames.next; list_del(element); - return list_entry(element, struct iwl4965_frame, list); + return list_entry(element, struct iwl_frame, list); } -static void iwl4965_free_frame(struct iwl_priv *priv, struct iwl4965_frame *frame) +static void iwl_free_frame(struct iwl_priv *priv, struct iwl_frame *frame) { memset(frame, 0, sizeof(*frame)); list_add(&frame->list, &priv->free_frames); @@ -1116,27 +462,39 @@ unsigned int iwl4965_fill_beacon_frame(struct iwl_priv *priv, return priv->ibss_beacon->len; } -static u8 iwl4965_rate_get_lowest_plcp(int rate_mask) +static u8 iwl4965_rate_get_lowest_plcp(struct iwl_priv *priv) { - u8 i; + int i; + int rate_mask; + + /* Set rate mask*/ + if (priv->staging_rxon.flags & RXON_FLG_BAND_24G_MSK) + rate_mask = priv->active_rate_basic & 0xF; + else + rate_mask = priv->active_rate_basic & 0xFF0; + /* Find lowest valid rate */ for (i = IWL_RATE_1M_INDEX; i != IWL_RATE_INVALID; - i = iwl4965_rates[i].next_ieee) { + i = iwl_rates[i].next_ieee) { if (rate_mask & (1 << i)) - return iwl4965_rates[i].plcp; + return iwl_rates[i].plcp; } - return IWL_RATE_INVALID; + /* No valid rate was found. Assign the lowest one */ + if (priv->staging_rxon.flags & RXON_FLG_BAND_24G_MSK) + return IWL_RATE_1M_PLCP; + else + return IWL_RATE_6M_PLCP; } static int iwl4965_send_beacon_cmd(struct iwl_priv *priv) { - struct iwl4965_frame *frame; + struct iwl_frame *frame; unsigned int frame_size; int rc; u8 rate; - frame = iwl4965_get_free_frame(priv); + frame = iwl_get_free_frame(priv); if (!frame) { IWL_ERROR("Could not obtain free frame buffer for beacon " @@ -1144,23 +502,14 @@ static int iwl4965_send_beacon_cmd(struct iwl_priv *priv) return -ENOMEM; } - if (!(priv->staging_rxon.flags & RXON_FLG_BAND_24G_MSK)) { - rate = iwl4965_rate_get_lowest_plcp(priv->active_rate_basic & - 0xFF0); - if (rate == IWL_INVALID_RATE) - rate = IWL_RATE_6M_PLCP; - } else { - rate = iwl4965_rate_get_lowest_plcp(priv->active_rate_basic & 0xF); - if (rate == IWL_INVALID_RATE) - rate = IWL_RATE_1M_PLCP; - } + rate = iwl4965_rate_get_lowest_plcp(priv); frame_size = iwl4965_hw_get_beacon_cmd(priv, frame, rate); rc = iwl_send_cmd_pdu(priv, REPLY_TX_BEACON, frame_size, &frame->u.cmd[0]); - iwl4965_free_frame(priv, frame); + iwl_free_frame(priv, frame); return rc; } @@ -1171,184 +520,69 @@ static int iwl4965_send_beacon_cmd(struct iwl_priv *priv) * ******************************************************************************/ -static void iwl4965_unset_hw_params(struct iwl_priv *priv) -{ - if (priv->shared_virt) - pci_free_consistent(priv->pci_dev, - sizeof(struct iwl4965_shared), - priv->shared_virt, - priv->shared_phys); -} - -/** - * iwl4965_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 iwl4965_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] = iwl4965_rates[i].ieee | - ((bit & basic_rate) ? 0x80 : 0x00); - (*cnt)++; - (*left)--; - if ((*left <= 0) || - (*cnt >= IWL_SUPPORTED_RATES_IE_LEN)) - break; - } - } - - return ret_rates; -} - -/** - * iwl4965_fill_probe_req - fill in all required fields and IE for probe request - */ -static u16 iwl4965_fill_probe_req(struct iwl_priv *priv, - enum ieee80211_band band, - struct ieee80211_mgmt *frame, - int left, int is_direct) +static void iwl4965_ht_conf(struct iwl_priv *priv, + struct ieee80211_bss_conf *bss_conf) { - int len = 0; - u8 *pos = NULL; - u16 active_rates, ret_rates, cck_rates, active_rate_basic; -#ifdef CONFIG_IWL4965_HT - const struct ieee80211_supported_band *sband = - iwl4965_get_hw_mode(priv, band); -#endif /* CONFIG_IWL4965_HT */ - - /* Make sure there is enough space for the probe request, - * two mandatory IEs and the data */ - left -= 24; - if (left < 0) - return 0; - len += 24; + struct ieee80211_ht_info *ht_conf = bss_conf->ht_conf; + struct ieee80211_ht_bss_info *ht_bss_conf = bss_conf->ht_bss_conf; + struct iwl_ht_info *iwl_conf = &priv->current_ht_config; - frame->frame_control = cpu_to_le16(IEEE80211_STYPE_PROBE_REQ); - memcpy(frame->da, iwl4965_broadcast_addr, ETH_ALEN); - memcpy(frame->sa, priv->mac_addr, ETH_ALEN); - memcpy(frame->bssid, iwl4965_broadcast_addr, ETH_ALEN); - frame->seq_ctrl = 0; + IWL_DEBUG_MAC80211("enter: \n"); - /* fill in our indirect SSID IE */ - /* ...next IE... */ + iwl_conf->is_ht = bss_conf->assoc_ht; - left -= 2; - if (left < 0) - return 0; - len += 2; - pos = &(frame->u.probe_req.variable[0]); - *pos++ = WLAN_EID_SSID; - *pos++ = 0; - - /* fill in our direct SSID IE... */ - if (is_direct) { - /* ...next IE... */ - left -= 2 + priv->essid_len; - if (left < 0) - return 0; - /* ... fill it in... */ - *pos++ = WLAN_EID_SSID; - *pos++ = priv->essid_len; - memcpy(pos, priv->essid, priv->essid_len); - pos += priv->essid_len; - len += 2 + priv->essid_len; - } - - /* fill in supported rate */ - /* ...next IE... */ - left -= 2; - if (left < 0) - return 0; + if (!iwl_conf->is_ht) + return; - /* ... fill it in... */ - *pos++ = WLAN_EID_SUPP_RATES; - *pos = 0; + priv->ps_mode = (u8)((ht_conf->cap & IEEE80211_HT_CAP_MIMO_PS) >> 2); - /* exclude 60M rate */ - active_rates = priv->rates_mask; - active_rates &= ~IWL_RATE_60M_MASK; + 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; - active_rate_basic = active_rates & IWL_BASIC_RATES_MASK; + 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); - cck_rates = IWL_CCK_RATES_MASK & active_rates; - ret_rates = iwl4965_supported_rate_to_ie(pos, cck_rates, - active_rate_basic, &left); - active_rates &= ~ret_rates; + iwl_conf->supported_chan_width = + !!(ht_conf->cap & IEEE80211_HT_CAP_SUP_WIDTH); + iwl_conf->extension_chan_offset = + ht_bss_conf->bss_cap & IEEE80211_HT_IE_CHA_SEC_OFFSET; + /* If no above or below channel supplied disable FAT channel */ + if (iwl_conf->extension_chan_offset != IEEE80211_HT_IE_CHA_SEC_ABOVE && + iwl_conf->extension_chan_offset != IEEE80211_HT_IE_CHA_SEC_BELOW) { + iwl_conf->extension_chan_offset = IEEE80211_HT_IE_CHA_SEC_NONE; + iwl_conf->supported_chan_width = 0; + } - ret_rates = iwl4965_supported_rate_to_ie(pos, active_rates, - active_rate_basic, &left); - active_rates &= ~ret_rates; + iwl_conf->tx_mimo_ps_mode = + (u8)((ht_conf->cap & IEEE80211_HT_CAP_MIMO_PS) >> 2); + memcpy(iwl_conf->supp_mcs_set, ht_conf->supp_mcs_set, 16); - len += 2 + *pos; - pos += (*pos) + 1; - if (active_rates == 0) - goto fill_end; + iwl_conf->control_channel = ht_bss_conf->primary_channel; + iwl_conf->tx_chan_width = + !!(ht_bss_conf->bss_cap & IEEE80211_HT_IE_CHA_WIDTH); + iwl_conf->ht_protection = + ht_bss_conf->bss_op_mode & IEEE80211_HT_IE_HT_PROTECTION; + iwl_conf->non_GF_STA_present = + !!(ht_bss_conf->bss_op_mode & IEEE80211_HT_IE_NON_GF_STA_PRSNT); - /* 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; - iwl4965_supported_rate_to_ie(pos, active_rates, - active_rate_basic, &left); - if (*pos > 0) - len += 2 + *pos; - -#ifdef CONFIG_IWL4965_HT - if (sband && sband->ht_info.ht_supported) { - struct ieee80211_ht_cap *ht_cap; - pos += (*pos) + 1; - *pos++ = WLAN_EID_HT_CAPABILITY; - *pos++ = sizeof(struct ieee80211_ht_cap); - ht_cap = (struct ieee80211_ht_cap *)pos; - ht_cap->cap_info = cpu_to_le16(sband->ht_info.cap); - memcpy(ht_cap->supp_mcs_set, sband->ht_info.supp_mcs_set, 16); - ht_cap->ampdu_params_info =(sband->ht_info.ampdu_factor & - IEEE80211_HT_CAP_AMPDU_FACTOR) | - ((sband->ht_info.ampdu_density << 2) & - IEEE80211_HT_CAP_AMPDU_DENSITY); - len += 2 + sizeof(struct ieee80211_ht_cap); - } -#endif /*CONFIG_IWL4965_HT */ - - fill_end: - return (u16)len; + IWL_DEBUG_MAC80211("control channel %d\n", iwl_conf->control_channel); + IWL_DEBUG_MAC80211("leave\n"); } /* * QoS support */ -static int iwl4965_send_qos_params_command(struct iwl_priv *priv, - struct iwl4965_qosparam_cmd *qos) -{ - - return iwl_send_cmd_pdu(priv, REPLY_QOS_PARAM, - sizeof(struct iwl4965_qosparam_cmd), qos); -} - -static void iwl4965_activate_qos(struct iwl_priv *priv, u8 force) +static void iwl_activate_qos(struct iwl_priv *priv, u8 force) { - unsigned long flags; - if (test_bit(STATUS_EXIT_PENDING, &priv->status)) return; if (!priv->qos_data.qos_enable) return; - spin_lock_irqsave(&priv->lock, flags); priv->qos_data.def_qos_parm.qos_flags = 0; if (priv->qos_data.qos_cap.q_AP.queue_request && @@ -1359,323 +593,18 @@ static void iwl4965_activate_qos(struct iwl_priv *priv, u8 force) priv->qos_data.def_qos_parm.qos_flags |= QOS_PARAM_FLG_UPDATE_EDCA_MSK; -#ifdef CONFIG_IWL4965_HT if (priv->current_ht_config.is_ht) priv->qos_data.def_qos_parm.qos_flags |= QOS_PARAM_FLG_TGN_MSK; -#endif /* CONFIG_IWL4965_HT */ - - spin_unlock_irqrestore(&priv->lock, flags); if (force || iwl_is_associated(priv)) { IWL_DEBUG_QOS("send QoS cmd with Qos active=%d FLAGS=0x%X\n", priv->qos_data.qos_active, priv->qos_data.def_qos_parm.qos_flags); - iwl4965_send_qos_params_command(priv, - &(priv->qos_data.def_qos_parm)); - } -} - -/* - * Power management (not Tx power!) functions - */ -#define MSEC_TO_USEC 1024 - -#define NOSLP __constant_cpu_to_le16(0), 0, 0 -#define SLP IWL_POWER_DRIVER_ALLOW_SLEEP_MSK, 0, 0 -#define SLP_TIMEOUT(T) __constant_cpu_to_le32((T) * MSEC_TO_USEC) -#define SLP_VEC(X0, X1, X2, X3, X4) {__constant_cpu_to_le32(X0), \ - __constant_cpu_to_le32(X1), \ - __constant_cpu_to_le32(X2), \ - __constant_cpu_to_le32(X3), \ - __constant_cpu_to_le32(X4)} - - -/* default power management (not Tx power) table values */ -/* for tim 0-10 */ -static struct iwl4965_power_vec_entry range_0[IWL_POWER_AC] = { - {{NOSLP, SLP_TIMEOUT(0), SLP_TIMEOUT(0), SLP_VEC(0, 0, 0, 0, 0)}, 0}, - {{SLP, SLP_TIMEOUT(200), SLP_TIMEOUT(500), SLP_VEC(1, 2, 3, 4, 4)}, 0}, - {{SLP, SLP_TIMEOUT(200), SLP_TIMEOUT(300), SLP_VEC(2, 4, 6, 7, 7)}, 0}, - {{SLP, SLP_TIMEOUT(50), SLP_TIMEOUT(100), SLP_VEC(2, 6, 9, 9, 10)}, 0}, - {{SLP, SLP_TIMEOUT(50), SLP_TIMEOUT(25), SLP_VEC(2, 7, 9, 9, 10)}, 1}, - {{SLP, SLP_TIMEOUT(25), SLP_TIMEOUT(25), SLP_VEC(4, 7, 10, 10, 10)}, 1} -}; - -/* for tim > 10 */ -static struct iwl4965_power_vec_entry range_1[IWL_POWER_AC] = { - {{NOSLP, SLP_TIMEOUT(0), SLP_TIMEOUT(0), SLP_VEC(0, 0, 0, 0, 0)}, 0}, - {{SLP, SLP_TIMEOUT(200), SLP_TIMEOUT(500), - SLP_VEC(1, 2, 3, 4, 0xFF)}, 0}, - {{SLP, SLP_TIMEOUT(200), SLP_TIMEOUT(300), - SLP_VEC(2, 4, 6, 7, 0xFF)}, 0}, - {{SLP, SLP_TIMEOUT(50), SLP_TIMEOUT(100), - SLP_VEC(2, 6, 9, 9, 0xFF)}, 0}, - {{SLP, SLP_TIMEOUT(50), SLP_TIMEOUT(25), SLP_VEC(2, 7, 9, 9, 0xFF)}, 0}, - {{SLP, SLP_TIMEOUT(25), SLP_TIMEOUT(25), - SLP_VEC(4, 7, 10, 10, 0xFF)}, 0} -}; - -int iwl4965_power_init_handle(struct iwl_priv *priv) -{ - int rc = 0, i; - struct iwl4965_power_mgr *pow_data; - int size = sizeof(struct iwl4965_power_vec_entry) * IWL_POWER_AC; - u16 pci_pm; - - IWL_DEBUG_POWER("Initialize power \n"); - - pow_data = &(priv->power_data); - - memset(pow_data, 0, sizeof(*pow_data)); - - pow_data->active_index = IWL_POWER_RANGE_0; - pow_data->dtim_val = 0xffff; - - memcpy(&pow_data->pwr_range_0[0], &range_0[0], size); - memcpy(&pow_data->pwr_range_1[0], &range_1[0], size); - - rc = pci_read_config_word(priv->pci_dev, PCI_LINK_CTRL, &pci_pm); - if (rc != 0) - return 0; - else { - struct iwl4965_powertable_cmd *cmd; - - IWL_DEBUG_POWER("adjust power command flags\n"); - - for (i = 0; i < IWL_POWER_AC; i++) { - cmd = &pow_data->pwr_range_0[i].cmd; - - if (pci_pm & 0x1) - cmd->flags &= ~IWL_POWER_PCI_PM_MSK; - else - cmd->flags |= IWL_POWER_PCI_PM_MSK; - } + iwl_send_cmd_pdu_async(priv, REPLY_QOS_PARAM, + sizeof(struct iwl_qosparam_cmd), + &priv->qos_data.def_qos_parm, NULL); } - return rc; -} - -static int iwl4965_update_power_cmd(struct iwl_priv *priv, - struct iwl4965_powertable_cmd *cmd, u32 mode) -{ - int rc = 0, i; - u8 skip; - u32 max_sleep = 0; - struct iwl4965_power_vec_entry *range; - u8 period = 0; - struct iwl4965_power_mgr *pow_data; - - if (mode > IWL_POWER_INDEX_5) { - IWL_DEBUG_POWER("Error invalid power mode \n"); - return -1; - } - pow_data = &(priv->power_data); - - if (pow_data->active_index == IWL_POWER_RANGE_0) - range = &pow_data->pwr_range_0[0]; - else - range = &pow_data->pwr_range_1[1]; - - memcpy(cmd, &range[mode].cmd, sizeof(struct iwl4965_powertable_cmd)); - -#ifdef IWL_MAC80211_DISABLE - if (priv->assoc_network != NULL) { - unsigned long flags; - - period = priv->assoc_network->tim.tim_period; - } -#endif /*IWL_MAC80211_DISABLE */ - skip = range[mode].no_dtim; - - if (period == 0) { - period = 1; - skip = 0; - } - - if (skip == 0) { - max_sleep = period; - cmd->flags &= ~IWL_POWER_SLEEP_OVER_DTIM_MSK; - } else { - __le32 slp_itrvl = cmd->sleep_interval[IWL_POWER_VEC_SIZE - 1]; - max_sleep = (le32_to_cpu(slp_itrvl) / period) * period; - cmd->flags |= IWL_POWER_SLEEP_OVER_DTIM_MSK; - } - - for (i = 0; i < IWL_POWER_VEC_SIZE; i++) { - if (le32_to_cpu(cmd->sleep_interval[i]) > max_sleep) - cmd->sleep_interval[i] = cpu_to_le32(max_sleep); - } - - IWL_DEBUG_POWER("Flags value = 0x%08X\n", cmd->flags); - IWL_DEBUG_POWER("Tx timeout = %u\n", le32_to_cpu(cmd->tx_data_timeout)); - IWL_DEBUG_POWER("Rx timeout = %u\n", le32_to_cpu(cmd->rx_data_timeout)); - IWL_DEBUG_POWER("Sleep interval vector = { %d , %d , %d , %d , %d }\n", - le32_to_cpu(cmd->sleep_interval[0]), - le32_to_cpu(cmd->sleep_interval[1]), - le32_to_cpu(cmd->sleep_interval[2]), - le32_to_cpu(cmd->sleep_interval[3]), - le32_to_cpu(cmd->sleep_interval[4])); - - return rc; -} - -static int iwl4965_send_power_mode(struct iwl_priv *priv, u32 mode) -{ - u32 uninitialized_var(final_mode); - int rc; - struct iwl4965_powertable_cmd cmd; - - /* If on battery, set to 3, - * if plugged into AC power, set to CAM ("continuously aware mode"), - * else user level */ - switch (mode) { - case IWL_POWER_BATTERY: - final_mode = IWL_POWER_INDEX_3; - break; - case IWL_POWER_AC: - final_mode = IWL_POWER_MODE_CAM; - break; - default: - final_mode = mode; - break; - } - - cmd.keep_alive_beacons = 0; - - iwl4965_update_power_cmd(priv, &cmd, final_mode); - - rc = iwl_send_cmd_pdu(priv, POWER_TABLE_CMD, sizeof(cmd), &cmd); - - if (final_mode == IWL_POWER_MODE_CAM) - clear_bit(STATUS_POWER_PMI, &priv->status); - else - set_bit(STATUS_POWER_PMI, &priv->status); - - return rc; -} - -int iwl4965_is_network_packet(struct iwl_priv *priv, struct ieee80211_hdr *header) -{ - /* Filter incoming packets to determine if they are targeted toward - * this network, discarding packets coming from ourselves */ - switch (priv->iw_mode) { - case IEEE80211_IF_TYPE_IBSS: /* Header: Dest. | Source | BSSID */ - /* packets from our adapter are dropped (echo) */ - if (!compare_ether_addr(header->addr2, priv->mac_addr)) - return 0; - /* {broad,multi}cast packets to our IBSS go through */ - if (is_multicast_ether_addr(header->addr1)) - return !compare_ether_addr(header->addr3, priv->bssid); - /* packets to our adapter go through */ - return !compare_ether_addr(header->addr1, priv->mac_addr); - case IEEE80211_IF_TYPE_STA: /* Header: Dest. | AP{BSSID} | Source */ - /* packets from our adapter are dropped (echo) */ - if (!compare_ether_addr(header->addr3, priv->mac_addr)) - return 0; - /* {broad,multi}cast packets to our BSS go through */ - if (is_multicast_ether_addr(header->addr1)) - return !compare_ether_addr(header->addr2, priv->bssid); - /* packets to our adapter go through */ - return !compare_ether_addr(header->addr1, priv->mac_addr); - default: - break; - } - - return 1; -} - -#define TX_STATUS_ENTRY(x) case TX_STATUS_FAIL_ ## x: return #x - -static const char *iwl4965_get_tx_fail_reason(u32 status) -{ - switch (status & TX_STATUS_MSK) { - case TX_STATUS_SUCCESS: - return "SUCCESS"; - TX_STATUS_ENTRY(SHORT_LIMIT); - TX_STATUS_ENTRY(LONG_LIMIT); - TX_STATUS_ENTRY(FIFO_UNDERRUN); - TX_STATUS_ENTRY(MGMNT_ABORT); - TX_STATUS_ENTRY(NEXT_FRAG); - TX_STATUS_ENTRY(LIFE_EXPIRE); - TX_STATUS_ENTRY(DEST_PS); - TX_STATUS_ENTRY(ABORTED); - TX_STATUS_ENTRY(BT_RETRY); - TX_STATUS_ENTRY(STA_INVALID); - TX_STATUS_ENTRY(FRAG_DROPPED); - TX_STATUS_ENTRY(TID_DISABLE); - TX_STATUS_ENTRY(FRAME_FLUSHED); - TX_STATUS_ENTRY(INSUFFICIENT_CF_POLL); - TX_STATUS_ENTRY(TX_LOCKED); - TX_STATUS_ENTRY(NO_BEACON_ON_RADAR); - } - - return "UNKNOWN"; -} - -/** - * iwl4965_scan_cancel - Cancel any currently executing HW scan - * - * NOTE: priv->mutex is not required before calling this function - */ -static int iwl4965_scan_cancel(struct iwl_priv *priv) -{ - if (!test_bit(STATUS_SCAN_HW, &priv->status)) { - clear_bit(STATUS_SCANNING, &priv->status); - return 0; - } - - if (test_bit(STATUS_SCANNING, &priv->status)) { - if (!test_bit(STATUS_SCAN_ABORTING, &priv->status)) { - IWL_DEBUG_SCAN("Queuing scan abort.\n"); - set_bit(STATUS_SCAN_ABORTING, &priv->status); - queue_work(priv->workqueue, &priv->abort_scan); - - } else - IWL_DEBUG_SCAN("Scan abort already in progress.\n"); - - return test_bit(STATUS_SCANNING, &priv->status); - } - - return 0; -} - -/** - * iwl4965_scan_cancel_timeout - Cancel any currently executing HW scan - * @ms: amount of time to wait (in milliseconds) for scan to abort - * - * NOTE: priv->mutex must be held before calling this function - */ -static int iwl4965_scan_cancel_timeout(struct iwl_priv *priv, unsigned long ms) -{ - unsigned long now = jiffies; - int ret; - - ret = iwl4965_scan_cancel(priv); - if (ret && ms) { - mutex_unlock(&priv->mutex); - while (!time_after(jiffies, now + msecs_to_jiffies(ms)) && - test_bit(STATUS_SCANNING, &priv->status)) - msleep(1); - mutex_lock(&priv->mutex); - - return test_bit(STATUS_SCANNING, &priv->status); - } - - return ret; -} - -static void iwl4965_sequence_reset(struct iwl_priv *priv) -{ - /* Reset ieee stats */ - - /* We don't reset the net_device_stats (ieee->stats) on - * re-association */ - - priv->last_seq_num = -1; - priv->last_frag_num = -1; - priv->last_packet_time = 0; - - iwl4965_scan_cancel(priv); } #define MAX_UCODE_BEACON_INTERVAL 4096 @@ -1750,46 +679,8 @@ static void iwl4965_setup_rxon_timing(struct iwl_priv *priv) le16_to_cpu(priv->rxon_timing.atim_window)); } -static int iwl4965_scan_initiate(struct iwl_priv *priv) -{ - if (priv->iw_mode == IEEE80211_IF_TYPE_AP) { - IWL_ERROR("APs don't scan.\n"); - return 0; - } - - if (!iwl_is_ready_rf(priv)) { - IWL_DEBUG_SCAN("Aborting scan due to not ready.\n"); - return -EIO; - } - - if (test_bit(STATUS_SCANNING, &priv->status)) { - IWL_DEBUG_SCAN("Scan already in progress.\n"); - return -EAGAIN; - } - - if (test_bit(STATUS_SCAN_ABORTING, &priv->status)) { - IWL_DEBUG_SCAN("Scan request while abort pending. " - "Queuing.\n"); - return -EAGAIN; - } - - IWL_DEBUG_INFO("Starting scan...\n"); - if (priv->cfg->sku & IWL_SKU_G) - priv->scan_bands |= BIT(IEEE80211_BAND_2GHZ); - if (priv->cfg->sku & IWL_SKU_A) - priv->scan_bands |= BIT(IEEE80211_BAND_5GHZ); - set_bit(STATUS_SCANNING, &priv->status); - priv->scan_start = jiffies; - priv->scan_pass_start = priv->scan_start; - - queue_work(priv->workqueue, &priv->request_scan); - - return 0; -} - - -static void iwl4965_set_flags_for_phymode(struct iwl_priv *priv, - enum ieee80211_band band) +static void iwl_set_flags_for_band(struct iwl_priv *priv, + enum ieee80211_band band) { if (band == IEEE80211_BAND_5GHZ) { priv->staging_rxon.flags &= @@ -1858,7 +749,7 @@ static void iwl4965_connection_init_rx_config(struct iwl_priv *priv) #endif ch_info = iwl_get_channel_info(priv, priv->band, - le16_to_cpu(priv->staging_rxon.channel)); + le16_to_cpu(priv->active_rxon.channel)); if (!ch_info) ch_info = &priv->channel_info[0]; @@ -1874,7 +765,7 @@ static void iwl4965_connection_init_rx_config(struct iwl_priv *priv) priv->staging_rxon.channel = cpu_to_le16(ch_info->channel); priv->band = ch_info->band; - iwl4965_set_flags_for_phymode(priv, priv->band); + iwl_set_flags_for_band(priv, priv->band); priv->staging_rxon.ofdm_basic_rates = (IWL_OFDM_RATES_MASK >> IWL_FIRST_OFDM_RATE) & 0xFF; @@ -1887,38 +778,24 @@ static void iwl4965_connection_init_rx_config(struct iwl_priv *priv) 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; - iwl4965_set_rxon_chain(priv); + iwl_set_rxon_chain(priv); } static int iwl4965_set_mode(struct iwl_priv *priv, int mode) { - if (mode == IEEE80211_IF_TYPE_IBSS) { - 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_ERROR("channel %d not IBSS channel\n", - le16_to_cpu(priv->staging_rxon.channel)); - return -EINVAL; - } - } - priv->iw_mode = mode; iwl4965_connection_init_rx_config(priv); memcpy(priv->staging_rxon.node_addr, priv->mac_addr, ETH_ALEN); - iwlcore_clear_stations_table(priv); + iwl_clear_stations_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 (iwl4965_scan_cancel_timeout(priv, 100)) { + if (iwl_scan_cancel_timeout(priv, 100)) { IWL_WARNING("Aborted scan still in progress after 100ms\n"); IWL_DEBUG_MAC80211("leaving - scan abort failed.\n"); return -EAGAIN; @@ -1929,448 +806,13 @@ static int iwl4965_set_mode(struct iwl_priv *priv, int mode) return 0; } -static void iwl4965_build_tx_cmd_hwcrypto(struct iwl_priv *priv, - struct ieee80211_tx_control *ctl, - struct iwl_cmd *cmd, - struct sk_buff *skb_frag, - int sta_id) -{ - struct iwl4965_hw_key *keyinfo = &priv->stations[sta_id].keyinfo; - struct iwl_wep_key *wepkey; - int keyidx = 0; - - BUG_ON(ctl->key_idx > 3); - - switch (keyinfo->alg) { - case ALG_CCMP: - cmd->cmd.tx.sec_ctl = TX_CMD_SEC_CCM; - memcpy(cmd->cmd.tx.key, keyinfo->key, keyinfo->keylen); - if (ctl->flags & IEEE80211_TXCTL_AMPDU) - cmd->cmd.tx.tx_flags |= TX_CMD_FLG_AGG_CCMP_MSK; - IWL_DEBUG_TX("tx_cmd with aes hwcrypto\n"); - break; - - case ALG_TKIP: - cmd->cmd.tx.sec_ctl = TX_CMD_SEC_TKIP; - ieee80211_get_tkip_key(keyinfo->conf, skb_frag, - IEEE80211_TKIP_P2_KEY, cmd->cmd.tx.key); - IWL_DEBUG_TX("tx_cmd with tkip hwcrypto\n"); - break; - - case ALG_WEP: - wepkey = &priv->wep_keys[ctl->key_idx]; - cmd->cmd.tx.sec_ctl = 0; - if (priv->default_wep_key) { - /* the WEP key was sent as static */ - keyidx = ctl->key_idx; - memcpy(&cmd->cmd.tx.key[3], wepkey->key, - wepkey->key_size); - if (wepkey->key_size == WEP_KEY_LEN_128) - cmd->cmd.tx.sec_ctl |= TX_CMD_SEC_KEY128; - } else { - /* the WEP key was sent as dynamic */ - keyidx = keyinfo->keyidx; - memcpy(&cmd->cmd.tx.key[3], keyinfo->key, - keyinfo->keylen); - if (keyinfo->keylen == WEP_KEY_LEN_128) - cmd->cmd.tx.sec_ctl |= TX_CMD_SEC_KEY128; - } - - cmd->cmd.tx.sec_ctl |= (TX_CMD_SEC_WEP | - (keyidx & TX_CMD_SEC_MSK) << TX_CMD_SEC_SHIFT); - - IWL_DEBUG_TX("Configuring packet for WEP encryption " - "with key %d\n", keyidx); - break; - - default: - printk(KERN_ERR "Unknown encode alg %d\n", keyinfo->alg); - break; - } -} - -/* - * handle build REPLY_TX command notification. - */ -static void iwl4965_build_tx_cmd_basic(struct iwl_priv *priv, - struct iwl_cmd *cmd, - struct ieee80211_tx_control *ctrl, - struct ieee80211_hdr *hdr, - int is_unicast, u8 std_id) -{ - __le16 *qc; - u16 fc = le16_to_cpu(hdr->frame_control); - __le32 tx_flags = cmd->cmd.tx.tx_flags; - - cmd->cmd.tx.stop_time.life_time = TX_CMD_LIFE_TIME_INFINITE; - if (!(ctrl->flags & IEEE80211_TXCTL_NO_ACK)) { - tx_flags |= TX_CMD_FLG_ACK_MSK; - if ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT) - tx_flags |= TX_CMD_FLG_SEQ_CTL_MSK; - if (ieee80211_is_probe_response(fc) && - !(le16_to_cpu(hdr->seq_ctrl) & 0xf)) - tx_flags |= TX_CMD_FLG_TSF_MSK; - } else { - tx_flags &= (~TX_CMD_FLG_ACK_MSK); - tx_flags |= TX_CMD_FLG_SEQ_CTL_MSK; - } - - if (ieee80211_is_back_request(fc)) - tx_flags |= TX_CMD_FLG_ACK_MSK | TX_CMD_FLG_IMM_BA_RSP_MASK; - - - cmd->cmd.tx.sta_id = std_id; - if (ieee80211_get_morefrag(hdr)) - tx_flags |= TX_CMD_FLG_MORE_FRAG_MSK; - - qc = ieee80211_get_qos_ctrl(hdr); - if (qc) { - cmd->cmd.tx.tid_tspec = (u8) (le16_to_cpu(*qc) & 0xf); - tx_flags &= ~TX_CMD_FLG_SEQ_CTL_MSK; - } else - tx_flags |= TX_CMD_FLG_SEQ_CTL_MSK; - - if (ctrl->flags & IEEE80211_TXCTL_USE_RTS_CTS) { - tx_flags |= TX_CMD_FLG_RTS_MSK; - tx_flags &= ~TX_CMD_FLG_CTS_MSK; - } else if (ctrl->flags & IEEE80211_TXCTL_USE_CTS_PROTECT) { - tx_flags &= ~TX_CMD_FLG_RTS_MSK; - tx_flags |= TX_CMD_FLG_CTS_MSK; - } - - if ((tx_flags & TX_CMD_FLG_RTS_MSK) || (tx_flags & TX_CMD_FLG_CTS_MSK)) - tx_flags |= TX_CMD_FLG_FULL_TXOP_PROT_MSK; - - tx_flags &= ~(TX_CMD_FLG_ANT_SEL_MSK); - if ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT) { - if ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_ASSOC_REQ || - (fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_REASSOC_REQ) - cmd->cmd.tx.timeout.pm_frame_timeout = cpu_to_le16(3); - else - cmd->cmd.tx.timeout.pm_frame_timeout = cpu_to_le16(2); - } else { - cmd->cmd.tx.timeout.pm_frame_timeout = 0; - } - - cmd->cmd.tx.driver_txop = 0; - cmd->cmd.tx.tx_flags = tx_flags; - cmd->cmd.tx.next_frame_len = 0; -} -static void iwl_update_tx_stats(struct iwl_priv *priv, u16 fc, u16 len) -{ - /* 0 - mgmt, 1 - cnt, 2 - data */ - int idx = (fc & IEEE80211_FCTL_FTYPE) >> 2; - priv->tx_stats[idx].cnt++; - priv->tx_stats[idx].bytes += len; -} -/** - * iwl4965_get_sta_id - Find station's index within station table - * - * If new IBSS station, create new entry in station table - */ -static int iwl4965_get_sta_id(struct iwl_priv *priv, - struct ieee80211_hdr *hdr) -{ - int sta_id; - u16 fc = le16_to_cpu(hdr->frame_control); - DECLARE_MAC_BUF(mac); - - /* 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 IEEE80211_IF_TYPE_STA: - return IWL_AP_ID; - - /* If we are an AP, then find the station, or use BCAST */ - case IEEE80211_IF_TYPE_AP: - sta_id = iwl4965_hw_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 IEEE80211_IF_TYPE_IBSS: - sta_id = iwl4965_hw_find_station(priv, hdr->addr1); - if (sta_id != IWL_INVALID_STATION) - return sta_id; - - /* Create new station table entry */ - sta_id = iwl4965_add_station_flags(priv, hdr->addr1, - 0, CMD_ASYNC, NULL); - - if (sta_id != IWL_INVALID_STATION) - return sta_id; - - IWL_DEBUG_DROP("Station %s not in station map. " - "Defaulting to broadcast...\n", - print_mac(mac, hdr->addr1)); - iwl_print_hex_dump(IWL_DL_DROP, (u8 *) hdr, sizeof(*hdr)); - return priv->hw_params.bcast_sta_id; - - default: - IWL_WARNING("Unknown mode of operation: %d", priv->iw_mode); - return priv->hw_params.bcast_sta_id; - } -} - -/* - * start REPLY_TX command process - */ -static int iwl4965_tx_skb(struct iwl_priv *priv, - struct sk_buff *skb, struct ieee80211_tx_control *ctl) -{ - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; - struct iwl4965_tfd_frame *tfd; - u32 *control_flags; - int txq_id = ctl->queue; - struct iwl4965_tx_queue *txq = NULL; - struct iwl4965_queue *q = NULL; - dma_addr_t phys_addr; - dma_addr_t txcmd_phys; - dma_addr_t scratch_phys; - struct iwl_cmd *out_cmd = NULL; - u16 len, idx, len_org; - u8 id, hdr_len, unicast; - u8 sta_id; - u16 seq_number = 0; - u16 fc; - __le16 *qc; - u8 wait_write_ptr = 0; - unsigned long flags; - int rc; - - spin_lock_irqsave(&priv->lock, flags); - if (iwl_is_rfkill(priv)) { - IWL_DEBUG_DROP("Dropping - RF KILL\n"); - goto drop_unlock; - } - - if (!priv->vif) { - IWL_DEBUG_DROP("Dropping - !priv->vif\n"); - goto drop_unlock; - } - - if ((ctl->tx_rate->hw_value & 0xFF) == IWL_INVALID_RATE) { - IWL_ERROR("ERROR: No TX rate available.\n"); - goto drop_unlock; - } - - unicast = !is_multicast_ether_addr(hdr->addr1); - id = 0; - - fc = le16_to_cpu(hdr->frame_control); - -#ifdef CONFIG_IWLWIFI_DEBUG - if (ieee80211_is_auth(fc)) - IWL_DEBUG_TX("Sending AUTH frame\n"); - else if (ieee80211_is_assoc_request(fc)) - IWL_DEBUG_TX("Sending ASSOC frame\n"); - else if (ieee80211_is_reassoc_request(fc)) - IWL_DEBUG_TX("Sending REASSOC frame\n"); -#endif - - /* drop all data frame if we are not associated */ - if (((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA) && - (!iwl_is_associated(priv) || - ((priv->iw_mode == IEEE80211_IF_TYPE_STA) && !priv->assoc_id) || - !priv->assoc_station_added)) { - IWL_DEBUG_DROP("Dropping - !iwl_is_associated\n"); - goto drop_unlock; - } - - spin_unlock_irqrestore(&priv->lock, flags); - - hdr_len = ieee80211_get_hdrlen(fc); - - /* Find (or create) index into station table for destination station */ - sta_id = iwl4965_get_sta_id(priv, hdr); - if (sta_id == IWL_INVALID_STATION) { - DECLARE_MAC_BUF(mac); - - IWL_DEBUG_DROP("Dropping - INVALID STATION: %s\n", - print_mac(mac, hdr->addr1)); - goto drop; - } - - IWL_DEBUG_RATE("station Id %d\n", sta_id); - - qc = ieee80211_get_qos_ctrl(hdr); - if (qc) { - u8 tid = (u8)(le16_to_cpu(*qc) & 0xf); - seq_number = priv->stations[sta_id].tid[tid].seq_number & - IEEE80211_SCTL_SEQ; - hdr->seq_ctrl = cpu_to_le16(seq_number) | - (hdr->seq_ctrl & - __constant_cpu_to_le16(IEEE80211_SCTL_FRAG)); - seq_number += 0x10; -#ifdef CONFIG_IWL4965_HT - /* aggregation is on for this <sta,tid> */ - if (ctl->flags & IEEE80211_TXCTL_AMPDU) - txq_id = priv->stations[sta_id].tid[tid].agg.txq_id; - priv->stations[sta_id].tid[tid].tfds_in_queue++; -#endif /* CONFIG_IWL4965_HT */ - } - - /* Descriptor for chosen Tx queue */ - txq = &priv->txq[txq_id]; - q = &txq->q; - - spin_lock_irqsave(&priv->lock, flags); - - /* Set up first empty TFD within this queue's circular TFD buffer */ - tfd = &txq->bd[q->write_ptr]; - memset(tfd, 0, sizeof(*tfd)); - control_flags = (u32 *) tfd; - idx = get_cmd_index(q, q->write_ptr, 0); - - /* Set up driver data for this TFD */ - memset(&(txq->txb[q->write_ptr]), 0, sizeof(struct iwl4965_tx_info)); - txq->txb[q->write_ptr].skb[0] = skb; - memcpy(&(txq->txb[q->write_ptr].status.control), - ctl, sizeof(struct ieee80211_tx_control)); - - /* Set up first empty entry in queue's array of Tx/cmd buffers */ - out_cmd = &txq->cmd[idx]; - memset(&out_cmd->hdr, 0, sizeof(out_cmd->hdr)); - memset(&out_cmd->cmd.tx, 0, sizeof(out_cmd->cmd.tx)); - - /* - * Set up the Tx-command (not MAC!) header. - * Store the chosen Tx queue and TFD index within the sequence field; - * after Tx, uCode's Tx response will return this value so driver can - * locate the frame within the tx queue and do post-tx processing. - */ - out_cmd->hdr.cmd = REPLY_TX; - out_cmd->hdr.sequence = cpu_to_le16((u16)(QUEUE_TO_SEQ(txq_id) | - INDEX_TO_SEQ(q->write_ptr))); - - /* Copy MAC header from skb into command buffer */ - memcpy(out_cmd->cmd.tx.hdr, hdr, hdr_len); - - /* - * Use the first empty entry in this queue's command buffer array - * to contain the Tx command and MAC header concatenated together - * (payload data will be in another buffer). - * Size of this varies, due to varying MAC header length. - * If end is not dword aligned, we'll have 2 extra bytes at the end - * of the MAC header (device reads on dword boundaries). - * We'll tell device about this padding later. - */ - len = priv->hw_params.tx_cmd_len + - sizeof(struct iwl_cmd_header) + hdr_len; - - len_org = len; - len = (len + 3) & ~3; - - if (len_org != len) - len_org = 1; - else - len_org = 0; - - /* Physical address of this Tx command's header (not MAC header!), - * within command buffer array. */ - txcmd_phys = txq->dma_addr_cmd + sizeof(struct iwl_cmd) * idx + - offsetof(struct iwl_cmd, hdr); - - /* Add buffer containing Tx command and MAC(!) header to TFD's - * first entry */ - iwl4965_hw_txq_attach_buf_to_tfd(priv, tfd, txcmd_phys, len); - - if (!(ctl->flags & IEEE80211_TXCTL_DO_NOT_ENCRYPT)) - iwl4965_build_tx_cmd_hwcrypto(priv, ctl, out_cmd, skb, sta_id); - - /* Set up TFD's 2nd entry to point directly to remainder of skb, - * if any (802.11 null frames have no payload). */ - len = skb->len - hdr_len; - if (len) { - phys_addr = pci_map_single(priv->pci_dev, skb->data + hdr_len, - len, PCI_DMA_TODEVICE); - iwl4965_hw_txq_attach_buf_to_tfd(priv, tfd, phys_addr, len); - } - - /* Tell 4965 about any 2-byte padding after MAC header */ - if (len_org) - out_cmd->cmd.tx.tx_flags |= TX_CMD_FLG_MH_PAD_MSK; - - /* Total # bytes to be transmitted */ - len = (u16)skb->len; - out_cmd->cmd.tx.len = cpu_to_le16(len); - - /* TODO need this for burst mode later on */ - iwl4965_build_tx_cmd_basic(priv, out_cmd, ctl, hdr, unicast, sta_id); - - /* set is_hcca to 0; it probably will never be implemented */ - iwl4965_hw_build_tx_cmd_rate(priv, out_cmd, ctl, hdr, sta_id, 0); - - iwl_update_tx_stats(priv, fc, len); - - scratch_phys = txcmd_phys + sizeof(struct iwl_cmd_header) + - offsetof(struct iwl4965_tx_cmd, scratch); - out_cmd->cmd.tx.dram_lsb_ptr = cpu_to_le32(scratch_phys); - out_cmd->cmd.tx.dram_msb_ptr = iwl_get_dma_hi_address(scratch_phys); - - if (!ieee80211_get_morefrag(hdr)) { - txq->need_update = 1; - if (qc) { - u8 tid = (u8)(le16_to_cpu(*qc) & 0xf); - priv->stations[sta_id].tid[tid].seq_number = seq_number; - } - } else { - wait_write_ptr = 1; - txq->need_update = 0; - } - - iwl_print_hex_dump(IWL_DL_TX, out_cmd->cmd.payload, - sizeof(out_cmd->cmd.tx)); - - iwl_print_hex_dump(IWL_DL_TX, (u8 *)out_cmd->cmd.tx.hdr, - ieee80211_get_hdrlen(fc)); - - /* Set up entry for this TFD in Tx byte-count array */ - priv->cfg->ops->lib->txq_update_byte_cnt_tbl(priv, txq, len); - - /* Tell device the write index *just past* this latest filled TFD */ - q->write_ptr = iwl_queue_inc_wrap(q->write_ptr, q->n_bd); - rc = iwl4965_tx_queue_update_write_ptr(priv, txq); - spin_unlock_irqrestore(&priv->lock, flags); - - if (rc) - return rc; - - if ((iwl4965_queue_space(q) < q->high_mark) - && priv->mac80211_registered) { - if (wait_write_ptr) { - spin_lock_irqsave(&priv->lock, flags); - txq->need_update = 1; - iwl4965_tx_queue_update_write_ptr(priv, txq); - spin_unlock_irqrestore(&priv->lock, flags); - } - - ieee80211_stop_queue(priv->hw, ctl->queue); - } - - return 0; - -drop_unlock: - spin_unlock_irqrestore(&priv->lock, flags); -drop: - return -1; -} - static void iwl4965_set_rate(struct iwl_priv *priv) { const struct ieee80211_supported_band *hw = NULL; struct ieee80211_rate *rate; int i; - hw = iwl4965_get_hw_mode(priv, priv->band); + hw = iwl_get_hw_mode(priv, priv->band); if (!hw) { IWL_ERROR("Failed to set rate: unable to get hw mode\n"); return; @@ -2411,169 +853,6 @@ static void iwl4965_set_rate(struct iwl_priv *priv) (IWL_OFDM_BASIC_RATES_MASK >> IWL_FIRST_OFDM_RATE) & 0xFF; } -void iwl4965_radio_kill_sw(struct iwl_priv *priv, int disable_radio) -{ - unsigned long flags; - - if (!!disable_radio == test_bit(STATUS_RF_KILL_SW, &priv->status)) - return; - - IWL_DEBUG_RF_KILL("Manual SW RF KILL set to: RADIO %s\n", - disable_radio ? "OFF" : "ON"); - - if (disable_radio) { - iwl4965_scan_cancel(priv); - /* FIXME: This is a workaround for AP */ - if (priv->iw_mode != IEEE80211_IF_TYPE_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)) - iwl4965_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); - } - return; - } - - spin_lock_irqsave(&priv->lock, flags); - iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL); - - clear_bit(STATUS_RF_KILL_SW, &priv->status); - spin_unlock_irqrestore(&priv->lock, flags); - - /* wake up ucode */ - msleep(10); - - spin_lock_irqsave(&priv->lock, flags); - iwl_read32(priv, CSR_UCODE_DRV_GP1); - if (!iwl_grab_nic_access(priv)) - iwl_release_nic_access(priv); - spin_unlock_irqrestore(&priv->lock, flags); - - if (test_bit(STATUS_RF_KILL_HW, &priv->status)) { - IWL_DEBUG_RF_KILL("Can not turn radio back on - " - "disabled by HW switch\n"); - return; - } - - queue_work(priv->workqueue, &priv->restart); - return; -} - -void iwl4965_set_decrypted_flag(struct iwl_priv *priv, struct sk_buff *skb, - u32 decrypt_res, struct ieee80211_rx_status *stats) -{ - u16 fc = - le16_to_cpu(((struct ieee80211_hdr *)skb->data)->frame_control); - - if (priv->active_rxon.filter_flags & RXON_FILTER_DIS_DECRYPT_MSK) - return; - - if (!(fc & IEEE80211_FCTL_PROTECTED)) - return; - - IWL_DEBUG_RX("decrypt_res:0x%x\n", decrypt_res); - switch (decrypt_res & RX_RES_STATUS_SEC_TYPE_MSK) { - case RX_RES_STATUS_SEC_TYPE_TKIP: - /* The uCode has got a bad phase 1 Key, pushes the packet. - * Decryption will be done in SW. */ - if ((decrypt_res & RX_RES_STATUS_DECRYPT_TYPE_MSK) == - RX_RES_STATUS_BAD_KEY_TTAK) - break; - - if ((decrypt_res & RX_RES_STATUS_DECRYPT_TYPE_MSK) == - RX_RES_STATUS_BAD_ICV_MIC) - stats->flag |= RX_FLAG_MMIC_ERROR; - case RX_RES_STATUS_SEC_TYPE_WEP: - case RX_RES_STATUS_SEC_TYPE_CCMP: - if ((decrypt_res & RX_RES_STATUS_DECRYPT_TYPE_MSK) == - RX_RES_STATUS_DECRYPT_OK) { - IWL_DEBUG_RX("hw decrypt successfully!!!\n"); - stats->flag |= RX_FLAG_DECRYPTED; - } - break; - - default: - break; - } -} - - -#define IWL_PACKET_RETRY_TIME HZ - -int iwl4965_is_duplicate_packet(struct iwl_priv *priv, struct ieee80211_hdr *header) -{ - u16 sc = le16_to_cpu(header->seq_ctrl); - u16 seq = (sc & IEEE80211_SCTL_SEQ) >> 4; - u16 frag = sc & IEEE80211_SCTL_FRAG; - u16 *last_seq, *last_frag; - unsigned long *last_time; - - switch (priv->iw_mode) { - case IEEE80211_IF_TYPE_IBSS:{ - struct list_head *p; - struct iwl4965_ibss_seq *entry = NULL; - u8 *mac = header->addr2; - int index = mac[5] & (IWL_IBSS_MAC_HASH_SIZE - 1); - - __list_for_each(p, &priv->ibss_mac_hash[index]) { - entry = list_entry(p, struct iwl4965_ibss_seq, list); - if (!compare_ether_addr(entry->mac, mac)) - break; - } - if (p == &priv->ibss_mac_hash[index]) { - entry = kzalloc(sizeof(*entry), GFP_ATOMIC); - if (!entry) { - IWL_ERROR("Cannot malloc new mac entry\n"); - return 0; - } - memcpy(entry->mac, mac, ETH_ALEN); - entry->seq_num = seq; - entry->frag_num = frag; - entry->packet_time = jiffies; - list_add(&entry->list, &priv->ibss_mac_hash[index]); - return 0; - } - last_seq = &entry->seq_num; - last_frag = &entry->frag_num; - last_time = &entry->packet_time; - break; - } - case IEEE80211_IF_TYPE_STA: - last_seq = &priv->last_seq_num; - last_frag = &priv->last_frag_num; - last_time = &priv->last_packet_time; - break; - default: - return 0; - } - if ((*last_seq == seq) && - time_after(*last_time + IWL_PACKET_RETRY_TIME, jiffies)) { - if (*last_frag == frag) - goto drop; - if (*last_frag + 1 != frag) - /* out-of-order fragment */ - goto drop; - } else - *last_seq = seq; - - *last_frag = frag; - *last_time = jiffies; - return 0; - - drop: - return 1; -} - #ifdef CONFIG_IWL4965_SPECTRUM_MEASUREMENT #include "iwl-spectrum.h" @@ -2632,7 +911,7 @@ static int iwl4965_get_measurement(struct iwl_priv *priv, u8 type) { struct iwl4965_spectrum_cmd spectrum; - struct iwl4965_rx_packet *res; + struct iwl_rx_packet *res; struct iwl_host_cmd cmd = { .id = REPLY_SPECTRUM_MEASUREMENT_CMD, .data = (void *)&spectrum, @@ -2677,7 +956,7 @@ static int iwl4965_get_measurement(struct iwl_priv *priv, if (rc) return rc; - res = (struct iwl4965_rx_packet *)cmd.meta.u.skb->data; + res = (struct iwl_rx_packet *)cmd.meta.u.skb->data; if (res->hdr.flags & IWL_CMD_FAILED_MSK) { IWL_ERROR("Bad return from REPLY_RX_ON_ASSOC command\n"); rc = -EIO; @@ -2707,352 +986,16 @@ static int iwl4965_get_measurement(struct iwl_priv *priv, } #endif -static void iwl4965_txstatus_to_ieee(struct iwl_priv *priv, - struct iwl4965_tx_info *tx_sta) -{ - - tx_sta->status.ack_signal = 0; - tx_sta->status.excessive_retries = 0; - tx_sta->status.queue_length = 0; - tx_sta->status.queue_number = 0; - - if (in_interrupt()) - ieee80211_tx_status_irqsafe(priv->hw, - tx_sta->skb[0], &(tx_sta->status)); - else - ieee80211_tx_status(priv->hw, - tx_sta->skb[0], &(tx_sta->status)); - - tx_sta->skb[0] = NULL; -} - -/** - * iwl4965_tx_queue_reclaim - Reclaim Tx queue entries already Tx'd - * - * When FW advances 'R' index, all entries between old and new 'R' index - * need to be reclaimed. As result, some free space forms. If there is - * enough free space (> low mark), wake the stack that feeds us. - */ -int iwl4965_tx_queue_reclaim(struct iwl_priv *priv, int txq_id, int index) -{ - struct iwl4965_tx_queue *txq = &priv->txq[txq_id]; - struct iwl4965_queue *q = &txq->q; - int nfreed = 0; - - if ((index >= q->n_bd) || (x2_queue_used(q, index) == 0)) { - IWL_ERROR("Read index for DMA queue txq id (%d), index %d, " - "is out of range [0-%d] %d %d.\n", txq_id, - index, q->n_bd, q->write_ptr, q->read_ptr); - return 0; - } - - for (index = iwl_queue_inc_wrap(index, q->n_bd); - q->read_ptr != index; - q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd)) { - if (txq_id != IWL_CMD_QUEUE_NUM) { - iwl4965_txstatus_to_ieee(priv, - &(txq->txb[txq->q.read_ptr])); - iwl4965_hw_txq_free_tfd(priv, txq); - } else if (nfreed > 1) { - IWL_ERROR("HCMD skipped: index (%d) %d %d\n", index, - q->write_ptr, q->read_ptr); - queue_work(priv->workqueue, &priv->restart); - } - nfreed++; - } - -/* if (iwl4965_queue_space(q) > q->low_mark && (txq_id >= 0) && - (txq_id != IWL_CMD_QUEUE_NUM) && - priv->mac80211_registered) - ieee80211_wake_queue(priv->hw, txq_id); */ - - - return nfreed; -} - -static int iwl4965_is_tx_success(u32 status) -{ - status &= TX_STATUS_MSK; - return (status == TX_STATUS_SUCCESS) - || (status == TX_STATUS_DIRECT_DONE); -} - /****************************************************************************** * * Generic RX handler implementations * ******************************************************************************/ -#ifdef CONFIG_IWL4965_HT - -static inline int iwl4965_get_ra_sta_id(struct iwl_priv *priv, - struct ieee80211_hdr *hdr) +static void iwl_rx_reply_alive(struct iwl_priv *priv, + struct iwl_rx_mem_buffer *rxb) { - if (priv->iw_mode == IEEE80211_IF_TYPE_STA) - return IWL_AP_ID; - else { - u8 *da = ieee80211_get_DA(hdr); - return iwl4965_hw_find_station(priv, da); - } -} - -static struct ieee80211_hdr *iwl4965_tx_queue_get_hdr( - struct iwl_priv *priv, int txq_id, int idx) -{ - if (priv->txq[txq_id].txb[idx].skb[0]) - return (struct ieee80211_hdr *)priv->txq[txq_id]. - txb[idx].skb[0]->data; - return NULL; -} - -static inline u32 iwl4965_get_scd_ssn(struct iwl4965_tx_resp *tx_resp) -{ - __le32 *scd_ssn = (__le32 *)((u32 *)&tx_resp->status + - tx_resp->frame_count); - return le32_to_cpu(*scd_ssn) & MAX_SN; - -} - -/** - * iwl4965_tx_status_reply_tx - Handle Tx rspnse for frames in aggregation queue - */ -static int iwl4965_tx_status_reply_tx(struct iwl_priv *priv, - struct iwl4965_ht_agg *agg, - struct iwl4965_tx_resp_agg *tx_resp, - u16 start_idx) -{ - u16 status; - struct agg_tx_status *frame_status = &tx_resp->status; - struct ieee80211_tx_status *tx_status = NULL; - struct ieee80211_hdr *hdr = NULL; - int i, sh; - int txq_id, idx; - u16 seq; - - if (agg->wait_for_ba) - IWL_DEBUG_TX_REPLY("got tx response w/o block-ack\n"); - - agg->frame_count = tx_resp->frame_count; - agg->start_idx = start_idx; - agg->rate_n_flags = le32_to_cpu(tx_resp->rate_n_flags); - agg->bitmap = 0; - - /* # frames attempted by Tx command */ - if (agg->frame_count == 1) { - /* Only one frame was attempted; no block-ack will arrive */ - status = le16_to_cpu(frame_status[0].status); - seq = le16_to_cpu(frame_status[0].sequence); - idx = SEQ_TO_INDEX(seq); - txq_id = SEQ_TO_QUEUE(seq); - - /* FIXME: code repetition */ - IWL_DEBUG_TX_REPLY("FrameCnt = %d, StartIdx=%d idx=%d\n", - agg->frame_count, agg->start_idx, idx); - - tx_status = &(priv->txq[txq_id].txb[idx].status); - tx_status->retry_count = tx_resp->failure_frame; - tx_status->queue_number = status & 0xff; - tx_status->queue_length = tx_resp->failure_rts; - tx_status->control.flags &= ~IEEE80211_TXCTL_AMPDU; - tx_status->flags = iwl4965_is_tx_success(status)? - IEEE80211_TX_STATUS_ACK : 0; - iwl4965_hwrate_to_tx_control(priv, - le32_to_cpu(tx_resp->rate_n_flags), - &tx_status->control); - /* FIXME: code repetition end */ - - IWL_DEBUG_TX_REPLY("1 Frame 0x%x failure :%d\n", - status & 0xff, tx_resp->failure_frame); - IWL_DEBUG_TX_REPLY("Rate Info rate_n_flags=%x\n", - iwl4965_hw_get_rate_n_flags(tx_resp->rate_n_flags)); - - agg->wait_for_ba = 0; - } else { - /* Two or more frames were attempted; expect block-ack */ - u64 bitmap = 0; - int start = agg->start_idx; - - /* Construct bit-map of pending frames within Tx window */ - for (i = 0; i < agg->frame_count; i++) { - u16 sc; - status = le16_to_cpu(frame_status[i].status); - seq = le16_to_cpu(frame_status[i].sequence); - idx = SEQ_TO_INDEX(seq); - txq_id = SEQ_TO_QUEUE(seq); - - if (status & (AGG_TX_STATE_FEW_BYTES_MSK | - AGG_TX_STATE_ABORT_MSK)) - continue; - - IWL_DEBUG_TX_REPLY("FrameCnt = %d, txq_id=%d idx=%d\n", - agg->frame_count, txq_id, idx); - - hdr = iwl4965_tx_queue_get_hdr(priv, txq_id, idx); - - sc = le16_to_cpu(hdr->seq_ctrl); - if (idx != (SEQ_TO_SN(sc) & 0xff)) { - IWL_ERROR("BUG_ON idx doesn't match seq control" - " idx=%d, seq_idx=%d, seq=%d\n", - idx, SEQ_TO_SN(sc), - hdr->seq_ctrl); - return -1; - } - - IWL_DEBUG_TX_REPLY("AGG Frame i=%d idx %d seq=%d\n", - i, idx, SEQ_TO_SN(sc)); - - sh = idx - start; - if (sh > 64) { - sh = (start - idx) + 0xff; - bitmap = bitmap << sh; - sh = 0; - start = idx; - } else if (sh < -64) - sh = 0xff - (start - idx); - else if (sh < 0) { - sh = start - idx; - start = idx; - bitmap = bitmap << sh; - sh = 0; - } - bitmap |= (1 << sh); - IWL_DEBUG_TX_REPLY("start=%d bitmap=0x%x\n", - start, (u32)(bitmap & 0xFFFFFFFF)); - } - - agg->bitmap = bitmap; - agg->start_idx = start; - agg->rate_n_flags = le32_to_cpu(tx_resp->rate_n_flags); - IWL_DEBUG_TX_REPLY("Frames %d start_idx=%d bitmap=0x%llx\n", - agg->frame_count, agg->start_idx, - (unsigned long long)agg->bitmap); - - if (bitmap) - agg->wait_for_ba = 1; - } - return 0; -} -#endif - -/** - * iwl4965_rx_reply_tx - Handle standard (non-aggregation) Tx response - */ -static void iwl4965_rx_reply_tx(struct iwl_priv *priv, - struct iwl4965_rx_mem_buffer *rxb) -{ - struct iwl4965_rx_packet *pkt = (void *)rxb->skb->data; - u16 sequence = le16_to_cpu(pkt->hdr.sequence); - int txq_id = SEQ_TO_QUEUE(sequence); - int index = SEQ_TO_INDEX(sequence); - struct iwl4965_tx_queue *txq = &priv->txq[txq_id]; - struct ieee80211_tx_status *tx_status; - struct iwl4965_tx_resp *tx_resp = (void *)&pkt->u.raw[0]; - u32 status = le32_to_cpu(tx_resp->status); -#ifdef CONFIG_IWL4965_HT - int tid = MAX_TID_COUNT, sta_id = IWL_INVALID_STATION; - struct ieee80211_hdr *hdr; - __le16 *qc; -#endif - - if ((index >= txq->q.n_bd) || (x2_queue_used(&txq->q, index) == 0)) { - IWL_ERROR("Read index for DMA queue txq_id (%d) index %d " - "is out of range [0-%d] %d %d\n", txq_id, - index, txq->q.n_bd, txq->q.write_ptr, - txq->q.read_ptr); - return; - } - -#ifdef CONFIG_IWL4965_HT - hdr = iwl4965_tx_queue_get_hdr(priv, txq_id, index); - qc = ieee80211_get_qos_ctrl(hdr); - - if (qc) - tid = le16_to_cpu(*qc) & 0xf; - - sta_id = iwl4965_get_ra_sta_id(priv, hdr); - if (txq->sched_retry && unlikely(sta_id == IWL_INVALID_STATION)) { - IWL_ERROR("Station not known\n"); - return; - } - - if (txq->sched_retry) { - const u32 scd_ssn = iwl4965_get_scd_ssn(tx_resp); - struct iwl4965_ht_agg *agg = NULL; - - if (!qc) - return; - - agg = &priv->stations[sta_id].tid[tid].agg; - - iwl4965_tx_status_reply_tx(priv, agg, - (struct iwl4965_tx_resp_agg *)tx_resp, index); - - if ((tx_resp->frame_count == 1) && - !iwl4965_is_tx_success(status)) { - /* TODO: send BAR */ - } - - if (txq->q.read_ptr != (scd_ssn & 0xff)) { - int freed; - index = iwl_queue_dec_wrap(scd_ssn & 0xff, txq->q.n_bd); - IWL_DEBUG_TX_REPLY("Retry scheduler reclaim scd_ssn " - "%d index %d\n", scd_ssn , index); - freed = iwl4965_tx_queue_reclaim(priv, txq_id, index); - priv->stations[sta_id].tid[tid].tfds_in_queue -= freed; - - if (iwl4965_queue_space(&txq->q) > txq->q.low_mark && - txq_id >= 0 && priv->mac80211_registered && - agg->state != IWL_EMPTYING_HW_QUEUE_DELBA) - ieee80211_wake_queue(priv->hw, txq_id); - - iwl4965_check_empty_hw_queue(priv, sta_id, tid, txq_id); - } - } else { -#endif /* CONFIG_IWL4965_HT */ - tx_status = &(txq->txb[txq->q.read_ptr].status); - - tx_status->retry_count = tx_resp->failure_frame; - tx_status->queue_number = status; - tx_status->queue_length = tx_resp->bt_kill_count; - tx_status->queue_length |= tx_resp->failure_rts; - tx_status->flags = - iwl4965_is_tx_success(status) ? IEEE80211_TX_STATUS_ACK : 0; - iwl4965_hwrate_to_tx_control(priv, le32_to_cpu(tx_resp->rate_n_flags), - &tx_status->control); - - IWL_DEBUG_TX("Tx queue %d Status %s (0x%08x) rate_n_flags 0x%x " - "retries %d\n", txq_id, iwl4965_get_tx_fail_reason(status), - status, le32_to_cpu(tx_resp->rate_n_flags), - tx_resp->failure_frame); - - IWL_DEBUG_TX_REPLY("Tx queue reclaim %d\n", index); - if (index != -1) { -#ifdef CONFIG_IWL4965_HT - int freed = iwl4965_tx_queue_reclaim(priv, txq_id, index); - - if (tid != MAX_TID_COUNT) - priv->stations[sta_id].tid[tid].tfds_in_queue -= freed; - if (iwl4965_queue_space(&txq->q) > txq->q.low_mark && - (txq_id >= 0) && - priv->mac80211_registered) - ieee80211_wake_queue(priv->hw, txq_id); - if (tid != MAX_TID_COUNT) - iwl4965_check_empty_hw_queue(priv, sta_id, tid, txq_id); -#endif - } -#ifdef CONFIG_IWL4965_HT - } -#endif /* CONFIG_IWL4965_HT */ - - if (iwl_check_bits(status, TX_ABORT_REQUIRED_MSK)) - IWL_ERROR("TODO: Implement Tx ABORT REQUIRED!!!\n"); -} - - -static void iwl4965_rx_reply_alive(struct iwl_priv *priv, - struct iwl4965_rx_mem_buffer *rxb) -{ - struct iwl4965_rx_packet *pkt = (void *)rxb->skb->data; - struct iwl4965_alive_resp *palive; + struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; + struct iwl_alive_resp *palive; struct delayed_work *pwork; palive = &pkt->u.alive_frame; @@ -3066,12 +1009,12 @@ static void iwl4965_rx_reply_alive(struct iwl_priv *priv, IWL_DEBUG_INFO("Initialization Alive received.\n"); memcpy(&priv->card_alive_init, &pkt->u.alive_frame, - sizeof(struct iwl4965_init_alive_resp)); + sizeof(struct iwl_init_alive_resp)); pwork = &priv->init_alive_start; } else { IWL_DEBUG_INFO("Runtime Alive received.\n"); memcpy(&priv->card_alive, &pkt->u.alive_frame, - sizeof(struct iwl4965_alive_resp)); + sizeof(struct iwl_alive_resp)); pwork = &priv->alive_start; } @@ -3084,19 +1027,10 @@ static void iwl4965_rx_reply_alive(struct iwl_priv *priv, IWL_WARNING("uCode did not respond OK.\n"); } -static void iwl4965_rx_reply_add_sta(struct iwl_priv *priv, - struct iwl4965_rx_mem_buffer *rxb) -{ - struct iwl4965_rx_packet *pkt = (void *)rxb->skb->data; - - IWL_DEBUG_RX("Received REPLY_ADD_STA: 0x%02X\n", pkt->u.status); - return; -} - static void iwl4965_rx_reply_error(struct iwl_priv *priv, - struct iwl4965_rx_mem_buffer *rxb) + struct iwl_rx_mem_buffer *rxb) { - struct iwl4965_rx_packet *pkt = (void *)rxb->skb->data; + struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; IWL_ERROR("Error Reply type 0x%08X cmd %s (0x%02X) " "seq 0x%04X ser 0x%08X\n", @@ -3109,10 +1043,10 @@ static void iwl4965_rx_reply_error(struct iwl_priv *priv, #define TX_STATUS_ENTRY(x) case TX_STATUS_FAIL_ ## x: return #x -static void iwl4965_rx_csa(struct iwl_priv *priv, struct iwl4965_rx_mem_buffer *rxb) +static void iwl4965_rx_csa(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) { - struct iwl4965_rx_packet *pkt = (void *)rxb->skb->data; - struct iwl4965_rxon_cmd *rxon = (void *)&priv->active_rxon; + struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; + struct iwl_rxon_cmd *rxon = (void *)&priv->active_rxon; struct iwl4965_csa_notification *csa = &(pkt->u.csa_notif); IWL_DEBUG_11H("CSA notif: channel %d, status %d\n", le16_to_cpu(csa->channel), le32_to_cpu(csa->status)); @@ -3121,15 +1055,15 @@ static void iwl4965_rx_csa(struct iwl_priv *priv, struct iwl4965_rx_mem_buffer * } static void iwl4965_rx_spectrum_measure_notif(struct iwl_priv *priv, - struct iwl4965_rx_mem_buffer *rxb) + struct iwl_rx_mem_buffer *rxb) { #ifdef CONFIG_IWL4965_SPECTRUM_MEASUREMENT - struct iwl4965_rx_packet *pkt = (void *)rxb->skb->data; + struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; struct iwl4965_spectrum_notification *report = &(pkt->u.spectrum_notif); if (!report->state) { - IWL_DEBUG(IWL_DL_11H | IWL_DL_INFO, - "Spectrum Measure Notification: Start\n"); + IWL_DEBUG(IWL_DL_11H, + "Spectrum Measure Notification: Start\n"); return; } @@ -3139,10 +1073,10 @@ static void iwl4965_rx_spectrum_measure_notif(struct iwl_priv *priv, } static void iwl4965_rx_pm_sleep_notif(struct iwl_priv *priv, - struct iwl4965_rx_mem_buffer *rxb) + struct iwl_rx_mem_buffer *rxb) { #ifdef CONFIG_IWLWIFI_DEBUG - struct iwl4965_rx_packet *pkt = (void *)rxb->skb->data; + struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; struct iwl4965_sleep_notification *sleep = &(pkt->u.sleep_notif); IWL_DEBUG_RX("sleep mode: %d, src: %d\n", sleep->pm_sleep_mode, sleep->pm_wakeup_src); @@ -3150,13 +1084,13 @@ static void iwl4965_rx_pm_sleep_notif(struct iwl_priv *priv, } static void iwl4965_rx_pm_debug_statistics_notif(struct iwl_priv *priv, - struct iwl4965_rx_mem_buffer *rxb) + struct iwl_rx_mem_buffer *rxb) { - struct iwl4965_rx_packet *pkt = (void *)rxb->skb->data; + struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; IWL_DEBUG_RADIO("Dumping %d bytes of unhandled " "notification for %s:\n", le32_to_cpu(pkt->len), get_cmd_string(pkt->hdr.cmd)); - iwl_print_hex_dump(IWL_DL_RADIO, pkt->u.raw, le32_to_cpu(pkt->len)); + iwl_print_hex_dump(priv, IWL_DL_RADIO, pkt->u.raw, le32_to_cpu(pkt->len)); } static void iwl4965_bg_beacon_update(struct work_struct *work) @@ -3166,7 +1100,7 @@ static void iwl4965_bg_beacon_update(struct work_struct *work) struct sk_buff *beacon; /* Pull updated AP beacon from mac80211. will fail if not in AP mode */ - beacon = ieee80211_beacon_get(priv->hw, priv->vif, NULL); + beacon = ieee80211_beacon_get(priv->hw, priv->vif); if (!beacon) { IWL_ERROR("update beacon failed\n"); @@ -3184,17 +1118,37 @@ static void iwl4965_bg_beacon_update(struct work_struct *work) iwl4965_send_beacon_cmd(priv); } +/** + * iwl4965_bg_statistics_periodic - Timer callback to queue statistics + * + * This callback is provided in order to send a statistics request. + * + * This timer function is continually reset to execute within + * REG_RECALIB_PERIOD seconds since the last STATISTICS_NOTIFICATION + * was received. We need to ensure we receive the statistics in order + * to update the temperature used for calibrating the TXPOWER. + */ +static void iwl4965_bg_statistics_periodic(unsigned long data) +{ + struct iwl_priv *priv = (struct iwl_priv *)data; + + if (test_bit(STATUS_EXIT_PENDING, &priv->status)) + return; + + iwl_send_statistics_request(priv, CMD_ASYNC); +} + static void iwl4965_rx_beacon_notif(struct iwl_priv *priv, - struct iwl4965_rx_mem_buffer *rxb) + struct iwl_rx_mem_buffer *rxb) { #ifdef CONFIG_IWLWIFI_DEBUG - struct iwl4965_rx_packet *pkt = (void *)rxb->skb->data; + struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; struct iwl4965_beacon_notif *beacon = &(pkt->u.beacon_status); - u8 rate = iwl4965_hw_get_rate(beacon->beacon_notify_hdr.rate_n_flags); + u8 rate = iwl_hw_get_rate(beacon->beacon_notify_hdr.rate_n_flags); IWL_DEBUG_RX("beacon status %x retries %d iss %d " "tsf %d %d rate %d\n", - le32_to_cpu(beacon->beacon_notify_hdr.status) & TX_STATUS_MSK, + le32_to_cpu(beacon->beacon_notify_hdr.u.status) & TX_STATUS_MSK, beacon->beacon_notify_hdr.failure_frame, le32_to_cpu(beacon->ibss_mgr_status), le32_to_cpu(beacon->high_tsf), @@ -3206,129 +1160,12 @@ static void iwl4965_rx_beacon_notif(struct iwl_priv *priv, queue_work(priv->workqueue, &priv->beacon_update); } -/* Service response to REPLY_SCAN_CMD (0x80) */ -static void iwl4965_rx_reply_scan(struct iwl_priv *priv, - struct iwl4965_rx_mem_buffer *rxb) -{ -#ifdef CONFIG_IWLWIFI_DEBUG - struct iwl4965_rx_packet *pkt = (void *)rxb->skb->data; - struct iwl4965_scanreq_notification *notif = - (struct iwl4965_scanreq_notification *)pkt->u.raw; - - IWL_DEBUG_RX("Scan request status = 0x%x\n", notif->status); -#endif -} - -/* Service SCAN_START_NOTIFICATION (0x82) */ -static void iwl4965_rx_scan_start_notif(struct iwl_priv *priv, - struct iwl4965_rx_mem_buffer *rxb) -{ - struct iwl4965_rx_packet *pkt = (void *)rxb->skb->data; - struct iwl4965_scanstart_notification *notif = - (struct iwl4965_scanstart_notification *)pkt->u.raw; - priv->scan_start_tsf = le32_to_cpu(notif->tsf_low); - IWL_DEBUG_SCAN("Scan start: " - "%d [802.11%s] " - "(TSF: 0x%08X:%08X) - %d (beacon timer %u)\n", - notif->channel, - notif->band ? "bg" : "a", - notif->tsf_high, - notif->tsf_low, notif->status, notif->beacon_timer); -} - -/* Service SCAN_RESULTS_NOTIFICATION (0x83) */ -static void iwl4965_rx_scan_results_notif(struct iwl_priv *priv, - struct iwl4965_rx_mem_buffer *rxb) -{ - struct iwl4965_rx_packet *pkt = (void *)rxb->skb->data; - struct iwl4965_scanresults_notification *notif = - (struct iwl4965_scanresults_notification *)pkt->u.raw; - - IWL_DEBUG_SCAN("Scan ch.res: " - "%d [802.11%s] " - "(TSF: 0x%08X:%08X) - %d " - "elapsed=%lu usec (%dms since last)\n", - notif->channel, - notif->band ? "bg" : "a", - le32_to_cpu(notif->tsf_high), - le32_to_cpu(notif->tsf_low), - le32_to_cpu(notif->statistics[0]), - le32_to_cpu(notif->tsf_low) - priv->scan_start_tsf, - jiffies_to_msecs(elapsed_jiffies - (priv->last_scan_jiffies, jiffies))); - - priv->last_scan_jiffies = jiffies; - priv->next_scan_jiffies = 0; -} - -/* Service SCAN_COMPLETE_NOTIFICATION (0x84) */ -static void iwl4965_rx_scan_complete_notif(struct iwl_priv *priv, - struct iwl4965_rx_mem_buffer *rxb) -{ - struct iwl4965_rx_packet *pkt = (void *)rxb->skb->data; - struct iwl4965_scancomplete_notification *scan_notif = (void *)pkt->u.raw; - - IWL_DEBUG_SCAN("Scan complete: %d channels (TSF 0x%08X:%08X) - %d\n", - scan_notif->scanned_channels, - scan_notif->tsf_low, - scan_notif->tsf_high, scan_notif->status); - - /* The HW is no longer scanning */ - clear_bit(STATUS_SCAN_HW, &priv->status); - - /* The scan completion notification came in, so kill that timer... */ - cancel_delayed_work(&priv->scan_check); - - IWL_DEBUG_INFO("Scan pass on %sGHz took %dms\n", - (priv->scan_bands & BIT(IEEE80211_BAND_2GHZ)) ? - "2.4" : "5.2", - jiffies_to_msecs(elapsed_jiffies - (priv->scan_pass_start, jiffies))); - - /* Remove this scanned band from the list of pending - * bands to scan, band G precedes A in order of scanning - * as seen in iwl_bg_request_scan */ - if (priv->scan_bands & BIT(IEEE80211_BAND_2GHZ)) - priv->scan_bands &= ~BIT(IEEE80211_BAND_2GHZ); - else if (priv->scan_bands & BIT(IEEE80211_BAND_5GHZ)) - priv->scan_bands &= ~BIT(IEEE80211_BAND_5GHZ); - - /* If a request to abort was given, or the scan did not succeed - * then we reset the scan state machine and terminate, - * re-queuing another scan if one has been requested */ - if (test_bit(STATUS_SCAN_ABORTING, &priv->status)) { - IWL_DEBUG_INFO("Aborted scan completed.\n"); - clear_bit(STATUS_SCAN_ABORTING, &priv->status); - } else { - /* If there are more bands on this scan pass reschedule */ - if (priv->scan_bands) - goto reschedule; - } - - priv->last_scan_jiffies = jiffies; - priv->next_scan_jiffies = 0; - IWL_DEBUG_INFO("Setting scan to off\n"); - - clear_bit(STATUS_SCANNING, &priv->status); - - IWL_DEBUG_INFO("Scan took %dms\n", - jiffies_to_msecs(elapsed_jiffies(priv->scan_start, jiffies))); - - queue_work(priv->workqueue, &priv->scan_completed); - - return; - -reschedule: - priv->scan_pass_start = jiffies; - queue_work(priv->workqueue, &priv->request_scan); -} - /* Handle notification from uCode that card's power state is changing * due to software, hardware, or critical temperature RFKILL */ static void iwl4965_rx_card_state_notif(struct iwl_priv *priv, - struct iwl4965_rx_mem_buffer *rxb) + struct iwl_rx_mem_buffer *rxb) { - struct iwl4965_rx_packet *pkt = (void *)rxb->skb->data; + 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; @@ -3383,7 +1220,7 @@ static void iwl4965_rx_card_state_notif(struct iwl_priv *priv, clear_bit(STATUS_RF_KILL_SW, &priv->status); if (!(flags & RXON_CARD_DISABLED)) - iwl4965_scan_cancel(priv); + iwl_scan_cancel(priv); if ((test_bit(STATUS_RF_KILL_HW, &status) != test_bit(STATUS_RF_KILL_HW, &priv->status)) || @@ -3403,10 +1240,9 @@ static void iwl4965_rx_card_state_notif(struct iwl_priv *priv, * This function chains into the hardware specific files for them to setup * any hardware specific handlers as well. */ -static void iwl4965_setup_rx_handlers(struct iwl_priv *priv) +static void iwl_setup_rx_handlers(struct iwl_priv *priv) { - priv->rx_handlers[REPLY_ALIVE] = iwl4965_rx_reply_alive; - priv->rx_handlers[REPLY_ADD_STA] = iwl4965_rx_reply_add_sta; + priv->rx_handlers[REPLY_ALIVE] = iwl_rx_reply_alive; priv->rx_handlers[REPLY_ERROR] = iwl4965_rx_reply_error; priv->rx_handlers[CHANNEL_SWITCH_NOTIFICATION] = iwl4965_rx_csa; priv->rx_handlers[SPECTRUM_MEASURE_NOTIFICATION] = @@ -3421,500 +1257,47 @@ static void iwl4965_setup_rx_handlers(struct iwl_priv *priv) * statistics request from the host as well as for the periodic * statistics notifications (after received beacons) from the uCode. */ - priv->rx_handlers[REPLY_STATISTICS_CMD] = iwl4965_hw_rx_statistics; - priv->rx_handlers[STATISTICS_NOTIFICATION] = iwl4965_hw_rx_statistics; - - priv->rx_handlers[REPLY_SCAN_CMD] = iwl4965_rx_reply_scan; - priv->rx_handlers[SCAN_START_NOTIFICATION] = iwl4965_rx_scan_start_notif; - priv->rx_handlers[SCAN_RESULTS_NOTIFICATION] = - iwl4965_rx_scan_results_notif; - priv->rx_handlers[SCAN_COMPLETE_NOTIFICATION] = - iwl4965_rx_scan_complete_notif; - priv->rx_handlers[CARD_STATE_NOTIFICATION] = iwl4965_rx_card_state_notif; - priv->rx_handlers[REPLY_TX] = iwl4965_rx_reply_tx; - - /* Set up hardware specific Rx handlers */ - iwl4965_hw_rx_handler_setup(priv); -} - -/** - * iwl4965_tx_cmd_complete - Pull unused buffers off the queue and reclaim them - * @rxb: Rx buffer to reclaim - * - * If an Rx buffer has an async callback associated with it the callback - * will be executed. The attached skb (if present) will only be freed - * if the callback returns 1 - */ -static void iwl4965_tx_cmd_complete(struct iwl_priv *priv, - struct iwl4965_rx_mem_buffer *rxb) -{ - struct iwl4965_rx_packet *pkt = (struct iwl4965_rx_packet *)rxb->skb->data; - u16 sequence = le16_to_cpu(pkt->hdr.sequence); - int txq_id = SEQ_TO_QUEUE(sequence); - int index = SEQ_TO_INDEX(sequence); - int huge = sequence & SEQ_HUGE_FRAME; - int cmd_index; - struct iwl_cmd *cmd; - - /* If a Tx command is being handled and it isn't in the actual - * command queue then there a command routing bug has been introduced - * in the queue management code. */ - if (txq_id != IWL_CMD_QUEUE_NUM) - IWL_ERROR("Error wrong command queue %d command id 0x%X\n", - txq_id, pkt->hdr.cmd); - BUG_ON(txq_id != IWL_CMD_QUEUE_NUM); - - cmd_index = get_cmd_index(&priv->txq[IWL_CMD_QUEUE_NUM].q, index, huge); - cmd = &priv->txq[IWL_CMD_QUEUE_NUM].cmd[cmd_index]; - - /* Input error checking is done when commands are added to queue. */ - if (cmd->meta.flags & CMD_WANT_SKB) { - cmd->meta.source->u.skb = rxb->skb; - rxb->skb = NULL; - } else if (cmd->meta.u.callback && - !cmd->meta.u.callback(priv, cmd, rxb->skb)) - rxb->skb = NULL; - - iwl4965_tx_queue_reclaim(priv, txq_id, index); - - if (!(cmd->meta.flags & CMD_ASYNC)) { - clear_bit(STATUS_HCMD_ACTIVE, &priv->status); - wake_up_interruptible(&priv->wait_command_queue); - } -} - -/************************** RX-FUNCTIONS ****************************/ -/* - * Rx theory of operation - * - * Driver allocates a circular buffer of Receive Buffer Descriptors (RBDs), - * each of which point to Receive Buffers to be filled by 4965. These get - * used not only for Rx frames, but for any command response or notification - * from the 4965. The driver and 4965 manage the Rx buffers by means - * of indexes into the circular buffer. - * - * Rx Queue Indexes - * The host/firmware share two index registers for managing the Rx buffers. - * - * The READ index maps to the first position that the firmware may be writing - * to -- the driver can read up to (but not including) this position and get - * good data. - * The READ index is managed by the firmware once the card is enabled. - * - * The WRITE index maps to the last position the driver has read from -- the - * position preceding WRITE is the last slot the firmware can place a packet. - * - * The queue is empty (no good data) if WRITE = READ - 1, and is full if - * WRITE = READ. - * - * During initialization, the host sets up the READ queue position to the first - * INDEX position, and WRITE to the last (READ - 1 wrapped) - * - * When the firmware places a packet in a buffer, it will advance the READ index - * and fire the RX interrupt. The driver can then query the READ index and - * process as many packets as possible, moving the WRITE index forward as it - * resets the Rx queue buffers with new memory. - * - * The management in the driver is as follows: - * + A list of pre-allocated SKBs is stored in iwl->rxq->rx_free. When - * iwl->rxq->free_count drops to or below RX_LOW_WATERMARK, work is scheduled - * to replenish the iwl->rxq->rx_free. - * + In iwl4965_rx_replenish (scheduled) if 'processed' != 'read' then the - * iwl->rxq is replenished and the READ INDEX is updated (updating the - * 'processed' and 'read' driver indexes as well) - * + A received packet is processed and handed to the kernel network stack, - * detached from the iwl->rxq. The driver 'processed' index is updated. - * + The Host/Firmware iwl->rxq is replenished at tasklet time from the rx_free - * list. If there are no allocated buffers in iwl->rxq->rx_free, the READ - * INDEX is not incremented and iwl->status(RX_STALLED) is set. If there - * were enough free buffers and RX_STALLED is set it is cleared. - * - * - * Driver sequence: - * - * iwl4965_rx_queue_alloc() Allocates rx_free - * iwl4965_rx_replenish() Replenishes rx_free list from rx_used, and calls - * iwl4965_rx_queue_restock - * iwl4965_rx_queue_restock() Moves available buffers from rx_free into Rx - * queue, updates firmware pointers, and updates - * the WRITE index. If insufficient rx_free buffers - * are available, schedules iwl4965_rx_replenish - * - * -- enable interrupts -- - * ISR - iwl4965_rx() Detach iwl4965_rx_mem_buffers from pool up to the - * READ INDEX, detaching the SKB from the pool. - * Moves the packet buffer from queue to rx_used. - * Calls iwl4965_rx_queue_restock to refill any empty - * slots. - * ... - * - */ - -/** - * iwl4965_rx_queue_space - Return number of free slots available in queue. - */ -static int iwl4965_rx_queue_space(const struct iwl4965_rx_queue *q) -{ - int s = q->read - q->write; - if (s <= 0) - s += RX_QUEUE_SIZE; - /* keep some buffer to not confuse full and empty queue */ - s -= 2; - if (s < 0) - s = 0; - return s; -} - -/** - * iwl4965_rx_queue_update_write_ptr - Update the write pointer for the RX queue - */ -int iwl4965_rx_queue_update_write_ptr(struct iwl_priv *priv, struct iwl4965_rx_queue *q) -{ - u32 reg = 0; - int rc = 0; - unsigned long flags; - - spin_lock_irqsave(&q->lock, flags); - - if (q->need_update == 0) - goto exit_unlock; - - /* If power-saving is in use, make sure device is awake */ - if (test_bit(STATUS_POWER_PMI, &priv->status)) { - reg = iwl_read32(priv, CSR_UCODE_DRV_GP1); - - if (reg & CSR_UCODE_DRV_GP1_BIT_MAC_SLEEP) { - iwl_set_bit(priv, CSR_GP_CNTRL, - CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); - goto exit_unlock; - } - - rc = iwl_grab_nic_access(priv); - if (rc) - goto exit_unlock; - - /* Device expects a multiple of 8 */ - iwl_write_direct32(priv, FH_RSCSR_CHNL0_WPTR, - q->write & ~0x7); - iwl_release_nic_access(priv); - - /* Else device is assumed to be awake */ - } else - /* Device expects a multiple of 8 */ - iwl_write32(priv, FH_RSCSR_CHNL0_WPTR, q->write & ~0x7); + priv->rx_handlers[REPLY_STATISTICS_CMD] = iwl_rx_statistics; + priv->rx_handlers[STATISTICS_NOTIFICATION] = iwl_rx_statistics; + iwl_setup_rx_scan_handlers(priv); - q->need_update = 0; - - exit_unlock: - spin_unlock_irqrestore(&q->lock, flags); - return rc; -} - -/** - * iwl4965_dma_addr2rbd_ptr - convert a DMA address to a uCode read buffer ptr - */ -static inline __le32 iwl4965_dma_addr2rbd_ptr(struct iwl_priv *priv, - dma_addr_t dma_addr) -{ - return cpu_to_le32((u32)(dma_addr >> 8)); -} - - -/** - * iwl4965_rx_queue_restock - refill RX queue from pre-allocated pool - * - * If there are slots in the RX queue that need to be restocked, - * and we have free pre-allocated buffers, fill the ranks as much - * as we can, pulling from rx_free. - * - * This moves the 'write' index forward to catch up with 'processed', and - * also updates the memory address in the firmware to reference the new - * target buffer. - */ -static int iwl4965_rx_queue_restock(struct iwl_priv *priv) -{ - struct iwl4965_rx_queue *rxq = &priv->rxq; - struct list_head *element; - struct iwl4965_rx_mem_buffer *rxb; - unsigned long flags; - int write, rc; - - spin_lock_irqsave(&rxq->lock, flags); - write = rxq->write & ~0x7; - while ((iwl4965_rx_queue_space(rxq) > 0) && (rxq->free_count)) { - /* Get next free Rx buffer, remove from free list */ - element = rxq->rx_free.next; - rxb = list_entry(element, struct iwl4965_rx_mem_buffer, list); - list_del(element); - - /* Point to Rx buffer via next RBD in circular buffer */ - rxq->bd[rxq->write] = iwl4965_dma_addr2rbd_ptr(priv, rxb->dma_addr); - rxq->queue[rxq->write] = rxb; - rxq->write = (rxq->write + 1) & RX_QUEUE_MASK; - rxq->free_count--; - } - spin_unlock_irqrestore(&rxq->lock, flags); - /* If the pre-allocated buffer pool is dropping low, schedule to - * refill it */ - if (rxq->free_count <= RX_LOW_WATERMARK) - queue_work(priv->workqueue, &priv->rx_replenish); - - - /* 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)) - || (abs(rxq->write - rxq->read) > 7)) { - spin_lock_irqsave(&rxq->lock, flags); - rxq->need_update = 1; - spin_unlock_irqrestore(&rxq->lock, flags); - rc = iwl4965_rx_queue_update_write_ptr(priv, rxq); - if (rc) - return rc; - } - - return 0; -} - -/** - * iwl4965_rx_replenish - Move all used packet from rx_used to rx_free - * - * When moving to rx_free an SKB is allocated for the slot. - * - * Also restock the Rx queue via iwl4965_rx_queue_restock. - * This is called as a scheduled work item (except for during initialization) - */ -static void iwl4965_rx_allocate(struct iwl_priv *priv) -{ - struct iwl4965_rx_queue *rxq = &priv->rxq; - struct list_head *element; - struct iwl4965_rx_mem_buffer *rxb; - unsigned long flags; - spin_lock_irqsave(&rxq->lock, flags); - while (!list_empty(&rxq->rx_used)) { - element = rxq->rx_used.next; - rxb = list_entry(element, struct iwl4965_rx_mem_buffer, list); - - /* Alloc a new receive buffer */ - rxb->skb = - alloc_skb(priv->hw_params.rx_buf_size, - __GFP_NOWARN | GFP_ATOMIC); - if (!rxb->skb) { - if (net_ratelimit()) - printk(KERN_CRIT DRV_NAME - ": Can not allocate SKB buffers\n"); - /* We don't reschedule replenish work here -- we will - * call the restock method and if it still needs - * more buffers it will schedule replenish */ - break; - } - priv->alloc_rxb_skb++; - list_del(element); + /* status change handler */ + priv->rx_handlers[CARD_STATE_NOTIFICATION] = iwl4965_rx_card_state_notif; - /* Get physical address of RB/SKB */ - rxb->dma_addr = - pci_map_single(priv->pci_dev, rxb->skb->data, - priv->hw_params.rx_buf_size, PCI_DMA_FROMDEVICE); - list_add_tail(&rxb->list, &rxq->rx_free); - rxq->free_count++; - } - spin_unlock_irqrestore(&rxq->lock, flags); + priv->rx_handlers[MISSED_BEACONS_NOTIFICATION] = + iwl_rx_missed_beacon_notif; + /* Rx handlers */ + priv->rx_handlers[REPLY_RX_PHY_CMD] = iwl_rx_reply_rx_phy; + priv->rx_handlers[REPLY_RX_MPDU_CMD] = iwl_rx_reply_rx; + /* block ack */ + priv->rx_handlers[REPLY_COMPRESSED_BA] = iwl_rx_reply_compressed_ba; + /* Set up hardware specific Rx handlers */ + priv->cfg->ops->lib->rx_handler_setup(priv); } /* * this should be called while priv->lock is locked */ -static void __iwl4965_rx_replenish(void *data) +static void __iwl_rx_replenish(struct iwl_priv *priv) { - struct iwl_priv *priv = data; - - iwl4965_rx_allocate(priv); - iwl4965_rx_queue_restock(priv); + iwl_rx_allocate(priv); + iwl_rx_queue_restock(priv); } -void iwl4965_rx_replenish(void *data) -{ - struct iwl_priv *priv = data; - unsigned long flags; - - iwl4965_rx_allocate(priv); - - spin_lock_irqsave(&priv->lock, flags); - iwl4965_rx_queue_restock(priv); - spin_unlock_irqrestore(&priv->lock, flags); -} - -/* 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 - * non NULL it is unmapped and freed - */ -static void iwl4965_rx_queue_free(struct iwl_priv *priv, struct iwl4965_rx_queue *rxq) -{ - int i; - for (i = 0; i < RX_QUEUE_SIZE + RX_FREE_BUFFERS; i++) { - if (rxq->pool[i].skb != NULL) { - pci_unmap_single(priv->pci_dev, - rxq->pool[i].dma_addr, - priv->hw_params.rx_buf_size, - PCI_DMA_FROMDEVICE); - dev_kfree_skb(rxq->pool[i].skb); - } - } - - pci_free_consistent(priv->pci_dev, 4 * RX_QUEUE_SIZE, rxq->bd, - rxq->dma_addr); - rxq->bd = NULL; -} - -int iwl4965_rx_queue_alloc(struct iwl_priv *priv) -{ - struct iwl4965_rx_queue *rxq = &priv->rxq; - struct pci_dev *dev = priv->pci_dev; - int i; - - spin_lock_init(&rxq->lock); - INIT_LIST_HEAD(&rxq->rx_free); - INIT_LIST_HEAD(&rxq->rx_used); - - /* Alloc the circular buffer of Read Buffer Descriptors (RBDs) */ - rxq->bd = pci_alloc_consistent(dev, 4 * RX_QUEUE_SIZE, &rxq->dma_addr); - if (!rxq->bd) - return -ENOMEM; - - /* Fill the rx_used queue with _all_ of the Rx buffers */ - for (i = 0; i < RX_FREE_BUFFERS + RX_QUEUE_SIZE; i++) - list_add_tail(&rxq->pool[i].list, &rxq->rx_used); - - /* 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->free_count = 0; - rxq->need_update = 0; - return 0; -} - -void iwl4965_rx_queue_reset(struct iwl_priv *priv, struct iwl4965_rx_queue *rxq) -{ - unsigned long flags; - int i; - spin_lock_irqsave(&rxq->lock, flags); - INIT_LIST_HEAD(&rxq->rx_free); - INIT_LIST_HEAD(&rxq->rx_used); - /* Fill the rx_used queue with _all_ of the Rx buffers */ - for (i = 0; i < RX_FREE_BUFFERS + RX_QUEUE_SIZE; i++) { - /* In the reset function, these buffers may have been allocated - * to an SKB, so we need to unmap and free potential storage */ - if (rxq->pool[i].skb != NULL) { - pci_unmap_single(priv->pci_dev, - rxq->pool[i].dma_addr, - priv->hw_params.rx_buf_size, - PCI_DMA_FROMDEVICE); - priv->alloc_rxb_skb--; - dev_kfree_skb(rxq->pool[i].skb); - rxq->pool[i].skb = NULL; - } - list_add_tail(&rxq->pool[i].list, &rxq->rx_used); - } - - /* 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->free_count = 0; - spin_unlock_irqrestore(&rxq->lock, flags); -} - -/* Convert linear signal-to-noise ratio into dB */ -static u8 ratio2dB[100] = { -/* 0 1 2 3 4 5 6 7 8 9 */ - 0, 0, 6, 10, 12, 14, 16, 17, 18, 19, /* 00 - 09 */ - 20, 21, 22, 22, 23, 23, 24, 25, 26, 26, /* 10 - 19 */ - 26, 26, 26, 27, 27, 28, 28, 28, 29, 29, /* 20 - 29 */ - 29, 30, 30, 30, 31, 31, 31, 31, 32, 32, /* 30 - 39 */ - 32, 32, 32, 33, 33, 33, 33, 33, 34, 34, /* 40 - 49 */ - 34, 34, 34, 34, 35, 35, 35, 35, 35, 35, /* 50 - 59 */ - 36, 36, 36, 36, 36, 36, 36, 37, 37, 37, /* 60 - 69 */ - 37, 37, 37, 37, 37, 38, 38, 38, 38, 38, /* 70 - 79 */ - 38, 38, 38, 38, 38, 39, 39, 39, 39, 39, /* 80 - 89 */ - 39, 39, 39, 39, 39, 40, 40, 40, 40, 40 /* 90 - 99 */ -}; - -/* Calculates a relative dB value from a ratio of linear - * (i.e. not dB) signal levels. - * Conversion assumes that levels are voltages (20*log), not powers (10*log). */ -int iwl4965_calc_db_from_ratio(int sig_ratio) -{ - /* 1000:1 or higher just report as 60 dB */ - if (sig_ratio >= 1000) - return 60; - - /* 100:1 or higher, divide by 10 and use table, - * add 20 dB to make up for divide by 10 */ - if (sig_ratio >= 100) - return (20 + (int)ratio2dB[sig_ratio/10]); - - /* We shouldn't see this */ - if (sig_ratio < 1) - return 0; - - /* Use table for ratios 1:1 - 99:1 */ - return (int)ratio2dB[sig_ratio]; -} - -#define PERFECT_RSSI (-20) /* dBm */ -#define WORST_RSSI (-95) /* dBm */ -#define RSSI_RANGE (PERFECT_RSSI - WORST_RSSI) - -/* Calculate an indication of rx signal quality (a percentage, not dBm!). - * See http://www.ces.clemson.edu/linux/signal_quality.shtml for info - * about formulas used below. */ -int iwl4965_calc_sig_qual(int rssi_dbm, int noise_dbm) -{ - int sig_qual; - int degradation = PERFECT_RSSI - rssi_dbm; - - /* If we get a noise measurement, use signal-to-noise ratio (SNR) - * as indicator; formula is (signal dbm - noise dbm). - * SNR at or above 40 is a great signal (100%). - * Below that, scale to fit SNR of 0 - 40 dB within 0 - 100% indicator. - * Weakest usable signal is usually 10 - 15 dB SNR. */ - if (noise_dbm) { - if (rssi_dbm - noise_dbm >= 40) - return 100; - else if (rssi_dbm < noise_dbm) - return 0; - sig_qual = ((rssi_dbm - noise_dbm) * 5) / 2; - - /* Else use just the signal level. - * This formula is a least squares fit of data points collected and - * compared with a reference system that had a percentage (%) display - * for signal quality. */ - } else - sig_qual = (100 * (RSSI_RANGE * RSSI_RANGE) - degradation * - (15 * RSSI_RANGE + 62 * degradation)) / - (RSSI_RANGE * RSSI_RANGE); - - if (sig_qual > 100) - sig_qual = 100; - else if (sig_qual < 1) - sig_qual = 0; - - return sig_qual; -} - /** - * iwl4965_rx_handle - Main entry function for receiving responses from uCode + * iwl_rx_handle - Main entry function for receiving responses from uCode * * Uses the priv->rx_handlers callback function array to invoke * the appropriate handlers, including command responses, * frame-received notifications, and other notifications. */ -static void iwl4965_rx_handle(struct iwl_priv *priv) +void iwl_rx_handle(struct iwl_priv *priv) { - struct iwl4965_rx_mem_buffer *rxb; - struct iwl4965_rx_packet *pkt; - struct iwl4965_rx_queue *rxq = &priv->rxq; + struct iwl_rx_mem_buffer *rxb; + struct iwl_rx_packet *pkt; + struct iwl_rx_queue *rxq = &priv->rxq; u32 r, i; int reclaim; unsigned long flags; @@ -3923,14 +1306,14 @@ static void iwl4965_rx_handle(struct iwl_priv *priv) /* uCode's read index (stored in shared DRAM) indicates the last Rx * buffer that the driver may process (last buffer filled by ucode). */ - r = iwl4965_hw_get_rx_read(priv); + r = priv->cfg->ops->lib->shared_mem_rx_idx(priv); i = rxq->read; /* Rx interrupt, but nothing sent from uCode */ if (i == r) - IWL_DEBUG(IWL_DL_RX | IWL_DL_ISR, "r = %d, i = %d\n", r, i); + IWL_DEBUG(IWL_DL_RX, "r = %d, i = %d\n", r, i); - if (iwl4965_rx_queue_space(rxq) > (RX_QUEUE_SIZE / 2)) + if (iwl_rx_queue_space(rxq) > (RX_QUEUE_SIZE / 2)) fill_rx = 1; while (i != r) { @@ -3946,7 +1329,7 @@ static void iwl4965_rx_handle(struct iwl_priv *priv) pci_dma_sync_single_for_cpu(priv->pci_dev, rxb->dma_addr, priv->hw_params.rx_buf_size, PCI_DMA_FROMDEVICE); - pkt = (struct iwl4965_rx_packet *)rxb->skb->data; + pkt = (struct iwl_rx_packet *)rxb->skb->data; /* Reclaim a command buffer only if this packet is a response * to a (driver-originated) command. @@ -3965,13 +1348,12 @@ static void iwl4965_rx_handle(struct iwl_priv *priv) * handle those that need handling via function in * rx_handlers table. See iwl4965_setup_rx_handlers() */ if (priv->rx_handlers[pkt->hdr.cmd]) { - IWL_DEBUG(IWL_DL_HOST_COMMAND | IWL_DL_RX | IWL_DL_ISR, - "r = %d, i = %d, %s, 0x%02x\n", r, i, - get_cmd_string(pkt->hdr.cmd), pkt->hdr.cmd); + IWL_DEBUG(IWL_DL_RX, "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); } else { /* No handling needed */ - IWL_DEBUG(IWL_DL_HOST_COMMAND | IWL_DL_RX | IWL_DL_ISR, + IWL_DEBUG(IWL_DL_RX, "r %d i %d No handler needed for %s, 0x%02x\n", r, i, get_cmd_string(pkt->hdr.cmd), pkt->hdr.cmd); @@ -3982,7 +1364,7 @@ static void iwl4965_rx_handle(struct iwl_priv *priv) * fire off the (possibly) blocking iwl_send_cmd() * as we reclaim the driver command queue */ if (rxb && rxb->skb) - iwl4965_tx_cmd_complete(priv, rxb); + iwl_tx_cmd_complete(priv, rxb); else IWL_WARNING("Claim null rxb?\n"); } @@ -4009,7 +1391,7 @@ static void iwl4965_rx_handle(struct iwl_priv *priv) count++; if (count >= 8) { priv->rxq.read = i; - __iwl4965_rx_replenish(priv); + __iwl_rx_replenish(priv); count = 0; } } @@ -4017,62 +1399,17 @@ static void iwl4965_rx_handle(struct iwl_priv *priv) /* Backtrack one entry */ priv->rxq.read = i; - iwl4965_rx_queue_restock(priv); -} - -/** - * iwl4965_tx_queue_update_write_ptr - Send new write index to hardware - */ -static int iwl4965_tx_queue_update_write_ptr(struct iwl_priv *priv, - struct iwl4965_tx_queue *txq) -{ - u32 reg = 0; - int rc = 0; - int txq_id = txq->q.id; - - if (txq->need_update == 0) - return rc; - - /* if we're trying to save power */ - if (test_bit(STATUS_POWER_PMI, &priv->status)) { - /* wake up nic if it's powered down ... - * uCode will wake up, and interrupt us again, so next - * time we'll skip this part. */ - reg = iwl_read32(priv, CSR_UCODE_DRV_GP1); - - if (reg & CSR_UCODE_DRV_GP1_BIT_MAC_SLEEP) { - IWL_DEBUG_INFO("Requesting wakeup, GP1 = 0x%x\n", reg); - iwl_set_bit(priv, CSR_GP_CNTRL, - CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); - return rc; - } - - /* restore this queue's parameters in nic hardware. */ - rc = iwl_grab_nic_access(priv); - if (rc) - return rc; - 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). */ - } else - iwl_write32(priv, HBUS_TARG_WRPTR, - txq->q.write_ptr | (txq_id << 8)); - - txq->need_update = 0; - - return rc; + iwl_rx_queue_restock(priv); } #ifdef CONFIG_IWLWIFI_DEBUG -static void iwl4965_print_rx_config_cmd(struct iwl4965_rxon_cmd *rxon) +static void iwl4965_print_rx_config_cmd(struct iwl_priv *priv) { + struct iwl_rxon_cmd *rxon = &priv->staging_rxon; DECLARE_MAC_BUF(mac); IWL_DEBUG_RADIO("RX CONFIG:\n"); - iwl_print_hex_dump(IWL_DL_RADIO, (u8 *) rxon, sizeof(*rxon)); + iwl_print_hex_dump(priv, IWL_DL_RADIO, (u8 *) rxon, sizeof(*rxon)); IWL_DEBUG_RADIO("u16 channel: 0x%x\n", le16_to_cpu(rxon->channel)); IWL_DEBUG_RADIO("u32 flags: 0x%08X\n", le32_to_cpu(rxon->flags)); IWL_DEBUG_RADIO("u32 filter_flags: 0x%08x\n", @@ -4118,173 +1455,6 @@ static inline void iwl4965_disable_interrupts(struct iwl_priv *priv) IWL_DEBUG_ISR("Disabled interrupts\n"); } -static const char *desc_lookup(int i) -{ - switch (i) { - case 1: - return "FAIL"; - case 2: - return "BAD_PARAM"; - case 3: - return "BAD_CHECKSUM"; - case 4: - return "NMI_INTERRUPT"; - case 5: - return "SYSASSERT"; - case 6: - return "FATAL_ERROR"; - } - - return "UNKNOWN"; -} - -#define ERROR_START_OFFSET (1 * sizeof(u32)) -#define ERROR_ELEM_SIZE (7 * sizeof(u32)) - -static void iwl4965_dump_nic_error_log(struct iwl_priv *priv) -{ - u32 data2, line; - u32 desc, time, count, base, data1; - u32 blink1, blink2, ilink1, ilink2; - int rc; - - base = le32_to_cpu(priv->card_alive.error_event_table_ptr); - - if (!priv->cfg->ops->lib->is_valid_rtc_data_addr(base)) { - IWL_ERROR("Not valid error log pointer 0x%08X\n", base); - return; - } - - rc = iwl_grab_nic_access(priv); - if (rc) { - IWL_WARNING("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) { - IWL_ERROR("Start IWL Error Log Dump:\n"); - IWL_ERROR("Status: 0x%08lX, count: %d\n", priv->status, count); - } - - desc = iwl_read_targ_mem(priv, base + 1 * sizeof(u32)); - blink1 = iwl_read_targ_mem(priv, base + 3 * sizeof(u32)); - blink2 = iwl_read_targ_mem(priv, base + 4 * sizeof(u32)); - ilink1 = iwl_read_targ_mem(priv, base + 5 * sizeof(u32)); - ilink2 = iwl_read_targ_mem(priv, base + 6 * sizeof(u32)); - data1 = iwl_read_targ_mem(priv, base + 7 * sizeof(u32)); - data2 = iwl_read_targ_mem(priv, base + 8 * sizeof(u32)); - line = iwl_read_targ_mem(priv, base + 9 * sizeof(u32)); - time = iwl_read_targ_mem(priv, base + 11 * sizeof(u32)); - - IWL_ERROR("Desc Time " - "data1 data2 line\n"); - IWL_ERROR("%-13s (#%d) %010u 0x%08X 0x%08X %u\n", - desc_lookup(desc), desc, time, data1, data2, line); - IWL_ERROR("blink1 blink2 ilink1 ilink2\n"); - IWL_ERROR("0x%05X 0x%05X 0x%05X 0x%05X\n", blink1, blink2, - ilink1, ilink2); - - iwl_release_nic_access(priv); -} - -#define EVENT_START_OFFSET (4 * sizeof(u32)) - -/** - * iwl4965_print_event_log - Dump error event log to syslog - * - * NOTE: Must be called with iwl_grab_nic_access() already obtained! - */ -static void iwl4965_print_event_log(struct iwl_priv *priv, u32 start_idx, - u32 num_events, u32 mode) -{ - u32 i; - u32 base; /* SRAM byte address of event log header */ - u32 event_size; /* 2 u32s, or 3 u32s if timestamp recorded */ - u32 ptr; /* SRAM byte address of log data */ - u32 ev, time, data; /* event log data */ - - if (num_events == 0) - return; - - base = le32_to_cpu(priv->card_alive.log_event_table_ptr); - - if (mode == 0) - event_size = 2 * sizeof(u32); - else - event_size = 3 * sizeof(u32); - - ptr = base + EVENT_START_OFFSET + (start_idx * event_size); - - /* "time" is actually "data" for mode 0 (no timestamp). - * place event id # at far right for easier visual parsing. */ - for (i = 0; i < num_events; i++) { - ev = iwl_read_targ_mem(priv, ptr); - ptr += sizeof(u32); - time = iwl_read_targ_mem(priv, ptr); - ptr += sizeof(u32); - if (mode == 0) - IWL_ERROR("0x%08x\t%04u\n", time, ev); /* data, ev */ - else { - data = iwl_read_targ_mem(priv, ptr); - ptr += sizeof(u32); - IWL_ERROR("%010u\t0x%08x\t%04u\n", time, data, ev); - } - } -} - -static void iwl4965_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 */ - u32 num_wraps; /* # times uCode wrapped to top of log */ - u32 next_entry; /* index of next entry to be written by uCode */ - u32 size; /* # entries that we'll print */ - - base = le32_to_cpu(priv->card_alive.log_event_table_ptr); - if (!priv->cfg->ops->lib->is_valid_rtc_data_addr(base)) { - IWL_ERROR("Invalid event log pointer 0x%08X\n", base); - return; - } - - rc = iwl_grab_nic_access(priv); - if (rc) { - IWL_WARNING("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))); - num_wraps = iwl_read_targ_mem(priv, base + (2 * sizeof(u32))); - next_entry = iwl_read_targ_mem(priv, base + (3 * sizeof(u32))); - - size = num_wraps ? capacity : next_entry; - - /* bail out if nothing in log */ - if (size == 0) { - IWL_ERROR("Start IWL Event Log Dump: nothing in log\n"); - iwl_release_nic_access(priv); - return; - } - - IWL_ERROR("Start IWL Event Log Dump: display count %d, wraps %d\n", - size, num_wraps); - - /* if uCode has wrapped back to top of log, start at the oldest entry, - * i.e the next one that uCode would fill. */ - if (num_wraps) - iwl4965_print_event_log(priv, next_entry, - capacity - next_entry, mode); - - /* (then/else) start at top of log */ - iwl4965_print_event_log(priv, 0, next_entry, mode); - - iwl_release_nic_access(priv); -} /** * iwl4965_irq_handle_error - called for HW or SW error interrupt from card @@ -4298,10 +1468,10 @@ static void iwl4965_irq_handle_error(struct iwl_priv *priv) clear_bit(STATUS_HCMD_ACTIVE, &priv->status); #ifdef CONFIG_IWLWIFI_DEBUG - if (iwl_debug_level & IWL_DL_FW_ERRORS) { - iwl4965_dump_nic_error_log(priv); - iwl4965_dump_nic_event_log(priv); - iwl4965_print_rx_config_cmd(&priv->staging_rxon); + if (priv->debug_level & IWL_DL_FW_ERRORS) { + iwl_dump_nic_error_log(priv); + iwl_dump_nic_event_log(priv); + iwl4965_print_rx_config_cmd(priv); } #endif @@ -4312,7 +1482,7 @@ static void iwl4965_irq_handle_error(struct iwl_priv *priv) clear_bit(STATUS_READY, &priv->status); if (!test_bit(STATUS_EXIT_PENDING, &priv->status)) { - IWL_DEBUG(IWL_DL_INFO | IWL_DL_FW_ERRORS, + IWL_DEBUG(IWL_DL_FW_ERRORS, "Restarting adapter due to uCode error.\n"); if (iwl_is_associated(priv)) { @@ -4320,7 +1490,8 @@ static void iwl4965_irq_handle_error(struct iwl_priv *priv) sizeof(priv->recovery_rxon)); priv->error_recovering = 1; } - queue_work(priv->workqueue, &priv->restart); + if (priv->cfg->mod_params->restart_fw) + queue_work(priv->workqueue, &priv->restart); } } @@ -4333,7 +1504,7 @@ static void iwl4965_error_recovery(struct iwl_priv *priv) priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK; iwl4965_commit_rxon(priv); - iwl4965_rxon_add_station(priv, priv->bssid, 1); + 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); @@ -4365,7 +1536,7 @@ static void iwl4965_irq_tasklet(struct iwl_priv *priv) iwl_write32(priv, CSR_FH_INT_STATUS, inta_fh); #ifdef CONFIG_IWLWIFI_DEBUG - if (iwl_debug_level & IWL_DL_ISR) { + if (priv->debug_level & IWL_DL_ISR) { /* just for debug */ inta_mask = iwl_read32(priv, CSR_INT_MASK); IWL_DEBUG_ISR("inta 0x%08x, enabled 0x%08x, fh 0x%08x\n", @@ -4399,7 +1570,7 @@ static void iwl4965_irq_tasklet(struct iwl_priv *priv) } #ifdef CONFIG_IWLWIFI_DEBUG - if (iwl_debug_level & (IWL_DL_ISR)) { + 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("Scheduler finished to transmit " @@ -4420,18 +1591,15 @@ static void iwl4965_irq_tasklet(struct iwl_priv *priv) CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW)) hw_rf_kill = 1; - IWL_DEBUG(IWL_DL_INFO | IWL_DL_RF_KILL | IWL_DL_ISR, - "RF_KILL bit toggled to %s.\n", + IWL_DEBUG(IWL_DL_RF_KILL, "RF_KILL bit toggled to %s.\n", hw_rf_kill ? "disable radio":"enable radio"); - /* Queue restart only if RF_KILL switch was set to "kill" - * when we loaded driver, and is now set to "enable". - * After we're Alive, RF_KILL gets handled by - * iwl4965_rx_card_state_notif() */ - if (!hw_rf_kill && !test_bit(STATUS_ALIVE, &priv->status)) { + /* driver only loads ucode once setting the interface up. + * the driver as well won't allow loading if RFKILL is set + * therefore no need to restart the driver from this handler + */ + if (!hw_rf_kill && !test_bit(STATUS_ALIVE, &priv->status)) clear_bit(STATUS_RF_KILL_HW, &priv->status); - queue_work(priv->workqueue, &priv->restart); - } handled |= CSR_INT_BIT_RF_KILL; } @@ -4453,13 +1621,13 @@ static void iwl4965_irq_tasklet(struct iwl_priv *priv) /* uCode wakes up after power-down sleep */ if (inta & CSR_INT_BIT_WAKEUP) { IWL_DEBUG_ISR("Wakeup interrupt\n"); - iwl4965_rx_queue_update_write_ptr(priv, &priv->rxq); - iwl4965_tx_queue_update_write_ptr(priv, &priv->txq[0]); - iwl4965_tx_queue_update_write_ptr(priv, &priv->txq[1]); - iwl4965_tx_queue_update_write_ptr(priv, &priv->txq[2]); - iwl4965_tx_queue_update_write_ptr(priv, &priv->txq[3]); - iwl4965_tx_queue_update_write_ptr(priv, &priv->txq[4]); - iwl4965_tx_queue_update_write_ptr(priv, &priv->txq[5]); + 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]); handled |= CSR_INT_BIT_WAKEUP; } @@ -4468,13 +1636,16 @@ static void iwl4965_irq_tasklet(struct iwl_priv *priv) * 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)) { - iwl4965_rx_handle(priv); + iwl_rx_handle(priv); handled |= (CSR_INT_BIT_FH_RX | CSR_INT_BIT_SW_RX); } if (inta & CSR_INT_BIT_FH_TX) { IWL_DEBUG_ISR("Tx interrupt\n"); 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) @@ -4492,7 +1663,7 @@ static void iwl4965_irq_tasklet(struct iwl_priv *priv) iwl4965_enable_interrupts(priv); #ifdef CONFIG_IWLWIFI_DEBUG - if (iwl_debug_level & (IWL_DL_ISR)) { + if (priv->debug_level & (IWL_DL_ISR)) { inta = iwl_read32(priv, CSR_INT); inta_mask = iwl_read32(priv, CSR_INT_MASK); inta_fh = iwl_read32(priv, CSR_FH_INT_STATUS); @@ -4561,297 +1732,6 @@ static irqreturn_t iwl4965_isr(int irq, void *data) return IRQ_NONE; } -/* For active scan, listen ACTIVE_DWELL_TIME (msec) on each channel after - * sending probe req. This should be set long enough to hear probe responses - * from more than one AP. */ -#define IWL_ACTIVE_DWELL_TIME_24 (20) /* all times in msec */ -#define IWL_ACTIVE_DWELL_TIME_52 (10) - -/* For faster active scanning, scan will move to the next channel if fewer than - * PLCP_QUIET_THRESH packets are heard on this channel within - * ACTIVE_QUIET_TIME after sending probe request. This shortens the dwell - * time if it's a quiet channel (nothing responded to our probe, and there's - * no other traffic). - * Disable "quiet" feature by setting PLCP_QUIET_THRESH to 0. */ -#define IWL_PLCP_QUIET_THRESH __constant_cpu_to_le16(1) /* packets */ -#define IWL_ACTIVE_QUIET_TIME __constant_cpu_to_le16(5) /* msec */ - -/* For passive scan, listen PASSIVE_DWELL_TIME (msec) on each channel. - * Must be set longer than active dwell time. - * For the most reliable scan, set > AP beacon interval (typically 100msec). */ -#define IWL_PASSIVE_DWELL_TIME_24 (20) /* all times in msec */ -#define IWL_PASSIVE_DWELL_TIME_52 (10) -#define IWL_PASSIVE_DWELL_BASE (100) -#define IWL_CHANNEL_TUNE_TIME 5 - -static inline u16 iwl4965_get_active_dwell_time(struct iwl_priv *priv, - enum ieee80211_band band) -{ - if (band == IEEE80211_BAND_5GHZ) - return IWL_ACTIVE_DWELL_TIME_52; - else - return IWL_ACTIVE_DWELL_TIME_24; -} - -static u16 iwl4965_get_passive_dwell_time(struct iwl_priv *priv, - enum ieee80211_band band) -{ - u16 active = iwl4965_get_active_dwell_time(priv, band); - u16 passive = (band != IEEE80211_BAND_5GHZ) ? - IWL_PASSIVE_DWELL_BASE + IWL_PASSIVE_DWELL_TIME_24 : - IWL_PASSIVE_DWELL_BASE + IWL_PASSIVE_DWELL_TIME_52; - - if (iwl_is_associated(priv)) { - /* If we're associated, we clamp the maximum passive - * dwell time to be 98% of the beacon interval (minus - * 2 * channel tune time) */ - passive = priv->beacon_int; - if ((passive > IWL_PASSIVE_DWELL_BASE) || !passive) - passive = IWL_PASSIVE_DWELL_BASE; - passive = (passive * 98) / 100 - IWL_CHANNEL_TUNE_TIME * 2; - } - - if (passive <= active) - passive = active + 1; - - return passive; -} - -static int iwl4965_get_channels_for_scan(struct iwl_priv *priv, - enum ieee80211_band band, - u8 is_active, u8 direct_mask, - struct iwl4965_scan_channel *scan_ch) -{ - const struct ieee80211_channel *channels = NULL; - const struct ieee80211_supported_band *sband; - const struct iwl_channel_info *ch_info; - u16 passive_dwell = 0; - u16 active_dwell = 0; - int added, i; - - sband = iwl4965_get_hw_mode(priv, band); - if (!sband) - return 0; - - channels = sband->channels; - - active_dwell = iwl4965_get_active_dwell_time(priv, band); - passive_dwell = iwl4965_get_passive_dwell_time(priv, band); - - for (i = 0, added = 0; i < sband->n_channels; i++) { - if (channels[i].flags & IEEE80211_CHAN_DISABLED) - continue; - - scan_ch->channel = ieee80211_frequency_to_channel(channels[i].center_freq); - - ch_info = iwl_get_channel_info(priv, band, scan_ch->channel); - if (!is_channel_valid(ch_info)) { - IWL_DEBUG_SCAN("Channel %d is INVALID for this band.\n", - scan_ch->channel); - continue; - } - - if (!is_active || is_channel_passive(ch_info) || - (channels[i].flags & IEEE80211_CHAN_PASSIVE_SCAN)) - scan_ch->type = 0; /* passive */ - else - scan_ch->type = 1; /* active */ - - if (scan_ch->type & 1) - scan_ch->type |= (direct_mask << 1); - - if (is_channel_narrow(ch_info)) - scan_ch->type |= (1 << 7); - - scan_ch->active_dwell = cpu_to_le16(active_dwell); - scan_ch->passive_dwell = cpu_to_le16(passive_dwell); - - /* Set txpower levels to defaults */ - scan_ch->tpc.dsp_atten = 110; - /* scan_pwr_info->tpc.dsp_atten; */ - - /*scan_pwr_info->tpc.tx_gain; */ - if (band == IEEE80211_BAND_5GHZ) - scan_ch->tpc.tx_gain = ((1 << 5) | (3 << 3)) | 3; - else { - scan_ch->tpc.tx_gain = ((1 << 5) | (5 << 3)); - /* NOTE: if we were doing 6Mb OFDM for scans we'd use - * power level: - * scan_ch->tpc.tx_gain = ((1 << 5) | (2 << 3)) | 3; - */ - } - - IWL_DEBUG_SCAN("Scanning %d [%s %d]\n", - scan_ch->channel, - (scan_ch->type & 1) ? "ACTIVE" : "PASSIVE", - (scan_ch->type & 1) ? - active_dwell : passive_dwell); - - scan_ch++; - added++; - } - - IWL_DEBUG_SCAN("total channels to scan %d \n", added); - return added; -} - -static void iwl4965_init_hw_rates(struct iwl_priv *priv, - struct ieee80211_rate *rates) -{ - int i; - - for (i = 0; i < IWL_RATE_COUNT; i++) { - rates[i].bitrate = iwl4965_rates[i].ieee * 5; - rates[i].hw_value = i; /* Rate scaling will work on indexes */ - rates[i].hw_value_short = i; - rates[i].flags = 0; - if ((i > IWL_LAST_OFDM_RATE) || (i < IWL_FIRST_OFDM_RATE)) { - /* - * If CCK != 1M then set short preamble rate flag. - */ - rates[i].flags |= - (iwl4965_rates[i].plcp == IWL_RATE_1M_PLCP) ? - 0 : IEEE80211_RATE_SHORT_PREAMBLE; - } - } -} - -/** - * iwl4965_init_geos - Initialize mac80211's geo/channel info based from eeprom - */ -int iwl4965_init_geos(struct iwl_priv *priv) -{ - struct iwl_channel_info *ch; - struct ieee80211_supported_band *sband; - struct ieee80211_channel *channels; - struct ieee80211_channel *geo_ch; - struct ieee80211_rate *rates; - int i = 0; - - if (priv->bands[IEEE80211_BAND_2GHZ].n_bitrates || - priv->bands[IEEE80211_BAND_5GHZ].n_bitrates) { - IWL_DEBUG_INFO("Geography modes already initialized.\n"); - set_bit(STATUS_GEO_CONFIGURED, &priv->status); - return 0; - } - - channels = kzalloc(sizeof(struct ieee80211_channel) * - priv->channel_count, GFP_KERNEL); - if (!channels) - return -ENOMEM; - - rates = kzalloc((sizeof(struct ieee80211_rate) * (IWL_RATE_COUNT + 1)), - GFP_KERNEL); - if (!rates) { - kfree(channels); - return -ENOMEM; - } - - /* 5.2GHz channels start after the 2.4GHz channels */ - sband = &priv->bands[IEEE80211_BAND_5GHZ]; - sband->channels = &channels[ARRAY_SIZE(iwl_eeprom_band_1)]; - /* just OFDM */ - sband->bitrates = &rates[IWL_FIRST_OFDM_RATE]; - sband->n_bitrates = IWL_RATE_COUNT - IWL_FIRST_OFDM_RATE; - - iwl4965_init_ht_hw_capab(priv, &sband->ht_info, IEEE80211_BAND_5GHZ); - - sband = &priv->bands[IEEE80211_BAND_2GHZ]; - sband->channels = channels; - /* OFDM & CCK */ - sband->bitrates = rates; - sband->n_bitrates = IWL_RATE_COUNT; - - iwl4965_init_ht_hw_capab(priv, &sband->ht_info, IEEE80211_BAND_2GHZ); - - priv->ieee_channels = channels; - priv->ieee_rates = rates; - - iwl4965_init_hw_rates(priv, rates); - - for (i = 0; i < priv->channel_count; i++) { - ch = &priv->channel_info[i]; - - /* FIXME: might be removed if scan is OK */ - if (!is_channel_valid(ch)) - continue; - - if (is_channel_a_band(ch)) - sband = &priv->bands[IEEE80211_BAND_5GHZ]; - else - sband = &priv->bands[IEEE80211_BAND_2GHZ]; - - geo_ch = &sband->channels[sband->n_channels++]; - - geo_ch->center_freq = ieee80211_channel_to_frequency(ch->channel); - geo_ch->max_power = ch->max_power_avg; - geo_ch->max_antenna_gain = 0xff; - geo_ch->hw_value = ch->channel; - - if (is_channel_valid(ch)) { - if (!(ch->flags & EEPROM_CHANNEL_IBSS)) - geo_ch->flags |= IEEE80211_CHAN_NO_IBSS; - - if (!(ch->flags & EEPROM_CHANNEL_ACTIVE)) - geo_ch->flags |= IEEE80211_CHAN_PASSIVE_SCAN; - - if (ch->flags & EEPROM_CHANNEL_RADAR) - geo_ch->flags |= IEEE80211_CHAN_RADAR; - - if (ch->max_power_avg > priv->max_channel_txpower_limit) - priv->max_channel_txpower_limit = - ch->max_power_avg; - } else { - geo_ch->flags |= IEEE80211_CHAN_DISABLED; - } - - /* Save flags for reg domain usage */ - geo_ch->orig_flags = geo_ch->flags; - - IWL_DEBUG_INFO("Channel %d Freq=%d[%sGHz] %s flag=0%X\n", - ch->channel, geo_ch->center_freq, - is_channel_a_band(ch) ? "5.2" : "2.4", - geo_ch->flags & IEEE80211_CHAN_DISABLED ? - "restricted" : "valid", - geo_ch->flags); - } - - if ((priv->bands[IEEE80211_BAND_5GHZ].n_channels == 0) && - priv->cfg->sku & IWL_SKU_A) { - printk(KERN_INFO DRV_NAME - ": Incorrectly detected BG card as ABG. Please send " - "your PCI ID 0x%04X:0x%04X to maintainer.\n", - priv->pci_dev->device, priv->pci_dev->subsystem_device); - priv->cfg->sku &= ~IWL_SKU_A; - } - - printk(KERN_INFO DRV_NAME - ": Tunable channels: %d 802.11bg, %d 802.11a channels\n", - priv->bands[IEEE80211_BAND_2GHZ].n_channels, - priv->bands[IEEE80211_BAND_5GHZ].n_channels); - - if (priv->bands[IEEE80211_BAND_2GHZ].n_channels) - priv->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = - &priv->bands[IEEE80211_BAND_2GHZ]; - if (priv->bands[IEEE80211_BAND_5GHZ].n_channels) - priv->hw->wiphy->bands[IEEE80211_BAND_5GHZ] = - &priv->bands[IEEE80211_BAND_5GHZ]; - - set_bit(STATUS_GEO_CONFIGURED, &priv->status); - - return 0; -} - -/* - * iwl4965_free_geos - undo allocations in iwl4965_init_geos - */ -void iwl4965_free_geos(struct iwl_priv *priv) -{ - kfree(priv->ieee_channels); - kfree(priv->ieee_rates); - clear_bit(STATUS_GEO_CONFIGURED, &priv->status); -} - /****************************************************************************** * * uCode download functions @@ -4868,146 +1748,6 @@ static void iwl4965_dealloc_ucode_pci(struct iwl_priv *priv) iwl_free_fw_desc(priv->pci_dev, &priv->ucode_boot); } -/** - * iwl4965_verify_inst_full - verify runtime uCode image in card vs. host, - * looking at all data. - */ -static int iwl4965_verify_inst_full(struct iwl_priv *priv, __le32 *image, - u32 len) -{ - u32 val; - u32 save_len = len; - int rc = 0; - u32 errcnt; - - IWL_DEBUG_INFO("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, RTC_INST_LOWER_BOUND); - - errcnt = 0; - for (; len > 0; len -= sizeof(u32), image++) { - /* read data comes through single port, auto-incr addr */ - /* NOTE: Use the debugless read so we don't flood kernel log - * if IWL_DL_IO is set */ - val = _iwl_read_direct32(priv, HBUS_TARG_MEM_RDAT); - if (val != le32_to_cpu(*image)) { - IWL_ERROR("uCode INST section is invalid at " - "offset 0x%x, is 0x%x, s/b 0x%x\n", - save_len - len, val, le32_to_cpu(*image)); - rc = -EIO; - errcnt++; - if (errcnt >= 20) - break; - } - } - - iwl_release_nic_access(priv); - - if (!errcnt) - IWL_DEBUG_INFO - ("ucode image in INSTRUCTION memory is good\n"); - - return rc; -} - - -/** - * iwl4965_verify_inst_sparse - verify runtime uCode image in card vs. host, - * using sample data 100 bytes apart. If these sample points are good, - * it's a pretty good bet that everything between them is good, too. - */ -static int iwl4965_verify_inst_sparse(struct iwl_priv *priv, __le32 *image, u32 len) -{ - u32 val; - int rc = 0; - u32 errcnt = 0; - u32 i; - - IWL_DEBUG_INFO("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 - * if IWL_DL_IO is set */ - iwl_write_direct32(priv, HBUS_TARG_MEM_RADDR, - i + RTC_INST_LOWER_BOUND); - val = _iwl_read_direct32(priv, HBUS_TARG_MEM_RDAT); - if (val != le32_to_cpu(*image)) { -#if 0 /* Enable this if you want to see details */ - IWL_ERROR("uCode INST section is invalid at " - "offset 0x%x, is 0x%x, s/b 0x%x\n", - i, val, *image); -#endif - rc = -EIO; - errcnt++; - if (errcnt >= 3) - break; - } - } - - iwl_release_nic_access(priv); - - return rc; -} - - -/** - * iwl4965_verify_ucode - determine which instruction image is in SRAM, - * and verify its contents - */ -static int iwl4965_verify_ucode(struct iwl_priv *priv) -{ - __le32 *image; - u32 len; - int rc = 0; - - /* Try bootstrap */ - image = (__le32 *)priv->ucode_boot.v_addr; - len = priv->ucode_boot.len; - rc = iwl4965_verify_inst_sparse(priv, image, len); - if (rc == 0) { - IWL_DEBUG_INFO("Bootstrap uCode is good in inst SRAM\n"); - return 0; - } - - /* Try initialize */ - image = (__le32 *)priv->ucode_init.v_addr; - len = priv->ucode_init.len; - rc = iwl4965_verify_inst_sparse(priv, image, len); - if (rc == 0) { - IWL_DEBUG_INFO("Initialize uCode is good in inst SRAM\n"); - return 0; - } - - /* Try runtime/protocol */ - image = (__le32 *)priv->ucode_code.v_addr; - len = priv->ucode_code.len; - rc = iwl4965_verify_inst_sparse(priv, image, len); - if (rc == 0) { - IWL_DEBUG_INFO("Runtime uCode is good in inst SRAM\n"); - return 0; - } - - IWL_ERROR("NO VALID UCODE IMAGE IN INSTRUCTION SRAM!!\n"); - - /* Since nothing seems to match, show first several data entries in - * instruction SRAM, so maybe visual inspection will give a clue. - * Selection of bootstrap image (vs. other images) is arbitrary. */ - image = (__le32 *)priv->ucode_boot.v_addr; - len = priv->ucode_boot.len; - rc = iwl4965_verify_inst_full(priv, image, len); - - return rc; -} - static void iwl4965_nic_start(struct iwl_priv *priv) { /* Remove all resets to allow NIC to operate */ @@ -5022,7 +1762,7 @@ static void iwl4965_nic_start(struct iwl_priv *priv) */ static int iwl4965_read_ucode(struct iwl_priv *priv) { - struct iwl4965_ucode *ucode; + struct iwl_ucode *ucode; int ret; const struct firmware *ucode_raw; const char *name = priv->cfg->fw_name; @@ -5083,34 +1823,34 @@ static int iwl4965_read_ucode(struct iwl_priv *priv) } /* Verify that uCode images will fit in card's SRAM */ - if (inst_size > IWL_MAX_INST_SIZE) { + if (inst_size > priv->hw_params.max_inst_size) { IWL_DEBUG_INFO("uCode instr len %d too large to fit in\n", inst_size); ret = -EINVAL; goto err_release; } - if (data_size > IWL_MAX_DATA_SIZE) { + if (data_size > priv->hw_params.max_data_size) { IWL_DEBUG_INFO("uCode data len %d too large to fit in\n", data_size); ret = -EINVAL; goto err_release; } - if (init_size > IWL_MAX_INST_SIZE) { + if (init_size > priv->hw_params.max_inst_size) { IWL_DEBUG_INFO ("uCode init instr len %d too large to fit in\n", init_size); ret = -EINVAL; goto err_release; } - if (init_data_size > IWL_MAX_DATA_SIZE) { + if (init_data_size > priv->hw_params.max_data_size) { IWL_DEBUG_INFO ("uCode init data len %d too large to fit in\n", init_data_size); ret = -EINVAL; goto err_release; } - if (boot_size > IWL_MAX_BSM_SIZE) { + if (boot_size > priv->hw_params.max_bsm_size) { IWL_DEBUG_INFO ("uCode boot instr len %d too large to fit in\n", boot_size); @@ -5211,111 +1951,12 @@ static int iwl4965_read_ucode(struct iwl_priv *priv) return ret; } - -/** - * iwl4965_set_ucode_ptrs - Set uCode address location - * - * Tell initialization uCode where to find runtime uCode. - * - * BSM registers initially contain pointers to initialization uCode. - * We need to replace them to load runtime uCode inst and data, - * and to save runtime data when powering down. - */ -static int iwl4965_set_ucode_ptrs(struct iwl_priv *priv) -{ - dma_addr_t pinst; - dma_addr_t pdata; - int rc = 0; - unsigned long flags; - - /* 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); - 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); - iwl_write_prph(priv, BSM_DRAM_DATA_BYTECOUNT_REG, - priv->ucode_data.len); - - /* Inst bytecount must be last to set up, bit 31 signals uCode - * 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("Runtime uCode pointers are set.\n"); - - return rc; -} - -/** - * iwl4965_init_alive_start - Called after REPLY_ALIVE notification received - * - * Called after REPLY_ALIVE notification received from "initialize" uCode. - * - * The 4965 "initialize" ALIVE reply contains calibration data for: - * Voltage, temperature, and MIMO tx gain correction, now stored in priv - * (3945 does not contain this data). - * - * Tell "initialize" uCode to go ahead and load the runtime uCode. -*/ -static void iwl4965_init_alive_start(struct iwl_priv *priv) -{ - /* Check alive response for "valid" sign from uCode */ - if (priv->card_alive_init.is_valid != UCODE_VALID_OK) { - /* We had an error bringing up the hardware, so take it - * all the way back down so we can try again */ - IWL_DEBUG_INFO("Initialize Alive failed.\n"); - goto restart; - } - - /* Bootstrap uCode has loaded initialize uCode ... verify inst image. - * This is a paranoid check, because we would not have gotten the - * "initialize" alive if code weren't properly loaded. */ - if (iwl4965_verify_ucode(priv)) { - /* Runtime instruction load was bad; - * take it all the way back down so we can try again */ - IWL_DEBUG_INFO("Bad \"initialize\" uCode load.\n"); - goto restart; - } - - /* Calculate temperature */ - priv->temperature = iwl4965_get_temperature(priv); - - /* Send pointers to protocol/runtime uCode image ... init code will - * load and launch runtime uCode, which will send us another "Alive" - * notification. */ - IWL_DEBUG_INFO("Initialization Alive received.\n"); - if (iwl4965_set_ucode_ptrs(priv)) { - /* Runtime instruction load won't happen; - * take it all the way back down so we can try again */ - IWL_DEBUG_INFO("Couldn't set up uCode pointers.\n"); - goto restart; - } - return; - - restart: - queue_work(priv->workqueue, &priv->restart); -} - - /** - * iwl4965_alive_start - called after REPLY_ALIVE notification received + * iwl_alive_start - called after REPLY_ALIVE notification received * from protocol/runtime uCode (initialization uCode's - * Alive gets handled by iwl4965_init_alive_start()). + * Alive gets handled by iwl_init_alive_start()). */ -static void iwl4965_alive_start(struct iwl_priv *priv) +static void iwl_alive_start(struct iwl_priv *priv) { int ret = 0; @@ -5331,15 +1972,14 @@ static void iwl4965_alive_start(struct iwl_priv *priv) /* Initialize uCode has loaded Runtime uCode ... verify inst image. * This is a paranoid check, because we would not have gotten the * "runtime" alive if code weren't properly loaded. */ - if (iwl4965_verify_ucode(priv)) { + if (iwl_verify_ucode(priv)) { /* Runtime instruction load was bad; * take it all the way back down so we can try again */ IWL_DEBUG_INFO("Bad runtime uCode load.\n"); goto restart; } - iwlcore_clear_stations_table(priv); - + iwl_clear_stations_table(priv); ret = priv->cfg->ops->lib->alive_notify(priv); if (ret) { IWL_WARNING("Could not complete ALIVE transition [ntf]: %d\n", @@ -5350,22 +1990,17 @@ static void iwl4965_alive_start(struct iwl_priv *priv) /* After the ALIVE response, we can send host commands to 4965 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; - ieee80211_start_queues(priv->hw); + ieee80211_wake_queues(priv->hw); priv->active_rate = priv->rates_mask; priv->active_rate_basic = priv->rates_mask & IWL_BASIC_RATES_MASK; - iwl4965_send_power_mode(priv, IWL_POWER_LEVEL(priv->power_mode)); - if (iwl_is_associated(priv)) { - struct iwl4965_rxon_cmd *active_rxon = - (struct iwl4965_rxon_cmd *)(&priv->active_rxon); + struct iwl_rxon_cmd *active_rxon = + (struct iwl_rxon_cmd *)&priv->active_rxon; memcpy(&priv->staging_rxon, &priv->active_rxon, sizeof(priv->staging_rxon)); @@ -5379,13 +2014,13 @@ static void iwl4965_alive_start(struct iwl_priv *priv) /* Configure Bluetooth device coexistence support */ iwl4965_send_bt_config(priv); + iwl_reset_run_time_calib(priv); + /* Configure the adapter for unassociated operation */ iwl4965_commit_rxon(priv); /* At this point, the NIC is initialized and operational */ - priv->notif_missed_beacons = 0; - - iwl4965_rf_kill_ct_config(priv); + iwl_rf_kill_ct_config(priv); iwl_leds_register(priv); @@ -5396,34 +2031,33 @@ static void iwl4965_alive_start(struct iwl_priv *priv) if (priv->error_recovering) iwl4965_error_recovery(priv); - iwlcore_low_level_notify(priv, IWLCORE_START_EVT); + iwl_power_update_mode(priv, 1); ieee80211_notify_mac(priv->hw, IEEE80211_NOTIFY_RE_ASSOC); + + if (test_and_clear_bit(STATUS_MODE_PENDING, &priv->status)) + iwl4965_set_mode(priv, priv->iw_mode); + return; restart: queue_work(priv->workqueue, &priv->restart); } -static void iwl4965_cancel_deferred_work(struct iwl_priv *priv); +static void iwl_cancel_deferred_work(struct iwl_priv *priv); static void __iwl4965_down(struct iwl_priv *priv) { unsigned long flags; int exit_pending = test_bit(STATUS_EXIT_PENDING, &priv->status); - struct ieee80211_conf *conf = NULL; IWL_DEBUG_INFO(DRV_NAME " is going down\n"); - conf = ieee80211_get_hw_conf(priv->hw); - if (!exit_pending) set_bit(STATUS_EXIT_PENDING, &priv->status); iwl_leds_unregister(priv); - iwlcore_low_level_notify(priv, IWLCORE_STOP_EVT); - - iwlcore_clear_stations_table(priv); + iwl_clear_stations_table(priv); /* Unblock any waiting calls */ wake_up_interruptible_all(&priv->wait_command_queue); @@ -5455,7 +2089,9 @@ static void __iwl4965_down(struct iwl_priv *priv) test_bit(STATUS_GEO_CONFIGURED, &priv->status) << STATUS_GEO_CONFIGURED | test_bit(STATUS_IN_SUSPEND, &priv->status) << - STATUS_IN_SUSPEND; + STATUS_IN_SUSPEND | + test_bit(STATUS_EXIT_PENDING, &priv->status) << + STATUS_EXIT_PENDING; goto exit; } @@ -5470,15 +2106,17 @@ static void __iwl4965_down(struct iwl_priv *priv) test_bit(STATUS_IN_SUSPEND, &priv->status) << STATUS_IN_SUSPEND | test_bit(STATUS_FW_ERROR, &priv->status) << - STATUS_FW_ERROR; + STATUS_FW_ERROR | + test_bit(STATUS_EXIT_PENDING, &priv->status) << + STATUS_EXIT_PENDING; spin_lock_irqsave(&priv->lock, flags); iwl_clear_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); spin_unlock_irqrestore(&priv->lock, flags); - iwl4965_hw_txq_ctx_stop(priv); - iwl4965_hw_rxq_stop(priv); + iwl_txq_ctx_stop(priv); + iwl_rxq_stop(priv); spin_lock_irqsave(&priv->lock, flags); if (!iwl_grab_nic_access(priv)) { @@ -5490,19 +2128,19 @@ static void __iwl4965_down(struct iwl_priv *priv) udelay(5); - iwl4965_hw_nic_stop_master(priv); - iwl_set_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET); - iwl4965_hw_nic_reset(priv); + /* FIXME: apm_ops.suspend(priv) */ + priv->cfg->ops->lib->apm_ops.reset(priv); + priv->cfg->ops->lib->free_shared_mem(priv); exit: - memset(&priv->card_alive, 0, sizeof(struct iwl4965_alive_resp)); + memset(&priv->card_alive, 0, sizeof(struct iwl_alive_resp)); if (priv->ibss_beacon) dev_kfree_skb(priv->ibss_beacon); priv->ibss_beacon = NULL; /* clear out any free frames */ - iwl4965_clear_free_frames(priv); + iwl_clear_free_frames(priv); } static void iwl4965_down(struct iwl_priv *priv) @@ -5511,7 +2149,7 @@ static void iwl4965_down(struct iwl_priv *priv) __iwl4965_down(priv); mutex_unlock(&priv->mutex); - iwl4965_cancel_deferred_work(priv); + iwl_cancel_deferred_work(priv); } #define MAX_HW_RESTARTS 5 @@ -5526,13 +2164,6 @@ static int __iwl4965_up(struct iwl_priv *priv) return -EIO; } - if (test_bit(STATUS_RF_KILL_SW, &priv->status)) { - IWL_WARNING("Radio disabled by SW RF kill (module " - "parameter)\n"); - iwl_rfkill_set_hw_state(priv); - return -ENODEV; - } - if (!priv->ucode_data_backup.v_addr || !priv->ucode_data.v_addr) { IWL_ERROR("ucode not available for device bringup\n"); return -EIO; @@ -5542,19 +2173,25 @@ static int __iwl4965_up(struct iwl_priv *priv) 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 { + else set_bit(STATUS_RF_KILL_HW, &priv->status); - if (!test_bit(STATUS_IN_SUSPEND, &priv->status)) { - iwl_rfkill_set_hw_state(priv); - IWL_WARNING("Radio disabled by HW RF Kill switch\n"); - return -ENODEV; - } + + if (!test_bit(STATUS_IN_SUSPEND, &priv->status) && + iwl_is_rfkill(priv)) { + IWL_WARNING("Radio disabled by %s RF Kill switch\n", + test_bit(STATUS_RF_KILL_HW, &priv->status) ? "HW" : "SW"); + return -ENODEV; } - iwl_rfkill_set_hw_state(priv); iwl_write32(priv, CSR_INT, 0xFFFFFFFF); - ret = priv->cfg->ops->lib->hw_nic_init(priv); + ret = priv->cfg->ops->lib->alloc_shared_mem(priv); + if (ret) { + IWL_ERROR("Unable to allocate shared memory\n"); + return ret; + } + + ret = iwl_hw_nic_init(priv); if (ret) { IWL_ERROR("Unable to init nic\n"); return ret; @@ -5580,12 +2217,13 @@ static int __iwl4965_up(struct iwl_priv *priv) priv->ucode_data.len); /* We return success when we resume from suspend and rf_kill is on. */ - if (test_bit(STATUS_RF_KILL_HW, &priv->status)) + if (test_bit(STATUS_RF_KILL_HW, &priv->status) || + test_bit(STATUS_RF_KILL_SW, &priv->status)) return 0; for (i = 0; i < MAX_HW_RESTARTS; i++) { - iwlcore_clear_stations_table(priv); + iwl_clear_stations_table(priv); /* load bootstrap state machine, * load bootstrap program into processor's memory, @@ -5597,6 +2235,9 @@ static int __iwl4965_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 */ iwl4965_nic_start(priv); @@ -5607,6 +2248,7 @@ static int __iwl4965_up(struct iwl_priv *priv) set_bit(STATUS_EXIT_PENDING, &priv->status); __iwl4965_down(priv); + clear_bit(STATUS_EXIT_PENDING, &priv->status); /* tried to restart and config the device for as long as our * patience could withstand */ @@ -5621,7 +2263,7 @@ static int __iwl4965_up(struct iwl_priv *priv) * *****************************************************************************/ -static void iwl4965_bg_init_alive_start(struct work_struct *data) +static void iwl_bg_init_alive_start(struct work_struct *data) { struct iwl_priv *priv = container_of(data, struct iwl_priv, init_alive_start.work); @@ -5630,11 +2272,11 @@ static void iwl4965_bg_init_alive_start(struct work_struct *data) return; mutex_lock(&priv->mutex); - iwl4965_init_alive_start(priv); + priv->cfg->ops->lib->init_alive_start(priv); mutex_unlock(&priv->mutex); } -static void iwl4965_bg_alive_start(struct work_struct *data) +static void iwl_bg_alive_start(struct work_struct *data) { struct iwl_priv *priv = container_of(data, struct iwl_priv, alive_start.work); @@ -5643,7 +2285,7 @@ static void iwl4965_bg_alive_start(struct work_struct *data) return; mutex_lock(&priv->mutex); - iwl4965_alive_start(priv); + iwl_alive_start(priv); mutex_unlock(&priv->mutex); } @@ -5659,7 +2301,7 @@ static void iwl4965_bg_rf_kill(struct work_struct *work) mutex_lock(&priv->mutex); if (!iwl_is_rfkill(priv)) { - IWL_DEBUG(IWL_DL_INFO | IWL_DL_RF_KILL, + IWL_DEBUG(IWL_DL_RF_KILL, "HW and/or SW RF Kill no longer active, restarting " "device\n"); if (!test_bit(STATUS_EXIT_PENDING, &priv->status)) @@ -5677,239 +2319,53 @@ static void iwl4965_bg_rf_kill(struct work_struct *work) "Kill switch must be turned off for " "wireless networking to work.\n"); } - iwl_rfkill_set_hw_state(priv); - mutex_unlock(&priv->mutex); + iwl_rfkill_set_hw_state(priv); } -#define IWL_SCAN_CHECK_WATCHDOG (7 * HZ) - -static void iwl4965_bg_scan_check(struct work_struct *data) +static void iwl4965_bg_set_monitor(struct work_struct *work) { - struct iwl_priv *priv = - container_of(data, struct iwl_priv, scan_check.work); + struct iwl_priv *priv = container_of(work, + struct iwl_priv, set_monitor); + int ret; - if (test_bit(STATUS_EXIT_PENDING, &priv->status)) - return; + IWL_DEBUG(IWL_DL_STATE, "setting monitor mode\n"); mutex_lock(&priv->mutex); - if (test_bit(STATUS_SCANNING, &priv->status) || - test_bit(STATUS_SCAN_ABORTING, &priv->status)) { - IWL_DEBUG(IWL_DL_INFO | IWL_DL_SCAN, - "Scan completion watchdog resetting adapter (%dms)\n", - jiffies_to_msecs(IWL_SCAN_CHECK_WATCHDOG)); - if (!test_bit(STATUS_EXIT_PENDING, &priv->status)) - iwl4965_send_scan_abort(priv); + ret = iwl4965_set_mode(priv, IEEE80211_IF_TYPE_MNTR); + + if (ret) { + if (ret == -EAGAIN) + IWL_DEBUG(IWL_DL_STATE, "leave - not ready\n"); + else + IWL_ERROR("iwl4965_set_mode() failed ret = %d\n", ret); } + mutex_unlock(&priv->mutex); } -static void iwl4965_bg_request_scan(struct work_struct *data) +static void iwl_bg_run_time_calib_work(struct work_struct *work) { - struct iwl_priv *priv = - container_of(data, struct iwl_priv, request_scan); - struct iwl_host_cmd cmd = { - .id = REPLY_SCAN_CMD, - .len = sizeof(struct iwl4965_scan_cmd), - .meta.flags = CMD_SIZE_HUGE, - }; - struct iwl4965_scan_cmd *scan; - struct ieee80211_conf *conf = NULL; - u16 cmd_len; - enum ieee80211_band band; - u8 direct_mask; - int ret = 0; - - conf = ieee80211_get_hw_conf(priv->hw); + struct iwl_priv *priv = container_of(work, struct iwl_priv, + run_time_calib_work); mutex_lock(&priv->mutex); - if (!iwl_is_ready(priv)) { - IWL_WARNING("request scan called when driver not ready.\n"); - goto done; - } - - /* Make sure the scan wasn't cancelled before this queued work - * was given the chance to run... */ - if (!test_bit(STATUS_SCANNING, &priv->status)) - goto done; - - /* This should never be called or scheduled if there is currently - * a scan active in the hardware. */ - if (test_bit(STATUS_SCAN_HW, &priv->status)) { - IWL_DEBUG_INFO("Multiple concurrent scan requests in parallel. " - "Ignoring second request.\n"); - ret = -EIO; - goto done; - } - - if (test_bit(STATUS_EXIT_PENDING, &priv->status)) { - IWL_DEBUG_SCAN("Aborting scan due to device shutdown\n"); - goto done; - } - - if (test_bit(STATUS_SCAN_ABORTING, &priv->status)) { - IWL_DEBUG_HC("Scan request while abort pending. Queuing.\n"); - goto done; - } - - if (iwl_is_rfkill(priv)) { - IWL_DEBUG_HC("Aborting scan due to RF Kill activation\n"); - goto done; - } - - if (!test_bit(STATUS_READY, &priv->status)) { - IWL_DEBUG_HC("Scan request while uninitialized. Queuing.\n"); - goto done; - } - - if (!priv->scan_bands) { - IWL_DEBUG_HC("Aborting scan due to no requested bands\n"); - goto done; - } - - if (!priv->scan) { - priv->scan = kmalloc(sizeof(struct iwl4965_scan_cmd) + - IWL_MAX_SCAN_SIZE, GFP_KERNEL); - if (!priv->scan) { - ret = -ENOMEM; - goto done; - } + if (test_bit(STATUS_EXIT_PENDING, &priv->status) || + test_bit(STATUS_SCANNING, &priv->status)) { + mutex_unlock(&priv->mutex); + return; } - scan = priv->scan; - memset(scan, 0, sizeof(struct iwl4965_scan_cmd) + IWL_MAX_SCAN_SIZE); - scan->quiet_plcp_th = IWL_PLCP_QUIET_THRESH; - scan->quiet_time = IWL_ACTIVE_QUIET_TIME; + if (priv->start_calib) { + iwl_chain_noise_calibration(priv, &priv->statistics); - if (iwl_is_associated(priv)) { - u16 interval = 0; - u32 extra; - u32 suspend_time = 100; - u32 scan_suspend_time = 100; - unsigned long flags; - - IWL_DEBUG_INFO("Scanning while associated...\n"); - - spin_lock_irqsave(&priv->lock, flags); - interval = priv->beacon_int; - spin_unlock_irqrestore(&priv->lock, flags); - - scan->suspend_time = 0; - scan->max_out_time = cpu_to_le32(200 * 1024); - if (!interval) - interval = suspend_time; - - extra = (suspend_time / interval) << 22; - scan_suspend_time = (extra | - ((suspend_time % interval) * 1024)); - scan->suspend_time = cpu_to_le32(scan_suspend_time); - IWL_DEBUG_SCAN("suspend_time 0x%X beacon interval %d\n", - scan_suspend_time, interval); - } - - /* We should add the ability for user to lock to PASSIVE ONLY */ - if (priv->one_direct_scan) { - IWL_DEBUG_SCAN - ("Kicking off one direct scan for '%s'\n", - iwl4965_escape_essid(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); - direct_mask = 1; - } else if (!iwl_is_associated(priv) && priv->essid_len) { - IWL_DEBUG_SCAN - ("Kicking off one direct scan for '%s' when not associated\n", - iwl4965_escape_essid(priv->essid, priv->essid_len)); - scan->direct_scan[0].id = WLAN_EID_SSID; - scan->direct_scan[0].len = priv->essid_len; - memcpy(scan->direct_scan[0].ssid, priv->essid, priv->essid_len); - direct_mask = 1; - } else { - IWL_DEBUG_SCAN("Kicking off one indirect scan.\n"); - direct_mask = 0; + iwl_sensitivity_calibration(priv, &priv->statistics); } - scan->tx_cmd.tx_flags = TX_CMD_FLG_SEQ_CTL_MSK; - scan->tx_cmd.sta_id = priv->hw_params.bcast_sta_id; - scan->tx_cmd.stop_time.life_time = TX_CMD_LIFE_TIME_INFINITE; - - - if (priv->scan_bands & BIT(IEEE80211_BAND_2GHZ)) { - scan->flags = RXON_FLG_BAND_24G_MSK | RXON_FLG_AUTO_DETECT_MSK; - scan->tx_cmd.rate_n_flags = - iwl4965_hw_set_rate_n_flags(IWL_RATE_1M_PLCP, - RATE_MCS_ANT_B_MSK|RATE_MCS_CCK_MSK); - - scan->good_CRC_th = 0; - band = IEEE80211_BAND_2GHZ; - } else if (priv->scan_bands & BIT(IEEE80211_BAND_5GHZ)) { - scan->tx_cmd.rate_n_flags = - iwl4965_hw_set_rate_n_flags(IWL_RATE_6M_PLCP, - RATE_MCS_ANT_B_MSK); - scan->good_CRC_th = IWL_GOOD_CRC_TH; - band = IEEE80211_BAND_5GHZ; - } else { - IWL_WARNING("Invalid scan band count\n"); - goto done; - } - - /* We don't build a direct scan probe request; the uCode will do - * that based on the direct_mask added to each channel entry */ - cmd_len = iwl4965_fill_probe_req(priv, band, - (struct ieee80211_mgmt *)scan->data, - IWL_MAX_SCAN_SIZE - sizeof(*scan), 0); - - scan->tx_cmd.len = cpu_to_le16(cmd_len); - /* select Rx chains */ - - /* Force use of chains B and C (0x6) for scan Rx. - * Avoid A (0x1) because of its off-channel reception on A-band. - * MIMO is not used here, but value is required to make uCode happy. */ - scan->rx_chain = RXON_RX_CHAIN_DRIVER_FORCE_MSK | - cpu_to_le16((0x7 << RXON_RX_CHAIN_VALID_POS) | - (0x6 << RXON_RX_CHAIN_FORCE_SEL_POS) | - (0x7 << RXON_RX_CHAIN_FORCE_MIMO_SEL_POS)); - - if (priv->iw_mode == IEEE80211_IF_TYPE_MNTR) - scan->filter_flags = RXON_FILTER_PROMISC_MSK; - - if (direct_mask) - scan->channel_count = - iwl4965_get_channels_for_scan( - priv, band, 1, /* active */ - direct_mask, - (void *)&scan->data[le16_to_cpu(scan->tx_cmd.len)]); - else - scan->channel_count = - iwl4965_get_channels_for_scan( - priv, band, 0, /* passive */ - direct_mask, - (void *)&scan->data[le16_to_cpu(scan->tx_cmd.len)]); - - cmd.len += le16_to_cpu(scan->tx_cmd.len) + - scan->channel_count * sizeof(struct iwl4965_scan_channel); - cmd.data = scan; - scan->len = cpu_to_le16(cmd.len); - - set_bit(STATUS_SCAN_HW, &priv->status); - ret = iwl_send_cmd_sync(priv, &cmd); - if (ret) - goto done; - - queue_delayed_work(priv->workqueue, &priv->scan_check, - IWL_SCAN_CHECK_WATCHDOG); - mutex_unlock(&priv->mutex); return; - - done: - /* inform mac80211 scan aborted */ - queue_work(priv->workqueue, &priv->scan_completed); - mutex_unlock(&priv->mutex); } static void iwl4965_bg_up(struct work_struct *data) @@ -5922,6 +2378,7 @@ static void iwl4965_bg_up(struct work_struct *data) mutex_lock(&priv->mutex); __iwl4965_up(priv); mutex_unlock(&priv->mutex); + iwl_rfkill_set_hw_state(priv); } static void iwl4965_bg_restart(struct work_struct *data) @@ -5944,7 +2401,7 @@ static void iwl4965_bg_rx_replenish(struct work_struct *data) return; mutex_lock(&priv->mutex); - iwl4965_rx_replenish(priv); + iwl_rx_replenish(priv); mutex_unlock(&priv->mutex); } @@ -5955,6 +2412,7 @@ static void iwl4965_post_associate(struct iwl_priv *priv) struct ieee80211_conf *conf = NULL; int ret = 0; DECLARE_MAC_BUF(mac); + unsigned long flags; if (priv->iw_mode == IEEE80211_IF_TYPE_AP) { IWL_ERROR("%s Should not be called in AP mode\n", __FUNCTION__); @@ -5973,7 +2431,7 @@ static void iwl4965_post_associate(struct iwl_priv *priv) if (!priv->vif || !priv->is_open) return; - iwl4965_scan_cancel_timeout(priv, 200); + iwl_scan_cancel_timeout(priv, 200); conf = ieee80211_get_hw_conf(priv->hw); @@ -5990,11 +2448,10 @@ static void iwl4965_post_associate(struct iwl_priv *priv) priv->staging_rxon.filter_flags |= RXON_FILTER_ASSOC_MSK; -#ifdef CONFIG_IWL4965_HT if (priv->current_ht_config.is_ht) - iwl4965_set_rxon_ht(priv, &priv->current_ht_config); -#endif /* CONFIG_IWL4965_HT*/ - iwl4965_set_rxon_chain(priv); + iwl_set_rxon_ht(priv, &priv->current_ht_config); + + iwl_set_rxon_chain(priv); priv->staging_rxon.assoc_id = cpu_to_le16(priv->assoc_id); IWL_DEBUG_ASSOC("assoc id %d beacon interval %d\n", @@ -6020,17 +2477,14 @@ static void iwl4965_post_associate(struct iwl_priv *priv) switch (priv->iw_mode) { case IEEE80211_IF_TYPE_STA: - iwl4965_rate_scale_init(priv->hw, IWL_AP_ID); break; case IEEE80211_IF_TYPE_IBSS: - /* clear out the station table */ - iwlcore_clear_stations_table(priv); + /* assume default assoc id */ + priv->assoc_id = 1; - iwl4965_rxon_add_station(priv, iwl4965_broadcast_addr, 0); - iwl4965_rxon_add_station(priv, priv->bssid, 0); - iwl4965_rate_scale_init(priv->hw, IWL_STA_ID); + iwl_rxon_add_station(priv, priv->bssid, 0); iwl4965_send_beacon_cmd(priv); break; @@ -6041,58 +2495,30 @@ static void iwl4965_post_associate(struct iwl_priv *priv) break; } - iwl4965_sequence_reset(priv); - -#ifdef CONFIG_IWL4965_SENSITIVITY /* Enable Rx differential gain and sensitivity calibrations */ - iwl4965_chain_noise_reset(priv); + iwl_chain_noise_reset(priv); priv->start_calib = 1; -#endif /* CONFIG_IWL4965_SENSITIVITY */ if (priv->iw_mode == IEEE80211_IF_TYPE_IBSS) priv->assoc_station_added = 1; - iwl4965_activate_qos(priv, 0); + spin_lock_irqsave(&priv->lock, flags); + iwl_activate_qos(priv, 0); + spin_unlock_irqrestore(&priv->lock, flags); + iwl_power_update_mode(priv, 0); /* we have just associated, don't start scan too early */ priv->next_scan_jiffies = jiffies + IWL_DELAY_NEXT_SCAN; } - -static void iwl4965_bg_post_associate(struct work_struct *data) -{ - struct iwl_priv *priv = container_of(data, struct iwl_priv, - post_associate.work); - - mutex_lock(&priv->mutex); - iwl4965_post_associate(priv); - mutex_unlock(&priv->mutex); - -} - -static void iwl4965_bg_abort_scan(struct work_struct *work) -{ - struct iwl_priv *priv = container_of(work, struct iwl_priv, abort_scan); - - if (!iwl_is_ready(priv)) - return; - - mutex_lock(&priv->mutex); - - set_bit(STATUS_SCAN_ABORTING, &priv->status); - iwl4965_send_scan_abort(priv); - - mutex_unlock(&priv->mutex); -} - static int iwl4965_mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf); -static void iwl4965_bg_scan_completed(struct work_struct *work) +static void iwl_bg_scan_completed(struct work_struct *work) { struct iwl_priv *priv = container_of(work, struct iwl_priv, scan_completed); - IWL_DEBUG(IWL_DL_INFO | IWL_DL_SCAN, "SCAN complete scan\n"); + IWL_DEBUG_SCAN("SCAN complete scan\n"); if (test_bit(STATUS_EXIT_PENDING, &priv->status)) return; @@ -6105,7 +2531,7 @@ static void iwl4965_bg_scan_completed(struct work_struct *work) /* Since setting the TXPOWER may have been deferred while * performing the scan, fire one off */ mutex_lock(&priv->mutex); - iwl4965_hw_reg_send_txpower(priv); + iwl_set_tx_power(priv, priv->tx_power_user_lmt, true); mutex_unlock(&priv->mutex); } @@ -6115,7 +2541,7 @@ static void iwl4965_bg_scan_completed(struct work_struct *work) * *****************************************************************************/ -#define UCODE_READY_TIMEOUT (2 * HZ) +#define UCODE_READY_TIMEOUT (4 * HZ) static int iwl4965_mac_start(struct ieee80211_hw *hw) { @@ -6141,7 +2567,7 @@ static int iwl4965_mac_start(struct ieee80211_hw *hw) /* we should be verifying the device is ready to be opened */ mutex_lock(&priv->mutex); - memset(&priv->staging_rxon, 0, sizeof(struct iwl4965_rxon_cmd)); + memset(&priv->staging_rxon, 0, sizeof(struct iwl_rxon_cmd)); /* fetch ucode file from disk, alloc and copy to bus-master buffers ... * ucode filename and max sizes are card-specific. */ @@ -6158,6 +2584,8 @@ static int iwl4965_mac_start(struct ieee80211_hw *hw) mutex_unlock(&priv->mutex); + iwl_rfkill_set_hw_state(priv); + if (ret) goto out_release_irq; @@ -6166,15 +2594,15 @@ static int iwl4965_mac_start(struct ieee80211_hw *hw) if (test_bit(STATUS_IN_SUSPEND, &priv->status)) return 0; - /* Wait for START_ALIVE from ucode. Otherwise callbacks from + /* 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, test_bit(STATUS_READY, &priv->status), UCODE_READY_TIMEOUT); if (!ret) { if (!test_bit(STATUS_READY, &priv->status)) { - IWL_ERROR("Wait for START_ALIVE timeout after %dms.\n", - jiffies_to_msecs(UCODE_READY_TIMEOUT)); + IWL_ERROR("START_ALIVE timeout after %dms.\n", + jiffies_to_msecs(UCODE_READY_TIMEOUT)); ret = -ETIMEDOUT; goto out_release_irq; } @@ -6212,8 +2640,7 @@ static void iwl4965_mac_stop(struct ieee80211_hw *hw) * RXON_FILTER_ASSOC_MSK BIT */ mutex_lock(&priv->mutex); - iwl4965_scan_cancel_timeout(priv, 100); - cancel_delayed_work(&priv->post_associate); + iwl_scan_cancel_timeout(priv, 100); mutex_unlock(&priv->mutex); } @@ -6228,8 +2655,7 @@ static void iwl4965_mac_stop(struct ieee80211_hw *hw) IWL_DEBUG_MAC80211("leave\n"); } -static int iwl4965_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb, - struct ieee80211_tx_control *ctl) +static int iwl4965_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb) { struct iwl_priv *priv = hw->priv; @@ -6242,9 +2668,9 @@ static int iwl4965_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb, } IWL_DEBUG_TX("dev->xmit(%d bytes) at rate 0x%02x\n", skb->len, - ctl->tx_rate->bitrate); + ieee80211_get_tx_rate(hw, IEEE80211_SKB_CB(skb))->bitrate); - if (iwl4965_tx_skb(priv, skb, ctl)) + if (iwl_tx_skb(priv, skb)) dev_kfree_skb_any(skb); IWL_DEBUG_MAC80211("leave\n"); @@ -6277,8 +2703,9 @@ static int iwl4965_mac_add_interface(struct ieee80211_hw *hw, memcpy(priv->mac_addr, conf->mac_addr, ETH_ALEN); } - if (iwl_is_ready(priv)) - iwl4965_set_mode(priv, conf->type); + if (iwl4965_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); @@ -6299,12 +2726,21 @@ static int iwl4965_mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *co const struct iwl_channel_info *ch_info; unsigned long flags; int ret = 0; + u16 channel; mutex_lock(&priv->mutex); IWL_DEBUG_MAC80211("enter to channel %d\n", conf->channel->hw_value); priv->add_radiotap = !!(conf->flags & IEEE80211_CONF_RADIOTAP); + if (conf->radio_enabled && iwl_radio_kill_sw_enable_radio(priv)) { + IWL_DEBUG_MAC80211("leave - RF-KILL - waiting for uCode\n"); + goto out; + } + + if (!conf->radio_enabled) + iwl_radio_kill_sw_disable_radio(priv); + if (!iwl_is_ready(priv)) { IWL_DEBUG_MAC80211("leave - not ready\n"); ret = -EIO; @@ -6319,33 +2755,37 @@ static int iwl4965_mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *co return 0; } - spin_lock_irqsave(&priv->lock, flags); - - ch_info = iwl_get_channel_info(priv, conf->channel->band, - ieee80211_frequency_to_channel(conf->channel->center_freq)); + channel = ieee80211_frequency_to_channel(conf->channel->center_freq); + ch_info = iwl_get_channel_info(priv, conf->channel->band, channel); if (!is_channel_valid(ch_info)) { IWL_DEBUG_MAC80211("leave - invalid channel\n"); - spin_unlock_irqrestore(&priv->lock, flags); ret = -EINVAL; goto out; } -#ifdef CONFIG_IWL4965_HT + if (priv->iw_mode == IEEE80211_IF_TYPE_IBSS && + !is_channel_ibss(ch_info)) { + IWL_ERROR("channel %d in band %d not IBSS channel\n", + conf->channel->hw_value, conf->channel->band); + ret = -EINVAL; + goto out; + } + + 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) != conf->channel->hw_value) + if ((le16_to_cpu(priv->staging_rxon.channel) != channel) #ifdef IEEE80211_CONF_CHANNEL_SWITCH && !(conf->flags & IEEE80211_CONF_CHANNEL_SWITCH) #endif ) priv->staging_rxon.flags = 0; -#endif /* CONFIG_IWL4965_HT */ - iwlcore_set_rxon_channel(priv, conf->channel->band, - ieee80211_frequency_to_channel(conf->channel->center_freq)); + iwl_set_rxon_channel(priv, conf->channel->band, channel); - iwl4965_set_flags_for_phymode(priv, conf->channel->band); + iwl_set_flags_for_band(priv, conf->channel->band); /* The list of supported rates and rate mask can be different * for each band; since the band may have changed, reset @@ -6361,9 +2801,6 @@ static int iwl4965_mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *co } #endif - if (priv->cfg->ops->lib->radio_kill_sw) - priv->cfg->ops->lib->radio_kill_sw(priv, !conf->radio_enabled); - if (!conf->radio_enabled) { IWL_DEBUG_MAC80211("leave - radio disabled\n"); goto out; @@ -6375,6 +2812,11 @@ static int iwl4965_mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *co goto out; } + IWL_DEBUG_MAC80211("TX Power old=%d new=%d\n", + priv->tx_power_user_lmt, conf->power_level); + + iwl_set_tx_power(priv, conf->power_level, false); + iwl4965_set_rate(priv); if (memcmp(&priv->active_rxon, @@ -6394,12 +2836,13 @@ out: static void iwl4965_config_ap(struct iwl_priv *priv) { int ret = 0; + unsigned long flags; if (test_bit(STATUS_EXIT_PENDING, &priv->status)) return; /* The following should be done only at AP bring up */ - if ((priv->active_rxon.filter_flags & RXON_FILTER_ASSOC_MSK) == 0) { + if (!(iwl_is_associated(priv))) { /* RXON - unassoc (to set timing command) */ priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK; @@ -6414,7 +2857,7 @@ static void iwl4965_config_ap(struct iwl_priv *priv) IWL_WARNING("REPLY_RXON_TIMING failed - " "Attempting to continue.\n"); - iwl4965_set_rxon_chain(priv); + iwl_set_rxon_chain(priv); /* FIXME: what should be the assoc_id for AP? */ priv->staging_rxon.assoc_id = cpu_to_le16(priv->assoc_id); @@ -6441,8 +2884,10 @@ static void iwl4965_config_ap(struct iwl_priv *priv) /* restore RXON assoc */ priv->staging_rxon.filter_flags |= RXON_FILTER_ASSOC_MSK; iwl4965_commit_rxon(priv); - iwl4965_activate_qos(priv, 1); - iwl4965_rxon_add_station(priv, iwl4965_broadcast_addr, 0); + spin_lock_irqsave(&priv->lock, flags); + iwl_activate_qos(priv, 1); + spin_unlock_irqrestore(&priv->lock, flags); + iwl_rxon_add_station(priv, iwl_bcast_addr, 0); } iwl4965_send_beacon_cmd(priv); @@ -6451,6 +2896,9 @@ static void iwl4965_config_ap(struct iwl_priv *priv) * clear sta table, add BCAST sta... */ } +/* temporary */ +static int iwl4965_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb); + static int iwl4965_mac_config_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_if_conf *conf) @@ -6468,8 +2916,18 @@ static int iwl4965_mac_config_interface(struct ieee80211_hw *hw, return 0; } + if (priv->iw_mode == IEEE80211_IF_TYPE_IBSS && + conf->changed & IEEE80211_IFCC_BEACON) { + struct sk_buff *beacon = ieee80211_beacon_get(hw, vif); + if (!beacon) + return -ENOMEM; + rc = iwl4965_mac_beacon_update(hw, beacon); + if (rc) + return rc; + } + if ((priv->iw_mode == IEEE80211_IF_TYPE_AP) && - (!conf->beacon || !conf->ssid_len)) { + (!conf->ssid_len)) { IWL_DEBUG_MAC80211 ("Leaving in AP mode because HostAPD is not ready.\n"); return 0; @@ -6501,7 +2959,7 @@ static int iwl4965_mac_config_interface(struct ieee80211_hw *hw, if (priv->ibss_beacon) dev_kfree_skb(priv->ibss_beacon); - priv->ibss_beacon = conf->beacon; + priv->ibss_beacon = ieee80211_beacon_get(hw, vif); } if (iwl_is_rfkill(priv)) @@ -6511,7 +2969,7 @@ static int iwl4965_mac_config_interface(struct ieee80211_hw *hw, !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 (iwl4965_scan_cancel_timeout(priv, 100)) { + if (iwl_scan_cancel_timeout(priv, 100)) { IWL_WARNING("Aborted scan still in progress " "after 100ms\n"); IWL_DEBUG_MAC80211("leaving - scan abort failed.\n"); @@ -6531,12 +2989,12 @@ static int iwl4965_mac_config_interface(struct ieee80211_hw *hw, else { rc = iwl4965_commit_rxon(priv); if ((priv->iw_mode == IEEE80211_IF_TYPE_STA) && rc) - iwl4965_rxon_add_station( + iwl_rxon_add_station( priv, priv->active_rxon.bssid_addr, 1); } } else { - iwl4965_scan_cancel_timeout(priv, 100); + iwl_scan_cancel_timeout(priv, 100); priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK; iwl4965_commit_rxon(priv); } @@ -6562,11 +3020,18 @@ static void iwl4965_configure_filter(struct ieee80211_hw *hw, unsigned int *total_flags, int mc_count, struct dev_addr_list *mc_list) { - /* - * XXX: dummy - * see also iwl4965_connection_init_rx_config - */ - *total_flags = 0; + struct iwl_priv *priv = hw->priv; + + if (changed_flags & (*total_flags) & FIF_OTHER_BSS) { + IWL_DEBUG_MAC80211("Enter: type %d (0x%x, 0x%x)\n", + IEEE80211_IF_TYPE_MNTR, + changed_flags, *total_flags); + /* queue work 'cuz mac80211 is holding a lock which + * prevents us from issuing (synchronous) f/w cmds */ + queue_work(priv->workqueue, &priv->set_monitor); + } + *total_flags &= FIF_OTHER_BSS | FIF_ALLMULTI | + FIF_BCN_PRBRESP_PROMISC | FIF_CONTROL; } static void iwl4965_mac_remove_interface(struct ieee80211_hw *hw, @@ -6579,8 +3044,7 @@ static void iwl4965_mac_remove_interface(struct ieee80211_hw *hw, mutex_lock(&priv->mutex); if (iwl_is_ready_rf(priv)) { - iwl4965_scan_cancel_timeout(priv, 100); - cancel_delayed_work(&priv->post_associate); + iwl_scan_cancel_timeout(priv, 100); priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK; iwl4965_commit_rxon(priv); } @@ -6596,64 +3060,6 @@ static void iwl4965_mac_remove_interface(struct ieee80211_hw *hw, } - -#ifdef CONFIG_IWL4965_HT -static void iwl4965_ht_conf(struct iwl_priv *priv, - struct ieee80211_bss_conf *bss_conf) -{ - struct ieee80211_ht_info *ht_conf = bss_conf->ht_conf; - struct ieee80211_ht_bss_info *ht_bss_conf = bss_conf->ht_bss_conf; - struct iwl_ht_info *iwl_conf = &priv->current_ht_config; - - IWL_DEBUG_MAC80211("enter: \n"); - - iwl_conf->is_ht = bss_conf->assoc_ht; - - if (!iwl_conf->is_ht) - return; - - priv->ps_mode = (u8)((ht_conf->cap & IEEE80211_HT_CAP_MIMO_PS) >> 2); - - if (ht_conf->cap & IEEE80211_HT_CAP_SGI_20) - iwl_conf->sgf |= 0x1; - if (ht_conf->cap & IEEE80211_HT_CAP_SGI_40) - iwl_conf->sgf |= 0x2; - - 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); - iwl_conf->extension_chan_offset = - ht_bss_conf->bss_cap & IEEE80211_HT_IE_CHA_SEC_OFFSET; - /* If no above or below channel supplied disable FAT channel */ - if (iwl_conf->extension_chan_offset != IWL_EXT_CHANNEL_OFFSET_ABOVE && - iwl_conf->extension_chan_offset != IWL_EXT_CHANNEL_OFFSET_BELOW) - iwl_conf->supported_chan_width = 0; - - iwl_conf->tx_mimo_ps_mode = - (u8)((ht_conf->cap & IEEE80211_HT_CAP_MIMO_PS) >> 2); - memcpy(iwl_conf->supp_mcs_set, ht_conf->supp_mcs_set, 16); - - iwl_conf->control_channel = ht_bss_conf->primary_channel; - iwl_conf->tx_chan_width = - !!(ht_bss_conf->bss_cap & IEEE80211_HT_IE_CHA_WIDTH); - iwl_conf->ht_protection = - ht_bss_conf->bss_op_mode & IEEE80211_HT_IE_HT_PROTECTION; - iwl_conf->non_GF_STA_present = - !!(ht_bss_conf->bss_op_mode & IEEE80211_HT_IE_NON_GF_STA_PRSNT); - - IWL_DEBUG_MAC80211("control channel %d\n", iwl_conf->control_channel); - IWL_DEBUG_MAC80211("leave\n"); -} -#else -static inline void iwl4965_ht_conf(struct iwl_priv *priv, - struct ieee80211_bss_conf *bss_conf) -{ -} -#endif - #define IWL_DELAY_NEXT_SCAN_AFTER_ASSOC (HZ*6) static void iwl4965_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, @@ -6684,7 +3090,7 @@ static void iwl4965_bss_info_changed(struct ieee80211_hw *hw, if (changes & BSS_CHANGED_HT) { IWL_DEBUG_MAC80211("HT %d\n", bss_conf->assoc_ht); iwl4965_ht_conf(priv, bss_conf); - iwl4965_set_rxon_chain(priv); + iwl_set_rxon_chain(priv); } if (changes & BSS_CHANGED_ASSOC) { @@ -6751,7 +3157,7 @@ static int iwl4965_mac_hw_scan(struct ieee80211_hw *hw, u8 *ssid, size_t len) } if (len) { IWL_DEBUG_SCAN("direct scan for %s [%d]\n ", - iwl4965_escape_essid(ssid, len), (int)len); + iwl_escape_essid(ssid, len), (int)len); priv->one_direct_scan = 1; priv->direct_ssid_len = (u8) @@ -6760,7 +3166,7 @@ static int iwl4965_mac_hw_scan(struct ieee80211_hw *hw, u8 *ssid, size_t len) } else priv->one_direct_scan = 0; - rc = iwl4965_scan_initiate(priv); + rc = iwl_scan_initiate(priv); IWL_DEBUG_MAC80211("leave\n"); @@ -6784,14 +3190,14 @@ static void iwl4965_mac_update_tkip_key(struct ieee80211_hw *hw, IWL_DEBUG_MAC80211("enter\n"); - sta_id = iwl4965_hw_find_station(priv, addr); + sta_id = iwl_find_station(priv, addr); if (sta_id == IWL_INVALID_STATION) { IWL_DEBUG_MAC80211("leave - %s not in station map.\n", print_mac(mac, addr)); return; } - iwl4965_scan_cancel_timeout(priv, 100); + iwl_scan_cancel_timeout(priv, 100); key_flags |= (STA_KEY_FLG_TKIP | STA_KEY_FLG_MAP_KEY_MSK); key_flags |= cpu_to_le16(keyconf->keyidx << STA_KEY_FLG_KEYID_POS); @@ -6812,7 +3218,7 @@ static void iwl4965_mac_update_tkip_key(struct ieee80211_hw *hw, priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_KEY_MASK; priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK; - iwl4965_send_add_station(priv, &priv->stations[sta_id].sta, CMD_ASYNC); + iwl_send_add_sta(priv, &priv->stations[sta_id].sta, CMD_ASYNC); spin_unlock_irqrestore(&priv->sta_lock, flags); @@ -6831,7 +3237,7 @@ static int iwl4965_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, IWL_DEBUG_MAC80211("enter\n"); - if (priv->cfg->mod_params->sw_crypto) { + if (priv->hw_params.sw_crypto) { IWL_DEBUG_MAC80211("leave - hwcrypto disabled\n"); return -EOPNOTSUPP; } @@ -6840,7 +3246,7 @@ static int iwl4965_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, /* only support pairwise keys */ return -EOPNOTSUPP; - sta_id = iwl4965_hw_find_station(priv, addr); + sta_id = iwl_find_station(priv, addr); if (sta_id == IWL_INVALID_STATION) { IWL_DEBUG_MAC80211("leave - %s not in station map.\n", print_mac(mac, addr)); @@ -6849,7 +3255,7 @@ static int iwl4965_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, } mutex_lock(&priv->mutex); - iwl4965_scan_cancel_timeout(priv, 100); + iwl_scan_cancel_timeout(priv, 100); mutex_unlock(&priv->mutex); /* If we are getting WEP group key and we didn't receive any key mapping @@ -6861,7 +3267,8 @@ static int iwl4965_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, if (cmd == SET_KEY) is_default_wep_key = !priv->key_mapping_key; else - is_default_wep_key = priv->default_wep_key; + is_default_wep_key = + (key->hw_key_idx == HW_KEY_DEFAULT); } switch (cmd) { @@ -6877,7 +3284,7 @@ static int iwl4965_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, if (is_default_wep_key) ret = iwl_remove_default_wep_key(priv, key); else - ret = iwl_remove_dynamic_key(priv, sta_id); + ret = iwl_remove_dynamic_key(priv, key, sta_id); IWL_DEBUG_MAC80211("disable hwcrypto key\n"); break; @@ -6890,7 +3297,7 @@ static int iwl4965_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, return ret; } -static int iwl4965_mac_conf_tx(struct ieee80211_hw *hw, int queue, +static int iwl4965_mac_conf_tx(struct ieee80211_hw *hw, u16 queue, const struct ieee80211_tx_queue_params *params) { struct iwl_priv *priv = hw->priv; @@ -6927,15 +3334,12 @@ static int iwl4965_mac_conf_tx(struct ieee80211_hw *hw, int queue, 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 == IEEE80211_IF_TYPE_AP) - iwl4965_activate_qos(priv, 1); + iwl_activate_qos(priv, 1); else if (priv->assoc_id && iwl_is_associated(priv)) - iwl4965_activate_qos(priv, 0); + iwl_activate_qos(priv, 0); - mutex_unlock(&priv->mutex); + spin_unlock_irqrestore(&priv->lock, flags); IWL_DEBUG_MAC80211("leave\n"); return 0; @@ -6946,8 +3350,8 @@ static int iwl4965_mac_get_tx_stats(struct ieee80211_hw *hw, { struct iwl_priv *priv = hw->priv; int i, avail; - struct iwl4965_tx_queue *txq; - struct iwl4965_queue *q; + struct iwl_tx_queue *txq; + struct iwl_queue *q; unsigned long flags; IWL_DEBUG_MAC80211("enter\n"); @@ -6962,11 +3366,11 @@ static int iwl4965_mac_get_tx_stats(struct ieee80211_hw *hw, for (i = 0; i < AC_NUM; i++) { txq = &priv->txq[i]; q = &txq->q; - avail = iwl4965_queue_space(q); + avail = iwl_queue_space(q); - stats->data[i].len = q->n_window - avail; - stats->data[i].limit = q->n_window - q->high_mark; - stats->data[i].count = q->n_window; + 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); @@ -6979,14 +3383,9 @@ static int iwl4965_mac_get_tx_stats(struct ieee80211_hw *hw, static int iwl4965_mac_get_stats(struct ieee80211_hw *hw, struct ieee80211_low_level_stats *stats) { - IWL_DEBUG_MAC80211("enter\n"); - IWL_DEBUG_MAC80211("leave\n"); - - return 0; -} + struct iwl_priv *priv = hw->priv; -static u64 iwl4965_mac_get_tsf(struct ieee80211_hw *hw) -{ + priv = hw->priv; IWL_DEBUG_MAC80211("enter\n"); IWL_DEBUG_MAC80211("leave\n"); @@ -7001,16 +3400,11 @@ static void iwl4965_mac_reset_tsf(struct ieee80211_hw *hw) mutex_lock(&priv->mutex); IWL_DEBUG_MAC80211("enter\n"); - priv->lq_mngr.lq_ready = 0; -#ifdef CONFIG_IWL4965_HT spin_lock_irqsave(&priv->lock, flags); memset(&priv->current_ht_config, 0, sizeof(struct iwl_ht_info)); spin_unlock_irqrestore(&priv->lock, flags); -#endif /* CONFIG_IWL4965_HT */ - - iwlcore_reset_qos(priv); - cancel_delayed_work(&priv->post_associate); + iwl_reset_qos(priv); spin_lock_irqsave(&priv->lock, flags); priv->assoc_id = 0; @@ -7040,11 +3434,13 @@ static void iwl4965_mac_reset_tsf(struct ieee80211_hw *hw) * clear RXON_FILTER_ASSOC_MSK bit */ if (priv->iw_mode != IEEE80211_IF_TYPE_AP) { - iwl4965_scan_cancel_timeout(priv, 100); + iwl_scan_cancel_timeout(priv, 100); priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK; iwl4965_commit_rxon(priv); } + iwl_power_update_mode(priv, 0); + /* Per mac80211.h: This is only used in IBSS mode... */ if (priv->iw_mode != IEEE80211_IF_TYPE_IBSS) { @@ -7060,11 +3456,11 @@ static void iwl4965_mac_reset_tsf(struct ieee80211_hw *hw) IWL_DEBUG_MAC80211("leave\n"); } -static int iwl4965_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb, - struct ieee80211_tx_control *control) +static int iwl4965_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb) { struct iwl_priv *priv = hw->priv; unsigned long flags; + __le64 timestamp; mutex_lock(&priv->mutex); IWL_DEBUG_MAC80211("enter\n"); @@ -7089,13 +3485,15 @@ static int iwl4965_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *sk priv->ibss_beacon = skb; priv->assoc_id = 0; + timestamp = ((struct ieee80211_mgmt *)skb->data)->u.beacon.timestamp; + priv->timestamp = le64_to_cpu(timestamp) + (priv->beacon_int * 1000); IWL_DEBUG_MAC80211("leave\n"); spin_unlock_irqrestore(&priv->lock, flags); - iwlcore_reset_qos(priv); + iwl_reset_qos(priv); - queue_work(priv->workqueue, &priv->post_associate.work); + iwl4965_post_associate(priv); mutex_unlock(&priv->mutex); @@ -7118,13 +3516,18 @@ static int iwl4965_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *sk * See the level definitions in iwl for details. */ -static ssize_t show_debug_level(struct device_driver *d, char *buf) +static ssize_t show_debug_level(struct device *d, + struct device_attribute *attr, char *buf) { - return sprintf(buf, "0x%08X\n", iwl_debug_level); + struct iwl_priv *priv = d->driver_data; + + return sprintf(buf, "0x%08X\n", priv->debug_level); } -static ssize_t store_debug_level(struct device_driver *d, +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; char *p = (char *)buf; u32 val; @@ -7133,17 +3536,49 @@ static ssize_t store_debug_level(struct device_driver *d, printk(KERN_INFO DRV_NAME ": %s is not in hex or decimal form.\n", buf); else - iwl_debug_level = val; + priv->debug_level = val; return strnlen(buf, count); } -static DRIVER_ATTR(debug_level, S_IWUSR | S_IRUGO, - show_debug_level, store_debug_level); +static DEVICE_ATTR(debug_level, S_IWUSR | S_IRUGO, + show_debug_level, store_debug_level); + #endif /* CONFIG_IWLWIFI_DEBUG */ +static ssize_t show_version(struct device *d, + struct device_attribute *attr, char *buf) +{ + struct iwl_priv *priv = d->driver_data; + struct iwl_alive_resp *palive = &priv->card_alive; + ssize_t pos = 0; + u16 eeprom_ver; + + if (palive->is_valid) + pos += sprintf(buf + pos, + "fw version: 0x%01X.0x%01X.0x%01X.0x%01X\n" + "fw type: 0x%01X 0x%01X\n", + palive->ucode_major, palive->ucode_minor, + palive->sw_rev[0], palive->sw_rev[1], + palive->ver_type, palive->ver_subtype); + else + pos += sprintf(buf + pos, "fw not loaded\n"); + + if (priv->eeprom) { + eeprom_ver = iwl_eeprom_query16(priv, EEPROM_VERSION); + pos += sprintf(buf + pos, "EEPROM version: 0x%x\n", + eeprom_ver); + } else { + pos += sprintf(buf + pos, "EEPROM not initialzed\n"); + } + + return pos; +} + +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) { @@ -7152,7 +3587,7 @@ static ssize_t show_temperature(struct device *d, if (!iwl_is_alive(priv)) return -EAGAIN; - return sprintf(buf, "%d\n", iwl4965_hw_get_temperature(priv)); + return sprintf(buf, "%d\n", priv->temperature); } static DEVICE_ATTR(temperature, S_IRUGO, show_temperature, NULL); @@ -7170,7 +3605,7 @@ 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; - return sprintf(buf, "%d\n", priv->user_txpower_limit); + return sprintf(buf, "%d\n", priv->tx_power_user_lmt); } static ssize_t store_tx_power(struct device *d, @@ -7186,7 +3621,7 @@ static ssize_t store_tx_power(struct device *d, printk(KERN_INFO DRV_NAME ": %s is not in decimal form.\n", buf); else - iwl4965_hw_reg_set_txpower(priv, val); + iwl_set_tx_power(priv, val, false); return count; } @@ -7211,7 +3646,7 @@ static ssize_t store_flags(struct device *d, mutex_lock(&priv->mutex); if (le32_to_cpu(priv->staging_rxon.flags) != flags) { /* Cancel any currently running scans... */ - if (iwl4965_scan_cancel_timeout(priv, 100)) + if (iwl_scan_cancel_timeout(priv, 100)) IWL_WARNING("Could not cancel scan.\n"); else { IWL_DEBUG_INFO("Committing rxon.flags = 0x%04X\n", @@ -7246,7 +3681,7 @@ static ssize_t store_filter_flags(struct device *d, mutex_lock(&priv->mutex); if (le32_to_cpu(priv->staging_rxon.filter_flags) != filter_flags) { /* Cancel any currently running scans... */ - if (iwl4965_scan_cancel_timeout(priv, 100)) + if (iwl_scan_cancel_timeout(priv, 100)) IWL_WARNING("Could not cancel scan.\n"); else { IWL_DEBUG_INFO("Committing rxon.filter_flags = " @@ -7376,20 +3811,11 @@ static ssize_t store_power_level(struct device *d, goto out; } - if ((mode < 1) || (mode > IWL_POWER_LIMIT) || (mode == IWL_POWER_AC)) - mode = IWL_POWER_AC; - else - mode |= IWL_POWER_ENABLED; - - if (mode != priv->power_mode) { - rc = iwl4965_send_power_mode(priv, IWL_POWER_LEVEL(mode)); - if (rc) { - IWL_DEBUG_MAC80211("failed setting power mode.\n"); - goto out; - } - priv->power_mode = mode; + rc = iwl_power_set_user_mode(priv, mode); + if (rc) { + IWL_DEBUG_MAC80211("failed setting power mode.\n"); + goto out; } - rc = count; out: @@ -7419,7 +3845,7 @@ static ssize_t show_power_level(struct device *d, struct device_attribute *attr, char *buf) { struct iwl_priv *priv = dev_get_drvdata(d); - int level = IWL_POWER_LEVEL(priv->power_mode); + int level = priv->power_data.power_mode; char *p = buf; p += sprintf(p, "%d ", level); @@ -7437,14 +3863,14 @@ static ssize_t show_power_level(struct device *d, timeout_duration[level - 1] / 1000, period_duration[level - 1] / 1000); } - +/* if (!(priv->power_mode & IWL_POWER_ENABLED)) p += sprintf(p, " OFF\n"); else p += sprintf(p, " \n"); - +*/ + p += sprintf(p, " \n"); return (p - buf + 1); - } static DEVICE_ATTR(power_level, S_IWUSR | S_IRUSR, show_power_level, @@ -7453,8 +3879,62 @@ static DEVICE_ATTR(power_level, S_IWUSR | S_IRUSR, show_power_level, static ssize_t show_channels(struct device *d, struct device_attribute *attr, char *buf) { - /* all this shit doesn't belong into sysfs anyway */ - return 0; + + struct iwl_priv *priv = dev_get_drvdata(d); + struct ieee80211_channel *channels = NULL; + const struct ieee80211_supported_band *supp_band = NULL; + int len = 0, i; + int count = 0; + + if (!test_bit(STATUS_GEO_CONFIGURED, &priv->status)) + return -EAGAIN; + + supp_band = iwl_get_hw_mode(priv, IEEE80211_BAND_2GHZ); + channels = supp_band->channels; + count = supp_band->n_channels; + + len += sprintf(&buf[len], + "Displaying %d channels in 2.4GHz band " + "(802.11bg):\n", count); + + for (i = 0; i < count; i++) + len += sprintf(&buf[len], "%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; + count = supp_band->n_channels; + + len += sprintf(&buf[len], "Displaying %d channels in 5.2GHz band " + "(802.11a):\n", count); + + for (i = 0; i < count; i++) + len += sprintf(&buf[len], "%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"); + + return len; } static DEVICE_ATTR(channels, S_IRUSR, show_channels, NULL); @@ -7463,7 +3943,7 @@ static ssize_t show_statistics(struct device *d, struct device_attribute *attr, char *buf) { struct iwl_priv *priv = dev_get_drvdata(d); - u32 size = sizeof(struct iwl4965_notif_statistics); + u32 size = sizeof(struct iwl_notif_statistics); u32 len = 0, ofs = 0; u8 *data = (u8 *) & priv->statistics; int rc = 0; @@ -7497,44 +3977,6 @@ static ssize_t show_statistics(struct device *d, static DEVICE_ATTR(statistics, S_IRUGO, show_statistics, NULL); -static ssize_t show_antenna(struct device *d, - struct device_attribute *attr, char *buf) -{ - struct iwl_priv *priv = dev_get_drvdata(d); - - if (!iwl_is_alive(priv)) - return -EAGAIN; - - return sprintf(buf, "%d\n", priv->antenna); -} - -static ssize_t store_antenna(struct device *d, - struct device_attribute *attr, - const char *buf, size_t count) -{ - int ant; - struct iwl_priv *priv = dev_get_drvdata(d); - - if (count == 0) - return 0; - - if (sscanf(buf, "%1i", &ant) != 1) { - IWL_DEBUG_INFO("not in hex or decimal form.\n"); - return count; - } - - if ((ant >= 0) && (ant <= 2)) { - IWL_DEBUG_INFO("Setting antenna select to %d.\n", ant); - priv->antenna = (enum iwl4965_antenna)ant; - } else - IWL_DEBUG_INFO("Bad antenna select value %d.\n", ant); - - - return count; -} - -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) { @@ -7546,41 +3988,13 @@ static ssize_t show_status(struct device *d, static DEVICE_ATTR(status, S_IRUGO, show_status, NULL); -static ssize_t dump_error_log(struct device *d, - struct device_attribute *attr, - const char *buf, size_t count) -{ - char *p = (char *)buf; - - if (p[0] == '1') - iwl4965_dump_nic_error_log((struct iwl_priv *)d->driver_data); - - return strnlen(buf, count); -} - -static DEVICE_ATTR(dump_errors, S_IWUSR, NULL, dump_error_log); - -static ssize_t dump_event_log(struct device *d, - struct device_attribute *attr, - const char *buf, size_t count) -{ - char *p = (char *)buf; - - if (p[0] == '1') - iwl4965_dump_nic_event_log((struct iwl_priv *)d->driver_data); - - return strnlen(buf, count); -} - -static DEVICE_ATTR(dump_events, S_IWUSR, NULL, dump_event_log); - /***************************************************************************** * * driver setup and teardown * *****************************************************************************/ -static void iwl4965_setup_deferred_work(struct iwl_priv *priv) +static void iwl_setup_deferred_work(struct iwl_priv *priv) { priv->workqueue = create_workqueue(DRV_NAME); @@ -7589,38 +4003,42 @@ static void iwl4965_setup_deferred_work(struct iwl_priv *priv) INIT_WORK(&priv->up, iwl4965_bg_up); INIT_WORK(&priv->restart, iwl4965_bg_restart); INIT_WORK(&priv->rx_replenish, iwl4965_bg_rx_replenish); - INIT_WORK(&priv->scan_completed, iwl4965_bg_scan_completed); - INIT_WORK(&priv->request_scan, iwl4965_bg_request_scan); - INIT_WORK(&priv->abort_scan, iwl4965_bg_abort_scan); INIT_WORK(&priv->rf_kill, iwl4965_bg_rf_kill); INIT_WORK(&priv->beacon_update, iwl4965_bg_beacon_update); - INIT_DELAYED_WORK(&priv->post_associate, iwl4965_bg_post_associate); - INIT_DELAYED_WORK(&priv->init_alive_start, iwl4965_bg_init_alive_start); - INIT_DELAYED_WORK(&priv->alive_start, iwl4965_bg_alive_start); - INIT_DELAYED_WORK(&priv->scan_check, iwl4965_bg_scan_check); + INIT_WORK(&priv->set_monitor, iwl4965_bg_set_monitor); + 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); + INIT_DELAYED_WORK(&priv->alive_start, iwl_bg_alive_start); + + /* FIXME : remove when resolved PENDING */ + INIT_WORK(&priv->scan_completed, iwl_bg_scan_completed); + iwl_setup_scan_deferred_work(priv); + + if (priv->cfg->ops->lib->setup_deferred_work) + priv->cfg->ops->lib->setup_deferred_work(priv); - iwl4965_hw_setup_deferred_work(priv); + init_timer(&priv->statistics_periodic); + priv->statistics_periodic.data = (unsigned long)priv; + priv->statistics_periodic.function = iwl4965_bg_statistics_periodic; tasklet_init(&priv->irq_tasklet, (void (*)(unsigned long)) iwl4965_irq_tasklet, (unsigned long)priv); } -static void iwl4965_cancel_deferred_work(struct iwl_priv *priv) +static void iwl_cancel_deferred_work(struct iwl_priv *priv) { - iwl4965_hw_cancel_deferred_work(priv); + if (priv->cfg->ops->lib->cancel_deferred_work) + priv->cfg->ops->lib->cancel_deferred_work(priv); cancel_delayed_work_sync(&priv->init_alive_start); cancel_delayed_work(&priv->scan_check); cancel_delayed_work(&priv->alive_start); - cancel_delayed_work(&priv->post_associate); cancel_work_sync(&priv->beacon_update); + del_timer_sync(&priv->statistics_periodic); } static struct attribute *iwl4965_sysfs_entries[] = { - &dev_attr_antenna.attr, &dev_attr_channels.attr, - &dev_attr_dump_errors.attr, - &dev_attr_dump_events.attr, &dev_attr_flags.attr, &dev_attr_filter_flags.attr, #ifdef CONFIG_IWL4965_SPECTRUM_MEASUREMENT @@ -7633,6 +4051,10 @@ static struct attribute *iwl4965_sysfs_entries[] = { &dev_attr_status.attr, &dev_attr_temperature.attr, &dev_attr_tx_power.attr, +#ifdef CONFIG_IWLWIFI_DEBUG + &dev_attr_debug_level.attr, +#endif + &dev_attr_version.attr, NULL }; @@ -7656,13 +4078,9 @@ static struct ieee80211_ops iwl4965_hw_ops = { .get_stats = iwl4965_mac_get_stats, .get_tx_stats = iwl4965_mac_get_tx_stats, .conf_tx = iwl4965_mac_conf_tx, - .get_tsf = iwl4965_mac_get_tsf, .reset_tsf = iwl4965_mac_reset_tsf, - .beacon_update = iwl4965_mac_beacon_update, .bss_info_changed = iwl4965_bss_info_changed, -#ifdef CONFIG_IWL4965_HT .ampdu_action = iwl4965_mac_ampdu_action, -#endif /* CONFIG_IWL4965_HT */ .hw_scan = iwl4965_mac_hw_scan }; @@ -7682,7 +4100,9 @@ static int iwl4965_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e /* Disabling hardware scan means that mac80211 will perform scans * "the hard way", rather than using device's scan. */ if (cfg->mod_params->disable_hw_scan) { - IWL_DEBUG_INFO("Disabling hw_scan\n"); + if (cfg->mod_params->debug & IWL_DL_INFO) + dev_printk(KERN_DEBUG, &(pdev->dev), + "Disabling hw_scan\n"); iwl4965_hw_ops.hw_scan = NULL; } @@ -7701,7 +4121,7 @@ static int iwl4965_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e priv->pci_dev = pdev; #ifdef CONFIG_IWLWIFI_DEBUG - iwl_debug_level = priv->cfg->mod_params->debug; + priv->debug_level = priv->cfg->mod_params->debug; atomic_set(&priv->restrict_refcnt, 0); #endif @@ -7715,13 +4135,19 @@ static int iwl4965_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e pci_set_master(pdev); - err = pci_set_dma_mask(pdev, DMA_32BIT_MASK); + err = pci_set_dma_mask(pdev, DMA_64BIT_MASK); if (!err) - err = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK); + err = pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK); + if (err) { + err = pci_set_dma_mask(pdev, DMA_32BIT_MASK); + if (!err) + err = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK); + /* both attempts failed: */ if (err) { - printk(KERN_WARNING DRV_NAME - ": No suitable DMA available.\n"); + printk(KERN_WARNING "%s: No suitable DMA available.\n", + DRV_NAME); goto out_pci_disable_device; + } } err = pci_request_regions(pdev, DRV_NAME); @@ -7747,31 +4173,31 @@ static int iwl4965_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e (unsigned long long) pci_resource_len(pdev, 0)); IWL_DEBUG_INFO("pci_resource_base = %p\n", priv->hw_base); + iwl_hw_detect(priv); printk(KERN_INFO DRV_NAME - ": Detected Intel Wireless WiFi Link %s\n", priv->cfg->name); + ": Detected Intel Wireless WiFi Link %s REV=0x%X\n", + priv->cfg->name, priv->hw_rev); - /***************** - * 4. Read EEPROM - *****************/ - /* nic init */ - iwl_set_bit(priv, CSR_GIO_CHICKEN_BITS, - CSR_GIO_CHICKEN_BITS_REG_BIT_DIS_L0S_EXIT_TIMER); - - iwl_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE); - err = iwl_poll_bit(priv, CSR_GP_CNTRL, - CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, - CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000); + /* amp init */ + err = priv->cfg->ops->lib->apm_ops.init(priv); if (err < 0) { - IWL_DEBUG_INFO("Failed to init the card\n"); + IWL_DEBUG_INFO("Failed to init APMG\n"); goto out_iounmap; } + /***************** + * 4. Read EEPROM + *****************/ /* Read the EEPROM */ err = iwl_eeprom_init(priv); if (err) { IWL_ERROR("Unable to init EEPROM\n"); goto out_iounmap; } - /* MAC Address location in EEPROM same for 3945/4965 */ + err = iwl_eeprom_check_version(priv); + if (err) + goto out_iounmap; + + /* extract MAC Address */ iwl_eeprom_get_mac(priv, priv->mac_addr); IWL_DEBUG_INFO("MAC address: %s\n", print_mac(mac, priv->mac_addr)); SET_IEEE80211_PERM_ADDR(priv->hw, priv->mac_addr); @@ -7779,19 +4205,18 @@ static int iwl4965_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e /************************ * 5. Setup HW constants ************************/ - /* Device-specific setup */ - if (priv->cfg->ops->lib->set_hw_params(priv)) { + if (iwl_set_hw_params(priv)) { IWL_ERROR("failed to set hw parameters\n"); - goto out_iounmap; + goto out_free_eeprom; } /******************* - * 6. Setup hw/priv + * 6. Setup priv *******************/ - err = iwl_setup(priv); + err = iwl_init_drv(priv); if (err) - goto out_unset_hw_params; + goto out_free_eeprom; /* At this point both hw and priv are initialized. */ /********************************** @@ -7804,9 +4229,6 @@ static int iwl4965_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e IWL_DEBUG_INFO("Radio disabled.\n"); } - if (priv->cfg->mod_params->enable_qos) - priv->qos_data.qos_enable = 1; - /******************** * 8. Setup services ********************/ @@ -7817,17 +4239,12 @@ static int iwl4965_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e err = sysfs_create_group(&pdev->dev.kobj, &iwl4965_attribute_group); if (err) { IWL_ERROR("failed to create sysfs device attributes\n"); - goto out_unset_hw_params; + goto out_uninit_drv; } - err = iwl_dbgfs_register(priv, DRV_NAME); - if (err) { - IWL_ERROR("failed to create debugfs files\n"); - goto out_remove_sysfs; - } - iwl4965_setup_deferred_work(priv); - iwl4965_setup_rx_handlers(priv); + iwl_setup_deferred_work(priv); + iwl_setup_rx_handlers(priv); /******************** * 9. Conclude @@ -7835,14 +4252,31 @@ static int iwl4965_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e pci_save_state(pdev); pci_disable_device(pdev); - /* notify iwlcore to init */ - iwlcore_low_level_notify(priv, IWLCORE_INIT_EVT); + /********************************** + * 10. Setup and register mac80211 + **********************************/ + + err = iwl_setup_mac(priv); + if (err) + goto out_remove_sysfs; + + err = iwl_dbgfs_register(priv, DRV_NAME); + if (err) + IWL_ERROR("failed to create debugfs files\n"); + + err = iwl_rfkill_init(priv); + if (err) + IWL_ERROR("Unable to initialize RFKILL system. " + "Ignoring error: %d\n", err); + iwl_power_initialize(priv); return 0; out_remove_sysfs: sysfs_remove_group(&pdev->dev.kobj, &iwl4965_attribute_group); - out_unset_hw_params: - iwl4965_unset_hw_params(priv); + out_uninit_drv: + iwl_uninit_drv(priv); + out_free_eeprom: + iwl_eeprom_free(priv); out_iounmap: pci_iounmap(pdev, priv->hw_base); out_pci_release_regions: @@ -7859,8 +4293,6 @@ static int iwl4965_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e static void __devexit iwl4965_pci_remove(struct pci_dev *pdev) { struct iwl_priv *priv = pci_get_drvdata(pdev); - struct list_head *p, *q; - int i; unsigned long flags; if (!priv) @@ -7868,6 +4300,9 @@ static void __devexit iwl4965_pci_remove(struct pci_dev *pdev) IWL_DEBUG_INFO("*** UNLOAD DRIVER ***\n"); + iwl_dbgfs_unregister(priv); + sysfs_remove_group(&pdev->dev.kobj, &iwl4965_attribute_group); + if (priv->mac80211_registered) { ieee80211_unregister_hw(priv->hw); priv->mac80211_registered = 0; @@ -7886,26 +4321,15 @@ static void __devexit iwl4965_pci_remove(struct pci_dev *pdev) iwl_synchronize_irq(priv); - /* Free MAC hash list for ADHOC */ - for (i = 0; i < IWL_IBSS_MAC_HASH_SIZE; i++) { - list_for_each_safe(p, q, &priv->ibss_mac_hash[i]) { - list_del(p); - kfree(list_entry(p, struct iwl4965_ibss_seq, list)); - } - } - - iwlcore_low_level_notify(priv, IWLCORE_REMOVE_EVT); - iwl_dbgfs_unregister(priv); - sysfs_remove_group(&pdev->dev.kobj, &iwl4965_attribute_group); - + iwl_rfkill_unregister(priv); iwl4965_dealloc_ucode_pci(priv); if (priv->rxq.bd) - iwl4965_rx_queue_free(priv, &priv->rxq); - iwl4965_hw_txq_ctx_free(priv); + iwl_rx_queue_free(priv, &priv->rxq); + iwl_hw_txq_ctx_free(priv); - iwl4965_unset_hw_params(priv); - iwlcore_clear_stations_table(priv); + iwl_clear_stations_table(priv); + iwl_eeprom_free(priv); /*netif_stop_queue(dev); */ @@ -7922,8 +4346,7 @@ static void __devexit iwl4965_pci_remove(struct pci_dev *pdev) pci_disable_device(pdev); pci_set_drvdata(pdev, NULL); - iwl_free_channel_map(priv); - iwl4965_free_geos(priv); + iwl_uninit_drv(priv); if (priv->ibss_beacon) dev_kfree_skb(priv->ibss_beacon); @@ -7973,6 +4396,19 @@ static int iwl4965_pci_resume(struct pci_dev *pdev) static struct pci_device_id iwl_hw_card_ids[] = { {IWL_PCI_DEVICE(0x4229, PCI_ANY_ID, iwl4965_agn_cfg)}, {IWL_PCI_DEVICE(0x4230, PCI_ANY_ID, iwl4965_agn_cfg)}, +#ifdef CONFIG_IWL5000 + {IWL_PCI_DEVICE(0x4232, 0x1205, iwl5100_bg_cfg)}, + {IWL_PCI_DEVICE(0x4232, 0x1305, iwl5100_bg_cfg)}, + {IWL_PCI_DEVICE(0x4232, 0x1206, iwl5100_abg_cfg)}, + {IWL_PCI_DEVICE(0x4232, 0x1306, iwl5100_abg_cfg)}, + {IWL_PCI_DEVICE(0x4232, 0x1326, iwl5100_abg_cfg)}, + {IWL_PCI_DEVICE(0x4237, 0x1216, iwl5100_abg_cfg)}, + {IWL_PCI_DEVICE(0x4232, PCI_ANY_ID, iwl5100_agn_cfg)}, + {IWL_PCI_DEVICE(0x4235, PCI_ANY_ID, iwl5300_agn_cfg)}, + {IWL_PCI_DEVICE(0x4236, PCI_ANY_ID, iwl5300_agn_cfg)}, + {IWL_PCI_DEVICE(0x4237, PCI_ANY_ID, iwl5100_agn_cfg)}, + {IWL_PCI_DEVICE(0x423A, PCI_ANY_ID, iwl5350_agn_cfg)}, +#endif /* CONFIG_IWL5000 */ {0} }; MODULE_DEVICE_TABLE(pci, iwl_hw_card_ids); @@ -8006,20 +4442,9 @@ static int __init iwl4965_init(void) IWL_ERROR("Unable to initialize PCI module\n"); goto error_register; } -#ifdef CONFIG_IWLWIFI_DEBUG - ret = driver_create_file(&iwl_driver.driver, &driver_attr_debug_level); - if (ret) { - IWL_ERROR("Unable to create driver sysfs file\n"); - goto error_debug; - } -#endif return ret; -#ifdef CONFIG_IWLWIFI_DEBUG -error_debug: - pci_unregister_driver(&iwl_driver); -#endif error_register: iwl4965_rate_control_unregister(); return ret; @@ -8027,9 +4452,6 @@ error_register: static void __exit iwl4965_exit(void) { -#ifdef CONFIG_IWLWIFI_DEBUG - driver_remove_file(&iwl_driver.driver, &driver_attr_debug_level); -#endif pci_unregister_driver(&iwl_driver); iwl4965_rate_control_unregister(); } diff --git a/drivers/net/wireless/libertas/Makefile b/drivers/net/wireless/libertas/Makefile index f0724e31adfd..02080a3682a9 100644 --- a/drivers/net/wireless/libertas/Makefile +++ b/drivers/net/wireless/libertas/Makefile @@ -1,9 +1,5 @@ -libertas-objs := main.o wext.o \ - rx.o tx.o cmd.o \ - cmdresp.o scan.o \ - 11d.o \ - debugfs.o \ - ethtool.o assoc.o +libertas-objs := main.o wext.o rx.o tx.o cmd.o cmdresp.o scan.o 11d.o \ + debugfs.o persistcfg.o ethtool.o assoc.o usb8xxx-objs += if_usb.o libertas_cs-objs += if_cs.o diff --git a/drivers/net/wireless/libertas/assoc.c b/drivers/net/wireless/libertas/assoc.c index c9c3640ce9fb..a267d6e65f03 100644 --- a/drivers/net/wireless/libertas/assoc.c +++ b/drivers/net/wireless/libertas/assoc.c @@ -603,7 +603,8 @@ static int assoc_helper_channel(struct lbs_private *priv, /* Change mesh channel first; 21.p21 firmware won't let you change channel otherwise (even though it'll return an error to this */ - lbs_mesh_config(priv, 0, assoc_req->channel); + lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_STOP, + assoc_req->channel); } lbs_deb_assoc("ASSOC: channel: %d -> %d\n", @@ -642,7 +643,8 @@ static int assoc_helper_channel(struct lbs_private *priv, restore_mesh: if (priv->mesh_dev) - lbs_mesh_config(priv, 1, priv->curbssparams.channel); + lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START, + priv->curbssparams.channel); done: lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret); @@ -1248,7 +1250,7 @@ static int get_common_rates(struct lbs_private *priv, lbs_deb_hex(LBS_DEB_JOIN, "common rates", tmp, tmp_size); lbs_deb_join("TX data rate 0x%02x\n", priv->cur_rate); - if (!priv->auto_rate) { + if (!priv->enablehwauto) { for (i = 0; i < tmp_size; i++) { if (tmp[i] == priv->cur_rate) goto done; diff --git a/drivers/net/wireless/libertas/cmd.c b/drivers/net/wireless/libertas/cmd.c index 8124fd9b1353..75427e61898d 100644 --- a/drivers/net/wireless/libertas/cmd.c +++ b/drivers/net/wireless/libertas/cmd.c @@ -4,6 +4,7 @@ */ #include <net/iw_handler.h> +#include <net/ieee80211.h> #include <linux/kfifo.h> #include "host.h" #include "hostcmd.h" @@ -109,7 +110,7 @@ int lbs_update_hw_spec(struct lbs_private *priv) * CF card firmware 5.0.16p0: cap 0x00000303 * USB dongle firmware 5.110.17p2: cap 0x00000303 */ - printk("libertas: %s, fw %u.%u.%up%u, cap 0x%08x\n", + lbs_pr_info("%s, fw %u.%u.%up%u, cap 0x%08x\n", print_mac(mac, cmd.permanentaddr), priv->fwrelease >> 24 & 0xff, priv->fwrelease >> 16 & 0xff, @@ -675,58 +676,60 @@ static int lbs_cmd_802_11_monitor_mode(struct cmd_ds_command *cmd, return 0; } -static int lbs_cmd_802_11_rate_adapt_rateset(struct lbs_private *priv, - struct cmd_ds_command *cmd, - u16 cmd_action) +static __le16 lbs_rate_to_fw_bitmap(int rate, int lower_rates_ok) { - struct cmd_ds_802_11_rate_adapt_rateset - *rateadapt = &cmd->params.rateset; - - lbs_deb_enter(LBS_DEB_CMD); - cmd->size = - cpu_to_le16(sizeof(struct cmd_ds_802_11_rate_adapt_rateset) - + S_DS_GEN); - cmd->command = cpu_to_le16(CMD_802_11_RATE_ADAPT_RATESET); - - rateadapt->action = cpu_to_le16(cmd_action); - rateadapt->enablehwauto = cpu_to_le16(priv->enablehwauto); - rateadapt->bitmap = cpu_to_le16(priv->ratebitmap); - - lbs_deb_leave(LBS_DEB_CMD); - return 0; +/* Bit Rate +* 15:13 Reserved +* 12 54 Mbps +* 11 48 Mbps +* 10 36 Mbps +* 9 24 Mbps +* 8 18 Mbps +* 7 12 Mbps +* 6 9 Mbps +* 5 6 Mbps +* 4 Reserved +* 3 11 Mbps +* 2 5.5 Mbps +* 1 2 Mbps +* 0 1 Mbps +**/ + + uint16_t ratemask; + int i = lbs_data_rate_to_fw_index(rate); + if (lower_rates_ok) + ratemask = (0x1fef >> (12 - i)); + else + ratemask = (1 << i); + return cpu_to_le16(ratemask); } -/** - * @brief Get the current data rate - * - * @param priv A pointer to struct lbs_private structure - * - * @return The data rate on success, error on failure - */ -int lbs_get_data_rate(struct lbs_private *priv) +int lbs_cmd_802_11_rate_adapt_rateset(struct lbs_private *priv, + uint16_t cmd_action) { - struct cmd_ds_802_11_data_rate cmd; - int ret = -1; + struct cmd_ds_802_11_rate_adapt_rateset cmd; + int ret; lbs_deb_enter(LBS_DEB_CMD); - memset(&cmd, 0, sizeof(cmd)); - cmd.hdr.size = cpu_to_le16(sizeof(cmd)); - cmd.action = cpu_to_le16(CMD_ACT_GET_TX_RATE); - - ret = lbs_cmd_with_response(priv, CMD_802_11_DATA_RATE, &cmd); - if (ret) - goto out; + if (!priv->cur_rate && !priv->enablehwauto) + return -EINVAL; - lbs_deb_hex(LBS_DEB_CMD, "DATA_RATE_RESP", (u8 *) &cmd, sizeof (cmd)); + cmd.hdr.size = cpu_to_le16(sizeof(cmd)); - ret = (int) lbs_fw_index_to_data_rate(cmd.rates[0]); - lbs_deb_cmd("DATA_RATE: current rate 0x%02x\n", ret); + cmd.action = cpu_to_le16(cmd_action); + cmd.enablehwauto = cpu_to_le16(priv->enablehwauto); + cmd.bitmap = lbs_rate_to_fw_bitmap(priv->cur_rate, priv->enablehwauto); + ret = lbs_cmd_with_response(priv, CMD_802_11_RATE_ADAPT_RATESET, &cmd); + if (!ret && cmd_action == CMD_ACT_GET) { + priv->ratebitmap = le16_to_cpu(cmd.bitmap); + priv->enablehwauto = le16_to_cpu(cmd.enablehwauto); + } -out: lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret); return ret; } +EXPORT_SYMBOL_GPL(lbs_cmd_802_11_rate_adapt_rateset); /** * @brief Set the data rate @@ -778,28 +781,6 @@ out: return ret; } -static int lbs_cmd_mac_multicast_adr(struct lbs_private *priv, - struct cmd_ds_command *cmd, - u16 cmd_action) -{ - struct cmd_ds_mac_multicast_adr *pMCastAdr = &cmd->params.madr; - - lbs_deb_enter(LBS_DEB_CMD); - cmd->size = cpu_to_le16(sizeof(struct cmd_ds_mac_multicast_adr) + - S_DS_GEN); - cmd->command = cpu_to_le16(CMD_MAC_MULTICAST_ADR); - - lbs_deb_cmd("MULTICAST_ADR: setting %d addresses\n", pMCastAdr->nr_of_adrs); - pMCastAdr->action = cpu_to_le16(cmd_action); - pMCastAdr->nr_of_adrs = - cpu_to_le16((u16) priv->nr_of_multicastmacaddr); - memcpy(pMCastAdr->maclist, priv->multicastlist, - priv->nr_of_multicastmacaddr * ETH_ALEN); - - lbs_deb_leave(LBS_DEB_CMD); - return 0; -} - /** * @brief Get the radio channel * @@ -1052,24 +1033,69 @@ int lbs_mesh_access(struct lbs_private *priv, uint16_t cmd_action, return ret; } -int lbs_mesh_config(struct lbs_private *priv, uint16_t enable, uint16_t chan) +int lbs_mesh_config_send(struct lbs_private *priv, + struct cmd_ds_mesh_config *cmd, + uint16_t action, uint16_t type) +{ + int ret; + + lbs_deb_enter(LBS_DEB_CMD); + + cmd->hdr.command = cpu_to_le16(CMD_MESH_CONFIG); + 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); + + lbs_deb_leave(LBS_DEB_CMD); + return ret; +} + +/* This function is the CMD_MESH_CONFIG legacy function. It only handles the + * START and STOP actions. The extended actions supported by CMD_MESH_CONFIG + * are all handled by preparing a struct cmd_ds_mesh_config and passing it to + * lbs_mesh_config_send. + */ +int lbs_mesh_config(struct lbs_private *priv, uint16_t action, uint16_t chan) { struct cmd_ds_mesh_config cmd; + struct mrvl_meshie *ie; memset(&cmd, 0, sizeof(cmd)); - cmd.action = cpu_to_le16(enable); cmd.channel = cpu_to_le16(chan); - cmd.type = cpu_to_le16(priv->mesh_tlv); - cmd.hdr.size = cpu_to_le16(sizeof(cmd)); - - if (enable) { - cmd.length = cpu_to_le16(priv->mesh_ssid_len); - memcpy(cmd.data, priv->mesh_ssid, priv->mesh_ssid_len); + ie = (struct mrvl_meshie *)cmd.data; + + switch (action) { + case CMD_ACT_MESH_CONFIG_START: + ie->hdr.id = MFIE_TYPE_GENERIC; + ie->val.oui[0] = 0x00; + ie->val.oui[1] = 0x50; + ie->val.oui[2] = 0x43; + ie->val.type = MARVELL_MESH_IE_TYPE; + ie->val.subtype = MARVELL_MESH_IE_SUBTYPE; + ie->val.version = MARVELL_MESH_IE_VERSION; + ie->val.active_protocol_id = MARVELL_MESH_PROTO_ID_HWMP; + ie->val.active_metric_id = MARVELL_MESH_METRIC_ID; + ie->val.mesh_capability = MARVELL_MESH_CAPABILITY; + ie->val.mesh_id_len = priv->mesh_ssid_len; + memcpy(ie->val.mesh_id, priv->mesh_ssid, priv->mesh_ssid_len); + ie->hdr.len = sizeof(struct mrvl_meshie_val) - + IW_ESSID_MAX_SIZE + priv->mesh_ssid_len; + cmd.length = cpu_to_le16(sizeof(struct mrvl_meshie_val)); + break; + case CMD_ACT_MESH_CONFIG_STOP: + break; + default: + return -1; } - lbs_deb_cmd("mesh config enable %d TLV %x channel %d SSID %s\n", - enable, priv->mesh_tlv, chan, + lbs_deb_cmd("mesh config action %d type %x channel %d SSID %s\n", + action, priv->mesh_tlv, chan, escape_essid(priv->mesh_ssid, priv->mesh_ssid_len)); - return lbs_cmd_with_response(priv, CMD_MESH_CONFIG, &cmd); + + return lbs_mesh_config_send(priv, &cmd, action, priv->mesh_tlv); } static int lbs_cmd_bcn_ctrl(struct lbs_private * priv, @@ -1144,7 +1170,7 @@ static void lbs_submit_command(struct lbs_private *priv, struct cmd_header *cmd; uint16_t cmdsize; uint16_t command; - int timeo = 5 * HZ; + int timeo = 3 * HZ; int ret; lbs_deb_enter(LBS_DEB_HOST); @@ -1162,7 +1188,7 @@ static void lbs_submit_command(struct lbs_private *priv, /* These commands take longer */ if (command == CMD_802_11_SCAN || command == CMD_802_11_ASSOCIATE || command == CMD_802_11_AUTHENTICATE) - timeo = 10 * HZ; + timeo = 5 * HZ; lbs_deb_cmd("DNLD_CMD: command 0x%04x, seq %d, size %d\n", command, le16_to_cpu(cmd->seqnum), cmdsize); @@ -1174,7 +1200,7 @@ static void lbs_submit_command(struct lbs_private *priv, lbs_pr_info("DNLD_CMD: hw_host_to_card failed: %d\n", ret); /* Let the timer kick in and retry, and potentially reset the whole thing if the condition persists */ - timeo = HZ; + timeo = HZ/4; } /* Setup the timer after transmit command */ @@ -1279,8 +1305,7 @@ void lbs_set_mac_control(struct lbs_private *priv) cmd.action = cpu_to_le16(priv->mac_control); cmd.reserved = 0; - lbs_cmd_async(priv, CMD_MAC_CONTROL, - &cmd.hdr, sizeof(cmd)); + lbs_cmd_async(priv, CMD_MAC_CONTROL, &cmd.hdr, sizeof(cmd)); lbs_deb_leave(LBS_DEB_CMD); } @@ -1387,15 +1412,6 @@ int lbs_prepare_and_send_command(struct lbs_private *priv, cmd_action, pdata_buf); break; - case CMD_802_11_RATE_ADAPT_RATESET: - ret = lbs_cmd_802_11_rate_adapt_rateset(priv, - cmdptr, cmd_action); - break; - - case CMD_MAC_MULTICAST_ADR: - ret = lbs_cmd_mac_multicast_adr(priv, cmdptr, cmd_action); - break; - case CMD_802_11_MONITOR_MODE: ret = lbs_cmd_802_11_monitor_mode(cmdptr, cmd_action, pdata_buf); @@ -1484,7 +1500,7 @@ int lbs_prepare_and_send_command(struct lbs_private *priv, ret = lbs_cmd_bcn_ctrl(priv, cmdptr, cmd_action); break; default: - lbs_deb_host("PREP_CMD: unknown command 0x%04x\n", cmd_no); + lbs_pr_err("PREP_CMD: unknown command 0x%04x\n", cmd_no); ret = -1; break; } diff --git a/drivers/net/wireless/libertas/cmd.h b/drivers/net/wireless/libertas/cmd.h index 3dfc2d43c224..a53b51f8bdb4 100644 --- a/drivers/net/wireless/libertas/cmd.h +++ b/drivers/net/wireless/libertas/cmd.h @@ -34,18 +34,22 @@ int lbs_update_hw_spec(struct lbs_private *priv); int lbs_mesh_access(struct lbs_private *priv, uint16_t cmd_action, struct cmd_ds_mesh_access *cmd); -int lbs_get_data_rate(struct lbs_private *priv); int lbs_set_data_rate(struct lbs_private *priv, u8 rate); int lbs_get_channel(struct lbs_private *priv); int lbs_set_channel(struct lbs_private *priv, u8 channel); +int lbs_mesh_config_send(struct lbs_private *priv, + struct cmd_ds_mesh_config *cmd, + uint16_t action, uint16_t type); int lbs_mesh_config(struct lbs_private *priv, uint16_t enable, uint16_t chan); int lbs_host_sleep_cfg(struct lbs_private *priv, uint32_t criteria); int lbs_suspend(struct lbs_private *priv); -int lbs_resume(struct lbs_private *priv); +void lbs_resume(struct lbs_private *priv); +int lbs_cmd_802_11_rate_adapt_rateset(struct lbs_private *priv, + uint16_t cmd_action); int lbs_cmd_802_11_inactivity_timeout(struct lbs_private *priv, uint16_t cmd_action, uint16_t *timeout); int lbs_cmd_802_11_sleep_params(struct lbs_private *priv, uint16_t cmd_action, diff --git a/drivers/net/wireless/libertas/cmdresp.c b/drivers/net/wireless/libertas/cmdresp.c index 5abecb7673e6..24de3c3cf877 100644 --- a/drivers/net/wireless/libertas/cmdresp.c +++ b/drivers/net/wireless/libertas/cmdresp.c @@ -203,22 +203,6 @@ static int lbs_ret_802_11_rf_tx_power(struct lbs_private *priv, return 0; } -static int lbs_ret_802_11_rate_adapt_rateset(struct lbs_private *priv, - struct cmd_ds_command *resp) -{ - struct cmd_ds_802_11_rate_adapt_rateset *rates = &resp->params.rateset; - - lbs_deb_enter(LBS_DEB_CMD); - - if (rates->action == CMD_ACT_GET) { - priv->enablehwauto = le16_to_cpu(rates->enablehwauto); - priv->ratebitmap = le16_to_cpu(rates->bitmap); - } - - lbs_deb_leave(LBS_DEB_CMD); - return 0; -} - static int lbs_ret_802_11_rssi(struct lbs_private *priv, struct cmd_ds_command *resp) { @@ -316,16 +300,11 @@ static inline int handle_cmd_response(struct lbs_private *priv, break; - case CMD_RET(CMD_MAC_MULTICAST_ADR): case CMD_RET(CMD_802_11_RESET): case CMD_RET(CMD_802_11_AUTHENTICATE): case CMD_RET(CMD_802_11_BEACON_STOP): break; - case CMD_RET(CMD_802_11_RATE_ADAPT_RATESET): - ret = lbs_ret_802_11_rate_adapt_rateset(priv, resp); - break; - case CMD_RET(CMD_802_11_RSSI): ret = lbs_ret_802_11_rssi(priv, resp); break; @@ -376,8 +355,8 @@ static inline int handle_cmd_response(struct lbs_private *priv, break; default: - lbs_deb_host("CMD_RESP: unknown cmd response 0x%04x\n", - le16_to_cpu(resp->command)); + lbs_pr_err("CMD_RESP: unknown cmd response 0x%04x\n", + le16_to_cpu(resp->command)); break; } lbs_deb_leave(LBS_DEB_HOST); diff --git a/drivers/net/wireless/libertas/decl.h b/drivers/net/wireless/libertas/decl.h index b652fa301e19..a8ac974dacac 100644 --- a/drivers/net/wireless/libertas/decl.h +++ b/drivers/net/wireless/libertas/decl.h @@ -60,13 +60,17 @@ void lbs_mac_event_disconnected(struct lbs_private *priv); void lbs_send_iwevcustom_event(struct lbs_private *priv, s8 *str); +/* persistcfg.c */ +void lbs_persist_config_init(struct net_device *net); +void lbs_persist_config_remove(struct net_device *net); + /* main.c */ struct chan_freq_power *lbs_get_region_cfp_table(u8 region, int *cfp_no); struct lbs_private *lbs_add_card(void *card, struct device *dmdev); -int lbs_remove_card(struct lbs_private *priv); +void lbs_remove_card(struct lbs_private *priv); int lbs_start_card(struct lbs_private *priv); -int lbs_stop_card(struct lbs_private *priv); +void lbs_stop_card(struct lbs_private *priv); void lbs_host_to_card_done(struct lbs_private *priv); int lbs_update_channel(struct lbs_private *priv); diff --git a/drivers/net/wireless/libertas/defs.h b/drivers/net/wireless/libertas/defs.h index d39520111062..12e687550bce 100644 --- a/drivers/net/wireless/libertas/defs.h +++ b/drivers/net/wireless/libertas/defs.h @@ -40,6 +40,7 @@ #define LBS_DEB_THREAD 0x00100000 #define LBS_DEB_HEX 0x00200000 #define LBS_DEB_SDIO 0x00400000 +#define LBS_DEB_SYSFS 0x00800000 extern unsigned int lbs_debug; @@ -81,7 +82,8 @@ do { if ((lbs_debug & (grp)) == (grp)) \ #define lbs_deb_usbd(dev, fmt, args...) LBS_DEB_LL(LBS_DEB_USB, " usbd", "%s:" fmt, (dev)->bus_id, ##args) #define lbs_deb_cs(fmt, args...) LBS_DEB_LL(LBS_DEB_CS, " cs", fmt, ##args) #define lbs_deb_thread(fmt, args...) LBS_DEB_LL(LBS_DEB_THREAD, " thread", fmt, ##args) -#define lbs_deb_sdio(fmt, args...) LBS_DEB_LL(LBS_DEB_SDIO, " thread", fmt, ##args) +#define lbs_deb_sdio(fmt, args...) LBS_DEB_LL(LBS_DEB_SDIO, " sdio", fmt, ##args) +#define lbs_deb_sysfs(fmt, args...) LBS_DEB_LL(LBS_DEB_SYSFS, " sysfs", fmt, ##args) #define lbs_pr_info(format, args...) \ printk(KERN_INFO DRV_NAME": " format, ## args) @@ -170,6 +172,16 @@ static inline void lbs_deb_hex(unsigned int grp, const char *prompt, u8 *buf, in #define MARVELL_MESH_IE_LENGTH 9 +/* Values used to populate the struct mrvl_mesh_ie. The only time you need this + * is when enabling the mesh using CMD_MESH_CONFIG. + */ +#define MARVELL_MESH_IE_TYPE 4 +#define MARVELL_MESH_IE_SUBTYPE 0 +#define MARVELL_MESH_IE_VERSION 0 +#define MARVELL_MESH_PROTO_ID_HWMP 0 +#define MARVELL_MESH_METRIC_ID 0 +#define MARVELL_MESH_CAPABILITY 0 + /** INT status Bit Definition*/ #define MRVDRV_TX_DNLD_RDY 0x0001 #define MRVDRV_RX_UPLD_RDY 0x0002 diff --git a/drivers/net/wireless/libertas/dev.h b/drivers/net/wireless/libertas/dev.h index 0d9edb9b11f5..f5bb40c54d85 100644 --- a/drivers/net/wireless/libertas/dev.h +++ b/drivers/net/wireless/libertas/dev.h @@ -140,6 +140,8 @@ struct lbs_private { wait_queue_head_t waitq; struct workqueue_struct *work_thread; + struct work_struct mcast_work; + /** Scanning */ struct delayed_work scan_work; struct delayed_work assoc_work; @@ -151,6 +153,7 @@ struct lbs_private { /** Hardware access */ int (*hw_host_to_card) (struct lbs_private *priv, u8 type, u8 *payload, u16 nb); + void (*reset_card) (struct lbs_private *priv); /* Wake On LAN */ uint32_t wol_criteria; @@ -234,8 +237,8 @@ struct lbs_private { /** 802.11 statistics */ // struct cmd_DS_802_11_GET_STAT wlan802_11Stat; - u16 enablehwauto; - u16 ratebitmap; + uint16_t enablehwauto; + uint16_t ratebitmap; u32 fragthsd; u32 rtsthsd; @@ -293,7 +296,6 @@ struct lbs_private { /** data rate stuff */ u8 cur_rate; - u8 auto_rate; /** RF calibration data */ diff --git a/drivers/net/wireless/libertas/host.h b/drivers/net/wireless/libertas/host.h index 3915c3144fad..c92e41b4faf4 100644 --- a/drivers/net/wireless/libertas/host.h +++ b/drivers/net/wireless/libertas/host.h @@ -256,6 +256,23 @@ enum cmd_mesh_access_opts { CMD_ACT_MESH_GET_AUTOSTART_ENABLED, }; +/* Define actions and types for CMD_MESH_CONFIG */ +enum cmd_mesh_config_actions { + CMD_ACT_MESH_CONFIG_STOP = 0, + CMD_ACT_MESH_CONFIG_START, + CMD_ACT_MESH_CONFIG_SET, + CMD_ACT_MESH_CONFIG_GET, +}; + +enum cmd_mesh_config_types { + CMD_TYPE_MESH_SET_BOOTFLAG = 1, + CMD_TYPE_MESH_SET_BOOTTIME, + CMD_TYPE_MESH_SET_DEF_CHANNEL, + CMD_TYPE_MESH_SET_MESH_IE, + CMD_TYPE_MESH_GET_DEFAULTS, + CMD_TYPE_MESH_GET_MESH_IE, /* GET_DEFAULTS is superset of GET_MESHIE */ +}; + /** Card Event definition */ #define MACREG_INT_CODE_TX_PPA_FREE 0 #define MACREG_INT_CODE_TX_DMA_DONE 1 diff --git a/drivers/net/wireless/libertas/hostcmd.h b/drivers/net/wireless/libertas/hostcmd.h index f29bc5bbda3e..913b480211a9 100644 --- a/drivers/net/wireless/libertas/hostcmd.h +++ b/drivers/net/wireless/libertas/hostcmd.h @@ -219,6 +219,7 @@ struct cmd_ds_mac_control { }; struct cmd_ds_mac_multicast_adr { + struct cmd_header hdr; __le16 action; __le16 nr_of_adrs; u8 maclist[ETH_ALEN * MRVDRV_MAX_MULTICAST_LIST_SIZE]; @@ -499,6 +500,7 @@ struct cmd_ds_802_11_data_rate { }; struct cmd_ds_802_11_rate_adapt_rateset { + struct cmd_header hdr; __le16 action; __le16 enablehwauto; __le16 bitmap; @@ -702,8 +704,6 @@ struct cmd_ds_command { struct cmd_ds_802_11_rf_tx_power txp; struct cmd_ds_802_11_rf_antenna rant; struct cmd_ds_802_11_monitor_mode monitor; - struct cmd_ds_802_11_rate_adapt_rateset rateset; - struct cmd_ds_mac_multicast_adr madr; struct cmd_ds_802_11_ad_hoc_join adj; struct cmd_ds_802_11_rssi rssi; struct cmd_ds_802_11_rssi_rsp rssirsp; diff --git a/drivers/net/wireless/libertas/if_cs.c b/drivers/net/wireless/libertas/if_cs.c index d075b448da94..04d7a251e3f0 100644 --- a/drivers/net/wireless/libertas/if_cs.c +++ b/drivers/net/wireless/libertas/if_cs.c @@ -148,76 +148,149 @@ static int if_cs_poll_while_fw_download(struct if_cs_card *card, uint addr, u8 r { int i; - for (i = 0; i < 1000; i++) { + for (i = 0; i < 100000; i++) { u8 val = if_cs_read8(card, addr); if (val == reg) return i; - udelay(500); + udelay(5); } return -ETIME; } -/* Host control registers and their bit definitions */ - -#define IF_CS_H_STATUS 0x00000000 -#define IF_CS_H_STATUS_TX_OVER 0x0001 -#define IF_CS_H_STATUS_RX_OVER 0x0002 -#define IF_CS_H_STATUS_DNLD_OVER 0x0004 - -#define IF_CS_H_INT_CAUSE 0x00000002 -#define IF_CS_H_IC_TX_OVER 0x0001 -#define IF_CS_H_IC_RX_OVER 0x0002 -#define IF_CS_H_IC_DNLD_OVER 0x0004 -#define IF_CS_H_IC_POWER_DOWN 0x0008 -#define IF_CS_H_IC_HOST_EVENT 0x0010 -#define IF_CS_H_IC_MASK 0x001f - -#define IF_CS_H_INT_MASK 0x00000004 -#define IF_CS_H_IM_MASK 0x001f - -#define IF_CS_H_WRITE_LEN 0x00000014 - -#define IF_CS_H_WRITE 0x00000016 +/* + * First the bitmasks for the host/card interrupt/status registers: + */ +#define IF_CS_BIT_TX 0x0001 +#define IF_CS_BIT_RX 0x0002 +#define IF_CS_BIT_COMMAND 0x0004 +#define IF_CS_BIT_RESP 0x0008 +#define IF_CS_BIT_EVENT 0x0010 +#define IF_CS_BIT_MASK 0x001f -#define IF_CS_H_CMD_LEN 0x00000018 -#define IF_CS_H_CMD 0x0000001A -#define IF_CS_C_READ_LEN 0x00000024 +/* + * It's not really clear to me what the host status register is for. It + * needs to be set almost in union with "host int cause". The following + * bits from above are used: + * + * IF_CS_BIT_TX driver downloaded a data packet + * IF_CS_BIT_RX driver got a data packet + * IF_CS_BIT_COMMAND driver downloaded a command + * IF_CS_BIT_RESP not used (has some meaning with powerdown) + * IF_CS_BIT_EVENT driver read a host event + */ +#define IF_CS_HOST_STATUS 0x00000000 -#define IF_CS_H_READ 0x00000010 +/* + * With the host int cause register can the host (that is, Linux) cause + * an interrupt in the firmware, to tell the firmware about those events: + * + * IF_CS_BIT_TX a data packet has been downloaded + * IF_CS_BIT_RX a received data packet has retrieved + * IF_CS_BIT_COMMAND a firmware block or a command has been downloaded + * IF_CS_BIT_RESP not used (has some meaning with powerdown) + * IF_CS_BIT_EVENT a host event (link lost etc) has been retrieved + */ +#define IF_CS_HOST_INT_CAUSE 0x00000002 -/* Card control registers and their bit definitions */ +/* + * The host int mask register is used to enable/disable interrupt. However, + * I have the suspicion that disabled interrupts are lost. + */ +#define IF_CS_HOST_INT_MASK 0x00000004 -#define IF_CS_C_STATUS 0x00000020 -#define IF_CS_C_S_TX_DNLD_RDY 0x0001 -#define IF_CS_C_S_RX_UPLD_RDY 0x0002 -#define IF_CS_C_S_CMD_DNLD_RDY 0x0004 -#define IF_CS_C_S_CMD_UPLD_RDY 0x0008 -#define IF_CS_C_S_CARDEVENT 0x0010 -#define IF_CS_C_S_MASK 0x001f -#define IF_CS_C_S_STATUS_MASK 0x7f00 +/* + * Used to send or receive data packets: + */ +#define IF_CS_WRITE 0x00000016 +#define IF_CS_WRITE_LEN 0x00000014 +#define IF_CS_READ 0x00000010 +#define IF_CS_READ_LEN 0x00000024 -#define IF_CS_C_INT_CAUSE 0x00000022 -#define IF_CS_C_IC_MASK 0x001f +/* + * Used to send commands (and to send firmware block) and to + * receive command responses: + */ +#define IF_CS_CMD 0x0000001A +#define IF_CS_CMD_LEN 0x00000018 +#define IF_CS_RESP 0x00000012 +#define IF_CS_RESP_LEN 0x00000030 -#define IF_CS_C_SQ_READ_LOW 0x00000028 -#define IF_CS_C_SQ_HELPER_OK 0x10 +/* + * The card status registers shows what the card/firmware actually + * accepts: + * + * IF_CS_BIT_TX you may send a data packet + * IF_CS_BIT_RX you may retrieve a data packet + * IF_CS_BIT_COMMAND you may send a command + * IF_CS_BIT_RESP you may retrieve a command response + * IF_CS_BIT_EVENT the card has a event for use (link lost, snr low etc) + * + * When reading this register several times, you will get back the same + * results --- with one exception: the IF_CS_BIT_EVENT clear itself + * automatically. + * + * Not that we don't rely on BIT_RX,_BIT_RESP or BIT_EVENT because + * we handle this via the card int cause register. + */ +#define IF_CS_CARD_STATUS 0x00000020 +#define IF_CS_CARD_STATUS_MASK 0x7f00 -#define IF_CS_C_CMD_LEN 0x00000030 +/* + * The card int cause register is used by the card/firmware to notify us + * about the following events: + * + * IF_CS_BIT_TX a data packet has successfully been sentx + * IF_CS_BIT_RX a data packet has been received and can be retrieved + * IF_CS_BIT_COMMAND not used + * IF_CS_BIT_RESP the firmware has a command response for us + * IF_CS_BIT_EVENT the card has a event for use (link lost, snr low etc) + */ +#define IF_CS_CARD_INT_CAUSE 0x00000022 -#define IF_CS_C_CMD 0x00000012 +/* + * This is used to for handshaking with the card's bootloader/helper image + * to synchronize downloading of firmware blocks. + */ +#define IF_CS_SQ_READ_LOW 0x00000028 +#define IF_CS_SQ_HELPER_OK 0x10 +/* + * The scratch register tells us ... + * + * IF_CS_SCRATCH_BOOT_OK the bootloader runs + * IF_CS_SCRATCH_HELPER_OK the helper firmware already runs + */ #define IF_CS_SCRATCH 0x0000003F +#define IF_CS_SCRATCH_BOOT_OK 0x00 +#define IF_CS_SCRATCH_HELPER_OK 0x5a +/* + * Used to detect ancient chips: + */ +#define IF_CS_PRODUCT_ID 0x0000001C +#define IF_CS_CF8385_B1_REV 0x12 /********************************************************************/ -/* I/O */ +/* I/O and interrupt handling */ /********************************************************************/ +static inline void if_cs_enable_ints(struct if_cs_card *card) +{ + lbs_deb_enter(LBS_DEB_CS); + if_cs_write16(card, IF_CS_HOST_INT_MASK, 0); +} + +static inline void if_cs_disable_ints(struct if_cs_card *card) +{ + lbs_deb_enter(LBS_DEB_CS); + if_cs_write16(card, IF_CS_HOST_INT_MASK, IF_CS_BIT_MASK); +} + /* * Called from if_cs_host_to_card to send a command to the hardware */ @@ -228,11 +301,12 @@ static int if_cs_send_cmd(struct lbs_private *priv, u8 *buf, u16 nb) int loops = 0; lbs_deb_enter(LBS_DEB_CS); + if_cs_disable_ints(card); /* Is hardware ready? */ while (1) { - u16 val = if_cs_read16(card, IF_CS_C_STATUS); - if (val & IF_CS_C_S_CMD_DNLD_RDY) + u16 status = if_cs_read16(card, IF_CS_CARD_STATUS); + if (status & IF_CS_BIT_COMMAND) break; if (++loops > 100) { lbs_pr_err("card not ready for commands\n"); @@ -241,51 +315,56 @@ static int if_cs_send_cmd(struct lbs_private *priv, u8 *buf, u16 nb) mdelay(1); } - if_cs_write16(card, IF_CS_H_CMD_LEN, nb); + if_cs_write16(card, IF_CS_CMD_LEN, nb); - if_cs_write16_rep(card, IF_CS_H_CMD, buf, nb / 2); + if_cs_write16_rep(card, IF_CS_CMD, buf, nb / 2); /* Are we supposed to transfer an odd amount of bytes? */ if (nb & 1) - if_cs_write8(card, IF_CS_H_CMD, buf[nb-1]); + if_cs_write8(card, IF_CS_CMD, buf[nb-1]); /* "Assert the download over interrupt command in the Host * status register" */ - if_cs_write16(card, IF_CS_H_STATUS, IF_CS_H_STATUS_DNLD_OVER); + if_cs_write16(card, IF_CS_HOST_STATUS, IF_CS_BIT_COMMAND); /* "Assert the download over interrupt command in the Card * interrupt case register" */ - if_cs_write16(card, IF_CS_H_INT_CAUSE, IF_CS_H_IC_DNLD_OVER); + if_cs_write16(card, IF_CS_HOST_INT_CAUSE, IF_CS_BIT_COMMAND); ret = 0; done: + if_cs_enable_ints(card); lbs_deb_leave_args(LBS_DEB_CS, "ret %d", ret); return ret; } - /* * Called from if_cs_host_to_card to send a data to the hardware */ static void if_cs_send_data(struct lbs_private *priv, u8 *buf, u16 nb) { struct if_cs_card *card = (struct if_cs_card *)priv->card; + u16 status; lbs_deb_enter(LBS_DEB_CS); + if_cs_disable_ints(card); + + status = if_cs_read16(card, IF_CS_CARD_STATUS); + BUG_ON((status & IF_CS_BIT_TX) == 0); - if_cs_write16(card, IF_CS_H_WRITE_LEN, nb); + if_cs_write16(card, IF_CS_WRITE_LEN, nb); /* write even number of bytes, then odd byte if necessary */ - if_cs_write16_rep(card, IF_CS_H_WRITE, buf, nb / 2); + if_cs_write16_rep(card, IF_CS_WRITE, buf, nb / 2); if (nb & 1) - if_cs_write8(card, IF_CS_H_WRITE, buf[nb-1]); + if_cs_write8(card, IF_CS_WRITE, buf[nb-1]); - if_cs_write16(card, IF_CS_H_STATUS, IF_CS_H_STATUS_TX_OVER); - if_cs_write16(card, IF_CS_H_INT_CAUSE, IF_CS_H_STATUS_TX_OVER); + if_cs_write16(card, IF_CS_HOST_STATUS, IF_CS_BIT_TX); + if_cs_write16(card, IF_CS_HOST_INT_CAUSE, IF_CS_BIT_TX); + if_cs_enable_ints(card); lbs_deb_leave(LBS_DEB_CS); } - /* * Get the command result out of the card. */ @@ -293,27 +372,28 @@ static int if_cs_receive_cmdres(struct lbs_private *priv, u8 *data, u32 *len) { unsigned long flags; int ret = -1; - u16 val; + u16 status; lbs_deb_enter(LBS_DEB_CS); /* is hardware ready? */ - val = if_cs_read16(priv->card, IF_CS_C_STATUS); - if ((val & IF_CS_C_S_CMD_UPLD_RDY) == 0) { - lbs_pr_err("card not ready for CMD\n"); + status = if_cs_read16(priv->card, IF_CS_CARD_STATUS); + if ((status & IF_CS_BIT_RESP) == 0) { + lbs_pr_err("no cmd response in card\n"); + *len = 0; goto out; } - *len = if_cs_read16(priv->card, IF_CS_C_CMD_LEN); + *len = if_cs_read16(priv->card, IF_CS_RESP_LEN); if ((*len == 0) || (*len > LBS_CMD_BUFFER_SIZE)) { lbs_pr_err("card cmd buffer has invalid # of bytes (%d)\n", *len); goto out; } /* read even number of bytes, then odd byte if necessary */ - if_cs_read16_rep(priv->card, IF_CS_C_CMD, data, *len/sizeof(u16)); + if_cs_read16_rep(priv->card, IF_CS_RESP, data, *len/sizeof(u16)); if (*len & 1) - data[*len-1] = if_cs_read8(priv->card, IF_CS_C_CMD); + data[*len-1] = if_cs_read8(priv->card, IF_CS_RESP); /* This is a workaround for a firmware that reports too much * bytes */ @@ -330,7 +410,6 @@ out: return ret; } - static struct sk_buff *if_cs_receive_data(struct lbs_private *priv) { struct sk_buff *skb = NULL; @@ -339,7 +418,7 @@ static struct sk_buff *if_cs_receive_data(struct lbs_private *priv) lbs_deb_enter(LBS_DEB_CS); - len = if_cs_read16(priv->card, IF_CS_C_READ_LEN); + len = if_cs_read16(priv->card, IF_CS_READ_LEN); if (len == 0 || len > MRVDRV_ETH_RX_PACKET_BUFFER_SIZE) { lbs_pr_err("card data buffer has invalid # of bytes (%d)\n", len); priv->stats.rx_dropped++; @@ -354,38 +433,19 @@ static struct sk_buff *if_cs_receive_data(struct lbs_private *priv) data = skb->data; /* read even number of bytes, then odd byte if necessary */ - if_cs_read16_rep(priv->card, IF_CS_H_READ, data, len/sizeof(u16)); + if_cs_read16_rep(priv->card, IF_CS_READ, data, len/sizeof(u16)); if (len & 1) - data[len-1] = if_cs_read8(priv->card, IF_CS_H_READ); + data[len-1] = if_cs_read8(priv->card, IF_CS_READ); dat_err: - if_cs_write16(priv->card, IF_CS_H_STATUS, IF_CS_H_STATUS_RX_OVER); - if_cs_write16(priv->card, IF_CS_H_INT_CAUSE, IF_CS_H_IC_RX_OVER); + if_cs_write16(priv->card, IF_CS_HOST_STATUS, IF_CS_BIT_RX); + if_cs_write16(priv->card, IF_CS_HOST_INT_CAUSE, IF_CS_BIT_RX); out: lbs_deb_leave_args(LBS_DEB_CS, "ret %p", skb); return skb; } - - -/********************************************************************/ -/* Interrupts */ -/********************************************************************/ - -static inline void if_cs_enable_ints(struct if_cs_card *card) -{ - lbs_deb_enter(LBS_DEB_CS); - if_cs_write16(card, IF_CS_H_INT_MASK, 0); -} - -static inline void if_cs_disable_ints(struct if_cs_card *card) -{ - lbs_deb_enter(LBS_DEB_CS); - if_cs_write16(card, IF_CS_H_INT_MASK, IF_CS_H_IM_MASK); -} - - static irqreturn_t if_cs_interrupt(int irq, void *data) { struct if_cs_card *card = data; @@ -394,10 +454,10 @@ static irqreturn_t if_cs_interrupt(int irq, void *data) lbs_deb_enter(LBS_DEB_CS); - cause = if_cs_read16(card, IF_CS_C_INT_CAUSE); - if_cs_write16(card, IF_CS_C_INT_CAUSE, cause & IF_CS_C_IC_MASK); - + /* Ask card interrupt cause register if there is something for us */ + cause = if_cs_read16(card, IF_CS_CARD_INT_CAUSE); lbs_deb_cs("cause 0x%04x\n", cause); + if (cause == 0) { /* Not for us */ return IRQ_NONE; @@ -409,11 +469,7 @@ static irqreturn_t if_cs_interrupt(int irq, void *data) return IRQ_HANDLED; } - /* TODO: I'm not sure what the best ordering is */ - - cause = if_cs_read16(card, IF_CS_C_STATUS) & IF_CS_C_S_MASK; - - if (cause & IF_CS_C_S_RX_UPLD_RDY) { + if (cause & IF_CS_BIT_RX) { struct sk_buff *skb; lbs_deb_cs("rx packet\n"); skb = if_cs_receive_data(priv); @@ -421,16 +477,16 @@ static irqreturn_t if_cs_interrupt(int irq, void *data) lbs_process_rxed_packet(priv, skb); } - if (cause & IF_CS_H_IC_TX_OVER) { - lbs_deb_cs("tx over\n"); + if (cause & IF_CS_BIT_TX) { + lbs_deb_cs("tx done\n"); lbs_host_to_card_done(priv); } - if (cause & IF_CS_C_S_CMD_UPLD_RDY) { + if (cause & IF_CS_BIT_RESP) { unsigned long flags; u8 i; - lbs_deb_cs("cmd upload ready\n"); + lbs_deb_cs("cmd resp\n"); spin_lock_irqsave(&priv->driver_lock, flags); i = (priv->resp_idx == 0) ? 1 : 0; spin_unlock_irqrestore(&priv->driver_lock, flags); @@ -444,15 +500,17 @@ static irqreturn_t if_cs_interrupt(int irq, void *data) spin_unlock_irqrestore(&priv->driver_lock, flags); } - if (cause & IF_CS_H_IC_HOST_EVENT) { - u16 event = if_cs_read16(priv->card, IF_CS_C_STATUS) - & IF_CS_C_S_STATUS_MASK; - if_cs_write16(priv->card, IF_CS_H_INT_CAUSE, - IF_CS_H_IC_HOST_EVENT); - lbs_deb_cs("eventcause 0x%04x\n", event); - lbs_queue_event(priv, event >> 8 & 0xff); + if (cause & IF_CS_BIT_EVENT) { + u16 status = if_cs_read16(priv->card, IF_CS_CARD_STATUS); + if_cs_write16(priv->card, IF_CS_HOST_INT_CAUSE, + IF_CS_BIT_EVENT); + lbs_queue_event(priv, (status & IF_CS_CARD_STATUS_MASK) >> 8); } + /* Clear interrupt cause */ + if_cs_write16(card, IF_CS_CARD_INT_CAUSE, cause & IF_CS_BIT_MASK); + + lbs_deb_leave(LBS_DEB_CS); return IRQ_HANDLED; } @@ -482,11 +540,11 @@ static int if_cs_prog_helper(struct if_cs_card *card) /* "If the value is 0x5a, the firmware is already * downloaded successfully" */ - if (scratch == 0x5a) + if (scratch == IF_CS_SCRATCH_HELPER_OK) goto done; /* "If the value is != 00, it is invalid value of register */ - if (scratch != 0x00) { + if (scratch != IF_CS_SCRATCH_BOOT_OK) { ret = -ENODEV; goto done; } @@ -514,26 +572,26 @@ static int if_cs_prog_helper(struct if_cs_card *card) /* "write the number of bytes to be sent to the I/O Command * write length register" */ - if_cs_write16(card, IF_CS_H_CMD_LEN, count); + if_cs_write16(card, IF_CS_CMD_LEN, count); /* "write this to I/O Command port register as 16 bit writes */ if (count) - if_cs_write16_rep(card, IF_CS_H_CMD, + if_cs_write16_rep(card, IF_CS_CMD, &fw->data[sent], count >> 1); /* "Assert the download over interrupt command in the Host * status register" */ - if_cs_write8(card, IF_CS_H_STATUS, IF_CS_H_STATUS_DNLD_OVER); + if_cs_write8(card, IF_CS_HOST_STATUS, IF_CS_BIT_COMMAND); /* "Assert the download over interrupt command in the Card * interrupt case register" */ - if_cs_write16(card, IF_CS_H_INT_CAUSE, IF_CS_H_IC_DNLD_OVER); + if_cs_write16(card, IF_CS_HOST_INT_CAUSE, IF_CS_BIT_COMMAND); /* "The host polls the Card Status register ... for 50 ms before declaring a failure */ - ret = if_cs_poll_while_fw_download(card, IF_CS_C_STATUS, - IF_CS_C_S_CMD_DNLD_RDY); + ret = if_cs_poll_while_fw_download(card, IF_CS_CARD_STATUS, + IF_CS_BIT_COMMAND); if (ret < 0) { lbs_pr_err("can't download helper at 0x%x, ret %d\n", sent, ret); @@ -575,14 +633,15 @@ static int if_cs_prog_real(struct if_cs_card *card) } lbs_deb_cs("fw size %td\n", fw->size); - ret = if_cs_poll_while_fw_download(card, IF_CS_C_SQ_READ_LOW, IF_CS_C_SQ_HELPER_OK); + ret = if_cs_poll_while_fw_download(card, IF_CS_SQ_READ_LOW, + IF_CS_SQ_HELPER_OK); if (ret < 0) { lbs_pr_err("helper firmware doesn't answer\n"); goto err_release; } for (sent = 0; sent < fw->size; sent += len) { - len = if_cs_read16(card, IF_CS_C_SQ_READ_LOW); + len = if_cs_read16(card, IF_CS_SQ_READ_LOW); if (len & 1) { retry++; lbs_pr_info("odd, need to retry this firmware block\n"); @@ -600,16 +659,16 @@ static int if_cs_prog_real(struct if_cs_card *card) } - if_cs_write16(card, IF_CS_H_CMD_LEN, len); + if_cs_write16(card, IF_CS_CMD_LEN, len); - if_cs_write16_rep(card, IF_CS_H_CMD, + if_cs_write16_rep(card, IF_CS_CMD, &fw->data[sent], (len+1) >> 1); - if_cs_write8(card, IF_CS_H_STATUS, IF_CS_H_STATUS_DNLD_OVER); - if_cs_write16(card, IF_CS_H_INT_CAUSE, IF_CS_H_IC_DNLD_OVER); + if_cs_write8(card, IF_CS_HOST_STATUS, IF_CS_BIT_COMMAND); + if_cs_write16(card, IF_CS_HOST_INT_CAUSE, IF_CS_BIT_COMMAND); - ret = if_cs_poll_while_fw_download(card, IF_CS_C_STATUS, - IF_CS_C_S_CMD_DNLD_RDY); + ret = if_cs_poll_while_fw_download(card, IF_CS_CARD_STATUS, + IF_CS_BIT_COMMAND); if (ret < 0) { lbs_pr_err("can't download firmware at 0x%x\n", sent); goto err_release; @@ -806,6 +865,12 @@ static int if_cs_probe(struct pcmcia_device *p_dev) p_dev->irq.AssignedIRQ, p_dev->io.BasePort1, 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) { + lbs_pr_err("old chips like 8385 rev B1 aren't supported\n"); + ret = -ENODEV; + goto out2; + } /* Load the firmware early, before calling into libertas.ko */ ret = if_cs_prog_helper(card); @@ -837,7 +902,7 @@ static int if_cs_probe(struct pcmcia_device *p_dev) /* Clear any interrupt cause that happend while sending * firmware/initializing card */ - if_cs_write16(card, IF_CS_C_INT_CAUSE, IF_CS_C_IC_MASK); + if_cs_write16(card, IF_CS_CARD_INT_CAUSE, IF_CS_BIT_MASK); if_cs_enable_ints(card); /* And finally bring the card up */ diff --git a/drivers/net/wireless/libertas/if_usb.c b/drivers/net/wireless/libertas/if_usb.c index 4dcd4092e0f0..632c291404ab 100644 --- a/drivers/net/wireless/libertas/if_usb.c +++ b/drivers/net/wireless/libertas/if_usb.c @@ -7,6 +7,10 @@ #include <linux/netdevice.h> #include <linux/usb.h> +#ifdef CONFIG_OLPC +#include <asm/olpc.h> +#endif + #define DRV_NAME "usb8xxx" #include "host.h" @@ -146,6 +150,14 @@ static void if_usb_fw_timeo(unsigned long priv) wake_up(&cardp->fw_wq); } +#ifdef CONFIG_OLPC +static void if_usb_reset_olpc_card(struct lbs_private *priv) +{ + printk(KERN_CRIT "Resetting OLPC wireless via EC...\n"); + olpc_ec_cmd(0x25, NULL, 0, NULL, 0); +} +#endif + /** * @brief sets the configuration values * @param ifnum interface number @@ -231,6 +243,11 @@ static int if_usb_probe(struct usb_interface *intf, cardp->priv->fw_ready = 1; priv->hw_host_to_card = if_usb_host_to_card; +#ifdef CONFIG_OLPC + if (machine_is_olpc()) + priv->reset_card = if_usb_reset_olpc_card; +#endif + cardp->boot2_version = udev->descriptor.bcdDevice; if_usb_submit_rx_urb(cardp); @@ -364,6 +381,11 @@ static int if_usb_reset_device(struct if_usb_card *cardp) ret = usb_reset_device(cardp->udev); msleep(100); +#ifdef CONFIG_OLPC + if (ret && machine_is_olpc()) + if_usb_reset_olpc_card(NULL); +#endif + lbs_deb_leave_args(LBS_DEB_USB, "ret %d", ret); return ret; diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c index acfc4bfcc262..14d5d61cec4c 100644 --- a/drivers/net/wireless/libertas/main.c +++ b/drivers/net/wireless/libertas/main.c @@ -11,6 +11,7 @@ #include <linux/if_arp.h> #include <linux/kthread.h> #include <linux/kfifo.h> +#include <linux/stddef.h> #include <net/iw_handler.h> #include <net/ieee80211.h> @@ -343,14 +344,15 @@ static ssize_t lbs_mesh_set(struct device *dev, { struct lbs_private *priv = to_net_dev(dev)->priv; int enable; - int ret; + int ret, action = CMD_ACT_MESH_CONFIG_STOP; sscanf(buf, "%x", &enable); enable = !!enable; if (enable == !!priv->mesh_dev) return count; - - ret = lbs_mesh_config(priv, enable, priv->curbssparams.channel); + if (enable) + action = CMD_ACT_MESH_CONFIG_START; + ret = lbs_mesh_config(priv, action, priv->curbssparams.channel); if (ret) return ret; @@ -446,6 +448,8 @@ static int lbs_mesh_stop(struct net_device *dev) spin_unlock_irq(&priv->driver_lock); + schedule_work(&priv->mcast_work); + lbs_deb_leave(LBS_DEB_MESH); return 0; } @@ -467,6 +471,8 @@ static int lbs_eth_stop(struct net_device *dev) netif_stop_queue(dev); spin_unlock_irq(&priv->driver_lock); + schedule_work(&priv->mcast_work); + lbs_deb_leave(LBS_DEB_NET); return 0; } @@ -563,89 +569,116 @@ done: return ret; } -static int lbs_copy_multicast_address(struct lbs_private *priv, - struct net_device *dev) + +static inline int mac_in_list(unsigned char *list, int list_len, + unsigned char *mac) { - int i = 0; - struct dev_mc_list *mcptr = dev->mc_list; + while (list_len) { + if (!memcmp(list, mac, ETH_ALEN)) + return 1; + list += ETH_ALEN; + list_len--; + } + return 0; +} + + +static int lbs_add_mcast_addrs(struct cmd_ds_mac_multicast_adr *cmd, + struct net_device *dev, int nr_addrs) +{ + int i = nr_addrs; + struct dev_mc_list *mc_list; + DECLARE_MAC_BUF(mac); + + if ((dev->flags & (IFF_UP|IFF_MULTICAST)) != (IFF_UP|IFF_MULTICAST)) + return nr_addrs; + + netif_addr_lock_bh(dev); + for (mc_list = dev->mc_list; mc_list; mc_list = mc_list->next) { + if (mac_in_list(cmd->maclist, nr_addrs, mc_list->dmi_addr)) { + lbs_deb_net("mcast address %s:%s skipped\n", dev->name, + print_mac(mac, mc_list->dmi_addr)); + continue; + } - for (i = 0; i < dev->mc_count; i++) { - memcpy(&priv->multicastlist[i], mcptr->dmi_addr, ETH_ALEN); - mcptr = mcptr->next; + if (i == MRVDRV_MAX_MULTICAST_LIST_SIZE) + break; + memcpy(&cmd->maclist[6*i], mc_list->dmi_addr, ETH_ALEN); + lbs_deb_net("mcast address %s:%s added to filter\n", dev->name, + print_mac(mac, mc_list->dmi_addr)); + i++; } + netif_addr_unlock_bh(dev); + if (mc_list) + return -EOVERFLOW; + return i; } -static void lbs_set_multicast_list(struct net_device *dev) +static void lbs_set_mcast_worker(struct work_struct *work) { - struct lbs_private *priv = dev->priv; - int old_mac_control; - DECLARE_MAC_BUF(mac); + struct lbs_private *priv = container_of(work, struct lbs_private, mcast_work); + struct cmd_ds_mac_multicast_adr mcast_cmd; + int dev_flags; + int nr_addrs; + int old_mac_control = priv->mac_control; lbs_deb_enter(LBS_DEB_NET); - old_mac_control = priv->mac_control; - - if (dev->flags & IFF_PROMISC) { - lbs_deb_net("enable promiscuous mode\n"); - priv->mac_control |= - CMD_ACT_MAC_PROMISCUOUS_ENABLE; - priv->mac_control &= - ~(CMD_ACT_MAC_ALL_MULTICAST_ENABLE | - CMD_ACT_MAC_MULTICAST_ENABLE); - } else { - /* Multicast */ - priv->mac_control &= - ~CMD_ACT_MAC_PROMISCUOUS_ENABLE; - - if (dev->flags & IFF_ALLMULTI || dev->mc_count > - MRVDRV_MAX_MULTICAST_LIST_SIZE) { - lbs_deb_net( "enabling all multicast\n"); - priv->mac_control |= - CMD_ACT_MAC_ALL_MULTICAST_ENABLE; - priv->mac_control &= - ~CMD_ACT_MAC_MULTICAST_ENABLE; - } else { - priv->mac_control &= - ~CMD_ACT_MAC_ALL_MULTICAST_ENABLE; - - if (!dev->mc_count) { - lbs_deb_net("no multicast addresses, " - "disabling multicast\n"); - priv->mac_control &= - ~CMD_ACT_MAC_MULTICAST_ENABLE; - } else { - int i; - - priv->mac_control |= - CMD_ACT_MAC_MULTICAST_ENABLE; - - priv->nr_of_multicastmacaddr = - lbs_copy_multicast_address(priv, dev); - - lbs_deb_net("multicast addresses: %d\n", - dev->mc_count); - - for (i = 0; i < dev->mc_count; i++) { - lbs_deb_net("Multicast address %d: %s\n", - i, print_mac(mac, - priv->multicastlist[i])); - } - /* send multicast addresses to firmware */ - lbs_prepare_and_send_command(priv, - CMD_MAC_MULTICAST_ADR, - CMD_ACT_SET, 0, 0, - NULL); - } - } + dev_flags = priv->dev->flags; + if (priv->mesh_dev) + dev_flags |= priv->mesh_dev->flags; + + if (dev_flags & IFF_PROMISC) { + priv->mac_control |= CMD_ACT_MAC_PROMISCUOUS_ENABLE; + priv->mac_control &= ~(CMD_ACT_MAC_ALL_MULTICAST_ENABLE | + CMD_ACT_MAC_MULTICAST_ENABLE); + goto out_set_mac_control; + } else if (dev_flags & IFF_ALLMULTI) { + do_allmulti: + priv->mac_control |= CMD_ACT_MAC_ALL_MULTICAST_ENABLE; + priv->mac_control &= ~(CMD_ACT_MAC_PROMISCUOUS_ENABLE | + CMD_ACT_MAC_MULTICAST_ENABLE); + goto out_set_mac_control; } + /* Once for priv->dev, again for priv->mesh_dev if it exists */ + nr_addrs = lbs_add_mcast_addrs(&mcast_cmd, priv->dev, 0); + if (nr_addrs >= 0 && priv->mesh_dev) + nr_addrs = lbs_add_mcast_addrs(&mcast_cmd, priv->mesh_dev, nr_addrs); + if (nr_addrs < 0) + goto do_allmulti; + + if (nr_addrs) { + int size = offsetof(struct cmd_ds_mac_multicast_adr, + maclist[6*nr_addrs]); + + mcast_cmd.action = cpu_to_le16(CMD_ACT_SET); + mcast_cmd.hdr.size = cpu_to_le16(size); + mcast_cmd.nr_of_adrs = cpu_to_le16(nr_addrs); + + lbs_cmd_async(priv, CMD_MAC_MULTICAST_ADR, &mcast_cmd.hdr, size); + + priv->mac_control |= CMD_ACT_MAC_MULTICAST_ENABLE; + } else + priv->mac_control &= ~CMD_ACT_MAC_MULTICAST_ENABLE; + + priv->mac_control &= ~(CMD_ACT_MAC_PROMISCUOUS_ENABLE | + CMD_ACT_MAC_ALL_MULTICAST_ENABLE); + out_set_mac_control: if (priv->mac_control != old_mac_control) lbs_set_mac_control(priv); lbs_deb_leave(LBS_DEB_NET); } +static void lbs_set_multicast_list(struct net_device *dev) +{ + struct lbs_private *priv = dev->priv; + + schedule_work(&priv->mcast_work); +} + /** * @brief This function handles the major jobs in the LBS driver. * It handles all events generated by firmware, RX data received @@ -689,20 +722,20 @@ static int lbs_thread(void *data) shouldsleep = 1; /* Something is en route to the device already */ else if (priv->tx_pending_len > 0) shouldsleep = 0; /* We've a packet to send */ + else if (priv->resp_len[priv->resp_idx]) + shouldsleep = 0; /* We have a command response */ else if (priv->cur_cmd) shouldsleep = 1; /* Can't send a command; one already running */ else if (!list_empty(&priv->cmdpendingq)) shouldsleep = 0; /* We have a command to send */ else if (__kfifo_len(priv->event_fifo)) shouldsleep = 0; /* We have an event to process */ - else if (priv->resp_len[priv->resp_idx]) - shouldsleep = 0; /* We have a command response */ else shouldsleep = 1; /* No command */ if (shouldsleep) { lbs_deb_thread("sleeping, connect_status %d, " - "ps_mode %d, ps_state %d\n", + "psmode %d, psstate %d\n", priv->connect_status, priv->psmode, priv->psstate); spin_unlock_irq(&priv->driver_lock); @@ -749,16 +782,21 @@ static int lbs_thread(void *data) if (priv->cmd_timed_out && priv->cur_cmd) { struct cmd_ctrl_node *cmdnode = priv->cur_cmd; - if (++priv->nr_retries > 10) { - lbs_pr_info("Excessive timeouts submitting command %x\n", - le16_to_cpu(cmdnode->cmdbuf->command)); + if (++priv->nr_retries > 3) { + lbs_pr_info("Excessive timeouts submitting " + "command 0x%04x\n", + le16_to_cpu(cmdnode->cmdbuf->command)); lbs_complete_command(priv, cmdnode, -ETIMEDOUT); priv->nr_retries = 0; + if (priv->reset_card) + priv->reset_card(priv); } else { priv->cur_cmd = NULL; priv->dnld_sent = DNLD_RES_RECEIVED; - lbs_pr_info("requeueing command %x due to timeout (#%d)\n", - le16_to_cpu(cmdnode->cmdbuf->command), priv->nr_retries); + lbs_pr_info("requeueing command 0x%04x due " + "to timeout (#%d)\n", + le16_to_cpu(cmdnode->cmdbuf->command), + priv->nr_retries); /* Stick it back at the _top_ of the pending queue for immediate resubmission */ @@ -890,7 +928,7 @@ int lbs_suspend(struct lbs_private *priv) } EXPORT_SYMBOL_GPL(lbs_suspend); -int lbs_resume(struct lbs_private *priv) +void lbs_resume(struct lbs_private *priv) { lbs_deb_enter(LBS_DEB_FW); @@ -906,7 +944,6 @@ int lbs_resume(struct lbs_private *priv) netif_device_attach(priv->mesh_dev); lbs_deb_leave(LBS_DEB_FW); - return 0; } EXPORT_SYMBOL_GPL(lbs_resume); @@ -929,20 +966,10 @@ static int lbs_setup_firmware(struct lbs_private *priv) */ memset(priv->current_addr, 0xff, ETH_ALEN); ret = lbs_update_hw_spec(priv); - if (ret) { - ret = -1; + if (ret) goto done; - } lbs_set_mac_control(priv); - - ret = lbs_get_data_rate(priv); - if (ret < 0) { - ret = -1; - goto done; - } - - ret = 0; done: lbs_deb_leave_args(LBS_DEB_FW, "ret %d", ret); return ret; @@ -960,12 +987,11 @@ static void command_timer_fn(unsigned long data) lbs_deb_enter(LBS_DEB_CMD); spin_lock_irqsave(&priv->driver_lock, flags); - if (!priv->cur_cmd) { - lbs_pr_info("Command timer expired; no pending command\n"); + if (!priv->cur_cmd) goto out; - } - lbs_pr_info("Command %x timed out\n", le16_to_cpu(priv->cur_cmd->cmdbuf->command)); + lbs_pr_info("command 0x%04x timed out\n", + le16_to_cpu(priv->cur_cmd->cmdbuf->command)); priv->cmd_timed_out = 1; wake_up_interruptible(&priv->waitq); @@ -1019,7 +1045,7 @@ static int lbs_init_adapter(struct lbs_private *priv) priv->curbssparams.channel = DEFAULT_AD_HOC_CHANNEL; priv->mac_control = CMD_ACT_MAC_RX_ON | CMD_ACT_MAC_TX_ON; priv->radioon = RADIO_ON; - priv->auto_rate = 1; + priv->enablehwauto = 1; priv->capability = WLAN_CAPABILITY_SHORT_PREAMBLE; priv->psmode = LBS802_11POWERMODECAM; priv->psstate = PS_STATE_FULL_POWER; @@ -1134,6 +1160,7 @@ struct lbs_private *lbs_add_card(void *card, struct device *dmdev) priv->work_thread = create_singlethread_workqueue("lbs_worker"); INIT_DELAYED_WORK(&priv->assoc_work, lbs_association_worker); INIT_DELAYED_WORK(&priv->scan_work, lbs_scan_worker); + INIT_WORK(&priv->mcast_work, lbs_set_mcast_worker); INIT_WORK(&priv->sync_channel, lbs_sync_channel_worker); sprintf(priv->mesh_ssid, "mesh"); @@ -1156,7 +1183,7 @@ done: EXPORT_SYMBOL_GPL(lbs_add_card); -int lbs_remove_card(struct lbs_private *priv) +void lbs_remove_card(struct lbs_private *priv) { struct net_device *dev = priv->dev; union iwreq_data wrqu; @@ -1168,8 +1195,9 @@ int lbs_remove_card(struct lbs_private *priv) dev = priv->dev; - cancel_delayed_work(&priv->scan_work); - cancel_delayed_work(&priv->assoc_work); + cancel_delayed_work_sync(&priv->scan_work); + cancel_delayed_work_sync(&priv->assoc_work); + cancel_work_sync(&priv->mcast_work); destroy_workqueue(priv->work_thread); if (priv->psmode == LBS802_11POWERMODEMAX_PSP) { @@ -1191,7 +1219,6 @@ int lbs_remove_card(struct lbs_private *priv) free_netdev(dev); lbs_deb_leave(LBS_DEB_MAIN); - return 0; } EXPORT_SYMBOL_GPL(lbs_remove_card); @@ -1236,9 +1263,11 @@ int lbs_start_card(struct lbs_private *priv) useful */ priv->mesh_tlv = 0x100 + 291; - if (lbs_mesh_config(priv, 1, priv->curbssparams.channel)) { + if (lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START, + priv->curbssparams.channel)) { priv->mesh_tlv = 0x100 + 37; - if (lbs_mesh_config(priv, 1, priv->curbssparams.channel)) + if (lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START, + priv->curbssparams.channel)) priv->mesh_tlv = 0; } if (priv->mesh_tlv) { @@ -1262,24 +1291,28 @@ done: EXPORT_SYMBOL_GPL(lbs_start_card); -int lbs_stop_card(struct lbs_private *priv) +void lbs_stop_card(struct lbs_private *priv) { struct net_device *dev = priv->dev; - int ret = -1; struct cmd_ctrl_node *cmdnode; unsigned long flags; lbs_deb_enter(LBS_DEB_MAIN); + if (!priv) + goto out; + netif_stop_queue(priv->dev); netif_carrier_off(priv->dev); lbs_debugfs_remove_one(priv); device_remove_file(&dev->dev, &dev_attr_lbs_rtap); - if (priv->mesh_tlv) + if (priv->mesh_tlv) { device_remove_file(&dev->dev, &dev_attr_lbs_mesh); + } /* Flush pending command nodes */ + del_timer_sync(&priv->command_timer); spin_lock_irqsave(&priv->driver_lock, flags); list_for_each_entry(cmdnode, &priv->cmdpendingq, list) { cmdnode->result = -ENOENT; @@ -1290,8 +1323,8 @@ int lbs_stop_card(struct lbs_private *priv) unregister_netdev(dev); - lbs_deb_leave_args(LBS_DEB_MAIN, "ret %d", ret); - return ret; +out: + lbs_deb_leave(LBS_DEB_MAIN); } EXPORT_SYMBOL_GPL(lbs_stop_card); @@ -1332,6 +1365,8 @@ static int lbs_add_mesh(struct lbs_private *priv) #ifdef WIRELESS_EXT mesh_dev->wireless_handlers = (struct iw_handler_def *)&mesh_handler_def; #endif + mesh_dev->flags |= IFF_BROADCAST | IFF_MULTICAST; + mesh_dev->set_multicast_list = lbs_set_multicast_list; /* Register virtual mesh interface */ ret = register_netdev(mesh_dev); if (ret) { @@ -1343,6 +1378,8 @@ static int lbs_add_mesh(struct lbs_private *priv) if (ret) goto err_unregister; + lbs_persist_config_init(mesh_dev); + /* Everything successful */ ret = 0; goto done; @@ -1369,8 +1406,9 @@ static void lbs_remove_mesh(struct lbs_private *priv) lbs_deb_enter(LBS_DEB_MESH); netif_stop_queue(mesh_dev); - netif_carrier_off(priv->mesh_dev); + netif_carrier_off(mesh_dev); sysfs_remove_group(&(mesh_dev->dev.kobj), &lbs_mesh_attr_group); + lbs_persist_config_remove(mesh_dev); unregister_netdev(mesh_dev); priv->mesh_dev = NULL; free_netdev(mesh_dev); @@ -1533,10 +1571,11 @@ static void lbs_remove_rtap(struct lbs_private *priv) { lbs_deb_enter(LBS_DEB_MAIN); if (priv->rtap_net_dev == NULL) - return; + goto out; unregister_netdev(priv->rtap_net_dev); free_netdev(priv->rtap_net_dev); priv->rtap_net_dev = NULL; +out: lbs_deb_leave(LBS_DEB_MAIN); } @@ -1563,7 +1602,6 @@ static int lbs_add_rtap(struct lbs_private *priv) rtap_dev->stop = lbs_rtap_stop; rtap_dev->get_stats = lbs_rtap_get_stats; rtap_dev->hard_start_xmit = lbs_rtap_hard_start_xmit; - rtap_dev->set_multicast_list = lbs_set_multicast_list; rtap_dev->priv = priv; SET_NETDEV_DEV(rtap_dev, priv->dev->dev.parent); diff --git a/drivers/net/wireless/libertas/persistcfg.c b/drivers/net/wireless/libertas/persistcfg.c new file mode 100644 index 000000000000..6d0ff8decaf7 --- /dev/null +++ b/drivers/net/wireless/libertas/persistcfg.c @@ -0,0 +1,453 @@ +#include <linux/moduleparam.h> +#include <linux/delay.h> +#include <linux/etherdevice.h> +#include <linux/netdevice.h> +#include <linux/if_arp.h> +#include <linux/kthread.h> +#include <linux/kfifo.h> + +#include "host.h" +#include "decl.h" +#include "dev.h" +#include "wext.h" +#include "debugfs.h" +#include "scan.h" +#include "assoc.h" +#include "cmd.h" + +static int mesh_get_default_parameters(struct device *dev, + struct mrvl_mesh_defaults *defs) +{ + struct lbs_private *priv = to_net_dev(dev)->priv; + struct cmd_ds_mesh_config cmd; + int ret; + + memset(&cmd, 0, sizeof(struct cmd_ds_mesh_config)); + ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_GET, + CMD_TYPE_MESH_GET_DEFAULTS); + + if (ret) + return -EOPNOTSUPP; + + memcpy(defs, &cmd.data[0], sizeof(struct mrvl_mesh_defaults)); + + return 0; +} + +/** + * @brief Get function for sysfs attribute bootflag + */ +static ssize_t bootflag_get(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct mrvl_mesh_defaults defs; + int ret; + + ret = mesh_get_default_parameters(dev, &defs); + + if (ret) + return ret; + + return snprintf(buf, 12, "0x%x\n", le32_to_cpu(defs.bootflag)); +} + +/** + * @brief Set function for sysfs attribute bootflag + */ +static ssize_t bootflag_set(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct lbs_private *priv = to_net_dev(dev)->priv; + struct cmd_ds_mesh_config cmd; + uint32_t datum; + int ret; + + memset(&cmd, 0, sizeof(cmd)); + ret = sscanf(buf, "%x", &datum); + if (ret != 1) + return -EINVAL; + + *((__le32 *)&cmd.data[0]) = cpu_to_le32(!!datum); + cmd.length = cpu_to_le16(sizeof(uint32_t)); + ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET, + CMD_TYPE_MESH_SET_BOOTFLAG); + if (ret) + return ret; + + return strlen(buf); +} + +/** + * @brief Get function for sysfs attribute boottime + */ +static ssize_t boottime_get(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct mrvl_mesh_defaults defs; + int ret; + + ret = mesh_get_default_parameters(dev, &defs); + + if (ret) + return ret; + + return snprintf(buf, 12, "0x%x\n", defs.boottime); +} + +/** + * @brief Set function for sysfs attribute boottime + */ +static ssize_t boottime_set(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct lbs_private *priv = to_net_dev(dev)->priv; + struct cmd_ds_mesh_config cmd; + uint32_t datum; + int ret; + + memset(&cmd, 0, sizeof(cmd)); + ret = sscanf(buf, "%x", &datum); + if (ret != 1) + return -EINVAL; + + /* A too small boot time will result in the device booting into + * standalone (no-host) mode before the host can take control of it, + * so the change will be hard to revert. This may be a desired + * feature (e.g to configure a very fast boot time for devices that + * will not be attached to a host), but dangerous. So I'm enforcing a + * lower limit of 20 seconds: remove and recompile the driver if this + * does not work for you. + */ + datum = (datum < 20) ? 20 : datum; + cmd.data[0] = datum; + cmd.length = cpu_to_le16(sizeof(uint8_t)); + ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET, + CMD_TYPE_MESH_SET_BOOTTIME); + if (ret) + return ret; + + return strlen(buf); +} + +/** + * @brief Get function for sysfs attribute channel + */ +static ssize_t channel_get(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct mrvl_mesh_defaults defs; + int ret; + + ret = mesh_get_default_parameters(dev, &defs); + + if (ret) + return ret; + + return snprintf(buf, 12, "0x%x\n", le16_to_cpu(defs.channel)); +} + +/** + * @brief Set function for sysfs attribute channel + */ +static ssize_t channel_set(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct lbs_private *priv = to_net_dev(dev)->priv; + struct cmd_ds_mesh_config cmd; + uint16_t datum; + int ret; + + memset(&cmd, 0, sizeof(cmd)); + ret = sscanf(buf, "%hx", &datum); + if (ret != 1 || datum < 1 || datum > 11) + return -EINVAL; + + *((__le16 *)&cmd.data[0]) = cpu_to_le16(datum); + cmd.length = cpu_to_le16(sizeof(uint16_t)); + ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET, + CMD_TYPE_MESH_SET_DEF_CHANNEL); + if (ret) + return ret; + + return strlen(buf); +} + +/** + * @brief Get function for sysfs attribute mesh_id + */ +static ssize_t mesh_id_get(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct mrvl_mesh_defaults defs; + int maxlen; + int ret; + + ret = mesh_get_default_parameters(dev, &defs); + + if (ret) + return ret; + + if (defs.meshie.val.mesh_id_len > IW_ESSID_MAX_SIZE) { + lbs_pr_err("inconsistent mesh ID length"); + defs.meshie.val.mesh_id_len = IW_ESSID_MAX_SIZE; + } + + /* SSID not null terminated: reserve room for \0 + \n */ + maxlen = defs.meshie.val.mesh_id_len + 2; + maxlen = (PAGE_SIZE > maxlen) ? maxlen : PAGE_SIZE; + + defs.meshie.val.mesh_id[defs.meshie.val.mesh_id_len] = '\0'; + + return snprintf(buf, maxlen, "%s\n", defs.meshie.val.mesh_id); +} + +/** + * @brief Set function for sysfs attribute mesh_id + */ +static ssize_t mesh_id_set(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct cmd_ds_mesh_config cmd; + struct mrvl_mesh_defaults defs; + struct mrvl_meshie *ie; + struct lbs_private *priv = to_net_dev(dev)->priv; + int len; + int ret; + + if (count < 2 || count > IW_ESSID_MAX_SIZE + 1) + return -EINVAL; + + memset(&cmd, 0, sizeof(struct cmd_ds_mesh_config)); + ie = (struct mrvl_meshie *) &cmd.data[0]; + + /* fetch all other Information Element parameters */ + ret = mesh_get_default_parameters(dev, &defs); + + cmd.length = cpu_to_le16(sizeof(struct mrvl_meshie)); + + /* transfer IE elements */ + memcpy(ie, &defs.meshie, sizeof(struct mrvl_meshie)); + + len = count - 1; + memcpy(ie->val.mesh_id, buf, len); + /* SSID len */ + ie->val.mesh_id_len = len; + /* IE len */ + ie->hdr.len = sizeof(struct mrvl_meshie_val) - IW_ESSID_MAX_SIZE + len; + + ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET, + CMD_TYPE_MESH_SET_MESH_IE); + if (ret) + return ret; + + return strlen(buf); +} + +/** + * @brief Get function for sysfs attribute protocol_id + */ +static ssize_t protocol_id_get(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct mrvl_mesh_defaults defs; + int ret; + + ret = mesh_get_default_parameters(dev, &defs); + + if (ret) + return ret; + + return snprintf(buf, 5, "%d\n", defs.meshie.val.active_protocol_id); +} + +/** + * @brief Set function for sysfs attribute protocol_id + */ +static ssize_t protocol_id_set(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct cmd_ds_mesh_config cmd; + struct mrvl_mesh_defaults defs; + struct mrvl_meshie *ie; + struct lbs_private *priv = to_net_dev(dev)->priv; + uint32_t datum; + int ret; + + memset(&cmd, 0, sizeof(cmd)); + ret = sscanf(buf, "%x", &datum); + if (ret != 1) + return -EINVAL; + + /* fetch all other Information Element parameters */ + ret = mesh_get_default_parameters(dev, &defs); + + cmd.length = cpu_to_le16(sizeof(struct mrvl_meshie)); + + /* transfer IE elements */ + ie = (struct mrvl_meshie *) &cmd.data[0]; + memcpy(ie, &defs.meshie, sizeof(struct mrvl_meshie)); + /* update protocol id */ + ie->val.active_protocol_id = datum; + + ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET, + CMD_TYPE_MESH_SET_MESH_IE); + if (ret) + return ret; + + return strlen(buf); +} + +/** + * @brief Get function for sysfs attribute metric_id + */ +static ssize_t metric_id_get(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct mrvl_mesh_defaults defs; + int ret; + + ret = mesh_get_default_parameters(dev, &defs); + + if (ret) + return ret; + + return snprintf(buf, 5, "%d\n", defs.meshie.val.active_metric_id); +} + +/** + * @brief Set function for sysfs attribute metric_id + */ +static ssize_t metric_id_set(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct cmd_ds_mesh_config cmd; + struct mrvl_mesh_defaults defs; + struct mrvl_meshie *ie; + struct lbs_private *priv = to_net_dev(dev)->priv; + uint32_t datum; + int ret; + + memset(&cmd, 0, sizeof(cmd)); + ret = sscanf(buf, "%x", &datum); + if (ret != 1) + return -EINVAL; + + /* fetch all other Information Element parameters */ + ret = mesh_get_default_parameters(dev, &defs); + + cmd.length = cpu_to_le16(sizeof(struct mrvl_meshie)); + + /* transfer IE elements */ + ie = (struct mrvl_meshie *) &cmd.data[0]; + memcpy(ie, &defs.meshie, sizeof(struct mrvl_meshie)); + /* update metric id */ + ie->val.active_metric_id = datum; + + ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET, + CMD_TYPE_MESH_SET_MESH_IE); + if (ret) + return ret; + + return strlen(buf); +} + +/** + * @brief Get function for sysfs attribute capability + */ +static ssize_t capability_get(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct mrvl_mesh_defaults defs; + int ret; + + ret = mesh_get_default_parameters(dev, &defs); + + if (ret) + return ret; + + return snprintf(buf, 5, "%d\n", defs.meshie.val.mesh_capability); +} + +/** + * @brief Set function for sysfs attribute capability + */ +static ssize_t capability_set(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct cmd_ds_mesh_config cmd; + struct mrvl_mesh_defaults defs; + struct mrvl_meshie *ie; + struct lbs_private *priv = to_net_dev(dev)->priv; + uint32_t datum; + int ret; + + memset(&cmd, 0, sizeof(cmd)); + ret = sscanf(buf, "%x", &datum); + if (ret != 1) + return -EINVAL; + + /* fetch all other Information Element parameters */ + ret = mesh_get_default_parameters(dev, &defs); + + cmd.length = cpu_to_le16(sizeof(struct mrvl_meshie)); + + /* transfer IE elements */ + ie = (struct mrvl_meshie *) &cmd.data[0]; + memcpy(ie, &defs.meshie, sizeof(struct mrvl_meshie)); + /* update value */ + ie->val.mesh_capability = datum; + + ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET, + CMD_TYPE_MESH_SET_MESH_IE); + if (ret) + return ret; + + return strlen(buf); +} + + +static DEVICE_ATTR(bootflag, 0644, bootflag_get, bootflag_set); +static DEVICE_ATTR(boottime, 0644, boottime_get, boottime_set); +static DEVICE_ATTR(channel, 0644, channel_get, channel_set); +static DEVICE_ATTR(mesh_id, 0644, mesh_id_get, mesh_id_set); +static DEVICE_ATTR(protocol_id, 0644, protocol_id_get, protocol_id_set); +static DEVICE_ATTR(metric_id, 0644, metric_id_get, metric_id_set); +static DEVICE_ATTR(capability, 0644, capability_get, capability_set); + +static struct attribute *boot_opts_attrs[] = { + &dev_attr_bootflag.attr, + &dev_attr_boottime.attr, + &dev_attr_channel.attr, + NULL +}; + +static struct attribute_group boot_opts_group = { + .name = "boot_options", + .attrs = boot_opts_attrs, +}; + +static struct attribute *mesh_ie_attrs[] = { + &dev_attr_mesh_id.attr, + &dev_attr_protocol_id.attr, + &dev_attr_metric_id.attr, + &dev_attr_capability.attr, + NULL +}; + +static struct attribute_group mesh_ie_group = { + .name = "mesh_ie", + .attrs = mesh_ie_attrs, +}; + +void lbs_persist_config_init(struct net_device *dev) +{ + int ret; + ret = sysfs_create_group(&(dev->dev.kobj), &boot_opts_group); + ret = sysfs_create_group(&(dev->dev.kobj), &mesh_ie_group); +} + +void lbs_persist_config_remove(struct net_device *dev) +{ + sysfs_remove_group(&(dev->dev.kobj), &boot_opts_group); + sysfs_remove_group(&(dev->dev.kobj), &mesh_ie_group); +} diff --git a/drivers/net/wireless/libertas/rx.c b/drivers/net/wireless/libertas/rx.c index 05af7316f698..5749f22b296f 100644 --- a/drivers/net/wireless/libertas/rx.c +++ b/drivers/net/wireless/libertas/rx.c @@ -237,7 +237,7 @@ int lbs_process_rxed_packet(struct lbs_private *priv, struct sk_buff *skb) /* Take the data rate from the rxpd structure * only if the rate is auto */ - if (priv->auto_rate) + if (priv->enablehwauto) priv->cur_rate = lbs_fw_index_to_data_rate(p_rx_pd->rx_rate); lbs_compute_rssi(priv, p_rx_pd); @@ -383,7 +383,7 @@ static int process_rxed_802_11_packet(struct lbs_private *priv, /* Take the data rate from the rxpd structure * only if the rate is auto */ - if (priv->auto_rate) + if (priv->enablehwauto) priv->cur_rate = lbs_fw_index_to_data_rate(prxpd->rx_rate); lbs_compute_rssi(priv, prxpd); diff --git a/drivers/net/wireless/libertas/scan.c b/drivers/net/wireless/libertas/scan.c index 387d4878af2f..4b274562f965 100644 --- a/drivers/net/wireless/libertas/scan.c +++ b/drivers/net/wireless/libertas/scan.c @@ -776,8 +776,9 @@ out: #define MAX_CUSTOM_LEN 64 static inline char *lbs_translate_scan(struct lbs_private *priv, - char *start, char *stop, - struct bss_descriptor *bss) + struct iw_request_info *info, + char *start, char *stop, + struct bss_descriptor *bss) { struct chan_freq_power *cfp; char *current_val; /* For rates */ @@ -801,24 +802,24 @@ static inline char *lbs_translate_scan(struct lbs_private *priv, iwe.cmd = SIOCGIWAP; iwe.u.ap_addr.sa_family = ARPHRD_ETHER; memcpy(iwe.u.ap_addr.sa_data, &bss->bssid, ETH_ALEN); - start = iwe_stream_add_event(start, stop, &iwe, IW_EV_ADDR_LEN); + start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_ADDR_LEN); /* SSID */ iwe.cmd = SIOCGIWESSID; iwe.u.data.flags = 1; iwe.u.data.length = min((uint32_t) bss->ssid_len, (uint32_t) IW_ESSID_MAX_SIZE); - start = iwe_stream_add_point(start, stop, &iwe, bss->ssid); + start = iwe_stream_add_point(info, start, stop, &iwe, bss->ssid); /* Mode */ iwe.cmd = SIOCGIWMODE; iwe.u.mode = bss->mode; - start = iwe_stream_add_event(start, stop, &iwe, IW_EV_UINT_LEN); + start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_UINT_LEN); /* Frequency */ iwe.cmd = SIOCGIWFREQ; iwe.u.freq.m = (long)cfp->freq * 100000; iwe.u.freq.e = 1; - start = iwe_stream_add_event(start, stop, &iwe, IW_EV_FREQ_LEN); + start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_FREQ_LEN); /* Add quality statistics */ iwe.cmd = IWEVQUAL; @@ -852,7 +853,7 @@ static inline char *lbs_translate_scan(struct lbs_private *priv, nf = priv->NF[TYPE_RXPD][TYPE_AVG] / AVG_SCALE; iwe.u.qual.level = CAL_RSSI(snr, nf); } - start = iwe_stream_add_event(start, stop, &iwe, IW_EV_QUAL_LEN); + start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_QUAL_LEN); /* Add encryption capability */ iwe.cmd = SIOCGIWENCODE; @@ -862,9 +863,9 @@ static inline char *lbs_translate_scan(struct lbs_private *priv, iwe.u.data.flags = IW_ENCODE_DISABLED; } iwe.u.data.length = 0; - start = iwe_stream_add_point(start, stop, &iwe, bss->ssid); + start = iwe_stream_add_point(info, start, stop, &iwe, bss->ssid); - current_val = start + IW_EV_LCP_LEN; + current_val = start + iwe_stream_lcp_len(info); iwe.cmd = SIOCGIWRATE; iwe.u.bitrate.fixed = 0; @@ -874,19 +875,19 @@ static inline char *lbs_translate_scan(struct lbs_private *priv, for (j = 0; bss->rates[j] && (j < sizeof(bss->rates)); j++) { /* Bit rate given in 500 kb/s units */ iwe.u.bitrate.value = bss->rates[j] * 500000; - current_val = iwe_stream_add_value(start, current_val, - stop, &iwe, IW_EV_PARAM_LEN); + current_val = iwe_stream_add_value(info, start, current_val, + stop, &iwe, IW_EV_PARAM_LEN); } if ((bss->mode == IW_MODE_ADHOC) && priv->adhoccreate && !lbs_ssid_cmp(priv->curbssparams.ssid, priv->curbssparams.ssid_len, bss->ssid, bss->ssid_len)) { iwe.u.bitrate.value = 22 * 500000; - current_val = iwe_stream_add_value(start, current_val, + current_val = iwe_stream_add_value(info, start, current_val, stop, &iwe, IW_EV_PARAM_LEN); } /* Check if we added any event */ - if((current_val - start) > IW_EV_LCP_LEN) + if ((current_val - start) > iwe_stream_lcp_len(info)) start = current_val; memset(&iwe, 0, sizeof(iwe)); @@ -895,7 +896,7 @@ static inline char *lbs_translate_scan(struct lbs_private *priv, memcpy(buf, bss->wpa_ie, bss->wpa_ie_len); iwe.cmd = IWEVGENIE; iwe.u.data.length = bss->wpa_ie_len; - start = iwe_stream_add_point(start, stop, &iwe, buf); + start = iwe_stream_add_point(info, start, stop, &iwe, buf); } memset(&iwe, 0, sizeof(iwe)); @@ -904,7 +905,7 @@ static inline char *lbs_translate_scan(struct lbs_private *priv, memcpy(buf, bss->rsn_ie, bss->rsn_ie_len); iwe.cmd = IWEVGENIE; iwe.u.data.length = bss->rsn_ie_len; - start = iwe_stream_add_point(start, stop, &iwe, buf); + start = iwe_stream_add_point(info, start, stop, &iwe, buf); } if (bss->mesh) { @@ -915,7 +916,8 @@ static inline char *lbs_translate_scan(struct lbs_private *priv, p += snprintf(p, MAX_CUSTOM_LEN, "mesh-type: olpc"); iwe.u.data.length = p - custom; if (iwe.u.data.length) - start = iwe_stream_add_point(start, stop, &iwe, custom); + start = iwe_stream_add_point(info, start, stop, + &iwe, custom); } out: @@ -1036,7 +1038,7 @@ int lbs_get_scan(struct net_device *dev, struct iw_request_info *info, } /* Translate to WE format this entry */ - next_ev = lbs_translate_scan(priv, ev, stop, iter_bss); + next_ev = lbs_translate_scan(priv, info, ev, stop, iter_bss); if (next_ev == NULL) continue; ev = next_ev; diff --git a/drivers/net/wireless/libertas/types.h b/drivers/net/wireless/libertas/types.h index 4031be420862..e0c2599da92f 100644 --- a/drivers/net/wireless/libertas/types.h +++ b/drivers/net/wireless/libertas/types.h @@ -6,6 +6,8 @@ #include <linux/if_ether.h> #include <asm/byteorder.h> +#include <linux/wireless.h> +#include <net/ieee80211.h> struct ieeetypes_cfparamset { u8 elementid; @@ -252,4 +254,32 @@ struct mrvlietypes_ledbhv { struct led_bhv ledbhv[1]; } __attribute__ ((packed)); +/* Meant to be packed as the value member of a struct ieee80211_info_element. + * Note that the len member of the ieee80211_info_element varies depending on + * the mesh_id_len */ +struct mrvl_meshie_val { + uint8_t oui[P80211_OUI_LEN]; + uint8_t type; + uint8_t subtype; + uint8_t version; + uint8_t active_protocol_id; + uint8_t active_metric_id; + uint8_t mesh_capability; + uint8_t mesh_id_len; + uint8_t mesh_id[IW_ESSID_MAX_SIZE]; +} __attribute__ ((packed)); + +struct mrvl_meshie { + struct ieee80211_info_element hdr; + struct mrvl_meshie_val val; +} __attribute__ ((packed)); + +struct mrvl_mesh_defaults { + __le32 bootflag; + uint8_t boottime; + uint8_t reserved; + __le16 channel; + struct mrvl_meshie meshie; +} __attribute__ ((packed)); + #endif diff --git a/drivers/net/wireless/libertas/wext.c b/drivers/net/wireless/libertas/wext.c index 0973d015a520..8b3ed77860b3 100644 --- a/drivers/net/wireless/libertas/wext.c +++ b/drivers/net/wireless/libertas/wext.c @@ -1002,7 +1002,7 @@ static int lbs_mesh_set_freq(struct net_device *dev, else if (priv->mode == IW_MODE_ADHOC) lbs_stop_adhoc_network(priv); } - lbs_mesh_config(priv, 1, fwrq->m); + lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START, fwrq->m); lbs_update_channel(priv); ret = 0; @@ -1021,29 +1021,38 @@ static int lbs_set_rate(struct net_device *dev, struct iw_request_info *info, lbs_deb_enter(LBS_DEB_WEXT); lbs_deb_wext("vwrq->value %d\n", vwrq->value); + lbs_deb_wext("vwrq->fixed %d\n", vwrq->fixed); + + if (vwrq->fixed && vwrq->value == -1) + goto out; /* Auto rate? */ - if (vwrq->value == -1) { - priv->auto_rate = 1; + priv->enablehwauto = !vwrq->fixed; + + if (vwrq->value == -1) priv->cur_rate = 0; - } else { + else { if (vwrq->value % 100000) goto out; + new_rate = vwrq->value / 500000; + priv->cur_rate = new_rate; + /* the rest is only needed for lbs_set_data_rate() */ memset(rates, 0, sizeof(rates)); copy_active_data_rates(priv, rates); - new_rate = vwrq->value / 500000; if (!memchr(rates, new_rate, sizeof(rates))) { lbs_pr_alert("fixed data rate 0x%X out of range\n", new_rate); goto out; } - - priv->cur_rate = new_rate; - priv->auto_rate = 0; } - ret = lbs_set_data_rate(priv, new_rate); + /* Try the newer command first (Firmware Spec 5.1 and above) */ + ret = lbs_cmd_802_11_rate_adapt_rateset(priv, CMD_ACT_SET); + + /* Fallback to older version */ + if (ret) + ret = lbs_set_data_rate(priv, new_rate); out: lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret); @@ -1060,7 +1069,7 @@ static int lbs_get_rate(struct net_device *dev, struct iw_request_info *info, if (priv->connect_status == LBS_CONNECTED) { vwrq->value = priv->cur_rate * 500000; - if (priv->auto_rate) + if (priv->enablehwauto) vwrq->fixed = 0; else vwrq->fixed = 1; @@ -2011,7 +2020,8 @@ static int lbs_mesh_set_essid(struct net_device *dev, priv->mesh_ssid_len = dwrq->length; } - lbs_mesh_config(priv, 1, priv->curbssparams.channel); + lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START, + priv->curbssparams.channel); out: lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret); return ret; diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c new file mode 100644 index 000000000000..913dc9fe08f9 --- /dev/null +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -0,0 +1,515 @@ +/* + * mac80211_hwsim - software simulator of 802.11 radio(s) for mac80211 + * Copyright (c) 2008, Jouni Malinen <j@w1.fi> + * + * 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. + */ + +/* + * TODO: + * - IBSS mode simulation (Beacon transmission with competition for "air time") + * - IEEE 802.11a and 802.11n modes + * - RX filtering based on filter configuration (data->rx_filter) + */ + +#include <net/mac80211.h> +#include <net/ieee80211_radiotap.h> +#include <linux/if_arp.h> +#include <linux/rtnetlink.h> +#include <linux/etherdevice.h> + +MODULE_AUTHOR("Jouni Malinen"); +MODULE_DESCRIPTION("Software simulator of 802.11 radio(s) for mac80211"); +MODULE_LICENSE("GPL"); + +static int radios = 2; +module_param(radios, int, 0444); +MODULE_PARM_DESC(radios, "Number of simulated radios"); + + +static struct class *hwsim_class; + +static struct ieee80211_hw **hwsim_radios; +static int hwsim_radio_count; +static struct net_device *hwsim_mon; /* global monitor netdev */ + + +static const struct ieee80211_channel hwsim_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 hwsim_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 } +}; + +struct mac80211_hwsim_data { + struct device *dev; + struct ieee80211_supported_band band; + struct ieee80211_channel channels[ARRAY_SIZE(hwsim_channels)]; + 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; + struct timer_list beacon_timer; +}; + + +struct hwsim_radiotap_hdr { + struct ieee80211_radiotap_header hdr; + u8 rt_flags; + u8 rt_rate; + __le16 rt_channel; + __le16 rt_chbitmask; +} __attribute__ ((packed)); + + +static int hwsim_mon_xmit(struct sk_buff *skb, struct net_device *dev) +{ + /* TODO: allow packet injection */ + dev_kfree_skb(skb); + return 0; +} + + +static void mac80211_hwsim_monitor_rx(struct ieee80211_hw *hw, + struct sk_buff *tx_skb) +{ + struct mac80211_hwsim_data *data = hw->priv; + struct sk_buff *skb; + struct hwsim_radiotap_hdr *hdr; + u16 flags; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx_skb); + struct ieee80211_rate *txrate = ieee80211_get_tx_rate(hw, info); + + if (!netif_running(hwsim_mon)) + return; + + skb = skb_copy_expand(tx_skb, sizeof(*hdr), 0, GFP_ATOMIC); + if (skb == NULL) + return; + + hdr = (struct hwsim_radiotap_hdr *) skb_push(skb, sizeof(*hdr)); + hdr->hdr.it_version = PKTHDR_RADIOTAP_VERSION; + hdr->hdr.it_pad = 0; + hdr->hdr.it_len = cpu_to_le16(sizeof(*hdr)); + hdr->hdr.it_present = cpu_to_le32((1 << IEEE80211_RADIOTAP_FLAGS) | + (1 << IEEE80211_RADIOTAP_RATE) | + (1 << IEEE80211_RADIOTAP_CHANNEL)); + hdr->rt_flags = 0; + hdr->rt_rate = txrate->bitrate / 5; + hdr->rt_channel = cpu_to_le16(data->channel->center_freq); + flags = IEEE80211_CHAN_2GHZ; + if (txrate->flags & IEEE80211_RATE_ERP_G) + flags |= IEEE80211_CHAN_OFDM; + else + flags |= IEEE80211_CHAN_CCK; + hdr->rt_chbitmask = cpu_to_le16(flags); + + skb->dev = hwsim_mon; + skb_set_mac_header(skb, 0); + skb->ip_summed = CHECKSUM_UNNECESSARY; + skb->pkt_type = PACKET_OTHERHOST; + skb->protocol = htons(ETH_P_802_2); + memset(skb->cb, 0, sizeof(skb->cb)); + netif_rx(skb); +} + + +static int mac80211_hwsim_tx_frame(struct ieee80211_hw *hw, + struct sk_buff *skb) +{ + struct mac80211_hwsim_data *data = hw->priv; + int i, ack = 0; + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + struct ieee80211_rx_status rx_status; + + memset(&rx_status, 0, sizeof(rx_status)); + /* TODO: set mactime */ + rx_status.freq = data->channel->center_freq; + rx_status.band = data->channel->band; + rx_status.rate_idx = info->tx_rate_idx; + /* TODO: simulate signal strength (and optional packet drop) */ + + /* Copy skb to all enabled radios that are on the current frequency */ + for (i = 0; i < hwsim_radio_count; i++) { + struct mac80211_hwsim_data *data2; + struct sk_buff *nskb; + + if (hwsim_radios[i] == NULL || hwsim_radios[i] == hw) + continue; + data2 = hwsim_radios[i]->priv; + if (!data2->started || !data2->radio_enabled || + data->channel->center_freq != data2->channel->center_freq) + continue; + + nskb = skb_copy(skb, GFP_ATOMIC); + if (nskb == NULL) + continue; + + if (memcmp(hdr->addr1, hwsim_radios[i]->wiphy->perm_addr, + ETH_ALEN) == 0) + ack = 1; + ieee80211_rx_irqsafe(hwsim_radios[i], nskb, &rx_status); + } + + return ack; +} + + +static int mac80211_hwsim_tx(struct ieee80211_hw *hw, struct sk_buff *skb) +{ + struct mac80211_hwsim_data *data = hw->priv; + int ack; + struct ieee80211_tx_info *txi; + + mac80211_hwsim_monitor_rx(hw, skb); + + if (skb->len < 10) { + /* Should not happen; just a sanity check for addr1 use */ + dev_kfree_skb(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); + memset(&txi->status, 0, sizeof(txi->status)); + if (!(txi->flags & IEEE80211_TX_CTL_NO_ACK)) { + if (ack) + txi->flags |= IEEE80211_TX_STAT_ACK; + else + txi->status.excessive_retries = 1; + } + ieee80211_tx_status_irqsafe(hw, skb); + return NETDEV_TX_OK; +} + + +static int mac80211_hwsim_start(struct ieee80211_hw *hw) +{ + struct mac80211_hwsim_data *data = hw->priv; + printk(KERN_DEBUG "%s:%s\n", wiphy_name(hw->wiphy), __func__); + data->started = 1; + return 0; +} + + +static void mac80211_hwsim_stop(struct ieee80211_hw *hw) +{ + struct mac80211_hwsim_data *data = hw->priv; + data->started = 0; + printk(KERN_DEBUG "%s:%s\n", wiphy_name(hw->wiphy), __func__); +} + + +static int mac80211_hwsim_add_interface(struct ieee80211_hw *hw, + struct ieee80211_if_init_conf *conf) +{ + DECLARE_MAC_BUF(mac); + printk(KERN_DEBUG "%s:%s (type=%d mac_addr=%s)\n", + wiphy_name(hw->wiphy), __func__, conf->type, + print_mac(mac, conf->mac_addr)); + return 0; +} + + +static void mac80211_hwsim_remove_interface( + struct ieee80211_hw *hw, struct ieee80211_if_init_conf *conf) +{ + DECLARE_MAC_BUF(mac); + printk(KERN_DEBUG "%s:%s (type=%d mac_addr=%s)\n", + wiphy_name(hw->wiphy), __func__, conf->type, + print_mac(mac, conf->mac_addr)); +} + + +static void mac80211_hwsim_beacon_tx(void *arg, u8 *mac, + struct ieee80211_vif *vif) +{ + struct ieee80211_hw *hw = arg; + struct sk_buff *skb; + struct ieee80211_tx_info *info; + + if (vif->type != IEEE80211_IF_TYPE_AP) + return; + + skb = ieee80211_beacon_get(hw, vif); + if (skb == NULL) + return; + info = IEEE80211_SKB_CB(skb); + + mac80211_hwsim_monitor_rx(hw, skb); + mac80211_hwsim_tx_frame(hw, skb); + dev_kfree_skb(skb); +} + + +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) + return; + + ieee80211_iterate_active_interfaces_atomic( + hw, mac80211_hwsim_beacon_tx, hw); + + data->beacon_timer.expires = jiffies + data->beacon_int; + add_timer(&data->beacon_timer); +} + + +static int mac80211_hwsim_config(struct ieee80211_hw *hw, + struct ieee80211_conf *conf) +{ + struct mac80211_hwsim_data *data = hw->priv; + + printk(KERN_DEBUG "%s:%s (freq=%d radio_enabled=%d beacon_int=%d)\n", + wiphy_name(hw->wiphy), __func__, + conf->channel->center_freq, conf->radio_enabled, + conf->beacon_int); + + 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) + del_timer(&data->beacon_timer); + else + mod_timer(&data->beacon_timer, jiffies + data->beacon_int); + + return 0; +} + + +static void mac80211_hwsim_configure_filter(struct ieee80211_hw *hw, + unsigned int changed_flags, + unsigned int *total_flags, + int mc_count, + struct dev_addr_list *mc_list) +{ + struct mac80211_hwsim_data *data = hw->priv; + + printk(KERN_DEBUG "%s:%s\n", wiphy_name(hw->wiphy), __func__); + + data->rx_filter = 0; + if (*total_flags & FIF_PROMISC_IN_BSS) + data->rx_filter |= FIF_PROMISC_IN_BSS; + if (*total_flags & FIF_ALLMULTI) + data->rx_filter |= FIF_ALLMULTI; + + *total_flags = data->rx_filter; +} + + + +static const struct ieee80211_ops mac80211_hwsim_ops = +{ + .tx = mac80211_hwsim_tx, + .start = mac80211_hwsim_start, + .stop = mac80211_hwsim_stop, + .add_interface = mac80211_hwsim_add_interface, + .remove_interface = mac80211_hwsim_remove_interface, + .config = mac80211_hwsim_config, + .configure_filter = mac80211_hwsim_configure_filter, +}; + + +static void mac80211_hwsim_free(void) +{ + int i; + + for (i = 0; i < hwsim_radio_count; i++) { + if (hwsim_radios[i]) { + struct mac80211_hwsim_data *data; + data = hwsim_radios[i]->priv; + ieee80211_unregister_hw(hwsim_radios[i]); + if (!IS_ERR(data->dev)) + device_unregister(data->dev); + ieee80211_free_hw(hwsim_radios[i]); + } + } + kfree(hwsim_radios); + class_destroy(hwsim_class); +} + + +static struct device_driver mac80211_hwsim_driver = { + .name = "mac80211_hwsim" +}; + + +static void hwsim_mon_setup(struct net_device *dev) +{ + dev->hard_start_xmit = hwsim_mon_xmit; + dev->destructor = free_netdev; + ether_setup(dev); + dev->tx_queue_len = 0; + dev->type = ARPHRD_IEEE80211_RADIOTAP; + memset(dev->dev_addr, 0, ETH_ALEN); + dev->dev_addr[0] = 0x12; +} + + +static int __init init_mac80211_hwsim(void) +{ + int i, err = 0; + u8 addr[ETH_ALEN]; + struct mac80211_hwsim_data *data; + struct ieee80211_hw *hw; + DECLARE_MAC_BUF(mac); + + if (radios < 1 || radios > 65535) + return -EINVAL; + + hwsim_radio_count = radios; + hwsim_radios = kcalloc(hwsim_radio_count, + sizeof(struct ieee80211_hw *), GFP_KERNEL); + if (hwsim_radios == NULL) + return -ENOMEM; + + hwsim_class = class_create(THIS_MODULE, "mac80211_hwsim"); + if (IS_ERR(hwsim_class)) { + kfree(hwsim_radios); + return PTR_ERR(hwsim_class); + } + + memset(addr, 0, ETH_ALEN); + addr[0] = 0x02; + + for (i = 0; i < hwsim_radio_count; i++) { + printk(KERN_DEBUG "mac80211_hwsim: Initializing radio %d\n", + i); + hw = ieee80211_alloc_hw(sizeof(*data), &mac80211_hwsim_ops); + if (hw == NULL) { + printk(KERN_DEBUG "mac80211_hwsim: ieee80211_alloc_hw " + "failed\n"); + err = -ENOMEM; + goto failed; + } + hwsim_radios[i] = hw; + + data = hw->priv; + data->dev = device_create_drvdata(hwsim_class, NULL, 0, hw, + "hwsim%d", i); + if (IS_ERR(data->dev)) { + printk(KERN_DEBUG + "mac80211_hwsim: device_create_drvdata " + "failed (%ld)\n", PTR_ERR(data->dev)); + err = -ENOMEM; + goto failed; + } + data->dev->driver = &mac80211_hwsim_driver; + + SET_IEEE80211_DEV(hw, data->dev); + addr[3] = i >> 8; + addr[4] = i; + SET_IEEE80211_PERM_ADDR(hw, addr); + + hw->channel_change_time = 1; + hw->queues = 1; + + memcpy(data->channels, hwsim_channels, sizeof(hwsim_channels)); + memcpy(data->rates, hwsim_rates, sizeof(hwsim_rates)); + data->band.channels = data->channels; + data->band.n_channels = ARRAY_SIZE(hwsim_channels); + data->band.bitrates = data->rates; + data->band.n_bitrates = ARRAY_SIZE(hwsim_rates); + hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &data->band; + + err = ieee80211_register_hw(hw); + if (err < 0) { + printk(KERN_DEBUG "mac80211_hwsim: " + "ieee80211_register_hw failed (%d)\n", err); + goto failed; + } + + printk(KERN_DEBUG "%s: hwaddr %s registered\n", + wiphy_name(hw->wiphy), + print_mac(mac, hw->wiphy->perm_addr)); + + setup_timer(&data->beacon_timer, mac80211_hwsim_beacon, + (unsigned long) hw); + } + + hwsim_mon = alloc_netdev(0, "hwsim%d", hwsim_mon_setup); + if (hwsim_mon == NULL) + goto failed; + + rtnl_lock(); + + err = dev_alloc_name(hwsim_mon, hwsim_mon->name); + if (err < 0) { + goto failed_mon; + } + + err = register_netdevice(hwsim_mon); + if (err < 0) + goto failed_mon; + + rtnl_unlock(); + + return 0; + +failed_mon: + rtnl_unlock(); + free_netdev(hwsim_mon); + +failed: + mac80211_hwsim_free(); + return err; +} + + +static void __exit exit_mac80211_hwsim(void) +{ + printk(KERN_DEBUG "mac80211_hwsim: unregister %d radios\n", + hwsim_radio_count); + + unregister_netdev(hwsim_mon); + mac80211_hwsim_free(); +} + + +module_init(init_mac80211_hwsim); +module_exit(exit_mac80211_hwsim); diff --git a/drivers/net/wireless/orinoco.c b/drivers/net/wireless/orinoco.c index 6d13a0d15a0c..b047306bf386 100644 --- a/drivers/net/wireless/orinoco.c +++ b/drivers/net/wireless/orinoco.c @@ -4046,6 +4046,7 @@ static int orinoco_ioctl_setscan(struct net_device *dev, * format that the Wireless Tools will understand - Jean II * Return message length or -errno for fatal errors */ static inline char *orinoco_translate_scan(struct net_device *dev, + struct iw_request_info *info, char *current_ev, char *end_buf, union hermes_scan_info *bss, @@ -4062,7 +4063,8 @@ static inline char *orinoco_translate_scan(struct net_device *dev, iwe.cmd = SIOCGIWAP; iwe.u.ap_addr.sa_family = ARPHRD_ETHER; memcpy(iwe.u.ap_addr.sa_data, bss->a.bssid, ETH_ALEN); - current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_ADDR_LEN); + current_ev = iwe_stream_add_event(info, current_ev, end_buf, + &iwe, IW_EV_ADDR_LEN); /* Other entries will be displayed in the order we give them */ @@ -4072,7 +4074,8 @@ static inline char *orinoco_translate_scan(struct net_device *dev, iwe.u.data.length = 32; iwe.cmd = SIOCGIWESSID; iwe.u.data.flags = 1; - current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, bss->a.essid); + current_ev = iwe_stream_add_point(info, current_ev, end_buf, + &iwe, bss->a.essid); /* Add mode */ iwe.cmd = SIOCGIWMODE; @@ -4082,7 +4085,8 @@ static inline char *orinoco_translate_scan(struct net_device *dev, iwe.u.mode = IW_MODE_MASTER; else iwe.u.mode = IW_MODE_ADHOC; - current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_UINT_LEN); + current_ev = iwe_stream_add_event(info, current_ev, end_buf, + &iwe, IW_EV_UINT_LEN); } channel = bss->s.channel; @@ -4091,7 +4095,7 @@ static inline char *orinoco_translate_scan(struct net_device *dev, iwe.cmd = SIOCGIWFREQ; iwe.u.freq.m = channel_frequency[channel-1] * 100000; iwe.u.freq.e = 1; - current_ev = iwe_stream_add_event(current_ev, end_buf, + current_ev = iwe_stream_add_event(info, current_ev, end_buf, &iwe, IW_EV_FREQ_LEN); } @@ -4106,7 +4110,8 @@ static inline char *orinoco_translate_scan(struct net_device *dev, iwe.u.qual.qual = iwe.u.qual.level - iwe.u.qual.noise; else iwe.u.qual.qual = 0; - current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_QUAL_LEN); + current_ev = iwe_stream_add_event(info, current_ev, end_buf, + &iwe, IW_EV_QUAL_LEN); /* Add encryption capability */ iwe.cmd = SIOCGIWENCODE; @@ -4115,7 +4120,8 @@ static inline char *orinoco_translate_scan(struct net_device *dev, else iwe.u.data.flags = IW_ENCODE_DISABLED; iwe.u.data.length = 0; - current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, bss->a.essid); + current_ev = iwe_stream_add_point(info, current_ev, end_buf, + &iwe, bss->a.essid); /* Add EXTRA: Age to display seconds since last beacon/probe response * for given network. */ @@ -4126,11 +4132,12 @@ static inline char *orinoco_translate_scan(struct net_device *dev, jiffies_to_msecs(jiffies - last_scanned)); iwe.u.data.length = p - custom; if (iwe.u.data.length) - current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, custom); + current_ev = iwe_stream_add_point(info, current_ev, end_buf, + &iwe, custom); /* Bit rate is not available in Lucent/Agere firmwares */ if (priv->firmware_type != FIRMWARE_TYPE_AGERE) { - char *current_val = current_ev + IW_EV_LCP_LEN; + char *current_val = current_ev + iwe_stream_lcp_len(info); int i; int step; @@ -4149,12 +4156,13 @@ static inline char *orinoco_translate_scan(struct net_device *dev, break; /* Bit rate given in 500 kb/s units (+ 0x80) */ iwe.u.bitrate.value = ((bss->p.rates[i] & 0x7f) * 500000); - current_val = iwe_stream_add_value(current_ev, current_val, + current_val = iwe_stream_add_value(info, current_ev, + current_val, end_buf, &iwe, IW_EV_PARAM_LEN); } /* Check if we added any event */ - if ((current_val - current_ev) > IW_EV_LCP_LEN) + if ((current_val - current_ev) > iwe_stream_lcp_len(info)) current_ev = current_val; } @@ -4190,7 +4198,7 @@ static int orinoco_ioctl_getscan(struct net_device *dev, list_for_each_entry(bss, &priv->bss_list, list) { /* Translate to WE format this entry */ - current_ev = orinoco_translate_scan(dev, current_ev, + current_ev = orinoco_translate_scan(dev, info, current_ev, extra + srq->length, &bss->bss, bss->last_scanned); diff --git a/drivers/net/wireless/p54/p54.h b/drivers/net/wireless/p54/p54.h index 06d2c67f4c81..c6f27b9022f9 100644 --- a/drivers/net/wireless/p54/p54.h +++ b/drivers/net/wireless/p54/p54.h @@ -64,7 +64,7 @@ struct p54_common { unsigned int tx_hdr_len; void *cached_vdcf; unsigned int fw_var; - struct ieee80211_tx_queue_stats tx_stats; + struct ieee80211_tx_queue_stats tx_stats[4]; }; int p54_rx(struct ieee80211_hw *dev, struct sk_buff *skb); diff --git a/drivers/net/wireless/p54/p54common.c b/drivers/net/wireless/p54/p54common.c index 63f9badf3f52..ffaf7a6b6810 100644 --- a/drivers/net/wireless/p54/p54common.c +++ b/drivers/net/wireless/p54/p54common.c @@ -146,10 +146,10 @@ void p54_parse_firmware(struct ieee80211_hw *dev, const struct firmware *fw) if (priv->fw_var >= 0x300) { /* Firmware supports QoS, use it! */ - priv->tx_stats.data[0].limit = 3; - priv->tx_stats.data[1].limit = 4; - priv->tx_stats.data[2].limit = 3; - priv->tx_stats.data[3].limit = 1; + priv->tx_stats[0].limit = 3; + priv->tx_stats[1].limit = 4; + priv->tx_stats[2].limit = 3; + priv->tx_stats[3].limit = 1; dev->queues = 4; } } @@ -355,8 +355,9 @@ static void p54_rx_data(struct ieee80211_hw *dev, struct sk_buff *skb) struct ieee80211_rx_status rx_status = {0}; u16 freq = le16_to_cpu(hdr->freq); - rx_status.ssi = hdr->rssi; + rx_status.signal = hdr->rssi; /* XX correct? */ + rx_status.qual = (100 * hdr->rssi) / 127; rx_status.rate_idx = hdr->rate & 0xf; rx_status.freq = freq; rx_status.band = IEEE80211_BAND_2GHZ; @@ -375,11 +376,8 @@ static void inline p54_wake_free_queues(struct ieee80211_hw *dev) struct p54_common *priv = dev->priv; int i; - /* ieee80211_start_queues is great if all queues are really empty. - * But, what if some are full? */ - for (i = 0; i < dev->queues; i++) - if (priv->tx_stats.data[i].len < priv->tx_stats.data[i].limit) + if (priv->tx_stats[i].len < priv->tx_stats[i].limit) ieee80211_wake_queue(dev, i); } @@ -395,45 +393,42 @@ static void p54_rx_frame_sent(struct ieee80211_hw *dev, struct sk_buff *skb) u32 last_addr = priv->rx_start; while (entry != (struct sk_buff *)&priv->tx_queue) { - range = (struct memrecord *)&entry->cb; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(entry); + range = (void *)info->driver_data; if (range->start_addr == addr) { - struct ieee80211_tx_status status; struct p54_control_hdr *entry_hdr; struct p54_tx_control_allocdata *entry_data; int pad = 0; - if (entry->next != (struct sk_buff *)&priv->tx_queue) - freed = ((struct memrecord *)&entry->next->cb)->start_addr - last_addr; - else + if (entry->next != (struct sk_buff *)&priv->tx_queue) { + struct ieee80211_tx_info *ni; + struct memrecord *mr; + + ni = IEEE80211_SKB_CB(entry->next); + mr = (struct memrecord *)ni->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); - if (!range->control) { - kfree_skb(entry); - break; - } - memset(&status, 0, sizeof(status)); - memcpy(&status.control, range->control, - sizeof(status.control)); - kfree(range->control); - priv->tx_stats.data[status.control.queue].len--; - + memset(&info->status, 0, sizeof(info->status)); + priv->tx_stats[skb_get_queue_mapping(skb)].len--; entry_hdr = (struct p54_control_hdr *) entry->data; entry_data = (struct p54_tx_control_allocdata *) entry_hdr->data; if ((entry_hdr->magic1 & cpu_to_le16(0x4000)) != 0) pad = entry_data->align[0]; - if (!(status.control.flags & IEEE80211_TXCTL_NO_ACK)) { + if (!(info->flags & IEEE80211_TX_CTL_NO_ACK)) { if (!(payload->status & 0x01)) - status.flags |= IEEE80211_TX_STATUS_ACK; + info->flags |= IEEE80211_TX_STAT_ACK; else - status.excessive_retries = 1; + info->status.excessive_retries = 1; } - status.retry_count = payload->retries - 1; - status.ack_signal = le16_to_cpu(payload->ack_rssi); + info->status.retry_count = payload->retries - 1; + info->status.ack_signal = le16_to_cpu(payload->ack_rssi); skb_pull(entry, sizeof(*hdr) + pad + sizeof(*entry_data)); - ieee80211_tx_status_irqsafe(dev, entry, &status); + ieee80211_tx_status_irqsafe(dev, entry); break; } else last_addr = range->end_addr; @@ -498,13 +493,11 @@ EXPORT_SYMBOL_GPL(p54_rx); * allocated areas. */ static void p54_assign_address(struct ieee80211_hw *dev, struct sk_buff *skb, - struct p54_control_hdr *data, u32 len, - struct ieee80211_tx_control *control) + struct p54_control_hdr *data, u32 len) { struct p54_common *priv = dev->priv; struct sk_buff *entry = priv->tx_queue.next; struct sk_buff *target_skb = NULL; - struct memrecord *range; u32 last_addr = priv->rx_start; u32 largest_hole = 0; u32 target_addr = priv->rx_start; @@ -516,7 +509,8 @@ static void p54_assign_address(struct ieee80211_hw *dev, struct sk_buff *skb, left = skb_queue_len(&priv->tx_queue); while (left--) { u32 hole_size; - range = (struct memrecord *)&entry->cb; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(entry); + struct memrecord *range = (void *)info->driver_data; hole_size = range->start_addr - last_addr; if (!target_skb && hole_size >= len) { target_skb = entry->prev; @@ -531,17 +525,18 @@ static void p54_assign_address(struct ieee80211_hw *dev, struct sk_buff *skb, target_skb = priv->tx_queue.prev; largest_hole = max(largest_hole, priv->rx_end - last_addr - len); if (!skb_queue_empty(&priv->tx_queue)) { - range = (struct memrecord *)&target_skb->cb; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(target_skb); + struct memrecord *range = (void *)info->driver_data; target_addr = range->end_addr; } } else largest_hole = max(largest_hole, priv->rx_end - last_addr); if (skb) { - range = (struct memrecord *)&skb->cb; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + struct memrecord *range = (void *)info->driver_data; range->start_addr = target_addr; range->end_addr = target_addr + len; - range->control = control; __skb_queue_after(&priv->tx_queue, target_skb, skb); if (largest_hole < IEEE80211_MAX_RTS_THRESHOLD + 0x170 + sizeof(struct p54_control_hdr)) @@ -552,32 +547,27 @@ static void p54_assign_address(struct ieee80211_hw *dev, struct sk_buff *skb, data->req_id = cpu_to_le32(target_addr + 0x70); } -static int p54_tx(struct ieee80211_hw *dev, struct sk_buff *skb, - struct ieee80211_tx_control *control) +static int p54_tx(struct ieee80211_hw *dev, struct sk_buff *skb) { - struct ieee80211_tx_queue_stats_data *current_queue; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + struct ieee80211_tx_queue_stats *current_queue; struct p54_common *priv = dev->priv; struct p54_control_hdr *hdr; struct p54_tx_control_allocdata *txhdr; - struct ieee80211_tx_control *control_copy; size_t padding, len; u8 rate; - current_queue = &priv->tx_stats.data[control->queue]; + current_queue = &priv->tx_stats[skb_get_queue_mapping(skb)]; if (unlikely(current_queue->len > current_queue->limit)) return NETDEV_TX_BUSY; current_queue->len++; current_queue->count++; if (current_queue->len == current_queue->limit) - ieee80211_stop_queue(dev, control->queue); + ieee80211_stop_queue(dev, skb_get_queue_mapping(skb)); padding = (unsigned long)(skb->data - (sizeof(*hdr) + sizeof(*txhdr))) & 3; len = skb->len; - control_copy = kmalloc(sizeof(*control), GFP_ATOMIC); - if (control_copy) - memcpy(control_copy, control, sizeof(*control)); - txhdr = (struct p54_tx_control_allocdata *) skb_push(skb, sizeof(*txhdr) + padding); hdr = (struct p54_control_hdr *) skb_push(skb, sizeof(*hdr)); @@ -587,35 +577,37 @@ static int p54_tx(struct ieee80211_hw *dev, struct sk_buff *skb, else hdr->magic1 = cpu_to_le16(0x0010); hdr->len = cpu_to_le16(len); - hdr->type = (control->flags & IEEE80211_TXCTL_NO_ACK) ? 0 : cpu_to_le16(1); - hdr->retry1 = hdr->retry2 = control->retry_limit; - p54_assign_address(dev, skb, hdr, skb->len, control_copy); + hdr->type = (info->flags & IEEE80211_TX_CTL_NO_ACK) ? 0 : cpu_to_le16(1); + hdr->retry1 = hdr->retry2 = info->control.retry_limit; memset(txhdr->wep_key, 0x0, 16); txhdr->padding = 0; txhdr->padding2 = 0; /* TODO: add support for alternate retry TX rates */ - rate = control->tx_rate->hw_value; - if (control->flags & IEEE80211_TXCTL_SHORT_PREAMBLE) + rate = ieee80211_get_tx_rate(dev, info)->hw_value; + if (info->flags & IEEE80211_TX_CTL_SHORT_PREAMBLE) rate |= 0x10; - if (control->flags & IEEE80211_TXCTL_USE_RTS_CTS) + if (info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) rate |= 0x40; - else if (control->flags & IEEE80211_TXCTL_USE_CTS_PROTECT) + else if (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT) rate |= 0x20; memset(txhdr->rateset, rate, 8); txhdr->wep_key_present = 0; txhdr->wep_key_len = 0; - txhdr->frame_type = cpu_to_le32(control->queue + 4); + txhdr->frame_type = cpu_to_le32(skb_get_queue_mapping(skb) + 4); txhdr->magic4 = 0; - txhdr->antenna = (control->antenna_sel_tx == 0) ? - 2 : control->antenna_sel_tx - 1; + txhdr->antenna = (info->antenna_sel_tx == 0) ? + 2 : info->antenna_sel_tx - 1; txhdr->output_power = 0x7f; // HW Maximum - txhdr->magic5 = (control->flags & IEEE80211_TXCTL_NO_ACK) ? + txhdr->magic5 = (info->flags & IEEE80211_TX_CTL_NO_ACK) ? 0 : ((rate > 0x3) ? cpu_to_le32(0x33) : cpu_to_le32(0x23)); if (padding) txhdr->align[0] = padding; + /* modifies skb->cb and with it info, so must be last! */ + p54_assign_address(dev, skb, hdr, skb->len); + priv->tx(dev, hdr, skb->len, 0); return 0; } @@ -638,7 +630,7 @@ static int p54_set_filter(struct ieee80211_hw *dev, u16 filter_type, filter = (struct p54_tx_control_filter *) hdr->data; hdr->magic1 = cpu_to_le16(0x8001); hdr->len = cpu_to_le16(sizeof(*filter)); - p54_assign_address(dev, NULL, hdr, sizeof(*hdr) + sizeof(*filter), NULL); + p54_assign_address(dev, NULL, hdr, sizeof(*hdr) + sizeof(*filter)); hdr->type = cpu_to_le16(P54_CONTROL_TYPE_FILTER_SET); filter->filter_type = cpu_to_le16(filter_type); @@ -682,7 +674,7 @@ static int p54_set_freq(struct ieee80211_hw *dev, __le16 freq) hdr->magic1 = cpu_to_le16(0x8001); hdr->len = cpu_to_le16(sizeof(*chan)); hdr->type = cpu_to_le16(P54_CONTROL_TYPE_CHANNEL_CHANGE); - p54_assign_address(dev, NULL, hdr, sizeof(*hdr) + payload_len, NULL); + p54_assign_address(dev, NULL, hdr, sizeof(*hdr) + payload_len); chan->magic1 = cpu_to_le16(0x1); chan->magic2 = cpu_to_le16(0x0); @@ -755,7 +747,7 @@ static int p54_set_leds(struct ieee80211_hw *dev, int mode, int link, int act) hdr->magic1 = cpu_to_le16(0x8001); hdr->len = cpu_to_le16(sizeof(*led)); hdr->type = cpu_to_le16(P54_CONTROL_TYPE_LED); - p54_assign_address(dev, NULL, hdr, sizeof(*hdr) + sizeof(*led), NULL); + p54_assign_address(dev, NULL, hdr, sizeof(*hdr) + sizeof(*led)); led = (struct p54_tx_control_led *) hdr->data; led->mode = cpu_to_le16(mode); @@ -805,7 +797,7 @@ static void p54_set_vdcf(struct ieee80211_hw *dev) hdr = (void *)priv->cached_vdcf + priv->tx_hdr_len; - p54_assign_address(dev, NULL, hdr, sizeof(*hdr) + sizeof(*vdcf), NULL); + p54_assign_address(dev, NULL, hdr, sizeof(*hdr) + sizeof(*vdcf)); vdcf = (struct p54_tx_control_vdcf *) hdr->data; @@ -841,12 +833,8 @@ static void p54_stop(struct ieee80211_hw *dev) { struct p54_common *priv = dev->priv; struct sk_buff *skb; - while ((skb = skb_dequeue(&priv->tx_queue))) { - struct memrecord *range = (struct memrecord *)&skb->cb; - if (range->control) - kfree(range->control); + while ((skb = skb_dequeue(&priv->tx_queue))) kfree_skb(skb); - } priv->stop(dev); priv->mode = IEEE80211_IF_TYPE_INVALID; } @@ -936,7 +924,7 @@ static void p54_configure_filter(struct ieee80211_hw *dev, } } -static int p54_conf_tx(struct ieee80211_hw *dev, int queue, +static int p54_conf_tx(struct ieee80211_hw *dev, u16 queue, const struct ieee80211_tx_queue_params *params) { struct p54_common *priv = dev->priv; @@ -945,7 +933,7 @@ static int p54_conf_tx(struct ieee80211_hw *dev, int queue, vdcf = (struct p54_tx_control_vdcf *)(((struct p54_control_hdr *) ((void *)priv->cached_vdcf + priv->tx_hdr_len))->data); - if ((params) && !((queue < 0) || (queue > 4))) { + if ((params) && !(queue > 4)) { P54_SET_QUEUE(vdcf->queue[queue], params->aifs, params->cw_min, params->cw_max, params->txop); } else @@ -967,11 +955,8 @@ static int p54_get_tx_stats(struct ieee80211_hw *dev, struct ieee80211_tx_queue_stats *stats) { struct p54_common *priv = dev->priv; - unsigned int i; - for (i = 0; i < dev->queues; i++) - memcpy(&stats->data[i], &priv->tx_stats.data[i], - sizeof(stats->data[i])); + memcpy(stats, &priv->tx_stats, sizeof(stats[0]) * dev->queues); return 0; } @@ -1004,11 +989,12 @@ struct ieee80211_hw *p54_init_common(size_t priv_data_len) skb_queue_head_init(&priv->tx_queue); dev->wiphy->bands[IEEE80211_BAND_2GHZ] = &band_2GHz; dev->flags = IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | /* not sure */ - IEEE80211_HW_RX_INCLUDES_FCS; + IEEE80211_HW_RX_INCLUDES_FCS | + IEEE80211_HW_SIGNAL_UNSPEC; dev->channel_change_time = 1000; /* TODO: find actual value */ - dev->max_rssi = 127; + dev->max_signal = 127; - priv->tx_stats.data[0].limit = 5; + priv->tx_stats[0].limit = 5; dev->queues = 1; dev->extra_tx_headroom = sizeof(struct p54_control_hdr) + 4 + diff --git a/drivers/net/wireless/p54/p54common.h b/drivers/net/wireless/p54/p54common.h index c15b56e1d75e..2245fcce92dc 100644 --- a/drivers/net/wireless/p54/p54common.h +++ b/drivers/net/wireless/p54/p54common.h @@ -152,7 +152,6 @@ struct pda_pa_curve_data { struct memrecord { u32 start_addr; u32 end_addr; - struct ieee80211_tx_control *control; }; struct p54_eeprom_lm86 { diff --git a/drivers/net/wireless/p54/p54pci.c b/drivers/net/wireless/p54/p54pci.c index fa527723fbe0..7dd4add4bf4e 100644 --- a/drivers/net/wireless/p54/p54pci.c +++ b/drivers/net/wireless/p54/p54pci.c @@ -665,7 +665,7 @@ static int p54p_resume(struct pci_dev *pdev) if (priv->common.mode != IEEE80211_IF_TYPE_INVALID) { p54p_open(dev); - ieee80211_start_queues(dev); + ieee80211_wake_queues(dev); } return 0; diff --git a/drivers/net/wireless/prism54/isl_ioctl.c b/drivers/net/wireless/prism54/isl_ioctl.c index 5b375b289036..97fa14e0a479 100644 --- a/drivers/net/wireless/prism54/isl_ioctl.c +++ b/drivers/net/wireless/prism54/isl_ioctl.c @@ -571,8 +571,9 @@ prism54_set_scan(struct net_device *dev, struct iw_request_info *info, */ static char * -prism54_translate_bss(struct net_device *ndev, char *current_ev, - char *end_buf, struct obj_bss *bss, char noise) +prism54_translate_bss(struct net_device *ndev, struct iw_request_info *info, + char *current_ev, char *end_buf, struct obj_bss *bss, + char noise) { struct iw_event iwe; /* Temporary buffer */ short cap; @@ -584,8 +585,8 @@ prism54_translate_bss(struct net_device *ndev, char *current_ev, memcpy(iwe.u.ap_addr.sa_data, bss->address, 6); iwe.u.ap_addr.sa_family = ARPHRD_ETHER; iwe.cmd = SIOCGIWAP; - current_ev = - iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_ADDR_LEN); + current_ev = iwe_stream_add_event(info, current_ev, end_buf, + &iwe, IW_EV_ADDR_LEN); /* The following entries will be displayed in the same order we give them */ @@ -593,7 +594,7 @@ prism54_translate_bss(struct net_device *ndev, char *current_ev, iwe.u.data.length = bss->ssid.length; iwe.u.data.flags = 1; iwe.cmd = SIOCGIWESSID; - current_ev = iwe_stream_add_point(current_ev, end_buf, + current_ev = iwe_stream_add_point(info, current_ev, end_buf, &iwe, bss->ssid.octets); /* Capabilities */ @@ -610,9 +611,8 @@ prism54_translate_bss(struct net_device *ndev, char *current_ev, iwe.u.mode = IW_MODE_ADHOC; iwe.cmd = SIOCGIWMODE; if (iwe.u.mode) - current_ev = - iwe_stream_add_event(current_ev, end_buf, &iwe, - IW_EV_UINT_LEN); + current_ev = iwe_stream_add_event(info, current_ev, end_buf, + &iwe, IW_EV_UINT_LEN); /* Encryption capability */ if (cap & CAP_CRYPT) @@ -621,14 +621,15 @@ prism54_translate_bss(struct net_device *ndev, char *current_ev, iwe.u.data.flags = IW_ENCODE_DISABLED; iwe.u.data.length = 0; iwe.cmd = SIOCGIWENCODE; - current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, NULL); + current_ev = iwe_stream_add_point(info, current_ev, end_buf, + &iwe, NULL); /* Add frequency. (short) bss->channel is the frequency in MHz */ iwe.u.freq.m = bss->channel; iwe.u.freq.e = 6; iwe.cmd = SIOCGIWFREQ; - current_ev = - iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_FREQ_LEN); + current_ev = iwe_stream_add_event(info, current_ev, end_buf, + &iwe, IW_EV_FREQ_LEN); /* Add quality statistics */ iwe.u.qual.level = bss->rssi; @@ -636,20 +637,20 @@ prism54_translate_bss(struct net_device *ndev, char *current_ev, /* do a simple SNR for quality */ iwe.u.qual.qual = bss->rssi - noise; iwe.cmd = IWEVQUAL; - current_ev = - iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_QUAL_LEN); + current_ev = iwe_stream_add_event(info, current_ev, end_buf, + &iwe, IW_EV_QUAL_LEN); /* Add WPA/RSN Information Element, if any */ wpa_ie_len = prism54_wpa_bss_ie_get(priv, bss->address, wpa_ie); if (wpa_ie_len > 0) { iwe.cmd = IWEVGENIE; iwe.u.data.length = min(wpa_ie_len, (size_t)MAX_WPA_IE_LEN); - current_ev = iwe_stream_add_point(current_ev, end_buf, - &iwe, wpa_ie); + current_ev = iwe_stream_add_point(info, current_ev, end_buf, + &iwe, wpa_ie); } /* Do the bitrates */ { - char * current_val = current_ev + IW_EV_LCP_LEN; + char *current_val = current_ev + iwe_stream_lcp_len(info); int i; int mask; @@ -662,14 +663,14 @@ prism54_translate_bss(struct net_device *ndev, char *current_ev, for(i = 0; i < sizeof(scan_rate_list); i++) { if(bss->rates & mask) { iwe.u.bitrate.value = (scan_rate_list[i] * 500000); - current_val = iwe_stream_add_value(current_ev, current_val, - end_buf, &iwe, - IW_EV_PARAM_LEN); + current_val = iwe_stream_add_value( + info, current_ev, current_val, + end_buf, &iwe, IW_EV_PARAM_LEN); } mask <<= 1; } /* Check if we added any event */ - if ((current_val - current_ev) > IW_EV_LCP_LEN) + if ((current_val - current_ev) > iwe_stream_lcp_len(info)) current_ev = current_val; } @@ -710,7 +711,7 @@ prism54_get_scan(struct net_device *ndev, struct iw_request_info *info, /* ok now, scan the list and translate its info */ for (i = 0; i < (int) bsslist->nr; i++) { - current_ev = prism54_translate_bss(ndev, current_ev, + current_ev = prism54_translate_bss(ndev, info, current_ev, extra + dwrq->length, &(bsslist->bsslist[i]), noise); @@ -2704,6 +2705,7 @@ prism2_ioctl_scan_req(struct net_device *ndev, struct prism2_hostapd_param *param) { islpci_private *priv = netdev_priv(ndev); + struct iw_request_info info; int i, rvalue; struct obj_bsslist *bsslist; u32 noise = 0; @@ -2727,9 +2729,12 @@ prism2_ioctl_scan_req(struct net_device *ndev, rvalue |= mgt_get_request(priv, DOT11_OID_BSSLIST, 0, NULL, &r); bsslist = r.ptr; + info.cmd = PRISM54_HOSTAPD; + info.flags = 0; + /* ok now, scan the list and translate its info */ for (i = 0; i < min(IW_MAX_AP, (int) bsslist->nr); i++) - current_ev = prism54_translate_bss(ndev, current_ev, + current_ev = prism54_translate_bss(ndev, &info, current_ev, extra + IW_SCAN_MAX_DATA, &(bsslist->bsslist[i]), noise); diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c index 18c9931e3267..00e965b9da75 100644 --- a/drivers/net/wireless/rndis_wlan.c +++ b/drivers/net/wireless/rndis_wlan.c @@ -310,8 +310,11 @@ enum wpa_key_mgmt { KEY_MGMT_802_1X, KEY_MGMT_PSK, KEY_MGMT_NONE, #define CAP_MODE_MASK 7 #define CAP_SUPPORT_TXPOWER 8 -#define WORK_CONNECTION_EVENT (1<<0) -#define WORK_SET_MULTICAST_LIST (1<<1) +#define WORK_LINK_UP (1<<0) +#define WORK_LINK_DOWN (1<<1) +#define WORK_SET_MULTICAST_LIST (1<<2) + +#define COMMAND_BUFFER_SIZE (CONTROL_BUFFER_SIZE + sizeof(struct rndis_set)) /* RNDIS device private data */ struct rndis_wext_private { @@ -361,6 +364,8 @@ struct rndis_wext_private { u8 *wpa_ie; int wpa_cipher_pair; int wpa_cipher_group; + + u8 command_buffer[COMMAND_BUFFER_SIZE]; }; @@ -427,18 +432,23 @@ static int rndis_query_oid(struct usbnet *dev, __le32 oid, void *data, int *len) buflen = *len + sizeof(*u.get); if (buflen < CONTROL_BUFFER_SIZE) buflen = CONTROL_BUFFER_SIZE; - u.buf = kmalloc(buflen, GFP_KERNEL); - if (!u.buf) - return -ENOMEM; + + if (buflen > COMMAND_BUFFER_SIZE) { + u.buf = kmalloc(buflen, GFP_KERNEL); + if (!u.buf) + return -ENOMEM; + } else { + u.buf = priv->command_buffer; + } + + mutex_lock(&priv->command_lock); + memset(u.get, 0, sizeof *u.get); u.get->msg_type = RNDIS_MSG_QUERY; u.get->msg_len = ccpu2(sizeof *u.get); u.get->oid = oid; - mutex_lock(&priv->command_lock); - ret = rndis_command(dev, u.header); - mutex_unlock(&priv->command_lock); - + ret = rndis_command(dev, u.header, buflen); if (ret == 0) { ret = le32_to_cpu(u.get_c->len); *len = (*len > ret) ? ret : *len; @@ -446,7 +456,10 @@ static int rndis_query_oid(struct usbnet *dev, __le32 oid, void *data, int *len) ret = rndis_error_status(u.get_c->status); } - kfree(u.buf); + mutex_unlock(&priv->command_lock); + + if (u.buf != priv->command_buffer) + kfree(u.buf); return ret; } @@ -465,9 +478,16 @@ static int rndis_set_oid(struct usbnet *dev, __le32 oid, void *data, int len) buflen = len + sizeof(*u.set); if (buflen < CONTROL_BUFFER_SIZE) buflen = CONTROL_BUFFER_SIZE; - u.buf = kmalloc(buflen, GFP_KERNEL); - if (!u.buf) - return -ENOMEM; + + if (buflen > COMMAND_BUFFER_SIZE) { + u.buf = kmalloc(buflen, GFP_KERNEL); + if (!u.buf) + return -ENOMEM; + } else { + u.buf = priv->command_buffer; + } + + mutex_lock(&priv->command_lock); memset(u.set, 0, sizeof *u.set); u.set->msg_type = RNDIS_MSG_SET; @@ -478,14 +498,14 @@ static int rndis_set_oid(struct usbnet *dev, __le32 oid, void *data, int len) u.set->handle = ccpu2(0); memcpy(u.buf + sizeof(*u.set), data, len); - mutex_lock(&priv->command_lock); - ret = rndis_command(dev, u.header); - mutex_unlock(&priv->command_lock); - + ret = rndis_command(dev, u.header, buflen); if (ret == 0) ret = rndis_error_status(u.set_c->status); - kfree(u.buf); + mutex_unlock(&priv->command_lock); + + if (u.buf != priv->command_buffer) + kfree(u.buf); return ret; } @@ -620,8 +640,7 @@ static void dsconfig_to_freq(unsigned int dsconfig, struct iw_freq *freq) static int freq_to_dsconfig(struct iw_freq *freq, unsigned int *dsconfig) { if (freq->m < 1000 && freq->e == 0) { - if (freq->m >= 1 && - freq->m <= (sizeof(freq_chan) / sizeof(freq_chan[0]))) + if (freq->m >= 1 && freq->m <= ARRAY_SIZE(freq_chan)) *dsconfig = freq_chan[freq->m - 1] * 1000; else return -1; @@ -1135,7 +1154,7 @@ 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 < sizeof(rates_80211g); i++) { + for (i = 0; i < ARRAY_SIZE(rates_80211g); i++) { for (j = 0; j < num; j++) { if (range->bitrate[j] == rates_80211g[i] * 1000000) @@ -1159,10 +1178,9 @@ static int rndis_iw_get_range(struct net_device *dev, range->throughput = 11 * 1000 * 1000 / 2; } - range->num_channels = (sizeof(freq_chan)/sizeof(freq_chan[0])); + range->num_channels = ARRAY_SIZE(freq_chan); - for (i = 0; i < (sizeof(freq_chan)/sizeof(freq_chan[0])) && - i < IW_MAX_FREQUENCIES; i++) { + for (i = 0; i < ARRAY_SIZE(freq_chan) && i < IW_MAX_FREQUENCIES; i++) { range->freq[i].i = i + 1; range->freq[i].m = freq_chan[i] * 100000; range->freq[i].e = 1; @@ -1630,7 +1648,9 @@ static int rndis_iw_set_scan(struct net_device *dev, static char *rndis_translate_scan(struct net_device *dev, - char *cev, char *end_buf, struct ndis_80211_bssid_ex *bssid) + struct iw_request_info *info, char *cev, + char *end_buf, + struct ndis_80211_bssid_ex *bssid) { #ifdef DEBUG struct usbnet *usbdev = dev->priv; @@ -1649,14 +1669,14 @@ static char *rndis_translate_scan(struct net_device *dev, 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(cev, end_buf, &iwe, IW_EV_ADDR_LEN); + 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(cev, end_buf, &iwe, bssid->ssid.essid); + 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; @@ -1672,12 +1692,12 @@ static char *rndis_translate_scan(struct net_device *dev, iwe.u.mode = IW_MODE_AUTO; break; } - cev = iwe_stream_add_event(cev, end_buf, &iwe, IW_EV_UINT_LEN); + 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(cev, end_buf, &iwe, IW_EV_FREQ_LEN); + 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; @@ -1686,7 +1706,7 @@ static char *rndis_translate_scan(struct net_device *dev, iwe.u.qual.updated = IW_QUAL_QUAL_UPDATED | IW_QUAL_LEVEL_UPDATED | IW_QUAL_NOISE_INVALID; - cev = iwe_stream_add_event(cev, end_buf, &iwe, IW_EV_QUAL_LEN); + 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; @@ -1696,10 +1716,10 @@ static char *rndis_translate_scan(struct net_device *dev, else iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY; - cev = iwe_stream_add_point(cev, end_buf, &iwe, NULL); + cev = iwe_stream_add_point(info, cev, end_buf, &iwe, NULL); devdbg(usbdev, "RATES:"); - current_val = cev + IW_EV_LCP_LEN; + current_val = cev + iwe_stream_lcp_len(info); iwe.cmd = SIOCGIWRATE; for (i = 0; i < sizeof(bssid->rates); i++) { if (bssid->rates[i] & 0x7f) { @@ -1707,13 +1727,13 @@ static char *rndis_translate_scan(struct net_device *dev, ((bssid->rates[i] & 0x7f) * 500000); devdbg(usbdev, " %d", iwe.u.bitrate.value); - current_val = iwe_stream_add_value(cev, + current_val = iwe_stream_add_value(info, cev, current_val, end_buf, &iwe, IW_EV_PARAM_LEN); } } - if ((current_val - cev) > IW_EV_LCP_LEN) + if ((current_val - cev) > iwe_stream_lcp_len(info)) cev = current_val; beacon = le32_to_cpu(bssid->config.beacon_period); @@ -1721,14 +1741,14 @@ static char *rndis_translate_scan(struct net_device *dev, iwe.cmd = IWEVCUSTOM; snprintf(sbuf, sizeof(sbuf), "bcn_int=%d", beacon); iwe.u.data.length = strlen(sbuf); - cev = iwe_stream_add_point(cev, end_buf, &iwe, 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(cev, end_buf, &iwe, 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), @@ -1742,7 +1762,7 @@ static char *rndis_translate_scan(struct net_device *dev, (ie->id == MFIE_TYPE_RSN) ? 2 : 1); iwe.cmd = IWEVGENIE; iwe.u.data.length = min(ie->len + 2, MAX_WPA_IE_LEN); - cev = iwe_stream_add_point(cev, end_buf, &iwe, + cev = iwe_stream_add_point(info, cev, end_buf, &iwe, (u8 *)ie); } @@ -1785,8 +1805,8 @@ static int rndis_iw_get_scan(struct net_device *dev, devdbg(usbdev, "SIOCGIWSCAN: %d BSSIDs found", count); while (count && ((void *)bssid + bssid_len) <= (buf + len)) { - cev = rndis_translate_scan(dev, cev, extra + IW_SCAN_MAX_DATA, - bssid); + 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--; @@ -2213,7 +2233,9 @@ static void rndis_wext_worker(struct work_struct *work) int assoc_size = sizeof(*info) + IW_CUSTOM_MAX + 32; int ret, offset; - if (test_and_clear_bit(WORK_CONNECTION_EVENT, &priv->work_pending)) { + if (test_and_clear_bit(WORK_LINK_UP, &priv->work_pending)) { + netif_carrier_on(usbdev->net); + info = kzalloc(assoc_size, GFP_KERNEL); if (!info) goto get_bssid; @@ -2251,6 +2273,15 @@ get_bssid: } } + if (test_and_clear_bit(WORK_LINK_DOWN, &priv->work_pending)) { + netif_carrier_off(usbdev->net); + + evt.data.flags = 0; + evt.data.length = 0; + memset(evt.ap_addr.sa_data, 0, ETH_ALEN); + wireless_send_event(usbdev->net, SIOCGIWAP, &evt, NULL); + } + if (test_and_clear_bit(WORK_SET_MULTICAST_LIST, &priv->work_pending)) set_multicast_list(usbdev); } @@ -2260,29 +2291,24 @@ static void rndis_wext_set_multicast_list(struct net_device *dev) struct usbnet *usbdev = dev->priv; struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev); + if (test_bit(WORK_SET_MULTICAST_LIST, &priv->work_pending)) + return; + set_bit(WORK_SET_MULTICAST_LIST, &priv->work_pending); queue_work(priv->workqueue, &priv->work); } -static void rndis_wext_link_change(struct usbnet *dev, int state) +static void rndis_wext_link_change(struct usbnet *usbdev, int state) { - struct rndis_wext_private *priv = get_rndis_wext_priv(dev); - union iwreq_data evt; + struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev); - if (state) { - /* queue work to avoid recursive calls into rndis_command */ - set_bit(WORK_CONNECTION_EVENT, &priv->work_pending); - queue_work(priv->workqueue, &priv->work); - } else { - evt.data.flags = 0; - evt.data.length = 0; - memset(evt.ap_addr.sa_data, 0, ETH_ALEN); - wireless_send_event(dev->net, SIOCGIWAP, &evt, NULL); - } + /* queue work to avoid recursive calls into rndis_command */ + set_bit(state ? WORK_LINK_UP : WORK_LINK_DOWN, &priv->work_pending); + queue_work(priv->workqueue, &priv->work); } -static int rndis_wext_get_caps(struct usbnet *dev) +static int rndis_wext_get_caps(struct usbnet *usbdev) { struct { __le32 num_items; @@ -2290,18 +2316,18 @@ static int rndis_wext_get_caps(struct usbnet *dev) } networks_supported; int len, retval, i, n; __le32 tx_power; - struct rndis_wext_private *priv = get_rndis_wext_priv(dev); + struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev); /* determine if supports setting txpower */ len = sizeof(tx_power); - retval = rndis_query_oid(dev, OID_802_11_TX_POWER_LEVEL, &tx_power, - &len); + 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(dev, OID_802_11_NETWORK_TYPES_SUPPORTED, + retval = rndis_query_oid(usbdev, OID_802_11_NETWORK_TYPES_SUPPORTED, &networks_supported, &len); if (retval >= 0) { n = le32_to_cpu(networks_supported.num_items); @@ -2440,9 +2466,9 @@ end: } -static int bcm4320_early_init(struct usbnet *dev) +static int bcm4320_early_init(struct usbnet *usbdev) { - struct rndis_wext_private *priv = get_rndis_wext_priv(dev); + struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev); char buf[8]; /* Early initialization settings, setting these won't have effect @@ -2490,51 +2516,48 @@ static int bcm4320_early_init(struct usbnet *dev) else priv->param_workaround_interval = modparam_workaround_interval; - rndis_set_config_parameter_str(dev, "Country", priv->param_country); - rndis_set_config_parameter_str(dev, "FrameBursting", + rndis_set_config_parameter_str(usbdev, "Country", priv->param_country); + rndis_set_config_parameter_str(usbdev, "FrameBursting", priv->param_frameburst ? "1" : "0"); - rndis_set_config_parameter_str(dev, "Afterburner", + rndis_set_config_parameter_str(usbdev, "Afterburner", priv->param_afterburner ? "1" : "0"); sprintf(buf, "%d", priv->param_power_save); - rndis_set_config_parameter_str(dev, "PowerSaveMode", buf); + rndis_set_config_parameter_str(usbdev, "PowerSaveMode", buf); sprintf(buf, "%d", priv->param_power_output); - rndis_set_config_parameter_str(dev, "PwrOut", buf); + rndis_set_config_parameter_str(usbdev, "PwrOut", buf); sprintf(buf, "%d", priv->param_roamtrigger); - rndis_set_config_parameter_str(dev, "RoamTrigger", buf); + rndis_set_config_parameter_str(usbdev, "RoamTrigger", buf); sprintf(buf, "%d", priv->param_roamdelta); - rndis_set_config_parameter_str(dev, "RoamDelta", buf); + rndis_set_config_parameter_str(usbdev, "RoamDelta", buf); return 0; } -static int rndis_wext_bind(struct usbnet *dev, struct usb_interface *intf) +static int rndis_wext_bind(struct usbnet *usbdev, struct usb_interface *intf) { - struct net_device *net = dev->net; struct rndis_wext_private *priv; int retval, len; __le32 tmp; /* allocate rndis private data */ - priv = kmalloc(sizeof(struct rndis_wext_private), GFP_KERNEL); + priv = kzalloc(sizeof(struct rndis_wext_private), GFP_KERNEL); if (!priv) return -ENOMEM; /* These have to be initialized before calling generic_rndis_bind(). * Otherwise we'll be in big trouble in rndis_wext_early_init(). */ - dev->driver_priv = priv; - memset(priv, 0, sizeof(*priv)); - memset(priv->name, 0, sizeof(priv->name)); + usbdev->driver_priv = priv; strcpy(priv->name, "IEEE802.11"); - net->wireless_handlers = &rndis_iw_handlers; - priv->usbdev = dev; + usbdev->net->wireless_handlers = &rndis_iw_handlers; + priv->usbdev = usbdev; mutex_init(&priv->command_lock); spin_lock_init(&priv->stats_lock); /* try bind rndis_host */ - retval = generic_rndis_bind(dev, intf, FLAG_RNDIS_PHYM_WIRELESS); + retval = generic_rndis_bind(usbdev, intf, FLAG_RNDIS_PHYM_WIRELESS); if (retval < 0) goto fail; @@ -2545,20 +2568,21 @@ static int rndis_wext_bind(struct usbnet *dev, struct usb_interface *intf) * rndis_host wants to avoid all OID as much as possible * so do promisc/multicast handling in rndis_wext. */ - dev->net->set_multicast_list = rndis_wext_set_multicast_list; + usbdev->net->set_multicast_list = rndis_wext_set_multicast_list; tmp = RNDIS_PACKET_TYPE_DIRECTED | RNDIS_PACKET_TYPE_BROADCAST; - retval = rndis_set_oid(dev, OID_GEN_CURRENT_PACKET_FILTER, &tmp, + retval = rndis_set_oid(usbdev, OID_GEN_CURRENT_PACKET_FILTER, &tmp, sizeof(tmp)); len = sizeof(tmp); - retval = rndis_query_oid(dev, OID_802_3_MAXIMUM_LIST_SIZE, &tmp, &len); + retval = rndis_query_oid(usbdev, OID_802_3_MAXIMUM_LIST_SIZE, &tmp, + &len); priv->multicast_size = le32_to_cpu(tmp); if (retval < 0 || priv->multicast_size < 0) priv->multicast_size = 0; if (priv->multicast_size > 0) - dev->net->flags |= IFF_MULTICAST; + usbdev->net->flags |= IFF_MULTICAST; else - dev->net->flags &= ~IFF_MULTICAST; + usbdev->net->flags &= ~IFF_MULTICAST; priv->iwstats.qual.qual = 0; priv->iwstats.qual.level = 0; @@ -2568,12 +2592,13 @@ static int rndis_wext_bind(struct usbnet *dev, struct usb_interface *intf) | IW_QUAL_QUAL_INVALID | IW_QUAL_LEVEL_INVALID; - rndis_wext_get_caps(dev); - set_default_iw_params(dev); + rndis_wext_get_caps(usbdev); + set_default_iw_params(usbdev); /* turn radio on */ priv->radio_on = 1; - disassociate(dev, 1); + disassociate(usbdev, 1); + netif_carrier_off(usbdev->net); /* because rndis_command() sleeps we need to use workqueue */ priv->workqueue = create_singlethread_workqueue("rndis_wlan"); @@ -2590,12 +2615,12 @@ fail: } -static void rndis_wext_unbind(struct usbnet *dev, struct usb_interface *intf) +static void rndis_wext_unbind(struct usbnet *usbdev, struct usb_interface *intf) { - struct rndis_wext_private *priv = get_rndis_wext_priv(dev); + struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev); /* turn radio off */ - disassociate(dev, 0); + disassociate(usbdev, 0); cancel_delayed_work_sync(&priv->stats_work); cancel_work_sync(&priv->work); @@ -2606,13 +2631,13 @@ static void rndis_wext_unbind(struct usbnet *dev, struct usb_interface *intf) kfree(priv->wpa_ie); kfree(priv); - rndis_unbind(dev, intf); + rndis_unbind(usbdev, intf); } -static int rndis_wext_reset(struct usbnet *dev) +static int rndis_wext_reset(struct usbnet *usbdev) { - return deauthenticate(dev); + return deauthenticate(usbdev); } diff --git a/drivers/net/wireless/rt2x00/Kconfig b/drivers/net/wireless/rt2x00/Kconfig index 2d611876bbe0..d485a86bba75 100644 --- a/drivers/net/wireless/rt2x00/Kconfig +++ b/drivers/net/wireless/rt2x00/Kconfig @@ -5,12 +5,16 @@ config RT2X00 This will enable the experimental support for the Ralink drivers, developed in the rt2x00 project <http://rt2x00.serialmonkey.com>. - These drivers will make use of the mac80211 stack. + These drivers make use of the mac80211 stack. When building one of the individual drivers, the rt2x00 library will also be created. That library (when the driver is built as a module) will be called "rt2x00lib.ko". + Additionally PCI and USB libraries will also be build depending + on the types of drivers being selected, these libraries will be + called "rt2x00pci.ko" and "rt2x00usb.ko". + if RT2X00 config RT2X00_LIB @@ -32,35 +36,34 @@ config RT2X00_LIB_FIRMWARE config RT2X00_LIB_RFKILL boolean depends on RT2X00_LIB - depends on INPUT select RFKILL - select INPUT_POLLDEV config RT2X00_LIB_LEDS boolean depends on RT2X00_LIB && NEW_LEDS config RT2400PCI - tristate "Ralink rt2400 pci/pcmcia support" + tristate "Ralink rt2400 (PCI/PCMCIA) support" depends on PCI select RT2X00_LIB_PCI select EEPROM_93CX6 ---help--- - This is an experimental driver for the Ralink rt2400 wireless chip. + This adds support for rt2400 wireless chipset family. + Supported chips: RT2460. When compiled as a module, this driver will be called "rt2400pci.ko". config RT2400PCI_RFKILL - bool "RT2400 rfkill support" - depends on RT2400PCI && INPUT + bool "Ralink rt2400 rfkill support" + depends on RT2400PCI select RT2X00_LIB_RFKILL ---help--- - This adds support for integrated rt2400 devices that feature a + This adds support for integrated rt2400 hardware that features a hardware button to control the radio state. This feature depends on the RF switch subsystem rfkill. config RT2400PCI_LEDS - bool "RT2400 leds support" + bool "Ralink rt2400 leds support" depends on RT2400PCI && NEW_LEDS select LEDS_CLASS select RT2X00_LIB_LEDS @@ -68,26 +71,27 @@ config RT2400PCI_LEDS This adds support for led triggers provided my mac80211. config RT2500PCI - tristate "Ralink rt2500 pci/pcmcia support" + tristate "Ralink rt2500 (PCI/PCMCIA) support" depends on PCI select RT2X00_LIB_PCI select EEPROM_93CX6 ---help--- - This is an experimental driver for the Ralink rt2500 wireless chip. + This adds support for rt2500 wireless chipset family. + Supported chips: RT2560. When compiled as a module, this driver will be called "rt2500pci.ko". config RT2500PCI_RFKILL - bool "RT2500 rfkill support" - depends on RT2500PCI && INPUT + bool "Ralink rt2500 rfkill support" + depends on RT2500PCI select RT2X00_LIB_RFKILL ---help--- - This adds support for integrated rt2500 devices that feature a + This adds support for integrated rt2500 hardware that features a hardware button to control the radio state. This feature depends on the RF switch subsystem rfkill. config RT2500PCI_LEDS - bool "RT2500 leds support" + bool "Ralink rt2500 leds support" depends on RT2500PCI && NEW_LEDS select LEDS_CLASS select RT2X00_LIB_LEDS @@ -95,28 +99,29 @@ config RT2500PCI_LEDS This adds support for led triggers provided my mac80211. config RT61PCI - tristate "Ralink rt61 pci/pcmcia support" + tristate "Ralink rt2501/rt61 (PCI/PCMCIA) support" depends on PCI select RT2X00_LIB_PCI select RT2X00_LIB_FIRMWARE select CRC_ITU_T select EEPROM_93CX6 ---help--- - This is an experimental driver for the Ralink rt61 wireless chip. + This adds support for rt2501 wireless chipset family. + Supported chips: RT2561, RT2561S & RT2661. When compiled as a module, this driver will be called "rt61pci.ko". config RT61PCI_RFKILL - bool "RT61 rfkill support" - depends on RT61PCI && INPUT + bool "Ralink rt2501/rt61 rfkill support" + depends on RT61PCI select RT2X00_LIB_RFKILL ---help--- - This adds support for integrated rt61 devices that feature a + This adds support for integrated rt61 hardware that features a hardware button to control the radio state. This feature depends on the RF switch subsystem rfkill. config RT61PCI_LEDS - bool "RT61 leds support" + bool "Ralink rt2501/rt61 leds support" depends on RT61PCI && NEW_LEDS select LEDS_CLASS select RT2X00_LIB_LEDS @@ -124,16 +129,17 @@ config RT61PCI_LEDS This adds support for led triggers provided my mac80211. config RT2500USB - tristate "Ralink rt2500 usb support" + tristate "Ralink rt2500 (USB) support" depends on USB select RT2X00_LIB_USB ---help--- - This is an experimental driver for the Ralink rt2500 wireless chip. + This adds support for rt2500 wireless chipset family. + Supported chips: RT2571 & RT2572. When compiled as a module, this driver will be called "rt2500usb.ko". config RT2500USB_LEDS - bool "RT2500 leds support" + bool "Ralink rt2500 leds support" depends on RT2500USB && NEW_LEDS select LEDS_CLASS select RT2X00_LIB_LEDS @@ -141,18 +147,19 @@ config RT2500USB_LEDS This adds support for led triggers provided my mac80211. config RT73USB - tristate "Ralink rt73 usb support" + tristate "Ralink rt2501/rt73 (USB) support" depends on USB select RT2X00_LIB_USB select RT2X00_LIB_FIRMWARE select CRC_ITU_T ---help--- - This is an experimental driver for the Ralink rt73 wireless chip. + This adds support for rt2501 wireless chipset family. + Supported chips: RT2571W, RT2573 & RT2671. When compiled as a module, this driver will be called "rt73usb.ko". config RT73USB_LEDS - bool "RT73 leds support" + bool "Ralink rt2501/rt73 leds support" depends on RT73USB && NEW_LEDS select LEDS_CLASS select RT2X00_LIB_LEDS @@ -165,7 +172,7 @@ config RT2X00_LIB_DEBUGFS ---help--- Enable creation of debugfs files for the rt2x00 drivers. These debugfs files support both reading and writing of the - most important register types of the rt2x00 devices. + most important register types of the rt2x00 hardware. config RT2X00_DEBUG bool "Ralink debug output" diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c index b36ed1c6c746..4c0538d6099b 100644 --- a/drivers/net/wireless/rt2x00/rt2400pci.c +++ b/drivers/net/wireless/rt2x00/rt2400pci.c @@ -277,6 +277,17 @@ static int rt2400pci_blink_set(struct led_classdev *led_cdev, return 0; } + +static void rt2400pci_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 = rt2400pci_brightness_set; + led->led_dev.blink_set = rt2400pci_blink_set; + led->flags = LED_INITIALIZED; +} #endif /* CONFIG_RT2400PCI_LEDS */ /* @@ -620,48 +631,38 @@ static void rt2400pci_link_tuner(struct rt2x00_dev *rt2x00dev) static void rt2400pci_init_rxentry(struct rt2x00_dev *rt2x00dev, struct queue_entry *entry) { - struct queue_entry_priv_pci_rx *priv_rx = entry->priv_data; + struct queue_entry_priv_pci *entry_priv = entry->priv_data; + struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb); u32 word; - rt2x00_desc_read(priv_rx->desc, 2, &word); - rt2x00_set_field32(&word, RXD_W2_BUFFER_LENGTH, - entry->queue->data_size); - rt2x00_desc_write(priv_rx->desc, 2, word); + rt2x00_desc_read(entry_priv->desc, 2, &word); + rt2x00_set_field32(&word, RXD_W2_BUFFER_LENGTH, entry->skb->len); + rt2x00_desc_write(entry_priv->desc, 2, word); - rt2x00_desc_read(priv_rx->desc, 1, &word); - rt2x00_set_field32(&word, RXD_W1_BUFFER_ADDRESS, priv_rx->data_dma); - rt2x00_desc_write(priv_rx->desc, 1, word); + rt2x00_desc_read(entry_priv->desc, 1, &word); + rt2x00_set_field32(&word, RXD_W1_BUFFER_ADDRESS, skbdesc->skb_dma); + rt2x00_desc_write(entry_priv->desc, 1, word); - rt2x00_desc_read(priv_rx->desc, 0, &word); + rt2x00_desc_read(entry_priv->desc, 0, &word); rt2x00_set_field32(&word, RXD_W0_OWNER_NIC, 1); - rt2x00_desc_write(priv_rx->desc, 0, word); + rt2x00_desc_write(entry_priv->desc, 0, word); } static void rt2400pci_init_txentry(struct rt2x00_dev *rt2x00dev, struct queue_entry *entry) { - struct queue_entry_priv_pci_tx *priv_tx = entry->priv_data; + struct queue_entry_priv_pci *entry_priv = entry->priv_data; u32 word; - rt2x00_desc_read(priv_tx->desc, 1, &word); - rt2x00_set_field32(&word, TXD_W1_BUFFER_ADDRESS, priv_tx->data_dma); - rt2x00_desc_write(priv_tx->desc, 1, word); - - rt2x00_desc_read(priv_tx->desc, 2, &word); - rt2x00_set_field32(&word, TXD_W2_BUFFER_LENGTH, - entry->queue->data_size); - rt2x00_desc_write(priv_tx->desc, 2, word); - - rt2x00_desc_read(priv_tx->desc, 0, &word); + rt2x00_desc_read(entry_priv->desc, 0, &word); rt2x00_set_field32(&word, TXD_W0_VALID, 0); rt2x00_set_field32(&word, TXD_W0_OWNER_NIC, 0); - rt2x00_desc_write(priv_tx->desc, 0, word); + rt2x00_desc_write(entry_priv->desc, 0, word); } static int rt2400pci_init_queues(struct rt2x00_dev *rt2x00dev) { - struct queue_entry_priv_pci_rx *priv_rx; - struct queue_entry_priv_pci_tx *priv_tx; + struct queue_entry_priv_pci *entry_priv; u32 reg; /* @@ -674,28 +675,28 @@ static int rt2400pci_init_queues(struct rt2x00_dev *rt2x00dev) rt2x00_set_field32(®, TXCSR2_NUM_PRIO, rt2x00dev->tx[0].limit); rt2x00pci_register_write(rt2x00dev, TXCSR2, reg); - priv_tx = rt2x00dev->tx[1].entries[0].priv_data; + entry_priv = rt2x00dev->tx[1].entries[0].priv_data; rt2x00pci_register_read(rt2x00dev, TXCSR3, ®); rt2x00_set_field32(®, TXCSR3_TX_RING_REGISTER, - priv_tx->desc_dma); + entry_priv->desc_dma); rt2x00pci_register_write(rt2x00dev, TXCSR3, reg); - priv_tx = rt2x00dev->tx[0].entries[0].priv_data; + entry_priv = rt2x00dev->tx[0].entries[0].priv_data; rt2x00pci_register_read(rt2x00dev, TXCSR5, ®); rt2x00_set_field32(®, TXCSR5_PRIO_RING_REGISTER, - priv_tx->desc_dma); + entry_priv->desc_dma); rt2x00pci_register_write(rt2x00dev, TXCSR5, reg); - priv_tx = rt2x00dev->bcn[1].entries[0].priv_data; + entry_priv = rt2x00dev->bcn[1].entries[0].priv_data; rt2x00pci_register_read(rt2x00dev, TXCSR4, ®); rt2x00_set_field32(®, TXCSR4_ATIM_RING_REGISTER, - priv_tx->desc_dma); + entry_priv->desc_dma); rt2x00pci_register_write(rt2x00dev, TXCSR4, reg); - priv_tx = rt2x00dev->bcn[0].entries[0].priv_data; + entry_priv = rt2x00dev->bcn[0].entries[0].priv_data; rt2x00pci_register_read(rt2x00dev, TXCSR6, ®); rt2x00_set_field32(®, TXCSR6_BEACON_RING_REGISTER, - priv_tx->desc_dma); + entry_priv->desc_dma); rt2x00pci_register_write(rt2x00dev, TXCSR6, reg); rt2x00pci_register_read(rt2x00dev, RXCSR1, ®); @@ -703,9 +704,10 @@ static int rt2400pci_init_queues(struct rt2x00_dev *rt2x00dev) rt2x00_set_field32(®, RXCSR1_NUM_RXD, rt2x00dev->rx->limit); rt2x00pci_register_write(rt2x00dev, RXCSR1, reg); - priv_rx = rt2x00dev->rx->entries[0].priv_data; + entry_priv = rt2x00dev->rx->entries[0].priv_data; rt2x00pci_register_read(rt2x00dev, RXCSR2, ®); - rt2x00_set_field32(®, RXCSR2_RX_RING_REGISTER, priv_rx->desc_dma); + rt2x00_set_field32(®, RXCSR2_RX_RING_REGISTER, + entry_priv->desc_dma); rt2x00pci_register_write(rt2x00dev, RXCSR2, reg); return 0; @@ -801,25 +803,32 @@ static int rt2400pci_init_registers(struct rt2x00_dev *rt2x00dev) return 0; } -static int rt2400pci_init_bbp(struct rt2x00_dev *rt2x00dev) +static int rt2400pci_wait_bbp_ready(struct rt2x00_dev *rt2x00dev) { unsigned int i; - u16 eeprom; - u8 reg_id; u8 value; for (i = 0; i < REGISTER_BUSY_COUNT; i++) { rt2400pci_bbp_read(rt2x00dev, 0, &value); if ((value != 0xff) && (value != 0x00)) - goto continue_csr_init; - NOTICE(rt2x00dev, "Waiting for BBP register.\n"); + return 0; udelay(REGISTER_BUSY_DELAY); } ERROR(rt2x00dev, "BBP register access failed, aborting.\n"); return -EACCES; +} + +static int rt2400pci_init_bbp(struct rt2x00_dev *rt2x00dev) +{ + unsigned int i; + u16 eeprom; + u8 reg_id; + u8 value; + + if (unlikely(rt2400pci_wait_bbp_ready(rt2x00dev))) + return -EACCES; -continue_csr_init: rt2400pci_bbp_write(rt2x00dev, 1, 0x00); rt2400pci_bbp_write(rt2x00dev, 3, 0x27); rt2400pci_bbp_write(rt2x00dev, 4, 0x08); @@ -858,7 +867,8 @@ static void rt2400pci_toggle_rx(struct rt2x00_dev *rt2x00dev, rt2x00pci_register_read(rt2x00dev, RXCSR0, ®); rt2x00_set_field32(®, RXCSR0_DISABLE_RX, - state == STATE_RADIO_RX_OFF); + (state == STATE_RADIO_RX_OFF) || + (state == STATE_RADIO_RX_OFF_LINK)); rt2x00pci_register_write(rt2x00dev, RXCSR0, reg); } @@ -895,17 +905,10 @@ static int rt2400pci_enable_radio(struct rt2x00_dev *rt2x00dev) /* * Initialize all registers. */ - if (rt2400pci_init_queues(rt2x00dev) || - rt2400pci_init_registers(rt2x00dev) || - rt2400pci_init_bbp(rt2x00dev)) { - ERROR(rt2x00dev, "Register initialization failed.\n"); + if (unlikely(rt2400pci_init_queues(rt2x00dev) || + rt2400pci_init_registers(rt2x00dev) || + rt2400pci_init_bbp(rt2x00dev))) return -EIO; - } - - /* - * Enable interrupts. - */ - rt2400pci_toggle_irq(rt2x00dev, STATE_RADIO_IRQ_ON); return 0; } @@ -927,11 +930,6 @@ static void rt2400pci_disable_radio(struct rt2x00_dev *rt2x00dev) rt2x00pci_register_read(rt2x00dev, TXCSR0, ®); rt2x00_set_field32(®, TXCSR0_ABORT, 1); rt2x00pci_register_write(rt2x00dev, TXCSR0, reg); - - /* - * Disable interrupts. - */ - rt2400pci_toggle_irq(rt2x00dev, STATE_RADIO_IRQ_OFF); } static int rt2400pci_set_state(struct rt2x00_dev *rt2x00dev, @@ -966,10 +964,6 @@ static int rt2400pci_set_state(struct rt2x00_dev *rt2x00dev, msleep(10); } - NOTICE(rt2x00dev, "Device failed to enter state %d, " - "current device state: bbp %d and rf %d.\n", - state, bbp_state, rf_state); - return -EBUSY; } @@ -987,11 +981,13 @@ static int rt2400pci_set_device_state(struct rt2x00_dev *rt2x00dev, break; case STATE_RADIO_RX_ON: case STATE_RADIO_RX_ON_LINK: - rt2400pci_toggle_rx(rt2x00dev, STATE_RADIO_RX_ON); - break; case STATE_RADIO_RX_OFF: case STATE_RADIO_RX_OFF_LINK: - rt2400pci_toggle_rx(rt2x00dev, STATE_RADIO_RX_OFF); + rt2400pci_toggle_rx(rt2x00dev, state); + break; + case STATE_RADIO_IRQ_ON: + case STATE_RADIO_IRQ_OFF: + rt2400pci_toggle_irq(rt2x00dev, state); break; case STATE_DEEP_SLEEP: case STATE_SLEEP: @@ -1004,6 +1000,10 @@ static int rt2400pci_set_device_state(struct rt2x00_dev *rt2x00dev, break; } + if (unlikely(retval)) + ERROR(rt2x00dev, "Device failed to enter state %d (%d).\n", + state, retval); + return retval; } @@ -1012,18 +1012,23 @@ static int rt2400pci_set_device_state(struct rt2x00_dev *rt2x00dev, */ static void rt2400pci_write_tx_desc(struct rt2x00_dev *rt2x00dev, struct sk_buff *skb, - struct txentry_desc *txdesc, - struct ieee80211_tx_control *control) + struct txentry_desc *txdesc) { struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb); + struct queue_entry_priv_pci *entry_priv = skbdesc->entry->priv_data; __le32 *txd = skbdesc->desc; u32 word; /* * Start writing the descriptor words. */ + rt2x00_desc_read(entry_priv->desc, 1, &word); + rt2x00_set_field32(&word, TXD_W1_BUFFER_ADDRESS, skbdesc->skb_dma); + rt2x00_desc_write(entry_priv->desc, 1, word); + rt2x00_desc_read(txd, 2, &word); - rt2x00_set_field32(&word, TXD_W2_DATABYTE_COUNT, skbdesc->data_len); + rt2x00_set_field32(&word, TXD_W2_BUFFER_LENGTH, skb->len); + rt2x00_set_field32(&word, TXD_W2_DATABYTE_COUNT, skb->len); rt2x00_desc_write(txd, 2, word); rt2x00_desc_read(txd, 3, &word); @@ -1057,20 +1062,53 @@ static void rt2400pci_write_tx_desc(struct rt2x00_dev *rt2x00dev, test_bit(ENTRY_TXD_RTS_FRAME, &txdesc->flags)); rt2x00_set_field32(&word, TXD_W0_IFS, txdesc->ifs); rt2x00_set_field32(&word, TXD_W0_RETRY_MODE, - !!(control->flags & - IEEE80211_TXCTL_LONG_RETRY_LIMIT)); + test_bit(ENTRY_TXD_RETRY_MODE, &txdesc->flags)); rt2x00_desc_write(txd, 0, word); } /* * TX data initialization */ +static void rt2400pci_write_beacon(struct queue_entry *entry) +{ + struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev; + struct queue_entry_priv_pci *entry_priv = entry->priv_data; + struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb); + u32 word; + u32 reg; + + /* + * Disable beaconing while we are reloading the beacon data, + * otherwise we might be sending out invalid data. + */ + rt2x00pci_register_read(rt2x00dev, CSR14, ®); + rt2x00_set_field32(®, CSR14_TSF_COUNT, 0); + rt2x00_set_field32(®, CSR14_TBCN, 0); + rt2x00_set_field32(®, CSR14_BEACON_GEN, 0); + rt2x00pci_register_write(rt2x00dev, CSR14, reg); + + /* + * Replace rt2x00lib allocated descriptor with the + * pointer to the _real_ hardware descriptor. + * After that, map the beacon to DMA and update the + * descriptor. + */ + memcpy(entry_priv->desc, skbdesc->desc, skbdesc->desc_len); + skbdesc->desc = entry_priv->desc; + + rt2x00queue_map_txskb(rt2x00dev, entry->skb); + + rt2x00_desc_read(entry_priv->desc, 1, &word); + rt2x00_set_field32(&word, TXD_W1_BUFFER_ADDRESS, skbdesc->skb_dma); + rt2x00_desc_write(entry_priv->desc, 1, word); +} + static void rt2400pci_kick_tx_queue(struct rt2x00_dev *rt2x00dev, - const unsigned int queue) + const enum data_queue_qid queue) { u32 reg; - if (queue == RT2X00_BCN_QUEUE_BEACON) { + if (queue == QID_BEACON) { rt2x00pci_register_read(rt2x00dev, CSR14, ®); if (!rt2x00_get_field32(reg, CSR14_BEACON_GEN)) { rt2x00_set_field32(®, CSR14_TSF_COUNT, 1); @@ -1082,12 +1120,9 @@ static void rt2400pci_kick_tx_queue(struct rt2x00_dev *rt2x00dev, } rt2x00pci_register_read(rt2x00dev, TXCSR0, ®); - rt2x00_set_field32(®, TXCSR0_KICK_PRIO, - (queue == IEEE80211_TX_QUEUE_DATA0)); - rt2x00_set_field32(®, TXCSR0_KICK_TX, - (queue == IEEE80211_TX_QUEUE_DATA1)); - rt2x00_set_field32(®, TXCSR0_KICK_ATIM, - (queue == RT2X00_BCN_QUEUE_ATIM)); + rt2x00_set_field32(®, TXCSR0_KICK_PRIO, (queue == QID_AC_BE)); + rt2x00_set_field32(®, TXCSR0_KICK_TX, (queue == QID_AC_BK)); + rt2x00_set_field32(®, TXCSR0_KICK_ATIM, (queue == QID_ATIM)); rt2x00pci_register_write(rt2x00dev, TXCSR0, reg); } @@ -1097,32 +1132,54 @@ static void rt2400pci_kick_tx_queue(struct rt2x00_dev *rt2x00dev, static void rt2400pci_fill_rxdone(struct queue_entry *entry, struct rxdone_entry_desc *rxdesc) { - struct queue_entry_priv_pci_rx *priv_rx = entry->priv_data; + struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev; + struct queue_entry_priv_pci *entry_priv = entry->priv_data; u32 word0; u32 word2; u32 word3; + u32 word4; + u64 tsf; + u32 rx_low; + u32 rx_high; - rt2x00_desc_read(priv_rx->desc, 0, &word0); - rt2x00_desc_read(priv_rx->desc, 2, &word2); - rt2x00_desc_read(priv_rx->desc, 3, &word3); + rt2x00_desc_read(entry_priv->desc, 0, &word0); + rt2x00_desc_read(entry_priv->desc, 2, &word2); + rt2x00_desc_read(entry_priv->desc, 3, &word3); + rt2x00_desc_read(entry_priv->desc, 4, &word4); - rxdesc->flags = 0; if (rt2x00_get_field32(word0, RXD_W0_CRC_ERROR)) rxdesc->flags |= RX_FLAG_FAILED_FCS_CRC; if (rt2x00_get_field32(word0, RXD_W0_PHYSICAL_ERROR)) rxdesc->flags |= RX_FLAG_FAILED_PLCP_CRC; /* + * We only get the lower 32bits from the timestamp, + * to get the full 64bits we must complement it with + * the timestamp from get_tsf(). + * Note that when a wraparound of the lower 32bits + * has occurred between the frame arrival and the get_tsf() + * call, we must decrease the higher 32bits with 1 to get + * to correct value. + */ + tsf = rt2x00dev->ops->hw->get_tsf(rt2x00dev->hw); + rx_low = rt2x00_get_field32(word4, RXD_W4_RX_END_TIME); + rx_high = upper_32_bits(tsf); + + if ((u32)tsf <= rx_low) + rx_high--; + + /* * Obtain the status about this packet. * The signal is the PLCP value, and needs to be stripped * of the preamble bit (0x08). */ + rxdesc->timestamp = ((u64)rx_high << 32) | rx_low; rxdesc->signal = rt2x00_get_field32(word2, RXD_W2_SIGNAL) & ~0x08; rxdesc->rssi = rt2x00_get_field32(word2, RXD_W3_RSSI) - entry->queue->rt2x00dev->rssi_offset; rxdesc->size = rt2x00_get_field32(word0, RXD_W0_DATABYTE_COUNT); - rxdesc->dev_flags = RXDONE_SIGNAL_PLCP; + rxdesc->dev_flags |= RXDONE_SIGNAL_PLCP; if (rt2x00_get_field32(word0, RXD_W0_MY_BSS)) rxdesc->dev_flags |= RXDONE_MY_BSS; } @@ -1131,18 +1188,18 @@ static void rt2400pci_fill_rxdone(struct queue_entry *entry, * Interrupt functions. */ static void rt2400pci_txdone(struct rt2x00_dev *rt2x00dev, - const enum ieee80211_tx_queue queue_idx) + const enum data_queue_qid queue_idx) { struct data_queue *queue = rt2x00queue_get_queue(rt2x00dev, queue_idx); - struct queue_entry_priv_pci_tx *priv_tx; + struct queue_entry_priv_pci *entry_priv; struct queue_entry *entry; struct txdone_entry_desc txdesc; u32 word; while (!rt2x00queue_empty(queue)) { entry = rt2x00queue_get_entry(queue, Q_INDEX_DONE); - priv_tx = entry->priv_data; - rt2x00_desc_read(priv_tx->desc, 0, &word); + entry_priv = entry->priv_data; + rt2x00_desc_read(entry_priv->desc, 0, &word); if (rt2x00_get_field32(word, TXD_W0_OWNER_NIC) || !rt2x00_get_field32(word, TXD_W0_VALID)) @@ -1151,10 +1208,21 @@ static void rt2400pci_txdone(struct rt2x00_dev *rt2x00dev, /* * Obtain the status about this packet. */ - txdesc.status = rt2x00_get_field32(word, TXD_W0_RESULT); + txdesc.flags = 0; + switch (rt2x00_get_field32(word, TXD_W0_RESULT)) { + case 0: /* Success */ + case 1: /* Success with retry */ + __set_bit(TXDONE_SUCCESS, &txdesc.flags); + break; + case 2: /* Failure, excessive retries */ + __set_bit(TXDONE_EXCESSIVE_RETRY, &txdesc.flags); + /* Don't break, this is a failed frame! */ + default: /* Failure */ + __set_bit(TXDONE_FAILURE, &txdesc.flags); + } txdesc.retry = rt2x00_get_field32(word, TXD_W0_RETRY_COUNT); - rt2x00pci_txdone(rt2x00dev, entry, &txdesc); + rt2x00lib_txdone(entry, &txdesc); } } @@ -1198,19 +1266,19 @@ static irqreturn_t rt2400pci_interrupt(int irq, void *dev_instance) * 3 - Atim ring transmit done interrupt. */ if (rt2x00_get_field32(reg, CSR7_TXDONE_ATIMRING)) - rt2400pci_txdone(rt2x00dev, RT2X00_BCN_QUEUE_ATIM); + rt2400pci_txdone(rt2x00dev, QID_ATIM); /* * 4 - Priority ring transmit done interrupt. */ if (rt2x00_get_field32(reg, CSR7_TXDONE_PRIORING)) - rt2400pci_txdone(rt2x00dev, IEEE80211_TX_QUEUE_DATA0); + rt2400pci_txdone(rt2x00dev, QID_AC_BE); /* * 5 - Tx ring transmit done interrupt. */ if (rt2x00_get_field32(reg, CSR7_TXDONE_TXRING)) - rt2400pci_txdone(rt2x00dev, IEEE80211_TX_QUEUE_DATA1); + rt2400pci_txdone(rt2x00dev, QID_AC_BK); return IRQ_HANDLED; } @@ -1309,23 +1377,10 @@ static int rt2400pci_init_eeprom(struct rt2x00_dev *rt2x00dev) #ifdef CONFIG_RT2400PCI_LEDS value = rt2x00_get_field16(eeprom, EEPROM_ANTENNA_LED_MODE); - rt2x00dev->led_radio.rt2x00dev = rt2x00dev; - rt2x00dev->led_radio.type = LED_TYPE_RADIO; - rt2x00dev->led_radio.led_dev.brightness_set = - rt2400pci_brightness_set; - rt2x00dev->led_radio.led_dev.blink_set = - rt2400pci_blink_set; - rt2x00dev->led_radio.flags = LED_INITIALIZED; - - if (value == LED_MODE_TXRX_ACTIVITY) { - rt2x00dev->led_qual.rt2x00dev = rt2x00dev; - rt2x00dev->led_qual.type = LED_TYPE_ACTIVITY; - rt2x00dev->led_qual.led_dev.brightness_set = - rt2400pci_brightness_set; - rt2x00dev->led_qual.led_dev.blink_set = - rt2400pci_blink_set; - rt2x00dev->led_qual.flags = LED_INITIALIZED; - } + rt2400pci_init_led(rt2x00dev, &rt2x00dev->led_radio, LED_TYPE_RADIO); + if (value == LED_MODE_TXRX_ACTIVITY) + rt2400pci_init_led(rt2x00dev, &rt2x00dev->led_qual, + LED_TYPE_ACTIVITY); #endif /* CONFIG_RT2400PCI_LEDS */ /* @@ -1375,13 +1430,11 @@ static void rt2400pci_probe_hw_mode(struct rt2x00_dev *rt2x00dev) /* * Initialize all hw fields. */ - rt2x00dev->hw->flags = IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING; + rt2x00dev->hw->flags = IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | + IEEE80211_HW_SIGNAL_DBM; rt2x00dev->hw->extra_tx_headroom = 0; - rt2x00dev->hw->max_signal = MAX_SIGNAL; - rt2x00dev->hw->max_rssi = MAX_RX_SSI; - rt2x00dev->hw->queues = 2; - SET_IEEE80211_DEV(rt2x00dev->hw, &rt2x00dev_pci(rt2x00dev)->dev); + SET_IEEE80211_DEV(rt2x00dev->hw, rt2x00dev->dev); SET_IEEE80211_PERM_ADDR(rt2x00dev->hw, rt2x00_eeprom_addr(rt2x00dev, EEPROM_MAC_ADDR_0)); @@ -1427,9 +1480,10 @@ static int rt2400pci_probe_hw(struct rt2x00_dev *rt2x00dev) rt2400pci_probe_hw_mode(rt2x00dev); /* - * This device requires the atim queue + * This device requires the atim queue and DMA-mapped skbs. */ __set_bit(DRIVER_REQUIRE_ATIM_QUEUE, &rt2x00dev->flags); + __set_bit(DRIVER_REQUIRE_DMA, &rt2x00dev->flags); /* * Set the rssi offset. @@ -1456,8 +1510,7 @@ static int rt2400pci_set_retry_limit(struct ieee80211_hw *hw, return 0; } -static int rt2400pci_conf_tx(struct ieee80211_hw *hw, - int queue, +static int rt2400pci_conf_tx(struct ieee80211_hw *hw, u16 queue, const struct ieee80211_tx_queue_params *params) { struct rt2x00_dev *rt2x00dev = hw->priv; @@ -1467,7 +1520,7 @@ static int rt2400pci_conf_tx(struct ieee80211_hw *hw, * per queue. So by default we only configure the TX queue, * and ignore all other configurations. */ - if (queue != IEEE80211_TX_QUEUE_DATA0) + if (queue != 0) return -EINVAL; if (rt2x00mac_conf_tx(hw, queue, params)) @@ -1496,60 +1549,6 @@ static u64 rt2400pci_get_tsf(struct ieee80211_hw *hw) return tsf; } -static int rt2400pci_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb, - struct ieee80211_tx_control *control) -{ - struct rt2x00_dev *rt2x00dev = hw->priv; - struct rt2x00_intf *intf = vif_to_intf(control->vif); - struct queue_entry_priv_pci_tx *priv_tx; - struct skb_frame_desc *skbdesc; - u32 reg; - - if (unlikely(!intf->beacon)) - return -ENOBUFS; - priv_tx = intf->beacon->priv_data; - - /* - * Fill in skb descriptor - */ - skbdesc = get_skb_frame_desc(skb); - memset(skbdesc, 0, sizeof(*skbdesc)); - skbdesc->flags |= FRAME_DESC_DRIVER_GENERATED; - skbdesc->data = skb->data; - skbdesc->data_len = skb->len; - skbdesc->desc = priv_tx->desc; - skbdesc->desc_len = intf->beacon->queue->desc_size; - skbdesc->entry = intf->beacon; - - /* - * Disable beaconing while we are reloading the beacon data, - * otherwise we might be sending out invalid data. - */ - rt2x00pci_register_read(rt2x00dev, CSR14, ®); - rt2x00_set_field32(®, CSR14_TSF_COUNT, 0); - rt2x00_set_field32(®, CSR14_TBCN, 0); - rt2x00_set_field32(®, CSR14_BEACON_GEN, 0); - rt2x00pci_register_write(rt2x00dev, CSR14, reg); - - /* - * mac80211 doesn't provide the control->queue variable - * for beacons. Set our own queue identification so - * it can be used during descriptor initialization. - */ - control->queue = RT2X00_BCN_QUEUE_BEACON; - rt2x00lib_write_tx_desc(rt2x00dev, skb, control); - - /* - * Enable beacon generation. - * Write entire beacon with descriptor to register, - * and kick the beacon generator. - */ - memcpy(priv_tx->data, skb->data, skb->len); - rt2x00dev->ops->lib->kick_tx_queue(rt2x00dev, control->queue); - - return 0; -} - static int rt2400pci_tx_last_beacon(struct ieee80211_hw *hw) { struct rt2x00_dev *rt2x00dev = hw->priv; @@ -1574,7 +1573,6 @@ static const struct ieee80211_ops rt2400pci_mac80211_ops = { .conf_tx = rt2400pci_conf_tx, .get_tx_stats = rt2x00mac_get_tx_stats, .get_tsf = rt2400pci_get_tsf, - .beacon_update = rt2400pci_beacon_update, .tx_last_beacon = rt2400pci_tx_last_beacon, }; @@ -1592,6 +1590,7 @@ static const struct rt2x00lib_ops rt2400pci_rt2x00_ops = { .link_tuner = rt2400pci_link_tuner, .write_tx_desc = rt2400pci_write_tx_desc, .write_tx_data = rt2x00pci_write_tx_data, + .write_beacon = rt2400pci_write_beacon, .kick_tx_queue = rt2400pci_kick_tx_queue, .fill_rxdone = rt2400pci_fill_rxdone, .config_filter = rt2400pci_config_filter, @@ -1604,28 +1603,28 @@ static const struct data_queue_desc rt2400pci_queue_rx = { .entry_num = RX_ENTRIES, .data_size = DATA_FRAME_SIZE, .desc_size = RXD_DESC_SIZE, - .priv_size = sizeof(struct queue_entry_priv_pci_rx), + .priv_size = sizeof(struct queue_entry_priv_pci), }; static const struct data_queue_desc rt2400pci_queue_tx = { .entry_num = TX_ENTRIES, .data_size = DATA_FRAME_SIZE, .desc_size = TXD_DESC_SIZE, - .priv_size = sizeof(struct queue_entry_priv_pci_tx), + .priv_size = sizeof(struct queue_entry_priv_pci), }; static const struct data_queue_desc rt2400pci_queue_bcn = { .entry_num = BEACON_ENTRIES, .data_size = MGMT_FRAME_SIZE, .desc_size = TXD_DESC_SIZE, - .priv_size = sizeof(struct queue_entry_priv_pci_tx), + .priv_size = sizeof(struct queue_entry_priv_pci), }; static const struct data_queue_desc rt2400pci_queue_atim = { .entry_num = ATIM_ENTRIES, .data_size = DATA_FRAME_SIZE, .desc_size = TXD_DESC_SIZE, - .priv_size = sizeof(struct queue_entry_priv_pci_tx), + .priv_size = sizeof(struct queue_entry_priv_pci), }; static const struct rt2x00_ops rt2400pci_ops = { @@ -1634,6 +1633,7 @@ static const struct rt2x00_ops rt2400pci_ops = { .max_ap_intf = 1, .eeprom_size = EEPROM_SIZE, .rf_size = RF_SIZE, + .tx_queues = NUM_TX_QUEUES, .rx = &rt2400pci_queue_rx, .tx = &rt2400pci_queue_tx, .bcn = &rt2400pci_queue_bcn, diff --git a/drivers/net/wireless/rt2x00/rt2400pci.h b/drivers/net/wireless/rt2x00/rt2400pci.h index a5210f9a3360..bc5564258228 100644 --- a/drivers/net/wireless/rt2x00/rt2400pci.h +++ b/drivers/net/wireless/rt2x00/rt2400pci.h @@ -37,8 +37,6 @@ * Signal information. * Defaul offset is required for RSSI <-> dBm conversion. */ -#define MAX_SIGNAL 100 -#define MAX_RX_SSI -1 #define DEFAULT_RSSI_OFFSET 100 /* @@ -52,6 +50,11 @@ #define RF_SIZE 0x0010 /* + * Number of TX queues. + */ +#define NUM_TX_QUEUES 2 + +/* * Control/Status Registers(CSR). * Some values are set in TU, whereas 1 TU == 1024 us. */ diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c index f7731fb82555..aa6dfb811c71 100644 --- a/drivers/net/wireless/rt2x00/rt2500pci.c +++ b/drivers/net/wireless/rt2x00/rt2500pci.c @@ -277,6 +277,17 @@ static int rt2500pci_blink_set(struct led_classdev *led_cdev, return 0; } + +static void rt2500pci_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 = rt2500pci_brightness_set; + led->led_dev.blink_set = rt2500pci_blink_set; + led->flags = LED_INITIALIZED; +} #endif /* CONFIG_RT2500PCI_LEDS */ /* @@ -317,8 +328,7 @@ static void rt2500pci_config_intf(struct rt2x00_dev *rt2x00dev, struct rt2x00intf_conf *conf, const unsigned int flags) { - struct data_queue *queue = - rt2x00queue_get_queue(rt2x00dev, RT2X00_BCN_QUEUE_BEACON); + struct data_queue *queue = rt2x00queue_get_queue(rt2x00dev, QID_BEACON); unsigned int bcn_preload; u32 reg; @@ -716,38 +726,34 @@ dynamic_cca_tune: static void rt2500pci_init_rxentry(struct rt2x00_dev *rt2x00dev, struct queue_entry *entry) { - struct queue_entry_priv_pci_rx *priv_rx = entry->priv_data; + struct queue_entry_priv_pci *entry_priv = entry->priv_data; + struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb); u32 word; - rt2x00_desc_read(priv_rx->desc, 1, &word); - rt2x00_set_field32(&word, RXD_W1_BUFFER_ADDRESS, priv_rx->data_dma); - rt2x00_desc_write(priv_rx->desc, 1, word); + rt2x00_desc_read(entry_priv->desc, 1, &word); + rt2x00_set_field32(&word, RXD_W1_BUFFER_ADDRESS, skbdesc->skb_dma); + rt2x00_desc_write(entry_priv->desc, 1, word); - rt2x00_desc_read(priv_rx->desc, 0, &word); + rt2x00_desc_read(entry_priv->desc, 0, &word); rt2x00_set_field32(&word, RXD_W0_OWNER_NIC, 1); - rt2x00_desc_write(priv_rx->desc, 0, word); + rt2x00_desc_write(entry_priv->desc, 0, word); } static void rt2500pci_init_txentry(struct rt2x00_dev *rt2x00dev, struct queue_entry *entry) { - struct queue_entry_priv_pci_tx *priv_tx = entry->priv_data; + struct queue_entry_priv_pci *entry_priv = entry->priv_data; u32 word; - rt2x00_desc_read(priv_tx->desc, 1, &word); - rt2x00_set_field32(&word, TXD_W1_BUFFER_ADDRESS, priv_tx->data_dma); - rt2x00_desc_write(priv_tx->desc, 1, word); - - rt2x00_desc_read(priv_tx->desc, 0, &word); + rt2x00_desc_read(entry_priv->desc, 0, &word); rt2x00_set_field32(&word, TXD_W0_VALID, 0); rt2x00_set_field32(&word, TXD_W0_OWNER_NIC, 0); - rt2x00_desc_write(priv_tx->desc, 0, word); + rt2x00_desc_write(entry_priv->desc, 0, word); } static int rt2500pci_init_queues(struct rt2x00_dev *rt2x00dev) { - struct queue_entry_priv_pci_rx *priv_rx; - struct queue_entry_priv_pci_tx *priv_tx; + struct queue_entry_priv_pci *entry_priv; u32 reg; /* @@ -760,28 +766,28 @@ static int rt2500pci_init_queues(struct rt2x00_dev *rt2x00dev) rt2x00_set_field32(®, TXCSR2_NUM_PRIO, rt2x00dev->tx[0].limit); rt2x00pci_register_write(rt2x00dev, TXCSR2, reg); - priv_tx = rt2x00dev->tx[1].entries[0].priv_data; + entry_priv = rt2x00dev->tx[1].entries[0].priv_data; rt2x00pci_register_read(rt2x00dev, TXCSR3, ®); rt2x00_set_field32(®, TXCSR3_TX_RING_REGISTER, - priv_tx->desc_dma); + entry_priv->desc_dma); rt2x00pci_register_write(rt2x00dev, TXCSR3, reg); - priv_tx = rt2x00dev->tx[0].entries[0].priv_data; + entry_priv = rt2x00dev->tx[0].entries[0].priv_data; rt2x00pci_register_read(rt2x00dev, TXCSR5, ®); rt2x00_set_field32(®, TXCSR5_PRIO_RING_REGISTER, - priv_tx->desc_dma); + entry_priv->desc_dma); rt2x00pci_register_write(rt2x00dev, TXCSR5, reg); - priv_tx = rt2x00dev->bcn[1].entries[0].priv_data; + entry_priv = rt2x00dev->bcn[1].entries[0].priv_data; rt2x00pci_register_read(rt2x00dev, TXCSR4, ®); rt2x00_set_field32(®, TXCSR4_ATIM_RING_REGISTER, - priv_tx->desc_dma); + entry_priv->desc_dma); rt2x00pci_register_write(rt2x00dev, TXCSR4, reg); - priv_tx = rt2x00dev->bcn[0].entries[0].priv_data; + entry_priv = rt2x00dev->bcn[0].entries[0].priv_data; rt2x00pci_register_read(rt2x00dev, TXCSR6, ®); rt2x00_set_field32(®, TXCSR6_BEACON_RING_REGISTER, - priv_tx->desc_dma); + entry_priv->desc_dma); rt2x00pci_register_write(rt2x00dev, TXCSR6, reg); rt2x00pci_register_read(rt2x00dev, RXCSR1, ®); @@ -789,9 +795,10 @@ static int rt2500pci_init_queues(struct rt2x00_dev *rt2x00dev) rt2x00_set_field32(®, RXCSR1_NUM_RXD, rt2x00dev->rx->limit); rt2x00pci_register_write(rt2x00dev, RXCSR1, reg); - priv_rx = rt2x00dev->rx->entries[0].priv_data; + entry_priv = rt2x00dev->rx->entries[0].priv_data; rt2x00pci_register_read(rt2x00dev, RXCSR2, ®); - rt2x00_set_field32(®, RXCSR2_RX_RING_REGISTER, priv_rx->desc_dma); + rt2x00_set_field32(®, RXCSR2_RX_RING_REGISTER, + entry_priv->desc_dma); rt2x00pci_register_write(rt2x00dev, RXCSR2, reg); return 0; @@ -940,25 +947,32 @@ static int rt2500pci_init_registers(struct rt2x00_dev *rt2x00dev) return 0; } -static int rt2500pci_init_bbp(struct rt2x00_dev *rt2x00dev) +static int rt2500pci_wait_bbp_ready(struct rt2x00_dev *rt2x00dev) { unsigned int i; - u16 eeprom; - u8 reg_id; u8 value; for (i = 0; i < REGISTER_BUSY_COUNT; i++) { rt2500pci_bbp_read(rt2x00dev, 0, &value); if ((value != 0xff) && (value != 0x00)) - goto continue_csr_init; - NOTICE(rt2x00dev, "Waiting for BBP register.\n"); + return 0; udelay(REGISTER_BUSY_DELAY); } ERROR(rt2x00dev, "BBP register access failed, aborting.\n"); return -EACCES; +} + +static int rt2500pci_init_bbp(struct rt2x00_dev *rt2x00dev) +{ + unsigned int i; + u16 eeprom; + u8 reg_id; + u8 value; + + if (unlikely(rt2500pci_wait_bbp_ready(rt2x00dev))) + return -EACCES; -continue_csr_init: rt2500pci_bbp_write(rt2x00dev, 3, 0x02); rt2500pci_bbp_write(rt2x00dev, 4, 0x19); rt2500pci_bbp_write(rt2x00dev, 14, 0x1c); @@ -1013,7 +1027,8 @@ static void rt2500pci_toggle_rx(struct rt2x00_dev *rt2x00dev, rt2x00pci_register_read(rt2x00dev, RXCSR0, ®); rt2x00_set_field32(®, RXCSR0_DISABLE_RX, - state == STATE_RADIO_RX_OFF); + (state == STATE_RADIO_RX_OFF) || + (state == STATE_RADIO_RX_OFF_LINK)); rt2x00pci_register_write(rt2x00dev, RXCSR0, reg); } @@ -1050,17 +1065,10 @@ static int rt2500pci_enable_radio(struct rt2x00_dev *rt2x00dev) /* * Initialize all registers. */ - if (rt2500pci_init_queues(rt2x00dev) || - rt2500pci_init_registers(rt2x00dev) || - rt2500pci_init_bbp(rt2x00dev)) { - ERROR(rt2x00dev, "Register initialization failed.\n"); + if (unlikely(rt2500pci_init_queues(rt2x00dev) || + rt2500pci_init_registers(rt2x00dev) || + rt2500pci_init_bbp(rt2x00dev))) return -EIO; - } - - /* - * Enable interrupts. - */ - rt2500pci_toggle_irq(rt2x00dev, STATE_RADIO_IRQ_ON); return 0; } @@ -1082,11 +1090,6 @@ static void rt2500pci_disable_radio(struct rt2x00_dev *rt2x00dev) rt2x00pci_register_read(rt2x00dev, TXCSR0, ®); rt2x00_set_field32(®, TXCSR0_ABORT, 1); rt2x00pci_register_write(rt2x00dev, TXCSR0, reg); - - /* - * Disable interrupts. - */ - rt2500pci_toggle_irq(rt2x00dev, STATE_RADIO_IRQ_OFF); } static int rt2500pci_set_state(struct rt2x00_dev *rt2x00dev, @@ -1121,10 +1124,6 @@ static int rt2500pci_set_state(struct rt2x00_dev *rt2x00dev, msleep(10); } - NOTICE(rt2x00dev, "Device failed to enter state %d, " - "current device state: bbp %d and rf %d.\n", - state, bbp_state, rf_state); - return -EBUSY; } @@ -1142,11 +1141,13 @@ static int rt2500pci_set_device_state(struct rt2x00_dev *rt2x00dev, break; case STATE_RADIO_RX_ON: case STATE_RADIO_RX_ON_LINK: - rt2500pci_toggle_rx(rt2x00dev, STATE_RADIO_RX_ON); - break; case STATE_RADIO_RX_OFF: case STATE_RADIO_RX_OFF_LINK: - rt2500pci_toggle_rx(rt2x00dev, STATE_RADIO_RX_OFF); + rt2500pci_toggle_rx(rt2x00dev, state); + break; + case STATE_RADIO_IRQ_ON: + case STATE_RADIO_IRQ_OFF: + rt2500pci_toggle_irq(rt2x00dev, state); break; case STATE_DEEP_SLEEP: case STATE_SLEEP: @@ -1159,6 +1160,10 @@ static int rt2500pci_set_device_state(struct rt2x00_dev *rt2x00dev, break; } + if (unlikely(retval)) + ERROR(rt2x00dev, "Device failed to enter state %d (%d).\n", + state, retval); + return retval; } @@ -1167,16 +1172,20 @@ static int rt2500pci_set_device_state(struct rt2x00_dev *rt2x00dev, */ static void rt2500pci_write_tx_desc(struct rt2x00_dev *rt2x00dev, struct sk_buff *skb, - struct txentry_desc *txdesc, - struct ieee80211_tx_control *control) + struct txentry_desc *txdesc) { struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb); + struct queue_entry_priv_pci *entry_priv = skbdesc->entry->priv_data; __le32 *txd = skbdesc->desc; u32 word; /* * Start writing the descriptor words. */ + rt2x00_desc_read(entry_priv->desc, 1, &word); + rt2x00_set_field32(&word, TXD_W1_BUFFER_ADDRESS, skbdesc->skb_dma); + rt2x00_desc_write(entry_priv->desc, 1, word); + rt2x00_desc_read(txd, 2, &word); rt2x00_set_field32(&word, TXD_W2_IV_OFFSET, IEEE80211_HEADER); rt2x00_set_field32(&word, TXD_W2_AIFS, txdesc->aifs); @@ -1210,9 +1219,7 @@ static void rt2500pci_write_tx_desc(struct rt2x00_dev *rt2x00dev, rt2x00_set_field32(&word, TXD_W0_CIPHER_OWNER, 1); rt2x00_set_field32(&word, TXD_W0_IFS, txdesc->ifs); rt2x00_set_field32(&word, TXD_W0_RETRY_MODE, - !!(control->flags & - IEEE80211_TXCTL_LONG_RETRY_LIMIT)); - rt2x00_set_field32(&word, TXD_W0_DATABYTE_COUNT, skbdesc->data_len); + test_bit(ENTRY_TXD_RETRY_MODE, &txdesc->flags)); rt2x00_set_field32(&word, TXD_W0_CIPHER_ALG, CIPHER_NONE); rt2x00_desc_write(txd, 0, word); } @@ -1220,12 +1227,46 @@ static void rt2500pci_write_tx_desc(struct rt2x00_dev *rt2x00dev, /* * TX data initialization */ +static void rt2500pci_write_beacon(struct queue_entry *entry) +{ + struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev; + struct queue_entry_priv_pci *entry_priv = entry->priv_data; + struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb); + u32 word; + u32 reg; + + /* + * Disable beaconing while we are reloading the beacon data, + * otherwise we might be sending out invalid data. + */ + rt2x00pci_register_read(rt2x00dev, CSR14, ®); + rt2x00_set_field32(®, CSR14_TSF_COUNT, 0); + rt2x00_set_field32(®, CSR14_TBCN, 0); + rt2x00_set_field32(®, CSR14_BEACON_GEN, 0); + rt2x00pci_register_write(rt2x00dev, CSR14, reg); + + /* + * Replace rt2x00lib allocated descriptor with the + * pointer to the _real_ hardware descriptor. + * After that, map the beacon to DMA and update the + * descriptor. + */ + memcpy(entry_priv->desc, skbdesc->desc, skbdesc->desc_len); + skbdesc->desc = entry_priv->desc; + + rt2x00queue_map_txskb(rt2x00dev, entry->skb); + + rt2x00_desc_read(entry_priv->desc, 1, &word); + rt2x00_set_field32(&word, TXD_W1_BUFFER_ADDRESS, skbdesc->skb_dma); + rt2x00_desc_write(entry_priv->desc, 1, word); +} + static void rt2500pci_kick_tx_queue(struct rt2x00_dev *rt2x00dev, - const unsigned int queue) + const enum data_queue_qid queue) { u32 reg; - if (queue == RT2X00_BCN_QUEUE_BEACON) { + if (queue == QID_BEACON) { rt2x00pci_register_read(rt2x00dev, CSR14, ®); if (!rt2x00_get_field32(reg, CSR14_BEACON_GEN)) { rt2x00_set_field32(®, CSR14_TSF_COUNT, 1); @@ -1237,12 +1278,9 @@ static void rt2500pci_kick_tx_queue(struct rt2x00_dev *rt2x00dev, } rt2x00pci_register_read(rt2x00dev, TXCSR0, ®); - rt2x00_set_field32(®, TXCSR0_KICK_PRIO, - (queue == IEEE80211_TX_QUEUE_DATA0)); - rt2x00_set_field32(®, TXCSR0_KICK_TX, - (queue == IEEE80211_TX_QUEUE_DATA1)); - rt2x00_set_field32(®, TXCSR0_KICK_ATIM, - (queue == RT2X00_BCN_QUEUE_ATIM)); + rt2x00_set_field32(®, TXCSR0_KICK_PRIO, (queue == QID_AC_BE)); + rt2x00_set_field32(®, TXCSR0_KICK_TX, (queue == QID_AC_BK)); + rt2x00_set_field32(®, TXCSR0_KICK_ATIM, (queue == QID_ATIM)); rt2x00pci_register_write(rt2x00dev, TXCSR0, reg); } @@ -1252,14 +1290,13 @@ static void rt2500pci_kick_tx_queue(struct rt2x00_dev *rt2x00dev, static void rt2500pci_fill_rxdone(struct queue_entry *entry, struct rxdone_entry_desc *rxdesc) { - struct queue_entry_priv_pci_rx *priv_rx = entry->priv_data; + struct queue_entry_priv_pci *entry_priv = entry->priv_data; u32 word0; u32 word2; - rt2x00_desc_read(priv_rx->desc, 0, &word0); - rt2x00_desc_read(priv_rx->desc, 2, &word2); + rt2x00_desc_read(entry_priv->desc, 0, &word0); + rt2x00_desc_read(entry_priv->desc, 2, &word2); - rxdesc->flags = 0; if (rt2x00_get_field32(word0, RXD_W0_CRC_ERROR)) rxdesc->flags |= RX_FLAG_FAILED_FCS_CRC; if (rt2x00_get_field32(word0, RXD_W0_PHYSICAL_ERROR)) @@ -1276,7 +1313,6 @@ static void rt2500pci_fill_rxdone(struct queue_entry *entry, entry->queue->rt2x00dev->rssi_offset; rxdesc->size = rt2x00_get_field32(word0, RXD_W0_DATABYTE_COUNT); - rxdesc->dev_flags = 0; if (rt2x00_get_field32(word0, RXD_W0_OFDM)) rxdesc->dev_flags |= RXDONE_SIGNAL_PLCP; if (rt2x00_get_field32(word0, RXD_W0_MY_BSS)) @@ -1287,18 +1323,18 @@ static void rt2500pci_fill_rxdone(struct queue_entry *entry, * Interrupt functions. */ static void rt2500pci_txdone(struct rt2x00_dev *rt2x00dev, - const enum ieee80211_tx_queue queue_idx) + const enum data_queue_qid queue_idx) { struct data_queue *queue = rt2x00queue_get_queue(rt2x00dev, queue_idx); - struct queue_entry_priv_pci_tx *priv_tx; + struct queue_entry_priv_pci *entry_priv; struct queue_entry *entry; struct txdone_entry_desc txdesc; u32 word; while (!rt2x00queue_empty(queue)) { entry = rt2x00queue_get_entry(queue, Q_INDEX_DONE); - priv_tx = entry->priv_data; - rt2x00_desc_read(priv_tx->desc, 0, &word); + entry_priv = entry->priv_data; + rt2x00_desc_read(entry_priv->desc, 0, &word); if (rt2x00_get_field32(word, TXD_W0_OWNER_NIC) || !rt2x00_get_field32(word, TXD_W0_VALID)) @@ -1307,10 +1343,21 @@ static void rt2500pci_txdone(struct rt2x00_dev *rt2x00dev, /* * Obtain the status about this packet. */ - txdesc.status = rt2x00_get_field32(word, TXD_W0_RESULT); + txdesc.flags = 0; + switch (rt2x00_get_field32(word, TXD_W0_RESULT)) { + case 0: /* Success */ + case 1: /* Success with retry */ + __set_bit(TXDONE_SUCCESS, &txdesc.flags); + break; + case 2: /* Failure, excessive retries */ + __set_bit(TXDONE_EXCESSIVE_RETRY, &txdesc.flags); + /* Don't break, this is a failed frame! */ + default: /* Failure */ + __set_bit(TXDONE_FAILURE, &txdesc.flags); + } txdesc.retry = rt2x00_get_field32(word, TXD_W0_RETRY_COUNT); - rt2x00pci_txdone(rt2x00dev, entry, &txdesc); + rt2x00lib_txdone(entry, &txdesc); } } @@ -1354,19 +1401,19 @@ static irqreturn_t rt2500pci_interrupt(int irq, void *dev_instance) * 3 - Atim ring transmit done interrupt. */ if (rt2x00_get_field32(reg, CSR7_TXDONE_ATIMRING)) - rt2500pci_txdone(rt2x00dev, RT2X00_BCN_QUEUE_ATIM); + rt2500pci_txdone(rt2x00dev, QID_ATIM); /* * 4 - Priority ring transmit done interrupt. */ if (rt2x00_get_field32(reg, CSR7_TXDONE_PRIORING)) - rt2500pci_txdone(rt2x00dev, IEEE80211_TX_QUEUE_DATA0); + rt2500pci_txdone(rt2x00dev, QID_AC_BE); /* * 5 - Tx ring transmit done interrupt. */ if (rt2x00_get_field32(reg, CSR7_TXDONE_TXRING)) - rt2500pci_txdone(rt2x00dev, IEEE80211_TX_QUEUE_DATA1); + rt2500pci_txdone(rt2x00dev, QID_AC_BK); return IRQ_HANDLED; } @@ -1486,23 +1533,10 @@ static int rt2500pci_init_eeprom(struct rt2x00_dev *rt2x00dev) #ifdef CONFIG_RT2500PCI_LEDS value = rt2x00_get_field16(eeprom, EEPROM_ANTENNA_LED_MODE); - rt2x00dev->led_radio.rt2x00dev = rt2x00dev; - rt2x00dev->led_radio.type = LED_TYPE_RADIO; - rt2x00dev->led_radio.led_dev.brightness_set = - rt2500pci_brightness_set; - rt2x00dev->led_radio.led_dev.blink_set = - rt2500pci_blink_set; - rt2x00dev->led_radio.flags = LED_INITIALIZED; - - if (value == LED_MODE_TXRX_ACTIVITY) { - rt2x00dev->led_qual.rt2x00dev = rt2x00dev; - rt2x00dev->led_qual.type = LED_TYPE_ACTIVITY; - rt2x00dev->led_qual.led_dev.brightness_set = - rt2500pci_brightness_set; - rt2x00dev->led_qual.led_dev.blink_set = - rt2500pci_blink_set; - rt2x00dev->led_qual.flags = LED_INITIALIZED; - } + rt2500pci_init_led(rt2x00dev, &rt2x00dev->led_radio, LED_TYPE_RADIO); + if (value == LED_MODE_TXRX_ACTIVITY) + rt2500pci_init_led(rt2x00dev, &rt2x00dev->led_qual, + LED_TYPE_ACTIVITY); #endif /* CONFIG_RT2500PCI_LEDS */ /* @@ -1695,13 +1729,12 @@ static void rt2500pci_probe_hw_mode(struct rt2x00_dev *rt2x00dev) /* * Initialize all hw fields. */ - rt2x00dev->hw->flags = IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING; + rt2x00dev->hw->flags = IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | + IEEE80211_HW_SIGNAL_DBM; + rt2x00dev->hw->extra_tx_headroom = 0; - rt2x00dev->hw->max_signal = MAX_SIGNAL; - rt2x00dev->hw->max_rssi = MAX_RX_SSI; - rt2x00dev->hw->queues = 2; - SET_IEEE80211_DEV(rt2x00dev->hw, &rt2x00dev_pci(rt2x00dev)->dev); + SET_IEEE80211_DEV(rt2x00dev->hw, rt2x00dev->dev); SET_IEEE80211_PERM_ADDR(rt2x00dev->hw, rt2x00_eeprom_addr(rt2x00dev, EEPROM_MAC_ADDR_0)); @@ -1765,9 +1798,10 @@ static int rt2500pci_probe_hw(struct rt2x00_dev *rt2x00dev) rt2500pci_probe_hw_mode(rt2x00dev); /* - * This device requires the atim queue + * This device requires the atim queue and DMA-mapped skbs. */ __set_bit(DRIVER_REQUIRE_ATIM_QUEUE, &rt2x00dev->flags); + __set_bit(DRIVER_REQUIRE_DMA, &rt2x00dev->flags); /* * Set the rssi offset. @@ -1808,61 +1842,6 @@ static u64 rt2500pci_get_tsf(struct ieee80211_hw *hw) return tsf; } -static int rt2500pci_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb, - struct ieee80211_tx_control *control) -{ - struct rt2x00_dev *rt2x00dev = hw->priv; - struct rt2x00_intf *intf = vif_to_intf(control->vif); - struct queue_entry_priv_pci_tx *priv_tx; - struct skb_frame_desc *skbdesc; - u32 reg; - - if (unlikely(!intf->beacon)) - return -ENOBUFS; - - priv_tx = intf->beacon->priv_data; - - /* - * Fill in skb descriptor - */ - skbdesc = get_skb_frame_desc(skb); - memset(skbdesc, 0, sizeof(*skbdesc)); - skbdesc->flags |= FRAME_DESC_DRIVER_GENERATED; - skbdesc->data = skb->data; - skbdesc->data_len = skb->len; - skbdesc->desc = priv_tx->desc; - skbdesc->desc_len = intf->beacon->queue->desc_size; - skbdesc->entry = intf->beacon; - - /* - * Disable beaconing while we are reloading the beacon data, - * otherwise we might be sending out invalid data. - */ - rt2x00pci_register_read(rt2x00dev, CSR14, ®); - rt2x00_set_field32(®, CSR14_TSF_COUNT, 0); - rt2x00_set_field32(®, CSR14_TBCN, 0); - rt2x00_set_field32(®, CSR14_BEACON_GEN, 0); - rt2x00pci_register_write(rt2x00dev, CSR14, reg); - - /* - * mac80211 doesn't provide the control->queue variable - * for beacons. Set our own queue identification so - * it can be used during descriptor initialization. - */ - control->queue = RT2X00_BCN_QUEUE_BEACON; - rt2x00lib_write_tx_desc(rt2x00dev, skb, control); - - /* - * Enable beacon generation. - * Write entire beacon with descriptor to register, - * and kick the beacon generator. - */ - memcpy(priv_tx->data, skb->data, skb->len); - rt2x00dev->ops->lib->kick_tx_queue(rt2x00dev, control->queue); - - return 0; -} - static int rt2500pci_tx_last_beacon(struct ieee80211_hw *hw) { struct rt2x00_dev *rt2x00dev = hw->priv; @@ -1887,7 +1866,6 @@ static const struct ieee80211_ops rt2500pci_mac80211_ops = { .conf_tx = rt2x00mac_conf_tx, .get_tx_stats = rt2x00mac_get_tx_stats, .get_tsf = rt2500pci_get_tsf, - .beacon_update = rt2500pci_beacon_update, .tx_last_beacon = rt2500pci_tx_last_beacon, }; @@ -1905,6 +1883,7 @@ static const struct rt2x00lib_ops rt2500pci_rt2x00_ops = { .link_tuner = rt2500pci_link_tuner, .write_tx_desc = rt2500pci_write_tx_desc, .write_tx_data = rt2x00pci_write_tx_data, + .write_beacon = rt2500pci_write_beacon, .kick_tx_queue = rt2500pci_kick_tx_queue, .fill_rxdone = rt2500pci_fill_rxdone, .config_filter = rt2500pci_config_filter, @@ -1917,28 +1896,28 @@ static const struct data_queue_desc rt2500pci_queue_rx = { .entry_num = RX_ENTRIES, .data_size = DATA_FRAME_SIZE, .desc_size = RXD_DESC_SIZE, - .priv_size = sizeof(struct queue_entry_priv_pci_rx), + .priv_size = sizeof(struct queue_entry_priv_pci), }; static const struct data_queue_desc rt2500pci_queue_tx = { .entry_num = TX_ENTRIES, .data_size = DATA_FRAME_SIZE, .desc_size = TXD_DESC_SIZE, - .priv_size = sizeof(struct queue_entry_priv_pci_tx), + .priv_size = sizeof(struct queue_entry_priv_pci), }; static const struct data_queue_desc rt2500pci_queue_bcn = { .entry_num = BEACON_ENTRIES, .data_size = MGMT_FRAME_SIZE, .desc_size = TXD_DESC_SIZE, - .priv_size = sizeof(struct queue_entry_priv_pci_tx), + .priv_size = sizeof(struct queue_entry_priv_pci), }; static const struct data_queue_desc rt2500pci_queue_atim = { .entry_num = ATIM_ENTRIES, .data_size = DATA_FRAME_SIZE, .desc_size = TXD_DESC_SIZE, - .priv_size = sizeof(struct queue_entry_priv_pci_tx), + .priv_size = sizeof(struct queue_entry_priv_pci), }; static const struct rt2x00_ops rt2500pci_ops = { @@ -1947,6 +1926,7 @@ static const struct rt2x00_ops rt2500pci_ops = { .max_ap_intf = 1, .eeprom_size = EEPROM_SIZE, .rf_size = RF_SIZE, + .tx_queues = NUM_TX_QUEUES, .rx = &rt2500pci_queue_rx, .tx = &rt2500pci_queue_tx, .bcn = &rt2500pci_queue_bcn, diff --git a/drivers/net/wireless/rt2x00/rt2500pci.h b/drivers/net/wireless/rt2x00/rt2500pci.h index 13899550465a..42f376929ea9 100644 --- a/drivers/net/wireless/rt2x00/rt2500pci.h +++ b/drivers/net/wireless/rt2x00/rt2500pci.h @@ -48,8 +48,6 @@ * Signal information. * Defaul offset is required for RSSI <-> dBm conversion. */ -#define MAX_SIGNAL 100 -#define MAX_RX_SSI -1 #define DEFAULT_RSSI_OFFSET 121 /* @@ -63,6 +61,11 @@ #define RF_SIZE 0x0014 /* + * Number of TX queues. + */ +#define NUM_TX_QUEUES 2 + +/* * Control/Status Registers(CSR). * Some values are set in TU, whereas 1 TU == 1024 us. */ @@ -748,7 +751,7 @@ #define LEDCSR_LED_DEFAULT FIELD32(0x00100000) /* - * AES control register. + * SECCSR3: AES control register. */ #define SECCSR3 0x00fc @@ -892,7 +895,7 @@ #define ARTCSR2_ACK_CTS_54MBS FIELD32(0xff000000) /* - * SECCSR1_RT2509: WEP control register. + * SECCSR1: WEP control register. * KICK_ENCRYPT: Kick encryption engine, self-clear. * ONE_SHOT: 0: ring mode, 1: One shot only mode. * DESC_ADDRESS: Descriptor physical address of frame. diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c index d90512f97b39..3558cb210747 100644 --- a/drivers/net/wireless/rt2x00/rt2500usb.c +++ b/drivers/net/wireless/rt2x00/rt2500usb.c @@ -76,10 +76,10 @@ static inline void rt2500usb_register_multiread(struct rt2x00_dev *rt2x00dev, const unsigned int offset, void *value, const u16 length) { - int timeout = REGISTER_TIMEOUT * (length / sizeof(u16)); rt2x00usb_vendor_request_buff(rt2x00dev, USB_MULTI_READ, USB_VENDOR_REQUEST_IN, offset, - value, length, timeout); + value, length, + REGISTER_TIMEOUT16(length)); } static inline void rt2500usb_register_write(struct rt2x00_dev *rt2x00dev, @@ -106,10 +106,10 @@ static inline void rt2500usb_register_multiwrite(struct rt2x00_dev *rt2x00dev, const unsigned int offset, void *value, const u16 length) { - int timeout = REGISTER_TIMEOUT * (length / sizeof(u16)); rt2x00usb_vendor_request_buff(rt2x00dev, USB_MULTI_WRITE, USB_VENDOR_REQUEST_OUT, offset, - value, length, timeout); + value, length, + REGISTER_TIMEOUT16(length)); } static u16 rt2500usb_bbp_check(struct rt2x00_dev *rt2x00dev) @@ -322,6 +322,17 @@ static int rt2500usb_blink_set(struct led_classdev *led_cdev, return 0; } + +static void rt2500usb_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 = rt2500usb_brightness_set; + led->led_dev.blink_set = rt2500usb_blink_set; + led->flags = LED_INITIALIZED; +} #endif /* CONFIG_RT2500USB_LEDS */ /* @@ -860,25 +871,32 @@ static int rt2500usb_init_registers(struct rt2x00_dev *rt2x00dev) return 0; } -static int rt2500usb_init_bbp(struct rt2x00_dev *rt2x00dev) +static int rt2500usb_wait_bbp_ready(struct rt2x00_dev *rt2x00dev) { unsigned int i; - u16 eeprom; u8 value; - u8 reg_id; for (i = 0; i < REGISTER_BUSY_COUNT; i++) { rt2500usb_bbp_read(rt2x00dev, 0, &value); if ((value != 0xff) && (value != 0x00)) - goto continue_csr_init; - NOTICE(rt2x00dev, "Waiting for BBP register.\n"); + return 0; udelay(REGISTER_BUSY_DELAY); } ERROR(rt2x00dev, "BBP register access failed, aborting.\n"); return -EACCES; +} + +static int rt2500usb_init_bbp(struct rt2x00_dev *rt2x00dev) +{ + unsigned int i; + u16 eeprom; + u8 value; + u8 reg_id; + + if (unlikely(rt2500usb_wait_bbp_ready(rt2x00dev))) + return -EACCES; -continue_csr_init: rt2500usb_bbp_write(rt2x00dev, 3, 0x02); rt2500usb_bbp_write(rt2x00dev, 4, 0x19); rt2500usb_bbp_write(rt2x00dev, 14, 0x1c); @@ -934,7 +952,8 @@ static void rt2500usb_toggle_rx(struct rt2x00_dev *rt2x00dev, rt2500usb_register_read(rt2x00dev, TXRX_CSR2, ®); rt2x00_set_field16(®, TXRX_CSR2_DISABLE_RX, - state == STATE_RADIO_RX_OFF); + (state == STATE_RADIO_RX_OFF) || + (state == STATE_RADIO_RX_OFF_LINK)); rt2500usb_register_write(rt2x00dev, TXRX_CSR2, reg); } @@ -943,11 +962,9 @@ static int rt2500usb_enable_radio(struct rt2x00_dev *rt2x00dev) /* * Initialize all registers. */ - if (rt2500usb_init_registers(rt2x00dev) || - rt2500usb_init_bbp(rt2x00dev)) { - ERROR(rt2x00dev, "Register initialization failed.\n"); + if (unlikely(rt2500usb_init_registers(rt2x00dev) || + rt2500usb_init_bbp(rt2x00dev))) return -EIO; - } return 0; } @@ -1000,10 +1017,6 @@ static int rt2500usb_set_state(struct rt2x00_dev *rt2x00dev, msleep(30); } - NOTICE(rt2x00dev, "Device failed to enter state %d, " - "current device state: bbp %d and rf %d.\n", - state, bbp_state, rf_state); - return -EBUSY; } @@ -1021,11 +1034,13 @@ static int rt2500usb_set_device_state(struct rt2x00_dev *rt2x00dev, break; case STATE_RADIO_RX_ON: case STATE_RADIO_RX_ON_LINK: - rt2500usb_toggle_rx(rt2x00dev, STATE_RADIO_RX_ON); - break; case STATE_RADIO_RX_OFF: case STATE_RADIO_RX_OFF_LINK: - rt2500usb_toggle_rx(rt2x00dev, STATE_RADIO_RX_OFF); + rt2500usb_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: @@ -1038,6 +1053,10 @@ static int rt2500usb_set_device_state(struct rt2x00_dev *rt2x00dev, break; } + if (unlikely(retval)) + ERROR(rt2x00dev, "Device failed to enter state %d (%d).\n", + state, retval); + return retval; } @@ -1046,8 +1065,7 @@ static int rt2500usb_set_device_state(struct rt2x00_dev *rt2x00dev, */ static void rt2500usb_write_tx_desc(struct rt2x00_dev *rt2x00dev, struct sk_buff *skb, - struct txentry_desc *txdesc, - struct ieee80211_tx_control *control) + struct txentry_desc *txdesc) { struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb); __le32 *txd = skbdesc->desc; @@ -1071,7 +1089,7 @@ static void rt2500usb_write_tx_desc(struct rt2x00_dev *rt2x00dev, rt2x00_desc_write(txd, 2, word); rt2x00_desc_read(txd, 0, &word); - rt2x00_set_field32(&word, TXD_W0_RETRY_LIMIT, control->retry_limit); + rt2x00_set_field32(&word, TXD_W0_RETRY_LIMIT, txdesc->retry_limit); rt2x00_set_field32(&word, TXD_W0_MORE_FRAG, test_bit(ENTRY_TXD_MORE_FRAG, &txdesc->flags)); rt2x00_set_field32(&word, TXD_W0_ACK, @@ -1081,13 +1099,73 @@ static void rt2500usb_write_tx_desc(struct rt2x00_dev *rt2x00dev, rt2x00_set_field32(&word, TXD_W0_OFDM, test_bit(ENTRY_TXD_OFDM_RATE, &txdesc->flags)); rt2x00_set_field32(&word, TXD_W0_NEW_SEQ, - !!(control->flags & IEEE80211_TXCTL_FIRST_FRAGMENT)); + test_bit(ENTRY_TXD_FIRST_FRAGMENT, &txdesc->flags)); rt2x00_set_field32(&word, TXD_W0_IFS, txdesc->ifs); - rt2x00_set_field32(&word, TXD_W0_DATABYTE_COUNT, skbdesc->data_len); + rt2x00_set_field32(&word, TXD_W0_DATABYTE_COUNT, + skb->len - skbdesc->desc_len); rt2x00_set_field32(&word, TXD_W0_CIPHER, CIPHER_NONE); rt2x00_desc_write(txd, 0, word); } +/* + * TX data initialization + */ +static void rt2500usb_beacondone(struct urb *urb); + +static void rt2500usb_write_beacon(struct queue_entry *entry) +{ + struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev; + struct usb_device *usb_dev = to_usb_device_intf(rt2x00dev->dev); + struct queue_entry_priv_usb_bcn *bcn_priv = entry->priv_data; + struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb); + int pipe = usb_sndbulkpipe(usb_dev, 1); + int length; + u16 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. + */ + rt2500usb_register_read(rt2x00dev, TXRX_CSR19, ®); + rt2x00_set_field16(®, TXRX_CSR19_TSF_COUNT, 0); + rt2x00_set_field16(®, TXRX_CSR19_TBCN, 0); + rt2x00_set_field16(®, TXRX_CSR19_BEACON_GEN, 0); + rt2500usb_register_write(rt2x00dev, TXRX_CSR19, reg); + + /* + * USB devices cannot blindly pass the skb->len as the + * length of the data to usb_fill_bulk_urb. Pass the skb + * to the driver to determine what the length should be. + */ + length = rt2x00dev->ops->lib->get_tx_data_len(rt2x00dev, entry->skb); + + usb_fill_bulk_urb(bcn_priv->urb, usb_dev, pipe, + entry->skb->data, length, rt2500usb_beacondone, + entry); + + /* + * Second we need to create the guardian byte. + * We only need a single byte, so lets recycle + * the 'flags' field we are not using for beacons. + */ + bcn_priv->guardian_data = 0; + usb_fill_bulk_urb(bcn_priv->guardian_urb, usb_dev, pipe, + &bcn_priv->guardian_data, 1, rt2500usb_beacondone, + entry); + + /* + * Send out the guardian byte. + */ + usb_submit_urb(bcn_priv->guardian_urb, GFP_ATOMIC); +} + static int rt2500usb_get_tx_data_len(struct rt2x00_dev *rt2x00dev, struct sk_buff *skb) { @@ -1103,16 +1181,15 @@ static int rt2500usb_get_tx_data_len(struct rt2x00_dev *rt2x00dev, return length; } -/* - * TX data initialization - */ static void rt2500usb_kick_tx_queue(struct rt2x00_dev *rt2x00dev, - const unsigned int queue) + const enum data_queue_qid queue) { u16 reg; - if (queue != RT2X00_BCN_QUEUE_BEACON) + if (queue != QID_BEACON) { + rt2x00usb_kick_tx_queue(rt2x00dev, queue); return; + } rt2500usb_register_read(rt2x00dev, TXRX_CSR19, ®); if (!rt2x00_get_field16(reg, TXRX_CSR19_BEACON_GEN)) { @@ -1138,30 +1215,28 @@ static void rt2500usb_kick_tx_queue(struct rt2x00_dev *rt2x00dev, static void rt2500usb_fill_rxdone(struct queue_entry *entry, struct rxdone_entry_desc *rxdesc) { - struct queue_entry_priv_usb_rx *priv_rx = entry->priv_data; + struct queue_entry_priv_usb *entry_priv = entry->priv_data; struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb); __le32 *rxd = (__le32 *)(entry->skb->data + - (priv_rx->urb->actual_length - entry->queue->desc_size)); - unsigned int offset = entry->queue->desc_size + 2; + (entry_priv->urb->actual_length - + entry->queue->desc_size)); u32 word0; u32 word1; /* - * Copy descriptor to the available headroom inside the skbuffer. + * Copy descriptor to the skbdesc->desc buffer, making it safe from moving of + * frame data in rt2x00usb. */ - skb_push(entry->skb, offset); - memcpy(entry->skb->data, rxd, entry->queue->desc_size); - rxd = (__le32 *)entry->skb->data; + memcpy(skbdesc->desc, rxd, skbdesc->desc_len); + rxd = (__le32 *)skbdesc->desc; /* - * The descriptor is now aligned to 4 bytes and thus it is - * now safe to read it on all architectures. + * It is now safe to read the descriptor on all architectures. */ rt2x00_desc_read(rxd, 0, &word0); rt2x00_desc_read(rxd, 1, &word1); - rxdesc->flags = 0; if (rt2x00_get_field32(word0, RXD_W0_CRC_ERROR)) rxdesc->flags |= RX_FLAG_FAILED_FCS_CRC; if (rt2x00_get_field32(word0, RXD_W0_PHYSICAL_ERROR)) @@ -1178,7 +1253,6 @@ static void rt2500usb_fill_rxdone(struct queue_entry *entry, entry->queue->rt2x00dev->rssi_offset; rxdesc->size = rt2x00_get_field32(word0, RXD_W0_DATABYTE_COUNT); - rxdesc->dev_flags = 0; if (rt2x00_get_field32(word0, RXD_W0_OFDM)) rxdesc->dev_flags |= RXDONE_SIGNAL_PLCP; if (rt2x00_get_field32(word0, RXD_W0_MY_BSS)) @@ -1187,16 +1261,7 @@ static void rt2500usb_fill_rxdone(struct queue_entry *entry, /* * Adjust the skb memory window to the frame boundaries. */ - skb_pull(entry->skb, offset); skb_trim(entry->skb, rxdesc->size); - - /* - * Set descriptor and data pointer. - */ - skbdesc->data = entry->skb->data; - skbdesc->data_len = rxdesc->size; - skbdesc->desc = rxd; - skbdesc->desc_len = entry->queue->desc_size; } /* @@ -1205,7 +1270,7 @@ static void rt2500usb_fill_rxdone(struct queue_entry *entry, static void rt2500usb_beacondone(struct urb *urb) { struct queue_entry *entry = (struct queue_entry *)urb->context; - struct queue_entry_priv_usb_bcn *priv_bcn = entry->priv_data; + struct queue_entry_priv_usb_bcn *bcn_priv = entry->priv_data; if (!test_bit(DEVICE_ENABLED_RADIO, &entry->queue->rt2x00dev->flags)) return; @@ -1216,9 +1281,9 @@ static void rt2500usb_beacondone(struct urb *urb) * Otherwise we should free the sk_buffer, the device * should be doing the rest of the work now. */ - if (priv_bcn->guardian_urb == urb) { - usb_submit_urb(priv_bcn->urb, GFP_ATOMIC); - } else if (priv_bcn->urb == urb) { + if (bcn_priv->guardian_urb == urb) { + usb_submit_urb(bcn_priv->urb, GFP_ATOMIC); + } else if (bcn_priv->urb == urb) { dev_kfree_skb(entry->skb); entry->skb = NULL; } @@ -1397,23 +1462,10 @@ static int rt2500usb_init_eeprom(struct rt2x00_dev *rt2x00dev) #ifdef CONFIG_RT2500USB_LEDS value = rt2x00_get_field16(eeprom, EEPROM_ANTENNA_LED_MODE); - rt2x00dev->led_radio.rt2x00dev = rt2x00dev; - rt2x00dev->led_radio.type = LED_TYPE_RADIO; - rt2x00dev->led_radio.led_dev.brightness_set = - rt2500usb_brightness_set; - rt2x00dev->led_radio.led_dev.blink_set = - rt2500usb_blink_set; - rt2x00dev->led_radio.flags = LED_INITIALIZED; - - if (value == LED_MODE_TXRX_ACTIVITY) { - rt2x00dev->led_qual.rt2x00dev = rt2x00dev; - rt2x00dev->led_qual.type = LED_TYPE_ACTIVITY; - rt2x00dev->led_qual.led_dev.brightness_set = - rt2500usb_brightness_set; - rt2x00dev->led_qual.led_dev.blink_set = - rt2500usb_blink_set; - rt2x00dev->led_qual.flags = LED_INITIALIZED; - } + rt2500usb_init_led(rt2x00dev, &rt2x00dev->led_radio, LED_TYPE_RADIO); + if (value == LED_MODE_TXRX_ACTIVITY) + rt2500usb_init_led(rt2x00dev, &rt2x00dev->led_qual, + LED_TYPE_ACTIVITY); #endif /* CONFIG_RT2500USB_LEDS */ /* @@ -1600,13 +1652,12 @@ static void rt2500usb_probe_hw_mode(struct rt2x00_dev *rt2x00dev) rt2x00dev->hw->flags = IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE | IEEE80211_HW_RX_INCLUDES_FCS | - IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING; + IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | + IEEE80211_HW_SIGNAL_DBM; + rt2x00dev->hw->extra_tx_headroom = TXD_DESC_SIZE; - rt2x00dev->hw->max_signal = MAX_SIGNAL; - rt2x00dev->hw->max_rssi = MAX_RX_SSI; - rt2x00dev->hw->queues = 2; - SET_IEEE80211_DEV(rt2x00dev->hw, &rt2x00dev_usb(rt2x00dev)->dev); + SET_IEEE80211_DEV(rt2x00dev->hw, rt2x00dev->dev); SET_IEEE80211_PERM_ADDR(rt2x00dev->hw, rt2x00_eeprom_addr(rt2x00dev, EEPROM_MAC_ADDR_0)); @@ -1684,97 +1735,6 @@ static int rt2500usb_probe_hw(struct rt2x00_dev *rt2x00dev) return 0; } -/* - * IEEE80211 stack callback functions. - */ -static int rt2500usb_beacon_update(struct ieee80211_hw *hw, - struct sk_buff *skb, - struct ieee80211_tx_control *control) -{ - struct rt2x00_dev *rt2x00dev = hw->priv; - struct usb_device *usb_dev = rt2x00dev_usb_dev(rt2x00dev); - struct rt2x00_intf *intf = vif_to_intf(control->vif); - struct queue_entry_priv_usb_bcn *priv_bcn; - struct skb_frame_desc *skbdesc; - int pipe = usb_sndbulkpipe(usb_dev, 1); - int length; - u16 reg; - - if (unlikely(!intf->beacon)) - return -ENOBUFS; - - priv_bcn = intf->beacon->priv_data; - - /* - * Add the descriptor in front of the skb. - */ - skb_push(skb, intf->beacon->queue->desc_size); - memset(skb->data, 0, intf->beacon->queue->desc_size); - - /* - * Fill in skb descriptor - */ - skbdesc = get_skb_frame_desc(skb); - memset(skbdesc, 0, sizeof(*skbdesc)); - skbdesc->flags |= FRAME_DESC_DRIVER_GENERATED; - skbdesc->data = skb->data + intf->beacon->queue->desc_size; - skbdesc->data_len = skb->len - intf->beacon->queue->desc_size; - skbdesc->desc = skb->data; - skbdesc->desc_len = intf->beacon->queue->desc_size; - skbdesc->entry = intf->beacon; - - /* - * Disable beaconing while we are reloading the beacon data, - * otherwise we might be sending out invalid data. - */ - rt2500usb_register_read(rt2x00dev, TXRX_CSR19, ®); - rt2x00_set_field16(®, TXRX_CSR19_TSF_COUNT, 0); - rt2x00_set_field16(®, TXRX_CSR19_TBCN, 0); - rt2x00_set_field16(®, TXRX_CSR19_BEACON_GEN, 0); - rt2500usb_register_write(rt2x00dev, TXRX_CSR19, reg); - - /* - * mac80211 doesn't provide the control->queue variable - * for beacons. Set our own queue identification so - * it can be used during descriptor initialization. - */ - control->queue = RT2X00_BCN_QUEUE_BEACON; - rt2x00lib_write_tx_desc(rt2x00dev, skb, control); - - /* - * USB devices cannot blindly pass the skb->len as the - * length of the data to usb_fill_bulk_urb. Pass the skb - * to the driver to determine what the length should be. - */ - length = rt2500usb_get_tx_data_len(rt2x00dev, skb); - - usb_fill_bulk_urb(priv_bcn->urb, usb_dev, pipe, - skb->data, length, rt2500usb_beacondone, - intf->beacon); - - /* - * Second we need to create the guardian byte. - * We only need a single byte, so lets recycle - * the 'flags' field we are not using for beacons. - */ - priv_bcn->guardian_data = 0; - usb_fill_bulk_urb(priv_bcn->guardian_urb, usb_dev, pipe, - &priv_bcn->guardian_data, 1, rt2500usb_beacondone, - intf->beacon); - - /* - * Send out the guardian byte. - */ - usb_submit_urb(priv_bcn->guardian_urb, GFP_ATOMIC); - - /* - * Enable beacon generation. - */ - rt2500usb_kick_tx_queue(rt2x00dev, control->queue); - - return 0; -} - static const struct ieee80211_ops rt2500usb_mac80211_ops = { .tx = rt2x00mac_tx, .start = rt2x00mac_start, @@ -1788,7 +1748,6 @@ static const struct ieee80211_ops rt2500usb_mac80211_ops = { .bss_info_changed = rt2x00mac_bss_info_changed, .conf_tx = rt2x00mac_conf_tx, .get_tx_stats = rt2x00mac_get_tx_stats, - .beacon_update = rt2500usb_beacon_update, }; static const struct rt2x00lib_ops rt2500usb_rt2x00_ops = { @@ -1803,6 +1762,7 @@ static const struct rt2x00lib_ops rt2500usb_rt2x00_ops = { .link_tuner = rt2500usb_link_tuner, .write_tx_desc = rt2500usb_write_tx_desc, .write_tx_data = rt2x00usb_write_tx_data, + .write_beacon = rt2500usb_write_beacon, .get_tx_data_len = rt2500usb_get_tx_data_len, .kick_tx_queue = rt2500usb_kick_tx_queue, .fill_rxdone = rt2500usb_fill_rxdone, @@ -1816,14 +1776,14 @@ static const struct data_queue_desc rt2500usb_queue_rx = { .entry_num = RX_ENTRIES, .data_size = DATA_FRAME_SIZE, .desc_size = RXD_DESC_SIZE, - .priv_size = sizeof(struct queue_entry_priv_usb_rx), + .priv_size = sizeof(struct queue_entry_priv_usb), }; static const struct data_queue_desc rt2500usb_queue_tx = { .entry_num = TX_ENTRIES, .data_size = DATA_FRAME_SIZE, .desc_size = TXD_DESC_SIZE, - .priv_size = sizeof(struct queue_entry_priv_usb_tx), + .priv_size = sizeof(struct queue_entry_priv_usb), }; static const struct data_queue_desc rt2500usb_queue_bcn = { @@ -1837,7 +1797,7 @@ static const struct data_queue_desc rt2500usb_queue_atim = { .entry_num = ATIM_ENTRIES, .data_size = DATA_FRAME_SIZE, .desc_size = TXD_DESC_SIZE, - .priv_size = sizeof(struct queue_entry_priv_usb_tx), + .priv_size = sizeof(struct queue_entry_priv_usb), }; static const struct rt2x00_ops rt2500usb_ops = { @@ -1846,6 +1806,7 @@ static const struct rt2x00_ops rt2500usb_ops = { .max_ap_intf = 1, .eeprom_size = EEPROM_SIZE, .rf_size = RF_SIZE, + .tx_queues = NUM_TX_QUEUES, .rx = &rt2500usb_queue_rx, .tx = &rt2500usb_queue_tx, .bcn = &rt2500usb_queue_bcn, diff --git a/drivers/net/wireless/rt2x00/rt2500usb.h b/drivers/net/wireless/rt2x00/rt2500usb.h index a37a068d0c71..4769ffeb4cc6 100644 --- a/drivers/net/wireless/rt2x00/rt2500usb.h +++ b/drivers/net/wireless/rt2x00/rt2500usb.h @@ -48,8 +48,6 @@ * Signal information. * Defaul offset is required for RSSI <-> dBm conversion. */ -#define MAX_SIGNAL 100 -#define MAX_RX_SSI -1 #define DEFAULT_RSSI_OFFSET 120 /* @@ -63,6 +61,11 @@ #define RF_SIZE 0x0014 /* + * Number of TX queues. + */ +#define NUM_TX_QUEUES 2 + +/* * Control/Status Registers(CSR). * Some values are set in TU, whereas 1 TU == 1024 us. */ @@ -206,7 +209,7 @@ #define MAC_CSR21_OFF_PERIOD FIELD16(0xff00) /* - * Collision window control register. + * MAC_CSR22: Collision window control register. */ #define MAC_CSR22 0x042c @@ -293,7 +296,7 @@ #define TXRX_CSR7_BBP_ID1_VALID FIELD16(0x8000) /* - * TXRX_CSR5: OFDM TX BBP ID1. + * TXRX_CSR8: OFDM TX BBP ID1. */ #define TXRX_CSR8 0x0450 #define TXRX_CSR8_BBP_ID0 FIELD16(0x007f) @@ -367,7 +370,14 @@ */ /* - * SEC_CSR0-SEC_CSR7: Shared key 0, word 0-7 + * SEC_CSR0: Shared key 0, word 0 + * SEC_CSR1: Shared key 0, word 1 + * SEC_CSR2: Shared key 0, word 2 + * SEC_CSR3: Shared key 0, word 3 + * SEC_CSR4: Shared key 0, word 4 + * SEC_CSR5: Shared key 0, word 5 + * SEC_CSR6: Shared key 0, word 6 + * SEC_CSR7: Shared key 0, word 7 */ #define SEC_CSR0 0x0480 #define SEC_CSR1 0x0482 @@ -379,7 +389,14 @@ #define SEC_CSR7 0x048e /* - * SEC_CSR8-SEC_CSR15: Shared key 1, word 0-7 + * SEC_CSR8: Shared key 1, word 0 + * SEC_CSR9: Shared key 1, word 1 + * SEC_CSR10: Shared key 1, word 2 + * SEC_CSR11: Shared key 1, word 3 + * SEC_CSR12: Shared key 1, word 4 + * SEC_CSR13: Shared key 1, word 5 + * SEC_CSR14: Shared key 1, word 6 + * SEC_CSR15: Shared key 1, word 7 */ #define SEC_CSR8 0x0490 #define SEC_CSR9 0x0492 @@ -391,7 +408,14 @@ #define SEC_CSR15 0x049e /* - * SEC_CSR16-SEC_CSR23: Shared key 2, word 0-7 + * SEC_CSR16: Shared key 2, word 0 + * SEC_CSR17: Shared key 2, word 1 + * SEC_CSR18: Shared key 2, word 2 + * SEC_CSR19: Shared key 2, word 3 + * SEC_CSR20: Shared key 2, word 4 + * SEC_CSR21: Shared key 2, word 5 + * SEC_CSR22: Shared key 2, word 6 + * SEC_CSR23: Shared key 2, word 7 */ #define SEC_CSR16 0x04a0 #define SEC_CSR17 0x04a2 @@ -403,7 +427,14 @@ #define SEC_CSR23 0x04ae /* - * SEC_CSR24-SEC_CSR31: Shared key 3, word 0-7 + * SEC_CSR24: Shared key 3, word 0 + * SEC_CSR25: Shared key 3, word 1 + * SEC_CSR26: Shared key 3, word 2 + * SEC_CSR27: Shared key 3, word 3 + * SEC_CSR28: Shared key 3, word 4 + * SEC_CSR29: Shared key 3, word 5 + * SEC_CSR30: Shared key 3, word 6 + * SEC_CSR31: Shared key 3, word 7 */ #define SEC_CSR24 0x04b0 #define SEC_CSR25 0x04b2 diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h index a74e1a5c56fd..07b03b3c7ef1 100644 --- a/drivers/net/wireless/rt2x00/rt2x00.h +++ b/drivers/net/wireless/rt2x00/rt2x00.h @@ -44,7 +44,7 @@ /* * Module information. */ -#define DRV_VERSION "2.1.4" +#define DRV_VERSION "2.1.8" #define DRV_PROJECT "http://rt2x00.serialmonkey.com" /* @@ -111,33 +111,6 @@ #define EIFS ( SIFS + (8 * (IEEE80211_HEADER + ACK_SIZE)) ) /* - * IEEE802.11 header defines - */ -static inline int is_rts_frame(u16 fc) -{ - return (((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_CTL) && - ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_RTS)); -} - -static inline int is_cts_frame(u16 fc) -{ - return (((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_CTL) && - ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_CTS)); -} - -static inline int is_probe_resp(u16 fc) -{ - return (((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT) && - ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_PROBE_RESP)); -} - -static inline int is_beacon(u16 fc) -{ - return (((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT) && - ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_BEACON)); -} - -/* * Chipset identification * The chipset on the device is composed of a RT and RF chip. * The chipset combination is important for determining device capabilities. @@ -391,6 +364,8 @@ struct rt2x00_intf { #define DELAYED_UPDATE_BEACON 0x00000001 #define DELAYED_CONFIG_ERP 0x00000002 #define DELAYED_LED_ASSOC 0x00000004 + + u16 seqno; }; static inline struct rt2x00_intf* vif_to_intf(struct ieee80211_vif *vif) @@ -409,7 +384,7 @@ static inline struct rt2x00_intf* vif_to_intf(struct ieee80211_vif *vif) * @supported_rates: Rate types which are supported (CCK, OFDM). * @num_channels: Number of supported channels. This is used as array size * for @tx_power_a, @tx_power_bg and @channels. - * channels: Device/chipset specific channel values (See &struct rf_channel). + * @channels: Device/chipset specific channel values (See &struct rf_channel). * @tx_power_a: TX power values for all 5.2GHz channels (may be NULL). * @tx_power_bg: TX power values for all 2.4GHz channels (may be NULL). * @tx_power_default: Default TX power value to use when either @@ -461,6 +436,7 @@ struct rt2x00lib_conf { */ struct rt2x00lib_erp { int short_preamble; + int cts_protection; int ack_timeout; int ack_consume_time; @@ -545,15 +521,13 @@ struct rt2x00lib_ops { */ void (*write_tx_desc) (struct rt2x00_dev *rt2x00dev, struct sk_buff *skb, - struct txentry_desc *txdesc, - struct ieee80211_tx_control *control); - int (*write_tx_data) (struct rt2x00_dev *rt2x00dev, - struct data_queue *queue, struct sk_buff *skb, - struct ieee80211_tx_control *control); + struct txentry_desc *txdesc); + int (*write_tx_data) (struct queue_entry *entry); + void (*write_beacon) (struct queue_entry *entry); int (*get_tx_data_len) (struct rt2x00_dev *rt2x00dev, struct sk_buff *skb); void (*kick_tx_queue) (struct rt2x00_dev *rt2x00dev, - const unsigned int queue); + const enum data_queue_qid queue); /* * RX control handlers @@ -597,6 +571,7 @@ struct rt2x00_ops { const unsigned int max_ap_intf; const unsigned int eeprom_size; const unsigned int rf_size; + const unsigned int tx_queues; const struct data_queue_desc *rx; const struct data_queue_desc *tx; const struct data_queue_desc *bcn; @@ -626,11 +601,11 @@ enum rt2x00_flags { /* * Driver features */ - DRIVER_SUPPORT_MIXED_INTERFACES, DRIVER_REQUIRE_FIRMWARE, DRIVER_REQUIRE_BEACON_GUARD, DRIVER_REQUIRE_ATIM_QUEUE, DRIVER_REQUIRE_SCHEDULED, + DRIVER_REQUIRE_DMA, /* * Driver configuration @@ -655,11 +630,7 @@ struct rt2x00_dev { * When accessing this variable, the rt2x00dev_{pci,usb} * macro's should be used for correct typecasting. */ - void *dev; -#define rt2x00dev_pci(__dev) ( (struct pci_dev *)(__dev)->dev ) -#define rt2x00dev_usb(__dev) ( (struct usb_interface *)(__dev)->dev ) -#define rt2x00dev_usb_dev(__dev)\ - ( (struct usb_device *)interface_to_usbdev(rt2x00dev_usb(__dev)) ) + struct device *dev; /* * Callback functions. @@ -682,7 +653,7 @@ struct rt2x00_dev { #define RFKILL_STATE_ALLOCATED 1 #define RFKILL_STATE_REGISTERED 2 struct rfkill *rfkill; - struct input_polled_dev *poll_dev; + struct delayed_work rfkill_work; #endif /* CONFIG_RT2X00_LIB_RFKILL */ /* @@ -820,8 +791,10 @@ struct rt2x00_dev { /* * Scheduled work. + * NOTE: intf_work will use ieee80211_iterate_active_interfaces() + * which means it cannot be placed on the hw->workqueue + * due to RTNL locking requirements. */ - struct workqueue_struct *workqueue; struct work_struct intf_work; struct work_struct filter_work; @@ -830,7 +803,7 @@ struct rt2x00_dev { * The Beacon array also contains the Atim queue * if that is supported by the device. */ - int data_queues; + unsigned int data_queues; struct data_queue *rx; struct data_queue *tx; struct data_queue *bcn; @@ -934,55 +907,41 @@ static inline u16 get_duration_res(const unsigned int size, const u8 rate) } /** - * rt2x00queue_get_queue - Convert mac80211 queue index to rt2x00 queue + * rt2x00queue_map_txskb - Map a skb into DMA for TX purposes. * @rt2x00dev: Pointer to &struct rt2x00_dev. - * @queue: mac80211/rt2x00 queue index - * (see &enum ieee80211_tx_queue and &enum rt2x00_bcn_queue). + * @skb: The skb to map. + */ +void rt2x00queue_map_txskb(struct rt2x00_dev *rt2x00dev, struct sk_buff *skb); + +/** + * rt2x00queue_get_queue - Convert queue index to queue pointer + * @rt2x00dev: Pointer to &struct rt2x00_dev. + * @queue: rt2x00 queue index (see &enum data_queue_qid). */ struct data_queue *rt2x00queue_get_queue(struct rt2x00_dev *rt2x00dev, - const unsigned int queue); + const enum data_queue_qid queue); /** * rt2x00queue_get_entry - Get queue entry where the given index points to. - * @rt2x00dev: Pointer to &struct rt2x00_dev. + * @queue: Pointer to &struct data_queue from where we obtain the entry. * @index: Index identifier for obtaining the correct index. */ struct queue_entry *rt2x00queue_get_entry(struct data_queue *queue, enum queue_index index); -/** - * rt2x00queue_index_inc - Index incrementation function - * @queue: Queue (&struct data_queue) to perform the action on. - * @action: Index type (&enum queue_index) to perform the action on. - * - * This function will increase the requested index on the queue, - * it will grab the appropriate locks and handle queue overflow events by - * resetting the index to the start of the queue. - */ -void rt2x00queue_index_inc(struct data_queue *queue, enum queue_index index); - - /* * Interrupt context handlers. */ void rt2x00lib_beacondone(struct rt2x00_dev *rt2x00dev); void rt2x00lib_txdone(struct queue_entry *entry, struct txdone_entry_desc *txdesc); -void rt2x00lib_rxdone(struct queue_entry *entry, - struct rxdone_entry_desc *rxdesc); - -/* - * TX descriptor initializer - */ -void rt2x00lib_write_tx_desc(struct rt2x00_dev *rt2x00dev, - struct sk_buff *skb, - struct ieee80211_tx_control *control); +void rt2x00lib_rxdone(struct rt2x00_dev *rt2x00dev, + struct queue_entry *entry); /* * mac80211 handlers. */ -int rt2x00mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb, - struct ieee80211_tx_control *control); +int rt2x00mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb); int rt2x00mac_start(struct ieee80211_hw *hw); void rt2x00mac_stop(struct ieee80211_hw *hw); int rt2x00mac_add_interface(struct ieee80211_hw *hw, @@ -1005,7 +964,7 @@ void rt2x00mac_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_bss_conf *bss_conf, u32 changes); -int rt2x00mac_conf_tx(struct ieee80211_hw *hw, int queue, +int rt2x00mac_conf_tx(struct ieee80211_hw *hw, u16 queue, const struct ieee80211_tx_queue_params *params); /* diff --git a/drivers/net/wireless/rt2x00/rt2x00config.c b/drivers/net/wireless/rt2x00/rt2x00config.c index 48608e8cc8b4..f20ca712504f 100644 --- a/drivers/net/wireless/rt2x00/rt2x00config.c +++ b/drivers/net/wireless/rt2x00/rt2x00config.c @@ -84,6 +84,8 @@ void rt2x00lib_config_erp(struct rt2x00_dev *rt2x00dev, memset(&erp, 0, sizeof(erp)); erp.short_preamble = bss_conf->use_short_preamble; + erp.cts_protection = bss_conf->use_cts_prot; + erp.ack_timeout = PLCP + get_duration(ACK_SIZE, 10); erp.ack_consume_time = SIFS + PLCP + get_duration(ACK_SIZE, 10); diff --git a/drivers/net/wireless/rt2x00/rt2x00debug.c b/drivers/net/wireless/rt2x00/rt2x00debug.c index bfab3b8780d6..300cf061035f 100644 --- a/drivers/net/wireless/rt2x00/rt2x00debug.c +++ b/drivers/net/wireless/rt2x00/rt2x00debug.c @@ -115,7 +115,7 @@ struct rt2x00debug_intf { }; void rt2x00debug_dump_frame(struct rt2x00_dev *rt2x00dev, - struct sk_buff *skb) + enum rt2x00_dump_type type, struct sk_buff *skb) { struct rt2x00debug_intf *intf = rt2x00dev->debugfs_intf; struct skb_frame_desc *desc = get_skb_frame_desc(skb); @@ -133,7 +133,7 @@ void rt2x00debug_dump_frame(struct rt2x00_dev *rt2x00dev, return; } - skbcopy = alloc_skb(sizeof(*dump_hdr) + desc->desc_len + desc->data_len, + skbcopy = alloc_skb(sizeof(*dump_hdr) + desc->desc_len + skb->len, GFP_ATOMIC); if (!skbcopy) { DEBUG(rt2x00dev, "Failed to copy skb for dump.\n"); @@ -144,18 +144,18 @@ void rt2x00debug_dump_frame(struct rt2x00_dev *rt2x00dev, dump_hdr->version = cpu_to_le32(DUMP_HEADER_VERSION); dump_hdr->header_length = cpu_to_le32(sizeof(*dump_hdr)); dump_hdr->desc_length = cpu_to_le32(desc->desc_len); - dump_hdr->data_length = cpu_to_le32(desc->data_len); + dump_hdr->data_length = cpu_to_le32(skb->len); dump_hdr->chip_rt = cpu_to_le16(rt2x00dev->chip.rt); dump_hdr->chip_rf = cpu_to_le16(rt2x00dev->chip.rf); dump_hdr->chip_rev = cpu_to_le32(rt2x00dev->chip.rev); - dump_hdr->type = cpu_to_le16(desc->frame_type); + dump_hdr->type = cpu_to_le16(type); dump_hdr->queue_index = desc->entry->queue->qid; dump_hdr->entry_index = desc->entry->entry_idx; dump_hdr->timestamp_sec = cpu_to_le32(timestamp.tv_sec); dump_hdr->timestamp_usec = cpu_to_le32(timestamp.tv_usec); memcpy(skb_put(skbcopy, desc->desc_len), desc->desc, desc->desc_len); - memcpy(skb_put(skbcopy, desc->data_len), desc->data, desc->data_len); + memcpy(skb_put(skbcopy, skb->len), skb->data, skb->len); skb_queue_tail(&intf->frame_dump_skbqueue, skbcopy); wake_up_interruptible(&intf->frame_dump_waitqueue); diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c index c997d4f28ab3..8c93eb8353b0 100644 --- a/drivers/net/wireless/rt2x00/rt2x00dev.c +++ b/drivers/net/wireless/rt2x00/rt2x00dev.c @@ -28,7 +28,6 @@ #include "rt2x00.h" #include "rt2x00lib.h" -#include "rt2x00dump.h" /* * Link tuning handlers @@ -75,7 +74,7 @@ static void rt2x00lib_start_link_tuner(struct rt2x00_dev *rt2x00dev) rt2x00lib_reset_link_tuner(rt2x00dev); - queue_delayed_work(rt2x00dev->workqueue, + queue_delayed_work(rt2x00dev->hw->workqueue, &rt2x00dev->link.work, LINK_TUNE_INTERVAL); } @@ -113,6 +112,8 @@ int rt2x00lib_enable_radio(struct rt2x00_dev *rt2x00dev) if (status) return status; + rt2x00dev->ops->lib->set_device_state(rt2x00dev, STATE_RADIO_IRQ_ON); + rt2x00leds_led_radio(rt2x00dev, true); rt2x00led_led_activity(rt2x00dev, true); @@ -126,7 +127,7 @@ int rt2x00lib_enable_radio(struct rt2x00_dev *rt2x00dev) /* * Start the TX queues. */ - ieee80211_start_queues(rt2x00dev->hw); + ieee80211_wake_queues(rt2x00dev->hw); return 0; } @@ -150,6 +151,7 @@ void rt2x00lib_disable_radio(struct rt2x00_dev *rt2x00dev) * Disable radio. */ rt2x00dev->ops->lib->set_device_state(rt2x00dev, STATE_RADIO_OFF); + rt2x00dev->ops->lib->set_device_state(rt2x00dev, STATE_RADIO_IRQ_OFF); rt2x00led_led_activity(rt2x00dev, false); rt2x00leds_led_radio(rt2x00dev, false); } @@ -390,7 +392,7 @@ static void rt2x00lib_link_tuner(struct work_struct *work) * Increase tuner counter, and reschedule the next link tuner run. */ rt2x00dev->link.count++; - queue_delayed_work(rt2x00dev->workqueue, + queue_delayed_work(rt2x00dev->hw->workqueue, &rt2x00dev->link.work, LINK_TUNE_INTERVAL); } @@ -407,8 +409,6 @@ static void rt2x00lib_intf_scheduled_iter(void *data, u8 *mac, { struct rt2x00_dev *rt2x00dev = data; struct rt2x00_intf *intf = vif_to_intf(vif); - struct sk_buff *skb; - struct ieee80211_tx_control control; struct ieee80211_bss_conf conf; int delayed_flags; @@ -434,12 +434,8 @@ static void rt2x00lib_intf_scheduled_iter(void *data, u8 *mac, if (!test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags)) return; - if (delayed_flags & DELAYED_UPDATE_BEACON) { - skb = ieee80211_beacon_get(rt2x00dev->hw, vif, &control); - if (skb && rt2x00dev->ops->hw->beacon_update(rt2x00dev->hw, - skb, &control)) - dev_kfree_skb(skb); - } + if (delayed_flags & DELAYED_UPDATE_BEACON) + rt2x00queue_update_beacon(rt2x00dev, vif); if (delayed_flags & DELAYED_CONFIG_ERP) rt2x00lib_config_erp(rt2x00dev, intf, &conf); @@ -468,12 +464,19 @@ static void rt2x00lib_intf_scheduled(struct work_struct *work) static void rt2x00lib_beacondone_iter(void *data, u8 *mac, struct ieee80211_vif *vif) { + struct rt2x00_dev *rt2x00dev = data; struct rt2x00_intf *intf = vif_to_intf(vif); if (vif->type != IEEE80211_IF_TYPE_AP && vif->type != IEEE80211_IF_TYPE_IBSS) return; + /* + * Clean up the beacon skb. + */ + rt2x00queue_free_skb(rt2x00dev, intf->beacon->skb); + intf->beacon->skb = NULL; + spin_lock(&intf->lock); intf->delayed_flags |= DELAYED_UPDATE_BEACON; spin_unlock(&intf->lock); @@ -488,7 +491,7 @@ void rt2x00lib_beacondone(struct rt2x00_dev *rt2x00dev) rt2x00lib_beacondone_iter, rt2x00dev); - queue_work(rt2x00dev->workqueue, &rt2x00dev->intf_work); + schedule_work(&rt2x00dev->intf_work); } EXPORT_SYMBOL_GPL(rt2x00lib_beacondone); @@ -496,79 +499,132 @@ void rt2x00lib_txdone(struct queue_entry *entry, struct txdone_entry_desc *txdesc) { struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev; - struct skb_frame_desc *skbdesc; - struct ieee80211_tx_status tx_status; - int success = !!(txdesc->status == TX_SUCCESS || - txdesc->status == TX_SUCCESS_RETRY); - int fail = !!(txdesc->status == TX_FAIL_RETRY || - txdesc->status == TX_FAIL_INVALID || - txdesc->status == TX_FAIL_OTHER); + struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(entry->skb); + enum data_queue_qid qid = skb_get_queue_mapping(entry->skb); + + /* + * Unmap the skb. + */ + rt2x00queue_unmap_skb(rt2x00dev, entry->skb); + + /* + * Send frame to debugfs immediately, after this call is completed + * we are going to overwrite the skb->cb array. + */ + rt2x00debug_dump_frame(rt2x00dev, DUMP_FRAME_TXDONE, entry->skb); /* * Update TX statistics. */ - rt2x00dev->link.qual.tx_success += success; - rt2x00dev->link.qual.tx_failed += fail; + rt2x00dev->link.qual.tx_success += + test_bit(TXDONE_SUCCESS, &txdesc->flags); + rt2x00dev->link.qual.tx_failed += + test_bit(TXDONE_FAILURE, &txdesc->flags); /* * Initialize TX status */ - tx_status.flags = 0; - tx_status.ack_signal = 0; - tx_status.excessive_retries = (txdesc->status == TX_FAIL_RETRY); - tx_status.retry_count = txdesc->retry; - memcpy(&tx_status.control, txdesc->control, sizeof(*txdesc->control)); + memset(&tx_info->status, 0, sizeof(tx_info->status)); + tx_info->status.ack_signal = 0; + tx_info->status.excessive_retries = + test_bit(TXDONE_EXCESSIVE_RETRY, &txdesc->flags); + tx_info->status.retry_count = txdesc->retry; - if (!(tx_status.control.flags & IEEE80211_TXCTL_NO_ACK)) { - if (success) - tx_status.flags |= IEEE80211_TX_STATUS_ACK; - else + if (!(tx_info->flags & IEEE80211_TX_CTL_NO_ACK)) { + if (test_bit(TXDONE_SUCCESS, &txdesc->flags)) + tx_info->flags |= IEEE80211_TX_STAT_ACK; + else if (test_bit(TXDONE_FAILURE, &txdesc->flags)) rt2x00dev->low_level_stats.dot11ACKFailureCount++; } - tx_status.queue_length = entry->queue->limit; - tx_status.queue_number = tx_status.control.queue; - - if (tx_status.control.flags & IEEE80211_TXCTL_USE_RTS_CTS) { - if (success) + if (tx_info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) { + if (test_bit(TXDONE_SUCCESS, &txdesc->flags)) rt2x00dev->low_level_stats.dot11RTSSuccessCount++; - else + else if (test_bit(TXDONE_FAILURE, &txdesc->flags)) rt2x00dev->low_level_stats.dot11RTSFailureCount++; } /* - * Send the tx_status to debugfs. Only send the status report - * to mac80211 when the frame originated from there. If this was - * a extra frame coming through a mac80211 library call (RTS/CTS) - * then we should not send the status report back. - * If send to mac80211, mac80211 will clean up the skb structure, - * otherwise we have to do it ourself. + * Only send the status report to mac80211 when TX status was + * requested by it. If this was a extra frame coming through + * a mac80211 library call (RTS/CTS) then we should not send the + * status report back. */ - skbdesc = get_skb_frame_desc(entry->skb); - skbdesc->frame_type = DUMP_FRAME_TXDONE; - - rt2x00debug_dump_frame(rt2x00dev, entry->skb); - - if (!(skbdesc->flags & FRAME_DESC_DRIVER_GENERATED)) - ieee80211_tx_status_irqsafe(rt2x00dev->hw, - entry->skb, &tx_status); + if (tx_info->flags & IEEE80211_TX_CTL_REQ_TX_STATUS) + ieee80211_tx_status_irqsafe(rt2x00dev->hw, entry->skb); else - dev_kfree_skb(entry->skb); + dev_kfree_skb_irq(entry->skb); + + /* + * Make this entry available for reuse. + */ entry->skb = NULL; + entry->flags = 0; + + rt2x00dev->ops->lib->init_txentry(rt2x00dev, entry); + + __clear_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags); + rt2x00queue_index_inc(entry->queue, Q_INDEX_DONE); + + /* + * If the data queue was below the threshold before the txdone + * handler we must make sure the packet queue in the mac80211 stack + * is reenabled when the txdone handler has finished. + */ + if (!rt2x00queue_threshold(entry->queue)) + ieee80211_wake_queue(rt2x00dev->hw, qid); } EXPORT_SYMBOL_GPL(rt2x00lib_txdone); -void rt2x00lib_rxdone(struct queue_entry *entry, - struct rxdone_entry_desc *rxdesc) +void rt2x00lib_rxdone(struct rt2x00_dev *rt2x00dev, + struct queue_entry *entry) { - struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev; + struct rxdone_entry_desc rxdesc; + struct sk_buff *skb; struct ieee80211_rx_status *rx_status = &rt2x00dev->rx_status; struct ieee80211_supported_band *sband; struct ieee80211_hdr *hdr; const struct rt2x00_rate *rate; + unsigned int header_size; + unsigned int align; unsigned int i; int idx = -1; - u16 fc; + + /* + * Allocate a new sk_buffer. If no new buffer available, drop the + * received frame and reuse the existing buffer. + */ + skb = rt2x00queue_alloc_rxskb(rt2x00dev, entry); + if (!skb) + return; + + /* + * Unmap the skb. + */ + rt2x00queue_unmap_skb(rt2x00dev, entry->skb); + + /* + * Extract the RXD details. + */ + memset(&rxdesc, 0, sizeof(rxdesc)); + rt2x00dev->ops->lib->fill_rxdone(entry, &rxdesc); + + /* + * The data behind the ieee80211 header must be + * aligned on a 4 byte boundary. + */ + header_size = ieee80211_get_hdrlen_from_skb(entry->skb); + align = ((unsigned long)(entry->skb->data + header_size)) & 3; + + 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); /* * Update RX statistics. @@ -577,10 +633,10 @@ void rt2x00lib_rxdone(struct queue_entry *entry, 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_PLCP) && - (rate->bitrate == rxdesc->signal))) { + if (((rxdesc.dev_flags & RXDONE_SIGNAL_PLCP) && + (rate->plcp == rxdesc.signal)) || + (!(rxdesc.dev_flags & RXDONE_SIGNAL_PLCP) && + (rate->bitrate == rxdesc.signal))) { idx = i; break; } @@ -588,8 +644,8 @@ void rt2x00lib_rxdone(struct queue_entry *entry, if (idx < 0) { WARNING(rt2x00dev, "Frame received with unrecognized signal," - "signal=0x%.2x, plcp=%d.\n", rxdesc->signal, - !!(rxdesc->dev_flags & RXDONE_SIGNAL_PLCP)); + "signal=0x%.2x, plcp=%d.\n", rxdesc.signal, + !!(rxdesc.dev_flags & RXDONE_SIGNAL_PLCP)); idx = 0; } @@ -597,170 +653,38 @@ void rt2x00lib_rxdone(struct queue_entry *entry, * Only update link status if this is a beacon frame carrying our bssid. */ hdr = (struct ieee80211_hdr *)entry->skb->data; - fc = le16_to_cpu(hdr->frame_control); - if (is_beacon(fc) && (rxdesc->dev_flags & RXDONE_MY_BSS)) - rt2x00lib_update_link_stats(&rt2x00dev->link, rxdesc->rssi); + if (ieee80211_is_beacon(hdr->frame_control) && + (rxdesc.dev_flags & RXDONE_MY_BSS)) + rt2x00lib_update_link_stats(&rt2x00dev->link, rxdesc.rssi); rt2x00dev->link.qual.rx_success++; + rx_status->mactime = rxdesc.timestamp; rx_status->rate_idx = idx; - rx_status->signal = - rt2x00lib_calculate_link_signal(rt2x00dev, rxdesc->rssi); - rx_status->ssi = rxdesc->rssi; - rx_status->flag = rxdesc->flags; + rx_status->qual = + rt2x00lib_calculate_link_signal(rt2x00dev, rxdesc.rssi); + rx_status->signal = rxdesc.rssi; + rx_status->flag = rxdesc.flags; rx_status->antenna = rt2x00dev->link.ant.active.rx; /* * Send frame to mac80211 & debugfs. * mac80211 will clean up the skb structure. */ - get_skb_frame_desc(entry->skb)->frame_type = DUMP_FRAME_RXDONE; - rt2x00debug_dump_frame(rt2x00dev, entry->skb); + rt2x00debug_dump_frame(rt2x00dev, DUMP_FRAME_RXDONE, entry->skb); ieee80211_rx_irqsafe(rt2x00dev->hw, entry->skb, rx_status); - entry->skb = NULL; -} -EXPORT_SYMBOL_GPL(rt2x00lib_rxdone); - -/* - * TX descriptor initializer - */ -void rt2x00lib_write_tx_desc(struct rt2x00_dev *rt2x00dev, - struct sk_buff *skb, - struct ieee80211_tx_control *control) -{ - struct txentry_desc txdesc; - struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb); - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skbdesc->data; - const struct rt2x00_rate *rate; - int tx_rate; - int length; - int duration; - int residual; - u16 frame_control; - u16 seq_ctrl; - - memset(&txdesc, 0, sizeof(txdesc)); - - txdesc.queue = skbdesc->entry->queue->qid; - txdesc.cw_min = skbdesc->entry->queue->cw_min; - txdesc.cw_max = skbdesc->entry->queue->cw_max; - txdesc.aifs = skbdesc->entry->queue->aifs; - - /* - * Read required fields from ieee80211 header. - */ - frame_control = le16_to_cpu(hdr->frame_control); - seq_ctrl = le16_to_cpu(hdr->seq_ctrl); - - tx_rate = control->tx_rate->hw_value; /* - * Check whether this frame is to be acked + * Replace the skb with the freshly allocated one. */ - if (!(control->flags & IEEE80211_TXCTL_NO_ACK)) - __set_bit(ENTRY_TXD_ACK, &txdesc.flags); - - /* - * Check if this is a RTS/CTS frame - */ - if (is_rts_frame(frame_control) || is_cts_frame(frame_control)) { - __set_bit(ENTRY_TXD_BURST, &txdesc.flags); - if (is_rts_frame(frame_control)) { - __set_bit(ENTRY_TXD_RTS_FRAME, &txdesc.flags); - __set_bit(ENTRY_TXD_ACK, &txdesc.flags); - } else - __clear_bit(ENTRY_TXD_ACK, &txdesc.flags); - if (control->rts_cts_rate) - tx_rate = control->rts_cts_rate->hw_value; - } - - rate = rt2x00_get_rate(tx_rate); - - /* - * Check if more fragments are pending - */ - if (ieee80211_get_morefrag(hdr)) { - __set_bit(ENTRY_TXD_BURST, &txdesc.flags); - __set_bit(ENTRY_TXD_MORE_FRAG, &txdesc.flags); - } - - /* - * Beacons and probe responses require the tsf timestamp - * to be inserted into the frame. - */ - if (control->queue == RT2X00_BCN_QUEUE_BEACON || - is_probe_resp(frame_control)) - __set_bit(ENTRY_TXD_REQ_TIMESTAMP, &txdesc.flags); - - /* - * Determine with what IFS priority this frame should be send. - * Set ifs to IFS_SIFS when the this is not the first fragment, - * or this fragment came after RTS/CTS. - */ - if ((seq_ctrl & IEEE80211_SCTL_FRAG) > 0 || - test_bit(ENTRY_TXD_RTS_FRAME, &txdesc.flags)) - txdesc.ifs = IFS_SIFS; - else - txdesc.ifs = IFS_BACKOFF; - - /* - * PLCP setup - * Length calculation depends on OFDM/CCK rate. - */ - txdesc.signal = rate->plcp; - txdesc.service = 0x04; - - length = skbdesc->data_len + FCS_LEN; - if (rate->flags & DEV_RATE_OFDM) { - __set_bit(ENTRY_TXD_OFDM_RATE, &txdesc.flags); - - txdesc.length_high = (length >> 6) & 0x3f; - txdesc.length_low = length & 0x3f; - } else { - /* - * Convert length to microseconds. - */ - residual = get_duration_res(length, rate->bitrate); - duration = get_duration(length, rate->bitrate); - - if (residual != 0) { - duration++; - - /* - * Check if we need to set the Length Extension - */ - if (rate->bitrate == 110 && residual <= 30) - txdesc.service |= 0x80; - } - - txdesc.length_high = (duration >> 8) & 0xff; - txdesc.length_low = duration & 0xff; - - /* - * When preamble is enabled we should set the - * preamble bit for the signal. - */ - if (rt2x00_get_rate_preamble(tx_rate)) - txdesc.signal |= 0x08; - } - - rt2x00dev->ops->lib->write_tx_desc(rt2x00dev, skb, &txdesc, control); + entry->skb = skb; + entry->flags = 0; - /* - * Update queue entry. - */ - skbdesc->entry->skb = skb; + rt2x00dev->ops->lib->init_rxentry(rt2x00dev, entry); - /* - * The frame has been completely initialized and ready - * for sending to the device. The caller will push the - * frame to the device, but we are going to push the - * frame to debugfs here. - */ - skbdesc->frame_type = DUMP_FRAME_TX; - rt2x00debug_dump_frame(rt2x00dev, skb); + rt2x00queue_index_inc(entry->queue, Q_INDEX); } -EXPORT_SYMBOL_GPL(rt2x00lib_write_tx_desc); +EXPORT_SYMBOL_GPL(rt2x00lib_rxdone); /* * Driver initialization handlers. @@ -978,6 +902,11 @@ static int rt2x00lib_probe_hw(struct rt2x00_dev *rt2x00dev) return status; /* + * Initialize HW fields. + */ + rt2x00dev->hw->queues = rt2x00dev->ops->tx_queues; + + /* * Register HW. */ status = ieee80211_register_hw(rt2x00dev->hw); @@ -1131,10 +1060,6 @@ int rt2x00lib_probe_dev(struct rt2x00_dev *rt2x00dev) /* * Initialize configuration work. */ - rt2x00dev->workqueue = create_singlethread_workqueue("rt2x00lib"); - if (!rt2x00dev->workqueue) - goto exit; - INIT_WORK(&rt2x00dev->intf_work, rt2x00lib_intf_scheduled); INIT_WORK(&rt2x00dev->filter_work, rt2x00lib_packetfilter_scheduled); INIT_DELAYED_WORK(&rt2x00dev->link.work, rt2x00lib_link_tuner); @@ -1195,13 +1120,6 @@ void rt2x00lib_remove_dev(struct rt2x00_dev *rt2x00dev) rt2x00leds_unregister(rt2x00dev); /* - * Stop all queued work. Note that most tasks will already be halted - * during rt2x00lib_disable_radio() and rt2x00lib_uninitialize(). - */ - flush_workqueue(rt2x00dev->workqueue); - destroy_workqueue(rt2x00dev->workqueue); - - /* * Free ieee80211_hw memory. */ rt2x00lib_remove_hw(rt2x00dev); @@ -1246,7 +1164,6 @@ int rt2x00lib_suspend(struct rt2x00_dev *rt2x00dev, pm_message_t state) * Suspend/disable extra components. */ rt2x00leds_suspend(rt2x00dev); - rt2x00rfkill_suspend(rt2x00dev); rt2x00debug_deregister(rt2x00dev); exit: @@ -1302,7 +1219,6 @@ int rt2x00lib_resume(struct rt2x00_dev *rt2x00dev) * Restore/enable extra components. */ rt2x00debug_register(rt2x00dev); - rt2x00rfkill_resume(rt2x00dev); rt2x00leds_resume(rt2x00dev); /* @@ -1343,7 +1259,7 @@ int rt2x00lib_resume(struct rt2x00_dev *rt2x00dev) * In that case we have disabled the TX queue and should * now enable it again */ - ieee80211_start_queues(rt2x00dev->hw); + ieee80211_wake_queues(rt2x00dev->hw); /* * During interface iteration we might have changed the diff --git a/drivers/net/wireless/rt2x00/rt2x00firmware.c b/drivers/net/wireless/rt2x00/rt2x00firmware.c index b971bc6e7ee2..bab05a56e7a0 100644 --- a/drivers/net/wireless/rt2x00/rt2x00firmware.c +++ b/drivers/net/wireless/rt2x00/rt2x00firmware.c @@ -100,6 +100,14 @@ int rt2x00lib_load_firmware(struct rt2x00_dev *rt2x00dev) retval = rt2x00dev->ops->lib->load_firmware(rt2x00dev, rt2x00dev->fw->data, rt2x00dev->fw->size); + + /* + * When the firmware is uploaded to the hardware the LED + * association status might have been triggered, for correct + * LED handling it should now be reset. + */ + rt2x00leds_led_assoc(rt2x00dev, false); + return retval; } diff --git a/drivers/net/wireless/rt2x00/rt2x00lib.h b/drivers/net/wireless/rt2x00/rt2x00lib.h index 41ee02cd2825..f2c9b0e79b5f 100644 --- a/drivers/net/wireless/rt2x00/rt2x00lib.h +++ b/drivers/net/wireless/rt2x00/rt2x00lib.h @@ -26,12 +26,14 @@ #ifndef RT2X00LIB_H #define RT2X00LIB_H +#include "rt2x00dump.h" + /* * 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 RFKILL_POLL_INTERVAL ( round_jiffies_relative(HZ) ) /* * rt2x00_rate: Per rate device information @@ -96,9 +98,65 @@ void rt2x00lib_config_antenna(struct rt2x00_dev *rt2x00dev, void rt2x00lib_config(struct rt2x00_dev *rt2x00dev, struct ieee80211_conf *conf, const int force_config); -/* - * Queue handlers. +/** + * DOC: Queue handlers + */ + +/** + * rt2x00queue_alloc_rxskb - allocate a skb for RX purposes. + * @rt2x00dev: Pointer to &struct rt2x00_dev. + * @queue: The queue for which the skb will be applicable. + */ +struct sk_buff *rt2x00queue_alloc_rxskb(struct rt2x00_dev *rt2x00dev, + struct queue_entry *entry); + +/** + * rt2x00queue_unmap_skb - Unmap a skb from DMA. + * @rt2x00dev: Pointer to &struct rt2x00_dev. + * @skb: The skb to unmap. + */ +void rt2x00queue_unmap_skb(struct rt2x00_dev *rt2x00dev, struct sk_buff *skb); + +/** + * rt2x00queue_free_skb - free a skb + * @rt2x00dev: Pointer to &struct rt2x00_dev. + * @skb: The skb to free. + */ +void rt2x00queue_free_skb(struct rt2x00_dev *rt2x00dev, struct sk_buff *skb); + +/** + * rt2x00queue_free_skb - free a skb + * @rt2x00dev: Pointer to &struct rt2x00_dev. + * @skb: The skb to free. + */ +void rt2x00queue_free_skb(struct rt2x00_dev *rt2x00dev, struct sk_buff *skb); + +/** + * rt2x00queue_write_tx_frame - Write TX frame to hardware + * @queue: Queue over which the frame should be send + * @skb: The skb to send + */ +int rt2x00queue_write_tx_frame(struct data_queue *queue, struct sk_buff *skb); + +/** + * rt2x00queue_update_beacon - Send new beacon from mac80211 to hardware + * @rt2x00dev: Pointer to &struct rt2x00_dev. + * @vif: Interface for which the beacon should be updated. */ +int rt2x00queue_update_beacon(struct rt2x00_dev *rt2x00dev, + struct ieee80211_vif *vif); + +/** + * rt2x00queue_index_inc - Index incrementation function + * @queue: Queue (&struct data_queue) to perform the action on. + * @index: Index type (&enum queue_index) to perform the action on. + * + * This function will increase the requested index on the queue, + * it will grab the appropriate locks and handle queue overflow events by + * resetting the index to the start of the queue. + */ +void rt2x00queue_index_inc(struct data_queue *queue, enum queue_index index); + void rt2x00queue_init_rx(struct rt2x00_dev *rt2x00dev); void rt2x00queue_init_tx(struct rt2x00_dev *rt2x00dev); int rt2x00queue_initialize(struct rt2x00_dev *rt2x00dev); @@ -128,7 +186,8 @@ static inline void rt2x00lib_free_firmware(struct rt2x00_dev *rt2x00dev) #ifdef CONFIG_RT2X00_LIB_DEBUGFS void rt2x00debug_register(struct rt2x00_dev *rt2x00dev); void rt2x00debug_deregister(struct rt2x00_dev *rt2x00dev); -void rt2x00debug_dump_frame(struct rt2x00_dev *rt2x00dev, struct sk_buff *skb); +void rt2x00debug_dump_frame(struct rt2x00_dev *rt2x00dev, + enum rt2x00_dump_type type, struct sk_buff *skb); #else static inline void rt2x00debug_register(struct rt2x00_dev *rt2x00dev) { @@ -139,6 +198,7 @@ static inline void rt2x00debug_deregister(struct rt2x00_dev *rt2x00dev) } static inline void rt2x00debug_dump_frame(struct rt2x00_dev *rt2x00dev, + enum rt2x00_dump_type type, struct sk_buff *skb) { } @@ -152,8 +212,6 @@ void rt2x00rfkill_register(struct rt2x00_dev *rt2x00dev); void rt2x00rfkill_unregister(struct rt2x00_dev *rt2x00dev); void rt2x00rfkill_allocate(struct rt2x00_dev *rt2x00dev); void rt2x00rfkill_free(struct rt2x00_dev *rt2x00dev); -void rt2x00rfkill_suspend(struct rt2x00_dev *rt2x00dev); -void rt2x00rfkill_resume(struct rt2x00_dev *rt2x00dev); #else static inline void rt2x00rfkill_register(struct rt2x00_dev *rt2x00dev) { @@ -170,14 +228,6 @@ static inline void rt2x00rfkill_allocate(struct rt2x00_dev *rt2x00dev) static inline void rt2x00rfkill_free(struct rt2x00_dev *rt2x00dev) { } - -static inline void rt2x00rfkill_suspend(struct rt2x00_dev *rt2x00dev) -{ -} - -static inline void rt2x00rfkill_resume(struct rt2x00_dev *rt2x00dev) -{ -} #endif /* CONFIG_RT2X00_LIB_RFKILL */ /* diff --git a/drivers/net/wireless/rt2x00/rt2x00mac.c b/drivers/net/wireless/rt2x00/rt2x00mac.c index 9cb023edd2e9..f1dcbaa80c3c 100644 --- a/drivers/net/wireless/rt2x00/rt2x00mac.c +++ b/drivers/net/wireless/rt2x00/rt2x00mac.c @@ -31,14 +31,14 @@ static int rt2x00mac_tx_rts_cts(struct rt2x00_dev *rt2x00dev, struct data_queue *queue, - struct sk_buff *frag_skb, - struct ieee80211_tx_control *control) + struct sk_buff *frag_skb) { - struct skb_frame_desc *skbdesc; + struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(frag_skb); + struct ieee80211_tx_info *rts_info; struct sk_buff *skb; int size; - if (control->flags & IEEE80211_TXCTL_USE_CTS_PROTECT) + if (tx_info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT) size = sizeof(struct ieee80211_cts); else size = sizeof(struct ieee80211_rts); @@ -52,23 +52,37 @@ static int rt2x00mac_tx_rts_cts(struct rt2x00_dev *rt2x00dev, skb_reserve(skb, rt2x00dev->hw->extra_tx_headroom); skb_put(skb, size); - if (control->flags & IEEE80211_TXCTL_USE_CTS_PROTECT) - ieee80211_ctstoself_get(rt2x00dev->hw, control->vif, - frag_skb->data, frag_skb->len, control, + /* + * Copy TX information over from original frame to + * RTS/CTS frame. Note that we set the no encryption flag + * since we don't want this frame to be encrypted. + * RTS frames should be acked, while CTS-to-self frames + * should not. The ready for TX flag is cleared to prevent + * it being automatically send when the descriptor is + * written to the hardware. + */ + memcpy(skb->cb, frag_skb->cb, sizeof(skb->cb)); + rts_info = IEEE80211_SKB_CB(skb); + rts_info->flags |= IEEE80211_TX_CTL_DO_NOT_ENCRYPT; + rts_info->flags &= ~IEEE80211_TX_CTL_USE_RTS_CTS; + rts_info->flags &= ~IEEE80211_TX_CTL_USE_CTS_PROTECT; + rts_info->flags &= ~IEEE80211_TX_CTL_REQ_TX_STATUS; + + if (tx_info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT) + rts_info->flags |= IEEE80211_TX_CTL_NO_ACK; + else + rts_info->flags &= ~IEEE80211_TX_CTL_NO_ACK; + + if (tx_info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT) + ieee80211_ctstoself_get(rt2x00dev->hw, tx_info->control.vif, + frag_skb->data, size, tx_info, (struct ieee80211_cts *)(skb->data)); else - ieee80211_rts_get(rt2x00dev->hw, control->vif, - frag_skb->data, frag_skb->len, control, + ieee80211_rts_get(rt2x00dev->hw, tx_info->control.vif, + frag_skb->data, size, tx_info, (struct ieee80211_rts *)(skb->data)); - /* - * Initialize skb descriptor - */ - skbdesc = get_skb_frame_desc(skb); - memset(skbdesc, 0, sizeof(*skbdesc)); - skbdesc->flags |= FRAME_DESC_DRIVER_GENERATED; - - if (rt2x00dev->ops->lib->write_tx_data(rt2x00dev, queue, skb, control)) { + if (rt2x00queue_write_tx_frame(queue, skb)) { WARNING(rt2x00dev, "Failed to send RTS/CTS frame.\n"); return NETDEV_TX_BUSY; } @@ -76,13 +90,14 @@ static int rt2x00mac_tx_rts_cts(struct rt2x00_dev *rt2x00dev, return NETDEV_TX_OK; } -int rt2x00mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb, - struct ieee80211_tx_control *control) +int rt2x00mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb) { struct rt2x00_dev *rt2x00dev = hw->priv; + struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); struct ieee80211_hdr *ieee80211hdr = (struct ieee80211_hdr *)skb->data; + enum data_queue_qid qid = skb_get_queue_mapping(skb); + struct rt2x00_intf *intf = vif_to_intf(tx_info->control.vif); struct data_queue *queue; - struct skb_frame_desc *skbdesc; u16 frame_control; /* @@ -100,57 +115,62 @@ int rt2x00mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb, /* * Determine which queue to put packet on. */ - if (control->flags & IEEE80211_TXCTL_SEND_AFTER_DTIM && + if (tx_info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM && test_bit(DRIVER_REQUIRE_ATIM_QUEUE, &rt2x00dev->flags)) - queue = rt2x00queue_get_queue(rt2x00dev, RT2X00_BCN_QUEUE_ATIM); + queue = rt2x00queue_get_queue(rt2x00dev, QID_ATIM); else - queue = rt2x00queue_get_queue(rt2x00dev, control->queue); + queue = rt2x00queue_get_queue(rt2x00dev, qid); if (unlikely(!queue)) { ERROR(rt2x00dev, "Attempt to send packet over invalid queue %d.\n" - "Please file bug report to %s.\n", - control->queue, DRV_PROJECT); + "Please file bug report to %s.\n", qid, DRV_PROJECT); dev_kfree_skb_any(skb); return NETDEV_TX_OK; } /* - * If CTS/RTS is required. and this frame is not CTS or RTS, - * create and queue that frame first. But make sure we have - * at least enough entries available to send this CTS/RTS - * frame as well as the data frame. + * If CTS/RTS is required. create and queue that frame first. + * Make sure we have at least enough entries available to send + * this CTS/RTS frame as well as the data frame. + * Note that when the driver has set the set_rts_threshold() + * callback function it doesn't need software generation of + * either RTS or CTS-to-self frame and handles everything + * inside the hardware. */ frame_control = le16_to_cpu(ieee80211hdr->frame_control); - if (!is_rts_frame(frame_control) && !is_cts_frame(frame_control) && - (control->flags & (IEEE80211_TXCTL_USE_RTS_CTS | - IEEE80211_TXCTL_USE_CTS_PROTECT))) { + if ((tx_info->flags & (IEEE80211_TX_CTL_USE_RTS_CTS | + IEEE80211_TX_CTL_USE_CTS_PROTECT)) && + !rt2x00dev->ops->hw->set_rts_threshold) { if (rt2x00queue_available(queue) <= 1) { - ieee80211_stop_queue(rt2x00dev->hw, control->queue); + ieee80211_stop_queue(rt2x00dev->hw, qid); return NETDEV_TX_BUSY; } - if (rt2x00mac_tx_rts_cts(rt2x00dev, queue, skb, control)) { - ieee80211_stop_queue(rt2x00dev->hw, control->queue); + if (rt2x00mac_tx_rts_cts(rt2x00dev, queue, skb)) { + ieee80211_stop_queue(rt2x00dev->hw, qid); return NETDEV_TX_BUSY; } } /* - * Initialize skb descriptor + * XXX: This is as wrong as the old mac80211 code was, + * due to beacons not getting sequence numbers assigned + * properly. */ - skbdesc = get_skb_frame_desc(skb); - memset(skbdesc, 0, sizeof(*skbdesc)); + if (tx_info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) { + if (tx_info->flags & IEEE80211_TX_CTL_FIRST_FRAGMENT) + intf->seqno += 0x10; + ieee80211hdr->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG); + ieee80211hdr->seq_ctrl |= cpu_to_le16(intf->seqno); + } - if (rt2x00dev->ops->lib->write_tx_data(rt2x00dev, queue, skb, control)) { - ieee80211_stop_queue(rt2x00dev->hw, control->queue); + if (rt2x00queue_write_tx_frame(queue, skb)) { + ieee80211_stop_queue(rt2x00dev->hw, qid); return NETDEV_TX_BUSY; } - if (rt2x00queue_full(queue)) - ieee80211_stop_queue(rt2x00dev->hw, control->queue); - - if (rt2x00dev->ops->lib->kick_tx_queue) - rt2x00dev->ops->lib->kick_tx_queue(rt2x00dev, control->queue); + if (rt2x00queue_threshold(queue)) + ieee80211_stop_queue(rt2x00dev->hw, qid); return NETDEV_TX_OK; } @@ -183,8 +203,7 @@ int rt2x00mac_add_interface(struct ieee80211_hw *hw, { struct rt2x00_dev *rt2x00dev = hw->priv; struct rt2x00_intf *intf = vif_to_intf(conf->vif); - struct data_queue *queue = - rt2x00queue_get_queue(rt2x00dev, RT2X00_BCN_QUEUE_BEACON); + struct data_queue *queue = rt2x00queue_get_queue(rt2x00dev, QID_BEACON); struct queue_entry *entry = NULL; unsigned int i; @@ -197,13 +216,12 @@ int rt2x00mac_add_interface(struct ieee80211_hw *hw, return -ENODEV; /* - * When we don't support mixed interfaces (a combination - * of sta and ap virtual interfaces) then we can only - * add this interface when the rival interface count is 0. + * We don't support mixed combinations of sta and ap virtual + * interfaces. We can only add this interface when the rival + * interface count is 0. */ - if (!test_bit(DRIVER_SUPPORT_MIXED_INTERFACES, &rt2x00dev->flags) && - ((conf->type == IEEE80211_IF_TYPE_AP && rt2x00dev->intf_sta_count) || - (conf->type != IEEE80211_IF_TYPE_AP && rt2x00dev->intf_ap_count))) + if ((conf->type == IEEE80211_IF_TYPE_AP && rt2x00dev->intf_sta_count) || + (conf->type != IEEE80211_IF_TYPE_AP && rt2x00dev->intf_ap_count)) return -ENOBUFS; /* @@ -343,7 +361,8 @@ int rt2x00mac_config_interface(struct ieee80211_hw *hw, { struct rt2x00_dev *rt2x00dev = hw->priv; struct rt2x00_intf *intf = vif_to_intf(vif); - int status; + int update_bssid = 0; + int status = 0; /* * Mac80211 might be calling this function while we are trying @@ -355,12 +374,13 @@ int rt2x00mac_config_interface(struct ieee80211_hw *hw, spin_lock(&intf->lock); /* - * If the interface does not work in master mode, - * then the bssid value in the interface structure - * should now be set. + * conf->bssid can be NULL if coming from the internal + * beacon update routine. */ - if (conf->type != IEEE80211_IF_TYPE_AP) + if (conf->changed & IEEE80211_IFCC_BSSID && conf->bssid) { + update_bssid = 1; memcpy(&intf->bssid, conf->bssid, ETH_ALEN); + } spin_unlock(&intf->lock); @@ -370,19 +390,14 @@ int rt2x00mac_config_interface(struct ieee80211_hw *hw, * values as arguments we make keep access to rt2x00_intf thread safe * even without the lock. */ - rt2x00lib_config_intf(rt2x00dev, intf, conf->type, NULL, conf->bssid); + rt2x00lib_config_intf(rt2x00dev, intf, vif->type, NULL, + update_bssid ? conf->bssid : NULL); /* - * We only need to initialize the beacon when master mode is enabled. + * Update the beacon. */ - if (conf->type != IEEE80211_IF_TYPE_AP || !conf->beacon) - return 0; - - status = rt2x00dev->ops->hw->beacon_update(rt2x00dev->hw, - conf->beacon, - conf->beacon_control); - if (status) - dev_kfree_skb(conf->beacon); + if (conf->changed & IEEE80211_IFCC_BEACON) + status = rt2x00queue_update_beacon(rt2x00dev, vif); return status; } @@ -428,7 +443,7 @@ void rt2x00mac_configure_filter(struct ieee80211_hw *hw, if (!test_bit(DRIVER_REQUIRE_SCHEDULED, &rt2x00dev->flags)) rt2x00dev->ops->lib->config_filter(rt2x00dev, *total_flags); else - queue_work(rt2x00dev->workqueue, &rt2x00dev->filter_work); + queue_work(rt2x00dev->hw->workqueue, &rt2x00dev->filter_work); } EXPORT_SYMBOL_GPL(rt2x00mac_configure_filter); @@ -454,10 +469,10 @@ int rt2x00mac_get_tx_stats(struct ieee80211_hw *hw, struct rt2x00_dev *rt2x00dev = hw->priv; unsigned int i; - for (i = 0; i < hw->queues; i++) { - stats->data[i].len = rt2x00dev->tx[i].length; - stats->data[i].limit = rt2x00dev->tx[i].limit; - stats->data[i].count = rt2x00dev->tx[i].count; + for (i = 0; i < rt2x00dev->ops->tx_queues; i++) { + stats[i].len = rt2x00dev->tx[i].length; + stats[i].limit = rt2x00dev->tx[i].limit; + stats[i].count = rt2x00dev->tx[i].count; } return 0; @@ -498,7 +513,7 @@ void rt2x00mac_bss_info_changed(struct ieee80211_hw *hw, * When the erp information has changed, we should perform * additional configuration steps. For all other changes we are done. */ - if (changes & BSS_CHANGED_ERP_PREAMBLE) { + if (changes & (BSS_CHANGED_ERP_PREAMBLE | BSS_CHANGED_ERP_CTS_PROT)) { if (!test_bit(DRIVER_REQUIRE_SCHEDULED, &rt2x00dev->flags)) rt2x00lib_config_erp(rt2x00dev, intf, bss_conf); else @@ -509,13 +524,13 @@ void rt2x00mac_bss_info_changed(struct ieee80211_hw *hw, memcpy(&intf->conf, bss_conf, sizeof(*bss_conf)); if (delayed) { intf->delayed_flags |= delayed; - queue_work(rt2x00dev->workqueue, &rt2x00dev->intf_work); + schedule_work(&rt2x00dev->intf_work); } spin_unlock(&intf->lock); } EXPORT_SYMBOL_GPL(rt2x00mac_bss_info_changed); -int rt2x00mac_conf_tx(struct ieee80211_hw *hw, int queue_idx, +int rt2x00mac_conf_tx(struct ieee80211_hw *hw, u16 queue_idx, const struct ieee80211_tx_queue_params *params) { struct rt2x00_dev *rt2x00dev = hw->priv; @@ -539,10 +554,7 @@ int rt2x00mac_conf_tx(struct ieee80211_hw *hw, int queue_idx, else queue->cw_max = 10; /* cw_min: 2^10 = 1024. */ - if (params->aifs >= 0) - queue->aifs = params->aifs; - else - queue->aifs = 2; + queue->aifs = params->aifs; INFO(rt2x00dev, "Configured TX queue %d - CWmin: %d, CWmax: %d, Aifs: %d.\n", diff --git a/drivers/net/wireless/rt2x00/rt2x00pci.c b/drivers/net/wireless/rt2x00/rt2x00pci.c index 60893de3bf8f..adf2876ed8ab 100644 --- a/drivers/net/wireless/rt2x00/rt2x00pci.c +++ b/drivers/net/wireless/rt2x00/rt2x00pci.c @@ -34,44 +34,34 @@ /* * TX data handlers. */ -int rt2x00pci_write_tx_data(struct rt2x00_dev *rt2x00dev, - struct data_queue *queue, struct sk_buff *skb, - struct ieee80211_tx_control *control) +int rt2x00pci_write_tx_data(struct queue_entry *entry) { - struct queue_entry *entry = rt2x00queue_get_entry(queue, Q_INDEX); - struct queue_entry_priv_pci_tx *priv_tx = entry->priv_data; + struct queue_entry_priv_pci *entry_priv = entry->priv_data; struct skb_frame_desc *skbdesc; u32 word; - if (rt2x00queue_full(queue)) - return -EINVAL; - - rt2x00_desc_read(priv_tx->desc, 0, &word); + rt2x00_desc_read(entry_priv->desc, 0, &word); - if (rt2x00_get_field32(word, TXD_ENTRY_OWNER_NIC) || - rt2x00_get_field32(word, TXD_ENTRY_VALID)) { - ERROR(rt2x00dev, - "Arrived at non-free entry in the non-full queue %d.\n" + /* + * This should not happen, we already checked the entry + * was ours. When the hardware disagrees there has been + * a queue corruption! + */ + if (unlikely(rt2x00_get_field32(word, TXD_ENTRY_OWNER_NIC) || + rt2x00_get_field32(word, TXD_ENTRY_VALID))) { + ERROR(entry->queue->rt2x00dev, + "Corrupt queue %d, accessing entry which is not ours.\n" "Please file bug report to %s.\n", - control->queue, DRV_PROJECT); + entry->queue->qid, DRV_PROJECT); return -EINVAL; } /* * Fill in skb descriptor */ - skbdesc = get_skb_frame_desc(skb); - skbdesc->data = skb->data; - skbdesc->data_len = skb->len; - skbdesc->desc = priv_tx->desc; - skbdesc->desc_len = queue->desc_size; - skbdesc->entry = entry; - - memcpy(&priv_tx->control, control, sizeof(priv_tx->control)); - memcpy(priv_tx->data, skb->data, skb->len); - rt2x00lib_write_tx_desc(rt2x00dev, skb, control); - - rt2x00queue_index_inc(queue, Q_INDEX); + skbdesc = get_skb_frame_desc(entry->skb); + skbdesc->desc = entry_priv->desc; + skbdesc->desc_len = entry->queue->desc_size; return 0; } @@ -84,180 +74,62 @@ void rt2x00pci_rxdone(struct rt2x00_dev *rt2x00dev) { struct data_queue *queue = rt2x00dev->rx; struct queue_entry *entry; - struct queue_entry_priv_pci_rx *priv_rx; - struct ieee80211_hdr *hdr; + struct queue_entry_priv_pci *entry_priv; struct skb_frame_desc *skbdesc; - struct rxdone_entry_desc rxdesc; - int header_size; - int align; u32 word; while (1) { entry = rt2x00queue_get_entry(queue, Q_INDEX); - priv_rx = entry->priv_data; - rt2x00_desc_read(priv_rx->desc, 0, &word); + entry_priv = entry->priv_data; + rt2x00_desc_read(entry_priv->desc, 0, &word); if (rt2x00_get_field32(word, RXD_ENTRY_OWNER_NIC)) break; - memset(&rxdesc, 0, sizeof(rxdesc)); - rt2x00dev->ops->lib->fill_rxdone(entry, &rxdesc); - - hdr = (struct ieee80211_hdr *)priv_rx->data; - header_size = - ieee80211_get_hdrlen(le16_to_cpu(hdr->frame_control)); - /* - * The data behind the ieee80211 header must be - * aligned on a 4 byte boundary. - */ - align = header_size % 4; - - /* - * Allocate the sk_buffer, initialize it and copy - * all data into it. - */ - entry->skb = dev_alloc_skb(rxdesc.size + align); - if (!entry->skb) - return; - - skb_reserve(entry->skb, align); - memcpy(skb_put(entry->skb, rxdesc.size), - priv_rx->data, rxdesc.size); - - /* - * Fill in skb descriptor + * Fill in desc fields of the skb descriptor */ skbdesc = get_skb_frame_desc(entry->skb); - memset(skbdesc, 0, sizeof(*skbdesc)); - skbdesc->data = entry->skb->data; - skbdesc->data_len = entry->skb->len; - skbdesc->desc = priv_rx->desc; - skbdesc->desc_len = queue->desc_size; - skbdesc->entry = entry; + skbdesc->desc = entry_priv->desc; + skbdesc->desc_len = entry->queue->desc_size; /* * Send the frame to rt2x00lib for further processing. */ - rt2x00lib_rxdone(entry, &rxdesc); - - if (test_bit(DEVICE_ENABLED_RADIO, &queue->rt2x00dev->flags)) { - rt2x00_set_field32(&word, RXD_ENTRY_OWNER_NIC, 1); - rt2x00_desc_write(priv_rx->desc, 0, word); - } - - rt2x00queue_index_inc(queue, Q_INDEX); + rt2x00lib_rxdone(rt2x00dev, entry); } } EXPORT_SYMBOL_GPL(rt2x00pci_rxdone); -void rt2x00pci_txdone(struct rt2x00_dev *rt2x00dev, struct queue_entry *entry, - struct txdone_entry_desc *txdesc) -{ - struct queue_entry_priv_pci_tx *priv_tx = entry->priv_data; - u32 word; - - txdesc->control = &priv_tx->control; - rt2x00lib_txdone(entry, txdesc); - - /* - * Make this entry available for reuse. - */ - entry->flags = 0; - - rt2x00_desc_read(priv_tx->desc, 0, &word); - rt2x00_set_field32(&word, TXD_ENTRY_OWNER_NIC, 0); - rt2x00_set_field32(&word, TXD_ENTRY_VALID, 0); - rt2x00_desc_write(priv_tx->desc, 0, word); - - rt2x00queue_index_inc(entry->queue, Q_INDEX_DONE); - - /* - * If the data queue was full before the txdone handler - * we must make sure the packet queue in the mac80211 stack - * is reenabled when the txdone handler has finished. - */ - if (!rt2x00queue_full(entry->queue)) - ieee80211_wake_queue(rt2x00dev->hw, priv_tx->control.queue); - -} -EXPORT_SYMBOL_GPL(rt2x00pci_txdone); - /* * Device initialization handlers. */ -#define desc_size(__queue) \ -({ \ - ((__queue)->limit * (__queue)->desc_size);\ -}) - -#define data_size(__queue) \ -({ \ - ((__queue)->limit * (__queue)->data_size);\ -}) - -#define dma_size(__queue) \ -({ \ - data_size(__queue) + desc_size(__queue);\ -}) - -#define desc_offset(__queue, __base, __i) \ -({ \ - (__base) + data_size(__queue) + \ - ((__i) * (__queue)->desc_size); \ -}) - -#define data_offset(__queue, __base, __i) \ -({ \ - (__base) + \ - ((__i) * (__queue)->data_size); \ -}) - static int rt2x00pci_alloc_queue_dma(struct rt2x00_dev *rt2x00dev, struct data_queue *queue) { - struct pci_dev *pci_dev = rt2x00dev_pci(rt2x00dev); - struct queue_entry_priv_pci_rx *priv_rx; - struct queue_entry_priv_pci_tx *priv_tx; + struct queue_entry_priv_pci *entry_priv; void *addr; dma_addr_t dma; - void *desc_addr; - dma_addr_t desc_dma; - void *data_addr; - dma_addr_t data_dma; unsigned int i; /* * Allocate DMA memory for descriptor and buffer. */ - addr = pci_alloc_consistent(pci_dev, dma_size(queue), &dma); + addr = dma_alloc_coherent(rt2x00dev->dev, + queue->limit * queue->desc_size, + &dma, GFP_KERNEL | GFP_DMA); if (!addr) return -ENOMEM; - memset(addr, 0, dma_size(queue)); + memset(addr, 0, queue->limit * queue->desc_size); /* * Initialize all queue entries to contain valid addresses. */ for (i = 0; i < queue->limit; i++) { - desc_addr = desc_offset(queue, addr, i); - desc_dma = desc_offset(queue, dma, i); - data_addr = data_offset(queue, addr, i); - data_dma = data_offset(queue, dma, i); - - if (queue->qid == QID_RX) { - priv_rx = queue->entries[i].priv_data; - priv_rx->desc = desc_addr; - priv_rx->desc_dma = desc_dma; - priv_rx->data = data_addr; - priv_rx->data_dma = data_dma; - } else { - priv_tx = queue->entries[i].priv_data; - priv_tx->desc = desc_addr; - priv_tx->desc_dma = desc_dma; - priv_tx->data = data_addr; - priv_tx->data_dma = data_dma; - } + entry_priv = queue->entries[i].priv_data; + entry_priv->desc = addr + i * queue->desc_size; + entry_priv->desc_dma = dma + i * queue->desc_size; } return 0; @@ -266,34 +138,19 @@ static int rt2x00pci_alloc_queue_dma(struct rt2x00_dev *rt2x00dev, static void rt2x00pci_free_queue_dma(struct rt2x00_dev *rt2x00dev, struct data_queue *queue) { - struct pci_dev *pci_dev = rt2x00dev_pci(rt2x00dev); - struct queue_entry_priv_pci_rx *priv_rx; - struct queue_entry_priv_pci_tx *priv_tx; - void *data_addr; - dma_addr_t data_dma; - - if (queue->qid == QID_RX) { - priv_rx = queue->entries[0].priv_data; - data_addr = priv_rx->data; - data_dma = priv_rx->data_dma; - - priv_rx->data = NULL; - } else { - priv_tx = queue->entries[0].priv_data; - data_addr = priv_tx->data; - data_dma = priv_tx->data_dma; - - priv_tx->data = NULL; - } - - if (data_addr) - pci_free_consistent(pci_dev, dma_size(queue), - data_addr, data_dma); + struct queue_entry_priv_pci *entry_priv = + queue->entries[0].priv_data; + + if (entry_priv->desc) + dma_free_coherent(rt2x00dev->dev, + queue->limit * queue->desc_size, + entry_priv->desc, entry_priv->desc_dma); + entry_priv->desc = NULL; } int rt2x00pci_initialize(struct rt2x00_dev *rt2x00dev) { - struct pci_dev *pci_dev = rt2x00dev_pci(rt2x00dev); + struct pci_dev *pci_dev = to_pci_dev(rt2x00dev->dev); struct data_queue *queue; int status; @@ -334,7 +191,7 @@ void rt2x00pci_uninitialize(struct rt2x00_dev *rt2x00dev) /* * Free irq line. */ - free_irq(rt2x00dev_pci(rt2x00dev)->irq, rt2x00dev); + free_irq(to_pci_dev(rt2x00dev->dev)->irq, rt2x00dev); /* * Free DMA @@ -363,7 +220,7 @@ static void rt2x00pci_free_reg(struct rt2x00_dev *rt2x00dev) static int rt2x00pci_alloc_reg(struct rt2x00_dev *rt2x00dev) { - struct pci_dev *pci_dev = rt2x00dev_pci(rt2x00dev); + struct pci_dev *pci_dev = to_pci_dev(rt2x00dev->dev); rt2x00dev->csr.base = ioremap(pci_resource_start(pci_dev, 0), pci_resource_len(pci_dev, 0)); @@ -412,7 +269,7 @@ int rt2x00pci_probe(struct pci_dev *pci_dev, const struct pci_device_id *id) if (pci_set_mwi(pci_dev)) ERROR_PROBE("MWI not available.\n"); - if (pci_set_dma_mask(pci_dev, DMA_32BIT_MASK)) { + if (dma_set_mask(&pci_dev->dev, DMA_32BIT_MASK)) { ERROR_PROBE("PCI DMA not supported.\n"); retval = -EIO; goto exit_disable_device; @@ -428,7 +285,7 @@ int rt2x00pci_probe(struct pci_dev *pci_dev, const struct pci_device_id *id) pci_set_drvdata(pci_dev, hw); rt2x00dev = hw->priv; - rt2x00dev->dev = pci_dev; + rt2x00dev->dev = &pci_dev->dev; rt2x00dev->ops = ops; rt2x00dev->hw = hw; diff --git a/drivers/net/wireless/rt2x00/rt2x00pci.h b/drivers/net/wireless/rt2x00/rt2x00pci.h index b41967ecbf6d..80bf97c03e2d 100644 --- a/drivers/net/wireless/rt2x00/rt2x00pci.h +++ b/drivers/net/wireless/rt2x00/rt2x00pci.h @@ -87,44 +87,26 @@ rt2x00pci_register_multiwrite(struct rt2x00_dev *rt2x00dev, memcpy_toio(rt2x00dev->csr.base + offset, value, length); } -/* - * TX data handlers. - */ -int rt2x00pci_write_tx_data(struct rt2x00_dev *rt2x00dev, - struct data_queue *queue, struct sk_buff *skb, - struct ieee80211_tx_control *control); - /** - * struct queue_entry_priv_pci_rx: Per RX entry PCI specific information + * rt2x00pci_write_tx_data - Initialize data for TX operation + * @entry: The entry where the frame is located * - * @desc: Pointer to device descriptor. - * @data: Pointer to device's entry memory. - * @dma: DMA pointer to &data. + * This function will initialize the DMA and skb descriptor + * to prepare the entry for the actual TX operation. */ -struct queue_entry_priv_pci_rx { - __le32 *desc; - dma_addr_t desc_dma; - - void *data; - dma_addr_t data_dma; -}; +int rt2x00pci_write_tx_data(struct queue_entry *entry); /** - * struct queue_entry_priv_pci_tx: Per TX entry PCI specific information + * struct queue_entry_priv_pci: Per entry PCI specific information * * @desc: Pointer to device descriptor + * @desc_dma: DMA pointer to &desc. * @data: Pointer to device's entry memory. - * @dma: DMA pointer to &data. - * @control: mac80211 control structure used to transmit data. + * @data_dma: DMA pointer to &data. */ -struct queue_entry_priv_pci_tx { +struct queue_entry_priv_pci { __le32 *desc; dma_addr_t desc_dma; - - void *data; - dma_addr_t data_dma; - - struct ieee80211_tx_control control; }; /** @@ -133,15 +115,6 @@ struct queue_entry_priv_pci_tx { */ void rt2x00pci_rxdone(struct rt2x00_dev *rt2x00dev); -/** - * rt2x00pci_txdone - Handle TX done events - * @rt2x00dev: Device pointer, see &struct rt2x00_dev. - * @entry: Entry which has completed the transmission of a frame. - * @desc: TX done descriptor - */ -void rt2x00pci_txdone(struct rt2x00_dev *rt2x00dev, struct queue_entry *entry, - struct txdone_entry_desc *desc); - /* * Device initialization handlers. */ diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.c b/drivers/net/wireless/rt2x00/rt2x00queue.c index 659e9f44c40c..7f442030f5ad 100644 --- a/drivers/net/wireless/rt2x00/rt2x00queue.c +++ b/drivers/net/wireless/rt2x00/rt2x00queue.c @@ -25,24 +25,370 @@ #include <linux/kernel.h> #include <linux/module.h> +#include <linux/dma-mapping.h> #include "rt2x00.h" #include "rt2x00lib.h" +struct sk_buff *rt2x00queue_alloc_rxskb(struct rt2x00_dev *rt2x00dev, + struct queue_entry *entry) +{ + unsigned int frame_size; + unsigned int reserved_size; + struct sk_buff *skb; + struct skb_frame_desc *skbdesc; + + /* + * The frame size includes descriptor size, because the + * hardware directly receive the frame into the skbuffer. + */ + frame_size = entry->queue->data_size + entry->queue->desc_size; + + /* + * The payload should be aligned to a 4-byte boundary, + * this means we need at least 3 bytes for moving the frame + * into the correct offset. + */ + reserved_size = 4; + + /* + * Allocate skbuffer. + */ + skb = dev_alloc_skb(frame_size + reserved_size); + if (!skb) + return NULL; + + skb_reserve(skb, reserved_size); + skb_put(skb, frame_size); + + /* + * Populate skbdesc. + */ + skbdesc = get_skb_frame_desc(skb); + memset(skbdesc, 0, sizeof(*skbdesc)); + skbdesc->entry = entry; + + if (test_bit(DRIVER_REQUIRE_DMA, &rt2x00dev->flags)) { + skbdesc->skb_dma = dma_map_single(rt2x00dev->dev, + skb->data, + skb->len, + DMA_FROM_DEVICE); + skbdesc->flags |= SKBDESC_DMA_MAPPED_RX; + } + + return skb; +} + +void rt2x00queue_map_txskb(struct rt2x00_dev *rt2x00dev, struct sk_buff *skb) +{ + struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb); + + skbdesc->skb_dma = dma_map_single(rt2x00dev->dev, skb->data, skb->len, + DMA_TO_DEVICE); + skbdesc->flags |= SKBDESC_DMA_MAPPED_TX; +} +EXPORT_SYMBOL_GPL(rt2x00queue_map_txskb); + +void rt2x00queue_unmap_skb(struct rt2x00_dev *rt2x00dev, struct sk_buff *skb) +{ + struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb); + + if (skbdesc->flags & SKBDESC_DMA_MAPPED_RX) { + dma_unmap_single(rt2x00dev->dev, skbdesc->skb_dma, skb->len, + DMA_FROM_DEVICE); + skbdesc->flags &= ~SKBDESC_DMA_MAPPED_RX; + } + + if (skbdesc->flags & SKBDESC_DMA_MAPPED_TX) { + dma_unmap_single(rt2x00dev->dev, skbdesc->skb_dma, skb->len, + DMA_TO_DEVICE); + skbdesc->flags &= ~SKBDESC_DMA_MAPPED_TX; + } +} + +void rt2x00queue_free_skb(struct rt2x00_dev *rt2x00dev, struct sk_buff *skb) +{ + if (!skb) + return; + + rt2x00queue_unmap_skb(rt2x00dev, skb); + dev_kfree_skb_any(skb); +} + +static void rt2x00queue_create_tx_descriptor(struct queue_entry *entry, + struct txentry_desc *txdesc) +{ + struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev; + struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(entry->skb); + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)entry->skb->data; + struct ieee80211_rate *rate = + ieee80211_get_tx_rate(rt2x00dev->hw, tx_info); + const struct rt2x00_rate *hwrate; + unsigned int data_length; + unsigned int duration; + unsigned int residual; + + memset(txdesc, 0, sizeof(*txdesc)); + + /* + * Initialize information from queue + */ + txdesc->queue = entry->queue->qid; + txdesc->cw_min = entry->queue->cw_min; + txdesc->cw_max = entry->queue->cw_max; + txdesc->aifs = entry->queue->aifs; + + /* Data length should be extended with 4 bytes for CRC */ + data_length = entry->skb->len + 4; + + /* + * Check whether this frame is to be acked. + */ + if (!(tx_info->flags & IEEE80211_TX_CTL_NO_ACK)) + __set_bit(ENTRY_TXD_ACK, &txdesc->flags); + + /* + * Check if this is a RTS/CTS frame + */ + if (ieee80211_is_rts(hdr->frame_control) || + ieee80211_is_cts(hdr->frame_control)) { + __set_bit(ENTRY_TXD_BURST, &txdesc->flags); + if (ieee80211_is_rts(hdr->frame_control)) + __set_bit(ENTRY_TXD_RTS_FRAME, &txdesc->flags); + else + __set_bit(ENTRY_TXD_CTS_FRAME, &txdesc->flags); + if (tx_info->control.rts_cts_rate_idx >= 0) + rate = + ieee80211_get_rts_cts_rate(rt2x00dev->hw, tx_info); + } + + /* + * Determine retry information. + */ + txdesc->retry_limit = tx_info->control.retry_limit; + if (tx_info->flags & IEEE80211_TX_CTL_LONG_RETRY_LIMIT) + __set_bit(ENTRY_TXD_RETRY_MODE, &txdesc->flags); + + /* + * Check if more fragments are pending + */ + if (ieee80211_has_morefrags(hdr->frame_control)) { + __set_bit(ENTRY_TXD_BURST, &txdesc->flags); + __set_bit(ENTRY_TXD_MORE_FRAG, &txdesc->flags); + } + + /* + * Beacons and probe responses require the tsf timestamp + * to be inserted into the frame. + */ + if (ieee80211_is_beacon(hdr->frame_control) || + ieee80211_is_probe_resp(hdr->frame_control)) + __set_bit(ENTRY_TXD_REQ_TIMESTAMP, &txdesc->flags); + + /* + * Determine with what IFS priority this frame should be send. + * Set ifs to IFS_SIFS when the this is not the first fragment, + * or this fragment came after RTS/CTS. + */ + if (test_bit(ENTRY_TXD_RTS_FRAME, &txdesc->flags)) { + txdesc->ifs = IFS_SIFS; + } else if (tx_info->flags & IEEE80211_TX_CTL_FIRST_FRAGMENT) { + __set_bit(ENTRY_TXD_FIRST_FRAGMENT, &txdesc->flags); + txdesc->ifs = IFS_BACKOFF; + } else { + txdesc->ifs = IFS_SIFS; + } + + /* + * PLCP setup + * Length calculation depends on OFDM/CCK rate. + */ + hwrate = rt2x00_get_rate(rate->hw_value); + txdesc->signal = hwrate->plcp; + txdesc->service = 0x04; + + if (hwrate->flags & DEV_RATE_OFDM) { + __set_bit(ENTRY_TXD_OFDM_RATE, &txdesc->flags); + + txdesc->length_high = (data_length >> 6) & 0x3f; + txdesc->length_low = data_length & 0x3f; + } else { + /* + * Convert length to microseconds. + */ + residual = get_duration_res(data_length, hwrate->bitrate); + duration = get_duration(data_length, hwrate->bitrate); + + if (residual != 0) { + duration++; + + /* + * Check if we need to set the Length Extension + */ + if (hwrate->bitrate == 110 && residual <= 30) + txdesc->service |= 0x80; + } + + txdesc->length_high = (duration >> 8) & 0xff; + txdesc->length_low = duration & 0xff; + + /* + * When preamble is enabled we should set the + * preamble bit for the signal. + */ + if (rt2x00_get_rate_preamble(rate->hw_value)) + txdesc->signal |= 0x08; + } +} + +static void rt2x00queue_write_tx_descriptor(struct queue_entry *entry, + struct txentry_desc *txdesc) +{ + struct data_queue *queue = entry->queue; + struct rt2x00_dev *rt2x00dev = queue->rt2x00dev; + + rt2x00dev->ops->lib->write_tx_desc(rt2x00dev, entry->skb, txdesc); + + /* + * All processing on the frame has been completed, this means + * it is now ready to be dumped to userspace through debugfs. + */ + rt2x00debug_dump_frame(rt2x00dev, DUMP_FRAME_TX, entry->skb); + + /* + * Check if we need to kick the queue, there are however a few rules + * 1) Don't kick beacon queue + * 2) Don't kick unless this is the last in frame in a burst. + * When the burst flag is set, this frame is always followed + * by another frame which in some way are related to eachother. + * This is true for fragments, RTS or CTS-to-self frames. + * 3) Rule 2 can be broken when the available entries + * in the queue are less then a certain threshold. + */ + if (entry->queue->qid == QID_BEACON) + return; + + if (rt2x00queue_threshold(queue) || + !test_bit(ENTRY_TXD_BURST, &txdesc->flags)) + rt2x00dev->ops->lib->kick_tx_queue(rt2x00dev, queue->qid); +} + +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; + + if (unlikely(rt2x00queue_full(queue))) + return -EINVAL; + + if (__test_and_set_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags)) { + ERROR(queue->rt2x00dev, + "Arrived at non-free entry in the non-full queue %d.\n" + "Please file bug report to %s.\n", + queue->qid, DRV_PROJECT); + return -EINVAL; + } + + /* + * Copy all TX descriptor information into txdesc, + * after that we are free to use the skb->cb array + * for our information. + */ + entry->skb = skb; + rt2x00queue_create_tx_descriptor(entry, &txdesc); + + /* + * skb->cb array is now ours and we are free to use it. + */ + skbdesc = get_skb_frame_desc(entry->skb); + memset(skbdesc, 0, sizeof(*skbdesc)); + skbdesc->entry = entry; + + if (unlikely(queue->rt2x00dev->ops->lib->write_tx_data(entry))) { + __clear_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags); + return -EIO; + } + + if (test_bit(DRIVER_REQUIRE_DMA, &queue->rt2x00dev->flags)) + rt2x00queue_map_txskb(queue->rt2x00dev, skb); + + __set_bit(ENTRY_DATA_PENDING, &entry->flags); + + rt2x00queue_index_inc(queue, Q_INDEX); + rt2x00queue_write_tx_descriptor(entry, &txdesc); + + return 0; +} + +int rt2x00queue_update_beacon(struct rt2x00_dev *rt2x00dev, + struct ieee80211_vif *vif) +{ + struct rt2x00_intf *intf = vif_to_intf(vif); + struct skb_frame_desc *skbdesc; + struct txentry_desc txdesc; + __le32 desc[16]; + + if (unlikely(!intf->beacon)) + return -ENOBUFS; + + intf->beacon->skb = ieee80211_beacon_get(rt2x00dev->hw, vif); + if (!intf->beacon->skb) + return -ENOMEM; + + /* + * Copy all TX descriptor information into txdesc, + * after that we are free to use the skb->cb array + * for our information. + */ + rt2x00queue_create_tx_descriptor(intf->beacon, &txdesc); + + /* + * For the descriptor we use a local array from where the + * driver can move it to the correct location required for + * the hardware. + */ + memset(desc, 0, sizeof(desc)); + + /* + * Fill in skb descriptor + */ + skbdesc = get_skb_frame_desc(intf->beacon->skb); + memset(skbdesc, 0, sizeof(*skbdesc)); + skbdesc->desc = desc; + skbdesc->desc_len = intf->beacon->queue->desc_size; + skbdesc->entry = intf->beacon; + + /* + * Write TX descriptor into reserved room in front of the beacon. + */ + rt2x00queue_write_tx_descriptor(intf->beacon, &txdesc); + + /* + * Send beacon to hardware. + * Also enable beacon generation, which might have been disabled + * by the driver during the config_beacon() callback function. + */ + rt2x00dev->ops->lib->write_beacon(intf->beacon); + rt2x00dev->ops->lib->kick_tx_queue(rt2x00dev, QID_BEACON); + + return 0; +} + struct data_queue *rt2x00queue_get_queue(struct rt2x00_dev *rt2x00dev, - const unsigned int queue) + const enum data_queue_qid queue) { int atim = test_bit(DRIVER_REQUIRE_ATIM_QUEUE, &rt2x00dev->flags); - if (queue < rt2x00dev->hw->queues && rt2x00dev->tx) + if (queue < rt2x00dev->ops->tx_queues && rt2x00dev->tx) return &rt2x00dev->tx[queue]; if (!rt2x00dev->bcn) return NULL; - if (queue == RT2X00_BCN_QUEUE_BEACON) + if (queue == QID_BEACON) return &rt2x00dev->bcn[0]; - else if (queue == RT2X00_BCN_QUEUE_ATIM && atim) + else if (queue == QID_ATIM && atim) return &rt2x00dev->bcn[1]; return NULL; @@ -96,7 +442,6 @@ void rt2x00queue_index_inc(struct data_queue *queue, enum queue_index index) spin_unlock_irqrestore(&queue->lock, irqflags); } -EXPORT_SYMBOL_GPL(rt2x00queue_index_inc); static void rt2x00queue_reset(struct data_queue *queue) { @@ -153,6 +498,7 @@ static int rt2x00queue_alloc_entries(struct data_queue *queue, rt2x00queue_reset(queue); queue->limit = qdesc->entry_num; + queue->threshold = DIV_ROUND_UP(qdesc->entry_num, 10); queue->data_size = qdesc->data_size; queue->desc_size = qdesc->desc_size; @@ -185,12 +531,41 @@ static int rt2x00queue_alloc_entries(struct data_queue *queue, return 0; } +static void rt2x00queue_free_skbs(struct rt2x00_dev *rt2x00dev, + struct data_queue *queue) +{ + unsigned int i; + + if (!queue->entries) + return; + + for (i = 0; i < queue->limit; i++) { + if (queue->entries[i].skb) + rt2x00queue_free_skb(rt2x00dev, queue->entries[i].skb); + } +} + +static int rt2x00queue_alloc_rxskbs(struct rt2x00_dev *rt2x00dev, + struct data_queue *queue) +{ + unsigned int i; + struct sk_buff *skb; + + for (i = 0; i < queue->limit; i++) { + skb = rt2x00queue_alloc_rxskb(rt2x00dev, &queue->entries[i]); + if (!skb) + return -ENOMEM; + queue->entries[i].skb = skb; + } + + return 0; +} + int rt2x00queue_initialize(struct rt2x00_dev *rt2x00dev) { struct data_queue *queue; int status; - status = rt2x00queue_alloc_entries(rt2x00dev->rx, rt2x00dev->ops->rx); if (status) goto exit; @@ -205,11 +580,14 @@ int rt2x00queue_initialize(struct rt2x00_dev *rt2x00dev) if (status) goto exit; - if (!test_bit(DRIVER_REQUIRE_ATIM_QUEUE, &rt2x00dev->flags)) - return 0; + if (test_bit(DRIVER_REQUIRE_ATIM_QUEUE, &rt2x00dev->flags)) { + status = rt2x00queue_alloc_entries(&rt2x00dev->bcn[1], + rt2x00dev->ops->atim); + if (status) + goto exit; + } - status = rt2x00queue_alloc_entries(&rt2x00dev->bcn[1], - rt2x00dev->ops->atim); + status = rt2x00queue_alloc_rxskbs(rt2x00dev, rt2x00dev->rx); if (status) goto exit; @@ -227,6 +605,8 @@ void rt2x00queue_uninitialize(struct rt2x00_dev *rt2x00dev) { struct data_queue *queue; + rt2x00queue_free_skbs(rt2x00dev, rt2x00dev->rx); + queue_for_each(rt2x00dev, queue) { kfree(queue->entries); queue->entries = NULL; @@ -255,11 +635,11 @@ int rt2x00queue_allocate(struct rt2x00_dev *rt2x00dev) /* * We need the following queues: * RX: 1 - * TX: hw->queues + * TX: ops->tx_queues * Beacon: 1 * Atim: 1 (if required) */ - rt2x00dev->data_queues = 2 + rt2x00dev->hw->queues + req_atim; + rt2x00dev->data_queues = 2 + rt2x00dev->ops->tx_queues + req_atim; queue = kzalloc(rt2x00dev->data_queues * sizeof(*queue), GFP_KERNEL); if (!queue) { @@ -272,7 +652,7 @@ int rt2x00queue_allocate(struct rt2x00_dev *rt2x00dev) */ rt2x00dev->rx = queue; rt2x00dev->tx = &queue[1]; - rt2x00dev->bcn = &queue[1 + rt2x00dev->hw->queues]; + rt2x00dev->bcn = &queue[1 + rt2x00dev->ops->tx_queues]; /* * Initialize queue parameters. @@ -280,7 +660,8 @@ int rt2x00queue_allocate(struct rt2x00_dev *rt2x00dev) * TX: qid = QID_AC_BE + index * TX: cw_min: 2^5 = 32. * TX: cw_max: 2^10 = 1024. - * BCN & Atim: qid = QID_MGMT + * BCN: qid = QID_BEACON + * ATIM: qid = QID_ATIM */ rt2x00queue_init(rt2x00dev, rt2x00dev->rx, QID_RX); @@ -288,9 +669,9 @@ int rt2x00queue_allocate(struct rt2x00_dev *rt2x00dev) tx_queue_for_each(rt2x00dev, queue) rt2x00queue_init(rt2x00dev, queue, qid++); - rt2x00queue_init(rt2x00dev, &rt2x00dev->bcn[0], QID_MGMT); + rt2x00queue_init(rt2x00dev, &rt2x00dev->bcn[0], QID_BEACON); if (req_atim) - rt2x00queue_init(rt2x00dev, &rt2x00dev->bcn[1], QID_MGMT); + rt2x00queue_init(rt2x00dev, &rt2x00dev->bcn[1], QID_ATIM); return 0; } diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.h b/drivers/net/wireless/rt2x00/rt2x00queue.h index 7027c9f47d3f..8945945c892e 100644 --- a/drivers/net/wireless/rt2x00/rt2x00queue.h +++ b/drivers/net/wireless/rt2x00/rt2x00queue.h @@ -42,18 +42,32 @@ /** * DOC: Number of entries per queue * - * After research it was concluded that 12 entries in a RX and TX - * queue would be sufficient. Although this is almost one third of - * the amount the legacy driver allocated, the queues aren't getting - * filled to the maximum even when working with the maximum rate. + * Under normal load without fragmentation 12 entries are sufficient + * without the queue being filled up to the maximum. When using fragmentation + * and the queue threshold code we need to add some additional margins to + * make sure the queue will never (or only under extreme load) fill up + * completely. + * Since we don't use preallocated DMA having a large number of queue entries + * will have only minimal impact on the memory requirements for the queue. */ -#define RX_ENTRIES 12 -#define TX_ENTRIES 12 +#define RX_ENTRIES 24 +#define TX_ENTRIES 24 #define BEACON_ENTRIES 1 -#define ATIM_ENTRIES 1 +#define ATIM_ENTRIES 8 /** * enum data_queue_qid: Queue identification + * + * @QID_AC_BE: AC BE queue + * @QID_AC_BK: AC BK queue + * @QID_AC_VI: AC VI queue + * @QID_AC_VO: AC VO queue + * @QID_HCCA: HCCA queue + * @QID_MGMT: MGMT queue (prio queue) + * @QID_RX: RX queue + * @QID_OTHER: None of the above (don't use, only present for completeness) + * @QID_BEACON: Beacon queue (value unspecified, don't send it to device) + * @QID_ATIM: Atim queue (value unspeficied, don't send it to device) */ enum data_queue_qid { QID_AC_BE = 0, @@ -64,68 +78,55 @@ enum data_queue_qid { QID_MGMT = 13, QID_RX = 14, QID_OTHER = 15, -}; - -/** - * enum rt2x00_bcn_queue: Beacon queue index - * - * Start counting with a high offset, this because this enumeration - * supplements &enum ieee80211_tx_queue and we should prevent value - * conflicts. - * - * @RT2X00_BCN_QUEUE_BEACON: Beacon queue - * @RT2X00_BCN_QUEUE_ATIM: Atim queue (sends frame after beacon) - */ -enum rt2x00_bcn_queue { - RT2X00_BCN_QUEUE_BEACON = 100, - RT2X00_BCN_QUEUE_ATIM = 101, + QID_BEACON, + QID_ATIM, }; /** * enum skb_frame_desc_flags: Flags for &struct skb_frame_desc * - * @FRAME_DESC_DRIVER_GENERATED: Frame was generated inside driver - * and should not be reported back to mac80211 during txdone. + * @SKBDESC_DMA_MAPPED_RX: &skb_dma field has been mapped for RX + * @SKBDESC_DMA_MAPPED_TX: &skb_dma field has been mapped for TX */ enum skb_frame_desc_flags { - FRAME_DESC_DRIVER_GENERATED = 1 << 0, + SKBDESC_DMA_MAPPED_RX = (1 << 0), + SKBDESC_DMA_MAPPED_TX = (1 << 1), }; /** * struct skb_frame_desc: Descriptor information for the skb buffer * - * This structure is placed over the skb->cb array, this means that - * this structure should not exceed the size of that array (48 bytes). + * This structure is placed over the driver_data array, this means that + * this structure should not exceed the size of that array (40 bytes). * * @flags: Frame flags, see &enum skb_frame_desc_flags. - * @frame_type: Frame type, see &enum rt2x00_dump_type. - * @data: Pointer to data part of frame (Start of ieee80211 header). + * @desc_len: Length of the frame descriptor. * @desc: Pointer to descriptor part of the frame. * Note that this pointer could point to something outside * of the scope of the skb->data pointer. - * @data_len: Length of the frame data. - * @desc_len: Length of the frame descriptor. - + * @skb_dma: (PCI-only) the DMA address associated with the sk buffer. * @entry: The entry to which this sk buffer belongs. */ struct skb_frame_desc { unsigned int flags; - unsigned int frame_type; - - void *data; + unsigned int desc_len; void *desc; - unsigned int data_len; - unsigned int desc_len; + dma_addr_t skb_dma; struct queue_entry *entry; }; +/** + * get_skb_frame_desc - Obtain the rt2x00 frame descriptor from a sk_buff. + * @skb: &struct sk_buff from where we obtain the &struct skb_frame_desc + */ static inline struct skb_frame_desc* get_skb_frame_desc(struct sk_buff *skb) { - BUILD_BUG_ON(sizeof(struct skb_frame_desc) > sizeof(skb->cb)); - return (struct skb_frame_desc *)&skb->cb[0]; + BUILD_BUG_ON(sizeof(struct skb_frame_desc) > + IEEE80211_TX_INFO_DRIVER_DATA_SIZE); + return (struct skb_frame_desc *)&IEEE80211_SKB_CB(skb)->driver_data; } /** @@ -145,6 +146,7 @@ enum rxdone_entry_desc_flags { * * Summary of information that has been read from the RX frame descriptor. * + * @timestamp: RX Timestamp * @signal: Signal of the received frame. * @rssi: RSSI of the received frame. * @size: Data size of the received frame. @@ -153,6 +155,7 @@ enum rxdone_entry_desc_flags { */ struct rxdone_entry_desc { + u64 timestamp; int signal; int rssi; int size; @@ -161,18 +164,32 @@ struct rxdone_entry_desc { }; /** + * enum txdone_entry_desc_flags: Flags for &struct txdone_entry_desc + * + * @TXDONE_UNKNOWN: Hardware could not determine success of transmission. + * @TXDONE_SUCCESS: Frame was successfully send + * @TXDONE_FAILURE: Frame was not successfully send + * @TXDONE_EXCESSIVE_RETRY: In addition to &TXDONE_FAILURE, the + * frame transmission failed due to excessive retries. + */ +enum txdone_entry_desc_flags { + TXDONE_UNKNOWN = 1 << 0, + TXDONE_SUCCESS = 1 << 1, + TXDONE_FAILURE = 1 << 2, + TXDONE_EXCESSIVE_RETRY = 1 << 3, +}; + +/** * struct txdone_entry_desc: TX done entry descriptor * * Summary of information that has been read from the TX frame descriptor * after the device is done with transmission. * - * @control: Control structure which was used to transmit the frame. - * @status: TX status (See &enum tx_status). + * @flags: TX done flags (See &enum txdone_entry_desc_flags). * @retry: Retry count. */ struct txdone_entry_desc { - struct ieee80211_tx_control *control; - int status; + unsigned long flags; int retry; }; @@ -180,19 +197,25 @@ struct txdone_entry_desc { * enum txentry_desc_flags: Status flags for TX entry descriptor * * @ENTRY_TXD_RTS_FRAME: This frame is a RTS frame. + * @ENTRY_TXD_CTS_FRAME: This frame is a CTS-to-self frame. * @ENTRY_TXD_OFDM_RATE: This frame is send out with an OFDM rate. + * @ENTRY_TXD_FIRST_FRAGMENT: This is the first frame. * @ENTRY_TXD_MORE_FRAG: This frame is followed by another fragment. * @ENTRY_TXD_REQ_TIMESTAMP: Require timestamp to be inserted. * @ENTRY_TXD_BURST: This frame belongs to the same burst event. * @ENTRY_TXD_ACK: An ACK is required for this frame. + * @ENTRY_TXD_RETRY_MODE: When set, the long retry count is used. */ enum txentry_desc_flags { ENTRY_TXD_RTS_FRAME, + ENTRY_TXD_CTS_FRAME, ENTRY_TXD_OFDM_RATE, + ENTRY_TXD_FIRST_FRAGMENT, ENTRY_TXD_MORE_FRAG, ENTRY_TXD_REQ_TIMESTAMP, ENTRY_TXD_BURST, ENTRY_TXD_ACK, + ENTRY_TXD_RETRY_MODE, }; /** @@ -206,6 +229,7 @@ enum txentry_desc_flags { * @length_low: PLCP length low word. * @signal: PLCP signal. * @service: PLCP service. + * @retry_limit: Max number of retries. * @aifs: AIFS value. * @ifs: IFS value. * @cw_min: cwmin value. @@ -221,10 +245,11 @@ struct txentry_desc { u16 signal; u16 service; - int aifs; - int ifs; - int cw_min; - int cw_max; + short retry_limit; + short aifs; + short ifs; + short cw_min; + short cw_max; }; /** @@ -239,12 +264,14 @@ struct txentry_desc { * @ENTRY_OWNER_DEVICE_CRYPTO: This entry is owned by the device for data * encryption or decryption. The entry should only be touched after * the device has signaled it is done with it. + * @ENTRY_DATA_PENDING: This entry contains a valid frame and is waiting + * for the signal to start sending. */ - enum queue_entry_flags { ENTRY_BCN_ASSIGNED, ENTRY_OWNER_DEVICE_DATA, ENTRY_OWNER_DEVICE_CRYPTO, + ENTRY_DATA_PENDING, }; /** @@ -302,6 +329,7 @@ enum queue_index { * index corruption due to concurrency. * @count: Number of frames handled in the queue. * @limit: Maximum number of entries in the queue. + * @threshold: Minimum number of free entries before queue is kicked by force. * @length: Number of frames in queue. * @index: Index pointers to entry positions in the queue, * use &enum queue_index to get a specific index field. @@ -320,6 +348,7 @@ struct data_queue { spinlock_t lock; unsigned int count; unsigned short limit; + unsigned short threshold; unsigned short length; unsigned short index[Q_INDEX_MAX]; @@ -369,7 +398,7 @@ struct data_queue_desc { * the end of the TX queue array. */ #define tx_queue_end(__dev) \ - &(__dev)->tx[(__dev)->hw->queues] + &(__dev)->tx[(__dev)->ops->tx_queues] /** * queue_loop - Loop through the queues within a specific range (HELPER MACRO). @@ -444,6 +473,15 @@ static inline int rt2x00queue_available(struct data_queue *queue) } /** + * rt2x00queue_threshold - Check if the queue is below threshold + * @queue: Queue to check. + */ +static inline int rt2x00queue_threshold(struct data_queue *queue) +{ + return rt2x00queue_available(queue) < queue->threshold; +} + +/** * rt2x00_desc_read - Read a word from the hardware descriptor. * @desc: Base descriptor address * @word: Word index from where the descriptor should be read. diff --git a/drivers/net/wireless/rt2x00/rt2x00reg.h b/drivers/net/wireless/rt2x00/rt2x00reg.h index 0325bed2fbf5..7e88ce5651b9 100644 --- a/drivers/net/wireless/rt2x00/rt2x00reg.h +++ b/drivers/net/wireless/rt2x00/rt2x00reg.h @@ -27,17 +27,6 @@ #define RT2X00REG_H /* - * TX result flags. - */ -enum tx_status { - TX_SUCCESS = 0, - TX_SUCCESS_RETRY = 1, - TX_FAIL_RETRY = 2, - TX_FAIL_INVALID = 3, - TX_FAIL_OTHER = 4, -}; - -/* * Antenna values */ enum antenna { @@ -141,83 +130,107 @@ struct rt2x00_field32 { /* * Power of two check, this will check - * if the mask that has been given contains - * and contiguous set of bits. + * if the mask that has been given contains and contiguous set of bits. + * Note that we cannot use the is_power_of_2() function since this + * check must be done at compile-time. */ #define is_power_of_two(x) ( !((x) & ((x)-1)) ) #define low_bit_mask(x) ( ((x)-1) & ~(x) ) #define is_valid_mask(x) is_power_of_two(1 + (x) + low_bit_mask(x)) +/* + * Macro's to find first set bit in a variable. + * These macro's behaves the same as the __ffs() function with + * the most important difference that this is done during + * compile-time rather then run-time. + */ +#define compile_ffs2(__x) \ + __builtin_choose_expr(((__x) & 0x1), 0, 1) + +#define compile_ffs4(__x) \ + __builtin_choose_expr(((__x) & 0x3), \ + (compile_ffs2((__x))), \ + (compile_ffs2((__x) >> 2) + 2)) + +#define compile_ffs8(__x) \ + __builtin_choose_expr(((__x) & 0xf), \ + (compile_ffs4((__x))), \ + (compile_ffs4((__x) >> 4) + 4)) + +#define compile_ffs16(__x) \ + __builtin_choose_expr(((__x) & 0xff), \ + (compile_ffs8((__x))), \ + (compile_ffs8((__x) >> 8) + 8)) + +#define compile_ffs32(__x) \ + __builtin_choose_expr(((__x) & 0xffff), \ + (compile_ffs16((__x))), \ + (compile_ffs16((__x) >> 16) + 16)) + +/* + * This macro will check the requirements for the FIELD{8,16,32} macros + * The mask should be a constant non-zero contiguous set of bits which + * does not exceed the given typelimit. + */ +#define FIELD_CHECK(__mask, __type) \ + BUILD_BUG_ON(!__builtin_constant_p(__mask) || \ + !(__mask) || \ + !is_valid_mask(__mask) || \ + (__mask) != (__type)(__mask)) \ + #define FIELD8(__mask) \ ({ \ - BUILD_BUG_ON(!(__mask) || \ - !is_valid_mask(__mask) || \ - (__mask) != (u8)(__mask)); \ + FIELD_CHECK(__mask, u8); \ (struct rt2x00_field8) { \ - __ffs(__mask), (__mask) \ + compile_ffs8(__mask), (__mask) \ }; \ }) #define FIELD16(__mask) \ ({ \ - BUILD_BUG_ON(!(__mask) || \ - !is_valid_mask(__mask) || \ - (__mask) != (u16)(__mask));\ + FIELD_CHECK(__mask, u16); \ (struct rt2x00_field16) { \ - __ffs(__mask), (__mask) \ + compile_ffs16(__mask), (__mask) \ }; \ }) #define FIELD32(__mask) \ ({ \ - BUILD_BUG_ON(!(__mask) || \ - !is_valid_mask(__mask) || \ - (__mask) != (u32)(__mask));\ + FIELD_CHECK(__mask, u32); \ (struct rt2x00_field32) { \ - __ffs(__mask), (__mask) \ + compile_ffs32(__mask), (__mask) \ }; \ }) -static inline void rt2x00_set_field32(u32 *reg, - const struct rt2x00_field32 field, - const u32 value) -{ - *reg &= ~(field.bit_mask); - *reg |= (value << field.bit_offset) & field.bit_mask; -} - -static inline u32 rt2x00_get_field32(const u32 reg, - const struct rt2x00_field32 field) -{ - return (reg & field.bit_mask) >> field.bit_offset; -} - -static inline void rt2x00_set_field16(u16 *reg, - const struct rt2x00_field16 field, - const u16 value) -{ - *reg &= ~(field.bit_mask); - *reg |= (value << field.bit_offset) & field.bit_mask; -} - -static inline u16 rt2x00_get_field16(const u16 reg, - const struct rt2x00_field16 field) -{ - return (reg & field.bit_mask) >> field.bit_offset; -} - -static inline void rt2x00_set_field8(u8 *reg, - const struct rt2x00_field8 field, - const u8 value) -{ - *reg &= ~(field.bit_mask); - *reg |= (value << field.bit_offset) & field.bit_mask; -} - -static inline u8 rt2x00_get_field8(const u8 reg, - const struct rt2x00_field8 field) -{ - return (reg & field.bit_mask) >> field.bit_offset; -} +#define SET_FIELD(__reg, __type, __field, __value)\ +({ \ + typecheck(__type, __field); \ + *(__reg) &= ~((__field).bit_mask); \ + *(__reg) |= ((__value) << \ + ((__field).bit_offset)) & \ + ((__field).bit_mask); \ +}) + +#define GET_FIELD(__reg, __type, __field) \ +({ \ + typecheck(__type, __field); \ + ((__reg) & ((__field).bit_mask)) >> \ + ((__field).bit_offset); \ +}) + +#define rt2x00_set_field32(__reg, __field, __value) \ + SET_FIELD(__reg, struct rt2x00_field32, __field, __value) +#define rt2x00_get_field32(__reg, __field) \ + GET_FIELD(__reg, struct rt2x00_field32, __field) + +#define rt2x00_set_field16(__reg, __field, __value) \ + SET_FIELD(__reg, struct rt2x00_field16, __field, __value) +#define rt2x00_get_field16(__reg, __field) \ + GET_FIELD(__reg, struct rt2x00_field16, __field) + +#define rt2x00_set_field8(__reg, __field, __value) \ + SET_FIELD(__reg, struct rt2x00_field8, __field, __value) +#define rt2x00_get_field8(__reg, __field) \ + GET_FIELD(__reg, struct rt2x00_field8, __field) #endif /* RT2X00REG_H */ diff --git a/drivers/net/wireless/rt2x00/rt2x00rfkill.c b/drivers/net/wireless/rt2x00/rt2x00rfkill.c index fcef9885ab5e..04b29716d356 100644 --- a/drivers/net/wireless/rt2x00/rt2x00rfkill.c +++ b/drivers/net/wireless/rt2x00/rt2x00rfkill.c @@ -23,7 +23,6 @@ Abstract: rt2x00 rfkill routines. */ -#include <linux/input-polldev.h> #include <linux/kernel.h> #include <linux/module.h> #include <linux/rfkill.h> @@ -45,28 +44,51 @@ static int rt2x00rfkill_toggle_radio(void *data, enum rfkill_state state) if (!test_bit(DEVICE_STARTED, &rt2x00dev->flags)) return 0; - if (state == RFKILL_STATE_ON) { + if (state == RFKILL_STATE_UNBLOCKED) { INFO(rt2x00dev, "Hardware button pressed, enabling radio.\n"); __clear_bit(DEVICE_DISABLED_RADIO_HW, &rt2x00dev->flags); retval = rt2x00lib_enable_radio(rt2x00dev); - } else if (state == RFKILL_STATE_OFF) { + } else if (state == RFKILL_STATE_SOFT_BLOCKED) { INFO(rt2x00dev, "Hardware button pressed, disabling radio.\n"); __set_bit(DEVICE_DISABLED_RADIO_HW, &rt2x00dev->flags); rt2x00lib_disable_radio(rt2x00dev); + } else { + WARNING(rt2x00dev, "Received unexpected rfkill state %d.\n", + state); } return retval; } -static void rt2x00rfkill_poll(struct input_polled_dev *poll_dev) +static int rt2x00rfkill_get_state(void *data, enum rfkill_state *state) { - struct rt2x00_dev *rt2x00dev = poll_dev->private; - int state = rt2x00dev->ops->lib->rfkill_poll(rt2x00dev); + struct rt2x00_dev *rt2x00dev = data; - if (rt2x00dev->rfkill->state != state) { - input_report_key(poll_dev->input, KEY_WLAN, 1); - input_report_key(poll_dev->input, KEY_WLAN, 0); - } + *state = rt2x00dev->rfkill->state; + + return 0; +} + +static void rt2x00rfkill_poll(struct work_struct *work) +{ + struct rt2x00_dev *rt2x00dev = + container_of(work, struct rt2x00_dev, rfkill_work.work); + int state; + + if (!test_bit(RFKILL_STATE_REGISTERED, &rt2x00dev->rfkill_state)) + return; + + /* + * rfkill_poll reports 1 when the key has been pressed and the + * radio should be blocked. + */ + state = !rt2x00dev->ops->lib->rfkill_poll(rt2x00dev) ? + RFKILL_STATE_UNBLOCKED : RFKILL_STATE_SOFT_BLOCKED; + + rfkill_force_state(rt2x00dev->rfkill, state); + + queue_delayed_work(rt2x00dev->hw->workqueue, + &rt2x00dev->rfkill_work, RFKILL_POLL_INTERVAL); } void rt2x00rfkill_register(struct rt2x00_dev *rt2x00dev) @@ -80,12 +102,6 @@ void rt2x00rfkill_register(struct rt2x00_dev *rt2x00dev) return; } - if (input_register_polled_device(rt2x00dev->poll_dev)) { - ERROR(rt2x00dev, "Failed to register polled device.\n"); - rfkill_unregister(rt2x00dev->rfkill); - return; - } - __set_bit(RFKILL_STATE_REGISTERED, &rt2x00dev->rfkill_state); /* @@ -93,7 +109,7 @@ void rt2x00rfkill_register(struct rt2x00_dev *rt2x00dev) * and correctly sends the signal to the rfkill layer about this * state. */ - rt2x00rfkill_poll(rt2x00dev->poll_dev); + rt2x00rfkill_poll(&rt2x00dev->rfkill_work.work); } void rt2x00rfkill_unregister(struct rt2x00_dev *rt2x00dev) @@ -102,38 +118,13 @@ void rt2x00rfkill_unregister(struct rt2x00_dev *rt2x00dev) !test_bit(RFKILL_STATE_REGISTERED, &rt2x00dev->rfkill_state)) return; - input_unregister_polled_device(rt2x00dev->poll_dev); + cancel_delayed_work_sync(&rt2x00dev->rfkill_work); + rfkill_unregister(rt2x00dev->rfkill); __clear_bit(RFKILL_STATE_REGISTERED, &rt2x00dev->rfkill_state); } -static struct input_polled_dev * -rt2x00rfkill_allocate_polldev(struct rt2x00_dev *rt2x00dev) -{ - struct input_polled_dev *poll_dev; - - poll_dev = input_allocate_polled_device(); - if (!poll_dev) - return NULL; - - poll_dev->private = rt2x00dev; - poll_dev->poll = rt2x00rfkill_poll; - poll_dev->poll_interval = RFKILL_POLL_INTERVAL; - - poll_dev->input->name = rt2x00dev->ops->name; - poll_dev->input->phys = wiphy_name(rt2x00dev->hw->wiphy); - poll_dev->input->id.bustype = BUS_HOST; - poll_dev->input->id.vendor = 0x1814; - poll_dev->input->id.product = rt2x00dev->chip.rt; - poll_dev->input->id.version = rt2x00dev->chip.rev; - poll_dev->input->dev.parent = wiphy_dev(rt2x00dev->hw->wiphy); - poll_dev->input->evbit[0] = BIT(EV_KEY); - set_bit(KEY_WLAN, poll_dev->input->keybit); - - return poll_dev; -} - void rt2x00rfkill_allocate(struct rt2x00_dev *rt2x00dev) { if (!test_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags)) @@ -150,14 +141,9 @@ void rt2x00rfkill_allocate(struct rt2x00_dev *rt2x00dev) rt2x00dev->rfkill->data = rt2x00dev; rt2x00dev->rfkill->state = -1; rt2x00dev->rfkill->toggle_radio = rt2x00rfkill_toggle_radio; + rt2x00dev->rfkill->get_state = rt2x00rfkill_get_state; - rt2x00dev->poll_dev = rt2x00rfkill_allocate_polldev(rt2x00dev); - if (!rt2x00dev->poll_dev) { - ERROR(rt2x00dev, "Failed to allocate polled device.\n"); - rfkill_free(rt2x00dev->rfkill); - rt2x00dev->rfkill = NULL; - return; - } + INIT_DELAYED_WORK(&rt2x00dev->rfkill_work, rt2x00rfkill_poll); return; } @@ -168,32 +154,8 @@ void rt2x00rfkill_free(struct rt2x00_dev *rt2x00dev) !test_bit(RFKILL_STATE_ALLOCATED, &rt2x00dev->rfkill_state)) return; - input_free_polled_device(rt2x00dev->poll_dev); - rt2x00dev->poll_dev = NULL; + cancel_delayed_work_sync(&rt2x00dev->rfkill_work); rfkill_free(rt2x00dev->rfkill); rt2x00dev->rfkill = NULL; } - -void rt2x00rfkill_suspend(struct rt2x00_dev *rt2x00dev) -{ - if (!test_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags) || - !test_bit(RFKILL_STATE_ALLOCATED, &rt2x00dev->rfkill_state)) - return; - - input_free_polled_device(rt2x00dev->poll_dev); - rt2x00dev->poll_dev = NULL; -} - -void rt2x00rfkill_resume(struct rt2x00_dev *rt2x00dev) -{ - if (!test_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags) || - !test_bit(RFKILL_STATE_ALLOCATED, &rt2x00dev->rfkill_state)) - return; - - rt2x00dev->poll_dev = rt2x00rfkill_allocate_polldev(rt2x00dev); - if (!rt2x00dev->poll_dev) { - ERROR(rt2x00dev, "Failed to allocate polled device.\n"); - return; - } -} diff --git a/drivers/net/wireless/rt2x00/rt2x00usb.c b/drivers/net/wireless/rt2x00/rt2x00usb.c index e5ceae805b57..83862e7f7aec 100644 --- a/drivers/net/wireless/rt2x00/rt2x00usb.c +++ b/drivers/net/wireless/rt2x00/rt2x00usb.c @@ -40,7 +40,7 @@ int rt2x00usb_vendor_request(struct rt2x00_dev *rt2x00dev, void *buffer, const u16 buffer_length, const int timeout) { - struct usb_device *usb_dev = rt2x00dev_usb_dev(rt2x00dev); + struct usb_device *usb_dev = to_usb_device_intf(rt2x00dev->dev); int status; unsigned int i; unsigned int pipe = @@ -129,17 +129,12 @@ static void rt2x00usb_interrupt_txdone(struct urb *urb) { struct queue_entry *entry = (struct queue_entry *)urb->context; struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev; - struct queue_entry_priv_usb_tx *priv_tx = entry->priv_data; struct txdone_entry_desc txdesc; - __le32 *txd = (__le32 *)entry->skb->data; - u32 word; if (!test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags) || - !__test_and_clear_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags)) + !test_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags)) return; - rt2x00_desc_read(txd, 0, &word); - /* * Remove the descriptor data from the buffer. */ @@ -147,128 +142,116 @@ static void rt2x00usb_interrupt_txdone(struct urb *urb) /* * Obtain the status about this packet. + * Note that when the status is 0 it does not mean the + * frame was send out correctly. It only means the frame + * was succesfully pushed to the hardware, we have no + * way to determine the transmission status right now. + * (Only indirectly by looking at the failed TX counters + * in the register). */ - txdesc.status = !urb->status ? TX_SUCCESS : TX_FAIL_RETRY; + if (!urb->status) + __set_bit(TXDONE_UNKNOWN, &txdesc.flags); + else + __set_bit(TXDONE_FAILURE, &txdesc.flags); txdesc.retry = 0; - txdesc.control = &priv_tx->control; rt2x00lib_txdone(entry, &txdesc); - - /* - * Make this entry available for reuse. - */ - entry->flags = 0; - rt2x00queue_index_inc(entry->queue, Q_INDEX_DONE); - - /* - * If the data queue was full before the txdone handler - * we must make sure the packet queue in the mac80211 stack - * is reenabled when the txdone handler has finished. - */ - if (!rt2x00queue_full(entry->queue)) - ieee80211_wake_queue(rt2x00dev->hw, priv_tx->control.queue); } -int rt2x00usb_write_tx_data(struct rt2x00_dev *rt2x00dev, - struct data_queue *queue, struct sk_buff *skb, - struct ieee80211_tx_control *control) +int rt2x00usb_write_tx_data(struct queue_entry *entry) { - struct usb_device *usb_dev = rt2x00dev_usb_dev(rt2x00dev); - struct queue_entry *entry = rt2x00queue_get_entry(queue, Q_INDEX); - struct queue_entry_priv_usb_tx *priv_tx = entry->priv_data; + struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev; + struct usb_device *usb_dev = to_usb_device_intf(rt2x00dev->dev); + struct queue_entry_priv_usb *entry_priv = entry->priv_data; struct skb_frame_desc *skbdesc; u32 length; - if (rt2x00queue_full(queue)) - return -EINVAL; - - if (test_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags)) { - ERROR(rt2x00dev, - "Arrived at non-free entry in the non-full queue %d.\n" - "Please file bug report to %s.\n", - control->queue, DRV_PROJECT); - return -EINVAL; - } - /* * Add the descriptor in front of the skb. */ - skb_push(skb, queue->desc_size); - memset(skb->data, 0, queue->desc_size); + skb_push(entry->skb, entry->queue->desc_size); + memset(entry->skb->data, 0, entry->queue->desc_size); /* * Fill in skb descriptor */ - skbdesc = get_skb_frame_desc(skb); - skbdesc->data = skb->data + queue->desc_size; - skbdesc->data_len = skb->len - queue->desc_size; - skbdesc->desc = skb->data; - skbdesc->desc_len = queue->desc_size; - skbdesc->entry = entry; - - memcpy(&priv_tx->control, control, sizeof(priv_tx->control)); - rt2x00lib_write_tx_desc(rt2x00dev, skb, control); + skbdesc = get_skb_frame_desc(entry->skb); + skbdesc->desc = entry->skb->data; + skbdesc->desc_len = entry->queue->desc_size; /* * USB devices cannot blindly pass the skb->len as the * length of the data to usb_fill_bulk_urb. Pass the skb * to the driver to determine what the length should be. */ - length = rt2x00dev->ops->lib->get_tx_data_len(rt2x00dev, skb); - - /* - * Initialize URB and send the frame to the device. - */ - __set_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags); - usb_fill_bulk_urb(priv_tx->urb, usb_dev, usb_sndbulkpipe(usb_dev, 1), - skb->data, length, rt2x00usb_interrupt_txdone, entry); - usb_submit_urb(priv_tx->urb, GFP_ATOMIC); + length = rt2x00dev->ops->lib->get_tx_data_len(rt2x00dev, entry->skb); - rt2x00queue_index_inc(queue, Q_INDEX); + usb_fill_bulk_urb(entry_priv->urb, usb_dev, + usb_sndbulkpipe(usb_dev, 1), + entry->skb->data, length, + rt2x00usb_interrupt_txdone, entry); return 0; } EXPORT_SYMBOL_GPL(rt2x00usb_write_tx_data); -/* - * RX data handlers. - */ -static struct sk_buff* rt2x00usb_alloc_rxskb(struct data_queue *queue) +static inline void rt2x00usb_kick_tx_entry(struct queue_entry *entry) { - struct sk_buff *skb; - unsigned int frame_size; + struct queue_entry_priv_usb *entry_priv = entry->priv_data; + + if (__test_and_clear_bit(ENTRY_DATA_PENDING, &entry->flags)) + usb_submit_urb(entry_priv->urb, GFP_ATOMIC); +} + +void rt2x00usb_kick_tx_queue(struct rt2x00_dev *rt2x00dev, + const enum data_queue_qid qid) +{ + struct data_queue *queue = rt2x00queue_get_queue(rt2x00dev, qid); + unsigned long irqflags; + unsigned int index; + unsigned int index_done; + unsigned int i; /* - * As alignment we use 2 and not NET_IP_ALIGN because we need - * to be sure we have 2 bytes room in the head. (NET_IP_ALIGN - * can be 0 on some hardware). We use these 2 bytes for frame - * alignment later, we assume that the chance that - * header_size % 4 == 2 is bigger then header_size % 2 == 0 - * and thus optimize alignment by reserving the 2 bytes in - * advance. + * Only protect the range we are going to loop over, + * if during our loop a extra entry is set to pending + * it should not be kicked during this run, since it + * is part of another TX operation. */ - frame_size = queue->data_size + queue->desc_size; - skb = dev_alloc_skb(queue->desc_size + frame_size + 2); - if (!skb) - return NULL; - - skb_reserve(skb, queue->desc_size + 2); - skb_put(skb, frame_size); + spin_lock_irqsave(&queue->lock, irqflags); + index = queue->index[Q_INDEX]; + index_done = queue->index[Q_INDEX_DONE]; + spin_unlock_irqrestore(&queue->lock, irqflags); - return skb; + /* + * Start from the TX done pointer, this guarentees that we will + * send out all frames in the correct order. + */ + if (index_done < index) { + for (i = index_done; i < index; i++) + rt2x00usb_kick_tx_entry(&queue->entries[i]); + } else { + for (i = index_done; i < queue->limit; i++) + rt2x00usb_kick_tx_entry(&queue->entries[i]); + + for (i = 0; i < index; i++) + rt2x00usb_kick_tx_entry(&queue->entries[i]); + } } +EXPORT_SYMBOL_GPL(rt2x00usb_kick_tx_queue); +/* + * RX data handlers. + */ static void rt2x00usb_interrupt_rxdone(struct urb *urb) { struct queue_entry *entry = (struct queue_entry *)urb->context; struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev; - struct sk_buff *skb; - struct skb_frame_desc *skbdesc; - struct rxdone_entry_desc rxdesc; - int header_size; + struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb); + u8 rxd[32]; if (!test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags) || - !test_and_clear_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags)) + !test_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags)) return; /* @@ -276,61 +259,22 @@ static void rt2x00usb_interrupt_rxdone(struct urb *urb) * to be actually valid, or if the urb is signaling * a problem. */ - if (urb->actual_length < entry->queue->desc_size || urb->status) - goto skip_entry; - - /* - * Fill in skb descriptor - */ - skbdesc = get_skb_frame_desc(entry->skb); - memset(skbdesc, 0, sizeof(*skbdesc)); - skbdesc->entry = entry; - - memset(&rxdesc, 0, sizeof(rxdesc)); - rt2x00dev->ops->lib->fill_rxdone(entry, &rxdesc); - - /* - * The data behind the ieee80211 header must be - * aligned on a 4 byte boundary. - */ - header_size = ieee80211_get_hdrlen_from_skb(entry->skb); - if (header_size % 4 == 0) { - skb_push(entry->skb, 2); - memmove(entry->skb->data, entry->skb->data + 2, - entry->skb->len - 2); - skbdesc->data = entry->skb->data; - skb_trim(entry->skb,entry->skb->len - 2); + if (urb->actual_length < entry->queue->desc_size || urb->status) { + __set_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags); + usb_submit_urb(urb, GFP_ATOMIC); + return; } /* - * Allocate a new sk buffer to replace the current one. - * If allocation fails, we should drop the current frame - * so we can recycle the existing sk buffer for the new frame. + * Fill in desc fields of the skb descriptor */ - skb = rt2x00usb_alloc_rxskb(entry->queue); - if (!skb) - goto skip_entry; + skbdesc->desc = rxd; + skbdesc->desc_len = entry->queue->desc_size; /* * Send the frame to rt2x00lib for further processing. */ - rt2x00lib_rxdone(entry, &rxdesc); - - /* - * Replace current entry's skb with the newly allocated one, - * and reinitialize the urb. - */ - entry->skb = skb; - urb->transfer_buffer = entry->skb->data; - urb->transfer_buffer_length = entry->skb->len; - -skip_entry: - if (test_bit(DEVICE_ENABLED_RADIO, &entry->queue->rt2x00dev->flags)) { - __set_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags); - usb_submit_urb(urb, GFP_ATOMIC); - } - - rt2x00queue_index_inc(entry->queue, Q_INDEX); + rt2x00lib_rxdone(rt2x00dev, entry); } /* @@ -338,27 +282,21 @@ skip_entry: */ void rt2x00usb_disable_radio(struct rt2x00_dev *rt2x00dev) { - struct queue_entry_priv_usb_rx *priv_rx; - struct queue_entry_priv_usb_tx *priv_tx; - struct queue_entry_priv_usb_bcn *priv_bcn; + struct queue_entry_priv_usb *entry_priv; + struct queue_entry_priv_usb_bcn *bcn_priv; struct data_queue *queue; unsigned int i; - rt2x00usb_vendor_request_sw(rt2x00dev, USB_RX_CONTROL, 0x0000, 0x0000, + rt2x00usb_vendor_request_sw(rt2x00dev, USB_RX_CONTROL, 0, 0, REGISTER_TIMEOUT); /* * Cancel all queues. */ - for (i = 0; i < rt2x00dev->rx->limit; i++) { - priv_rx = rt2x00dev->rx->entries[i].priv_data; - usb_kill_urb(priv_rx->urb); - } - - tx_queue_for_each(rt2x00dev, queue) { + queue_for_each(rt2x00dev, queue) { for (i = 0; i < queue->limit; i++) { - priv_tx = queue->entries[i].priv_data; - usb_kill_urb(priv_tx->urb); + entry_priv = queue->entries[i].priv_data; + usb_kill_urb(entry_priv->urb); } } @@ -369,19 +307,9 @@ void rt2x00usb_disable_radio(struct rt2x00_dev *rt2x00dev) return; for (i = 0; i < rt2x00dev->bcn->limit; i++) { - priv_bcn = rt2x00dev->bcn->entries[i].priv_data; - usb_kill_urb(priv_bcn->urb); - - if (priv_bcn->guardian_urb) - usb_kill_urb(priv_bcn->guardian_urb); - } - - if (!test_bit(DRIVER_REQUIRE_ATIM_QUEUE, &rt2x00dev->flags)) - return; - - for (i = 0; i < rt2x00dev->bcn[1].limit; i++) { - priv_tx = rt2x00dev->bcn[1].entries[i].priv_data; - usb_kill_urb(priv_tx->urb); + bcn_priv = rt2x00dev->bcn->entries[i].priv_data; + if (bcn_priv->guardian_urb) + usb_kill_urb(bcn_priv->guardian_urb); } } EXPORT_SYMBOL_GPL(rt2x00usb_disable_radio); @@ -392,16 +320,16 @@ EXPORT_SYMBOL_GPL(rt2x00usb_disable_radio); void rt2x00usb_init_rxentry(struct rt2x00_dev *rt2x00dev, struct queue_entry *entry) { - struct usb_device *usb_dev = rt2x00dev_usb_dev(rt2x00dev); - struct queue_entry_priv_usb_rx *priv_rx = entry->priv_data; + struct usb_device *usb_dev = to_usb_device_intf(rt2x00dev->dev); + struct queue_entry_priv_usb *entry_priv = entry->priv_data; - usb_fill_bulk_urb(priv_rx->urb, usb_dev, + usb_fill_bulk_urb(entry_priv->urb, usb_dev, usb_rcvbulkpipe(usb_dev, 1), entry->skb->data, entry->skb->len, rt2x00usb_interrupt_rxdone, entry); __set_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags); - usb_submit_urb(priv_rx->urb, GFP_ATOMIC); + usb_submit_urb(entry_priv->urb, GFP_ATOMIC); } EXPORT_SYMBOL_GPL(rt2x00usb_init_rxentry); @@ -415,38 +343,31 @@ EXPORT_SYMBOL_GPL(rt2x00usb_init_txentry); static int rt2x00usb_alloc_urb(struct rt2x00_dev *rt2x00dev, struct data_queue *queue) { - struct queue_entry_priv_usb_rx *priv_rx; - struct queue_entry_priv_usb_tx *priv_tx; - struct queue_entry_priv_usb_bcn *priv_bcn; - struct urb *urb; - unsigned int guardian = - test_bit(DRIVER_REQUIRE_BEACON_GUARD, &rt2x00dev->flags); + struct queue_entry_priv_usb *entry_priv; + struct queue_entry_priv_usb_bcn *bcn_priv; unsigned int i; + for (i = 0; i < queue->limit; i++) { + entry_priv = queue->entries[i].priv_data; + entry_priv->urb = usb_alloc_urb(0, GFP_KERNEL); + if (!entry_priv->urb) + return -ENOMEM; + } + /* - * Allocate the URB's + * If this is not the beacon queue or + * no guardian byte was required for the beacon, + * then we are done. */ + if (rt2x00dev->bcn != queue || + !test_bit(DRIVER_REQUIRE_BEACON_GUARD, &rt2x00dev->flags)) + return 0; + for (i = 0; i < queue->limit; i++) { - urb = usb_alloc_urb(0, GFP_KERNEL); - if (!urb) + bcn_priv = queue->entries[i].priv_data; + bcn_priv->guardian_urb = usb_alloc_urb(0, GFP_KERNEL); + if (!bcn_priv->guardian_urb) return -ENOMEM; - - if (queue->qid == QID_RX) { - priv_rx = queue->entries[i].priv_data; - priv_rx->urb = urb; - } else if (queue->qid == QID_MGMT && guardian) { - priv_bcn = queue->entries[i].priv_data; - priv_bcn->urb = urb; - - urb = usb_alloc_urb(0, GFP_KERNEL); - if (!urb) - return -ENOMEM; - - priv_bcn->guardian_urb = urb; - } else { - priv_tx = queue->entries[i].priv_data; - priv_tx->urb = urb; - } } return 0; @@ -455,47 +376,39 @@ static int rt2x00usb_alloc_urb(struct rt2x00_dev *rt2x00dev, static void rt2x00usb_free_urb(struct rt2x00_dev *rt2x00dev, struct data_queue *queue) { - struct queue_entry_priv_usb_rx *priv_rx; - struct queue_entry_priv_usb_tx *priv_tx; - struct queue_entry_priv_usb_bcn *priv_bcn; - struct urb *urb; - unsigned int guardian = - test_bit(DRIVER_REQUIRE_BEACON_GUARD, &rt2x00dev->flags); + struct queue_entry_priv_usb *entry_priv; + struct queue_entry_priv_usb_bcn *bcn_priv; unsigned int i; if (!queue->entries) return; for (i = 0; i < queue->limit; i++) { - if (queue->qid == QID_RX) { - priv_rx = queue->entries[i].priv_data; - urb = priv_rx->urb; - } else if (queue->qid == QID_MGMT && guardian) { - priv_bcn = queue->entries[i].priv_data; - - usb_kill_urb(priv_bcn->guardian_urb); - usb_free_urb(priv_bcn->guardian_urb); - - urb = priv_bcn->urb; - } else { - priv_tx = queue->entries[i].priv_data; - urb = priv_tx->urb; - } + entry_priv = queue->entries[i].priv_data; + usb_kill_urb(entry_priv->urb); + usb_free_urb(entry_priv->urb); + } - usb_kill_urb(urb); - usb_free_urb(urb); - if (queue->entries[i].skb) - kfree_skb(queue->entries[i].skb); + /* + * If this is not the beacon queue or + * no guardian byte was required for the beacon, + * then we are done. + */ + if (rt2x00dev->bcn != queue || + !test_bit(DRIVER_REQUIRE_BEACON_GUARD, &rt2x00dev->flags)) + return; + + for (i = 0; i < queue->limit; i++) { + bcn_priv = queue->entries[i].priv_data; + usb_kill_urb(bcn_priv->guardian_urb); + usb_free_urb(bcn_priv->guardian_urb); } } int rt2x00usb_initialize(struct rt2x00_dev *rt2x00dev) { struct data_queue *queue; - struct sk_buff *skb; - unsigned int entry_size; - unsigned int i; - int uninitialized_var(status); + int status; /* * Allocate DMA @@ -506,18 +419,6 @@ int rt2x00usb_initialize(struct rt2x00_dev *rt2x00dev) goto exit; } - /* - * For the RX queue, skb's should be allocated. - */ - entry_size = rt2x00dev->rx->data_size + rt2x00dev->rx->desc_size; - for (i = 0; i < rt2x00dev->rx->limit; i++) { - skb = rt2x00usb_alloc_rxskb(rt2x00dev->rx); - if (!skb) - goto exit; - - rt2x00dev->rx->entries[i].skb = skb; - } - return 0; exit: @@ -596,7 +497,7 @@ int rt2x00usb_probe(struct usb_interface *usb_intf, usb_set_intfdata(usb_intf, hw); rt2x00dev = hw->priv; - rt2x00dev->dev = usb_intf; + rt2x00dev->dev = &usb_intf->dev; rt2x00dev->ops = ops; rt2x00dev->hw = hw; mutex_init(&rt2x00dev->usb_cache_mutex); diff --git a/drivers/net/wireless/rt2x00/rt2x00usb.h b/drivers/net/wireless/rt2x00/rt2x00usb.h index 11e55180cbaf..aad794adf52c 100644 --- a/drivers/net/wireless/rt2x00/rt2x00usb.h +++ b/drivers/net/wireless/rt2x00/rt2x00usb.h @@ -26,6 +26,12 @@ #ifndef RT2X00USB_H #define RT2X00USB_H +#define to_usb_device_intf(d) \ +({ \ + struct usb_interface *intf = to_usb_interface(d); \ + interface_to_usbdev(intf); \ +}) + /* * This variable should be used with the * usb_driver structure initialization. @@ -47,6 +53,20 @@ #define REGISTER_TIMEOUT 500 #define REGISTER_TIMEOUT_FIRMWARE 1000 +/** + * REGISTER_TIMEOUT16 - Determine the timeout for 16bit register access + * @__datalen: Data length + */ +#define REGISTER_TIMEOUT16(__datalen) \ + ( REGISTER_TIMEOUT * ((__datalen) / sizeof(u16)) ) + +/** + * REGISTER_TIMEOUT32 - Determine the timeout for 32bit register access + * @__datalen: Data length + */ +#define REGISTER_TIMEOUT32(__datalen) \ + ( REGISTER_TIMEOUT * ((__datalen) / sizeof(u32)) ) + /* * Cache size */ @@ -185,13 +205,12 @@ static inline int rt2x00usb_vendor_request_sw(struct rt2x00_dev *rt2x00dev, * kmalloc for correct handling inside the kernel USB layer. */ static inline int rt2x00usb_eeprom_read(struct rt2x00_dev *rt2x00dev, - __le16 *eeprom, const u16 lenght) + __le16 *eeprom, const u16 length) { - int timeout = REGISTER_TIMEOUT * (lenght / sizeof(u16)); - return rt2x00usb_vendor_request(rt2x00dev, USB_EEPROM_READ, USB_VENDOR_REQUEST_IN, 0, 0, - eeprom, lenght, timeout); + eeprom, length, + REGISTER_TIMEOUT16(length)); } /* @@ -199,55 +218,53 @@ static inline int rt2x00usb_eeprom_read(struct rt2x00_dev *rt2x00dev, */ void rt2x00usb_disable_radio(struct rt2x00_dev *rt2x00dev); -/* - * TX data handlers. - */ -int rt2x00usb_write_tx_data(struct rt2x00_dev *rt2x00dev, - struct data_queue *queue, struct sk_buff *skb, - struct ieee80211_tx_control *control); - /** - * struct queue_entry_priv_usb_rx: Per RX entry USB specific information + * rt2x00usb_write_tx_data - Initialize URB for TX operation + * @entry: The entry where the frame is located * - * @urb: Urb structure used for device communication. + * This function will initialize the URB and skb descriptor + * to prepare the entry for the actual TX operation. */ -struct queue_entry_priv_usb_rx { - struct urb *urb; -}; +int rt2x00usb_write_tx_data(struct queue_entry *entry); /** - * struct queue_entry_priv_usb_tx: Per TX entry USB specific information + * struct queue_entry_priv_usb: Per entry USB specific information * * @urb: Urb structure used for device communication. - * @control: mac80211 control structure used to transmit data. */ -struct queue_entry_priv_usb_tx { +struct queue_entry_priv_usb { struct urb *urb; - - struct ieee80211_tx_control control; }; /** - * struct queue_entry_priv_usb_tx: Per TX entry USB specific information + * struct queue_entry_priv_usb_bcn: Per TX entry USB specific information * - * The first section should match &struct queue_entry_priv_usb_tx exactly. + * The first section should match &struct queue_entry_priv_usb exactly. * rt2500usb can use this structure to send a guardian byte when working * with beacons. * * @urb: Urb structure used for device communication. - * @control: mac80211 control structure used to transmit data. * @guardian_data: Set to 0, used for sending the guardian data. * @guardian_urb: Urb structure used to send the guardian data. */ struct queue_entry_priv_usb_bcn { struct urb *urb; - struct ieee80211_tx_control control; - unsigned int guardian_data; struct urb *guardian_urb; }; +/** + * rt2x00usb_kick_tx_queue - Kick data queue + * @rt2x00dev: Pointer to &struct rt2x00_dev + * @qid: Data queue to kick + * + * This will walk through all entries of the queue and push all pending + * frames to the hardware as a single burst. + */ +void rt2x00usb_kick_tx_queue(struct rt2x00_dev *rt2x00dev, + const enum data_queue_qid qid); + /* * Device initialization handlers. */ diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c index 580f90b63de7..f7c1f92c1448 100644 --- a/drivers/net/wireless/rt2x00/rt61pci.c +++ b/drivers/net/wireless/rt2x00/rt61pci.c @@ -330,6 +330,17 @@ static int rt61pci_blink_set(struct led_classdev *led_cdev, return 0; } + +static void rt61pci_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 = rt61pci_brightness_set; + led->led_dev.blink_set = rt61pci_blink_set; + led->flags = LED_INITIALIZED; +} #endif /* CONFIG_RT61PCI_LEDS */ /* @@ -1018,49 +1029,35 @@ static int rt61pci_load_firmware(struct rt2x00_dev *rt2x00dev, const void *data, static void rt61pci_init_rxentry(struct rt2x00_dev *rt2x00dev, struct queue_entry *entry) { - struct queue_entry_priv_pci_rx *priv_rx = entry->priv_data; + struct queue_entry_priv_pci *entry_priv = entry->priv_data; + struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb); u32 word; - rt2x00_desc_read(priv_rx->desc, 5, &word); + rt2x00_desc_read(entry_priv->desc, 5, &word); rt2x00_set_field32(&word, RXD_W5_BUFFER_PHYSICAL_ADDRESS, - priv_rx->data_dma); - rt2x00_desc_write(priv_rx->desc, 5, word); + skbdesc->skb_dma); + rt2x00_desc_write(entry_priv->desc, 5, word); - rt2x00_desc_read(priv_rx->desc, 0, &word); + rt2x00_desc_read(entry_priv->desc, 0, &word); rt2x00_set_field32(&word, RXD_W0_OWNER_NIC, 1); - rt2x00_desc_write(priv_rx->desc, 0, word); + rt2x00_desc_write(entry_priv->desc, 0, word); } static void rt61pci_init_txentry(struct rt2x00_dev *rt2x00dev, struct queue_entry *entry) { - struct queue_entry_priv_pci_tx *priv_tx = entry->priv_data; + struct queue_entry_priv_pci *entry_priv = entry->priv_data; u32 word; - rt2x00_desc_read(priv_tx->desc, 1, &word); - rt2x00_set_field32(&word, TXD_W1_BUFFER_COUNT, 1); - rt2x00_desc_write(priv_tx->desc, 1, word); - - rt2x00_desc_read(priv_tx->desc, 5, &word); - rt2x00_set_field32(&word, TXD_W5_PID_TYPE, entry->queue->qid); - rt2x00_set_field32(&word, TXD_W5_PID_SUBTYPE, entry->entry_idx); - rt2x00_desc_write(priv_tx->desc, 5, word); - - rt2x00_desc_read(priv_tx->desc, 6, &word); - rt2x00_set_field32(&word, TXD_W6_BUFFER_PHYSICAL_ADDRESS, - priv_tx->data_dma); - rt2x00_desc_write(priv_tx->desc, 6, word); - - rt2x00_desc_read(priv_tx->desc, 0, &word); + rt2x00_desc_read(entry_priv->desc, 0, &word); rt2x00_set_field32(&word, TXD_W0_VALID, 0); rt2x00_set_field32(&word, TXD_W0_OWNER_NIC, 0); - rt2x00_desc_write(priv_tx->desc, 0, word); + rt2x00_desc_write(entry_priv->desc, 0, word); } static int rt61pci_init_queues(struct rt2x00_dev *rt2x00dev) { - struct queue_entry_priv_pci_rx *priv_rx; - struct queue_entry_priv_pci_tx *priv_tx; + struct queue_entry_priv_pci *entry_priv; u32 reg; /* @@ -1082,28 +1079,28 @@ static int rt61pci_init_queues(struct rt2x00_dev *rt2x00dev) rt2x00dev->tx[0].desc_size / 4); rt2x00pci_register_write(rt2x00dev, TX_RING_CSR1, reg); - priv_tx = rt2x00dev->tx[0].entries[0].priv_data; + entry_priv = rt2x00dev->tx[0].entries[0].priv_data; rt2x00pci_register_read(rt2x00dev, AC0_BASE_CSR, ®); rt2x00_set_field32(®, AC0_BASE_CSR_RING_REGISTER, - priv_tx->desc_dma); + entry_priv->desc_dma); rt2x00pci_register_write(rt2x00dev, AC0_BASE_CSR, reg); - priv_tx = rt2x00dev->tx[1].entries[0].priv_data; + entry_priv = rt2x00dev->tx[1].entries[0].priv_data; rt2x00pci_register_read(rt2x00dev, AC1_BASE_CSR, ®); rt2x00_set_field32(®, AC1_BASE_CSR_RING_REGISTER, - priv_tx->desc_dma); + entry_priv->desc_dma); rt2x00pci_register_write(rt2x00dev, AC1_BASE_CSR, reg); - priv_tx = rt2x00dev->tx[2].entries[0].priv_data; + entry_priv = rt2x00dev->tx[2].entries[0].priv_data; rt2x00pci_register_read(rt2x00dev, AC2_BASE_CSR, ®); rt2x00_set_field32(®, AC2_BASE_CSR_RING_REGISTER, - priv_tx->desc_dma); + entry_priv->desc_dma); rt2x00pci_register_write(rt2x00dev, AC2_BASE_CSR, reg); - priv_tx = rt2x00dev->tx[3].entries[0].priv_data; + entry_priv = rt2x00dev->tx[3].entries[0].priv_data; rt2x00pci_register_read(rt2x00dev, AC3_BASE_CSR, ®); rt2x00_set_field32(®, AC3_BASE_CSR_RING_REGISTER, - priv_tx->desc_dma); + entry_priv->desc_dma); rt2x00pci_register_write(rt2x00dev, AC3_BASE_CSR, reg); rt2x00pci_register_read(rt2x00dev, RX_RING_CSR, ®); @@ -1113,10 +1110,10 @@ static int rt61pci_init_queues(struct rt2x00_dev *rt2x00dev) rt2x00_set_field32(®, RX_RING_CSR_RXD_WRITEBACK_SIZE, 4); rt2x00pci_register_write(rt2x00dev, RX_RING_CSR, reg); - priv_rx = rt2x00dev->rx->entries[0].priv_data; + entry_priv = rt2x00dev->rx->entries[0].priv_data; rt2x00pci_register_read(rt2x00dev, RX_BASE_CSR, ®); rt2x00_set_field32(®, RX_BASE_CSR_RING_REGISTER, - priv_rx->desc_dma); + entry_priv->desc_dma); rt2x00pci_register_write(rt2x00dev, RX_BASE_CSR, reg); rt2x00pci_register_read(rt2x00dev, TX_DMA_DST_CSR, ®); @@ -1294,25 +1291,32 @@ static int rt61pci_init_registers(struct rt2x00_dev *rt2x00dev) return 0; } -static int rt61pci_init_bbp(struct rt2x00_dev *rt2x00dev) +static int rt61pci_wait_bbp_ready(struct rt2x00_dev *rt2x00dev) { unsigned int i; - u16 eeprom; - u8 reg_id; u8 value; for (i = 0; i < REGISTER_BUSY_COUNT; i++) { rt61pci_bbp_read(rt2x00dev, 0, &value); if ((value != 0xff) && (value != 0x00)) - goto continue_csr_init; - NOTICE(rt2x00dev, "Waiting for BBP register.\n"); + return 0; udelay(REGISTER_BUSY_DELAY); } ERROR(rt2x00dev, "BBP register access failed, aborting.\n"); return -EACCES; +} + +static int rt61pci_init_bbp(struct rt2x00_dev *rt2x00dev) +{ + unsigned int i; + u16 eeprom; + u8 reg_id; + u8 value; + + if (unlikely(rt61pci_wait_bbp_ready(rt2x00dev))) + return -EACCES; -continue_csr_init: rt61pci_bbp_write(rt2x00dev, 3, 0x00); rt61pci_bbp_write(rt2x00dev, 15, 0x30); rt61pci_bbp_write(rt2x00dev, 21, 0xc8); @@ -1361,7 +1365,8 @@ static void rt61pci_toggle_rx(struct rt2x00_dev *rt2x00dev, rt2x00pci_register_read(rt2x00dev, TXRX_CSR0, ®); rt2x00_set_field32(®, TXRX_CSR0_DISABLE_RX, - state == STATE_RADIO_RX_OFF); + (state == STATE_RADIO_RX_OFF) || + (state == STATE_RADIO_RX_OFF_LINK)); rt2x00pci_register_write(rt2x00dev, TXRX_CSR0, reg); } @@ -1413,17 +1418,10 @@ static int rt61pci_enable_radio(struct rt2x00_dev *rt2x00dev) /* * Initialize all registers. */ - if (rt61pci_init_queues(rt2x00dev) || - rt61pci_init_registers(rt2x00dev) || - rt61pci_init_bbp(rt2x00dev)) { - ERROR(rt2x00dev, "Register initialization failed.\n"); + if (unlikely(rt61pci_init_queues(rt2x00dev) || + rt61pci_init_registers(rt2x00dev) || + rt61pci_init_bbp(rt2x00dev))) return -EIO; - } - - /* - * Enable interrupts. - */ - rt61pci_toggle_irq(rt2x00dev, STATE_RADIO_IRQ_ON); /* * Enable RX. @@ -1455,11 +1453,6 @@ static void rt61pci_disable_radio(struct rt2x00_dev *rt2x00dev) rt2x00_set_field32(®, TX_CNTL_CSR_ABORT_TX_AC2, 1); rt2x00_set_field32(®, TX_CNTL_CSR_ABORT_TX_AC3, 1); rt2x00pci_register_write(rt2x00dev, TX_CNTL_CSR, reg); - - /* - * Disable interrupts. - */ - rt61pci_toggle_irq(rt2x00dev, STATE_RADIO_IRQ_OFF); } static int rt61pci_set_state(struct rt2x00_dev *rt2x00dev, enum dev_state state) @@ -1467,7 +1460,6 @@ static int rt61pci_set_state(struct rt2x00_dev *rt2x00dev, enum dev_state state) u32 reg; unsigned int i; char put_to_sleep; - char current_state; put_to_sleep = (state != STATE_AWAKE); @@ -1483,16 +1475,12 @@ static int rt61pci_set_state(struct rt2x00_dev *rt2x00dev, enum dev_state state) */ for (i = 0; i < REGISTER_BUSY_COUNT; i++) { rt2x00pci_register_read(rt2x00dev, MAC_CSR12, ®); - current_state = - rt2x00_get_field32(reg, MAC_CSR12_BBP_CURRENT_STATE); - if (current_state == !put_to_sleep) + state = rt2x00_get_field32(reg, MAC_CSR12_BBP_CURRENT_STATE); + if (state == !put_to_sleep) return 0; msleep(10); } - NOTICE(rt2x00dev, "Device failed to enter state %d, " - "current device state %d.\n", !put_to_sleep, current_state); - return -EBUSY; } @@ -1510,11 +1498,13 @@ static int rt61pci_set_device_state(struct rt2x00_dev *rt2x00dev, break; case STATE_RADIO_RX_ON: case STATE_RADIO_RX_ON_LINK: - rt61pci_toggle_rx(rt2x00dev, STATE_RADIO_RX_ON); - break; case STATE_RADIO_RX_OFF: case STATE_RADIO_RX_OFF_LINK: - rt61pci_toggle_rx(rt2x00dev, STATE_RADIO_RX_OFF); + rt61pci_toggle_rx(rt2x00dev, state); + break; + case STATE_RADIO_IRQ_ON: + case STATE_RADIO_IRQ_OFF: + rt61pci_toggle_irq(rt2x00dev, state); break; case STATE_DEEP_SLEEP: case STATE_SLEEP: @@ -1527,6 +1517,10 @@ static int rt61pci_set_device_state(struct rt2x00_dev *rt2x00dev, break; } + if (unlikely(retval)) + ERROR(rt2x00dev, "Device failed to enter state %d (%d).\n", + state, retval); + return retval; } @@ -1535,8 +1529,7 @@ static int rt61pci_set_device_state(struct rt2x00_dev *rt2x00dev, */ static void rt61pci_write_tx_desc(struct rt2x00_dev *rt2x00dev, struct sk_buff *skb, - struct txentry_desc *txdesc, - struct ieee80211_tx_control *control) + struct txentry_desc *txdesc) { struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb); __le32 *txd = skbdesc->desc; @@ -1552,6 +1545,7 @@ static void rt61pci_write_tx_desc(struct rt2x00_dev *rt2x00dev, rt2x00_set_field32(&word, TXD_W1_CWMAX, txdesc->cw_max); rt2x00_set_field32(&word, TXD_W1_IV_OFFSET, IEEE80211_HEADER); rt2x00_set_field32(&word, TXD_W1_HW_SEQUENCE, 1); + rt2x00_set_field32(&word, TXD_W1_BUFFER_COUNT, 1); rt2x00_desc_write(txd, 1, word); rt2x00_desc_read(txd, 2, &word); @@ -1562,14 +1556,22 @@ static void rt61pci_write_tx_desc(struct rt2x00_dev *rt2x00dev, rt2x00_desc_write(txd, 2, word); rt2x00_desc_read(txd, 5, &word); + rt2x00_set_field32(&word, TXD_W5_PID_TYPE, skbdesc->entry->queue->qid); + rt2x00_set_field32(&word, TXD_W5_PID_SUBTYPE, + skbdesc->entry->entry_idx); rt2x00_set_field32(&word, TXD_W5_TX_POWER, TXPOWER_TO_DEV(rt2x00dev->tx_power)); rt2x00_set_field32(&word, TXD_W5_WAITING_DMA_DONE_INT, 1); rt2x00_desc_write(txd, 5, word); + rt2x00_desc_read(txd, 6, &word); + rt2x00_set_field32(&word, TXD_W6_BUFFER_PHYSICAL_ADDRESS, + skbdesc->skb_dma); + rt2x00_desc_write(txd, 6, word); + if (skbdesc->desc_len > TXINFO_SIZE) { rt2x00_desc_read(txd, 11, &word); - rt2x00_set_field32(&word, TXD_W11_BUFFER_LENGTH0, skbdesc->data_len); + rt2x00_set_field32(&word, TXD_W11_BUFFER_LENGTH0, skb->len); rt2x00_desc_write(txd, 11, word); } @@ -1586,10 +1588,9 @@ static void rt61pci_write_tx_desc(struct rt2x00_dev *rt2x00dev, test_bit(ENTRY_TXD_OFDM_RATE, &txdesc->flags)); rt2x00_set_field32(&word, TXD_W0_IFS, txdesc->ifs); rt2x00_set_field32(&word, TXD_W0_RETRY_MODE, - !!(control->flags & - IEEE80211_TXCTL_LONG_RETRY_LIMIT)); + test_bit(ENTRY_TXD_RETRY_MODE, &txdesc->flags)); rt2x00_set_field32(&word, TXD_W0_TKIP_MIC, 0); - rt2x00_set_field32(&word, TXD_W0_DATABYTE_COUNT, skbdesc->data_len); + rt2x00_set_field32(&word, TXD_W0_DATABYTE_COUNT, skb->len); rt2x00_set_field32(&word, TXD_W0_BURST, test_bit(ENTRY_TXD_BURST, &txdesc->flags)); rt2x00_set_field32(&word, TXD_W0_CIPHER_ALG, CIPHER_NONE); @@ -1599,12 +1600,47 @@ static void rt61pci_write_tx_desc(struct rt2x00_dev *rt2x00dev, /* * TX data initialization */ +static void rt61pci_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; + + /* + * Disable beaconing while we are reloading the beacon data, + * otherwise we might be sending out invalid data. + */ + rt2x00pci_register_read(rt2x00dev, TXRX_CSR9, ®); + rt2x00_set_field32(®, TXRX_CSR9_TSF_TICKING, 0); + rt2x00_set_field32(®, TXRX_CSR9_TBTT_ENABLE, 0); + rt2x00_set_field32(®, TXRX_CSR9_BEACON_GEN, 0); + rt2x00pci_register_write(rt2x00dev, TXRX_CSR9, reg); + + /* + * Write entire beacon with descriptor to register. + */ + beacon_base = HW_BEACON_OFFSET(entry->entry_idx); + rt2x00pci_register_multiwrite(rt2x00dev, + beacon_base, + skbdesc->desc, skbdesc->desc_len); + rt2x00pci_register_multiwrite(rt2x00dev, + beacon_base + skbdesc->desc_len, + entry->skb->data, entry->skb->len); + + /* + * Clean up beacon skb. + */ + dev_kfree_skb_any(entry->skb); + entry->skb = NULL; +} + static void rt61pci_kick_tx_queue(struct rt2x00_dev *rt2x00dev, - const unsigned int queue) + const enum data_queue_qid queue) { u32 reg; - if (queue == RT2X00_BCN_QUEUE_BEACON) { + if (queue == QID_BEACON) { /* * For Wi-Fi faily generated beacons between participating * stations. Set TBTT phase adaptive adjustment step to 8us. @@ -1622,14 +1658,10 @@ static void rt61pci_kick_tx_queue(struct rt2x00_dev *rt2x00dev, } rt2x00pci_register_read(rt2x00dev, TX_CNTL_CSR, ®); - rt2x00_set_field32(®, TX_CNTL_CSR_KICK_TX_AC0, - (queue == IEEE80211_TX_QUEUE_DATA0)); - rt2x00_set_field32(®, TX_CNTL_CSR_KICK_TX_AC1, - (queue == IEEE80211_TX_QUEUE_DATA1)); - rt2x00_set_field32(®, TX_CNTL_CSR_KICK_TX_AC2, - (queue == IEEE80211_TX_QUEUE_DATA2)); - rt2x00_set_field32(®, TX_CNTL_CSR_KICK_TX_AC3, - (queue == IEEE80211_TX_QUEUE_DATA3)); + rt2x00_set_field32(®, TX_CNTL_CSR_KICK_TX_AC0, (queue == QID_AC_BE)); + rt2x00_set_field32(®, TX_CNTL_CSR_KICK_TX_AC1, (queue == QID_AC_BK)); + rt2x00_set_field32(®, TX_CNTL_CSR_KICK_TX_AC2, (queue == QID_AC_VI)); + rt2x00_set_field32(®, TX_CNTL_CSR_KICK_TX_AC3, (queue == QID_AC_VO)); rt2x00pci_register_write(rt2x00dev, TX_CNTL_CSR, reg); } @@ -1680,14 +1712,13 @@ static int rt61pci_agc_to_rssi(struct rt2x00_dev *rt2x00dev, int rxd_w1) static void rt61pci_fill_rxdone(struct queue_entry *entry, struct rxdone_entry_desc *rxdesc) { - struct queue_entry_priv_pci_rx *priv_rx = entry->priv_data; + struct queue_entry_priv_pci *entry_priv = entry->priv_data; u32 word0; u32 word1; - rt2x00_desc_read(priv_rx->desc, 0, &word0); - rt2x00_desc_read(priv_rx->desc, 1, &word1); + rt2x00_desc_read(entry_priv->desc, 0, &word0); + rt2x00_desc_read(entry_priv->desc, 1, &word1); - rxdesc->flags = 0; if (rt2x00_get_field32(word0, RXD_W0_CRC_ERROR)) rxdesc->flags |= RX_FLAG_FAILED_FCS_CRC; @@ -1701,7 +1732,6 @@ static void rt61pci_fill_rxdone(struct queue_entry *entry, rxdesc->rssi = rt61pci_agc_to_rssi(entry->queue->rt2x00dev, word1); rxdesc->size = rt2x00_get_field32(word0, RXD_W0_DATABYTE_COUNT); - rxdesc->dev_flags = 0; if (rt2x00_get_field32(word0, RXD_W0_OFDM)) rxdesc->dev_flags |= RXDONE_SIGNAL_PLCP; if (rt2x00_get_field32(word0, RXD_W0_MY_BSS)) @@ -1716,7 +1746,7 @@ static void rt61pci_txdone(struct rt2x00_dev *rt2x00dev) struct data_queue *queue; struct queue_entry *entry; struct queue_entry *entry_done; - struct queue_entry_priv_pci_tx *priv_tx; + struct queue_entry_priv_pci *entry_priv; struct txdone_entry_desc txdesc; u32 word; u32 reg; @@ -1761,8 +1791,8 @@ static void rt61pci_txdone(struct rt2x00_dev *rt2x00dev) continue; entry = &queue->entries[index]; - priv_tx = entry->priv_data; - rt2x00_desc_read(priv_tx->desc, 0, &word); + entry_priv = entry->priv_data; + rt2x00_desc_read(entry_priv->desc, 0, &word); if (rt2x00_get_field32(word, TXD_W0_OWNER_NIC) || !rt2x00_get_field32(word, TXD_W0_VALID)) @@ -1777,20 +1807,31 @@ static void rt61pci_txdone(struct rt2x00_dev *rt2x00dev) "TX status report missed for entry %d\n", entry_done->entry_idx); - txdesc.status = TX_FAIL_OTHER; + txdesc.flags = 0; + __set_bit(TXDONE_UNKNOWN, &txdesc.flags); txdesc.retry = 0; - rt2x00pci_txdone(rt2x00dev, entry_done, &txdesc); + rt2x00lib_txdone(entry_done, &txdesc); entry_done = rt2x00queue_get_entry(queue, Q_INDEX_DONE); } /* * Obtain the status about this packet. */ - txdesc.status = rt2x00_get_field32(reg, STA_CSR4_TX_RESULT); + txdesc.flags = 0; + switch (rt2x00_get_field32(reg, STA_CSR4_TX_RESULT)) { + case 0: /* Success, maybe with retry */ + __set_bit(TXDONE_SUCCESS, &txdesc.flags); + break; + case 6: /* Failure, excessive retries */ + __set_bit(TXDONE_EXCESSIVE_RETRY, &txdesc.flags); + /* Don't break, this is a failed frame! */ + default: /* Failure */ + __set_bit(TXDONE_FAILURE, &txdesc.flags); + } txdesc.retry = rt2x00_get_field32(reg, STA_CSR4_RETRY_COUNT); - rt2x00pci_txdone(rt2x00dev, entry, &txdesc); + rt2x00lib_txdone(entry, &txdesc); } } @@ -1976,7 +2017,7 @@ static int rt61pci_init_eeprom(struct rt2x00_dev *rt2x00dev) * To determine the RT chip we have to read the * PCI header of the device. */ - pci_read_config_word(rt2x00dev_pci(rt2x00dev), + 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, ®); @@ -2078,31 +2119,11 @@ static int rt61pci_init_eeprom(struct rt2x00_dev *rt2x00dev) rt2x00_eeprom_read(rt2x00dev, EEPROM_LED, &eeprom); value = rt2x00_get_field16(eeprom, EEPROM_LED_LED_MODE); - rt2x00dev->led_radio.rt2x00dev = rt2x00dev; - rt2x00dev->led_radio.type = LED_TYPE_RADIO; - rt2x00dev->led_radio.led_dev.brightness_set = - rt61pci_brightness_set; - rt2x00dev->led_radio.led_dev.blink_set = - rt61pci_blink_set; - rt2x00dev->led_radio.flags = LED_INITIALIZED; - - rt2x00dev->led_assoc.rt2x00dev = rt2x00dev; - rt2x00dev->led_assoc.type = LED_TYPE_ASSOC; - rt2x00dev->led_assoc.led_dev.brightness_set = - rt61pci_brightness_set; - rt2x00dev->led_assoc.led_dev.blink_set = - rt61pci_blink_set; - rt2x00dev->led_assoc.flags = LED_INITIALIZED; - - if (value == LED_MODE_SIGNAL_STRENGTH) { - rt2x00dev->led_qual.rt2x00dev = rt2x00dev; - rt2x00dev->led_qual.type = LED_TYPE_QUALITY; - rt2x00dev->led_qual.led_dev.brightness_set = - rt61pci_brightness_set; - rt2x00dev->led_qual.led_dev.blink_set = - rt61pci_blink_set; - rt2x00dev->led_qual.flags = LED_INITIALIZED; - } + rt61pci_init_led(rt2x00dev, &rt2x00dev->led_radio, LED_TYPE_RADIO); + rt61pci_init_led(rt2x00dev, &rt2x00dev->led_assoc, LED_TYPE_ASSOC); + if (value == LED_MODE_SIGNAL_STRENGTH) + rt61pci_init_led(rt2x00dev, &rt2x00dev->led_qual, + LED_TYPE_QUALITY); rt2x00_set_field16(&rt2x00dev->led_mcu_reg, MCU_LEDCS_LED_MODE, value); rt2x00_set_field16(&rt2x00dev->led_mcu_reg, MCU_LEDCS_POLARITY_GPIO_0, @@ -2258,13 +2279,11 @@ static void rt61pci_probe_hw_mode(struct rt2x00_dev *rt2x00dev) */ rt2x00dev->hw->flags = IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE | - IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING; + IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | + IEEE80211_HW_SIGNAL_DBM; rt2x00dev->hw->extra_tx_headroom = 0; - rt2x00dev->hw->max_signal = MAX_SIGNAL; - rt2x00dev->hw->max_rssi = MAX_RX_SSI; - rt2x00dev->hw->queues = 4; - SET_IEEE80211_DEV(rt2x00dev->hw, &rt2x00dev_pci(rt2x00dev)->dev); + SET_IEEE80211_DEV(rt2x00dev->hw, rt2x00dev->dev); SET_IEEE80211_PERM_ADDR(rt2x00dev->hw, rt2x00_eeprom_addr(rt2x00dev, EEPROM_MAC_ADDR_0)); @@ -2327,9 +2346,10 @@ static int rt61pci_probe_hw(struct rt2x00_dev *rt2x00dev) rt61pci_probe_hw_mode(rt2x00dev); /* - * This device requires firmware. + * This device requires firmware and DMA mapped skbs. */ __set_bit(DRIVER_REQUIRE_FIRMWARE, &rt2x00dev->flags); + __set_bit(DRIVER_REQUIRE_DMA, &rt2x00dev->flags); /* * Set the rssi offset. @@ -2370,67 +2390,6 @@ static u64 rt61pci_get_tsf(struct ieee80211_hw *hw) return tsf; } -static int rt61pci_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb, - struct ieee80211_tx_control *control) -{ - struct rt2x00_dev *rt2x00dev = hw->priv; - struct rt2x00_intf *intf = vif_to_intf(control->vif); - struct queue_entry_priv_pci_tx *priv_tx; - struct skb_frame_desc *skbdesc; - unsigned int beacon_base; - u32 reg; - - if (unlikely(!intf->beacon)) - return -ENOBUFS; - - priv_tx = intf->beacon->priv_data; - memset(priv_tx->desc, 0, intf->beacon->queue->desc_size); - - /* - * Fill in skb descriptor - */ - skbdesc = get_skb_frame_desc(skb); - memset(skbdesc, 0, sizeof(*skbdesc)); - skbdesc->flags |= FRAME_DESC_DRIVER_GENERATED; - skbdesc->data = skb->data; - skbdesc->data_len = skb->len; - skbdesc->desc = priv_tx->desc; - skbdesc->desc_len = intf->beacon->queue->desc_size; - skbdesc->entry = intf->beacon; - - /* - * Disable beaconing while we are reloading the beacon data, - * otherwise we might be sending out invalid data. - */ - rt2x00pci_register_read(rt2x00dev, TXRX_CSR9, ®); - rt2x00_set_field32(®, TXRX_CSR9_TSF_TICKING, 0); - rt2x00_set_field32(®, TXRX_CSR9_TBTT_ENABLE, 0); - rt2x00_set_field32(®, TXRX_CSR9_BEACON_GEN, 0); - rt2x00pci_register_write(rt2x00dev, TXRX_CSR9, reg); - - /* - * mac80211 doesn't provide the control->queue variable - * for beacons. Set our own queue identification so - * it can be used during descriptor initialization. - */ - control->queue = RT2X00_BCN_QUEUE_BEACON; - rt2x00lib_write_tx_desc(rt2x00dev, skb, control); - - /* - * Write entire beacon with descriptor to register, - * and kick the beacon generator. - */ - beacon_base = HW_BEACON_OFFSET(intf->beacon->entry_idx); - rt2x00pci_register_multiwrite(rt2x00dev, beacon_base, - skbdesc->desc, skbdesc->desc_len); - rt2x00pci_register_multiwrite(rt2x00dev, - beacon_base + skbdesc->desc_len, - skbdesc->data, skbdesc->data_len); - rt61pci_kick_tx_queue(rt2x00dev, control->queue); - - return 0; -} - static const struct ieee80211_ops rt61pci_mac80211_ops = { .tx = rt2x00mac_tx, .start = rt2x00mac_start, @@ -2446,7 +2405,6 @@ static const struct ieee80211_ops rt61pci_mac80211_ops = { .conf_tx = rt2x00mac_conf_tx, .get_tx_stats = rt2x00mac_get_tx_stats, .get_tsf = rt61pci_get_tsf, - .beacon_update = rt61pci_beacon_update, }; static const struct rt2x00lib_ops rt61pci_rt2x00_ops = { @@ -2466,6 +2424,7 @@ static const struct rt2x00lib_ops rt61pci_rt2x00_ops = { .link_tuner = rt61pci_link_tuner, .write_tx_desc = rt61pci_write_tx_desc, .write_tx_data = rt2x00pci_write_tx_data, + .write_beacon = rt61pci_write_beacon, .kick_tx_queue = rt61pci_kick_tx_queue, .fill_rxdone = rt61pci_fill_rxdone, .config_filter = rt61pci_config_filter, @@ -2478,21 +2437,21 @@ static const struct data_queue_desc rt61pci_queue_rx = { .entry_num = RX_ENTRIES, .data_size = DATA_FRAME_SIZE, .desc_size = RXD_DESC_SIZE, - .priv_size = sizeof(struct queue_entry_priv_pci_rx), + .priv_size = sizeof(struct queue_entry_priv_pci), }; static const struct data_queue_desc rt61pci_queue_tx = { .entry_num = TX_ENTRIES, .data_size = DATA_FRAME_SIZE, .desc_size = TXD_DESC_SIZE, - .priv_size = sizeof(struct queue_entry_priv_pci_tx), + .priv_size = sizeof(struct queue_entry_priv_pci), }; static const struct data_queue_desc rt61pci_queue_bcn = { .entry_num = 4 * BEACON_ENTRIES, .data_size = 0, /* No DMA required for beacons */ .desc_size = TXINFO_SIZE, - .priv_size = sizeof(struct queue_entry_priv_pci_tx), + .priv_size = sizeof(struct queue_entry_priv_pci), }; static const struct rt2x00_ops rt61pci_ops = { @@ -2501,6 +2460,7 @@ static const struct rt2x00_ops rt61pci_ops = { .max_ap_intf = 4, .eeprom_size = EEPROM_SIZE, .rf_size = RF_SIZE, + .tx_queues = NUM_TX_QUEUES, .rx = &rt61pci_queue_rx, .tx = &rt61pci_queue_tx, .bcn = &rt61pci_queue_bcn, diff --git a/drivers/net/wireless/rt2x00/rt61pci.h b/drivers/net/wireless/rt2x00/rt61pci.h index 3511bba7ff65..1004d5b899e6 100644 --- a/drivers/net/wireless/rt2x00/rt61pci.h +++ b/drivers/net/wireless/rt2x00/rt61pci.h @@ -39,8 +39,6 @@ * Signal information. * Defaul offset is required for RSSI <-> dBm conversion. */ -#define MAX_SIGNAL 100 -#define MAX_RX_SSI -1 #define DEFAULT_RSSI_OFFSET 120 /* @@ -54,6 +52,11 @@ #define RF_SIZE 0x0014 /* + * Number of TX queues. + */ +#define NUM_TX_QUEUES 4 + +/* * PCI registers. */ diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c index 6a62d6bb96fe..d383735ab8f2 100644 --- a/drivers/net/wireless/rt2x00/rt73usb.c +++ b/drivers/net/wireless/rt2x00/rt73usb.c @@ -74,10 +74,10 @@ static inline void rt73usb_register_multiread(struct rt2x00_dev *rt2x00dev, const unsigned int offset, void *value, const u32 length) { - int timeout = REGISTER_TIMEOUT * (length / sizeof(u32)); rt2x00usb_vendor_request_buff(rt2x00dev, USB_MULTI_READ, USB_VENDOR_REQUEST_IN, offset, - value, length, timeout); + value, length, + REGISTER_TIMEOUT32(length)); } static inline void rt73usb_register_write(struct rt2x00_dev *rt2x00dev, @@ -102,10 +102,10 @@ static inline void rt73usb_register_multiwrite(struct rt2x00_dev *rt2x00dev, const unsigned int offset, void *value, const u32 length) { - int timeout = REGISTER_TIMEOUT * (length / sizeof(u32)); rt2x00usb_vendor_request_buff(rt2x00dev, USB_MULTI_WRITE, USB_VENDOR_REQUEST_OUT, offset, - value, length, timeout); + value, length, + REGISTER_TIMEOUT32(length)); } static u32 rt73usb_bbp_check(struct rt2x00_dev *rt2x00dev) @@ -341,6 +341,17 @@ static int rt73usb_blink_set(struct led_classdev *led_cdev, return 0; } + +static void rt73usb_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 = rt73usb_brightness_set; + led->led_dev.blink_set = rt73usb_blink_set; + led->flags = LED_INITIALIZED; +} #endif /* CONFIG_RT73USB_LEDS */ /* @@ -882,7 +893,6 @@ static int rt73usb_load_firmware(struct rt2x00_dev *rt2x00dev, const void *data, const char *ptr = data; char *cache; int buflen; - int timeout; /* * Wait for stable hardware. @@ -913,14 +923,14 @@ static int rt73usb_load_firmware(struct rt2x00_dev *rt2x00dev, const void *data, for (i = 0; i < len; i += CSR_CACHE_SIZE_FIRMWARE) { buflen = min_t(int, len - i, CSR_CACHE_SIZE_FIRMWARE); - timeout = REGISTER_TIMEOUT * (buflen / sizeof(u32)); memcpy(cache, ptr, buflen); rt2x00usb_vendor_request(rt2x00dev, USB_MULTI_WRITE, USB_VENDOR_REQUEST_OUT, FIRMWARE_IMAGE_BASE + i, 0, - cache, buflen, timeout); + cache, buflen, + REGISTER_TIMEOUT32(buflen)); ptr += buflen; } @@ -1100,25 +1110,32 @@ static int rt73usb_init_registers(struct rt2x00_dev *rt2x00dev) return 0; } -static int rt73usb_init_bbp(struct rt2x00_dev *rt2x00dev) +static int rt73usb_wait_bbp_ready(struct rt2x00_dev *rt2x00dev) { unsigned int i; - u16 eeprom; - u8 reg_id; u8 value; for (i = 0; i < REGISTER_BUSY_COUNT; i++) { rt73usb_bbp_read(rt2x00dev, 0, &value); if ((value != 0xff) && (value != 0x00)) - goto continue_csr_init; - NOTICE(rt2x00dev, "Waiting for BBP register.\n"); + return 0; udelay(REGISTER_BUSY_DELAY); } ERROR(rt2x00dev, "BBP register access failed, aborting.\n"); return -EACCES; +} + +static int rt73usb_init_bbp(struct rt2x00_dev *rt2x00dev) +{ + unsigned int i; + u16 eeprom; + u8 reg_id; + u8 value; + + if (unlikely(rt73usb_wait_bbp_ready(rt2x00dev))) + return -EACCES; -continue_csr_init: rt73usb_bbp_write(rt2x00dev, 3, 0x80); rt73usb_bbp_write(rt2x00dev, 15, 0x30); rt73usb_bbp_write(rt2x00dev, 21, 0xc8); @@ -1168,7 +1185,8 @@ static void rt73usb_toggle_rx(struct rt2x00_dev *rt2x00dev, rt73usb_register_read(rt2x00dev, TXRX_CSR0, ®); rt2x00_set_field32(®, TXRX_CSR0_DISABLE_RX, - state == STATE_RADIO_RX_OFF); + (state == STATE_RADIO_RX_OFF) || + (state == STATE_RADIO_RX_OFF_LINK)); rt73usb_register_write(rt2x00dev, TXRX_CSR0, reg); } @@ -1177,11 +1195,9 @@ static int rt73usb_enable_radio(struct rt2x00_dev *rt2x00dev) /* * Initialize all registers. */ - if (rt73usb_init_registers(rt2x00dev) || - rt73usb_init_bbp(rt2x00dev)) { - ERROR(rt2x00dev, "Register initialization failed.\n"); + if (unlikely(rt73usb_init_registers(rt2x00dev) || + rt73usb_init_bbp(rt2x00dev))) return -EIO; - } return 0; } @@ -1203,7 +1219,6 @@ static int rt73usb_set_state(struct rt2x00_dev *rt2x00dev, enum dev_state state) u32 reg; unsigned int i; char put_to_sleep; - char current_state; put_to_sleep = (state != STATE_AWAKE); @@ -1219,16 +1234,12 @@ static int rt73usb_set_state(struct rt2x00_dev *rt2x00dev, enum dev_state state) */ for (i = 0; i < REGISTER_BUSY_COUNT; i++) { rt73usb_register_read(rt2x00dev, MAC_CSR12, ®); - current_state = - rt2x00_get_field32(reg, MAC_CSR12_BBP_CURRENT_STATE); - if (current_state == !put_to_sleep) + state = rt2x00_get_field32(reg, MAC_CSR12_BBP_CURRENT_STATE); + if (state == !put_to_sleep) return 0; msleep(10); } - NOTICE(rt2x00dev, "Device failed to enter state %d, " - "current device state %d.\n", !put_to_sleep, current_state); - return -EBUSY; } @@ -1246,11 +1257,13 @@ static int rt73usb_set_device_state(struct rt2x00_dev *rt2x00dev, break; case STATE_RADIO_RX_ON: case STATE_RADIO_RX_ON_LINK: - rt73usb_toggle_rx(rt2x00dev, STATE_RADIO_RX_ON); - break; case STATE_RADIO_RX_OFF: case STATE_RADIO_RX_OFF_LINK: - rt73usb_toggle_rx(rt2x00dev, STATE_RADIO_RX_OFF); + rt73usb_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: @@ -1263,6 +1276,10 @@ static int rt73usb_set_device_state(struct rt2x00_dev *rt2x00dev, break; } + if (unlikely(retval)) + ERROR(rt2x00dev, "Device failed to enter state %d (%d).\n", + state, retval); + return retval; } @@ -1271,8 +1288,7 @@ static int rt73usb_set_device_state(struct rt2x00_dev *rt2x00dev, */ static void rt73usb_write_tx_desc(struct rt2x00_dev *rt2x00dev, struct sk_buff *skb, - struct txentry_desc *txdesc, - struct ieee80211_tx_control *control) + struct txentry_desc *txdesc) { struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb); __le32 *txd = skbdesc->desc; @@ -1317,16 +1333,59 @@ static void rt73usb_write_tx_desc(struct rt2x00_dev *rt2x00dev, test_bit(ENTRY_TXD_OFDM_RATE, &txdesc->flags)); rt2x00_set_field32(&word, TXD_W0_IFS, txdesc->ifs); rt2x00_set_field32(&word, TXD_W0_RETRY_MODE, - !!(control->flags & - IEEE80211_TXCTL_LONG_RETRY_LIMIT)); + test_bit(ENTRY_TXD_RETRY_MODE, &txdesc->flags)); rt2x00_set_field32(&word, TXD_W0_TKIP_MIC, 0); - rt2x00_set_field32(&word, TXD_W0_DATABYTE_COUNT, skbdesc->data_len); + rt2x00_set_field32(&word, TXD_W0_DATABYTE_COUNT, + skb->len - skbdesc->desc_len); rt2x00_set_field32(&word, TXD_W0_BURST2, test_bit(ENTRY_TXD_BURST, &txdesc->flags)); rt2x00_set_field32(&word, TXD_W0_CIPHER_ALG, CIPHER_NONE); rt2x00_desc_write(txd, 0, word); } +/* + * TX data initialization + */ +static void rt73usb_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. + */ + rt73usb_register_read(rt2x00dev, TXRX_CSR9, ®); + rt2x00_set_field32(®, TXRX_CSR9_TSF_TICKING, 0); + rt2x00_set_field32(®, TXRX_CSR9_TBTT_ENABLE, 0); + rt2x00_set_field32(®, TXRX_CSR9_BEACON_GEN, 0); + rt73usb_register_write(rt2x00dev, TXRX_CSR9, reg); + + /* + * Write entire beacon with descriptor to register. + */ + beacon_base = HW_BEACON_OFFSET(entry->entry_idx); + rt2x00usb_vendor_request(rt2x00dev, USB_MULTI_WRITE, + USB_VENDOR_REQUEST_OUT, beacon_base, 0, + 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 rt73usb_get_tx_data_len(struct rt2x00_dev *rt2x00dev, struct sk_buff *skb) { @@ -1342,16 +1401,15 @@ static int rt73usb_get_tx_data_len(struct rt2x00_dev *rt2x00dev, return length; } -/* - * TX data initialization - */ static void rt73usb_kick_tx_queue(struct rt2x00_dev *rt2x00dev, - const unsigned int queue) + const enum data_queue_qid queue) { u32 reg; - if (queue != RT2X00_BCN_QUEUE_BEACON) + if (queue != QID_BEACON) { + rt2x00usb_kick_tx_queue(rt2x00dev, queue); return; + } /* * For Wi-Fi faily generated beacons between participating stations. @@ -1421,25 +1479,22 @@ static void rt73usb_fill_rxdone(struct queue_entry *entry, { struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb); __le32 *rxd = (__le32 *)entry->skb->data; - unsigned int offset = entry->queue->desc_size + 2; u32 word0; u32 word1; /* - * Copy descriptor to the available headroom inside the skbuffer. + * Copy descriptor to the skbdesc->desc buffer, making it safe from moving of + * frame data in rt2x00usb. */ - skb_push(entry->skb, offset); - memcpy(entry->skb->data, rxd, entry->queue->desc_size); - rxd = (__le32 *)entry->skb->data; + memcpy(skbdesc->desc, rxd, skbdesc->desc_len); + rxd = (__le32 *)skbdesc->desc; /* - * The descriptor is now aligned to 4 bytes and thus it is - * now safe to read it on all architectures. + * It is now safe to read the descriptor on all architectures. */ rt2x00_desc_read(rxd, 0, &word0); rt2x00_desc_read(rxd, 1, &word1); - rxdesc->flags = 0; if (rt2x00_get_field32(word0, RXD_W0_CRC_ERROR)) rxdesc->flags |= RX_FLAG_FAILED_FCS_CRC; @@ -1453,25 +1508,16 @@ static void rt73usb_fill_rxdone(struct queue_entry *entry, rxdesc->rssi = rt73usb_agc_to_rssi(entry->queue->rt2x00dev, word1); rxdesc->size = rt2x00_get_field32(word0, RXD_W0_DATABYTE_COUNT); - rxdesc->dev_flags = 0; if (rt2x00_get_field32(word0, RXD_W0_OFDM)) rxdesc->dev_flags |= RXDONE_SIGNAL_PLCP; if (rt2x00_get_field32(word0, RXD_W0_MY_BSS)) rxdesc->dev_flags |= RXDONE_MY_BSS; /* - * Adjust the skb memory window to the frame boundaries. + * Set skb pointers, and update frame information. */ - skb_pull(entry->skb, offset + entry->queue->desc_size); + skb_pull(entry->skb, entry->queue->desc_size); skb_trim(entry->skb, rxdesc->size); - - /* - * Set descriptor and data pointer. - */ - skbdesc->data = entry->skb->data; - skbdesc->data_len = rxdesc->size; - skbdesc->desc = rxd; - skbdesc->desc_len = entry->queue->desc_size; } /* @@ -1644,31 +1690,11 @@ static int rt73usb_init_eeprom(struct rt2x00_dev *rt2x00dev) #ifdef CONFIG_RT73USB_LEDS rt2x00_eeprom_read(rt2x00dev, EEPROM_LED, &eeprom); - rt2x00dev->led_radio.rt2x00dev = rt2x00dev; - rt2x00dev->led_radio.type = LED_TYPE_RADIO; - rt2x00dev->led_radio.led_dev.brightness_set = - rt73usb_brightness_set; - rt2x00dev->led_radio.led_dev.blink_set = - rt73usb_blink_set; - rt2x00dev->led_radio.flags = LED_INITIALIZED; - - rt2x00dev->led_assoc.rt2x00dev = rt2x00dev; - rt2x00dev->led_assoc.type = LED_TYPE_ASSOC; - rt2x00dev->led_assoc.led_dev.brightness_set = - rt73usb_brightness_set; - rt2x00dev->led_assoc.led_dev.blink_set = - rt73usb_blink_set; - rt2x00dev->led_assoc.flags = LED_INITIALIZED; - - if (value == LED_MODE_SIGNAL_STRENGTH) { - rt2x00dev->led_qual.rt2x00dev = rt2x00dev; - rt2x00dev->led_qual.type = LED_TYPE_QUALITY; - rt2x00dev->led_qual.led_dev.brightness_set = - rt73usb_brightness_set; - rt2x00dev->led_qual.led_dev.blink_set = - rt73usb_blink_set; - rt2x00dev->led_qual.flags = LED_INITIALIZED; - } + rt73usb_init_led(rt2x00dev, &rt2x00dev->led_radio, LED_TYPE_RADIO); + rt73usb_init_led(rt2x00dev, &rt2x00dev->led_assoc, LED_TYPE_ASSOC); + if (value == LED_MODE_SIGNAL_STRENGTH) + rt73usb_init_led(rt2x00dev, &rt2x00dev->led_qual, + LED_TYPE_QUALITY); rt2x00_set_field16(&rt2x00dev->led_mcu_reg, MCU_LEDCS_LED_MODE, value); rt2x00_set_field16(&rt2x00dev->led_mcu_reg, MCU_LEDCS_POLARITY_GPIO_0, @@ -1846,13 +1872,11 @@ static void rt73usb_probe_hw_mode(struct rt2x00_dev *rt2x00dev) */ rt2x00dev->hw->flags = IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE | - IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING; + IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | + IEEE80211_HW_SIGNAL_DBM; rt2x00dev->hw->extra_tx_headroom = TXD_DESC_SIZE; - rt2x00dev->hw->max_signal = MAX_SIGNAL; - rt2x00dev->hw->max_rssi = MAX_RX_SSI; - rt2x00dev->hw->queues = 4; - SET_IEEE80211_DEV(rt2x00dev->hw, &rt2x00dev_usb(rt2x00dev)->dev); + SET_IEEE80211_DEV(rt2x00dev->hw, rt2x00dev->dev); SET_IEEE80211_PERM_ADDR(rt2x00dev->hw, rt2x00_eeprom_addr(rt2x00dev, EEPROM_MAC_ADDR_0)); @@ -1974,69 +1998,6 @@ static u64 rt73usb_get_tsf(struct ieee80211_hw *hw) #define rt73usb_get_tsf NULL #endif -static int rt73usb_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb, - struct ieee80211_tx_control *control) -{ - struct rt2x00_dev *rt2x00dev = hw->priv; - struct rt2x00_intf *intf = vif_to_intf(control->vif); - struct skb_frame_desc *skbdesc; - unsigned int beacon_base; - unsigned int timeout; - u32 reg; - - if (unlikely(!intf->beacon)) - return -ENOBUFS; - - /* - * Add the descriptor in front of the skb. - */ - skb_push(skb, intf->beacon->queue->desc_size); - memset(skb->data, 0, intf->beacon->queue->desc_size); - - /* - * Fill in skb descriptor - */ - skbdesc = get_skb_frame_desc(skb); - memset(skbdesc, 0, sizeof(*skbdesc)); - skbdesc->flags |= FRAME_DESC_DRIVER_GENERATED; - skbdesc->data = skb->data + intf->beacon->queue->desc_size; - skbdesc->data_len = skb->len - intf->beacon->queue->desc_size; - skbdesc->desc = skb->data; - skbdesc->desc_len = intf->beacon->queue->desc_size; - skbdesc->entry = intf->beacon; - - /* - * Disable beaconing while we are reloading the beacon data, - * otherwise we might be sending out invalid data. - */ - rt73usb_register_read(rt2x00dev, TXRX_CSR9, ®); - rt2x00_set_field32(®, TXRX_CSR9_TSF_TICKING, 0); - rt2x00_set_field32(®, TXRX_CSR9_TBTT_ENABLE, 0); - rt2x00_set_field32(®, TXRX_CSR9_BEACON_GEN, 0); - rt73usb_register_write(rt2x00dev, TXRX_CSR9, reg); - - /* - * mac80211 doesn't provide the control->queue variable - * for beacons. Set our own queue identification so - * it can be used during descriptor initialization. - */ - control->queue = RT2X00_BCN_QUEUE_BEACON; - rt2x00lib_write_tx_desc(rt2x00dev, skb, control); - - /* - * Write entire beacon with descriptor to register, - * and kick the beacon generator. - */ - beacon_base = HW_BEACON_OFFSET(intf->beacon->entry_idx); - timeout = REGISTER_TIMEOUT * (skb->len / sizeof(u32)); - rt2x00usb_vendor_request(rt2x00dev, USB_MULTI_WRITE, - USB_VENDOR_REQUEST_OUT, beacon_base, 0, - skb->data, skb->len, timeout); - rt73usb_kick_tx_queue(rt2x00dev, control->queue); - - return 0; -} - static const struct ieee80211_ops rt73usb_mac80211_ops = { .tx = rt2x00mac_tx, .start = rt2x00mac_start, @@ -2052,7 +2013,6 @@ static const struct ieee80211_ops rt73usb_mac80211_ops = { .conf_tx = rt2x00mac_conf_tx, .get_tx_stats = rt2x00mac_get_tx_stats, .get_tsf = rt73usb_get_tsf, - .beacon_update = rt73usb_beacon_update, }; static const struct rt2x00lib_ops rt73usb_rt2x00_ops = { @@ -2070,6 +2030,7 @@ static const struct rt2x00lib_ops rt73usb_rt2x00_ops = { .link_tuner = rt73usb_link_tuner, .write_tx_desc = rt73usb_write_tx_desc, .write_tx_data = rt2x00usb_write_tx_data, + .write_beacon = rt73usb_write_beacon, .get_tx_data_len = rt73usb_get_tx_data_len, .kick_tx_queue = rt73usb_kick_tx_queue, .fill_rxdone = rt73usb_fill_rxdone, @@ -2083,21 +2044,21 @@ static const struct data_queue_desc rt73usb_queue_rx = { .entry_num = RX_ENTRIES, .data_size = DATA_FRAME_SIZE, .desc_size = RXD_DESC_SIZE, - .priv_size = sizeof(struct queue_entry_priv_usb_rx), + .priv_size = sizeof(struct queue_entry_priv_usb), }; static const struct data_queue_desc rt73usb_queue_tx = { .entry_num = TX_ENTRIES, .data_size = DATA_FRAME_SIZE, .desc_size = TXD_DESC_SIZE, - .priv_size = sizeof(struct queue_entry_priv_usb_tx), + .priv_size = sizeof(struct queue_entry_priv_usb), }; static const struct data_queue_desc rt73usb_queue_bcn = { .entry_num = 4 * BEACON_ENTRIES, .data_size = MGMT_FRAME_SIZE, .desc_size = TXINFO_SIZE, - .priv_size = sizeof(struct queue_entry_priv_usb_tx), + .priv_size = sizeof(struct queue_entry_priv_usb), }; static const struct rt2x00_ops rt73usb_ops = { @@ -2106,6 +2067,7 @@ static const struct rt2x00_ops rt73usb_ops = { .max_ap_intf = 4, .eeprom_size = EEPROM_SIZE, .rf_size = RF_SIZE, + .tx_queues = NUM_TX_QUEUES, .rx = &rt73usb_queue_rx, .tx = &rt73usb_queue_tx, .bcn = &rt73usb_queue_bcn, diff --git a/drivers/net/wireless/rt2x00/rt73usb.h b/drivers/net/wireless/rt2x00/rt73usb.h index 06d687425fef..148493501011 100644 --- a/drivers/net/wireless/rt2x00/rt73usb.h +++ b/drivers/net/wireless/rt2x00/rt73usb.h @@ -39,8 +39,6 @@ * Signal information. * Defaul offset is required for RSSI <-> dBm conversion. */ -#define MAX_SIGNAL 100 -#define MAX_RX_SSI -1 #define DEFAULT_RSSI_OFFSET 120 /* @@ -54,6 +52,11 @@ #define RF_SIZE 0x0014 /* + * Number of TX queues. + */ +#define NUM_TX_QUEUES 4 + +/* * USB registers. */ diff --git a/drivers/net/wireless/rtl8180_dev.c b/drivers/net/wireless/rtl8180_dev.c index c181f23e930d..b7172a12c057 100644 --- a/drivers/net/wireless/rtl8180_dev.c +++ b/drivers/net/wireless/rtl8180_dev.c @@ -132,8 +132,8 @@ static void rtl8180_handle_rx(struct ieee80211_hw *dev) rx_status.antenna = (flags2 >> 15) & 1; /* TODO: improve signal/rssi reporting */ - rx_status.signal = flags2 & 0xFF; - rx_status.ssi = (flags2 >> 8) & 0x7F; + rx_status.qual = flags2 & 0xFF; + rx_status.signal = (flags2 >> 8) & 0x7F; /* XXX: is this correct? */ rx_status.rate_idx = (flags >> 20) & 0xF; rx_status.freq = dev->conf.channel->center_freq; @@ -170,34 +170,29 @@ static void rtl8180_handle_tx(struct ieee80211_hw *dev, unsigned int prio) while (skb_queue_len(&ring->queue)) { struct rtl8180_tx_desc *entry = &ring->desc[ring->idx]; struct sk_buff *skb; - struct ieee80211_tx_status status; - struct ieee80211_tx_control *control; + struct ieee80211_tx_info *info; u32 flags = le32_to_cpu(entry->flags); if (flags & RTL8180_TX_DESC_FLAG_OWN) return; - memset(&status, 0, sizeof(status)); - ring->idx = (ring->idx + 1) % ring->entries; skb = __skb_dequeue(&ring->queue); pci_unmap_single(priv->pdev, le32_to_cpu(entry->tx_buf), skb->len, PCI_DMA_TODEVICE); - control = *((struct ieee80211_tx_control **)skb->cb); - if (control) - memcpy(&status.control, control, sizeof(*control)); - kfree(control); + info = IEEE80211_SKB_CB(skb); + memset(&info->status, 0, sizeof(info->status)); - if (!(status.control.flags & IEEE80211_TXCTL_NO_ACK)) { + if (!(info->flags & IEEE80211_TX_CTL_NO_ACK)) { if (flags & RTL8180_TX_DESC_FLAG_TX_OK) - status.flags = IEEE80211_TX_STATUS_ACK; + info->flags |= IEEE80211_TX_STAT_ACK; else - status.excessive_retries = 1; + info->status.excessive_retries = 1; } - status.retry_count = flags & 0xFF; + info->status.retry_count = flags & 0xFF; - ieee80211_tx_status_irqsafe(dev, skb, &status); + ieee80211_tx_status_irqsafe(dev, skb); if (ring->entries - skb_queue_len(&ring->queue) == 2) ieee80211_wake_queue(dev, prio); } @@ -238,9 +233,9 @@ static irqreturn_t rtl8180_interrupt(int irq, void *dev_id) return IRQ_HANDLED; } -static int rtl8180_tx(struct ieee80211_hw *dev, struct sk_buff *skb, - struct ieee80211_tx_control *control) +static int rtl8180_tx(struct ieee80211_hw *dev, struct sk_buff *skb) { + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct rtl8180_priv *priv = dev->priv; struct rtl8180_tx_ring *ring; struct rtl8180_tx_desc *entry; @@ -251,46 +246,40 @@ static int rtl8180_tx(struct ieee80211_hw *dev, struct sk_buff *skb, u16 plcp_len = 0; __le16 rts_duration = 0; - prio = control->queue; + prio = skb_get_queue_mapping(skb); ring = &priv->tx_ring[prio]; mapping = pci_map_single(priv->pdev, skb->data, skb->len, PCI_DMA_TODEVICE); - BUG_ON(!control->tx_rate); - tx_flags = RTL8180_TX_DESC_FLAG_OWN | RTL8180_TX_DESC_FLAG_FS | RTL8180_TX_DESC_FLAG_LS | - (control->tx_rate->hw_value << 24) | skb->len; + (ieee80211_get_tx_rate(dev, info)->hw_value << 24) | + skb->len; if (priv->r8185) tx_flags |= RTL8180_TX_DESC_FLAG_DMA | RTL8180_TX_DESC_FLAG_NO_ENC; - if (control->flags & IEEE80211_TXCTL_USE_RTS_CTS) { - BUG_ON(!control->rts_cts_rate); + if (info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) { tx_flags |= RTL8180_TX_DESC_FLAG_RTS; - tx_flags |= control->rts_cts_rate->hw_value << 19; - } else if (control->flags & IEEE80211_TXCTL_USE_CTS_PROTECT) { - BUG_ON(!control->rts_cts_rate); + tx_flags |= ieee80211_get_rts_cts_rate(dev, info)->hw_value << 19; + } else if (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT) { tx_flags |= RTL8180_TX_DESC_FLAG_CTS; - tx_flags |= control->rts_cts_rate->hw_value << 19; + tx_flags |= ieee80211_get_rts_cts_rate(dev, info)->hw_value << 19; } - *((struct ieee80211_tx_control **) skb->cb) = - kmemdup(control, sizeof(*control), GFP_ATOMIC); - - if (control->flags & IEEE80211_TXCTL_USE_RTS_CTS) + if (info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) rts_duration = ieee80211_rts_duration(dev, priv->vif, skb->len, - control); + info); if (!priv->r8185) { unsigned int remainder; plcp_len = DIV_ROUND_UP(16 * (skb->len + 4), - (control->tx_rate->bitrate * 2) / 10); + (ieee80211_get_tx_rate(dev, info)->bitrate * 2) / 10); remainder = (16 * (skb->len + 4)) % - ((control->tx_rate->bitrate * 2) / 10); + ((ieee80211_get_tx_rate(dev, info)->bitrate * 2) / 10); if (remainder > 0 && remainder <= 6) plcp_len |= 1 << 15; } @@ -303,13 +292,13 @@ static int rtl8180_tx(struct ieee80211_hw *dev, struct sk_buff *skb, entry->plcp_len = cpu_to_le16(plcp_len); entry->tx_buf = cpu_to_le32(mapping); entry->frame_len = cpu_to_le32(skb->len); - entry->flags2 = control->alt_retry_rate != NULL ? - control->alt_retry_rate->bitrate << 4 : 0; - entry->retry_limit = control->retry_limit; + entry->flags2 = info->control.alt_retry_rate_idx >= 0 ? + ieee80211_get_alt_retry_rate(dev, info)->bitrate << 4 : 0; + entry->retry_limit = info->control.retry_limit; entry->flags = cpu_to_le32(tx_flags); __skb_queue_tail(&ring->queue, skb); if (ring->entries - skb_queue_len(&ring->queue) < 2) - ieee80211_stop_queue(dev, control->queue); + ieee80211_stop_queue(dev, skb_get_queue_mapping(skb)); spin_unlock_irqrestore(&priv->lock, flags); rtl818x_iowrite8(priv, &priv->map->TX_DMA_POLLING, (1 << (prio + 4))); @@ -525,7 +514,6 @@ static void rtl8180_free_tx_ring(struct ieee80211_hw *dev, unsigned int prio) pci_unmap_single(priv->pdev, le32_to_cpu(entry->tx_buf), skb->len, PCI_DMA_TODEVICE); - kfree(*((struct ieee80211_tx_control **) skb->cb)); kfree_skb(skb); ring->idx = (ring->idx + 1) % ring->entries; } @@ -894,9 +882,10 @@ static int __devinit rtl8180_probe(struct pci_dev *pdev, dev->wiphy->bands[IEEE80211_BAND_2GHZ] = &priv->band; dev->flags = IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | - IEEE80211_HW_RX_INCLUDES_FCS; + IEEE80211_HW_RX_INCLUDES_FCS | + IEEE80211_HW_SIGNAL_UNSPEC; dev->queues = 1; - dev->max_rssi = 65; + dev->max_signal = 65; reg = rtl818x_ioread32(priv, &priv->map->TX_CONF); reg &= RTL818X_TX_CONF_HWVER_MASK; diff --git a/drivers/net/wireless/rtl8187.h b/drivers/net/wireless/rtl8187.h index 076d88b6db0e..3afb49f8866a 100644 --- a/drivers/net/wireless/rtl8187.h +++ b/drivers/net/wireless/rtl8187.h @@ -44,23 +44,48 @@ struct rtl8187_rx_hdr { __le64 mac_time; } __attribute__((packed)); -struct rtl8187_tx_info { - struct ieee80211_tx_control *control; - struct urb *urb; - struct ieee80211_hw *dev; -}; - -struct rtl8187_tx_hdr { +struct rtl8187b_rx_hdr { __le32 flags; + __le64 mac_time; + u8 noise; + u8 signal; + u8 agc; + u8 reserved; + __le32 unused; +} __attribute__((packed)); + +/* {rtl8187,rtl8187b}_tx_info is in skb */ + +/* Tx flags are common between rtl8187 and rtl8187b */ #define RTL8187_TX_FLAG_NO_ENCRYPT (1 << 15) #define RTL8187_TX_FLAG_MORE_FRAG (1 << 17) #define RTL8187_TX_FLAG_CTS (1 << 18) #define RTL8187_TX_FLAG_RTS (1 << 23) + +struct rtl8187_tx_hdr { + __le32 flags; + __le16 rts_duration; + __le16 len; + __le32 retry; +} __attribute__((packed)); + +struct rtl8187b_tx_hdr { + __le32 flags; __le16 rts_duration; __le16 len; + __le32 unused_1; + __le16 unused_2; + __le16 tx_duration; + __le32 unused_3; __le32 retry; + __le32 unused_4[2]; } __attribute__((packed)); +enum { + DEVICE_RTL8187, + DEVICE_RTL8187B +}; + struct rtl8187_priv { /* common between rtl818x drivers */ struct rtl818x_csr *map; @@ -76,70 +101,120 @@ struct rtl8187_priv { u32 rx_conf; u16 txpwr_base; u8 asic_rev; + u8 is_rtl8187b; + enum { + RTL8187BvB, + RTL8187BvD, + RTL8187BvE + } hw_rev; struct sk_buff_head rx_queue; + u8 signal; + u8 quality; + u8 noise; }; void rtl8187_write_phy(struct ieee80211_hw *dev, u8 addr, u32 data); -static inline u8 rtl818x_ioread8(struct rtl8187_priv *priv, u8 *addr) +static inline u8 rtl818x_ioread8_idx(struct rtl8187_priv *priv, + u8 *addr, u8 idx) { u8 val; usb_control_msg(priv->udev, usb_rcvctrlpipe(priv->udev, 0), RTL8187_REQ_GET_REG, RTL8187_REQT_READ, - (unsigned long)addr, 0, &val, sizeof(val), HZ / 2); + (unsigned long)addr, idx & 0x03, &val, + sizeof(val), HZ / 2); return val; } -static inline u16 rtl818x_ioread16(struct rtl8187_priv *priv, __le16 *addr) +static inline u8 rtl818x_ioread8(struct rtl8187_priv *priv, u8 *addr) +{ + return rtl818x_ioread8_idx(priv, addr, 0); +} + +static inline u16 rtl818x_ioread16_idx(struct rtl8187_priv *priv, + __le16 *addr, u8 idx) { __le16 val; usb_control_msg(priv->udev, usb_rcvctrlpipe(priv->udev, 0), RTL8187_REQ_GET_REG, RTL8187_REQT_READ, - (unsigned long)addr, 0, &val, sizeof(val), HZ / 2); + (unsigned long)addr, idx & 0x03, &val, + sizeof(val), HZ / 2); return le16_to_cpu(val); } -static inline u32 rtl818x_ioread32(struct rtl8187_priv *priv, __le32 *addr) +static inline u16 rtl818x_ioread16(struct rtl8187_priv *priv, __le16 *addr) +{ + return rtl818x_ioread16_idx(priv, addr, 0); +} + +static inline u32 rtl818x_ioread32_idx(struct rtl8187_priv *priv, + __le32 *addr, u8 idx) { __le32 val; usb_control_msg(priv->udev, usb_rcvctrlpipe(priv->udev, 0), RTL8187_REQ_GET_REG, RTL8187_REQT_READ, - (unsigned long)addr, 0, &val, sizeof(val), HZ / 2); + (unsigned long)addr, idx & 0x03, &val, + sizeof(val), HZ / 2); return le32_to_cpu(val); } -static inline void rtl818x_iowrite8(struct rtl8187_priv *priv, - u8 *addr, u8 val) +static inline u32 rtl818x_ioread32(struct rtl8187_priv *priv, __le32 *addr) +{ + return rtl818x_ioread32_idx(priv, addr, 0); +} + +static inline void rtl818x_iowrite8_idx(struct rtl8187_priv *priv, + u8 *addr, u8 val, u8 idx) { usb_control_msg(priv->udev, usb_sndctrlpipe(priv->udev, 0), RTL8187_REQ_SET_REG, RTL8187_REQT_WRITE, - (unsigned long)addr, 0, &val, sizeof(val), HZ / 2); + (unsigned long)addr, idx & 0x03, &val, + sizeof(val), HZ / 2); +} + +static inline void rtl818x_iowrite8(struct rtl8187_priv *priv, u8 *addr, u8 val) +{ + rtl818x_iowrite8_idx(priv, addr, val, 0); } -static inline void rtl818x_iowrite16(struct rtl8187_priv *priv, - __le16 *addr, u16 val) +static inline void rtl818x_iowrite16_idx(struct rtl8187_priv *priv, + __le16 *addr, u16 val, u8 idx) { __le16 buf = cpu_to_le16(val); usb_control_msg(priv->udev, usb_sndctrlpipe(priv->udev, 0), RTL8187_REQ_SET_REG, RTL8187_REQT_WRITE, - (unsigned long)addr, 0, &buf, sizeof(buf), HZ / 2); + (unsigned long)addr, idx & 0x03, &buf, sizeof(buf), + HZ / 2); } -static inline void rtl818x_iowrite32(struct rtl8187_priv *priv, - __le32 *addr, u32 val) +static inline void rtl818x_iowrite16(struct rtl8187_priv *priv, __le16 *addr, + u16 val) +{ + rtl818x_iowrite16_idx(priv, addr, val, 0); +} + +static inline void rtl818x_iowrite32_idx(struct rtl8187_priv *priv, + __le32 *addr, u32 val, u8 idx) { __le32 buf = cpu_to_le32(val); usb_control_msg(priv->udev, usb_sndctrlpipe(priv->udev, 0), RTL8187_REQ_SET_REG, RTL8187_REQT_WRITE, - (unsigned long)addr, 0, &buf, sizeof(buf), HZ / 2); + (unsigned long)addr, idx & 0x03, &buf, sizeof(buf), + HZ / 2); +} + +static inline void rtl818x_iowrite32(struct rtl8187_priv *priv, __le32 *addr, + u32 val) +{ + rtl818x_iowrite32_idx(priv, addr, val, 0); } #endif /* RTL8187_H */ diff --git a/drivers/net/wireless/rtl8187_dev.c b/drivers/net/wireless/rtl8187_dev.c index 9223ada5f00e..d3067b1216ca 100644 --- a/drivers/net/wireless/rtl8187_dev.c +++ b/drivers/net/wireless/rtl8187_dev.c @@ -27,19 +27,21 @@ MODULE_AUTHOR("Michael Wu <flamingice@sourmilk.net>"); MODULE_AUTHOR("Andrea Merello <andreamrl@tiscali.it>"); -MODULE_DESCRIPTION("RTL8187 USB wireless driver"); +MODULE_DESCRIPTION("RTL8187/RTL8187B USB wireless driver"); MODULE_LICENSE("GPL"); static struct usb_device_id rtl8187_table[] __devinitdata = { /* Realtek */ - {USB_DEVICE(0x0bda, 0x8187)}, + {USB_DEVICE(0x0bda, 0x8187), .driver_info = DEVICE_RTL8187}, + {USB_DEVICE(0x0bda, 0x8189), .driver_info = DEVICE_RTL8187B}, + {USB_DEVICE(0x0bda, 0x8197), .driver_info = DEVICE_RTL8187B}, /* Netgear */ - {USB_DEVICE(0x0846, 0x6100)}, - {USB_DEVICE(0x0846, 0x6a00)}, + {USB_DEVICE(0x0846, 0x6100), .driver_info = DEVICE_RTL8187}, + {USB_DEVICE(0x0846, 0x6a00), .driver_info = DEVICE_RTL8187}, /* HP */ - {USB_DEVICE(0x03f0, 0xca02)}, + {USB_DEVICE(0x03f0, 0xca02), .driver_info = DEVICE_RTL8187}, /* Sitecom */ - {USB_DEVICE(0x0df6, 0x000d)}, + {USB_DEVICE(0x0df6, 0x000d), .driver_info = DEVICE_RTL8187}, {} }; @@ -150,27 +152,25 @@ void rtl8187_write_phy(struct ieee80211_hw *dev, u8 addr, u32 data) static void rtl8187_tx_cb(struct urb *urb) { - struct ieee80211_tx_status status; struct sk_buff *skb = (struct sk_buff *)urb->context; - struct rtl8187_tx_info *info = (struct rtl8187_tx_info *)skb->cb; - - memset(&status, 0, sizeof(status)); - - usb_free_urb(info->urb); - if (info->control) - memcpy(&status.control, info->control, sizeof(status.control)); - kfree(info->control); - skb_pull(skb, sizeof(struct rtl8187_tx_hdr)); - status.flags |= IEEE80211_TX_STATUS_ACK; - ieee80211_tx_status_irqsafe(info->dev, skb, &status); + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + struct ieee80211_hw *hw = info->driver_data[0]; + struct rtl8187_priv *priv = hw->priv; + + usb_free_urb(info->driver_data[1]); + skb_pull(skb, priv->is_rtl8187b ? sizeof(struct rtl8187b_tx_hdr) : + sizeof(struct rtl8187_tx_hdr)); + memset(&info->status, 0, sizeof(info->status)); + info->flags |= IEEE80211_TX_STAT_ACK; + ieee80211_tx_status_irqsafe(hw, skb); } -static int rtl8187_tx(struct ieee80211_hw *dev, struct sk_buff *skb, - struct ieee80211_tx_control *control) +static int rtl8187_tx(struct ieee80211_hw *dev, struct sk_buff *skb) { struct rtl8187_priv *priv = dev->priv; - struct rtl8187_tx_hdr *hdr; - struct rtl8187_tx_info *info; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + unsigned int ep; + void *buf; struct urb *urb; __le16 rts_dur = 0; u32 flags; @@ -185,35 +185,60 @@ static int rtl8187_tx(struct ieee80211_hw *dev, struct sk_buff *skb, flags = skb->len; flags |= RTL8187_TX_FLAG_NO_ENCRYPT; - BUG_ON(!control->tx_rate); - - flags |= control->tx_rate->hw_value << 24; - if (ieee80211_get_morefrag((struct ieee80211_hdr *)skb->data)) + flags |= ieee80211_get_tx_rate(dev, info)->hw_value << 24; + if (ieee80211_has_morefrags(((struct ieee80211_hdr *)skb->data)->frame_control)) flags |= RTL8187_TX_FLAG_MORE_FRAG; - if (control->flags & IEEE80211_TXCTL_USE_RTS_CTS) { - BUG_ON(!control->rts_cts_rate); + if (info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) { flags |= RTL8187_TX_FLAG_RTS; - flags |= control->rts_cts_rate->hw_value << 19; + flags |= ieee80211_get_rts_cts_rate(dev, info)->hw_value << 19; rts_dur = ieee80211_rts_duration(dev, priv->vif, - skb->len, control); - } else if (control->flags & IEEE80211_TXCTL_USE_CTS_PROTECT) { - BUG_ON(!control->rts_cts_rate); + skb->len, info); + } else if (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT) { flags |= RTL8187_TX_FLAG_CTS; - flags |= control->rts_cts_rate->hw_value << 19; + flags |= ieee80211_get_rts_cts_rate(dev, info)->hw_value << 19; } - hdr = (struct rtl8187_tx_hdr *)skb_push(skb, sizeof(*hdr)); - hdr->flags = cpu_to_le32(flags); - hdr->len = 0; - hdr->rts_duration = rts_dur; - hdr->retry = cpu_to_le32(control->retry_limit << 8); + if (!priv->is_rtl8187b) { + struct rtl8187_tx_hdr *hdr = + (struct rtl8187_tx_hdr *)skb_push(skb, sizeof(*hdr)); + hdr->flags = cpu_to_le32(flags); + hdr->len = 0; + hdr->rts_duration = rts_dur; + hdr->retry = cpu_to_le32(info->control.retry_limit << 8); + buf = hdr; - info = (struct rtl8187_tx_info *)skb->cb; - info->control = kmemdup(control, sizeof(*control), GFP_ATOMIC); - info->urb = urb; - info->dev = dev; - usb_fill_bulk_urb(urb, priv->udev, usb_sndbulkpipe(priv->udev, 2), - hdr, skb->len, rtl8187_tx_cb, skb); + ep = 2; + } else { + /* fc needs to be calculated before skb_push() */ + unsigned int epmap[4] = { 6, 7, 5, 4 }; + struct ieee80211_hdr *tx_hdr = + (struct ieee80211_hdr *)(skb->data); + u16 fc = le16_to_cpu(tx_hdr->frame_control); + + struct rtl8187b_tx_hdr *hdr = + (struct rtl8187b_tx_hdr *)skb_push(skb, sizeof(*hdr)); + struct ieee80211_rate *txrate = + ieee80211_get_tx_rate(dev, info); + memset(hdr, 0, sizeof(*hdr)); + hdr->flags = cpu_to_le32(flags); + hdr->rts_duration = rts_dur; + hdr->retry = cpu_to_le32(info->control.retry_limit << 8); + hdr->tx_duration = + ieee80211_generic_frame_duration(dev, priv->vif, + skb->len, txrate); + buf = hdr; + + if ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT) + ep = 12; + else + ep = epmap[skb_get_queue_mapping(skb)]; + } + + info->driver_data[0] = dev; + info->driver_data[1] = urb; + + usb_fill_bulk_urb(urb, priv->udev, usb_sndbulkpipe(priv->udev, ep), + buf, skb->len, rtl8187_tx_cb, skb); rc = usb_submit_urb(urb, GFP_ATOMIC); if (rc < 0) { usb_free_urb(urb); @@ -229,7 +254,6 @@ static void rtl8187_rx_cb(struct urb *urb) struct rtl8187_rx_info *info = (struct rtl8187_rx_info *)skb->cb; struct ieee80211_hw *dev = info->dev; struct rtl8187_priv *priv = dev->priv; - struct rtl8187_rx_hdr *hdr; struct ieee80211_rx_status rx_status = { 0 }; int rate, signal; u32 flags; @@ -250,11 +274,33 @@ static void rtl8187_rx_cb(struct urb *urb) } skb_put(skb, urb->actual_length); - hdr = (struct rtl8187_rx_hdr *)(skb_tail_pointer(skb) - sizeof(*hdr)); - flags = le32_to_cpu(hdr->flags); - skb_trim(skb, flags & 0x0FFF); + if (!priv->is_rtl8187b) { + struct rtl8187_rx_hdr *hdr = + (typeof(hdr))(skb_tail_pointer(skb) - sizeof(*hdr)); + flags = le32_to_cpu(hdr->flags); + signal = hdr->signal & 0x7f; + rx_status.antenna = (hdr->signal >> 7) & 1; + rx_status.signal = signal; + rx_status.noise = hdr->noise; + rx_status.mactime = le64_to_cpu(hdr->mac_time); + priv->signal = signal; + priv->quality = signal; + priv->noise = hdr->noise; + } else { + struct rtl8187b_rx_hdr *hdr = + (typeof(hdr))(skb_tail_pointer(skb) - sizeof(*hdr)); + flags = le32_to_cpu(hdr->flags); + signal = hdr->agc >> 1; + rx_status.antenna = (hdr->signal >> 7) & 1; + rx_status.signal = 64 - min(hdr->noise, (u8)64); + rx_status.noise = hdr->noise; + rx_status.mactime = le64_to_cpu(hdr->mac_time); + priv->signal = hdr->signal; + priv->quality = hdr->agc >> 1; + priv->noise = hdr->noise; + } - signal = hdr->agc >> 1; + skb_trim(skb, flags & 0x0FFF); rate = (flags >> 20) & 0xF; if (rate > 3) { /* OFDM rate */ if (signal > 90) @@ -270,13 +316,11 @@ static void rtl8187_rx_cb(struct urb *urb) signal = 95 - signal; } - rx_status.antenna = (hdr->signal >> 7) & 1; - rx_status.signal = 64 - min(hdr->noise, (u8)64); - rx_status.ssi = signal; + rx_status.qual = priv->quality; + rx_status.signal = signal; rx_status.rate_idx = rate; rx_status.freq = dev->conf.channel->center_freq; rx_status.band = dev->conf.channel->band; - rx_status.mactime = le64_to_cpu(hdr->mac_time); rx_status.flag |= RX_FLAG_TSFT; if (flags & (1 << 13)) rx_status.flag |= RX_FLAG_FAILED_FCS_CRC; @@ -316,7 +360,8 @@ static int rtl8187_init_urbs(struct ieee80211_hw *dev) break; } usb_fill_bulk_urb(entry, priv->udev, - usb_rcvbulkpipe(priv->udev, 1), + usb_rcvbulkpipe(priv->udev, + priv->is_rtl8187b ? 3 : 1), skb_tail_pointer(skb), RTL8187_MAX_RX, rtl8187_rx_cb, skb); info = (struct rtl8187_rx_info *)skb->cb; @@ -329,29 +374,12 @@ static int rtl8187_init_urbs(struct ieee80211_hw *dev) return 0; } -static int rtl8187_init_hw(struct ieee80211_hw *dev) +static int rtl8187_cmd_reset(struct ieee80211_hw *dev) { struct rtl8187_priv *priv = dev->priv; u8 reg; int i; - /* reset */ - rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG); - reg = rtl818x_ioread8(priv, &priv->map->CONFIG3); - rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg | RTL818X_CONFIG3_ANAPARAM_WRITE); - rtl818x_iowrite32(priv, &priv->map->ANAPARAM, RTL8225_ANAPARAM_ON); - rtl818x_iowrite32(priv, &priv->map->ANAPARAM2, RTL8225_ANAPARAM2_ON); - rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg & ~RTL818X_CONFIG3_ANAPARAM_WRITE); - rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL); - - rtl818x_iowrite16(priv, &priv->map->INT_MASK, 0); - - msleep(200); - rtl818x_iowrite8(priv, (u8 *)0xFE18, 0x10); - rtl818x_iowrite8(priv, (u8 *)0xFE18, 0x11); - rtl818x_iowrite8(priv, (u8 *)0xFE18, 0x00); - msleep(200); - reg = rtl818x_ioread8(priv, &priv->map->CMD); reg &= (1 << 1); reg |= RTL818X_CMD_RESET; @@ -387,12 +415,52 @@ static int rtl8187_init_hw(struct ieee80211_hw *dev) return -ETIMEDOUT; } + return 0; +} + +static int rtl8187_init_hw(struct ieee80211_hw *dev) +{ + struct rtl8187_priv *priv = dev->priv; + u8 reg; + int res; + + /* reset */ + rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, + RTL818X_EEPROM_CMD_CONFIG); + reg = rtl818x_ioread8(priv, &priv->map->CONFIG3); + rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg | + RTL818X_CONFIG3_ANAPARAM_WRITE); + rtl818x_iowrite32(priv, &priv->map->ANAPARAM, + RTL8187_RTL8225_ANAPARAM_ON); + rtl818x_iowrite32(priv, &priv->map->ANAPARAM2, + RTL8187_RTL8225_ANAPARAM2_ON); + rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg & + ~RTL818X_CONFIG3_ANAPARAM_WRITE); + rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, + RTL818X_EEPROM_CMD_NORMAL); + + rtl818x_iowrite16(priv, &priv->map->INT_MASK, 0); + + msleep(200); + rtl818x_iowrite8(priv, (u8 *)0xFE18, 0x10); + rtl818x_iowrite8(priv, (u8 *)0xFE18, 0x11); + rtl818x_iowrite8(priv, (u8 *)0xFE18, 0x00); + msleep(200); + + res = rtl8187_cmd_reset(dev); + if (res) + return res; + rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG); reg = rtl818x_ioread8(priv, &priv->map->CONFIG3); - rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg | RTL818X_CONFIG3_ANAPARAM_WRITE); - rtl818x_iowrite32(priv, &priv->map->ANAPARAM, RTL8225_ANAPARAM_ON); - rtl818x_iowrite32(priv, &priv->map->ANAPARAM2, RTL8225_ANAPARAM2_ON); - rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg & ~RTL818X_CONFIG3_ANAPARAM_WRITE); + rtl818x_iowrite8(priv, &priv->map->CONFIG3, + reg | RTL818X_CONFIG3_ANAPARAM_WRITE); + rtl818x_iowrite32(priv, &priv->map->ANAPARAM, + RTL8187_RTL8225_ANAPARAM_ON); + rtl818x_iowrite32(priv, &priv->map->ANAPARAM2, + RTL8187_RTL8225_ANAPARAM2_ON); + rtl818x_iowrite8(priv, &priv->map->CONFIG3, + reg & ~RTL818X_CONFIG3_ANAPARAM_WRITE); rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL); /* setup card */ @@ -437,9 +505,11 @@ static int rtl8187_init_hw(struct ieee80211_hw *dev) rtl818x_iowrite32(priv, &priv->map->RF_TIMING, 0x000a8008); rtl818x_iowrite16(priv, &priv->map->BRSR, 0xFFFF); rtl818x_iowrite32(priv, &priv->map->RF_PARA, 0x00100044); - rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG); + rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, + RTL818X_EEPROM_CMD_CONFIG); rtl818x_iowrite8(priv, &priv->map->CONFIG3, 0x44); - rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL); + rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, + RTL818X_EEPROM_CMD_NORMAL); rtl818x_iowrite16(priv, &priv->map->RFPinsEnable, 0x1FF7); msleep(100); @@ -456,16 +526,201 @@ static int rtl8187_init_hw(struct ieee80211_hw *dev) return 0; } +static const u8 rtl8187b_reg_table[][3] = { + {0xF0, 0x32, 0}, {0xF1, 0x32, 0}, {0xF2, 0x00, 0}, {0xF3, 0x00, 0}, + {0xF4, 0x32, 0}, {0xF5, 0x43, 0}, {0xF6, 0x00, 0}, {0xF7, 0x00, 0}, + {0xF8, 0x46, 0}, {0xF9, 0xA4, 0}, {0xFA, 0x00, 0}, {0xFB, 0x00, 0}, + {0xFC, 0x96, 0}, {0xFD, 0xA4, 0}, {0xFE, 0x00, 0}, {0xFF, 0x00, 0}, + + {0x58, 0x4B, 1}, {0x59, 0x00, 1}, {0x5A, 0x4B, 1}, {0x5B, 0x00, 1}, + {0x60, 0x4B, 1}, {0x61, 0x09, 1}, {0x62, 0x4B, 1}, {0x63, 0x09, 1}, + {0xCE, 0x0F, 1}, {0xCF, 0x00, 1}, {0xE0, 0xFF, 1}, {0xE1, 0x0F, 1}, + {0xE2, 0x00, 1}, {0xF0, 0x4E, 1}, {0xF1, 0x01, 1}, {0xF2, 0x02, 1}, + {0xF3, 0x03, 1}, {0xF4, 0x04, 1}, {0xF5, 0x05, 1}, {0xF6, 0x06, 1}, + {0xF7, 0x07, 1}, {0xF8, 0x08, 1}, + + {0x4E, 0x00, 2}, {0x0C, 0x04, 2}, {0x21, 0x61, 2}, {0x22, 0x68, 2}, + {0x23, 0x6F, 2}, {0x24, 0x76, 2}, {0x25, 0x7D, 2}, {0x26, 0x84, 2}, + {0x27, 0x8D, 2}, {0x4D, 0x08, 2}, {0x50, 0x05, 2}, {0x51, 0xF5, 2}, + {0x52, 0x04, 2}, {0x53, 0xA0, 2}, {0x54, 0x1F, 2}, {0x55, 0x23, 2}, + {0x56, 0x45, 2}, {0x57, 0x67, 2}, {0x58, 0x08, 2}, {0x59, 0x08, 2}, + {0x5A, 0x08, 2}, {0x5B, 0x08, 2}, {0x60, 0x08, 2}, {0x61, 0x08, 2}, + {0x62, 0x08, 2}, {0x63, 0x08, 2}, {0x64, 0xCF, 2}, {0x72, 0x56, 2}, + {0x73, 0x9A, 2}, + + {0x34, 0xF0, 0}, {0x35, 0x0F, 0}, {0x5B, 0x40, 0}, {0x84, 0x88, 0}, + {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}, + + {0x4C, 0x00, 2}, {0x9F, 0x00, 3}, {0x8C, 0x01, 0}, {0x8D, 0x10, 0}, + {0x8E, 0x08, 0}, {0x8F, 0x00, 0} +}; + +static int rtl8187b_init_hw(struct ieee80211_hw *dev) +{ + struct rtl8187_priv *priv = dev->priv; + int res, i; + u8 reg; + + rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, + RTL818X_EEPROM_CMD_CONFIG); + + reg = rtl818x_ioread8(priv, &priv->map->CONFIG3); + reg |= RTL818X_CONFIG3_ANAPARAM_WRITE | RTL818X_CONFIG3_GNT_SELECT; + rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg); + rtl818x_iowrite32(priv, &priv->map->ANAPARAM2, + RTL8187B_RTL8225_ANAPARAM2_ON); + rtl818x_iowrite32(priv, &priv->map->ANAPARAM, + RTL8187B_RTL8225_ANAPARAM_ON); + rtl818x_iowrite8(priv, &priv->map->ANAPARAM3, + RTL8187B_RTL8225_ANAPARAM3_ON); + + rtl818x_iowrite8(priv, (u8 *)0xFF61, 0x10); + reg = rtl818x_ioread8(priv, (u8 *)0xFF62); + rtl818x_iowrite8(priv, (u8 *)0xFF62, reg & ~(1 << 5)); + rtl818x_iowrite8(priv, (u8 *)0xFF62, reg | (1 << 5)); + + reg = rtl818x_ioread8(priv, &priv->map->CONFIG3); + reg &= ~RTL818X_CONFIG3_ANAPARAM_WRITE; + rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg); + + rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, + RTL818X_EEPROM_CMD_NORMAL); + + res = rtl8187_cmd_reset(dev); + if (res) + return res; + + rtl818x_iowrite16(priv, (__le16 *)0xFF2D, 0x0FFF); + reg = rtl818x_ioread8(priv, &priv->map->CW_CONF); + reg |= RTL818X_CW_CONF_PERPACKET_RETRY_SHIFT; + rtl818x_iowrite8(priv, &priv->map->CW_CONF, reg); + reg = rtl818x_ioread8(priv, &priv->map->TX_AGC_CTL); + reg |= RTL818X_TX_AGC_CTL_PERPACKET_GAIN_SHIFT | + RTL818X_TX_AGC_CTL_PERPACKET_ANTSEL_SHIFT; + rtl818x_iowrite8(priv, &priv->map->TX_AGC_CTL, reg); + + rtl818x_iowrite16_idx(priv, (__le16 *)0xFFE0, 0x0FFF, 1); + reg = rtl818x_ioread8(priv, &priv->map->RATE_FALLBACK); + reg |= RTL818X_RATE_FALLBACK_ENABLE; + rtl818x_iowrite8(priv, &priv->map->RATE_FALLBACK, reg); + + rtl818x_iowrite16(priv, &priv->map->BEACON_INTERVAL, 100); + rtl818x_iowrite16(priv, &priv->map->ATIM_WND, 2); + rtl818x_iowrite16_idx(priv, (__le16 *)0xFFD4, 0xFFFF, 1); + + rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, + RTL818X_EEPROM_CMD_CONFIG); + reg = rtl818x_ioread8(priv, &priv->map->CONFIG1); + rtl818x_iowrite8(priv, &priv->map->CONFIG1, (reg & 0x3F) | 0x80); + rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, + RTL818X_EEPROM_CMD_NORMAL); + + rtl818x_iowrite8(priv, &priv->map->WPA_CONF, 0); + for (i = 0; i < ARRAY_SIZE(rtl8187b_reg_table); i++) { + rtl818x_iowrite8_idx(priv, + (u8 *)(uintptr_t) + (rtl8187b_reg_table[i][0] | 0xFF00), + rtl8187b_reg_table[i][1], + rtl8187b_reg_table[i][2]); + } + + rtl818x_iowrite16(priv, &priv->map->TID_AC_MAP, 0xFA50); + rtl818x_iowrite16(priv, &priv->map->INT_MIG, 0); + + rtl818x_iowrite32_idx(priv, (__le32 *)0xFFF0, 0, 1); + rtl818x_iowrite32_idx(priv, (__le32 *)0xFFF4, 0, 1); + rtl818x_iowrite8_idx(priv, (u8 *)0xFFF8, 0, 1); + + rtl818x_iowrite32(priv, &priv->map->RF_TIMING, 0x00004001); + + rtl818x_iowrite16_idx(priv, (__le16 *)0xFF72, 0x569A, 2); + + rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, + RTL818X_EEPROM_CMD_CONFIG); + reg = rtl818x_ioread8(priv, &priv->map->CONFIG3); + reg |= RTL818X_CONFIG3_ANAPARAM_WRITE; + rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg); + rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, + RTL818X_EEPROM_CMD_NORMAL); + + rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, 0x0480); + rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, 0x2488); + rtl818x_iowrite16(priv, &priv->map->RFPinsEnable, 0x1FFF); + msleep(1100); + + priv->rf->init(dev); + + reg = RTL818X_CMD_TX_ENABLE | RTL818X_CMD_RX_ENABLE; + rtl818x_iowrite8(priv, &priv->map->CMD, reg); + rtl818x_iowrite16(priv, &priv->map->INT_MASK, 0xFFFF); + + rtl818x_iowrite8(priv, (u8 *)0xFE41, 0xF4); + rtl818x_iowrite8(priv, (u8 *)0xFE40, 0x00); + rtl818x_iowrite8(priv, (u8 *)0xFE42, 0x00); + rtl818x_iowrite8(priv, (u8 *)0xFE42, 0x01); + rtl818x_iowrite8(priv, (u8 *)0xFE40, 0x0F); + rtl818x_iowrite8(priv, (u8 *)0xFE42, 0x00); + rtl818x_iowrite8(priv, (u8 *)0xFE42, 0x01); + + reg = rtl818x_ioread8(priv, (u8 *)0xFFDB); + rtl818x_iowrite8(priv, (u8 *)0xFFDB, reg | (1 << 2)); + rtl818x_iowrite16_idx(priv, (__le16 *)0xFF72, 0x59FA, 3); + rtl818x_iowrite16_idx(priv, (__le16 *)0xFF74, 0x59D2, 3); + rtl818x_iowrite16_idx(priv, (__le16 *)0xFF76, 0x59D2, 3); + rtl818x_iowrite16_idx(priv, (__le16 *)0xFF78, 0x19FA, 3); + rtl818x_iowrite16_idx(priv, (__le16 *)0xFF7A, 0x19FA, 3); + rtl818x_iowrite16_idx(priv, (__le16 *)0xFF7C, 0x00D0, 3); + rtl818x_iowrite8(priv, (u8 *)0xFF61, 0); + rtl818x_iowrite8_idx(priv, (u8 *)0xFF80, 0x0F, 1); + rtl818x_iowrite8_idx(priv, (u8 *)0xFF83, 0x03, 1); + rtl818x_iowrite8(priv, (u8 *)0xFFDA, 0x10); + rtl818x_iowrite8_idx(priv, (u8 *)0xFF4D, 0x08, 2); + + rtl818x_iowrite32(priv, &priv->map->HSSI_PARA, 0x0600321B); + + rtl818x_iowrite16_idx(priv, (__le16 *)0xFFEC, 0x0800, 1); + + return 0; +} + static int rtl8187_start(struct ieee80211_hw *dev) { struct rtl8187_priv *priv = dev->priv; u32 reg; int ret; - ret = rtl8187_init_hw(dev); + ret = (!priv->is_rtl8187b) ? rtl8187_init_hw(dev) : + rtl8187b_init_hw(dev); if (ret) return ret; + if (priv->is_rtl8187b) { + reg = RTL818X_RX_CONF_MGMT | + RTL818X_RX_CONF_DATA | + RTL818X_RX_CONF_BROADCAST | + RTL818X_RX_CONF_NICMAC | + RTL818X_RX_CONF_BSSID | + (7 << 13 /* RX FIFO threshold NONE */) | + (7 << 10 /* MAX RX DMA */) | + RTL818X_RX_CONF_RX_AUTORESETPHY | + RTL818X_RX_CONF_ONLYERLPKT | + RTL818X_RX_CONF_MULTICAST; + priv->rx_conf = reg; + rtl818x_iowrite32(priv, &priv->map->RX_CONF, reg); + + rtl818x_iowrite32(priv, &priv->map->TX_CONF, + RTL818X_TX_CONF_HW_SEQNUM | + RTL818X_TX_CONF_DISREQQSIZE | + (7 << 8 /* short retry limit */) | + (7 << 0 /* long retry limit */) | + (7 << 21 /* MAX TX DMA */)); + rtl8187_init_urbs(dev); + return 0; + } + rtl818x_iowrite16(priv, &priv->map->INT_MASK, 0xFFFF); rtl818x_iowrite32(priv, &priv->map->MAR[0], ~0); @@ -592,18 +847,20 @@ static int rtl8187_config(struct ieee80211_hw *dev, struct ieee80211_conf *conf) msleep(10); rtl818x_iowrite32(priv, &priv->map->TX_CONF, reg); - rtl818x_iowrite8(priv, &priv->map->SIFS, 0x22); - - if (conf->flags & IEEE80211_CONF_SHORT_SLOT_TIME) { - rtl818x_iowrite8(priv, &priv->map->SLOT, 0x9); - rtl818x_iowrite8(priv, &priv->map->DIFS, 0x14); - rtl818x_iowrite8(priv, &priv->map->EIFS, 91 - 0x14); - rtl818x_iowrite8(priv, &priv->map->CW_VAL, 0x73); - } else { - rtl818x_iowrite8(priv, &priv->map->SLOT, 0x14); - rtl818x_iowrite8(priv, &priv->map->DIFS, 0x24); - rtl818x_iowrite8(priv, &priv->map->EIFS, 91 - 0x24); - rtl818x_iowrite8(priv, &priv->map->CW_VAL, 0xa5); + if (!priv->is_rtl8187b) { + rtl818x_iowrite8(priv, &priv->map->SIFS, 0x22); + + if (conf->flags & IEEE80211_CONF_SHORT_SLOT_TIME) { + rtl818x_iowrite8(priv, &priv->map->SLOT, 0x9); + rtl818x_iowrite8(priv, &priv->map->DIFS, 0x14); + rtl818x_iowrite8(priv, &priv->map->EIFS, 91 - 0x14); + rtl818x_iowrite8(priv, &priv->map->CW_VAL, 0x73); + } else { + rtl818x_iowrite8(priv, &priv->map->SLOT, 0x14); + rtl818x_iowrite8(priv, &priv->map->DIFS, 0x24); + rtl818x_iowrite8(priv, &priv->map->EIFS, 91 - 0x24); + rtl818x_iowrite8(priv, &priv->map->CW_VAL, 0xa5); + } } rtl818x_iowrite16(priv, &priv->map->ATIM_WND, 2); @@ -619,14 +876,20 @@ static int rtl8187_config_interface(struct ieee80211_hw *dev, { struct rtl8187_priv *priv = dev->priv; int i; + u8 reg; 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); + 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); + } return 0; } @@ -713,6 +976,7 @@ static int __devinit rtl8187_probe(struct usb_interface *intf, struct rtl8187_priv *priv; struct eeprom_93cx6 eeprom; struct ieee80211_channel *channel; + const char *chip_name; u16 txpwr, reg; int err, i; DECLARE_MAC_BUF(mac); @@ -724,6 +988,7 @@ static int __devinit rtl8187_probe(struct usb_interface *intf, } priv = dev->priv; + priv->is_rtl8187b = (id->driver_info == DEVICE_RTL8187B); SET_IEEE80211_DEV(dev, &intf->dev); usb_set_intfdata(intf, dev); @@ -750,11 +1015,9 @@ static int __devinit rtl8187_probe(struct usb_interface *intf, priv->mode = IEEE80211_IF_TYPE_MNTR; dev->flags = IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | - IEEE80211_HW_RX_INCLUDES_FCS; - dev->extra_tx_headroom = sizeof(struct rtl8187_tx_hdr); - dev->queues = 1; - dev->max_rssi = 65; - dev->max_signal = 64; + IEEE80211_HW_RX_INCLUDES_FCS | + IEEE80211_HW_SIGNAL_UNSPEC; + dev->max_signal = 65; eeprom.data = dev; eeprom.register_read = rtl8187_eeprom_register_read; @@ -788,12 +1051,6 @@ static int __devinit rtl8187_probe(struct usb_interface *intf, (*channel++).hw_value = txpwr & 0xFF; (*channel++).hw_value = txpwr >> 8; } - for (i = 0; i < 2; i++) { - eeprom_93cx6_read(&eeprom, RTL8187_EEPROM_TXPWR_CHAN_6 + i, - &txpwr); - (*channel++).hw_value = txpwr & 0xFF; - (*channel++).hw_value = txpwr >> 8; - } eeprom_93cx6_read(&eeprom, RTL8187_EEPROM_TXPWR_BASE, &priv->txpwr_base); @@ -807,7 +1064,90 @@ static int __devinit rtl8187_probe(struct usb_interface *intf, rtl818x_iowrite8(priv, &priv->map->PGSELECT, reg); rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL); + if (!priv->is_rtl8187b) { + u32 reg32; + reg32 = rtl818x_ioread32(priv, &priv->map->TX_CONF); + reg32 &= RTL818X_TX_CONF_HWVER_MASK; + switch (reg32) { + case RTL818X_TX_CONF_R8187vD_B: + /* Some RTL8187B devices have a USB ID of 0x8187 + * detect them here */ + chip_name = "RTL8187BvB(early)"; + priv->is_rtl8187b = 1; + priv->hw_rev = RTL8187BvB; + break; + case RTL818X_TX_CONF_R8187vD: + chip_name = "RTL8187vD"; + break; + default: + chip_name = "RTL8187vB (default)"; + } + } else { + /* + * Force USB request to write radio registers for 8187B, Realtek + * only uses it in their sources + */ + /*if (priv->asic_rev == 0) { + printk(KERN_WARNING "rtl8187: Forcing use of USB " + "requests to write to radio registers\n"); + priv->asic_rev = 1; + }*/ + switch (rtl818x_ioread8(priv, (u8 *)0xFFE1)) { + case RTL818X_R8187B_B: + chip_name = "RTL8187BvB"; + priv->hw_rev = RTL8187BvB; + break; + case RTL818X_R8187B_D: + chip_name = "RTL8187BvD"; + priv->hw_rev = RTL8187BvD; + break; + case RTL818X_R8187B_E: + chip_name = "RTL8187BvE"; + priv->hw_rev = RTL8187BvE; + break; + default: + chip_name = "RTL8187BvB (default)"; + priv->hw_rev = RTL8187BvB; + } + } + + if (!priv->is_rtl8187b) { + for (i = 0; i < 2; i++) { + eeprom_93cx6_read(&eeprom, + RTL8187_EEPROM_TXPWR_CHAN_6 + i, + &txpwr); + (*channel++).hw_value = txpwr & 0xFF; + (*channel++).hw_value = txpwr >> 8; + } + } else { + eeprom_93cx6_read(&eeprom, RTL8187_EEPROM_TXPWR_CHAN_6, + &txpwr); + (*channel++).hw_value = txpwr & 0xFF; + + eeprom_93cx6_read(&eeprom, 0x0A, &txpwr); + (*channel++).hw_value = txpwr & 0xFF; + + eeprom_93cx6_read(&eeprom, 0x1C, &txpwr); + (*channel++).hw_value = txpwr & 0xFF; + (*channel++).hw_value = txpwr >> 8; + } + + if (priv->is_rtl8187b) + printk(KERN_WARNING "rtl8187: 8187B chip detected. Support " + "is EXPERIMENTAL, and could damage your\n" + " hardware, use at your own risk\n"); + if ((id->driver_info == DEVICE_RTL8187) && priv->is_rtl8187b) + printk(KERN_INFO "rtl8187: inconsistency between id with OEM" + " info!\n"); + priv->rf = rtl8187_detect_rf(dev); + dev->extra_tx_headroom = (!priv->is_rtl8187b) ? + sizeof(struct rtl8187_tx_hdr) : + sizeof(struct rtl8187b_tx_hdr); + if (!priv->is_rtl8187b) + dev->queues = 1; + else + dev->queues = 4; err = ieee80211_register_hw(dev); if (err) { @@ -815,9 +1155,9 @@ static int __devinit rtl8187_probe(struct usb_interface *intf, goto err_free_dev; } - printk(KERN_INFO "%s: hwaddr %s, rtl8187 V%d + %s\n", + printk(KERN_INFO "%s: hwaddr %s, %s V%d + %s\n", wiphy_name(dev->wiphy), print_mac(mac, dev->wiphy->perm_addr), - priv->asic_rev, priv->rf->name); + chip_name, priv->asic_rev, priv->rf->name); return 0; @@ -847,7 +1187,7 @@ static struct usb_driver rtl8187_driver = { .name = KBUILD_MODNAME, .id_table = rtl8187_table, .probe = rtl8187_probe, - .disconnect = rtl8187_disconnect, + .disconnect = __devexit_p(rtl8187_disconnect), }; static int __init rtl8187_init(void) diff --git a/drivers/net/wireless/rtl8187_rtl8225.c b/drivers/net/wireless/rtl8187_rtl8225.c index 9146387b4c5e..1bae89903410 100644 --- a/drivers/net/wireless/rtl8187_rtl8225.c +++ b/drivers/net/wireless/rtl8187_rtl8225.c @@ -305,9 +305,12 @@ static void rtl8225_rf_set_tx_power(struct ieee80211_hw *dev, int channel) /* anaparam2 on */ rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG); reg = rtl818x_ioread8(priv, &priv->map->CONFIG3); - rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg | RTL818X_CONFIG3_ANAPARAM_WRITE); - rtl818x_iowrite32(priv, &priv->map->ANAPARAM2, RTL8225_ANAPARAM2_ON); - rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg & ~RTL818X_CONFIG3_ANAPARAM_WRITE); + rtl818x_iowrite8(priv, &priv->map->CONFIG3, + reg | RTL818X_CONFIG3_ANAPARAM_WRITE); + rtl818x_iowrite32(priv, &priv->map->ANAPARAM2, + RTL8187_RTL8225_ANAPARAM2_ON); + rtl818x_iowrite8(priv, &priv->map->CONFIG3, + reg & ~RTL818X_CONFIG3_ANAPARAM_WRITE); rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL); rtl8225_write_phy_ofdm(dev, 2, 0x42); @@ -471,12 +474,42 @@ static void rtl8225_rf_init(struct ieee80211_hw *dev) rtl8225_write_phy_cck(dev, 0x41, rtl8225_threshold[2]); } +static const u8 rtl8225z2_agc[] = { + 0x5e, 0x5e, 0x5e, 0x5e, 0x5d, 0x5b, 0x59, 0x57, 0x55, 0x53, 0x51, 0x4f, + 0x4d, 0x4b, 0x49, 0x47, 0x45, 0x43, 0x41, 0x3f, 0x3d, 0x3b, 0x39, 0x37, + 0x35, 0x33, 0x31, 0x2f, 0x2d, 0x2b, 0x29, 0x27, 0x25, 0x23, 0x21, 0x1f, + 0x1d, 0x1b, 0x19, 0x17, 0x15, 0x13, 0x11, 0x0f, 0x0d, 0x0b, 0x09, 0x07, + 0x05, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, + 0x19, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x26, 0x27, 0x27, 0x28, + 0x28, 0x29, 0x2a, 0x2a, 0x2a, 0x2b, 0x2b, 0x2b, 0x2c, 0x2c, 0x2c, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2e, 0x2e, 0x2e, 0x2e, 0x2f, 0x2f, 0x2f, 0x30, 0x30, + 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, + 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31 +}; +static const u8 rtl8225z2_ofdm[] = { + 0x10, 0x0d, 0x01, 0x00, 0x14, 0xfb, 0xfb, 0x60, + 0x00, 0x60, 0x00, 0x00, 0x00, 0x5c, 0x00, 0x00, + 0x40, 0x00, 0x40, 0x00, 0x00, 0x00, 0xa8, 0x26, + 0x32, 0x33, 0x07, 0xa5, 0x6f, 0x55, 0xc8, 0xb3, + 0x0a, 0xe1, 0x2C, 0x8a, 0x86, 0x83, 0x34, 0x0f, + 0x4f, 0x24, 0x6f, 0xc2, 0x6b, 0x40, 0x80, 0x00, + 0xc0, 0xc1, 0x58, 0xf1, 0x00, 0xe4, 0x90, 0x3e, + 0x6d, 0x3c, 0xfb, 0x07 +}; + static const u8 rtl8225z2_tx_power_cck_ch14[] = { - 0x36, 0x35, 0x2e, 0x1b, 0x00, 0x00, 0x00, 0x00 + 0x36, 0x35, 0x2e, 0x1b, 0x00, 0x00, 0x00, 0x00, + 0x30, 0x2f, 0x29, 0x15, 0x00, 0x00, 0x00, 0x00, + 0x30, 0x2f, 0x29, 0x15, 0x00, 0x00, 0x00, 0x00, + 0x30, 0x2f, 0x29, 0x15, 0x00, 0x00, 0x00, 0x00 }; static const u8 rtl8225z2_tx_power_cck[] = { - 0x36, 0x35, 0x2e, 0x25, 0x1c, 0x12, 0x09, 0x04 + 0x36, 0x35, 0x2e, 0x25, 0x1c, 0x12, 0x09, 0x04, + 0x30, 0x2f, 0x29, 0x21, 0x19, 0x10, 0x08, 0x03, + 0x2b, 0x2a, 0x25, 0x1e, 0x16, 0x0e, 0x07, 0x03, + 0x26, 0x25, 0x21, 0x1b, 0x14, 0x0d, 0x06, 0x03 }; static const u8 rtl8225z2_tx_power_ofdm[] = { @@ -526,9 +559,12 @@ static void rtl8225z2_rf_set_tx_power(struct ieee80211_hw *dev, int channel) /* anaparam2 on */ rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG); reg = rtl818x_ioread8(priv, &priv->map->CONFIG3); - rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg | RTL818X_CONFIG3_ANAPARAM_WRITE); - rtl818x_iowrite32(priv, &priv->map->ANAPARAM2, RTL8225_ANAPARAM2_ON); - rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg & ~RTL818X_CONFIG3_ANAPARAM_WRITE); + rtl818x_iowrite8(priv, &priv->map->CONFIG3, + reg | RTL818X_CONFIG3_ANAPARAM_WRITE); + rtl818x_iowrite32(priv, &priv->map->ANAPARAM2, + RTL8187_RTL8225_ANAPARAM2_ON); + rtl818x_iowrite8(priv, &priv->map->CONFIG3, + reg & ~RTL818X_CONFIG3_ANAPARAM_WRITE); rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL); rtl8225_write_phy_ofdm(dev, 2, 0x42); @@ -542,6 +578,85 @@ static void rtl8225z2_rf_set_tx_power(struct ieee80211_hw *dev, int channel) msleep(1); } +static void rtl8225z2_b_rf_set_tx_power(struct ieee80211_hw *dev, int channel) +{ + struct rtl8187_priv *priv = dev->priv; + u8 cck_power, ofdm_power; + const u8 *tmp; + int i; + + cck_power = priv->channels[channel - 1].hw_value & 0xF; + ofdm_power = priv->channels[channel - 1].hw_value >> 4; + + if (cck_power > 15) + cck_power = (priv->hw_rev == RTL8187BvB) ? 15 : 22; + else + cck_power += (priv->hw_rev == RTL8187BvB) ? 0 : 7; + cck_power += priv->txpwr_base & 0xF; + cck_power = min(cck_power, (u8)35); + + if (ofdm_power > 15) + ofdm_power = (priv->hw_rev == RTL8187BvB) ? 17 : 25; + else + ofdm_power += (priv->hw_rev == RTL8187BvB) ? 2 : 10; + ofdm_power += (priv->txpwr_base >> 4) & 0xF; + ofdm_power = min(ofdm_power, (u8)35); + + if (channel == 14) + tmp = rtl8225z2_tx_power_cck_ch14; + else + tmp = rtl8225z2_tx_power_cck; + + if (priv->hw_rev == RTL8187BvB) { + if (cck_power <= 6) + ; /* do nothing */ + else if (cck_power <= 11) + tmp += 8; + else + tmp += 16; + } else { + if (cck_power <= 5) + ; /* do nothing */ + else if (cck_power <= 11) + tmp += 8; + else if (cck_power <= 17) + tmp += 16; + else + tmp += 24; + } + + for (i = 0; i < 8; i++) + rtl8225_write_phy_cck(dev, 0x44 + i, *tmp++); + + rtl818x_iowrite8(priv, &priv->map->TX_GAIN_CCK, + rtl8225z2_tx_gain_cck_ofdm[cck_power]); + msleep(1); + + rtl818x_iowrite8(priv, &priv->map->TX_GAIN_OFDM, + rtl8225z2_tx_gain_cck_ofdm[ofdm_power] << 1); + if (priv->hw_rev == RTL8187BvB) { + if (ofdm_power <= 11) { + rtl8225_write_phy_ofdm(dev, 0x87, 0x60); + rtl8225_write_phy_ofdm(dev, 0x89, 0x60); + } else { + rtl8225_write_phy_ofdm(dev, 0x87, 0x5c); + rtl8225_write_phy_ofdm(dev, 0x89, 0x5c); + } + } else { + if (ofdm_power <= 11) { + rtl8225_write_phy_ofdm(dev, 0x87, 0x5c); + rtl8225_write_phy_ofdm(dev, 0x89, 0x5c); + } else if (ofdm_power <= 17) { + rtl8225_write_phy_ofdm(dev, 0x87, 0x54); + rtl8225_write_phy_ofdm(dev, 0x89, 0x54); + } else { + rtl8225_write_phy_ofdm(dev, 0x87, 0x50); + rtl8225_write_phy_ofdm(dev, 0x89, 0x50); + } + } + msleep(1); +} + static const u16 rtl8225z2_rxgain[] = { 0x0400, 0x0401, 0x0402, 0x0403, 0x0404, 0x0405, 0x0408, 0x0409, 0x040a, 0x040b, 0x0502, 0x0503, 0x0504, 0x0505, 0x0540, 0x0541, @@ -715,6 +830,81 @@ static void rtl8225z2_rf_init(struct ieee80211_hw *dev) rtl818x_iowrite32(priv, (__le32 *)0xFF94, 0x3dc00002); } +static void rtl8225z2_b_rf_init(struct ieee80211_hw *dev) +{ + struct rtl8187_priv *priv = dev->priv; + int i; + + rtl8225_write(dev, 0x0, 0x0B7); msleep(1); + rtl8225_write(dev, 0x1, 0xEE0); msleep(1); + rtl8225_write(dev, 0x2, 0x44D); msleep(1); + rtl8225_write(dev, 0x3, 0x441); msleep(1); + rtl8225_write(dev, 0x4, 0x8C3); msleep(1); + rtl8225_write(dev, 0x5, 0xC72); msleep(1); + rtl8225_write(dev, 0x6, 0x0E6); msleep(1); + rtl8225_write(dev, 0x7, 0x82A); msleep(1); + rtl8225_write(dev, 0x8, 0x03F); msleep(1); + rtl8225_write(dev, 0x9, 0x335); msleep(1); + rtl8225_write(dev, 0xa, 0x9D4); msleep(1); + rtl8225_write(dev, 0xb, 0x7BB); msleep(1); + rtl8225_write(dev, 0xc, 0x850); msleep(1); + rtl8225_write(dev, 0xd, 0xCDF); msleep(1); + rtl8225_write(dev, 0xe, 0x02B); msleep(1); + rtl8225_write(dev, 0xf, 0x114); msleep(1); + + rtl8225_write(dev, 0x0, 0x1B7); msleep(1); + + for (i = 0; i < ARRAY_SIZE(rtl8225z2_rxgain); i++) { + rtl8225_write(dev, 0x1, i + 1); msleep(1); + rtl8225_write(dev, 0x2, rtl8225z2_rxgain[i]); msleep(1); + } + + rtl8225_write(dev, 0x3, 0x080); msleep(1); + rtl8225_write(dev, 0x5, 0x004); msleep(1); + rtl8225_write(dev, 0x0, 0x0B7); msleep(1); + msleep(3000); + + rtl8225_write(dev, 0x2, 0xC4D); msleep(1); + msleep(2000); + + rtl8225_write(dev, 0x2, 0x44D); msleep(1); + rtl8225_write(dev, 0x0, 0x2BF); msleep(1); + + rtl818x_iowrite8(priv, &priv->map->TX_GAIN_CCK, 0x03); + rtl818x_iowrite8(priv, &priv->map->TX_GAIN_OFDM, 0x07); + rtl818x_iowrite8(priv, &priv->map->TX_ANTENNA, 0x03); + + rtl8225_write_phy_ofdm(dev, 0x80, 0x12); + for (i = 0; i < ARRAY_SIZE(rtl8225z2_agc); i++) { + rtl8225_write_phy_ofdm(dev, 0xF, rtl8225z2_agc[i]); + rtl8225_write_phy_ofdm(dev, 0xE, 0x80 + i); + rtl8225_write_phy_ofdm(dev, 0xE, 0); + } + rtl8225_write_phy_ofdm(dev, 0x80, 0x10); + + for (i = 0; i < ARRAY_SIZE(rtl8225z2_ofdm); i++) + rtl8225_write_phy_ofdm(dev, i, rtl8225z2_ofdm[i]); + + rtl818x_iowrite8(priv, &priv->map->SIFS, 0x22); + rtl818x_iowrite8(priv, &priv->map->SLOT, 9); + rtl818x_iowrite8(priv, (u8 *)0xFFF0, 28); + rtl818x_iowrite8(priv, (u8 *)0xFFF4, 28); + rtl818x_iowrite8(priv, (u8 *)0xFFF8, 28); + rtl818x_iowrite8(priv, (u8 *)0xFFFC, 28); + rtl818x_iowrite8(priv, (u8 *)0xFF2D, 0x5B); + rtl818x_iowrite8(priv, (u8 *)0xFF79, 0x5B); + rtl818x_iowrite32(priv, (__le32 *)0xFFF0, (7 << 12) | (3 << 8) | 28); + rtl818x_iowrite32(priv, (__le32 *)0xFFF4, (7 << 12) | (3 << 8) | 28); + rtl818x_iowrite32(priv, (__le32 *)0xFFF8, (7 << 12) | (3 << 8) | 28); + rtl818x_iowrite32(priv, (__le32 *)0xFFFC, (7 << 12) | (3 << 8) | 28); + rtl818x_iowrite8(priv, &priv->map->ACM_CONTROL, 0); + + rtl8225_write_phy_ofdm(dev, 0x97, 0x46); msleep(1); + rtl8225_write_phy_ofdm(dev, 0xa4, 0xb6); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x85, 0xfc); msleep(1); + rtl8225_write_phy_cck(dev, 0xc1, 0x88); msleep(1); +} + static void rtl8225_rf_stop(struct ieee80211_hw *dev) { u8 reg; @@ -725,8 +915,19 @@ static void rtl8225_rf_stop(struct ieee80211_hw *dev) rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG); reg = rtl818x_ioread8(priv, &priv->map->CONFIG3); rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg | RTL818X_CONFIG3_ANAPARAM_WRITE); - rtl818x_iowrite32(priv, &priv->map->ANAPARAM2, RTL8225_ANAPARAM2_OFF); - rtl818x_iowrite32(priv, &priv->map->ANAPARAM, RTL8225_ANAPARAM_OFF); + if (!priv->is_rtl8187b) { + rtl818x_iowrite32(priv, &priv->map->ANAPARAM2, + RTL8187_RTL8225_ANAPARAM2_OFF); + rtl818x_iowrite32(priv, &priv->map->ANAPARAM, + RTL8187_RTL8225_ANAPARAM_OFF); + } else { + rtl818x_iowrite32(priv, &priv->map->ANAPARAM2, + RTL8187B_RTL8225_ANAPARAM2_OFF); + rtl818x_iowrite32(priv, &priv->map->ANAPARAM, + RTL8187B_RTL8225_ANAPARAM_OFF); + rtl818x_iowrite8(priv, &priv->map->ANAPARAM3, + RTL8187B_RTL8225_ANAPARAM3_OFF); + } rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg & ~RTL818X_CONFIG3_ANAPARAM_WRITE); rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL); } @@ -739,8 +940,10 @@ static void rtl8225_rf_set_channel(struct ieee80211_hw *dev, if (priv->rf->init == rtl8225_rf_init) rtl8225_rf_set_tx_power(dev, chan); - else + else if (priv->rf->init == rtl8225z2_rf_init) rtl8225z2_rf_set_tx_power(dev, chan); + else + rtl8225z2_b_rf_set_tx_power(dev, chan); rtl8225_write(dev, 0x7, rtl8225_chan[chan - 1]); msleep(10); @@ -760,19 +963,30 @@ static const struct rtl818x_rf_ops rtl8225z2_ops = { .set_chan = rtl8225_rf_set_channel }; +static const struct rtl818x_rf_ops rtl8225z2_b_ops = { + .name = "rtl8225z2", + .init = rtl8225z2_b_rf_init, + .stop = rtl8225_rf_stop, + .set_chan = rtl8225_rf_set_channel +}; + const struct rtl818x_rf_ops * rtl8187_detect_rf(struct ieee80211_hw *dev) { u16 reg8, reg9; + struct rtl8187_priv *priv = dev->priv; - rtl8225_write(dev, 0, 0x1B7); + if (!priv->is_rtl8187b) { + rtl8225_write(dev, 0, 0x1B7); - reg8 = rtl8225_read(dev, 8); - reg9 = rtl8225_read(dev, 9); + reg8 = rtl8225_read(dev, 8); + reg9 = rtl8225_read(dev, 9); - rtl8225_write(dev, 0, 0x0B7); + rtl8225_write(dev, 0, 0x0B7); - if (reg8 != 0x588 || reg9 != 0x700) - return &rtl8225_ops; + if (reg8 != 0x588 || reg9 != 0x700) + return &rtl8225_ops; - return &rtl8225z2_ops; + return &rtl8225z2_ops; + } else + return &rtl8225z2_b_ops; } diff --git a/drivers/net/wireless/rtl8187_rtl8225.h b/drivers/net/wireless/rtl8187_rtl8225.h index d39ed0295b6e..20c5b6ead0f6 100644 --- a/drivers/net/wireless/rtl8187_rtl8225.h +++ b/drivers/net/wireless/rtl8187_rtl8225.h @@ -15,10 +15,17 @@ #ifndef RTL8187_RTL8225_H #define RTL8187_RTL8225_H -#define RTL8225_ANAPARAM_ON 0xa0000a59 -#define RTL8225_ANAPARAM2_ON 0x860c7312 -#define RTL8225_ANAPARAM_OFF 0xa00beb59 -#define RTL8225_ANAPARAM2_OFF 0x840dec11 +#define RTL8187_RTL8225_ANAPARAM_ON 0xa0000a59 +#define RTL8187_RTL8225_ANAPARAM2_ON 0x860c7312 +#define RTL8187_RTL8225_ANAPARAM_OFF 0xa00beb59 +#define RTL8187_RTL8225_ANAPARAM2_OFF 0x840dec11 + +#define RTL8187B_RTL8225_ANAPARAM_ON 0x45090658 +#define RTL8187B_RTL8225_ANAPARAM2_ON 0x727f3f52 +#define RTL8187B_RTL8225_ANAPARAM3_ON 0x00 +#define RTL8187B_RTL8225_ANAPARAM_OFF 0x55480658 +#define RTL8187B_RTL8225_ANAPARAM2_OFF 0x72003f50 +#define RTL8187B_RTL8225_ANAPARAM3_OFF 0x00 const struct rtl818x_rf_ops * rtl8187_detect_rf(struct ieee80211_hw *); diff --git a/drivers/net/wireless/rtl818x.h b/drivers/net/wireless/rtl818x.h index 4f7d38f506eb..00900fe16fce 100644 --- a/drivers/net/wireless/rtl818x.h +++ b/drivers/net/wireless/rtl818x.h @@ -66,7 +66,10 @@ struct rtl818x_csr { #define RTL818X_TX_CONF_R8180_F (3 << 25) #define RTL818X_TX_CONF_R8185_ABC (4 << 25) #define RTL818X_TX_CONF_R8185_D (5 << 25) +#define RTL818X_TX_CONF_R8187vD (5 << 25) +#define RTL818X_TX_CONF_R8187vD_B (6 << 25) #define RTL818X_TX_CONF_HWVER_MASK (7 << 25) +#define RTL818X_TX_CONF_DISREQQSIZE (1 << 28) #define RTL818X_TX_CONF_PROBE_DTS (1 << 29) #define RTL818X_TX_CONF_HW_SEQNUM (1 << 30) #define RTL818X_TX_CONF_CW_MIN (1 << 31) @@ -106,8 +109,11 @@ struct rtl818x_csr { #define RTL818X_MSR_NO_LINK (0 << 2) #define RTL818X_MSR_ADHOC (1 << 2) #define RTL818X_MSR_INFRA (2 << 2) +#define RTL818X_MSR_MASTER (3 << 2) +#define RTL818X_MSR_ENEDCA (4 << 2) u8 CONFIG3; #define RTL818X_CONFIG3_ANAPARAM_WRITE (1 << 6) +#define RTL818X_CONFIG3_GNT_SELECT (1 << 7) u8 CONFIG4; #define RTL818X_CONFIG4_POWEROFF (1 << 6) #define RTL818X_CONFIG4_VCOOFF (1 << 7) @@ -133,7 +139,9 @@ struct rtl818x_csr { __le32 RF_TIMING; u8 GP_ENABLE; u8 GPIO; - u8 reserved_12[10]; + u8 reserved_12[2]; + __le32 HSSI_PARA; + u8 reserved_13[4]; u8 TX_AGC_CTL; #define RTL818X_TX_AGC_CTL_PERPACKET_GAIN_SHIFT (1 << 0) #define RTL818X_TX_AGC_CTL_PERPACKET_ANTSEL_SHIFT (1 << 1) @@ -141,29 +149,39 @@ struct rtl818x_csr { u8 TX_GAIN_CCK; u8 TX_GAIN_OFDM; u8 TX_ANTENNA; - u8 reserved_13[16]; + u8 reserved_14[16]; u8 WPA_CONF; - u8 reserved_14[3]; + u8 reserved_15[3]; u8 SIFS; u8 DIFS; u8 SLOT; - u8 reserved_15[5]; + u8 reserved_16[5]; u8 CW_CONF; #define RTL818X_CW_CONF_PERPACKET_CW_SHIFT (1 << 0) #define RTL818X_CW_CONF_PERPACKET_RETRY_SHIFT (1 << 1) u8 CW_VAL; u8 RATE_FALLBACK; - u8 reserved_16[25]; +#define RTL818X_RATE_FALLBACK_ENABLE (1 << 7) + u8 ACM_CONTROL; + u8 reserved_17[24]; u8 CONFIG5; u8 TX_DMA_POLLING; - u8 reserved_17[2]; + u8 reserved_18[2]; __le16 CWR; u8 RETRY_CTR; - u8 reserved_18[5]; + u8 reserved_19[3]; + __le16 INT_MIG; +/* RTL818X_R8187B_*: magic numbers from ioregisters */ +#define RTL818X_R8187B_B 0 +#define RTL818X_R8187B_D 1 +#define RTL818X_R8187B_E 2 __le32 RDSAR; - u8 reserved_19[12]; - __le16 FEMR; + __le16 TID_AC_MAP; u8 reserved_20[4]; + u8 ANAPARAM3; + u8 reserved_21[5]; + __le16 FEMR; + u8 reserved_22[4]; __le16 TALLY_CNT; u8 TALLY_SEL; } __attribute__((packed)); diff --git a/drivers/net/wireless/strip.c b/drivers/net/wireless/strip.c index 883af891ebfb..417e9e675fac 100644 --- a/drivers/net/wireless/strip.c +++ b/drivers/net/wireless/strip.c @@ -2728,7 +2728,7 @@ static int strip_ioctl(struct tty_struct *tty, struct file *file, /************************************************************************/ /* Initialization */ -static struct tty_ldisc strip_ldisc = { +static struct tty_ldisc_ops strip_ldisc = { .magic = TTY_LDISC_MAGIC, .name = "strip", .owner = THIS_MODULE, diff --git a/drivers/net/wireless/wl3501_cs.c b/drivers/net/wireless/wl3501_cs.c index 42a36b3f3ff7..377141995e36 100644 --- a/drivers/net/wireless/wl3501_cs.c +++ b/drivers/net/wireless/wl3501_cs.c @@ -1624,25 +1624,25 @@ static int wl3501_get_scan(struct net_device *dev, struct iw_request_info *info, iwe.cmd = SIOCGIWAP; iwe.u.ap_addr.sa_family = ARPHRD_ETHER; memcpy(iwe.u.ap_addr.sa_data, this->bss_set[i].bssid, ETH_ALEN); - current_ev = iwe_stream_add_event(current_ev, + current_ev = iwe_stream_add_event(info, current_ev, extra + IW_SCAN_MAX_DATA, &iwe, IW_EV_ADDR_LEN); iwe.cmd = SIOCGIWESSID; iwe.u.data.flags = 1; iwe.u.data.length = this->bss_set[i].ssid.el.len; - current_ev = iwe_stream_add_point(current_ev, + current_ev = iwe_stream_add_point(info, current_ev, extra + IW_SCAN_MAX_DATA, &iwe, this->bss_set[i].ssid.essid); iwe.cmd = SIOCGIWMODE; iwe.u.mode = this->bss_set[i].bss_type; - current_ev = iwe_stream_add_event(current_ev, + current_ev = iwe_stream_add_event(info, current_ev, extra + IW_SCAN_MAX_DATA, &iwe, IW_EV_UINT_LEN); iwe.cmd = SIOCGIWFREQ; iwe.u.freq.m = this->bss_set[i].ds_pset.chan; iwe.u.freq.e = 0; - current_ev = iwe_stream_add_event(current_ev, + current_ev = iwe_stream_add_event(info, current_ev, extra + IW_SCAN_MAX_DATA, &iwe, IW_EV_FREQ_LEN); iwe.cmd = SIOCGIWENCODE; @@ -1651,7 +1651,7 @@ static int wl3501_get_scan(struct net_device *dev, struct iw_request_info *info, else iwe.u.data.flags = IW_ENCODE_DISABLED; iwe.u.data.length = 0; - current_ev = iwe_stream_add_point(current_ev, + current_ev = iwe_stream_add_point(info, current_ev, extra + IW_SCAN_MAX_DATA, &iwe, NULL); } diff --git a/drivers/net/wireless/zd1201.c b/drivers/net/wireless/zd1201.c index 78baa0f7926d..b16ec6e5f0e3 100644 --- a/drivers/net/wireless/zd1201.c +++ b/drivers/net/wireless/zd1201.c @@ -1152,32 +1152,36 @@ static int zd1201_get_scan(struct net_device *dev, iwe.cmd = SIOCGIWAP; iwe.u.ap_addr.sa_family = ARPHRD_ETHER; memcpy(iwe.u.ap_addr.sa_data, zd->rxdata+i+6, 6); - cev = iwe_stream_add_event(cev, end_buf, &iwe, IW_EV_ADDR_LEN); + cev = iwe_stream_add_event(info, cev, end_buf, + &iwe, IW_EV_ADDR_LEN); iwe.cmd = SIOCGIWESSID; iwe.u.data.length = zd->rxdata[i+16]; iwe.u.data.flags = 1; - cev = iwe_stream_add_point(cev, end_buf, &iwe, zd->rxdata+i+18); + cev = iwe_stream_add_point(info, cev, end_buf, + &iwe, zd->rxdata+i+18); iwe.cmd = SIOCGIWMODE; if (zd->rxdata[i+14]&0x01) iwe.u.mode = IW_MODE_MASTER; else iwe.u.mode = IW_MODE_ADHOC; - cev = iwe_stream_add_event(cev, end_buf, &iwe, IW_EV_UINT_LEN); + cev = iwe_stream_add_event(info, cev, end_buf, + &iwe, IW_EV_UINT_LEN); iwe.cmd = SIOCGIWFREQ; iwe.u.freq.m = zd->rxdata[i+0]; iwe.u.freq.e = 0; - cev = iwe_stream_add_event(cev, end_buf, &iwe, IW_EV_FREQ_LEN); + cev = iwe_stream_add_event(info, cev, end_buf, + &iwe, IW_EV_FREQ_LEN); iwe.cmd = SIOCGIWRATE; iwe.u.bitrate.fixed = 0; iwe.u.bitrate.disabled = 0; for (j=0; j<10; j++) if (zd->rxdata[i+50+j]) { iwe.u.bitrate.value = (zd->rxdata[i+50+j]&0x7f)*500000; - cev=iwe_stream_add_event(cev, end_buf, &iwe, - IW_EV_PARAM_LEN); + cev = iwe_stream_add_event(info, cev, end_buf, + &iwe, IW_EV_PARAM_LEN); } iwe.cmd = SIOCGIWENCODE; @@ -1186,14 +1190,15 @@ static int zd1201_get_scan(struct net_device *dev, iwe.u.data.flags = IW_ENCODE_ENABLED; else iwe.u.data.flags = IW_ENCODE_DISABLED; - cev = iwe_stream_add_point(cev, end_buf, &iwe, NULL); + cev = iwe_stream_add_point(info, cev, end_buf, &iwe, NULL); iwe.cmd = IWEVQUAL; iwe.u.qual.qual = zd->rxdata[i+4]; iwe.u.qual.noise= zd->rxdata[i+2]/10-100; iwe.u.qual.level = (256+zd->rxdata[i+4]*100)/255-100; iwe.u.qual.updated = 7; - cev = iwe_stream_add_event(cev, end_buf, &iwe, IW_EV_QUAL_LEN); + cev = iwe_stream_add_event(info, cev, end_buf, + &iwe, IW_EV_QUAL_LEN); } if (!enabled_save) diff --git a/drivers/net/wireless/zd1211rw/zd_mac.c b/drivers/net/wireless/zd1211rw/zd_mac.c index 694e95d35fd4..fcc532bb6a7e 100644 --- a/drivers/net/wireless/zd1211rw/zd_mac.c +++ b/drivers/net/wireless/zd1211rw/zd_mac.c @@ -224,36 +224,6 @@ out: return r; } -/** - * clear_tx_skb_control_block - clears the control block of tx skbuffs - * @skb: a &struct sk_buff pointer - * - * This clears the control block of skbuff buffers, which were transmitted to - * the device. Notify that the function is not thread-safe, so prevent - * multiple calls. - */ -static void clear_tx_skb_control_block(struct sk_buff *skb) -{ - struct zd_tx_skb_control_block *cb = - (struct zd_tx_skb_control_block *)skb->cb; - - kfree(cb->control); - cb->control = NULL; -} - -/** - * kfree_tx_skb - frees a tx skbuff - * @skb: a &struct sk_buff pointer - * - * Frees the tx skbuff. Frees also the allocated control structure in the - * control block if necessary. - */ -static void kfree_tx_skb(struct sk_buff *skb) -{ - clear_tx_skb_control_block(skb); - dev_kfree_skb_any(skb); -} - static void zd_op_stop(struct ieee80211_hw *hw) { struct zd_mac *mac = zd_hw_mac(hw); @@ -276,40 +246,15 @@ static void zd_op_stop(struct ieee80211_hw *hw) while ((skb = skb_dequeue(ack_wait_queue))) - kfree_tx_skb(skb); -} - -/** - * init_tx_skb_control_block - initializes skb control block - * @skb: a &sk_buff pointer - * @dev: pointer to the mac80221 device - * @control: mac80211 tx control applying for the frame in @skb - * - * Initializes the control block of the skbuff to be transmitted. - */ -static int init_tx_skb_control_block(struct sk_buff *skb, - struct ieee80211_hw *hw, - struct ieee80211_tx_control *control) -{ - struct zd_tx_skb_control_block *cb = - (struct zd_tx_skb_control_block *)skb->cb; - - ZD_ASSERT(sizeof(*cb) <= sizeof(skb->cb)); - memset(cb, 0, sizeof(*cb)); - cb->hw= hw; - cb->control = kmalloc(sizeof(*control), GFP_ATOMIC); - if (cb->control == NULL) - return -ENOMEM; - memcpy(cb->control, control, sizeof(*control)); - - return 0; + dev_kfree_skb_any(skb); } /** * tx_status - reports tx status of a packet if required * @hw - a &struct ieee80211_hw pointer * @skb - a sk-buffer - * @status - the tx status of the packet without control information + * @flags: extra flags to set in the TX status info + * @ackssi: ACK signal strength * @success - True for successfull transmission of the frame * * This information calls ieee80211_tx_status_irqsafe() if required by the @@ -319,18 +264,17 @@ static int init_tx_skb_control_block(struct sk_buff *skb, * If no status information has been requested, the skb is freed. */ static void tx_status(struct ieee80211_hw *hw, struct sk_buff *skb, - struct ieee80211_tx_status *status, - bool success) + u32 flags, int ackssi, bool success) { - struct zd_tx_skb_control_block *cb = (struct zd_tx_skb_control_block *) - skb->cb; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + + memset(&info->status, 0, sizeof(info->status)); - ZD_ASSERT(cb->control != NULL); - memcpy(&status->control, cb->control, sizeof(status->control)); if (!success) - status->excessive_retries = 1; - clear_tx_skb_control_block(skb); - ieee80211_tx_status_irqsafe(hw, skb, status); + info->status.excessive_retries = 1; + info->flags |= flags; + info->status.ack_signal = ackssi; + ieee80211_tx_status_irqsafe(hw, skb); } /** @@ -345,15 +289,12 @@ void zd_mac_tx_failed(struct ieee80211_hw *hw) { struct sk_buff_head *q = &zd_hw_mac(hw)->ack_wait_queue; struct sk_buff *skb; - struct ieee80211_tx_status status; skb = skb_dequeue(q); if (skb == NULL) return; - memset(&status, 0, sizeof(status)); - - tx_status(hw, skb, &status, 0); + tx_status(hw, skb, 0, 0, 0); } /** @@ -368,28 +309,20 @@ void zd_mac_tx_failed(struct ieee80211_hw *hw) */ void zd_mac_tx_to_dev(struct sk_buff *skb, int error) { - struct zd_tx_skb_control_block *cb = - (struct zd_tx_skb_control_block *)skb->cb; - struct ieee80211_hw *hw = cb->hw; - - if (likely(cb->control)) { - skb_pull(skb, sizeof(struct zd_ctrlset)); - if (unlikely(error || - (cb->control->flags & IEEE80211_TXCTL_NO_ACK))) - { - struct ieee80211_tx_status status; - memset(&status, 0, sizeof(status)); - tx_status(hw, skb, &status, !error); - } else { - struct sk_buff_head *q = - &zd_hw_mac(hw)->ack_wait_queue; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + struct ieee80211_hw *hw = info->driver_data[0]; - skb_queue_tail(q, skb); - while (skb_queue_len(q) > ZD_MAC_MAX_ACK_WAITERS) - zd_mac_tx_failed(hw); - } + skb_pull(skb, sizeof(struct zd_ctrlset)); + if (unlikely(error || + (info->flags & IEEE80211_TX_CTL_NO_ACK))) { + tx_status(hw, skb, 0, 0, !error); } else { - kfree_tx_skb(skb); + struct sk_buff_head *q = + &zd_hw_mac(hw)->ack_wait_queue; + + skb_queue_tail(q, skb); + while (skb_queue_len(q) > ZD_MAC_MAX_ACK_WAITERS) + zd_mac_tx_failed(hw); } } @@ -443,8 +376,6 @@ static int zd_calc_tx_length_us(u8 *service, u8 zd_rate, u16 tx_length) static void cs_set_control(struct zd_mac *mac, struct zd_ctrlset *cs, struct ieee80211_hdr *header, u32 flags) { - u16 fctl = le16_to_cpu(header->frame_control); - /* * CONTROL TODO: * - if backoff needed, enable bit 0 @@ -454,7 +385,7 @@ static void cs_set_control(struct zd_mac *mac, struct zd_ctrlset *cs, cs->control = 0; /* First fragment */ - if (flags & IEEE80211_TXCTL_FIRST_FRAGMENT) + if (flags & IEEE80211_TX_CTL_FIRST_FRAGMENT) cs->control |= ZD_CS_NEED_RANDOM_BACKOFF; /* Multicast */ @@ -462,79 +393,104 @@ static void cs_set_control(struct zd_mac *mac, struct zd_ctrlset *cs, cs->control |= ZD_CS_MULTICAST; /* PS-POLL */ - if ((fctl & (IEEE80211_FCTL_FTYPE|IEEE80211_FCTL_STYPE)) == - (IEEE80211_FTYPE_CTL|IEEE80211_STYPE_PSPOLL)) + if (ieee80211_is_pspoll(header->frame_control)) cs->control |= ZD_CS_PS_POLL_FRAME; - if (flags & IEEE80211_TXCTL_USE_RTS_CTS) + if (flags & IEEE80211_TX_CTL_USE_RTS_CTS) cs->control |= ZD_CS_RTS; - if (flags & IEEE80211_TXCTL_USE_CTS_PROTECT) + if (flags & IEEE80211_TX_CTL_USE_CTS_PROTECT) cs->control |= ZD_CS_SELF_CTS; /* FIXME: Management frame? */ } -void zd_mac_config_beacon(struct ieee80211_hw *hw, struct sk_buff *beacon) +static int zd_mac_config_beacon(struct ieee80211_hw *hw, struct sk_buff *beacon) { struct zd_mac *mac = zd_hw_mac(hw); + int r; u32 tmp, j = 0; /* 4 more bytes for tail CRC */ u32 full_len = beacon->len + 4; - zd_iowrite32(&mac->chip, CR_BCN_FIFO_SEMAPHORE, 0); - zd_ioread32(&mac->chip, CR_BCN_FIFO_SEMAPHORE, &tmp); + + r = zd_iowrite32(&mac->chip, CR_BCN_FIFO_SEMAPHORE, 0); + if (r < 0) + return r; + r = zd_ioread32(&mac->chip, CR_BCN_FIFO_SEMAPHORE, &tmp); + if (r < 0) + return r; + while (tmp & 0x2) { - zd_ioread32(&mac->chip, CR_BCN_FIFO_SEMAPHORE, &tmp); + r = zd_ioread32(&mac->chip, CR_BCN_FIFO_SEMAPHORE, &tmp); + if (r < 0) + return r; if ((++j % 100) == 0) { printk(KERN_ERR "CR_BCN_FIFO_SEMAPHORE not ready\n"); if (j >= 500) { printk(KERN_ERR "Giving up beacon config.\n"); - return; + return -ETIMEDOUT; } } msleep(1); } - zd_iowrite32(&mac->chip, CR_BCN_FIFO, full_len - 1); - if (zd_chip_is_zd1211b(&mac->chip)) - zd_iowrite32(&mac->chip, CR_BCN_LENGTH, full_len - 1); + r = zd_iowrite32(&mac->chip, CR_BCN_FIFO, full_len - 1); + if (r < 0) + return r; + if (zd_chip_is_zd1211b(&mac->chip)) { + r = zd_iowrite32(&mac->chip, CR_BCN_LENGTH, full_len - 1); + if (r < 0) + return r; + } - for (j = 0 ; j < beacon->len; j++) - zd_iowrite32(&mac->chip, CR_BCN_FIFO, + for (j = 0 ; j < beacon->len; j++) { + r = zd_iowrite32(&mac->chip, CR_BCN_FIFO, *((u8 *)(beacon->data + j))); + if (r < 0) + return r; + } + + for (j = 0; j < 4; j++) { + r = zd_iowrite32(&mac->chip, CR_BCN_FIFO, 0x0); + if (r < 0) + return r; + } - for (j = 0; j < 4; j++) - zd_iowrite32(&mac->chip, CR_BCN_FIFO, 0x0); + r = zd_iowrite32(&mac->chip, CR_BCN_FIFO_SEMAPHORE, 1); + if (r < 0) + return r; - zd_iowrite32(&mac->chip, CR_BCN_FIFO_SEMAPHORE, 1); /* 802.11b/g 2.4G CCK 1Mb * 802.11a, not yet implemented, uses different values (see GPL vendor * driver) */ - zd_iowrite32(&mac->chip, CR_BCN_PLCP_CFG, 0x00000400 | + return zd_iowrite32(&mac->chip, CR_BCN_PLCP_CFG, 0x00000400 | (full_len << 19)); } static int fill_ctrlset(struct zd_mac *mac, - struct sk_buff *skb, - struct ieee80211_tx_control *control) + struct sk_buff *skb) { int r; struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; unsigned int frag_len = skb->len + FCS_LEN; unsigned int packet_length; + struct ieee80211_rate *txrate; struct zd_ctrlset *cs = (struct zd_ctrlset *) skb_push(skb, sizeof(struct zd_ctrlset)); + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); ZD_ASSERT(frag_len <= 0xffff); - cs->modulation = control->tx_rate->hw_value; - if (control->flags & IEEE80211_TXCTL_SHORT_PREAMBLE) - cs->modulation = control->tx_rate->hw_value_short; + txrate = ieee80211_get_tx_rate(mac->hw, info); + + cs->modulation = txrate->hw_value; + if (info->flags & IEEE80211_TX_CTL_SHORT_PREAMBLE) + cs->modulation = txrate->hw_value_short; cs->tx_length = cpu_to_le16(frag_len); - cs_set_control(mac, cs, hdr, control->flags); + cs_set_control(mac, cs, hdr, info->flags); packet_length = frag_len + sizeof(struct zd_ctrlset) + 10; ZD_ASSERT(packet_length <= 0xffff); @@ -579,24 +535,21 @@ static int fill_ctrlset(struct zd_mac *mac, * control block of the skbuff will be initialized. If necessary the incoming * mac80211 queues will be stopped. */ -static int zd_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb, - struct ieee80211_tx_control *control) +static int zd_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb) { struct zd_mac *mac = zd_hw_mac(hw); + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); int r; - r = fill_ctrlset(mac, skb, control); + r = fill_ctrlset(mac, skb); if (r) return r; - r = init_tx_skb_control_block(skb, hw, control); - if (r) - return r; + info->driver_data[0] = hw; + r = zd_usb_tx(&mac->chip.usb, skb); - if (r) { - clear_tx_skb_control_block(skb); + if (r) return r; - } return 0; } @@ -617,13 +570,11 @@ static int zd_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb, static int filter_ack(struct ieee80211_hw *hw, struct ieee80211_hdr *rx_hdr, struct ieee80211_rx_status *stats) { - u16 fc = le16_to_cpu(rx_hdr->frame_control); struct sk_buff *skb; struct sk_buff_head *q; unsigned long flags; - if ((fc & (IEEE80211_FCTL_FTYPE | IEEE80211_FCTL_STYPE)) != - (IEEE80211_FTYPE_CTL | IEEE80211_STYPE_ACK)) + if (!ieee80211_is_ack(rx_hdr->frame_control)) return 0; q = &zd_hw_mac(hw)->ack_wait_queue; @@ -634,13 +585,8 @@ static int filter_ack(struct ieee80211_hw *hw, struct ieee80211_hdr *rx_hdr, tx_hdr = (struct ieee80211_hdr *)skb->data; if (likely(!compare_ether_addr(tx_hdr->addr2, rx_hdr->addr1))) { - struct ieee80211_tx_status status; - - memset(&status, 0, sizeof(status)); - status.flags = IEEE80211_TX_STATUS_ACK; - status.ack_signal = stats->ssi; __skb_unlink(skb, q); - tx_status(hw, skb, &status, 1); + tx_status(hw, skb, IEEE80211_TX_STAT_ACK, stats->signal, 1); goto out; } } @@ -656,8 +602,8 @@ int zd_mac_rx(struct ieee80211_hw *hw, const u8 *buffer, unsigned int length) const struct rx_status *status; struct sk_buff *skb; int bad_frame = 0; - u16 fc; - bool is_qos, is_4addr, need_padding; + __le16 fc; + int need_padding; int i; u8 rate; @@ -691,8 +637,8 @@ int zd_mac_rx(struct ieee80211_hw *hw, const u8 *buffer, unsigned int length) stats.freq = zd_channels[_zd_chip_get_channel(&mac->chip) - 1].center_freq; stats.band = IEEE80211_BAND_2GHZ; - stats.ssi = status->signal_strength; - stats.signal = zd_rx_qual_percent(buffer, + stats.signal = status->signal_strength; + stats.qual = zd_rx_qual_percent(buffer, length - sizeof(struct rx_status), status); @@ -716,13 +662,8 @@ int zd_mac_rx(struct ieee80211_hw *hw, const u8 *buffer, unsigned int length) && !mac->pass_ctrl) return 0; - fc = le16_to_cpu(*((__le16 *) buffer)); - - is_qos = ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA) && - (fc & IEEE80211_STYPE_QOS_DATA); - is_4addr = (fc & (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) == - (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS); - need_padding = is_qos ^ is_4addr; + fc = *(__le16 *)buffer; + need_padding = ieee80211_is_data_qos(fc) ^ ieee80211_has_a4(fc); skb = dev_alloc_skb(length + (need_padding ? 2 : 0)); if (skb == NULL) @@ -751,6 +692,7 @@ static int zd_op_add_interface(struct ieee80211_hw *hw, case IEEE80211_IF_TYPE_MNTR: case IEEE80211_IF_TYPE_MESH_POINT: case IEEE80211_IF_TYPE_STA: + case IEEE80211_IF_TYPE_IBSS: mac->type = conf->type; break; default: @@ -781,14 +723,24 @@ static int zd_op_config_interface(struct ieee80211_hw *hw, { struct zd_mac *mac = zd_hw_mac(hw); int associated; + int r; - if (mac->type == IEEE80211_IF_TYPE_MESH_POINT) { + if (mac->type == IEEE80211_IF_TYPE_MESH_POINT || + mac->type == IEEE80211_IF_TYPE_IBSS) { associated = true; - if (conf->beacon) { - zd_mac_config_beacon(hw, conf->beacon); - kfree_skb(conf->beacon); - zd_set_beacon_interval(&mac->chip, BCN_MODE_IBSS | + 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); + if (r < 0) + return r; + r = zd_set_beacon_interval(&mac->chip, BCN_MODE_IBSS | hw->conf.beacon_int); + if (r < 0) + return r; + kfree_skb(beacon); } } else associated = is_valid_ether_addr(conf->bssid); @@ -983,10 +935,10 @@ struct ieee80211_hw *zd_mac_alloc_hw(struct usb_interface *intf) hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &mac->band; hw->flags = IEEE80211_HW_RX_INCLUDES_FCS | - IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE; - hw->max_rssi = 100; - hw->max_signal = 100; + IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE | + IEEE80211_HW_SIGNAL_DB; + hw->max_signal = 100; hw->queues = 1; hw->extra_tx_headroom = sizeof(struct zd_ctrlset); diff --git a/drivers/net/wireless/zd1211rw/zd_mac.h b/drivers/net/wireless/zd1211rw/zd_mac.h index 71170244d2c9..18c1d56d3dd7 100644 --- a/drivers/net/wireless/zd1211rw/zd_mac.h +++ b/drivers/net/wireless/zd1211rw/zd_mac.h @@ -149,22 +149,6 @@ struct housekeeping { struct delayed_work link_led_work; }; -/** - * struct zd_tx_skb_control_block - control block for tx skbuffs - * @control: &struct ieee80211_tx_control pointer - * @context: context pointer - * - * This structure is used to fill the cb field in an &sk_buff to transmit. - * The control field is NULL, if there is no requirement from the mac80211 - * stack to report about the packet ACK. This is the case if the flag - * IEEE80211_TXCTL_NO_ACK is not set in &struct ieee80211_tx_control. - */ -struct zd_tx_skb_control_block { - struct ieee80211_tx_control *control; - struct ieee80211_hw *hw; - void *context; -}; - #define ZD_MAC_STATS_BUFFER_SIZE 16 #define ZD_MAC_MAX_ACK_WAITERS 10 diff --git a/drivers/net/wireless/zd1211rw/zd_usb.c b/drivers/net/wireless/zd1211rw/zd_usb.c index 6cdad9764604..da8b7433e3a6 100644 --- a/drivers/net/wireless/zd1211rw/zd_usb.c +++ b/drivers/net/wireless/zd1211rw/zd_usb.c @@ -170,10 +170,11 @@ static int upload_code(struct usb_device *udev, if (flags & REBOOT) { u8 ret; + /* Use "DMA-aware" buffer. */ r = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), USB_REQ_FIRMWARE_CONFIRM, USB_DIR_IN | USB_TYPE_VENDOR, - 0, 0, &ret, sizeof(ret), 5000 /* ms */); + 0, 0, p, sizeof(ret), 5000 /* ms */); if (r != sizeof(ret)) { dev_err(&udev->dev, "control request firmeware confirmation failed." @@ -182,6 +183,7 @@ static int upload_code(struct usb_device *udev, r = -ENODEV; goto error; } + ret = p[0]; if (ret & 0x80) { dev_err(&udev->dev, "Internal error while downloading." @@ -313,22 +315,31 @@ int zd_usb_read_fw(struct zd_usb *usb, zd_addr_t addr, u8 *data, u16 len) { int r; struct usb_device *udev = zd_usb_to_usbdev(usb); + u8 *buf; + /* Use "DMA-aware" buffer. */ + buf = kmalloc(len, GFP_KERNEL); + if (!buf) + return -ENOMEM; r = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), USB_REQ_FIRMWARE_READ_DATA, USB_DIR_IN | 0x40, addr, 0, - data, len, 5000); + buf, len, 5000); if (r < 0) { dev_err(&udev->dev, "read over firmware interface failed: %d\n", r); - return r; + goto exit; } else if (r != len) { dev_err(&udev->dev, "incomplete read over firmware interface: %d/%d\n", r, len); - return -EIO; + r = -EIO; + goto exit; } - - return 0; + r = 0; + memcpy(data, buf, len); +exit: + kfree(buf); + return r; } #define urb_dev(urb) (&(urb)->dev->dev) @@ -870,7 +881,7 @@ static void tx_urb_complete(struct urb *urb) { int r; struct sk_buff *skb; - struct zd_tx_skb_control_block *cb; + struct ieee80211_tx_info *info; struct zd_usb *usb; switch (urb->status) { @@ -894,8 +905,8 @@ free_urb: * grab 'usb' pointer before handing off the skb (since * it might be freed by zd_mac_tx_to_dev or mac80211) */ - cb = (struct zd_tx_skb_control_block *)skb->cb; - usb = &zd_hw_mac(cb->hw)->chip.usb; + info = IEEE80211_SKB_CB(skb); + usb = &zd_hw_mac(info->driver_data[0])->chip.usb; zd_mac_tx_to_dev(skb, urb->status); free_tx_urb(usb, urb); tx_dec_submitted_urbs(usb); diff --git a/drivers/net/xen-netfront.c b/drivers/net/xen-netfront.c index ef671d1a3bf0..902bbe788215 100644 --- a/drivers/net/xen-netfront.c +++ b/drivers/net/xen-netfront.c @@ -92,7 +92,7 @@ struct netfront_info { */ union skb_entry { struct sk_buff *skb; - unsigned link; + unsigned long link; } tx_skbs[NET_TX_RING_SIZE]; grant_ref_t gref_tx_head; grant_ref_t grant_tx_ref[NET_TX_RING_SIZE]; @@ -125,6 +125,17 @@ struct netfront_rx_info { struct xen_netif_extra_info extras[XEN_NETIF_EXTRA_TYPE_MAX - 1]; }; +static void skb_entry_set_link(union skb_entry *list, unsigned short id) +{ + list->link = id; +} + +static int skb_entry_is_link(const union skb_entry *list) +{ + BUILD_BUG_ON(sizeof(list->skb) != sizeof(list->link)); + return ((unsigned long)list->skb < PAGE_OFFSET); +} + /* * Access macros for acquiring freeing slots in tx_skbs[]. */ @@ -132,7 +143,7 @@ struct netfront_rx_info { static void add_id_to_freelist(unsigned *head, union skb_entry *list, unsigned short id) { - list[id].link = *head; + skb_entry_set_link(&list[id], *head); *head = id; } @@ -993,7 +1004,7 @@ static void xennet_release_tx_bufs(struct netfront_info *np) for (i = 0; i < NET_TX_RING_SIZE; i++) { /* Skip over entries which are actually freelist references */ - if ((unsigned long)np->tx_skbs[i].skb < PAGE_OFFSET) + if (skb_entry_is_link(&np->tx_skbs[i])) continue; skb = np->tx_skbs[i].skb; @@ -1123,7 +1134,7 @@ static struct net_device * __devinit xennet_create_dev(struct xenbus_device *dev /* Initialise tx_skbs as a free chain containing every entry. */ np->tx_skb_freelist = 0; for (i = 0; i < NET_TX_RING_SIZE; i++) { - np->tx_skbs[i].link = i+1; + skb_entry_set_link(&np->tx_skbs[i], i+1); np->grant_tx_ref[i] = GRANT_INVALID_REF; } diff --git a/drivers/pci/intel-iommu.c b/drivers/pci/intel-iommu.c index 3f7b81c065d2..8d0e60ac849c 100644 --- a/drivers/pci/intel-iommu.c +++ b/drivers/pci/intel-iommu.c @@ -37,7 +37,7 @@ #include "intel-iommu.h" #include <asm/proto.h> /* force_iommu in this header in x86-64*/ #include <asm/cacheflush.h> -#include <asm/gart.h> +#include <asm/iommu.h> #include "pci.h" #define IS_GFX_DEVICE(pdev) ((pdev->class >> 16) == PCI_BASE_CLASS_DISPLAY) diff --git a/drivers/s390/net/qeth_l3_main.c b/drivers/s390/net/qeth_l3_main.c index 22f64aa6dd1f..b29afef5c7fb 100644 --- a/drivers/s390/net/qeth_l3_main.c +++ b/drivers/s390/net/qeth_l3_main.c @@ -2013,7 +2013,7 @@ static int qeth_l3_verify_vlan_dev(struct net_device *dev, } } - if (rc && !(netdev_priv(vlan_dev_info(dev)->real_dev) == (void *)card)) + if (rc && !(netdev_priv(vlan_dev_real_dev(dev)) == (void *)card)) return 0; return rc; @@ -2049,7 +2049,7 @@ static struct qeth_card *qeth_l3_get_card_from_dev(struct net_device *dev) if (rc == QETH_REAL_CARD) card = netdev_priv(dev); else if (rc == QETH_VLAN_CARD) - card = netdev_priv(vlan_dev_info(dev)->real_dev); + card = netdev_priv(vlan_dev_real_dev(dev)); if (card && card->options.layer2) card = NULL; QETH_DBF_TEXT_(TRACE, 4, "%d", rc); diff --git a/drivers/serial/21285.c b/drivers/serial/21285.c index 0276471cb25e..6558a4037806 100644 --- a/drivers/serial/21285.c +++ b/drivers/serial/21285.c @@ -4,8 +4,6 @@ * Driver for the serial port on the 21285 StrongArm-110 core logic chip. * * Based on drivers/char/serial.c - * - * $Id: 21285.c,v 1.37 2002/07/28 10:03:27 rmk Exp $ */ #include <linux/module.h> #include <linux/tty.h> @@ -88,7 +86,7 @@ static void serial21285_enable_ms(struct uart_port *port) static irqreturn_t serial21285_rx_chars(int irq, void *dev_id) { struct uart_port *port = dev_id; - struct tty_struct *tty = port->info->tty; + struct tty_struct *tty = port->info->port.tty; unsigned int status, ch, flag, rxs, max_count = 256; status = *CSR_UARTFLG; @@ -237,8 +235,8 @@ serial21285_set_termios(struct uart_port *port, struct ktermios *termios, baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16); quot = uart_get_divisor(port, baud); - if (port->info && port->info->tty) { - struct tty_struct *tty = port->info->tty; + if (port->info && port->info->port.tty) { + struct tty_struct *tty = port->info->port.tty; unsigned int b = port->uartclk / (16 * quot); tty_encode_baud_rate(tty, b, b); } @@ -494,7 +492,7 @@ static int __init serial21285_init(void) { int ret; - printk(KERN_INFO "Serial: 21285 driver $Revision: 1.37 $\n"); + printk(KERN_INFO "Serial: 21285 driver\n"); serial21285_setup_ports(); @@ -515,5 +513,5 @@ module_init(serial21285_init); module_exit(serial21285_exit); MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("Intel Footbridge (21285) serial driver $Revision: 1.37 $"); +MODULE_DESCRIPTION("Intel Footbridge (21285) serial driver"); MODULE_ALIAS_CHARDEV(SERIAL_21285_MAJOR, SERIAL_21285_MINOR); diff --git a/drivers/serial/68328serial.c b/drivers/serial/68328serial.c index bbf5bc5892c7..381b12ac20e0 100644 --- a/drivers/serial/68328serial.c +++ b/drivers/serial/68328serial.c @@ -249,7 +249,7 @@ static void status_handle(struct m68k_serial *info, unsigned short status) { #if 0 if(status & DCD) { - if((info->tty->termios->c_cflag & CRTSCTS) && + if((info->port.tty->termios->c_cflag & CRTSCTS) && ((info->curregs[3] & AUTO_ENAB)==0)) { info->curregs[3] |= AUTO_ENAB; info->pendregs[3] |= AUTO_ENAB; @@ -274,7 +274,7 @@ static void status_handle(struct m68k_serial *info, unsigned short status) static void receive_chars(struct m68k_serial *info, unsigned short rx) { - struct tty_struct *tty = info->tty; + struct tty_struct *tty = info->port.tty; m68328_uart *uart = &uart_addr[info->line]; unsigned char ch, flag; @@ -345,7 +345,7 @@ static void transmit_chars(struct m68k_serial *info) goto clear_and_return; } - if((info->xmit_cnt <= 0) || info->tty->stopped) { + if((info->xmit_cnt <= 0) || info->port.tty->stopped) { /* That's peculiar... TX ints off */ uart->ustcnt &= ~USTCNT_TX_INTR_MASK; goto clear_and_return; @@ -403,7 +403,7 @@ static void do_softint(struct work_struct *work) struct m68k_serial *info = container_of(work, struct m68k_serial, tqueue); struct tty_struct *tty; - tty = info->tty; + tty = info->port.tty; if (!tty) return; #if 0 @@ -427,7 +427,7 @@ static void do_serial_hangup(struct work_struct *work) struct m68k_serial *info = container_of(work, struct m68k_serial, tqueue_hangup); struct tty_struct *tty; - tty = info->tty; + tty = info->port.tty; if (!tty) return; @@ -471,8 +471,8 @@ static int startup(struct m68k_serial * info) uart->ustcnt = USTCNT_UEN | USTCNT_RXEN | USTCNT_RX_INTR_MASK; #endif - if (info->tty) - clear_bit(TTY_IO_ERROR, &info->tty->flags); + if (info->port.tty) + clear_bit(TTY_IO_ERROR, &info->port.tty->flags); info->xmit_cnt = info->xmit_head = info->xmit_tail = 0; /* @@ -506,8 +506,8 @@ static void shutdown(struct m68k_serial * info) info->xmit_buf = 0; } - if (info->tty) - set_bit(TTY_IO_ERROR, &info->tty->flags); + if (info->port.tty) + set_bit(TTY_IO_ERROR, &info->port.tty->flags); info->flags &= ~S_INITIALIZED; local_irq_restore(flags); @@ -573,9 +573,9 @@ static void change_speed(struct m68k_serial *info) unsigned cflag; int i; - if (!info->tty || !info->tty->termios) + if (!info->port.tty || !info->port.tty->termios) return; - cflag = info->tty->termios->c_cflag; + cflag = info->port.tty->termios->c_cflag; if (!(port = info->port)) return; @@ -1131,7 +1131,7 @@ static void rs_close(struct tty_struct *tty, struct file * filp) tty_ldisc_flush(tty); tty->closing = 0; info->event = 0; - info->tty = 0; + info->port.tty = NULL; #warning "This is not and has never been valid so fix it" #if 0 if (tty->ldisc.num != ldiscs[N_TTY].num) { @@ -1169,7 +1169,7 @@ void rs_hangup(struct tty_struct *tty) info->event = 0; info->count = 0; info->flags &= ~S_NORMAL_ACTIVE; - info->tty = 0; + info->port.tty = NULL; wake_up_interruptible(&info->open_wait); } @@ -1286,7 +1286,7 @@ int rs_open(struct tty_struct *tty, struct file * filp) info->count++; tty->driver_data = info; - info->tty = tty; + info->port.tty = tty; /* * Start up serial port @@ -1363,7 +1363,7 @@ rs68328_init(void) info = &m68k_soft[i]; info->magic = SERIAL_MAGIC; info->port = (int) &uart_addr[i]; - info->tty = 0; + info->port.tty = NULL; info->irq = uart_irqs[i]; info->custom_divisor = 16; info->close_delay = 50; diff --git a/drivers/serial/68360serial.c b/drivers/serial/68360serial.c index d9d4e9552a4d..24661cd5e4fb 100644 --- a/drivers/serial/68360serial.c +++ b/drivers/serial/68360serial.c @@ -393,7 +393,7 @@ static void rs_360_start(struct tty_struct *tty) static _INLINE_ void receive_chars(ser_info_t *info) { - struct tty_struct *tty = info->tty; + struct tty_struct *tty = info->port.tty; unsigned char ch, flag, *cp; /*int ignored = 0;*/ int i; @@ -514,7 +514,7 @@ static _INLINE_ void receive_chars(ser_info_t *info) static _INLINE_ void receive_break(ser_info_t *info) { - struct tty_struct *tty = info->tty; + struct tty_struct *tty = info->port.tty; info->state->icount.brk++; /* Check to see if there is room in the tty buffer for @@ -528,7 +528,7 @@ static _INLINE_ void transmit_chars(ser_info_t *info) { if ((info->flags & TX_WAKEUP) || - (info->tty->flags & (1 << TTY_DO_WRITE_WAKEUP))) { + (info->port.tty->flags & (1 << TTY_DO_WRITE_WAKEUP))) { schedule_work(&info->tqueue); } @@ -584,12 +584,12 @@ static _INLINE_ void check_modem_status(struct async_struct *info) } } if (info->flags & ASYNC_CTS_FLOW) { - if (info->tty->hw_stopped) { + if (info->port.tty->hw_stopped) { if (status & UART_MSR_CTS) { #if (defined(SERIAL_DEBUG_INTR) || defined(SERIAL_DEBUG_FLOW)) printk("CTS tx start..."); #endif - info->tty->hw_stopped = 0; + info->port.tty->hw_stopped = 0; info->IER |= UART_IER_THRI; serial_out(info, UART_IER, info->IER); rs_sched_event(info, RS_EVENT_WRITE_WAKEUP); @@ -600,7 +600,7 @@ static _INLINE_ void check_modem_status(struct async_struct *info) #if (defined(SERIAL_DEBUG_INTR) || defined(SERIAL_DEBUG_FLOW)) printk("CTS tx stop..."); #endif - info->tty->hw_stopped = 1; + info->port.tty->hw_stopped = 1; info->IER &= ~UART_IER_THRI; serial_out(info, UART_IER, info->IER); } @@ -670,7 +670,7 @@ static void do_softint(void *private_) ser_info_t *info = (ser_info_t *) private_; struct tty_struct *tty; - tty = info->tty; + tty = info->port.tty; if (!tty) return; @@ -693,7 +693,7 @@ static void do_serial_hangup(void *private_) struct async_struct *info = (struct async_struct *) private_; struct tty_struct *tty; - tty = info->tty; + tty = info->port.tty; if (!tty) return; @@ -721,8 +721,8 @@ static int startup(ser_info_t *info) #ifdef maybe if (!state->port || !state->type) { - if (info->tty) - set_bit(TTY_IO_ERROR, &info->tty->flags); + if (info->port.tty) + set_bit(TTY_IO_ERROR, &info->port.tty->flags); goto errout; } #endif @@ -734,12 +734,12 @@ static int startup(ser_info_t *info) #ifdef modem_control info->MCR = 0; - if (info->tty->termios->c_cflag & CBAUD) + if (info->port.tty->termios->c_cflag & CBAUD) info->MCR = UART_MCR_DTR | UART_MCR_RTS; #endif - if (info->tty) - clear_bit(TTY_IO_ERROR, &info->tty->flags); + if (info->port.tty) + clear_bit(TTY_IO_ERROR, &info->port.tty->flags); /* * and set the speed of the serial port @@ -842,8 +842,8 @@ static void shutdown(ser_info_t *info) smcp->smc_smcmr &= ~(SMCMR_REN | SMCMR_TEN); } - if (info->tty) - set_bit(TTY_IO_ERROR, &info->tty->flags); + if (info->port.tty) + set_bit(TTY_IO_ERROR, &info->port.tty->flags); info->flags &= ~ASYNC_INITIALIZED; local_irq_restore(flags); @@ -863,9 +863,9 @@ static void change_speed(ser_info_t *info) volatile struct smc_regs *smcp; volatile struct scc_regs *sccp; - if (!info->tty || !info->tty->termios) + if (!info->port.tty || !info->port.tty->termios) return; - cflag = info->tty->termios->c_cflag; + cflag = info->port.tty->termios->c_cflag; state = info->state; @@ -936,24 +936,24 @@ static void change_speed(ser_info_t *info) * Set up parity check flag */ info->read_status_mask = (BD_SC_EMPTY | BD_SC_OV); - if (I_INPCK(info->tty)) + if (I_INPCK(info->port.tty)) info->read_status_mask |= BD_SC_FR | BD_SC_PR; - if (I_BRKINT(info->tty) || I_PARMRK(info->tty)) + if (I_BRKINT(info->port.tty) || I_PARMRK(info->port.tty)) info->read_status_mask |= BD_SC_BR; /* * Characters to ignore */ info->ignore_status_mask = 0; - if (I_IGNPAR(info->tty)) + if (I_IGNPAR(info->port.tty)) info->ignore_status_mask |= BD_SC_PR | BD_SC_FR; - if (I_IGNBRK(info->tty)) { + if (I_IGNBRK(info->port.tty)) { info->ignore_status_mask |= BD_SC_BR; /* * If we're ignore parity and break indicators, ignore * overruns too. (For real raw support). */ - if (I_IGNPAR(info->tty)) + if (I_IGNPAR(info->port.tty)) info->ignore_status_mask |= BD_SC_OV; } /* @@ -1658,7 +1658,7 @@ static void rs_360_close(struct tty_struct *tty, struct file * filp) tty_ldisc_flush(tty); tty->closing = 0; info->event = 0; - info->tty = 0; + info->port.tty = NULL; if (info->blocked_open) { if (info->close_delay) { msleep_interruptible(jiffies_to_msecs(info->close_delay)); @@ -1758,7 +1758,7 @@ static void rs_360_hangup(struct tty_struct *tty) info->event = 0; state->count = 0; info->flags &= ~ASYNC_NORMAL_ACTIVE; - info->tty = 0; + info->port.tty = NULL; wake_up_interruptible(&info->open_wait); } @@ -1919,7 +1919,7 @@ static int rs_360_open(struct tty_struct *tty, struct file * filp) printk("rs_open %s, count = %d\n", tty->name, info->state->count); #endif tty->driver_data = info; - info->tty = tty; + info->port.tty = tty; /* * Start up serial port @@ -1976,7 +1976,7 @@ static inline int line_info(char *buf, struct serial_state *state) info->port = state->port; info->flags = state->flags; info->quot = 0; - info->tty = 0; + info->port.tty = NULL; } local_irq_disable(); status = serial_in(info, UART_MSR); diff --git a/drivers/serial/8250.c b/drivers/serial/8250.c index be95e55b228b..ce948b66bbd4 100644 --- a/drivers/serial/8250.c +++ b/drivers/serial/8250.c @@ -12,8 +12,6 @@ * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * - * $Id: 8250.c,v 1.90 2002/07/28 10:03:27 rmk Exp $ - * * A note about mapbase / membase * * mapbase is the physical address of the IO port. @@ -1289,7 +1287,7 @@ static void serial8250_enable_ms(struct uart_port *port) static void receive_chars(struct uart_8250_port *up, unsigned int *status) { - struct tty_struct *tty = up->port.info->tty; + struct tty_struct *tty = up->port.info->port.tty; unsigned char ch, lsr = *status; int max_count = 256; char flag; @@ -2934,7 +2932,7 @@ static int __init serial8250_init(void) if (nr_uarts > UART_NR) nr_uarts = UART_NR; - printk(KERN_INFO "Serial: 8250/16550 driver $Revision: 1.90 $ " + printk(KERN_INFO "Serial: 8250/16550 driver" "%d ports, IRQ sharing %sabled\n", nr_uarts, share_irqs ? "en" : "dis"); @@ -2995,7 +2993,7 @@ EXPORT_SYMBOL(serial8250_suspend_port); EXPORT_SYMBOL(serial8250_resume_port); MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("Generic 8250/16x50 serial driver $Revision: 1.90 $"); +MODULE_DESCRIPTION("Generic 8250/16x50 serial driver"); module_param(share_irqs, uint, 0644); MODULE_PARM_DESC(share_irqs, "Share IRQs with other non-8250/16x50 devices" diff --git a/drivers/serial/8250.h b/drivers/serial/8250.h index 91bd28f2bb47..78c00162b04e 100644 --- a/drivers/serial/8250.h +++ b/drivers/serial/8250.h @@ -11,8 +11,6 @@ * 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. - * - * $Id: 8250.h,v 1.8 2002/07/21 21:32:30 rmk Exp $ */ #include <linux/serial_8250.h> diff --git a/drivers/serial/8250_pci.c b/drivers/serial/8250_pci.c index 788c3559522d..1b36087665a2 100644 --- a/drivers/serial/8250_pci.c +++ b/drivers/serial/8250_pci.c @@ -10,8 +10,6 @@ * 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. - * - * $Id: 8250_pci.c,v 1.28 2002/11/02 11:14:18 rmk Exp $ */ #include <linux/module.h> #include <linux/init.h> diff --git a/drivers/serial/8250_pnp.c b/drivers/serial/8250_pnp.c index 638b68649e79..fde7f9ccf57e 100644 --- a/drivers/serial/8250_pnp.c +++ b/drivers/serial/8250_pnp.c @@ -12,8 +12,6 @@ * 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. - * - * $Id: 8250_pnp.c,v 1.10 2002/07/21 21:32:30 rmk Exp $ */ #include <linux/module.h> #include <linux/init.h> diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig index 18ca9075e131..8fc7451c0049 100644 --- a/drivers/serial/Kconfig +++ b/drivers/serial/Kconfig @@ -1,8 +1,6 @@ # # Serial device configuration # -# $Id: Kconfig,v 1.11 2004/03/11 18:08:04 lethal Exp $ -# menu "Serial drivers" depends on HAS_IOMEM diff --git a/drivers/serial/Makefile b/drivers/serial/Makefile index 7d85c1fbe7e0..3a0bbbe17aa3 100644 --- a/drivers/serial/Makefile +++ b/drivers/serial/Makefile @@ -1,8 +1,6 @@ # # Makefile for the kernel serial device drivers. # -# $Id: Makefile,v 1.8 2002/07/21 21:32:30 rmk Exp $ -# obj-$(CONFIG_SERIAL_CORE) += serial_core.o obj-$(CONFIG_SERIAL_21285) += 21285.o diff --git a/drivers/serial/amba-pl010.c b/drivers/serial/amba-pl010.c index e88da72f8304..90b56c2c31e2 100644 --- a/drivers/serial/amba-pl010.c +++ b/drivers/serial/amba-pl010.c @@ -22,8 +22,6 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * - * $Id: amba.c,v 1.41 2002/07/28 10:03:27 rmk Exp $ - * * This is a generic driver for ARM AMBA-type serial ports. They * have a lot of 16550-like features, but are not register compatible. * Note that although they do have CTS, DCD and DSR inputs, they do @@ -119,7 +117,7 @@ static void pl010_enable_ms(struct uart_port *port) static void pl010_rx_chars(struct uart_amba_port *uap) { - struct tty_struct *tty = uap->port.info->tty; + struct tty_struct *tty = uap->port.info->port.tty; unsigned int status, ch, flag, rsr, max_count = 256; status = readb(uap->port.membase + UART01x_FR); @@ -791,7 +789,7 @@ static int __init pl010_init(void) { int ret; - printk(KERN_INFO "Serial: AMBA driver $Revision: 1.41 $\n"); + printk(KERN_INFO "Serial: AMBA driver\n"); ret = uart_register_driver(&amba_reg); if (ret == 0) { @@ -812,5 +810,5 @@ module_init(pl010_init); module_exit(pl010_exit); MODULE_AUTHOR("ARM Ltd/Deep Blue Solutions Ltd"); -MODULE_DESCRIPTION("ARM AMBA serial port driver $Revision: 1.41 $"); +MODULE_DESCRIPTION("ARM AMBA serial port driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/serial/amba-pl011.c b/drivers/serial/amba-pl011.c index 08adc1de4a79..9d08f27208a1 100644 --- a/drivers/serial/amba-pl011.c +++ b/drivers/serial/amba-pl011.c @@ -22,8 +22,6 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * - * $Id: amba.c,v 1.41 2002/07/28 10:03:27 rmk Exp $ - * * This is a generic driver for ARM AMBA-type serial ports. They * have a lot of 16550-like features, but are not register compatible. * Note that although they do have CTS, DCD and DSR inputs, they do @@ -109,7 +107,7 @@ static void pl011_enable_ms(struct uart_port *port) static void pl011_rx_chars(struct uart_amba_port *uap) { - struct tty_struct *tty = uap->port.info->tty; + struct tty_struct *tty = uap->port.info->port.tty; unsigned int status, ch, flag, max_count = 256; status = readw(uap->port.membase + UART01x_FR); diff --git a/drivers/serial/atmel_serial.c b/drivers/serial/atmel_serial.c index 6aeef22bd203..1fee12c1f4f8 100644 --- a/drivers/serial/atmel_serial.c +++ b/drivers/serial/atmel_serial.c @@ -662,14 +662,14 @@ static void atmel_rx_from_ring(struct uart_port *port) * uart_start(), which takes the lock. */ spin_unlock(&port->lock); - tty_flip_buffer_push(port->info->tty); + tty_flip_buffer_push(port->info->port.tty); spin_lock(&port->lock); } static void atmel_rx_from_dma(struct uart_port *port) { struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); - struct tty_struct *tty = port->info->tty; + struct tty_struct *tty = port->info->port.tty; struct atmel_dma_buffer *pdc; int rx_idx = atmel_port->pdc_rx_idx; unsigned int head; @@ -794,7 +794,7 @@ static void atmel_tasklet_func(unsigned long data) static int atmel_startup(struct uart_port *port) { struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); - struct tty_struct *tty = port->info->tty; + struct tty_struct *tty = port->info->port.tty; int retval; /* @@ -956,6 +956,20 @@ static void atmel_shutdown(struct uart_port *port) } /* + * Flush any TX data submitted for DMA. Called when the TX circular + * buffer is reset. + */ +static void atmel_flush_buffer(struct uart_port *port) +{ + struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); + + if (atmel_use_dma_tx(port)) { + UART_PUT_TCR(port, 0); + atmel_port->pdc_tx.ofs = 0; + } +} + +/* * Power / Clock management. */ static void atmel_serial_pm(struct uart_port *port, unsigned int state, @@ -1189,6 +1203,7 @@ static struct uart_ops atmel_pops = { .break_ctl = atmel_break_ctl, .startup = atmel_startup, .shutdown = atmel_shutdown, + .flush_buffer = atmel_flush_buffer, .set_termios = atmel_set_termios, .type = atmel_type, .release_port = atmel_release_port, diff --git a/drivers/serial/bfin_5xx.c b/drivers/serial/bfin_5xx.c index fd9bb777df28..9d8543762a30 100644 --- a/drivers/serial/bfin_5xx.c +++ b/drivers/serial/bfin_5xx.c @@ -175,7 +175,7 @@ int kgdb_get_debug_char(void) #ifdef CONFIG_SERIAL_BFIN_PIO static void bfin_serial_rx_chars(struct bfin_serial_port *uart) { - struct tty_struct *tty = uart->port.info->tty; + struct tty_struct *tty = uart->port.info->port.tty; unsigned int status, ch, flg; static struct timeval anomaly_start = { .tv_sec = 0 }; @@ -393,7 +393,7 @@ static void bfin_serial_dma_tx_chars(struct bfin_serial_port *uart) static void bfin_serial_dma_rx_chars(struct bfin_serial_port *uart) { - struct tty_struct *tty = uart->port.info->tty; + struct tty_struct *tty = uart->port.info->port.tty; int i, flg, status; status = UART_GET_LSR(uart); @@ -552,7 +552,7 @@ static void bfin_serial_mctrl_check(struct bfin_serial_port *uart) #ifdef CONFIG_SERIAL_BFIN_CTSRTS unsigned int status; struct uart_info *info = uart->port.info; - struct tty_struct *tty = info->tty; + struct tty_struct *tty = info->port.tty; status = bfin_serial_get_mctrl(&uart->port); uart_handle_cts_change(&uart->port, status & TIOCM_CTS); @@ -814,10 +814,10 @@ static void bfin_serial_set_ldisc(struct uart_port *port) int line = port->line; unsigned short val; - if (line >= port->info->tty->driver->num) + if (line >= port->info->port.tty->driver->num) return; - switch (port->info->tty->ldisc.num) { + switch (port->info->port.tty->ldisc.num) { case N_IRDA: val = UART_GET_GCTL(&bfin_serial_ports[line]); val |= (IREN | RPOLC); diff --git a/drivers/serial/bfin_sport_uart.c b/drivers/serial/bfin_sport_uart.c index aca1240ad808..dd8564d25051 100644 --- a/drivers/serial/bfin_sport_uart.c +++ b/drivers/serial/bfin_sport_uart.c @@ -174,7 +174,7 @@ static int sport_uart_setup(struct sport_uart_port *up, int sclk, int baud_rate) static irqreturn_t sport_uart_rx_irq(int irq, void *dev_id) { struct sport_uart_port *up = dev_id; - struct tty_struct *tty = up->port.info->tty; + struct tty_struct *tty = up->port.info->port.tty; unsigned int ch; do { @@ -201,7 +201,7 @@ static irqreturn_t sport_uart_tx_irq(int irq, void *dev_id) static irqreturn_t sport_uart_err_irq(int irq, void *dev_id) { struct sport_uart_port *up = dev_id; - struct tty_struct *tty = up->port.info->tty; + struct tty_struct *tty = up->port.info->port.tty; unsigned int stat = SPORT_GET_STAT(up); /* Overflow in RX FIFO */ diff --git a/drivers/serial/clps711x.c b/drivers/serial/clps711x.c index 23827189ec0e..fc1fa9267c59 100644 --- a/drivers/serial/clps711x.c +++ b/drivers/serial/clps711x.c @@ -21,9 +21,6 @@ * 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 - * - * $Id: clps711x.c,v 1.42 2002/07/28 10:03:28 rmk Exp $ - * */ #if defined(CONFIG_SERIAL_CLPS711X_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) @@ -96,7 +93,7 @@ static void clps711xuart_enable_ms(struct uart_port *port) static irqreturn_t clps711xuart_int_rx(int irq, void *dev_id) { struct uart_port *port = dev_id; - struct tty_struct *tty = port->info->tty; + struct tty_struct *tty = port->info->port.tty; unsigned int status, ch, flg; status = clps_readl(SYSFLG(port)); @@ -551,7 +548,7 @@ static int __init clps711xuart_init(void) { int ret, i; - printk(KERN_INFO "Serial: CLPS711x driver $Revision: 1.42 $\n"); + printk(KERN_INFO "Serial: CLPS711x driver\n"); ret = uart_register_driver(&clps711x_reg); if (ret) @@ -577,6 +574,6 @@ module_init(clps711xuart_init); module_exit(clps711xuart_exit); MODULE_AUTHOR("Deep Blue Solutions Ltd"); -MODULE_DESCRIPTION("CLPS-711x generic serial driver $Revision: 1.42 $"); +MODULE_DESCRIPTION("CLPS-711x generic serial driver"); MODULE_LICENSE("GPL"); MODULE_ALIAS_CHARDEV(SERIAL_CLPS711X_MAJOR, SERIAL_CLPS711X_MINOR); diff --git a/drivers/serial/crisv10.c b/drivers/serial/crisv10.c index 3e0366eab412..8249ac490559 100644 --- a/drivers/serial/crisv10.c +++ b/drivers/serial/crisv10.c @@ -968,7 +968,7 @@ static DEFINE_MUTEX(tmp_buf_mutex); /* Calculate the chartime depending on baudrate, numbor of bits etc. */ static void update_char_time(struct e100_serial * info) { - tcflag_t cflags = info->tty->termios->c_cflag; + tcflag_t cflags = info->port.tty->termios->c_cflag; int bits; /* calc. number of bits / data byte */ @@ -1483,7 +1483,8 @@ rs_stop(struct tty_struct *tty) CIRC_CNT(info->xmit.head, info->xmit.tail,SERIAL_XMIT_SIZE))); - xoff = IO_FIELD(R_SERIAL0_XOFF, xoff_char, STOP_CHAR(info->tty)); + xoff = IO_FIELD(R_SERIAL0_XOFF, xoff_char, + STOP_CHAR(info->port.tty)); xoff |= IO_STATE(R_SERIAL0_XOFF, tx_stop, stop); if (tty->termios->c_iflag & IXON ) { xoff |= IO_STATE(R_SERIAL0_XOFF, auto_xoff, enable); @@ -1772,7 +1773,7 @@ add_char_and_flag(struct e100_serial *info, unsigned char data, unsigned char fl info->icount.rx++; } else { - struct tty_struct *tty = info->tty; + struct tty_struct *tty = info->port.tty; tty_insert_flip_char(tty, data, flag); info->icount.rx++; } @@ -1838,7 +1839,7 @@ static unsigned int handle_all_descr_data(struct e100_serial *info) descr->status = 0; DFLOW( DEBUG_LOG(info->line, "RX %lu\n", recvl); - if (info->tty->stopped) { + if (info->port.tty->stopped) { unsigned char *buf = phys_to_virt(descr->buf); DEBUG_LOG(info->line, "rx 0x%02X\n", buf[0]); DEBUG_LOG(info->line, "rx 0x%02X\n", buf[1]); @@ -1872,7 +1873,7 @@ static void receive_chars_dma(struct e100_serial *info) IO_STATE(R_DMA_CH6_CLR_INTR, clr_descr, do) | IO_STATE(R_DMA_CH6_CLR_INTR, clr_eop, do); - tty = info->tty; + tty = info->port.tty; if (!tty) /* Something wrong... */ return; @@ -2122,7 +2123,7 @@ static void flush_to_flip_buffer(struct e100_serial *info) unsigned long flags; local_irq_save(flags); - tty = info->tty; + tty = info->port.tty; if (!tty) { local_irq_restore(flags); @@ -2287,7 +2288,7 @@ static struct e100_serial * handle_ser_rx_interrupt_no_dma(struct e100_serial *info) { unsigned long data_read; - struct tty_struct *tty = info->tty; + struct tty_struct *tty = info->port.tty; if (!tty) { printk("!NO TTY!\n"); @@ -2350,7 +2351,7 @@ more_data: data_in, data_read); char flag = TTY_NORMAL; if (info->errorcode == ERRCODE_INSERT_BREAK) { - struct tty_struct *tty = info->tty; + struct tty_struct *tty = info->port.tty; tty_insert_flip_char(tty, 0, flag); info->icount.rx++; } @@ -2396,7 +2397,7 @@ more_data: goto more_data; } - tty_flip_buffer_push(info->tty); + tty_flip_buffer_push(info->port.tty); return info; } @@ -2547,8 +2548,8 @@ static void handle_ser_tx_interrupt(struct e100_serial *info) rstat = info->port[REG_STATUS]; DFLOW(DEBUG_LOG(info->line, "stat %x\n", rstat)); e100_disable_serial_tx_ready_irq(info); - if (info->tty->stopped) - rs_stop(info->tty); + if (info->port.tty->stopped) + rs_stop(info->port.tty); /* Enable the DMA channel and tell it to continue */ e100_enable_txdma_channel(info); /* Wait 12 cycles before doing the DMA command */ @@ -2561,9 +2562,10 @@ static void handle_ser_tx_interrupt(struct e100_serial *info) } /* Normal char-by-char interrupt */ if (info->xmit.head == info->xmit.tail - || info->tty->stopped - || info->tty->hw_stopped) { - DFLOW(DEBUG_LOG(info->line, "tx_int: stopped %i\n", info->tty->stopped)); + || info->port.tty->stopped + || info->port.tty->hw_stopped) { + DFLOW(DEBUG_LOG(info->line, "tx_int: stopped %i\n", + info->port.tty->stopped)); e100_disable_serial_tx_ready_irq(info); info->tr_running = 0; return; @@ -2725,7 +2727,7 @@ do_softint(struct work_struct *work) info = container_of(work, struct e100_serial, work); - tty = info->tty; + tty = info->port.tty; if (!tty) return; @@ -2767,8 +2769,8 @@ startup(struct e100_serial * info) /* Bits and pieces collected from below. Better to have them in one ifdef:ed clause than to mix in a lot of ifdefs, right? */ - if (info->tty) - clear_bit(TTY_IO_ERROR, &info->tty->flags); + if (info->port.tty) + clear_bit(TTY_IO_ERROR, &info->port.tty->flags); info->xmit.head = info->xmit.tail = 0; info->first_recv_buffer = info->last_recv_buffer = NULL; @@ -2825,8 +2827,8 @@ startup(struct e100_serial * info) e100_disable_txdma_channel(info); } - if (info->tty) - clear_bit(TTY_IO_ERROR, &info->tty->flags); + if (info->port.tty) + clear_bit(TTY_IO_ERROR, &info->port.tty->flags); info->xmit.head = info->xmit.tail = 0; info->first_recv_buffer = info->last_recv_buffer = NULL; @@ -2940,14 +2942,14 @@ shutdown(struct e100_serial * info) descr[i].buf = 0; } - if (!info->tty || (info->tty->termios->c_cflag & HUPCL)) { + if (!info->port.tty || (info->port.tty->termios->c_cflag & HUPCL)) { /* hang up DTR and RTS if HUPCL is enabled */ e100_dtr(info, 0); e100_rts(info, 0); /* could check CRTSCTS before doing this */ } - if (info->tty) - set_bit(TTY_IO_ERROR, &info->tty->flags); + if (info->port.tty) + set_bit(TTY_IO_ERROR, &info->port.tty->flags); info->flags &= ~ASYNC_INITIALIZED; local_irq_restore(flags); @@ -2964,12 +2966,12 @@ change_speed(struct e100_serial *info) unsigned long flags; /* first some safety checks */ - if (!info->tty || !info->tty->termios) + if (!info->port.tty || !info->port.tty->termios) return; if (!info->port) return; - cflag = info->tty->termios->c_cflag; + cflag = info->port.tty->termios->c_cflag; /* possibly, the tx/rx should be disabled first to do this safely */ @@ -3097,10 +3099,11 @@ change_speed(struct e100_serial *info) info->port[REG_TR_CTRL] = info->tx_ctrl; info->port[REG_REC_CTRL] = info->rx_ctrl; - xoff = IO_FIELD(R_SERIAL0_XOFF, xoff_char, STOP_CHAR(info->tty)); + xoff = IO_FIELD(R_SERIAL0_XOFF, xoff_char, STOP_CHAR(info->port.tty)); xoff |= IO_STATE(R_SERIAL0_XOFF, tx_stop, enable); - if (info->tty->termios->c_iflag & IXON ) { - DFLOW(DEBUG_LOG(info->line, "FLOW XOFF enabled 0x%02X\n", STOP_CHAR(info->tty))); + if (info->port.tty->termios->c_iflag & IXON ) { + DFLOW(DEBUG_LOG(info->line, "FLOW XOFF enabled 0x%02X\n", + STOP_CHAR(info->port.tty))); xoff |= IO_STATE(R_SERIAL0_XOFF, auto_xoff, enable); } @@ -3475,7 +3478,7 @@ set_serial_info(struct e100_serial *info, info->type = new_serial.type; info->close_delay = new_serial.close_delay; info->closing_wait = new_serial.closing_wait; - info->tty->low_latency = (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0; + info->port.tty->low_latency = (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0; check_and_exit: if (info->flags & ASYNC_INITIALIZED) { @@ -3811,7 +3814,7 @@ rs_close(struct tty_struct *tty, struct file * filp) tty_ldisc_flush(tty); tty->closing = 0; info->event = 0; - info->tty = 0; + info->port.tty = NULL; if (info->blocked_open) { if (info->close_delay) schedule_timeout_interruptible(info->close_delay); @@ -3915,7 +3918,7 @@ rs_hangup(struct tty_struct *tty) info->event = 0; info->count = 0; info->flags &= ~ASYNC_NORMAL_ACTIVE; - info->tty = 0; + info->port.tty = NULL; wake_up_interruptible(&info->open_wait); } @@ -4077,9 +4080,9 @@ rs_open(struct tty_struct *tty, struct file * filp) info->count++; tty->driver_data = info; - info->tty = tty; + info->port.tty = tty; - info->tty->low_latency = (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0; + info->port.tty->low_latency = (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0; if (!tmp_buf) { page = get_zeroed_page(GFP_KERNEL); @@ -4267,14 +4270,14 @@ static int line_info(char *buf, struct e100_serial *info) (unsigned long)info->max_recv_cnt); #if 1 - if (info->tty) { + if (info->port.tty) { - if (info->tty->stopped) + if (info->port.tty->stopped) ret += sprintf(buf+ret, " stopped:%i", - (int)info->tty->stopped); - if (info->tty->hw_stopped) + (int)info->port.tty->stopped); + if (info->port.tty->hw_stopped) ret += sprintf(buf+ret, " hw_stopped:%i", - (int)info->tty->hw_stopped); + (int)info->port.tty->hw_stopped); } { @@ -4465,7 +4468,7 @@ rs_init(void) info->uses_dma_in = 0; info->uses_dma_out = 0; info->line = i; - info->tty = 0; + info->port.tty = NULL; info->type = PORT_ETRAX; info->tr_running = 0; info->forced_eop = 0; diff --git a/drivers/serial/dz.c b/drivers/serial/dz.c index 0dddd68b20d2..a81d2c2ff8a2 100644 --- a/drivers/serial/dz.c +++ b/drivers/serial/dz.c @@ -197,7 +197,7 @@ static inline void dz_receive_chars(struct dz_mux *mux) while ((status = dz_in(dport, DZ_RBUF)) & DZ_DVAL) { dport = &mux->dport[LINE(status)]; uport = &dport->port; - tty = uport->info->tty; /* point to the proper dev */ + tty = uport->info->port.tty; /* point to the proper dev */ ch = UCHAR(status); /* grab the char */ flag = TTY_NORMAL; @@ -249,7 +249,7 @@ static inline void dz_receive_chars(struct dz_mux *mux) } for (i = 0; i < DZ_NB_PORT; i++) if (lines_rx[i]) - tty_flip_buffer_push(mux->dport[i].port.info->tty); + tty_flip_buffer_push(mux->dport[i].port.info->port.tty); } /* diff --git a/drivers/serial/imx.c b/drivers/serial/imx.c index 64acb39a51ba..e0da4dc7bbf6 100644 --- a/drivers/serial/imx.c +++ b/drivers/serial/imx.c @@ -372,7 +372,7 @@ static irqreturn_t imx_rxint(int irq, void *dev_id) { struct imx_port *sport = dev_id; unsigned int rx,flg,ignored = 0; - struct tty_struct *tty = sport->port.info->tty; + struct tty_struct *tty = sport->port.info->port.tty; unsigned long flags, temp; spin_lock_irqsave(&sport->port.lock,flags); diff --git a/drivers/serial/ioc3_serial.c b/drivers/serial/ioc3_serial.c index 4f1af71e9a1b..6dd98f9fb89c 100644 --- a/drivers/serial/ioc3_serial.c +++ b/drivers/serial/ioc3_serial.c @@ -905,7 +905,7 @@ static void transmit_chars(struct uart_port *the_port) return; info = the_port->info; - tty = info->tty; + tty = info->port.tty; if (uart_circ_empty(&info->xmit) || uart_tx_stopped(the_port)) { /* Nothing to do or hw stopped */ @@ -997,14 +997,14 @@ ioc3_change_speed(struct uart_port *the_port, the_port->ignore_status_mask = N_ALL_INPUT; - info->tty->low_latency = 1; + info->port.tty->low_latency = 1; - if (I_IGNPAR(info->tty)) + if (I_IGNPAR(info->port.tty)) the_port->ignore_status_mask &= ~(N_PARITY_ERROR | N_FRAMING_ERROR); - if (I_IGNBRK(info->tty)) { + if (I_IGNBRK(info->port.tty)) { the_port->ignore_status_mask &= ~N_BREAK; - if (I_IGNPAR(info->tty)) + if (I_IGNPAR(info->port.tty)) the_port->ignore_status_mask &= ~N_OVERRUN_ERROR; } if (!(cflag & CREAD)) { @@ -1399,14 +1399,14 @@ static int receive_chars(struct uart_port *the_port) /* Make sure all the pointers are "good" ones */ if (!info) return 0; - if (!info->tty) + if (!info->port.tty) return 0; if (!(port->ip_flags & INPUT_ENABLE)) return 0; spin_lock_irqsave(&the_port->lock, pflags); - tty = info->tty; + tty = info->port.tty; read_count = do_read(the_port, ch, MAX_CHARS); if (read_count > 0) { diff --git a/drivers/serial/ioc4_serial.c b/drivers/serial/ioc4_serial.c index 49b8a82b7b9f..6bab63cd5b29 100644 --- a/drivers/serial/ioc4_serial.c +++ b/drivers/serial/ioc4_serial.c @@ -1635,7 +1635,7 @@ static void transmit_chars(struct uart_port *the_port) return; info = the_port->info; - tty = info->tty; + tty = info->port.tty; if (uart_circ_empty(&info->xmit) || uart_tx_stopped(the_port)) { /* Nothing to do or hw stopped */ @@ -1738,14 +1738,14 @@ ioc4_change_speed(struct uart_port *the_port, the_port->ignore_status_mask = N_ALL_INPUT; - info->tty->low_latency = 1; + info->port.tty->low_latency = 1; - if (I_IGNPAR(info->tty)) + if (I_IGNPAR(info->port.tty)) the_port->ignore_status_mask &= ~(N_PARITY_ERROR | N_FRAMING_ERROR); - if (I_IGNBRK(info->tty)) { + if (I_IGNBRK(info->port.tty)) { the_port->ignore_status_mask &= ~N_BREAK; - if (I_IGNPAR(info->tty)) + if (I_IGNPAR(info->port.tty)) the_port->ignore_status_mask &= ~N_OVERRUN_ERROR; } if (!(cflag & CREAD)) { @@ -1801,7 +1801,8 @@ static inline int ic4_startup_local(struct uart_port *the_port) ioc4_set_proto(port, the_port->mapbase); /* set the speed of the serial port */ - ioc4_change_speed(the_port, info->tty->termios, (struct ktermios *)0); + ioc4_change_speed(the_port, info->port.tty->termios, + (struct ktermios *)0); return 0; } @@ -2346,11 +2347,11 @@ static void receive_chars(struct uart_port *the_port) /* Make sure all the pointers are "good" ones */ if (!info) return; - if (!info->tty) + if (!info->port.tty) return; spin_lock_irqsave(&the_port->lock, pflags); - tty = info->tty; + tty = info->port.tty; request_count = tty_buffer_request_room(tty, IOC4_MAX_CHARS); @@ -2440,8 +2441,8 @@ static void ic4_shutdown(struct uart_port *the_port) wake_up_interruptible(&info->delta_msr_wait); - if (info->tty) - set_bit(TTY_IO_ERROR, &info->tty->flags); + if (info->port.tty) + set_bit(TTY_IO_ERROR, &info->port.tty->flags); spin_lock_irqsave(&the_port->lock, port_flags); set_notification(port, N_ALL, 0); diff --git a/drivers/serial/ip22zilog.c b/drivers/serial/ip22zilog.c index 9c95bc0398ad..0d9acbd0bb70 100644 --- a/drivers/serial/ip22zilog.c +++ b/drivers/serial/ip22zilog.c @@ -257,8 +257,8 @@ static struct tty_struct *ip22zilog_receive_chars(struct uart_ip22zilog_port *up tty = NULL; if (up->port.info != NULL && - up->port.info->tty != NULL) - tty = up->port.info->tty; + up->port.info->port.tty != NULL) + tty = up->port.info->port.tty; for (;;) { ch = readb(&channel->control); diff --git a/drivers/serial/jsm/jsm_neo.c b/drivers/serial/jsm/jsm_neo.c index b2d6f5b1a7c2..b7584ca55ade 100644 --- a/drivers/serial/jsm/jsm_neo.c +++ b/drivers/serial/jsm/jsm_neo.c @@ -998,7 +998,7 @@ static void neo_param(struct jsm_channel *ch) { 50, B50 }, }; - cflag = C_BAUD(ch->uart_port.info->tty); + cflag = C_BAUD(ch->uart_port.info->port.tty); baud = 9600; for (i = 0; i < ARRAY_SIZE(baud_rates); i++) { if (baud_rates[i].cflag == cflag) { diff --git a/drivers/serial/jsm/jsm_tty.c b/drivers/serial/jsm/jsm_tty.c index 94ec66372508..a697914ae3d0 100644 --- a/drivers/serial/jsm/jsm_tty.c +++ b/drivers/serial/jsm/jsm_tty.c @@ -145,7 +145,7 @@ static void jsm_tty_send_xchar(struct uart_port *port, char ch) struct ktermios *termios; spin_lock_irqsave(&port->lock, lock_flags); - termios = port->info->tty->termios; + termios = port->info->port.tty->termios; if (ch == termios->c_cc[VSTART]) channel->ch_bd->bd_ops->send_start_character(channel); @@ -239,7 +239,7 @@ static int jsm_tty_open(struct uart_port *port) channel->ch_cached_lsr = 0; channel->ch_stops_sent = 0; - termios = port->info->tty->termios; + termios = port->info->port.tty->termios; channel->ch_c_cflag = termios->c_cflag; channel->ch_c_iflag = termios->c_iflag; channel->ch_c_oflag = termios->c_oflag; @@ -272,7 +272,7 @@ static void jsm_tty_close(struct uart_port *port) jsm_printk(CLOSE, INFO, &channel->ch_bd->pci_dev, "start\n"); bd = channel->ch_bd; - ts = channel->uart_port.info->tty->termios; + ts = channel->uart_port.info->port.tty->termios; channel->ch_flags &= ~(CH_STOPI); @@ -515,7 +515,7 @@ void jsm_input(struct jsm_channel *ch) if (!ch) return; - tp = ch->uart_port.info->tty; + tp = ch->uart_port.info->port.tty; bd = ch->ch_bd; if(!bd) diff --git a/drivers/serial/m32r_sio.c b/drivers/serial/m32r_sio.c index c2bb11c02bde..23d030511019 100644 --- a/drivers/serial/m32r_sio.c +++ b/drivers/serial/m32r_sio.c @@ -325,7 +325,7 @@ static void m32r_sio_enable_ms(struct uart_port *port) static void receive_chars(struct uart_sio_port *up, int *status) { - struct tty_struct *tty = up->port.info->tty; + struct tty_struct *tty = up->port.info->port.tty; unsigned char ch; unsigned char flag; int max_count = 256; @@ -1160,7 +1160,7 @@ static int __init m32r_sio_init(void) { int ret, i; - printk(KERN_INFO "Serial: M32R SIO driver $Revision: 1.11 $ "); + printk(KERN_INFO "Serial: M32R SIO driver\n"); for (i = 0; i < NR_IRQS; i++) spin_lock_init(&irq_lists[i].lock); @@ -1189,4 +1189,4 @@ EXPORT_SYMBOL(m32r_sio_suspend_port); EXPORT_SYMBOL(m32r_sio_resume_port); MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("Generic M32R SIO serial driver $Revision: 1.11 $"); +MODULE_DESCRIPTION("Generic M32R SIO serial driver"); diff --git a/drivers/serial/mcf.c b/drivers/serial/mcf.c index 7e164e0cd211..b2001c5b145c 100644 --- a/drivers/serial/mcf.c +++ b/drivers/serial/mcf.c @@ -312,7 +312,7 @@ static void mcf_rx_chars(struct mcf_uart *pp) uart_insert_char(port, status, MCFUART_USR_RXOVERRUN, ch, flag); } - tty_flip_buffer_push(port->info->tty); + tty_flip_buffer_push(port->info->port.tty); } /****************************************************************************/ diff --git a/drivers/serial/mcfserial.c b/drivers/serial/mcfserial.c index 56007cc8a9b3..fbe3835f6b77 100644 --- a/drivers/serial/mcfserial.c +++ b/drivers/serial/mcfserial.c @@ -327,7 +327,7 @@ static void mcfrs_start(struct tty_struct *tty) static inline void receive_chars(struct mcf_serial *info) { volatile unsigned char *uartp; - struct tty_struct *tty = info->tty; + struct tty_struct *tty = info->port.tty; unsigned char status, ch, flag; if (!tty) @@ -382,7 +382,7 @@ static inline void transmit_chars(struct mcf_serial *info) info->stats.tx++; } - if ((info->xmit_cnt <= 0) || info->tty->stopped) { + if ((info->xmit_cnt <= 0) || info->port.tty->stopped) { info->imr &= ~MCFUART_UIR_TXREADY; uartp[MCFUART_UIMR] = info->imr; return; @@ -428,7 +428,7 @@ irqreturn_t mcfrs_interrupt(int irq, void *dev_id) static void mcfrs_offintr(struct work_struct *work) { struct mcf_serial *info = container_of(work, struct mcf_serial, tqueue); - struct tty_struct *tty = info->tty; + struct tty_struct *tty = info->port.tty; if (tty) tty_wakeup(tty); @@ -498,7 +498,7 @@ static void mcfrs_timer(void) static void do_serial_hangup(struct work_struct *work) { struct mcf_serial *info = container_of(work, struct mcf_serial, tqueue_hangup); - struct tty_struct *tty = info->tty; + struct tty_struct *tty = info->port.tty; if (tty) tty_hangup(tty); @@ -532,8 +532,8 @@ static int startup(struct mcf_serial * info) uartp[MCFUART_UCR] = MCFUART_UCR_CMDRESETTX; /* reset TX */ mcfrs_setsignals(info, 1, 1); - if (info->tty) - clear_bit(TTY_IO_ERROR, &info->tty->flags); + if (info->port.tty) + clear_bit(TTY_IO_ERROR, &info->port.tty->flags); info->xmit_cnt = info->xmit_head = info->xmit_tail = 0; /* @@ -578,7 +578,7 @@ static void shutdown(struct mcf_serial * info) uartp[MCFUART_UCR] = MCFUART_UCR_CMDRESETRX; /* reset RX */ uartp[MCFUART_UCR] = MCFUART_UCR_CMDRESETTX; /* reset TX */ - if (!info->tty || (info->tty->termios->c_cflag & HUPCL)) + if (!info->port.tty || (info->port.tty->termios->c_cflag & HUPCL)) mcfrs_setsignals(info, 0, 0); if (info->xmit_buf) { @@ -586,8 +586,8 @@ static void shutdown(struct mcf_serial * info) info->xmit_buf = 0; } - if (info->tty) - set_bit(TTY_IO_ERROR, &info->tty->flags); + if (info->port.tty) + set_bit(TTY_IO_ERROR, &info->port.tty->flags); info->flags &= ~ASYNC_INITIALIZED; local_irq_restore(flags); @@ -609,9 +609,9 @@ static void mcfrs_change_speed(struct mcf_serial *info) unsigned int fraction; #endif - if (!info->tty || !info->tty->termios) + if (!info->port.tty || !info->port.tty->termios) return; - cflag = info->tty->termios->c_cflag; + cflag = info->port.tty->termios->c_cflag; if (info->addr == 0) return; @@ -623,7 +623,7 @@ static void mcfrs_change_speed(struct mcf_serial *info) if (i & CBAUDEX) { i &= ~CBAUDEX; if (i < 1 || i > 4) - info->tty->termios->c_cflag &= ~CBAUDEX; + info->port.tty->termios->c_cflag &= ~CBAUDEX; else i += 15; } @@ -1216,7 +1216,7 @@ static void mcfrs_close(struct tty_struct *tty, struct file * filp) tty->closing = 0; info->event = 0; - info->tty = 0; + info->port.tty = NULL; #if 0 if (tty->ldisc.num != ldiscs[N_TTY].num) { if (tty->ldisc.close) @@ -1325,7 +1325,7 @@ void mcfrs_hangup(struct tty_struct *tty) info->event = 0; info->count = 0; info->flags &= ~ASYNC_NORMAL_ACTIVE; - info->tty = 0; + info->port.tty = NULL; wake_up_interruptible(&info->open_wait); } @@ -1452,7 +1452,7 @@ int mcfrs_open(struct tty_struct *tty, struct file * filp) #endif info->count++; tty->driver_data = info; - info->tty = tty; + info->port.tty = tty; /* * Start up serial port @@ -1767,7 +1767,7 @@ mcfrs_init(void) for (i = 0, info = mcfrs_table; (i < NR_PORTS); i++, info++) { info->magic = SERIAL_MAGIC; info->line = i; - info->tty = 0; + info->port.tty = NULL; info->custom_divisor = 16; info->close_delay = 50; info->closing_wait = 3000; diff --git a/drivers/serial/mpc52xx_uart.c b/drivers/serial/mpc52xx_uart.c index efc971d9647b..36126070d9af 100644 --- a/drivers/serial/mpc52xx_uart.c +++ b/drivers/serial/mpc52xx_uart.c @@ -732,7 +732,7 @@ static struct uart_ops mpc52xx_uart_ops = { static inline int mpc52xx_uart_int_rx_chars(struct uart_port *port) { - struct tty_struct *tty = port->info->tty; + struct tty_struct *tty = port->info->port.tty; unsigned char ch, flag; unsigned short status; diff --git a/drivers/serial/mpsc.c b/drivers/serial/mpsc.c index e8819c43f57d..c9f53e71f252 100644 --- a/drivers/serial/mpsc.c +++ b/drivers/serial/mpsc.c @@ -932,7 +932,7 @@ static int mpsc_make_ready(struct mpsc_port_info *pi) static int mpsc_rx_intr(struct mpsc_port_info *pi) { struct mpsc_rx_desc *rxre; - struct tty_struct *tty = pi->port.info->tty; + struct tty_struct *tty = pi->port.info->port.tty; u32 cmdstat, bytes_in, i; int rc = 0; u8 *bp; @@ -1972,7 +1972,7 @@ static int __init mpsc_drv_init(void) { int rc; - printk(KERN_INFO "Serial: MPSC driver $Revision: 1.00 $\n"); + printk(KERN_INFO "Serial: MPSC driver\n"); memset(mpsc_ports, 0, sizeof(mpsc_ports)); memset(&mpsc_shared_regs, 0, sizeof(mpsc_shared_regs)); @@ -2004,7 +2004,7 @@ module_init(mpsc_drv_init); module_exit(mpsc_drv_exit); MODULE_AUTHOR("Mark A. Greer <mgreer@mvista.com>"); -MODULE_DESCRIPTION("Generic Marvell MPSC serial/UART driver $Revision: 1.00 $"); +MODULE_DESCRIPTION("Generic Marvell MPSC serial/UART driver"); MODULE_VERSION(MPSC_VERSION); MODULE_LICENSE("GPL"); MODULE_ALIAS_CHARDEV_MAJOR(MPSC_MAJOR); diff --git a/drivers/serial/mux.c b/drivers/serial/mux.c index e94031731a47..953a5ffa9b44 100644 --- a/drivers/serial/mux.c +++ b/drivers/serial/mux.c @@ -243,7 +243,7 @@ static void mux_write(struct uart_port *port) static void mux_read(struct uart_port *port) { int data; - struct tty_struct *tty = port->info->tty; + struct tty_struct *tty = port->info->port.tty; __u32 start_count = port->icount.rx; while(1) { diff --git a/drivers/serial/netx-serial.c b/drivers/serial/netx-serial.c index 81ac9bb4f39b..9f8ccb735c19 100644 --- a/drivers/serial/netx-serial.c +++ b/drivers/serial/netx-serial.c @@ -203,7 +203,7 @@ static void netx_txint(struct uart_port *port) static void netx_rxint(struct uart_port *port) { unsigned char rx, flg, status; - struct tty_struct *tty = port->info->tty; + struct tty_struct *tty = port->info->port.tty; while (!(readl(port->membase + UART_FR) & FR_RXFE)) { rx = readl(port->membase + UART_DR); diff --git a/drivers/serial/pmac_zilog.c b/drivers/serial/pmac_zilog.c index 794bd0f50d73..317b061f7641 100644 --- a/drivers/serial/pmac_zilog.c +++ b/drivers/serial/pmac_zilog.c @@ -242,12 +242,12 @@ static struct tty_struct *pmz_receive_chars(struct uart_pmac_port *uap) } /* Sanity check, make sure the old bug is no longer happening */ - if (uap->port.info == NULL || uap->port.info->tty == NULL) { + if (uap->port.info == NULL || uap->port.info->port.tty == NULL) { WARN_ON(1); (void)read_zsdata(uap); return NULL; } - tty = uap->port.info->tty; + tty = uap->port.info->port.tty; while (1) { error = 0; diff --git a/drivers/serial/pnx8xxx_uart.c b/drivers/serial/pnx8xxx_uart.c index d0e5a79ea635..22e30d21225e 100644 --- a/drivers/serial/pnx8xxx_uart.c +++ b/drivers/serial/pnx8xxx_uart.c @@ -181,7 +181,7 @@ static void pnx8xxx_enable_ms(struct uart_port *port) static void pnx8xxx_rx_chars(struct pnx8xxx_port *sport) { - struct tty_struct *tty = sport->port.info->tty; + struct tty_struct *tty = sport->port.info->port.tty; unsigned int status, ch, flg; status = FIFO_TO_SM(serial_in(sport, PNX8XXX_FIFO)) | @@ -824,7 +824,7 @@ static int __init pnx8xxx_serial_init(void) { int ret; - printk(KERN_INFO "Serial: PNX8XXX driver $Revision: 1.2 $\n"); + printk(KERN_INFO "Serial: PNX8XXX driver\n"); pnx8xxx_init_ports(); diff --git a/drivers/serial/pxa.c b/drivers/serial/pxa.c index b4f7ffb7688d..b9a93f326fb8 100644 --- a/drivers/serial/pxa.c +++ b/drivers/serial/pxa.c @@ -101,7 +101,7 @@ static void serial_pxa_stop_rx(struct uart_port *port) static inline void receive_chars(struct uart_pxa_port *up, int *status) { - struct tty_struct *tty = up->port.info->tty; + struct tty_struct *tty = up->port.info->port.tty; unsigned int ch, flag; int max_count = 256; diff --git a/drivers/serial/sa1100.c b/drivers/serial/sa1100.c index 62b38582f5e9..a5e76cc18073 100644 --- a/drivers/serial/sa1100.c +++ b/drivers/serial/sa1100.c @@ -20,9 +20,6 @@ * 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 - * - * $Id: sa1100.c,v 1.50 2002/07/29 14:41:04 rmk Exp $ - * */ #if defined(CONFIG_SERIAL_SA1100_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) @@ -192,7 +189,7 @@ static void sa1100_enable_ms(struct uart_port *port) static void sa1100_rx_chars(struct sa1100_port *sport) { - struct tty_struct *tty = sport->port.info->tty; + struct tty_struct *tty = sport->port.info->port.tty; unsigned int status, ch, flg; status = UTSR1_TO_SM(UART_GET_UTSR1(sport)) | @@ -892,7 +889,7 @@ static int __init sa1100_serial_init(void) { int ret; - printk(KERN_INFO "Serial: SA11x0 driver $Revision: 1.50 $\n"); + printk(KERN_INFO "Serial: SA11x0 driver\n"); sa1100_init_ports(); @@ -915,7 +912,7 @@ module_init(sa1100_serial_init); module_exit(sa1100_serial_exit); MODULE_AUTHOR("Deep Blue Solutions Ltd"); -MODULE_DESCRIPTION("SA1100 generic serial port driver $Revision: 1.50 $"); +MODULE_DESCRIPTION("SA1100 generic serial port driver"); MODULE_LICENSE("GPL"); MODULE_ALIAS_CHARDEV_MAJOR(SERIAL_SA1100_MAJOR); MODULE_ALIAS("platform:sa11x0-uart"); diff --git a/drivers/serial/sb1250-duart.c b/drivers/serial/sb1250-duart.c index f8e1447a022a..a4fb343a08da 100644 --- a/drivers/serial/sb1250-duart.c +++ b/drivers/serial/sb1250-duart.c @@ -384,7 +384,7 @@ static void sbd_receive_chars(struct sbd_port *sport) uart_insert_char(uport, status, M_DUART_OVRUN_ERR, ch, flag); } - tty_flip_buffer_push(uport->info->tty); + tty_flip_buffer_push(uport->info->port.tty); } static void sbd_transmit_chars(struct sbd_port *sport) diff --git a/drivers/serial/sc26xx.c b/drivers/serial/sc26xx.c index ae2a9e2df777..e0be11ceaa25 100644 --- a/drivers/serial/sc26xx.c +++ b/drivers/serial/sc26xx.c @@ -141,7 +141,7 @@ static struct tty_struct *receive_chars(struct uart_port *port) u8 status; if (port->info != NULL) /* Unopened serial console */ - tty = port->info->tty; + tty = port->info->port.tty; while (limit-- > 0) { status = READ_SC_PORT(port, SR); diff --git a/drivers/serial/serial_core.c b/drivers/serial/serial_core.c index 42d2e108b679..0bce1fe2c62a 100644 --- a/drivers/serial/serial_core.c +++ b/drivers/serial/serial_core.c @@ -50,7 +50,7 @@ static struct lock_class_key port_lock_key; #define HIGH_BITS_OFFSET ((sizeof(long)-sizeof(int))*8) -#define uart_users(state) ((state)->count + ((state)->info ? (state)->info->blocked_open : 0)) +#define uart_users(state) ((state)->count + ((state)->info ? (state)->info->port.blocked_open : 0)) #ifdef CONFIG_SERIAL_CORE_CONSOLE #define uart_console(port) ((port)->cons && (port)->cons->index == (port)->line) @@ -113,7 +113,7 @@ static void uart_start(struct tty_struct *tty) static void uart_tasklet_action(unsigned long data) { struct uart_state *state = (struct uart_state *)data; - tty_wakeup(state->info->tty); + tty_wakeup(state->info->port.tty); } static inline void @@ -135,7 +135,7 @@ uart_update_mctrl(struct uart_port *port, unsigned int set, unsigned int clear) /* * Startup the port. This will be called once per open. All calls - * will be serialised by the per-port semaphore. + * will be serialised by the per-port mutex. */ static int uart_startup(struct uart_state *state, int init_hw) { @@ -152,7 +152,7 @@ static int uart_startup(struct uart_state *state, int init_hw) * once we have successfully opened the port. Also set * up the tty->alt_speed kludge */ - set_bit(TTY_IO_ERROR, &info->tty->flags); + set_bit(TTY_IO_ERROR, &info->port.tty->flags); if (port->type == PORT_UNKNOWN) return 0; @@ -162,6 +162,7 @@ static int uart_startup(struct uart_state *state, int init_hw) * buffer. */ if (!info->xmit.buf) { + /* This is protected by the per port mutex */ page = get_zeroed_page(GFP_KERNEL); if (!page) return -ENOMEM; @@ -182,20 +183,20 @@ static int uart_startup(struct uart_state *state, int init_hw) * Setup the RTS and DTR signals once the * port is open and ready to respond. */ - if (info->tty->termios->c_cflag & CBAUD) + if (info->port.tty->termios->c_cflag & CBAUD) uart_set_mctrl(port, TIOCM_RTS | TIOCM_DTR); } if (info->flags & UIF_CTS_FLOW) { spin_lock_irq(&port->lock); if (!(port->ops->get_mctrl(port) & TIOCM_CTS)) - info->tty->hw_stopped = 1; + info->port.tty->hw_stopped = 1; spin_unlock_irq(&port->lock); } info->flags |= UIF_INITIALIZED; - clear_bit(TTY_IO_ERROR, &info->tty->flags); + clear_bit(TTY_IO_ERROR, &info->port.tty->flags); } if (retval && capable(CAP_SYS_ADMIN)) @@ -217,8 +218,8 @@ static void uart_shutdown(struct uart_state *state) /* * Set the TTY IO error marker */ - if (info->tty) - set_bit(TTY_IO_ERROR, &info->tty->flags); + if (info->port.tty) + set_bit(TTY_IO_ERROR, &info->port.tty->flags); if (info->flags & UIF_INITIALIZED) { info->flags &= ~UIF_INITIALIZED; @@ -226,7 +227,7 @@ static void uart_shutdown(struct uart_state *state) /* * Turn off DTR and RTS early. */ - if (!info->tty || (info->tty->termios->c_cflag & HUPCL)) + if (!info->port.tty || (info->port.tty->termios->c_cflag & HUPCL)) uart_clear_mctrl(port, TIOCM_DTR | TIOCM_RTS); /* @@ -426,7 +427,7 @@ EXPORT_SYMBOL(uart_get_divisor); static void uart_change_speed(struct uart_state *state, struct ktermios *old_termios) { - struct tty_struct *tty = state->info->tty; + struct tty_struct *tty = state->info->port.tty; struct uart_port *port = state->port; struct ktermios *termios; @@ -573,6 +574,8 @@ static void uart_flush_buffer(struct tty_struct *tty) spin_lock_irqsave(&port->lock, flags); uart_circ_clear(&state->info->xmit); + if (port->ops->flush_buffer) + port->ops->flush_buffer(port); spin_unlock_irqrestore(&port->lock, flags); tty_wakeup(tty); } @@ -834,8 +837,8 @@ static int uart_set_info(struct uart_state *state, state->closing_wait = closing_wait; if (new_serial.xmit_fifo_size) port->fifosize = new_serial.xmit_fifo_size; - if (state->info->tty) - state->info->tty->low_latency = + if (state->info->port.tty) + state->info->port.tty->low_latency = (port->flags & UPF_LOW_LATENCY) ? 1 : 0; check_and_exit: @@ -855,7 +858,7 @@ static int uart_set_info(struct uart_state *state, printk(KERN_NOTICE "%s sets custom speed on %s. This " "is deprecated.\n", current->comm, - tty_name(state->info->tty, buf)); + tty_name(state->info->port.tty, buf)); } uart_change_speed(state, NULL); } @@ -887,7 +890,7 @@ static int uart_get_lsr_info(struct uart_state *state, */ if (port->x_char || ((uart_circ_chars_pending(&state->info->xmit) > 0) && - !state->info->tty->stopped && !state->info->tty->hw_stopped)) + !state->info->port.tty->stopped && !state->info->port.tty->hw_stopped)) result &= ~TIOCSER_TEMT; return put_user(result, value); @@ -1237,7 +1240,7 @@ static void uart_set_termios(struct tty_struct *tty, */ if (!(old_termios->c_cflag & CLOCAL) && (tty->termios->c_cflag & CLOCAL)) - wake_up_interruptible(&state->info->open_wait); + wake_up_interruptible(&state->info->port.open_wait); #endif } @@ -1318,9 +1321,9 @@ static void uart_close(struct tty_struct *tty, struct file *filp) tty_ldisc_flush(tty); tty->closing = 0; - state->info->tty = NULL; + state->info->port.tty = NULL; - if (state->info->blocked_open) { + if (state->info->port.blocked_open) { if (state->close_delay) msleep_interruptible(state->close_delay); } else if (!uart_console(port)) { @@ -1331,7 +1334,7 @@ static void uart_close(struct tty_struct *tty, struct file *filp) * Wake up anyone trying to open this port. */ state->info->flags &= ~UIF_NORMAL_ACTIVE; - wake_up_interruptible(&state->info->open_wait); + wake_up_interruptible(&state->info->port.open_wait); done: mutex_unlock(&state->mutex); @@ -1415,8 +1418,8 @@ static void uart_hangup(struct tty_struct *tty) uart_shutdown(state); state->count = 0; state->info->flags &= ~UIF_NORMAL_ACTIVE; - state->info->tty = NULL; - wake_up_interruptible(&state->info->open_wait); + state->info->port.tty = NULL; + wake_up_interruptible(&state->info->port.open_wait); wake_up_interruptible(&state->info->delta_msr_wait); } mutex_unlock(&state->mutex); @@ -1430,7 +1433,7 @@ static void uart_hangup(struct tty_struct *tty) */ static void uart_update_termios(struct uart_state *state) { - struct tty_struct *tty = state->info->tty; + struct tty_struct *tty = state->info->port.tty; struct uart_port *port = state->port; if (uart_console(port) && port->cons->cflag) { @@ -1469,17 +1472,17 @@ uart_block_til_ready(struct file *filp, struct uart_state *state) struct uart_port *port = state->port; unsigned int mctrl; - info->blocked_open++; + info->port.blocked_open++; state->count--; - add_wait_queue(&info->open_wait, &wait); + add_wait_queue(&info->port.open_wait, &wait); while (1) { set_current_state(TASK_INTERRUPTIBLE); /* * If we have been hung up, tell userspace/restart open. */ - if (tty_hung_up_p(filp) || info->tty == NULL) + if (tty_hung_up_p(filp) || info->port.tty == NULL) break; /* @@ -1498,8 +1501,8 @@ uart_block_til_ready(struct file *filp, struct uart_state *state) * have set TTY_IO_ERROR for a non-existant port. */ if ((filp->f_flags & O_NONBLOCK) || - (info->tty->termios->c_cflag & CLOCAL) || - (info->tty->flags & (1 << TTY_IO_ERROR))) + (info->port.tty->termios->c_cflag & CLOCAL) || + (info->port.tty->flags & (1 << TTY_IO_ERROR))) break; /* @@ -1507,7 +1510,7 @@ uart_block_til_ready(struct file *filp, struct uart_state *state) * not set RTS here - we want to make sure we catch * the data from the modem. */ - if (info->tty->termios->c_cflag & CBAUD) + if (info->port.tty->termios->c_cflag & CBAUD) uart_set_mctrl(port, TIOCM_DTR); /* @@ -1529,15 +1532,15 @@ uart_block_til_ready(struct file *filp, struct uart_state *state) break; } set_current_state(TASK_RUNNING); - remove_wait_queue(&info->open_wait, &wait); + remove_wait_queue(&info->port.open_wait, &wait); state->count++; - info->blocked_open--; + info->port.blocked_open--; if (signal_pending(current)) return -ERESTARTSYS; - if (!info->tty || tty_hung_up_p(filp)) + if (!info->port.tty || tty_hung_up_p(filp)) return -EAGAIN; return 0; @@ -1560,10 +1563,13 @@ static struct uart_state *uart_get(struct uart_driver *drv, int line) goto err_unlock; } + /* BKL: RACE HERE - LEAK */ + /* We should move this into the uart_state structure and kill off + this whole complexity */ if (!state->info) { state->info = kzalloc(sizeof(struct uart_info), GFP_KERNEL); if (state->info) { - init_waitqueue_head(&state->info->open_wait); + init_waitqueue_head(&state->info->port.open_wait); init_waitqueue_head(&state->info->delta_msr_wait); /* @@ -1620,7 +1626,7 @@ static int uart_open(struct tty_struct *tty, struct file *filp) * be re-entered while allocating the info structure, or while we * request any IRQs that the driver may need. This also has the nice * side-effect that it delays the action of uart_hangup, so we can - * guarantee that info->tty will always contain something reasonable. + * guarantee that info->port.tty will always contain something reasonable. */ state = uart_get(drv, line); if (IS_ERR(state)) { @@ -1636,7 +1642,7 @@ static int uart_open(struct tty_struct *tty, struct file *filp) tty->driver_data = state; tty->low_latency = (state->port->flags & UPF_LOW_LATENCY) ? 1 : 0; tty->alt_speed = 0; - state->info->tty = tty; + state->info->port.tty = tty; /* * If the port is in the middle of closing, bail out now. @@ -2099,8 +2105,8 @@ int uart_resume_port(struct uart_driver *drv, struct uart_port *port) /* * If that's unset, use the tty termios setting. */ - if (state->info && state->info->tty && termios.c_cflag == 0) - termios = *state->info->tty->termios; + if (state->info && state->info->port.tty && termios.c_cflag == 0) + termios = *state->info->port.tty->termios; uart_change_pm(state, 0); port->ops->set_termios(port, &termios, NULL); @@ -2519,8 +2525,8 @@ int uart_remove_one_port(struct uart_driver *drv, struct uart_port *port) tty_unregister_device(drv->tty_driver, port->line); info = state->info; - if (info && info->tty) - tty_vhangup(info->tty); + if (info && info->port.tty) + tty_vhangup(info->port.tty); /* * All users of this port should now be disconnected from diff --git a/drivers/serial/serial_ks8695.c b/drivers/serial/serial_ks8695.c index 8721afe1ae4f..0edbc5dd378b 100644 --- a/drivers/serial/serial_ks8695.c +++ b/drivers/serial/serial_ks8695.c @@ -108,7 +108,7 @@ static void ks8695uart_disable_ms(struct uart_port *port) static irqreturn_t ks8695uart_rx_chars(int irq, void *dev_id) { struct uart_port *port = dev_id; - struct tty_struct *tty = port->info->tty; + struct tty_struct *tty = port->info->port.tty; unsigned int status, ch, lsr, flg, max_count = 256; status = UART_GET_LSR(port); /* clears pending LSR interrupts */ diff --git a/drivers/serial/serial_lh7a40x.c b/drivers/serial/serial_lh7a40x.c index eb18d429752d..cb49a5ac022f 100644 --- a/drivers/serial/serial_lh7a40x.c +++ b/drivers/serial/serial_lh7a40x.c @@ -137,7 +137,7 @@ static void lh7a40xuart_enable_ms (struct uart_port* port) static void lh7a40xuart_rx_chars (struct uart_port* port) { - struct tty_struct* tty = port->info->tty; + struct tty_struct* tty = port->info->port.tty; int cbRxMax = 256; /* (Gross) limit on receive */ unsigned int data; /* Received data and status */ unsigned int flag; diff --git a/drivers/serial/sh-sci.c b/drivers/serial/sh-sci.c index ce6ee92b3a1b..208e42ba9455 100644 --- a/drivers/serial/sh-sci.c +++ b/drivers/serial/sh-sci.c @@ -521,7 +521,7 @@ static void sci_transmit_chars(struct uart_port *port) static inline void sci_receive_chars(struct uart_port *port) { struct sci_port *sci_port = (struct sci_port *)port; - struct tty_struct *tty = port->info->tty; + struct tty_struct *tty = port->info->port.tty; int i, count, copied = 0; unsigned short status; unsigned char flag; @@ -642,7 +642,7 @@ static inline int sci_handle_errors(struct uart_port *port) { int copied = 0; unsigned short status = sci_in(port, SCxSR); - struct tty_struct *tty = port->info->tty; + struct tty_struct *tty = port->info->port.tty; if (status & SCxSR_ORER(port)) { /* overrun error */ @@ -692,7 +692,7 @@ static inline int sci_handle_breaks(struct uart_port *port) { int copied = 0; unsigned short status = sci_in(port, SCxSR); - struct tty_struct *tty = port->info->tty; + struct tty_struct *tty = port->info->port.tty; struct sci_port *s = &sci_ports[port->line]; if (uart_handle_break(port)) @@ -762,7 +762,7 @@ static irqreturn_t sci_er_interrupt(int irq, void *ptr) } else { #if defined(SCIF_ORER) if((sci_in(port, SCLSR) & SCIF_ORER) != 0) { - struct tty_struct *tty = port->info->tty; + struct tty_struct *tty = port->info->port.tty; sci_out(port, SCLSR, 0); tty_insert_flip_char(tty, 0, TTY_OVERRUN); diff --git a/drivers/serial/sn_console.c b/drivers/serial/sn_console.c index 019da2e05f0b..b73e3c0056cd 100644 --- a/drivers/serial/sn_console.c +++ b/drivers/serial/sn_console.c @@ -471,7 +471,7 @@ sn_receive_chars(struct sn_cons_port *port, unsigned long flags) if (port->sc_port.info) { /* The serial_core stuffs are initilized, use them */ - tty = port->sc_port.info->tty; + tty = port->sc_port.info->port.tty; } else { /* Not registered yet - can't pass to tty layer. */ diff --git a/drivers/serial/sunhv.c b/drivers/serial/sunhv.c index 2847336742d7..aeeec5588afd 100644 --- a/drivers/serial/sunhv.c +++ b/drivers/serial/sunhv.c @@ -185,7 +185,7 @@ static struct tty_struct *receive_chars(struct uart_port *port) struct tty_struct *tty = NULL; if (port->info != NULL) /* Unopened serial console */ - tty = port->info->tty; + tty = port->info->port.tty; if (sunhv_ops->receive_chars(port, tty)) sun_do_break(); diff --git a/drivers/serial/sunsab.c b/drivers/serial/sunsab.c index 9ff5b38f3bee..15ee497e1c78 100644 --- a/drivers/serial/sunsab.c +++ b/drivers/serial/sunsab.c @@ -118,7 +118,7 @@ receive_chars(struct uart_sunsab_port *up, int i; if (up->port.info != NULL) /* Unopened serial console */ - tty = up->port.info->tty; + tty = up->port.info->port.tty; /* Read number of BYTES (Character + Status) available. */ if (stat->sreg.isr0 & SAB82532_ISR0_RPF) { diff --git a/drivers/serial/sunsu.c b/drivers/serial/sunsu.c index 03806a935209..e24e68235088 100644 --- a/drivers/serial/sunsu.c +++ b/drivers/serial/sunsu.c @@ -1,4 +1,4 @@ -/* $Id: su.c,v 1.55 2002/01/08 16:00:16 davem Exp $ +/* * su.c: Small serial driver for keyboard/mouse interface on sparc32/PCI * * Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be) @@ -311,7 +311,7 @@ static void sunsu_enable_ms(struct uart_port *port) static struct tty_struct * receive_chars(struct uart_sunsu_port *up, unsigned char *status) { - struct tty_struct *tty = up->port.info->tty; + struct tty_struct *tty = up->port.info->port.tty; unsigned char ch, flag; int max_count = 256; int saw_console_brk = 0; diff --git a/drivers/serial/sunzilog.c b/drivers/serial/sunzilog.c index 7e9fa5ef0eb7..0f3d69b86d67 100644 --- a/drivers/serial/sunzilog.c +++ b/drivers/serial/sunzilog.c @@ -329,8 +329,8 @@ sunzilog_receive_chars(struct uart_sunzilog_port *up, tty = NULL; if (up->port.info != NULL && /* Unopened serial console */ - up->port.info->tty != NULL) /* Keyboard || mouse */ - tty = up->port.info->tty; + up->port.info->port.tty != NULL) /* Keyboard || mouse */ + tty = up->port.info->port.tty; for (;;) { diff --git a/drivers/serial/uartlite.c b/drivers/serial/uartlite.c index b51c24245be4..6a3f8fb0c9dd 100644 --- a/drivers/serial/uartlite.c +++ b/drivers/serial/uartlite.c @@ -75,7 +75,7 @@ static struct uart_port ulite_ports[ULITE_NR_UARTS]; static int ulite_receive(struct uart_port *port, int stat) { - struct tty_struct *tty = port->info->tty; + struct tty_struct *tty = port->info->port.tty; unsigned char ch = 0; char flag = TTY_NORMAL; @@ -162,7 +162,7 @@ static irqreturn_t ulite_isr(int irq, void *dev_id) busy |= ulite_transmit(port, stat); } while (busy); - tty_flip_buffer_push(port->info->tty); + tty_flip_buffer_push(port->info->port.tty); return IRQ_HANDLED; } diff --git a/drivers/serial/ucc_uart.c b/drivers/serial/ucc_uart.c index 566a8b42e05a..5c5d18dcb6ac 100644 --- a/drivers/serial/ucc_uart.c +++ b/drivers/serial/ucc_uart.c @@ -466,7 +466,7 @@ static void qe_uart_int_rx(struct uart_qe_port *qe_port) int i; unsigned char ch, *cp; struct uart_port *port = &qe_port->port; - struct tty_struct *tty = port->info->tty; + struct tty_struct *tty = port->info->port.tty; struct qe_bd *bdp; u16 status; unsigned int flg; diff --git a/drivers/serial/v850e_uart.c b/drivers/serial/v850e_uart.c index dd98aca6ed08..5acf061b6cd2 100644 --- a/drivers/serial/v850e_uart.c +++ b/drivers/serial/v850e_uart.c @@ -300,8 +300,8 @@ static irqreturn_t v850e_uart_rx_irq(int irq, void *data) port->icount.rx++; - tty_insert_flip_char (port->info->tty, ch, ch_stat); - tty_schedule_flip (port->info->tty); + tty_insert_flip_char (port->info->port.tty, ch, ch_stat); + tty_schedule_flip (port->info->port.tty); return IRQ_HANDLED; } diff --git a/drivers/serial/vr41xx_siu.c b/drivers/serial/vr41xx_siu.c index bb6ce6bba32f..0573f3b5175e 100644 --- a/drivers/serial/vr41xx_siu.c +++ b/drivers/serial/vr41xx_siu.c @@ -318,7 +318,7 @@ static inline void receive_chars(struct uart_port *port, uint8_t *status) char flag; int max_count = RX_MAX_COUNT; - tty = port->info->tty; + tty = port->info->port.tty; lsr = *status; do { diff --git a/drivers/serial/zs.c b/drivers/serial/zs.c index 65f1294fd27b..bd45b6230fd8 100644 --- a/drivers/serial/zs.c +++ b/drivers/serial/zs.c @@ -602,7 +602,7 @@ static void zs_receive_chars(struct zs_port *zport) uart_insert_char(uport, status, Rx_OVR, ch, flag); } - tty_flip_buffer_push(uport->info->tty); + tty_flip_buffer_push(uport->info->port.tty); } static void zs_raw_transmit_chars(struct zs_port *zport) diff --git a/drivers/ssb/Kconfig b/drivers/ssb/Kconfig index cd845b8acd17..307b1f62d949 100644 --- a/drivers/ssb/Kconfig +++ b/drivers/ssb/Kconfig @@ -2,7 +2,7 @@ menu "Sonics Silicon Backplane" config SSB_POSSIBLE bool - depends on HAS_IOMEM + depends on HAS_IOMEM && HAS_DMA default y config SSB diff --git a/drivers/ssb/main.c b/drivers/ssb/main.c index d184f2aea78d..d831a2beff39 100644 --- a/drivers/ssb/main.c +++ b/drivers/ssb/main.c @@ -462,18 +462,15 @@ static int ssb_devices_register(struct ssb_bus *bus) #ifdef CONFIG_SSB_PCIHOST sdev->irq = bus->host_pci->irq; dev->parent = &bus->host_pci->dev; - sdev->dma_dev = &bus->host_pci->dev; #endif break; case SSB_BUSTYPE_PCMCIA: #ifdef CONFIG_SSB_PCMCIAHOST sdev->irq = bus->host_pcmcia->irq.AssignedIRQ; dev->parent = &bus->host_pcmcia->dev; - sdev->dma_dev = &bus->host_pcmcia->dev; #endif break; case SSB_BUSTYPE_SSB: - sdev->dma_dev = dev; break; } @@ -1156,36 +1153,82 @@ u32 ssb_dma_translation(struct ssb_device *dev) { switch (dev->bus->bustype) { case SSB_BUSTYPE_SSB: - case SSB_BUSTYPE_PCMCIA: return 0; case SSB_BUSTYPE_PCI: return SSB_PCI_DMA; + default: + __ssb_dma_not_implemented(dev); } return 0; } EXPORT_SYMBOL(ssb_dma_translation); -int ssb_dma_set_mask(struct ssb_device *ssb_dev, u64 mask) +int ssb_dma_set_mask(struct ssb_device *dev, u64 mask) { - struct device *dma_dev = ssb_dev->dma_dev; - int err = 0; + int err; -#ifdef CONFIG_SSB_PCIHOST - if (ssb_dev->bus->bustype == SSB_BUSTYPE_PCI) { - err = pci_set_dma_mask(ssb_dev->bus->host_pci, mask); + switch (dev->bus->bustype) { + case SSB_BUSTYPE_PCI: + err = pci_set_dma_mask(dev->bus->host_pci, mask); if (err) return err; - err = pci_set_consistent_dma_mask(ssb_dev->bus->host_pci, mask); + err = pci_set_consistent_dma_mask(dev->bus->host_pci, mask); return err; + case SSB_BUSTYPE_SSB: + return dma_set_mask(dev->dev, mask); + default: + __ssb_dma_not_implemented(dev); } -#endif - dma_dev->coherent_dma_mask = mask; - dma_dev->dma_mask = &dma_dev->coherent_dma_mask; - - return err; + return -ENOSYS; } EXPORT_SYMBOL(ssb_dma_set_mask); +void * ssb_dma_alloc_consistent(struct ssb_device *dev, size_t size, + dma_addr_t *dma_handle, gfp_t gfp_flags) +{ + switch (dev->bus->bustype) { + case SSB_BUSTYPE_PCI: + if (gfp_flags & GFP_DMA) { + /* Workaround: The PCI API does not support passing + * a GFP flag. */ + return dma_alloc_coherent(&dev->bus->host_pci->dev, + size, dma_handle, gfp_flags); + } + return pci_alloc_consistent(dev->bus->host_pci, size, dma_handle); + case SSB_BUSTYPE_SSB: + return dma_alloc_coherent(dev->dev, size, dma_handle, gfp_flags); + default: + __ssb_dma_not_implemented(dev); + } + return NULL; +} +EXPORT_SYMBOL(ssb_dma_alloc_consistent); + +void ssb_dma_free_consistent(struct ssb_device *dev, size_t size, + void *vaddr, dma_addr_t dma_handle, + gfp_t gfp_flags) +{ + switch (dev->bus->bustype) { + case SSB_BUSTYPE_PCI: + if (gfp_flags & GFP_DMA) { + /* Workaround: The PCI API does not support passing + * a GFP flag. */ + dma_free_coherent(&dev->bus->host_pci->dev, + size, vaddr, dma_handle); + return; + } + pci_free_consistent(dev->bus->host_pci, size, + vaddr, dma_handle); + return; + case SSB_BUSTYPE_SSB: + dma_free_coherent(dev->dev, size, vaddr, dma_handle); + return; + default: + __ssb_dma_not_implemented(dev); + } +} +EXPORT_SYMBOL(ssb_dma_free_consistent); + int ssb_bus_may_powerdown(struct ssb_bus *bus) { struct ssb_chipcommon *cc; diff --git a/drivers/ssb/pci.c b/drivers/ssb/pci.c index 57c4ccfab1ee..f883dcfffe06 100644 --- a/drivers/ssb/pci.c +++ b/drivers/ssb/pci.c @@ -510,17 +510,15 @@ static int ssb_pci_sprom_get(struct ssb_bus *bus, sprom_do_read(bus, buf); err = sprom_check_crc(buf, bus->sprom_size); if (err) { - /* check for rev 4 sprom - has special signature */ - if (buf[32] == 0x5372) { - kfree(buf); - buf = kcalloc(SSB_SPROMSIZE_WORDS_R4, sizeof(u16), - GFP_KERNEL); - if (!buf) - goto out; - bus->sprom_size = SSB_SPROMSIZE_WORDS_R4; - sprom_do_read(bus, buf); - err = sprom_check_crc(buf, bus->sprom_size); - } + /* try for a 440 byte SPROM - revision 4 and higher */ + kfree(buf); + buf = kcalloc(SSB_SPROMSIZE_WORDS_R4, sizeof(u16), + GFP_KERNEL); + if (!buf) + goto out; + bus->sprom_size = SSB_SPROMSIZE_WORDS_R4; + sprom_do_read(bus, buf); + err = sprom_check_crc(buf, bus->sprom_size); if (err) ssb_printk(KERN_WARNING PFX "WARNING: Invalid" " SPROM CRC (corrupt SPROM)\n"); diff --git a/drivers/video/amifb.c b/drivers/video/amifb.c index 05a328c11a8b..45c154ade9ca 100644 --- a/drivers/video/amifb.c +++ b/drivers/video/amifb.c @@ -2383,6 +2383,9 @@ default_chipset: goto amifb_error; } + fb_videomode_to_modelist(ami_modedb, NUM_TOTAL_MODES, + &fb_info.modelist); + round_down_bpp = 0; chipptr = chipalloc(fb_info.fix.smem_len+ SPRITEMEMSIZE+ diff --git a/drivers/video/atafb.c b/drivers/video/atafb.c index dff35474b854..fa55d356b535 100644 --- a/drivers/video/atafb.c +++ b/drivers/video/atafb.c @@ -3110,7 +3110,7 @@ int __init atafb_init(void) printk("atafb_init: start\n"); if (!MACH_IS_ATARI) - return -ENXIO; + return -ENODEV; do { #ifdef ATAFB_EXT @@ -3230,6 +3230,9 @@ int __init atafb_init(void) return -EINVAL; } + fb_videomode_to_modelist(atafb_modedb, NUM_TOTAL_MODES, + &fb_info.modelist); + atafb_set_disp(&fb_info); fb_alloc_cmap(&(fb_info.cmap), 1 << fb_info.var.bits_per_pixel, 0); diff --git a/drivers/video/c2p.c b/drivers/video/c2p.c index 5c30bbd33054..376bc07ff952 100644 --- a/drivers/video/c2p.c +++ b/drivers/video/c2p.c @@ -12,6 +12,7 @@ * for more details. */ +#include <linux/module.h> #include <linux/string.h> #include "c2p.h" @@ -226,4 +227,6 @@ void c2p(u8 *dst, const u8 *src, u32 dx, u32 dy, u32 width, u32 height, dst += dst_nextline; } } +EXPORT_SYMBOL_GPL(c2p); +MODULE_LICENSE("GPL"); diff --git a/drivers/xen/manage.c b/drivers/xen/manage.c index 5b546e365f00..a5bc91ae6ff6 100644 --- a/drivers/xen/manage.c +++ b/drivers/xen/manage.c @@ -63,11 +63,12 @@ static int xen_suspend(void *data) gnttab_resume(); xen_mm_unpin_all(); - device_power_up(); + device_power_up(PMSG_RESUME); if (!*cancelled) { xen_irq_resume(); xen_console_resume(); + xen_timer_resume(); } return 0; @@ -107,12 +108,13 @@ static void do_suspend(void) goto out; } - if (!cancelled) + if (!cancelled) { + xen_arch_resume(); xenbus_resume(); - else + } else xenbus_suspend_cancel(); - device_resume(); + device_resume(PMSG_RESUME); /* Make sure timer events get retriggered on all CPUs */ clock_was_set(); diff --git a/drivers/zorro/proc.c b/drivers/zorro/proc.c index 099b6fb5b5cb..d47c47fc048f 100644 --- a/drivers/zorro/proc.c +++ b/drivers/zorro/proc.c @@ -1,6 +1,4 @@ /* - * $Id: proc.c,v 1.1.2.1 1998/06/07 23:21:01 geert Exp $ - * * Procfs interface for the Zorro bus. * * Copyright (C) 1998-2003 Geert Uytterhoeven @@ -160,4 +158,4 @@ static int __init zorro_proc_init(void) return 0; } -__initcall(zorro_proc_init); +device_initcall(zorro_proc_init); diff --git a/drivers/zorro/zorro-sysfs.c b/drivers/zorro/zorro-sysfs.c index 808b4f8675c5..3da712cc7708 100644 --- a/drivers/zorro/zorro-sysfs.c +++ b/drivers/zorro/zorro-sysfs.c @@ -15,6 +15,7 @@ #include <linux/zorro.h> #include <linux/stat.h> #include <linux/string.h> +#include <linux/fs.h> #include "zorro.h" @@ -56,12 +57,6 @@ static ssize_t zorro_read_config(struct kobject *kobj, struct zorro_dev *z = to_zorro_dev(container_of(kobj, struct device, kobj)); struct ConfigDev cd; - unsigned int size = sizeof(cd); - - if (off > size) - return 0; - if (off+count > size) - count = size-off; /* Construct a ConfigDev */ memset(&cd, 0, sizeof(cd)); @@ -71,8 +66,7 @@ static ssize_t zorro_read_config(struct kobject *kobj, cd.cd_BoardAddr = (void *)zorro_resource_start(z); cd.cd_BoardSize = zorro_resource_len(z); - memcpy(buf, (void *)&cd+off, count); - return count; + return memory_read_from_buffer(buf, count, &off, &cd, sizeof(cd)); } static struct bin_attribute zorro_config_attr = { diff --git a/drivers/zorro/zorro.c b/drivers/zorro/zorro.c index 4cc42b64820c..dff16d9767d8 100644 --- a/drivers/zorro/zorro.c +++ b/drivers/zorro/zorro.c @@ -1,6 +1,4 @@ /* - * $Id: zorro.c,v 1.1.2.1 1998/06/07 23:21:02 geert Exp $ - * * Zorro Bus Services * * Copyright (C) 1995-2003 Geert Uytterhoeven diff --git a/drivers/zorro/zorro.ids b/drivers/zorro/zorro.ids index 560fef2a7b1c..0c0f99e2dd62 100644 --- a/drivers/zorro/zorro.ids +++ b/drivers/zorro/zorro.ids @@ -4,8 +4,6 @@ # Maintained by Geert Uytterhoeven <zorro@linux-m68k.org> # If you have any new entries, please send them to the maintainer. # -# $Id: zorro.ids,v 1.19 2002/10/14 13:08:58 geert Exp $ -# # Manufacturers and Products. Please keep sorted. diff --git a/fs/compat_ioctl.c b/fs/compat_ioctl.c index c54eaab71a19..7b3a03c7c6a9 100644 --- a/fs/compat_ioctl.c +++ b/fs/compat_ioctl.c @@ -58,7 +58,6 @@ #include <linux/syscalls.h> #include <linux/i2c.h> #include <linux/i2c-dev.h> -#include <linux/wireless.h> #include <linux/atalk.h> #include <linux/loop.h> @@ -1759,64 +1758,6 @@ static int do_i2c_smbus_ioctl(unsigned int fd, unsigned int cmd, unsigned long a return sys_ioctl(fd, cmd, (unsigned long)tdata); } -struct compat_iw_point { - compat_caddr_t pointer; - __u16 length; - __u16 flags; -}; - -static int do_wireless_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg) -{ - struct iwreq __user *iwr; - struct iwreq __user *iwr_u; - struct iw_point __user *iwp; - struct compat_iw_point __user *iwp_u; - compat_caddr_t pointer_u; - void __user *pointer; - __u16 length, flags; - int ret; - - iwr_u = compat_ptr(arg); - iwp_u = (struct compat_iw_point __user *) &iwr_u->u.data; - iwr = compat_alloc_user_space(sizeof(*iwr)); - if (iwr == NULL) - return -ENOMEM; - - iwp = &iwr->u.data; - - if (!access_ok(VERIFY_WRITE, iwr, sizeof(*iwr))) - return -EFAULT; - - if (__copy_in_user(&iwr->ifr_ifrn.ifrn_name[0], - &iwr_u->ifr_ifrn.ifrn_name[0], - sizeof(iwr->ifr_ifrn.ifrn_name))) - return -EFAULT; - - if (__get_user(pointer_u, &iwp_u->pointer) || - __get_user(length, &iwp_u->length) || - __get_user(flags, &iwp_u->flags)) - return -EFAULT; - - if (__put_user(compat_ptr(pointer_u), &iwp->pointer) || - __put_user(length, &iwp->length) || - __put_user(flags, &iwp->flags)) - return -EFAULT; - - ret = sys_ioctl(fd, cmd, (unsigned long) iwr); - - if (__get_user(pointer, &iwp->pointer) || - __get_user(length, &iwp->length) || - __get_user(flags, &iwp->flags)) - return -EFAULT; - - if (__put_user(ptr_to_compat(pointer), &iwp_u->pointer) || - __put_user(length, &iwp_u->length) || - __put_user(flags, &iwp_u->flags)) - return -EFAULT; - - return ret; -} - /* Since old style bridge ioctl's endup using SIOCDEVPRIVATE * for some operations; this forces use of the newer bridge-utils that * use compatiable ioctls @@ -2405,6 +2346,7 @@ COMPATIBLE_IOCTL(HCIGETDEVLIST) COMPATIBLE_IOCTL(HCIGETDEVINFO) COMPATIBLE_IOCTL(HCIGETCONNLIST) COMPATIBLE_IOCTL(HCIGETCONNINFO) +COMPATIBLE_IOCTL(HCIGETAUTHINFO) COMPATIBLE_IOCTL(HCISETRAW) COMPATIBLE_IOCTL(HCISETSCAN) COMPATIBLE_IOCTL(HCISETAUTH) @@ -2501,36 +2443,6 @@ COMPATIBLE_IOCTL(I2C_TENBIT) COMPATIBLE_IOCTL(I2C_PEC) COMPATIBLE_IOCTL(I2C_RETRIES) COMPATIBLE_IOCTL(I2C_TIMEOUT) -/* wireless */ -COMPATIBLE_IOCTL(SIOCSIWCOMMIT) -COMPATIBLE_IOCTL(SIOCGIWNAME) -COMPATIBLE_IOCTL(SIOCSIWNWID) -COMPATIBLE_IOCTL(SIOCGIWNWID) -COMPATIBLE_IOCTL(SIOCSIWFREQ) -COMPATIBLE_IOCTL(SIOCGIWFREQ) -COMPATIBLE_IOCTL(SIOCSIWMODE) -COMPATIBLE_IOCTL(SIOCGIWMODE) -COMPATIBLE_IOCTL(SIOCSIWSENS) -COMPATIBLE_IOCTL(SIOCGIWSENS) -COMPATIBLE_IOCTL(SIOCSIWRANGE) -COMPATIBLE_IOCTL(SIOCSIWPRIV) -COMPATIBLE_IOCTL(SIOCSIWSTATS) -COMPATIBLE_IOCTL(SIOCSIWAP) -COMPATIBLE_IOCTL(SIOCGIWAP) -COMPATIBLE_IOCTL(SIOCSIWRATE) -COMPATIBLE_IOCTL(SIOCGIWRATE) -COMPATIBLE_IOCTL(SIOCSIWRTS) -COMPATIBLE_IOCTL(SIOCGIWRTS) -COMPATIBLE_IOCTL(SIOCSIWFRAG) -COMPATIBLE_IOCTL(SIOCGIWFRAG) -COMPATIBLE_IOCTL(SIOCSIWTXPOW) -COMPATIBLE_IOCTL(SIOCGIWTXPOW) -COMPATIBLE_IOCTL(SIOCSIWRETRY) -COMPATIBLE_IOCTL(SIOCGIWRETRY) -COMPATIBLE_IOCTL(SIOCSIWPOWER) -COMPATIBLE_IOCTL(SIOCGIWPOWER) -COMPATIBLE_IOCTL(SIOCSIWAUTH) -COMPATIBLE_IOCTL(SIOCGIWAUTH) /* hiddev */ COMPATIBLE_IOCTL(HIDIOCGVERSION) COMPATIBLE_IOCTL(HIDIOCAPPLICATION) @@ -2761,29 +2673,7 @@ COMPATIBLE_IOCTL(USBDEVFS_IOCTL32) HANDLE_IOCTL(I2C_FUNCS, w_long) HANDLE_IOCTL(I2C_RDWR, do_i2c_rdwr_ioctl) HANDLE_IOCTL(I2C_SMBUS, do_i2c_smbus_ioctl) -/* wireless */ -HANDLE_IOCTL(SIOCGIWRANGE, do_wireless_ioctl) -HANDLE_IOCTL(SIOCGIWPRIV, do_wireless_ioctl) -HANDLE_IOCTL(SIOCGIWSTATS, do_wireless_ioctl) -HANDLE_IOCTL(SIOCSIWSPY, do_wireless_ioctl) -HANDLE_IOCTL(SIOCGIWSPY, do_wireless_ioctl) -HANDLE_IOCTL(SIOCSIWTHRSPY, do_wireless_ioctl) -HANDLE_IOCTL(SIOCGIWTHRSPY, do_wireless_ioctl) -HANDLE_IOCTL(SIOCSIWMLME, do_wireless_ioctl) -HANDLE_IOCTL(SIOCGIWAPLIST, do_wireless_ioctl) -HANDLE_IOCTL(SIOCSIWSCAN, do_wireless_ioctl) -HANDLE_IOCTL(SIOCGIWSCAN, do_wireless_ioctl) -HANDLE_IOCTL(SIOCSIWESSID, do_wireless_ioctl) -HANDLE_IOCTL(SIOCGIWESSID, do_wireless_ioctl) -HANDLE_IOCTL(SIOCSIWNICKN, do_wireless_ioctl) -HANDLE_IOCTL(SIOCGIWNICKN, do_wireless_ioctl) -HANDLE_IOCTL(SIOCSIWENCODE, do_wireless_ioctl) -HANDLE_IOCTL(SIOCGIWENCODE, do_wireless_ioctl) -HANDLE_IOCTL(SIOCSIWGENIE, do_wireless_ioctl) -HANDLE_IOCTL(SIOCGIWGENIE, do_wireless_ioctl) -HANDLE_IOCTL(SIOCSIWENCODEEXT, do_wireless_ioctl) -HANDLE_IOCTL(SIOCGIWENCODEEXT, do_wireless_ioctl) -HANDLE_IOCTL(SIOCSIWPMKSA, do_wireless_ioctl) +/* bridge */ HANDLE_IOCTL(SIOCSIFBR, old_bridge_ioctl) HANDLE_IOCTL(SIOCGIFBR, old_bridge_ioctl) /* Not implemented in the native kernel */ diff --git a/fs/configfs/dir.c b/fs/configfs/dir.c index 0e64312a084c..179589be063a 100644 --- a/fs/configfs/dir.c +++ b/fs/configfs/dir.c @@ -1027,9 +1027,10 @@ EXPORT_SYMBOL(configfs_undepend_item); static int configfs_mkdir(struct inode *dir, struct dentry *dentry, int mode) { - int ret, module_got = 0; - struct config_group *group; - struct config_item *item; + int ret = 0; + int module_got = 0; + struct config_group *group = NULL; + struct config_item *item = NULL; struct config_item *parent_item; struct configfs_subsystem *subsys; struct configfs_dirent *sd; @@ -1070,25 +1071,30 @@ static int configfs_mkdir(struct inode *dir, struct dentry *dentry, int mode) snprintf(name, dentry->d_name.len + 1, "%s", dentry->d_name.name); mutex_lock(&subsys->su_mutex); - group = NULL; - item = NULL; if (type->ct_group_ops->make_group) { - ret = type->ct_group_ops->make_group(to_config_group(parent_item), name, &group); - if (!ret) { + group = type->ct_group_ops->make_group(to_config_group(parent_item), name); + if (!group) + group = ERR_PTR(-ENOMEM); + if (!IS_ERR(group)) { link_group(to_config_group(parent_item), group); item = &group->cg_item; - } + } else + ret = PTR_ERR(group); } else { - ret = type->ct_group_ops->make_item(to_config_group(parent_item), name, &item); - if (!ret) + item = type->ct_group_ops->make_item(to_config_group(parent_item), name); + if (!item) + item = ERR_PTR(-ENOMEM); + if (!IS_ERR(item)) link_obj(parent_item, item); + else + ret = PTR_ERR(item); } mutex_unlock(&subsys->su_mutex); kfree(name); if (ret) { /* - * If ret != 0, then link_obj() was never called. + * If item == NULL, then link_obj() was never called. * There are no extra references to clean up. */ goto out_put; diff --git a/fs/dlm/config.c b/fs/dlm/config.c index 492d8caaaf25..c4e7d721bd8d 100644 --- a/fs/dlm/config.c +++ b/fs/dlm/config.c @@ -41,20 +41,16 @@ struct comm; struct nodes; struct node; -static int make_cluster(struct config_group *, const char *, - struct config_group **); +static struct config_group *make_cluster(struct config_group *, const char *); static void drop_cluster(struct config_group *, struct config_item *); static void release_cluster(struct config_item *); -static int make_space(struct config_group *, const char *, - struct config_group **); +static struct config_group *make_space(struct config_group *, const char *); static void drop_space(struct config_group *, struct config_item *); static void release_space(struct config_item *); -static int make_comm(struct config_group *, const char *, - struct config_item **); +static struct config_item *make_comm(struct config_group *, const char *); static void drop_comm(struct config_group *, struct config_item *); static void release_comm(struct config_item *); -static int make_node(struct config_group *, const char *, - struct config_item **); +static struct config_item *make_node(struct config_group *, const char *); static void drop_node(struct config_group *, struct config_item *); static void release_node(struct config_item *); @@ -396,8 +392,8 @@ static struct node *to_node(struct config_item *i) return i ? container_of(i, struct node, item) : NULL; } -static int make_cluster(struct config_group *g, const char *name, - struct config_group **new_g) +static struct config_group *make_cluster(struct config_group *g, + const char *name) { struct cluster *cl = NULL; struct spaces *sps = NULL; @@ -435,15 +431,14 @@ static int make_cluster(struct config_group *g, const char *name, space_list = &sps->ss_group; comm_list = &cms->cs_group; - *new_g = &cl->group; - return 0; + return &cl->group; fail: kfree(cl); kfree(gps); kfree(sps); kfree(cms); - return -ENOMEM; + return ERR_PTR(-ENOMEM); } static void drop_cluster(struct config_group *g, struct config_item *i) @@ -471,8 +466,7 @@ static void release_cluster(struct config_item *i) kfree(cl); } -static int make_space(struct config_group *g, const char *name, - struct config_group **new_g) +static struct config_group *make_space(struct config_group *g, const char *name) { struct space *sp = NULL; struct nodes *nds = NULL; @@ -495,14 +489,13 @@ static int make_space(struct config_group *g, const char *name, INIT_LIST_HEAD(&sp->members); mutex_init(&sp->members_lock); sp->members_count = 0; - *new_g = &sp->group; - return 0; + return &sp->group; fail: kfree(sp); kfree(gps); kfree(nds); - return -ENOMEM; + return ERR_PTR(-ENOMEM); } static void drop_space(struct config_group *g, struct config_item *i) @@ -529,21 +522,19 @@ static void release_space(struct config_item *i) kfree(sp); } -static int make_comm(struct config_group *g, const char *name, - struct config_item **new_i) +static struct config_item *make_comm(struct config_group *g, const char *name) { struct comm *cm; cm = kzalloc(sizeof(struct comm), GFP_KERNEL); if (!cm) - return -ENOMEM; + return ERR_PTR(-ENOMEM); config_item_init_type_name(&cm->item, name, &comm_type); cm->nodeid = -1; cm->local = 0; cm->addr_count = 0; - *new_i = &cm->item; - return 0; + return &cm->item; } static void drop_comm(struct config_group *g, struct config_item *i) @@ -563,15 +554,14 @@ static void release_comm(struct config_item *i) kfree(cm); } -static int make_node(struct config_group *g, const char *name, - struct config_item **new_i) +static struct config_item *make_node(struct config_group *g, const char *name) { struct space *sp = to_space(g->cg_item.ci_parent); struct node *nd; nd = kzalloc(sizeof(struct node), GFP_KERNEL); if (!nd) - return -ENOMEM; + return ERR_PTR(-ENOMEM); config_item_init_type_name(&nd->item, name, &node_type); nd->nodeid = -1; @@ -583,8 +573,7 @@ static int make_node(struct config_group *g, const char *name, sp->members_count++; mutex_unlock(&sp->members_lock); - *new_i = &nd->item; - return 0; + return &nd->item; } static void drop_node(struct config_group *g, struct config_item *i) diff --git a/fs/lockd/svc.c b/fs/lockd/svc.c index 2169af4d5455..5bd9bf0fa9df 100644 --- a/fs/lockd/svc.c +++ b/fs/lockd/svc.c @@ -50,7 +50,7 @@ EXPORT_SYMBOL(nlmsvc_ops); static DEFINE_MUTEX(nlmsvc_mutex); static unsigned int nlmsvc_users; static struct task_struct *nlmsvc_task; -static struct svc_serv *nlmsvc_serv; +static struct svc_rqst *nlmsvc_rqst; int nlmsvc_grace_period; unsigned long nlmsvc_timeout; @@ -194,20 +194,11 @@ lockd(void *vrqstp) svc_process(rqstp); } - flush_signals(current); if (nlmsvc_ops) nlmsvc_invalidate_all(); nlm_shutdown_hosts(); - unlock_kernel(); - - nlmsvc_task = NULL; - nlmsvc_serv = NULL; - - /* Exit the RPC thread */ - svc_exit_thread(rqstp); - return 0; } @@ -254,16 +245,15 @@ int lockd_up(int proto) /* Maybe add a 'family' option when IPv6 is supported ?? */ { struct svc_serv *serv; - struct svc_rqst *rqstp; int error = 0; mutex_lock(&nlmsvc_mutex); /* * Check whether we're already up and running. */ - if (nlmsvc_serv) { + if (nlmsvc_rqst) { if (proto) - error = make_socks(nlmsvc_serv, proto); + error = make_socks(nlmsvc_rqst->rq_server, proto); goto out; } @@ -288,9 +278,10 @@ lockd_up(int proto) /* Maybe add a 'family' option when IPv6 is supported ?? */ /* * Create the kernel thread and wait for it to start. */ - rqstp = svc_prepare_thread(serv, &serv->sv_pools[0]); - if (IS_ERR(rqstp)) { - error = PTR_ERR(rqstp); + nlmsvc_rqst = svc_prepare_thread(serv, &serv->sv_pools[0]); + if (IS_ERR(nlmsvc_rqst)) { + error = PTR_ERR(nlmsvc_rqst); + nlmsvc_rqst = NULL; printk(KERN_WARNING "lockd_up: svc_rqst allocation failed, error=%d\n", error); @@ -298,16 +289,15 @@ lockd_up(int proto) /* Maybe add a 'family' option when IPv6 is supported ?? */ } svc_sock_update_bufs(serv); - nlmsvc_serv = rqstp->rq_server; - nlmsvc_task = kthread_run(lockd, rqstp, serv->sv_name); + nlmsvc_task = kthread_run(lockd, nlmsvc_rqst, serv->sv_name); if (IS_ERR(nlmsvc_task)) { error = PTR_ERR(nlmsvc_task); + svc_exit_thread(nlmsvc_rqst); nlmsvc_task = NULL; - nlmsvc_serv = NULL; + nlmsvc_rqst = NULL; printk(KERN_WARNING "lockd_up: kthread_run failed, error=%d\n", error); - svc_exit_thread(rqstp); goto destroy_and_out; } @@ -346,6 +336,9 @@ lockd_down(void) BUG(); } kthread_stop(nlmsvc_task); + svc_exit_thread(nlmsvc_rqst); + nlmsvc_task = NULL; + nlmsvc_rqst = NULL; out: mutex_unlock(&nlmsvc_mutex); } diff --git a/fs/lockd/svc4proc.c b/fs/lockd/svc4proc.c index 2e27176ff42f..399444639337 100644 --- a/fs/lockd/svc4proc.c +++ b/fs/lockd/svc4proc.c @@ -58,8 +58,7 @@ nlm4svc_retrieve_args(struct svc_rqst *rqstp, struct nlm_args *argp, return 0; no_locks: - if (host) - nlm_release_host(host); + nlm_release_host(host); if (error) return error; return nlm_lck_denied_nolocks; @@ -100,7 +99,7 @@ nlm4svc_proc_test(struct svc_rqst *rqstp, struct nlm_args *argp, return resp->status == nlm_drop_reply ? rpc_drop_reply :rpc_success; /* Now check for conflicting locks */ - resp->status = nlmsvc_testlock(rqstp, file, &argp->lock, &resp->lock, &resp->cookie); + resp->status = nlmsvc_testlock(rqstp, file, host, &argp->lock, &resp->lock, &resp->cookie); if (resp->status == nlm_drop_reply) rc = rpc_drop_reply; else @@ -146,7 +145,7 @@ nlm4svc_proc_lock(struct svc_rqst *rqstp, struct nlm_args *argp, #endif /* Now try to lock the file */ - resp->status = nlmsvc_lock(rqstp, file, &argp->lock, + resp->status = nlmsvc_lock(rqstp, file, host, &argp->lock, argp->block, &argp->cookie); if (resp->status == nlm_drop_reply) rc = rpc_drop_reply; diff --git a/fs/lockd/svclock.c b/fs/lockd/svclock.c index 56a08ab9a4cb..821b9acdfb66 100644 --- a/fs/lockd/svclock.c +++ b/fs/lockd/svclock.c @@ -129,9 +129,9 @@ nlmsvc_lookup_block(struct nlm_file *file, struct nlm_lock *lock) static inline int nlm_cookie_match(struct nlm_cookie *a, struct nlm_cookie *b) { - if(a->len != b->len) + if (a->len != b->len) return 0; - if(memcmp(a->data,b->data,a->len)) + if (memcmp(a->data, b->data, a->len)) return 0; return 1; } @@ -180,6 +180,7 @@ nlmsvc_create_block(struct svc_rqst *rqstp, struct nlm_host *host, struct nlm_block *block; struct nlm_rqst *call = NULL; + nlm_get_host(host); call = nlm_alloc_call(host); if (call == NULL) return NULL; @@ -358,10 +359,10 @@ nlmsvc_defer_lock_rqst(struct svc_rqst *rqstp, struct nlm_block *block) */ __be32 nlmsvc_lock(struct svc_rqst *rqstp, struct nlm_file *file, - struct nlm_lock *lock, int wait, struct nlm_cookie *cookie) + struct nlm_host *host, struct nlm_lock *lock, int wait, + struct nlm_cookie *cookie) { struct nlm_block *block = NULL; - struct nlm_host *host; int error; __be32 ret; @@ -373,11 +374,6 @@ nlmsvc_lock(struct svc_rqst *rqstp, struct nlm_file *file, (long long)lock->fl.fl_end, wait); - /* Create host handle for callback */ - host = nlmsvc_lookup_host(rqstp, lock->caller, lock->len); - if (host == NULL) - return nlm_lck_denied_nolocks; - /* Lock file against concurrent access */ mutex_lock(&file->f_mutex); /* Get existing block (in case client is busy-waiting) @@ -385,8 +381,7 @@ nlmsvc_lock(struct svc_rqst *rqstp, struct nlm_file *file, */ block = nlmsvc_lookup_block(file, lock); if (block == NULL) { - block = nlmsvc_create_block(rqstp, nlm_get_host(host), file, - lock, cookie); + block = nlmsvc_create_block(rqstp, host, file, lock, cookie); ret = nlm_lck_denied_nolocks; if (block == NULL) goto out; @@ -417,7 +412,7 @@ nlmsvc_lock(struct svc_rqst *rqstp, struct nlm_file *file, lock->fl.fl_flags &= ~FL_SLEEP; dprintk("lockd: vfs_lock_file returned %d\n", error); - switch(error) { + switch (error) { case 0: ret = nlm_granted; goto out; @@ -450,7 +445,6 @@ nlmsvc_lock(struct svc_rqst *rqstp, struct nlm_file *file, out: mutex_unlock(&file->f_mutex); nlmsvc_release_block(block); - nlm_release_host(host); dprintk("lockd: nlmsvc_lock returned %u\n", ret); return ret; } @@ -460,8 +454,8 @@ out: */ __be32 nlmsvc_testlock(struct svc_rqst *rqstp, struct nlm_file *file, - struct nlm_lock *lock, struct nlm_lock *conflock, - struct nlm_cookie *cookie) + struct nlm_host *host, struct nlm_lock *lock, + struct nlm_lock *conflock, struct nlm_cookie *cookie) { struct nlm_block *block = NULL; int error; @@ -479,16 +473,9 @@ nlmsvc_testlock(struct svc_rqst *rqstp, struct nlm_file *file, if (block == NULL) { struct file_lock *conf = kzalloc(sizeof(*conf), GFP_KERNEL); - struct nlm_host *host; if (conf == NULL) return nlm_granted; - /* Create host handle for callback */ - host = nlmsvc_lookup_host(rqstp, lock->caller, lock->len); - if (host == NULL) { - kfree(conf); - return nlm_lck_denied_nolocks; - } block = nlmsvc_create_block(rqstp, host, file, lock, cookie); if (block == NULL) { kfree(conf); @@ -897,7 +884,7 @@ nlmsvc_retry_blocked(void) if (block->b_when == NLM_NEVER) break; - if (time_after(block->b_when,jiffies)) { + if (time_after(block->b_when, jiffies)) { timeout = block->b_when - jiffies; break; } diff --git a/fs/lockd/svcproc.c b/fs/lockd/svcproc.c index ce6952b50a75..76019d2ff72d 100644 --- a/fs/lockd/svcproc.c +++ b/fs/lockd/svcproc.c @@ -87,8 +87,7 @@ nlmsvc_retrieve_args(struct svc_rqst *rqstp, struct nlm_args *argp, return 0; no_locks: - if (host) - nlm_release_host(host); + nlm_release_host(host); if (error) return error; return nlm_lck_denied_nolocks; @@ -129,7 +128,7 @@ nlmsvc_proc_test(struct svc_rqst *rqstp, struct nlm_args *argp, return resp->status == nlm_drop_reply ? rpc_drop_reply :rpc_success; /* Now check for conflicting locks */ - resp->status = cast_status(nlmsvc_testlock(rqstp, file, &argp->lock, &resp->lock, &resp->cookie)); + resp->status = cast_status(nlmsvc_testlock(rqstp, file, host, &argp->lock, &resp->lock, &resp->cookie)); if (resp->status == nlm_drop_reply) rc = rpc_drop_reply; else @@ -176,7 +175,7 @@ nlmsvc_proc_lock(struct svc_rqst *rqstp, struct nlm_args *argp, #endif /* Now try to lock the file */ - resp->status = cast_status(nlmsvc_lock(rqstp, file, &argp->lock, + resp->status = cast_status(nlmsvc_lock(rqstp, file, host, &argp->lock, argp->block, &argp->cookie)); if (resp->status == nlm_drop_reply) rc = rpc_drop_reply; diff --git a/fs/lockd/svcsubs.c b/fs/lockd/svcsubs.c index d1c48b539df8..198b4e55b373 100644 --- a/fs/lockd/svcsubs.c +++ b/fs/lockd/svcsubs.c @@ -373,13 +373,16 @@ nlmsvc_free_host_resources(struct nlm_host *host) } } -/* - * Remove all locks held for clients +/** + * nlmsvc_invalidate_all - remove all locks held for clients + * + * Release all locks held by NFS clients. + * */ void nlmsvc_invalidate_all(void) { - /* Release all locks held by NFS clients. + /* * Previously, the code would call * nlmsvc_free_host_resources for each client in * turn, which is about as inefficient as it gets. @@ -396,6 +399,12 @@ nlmsvc_match_sb(void *datap, struct nlm_file *file) return sb == file->f_file->f_path.mnt->mnt_sb; } +/** + * nlmsvc_unlock_all_by_sb - release locks held on this file system + * @sb: super block + * + * Release all locks held by clients accessing this file system. + */ int nlmsvc_unlock_all_by_sb(struct super_block *sb) { @@ -409,17 +418,22 @@ EXPORT_SYMBOL_GPL(nlmsvc_unlock_all_by_sb); static int nlmsvc_match_ip(void *datap, struct nlm_host *host) { - __be32 *server_addr = datap; - - return host->h_saddr.sin_addr.s_addr == *server_addr; + return nlm_cmp_addr(&host->h_saddr, datap); } +/** + * nlmsvc_unlock_all_by_ip - release local locks by IP address + * @server_addr: server's IP address as seen by clients + * + * Release all locks held by clients accessing this host + * via the passed in IP address. + */ int -nlmsvc_unlock_all_by_ip(__be32 server_addr) +nlmsvc_unlock_all_by_ip(struct sockaddr *server_addr) { int ret; - ret = nlm_traverse_files(&server_addr, nlmsvc_match_ip, NULL); - return ret ? -EIO : 0; + ret = nlm_traverse_files(server_addr, nlmsvc_match_ip, NULL); + return ret ? -EIO : 0; } EXPORT_SYMBOL_GPL(nlmsvc_unlock_all_by_ip); diff --git a/fs/nfsd/lockd.c b/fs/nfsd/lockd.c index 9e4a568a5013..6b6225ac4926 100644 --- a/fs/nfsd/lockd.c +++ b/fs/nfsd/lockd.c @@ -35,7 +35,7 @@ nlm_fopen(struct svc_rqst *rqstp, struct nfs_fh *f, struct file **filp) fh.fh_export = NULL; exp_readlock(); - nfserr = nfsd_open(rqstp, &fh, S_IFREG, MAY_LOCK, filp); + nfserr = nfsd_open(rqstp, &fh, S_IFREG, NFSD_MAY_LOCK, filp); fh_put(&fh); rqstp->rq_client = NULL; exp_readunlock(); diff --git a/fs/nfsd/nfs2acl.c b/fs/nfsd/nfs2acl.c index 1c3b7654e966..4e3219e84116 100644 --- a/fs/nfsd/nfs2acl.c +++ b/fs/nfsd/nfs2acl.c @@ -40,7 +40,8 @@ static __be32 nfsacld_proc_getacl(struct svc_rqst * rqstp, dprintk("nfsd: GETACL(2acl) %s\n", SVCFH_fmt(&argp->fh)); fh = fh_copy(&resp->fh, &argp->fh); - if ((nfserr = fh_verify(rqstp, &resp->fh, 0, MAY_NOP))) + nfserr = fh_verify(rqstp, &resp->fh, 0, NFSD_MAY_NOP); + if (nfserr) RETURN_STATUS(nfserr); if (argp->mask & ~(NFS_ACL|NFS_ACLCNT|NFS_DFACL|NFS_DFACLCNT)) @@ -107,7 +108,7 @@ static __be32 nfsacld_proc_setacl(struct svc_rqst * rqstp, dprintk("nfsd: SETACL(2acl) %s\n", SVCFH_fmt(&argp->fh)); fh = fh_copy(&resp->fh, &argp->fh); - nfserr = fh_verify(rqstp, &resp->fh, 0, MAY_SATTR); + nfserr = fh_verify(rqstp, &resp->fh, 0, NFSD_MAY_SATTR); if (!nfserr) { nfserr = nfserrno( nfsd_set_posix_acl( @@ -134,7 +135,7 @@ static __be32 nfsacld_proc_getattr(struct svc_rqst * rqstp, dprintk("nfsd: GETATTR %s\n", SVCFH_fmt(&argp->fh)); fh_copy(&resp->fh, &argp->fh); - return fh_verify(rqstp, &resp->fh, 0, MAY_NOP); + return fh_verify(rqstp, &resp->fh, 0, NFSD_MAY_NOP); } /* diff --git a/fs/nfsd/nfs3acl.c b/fs/nfsd/nfs3acl.c index b647f2f872dc..9981dbb377a3 100644 --- a/fs/nfsd/nfs3acl.c +++ b/fs/nfsd/nfs3acl.c @@ -36,7 +36,8 @@ static __be32 nfsd3_proc_getacl(struct svc_rqst * rqstp, __be32 nfserr = 0; fh = fh_copy(&resp->fh, &argp->fh); - if ((nfserr = fh_verify(rqstp, &resp->fh, 0, MAY_NOP))) + nfserr = fh_verify(rqstp, &resp->fh, 0, NFSD_MAY_NOP); + if (nfserr) RETURN_STATUS(nfserr); if (argp->mask & ~(NFS_ACL|NFS_ACLCNT|NFS_DFACL|NFS_DFACLCNT)) @@ -101,7 +102,7 @@ static __be32 nfsd3_proc_setacl(struct svc_rqst * rqstp, __be32 nfserr = 0; fh = fh_copy(&resp->fh, &argp->fh); - nfserr = fh_verify(rqstp, &resp->fh, 0, MAY_SATTR); + nfserr = fh_verify(rqstp, &resp->fh, 0, NFSD_MAY_SATTR); if (!nfserr) { nfserr = nfserrno( nfsd_set_posix_acl( diff --git a/fs/nfsd/nfs3proc.c b/fs/nfsd/nfs3proc.c index c721a1e6e9dd..4d617ea28cfc 100644 --- a/fs/nfsd/nfs3proc.c +++ b/fs/nfsd/nfs3proc.c @@ -63,7 +63,7 @@ nfsd3_proc_getattr(struct svc_rqst *rqstp, struct nfsd_fhandle *argp, SVCFH_fmt(&argp->fh)); fh_copy(&resp->fh, &argp->fh); - nfserr = fh_verify(rqstp, &resp->fh, 0, MAY_NOP); + nfserr = fh_verify(rqstp, &resp->fh, 0, NFSD_MAY_NOP); if (nfserr) RETURN_STATUS(nfserr); @@ -242,7 +242,7 @@ nfsd3_proc_create(struct svc_rqst *rqstp, struct nfsd3_createargs *argp, attr = &argp->attrs; /* Get the directory inode */ - nfserr = fh_verify(rqstp, dirfhp, S_IFDIR, MAY_CREATE); + nfserr = fh_verify(rqstp, dirfhp, S_IFDIR, NFSD_MAY_CREATE); if (nfserr) RETURN_STATUS(nfserr); @@ -558,7 +558,7 @@ nfsd3_proc_fsinfo(struct svc_rqst * rqstp, struct nfsd_fhandle *argp, resp->f_maxfilesize = ~(u32) 0; resp->f_properties = NFS3_FSF_DEFAULT; - nfserr = fh_verify(rqstp, &argp->fh, 0, MAY_NOP); + nfserr = fh_verify(rqstp, &argp->fh, 0, NFSD_MAY_NOP); /* Check special features of the file system. May request * different read/write sizes for file systems known to have @@ -597,7 +597,7 @@ nfsd3_proc_pathconf(struct svc_rqst * rqstp, struct nfsd_fhandle *argp, resp->p_case_insensitive = 0; resp->p_case_preserving = 1; - nfserr = fh_verify(rqstp, &argp->fh, 0, MAY_NOP); + nfserr = fh_verify(rqstp, &argp->fh, 0, NFSD_MAY_NOP); if (nfserr == 0) { struct super_block *sb = argp->fh.fh_dentry->d_inode->i_sb; diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c index c309c881bd4e..eef1629806f5 100644 --- a/fs/nfsd/nfs4proc.c +++ b/fs/nfsd/nfs4proc.c @@ -71,11 +71,11 @@ do_open_permission(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfs return nfserr_inval; if (open->op_share_access & NFS4_SHARE_ACCESS_READ) - accmode |= MAY_READ; + accmode |= NFSD_MAY_READ; if (open->op_share_access & NFS4_SHARE_ACCESS_WRITE) - accmode |= (MAY_WRITE | MAY_TRUNC); + accmode |= (NFSD_MAY_WRITE | NFSD_MAY_TRUNC); if (open->op_share_deny & NFS4_SHARE_DENY_WRITE) - accmode |= MAY_WRITE; + accmode |= NFSD_MAY_WRITE; status = fh_verify(rqstp, current_fh, S_IFREG, accmode); @@ -126,7 +126,8 @@ do_open_lookup(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_o &resfh.fh_handle.fh_base, resfh.fh_handle.fh_size); if (!created) - status = do_open_permission(rqstp, current_fh, open, MAY_NOP); + status = do_open_permission(rqstp, current_fh, open, + NFSD_MAY_NOP); out: fh_put(&resfh); @@ -157,7 +158,8 @@ do_open_fhandle(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_ open->op_truncate = (open->op_iattr.ia_valid & ATTR_SIZE) && (open->op_iattr.ia_size == 0); - status = do_open_permission(rqstp, current_fh, open, MAY_OWNER_OVERRIDE); + status = do_open_permission(rqstp, current_fh, open, + NFSD_MAY_OWNER_OVERRIDE); return status; } @@ -186,7 +188,7 @@ nfsd4_open(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, cstate->current_fh.fh_handle.fh_size = rp->rp_openfh_len; memcpy(&cstate->current_fh.fh_handle.fh_base, rp->rp_openfh, rp->rp_openfh_len); - status = fh_verify(rqstp, &cstate->current_fh, 0, MAY_NOP); + status = fh_verify(rqstp, &cstate->current_fh, 0, NFSD_MAY_NOP); if (status) dprintk("nfsd4_open: replay failed" " restoring previous filehandle\n"); @@ -285,7 +287,7 @@ nfsd4_putfh(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, cstate->current_fh.fh_handle.fh_size = putfh->pf_fhlen; memcpy(&cstate->current_fh.fh_handle.fh_base, putfh->pf_fhval, putfh->pf_fhlen); - return fh_verify(rqstp, &cstate->current_fh, 0, MAY_NOP); + return fh_verify(rqstp, &cstate->current_fh, 0, NFSD_MAY_NOP); } static __be32 @@ -363,7 +365,8 @@ nfsd4_create(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, fh_init(&resfh, NFS4_FHSIZE); - status = fh_verify(rqstp, &cstate->current_fh, S_IFDIR, MAY_CREATE); + status = fh_verify(rqstp, &cstate->current_fh, S_IFDIR, + NFSD_MAY_CREATE); if (status == nfserr_symlink) status = nfserr_notdir; if (status) @@ -445,7 +448,7 @@ nfsd4_getattr(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, { __be32 status; - status = fh_verify(rqstp, &cstate->current_fh, 0, MAY_NOP); + status = fh_verify(rqstp, &cstate->current_fh, 0, NFSD_MAY_NOP); if (status) return status; @@ -730,7 +733,7 @@ _nfsd4_verify(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, int count; __be32 status; - status = fh_verify(rqstp, &cstate->current_fh, 0, MAY_NOP); + status = fh_verify(rqstp, &cstate->current_fh, 0, NFSD_MAY_NOP); if (status) return status; @@ -843,10 +846,13 @@ struct nfsd4_operation { #define ALLOWED_WITHOUT_FH 1 /* GETATTR and ops not listed as returning NFS4ERR_MOVED: */ #define ALLOWED_ON_ABSENT_FS 2 + char *op_name; }; static struct nfsd4_operation nfsd4_ops[]; +static inline char *nfsd4_op_name(unsigned opnum); + /* * COMPOUND call. */ @@ -888,7 +894,9 @@ nfsd4_proc_compound(struct svc_rqst *rqstp, while (!status && resp->opcnt < args->opcnt) { op = &args->ops[resp->opcnt++]; - dprintk("nfsv4 compound op #%d: %d\n", resp->opcnt, op->opnum); + dprintk("nfsv4 compound op #%d/%d: %d (%s)\n", + resp->opcnt, args->opcnt, op->opnum, + nfsd4_op_name(op->opnum)); /* * The XDR decode routines may have pre-set op->status; @@ -952,126 +960,170 @@ encode_op: out: nfsd4_release_compoundargs(args); cstate_free(cstate); + dprintk("nfsv4 compound returned %d\n", ntohl(status)); return status; } static struct nfsd4_operation nfsd4_ops[OP_RELEASE_LOCKOWNER+1] = { [OP_ACCESS] = { .op_func = (nfsd4op_func)nfsd4_access, + .op_name = "OP_ACCESS", }, [OP_CLOSE] = { .op_func = (nfsd4op_func)nfsd4_close, + .op_name = "OP_CLOSE", }, [OP_COMMIT] = { .op_func = (nfsd4op_func)nfsd4_commit, + .op_name = "OP_COMMIT", }, [OP_CREATE] = { .op_func = (nfsd4op_func)nfsd4_create, + .op_name = "OP_CREATE", }, [OP_DELEGRETURN] = { .op_func = (nfsd4op_func)nfsd4_delegreturn, + .op_name = "OP_DELEGRETURN", }, [OP_GETATTR] = { .op_func = (nfsd4op_func)nfsd4_getattr, .op_flags = ALLOWED_ON_ABSENT_FS, + .op_name = "OP_GETATTR", }, [OP_GETFH] = { .op_func = (nfsd4op_func)nfsd4_getfh, + .op_name = "OP_GETFH", }, [OP_LINK] = { .op_func = (nfsd4op_func)nfsd4_link, + .op_name = "OP_LINK", }, [OP_LOCK] = { .op_func = (nfsd4op_func)nfsd4_lock, + .op_name = "OP_LOCK", }, [OP_LOCKT] = { .op_func = (nfsd4op_func)nfsd4_lockt, + .op_name = "OP_LOCKT", }, [OP_LOCKU] = { .op_func = (nfsd4op_func)nfsd4_locku, + .op_name = "OP_LOCKU", }, [OP_LOOKUP] = { .op_func = (nfsd4op_func)nfsd4_lookup, + .op_name = "OP_LOOKUP", }, [OP_LOOKUPP] = { .op_func = (nfsd4op_func)nfsd4_lookupp, + .op_name = "OP_LOOKUPP", }, [OP_NVERIFY] = { .op_func = (nfsd4op_func)nfsd4_nverify, + .op_name = "OP_NVERIFY", }, [OP_OPEN] = { .op_func = (nfsd4op_func)nfsd4_open, + .op_name = "OP_OPEN", }, [OP_OPEN_CONFIRM] = { .op_func = (nfsd4op_func)nfsd4_open_confirm, + .op_name = "OP_OPEN_CONFIRM", }, [OP_OPEN_DOWNGRADE] = { .op_func = (nfsd4op_func)nfsd4_open_downgrade, + .op_name = "OP_OPEN_DOWNGRADE", }, [OP_PUTFH] = { .op_func = (nfsd4op_func)nfsd4_putfh, .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS, + .op_name = "OP_PUTFH", }, [OP_PUTPUBFH] = { - /* unsupported; just for future reference: */ + /* unsupported, just for future reference: */ .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS, + .op_name = "OP_PUTPUBFH", }, [OP_PUTROOTFH] = { .op_func = (nfsd4op_func)nfsd4_putrootfh, .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS, + .op_name = "OP_PUTROOTFH", }, [OP_READ] = { .op_func = (nfsd4op_func)nfsd4_read, + .op_name = "OP_READ", }, [OP_READDIR] = { .op_func = (nfsd4op_func)nfsd4_readdir, + .op_name = "OP_READDIR", }, [OP_READLINK] = { .op_func = (nfsd4op_func)nfsd4_readlink, + .op_name = "OP_READLINK", }, [OP_REMOVE] = { .op_func = (nfsd4op_func)nfsd4_remove, + .op_name = "OP_REMOVE", }, [OP_RENAME] = { + .op_name = "OP_RENAME", .op_func = (nfsd4op_func)nfsd4_rename, }, [OP_RENEW] = { .op_func = (nfsd4op_func)nfsd4_renew, .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS, + .op_name = "OP_RENEW", }, [OP_RESTOREFH] = { .op_func = (nfsd4op_func)nfsd4_restorefh, .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS, + .op_name = "OP_RESTOREFH", }, [OP_SAVEFH] = { .op_func = (nfsd4op_func)nfsd4_savefh, + .op_name = "OP_SAVEFH", }, [OP_SECINFO] = { .op_func = (nfsd4op_func)nfsd4_secinfo, + .op_name = "OP_SECINFO", }, [OP_SETATTR] = { .op_func = (nfsd4op_func)nfsd4_setattr, + .op_name = "OP_SETATTR", }, [OP_SETCLIENTID] = { .op_func = (nfsd4op_func)nfsd4_setclientid, .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS, + .op_name = "OP_SETCLIENTID", }, [OP_SETCLIENTID_CONFIRM] = { .op_func = (nfsd4op_func)nfsd4_setclientid_confirm, .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS, + .op_name = "OP_SETCLIENTID_CONFIRM", }, [OP_VERIFY] = { .op_func = (nfsd4op_func)nfsd4_verify, + .op_name = "OP_VERIFY", }, [OP_WRITE] = { .op_func = (nfsd4op_func)nfsd4_write, + .op_name = "OP_WRITE", }, [OP_RELEASE_LOCKOWNER] = { .op_func = (nfsd4op_func)nfsd4_release_lockowner, .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS, + .op_name = "OP_RELEASE_LOCKOWNER", }, }; +static inline char * +nfsd4_op_name(unsigned opnum) +{ + if (opnum < ARRAY_SIZE(nfsd4_ops)) + return nfsd4_ops[opnum].op_name; + return "unknown_operation"; +} + #define nfs4svc_decode_voidargs NULL #define nfs4svc_release_void NULL #define nfsd4_voidres nfsd4_voidargs diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 8799b8708188..1578d7a2667e 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -1173,6 +1173,24 @@ static inline int deny_valid(u32 x) return x <= NFS4_SHARE_DENY_BOTH; } +/* + * We store the NONE, READ, WRITE, and BOTH bits separately in the + * st_{access,deny}_bmap field of the stateid, in order to track not + * only what share bits are currently in force, but also what + * combinations of share bits previous opens have used. This allows us + * to enforce the recommendation of rfc 3530 14.2.19 that the server + * return an error if the client attempt to downgrade to a combination + * of share bits not explicable by closing some of its previous opens. + * + * XXX: This enforcement is actually incomplete, since we don't keep + * track of access/deny bit combinations; so, e.g., we allow: + * + * OPEN allow read, deny write + * OPEN allow both, deny none + * DOWNGRADE allow read, deny none + * + * which we should reject. + */ static void set_access(unsigned int *access, unsigned long bmap) { int i; @@ -1570,6 +1588,10 @@ nfs4_upgrade_open(struct svc_rqst *rqstp, struct svc_fh *cur_fh, struct nfs4_sta int err = get_write_access(inode); if (err) return nfserrno(err); + err = mnt_want_write(cur_fh->fh_export->ex_path.mnt); + if (err) + return nfserrno(err); + file_take_write(filp); } status = nfsd4_truncate(rqstp, cur_fh, open); if (status) { @@ -1579,8 +1601,8 @@ nfs4_upgrade_open(struct svc_rqst *rqstp, struct svc_fh *cur_fh, struct nfs4_sta } /* remember the open */ filp->f_mode |= open->op_share_access; - set_bit(open->op_share_access, &stp->st_access_bmap); - set_bit(open->op_share_deny, &stp->st_deny_bmap); + __set_bit(open->op_share_access, &stp->st_access_bmap); + __set_bit(open->op_share_deny, &stp->st_deny_bmap); return nfs_ok; } @@ -1722,9 +1744,9 @@ nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nf /* Stateid was not found, this is a new OPEN */ int flags = 0; if (open->op_share_access & NFS4_SHARE_ACCESS_READ) - flags |= MAY_READ; + flags |= NFSD_MAY_READ; if (open->op_share_access & NFS4_SHARE_ACCESS_WRITE) - flags |= MAY_WRITE; + flags |= NFSD_MAY_WRITE; status = nfs4_new_open(rqstp, &stp, dp, current_fh, flags); if (status) goto out; @@ -2610,7 +2632,7 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, return nfserr_inval; if ((status = fh_verify(rqstp, &cstate->current_fh, - S_IFREG, MAY_LOCK))) { + S_IFREG, NFSD_MAY_LOCK))) { dprintk("NFSD: nfsd4_lock: permission denied!\n"); return status; } @@ -3249,12 +3271,14 @@ nfs4_state_shutdown(void) nfs4_unlock_state(); } +/* + * user_recovery_dirname is protected by the nfsd_mutex since it's only + * accessed when nfsd is starting. + */ static void nfs4_set_recdir(char *recdir) { - nfs4_lock_state(); strcpy(user_recovery_dirname, recdir); - nfs4_unlock_state(); } /* @@ -3278,6 +3302,12 @@ nfs4_reset_recoverydir(char *recdir) return status; } +char * +nfs4_recoverydir(void) +{ + return user_recovery_dirname; +} + /* * Called when leasetime is changed. * @@ -3286,11 +3316,12 @@ nfs4_reset_recoverydir(char *recdir) * we start to register any changes in lease time. If the administrator * really wants to change the lease time *now*, they can go ahead and bring * nfsd down and then back up again after changing the lease time. + * + * user_lease_time is protected by nfsd_mutex since it's only really accessed + * when nfsd is starting */ void nfs4_reset_lease(time_t leasetime) { - lock_kernel(); user_lease_time = leasetime; - unlock_kernel(); } diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index c513bbdf2d36..14ba4d9b2859 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -986,10 +986,74 @@ nfsd4_decode_release_lockowner(struct nfsd4_compoundargs *argp, struct nfsd4_rel } static __be32 +nfsd4_decode_noop(struct nfsd4_compoundargs *argp, void *p) +{ + return nfs_ok; +} + +static __be32 +nfsd4_decode_notsupp(struct nfsd4_compoundargs *argp, void *p) +{ + return nfserr_opnotsupp; +} + +typedef __be32(*nfsd4_dec)(struct nfsd4_compoundargs *argp, void *); + +static nfsd4_dec nfsd4_dec_ops[] = { + [OP_ACCESS] = (nfsd4_dec)nfsd4_decode_access, + [OP_CLOSE] = (nfsd4_dec)nfsd4_decode_close, + [OP_COMMIT] = (nfsd4_dec)nfsd4_decode_commit, + [OP_CREATE] = (nfsd4_dec)nfsd4_decode_create, + [OP_DELEGPURGE] = (nfsd4_dec)nfsd4_decode_notsupp, + [OP_DELEGRETURN] = (nfsd4_dec)nfsd4_decode_delegreturn, + [OP_GETATTR] = (nfsd4_dec)nfsd4_decode_getattr, + [OP_GETFH] = (nfsd4_dec)nfsd4_decode_noop, + [OP_LINK] = (nfsd4_dec)nfsd4_decode_link, + [OP_LOCK] = (nfsd4_dec)nfsd4_decode_lock, + [OP_LOCKT] = (nfsd4_dec)nfsd4_decode_lockt, + [OP_LOCKU] = (nfsd4_dec)nfsd4_decode_locku, + [OP_LOOKUP] = (nfsd4_dec)nfsd4_decode_lookup, + [OP_LOOKUPP] = (nfsd4_dec)nfsd4_decode_noop, + [OP_NVERIFY] = (nfsd4_dec)nfsd4_decode_verify, + [OP_OPEN] = (nfsd4_dec)nfsd4_decode_open, + [OP_OPENATTR] = (nfsd4_dec)nfsd4_decode_notsupp, + [OP_OPEN_CONFIRM] = (nfsd4_dec)nfsd4_decode_open_confirm, + [OP_OPEN_DOWNGRADE] = (nfsd4_dec)nfsd4_decode_open_downgrade, + [OP_PUTFH] = (nfsd4_dec)nfsd4_decode_putfh, + [OP_PUTPUBFH] = (nfsd4_dec)nfsd4_decode_notsupp, + [OP_PUTROOTFH] = (nfsd4_dec)nfsd4_decode_noop, + [OP_READ] = (nfsd4_dec)nfsd4_decode_read, + [OP_READDIR] = (nfsd4_dec)nfsd4_decode_readdir, + [OP_READLINK] = (nfsd4_dec)nfsd4_decode_noop, + [OP_REMOVE] = (nfsd4_dec)nfsd4_decode_remove, + [OP_RENAME] = (nfsd4_dec)nfsd4_decode_rename, + [OP_RENEW] = (nfsd4_dec)nfsd4_decode_renew, + [OP_RESTOREFH] = (nfsd4_dec)nfsd4_decode_noop, + [OP_SAVEFH] = (nfsd4_dec)nfsd4_decode_noop, + [OP_SECINFO] = (nfsd4_dec)nfsd4_decode_secinfo, + [OP_SETATTR] = (nfsd4_dec)nfsd4_decode_setattr, + [OP_SETCLIENTID] = (nfsd4_dec)nfsd4_decode_setclientid, + [OP_SETCLIENTID_CONFIRM] = (nfsd4_dec)nfsd4_decode_setclientid_confirm, + [OP_VERIFY] = (nfsd4_dec)nfsd4_decode_verify, + [OP_WRITE] = (nfsd4_dec)nfsd4_decode_write, + [OP_RELEASE_LOCKOWNER] = (nfsd4_dec)nfsd4_decode_release_lockowner, +}; + +struct nfsd4_minorversion_ops { + nfsd4_dec *decoders; + int nops; +}; + +static struct nfsd4_minorversion_ops nfsd4_minorversion[] = { + [0] = { nfsd4_dec_ops, ARRAY_SIZE(nfsd4_dec_ops) }, +}; + +static __be32 nfsd4_decode_compound(struct nfsd4_compoundargs *argp) { DECODE_HEAD; struct nfsd4_op *op; + struct nfsd4_minorversion_ops *ops; int i; /* @@ -1019,6 +1083,10 @@ nfsd4_decode_compound(struct nfsd4_compoundargs *argp) } } + if (argp->minorversion >= ARRAY_SIZE(nfsd4_minorversion)) + argp->opcnt = 0; + + ops = &nfsd4_minorversion[argp->minorversion]; for (i = 0; i < argp->opcnt; i++) { op = &argp->ops[i]; op->replay = NULL; @@ -1056,120 +1124,11 @@ nfsd4_decode_compound(struct nfsd4_compoundargs *argp) } op->opnum = ntohl(*argp->p++); - switch (op->opnum) { - case 2: /* Reserved operation */ - op->opnum = OP_ILLEGAL; - if (argp->minorversion == 0) - op->status = nfserr_op_illegal; - else - op->status = nfserr_minor_vers_mismatch; - break; - case OP_ACCESS: - op->status = nfsd4_decode_access(argp, &op->u.access); - break; - case OP_CLOSE: - op->status = nfsd4_decode_close(argp, &op->u.close); - break; - case OP_COMMIT: - op->status = nfsd4_decode_commit(argp, &op->u.commit); - break; - case OP_CREATE: - op->status = nfsd4_decode_create(argp, &op->u.create); - break; - case OP_DELEGRETURN: - op->status = nfsd4_decode_delegreturn(argp, &op->u.delegreturn); - break; - case OP_GETATTR: - op->status = nfsd4_decode_getattr(argp, &op->u.getattr); - break; - case OP_GETFH: - op->status = nfs_ok; - break; - case OP_LINK: - op->status = nfsd4_decode_link(argp, &op->u.link); - break; - case OP_LOCK: - op->status = nfsd4_decode_lock(argp, &op->u.lock); - break; - case OP_LOCKT: - op->status = nfsd4_decode_lockt(argp, &op->u.lockt); - break; - case OP_LOCKU: - op->status = nfsd4_decode_locku(argp, &op->u.locku); - break; - case OP_LOOKUP: - op->status = nfsd4_decode_lookup(argp, &op->u.lookup); - break; - case OP_LOOKUPP: - op->status = nfs_ok; - break; - case OP_NVERIFY: - op->status = nfsd4_decode_verify(argp, &op->u.nverify); - break; - case OP_OPEN: - op->status = nfsd4_decode_open(argp, &op->u.open); - break; - case OP_OPEN_CONFIRM: - op->status = nfsd4_decode_open_confirm(argp, &op->u.open_confirm); - break; - case OP_OPEN_DOWNGRADE: - op->status = nfsd4_decode_open_downgrade(argp, &op->u.open_downgrade); - break; - case OP_PUTFH: - op->status = nfsd4_decode_putfh(argp, &op->u.putfh); - break; - case OP_PUTROOTFH: - op->status = nfs_ok; - break; - case OP_READ: - op->status = nfsd4_decode_read(argp, &op->u.read); - break; - case OP_READDIR: - op->status = nfsd4_decode_readdir(argp, &op->u.readdir); - break; - case OP_READLINK: - op->status = nfs_ok; - break; - case OP_REMOVE: - op->status = nfsd4_decode_remove(argp, &op->u.remove); - break; - case OP_RENAME: - op->status = nfsd4_decode_rename(argp, &op->u.rename); - break; - case OP_RESTOREFH: - op->status = nfs_ok; - break; - case OP_RENEW: - op->status = nfsd4_decode_renew(argp, &op->u.renew); - break; - case OP_SAVEFH: - op->status = nfs_ok; - break; - case OP_SECINFO: - op->status = nfsd4_decode_secinfo(argp, &op->u.secinfo); - break; - case OP_SETATTR: - op->status = nfsd4_decode_setattr(argp, &op->u.setattr); - break; - case OP_SETCLIENTID: - op->status = nfsd4_decode_setclientid(argp, &op->u.setclientid); - break; - case OP_SETCLIENTID_CONFIRM: - op->status = nfsd4_decode_setclientid_confirm(argp, &op->u.setclientid_confirm); - break; - case OP_VERIFY: - op->status = nfsd4_decode_verify(argp, &op->u.verify); - break; - case OP_WRITE: - op->status = nfsd4_decode_write(argp, &op->u.write); - break; - case OP_RELEASE_LOCKOWNER: - op->status = nfsd4_decode_release_lockowner(argp, &op->u.release_lockowner); - break; - default: + if (op->opnum >= OP_ACCESS && op->opnum < ops->nops) + op->status = ops->decoders[op->opnum](argp, &op->u); + else { op->opnum = OP_ILLEGAL; op->status = nfserr_op_illegal; - break; } if (op->status) { @@ -1201,11 +1160,11 @@ nfsd4_decode_compound(struct nfsd4_compoundargs *argp) *p++ = htonl((u32)((n) >> 32)); \ *p++ = htonl((u32)(n)); \ } while (0) -#define WRITEMEM(ptr,nbytes) do { \ +#define WRITEMEM(ptr,nbytes) do { if (nbytes > 0) { \ *(p + XDR_QUADLEN(nbytes) -1) = 0; \ memcpy(p, ptr, nbytes); \ p += XDR_QUADLEN(nbytes); \ -} while (0) +}} while (0) #define WRITECINFO(c) do { \ *p++ = htonl(c.atomic); \ *p++ = htonl(c.before_ctime_sec); \ @@ -1991,7 +1950,7 @@ fail: return -EINVAL; } -static void +static __be32 nfsd4_encode_access(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_access *access) { ENCODE_HEAD; @@ -2002,9 +1961,10 @@ nfsd4_encode_access(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_ WRITE32(access->ac_resp_access); ADJUST_ARGS(); } + return nfserr; } -static void +static __be32 nfsd4_encode_close(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_close *close) { ENCODE_SEQID_OP_HEAD; @@ -2016,10 +1976,11 @@ nfsd4_encode_close(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_c ADJUST_ARGS(); } ENCODE_SEQID_OP_TAIL(close->cl_stateowner); + return nfserr; } -static void +static __be32 nfsd4_encode_commit(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_commit *commit) { ENCODE_HEAD; @@ -2029,9 +1990,10 @@ nfsd4_encode_commit(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_ WRITEMEM(commit->co_verf.data, 8); ADJUST_ARGS(); } + return nfserr; } -static void +static __be32 nfsd4_encode_create(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_create *create) { ENCODE_HEAD; @@ -2044,6 +2006,7 @@ nfsd4_encode_create(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_ WRITE32(create->cr_bmval[1]); ADJUST_ARGS(); } + return nfserr; } static __be32 @@ -2064,9 +2027,10 @@ nfsd4_encode_getattr(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4 return nfserr; } -static void -nfsd4_encode_getfh(struct nfsd4_compoundres *resp, __be32 nfserr, struct svc_fh *fhp) +static __be32 +nfsd4_encode_getfh(struct nfsd4_compoundres *resp, __be32 nfserr, struct svc_fh **fhpp) { + struct svc_fh *fhp = *fhpp; unsigned int len; ENCODE_HEAD; @@ -2077,6 +2041,7 @@ nfsd4_encode_getfh(struct nfsd4_compoundres *resp, __be32 nfserr, struct svc_fh WRITEMEM(&fhp->fh_handle.fh_base, len); ADJUST_ARGS(); } + return nfserr; } /* @@ -2104,7 +2069,7 @@ nfsd4_encode_lock_denied(struct nfsd4_compoundres *resp, struct nfsd4_lock_denie ADJUST_ARGS(); } -static void +static __be32 nfsd4_encode_lock(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_lock *lock) { ENCODE_SEQID_OP_HEAD; @@ -2118,16 +2083,18 @@ nfsd4_encode_lock(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_lo nfsd4_encode_lock_denied(resp, &lock->lk_denied); ENCODE_SEQID_OP_TAIL(lock->lk_replay_owner); + return nfserr; } -static void +static __be32 nfsd4_encode_lockt(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_lockt *lockt) { if (nfserr == nfserr_denied) nfsd4_encode_lock_denied(resp, &lockt->lt_denied); + return nfserr; } -static void +static __be32 nfsd4_encode_locku(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_locku *locku) { ENCODE_SEQID_OP_HEAD; @@ -2140,10 +2107,11 @@ nfsd4_encode_locku(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_l } ENCODE_SEQID_OP_TAIL(locku->lu_stateowner); + return nfserr; } -static void +static __be32 nfsd4_encode_link(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_link *link) { ENCODE_HEAD; @@ -2153,10 +2121,11 @@ nfsd4_encode_link(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_li WRITECINFO(link->li_cinfo); ADJUST_ARGS(); } + return nfserr; } -static void +static __be32 nfsd4_encode_open(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_open *open) { ENCODE_SEQID_OP_HEAD; @@ -2219,9 +2188,10 @@ nfsd4_encode_open(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_op /* XXX save filehandle here */ out: ENCODE_SEQID_OP_TAIL(open->op_stateowner); + return nfserr; } -static void +static __be32 nfsd4_encode_open_confirm(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_open_confirm *oc) { ENCODE_SEQID_OP_HEAD; @@ -2234,9 +2204,10 @@ nfsd4_encode_open_confirm(struct nfsd4_compoundres *resp, __be32 nfserr, struct } ENCODE_SEQID_OP_TAIL(oc->oc_stateowner); + return nfserr; } -static void +static __be32 nfsd4_encode_open_downgrade(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_open_downgrade *od) { ENCODE_SEQID_OP_HEAD; @@ -2249,6 +2220,7 @@ nfsd4_encode_open_downgrade(struct nfsd4_compoundres *resp, __be32 nfserr, struc } ENCODE_SEQID_OP_TAIL(od->od_stateowner); + return nfserr; } static __be32 @@ -2443,7 +2415,7 @@ err_no_verf: return nfserr; } -static void +static __be32 nfsd4_encode_remove(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_remove *remove) { ENCODE_HEAD; @@ -2453,9 +2425,10 @@ nfsd4_encode_remove(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_ WRITECINFO(remove->rm_cinfo); ADJUST_ARGS(); } + return nfserr; } -static void +static __be32 nfsd4_encode_rename(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_rename *rename) { ENCODE_HEAD; @@ -2466,9 +2439,10 @@ nfsd4_encode_rename(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_ WRITECINFO(rename->rn_tinfo); ADJUST_ARGS(); } + return nfserr; } -static void +static __be32 nfsd4_encode_secinfo(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_secinfo *secinfo) { @@ -2532,13 +2506,14 @@ nfsd4_encode_secinfo(struct nfsd4_compoundres *resp, __be32 nfserr, out: if (exp) exp_put(exp); + return nfserr; } /* * The SETATTR encode routine is special -- it always encodes a bitmap, * regardless of the error status. */ -static void +static __be32 nfsd4_encode_setattr(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_setattr *setattr) { ENCODE_HEAD; @@ -2555,9 +2530,10 @@ nfsd4_encode_setattr(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4 WRITE32(setattr->sa_bmval[1]); } ADJUST_ARGS(); + return nfserr; } -static void +static __be32 nfsd4_encode_setclientid(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_setclientid *scd) { ENCODE_HEAD; @@ -2574,9 +2550,10 @@ nfsd4_encode_setclientid(struct nfsd4_compoundres *resp, __be32 nfserr, struct n WRITE32(0); ADJUST_ARGS(); } + return nfserr; } -static void +static __be32 nfsd4_encode_write(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_write *write) { ENCODE_HEAD; @@ -2588,8 +2565,56 @@ nfsd4_encode_write(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_w WRITEMEM(write->wr_verifier.data, 8); ADJUST_ARGS(); } + return nfserr; } +static __be32 +nfsd4_encode_noop(struct nfsd4_compoundres *resp, __be32 nfserr, void *p) +{ + return nfserr; +} + +typedef __be32(* nfsd4_enc)(struct nfsd4_compoundres *, __be32, void *); + +static nfsd4_enc nfsd4_enc_ops[] = { + [OP_ACCESS] = (nfsd4_enc)nfsd4_encode_access, + [OP_CLOSE] = (nfsd4_enc)nfsd4_encode_close, + [OP_COMMIT] = (nfsd4_enc)nfsd4_encode_commit, + [OP_CREATE] = (nfsd4_enc)nfsd4_encode_create, + [OP_DELEGPURGE] = (nfsd4_enc)nfsd4_encode_noop, + [OP_DELEGRETURN] = (nfsd4_enc)nfsd4_encode_noop, + [OP_GETATTR] = (nfsd4_enc)nfsd4_encode_getattr, + [OP_GETFH] = (nfsd4_enc)nfsd4_encode_getfh, + [OP_LINK] = (nfsd4_enc)nfsd4_encode_link, + [OP_LOCK] = (nfsd4_enc)nfsd4_encode_lock, + [OP_LOCKT] = (nfsd4_enc)nfsd4_encode_lockt, + [OP_LOCKU] = (nfsd4_enc)nfsd4_encode_locku, + [OP_LOOKUP] = (nfsd4_enc)nfsd4_encode_noop, + [OP_LOOKUPP] = (nfsd4_enc)nfsd4_encode_noop, + [OP_NVERIFY] = (nfsd4_enc)nfsd4_encode_noop, + [OP_OPEN] = (nfsd4_enc)nfsd4_encode_open, + [OP_OPEN_CONFIRM] = (nfsd4_enc)nfsd4_encode_open_confirm, + [OP_OPEN_DOWNGRADE] = (nfsd4_enc)nfsd4_encode_open_downgrade, + [OP_PUTFH] = (nfsd4_enc)nfsd4_encode_noop, + [OP_PUTPUBFH] = (nfsd4_enc)nfsd4_encode_noop, + [OP_PUTROOTFH] = (nfsd4_enc)nfsd4_encode_noop, + [OP_READ] = (nfsd4_enc)nfsd4_encode_read, + [OP_READDIR] = (nfsd4_enc)nfsd4_encode_readdir, + [OP_READLINK] = (nfsd4_enc)nfsd4_encode_readlink, + [OP_REMOVE] = (nfsd4_enc)nfsd4_encode_remove, + [OP_RENAME] = (nfsd4_enc)nfsd4_encode_rename, + [OP_RENEW] = (nfsd4_enc)nfsd4_encode_noop, + [OP_RESTOREFH] = (nfsd4_enc)nfsd4_encode_noop, + [OP_SAVEFH] = (nfsd4_enc)nfsd4_encode_noop, + [OP_SECINFO] = (nfsd4_enc)nfsd4_encode_secinfo, + [OP_SETATTR] = (nfsd4_enc)nfsd4_encode_setattr, + [OP_SETCLIENTID] = (nfsd4_enc)nfsd4_encode_setclientid, + [OP_SETCLIENTID_CONFIRM] = (nfsd4_enc)nfsd4_encode_noop, + [OP_VERIFY] = (nfsd4_enc)nfsd4_encode_noop, + [OP_WRITE] = (nfsd4_enc)nfsd4_encode_write, + [OP_RELEASE_LOCKOWNER] = (nfsd4_enc)nfsd4_encode_noop, +}; + void nfsd4_encode_operation(struct nfsd4_compoundres *resp, struct nfsd4_op *op) { @@ -2601,101 +2626,12 @@ nfsd4_encode_operation(struct nfsd4_compoundres *resp, struct nfsd4_op *op) statp = p++; /* to be backfilled at the end */ ADJUST_ARGS(); - switch (op->opnum) { - case OP_ACCESS: - nfsd4_encode_access(resp, op->status, &op->u.access); - break; - case OP_CLOSE: - nfsd4_encode_close(resp, op->status, &op->u.close); - break; - case OP_COMMIT: - nfsd4_encode_commit(resp, op->status, &op->u.commit); - break; - case OP_CREATE: - nfsd4_encode_create(resp, op->status, &op->u.create); - break; - case OP_DELEGRETURN: - break; - case OP_GETATTR: - op->status = nfsd4_encode_getattr(resp, op->status, &op->u.getattr); - break; - case OP_GETFH: - nfsd4_encode_getfh(resp, op->status, op->u.getfh); - break; - case OP_LINK: - nfsd4_encode_link(resp, op->status, &op->u.link); - break; - case OP_LOCK: - nfsd4_encode_lock(resp, op->status, &op->u.lock); - break; - case OP_LOCKT: - nfsd4_encode_lockt(resp, op->status, &op->u.lockt); - break; - case OP_LOCKU: - nfsd4_encode_locku(resp, op->status, &op->u.locku); - break; - case OP_LOOKUP: - break; - case OP_LOOKUPP: - break; - case OP_NVERIFY: - break; - case OP_OPEN: - nfsd4_encode_open(resp, op->status, &op->u.open); - break; - case OP_OPEN_CONFIRM: - nfsd4_encode_open_confirm(resp, op->status, &op->u.open_confirm); - break; - case OP_OPEN_DOWNGRADE: - nfsd4_encode_open_downgrade(resp, op->status, &op->u.open_downgrade); - break; - case OP_PUTFH: - break; - case OP_PUTROOTFH: - break; - case OP_READ: - op->status = nfsd4_encode_read(resp, op->status, &op->u.read); - break; - case OP_READDIR: - op->status = nfsd4_encode_readdir(resp, op->status, &op->u.readdir); - break; - case OP_READLINK: - op->status = nfsd4_encode_readlink(resp, op->status, &op->u.readlink); - break; - case OP_REMOVE: - nfsd4_encode_remove(resp, op->status, &op->u.remove); - break; - case OP_RENAME: - nfsd4_encode_rename(resp, op->status, &op->u.rename); - break; - case OP_RENEW: - break; - case OP_RESTOREFH: - break; - case OP_SAVEFH: - break; - case OP_SECINFO: - nfsd4_encode_secinfo(resp, op->status, &op->u.secinfo); - break; - case OP_SETATTR: - nfsd4_encode_setattr(resp, op->status, &op->u.setattr); - break; - case OP_SETCLIENTID: - nfsd4_encode_setclientid(resp, op->status, &op->u.setclientid); - break; - case OP_SETCLIENTID_CONFIRM: - break; - case OP_VERIFY: - break; - case OP_WRITE: - nfsd4_encode_write(resp, op->status, &op->u.write); - break; - case OP_RELEASE_LOCKOWNER: - break; - default: - break; - } - + if (op->opnum == OP_ILLEGAL) + goto status; + BUG_ON(op->opnum < 0 || op->opnum >= ARRAY_SIZE(nfsd4_enc_ops) || + !nfsd4_enc_ops[op->opnum]); + op->status = nfsd4_enc_ops[op->opnum](resp, op->status, &op->u); +status: /* * Note: We write the status directly, instead of using WRITE32(), * since it is already in network byte order. diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c index 5ac00c4fee91..1955a2702e60 100644 --- a/fs/nfsd/nfsctl.c +++ b/fs/nfsd/nfsctl.c @@ -310,9 +310,12 @@ static ssize_t write_getfd(struct file *file, char *buf, size_t size) static ssize_t failover_unlock_ip(struct file *file, char *buf, size_t size) { - __be32 server_ip; - char *fo_path, c; + struct sockaddr_in sin = { + .sin_family = AF_INET, + }; int b1, b2, b3, b4; + char c; + char *fo_path; /* sanity check */ if (size == 0) @@ -326,11 +329,13 @@ static ssize_t failover_unlock_ip(struct file *file, char *buf, size_t size) return -EINVAL; /* get ipv4 address */ - if (sscanf(fo_path, "%u.%u.%u.%u%c", &b1, &b2, &b3, &b4, &c) != 4) + if (sscanf(fo_path, NIPQUAD_FMT "%c", &b1, &b2, &b3, &b4, &c) != 4) return -EINVAL; - server_ip = htonl((((((b1<<8)|b2)<<8)|b3)<<8)|b4); + if (b1 > 255 || b2 > 255 || b3 > 255 || b4 > 255) + return -EINVAL; + sin.sin_addr.s_addr = htonl((b1 << 24) | (b2 << 16) | (b3 << 8) | b4); - return nlmsvc_unlock_all_by_ip(server_ip); + return nlmsvc_unlock_all_by_ip((struct sockaddr *)&sin); } static ssize_t failover_unlock_fs(struct file *file, char *buf, size_t size) @@ -450,22 +455,26 @@ static ssize_t write_pool_threads(struct file *file, char *buf, size_t size) int i; int rv; int len; - int npools = nfsd_nrpools(); + int npools; int *nthreads; + mutex_lock(&nfsd_mutex); + npools = nfsd_nrpools(); if (npools == 0) { /* * NFS is shut down. The admin can start it by * writing to the threads file but NOT the pool_threads * file, sorry. Report zero threads. */ + mutex_unlock(&nfsd_mutex); strcpy(buf, "0\n"); return strlen(buf); } nthreads = kcalloc(npools, sizeof(int), GFP_KERNEL); + rv = -ENOMEM; if (nthreads == NULL) - return -ENOMEM; + goto out_free; if (size > 0) { for (i = 0; i < npools; i++) { @@ -496,14 +505,16 @@ static ssize_t write_pool_threads(struct file *file, char *buf, size_t size) mesg += len; } + mutex_unlock(&nfsd_mutex); return (mesg-buf); out_free: kfree(nthreads); + mutex_unlock(&nfsd_mutex); return rv; } -static ssize_t write_versions(struct file *file, char *buf, size_t size) +static ssize_t __write_versions(struct file *file, char *buf, size_t size) { /* * Format: @@ -566,14 +577,23 @@ static ssize_t write_versions(struct file *file, char *buf, size_t size) return len; } -static ssize_t write_ports(struct file *file, char *buf, size_t size) +static ssize_t write_versions(struct file *file, char *buf, size_t size) +{ + ssize_t rv; + + mutex_lock(&nfsd_mutex); + rv = __write_versions(file, buf, size); + mutex_unlock(&nfsd_mutex); + return rv; +} + +static ssize_t __write_ports(struct file *file, char *buf, size_t size) { if (size == 0) { int len = 0; - lock_kernel(); + if (nfsd_serv) len = svc_xprt_names(nfsd_serv, buf, 0); - unlock_kernel(); return len; } /* Either a single 'fd' number is written, in which @@ -603,9 +623,7 @@ static ssize_t write_ports(struct file *file, char *buf, size_t size) /* Decrease the count, but don't shutdown the * the service */ - lock_kernel(); nfsd_serv->sv_nrthreads--; - unlock_kernel(); } return err < 0 ? err : 0; } @@ -614,10 +632,8 @@ static ssize_t write_ports(struct file *file, char *buf, size_t size) int len = 0; if (!toclose) return -ENOMEM; - lock_kernel(); if (nfsd_serv) len = svc_sock_names(buf, nfsd_serv, toclose); - unlock_kernel(); if (len >= 0) lockd_down(); kfree(toclose); @@ -655,7 +671,6 @@ static ssize_t write_ports(struct file *file, char *buf, size_t size) if (sscanf(&buf[1], "%15s %4d", transport, &port) == 2) { if (port == 0) return -EINVAL; - lock_kernel(); if (nfsd_serv) { xprt = svc_find_xprt(nfsd_serv, transport, AF_UNSPEC, port); @@ -666,13 +681,23 @@ static ssize_t write_ports(struct file *file, char *buf, size_t size) } else err = -ENOTCONN; } - unlock_kernel(); return err < 0 ? err : 0; } } return -EINVAL; } +static ssize_t write_ports(struct file *file, char *buf, size_t size) +{ + ssize_t rv; + + mutex_lock(&nfsd_mutex); + rv = __write_ports(file, buf, size); + mutex_unlock(&nfsd_mutex); + return rv; +} + + int nfsd_max_blksize; static ssize_t write_maxblksize(struct file *file, char *buf, size_t size) @@ -691,13 +716,13 @@ static ssize_t write_maxblksize(struct file *file, char *buf, size_t size) if (bsize > NFSSVC_MAXBLKSIZE) bsize = NFSSVC_MAXBLKSIZE; bsize &= ~(1024-1); - lock_kernel(); + mutex_lock(&nfsd_mutex); if (nfsd_serv && nfsd_serv->sv_nrthreads) { - unlock_kernel(); + mutex_unlock(&nfsd_mutex); return -EBUSY; } nfsd_max_blksize = bsize; - unlock_kernel(); + mutex_unlock(&nfsd_mutex); } return sprintf(buf, "%d\n", nfsd_max_blksize); } @@ -705,16 +730,17 @@ static ssize_t write_maxblksize(struct file *file, char *buf, size_t size) #ifdef CONFIG_NFSD_V4 extern time_t nfs4_leasetime(void); -static ssize_t write_leasetime(struct file *file, char *buf, size_t size) +static ssize_t __write_leasetime(struct file *file, char *buf, size_t size) { /* if size > 10 seconds, call * nfs4_reset_lease() then write out the new lease (seconds) as reply */ char *mesg = buf; - int rv; + int rv, lease; if (size > 0) { - int lease; + if (nfsd_serv) + return -EBUSY; rv = get_int(&mesg, &lease); if (rv) return rv; @@ -726,24 +752,52 @@ static ssize_t write_leasetime(struct file *file, char *buf, size_t size) return strlen(buf); } -static ssize_t write_recoverydir(struct file *file, char *buf, size_t size) +static ssize_t write_leasetime(struct file *file, char *buf, size_t size) +{ + ssize_t rv; + + mutex_lock(&nfsd_mutex); + rv = __write_leasetime(file, buf, size); + mutex_unlock(&nfsd_mutex); + return rv; +} + +extern char *nfs4_recoverydir(void); + +static ssize_t __write_recoverydir(struct file *file, char *buf, size_t size) { char *mesg = buf; char *recdir; int len, status; - if (size == 0 || size > PATH_MAX || buf[size-1] != '\n') - return -EINVAL; - buf[size-1] = 0; + if (size > 0) { + if (nfsd_serv) + return -EBUSY; + if (size > PATH_MAX || buf[size-1] != '\n') + return -EINVAL; + buf[size-1] = 0; - recdir = mesg; - len = qword_get(&mesg, recdir, size); - if (len <= 0) - return -EINVAL; + recdir = mesg; + len = qword_get(&mesg, recdir, size); + if (len <= 0) + return -EINVAL; - status = nfs4_reset_recoverydir(recdir); + status = nfs4_reset_recoverydir(recdir); + } + sprintf(buf, "%s\n", nfs4_recoverydir()); return strlen(buf); } + +static ssize_t write_recoverydir(struct file *file, char *buf, size_t size) +{ + ssize_t rv; + + mutex_lock(&nfsd_mutex); + rv = __write_recoverydir(file, buf, size); + mutex_unlock(&nfsd_mutex); + return rv; +} + #endif /*----------------------------------------------------------------------------*/ diff --git a/fs/nfsd/nfsfh.c b/fs/nfsd/nfsfh.c index 100ae5641162..f45451eb1e38 100644 --- a/fs/nfsd/nfsfh.c +++ b/fs/nfsd/nfsfh.c @@ -176,9 +176,24 @@ static __be32 nfsd_set_fh_dentry(struct svc_rqst *rqstp, struct svc_fh *fhp) if (IS_ERR(exp)) return nfserrno(PTR_ERR(exp)); - error = nfsd_setuser_and_check_port(rqstp, exp); - if (error) - goto out; + if (exp->ex_flags & NFSEXP_NOSUBTREECHECK) { + /* Elevate privileges so that the lack of 'r' or 'x' + * permission on some parent directory will + * not stop exportfs_decode_fh from being able + * to reconnect a directory into the dentry cache. + * The same problem can affect "SUBTREECHECK" exports, + * but as nfsd_acceptable depends on correct + * access control settings being in effect, we cannot + * fix that case easily. + */ + current->cap_effective = + cap_raise_nfsd_set(current->cap_effective, + current->cap_permitted); + } else { + error = nfsd_setuser_and_check_port(rqstp, exp); + if (error) + goto out; + } /* * Look up the dentry using the NFS file handle. @@ -215,6 +230,14 @@ static __be32 nfsd_set_fh_dentry(struct svc_rqst *rqstp, struct svc_fh *fhp) goto out; } + if (exp->ex_flags & NFSEXP_NOSUBTREECHECK) { + error = nfsd_setuser_and_check_port(rqstp, exp); + if (error) { + dput(dentry); + goto out; + } + } + if (S_ISDIR(dentry->d_inode->i_mode) && (dentry->d_flags & DCACHE_DISCONNECTED)) { printk("nfsd: find_fh_dentry returned a DISCONNECTED directory: %s/%s\n", @@ -279,7 +302,7 @@ fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, int access) if (error) goto out; - if (!(access & MAY_LOCK)) { + if (!(access & NFSD_MAY_LOCK)) { /* * pseudoflavor restrictions are not enforced on NLM, * which clients virtually always use auth_sys for, diff --git a/fs/nfsd/nfsproc.c b/fs/nfsd/nfsproc.c index 6cfc96a12483..0766f95d236a 100644 --- a/fs/nfsd/nfsproc.c +++ b/fs/nfsd/nfsproc.c @@ -65,7 +65,7 @@ nfsd_proc_getattr(struct svc_rqst *rqstp, struct nfsd_fhandle *argp, dprintk("nfsd: GETATTR %s\n", SVCFH_fmt(&argp->fh)); fh_copy(&resp->fh, &argp->fh); - nfserr = fh_verify(rqstp, &resp->fh, 0, MAY_NOP); + nfserr = fh_verify(rqstp, &resp->fh, 0, NFSD_MAY_NOP); return nfsd_return_attrs(nfserr, resp); } @@ -215,11 +215,11 @@ nfsd_proc_create(struct svc_rqst *rqstp, struct nfsd_createargs *argp, SVCFH_fmt(dirfhp), argp->len, argp->name); /* First verify the parent file handle */ - nfserr = fh_verify(rqstp, dirfhp, S_IFDIR, MAY_EXEC); + nfserr = fh_verify(rqstp, dirfhp, S_IFDIR, NFSD_MAY_EXEC); if (nfserr) goto done; /* must fh_put dirfhp even on error */ - /* Check for MAY_WRITE in nfsd_create if necessary */ + /* Check for NFSD_MAY_WRITE in nfsd_create if necessary */ nfserr = nfserr_acces; if (!argp->len) @@ -281,7 +281,7 @@ nfsd_proc_create(struct svc_rqst *rqstp, struct nfsd_createargs *argp, nfserr = nfsd_permission(rqstp, newfhp->fh_export, newfhp->fh_dentry, - MAY_WRITE|MAY_LOCAL_ACCESS); + NFSD_MAY_WRITE|NFSD_MAY_LOCAL_ACCESS); if (nfserr && nfserr != nfserr_rofs) goto out_unlock; } @@ -614,6 +614,7 @@ nfserrno (int errno) #endif { nfserr_stale, -ESTALE }, { nfserr_jukebox, -ETIMEDOUT }, + { nfserr_jukebox, -ERESTARTSYS }, { nfserr_dropit, -EAGAIN }, { nfserr_dropit, -ENOMEM }, { nfserr_badname, -ESRCH }, diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c index 941041f4b136..80292ff5e924 100644 --- a/fs/nfsd/nfssvc.c +++ b/fs/nfsd/nfssvc.c @@ -21,6 +21,7 @@ #include <linux/smp_lock.h> #include <linux/freezer.h> #include <linux/fs_struct.h> +#include <linux/kthread.h> #include <linux/sunrpc/types.h> #include <linux/sunrpc/stats.h> @@ -36,28 +37,38 @@ #define NFSDDBG_FACILITY NFSDDBG_SVC -/* these signals will be delivered to an nfsd thread - * when handling a request - */ -#define ALLOWED_SIGS (sigmask(SIGKILL)) -/* these signals will be delivered to an nfsd thread - * when not handling a request. i.e. when waiting - */ -#define SHUTDOWN_SIGS (sigmask(SIGKILL) | sigmask(SIGHUP) | sigmask(SIGINT) | sigmask(SIGQUIT)) -/* if the last thread dies with SIGHUP, then the exports table is - * left unchanged ( like 2.4-{0-9} ). Any other signal will clear - * the exports table (like 2.2). - */ -#define SIG_NOCLEAN SIGHUP - extern struct svc_program nfsd_program; -static void nfsd(struct svc_rqst *rqstp); +static int nfsd(void *vrqstp); struct timeval nfssvc_boot; - struct svc_serv *nfsd_serv; static atomic_t nfsd_busy; static unsigned long nfsd_last_call; static DEFINE_SPINLOCK(nfsd_call_lock); +/* + * nfsd_mutex protects nfsd_serv -- both the pointer itself and the members + * of the svc_serv struct. In particular, ->sv_nrthreads but also to some + * extent ->sv_temp_socks and ->sv_permsocks. It also protects nfsdstats.th_cnt + * + * If (out side the lock) nfsd_serv is non-NULL, then it must point to a + * properly initialised 'struct svc_serv' with ->sv_nrthreads > 0. That number + * of nfsd threads must exist and each must listed in ->sp_all_threads in each + * entry of ->sv_pools[]. + * + * Transitions of the thread count between zero and non-zero are of particular + * interest since the svc_serv needs to be created and initialized at that + * point, or freed. + * + * Finally, the nfsd_mutex also protects some of the global variables that are + * accessed when nfsd starts and that are settable via the write_* routines in + * nfsctl.c. In particular: + * + * user_recovery_dirname + * user_lease_time + * nfsd_versions + */ +DEFINE_MUTEX(nfsd_mutex); +struct svc_serv *nfsd_serv; + #if defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL) static struct svc_stat nfsd_acl_svcstats; static struct svc_version * nfsd_acl_version[] = { @@ -145,13 +156,14 @@ int nfsd_vers(int vers, enum vers_op change) int nfsd_nrthreads(void) { - if (nfsd_serv == NULL) - return 0; - else - return nfsd_serv->sv_nrthreads; + int rv = 0; + mutex_lock(&nfsd_mutex); + if (nfsd_serv) + rv = nfsd_serv->sv_nrthreads; + mutex_unlock(&nfsd_mutex); + return rv; } -static int killsig; /* signal that was used to kill last nfsd */ static void nfsd_last_thread(struct svc_serv *serv) { /* When last nfsd thread exits we need to do some clean-up */ @@ -162,11 +174,9 @@ static void nfsd_last_thread(struct svc_serv *serv) nfsd_racache_shutdown(); nfs4_state_shutdown(); - printk(KERN_WARNING "nfsd: last server has exited\n"); - if (killsig != SIG_NOCLEAN) { - printk(KERN_WARNING "nfsd: unexporting all filesystems\n"); - nfsd_export_flush(); - } + printk(KERN_WARNING "nfsd: last server has exited, flushing export " + "cache\n"); + nfsd_export_flush(); } void nfsd_reset_versions(void) @@ -190,13 +200,14 @@ void nfsd_reset_versions(void) } } + int nfsd_create_serv(void) { int err = 0; - lock_kernel(); + + WARN_ON(!mutex_is_locked(&nfsd_mutex)); if (nfsd_serv) { svc_get(nfsd_serv); - unlock_kernel(); return 0; } if (nfsd_max_blksize == 0) { @@ -217,13 +228,11 @@ int nfsd_create_serv(void) } atomic_set(&nfsd_busy, 0); - nfsd_serv = svc_create_pooled(&nfsd_program, - nfsd_max_blksize, - nfsd_last_thread, - nfsd, SIG_NOCLEAN, THIS_MODULE); + nfsd_serv = svc_create_pooled(&nfsd_program, nfsd_max_blksize, + nfsd_last_thread, nfsd, THIS_MODULE); if (nfsd_serv == NULL) err = -ENOMEM; - unlock_kernel(); + do_gettimeofday(&nfssvc_boot); /* record boot time */ return err; } @@ -282,6 +291,8 @@ int nfsd_set_nrthreads(int n, int *nthreads) int tot = 0; int err = 0; + WARN_ON(!mutex_is_locked(&nfsd_mutex)); + if (nfsd_serv == NULL || n <= 0) return 0; @@ -316,7 +327,6 @@ int nfsd_set_nrthreads(int n, int *nthreads) nthreads[0] = 1; /* apply the new numbers */ - lock_kernel(); svc_get(nfsd_serv); for (i = 0; i < n; i++) { err = svc_set_num_threads(nfsd_serv, &nfsd_serv->sv_pools[i], @@ -325,7 +335,6 @@ int nfsd_set_nrthreads(int n, int *nthreads) break; } svc_destroy(nfsd_serv); - unlock_kernel(); return err; } @@ -334,8 +343,8 @@ int nfsd_svc(unsigned short port, int nrservs) { int error; - - lock_kernel(); + + mutex_lock(&nfsd_mutex); dprintk("nfsd: creating service\n"); error = -EINVAL; if (nrservs <= 0) @@ -363,7 +372,7 @@ nfsd_svc(unsigned short port, int nrservs) failure: svc_destroy(nfsd_serv); /* Release server */ out: - unlock_kernel(); + mutex_unlock(&nfsd_mutex); return error; } @@ -391,18 +400,17 @@ update_thread_usage(int busy_threads) /* * This is the NFS server kernel thread */ -static void -nfsd(struct svc_rqst *rqstp) +static int +nfsd(void *vrqstp) { + struct svc_rqst *rqstp = (struct svc_rqst *) vrqstp; struct fs_struct *fsp; - int err; - sigset_t shutdown_mask, allowed_mask; + int err, preverr = 0; /* Lock module and set up kernel thread */ - lock_kernel(); - daemonize("nfsd"); + mutex_lock(&nfsd_mutex); - /* After daemonize() this kernel thread shares current->fs + /* At this point, the thread shares current->fs * with the init process. We need to create files with a * umask of 0 instead of init's umask. */ fsp = copy_fs_struct(current->fs); @@ -414,14 +422,17 @@ nfsd(struct svc_rqst *rqstp) current->fs = fsp; current->fs->umask = 0; - siginitsetinv(&shutdown_mask, SHUTDOWN_SIGS); - siginitsetinv(&allowed_mask, ALLOWED_SIGS); + /* + * thread is spawned with all signals set to SIG_IGN, re-enable + * the ones that will bring down the thread + */ + allow_signal(SIGKILL); + allow_signal(SIGHUP); + allow_signal(SIGINT); + allow_signal(SIGQUIT); nfsdstats.th_cnt++; - - rqstp->rq_task = current; - - unlock_kernel(); + mutex_unlock(&nfsd_mutex); /* * We want less throttling in balance_dirty_pages() so that nfs to @@ -435,26 +446,30 @@ nfsd(struct svc_rqst *rqstp) * The main request loop */ for (;;) { - /* Block all but the shutdown signals */ - sigprocmask(SIG_SETMASK, &shutdown_mask, NULL); - /* * Find a socket with data available and call its * recvfrom routine. */ while ((err = svc_recv(rqstp, 60*60*HZ)) == -EAGAIN) ; - if (err < 0) + if (err == -EINTR) break; + else if (err < 0) { + if (err != preverr) { + printk(KERN_WARNING "%s: unexpected error " + "from svc_recv (%d)\n", __func__, -err); + preverr = err; + } + schedule_timeout_uninterruptible(HZ); + continue; + } + update_thread_usage(atomic_read(&nfsd_busy)); atomic_inc(&nfsd_busy); /* Lock the export hash tables for reading. */ exp_readlock(); - /* Process request with signals blocked. */ - sigprocmask(SIG_SETMASK, &allowed_mask, NULL); - svc_process(rqstp); /* Unlock export hash tables */ @@ -463,22 +478,10 @@ nfsd(struct svc_rqst *rqstp) atomic_dec(&nfsd_busy); } - if (err != -EINTR) { - printk(KERN_WARNING "nfsd: terminating on error %d\n", -err); - } else { - unsigned int signo; - - for (signo = 1; signo <= _NSIG; signo++) - if (sigismember(¤t->pending.signal, signo) && - !sigismember(¤t->blocked, signo)) - break; - killsig = signo; - } /* Clear signals before calling svc_exit_thread() */ flush_signals(current); - lock_kernel(); - + mutex_lock(&nfsd_mutex); nfsdstats.th_cnt --; out: @@ -486,8 +489,9 @@ out: svc_exit_thread(rqstp); /* Release module */ - unlock_kernel(); + mutex_unlock(&nfsd_mutex); module_put_and_exit(0); + return 0; } static __be32 map_new_errors(u32 vers, __be32 nfserr) diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c index a3a291f771f4..0f4481e0502d 100644 --- a/fs/nfsd/vfs.c +++ b/fs/nfsd/vfs.c @@ -144,7 +144,7 @@ nfsd_lookup_dentry(struct svc_rqst *rqstp, struct svc_fh *fhp, dprintk("nfsd: nfsd_lookup(fh %s, %.*s)\n", SVCFH_fmt(fhp), len,name); /* Obtain dentry and export. */ - err = fh_verify(rqstp, fhp, S_IFDIR, MAY_EXEC); + err = fh_verify(rqstp, fhp, S_IFDIR, NFSD_MAY_EXEC); if (err) return err; @@ -262,14 +262,14 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap, { struct dentry *dentry; struct inode *inode; - int accmode = MAY_SATTR; + int accmode = NFSD_MAY_SATTR; int ftype = 0; __be32 err; int host_err; int size_change = 0; if (iap->ia_valid & (ATTR_ATIME | ATTR_MTIME | ATTR_SIZE)) - accmode |= MAY_WRITE|MAY_OWNER_OVERRIDE; + accmode |= NFSD_MAY_WRITE|NFSD_MAY_OWNER_OVERRIDE; if (iap->ia_valid & ATTR_SIZE) ftype = S_IFREG; @@ -331,7 +331,8 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap, */ if (iap->ia_valid & ATTR_SIZE) { if (iap->ia_size < inode->i_size) { - err = nfsd_permission(rqstp, fhp->fh_export, dentry, MAY_TRUNC|MAY_OWNER_OVERRIDE); + err = nfsd_permission(rqstp, fhp->fh_export, dentry, + NFSD_MAY_TRUNC|NFSD_MAY_OWNER_OVERRIDE); if (err) goto out; } @@ -462,7 +463,7 @@ nfsd4_set_nfs4_acl(struct svc_rqst *rqstp, struct svc_fh *fhp, unsigned int flags = 0; /* Get inode */ - error = fh_verify(rqstp, fhp, 0 /* S_IFREG */, MAY_SATTR); + error = fh_verify(rqstp, fhp, 0 /* S_IFREG */, NFSD_MAY_SATTR); if (error) return error; @@ -563,20 +564,20 @@ struct accessmap { int how; }; static struct accessmap nfs3_regaccess[] = { - { NFS3_ACCESS_READ, MAY_READ }, - { NFS3_ACCESS_EXECUTE, MAY_EXEC }, - { NFS3_ACCESS_MODIFY, MAY_WRITE|MAY_TRUNC }, - { NFS3_ACCESS_EXTEND, MAY_WRITE }, + { NFS3_ACCESS_READ, NFSD_MAY_READ }, + { NFS3_ACCESS_EXECUTE, NFSD_MAY_EXEC }, + { NFS3_ACCESS_MODIFY, NFSD_MAY_WRITE|NFSD_MAY_TRUNC }, + { NFS3_ACCESS_EXTEND, NFSD_MAY_WRITE }, { 0, 0 } }; static struct accessmap nfs3_diraccess[] = { - { NFS3_ACCESS_READ, MAY_READ }, - { NFS3_ACCESS_LOOKUP, MAY_EXEC }, - { NFS3_ACCESS_MODIFY, MAY_EXEC|MAY_WRITE|MAY_TRUNC }, - { NFS3_ACCESS_EXTEND, MAY_EXEC|MAY_WRITE }, - { NFS3_ACCESS_DELETE, MAY_REMOVE }, + { NFS3_ACCESS_READ, NFSD_MAY_READ }, + { NFS3_ACCESS_LOOKUP, NFSD_MAY_EXEC }, + { NFS3_ACCESS_MODIFY, NFSD_MAY_EXEC|NFSD_MAY_WRITE|NFSD_MAY_TRUNC}, + { NFS3_ACCESS_EXTEND, NFSD_MAY_EXEC|NFSD_MAY_WRITE }, + { NFS3_ACCESS_DELETE, NFSD_MAY_REMOVE }, { 0, 0 } }; @@ -589,10 +590,10 @@ static struct accessmap nfs3_anyaccess[] = { * mainly at mode bits, and we make sure to ignore read-only * filesystem checks */ - { NFS3_ACCESS_READ, MAY_READ }, - { NFS3_ACCESS_EXECUTE, MAY_EXEC }, - { NFS3_ACCESS_MODIFY, MAY_WRITE|MAY_LOCAL_ACCESS }, - { NFS3_ACCESS_EXTEND, MAY_WRITE|MAY_LOCAL_ACCESS }, + { NFS3_ACCESS_READ, NFSD_MAY_READ }, + { NFS3_ACCESS_EXECUTE, NFSD_MAY_EXEC }, + { NFS3_ACCESS_MODIFY, NFSD_MAY_WRITE|NFSD_MAY_LOCAL_ACCESS }, + { NFS3_ACCESS_EXTEND, NFSD_MAY_WRITE|NFSD_MAY_LOCAL_ACCESS }, { 0, 0 } }; @@ -606,7 +607,7 @@ nfsd_access(struct svc_rqst *rqstp, struct svc_fh *fhp, u32 *access, u32 *suppor u32 query, result = 0, sresult = 0; __be32 error; - error = fh_verify(rqstp, fhp, 0, MAY_NOP); + error = fh_verify(rqstp, fhp, 0, NFSD_MAY_NOP); if (error) goto out; @@ -678,7 +679,7 @@ nfsd_open(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, * and (hopefully) checked permission - so allow OWNER_OVERRIDE * in case a chmod has now revoked permission. */ - err = fh_verify(rqstp, fhp, type, access | MAY_OWNER_OVERRIDE); + err = fh_verify(rqstp, fhp, type, access | NFSD_MAY_OWNER_OVERRIDE); if (err) goto out; @@ -689,7 +690,7 @@ nfsd_open(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, * or any access when mandatory locking enabled */ err = nfserr_perm; - if (IS_APPEND(inode) && (access & MAY_WRITE)) + if (IS_APPEND(inode) && (access & NFSD_MAY_WRITE)) goto out; /* * We must ignore files (but only files) which might have mandatory @@ -706,14 +707,14 @@ nfsd_open(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, * Check to see if there are any leases on this file. * This may block while leases are broken. */ - host_err = break_lease(inode, O_NONBLOCK | ((access & MAY_WRITE) ? FMODE_WRITE : 0)); + host_err = break_lease(inode, O_NONBLOCK | ((access & NFSD_MAY_WRITE) ? FMODE_WRITE : 0)); if (host_err == -EWOULDBLOCK) host_err = -ETIMEDOUT; if (host_err) /* NOMEM or WOULDBLOCK */ goto out_nfserr; - if (access & MAY_WRITE) { - if (access & MAY_READ) + if (access & NFSD_MAY_WRITE) { + if (access & NFSD_MAY_READ) flags = O_RDWR|O_LARGEFILE; else flags = O_WRONLY|O_LARGEFILE; @@ -1069,12 +1070,12 @@ nfsd_read(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file, if (file) { err = nfsd_permission(rqstp, fhp->fh_export, fhp->fh_dentry, - MAY_READ|MAY_OWNER_OVERRIDE); + NFSD_MAY_READ|NFSD_MAY_OWNER_OVERRIDE); if (err) goto out; err = nfsd_vfs_read(rqstp, fhp, file, offset, vec, vlen, count); } else { - err = nfsd_open(rqstp, fhp, S_IFREG, MAY_READ, &file); + err = nfsd_open(rqstp, fhp, S_IFREG, NFSD_MAY_READ, &file); if (err) goto out; err = nfsd_vfs_read(rqstp, fhp, file, offset, vec, vlen, count); @@ -1098,13 +1099,13 @@ nfsd_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file, if (file) { err = nfsd_permission(rqstp, fhp->fh_export, fhp->fh_dentry, - MAY_WRITE|MAY_OWNER_OVERRIDE); + NFSD_MAY_WRITE|NFSD_MAY_OWNER_OVERRIDE); if (err) goto out; err = nfsd_vfs_write(rqstp, fhp, file, offset, vec, vlen, cnt, stablep); } else { - err = nfsd_open(rqstp, fhp, S_IFREG, MAY_WRITE, &file); + err = nfsd_open(rqstp, fhp, S_IFREG, NFSD_MAY_WRITE, &file); if (err) goto out; @@ -1136,7 +1137,8 @@ nfsd_commit(struct svc_rqst *rqstp, struct svc_fh *fhp, if ((u64)count > ~(u64)offset) return nfserr_inval; - if ((err = nfsd_open(rqstp, fhp, S_IFREG, MAY_WRITE, &file)) != 0) + err = nfsd_open(rqstp, fhp, S_IFREG, NFSD_MAY_WRITE, &file); + if (err) return err; if (EX_ISSYNC(fhp->fh_export)) { if (file->f_op && file->f_op->fsync) { @@ -1197,7 +1199,7 @@ nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp, if (isdotent(fname, flen)) goto out; - err = fh_verify(rqstp, fhp, S_IFDIR, MAY_CREATE); + err = fh_verify(rqstp, fhp, S_IFDIR, NFSD_MAY_CREATE); if (err) goto out; @@ -1248,36 +1250,34 @@ nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp, iap->ia_mode = 0; iap->ia_mode = (iap->ia_mode & S_IALLUGO) | type; + err = nfserr_inval; + if (!S_ISREG(type) && !S_ISDIR(type) && !special_file(type)) { + printk(KERN_WARNING "nfsd: bad file type %o in nfsd_create\n", + type); + goto out; + } + + host_err = mnt_want_write(fhp->fh_export->ex_path.mnt); + if (host_err) + goto out_nfserr; + /* * Get the dir op function pointer. */ err = 0; switch (type) { case S_IFREG: - host_err = mnt_want_write(fhp->fh_export->ex_path.mnt); - if (host_err) - goto out_nfserr; host_err = vfs_create(dirp, dchild, iap->ia_mode, NULL); break; case S_IFDIR: - host_err = mnt_want_write(fhp->fh_export->ex_path.mnt); - if (host_err) - goto out_nfserr; host_err = vfs_mkdir(dirp, dchild, iap->ia_mode); break; case S_IFCHR: case S_IFBLK: case S_IFIFO: case S_IFSOCK: - host_err = mnt_want_write(fhp->fh_export->ex_path.mnt); - if (host_err) - goto out_nfserr; host_err = vfs_mknod(dirp, dchild, iap->ia_mode, rdev); break; - default: - printk("nfsd: bad file type %o in nfsd_create\n", type); - host_err = -EINVAL; - goto out_nfserr; } if (host_err < 0) { mnt_drop_write(fhp->fh_export->ex_path.mnt); @@ -1289,7 +1289,6 @@ nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp, write_inode_now(dchild->d_inode, 1); } - err2 = nfsd_create_setattr(rqstp, resfhp, iap); if (err2) err = err2; @@ -1334,7 +1333,7 @@ nfsd_create_v3(struct svc_rqst *rqstp, struct svc_fh *fhp, goto out; if (!(iap->ia_valid & ATTR_MODE)) iap->ia_mode = 0; - err = fh_verify(rqstp, fhp, S_IFDIR, MAY_CREATE); + err = fh_verify(rqstp, fhp, S_IFDIR, NFSD_MAY_CREATE); if (err) goto out; @@ -1471,7 +1470,7 @@ nfsd_readlink(struct svc_rqst *rqstp, struct svc_fh *fhp, char *buf, int *lenp) __be32 err; int host_err; - err = fh_verify(rqstp, fhp, S_IFLNK, MAY_NOP); + err = fh_verify(rqstp, fhp, S_IFLNK, NFSD_MAY_NOP); if (err) goto out; @@ -1526,7 +1525,7 @@ nfsd_symlink(struct svc_rqst *rqstp, struct svc_fh *fhp, if (isdotent(fname, flen)) goto out; - err = fh_verify(rqstp, fhp, S_IFDIR, MAY_CREATE); + err = fh_verify(rqstp, fhp, S_IFDIR, NFSD_MAY_CREATE); if (err) goto out; fh_lock(fhp); @@ -1591,10 +1590,10 @@ nfsd_link(struct svc_rqst *rqstp, struct svc_fh *ffhp, __be32 err; int host_err; - err = fh_verify(rqstp, ffhp, S_IFDIR, MAY_CREATE); + err = fh_verify(rqstp, ffhp, S_IFDIR, NFSD_MAY_CREATE); if (err) goto out; - err = fh_verify(rqstp, tfhp, -S_IFDIR, MAY_NOP); + err = fh_verify(rqstp, tfhp, -S_IFDIR, NFSD_MAY_NOP); if (err) goto out; @@ -1661,10 +1660,10 @@ nfsd_rename(struct svc_rqst *rqstp, struct svc_fh *ffhp, char *fname, int flen, __be32 err; int host_err; - err = fh_verify(rqstp, ffhp, S_IFDIR, MAY_REMOVE); + err = fh_verify(rqstp, ffhp, S_IFDIR, NFSD_MAY_REMOVE); if (err) goto out; - err = fh_verify(rqstp, tfhp, S_IFDIR, MAY_CREATE); + err = fh_verify(rqstp, tfhp, S_IFDIR, NFSD_MAY_CREATE); if (err) goto out; @@ -1768,7 +1767,7 @@ nfsd_unlink(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, err = nfserr_acces; if (!flen || isdotent(fname, flen)) goto out; - err = fh_verify(rqstp, fhp, S_IFDIR, MAY_REMOVE); + err = fh_verify(rqstp, fhp, S_IFDIR, NFSD_MAY_REMOVE); if (err) goto out; @@ -1834,7 +1833,7 @@ nfsd_readdir(struct svc_rqst *rqstp, struct svc_fh *fhp, loff_t *offsetp, struct file *file; loff_t offset = *offsetp; - err = nfsd_open(rqstp, fhp, S_IFDIR, MAY_READ, &file); + err = nfsd_open(rqstp, fhp, S_IFDIR, NFSD_MAY_READ, &file); if (err) goto out; @@ -1875,7 +1874,7 @@ out: __be32 nfsd_statfs(struct svc_rqst *rqstp, struct svc_fh *fhp, struct kstatfs *stat) { - __be32 err = fh_verify(rqstp, fhp, 0, MAY_NOP); + __be32 err = fh_verify(rqstp, fhp, 0, NFSD_MAY_NOP); if (!err && vfs_statfs(fhp->fh_dentry,stat)) err = nfserr_io; return err; @@ -1896,18 +1895,18 @@ nfsd_permission(struct svc_rqst *rqstp, struct svc_export *exp, struct inode *inode = dentry->d_inode; int err; - if (acc == MAY_NOP) + if (acc == NFSD_MAY_NOP) return 0; #if 0 dprintk("nfsd: permission 0x%x%s%s%s%s%s%s%s mode 0%o%s%s%s\n", acc, - (acc & MAY_READ)? " read" : "", - (acc & MAY_WRITE)? " write" : "", - (acc & MAY_EXEC)? " exec" : "", - (acc & MAY_SATTR)? " sattr" : "", - (acc & MAY_TRUNC)? " trunc" : "", - (acc & MAY_LOCK)? " lock" : "", - (acc & MAY_OWNER_OVERRIDE)? " owneroverride" : "", + (acc & NFSD_MAY_READ)? " read" : "", + (acc & NFSD_MAY_WRITE)? " write" : "", + (acc & NFSD_MAY_EXEC)? " exec" : "", + (acc & NFSD_MAY_SATTR)? " sattr" : "", + (acc & NFSD_MAY_TRUNC)? " trunc" : "", + (acc & NFSD_MAY_LOCK)? " lock" : "", + (acc & NFSD_MAY_OWNER_OVERRIDE)? " owneroverride" : "", inode->i_mode, IS_IMMUTABLE(inode)? " immut" : "", IS_APPEND(inode)? " append" : "", @@ -1920,18 +1919,18 @@ nfsd_permission(struct svc_rqst *rqstp, struct svc_export *exp, * system. But if it is IRIX doing check on write-access for a * device special file, we ignore rofs. */ - if (!(acc & MAY_LOCAL_ACCESS)) - if (acc & (MAY_WRITE | MAY_SATTR | MAY_TRUNC)) { + if (!(acc & NFSD_MAY_LOCAL_ACCESS)) + if (acc & (NFSD_MAY_WRITE | NFSD_MAY_SATTR | NFSD_MAY_TRUNC)) { if (exp_rdonly(rqstp, exp) || __mnt_is_readonly(exp->ex_path.mnt)) return nfserr_rofs; - if (/* (acc & MAY_WRITE) && */ IS_IMMUTABLE(inode)) + if (/* (acc & NFSD_MAY_WRITE) && */ IS_IMMUTABLE(inode)) return nfserr_perm; } - if ((acc & MAY_TRUNC) && IS_APPEND(inode)) + if ((acc & NFSD_MAY_TRUNC) && IS_APPEND(inode)) return nfserr_perm; - if (acc & MAY_LOCK) { + if (acc & NFSD_MAY_LOCK) { /* If we cannot rely on authentication in NLM requests, * just allow locks, otherwise require read permission, or * ownership @@ -1939,7 +1938,7 @@ nfsd_permission(struct svc_rqst *rqstp, struct svc_export *exp, if (exp->ex_flags & NFSEXP_NOAUTHNLM) return 0; else - acc = MAY_READ | MAY_OWNER_OVERRIDE; + acc = NFSD_MAY_READ | NFSD_MAY_OWNER_OVERRIDE; } /* * The file owner always gets access permission for accesses that @@ -1955,15 +1954,16 @@ nfsd_permission(struct svc_rqst *rqstp, struct svc_export *exp, * We must trust the client to do permission checking - using "ACCESS" * with NFSv3. */ - if ((acc & MAY_OWNER_OVERRIDE) && + if ((acc & NFSD_MAY_OWNER_OVERRIDE) && inode->i_uid == current->fsuid) return 0; + /* This assumes NFSD_MAY_{READ,WRITE,EXEC} == MAY_{READ,WRITE,EXEC} */ err = permission(inode, acc & (MAY_READ|MAY_WRITE|MAY_EXEC), NULL); /* Allow read access to binaries even when mode 111 */ if (err == -EACCES && S_ISREG(inode->i_mode) && - acc == (MAY_READ | MAY_OWNER_OVERRIDE)) + acc == (NFSD_MAY_READ | NFSD_MAY_OWNER_OVERRIDE)) err = permission(inode, MAY_EXEC, NULL); return err? nfserrno(err) : 0; diff --git a/fs/ocfs2/cluster/heartbeat.c b/fs/ocfs2/cluster/heartbeat.c index 443d108211ab..7dce1612553e 100644 --- a/fs/ocfs2/cluster/heartbeat.c +++ b/fs/ocfs2/cluster/heartbeat.c @@ -1489,31 +1489,22 @@ static struct o2hb_heartbeat_group *to_o2hb_heartbeat_group(struct config_group : NULL; } -static int o2hb_heartbeat_group_make_item(struct config_group *group, - const char *name, - struct config_item **new_item) +static struct config_item *o2hb_heartbeat_group_make_item(struct config_group *group, + const char *name) { struct o2hb_region *reg = NULL; - int ret = 0; reg = kzalloc(sizeof(struct o2hb_region), GFP_KERNEL); - if (reg == NULL) { - ret = -ENOMEM; - goto out; - } + if (reg == NULL) + return ERR_PTR(-ENOMEM); config_item_init_type_name(®->hr_item, name, &o2hb_region_type); - *new_item = ®->hr_item; - spin_lock(&o2hb_live_lock); list_add_tail(®->hr_all_item, &o2hb_all_regions); spin_unlock(&o2hb_live_lock); -out: - if (ret) - kfree(reg); - return ret; + return ®->hr_item; } static void o2hb_heartbeat_group_drop_item(struct config_group *group, diff --git a/fs/ocfs2/cluster/nodemanager.c b/fs/ocfs2/cluster/nodemanager.c index b364b7052e46..816a3f61330c 100644 --- a/fs/ocfs2/cluster/nodemanager.c +++ b/fs/ocfs2/cluster/nodemanager.c @@ -644,35 +644,23 @@ out: return ret; } -static int o2nm_node_group_make_item(struct config_group *group, - const char *name, - struct config_item **new_item) +static struct config_item *o2nm_node_group_make_item(struct config_group *group, + const char *name) { struct o2nm_node *node = NULL; - int ret = 0; - if (strlen(name) > O2NM_MAX_NAME_LEN) { - ret = -ENAMETOOLONG; - goto out; - } + if (strlen(name) > O2NM_MAX_NAME_LEN) + return ERR_PTR(-ENAMETOOLONG); node = kzalloc(sizeof(struct o2nm_node), GFP_KERNEL); - if (node == NULL) { - ret = -ENOMEM; - goto out; - } + if (node == NULL) + return ERR_PTR(-ENOMEM); strcpy(node->nd_name, name); /* use item.ci_namebuf instead? */ config_item_init_type_name(&node->nd_item, name, &o2nm_node_type); spin_lock_init(&node->nd_lock); - *new_item = &node->nd_item; - -out: - if (ret) - kfree(node); - - return ret; + return &node->nd_item; } static void o2nm_node_group_drop_item(struct config_group *group, @@ -756,31 +744,25 @@ static struct o2nm_cluster_group *to_o2nm_cluster_group(struct config_group *gro } #endif -static int o2nm_cluster_group_make_group(struct config_group *group, - const char *name, - struct config_group **new_group) +static struct config_group *o2nm_cluster_group_make_group(struct config_group *group, + const char *name) { struct o2nm_cluster *cluster = NULL; struct o2nm_node_group *ns = NULL; - struct config_group *o2hb_group = NULL; + struct config_group *o2hb_group = NULL, *ret = NULL; void *defs = NULL; - int ret = 0; /* this runs under the parent dir's i_mutex; there can be only * one caller in here at a time */ - if (o2nm_single_cluster) { - ret = -ENOSPC; - goto out; - } + if (o2nm_single_cluster) + return ERR_PTR(-ENOSPC); cluster = kzalloc(sizeof(struct o2nm_cluster), GFP_KERNEL); ns = kzalloc(sizeof(struct o2nm_node_group), GFP_KERNEL); defs = kcalloc(3, sizeof(struct config_group *), GFP_KERNEL); o2hb_group = o2hb_alloc_hb_set(); - if (cluster == NULL || ns == NULL || o2hb_group == NULL || defs == NULL) { - ret = -ENOMEM; + if (cluster == NULL || ns == NULL || o2hb_group == NULL || defs == NULL) goto out; - } config_group_init_type_name(&cluster->cl_group, name, &o2nm_cluster_type); @@ -797,15 +779,16 @@ static int o2nm_cluster_group_make_group(struct config_group *group, cluster->cl_idle_timeout_ms = O2NET_IDLE_TIMEOUT_MS_DEFAULT; cluster->cl_keepalive_delay_ms = O2NET_KEEPALIVE_DELAY_MS_DEFAULT; - *new_group = &cluster->cl_group; + ret = &cluster->cl_group; o2nm_single_cluster = cluster; out: - if (ret) { + if (ret == NULL) { kfree(cluster); kfree(ns); o2hb_free_hb_set(o2hb_group); kfree(defs); + ret = ERR_PTR(-ENOMEM); } return ret; diff --git a/fs/proc/proc_net.c b/fs/proc/proc_net.c index 83f357b30d71..b224a28e0c15 100644 --- a/fs/proc/proc_net.c +++ b/fs/proc/proc_net.c @@ -51,6 +51,30 @@ int seq_open_net(struct inode *ino, struct file *f, } EXPORT_SYMBOL_GPL(seq_open_net); +int single_open_net(struct inode *inode, struct file *file, + int (*show)(struct seq_file *, void *)) +{ + int err; + struct net *net; + + err = -ENXIO; + net = get_proc_net(inode); + if (net == NULL) + goto err_net; + + err = single_open(file, show, net); + if (err < 0) + goto err_open; + + return 0; + +err_open: + put_net(net); +err_net: + return err; +} +EXPORT_SYMBOL_GPL(single_open_net); + int seq_release_net(struct inode *ino, struct file *f) { struct seq_file *seq; @@ -63,6 +87,14 @@ int seq_release_net(struct inode *ino, struct file *f) } EXPORT_SYMBOL_GPL(seq_release_net); +int single_release_net(struct inode *ino, struct file *f) +{ + struct seq_file *seq = f->private_data; + put_net(seq->private); + return single_release(ino, f); +} +EXPORT_SYMBOL_GPL(single_release_net); + static struct net *get_proc_task_net(struct inode *dir) { struct task_struct *task; diff --git a/fs/proc/proc_tty.c b/fs/proc/proc_tty.c index 21f490f5d65c..d153946d6d15 100644 --- a/fs/proc/proc_tty.c +++ b/fs/proc/proc_tty.c @@ -136,54 +136,6 @@ static const struct file_operations proc_tty_drivers_operations = { .release = seq_release, }; -static void * tty_ldiscs_seq_start(struct seq_file *m, loff_t *pos) -{ - return (*pos < NR_LDISCS) ? pos : NULL; -} - -static void * tty_ldiscs_seq_next(struct seq_file *m, void *v, loff_t *pos) -{ - (*pos)++; - return (*pos < NR_LDISCS) ? pos : NULL; -} - -static void tty_ldiscs_seq_stop(struct seq_file *m, void *v) -{ -} - -static int tty_ldiscs_seq_show(struct seq_file *m, void *v) -{ - int i = *(loff_t *)v; - struct tty_ldisc *ld; - - ld = tty_ldisc_get(i); - if (ld == NULL) - return 0; - seq_printf(m, "%-10s %2d\n", ld->name ? ld->name : "???", i); - tty_ldisc_put(i); - return 0; -} - -static const struct seq_operations tty_ldiscs_seq_ops = { - .start = tty_ldiscs_seq_start, - .next = tty_ldiscs_seq_next, - .stop = tty_ldiscs_seq_stop, - .show = tty_ldiscs_seq_show, -}; - -static int proc_tty_ldiscs_open(struct inode *inode, struct file *file) -{ - return seq_open(file, &tty_ldiscs_seq_ops); -} - -static const struct file_operations tty_ldiscs_proc_fops = { - .owner = THIS_MODULE, - .open = proc_tty_ldiscs_open, - .read = seq_read, - .llseek = seq_lseek, - .release = seq_release, -}; - /* * This function is called by tty_register_driver() to handle * registering the driver's /proc handler into /proc/tty/driver/<foo> diff --git a/include/asm-avr32/ioctls.h b/include/asm-avr32/ioctls.h index 0500426b7186..0cf2c0a4502b 100644 --- a/include/asm-avr32/ioctls.h +++ b/include/asm-avr32/ioctls.h @@ -47,6 +47,10 @@ #define TIOCSBRK 0x5427 /* BSD compatibility */ #define TIOCCBRK 0x5428 /* BSD compatibility */ #define TIOCGSID 0x5429 /* Return the session ID of FD */ +#define TCGETS2 _IOR('T',0x2A, struct termios2) +#define TCSETS2 _IOW('T',0x2B, struct termios2) +#define TCSETSW2 _IOW('T',0x2C, struct termios2) +#define TCSETSF2 _IOW('T',0x2D, struct termios2) #define TIOCGPTN _IOR('T',0x30, unsigned int) /* Get Pty Number (of pty-mux device) */ #define TIOCSPTLCK _IOW('T',0x31, int) /* Lock/unlock Pty */ diff --git a/include/asm-cris/Kbuild b/include/asm-cris/Kbuild index 17455459c43f..b7037d80d461 100644 --- a/include/asm-cris/Kbuild +++ b/include/asm-cris/Kbuild @@ -1,7 +1,8 @@ include include/asm-generic/Kbuild.asm -header-$(CONFIG_ETRAX_ARCH_V10) += arch-v10/ -header-$(CONFIG_ETRAX_ARCH_V32) += arch-v32/ +header-y += arch/ +header-y += arch-v10/ +header-y += arch-v32/ header-y += ethernet.h header-y += rtc.h diff --git a/include/asm-frv/ioctls.h b/include/asm-frv/ioctls.h index 341c7ddef2a3..d0c30e31fbda 100644 --- a/include/asm-frv/ioctls.h +++ b/include/asm-frv/ioctls.h @@ -47,6 +47,10 @@ #define TIOCSBRK 0x5427 /* BSD compatibility */ #define TIOCCBRK 0x5428 /* BSD compatibility */ #define TIOCGSID 0x5429 /* Return the session ID of FD */ +#define TCGETS2 _IOR('T',0x2A, struct termios2) +#define TCSETS2 _IOW('T',0x2B, struct termios2) +#define TCSETSW2 _IOW('T',0x2C, struct termios2) +#define TCSETSF2 _IOW('T',0x2D, struct termios2) #define TIOCGPTN _IOR('T',0x30, unsigned int) /* Get Pty Number (of pty-mux device) */ #define TIOCSPTLCK _IOW('T',0x31, int) /* Lock/unlock Pty */ diff --git a/include/asm-frv/termbits.h b/include/asm-frv/termbits.h index 74851b424d4f..5568492b5086 100644 --- a/include/asm-frv/termbits.h +++ b/include/asm-frv/termbits.h @@ -141,6 +141,7 @@ struct ktermios { #define HUPCL 0002000 #define CLOCAL 0004000 #define CBAUDEX 0010000 +#define BOTHER 0010000 #define B57600 0010001 #define B115200 0010002 #define B230400 0010003 @@ -156,11 +157,13 @@ struct ktermios { #define B3000000 0010015 #define B3500000 0010016 #define B4000000 0010017 -#define CIBAUD 002003600000 /* input baud rate (not used) */ +#define CIBAUD 002003600000 /* Input baud rate */ #define CTVB 004000000000 /* VisioBraille Terminal flow control */ #define CMSPAR 010000000000 /* mark or space (stick) parity */ #define CRTSCTS 020000000000 /* flow control */ +#define IBSHIFT 16 /* Shift from CBAUD to CIBAUD */ + /* c_lflag bits */ #define ISIG 0000001 #define ICANON 0000002 diff --git a/include/asm-ia64/kvm_host.h b/include/asm-ia64/kvm_host.h index c082c208c1f3..1efe513a9941 100644 --- a/include/asm-ia64/kvm_host.h +++ b/include/asm-ia64/kvm_host.h @@ -38,6 +38,7 @@ /* memory slots that does not exposed to userspace */ #define KVM_PRIVATE_MEM_SLOTS 4 +#define KVM_COALESCED_MMIO_PAGE_OFFSET 1 /* define exit reasons from vmm to kvm*/ #define EXIT_REASON_VM_PANIC 0 @@ -521,4 +522,6 @@ int kvm_emulate_halt(struct kvm_vcpu *vcpu); int kvm_pal_emul(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run); void kvm_sal_emul(struct kvm_vcpu *vcpu); +static inline void kvm_inject_nmi(struct kvm_vcpu *vcpu) {} + #endif diff --git a/include/asm-m68k/amigahw.h b/include/asm-m68k/amigahw.h index a16fe4e5a28a..5ca5dd951a4a 100644 --- a/include/asm-m68k/amigahw.h +++ b/include/asm-m68k/amigahw.h @@ -22,8 +22,6 @@ * Different Amiga models */ -extern unsigned long amiga_model; - #define AMI_UNKNOWN (0) #define AMI_500 (1) #define AMI_500PLUS (2) @@ -59,11 +57,9 @@ extern unsigned long amiga_chipset; */ extern unsigned long amiga_eclock; /* 700 kHz E Peripheral Clock */ -extern unsigned long amiga_masterclock; /* 28 MHz Master Clock */ extern unsigned long amiga_colorclock; /* 3.5 MHz Color Clock */ extern unsigned long amiga_chip_size; /* Chip RAM Size (bytes) */ extern unsigned char amiga_vblank; /* VBLANK Frequency */ -extern unsigned char amiga_psfreq; /* Power Supply Frequency */ #define AMIGAHW_DECLARE(name) unsigned name : 1 diff --git a/include/asm-m68k/amigaints.h b/include/asm-m68k/amigaints.h index 7c8713468fd2..b1bcdb835ab9 100644 --- a/include/asm-m68k/amigaints.h +++ b/include/asm-m68k/amigaints.h @@ -98,6 +98,8 @@ #define CIA_ICR_ALL 0x1f #define CIA_ICR_SETCLR 0x80 +extern void amiga_init_IRQ(void); + /* to access the interrupt control registers of CIA's use only ** these functions, they behave exactly like the amiga os routines */ diff --git a/include/asm-m68k/apollodma.h b/include/asm-m68k/apollodma.h index 6821e3ba32e9..954adc851adb 100644 --- a/include/asm-m68k/apollodma.h +++ b/include/asm-m68k/apollodma.h @@ -1,4 +1,4 @@ -/* $Id: dma.h,v 1.7 1992/12/14 00:29:34 root Exp root $ +/* * linux/include/asm/dma.h: Defines for using and allocating dma channels. * Written by Hennus Bergman, 1992. * High DMA channel support & info by Hannu Savolainen diff --git a/include/asm-m68k/dvma.h b/include/asm-m68k/dvma.h index e1112de5a5e3..4fff408d0150 100644 --- a/include/asm-m68k/dvma.h +++ b/include/asm-m68k/dvma.h @@ -1,4 +1,4 @@ -/* $Id: dvma.h,v 1.4 1999/03/27 20:23:41 tsbogend Exp $ +/* * include/asm-m68k/dma.h * * Copyright 1995 (C) David S. Miller (davem@caip.rutgers.edu) @@ -63,8 +63,6 @@ static inline int dvma_map_cpu(unsigned long kaddr, unsigned long vaddr, return 0; } -extern unsigned long dvma_page(unsigned long kaddr, unsigned long vaddr); - #else /* Sun3x */ /* sun3x dvma page support */ diff --git a/include/asm-m68k/fpu.h b/include/asm-m68k/fpu.h index 59701d7b4e78..ffb6b8cfc6d5 100644 --- a/include/asm-m68k/fpu.h +++ b/include/asm-m68k/fpu.h @@ -7,15 +7,15 @@ */ #if defined(CONFIG_M68020) || defined(CONFIG_M68030) -#define FPSTATESIZE (216/sizeof(unsigned char)) +#define FPSTATESIZE (216) #elif defined(CONFIG_M68040) -#define FPSTATESIZE (96/sizeof(unsigned char)) +#define FPSTATESIZE (96) #elif defined(CONFIG_M68KFPU_EMU) -#define FPSTATESIZE (28/sizeof(unsigned char)) +#define FPSTATESIZE (28) #elif defined(CONFIG_M68060) -#define FPSTATESIZE (12/sizeof(unsigned char)) +#define FPSTATESIZE (12) #else -#define FPSTATESIZE error no_cpu_type_configured +#define FPSTATESIZE (0) #endif #endif /* __M68K_FPU_H */ diff --git a/include/asm-m68k/irq.h b/include/asm-m68k/irq.h index eb29a5260591..226bfc0f21b1 100644 --- a/include/asm-m68k/irq.h +++ b/include/asm-m68k/irq.h @@ -24,7 +24,7 @@ #elif defined(CONFIG_HP300) #define NR_IRQS 8 #else -#error unknown nr of irqs +#define NR_IRQS 0 #endif /* diff --git a/include/asm-m68k/mac_baboon.h b/include/asm-m68k/mac_baboon.h index e87850830be8..c2a042b8c349 100644 --- a/include/asm-m68k/mac_baboon.h +++ b/include/asm-m68k/mac_baboon.h @@ -29,6 +29,4 @@ struct baboon { */ }; -extern volatile struct baboon *baboon; - #endif /* __ASSEMBLY **/ diff --git a/include/asm-m68k/mac_via.h b/include/asm-m68k/mac_via.h index 59b758cd16ad..39afb438b656 100644 --- a/include/asm-m68k/mac_via.h +++ b/include/asm-m68k/mac_via.h @@ -253,7 +253,6 @@ extern volatile __u8 *via1,*via2; extern int rbv_present,via_alt_mapping; -extern __u8 rbv_clear; static inline int rbv_set_video_bpp(int bpp) { diff --git a/include/asm-m68k/machines.h b/include/asm-m68k/machines.h index da6015a90f24..be667e84f01b 100644 --- a/include/asm-m68k/machines.h +++ b/include/asm-m68k/machines.h @@ -1,4 +1,4 @@ -/* $Id: machines.h,v 1.4 1995/11/25 02:31:58 davem Exp $ +/* * machines.h: Defines for taking apart the machine type value in the * idprom and determining the kind of machine we are on. * @@ -21,8 +21,6 @@ struct Sun_Machine_Models { //#define NUM_SUN_MACHINES 23 #define NUM_SUN_MACHINES 8 -extern struct Sun_Machine_Models Sun_Machines[NUM_SUN_MACHINES]; - /* The machine type in the idprom area looks like this: * * --------------- diff --git a/include/asm-m68k/macintosh.h b/include/asm-m68k/macintosh.h index 28b0f49ee521..05309f7e3d06 100644 --- a/include/asm-m68k/macintosh.h +++ b/include/asm-m68k/macintosh.h @@ -12,8 +12,6 @@ extern void mac_reset(void); extern void mac_poweroff(void); extern void mac_init_IRQ(void); extern int mac_irq_pending(unsigned int); -extern void mac_identify(void); -extern void mac_report_hardware(void); /* * Floppy driver magic hook - probably shouldnt be here @@ -21,9 +19,6 @@ extern void mac_report_hardware(void); extern void via1_set_head(int); -extern void parse_booter(char *ptr); -extern void print_booter(char *ptr); - /* * Macintosh Table */ diff --git a/include/asm-m68k/md.h b/include/asm-m68k/md.h index 467ea08383e4..d2f78f226f3d 100644 --- a/include/asm-m68k/md.h +++ b/include/asm-m68k/md.h @@ -1,4 +1,4 @@ -/* $Id: md.h,v 1.1 1997/12/15 15:12:04 jj Exp $ +/* * md.h: High speed xor_block operation for RAID4/5 * */ diff --git a/include/asm-m68k/openprom.h b/include/asm-m68k/openprom.h index 869ab9176e9f..d33cdadf78e1 100644 --- a/include/asm-m68k/openprom.h +++ b/include/asm-m68k/openprom.h @@ -1,4 +1,3 @@ -/* $Id: openprom.h,v 1.19 1996/09/25 03:51:08 davem Exp $ */ #ifndef __SPARC_OPENPROM_H #define __SPARC_OPENPROM_H diff --git a/include/asm-m68k/oplib.h b/include/asm-m68k/oplib.h index 06caa2d08451..f082d03336bd 100644 --- a/include/asm-m68k/oplib.h +++ b/include/asm-m68k/oplib.h @@ -1,4 +1,4 @@ -/* $Id: oplib.h,v 1.12 1996/10/31 06:29:13 davem Exp $ +/* * oplib.h: Describes the interface and available routines in the * Linux Prom library. * @@ -19,7 +19,6 @@ enum prom_major_version { PROM_V2, /* sun4c and early sun4m V2 prom */ PROM_V3, /* sun4m and later, up to sun4d/sun4e machines V3 */ PROM_P1275, /* IEEE compliant ISA based Sun PROM, only sun4u */ - PROM_AP1000, /* actually no prom at all */ }; extern enum prom_major_version prom_vers; diff --git a/include/asm-m68k/sbus.h b/include/asm-m68k/sbus.h index 3b25c0040aa6..bfe3ba147f2e 100644 --- a/include/asm-m68k/sbus.h +++ b/include/asm-m68k/sbus.h @@ -12,11 +12,6 @@ struct sbus_dev { } reg_addrs[1]; }; -extern void *sparc_alloc_io (u32, void *, int, char *, u32, int); -#define sparc_alloc_io(a,b,c,d,e,f) (a) - -#define ARCH_SUN4 0 - /* sbus IO functions stolen from include/asm-sparc/io.h for the serial driver */ /* No SBUS on the Sun3, kludge -- sam */ diff --git a/include/asm-m68k/sun3-head.h b/include/asm-m68k/sun3-head.h index e74f384e269f..05af2f18b3bd 100644 --- a/include/asm-m68k/sun3-head.h +++ b/include/asm-m68k/sun3-head.h @@ -1,4 +1,3 @@ -/* $Id: head.h,v 1.32 1996/12/04 00:12:48 ecd Exp $ */ #ifndef __SUN3_HEAD_H #define __SUN3_HEAD_H diff --git a/include/asm-m68k/tlbflush.h b/include/asm-m68k/tlbflush.h index 17707ec315e2..acb6bf21a321 100644 --- a/include/asm-m68k/tlbflush.h +++ b/include/asm-m68k/tlbflush.h @@ -16,7 +16,7 @@ static inline void flush_tlb_kernel_page(void *addr) ".chip 68k" : : "a" (addr)); set_fs(old_fs); - } else + } else if (CPU_IS_020_OR_030) __asm__ __volatile__("pflush #4,#4,(%0)" : : "a" (addr)); } @@ -29,7 +29,7 @@ static inline void __flush_tlb(void) __asm__ __volatile__(".chip 68040\n\t" "pflushan\n\t" ".chip 68k"); - else + else if (CPU_IS_020_OR_030) __asm__ __volatile__("pflush #0,#4"); } @@ -45,7 +45,7 @@ static inline void __flush_tlb_one(unsigned long addr) { if (CPU_IS_040_OR_060) __flush_tlb040_one(addr); - else + else if (CPU_IS_020_OR_030) __asm__ __volatile__("pflush #0,#4,(%0)" : : "a" (addr)); } @@ -60,7 +60,7 @@ static inline void flush_tlb_all(void) __asm__ __volatile__(".chip 68040\n\t" "pflusha\n\t" ".chip 68k"); - else + else if (CPU_IS_020_OR_030) __asm__ __volatile__("pflusha"); } diff --git a/include/asm-mips/bitops.h b/include/asm-mips/bitops.h index 9a7274ba6a0b..49df8c4c9d25 100644 --- a/include/asm-mips/bitops.h +++ b/include/asm-mips/bitops.h @@ -82,7 +82,7 @@ static inline void set_bit(unsigned long nr, volatile unsigned long *addr) "2: b 1b \n" " .previous \n" : "=&r" (temp), "=m" (*m) - : "i" (bit), "m" (*m), "r" (~0)); + : "ir" (bit), "m" (*m), "r" (~0)); #endif /* CONFIG_CPU_MIPSR2 */ } else if (cpu_has_llsc) { __asm__ __volatile__( @@ -147,7 +147,7 @@ static inline void clear_bit(unsigned long nr, volatile unsigned long *addr) "2: b 1b \n" " .previous \n" : "=&r" (temp), "=m" (*m) - : "i" (bit), "m" (*m)); + : "ir" (bit), "m" (*m)); #endif /* CONFIG_CPU_MIPSR2 */ } else if (cpu_has_llsc) { __asm__ __volatile__( @@ -428,7 +428,7 @@ static inline int test_and_clear_bit(unsigned long nr, "2: b 1b \n" " .previous \n" : "=&r" (temp), "=m" (*m), "=&r" (res) - : "i" (bit), "m" (*m) + : "ir" (bit), "m" (*m) : "memory"); #endif } else if (cpu_has_llsc) { diff --git a/include/asm-mips/bootinfo.h b/include/asm-mips/bootinfo.h index d39e143b4a3c..610fe3af7a03 100644 --- a/include/asm-mips/bootinfo.h +++ b/include/asm-mips/bootinfo.h @@ -51,6 +51,12 @@ #define MACH_MSP7120_FPGA 5 /* PMC-Sierra MSP7120 Emulation */ #define MACH_MSP_OTHER 255 /* PMC-Sierra unknown board type */ +/* + * Valid machtype for group Mikrotik + */ +#define MACH_MIKROTIK_RB532 0 /* Mikrotik RouterBoard 532 */ +#define MACH_MIKROTIK_RB532A 1 /* Mikrotik RouterBoard 532A */ + #define CL_SIZE COMMAND_LINE_SIZE extern char *system_type; diff --git a/include/asm-mips/fpu.h b/include/asm-mips/fpu.h index e59d4c039661..8a3ef247659a 100644 --- a/include/asm-mips/fpu.h +++ b/include/asm-mips/fpu.h @@ -35,6 +35,8 @@ extern asmlinkage int (*save_fp_context32)(struct sigcontext32 __user *sc); extern asmlinkage int (*restore_fp_context32)(struct sigcontext32 __user *sc); extern void fpu_emulator_init_fpu(void); +extern int fpu_emulator_save_context(struct sigcontext __user *sc); +extern int fpu_emulator_restore_context(struct sigcontext __user *sc); extern void _init_fpu(void); extern void _save_fp(struct task_struct *); extern void _restore_fp(struct task_struct *); diff --git a/include/asm-mips/mach-rc32434/cpu-feature-overrides.h b/include/asm-mips/mach-rc32434/cpu-feature-overrides.h new file mode 100644 index 000000000000..f3bc7efa2608 --- /dev/null +++ b/include/asm-mips/mach-rc32434/cpu-feature-overrides.h @@ -0,0 +1,81 @@ +/* + * IDT RC32434 specific CPU feature overrides + * + * Copyright (C) 2008 Florian Fainelli <florian@openwrt.org> + * + * This file was derived from: include/asm-mips/cpu-features.h + * Copyright (C) 2003, 2004 Ralf Baechle + * Copyright (C) 2004 Maciej W. Rozycki + * + * 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 Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ +#ifndef __ASM_MACH_RC32434_CPU_FEATURE_OVERRIDES_H +#define __ASM_MACH_RC32434_CPU_FEATURE_OVERRIDES_H + +/* + * The IDT RC32434 SOC has a built-in MIPS 4Kc core. + */ +#define cpu_has_tlb 1 +#define cpu_has_4kex 1 +#define cpu_has_3k_cache 0 +#define cpu_has_4k_cache 1 +#define cpu_has_tx39_cache 0 +#define cpu_has_sb1_cache 0 +#define cpu_has_fpu 0 +#define cpu_has_32fpr 0 +#define cpu_has_counter 1 +#define cpu_has_watch 1 +#define cpu_has_divec 1 +#define cpu_has_vce 0 +#define cpu_has_cache_cdex_p 0 +#define cpu_has_cache_cdex_s 0 +#define cpu_has_prefetch 1 +#define cpu_has_mcheck 1 +#define cpu_has_ejtag 1 +#define cpu_has_llsc 1 + +#define cpu_has_mips16 0 +#define cpu_has_mdmx 0 +#define cpu_has_mips3d 0 +#define cpu_has_smartmips 0 + +#define cpu_has_vtag_icache 0 +/* #define cpu_has_dc_aliases ? */ +/* #define cpu_has_ic_fills_f_dc ? */ +/* #define cpu_has_pindexed_dcache ? */ + +/* #define cpu_icache_snoops_remote_store ? */ + +#define cpu_has_mips32r1 1 +#define cpu_has_mips32r2 0 +#define cpu_has_mips64r1 0 +#define cpu_has_mips64r2 0 + +#define cpu_has_dsp 0 +#define cpu_has_mipsmt 0 + +/* #define cpu_has_nofpuex ? */ +#define cpu_has_64bits 0 +#define cpu_has_64bit_zero_reg 0 +#define cpu_has_64bit_gp_regs 0 +#define cpu_has_64bit_addresses 0 + +#define cpu_has_inclusive_pcaches 0 + +#define cpu_dcache_line_size() 16 +#define cpu_icache_line_size() 16 + +#endif /* __ASM_MACH_RC32434_CPU_FEATURE_OVERRIDES_H */ diff --git a/include/asm-mips/mach-rc32434/ddr.h b/include/asm-mips/mach-rc32434/ddr.h new file mode 100644 index 000000000000..291e2cf9dde0 --- /dev/null +++ b/include/asm-mips/mach-rc32434/ddr.h @@ -0,0 +1,141 @@ +/* + * Definitions for the DDR registers + * + * Copyright 2002 Ryan Holm <ryan.holmQVist@idt.com> + * Copyright 2008 Florian Fainelli <florian@openwrt.org> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * THIS SOFTWARE IS PROVIDED ``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 AUTHOR 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. + * + * 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 _ASM_RC32434_DDR_H_ +#define _ASM_RC32434_DDR_H_ + +#include <asm/mach-rc32434/rb.h> + +/* DDR register structure */ +struct ddr_ram { + u32 ddrbase; + u32 ddrmask; + u32 res1; + u32 res2; + u32 ddrc; + u32 ddrabase; + u32 ddramask; + u32 ddramap; + u32 ddrcust; + u32 ddrrdc; + u32 ddrspare; +}; + +#define DDR0_PHYS_ADDR 0x18018000 + +/* DDR banks masks */ +#define DDR_MASK 0xffff0000 +#define DDR0_BASE_MSK DDR_MASK +#define DDR1_BASE_MSK DDR_MASK + +/* DDR bank0 registers */ +#define RC32434_DDR0_ATA_BIT 5 +#define RC32434_DDR0_ATA_MSK 0x000000E0 +#define RC32434_DDR0_DBW_BIT 8 +#define RC32434_DDR0_DBW_MSK 0x00000100 +#define RC32434_DDR0_WR_BIT 9 +#define RC32434_DDR0_WR_MSK 0x00000600 +#define RC32434_DDR0_PS_BIT 11 +#define RC32434_DDR0_PS_MSK 0x00001800 +#define RC32434_DDR0_DTYPE_BIT 13 +#define RC32434_DDR0_DTYPE_MSK 0x0000e000 +#define RC32434_DDR0_RFC_BIT 16 +#define RC32434_DDR0_RFC_MSK 0x000f0000 +#define RC32434_DDR0_RP_BIT 20 +#define RC32434_DDR0_RP_MSK 0x00300000 +#define RC32434_DDR0_AP_BIT 22 +#define RC32434_DDR0_AP_MSK 0x00400000 +#define RC32434_DDR0_RCD_BIT 23 +#define RC32434_DDR0_RCD_MSK 0x01800000 +#define RC32434_DDR0_CL_BIT 25 +#define RC32434_DDR0_CL_MSK 0x06000000 +#define RC32434_DDR0_DBM_BIT 27 +#define RC32434_DDR0_DBM_MSK 0x08000000 +#define RC32434_DDR0_SDS_BIT 28 +#define RC32434_DDR0_SDS_MSK 0x10000000 +#define RC32434_DDR0_ATP_BIT 29 +#define RC32434_DDR0_ATP_MSK 0x60000000 +#define RC32434_DDR0_RE_BIT 31 +#define RC32434_DDR0_RE_MSK 0x80000000 + +/* DDR bank C registers */ +#define RC32434_DDRC_MSK(x) BIT_TO_MASK(x) +#define RC32434_DDRC_CES_BIT 0 +#define RC32434_DDRC_ACE_BIT 1 + +/* Custom DDR bank registers */ +#define RC32434_DCST_MSK(x) BIT_TO_MASK(x) +#define RC32434_DCST_CS_BIT 0 +#define RC32434_DCST_CS_MSK 0x00000003 +#define RC32434_DCST_WE_BIT 2 +#define RC32434_DCST_RAS_BIT 3 +#define RC32434_DCST_CAS_BIT 4 +#define RC32434_DSCT_CKE_BIT 5 +#define RC32434_DSCT_BA_BIT 6 +#define RC32434_DSCT_BA_MSK 0x000000c0 + +/* DDR QSC registers */ +#define RC32434_QSC_DM_BIT 0 +#define RC32434_QSC_DM_MSK 0x00000003 +#define RC32434_QSC_DQSBS_BIT 2 +#define RC32434_QSC_DQSBS_MSK 0x000000fc +#define RC32434_QSC_DB_BIT 8 +#define RC32434_QSC_DB_MSK 0x00000100 +#define RC32434_QSC_DBSP_BIT 9 +#define RC32434_QSC_DBSP_MSK 0x01fffe00 +#define RC32434_QSC_BDP_BIT 25 +#define RC32434_QSC_BDP_MSK 0x7e000000 + +/* DDR LLC registers */ +#define RC32434_LLC_EAO_BIT 0 +#define RC32434_LLC_EAO_MSK 0x00000001 +#define RC32434_LLC_EO_BIT 1 +#define RC32434_LLC_EO_MSK 0x0000003e +#define RC32434_LLC_FS_BIT 6 +#define RC32434_LLC_FS_MSK 0x000000c0 +#define RC32434_LLC_AS_BIT 8 +#define RC32434_LLC_AS_MSK 0x00000700 +#define RC32434_LLC_SP_BIT 11 +#define RC32434_LLC_SP_MSK 0x001ff800 + +/* DDR LLFC registers */ +#define RC32434_LLFC_MSK(x) BIT_TO_MASK(x) +#define RC32434_LLFC_MEN_BIT 0 +#define RC32434_LLFC_EAN_BIT 1 +#define RC32434_LLFC_FF_BIT 2 + +/* DDR DLLTA registers */ +#define RC32434_DLLTA_ADDR_BIT 2 +#define RC32434_DLLTA_ADDR_MSK 0xfffffffc + +/* DDR DLLED registers */ +#define RC32434_DLLED_MSK(x) BIT_TO_MASK(x) +#define RC32434_DLLED_DBE_BIT 0 +#define RC32434_DLLED_DTE_BIT 1 + +#endif /* _ASM_RC32434_DDR_H_ */ diff --git a/include/asm-mips/mach-rc32434/dma.h b/include/asm-mips/mach-rc32434/dma.h new file mode 100644 index 000000000000..5f898b5873f7 --- /dev/null +++ b/include/asm-mips/mach-rc32434/dma.h @@ -0,0 +1,103 @@ +/* + * Copyright 2002 Integrated Device Technology, Inc. + * All rights reserved. + * + * DMA register definition. + * + * Author : ryan.holmQVist@idt.com + * Date : 20011005 + */ + +#ifndef __ASM_RC32434_DMA_H +#define __ASM_RC32434_DMA_H + +#include <asm/mach-rc32434/rb.h> + +#define DMA0_BASE_ADDR 0x18040000 + +/* + * DMA descriptor (in physical memory). + */ + +struct dma_desc { + u32 control; /* Control. use DMAD_* */ + u32 ca; /* Current Address. */ + u32 devcs; /* Device control and status. */ + u32 link; /* Next descriptor in chain. */ +}; + +#define DMA_DESC_SIZ sizeof(struct dma_desc) +#define DMA_DESC_COUNT_BIT 0 +#define DMA_DESC_COUNT_MSK 0x0003ffff +#define DMA_DESC_DS_BIT 20 +#define DMA_DESC_DS_MSK 0x00300000 + +#define DMA_DESC_DEV_CMD_BIT 22 +#define DMA_DESC_DEV_CMD_MSK 0x01c00000 + +/* DMA command sizes */ +#define DMA_DESC_DEV_CMD_BYTE 0 +#define DMA_DESC_DEV_CMD_HLF_WD 1 +#define DMA_DESC_DEV_CMD_WORD 2 +#define DMA_DESC_DEV_CMD_2WORDS 3 +#define DMA_DESC_DEV_CMD_4WORDS 4 +#define DMA_DESC_DEV_CMD_6WORDS 5 +#define DMA_DESC_DEV_CMD_8WORDS 6 +#define DMA_DESC_DEV_CMD_16WORDS 7 + +/* DMA descriptors interrupts */ +#define DMA_DESC_COF (1 << 25) /* Chain on finished */ +#define DMA_DESC_COD (1 << 26) /* Chain on done */ +#define DMA_DESC_IOF (1 << 27) /* Interrupt on finished */ +#define DMA_DESC_IOD (1 << 28) /* Interrupt on done */ +#define DMA_DESC_TERM (1 << 29) /* Terminated */ +#define DMA_DESC_DONE (1 << 30) /* Done */ +#define DMA_DESC_FINI (1 << 31) /* Finished */ + +/* + * DMA register (within Internal Register Map). + */ + +struct dma_reg { + u32 dmac; /* Control. */ + u32 dmas; /* Status. */ + u32 dmasm; /* Mask. */ + u32 dmadptr; /* Descriptor pointer. */ + u32 dmandptr; /* Next descriptor pointer. */ +}; + +/* DMA channels specific registers */ +#define DMA_CHAN_RUN_BIT (1 << 0) +#define DMA_CHAN_DONE_BIT (1 << 1) +#define DMA_CHAN_MODE_BIT (1 << 2) +#define DMA_CHAN_MODE_MSK 0x0000000c +#define DMA_CHAN_MODE_AUTO 0 +#define DMA_CHAN_MODE_BURST 1 +#define DMA_CHAN_MODE_XFRT 2 +#define DMA_CHAN_MODE_RSVD 3 +#define DMA_CHAN_ACT_BIT (1 << 4) + +/* DMA status registers */ +#define DMA_STAT_FINI (1 << 0) +#define DMA_STAT_DONE (1 << 1) +#define DMA_STAT_CHAIN (1 << 2) +#define DMA_STAT_ERR (1 << 3) +#define DMA_STAT_HALT (1 << 4) + +/* + * DMA channel definitions + */ + +#define DMA_CHAN_ETH_RCV 0 +#define DMA_CHAN_ETH_XMT 1 +#define DMA_CHAN_MEM_TO_FIFO 2 +#define DMA_CHAN_FIFO_TO_MEM 3 +#define DMA_CHAN_PCI_TO_MEM 4 +#define DMA_CHAN_MEM_TO_PCI 5 +#define DMA_CHAN_COUNT 6 + +struct dma_channel { + struct dma_reg ch[DMA_CHAN_COUNT]; +}; + +#endif /* __ASM_RC32434_DMA_H */ diff --git a/include/asm-mips/mach-rc32434/dma_v.h b/include/asm-mips/mach-rc32434/dma_v.h new file mode 100644 index 000000000000..173a9f9146cd --- /dev/null +++ b/include/asm-mips/mach-rc32434/dma_v.h @@ -0,0 +1,52 @@ +/* + * Copyright 2002 Integrated Device Technology, Inc. + * All rights reserved. + * + * DMA register definition. + * + * Author : ryan.holmQVist@idt.com + * Date : 20011005 + */ + +#ifndef _ASM_RC32434_DMA_V_H_ +#define _ASM_RC32434_DMA_V_H_ + +#include <asm/mach-rc32434/dma.h> +#include <asm/mach-rc32434/rc32434.h> + +#define DMA_CHAN_OFFSET 0x14 +#define IS_DMA_USED(X) (((X) & \ + (DMA_DESC_FINI | DMA_DESC_DONE | DMA_DESC_TERM)) \ + != 0) +#define DMA_COUNT(count) ((count) & DMA_DESC_COUNT_MSK) + +#define DMA_HALT_TIMEOUT 500 + +static inline int rc32434_halt_dma(struct dma_reg *ch) +{ + int timeout = 1; + if (__raw_readl(&ch->dmac) & DMA_CHAN_RUN_BIT) { + __raw_writel(0, &ch->dmac); + for (timeout = DMA_HALT_TIMEOUT; timeout > 0; timeout--) { + if (__raw_readl(&ch->dmas) & DMA_STAT_HALT) { + __raw_writel(0, &ch->dmas); + break; + } + } + } + + return timeout ? 0 : 1; +} + +static inline void rc32434_start_dma(struct dma_reg *ch, u32 dma_addr) +{ + __raw_writel(0, &ch->dmandptr); + __raw_writel(dma_addr, &ch->dmadptr); +} + +static inline void rc32434_chain_dma(struct dma_reg *ch, u32 dma_addr) +{ + __raw_writel(dma_addr, &ch->dmandptr); +} + +#endif /* _ASM_RC32434_DMA_V_H_ */ diff --git a/include/asm-mips/mach-rc32434/eth.h b/include/asm-mips/mach-rc32434/eth.h new file mode 100644 index 000000000000..a25cbc56173d --- /dev/null +++ b/include/asm-mips/mach-rc32434/eth.h @@ -0,0 +1,220 @@ +/* + * Definitions for the Ethernet registers + * + * Copyright 2002 Allend Stichter <allen.stichter@idt.com> + * Copyright 2008 Florian Fainelli <florian@openwrt.org> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * THIS SOFTWARE IS PROVIDED ``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 AUTHOR 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. + * + * 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 __ASM_RC32434_ETH_H +#define __ASM_RC32434_ETH_H + + +#define ETH0_BASE_ADDR 0x18060000 + +struct eth_regs { + u32 ethintfc; + u32 ethfifott; + u32 etharc; + u32 ethhash0; + u32 ethhash1; + u32 ethu0[4]; /* Reserved. */ + u32 ethpfs; + u32 ethmcp; + u32 eth_u1[10]; /* Reserved. */ + u32 ethspare; + u32 eth_u2[42]; /* Reserved. */ + u32 ethsal0; + u32 ethsah0; + u32 ethsal1; + u32 ethsah1; + u32 ethsal2; + u32 ethsah2; + u32 ethsal3; + u32 ethsah3; + u32 ethrbc; + u32 ethrpc; + u32 ethrupc; + u32 ethrfc; + u32 ethtbc; + u32 ethgpf; + u32 eth_u9[50]; /* Reserved. */ + u32 ethmac1; + u32 ethmac2; + u32 ethipgt; + u32 ethipgr; + u32 ethclrt; + u32 ethmaxf; + u32 eth_u10; /* Reserved. */ + u32 ethmtest; + u32 miimcfg; + u32 miimcmd; + u32 miimaddr; + u32 miimwtd; + u32 miimrdd; + u32 miimind; + u32 eth_u11; /* Reserved. */ + u32 eth_u12; /* Reserved. */ + u32 ethcfsa0; + u32 ethcfsa1; + u32 ethcfsa2; +}; + +/* Ethernet interrupt registers */ +#define ETH_INT_FC_EN (1 << 0) +#define ETH_INT_FC_ITS (1 << 1) +#define ETH_INT_FC_RIP (1 << 2) +#define ETH_INT_FC_JAM (1 << 3) +#define ETH_INT_FC_OVR (1 << 4) +#define ETH_INT_FC_UND (1 << 5) +#define ETH_INT_FC_IOC 0x000000c0 + +/* Ethernet FIFO registers */ +#define ETH_FIFI_TT_TTH_BIT 0 +#define ETH_FIFO_TT_TTH 0x0000007f + +/* Ethernet ARC/multicast registers */ +#define ETH_ARC_PRO (1 << 0) +#define ETH_ARC_AM (1 << 1) +#define ETH_ARC_AFM (1 << 2) +#define ETH_ARC_AB (1 << 3) + +/* Ethernet SAL registers */ +#define ETH_SAL_BYTE_5 0x000000ff +#define ETH_SAL_BYTE_4 0x0000ff00 +#define ETH_SAL_BYTE_3 0x00ff0000 +#define ETH_SAL_BYTE_2 0xff000000 + +/* Ethernet SAH registers */ +#define ETH_SAH_BYTE1 0x000000ff +#define ETH_SAH_BYTE0 0x0000ff00 + +/* Ethernet GPF register */ +#define ETH_GPF_PTV 0x0000ffff + +/* Ethernet PFG register */ +#define ETH_PFS_PFD (1 << 0) + +/* Ethernet CFSA[0-3] registers */ +#define ETH_CFSA0_CFSA4 0x000000ff +#define ETH_CFSA0_CFSA5 0x0000ff00 +#define ETH_CFSA1_CFSA2 0x000000ff +#define ETH_CFSA1_CFSA3 0x0000ff00 +#define ETH_CFSA1_CFSA0 0x000000ff +#define ETH_CFSA1_CFSA1 0x0000ff00 + +/* Ethernet MAC1 registers */ +#define ETH_MAC1_RE (1 << 0) +#define ETH_MAC1_PAF (1 << 1) +#define ETH_MAC1_RFC (1 << 2) +#define ETH_MAC1_TFC (1 << 3) +#define ETH_MAC1_LB (1 << 4) +#define ETH_MAC1_MR (1 << 31) + +/* Ethernet MAC2 registers */ +#define ETH_MAC2_FD (1 << 0) +#define ETH_MAC2_FLC (1 << 1) +#define ETH_MAC2_HFE (1 << 2) +#define ETH_MAC2_DC (1 << 3) +#define ETH_MAC2_CEN (1 << 4) +#define ETH_MAC2_PE (1 << 5) +#define ETH_MAC2_VPE (1 << 6) +#define ETH_MAC2_APE (1 << 7) +#define ETH_MAC2_PPE (1 << 8) +#define ETH_MAC2_LPE (1 << 9) +#define ETH_MAC2_NB (1 << 12) +#define ETH_MAC2_BP (1 << 13) +#define ETH_MAC2_ED (1 << 14) + +/* Ethernet IPGT register */ +#define ETH_IPGT 0x0000007f + +/* Ethernet IPGR registers */ +#define ETH_IPGR_IPGR2 0x0000007f +#define ETH_IPGR_IPGR1 0x00007f00 + +/* Ethernet CLRT registers */ +#define ETH_CLRT_MAX_RET 0x0000000f +#define ETH_CLRT_COL_WIN 0x00003f00 + +/* Ethernet MAXF register */ +#define ETH_MAXF 0x0000ffff + +/* Ethernet test registers */ +#define ETH_TEST_REG (1 << 2) +#define ETH_MCP_DIV 0x000000ff + +/* MII registers */ +#define ETH_MII_CFG_RSVD 0x0000000c +#define ETH_MII_CMD_RD (1 << 0) +#define ETH_MII_CMD_SCN (1 << 1) +#define ETH_MII_REG_ADDR 0x0000001f +#define ETH_MII_PHY_ADDR 0x00001f00 +#define ETH_MII_WTD_DATA 0x0000ffff +#define ETH_MII_RDD_DATA 0x0000ffff +#define ETH_MII_IND_BSY (1 << 0) +#define ETH_MII_IND_SCN (1 << 1) +#define ETH_MII_IND_NV (1 << 2) + +/* + * Values for the DEVCS field of the Ethernet DMA Rx and Tx descriptors. + */ + +#define ETH_RX_FD (1 << 0) +#define ETH_RX_LD (1 << 1) +#define ETH_RX_ROK (1 << 2) +#define ETH_RX_FM (1 << 3) +#define ETH_RX_MP (1 << 4) +#define ETH_RX_BP (1 << 5) +#define ETH_RX_VLT (1 << 6) +#define ETH_RX_CF (1 << 7) +#define ETH_RX_OVR (1 << 8) +#define ETH_RX_CRC (1 << 9) +#define ETH_RX_CV (1 << 10) +#define ETH_RX_DB (1 << 11) +#define ETH_RX_LE (1 << 12) +#define ETH_RX_LOR (1 << 13) +#define ETH_RX_CES (1 << 14) +#define ETH_RX_LEN_BIT 16 +#define ETH_RX_LEN 0xffff0000 + +#define ETH_TX_FD (1 << 0) +#define ETH_TX_LD (1 << 1) +#define ETH_TX_OEN (1 << 2) +#define ETH_TX_PEN (1 << 3) +#define ETH_TX_CEN (1 << 4) +#define ETH_TX_HEN (1 << 5) +#define ETH_TX_TOK (1 << 6) +#define ETH_TX_MP (1 << 7) +#define ETH_TX_BP (1 << 8) +#define ETH_TX_UND (1 << 9) +#define ETH_TX_OF (1 << 10) +#define ETH_TX_ED (1 << 11) +#define ETH_TX_EC (1 << 12) +#define ETH_TX_LC (1 << 13) +#define ETH_TX_TD (1 << 14) +#define ETH_TX_CRC (1 << 15) +#define ETH_TX_LE (1 << 16) +#define ETH_TX_CC 0x001E0000 + +#endif /* __ASM_RC32434_ETH_H */ diff --git a/include/asm-mips/mach-rc32434/gpio.h b/include/asm-mips/mach-rc32434/gpio.h new file mode 100644 index 000000000000..f946f5f45bbb --- /dev/null +++ b/include/asm-mips/mach-rc32434/gpio.h @@ -0,0 +1,126 @@ +/* + * Copyright 2002 Integrated Device Technology, Inc. + * All rights reserved. + * + * GPIO register definition. + * + * Author : ryan.holmQVist@idt.com + * Date : 20011005 + * Copyright (C) 2001, 2002 Ryan Holm <ryan.holmQVist@idt.com> + * Copyright (C) 2008 Florian Fainelli <florian@openwrt.org> + */ + +#ifndef _RC32434_GPIO_H_ +#define _RC32434_GPIO_H_ + +#include <linux/types.h> + +struct rb532_gpio_reg { + u32 gpiofunc; /* GPIO Function Register + * gpiofunc[x]==0 bit = gpio + * func[x]==1 bit = altfunc + */ + u32 gpiocfg; /* GPIO Configuration Register + * gpiocfg[x]==0 bit = input + * gpiocfg[x]==1 bit = output + */ + u32 gpiod; /* GPIO Data Register + * gpiod[x] read/write gpio pinX status + */ + u32 gpioilevel; /* GPIO Interrupt Status Register + * interrupt level (see gpioistat) + */ + u32 gpioistat; /* Gpio Interrupt Status Register + * istat[x] = (gpiod[x] == level[x]) + * cleared in ISR (STICKY bits) + */ + u32 gpionmien; /* GPIO Non-maskable Interrupt Enable Register */ +}; + +/* UART GPIO signals */ +#define RC32434_UART0_SOUT (1 << 0) +#define RC32434_UART0_SIN (1 << 1) +#define RC32434_UART0_RTS (1 << 2) +#define RC32434_UART0_CTS (1 << 3) + +/* M & P bus GPIO signals */ +#define RC32434_MP_BIT_22 (1 << 4) +#define RC32434_MP_BIT_23 (1 << 5) +#define RC32434_MP_BIT_24 (1 << 6) +#define RC32434_MP_BIT_25 (1 << 7) + +/* CPU GPIO signals */ +#define RC32434_CPU_GPIO (1 << 8) + +/* Reserved GPIO signals */ +#define RC32434_AF_SPARE_6 (1 << 9) +#define RC32434_AF_SPARE_4 (1 << 10) +#define RC32434_AF_SPARE_3 (1 << 11) +#define RC32434_AF_SPARE_2 (1 << 12) + +/* PCI messaging unit */ +#define RC32434_PCI_MSU_GPIO (1 << 13) + + +extern void set_434_reg(unsigned reg_offs, unsigned bit, unsigned len, unsigned val); +extern unsigned get_434_reg(unsigned reg_offs); +extern void set_latch_u5(unsigned char or_mask, unsigned char nand_mask); +extern unsigned char get_latch_u5(void); + +extern int rb532_gpio_get_value(unsigned gpio); +extern void rb532_gpio_set_value(unsigned gpio, int value); +extern int rb532_gpio_direction_input(unsigned gpio); +extern int rb532_gpio_direction_output(unsigned gpio, int value); +extern void rb532_gpio_set_int_level(unsigned gpio, int value); +extern int rb532_gpio_get_int_level(unsigned gpio); +extern void rb532_gpio_set_int_status(unsigned gpio, int value); +extern int rb532_gpio_get_int_status(unsigned gpio); + + +/* Wrappers for the arch-neutral GPIO API */ + +static inline int gpio_request(unsigned gpio, const char *label) +{ + /* Not yet implemented */ + return 0; +} + +static inline void gpio_free(unsigned gpio) +{ + /* Not yet implemented */ +} + +static inline int gpio_direction_input(unsigned gpio) +{ + return rb532_gpio_direction_input(gpio); +} + +static inline int gpio_direction_output(unsigned gpio, int value) +{ + return rb532_gpio_direction_output(gpio, value); +} + +static inline int gpio_get_value(unsigned gpio) +{ + return rb532_gpio_get_value(gpio); +} + +static inline void gpio_set_value(unsigned gpio, int value) +{ + rb532_gpio_set_value(gpio, value); +} + +static inline int gpio_to_irq(unsigned gpio) +{ + return gpio; +} + +static inline int irq_to_gpio(unsigned irq) +{ + return irq; +} + +/* For cansleep */ +#include <asm-generic/gpio.h> + +#endif /* _RC32434_GPIO_H_ */ diff --git a/include/asm-mips/mach-rc32434/integ.h b/include/asm-mips/mach-rc32434/integ.h new file mode 100644 index 000000000000..fa65bc3d8807 --- /dev/null +++ b/include/asm-mips/mach-rc32434/integ.h @@ -0,0 +1,59 @@ +/* + * Definitions for the Watchdog registers + * + * Copyright 2002 Ryan Holm <ryan.holmQVist@idt.com> + * Copyright 2008 Florian Fainelli <florian@openwrt.org> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * THIS SOFTWARE IS PROVIDED ``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 AUTHOR 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. + * + * 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 __RC32434_INTEG_H__ +#define __RC32434_INTEG_H__ + +#include <asm/mach-rc32434/rb.h> + +#define INTEG0_BASE_ADDR 0x18030030 + +struct integ { + u32 errcs; /* sticky use ERRCS_ */ + u32 wtcount; /* Watchdog timer count reg. */ + u32 wtcompare; /* Watchdog timer timeout value. */ + u32 wtc; /* Watchdog timer control. use WTC_ */ +}; + +/* Error counters */ +#define RC32434_ERR_WTO 0 +#define RC32434_ERR_WNE 1 +#define RC32434_ERR_UCW 2 +#define RC32434_ERR_UCR 3 +#define RC32434_ERR_UPW 4 +#define RC32434_ERR_UPR 5 +#define RC32434_ERR_UDW 6 +#define RC32434_ERR_UDR 7 +#define RC32434_ERR_SAE 8 +#define RC32434_ERR_WRE 9 + +/* Watchdog control bits */ +#define RC32434_WTC_EN 0 +#define RC32434_WTC_TO 1 + +#endif /* __RC32434_INTEG_H__ */ diff --git a/include/asm-mips/mach-rc32434/irq.h b/include/asm-mips/mach-rc32434/irq.h new file mode 100644 index 000000000000..cb9e4725f5dc --- /dev/null +++ b/include/asm-mips/mach-rc32434/irq.h @@ -0,0 +1,8 @@ +#ifndef __ASM_RC32434_IRQ_H +#define __ASM_RC32434_IRQ_H + +#define NR_IRQS 256 + +#include <asm/mach-generic/irq.h> + +#endif /* __ASM_RC32434_IRQ_H */ diff --git a/include/asm-mips/mach-rc32434/pci.h b/include/asm-mips/mach-rc32434/pci.h new file mode 100644 index 000000000000..410638f2af74 --- /dev/null +++ b/include/asm-mips/mach-rc32434/pci.h @@ -0,0 +1,481 @@ +/* + * 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 SOFTWARE IS PROVIDED ``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 AUTHOR 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. + * + * 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. + * + * Copyright 2004 IDT Inc. (rischelp@idt.com) + * + * Initial Release + */ + +#ifndef _ASM_RC32434_PCI_H_ +#define _ASM_RC32434_PCI_H_ + +#define epld_mask ((volatile unsigned char *)0xB900000d) + +#define PCI0_BASE_ADDR 0x18080000 +#define PCI_LBA_COUNT 4 + +struct pci_map { + u32 address; /* Address. */ + u32 control; /* Control. */ + u32 mapping; /* mapping. */ +}; + +struct pci_reg { + u32 pcic; + u32 pcis; + u32 pcism; + u32 pcicfga; + u32 pcicfgd; + volatile struct pci_map pcilba[PCI_LBA_COUNT]; + u32 pcidac; + u32 pcidas; + u32 pcidasm; + u32 pcidad; + u32 pcidma8c; + u32 pcidma9c; + u32 pcitc; +}; + +#define PCI_MSU_COUNT 2 + +struct pci_msu { + u32 pciim[PCI_MSU_COUNT]; + u32 pciom[PCI_MSU_COUNT]; + u32 pciid; + u32 pciiic; + u32 pciiim; + u32 pciiod; + u32 pciioic; + u32 pciioim; +}; + +/* + * PCI Control Register + */ + +#define PCI_CTL_EN (1 << 0) +#define PCI_CTL_TNR (1 << 1) +#define PCI_CTL_SCE (1 << 2) +#define PCI_CTL_IEN (1 << 3) +#define PCI_CTL_AAA (1 << 4) +#define PCI_CTL_EAP (1 << 5) +#define PCI_CTL_PCIM_BIT 6 +#define PCI_CTL_PCIM 0x000001c0 + +#define PCI_CTL_PCIM_DIS 0 +#define PCI_CTL_PCIM_TNR 1 /* Satellite - target not ready */ +#define PCI_CTL_PCIM_SUS 2 /* Satellite - suspended CPU. */ +#define PCI_CTL_PCIM_EXT 3 /* Host - external arbiter. */ +#define PCI_CTL PCIM_PRIO 4 /* Host - fixed priority arb. */ +#define PCI_CTL_PCIM_RR 5 /* Host - round robin priority. */ +#define PCI_CTL_PCIM_RSVD6 6 +#define PCI_CTL_PCIM_RSVD7 7 + +#define PCI_CTL_IGM (1 << 9) + +/* + * PCI Status Register + */ + +#define PCI_STAT_EED (1 << 0) +#define PCI_STAT_WR (1 << 1) +#define PCI_STAT_NMI (1 << 2) +#define PCI_STAT_II (1 << 3) +#define PCI_STAT_CWE (1 << 4) +#define PCI_STAT_CRE (1 << 5) +#define PCI_STAT_MDPE (1 << 6) +#define PCI_STAT_STA (1 << 7) +#define PCI_STAT_RTA (1 << 8) +#define PCI_STAT_RMA (1 << 9) +#define PCI_STAT_SSE (1 << 10) +#define PCI_STAT_OSE (1 << 11) +#define PCI_STAT_PE (1 << 12) +#define PCI_STAT_TAE (1 << 13) +#define PCI_STAT_RLE (1 << 14) +#define PCI_STAT_BME (1 << 15) +#define PCI_STAT_PRD (1 << 16) +#define PCI_STAT_RIP (1 << 17) + +/* + * PCI Status Mask Register + */ + +#define PCI_STATM_EED PCI_STAT_EED +#define PCI_STATM_WR PCI_STAT_WR +#define PCI_STATM_NMI PCI_STAT_NMI +#define PCI_STATM_II PCI_STAT_II +#define PCI_STATM_CWE PCI_STAT_CWE +#define PCI_STATM_CRE PCI_STAT_CRE +#define PCI_STATM_MDPE PCI_STAT_MDPE +#define PCI_STATM_STA PCI_STAT_STA +#define PCI_STATM_RTA PCI_STAT_RTA +#define PCI_STATM_RMA PCI_STAT_RMA +#define PCI_STATM_SSE PCI_STAT_SSE +#define PCI_STATM_OSE PCI_STAT_OSE +#define PCI_STATM_PE PCI_STAT_PE +#define PCI_STATM_TAE PCI_STAT_TAE +#define PCI_STATM_RLE PCI_STAT_RLE +#define PCI_STATM_BME PCI_STAT_BME +#define PCI_STATM_PRD PCI_STAT_PRD +#define PCI_STATM_RIP PCI_STAT_RIP + +/* + * PCI Configuration Address Register + */ +#define PCI_CFGA_REG_BIT 2 +#define PCI_CFGA_REG 0x000000fc +#define PCI_CFGA_REG_ID (0x00 >> 2) /* use PCFGID */ +#define PCI_CFGA_REG_04 (0x04 >> 2) /* use PCFG04_ */ +#define PCI_CFGA_REG_08 (0x08 >> 2) /* use PCFG08_ */ +#define PCI_CFGA_REG_0C (0x0C >> 2) /* use PCFG0C_ */ +#define PCI_CFGA_REG_PBA0 (0x10 >> 2) /* use PCIPBA_ */ +#define PCI_CFGA_REG_PBA1 (0x14 >> 2) /* use PCIPBA_ */ +#define PCI_CFGA_REG_PBA2 (0x18 >> 2) /* use PCIPBA_ */ +#define PCI_CFGA_REG_PBA3 (0x1c >> 2) /* use PCIPBA_ */ +#define PCI_CFGA_REG_SUBSYS (0x2c >> 2) /* use PCFGSS_ */ +#define PCI_CFGA_REG_3C (0x3C >> 2) /* use PCFG3C_ */ +#define PCI_CFGA_REG_PBBA0C (0x44 >> 2) /* use PCIPBAC_ */ +#define PCI_CFGA_REG_PBA0M (0x48 >> 2) +#define PCI_CFGA_REG_PBA1C (0x4c >> 2) /* use PCIPBAC_ */ +#define PCI_CFGA_REG_PBA1M (0x50 >> 2) +#define PCI_CFGA_REG_PBA2C (0x54 >> 2) /* use PCIPBAC_ */ +#define PCI_CFGA_REG_PBA2M (0x58 >> 2) +#define PCI_CFGA_REG_PBA3C (0x5c >> 2) /* use PCIPBAC_ */ +#define PCI_CFGA_REG_PBA3M (0x60 >> 2) +#define PCI_CFGA_REG_PMGT (0x64 >> 2) +#define PCI_CFGA_FUNC_BIT 8 +#define PCI_CFGA_FUNC 0x00000700 +#define PCI_CFGA_DEV_BIT 11 +#define PCI_CFGA_DEV 0x0000f800 +#define PCI_CFGA_DEV_INTERN 0 +#define PCI_CFGA_BUS_BIT 16 +#define PCI CFGA_BUS 0x00ff0000 +#define PCI_CFGA_BUS_TYPE0 0 +#define PCI_CFGA_EN (1 << 31) + +/* PCI CFG04 commands */ +#define PCI_CFG04_CMD_IO_ENA (1 << 0) +#define PCI_CFG04_CMD_MEM_ENA (1 << 1) +#define PCI_CFG04_CMD_BM_ENA (1 << 2) +#define PCI_CFG04_CMD_MW_INV (1 << 4) +#define PCI_CFG04_CMD_PAR_ENA (1 << 6) +#define PCI_CFG04_CMD_SER_ENA (1 << 8) +#define PCI_CFG04_CMD_FAST_ENA (1 << 9) + +/* PCI CFG04 status fields */ +#define PCI_CFG04_STAT_BIT 16 +#define PCI_CFG04_STAT 0xffff0000 +#define PCI_CFG04_STAT_66_MHZ (1 << 21) +#define PCI_CFG04_STAT_FBB (1 << 23) +#define PCI_CFG04_STAT_MDPE (1 << 24) +#define PCI_CFG04_STAT_DST (1 << 25) +#define PCI_CFG04_STAT_STA (1 << 27) +#define PCI_CFG04_STAT_RTA (1 << 28) +#define PCI_CFG04_STAT_RMA (1 << 29) +#define PCI_CFG04_STAT_SSE (1 << 30) +#define PCI_CFG04_STAT_PE (1 << 31) + +#define PCI_PBA_MSI (1 << 0) +#define PCI_PBA_P (1 << 2) + +/* PCI PBAC registers */ +#define PCI_PBAC_MSI (1 << 0) +#define PCI_PBAC_P (1 << 1) +#define PCI_PBAC_SIZE_BIT 2 +#define PCI_PBAC_SIZE 0x0000007c +#define PCI_PBAC_SB (1 << 7) +#define PCI_PBAC_PP (1 << 8) +#define PCI_PBAC_MR_BIT 9 +#define PCI_PBAC_MR 0x00000600 +#define PCI_PBAC_MR_RD 0 +#define PCI_PBAC_MR_RD_LINE 1 +#define PCI_PBAC_MR_RD_MULT 2 +#define PCI_PBAC_MRL (1 << 11) +#define PCI_PBAC_MRM (1 << 12) +#define PCI_PBAC_TRP (1 << 13) + +#define PCI_CFG40_TRDY_TIM 0x000000ff +#define PCI_CFG40_RET_LIM 0x0000ff00 + +/* + * PCI Local Base Address [0|1|2|3] Register + */ + +#define PCI_LBA_BADDR_BIT 0 +#define PCI_LBA_BADDR 0xffffff00 + +/* + * PCI Local Base Address Control Register + */ + +#define PCI_LBAC_MSI (1 << 0) +#define PCI_LBAC_MSI_MEM 0 +#define PCI_LBAC_MSI_IO 1 +#define PCI_LBAC_SIZE_BIT 2 +#define PCI_LBAC_SIZE 0x0000007c +#define PCI_LBAC_SB (1 << 7) +#define PCI_LBAC_RT (1 << 8) +#define PCI_LBAC_RT_NO_PREF 0 +#define PCI_LBAC_RT_PREF 1 + +/* + * PCI Local Base Address [0|1|2|3] Mapping Register + */ +#define PCI_LBAM_MADDR_BIT 8 +#define PCI_LBAM_MADDR 0xffffff00 + +/* + * PCI Decoupled Access Control Register + */ +#define PCI_DAC_DEN (1 << 0) + +/* + * PCI Decoupled Access Status Register + */ +#define PCI_DAS_D (1 << 0) +#define PCI_DAS_B (1 << 1) +#define PCI_DAS_E (1 << 2) +#define PCI_DAS_OFE (1 << 3) +#define PCI_DAS_OFF (1 << 4) +#define PCI_DAS_IFE (1 << 5) +#define PCI_DAS_IFF (1 << 6) + +/* + * PCI DMA Channel 8 Configuration Register + */ +#define PCI_DMA8C_MBS_BIT 0 +#define PCI_DMA8C_MBS 0x00000fff /* Maximum Burst Size. */ +#define PCI_DMA8C_OUR (1 << 12) + +/* + * PCI DMA Channel 9 Configuration Register + */ +#define PCI_DMA9C_MBS_BIT 0 /* Maximum Burst Size. */ +#define PCI_DMA9C_MBS 0x00000fff + +/* + * PCI to Memory(DMA Channel 8) AND Memory to PCI DMA(DMA Channel 9)Descriptors + */ + +#define PCI_DMAD_PT_BIT 22 /* in DEVCMD field (descriptor) */ +#define PCI_DMAD_PT 0x00c00000 /* preferred transaction field */ +/* These are for reads (DMA channel 8) */ +#define PCI_DMAD_DEVCMD_MR 0 /* memory read */ +#define PCI_DMAD_DEVCMD_MRL 1 /* memory read line */ +#define PCI_DMAD_DEVCMD_MRM 2 /* memory read multiple */ +#define PCI_DMAD_DEVCMD_IOR 3 /* I/O read */ +/* These are for writes (DMA channel 9) */ +#define PCI_DMAD_DEVCMD_MW 0 /* memory write */ +#define PCI_DMAD_DEVCMD_MWI 1 /* memory write invalidate */ +#define PCI_DMAD_DEVCMD_IOW 3 /* I/O write */ + +/* Swap byte field applies to both DMA channel 8 and 9 */ +#define PCI_DMAD_SB (1 << 24) /* swap byte field */ + + +/* + * PCI Target Control Register + */ + +#define PCI_TC_RTIMER_BIT 0 +#define PCI_TC_RTIMER 0x000000ff +#define PCI_TC_DTIMER_BIT 8 +#define PCI_TC_DTIMER 0x0000ff00 +#define PCI_TC_RDR (1 << 18) +#define PCI_TC_DDT (1 << 19) + +/* + * PCI messaging unit [applies to both inbound and outbound registers ] + */ +#define PCI_MSU_M0 (1 << 0) +#define PCI_MSU_M1 (1 << 1) +#define PCI_MSU_DB (1 << 2) + +#define PCI_MSG_ADDR 0xB8088010 +#define PCI0_ADDR 0xB8080000 +#define rc32434_pci ((struct pci_reg *) PCI0_ADDR) +#define rc32434_pci_msg ((struct pci_msu *) PCI_MSG_ADDR) + +#define PCIM_SHFT 0x6 +#define PCIM_BIT_LEN 0x7 +#define PCIM_H_EA 0x3 +#define PCIM_H_IA_FIX 0x4 +#define PCIM_H_IA_RR 0x5 +#if 0 +#define PCI_ADDR_START 0x13000000 +#endif + +#define PCI_ADDR_START 0x50000000 + +#define CPUTOPCI_MEM_WIN 0x02000000 +#define CPUTOPCI_IO_WIN 0x00100000 +#define PCILBA_SIZE_SHFT 2 +#define PCILBA_SIZE_MASK 0x1F +#define SIZE_256MB 0x1C +#define SIZE_128MB 0x1B +#define SIZE_64MB 0x1A +#define SIZE_32MB 0x19 +#define SIZE_16MB 0x18 +#define SIZE_4MB 0x16 +#define SIZE_2MB 0x15 +#define SIZE_1MB 0x14 +#define KORINA_CONFIG0_ADDR 0x80000000 +#define KORINA_CONFIG1_ADDR 0x80000004 +#define KORINA_CONFIG2_ADDR 0x80000008 +#define KORINA_CONFIG3_ADDR 0x8000000C +#define KORINA_CONFIG4_ADDR 0x80000010 +#define KORINA_CONFIG5_ADDR 0x80000014 +#define KORINA_CONFIG6_ADDR 0x80000018 +#define KORINA_CONFIG7_ADDR 0x8000001C +#define KORINA_CONFIG8_ADDR 0x80000020 +#define KORINA_CONFIG9_ADDR 0x80000024 +#define KORINA_CONFIG10_ADDR 0x80000028 +#define KORINA_CONFIG11_ADDR 0x8000002C +#define KORINA_CONFIG12_ADDR 0x80000030 +#define KORINA_CONFIG13_ADDR 0x80000034 +#define KORINA_CONFIG14_ADDR 0x80000038 +#define KORINA_CONFIG15_ADDR 0x8000003C +#define KORINA_CONFIG16_ADDR 0x80000040 +#define KORINA_CONFIG17_ADDR 0x80000044 +#define KORINA_CONFIG18_ADDR 0x80000048 +#define KORINA_CONFIG19_ADDR 0x8000004C +#define KORINA_CONFIG20_ADDR 0x80000050 +#define KORINA_CONFIG21_ADDR 0x80000054 +#define KORINA_CONFIG22_ADDR 0x80000058 +#define KORINA_CONFIG23_ADDR 0x8000005C +#define KORINA_CONFIG24_ADDR 0x80000060 +#define KORINA_CONFIG25_ADDR 0x80000064 +#define KORINA_CMD (PCI_CFG04_CMD_IO_ENA | \ + PCI_CFG04_CMD_MEM_ENA | \ + PCI_CFG04_CMD_BM_ENA | \ + PCI_CFG04_CMD_MW_INV | \ + PCI_CFG04_CMD_PAR_ENA | \ + PCI_CFG04_CMD_SER_ENA) + +#define KORINA_STAT (PCI_CFG04_STAT_MDPE | \ + PCI_CFG04_STAT_STA | \ + PCI_CFG04_STAT_RTA | \ + PCI_CFG04_STAT_RMA | \ + PCI_CFG04_STAT_SSE | \ + PCI_CFG04_STAT_PE) + +#define KORINA_CNFG1 ((KORINA_STAT<<16)|KORINA_CMD) + +#define KORINA_REVID 0 +#define KORINA_CLASS_CODE 0 +#define KORINA_CNFG2 ((KORINA_CLASS_CODE<<8) | \ + KORINA_REVID) + +#define KORINA_CACHE_LINE_SIZE 4 +#define KORINA_MASTER_LAT 0x3c +#define KORINA_HEADER_TYPE 0 +#define KORINA_BIST 0 + +#define KORINA_CNFG3 ((KORINA_BIST << 24) | \ + (KORINA_HEADER_TYPE<<16) | \ + (KORINA_MASTER_LAT<<8) | \ + KORINA_CACHE_LINE_SIZE) + +#define KORINA_BAR0 0x00000008 /* 128 MB Memory */ +#define KORINA_BAR1 0x18800001 /* 1 MB IO */ +#define KORINA_BAR2 0x18000001 /* 2 MB IO window for Korina + internal Registers */ +#define KORINA_BAR3 0x48000008 /* Spare 128 MB Memory */ + +#define KORINA_CNFG4 KORINA_BAR0 +#define KORINA_CNFG5 KORINA_BAR1 +#define KORINA_CNFG6 KORINA_BAR2 +#define KORINA_CNFG7 KORINA_BAR3 + +#define KORINA_SUBSYS_VENDOR_ID 0x011d +#define KORINA_SUBSYSTEM_ID 0x0214 +#define KORINA_CNFG8 0 +#define KORINA_CNFG9 0 +#define KORINA_CNFG10 0 +#define KORINA_CNFG11 ((KORINA_SUBSYS_VENDOR_ID<<16) | \ + KORINA_SUBSYSTEM_ID) +#define KORINA_INT_LINE 1 +#define KORINA_INT_PIN 1 +#define KORINA_MIN_GNT 8 +#define KORINA_MAX_LAT 0x38 +#define KORINA_CNFG12 0 +#define KORINA_CNFG13 0 +#define KORINA_CNFG14 0 +#define KORINA_CNFG15 ((KORINA_MAX_LAT<<24) | \ + (KORINA_MIN_GNT<<16) | \ + (KORINA_INT_PIN<<8) | \ + KORINA_INT_LINE) +#define KORINA_RETRY_LIMIT 0x80 +#define KORINA_TRDY_LIMIT 0x80 +#define KORINA_CNFG16 ((KORINA_RETRY_LIMIT<<8) | \ + KORINA_TRDY_LIMIT) +#define PCI_PBAxC_R 0x0 +#define PCI_PBAxC_RL 0x1 +#define PCI_PBAxC_RM 0x2 +#define SIZE_SHFT 2 + +#if defined(__MIPSEB__) +#define KORINA_PBA0C (PCI_PBAC_MRL | PCI_PBAC_SB | \ + ((PCI_PBAxC_RM & 0x3) << PCI_PBAC_MR_BIT) | \ + PCI_PBAC_PP | \ + (SIZE_128MB<<SIZE_SHFT) | \ + PCI_PBAC_P) +#else +#define KORINA_PBA0C (PCI_PBAC_MRL | \ + ((PCI_PBAxC_RM & 0x3) << PCI_PBAC_MR_BIT) | \ + PCI_PBAC_PP | \ + (SIZE_128MB<<SIZE_SHFT) | \ + PCI_PBAC_P) +#endif +#define KORINA_CNFG17 KORINA_PBA0C +#define KORINA_PBA0M 0x0 +#define KORINA_CNFG18 KORINA_PBA0M + +#if defined(__MIPSEB__) +#define KORINA_PBA1C ((SIZE_1MB<<SIZE_SHFT) | PCI_PBAC_SB | \ + PCI_PBAC_MSI) +#else +#define KORINA_PBA1C ((SIZE_1MB<<SIZE_SHFT) | \ + PCI_PBAC_MSI) +#endif +#define KORINA_CNFG19 KORINA_PBA1C +#define KORINA_PBA1M 0x0 +#define KORINA_CNFG20 KORINA_PBA1M + +#if defined(__MIPSEB__) +#define KORINA_PBA2C ((SIZE_2MB<<SIZE_SHFT) | PCI_PBAC_SB | \ + PCI_PBAC_MSI) +#else +#define KORINA_PBA2C ((SIZE_2MB<<SIZE_SHFT) | \ + PCI_PBAC_MSI) +#endif +#define KORINA_CNFG21 KORINA_PBA2C +#define KORINA_PBA2M 0x18000000 +#define KORINA_CNFG22 KORINA_PBA2M +#define KORINA_PBA3C 0 +#define KORINA_CNFG23 KORINA_PBA3C +#define KORINA_PBA3M 0 +#define KORINA_CNFG24 KORINA_PBA3M + +#define PCITC_DTIMER_VAL 8 +#define PCITC_RTIMER_VAL 0x10 + +#endif /* __ASM_RC32434_PCI_H */ diff --git a/include/asm-mips/mach-rc32434/prom.h b/include/asm-mips/mach-rc32434/prom.h new file mode 100644 index 000000000000..1d66ddcda89a --- /dev/null +++ b/include/asm-mips/mach-rc32434/prom.h @@ -0,0 +1,44 @@ +/* + * Definitions for the PROM + * + * Copyright 2002 Ryan Holm <ryan.holmQVist@idt.com> + * Copyright 2008 Florian Fainelli <florian@openwrt.org> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * THIS SOFTWARE IS PROVIDED ``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 AUTHOR 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. + * + * 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. + * + */ + +#define PROM_ENTRY(x) (0xbfc00000 + ((x) * 8)) + +#define GPIO_INIT_NOBUTTON "" +#define GPIO_INIT_BUTTON " 2" + +#define SR_NMI 0x00180000 +#define SERIAL_SPEED_ENTRY 0x00000001 + +#define FREQ_TAG "HZ=" +#define GPIO_TAG "gpio=" +#define KMAC_TAG "kmac=" +#define MEM_TAG "mem=" +#define BOARD_TAG "board=" + +#define BOARD_RB532 "500" +#define BOARD_RB532A "500r5" diff --git a/include/asm-mips/mach-rc32434/rb.h b/include/asm-mips/mach-rc32434/rb.h new file mode 100644 index 000000000000..e0a76e3ffea8 --- /dev/null +++ b/include/asm-mips/mach-rc32434/rb.h @@ -0,0 +1,81 @@ +/* + * 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. + * + * Copyright (C) 2004 IDT Inc. + * Copyright (C) 2006 Felix Fietkau <nbd@openwrt.org> + */ +#ifndef __ASM_RC32434_RB_H +#define __ASM_RC32434_RB_H + +#include <linux/genhd.h> + +#define IDT434_REG_BASE ((volatile void *) KSEG1ADDR(0x18000000)) +#define DEV0BASE 0x010000 +#define DEV0MASK 0x010004 +#define DEV0C 0x010008 +#define DEV0T 0x01000C +#define DEV1BASE 0x010010 +#define DEV1MASK 0x010014 +#define DEV1C 0x010018 +#define DEV1TC 0x01001C +#define DEV2BASE 0x010020 +#define DEV2MASK 0x010024 +#define DEV2C 0x010028 +#define DEV2TC 0x01002C +#define DEV3BASE 0x010030 +#define DEV3MASK 0x010034 +#define DEV3C 0x010038 +#define DEV3TC 0x01003C +#define BTCS 0x010040 +#define BTCOMPARE 0x010044 +#define GPIOBASE 0x050000 +#define GPIOCFG 0x050004 +#define GPIOD 0x050008 +#define GPIOILEVEL 0x05000C +#define GPIOISTAT 0x050010 +#define GPIONMIEN 0x050014 +#define IMASK6 0x038038 +#define LO_WPX (1 << 0) +#define LO_ALE (1 << 1) +#define LO_CLE (1 << 2) +#define LO_CEX (1 << 3) +#define LO_FOFF (1 << 5) +#define LO_SPICS (1 << 6) +#define LO_ULED (1 << 7) + +#define BIT_TO_MASK(x) (1 << x) + +struct dev_reg { + u32 base; + u32 mask; + u32 ctl; + u32 timing; +}; + +struct korina_device { + char *name; + unsigned char mac[6]; + struct net_device *dev; +}; + +struct cf_device { + int gpio_pin; + void *dev; + struct gendisk *gd; +}; + +struct mpmc_device { + unsigned char state; + spinlock_t lock; + void __iomem *base; +}; + +#endif /* __ASM_RC32434_RB_H */ diff --git a/include/asm-mips/mach-rc32434/rc32434.h b/include/asm-mips/mach-rc32434/rc32434.h new file mode 100644 index 000000000000..c4a02145104e --- /dev/null +++ b/include/asm-mips/mach-rc32434/rc32434.h @@ -0,0 +1,61 @@ +/* + * Definitions for IDT RC323434 CPU. + */ + +#ifndef _ASM_RC32434_RC32434_H_ +#define _ASM_RC32434_RC32434_H_ + +#include <linux/delay.h> +#include <linux/io.h> + +#define RC32434_REG_BASE 0x18000000 +#define RC32434_RST (1 << 15) + +#define IDT_CLOCK_MULT 2 +#define MIPS_CPU_TIMER_IRQ 7 + +/* Interrupt Controller */ +#define IC_GROUP0_PEND (RC32434_REG_BASE + 0x38000) +#define IC_GROUP0_MASK (RC32434_REG_BASE + 0x38008) +#define IC_GROUP_OFFSET 0x0C + +#define NUM_INTR_GROUPS 5 + +/* 16550 UARTs */ +#define GROUP0_IRQ_BASE 8 /* GRP2 IRQ numbers start here */ + /* GRP3 IRQ numbers start here */ +#define GROUP1_IRQ_BASE (GROUP0_IRQ_BASE + 32) + /* GRP4 IRQ numbers start here */ +#define GROUP2_IRQ_BASE (GROUP1_IRQ_BASE + 32) + /* GRP5 IRQ numbers start here */ +#define GROUP3_IRQ_BASE (GROUP2_IRQ_BASE + 32) +#define GROUP4_IRQ_BASE (GROUP3_IRQ_BASE + 32) + + +#ifdef __MIPSEB__ +#define RC32434_UART0_BASE (RC32434_REG_BASE + 0x58003) +#else +#define RC32434_UART0_BASE (RC32434_REG_BASE + 0x58000) +#endif + +#define RC32434_UART0_IRQ (GROUP3_IRQ_BASE + 0) + +/* cpu pipeline flush */ +static inline void rc32434_sync(void) +{ + __asm__ volatile ("sync"); +} + +static inline void rc32434_sync_udelay(int us) +{ + __asm__ volatile ("sync"); + udelay(us); +} + +static inline void rc32434_sync_delay(int ms) +{ + __asm__ volatile ("sync"); + mdelay(ms); +} + +#endif /* _ASM_RC32434_RC32434_H_ */ diff --git a/include/asm-mips/mach-rc32434/timer.h b/include/asm-mips/mach-rc32434/timer.h new file mode 100644 index 000000000000..e49b1d57a017 --- /dev/null +++ b/include/asm-mips/mach-rc32434/timer.h @@ -0,0 +1,65 @@ +/* + * Definitions for timer registers + * + * Copyright 2004 Philip Rischel <rischelp@idt.com> + * Copyright 2008 Florian Fainelli <florian@openwrt.org> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * THIS SOFTWARE IS PROVIDED ``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 AUTHOR 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. + * + * 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 __ASM_RC32434_TIMER_H +#define __ASM_RC32434_TIMER_H + +#include <asm/mach-rc32434/rb.h> + +#define TIMER0_BASE_ADDR 0x18028000 +#define TIMER_COUNT 3 + +struct timer_counter { + u32 count; + u32 compare; + u32 ctc; /*use CTC_ */ +}; + +struct timer { + struct timer_counter tim[TIMER_COUNT]; + u32 rcount; /* use RCOUNT_ */ + u32 rcompare; /* use RCOMPARE_ */ + u32 rtc; /* use RTC_ */ +}; + +#define RC32434_CTC_EN_BIT 0 +#define RC32434_CTC_TO_BIT 1 + +/* Real time clock registers */ +#define RC32434_RTC_MSK(x) BIT_TO_MASK(x) +#define RC32434_RTC_CE_BIT 0 +#define RC32434_RTC_TO_BIT 1 +#define RC32434_RTC_RQE_BIT 2 + +/* Counter registers */ +#define RC32434_RCOUNT_BIT 0 +#define RC32434_RCOUNT_MSK 0x0000ffff +#define RC32434_RCOMP_BIT 0 +#define RC32434_RCOMP_MSK 0x0000ffff + +#endif /* __ASM_RC32434_TIMER_H */ diff --git a/include/asm-mips/mach-rc32434/war.h b/include/asm-mips/mach-rc32434/war.h new file mode 100644 index 000000000000..3ddf187e98a6 --- /dev/null +++ b/include/asm-mips/mach-rc32434/war.h @@ -0,0 +1,25 @@ +/* + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 2002, 2004, 2007 by Ralf Baechle <ralf@linux-mips.org> + */ +#ifndef __ASM_MIPS_MACH_MIPS_WAR_H +#define __ASM_MIPS_MACH_MIPS_WAR_H + +#define R4600_V1_INDEX_ICACHEOP_WAR 0 +#define R4600_V1_HIT_CACHEOP_WAR 0 +#define R4600_V2_HIT_CACHEOP_WAR 0 +#define R5432_CP0_INTERRUPT_WAR 0 +#define BCM1250_M3_WAR 0 +#define SIBYTE_1956_WAR 0 +#define MIPS4K_ICACHE_REFILL_WAR 1 +#define MIPS_CACHE_SYNC_WAR 0 +#define TX49XX_ICACHE_INDEX_INV_WAR 0 +#define RM9000_CDEX_SMP_WAR 0 +#define ICACHE_REFILLS_WORKAROUND_WAR 0 +#define R10000_LLSC_WAR 0 +#define MIPS34K_MISSED_ITLB_WAR 0 + +#endif /* __ASM_MIPS_MACH_MIPS_WAR_H */ diff --git a/include/asm-mips/mips-boards/atlas.h b/include/asm-mips/mips-boards/atlas.h deleted file mode 100644 index a8ae12d120ee..000000000000 --- a/include/asm-mips/mips-boards/atlas.h +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Carsten Langgaard, carstenl@mips.com - * Copyright (C) 2000 MIPS Technologies, Inc. All rights reserved. - * - * ######################################################################## - * - * This program is free software; you can distribute 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 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. - * - * ######################################################################## - * - * Defines of the Atlas board specific address-MAP, registers, etc. - * - */ -#ifndef _MIPS_ATLAS_H -#define _MIPS_ATLAS_H - -#include <asm/addrspace.h> - -/* - * Atlas RTC-device indirect register access. - */ -#define ATLAS_RTC_ADR_REG 0x1f000800 -#define ATLAS_RTC_DAT_REG 0x1f000808 - -/* - * Atlas interrupt controller register base. - */ -#define ATLAS_ICTRL_REGS_BASE 0x1f000000 - -/* - * Atlas registers are memory mapped on 64-bit aligned boundaries and - * only word access are allowed. - */ -struct atlas_ictrl_regs { - volatile unsigned int intraw; - int dummy1; - volatile unsigned int intseten; - int dummy2; - volatile unsigned int intrsten; - int dummy3; - volatile unsigned int intenable; - int dummy4; - volatile unsigned int intstatus; - int dummy5; -}; - -/* - * Atlas UART register base. - */ -#define ATLAS_UART_REGS_BASE 0x1f000900 -#define ATLAS_BASE_BAUD ( 3686400 / 16 ) - -/* - * Atlas PSU standby register. - */ -#define ATLAS_PSUSTBY_REG 0x1f000600 -#define ATLAS_GOSTBY 0x4d - -/* - * We make a universal assumption about the way the bootloader (YAMON) - * have located the Philips SAA9730 chip. - * This is not ideal, but is needed for setting up remote debugging as - * soon as possible. - */ -#define ATLAS_SAA9730_REG 0x10800000 - -#define ATLAS_SAA9730_BAUDCLOCK 3692300 - -#endif /* !(_MIPS_ATLAS_H) */ diff --git a/include/asm-mips/mips-boards/atlasint.h b/include/asm-mips/mips-boards/atlasint.h deleted file mode 100644 index 93ba1c1b2a4f..000000000000 --- a/include/asm-mips/mips-boards/atlasint.h +++ /dev/null @@ -1,109 +0,0 @@ -/* - * Copyright (C) 1999, 2006 MIPS Technologies, Inc. All rights reserved. - * Authors: Carsten Langgaard <carstenl@mips.com> - * Maciej W. Rozycki <macro@mips.com> - * - * ######################################################################## - * - * This program is free software; you can distribute 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 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. - * - * ######################################################################## - * - * Defines for the Atlas interrupt controller. - * - */ -#ifndef _MIPS_ATLASINT_H -#define _MIPS_ATLASINT_H - -#include <irq.h> - -/* CPU interrupt offsets */ -#define MIPSCPU_INT_SW0 0 -#define MIPSCPU_INT_SW1 1 -#define MIPSCPU_INT_MB0 2 -#define MIPSCPU_INT_ATLAS MIPSCPU_INT_MB0 -#define MIPSCPU_INT_MB1 3 -#define MIPSCPU_INT_MB2 4 -#define MIPSCPU_INT_MB3 5 -#define MIPSCPU_INT_MB4 6 - -/* - * Interrupts 8..39 are used for Atlas interrupt controller interrupts - */ -#define ATLAS_INT_BASE 8 -#define ATLAS_INT_UART (ATLAS_INT_BASE + 0) -#define ATLAS_INT_TIM0 (ATLAS_INT_BASE + 1) -#define ATLAS_INT_RES2 (ATLAS_INT_BASE + 2) -#define ATLAS_INT_RES3 (ATLAS_INT_BASE + 3) -#define ATLAS_INT_RTC (ATLAS_INT_BASE + 4) -#define ATLAS_INT_COREHI (ATLAS_INT_BASE + 5) -#define ATLAS_INT_CORELO (ATLAS_INT_BASE + 6) -#define ATLAS_INT_RES7 (ATLAS_INT_BASE + 7) -#define ATLAS_INT_PCIA (ATLAS_INT_BASE + 8) -#define ATLAS_INT_PCIB (ATLAS_INT_BASE + 9) -#define ATLAS_INT_PCIC (ATLAS_INT_BASE + 10) -#define ATLAS_INT_PCID (ATLAS_INT_BASE + 11) -#define ATLAS_INT_ENUM (ATLAS_INT_BASE + 12) -#define ATLAS_INT_DEG (ATLAS_INT_BASE + 13) -#define ATLAS_INT_ATXFAIL (ATLAS_INT_BASE + 14) -#define ATLAS_INT_INTA (ATLAS_INT_BASE + 15) -#define ATLAS_INT_INTB (ATLAS_INT_BASE + 16) -#define ATLAS_INT_ETH ATLAS_INT_INTB -#define ATLAS_INT_INTC (ATLAS_INT_BASE + 17) -#define ATLAS_INT_SCSI ATLAS_INT_INTC -#define ATLAS_INT_INTD (ATLAS_INT_BASE + 18) -#define ATLAS_INT_SERR (ATLAS_INT_BASE + 19) -#define ATLAS_INT_RES20 (ATLAS_INT_BASE + 20) -#define ATLAS_INT_RES21 (ATLAS_INT_BASE + 21) -#define ATLAS_INT_RES22 (ATLAS_INT_BASE + 22) -#define ATLAS_INT_RES23 (ATLAS_INT_BASE + 23) -#define ATLAS_INT_RES24 (ATLAS_INT_BASE + 24) -#define ATLAS_INT_RES25 (ATLAS_INT_BASE + 25) -#define ATLAS_INT_RES26 (ATLAS_INT_BASE + 26) -#define ATLAS_INT_RES27 (ATLAS_INT_BASE + 27) -#define ATLAS_INT_RES28 (ATLAS_INT_BASE + 28) -#define ATLAS_INT_RES29 (ATLAS_INT_BASE + 29) -#define ATLAS_INT_RES30 (ATLAS_INT_BASE + 30) -#define ATLAS_INT_RES31 (ATLAS_INT_BASE + 31) -#define ATLAS_INT_END (ATLAS_INT_BASE + 31) - -/* - * Interrupts 64..127 are used for Soc-it Classic interrupts - */ -#define MSC01C_INT_BASE 64 - -/* SOC-it Classic interrupt offsets */ -#define MSC01C_INT_TMR 0 -#define MSC01C_INT_PCI 1 - -/* - * Interrupts 64..127 are used for Soc-it EIC interrupts - */ -#define MSC01E_INT_BASE 64 - -/* SOC-it EIC interrupt offsets */ -#define MSC01E_INT_SW0 1 -#define MSC01E_INT_SW1 2 -#define MSC01E_INT_MB0 3 -#define MSC01E_INT_ATLAS MSC01E_INT_MB0 -#define MSC01E_INT_MB1 4 -#define MSC01E_INT_MB2 5 -#define MSC01E_INT_MB3 6 -#define MSC01E_INT_MB4 7 -#define MSC01E_INT_TMR 8 -#define MSC01E_INT_PCI 9 -#define MSC01E_INT_PERFCTR 10 -#define MSC01E_INT_CPUCTR 11 - -#endif /* !(_MIPS_ATLASINT_H) */ diff --git a/include/asm-mips/mips-boards/maltasmp.h b/include/asm-mips/mips-boards/maltasmp.h deleted file mode 100644 index 8d7e955d506e..000000000000 --- a/include/asm-mips/mips-boards/maltasmp.h +++ /dev/null @@ -1,36 +0,0 @@ -/* - * There are several SMP models supported - * SMTC is mutually exclusive to other options (atm) - */ -#if defined(CONFIG_MIPS_MT_SMTC) -#define malta_smtc 1 -#define malta_cmp 0 -#define malta_smvp 0 -#else -#define malta_smtc 0 -#if defined(CONFIG_MIPS_CMP) -extern int gcmp_present; -#define malta_cmp gcmp_present -#else -#define malta_cmp 0 -#endif -/* FIXME: should become COMFIG_MIPS_MT_SMVP */ -#if defined(CONFIG_MIPS_MT_SMP) -#define malta_smvp 1 -#else -#define malta_smvp 0 -#endif -#endif - -#include <asm/mipsregs.h> -#include <asm/mipsmtregs.h> - -/* malta_smtc */ -#include <asm/smtc.h> -#include <asm/smtc_ipi.h> - -/* malta_cmp */ -#include <asm/cmp.h> - -/* malta_smvp */ -#include <asm/smvp.h> diff --git a/include/asm-mips/mips-boards/saa9730_uart.h b/include/asm-mips/mips-boards/saa9730_uart.h deleted file mode 100644 index c913143d58ec..000000000000 --- a/include/asm-mips/mips-boards/saa9730_uart.h +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Carsten Langgaard, carstenl@mips.com - * Copyright (C) 2000 MIPS Technologies, Inc. All rights reserved. - * - * ######################################################################## - * - * This program is free software; you can distribute 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 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. - * - * ######################################################################## - * - * Register definitions for the UART part of the Philips SAA9730 chip. - * - */ - -#ifndef SAA9730_UART_H -#define SAA9730_UART_H - -/* The SAA9730 UART register map, as seen via the PCI bus */ - -#define SAA9730_UART_REGS_ADDR 0x21800 - -struct uart_saa9730_regmap { - volatile unsigned char Thr_Rbr; - volatile unsigned char Ier; - volatile unsigned char Iir_Fcr; - volatile unsigned char Lcr; - volatile unsigned char Mcr; - volatile unsigned char Lsr; - volatile unsigned char Msr; - volatile unsigned char Scr; - volatile unsigned char BaudDivLsb; - volatile unsigned char BaudDivMsb; - volatile unsigned char Junk0; - volatile unsigned char Junk1; - volatile unsigned int Config; /* 0x2180c */ - volatile unsigned int TxStart; /* 0x21810 */ - volatile unsigned int TxLength; /* 0x21814 */ - volatile unsigned int TxCounter; /* 0x21818 */ - volatile unsigned int RxStart; /* 0x2181c */ - volatile unsigned int RxLength; /* 0x21820 */ - volatile unsigned int RxCounter; /* 0x21824 */ -}; -typedef volatile struct uart_saa9730_regmap t_uart_saa9730_regmap; - -/* - * Only a subset of the UART control bits are defined here, - * enough to make the serial debug port work. - */ - -#define SAA9730_LCR_DATA8 0x03 - -#define SAA9730_MCR_DTR 0x01 -#define SAA9730_MCR_RTS 0x02 - -#define SAA9730_LSR_DR 0x01 -#define SAA9730_LSR_THRE 0x20 - -#endif /* !(SAA9730_UART_H) */ diff --git a/include/asm-mips/mips-boards/sead.h b/include/asm-mips/mips-boards/sead.h deleted file mode 100644 index 68c69de0b66f..000000000000 --- a/include/asm-mips/mips-boards/sead.h +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Carsten Langgaard, carstenl@mips.com - * Copyright (C) 2002 MIPS Technologies, Inc. All rights reserved. - * - * ######################################################################## - * - * This program is free software; you can distribute 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 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. - * - * ######################################################################## - * - * Defines of the SEAD board specific address-MAP, registers, etc. - * - */ -#ifndef _MIPS_SEAD_H -#define _MIPS_SEAD_H - -#include <asm/addrspace.h> - -/* - * SEAD UART register base. - */ -#define SEAD_UART0_REGS_BASE (0x1f000800) -#define SEAD_BASE_BAUD ( 3686400 / 16 ) - -#endif /* !(_MIPS_SEAD_H) */ diff --git a/include/asm-mips/mips-boards/seadint.h b/include/asm-mips/mips-boards/seadint.h deleted file mode 100644 index e710bae07340..000000000000 --- a/include/asm-mips/mips-boards/seadint.h +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Carsten Langgaard, carstenl@mips.com - * Copyright (C) 2002 MIPS Technologies, Inc. All rights reserved. - * - * This program is free software; you can distribute 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 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. - * - * Defines for the SEAD interrupt controller. - */ -#ifndef _MIPS_SEADINT_H -#define _MIPS_SEADINT_H - -#include <irq.h> - -#define MIPSCPU_INT_UART0 2 -#define MIPSCPU_INT_UART1 3 - -#endif /* !(_MIPS_SEADINT_H) */ diff --git a/include/asm-mips/page.h b/include/asm-mips/page.h index 8735aa0b8963..494f00ba9541 100644 --- a/include/asm-mips/page.h +++ b/include/asm-mips/page.h @@ -34,6 +34,9 @@ #include <linux/pfn.h> #include <asm/io.h> +extern void build_clear_page(void); +extern void build_copy_page(void); + /* * It's normally defined only for FLATMEM config but it's * used in our early mem init code for all memory models. diff --git a/include/asm-mips/pci.h b/include/asm-mips/pci.h index d3be83436070..c205875d7f31 100644 --- a/include/asm-mips/pci.h +++ b/include/asm-mips/pci.h @@ -173,6 +173,5 @@ static inline int pci_get_legacy_ide_irq(struct pci_dev *dev, int channel) } extern int pci_probe_only; -extern unsigned int pcibios_max_latency; #endif /* _ASM_PCI_H */ diff --git a/include/asm-mips/setup.h b/include/asm-mips/setup.h index 883f59bfa097..e600cedda976 100644 --- a/include/asm-mips/setup.h +++ b/include/asm-mips/setup.h @@ -3,6 +3,8 @@ #define COMMAND_LINE_SIZE 256 +#ifdef __KERNEL__ extern void setup_early_printk(void); +#endif /* __KERNEL__ */ #endif /* __SETUP_H */ diff --git a/include/asm-mips/txx9/generic.h b/include/asm-mips/txx9/generic.h index d8756660523d..cbae37ec3d88 100644 --- a/include/asm-mips/txx9/generic.h +++ b/include/asm-mips/txx9/generic.h @@ -12,6 +12,8 @@ #include <linux/ioport.h> /* for struct resource */ extern struct resource txx9_ce_res[]; +#define TXX9_CE(n) (unsigned long)(txx9_ce_res[(n)].start) +extern unsigned int txx9_pcode; extern char txx9_pcode_str[8]; void txx9_reg_res_init(unsigned int pcode, unsigned long base, unsigned long size); @@ -19,6 +21,11 @@ void txx9_reg_res_init(unsigned int pcode, unsigned long base, extern unsigned int txx9_master_clock; extern unsigned int txx9_cpu_clock; extern unsigned int txx9_gbus_clock; +#define TXX9_IMCLK (txx9_gbus_clock / 2) + +extern int txx9_ccfg_toeon; +struct uart_port; +int early_serial_txx9_setup(struct uart_port *port); struct pci_dev; struct txx9_board_vec { diff --git a/include/asm-mips/txx9/rbtx4927.h b/include/asm-mips/txx9/rbtx4927.h index bf194589216f..6fcec912c143 100644 --- a/include/asm-mips/txx9/rbtx4927.h +++ b/include/asm-mips/txx9/rbtx4927.h @@ -34,7 +34,23 @@ #define RBTX4927_PCIIO 0x16000000 #define RBTX4927_PCIIO_SIZE 0x01000000 -#define rbtx4927_pcireset_addr ((__u8 __iomem *)0xbc00f006UL) +#define RBTX4927_IMASK_ADDR (IO_BASE + TXX9_CE(2) + 0x00002000) +#define RBTX4927_IMSTAT_ADDR (IO_BASE + TXX9_CE(2) + 0x00002006) +#define RBTX4927_SOFTRESET_ADDR (IO_BASE + TXX9_CE(2) + 0x0000f000) +#define RBTX4927_SOFTRESETLOCK_ADDR (IO_BASE + TXX9_CE(2) + 0x0000f002) +#define RBTX4927_PCIRESET_ADDR (IO_BASE + TXX9_CE(2) + 0x0000f006) +#define RBTX4927_BRAMRTC_BASE (IO_BASE + TXX9_CE(2) + 0x00010000) +#define RBTX4927_ETHER_BASE (IO_BASE + TXX9_CE(2) + 0x00020000) + +/* Ethernet port address */ +#define RBTX4927_ETHER_ADDR (RBTX4927_ETHER_BASE + 0x280) + +#define rbtx4927_imask_addr ((__u8 __iomem *)RBTX4927_IMASK_ADDR) +#define rbtx4927_imstat_addr ((__u8 __iomem *)RBTX4927_IMSTAT_ADDR) +#define rbtx4927_softreset_addr ((__u8 __iomem *)RBTX4927_SOFTRESET_ADDR) +#define rbtx4927_softresetlock_addr \ + ((__u8 __iomem *)RBTX4927_SOFTRESETLOCK_ADDR) +#define rbtx4927_pcireset_addr ((__u8 __iomem *)RBTX4927_PCIRESET_ADDR) /* bits for ISTAT/IMASK/IMSTAT */ #define RBTX4927_INTB_PCID 0 @@ -62,13 +78,7 @@ #define RBTX4927_ISA_IO_OFFSET 0 #endif -#define RBTX4927_SW_RESET_DO (void __iomem *)0xbc00f000UL -#define RBTX4927_SW_RESET_DO_SET 0x01 - -#define RBTX4927_SW_RESET_ENABLE (void __iomem *)0xbc00f002UL -#define RBTX4927_SW_RESET_ENABLE_SET 0x01 - -#define RBTX4927_RTL_8019_BASE (0x1c020280 - RBTX4927_ISA_IO_OFFSET) +#define RBTX4927_RTL_8019_BASE (RBTX4927_ETHER_ADDR - mips_io_port_base) #define RBTX4927_RTL_8019_IRQ (TXX9_IRQ_BASE + TX4927_IR_INT(3)) void rbtx4927_prom_init(void); diff --git a/include/asm-mips/txx9/rbtx4938.h b/include/asm-mips/txx9/rbtx4938.h index 2f5d5e705a41..9f0441a28126 100644 --- a/include/asm-mips/txx9/rbtx4938.h +++ b/include/asm-mips/txx9/rbtx4938.h @@ -15,35 +15,31 @@ #include <asm/txx9irq.h> #include <asm/txx9/tx4938.h> -/* CS */ -#define RBTX4938_CE0 0x1c000000 /* 64M */ -#define RBTX4938_CE2 0x17f00000 /* 1M */ - /* Address map */ -#define RBTX4938_FPGA_REG_ADDR (KSEG1 + RBTX4938_CE2 + 0x00000000) -#define RBTX4938_FPGA_REV_ADDR (KSEG1 + RBTX4938_CE2 + 0x00000002) -#define RBTX4938_CONFIG1_ADDR (KSEG1 + RBTX4938_CE2 + 0x00000004) -#define RBTX4938_CONFIG2_ADDR (KSEG1 + RBTX4938_CE2 + 0x00000006) -#define RBTX4938_CONFIG3_ADDR (KSEG1 + RBTX4938_CE2 + 0x00000008) -#define RBTX4938_LED_ADDR (KSEG1 + RBTX4938_CE2 + 0x00001000) -#define RBTX4938_DIPSW_ADDR (KSEG1 + RBTX4938_CE2 + 0x00001002) -#define RBTX4938_BDIPSW_ADDR (KSEG1 + RBTX4938_CE2 + 0x00001004) -#define RBTX4938_IMASK_ADDR (KSEG1 + RBTX4938_CE2 + 0x00002000) -#define RBTX4938_IMASK2_ADDR (KSEG1 + RBTX4938_CE2 + 0x00002002) -#define RBTX4938_INTPOL_ADDR (KSEG1 + RBTX4938_CE2 + 0x00002004) -#define RBTX4938_ISTAT_ADDR (KSEG1 + RBTX4938_CE2 + 0x00002006) -#define RBTX4938_ISTAT2_ADDR (KSEG1 + RBTX4938_CE2 + 0x00002008) -#define RBTX4938_IMSTAT_ADDR (KSEG1 + RBTX4938_CE2 + 0x0000200a) -#define RBTX4938_IMSTAT2_ADDR (KSEG1 + RBTX4938_CE2 + 0x0000200c) -#define RBTX4938_SOFTINT_ADDR (KSEG1 + RBTX4938_CE2 + 0x00003000) -#define RBTX4938_PIOSEL_ADDR (KSEG1 + RBTX4938_CE2 + 0x00005000) -#define RBTX4938_SPICS_ADDR (KSEG1 + RBTX4938_CE2 + 0x00005002) -#define RBTX4938_SFPWR_ADDR (KSEG1 + RBTX4938_CE2 + 0x00005008) -#define RBTX4938_SFVOL_ADDR (KSEG1 + RBTX4938_CE2 + 0x0000500a) -#define RBTX4938_SOFTRESET_ADDR (KSEG1 + RBTX4938_CE2 + 0x00007000) -#define RBTX4938_SOFTRESETLOCK_ADDR (KSEG1 + RBTX4938_CE2 + 0x00007002) -#define RBTX4938_PCIRESET_ADDR (KSEG1 + RBTX4938_CE2 + 0x00007004) -#define RBTX4938_ETHER_BASE (KSEG1 + RBTX4938_CE2 + 0x00020000) +#define RBTX4938_FPGA_REG_ADDR (IO_BASE + TXX9_CE(2) + 0x00000000) +#define RBTX4938_FPGA_REV_ADDR (IO_BASE + TXX9_CE(2) + 0x00000002) +#define RBTX4938_CONFIG1_ADDR (IO_BASE + TXX9_CE(2) + 0x00000004) +#define RBTX4938_CONFIG2_ADDR (IO_BASE + TXX9_CE(2) + 0x00000006) +#define RBTX4938_CONFIG3_ADDR (IO_BASE + TXX9_CE(2) + 0x00000008) +#define RBTX4938_LED_ADDR (IO_BASE + TXX9_CE(2) + 0x00001000) +#define RBTX4938_DIPSW_ADDR (IO_BASE + TXX9_CE(2) + 0x00001002) +#define RBTX4938_BDIPSW_ADDR (IO_BASE + TXX9_CE(2) + 0x00001004) +#define RBTX4938_IMASK_ADDR (IO_BASE + TXX9_CE(2) + 0x00002000) +#define RBTX4938_IMASK2_ADDR (IO_BASE + TXX9_CE(2) + 0x00002002) +#define RBTX4938_INTPOL_ADDR (IO_BASE + TXX9_CE(2) + 0x00002004) +#define RBTX4938_ISTAT_ADDR (IO_BASE + TXX9_CE(2) + 0x00002006) +#define RBTX4938_ISTAT2_ADDR (IO_BASE + TXX9_CE(2) + 0x00002008) +#define RBTX4938_IMSTAT_ADDR (IO_BASE + TXX9_CE(2) + 0x0000200a) +#define RBTX4938_IMSTAT2_ADDR (IO_BASE + TXX9_CE(2) + 0x0000200c) +#define RBTX4938_SOFTINT_ADDR (IO_BASE + TXX9_CE(2) + 0x00003000) +#define RBTX4938_PIOSEL_ADDR (IO_BASE + TXX9_CE(2) + 0x00005000) +#define RBTX4938_SPICS_ADDR (IO_BASE + TXX9_CE(2) + 0x00005002) +#define RBTX4938_SFPWR_ADDR (IO_BASE + TXX9_CE(2) + 0x00005008) +#define RBTX4938_SFVOL_ADDR (IO_BASE + TXX9_CE(2) + 0x0000500a) +#define RBTX4938_SOFTRESET_ADDR (IO_BASE + TXX9_CE(2) + 0x00007000) +#define RBTX4938_SOFTRESETLOCK_ADDR (IO_BASE + TXX9_CE(2) + 0x00007002) +#define RBTX4938_PCIRESET_ADDR (IO_BASE + TXX9_CE(2) + 0x00007004) +#define RBTX4938_ETHER_BASE (IO_BASE + TXX9_CE(2) + 0x00020000) /* Ethernet port address (Jumperless Mode (W12:Open)) */ #define RBTX4938_ETHER_ADDR (RBTX4938_ETHER_BASE + 0x280) diff --git a/include/asm-mips/txx9/tx3927.h b/include/asm-mips/txx9/tx3927.h index ca414c7624e1..ea79e1b16e71 100644 --- a/include/asm-mips/txx9/tx3927.h +++ b/include/asm-mips/txx9/tx3927.h @@ -10,17 +10,18 @@ #include <asm/txx9/txx927.h> -#define TX3927_SDRAMC_REG 0xfffe8000 -#define TX3927_ROMC_REG 0xfffe9000 -#define TX3927_DMA_REG 0xfffeb000 -#define TX3927_IRC_REG 0xfffec000 -#define TX3927_PCIC_REG 0xfffed000 -#define TX3927_CCFG_REG 0xfffee000 +#define TX3927_REG_BASE 0xfffe0000UL +#define TX3927_SDRAMC_REG (TX3927_REG_BASE + 0x8000) +#define TX3927_ROMC_REG (TX3927_REG_BASE + 0x9000) +#define TX3927_DMA_REG (TX3927_REG_BASE + 0xb000) +#define TX3927_IRC_REG (TX3927_REG_BASE + 0xc000) +#define TX3927_PCIC_REG (TX3927_REG_BASE + 0xd000) +#define TX3927_CCFG_REG (TX3927_REG_BASE + 0xe000) #define TX3927_NR_TMR 3 -#define TX3927_TMR_REG(ch) (0xfffef000 + (ch) * 0x100) +#define TX3927_TMR_REG(ch) (TX3927_REG_BASE + 0xf000 + (ch) * 0x100) #define TX3927_NR_SIO 2 -#define TX3927_SIO_REG(ch) (0xfffef300 + (ch) * 0x100) -#define TX3927_PIO_REG 0xfffef500 +#define TX3927_SIO_REG(ch) (TX3927_REG_BASE + 0xf300 + (ch) * 0x100) +#define TX3927_PIO_REG (TX3927_REG_BASE + 0xf500) struct tx3927_sdramc_reg { volatile unsigned long cr[8]; diff --git a/include/asm-mips/txx9/tx4927.h b/include/asm-mips/txx9/tx4927.h index 46d60afc038b..ceb4b79ff4e3 100644 --- a/include/asm-mips/txx9/tx4927.h +++ b/include/asm-mips/txx9/tx4927.h @@ -32,32 +32,46 @@ #include <asm/txx9irq.h> #include <asm/txx9/tx4927pcic.h> -#define TX4927_SDRAMC_REG 0xff1f8000 -#define TX4927_EBUSC_REG 0xff1f9000 -#define TX4927_PCIC_REG 0xff1fd000 -#define TX4927_CCFG_REG 0xff1fe000 -#define TX4927_IRC_REG 0xff1ff600 +#ifdef CONFIG_64BIT +#define TX4927_REG_BASE 0xffffffffff1f0000UL +#else +#define TX4927_REG_BASE 0xff1f0000UL +#endif +#define TX4927_REG_SIZE 0x00010000 + +#define TX4927_SDRAMC_REG (TX4927_REG_BASE + 0x8000) +#define TX4927_EBUSC_REG (TX4927_REG_BASE + 0x9000) +#define TX4927_PCIC_REG (TX4927_REG_BASE + 0xd000) +#define TX4927_CCFG_REG (TX4927_REG_BASE + 0xe000) +#define TX4927_IRC_REG (TX4927_REG_BASE + 0xf600) #define TX4927_NR_TMR 3 -#define TX4927_TMR_REG(ch) (0xff1ff000 + (ch) * 0x100) +#define TX4927_TMR_REG(ch) (TX4927_REG_BASE + 0xf000 + (ch) * 0x100) +#define TX4927_NR_SIO 2 +#define TX4927_SIO_REG(ch) (TX4927_REG_BASE + 0xf300 + (ch) * 0x100) +#define TX4927_PIO_REG (TX4927_REG_BASE + 0xf500) #define TX4927_IR_INT(n) (2 + (n)) #define TX4927_IR_SIO(n) (8 + (n)) #define TX4927_IR_PCIC 16 +#define TX4927_NUM_IR_TMR 3 +#define TX4927_IR_TMR(n) (17 + (n)) #define TX4927_IR_PCIERR 22 #define TX4927_NUM_IR 32 #define TX4927_IRC_INT 2 /* IP[2] in Status register */ +#define TX4927_NUM_PIO 16 + struct tx4927_sdramc_reg { - volatile unsigned long long cr[4]; - volatile unsigned long long unused0[4]; - volatile unsigned long long tr; - volatile unsigned long long unused1[2]; - volatile unsigned long long cmd; + u64 cr[4]; + u64 unused0[4]; + u64 tr; + u64 unused1[2]; + u64 cmd; }; struct tx4927_ebusc_reg { - volatile unsigned long long cr[8]; + u64 cr[8]; }; struct tx4927_ccfg_reg { @@ -160,12 +174,28 @@ struct tx4927_ccfg_reg { #define TX4927_CLKCTR_SIO0RST 0x00000002 #define TX4927_CLKCTR_SIO1RST 0x00000001 -#define tx4927_sdramcptr ((struct tx4927_sdramc_reg *)TX4927_SDRAMC_REG) +#define tx4927_sdramcptr \ + ((struct tx4927_sdramc_reg __iomem *)TX4927_SDRAMC_REG) #define tx4927_pcicptr \ ((struct tx4927_pcic_reg __iomem *)TX4927_PCIC_REG) #define tx4927_ccfgptr \ ((struct tx4927_ccfg_reg __iomem *)TX4927_CCFG_REG) -#define tx4927_ebuscptr ((struct tx4927_ebusc_reg *)TX4927_EBUSC_REG) +#define tx4927_ebuscptr \ + ((struct tx4927_ebusc_reg __iomem *)TX4927_EBUSC_REG) +#define tx4927_pioptr ((struct txx9_pio_reg __iomem *)TX4927_PIO_REG) + +#define TX4927_REV_PCODE() \ + ((__u32)__raw_readq(&tx4927_ccfgptr->crir) >> 16) + +#define TX4927_SDRAMC_CR(ch) __raw_readq(&tx4927_sdramcptr->cr[(ch)]) +#define TX4927_SDRAMC_BA(ch) ((TX4927_SDRAMC_CR(ch) >> 49) << 21) +#define TX4927_SDRAMC_SIZE(ch) \ + ((((TX4927_SDRAMC_CR(ch) >> 33) & 0x7fff) + 1) << 21) + +#define TX4927_EBUSC_CR(ch) __raw_readq(&tx4927_ebuscptr->cr[(ch)]) +#define TX4927_EBUSC_BA(ch) ((TX4927_EBUSC_CR(ch) >> 48) << 20) +#define TX4927_EBUSC_SIZE(ch) \ + (0x00100000 << ((unsigned long)(TX4927_EBUSC_CR(ch) >> 8) & 0xf)) /* utilities */ static inline void txx9_clear64(__u64 __iomem *adr, __u64 bits) @@ -212,6 +242,11 @@ static inline void tx4927_ccfg_change(__u64 change, __u64 new) &tx4927_ccfgptr->ccfg); } +unsigned int tx4927_get_mem_size(void); +void tx4927_wdr_init(void); +void tx4927_setup(void); +void tx4927_time_init(unsigned int tmrnr); +void tx4927_setup_serial(void); int tx4927_report_pciclk(void); int tx4927_pciclk66_setup(void); void tx4927_irq_init(void); diff --git a/include/asm-mips/txx9/tx4938.h b/include/asm-mips/txx9/tx4938.h index 12de68a4c10a..1ed969d381d6 100644 --- a/include/asm-mips/txx9/tx4938.h +++ b/include/asm-mips/txx9/tx4938.h @@ -15,20 +15,11 @@ /* some controllers are compatible with 4927 */ #include <asm/txx9/tx4927.h> -#define tx4938_read_nfmc(addr) (*(volatile unsigned int *)(addr)) -#define tx4938_write_nfmc(b, addr) (*(volatile unsigned int *)(addr)) = (b) - -#define TX4938_PCIIO_0 0x10000000 -#define TX4938_PCIIO_1 0x01010000 -#define TX4938_PCIMEM_0 0x08000000 -#define TX4938_PCIMEM_1 0x11000000 - -#define TX4938_PCIIO_SIZE_0 0x01000000 -#define TX4938_PCIIO_SIZE_1 0x00010000 -#define TX4938_PCIMEM_SIZE_0 0x08000000 -#define TX4938_PCIMEM_SIZE_1 0x00010000 - -#define TX4938_REG_BASE 0xff1f0000 /* == TX4937_REG_BASE */ +#ifdef CONFIG_64BIT +#define TX4938_REG_BASE 0xffffffffff1f0000UL /* == TX4937_REG_BASE */ +#else +#define TX4938_REG_BASE 0xff1f0000UL /* == TX4937_REG_BASE */ +#endif #define TX4938_REG_SIZE 0x00010000 /* == TX4937_REG_SIZE */ /* NDFMC, SRAMC, PCIC1, SPIC: TX4938 only */ @@ -49,149 +40,8 @@ #define TX4938_ACLC_REG (TX4938_REG_BASE + 0xf700) #define TX4938_SPI_REG (TX4938_REG_BASE + 0xf800) -#define _CONST64(c) c##ull - -#include <asm/byteorder.h> - -#ifdef __BIG_ENDIAN -#define endian_def_l2(e1, e2) \ - volatile unsigned long e1, e2 -#define endian_def_s2(e1, e2) \ - volatile unsigned short e1, e2 -#define endian_def_sb2(e1, e2, e3) \ - volatile unsigned short e1;volatile unsigned char e2, e3 -#define endian_def_b2s(e1, e2, e3) \ - volatile unsigned char e1, e2;volatile unsigned short e3 -#define endian_def_b4(e1, e2, e3, e4) \ - volatile unsigned char e1, e2, e3, e4 -#else -#define endian_def_l2(e1, e2) \ - volatile unsigned long e2, e1 -#define endian_def_s2(e1, e2) \ - volatile unsigned short e2, e1 -#define endian_def_sb2(e1, e2, e3) \ - volatile unsigned char e3, e2;volatile unsigned short e1 -#define endian_def_b2s(e1, e2, e3) \ - volatile unsigned short e3;volatile unsigned char e2, e1 -#define endian_def_b4(e1, e2, e3, e4) \ - volatile unsigned char e4, e3, e2, e1 -#endif - - -struct tx4938_sdramc_reg { - volatile unsigned long long cr[4]; - volatile unsigned long long unused0[4]; - volatile unsigned long long tr; - volatile unsigned long long unused1[2]; - volatile unsigned long long cmd; - volatile unsigned long long sfcmd; -}; - -struct tx4938_ebusc_reg { - volatile unsigned long long cr[8]; -}; - -struct tx4938_dma_reg { - struct tx4938_dma_ch_reg { - volatile unsigned long long cha; - volatile unsigned long long sar; - volatile unsigned long long dar; - endian_def_l2(unused0, cntr); - endian_def_l2(unused1, sair); - endian_def_l2(unused2, dair); - endian_def_l2(unused3, ccr); - endian_def_l2(unused4, csr); - } ch[4]; - volatile unsigned long long dbr[8]; - volatile unsigned long long tdhr; - volatile unsigned long long midr; - endian_def_l2(unused0, mcr); -}; - -struct tx4938_aclc_reg { - volatile unsigned long acctlen; - volatile unsigned long acctldis; - volatile unsigned long acregacc; - volatile unsigned long unused0; - volatile unsigned long acintsts; - volatile unsigned long acintmsts; - volatile unsigned long acinten; - volatile unsigned long acintdis; - volatile unsigned long acsemaph; - volatile unsigned long unused1[7]; - volatile unsigned long acgpidat; - volatile unsigned long acgpodat; - volatile unsigned long acslten; - volatile unsigned long acsltdis; - volatile unsigned long acfifosts; - volatile unsigned long unused2[11]; - volatile unsigned long acdmasts; - volatile unsigned long acdmasel; - volatile unsigned long unused3[6]; - volatile unsigned long acaudodat; - volatile unsigned long acsurrdat; - volatile unsigned long accentdat; - volatile unsigned long aclfedat; - volatile unsigned long acaudiat; - volatile unsigned long unused4; - volatile unsigned long acmodoat; - volatile unsigned long acmodidat; - volatile unsigned long unused5[15]; - volatile unsigned long acrevid; -}; - - -struct tx4938_tmr_reg { - volatile unsigned long tcr; - volatile unsigned long tisr; - volatile unsigned long cpra; - volatile unsigned long cprb; - volatile unsigned long itmr; - volatile unsigned long unused0[3]; - volatile unsigned long ccdr; - volatile unsigned long unused1[3]; - volatile unsigned long pgmr; - volatile unsigned long unused2[3]; - volatile unsigned long wtmr; - volatile unsigned long unused3[43]; - volatile unsigned long trr; -}; - -struct tx4938_sio_reg { - volatile unsigned long lcr; - volatile unsigned long dicr; - volatile unsigned long disr; - volatile unsigned long cisr; - volatile unsigned long fcr; - volatile unsigned long flcr; - volatile unsigned long bgr; - volatile unsigned long tfifo; - volatile unsigned long rfifo; -}; - -struct tx4938_ndfmc_reg { - endian_def_l2(unused0, dtr); - endian_def_l2(unused1, mcr); - endian_def_l2(unused2, sr); - endian_def_l2(unused3, isr); - endian_def_l2(unused4, imr); - endian_def_l2(unused5, spr); - endian_def_l2(unused6, rstr); -}; - -struct tx4938_spi_reg { - volatile unsigned long mcr; - volatile unsigned long cr0; - volatile unsigned long cr1; - volatile unsigned long fs; - volatile unsigned long unused1; - volatile unsigned long sr; - volatile unsigned long dr; - volatile unsigned long unused2; -}; - struct tx4938_sramc_reg { - volatile unsigned long long cr; + u64 cr; }; struct tx4938_ccfg_reg { @@ -209,34 +59,6 @@ struct tx4938_ccfg_reg { u64 jmpadr; }; -#undef endian_def_l2 -#undef endian_def_s2 -#undef endian_def_sb2 -#undef endian_def_b2s -#undef endian_def_b4 - -/* - * NDFMC - */ - -/* NDFMCR : NDFMC Mode Control */ -#define TX4938_NDFMCR_WE 0x80 -#define TX4938_NDFMCR_ECC_ALL 0x60 -#define TX4938_NDFMCR_ECC_RESET 0x60 -#define TX4938_NDFMCR_ECC_READ 0x40 -#define TX4938_NDFMCR_ECC_ON 0x20 -#define TX4938_NDFMCR_ECC_OFF 0x00 -#define TX4938_NDFMCR_CE 0x10 -#define TX4938_NDFMCR_BSPRT 0x04 -#define TX4938_NDFMCR_ALE 0x02 -#define TX4938_NDFMCR_CLE 0x01 - -/* NDFMCR : NDFMC Status */ -#define TX4938_NDFSR_BUSY 0x80 - -/* NDFMCR : NDFMC Reset */ -#define TX4938_NDFRSTR_RST 0x01 - /* * IRC */ @@ -268,13 +90,15 @@ struct tx4938_ccfg_reg { #define TX4938_IRC_INT 2 /* IP[2] in Status register */ +#define TX4938_NUM_PIO 16 + /* * CCFG */ /* CCFG : Chip Configuration */ -#define TX4938_CCFG_WDRST _CONST64(0x0000020000000000) -#define TX4938_CCFG_WDREXEN _CONST64(0x0000010000000000) -#define TX4938_CCFG_BCFG_MASK _CONST64(0x000000ff00000000) +#define TX4938_CCFG_WDRST 0x0000020000000000ULL +#define TX4938_CCFG_WDREXEN 0x0000010000000000ULL +#define TX4938_CCFG_BCFG_MASK 0x000000ff00000000ULL #define TX4938_CCFG_TINTDIS 0x01000000 #define TX4938_CCFG_PCI66 0x00800000 #define TX4938_CCFG_PCIMODE 0x00400000 @@ -310,12 +134,12 @@ struct tx4938_ccfg_reg { #define TX4938_CCFG_ACEHOLD 0x00000001 /* PCFG : Pin Configuration */ -#define TX4938_PCFG_ETH0_SEL _CONST64(0x8000000000000000) -#define TX4938_PCFG_ETH1_SEL _CONST64(0x4000000000000000) -#define TX4938_PCFG_ATA_SEL _CONST64(0x2000000000000000) -#define TX4938_PCFG_ISA_SEL _CONST64(0x1000000000000000) -#define TX4938_PCFG_SPI_SEL _CONST64(0x0800000000000000) -#define TX4938_PCFG_NDF_SEL _CONST64(0x0400000000000000) +#define TX4938_PCFG_ETH0_SEL 0x8000000000000000ULL +#define TX4938_PCFG_ETH1_SEL 0x4000000000000000ULL +#define TX4938_PCFG_ATA_SEL 0x2000000000000000ULL +#define TX4938_PCFG_ISA_SEL 0x1000000000000000ULL +#define TX4938_PCFG_SPI_SEL 0x0800000000000000ULL +#define TX4938_PCFG_NDF_SEL 0x0400000000000000ULL #define TX4938_PCFG_SDCLKDLY_MASK 0x30000000 #define TX4938_PCFG_SDCLKDLY(d) ((d)<<28) #define TX4938_PCFG_SYSCLKEN 0x08000000 @@ -336,8 +160,8 @@ struct tx4938_ccfg_reg { #define TX4938_PCFG_DMASEL3_SIO0 0x00000008 /* CLKCTR : Clock Control */ -#define TX4938_CLKCTR_NDFCKD _CONST64(0x0001000000000000) -#define TX4938_CLKCTR_NDFRST _CONST64(0x0000000100000000) +#define TX4938_CLKCTR_NDFCKD 0x0001000000000000ULL +#define TX4938_CLKCTR_NDFRST 0x0000000100000000ULL #define TX4938_CLKCTR_ETH1CKD 0x80000000 #define TX4938_CLKCTR_ETH0CKD 0x40000000 #define TX4938_CLKCTR_SPICKD 0x20000000 @@ -424,20 +248,16 @@ struct tx4938_ccfg_reg { #define TX4938_DMA_CSR_DESERR 0x00000002 #define TX4938_DMA_CSR_SORERR 0x00000001 -#define tx4938_sdramcptr ((struct tx4938_sdramc_reg *)TX4938_SDRAMC_REG) -#define tx4938_ebuscptr ((struct tx4938_ebusc_reg *)TX4938_EBUSC_REG) -#define tx4938_dmaptr(ch) ((struct tx4938_dma_reg *)TX4938_DMA_REG(ch)) -#define tx4938_ndfmcptr ((struct tx4938_ndfmc_reg *)TX4938_NDFMC_REG) +#define tx4938_sdramcptr tx4927_sdramcptr +#define tx4938_ebuscptr tx4927_ebuscptr #define tx4938_pcicptr tx4927_pcicptr #define tx4938_pcic1ptr \ ((struct tx4927_pcic_reg __iomem *)TX4938_PCIC1_REG) #define tx4938_ccfgptr \ ((struct tx4938_ccfg_reg __iomem *)TX4938_CCFG_REG) -#define tx4938_sioptr(ch) ((struct tx4938_sio_reg *)TX4938_SIO_REG(ch)) #define tx4938_pioptr ((struct txx9_pio_reg __iomem *)TX4938_PIO_REG) -#define tx4938_aclcptr ((struct tx4938_aclc_reg *)TX4938_ACLC_REG) -#define tx4938_spiptr ((struct tx4938_spi_reg *)TX4938_SPI_REG) -#define tx4938_sramcptr ((struct tx4938_sramc_reg *)TX4938_SRAMC_REG) +#define tx4938_sramcptr \ + ((struct tx4938_sramc_reg __iomem *)TX4938_SRAMC_REG) #define TX4938_REV_PCODE() \ @@ -447,14 +267,19 @@ struct tx4938_ccfg_reg { #define tx4938_ccfg_set(bits) tx4927_ccfg_set(bits) #define tx4938_ccfg_change(change, new) tx4927_ccfg_change(change, new) -#define TX4938_SDRAMC_BA(ch) ((tx4938_sdramcptr->cr[ch] >> 49) << 21) -#define TX4938_SDRAMC_SIZE(ch) (((tx4938_sdramcptr->cr[ch] >> 33) + 1) << 21) +#define TX4938_SDRAMC_CR(ch) TX4927_SDRAMC_CR(ch) +#define TX4938_SDRAMC_BA(ch) TX4927_SDRAMC_BA(ch) +#define TX4938_SDRAMC_SIZE(ch) TX4927_SDRAMC_SIZE(ch) -#define TX4938_EBUSC_CR(ch) __raw_readq(&tx4938_ebuscptr->cr[(ch)]) -#define TX4938_EBUSC_BA(ch) ((tx4938_ebuscptr->cr[ch] >> 48) << 20) -#define TX4938_EBUSC_SIZE(ch) \ - (0x00100000 << ((unsigned long)(tx4938_ebuscptr->cr[ch] >> 8) & 0xf)) +#define TX4938_EBUSC_CR(ch) TX4927_EBUSC_CR(ch) +#define TX4938_EBUSC_BA(ch) TX4927_EBUSC_BA(ch) +#define TX4938_EBUSC_SIZE(ch) TX4927_EBUSC_SIZE(ch) +#define tx4938_get_mem_size() tx4927_get_mem_size() +void tx4938_wdr_init(void); +void tx4938_setup(void); +void tx4938_time_init(unsigned int tmrnr); +void tx4938_setup_serial(void); int tx4938_report_pciclk(void); void tx4938_report_pci1clk(void); int tx4938_pciclk66_setup(void); diff --git a/include/asm-powerpc/kvm_host.h b/include/asm-powerpc/kvm_host.h index 81a69d711017..2655e2a4831e 100644 --- a/include/asm-powerpc/kvm_host.h +++ b/include/asm-powerpc/kvm_host.h @@ -31,6 +31,8 @@ /* memory slots that does not exposed to userspace */ #define KVM_PRIVATE_MEM_SLOTS 4 +#define KVM_COALESCED_MMIO_PAGE_OFFSET 1 + /* We don't currently support large pages. */ #define KVM_PAGES_PER_HPAGE (1<<31) diff --git a/include/asm-s390/kvm_host.h b/include/asm-s390/kvm_host.h index 18cbd8a39796..3234dd5b3511 100644 --- a/include/asm-s390/kvm_host.h +++ b/include/asm-s390/kvm_host.h @@ -62,7 +62,7 @@ struct sca_block { #define CPUSTAT_J 0x00000002 #define CPUSTAT_P 0x00000001 -struct sie_block { +struct kvm_s390_sie_block { atomic_t cpuflags; /* 0x0000 */ __u32 prefix; /* 0x0004 */ __u8 reserved8[32]; /* 0x0008 */ @@ -140,14 +140,14 @@ struct kvm_vcpu_stat { u32 diagnose_44; }; -struct io_info { +struct kvm_s390_io_info { __u16 subchannel_id; /* 0x0b8 */ __u16 subchannel_nr; /* 0x0ba */ __u32 io_int_parm; /* 0x0bc */ __u32 io_int_word; /* 0x0c0 */ }; -struct ext_info { +struct kvm_s390_ext_info { __u32 ext_params; __u64 ext_params2; }; @@ -160,22 +160,22 @@ struct ext_info { #define PGM_SPECIFICATION 0x06 #define PGM_DATA 0x07 -struct pgm_info { +struct kvm_s390_pgm_info { __u16 code; }; -struct prefix_info { +struct kvm_s390_prefix_info { __u32 address; }; -struct interrupt_info { +struct kvm_s390_interrupt_info { struct list_head list; u64 type; union { - struct io_info io; - struct ext_info ext; - struct pgm_info pgm; - struct prefix_info prefix; + struct kvm_s390_io_info io; + struct kvm_s390_ext_info ext; + struct kvm_s390_pgm_info pgm; + struct kvm_s390_prefix_info prefix; }; }; @@ -183,35 +183,35 @@ struct interrupt_info { #define ACTION_STORE_ON_STOP 1 #define ACTION_STOP_ON_STOP 2 -struct local_interrupt { +struct kvm_s390_local_interrupt { spinlock_t lock; struct list_head list; atomic_t active; - struct float_interrupt *float_int; + struct kvm_s390_float_interrupt *float_int; int timer_due; /* event indicator for waitqueue below */ wait_queue_head_t wq; atomic_t *cpuflags; unsigned int action_bits; }; -struct float_interrupt { +struct kvm_s390_float_interrupt { spinlock_t lock; struct list_head list; atomic_t active; int next_rr_cpu; unsigned long idle_mask [(64 + sizeof(long) - 1) / sizeof(long)]; - struct local_interrupt *local_int[64]; + struct kvm_s390_local_interrupt *local_int[64]; }; struct kvm_vcpu_arch { - struct sie_block *sie_block; + struct kvm_s390_sie_block *sie_block; unsigned long guest_gprs[16]; s390_fp_regs host_fpregs; unsigned int host_acrs[NUM_ACRS]; s390_fp_regs guest_fpregs; unsigned int guest_acrs[NUM_ACRS]; - struct local_interrupt local_int; + struct kvm_s390_local_interrupt local_int; struct timer_list ckc_timer; union { cpuid_t cpu_id; @@ -228,8 +228,8 @@ struct kvm_arch{ unsigned long guest_memsize; struct sca_block *sca; debug_info_t *dbf; - struct float_interrupt float_int; + struct kvm_s390_float_interrupt float_int; }; -extern int sie64a(struct sie_block *, __u64 *); +extern int sie64a(struct kvm_s390_sie_block *, __u64 *); #endif diff --git a/include/asm-x86/amd_iommu_types.h b/include/asm-x86/amd_iommu_types.h index 7bfcb47cc452..22aa58ca1991 100644 --- a/include/asm-x86/amd_iommu_types.h +++ b/include/asm-x86/amd_iommu_types.h @@ -27,13 +27,12 @@ /* * some size calculation constants */ -#define DEV_TABLE_ENTRY_SIZE 256 +#define DEV_TABLE_ENTRY_SIZE 32 #define ALIAS_TABLE_ENTRY_SIZE 2 #define RLOOKUP_TABLE_ENTRY_SIZE (sizeof(void *)) /* helper macros */ #define LOW_U32(x) ((x) & ((1ULL << 32)-1)) -#define HIGH_U32(x) (LOW_U32((x) >> 32)) /* Length of the MMIO region for the AMD IOMMU */ #define MMIO_REGION_LENGTH 0x4000 @@ -158,78 +157,170 @@ #define MAX_DOMAIN_ID 65536 +/* + * This structure contains generic data for IOMMU protection domains + * independent of their use. + */ struct protection_domain { - spinlock_t lock; - u16 id; - int mode; - u64 *pt_root; - void *priv; + spinlock_t lock; /* mostly used to lock the page table*/ + u16 id; /* the domain id written to the device table */ + int mode; /* paging mode (0-6 levels) */ + u64 *pt_root; /* page table root pointer */ + void *priv; /* private data */ }; +/* + * Data container for a dma_ops specific protection domain + */ struct dma_ops_domain { struct list_head list; + + /* generic protection domain information */ struct protection_domain domain; + + /* size of the aperture for the mappings */ unsigned long aperture_size; + + /* address we start to search for free addresses */ unsigned long next_bit; + + /* address allocation bitmap */ unsigned long *bitmap; + + /* + * Array of PTE pages for the aperture. In this array we save all the + * leaf pages of the domain page table used for the aperture. This way + * we don't need to walk the page table to find a specific PTE. We can + * just calculate its address in constant time. + */ u64 **pte_pages; }; +/* + * Structure where we save information about one hardware AMD IOMMU in the + * system. + */ struct amd_iommu { struct list_head list; + + /* locks the accesses to the hardware */ spinlock_t lock; + /* device id of this IOMMU */ u16 devid; + /* + * Capability pointer. There could be more than one IOMMU per PCI + * device function if there are more than one AMD IOMMU capability + * pointers. + */ u16 cap_ptr; + /* physical address of MMIO space */ u64 mmio_phys; + /* virtual address of MMIO space */ u8 *mmio_base; + + /* capabilities of that IOMMU read from ACPI */ u32 cap; + + /* first device this IOMMU handles. read from PCI */ u16 first_device; + /* last device this IOMMU handles. read from PCI */ u16 last_device; + + /* start of exclusion range of that IOMMU */ u64 exclusion_start; + /* length of exclusion range of that IOMMU */ u64 exclusion_length; + /* command buffer virtual address */ u8 *cmd_buf; + /* size of command buffer */ u32 cmd_buf_size; + /* if one, we need to send a completion wait command */ int need_sync; + /* default dma_ops domain for that IOMMU */ struct dma_ops_domain *default_dom; }; +/* + * List with all IOMMUs in the system. This list is not locked because it is + * only written and read at driver initialization or suspend time + */ extern struct list_head amd_iommu_list; +/* + * Structure defining one entry in the device table + */ struct dev_table_entry { u32 data[8]; }; +/* + * One entry for unity mappings parsed out of the ACPI table. + */ struct unity_map_entry { struct list_head list; + + /* starting device id this entry is used for (including) */ u16 devid_start; + /* end device id this entry is used for (including) */ u16 devid_end; + + /* start address to unity map (including) */ u64 address_start; + /* end address to unity map (including) */ u64 address_end; + + /* required protection */ int prot; }; +/* + * List of all unity mappings. It is not locked because as runtime it is only + * read. It is created at ACPI table parsing time. + */ extern struct list_head amd_iommu_unity_map; -/* data structures for device handling */ +/* + * Data structures for device handling + */ + +/* + * Device table used by hardware. Read and write accesses by software are + * locked with the amd_iommu_pd_table lock. + */ extern struct dev_table_entry *amd_iommu_dev_table; + +/* + * Alias table to find requestor ids to device ids. Not locked because only + * read on runtime. + */ extern u16 *amd_iommu_alias_table; + +/* + * Reverse lookup table to find the IOMMU which translates a specific device. + */ extern struct amd_iommu **amd_iommu_rlookup_table; +/* size of the dma_ops aperture as power of 2 */ extern unsigned amd_iommu_aperture_order; +/* largest PCI device id we expect translation requests for */ extern u16 amd_iommu_last_bdf; /* data structures for protection domain handling */ extern struct protection_domain **amd_iommu_pd_table; + +/* allocation bitmap for domain ids */ extern unsigned long *amd_iommu_pd_alloc_bitmap; +/* will be 1 if device isolation is enabled */ extern int amd_iommu_isolate; +/* takes a PCI device id and prints it out in a readable form */ static inline void print_devid(u16 devid, int nl) { int bus = devid >> 8; @@ -241,4 +332,11 @@ static inline void print_devid(u16 devid, int nl) printk("\n"); } +/* takes bus and device/function and returns the device id + * FIXME: should that be in generic PCI code? */ +static inline u16 calc_devid(u8 bus, u8 devfn) +{ + return (((u16)bus) << 8) | devfn; +} + #endif diff --git a/include/asm-x86/arch_hooks.h b/include/asm-x86/arch_hooks.h index 768aee8a04ef..8411750ceb63 100644 --- a/include/asm-x86/arch_hooks.h +++ b/include/asm-x86/arch_hooks.h @@ -21,6 +21,7 @@ extern void intr_init_hook(void); extern void pre_intr_init_hook(void); extern void pre_setup_arch_hook(void); extern void trap_init_hook(void); +extern void pre_time_init_hook(void); extern void time_init_hook(void); extern void mca_nmi_hook(void); diff --git a/include/asm-x86/bitops.h b/include/asm-x86/bitops.h index 96b1829cea15..cfb2b64f76e7 100644 --- a/include/asm-x86/bitops.h +++ b/include/asm-x86/bitops.h @@ -356,7 +356,7 @@ static inline unsigned long ffz(unsigned long word) * __fls: find last set bit in word * @word: The word to search * - * Undefined if no zero exists, so code should check against ~0UL first. + * Undefined if no set bit exists, so code should check against 0 first. */ static inline unsigned long __fls(unsigned long word) { diff --git a/include/asm-x86/calling.h b/include/asm-x86/calling.h index f13e62e2cb3e..2bc162e0ec6e 100644 --- a/include/asm-x86/calling.h +++ b/include/asm-x86/calling.h @@ -104,7 +104,7 @@ .endif .endm - .macro LOAD_ARGS offset + .macro LOAD_ARGS offset, skiprax=0 movq \offset(%rsp), %r11 movq \offset+8(%rsp), %r10 movq \offset+16(%rsp), %r9 @@ -113,7 +113,10 @@ movq \offset+48(%rsp), %rdx movq \offset+56(%rsp), %rsi movq \offset+64(%rsp), %rdi + .if \skiprax + .else movq \offset+72(%rsp), %rax + .endif .endm #define REST_SKIP 6*8 @@ -165,4 +168,3 @@ .macro icebp .byte 0xf1 .endm - diff --git a/include/asm-x86/dma-mapping.h b/include/asm-x86/dma-mapping.h index a1a4dc7fe6ec..c2ddd3d1b883 100644 --- a/include/asm-x86/dma-mapping.h +++ b/include/asm-x86/dma-mapping.h @@ -14,7 +14,6 @@ extern dma_addr_t bad_dma_address; extern int iommu_merge; extern struct device fallback_dev; extern int panic_on_overflow; -extern int forbid_dac; extern int force_iommu; struct dma_mapping_ops { diff --git a/include/asm-x86/e820.h b/include/asm-x86/e820.h index 06633b01dd5b..16a31e2c7c57 100644 --- a/include/asm-x86/e820.h +++ b/include/asm-x86/e820.h @@ -90,6 +90,14 @@ static inline void e820_mark_nosave_regions(unsigned long limit_pfn) } #endif +#ifdef CONFIG_MEMTEST +extern void early_memtest(unsigned long start, unsigned long end); +#else +static inline void early_memtest(unsigned long start, unsigned long end) +{ +} +#endif + extern unsigned long end_user_pfn; extern u64 find_e820_area(u64 start, u64 end, u64 size, u64 align); diff --git a/include/asm-x86/fixmap_32.h b/include/asm-x86/fixmap_32.h index aae2f0501a40..f1ac2b2167d7 100644 --- a/include/asm-x86/fixmap_32.h +++ b/include/asm-x86/fixmap_32.h @@ -90,13 +90,13 @@ enum fixed_addresses { * 256 temporary boot-time mappings, used by early_ioremap(), * before ioremap() is functional. * - * We round it up to the next 512 pages boundary so that we + * We round it up to the next 256 pages boundary so that we * can have a single pgd entry and a single pte table: */ #define NR_FIX_BTMAPS 64 #define FIX_BTMAPS_NESTING 4 - FIX_BTMAP_END = __end_of_permanent_fixed_addresses + 512 - - (__end_of_permanent_fixed_addresses & 511), + FIX_BTMAP_END = __end_of_permanent_fixed_addresses + 256 - + (__end_of_permanent_fixed_addresses & 255), FIX_BTMAP_BEGIN = FIX_BTMAP_END + NR_FIX_BTMAPS*FIX_BTMAPS_NESTING - 1, FIX_WP_TEST, #ifdef CONFIG_ACPI diff --git a/include/asm-x86/ftrace.h b/include/asm-x86/ftrace.h index c184441133f2..5c68b32ee1c8 100644 --- a/include/asm-x86/ftrace.h +++ b/include/asm-x86/ftrace.h @@ -1,5 +1,5 @@ #ifndef _ASM_X86_FTRACE -#define _ASM_SPARC64_FTRACE +#define _ASM_X86_FTRACE #ifdef CONFIG_FTRACE #define MCOUNT_ADDR ((long)(mcount)) diff --git a/include/asm-x86/gart.h b/include/asm-x86/gart.h index 33b9aeeb35a2..3f62a83887f3 100644 --- a/include/asm-x86/gart.h +++ b/include/asm-x86/gart.h @@ -2,7 +2,6 @@ #define _ASM_X8664_GART_H 1 #include <asm/e820.h> -#include <asm/iommu.h> extern void set_up_gart_resume(u32, u32); diff --git a/include/asm-x86/iommu.h b/include/asm-x86/iommu.h index 068c9a40aa5b..d63166fb3ab7 100644 --- a/include/asm-x86/iommu.h +++ b/include/asm-x86/iommu.h @@ -25,10 +25,18 @@ extern void gart_iommu_hole_init(void); static inline void early_gart_iommu_check(void) { } - +static inline void gart_iommu_init(void) +{ +} static inline void gart_iommu_shutdown(void) { } +static inline void gart_parse_options(char *options) +{ +} +static inline void gart_iommu_hole_init(void) +{ +} #endif #endif diff --git a/include/asm-x86/kvm.h b/include/asm-x86/kvm.h index 80eefef2cc76..6f1840812e59 100644 --- a/include/asm-x86/kvm.h +++ b/include/asm-x86/kvm.h @@ -228,5 +228,6 @@ struct kvm_pit_state { #define KVM_TRC_CLTS (KVM_TRC_HANDLER + 0x12) #define KVM_TRC_LMSW (KVM_TRC_HANDLER + 0x13) #define KVM_TRC_APIC_ACCESS (KVM_TRC_HANDLER + 0x14) +#define KVM_TRC_TDP_FAULT (KVM_TRC_HANDLER + 0x15) #endif diff --git a/include/asm-x86/kvm_host.h b/include/asm-x86/kvm_host.h index 844f2a89afbc..fdde0bedaa90 100644 --- a/include/asm-x86/kvm_host.h +++ b/include/asm-x86/kvm_host.h @@ -27,6 +27,7 @@ #define KVM_PRIVATE_MEM_SLOTS 4 #define KVM_PIO_PAGE_OFFSET 1 +#define KVM_COALESCED_MMIO_PAGE_OFFSET 2 #define CR3_PAE_RESERVED_BITS ((X86_CR3_PWT | X86_CR3_PCD) - 1) #define CR3_NONPAE_RESERVED_BITS ((PAGE_SIZE-1) & ~(X86_CR3_PWT | X86_CR3_PCD)) @@ -79,6 +80,7 @@ #define KVM_MIN_FREE_MMU_PAGES 5 #define KVM_REFILL_PAGES 25 #define KVM_MAX_CPUID_ENTRIES 40 +#define KVM_NR_VAR_MTRR 8 extern spinlock_t kvm_lock; extern struct list_head vm_list; @@ -109,12 +111,12 @@ enum { }; enum { + VCPU_SREG_ES, VCPU_SREG_CS, + VCPU_SREG_SS, VCPU_SREG_DS, - VCPU_SREG_ES, VCPU_SREG_FS, VCPU_SREG_GS, - VCPU_SREG_SS, VCPU_SREG_TR, VCPU_SREG_LDTR, }; @@ -243,6 +245,7 @@ struct kvm_vcpu_arch { gfn_t last_pt_write_gfn; int last_pt_write_count; u64 *last_pte_updated; + gfn_t last_pte_gfn; struct { gfn_t gfn; /* presumed gfn during guest pte update */ @@ -287,6 +290,10 @@ struct kvm_vcpu_arch { unsigned int hv_clock_tsc_khz; unsigned int time_offset; struct page *time_page; + + bool nmi_pending; + + u64 mtrr[0x100]; }; struct kvm_mem_alias { @@ -344,6 +351,7 @@ struct kvm_vcpu_stat { u32 mmio_exits; u32 signal_exits; u32 irq_window_exits; + u32 nmi_window_exits; u32 halt_exits; u32 halt_wakeup; u32 request_irq_exits; @@ -379,7 +387,6 @@ struct kvm_x86_ops { void (*prepare_guest_switch)(struct kvm_vcpu *vcpu); void (*vcpu_load)(struct kvm_vcpu *vcpu, int cpu); void (*vcpu_put)(struct kvm_vcpu *vcpu); - void (*vcpu_decache)(struct kvm_vcpu *vcpu); int (*set_guest_debug)(struct kvm_vcpu *vcpu, struct kvm_debug_guest *dbg); @@ -497,6 +504,10 @@ int emulator_get_dr(struct x86_emulate_ctxt *ctxt, int dr, int emulator_set_dr(struct x86_emulate_ctxt *ctxt, int dr, unsigned long value); +void kvm_get_segment(struct kvm_vcpu *vcpu, struct kvm_segment *var, int seg); +int kvm_load_segment_descriptor(struct kvm_vcpu *vcpu, u16 selector, + int type_bits, int seg); + int kvm_task_switch(struct kvm_vcpu *vcpu, u16 tss_selector, int reason); void kvm_set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0); @@ -515,6 +526,8 @@ void kvm_queue_exception_e(struct kvm_vcpu *vcpu, unsigned nr, u32 error_code); void kvm_inject_page_fault(struct kvm_vcpu *vcpu, unsigned long cr2, u32 error_code); +void kvm_inject_nmi(struct kvm_vcpu *vcpu); + void fx_init(struct kvm_vcpu *vcpu); int emulator_read_std(unsigned long addr, @@ -554,55 +567,53 @@ static inline struct kvm_mmu_page *page_header(hpa_t shadow_page) return (struct kvm_mmu_page *)page_private(page); } -static inline u16 read_fs(void) +static inline u16 kvm_read_fs(void) { u16 seg; asm("mov %%fs, %0" : "=g"(seg)); return seg; } -static inline u16 read_gs(void) +static inline u16 kvm_read_gs(void) { u16 seg; asm("mov %%gs, %0" : "=g"(seg)); return seg; } -static inline u16 read_ldt(void) +static inline u16 kvm_read_ldt(void) { u16 ldt; asm("sldt %0" : "=g"(ldt)); return ldt; } -static inline void load_fs(u16 sel) +static inline void kvm_load_fs(u16 sel) { asm("mov %0, %%fs" : : "rm"(sel)); } -static inline void load_gs(u16 sel) +static inline void kvm_load_gs(u16 sel) { asm("mov %0, %%gs" : : "rm"(sel)); } -#ifndef load_ldt -static inline void load_ldt(u16 sel) +static inline void kvm_load_ldt(u16 sel) { asm("lldt %0" : : "rm"(sel)); } -#endif -static inline void get_idt(struct descriptor_table *table) +static inline void kvm_get_idt(struct descriptor_table *table) { asm("sidt %0" : "=m"(*table)); } -static inline void get_gdt(struct descriptor_table *table) +static inline void kvm_get_gdt(struct descriptor_table *table) { asm("sgdt %0" : "=m"(*table)); } -static inline unsigned long read_tr_base(void) +static inline unsigned long kvm_read_tr_base(void) { u16 tr; asm("str %0" : "=g"(tr)); @@ -619,17 +630,17 @@ static inline unsigned long read_msr(unsigned long msr) } #endif -static inline void fx_save(struct i387_fxsave_struct *image) +static inline void kvm_fx_save(struct i387_fxsave_struct *image) { asm("fxsave (%0)":: "r" (image)); } -static inline void fx_restore(struct i387_fxsave_struct *image) +static inline void kvm_fx_restore(struct i387_fxsave_struct *image) { asm("fxrstor (%0)":: "r" (image)); } -static inline void fx_finit(void) +static inline void kvm_fx_finit(void) { asm("finit"); } @@ -691,4 +702,30 @@ enum { trace_mark(kvm_trace_##name, "%u %p %u %u %u %u %u %u", KVM_TRC_##evt, \ vcpu, 0, 0, 0, 0, 0, 0) +#ifdef CONFIG_64BIT +# define KVM_EX_ENTRY ".quad" +# define KVM_EX_PUSH "pushq" +#else +# define KVM_EX_ENTRY ".long" +# define KVM_EX_PUSH "pushl" +#endif + +/* + * Hardware virtualization extension instructions may fault if a + * reboot turns off virtualization while processes are running. + * Trap the fault and ignore the instruction if that happens. + */ +asmlinkage void kvm_handle_fault_on_reboot(void); + +#define __kvm_handle_fault_on_reboot(insn) \ + "666: " insn "\n\t" \ + ".pushsection .text.fixup, \"ax\" \n" \ + "667: \n\t" \ + KVM_EX_PUSH " $666b \n\t" \ + "jmp kvm_handle_fault_on_reboot \n\t" \ + ".popsection \n\t" \ + ".pushsection __ex_table, \"a\" \n\t" \ + KVM_EX_ENTRY " 666b, 667b \n\t" \ + ".popsection" + #endif diff --git a/include/asm-x86/kvm_x86_emulate.h b/include/asm-x86/kvm_x86_emulate.h index b877bbd2d3a7..4e8c1e48d91d 100644 --- a/include/asm-x86/kvm_x86_emulate.h +++ b/include/asm-x86/kvm_x86_emulate.h @@ -124,7 +124,8 @@ struct decode_cache { u8 rex_prefix; struct operand src; struct operand dst; - unsigned long *override_base; + bool has_seg_override; + u8 seg_override; unsigned int d; unsigned long regs[NR_VCPU_REGS]; unsigned long eip; @@ -134,6 +135,7 @@ struct decode_cache { u8 modrm_reg; u8 modrm_rm; u8 use_modrm_ea; + bool rip_relative; unsigned long modrm_ea; void *modrm_ptr; unsigned long modrm_val; @@ -150,12 +152,7 @@ struct x86_emulate_ctxt { /* Emulated execution mode, represented by an X86EMUL_MODE value. */ int mode; - unsigned long cs_base; - unsigned long ds_base; - unsigned long es_base; - unsigned long ss_base; - unsigned long gs_base; - unsigned long fs_base; + u32 cs_base; /* decode cache */ diff --git a/include/asm-x86/mach-generic/mach_mpspec.h b/include/asm-x86/mach-generic/mach_mpspec.h index 9ef0b941bb22..c83c120be538 100644 --- a/include/asm-x86/mach-generic/mach_mpspec.h +++ b/include/asm-x86/mach-generic/mach_mpspec.h @@ -7,4 +7,6 @@ /* Maximum 256 PCI busses, plus 1 ISA bus in each of 4 cabinets. */ #define MAX_MP_BUSSES 260 +extern void numaq_mps_oem_check(struct mp_config_table *mpc, char *oem, + char *productid); #endif /* __ASM_MACH_MPSPEC_H */ diff --git a/include/asm-x86/mach-visws/entry_arch.h b/include/asm-x86/mach-visws/entry_arch.h deleted file mode 100644 index 86be554342d4..000000000000 --- a/include/asm-x86/mach-visws/entry_arch.h +++ /dev/null @@ -1,5 +0,0 @@ -/* - * VISWS uses the standard Linux entry points: - */ - -#include "../mach-default/entry_arch.h" diff --git a/include/asm-x86/mach-visws/mach_apic.h b/include/asm-x86/mach-visws/mach_apic.h deleted file mode 100644 index 6943e7a1d0e6..000000000000 --- a/include/asm-x86/mach-visws/mach_apic.h +++ /dev/null @@ -1 +0,0 @@ -#include "../mach-default/mach_apic.h" diff --git a/include/asm-x86/mach-visws/mach_apicdef.h b/include/asm-x86/mach-visws/mach_apicdef.h deleted file mode 100644 index 42711d152a93..000000000000 --- a/include/asm-x86/mach-visws/mach_apicdef.h +++ /dev/null @@ -1 +0,0 @@ -#include "../mach-default/mach_apicdef.h" diff --git a/include/asm-x86/mach-visws/setup_arch.h b/include/asm-x86/mach-visws/setup_arch.h deleted file mode 100644 index fa4766ca2d10..000000000000 --- a/include/asm-x86/mach-visws/setup_arch.h +++ /dev/null @@ -1 +0,0 @@ -#include "../mach-default/setup_arch.h" diff --git a/include/asm-x86/mach-visws/smpboot_hooks.h b/include/asm-x86/mach-visws/smpboot_hooks.h deleted file mode 100644 index e4433ca88715..000000000000 --- a/include/asm-x86/mach-visws/smpboot_hooks.h +++ /dev/null @@ -1 +0,0 @@ -#include "../mach-default/smpboot_hooks.h" diff --git a/include/asm-x86/paravirt.h b/include/asm-x86/paravirt.h index 719d959d0bc4..695ce9383f52 100644 --- a/include/asm-x86/paravirt.h +++ b/include/asm-x86/paravirt.h @@ -1390,8 +1390,8 @@ extern struct paravirt_patch_site __parainstructions[], * caller saved registers but the argument parameter */ #define PV_SAVE_REGS "pushq %%rdi;" #define PV_RESTORE_REGS "popq %%rdi;" -#define PV_EXTRA_CLOBBERS EXTRA_CLOBBERS, "rcx" , "rdx" -#define PV_VEXTRA_CLOBBERS EXTRA_CLOBBERS, "rdi", "rcx" , "rdx" +#define PV_EXTRA_CLOBBERS EXTRA_CLOBBERS, "rcx" , "rdx", "rsi" +#define PV_VEXTRA_CLOBBERS EXTRA_CLOBBERS, "rdi", "rcx" , "rdx", "rsi" #define PV_FLAGS_ARG "D" #endif @@ -1483,8 +1483,26 @@ static inline unsigned long __raw_local_irq_save(void) #ifdef CONFIG_X86_64 -#define PV_SAVE_REGS pushq %rax; pushq %rdi; pushq %rcx; pushq %rdx -#define PV_RESTORE_REGS popq %rdx; popq %rcx; popq %rdi; popq %rax +#define PV_SAVE_REGS \ + push %rax; \ + push %rcx; \ + push %rdx; \ + push %rsi; \ + push %rdi; \ + push %r8; \ + push %r9; \ + push %r10; \ + push %r11 +#define PV_RESTORE_REGS \ + pop %r11; \ + pop %r10; \ + pop %r9; \ + pop %r8; \ + pop %rdi; \ + pop %rsi; \ + pop %rdx; \ + pop %rcx; \ + pop %rax #define PARA_PATCH(struct, off) ((PARAVIRT_PATCH_##struct + (off)) / 8) #define PARA_SITE(ptype, clobbers, ops) _PVSITE(ptype, clobbers, ops, .quad, 8) #define PARA_INDIRECT(addr) *addr(%rip) diff --git a/include/asm-x86/percpu.h b/include/asm-x86/percpu.h index 912a3a17b9db..4e91ee1e37aa 100644 --- a/include/asm-x86/percpu.h +++ b/include/asm-x86/percpu.h @@ -22,6 +22,32 @@ DECLARE_PER_CPU(struct x8664_pda, pda); +/* + * These are supposed to be implemented as a single instruction which + * operates on the per-cpu data base segment. x86-64 doesn't have + * that yet, so this is a fairly inefficient workaround for the + * meantime. The single instruction is atomic with respect to + * preemption and interrupts, so we need to explicitly disable + * interrupts here to achieve the same effect. However, because it + * can be used from within interrupt-disable/enable, we can't actually + * disable interrupts; disabling preemption is enough. + */ +#define x86_read_percpu(var) \ + ({ \ + typeof(per_cpu_var(var)) __tmp; \ + preempt_disable(); \ + __tmp = __get_cpu_var(var); \ + preempt_enable(); \ + __tmp; \ + }) + +#define x86_write_percpu(var, val) \ + do { \ + preempt_disable(); \ + __get_cpu_var(var) = (val); \ + preempt_enable(); \ + } while(0) + #else /* CONFIG_X86_64 */ #ifdef __ASSEMBLY__ diff --git a/include/asm-x86/pgtable.h b/include/asm-x86/pgtable.h index 49cbd76b9547..96aa76e691d8 100644 --- a/include/asm-x86/pgtable.h +++ b/include/asm-x86/pgtable.h @@ -302,6 +302,14 @@ int phys_mem_access_prot_allowed(struct file *file, unsigned long pfn, /* Install a pte for a particular vaddr in kernel space. */ void set_pte_vaddr(unsigned long vaddr, pte_t pte); +#ifdef CONFIG_X86_32 +extern void native_pagetable_setup_start(pgd_t *base); +extern void native_pagetable_setup_done(pgd_t *base); +#else +static inline void native_pagetable_setup_start(pgd_t *base) {} +static inline void native_pagetable_setup_done(pgd_t *base) {} +#endif + #ifdef CONFIG_PARAVIRT #include <asm/paravirt.h> #else /* !CONFIG_PARAVIRT */ @@ -333,6 +341,16 @@ void set_pte_vaddr(unsigned long vaddr, pte_t pte); #define pte_update(mm, addr, ptep) do { } while (0) #define pte_update_defer(mm, addr, ptep) do { } while (0) + +static inline void __init paravirt_pagetable_setup_start(pgd_t *base) +{ + native_pagetable_setup_start(base); +} + +static inline void __init paravirt_pagetable_setup_done(pgd_t *base) +{ + native_pagetable_setup_done(base); +} #endif /* CONFIG_PARAVIRT */ #endif /* __ASSEMBLY__ */ diff --git a/include/asm-x86/pgtable_32.h b/include/asm-x86/pgtable_32.h index ec871c420d7e..0611abf96a5e 100644 --- a/include/asm-x86/pgtable_32.h +++ b/include/asm-x86/pgtable_32.h @@ -171,21 +171,6 @@ do { \ */ #define update_mmu_cache(vma, address, pte) do { } while (0) -extern void native_pagetable_setup_start(pgd_t *base); -extern void native_pagetable_setup_done(pgd_t *base); - -#ifndef CONFIG_PARAVIRT -static inline void __init paravirt_pagetable_setup_start(pgd_t *base) -{ - native_pagetable_setup_start(base); -} - -static inline void __init paravirt_pagetable_setup_done(pgd_t *base) -{ - native_pagetable_setup_done(base); -} -#endif /* !CONFIG_PARAVIRT */ - #endif /* !__ASSEMBLY__ */ /* diff --git a/include/asm-x86/pgtable_64.h b/include/asm-x86/pgtable_64.h index fa7208b483ca..805d3128bfc4 100644 --- a/include/asm-x86/pgtable_64.h +++ b/include/asm-x86/pgtable_64.h @@ -16,6 +16,8 @@ extern pud_t level3_kernel_pgt[512]; extern pud_t level3_ident_pgt[512]; extern pmd_t level2_kernel_pgt[512]; +extern pmd_t level2_fixmap_pgt[512]; +extern pmd_t level2_ident_pgt[512]; extern pgd_t init_level4_pgt[]; #define swapper_pg_dir init_level4_pgt diff --git a/include/asm-x86/processor.h b/include/asm-x86/processor.h index 55402d2ab938..15cb82a44e89 100644 --- a/include/asm-x86/processor.h +++ b/include/asm-x86/processor.h @@ -722,8 +722,6 @@ static inline void __sti_mwait(unsigned long eax, unsigned long ecx) extern void mwait_idle_with_hints(unsigned long eax, unsigned long ecx); -extern int force_mwait; - extern void select_idle_routine(const struct cpuinfo_x86 *c); extern unsigned long boot_option_idle_override; diff --git a/include/asm-x86/ptrace-abi.h b/include/asm-x86/ptrace-abi.h index f224eb3c3157..72e7b9db29bb 100644 --- a/include/asm-x86/ptrace-abi.h +++ b/include/asm-x86/ptrace-abi.h @@ -73,11 +73,11 @@ #ifdef __x86_64__ # define PTRACE_ARCH_PRCTL 30 -#else -# define PTRACE_SYSEMU 31 -# define PTRACE_SYSEMU_SINGLESTEP 32 #endif +#define PTRACE_SYSEMU 31 +#define PTRACE_SYSEMU_SINGLESTEP 32 + #define PTRACE_SINGLEBLOCK 33 /* resume execution until next branch */ #ifndef __ASSEMBLY__ diff --git a/include/asm-x86/segment.h b/include/asm-x86/segment.h index dfc8601c0892..646452ea9ea3 100644 --- a/include/asm-x86/segment.h +++ b/include/asm-x86/segment.h @@ -1,6 +1,15 @@ #ifndef _ASM_X86_SEGMENT_H_ #define _ASM_X86_SEGMENT_H_ +/* Constructor for a conventional segment GDT (or LDT) entry */ +/* This is a macro so it can be used in initializers */ +#define GDT_ENTRY(flags, base, limit) \ + ((((base) & 0xff000000ULL) << (56-24)) | \ + (((flags) & 0x0000f0ffULL) << 40) | \ + (((limit) & 0x000f0000ULL) << (48-16)) | \ + (((base) & 0x00ffffffULL) << 16) | \ + (((limit) & 0x0000ffffULL))) + /* Simple and small GDT entries for booting only */ #define GDT_ENTRY_BOOT_CS 2 diff --git a/include/asm-x86/setup.h b/include/asm-x86/setup.h index 90ab2225e71b..a07c6f1c01e1 100644 --- a/include/asm-x86/setup.h +++ b/include/asm-x86/setup.h @@ -19,13 +19,28 @@ static inline int is_visws_box(void) { return 0; } /* * Any setup quirks to be performed? */ -extern int (*arch_time_init_quirk)(void); -extern int (*arch_pre_intr_init_quirk)(void); -extern int (*arch_intr_init_quirk)(void); -extern int (*arch_trap_init_quirk)(void); -extern char * (*arch_memory_setup_quirk)(void); -extern int (*mach_get_smp_config_quirk)(unsigned int early); -extern int (*mach_find_smp_config_quirk)(unsigned int reserve); +struct mpc_config_processor; +struct mpc_config_bus; +struct mp_config_oemtable; +struct x86_quirks { + int (*arch_pre_time_init)(void); + int (*arch_time_init)(void); + int (*arch_pre_intr_init)(void); + int (*arch_intr_init)(void); + int (*arch_trap_init)(void); + char * (*arch_memory_setup)(void); + int (*mach_get_smp_config)(unsigned int early); + int (*mach_find_smp_config)(unsigned int reserve); + + int *mpc_record; + int (*mpc_apic_id)(struct mpc_config_processor *m); + void (*mpc_oem_bus_info)(struct mpc_config_bus *m, char *name); + void (*mpc_oem_pci_bus)(struct mpc_config_bus *m); + void (*smp_read_mpc_oem)(struct mp_config_oemtable *oemtable, + unsigned short oemsize); +}; + +extern struct x86_quirks *x86_quirks; #ifndef CONFIG_PARAVIRT #define paravirt_post_allocator_init() do {} while (0) @@ -76,6 +91,7 @@ extern unsigned long init_pg_tables_start; extern unsigned long init_pg_tables_end; #else +void __init x86_64_init_pda(void); void __init x86_64_start_kernel(char *real_mode); void __init x86_64_start_reservations(char *real_mode_data); diff --git a/include/asm-x86/signal.h b/include/asm-x86/signal.h index f15186d39c69..6dac49364e95 100644 --- a/include/asm-x86/signal.h +++ b/include/asm-x86/signal.h @@ -181,12 +181,12 @@ typedef struct sigaltstack { #ifdef __KERNEL__ #include <asm/sigcontext.h> -#ifdef __386__ +#ifdef __i386__ #define __HAVE_ARCH_SIG_BITOPS #define sigaddset(set,sig) \ - (__builtin_constantp(sig) \ + (__builtin_constant_p(sig) \ ? __const_sigaddset((set), (sig)) \ : __gen_sigaddset((set), (sig))) diff --git a/include/asm-x86/smp.h b/include/asm-x86/smp.h index c2784b3e0b77..3c877f74f279 100644 --- a/include/asm-x86/smp.h +++ b/include/asm-x86/smp.h @@ -25,6 +25,8 @@ extern cpumask_t cpu_callin_map; extern void (*mtrr_hook)(void); extern void zap_low_mappings(void); +extern int __cpuinit get_local_pda(int cpu); + extern int smp_num_siblings; extern unsigned int num_processors; extern cpumask_t cpu_initialized; diff --git a/include/asm-x86/swiotlb.h b/include/asm-x86/swiotlb.h index f5d9e74b1e4a..c706a7442633 100644 --- a/include/asm-x86/swiotlb.h +++ b/include/asm-x86/swiotlb.h @@ -45,12 +45,14 @@ extern int swiotlb_force; #ifdef CONFIG_SWIOTLB extern int swiotlb; +extern void pci_swiotlb_init(void); #else #define swiotlb 0 +static inline void pci_swiotlb_init(void) +{ +} #endif -extern void pci_swiotlb_init(void); - static inline void dma_mark_clean(void *addr, size_t size) {} #endif /* _ASM_SWIOTLB_H */ diff --git a/include/asm-x86/thread_info.h b/include/asm-x86/thread_info.h index 895339d2bc0b..0a8f27d31d0d 100644 --- a/include/asm-x86/thread_info.h +++ b/include/asm-x86/thread_info.h @@ -75,9 +75,7 @@ struct thread_info { #define TIF_NEED_RESCHED 3 /* rescheduling necessary */ #define TIF_SINGLESTEP 4 /* reenable singlestep on user return*/ #define TIF_IRET 5 /* force IRET */ -#ifdef CONFIG_X86_32 #define TIF_SYSCALL_EMU 6 /* syscall emulation active */ -#endif #define TIF_SYSCALL_AUDIT 7 /* syscall auditing active */ #define TIF_SECCOMP 8 /* secure computing */ #define TIF_MCE_NOTIFY 10 /* notify userspace of an MCE */ @@ -100,11 +98,7 @@ struct thread_info { #define _TIF_SINGLESTEP (1 << TIF_SINGLESTEP) #define _TIF_NEED_RESCHED (1 << TIF_NEED_RESCHED) #define _TIF_IRET (1 << TIF_IRET) -#ifdef CONFIG_X86_32 #define _TIF_SYSCALL_EMU (1 << TIF_SYSCALL_EMU) -#else -#define _TIF_SYSCALL_EMU 0 -#endif #define _TIF_SYSCALL_AUDIT (1 << TIF_SYSCALL_AUDIT) #define _TIF_SECCOMP (1 << TIF_SECCOMP) #define _TIF_MCE_NOTIFY (1 << TIF_MCE_NOTIFY) @@ -121,18 +115,27 @@ struct thread_info { #define _TIF_DS_AREA_MSR (1 << TIF_DS_AREA_MSR) #define _TIF_BTS_TRACE_TS (1 << TIF_BTS_TRACE_TS) +/* work to do in syscall_trace_enter() */ +#define _TIF_WORK_SYSCALL_ENTRY \ + (_TIF_SYSCALL_TRACE | _TIF_SYSCALL_EMU | \ + _TIF_SYSCALL_AUDIT | _TIF_SECCOMP | _TIF_SINGLESTEP) + +/* work to do in syscall_trace_leave() */ +#define _TIF_WORK_SYSCALL_EXIT \ + (_TIF_SYSCALL_TRACE | _TIF_SYSCALL_AUDIT | _TIF_SINGLESTEP) + /* work to do on interrupt/exception return */ #define _TIF_WORK_MASK \ (0x0000FFFF & \ - ~(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT|_TIF_SINGLESTEP| \ - _TIF_SECCOMP|_TIF_SYSCALL_EMU)) + ~(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT| \ + _TIF_SINGLESTEP|_TIF_SECCOMP|_TIF_SYSCALL_EMU)) /* work to do on any return to user space */ #define _TIF_ALLWORK_MASK (0x0000FFFF & ~_TIF_SECCOMP) /* Only used for 64 bit */ #define _TIF_DO_NOTIFY_MASK \ - (_TIF_SIGPENDING|_TIF_SINGLESTEP|_TIF_MCE_NOTIFY|_TIF_HRTICK_RESCHED) + (_TIF_SIGPENDING|_TIF_MCE_NOTIFY|_TIF_HRTICK_RESCHED) /* flags to check in __switch_to() */ #define _TIF_WORK_CTXSW \ diff --git a/include/asm-x86/traps.h b/include/asm-x86/traps.h new file mode 100644 index 000000000000..a4b65a71bd66 --- /dev/null +++ b/include/asm-x86/traps.h @@ -0,0 +1,66 @@ +#ifndef _ASM_X86_TRAPS_H +#define _ASM_X86_TRAPS_H + +/* Common in X86_32 and X86_64 */ +asmlinkage void divide_error(void); +asmlinkage void debug(void); +asmlinkage void nmi(void); +asmlinkage void int3(void); +asmlinkage void overflow(void); +asmlinkage void bounds(void); +asmlinkage void invalid_op(void); +asmlinkage void device_not_available(void); +asmlinkage void coprocessor_segment_overrun(void); +asmlinkage void invalid_TSS(void); +asmlinkage void segment_not_present(void); +asmlinkage void stack_segment(void); +asmlinkage void general_protection(void); +asmlinkage void page_fault(void); +asmlinkage void coprocessor_error(void); +asmlinkage void simd_coprocessor_error(void); +asmlinkage void alignment_check(void); +asmlinkage void spurious_interrupt_bug(void); +#ifdef CONFIG_X86_MCE +asmlinkage void machine_check(void); +#endif /* CONFIG_X86_MCE */ + +void do_divide_error(struct pt_regs *, long); +void do_overflow(struct pt_regs *, long); +void do_bounds(struct pt_regs *, long); +void do_coprocessor_segment_overrun(struct pt_regs *, long); +void do_invalid_TSS(struct pt_regs *, long); +void do_segment_not_present(struct pt_regs *, long); +void do_stack_segment(struct pt_regs *, long); +void do_alignment_check(struct pt_regs *, long); +void do_invalid_op(struct pt_regs *, long); +void do_general_protection(struct pt_regs *, long); +void do_nmi(struct pt_regs *, long); + +extern int panic_on_unrecovered_nmi; +extern int kstack_depth_to_print; + +#ifdef CONFIG_X86_32 + +void do_iret_error(struct pt_regs *, long); +void do_int3(struct pt_regs *, long); +void do_debug(struct pt_regs *, long); +void math_error(void __user *); +void do_coprocessor_error(struct pt_regs *, long); +void do_simd_coprocessor_error(struct pt_regs *, long); +void do_spurious_interrupt_bug(struct pt_regs *, long); +unsigned long patch_espfix_desc(unsigned long, unsigned long); +asmlinkage void math_emulate(long); + +#else /* CONFIG_X86_32 */ + +asmlinkage void double_fault(void); + +asmlinkage void do_int3(struct pt_regs *, long); +asmlinkage void do_stack_segment(struct pt_regs *, long); +asmlinkage void do_debug(struct pt_regs *, unsigned long); +asmlinkage void do_coprocessor_error(struct pt_regs *); +asmlinkage void do_simd_coprocessor_error(struct pt_regs *); +asmlinkage void do_spurious_interrupt_bug(struct pt_regs *); + +#endif /* CONFIG_X86_32 */ +#endif /* _ASM_X86_TRAPS_H */ diff --git a/include/asm-x86/uv/bios.h b/include/asm-x86/uv/bios.h new file mode 100644 index 000000000000..aa73362ff5df --- /dev/null +++ b/include/asm-x86/uv/bios.h @@ -0,0 +1,68 @@ +#ifndef _ASM_X86_BIOS_H +#define _ASM_X86_BIOS_H + +/* + * BIOS layer definitions. + * + * Copyright (c) 2008 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <linux/rtc.h> + +#define BIOS_FREQ_BASE 0x01000001 + +enum { + BIOS_FREQ_BASE_PLATFORM = 0, + BIOS_FREQ_BASE_INTERVAL_TIMER = 1, + BIOS_FREQ_BASE_REALTIME_CLOCK = 2 +}; + +# define BIOS_CALL(result, a0, a1, a2, a3, a4, a5, a6, a7) \ + do { \ + /* XXX - the real call goes here */ \ + result.status = BIOS_STATUS_UNIMPLEMENTED; \ + isrv.v0 = 0; \ + isrv.v1 = 0; \ + } while (0) + +enum { + BIOS_STATUS_SUCCESS = 0, + BIOS_STATUS_UNIMPLEMENTED = -1, + BIOS_STATUS_EINVAL = -2, + BIOS_STATUS_ERROR = -3 +}; + +struct uv_bios_retval { + /* + * A zero status value indicates call completed without error. + * A negative status value indicates reason of call failure. + * A positive status value indicates success but an + * informational value should be printed (e.g., "reboot for + * change to take effect"). + */ + s64 status; + u64 v0; + u64 v1; + u64 v2; +}; + +extern long +x86_bios_freq_base(unsigned long which, unsigned long *ticks_per_second, + unsigned long *drift_info); +extern const char *x86_bios_strerror(long status); + +#endif /* _ASM_X86_BIOS_H */ diff --git a/include/asm-x86/vdso.h b/include/asm-x86/vdso.h index 86e085e003d2..8e18fb80f5e6 100644 --- a/include/asm-x86/vdso.h +++ b/include/asm-x86/vdso.h @@ -36,4 +36,12 @@ extern const char VDSO32_PRELINK[]; extern void __user __kernel_sigreturn; extern void __user __kernel_rt_sigreturn; +/* + * These symbols are defined by vdso32.S to mark the bounds + * of the ELF DSO images included therein. + */ +extern const char vdso32_int80_start, vdso32_int80_end; +extern const char vdso32_syscall_start, vdso32_syscall_end; +extern const char vdso32_sysenter_start, vdso32_sysenter_end; + #endif /* asm-x86/vdso.h */ diff --git a/include/asm-x86/xen/hypercall.h b/include/asm-x86/xen/hypercall.h index 2a4f9b41d684..91cb7fd5c123 100644 --- a/include/asm-x86/xen/hypercall.h +++ b/include/asm-x86/xen/hypercall.h @@ -40,83 +40,157 @@ #include <xen/interface/sched.h> #include <xen/interface/physdev.h> +/* + * The hypercall asms have to meet several constraints: + * - Work on 32- and 64-bit. + * The two architectures put their arguments in different sets of + * registers. + * + * - Work around asm syntax quirks + * It isn't possible to specify one of the rNN registers in a + * constraint, so we use explicit register variables to get the + * args into the right place. + * + * - Mark all registers as potentially clobbered + * Even unused parameters can be clobbered by the hypervisor, so we + * need to make sure gcc knows it. + * + * - Avoid compiler bugs. + * This is the tricky part. Because x86_32 has such a constrained + * register set, gcc versions below 4.3 have trouble generating + * code when all the arg registers and memory are trashed by the + * asm. There are syntactically simpler ways of achieving the + * semantics below, but they cause the compiler to crash. + * + * The only combination I found which works is: + * - assign the __argX variables first + * - list all actually used parameters as "+r" (__argX) + * - clobber the rest + * + * The result certainly isn't pretty, and it really shows up cpp's + * weakness as as macro language. Sorry. (But let's just give thanks + * there aren't more than 5 arguments...) + */ + extern struct { char _entry[32]; } hypercall_page[]; +#define __HYPERCALL "call hypercall_page+%c[offset]" +#define __HYPERCALL_ENTRY(x) \ + [offset] "i" (__HYPERVISOR_##x * sizeof(hypercall_page[0])) + +#ifdef CONFIG_X86_32 +#define __HYPERCALL_RETREG "eax" +#define __HYPERCALL_ARG1REG "ebx" +#define __HYPERCALL_ARG2REG "ecx" +#define __HYPERCALL_ARG3REG "edx" +#define __HYPERCALL_ARG4REG "esi" +#define __HYPERCALL_ARG5REG "edi" +#else +#define __HYPERCALL_RETREG "rax" +#define __HYPERCALL_ARG1REG "rdi" +#define __HYPERCALL_ARG2REG "rsi" +#define __HYPERCALL_ARG3REG "rdx" +#define __HYPERCALL_ARG4REG "r10" +#define __HYPERCALL_ARG5REG "r8" +#endif + +#define __HYPERCALL_DECLS \ + register unsigned long __res asm(__HYPERCALL_RETREG); \ + register unsigned long __arg1 asm(__HYPERCALL_ARG1REG) = __arg1; \ + register unsigned long __arg2 asm(__HYPERCALL_ARG2REG) = __arg2; \ + register unsigned long __arg3 asm(__HYPERCALL_ARG3REG) = __arg3; \ + register unsigned long __arg4 asm(__HYPERCALL_ARG4REG) = __arg4; \ + register unsigned long __arg5 asm(__HYPERCALL_ARG5REG) = __arg5; + +#define __HYPERCALL_0PARAM "=r" (__res) +#define __HYPERCALL_1PARAM __HYPERCALL_0PARAM, "+r" (__arg1) +#define __HYPERCALL_2PARAM __HYPERCALL_1PARAM, "+r" (__arg2) +#define __HYPERCALL_3PARAM __HYPERCALL_2PARAM, "+r" (__arg3) +#define __HYPERCALL_4PARAM __HYPERCALL_3PARAM, "+r" (__arg4) +#define __HYPERCALL_5PARAM __HYPERCALL_4PARAM, "+r" (__arg5) + +#define __HYPERCALL_0ARG() +#define __HYPERCALL_1ARG(a1) \ + __HYPERCALL_0ARG() __arg1 = (unsigned long)(a1); +#define __HYPERCALL_2ARG(a1,a2) \ + __HYPERCALL_1ARG(a1) __arg2 = (unsigned long)(a2); +#define __HYPERCALL_3ARG(a1,a2,a3) \ + __HYPERCALL_2ARG(a1,a2) __arg3 = (unsigned long)(a3); +#define __HYPERCALL_4ARG(a1,a2,a3,a4) \ + __HYPERCALL_3ARG(a1,a2,a3) __arg4 = (unsigned long)(a4); +#define __HYPERCALL_5ARG(a1,a2,a3,a4,a5) \ + __HYPERCALL_4ARG(a1,a2,a3,a4) __arg5 = (unsigned long)(a5); + +#define __HYPERCALL_CLOBBER5 "memory" +#define __HYPERCALL_CLOBBER4 __HYPERCALL_CLOBBER5, __HYPERCALL_ARG5REG +#define __HYPERCALL_CLOBBER3 __HYPERCALL_CLOBBER4, __HYPERCALL_ARG4REG +#define __HYPERCALL_CLOBBER2 __HYPERCALL_CLOBBER3, __HYPERCALL_ARG3REG +#define __HYPERCALL_CLOBBER1 __HYPERCALL_CLOBBER2, __HYPERCALL_ARG2REG +#define __HYPERCALL_CLOBBER0 __HYPERCALL_CLOBBER1, __HYPERCALL_ARG1REG + #define _hypercall0(type, name) \ ({ \ - long __res; \ - asm volatile ( \ - "call %[call]" \ - : "=a" (__res) \ - : [call] "m" (hypercall_page[__HYPERVISOR_##name]) \ - : "memory" ); \ + __HYPERCALL_DECLS; \ + __HYPERCALL_0ARG(); \ + asm volatile (__HYPERCALL \ + : __HYPERCALL_0PARAM \ + : __HYPERCALL_ENTRY(name) \ + : __HYPERCALL_CLOBBER0); \ (type)__res; \ }) #define _hypercall1(type, name, a1) \ ({ \ - long __res, __ign1; \ - asm volatile ( \ - "call %[call]" \ - : "=a" (__res), "=b" (__ign1) \ - : "1" ((long)(a1)), \ - [call] "m" (hypercall_page[__HYPERVISOR_##name]) \ - : "memory" ); \ + __HYPERCALL_DECLS; \ + __HYPERCALL_1ARG(a1); \ + asm volatile (__HYPERCALL \ + : __HYPERCALL_1PARAM \ + : __HYPERCALL_ENTRY(name) \ + : __HYPERCALL_CLOBBER1); \ (type)__res; \ }) #define _hypercall2(type, name, a1, a2) \ ({ \ - long __res, __ign1, __ign2; \ - asm volatile ( \ - "call %[call]" \ - : "=a" (__res), "=b" (__ign1), "=c" (__ign2) \ - : "1" ((long)(a1)), "2" ((long)(a2)), \ - [call] "m" (hypercall_page[__HYPERVISOR_##name]) \ - : "memory" ); \ + __HYPERCALL_DECLS; \ + __HYPERCALL_2ARG(a1, a2); \ + asm volatile (__HYPERCALL \ + : __HYPERCALL_2PARAM \ + : __HYPERCALL_ENTRY(name) \ + : __HYPERCALL_CLOBBER2); \ (type)__res; \ }) #define _hypercall3(type, name, a1, a2, a3) \ ({ \ - long __res, __ign1, __ign2, __ign3; \ - asm volatile ( \ - "call %[call]" \ - : "=a" (__res), "=b" (__ign1), "=c" (__ign2), \ - "=d" (__ign3) \ - : "1" ((long)(a1)), "2" ((long)(a2)), \ - "3" ((long)(a3)), \ - [call] "m" (hypercall_page[__HYPERVISOR_##name]) \ - : "memory" ); \ + __HYPERCALL_DECLS; \ + __HYPERCALL_3ARG(a1, a2, a3); \ + asm volatile (__HYPERCALL \ + : __HYPERCALL_3PARAM \ + : __HYPERCALL_ENTRY(name) \ + : __HYPERCALL_CLOBBER3); \ (type)__res; \ }) #define _hypercall4(type, name, a1, a2, a3, a4) \ ({ \ - long __res, __ign1, __ign2, __ign3, __ign4; \ - asm volatile ( \ - "call %[call]" \ - : "=a" (__res), "=b" (__ign1), "=c" (__ign2), \ - "=d" (__ign3), "=S" (__ign4) \ - : "1" ((long)(a1)), "2" ((long)(a2)), \ - "3" ((long)(a3)), "4" ((long)(a4)), \ - [call] "m" (hypercall_page[__HYPERVISOR_##name]) \ - : "memory" ); \ + __HYPERCALL_DECLS; \ + __HYPERCALL_4ARG(a1, a2, a3, a4); \ + asm volatile (__HYPERCALL \ + : __HYPERCALL_4PARAM \ + : __HYPERCALL_ENTRY(name) \ + : __HYPERCALL_CLOBBER4); \ (type)__res; \ }) #define _hypercall5(type, name, a1, a2, a3, a4, a5) \ ({ \ - long __res, __ign1, __ign2, __ign3, __ign4, __ign5; \ - asm volatile ( \ - "call %[call]" \ - : "=a" (__res), "=b" (__ign1), "=c" (__ign2), \ - "=d" (__ign3), "=S" (__ign4), "=D" (__ign5) \ - : "1" ((long)(a1)), "2" ((long)(a2)), \ - "3" ((long)(a3)), "4" ((long)(a4)), \ - "5" ((long)(a5)), \ - [call] "m" (hypercall_page[__HYPERVISOR_##name]) \ - : "memory" ); \ + __HYPERCALL_DECLS; \ + __HYPERCALL_5ARG(a1, a2, a3, a4, a5); \ + asm volatile (__HYPERCALL \ + : __HYPERCALL_5PARAM \ + : __HYPERCALL_ENTRY(name) \ + : __HYPERCALL_CLOBBER5); \ (type)__res; \ }) @@ -152,6 +226,7 @@ HYPERVISOR_stack_switch(unsigned long ss, unsigned long esp) return _hypercall2(int, stack_switch, ss, esp); } +#ifdef CONFIG_X86_32 static inline int HYPERVISOR_set_callbacks(unsigned long event_selector, unsigned long event_address, @@ -162,6 +237,17 @@ HYPERVISOR_set_callbacks(unsigned long event_selector, event_selector, event_address, failsafe_selector, failsafe_address); } +#else /* CONFIG_X86_64 */ +static inline int +HYPERVISOR_set_callbacks(unsigned long event_address, + unsigned long failsafe_address, + unsigned long syscall_address) +{ + return _hypercall3(int, set_callbacks, + event_address, failsafe_address, + syscall_address); +} +#endif /* CONFIG_X86_{32,64} */ static inline int HYPERVISOR_callback_op(int cmd, void *arg) @@ -223,12 +309,12 @@ static inline int HYPERVISOR_update_va_mapping(unsigned long va, pte_t new_val, unsigned long flags) { - unsigned long pte_hi = 0; -#ifdef CONFIG_X86_PAE - pte_hi = new_val.pte_high; -#endif - return _hypercall4(int, update_va_mapping, va, - new_val.pte_low, pte_hi, flags); + if (sizeof(new_val) == sizeof(long)) + return _hypercall3(int, update_va_mapping, va, + new_val.pte, flags); + else + return _hypercall4(int, update_va_mapping, va, + new_val.pte, new_val.pte >> 32, flags); } static inline int @@ -281,12 +367,13 @@ static inline int HYPERVISOR_update_va_mapping_otherdomain(unsigned long va, pte_t new_val, unsigned long flags, domid_t domid) { - unsigned long pte_hi = 0; -#ifdef CONFIG_X86_PAE - pte_hi = new_val.pte_high; -#endif - return _hypercall5(int, update_va_mapping_otherdomain, va, - new_val.pte_low, pte_hi, flags, domid); + if (sizeof(new_val) == sizeof(long)) + return _hypercall4(int, update_va_mapping_otherdomain, va, + new_val.pte, flags, domid); + else + return _hypercall5(int, update_va_mapping_otherdomain, va, + new_val.pte, new_val.pte >> 32, + flags, domid); } static inline int @@ -301,6 +388,14 @@ HYPERVISOR_vcpu_op(int cmd, int vcpuid, void *extra_args) return _hypercall3(int, vcpu_op, cmd, vcpuid, extra_args); } +#ifdef CONFIG_X86_64 +static inline int +HYPERVISOR_set_segment_base(int reg, unsigned long value) +{ + return _hypercall2(int, set_segment_base, reg, value); +} +#endif + static inline int HYPERVISOR_suspend(unsigned long srec) { @@ -327,14 +422,14 @@ MULTI_update_va_mapping(struct multicall_entry *mcl, unsigned long va, { mcl->op = __HYPERVISOR_update_va_mapping; mcl->args[0] = va; -#ifdef CONFIG_X86_PAE - mcl->args[1] = new_val.pte_low; - mcl->args[2] = new_val.pte_high; -#else - mcl->args[1] = new_val.pte_low; - mcl->args[2] = 0; -#endif - mcl->args[3] = flags; + if (sizeof(new_val) == sizeof(long)) { + mcl->args[1] = new_val.pte; + mcl->args[2] = flags; + } else { + mcl->args[1] = new_val.pte; + mcl->args[2] = new_val.pte >> 32; + mcl->args[3] = flags; + } } static inline void @@ -354,15 +449,16 @@ MULTI_update_va_mapping_otherdomain(struct multicall_entry *mcl, unsigned long v { mcl->op = __HYPERVISOR_update_va_mapping_otherdomain; mcl->args[0] = va; -#ifdef CONFIG_X86_PAE - mcl->args[1] = new_val.pte_low; - mcl->args[2] = new_val.pte_high; -#else - mcl->args[1] = new_val.pte_low; - mcl->args[2] = 0; -#endif - mcl->args[3] = flags; - mcl->args[4] = domid; + if (sizeof(new_val) == sizeof(long)) { + mcl->args[1] = new_val.pte; + mcl->args[2] = flags; + mcl->args[3] = domid; + } else { + mcl->args[1] = new_val.pte; + mcl->args[2] = new_val.pte >> 32; + mcl->args[3] = flags; + mcl->args[4] = domid; + } } static inline void @@ -370,10 +466,15 @@ MULTI_update_descriptor(struct multicall_entry *mcl, u64 maddr, struct desc_struct desc) { mcl->op = __HYPERVISOR_update_descriptor; - mcl->args[0] = maddr; - mcl->args[1] = maddr >> 32; - mcl->args[2] = desc.a; - mcl->args[3] = desc.b; + if (sizeof(maddr) == sizeof(long)) { + mcl->args[0] = maddr; + mcl->args[1] = *(unsigned long *)&desc; + } else { + mcl->args[0] = maddr; + mcl->args[1] = maddr >> 32; + mcl->args[2] = desc.a; + mcl->args[3] = desc.b; + } } static inline void diff --git a/include/asm-x86/xen/interface.h b/include/asm-x86/xen/interface.h index 6227000a1e84..9d810f2538a2 100644 --- a/include/asm-x86/xen/interface.h +++ b/include/asm-x86/xen/interface.h @@ -1,13 +1,13 @@ /****************************************************************************** * arch-x86_32.h * - * Guest OS interface to x86 32-bit Xen. + * Guest OS interface to x86 Xen. * * Copyright (c) 2004, K A Fraser */ -#ifndef __XEN_PUBLIC_ARCH_X86_32_H__ -#define __XEN_PUBLIC_ARCH_X86_32_H__ +#ifndef __ASM_X86_XEN_INTERFACE_H +#define __ASM_X86_XEN_INTERFACE_H #ifdef __XEN__ #define __DEFINE_GUEST_HANDLE(name, type) \ @@ -57,6 +57,17 @@ DEFINE_GUEST_HANDLE(long); DEFINE_GUEST_HANDLE(void); #endif +#ifndef HYPERVISOR_VIRT_START +#define HYPERVISOR_VIRT_START mk_unsigned_long(__HYPERVISOR_VIRT_START) +#endif + +#ifndef machine_to_phys_mapping +#define machine_to_phys_mapping ((unsigned long *)HYPERVISOR_VIRT_START) +#endif + +/* Maximum number of virtual CPUs in multi-processor guests. */ +#define MAX_VIRT_CPUS 32 + /* * SEGMENT DESCRIPTOR TABLES */ @@ -71,58 +82,21 @@ DEFINE_GUEST_HANDLE(void); #define FIRST_RESERVED_GDT_ENTRY (FIRST_RESERVED_GDT_BYTE / 8) /* - * These flat segments are in the Xen-private section of every GDT. Since these - * are also present in the initial GDT, many OSes will be able to avoid - * installing their own GDT. - */ -#define FLAT_RING1_CS 0xe019 /* GDT index 259 */ -#define FLAT_RING1_DS 0xe021 /* GDT index 260 */ -#define FLAT_RING1_SS 0xe021 /* GDT index 260 */ -#define FLAT_RING3_CS 0xe02b /* GDT index 261 */ -#define FLAT_RING3_DS 0xe033 /* GDT index 262 */ -#define FLAT_RING3_SS 0xe033 /* GDT index 262 */ - -#define FLAT_KERNEL_CS FLAT_RING1_CS -#define FLAT_KERNEL_DS FLAT_RING1_DS -#define FLAT_KERNEL_SS FLAT_RING1_SS -#define FLAT_USER_CS FLAT_RING3_CS -#define FLAT_USER_DS FLAT_RING3_DS -#define FLAT_USER_SS FLAT_RING3_SS - -/* And the trap vector is... */ -#define TRAP_INSTR "int $0x82" - -/* - * Virtual addresses beyond this are not modifiable by guest OSes. The - * machine->physical mapping table starts at this address, read-only. - */ -#ifdef CONFIG_X86_PAE -#define __HYPERVISOR_VIRT_START 0xF5800000 -#else -#define __HYPERVISOR_VIRT_START 0xFC000000 -#endif - -#ifndef HYPERVISOR_VIRT_START -#define HYPERVISOR_VIRT_START mk_unsigned_long(__HYPERVISOR_VIRT_START) -#endif - -#ifndef machine_to_phys_mapping -#define machine_to_phys_mapping ((unsigned long *)HYPERVISOR_VIRT_START) -#endif - -/* Maximum number of virtual CPUs in multi-processor guests. */ -#define MAX_VIRT_CPUS 32 - -#ifndef __ASSEMBLY__ - -/* * Send an array of these to HYPERVISOR_set_trap_table() + * The privilege level specifies which modes may enter a trap via a software + * interrupt. On x86/64, since rings 1 and 2 are unavailable, we allocate + * privilege levels as follows: + * Level == 0: Noone may enter + * Level == 1: Kernel may enter + * Level == 2: Kernel may enter + * Level == 3: Everyone may enter */ #define TI_GET_DPL(_ti) ((_ti)->flags & 3) #define TI_GET_IF(_ti) ((_ti)->flags & 4) #define TI_SET_DPL(_ti, _dpl) ((_ti)->flags |= (_dpl)) #define TI_SET_IF(_ti, _if) ((_ti)->flags |= ((!!(_if))<<2)) +#ifndef __ASSEMBLY__ struct trap_info { uint8_t vector; /* exception vector */ uint8_t flags; /* 0-3: privilege level; 4: clear event enable? */ @@ -131,32 +105,21 @@ struct trap_info { }; DEFINE_GUEST_HANDLE_STRUCT(trap_info); -struct cpu_user_regs { - uint32_t ebx; - uint32_t ecx; - uint32_t edx; - uint32_t esi; - uint32_t edi; - uint32_t ebp; - uint32_t eax; - uint16_t error_code; /* private */ - uint16_t entry_vector; /* private */ - uint32_t eip; - uint16_t cs; - uint8_t saved_upcall_mask; - uint8_t _pad0; - uint32_t eflags; /* eflags.IF == !saved_upcall_mask */ - uint32_t esp; - uint16_t ss, _pad1; - uint16_t es, _pad2; - uint16_t ds, _pad3; - uint16_t fs, _pad4; - uint16_t gs, _pad5; +struct arch_shared_info { + unsigned long max_pfn; /* max pfn that appears in table */ + /* Frame containing list of mfns containing list of mfns containing p2m. */ + unsigned long pfn_to_mfn_frame_list_list; + unsigned long nmi_reason; }; -DEFINE_GUEST_HANDLE_STRUCT(cpu_user_regs); +#endif /* !__ASSEMBLY__ */ -typedef uint64_t tsc_timestamp_t; /* RDTSC timestamp */ +#ifdef CONFIG_X86_32 +#include "interface_32.h" +#else +#include "interface_64.h" +#endif +#ifndef __ASSEMBLY__ /* * The following is all CPU context. Note that the fpu_ctxt block is filled * in by FXSAVE if the CPU has feature FXSR; otherwise FSAVE is used. @@ -173,33 +136,29 @@ struct vcpu_guest_context { unsigned long ldt_base, ldt_ents; /* LDT (linear address, # ents) */ unsigned long gdt_frames[16], gdt_ents; /* GDT (machine frames, # ents) */ unsigned long kernel_ss, kernel_sp; /* Virtual TSS (only SS1/SP1) */ + /* NB. User pagetable on x86/64 is placed in ctrlreg[1]. */ unsigned long ctrlreg[8]; /* CR0-CR7 (control registers) */ unsigned long debugreg[8]; /* DB0-DB7 (debug registers) */ +#ifdef __i386__ unsigned long event_callback_cs; /* CS:EIP of event callback */ unsigned long event_callback_eip; unsigned long failsafe_callback_cs; /* CS:EIP of failsafe callback */ unsigned long failsafe_callback_eip; +#else + unsigned long event_callback_eip; + unsigned long failsafe_callback_eip; + unsigned long syscall_callback_eip; +#endif unsigned long vm_assist; /* VMASST_TYPE_* bitmap */ +#ifdef __x86_64__ + /* Segment base addresses. */ + uint64_t fs_base; + uint64_t gs_base_kernel; + uint64_t gs_base_user; +#endif }; DEFINE_GUEST_HANDLE_STRUCT(vcpu_guest_context); - -struct arch_shared_info { - unsigned long max_pfn; /* max pfn that appears in table */ - /* Frame containing list of mfns containing list of mfns containing p2m. */ - unsigned long pfn_to_mfn_frame_list_list; - unsigned long nmi_reason; -}; - -struct arch_vcpu_info { - unsigned long cr2; - unsigned long pad[5]; /* sizeof(struct vcpu_info) == 64 */ -}; - -struct xen_callback { - unsigned long cs; - unsigned long eip; -}; -#endif /* !__ASSEMBLY__ */ +#endif /* !__ASSEMBLY__ */ /* * Prefix forces emulation of some non-trapping instructions. @@ -213,4 +172,4 @@ struct xen_callback { #define XEN_CPUID XEN_EMULATE_PREFIX "cpuid" #endif -#endif +#endif /* __ASM_X86_XEN_INTERFACE_H */ diff --git a/include/asm-x86/xen/interface_32.h b/include/asm-x86/xen/interface_32.h new file mode 100644 index 000000000000..d8ac41d5db86 --- /dev/null +++ b/include/asm-x86/xen/interface_32.h @@ -0,0 +1,97 @@ +/****************************************************************************** + * arch-x86_32.h + * + * Guest OS interface to x86 32-bit Xen. + * + * Copyright (c) 2004, K A Fraser + */ + +#ifndef __ASM_X86_XEN_INTERFACE_32_H +#define __ASM_X86_XEN_INTERFACE_32_H + + +/* + * These flat segments are in the Xen-private section of every GDT. Since these + * are also present in the initial GDT, many OSes will be able to avoid + * installing their own GDT. + */ +#define FLAT_RING1_CS 0xe019 /* GDT index 259 */ +#define FLAT_RING1_DS 0xe021 /* GDT index 260 */ +#define FLAT_RING1_SS 0xe021 /* GDT index 260 */ +#define FLAT_RING3_CS 0xe02b /* GDT index 261 */ +#define FLAT_RING3_DS 0xe033 /* GDT index 262 */ +#define FLAT_RING3_SS 0xe033 /* GDT index 262 */ + +#define FLAT_KERNEL_CS FLAT_RING1_CS +#define FLAT_KERNEL_DS FLAT_RING1_DS +#define FLAT_KERNEL_SS FLAT_RING1_SS +#define FLAT_USER_CS FLAT_RING3_CS +#define FLAT_USER_DS FLAT_RING3_DS +#define FLAT_USER_SS FLAT_RING3_SS + +/* And the trap vector is... */ +#define TRAP_INSTR "int $0x82" + +/* + * Virtual addresses beyond this are not modifiable by guest OSes. The + * machine->physical mapping table starts at this address, read-only. + */ +#define __HYPERVISOR_VIRT_START 0xF5800000 + +#ifndef __ASSEMBLY__ + +struct cpu_user_regs { + uint32_t ebx; + uint32_t ecx; + uint32_t edx; + uint32_t esi; + uint32_t edi; + uint32_t ebp; + uint32_t eax; + uint16_t error_code; /* private */ + uint16_t entry_vector; /* private */ + uint32_t eip; + uint16_t cs; + uint8_t saved_upcall_mask; + uint8_t _pad0; + uint32_t eflags; /* eflags.IF == !saved_upcall_mask */ + uint32_t esp; + uint16_t ss, _pad1; + uint16_t es, _pad2; + uint16_t ds, _pad3; + uint16_t fs, _pad4; + uint16_t gs, _pad5; +}; +DEFINE_GUEST_HANDLE_STRUCT(cpu_user_regs); + +typedef uint64_t tsc_timestamp_t; /* RDTSC timestamp */ + +struct arch_vcpu_info { + unsigned long cr2; + unsigned long pad[5]; /* sizeof(struct vcpu_info) == 64 */ +}; + +struct xen_callback { + unsigned long cs; + unsigned long eip; +}; +typedef struct xen_callback xen_callback_t; + +#define XEN_CALLBACK(__cs, __eip) \ + ((struct xen_callback){ .cs = (__cs), .eip = (unsigned long)(__eip) }) +#endif /* !__ASSEMBLY__ */ + + +/* + * Page-directory addresses above 4GB do not fit into architectural %cr3. + * When accessing %cr3, or equivalent field in vcpu_guest_context, guests + * must use the following accessor macros to pack/unpack valid MFNs. + * + * Note that Xen is using the fact that the pagetable base is always + * page-aligned, and putting the 12 MSB of the address into the 12 LSB + * of cr3. + */ +#define xen_pfn_to_cr3(pfn) (((unsigned)(pfn) << 12) | ((unsigned)(pfn) >> 20)) +#define xen_cr3_to_pfn(cr3) (((unsigned)(cr3) >> 12) | ((unsigned)(cr3) << 20)) + +#endif /* __ASM_X86_XEN_INTERFACE_32_H */ diff --git a/include/asm-x86/xen/interface_64.h b/include/asm-x86/xen/interface_64.h new file mode 100644 index 000000000000..842266ce96e6 --- /dev/null +++ b/include/asm-x86/xen/interface_64.h @@ -0,0 +1,159 @@ +#ifndef __ASM_X86_XEN_INTERFACE_64_H +#define __ASM_X86_XEN_INTERFACE_64_H + +/* + * 64-bit segment selectors + * These flat segments are in the Xen-private section of every GDT. Since these + * are also present in the initial GDT, many OSes will be able to avoid + * installing their own GDT. + */ + +#define FLAT_RING3_CS32 0xe023 /* GDT index 260 */ +#define FLAT_RING3_CS64 0xe033 /* GDT index 261 */ +#define FLAT_RING3_DS32 0xe02b /* GDT index 262 */ +#define FLAT_RING3_DS64 0x0000 /* NULL selector */ +#define FLAT_RING3_SS32 0xe02b /* GDT index 262 */ +#define FLAT_RING3_SS64 0xe02b /* GDT index 262 */ + +#define FLAT_KERNEL_DS64 FLAT_RING3_DS64 +#define FLAT_KERNEL_DS32 FLAT_RING3_DS32 +#define FLAT_KERNEL_DS FLAT_KERNEL_DS64 +#define FLAT_KERNEL_CS64 FLAT_RING3_CS64 +#define FLAT_KERNEL_CS32 FLAT_RING3_CS32 +#define FLAT_KERNEL_CS FLAT_KERNEL_CS64 +#define FLAT_KERNEL_SS64 FLAT_RING3_SS64 +#define FLAT_KERNEL_SS32 FLAT_RING3_SS32 +#define FLAT_KERNEL_SS FLAT_KERNEL_SS64 + +#define FLAT_USER_DS64 FLAT_RING3_DS64 +#define FLAT_USER_DS32 FLAT_RING3_DS32 +#define FLAT_USER_DS FLAT_USER_DS64 +#define FLAT_USER_CS64 FLAT_RING3_CS64 +#define FLAT_USER_CS32 FLAT_RING3_CS32 +#define FLAT_USER_CS FLAT_USER_CS64 +#define FLAT_USER_SS64 FLAT_RING3_SS64 +#define FLAT_USER_SS32 FLAT_RING3_SS32 +#define FLAT_USER_SS FLAT_USER_SS64 + +#define __HYPERVISOR_VIRT_START 0xFFFF800000000000 +#define __HYPERVISOR_VIRT_END 0xFFFF880000000000 +#define __MACH2PHYS_VIRT_START 0xFFFF800000000000 +#define __MACH2PHYS_VIRT_END 0xFFFF804000000000 + +#ifndef HYPERVISOR_VIRT_START +#define HYPERVISOR_VIRT_START mk_unsigned_long(__HYPERVISOR_VIRT_START) +#define HYPERVISOR_VIRT_END mk_unsigned_long(__HYPERVISOR_VIRT_END) +#endif + +#define MACH2PHYS_VIRT_START mk_unsigned_long(__MACH2PHYS_VIRT_START) +#define MACH2PHYS_VIRT_END mk_unsigned_long(__MACH2PHYS_VIRT_END) +#define MACH2PHYS_NR_ENTRIES ((MACH2PHYS_VIRT_END-MACH2PHYS_VIRT_START)>>3) +#ifndef machine_to_phys_mapping +#define machine_to_phys_mapping ((unsigned long *)HYPERVISOR_VIRT_START) +#endif + +/* + * int HYPERVISOR_set_segment_base(unsigned int which, unsigned long base) + * @which == SEGBASE_* ; @base == 64-bit base address + * Returns 0 on success. + */ +#define SEGBASE_FS 0 +#define SEGBASE_GS_USER 1 +#define SEGBASE_GS_KERNEL 2 +#define SEGBASE_GS_USER_SEL 3 /* Set user %gs specified in base[15:0] */ + +/* + * int HYPERVISOR_iret(void) + * All arguments are on the kernel stack, in the following format. + * Never returns if successful. Current kernel context is lost. + * The saved CS is mapped as follows: + * RING0 -> RING3 kernel mode. + * RING1 -> RING3 kernel mode. + * RING2 -> RING3 kernel mode. + * RING3 -> RING3 user mode. + * However RING0 indicates that the guest kernel should return to iteself + * directly with + * orb $3,1*8(%rsp) + * iretq + * If flags contains VGCF_in_syscall: + * Restore RAX, RIP, RFLAGS, RSP. + * Discard R11, RCX, CS, SS. + * Otherwise: + * Restore RAX, R11, RCX, CS:RIP, RFLAGS, SS:RSP. + * All other registers are saved on hypercall entry and restored to user. + */ +/* Guest exited in SYSCALL context? Return to guest with SYSRET? */ +#define _VGCF_in_syscall 8 +#define VGCF_in_syscall (1<<_VGCF_in_syscall) +#define VGCF_IN_SYSCALL VGCF_in_syscall + +#ifndef __ASSEMBLY__ + +struct iret_context { + /* Top of stack (%rsp at point of hypercall). */ + uint64_t rax, r11, rcx, flags, rip, cs, rflags, rsp, ss; + /* Bottom of iret stack frame. */ +}; + +#if defined(__GNUC__) && !defined(__STRICT_ANSI__) +/* Anonymous union includes both 32- and 64-bit names (e.g., eax/rax). */ +#define __DECL_REG(name) union { \ + uint64_t r ## name, e ## name; \ + uint32_t _e ## name; \ +} +#else +/* Non-gcc sources must always use the proper 64-bit name (e.g., rax). */ +#define __DECL_REG(name) uint64_t r ## name +#endif + +struct cpu_user_regs { + uint64_t r15; + uint64_t r14; + uint64_t r13; + uint64_t r12; + __DECL_REG(bp); + __DECL_REG(bx); + uint64_t r11; + uint64_t r10; + uint64_t r9; + uint64_t r8; + __DECL_REG(ax); + __DECL_REG(cx); + __DECL_REG(dx); + __DECL_REG(si); + __DECL_REG(di); + uint32_t error_code; /* private */ + uint32_t entry_vector; /* private */ + __DECL_REG(ip); + uint16_t cs, _pad0[1]; + uint8_t saved_upcall_mask; + uint8_t _pad1[3]; + __DECL_REG(flags); /* rflags.IF == !saved_upcall_mask */ + __DECL_REG(sp); + uint16_t ss, _pad2[3]; + uint16_t es, _pad3[3]; + uint16_t ds, _pad4[3]; + uint16_t fs, _pad5[3]; /* Non-zero => takes precedence over fs_base. */ + uint16_t gs, _pad6[3]; /* Non-zero => takes precedence over gs_base_usr. */ +}; +DEFINE_GUEST_HANDLE_STRUCT(cpu_user_regs); + +#undef __DECL_REG + +#define xen_pfn_to_cr3(pfn) ((unsigned long)(pfn) << 12) +#define xen_cr3_to_pfn(cr3) ((unsigned long)(cr3) >> 12) + +struct arch_vcpu_info { + unsigned long cr2; + unsigned long pad; /* sizeof(vcpu_info_t) == 64 */ +}; + +typedef unsigned long xen_callback_t; + +#define XEN_CALLBACK(__cs, __rip) \ + ((unsigned long)(__rip)) + +#endif /* !__ASSEMBLY__ */ + + +#endif /* __ASM_X86_XEN_INTERFACE_64_H */ diff --git a/include/asm-x86/xen/page.h b/include/asm-x86/xen/page.h index 377c04591c15..05e678a86628 100644 --- a/include/asm-x86/xen/page.h +++ b/include/asm-x86/xen/page.h @@ -148,13 +148,17 @@ static inline pte_t __pte_ma(pteval_t x) } #define pmd_val_ma(v) ((v).pmd) +#ifdef __PAGETABLE_PUD_FOLDED #define pud_val_ma(v) ((v).pgd.pgd) +#else +#define pud_val_ma(v) ((v).pud) +#endif #define __pmd_ma(x) ((pmd_t) { (x) } ) #define pgd_val_ma(x) ((x).pgd) -xmaddr_t arbitrary_virt_to_machine(unsigned long address); +xmaddr_t arbitrary_virt_to_machine(void *address); void make_lowmem_page_readonly(void *vaddr); void make_lowmem_page_readwrite(void *vaddr); diff --git a/include/linux/brcmphy.h b/include/linux/brcmphy.h new file mode 100644 index 000000000000..9b64b6d67873 --- /dev/null +++ b/include/linux/brcmphy.h @@ -0,0 +1,6 @@ +#define PHY_BRCM_WIRESPEED_ENABLE 0x00000001 +#define PHY_BRCM_AUTO_PWRDWN_ENABLE 0x00000002 +#define PHY_BRCM_APD_CLK125_ENABLE 0x00000004 +#define PHY_BRCM_STD_IBND_DISABLE 0x00000008 +#define PHY_BRCM_EXT_IBND_RX_ENABLE 0x00000010 +#define PHY_BRCM_EXT_IBND_TX_ENABLE 0x00000020 diff --git a/include/linux/configfs.h b/include/linux/configfs.h index 0488f937634a..d62c19ff041c 100644 --- a/include/linux/configfs.h +++ b/include/linux/configfs.h @@ -148,7 +148,8 @@ struct configfs_attribute { * items. If the item is a group, it may support mkdir(2). * Groups supply one of make_group() and make_item(). If the * group supports make_group(), one can create group children. If it - * supports make_item(), one can create config_item children. If it has + * supports make_item(), one can create config_item children. make_group() + * and make_item() return ERR_PTR() on errors. If it has * default_groups on group->default_groups, it has automatically created * group children. default_groups may coexist alongsize make_group() or * make_item(), but if the group wishes to have only default_groups @@ -165,8 +166,8 @@ struct configfs_item_operations { }; struct configfs_group_operations { - int (*make_item)(struct config_group *group, const char *name, struct config_item **new_item); - int (*make_group)(struct config_group *group, const char *name, struct config_group **new_group); + struct config_item *(*make_item)(struct config_group *group, const char *name); + struct config_group *(*make_group)(struct config_group *group, const char *name); int (*commit_item)(struct config_item *item); void (*disconnect_notify)(struct config_group *group, struct config_item *item); void (*drop_item)(struct config_group *group, struct config_item *item); diff --git a/include/linux/cyclades.h b/include/linux/cyclades.h index 504cb2c3fa9a..2d3d1e04ba92 100644 --- a/include/linux/cyclades.h +++ b/include/linux/cyclades.h @@ -550,11 +550,11 @@ struct cyclades_icount { struct cyclades_port { int magic; + struct tty_port port; struct cyclades_card *card; int line; int flags; /* defined in tty.h */ int type; /* UART type */ - struct tty_struct *tty; int read_status_mask; int ignore_status_mask; int timeout; @@ -567,13 +567,8 @@ struct cyclades_port { int chip_rev; int custom_divisor; u8 x_char; /* to be pushed out ASAP */ - int close_delay; - unsigned short closing_wait; - int count; /* # of fd on device */ int breakon; int breakoff; - int blocked_open; /* # of blocked opens */ - unsigned char *xmit_buf; int xmit_head; int xmit_tail; int xmit_cnt; @@ -583,16 +578,14 @@ struct cyclades_port { struct cyclades_monitor mon; struct cyclades_idle_stats idle_stats; struct cyclades_icount icount; - wait_queue_head_t open_wait; - wait_queue_head_t close_wait; struct completion shutdown_wait; wait_queue_head_t delta_msr_wait; int throttle; }; #define CLOSING_WAIT_DELAY 30*HZ -#define CY_CLOSING_WAIT_NONE 65535 -#define CY_CLOSING_WAIT_INF 0 +#define CY_CLOSING_WAIT_NONE ASYNC_CLOSING_WAIT_NONE +#define CY_CLOSING_WAIT_INF ASYNC_CLOSING_WAIT_INF #define CyMAX_CHIPS_PER_CARD 8 diff --git a/include/linux/dccp.h b/include/linux/dccp.h index aa0737019e37..6080449fbec9 100644 --- a/include/linux/dccp.h +++ b/include/linux/dccp.h @@ -364,8 +364,6 @@ static inline unsigned int dccp_hdr_len(const struct sk_buff *skb) /* FIXME: for now we're default to 1 but it should really be 0 */ #define DCCPF_INITIAL_SEND_NDP_COUNT 1 -#define DCCP_NDP_LIMIT 0xFFFFFF - /** * struct dccp_minisock - Minimal DCCP connection representation * @@ -437,7 +435,7 @@ extern int dccp_parse_options(struct sock *sk, struct dccp_request_sock *dreq, struct sk_buff *skb); struct dccp_options_received { - u32 dccpor_ndp; /* only 24 bits */ + u64 dccpor_ndp:48; u32 dccpor_timestamp; u32 dccpor_timestamp_echo; u32 dccpor_elapsed_time; @@ -533,7 +531,7 @@ struct dccp_sock { __u16 dccps_r_ack_ratio; __u16 dccps_pcslen; __u16 dccps_pcrlen; - unsigned long dccps_ndp_count; + __u64 dccps_ndp_count:48; unsigned long dccps_rate_last; struct dccp_minisock dccps_minisock; struct dccp_ackvec *dccps_hc_rx_ackvec; diff --git a/include/linux/debugfs.h b/include/linux/debugfs.h index 7266124361b4..32755cdf68db 100644 --- a/include/linux/debugfs.h +++ b/include/linux/debugfs.h @@ -26,6 +26,8 @@ struct debugfs_blob_wrapper { unsigned long size; }; +extern struct dentry *arch_debugfs_dir; + #if defined(CONFIG_DEBUG_FS) /* declared over in file.c */ diff --git a/include/linux/dm9000.h b/include/linux/dm9000.h index a3750462f9e3..fc82446b6425 100644 --- a/include/linux/dm9000.h +++ b/include/linux/dm9000.h @@ -21,6 +21,7 @@ #define DM9000_PLATF_32BITONLY (0x0004) #define DM9000_PLATF_EXT_PHY (0x0008) #define DM9000_PLATF_NO_EEPROM (0x0010) +#define DM9000_PLATF_SIMPLE_PHY (0x0020) /* Use NSR to find LinkStatus */ /* platfrom data for platfrom device structure's platfrom_data field */ diff --git a/include/linux/ethtool.h b/include/linux/ethtool.h index c8d216357865..8bb5e87df365 100644 --- a/include/linux/ethtool.h +++ b/include/linux/ethtool.h @@ -272,6 +272,12 @@ enum ethtool_flags { ETH_FLAG_LRO = (1 << 15), /* LRO is enabled */ }; +struct ethtool_rxnfc { + __u32 cmd; + __u32 flow_type; + __u64 data; +}; + #ifdef __KERNEL__ struct net_device; @@ -396,6 +402,8 @@ struct ethtool_ops { /* the following hooks are obsolete */ int (*self_test_count)(struct net_device *);/* use get_sset_count */ int (*get_stats_count)(struct net_device *);/* use get_sset_count */ + int (*get_rxhash)(struct net_device *, struct ethtool_rxnfc *); + int (*set_rxhash)(struct net_device *, struct ethtool_rxnfc *); }; #endif /* __KERNEL__ */ @@ -442,6 +450,9 @@ struct ethtool_ops { #define ETHTOOL_GPFLAGS 0x00000027 /* Get driver-private flags bitmap */ #define ETHTOOL_SPFLAGS 0x00000028 /* Set driver-private flags bitmap */ +#define ETHTOOL_GRXFH 0x00000029 /* Get RX flow hash configuration */ +#define ETHTOOL_SRXFH 0x0000002a /* Set RX flow hash configuration */ + /* compatibility with older code */ #define SPARC_ETH_GSET ETHTOOL_GSET #define SPARC_ETH_SSET ETHTOOL_SSET @@ -528,4 +539,26 @@ struct ethtool_ops { #define WAKE_MAGIC (1 << 5) #define WAKE_MAGICSECURE (1 << 6) /* only meaningful if WAKE_MAGIC */ +/* L3-L4 network traffic flow types */ +#define TCP_V4_FLOW 0x01 +#define UDP_V4_FLOW 0x02 +#define SCTP_V4_FLOW 0x03 +#define AH_ESP_V4_FLOW 0x04 +#define TCP_V6_FLOW 0x05 +#define UDP_V6_FLOW 0x06 +#define SCTP_V6_FLOW 0x07 +#define AH_ESP_V6_FLOW 0x08 + +/* L3-L4 network traffic flow hash options */ +#define RXH_DEV_PORT (1 << 0) +#define RXH_L2DA (1 << 1) +#define RXH_VLAN (1 << 2) +#define RXH_L3_PROTO (1 << 3) +#define RXH_IP_SRC (1 << 4) +#define RXH_IP_DST (1 << 5) +#define RXH_L4_B_0_1 (1 << 6) /* src port in case of TCP/UDP/SCTP */ +#define RXH_L4_B_2_3 (1 << 7) /* dst port in case of TCP/UDP/SCTP */ +#define RXH_DISCARD (1 << 31) + + #endif /* _LINUX_ETHTOOL_H */ diff --git a/include/linux/fs.h b/include/linux/fs.h index c6455dadb21b..9c2ac5c0ef5c 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -918,12 +918,12 @@ struct file_lock { struct list_head fl_link; /* doubly linked list of all locks */ struct list_head fl_block; /* circular list of blocked processes */ fl_owner_t fl_owner; + unsigned char fl_flags; + unsigned char fl_type; unsigned int fl_pid; struct pid *fl_nspid; wait_queue_head_t fl_wait; struct file *fl_file; - unsigned char fl_flags; - unsigned char fl_type; loff_t fl_start; loff_t fl_end; diff --git a/include/linux/generic_serial.h b/include/linux/generic_serial.h index 110833666e37..4cc913939817 100644 --- a/include/linux/generic_serial.h +++ b/include/linux/generic_serial.h @@ -14,6 +14,7 @@ #ifdef __KERNEL__ #include <linux/mutex.h> +#include <linux/tty.h> struct real_driver { void (*disable_tx_interrupts) (void *); @@ -33,17 +34,12 @@ struct real_driver { struct gs_port { int magic; + struct tty_port port; unsigned char *xmit_buf; int xmit_head; int xmit_tail; int xmit_cnt; struct mutex port_write_mutex; - int flags; - wait_queue_head_t open_wait; - wait_queue_head_t close_wait; - int count; - int blocked_open; - struct tty_struct *tty; unsigned long event; unsigned short closing_wait; int close_delay; diff --git a/include/linux/hayesesp.h b/include/linux/hayesesp.h index 2177ee5b2fe2..940aeb51d53f 100644 --- a/include/linux/hayesesp.h +++ b/include/linux/hayesesp.h @@ -76,11 +76,10 @@ struct hayes_esp_config { struct esp_struct { int magic; + struct tty_port port; spinlock_t lock; - int port; + int io_port; int irq; - int flags; /* defined in tty.h */ - struct tty_struct *tty; int read_status_mask; int ignore_status_mask; int timeout; @@ -93,14 +92,10 @@ struct esp_struct { int MCR; /* Modem control register */ unsigned long last_active; int line; - int count; /* # of fd on device */ - int blocked_open; /* # of blocked opens */ unsigned char *xmit_buf; int xmit_head; int xmit_tail; int xmit_cnt; - wait_queue_head_t open_wait; - wait_queue_head_t close_wait; wait_queue_head_t delta_msr_wait; wait_queue_head_t break_wait; struct async_icount icount; /* kernel counters for the 4 input interrupts */ diff --git a/include/linux/hdlc.h b/include/linux/hdlc.h index 6115545a5b9c..c59769693bee 100644 --- a/include/linux/hdlc.h +++ b/include/linux/hdlc.h @@ -45,7 +45,6 @@ struct hdlc_proto { /* Pointed to by dev->priv */ typedef struct hdlc_device { - struct net_device_stats stats; /* used by HDLC layer to take control over HDLC device from hw driver*/ int (*attach)(struct net_device *dev, unsigned short encoding, unsigned short parity); @@ -109,12 +108,6 @@ int attach_hdlc_protocol(struct net_device *dev, struct hdlc_proto *proto, /* May be used by hardware driver to gain control over HDLC device */ void detach_hdlc_protocol(struct net_device *dev); -static __inline__ struct net_device_stats *hdlc_stats(struct net_device *dev) -{ - return &dev_to_hdlc(dev)->stats; -} - - static __inline__ __be16 hdlc_type_trans(struct sk_buff *skb, struct net_device *dev) { diff --git a/include/linux/i2c-id.h b/include/linux/i2c-id.h index ef13b7c66df3..4862398e05bf 100644 --- a/include/linux/i2c-id.h +++ b/include/linux/i2c-id.h @@ -33,15 +33,11 @@ #define I2C_DRIVERID_MSP3400 1 #define I2C_DRIVERID_TUNER 2 -#define I2C_DRIVERID_TDA8425 4 /* stereo sound processor */ #define I2C_DRIVERID_TEA6420 5 /* audio matrix switch */ #define I2C_DRIVERID_TEA6415C 6 /* video matrix switch */ #define I2C_DRIVERID_TDA9840 7 /* stereo sound processor */ #define I2C_DRIVERID_SAA7111A 8 /* video input processor */ #define I2C_DRIVERID_SAA7185B 13 /* video encoder */ -#define I2C_DRIVERID_TEA6300 18 /* audio mixer */ -#define I2C_DRIVERID_TDA9850 20 /* audio mixer */ -#define I2C_DRIVERID_TDA9855 21 /* audio mixer */ #define I2C_DRIVERID_SAA7110 22 /* video decoder */ #define I2C_DRIVERID_MGATVO 23 /* Matrox TVOut */ #define I2C_DRIVERID_SAA5249 24 /* SAA5249 and compatibles */ @@ -50,9 +46,7 @@ #define I2C_DRIVERID_TDA7432 27 /* Stereo sound processor */ #define I2C_DRIVERID_TVMIXER 28 /* Mixer driver for tv cards */ #define I2C_DRIVERID_TVAUDIO 29 /* Generic TV sound driver */ -#define I2C_DRIVERID_TDA9873 31 /* TV sound decoder chip */ #define I2C_DRIVERID_TDA9875 32 /* TV sound decoder chip */ -#define I2C_DRIVERID_PIC16C54_PV9 33 /* Audio mux/ir receiver */ #define I2C_DRIVERID_BT819 40 /* video decoder */ #define I2C_DRIVERID_BT856 41 /* video encoder */ #define I2C_DRIVERID_VPX3220 42 /* video decoder+vbi/vtxt */ @@ -63,7 +57,6 @@ #define I2C_DRIVERID_INDYCAM 58 /* SGI IndyCam */ #define I2C_DRIVERID_OVCAMCHIP 61 /* OmniVision CMOS image sens. */ #define I2C_DRIVERID_MAX6900 63 /* MAX6900 real-time clock */ -#define I2C_DRIVERID_TDA9874 66 /* TV sound decoder */ #define I2C_DRIVERID_SAA6752HS 67 /* MPEG2 encoder */ #define I2C_DRIVERID_TVEEPROM 68 /* TV EEPROM */ #define I2C_DRIVERID_WM8775 69 /* wm8775 audio processor */ @@ -158,7 +151,6 @@ #define I2C_HW_SMBUS_W9968CF 0x04000d #define I2C_HW_SMBUS_OV511 0x04000e /* OV511(+) USB 1.1 webcam ICs */ #define I2C_HW_SMBUS_OV518 0x04000f /* OV518(+) USB 1.1 webcam ICs */ -#define I2C_HW_SMBUS_OVFX2 0x040011 /* Cypress/OmniVision FX2 webcam */ #define I2C_HW_SMBUS_CAFE 0x040012 /* Marvell 88ALP01 "CAFE" cam */ #define I2C_HW_SMBUS_ALI1563 0x040013 diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h index 0b5e03eae6d2..a1630ba0b87c 100644 --- a/include/linux/ieee80211.h +++ b/include/linux/ieee80211.h @@ -98,6 +98,9 @@ #define IEEE80211_MAX_SSID_LEN 32 #define IEEE80211_MAX_MESH_ID_LEN 32 +#define IEEE80211_QOS_CTL_LEN 2 +#define IEEE80211_QOS_CTL_TID_MASK 0x000F +#define IEEE80211_QOS_CTL_TAG1D_MASK 0x0007 struct ieee80211_hdr { __le16 frame_control; @@ -109,6 +112,355 @@ struct ieee80211_hdr { u8 addr4[6]; } __attribute__ ((packed)); +/** + * ieee80211_has_tods - check if IEEE80211_FCTL_TODS is set + * @fc: frame control bytes in little-endian byteorder + */ +static inline int ieee80211_has_tods(__le16 fc) +{ + return (fc & cpu_to_le16(IEEE80211_FCTL_TODS)) != 0; +} + +/** + * ieee80211_has_fromds - check if IEEE80211_FCTL_FROMDS is set + * @fc: frame control bytes in little-endian byteorder + */ +static inline int ieee80211_has_fromds(__le16 fc) +{ + return (fc & cpu_to_le16(IEEE80211_FCTL_FROMDS)) != 0; +} + +/** + * ieee80211_has_a4 - check if IEEE80211_FCTL_TODS and IEEE80211_FCTL_FROMDS are set + * @fc: frame control bytes in little-endian byteorder + */ +static inline int ieee80211_has_a4(__le16 fc) +{ + __le16 tmp = cpu_to_le16(IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS); + return (fc & tmp) == tmp; +} + +/** + * ieee80211_has_morefrags - check if IEEE80211_FCTL_MOREFRAGS is set + * @fc: frame control bytes in little-endian byteorder + */ +static inline int ieee80211_has_morefrags(__le16 fc) +{ + return (fc & cpu_to_le16(IEEE80211_FCTL_MOREFRAGS)) != 0; +} + +/** + * ieee80211_has_retry - check if IEEE80211_FCTL_RETRY is set + * @fc: frame control bytes in little-endian byteorder + */ +static inline int ieee80211_has_retry(__le16 fc) +{ + return (fc & cpu_to_le16(IEEE80211_FCTL_RETRY)) != 0; +} + +/** + * ieee80211_has_pm - check if IEEE80211_FCTL_PM is set + * @fc: frame control bytes in little-endian byteorder + */ +static inline int ieee80211_has_pm(__le16 fc) +{ + return (fc & cpu_to_le16(IEEE80211_FCTL_PM)) != 0; +} + +/** + * ieee80211_has_moredata - check if IEEE80211_FCTL_MOREDATA is set + * @fc: frame control bytes in little-endian byteorder + */ +static inline int ieee80211_has_moredata(__le16 fc) +{ + return (fc & cpu_to_le16(IEEE80211_FCTL_MOREDATA)) != 0; +} + +/** + * ieee80211_has_protected - check if IEEE80211_FCTL_PROTECTED is set + * @fc: frame control bytes in little-endian byteorder + */ +static inline int ieee80211_has_protected(__le16 fc) +{ + return (fc & cpu_to_le16(IEEE80211_FCTL_PROTECTED)) != 0; +} + +/** + * ieee80211_has_order - check if IEEE80211_FCTL_ORDER is set + * @fc: frame control bytes in little-endian byteorder + */ +static inline int ieee80211_has_order(__le16 fc) +{ + return (fc & cpu_to_le16(IEEE80211_FCTL_ORDER)) != 0; +} + +/** + * ieee80211_is_mgmt - check if type is IEEE80211_FTYPE_MGMT + * @fc: frame control bytes in little-endian byteorder + */ +static inline int ieee80211_is_mgmt(__le16 fc) +{ + return (fc & cpu_to_le16(IEEE80211_FCTL_FTYPE)) == + cpu_to_le16(IEEE80211_FTYPE_MGMT); +} + +/** + * ieee80211_is_ctl - check if type is IEEE80211_FTYPE_CTL + * @fc: frame control bytes in little-endian byteorder + */ +static inline int ieee80211_is_ctl(__le16 fc) +{ + return (fc & cpu_to_le16(IEEE80211_FCTL_FTYPE)) == + cpu_to_le16(IEEE80211_FTYPE_CTL); +} + +/** + * ieee80211_is_data - check if type is IEEE80211_FTYPE_DATA + * @fc: frame control bytes in little-endian byteorder + */ +static inline int ieee80211_is_data(__le16 fc) +{ + return (fc & cpu_to_le16(IEEE80211_FCTL_FTYPE)) == + cpu_to_le16(IEEE80211_FTYPE_DATA); +} + +/** + * ieee80211_is_data_qos - check if type is IEEE80211_FTYPE_DATA and IEEE80211_STYPE_QOS_DATA is set + * @fc: frame control bytes in little-endian byteorder + */ +static inline int ieee80211_is_data_qos(__le16 fc) +{ + /* + * mask with QOS_DATA rather than IEEE80211_FCTL_STYPE as we just need + * to check the one bit + */ + return (fc & cpu_to_le16(IEEE80211_FCTL_FTYPE | IEEE80211_STYPE_QOS_DATA)) == + cpu_to_le16(IEEE80211_FTYPE_DATA | IEEE80211_STYPE_QOS_DATA); +} + +/** + * ieee80211_is_data_present - check if type is IEEE80211_FTYPE_DATA and has data + * @fc: frame control bytes in little-endian byteorder + */ +static inline int ieee80211_is_data_present(__le16 fc) +{ + /* + * mask with 0x40 and test that that bit is clear to only return true + * for the data-containing substypes. + */ + return (fc & cpu_to_le16(IEEE80211_FCTL_FTYPE | 0x40)) == + cpu_to_le16(IEEE80211_FTYPE_DATA); +} + +/** + * ieee80211_is_assoc_req - check if IEEE80211_FTYPE_MGMT && IEEE80211_STYPE_ASSOC_REQ + * @fc: frame control bytes in little-endian byteorder + */ +static inline int ieee80211_is_assoc_req(__le16 fc) +{ + return (fc & cpu_to_le16(IEEE80211_FCTL_FTYPE | IEEE80211_FCTL_STYPE)) == + cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_ASSOC_REQ); +} + +/** + * ieee80211_is_assoc_resp - check if IEEE80211_FTYPE_MGMT && IEEE80211_STYPE_ASSOC_RESP + * @fc: frame control bytes in little-endian byteorder + */ +static inline int ieee80211_is_assoc_resp(__le16 fc) +{ + return (fc & cpu_to_le16(IEEE80211_FCTL_FTYPE | IEEE80211_FCTL_STYPE)) == + cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_ASSOC_RESP); +} + +/** + * ieee80211_is_reassoc_req - check if IEEE80211_FTYPE_MGMT && IEEE80211_STYPE_REASSOC_REQ + * @fc: frame control bytes in little-endian byteorder + */ +static inline int ieee80211_is_reassoc_req(__le16 fc) +{ + return (fc & cpu_to_le16(IEEE80211_FCTL_FTYPE | IEEE80211_FCTL_STYPE)) == + cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_REASSOC_REQ); +} + +/** + * ieee80211_is_reassoc_resp - check if IEEE80211_FTYPE_MGMT && IEEE80211_STYPE_REASSOC_RESP + * @fc: frame control bytes in little-endian byteorder + */ +static inline int ieee80211_is_reassoc_resp(__le16 fc) +{ + return (fc & cpu_to_le16(IEEE80211_FCTL_FTYPE | IEEE80211_FCTL_STYPE)) == + cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_REASSOC_RESP); +} + +/** + * ieee80211_is_probe_req - check if IEEE80211_FTYPE_MGMT && IEEE80211_STYPE_PROBE_REQ + * @fc: frame control bytes in little-endian byteorder + */ +static inline int ieee80211_is_probe_req(__le16 fc) +{ + return (fc & cpu_to_le16(IEEE80211_FCTL_FTYPE | IEEE80211_FCTL_STYPE)) == + cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_PROBE_REQ); +} + +/** + * ieee80211_is_probe_resp - check if IEEE80211_FTYPE_MGMT && IEEE80211_STYPE_PROBE_RESP + * @fc: frame control bytes in little-endian byteorder + */ +static inline int ieee80211_is_probe_resp(__le16 fc) +{ + return (fc & cpu_to_le16(IEEE80211_FCTL_FTYPE | IEEE80211_FCTL_STYPE)) == + cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_PROBE_RESP); +} + +/** + * ieee80211_is_beacon - check if IEEE80211_FTYPE_MGMT && IEEE80211_STYPE_BEACON + * @fc: frame control bytes in little-endian byteorder + */ +static inline int ieee80211_is_beacon(__le16 fc) +{ + return (fc & cpu_to_le16(IEEE80211_FCTL_FTYPE | IEEE80211_FCTL_STYPE)) == + cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_BEACON); +} + +/** + * ieee80211_is_atim - check if IEEE80211_FTYPE_MGMT && IEEE80211_STYPE_ATIM + * @fc: frame control bytes in little-endian byteorder + */ +static inline int ieee80211_is_atim(__le16 fc) +{ + return (fc & cpu_to_le16(IEEE80211_FCTL_FTYPE | IEEE80211_FCTL_STYPE)) == + cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_ATIM); +} + +/** + * ieee80211_is_disassoc - check if IEEE80211_FTYPE_MGMT && IEEE80211_STYPE_DISASSOC + * @fc: frame control bytes in little-endian byteorder + */ +static inline int ieee80211_is_disassoc(__le16 fc) +{ + return (fc & cpu_to_le16(IEEE80211_FCTL_FTYPE | IEEE80211_FCTL_STYPE)) == + cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_DISASSOC); +} + +/** + * ieee80211_is_auth - check if IEEE80211_FTYPE_MGMT && IEEE80211_STYPE_AUTH + * @fc: frame control bytes in little-endian byteorder + */ +static inline int ieee80211_is_auth(__le16 fc) +{ + return (fc & cpu_to_le16(IEEE80211_FCTL_FTYPE | IEEE80211_FCTL_STYPE)) == + cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_AUTH); +} + +/** + * ieee80211_is_deauth - check if IEEE80211_FTYPE_MGMT && IEEE80211_STYPE_DEAUTH + * @fc: frame control bytes in little-endian byteorder + */ +static inline int ieee80211_is_deauth(__le16 fc) +{ + return (fc & cpu_to_le16(IEEE80211_FCTL_FTYPE | IEEE80211_FCTL_STYPE)) == + cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_DEAUTH); +} + +/** + * ieee80211_is_action - check if IEEE80211_FTYPE_MGMT && IEEE80211_STYPE_ACTION + * @fc: frame control bytes in little-endian byteorder + */ +static inline int ieee80211_is_action(__le16 fc) +{ + return (fc & cpu_to_le16(IEEE80211_FCTL_FTYPE | IEEE80211_FCTL_STYPE)) == + cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_ACTION); +} + +/** + * ieee80211_is_back_req - check if IEEE80211_FTYPE_CTL && IEEE80211_STYPE_BACK_REQ + * @fc: frame control bytes in little-endian byteorder + */ +static inline int ieee80211_is_back_req(__le16 fc) +{ + return (fc & cpu_to_le16(IEEE80211_FCTL_FTYPE | IEEE80211_FCTL_STYPE)) == + cpu_to_le16(IEEE80211_FTYPE_CTL | IEEE80211_STYPE_BACK_REQ); +} + +/** + * ieee80211_is_back - check if IEEE80211_FTYPE_CTL && IEEE80211_STYPE_BACK + * @fc: frame control bytes in little-endian byteorder + */ +static inline int ieee80211_is_back(__le16 fc) +{ + return (fc & cpu_to_le16(IEEE80211_FCTL_FTYPE | IEEE80211_FCTL_STYPE)) == + cpu_to_le16(IEEE80211_FTYPE_CTL | IEEE80211_STYPE_BACK); +} + +/** + * ieee80211_is_pspoll - check if IEEE80211_FTYPE_CTL && IEEE80211_STYPE_PSPOLL + * @fc: frame control bytes in little-endian byteorder + */ +static inline int ieee80211_is_pspoll(__le16 fc) +{ + return (fc & cpu_to_le16(IEEE80211_FCTL_FTYPE | IEEE80211_FCTL_STYPE)) == + cpu_to_le16(IEEE80211_FTYPE_CTL | IEEE80211_STYPE_PSPOLL); +} + +/** + * ieee80211_is_rts - check if IEEE80211_FTYPE_CTL && IEEE80211_STYPE_RTS + * @fc: frame control bytes in little-endian byteorder + */ +static inline int ieee80211_is_rts(__le16 fc) +{ + return (fc & cpu_to_le16(IEEE80211_FCTL_FTYPE | IEEE80211_FCTL_STYPE)) == + cpu_to_le16(IEEE80211_FTYPE_CTL | IEEE80211_STYPE_RTS); +} + +/** + * ieee80211_is_cts - check if IEEE80211_FTYPE_CTL && IEEE80211_STYPE_CTS + * @fc: frame control bytes in little-endian byteorder + */ +static inline int ieee80211_is_cts(__le16 fc) +{ + return (fc & cpu_to_le16(IEEE80211_FCTL_FTYPE | IEEE80211_FCTL_STYPE)) == + cpu_to_le16(IEEE80211_FTYPE_CTL | IEEE80211_STYPE_CTS); +} + +/** + * ieee80211_is_ack - check if IEEE80211_FTYPE_CTL && IEEE80211_STYPE_ACK + * @fc: frame control bytes in little-endian byteorder + */ +static inline int ieee80211_is_ack(__le16 fc) +{ + return (fc & cpu_to_le16(IEEE80211_FCTL_FTYPE | IEEE80211_FCTL_STYPE)) == + cpu_to_le16(IEEE80211_FTYPE_CTL | IEEE80211_STYPE_ACK); +} + +/** + * ieee80211_is_cfend - check if IEEE80211_FTYPE_CTL && IEEE80211_STYPE_CFEND + * @fc: frame control bytes in little-endian byteorder + */ +static inline int ieee80211_is_cfend(__le16 fc) +{ + return (fc & cpu_to_le16(IEEE80211_FCTL_FTYPE | IEEE80211_FCTL_STYPE)) == + cpu_to_le16(IEEE80211_FTYPE_CTL | IEEE80211_STYPE_CFEND); +} + +/** + * ieee80211_is_cfendack - check if IEEE80211_FTYPE_CTL && IEEE80211_STYPE_CFENDACK + * @fc: frame control bytes in little-endian byteorder + */ +static inline int ieee80211_is_cfendack(__le16 fc) +{ + return (fc & cpu_to_le16(IEEE80211_FCTL_FTYPE | IEEE80211_FCTL_STYPE)) == + cpu_to_le16(IEEE80211_FTYPE_CTL | IEEE80211_STYPE_CFENDACK); +} + +/** + * ieee80211_is_nullfunc - check if FTYPE=IEEE80211_FTYPE_DATA and STYPE=IEEE80211_STYPE_NULLFUNC + * @fc: frame control bytes in little-endian byteorder + */ +static inline int ieee80211_is_nullfunc(__le16 fc) +{ + return (fc & cpu_to_le16(IEEE80211_FCTL_FTYPE | IEEE80211_FCTL_STYPE)) == + cpu_to_le16(IEEE80211_FTYPE_DATA | IEEE80211_STYPE_NULLFUNC); +} struct ieee80211s_hdr { u8 flags; @@ -119,6 +471,40 @@ struct ieee80211s_hdr { u8 eaddr3[6]; } __attribute__ ((packed)); +/** + * struct ieee80211_quiet_ie + * + * This structure refers to "Quiet information element" + */ +struct ieee80211_quiet_ie { + u8 count; + u8 period; + __le16 duration; + __le16 offset; +} __attribute__ ((packed)); + +/** + * struct ieee80211_msrment_ie + * + * This structure refers to "Measurement Request/Report information element" + */ +struct ieee80211_msrment_ie { + u8 token; + u8 mode; + u8 type; + u8 request[0]; +} __attribute__ ((packed)); + +/** + * struct ieee80211_channel_sw_ie + * + * This structure refers to "Channel Switch Announcement information element" + */ +struct ieee80211_channel_sw_ie { + u8 mode; + u8 new_ch_num; + u8 count; +} __attribute__ ((packed)); struct ieee80211_mgmt { __le16 frame_control; @@ -194,13 +580,18 @@ struct ieee80211_mgmt { u8 action_code; u8 element_id; u8 length; - u8 switch_mode; - u8 new_chan; - u8 switch_count; + struct ieee80211_channel_sw_ie sw_elem; } __attribute__((packed)) chan_switch; struct{ u8 action_code; u8 dialog_token; + u8 element_id; + u8 length; + struct ieee80211_msrment_ie msr_elem; + } __attribute__((packed)) measurement; + struct{ + u8 action_code; + u8 dialog_token; __le16 capab; __le16 timeout; __le16 start_seq_num; @@ -269,6 +660,10 @@ struct ieee80211_bar { __le16 start_seq_num; } __attribute__((packed)); +/* 802.11 BAR control masks */ +#define IEEE80211_BAR_CTRL_ACK_POLICY_NORMAL 0x0000 +#define IEEE80211_BAR_CTRL_CBMTID_COMPRESSED_BA 0x0004 + /** * struct ieee80211_ht_cap - HT capabilities * @@ -306,20 +701,33 @@ struct ieee80211_ht_addt_info { #define IEEE80211_HT_CAP_SGI_40 0x0040 #define IEEE80211_HT_CAP_DELAY_BA 0x0400 #define IEEE80211_HT_CAP_MAX_AMSDU 0x0800 +/* 802.11n HT capability AMPDU settings */ #define IEEE80211_HT_CAP_AMPDU_FACTOR 0x03 #define IEEE80211_HT_CAP_AMPDU_DENSITY 0x1C +/* 802.11n HT capability MSC set */ +#define IEEE80211_SUPP_MCS_SET_UEQM 4 +#define IEEE80211_HT_CAP_MAX_STREAMS 4 +#define IEEE80211_SUPP_MCS_SET_LEN 10 +/* maximum streams the spec allows */ +#define IEEE80211_HT_CAP_MCS_TX_DEFINED 0x01 +#define IEEE80211_HT_CAP_MCS_TX_RX_DIFF 0x02 +#define IEEE80211_HT_CAP_MCS_TX_STREAMS 0x0C +#define IEEE80211_HT_CAP_MCS_TX_UEQM 0x10 /* 802.11n HT IE masks */ #define IEEE80211_HT_IE_CHA_SEC_OFFSET 0x03 +#define IEEE80211_HT_IE_CHA_SEC_NONE 0x00 +#define IEEE80211_HT_IE_CHA_SEC_ABOVE 0x01 +#define IEEE80211_HT_IE_CHA_SEC_BELOW 0x03 #define IEEE80211_HT_IE_CHA_WIDTH 0x04 #define IEEE80211_HT_IE_HT_PROTECTION 0x0003 #define IEEE80211_HT_IE_NON_GF_STA_PRSNT 0x0004 #define IEEE80211_HT_IE_NON_HT_STA_PRSNT 0x0010 /* MIMO Power Save Modes */ -#define WLAN_HT_CAP_MIMO_PS_STATIC 0 -#define WLAN_HT_CAP_MIMO_PS_DYNAMIC 1 -#define WLAN_HT_CAP_MIMO_PS_INVALID 2 -#define WLAN_HT_CAP_MIMO_PS_DISABLED 3 +#define WLAN_HT_CAP_MIMO_PS_STATIC 0 +#define WLAN_HT_CAP_MIMO_PS_DYNAMIC 1 +#define WLAN_HT_CAP_MIMO_PS_INVALID 2 +#define WLAN_HT_CAP_MIMO_PS_DISABLED 3 /* Authentication algorithms */ #define WLAN_AUTH_OPEN 0 @@ -337,11 +745,21 @@ struct ieee80211_ht_addt_info { #define WLAN_CAPABILITY_SHORT_PREAMBLE (1<<5) #define WLAN_CAPABILITY_PBCC (1<<6) #define WLAN_CAPABILITY_CHANNEL_AGILITY (1<<7) + /* 802.11h */ #define WLAN_CAPABILITY_SPECTRUM_MGMT (1<<8) #define WLAN_CAPABILITY_QOS (1<<9) #define WLAN_CAPABILITY_SHORT_SLOT_TIME (1<<10) #define WLAN_CAPABILITY_DSSS_OFDM (1<<13) +/* measurement */ +#define IEEE80211_SPCT_MSR_RPRT_MODE_LATE (1<<0) +#define IEEE80211_SPCT_MSR_RPRT_MODE_INCAPABLE (1<<1) +#define IEEE80211_SPCT_MSR_RPRT_MODE_REFUSED (1<<2) + +#define IEEE80211_SPCT_MSR_RPRT_TYPE_BASIC 0 +#define IEEE80211_SPCT_MSR_RPRT_TYPE_CCA 1 +#define IEEE80211_SPCT_MSR_RPRT_TYPE_RPI 2 + /* 802.11g ERP information element */ #define WLAN_ERP_NON_ERP_PRESENT (1<<0) @@ -512,6 +930,15 @@ enum ieee80211_category { WLAN_CATEGORY_WMM = 17, }; +/* SPECTRUM_MGMT action code */ +enum ieee80211_spectrum_mgmt_actioncode { + WLAN_ACTION_SPCT_MSR_REQ = 0, + WLAN_ACTION_SPCT_MSR_RPRT = 1, + WLAN_ACTION_SPCT_TPC_REQ = 2, + WLAN_ACTION_SPCT_TPC_RPRT = 3, + WLAN_ACTION_SPCT_CHL_SWITCH = 4, +}; + /* BACK action code */ enum ieee80211_back_actioncode { WLAN_ACTION_ADDBA_REQ = 0, @@ -540,63 +967,57 @@ enum ieee80211_back_parties { #define WLAN_MAX_KEY_LEN 32 /** + * ieee80211_get_qos_ctl - get pointer to qos control bytes + * @hdr: the frame + * + * The qos ctrl bytes come after the frame_control, duration, seq_num + * and 3 or 4 addresses of length ETH_ALEN. + * 3 addr: 2 + 2 + 2 + 3*6 = 24 + * 4 addr: 2 + 2 + 2 + 4*6 = 30 + */ +static inline u8 *ieee80211_get_qos_ctl(struct ieee80211_hdr *hdr) +{ + if (ieee80211_has_a4(hdr->frame_control)) + return (u8 *)hdr + 30; + else + return (u8 *)hdr + 24; +} + +/** * ieee80211_get_SA - get pointer to SA + * @hdr: the frame * * Given an 802.11 frame, this function returns the offset * to the source address (SA). It does not verify that the * header is long enough to contain the address, and the * header must be long enough to contain the frame control * field. - * - * @hdr: the frame */ static inline u8 *ieee80211_get_SA(struct ieee80211_hdr *hdr) { - u8 *raw = (u8 *) hdr; - u8 tofrom = (*(raw+1)) & 3; /* get the TODS and FROMDS bits */ - - switch (tofrom) { - case 2: - return hdr->addr3; - case 3: - return hdr->addr4; - } + if (ieee80211_has_a4(hdr->frame_control)) + return hdr->addr4; + if (ieee80211_has_fromds(hdr->frame_control)) + return hdr->addr3; return hdr->addr2; } /** * ieee80211_get_DA - get pointer to DA + * @hdr: the frame * * Given an 802.11 frame, this function returns the offset * to the destination address (DA). It does not verify that * the header is long enough to contain the address, and the * header must be long enough to contain the frame control * field. - * - * @hdr: the frame */ static inline u8 *ieee80211_get_DA(struct ieee80211_hdr *hdr) { - u8 *raw = (u8 *) hdr; - u8 to_ds = (*(raw+1)) & 1; /* get the TODS bit */ - - if (to_ds) + if (ieee80211_has_tods(hdr->frame_control)) return hdr->addr3; - return hdr->addr1; -} - -/** - * ieee80211_get_morefrag - determine whether the MOREFRAGS bit is set - * - * This function determines whether the "more fragments" bit is set - * in the frame. - * - * @hdr: the frame - */ -static inline int ieee80211_get_morefrag(struct ieee80211_hdr *hdr) -{ - return (le16_to_cpu(hdr->frame_control) & - IEEE80211_FCTL_MOREFRAGS) != 0; + else + return hdr->addr1; } #endif /* IEEE80211_H */ diff --git a/include/linux/if_bridge.h b/include/linux/if_bridge.h index 950e13d09e06..6badb3e2c4e4 100644 --- a/include/linux/if_bridge.h +++ b/include/linux/if_bridge.h @@ -4,8 +4,6 @@ * Authors: * Lennert Buytenhek <buytenh@gnu.org> * - * $Id: if_bridge.h,v 1.1 2000/02/18 16:47:01 davem Exp $ - * * 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 diff --git a/include/linux/if_packet.h b/include/linux/if_packet.h index ad09609227ff..18db0668065a 100644 --- a/include/linux/if_packet.h +++ b/include/linux/if_packet.h @@ -43,6 +43,9 @@ struct sockaddr_ll #define PACKET_COPY_THRESH 7 #define PACKET_AUXDATA 8 #define PACKET_ORIGDEV 9 +#define PACKET_VERSION 10 +#define PACKET_HDRLEN 11 +#define PACKET_RESERVE 12 struct tpacket_stats { @@ -57,6 +60,7 @@ struct tpacket_auxdata __u32 tp_snaplen; __u16 tp_mac; __u16 tp_net; + __u16 tp_vlan_tci; }; struct tpacket_hdr @@ -79,6 +83,26 @@ struct tpacket_hdr #define TPACKET_ALIGN(x) (((x)+TPACKET_ALIGNMENT-1)&~(TPACKET_ALIGNMENT-1)) #define TPACKET_HDRLEN (TPACKET_ALIGN(sizeof(struct tpacket_hdr)) + sizeof(struct sockaddr_ll)) +struct tpacket2_hdr +{ + __u32 tp_status; + __u32 tp_len; + __u32 tp_snaplen; + __u16 tp_mac; + __u16 tp_net; + __u32 tp_sec; + __u32 tp_nsec; + __u16 tp_vlan_tci; +}; + +#define TPACKET2_HDRLEN (TPACKET_ALIGN(sizeof(struct tpacket2_hdr)) + sizeof(struct sockaddr_ll)) + +enum tpacket_versions +{ + TPACKET_V1, + TPACKET_V2, +}; + /* Frame structure: diff --git a/include/linux/if_ppp.h b/include/linux/if_ppp.h index 0f2f70d4e48c..c3b1f8562709 100644 --- a/include/linux/if_ppp.h +++ b/include/linux/if_ppp.h @@ -1,5 +1,3 @@ -/* $Id: if_ppp.h,v 1.21 2000/03/27 06:03:36 paulus Exp $ */ - /* * if_ppp.h - Point-to-Point Protocol definitions. * diff --git a/include/linux/if_tun.h b/include/linux/if_tun.h index 8c71fe2fb1f5..4c6307ad9fdb 100644 --- a/include/linux/if_tun.h +++ b/include/linux/if_tun.h @@ -11,14 +11,13 @@ * 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. - * - * $Id: if_tun.h,v 1.2 2001/06/01 18:39:47 davem Exp $ */ #ifndef __IF_TUN_H #define __IF_TUN_H #include <linux/types.h> +#include <linux/if_ether.h> /* Read queue size */ #define TUN_READQ_SIZE 500 @@ -33,6 +32,7 @@ #define TUN_NO_PI 0x0040 #define TUN_ONE_QUEUE 0x0080 #define TUN_PERSIST 0x0100 +#define TUN_VNET_HDR 0x0200 /* Ioctl defines */ #define TUNSETNOCSUM _IOW('T', 200, int) @@ -42,17 +42,43 @@ #define TUNSETOWNER _IOW('T', 204, int) #define TUNSETLINK _IOW('T', 205, int) #define TUNSETGROUP _IOW('T', 206, int) +#define TUNGETFEATURES _IOR('T', 207, unsigned int) +#define TUNSETOFFLOAD _IOW('T', 208, unsigned int) +#define TUNSETTXFILTER _IOW('T', 209, unsigned int) /* TUNSETIFF ifr flags */ #define IFF_TUN 0x0001 #define IFF_TAP 0x0002 #define IFF_NO_PI 0x1000 #define IFF_ONE_QUEUE 0x2000 +#define IFF_VNET_HDR 0x4000 + +/* Features for GSO (TUNSETOFFLOAD). */ +#define TUN_F_CSUM 0x01 /* You can hand me unchecksummed packets. */ +#define TUN_F_TSO4 0x02 /* I can handle TSO for IPv4 packets */ +#define TUN_F_TSO6 0x04 /* I can handle TSO for IPv6 packets */ +#define TUN_F_TSO_ECN 0x08 /* I can handle TSO with ECN bits. */ +/* Protocol info prepended to the packets (when IFF_NO_PI is not set) */ +#define TUN_PKT_STRIP 0x0001 struct tun_pi { - unsigned short flags; + __u16 flags; __be16 proto; }; -#define TUN_PKT_STRIP 0x0001 + +/* + * Filter spec (used for SETXXFILTER ioctls) + * This stuff is applicable only to the TAP (Ethernet) devices. + * If the count is zero the filter is disabled and the driver accepts + * all packets (promisc mode). + * If the filter is enabled in order to accept broadcast packets + * broadcast addr must be explicitly included in the addr list. + */ +#define TUN_FLT_ALLMULTI 0x0001 /* Accept all multicast packets */ +struct tun_filter { + __u16 flags; /* TUN_FLT_ flags see above */ + __u16 count; /* Number of addresses */ + __u8 addr[0][ETH_ALEN]; +}; #endif /* __IF_TUN_H */ diff --git a/include/linux/if_vlan.h b/include/linux/if_vlan.h index 15ace02b7b24..9e7b49b8062d 100644 --- a/include/linux/if_vlan.h +++ b/include/linux/if_vlan.h @@ -14,10 +14,6 @@ #define _LINUX_IF_VLAN_H_ #ifdef __KERNEL__ - -/* externally defined structs */ -struct hlist_node; - #include <linux/netdevice.h> #include <linux/etherdevice.h> @@ -91,7 +87,7 @@ struct vlan_group { }; static inline struct net_device *vlan_group_get_device(struct vlan_group *vg, - unsigned int vlan_id) + u16 vlan_id) { struct net_device **array; array = vg->vlan_devices_arrays[vlan_id / VLAN_GROUP_ARRAY_PART_LEN]; @@ -99,7 +95,7 @@ static inline struct net_device *vlan_group_get_device(struct vlan_group *vg, } static inline void vlan_group_set_device(struct vlan_group *vg, - unsigned int vlan_id, + u16 vlan_id, struct net_device *dev) { struct net_device **array; @@ -109,164 +105,81 @@ static inline void vlan_group_set_device(struct vlan_group *vg, array[vlan_id % VLAN_GROUP_ARRAY_PART_LEN] = dev; } -struct vlan_priority_tci_mapping { - u32 priority; - unsigned short vlan_qos; /* This should be shifted when first set, so we only do it - * at provisioning time. - * ((skb->priority << 13) & 0xE000) - */ - struct vlan_priority_tci_mapping *next; -}; +#define vlan_tx_tag_present(__skb) ((__skb)->vlan_tci) +#define vlan_tx_tag_get(__skb) ((__skb)->vlan_tci) -/* Holds information that makes sense if this device is a VLAN device. */ -struct vlan_dev_info { - /** This will be the mapping that correlates skb->priority to - * 3 bits of VLAN QOS tags... - */ - unsigned int nr_ingress_mappings; - u32 ingress_priority_map[8]; - - unsigned int nr_egress_mappings; - struct vlan_priority_tci_mapping *egress_priority_map[16]; /* hash table */ - - unsigned short vlan_id; /* The VLAN Identifier for this interface. */ - unsigned short flags; /* (1 << 0) re_order_header This option will cause the - * VLAN code to move around the ethernet header on - * ingress to make the skb look **exactly** like it - * came in from an ethernet port. This destroys some of - * the VLAN information in the skb, but it fixes programs - * like DHCP that use packet-filtering and don't understand - * 802.1Q - */ - struct net_device *real_dev; /* the underlying device/interface */ - unsigned char real_dev_addr[ETH_ALEN]; - struct proc_dir_entry *dent; /* Holds the proc data */ - unsigned long cnt_inc_headroom_on_tx; /* How many times did we have to grow the skb on TX. */ - unsigned long cnt_encap_on_xmit; /* How many times did we have to encapsulate the skb on TX. */ -}; +#if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE) +extern struct net_device *vlan_dev_real_dev(const struct net_device *dev); +extern u16 vlan_dev_vlan_id(const struct net_device *dev); -static inline struct vlan_dev_info *vlan_dev_info(const struct net_device *dev) +extern int __vlan_hwaccel_rx(struct sk_buff *skb, struct vlan_group *grp, + u16 vlan_tci, int polling); +#else +static inline struct net_device *vlan_dev_real_dev(const struct net_device *dev) { - return netdev_priv(dev); + BUG(); + return NULL; } -/* inline functions */ -static inline __u32 vlan_get_ingress_priority(struct net_device *dev, - unsigned short vlan_tag) +static inline u16 vlan_dev_vlan_id(const struct net_device *dev) { - struct vlan_dev_info *vip = vlan_dev_info(dev); - - return vip->ingress_priority_map[(vlan_tag >> 13) & 0x7]; + BUG(); + return 0; } -/* VLAN tx hw acceleration helpers. */ -struct vlan_skb_tx_cookie { - u32 magic; - u32 vlan_tag; -}; - -#define VLAN_TX_COOKIE_MAGIC 0x564c414e /* "VLAN" in ascii. */ -#define VLAN_TX_SKB_CB(__skb) ((struct vlan_skb_tx_cookie *)&((__skb)->cb[0])) -#define vlan_tx_tag_present(__skb) \ - (VLAN_TX_SKB_CB(__skb)->magic == VLAN_TX_COOKIE_MAGIC) -#define vlan_tx_tag_get(__skb) (VLAN_TX_SKB_CB(__skb)->vlan_tag) - -/* VLAN rx hw acceleration helper. This acts like netif_{rx,receive_skb}(). */ -static inline int __vlan_hwaccel_rx(struct sk_buff *skb, - struct vlan_group *grp, - unsigned short vlan_tag, int polling) +static inline int __vlan_hwaccel_rx(struct sk_buff *skb, struct vlan_group *grp, + u16 vlan_tci, int polling) { - struct net_device_stats *stats; - - if (skb_bond_should_drop(skb)) { - dev_kfree_skb_any(skb); - return NET_RX_DROP; - } - - skb->dev = vlan_group_get_device(grp, vlan_tag & VLAN_VID_MASK); - if (skb->dev == NULL) { - dev_kfree_skb_any(skb); - - /* Not NET_RX_DROP, this is not being dropped - * due to congestion. - */ - return 0; - } - - skb->dev->last_rx = jiffies; - - stats = &skb->dev->stats; - stats->rx_packets++; - stats->rx_bytes += skb->len; - - skb->priority = vlan_get_ingress_priority(skb->dev, vlan_tag); - switch (skb->pkt_type) { - case PACKET_BROADCAST: - break; - - case PACKET_MULTICAST: - stats->multicast++; - break; - - case PACKET_OTHERHOST: - /* Our lower layer thinks this is not local, let's make sure. - * This allows the VLAN to have a different MAC than the underlying - * device, and still route correctly. - */ - if (!compare_ether_addr(eth_hdr(skb)->h_dest, - skb->dev->dev_addr)) - skb->pkt_type = PACKET_HOST; - break; - }; - - return (polling ? netif_receive_skb(skb) : netif_rx(skb)); + BUG(); + return NET_XMIT_SUCCESS; } +#endif +/** + * vlan_hwaccel_rx - netif_rx wrapper for VLAN RX acceleration + * @skb: buffer + * @grp: vlan group + * @vlan_tci: VLAN TCI as received from the card + */ static inline int vlan_hwaccel_rx(struct sk_buff *skb, struct vlan_group *grp, - unsigned short vlan_tag) + u16 vlan_tci) { - return __vlan_hwaccel_rx(skb, grp, vlan_tag, 0); + return __vlan_hwaccel_rx(skb, grp, vlan_tci, 0); } +/** + * vlan_hwaccel_receive_skb - netif_receive_skb wrapper for VLAN RX acceleration + * @skb: buffer + * @grp: vlan group + * @vlan_tci: VLAN TCI as received from the card + */ static inline int vlan_hwaccel_receive_skb(struct sk_buff *skb, struct vlan_group *grp, - unsigned short vlan_tag) + u16 vlan_tci) { - return __vlan_hwaccel_rx(skb, grp, vlan_tag, 1); + return __vlan_hwaccel_rx(skb, grp, vlan_tci, 1); } /** * __vlan_put_tag - regular VLAN tag inserting * @skb: skbuff to tag - * @tag: VLAN tag to insert + * @vlan_tci: VLAN TCI to insert * * Inserts the VLAN tag into @skb as part of the payload * Returns a VLAN tagged skb. If a new skb is created, @skb is freed. - * + * * Following the skb_unshare() example, in case of error, the calling function * doesn't have to worry about freeing the original skb. */ -static inline struct sk_buff *__vlan_put_tag(struct sk_buff *skb, unsigned short tag) +static inline struct sk_buff *__vlan_put_tag(struct sk_buff *skb, u16 vlan_tci) { struct vlan_ethhdr *veth; - if (skb_headroom(skb) < VLAN_HLEN) { - struct sk_buff *sk_tmp = skb; - skb = skb_realloc_headroom(sk_tmp, VLAN_HLEN); - kfree_skb(sk_tmp); - if (!skb) { - printk(KERN_ERR "vlan: failed to realloc headroom\n"); - return NULL; - } - } else { - skb = skb_unshare(skb, GFP_ATOMIC); - if (!skb) { - printk(KERN_ERR "vlan: failed to unshare skbuff\n"); - return NULL; - } + if (skb_cow_head(skb, VLAN_HLEN) < 0) { + kfree_skb(skb); + return NULL; } - veth = (struct vlan_ethhdr *)skb_push(skb, VLAN_HLEN); /* Move the mac addresses to the beginning of the new header. */ @@ -275,12 +188,10 @@ static inline struct sk_buff *__vlan_put_tag(struct sk_buff *skb, unsigned short /* first, the ethernet type */ veth->h_vlan_proto = htons(ETH_P_8021Q); - /* now, the tag */ - veth->h_vlan_TCI = htons(tag); + /* now, the TCI */ + veth->h_vlan_TCI = htons(vlan_tci); skb->protocol = htons(ETH_P_8021Q); - skb->mac_header -= VLAN_HLEN; - skb->network_header -= VLAN_HLEN; return skb; } @@ -288,18 +199,14 @@ static inline struct sk_buff *__vlan_put_tag(struct sk_buff *skb, unsigned short /** * __vlan_hwaccel_put_tag - hardware accelerated VLAN inserting * @skb: skbuff to tag - * @tag: VLAN tag to insert + * @vlan_tci: VLAN TCI to insert * - * Puts the VLAN tag in @skb->cb[] and lets the device do the rest + * Puts the VLAN TCI in @skb->vlan_tci and lets the device do the rest */ -static inline struct sk_buff *__vlan_hwaccel_put_tag(struct sk_buff *skb, unsigned short tag) +static inline struct sk_buff *__vlan_hwaccel_put_tag(struct sk_buff *skb, + u16 vlan_tci) { - struct vlan_skb_tx_cookie *cookie; - - cookie = VLAN_TX_SKB_CB(skb); - cookie->magic = VLAN_TX_COOKIE_MAGIC; - cookie->vlan_tag = tag; - + skb->vlan_tci = vlan_tci; return skb; } @@ -308,28 +215,28 @@ static inline struct sk_buff *__vlan_hwaccel_put_tag(struct sk_buff *skb, unsign /** * vlan_put_tag - inserts VLAN tag according to device features * @skb: skbuff to tag - * @tag: VLAN tag to insert + * @vlan_tci: VLAN TCI to insert * * Assumes skb->dev is the target that will xmit this frame. * Returns a VLAN tagged skb. */ -static inline struct sk_buff *vlan_put_tag(struct sk_buff *skb, unsigned short tag) +static inline struct sk_buff *vlan_put_tag(struct sk_buff *skb, u16 vlan_tci) { if (skb->dev->features & NETIF_F_HW_VLAN_TX) { - return __vlan_hwaccel_put_tag(skb, tag); + return __vlan_hwaccel_put_tag(skb, vlan_tci); } else { - return __vlan_put_tag(skb, tag); + return __vlan_put_tag(skb, vlan_tci); } } /** * __vlan_get_tag - get the VLAN ID that is part of the payload * @skb: skbuff to query - * @tag: buffer to store vlaue - * + * @vlan_tci: buffer to store vlaue + * * Returns error if the skb is not of VLAN type */ -static inline int __vlan_get_tag(const struct sk_buff *skb, unsigned short *tag) +static inline int __vlan_get_tag(const struct sk_buff *skb, u16 *vlan_tci) { struct vlan_ethhdr *veth = (struct vlan_ethhdr *)skb->data; @@ -337,29 +244,25 @@ static inline int __vlan_get_tag(const struct sk_buff *skb, unsigned short *tag) return -EINVAL; } - *tag = ntohs(veth->h_vlan_TCI); - + *vlan_tci = ntohs(veth->h_vlan_TCI); return 0; } /** * __vlan_hwaccel_get_tag - get the VLAN ID that is in @skb->cb[] * @skb: skbuff to query - * @tag: buffer to store vlaue - * - * Returns error if @skb->cb[] is not set correctly + * @vlan_tci: buffer to store vlaue + * + * Returns error if @skb->vlan_tci is not set correctly */ static inline int __vlan_hwaccel_get_tag(const struct sk_buff *skb, - unsigned short *tag) + u16 *vlan_tci) { - struct vlan_skb_tx_cookie *cookie; - - cookie = VLAN_TX_SKB_CB(skb); - if (cookie->magic == VLAN_TX_COOKIE_MAGIC) { - *tag = cookie->vlan_tag; + if (vlan_tx_tag_present(skb)) { + *vlan_tci = skb->vlan_tci; return 0; } else { - *tag = 0; + *vlan_tci = 0; return -EINVAL; } } @@ -369,16 +272,16 @@ static inline int __vlan_hwaccel_get_tag(const struct sk_buff *skb, /** * vlan_get_tag - get the VLAN ID from the skb * @skb: skbuff to query - * @tag: buffer to store vlaue - * + * @vlan_tci: buffer to store vlaue + * * Returns error if the skb is not VLAN tagged */ -static inline int vlan_get_tag(const struct sk_buff *skb, unsigned short *tag) +static inline int vlan_get_tag(const struct sk_buff *skb, u16 *vlan_tci) { if (skb->dev->features & NETIF_F_HW_VLAN_TX) { - return __vlan_hwaccel_get_tag(skb, tag); + return __vlan_hwaccel_get_tag(skb, vlan_tci); } else { - return __vlan_get_tag(skb, tag); + return __vlan_get_tag(skb, vlan_tci); } } @@ -402,6 +305,7 @@ enum vlan_ioctl_cmds { enum vlan_flags { VLAN_FLAG_REORDER_HDR = 0x1, + VLAN_FLAG_GVRP = 0x2, }; enum vlan_name_types { diff --git a/include/linux/igmp.h b/include/linux/igmp.h index f5a1a0db2e8e..7bb3c095c15b 100644 --- a/include/linux/igmp.h +++ b/include/linux/igmp.h @@ -228,7 +228,6 @@ extern int ip_mc_msfget(struct sock *sk, struct ip_msfilter *msf, extern int ip_mc_gsfget(struct sock *sk, struct group_filter *gsf, struct group_filter __user *optval, int __user *optlen); extern int ip_mc_sf_allow(struct sock *sk, __be32 local, __be32 rmt, int dif); -extern void ip_mr_init(void); extern void ip_mc_init_dev(struct in_device *); extern void ip_mc_destroy_dev(struct in_device *); extern void ip_mc_up(struct in_device *); diff --git a/include/linux/ip6_tunnel.h b/include/linux/ip6_tunnel.h index af3f4a70f3df..1e7cc4af40de 100644 --- a/include/linux/ip6_tunnel.h +++ b/include/linux/ip6_tunnel.h @@ -1,7 +1,3 @@ -/* - * $Id$ - */ - #ifndef _IP6_TUNNEL_H #define _IP6_TUNNEL_H diff --git a/include/linux/ipv6.h b/include/linux/ipv6.h index cde056e08181..391ad0843a46 100644 --- a/include/linux/ipv6.h +++ b/include/linux/ipv6.h @@ -163,6 +163,8 @@ struct ipv6_devconf { #ifdef CONFIG_IPV6_MROUTE __s32 mc_forwarding; #endif + __s32 disable_ipv6; + __s32 accept_dad; void *sysctl; }; @@ -194,6 +196,8 @@ enum { DEVCONF_OPTIMISTIC_DAD, DEVCONF_ACCEPT_SOURCE_ROUTE, DEVCONF_MC_FORWARDING, + DEVCONF_DISABLE_IPV6, + DEVCONF_ACCEPT_DAD, DEVCONF_MAX }; diff --git a/include/linux/istallion.h b/include/linux/istallion.h index 5a84fe944b74..0d1840723249 100644 --- a/include/linux/istallion.h +++ b/include/linux/istallion.h @@ -51,25 +51,21 @@ */ struct stliport { unsigned long magic; + struct tty_port port; unsigned int portnr; unsigned int panelnr; unsigned int brdnr; unsigned long state; unsigned int devnr; - int flags; int baud_base; int custom_divisor; int close_delay; int closing_wait; - int refcount; int openwaitcnt; int rc; int argsize; void *argp; unsigned int rxmarkmsk; - struct tty_struct *tty; - wait_queue_head_t open_wait; - wait_queue_head_t close_wait; wait_queue_head_t raw_wait; struct asysigs asig; unsigned long addr; diff --git a/include/linux/kvm.h b/include/linux/kvm.h index a281afeddfbb..0ea064cbfbc8 100644 --- a/include/linux/kvm.h +++ b/include/linux/kvm.h @@ -173,6 +173,30 @@ struct kvm_run { }; }; +/* for KVM_REGISTER_COALESCED_MMIO / KVM_UNREGISTER_COALESCED_MMIO */ + +struct kvm_coalesced_mmio_zone { + __u64 addr; + __u32 size; + __u32 pad; +}; + +struct kvm_coalesced_mmio { + __u64 phys_addr; + __u32 len; + __u32 pad; + __u8 data[8]; +}; + +struct kvm_coalesced_mmio_ring { + __u32 first, last; + struct kvm_coalesced_mmio coalesced_mmio[0]; +}; + +#define KVM_COALESCED_MMIO_MAX \ + ((PAGE_SIZE - sizeof(struct kvm_coalesced_mmio_ring)) / \ + sizeof(struct kvm_coalesced_mmio)) + /* for KVM_TRANSLATE */ struct kvm_translation { /* in */ @@ -294,14 +318,14 @@ struct kvm_trace_rec { __u32 vcpu_id; union { struct { - __u32 cycle_lo, cycle_hi; + __u64 cycle_u64; __u32 extra_u32[KVM_TRC_EXTRA_MAX]; } cycle; struct { __u32 extra_u32[KVM_TRC_EXTRA_MAX]; } nocycle; } u; -}; +} __attribute__((packed)); #define KVMIO 0xAE @@ -346,6 +370,7 @@ struct kvm_trace_rec { #define KVM_CAP_NOP_IO_DELAY 12 #define KVM_CAP_PV_MMU 13 #define KVM_CAP_MP_STATE 14 +#define KVM_CAP_COALESCED_MMIO 15 /* * ioctls for VM fds @@ -371,6 +396,10 @@ struct kvm_trace_rec { #define KVM_CREATE_PIT _IO(KVMIO, 0x64) #define KVM_GET_PIT _IOWR(KVMIO, 0x65, struct kvm_pit_state) #define KVM_SET_PIT _IOR(KVMIO, 0x66, struct kvm_pit_state) +#define KVM_REGISTER_COALESCED_MMIO \ + _IOW(KVMIO, 0x67, struct kvm_coalesced_mmio_zone) +#define KVM_UNREGISTER_COALESCED_MMIO \ + _IOW(KVMIO, 0x68, struct kvm_coalesced_mmio_zone) /* * ioctls for vcpu fds diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h index de9d1df4bba2..07d68a8ae8e9 100644 --- a/include/linux/kvm_host.h +++ b/include/linux/kvm_host.h @@ -52,7 +52,8 @@ struct kvm_io_bus { void kvm_io_bus_init(struct kvm_io_bus *bus); void kvm_io_bus_destroy(struct kvm_io_bus *bus); -struct kvm_io_device *kvm_io_bus_find_dev(struct kvm_io_bus *bus, gpa_t addr); +struct kvm_io_device *kvm_io_bus_find_dev(struct kvm_io_bus *bus, + gpa_t addr, int len, int is_write); void kvm_io_bus_register_dev(struct kvm_io_bus *bus, struct kvm_io_device *dev); @@ -116,6 +117,10 @@ struct kvm { struct kvm_vm_stat stat; struct kvm_arch arch; atomic_t users_count; +#ifdef KVM_COALESCED_MMIO_PAGE_OFFSET + struct kvm_coalesced_mmio_dev *coalesced_mmio_dev; + struct kvm_coalesced_mmio_ring *coalesced_mmio_ring; +#endif }; /* The guest did something we don't support. */ @@ -135,9 +140,6 @@ void kvm_vcpu_uninit(struct kvm_vcpu *vcpu); void vcpu_load(struct kvm_vcpu *vcpu); void vcpu_put(struct kvm_vcpu *vcpu); -void decache_vcpus_on_cpu(int cpu); - - int kvm_init(void *opaque, unsigned int vcpu_size, struct module *module); void kvm_exit(void); @@ -166,6 +168,7 @@ int kvm_arch_set_memory_region(struct kvm *kvm, struct kvm_userspace_memory_region *mem, struct kvm_memory_slot old, int user_alloc); +void kvm_arch_flush_shadow(struct kvm *kvm); gfn_t unalias_gfn(struct kvm *kvm, gfn_t gfn); struct page *gfn_to_page(struct kvm *kvm, gfn_t gfn); unsigned long gfn_to_hva(struct kvm *kvm, gfn_t gfn); diff --git a/include/linux/lockd/lockd.h b/include/linux/lockd/lockd.h index 102d928f7206..dbb87ab282e8 100644 --- a/include/linux/lockd/lockd.h +++ b/include/linux/lockd/lockd.h @@ -200,10 +200,12 @@ typedef int (*nlm_host_match_fn_t)(void *cur, struct nlm_host *ref); * Server-side lock handling */ __be32 nlmsvc_lock(struct svc_rqst *, struct nlm_file *, - struct nlm_lock *, int, struct nlm_cookie *); + struct nlm_host *, struct nlm_lock *, int, + struct nlm_cookie *); __be32 nlmsvc_unlock(struct nlm_file *, struct nlm_lock *); __be32 nlmsvc_testlock(struct svc_rqst *, struct nlm_file *, - struct nlm_lock *, struct nlm_lock *, struct nlm_cookie *); + struct nlm_host *, struct nlm_lock *, + struct nlm_lock *, struct nlm_cookie *); __be32 nlmsvc_cancel_blocked(struct nlm_file *, struct nlm_lock *); unsigned long nlmsvc_retry_blocked(void); void nlmsvc_traverse_blocks(struct nlm_host *, struct nlm_file *, @@ -224,7 +226,7 @@ void nlmsvc_invalidate_all(void); * Cluster failover support */ int nlmsvc_unlock_all_by_sb(struct super_block *sb); -int nlmsvc_unlock_all_by_ip(__be32 server_addr); +int nlmsvc_unlock_all_by_ip(struct sockaddr *server_addr); static inline struct inode *nlmsvc_file_inode(struct nlm_file *file) { diff --git a/include/linux/mfd/asic3.h b/include/linux/mfd/asic3.h index 4ab2162db13b..322cd6deb9f0 100644 --- a/include/linux/mfd/asic3.h +++ b/include/linux/mfd/asic3.h @@ -8,7 +8,7 @@ * published by the Free Software Foundation. * * Copyright 2001 Compaq Computer Corporation. - * Copyright 2007 OpendHand. + * Copyright 2007-2008 OpenedHand Ltd. */ #ifndef __ASIC3_H__ @@ -16,43 +16,22 @@ #include <linux/types.h> -struct asic3 { - void __iomem *mapping; - unsigned int bus_shift; - unsigned int irq_nr; - unsigned int irq_base; - spinlock_t lock; - u16 irq_bothedge[4]; - struct device *dev; -}; - struct asic3_platform_data { - struct { - u32 dir; - u32 init; - u32 sleep_mask; - u32 sleep_out; - u32 batt_fault_out; - u32 sleep_conf; - u32 alt_function; - } gpio_a, gpio_b, gpio_c, gpio_d; - - unsigned int bus_shift; + u16 *gpio_config; + unsigned int gpio_config_num; unsigned int irq_base; - struct platform_device **children; - unsigned int n_children; + unsigned int gpio_base; }; -int asic3_gpio_get_value(struct asic3 *asic, unsigned gpio); -void asic3_gpio_set_value(struct asic3 *asic, unsigned gpio, int val); - #define ASIC3_NUM_GPIO_BANKS 4 #define ASIC3_GPIOS_PER_BANK 16 #define ASIC3_NUM_GPIOS 64 #define ASIC3_NR_IRQS ASIC3_NUM_GPIOS + 6 +#define ASIC3_TO_GPIO(gpio) (NR_BUILTIN_GPIO + (gpio)) + #define ASIC3_GPIO_BANK_A 0 #define ASIC3_GPIO_BANK_B 1 #define ASIC3_GPIO_BANK_C 2 @@ -64,32 +43,89 @@ void asic3_gpio_set_value(struct asic3 *asic, unsigned gpio, int val); /* All offsets below are specified with this address bus shift */ #define ASIC3_DEFAULT_ADDR_SHIFT 2 -#define ASIC3_OFFSET(base, reg) (ASIC3_##base##_Base + ASIC3_##base##_##reg) +#define ASIC3_OFFSET(base, reg) (ASIC3_##base##_BASE + ASIC3_##base##_##reg) #define ASIC3_GPIO_OFFSET(base, reg) \ - (ASIC3_GPIO_##base##_Base + ASIC3_GPIO_##reg) - -#define ASIC3_GPIO_A_Base 0x0000 -#define ASIC3_GPIO_B_Base 0x0100 -#define ASIC3_GPIO_C_Base 0x0200 -#define ASIC3_GPIO_D_Base 0x0300 - -#define ASIC3_GPIO_Mask 0x00 /* R/W 0:don't mask */ -#define ASIC3_GPIO_Direction 0x04 /* R/W 0:input */ -#define ASIC3_GPIO_Out 0x08 /* R/W 0:output low */ -#define ASIC3_GPIO_TriggerType 0x0c /* R/W 0:level */ -#define ASIC3_GPIO_EdgeTrigger 0x10 /* R/W 0:falling */ -#define ASIC3_GPIO_LevelTrigger 0x14 /* R/W 0:low level detect */ -#define ASIC3_GPIO_SleepMask 0x18 /* R/W 0:don't mask in sleep mode */ -#define ASIC3_GPIO_SleepOut 0x1c /* R/W level 0:low in sleep mode */ -#define ASIC3_GPIO_BattFaultOut 0x20 /* R/W level 0:low in batt_fault */ -#define ASIC3_GPIO_IntStatus 0x24 /* R/W 0:none, 1:detect */ -#define ASIC3_GPIO_AltFunction 0x28 /* R/W 1:LED register control */ -#define ASIC3_GPIO_SleepConf 0x2c /* + (ASIC3_GPIO_##base##_BASE + ASIC3_GPIO_##reg) + +#define ASIC3_GPIO_A_BASE 0x0000 +#define ASIC3_GPIO_B_BASE 0x0100 +#define ASIC3_GPIO_C_BASE 0x0200 +#define ASIC3_GPIO_D_BASE 0x0300 + +#define ASIC3_GPIO_TO_BANK(gpio) ((gpio) >> 4) +#define ASIC3_GPIO_TO_BIT(gpio) ((gpio) - \ + (ASIC3_GPIOS_PER_BANK * ((gpio) >> 4))) +#define ASIC3_GPIO_TO_MASK(gpio) (1 << ASIC3_GPIO_TO_BIT(gpio)) +#define ASIC3_GPIO_TO_BASE(gpio) (ASIC3_GPIO_A_BASE + (((gpio) >> 4) * 0x0100)) +#define ASIC3_BANK_TO_BASE(bank) (ASIC3_GPIO_A_BASE + ((bank) * 0x100)) + +#define ASIC3_GPIO_MASK 0x00 /* R/W 0:don't mask */ +#define ASIC3_GPIO_DIRECTION 0x04 /* R/W 0:input */ +#define ASIC3_GPIO_OUT 0x08 /* R/W 0:output low */ +#define ASIC3_GPIO_TRIGGER_TYPE 0x0c /* R/W 0:level */ +#define ASIC3_GPIO_EDGE_TRIGGER 0x10 /* R/W 0:falling */ +#define ASIC3_GPIO_LEVEL_TRIGGER 0x14 /* R/W 0:low level detect */ +#define ASIC3_GPIO_SLEEP_MASK 0x18 /* R/W 0:don't mask in sleep mode */ +#define ASIC3_GPIO_SLEEP_OUT 0x1c /* R/W level 0:low in sleep mode */ +#define ASIC3_GPIO_BAT_FAULT_OUT 0x20 /* R/W level 0:low in batt_fault */ +#define ASIC3_GPIO_INT_STATUS 0x24 /* R/W 0:none, 1:detect */ +#define ASIC3_GPIO_ALT_FUNCTION 0x28 /* R/W 1:LED register control */ +#define ASIC3_GPIO_SLEEP_CONF 0x2c /* * R/W bit 1: autosleep * 0: disable gposlpout in normal mode, * enable gposlpout in sleep mode. */ -#define ASIC3_GPIO_Status 0x30 /* R Pin status */ +#define ASIC3_GPIO_STATUS 0x30 /* R Pin status */ + +/* + * ASIC3 GPIO config + * + * Bits 0..6 gpio number + * Bits 7..13 Alternate function + * Bit 14 Direction + * Bit 15 Initial value + * + */ +#define ASIC3_CONFIG_GPIO_PIN(config) ((config) & 0x7f) +#define ASIC3_CONFIG_GPIO_ALT(config) (((config) & (0x7f << 7)) >> 7) +#define ASIC3_CONFIG_GPIO_DIR(config) ((config & (1 << 14)) >> 14) +#define ASIC3_CONFIG_GPIO_INIT(config) ((config & (1 << 15)) >> 15) +#define ASIC3_CONFIG_GPIO(gpio, alt, dir, init) (((gpio) & 0x7f) \ + | (((alt) & 0x7f) << 7) | (((dir) & 0x1) << 14) \ + | (((init) & 0x1) << 15)) +#define ASIC3_CONFIG_GPIO_DEFAULT(gpio, dir, init) \ + ASIC3_CONFIG_GPIO((gpio), 0, (dir), (init)) +#define ASIC3_CONFIG_GPIO_DEFAULT_OUT(gpio, init) \ + ASIC3_CONFIG_GPIO((gpio), 0, 1, (init)) + +/* + * Alternate functions + */ +#define ASIC3_GPIOA11_PWM0 ASIC3_CONFIG_GPIO(11, 1, 1, 0) +#define ASIC3_GPIOA12_PWM1 ASIC3_CONFIG_GPIO(12, 1, 1, 0) +#define ASIC3_GPIOA15_CONTROL_CX ASIC3_CONFIG_GPIO(15, 1, 1, 0) +#define ASIC3_GPIOC0_LED0 ASIC3_CONFIG_GPIO(32, 1, 1, 0) +#define ASIC3_GPIOC1_LED1 ASIC3_CONFIG_GPIO(33, 1, 1, 0) +#define ASIC3_GPIOC2_LED2 ASIC3_CONFIG_GPIO(34, 1, 1, 0) +#define ASIC3_GPIOC3_SPI_RXD ASIC3_CONFIG_GPIO(35, 1, 0, 0) +#define ASIC3_GPIOC4_CF_nCD ASIC3_CONFIG_GPIO(36, 1, 0, 0) +#define ASIC3_GPIOC4_SPI_TXD ASIC3_CONFIG_GPIO(36, 1, 1, 0) +#define ASIC3_GPIOC5_SPI_CLK ASIC3_CONFIG_GPIO(37, 1, 1, 0) +#define ASIC3_GPIOC5_nCIOW ASIC3_CONFIG_GPIO(37, 1, 1, 0) +#define ASIC3_GPIOC6_nCIOR ASIC3_CONFIG_GPIO(38, 1, 1, 0) +#define ASIC3_GPIOC7_nPCE_1 ASIC3_CONFIG_GPIO(39, 1, 0, 0) +#define ASIC3_GPIOC8_nPCE_2 ASIC3_CONFIG_GPIO(40, 1, 0, 0) +#define ASIC3_GPIOC9_nPOE ASIC3_CONFIG_GPIO(41, 1, 0, 0) +#define ASIC3_GPIOC10_nPWE ASIC3_CONFIG_GPIO(42, 1, 0, 0) +#define ASIC3_GPIOC11_PSKTSEL ASIC3_CONFIG_GPIO(43, 1, 0, 0) +#define ASIC3_GPIOC12_nPREG ASIC3_CONFIG_GPIO(44, 1, 0, 0) +#define ASIC3_GPIOC13_nPWAIT ASIC3_CONFIG_GPIO(45, 1, 1, 0) +#define ASIC3_GPIOC14_nPIOIS16 ASIC3_CONFIG_GPIO(46, 1, 1, 0) +#define ASIC3_GPIOC15_nPIOR ASIC3_CONFIG_GPIO(47, 1, 0, 0) +#define ASIC3_GPIOD11_nCIOIS16 ASIC3_CONFIG_GPIO(59, 1, 0, 0) +#define ASIC3_GPIOD12_nCWAIT ASIC3_CONFIG_GPIO(60, 1, 0, 0) +#define ASIC3_GPIOD15_nPIOW ASIC3_CONFIG_GPIO(63, 1, 0, 0) + #define ASIC3_SPI_Base 0x0400 #define ASIC3_SPI_Control 0x0000 @@ -128,7 +164,7 @@ void asic3_gpio_set_value(struct asic3 *asic, unsigned gpio, int val); #define LED_AUTOSTOP (1 << 5) /* LED ON/OFF auto stop 0:disable, 1:enable */ #define LED_ALWAYS (1 << 6) /* LED Interrupt Mask 0:No mask, 1:mask */ -#define ASIC3_CLOCK_Base 0x0A00 +#define ASIC3_CLOCK_BASE 0x0A00 #define ASIC3_CLOCK_CDEX 0x00 #define ASIC3_CLOCK_SEL 0x04 @@ -159,12 +195,12 @@ void asic3_gpio_set_value(struct asic3 *asic, unsigned gpio, int val); #define CLOCK_SEL_CX (1 << 2) -#define ASIC3_INTR_Base 0x0B00 +#define ASIC3_INTR_BASE 0x0B00 -#define ASIC3_INTR_IntMask 0x00 /* Interrupt mask control */ -#define ASIC3_INTR_PIntStat 0x04 /* Peripheral interrupt status */ -#define ASIC3_INTR_IntCPS 0x08 /* Interrupt timer clock pre-scale */ -#define ASIC3_INTR_IntTBS 0x0c /* Interrupt timer set */ +#define ASIC3_INTR_INT_MASK 0x00 /* Interrupt mask control */ +#define ASIC3_INTR_P_INT_STAT 0x04 /* Peripheral interrupt status */ +#define ASIC3_INTR_INT_CPS 0x08 /* Interrupt timer clock pre-scale */ +#define ASIC3_INTR_INT_TBS 0x0c /* Interrupt timer set */ #define ASIC3_INTMASK_GINTMASK (1 << 0) /* Global INTs mask 1:enable */ #define ASIC3_INTMASK_GINTEL (1 << 1) /* 1: rising edge, 0: hi level */ @@ -227,44 +263,12 @@ void asic3_gpio_set_value(struct asic3 *asic, unsigned gpio, int val); #define ASIC3_EXTCF_CF_SLEEP (1 << 15) /* CF sleep mode control */ /********************************************* - * The Onewire interface registers - * - * OWM_CMD - * OWM_DAT - * OWM_INTR - * OWM_INTEN - * OWM_CLKDIV + * The Onewire interface (DS1WM) is handled + * by the ds1wm driver. * *********************************************/ -#define ASIC3_OWM_Base 0xC00 - -#define ASIC3_OWM_CMD 0x00 -#define ASIC3_OWM_DAT 0x04 -#define ASIC3_OWM_INTR 0x08 -#define ASIC3_OWM_INTEN 0x0C -#define ASIC3_OWM_CLKDIV 0x10 - -#define ASIC3_OWM_CMD_ONEWR (1 << 0) -#define ASIC3_OWM_CMD_SRA (1 << 1) -#define ASIC3_OWM_CMD_DQO (1 << 2) -#define ASIC3_OWM_CMD_DQI (1 << 3) - -#define ASIC3_OWM_INTR_PD (1 << 0) -#define ASIC3_OWM_INTR_PDR (1 << 1) -#define ASIC3_OWM_INTR_TBE (1 << 2) -#define ASIC3_OWM_INTR_TEMP (1 << 3) -#define ASIC3_OWM_INTR_RBF (1 << 4) - -#define ASIC3_OWM_INTEN_EPD (1 << 0) -#define ASIC3_OWM_INTEN_IAS (1 << 1) -#define ASIC3_OWM_INTEN_ETBE (1 << 2) -#define ASIC3_OWM_INTEN_ETMT (1 << 3) -#define ASIC3_OWM_INTEN_ERBF (1 << 4) - -#define ASIC3_OWM_CLKDIV_PRE (3 << 0) /* two bits wide at bit 0 */ -#define ASIC3_OWM_CLKDIV_DIV (7 << 2) /* 3 bits wide at bit 2 */ - +#define ASIC3_OWM_BASE 0xC00 /***************************************************************************** * The SD configuration registers are at a completely different location @@ -492,6 +496,7 @@ void asic3_gpio_set_value(struct asic3 *asic, unsigned gpio, int val); #define ASIC3_SDIO_CTRL_LEDCtrl 0x7C #define ASIC3_SDIO_CTRL_SoftwareReset 0x1C0 -#define ASIC3_MAP_SIZE 0x2000 +#define ASIC3_MAP_SIZE_32BIT 0x2000 +#define ASIC3_MAP_SIZE_16BIT 0x1000 #endif /* __ASIC3_H__ */ diff --git a/include/linux/mroute.h b/include/linux/mroute.h index de4decfa1bfc..07112ee9293a 100644 --- a/include/linux/mroute.h +++ b/include/linux/mroute.h @@ -144,11 +144,37 @@ static inline int ip_mroute_opt(int opt) } #endif +#ifdef CONFIG_IP_MROUTE extern int ip_mroute_setsockopt(struct sock *, int, char __user *, int); extern int ip_mroute_getsockopt(struct sock *, int, char __user *, int __user *); extern int ipmr_ioctl(struct sock *sk, int cmd, void __user *arg); -extern void ip_mr_init(void); +extern int ip_mr_init(void); +#else +static inline +int ip_mroute_setsockopt(struct sock *sock, + int optname, char __user *optval, int optlen) +{ + return -ENOPROTOOPT; +} + +static inline +int ip_mroute_getsockopt(struct sock *sock, + int optname, char __user *optval, int __user *optlen) +{ + return -ENOPROTOOPT; +} +static inline +int ipmr_ioctl(struct sock *sk, int cmd, void __user *arg) +{ + return -ENOIOCTLCMD; +} + +static inline int ip_mr_init(void) +{ + return 0; +} +#endif struct vif_device { diff --git a/include/linux/mroute6.h b/include/linux/mroute6.h index e7989593142b..5cf50473a10f 100644 --- a/include/linux/mroute6.h +++ b/include/linux/mroute6.h @@ -131,11 +131,44 @@ static inline int ip6_mroute_opt(int opt) struct sock; +#ifdef CONFIG_IPV6_MROUTE extern int ip6_mroute_setsockopt(struct sock *, int, char __user *, int); extern int ip6_mroute_getsockopt(struct sock *, int, char __user *, int __user *); extern int ip6_mr_input(struct sk_buff *skb); extern int ip6mr_ioctl(struct sock *sk, int cmd, void __user *arg); -extern void ip6_mr_init(void); +extern int ip6_mr_init(void); +extern void ip6_mr_cleanup(void); +#else +static inline +int ip6_mroute_setsockopt(struct sock *sock, + int optname, char __user *optval, int optlen) +{ + return -ENOPROTOOPT; +} + +static inline +int ip6_mroute_getsockopt(struct sock *sock, + int optname, char __user *optval, int __user *optlen) +{ + return -ENOPROTOOPT; +} + +static inline +int ip6mr_ioctl(struct sock *sk, int cmd, void __user *arg) +{ + return -ENOIOCTLCMD; +} + +static inline int ip6_mr_init(void) +{ + return 0; +} + +static inline void ip6_mr_cleanup(void) +{ + return; +} +#endif struct mif_device { diff --git a/include/linux/mv643xx_eth.h b/include/linux/mv643xx_eth.h index a15cdd4a8e58..12078577aef6 100644 --- a/include/linux/mv643xx_eth.h +++ b/include/linux/mv643xx_eth.h @@ -17,30 +17,59 @@ struct mv643xx_eth_shared_platform_data { struct mbus_dram_target_info *dram; - unsigned int t_clk; + unsigned int t_clk; }; struct mv643xx_eth_platform_data { + /* + * Pointer back to our parent instance, and our port number. + */ struct platform_device *shared; - int port_number; + int port_number; + /* + * Whether a PHY is present, and if yes, at which address. + */ struct platform_device *shared_smi; + int force_phy_addr; + int phy_addr; - u16 force_phy_addr; /* force override if phy_addr == 0 */ - u16 phy_addr; - - /* If speed is 0, then speed and duplex are autonegotiated. */ - int speed; /* 0, SPEED_10, SPEED_100, SPEED_1000 */ - int duplex; /* DUPLEX_HALF or DUPLEX_FULL */ - - /* non-zero values of the following fields override defaults */ - u32 tx_queue_size; - u32 rx_queue_size; - u32 tx_sram_addr; - u32 tx_sram_size; - u32 rx_sram_addr; - u32 rx_sram_size; - u8 mac_addr[6]; /* mac address if non-zero*/ + /* + * Use this MAC address if it is valid, overriding the + * address that is already in the hardware. + */ + u8 mac_addr[6]; + + /* + * If speed is 0, autonegotiation is enabled. + * Valid values for speed: 0, SPEED_10, SPEED_100, SPEED_1000. + * Valid values for duplex: DUPLEX_HALF, DUPLEX_FULL. + */ + int speed; + int duplex; + + /* + * Which RX/TX queues to use. + */ + int rx_queue_mask; + int tx_queue_mask; + + /* + * Override default RX/TX queue sizes if nonzero. + */ + int rx_queue_size; + int tx_queue_size; + + /* + * Use on-chip SRAM for RX/TX descriptors if size is nonzero + * and sufficient to contain all descriptors for the requested + * ring sizes. + */ + unsigned long rx_sram_addr; + int rx_sram_size; + unsigned long tx_sram_addr; + int tx_sram_size; }; -#endif /* __LINUX_MV643XX_ETH_H */ + +#endif diff --git a/include/linux/net.h b/include/linux/net.h index 71f7dd559285..150a48c68d52 100644 --- a/include/linux/net.h +++ b/include/linux/net.h @@ -106,23 +106,23 @@ enum sock_shutdown_cmd { /** * struct socket - general BSD socket * @state: socket state (%SS_CONNECTED, etc) + * @type: socket type (%SOCK_STREAM, etc) * @flags: socket flags (%SOCK_ASYNC_NOSPACE, etc) * @ops: protocol specific socket operations * @fasync_list: Asynchronous wake up list * @file: File back pointer for gc * @sk: internal networking protocol agnostic socket representation * @wait: wait queue for several uses - * @type: socket type (%SOCK_STREAM, etc) */ struct socket { socket_state state; + short type; unsigned long flags; const struct proto_ops *ops; struct fasync_struct *fasync_list; struct file *file; struct sock *sk; wait_queue_head_t wait; - short type; }; struct vm_area_struct; diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 25f87102ab66..812bcd8b4363 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -118,14 +118,6 @@ struct wireless_dev; #endif /* __KERNEL__ */ -struct net_device_subqueue -{ - /* Give a control state for each queue. This struct may contain - * per-queue locks in the future. - */ - unsigned long state; -}; - /* * Network device statistics. Akin to the 2.0 ether stats but * with byte counters. @@ -281,14 +273,11 @@ struct header_ops { enum netdev_state_t { - __LINK_STATE_XOFF=0, __LINK_STATE_START, __LINK_STATE_PRESENT, - __LINK_STATE_SCHED, __LINK_STATE_NOCARRIER, __LINK_STATE_LINKWATCH_PENDING, __LINK_STATE_DORMANT, - __LINK_STATE_QDISC_RUNNING, }; @@ -448,6 +437,20 @@ static inline void napi_synchronize(const struct napi_struct *n) # define napi_synchronize(n) barrier() #endif +enum netdev_queue_state_t +{ + __QUEUE_STATE_XOFF, +}; + +struct netdev_queue { + struct net_device *dev; + struct Qdisc *qdisc; + unsigned long state; + spinlock_t _xmit_lock; + int xmit_lock_owner; + struct Qdisc *qdisc_sleeping; +} ____cacheline_aligned_in_smp; + /* * The DEVICE structure. * Actually, this whole structure is a big mistake. It mixes I/O @@ -516,7 +519,6 @@ struct net_device #define NETIF_F_LLTX 4096 /* LockLess TX - deprecated. Please */ /* do not use LLTX in new drivers */ #define NETIF_F_NETNS_LOCAL 8192 /* Does not change network namespaces */ -#define NETIF_F_MULTI_QUEUE 16384 /* Has multiple TX/RX queues */ #define NETIF_F_LRO 32768 /* large receive offload */ /* Segmentation offload features */ @@ -537,8 +539,6 @@ struct net_device #define NETIF_F_V6_CSUM (NETIF_F_GEN_CSUM | NETIF_F_IPV6_CSUM) #define NETIF_F_ALL_CSUM (NETIF_F_V4_CSUM | NETIF_F_V6_CSUM) - struct net_device *next_sched; - /* Interface index. Unique device identifier */ int ifindex; int iflink; @@ -594,13 +594,14 @@ 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 */ int uc_count; /* Number of installed ucasts */ int uc_promisc; struct dev_addr_list *mc_list; /* Multicast mac addresses */ int mc_count; /* Number of installed mcasts */ - int promiscuity; - int allmulti; + unsigned int promiscuity; + unsigned int allmulti; /* Protocol specific pointers */ @@ -624,32 +625,21 @@ struct net_device unsigned char broadcast[MAX_ADDR_LEN]; /* hw bcast add */ - /* ingress path synchronizer */ - spinlock_t ingress_lock; - struct Qdisc *qdisc_ingress; + struct netdev_queue rx_queue; -/* - * Cache line mostly used on queue transmit path (qdisc) - */ - /* device queue lock */ - spinlock_t queue_lock ____cacheline_aligned_in_smp; - struct Qdisc *qdisc; - struct Qdisc *qdisc_sleeping; - struct list_head qdisc_list; - unsigned long tx_queue_len; /* Max frames per queue allowed */ + struct netdev_queue *_tx ____cacheline_aligned_in_smp; - /* Partially transmitted GSO packet. */ - struct sk_buff *gso_skb; + /* Number of TX queues allocated at alloc_netdev_mq() time */ + unsigned int num_tx_queues; + + /* Number of TX queues currently active in device */ + unsigned int real_num_tx_queues; + + unsigned long tx_queue_len; /* Max frames per queue allowed */ /* * One part is mostly used on xmit path (device) */ - /* hard_start_xmit synchronizer */ - spinlock_t _xmit_lock ____cacheline_aligned_in_smp; - /* cpu id of processor entered to hard_start_xmit or -1, - if nobody entered there. - */ - int xmit_lock_owner; void *priv; /* pointer to private data */ int (*hard_start_xmit) (struct sk_buff *skb, struct net_device *dev); @@ -728,6 +718,9 @@ struct net_device void (*poll_controller)(struct net_device *dev); #endif + u16 (*select_queue)(struct net_device *dev, + struct sk_buff *skb); + #ifdef CONFIG_NET_NS /* Network namespace this network device is inside */ struct net *nd_net; @@ -740,6 +733,8 @@ struct net_device struct net_bridge_port *br_port; /* macvlan */ struct macvlan_port *macvlan_port; + /* GARP */ + struct garp_port *garp_port; /* class/net/name entry */ struct device dev; @@ -755,16 +750,31 @@ struct net_device /* for setting kernel sock attribute on TCP connection setup */ #define GSO_MAX_SIZE 65536 unsigned int gso_max_size; - - /* The TX queue control structures */ - unsigned int egress_subqueue_count; - struct net_device_subqueue egress_subqueue[1]; }; #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, + unsigned int index) +{ + return &dev->_tx[index]; +} + +static inline void netdev_for_each_tx_queue(struct net_device *dev, + void (*f)(struct net_device *, + struct netdev_queue *, + void *), + void *arg) +{ + unsigned int i; + + for (i = 0; i < dev->num_tx_queues; i++) + f(dev, &dev->_tx[i], arg); +} + /* * Net namespace inlines */ @@ -795,7 +805,9 @@ void dev_net_set(struct net_device *dev, struct net *net) */ static inline void *netdev_priv(const struct net_device *dev) { - return dev->priv; + return (char *)dev + ((sizeof(struct net_device) + + NETDEV_ALIGN_CONST) + & ~NETDEV_ALIGN_CONST); } /* Set the sysfs physical device reference for the network logical device @@ -830,6 +842,19 @@ static inline void netif_napi_add(struct net_device *dev, set_bit(NAPI_STATE_SCHED, &napi->state); } +/** + * netif_napi_del - remove a napi context + * @napi: napi context + * + * netif_napi_del() removes a napi context from the network device napi list + */ +static inline void netif_napi_del(struct napi_struct *napi) +{ +#ifdef CONFIG_NETPOLL + list_del(&napi->dev_list); +#endif +} + struct packet_type { __be16 type; /* This is really htons(ether_type). */ struct net_device *dev; /* NULL is wildcarded here */ @@ -890,6 +915,7 @@ extern struct net_device *__dev_get_by_name(struct net *net, const char *name); extern int dev_alloc_name(struct net_device *dev, const char *name); extern int dev_open(struct net_device *dev); extern int dev_close(struct net_device *dev); +extern void dev_disable_lro(struct net_device *dev); extern int dev_queue_xmit(struct sk_buff *skb); extern int register_netdevice(struct net_device *dev); extern void unregister_netdevice(struct net_device *dev); @@ -939,7 +965,7 @@ static inline int unregister_gifconf(unsigned int family) */ struct softnet_data { - struct net_device *output_queue; + struct Qdisc *output_queue; struct sk_buff_head input_pkt_queue; struct list_head poll_list; struct sk_buff *completion_queue; @@ -954,12 +980,20 @@ DECLARE_PER_CPU(struct softnet_data,softnet_data); #define HAVE_NETIF_QUEUE -extern void __netif_schedule(struct net_device *dev); +extern void __netif_schedule(struct Qdisc *q); -static inline void netif_schedule(struct net_device *dev) +static inline void netif_schedule_queue(struct netdev_queue *txq) { - if (!test_bit(__LINK_STATE_XOFF, &dev->state)) - __netif_schedule(dev); + if (!test_bit(__QUEUE_STATE_XOFF, &txq->state)) + __netif_schedule(txq->qdisc); +} + +static inline void netif_tx_schedule_all(struct net_device *dev) +{ + unsigned int i; + + for (i = 0; i < dev->num_tx_queues; i++) + netif_schedule_queue(netdev_get_tx_queue(dev, i)); } /** @@ -968,9 +1002,24 @@ static inline void netif_schedule(struct net_device *dev) * * Allow upper layers to call the device hard_start_xmit routine. */ +static inline void netif_tx_start_queue(struct netdev_queue *dev_queue) +{ + clear_bit(__QUEUE_STATE_XOFF, &dev_queue->state); +} + static inline void netif_start_queue(struct net_device *dev) { - clear_bit(__LINK_STATE_XOFF, &dev->state); + netif_tx_start_queue(netdev_get_tx_queue(dev, 0)); +} + +static inline void netif_tx_start_all_queues(struct net_device *dev) +{ + unsigned int i; + + for (i = 0; i < dev->num_tx_queues; i++) { + struct netdev_queue *txq = netdev_get_tx_queue(dev, i); + netif_tx_start_queue(txq); + } } /** @@ -980,16 +1029,31 @@ static inline void netif_start_queue(struct net_device *dev) * Allow upper layers to call the device hard_start_xmit routine. * Used for flow control when transmit resources are available. */ -static inline void netif_wake_queue(struct net_device *dev) +static inline void netif_tx_wake_queue(struct netdev_queue *dev_queue) { #ifdef CONFIG_NETPOLL_TRAP if (netpoll_trap()) { - clear_bit(__LINK_STATE_XOFF, &dev->state); + clear_bit(__QUEUE_STATE_XOFF, &dev_queue->state); return; } #endif - if (test_and_clear_bit(__LINK_STATE_XOFF, &dev->state)) - __netif_schedule(dev); + if (test_and_clear_bit(__QUEUE_STATE_XOFF, &dev_queue->state)) + __netif_schedule(dev_queue->qdisc); +} + +static inline void netif_wake_queue(struct net_device *dev) +{ + netif_tx_wake_queue(netdev_get_tx_queue(dev, 0)); +} + +static inline void netif_tx_wake_all_queues(struct net_device *dev) +{ + unsigned int i; + + for (i = 0; i < dev->num_tx_queues; i++) { + struct netdev_queue *txq = netdev_get_tx_queue(dev, i); + netif_tx_wake_queue(txq); + } } /** @@ -999,9 +1063,24 @@ static inline void netif_wake_queue(struct net_device *dev) * Stop upper layers calling the device hard_start_xmit routine. * Used for flow control when transmit resources are unavailable. */ +static inline void netif_tx_stop_queue(struct netdev_queue *dev_queue) +{ + set_bit(__QUEUE_STATE_XOFF, &dev_queue->state); +} + static inline void netif_stop_queue(struct net_device *dev) { - set_bit(__LINK_STATE_XOFF, &dev->state); + netif_tx_stop_queue(netdev_get_tx_queue(dev, 0)); +} + +static inline void netif_tx_stop_all_queues(struct net_device *dev) +{ + unsigned int i; + + for (i = 0; i < dev->num_tx_queues; i++) { + struct netdev_queue *txq = netdev_get_tx_queue(dev, i); + netif_tx_stop_queue(txq); + } } /** @@ -1010,9 +1089,14 @@ static inline void netif_stop_queue(struct net_device *dev) * * Test if transmit queue on device is currently unable to send. */ +static inline int netif_tx_queue_stopped(const struct netdev_queue *dev_queue) +{ + return test_bit(__QUEUE_STATE_XOFF, &dev_queue->state); +} + static inline int netif_queue_stopped(const struct net_device *dev) { - return test_bit(__LINK_STATE_XOFF, &dev->state); + return netif_tx_queue_stopped(netdev_get_tx_queue(dev, 0)); } /** @@ -1042,9 +1126,8 @@ static inline int netif_running(const struct net_device *dev) */ static inline void netif_start_subqueue(struct net_device *dev, u16 queue_index) { -#ifdef CONFIG_NETDEVICES_MULTIQUEUE - clear_bit(__LINK_STATE_XOFF, &dev->egress_subqueue[queue_index].state); -#endif + struct netdev_queue *txq = netdev_get_tx_queue(dev, queue_index); + clear_bit(__QUEUE_STATE_XOFF, &txq->state); } /** @@ -1056,13 +1139,12 @@ static inline void netif_start_subqueue(struct net_device *dev, u16 queue_index) */ static inline void netif_stop_subqueue(struct net_device *dev, u16 queue_index) { -#ifdef CONFIG_NETDEVICES_MULTIQUEUE + struct netdev_queue *txq = netdev_get_tx_queue(dev, queue_index); #ifdef CONFIG_NETPOLL_TRAP if (netpoll_trap()) return; #endif - set_bit(__LINK_STATE_XOFF, &dev->egress_subqueue[queue_index].state); -#endif + set_bit(__QUEUE_STATE_XOFF, &txq->state); } /** @@ -1075,12 +1157,8 @@ static inline void netif_stop_subqueue(struct net_device *dev, u16 queue_index) static inline int __netif_subqueue_stopped(const struct net_device *dev, u16 queue_index) { -#ifdef CONFIG_NETDEVICES_MULTIQUEUE - return test_bit(__LINK_STATE_XOFF, - &dev->egress_subqueue[queue_index].state); -#else - return 0; -#endif + struct netdev_queue *txq = netdev_get_tx_queue(dev, queue_index); + return test_bit(__QUEUE_STATE_XOFF, &txq->state); } static inline int netif_subqueue_stopped(const struct net_device *dev, @@ -1098,15 +1176,13 @@ static inline int netif_subqueue_stopped(const struct net_device *dev, */ static inline void netif_wake_subqueue(struct net_device *dev, u16 queue_index) { -#ifdef CONFIG_NETDEVICES_MULTIQUEUE + struct netdev_queue *txq = netdev_get_tx_queue(dev, queue_index); #ifdef CONFIG_NETPOLL_TRAP if (netpoll_trap()) return; #endif - if (test_and_clear_bit(__LINK_STATE_XOFF, - &dev->egress_subqueue[queue_index].state)) - __netif_schedule(dev); -#endif + if (test_and_clear_bit(__QUEUE_STATE_XOFF, &txq->state)) + __netif_schedule(txq->qdisc); } /** @@ -1114,15 +1190,10 @@ static inline void netif_wake_subqueue(struct net_device *dev, u16 queue_index) * @dev: network device * * Check if device has multiple transmit queues - * Always falls if NETDEVICE_MULTIQUEUE is not configured */ static inline int netif_is_multiqueue(const struct net_device *dev) { -#ifdef CONFIG_NETDEVICES_MULTIQUEUE - return (!!(NETIF_F_MULTI_QUEUE & dev->features)); -#else - return 0; -#endif + return (dev->num_tx_queues > 1); } /* Use this variant when it is known for sure that it @@ -1142,6 +1213,7 @@ extern int netif_rx(struct sk_buff *skb); extern int netif_rx_ni(struct sk_buff *skb); #define HAVE_NETIF_RECEIVE_SKB 1 extern int netif_receive_skb(struct sk_buff *skb); +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 *); extern int dev_ethtool(struct net *net, struct ifreq *); @@ -1154,7 +1226,8 @@ extern int dev_set_mtu(struct net_device *, int); extern int dev_set_mac_address(struct net_device *, struct sockaddr *); extern int dev_hard_start_xmit(struct sk_buff *skb, - struct net_device *dev); + struct net_device *dev, + struct netdev_queue *txq); extern int netdev_budget; @@ -1397,62 +1470,121 @@ static inline void netif_rx_complete(struct net_device *dev, * * Get network device transmit lock */ -static inline void __netif_tx_lock(struct net_device *dev, int cpu) +static inline void __netif_tx_lock(struct netdev_queue *txq, int cpu) { - spin_lock(&dev->_xmit_lock); - dev->xmit_lock_owner = cpu; + spin_lock(&txq->_xmit_lock); + txq->xmit_lock_owner = cpu; +} + +static inline void __netif_tx_lock_bh(struct netdev_queue *txq) +{ + spin_lock_bh(&txq->_xmit_lock); + txq->xmit_lock_owner = smp_processor_id(); } static inline void netif_tx_lock(struct net_device *dev) { - __netif_tx_lock(dev, smp_processor_id()); + int cpu = smp_processor_id(); + unsigned int i; + + for (i = 0; i < dev->num_tx_queues; i++) { + struct netdev_queue *txq = netdev_get_tx_queue(dev, i); + __netif_tx_lock(txq, cpu); + } } static inline void netif_tx_lock_bh(struct net_device *dev) { - spin_lock_bh(&dev->_xmit_lock); - dev->xmit_lock_owner = smp_processor_id(); + local_bh_disable(); + netif_tx_lock(dev); } -static inline int netif_tx_trylock(struct net_device *dev) +static inline int __netif_tx_trylock(struct netdev_queue *txq) { - int ok = spin_trylock(&dev->_xmit_lock); + int ok = spin_trylock(&txq->_xmit_lock); if (likely(ok)) - dev->xmit_lock_owner = smp_processor_id(); + txq->xmit_lock_owner = smp_processor_id(); return ok; } +static inline int netif_tx_trylock(struct net_device *dev) +{ + return __netif_tx_trylock(netdev_get_tx_queue(dev, 0)); +} + +static inline void __netif_tx_unlock(struct netdev_queue *txq) +{ + txq->xmit_lock_owner = -1; + spin_unlock(&txq->_xmit_lock); +} + +static inline void __netif_tx_unlock_bh(struct netdev_queue *txq) +{ + txq->xmit_lock_owner = -1; + spin_unlock_bh(&txq->_xmit_lock); +} + static inline void netif_tx_unlock(struct net_device *dev) { - dev->xmit_lock_owner = -1; - spin_unlock(&dev->_xmit_lock); + unsigned int i; + + for (i = 0; i < dev->num_tx_queues; i++) { + struct netdev_queue *txq = netdev_get_tx_queue(dev, i); + __netif_tx_unlock(txq); + } + } static inline void netif_tx_unlock_bh(struct net_device *dev) { - dev->xmit_lock_owner = -1; - spin_unlock_bh(&dev->_xmit_lock); + netif_tx_unlock(dev); + local_bh_enable(); } -#define HARD_TX_LOCK(dev, cpu) { \ +#define HARD_TX_LOCK(dev, txq, cpu) { \ if ((dev->features & NETIF_F_LLTX) == 0) { \ - __netif_tx_lock(dev, cpu); \ + __netif_tx_lock(txq, cpu); \ } \ } -#define HARD_TX_UNLOCK(dev) { \ +#define HARD_TX_UNLOCK(dev, txq) { \ if ((dev->features & NETIF_F_LLTX) == 0) { \ - netif_tx_unlock(dev); \ + __netif_tx_unlock(txq); \ } \ } static inline void netif_tx_disable(struct net_device *dev) { + unsigned int i; + netif_tx_lock_bh(dev); - netif_stop_queue(dev); + for (i = 0; i < dev->num_tx_queues; i++) { + struct netdev_queue *txq = netdev_get_tx_queue(dev, i); + netif_tx_stop_queue(txq); + } netif_tx_unlock_bh(dev); } +static inline void netif_addr_lock(struct net_device *dev) +{ + spin_lock(&dev->addr_list_lock); +} + +static inline void netif_addr_lock_bh(struct net_device *dev) +{ + spin_lock_bh(&dev->addr_list_lock); +} + +static inline void netif_addr_unlock(struct net_device *dev) +{ + spin_unlock(&dev->addr_list_lock); +} + +static inline void netif_addr_unlock_bh(struct net_device *dev) +{ + spin_unlock_bh(&dev->addr_list_lock); +} + /* These functions live elsewhere (drivers/net/net_init.c, but related) */ extern void ether_setup(struct net_device *dev); @@ -1480,9 +1612,10 @@ extern int __dev_addr_delete(struct dev_addr_list **list, int *count, void *ad extern int __dev_addr_add(struct dev_addr_list **list, int *count, void *addr, int alen, int newonly); extern int __dev_addr_sync(struct dev_addr_list **to, int *to_count, struct dev_addr_list **from, int *from_count); extern void __dev_addr_unsync(struct dev_addr_list **to, int *to_count, struct dev_addr_list **from, int *from_count); -extern void dev_set_promiscuity(struct net_device *dev, int inc); -extern void dev_set_allmulti(struct net_device *dev, int inc); +extern int dev_set_promiscuity(struct net_device *dev, int inc); +extern int dev_set_allmulti(struct net_device *dev, int inc); extern void netdev_state_change(struct net_device *dev); +extern void netdev_bonding_change(struct net_device *dev); extern void netdev_features_change(struct net_device *dev); /* Load a device via the kmod */ extern void dev_load(struct net *net, const char *name); @@ -1509,6 +1642,9 @@ extern void *dev_seq_next(struct seq_file *seq, void *v, loff_t *pos); extern void dev_seq_stop(struct seq_file *seq, void *v); #endif +extern int netdev_class_create_file(struct class_attribute *class_attr); +extern void netdev_class_remove_file(struct class_attribute *class_attr); + extern void linkwatch_run_queue(void); extern int netdev_compute_features(unsigned long all, unsigned long one); diff --git a/include/linux/netfilter/nfnetlink_conntrack.h b/include/linux/netfilter/nfnetlink_conntrack.h index 0a383ac083cb..759bc043dc65 100644 --- a/include/linux/netfilter/nfnetlink_conntrack.h +++ b/include/linux/netfilter/nfnetlink_conntrack.h @@ -81,6 +81,7 @@ enum ctattr_protoinfo { CTA_PROTOINFO_UNSPEC, CTA_PROTOINFO_TCP, CTA_PROTOINFO_DCCP, + CTA_PROTOINFO_SCTP, __CTA_PROTOINFO_MAX }; #define CTA_PROTOINFO_MAX (__CTA_PROTOINFO_MAX - 1) @@ -103,6 +104,15 @@ enum ctattr_protoinfo_dccp { }; #define CTA_PROTOINFO_DCCP_MAX (__CTA_PROTOINFO_DCCP_MAX - 1) +enum ctattr_protoinfo_sctp { + CTA_PROTOINFO_SCTP_UNSPEC, + CTA_PROTOINFO_SCTP_STATE, + CTA_PROTOINFO_SCTP_VTAG_ORIGINAL, + CTA_PROTOINFO_SCTP_VTAG_REPLY, + __CTA_PROTOINFO_SCTP_MAX +}; +#define CTA_PROTOINFO_SCTP_MAX (__CTA_PROTOINFO_SCTP_MAX - 1) + enum ctattr_counters { CTA_COUNTERS_UNSPEC, CTA_COUNTERS_PACKETS, /* old 64bit counters */ diff --git a/include/linux/netfilter/xt_string.h b/include/linux/netfilter/xt_string.h index bb21dd1aee2d..8a6ba7bbef9f 100644 --- a/include/linux/netfilter/xt_string.h +++ b/include/linux/netfilter/xt_string.h @@ -4,6 +4,11 @@ #define XT_STRING_MAX_PATTERN_SIZE 128 #define XT_STRING_MAX_ALGO_NAME_SIZE 16 +enum { + XT_STRING_FLAG_INVERT = 0x01, + XT_STRING_FLAG_IGNORECASE = 0x02 +}; + struct xt_string_info { u_int16_t from_offset; @@ -11,7 +16,15 @@ struct xt_string_info char algo[XT_STRING_MAX_ALGO_NAME_SIZE]; char pattern[XT_STRING_MAX_PATTERN_SIZE]; u_int8_t patlen; - u_int8_t invert; + union { + struct { + u_int8_t invert; + } v0; + + struct { + u_int8_t flags; + } v1; + } u; /* Used internally by the kernel */ struct ts_config __attribute__((aligned(8))) *config; diff --git a/include/linux/netfilter_bridge/ebt_ip6.h b/include/linux/netfilter_bridge/ebt_ip6.h new file mode 100644 index 000000000000..2273c3ae33ca --- /dev/null +++ b/include/linux/netfilter_bridge/ebt_ip6.h @@ -0,0 +1,40 @@ +/* + * ebt_ip6 + * + * Authors: + * Kuo-Lang Tseng <kuo-lang.tseng@intel.com> + * Manohar Castelino <manohar.r.castelino@intel.com> + * + * Jan 11, 2008 + * + */ + +#ifndef __LINUX_BRIDGE_EBT_IP6_H +#define __LINUX_BRIDGE_EBT_IP6_H + +#define EBT_IP6_SOURCE 0x01 +#define EBT_IP6_DEST 0x02 +#define EBT_IP6_TCLASS 0x04 +#define EBT_IP6_PROTO 0x08 +#define EBT_IP6_SPORT 0x10 +#define EBT_IP6_DPORT 0x20 +#define EBT_IP6_MASK (EBT_IP6_SOURCE | EBT_IP6_DEST | EBT_IP6_TCLASS |\ + EBT_IP6_PROTO | EBT_IP6_SPORT | EBT_IP6_DPORT) +#define EBT_IP6_MATCH "ip6" + +/* the same values are used for the invflags */ +struct ebt_ip6_info +{ + struct in6_addr saddr; + struct in6_addr daddr; + struct in6_addr smsk; + struct in6_addr dmsk; + uint8_t tclass; + uint8_t protocol; + uint8_t bitmask; + uint8_t invflags; + uint16_t sport[2]; + uint16_t dport[2]; +}; + +#endif diff --git a/include/linux/netfilter_bridge/ebt_log.h b/include/linux/netfilter_bridge/ebt_log.h index 96e231ae7554..b76e653157e5 100644 --- a/include/linux/netfilter_bridge/ebt_log.h +++ b/include/linux/netfilter_bridge/ebt_log.h @@ -4,7 +4,8 @@ #define EBT_LOG_IP 0x01 /* if the frame is made by ip, log the ip information */ #define EBT_LOG_ARP 0x02 #define EBT_LOG_NFLOG 0x04 -#define EBT_LOG_MASK (EBT_LOG_IP | EBT_LOG_ARP) +#define EBT_LOG_IP6 0x08 +#define EBT_LOG_MASK (EBT_LOG_IP | EBT_LOG_ARP | EBT_LOG_IP6) #define EBT_LOG_PREFIX_SIZE 30 #define EBT_LOG_WATCHER "log" diff --git a/include/linux/netfilter_ipv4.h b/include/linux/netfilter_ipv4.h index 650318b0c405..29c7727ff0e8 100644 --- a/include/linux/netfilter_ipv4.h +++ b/include/linux/netfilter_ipv4.h @@ -60,6 +60,7 @@ enum nf_ip_hook_priorities { NF_IP_PRI_MANGLE = -150, NF_IP_PRI_NAT_DST = -100, NF_IP_PRI_FILTER = 0, + NF_IP_PRI_SECURITY = 50, NF_IP_PRI_NAT_SRC = 100, NF_IP_PRI_SELINUX_LAST = 225, NF_IP_PRI_CONNTRACK_CONFIRM = INT_MAX, diff --git a/include/linux/netfilter_ipv6.h b/include/linux/netfilter_ipv6.h index 3475a65dae9b..d654873aa25a 100644 --- a/include/linux/netfilter_ipv6.h +++ b/include/linux/netfilter_ipv6.h @@ -64,11 +64,14 @@ enum nf_ip6_hook_priorities { NF_IP6_PRI_MANGLE = -150, NF_IP6_PRI_NAT_DST = -100, NF_IP6_PRI_FILTER = 0, + NF_IP6_PRI_SECURITY = 50, NF_IP6_PRI_NAT_SRC = 100, NF_IP6_PRI_SELINUX_LAST = 225, NF_IP6_PRI_LAST = INT_MAX, }; +#ifdef __KERNEL__ + #ifdef CONFIG_NETFILTER extern int ip6_route_me_harder(struct sk_buff *skb); extern __sum16 nf_ip6_checksum(struct sk_buff *skb, unsigned int hook, @@ -81,4 +84,6 @@ static inline int ipv6_netfilter_init(void) { return 0; } static inline void ipv6_netfilter_fini(void) { return; } #endif /* CONFIG_NETFILTER */ +#endif /* __KERNEL__ */ + #endif /*__LINUX_IP6_NETFILTER_H*/ diff --git a/include/linux/netlink.h b/include/linux/netlink.h index bec1062a25a1..9ff1b54908f3 100644 --- a/include/linux/netlink.h +++ b/include/linux/netlink.h @@ -193,7 +193,7 @@ extern int netlink_unregister_notifier(struct notifier_block *nb); /* finegrained unicast helpers: */ struct sock *netlink_getsockbyfilp(struct file *filp); -int netlink_attachskb(struct sock *sk, struct sk_buff *skb, int nonblock, +int netlink_attachskb(struct sock *sk, struct sk_buff *skb, long *timeo, struct sock *ssk); void netlink_detachskb(struct sock *sk, struct sk_buff *skb); int netlink_sendskb(struct sock *sk, struct sk_buff *skb); diff --git a/include/linux/nfs4.h b/include/linux/nfs4.h index 8726491de154..ea0366769484 100644 --- a/include/linux/nfs4.h +++ b/include/linux/nfs4.h @@ -65,9 +65,6 @@ #define NFS4_ACE_SUCCESSFUL_ACCESS_ACE_FLAG 0x00000010 #define NFS4_ACE_FAILED_ACCESS_ACE_FLAG 0x00000020 #define NFS4_ACE_IDENTIFIER_GROUP 0x00000040 -#define NFS4_ACE_OWNER 0x00000080 -#define NFS4_ACE_GROUP 0x00000100 -#define NFS4_ACE_EVERYONE 0x00000200 #define NFS4_ACE_READ_DATA 0x00000001 #define NFS4_ACE_LIST_DIRECTORY 0x00000001 diff --git a/include/linux/nfsd/nfsd.h b/include/linux/nfsd/nfsd.h index 41d30c9c9de6..a2861d95ecc3 100644 --- a/include/linux/nfsd/nfsd.h +++ b/include/linux/nfsd/nfsd.h @@ -28,20 +28,20 @@ #define NFSD_SUPPORTED_MINOR_VERSION 0 /* - * Special flags for nfsd_permission. These must be different from MAY_READ, - * MAY_WRITE, and MAY_EXEC. + * Flags for nfsd_permission */ -#define MAY_NOP 0 -#define MAY_SATTR 8 -#define MAY_TRUNC 16 -#define MAY_LOCK 32 -#define MAY_OWNER_OVERRIDE 64 -#define MAY_LOCAL_ACCESS 128 /* IRIX doing local access check on device special file*/ -#if (MAY_SATTR | MAY_TRUNC | MAY_LOCK | MAY_OWNER_OVERRIDE | MAY_LOCAL_ACCESS) & (MAY_READ | MAY_WRITE | MAY_EXEC) -# error "please use a different value for MAY_SATTR or MAY_TRUNC or MAY_LOCK or MAY_LOCAL_ACCESS or MAY_OWNER_OVERRIDE." -#endif -#define MAY_CREATE (MAY_EXEC|MAY_WRITE) -#define MAY_REMOVE (MAY_EXEC|MAY_WRITE|MAY_TRUNC) +#define NFSD_MAY_NOP 0 +#define NFSD_MAY_EXEC 1 /* == MAY_EXEC */ +#define NFSD_MAY_WRITE 2 /* == MAY_WRITE */ +#define NFSD_MAY_READ 4 /* == MAY_READ */ +#define NFSD_MAY_SATTR 8 +#define NFSD_MAY_TRUNC 16 +#define NFSD_MAY_LOCK 32 +#define NFSD_MAY_OWNER_OVERRIDE 64 +#define NFSD_MAY_LOCAL_ACCESS 128 /* IRIX doing local access check on device special file*/ + +#define NFSD_MAY_CREATE (NFSD_MAY_EXEC|NFSD_MAY_WRITE) +#define NFSD_MAY_REMOVE (NFSD_MAY_EXEC|NFSD_MAY_WRITE|NFSD_MAY_TRUNC) /* * Callback function for readdir @@ -54,6 +54,7 @@ typedef int (*nfsd_dirop_t)(struct inode *, struct dentry *, int, int); extern struct svc_program nfsd_program; extern struct svc_version nfsd_version2, nfsd_version3, nfsd_version4; +extern struct mutex nfsd_mutex; extern struct svc_serv *nfsd_serv; extern struct seq_operations nfs_exports_op; diff --git a/include/linux/nfsd/state.h b/include/linux/nfsd/state.h index db348f749376..d0fe2e378452 100644 --- a/include/linux/nfsd/state.h +++ b/include/linux/nfsd/state.h @@ -98,8 +98,6 @@ struct nfs4_callback { u32 cb_ident; /* RPC client info */ atomic_t cb_set; /* successful CB_NULL call */ - struct rpc_program cb_program; - struct rpc_stat cb_stat; struct rpc_clnt * cb_client; }; diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h index ea6517e58b04..2be7c63bc0f2 100644 --- a/include/linux/nl80211.h +++ b/include/linux/nl80211.h @@ -122,13 +122,13 @@ enum nl80211_commands { NL80211_CMD_NEW_STATION, NL80211_CMD_DEL_STATION, - /* add commands here */ - NL80211_CMD_GET_MPATH, NL80211_CMD_SET_MPATH, NL80211_CMD_NEW_MPATH, NL80211_CMD_DEL_MPATH, + /* add commands here */ + /* used to define NL80211_CMD_MAX below */ __NL80211_CMD_AFTER_LAST, NL80211_CMD_MAX = __NL80211_CMD_AFTER_LAST - 1 @@ -230,18 +230,21 @@ enum nl80211_attrs { NL80211_ATTR_MNTR_FLAGS, - /* add attributes here, update the policy in nl80211.c */ - NL80211_ATTR_MESH_ID, NL80211_ATTR_STA_PLINK_ACTION, NL80211_ATTR_MPATH_NEXT_HOP, NL80211_ATTR_MPATH_INFO, + /* add attributes here, update the policy in nl80211.c */ + __NL80211_ATTR_AFTER_LAST, NL80211_ATTR_MAX = __NL80211_ATTR_AFTER_LAST - 1 }; -#define NL80211_MAX_SUPP_RATES 32 +#define NL80211_MAX_SUPP_RATES 32 +#define NL80211_TKIP_DATA_OFFSET_ENCR_KEY 0 +#define NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY 16 +#define NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY 24 /** * enum nl80211_iftype - (virtual) interface types diff --git a/include/linux/notifier.h b/include/linux/notifier.h index 0ff6224d172a..bd3d72ddf333 100644 --- a/include/linux/notifier.h +++ b/include/linux/notifier.h @@ -197,6 +197,7 @@ static inline int notifier_to_errno(int ret) #define NETDEV_GOING_DOWN 0x0009 #define NETDEV_CHANGENAME 0x000A #define NETDEV_FEAT_CHANGE 0x000B +#define NETDEV_BONDING_FAILOVER 0x000C #define SYS_DOWN 0x0001 /* Notify of system down */ #define SYS_RESTART SYS_DOWN diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h index 6be6a7943d8b..d8507eb394cf 100644 --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h @@ -1950,6 +1950,8 @@ #define PCI_DEVICE_ID_NX2_5708 0x164c #define PCI_DEVICE_ID_TIGON3_5702FE 0x164d #define PCI_DEVICE_ID_NX2_57710 0x164e +#define PCI_DEVICE_ID_NX2_57711 0x164f +#define PCI_DEVICE_ID_NX2_57711E 0x1650 #define PCI_DEVICE_ID_TIGON3_5705 0x1653 #define PCI_DEVICE_ID_TIGON3_5705_2 0x1654 #define PCI_DEVICE_ID_TIGON3_5720 0x1658 @@ -1982,6 +1984,7 @@ #define PCI_DEVICE_ID_TIGON3_5787M 0x1693 #define PCI_DEVICE_ID_TIGON3_5782 0x1696 #define PCI_DEVICE_ID_TIGON3_5784 0x1698 +#define PCI_DEVICE_ID_TIGON3_5785 0x1699 #define PCI_DEVICE_ID_TIGON3_5786 0x169a #define PCI_DEVICE_ID_TIGON3_5787 0x169b #define PCI_DEVICE_ID_TIGON3_5788 0x169c diff --git a/include/linux/pkt_cls.h b/include/linux/pkt_cls.h index 99efbed81fa2..7cf7824df778 100644 --- a/include/linux/pkt_cls.h +++ b/include/linux/pkt_cls.h @@ -374,6 +374,7 @@ enum TCA_FLOW_ACT, TCA_FLOW_POLICE, TCA_FLOW_EMATCHES, + TCA_FLOW_PERTURB, __TCA_FLOW_MAX }; diff --git a/include/linux/pkt_sched.h b/include/linux/pkt_sched.h index dbb7ac37960d..e5de421ac7b4 100644 --- a/include/linux/pkt_sched.h +++ b/include/linux/pkt_sched.h @@ -85,6 +85,26 @@ struct tc_ratespec #define TC_RTAB_SIZE 1024 +struct tc_sizespec { + unsigned char cell_log; + unsigned char size_log; + short cell_align; + int overhead; + unsigned int linklayer; + unsigned int mpu; + unsigned int mtu; + unsigned int tsize; +}; + +enum { + TCA_STAB_UNSPEC, + TCA_STAB_BASE, + TCA_STAB_DATA, + __TCA_STAB_MAX +}; + +#define TCA_STAB_MAX (__TCA_STAB_MAX - 1) + /* FIFO section */ struct tc_fifo_qopt @@ -103,15 +123,6 @@ struct tc_prio_qopt __u8 priomap[TC_PRIO_MAX+1]; /* Map: logical priority -> PRIO band */ }; -enum -{ - TCA_PRIO_UNSPEC, - TCA_PRIO_MQ, - __TCA_PRIO_MAX -}; - -#define TCA_PRIO_MAX (__TCA_PRIO_MAX - 1) - /* TBF section */ struct tc_tbf_qopt diff --git a/include/linux/ppp-comp.h b/include/linux/ppp-comp.h index e86a7a5cf355..b8d4ddd22736 100644 --- a/include/linux/ppp-comp.h +++ b/include/linux/ppp-comp.h @@ -23,8 +23,6 @@ * ON AN "AS IS" BASIS, AND THE AUSTRALIAN NATIONAL UNIVERSITY HAS NO * OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, * OR MODIFICATIONS. - * - * $Id: ppp-comp.h,v 1.6 1997/11/27 06:04:44 paulus Exp $ */ /* diff --git a/include/linux/ppp_defs.h b/include/linux/ppp_defs.h index c6b13ff85028..6e8adc77522c 100644 --- a/include/linux/ppp_defs.h +++ b/include/linux/ppp_defs.h @@ -1,5 +1,3 @@ -/* $Id: ppp_defs.h,v 1.2 1994/09/21 01:31:06 paulus Exp $ */ - /* * ppp_defs.h - PPP definitions. * diff --git a/include/linux/rfkill.h b/include/linux/rfkill.h index e3ab21d7fc7f..c5f6e54ec6ae 100644 --- a/include/linux/rfkill.h +++ b/include/linux/rfkill.h @@ -34,26 +34,37 @@ * 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. */ enum rfkill_type { RFKILL_TYPE_WLAN , RFKILL_TYPE_BLUETOOTH, RFKILL_TYPE_UWB, RFKILL_TYPE_WIMAX, + RFKILL_TYPE_WWAN, RFKILL_TYPE_MAX, }; enum rfkill_state { - RFKILL_STATE_OFF = 0, - RFKILL_STATE_ON = 1, + RFKILL_STATE_SOFT_BLOCKED = 0, /* Radio output blocked */ + RFKILL_STATE_UNBLOCKED = 1, /* Radio output allowed */ + RFKILL_STATE_HARD_BLOCKED = 2, /* Output blocked, non-overrideable */ }; +/* + * 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. * @type: Radio type which the button controls, the value stored * here should be a value from enum rfkill_type. - * @state: State of the switch (on/off). + * @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. @@ -61,6 +72,12 @@ enum rfkill_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 @@ -80,6 +97,7 @@ struct rfkill { void *data; int (*toggle_radio)(void *data, enum rfkill_state state); + int (*get_state)(void *data, enum rfkill_state *state); #ifdef CONFIG_RFKILL_LEDS struct led_trigger led_trigger; @@ -95,6 +113,21 @@ void rfkill_free(struct rfkill *rfkill); int rfkill_register(struct rfkill *rfkill); void rfkill_unregister(struct rfkill *rfkill); +int rfkill_force_state(struct rfkill *rfkill, enum rfkill_state state); + +/** + * rfkill_state_complement - return complementar state + * @state: state to return the complement of + * + * Returns RFKILL_STATE_SOFT_BLOCKED if @state is RFKILL_STATE_UNBLOCKED, + * returns RFKILL_STATE_UNBLOCKED otherwise. + */ +static inline enum rfkill_state rfkill_state_complement(enum rfkill_state state) +{ + return (state == RFKILL_STATE_UNBLOCKED) ? + RFKILL_STATE_SOFT_BLOCKED : RFKILL_STATE_UNBLOCKED; +} + /** * rfkill_get_led_name - Get the LED trigger name for the button's LED. * This function might return a NULL pointer if registering of the @@ -110,4 +143,11 @@ static inline char *rfkill_get_led_name(struct rfkill *rfkill) #endif } +/* rfkill notification chain */ +#define RFKILL_STATE_CHANGED 0x0001 /* state of a normal rfkill + switch has changed */ + +int register_rfkill_notifier(struct notifier_block *nb); +int unregister_rfkill_notifier(struct notifier_block *nb); + #endif /* RFKILL_H */ diff --git a/include/linux/rtnetlink.h b/include/linux/rtnetlink.h index b358c704d102..f4d386c191f5 100644 --- a/include/linux/rtnetlink.h +++ b/include/linux/rtnetlink.h @@ -482,6 +482,7 @@ enum TCA_RATE, TCA_FCNT, TCA_STATS2, + TCA_STAB, __TCA_MAX }; diff --git a/include/linux/seq_file_net.h b/include/linux/seq_file_net.h index 4ac52542a563..32c89bbe24a2 100644 --- a/include/linux/seq_file_net.h +++ b/include/linux/seq_file_net.h @@ -14,7 +14,10 @@ struct seq_net_private { int seq_open_net(struct inode *, struct file *, const struct seq_operations *, int); +int single_open_net(struct inode *, struct file *file, + int (*show)(struct seq_file *, void *)); int seq_release_net(struct inode *, struct file *); +int single_release_net(struct inode *, struct file *); static inline struct net *seq_file_net(struct seq_file *seq) { #ifdef CONFIG_NET_NS diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h index d8f31de632c5..f3a1c0e45021 100644 --- a/include/linux/serial_core.h +++ b/include/linux/serial_core.h @@ -190,6 +190,7 @@ struct uart_ops { void (*break_ctl)(struct uart_port *, int ctl); int (*startup)(struct uart_port *); void (*shutdown)(struct uart_port *); + void (*flush_buffer)(struct uart_port *); void (*set_termios)(struct uart_port *, struct ktermios *new, struct ktermios *old); void (*set_ldisc)(struct uart_port *); @@ -343,13 +344,15 @@ typedef unsigned int __bitwise__ uif_t; * stuff here. */ struct uart_info { - struct tty_struct *tty; + struct tty_port port; struct circ_buf xmit; uif_t flags; /* * Definitions for info->flags. These are _private_ to serial_core, and * are specific to this structure. They may be queried by low level drivers. + * + * FIXME: use the ASY_ definitions */ #define UIF_CHECK_CD ((__force uif_t) (1 << 25)) #define UIF_CTS_FLOW ((__force uif_t) (1 << 26)) @@ -357,11 +360,7 @@ struct uart_info { #define UIF_INITIALIZED ((__force uif_t) (1 << 31)) #define UIF_SUSPENDED ((__force uif_t) (1 << 30)) - int blocked_open; - struct tasklet_struct tlet; - - wait_queue_head_t open_wait; wait_queue_head_t delta_msr_wait; }; @@ -438,8 +437,8 @@ int uart_resume_port(struct uart_driver *reg, struct uart_port *port); #define uart_circ_chars_free(circ) \ (CIRC_SPACE((circ)->head, (circ)->tail, UART_XMIT_SIZE)) -#define uart_tx_stopped(port) \ - ((port)->info->tty->stopped || (port)->info->tty->hw_stopped) +#define uart_tx_stopped(portp) \ + ((portp)->info->port.tty->stopped || (portp)->info->port.tty->hw_stopped) /* * The following are helper functions for the low level drivers. @@ -450,7 +449,7 @@ uart_handle_sysrq_char(struct uart_port *port, unsigned int ch) #ifdef SUPPORT_SYSRQ if (port->sysrq) { if (ch && time_before(jiffies, port->sysrq)) { - handle_sysrq(ch, port->info ? port->info->tty : NULL); + handle_sysrq(ch, port->info ? port->info->port.tty : NULL); port->sysrq = 0; return 1; } @@ -479,7 +478,7 @@ static inline int uart_handle_break(struct uart_port *port) } #endif if (port->flags & UPF_SAK) - do_SAK(info->tty); + do_SAK(info->port.tty); return 0; } @@ -502,9 +501,9 @@ uart_handle_dcd_change(struct uart_port *port, unsigned int status) if (info->flags & UIF_CHECK_CD) { if (status) - wake_up_interruptible(&info->open_wait); - else if (info->tty) - tty_hangup(info->tty); + wake_up_interruptible(&info->port.open_wait); + else if (info->port.tty) + tty_hangup(info->port.tty); } } @@ -517,7 +516,7 @@ static inline void uart_handle_cts_change(struct uart_port *port, unsigned int status) { struct uart_info *info = port->info; - struct tty_struct *tty = info->tty; + struct tty_struct *tty = info->port.tty; port->icount.cts++; @@ -543,7 +542,7 @@ static inline void uart_insert_char(struct uart_port *port, unsigned int status, unsigned int overrun, unsigned int ch, unsigned int flag) { - struct tty_struct *tty = port->info->tty; + struct tty_struct *tty = port->info->port.tty; if ((status & port->ignore_status_mask & ~overrun) == 0) tty_insert_flip_char(tty, ch, flag); diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index 299ec4b31412..7ea44f6621f2 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -246,6 +246,7 @@ typedef unsigned char *sk_buff_data_t; * @dma_cookie: a cookie to one of several possible DMA operations * done by skb DMA functions * @secmark: security marking + * @vlan_tci: vlan tag control information */ struct sk_buff { @@ -305,9 +306,7 @@ struct sk_buff { #endif int iif; -#ifdef CONFIG_NETDEVICES_MULTIQUEUE __u16 queue_mapping; -#endif #ifdef CONFIG_NET_SCHED __u16 tc_index; /* traffic control index */ #ifdef CONFIG_NET_CLS_ACT @@ -328,6 +327,8 @@ struct sk_buff { __u32 mark; + __u16 vlan_tci; + sk_buff_data_t transport_header; sk_buff_data_t network_header; sk_buff_data_t mac_header; @@ -1671,25 +1672,17 @@ static inline void skb_init_secmark(struct sk_buff *skb) static inline void skb_set_queue_mapping(struct sk_buff *skb, u16 queue_mapping) { -#ifdef CONFIG_NETDEVICES_MULTIQUEUE skb->queue_mapping = queue_mapping; -#endif } static inline u16 skb_get_queue_mapping(struct sk_buff *skb) { -#ifdef CONFIG_NETDEVICES_MULTIQUEUE return skb->queue_mapping; -#else - return 0; -#endif } static inline void skb_copy_queue_mapping(struct sk_buff *to, const struct sk_buff *from) { -#ifdef CONFIG_NETDEVICES_MULTIQUEUE to->queue_mapping = from->queue_mapping; -#endif } static inline int skb_is_gso(const struct sk_buff *skb) @@ -1702,6 +1695,20 @@ static inline int skb_is_gso_v6(const struct sk_buff *skb) return skb_shinfo(skb)->gso_type & SKB_GSO_TCPV6; } +extern void __skb_warn_lro_forwarding(const struct sk_buff *skb); + +static inline bool skb_warn_if_lro(const struct sk_buff *skb) +{ + /* LRO sets gso_size but not gso_type, whereas if GSO is really + * wanted then gso_type will be set. */ + struct skb_shared_info *shinfo = skb_shinfo(skb); + if (shinfo->gso_size != 0 && unlikely(shinfo->gso_type == 0)) { + __skb_warn_lro_forwarding(skb); + return true; + } + return false; +} + static inline void skb_forward_csum(struct sk_buff *skb) { /* Unfortunately we don't support this one. Any brave souls? */ diff --git a/include/linux/smc911x.h b/include/linux/smc911x.h new file mode 100644 index 000000000000..b58f54c24183 --- /dev/null +++ b/include/linux/smc911x.h @@ -0,0 +1,12 @@ +#ifndef __SMC911X_H__ +#define __SMC911X_H__ + +#define SMC911X_USE_16BIT (1 << 0) +#define SMC911X_USE_32BIT (1 << 1) + +struct smc911x_platdata { + unsigned long flags; + unsigned long irq_flags; /* IRQF_... */ +}; + +#endif /* __SMC911X_H__ */ diff --git a/include/linux/socket.h b/include/linux/socket.h index bd2b30a74e76..950af631e7fb 100644 --- a/include/linux/socket.h +++ b/include/linux/socket.h @@ -306,10 +306,10 @@ extern int csum_partial_copy_fromiovecend(unsigned char *kdata, int offset, unsigned int len, __wsum *csump); -extern int verify_iovec(struct msghdr *m, struct iovec *iov, char *address, int mode); +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 move_addr_to_user(void *kaddr, int klen, void __user *uaddr, int __user *ulen); -extern int move_addr_to_kernel(void __user *uaddr, int ulen, void *kaddr); +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); #endif diff --git a/include/linux/sonet.h b/include/linux/sonet.h index 753680296e17..67ad11fcf88b 100644 --- a/include/linux/sonet.h +++ b/include/linux/sonet.h @@ -34,7 +34,7 @@ struct sonet_stats { /* clear error insertion */ #define SONET_GETDIAG _IOR('a',ATMIOC_PHYTYP+4,int) /* query error insertion */ -#define SONET_SETFRAMING _IO('a',ATMIOC_PHYTYP+5) +#define SONET_SETFRAMING _IOW('a',ATMIOC_PHYTYP+5,int) /* set framing mode (SONET/SDH) */ #define SONET_GETFRAMING _IOR('a',ATMIOC_PHYTYP+6,int) /* get framing mode */ diff --git a/include/linux/ssb/ssb.h b/include/linux/ssb/ssb.h index 50dfd0dc4093..4bf8cade9dbc 100644 --- a/include/linux/ssb/ssb.h +++ b/include/linux/ssb/ssb.h @@ -7,6 +7,7 @@ #include <linux/spinlock.h> #include <linux/pci.h> #include <linux/mod_devicetable.h> +#include <linux/dma-mapping.h> #include <linux/ssb/ssb_regs.h> @@ -137,9 +138,6 @@ struct ssb_device { const struct ssb_bus_ops *ops; struct device *dev; - /* Pointer to the device that has to be used for - * any DMA related operation. */ - struct device *dma_dev; struct ssb_bus *bus; struct ssb_device_id id; @@ -399,13 +397,151 @@ static inline void ssb_block_write(struct ssb_device *dev, const void *buffer, #endif /* CONFIG_SSB_BLOCKIO */ +/* The SSB DMA API. Use this API for any DMA operation on the device. + * This API basically is a wrapper that calls the correct DMA API for + * the host device type the SSB device is attached to. */ + /* Translation (routing) bits that need to be ORed to DMA * addresses before they are given to a device. */ extern u32 ssb_dma_translation(struct ssb_device *dev); #define SSB_DMA_TRANSLATION_MASK 0xC0000000 #define SSB_DMA_TRANSLATION_SHIFT 30 -extern int ssb_dma_set_mask(struct ssb_device *ssb_dev, u64 mask); +extern int ssb_dma_set_mask(struct ssb_device *dev, u64 mask); + +extern void * ssb_dma_alloc_consistent(struct ssb_device *dev, size_t size, + dma_addr_t *dma_handle, gfp_t gfp_flags); +extern void ssb_dma_free_consistent(struct ssb_device *dev, size_t size, + void *vaddr, dma_addr_t dma_handle, + gfp_t gfp_flags); + +static inline void __cold __ssb_dma_not_implemented(struct ssb_device *dev) +{ +#ifdef CONFIG_SSB_DEBUG + printk(KERN_ERR "SSB: BUG! Calling DMA API for " + "unsupported bustype %d\n", dev->bus->bustype); +#endif /* DEBUG */ +} + +static inline int ssb_dma_mapping_error(struct ssb_device *dev, dma_addr_t addr) +{ + switch (dev->bus->bustype) { + case SSB_BUSTYPE_PCI: + return pci_dma_mapping_error(addr); + case SSB_BUSTYPE_SSB: + return dma_mapping_error(addr); + default: + __ssb_dma_not_implemented(dev); + } + return -ENOSYS; +} + +static inline dma_addr_t ssb_dma_map_single(struct ssb_device *dev, void *p, + size_t size, enum dma_data_direction dir) +{ + switch (dev->bus->bustype) { + case SSB_BUSTYPE_PCI: + return pci_map_single(dev->bus->host_pci, p, size, dir); + case SSB_BUSTYPE_SSB: + return dma_map_single(dev->dev, p, size, dir); + default: + __ssb_dma_not_implemented(dev); + } + return 0; +} + +static inline void ssb_dma_unmap_single(struct ssb_device *dev, dma_addr_t dma_addr, + size_t size, enum dma_data_direction dir) +{ + switch (dev->bus->bustype) { + case SSB_BUSTYPE_PCI: + pci_unmap_single(dev->bus->host_pci, dma_addr, size, dir); + return; + case SSB_BUSTYPE_SSB: + dma_unmap_single(dev->dev, dma_addr, size, dir); + return; + default: + __ssb_dma_not_implemented(dev); + } +} + +static inline void ssb_dma_sync_single_for_cpu(struct ssb_device *dev, + dma_addr_t dma_addr, + size_t size, + enum dma_data_direction dir) +{ + switch (dev->bus->bustype) { + case SSB_BUSTYPE_PCI: + pci_dma_sync_single_for_cpu(dev->bus->host_pci, dma_addr, + size, dir); + return; + case SSB_BUSTYPE_SSB: + dma_sync_single_for_cpu(dev->dev, dma_addr, size, dir); + return; + default: + __ssb_dma_not_implemented(dev); + } +} + +static inline void ssb_dma_sync_single_for_device(struct ssb_device *dev, + dma_addr_t dma_addr, + size_t size, + enum dma_data_direction dir) +{ + switch (dev->bus->bustype) { + case SSB_BUSTYPE_PCI: + pci_dma_sync_single_for_device(dev->bus->host_pci, dma_addr, + size, dir); + return; + case SSB_BUSTYPE_SSB: + dma_sync_single_for_device(dev->dev, dma_addr, size, dir); + return; + default: + __ssb_dma_not_implemented(dev); + } +} + +static inline void ssb_dma_sync_single_range_for_cpu(struct ssb_device *dev, + dma_addr_t dma_addr, + unsigned long offset, + size_t size, + enum dma_data_direction dir) +{ + switch (dev->bus->bustype) { + case SSB_BUSTYPE_PCI: + /* Just sync everything. That's all the PCI API can do. */ + pci_dma_sync_single_for_cpu(dev->bus->host_pci, dma_addr, + offset + size, dir); + return; + case SSB_BUSTYPE_SSB: + dma_sync_single_range_for_cpu(dev->dev, dma_addr, offset, + size, dir); + return; + default: + __ssb_dma_not_implemented(dev); + } +} + +static inline void ssb_dma_sync_single_range_for_device(struct ssb_device *dev, + dma_addr_t dma_addr, + unsigned long offset, + size_t size, + enum dma_data_direction dir) +{ + switch (dev->bus->bustype) { + case SSB_BUSTYPE_PCI: + /* Just sync everything. That's all the PCI API can do. */ + pci_dma_sync_single_for_device(dev->bus->host_pci, dma_addr, + offset + size, dir); + return; + case SSB_BUSTYPE_SSB: + dma_sync_single_range_for_device(dev->dev, dma_addr, offset, + size, dir); + return; + default: + __ssb_dma_not_implemented(dev); + } +} #ifdef CONFIG_SSB_PCIHOST diff --git a/include/linux/stallion.h b/include/linux/stallion.h index 0424d75a5aaa..336af33c6ea4 100644 --- a/include/linux/stallion.h +++ b/include/linux/stallion.h @@ -69,6 +69,7 @@ struct stlrq { */ struct stlport { unsigned long magic; + struct tty_port port; unsigned int portnr; unsigned int panelnr; unsigned int brdnr; @@ -76,12 +77,10 @@ struct stlport { int uartaddr; unsigned int pagenr; unsigned long istate; - int flags; int baud_base; int custom_divisor; int close_delay; int closing_wait; - int refcount; int openwaitcnt; int brklen; unsigned int sigs; @@ -92,9 +91,6 @@ struct stlport { unsigned long clk; unsigned long hwid; void *uartp; - struct tty_struct *tty; - wait_queue_head_t open_wait; - wait_queue_head_t close_wait; comstats_t stats; struct stlrq tx; }; diff --git a/include/linux/sunrpc/auth_gss.h b/include/linux/sunrpc/auth_gss.h index fec6899bf355..d48d4e605f74 100644 --- a/include/linux/sunrpc/auth_gss.h +++ b/include/linux/sunrpc/auth_gss.h @@ -7,8 +7,6 @@ * Andy Adamson <andros@umich.edu> * Bruce Fields <bfields@umich.edu> * Copyright (c) 2000 The Regents of the University of Michigan - * - * $Id$ */ #ifndef _LINUX_SUNRPC_AUTH_GSS_H diff --git a/include/linux/sunrpc/gss_api.h b/include/linux/sunrpc/gss_api.h index 459c5fc11d51..03f33330ece2 100644 --- a/include/linux/sunrpc/gss_api.h +++ b/include/linux/sunrpc/gss_api.h @@ -7,8 +7,6 @@ * Andy Adamson <andros@umich.edu> * Bruce Fields <bfields@umich.edu> * Copyright (c) 2000 The Regents of the University of Michigan - * - * $Id$ */ #ifndef _LINUX_SUNRPC_GSS_API_H diff --git a/include/linux/sunrpc/gss_krb5.h b/include/linux/sunrpc/gss_krb5.h index a10f1fb0bf7c..e7bbdba474d5 100644 --- a/include/linux/sunrpc/gss_krb5.h +++ b/include/linux/sunrpc/gss_krb5.h @@ -51,6 +51,9 @@ struct krb5_ctx { extern spinlock_t krb5_seq_lock; +/* The length of the Kerberos GSS token header */ +#define GSS_KRB5_TOK_HDR_LEN (16) + #define KG_TOK_MIC_MSG 0x0101 #define KG_TOK_WRAP_MSG 0x0201 diff --git a/include/linux/sunrpc/svc.h b/include/linux/sunrpc/svc.h index 4b54c5fdcfd9..dc69068d94c7 100644 --- a/include/linux/sunrpc/svc.h +++ b/include/linux/sunrpc/svc.h @@ -22,7 +22,7 @@ /* * This is the RPC server thread function prototype */ -typedef void (*svc_thread_fn)(struct svc_rqst *); +typedef int (*svc_thread_fn)(void *); /* * @@ -80,7 +80,6 @@ struct svc_serv { struct module * sv_module; /* optional module to count when * adding threads */ svc_thread_fn sv_function; /* main function for threads */ - int sv_kill_signal; /* signal to kill threads */ }; /* @@ -388,8 +387,8 @@ struct svc_rqst *svc_prepare_thread(struct svc_serv *serv, struct svc_pool *pool); void svc_exit_thread(struct svc_rqst *); struct svc_serv * svc_create_pooled(struct svc_program *, unsigned int, - void (*shutdown)(struct svc_serv*), - svc_thread_fn, int sig, struct module *); + void (*shutdown)(struct svc_serv*), svc_thread_fn, + struct module *); int svc_set_num_threads(struct svc_serv *, struct svc_pool *, int); void svc_destroy(struct svc_serv *); int svc_process(struct svc_rqst *); diff --git a/include/linux/sunrpc/svc_rdma.h b/include/linux/sunrpc/svc_rdma.h index 05eb4664d0dd..ef2e3a20bf3b 100644 --- a/include/linux/sunrpc/svc_rdma.h +++ b/include/linux/sunrpc/svc_rdma.h @@ -72,7 +72,7 @@ extern atomic_t rdma_stat_sq_prod; */ struct svc_rdma_op_ctxt { struct svc_rdma_op_ctxt *read_hdr; - struct list_head free_list; + int hdr_count; struct xdr_buf arg; struct list_head dto_q; enum ib_wr_opcode wr_op; @@ -86,6 +86,31 @@ struct svc_rdma_op_ctxt { struct page *pages[RPCSVC_MAXPAGES]; }; +/* + * NFS_ requests are mapped on the client side by the chunk lists in + * the RPCRDMA header. During the fetching of the RPC from the client + * and the writing of the reply to the client, the memory in the + * client and the memory in the server must be mapped as contiguous + * vaddr/len for access by the hardware. These data strucures keep + * these mappings. + * + * For an RDMA_WRITE, the 'sge' maps the RPC REPLY. For RDMA_READ, the + * 'sge' in the svc_rdma_req_map maps the server side RPC reply and the + * 'ch' field maps the read-list of the RPCRDMA header to the 'sge' + * mapping of the reply. + */ +struct svc_rdma_chunk_sge { + int start; /* sge no for this chunk */ + int count; /* sge count for this chunk */ +}; +struct svc_rdma_req_map { + unsigned long count; + union { + struct kvec sge[RPCSVC_MAXPAGES]; + struct svc_rdma_chunk_sge ch[RPCSVC_MAXPAGES]; + }; +}; + #define RDMACTXT_F_LAST_CTXT 2 struct svcxprt_rdma { @@ -93,7 +118,6 @@ struct svcxprt_rdma { struct rdma_cm_id *sc_cm_id; /* RDMA connection id */ struct list_head sc_accept_q; /* Conn. waiting accept */ int sc_ord; /* RDMA read limit */ - wait_queue_head_t sc_read_wait; int sc_max_sge; int sc_sq_depth; /* Depth of SQ */ @@ -104,12 +128,8 @@ struct svcxprt_rdma { struct ib_pd *sc_pd; + atomic_t sc_dma_used; atomic_t sc_ctxt_used; - struct list_head sc_ctxt_free; - int sc_ctxt_cnt; - int sc_ctxt_bump; - int sc_ctxt_max; - spinlock_t sc_ctxt_lock; struct list_head sc_rq_dto_q; spinlock_t sc_rq_dto_lock; struct ib_qp *sc_qp; @@ -173,6 +193,8 @@ extern int svc_rdma_post_recv(struct svcxprt_rdma *); extern int svc_rdma_create_listen(struct svc_serv *, int, struct sockaddr *); extern struct svc_rdma_op_ctxt *svc_rdma_get_context(struct svcxprt_rdma *); extern void svc_rdma_put_context(struct svc_rdma_op_ctxt *, int); +extern struct svc_rdma_req_map *svc_rdma_get_req_map(void); +extern void svc_rdma_put_req_map(struct svc_rdma_req_map *); extern void svc_sq_reap(struct svcxprt_rdma *); extern void svc_rq_reap(struct svcxprt_rdma *); extern struct svc_xprt_class svc_rdma_class; diff --git a/include/linux/sunrpc/svcauth_gss.h b/include/linux/sunrpc/svcauth_gss.h index 417a1def56db..c9165d9771a8 100644 --- a/include/linux/sunrpc/svcauth_gss.h +++ b/include/linux/sunrpc/svcauth_gss.h @@ -3,9 +3,6 @@ * * Bruce Fields <bfields@umich.edu> * Copyright (c) 2002 The Regents of the Unviersity of Michigan - * - * $Id$ - * */ #ifndef _LINUX_SUNRPC_SVCAUTH_GSS_H diff --git a/include/linux/tcp.h b/include/linux/tcp.h index b31b6b74aa28..2e2557388e36 100644 --- a/include/linux/tcp.h +++ b/include/linux/tcp.h @@ -224,6 +224,12 @@ struct tcp_options_received { u16 mss_clamp; /* Maximal mss, negotiated at connection setup */ }; +/* This is the max number of SACKS that we'll generate and process. It's safe + * to increse this, although since: + * size = TCPOLEN_SACK_BASE_ALIGNED (4) + n * TCPOLEN_SACK_PERBLOCK (8) + * only four options will fit in a standard TCP header */ +#define TCP_NUM_SACKS 4 + struct tcp_request_sock { struct inet_request_sock req; #ifdef CONFIG_TCP_MD5SIG @@ -291,10 +297,9 @@ struct tcp_sock { u32 rcv_ssthresh; /* Current window clamp */ u32 frto_highmark; /* snd_nxt when RTO occurred */ - u8 reordering; /* Packet reordering metric. */ + u16 advmss; /* Advertised MSS */ u8 frto_counter; /* Number of new acks after RTO */ u8 nonagle; /* Disable Nagle algorithm? */ - u8 keepalive_probes; /* num of allowed keep alive probes */ /* RTT measurement */ u32 srtt; /* smoothed round trip time << 3 */ @@ -305,6 +310,10 @@ struct tcp_sock { u32 packets_out; /* Packets which are "in flight" */ u32 retrans_out; /* Retransmitted packets out */ + + u16 urg_data; /* Saved octet of OOB data and control flags */ + u8 urg_mode; /* In urgent mode */ + u8 ecn_flags; /* ECN status bits. */ /* * Options received (usually on last packet, some only on SYN packets). */ @@ -320,13 +329,24 @@ struct tcp_sock { u32 snd_cwnd_used; u32 snd_cwnd_stamp; - struct sk_buff_head out_of_order_queue; /* Out of order segments go here */ - u32 rcv_wnd; /* Current receiver window */ u32 write_seq; /* Tail(+1) of data held in tcp send buffer */ u32 pushed_seq; /* Last pushed seq, required to talk to windows */ + u32 lost_out; /* Lost packets */ + u32 sacked_out; /* SACK'd packets */ + u32 fackets_out; /* FACK'd packets */ + u32 tso_deferred; + u32 bytes_acked; /* Appropriate Byte Counting - RFC3465 */ -/* SACKs data */ + /* from STCP, retrans queue hinting */ + struct sk_buff* lost_skb_hint; + struct sk_buff *scoreboard_skb_hint; + struct sk_buff *retransmit_skb_hint; + struct sk_buff *forward_skb_hint; + + struct sk_buff_head out_of_order_queue; /* Out of order segments go here */ + + /* SACKs data, these 2 need to be together (see tcp_build_and_update_options) */ struct tcp_sack_block duplicate_sack[1]; /* D-SACK block */ struct tcp_sack_block selective_acks[4]; /* The SACKS themselves*/ @@ -337,23 +357,14 @@ struct tcp_sock { * sacked_out > 0) */ - /* from STCP, retrans queue hinting */ - struct sk_buff* lost_skb_hint; - - struct sk_buff *scoreboard_skb_hint; - struct sk_buff *retransmit_skb_hint; - struct sk_buff *forward_skb_hint; - int lost_cnt_hint; int retransmit_cnt_hint; u32 lost_retrans_low; /* Sent seq after any rxmit (lowest) */ - u16 advmss; /* Advertised MSS */ + u8 reordering; /* Packet reordering metric. */ + u8 keepalive_probes; /* num of allowed keep alive probes */ u32 prior_ssthresh; /* ssthresh saved at recovery start */ - u32 lost_out; /* Lost packets */ - u32 sacked_out; /* SACK'd packets */ - u32 fackets_out; /* FACK'd packets */ u32 high_seq; /* snd_nxt at onset of congestion */ u32 retrans_stamp; /* Timestamp of the last retransmit, @@ -361,23 +372,16 @@ struct tcp_sock { * the first SYN. */ u32 undo_marker; /* tracking retrans started here. */ int undo_retrans; /* number of undoable retransmissions. */ + u32 total_retrans; /* Total retransmits for entire connection */ + u32 urg_seq; /* Seq of received urgent pointer */ - u16 urg_data; /* Saved octet of OOB data and control flags */ - u8 urg_mode; /* In urgent mode */ - u8 ecn_flags; /* ECN status bits. */ u32 snd_up; /* Urgent pointer */ - u32 total_retrans; /* Total retransmits for entire connection */ - u32 bytes_acked; /* Appropriate Byte Counting - RFC3465 */ - unsigned int keepalive_time; /* time before keep alive takes place */ unsigned int keepalive_intvl; /* time interval between keep alive probes */ - int linger2; unsigned long last_synq_overflow; - u32 tso_deferred; - /* Receiver side RTT estimation */ struct { u32 rtt; @@ -405,6 +409,8 @@ 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/linux/textsearch.h b/include/linux/textsearch.h index 6f371f24160b..d9a85d616385 100644 --- a/include/linux/textsearch.h +++ b/include/linux/textsearch.h @@ -10,10 +10,8 @@ struct ts_config; -/** - * TS_AUTOLOAD - Automatically load textsearch modules when needed - */ -#define TS_AUTOLOAD 1 +#define TS_AUTOLOAD 1 /* Automatically load textsearch modules when needed */ +#define TS_IGNORECASE 2 /* Searches string case insensitively */ /** * struct ts_state - search state @@ -39,7 +37,7 @@ struct ts_state struct ts_ops { const char *name; - struct ts_config * (*init)(const void *, unsigned int, gfp_t); + struct ts_config * (*init)(const void *, unsigned int, gfp_t, int); unsigned int (*find)(struct ts_config *, struct ts_state *); void (*destroy)(struct ts_config *); @@ -52,12 +50,14 @@ struct ts_ops /** * struct ts_config - search configuration * @ops: operations of chosen algorithm + * @flags: flags * @get_next_block: callback to fetch the next block to search in * @finish: callback to finalize a search */ struct ts_config { struct ts_ops *ops; + int flags; /** * get_next_block - fetch next block of data @@ -162,11 +162,10 @@ static inline struct ts_config *alloc_ts_config(size_t payload, { struct ts_config *conf; - conf = kmalloc(TS_PRIV_ALIGN(sizeof(*conf)) + payload, gfp_mask); + conf = kzalloc(TS_PRIV_ALIGN(sizeof(*conf)) + payload, gfp_mask); if (conf == NULL) return ERR_PTR(-ENOMEM); - memset(conf, 0, TS_PRIV_ALIGN(sizeof(*conf)) + payload); return conf; } diff --git a/include/linux/tipc_config.h b/include/linux/tipc_config.h index b0c916d1f375..2bc6fa4adeb5 100644 --- a/include/linux/tipc_config.h +++ b/include/linux/tipc_config.h @@ -2,7 +2,7 @@ * include/linux/tipc_config.h: Include file for TIPC configuration interface * * Copyright (c) 2003-2006, Ericsson AB - * Copyright (c) 2005, Wind River Systems + * Copyright (c) 2005-2007, Wind River Systems * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -136,6 +136,14 @@ #define TIPC_CMD_SET_NETID 0x800B /* tx unsigned, rx none */ /* + * Reserved commands: + * May not be issued by any process. + * Used internally by TIPC. + */ + +#define TIPC_CMD_NOT_NET_ADMIN 0xC001 /* tx none, rx none */ + +/* * TLV types defined for TIPC */ diff --git a/include/linux/tty.h b/include/linux/tty.h index 324a3b231d40..4e5833073aa6 100644 --- a/include/linux/tty.h +++ b/include/linux/tty.h @@ -71,7 +71,8 @@ struct tty_bufhead { struct tty_buffer *head; /* Queue head */ struct tty_buffer *tail; /* Active buffer */ struct tty_buffer *free; /* Free queue head */ - int memory_used; /* Buffer space used excluding free queue */ + int memory_used; /* Buffer space used excluding + free queue */ }; /* * When a break, frame error, or parity error happens, these codes are @@ -101,71 +102,96 @@ struct tty_bufhead { #define LNEXT_CHAR(tty) ((tty)->termios->c_cc[VLNEXT]) #define EOL2_CHAR(tty) ((tty)->termios->c_cc[VEOL2]) -#define _I_FLAG(tty,f) ((tty)->termios->c_iflag & (f)) -#define _O_FLAG(tty,f) ((tty)->termios->c_oflag & (f)) -#define _C_FLAG(tty,f) ((tty)->termios->c_cflag & (f)) -#define _L_FLAG(tty,f) ((tty)->termios->c_lflag & (f)) - -#define I_IGNBRK(tty) _I_FLAG((tty),IGNBRK) -#define I_BRKINT(tty) _I_FLAG((tty),BRKINT) -#define I_IGNPAR(tty) _I_FLAG((tty),IGNPAR) -#define I_PARMRK(tty) _I_FLAG((tty),PARMRK) -#define I_INPCK(tty) _I_FLAG((tty),INPCK) -#define I_ISTRIP(tty) _I_FLAG((tty),ISTRIP) -#define I_INLCR(tty) _I_FLAG((tty),INLCR) -#define I_IGNCR(tty) _I_FLAG((tty),IGNCR) -#define I_ICRNL(tty) _I_FLAG((tty),ICRNL) -#define I_IUCLC(tty) _I_FLAG((tty),IUCLC) -#define I_IXON(tty) _I_FLAG((tty),IXON) -#define I_IXANY(tty) _I_FLAG((tty),IXANY) -#define I_IXOFF(tty) _I_FLAG((tty),IXOFF) -#define I_IMAXBEL(tty) _I_FLAG((tty),IMAXBEL) -#define I_IUTF8(tty) _I_FLAG((tty),IUTF8) - -#define O_OPOST(tty) _O_FLAG((tty),OPOST) -#define O_OLCUC(tty) _O_FLAG((tty),OLCUC) -#define O_ONLCR(tty) _O_FLAG((tty),ONLCR) -#define O_OCRNL(tty) _O_FLAG((tty),OCRNL) -#define O_ONOCR(tty) _O_FLAG((tty),ONOCR) -#define O_ONLRET(tty) _O_FLAG((tty),ONLRET) -#define O_OFILL(tty) _O_FLAG((tty),OFILL) -#define O_OFDEL(tty) _O_FLAG((tty),OFDEL) -#define O_NLDLY(tty) _O_FLAG((tty),NLDLY) -#define O_CRDLY(tty) _O_FLAG((tty),CRDLY) -#define O_TABDLY(tty) _O_FLAG((tty),TABDLY) -#define O_BSDLY(tty) _O_FLAG((tty),BSDLY) -#define O_VTDLY(tty) _O_FLAG((tty),VTDLY) -#define O_FFDLY(tty) _O_FLAG((tty),FFDLY) - -#define C_BAUD(tty) _C_FLAG((tty),CBAUD) -#define C_CSIZE(tty) _C_FLAG((tty),CSIZE) -#define C_CSTOPB(tty) _C_FLAG((tty),CSTOPB) -#define C_CREAD(tty) _C_FLAG((tty),CREAD) -#define C_PARENB(tty) _C_FLAG((tty),PARENB) -#define C_PARODD(tty) _C_FLAG((tty),PARODD) -#define C_HUPCL(tty) _C_FLAG((tty),HUPCL) -#define C_CLOCAL(tty) _C_FLAG((tty),CLOCAL) -#define C_CIBAUD(tty) _C_FLAG((tty),CIBAUD) -#define C_CRTSCTS(tty) _C_FLAG((tty),CRTSCTS) - -#define L_ISIG(tty) _L_FLAG((tty),ISIG) -#define L_ICANON(tty) _L_FLAG((tty),ICANON) -#define L_XCASE(tty) _L_FLAG((tty),XCASE) -#define L_ECHO(tty) _L_FLAG((tty),ECHO) -#define L_ECHOE(tty) _L_FLAG((tty),ECHOE) -#define L_ECHOK(tty) _L_FLAG((tty),ECHOK) -#define L_ECHONL(tty) _L_FLAG((tty),ECHONL) -#define L_NOFLSH(tty) _L_FLAG((tty),NOFLSH) -#define L_TOSTOP(tty) _L_FLAG((tty),TOSTOP) -#define L_ECHOCTL(tty) _L_FLAG((tty),ECHOCTL) -#define L_ECHOPRT(tty) _L_FLAG((tty),ECHOPRT) -#define L_ECHOKE(tty) _L_FLAG((tty),ECHOKE) -#define L_FLUSHO(tty) _L_FLAG((tty),FLUSHO) -#define L_PENDIN(tty) _L_FLAG((tty),PENDIN) -#define L_IEXTEN(tty) _L_FLAG((tty),IEXTEN) +#define _I_FLAG(tty, f) ((tty)->termios->c_iflag & (f)) +#define _O_FLAG(tty, f) ((tty)->termios->c_oflag & (f)) +#define _C_FLAG(tty, f) ((tty)->termios->c_cflag & (f)) +#define _L_FLAG(tty, f) ((tty)->termios->c_lflag & (f)) + +#define I_IGNBRK(tty) _I_FLAG((tty), IGNBRK) +#define I_BRKINT(tty) _I_FLAG((tty), BRKINT) +#define I_IGNPAR(tty) _I_FLAG((tty), IGNPAR) +#define I_PARMRK(tty) _I_FLAG((tty), PARMRK) +#define I_INPCK(tty) _I_FLAG((tty), INPCK) +#define I_ISTRIP(tty) _I_FLAG((tty), ISTRIP) +#define I_INLCR(tty) _I_FLAG((tty), INLCR) +#define I_IGNCR(tty) _I_FLAG((tty), IGNCR) +#define I_ICRNL(tty) _I_FLAG((tty), ICRNL) +#define I_IUCLC(tty) _I_FLAG((tty), IUCLC) +#define I_IXON(tty) _I_FLAG((tty), IXON) +#define I_IXANY(tty) _I_FLAG((tty), IXANY) +#define I_IXOFF(tty) _I_FLAG((tty), IXOFF) +#define I_IMAXBEL(tty) _I_FLAG((tty), IMAXBEL) +#define I_IUTF8(tty) _I_FLAG((tty), IUTF8) + +#define O_OPOST(tty) _O_FLAG((tty), OPOST) +#define O_OLCUC(tty) _O_FLAG((tty), OLCUC) +#define O_ONLCR(tty) _O_FLAG((tty), ONLCR) +#define O_OCRNL(tty) _O_FLAG((tty), OCRNL) +#define O_ONOCR(tty) _O_FLAG((tty), ONOCR) +#define O_ONLRET(tty) _O_FLAG((tty), ONLRET) +#define O_OFILL(tty) _O_FLAG((tty), OFILL) +#define O_OFDEL(tty) _O_FLAG((tty), OFDEL) +#define O_NLDLY(tty) _O_FLAG((tty), NLDLY) +#define O_CRDLY(tty) _O_FLAG((tty), CRDLY) +#define O_TABDLY(tty) _O_FLAG((tty), TABDLY) +#define O_BSDLY(tty) _O_FLAG((tty), BSDLY) +#define O_VTDLY(tty) _O_FLAG((tty), VTDLY) +#define O_FFDLY(tty) _O_FLAG((tty), FFDLY) + +#define C_BAUD(tty) _C_FLAG((tty), CBAUD) +#define C_CSIZE(tty) _C_FLAG((tty), CSIZE) +#define C_CSTOPB(tty) _C_FLAG((tty), CSTOPB) +#define C_CREAD(tty) _C_FLAG((tty), CREAD) +#define C_PARENB(tty) _C_FLAG((tty), PARENB) +#define C_PARODD(tty) _C_FLAG((tty), PARODD) +#define C_HUPCL(tty) _C_FLAG((tty), HUPCL) +#define C_CLOCAL(tty) _C_FLAG((tty), CLOCAL) +#define C_CIBAUD(tty) _C_FLAG((tty), CIBAUD) +#define C_CRTSCTS(tty) _C_FLAG((tty), CRTSCTS) + +#define L_ISIG(tty) _L_FLAG((tty), ISIG) +#define L_ICANON(tty) _L_FLAG((tty), ICANON) +#define L_XCASE(tty) _L_FLAG((tty), XCASE) +#define L_ECHO(tty) _L_FLAG((tty), ECHO) +#define L_ECHOE(tty) _L_FLAG((tty), ECHOE) +#define L_ECHOK(tty) _L_FLAG((tty), ECHOK) +#define L_ECHONL(tty) _L_FLAG((tty), ECHONL) +#define L_NOFLSH(tty) _L_FLAG((tty), NOFLSH) +#define L_TOSTOP(tty) _L_FLAG((tty), TOSTOP) +#define L_ECHOCTL(tty) _L_FLAG((tty), ECHOCTL) +#define L_ECHOPRT(tty) _L_FLAG((tty), ECHOPRT) +#define L_ECHOKE(tty) _L_FLAG((tty), ECHOKE) +#define L_FLUSHO(tty) _L_FLAG((tty), FLUSHO) +#define L_PENDIN(tty) _L_FLAG((tty), PENDIN) +#define L_IEXTEN(tty) _L_FLAG((tty), IEXTEN) struct device; struct signal_struct; + +/* + * Port level information. Each device keeps its own port level information + * so provide a common structure for those ports wanting to use common support + * routines. + * + * The tty port has a different lifetime to the tty so must be kept apart. + * In addition be careful as tty -> port mappings are valid for the life + * of the tty object but in many cases port -> tty mappings are valid only + * until a hangup so don't use the wrong path. + */ + +struct tty_port { + struct tty_struct *tty; /* Back pointer */ + int blocked_open; /* Waiting to open */ + int count; /* Usage count */ + wait_queue_head_t open_wait; /* Open waiters */ + wait_queue_head_t close_wait; /* Close waiters */ + unsigned long flags; /* TTY flags ASY_*/ + struct mutex mutex; /* Locking */ + unsigned char *xmit_buf; /* Optional buffer */ + int close_delay; /* Close port delay */ + int closing_wait; /* Delay for output */ +}; + /* * Where all of the state associated with a tty is kept while the tty * is open. Since the termios state should be kept even if the tty @@ -185,6 +211,7 @@ struct tty_struct { struct tty_driver *driver; const struct tty_operations *ops; int index; + /* The ldisc objects are protected by tty_ldisc_lock at the moment */ struct tty_ldisc ldisc; struct mutex termios_mutex; spinlock_t ctrl_lock; @@ -213,7 +240,7 @@ struct tty_struct { struct list_head tty_files; #define N_TTY_BUF_SIZE 4096 - + /* * The following is data for the N_TTY line discipline. For * historical reasons, this is included in the tty structure. @@ -241,6 +268,7 @@ struct tty_struct { spinlock_t read_lock; /* If the tty has a pending do_SAK, queue it here - akpm */ struct work_struct SAK_work; + struct tty_port *port; }; /* tty magic number */ @@ -248,14 +276,14 @@ struct tty_struct { /* * These bits are used in the flags field of the tty structure. - * + * * So that interrupts won't be able to mess up the queues, * copy_to_cooked must be atomic with respect to itself, as must * tty->write. Thus, you must use the inline functions set_bit() and * clear_bit() to make things atomic. */ #define TTY_THROTTLED 0 /* Call unthrottle() at threshold min */ -#define TTY_IO_ERROR 1 /* Canse an I/O error (may be no ldisc too) */ +#define TTY_IO_ERROR 1 /* Cause an I/O error (may be no ldisc too) */ #define TTY_OTHER_CLOSED 2 /* Other side (if any) has closed */ #define TTY_EXCLUSIVE 3 /* Exclusive open mode */ #define TTY_DEBUG 4 /* Debugging */ @@ -285,11 +313,11 @@ extern int vcs_init(void); extern int tty_paranoia_check(struct tty_struct *tty, struct inode *inode, const char *routine); extern char *tty_name(struct tty_struct *tty, char *buf); -extern void tty_wait_until_sent(struct tty_struct * tty, long timeout); -extern int tty_check_change(struct tty_struct * tty); -extern void stop_tty(struct tty_struct * tty); -extern void start_tty(struct tty_struct * tty); -extern int tty_register_ldisc(int disc, struct tty_ldisc *new_ldisc); +extern void tty_wait_until_sent(struct tty_struct *tty, long timeout); +extern int tty_check_change(struct tty_struct *tty); +extern void stop_tty(struct tty_struct *tty); +extern void start_tty(struct tty_struct *tty); +extern int tty_register_ldisc(int disc, struct tty_ldisc_ops *new_ldisc); extern int tty_unregister_ldisc(int disc); extern int tty_register_driver(struct tty_driver *driver); extern int tty_unregister_driver(struct tty_driver *driver); @@ -310,10 +338,10 @@ extern int is_current_pgrp_orphaned(void); extern struct pid *tty_get_pgrp(struct tty_struct *tty); extern int is_ignored(int sig); extern int tty_signal(int sig, struct tty_struct *tty); -extern void tty_hangup(struct tty_struct * tty); -extern void tty_vhangup(struct tty_struct * tty); +extern void tty_hangup(struct tty_struct *tty); +extern void tty_vhangup(struct tty_struct *tty); extern void tty_unhangup(struct file *filp); -extern int tty_hung_up_p(struct file * filp); +extern int tty_hung_up_p(struct file *filp); extern void do_SAK(struct tty_struct *tty); extern void __do_SAK(struct tty_struct *tty); extern void disassociate_ctty(int priv); @@ -322,17 +350,17 @@ extern void tty_flip_buffer_push(struct tty_struct *tty); extern speed_t tty_get_baud_rate(struct tty_struct *tty); extern speed_t tty_termios_baud_rate(struct ktermios *termios); extern speed_t tty_termios_input_baud_rate(struct ktermios *termios); -extern void tty_termios_encode_baud_rate(struct ktermios *termios, speed_t ibaud, speed_t obaud); -extern void tty_encode_baud_rate(struct tty_struct *tty, speed_t ibaud, speed_t obaud); +extern void tty_termios_encode_baud_rate(struct ktermios *termios, + speed_t ibaud, speed_t obaud); +extern void tty_encode_baud_rate(struct tty_struct *tty, + speed_t ibaud, speed_t obaud); extern void tty_termios_copy_hw(struct ktermios *new, struct ktermios *old); extern int tty_termios_hw_change(struct ktermios *a, struct ktermios *b); extern struct tty_ldisc *tty_ldisc_ref(struct tty_struct *); extern void tty_ldisc_deref(struct tty_ldisc *); extern struct tty_ldisc *tty_ldisc_ref_wait(struct tty_struct *); - -extern struct tty_ldisc *tty_ldisc_get(int); -extern void tty_ldisc_put(int); +extern const struct file_operations tty_ldiscs_proc_fops; extern void tty_wakeup(struct tty_struct *tty); extern void tty_ldisc_flush(struct tty_struct *tty); @@ -351,10 +379,14 @@ extern void tty_write_unlock(struct tty_struct *tty); extern int tty_write_lock(struct tty_struct *tty, int ndelay); #define tty_is_writelocked(tty) (mutex_is_locked(&tty->atomic_write_lock)) +extern void tty_port_init(struct tty_port *port); +extern int tty_port_alloc_xmit_buf(struct tty_port *port); +extern void tty_port_free_xmit_buf(struct tty_port *port); + /* n_tty.c */ -extern struct tty_ldisc tty_ldisc_N_TTY; +extern struct tty_ldisc_ops tty_ldisc_N_TTY; /* tty_audit.c */ #ifdef CONFIG_AUDIT @@ -363,7 +395,8 @@ extern void tty_audit_add_data(struct tty_struct *tty, unsigned char *data, extern void tty_audit_exit(void); extern void tty_audit_fork(struct signal_struct *sig); extern void tty_audit_push(struct tty_struct *tty); -extern void tty_audit_push_task(struct task_struct *tsk, uid_t loginuid, u32 sessionid); +extern void tty_audit_push_task(struct task_struct *tsk, + uid_t loginuid, u32 sessionid); #else static inline void tty_audit_add_data(struct tty_struct *tty, unsigned char *data, size_t size) @@ -378,19 +411,20 @@ static inline void tty_audit_fork(struct signal_struct *sig) static inline void tty_audit_push(struct tty_struct *tty) { } -static inline void tty_audit_push_task(struct task_struct *tsk, uid_t loginuid, u32 sessionid) +static inline void tty_audit_push_task(struct task_struct *tsk, + uid_t loginuid, u32 sessionid) { } #endif /* tty_ioctl.c */ -extern int n_tty_ioctl(struct tty_struct * tty, struct file * file, +extern int n_tty_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg); /* serial.c */ extern void serial_console_init(void); - + /* pcxx.c */ extern int pcxe_open(struct tty_struct *tty, struct file *filp); @@ -401,7 +435,7 @@ extern void console_print(const char *); /* vt.c */ -extern int vt_ioctl(struct tty_struct *tty, struct file * file, +extern int vt_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg); #endif /* __KERNEL__ */ diff --git a/include/linux/tty_ldisc.h b/include/linux/tty_ldisc.h index 6226504d9108..40f38d896777 100644 --- a/include/linux/tty_ldisc.h +++ b/include/linux/tty_ldisc.h @@ -104,7 +104,7 @@ #include <linux/fs.h> #include <linux/wait.h> -struct tty_ldisc { +struct tty_ldisc_ops { int magic; char *name; int num; @@ -142,6 +142,11 @@ struct tty_ldisc { int refcount; }; +struct tty_ldisc { + struct tty_ldisc_ops *ops; + int refcount; +}; + #define TTY_LDISC_MAGIC 0x5403 #define LDISC_FLAG_DEFINED 0x00000001 diff --git a/include/linux/udp.h b/include/linux/udp.h index 581ca2c14c52..0cf5c4c0ec81 100644 --- a/include/linux/udp.h +++ b/include/linux/udp.h @@ -38,6 +38,7 @@ struct udphdr { #ifdef __KERNEL__ #include <net/inet_sock.h> #include <linux/skbuff.h> +#include <net/netns/hash.h> static inline struct udphdr *udp_hdr(const struct sk_buff *skb) { @@ -46,6 +47,11 @@ static inline struct udphdr *udp_hdr(const struct sk_buff *skb) #define UDP_HTABLE_SIZE 128 +static inline int udp_hashfn(struct net *net, const unsigned num) +{ + return (num + net_hash_mix(net)) & (UDP_HTABLE_SIZE - 1); +} + struct udp_sock { /* inet_sock has to be the first member */ struct inet_sock inet; diff --git a/include/linux/usb/rndis_host.h b/include/linux/usb/rndis_host.h index 29d6458ecb8d..0a6e6d4b929a 100644 --- a/include/linux/usb/rndis_host.h +++ b/include/linux/usb/rndis_host.h @@ -260,7 +260,8 @@ struct rndis_keepalive_c { /* IN (optionally OUT) */ extern void rndis_status(struct usbnet *dev, struct urb *urb); -extern int rndis_command(struct usbnet *dev, struct rndis_msg_hdr *buf); +extern int +rndis_command(struct usbnet *dev, struct rndis_msg_hdr *buf, int buflen); extern int generic_rndis_bind(struct usbnet *dev, struct usb_interface *intf, int flags); extern void rndis_unbind(struct usbnet *dev, struct usb_interface *intf); diff --git a/include/linux/videodev2.h b/include/linux/videodev2.h index 4a535ea1e123..2e66a95e8d32 100644 --- a/include/linux/videodev2.h +++ b/include/linux/videodev2.h @@ -246,6 +246,7 @@ struct v4l2_capability #define V4L2_CAP_SLICED_VBI_OUTPUT 0x00000080 /* Is a sliced VBI output device */ #define V4L2_CAP_RDS_CAPTURE 0x00000100 /* RDS data capture */ #define V4L2_CAP_VIDEO_OUTPUT_OVERLAY 0x00000200 /* Can do video output overlay */ +#define V4L2_CAP_HW_FREQ_SEEK 0x00000400 /* Can do hardware frequency seek */ #define V4L2_CAP_TUNER 0x00010000 /* has a tuner */ #define V4L2_CAP_AUDIO 0x00020000 /* has audio support */ @@ -309,6 +310,7 @@ struct v4l2_pix_format /* see http://www.siliconimaging.com/RGB%20Bayer.htm */ #define V4L2_PIX_FMT_SBGGR8 v4l2_fourcc('B','A','8','1') /* 8 BGBG.. GRGR.. */ +#define V4L2_PIX_FMT_SGBRG8 v4l2_fourcc('G','B','R','G') /* 8 GBGB.. RGRG.. */ #define V4L2_PIX_FMT_SBGGR16 v4l2_fourcc('B','Y','R','2') /* 16 BGBG.. GRGR.. */ /* compressed formats */ @@ -323,6 +325,9 @@ struct v4l2_pix_format #define V4L2_PIX_FMT_PWC1 v4l2_fourcc('P','W','C','1') /* pwc older webcam */ #define V4L2_PIX_FMT_PWC2 v4l2_fourcc('P','W','C','2') /* pwc newer webcam */ #define V4L2_PIX_FMT_ET61X251 v4l2_fourcc('E','6','2','5') /* ET61X251 compression */ +#define V4L2_PIX_FMT_SPCA501 v4l2_fourcc('S','5','0','1') /* YUYV per line */ +#define V4L2_PIX_FMT_SPCA561 v4l2_fourcc('S','5','6','1') /* compressed GBRG bayer */ +#define V4L2_PIX_FMT_PAC207 v4l2_fourcc('P','2','0','7') /* compressed BGGR bayer */ /* * F O R M A T E N U M E R A T I O N @@ -1156,6 +1161,14 @@ struct v4l2_frequency __u32 reserved[8]; }; +struct v4l2_hw_freq_seek { + __u32 tuner; + enum v4l2_tuner_type type; + __u32 seek_upward; + __u32 wrap_around; + __u32 reserved[8]; +}; + /* * A U D I O */ @@ -1441,6 +1454,7 @@ struct v4l2_chip_ident { #define VIDIOC_G_CHIP_IDENT _IOWR ('V', 81, struct v4l2_chip_ident) #endif +#define VIDIOC_S_HW_FREQ_SEEK _IOW ('V', 82, struct v4l2_hw_freq_seek) #ifdef __OLD_VIDIOC_ /* for compatibility, will go away some day */ diff --git a/include/linux/wanrouter.h b/include/linux/wanrouter.h index 3add87465b1f..e0aa39612eba 100644 --- a/include/linux/wanrouter.h +++ b/include/linux/wanrouter.h @@ -522,7 +522,7 @@ extern int wanrouter_proc_init(void); extern void wanrouter_proc_cleanup(void); extern int wanrouter_proc_add(struct wan_device *wandev); extern int wanrouter_proc_delete(struct wan_device *wandev); -extern int wanrouter_ioctl( struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg); +extern long wanrouter_ioctl(struct file *file, unsigned int cmd, unsigned long arg); /* Public Data */ /* list of registered devices */ diff --git a/include/linux/wireless.h b/include/linux/wireless.h index 0a9b5b41ed67..d7958f9b52cb 100644 --- a/include/linux/wireless.h +++ b/include/linux/wireless.h @@ -611,6 +611,7 @@ #define IW_ENCODE_ALG_WEP 1 #define IW_ENCODE_ALG_TKIP 2 #define IW_ENCODE_ALG_CCMP 3 +#define IW_ENCODE_ALG_PMK 4 /* struct iw_encode_ext ->ext_flags */ #define IW_ENCODE_EXT_TX_SEQ_VALID 0x00000001 #define IW_ENCODE_EXT_RX_SEQ_VALID 0x00000002 @@ -630,6 +631,7 @@ #define IW_ENC_CAPA_WPA2 0x00000002 #define IW_ENC_CAPA_CIPHER_TKIP 0x00000004 #define IW_ENC_CAPA_CIPHER_CCMP 0x00000008 +#define IW_ENC_CAPA_4WAY_HANDSHAKE 0x00000010 /* Event capability macros - in (struct iw_range *)->event_capa * Because we have more than 32 possible events, we use an array of @@ -675,6 +677,19 @@ struct iw_point __u16 flags; /* Optional params */ }; +#ifdef __KERNEL__ +#ifdef CONFIG_COMPAT + +#include <linux/compat.h> + +struct compat_iw_point { + compat_caddr_t pointer; + __u16 length; + __u16 flags; +}; +#endif +#endif + /* * A frequency * For numbers lower than 10^9, we encode the number in 'm' and @@ -1098,6 +1113,21 @@ struct iw_event #define IW_EV_POINT_LEN (IW_EV_LCP_LEN + sizeof(struct iw_point) - \ IW_EV_POINT_OFF) +#ifdef __KERNEL__ +#ifdef CONFIG_COMPAT +struct __compat_iw_event { + __u16 len; /* Real length of this stuff */ + __u16 cmd; /* Wireless IOCTL */ + compat_caddr_t pointer; +}; +#define IW_EV_COMPAT_LCP_LEN offsetof(struct __compat_iw_event, pointer) +#define IW_EV_COMPAT_POINT_OFF offsetof(struct compat_iw_point, length) +#define IW_EV_COMPAT_POINT_LEN \ + (IW_EV_COMPAT_LCP_LEN + sizeof(struct compat_iw_point) - \ + IW_EV_COMPAT_POINT_OFF) +#endif +#endif + /* Size of the Event prefix when packed in stream */ #define IW_EV_LCP_PK_LEN (4) /* Size of the various events when packed in stream */ diff --git a/include/media/cx2341x.h b/include/media/cx2341x.h index 5f4608e88476..9ec4d5889ef5 100644 --- a/include/media/cx2341x.h +++ b/include/media/cx2341x.h @@ -27,6 +27,7 @@ enum cx2341x_port { enum cx2341x_cap { CX2341X_CAP_HAS_SLICED_VBI = 1 << 0, + CX2341X_CAP_HAS_TS = 1 << 1, }; struct cx2341x_mpeg_params { @@ -88,13 +89,13 @@ typedef int (*cx2341x_mbox_func)(void *priv, u32 cmd, int in, int out, int cx2341x_update(void *priv, cx2341x_mbox_func func, const struct cx2341x_mpeg_params *old, const struct cx2341x_mpeg_params *new); -int cx2341x_ctrl_query(struct cx2341x_mpeg_params *params, +int cx2341x_ctrl_query(const struct cx2341x_mpeg_params *params, struct v4l2_queryctrl *qctrl); -const char **cx2341x_ctrl_get_menu(u32 id); +const char **cx2341x_ctrl_get_menu(const struct cx2341x_mpeg_params *p, u32 id); int cx2341x_ext_ctrls(struct cx2341x_mpeg_params *params, int busy, struct v4l2_ext_controls *ctrls, unsigned int cmd); void cx2341x_fill_defaults(struct cx2341x_mpeg_params *p); -void cx2341x_log_status(struct cx2341x_mpeg_params *p, const char *prefix); +void cx2341x_log_status(const struct cx2341x_mpeg_params *p, const char *prefix); /* Firmware names */ #define CX2341X_FIRM_ENC_FILENAME "v4l-cx2341x-enc.fw" diff --git a/include/media/ir-kbd-i2c.h b/include/media/ir-kbd-i2c.h index a455f7ce5ee8..00fa57eb9fde 100644 --- a/include/media/ir-kbd-i2c.h +++ b/include/media/ir-kbd-i2c.h @@ -19,7 +19,4 @@ struct IR_i2c { char phys[32]; int (*get_key)(struct IR_i2c*, u32*, u32*); }; - -int get_key_pinnacle_grey(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw); -int get_key_pinnacle_color(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw); #endif diff --git a/include/media/pwc-ioctl.h b/include/media/pwc-ioctl.h index adc1254e887e..0f19779c4634 100644 --- a/include/media/pwc-ioctl.h +++ b/include/media/pwc-ioctl.h @@ -55,8 +55,7 @@ #include <linux/types.h> #include <linux/version.h> - - /* Enumeration of image sizes */ +/* Enumeration of image sizes */ #define PSZ_SQCIF 0x00 #define PSZ_QSIF 0x01 #define PSZ_QCIF 0x02 diff --git a/include/media/saa7146.h b/include/media/saa7146.h index 88b2b5a619aa..2f68f4cd0037 100644 --- a/include/media/saa7146.h +++ b/include/media/saa7146.h @@ -53,7 +53,7 @@ struct saa7146_vv; /* saa7146 page table */ struct saa7146_pgtable { unsigned int size; - u32 *cpu; + __le32 *cpu; dma_addr_t dma; /* used for offsets for u,v planes for planar capture modes */ unsigned long offset; @@ -101,7 +101,7 @@ struct saa7146_extension struct saa7146_dma { dma_addr_t dma_handle; - u32 *cpu_addr; + __le32 *cpu_addr; }; struct saa7146_dev diff --git a/include/media/sh_mobile_ceu.h b/include/media/sh_mobile_ceu.h new file mode 100644 index 000000000000..234a4711d2ec --- /dev/null +++ b/include/media/sh_mobile_ceu.h @@ -0,0 +1,12 @@ +#ifndef __ASM_SH_MOBILE_CEU_H__ +#define __ASM_SH_MOBILE_CEU_H__ + +#include <media/soc_camera.h> + +struct sh_mobile_ceu_info { + unsigned long flags; /* SOCAM_... */ + void (*enable_camera)(void); + void (*disable_camera)(void); +}; + +#endif /* __ASM_SH_MOBILE_CEU_H__ */ diff --git a/include/media/soc_camera.h b/include/media/soc_camera.h index 6a8c8be7a1ae..1de98f150e99 100644 --- a/include/media/soc_camera.h +++ b/include/media/soc_camera.h @@ -13,7 +13,7 @@ #define SOC_CAMERA_H #include <linux/videodev2.h> -#include <media/videobuf-dma-sg.h> +#include <media/videobuf-core.h> struct soc_camera_device { struct list_head list; @@ -48,15 +48,12 @@ struct soc_camera_device { struct soc_camera_file { struct soc_camera_device *icd; struct videobuf_queue vb_vidq; - spinlock_t *lock; }; struct soc_camera_host { struct list_head list; struct device dev; unsigned char nr; /* Host number */ - size_t msize; - struct videobuf_queue_ops *vbq_ops; void *priv; char *drv_name; struct soc_camera_host_ops *ops; @@ -69,13 +66,13 @@ struct soc_camera_host_ops { int (*set_fmt_cap)(struct soc_camera_device *, __u32, struct v4l2_rect *); int (*try_fmt_cap)(struct soc_camera_device *, struct v4l2_format *); + void (*init_videobuf)(struct videobuf_queue *, + struct soc_camera_device *); int (*reqbufs)(struct soc_camera_file *, struct v4l2_requestbuffers *); int (*querycap)(struct soc_camera_host *, struct v4l2_capability *); int (*try_bus_param)(struct soc_camera_device *, __u32); int (*set_bus_param)(struct soc_camera_device *, __u32); unsigned int (*poll)(struct file *, poll_table *); - spinlock_t* (*spinlock_alloc)(struct soc_camera_file *); - void (*spinlock_free)(spinlock_t *); }; struct soc_camera_link { @@ -156,11 +153,12 @@ static inline struct v4l2_queryctrl const *soc_camera_find_qctrl( #define SOCAM_DATAWIDTH_8 (1 << 6) #define SOCAM_DATAWIDTH_9 (1 << 7) #define SOCAM_DATAWIDTH_10 (1 << 8) -#define SOCAM_PCLK_SAMPLE_RISING (1 << 9) -#define SOCAM_PCLK_SAMPLE_FALLING (1 << 10) +#define SOCAM_DATAWIDTH_16 (1 << 9) +#define SOCAM_PCLK_SAMPLE_RISING (1 << 10) +#define SOCAM_PCLK_SAMPLE_FALLING (1 << 11) #define SOCAM_DATAWIDTH_MASK (SOCAM_DATAWIDTH_8 | SOCAM_DATAWIDTH_9 | \ - SOCAM_DATAWIDTH_10) + SOCAM_DATAWIDTH_10 | SOCAM_DATAWIDTH_16) static inline unsigned long soc_camera_bus_param_compatible( unsigned long camera_flags, unsigned long bus_flags) diff --git a/include/media/soc_camera_platform.h b/include/media/soc_camera_platform.h new file mode 100644 index 000000000000..851f18220984 --- /dev/null +++ b/include/media/soc_camera_platform.h @@ -0,0 +1,15 @@ +#ifndef __SOC_CAMERA_H__ +#define __SOC_CAMERA_H__ + +#include <linux/videodev2.h> + +struct soc_camera_platform_info { + int iface; + char *format_name; + unsigned long format_depth; + struct v4l2_pix_format format; + unsigned long bus_param; + int (*set_capture)(struct soc_camera_platform_info *info, int enable); +}; + +#endif /* __SOC_CAMERA_H__ */ diff --git a/include/media/v4l2-dev.h b/include/media/v4l2-dev.h index 859f7a6f6f67..33f379b1ecfe 100644 --- a/include/media/v4l2-dev.h +++ b/include/media/v4l2-dev.h @@ -59,8 +59,8 @@ enum v4l2_priority v4l2_prio_max(struct v4l2_prio_state *global); int v4l2_prio_check(struct v4l2_prio_state *global, enum v4l2_priority *local); /* names for fancy debug output */ -extern char *v4l2_field_names[]; -extern char *v4l2_type_names[]; +extern const char *v4l2_field_names[]; +extern const char *v4l2_type_names[]; /* Compatibility layer interface -- v4l1-compat module */ typedef int (*v4l2_kioctl)(struct inode *inode, struct file *file, @@ -96,6 +96,8 @@ struct video_device int type; /* v4l1 */ int type2; /* v4l2 */ int minor; + /* attribute to diferentiate multiple indexs on one physical device */ + int index; int debug; /* Activates debug level*/ @@ -118,74 +120,76 @@ struct video_device enum v4l2_priority p); /* VIDIOC_ENUM_FMT handlers */ - int (*vidioc_enum_fmt_cap) (struct file *file, void *fh, + int (*vidioc_enum_fmt_vid_cap) (struct file *file, void *fh, struct v4l2_fmtdesc *f); - int (*vidioc_enum_fmt_overlay) (struct file *file, void *fh, + int (*vidioc_enum_fmt_vid_overlay) (struct file *file, void *fh, struct v4l2_fmtdesc *f); - int (*vidioc_enum_fmt_vbi) (struct file *file, void *fh, + int (*vidioc_enum_fmt_vid_out) (struct file *file, void *fh, struct v4l2_fmtdesc *f); - int (*vidioc_enum_fmt_vbi_capture) (struct file *file, void *fh, - struct v4l2_fmtdesc *f); - int (*vidioc_enum_fmt_video_output)(struct file *file, void *fh, - struct v4l2_fmtdesc *f); - int (*vidioc_enum_fmt_output_overlay) (struct file *file, void *fh, - struct v4l2_fmtdesc *f); - int (*vidioc_enum_fmt_vbi_output) (struct file *file, void *fh, +#if 1 + /* deprecated, will be removed in 2.6.28 */ + int (*vidioc_enum_fmt_vbi_cap) (struct file *file, void *fh, struct v4l2_fmtdesc *f); +#endif int (*vidioc_enum_fmt_type_private)(struct file *file, void *fh, struct v4l2_fmtdesc *f); /* VIDIOC_G_FMT handlers */ - int (*vidioc_g_fmt_cap) (struct file *file, void *fh, + int (*vidioc_g_fmt_vid_cap) (struct file *file, void *fh, struct v4l2_format *f); - int (*vidioc_g_fmt_overlay) (struct file *file, void *fh, + int (*vidioc_g_fmt_vid_overlay)(struct file *file, void *fh, struct v4l2_format *f); - int (*vidioc_g_fmt_vbi) (struct file *file, void *fh, + int (*vidioc_g_fmt_vid_out) (struct file *file, void *fh, struct v4l2_format *f); - int (*vidioc_g_fmt_vbi_output) (struct file *file, void *fh, + int (*vidioc_g_fmt_vid_out_overlay)(struct file *file, void *fh, struct v4l2_format *f); - int (*vidioc_g_fmt_vbi_capture)(struct file *file, void *fh, + int (*vidioc_g_fmt_vbi_cap) (struct file *file, void *fh, struct v4l2_format *f); - int (*vidioc_g_fmt_video_output)(struct file *file, void *fh, + int (*vidioc_g_fmt_vbi_out) (struct file *file, void *fh, struct v4l2_format *f); - int (*vidioc_g_fmt_output_overlay) (struct file *file, void *fh, + int (*vidioc_g_fmt_sliced_vbi_cap)(struct file *file, void *fh, + struct v4l2_format *f); + int (*vidioc_g_fmt_sliced_vbi_out)(struct file *file, void *fh, struct v4l2_format *f); int (*vidioc_g_fmt_type_private)(struct file *file, void *fh, struct v4l2_format *f); /* VIDIOC_S_FMT handlers */ - int (*vidioc_s_fmt_cap) (struct file *file, void *fh, + int (*vidioc_s_fmt_vid_cap) (struct file *file, void *fh, struct v4l2_format *f); - - int (*vidioc_s_fmt_overlay) (struct file *file, void *fh, + int (*vidioc_s_fmt_vid_overlay)(struct file *file, void *fh, struct v4l2_format *f); - int (*vidioc_s_fmt_vbi) (struct file *file, void *fh, + int (*vidioc_s_fmt_vid_out) (struct file *file, void *fh, struct v4l2_format *f); - int (*vidioc_s_fmt_vbi_output) (struct file *file, void *fh, + int (*vidioc_s_fmt_vid_out_overlay)(struct file *file, void *fh, struct v4l2_format *f); - int (*vidioc_s_fmt_vbi_capture)(struct file *file, void *fh, + int (*vidioc_s_fmt_vbi_cap) (struct file *file, void *fh, struct v4l2_format *f); - int (*vidioc_s_fmt_video_output)(struct file *file, void *fh, + int (*vidioc_s_fmt_vbi_out) (struct file *file, void *fh, struct v4l2_format *f); - int (*vidioc_s_fmt_output_overlay) (struct file *file, void *fh, + int (*vidioc_s_fmt_sliced_vbi_cap)(struct file *file, void *fh, + struct v4l2_format *f); + int (*vidioc_s_fmt_sliced_vbi_out)(struct file *file, void *fh, struct v4l2_format *f); int (*vidioc_s_fmt_type_private)(struct file *file, void *fh, struct v4l2_format *f); /* VIDIOC_TRY_FMT handlers */ - int (*vidioc_try_fmt_cap) (struct file *file, void *fh, + int (*vidioc_try_fmt_vid_cap) (struct file *file, void *fh, + struct v4l2_format *f); + int (*vidioc_try_fmt_vid_overlay)(struct file *file, void *fh, struct v4l2_format *f); - int (*vidioc_try_fmt_overlay) (struct file *file, void *fh, + int (*vidioc_try_fmt_vid_out) (struct file *file, void *fh, struct v4l2_format *f); - int (*vidioc_try_fmt_vbi) (struct file *file, void *fh, + int (*vidioc_try_fmt_vid_out_overlay)(struct file *file, void *fh, struct v4l2_format *f); - int (*vidioc_try_fmt_vbi_output) (struct file *file, void *fh, + int (*vidioc_try_fmt_vbi_cap) (struct file *file, void *fh, struct v4l2_format *f); - int (*vidioc_try_fmt_vbi_capture)(struct file *file, void *fh, + int (*vidioc_try_fmt_vbi_out) (struct file *file, void *fh, struct v4l2_format *f); - int (*vidioc_try_fmt_video_output)(struct file *file, void *fh, + int (*vidioc_try_fmt_sliced_vbi_cap)(struct file *file, void *fh, struct v4l2_format *f); - int (*vidioc_try_fmt_output_overlay)(struct file *file, void *fh, + int (*vidioc_try_fmt_sliced_vbi_out)(struct file *file, void *fh, struct v4l2_format *f); int (*vidioc_try_fmt_type_private)(struct file *file, void *fh, struct v4l2_format *f); @@ -212,8 +216,9 @@ struct video_device int (*vidioc_streamoff)(struct file *file, void *fh, enum v4l2_buf_type i); /* Standard handling - G_STD and ENUMSTD are handled by videodev.c + ENUMSTD is handled by videodev.c */ + int (*vidioc_g_std) (struct file *file, void *fh, v4l2_std_id *norm); int (*vidioc_s_std) (struct file *file, void *fh, v4l2_std_id *norm); int (*vidioc_querystd) (struct file *file, void *fh, v4l2_std_id *a); @@ -224,7 +229,7 @@ struct video_device int (*vidioc_s_input) (struct file *file, void *fh, unsigned int i); /* Output handling */ - int (*vidioc_enumoutput) (struct file *file, void *fh, + int (*vidioc_enum_output) (struct file *file, void *fh, struct v4l2_output *a); int (*vidioc_g_output) (struct file *file, void *fh, unsigned int *i); int (*vidioc_s_output) (struct file *file, void *fh, unsigned int i); @@ -306,6 +311,8 @@ struct video_device /* Log status ioctl */ int (*vidioc_log_status) (struct file *file, void *fh); + int (*vidioc_s_hw_freq_seek) (struct file *file, void *fh, + struct v4l2_hw_freq_seek *a); /* Debugging ioctls */ #ifdef CONFIG_VIDEO_ADV_DEBUG @@ -342,6 +349,8 @@ void *priv; /* Version 2 functions */ extern int video_register_device(struct video_device *vfd, int type, int nr); +int video_register_device_index(struct video_device *vfd, int type, int nr, + int index); void video_unregister_device(struct video_device *); extern int video_ioctl2(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg); @@ -366,7 +375,7 @@ video_device_create_file(struct video_device *vfd, { int ret = device_create_file(&vfd->class_dev, attr); if (ret < 0) - printk(KERN_WARNING "%s error: %d\n", __FUNCTION__, ret); + printk(KERN_WARNING "%s error: %d\n", __func__, ret); return ret; } static inline void diff --git a/include/media/v4l2-i2c-drv-legacy.h b/include/media/v4l2-i2c-drv-legacy.h index 878562278b67..975ffbf4e2c5 100644 --- a/include/media/v4l2-i2c-drv-legacy.h +++ b/include/media/v4l2-i2c-drv-legacy.h @@ -68,7 +68,6 @@ static int v4l2_i2c_drv_detach_legacy(struct i2c_client *client) if (err) return err; kfree(client); - return 0; } diff --git a/include/media/videobuf-dma-contig.h b/include/media/videobuf-dma-contig.h new file mode 100644 index 000000000000..549386681aab --- /dev/null +++ b/include/media/videobuf-dma-contig.h @@ -0,0 +1,32 @@ +/* + * helper functions for physically contiguous capture buffers + * + * The functions support hardware lacking scatter gather support + * (i.e. the buffers must be linear in physical memory) + * + * Copyright (c) 2008 Magnus Damm + * + * 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 + */ +#ifndef _VIDEOBUF_DMA_CONTIG_H +#define _VIDEOBUF_DMA_CONTIG_H + +#include <linux/dma-mapping.h> +#include <media/videobuf-core.h> + +void videobuf_queue_dma_contig_init(struct videobuf_queue *q, + struct videobuf_queue_ops *ops, + struct device *dev, + spinlock_t *irqlock, + enum v4l2_buf_type type, + enum v4l2_field field, + unsigned int msize, + void *priv); + +dma_addr_t videobuf_to_dma_contig(struct videobuf_buffer *buf); +void videobuf_dma_contig_free(struct videobuf_queue *q, + struct videobuf_buffer *buf); + +#endif /* _VIDEOBUF_DMA_CONTIG_H */ diff --git a/include/media/videobuf-dma-sg.h b/include/media/videobuf-dma-sg.h index be8da269ee33..90edd22d343c 100644 --- a/include/media/videobuf-dma-sg.h +++ b/include/media/videobuf-dma-sg.h @@ -1,7 +1,7 @@ /* * helper functions for SG DMA video4linux capture buffers * - * The functions expect the hardware being able to scatter gatter + * The functions expect the hardware being able to scatter gather * (i.e. the buffers are not linear in physical memory, but fragmented * into PAGE_SIZE chunks). They also assume the driver does not need * to touch the video data. diff --git a/include/media/videobuf-vmalloc.h b/include/media/videobuf-vmalloc.h index aed39460c154..e87222c6a125 100644 --- a/include/media/videobuf-vmalloc.h +++ b/include/media/videobuf-vmalloc.h @@ -1,7 +1,7 @@ /* * helper functions for vmalloc capture buffers * - * The functions expect the hardware being able to scatter gatter + * The functions expect the hardware being able to scatter gather * (i.e. the buffers are not linear in physical memory, but fragmented * into PAGE_SIZE chunks). They also assume the driver does not need * to touch the video data. diff --git a/include/net/addrconf.h b/include/net/addrconf.h index bbd3d583c6e6..06b28142b3ab 100644 --- a/include/net/addrconf.h +++ b/include/net/addrconf.h @@ -121,7 +121,8 @@ static inline int addrconf_finite_timeout(unsigned long timeout) */ extern int ipv6_addr_label_init(void); extern void ipv6_addr_label_rtnl_register(void); -extern u32 ipv6_addr_label(const struct in6_addr *addr, +extern u32 ipv6_addr_label(struct net *net, + const struct in6_addr *addr, int type, int ifindex); /* diff --git a/include/net/bluetooth/bluetooth.h b/include/net/bluetooth/bluetooth.h index 750648df13f4..6f8418bf4241 100644 --- a/include/net/bluetooth/bluetooth.h +++ b/include/net/bluetooth/bluetooth.h @@ -121,6 +121,7 @@ void bt_sock_link(struct bt_sock_list *l, struct sock *s); void bt_sock_unlink(struct bt_sock_list *l, struct sock *s); int bt_sock_recvmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg, size_t len, int flags); uint bt_sock_poll(struct file * file, struct socket *sock, poll_table *wait); +int bt_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg); int bt_sock_wait_state(struct sock *sk, int state, unsigned long timeo); void bt_accept_enqueue(struct sock *parent, struct sock *sk); diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h index a8a9eb6af966..3cc294919312 100644 --- a/include/net/bluetooth/hci.h +++ b/include/net/bluetooth/hci.h @@ -72,8 +72,6 @@ enum { HCI_INQUIRY, HCI_RAW, - - HCI_SECMGR }; /* HCI ioctl defines */ @@ -86,6 +84,7 @@ enum { #define HCIGETDEVINFO _IOR('H', 211, int) #define HCIGETCONNLIST _IOR('H', 212, int) #define HCIGETCONNINFO _IOR('H', 213, int) +#define HCIGETAUTHINFO _IOR('H', 215, int) #define HCISETRAW _IOW('H', 220, int) #define HCISETSCAN _IOW('H', 221, int) @@ -97,8 +96,6 @@ enum { #define HCISETACLMTU _IOW('H', 227, int) #define HCISETSCOMTU _IOW('H', 228, int) -#define HCISETSECMGR _IOW('H', 230, int) - #define HCIINQUIRY _IOR('H', 240, int) /* HCI timeouts */ @@ -137,6 +134,8 @@ enum { #define ESCO_EV4 0x0010 #define ESCO_EV5 0x0020 +#define SCO_ESCO_MASK (ESCO_HV1 | ESCO_HV2 | ESCO_HV3) + /* ACL flags */ #define ACL_CONT 0x01 #define ACL_START 0x02 @@ -178,6 +177,8 @@ enum { #define LMP_SNIFF_SUBR 0x02 +#define LMP_SIMPLE_PAIR 0x08 + /* Connection modes */ #define HCI_CM_ACTIVE 0x0000 #define HCI_CM_HOLD 0x0001 @@ -199,6 +200,14 @@ enum { #define HCI_LM_RELIABLE 0x0010 #define HCI_LM_SECURE 0x0020 +/* Authentication types */ +#define HCI_AT_NO_BONDING 0x00 +#define HCI_AT_NO_BONDING_MITM 0x01 +#define HCI_AT_DEDICATED_BONDING 0x02 +#define HCI_AT_DEDICATED_BONDING_MITM 0x03 +#define HCI_AT_GENERAL_BONDING 0x04 +#define HCI_AT_GENERAL_BONDING_MITM 0x05 + /* ----- HCI Commands ---- */ #define HCI_OP_INQUIRY 0x0401 struct hci_cp_inquiry { @@ -402,6 +411,17 @@ struct hci_rp_write_link_policy { __le16 handle; } __attribute__ ((packed)); +#define HCI_OP_READ_DEF_LINK_POLICY 0x080e +struct hci_rp_read_def_link_policy { + __u8 status; + __le16 policy; +} __attribute__ ((packed)); + +#define HCI_OP_WRITE_DEF_LINK_POLICY 0x080f +struct hci_cp_write_def_link_policy { + __le16 policy; +} __attribute__ ((packed)); + #define HCI_OP_SNIFF_SUBRATE 0x0811 struct hci_cp_sniff_subrate { __le16 handle; @@ -501,6 +521,17 @@ struct hci_cp_host_buffer_size { __le16 sco_max_pkt; } __attribute__ ((packed)); +#define HCI_OP_READ_SSP_MODE 0x0c55 +struct hci_rp_read_ssp_mode { + __u8 status; + __u8 mode; +} __attribute__ ((packed)); + +#define HCI_OP_WRITE_SSP_MODE 0x0c56 +struct hci_cp_write_ssp_mode { + __u8 mode; +} __attribute__ ((packed)); + #define HCI_OP_READ_LOCAL_VERSION 0x1001 struct hci_rp_read_local_version { __u8 status; @@ -696,6 +727,13 @@ struct hci_ev_clock_offset { __le16 clock_offset; } __attribute__ ((packed)); +#define HCI_EV_PKT_TYPE_CHANGE 0x1d +struct hci_ev_pkt_type_change { + __u8 status; + __le16 handle; + __le16 pkt_type; +} __attribute__ ((packed)); + #define HCI_EV_PSCAN_REP_MODE 0x20 struct hci_ev_pscan_rep_mode { bdaddr_t bdaddr; @@ -774,6 +812,23 @@ struct extended_inquiry_info { __u8 data[240]; } __attribute__ ((packed)); +#define HCI_EV_IO_CAPA_REQUEST 0x31 +struct hci_ev_io_capa_request { + bdaddr_t bdaddr; +} __attribute__ ((packed)); + +#define HCI_EV_SIMPLE_PAIR_COMPLETE 0x36 +struct hci_ev_simple_pair_complete { + __u8 status; + bdaddr_t bdaddr; +} __attribute__ ((packed)); + +#define HCI_EV_REMOTE_HOST_FEATURES 0x3d +struct hci_ev_remote_host_features { + bdaddr_t bdaddr; + __u8 features[8]; +} __attribute__ ((packed)); + /* Internal events generated by Bluetooth stack */ #define HCI_EV_STACK_INTERNAL 0xfd struct hci_ev_stack_internal { @@ -951,6 +1006,11 @@ struct hci_conn_info_req { struct hci_conn_info conn_info[0]; }; +struct hci_auth_info_req { + bdaddr_t bdaddr; + __u8 type; +}; + struct hci_inquiry_req { __u16 dev_id; __u16 flags; diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index ea13baa3851b..cbf751094688 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -40,6 +40,7 @@ struct inquiry_data { __u8 dev_class[3]; __le16 clock_offset; __s8 rssi; + __u8 ssp_mode; }; struct inquiry_entry { @@ -75,6 +76,7 @@ struct hci_dev { __u8 dev_class[3]; __u8 features[8]; __u8 commands[64]; + __u8 ssp_mode; __u8 hci_ver; __u16 hci_rev; __u16 manufacturer; @@ -161,9 +163,12 @@ struct hci_conn { __u8 attempt; __u8 dev_class[3]; __u8 features[8]; + __u8 ssp_mode; __u16 interval; + __u16 pkt_type; __u16 link_policy; __u32 link_mode; + __u8 auth_type; __u8 power_save; unsigned long pend; @@ -344,7 +349,7 @@ static inline void hci_conn_put(struct hci_conn *conn) if (conn->state == BT_CONNECTED) { timeo = msecs_to_jiffies(HCI_DISCONN_TIMEOUT); if (!conn->out) - timeo *= 2; + timeo *= 5; } else timeo = msecs_to_jiffies(10); } else @@ -418,6 +423,7 @@ int hci_get_dev_list(void __user *arg); int hci_get_dev_info(void __user *arg); int hci_get_conn_list(void __user *arg); int hci_get_conn_info(struct hci_dev *hdev, void __user *arg); +int hci_get_auth_info(struct hci_dev *hdev, void __user *arg); int hci_inquiry(void __user *arg); void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb); @@ -459,6 +465,7 @@ void hci_conn_del_sysfs(struct hci_conn *conn); #define lmp_sniff_capable(dev) ((dev)->features[0] & LMP_SNIFF) #define lmp_sniffsubr_capable(dev) ((dev)->features[5] & LMP_SNIFF_SUBR) #define lmp_esco_capable(dev) ((dev)->features[3] & LMP_ESCO) +#define lmp_ssp_capable(dev) ((dev)->features[6] & LMP_SIMPLE_PAIR) /* ----- HCI protocols ----- */ struct hci_proto { @@ -474,7 +481,7 @@ struct hci_proto { int (*recv_acldata) (struct hci_conn *conn, struct sk_buff *skb, __u16 flags); int (*recv_scodata) (struct hci_conn *conn, struct sk_buff *skb); int (*auth_cfm) (struct hci_conn *conn, __u8 status); - int (*encrypt_cfm) (struct hci_conn *conn, __u8 status); + int (*encrypt_cfm) (struct hci_conn *conn, __u8 status, __u8 encrypt); }; static inline int hci_proto_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, __u8 type) @@ -532,17 +539,17 @@ static inline void hci_proto_auth_cfm(struct hci_conn *conn, __u8 status) hp->auth_cfm(conn, status); } -static inline void hci_proto_encrypt_cfm(struct hci_conn *conn, __u8 status) +static inline void hci_proto_encrypt_cfm(struct hci_conn *conn, __u8 status, __u8 encrypt) { register struct hci_proto *hp; hp = hci_proto[HCI_PROTO_L2CAP]; if (hp && hp->encrypt_cfm) - hp->encrypt_cfm(conn, status); + hp->encrypt_cfm(conn, status, encrypt); hp = hci_proto[HCI_PROTO_SCO]; if (hp && hp->encrypt_cfm) - hp->encrypt_cfm(conn, status); + hp->encrypt_cfm(conn, status, encrypt); } int hci_register_proto(struct hci_proto *hproto); @@ -579,7 +586,7 @@ static inline void hci_encrypt_cfm(struct hci_conn *conn, __u8 status, __u8 encr { struct list_head *p; - hci_proto_encrypt_cfm(conn, status); + hci_proto_encrypt_cfm(conn, status, encrypt); read_lock_bh(&hci_cb_list_lock); list_for_each(p, &hci_cb_list) { diff --git a/include/net/bluetooth/rfcomm.h b/include/net/bluetooth/rfcomm.h index 98ec7a320689..4dc8d92a4638 100644 --- a/include/net/bluetooth/rfcomm.h +++ b/include/net/bluetooth/rfcomm.h @@ -180,7 +180,9 @@ struct rfcomm_dlc { u8 addr; u8 priority; u8 v24_sig; + u8 remote_v24_sig; u8 mscex; + u8 out; u32 link_mode; diff --git a/include/net/compat.h b/include/net/compat.h index 164cb682e220..5bbf8bf9efea 100644 --- a/include/net/compat.h +++ b/include/net/compat.h @@ -32,7 +32,7 @@ extern int compat_sock_get_timestampns(struct sock *, struct timespec __user *); #endif /* defined(CONFIG_COMPAT) */ extern int get_compat_msghdr(struct msghdr *, struct compat_msghdr __user *); -extern int verify_compat_iovec(struct msghdr *, struct iovec *, char *, int); +extern int verify_compat_iovec(struct msghdr *, struct iovec *, struct sockaddr *, int); extern asmlinkage long compat_sys_sendmsg(int,struct compat_msghdr __user *,unsigned); extern asmlinkage long compat_sys_recvmsg(int,struct compat_msghdr __user *,unsigned); extern asmlinkage long compat_sys_getsockopt(int, int, int, char __user *, int __user *); diff --git a/include/net/dst.h b/include/net/dst.h index 002500e631f5..c5c318a628f8 100644 --- a/include/net/dst.h +++ b/include/net/dst.h @@ -128,6 +128,18 @@ static inline u32 dst_mtu(const struct dst_entry *dst) return mtu; } +/* RTT metrics are stored in milliseconds for user ABI, but used as jiffies */ +static inline unsigned long dst_metric_rtt(const struct dst_entry *dst, int metric) +{ + return msecs_to_jiffies(dst_metric(dst, metric)); +} + +static inline void set_dst_metric_rtt(struct dst_entry *dst, int metric, + unsigned long rtt) +{ + dst->metrics[metric-1] = jiffies_to_msecs(rtt); +} + static inline u32 dst_allfrag(const struct dst_entry *dst) { diff --git a/include/net/fib_rules.h b/include/net/fib_rules.h index a5c6ccc5bb19..c2bb5cae6515 100644 --- a/include/net/fib_rules.h +++ b/include/net/fib_rules.h @@ -62,7 +62,7 @@ struct fib_rules_ops /* Called after modifications to the rules set, must flush * the route cache if one exists. */ - void (*flush_cache)(void); + void (*flush_cache)(struct fib_rules_ops *ops); int nlgroup; const struct nla_policy *policy; diff --git a/include/net/garp.h b/include/net/garp.h new file mode 100644 index 000000000000..825f172caba9 --- /dev/null +++ b/include/net/garp.h @@ -0,0 +1,128 @@ +#ifndef _NET_GARP_H +#define _NET_GARP_H + +#include <net/stp.h> + +#define GARP_PROTOCOL_ID 0x1 +#define GARP_END_MARK 0x0 + +struct garp_pdu_hdr { + __be16 protocol; +}; + +struct garp_msg_hdr { + u8 attrtype; +}; + +enum garp_attr_event { + GARP_LEAVE_ALL, + GARP_JOIN_EMPTY, + GARP_JOIN_IN, + GARP_LEAVE_EMPTY, + GARP_LEAVE_IN, + GARP_EMPTY, +}; + +struct garp_attr_hdr { + u8 len; + u8 event; + u8 data[]; +}; + +struct garp_skb_cb { + u8 cur_type; +}; + +static inline struct garp_skb_cb *garp_cb(struct sk_buff *skb) +{ + BUILD_BUG_ON(sizeof(struct garp_skb_cb) > + FIELD_SIZEOF(struct sk_buff, cb)); + return (struct garp_skb_cb *)skb->cb; +} + +enum garp_applicant_state { + GARP_APPLICANT_INVALID, + GARP_APPLICANT_VA, + GARP_APPLICANT_AA, + GARP_APPLICANT_QA, + GARP_APPLICANT_LA, + GARP_APPLICANT_VP, + GARP_APPLICANT_AP, + GARP_APPLICANT_QP, + GARP_APPLICANT_VO, + GARP_APPLICANT_AO, + GARP_APPLICANT_QO, + __GARP_APPLICANT_MAX +}; +#define GARP_APPLICANT_MAX (__GARP_APPLICANT_MAX - 1) + +enum garp_event { + GARP_EVENT_REQ_JOIN, + GARP_EVENT_REQ_LEAVE, + GARP_EVENT_R_JOIN_IN, + GARP_EVENT_R_JOIN_EMPTY, + GARP_EVENT_R_EMPTY, + GARP_EVENT_R_LEAVE_IN, + GARP_EVENT_R_LEAVE_EMPTY, + GARP_EVENT_TRANSMIT_PDU, + __GARP_EVENT_MAX +}; +#define GARP_EVENT_MAX (__GARP_EVENT_MAX - 1) + +enum garp_action { + GARP_ACTION_NONE, + GARP_ACTION_S_JOIN_IN, + GARP_ACTION_S_LEAVE_EMPTY, +}; + +struct garp_attr { + struct rb_node node; + enum garp_applicant_state state; + u8 type; + u8 dlen; + unsigned char data[]; +}; + +enum garp_applications { + GARP_APPLICATION_GVRP, + __GARP_APPLICATION_MAX +}; +#define GARP_APPLICATION_MAX (__GARP_APPLICATION_MAX - 1) + +struct garp_application { + enum garp_applications type; + unsigned int maxattr; + struct stp_proto proto; +}; + +struct garp_applicant { + struct garp_application *app; + struct net_device *dev; + struct timer_list join_timer; + + spinlock_t lock; + struct sk_buff_head queue; + struct sk_buff *pdu; + struct rb_root gid; +}; + +struct garp_port { + struct garp_applicant *applicants[GARP_APPLICATION_MAX + 1]; +}; + +extern int garp_register_application(struct garp_application *app); +extern void garp_unregister_application(struct garp_application *app); + +extern int garp_init_applicant(struct net_device *dev, + struct garp_application *app); +extern void garp_uninit_applicant(struct net_device *dev, + struct garp_application *app); + +extern int garp_request_join(const struct net_device *dev, + const struct garp_application *app, + const void *data, u8 len, u8 type); +extern void garp_request_leave(const struct net_device *dev, + const struct garp_application *app, + const void *data, u8 len, u8 type); + +#endif /* _NET_GARP_H */ diff --git a/include/net/icmp.h b/include/net/icmp.h index dddb839ff4b5..dfa72d4e8907 100644 --- a/include/net/icmp.h +++ b/include/net/icmp.h @@ -29,27 +29,21 @@ struct icmp_err { }; extern struct icmp_err icmp_err_convert[]; -DECLARE_SNMP_STAT(struct icmp_mib, icmp_statistics); -DECLARE_SNMP_STAT(struct icmpmsg_mib, icmpmsg_statistics); -#define ICMP_INC_STATS(field) SNMP_INC_STATS(icmp_statistics, field) -#define ICMP_INC_STATS_BH(field) SNMP_INC_STATS_BH(icmp_statistics, field) -#define ICMP_INC_STATS_USER(field) SNMP_INC_STATS_USER(icmp_statistics, field) -#define ICMPMSGOUT_INC_STATS(field) SNMP_INC_STATS(icmpmsg_statistics, field+256) -#define ICMPMSGOUT_INC_STATS_BH(field) SNMP_INC_STATS_BH(icmpmsg_statistics, field+256) -#define ICMPMSGOUT_INC_STATS_USER(field) SNMP_INC_STATS_USER(icmpmsg_statistics, field+256) -#define ICMPMSGIN_INC_STATS(field) SNMP_INC_STATS(icmpmsg_statistics, field) -#define ICMPMSGIN_INC_STATS_BH(field) SNMP_INC_STATS_BH(icmpmsg_statistics, field) -#define ICMPMSGIN_INC_STATS_USER(field) SNMP_INC_STATS_USER(icmpmsg_statistics, field) +#define ICMP_INC_STATS(net, field) SNMP_INC_STATS((net)->mib.icmp_statistics, field) +#define ICMP_INC_STATS_BH(net, field) SNMP_INC_STATS_BH((net)->mib.icmp_statistics, field) +#define ICMPMSGOUT_INC_STATS(net, field) SNMP_INC_STATS((net)->mib.icmpmsg_statistics, field+256) +#define ICMPMSGIN_INC_STATS_BH(net, field) SNMP_INC_STATS_BH((net)->mib.icmpmsg_statistics, field) struct dst_entry; struct net_proto_family; struct sk_buff; +struct net; extern void icmp_send(struct sk_buff *skb_in, int type, int code, __be32 info); extern int icmp_rcv(struct sk_buff *skb); extern int icmp_ioctl(struct sock *sk, int cmd, unsigned long arg); extern int icmp_init(void); -extern void icmp_out_count(unsigned char type); +extern void icmp_out_count(struct net *net, unsigned char type); /* Move into dst.h ? */ extern int xrlim_allow(struct dst_entry *dst, int timeout); diff --git a/include/net/ieee80211.h b/include/net/ieee80211.h index 529816bfbc52..b31399e1fd83 100644 --- a/include/net/ieee80211.h +++ b/include/net/ieee80211.h @@ -1262,9 +1262,6 @@ extern int ieee80211_set_encryption(struct ieee80211_device *ieee); /* ieee80211_tx.c */ extern int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev); extern void ieee80211_txb_free(struct ieee80211_txb *); -extern int ieee80211_tx_frame(struct ieee80211_device *ieee, - struct ieee80211_hdr *frame, int hdr_len, - int total_len, int encrypt_mpdu); /* ieee80211_rx.c */ extern void ieee80211_rx_any(struct ieee80211_device *ieee, @@ -1312,14 +1309,6 @@ extern int ieee80211_wx_set_encodeext(struct ieee80211_device *ieee, extern int ieee80211_wx_get_encodeext(struct ieee80211_device *ieee, struct iw_request_info *info, union iwreq_data *wrqu, char *extra); -extern int ieee80211_wx_set_auth(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra); -extern int ieee80211_wx_get_auth(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra); static inline void ieee80211_increment_scans(struct ieee80211_device *ieee) { diff --git a/include/net/if_inet6.h b/include/net/if_inet6.h index b2cfc4927257..db66c7927743 100644 --- a/include/net/if_inet6.h +++ b/include/net/if_inet6.h @@ -148,7 +148,6 @@ struct ifacaddr6 #define IFA_HOST IPV6_ADDR_LOOPBACK #define IFA_LINK IPV6_ADDR_LINKLOCAL #define IFA_SITE IPV6_ADDR_SITELOCAL -#define IFA_GLOBAL 0x0000U struct ipv6_devstat { struct proc_dir_entry *proc_dir_entry; diff --git a/include/net/inet6_hashtables.h b/include/net/inet6_hashtables.h index 62a5b691858e..e48989f04c24 100644 --- a/include/net/inet6_hashtables.h +++ b/include/net/inet6_hashtables.h @@ -24,18 +24,20 @@ #include <net/inet_sock.h> #include <net/ipv6.h> +#include <net/netns/hash.h> struct inet_hashinfo; /* I have no idea if this is a good hash for v6 or not. -DaveM */ -static inline unsigned int inet6_ehashfn(const struct in6_addr *laddr, const u16 lport, +static inline unsigned int inet6_ehashfn(struct net *net, + const struct in6_addr *laddr, const u16 lport, const struct in6_addr *faddr, const __be16 fport) { u32 ports = (lport ^ (__force u16)fport); return jhash_3words((__force u32)laddr->s6_addr32[3], (__force u32)faddr->s6_addr32[3], - ports, inet_ehash_secret); + ports, inet_ehash_secret + net_hash_mix(net)); } static inline int inet6_sk_ehashfn(const struct sock *sk) @@ -46,7 +48,9 @@ static inline int inet6_sk_ehashfn(const struct sock *sk) const struct in6_addr *faddr = &np->daddr; const __u16 lport = inet->num; const __be16 fport = inet->dport; - return inet6_ehashfn(laddr, lport, faddr, fport); + struct net *net = sock_net(sk); + + return inet6_ehashfn(net, laddr, lport, faddr, fport); } extern void __inet6_hash(struct sock *sk); diff --git a/include/net/inet_hashtables.h b/include/net/inet_hashtables.h index 735b926a3497..bb619d80f2e2 100644 --- a/include/net/inet_hashtables.h +++ b/include/net/inet_hashtables.h @@ -29,6 +29,7 @@ #include <net/inet_sock.h> #include <net/sock.h> #include <net/tcp_states.h> +#include <net/netns/hash.h> #include <asm/atomic.h> #include <asm/byteorder.h> @@ -201,23 +202,24 @@ extern struct inet_bind_bucket * extern void inet_bind_bucket_destroy(struct kmem_cache *cachep, struct inet_bind_bucket *tb); -static inline int inet_bhashfn(const __u16 lport, const int bhash_size) +static inline int inet_bhashfn(struct net *net, + const __u16 lport, const int bhash_size) { - return lport & (bhash_size - 1); + return (lport + net_hash_mix(net)) & (bhash_size - 1); } extern void inet_bind_hash(struct sock *sk, struct inet_bind_bucket *tb, const unsigned short snum); /* These can have wildcards, don't try too hard. */ -static inline int inet_lhashfn(const unsigned short num) +static inline int inet_lhashfn(struct net *net, const unsigned short num) { - return num & (INET_LHTABLE_SIZE - 1); + return (num + net_hash_mix(net)) & (INET_LHTABLE_SIZE - 1); } static inline int inet_sk_listen_hashfn(const struct sock *sk) { - return inet_lhashfn(inet_sk(sk)->num); + return inet_lhashfn(sock_net(sk), inet_sk(sk)->num); } /* Caller must disable local BH processing. */ diff --git a/include/net/inet_sock.h b/include/net/inet_sock.h index 9fabe5b38912..643e26be058e 100644 --- a/include/net/inet_sock.h +++ b/include/net/inet_sock.h @@ -25,6 +25,7 @@ #include <net/sock.h> #include <net/request_sock.h> #include <net/route.h> +#include <net/netns/hash.h> /** struct ip_options - IP Options * @@ -171,13 +172,14 @@ extern int inet_sk_rebuild_header(struct sock *sk); extern u32 inet_ehash_secret; extern void build_ehash_secret(void); -static inline unsigned int inet_ehashfn(const __be32 laddr, const __u16 lport, +static inline unsigned int inet_ehashfn(struct net *net, + const __be32 laddr, const __u16 lport, const __be32 faddr, const __be16 fport) { return jhash_3words((__force __u32) laddr, (__force __u32) faddr, ((__u32) lport) << 16 | (__force __u32)fport, - inet_ehash_secret); + inet_ehash_secret + net_hash_mix(net)); } static inline int inet_sk_ehashfn(const struct sock *sk) @@ -187,8 +189,9 @@ static inline int inet_sk_ehashfn(const struct sock *sk) const __u16 lport = inet->num; const __be32 faddr = inet->daddr; const __be16 fport = inet->dport; + struct net *net = sock_net(sk); - return inet_ehashfn(laddr, lport, faddr, fport); + return inet_ehashfn(net, laddr, lport, faddr, fport); } diff --git a/include/net/inetpeer.h b/include/net/inetpeer.h index ad8404b56113..15e1f8fe4c1f 100644 --- a/include/net/inetpeer.h +++ b/include/net/inetpeer.h @@ -1,8 +1,6 @@ /* * INETPEER - A storage for permanent information about peers * - * Version: $Id: inetpeer.h,v 1.2 2002/01/12 07:54:56 davem Exp $ - * * Authors: Andrey V. Savochkin <saw@msu.ru> */ diff --git a/include/net/ip.h b/include/net/ip.h index 3b40bc2234be..b5862b975207 100644 --- a/include/net/ip.h +++ b/include/net/ip.h @@ -156,17 +156,14 @@ struct ipv4_config }; extern struct ipv4_config ipv4_config; -DECLARE_SNMP_STAT(struct ipstats_mib, ip_statistics); -#define IP_INC_STATS(field) SNMP_INC_STATS(ip_statistics, field) -#define IP_INC_STATS_BH(field) SNMP_INC_STATS_BH(ip_statistics, field) -#define IP_INC_STATS_USER(field) SNMP_INC_STATS_USER(ip_statistics, field) -#define IP_ADD_STATS_BH(field, val) SNMP_ADD_STATS_BH(ip_statistics, field, val) -DECLARE_SNMP_STAT(struct linux_mib, net_statistics); -#define NET_INC_STATS(field) SNMP_INC_STATS(net_statistics, field) -#define NET_INC_STATS_BH(field) SNMP_INC_STATS_BH(net_statistics, field) -#define NET_INC_STATS_USER(field) SNMP_INC_STATS_USER(net_statistics, field) -#define NET_ADD_STATS_BH(field, adnd) SNMP_ADD_STATS_BH(net_statistics, field, adnd) -#define NET_ADD_STATS_USER(field, adnd) SNMP_ADD_STATS_USER(net_statistics, field, adnd) +#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_BH(net, field, val) SNMP_ADD_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) +#define NET_ADD_STATS_BH(net, field, adnd) SNMP_ADD_STATS_BH((net)->mib.net_statistics, field, adnd) +#define NET_ADD_STATS_USER(net, field, adnd) SNMP_ADD_STATS_USER((net)->mib.net_statistics, field, adnd) extern unsigned long snmp_fold_field(void *mib[], int offt); extern int snmp_mib_init(void *ptr[2], size_t mibsize); diff --git a/include/net/ip6_tunnel.h b/include/net/ip6_tunnel.h index 6512d85f11b3..83b4e008b16d 100644 --- a/include/net/ip6_tunnel.h +++ b/include/net/ip6_tunnel.h @@ -1,7 +1,3 @@ -/* - * $Id$ - */ - #ifndef _NET_IP6_TUNNEL_H #define _NET_IP6_TUNNEL_H @@ -19,7 +15,6 @@ struct ip6_tnl { struct ip6_tnl *next; /* next tunnel in list */ struct net_device *dev; /* virtual device associated with tunnel */ - struct net_device_stats stat; /* statistics for tunnel device */ int recursion; /* depth of hard_start_xmit recursion */ struct ip6_tnl_parm parms; /* tunnel configuration parameters */ struct flowi fl; /* flowi template for xmit */ diff --git a/include/net/ipconfig.h b/include/net/ipconfig.h index 3924d7d2cb11..c74cc1bd5a02 100644 --- a/include/net/ipconfig.h +++ b/include/net/ipconfig.h @@ -1,6 +1,4 @@ /* - * $Id: ipconfig.h,v 1.4 2001/04/30 04:51:46 davem Exp $ - * * Copyright (C) 1997 Martin Mares * * Automatic IP Layer Configuration diff --git a/include/net/ipip.h b/include/net/ipip.h index 633ed4def8e3..a85bda64b852 100644 --- a/include/net/ipip.h +++ b/include/net/ipip.h @@ -11,7 +11,6 @@ struct ip_tunnel { struct ip_tunnel *next; struct net_device *dev; - struct net_device_stats stat; int recursion; /* Depth of hard_start_xmit recursion */ int err_count; /* Number of arrived ICMP errors */ diff --git a/include/net/ipv6.h b/include/net/ipv6.h index f422f7218e1c..2d5c18514a2d 100644 --- a/include/net/ipv6.h +++ b/include/net/ipv6.h @@ -4,8 +4,6 @@ * Authors: * Pedro Roque <roque@di.fc.ul.pt> * - * $Id: ipv6.h,v 1.1 2002/05/20 15:13:07 jgrimm Exp $ - * * 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 @@ -133,7 +131,6 @@ DECLARE_SNMP_STAT(struct ipstats_mib, ipv6_statistics); #define IP6_INC_STATS(idev,field) _DEVINC(ipv6, , idev, field) #define IP6_INC_STATS_BH(idev,field) _DEVINC(ipv6, _BH, idev, field) -#define IP6_INC_STATS_USER(idev,field) _DEVINC(ipv6, _USER, idev, field) #define IP6_ADD_STATS_BH(idev,field,val) _DEVADD(ipv6, _BH, idev, field, val) DECLARE_SNMP_STAT(struct icmpv6_mib, icmpv6_statistics); @@ -141,20 +138,15 @@ DECLARE_SNMP_STAT(struct icmpv6msg_mib, icmpv6msg_statistics); #define ICMP6_INC_STATS(idev, field) _DEVINC(icmpv6, , idev, field) #define ICMP6_INC_STATS_BH(idev, field) _DEVINC(icmpv6, _BH, idev, field) -#define ICMP6_INC_STATS_USER(idev, field) _DEVINC(icmpv6, _USER, idev, field) #define ICMP6MSGOUT_INC_STATS(idev, field) \ _DEVINC(icmpv6msg, , idev, field +256) #define ICMP6MSGOUT_INC_STATS_BH(idev, field) \ _DEVINC(icmpv6msg, _BH, idev, field +256) -#define ICMP6MSGOUT_INC_STATS_USER(idev, field) \ - _DEVINC(icmpv6msg, _USER, idev, field +256) #define ICMP6MSGIN_INC_STATS(idev, field) \ _DEVINC(icmpv6msg, , idev, field) #define ICMP6MSGIN_INC_STATS_BH(idev, field) \ _DEVINC(icmpv6msg, _BH, idev, field) -#define ICMP6MSGIN_INC_STATS_USER(idev, field) \ - _DEVINC(icmpv6msg, _USER, idev, field) struct ip6_ra_chain { @@ -229,9 +221,7 @@ static inline void fl6_sock_release(struct ip6_flowlabel *fl) atomic_dec(&fl->users); } -extern int ip6_ra_control(struct sock *sk, int sel, - void (*destructor)(struct sock *)); - +extern int ip6_ra_control(struct sock *sk, int sel); extern int ipv6_parse_hopopts(struct sk_buff *skb); diff --git a/include/net/irda/irda_device.h b/include/net/irda/irda_device.h index f70e9b39ebaf..3025ae17ddbe 100644 --- a/include/net/irda/irda_device.h +++ b/include/net/irda/irda_device.h @@ -223,7 +223,7 @@ int irda_device_is_receiving(struct net_device *dev); /* Interface for internal use */ static inline int irda_device_txqueue_empty(const struct net_device *dev) { - return skb_queue_empty(&dev->qdisc->q); + return qdisc_all_tx_empty(dev); } int irda_device_set_raw_mode(struct net_device* self, int status); struct net_device *alloc_irdadev(int sizeof_priv); diff --git a/include/net/iw_handler.h b/include/net/iw_handler.h index 369d50e08b99..51b9a37de991 100644 --- a/include/net/iw_handler.h +++ b/include/net/iw_handler.h @@ -256,7 +256,7 @@ #define EIWCOMMIT EINPROGRESS /* Flags available in struct iw_request_info */ -#define IW_REQUEST_FLAG_NONE 0x0000 /* No flag so far */ +#define IW_REQUEST_FLAG_COMPAT 0x0001 /* Compat ioctl call */ /* Type of headers we know about (basically union iwreq_data) */ #define IW_HEADER_TYPE_NULL 0 /* Not available */ @@ -478,105 +478,58 @@ extern void wireless_spy_update(struct net_device * dev, * Function that are so simple that it's more efficient inlining them */ -/*------------------------------------------------------------------*/ -/* - * Wrapper to add an Wireless Event to a stream of events. - */ -static inline char * -iwe_stream_add_event(char * stream, /* Stream of events */ - char * ends, /* End of stream */ - struct iw_event *iwe, /* Payload */ - int event_len) /* Real size of payload */ +static inline int iwe_stream_lcp_len(struct iw_request_info *info) { - /* Check if it's possible */ - if(likely((stream + event_len) < ends)) { - iwe->len = event_len; - /* Beware of alignement issues on 64 bits */ - memcpy(stream, (char *) iwe, IW_EV_LCP_PK_LEN); - memcpy(stream + IW_EV_LCP_LEN, - ((char *) iwe) + IW_EV_LCP_LEN, - event_len - IW_EV_LCP_LEN); - stream += event_len; - } - return stream; +#ifdef CONFIG_COMPAT + if (info->flags & IW_REQUEST_FLAG_COMPAT) + return IW_EV_COMPAT_LCP_LEN; +#endif + return IW_EV_LCP_LEN; } -/*------------------------------------------------------------------*/ -/* - * Wrapper to add an short Wireless Event containing a pointer to a - * stream of events. - */ -static inline char * -iwe_stream_add_point(char * stream, /* Stream of events */ - char * ends, /* End of stream */ - struct iw_event *iwe, /* Payload length + flags */ - char * extra) /* More payload */ +static inline int iwe_stream_point_len(struct iw_request_info *info) { - int event_len = IW_EV_POINT_LEN + iwe->u.data.length; - /* Check if it's possible */ - if(likely((stream + event_len) < ends)) { - iwe->len = event_len; - memcpy(stream, (char *) iwe, IW_EV_LCP_PK_LEN); - memcpy(stream + IW_EV_LCP_LEN, - ((char *) iwe) + IW_EV_LCP_LEN + IW_EV_POINT_OFF, - IW_EV_POINT_PK_LEN - IW_EV_LCP_PK_LEN); - memcpy(stream + IW_EV_POINT_LEN, extra, iwe->u.data.length); - stream += event_len; - } - return stream; +#ifdef CONFIG_COMPAT + if (info->flags & IW_REQUEST_FLAG_COMPAT) + return IW_EV_COMPAT_POINT_LEN; +#endif + return IW_EV_POINT_LEN; } -/*------------------------------------------------------------------*/ -/* - * Wrapper to add a value to a Wireless Event in a stream of events. - * Be careful, this one is tricky to use properly : - * At the first run, you need to have (value = event + IW_EV_LCP_LEN). - */ -static inline char * -iwe_stream_add_value(char * event, /* Event in the stream */ - char * value, /* Value in event */ - char * ends, /* End of stream */ - struct iw_event *iwe, /* Payload */ - int event_len) /* Real size of payload */ +static inline int iwe_stream_event_len_adjust(struct iw_request_info *info, + int event_len) { - /* Don't duplicate LCP */ - event_len -= IW_EV_LCP_LEN; - - /* Check if it's possible */ - if(likely((value + event_len) < ends)) { - /* Add new value */ - memcpy(value, (char *) iwe + IW_EV_LCP_LEN, event_len); - value += event_len; - /* Patch LCP */ - iwe->len = value - event; - memcpy(event, (char *) iwe, IW_EV_LCP_LEN); +#ifdef CONFIG_COMPAT + if (info->flags & IW_REQUEST_FLAG_COMPAT) { + event_len -= IW_EV_LCP_LEN; + event_len += IW_EV_COMPAT_LCP_LEN; } - return value; +#endif + + return event_len; } /*------------------------------------------------------------------*/ /* * Wrapper to add an Wireless Event to a stream of events. - * Same as above, with explicit error check... */ static inline char * -iwe_stream_check_add_event(char * stream, /* Stream of events */ - char * ends, /* End of stream */ - struct iw_event *iwe, /* Payload */ - int event_len, /* Size of payload */ - int * perr) /* Error report */ +iwe_stream_add_event(struct iw_request_info *info, char *stream, char *ends, + struct iw_event *iwe, int event_len) { - /* Check if it's possible, set error if not */ + int lcp_len = iwe_stream_lcp_len(info); + + event_len = iwe_stream_event_len_adjust(info, event_len); + + /* Check if it's possible */ if(likely((stream + event_len) < ends)) { iwe->len = event_len; /* Beware of alignement issues on 64 bits */ memcpy(stream, (char *) iwe, IW_EV_LCP_PK_LEN); - memcpy(stream + IW_EV_LCP_LEN, - ((char *) iwe) + IW_EV_LCP_LEN, - event_len - IW_EV_LCP_LEN); + memcpy(stream + lcp_len, &iwe->u, + event_len - lcp_len); stream += event_len; - } else - *perr = -E2BIG; + } return stream; } @@ -584,27 +537,25 @@ iwe_stream_check_add_event(char * stream, /* Stream of events */ /* * Wrapper to add an short Wireless Event containing a pointer to a * stream of events. - * Same as above, with explicit error check... */ static inline char * -iwe_stream_check_add_point(char * stream, /* Stream of events */ - char * ends, /* End of stream */ - struct iw_event *iwe, /* Payload length + flags */ - char * extra, /* More payload */ - int * perr) /* Error report */ +iwe_stream_add_point(struct iw_request_info *info, char *stream, char *ends, + struct iw_event *iwe, char *extra) { - int event_len = IW_EV_POINT_LEN + iwe->u.data.length; + int event_len = iwe_stream_point_len(info) + iwe->u.data.length; + int point_len = iwe_stream_point_len(info); + int lcp_len = iwe_stream_lcp_len(info); + /* Check if it's possible */ if(likely((stream + event_len) < ends)) { iwe->len = event_len; memcpy(stream, (char *) iwe, IW_EV_LCP_PK_LEN); - memcpy(stream + IW_EV_LCP_LEN, - ((char *) iwe) + IW_EV_LCP_LEN + IW_EV_POINT_OFF, + memcpy(stream + lcp_len, + ((char *) &iwe->u) + IW_EV_POINT_OFF, IW_EV_POINT_PK_LEN - IW_EV_LCP_PK_LEN); - memcpy(stream + IW_EV_POINT_LEN, extra, iwe->u.data.length); + memcpy(stream + point_len, extra, iwe->u.data.length); stream += event_len; - } else - *perr = -E2BIG; + } return stream; } @@ -613,29 +564,25 @@ iwe_stream_check_add_point(char * stream, /* Stream of events */ * Wrapper to add a value to a Wireless Event in a stream of events. * Be careful, this one is tricky to use properly : * At the first run, you need to have (value = event + IW_EV_LCP_LEN). - * Same as above, with explicit error check... */ static inline char * -iwe_stream_check_add_value(char * event, /* Event in the stream */ - char * value, /* Value in event */ - char * ends, /* End of stream */ - struct iw_event *iwe, /* Payload */ - int event_len, /* Size of payload */ - int * perr) /* Error report */ +iwe_stream_add_value(struct iw_request_info *info, char *event, char *value, + char *ends, struct iw_event *iwe, int event_len) { + int lcp_len = iwe_stream_lcp_len(info); + /* Don't duplicate LCP */ event_len -= IW_EV_LCP_LEN; /* Check if it's possible */ if(likely((value + event_len) < ends)) { /* Add new value */ - memcpy(value, (char *) iwe + IW_EV_LCP_LEN, event_len); + memcpy(value, &iwe->u, event_len); value += event_len; /* Patch LCP */ iwe->len = value - event; - memcpy(event, (char *) iwe, IW_EV_LCP_LEN); - } else - *perr = -E2BIG; + memcpy(event, (char *) iwe, lcp_len); + } return value; } diff --git a/include/net/mac80211.h b/include/net/mac80211.h index bcd1623245cb..4dd3d93e1960 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -42,7 +42,7 @@ * tasklet function. * * NOTE: If the driver opts to use the _irqsafe() functions, it may not also - * use the non-irqsafe functions! + * use the non-IRQ-safe functions! */ /** @@ -85,7 +85,7 @@ enum ieee80211_notification_types { * 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 + * 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) @@ -98,77 +98,49 @@ struct ieee80211_ht_bss_info { }; /** + * enum ieee80211_max_queues - maximum number of queues + * + * @IEEE80211_MAX_QUEUES: Maximum number of regular device queues. + * @IEEE80211_MAX_AMPDU_QUEUES: Maximum number of queues usable + * for A-MPDU operation. + */ +enum ieee80211_max_queues { + IEEE80211_MAX_QUEUES = 16, + IEEE80211_MAX_AMPDU_QUEUES = 16, +}; + +/** * struct ieee80211_tx_queue_params - transmit queue configuration * * The information provided in this structure is required for QoS * transmit queue configuration. Cf. IEEE 802.11 7.3.2.29. * - * @aifs: arbitration interface space [0..255, -1: use default] - * @cw_min: minimum contention window [will be a value of the form - * 2^n-1 in the range 1..1023; 0: use default] + * @aifs: arbitration interface space [0..255] + * @cw_min: minimum contention window [a value of the form + * 2^n-1 in the range 1..32767] * @cw_max: maximum contention window [like @cw_min] * @txop: maximum burst time in units of 32 usecs, 0 meaning disabled */ struct ieee80211_tx_queue_params { - s16 aifs; + u16 txop; u16 cw_min; u16 cw_max; - u16 txop; + u8 aifs; }; /** - * struct ieee80211_tx_queue_stats_data - transmit queue statistics + * struct ieee80211_tx_queue_stats - transmit queue statistics * * @len: number of packets in queue * @limit: queue length limit * @count: number of frames sent */ -struct ieee80211_tx_queue_stats_data { +struct ieee80211_tx_queue_stats { unsigned int len; unsigned int limit; unsigned int count; }; -/** - * enum ieee80211_tx_queue - transmit queue number - * - * These constants are used with some callbacks that take a - * queue number to set parameters for a queue. - * - * @IEEE80211_TX_QUEUE_DATA0: data queue 0 - * @IEEE80211_TX_QUEUE_DATA1: data queue 1 - * @IEEE80211_TX_QUEUE_DATA2: data queue 2 - * @IEEE80211_TX_QUEUE_DATA3: data queue 3 - * @IEEE80211_TX_QUEUE_DATA4: data queue 4 - * @IEEE80211_TX_QUEUE_SVP: ?? - * @NUM_TX_DATA_QUEUES: number of data queues - * @IEEE80211_TX_QUEUE_AFTER_BEACON: transmit queue for frames to be - * sent after a beacon - * @IEEE80211_TX_QUEUE_BEACON: transmit queue for beacon frames - * @NUM_TX_DATA_QUEUES_AMPDU: adding more queues for A-MPDU - */ -enum ieee80211_tx_queue { - IEEE80211_TX_QUEUE_DATA0, - IEEE80211_TX_QUEUE_DATA1, - IEEE80211_TX_QUEUE_DATA2, - IEEE80211_TX_QUEUE_DATA3, - IEEE80211_TX_QUEUE_DATA4, - IEEE80211_TX_QUEUE_SVP, - - NUM_TX_DATA_QUEUES, - -/* due to stupidity in the sub-ioctl userspace interface, the items in - * this struct need to have fixed values. As soon as it is removed, we can - * fix these entries. */ - IEEE80211_TX_QUEUE_AFTER_BEACON = 6, - IEEE80211_TX_QUEUE_BEACON = 7, - NUM_TX_DATA_QUEUES_AMPDU = 16 -}; - -struct ieee80211_tx_queue_stats { - struct ieee80211_tx_queue_stats_data data[NUM_TX_DATA_QUEUES_AMPDU]; -}; - struct ieee80211_low_level_stats { unsigned int dot11ACKFailureCount; unsigned int dot11RTSFailureCount; @@ -229,91 +201,151 @@ struct ieee80211_bss_conf { }; /** - * enum mac80211_tx_control_flags - flags to describe Tx configuration for - * the Tx frame - * - * These flags are used with the @flags member of &ieee80211_tx_control - * - * @IEEE80211_TXCTL_REQ_TX_STATUS: request TX status callback for this frame. - * @IEEE80211_TXCTL_DO_NOT_ENCRYPT: send this frame without encryption; - * e.g., for EAPOL frame - * @IEEE80211_TXCTL_USE_RTS_CTS: use RTS-CTS before sending frame - * @IEEE80211_TXCTL_USE_CTS_PROTECT: use CTS protection for the frame (e.g., - * for combined 802.11g / 802.11b networks) - * @IEEE80211_TXCTL_NO_ACK: tell the low level not to wait for an ack - * @IEEE80211_TXCTL_RATE_CTRL_PROBE - * @EEE80211_TXCTL_CLEAR_PS_FILT: clear powersave filter - * for destination station - * @IEEE80211_TXCTL_REQUEUE: - * @IEEE80211_TXCTL_FIRST_FRAGMENT: this is a first fragment of the frame - * @IEEE80211_TXCTL_LONG_RETRY_LIMIT: this frame should be send using the - * through set_retry_limit configured long - * retry value - * @IEEE80211_TXCTL_EAPOL_FRAME: internal to mac80211 - * @IEEE80211_TXCTL_SEND_AFTER_DTIM: send this frame after DTIM beacon - * @IEEE80211_TXCTL_AMPDU: this frame should be sent as part of an A-MPDU - * @IEEE80211_TXCTL_OFDM_HT: this frame can be sent in HT OFDM rates. number - * of streams when this flag is on can be extracted - * from antenna_sel_tx, so if 1 antenna is marked - * use SISO, 2 antennas marked use MIMO, n antennas - * marked use MIMO_n. - * @IEEE80211_TXCTL_GREEN_FIELD: use green field protection for this frame - * @IEEE80211_TXCTL_40_MHZ_WIDTH: send this frame using 40 Mhz channel width - * @IEEE80211_TXCTL_DUP_DATA: duplicate data frame on both 20 Mhz channels - * @IEEE80211_TXCTL_SHORT_GI: send this frame using short guard interval + * enum mac80211_tx_control_flags - flags to describe transmission information/status + * + * These flags are used with the @flags member of &ieee80211_tx_info. + * + * @IEEE80211_TX_CTL_REQ_TX_STATUS: request TX status callback for this frame. + * @IEEE80211_TX_CTL_DO_NOT_ENCRYPT: send this frame without encryption; + * e.g., for EAPOL frame + * @IEEE80211_TX_CTL_USE_RTS_CTS: use RTS-CTS before sending frame + * @IEEE80211_TX_CTL_USE_CTS_PROTECT: use CTS protection for the frame (e.g., + * for combined 802.11g / 802.11b networks) + * @IEEE80211_TX_CTL_NO_ACK: tell the low level not to wait for an ack + * @IEEE80211_TX_CTL_RATE_CTRL_PROBE: TBD + * @IEEE80211_TX_CTL_CLEAR_PS_FILT: clear powersave filter for destination + * station + * @IEEE80211_TX_CTL_REQUEUE: TBD + * @IEEE80211_TX_CTL_FIRST_FRAGMENT: this is a first fragment of the frame + * @IEEE80211_TX_CTL_SHORT_PREAMBLE: TBD + * @IEEE80211_TX_CTL_LONG_RETRY_LIMIT: this frame should be send using the + * through set_retry_limit configured long retry value + * @IEEE80211_TX_CTL_EAPOL_FRAME: internal to mac80211 + * @IEEE80211_TX_CTL_SEND_AFTER_DTIM: send this frame after DTIM beacon + * @IEEE80211_TX_CTL_AMPDU: this frame should be sent as part of an A-MPDU + * @IEEE80211_TX_CTL_OFDM_HT: this frame can be sent in HT OFDM rates. number + * of streams when this flag is on can be extracted from antenna_sel_tx, + * so if 1 antenna is marked use SISO, 2 antennas marked use MIMO, n + * antennas marked use MIMO_n. + * @IEEE80211_TX_CTL_GREEN_FIELD: use green field protection for this frame + * @IEEE80211_TX_CTL_40_MHZ_WIDTH: send this frame using 40 Mhz channel width + * @IEEE80211_TX_CTL_DUP_DATA: duplicate data frame on both 20 Mhz channels + * @IEEE80211_TX_CTL_SHORT_GI: send this frame using short guard interval + * @IEEE80211_TX_CTL_INJECTED: TBD + * @IEEE80211_TX_STAT_TX_FILTERED: The frame was not transmitted + * because the destination STA was in powersave mode. + * @IEEE80211_TX_STAT_ACK: Frame was acknowledged + * @IEEE80211_TX_STAT_AMPDU: The frame was aggregated, so status + * is for the whole aggregation. + * @IEEE80211_TX_STAT_AMPDU_NO_BACK: no block ack was returned, + * so consider using block ack request (BAR). + * @IEEE80211_TX_CTL_ASSIGN_SEQ: The driver has to assign a sequence + * number to this frame, taking care of not overwriting the fragment + * number and increasing the sequence number only when the + * IEEE80211_TX_CTL_FIRST_FRAGMENT flags is set. mac80211 will properly + * assign sequence numbers to QoS-data frames but cannot do so correctly + * for non-QoS-data and management frames because beacons need them from + * that counter as well and mac80211 cannot guarantee proper sequencing. + * If this flag is set, the driver should instruct the hardware to + * assign a sequence number to the frame or assign one itself. Cf. IEEE + * 802.11-2007 7.1.3.4.1 paragraph 3. This flag will always be set for + * beacons always be clear for frames without a sequence number field. */ enum mac80211_tx_control_flags { - IEEE80211_TXCTL_REQ_TX_STATUS = (1<<0), - IEEE80211_TXCTL_DO_NOT_ENCRYPT = (1<<1), - IEEE80211_TXCTL_USE_RTS_CTS = (1<<2), - IEEE80211_TXCTL_USE_CTS_PROTECT = (1<<3), - IEEE80211_TXCTL_NO_ACK = (1<<4), - IEEE80211_TXCTL_RATE_CTRL_PROBE = (1<<5), - IEEE80211_TXCTL_CLEAR_PS_FILT = (1<<6), - IEEE80211_TXCTL_REQUEUE = (1<<7), - IEEE80211_TXCTL_FIRST_FRAGMENT = (1<<8), - IEEE80211_TXCTL_SHORT_PREAMBLE = (1<<9), - IEEE80211_TXCTL_LONG_RETRY_LIMIT = (1<<10), - IEEE80211_TXCTL_EAPOL_FRAME = (1<<11), - IEEE80211_TXCTL_SEND_AFTER_DTIM = (1<<12), - IEEE80211_TXCTL_AMPDU = (1<<13), - IEEE80211_TXCTL_OFDM_HT = (1<<14), - IEEE80211_TXCTL_GREEN_FIELD = (1<<15), - IEEE80211_TXCTL_40_MHZ_WIDTH = (1<<16), - IEEE80211_TXCTL_DUP_DATA = (1<<17), - IEEE80211_TXCTL_SHORT_GI = (1<<18), + IEEE80211_TX_CTL_REQ_TX_STATUS = BIT(0), + IEEE80211_TX_CTL_DO_NOT_ENCRYPT = BIT(1), + IEEE80211_TX_CTL_USE_RTS_CTS = BIT(2), + IEEE80211_TX_CTL_USE_CTS_PROTECT = BIT(3), + IEEE80211_TX_CTL_NO_ACK = BIT(4), + IEEE80211_TX_CTL_RATE_CTRL_PROBE = BIT(5), + IEEE80211_TX_CTL_CLEAR_PS_FILT = BIT(6), + IEEE80211_TX_CTL_REQUEUE = BIT(7), + IEEE80211_TX_CTL_FIRST_FRAGMENT = BIT(8), + IEEE80211_TX_CTL_SHORT_PREAMBLE = BIT(9), + IEEE80211_TX_CTL_LONG_RETRY_LIMIT = BIT(10), + IEEE80211_TX_CTL_EAPOL_FRAME = BIT(11), + IEEE80211_TX_CTL_SEND_AFTER_DTIM = BIT(12), + IEEE80211_TX_CTL_AMPDU = BIT(13), + IEEE80211_TX_CTL_OFDM_HT = BIT(14), + IEEE80211_TX_CTL_GREEN_FIELD = BIT(15), + IEEE80211_TX_CTL_40_MHZ_WIDTH = BIT(16), + IEEE80211_TX_CTL_DUP_DATA = BIT(17), + IEEE80211_TX_CTL_SHORT_GI = BIT(18), + IEEE80211_TX_CTL_INJECTED = BIT(19), + IEEE80211_TX_STAT_TX_FILTERED = BIT(20), + IEEE80211_TX_STAT_ACK = BIT(21), + IEEE80211_TX_STAT_AMPDU = BIT(22), + IEEE80211_TX_STAT_AMPDU_NO_BACK = BIT(23), + IEEE80211_TX_CTL_ASSIGN_SEQ = BIT(24), }; -/* Transmit control fields. This data structure is passed to low-level driver - * with each TX frame. The low-level driver is responsible for configuring - * the hardware to use given values (depending on what is supported). */ -struct ieee80211_tx_control { - struct ieee80211_vif *vif; - struct ieee80211_rate *tx_rate; - - /* Transmit rate for RTS/CTS frame */ - struct ieee80211_rate *rts_cts_rate; - - /* retry rate for the last retries */ - struct ieee80211_rate *alt_retry_rate; - - u32 flags; /* tx control flags defined above */ - u8 key_idx; /* keyidx from hw->set_key(), undefined if - * IEEE80211_TXCTL_DO_NOT_ENCRYPT is set */ - u8 retry_limit; /* 1 = only first attempt, 2 = one retry, .. - * This could be used when set_retry_limit - * is not implemented by the driver */ - u8 antenna_sel_tx; /* 0 = default/diversity, otherwise bit - * position represents antenna number used */ - u8 icv_len; /* length of the ICV/MIC field in octets */ - u8 iv_len; /* length of the IV field in octets */ - u8 queue; /* hardware queue to use for this frame; - * 0 = highest, hw->queues-1 = lowest */ - u16 aid; /* Station AID */ - int type; /* internal */ +#define IEEE80211_TX_INFO_DRIVER_DATA_SIZE \ + (sizeof(((struct sk_buff *)0)->cb) - 8) +#define IEEE80211_TX_INFO_DRIVER_DATA_PTRS \ + (IEEE80211_TX_INFO_DRIVER_DATA_SIZE / sizeof(void *)) + +/** + * struct ieee80211_tx_info - skb transmit information + * + * This structure is placed in skb->cb for three uses: + * (1) mac80211 TX control - mac80211 tells the driver what to do + * (2) driver internal use (if applicable) + * (3) TX status information - driver tells mac80211 what happened + * + * @flags: transmit info flags, defined above + * @band: TBD + * @tx_rate_idx: TBD + * @antenna_sel_tx: TBD + * @control: union for control data + * @status: union for status data + * @driver_data: array of driver_data pointers + * @retry_count: number of retries + * @excessive_retries: set to 1 if the frame was retried many times + * but not acknowledged + * @ampdu_ack_len: number of aggregated frames. + * relevant only if IEEE80211_TX_STATUS_AMPDU was set. + * @ampdu_ack_map: block ack bit map for the aggregation. + * relevant only if IEEE80211_TX_STATUS_AMPDU was set. + * @ack_signal: signal strength of the ACK frame + */ +struct ieee80211_tx_info { + /* common information */ + u32 flags; + u8 band; + s8 tx_rate_idx; + u8 antenna_sel_tx; + + /* 1 byte hole */ + + union { + struct { + struct ieee80211_vif *vif; + struct ieee80211_key_conf *hw_key; + unsigned long jiffies; + int ifindex; + u16 aid; + s8 rts_cts_rate_idx, alt_retry_rate_idx; + u8 retry_limit; + u8 icv_len; + u8 iv_len; + } control; + struct { + u64 ampdu_ack_map; + int ack_signal; + u8 retry_count; + bool excessive_retries; + u8 ampdu_ack_len; + } status; + void *driver_data[IEEE80211_TX_INFO_DRIVER_DATA_PTRS]; + }; }; +static inline struct ieee80211_tx_info *IEEE80211_SKB_CB(struct sk_buff *skb) +{ + return (struct ieee80211_tx_info *)skb->cb; +} + /** * enum mac80211_rx_flags - receive flags @@ -353,13 +385,16 @@ enum mac80211_rx_flags { * The low-level driver should provide this information (the subset * supported by hardware) to the 802.11 code with each received * frame. + * * @mactime: value in microseconds of the 64-bit Time Synchronization Function * (TSF) timer when the first data symbol (MPDU) arrived at the hardware. * @band: the active band when this frame was received * @freq: frequency the radio was tuned to when receiving this frame, in MHz - * @ssi: signal strength when receiving this frame - * @signal: used as 'qual' in statistics reporting - * @noise: PHY noise when receiving this frame + * @signal: signal strength when receiving this frame, either in dBm, in dB or + * unspecified depending on the hardware capabilities flags + * @IEEE80211_HW_SIGNAL_* + * @noise: noise when receiving this frame, in dBm. + * @qual: overall signal quality indication, in percent (0-100). * @antenna: antenna used * @rate_idx: index of data rate into band's supported rates * @flag: %RX_FLAG_* @@ -368,64 +403,15 @@ struct ieee80211_rx_status { u64 mactime; enum ieee80211_band band; int freq; - int ssi; int signal; int noise; + int qual; int antenna; int rate_idx; int flag; }; /** - * enum ieee80211_tx_status_flags - transmit status flags - * - * Status flags to indicate various transmit conditions. - * - * @IEEE80211_TX_STATUS_TX_FILTERED: The frame was not transmitted - * because the destination STA was in powersave mode. - * @IEEE80211_TX_STATUS_ACK: Frame was acknowledged - * @IEEE80211_TX_STATUS_AMPDU: The frame was aggregated, so status - * is for the whole aggregation. - */ -enum ieee80211_tx_status_flags { - IEEE80211_TX_STATUS_TX_FILTERED = 1<<0, - IEEE80211_TX_STATUS_ACK = 1<<1, - IEEE80211_TX_STATUS_AMPDU = 1<<2, -}; - -/** - * struct ieee80211_tx_status - transmit status - * - * As much information as possible should be provided for each transmitted - * frame with ieee80211_tx_status(). - * - * @control: a copy of the &struct ieee80211_tx_control passed to the driver - * in the tx() callback. - * @flags: transmit status flags, defined above - * @retry_count: number of retries - * @excessive_retries: set to 1 if the frame was retried many times - * but not acknowledged - * @ampdu_ack_len: number of aggregated frames. - * relevant only if IEEE80211_TX_STATUS_AMPDU was set. - * @ampdu_ack_map: block ack bit map for the aggregation. - * relevant only if IEEE80211_TX_STATUS_AMPDU was set. - * @ack_signal: signal strength of the ACK frame - * @queue_length: ?? REMOVE - * @queue_number: ?? REMOVE - */ -struct ieee80211_tx_status { - struct ieee80211_tx_control control; - u8 flags; - u8 retry_count; - bool excessive_retries; - u8 ampdu_ack_len; - u64 ampdu_ack_map; - int ack_signal; - int queue_length; - int queue_number; -}; - -/** * enum ieee80211_conf_flags - configuration flags * * Flags to define PHY configuration options @@ -433,11 +419,13 @@ struct ieee80211_tx_status { * @IEEE80211_CONF_SHORT_SLOT_TIME: use 802.11g short slot time * @IEEE80211_CONF_RADIOTAP: add radiotap header at receive time (if supported) * @IEEE80211_CONF_SUPPORT_HT_MODE: use 802.11n HT capabilities (if supported) + * @IEEE80211_CONF_PS: Enable 802.11 power save mode */ enum ieee80211_conf_flags { IEEE80211_CONF_SHORT_SLOT_TIME = (1<<0), IEEE80211_CONF_RADIOTAP = (1<<1), IEEE80211_CONF_SUPPORT_HT_MODE = (1<<2), + IEEE80211_CONF_PS = (1<<3), }; /** @@ -553,34 +541,38 @@ struct ieee80211_if_init_conf { }; /** + * enum ieee80211_if_conf_change - interface config change flags + * + * @IEEE80211_IFCC_BSSID: The BSSID changed. + * @IEEE80211_IFCC_SSID: The SSID changed. + * @IEEE80211_IFCC_BEACON: The beacon for this interface changed + * (currently AP and MESH only), use ieee80211_beacon_get(). + */ +enum ieee80211_if_conf_change { + IEEE80211_IFCC_BSSID = BIT(0), + IEEE80211_IFCC_SSID = BIT(1), + IEEE80211_IFCC_BEACON = BIT(2), +}; + +/** * struct ieee80211_if_conf - configuration of an interface * - * @type: type of the interface. This is always the same as was specified in - * &struct ieee80211_if_init_conf. The type of an interface never changes - * during the life of the interface; this field is present only for - * convenience. + * @changed: parameters that have changed, see &enum ieee80211_if_conf_change. * @bssid: BSSID of the network we are associated to/creating. * @ssid: used (together with @ssid_len) by drivers for hardware that * generate beacons independently. The pointer is valid only during the * config_interface() call, so copy the value somewhere if you need * it. * @ssid_len: length of the @ssid field. - * @beacon: beacon template. Valid only if @host_gen_beacon_template in - * &struct ieee80211_hw is set. The driver is responsible of freeing - * the sk_buff. - * @beacon_control: tx_control for the beacon template, this field is only - * valid when the @beacon field was set. * * This structure is passed to the config_interface() callback of * &struct ieee80211_hw. */ struct ieee80211_if_conf { - int type; + u32 changed; u8 *bssid; u8 *ssid; size_t ssid_len; - struct sk_buff *beacon; - struct ieee80211_tx_control *beacon_control; }; /** @@ -597,8 +589,8 @@ enum ieee80211_key_alg { /** * enum ieee80211_key_len - key length - * @WEP40: WEP 5 byte long key - * @WEP104: WEP 13 byte long key + * @LEN_WEP40: WEP 5-byte long key + * @LEN_WEP104: WEP 13-byte long key */ enum ieee80211_key_len { LEN_WEP40 = 5, @@ -619,11 +611,14 @@ enum ieee80211_key_len { * @IEEE80211_KEY_FLAG_GENERATE_MMIC: This flag should be set by * the driver for a TKIP key if it requires Michael MIC * generation in software. + * @IEEE80211_KEY_FLAG_PAIRWISE: Set by mac80211, this flag indicates + * that the key is pairwise rather then a shared key. */ enum ieee80211_key_flags { IEEE80211_KEY_FLAG_WMM_STA = 1<<0, IEEE80211_KEY_FLAG_GENERATE_IV = 1<<1, IEEE80211_KEY_FLAG_GENERATE_MMIC= 1<<2, + IEEE80211_KEY_FLAG_PAIRWISE = 1<<3, }; /** @@ -639,7 +634,12 @@ enum ieee80211_key_flags { * @flags: key flags, see &enum ieee80211_key_flags. * @keyidx: the key index (0-3) * @keylen: key material length - * @key: key material + * @key: key material. For ALG_TKIP the key is encoded as a 256-bit (32 byte) + * data block: + * - Temporal Encryption Key (128 bits) + * - Temporal Authenticator Tx MIC Key (64 bits) + * - Temporal Authenticator Rx MIC Key (64 bits) + * */ struct ieee80211_key_conf { enum ieee80211_key_alg alg; @@ -667,7 +667,7 @@ enum set_key_cmd { * enum sta_notify_cmd - sta notify command * * Used with the sta_notify() callback in &struct ieee80211_ops, this - * indicates addition and removal of a station to station table + * indicates addition and removal of a station to station table. * * @STA_NOTIFY_ADD: a station was added to the station table * @STA_NOTIFY_REMOVE: a station being removed from the station table @@ -700,15 +700,6 @@ enum ieee80211_tkip_key_type { * any particular flags. There are some exceptions to this rule, * however, so you are advised to review these flags carefully. * - * @IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE: - * The device only needs to be supplied with a beacon template. - * If you need the host to generate each beacon then don't use - * this flag and call ieee80211_beacon_get() when you need the - * next beacon frame. Note that if you set this flag, you must - * implement the set_tim() callback for powersave mode to work - * properly. - * This flag is only relevant for access-point mode. - * * @IEEE80211_HW_RX_INCLUDES_FCS: * Indicates that received frames passed to the stack include * the FCS at the end. @@ -730,6 +721,29 @@ enum ieee80211_tkip_key_type { * @IEEE80211_HW_2GHZ_SHORT_PREAMBLE_INCAPABLE: * Hardware is not capable of receiving frames with short preamble on * the 2.4 GHz band. + * + * @IEEE80211_HW_SIGNAL_UNSPEC: + * Hardware can provide signal values but we don't know its units. We + * expect values between 0 and @max_signal. + * If possible please provide dB or dBm instead. + * + * @IEEE80211_HW_SIGNAL_DB: + * Hardware gives signal values in dB, decibel difference from an + * arbitrary, fixed reference. We expect values between 0 and @max_signal. + * If possible please provide dBm instead. + * + * @IEEE80211_HW_SIGNAL_DBM: + * Hardware gives signal values in dBm, decibel difference from + * one milliwatt. This is the preferred method since it is standardized + * between different devices. @max_signal does not need to be set. + * + * @IEEE80211_HW_NOISE_DBM: + * Hardware can provide noise (radio interference) values in units dBm, + * decibel difference from one milliwatt. + * + * @IEEE80211_HW_SPECTRUM_MGMT: + * Hardware supports spectrum management defined in 802.11h + * Measurement, Channel Switch, Quieting, TPC */ enum ieee80211_hw_flags { IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE = 1<<0, @@ -737,6 +751,11 @@ enum ieee80211_hw_flags { IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING = 1<<2, IEEE80211_HW_2GHZ_SHORT_SLOT_INCAPABLE = 1<<3, IEEE80211_HW_2GHZ_SHORT_PREAMBLE_INCAPABLE = 1<<4, + IEEE80211_HW_SIGNAL_UNSPEC = 1<<5, + IEEE80211_HW_SIGNAL_DB = 1<<6, + IEEE80211_HW_SIGNAL_DBM = 1<<7, + IEEE80211_HW_NOISE_DBM = 1<<8, + IEEE80211_HW_SPECTRUM_MGMT = 1<<9, }; /** @@ -754,8 +773,11 @@ enum ieee80211_hw_flags { * @conf: &struct ieee80211_conf, device configuration, don't use. * * @workqueue: single threaded workqueue available for driver use, - * allocated by mac80211 on registration and flushed on - * unregistration. + * allocated by mac80211 on registration and flushed when an + * interface is removed. + * NOTICE: All work performed on this workqueue should NEVER + * acquire the RTNL lock (i.e. Don't use the function + * ieee80211_iterate_active_interfaces()) * * @priv: pointer to private area that was allocated for driver use * along with this structure. @@ -767,15 +789,18 @@ enum ieee80211_hw_flags { * * @channel_change_time: time (in microseconds) it takes to change channels. * - * @max_rssi: Maximum value for ssi in RX information, use - * negative numbers for dBm and 0 to indicate no support. - * - * @max_signal: like @max_rssi, but for the signal value. - * - * @max_noise: like @max_rssi, but for the noise value. + * @max_signal: Maximum value for signal (rssi) in RX information, used + * only when @IEEE80211_HW_SIGNAL_UNSPEC or @IEEE80211_HW_SIGNAL_DB * * @queues: number of available hardware transmit queues for - * data packets. WMM/QoS requires at least four. + * data packets. WMM/QoS requires at least four, these + * queues need to have configurable access parameters. + * + * @ampdu_queues: number of available hardware transmit queues + * for A-MPDU packets, these have no access parameters + * because they're used only for A-MPDU frames. Note that + * mac80211 will not currently use any of the regular queues + * for aggregation. * * @rate_control_algorithm: rate control algorithm for this hardware. * If unset (NULL), the default algorithm will be used. Must be @@ -794,10 +819,8 @@ struct ieee80211_hw { unsigned int extra_tx_headroom; int channel_change_time; int vif_data_size; - u8 queues; - s8 max_rssi; + u16 queues, ampdu_queues; s8 max_signal; - s8 max_noise; }; /** @@ -822,6 +845,43 @@ static inline void SET_IEEE80211_PERM_ADDR(struct ieee80211_hw *hw, u8 *addr) memcpy(hw->wiphy->perm_addr, addr, ETH_ALEN); } +static inline int ieee80211_num_regular_queues(struct ieee80211_hw *hw) +{ + return hw->queues; +} + +static inline int ieee80211_num_queues(struct ieee80211_hw *hw) +{ + return hw->queues + hw->ampdu_queues; +} + +static inline struct ieee80211_rate * +ieee80211_get_tx_rate(const struct ieee80211_hw *hw, + const struct ieee80211_tx_info *c) +{ + if (WARN_ON(c->tx_rate_idx < 0)) + return NULL; + return &hw->wiphy->bands[c->band]->bitrates[c->tx_rate_idx]; +} + +static inline struct ieee80211_rate * +ieee80211_get_rts_cts_rate(const struct ieee80211_hw *hw, + const struct ieee80211_tx_info *c) +{ + if (c->control.rts_cts_rate_idx < 0) + return NULL; + return &hw->wiphy->bands[c->band]->bitrates[c->control.rts_cts_rate_idx]; +} + +static inline struct ieee80211_rate * +ieee80211_get_alt_retry_rate(const struct ieee80211_hw *hw, + const struct ieee80211_tx_info *c) +{ + if (c->control.alt_retry_rate_idx < 0) + return NULL; + return &hw->wiphy->bands[c->band]->bitrates[c->control.alt_retry_rate_idx]; +} + /** * DOC: Hardware crypto acceleration * @@ -979,8 +1039,10 @@ enum ieee80211_ampdu_mlme_action { * @tx: Handler that 802.11 module calls for each transmitted frame. * skb contains the buffer starting from the IEEE 802.11 header. * The low-level driver should send the frame out based on - * configuration in the TX control data. Must be implemented and - * atomic. + * configuration in the TX control data. This handler should, + * preferably, never fail and stop queues appropriately, more + * importantly, however, it must never fail for A-MPDU-queues. + * Must be implemented and atomic. * * @start: Called before the first netdevice attached to the hardware * is enabled. This should turn on the hardware and must turn on @@ -1072,15 +1134,13 @@ enum ieee80211_ampdu_mlme_action { * of assocaited station or AP. * * @conf_tx: Configure TX queue parameters (EDCF (aifs, cw_min, cw_max), - * bursting) for a hardware TX queue. The @queue parameter uses the - * %IEEE80211_TX_QUEUE_* constants. Must be atomic. + * bursting) for a hardware TX queue. Must be atomic. * * @get_tx_stats: Get statistics of the current TX queue status. This is used * to get number of currently queued packets (queue length), maximum queue * size (limit), and total number of packets sent using each TX queue - * (count). This information is used for WMM to find out which TX - * queues have room for more packets and by hostapd to provide - * statistics about the current queueing state to external programs. + * (count). The 'stats' pointer points to an array that has hw->queues + + * hw->ampdu_queues items. * * @get_tsf: Get the current TSF timer value from firmware/hardware. Currently, * this is only used for IBSS mode debugging and, as such, is not a @@ -1091,17 +1151,6 @@ enum ieee80211_ampdu_mlme_action { * function is optional if the firmware/hardware takes full care of * TSF synchronization. * - * @beacon_update: Setup beacon data for IBSS beacons. Unlike access point, - * IBSS uses a fixed beacon frame which is configured using this - * function. - * If the driver returns success (0) from this callback, it owns - * the skb. That means the driver is responsible to kfree_skb() it. - * The control structure is not dynamically allocated. That means the - * driver does not own the pointer and if it needs it somewhere - * outside of the context of this function, it must copy it - * somewhere else. - * This handler is required only for IBSS mode. - * * @tx_last_beacon: Determine whether the last IBSS beacon was sent by us. * This is needed only for IBSS mode and the result of this function is * used to determine whether to reply to Probe Requests. @@ -1116,8 +1165,7 @@ enum ieee80211_ampdu_mlme_action { * that TX/RX_STOP can pass NULL for this parameter. */ struct ieee80211_ops { - int (*tx)(struct ieee80211_hw *hw, struct sk_buff *skb, - struct ieee80211_tx_control *control); + int (*tx)(struct ieee80211_hw *hw, struct sk_buff *skb); int (*start)(struct ieee80211_hw *hw); void (*stop)(struct ieee80211_hw *hw); int (*add_interface)(struct ieee80211_hw *hw, @@ -1154,15 +1202,12 @@ struct ieee80211_ops { u32 short_retry, u32 long_retr); void (*sta_notify)(struct ieee80211_hw *hw, struct ieee80211_vif *vif, enum sta_notify_cmd, const u8 *addr); - int (*conf_tx)(struct ieee80211_hw *hw, int queue, + int (*conf_tx)(struct ieee80211_hw *hw, u16 queue, const struct ieee80211_tx_queue_params *params); int (*get_tx_stats)(struct ieee80211_hw *hw, struct ieee80211_tx_queue_stats *stats); u64 (*get_tsf)(struct ieee80211_hw *hw); void (*reset_tsf)(struct ieee80211_hw *hw); - int (*beacon_update)(struct ieee80211_hw *hw, - struct sk_buff *skb, - struct ieee80211_tx_control *control); int (*tx_last_beacon)(struct ieee80211_hw *hw); int (*ampdu_action)(struct ieee80211_hw *hw, enum ieee80211_ampdu_mlme_action action, @@ -1292,7 +1337,7 @@ void ieee80211_unregister_hw(struct ieee80211_hw *hw); * * This function frees everything that was allocated, including the * private data for the driver. You must call ieee80211_unregister_hw() - * before calling this function + * before calling this function. * * @hw: the hardware to free */ @@ -1358,16 +1403,12 @@ void ieee80211_rx_irqsafe(struct ieee80211_hw *hw, * * @hw: the hardware the frame was transmitted by * @skb: the frame that was transmitted, owned by mac80211 after this call - * @status: status information for this frame; the status pointer need not - * be valid after this function returns and is not freed by mac80211, - * it is recommended that it points to a stack area */ void ieee80211_tx_status(struct ieee80211_hw *hw, - struct sk_buff *skb, - struct ieee80211_tx_status *status); + struct sk_buff *skb); /** - * ieee80211_tx_status_irqsafe - irq-safe transmit status callback + * ieee80211_tx_status_irqsafe - IRQ-safe transmit status callback * * Like ieee80211_tx_status() but can be called in IRQ context * (internally defers to a tasklet.) @@ -1377,13 +1418,9 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, * * @hw: the hardware the frame was transmitted by * @skb: the frame that was transmitted, owned by mac80211 after this call - * @status: status information for this frame; the status pointer need not - * be valid after this function returns and is not freed by mac80211, - * it is recommended that it points to a stack area */ void ieee80211_tx_status_irqsafe(struct ieee80211_hw *hw, - struct sk_buff *skb, - struct ieee80211_tx_status *status); + struct sk_buff *skb); /** * ieee80211_beacon_get - beacon generation function @@ -1399,8 +1436,7 @@ void ieee80211_tx_status_irqsafe(struct ieee80211_hw *hw, * is responsible of freeing it. */ struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct ieee80211_tx_control *control); + struct ieee80211_vif *vif); /** * ieee80211_rts_get - RTS frame generation function @@ -1408,7 +1444,7 @@ struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw, * @vif: &struct ieee80211_vif pointer from &struct ieee80211_if_init_conf. * @frame: pointer to the frame that is going to be protected by the RTS. * @frame_len: the frame length (in octets). - * @frame_txctl: &struct ieee80211_tx_control of the frame. + * @frame_txctl: &struct ieee80211_tx_info of the frame. * @rts: The buffer where to store the RTS frame. * * If the RTS frames are generated by the host system (i.e., not in @@ -1418,7 +1454,7 @@ struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw, */ void ieee80211_rts_get(struct ieee80211_hw *hw, struct ieee80211_vif *vif, const void *frame, size_t frame_len, - const struct ieee80211_tx_control *frame_txctl, + const struct ieee80211_tx_info *frame_txctl, struct ieee80211_rts *rts); /** @@ -1426,7 +1462,7 @@ void ieee80211_rts_get(struct ieee80211_hw *hw, struct ieee80211_vif *vif, * @hw: pointer obtained from ieee80211_alloc_hw(). * @vif: &struct ieee80211_vif pointer from &struct ieee80211_if_init_conf. * @frame_len: the length of the frame that is going to be protected by the RTS. - * @frame_txctl: &struct ieee80211_tx_control of the frame. + * @frame_txctl: &struct ieee80211_tx_info of the frame. * * If the RTS is generated in firmware, but the host system must provide * the duration field, the low-level driver uses this function to receive @@ -1434,7 +1470,7 @@ void ieee80211_rts_get(struct ieee80211_hw *hw, struct ieee80211_vif *vif, */ __le16 ieee80211_rts_duration(struct ieee80211_hw *hw, struct ieee80211_vif *vif, size_t frame_len, - const struct ieee80211_tx_control *frame_txctl); + const struct ieee80211_tx_info *frame_txctl); /** * ieee80211_ctstoself_get - CTS-to-self frame generation function @@ -1442,7 +1478,7 @@ __le16 ieee80211_rts_duration(struct ieee80211_hw *hw, * @vif: &struct ieee80211_vif pointer from &struct ieee80211_if_init_conf. * @frame: pointer to the frame that is going to be protected by the CTS-to-self. * @frame_len: the frame length (in octets). - * @frame_txctl: &struct ieee80211_tx_control of the frame. + * @frame_txctl: &struct ieee80211_tx_info of the frame. * @cts: The buffer where to store the CTS-to-self frame. * * If the CTS-to-self frames are generated by the host system (i.e., not in @@ -1453,7 +1489,7 @@ __le16 ieee80211_rts_duration(struct ieee80211_hw *hw, void ieee80211_ctstoself_get(struct ieee80211_hw *hw, struct ieee80211_vif *vif, const void *frame, size_t frame_len, - const struct ieee80211_tx_control *frame_txctl, + const struct ieee80211_tx_info *frame_txctl, struct ieee80211_cts *cts); /** @@ -1461,7 +1497,7 @@ void ieee80211_ctstoself_get(struct ieee80211_hw *hw, * @hw: pointer obtained from ieee80211_alloc_hw(). * @vif: &struct ieee80211_vif pointer from &struct ieee80211_if_init_conf. * @frame_len: the length of the frame that is going to be protected by the CTS-to-self. - * @frame_txctl: &struct ieee80211_tx_control of the frame. + * @frame_txctl: &struct ieee80211_tx_info of the frame. * * If the CTS-to-self is generated in firmware, but the host system must provide * the duration field, the low-level driver uses this function to receive @@ -1470,7 +1506,7 @@ void ieee80211_ctstoself_get(struct ieee80211_hw *hw, __le16 ieee80211_ctstoself_duration(struct ieee80211_hw *hw, struct ieee80211_vif *vif, size_t frame_len, - const struct ieee80211_tx_control *frame_txctl); + const struct ieee80211_tx_info *frame_txctl); /** * ieee80211_generic_frame_duration - Calculate the duration field for a frame @@ -1509,8 +1545,7 @@ __le16 ieee80211_generic_frame_duration(struct ieee80211_hw *hw, * use common code for all beacons. */ struct sk_buff * -ieee80211_get_buffered_bc(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - struct ieee80211_tx_control *control); +ieee80211_get_buffered_bc(struct ieee80211_hw *hw, struct ieee80211_vif *vif); /** * ieee80211_get_hdrlen_from_skb - get header length from data @@ -1522,7 +1557,7 @@ ieee80211_get_buffered_bc(struct ieee80211_hw *hw, struct ieee80211_vif *vif, * * @skb: the frame */ -int ieee80211_get_hdrlen_from_skb(const struct sk_buff *skb); +unsigned int ieee80211_get_hdrlen_from_skb(const struct sk_buff *skb); /** * ieee80211_get_hdrlen - get header length from frame control @@ -1535,6 +1570,12 @@ int ieee80211_get_hdrlen_from_skb(const struct sk_buff *skb); int ieee80211_get_hdrlen(u16 fc); /** + * 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 @@ -1545,6 +1586,8 @@ int ieee80211_get_hdrlen(u16 fc); * @keyconf: the parameter passed with the set key * @skb: the skb for which the key is needed * @rc4key: a buffer to which the key will be written + * @type: TBD + * @key: TBD */ void ieee80211_get_tkip_key(struct ieee80211_key_conf *keyconf, struct sk_buff *skb, @@ -1568,14 +1611,6 @@ void ieee80211_wake_queue(struct ieee80211_hw *hw, int queue); void ieee80211_stop_queue(struct ieee80211_hw *hw, int queue); /** - * ieee80211_start_queues - start all queues - * @hw: pointer to as obtained from ieee80211_alloc_hw(). - * - * Drivers should use this function instead of netif_start_queue. - */ -void ieee80211_start_queues(struct ieee80211_hw *hw); - -/** * ieee80211_stop_queues - stop all queues * @hw: pointer as obtained from ieee80211_alloc_hw(). * @@ -1603,7 +1638,7 @@ void ieee80211_wake_queues(struct ieee80211_hw *hw); void ieee80211_scan_completed(struct ieee80211_hw *hw); /** - * ieee80211_iterate_active_interfaces- iterate active interfaces + * ieee80211_iterate_active_interfaces - iterate active interfaces * * This function iterates over the interfaces associated with a given * hardware that are currently active and calls the callback for them. @@ -1670,7 +1705,7 @@ void ieee80211_start_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u16 tid); * * This function must be called by low level driver once it has * finished with preparations for the BA session. - * This version of the function is irq safe. + * This version of the function is IRQ-safe. */ void ieee80211_start_tx_ba_cb_irqsafe(struct ieee80211_hw *hw, const u8 *ra, u16 tid); @@ -1710,7 +1745,7 @@ void ieee80211_stop_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u8 tid); * * This function must be called by low level driver once it has * finished with preparations for the BA session tear down. - * This version of the function is irq safe. + * This version of the function is IRQ-safe. */ void ieee80211_stop_tx_ba_cb_irqsafe(struct ieee80211_hw *hw, const u8 *ra, u16 tid); @@ -1718,7 +1753,7 @@ void ieee80211_stop_tx_ba_cb_irqsafe(struct ieee80211_hw *hw, const u8 *ra, /** * ieee80211_notify_mac - low level driver notification * @hw: pointer as obtained from ieee80211_alloc_hw(). - * @notification_types: enum ieee80211_notification_types + * @notif_type: enum ieee80211_notification_types * * This function must be called by low level driver to inform mac80211 of * low level driver status change or force mac80211 to re-assoc for low diff --git a/include/net/neighbour.h b/include/net/neighbour.h index dc420fecafb9..aa4b708654a4 100644 --- a/include/net/neighbour.h +++ b/include/net/neighbour.h @@ -75,7 +75,7 @@ struct neigh_statistics unsigned long destroys; /* number of destroyed neighs */ unsigned long hash_grows; /* number of hash resizes */ - unsigned long res_failed; /* nomber of failed resolutions */ + unsigned long res_failed; /* number of failed resolutions */ unsigned long lookups; /* number of lookups */ unsigned long hits; /* number of hits (among lookups) */ @@ -85,6 +85,8 @@ struct neigh_statistics unsigned long periodic_gc_runs; /* number of periodic GC runs */ unsigned long forced_gc_runs; /* number of forced GC runs */ + + unsigned long unres_discards; /* number of unresolved drops */ }; #define NEIGH_CACHE_STAT_INC(tbl, field) \ diff --git a/include/net/net_namespace.h b/include/net/net_namespace.h index d9dd0f707296..3855620b78a9 100644 --- a/include/net/net_namespace.h +++ b/include/net/net_namespace.h @@ -9,6 +9,7 @@ #include <linux/list.h> #include <net/netns/core.h> +#include <net/netns/mib.h> #include <net/netns/unix.h> #include <net/netns/packet.h> #include <net/netns/ipv4.h> @@ -52,6 +53,7 @@ struct net { struct sock *rtnl; /* rtnetlink socket */ struct netns_core core; + struct netns_mib mib; struct netns_packet packet; struct netns_unix unx; struct netns_ipv4 ipv4; @@ -212,8 +214,11 @@ extern void unregister_pernet_gen_device(int id, struct pernet_operations *); struct ctl_path; struct ctl_table; struct ctl_table_header; + extern struct ctl_table_header *register_net_sysctl_table(struct net *net, const struct ctl_path *path, struct ctl_table *table); +extern struct ctl_table_header *register_net_sysctl_rotable( + const struct ctl_path *path, struct ctl_table *table); extern void unregister_net_sysctl_table(struct ctl_table_header *header); #endif /* __NET_NET_NAMESPACE_H */ diff --git a/include/net/netfilter/ipv4/nf_conntrack_ipv4.h b/include/net/netfilter/ipv4/nf_conntrack_ipv4.h index 9bf059817aec..7573d52a4346 100644 --- a/include/net/netfilter/ipv4/nf_conntrack_ipv4.h +++ b/include/net/netfilter/ipv4/nf_conntrack_ipv4.h @@ -9,8 +9,6 @@ #ifndef _NF_CONNTRACK_IPV4_H #define _NF_CONNTRACK_IPV4_H -/* Returns new sk_buff, or NULL */ -struct sk_buff *nf_ct_ipv4_ct_gather_frags(struct sk_buff *skb); extern struct nf_conntrack_l3proto nf_conntrack_l3proto_ipv4; diff --git a/include/net/netfilter/nf_conntrack.h b/include/net/netfilter/nf_conntrack.h index 2dbd6c015b94..8f5b75734dd0 100644 --- a/include/net/netfilter/nf_conntrack.h +++ b/include/net/netfilter/nf_conntrack.h @@ -223,6 +223,25 @@ static inline void nf_ct_refresh(struct nf_conn *ct, __nf_ct_refresh_acct(ct, 0, skb, extra_jiffies, 0); } +extern bool __nf_ct_kill_acct(struct nf_conn *ct, + enum ip_conntrack_info ctinfo, + const struct sk_buff *skb, + int do_acct); + +/* kill conntrack and do accounting */ +static inline bool nf_ct_kill_acct(struct nf_conn *ct, + enum ip_conntrack_info ctinfo, + const struct sk_buff *skb) +{ + return __nf_ct_kill_acct(ct, ctinfo, skb, 1); +} + +/* kill conntrack without accounting */ +static inline bool nf_ct_kill(struct nf_conn *ct) +{ + return __nf_ct_kill_acct(ct, 0, NULL, 0); +} + /* These are for NAT. Icky. */ /* Update TCP window tracking data when NAT mangles the packet */ extern void nf_conntrack_tcp_update(const struct sk_buff *skb, @@ -239,7 +258,8 @@ nf_ct_iterate_cleanup(int (*iter)(struct nf_conn *i, void *data), void *data); extern void nf_conntrack_free(struct nf_conn *ct); extern struct nf_conn * nf_conntrack_alloc(const struct nf_conntrack_tuple *orig, - const struct nf_conntrack_tuple *repl); + const struct nf_conntrack_tuple *repl, + gfp_t gfp); /* It's confirmed if it is, or has been in the hash table. */ static inline int nf_ct_is_confirmed(struct nf_conn *ct) diff --git a/include/net/netns/hash.h b/include/net/netns/hash.h new file mode 100644 index 000000000000..548d78f2cc47 --- /dev/null +++ b/include/net/netns/hash.h @@ -0,0 +1,21 @@ +#ifndef __NET_NS_HASH_H__ +#define __NET_NS_HASH_H__ + +#include <asm/cache.h> + +struct net; + +static inline unsigned net_hash_mix(struct net *net) +{ +#ifdef CONFIG_NET_NS + /* + * shift this right to eliminate bits, that are + * always zeroed + */ + + return (unsigned)(((unsigned long)net) >> L1_CACHE_SHIFT); +#else + return 0; +#endif +} +#endif diff --git a/include/net/netns/ipv4.h b/include/net/netns/ipv4.h index 34ee348a2cf2..a6ed83853dcc 100644 --- a/include/net/netns/ipv4.h +++ b/include/net/netns/ipv4.h @@ -18,6 +18,7 @@ struct netns_ipv4 { struct ctl_table_header *forw_hdr; struct ctl_table_header *frags_hdr; struct ctl_table_header *ipv4_hdr; + struct ctl_table_header *route_hdr; #endif struct ipv4_devconf *devconf_all; struct ipv4_devconf *devconf_dflt; @@ -36,6 +37,7 @@ struct netns_ipv4 { struct xt_table *iptable_mangle; struct xt_table *iptable_raw; struct xt_table *arptable_filter; + struct xt_table *iptable_security; #endif int sysctl_icmp_echo_ignore_all; @@ -44,5 +46,8 @@ struct netns_ipv4 { int sysctl_icmp_ratelimit; int sysctl_icmp_ratemask; int sysctl_icmp_errors_use_inbound_ifaddr; + + struct timer_list rt_secret_timer; + atomic_t rt_genid; }; #endif diff --git a/include/net/netns/ipv6.h b/include/net/netns/ipv6.h index ac053be6c256..5bacd838e88b 100644 --- a/include/net/netns/ipv6.h +++ b/include/net/netns/ipv6.h @@ -35,6 +35,7 @@ struct netns_ipv6 { struct xt_table *ip6table_filter; struct xt_table *ip6table_mangle; struct xt_table *ip6table_raw; + struct xt_table *ip6table_security; #endif struct rt6_info *ip6_null_entry; struct rt6_statistics *rt6_stats; diff --git a/include/net/netns/mib.h b/include/net/netns/mib.h new file mode 100644 index 000000000000..449147604642 --- /dev/null +++ b/include/net/netns/mib.h @@ -0,0 +1,16 @@ +#ifndef __NETNS_MIB_H__ +#define __NETNS_MIB_H__ + +#include <net/snmp.h> + +struct netns_mib { + DEFINE_SNMP_STAT(struct tcp_mib, tcp_statistics); + DEFINE_SNMP_STAT(struct ipstats_mib, ip_statistics); + DEFINE_SNMP_STAT(struct linux_mib, net_statistics); + DEFINE_SNMP_STAT(struct udp_mib, udp_statistics); + DEFINE_SNMP_STAT(struct udp_mib, udplite_statistics); + DEFINE_SNMP_STAT(struct icmp_mib, icmp_statistics); + DEFINE_SNMP_STAT(struct icmpmsg_mib, icmpmsg_statistics); +}; + +#endif diff --git a/include/net/pkt_sched.h b/include/net/pkt_sched.h index 46fb4d80c74a..6affcfaa123e 100644 --- a/include/net/pkt_sched.h +++ b/include/net/pkt_sched.h @@ -72,6 +72,10 @@ extern void qdisc_watchdog_cancel(struct qdisc_watchdog *wd); extern struct Qdisc_ops pfifo_qdisc_ops; extern struct Qdisc_ops bfifo_qdisc_ops; +extern int fifo_set_limit(struct Qdisc *q, unsigned int limit); +extern struct Qdisc *fifo_create_dflt(struct Qdisc *sch, struct Qdisc_ops *ops, + unsigned int limit); + extern int register_qdisc(struct Qdisc_ops *qops); extern int unregister_qdisc(struct Qdisc_ops *qops); extern struct Qdisc *qdisc_lookup(struct net_device *dev, u32 handle); @@ -79,14 +83,14 @@ extern struct Qdisc *qdisc_lookup_class(struct net_device *dev, u32 handle); extern struct qdisc_rate_table *qdisc_get_rtab(struct tc_ratespec *r, struct nlattr *tab); extern void qdisc_put_rtab(struct qdisc_rate_table *tab); +extern void qdisc_put_stab(struct qdisc_size_table *tab); -extern void __qdisc_run(struct net_device *dev); +extern void __qdisc_run(struct Qdisc *q); -static inline void qdisc_run(struct net_device *dev) +static inline void qdisc_run(struct Qdisc *q) { - if (!netif_queue_stopped(dev) && - !test_and_set_bit(__LINK_STATE_QDISC_RUNNING, &dev->state)) - __qdisc_run(dev); + if (!test_and_set_bit(__QDISC_STATE_RUNNING, &q->state)) + __qdisc_run(q); } extern int tc_classify_compat(struct sk_buff *skb, struct tcf_proto *tp, diff --git a/include/net/rose.h b/include/net/rose.h index e5bb084d8754..cbd5364b2c8a 100644 --- a/include/net/rose.h +++ b/include/net/rose.h @@ -201,7 +201,7 @@ extern void rose_link_device_down(struct net_device *); extern struct net_device *rose_dev_first(void); extern struct net_device *rose_dev_get(rose_address *); extern struct rose_route *rose_route_free_lci(unsigned int, struct rose_neigh *); -extern struct rose_neigh *rose_get_neigh(rose_address *, unsigned char *, unsigned char *); +extern struct rose_neigh *rose_get_neigh(rose_address *, unsigned char *, unsigned char *, int); extern int rose_rt_ioctl(unsigned int, void __user *); extern void rose_link_failed(ax25_cb *, int); extern int rose_route_frame(struct sk_buff *, ax25_cb *); diff --git a/include/net/route.h b/include/net/route.h index fc836ff824cc..3140cc500854 100644 --- a/include/net/route.h +++ b/include/net/route.h @@ -111,7 +111,7 @@ struct in_device; extern int ip_rt_init(void); extern void ip_rt_redirect(__be32 old_gw, __be32 dst, __be32 new_gw, __be32 src, struct net_device *dev); -extern void rt_cache_flush(int how); +extern void rt_cache_flush(struct net *net, int how); extern int __ip_route_output_key(struct net *, struct rtable **, const struct flowi *flp); extern int ip_route_output_key(struct net *, struct rtable **, struct flowi *flp); extern int ip_route_output_flow(struct net *, struct rtable **rp, struct flowi *flp, struct sock *sk, int flags); diff --git a/include/net/sch_generic.h b/include/net/sch_generic.h index a87fc0312edc..b5f40d7ef724 100644 --- a/include/net/sch_generic.h +++ b/include/net/sch_generic.h @@ -23,6 +23,19 @@ struct qdisc_rate_table int refcnt; }; +enum qdisc_state_t +{ + __QDISC_STATE_RUNNING, + __QDISC_STATE_SCHED, +}; + +struct qdisc_size_table { + struct list_head list; + struct tc_sizespec szopts; + int refcnt; + u16 data[]; +}; + struct Qdisc { int (*enqueue)(struct sk_buff *skb, struct Qdisc *dev); @@ -33,21 +46,26 @@ struct Qdisc #define TCQ_F_INGRESS 4 int padded; struct Qdisc_ops *ops; + struct qdisc_size_table *stab; u32 handle; u32 parent; atomic_t refcnt; + unsigned long state; + struct sk_buff *gso_skb; struct sk_buff_head q; - struct net_device *dev; + struct netdev_queue *dev_queue; + struct Qdisc *next_sched; struct list_head list; struct gnet_stats_basic bstats; struct gnet_stats_queue qstats; struct gnet_stats_rate_est rate_est; - spinlock_t *stats_lock; struct rcu_head q_rcu; int (*reshape_fail)(struct sk_buff *skb, struct Qdisc *q); + void *u32_node; + /* This field is deprecated, but it is still used by CBQ * and it will live until better solution will be invented. */ @@ -155,18 +173,96 @@ struct tcf_proto struct tcf_proto_ops *ops; }; +struct qdisc_skb_cb { + unsigned int pkt_len; + char data[]; +}; + +static inline struct qdisc_skb_cb *qdisc_skb_cb(struct sk_buff *skb) +{ + return (struct qdisc_skb_cb *)skb->cb; +} -extern void qdisc_lock_tree(struct net_device *dev); -extern void qdisc_unlock_tree(struct net_device *dev); +static inline spinlock_t *qdisc_lock(struct Qdisc *qdisc) +{ + return &qdisc->q.lock; +} -#define sch_tree_lock(q) qdisc_lock_tree((q)->dev) -#define sch_tree_unlock(q) qdisc_unlock_tree((q)->dev) -#define tcf_tree_lock(tp) qdisc_lock_tree((tp)->q->dev) -#define tcf_tree_unlock(tp) qdisc_unlock_tree((tp)->q->dev) +static inline struct Qdisc *qdisc_root(struct Qdisc *qdisc) +{ + return qdisc->dev_queue->qdisc; +} + +static inline spinlock_t *qdisc_root_lock(struct Qdisc *qdisc) +{ + struct Qdisc *root = qdisc_root(qdisc); + + return qdisc_lock(root); +} + +static inline struct net_device *qdisc_dev(struct Qdisc *qdisc) +{ + return qdisc->dev_queue->dev; +} + +static inline void sch_tree_lock(struct Qdisc *q) +{ + spin_lock_bh(qdisc_root_lock(q)); +} + +static inline void sch_tree_unlock(struct Qdisc *q) +{ + spin_unlock_bh(qdisc_root_lock(q)); +} + +#define tcf_tree_lock(tp) sch_tree_lock((tp)->q) +#define tcf_tree_unlock(tp) sch_tree_unlock((tp)->q) extern struct Qdisc noop_qdisc; extern struct Qdisc_ops noop_qdisc_ops; +struct Qdisc_class_common +{ + u32 classid; + struct hlist_node hnode; +}; + +struct Qdisc_class_hash +{ + struct hlist_head *hash; + unsigned int hashsize; + unsigned int hashmask; + unsigned int hashelems; +}; + +static inline unsigned int qdisc_class_hash(u32 id, u32 mask) +{ + id ^= id >> 8; + id ^= id >> 4; + return id & mask; +} + +static inline struct Qdisc_class_common * +qdisc_class_find(struct Qdisc_class_hash *hash, u32 id) +{ + struct Qdisc_class_common *cl; + struct hlist_node *n; + unsigned int h; + + h = qdisc_class_hash(id, hash->hashmask); + hlist_for_each_entry(cl, n, &hash->hash[h], hnode) { + if (cl->classid == id) + return cl; + } + return NULL; +} + +extern int qdisc_class_hash_init(struct Qdisc_class_hash *); +extern void qdisc_class_hash_insert(struct Qdisc_class_hash *, struct Qdisc_class_common *); +extern void qdisc_class_hash_remove(struct Qdisc_class_hash *, struct Qdisc_class_common *); +extern void qdisc_class_hash_grow(struct Qdisc *, struct Qdisc_class_hash *); +extern void qdisc_class_hash_destroy(struct Qdisc_class_hash *); + extern void dev_init_scheduler(struct net_device *dev); extern void dev_shutdown(struct net_device *dev); extern void dev_activate(struct net_device *dev); @@ -174,18 +270,88 @@ extern void dev_deactivate(struct net_device *dev); extern void qdisc_reset(struct Qdisc *qdisc); extern void qdisc_destroy(struct Qdisc *qdisc); extern void qdisc_tree_decrease_qlen(struct Qdisc *qdisc, unsigned int n); -extern struct Qdisc *qdisc_alloc(struct net_device *dev, struct Qdisc_ops *ops); +extern struct Qdisc *qdisc_alloc(struct netdev_queue *dev_queue, + struct Qdisc_ops *ops); extern struct Qdisc *qdisc_create_dflt(struct net_device *dev, + struct netdev_queue *dev_queue, struct Qdisc_ops *ops, u32 parentid); +extern void qdisc_calculate_pkt_len(struct sk_buff *skb, + struct qdisc_size_table *stab); extern void tcf_destroy(struct tcf_proto *tp); extern void tcf_destroy_chain(struct tcf_proto **fl); +/* Reset all TX qdiscs of a device. */ +static inline void qdisc_reset_all_tx(struct net_device *dev) +{ + unsigned int i; + for (i = 0; i < dev->num_tx_queues; i++) + qdisc_reset(netdev_get_tx_queue(dev, i)->qdisc); +} + +/* Are all TX queues of the device empty? */ +static inline bool qdisc_all_tx_empty(const struct net_device *dev) +{ + unsigned int i; + for (i = 0; i < dev->num_tx_queues; i++) { + struct netdev_queue *txq = netdev_get_tx_queue(dev, i); + const struct Qdisc *q = txq->qdisc; + + if (q->q.qlen) + return false; + } + return true; +} + +/* Are any of the TX qdiscs changing? */ +static inline bool qdisc_tx_changing(struct net_device *dev) +{ + unsigned int i; + for (i = 0; i < dev->num_tx_queues; i++) { + struct netdev_queue *txq = netdev_get_tx_queue(dev, i); + if (txq->qdisc != txq->qdisc_sleeping) + return true; + } + return false; +} + +/* Is the device using the noop qdisc on all queues? */ +static inline bool qdisc_tx_is_noop(const struct net_device *dev) +{ + unsigned int i; + for (i = 0; i < dev->num_tx_queues; i++) { + struct netdev_queue *txq = netdev_get_tx_queue(dev, i); + if (txq->qdisc != &noop_qdisc) + return false; + } + return true; +} + +static inline unsigned int qdisc_pkt_len(struct sk_buff *skb) +{ + return qdisc_skb_cb(skb)->pkt_len; +} + +static inline int qdisc_enqueue(struct sk_buff *skb, struct Qdisc *sch) +{ +#ifdef CONFIG_NET_SCHED + if (sch->stab) + qdisc_calculate_pkt_len(skb, sch->stab); +#endif + return sch->enqueue(skb, sch); +} + +static inline int qdisc_enqueue_root(struct sk_buff *skb, struct Qdisc *sch) +{ + qdisc_skb_cb(skb)->pkt_len = skb->len; + return qdisc_enqueue(skb, sch); +} + static inline int __qdisc_enqueue_tail(struct sk_buff *skb, struct Qdisc *sch, struct sk_buff_head *list) { __skb_queue_tail(list, skb); - sch->qstats.backlog += skb->len; - sch->bstats.bytes += skb->len; + sch->qstats.backlog += qdisc_pkt_len(skb); + sch->bstats.bytes += qdisc_pkt_len(skb); sch->bstats.packets++; return NET_XMIT_SUCCESS; @@ -202,7 +368,7 @@ static inline struct sk_buff *__qdisc_dequeue_head(struct Qdisc *sch, struct sk_buff *skb = __skb_dequeue(list); if (likely(skb != NULL)) - sch->qstats.backlog -= skb->len; + sch->qstats.backlog -= qdisc_pkt_len(skb); return skb; } @@ -218,7 +384,7 @@ static inline struct sk_buff *__qdisc_dequeue_tail(struct Qdisc *sch, struct sk_buff *skb = __skb_dequeue_tail(list); if (likely(skb != NULL)) - sch->qstats.backlog -= skb->len; + sch->qstats.backlog -= qdisc_pkt_len(skb); return skb; } @@ -232,7 +398,7 @@ static inline int __qdisc_requeue(struct sk_buff *skb, struct Qdisc *sch, struct sk_buff_head *list) { __skb_queue_head(list, skb); - sch->qstats.backlog += skb->len; + sch->qstats.backlog += qdisc_pkt_len(skb); sch->qstats.requeues++; return NET_XMIT_SUCCESS; @@ -250,7 +416,7 @@ static inline void __qdisc_reset_queue(struct Qdisc *sch, * We do not know the backlog in bytes of this list, it * is up to the caller to correct it */ - skb_queue_purge(list); + __skb_queue_purge(list); } static inline void qdisc_reset_queue(struct Qdisc *sch) @@ -265,7 +431,7 @@ static inline unsigned int __qdisc_queue_drop(struct Qdisc *sch, struct sk_buff *skb = __qdisc_dequeue_tail(sch, list); if (likely(skb != NULL)) { - unsigned int len = skb->len; + unsigned int len = qdisc_pkt_len(skb); kfree_skb(skb); return len; } diff --git a/include/net/sctp/checksum.h b/include/net/sctp/checksum.h index ba75c67cb992..b799fb21519a 100644 --- a/include/net/sctp/checksum.h +++ b/include/net/sctp/checksum.h @@ -46,9 +46,14 @@ #include <net/sctp/sctp.h> #include <linux/crc32c.h> -static inline __u32 sctp_start_cksum(__u8 *buffer, __u16 length) +static inline __be32 sctp_crc32c(__be32 crc, u8 *buffer, u16 length) { - __u32 crc = ~(__u32) 0; + return (__force __be32)crc32c((__force u32)crc, buffer, length); +} + +static inline __be32 sctp_start_cksum(__u8 *buffer, __u16 length) +{ + __be32 crc = ~cpu_to_be32(0); __u8 zero[sizeof(__u32)] = {0}; /* Optimize this routine to be SCTP specific, knowing how @@ -56,23 +61,23 @@ static inline __u32 sctp_start_cksum(__u8 *buffer, __u16 length) */ /* Calculate CRC up to the checksum. */ - crc = crc32c(crc, buffer, sizeof(struct sctphdr) - sizeof(__u32)); + crc = sctp_crc32c(crc, buffer, sizeof(struct sctphdr) - sizeof(__u32)); /* Skip checksum field of the header. */ - crc = crc32c(crc, zero, sizeof(__u32)); + crc = sctp_crc32c(crc, zero, sizeof(__u32)); /* Calculate the rest of the CRC. */ - crc = crc32c(crc, &buffer[sizeof(struct sctphdr)], + crc = sctp_crc32c(crc, &buffer[sizeof(struct sctphdr)], length - sizeof(struct sctphdr)); return crc; } -static inline __u32 sctp_update_cksum(__u8 *buffer, __u16 length, __u32 crc32) +static inline __be32 sctp_update_cksum(__u8 *buffer, __u16 length, __be32 crc32) { - return crc32c(crc32, buffer, length); + return sctp_crc32c(crc32, buffer, length); } -static inline __u32 sctp_end_cksum(__u32 crc32) +static inline __be32 sctp_end_cksum(__be32 crc32) { - return ntohl(~crc32); + return ~crc32; } diff --git a/include/net/sctp/sctp.h b/include/net/sctp/sctp.h index 90b1e8d23b16..17b932b8a55a 100644 --- a/include/net/sctp/sctp.h +++ b/include/net/sctp/sctp.h @@ -179,6 +179,8 @@ int sctp_eps_proc_init(void); void sctp_eps_proc_exit(void); int sctp_assocs_proc_init(void); void sctp_assocs_proc_exit(void); +int sctp_remaddr_proc_init(void); +void sctp_remaddr_proc_exit(void); /* @@ -218,8 +220,6 @@ extern struct kmem_cache *sctp_bucket_cachep __read_mostly; #define sctp_release_sock(sk) release_sock(sk) #define sctp_bh_lock_sock(sk) bh_lock_sock(sk) #define sctp_bh_unlock_sock(sk) bh_unlock_sock(sk) -#define SCTP_SOCK_SLEEP_PRE(sk) SOCK_SLEEP_PRE(sk) -#define SCTP_SOCK_SLEEP_POST(sk) SOCK_SLEEP_POST(sk) /* SCTP SNMP MIB stats handlers */ DECLARE_SNMP_STAT(struct sctp_mib, sctp_statistics); diff --git a/include/net/sctp/structs.h b/include/net/sctp/structs.h index 7f25195f9855..70eb64a7e1a1 100644 --- a/include/net/sctp/structs.h +++ b/include/net/sctp/structs.h @@ -300,6 +300,7 @@ struct sctp_sock { /* The default SACK delay timeout for new associations. */ __u32 sackdelay; + __u32 sackfreq; /* Flags controlling Heartbeat, SACK delay, and Path MTU Discovery. */ __u32 param_flags; @@ -826,7 +827,7 @@ struct sctp_packet *sctp_packet_init(struct sctp_packet *, __u16 sport, __u16 dport); struct sctp_packet *sctp_packet_config(struct sctp_packet *, __u32 vtag, int); sctp_xmit_t sctp_packet_transmit_chunk(struct sctp_packet *, - struct sctp_chunk *); + struct sctp_chunk *, int); sctp_xmit_t sctp_packet_append_chunk(struct sctp_packet *, struct sctp_chunk *); int sctp_packet_transmit(struct sctp_packet *); @@ -946,6 +947,7 @@ struct sctp_transport { /* SACK delay timeout */ unsigned long sackdelay; + __u32 sackfreq; /* When was the last time (in jiffies) that we heard from this * transport? We use this to pick new active and retran paths. @@ -1209,6 +1211,8 @@ int sctp_add_bind_addr(struct sctp_bind_addr *, union sctp_addr *, int sctp_del_bind_addr(struct sctp_bind_addr *, union sctp_addr *); int sctp_bind_addr_match(struct sctp_bind_addr *, const union sctp_addr *, struct sctp_sock *); +int sctp_bind_addr_conflict(struct sctp_bind_addr *, const union sctp_addr *, + struct sctp_sock *, struct sctp_sock *); int sctp_bind_addr_state(const struct sctp_bind_addr *bp, const union sctp_addr *addr); union sctp_addr *sctp_find_unmatch_addr(struct sctp_bind_addr *bp, @@ -1553,6 +1557,7 @@ struct sctp_association { * : SACK's are not delayed (see Section 6). */ __u8 sack_needed; /* Do we need to sack the peer? */ + __u32 sack_cnt; /* These are capabilities which our peer advertised. */ __u8 ecn_capable; /* Can peer do ECN? */ @@ -1662,6 +1667,7 @@ struct sctp_association { /* SACK delay timeout */ unsigned long sackdelay; + __u32 sackfreq; unsigned long timeouts[SCTP_NUM_TIMEOUT_TYPES]; diff --git a/include/net/sctp/user.h b/include/net/sctp/user.h index 9619b9d35c9e..f205b10f0ab9 100644 --- a/include/net/sctp/user.h +++ b/include/net/sctp/user.h @@ -93,8 +93,9 @@ enum sctp_optname { #define SCTP_STATUS SCTP_STATUS SCTP_GET_PEER_ADDR_INFO, #define SCTP_GET_PEER_ADDR_INFO SCTP_GET_PEER_ADDR_INFO - SCTP_DELAYED_ACK_TIME, -#define SCTP_DELAYED_ACK_TIME SCTP_DELAYED_ACK_TIME + SCTP_DELAYED_ACK, +#define SCTP_DELAYED_ACK_TIME SCTP_DELAYED_ACK +#define SCTP_DELAYED_ACK SCTP_DELAYED_ACK SCTP_CONTEXT, /* Receive Context */ #define SCTP_CONTEXT SCTP_CONTEXT SCTP_FRAGMENT_INTERLEAVE, @@ -136,12 +137,14 @@ enum sctp_optname { #define SCTP_GET_LOCAL_ADDRS_NUM_OLD SCTP_GET_LOCAL_ADDRS_NUM_OLD SCTP_GET_LOCAL_ADDRS_OLD, /* Get all local addresss. */ #define SCTP_GET_LOCAL_ADDRS_OLD SCTP_GET_LOCAL_ADDRS_OLD - SCTP_SOCKOPT_CONNECTX, /* CONNECTX requests. */ -#define SCTP_SOCKOPT_CONNECTX SCTP_SOCKOPT_CONNECTX + SCTP_SOCKOPT_CONNECTX_OLD, /* CONNECTX old requests. */ +#define SCTP_SOCKOPT_CONNECTX_OLD SCTP_SOCKOPT_CONNECTX_OLD SCTP_GET_PEER_ADDRS, /* Get all peer addresss. */ #define SCTP_GET_PEER_ADDRS SCTP_GET_PEER_ADDRS SCTP_GET_LOCAL_ADDRS, /* Get all local addresss. */ #define SCTP_GET_LOCAL_ADDRS SCTP_GET_LOCAL_ADDRS + SCTP_SOCKOPT_CONNECTX, /* CONNECTX requests. */ +#define SCTP_SOCKOPT_CONNECTX SCTP_SOCKOPT_CONNECTX }; /* @@ -618,13 +621,26 @@ struct sctp_authkeyid { }; -/* 7.1.23. Delayed Ack Timer (SCTP_DELAYED_ACK_TIME) +/* + * 7.1.23. Get or set delayed ack timer (SCTP_DELAYED_SACK) * - * This options will get or set the delayed ack timer. The time is set - * in milliseconds. If the assoc_id is 0, then this sets or gets the - * endpoints default delayed ack timer value. If the assoc_id field is - * non-zero, then the set or get effects the specified association. + * This option will effect the way delayed acks are performed. This + * option allows you to get or set the delayed ack time, in + * milliseconds. It also allows changing the delayed ack frequency. + * Changing the frequency to 1 disables the delayed sack algorithm. If + * the assoc_id is 0, then this sets or gets the endpoints default + * values. If the assoc_id field is non-zero, then the set or get + * effects the specified association for the one to many model (the + * assoc_id field is ignored by the one to one model). Note that if + * sack_delay or sack_freq are 0 when setting this option, then the + * current values will remain unchanged. */ +struct sctp_sack_info { + sctp_assoc_t sack_assoc_id; + uint32_t sack_delay; + uint32_t sack_freq; +}; + struct sctp_assoc_value { sctp_assoc_t assoc_id; uint32_t assoc_value; diff --git a/include/net/snmp.h b/include/net/snmp.h index ce2f48507510..57c93628695f 100644 --- a/include/net/snmp.h +++ b/include/net/snmp.h @@ -14,8 +14,6 @@ * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. * - * $Id: snmp.h,v 1.19 2001/06/14 13:40:46 davem Exp $ - * */ #ifndef _SNMP_H diff --git a/include/net/sock.h b/include/net/sock.h index dc42b44c2aa1..06c5259aff30 100644 --- a/include/net/sock.h +++ b/include/net/sock.h @@ -166,7 +166,7 @@ struct sock_common { * @sk_err: last error * @sk_err_soft: errors that don't cause failure but are the cause of a * persistent failure not just 'timed out' - * @sk_drops: raw drops counter + * @sk_drops: raw/udp drops counter * @sk_ack_backlog: current listen backlog * @sk_max_ack_backlog: listen backlog set in listen() * @sk_priority: %SO_PRIORITY setting @@ -524,7 +524,7 @@ struct proto { int (*ioctl)(struct sock *sk, int cmd, unsigned long arg); int (*init)(struct sock *sk); - int (*destroy)(struct sock *sk); + void (*destroy)(struct sock *sk); void (*shutdown)(struct sock *sk, int how); int (*setsockopt)(struct sock *sk, int level, int optname, char __user *optval, @@ -565,7 +565,7 @@ struct proto { #endif /* Memory pressure */ - void (*enter_memory_pressure)(void); + void (*enter_memory_pressure)(struct sock *sk); atomic_t *memory_allocated; /* Current allocated memory. */ atomic_t *sockets_allocated; /* Current number of sockets. */ /* @@ -990,6 +990,11 @@ static inline void sock_put(struct sock *sk) extern int sk_receive_skb(struct sock *sk, struct sk_buff *skb, const int nested); +static inline void sk_set_socket(struct sock *sk, struct socket *sock) +{ + sk->sk_socket = sock; +} + /* Detach socket from process context. * Announce socket dead, detach it from wait queue and inode. * Note that parent inode held reference count on this struct sock, @@ -1001,7 +1006,7 @@ static inline void sock_orphan(struct sock *sk) { write_lock_bh(&sk->sk_callback_lock); sock_set_flag(sk, SOCK_DEAD); - sk->sk_socket = NULL; + sk_set_socket(sk, NULL); sk->sk_sleep = NULL; write_unlock_bh(&sk->sk_callback_lock); } @@ -1011,7 +1016,7 @@ static inline void sock_graft(struct sock *sk, struct socket *parent) write_lock_bh(&sk->sk_callback_lock); sk->sk_sleep = &parent->wait; parent->sk = sk; - sk->sk_socket = parent; + sk_set_socket(sk, parent); security_sock_graft(sk, parent); write_unlock_bh(&sk->sk_callback_lock); } @@ -1205,7 +1210,7 @@ static inline struct page *sk_stream_alloc_page(struct sock *sk) page = alloc_pages(sk->sk_allocation, 0); if (!page) { - sk->sk_prot->enter_memory_pressure(); + sk->sk_prot->enter_memory_pressure(sk); sk_stream_moderate_sndbuf(sk); } return page; @@ -1331,30 +1336,6 @@ extern int net_msg_warn; #define LIMIT_NETDEBUG(fmt, args...) \ do { if (net_msg_warn && net_ratelimit()) printk(fmt,##args); } while(0) -/* - * Macros for sleeping on a socket. Use them like this: - * - * SOCK_SLEEP_PRE(sk) - * if (condition) - * schedule(); - * SOCK_SLEEP_POST(sk) - * - * N.B. These are now obsolete and were, afaik, only ever used in DECnet - * and when the last use of them in DECnet has gone, I'm intending to - * remove them. - */ - -#define SOCK_SLEEP_PRE(sk) { struct task_struct *tsk = current; \ - DECLARE_WAITQUEUE(wait, tsk); \ - tsk->state = TASK_INTERRUPTIBLE; \ - add_wait_queue((sk)->sk_sleep, &wait); \ - release_sock(sk); - -#define SOCK_SLEEP_POST(sk) tsk->state = TASK_RUNNING; \ - remove_wait_queue((sk)->sk_sleep, &wait); \ - lock_sock(sk); \ - } - extern __u32 sysctl_wmem_max; extern __u32 sysctl_rmem_max; diff --git a/include/net/stp.h b/include/net/stp.h new file mode 100644 index 000000000000..ad447f105417 --- /dev/null +++ b/include/net/stp.h @@ -0,0 +1,14 @@ +#ifndef _NET_STP_H +#define _NET_STP_H + +struct stp_proto { + unsigned char group_address[ETH_ALEN]; + void (*rcv)(const struct stp_proto *, struct sk_buff *, + struct net_device *); + void *data; +}; + +extern int stp_proto_register(const struct stp_proto *proto); +extern void stp_proto_unregister(const struct stp_proto *proto); + +#endif /* _NET_STP_H */ diff --git a/include/net/tcp.h b/include/net/tcp.h index cf54034019d9..8983386356a5 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -50,6 +50,7 @@ extern atomic_t tcp_orphan_count; extern void tcp_time_wait(struct sock *sk, int state, int timeo); #define MAX_TCP_HEADER (128 + MAX_HEADER) +#define MAX_TCP_OPTION_SPACE 40 /* * Never offer a window over 32767 without using window scaling. Some @@ -184,6 +185,7 @@ extern void tcp_time_wait(struct sock *sk, int state, int timeo); #define TCPOLEN_SACK_BASE_ALIGNED 4 #define TCPOLEN_SACK_PERBLOCK 8 #define TCPOLEN_MD5SIG_ALIGNED 20 +#define TCPOLEN_MSS_ALIGNED 4 /* Flags in tp->nonagle */ #define TCP_NAGLE_OFF 1 /* Nagle's algo is disabled */ @@ -265,13 +267,10 @@ static inline int tcp_too_many_orphans(struct sock *sk, int num) extern struct proto tcp_prot; -DECLARE_SNMP_STAT(struct tcp_mib, tcp_statistics); -#define TCP_INC_STATS(field) SNMP_INC_STATS(tcp_statistics, field) -#define TCP_INC_STATS_BH(field) SNMP_INC_STATS_BH(tcp_statistics, field) -#define TCP_INC_STATS_USER(field) SNMP_INC_STATS_USER(tcp_statistics, field) -#define TCP_DEC_STATS(field) SNMP_DEC_STATS(tcp_statistics, field) -#define TCP_ADD_STATS_BH(field, val) SNMP_ADD_STATS_BH(tcp_statistics, field, val) -#define TCP_ADD_STATS_USER(field, val) SNMP_ADD_STATS_USER(tcp_statistics, field, val) +#define TCP_INC_STATS(net, field) SNMP_INC_STATS((net)->mib.tcp_statistics, field) +#define TCP_INC_STATS_BH(net, field) SNMP_INC_STATS_BH((net)->mib.tcp_statistics, field) +#define TCP_DEC_STATS(net, field) SNMP_DEC_STATS((net)->mib.tcp_statistics, field) +#define TCP_ADD_STATS_USER(net, field, val) SNMP_ADD_STATS_USER((net)->mib.tcp_statistics, field, val) extern void tcp_v4_err(struct sk_buff *skb, u32); @@ -398,6 +397,8 @@ extern void tcp_parse_options(struct sk_buff *skb, struct tcp_options_received *opt_rx, int estab); +extern u8 *tcp_parse_md5sig_option(struct tcphdr *th); + /* * TCP v4 functions exported for the inet6 API */ @@ -894,7 +895,7 @@ static inline int tcp_prequeue(struct sock *sk, struct sk_buff *skb) while ((skb1 = __skb_dequeue(&tp->ucopy.prequeue)) != NULL) { sk->sk_backlog_rcv(sk, skb1); - NET_INC_STATS_BH(LINUX_MIB_TCPPREQUEUEDROPPED); + NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_TCPPREQUEUEDROPPED); } tp->ucopy.memory = 0; @@ -975,7 +976,7 @@ static inline void tcp_openreq_init(struct request_sock *req, ireq->rmt_port = tcp_hdr(skb)->source; } -extern void tcp_enter_memory_pressure(void); +extern void tcp_enter_memory_pressure(struct sock *sk); static inline int keepalive_intvl_when(const struct tcp_sock *tp) { @@ -1024,13 +1025,13 @@ static inline int tcp_paws_check(const struct tcp_options_received *rx_opt, int #define TCP_CHECK_TIMER(sk) do { } while (0) -static inline void tcp_mib_init(void) +static inline void tcp_mib_init(struct net *net) { /* See RFC 2012 */ - TCP_ADD_STATS_USER(TCP_MIB_RTOALGORITHM, 1); - TCP_ADD_STATS_USER(TCP_MIB_RTOMIN, TCP_RTO_MIN*1000/HZ); - TCP_ADD_STATS_USER(TCP_MIB_RTOMAX, TCP_RTO_MAX*1000/HZ); - TCP_ADD_STATS_USER(TCP_MIB_MAXCONN, -1); + TCP_ADD_STATS_USER(net, TCP_MIB_RTOALGORITHM, 1); + TCP_ADD_STATS_USER(net, TCP_MIB_RTOMIN, TCP_RTO_MIN*1000/HZ); + TCP_ADD_STATS_USER(net, TCP_MIB_RTOMAX, TCP_RTO_MAX*1000/HZ); + TCP_ADD_STATS_USER(net, TCP_MIB_MAXCONN, -1); } /* from STCP */ @@ -1113,14 +1114,12 @@ struct tcp_md5sig_pool { #define TCP_MD5SIG_MAXKEYS (~(u32)0) /* really?! */ /* - functions */ -extern int tcp_v4_calc_md5_hash(char *md5_hash, - struct tcp_md5sig_key *key, - struct sock *sk, - struct dst_entry *dst, - struct request_sock *req, - struct tcphdr *th, - int protocol, - unsigned int tcplen); +extern int tcp_v4_md5_hash_skb(char *md5_hash, + struct tcp_md5sig_key *key, + struct sock *sk, + struct request_sock *req, + struct sk_buff *skb); + extern struct tcp_md5sig_key *tcp_v4_md5_lookup(struct sock *sk, struct sock *addr_sk); @@ -1132,11 +1131,26 @@ extern int tcp_v4_md5_do_add(struct sock *sk, extern int tcp_v4_md5_do_del(struct sock *sk, __be32 addr); +#ifdef CONFIG_TCP_MD5SIG +#define tcp_twsk_md5_key(twsk) ((twsk)->tw_md5_keylen ? \ + &(struct tcp_md5sig_key) { \ + .key = (twsk)->tw_md5_key, \ + .keylen = (twsk)->tw_md5_keylen, \ + } : NULL) +#else +#define tcp_twsk_md5_key(twsk) NULL +#endif + extern struct tcp_md5sig_pool **tcp_alloc_md5sig_pool(void); extern void tcp_free_md5sig_pool(void); extern struct tcp_md5sig_pool *__tcp_get_md5sig_pool(int cpu); extern void __tcp_put_md5sig_pool(void); +extern int tcp_md5_hash_header(struct tcp_md5sig_pool *, struct tcphdr *); +extern int tcp_md5_hash_skb_data(struct tcp_md5sig_pool *, struct sk_buff *, + unsigned header_len); +extern int tcp_md5_hash_key(struct tcp_md5sig_pool *hp, + struct tcp_md5sig_key *key); static inline struct tcp_md5sig_pool *tcp_get_md5sig_pool(void) @@ -1348,7 +1362,7 @@ extern void tcp_proc_unregister(struct net *net, struct tcp_seq_afinfo *afinfo); extern struct request_sock_ops tcp_request_sock_ops; extern struct request_sock_ops tcp6_request_sock_ops; -extern int tcp_v4_destroy_sock(struct sock *sk); +extern void tcp_v4_destroy_sock(struct sock *sk); extern int tcp_v4_gso_send_check(struct sk_buff *skb); extern struct sk_buff *tcp_tso_segment(struct sk_buff *skb, int features); @@ -1366,11 +1380,8 @@ struct tcp_sock_af_ops { int (*calc_md5_hash) (char *location, struct tcp_md5sig_key *md5, struct sock *sk, - struct dst_entry *dst, struct request_sock *req, - struct tcphdr *th, - int protocol, - unsigned int len); + struct sk_buff *skb); int (*md5_add) (struct sock *sk, struct sock *addr_sk, u8 *newkey, diff --git a/include/net/tipc/tipc_port.h b/include/net/tipc/tipc_port.h index 11105bcc4457..c54917cbfa48 100644 --- a/include/net/tipc/tipc_port.h +++ b/include/net/tipc/tipc_port.h @@ -2,7 +2,7 @@ * include/net/tipc/tipc_port.h: Include file for privileged access to TIPC ports * * Copyright (c) 1994-2007, Ericsson AB - * Copyright (c) 2005-2007, Wind River Systems + * Copyright (c) 2005-2008, Wind River Systems * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -75,13 +75,7 @@ struct tipc_port { }; -/** - * tipc_createport_raw - create a native TIPC port and return it's reference - * - * Note: 'dispatcher' and 'wakeup' deliver a locked port. - */ - -u32 tipc_createport_raw(void *usr_handle, +struct tipc_port *tipc_createport_raw(void *usr_handle, u32 (*dispatcher)(struct tipc_port *, struct sk_buff *), void (*wakeup)(struct tipc_port *), const u32 importance); diff --git a/include/net/transp_v6.h b/include/net/transp_v6.h index 112934a3288d..876b6f2bb4fd 100644 --- a/include/net/transp_v6.h +++ b/include/net/transp_v6.h @@ -53,7 +53,7 @@ extern int datagram_send_ctl(struct net *net, */ extern struct inet_connection_sock_af_ops ipv4_specific; -extern int inet6_destroy_sock(struct sock *sk); +extern void inet6_destroy_sock(struct sock *sk); #endif diff --git a/include/net/udp.h b/include/net/udp.h index ccce83707046..addcdc67234c 100644 --- a/include/net/udp.h +++ b/include/net/udp.h @@ -148,27 +148,25 @@ extern int udp_lib_setsockopt(struct sock *sk, int level, int optname, char __user *optval, int optlen, int (*push_pending_frames)(struct sock *)); -DECLARE_SNMP_STAT(struct udp_mib, udp_statistics); DECLARE_SNMP_STAT(struct udp_mib, udp_stats_in6); /* UDP-Lite does not have a standardized MIB yet, so we inherit from UDP */ -DECLARE_SNMP_STAT(struct udp_mib, udplite_statistics); DECLARE_SNMP_STAT(struct udp_mib, udplite_stats_in6); /* * SNMP statistics for UDP and UDP-Lite */ -#define UDP_INC_STATS_USER(field, is_udplite) do { \ - if (is_udplite) SNMP_INC_STATS_USER(udplite_statistics, field); \ - else SNMP_INC_STATS_USER(udp_statistics, field); } while(0) -#define UDP_INC_STATS_BH(field, is_udplite) do { \ - if (is_udplite) SNMP_INC_STATS_BH(udplite_statistics, field); \ - else SNMP_INC_STATS_BH(udp_statistics, field); } while(0) - -#define UDP6_INC_STATS_BH(field, is_udplite) do { \ +#define UDP_INC_STATS_USER(net, field, is_udplite) do { \ + if (is_udplite) SNMP_INC_STATS_USER((net)->mib.udplite_statistics, field); \ + else SNMP_INC_STATS_USER((net)->mib.udp_statistics, field); } while(0) +#define UDP_INC_STATS_BH(net, field, is_udplite) do { \ + if (is_udplite) SNMP_INC_STATS_BH((net)->mib.udplite_statistics, field); \ + else SNMP_INC_STATS_BH((net)->mib.udp_statistics, field); } while(0) + +#define UDP6_INC_STATS_BH(net, field, is_udplite) do { (void)net; \ if (is_udplite) SNMP_INC_STATS_BH(udplite_stats_in6, field); \ else SNMP_INC_STATS_BH(udp_stats_in6, field); } while(0) -#define UDP6_INC_STATS_USER(field, is_udplite) do { \ +#define UDP6_INC_STATS_USER(net, field, is_udplite) do { (void)net; \ if (is_udplite) SNMP_INC_STATS_USER(udplite_stats_in6, field); \ else SNMP_INC_STATS_USER(udp_stats_in6, field); } while(0) @@ -176,12 +174,12 @@ DECLARE_SNMP_STAT(struct udp_mib, udplite_stats_in6); #define UDPX_INC_STATS_BH(sk, field) \ do { \ if ((sk)->sk_family == AF_INET) \ - UDP_INC_STATS_BH(field, 0); \ + UDP_INC_STATS_BH(sock_net(sk), field, 0); \ else \ - UDP6_INC_STATS_BH(field, 0); \ + UDP6_INC_STATS_BH(sock_net(sk), field, 0); \ } while (0); #else -#define UDPX_INC_STATS_BH(sk, field) UDP_INC_STATS_BH(field, 0) +#define UDPX_INC_STATS_BH(sk, field) UDP_INC_STATS_BH(sock_net(sk), field, 0) #endif /* /proc */ @@ -196,8 +194,8 @@ struct udp_seq_afinfo { struct udp_iter_state { struct seq_net_private p; sa_family_t family; - struct hlist_head *hashtable; int bucket; + struct hlist_head *hashtable; }; #ifdef CONFIG_PROC_FS diff --git a/include/net/wext.h b/include/net/wext.h index 80b31d826b7a..6d76a39a9c5b 100644 --- a/include/net/wext.h +++ b/include/net/wext.h @@ -12,6 +12,8 @@ extern int wext_proc_init(struct net *net); extern void wext_proc_exit(struct net *net); extern int wext_handle_ioctl(struct net *net, struct ifreq *ifr, unsigned int cmd, void __user *arg); +extern int compat_wext_handle_ioctl(struct net *net, unsigned int cmd, + unsigned long arg); #else static inline int wext_proc_init(struct net *net) { @@ -26,6 +28,11 @@ static inline int wext_handle_ioctl(struct net *net, struct ifreq *ifr, unsigned { return -EINVAL; } +static inline int compat_wext_handle_ioctl(struct net *net, unsigned int cmd, + unsigned long arg) +{ + return -EINVAL; +} #endif #endif /* __NET_WEXT_H */ diff --git a/include/net/wireless.h b/include/net/wireless.h index 667b4080d30f..9324f8dd183e 100644 --- a/include/net/wireless.h +++ b/include/net/wireless.h @@ -39,12 +39,18 @@ 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 + * 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, }; /** diff --git a/include/xen/hvc-console.h b/include/xen/hvc-console.h index 98b79bc404dd..c3adde32669b 100644 --- a/include/xen/hvc-console.h +++ b/include/xen/hvc-console.h @@ -5,11 +5,12 @@ extern struct console xenboot_console; #ifdef CONFIG_HVC_XEN void xen_console_resume(void); +void xen_raw_console_write(const char *str); +void xen_raw_printk(const char *fmt, ...); #else static inline void xen_console_resume(void) { } +static inline void xen_raw_console_write(const char *str) { } +static inline void xen_raw_printk(const char *fmt, ...) { } #endif -void xen_raw_console_write(const char *str); -void xen_raw_printk(const char *fmt, ...); - #endif /* XEN_HVC_CONSOLE_H */ diff --git a/include/xen/interface/callback.h b/include/xen/interface/callback.h index 4aadcba31af9..2ae3cd243264 100644 --- a/include/xen/interface/callback.h +++ b/include/xen/interface/callback.h @@ -82,9 +82,9 @@ */ #define CALLBACKOP_register 0 struct callback_register { - uint16_t type; - uint16_t flags; - struct xen_callback address; + uint16_t type; + uint16_t flags; + xen_callback_t address; }; /* diff --git a/include/xen/xen-ops.h b/include/xen/xen-ops.h index a706d6a78960..883a21bba24b 100644 --- a/include/xen/xen-ops.h +++ b/include/xen/xen-ops.h @@ -11,4 +11,7 @@ void xen_post_suspend(int suspend_cancelled); void xen_mm_pin_all(void); void xen_mm_unpin_all(void); +void xen_timer_resume(void); +void xen_arch_resume(void); + #endif /* INCLUDE_XEN_OPS_H */ diff --git a/init/main.c b/init/main.c index edeace036fd9..756eca4b821a 100644 --- a/init/main.c +++ b/init/main.c @@ -630,9 +630,10 @@ asmlinkage void __init start_kernel(void) #ifdef CONFIG_BLK_DEV_INITRD if (initrd_start && !initrd_below_start_ok && - initrd_start < min_low_pfn << PAGE_SHIFT) { + page_to_pfn(virt_to_page(initrd_start)) < min_low_pfn) { printk(KERN_CRIT "initrd overwritten (0x%08lx < 0x%08lx) - " - "disabling it.\n",initrd_start,min_low_pfn << PAGE_SHIFT); + "disabling it.\n", + page_to_pfn(virt_to_page(initrd_start)), min_low_pfn); initrd_start = 0; } #endif diff --git a/ipc/mqueue.c b/ipc/mqueue.c index b3b69fd51330..3e84b958186b 100644 --- a/ipc/mqueue.c +++ b/ipc/mqueue.c @@ -1054,7 +1054,7 @@ retry: } timeo = MAX_SCHEDULE_TIMEOUT; - ret = netlink_attachskb(sock, nc, 0, &timeo, NULL); + ret = netlink_attachskb(sock, nc, &timeo, NULL); if (ret == 1) goto retry; if (ret) { diff --git a/kernel/power/Kconfig b/kernel/power/Kconfig index b45da40e8d25..59dfdf1e1d20 100644 --- a/kernel/power/Kconfig +++ b/kernel/power/Kconfig @@ -82,7 +82,7 @@ config PM_SLEEP_SMP config PM_SLEEP bool - depends on SUSPEND || HIBERNATION + depends on SUSPEND || HIBERNATION || XEN_SAVE_RESTORE default y config SUSPEND diff --git a/lib/textsearch.c b/lib/textsearch.c index a3e500ad51d7..4b7c6075256f 100644 --- a/lib/textsearch.c +++ b/lib/textsearch.c @@ -54,10 +54,13 @@ * USAGE * * Before a search can be performed, a configuration must be created - * by calling textsearch_prepare() specyfing the searching algorithm and - * the pattern to look for. The returned configuration may then be used - * for an arbitary amount of times and even in parallel as long as a - * separate struct ts_state variable is provided to every instance. + * by calling textsearch_prepare() specifying the searching algorithm, + * the pattern to look for and flags. As a flag, you can set TS_IGNORECASE + * to perform case insensitive matching. But it might slow down + * performance of algorithm, so you should use it at own your risk. + * The returned configuration may then be used for an arbitary + * amount of times and even in parallel as long as a separate struct + * ts_state variable is provided to every instance. * * The actual search is performed by either calling textsearch_find_- * continuous() for linear data or by providing an own get_next_block() @@ -89,7 +92,6 @@ * panic("Oh my god, dancing chickens at %d\n", pos); * * textsearch_destroy(conf); - * * ========================================================================== */ @@ -280,7 +282,7 @@ struct ts_config *textsearch_prepare(const char *algo, const void *pattern, if (ops == NULL) goto errout; - conf = ops->init(pattern, len, gfp_mask); + conf = ops->init(pattern, len, gfp_mask, flags); if (IS_ERR(conf)) { err = PTR_ERR(conf); goto errout; diff --git a/lib/ts_bm.c b/lib/ts_bm.c index 4a7fce72898e..9e66ee4020e9 100644 --- a/lib/ts_bm.c +++ b/lib/ts_bm.c @@ -39,6 +39,7 @@ #include <linux/module.h> #include <linux/types.h> #include <linux/string.h> +#include <linux/ctype.h> #include <linux/textsearch.h> /* Alphabet size, use ASCII */ @@ -64,6 +65,7 @@ static unsigned int bm_find(struct ts_config *conf, struct ts_state *state) unsigned int i, text_len, consumed = state->offset; const u8 *text; int shift = bm->patlen - 1, bs; + const u8 icase = conf->flags & TS_IGNORECASE; for (;;) { text_len = conf->get_next_block(consumed, &text, conf, state); @@ -75,7 +77,9 @@ static unsigned int bm_find(struct ts_config *conf, struct ts_state *state) DEBUGP("Searching in position %d (%c)\n", shift, text[shift]); for (i = 0; i < bm->patlen; i++) - if (text[shift-i] != bm->pattern[bm->patlen-1-i]) + if ((icase ? toupper(text[shift-i]) + : text[shift-i]) + != bm->pattern[bm->patlen-1-i]) goto next; /* London calling... */ @@ -111,14 +115,18 @@ static int subpattern(u8 *pattern, int i, int j, int g) return ret; } -static void compute_prefix_tbl(struct ts_bm *bm) +static void compute_prefix_tbl(struct ts_bm *bm, int flags) { int i, j, g; for (i = 0; i < ASIZE; i++) bm->bad_shift[i] = bm->patlen; - for (i = 0; i < bm->patlen - 1; i++) + for (i = 0; i < bm->patlen - 1; i++) { bm->bad_shift[bm->pattern[i]] = bm->patlen - 1 - i; + if (flags & TS_IGNORECASE) + bm->bad_shift[tolower(bm->pattern[i])] + = bm->patlen - 1 - i; + } /* Compute the good shift array, used to match reocurrences * of a subpattern */ @@ -135,10 +143,11 @@ static void compute_prefix_tbl(struct ts_bm *bm) } static struct ts_config *bm_init(const void *pattern, unsigned int len, - gfp_t gfp_mask) + gfp_t gfp_mask, int flags) { struct ts_config *conf; struct ts_bm *bm; + int i; unsigned int prefix_tbl_len = len * sizeof(unsigned int); size_t priv_size = sizeof(*bm) + len + prefix_tbl_len; @@ -146,11 +155,16 @@ static struct ts_config *bm_init(const void *pattern, unsigned int len, if (IS_ERR(conf)) return conf; + conf->flags = flags; bm = ts_config_priv(conf); bm->patlen = len; bm->pattern = (u8 *) bm->good_shift + prefix_tbl_len; - memcpy(bm->pattern, pattern, len); - compute_prefix_tbl(bm); + if (flags & TS_IGNORECASE) + for (i = 0; i < len; i++) + bm->pattern[i] = toupper(((u8 *)pattern)[i]); + else + memcpy(bm->pattern, pattern, len); + compute_prefix_tbl(bm, flags); return conf; } diff --git a/lib/ts_fsm.c b/lib/ts_fsm.c index af575b61526b..5696a35184e4 100644 --- a/lib/ts_fsm.c +++ b/lib/ts_fsm.c @@ -257,7 +257,7 @@ found_match: } static struct ts_config *fsm_init(const void *pattern, unsigned int len, - gfp_t gfp_mask) + gfp_t gfp_mask, int flags) { int i, err = -EINVAL; struct ts_config *conf; @@ -269,6 +269,9 @@ static struct ts_config *fsm_init(const void *pattern, unsigned int len, if (len % sizeof(struct ts_fsm_token) || ntokens < 1) goto errout; + if (flags & TS_IGNORECASE) + goto errout; + for (i = 0; i < ntokens; i++) { struct ts_fsm_token *t = &tokens[i]; @@ -284,6 +287,7 @@ static struct ts_config *fsm_init(const void *pattern, unsigned int len, if (IS_ERR(conf)) return conf; + conf->flags = flags; fsm = ts_config_priv(conf); fsm->ntokens = ntokens; memcpy(fsm->tokens, pattern, len); diff --git a/lib/ts_kmp.c b/lib/ts_kmp.c index 3ced628cab4b..632f783e65f1 100644 --- a/lib/ts_kmp.c +++ b/lib/ts_kmp.c @@ -33,6 +33,7 @@ #include <linux/module.h> #include <linux/types.h> #include <linux/string.h> +#include <linux/ctype.h> #include <linux/textsearch.h> struct ts_kmp @@ -47,6 +48,7 @@ static unsigned int kmp_find(struct ts_config *conf, struct ts_state *state) struct ts_kmp *kmp = ts_config_priv(conf); unsigned int i, q = 0, text_len, consumed = state->offset; const u8 *text; + const int icase = conf->flags & TS_IGNORECASE; for (;;) { text_len = conf->get_next_block(consumed, &text, conf, state); @@ -55,9 +57,11 @@ static unsigned int kmp_find(struct ts_config *conf, struct ts_state *state) break; for (i = 0; i < text_len; i++) { - while (q > 0 && kmp->pattern[q] != text[i]) + while (q > 0 && kmp->pattern[q] + != (icase ? toupper(text[i]) : text[i])) q = kmp->prefix_tbl[q - 1]; - if (kmp->pattern[q] == text[i]) + if (kmp->pattern[q] + == (icase ? toupper(text[i]) : text[i])) q++; if (unlikely(q == kmp->pattern_len)) { state->offset = consumed + i + 1; @@ -72,24 +76,28 @@ static unsigned int kmp_find(struct ts_config *conf, struct ts_state *state) } static inline void compute_prefix_tbl(const u8 *pattern, unsigned int len, - unsigned int *prefix_tbl) + unsigned int *prefix_tbl, int flags) { unsigned int k, q; + const u8 icase = flags & TS_IGNORECASE; for (k = 0, q = 1; q < len; q++) { - while (k > 0 && pattern[k] != pattern[q]) + while (k > 0 && (icase ? toupper(pattern[k]) : pattern[k]) + != (icase ? toupper(pattern[q]) : pattern[q])) k = prefix_tbl[k-1]; - if (pattern[k] == pattern[q]) + if ((icase ? toupper(pattern[k]) : pattern[k]) + == (icase ? toupper(pattern[q]) : pattern[q])) k++; prefix_tbl[q] = k; } } static struct ts_config *kmp_init(const void *pattern, unsigned int len, - gfp_t gfp_mask) + gfp_t gfp_mask, int flags) { struct ts_config *conf; struct ts_kmp *kmp; + int i; unsigned int prefix_tbl_len = len * sizeof(unsigned int); size_t priv_size = sizeof(*kmp) + len + prefix_tbl_len; @@ -97,11 +105,16 @@ static struct ts_config *kmp_init(const void *pattern, unsigned int len, if (IS_ERR(conf)) return conf; + conf->flags = flags; kmp = ts_config_priv(conf); kmp->pattern_len = len; - compute_prefix_tbl(pattern, len, kmp->prefix_tbl); + compute_prefix_tbl(pattern, len, kmp->prefix_tbl, flags); kmp->pattern = (u8 *) kmp->prefix_tbl + prefix_tbl_len; - memcpy(kmp->pattern, pattern, len); + if (flags & TS_IGNORECASE) + for (i = 0; i < len; i++) + kmp->pattern[i] = toupper(((u8 *)pattern)[i]); + else + memcpy(kmp->pattern, pattern, len); return conf; } diff --git a/mm/highmem.c b/mm/highmem.c index 7da4a7b6af11..e16e1523b688 100644 --- a/mm/highmem.c +++ b/mm/highmem.c @@ -40,6 +40,7 @@ #ifdef CONFIG_HIGHMEM unsigned long totalhigh_pages __read_mostly; +EXPORT_SYMBOL(totalhigh_pages); unsigned int nr_free_highpages (void) { diff --git a/net/802/Kconfig b/net/802/Kconfig new file mode 100644 index 000000000000..be33d27c8e69 --- /dev/null +++ b/net/802/Kconfig @@ -0,0 +1,7 @@ +config STP + tristate + select LLC + +config GARP + tristate + select STP diff --git a/net/802/Makefile b/net/802/Makefile index 68569ffddea1..7893d679910c 100644 --- a/net/802/Makefile +++ b/net/802/Makefile @@ -10,3 +10,5 @@ obj-$(CONFIG_FDDI) += fddi.o obj-$(CONFIG_HIPPI) += hippi.o obj-$(CONFIG_IPX) += p8022.o psnap.o p8023.o obj-$(CONFIG_ATALK) += p8022.o psnap.o +obj-$(CONFIG_STP) += stp.o +obj-$(CONFIG_GARP) += garp.o diff --git a/net/802/garp.c b/net/802/garp.c new file mode 100644 index 000000000000..1dcb0660c49d --- /dev/null +++ b/net/802/garp.c @@ -0,0 +1,636 @@ +/* + * IEEE 802.1D Generic Attribute Registration Protocol (GARP) + * + * Copyright (c) 2008 Patrick McHardy <kaber@trash.net> + * + * 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 <linux/kernel.h> +#include <linux/timer.h> +#include <linux/skbuff.h> +#include <linux/netdevice.h> +#include <linux/etherdevice.h> +#include <linux/rtnetlink.h> +#include <linux/llc.h> +#include <net/llc.h> +#include <net/llc_pdu.h> +#include <net/garp.h> +#include <asm/unaligned.h> + +static unsigned int garp_join_time __read_mostly = 200; +module_param(garp_join_time, uint, 0644); +MODULE_PARM_DESC(garp_join_time, "Join time in ms (default 200ms)"); +MODULE_LICENSE("GPL"); + +static const struct garp_state_trans { + u8 state; + u8 action; +} garp_applicant_state_table[GARP_APPLICANT_MAX + 1][GARP_EVENT_MAX + 1] = { + [GARP_APPLICANT_VA] = { + [GARP_EVENT_TRANSMIT_PDU] = { .state = GARP_APPLICANT_AA, + .action = GARP_ACTION_S_JOIN_IN }, + [GARP_EVENT_R_JOIN_IN] = { .state = GARP_APPLICANT_AA }, + [GARP_EVENT_R_JOIN_EMPTY] = { .state = GARP_APPLICANT_VA }, + [GARP_EVENT_R_EMPTY] = { .state = GARP_APPLICANT_VA }, + [GARP_EVENT_R_LEAVE_IN] = { .state = GARP_APPLICANT_VA }, + [GARP_EVENT_R_LEAVE_EMPTY] = { .state = GARP_APPLICANT_VP }, + [GARP_EVENT_REQ_JOIN] = { .state = GARP_APPLICANT_INVALID }, + [GARP_EVENT_REQ_LEAVE] = { .state = GARP_APPLICANT_LA }, + }, + [GARP_APPLICANT_AA] = { + [GARP_EVENT_TRANSMIT_PDU] = { .state = GARP_APPLICANT_QA, + .action = GARP_ACTION_S_JOIN_IN }, + [GARP_EVENT_R_JOIN_IN] = { .state = GARP_APPLICANT_QA }, + [GARP_EVENT_R_JOIN_EMPTY] = { .state = GARP_APPLICANT_VA }, + [GARP_EVENT_R_EMPTY] = { .state = GARP_APPLICANT_VA }, + [GARP_EVENT_R_LEAVE_IN] = { .state = GARP_APPLICANT_VA }, + [GARP_EVENT_R_LEAVE_EMPTY] = { .state = GARP_APPLICANT_VP }, + [GARP_EVENT_REQ_JOIN] = { .state = GARP_APPLICANT_INVALID }, + [GARP_EVENT_REQ_LEAVE] = { .state = GARP_APPLICANT_LA }, + }, + [GARP_APPLICANT_QA] = { + [GARP_EVENT_TRANSMIT_PDU] = { .state = GARP_APPLICANT_INVALID }, + [GARP_EVENT_R_JOIN_IN] = { .state = GARP_APPLICANT_QA }, + [GARP_EVENT_R_JOIN_EMPTY] = { .state = GARP_APPLICANT_VA }, + [GARP_EVENT_R_EMPTY] = { .state = GARP_APPLICANT_VA }, + [GARP_EVENT_R_LEAVE_IN] = { .state = GARP_APPLICANT_VP }, + [GARP_EVENT_R_LEAVE_EMPTY] = { .state = GARP_APPLICANT_VP }, + [GARP_EVENT_REQ_JOIN] = { .state = GARP_APPLICANT_INVALID }, + [GARP_EVENT_REQ_LEAVE] = { .state = GARP_APPLICANT_LA }, + }, + [GARP_APPLICANT_LA] = { + [GARP_EVENT_TRANSMIT_PDU] = { .state = GARP_APPLICANT_VO, + .action = GARP_ACTION_S_LEAVE_EMPTY }, + [GARP_EVENT_R_JOIN_IN] = { .state = GARP_APPLICANT_LA }, + [GARP_EVENT_R_JOIN_EMPTY] = { .state = GARP_APPLICANT_VO }, + [GARP_EVENT_R_EMPTY] = { .state = GARP_APPLICANT_LA }, + [GARP_EVENT_R_LEAVE_IN] = { .state = GARP_APPLICANT_LA }, + [GARP_EVENT_R_LEAVE_EMPTY] = { .state = GARP_APPLICANT_VO }, + [GARP_EVENT_REQ_JOIN] = { .state = GARP_APPLICANT_VA }, + [GARP_EVENT_REQ_LEAVE] = { .state = GARP_APPLICANT_INVALID }, + }, + [GARP_APPLICANT_VP] = { + [GARP_EVENT_TRANSMIT_PDU] = { .state = GARP_APPLICANT_AA, + .action = GARP_ACTION_S_JOIN_IN }, + [GARP_EVENT_R_JOIN_IN] = { .state = GARP_APPLICANT_AP }, + [GARP_EVENT_R_JOIN_EMPTY] = { .state = GARP_APPLICANT_VP }, + [GARP_EVENT_R_EMPTY] = { .state = GARP_APPLICANT_VP }, + [GARP_EVENT_R_LEAVE_IN] = { .state = GARP_APPLICANT_VP }, + [GARP_EVENT_R_LEAVE_EMPTY] = { .state = GARP_APPLICANT_VP }, + [GARP_EVENT_REQ_JOIN] = { .state = GARP_APPLICANT_INVALID }, + [GARP_EVENT_REQ_LEAVE] = { .state = GARP_APPLICANT_VO }, + }, + [GARP_APPLICANT_AP] = { + [GARP_EVENT_TRANSMIT_PDU] = { .state = GARP_APPLICANT_QA, + .action = GARP_ACTION_S_JOIN_IN }, + [GARP_EVENT_R_JOIN_IN] = { .state = GARP_APPLICANT_QP }, + [GARP_EVENT_R_JOIN_EMPTY] = { .state = GARP_APPLICANT_VP }, + [GARP_EVENT_R_EMPTY] = { .state = GARP_APPLICANT_VP }, + [GARP_EVENT_R_LEAVE_IN] = { .state = GARP_APPLICANT_VP }, + [GARP_EVENT_R_LEAVE_EMPTY] = { .state = GARP_APPLICANT_VP }, + [GARP_EVENT_REQ_JOIN] = { .state = GARP_APPLICANT_INVALID }, + [GARP_EVENT_REQ_LEAVE] = { .state = GARP_APPLICANT_AO }, + }, + [GARP_APPLICANT_QP] = { + [GARP_EVENT_TRANSMIT_PDU] = { .state = GARP_APPLICANT_INVALID }, + [GARP_EVENT_R_JOIN_IN] = { .state = GARP_APPLICANT_QP }, + [GARP_EVENT_R_JOIN_EMPTY] = { .state = GARP_APPLICANT_VP }, + [GARP_EVENT_R_EMPTY] = { .state = GARP_APPLICANT_VP }, + [GARP_EVENT_R_LEAVE_IN] = { .state = GARP_APPLICANT_VP }, + [GARP_EVENT_R_LEAVE_EMPTY] = { .state = GARP_APPLICANT_VP }, + [GARP_EVENT_REQ_JOIN] = { .state = GARP_APPLICANT_INVALID }, + [GARP_EVENT_REQ_LEAVE] = { .state = GARP_APPLICANT_QO }, + }, + [GARP_APPLICANT_VO] = { + [GARP_EVENT_TRANSMIT_PDU] = { .state = GARP_APPLICANT_INVALID }, + [GARP_EVENT_R_JOIN_IN] = { .state = GARP_APPLICANT_AO }, + [GARP_EVENT_R_JOIN_EMPTY] = { .state = GARP_APPLICANT_VO }, + [GARP_EVENT_R_EMPTY] = { .state = GARP_APPLICANT_VO }, + [GARP_EVENT_R_LEAVE_IN] = { .state = GARP_APPLICANT_VO }, + [GARP_EVENT_R_LEAVE_EMPTY] = { .state = GARP_APPLICANT_VO }, + [GARP_EVENT_REQ_JOIN] = { .state = GARP_APPLICANT_VP }, + [GARP_EVENT_REQ_LEAVE] = { .state = GARP_APPLICANT_INVALID }, + }, + [GARP_APPLICANT_AO] = { + [GARP_EVENT_TRANSMIT_PDU] = { .state = GARP_APPLICANT_INVALID }, + [GARP_EVENT_R_JOIN_IN] = { .state = GARP_APPLICANT_QO }, + [GARP_EVENT_R_JOIN_EMPTY] = { .state = GARP_APPLICANT_VO }, + [GARP_EVENT_R_EMPTY] = { .state = GARP_APPLICANT_VO }, + [GARP_EVENT_R_LEAVE_IN] = { .state = GARP_APPLICANT_VO }, + [GARP_EVENT_R_LEAVE_EMPTY] = { .state = GARP_APPLICANT_VO }, + [GARP_EVENT_REQ_JOIN] = { .state = GARP_APPLICANT_AP }, + [GARP_EVENT_REQ_LEAVE] = { .state = GARP_APPLICANT_INVALID }, + }, + [GARP_APPLICANT_QO] = { + [GARP_EVENT_TRANSMIT_PDU] = { .state = GARP_APPLICANT_INVALID }, + [GARP_EVENT_R_JOIN_IN] = { .state = GARP_APPLICANT_QO }, + [GARP_EVENT_R_JOIN_EMPTY] = { .state = GARP_APPLICANT_VO }, + [GARP_EVENT_R_EMPTY] = { .state = GARP_APPLICANT_VO }, + [GARP_EVENT_R_LEAVE_IN] = { .state = GARP_APPLICANT_VO }, + [GARP_EVENT_R_LEAVE_EMPTY] = { .state = GARP_APPLICANT_VO }, + [GARP_EVENT_REQ_JOIN] = { .state = GARP_APPLICANT_QP }, + [GARP_EVENT_REQ_LEAVE] = { .state = GARP_APPLICANT_INVALID }, + }, +}; + +static int garp_attr_cmp(const struct garp_attr *attr, + const void *data, u8 len, u8 type) +{ + if (attr->type != type) + return attr->type - type; + if (attr->dlen != len) + return attr->dlen - len; + return memcmp(attr->data, data, len); +} + +static struct garp_attr *garp_attr_lookup(const struct garp_applicant *app, + const void *data, u8 len, u8 type) +{ + struct rb_node *parent = app->gid.rb_node; + struct garp_attr *attr; + int d; + + while (parent) { + attr = rb_entry(parent, struct garp_attr, node); + d = garp_attr_cmp(attr, data, len, type); + if (d < 0) + parent = parent->rb_left; + else if (d > 0) + parent = parent->rb_right; + else + return attr; + } + return NULL; +} + +static void garp_attr_insert(struct garp_applicant *app, struct garp_attr *new) +{ + struct rb_node *parent = NULL, **p = &app->gid.rb_node; + struct garp_attr *attr; + int d; + + while (*p) { + parent = *p; + attr = rb_entry(parent, struct garp_attr, node); + d = garp_attr_cmp(attr, new->data, new->dlen, new->type); + if (d < 0) + p = &parent->rb_left; + else if (d > 0) + p = &parent->rb_right; + } + rb_link_node(&new->node, parent, p); + rb_insert_color(&new->node, &app->gid); +} + +static struct garp_attr *garp_attr_create(struct garp_applicant *app, + const void *data, u8 len, u8 type) +{ + struct garp_attr *attr; + + attr = kmalloc(sizeof(*attr) + len, GFP_ATOMIC); + if (!attr) + return attr; + attr->state = GARP_APPLICANT_VO; + attr->type = type; + attr->dlen = len; + memcpy(attr->data, data, len); + garp_attr_insert(app, attr); + return attr; +} + +static void garp_attr_destroy(struct garp_applicant *app, struct garp_attr *attr) +{ + rb_erase(&attr->node, &app->gid); + kfree(attr); +} + +static int garp_pdu_init(struct garp_applicant *app) +{ + struct sk_buff *skb; + struct garp_pdu_hdr *gp; + +#define LLC_RESERVE sizeof(struct llc_pdu_un) + skb = alloc_skb(app->dev->mtu + LL_RESERVED_SPACE(app->dev), + GFP_ATOMIC); + if (!skb) + return -ENOMEM; + + skb->dev = app->dev; + skb->protocol = htons(ETH_P_802_2); + skb_reserve(skb, LL_RESERVED_SPACE(app->dev) + LLC_RESERVE); + + gp = (struct garp_pdu_hdr *)__skb_put(skb, sizeof(*gp)); + put_unaligned(htons(GARP_PROTOCOL_ID), &gp->protocol); + + app->pdu = skb; + return 0; +} + +static int garp_pdu_append_end_mark(struct garp_applicant *app) +{ + if (skb_tailroom(app->pdu) < sizeof(u8)) + return -1; + *(u8 *)__skb_put(app->pdu, sizeof(u8)) = GARP_END_MARK; + return 0; +} + +static void garp_pdu_queue(struct garp_applicant *app) +{ + if (!app->pdu) + return; + + garp_pdu_append_end_mark(app); + garp_pdu_append_end_mark(app); + + llc_pdu_header_init(app->pdu, LLC_PDU_TYPE_U, LLC_SAP_BSPAN, + LLC_SAP_BSPAN, LLC_PDU_CMD); + llc_pdu_init_as_ui_cmd(app->pdu); + llc_mac_hdr_init(app->pdu, app->dev->dev_addr, + app->app->proto.group_address); + + skb_queue_tail(&app->queue, app->pdu); + app->pdu = NULL; +} + +static void garp_queue_xmit(struct garp_applicant *app) +{ + struct sk_buff *skb; + + while ((skb = skb_dequeue(&app->queue))) + dev_queue_xmit(skb); +} + +static int garp_pdu_append_msg(struct garp_applicant *app, u8 attrtype) +{ + struct garp_msg_hdr *gm; + + if (skb_tailroom(app->pdu) < sizeof(*gm)) + return -1; + gm = (struct garp_msg_hdr *)__skb_put(app->pdu, sizeof(*gm)); + gm->attrtype = attrtype; + garp_cb(app->pdu)->cur_type = attrtype; + return 0; +} + +static int garp_pdu_append_attr(struct garp_applicant *app, + const struct garp_attr *attr, + enum garp_attr_event event) +{ + struct garp_attr_hdr *ga; + unsigned int len; + int err; +again: + if (!app->pdu) { + err = garp_pdu_init(app); + if (err < 0) + return err; + } + + if (garp_cb(app->pdu)->cur_type != attr->type) { + if (garp_cb(app->pdu)->cur_type && + garp_pdu_append_end_mark(app) < 0) + goto queue; + if (garp_pdu_append_msg(app, attr->type) < 0) + goto queue; + } + + len = sizeof(*ga) + attr->dlen; + if (skb_tailroom(app->pdu) < len) + goto queue; + ga = (struct garp_attr_hdr *)__skb_put(app->pdu, len); + ga->len = len; + ga->event = event; + memcpy(ga->data, attr->data, attr->dlen); + return 0; + +queue: + garp_pdu_queue(app); + goto again; +} + +static void garp_attr_event(struct garp_applicant *app, + struct garp_attr *attr, enum garp_event event) +{ + enum garp_applicant_state state; + + state = garp_applicant_state_table[attr->state][event].state; + if (state == GARP_APPLICANT_INVALID) + return; + + switch (garp_applicant_state_table[attr->state][event].action) { + case GARP_ACTION_NONE: + break; + case GARP_ACTION_S_JOIN_IN: + /* When appending the attribute fails, don't update state in + * order to retry on next TRANSMIT_PDU event. */ + if (garp_pdu_append_attr(app, attr, GARP_JOIN_IN) < 0) + return; + break; + case GARP_ACTION_S_LEAVE_EMPTY: + garp_pdu_append_attr(app, attr, GARP_LEAVE_EMPTY); + /* As a pure applicant, sending a leave message implies that + * the attribute was unregistered and can be destroyed. */ + garp_attr_destroy(app, attr); + return; + default: + WARN_ON(1); + } + + attr->state = state; +} + +int garp_request_join(const struct net_device *dev, + const struct garp_application *appl, + const void *data, u8 len, u8 type) +{ + struct garp_port *port = dev->garp_port; + struct garp_applicant *app = port->applicants[appl->type]; + struct garp_attr *attr; + + spin_lock_bh(&app->lock); + attr = garp_attr_create(app, data, len, type); + if (!attr) { + spin_unlock_bh(&app->lock); + return -ENOMEM; + } + garp_attr_event(app, attr, GARP_EVENT_REQ_JOIN); + spin_unlock_bh(&app->lock); + return 0; +} +EXPORT_SYMBOL_GPL(garp_request_join); + +void garp_request_leave(const struct net_device *dev, + const struct garp_application *appl, + const void *data, u8 len, u8 type) +{ + struct garp_port *port = dev->garp_port; + struct garp_applicant *app = port->applicants[appl->type]; + struct garp_attr *attr; + + spin_lock_bh(&app->lock); + attr = garp_attr_lookup(app, data, len, type); + if (!attr) { + spin_unlock_bh(&app->lock); + return; + } + garp_attr_event(app, attr, GARP_EVENT_REQ_LEAVE); + spin_unlock_bh(&app->lock); +} +EXPORT_SYMBOL_GPL(garp_request_leave); + +static void garp_gid_event(struct garp_applicant *app, enum garp_event event) +{ + struct rb_node *node, *next; + struct garp_attr *attr; + + for (node = rb_first(&app->gid); + next = node ? rb_next(node) : NULL, node != NULL; + node = next) { + attr = rb_entry(node, struct garp_attr, node); + garp_attr_event(app, attr, event); + } +} + +static void garp_join_timer_arm(struct garp_applicant *app) +{ + unsigned long delay; + + delay = (u64)msecs_to_jiffies(garp_join_time) * net_random() >> 32; + mod_timer(&app->join_timer, jiffies + delay); +} + +static void garp_join_timer(unsigned long data) +{ + struct garp_applicant *app = (struct garp_applicant *)data; + + spin_lock(&app->lock); + garp_gid_event(app, GARP_EVENT_TRANSMIT_PDU); + garp_pdu_queue(app); + spin_unlock(&app->lock); + + garp_queue_xmit(app); + garp_join_timer_arm(app); +} + +static int garp_pdu_parse_end_mark(struct sk_buff *skb) +{ + if (!pskb_may_pull(skb, sizeof(u8))) + return -1; + if (*skb->data == GARP_END_MARK) { + skb_pull(skb, sizeof(u8)); + return -1; + } + return 0; +} + +static int garp_pdu_parse_attr(struct garp_applicant *app, struct sk_buff *skb, + u8 attrtype) +{ + const struct garp_attr_hdr *ga; + struct garp_attr *attr; + enum garp_event event; + unsigned int dlen; + + if (!pskb_may_pull(skb, sizeof(*ga))) + return -1; + ga = (struct garp_attr_hdr *)skb->data; + if (ga->len < sizeof(*ga)) + return -1; + + if (!pskb_may_pull(skb, ga->len)) + return -1; + skb_pull(skb, ga->len); + dlen = sizeof(*ga) - ga->len; + + if (attrtype > app->app->maxattr) + return 0; + + switch (ga->event) { + case GARP_LEAVE_ALL: + if (dlen != 0) + return -1; + garp_gid_event(app, GARP_EVENT_R_LEAVE_EMPTY); + return 0; + case GARP_JOIN_EMPTY: + event = GARP_EVENT_R_JOIN_EMPTY; + break; + case GARP_JOIN_IN: + event = GARP_EVENT_R_JOIN_IN; + break; + case GARP_LEAVE_EMPTY: + event = GARP_EVENT_R_LEAVE_EMPTY; + break; + case GARP_EMPTY: + event = GARP_EVENT_R_EMPTY; + break; + default: + return 0; + } + + if (dlen == 0) + return -1; + attr = garp_attr_lookup(app, ga->data, dlen, attrtype); + if (attr == NULL) + return 0; + garp_attr_event(app, attr, event); + return 0; +} + +static int garp_pdu_parse_msg(struct garp_applicant *app, struct sk_buff *skb) +{ + const struct garp_msg_hdr *gm; + + if (!pskb_may_pull(skb, sizeof(*gm))) + return -1; + gm = (struct garp_msg_hdr *)skb->data; + if (gm->attrtype == 0) + return -1; + skb_pull(skb, sizeof(*gm)); + + while (skb->len > 0) { + if (garp_pdu_parse_attr(app, skb, gm->attrtype) < 0) + return -1; + if (garp_pdu_parse_end_mark(skb) < 0) + break; + } + return 0; +} + +static void garp_pdu_rcv(const struct stp_proto *proto, struct sk_buff *skb, + struct net_device *dev) +{ + struct garp_application *appl = proto->data; + struct garp_port *port; + struct garp_applicant *app; + const struct garp_pdu_hdr *gp; + + port = rcu_dereference(dev->garp_port); + if (!port) + goto err; + app = rcu_dereference(port->applicants[appl->type]); + if (!app) + goto err; + + if (!pskb_may_pull(skb, sizeof(*gp))) + goto err; + gp = (struct garp_pdu_hdr *)skb->data; + if (get_unaligned(&gp->protocol) != htons(GARP_PROTOCOL_ID)) + goto err; + skb_pull(skb, sizeof(*gp)); + + spin_lock(&app->lock); + while (skb->len > 0) { + if (garp_pdu_parse_msg(app, skb) < 0) + break; + if (garp_pdu_parse_end_mark(skb) < 0) + break; + } + spin_unlock(&app->lock); +err: + kfree_skb(skb); +} + +static int garp_init_port(struct net_device *dev) +{ + struct garp_port *port; + + port = kzalloc(sizeof(*port), GFP_KERNEL); + if (!port) + return -ENOMEM; + rcu_assign_pointer(dev->garp_port, port); + return 0; +} + +static void garp_release_port(struct net_device *dev) +{ + struct garp_port *port = dev->garp_port; + unsigned int i; + + for (i = 0; i <= GARP_APPLICATION_MAX; i++) { + if (port->applicants[i]) + return; + } + rcu_assign_pointer(dev->garp_port, NULL); + synchronize_rcu(); + kfree(port); +} + +int garp_init_applicant(struct net_device *dev, struct garp_application *appl) +{ + struct garp_applicant *app; + int err; + + ASSERT_RTNL(); + + if (!dev->garp_port) { + err = garp_init_port(dev); + if (err < 0) + goto err1; + } + + err = -ENOMEM; + app = kzalloc(sizeof(*app), GFP_KERNEL); + if (!app) + goto err2; + + err = dev_mc_add(dev, appl->proto.group_address, ETH_ALEN, 0); + if (err < 0) + goto err3; + + app->dev = dev; + app->app = appl; + app->gid = RB_ROOT; + spin_lock_init(&app->lock); + skb_queue_head_init(&app->queue); + rcu_assign_pointer(dev->garp_port->applicants[appl->type], app); + setup_timer(&app->join_timer, garp_join_timer, (unsigned long)app); + garp_join_timer_arm(app); + return 0; + +err3: + kfree(app); +err2: + garp_release_port(dev); +err1: + return err; +} +EXPORT_SYMBOL_GPL(garp_init_applicant); + +void garp_uninit_applicant(struct net_device *dev, struct garp_application *appl) +{ + struct garp_port *port = dev->garp_port; + struct garp_applicant *app = port->applicants[appl->type]; + + ASSERT_RTNL(); + + rcu_assign_pointer(port->applicants[appl->type], NULL); + synchronize_rcu(); + + /* Delete timer and generate a final TRANSMIT_PDU event to flush out + * all pending messages before the applicant is gone. */ + del_timer_sync(&app->join_timer); + garp_gid_event(app, GARP_EVENT_TRANSMIT_PDU); + garp_pdu_queue(app); + garp_queue_xmit(app); + + dev_mc_delete(dev, appl->proto.group_address, ETH_ALEN, 0); + kfree(app); + garp_release_port(dev); +} +EXPORT_SYMBOL_GPL(garp_uninit_applicant); + +int garp_register_application(struct garp_application *appl) +{ + appl->proto.rcv = garp_pdu_rcv; + appl->proto.data = appl; + return stp_proto_register(&appl->proto); +} +EXPORT_SYMBOL_GPL(garp_register_application); + +void garp_unregister_application(struct garp_application *appl) +{ + stp_proto_unregister(&appl->proto); +} +EXPORT_SYMBOL_GPL(garp_unregister_application); diff --git a/net/802/stp.c b/net/802/stp.c new file mode 100644 index 000000000000..0b7a24452d11 --- /dev/null +++ b/net/802/stp.c @@ -0,0 +1,102 @@ +/* + * STP SAP demux + * + * Copyright (c) 2008 Patrick McHardy <kaber@trash.net> + * + * 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 <linux/mutex.h> +#include <linux/skbuff.h> +#include <linux/etherdevice.h> +#include <linux/llc.h> +#include <net/llc.h> +#include <net/llc_pdu.h> +#include <net/stp.h> + +/* 01:80:c2:00:00:20 - 01:80:c2:00:00:2F */ +#define GARP_ADDR_MIN 0x20 +#define GARP_ADDR_MAX 0x2F +#define GARP_ADDR_RANGE (GARP_ADDR_MAX - GARP_ADDR_MIN) + +static const struct stp_proto *garp_protos[GARP_ADDR_RANGE + 1] __read_mostly; +static const struct stp_proto *stp_proto __read_mostly; + +static struct llc_sap *sap __read_mostly; +static unsigned int sap_registered; +static DEFINE_MUTEX(stp_proto_mutex); + +/* Called under rcu_read_lock from LLC */ +static int stp_pdu_rcv(struct sk_buff *skb, struct net_device *dev, + struct packet_type *pt, struct net_device *orig_dev) +{ + const struct ethhdr *eh = eth_hdr(skb); + const struct llc_pdu_un *pdu = llc_pdu_un_hdr(skb); + const struct stp_proto *proto; + + if (pdu->ssap != LLC_SAP_BSPAN || + pdu->dsap != LLC_SAP_BSPAN || + pdu->ctrl_1 != LLC_PDU_TYPE_U) + goto err; + + if (eh->h_dest[5] >= GARP_ADDR_MIN && eh->h_dest[5] <= GARP_ADDR_MAX) { + proto = rcu_dereference(garp_protos[eh->h_dest[5] - + GARP_ADDR_MIN]); + if (proto && + compare_ether_addr(eh->h_dest, proto->group_address)) + goto err; + } else + proto = rcu_dereference(stp_proto); + + if (!proto) + goto err; + + proto->rcv(proto, skb, dev); + return 0; + +err: + kfree_skb(skb); + return 0; +} + +int stp_proto_register(const struct stp_proto *proto) +{ + int err = 0; + + mutex_lock(&stp_proto_mutex); + if (sap_registered++ == 0) { + sap = llc_sap_open(LLC_SAP_BSPAN, stp_pdu_rcv); + if (!sap) { + err = -ENOMEM; + goto out; + } + } + if (is_zero_ether_addr(proto->group_address)) + rcu_assign_pointer(stp_proto, proto); + else + rcu_assign_pointer(garp_protos[proto->group_address[5] - + GARP_ADDR_MIN], proto); +out: + mutex_unlock(&stp_proto_mutex); + return err; +} +EXPORT_SYMBOL_GPL(stp_proto_register); + +void stp_proto_unregister(const struct stp_proto *proto) +{ + mutex_lock(&stp_proto_mutex); + if (is_zero_ether_addr(proto->group_address)) + rcu_assign_pointer(stp_proto, NULL); + else + rcu_assign_pointer(garp_protos[proto->group_address[5] - + GARP_ADDR_MIN], NULL); + synchronize_rcu(); + + if (--sap_registered == 0) + llc_sap_put(sap); + mutex_unlock(&stp_proto_mutex); +} +EXPORT_SYMBOL_GPL(stp_proto_unregister); + +MODULE_LICENSE("GPL"); diff --git a/net/8021q/Kconfig b/net/8021q/Kconfig index c4a382e450e2..fa073a54963e 100644 --- a/net/8021q/Kconfig +++ b/net/8021q/Kconfig @@ -17,3 +17,13 @@ config VLAN_8021Q will be called 8021q. If unsure, say N. + +config VLAN_8021Q_GVRP + bool "GVRP (GARP VLAN Registration Protocol) support" + depends on VLAN_8021Q + select GARP + help + Select this to enable GVRP end-system support. GVRP is used for + automatic propagation of registered VLANs to switches. + + If unsure, say N. diff --git a/net/8021q/Makefile b/net/8021q/Makefile index 10ca7f486c3a..9f4f174ead1c 100644 --- a/net/8021q/Makefile +++ b/net/8021q/Makefile @@ -1,12 +1,10 @@ # # Makefile for the Linux VLAN layer. # +obj-$(subst m,y,$(CONFIG_VLAN_8021Q)) += vlan_core.o +obj-$(CONFIG_VLAN_8021Q) += 8021q.o -obj-$(CONFIG_VLAN_8021Q) += 8021q.o - -8021q-objs := vlan.o vlan_dev.o vlan_netlink.o - -ifeq ($(CONFIG_PROC_FS),y) -8021q-objs += vlanproc.o -endif +8021q-y := vlan.o vlan_dev.o vlan_netlink.o +8021q-$(CONFIG_VLAN_8021Q_GVRP) += vlan_gvrp.o +8021q-$(CONFIG_PROC_FS) += vlanproc.o diff --git a/net/8021q/vlan.c b/net/8021q/vlan.c index 08f14f6c5fd6..b661f47bf10a 100644 --- a/net/8021q/vlan.c +++ b/net/8021q/vlan.c @@ -18,22 +18,20 @@ * 2 of the License, or (at your option) any later version. */ -#include <asm/uaccess.h> /* for copy_from_user */ #include <linux/capability.h> #include <linux/module.h> #include <linux/netdevice.h> #include <linux/skbuff.h> -#include <net/datalink.h> -#include <linux/mm.h> -#include <linux/in.h> #include <linux/init.h> #include <linux/rculist.h> #include <net/p8022.h> #include <net/arp.h> #include <linux/rtnetlink.h> #include <linux/notifier.h> +#include <net/rtnetlink.h> #include <net/net_namespace.h> #include <net/netns/generic.h> +#include <asm/uaccess.h> #include <linux/if_vlan.h> #include "vlan.h" @@ -84,13 +82,12 @@ static struct vlan_group *__vlan_find_group(struct net_device *real_dev) * * Must be invoked with RCU read lock (no preempt) */ -struct net_device *__find_vlan_dev(struct net_device *real_dev, - unsigned short VID) +struct net_device *__find_vlan_dev(struct net_device *real_dev, u16 vlan_id) { struct vlan_group *grp = __vlan_find_group(real_dev); if (grp) - return vlan_group_get_device(grp, VID); + return vlan_group_get_device(grp, vlan_id); return NULL; } @@ -118,14 +115,14 @@ static struct vlan_group *vlan_group_alloc(struct net_device *real_dev) return grp; } -static int vlan_group_prealloc_vid(struct vlan_group *vg, int vid) +static int vlan_group_prealloc_vid(struct vlan_group *vg, u16 vlan_id) { struct net_device **array; unsigned int size; ASSERT_RTNL(); - array = vg->vlan_devices_arrays[vid / VLAN_GROUP_ARRAY_PART_LEN]; + array = vg->vlan_devices_arrays[vlan_id / VLAN_GROUP_ARRAY_PART_LEN]; if (array != NULL) return 0; @@ -134,7 +131,7 @@ static int vlan_group_prealloc_vid(struct vlan_group *vg, int vid) if (array == NULL) return -ENOBUFS; - vg->vlan_devices_arrays[vid / VLAN_GROUP_ARRAY_PART_LEN] = array; + vg->vlan_devices_arrays[vlan_id / VLAN_GROUP_ARRAY_PART_LEN] = array; return 0; } @@ -148,7 +145,7 @@ void unregister_vlan_dev(struct net_device *dev) struct vlan_dev_info *vlan = vlan_dev_info(dev); struct net_device *real_dev = vlan->real_dev; struct vlan_group *grp; - unsigned short vlan_id = vlan->vlan_id; + u16 vlan_id = vlan->vlan_id; ASSERT_RTNL(); @@ -166,8 +163,12 @@ void unregister_vlan_dev(struct net_device *dev) synchronize_net(); + unregister_netdevice(dev); + /* If the group is now empty, kill off the group. */ if (grp->nr_vlans == 0) { + vlan_gvrp_uninit_applicant(real_dev); + if (real_dev->features & NETIF_F_HW_VLAN_RX) real_dev->vlan_rx_register(real_dev, NULL); @@ -179,8 +180,6 @@ void unregister_vlan_dev(struct net_device *dev) /* Get rid of the vlan's reference to real_dev */ dev_put(real_dev); - - unregister_netdevice(dev); } static void vlan_transfer_operstate(const struct net_device *dev, @@ -204,7 +203,7 @@ static void vlan_transfer_operstate(const struct net_device *dev, } } -int vlan_check_real_dev(struct net_device *real_dev, unsigned short vlan_id) +int vlan_check_real_dev(struct net_device *real_dev, u16 vlan_id) { char *name = real_dev->name; @@ -241,7 +240,7 @@ int register_vlan_dev(struct net_device *dev) { struct vlan_dev_info *vlan = vlan_dev_info(dev); struct net_device *real_dev = vlan->real_dev; - unsigned short vlan_id = vlan->vlan_id; + u16 vlan_id = vlan->vlan_id; struct vlan_group *grp, *ngrp = NULL; int err; @@ -250,15 +249,18 @@ int register_vlan_dev(struct net_device *dev) ngrp = grp = vlan_group_alloc(real_dev); if (!grp) return -ENOBUFS; + err = vlan_gvrp_init_applicant(real_dev); + if (err < 0) + goto out_free_group; } err = vlan_group_prealloc_vid(grp, vlan_id); if (err < 0) - goto out_free_group; + goto out_uninit_applicant; err = register_netdevice(dev); if (err < 0) - goto out_free_group; + goto out_uninit_applicant; /* Account for reference in struct vlan_dev_info */ dev_hold(real_dev); @@ -279,6 +281,9 @@ int register_vlan_dev(struct net_device *dev) return 0; +out_uninit_applicant: + if (ngrp) + vlan_gvrp_uninit_applicant(real_dev); out_free_group: if (ngrp) vlan_group_free(ngrp); @@ -288,8 +293,7 @@ out_free_group: /* Attach a VLAN device to a mac address (ie Ethernet Card). * Returns 0 if the device was created or a negative error code otherwise. */ -static int register_vlan_device(struct net_device *real_dev, - unsigned short VLAN_ID) +static int register_vlan_device(struct net_device *real_dev, u16 vlan_id) { struct net_device *new_dev; struct net *net = dev_net(real_dev); @@ -297,10 +301,10 @@ static int register_vlan_device(struct net_device *real_dev, char name[IFNAMSIZ]; int err; - if (VLAN_ID >= VLAN_VID_MASK) + if (vlan_id >= VLAN_VID_MASK) return -ERANGE; - err = vlan_check_real_dev(real_dev, VLAN_ID); + err = vlan_check_real_dev(real_dev, vlan_id); if (err < 0) return err; @@ -308,26 +312,26 @@ static int register_vlan_device(struct net_device *real_dev, switch (vn->name_type) { case VLAN_NAME_TYPE_RAW_PLUS_VID: /* name will look like: eth1.0005 */ - snprintf(name, IFNAMSIZ, "%s.%.4i", real_dev->name, VLAN_ID); + snprintf(name, IFNAMSIZ, "%s.%.4i", real_dev->name, vlan_id); break; case VLAN_NAME_TYPE_PLUS_VID_NO_PAD: /* Put our vlan.VID in the name. * Name will look like: vlan5 */ - snprintf(name, IFNAMSIZ, "vlan%i", VLAN_ID); + snprintf(name, IFNAMSIZ, "vlan%i", vlan_id); break; case VLAN_NAME_TYPE_RAW_PLUS_VID_NO_PAD: /* Put our vlan.VID in the name. * Name will look like: eth0.5 */ - snprintf(name, IFNAMSIZ, "%s.%i", real_dev->name, VLAN_ID); + snprintf(name, IFNAMSIZ, "%s.%i", real_dev->name, vlan_id); break; case VLAN_NAME_TYPE_PLUS_VID: /* Put our vlan.VID in the name. * Name will look like: vlan0005 */ default: - snprintf(name, IFNAMSIZ, "vlan%.4i", VLAN_ID); + snprintf(name, IFNAMSIZ, "vlan%.4i", vlan_id); } new_dev = alloc_netdev(sizeof(struct vlan_dev_info), name, @@ -342,7 +346,7 @@ static int register_vlan_device(struct net_device *real_dev, */ new_dev->mtu = real_dev->mtu; - vlan_dev_info(new_dev)->vlan_id = VLAN_ID; /* 1 through VLAN_VID_MASK */ + vlan_dev_info(new_dev)->vlan_id = vlan_id; vlan_dev_info(new_dev)->real_dev = real_dev; vlan_dev_info(new_dev)->dent = NULL; vlan_dev_info(new_dev)->flags = VLAN_FLAG_REORDER_HDR; @@ -536,7 +540,6 @@ static struct notifier_block vlan_notifier_block __read_mostly = { static int vlan_ioctl_handler(struct net *net, void __user *arg) { int err; - unsigned short vid = 0; struct vlan_ioctl_args args; struct net_device *dev = NULL; @@ -563,8 +566,7 @@ static int vlan_ioctl_handler(struct net *net, void __user *arg) goto out; err = -EINVAL; - if (args.cmd != ADD_VLAN_CMD && - !(dev->priv_flags & IFF_802_1Q_VLAN)) + if (args.cmd != ADD_VLAN_CMD && !is_vlan_dev(dev)) goto out; } @@ -592,9 +594,9 @@ static int vlan_ioctl_handler(struct net *net, void __user *arg) err = -EPERM; if (!capable(CAP_NET_ADMIN)) break; - err = vlan_dev_set_vlan_flag(dev, - args.u.flag, - args.vlan_qos); + err = vlan_dev_change_flags(dev, + args.vlan_qos ? args.u.flag : 0, + args.u.flag); break; case SET_VLAN_NAME_TYPE_CMD: @@ -638,8 +640,7 @@ static int vlan_ioctl_handler(struct net *net, void __user *arg) case GET_VLAN_VID_CMD: err = 0; - vlan_dev_get_vid(dev, &vid); - args.u.VID = vid; + args.u.VID = vlan_dev_vlan_id(dev); if (copy_to_user(arg, &args, sizeof(struct vlan_ioctl_args))) err = -EFAULT; @@ -714,14 +715,20 @@ static int __init vlan_proto_init(void) if (err < 0) goto err2; - err = vlan_netlink_init(); + err = vlan_gvrp_init(); if (err < 0) goto err3; + err = vlan_netlink_init(); + if (err < 0) + goto err4; + dev_add_pack(&vlan_packet_type); vlan_ioctl_set(vlan_ioctl_handler); return 0; +err4: + vlan_gvrp_uninit(); err3: unregister_netdevice_notifier(&vlan_notifier_block); err2: @@ -746,8 +753,9 @@ 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(); + + vlan_gvrp_uninit(); } module_init(vlan_proto_init); diff --git a/net/8021q/vlan.h b/net/8021q/vlan.h index 5229a72c7ea1..a6603a4d917f 100644 --- a/net/8021q/vlan.h +++ b/net/8021q/vlan.h @@ -3,6 +3,55 @@ #include <linux/if_vlan.h> + +/** + * struct vlan_priority_tci_mapping - vlan egress priority mappings + * @priority: skb priority + * @vlan_qos: vlan priority: (skb->priority << 13) & 0xE000 + * @next: pointer to next struct + */ +struct vlan_priority_tci_mapping { + u32 priority; + u16 vlan_qos; + struct vlan_priority_tci_mapping *next; +}; + +/** + * struct vlan_dev_info - VLAN private device data + * @nr_ingress_mappings: number of ingress priority mappings + * @ingress_priority_map: ingress priority mappings + * @nr_egress_mappings: number of egress priority mappings + * @egress_priority_map: hash of egress priority mappings + * @vlan_id: VLAN identifier + * @flags: device flags + * @real_dev: underlying netdevice + * @real_dev_addr: address of underlying netdevice + * @dent: proc dir entry + * @cnt_inc_headroom_on_tx: statistic - number of skb expansions on TX + * @cnt_encap_on_xmit: statistic - number of skb encapsulations on TX + */ +struct vlan_dev_info { + unsigned int nr_ingress_mappings; + u32 ingress_priority_map[8]; + unsigned int nr_egress_mappings; + struct vlan_priority_tci_mapping *egress_priority_map[16]; + + u16 vlan_id; + u16 flags; + + struct net_device *real_dev; + unsigned char real_dev_addr[ETH_ALEN]; + + struct proc_dir_entry *dent; + unsigned long cnt_inc_headroom_on_tx; + unsigned long cnt_encap_on_xmit; +}; + +static inline struct vlan_dev_info *vlan_dev_info(const struct net_device *dev) +{ + return netdev_priv(dev); +} + #define VLAN_GRP_HASH_SHIFT 5 #define VLAN_GRP_HASH_SIZE (1 << VLAN_GRP_HASH_SHIFT) #define VLAN_GRP_HASH_MASK (VLAN_GRP_HASH_SIZE - 1) @@ -18,26 +67,47 @@ * Must be invoked with rcu_read_lock (ie preempt disabled) * or with RTNL. */ -struct net_device *__find_vlan_dev(struct net_device *real_dev, - unsigned short VID); /* vlan.c */ +struct net_device *__find_vlan_dev(struct net_device *real_dev, u16 vlan_id); /* found in vlan_dev.c */ int vlan_skb_recv(struct sk_buff *skb, struct net_device *dev, struct packet_type *ptype, struct net_device *orig_dev); void vlan_dev_set_ingress_priority(const struct net_device *dev, - u32 skb_prio, short vlan_prio); + u32 skb_prio, u16 vlan_prio); int vlan_dev_set_egress_priority(const struct net_device *dev, - u32 skb_prio, short vlan_prio); -int vlan_dev_set_vlan_flag(const struct net_device *dev, - u32 flag, short flag_val); + u32 skb_prio, u16 vlan_prio); +int vlan_dev_change_flags(const struct net_device *dev, u32 flag, u32 mask); void vlan_dev_get_realdev_name(const struct net_device *dev, char *result); -void vlan_dev_get_vid(const struct net_device *dev, unsigned short *result); -int vlan_check_real_dev(struct net_device *real_dev, unsigned short vlan_id); +int vlan_check_real_dev(struct net_device *real_dev, u16 vlan_id); void vlan_setup(struct net_device *dev); int register_vlan_dev(struct net_device *dev); void unregister_vlan_dev(struct net_device *dev); +static inline u32 vlan_get_ingress_priority(struct net_device *dev, + u16 vlan_tci) +{ + struct vlan_dev_info *vip = vlan_dev_info(dev); + + return vip->ingress_priority_map[(vlan_tci >> 13) & 0x7]; +} + +#ifdef CONFIG_VLAN_8021Q_GVRP +extern int vlan_gvrp_request_join(const struct net_device *dev); +extern void vlan_gvrp_request_leave(const struct net_device *dev); +extern int vlan_gvrp_init_applicant(struct net_device *dev); +extern void vlan_gvrp_uninit_applicant(struct net_device *dev); +extern int vlan_gvrp_init(void); +extern void vlan_gvrp_uninit(void); +#else +static inline int vlan_gvrp_request_join(const struct net_device *dev) { return 0; } +static inline void vlan_gvrp_request_leave(const struct net_device *dev) {} +static inline int vlan_gvrp_init_applicant(struct net_device *dev) { return 0; } +static inline void vlan_gvrp_uninit_applicant(struct net_device *dev) {} +static inline int vlan_gvrp_init(void) { return 0; } +static inline void vlan_gvrp_uninit(void) {} +#endif + int vlan_netlink_init(void); void vlan_netlink_fini(void); diff --git a/net/8021q/vlan_core.c b/net/8021q/vlan_core.c new file mode 100644 index 000000000000..916061f681b6 --- /dev/null +++ b/net/8021q/vlan_core.c @@ -0,0 +1,64 @@ +#include <linux/skbuff.h> +#include <linux/netdevice.h> +#include <linux/if_vlan.h> +#include "vlan.h" + +/* VLAN rx hw acceleration helper. This acts like netif_{rx,receive_skb}(). */ +int __vlan_hwaccel_rx(struct sk_buff *skb, struct vlan_group *grp, + u16 vlan_tci, int polling) +{ + struct net_device_stats *stats; + + if (skb_bond_should_drop(skb)) { + dev_kfree_skb_any(skb); + return NET_RX_DROP; + } + + skb->vlan_tci = vlan_tci; + netif_nit_deliver(skb); + + skb->dev = vlan_group_get_device(grp, vlan_tci & VLAN_VID_MASK); + if (skb->dev == NULL) { + dev_kfree_skb_any(skb); + /* Not NET_RX_DROP, this is not being dropped + * due to congestion. */ + return NET_RX_SUCCESS; + } + skb->dev->last_rx = jiffies; + skb->vlan_tci = 0; + + stats = &skb->dev->stats; + stats->rx_packets++; + stats->rx_bytes += skb->len; + + skb->priority = vlan_get_ingress_priority(skb->dev, vlan_tci); + switch (skb->pkt_type) { + case PACKET_BROADCAST: + break; + case PACKET_MULTICAST: + stats->multicast++; + break; + case PACKET_OTHERHOST: + /* Our lower layer thinks this is not local, let's make sure. + * This allows the VLAN to have a different MAC than the + * underlying device, and still route correctly. */ + if (!compare_ether_addr(eth_hdr(skb)->h_dest, + skb->dev->dev_addr)) + skb->pkt_type = PACKET_HOST; + break; + }; + return (polling ? netif_receive_skb(skb) : netif_rx(skb)); +} +EXPORT_SYMBOL(__vlan_hwaccel_rx); + +struct net_device *vlan_dev_real_dev(const struct net_device *dev) +{ + return vlan_dev_info(dev)->real_dev; +} +EXPORT_SYMBOL_GPL(vlan_dev_real_dev); + +u16 vlan_dev_vlan_id(const struct net_device *dev) +{ + return vlan_dev_info(dev)->vlan_id; +} +EXPORT_SYMBOL_GPL(vlan_dev_vlan_id); diff --git a/net/8021q/vlan_dev.c b/net/8021q/vlan_dev.c index 5d055c242ed8..f42bc2b26b85 100644 --- a/net/8021q/vlan_dev.c +++ b/net/8021q/vlan_dev.c @@ -21,21 +21,15 @@ */ #include <linux/module.h> -#include <linux/mm.h> -#include <linux/in.h> -#include <linux/init.h> -#include <asm/uaccess.h> /* for copy_from_user */ #include <linux/skbuff.h> #include <linux/netdevice.h> #include <linux/etherdevice.h> -#include <net/datalink.h> -#include <net/p8022.h> +#include <linux/ethtool.h> #include <net/arp.h> #include "vlan.h" #include "vlanproc.h" #include <linux/if_vlan.h> -#include <net/ip.h> /* * Rebuild the Ethernet MAC header. This is called after an ARP @@ -73,11 +67,8 @@ static int vlan_dev_rebuild_header(struct sk_buff *skb) static inline struct sk_buff *vlan_check_reorder_header(struct sk_buff *skb) { if (vlan_dev_info(skb->dev)->flags & VLAN_FLAG_REORDER_HDR) { - if (skb_shared(skb) || skb_cloned(skb)) { - struct sk_buff *nskb = skb_copy(skb, GFP_ATOMIC); - kfree_skb(skb); - skb = nskb; - } + if (skb_cow(skb, skb_headroom(skb)) < 0) + skb = NULL; if (skb) { /* Lifted from Gleb's VLAN code... */ memmove(skb->data - ETH_HLEN, @@ -149,9 +140,9 @@ int vlan_skb_recv(struct sk_buff *skb, struct net_device *dev, struct packet_type *ptype, struct net_device *orig_dev) { struct vlan_hdr *vhdr; - unsigned short vid; struct net_device_stats *stats; - unsigned short vlan_TCI; + u16 vlan_id; + u16 vlan_tci; skb = skb_share_check(skb, GFP_ATOMIC); if (skb == NULL) @@ -161,14 +152,14 @@ int vlan_skb_recv(struct sk_buff *skb, struct net_device *dev, goto err_free; vhdr = (struct vlan_hdr *)skb->data; - vlan_TCI = ntohs(vhdr->h_vlan_TCI); - vid = (vlan_TCI & VLAN_VID_MASK); + vlan_tci = ntohs(vhdr->h_vlan_TCI); + vlan_id = vlan_tci & VLAN_VID_MASK; rcu_read_lock(); - skb->dev = __find_vlan_dev(dev, vid); + skb->dev = __find_vlan_dev(dev, vlan_id); if (!skb->dev) { pr_debug("%s: ERROR: No net_device for VID: %u on dev: %s\n", - __func__, (unsigned int)vid, dev->name); + __func__, vlan_id, dev->name); goto err_unlock; } @@ -180,11 +171,10 @@ int vlan_skb_recv(struct sk_buff *skb, struct net_device *dev, skb_pull_rcsum(skb, VLAN_HLEN); - skb->priority = vlan_get_ingress_priority(skb->dev, - ntohs(vhdr->h_vlan_TCI)); + skb->priority = vlan_get_ingress_priority(skb->dev, vlan_tci); pr_debug("%s: priority: %u for TCI: %hu\n", - __func__, skb->priority, ntohs(vhdr->h_vlan_TCI)); + __func__, skb->priority, vlan_tci); switch (skb->pkt_type) { case PACKET_BROADCAST: /* Yeah, stats collect these together.. */ @@ -227,7 +217,7 @@ err_free: return NET_RX_DROP; } -static inline unsigned short +static inline u16 vlan_dev_get_egress_qos_mask(struct net_device *dev, struct sk_buff *skb) { struct vlan_priority_tci_mapping *mp; @@ -259,103 +249,44 @@ static int vlan_dev_hard_header(struct sk_buff *skb, struct net_device *dev, unsigned int len) { struct vlan_hdr *vhdr; - unsigned short veth_TCI = 0; - int rc = 0; - int build_vlan_header = 0; - struct net_device *vdev = dev; - - pr_debug("%s: skb: %p type: %hx len: %u vlan_id: %hx, daddr: %p\n", - __func__, skb, type, len, vlan_dev_info(dev)->vlan_id, - daddr); - - /* build vlan header only if re_order_header flag is NOT set. This - * fixes some programs that get confused when they see a VLAN device - * sending a frame that is VLAN encoded (the consensus is that the VLAN - * device should look completely like an Ethernet device when the - * REORDER_HEADER flag is set) The drawback to this is some extra - * header shuffling in the hard_start_xmit. Users can turn off this - * REORDER behaviour with the vconfig tool. - */ - if (!(vlan_dev_info(dev)->flags & VLAN_FLAG_REORDER_HDR)) - build_vlan_header = 1; + unsigned int vhdrlen = 0; + u16 vlan_tci = 0; + int rc; - if (build_vlan_header) { - vhdr = (struct vlan_hdr *) skb_push(skb, VLAN_HLEN); + if (WARN_ON(skb_headroom(skb) < dev->hard_header_len)) + return -ENOSPC; - /* build the four bytes that make this a VLAN header. */ - - /* Now, construct the second two bytes. This field looks - * something like: - * usr_priority: 3 bits (high bits) - * CFI 1 bit - * VLAN ID 12 bits (low bits) - * - */ - veth_TCI = vlan_dev_info(dev)->vlan_id; - veth_TCI |= vlan_dev_get_egress_qos_mask(dev, skb); + if (!(vlan_dev_info(dev)->flags & VLAN_FLAG_REORDER_HDR)) { + vhdr = (struct vlan_hdr *) skb_push(skb, VLAN_HLEN); - vhdr->h_vlan_TCI = htons(veth_TCI); + vlan_tci = vlan_dev_info(dev)->vlan_id; + vlan_tci |= vlan_dev_get_egress_qos_mask(dev, skb); + vhdr->h_vlan_TCI = htons(vlan_tci); /* * Set the protocol type. For a packet of type ETH_P_802_3 we * put the length in here instead. It is up to the 802.2 * layer to carry protocol information. */ - if (type != ETH_P_802_3) vhdr->h_vlan_encapsulated_proto = htons(type); else vhdr->h_vlan_encapsulated_proto = htons(len); skb->protocol = htons(ETH_P_8021Q); - skb_reset_network_header(skb); + type = ETH_P_8021Q; + vhdrlen = VLAN_HLEN; } /* Before delegating work to the lower layer, enter our MAC-address */ if (saddr == NULL) saddr = dev->dev_addr; + /* Now make the underlying real hard header */ dev = vlan_dev_info(dev)->real_dev; - - /* MPLS can send us skbuffs w/out enough space. This check will grow - * the skb if it doesn't have enough headroom. Not a beautiful solution, - * so I'll tick a counter so that users can know it's happening... - * If they care... - */ - - /* NOTE: This may still break if the underlying device is not the final - * device (and thus there are more headers to add...) It should work for - * good-ole-ethernet though. - */ - if (skb_headroom(skb) < dev->hard_header_len) { - struct sk_buff *sk_tmp = skb; - skb = skb_realloc_headroom(sk_tmp, dev->hard_header_len); - kfree_skb(sk_tmp); - if (skb == NULL) { - struct net_device_stats *stats = &vdev->stats; - stats->tx_dropped++; - return -ENOMEM; - } - vlan_dev_info(vdev)->cnt_inc_headroom_on_tx++; - pr_debug("%s: %s: had to grow skb\n", __func__, vdev->name); - } - - if (build_vlan_header) { - /* Now make the underlying real hard header */ - rc = dev_hard_header(skb, dev, ETH_P_8021Q, daddr, saddr, - len + VLAN_HLEN); - if (rc > 0) - rc += VLAN_HLEN; - else if (rc < 0) - rc -= VLAN_HLEN; - } else - /* If here, then we'll just make a normal looking ethernet - * frame, but, the hard_start_xmit method will insert the tag - * (it has to be able to do this for bridged and other skbs - * that don't come down the protocol stack in an orderly manner. - */ - rc = dev_hard_header(skb, dev, type, daddr, saddr, len); - + rc = dev_hard_header(skb, dev, type, daddr, saddr, len + vhdrlen); + if (rc > 0) + rc += vhdrlen; return rc; } @@ -369,78 +300,49 @@ static int vlan_dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) * NOTE: THIS ASSUMES DIX ETHERNET, SPECIFICALLY NOT SUPPORTING * OTHER THINGS LIKE FDDI/TokenRing/802.3 SNAPs... */ - if (veth->h_vlan_proto != htons(ETH_P_8021Q) || - vlan_dev_info(dev)->flags & VLAN_FLAG_REORDER_HDR) { - int orig_headroom = skb_headroom(skb); - unsigned short veth_TCI; + vlan_dev_info(dev)->flags & VLAN_FLAG_REORDER_HDR) { + unsigned int orig_headroom = skb_headroom(skb); + u16 vlan_tci; - /* This is not a VLAN frame...but we can fix that! */ vlan_dev_info(dev)->cnt_encap_on_xmit++; - pr_debug("%s: proto to encap: 0x%hx\n", - __func__, ntohs(veth->h_vlan_proto)); - /* Construct the second two bytes. This field looks something - * like: - * usr_priority: 3 bits (high bits) - * CFI 1 bit - * VLAN ID 12 bits (low bits) - */ - veth_TCI = vlan_dev_info(dev)->vlan_id; - veth_TCI |= vlan_dev_get_egress_qos_mask(dev, skb); - - skb = __vlan_put_tag(skb, veth_TCI); + vlan_tci = vlan_dev_info(dev)->vlan_id; + vlan_tci |= vlan_dev_get_egress_qos_mask(dev, skb); + skb = __vlan_put_tag(skb, vlan_tci); if (!skb) { stats->tx_dropped++; - return 0; + return NETDEV_TX_OK; } if (orig_headroom < VLAN_HLEN) vlan_dev_info(dev)->cnt_inc_headroom_on_tx++; } - pr_debug("%s: about to send skb: %p to dev: %s\n", - __func__, skb, skb->dev->name); - pr_debug(" " MAC_FMT " " MAC_FMT " %4hx %4hx %4hx\n", - veth->h_dest[0], veth->h_dest[1], veth->h_dest[2], - veth->h_dest[3], veth->h_dest[4], veth->h_dest[5], - veth->h_source[0], veth->h_source[1], veth->h_source[2], - veth->h_source[3], veth->h_source[4], veth->h_source[5], - veth->h_vlan_proto, veth->h_vlan_TCI, - veth->h_vlan_encapsulated_proto); - - stats->tx_packets++; /* for statics only */ + stats->tx_packets++; stats->tx_bytes += skb->len; skb->dev = vlan_dev_info(dev)->real_dev; dev_queue_xmit(skb); - - return 0; + return NETDEV_TX_OK; } static int vlan_dev_hwaccel_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) { struct net_device_stats *stats = &dev->stats; - unsigned short veth_TCI; + u16 vlan_tci; - /* Construct the second two bytes. This field looks something - * like: - * usr_priority: 3 bits (high bits) - * CFI 1 bit - * VLAN ID 12 bits (low bits) - */ - veth_TCI = vlan_dev_info(dev)->vlan_id; - veth_TCI |= vlan_dev_get_egress_qos_mask(dev, skb); - skb = __vlan_hwaccel_put_tag(skb, veth_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; skb->dev = vlan_dev_info(dev)->real_dev; dev_queue_xmit(skb); - - return 0; + return NETDEV_TX_OK; } static int vlan_dev_change_mtu(struct net_device *dev, int new_mtu) @@ -457,7 +359,7 @@ static int vlan_dev_change_mtu(struct net_device *dev, int new_mtu) } void vlan_dev_set_ingress_priority(const struct net_device *dev, - u32 skb_prio, short vlan_prio) + u32 skb_prio, u16 vlan_prio) { struct vlan_dev_info *vlan = vlan_dev_info(dev); @@ -470,7 +372,7 @@ void vlan_dev_set_ingress_priority(const struct net_device *dev, } int vlan_dev_set_egress_priority(const struct net_device *dev, - u32 skb_prio, short vlan_prio) + u32 skb_prio, u16 vlan_prio) { struct vlan_dev_info *vlan = vlan_dev_info(dev); struct vlan_priority_tci_mapping *mp = NULL; @@ -507,18 +409,23 @@ int vlan_dev_set_egress_priority(const struct net_device *dev, } /* Flags are defined in the vlan_flags enum in include/linux/if_vlan.h file. */ -int vlan_dev_set_vlan_flag(const struct net_device *dev, - u32 flag, short flag_val) +int vlan_dev_change_flags(const struct net_device *dev, u32 flags, u32 mask) { - /* verify flag is supported */ - if (flag == VLAN_FLAG_REORDER_HDR) { - if (flag_val) - vlan_dev_info(dev)->flags |= VLAN_FLAG_REORDER_HDR; + struct vlan_dev_info *vlan = vlan_dev_info(dev); + u32 old_flags = vlan->flags; + + if (mask & ~(VLAN_FLAG_REORDER_HDR | VLAN_FLAG_GVRP)) + return -EINVAL; + + vlan->flags = (old_flags & ~mask) | (flags & mask); + + if (netif_running(dev) && (vlan->flags ^ old_flags) & VLAN_FLAG_GVRP) { + if (vlan->flags & VLAN_FLAG_GVRP) + vlan_gvrp_request_join(dev); else - vlan_dev_info(dev)->flags &= ~VLAN_FLAG_REORDER_HDR; - return 0; + vlan_gvrp_request_leave(dev); } - return -EINVAL; + return 0; } void vlan_dev_get_realdev_name(const struct net_device *dev, char *result) @@ -526,11 +433,6 @@ void vlan_dev_get_realdev_name(const struct net_device *dev, char *result) strncpy(result, vlan_dev_info(dev)->real_dev->name, 23); } -void vlan_dev_get_vid(const struct net_device *dev, unsigned short *result) -{ - *result = vlan_dev_info(dev)->vlan_id; -} - static int vlan_dev_open(struct net_device *dev) { struct vlan_dev_info *vlan = vlan_dev_info(dev); @@ -543,21 +445,44 @@ static int vlan_dev_open(struct net_device *dev) if (compare_ether_addr(dev->dev_addr, real_dev->dev_addr)) { err = dev_unicast_add(real_dev, dev->dev_addr, ETH_ALEN); if (err < 0) - return err; + goto out; + } + + if (dev->flags & IFF_ALLMULTI) { + err = dev_set_allmulti(real_dev, 1); + if (err < 0) + goto del_unicast; } + if (dev->flags & IFF_PROMISC) { + err = dev_set_promiscuity(real_dev, 1); + if (err < 0) + goto clear_allmulti; + } + memcpy(vlan->real_dev_addr, real_dev->dev_addr, ETH_ALEN); - if (dev->flags & IFF_ALLMULTI) - dev_set_allmulti(real_dev, 1); - if (dev->flags & IFF_PROMISC) - dev_set_promiscuity(real_dev, 1); + if (vlan->flags & VLAN_FLAG_GVRP) + vlan_gvrp_request_join(dev); return 0; + +clear_allmulti: + if (dev->flags & IFF_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); +out: + return err; } static int vlan_dev_stop(struct net_device *dev) { - struct net_device *real_dev = vlan_dev_info(dev)->real_dev; + struct vlan_dev_info *vlan = vlan_dev_info(dev); + struct net_device *real_dev = vlan->real_dev; + + if (vlan->flags & VLAN_FLAG_GVRP) + vlan_gvrp_request_leave(dev); dev_mc_unsync(real_dev, dev); dev_unicast_unsync(real_dev, dev); @@ -645,6 +570,20 @@ static void vlan_dev_set_rx_mode(struct net_device *vlan_dev) */ static struct lock_class_key vlan_netdev_xmit_lock_key; +static void vlan_dev_set_lockdep_one(struct net_device *dev, + struct netdev_queue *txq, + void *_subclass) +{ + lockdep_set_class_and_subclass(&txq->_xmit_lock, + &vlan_netdev_xmit_lock_key, + *(int *)_subclass); +} + +static void vlan_dev_set_lockdep_class(struct net_device *dev, int subclass) +{ + netdev_for_each_tx_queue(dev, vlan_dev_set_lockdep_one, &subclass); +} + static const struct header_ops vlan_header_ops = { .create = vlan_dev_hard_header, .rebuild = vlan_dev_rebuild_header, @@ -683,11 +622,10 @@ static int vlan_dev_init(struct net_device *dev) dev->hard_start_xmit = vlan_dev_hard_start_xmit; } - if (real_dev->priv_flags & IFF_802_1Q_VLAN) + if (is_vlan_dev(real_dev)) subclass = 1; - lockdep_set_class_and_subclass(&dev->_xmit_lock, - &vlan_netdev_xmit_lock_key, subclass); + vlan_dev_set_lockdep_class(dev, subclass); return 0; } @@ -705,6 +643,35 @@ static void vlan_dev_uninit(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); +} + +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); +} + +static const struct ethtool_ops vlan_ethtool_ops = { + .get_link = ethtool_op_get_link, + .get_rx_csum = vlan_ethtool_get_rx_csum, + .get_flags = vlan_ethtool_get_flags, +}; + void vlan_setup(struct net_device *dev) { ether_setup(dev); @@ -723,6 +690,7 @@ void vlan_setup(struct net_device *dev) dev->change_rx_flags = vlan_dev_change_rx_flags; dev->do_ioctl = vlan_dev_ioctl; dev->destructor = free_netdev; + dev->ethtool_ops = &vlan_ethtool_ops; memset(dev->broadcast, 0, ETH_ALEN); } diff --git a/net/8021q/vlan_gvrp.c b/net/8021q/vlan_gvrp.c new file mode 100644 index 000000000000..061ceceeef12 --- /dev/null +++ b/net/8021q/vlan_gvrp.c @@ -0,0 +1,66 @@ +/* + * IEEE 802.1Q GARP VLAN Registration Protocol (GVRP) + * + * Copyright (c) 2008 Patrick McHardy <kaber@trash.net> + * + * 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 <linux/types.h> +#include <linux/if_vlan.h> +#include <net/garp.h> +#include "vlan.h" + +#define GARP_GVRP_ADDRESS { 0x01, 0x80, 0xc2, 0x00, 0x00, 0x21 } + +enum gvrp_attributes { + GVRP_ATTR_INVALID, + GVRP_ATTR_VID, + __GVRP_ATTR_MAX +}; +#define GVRP_ATTR_MAX (__GVRP_ATTR_MAX - 1) + +static struct garp_application vlan_gvrp_app __read_mostly = { + .proto.group_address = GARP_GVRP_ADDRESS, + .maxattr = GVRP_ATTR_MAX, + .type = GARP_APPLICATION_GVRP, +}; + +int vlan_gvrp_request_join(const struct net_device *dev) +{ + const struct vlan_dev_info *vlan = vlan_dev_info(dev); + __be16 vlan_id = htons(vlan->vlan_id); + + return garp_request_join(vlan->real_dev, &vlan_gvrp_app, + &vlan_id, sizeof(vlan_id), GVRP_ATTR_VID); +} + +void vlan_gvrp_request_leave(const struct net_device *dev) +{ + const struct vlan_dev_info *vlan = vlan_dev_info(dev); + __be16 vlan_id = htons(vlan->vlan_id); + + garp_request_leave(vlan->real_dev, &vlan_gvrp_app, + &vlan_id, sizeof(vlan_id), GVRP_ATTR_VID); +} + +int vlan_gvrp_init_applicant(struct net_device *dev) +{ + return garp_init_applicant(dev, &vlan_gvrp_app); +} + +void vlan_gvrp_uninit_applicant(struct net_device *dev) +{ + garp_uninit_applicant(dev, &vlan_gvrp_app); +} + +int __init vlan_gvrp_init(void) +{ + return garp_register_application(&vlan_gvrp_app); +} + +void vlan_gvrp_uninit(void) +{ + garp_unregister_application(&vlan_gvrp_app); +} diff --git a/net/8021q/vlan_netlink.c b/net/8021q/vlan_netlink.c index c93e69ec28ed..e9c91dcecc9b 100644 --- a/net/8021q/vlan_netlink.c +++ b/net/8021q/vlan_netlink.c @@ -59,7 +59,8 @@ static int vlan_validate(struct nlattr *tb[], struct nlattr *data[]) } if (data[IFLA_VLAN_FLAGS]) { flags = nla_data(data[IFLA_VLAN_FLAGS]); - if ((flags->flags & flags->mask) & ~VLAN_FLAG_REORDER_HDR) + if ((flags->flags & flags->mask) & + ~(VLAN_FLAG_REORDER_HDR | VLAN_FLAG_GVRP)) return -EINVAL; } @@ -75,7 +76,6 @@ static int vlan_validate(struct nlattr *tb[], struct nlattr *data[]) static int vlan_changelink(struct net_device *dev, struct nlattr *tb[], struct nlattr *data[]) { - struct vlan_dev_info *vlan = vlan_dev_info(dev); struct ifla_vlan_flags *flags; struct ifla_vlan_qos_mapping *m; struct nlattr *attr; @@ -83,8 +83,7 @@ static int vlan_changelink(struct net_device *dev, if (data[IFLA_VLAN_FLAGS]) { flags = nla_data(data[IFLA_VLAN_FLAGS]); - vlan->flags = (vlan->flags & ~flags->mask) | - (flags->flags & flags->mask); + vlan_dev_change_flags(dev, flags->flags, flags->mask); } if (data[IFLA_VLAN_INGRESS_QOS]) { nla_for_each_nested(attr, data[IFLA_VLAN_INGRESS_QOS], rem) { diff --git a/net/8021q/vlanproc.c b/net/8021q/vlanproc.c index 08b54b593d56..0feefa4e1a4b 100644 --- a/net/8021q/vlanproc.c +++ b/net/8021q/vlanproc.c @@ -18,16 +18,9 @@ *****************************************************************************/ #include <linux/module.h> -#include <linux/stddef.h> /* offsetof(), etc. */ -#include <linux/errno.h> /* return codes */ +#include <linux/errno.h> #include <linux/kernel.h> -#include <linux/slab.h> /* kmalloc(), kfree() */ -#include <linux/mm.h> -#include <linux/string.h> /* inline mem*, str* functions */ -#include <linux/init.h> /* __initfunc et al. */ -#include <asm/byteorder.h> /* htons(), etc. */ -#include <asm/uaccess.h> /* copy_to_user */ -#include <asm/io.h> +#include <linux/string.h> #include <linux/proc_fs.h> #include <linux/seq_file.h> #include <linux/fs.h> @@ -290,7 +283,7 @@ static int vlandev_seq_show(struct seq_file *seq, void *offset) static const char fmt[] = "%30s %12lu\n"; int i; - if (!(vlandev->priv_flags & IFF_802_1Q_VLAN)) + if (!is_vlan_dev(vlandev)) return 0; seq_printf(seq, diff --git a/net/Kconfig b/net/Kconfig index acbf7c60e89b..b98668751749 100644 --- a/net/Kconfig +++ b/net/Kconfig @@ -181,6 +181,7 @@ source "net/dccp/Kconfig" source "net/sctp/Kconfig" source "net/tipc/Kconfig" source "net/atm/Kconfig" +source "net/802/Kconfig" source "net/bridge/Kconfig" source "net/8021q/Kconfig" source "net/decnet/Kconfig" diff --git a/net/Makefile b/net/Makefile index b7a13643b549..4f43e7f874f3 100644 --- a/net/Makefile +++ b/net/Makefile @@ -42,7 +42,9 @@ obj-$(CONFIG_AF_RXRPC) += rxrpc/ obj-$(CONFIG_ATM) += atm/ obj-$(CONFIG_DECNET) += decnet/ obj-$(CONFIG_ECONET) += econet/ -obj-$(CONFIG_VLAN_8021Q) += 8021q/ +ifneq ($(CONFIG_VLAN_8021Q),) +obj-y += 8021q/ +endif obj-$(CONFIG_IP_DCCP) += dccp/ obj-$(CONFIG_IP_SCTP) += sctp/ obj-y += wireless/ diff --git a/net/appletalk/aarp.c b/net/appletalk/aarp.c index 25aa37ce9430..b25c1e909d14 100644 --- a/net/appletalk/aarp.c +++ b/net/appletalk/aarp.c @@ -333,7 +333,7 @@ static int aarp_device_event(struct notifier_block *this, unsigned long event, struct net_device *dev = ptr; int ct; - if (dev_net(dev) != &init_net) + if (!net_eq(dev_net(dev), &init_net)) return NOTIFY_DONE; if (event == NETDEV_DOWN) { @@ -716,7 +716,7 @@ static int aarp_rcv(struct sk_buff *skb, struct net_device *dev, struct atalk_addr sa, *ma, da; struct atalk_iface *ifa; - if (dev_net(dev) != &init_net) + if (!net_eq(dev_net(dev), &init_net)) goto out0; /* We only do Ethernet SNAP AARP. */ diff --git a/net/appletalk/ddp.c b/net/appletalk/ddp.c index 44cd42f7786b..07b5b82c5eab 100644 --- a/net/appletalk/ddp.c +++ b/net/appletalk/ddp.c @@ -648,7 +648,7 @@ static int ddp_device_event(struct notifier_block *this, unsigned long event, { struct net_device *dev = ptr; - if (dev_net(dev) != &init_net) + if (!net_eq(dev_net(dev), &init_net)) return NOTIFY_DONE; if (event == NETDEV_DOWN) @@ -1405,7 +1405,7 @@ static int atalk_rcv(struct sk_buff *skb, struct net_device *dev, int origlen; __u16 len_hops; - if (dev_net(dev) != &init_net) + if (!net_eq(dev_net(dev), &init_net)) goto freeit; /* Don't mangle buffer if shared */ @@ -1493,7 +1493,7 @@ freeit: static int ltalk_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt, struct net_device *orig_dev) { - if (dev_net(dev) != &init_net) + if (!net_eq(dev_net(dev), &init_net)) goto freeit; /* Expand any short form frames */ diff --git a/net/atm/addr.c b/net/atm/addr.c index 6afa77d63bb5..82e85abc303d 100644 --- a/net/atm/addr.c +++ b/net/atm/addr.c @@ -9,7 +9,7 @@ #include "signaling.h" #include "addr.h" -static int check_addr(struct sockaddr_atmsvc *addr) +static int check_addr(const struct sockaddr_atmsvc *addr) { int i; @@ -23,7 +23,7 @@ static int check_addr(struct sockaddr_atmsvc *addr) return -EINVAL; } -static int identical(struct sockaddr_atmsvc *a, struct sockaddr_atmsvc *b) +static int identical(const struct sockaddr_atmsvc *a, const struct sockaddr_atmsvc *b) { if (*a->sas_addr.prv) if (memcmp(a->sas_addr.prv, b->sas_addr.prv, ATM_ESA_LEN)) @@ -35,7 +35,7 @@ static int identical(struct sockaddr_atmsvc *a, struct sockaddr_atmsvc *b) return !strcmp(a->sas_addr.pub, b->sas_addr.pub); } -static void notify_sigd(struct atm_dev *dev) +static void notify_sigd(const struct atm_dev *dev) { struct sockaddr_atmpvc pvc; @@ -63,7 +63,7 @@ void atm_reset_addr(struct atm_dev *dev, enum atm_addr_type_t atype) notify_sigd(dev); } -int atm_add_addr(struct atm_dev *dev, struct sockaddr_atmsvc *addr, +int atm_add_addr(struct atm_dev *dev, const struct sockaddr_atmsvc *addr, enum atm_addr_type_t atype) { unsigned long flags; @@ -98,7 +98,7 @@ int atm_add_addr(struct atm_dev *dev, struct sockaddr_atmsvc *addr, return 0; } -int atm_del_addr(struct atm_dev *dev, struct sockaddr_atmsvc *addr, +int atm_del_addr(struct atm_dev *dev, const struct sockaddr_atmsvc *addr, enum atm_addr_type_t atype) { unsigned long flags; diff --git a/net/atm/addr.h b/net/atm/addr.h index f39433ad45da..6837e9e7eb13 100644 --- a/net/atm/addr.h +++ b/net/atm/addr.h @@ -10,9 +10,9 @@ #include <linux/atmdev.h> void atm_reset_addr(struct atm_dev *dev, enum atm_addr_type_t type); -int atm_add_addr(struct atm_dev *dev, struct sockaddr_atmsvc *addr, +int atm_add_addr(struct atm_dev *dev, const struct sockaddr_atmsvc *addr, enum atm_addr_type_t type); -int atm_del_addr(struct atm_dev *dev, struct sockaddr_atmsvc *addr, +int atm_del_addr(struct atm_dev *dev, const struct sockaddr_atmsvc *addr, enum atm_addr_type_t type); int atm_get_addr(struct atm_dev *dev, struct sockaddr_atmsvc __user *buf, size_t size, enum atm_addr_type_t type); diff --git a/net/atm/br2684.c b/net/atm/br2684.c index 05fafdc2eea3..8d9a6f158880 100644 --- a/net/atm/br2684.c +++ b/net/atm/br2684.c @@ -52,12 +52,12 @@ static void skb_debug(const struct sk_buff *skb) #define ETHERTYPE_IPV6 0x86, 0xdd #define PAD_BRIDGED 0x00, 0x00 -static unsigned char ethertype_ipv4[] = { ETHERTYPE_IPV4 }; -static unsigned char ethertype_ipv6[] = { ETHERTYPE_IPV6 }; -static unsigned char llc_oui_pid_pad[] = +static const unsigned char ethertype_ipv4[] = { ETHERTYPE_IPV4 }; +static const unsigned char ethertype_ipv6[] = { ETHERTYPE_IPV6 }; +static const unsigned char llc_oui_pid_pad[] = { LLC, SNAP_BRIDGED, PID_ETHERNET, PAD_BRIDGED }; -static unsigned char llc_oui_ipv4[] = { LLC, SNAP_ROUTED, ETHERTYPE_IPV4 }; -static unsigned char llc_oui_ipv6[] = { LLC, SNAP_ROUTED, ETHERTYPE_IPV6 }; +static const unsigned char llc_oui_ipv4[] = { LLC, SNAP_ROUTED, ETHERTYPE_IPV4 }; +static const unsigned char llc_oui_ipv6[] = { LLC, SNAP_ROUTED, ETHERTYPE_IPV6 }; enum br2684_encaps { e_vc = BR2684_ENCAPS_VC, @@ -217,8 +217,8 @@ static int br2684_xmit_vcc(struct sk_buff *skb, struct br2684_dev *brdev, return 1; } -static inline struct br2684_vcc *pick_outgoing_vcc(struct sk_buff *skb, - struct br2684_dev *brdev) +static inline struct br2684_vcc *pick_outgoing_vcc(const struct sk_buff *skb, + const struct br2684_dev *brdev) { return list_empty(&brdev->brvccs) ? NULL : list_entry_brvcc(brdev->brvccs.next); /* 1 vcc/dev right now */ } diff --git a/net/atm/clip.c b/net/atm/clip.c index 6f8223ebf551..5b5b96344ce6 100644 --- a/net/atm/clip.c +++ b/net/atm/clip.c @@ -612,7 +612,7 @@ static int clip_device_event(struct notifier_block *this, unsigned long event, { struct net_device *dev = arg; - if (dev_net(dev) != &init_net) + if (!net_eq(dev_net(dev), &init_net)) return NOTIFY_DONE; if (event == NETDEV_UNREGISTER) { diff --git a/net/atm/common.c b/net/atm/common.c index c865517ba449..d34edbe754c8 100644 --- a/net/atm/common.c +++ b/net/atm/common.c @@ -262,7 +262,7 @@ static int adjust_tp(struct atm_trafprm *tp,unsigned char aal) } -static int check_ci(struct atm_vcc *vcc, short vpi, int vci) +static int check_ci(const struct atm_vcc *vcc, short vpi, int vci) { struct hlist_head *head = &vcc_hash[vci & (VCC_HTABLE_SIZE - 1)]; @@ -290,7 +290,7 @@ static int check_ci(struct atm_vcc *vcc, short vpi, int vci) } -static int find_ci(struct atm_vcc *vcc, short *vpi, int *vci) +static int find_ci(const struct atm_vcc *vcc, short *vpi, int *vci) { static short p; /* poor man's per-device cache */ static int c; @@ -646,7 +646,7 @@ static int atm_change_qos(struct atm_vcc *vcc,struct atm_qos *qos) } -static int check_tp(struct atm_trafprm *tp) +static int check_tp(const struct atm_trafprm *tp) { /* @@@ Should be merged with adjust_tp */ if (!tp->traffic_class || tp->traffic_class == ATM_ANYCLASS) return 0; @@ -663,7 +663,7 @@ static int check_tp(struct atm_trafprm *tp) } -static int check_qos(struct atm_qos *qos) +static int check_qos(const struct atm_qos *qos) { int error; diff --git a/net/atm/lec.c b/net/atm/lec.c index 653aca3573ac..5799fb52365a 100644 --- a/net/atm/lec.c +++ b/net/atm/lec.c @@ -65,36 +65,36 @@ static int lec_close(struct net_device *dev); static struct net_device_stats *lec_get_stats(struct net_device *dev); static void lec_init(struct net_device *dev); static struct lec_arp_table *lec_arp_find(struct lec_priv *priv, - unsigned char *mac_addr); + const unsigned char *mac_addr); static int lec_arp_remove(struct lec_priv *priv, struct lec_arp_table *to_remove); /* LANE2 functions */ -static void lane2_associate_ind(struct net_device *dev, u8 *mac_address, - u8 *tlvs, u32 sizeoftlvs); -static int lane2_resolve(struct net_device *dev, u8 *dst_mac, int force, +static void lane2_associate_ind(struct net_device *dev, const u8 *mac_address, + const u8 *tlvs, u32 sizeoftlvs); +static int lane2_resolve(struct net_device *dev, const u8 *dst_mac, int force, u8 **tlvs, u32 *sizeoftlvs); -static int lane2_associate_req(struct net_device *dev, u8 *lan_dst, - u8 *tlvs, u32 sizeoftlvs); +static int lane2_associate_req(struct net_device *dev, const u8 *lan_dst, + const u8 *tlvs, u32 sizeoftlvs); -static int lec_addr_delete(struct lec_priv *priv, unsigned char *atm_addr, +static int lec_addr_delete(struct lec_priv *priv, const unsigned char *atm_addr, unsigned long permanent); static void lec_arp_check_empties(struct lec_priv *priv, struct atm_vcc *vcc, struct sk_buff *skb); static void lec_arp_destroy(struct lec_priv *priv); static void lec_arp_init(struct lec_priv *priv); static struct atm_vcc *lec_arp_resolve(struct lec_priv *priv, - unsigned char *mac_to_find, + const unsigned char *mac_to_find, int is_rdesc, struct lec_arp_table **ret_entry); -static void lec_arp_update(struct lec_priv *priv, unsigned char *mac_addr, - unsigned char *atm_addr, unsigned long remoteflag, +static void lec_arp_update(struct lec_priv *priv, const unsigned char *mac_addr, + const unsigned char *atm_addr, unsigned long remoteflag, unsigned int targetless_le_arp); static void lec_flush_complete(struct lec_priv *priv, unsigned long tran_id); static int lec_mcast_make(struct lec_priv *priv, struct atm_vcc *vcc); static void lec_set_flush_tran_id(struct lec_priv *priv, - unsigned char *atm_addr, + const unsigned char *atm_addr, unsigned long tran_id); -static void lec_vcc_added(struct lec_priv *priv, struct atmlec_ioc *ioc_data, +static void lec_vcc_added(struct lec_priv *priv, const struct atmlec_ioc *ioc_data, struct atm_vcc *vcc, void (*old_push) (struct atm_vcc *vcc, struct sk_buff *skb)); @@ -634,7 +634,7 @@ static struct atm_dev lecatm_dev = { */ static int send_to_lecd(struct lec_priv *priv, atmlec_msg_type type, - unsigned char *mac_addr, unsigned char *atm_addr, + const unsigned char *mac_addr, const unsigned char *atm_addr, struct sk_buff *data) { struct sock *sk; @@ -705,10 +705,9 @@ static void lec_init(struct net_device *dev) dev->set_multicast_list = lec_set_multicast_list; dev->do_ioctl = NULL; printk("%s: Initialized!\n", dev->name); - return; } -static unsigned char lec_ctrl_magic[] = { +static const unsigned char lec_ctrl_magic[] = { 0xff, 0x00, 0x01, @@ -1276,7 +1275,7 @@ module_exit(lane_module_cleanup); * lec will be used. * If dst_mac == NULL, targetless LE_ARP will be sent */ -static int lane2_resolve(struct net_device *dev, u8 *dst_mac, int force, +static int lane2_resolve(struct net_device *dev, const u8 *dst_mac, int force, u8 **tlvs, u32 *sizeoftlvs) { unsigned long flags; @@ -1322,8 +1321,8 @@ static int lane2_resolve(struct net_device *dev, u8 *dst_mac, int force, * Returns 1 for success, 0 for failure (out of memory) * */ -static int lane2_associate_req(struct net_device *dev, u8 *lan_dst, - u8 *tlvs, u32 sizeoftlvs) +static int lane2_associate_req(struct net_device *dev, const u8 *lan_dst, + const u8 *tlvs, u32 sizeoftlvs) { int retval; struct sk_buff *skb; @@ -1358,8 +1357,8 @@ static int lane2_associate_req(struct net_device *dev, u8 *lan_dst, * LANE2: 3.1.5, LE_ASSOCIATE.indication * */ -static void lane2_associate_ind(struct net_device *dev, u8 *mac_addr, - u8 *tlvs, u32 sizeoftlvs) +static void lane2_associate_ind(struct net_device *dev, const u8 *mac_addr, + const u8 *tlvs, u32 sizeoftlvs) { #if 0 int i = 0; @@ -1744,7 +1743,7 @@ static void lec_arp_destroy(struct lec_priv *priv) * Find entry by mac_address */ static struct lec_arp_table *lec_arp_find(struct lec_priv *priv, - unsigned char *mac_addr) + const unsigned char *mac_addr) { struct hlist_node *node; struct hlist_head *head; @@ -1764,7 +1763,7 @@ static struct lec_arp_table *lec_arp_find(struct lec_priv *priv, } static struct lec_arp_table *make_entry(struct lec_priv *priv, - unsigned char *mac_addr) + const unsigned char *mac_addr) { struct lec_arp_table *to_return; @@ -1921,7 +1920,7 @@ restart: * */ static struct atm_vcc *lec_arp_resolve(struct lec_priv *priv, - unsigned char *mac_to_find, int is_rdesc, + const unsigned char *mac_to_find, int is_rdesc, struct lec_arp_table **ret_entry) { unsigned long flags; @@ -2017,7 +2016,7 @@ out: } static int -lec_addr_delete(struct lec_priv *priv, unsigned char *atm_addr, +lec_addr_delete(struct lec_priv *priv, const unsigned char *atm_addr, unsigned long permanent) { unsigned long flags; @@ -2047,8 +2046,8 @@ lec_addr_delete(struct lec_priv *priv, unsigned char *atm_addr, * Notifies: Response to arp_request (atm_addr != NULL) */ static void -lec_arp_update(struct lec_priv *priv, unsigned char *mac_addr, - unsigned char *atm_addr, unsigned long remoteflag, +lec_arp_update(struct lec_priv *priv, const unsigned char *mac_addr, + const unsigned char *atm_addr, unsigned long remoteflag, unsigned int targetless_le_arp) { unsigned long flags; @@ -2148,7 +2147,7 @@ out: * Notifies: Vcc setup ready */ static void -lec_vcc_added(struct lec_priv *priv, struct atmlec_ioc *ioc_data, +lec_vcc_added(struct lec_priv *priv, const struct atmlec_ioc *ioc_data, struct atm_vcc *vcc, void (*old_push) (struct atm_vcc *vcc, struct sk_buff *skb)) { @@ -2336,7 +2335,7 @@ restart: static void lec_set_flush_tran_id(struct lec_priv *priv, - unsigned char *atm_addr, unsigned long tran_id) + const unsigned char *atm_addr, unsigned long tran_id) { unsigned long flags; struct hlist_node *node; diff --git a/net/atm/lec.h b/net/atm/lec.h index b41cda7ea1e1..0d376682c1a3 100644 --- a/net/atm/lec.h +++ b/net/atm/lec.h @@ -42,12 +42,12 @@ struct lecdatahdr_8025 { * */ struct lane2_ops { - int (*resolve) (struct net_device *dev, u8 *dst_mac, int force, + int (*resolve) (struct net_device *dev, const u8 *dst_mac, int force, u8 **tlvs, u32 *sizeoftlvs); - int (*associate_req) (struct net_device *dev, u8 *lan_dst, - u8 *tlvs, u32 sizeoftlvs); - void (*associate_indicator) (struct net_device *dev, u8 *mac_addr, - u8 *tlvs, u32 sizeoftlvs); + int (*associate_req) (struct net_device *dev, const u8 *lan_dst, + const u8 *tlvs, u32 sizeoftlvs); + void (*associate_indicator) (struct net_device *dev, const u8 *mac_addr, + const u8 *tlvs, u32 sizeoftlvs); }; /* diff --git a/net/atm/mpc.c b/net/atm/mpc.c index 9db332e7a6c0..4fccaa1e07be 100644 --- a/net/atm/mpc.c +++ b/net/atm/mpc.c @@ -964,7 +964,7 @@ static int mpoa_event_listener(struct notifier_block *mpoa_notifier, unsigned lo dev = (struct net_device *)dev_ptr; - if (dev_net(dev) != &init_net) + if (!net_eq(dev_net(dev), &init_net)) return NOTIFY_DONE; if (dev->name == NULL || strncmp(dev->name, "lec", 3)) diff --git a/net/ax25/af_ax25.c b/net/ax25/af_ax25.c index 2712544cf0ca..01c83e2a4c19 100644 --- a/net/ax25/af_ax25.c +++ b/net/ax25/af_ax25.c @@ -116,7 +116,7 @@ static int ax25_device_event(struct notifier_block *this, unsigned long event, { struct net_device *dev = (struct net_device *)ptr; - if (dev_net(dev) != &init_net) + if (!net_eq(dev_net(dev), &init_net)) return NOTIFY_DONE; /* Reject non AX.25 devices */ @@ -893,13 +893,11 @@ struct sock *ax25_make_new(struct sock *osk, struct ax25_dev *ax25_dev) sk->sk_destruct = ax25_free_sock; sk->sk_type = osk->sk_type; - sk->sk_socket = osk->sk_socket; sk->sk_priority = osk->sk_priority; sk->sk_protocol = osk->sk_protocol; sk->sk_rcvbuf = osk->sk_rcvbuf; sk->sk_sndbuf = osk->sk_sndbuf; sk->sk_state = TCP_ESTABLISHED; - sk->sk_sleep = osk->sk_sleep; sock_copy_flags(sk, osk); oax25 = ax25_sk(osk); @@ -1361,13 +1359,11 @@ static int ax25_accept(struct socket *sock, struct socket *newsock, int flags) goto out; newsk = skb->sk; - newsk->sk_socket = newsock; - newsk->sk_sleep = &newsock->wait; + sock_graft(newsk, newsock); /* Now attach up the new socket */ kfree_skb(skb); sk->sk_ack_backlog--; - newsock->sk = newsk; newsock->state = SS_CONNECTED; out: diff --git a/net/ax25/ax25_in.c b/net/ax25/ax25_in.c index 33790a8efbc8..4a5ba978a804 100644 --- a/net/ax25/ax25_in.c +++ b/net/ax25/ax25_in.c @@ -451,7 +451,7 @@ int ax25_kiss_rcv(struct sk_buff *skb, struct net_device *dev, skb->sk = NULL; /* Initially we don't know who it's for */ skb->destructor = NULL; /* Who initializes this, dammit?! */ - if (dev_net(dev) != &init_net) { + if (!net_eq(dev_net(dev), &init_net)) { kfree_skb(skb); return 0; } diff --git a/net/ax25/ax25_std_timer.c b/net/ax25/ax25_std_timer.c index 96e4b9273250..cdc7e751ef36 100644 --- a/net/ax25/ax25_std_timer.c +++ b/net/ax25/ax25_std_timer.c @@ -39,11 +39,9 @@ void ax25_std_heartbeat_expiry(ax25_cb *ax25) switch (ax25->state) { case AX25_STATE_0: - /* Magic here: If we listen() and a new link dies before it - is accepted() it isn't 'dead' so doesn't get removed. */ - if (!sk || sock_flag(sk, SOCK_DESTROY) || - (sk->sk_state == TCP_LISTEN && - sock_flag(sk, SOCK_DEAD))) { + if (!sk || + sock_flag(sk, SOCK_DESTROY) || + sock_flag(sk, SOCK_DEAD)) { if (sk) { sock_hold(sk); ax25_destroy_socket(ax25); diff --git a/net/bluetooth/af_bluetooth.c b/net/bluetooth/af_bluetooth.c index d366423c8392..4e59df5f8e05 100644 --- a/net/bluetooth/af_bluetooth.c +++ b/net/bluetooth/af_bluetooth.c @@ -36,6 +36,7 @@ #include <linux/init.h> #include <linux/poll.h> #include <net/sock.h> +#include <asm/ioctls.h> #if defined(CONFIG_KMOD) #include <linux/kmod.h> @@ -48,7 +49,7 @@ #define BT_DBG(D...) #endif -#define VERSION "2.11" +#define VERSION "2.12" /* Bluetooth sockets */ #define BT_MAX_PROTO 8 @@ -266,6 +267,8 @@ int bt_sock_recvmsg(struct kiocb *iocb, struct socket *sock, skb_reset_transport_header(skb); err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied); + if (err == 0) + sock_recv_timestamp(msg, sk, skb); skb_free_datagram(sk, skb); @@ -329,6 +332,54 @@ unsigned int bt_sock_poll(struct file * file, struct socket *sock, poll_table *w } EXPORT_SYMBOL(bt_sock_poll); +int bt_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) +{ + struct sock *sk = sock->sk; + struct sk_buff *skb; + long amount; + int err; + + BT_DBG("sk %p cmd %x arg %lx", sk, cmd, arg); + + switch (cmd) { + case TIOCOUTQ: + if (sk->sk_state == BT_LISTEN) + return -EINVAL; + + amount = sk->sk_sndbuf - atomic_read(&sk->sk_wmem_alloc); + if (amount < 0) + amount = 0; + err = put_user(amount, (int __user *) arg); + break; + + case TIOCINQ: + if (sk->sk_state == BT_LISTEN) + return -EINVAL; + + lock_sock(sk); + skb = skb_peek(&sk->sk_receive_queue); + amount = skb ? skb->len : 0; + release_sock(sk); + err = put_user(amount, (int __user *) arg); + break; + + case SIOCGSTAMP: + err = sock_get_timestamp(sk, (struct timeval __user *) arg); + break; + + case SIOCGSTAMPNS: + err = sock_get_timestampns(sk, (struct timespec __user *) arg); + break; + + default: + err = -ENOIOCTLCMD; + break; + } + + return err; +} +EXPORT_SYMBOL(bt_sock_ioctl); + int bt_sock_wait_state(struct sock *sk, int state, unsigned long timeo) { DECLARE_WAITQUEUE(wait, current); diff --git a/net/bluetooth/bnep/bnep.h b/net/bluetooth/bnep/bnep.h index e69244dd8de8..b69bf4e7c48b 100644 --- a/net/bluetooth/bnep/bnep.h +++ b/net/bluetooth/bnep/bnep.h @@ -16,10 +16,6 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -/* - * $Id: bnep.h,v 1.5 2002/08/04 21:23:58 maxk Exp $ - */ - #ifndef _BNEP_H #define _BNEP_H diff --git a/net/bluetooth/bnep/core.c b/net/bluetooth/bnep/core.c index f85d94643aaf..021172c0e666 100644 --- a/net/bluetooth/bnep/core.c +++ b/net/bluetooth/bnep/core.c @@ -25,10 +25,6 @@ SOFTWARE IS DISCLAIMED. */ -/* - * $Id: core.c,v 1.20 2002/08/04 21:23:58 maxk Exp $ - */ - #include <linux/module.h> #include <linux/kernel.h> @@ -507,6 +503,11 @@ static int bnep_session(void *arg) /* Delete network device */ unregister_netdev(dev); + /* Wakeup user-space polling for socket errors */ + s->sock->sk->sk_err = EUNATCH; + + wake_up_interruptible(s->sock->sk->sk_sleep); + /* Release the socket */ fput(s->sock->file); diff --git a/net/bluetooth/bnep/netdev.c b/net/bluetooth/bnep/netdev.c index 95e3837e4312..d9fa0ab2c87f 100644 --- a/net/bluetooth/bnep/netdev.c +++ b/net/bluetooth/bnep/netdev.c @@ -25,10 +25,6 @@ SOFTWARE IS DISCLAIMED. */ -/* - * $Id: netdev.c,v 1.8 2002/08/04 21:23:58 maxk Exp $ - */ - #include <linux/module.h> #include <linux/socket.h> diff --git a/net/bluetooth/bnep/sock.c b/net/bluetooth/bnep/sock.c index 201e5b1ce473..8ffb57f2303a 100644 --- a/net/bluetooth/bnep/sock.c +++ b/net/bluetooth/bnep/sock.c @@ -24,10 +24,6 @@ SOFTWARE IS DISCLAIMED. */ -/* - * $Id: sock.c,v 1.4 2002/08/04 21:23:58 maxk Exp $ - */ - #include <linux/module.h> #include <linux/types.h> diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index f8880261da0e..ca8d05245ca0 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -59,24 +59,31 @@ void hci_acl_connect(struct hci_conn *conn) BT_DBG("%p", conn); conn->state = BT_CONNECT; - conn->out = 1; + conn->out = 1; + conn->link_mode = HCI_LM_MASTER; conn->attempt++; + conn->link_policy = hdev->link_policy; + memset(&cp, 0, sizeof(cp)); bacpy(&cp.bdaddr, &conn->dst); cp.pscan_rep_mode = 0x02; - if ((ie = hci_inquiry_cache_lookup(hdev, &conn->dst)) && - inquiry_entry_age(ie) <= INQUIRY_ENTRY_AGE_MAX) { - cp.pscan_rep_mode = ie->data.pscan_rep_mode; - cp.pscan_mode = ie->data.pscan_mode; - cp.clock_offset = ie->data.clock_offset | cpu_to_le16(0x8000); + if ((ie = hci_inquiry_cache_lookup(hdev, &conn->dst))) { + if (inquiry_entry_age(ie) <= INQUIRY_ENTRY_AGE_MAX) { + cp.pscan_rep_mode = ie->data.pscan_rep_mode; + cp.pscan_mode = ie->data.pscan_mode; + cp.clock_offset = ie->data.clock_offset | + cpu_to_le16(0x8000); + } + memcpy(conn->dev_class, ie->data.dev_class, 3); + conn->ssp_mode = ie->data.ssp_mode; } - cp.pkt_type = cpu_to_le16(hdev->pkt_type & ACL_PTYPE_MASK); + cp.pkt_type = cpu_to_le16(conn->pkt_type); if (lmp_rswitch_capable(hdev) && !(hdev->link_mode & HCI_LM_MASTER)) cp.role_switch = 0x01; else @@ -122,7 +129,7 @@ void hci_add_sco(struct hci_conn *conn, __u16 handle) conn->out = 1; cp.handle = cpu_to_le16(handle); - cp.pkt_type = cpu_to_le16(hdev->pkt_type & SCO_PTYPE_MASK); + cp.pkt_type = cpu_to_le16(conn->pkt_type); hci_send_cmd(hdev, HCI_OP_ADD_SCO, sizeof(cp), &cp); } @@ -138,7 +145,7 @@ void hci_setup_sync(struct hci_conn *conn, __u16 handle) conn->out = 1; cp.handle = cpu_to_le16(handle); - cp.pkt_type = cpu_to_le16(hdev->esco_type); + cp.pkt_type = cpu_to_le16(conn->pkt_type); cp.tx_bandwidth = cpu_to_le32(0x00001f40); cp.rx_bandwidth = cpu_to_le32(0x00001f40); @@ -163,11 +170,13 @@ static void hci_conn_timeout(unsigned long arg) switch (conn->state) { case BT_CONNECT: + case BT_CONNECT2: if (conn->type == ACL_LINK) hci_acl_connect_cancel(conn); else hci_acl_disconn(conn, 0x13); break; + case BT_CONFIG: case BT_CONNECTED: hci_acl_disconn(conn, 0x13); break; @@ -199,13 +208,28 @@ struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst) return NULL; bacpy(&conn->dst, dst); - conn->hdev = hdev; - conn->type = type; - conn->mode = HCI_CM_ACTIVE; - conn->state = BT_OPEN; + conn->hdev = hdev; + conn->type = type; + conn->mode = HCI_CM_ACTIVE; + conn->state = BT_OPEN; conn->power_save = 1; + switch (type) { + case ACL_LINK: + conn->pkt_type = hdev->pkt_type & ACL_PTYPE_MASK; + break; + case SCO_LINK: + if (lmp_esco_capable(hdev)) + conn->pkt_type = hdev->esco_type & SCO_ESCO_MASK; + else + conn->pkt_type = hdev->pkt_type & SCO_PTYPE_MASK; + break; + case ESCO_LINK: + conn->pkt_type = hdev->esco_type; + break; + } + skb_queue_head_init(&conn->data_q); setup_timer(&conn->disc_timer, hci_conn_timeout, (unsigned long)conn); @@ -221,8 +245,6 @@ struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst) if (hdev->notify) hdev->notify(hdev, HCI_NOTIFY_CONN_ADD); - hci_conn_add_sysfs(conn); - tasklet_enable(&hdev->tx_task); return conn; @@ -254,12 +276,14 @@ int hci_conn_del(struct hci_conn *conn) } tasklet_disable(&hdev->tx_task); + hci_conn_hash_del(hdev, conn); if (hdev->notify) hdev->notify(hdev, HCI_NOTIFY_CONN_DEL); + tasklet_enable(&hdev->tx_task); + skb_queue_purge(&conn->data_q); - hci_conn_del_sysfs(conn); return 0; } @@ -355,13 +379,21 @@ int hci_conn_auth(struct hci_conn *conn) { BT_DBG("conn %p", conn); + if (conn->ssp_mode > 0 && conn->hdev->ssp_mode > 0) { + if (!(conn->auth_type & 0x01)) { + conn->auth_type = HCI_AT_GENERAL_BONDING_MITM; + conn->link_mode &= ~HCI_LM_AUTH; + } + } + if (conn->link_mode & HCI_LM_AUTH) return 1; if (!test_and_set_bit(HCI_CONN_AUTH_PEND, &conn->pend)) { struct hci_cp_auth_requested cp; cp.handle = cpu_to_le16(conn->handle); - hci_send_cmd(conn->hdev, HCI_OP_AUTH_REQUESTED, sizeof(cp), &cp); + hci_send_cmd(conn->hdev, HCI_OP_AUTH_REQUESTED, + sizeof(cp), &cp); } return 0; } @@ -373,7 +405,7 @@ int hci_conn_encrypt(struct hci_conn *conn) BT_DBG("conn %p", conn); if (conn->link_mode & HCI_LM_ENCRYPT) - return 1; + return hci_conn_auth(conn); if (test_and_set_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend)) return 0; @@ -382,7 +414,8 @@ int hci_conn_encrypt(struct hci_conn *conn) struct hci_cp_set_conn_encrypt cp; cp.handle = cpu_to_le16(conn->handle); cp.encrypt = 1; - hci_send_cmd(conn->hdev, HCI_OP_SET_CONN_ENCRYPT, sizeof(cp), &cp); + hci_send_cmd(conn->hdev, HCI_OP_SET_CONN_ENCRYPT, + sizeof(cp), &cp); } return 0; } @@ -396,7 +429,8 @@ int hci_conn_change_link_key(struct hci_conn *conn) if (!test_and_set_bit(HCI_CONN_AUTH_PEND, &conn->pend)) { struct hci_cp_change_conn_link_key cp; cp.handle = cpu_to_le16(conn->handle); - hci_send_cmd(conn->hdev, HCI_OP_CHANGE_CONN_LINK_KEY, sizeof(cp), &cp); + hci_send_cmd(conn->hdev, HCI_OP_CHANGE_CONN_LINK_KEY, + sizeof(cp), &cp); } return 0; } @@ -498,6 +532,8 @@ void hci_conn_hash_flush(struct hci_dev *hdev) c->state = BT_CLOSED; + hci_conn_del_sysfs(c); + hci_proto_disconn_ind(c, 0x16); hci_conn_del(c); } @@ -600,3 +636,23 @@ int hci_get_conn_info(struct hci_dev *hdev, void __user *arg) return copy_to_user(ptr, &ci, sizeof(ci)) ? -EFAULT : 0; } + +int hci_get_auth_info(struct hci_dev *hdev, void __user *arg) +{ + struct hci_auth_info_req req; + struct hci_conn *conn; + + if (copy_from_user(&req, arg, sizeof(req))) + return -EFAULT; + + hci_dev_lock_bh(hdev); + conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &req.bdaddr); + if (conn) + req.type = conn->auth_type; + hci_dev_unlock_bh(hdev); + + if (!conn) + return -ENOENT; + + return copy_to_user(arg, &req, sizeof(req)) ? -EFAULT : 0; +} diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index aec6929f5c16..f5b21cb93699 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -279,10 +279,20 @@ static void hci_encrypt_req(struct hci_dev *hdev, unsigned long opt) BT_DBG("%s %x", hdev->name, encrypt); - /* Authentication */ + /* Encryption */ hci_send_cmd(hdev, HCI_OP_WRITE_ENCRYPT_MODE, 1, &encrypt); } +static void hci_linkpol_req(struct hci_dev *hdev, unsigned long opt) +{ + __le16 policy = cpu_to_le16(opt); + + BT_DBG("%s %x", hdev->name, opt); + + /* Default link policy */ + hci_send_cmd(hdev, HCI_OP_WRITE_DEF_LINK_POLICY, 2, &policy); +} + /* Get HCI device by index. * Device is held on return. */ struct hci_dev *hci_dev_get(int index) @@ -694,32 +704,35 @@ int hci_dev_cmd(unsigned int cmd, void __user *arg) msecs_to_jiffies(HCI_INIT_TIMEOUT)); break; - case HCISETPTYPE: - hdev->pkt_type = (__u16) dr.dev_opt; - break; - case HCISETLINKPOL: - hdev->link_policy = (__u16) dr.dev_opt; + err = hci_request(hdev, hci_linkpol_req, dr.dev_opt, + msecs_to_jiffies(HCI_INIT_TIMEOUT)); break; case HCISETLINKMODE: - hdev->link_mode = ((__u16) dr.dev_opt) & (HCI_LM_MASTER | HCI_LM_ACCEPT); + hdev->link_mode = ((__u16) dr.dev_opt) & + (HCI_LM_MASTER | HCI_LM_ACCEPT); + break; + + case HCISETPTYPE: + hdev->pkt_type = (__u16) dr.dev_opt; break; case HCISETACLMTU: - hdev->acl_mtu = *((__u16 *)&dr.dev_opt + 1); - hdev->acl_pkts = *((__u16 *)&dr.dev_opt + 0); + hdev->acl_mtu = *((__u16 *) &dr.dev_opt + 1); + hdev->acl_pkts = *((__u16 *) &dr.dev_opt + 0); break; case HCISETSCOMTU: - hdev->sco_mtu = *((__u16 *)&dr.dev_opt + 1); - hdev->sco_pkts = *((__u16 *)&dr.dev_opt + 0); + hdev->sco_mtu = *((__u16 *) &dr.dev_opt + 1); + hdev->sco_pkts = *((__u16 *) &dr.dev_opt + 0); break; default: err = -EINVAL; break; } + hci_dev_put(hdev); return err; } @@ -1270,9 +1283,12 @@ static inline struct hci_conn *hci_low_sent(struct hci_dev *hdev, __u8 type, int struct hci_conn *c; c = list_entry(p, struct hci_conn, list); - if (c->type != type || c->state != BT_CONNECTED - || skb_queue_empty(&c->data_q)) + if (c->type != type || skb_queue_empty(&c->data_q)) + continue; + + if (c->state != BT_CONNECTED && c->state != BT_CONFIG) continue; + num++; if (c->sent < min) { diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 6aef8f24e581..0e3db289f4be 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -110,6 +110,25 @@ static void hci_cc_role_discovery(struct hci_dev *hdev, struct sk_buff *skb) hci_dev_unlock(hdev); } +static void hci_cc_read_link_policy(struct hci_dev *hdev, struct sk_buff *skb) +{ + struct hci_rp_read_link_policy *rp = (void *) skb->data; + struct hci_conn *conn; + + BT_DBG("%s status 0x%x", hdev->name, rp->status); + + if (rp->status) + return; + + hci_dev_lock(hdev); + + conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(rp->handle)); + if (conn) + conn->link_policy = __le16_to_cpu(rp->policy); + + hci_dev_unlock(hdev); +} + static void hci_cc_write_link_policy(struct hci_dev *hdev, struct sk_buff *skb) { struct hci_rp_write_link_policy *rp = (void *) skb->data; @@ -128,13 +147,41 @@ static void hci_cc_write_link_policy(struct hci_dev *hdev, struct sk_buff *skb) hci_dev_lock(hdev); conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(rp->handle)); - if (conn) { + if (conn) conn->link_policy = get_unaligned_le16(sent + 2); - } hci_dev_unlock(hdev); } +static void hci_cc_read_def_link_policy(struct hci_dev *hdev, struct sk_buff *skb) +{ + struct hci_rp_read_def_link_policy *rp = (void *) skb->data; + + BT_DBG("%s status 0x%x", hdev->name, rp->status); + + if (rp->status) + return; + + hdev->link_policy = __le16_to_cpu(rp->policy); +} + +static void hci_cc_write_def_link_policy(struct hci_dev *hdev, struct sk_buff *skb) +{ + __u8 status = *((__u8 *) skb->data); + void *sent; + + BT_DBG("%s status 0x%x", hdev->name, status); + + sent = hci_sent_cmd_data(hdev, HCI_OP_WRITE_DEF_LINK_POLICY); + if (!sent) + return; + + if (!status) + hdev->link_policy = get_unaligned_le16(sent); + + hci_req_complete(hdev, status); +} + static void hci_cc_reset(struct hci_dev *hdev, struct sk_buff *skb) { __u8 status = *((__u8 *) skb->data); @@ -151,12 +198,14 @@ static void hci_cc_write_local_name(struct hci_dev *hdev, struct sk_buff *skb) BT_DBG("%s status 0x%x", hdev->name, status); + if (status) + return; + sent = hci_sent_cmd_data(hdev, HCI_OP_WRITE_LOCAL_NAME); if (!sent) return; - if (!status) - memcpy(hdev->dev_name, sent, 248); + memcpy(hdev->dev_name, sent, 248); } static void hci_cc_read_local_name(struct hci_dev *hdev, struct sk_buff *skb) @@ -266,12 +315,14 @@ static void hci_cc_write_class_of_dev(struct hci_dev *hdev, struct sk_buff *skb) BT_DBG("%s status 0x%x", hdev->name, status); + if (status) + return; + sent = hci_sent_cmd_data(hdev, HCI_OP_WRITE_CLASS_OF_DEV); if (!sent) return; - if (!status) - memcpy(hdev->dev_class, sent, 3); + memcpy(hdev->dev_class, sent, 3); } static void hci_cc_read_voice_setting(struct hci_dev *hdev, struct sk_buff *skb) @@ -286,7 +337,7 @@ static void hci_cc_read_voice_setting(struct hci_dev *hdev, struct sk_buff *skb) setting = __le16_to_cpu(rp->voice_setting); - if (hdev->voice_setting == setting ) + if (hdev->voice_setting == setting) return; hdev->voice_setting = setting; @@ -303,28 +354,31 @@ static void hci_cc_read_voice_setting(struct hci_dev *hdev, struct sk_buff *skb) static void hci_cc_write_voice_setting(struct hci_dev *hdev, struct sk_buff *skb) { __u8 status = *((__u8 *) skb->data); + __u16 setting; void *sent; BT_DBG("%s status 0x%x", hdev->name, status); + if (status) + return; + sent = hci_sent_cmd_data(hdev, HCI_OP_WRITE_VOICE_SETTING); if (!sent) return; - if (!status) { - __u16 setting = get_unaligned_le16(sent); + setting = get_unaligned_le16(sent); - if (hdev->voice_setting != setting) { - hdev->voice_setting = setting; + if (hdev->voice_setting == setting) + return; - BT_DBG("%s voice setting 0x%04x", hdev->name, setting); + hdev->voice_setting = setting; - if (hdev->notify) { - tasklet_disable(&hdev->tx_task); - hdev->notify(hdev, HCI_NOTIFY_VOICE_SETTING); - tasklet_enable(&hdev->tx_task); - } - } + BT_DBG("%s voice setting 0x%04x", hdev->name, setting); + + if (hdev->notify) { + tasklet_disable(&hdev->tx_task); + hdev->notify(hdev, HCI_NOTIFY_VOICE_SETTING); + tasklet_enable(&hdev->tx_task); } } @@ -337,6 +391,35 @@ static void hci_cc_host_buffer_size(struct hci_dev *hdev, struct sk_buff *skb) hci_req_complete(hdev, status); } +static void hci_cc_read_ssp_mode(struct hci_dev *hdev, struct sk_buff *skb) +{ + struct hci_rp_read_ssp_mode *rp = (void *) skb->data; + + BT_DBG("%s status 0x%x", hdev->name, rp->status); + + if (rp->status) + return; + + hdev->ssp_mode = rp->mode; +} + +static void hci_cc_write_ssp_mode(struct hci_dev *hdev, struct sk_buff *skb) +{ + __u8 status = *((__u8 *) skb->data); + void *sent; + + BT_DBG("%s status 0x%x", hdev->name, status); + + if (status) + return; + + sent = hci_sent_cmd_data(hdev, HCI_OP_WRITE_SSP_MODE); + if (!sent) + return; + + hdev->ssp_mode = *((__u8 *) sent); +} + static void hci_cc_read_local_version(struct hci_dev *hdev, struct sk_buff *skb) { struct hci_rp_read_local_version *rp = (void *) skb->data; @@ -347,8 +430,8 @@ static void hci_cc_read_local_version(struct hci_dev *hdev, struct sk_buff *skb) return; hdev->hci_ver = rp->hci_ver; - hdev->hci_rev = btohs(rp->hci_rev); - hdev->manufacturer = btohs(rp->manufacturer); + hdev->hci_rev = __le16_to_cpu(rp->hci_rev); + hdev->manufacturer = __le16_to_cpu(rp->manufacturer); BT_DBG("%s manufacturer %d hci ver %d:%d", hdev->name, hdev->manufacturer, @@ -536,11 +619,119 @@ static void hci_cs_add_sco(struct hci_dev *hdev, __u8 status) hci_dev_unlock(hdev); } +static void hci_cs_auth_requested(struct hci_dev *hdev, __u8 status) +{ + struct hci_cp_auth_requested *cp; + struct hci_conn *conn; + + BT_DBG("%s status 0x%x", hdev->name, status); + + if (!status) + return; + + cp = hci_sent_cmd_data(hdev, HCI_OP_AUTH_REQUESTED); + if (!cp) + return; + + hci_dev_lock(hdev); + + conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(cp->handle)); + if (conn) { + if (conn->state == BT_CONFIG) { + hci_proto_connect_cfm(conn, status); + hci_conn_put(conn); + } + } + + hci_dev_unlock(hdev); +} + +static void hci_cs_set_conn_encrypt(struct hci_dev *hdev, __u8 status) +{ + struct hci_cp_set_conn_encrypt *cp; + struct hci_conn *conn; + + BT_DBG("%s status 0x%x", hdev->name, status); + + if (!status) + return; + + cp = hci_sent_cmd_data(hdev, HCI_OP_SET_CONN_ENCRYPT); + if (!cp) + return; + + hci_dev_lock(hdev); + + conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(cp->handle)); + if (conn) { + if (conn->state == BT_CONFIG) { + hci_proto_connect_cfm(conn, status); + hci_conn_put(conn); + } + } + + hci_dev_unlock(hdev); +} + static void hci_cs_remote_name_req(struct hci_dev *hdev, __u8 status) { BT_DBG("%s status 0x%x", hdev->name, status); } +static void hci_cs_read_remote_features(struct hci_dev *hdev, __u8 status) +{ + struct hci_cp_read_remote_features *cp; + struct hci_conn *conn; + + BT_DBG("%s status 0x%x", hdev->name, status); + + if (!status) + return; + + cp = hci_sent_cmd_data(hdev, HCI_OP_READ_REMOTE_FEATURES); + if (!cp) + return; + + hci_dev_lock(hdev); + + conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(cp->handle)); + if (conn) { + if (conn->state == BT_CONFIG) { + hci_proto_connect_cfm(conn, status); + hci_conn_put(conn); + } + } + + hci_dev_unlock(hdev); +} + +static void hci_cs_read_remote_ext_features(struct hci_dev *hdev, __u8 status) +{ + struct hci_cp_read_remote_ext_features *cp; + struct hci_conn *conn; + + BT_DBG("%s status 0x%x", hdev->name, status); + + if (!status) + return; + + cp = hci_sent_cmd_data(hdev, HCI_OP_READ_REMOTE_EXT_FEATURES); + if (!cp) + return; + + hci_dev_lock(hdev); + + conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(cp->handle)); + if (conn) { + if (conn->state == BT_CONFIG) { + hci_proto_connect_cfm(conn, status); + hci_conn_put(conn); + } + } + + hci_dev_unlock(hdev); +} + static void hci_cs_setup_sync_conn(struct hci_dev *hdev, __u8 status) { struct hci_cp_setup_sync_conn *cp; @@ -653,6 +844,7 @@ static inline void hci_inquiry_result_evt(struct hci_dev *hdev, struct sk_buff * memcpy(data.dev_class, info->dev_class, 3); data.clock_offset = info->clock_offset; data.rssi = 0x00; + data.ssp_mode = 0x00; info++; hci_inquiry_cache_update(hdev, &data); } @@ -675,7 +867,14 @@ static inline void hci_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *s if (!ev->status) { conn->handle = __le16_to_cpu(ev->handle); - conn->state = BT_CONNECTED; + + if (conn->type == ACL_LINK) { + conn->state = BT_CONFIG; + hci_conn_hold(conn); + } else + conn->state = BT_CONNECTED; + + hci_conn_add_sysfs(conn); if (test_bit(HCI_AUTH, &hdev->flags)) conn->link_mode |= HCI_LM_AUTH; @@ -687,30 +886,17 @@ static inline void hci_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *s if (conn->type == ACL_LINK) { struct hci_cp_read_remote_features cp; cp.handle = ev->handle; - hci_send_cmd(hdev, HCI_OP_READ_REMOTE_FEATURES, sizeof(cp), &cp); - } - - /* Set link policy */ - if (conn->type == ACL_LINK && hdev->link_policy) { - struct hci_cp_write_link_policy cp; - cp.handle = ev->handle; - cp.policy = cpu_to_le16(hdev->link_policy); - hci_send_cmd(hdev, HCI_OP_WRITE_LINK_POLICY, sizeof(cp), &cp); + hci_send_cmd(hdev, HCI_OP_READ_REMOTE_FEATURES, + sizeof(cp), &cp); } /* Set packet type for incoming connection */ - if (!conn->out) { + if (!conn->out && hdev->hci_ver < 3) { struct hci_cp_change_conn_ptype cp; cp.handle = ev->handle; - cp.pkt_type = (conn->type == ACL_LINK) ? - cpu_to_le16(hdev->pkt_type & ACL_PTYPE_MASK): - cpu_to_le16(hdev->pkt_type & SCO_PTYPE_MASK); - - hci_send_cmd(hdev, HCI_OP_CHANGE_CONN_PTYPE, sizeof(cp), &cp); - } else { - /* Update disconnect timer */ - hci_conn_hold(conn); - hci_conn_put(conn); + cp.pkt_type = cpu_to_le16(conn->pkt_type); + hci_send_cmd(hdev, HCI_OP_CHANGE_CONN_PTYPE, + sizeof(cp), &cp); } } else conn->state = BT_CLOSED; @@ -730,9 +916,10 @@ static inline void hci_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *s } } - hci_proto_connect_cfm(conn, ev->status); - if (ev->status) + if (ev->status) { + hci_proto_connect_cfm(conn, ev->status); hci_conn_del(conn); + } unlock: hci_dev_unlock(hdev); @@ -752,10 +939,14 @@ static inline void hci_conn_request_evt(struct hci_dev *hdev, struct sk_buff *sk if (mask & HCI_LM_ACCEPT) { /* Connection accepted */ + struct inquiry_entry *ie; struct hci_conn *conn; hci_dev_lock(hdev); + if ((ie = hci_inquiry_cache_lookup(hdev, &ev->bdaddr))) + memcpy(ie->data.dev_class, ev->dev_class, 3); + conn = hci_conn_hash_lookup_ba(hdev, ev->link_type, &ev->bdaddr); if (!conn) { if (!(conn = hci_conn_add(hdev, ev->link_type, &ev->bdaddr))) { @@ -786,7 +977,7 @@ static inline void hci_conn_request_evt(struct hci_dev *hdev, struct sk_buff *sk struct hci_cp_accept_sync_conn_req cp; bacpy(&cp.bdaddr, &ev->bdaddr); - cp.pkt_type = cpu_to_le16(hdev->esco_type); + cp.pkt_type = cpu_to_le16(conn->pkt_type); cp.tx_bandwidth = cpu_to_le32(0x00001f40); cp.rx_bandwidth = cpu_to_le32(0x00001f40); @@ -822,6 +1013,9 @@ static inline void hci_disconn_complete_evt(struct hci_dev *hdev, struct sk_buff conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(ev->handle)); if (conn) { conn->state = BT_CLOSED; + + hci_conn_del_sysfs(conn); + hci_proto_disconn_ind(conn, ev->reason); hci_conn_del(conn); } @@ -845,15 +1039,29 @@ static inline void hci_auth_complete_evt(struct hci_dev *hdev, struct sk_buff *s clear_bit(HCI_CONN_AUTH_PEND, &conn->pend); - hci_auth_cfm(conn, ev->status); + if (conn->state == BT_CONFIG) { + if (!ev->status && hdev->ssp_mode > 0 && + conn->ssp_mode > 0) { + struct hci_cp_set_conn_encrypt cp; + cp.handle = ev->handle; + cp.encrypt = 0x01; + hci_send_cmd(hdev, HCI_OP_SET_CONN_ENCRYPT, + sizeof(cp), &cp); + } else { + conn->state = BT_CONNECTED; + hci_proto_connect_cfm(conn, ev->status); + hci_conn_put(conn); + } + } else + hci_auth_cfm(conn, ev->status); if (test_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend)) { if (!ev->status) { struct hci_cp_set_conn_encrypt cp; - cp.handle = cpu_to_le16(conn->handle); - cp.encrypt = 1; - hci_send_cmd(conn->hdev, - HCI_OP_SET_CONN_ENCRYPT, sizeof(cp), &cp); + cp.handle = ev->handle; + cp.encrypt = 0x01; + hci_send_cmd(hdev, HCI_OP_SET_CONN_ENCRYPT, + sizeof(cp), &cp); } else { clear_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend); hci_encrypt_cfm(conn, ev->status, 0x00); @@ -883,15 +1091,24 @@ static inline void hci_encrypt_change_evt(struct hci_dev *hdev, struct sk_buff * conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(ev->handle)); if (conn) { if (!ev->status) { - if (ev->encrypt) + if (ev->encrypt) { + /* Encryption implies authentication */ + conn->link_mode |= HCI_LM_AUTH; conn->link_mode |= HCI_LM_ENCRYPT; - else + } else conn->link_mode &= ~HCI_LM_ENCRYPT; } clear_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend); - hci_encrypt_cfm(conn, ev->status, ev->encrypt); + if (conn->state == BT_CONFIG) { + if (!ev->status) + conn->state = BT_CONNECTED; + + hci_proto_connect_cfm(conn, ev->status); + hci_conn_put(conn); + } else + hci_encrypt_cfm(conn, ev->status, ev->encrypt); } hci_dev_unlock(hdev); @@ -926,14 +1143,29 @@ static inline void hci_remote_features_evt(struct hci_dev *hdev, struct sk_buff BT_DBG("%s status %d", hdev->name, ev->status); - if (ev->status) - return; - hci_dev_lock(hdev); conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(ev->handle)); - if (conn) - memcpy(conn->features, ev->features, 8); + if (conn) { + if (!ev->status) + memcpy(conn->features, ev->features, 8); + + if (conn->state == BT_CONFIG) { + if (!ev->status && lmp_ssp_capable(hdev) && + lmp_ssp_capable(conn)) { + struct hci_cp_read_remote_ext_features cp; + cp.handle = ev->handle; + cp.page = 0x01; + hci_send_cmd(hdev, + HCI_OP_READ_REMOTE_EXT_FEATURES, + sizeof(cp), &cp); + } else { + conn->state = BT_CONNECTED; + hci_proto_connect_cfm(conn, ev->status); + hci_conn_put(conn); + } + } + } hci_dev_unlock(hdev); } @@ -974,10 +1206,22 @@ static inline void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *sk hci_cc_role_discovery(hdev, skb); break; + case HCI_OP_READ_LINK_POLICY: + hci_cc_read_link_policy(hdev, skb); + break; + case HCI_OP_WRITE_LINK_POLICY: hci_cc_write_link_policy(hdev, skb); break; + case HCI_OP_READ_DEF_LINK_POLICY: + hci_cc_read_def_link_policy(hdev, skb); + break; + + case HCI_OP_WRITE_DEF_LINK_POLICY: + hci_cc_write_def_link_policy(hdev, skb); + break; + case HCI_OP_RESET: hci_cc_reset(hdev, skb); break; @@ -1022,6 +1266,14 @@ static inline void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *sk hci_cc_host_buffer_size(hdev, skb); break; + case HCI_OP_READ_SSP_MODE: + hci_cc_read_ssp_mode(hdev, skb); + break; + + case HCI_OP_WRITE_SSP_MODE: + hci_cc_write_ssp_mode(hdev, skb); + break; + case HCI_OP_READ_LOCAL_VERSION: hci_cc_read_local_version(hdev, skb); break; @@ -1076,10 +1328,26 @@ static inline void hci_cmd_status_evt(struct hci_dev *hdev, struct sk_buff *skb) hci_cs_add_sco(hdev, ev->status); break; + case HCI_OP_AUTH_REQUESTED: + hci_cs_auth_requested(hdev, ev->status); + break; + + case HCI_OP_SET_CONN_ENCRYPT: + hci_cs_set_conn_encrypt(hdev, ev->status); + break; + case HCI_OP_REMOTE_NAME_REQ: hci_cs_remote_name_req(hdev, ev->status); break; + case HCI_OP_READ_REMOTE_FEATURES: + hci_cs_read_remote_features(hdev, ev->status); + break; + + case HCI_OP_READ_REMOTE_EXT_FEATURES: + hci_cs_read_remote_ext_features(hdev, ev->status); + break; + case HCI_OP_SETUP_SYNC_CONN: hci_cs_setup_sync_conn(hdev, ev->status); break; @@ -1235,6 +1503,22 @@ static inline void hci_clock_offset_evt(struct hci_dev *hdev, struct sk_buff *sk hci_dev_unlock(hdev); } +static inline void hci_pkt_type_change_evt(struct hci_dev *hdev, struct sk_buff *skb) +{ + struct hci_ev_pkt_type_change *ev = (void *) skb->data; + struct hci_conn *conn; + + BT_DBG("%s status %d", hdev->name, ev->status); + + hci_dev_lock(hdev); + + conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(ev->handle)); + if (conn && !ev->status) + conn->pkt_type = __le16_to_cpu(ev->pkt_type); + + hci_dev_unlock(hdev); +} + static inline void hci_pscan_rep_mode_evt(struct hci_dev *hdev, struct sk_buff *skb) { struct hci_ev_pscan_rep_mode *ev = (void *) skb->data; @@ -1275,6 +1559,7 @@ static inline void hci_inquiry_result_with_rssi_evt(struct hci_dev *hdev, struct memcpy(data.dev_class, info->dev_class, 3); data.clock_offset = info->clock_offset; data.rssi = info->rssi; + data.ssp_mode = 0x00; info++; hci_inquiry_cache_update(hdev, &data); } @@ -1289,6 +1574,7 @@ static inline void hci_inquiry_result_with_rssi_evt(struct hci_dev *hdev, struct memcpy(data.dev_class, info->dev_class, 3); data.clock_offset = info->clock_offset; data.rssi = info->rssi; + data.ssp_mode = 0x00; info++; hci_inquiry_cache_update(hdev, &data); } @@ -1299,7 +1585,43 @@ static inline void hci_inquiry_result_with_rssi_evt(struct hci_dev *hdev, struct static inline void hci_remote_ext_features_evt(struct hci_dev *hdev, struct sk_buff *skb) { + struct hci_ev_remote_ext_features *ev = (void *) skb->data; + struct hci_conn *conn; + BT_DBG("%s", hdev->name); + + hci_dev_lock(hdev); + + conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(ev->handle)); + if (conn) { + if (!ev->status && ev->page == 0x01) { + struct inquiry_entry *ie; + + if ((ie = hci_inquiry_cache_lookup(hdev, &conn->dst))) + ie->data.ssp_mode = (ev->features[0] & 0x01); + + conn->ssp_mode = (ev->features[0] & 0x01); + } + + if (conn->state == BT_CONFIG) { + if (!ev->status && hdev->ssp_mode > 0 && + conn->ssp_mode > 0) { + if (conn->out) { + struct hci_cp_auth_requested cp; + cp.handle = ev->handle; + hci_send_cmd(hdev, + HCI_OP_AUTH_REQUESTED, + sizeof(cp), &cp); + } + } else { + conn->state = BT_CONNECTED; + hci_proto_connect_cfm(conn, ev->status); + hci_conn_put(conn); + } + } + } + + hci_dev_unlock(hdev); } static inline void hci_sync_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) @@ -1312,12 +1634,22 @@ static inline void hci_sync_conn_complete_evt(struct hci_dev *hdev, struct sk_bu hci_dev_lock(hdev); conn = hci_conn_hash_lookup_ba(hdev, ev->link_type, &ev->bdaddr); - if (!conn) - goto unlock; + if (!conn) { + if (ev->link_type == ESCO_LINK) + goto unlock; + + conn = hci_conn_hash_lookup_ba(hdev, ESCO_LINK, &ev->bdaddr); + if (!conn) + goto unlock; + + conn->type = SCO_LINK; + } if (!ev->status) { conn->handle = __le16_to_cpu(ev->handle); conn->state = BT_CONNECTED; + + hci_conn_add_sysfs(conn); } else conn->state = BT_CLOSED; @@ -1371,6 +1703,7 @@ static inline void hci_extended_inquiry_result_evt(struct hci_dev *hdev, struct memcpy(data.dev_class, info->dev_class, 3); data.clock_offset = info->clock_offset; data.rssi = info->rssi; + data.ssp_mode = 0x01; info++; hci_inquiry_cache_update(hdev, &data); } @@ -1378,6 +1711,53 @@ static inline void hci_extended_inquiry_result_evt(struct hci_dev *hdev, struct hci_dev_unlock(hdev); } +static inline void hci_io_capa_request_evt(struct hci_dev *hdev, struct sk_buff *skb) +{ + struct hci_ev_io_capa_request *ev = (void *) skb->data; + struct hci_conn *conn; + + BT_DBG("%s", hdev->name); + + hci_dev_lock(hdev); + + conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &ev->bdaddr); + if (conn) + hci_conn_hold(conn); + + hci_dev_unlock(hdev); +} + +static inline void hci_simple_pair_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) +{ + struct hci_ev_simple_pair_complete *ev = (void *) skb->data; + struct hci_conn *conn; + + BT_DBG("%s", hdev->name); + + hci_dev_lock(hdev); + + conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &ev->bdaddr); + if (conn) + hci_conn_put(conn); + + hci_dev_unlock(hdev); +} + +static inline void hci_remote_host_features_evt(struct hci_dev *hdev, struct sk_buff *skb) +{ + struct hci_ev_remote_host_features *ev = (void *) skb->data; + struct inquiry_entry *ie; + + BT_DBG("%s", hdev->name); + + hci_dev_lock(hdev); + + if ((ie = hci_inquiry_cache_lookup(hdev, &ev->bdaddr))) + ie->data.ssp_mode = (ev->features[0] & 0x01); + + hci_dev_unlock(hdev); +} + void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb) { struct hci_event_hdr *hdr = (void *) skb->data; @@ -1470,6 +1850,10 @@ void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb) hci_clock_offset_evt(hdev, skb); break; + case HCI_EV_PKT_TYPE_CHANGE: + hci_pkt_type_change_evt(hdev, skb); + break; + case HCI_EV_PSCAN_REP_MODE: hci_pscan_rep_mode_evt(hdev, skb); break; @@ -1498,6 +1882,18 @@ void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb) hci_extended_inquiry_result_evt(hdev, skb); break; + case HCI_EV_IO_CAPA_REQUEST: + hci_io_capa_request_evt(hdev, skb); + break; + + case HCI_EV_SIMPLE_PAIR_COMPLETE: + hci_simple_pair_complete_evt(hdev, skb); + break; + + case HCI_EV_REMOTE_HOST_FEATURES: + hci_remote_host_features_evt(hdev, skb); + break; + default: BT_DBG("%s event 0x%x", hdev->name, event); break; diff --git a/net/bluetooth/hci_sock.c b/net/bluetooth/hci_sock.c index 747fabd735d2..d62579b67959 100644 --- a/net/bluetooth/hci_sock.c +++ b/net/bluetooth/hci_sock.c @@ -193,19 +193,11 @@ static inline int hci_sock_bound_ioctl(struct sock *sk, unsigned int cmd, unsign return 0; - case HCISETSECMGR: - if (!capable(CAP_NET_ADMIN)) - return -EACCES; - - if (arg) - set_bit(HCI_SECMGR, &hdev->flags); - else - clear_bit(HCI_SECMGR, &hdev->flags); - - return 0; - case HCIGETCONNINFO: - return hci_get_conn_info(hdev, (void __user *)arg); + return hci_get_conn_info(hdev, (void __user *) arg); + + case HCIGETAUTHINFO: + return hci_get_auth_info(hdev, (void __user *) arg); default: if (hdev->ioctl) @@ -217,7 +209,7 @@ static inline int hci_sock_bound_ioctl(struct sock *sk, unsigned int cmd, unsign static int hci_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) { struct sock *sk = sock->sk; - void __user *argp = (void __user *)arg; + void __user *argp = (void __user *) arg; int err; BT_DBG("cmd %x arg %lx", cmd, arg); diff --git a/net/bluetooth/hci_sysfs.c b/net/bluetooth/hci_sysfs.c index 84360c117d4e..844ca5f1b2d4 100644 --- a/net/bluetooth/hci_sysfs.c +++ b/net/bluetooth/hci_sysfs.c @@ -113,11 +113,13 @@ static ssize_t show_inquiry_cache(struct device *dev, struct device_attribute *a struct inquiry_data *data = &e->data; bdaddr_t bdaddr; baswap(&bdaddr, &data->bdaddr); - n += sprintf(buf + n, "%s %d %d %d 0x%.2x%.2x%.2x 0x%.4x %d %u\n", + n += sprintf(buf + n, "%s %d %d %d 0x%.2x%.2x%.2x 0x%.4x %d %d %u\n", batostr(&bdaddr), - data->pscan_rep_mode, data->pscan_period_mode, data->pscan_mode, - data->dev_class[2], data->dev_class[1], data->dev_class[0], - __le16_to_cpu(data->clock_offset), data->rssi, e->timestamp); + data->pscan_rep_mode, data->pscan_period_mode, + data->pscan_mode, data->dev_class[2], + data->dev_class[1], data->dev_class[0], + __le16_to_cpu(data->clock_offset), + data->rssi, data->ssp_mode, e->timestamp); } hci_dev_unlock_bh(hdev); @@ -249,15 +251,28 @@ static ssize_t show_conn_address(struct device *dev, struct device_attribute *at return sprintf(buf, "%s\n", batostr(&bdaddr)); } +static ssize_t show_conn_features(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct hci_conn *conn = dev_get_drvdata(dev); + + return sprintf(buf, "0x%02x%02x%02x%02x%02x%02x%02x%02x\n", + conn->features[0], conn->features[1], + conn->features[2], conn->features[3], + conn->features[4], conn->features[5], + conn->features[6], conn->features[7]); +} + #define CONN_ATTR(_name,_mode,_show,_store) \ struct device_attribute conn_attr_##_name = __ATTR(_name,_mode,_show,_store) static CONN_ATTR(type, S_IRUGO, show_conn_type, NULL); static CONN_ATTR(address, S_IRUGO, show_conn_address, NULL); +static CONN_ATTR(features, S_IRUGO, show_conn_features, NULL); static struct device_attribute *conn_attrs[] = { &conn_attr_type, &conn_attr_address, + &conn_attr_features, NULL }; @@ -296,7 +311,6 @@ static void add_conn(struct work_struct *work) void hci_conn_add_sysfs(struct hci_conn *conn) { struct hci_dev *hdev = conn->hdev; - bdaddr_t *ba = &conn->dst; BT_DBG("conn %p", conn); @@ -305,11 +319,8 @@ void hci_conn_add_sysfs(struct hci_conn *conn) conn->dev.release = bt_release; - snprintf(conn->dev.bus_id, BUS_ID_SIZE, - "%s%2.2X%2.2X%2.2X%2.2X%2.2X%2.2X", - conn->type == ACL_LINK ? "acl" : "sco", - ba->b[5], ba->b[4], ba->b[3], - ba->b[2], ba->b[1], ba->b[0]); + snprintf(conn->dev.bus_id, BUS_ID_SIZE, "%s:%d", + hdev->name, conn->handle); dev_set_drvdata(&conn->dev, conn); diff --git a/net/bluetooth/hidp/core.c b/net/bluetooth/hidp/core.c index 519cdb920f93..96434d774c84 100644 --- a/net/bluetooth/hidp/core.c +++ b/net/bluetooth/hidp/core.c @@ -581,6 +581,12 @@ static int hidp_session(void *arg) hid_free_device(session->hid); } + /* Wakeup user-space polling for socket errors */ + session->intr_sock->sk->sk_err = EUNATCH; + session->ctrl_sock->sk->sk_err = EUNATCH; + + hidp_schedule(session); + fput(session->intr_sock->file); wait_event_timeout(*(ctrl_sk->sk_sleep), @@ -879,6 +885,10 @@ int hidp_del_connection(struct hidp_conndel_req *req) skb_queue_purge(&session->ctrl_transmit); skb_queue_purge(&session->intr_transmit); + /* Wakeup user-space polling for socket errors */ + session->intr_sock->sk->sk_err = EUNATCH; + session->ctrl_sock->sk->sk_err = EUNATCH; + /* Kill session thread */ atomic_inc(&session->terminate); hidp_schedule(session); diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c index 6e180d255505..c1239852834a 100644 --- a/net/bluetooth/l2cap.c +++ b/net/bluetooth/l2cap.c @@ -55,7 +55,7 @@ #define BT_DBG(D...) #endif -#define VERSION "2.9" +#define VERSION "2.10" static u32 l2cap_feat_mask = 0x0000; @@ -76,11 +76,21 @@ static struct sk_buff *l2cap_build_cmd(struct l2cap_conn *conn, static void l2cap_sock_timeout(unsigned long arg) { struct sock *sk = (struct sock *) arg; + int reason; BT_DBG("sock %p state %d", sk, sk->sk_state); bh_lock_sock(sk); - __l2cap_sock_close(sk, ETIMEDOUT); + + if (sk->sk_state == BT_CONNECT && + (l2cap_pi(sk)->link_mode & (L2CAP_LM_AUTH | + L2CAP_LM_ENCRYPT | L2CAP_LM_SECURE))) + reason = ECONNREFUSED; + else + reason = ETIMEDOUT; + + __l2cap_sock_close(sk, reason); + bh_unlock_sock(sk); l2cap_sock_kill(sk); @@ -240,7 +250,7 @@ static void l2cap_chan_del(struct sock *sk, int err) hci_conn_put(conn->hcon); } - sk->sk_state = BT_CLOSED; + sk->sk_state = BT_CLOSED; sock_set_flag(sk, SOCK_ZAPPED); if (err) @@ -253,6 +263,21 @@ static void l2cap_chan_del(struct sock *sk, int err) sk->sk_state_change(sk); } +/* Service level security */ +static inline int l2cap_check_link_mode(struct sock *sk) +{ + struct l2cap_conn *conn = l2cap_pi(sk)->conn; + + if ((l2cap_pi(sk)->link_mode & L2CAP_LM_ENCRYPT) || + (l2cap_pi(sk)->link_mode & L2CAP_LM_SECURE)) + return hci_conn_encrypt(conn->hcon); + + if (l2cap_pi(sk)->link_mode & L2CAP_LM_AUTH) + return hci_conn_auth(conn->hcon); + + return 1; +} + static inline u8 l2cap_get_ident(struct l2cap_conn *conn) { u8 id; @@ -287,6 +312,36 @@ static inline int l2cap_send_cmd(struct l2cap_conn *conn, u8 ident, u8 code, u16 return hci_send_acl(conn->hcon, skb, 0); } +static void l2cap_do_start(struct sock *sk) +{ + struct l2cap_conn *conn = l2cap_pi(sk)->conn; + + if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT) { + if (l2cap_check_link_mode(sk)) { + struct l2cap_conn_req req; + req.scid = cpu_to_le16(l2cap_pi(sk)->scid); + req.psm = l2cap_pi(sk)->psm; + + l2cap_pi(sk)->ident = l2cap_get_ident(conn); + + l2cap_send_cmd(conn, l2cap_pi(sk)->ident, + L2CAP_CONN_REQ, sizeof(req), &req); + } + } else { + struct l2cap_info_req req; + req.type = cpu_to_le16(L2CAP_IT_FEAT_MASK); + + conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_SENT; + conn->info_ident = l2cap_get_ident(conn); + + mod_timer(&conn->info_timer, jiffies + + msecs_to_jiffies(L2CAP_INFO_TIMEOUT)); + + l2cap_send_cmd(conn, conn->info_ident, + L2CAP_INFO_REQ, sizeof(req), &req); + } +} + /* ---- L2CAP connections ---- */ static void l2cap_conn_start(struct l2cap_conn *conn) { @@ -301,16 +356,37 @@ static void l2cap_conn_start(struct l2cap_conn *conn) bh_lock_sock(sk); if (sk->sk_type != SOCK_SEQPACKET) { - l2cap_sock_clear_timer(sk); - sk->sk_state = BT_CONNECTED; - sk->sk_state_change(sk); - } else if (sk->sk_state == BT_CONNECT) { - struct l2cap_conn_req req; - l2cap_pi(sk)->ident = l2cap_get_ident(conn); - req.scid = cpu_to_le16(l2cap_pi(sk)->scid); - req.psm = l2cap_pi(sk)->psm; - l2cap_send_cmd(conn, l2cap_pi(sk)->ident, + bh_unlock_sock(sk); + continue; + } + + if (sk->sk_state == BT_CONNECT) { + if (l2cap_check_link_mode(sk)) { + struct l2cap_conn_req req; + req.scid = cpu_to_le16(l2cap_pi(sk)->scid); + req.psm = l2cap_pi(sk)->psm; + + l2cap_pi(sk)->ident = l2cap_get_ident(conn); + + l2cap_send_cmd(conn, l2cap_pi(sk)->ident, L2CAP_CONN_REQ, sizeof(req), &req); + } + } else if (sk->sk_state == BT_CONNECT2) { + struct l2cap_conn_rsp rsp; + rsp.scid = cpu_to_le16(l2cap_pi(sk)->dcid); + rsp.dcid = cpu_to_le16(l2cap_pi(sk)->scid); + + if (l2cap_check_link_mode(sk)) { + sk->sk_state = BT_CONFIG; + rsp.result = cpu_to_le16(L2CAP_CR_SUCCESS); + rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO); + } else { + rsp.result = cpu_to_le16(L2CAP_CR_PEND); + rsp.status = cpu_to_le16(L2CAP_CS_AUTHEN_PEND); + } + + l2cap_send_cmd(conn, l2cap_pi(sk)->ident, + L2CAP_CONN_RSP, sizeof(rsp), &rsp); } bh_unlock_sock(sk); @@ -321,22 +397,27 @@ static void l2cap_conn_start(struct l2cap_conn *conn) static void l2cap_conn_ready(struct l2cap_conn *conn) { - BT_DBG("conn %p", conn); + struct l2cap_chan_list *l = &conn->chan_list; + struct sock *sk; - if (conn->chan_list.head || !hlist_empty(&l2cap_sk_list.head)) { - struct l2cap_info_req req; + BT_DBG("conn %p", conn); - req.type = cpu_to_le16(L2CAP_IT_FEAT_MASK); + read_lock(&l->lock); - conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_SENT; - conn->info_ident = l2cap_get_ident(conn); + for (sk = l->head; sk; sk = l2cap_pi(sk)->next_c) { + bh_lock_sock(sk); - mod_timer(&conn->info_timer, - jiffies + msecs_to_jiffies(L2CAP_INFO_TIMEOUT)); + if (sk->sk_type != SOCK_SEQPACKET) { + l2cap_sock_clear_timer(sk); + sk->sk_state = BT_CONNECTED; + sk->sk_state_change(sk); + } else if (sk->sk_state == BT_CONNECT) + l2cap_do_start(sk); - l2cap_send_cmd(conn, conn->info_ident, - L2CAP_INFO_REQ, sizeof(req), &req); + bh_unlock_sock(sk); } + + read_unlock(&l->lock); } /* Notify sockets that we cannot guaranty reliability anymore */ @@ -388,7 +469,8 @@ static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon, u8 status) conn->feat_mask = 0; - setup_timer(&conn->info_timer, l2cap_info_timeout, (unsigned long)conn); + setup_timer(&conn->info_timer, l2cap_info_timeout, + (unsigned long) conn); spin_lock_init(&conn->lock); rwlock_init(&conn->chan_list.lock); @@ -500,7 +582,7 @@ static void l2cap_sock_cleanup_listen(struct sock *parent) while ((sk = bt_accept_dequeue(parent, NULL))) l2cap_sock_close(sk); - parent->sk_state = BT_CLOSED; + parent->sk_state = BT_CLOSED; sock_set_flag(parent, SOCK_ZAPPED); } @@ -543,9 +625,8 @@ static void __l2cap_sock_close(struct sock *sk, int reason) req.scid = cpu_to_le16(l2cap_pi(sk)->scid); l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_DISCONN_REQ, sizeof(req), &req); - } else { + } else l2cap_chan_del(sk, reason); - } break; case BT_CONNECT: @@ -614,9 +695,9 @@ static struct sock *l2cap_sock_alloc(struct net *net, struct socket *sock, int p sock_reset_flag(sk, SOCK_ZAPPED); sk->sk_protocol = proto; - sk->sk_state = BT_OPEN; + sk->sk_state = BT_OPEN; - setup_timer(&sk->sk_timer, l2cap_sock_timeout, (unsigned long)sk); + setup_timer(&sk->sk_timer, l2cap_sock_timeout, (unsigned long) sk); bt_sock_link(&l2cap_sk_list, sk); return sk; @@ -729,22 +810,11 @@ static int l2cap_do_connect(struct sock *sk) l2cap_sock_set_timer(sk, sk->sk_sndtimeo); if (hcon->state == BT_CONNECTED) { - if (!(conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT)) { - l2cap_conn_ready(conn); - goto done; - } - - if (sk->sk_type == SOCK_SEQPACKET) { - struct l2cap_conn_req req; - l2cap_pi(sk)->ident = l2cap_get_ident(conn); - req.scid = cpu_to_le16(l2cap_pi(sk)->scid); - req.psm = l2cap_pi(sk)->psm; - l2cap_send_cmd(conn, l2cap_pi(sk)->ident, - L2CAP_CONN_REQ, sizeof(req), &req); - } else { + if (sk->sk_type != SOCK_SEQPACKET) { l2cap_sock_clear_timer(sk); sk->sk_state = BT_CONNECTED; - } + } else + l2cap_do_start(sk); } done: @@ -1145,7 +1215,8 @@ static int l2cap_sock_shutdown(struct socket *sock, int how) __l2cap_sock_close(sk, 0); if (sock_flag(sk, SOCK_LINGER) && sk->sk_lingertime) - err = bt_sock_wait_state(sk, BT_CLOSED, sk->sk_lingertime); + err = bt_sock_wait_state(sk, BT_CLOSED, + sk->sk_lingertime); } release_sock(sk); return err; @@ -1189,6 +1260,11 @@ static void l2cap_chan_ready(struct sock *sk) */ parent->sk_data_ready(parent, 0); } + + if (l2cap_pi(sk)->link_mode & L2CAP_LM_SECURE) { + struct l2cap_conn *conn = l2cap_pi(sk)->conn; + hci_conn_change_link_key(conn->hcon); + } } /* Copy frame to all raw sockets on that connection */ @@ -1477,7 +1553,7 @@ static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hd struct l2cap_conn_req *req = (struct l2cap_conn_req *) data; struct l2cap_conn_rsp rsp; struct sock *sk, *parent; - int result = 0, status = 0; + int result, status = 0; u16 dcid = 0, scid = __le16_to_cpu(req->scid); __le16 psm = req->psm; @@ -1526,25 +1602,24 @@ static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hd l2cap_sock_set_timer(sk, sk->sk_sndtimeo); - /* Service level security */ - result = L2CAP_CR_PEND; - status = L2CAP_CS_AUTHEN_PEND; - sk->sk_state = BT_CONNECT2; l2cap_pi(sk)->ident = cmd->ident; - if ((l2cap_pi(sk)->link_mode & L2CAP_LM_ENCRYPT) || - (l2cap_pi(sk)->link_mode & L2CAP_LM_SECURE)) { - if (!hci_conn_encrypt(conn->hcon)) - goto done; - } else if (l2cap_pi(sk)->link_mode & L2CAP_LM_AUTH) { - if (!hci_conn_auth(conn->hcon)) - goto done; + if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT) { + if (l2cap_check_link_mode(sk)) { + sk->sk_state = BT_CONFIG; + result = L2CAP_CR_SUCCESS; + status = L2CAP_CS_NO_INFO; + } else { + sk->sk_state = BT_CONNECT2; + result = L2CAP_CR_PEND; + status = L2CAP_CS_AUTHEN_PEND; + } + } else { + sk->sk_state = BT_CONNECT2; + result = L2CAP_CR_PEND; + status = L2CAP_CS_NO_INFO; } - sk->sk_state = BT_CONFIG; - result = status = 0; - -done: write_unlock_bh(&list->lock); response: @@ -1556,6 +1631,21 @@ sendresp: rsp.result = cpu_to_le16(result); rsp.status = cpu_to_le16(status); l2cap_send_cmd(conn, cmd->ident, L2CAP_CONN_RSP, sizeof(rsp), &rsp); + + if (result == L2CAP_CR_PEND && status == L2CAP_CS_NO_INFO) { + struct l2cap_info_req info; + info.type = cpu_to_le16(L2CAP_IT_FEAT_MASK); + + conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_SENT; + conn->info_ident = l2cap_get_ident(conn); + + mod_timer(&conn->info_timer, jiffies + + msecs_to_jiffies(L2CAP_INFO_TIMEOUT)); + + l2cap_send_cmd(conn, conn->info_ident, + L2CAP_INFO_REQ, sizeof(info), &info); + } + return 0; } @@ -1664,9 +1754,9 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr } if (!(l2cap_pi(sk)->conf_state & L2CAP_CONF_REQ_SENT)) { - u8 req[64]; + u8 buf[64]; l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ, - l2cap_build_conf_req(sk, req), req); + l2cap_build_conf_req(sk, buf), buf); } unlock: @@ -1708,7 +1798,7 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr default: sk->sk_state = BT_DISCONN; - sk->sk_err = ECONNRESET; + sk->sk_err = ECONNRESET; l2cap_sock_set_timer(sk, HZ * 5); { struct l2cap_disconn_req req; @@ -2080,10 +2170,8 @@ static int l2cap_disconn_ind(struct hci_conn *hcon, u8 reason) static int l2cap_auth_cfm(struct hci_conn *hcon, u8 status) { struct l2cap_chan_list *l; - struct l2cap_conn *conn = conn = hcon->l2cap_data; - struct l2cap_conn_rsp rsp; + struct l2cap_conn *conn = hcon->l2cap_data; struct sock *sk; - int result; if (!conn) return 0; @@ -2095,45 +2183,65 @@ static int l2cap_auth_cfm(struct hci_conn *hcon, u8 status) read_lock(&l->lock); for (sk = l->head; sk; sk = l2cap_pi(sk)->next_c) { + struct l2cap_pinfo *pi = l2cap_pi(sk); + bh_lock_sock(sk); - if (sk->sk_state != BT_CONNECT2 || - (l2cap_pi(sk)->link_mode & L2CAP_LM_ENCRYPT) || - (l2cap_pi(sk)->link_mode & L2CAP_LM_SECURE)) { + if ((pi->link_mode & (L2CAP_LM_ENCRYPT | L2CAP_LM_SECURE)) && + !(hcon->link_mode & HCI_LM_ENCRYPT) && + !status) { bh_unlock_sock(sk); continue; } - if (!status) { - sk->sk_state = BT_CONFIG; - result = 0; - } else { - sk->sk_state = BT_DISCONN; - l2cap_sock_set_timer(sk, HZ/10); - result = L2CAP_CR_SEC_BLOCK; - } + if (sk->sk_state == BT_CONNECT) { + if (!status) { + struct l2cap_conn_req req; + req.scid = cpu_to_le16(l2cap_pi(sk)->scid); + req.psm = l2cap_pi(sk)->psm; - rsp.scid = cpu_to_le16(l2cap_pi(sk)->dcid); - rsp.dcid = cpu_to_le16(l2cap_pi(sk)->scid); - rsp.result = cpu_to_le16(result); - rsp.status = cpu_to_le16(0); - l2cap_send_cmd(conn, l2cap_pi(sk)->ident, - L2CAP_CONN_RSP, sizeof(rsp), &rsp); + l2cap_pi(sk)->ident = l2cap_get_ident(conn); + + l2cap_send_cmd(conn, l2cap_pi(sk)->ident, + L2CAP_CONN_REQ, sizeof(req), &req); + } else { + l2cap_sock_clear_timer(sk); + l2cap_sock_set_timer(sk, HZ / 10); + } + } else if (sk->sk_state == BT_CONNECT2) { + struct l2cap_conn_rsp rsp; + __u16 result; + + if (!status) { + sk->sk_state = BT_CONFIG; + result = L2CAP_CR_SUCCESS; + } else { + sk->sk_state = BT_DISCONN; + l2cap_sock_set_timer(sk, HZ / 10); + result = L2CAP_CR_SEC_BLOCK; + } + + rsp.scid = cpu_to_le16(l2cap_pi(sk)->dcid); + rsp.dcid = cpu_to_le16(l2cap_pi(sk)->scid); + rsp.result = cpu_to_le16(result); + rsp.status = cpu_to_le16(0); + l2cap_send_cmd(conn, l2cap_pi(sk)->ident, + L2CAP_CONN_RSP, sizeof(rsp), &rsp); + } bh_unlock_sock(sk); } read_unlock(&l->lock); + return 0; } -static int l2cap_encrypt_cfm(struct hci_conn *hcon, u8 status) +static int l2cap_encrypt_cfm(struct hci_conn *hcon, u8 status, u8 encrypt) { struct l2cap_chan_list *l; struct l2cap_conn *conn = hcon->l2cap_data; - struct l2cap_conn_rsp rsp; struct sock *sk; - int result; if (!conn) return 0; @@ -2145,36 +2253,59 @@ static int l2cap_encrypt_cfm(struct hci_conn *hcon, u8 status) read_lock(&l->lock); for (sk = l->head; sk; sk = l2cap_pi(sk)->next_c) { + struct l2cap_pinfo *pi = l2cap_pi(sk); + bh_lock_sock(sk); - if (sk->sk_state != BT_CONNECT2) { + if ((pi->link_mode & (L2CAP_LM_ENCRYPT | L2CAP_LM_SECURE)) && + (sk->sk_state == BT_CONNECTED || + sk->sk_state == BT_CONFIG) && + !status && encrypt == 0x00) { + __l2cap_sock_close(sk, ECONNREFUSED); bh_unlock_sock(sk); continue; } - if (!status) { - sk->sk_state = BT_CONFIG; - result = 0; - } else { - sk->sk_state = BT_DISCONN; - l2cap_sock_set_timer(sk, HZ/10); - result = L2CAP_CR_SEC_BLOCK; - } + if (sk->sk_state == BT_CONNECT) { + if (!status) { + struct l2cap_conn_req req; + req.scid = cpu_to_le16(l2cap_pi(sk)->scid); + req.psm = l2cap_pi(sk)->psm; + + l2cap_pi(sk)->ident = l2cap_get_ident(conn); - rsp.scid = cpu_to_le16(l2cap_pi(sk)->dcid); - rsp.dcid = cpu_to_le16(l2cap_pi(sk)->scid); - rsp.result = cpu_to_le16(result); - rsp.status = cpu_to_le16(0); - l2cap_send_cmd(conn, l2cap_pi(sk)->ident, - L2CAP_CONN_RSP, sizeof(rsp), &rsp); + l2cap_send_cmd(conn, l2cap_pi(sk)->ident, + L2CAP_CONN_REQ, sizeof(req), &req); + } else { + l2cap_sock_clear_timer(sk); + l2cap_sock_set_timer(sk, HZ / 10); + } + } else if (sk->sk_state == BT_CONNECT2) { + struct l2cap_conn_rsp rsp; + __u16 result; + + if (!status) { + sk->sk_state = BT_CONFIG; + result = L2CAP_CR_SUCCESS; + } else { + sk->sk_state = BT_DISCONN; + l2cap_sock_set_timer(sk, HZ / 10); + result = L2CAP_CR_SEC_BLOCK; + } - if (l2cap_pi(sk)->link_mode & L2CAP_LM_SECURE) - hci_conn_change_link_key(hcon); + rsp.scid = cpu_to_le16(l2cap_pi(sk)->dcid); + rsp.dcid = cpu_to_le16(l2cap_pi(sk)->scid); + rsp.result = cpu_to_le16(result); + rsp.status = cpu_to_le16(0); + l2cap_send_cmd(conn, l2cap_pi(sk)->ident, + L2CAP_CONN_RSP, sizeof(rsp), &rsp); + } bh_unlock_sock(sk); } read_unlock(&l->lock); + return 0; } @@ -2301,9 +2432,9 @@ static const struct proto_ops l2cap_sock_ops = { .sendmsg = l2cap_sock_sendmsg, .recvmsg = bt_sock_recvmsg, .poll = bt_sock_poll, + .ioctl = bt_sock_ioctl, .mmap = sock_no_mmap, .socketpair = sock_no_socketpair, - .ioctl = sock_no_ioctl, .shutdown = l2cap_sock_shutdown, .setsockopt = l2cap_sock_setsockopt, .getsockopt = l2cap_sock_getsockopt diff --git a/net/bluetooth/rfcomm/core.c b/net/bluetooth/rfcomm/core.c index 0c2c93735e93..6cfc7ba611b3 100644 --- a/net/bluetooth/rfcomm/core.c +++ b/net/bluetooth/rfcomm/core.c @@ -23,8 +23,6 @@ /* * Bluetooth RFCOMM core. - * - * $Id: core.c,v 1.42 2002/10/01 23:26:25 maxk Exp $ */ #include <linux/module.h> @@ -53,7 +51,7 @@ #define BT_DBG(D...) #endif -#define VERSION "1.8" +#define VERSION "1.10" static int disable_cfc = 0; static int channel_mtu = -1; @@ -230,6 +228,21 @@ static int rfcomm_l2sock_create(struct socket **sock) return err; } +static inline int rfcomm_check_link_mode(struct rfcomm_dlc *d) +{ + struct sock *sk = d->session->sock->sk; + + if (d->link_mode & (RFCOMM_LM_ENCRYPT | RFCOMM_LM_SECURE)) { + if (!hci_conn_encrypt(l2cap_pi(sk)->conn->hcon)) + return 1; + } else if (d->link_mode & RFCOMM_LM_AUTH) { + if (!hci_conn_auth(l2cap_pi(sk)->conn->hcon)) + return 1; + } + + return 0; +} + /* ---- RFCOMM DLCs ---- */ static void rfcomm_dlc_timeout(unsigned long arg) { @@ -371,15 +384,23 @@ static int __rfcomm_dlc_open(struct rfcomm_dlc *d, bdaddr_t *src, bdaddr_t *dst, d->addr = __addr(s->initiator, dlci); d->priority = 7; - d->state = BT_CONFIG; + d->state = BT_CONFIG; rfcomm_dlc_link(s, d); + d->out = 1; + d->mtu = s->mtu; d->cfc = (s->cfc == RFCOMM_CFC_UNKNOWN) ? 0 : s->cfc; - if (s->state == BT_CONNECTED) - rfcomm_send_pn(s, 1, d); + if (s->state == BT_CONNECTED) { + if (rfcomm_check_link_mode(d)) + set_bit(RFCOMM_AUTH_PENDING, &d->flags); + else + rfcomm_send_pn(s, 1, d); + } + rfcomm_dlc_set_timer(d, RFCOMM_CONN_TIMEOUT); + return 0; } @@ -1146,21 +1167,6 @@ static int rfcomm_recv_disc(struct rfcomm_session *s, u8 dlci) return 0; } -static inline int rfcomm_check_link_mode(struct rfcomm_dlc *d) -{ - struct sock *sk = d->session->sock->sk; - - if (d->link_mode & (RFCOMM_LM_ENCRYPT | RFCOMM_LM_SECURE)) { - if (!hci_conn_encrypt(l2cap_pi(sk)->conn->hcon)) - return 1; - } else if (d->link_mode & RFCOMM_LM_AUTH) { - if (!hci_conn_auth(l2cap_pi(sk)->conn->hcon)) - return 1; - } - - return 0; -} - static void rfcomm_dlc_accept(struct rfcomm_dlc *d) { struct sock *sk = d->session->sock->sk; @@ -1205,10 +1211,8 @@ static int rfcomm_recv_sabm(struct rfcomm_session *s, u8 dlci) if (rfcomm_check_link_mode(d)) { set_bit(RFCOMM_AUTH_PENDING, &d->flags); rfcomm_dlc_set_timer(d, RFCOMM_AUTH_TIMEOUT); - return 0; - } - - rfcomm_dlc_accept(d); + } else + rfcomm_dlc_accept(d); } return 0; } @@ -1223,10 +1227,8 @@ static int rfcomm_recv_sabm(struct rfcomm_session *s, u8 dlci) if (rfcomm_check_link_mode(d)) { set_bit(RFCOMM_AUTH_PENDING, &d->flags); rfcomm_dlc_set_timer(d, RFCOMM_AUTH_TIMEOUT); - return 0; - } - - rfcomm_dlc_accept(d); + } else + rfcomm_dlc_accept(d); } else { rfcomm_send_dm(s, dlci); } @@ -1459,8 +1461,12 @@ static int rfcomm_recv_msc(struct rfcomm_session *s, int cr, struct sk_buff *skb clear_bit(RFCOMM_TX_THROTTLED, &d->flags); rfcomm_dlc_lock(d); + + d->remote_v24_sig = msc->v24_sig; + if (d->modem_status) d->modem_status(d, msc->v24_sig); + rfcomm_dlc_unlock(d); rfcomm_send_msc(s, 0, dlci, msc->v24_sig); @@ -1636,7 +1642,11 @@ static void rfcomm_process_connect(struct rfcomm_session *s) d = list_entry(p, struct rfcomm_dlc, list); if (d->state == BT_CONFIG) { d->mtu = s->mtu; - rfcomm_send_pn(s, 1, d); + if (rfcomm_check_link_mode(d)) { + set_bit(RFCOMM_AUTH_PENDING, &d->flags); + rfcomm_dlc_set_timer(d, RFCOMM_AUTH_TIMEOUT); + } else + rfcomm_send_pn(s, 1, d); } } } @@ -1709,7 +1719,11 @@ static inline void rfcomm_process_dlcs(struct rfcomm_session *s) if (test_and_clear_bit(RFCOMM_AUTH_ACCEPT, &d->flags)) { rfcomm_dlc_clear_timer(d); - rfcomm_dlc_accept(d); + if (d->out) { + rfcomm_send_pn(s, 1, d); + rfcomm_dlc_set_timer(d, RFCOMM_CONN_TIMEOUT); + } else + rfcomm_dlc_accept(d); if (d->link_mode & RFCOMM_LM_SECURE) { struct sock *sk = s->sock->sk; hci_conn_change_link_key(l2cap_pi(sk)->conn->hcon); @@ -1717,7 +1731,10 @@ static inline void rfcomm_process_dlcs(struct rfcomm_session *s) continue; } else if (test_and_clear_bit(RFCOMM_AUTH_REJECT, &d->flags)) { rfcomm_dlc_clear_timer(d); - rfcomm_send_dm(s, d->dlci); + if (!d->out) + rfcomm_send_dm(s, d->dlci); + else + d->state = BT_CLOSED; __rfcomm_dlc_close(d, ECONNREFUSED); continue; } @@ -1726,7 +1743,7 @@ static inline void rfcomm_process_dlcs(struct rfcomm_session *s) continue; if ((d->state == BT_CONNECTED || d->state == BT_DISCONN) && - d->mscex == RFCOMM_MSCEX_OK) + d->mscex == RFCOMM_MSCEX_OK) rfcomm_process_tx(d); } } @@ -1954,7 +1971,8 @@ static void rfcomm_auth_cfm(struct hci_conn *conn, u8 status) list_for_each_safe(p, n, &s->dlcs) { d = list_entry(p, struct rfcomm_dlc, list); - if (d->link_mode & (RFCOMM_LM_ENCRYPT | RFCOMM_LM_SECURE)) + if ((d->link_mode & (RFCOMM_LM_ENCRYPT | RFCOMM_LM_SECURE)) && + !(conn->link_mode & HCI_LM_ENCRYPT) && !status) continue; if (!test_and_clear_bit(RFCOMM_AUTH_PENDING, &d->flags)) @@ -1988,6 +2006,14 @@ static void rfcomm_encrypt_cfm(struct hci_conn *conn, u8 status, u8 encrypt) list_for_each_safe(p, n, &s->dlcs) { d = list_entry(p, struct rfcomm_dlc, list); + if ((d->link_mode & (RFCOMM_LM_ENCRYPT | RFCOMM_LM_SECURE)) && + (d->state == BT_CONNECTED || + d->state == BT_CONFIG) && + !status && encrypt == 0x00) { + __rfcomm_dlc_close(d, ECONNREFUSED); + continue; + } + if (!test_and_clear_bit(RFCOMM_AUTH_PENDING, &d->flags)) continue; diff --git a/net/bluetooth/rfcomm/sock.c b/net/bluetooth/rfcomm/sock.c index 5083adcbfae5..8a972b6ba85f 100644 --- a/net/bluetooth/rfcomm/sock.c +++ b/net/bluetooth/rfcomm/sock.c @@ -23,8 +23,6 @@ /* * RFCOMM sockets. - * - * $Id: sock.c,v 1.24 2002/10/03 01:00:34 maxk Exp $ */ #include <linux/module.h> @@ -309,13 +307,13 @@ static struct sock *rfcomm_sock_alloc(struct net *net, struct socket *sock, int sk->sk_destruct = rfcomm_sock_destruct; sk->sk_sndtimeo = RFCOMM_CONN_TIMEOUT; - sk->sk_sndbuf = RFCOMM_MAX_CREDITS * RFCOMM_DEFAULT_MTU * 10; - sk->sk_rcvbuf = RFCOMM_MAX_CREDITS * RFCOMM_DEFAULT_MTU * 10; + sk->sk_sndbuf = RFCOMM_MAX_CREDITS * RFCOMM_DEFAULT_MTU * 10; + sk->sk_rcvbuf = RFCOMM_MAX_CREDITS * RFCOMM_DEFAULT_MTU * 10; sock_reset_flag(sk, SOCK_ZAPPED); sk->sk_protocol = proto; - sk->sk_state = BT_OPEN; + sk->sk_state = BT_OPEN; bt_sock_link(&rfcomm_sk_list, sk); @@ -413,6 +411,8 @@ static int rfcomm_sock_connect(struct socket *sock, struct sockaddr *addr, int a bacpy(&bt_sk(sk)->dst, &sa->rc_bdaddr); rfcomm_pi(sk)->channel = sa->rc_channel; + d->link_mode = rfcomm_pi(sk)->link_mode; + err = rfcomm_dlc_open(d, &bt_sk(sk)->src, &sa->rc_bdaddr, sa->rc_channel); if (!err) err = bt_sock_wait_state(sk, BT_CONNECTED, @@ -688,6 +688,8 @@ static int rfcomm_sock_recvmsg(struct kiocb *iocb, struct socket *sock, copied += chunk; size -= chunk; + sock_recv_timestamp(msg, sk, skb); + if (!(flags & MSG_PEEK)) { atomic_sub(chunk, &sk->sk_rmem_alloc); @@ -793,15 +795,20 @@ static int rfcomm_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned lon struct sock *sk = sock->sk; int err; - lock_sock(sk); + BT_DBG("sk %p cmd %x arg %lx", sk, cmd, arg); + + err = bt_sock_ioctl(sock, cmd, arg); + if (err == -ENOIOCTLCMD) { #ifdef CONFIG_BT_RFCOMM_TTY - err = rfcomm_dev_ioctl(sk, cmd, (void __user *)arg); + lock_sock(sk); + err = rfcomm_dev_ioctl(sk, cmd, (void __user *) arg); + release_sock(sk); #else - err = -EOPNOTSUPP; + err = -EOPNOTSUPP; #endif + } - release_sock(sk); return err; } diff --git a/net/bluetooth/rfcomm/tty.c b/net/bluetooth/rfcomm/tty.c index c9191871c1e0..d3340dd52bcf 100644 --- a/net/bluetooth/rfcomm/tty.c +++ b/net/bluetooth/rfcomm/tty.c @@ -23,8 +23,6 @@ /* * RFCOMM TTY. - * - * $Id: tty.c,v 1.24 2002/10/03 01:54:38 holtmann Exp $ */ #include <linux/module.h> @@ -77,6 +75,8 @@ struct rfcomm_dev { struct device *tty_dev; atomic_t wmem_alloc; + + struct sk_buff_head pending; }; static LIST_HEAD(rfcomm_dev_list); @@ -264,13 +264,34 @@ static int rfcomm_dev_add(struct rfcomm_dev_req *req, struct rfcomm_dlc *dlc) init_waitqueue_head(&dev->wait); tasklet_init(&dev->wakeup_task, rfcomm_tty_wakeup, (unsigned long) dev); + skb_queue_head_init(&dev->pending); + rfcomm_dlc_lock(dlc); + + if (req->flags & (1 << RFCOMM_REUSE_DLC)) { + struct sock *sk = dlc->owner; + struct sk_buff *skb; + + BUG_ON(!sk); + + rfcomm_dlc_throttle(dlc); + + while ((skb = skb_dequeue(&sk->sk_receive_queue))) { + skb_orphan(skb); + skb_queue_tail(&dev->pending, skb); + atomic_sub(skb->len, &sk->sk_rmem_alloc); + } + } + dlc->data_ready = rfcomm_dev_data_ready; dlc->state_change = rfcomm_dev_state_change; dlc->modem_status = rfcomm_dev_modem_status; dlc->owner = dev; dev->dlc = dlc; + + rfcomm_dev_modem_status(dlc, dlc->remote_v24_sig); + rfcomm_dlc_unlock(dlc); /* It's safe to call __module_get() here because socket already @@ -539,11 +560,16 @@ static void rfcomm_dev_data_ready(struct rfcomm_dlc *dlc, struct sk_buff *skb) struct rfcomm_dev *dev = dlc->owner; struct tty_struct *tty; - if (!dev || !(tty = dev->tty)) { + if (!dev) { kfree_skb(skb); return; } + if (!(tty = dev->tty) || !skb_queue_empty(&dev->pending)) { + skb_queue_tail(&dev->pending, skb); + return; + } + BT_DBG("dlc %p tty %p len %d", dlc, tty, skb->len); tty_insert_flip_string(tty, skb->data, skb->len); @@ -617,14 +643,31 @@ static void rfcomm_tty_wakeup(unsigned long arg) return; BT_DBG("dev %p tty %p", dev, tty); + tty_wakeup(tty); +} - if (test_bit(TTY_DO_WRITE_WAKEUP, &tty->flags) && tty->ldisc.write_wakeup) - (tty->ldisc.write_wakeup)(tty); +static void rfcomm_tty_copy_pending(struct rfcomm_dev *dev) +{ + struct tty_struct *tty = dev->tty; + struct sk_buff *skb; + int inserted = 0; - wake_up_interruptible(&tty->write_wait); -#ifdef SERIAL_HAVE_POLL_WAIT - wake_up_interruptible(&tty->poll_wait); -#endif + if (!tty) + return; + + BT_DBG("dev %p tty %p", dev, tty); + + rfcomm_dlc_lock(dev->dlc); + + while ((skb = skb_dequeue(&dev->pending))) { + inserted += tty_insert_flip_string(tty, skb->data, skb->len); + kfree_skb(skb); + } + + rfcomm_dlc_unlock(dev->dlc); + + if (inserted > 0) + tty_flip_buffer_push(tty); } static int rfcomm_tty_open(struct tty_struct *tty, struct file *filp) @@ -691,6 +734,10 @@ static int rfcomm_tty_open(struct tty_struct *tty, struct file *filp) if (err == 0) device_move(dev->tty_dev, rfcomm_get_device(dev)); + rfcomm_tty_copy_pending(dev); + + rfcomm_dlc_unthrottle(dev->dlc); + return err; } @@ -1005,9 +1052,7 @@ static void rfcomm_tty_flush_buffer(struct tty_struct *tty) return; skb_queue_purge(&dev->dlc->tx_queue); - - if (test_bit(TTY_DO_WRITE_WAKEUP, &tty->flags) && tty->ldisc.write_wakeup) - tty->ldisc.write_wakeup(tty); + tty_wakeup(tty); } static void rfcomm_tty_send_xchar(struct tty_struct *tty, char ch) @@ -1123,6 +1168,7 @@ int rfcomm_init_ttys(void) rfcomm_tty_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV; rfcomm_tty_driver->init_termios = tty_std_termios; rfcomm_tty_driver->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL; + rfcomm_tty_driver->init_termios.c_lflag &= ~ICANON; tty_set_operations(rfcomm_tty_driver, &rfcomm_ops); if (tty_register_driver(rfcomm_tty_driver)) { diff --git a/net/bluetooth/sco.c b/net/bluetooth/sco.c index b0d487e2db20..8cda49874868 100644 --- a/net/bluetooth/sco.c +++ b/net/bluetooth/sco.c @@ -53,7 +53,9 @@ #define BT_DBG(D...) #endif -#define VERSION "0.5" +#define VERSION "0.6" + +static int disable_esco = 0; static const struct proto_ops sco_sock_ops; @@ -193,7 +195,10 @@ static int sco_connect(struct sock *sk) err = -ENOMEM; - type = lmp_esco_capable(hdev) ? ESCO_LINK : SCO_LINK; + if (lmp_esco_capable(hdev) && !disable_esco) + type = ESCO_LINK; + else + type = SCO_LINK; hcon = hci_connect(hdev, type, dst); if (!hcon) @@ -921,7 +926,7 @@ static const struct proto_ops sco_sock_ops = { .sendmsg = sco_sock_sendmsg, .recvmsg = bt_sock_recvmsg, .poll = bt_sock_poll, - .ioctl = sock_no_ioctl, + .ioctl = bt_sock_ioctl, .mmap = sock_no_mmap, .socketpair = sock_no_socketpair, .shutdown = sock_no_shutdown, @@ -994,6 +999,9 @@ static void __exit sco_exit(void) module_init(sco_init); module_exit(sco_exit); +module_param(disable_esco, bool, 0644); +MODULE_PARM_DESC(disable_esco, "Disable eSCO connection creation"); + MODULE_AUTHOR("Maxim Krasnyansky <maxk@qualcomm.com>, Marcel Holtmann <marcel@holtmann.org>"); MODULE_DESCRIPTION("Bluetooth SCO ver " VERSION); MODULE_VERSION(VERSION); diff --git a/net/bridge/Kconfig b/net/bridge/Kconfig index 12265aff7099..e143ca678881 100644 --- a/net/bridge/Kconfig +++ b/net/bridge/Kconfig @@ -5,6 +5,7 @@ config BRIDGE tristate "802.1d Ethernet Bridging" select LLC + select STP ---help--- If you say Y here, then your Linux box will be able to act as an Ethernet bridge, which means that the different Ethernet segments it diff --git a/net/bridge/br.c b/net/bridge/br.c index 8f3c58e5f7a5..573acdf6f9ff 100644 --- a/net/bridge/br.c +++ b/net/bridge/br.c @@ -5,8 +5,6 @@ * Authors: * Lennert Buytenhek <buytenh@gnu.org> * - * $Id: br.c,v 1.47 2001/12/24 00:56:41 davem Exp $ - * * 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 @@ -20,21 +18,24 @@ #include <linux/init.h> #include <linux/llc.h> #include <net/llc.h> +#include <net/stp.h> #include "br_private.h" int (*br_should_route_hook)(struct sk_buff *skb); -static struct llc_sap *br_stp_sap; +static const struct stp_proto br_stp_proto = { + .rcv = br_stp_rcv, +}; static int __init br_init(void) { int err; - br_stp_sap = llc_sap_open(LLC_SAP_BSPAN, br_stp_rcv); - if (!br_stp_sap) { + err = stp_proto_register(&br_stp_proto); + if (err < 0) { printk(KERN_ERR "bridge: can't register sap for STP\n"); - return -EADDRINUSE; + return err; } err = br_fdb_init(); @@ -67,13 +68,13 @@ err_out2: err_out1: br_fdb_fini(); err_out: - llc_sap_put(br_stp_sap); + stp_proto_unregister(&br_stp_proto); return err; } static void __exit br_deinit(void) { - rcu_assign_pointer(br_stp_sap->rcv_func, NULL); + stp_proto_unregister(&br_stp_proto); br_netlink_fini(); unregister_netdevice_notifier(&br_device_notifier); @@ -84,7 +85,6 @@ static void __exit br_deinit(void) synchronize_net(); br_netfilter_fini(); - llc_sap_put(br_stp_sap); br_fdb_get_hook = NULL; br_fdb_put_hook = NULL; diff --git a/net/bridge/br_device.c b/net/bridge/br_device.c index bf7787395fe0..d9449df7cad5 100644 --- a/net/bridge/br_device.c +++ b/net/bridge/br_device.c @@ -5,8 +5,6 @@ * Authors: * Lennert Buytenhek <buytenh@gnu.org> * - * $Id: br_device.c,v 1.6 2001/12/24 00:59:55 davem Exp $ - * * 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 @@ -21,12 +19,6 @@ #include <asm/uaccess.h> #include "br_private.h" -static struct net_device_stats *br_dev_get_stats(struct net_device *dev) -{ - struct net_bridge *br = netdev_priv(dev); - return &br->statistics; -} - /* net device transmit always called with no BH (preempt_disabled) */ int br_dev_xmit(struct sk_buff *skb, struct net_device *dev) { @@ -34,8 +26,8 @@ int br_dev_xmit(struct sk_buff *skb, struct net_device *dev) const unsigned char *dest = skb->data; struct net_bridge_fdb_entry *dst; - br->statistics.tx_packets++; - br->statistics.tx_bytes += skb->len; + dev->stats.tx_packets++; + dev->stats.tx_bytes += skb->len; skb_reset_mac_header(skb); skb_pull(skb, ETH_HLEN); @@ -95,6 +87,7 @@ static int br_set_mac_address(struct net_device *dev, void *p) spin_lock_bh(&br->lock); memcpy(dev->dev_addr, addr->sa_data, ETH_ALEN); br_stp_change_bridge_id(br, addr->sa_data); + br->flags |= BR_SET_MAC_ADDR; spin_unlock_bh(&br->lock); return 0; @@ -161,7 +154,6 @@ void br_dev_setup(struct net_device *dev) ether_setup(dev); dev->do_ioctl = br_dev_ioctl; - dev->get_stats = br_dev_get_stats; dev->hard_start_xmit = br_dev_xmit; dev->open = br_dev_open; dev->set_multicast_list = br_dev_set_multicast_list; diff --git a/net/bridge/br_fdb.c b/net/bridge/br_fdb.c index 142060f02054..a48f5efdb6bf 100644 --- a/net/bridge/br_fdb.c +++ b/net/bridge/br_fdb.c @@ -5,8 +5,6 @@ * Authors: * Lennert Buytenhek <buytenh@gnu.org> * - * $Id: br_fdb.c,v 1.6 2002/01/17 00:57:07 davem Exp $ - * * 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 diff --git a/net/bridge/br_forward.c b/net/bridge/br_forward.c index bdd7c35c3c7b..bdd9ccea17ce 100644 --- a/net/bridge/br_forward.c +++ b/net/bridge/br_forward.c @@ -5,8 +5,6 @@ * Authors: * Lennert Buytenhek <buytenh@gnu.org> * - * $Id: br_forward.c,v 1.4 2001/08/14 22:05:57 davem Exp $ - * * 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 @@ -91,7 +89,7 @@ void br_deliver(const struct net_bridge_port *to, struct sk_buff *skb) /* called with rcu_read_lock */ void br_forward(const struct net_bridge_port *to, struct sk_buff *skb) { - if (should_deliver(to, skb)) { + if (!skb_warn_if_lro(skb) && should_deliver(to, skb)) { __br_forward(to, skb); return; } @@ -115,7 +113,7 @@ static void br_flood(struct net_bridge *br, struct sk_buff *skb, struct sk_buff *skb2; if ((skb2 = skb_clone(skb, GFP_ATOMIC)) == NULL) { - br->statistics.tx_dropped++; + br->dev->stats.tx_dropped++; kfree_skb(skb); return; } diff --git a/net/bridge/br_if.c b/net/bridge/br_if.c index f38cc5317b88..a072ea5ca6f5 100644 --- a/net/bridge/br_if.c +++ b/net/bridge/br_if.c @@ -5,8 +5,6 @@ * Authors: * Lennert Buytenhek <buytenh@gnu.org> * - * $Id: br_if.c,v 1.7 2001/12/24 00:59:55 davem Exp $ - * * 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 @@ -375,6 +373,10 @@ int br_add_if(struct net_bridge *br, struct net_device *dev) if (IS_ERR(p)) return PTR_ERR(p); + err = dev_set_promiscuity(dev, 1); + if (err) + goto put_back; + err = kobject_init_and_add(&p->kobj, &brport_ktype, &(dev->dev.kobj), SYSFS_BRIDGE_PORT_ATTR); if (err) @@ -389,7 +391,7 @@ int br_add_if(struct net_bridge *br, struct net_device *dev) goto err2; rcu_assign_pointer(dev->br_port, p); - dev_set_promiscuity(dev, 1); + dev_disable_lro(dev); list_add_rcu(&p->list, &br->port_list); @@ -413,12 +415,12 @@ err2: br_fdb_delete_by_port(br, p, 1); err1: kobject_del(&p->kobj); - goto put_back; err0: kobject_put(&p->kobj); - + dev_set_promiscuity(dev, -1); put_back: dev_put(dev); + kfree(p); return err; } diff --git a/net/bridge/br_input.c b/net/bridge/br_input.c index 255c00f60ce7..30b88777c3df 100644 --- a/net/bridge/br_input.c +++ b/net/bridge/br_input.c @@ -5,8 +5,6 @@ * Authors: * Lennert Buytenhek <buytenh@gnu.org> * - * $Id: br_input.c,v 1.10 2001/12/24 04:50:20 davem Exp $ - * * 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 @@ -24,13 +22,13 @@ const u8 br_group_address[ETH_ALEN] = { 0x01, 0x80, 0xc2, 0x00, 0x00, 0x00 }; static void br_pass_frame_up(struct net_bridge *br, struct sk_buff *skb) { - struct net_device *indev; + struct net_device *indev, *brdev = br->dev; - br->statistics.rx_packets++; - br->statistics.rx_bytes += skb->len; + brdev->stats.rx_packets++; + brdev->stats.rx_bytes += skb->len; indev = skb->dev; - skb->dev = br->dev; + skb->dev = brdev; NF_HOOK(PF_BRIDGE, NF_BR_LOCAL_IN, skb, indev, NULL, netif_receive_skb); @@ -64,7 +62,7 @@ int br_handle_frame_finish(struct sk_buff *skb) dst = NULL; if (is_multicast_ether_addr(dest)) { - br->statistics.multicast++; + br->dev->stats.multicast++; skb2 = skb; } else if ((dst = __br_fdb_get(br, dest)) && dst->is_local) { skb2 = skb; @@ -136,14 +134,11 @@ struct sk_buff *br_handle_frame(struct net_bridge_port *p, struct sk_buff *skb) if (skb->protocol == htons(ETH_P_PAUSE)) goto drop; - /* Process STP BPDU's through normal netif_receive_skb() path */ - if (p->br->stp_enabled != BR_NO_STP) { - if (NF_HOOK(PF_BRIDGE, NF_BR_LOCAL_IN, skb, skb->dev, - NULL, br_handle_local_finish)) - return NULL; - else - return skb; - } + if (NF_HOOK(PF_BRIDGE, NF_BR_LOCAL_IN, skb, skb->dev, + NULL, br_handle_local_finish)) + return NULL; /* frame consumed by filter */ + else + return skb; /* continue processing */ } switch (p->state) { diff --git a/net/bridge/br_ioctl.c b/net/bridge/br_ioctl.c index 0655a5f07f58..eeee218eed80 100644 --- a/net/bridge/br_ioctl.c +++ b/net/bridge/br_ioctl.c @@ -5,8 +5,6 @@ * Authors: * Lennert Buytenhek <buytenh@gnu.org> * - * $Id: br_ioctl.c,v 1.4 2000/11/08 05:16:40 davem Exp $ - * * 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 diff --git a/net/bridge/br_notify.c b/net/bridge/br_notify.c index 00644a544e3c..76340bdd052e 100644 --- a/net/bridge/br_notify.c +++ b/net/bridge/br_notify.c @@ -5,8 +5,6 @@ * Authors: * Lennert Buytenhek <buytenh@gnu.org> * - * $Id: br_notify.c,v 1.2 2000/02/21 15:51:34 davem Exp $ - * * 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 @@ -37,7 +35,7 @@ static int br_device_event(struct notifier_block *unused, unsigned long event, v struct net_bridge_port *p = dev->br_port; struct net_bridge *br; - if (dev_net(dev) != &init_net) + if (!net_eq(dev_net(dev), &init_net)) return NOTIFY_DONE; /* not a port of a bridge */ diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h index c11b554fd109..815ed38925b2 100644 --- a/net/bridge/br_private.h +++ b/net/bridge/br_private.h @@ -4,8 +4,6 @@ * Authors: * Lennert Buytenhek <buytenh@gnu.org> * - * $Id: br_private.h,v 1.7 2001/12/24 00:59:55 davem Exp $ - * * 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 @@ -90,11 +88,12 @@ struct net_bridge spinlock_t lock; struct list_head port_list; struct net_device *dev; - struct net_device_stats statistics; spinlock_t hash_lock; struct hlist_head hash[BR_HASH_SIZE]; struct list_head age_list; unsigned long feature_mask; + unsigned long flags; +#define BR_SET_MAC_ADDR 0x00000001 /* STP */ bridge_id designated_root; @@ -227,8 +226,9 @@ extern void br_stp_set_path_cost(struct net_bridge_port *p, extern ssize_t br_show_bridge_id(char *buf, const struct bridge_id *id); /* br_stp_bpdu.c */ -extern int br_stp_rcv(struct sk_buff *skb, struct net_device *dev, - struct packet_type *pt, struct net_device *orig_dev); +struct stp_proto; +extern void br_stp_rcv(const struct stp_proto *proto, struct sk_buff *skb, + struct net_device *dev); /* br_stp_timer.c */ extern void br_stp_timer_init(struct net_bridge *br); diff --git a/net/bridge/br_private_stp.h b/net/bridge/br_private_stp.h index e29f01ac1adf..8b650f7fbfa0 100644 --- a/net/bridge/br_private_stp.h +++ b/net/bridge/br_private_stp.h @@ -4,8 +4,6 @@ * Authors: * Lennert Buytenhek <buytenh@gnu.org> * - * $Id: br_private_stp.h,v 1.3 2001/02/05 06:03:47 davem Exp $ - * * 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 diff --git a/net/bridge/br_stp.c b/net/bridge/br_stp.c index 9e96ffcd29a3..921bbe5cb94a 100644 --- a/net/bridge/br_stp.c +++ b/net/bridge/br_stp.c @@ -5,8 +5,6 @@ * Authors: * Lennert Buytenhek <buytenh@gnu.org> * - * $Id: br_stp.c,v 1.4 2000/06/19 10:13:35 davem Exp $ - * * 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 diff --git a/net/bridge/br_stp_bpdu.c b/net/bridge/br_stp_bpdu.c index ddeb6e5d45d6..8b200f96f722 100644 --- a/net/bridge/br_stp_bpdu.c +++ b/net/bridge/br_stp_bpdu.c @@ -5,8 +5,6 @@ * Authors: * Lennert Buytenhek <buytenh@gnu.org> * - * $Id: br_stp_bpdu.c,v 1.3 2001/11/10 02:35:25 davem Exp $ - * * 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 @@ -20,6 +18,7 @@ #include <net/net_namespace.h> #include <net/llc.h> #include <net/llc_pdu.h> +#include <net/stp.h> #include <asm/unaligned.h> #include "br_private.h" @@ -133,26 +132,20 @@ void br_send_tcn_bpdu(struct net_bridge_port *p) * * NO locks, but rcu_read_lock (preempt_disabled) */ -int br_stp_rcv(struct sk_buff *skb, struct net_device *dev, - struct packet_type *pt, struct net_device *orig_dev) +void br_stp_rcv(const struct stp_proto *proto, struct sk_buff *skb, + struct net_device *dev) { - const struct llc_pdu_un *pdu = llc_pdu_un_hdr(skb); const unsigned char *dest = eth_hdr(skb)->h_dest; struct net_bridge_port *p = rcu_dereference(dev->br_port); struct net_bridge *br; const unsigned char *buf; - if (dev_net(dev) != &init_net) + if (!net_eq(dev_net(dev), &init_net)) goto err; if (!p) goto err; - if (pdu->ssap != LLC_SAP_BSPAN - || pdu->dsap != LLC_SAP_BSPAN - || pdu->ctrl_1 != LLC_PDU_TYPE_U) - goto err; - if (!pskb_may_pull(skb, 4)) goto err; @@ -226,5 +219,4 @@ int br_stp_rcv(struct sk_buff *skb, struct net_device *dev, spin_unlock(&br->lock); err: kfree_skb(skb); - return 0; } diff --git a/net/bridge/br_stp_if.c b/net/bridge/br_stp_if.c index 1a430eccec9b..9a52ac5b4525 100644 --- a/net/bridge/br_stp_if.c +++ b/net/bridge/br_stp_if.c @@ -5,8 +5,6 @@ * Authors: * Lennert Buytenhek <buytenh@gnu.org> * - * $Id: br_stp_if.c,v 1.4 2001/04/14 21:14:39 davem Exp $ - * * 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 @@ -216,6 +214,10 @@ void br_stp_recalculate_bridge_id(struct net_bridge *br) const unsigned char *addr = br_mac_zero; struct net_bridge_port *p; + /* user has chosen a value so keep it */ + if (br->flags & BR_SET_MAC_ADDR) + return; + list_for_each_entry(p, &br->port_list, list) { if (addr == br_mac_zero || memcmp(p->dev->dev_addr, addr, ETH_ALEN) < 0) diff --git a/net/bridge/br_stp_timer.c b/net/bridge/br_stp_timer.c index 77f5255e6915..772a140bfdf0 100644 --- a/net/bridge/br_stp_timer.c +++ b/net/bridge/br_stp_timer.c @@ -5,8 +5,6 @@ * Authors: * Lennert Buytenhek <buytenh@gnu.org> * - * $Id: br_stp_timer.c,v 1.3 2000/05/05 02:17:17 davem Exp $ - * * 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 diff --git a/net/bridge/netfilter/Kconfig b/net/bridge/netfilter/Kconfig index 7beeefa0f9c0..909479794999 100644 --- a/net/bridge/netfilter/Kconfig +++ b/net/bridge/netfilter/Kconfig @@ -83,6 +83,15 @@ config BRIDGE_EBT_IP To compile it as a module, choose M here. If unsure, say N. +config BRIDGE_EBT_IP6 + tristate "ebt: IP6 filter support" + depends on BRIDGE_NF_EBTABLES && IPV6 + help + This option adds the IP6 match, which allows basic IPV6 header field + filtering. + + To compile it as a module, choose M here. If unsure, say N. + config BRIDGE_EBT_LIMIT tristate "ebt: limit match support" depends on BRIDGE_NF_EBTABLES @@ -221,7 +230,7 @@ config BRIDGE_EBT_NFLOG either the old LOG target, the old ULOG target or nfnetlink_log as backend. - This option adds the ulog watcher, that you can use in any rule + This option adds the nflog watcher, that you can use in any rule in any ebtables table. To compile it as a module, choose M here. If unsure, say N. diff --git a/net/bridge/netfilter/Makefile b/net/bridge/netfilter/Makefile index 83715d73a503..0718699540b0 100644 --- a/net/bridge/netfilter/Makefile +++ b/net/bridge/netfilter/Makefile @@ -14,6 +14,7 @@ obj-$(CONFIG_BRIDGE_EBT_802_3) += ebt_802_3.o obj-$(CONFIG_BRIDGE_EBT_AMONG) += ebt_among.o obj-$(CONFIG_BRIDGE_EBT_ARP) += ebt_arp.o obj-$(CONFIG_BRIDGE_EBT_IP) += ebt_ip.o +obj-$(CONFIG_BRIDGE_EBT_IP6) += ebt_ip6.o obj-$(CONFIG_BRIDGE_EBT_LIMIT) += ebt_limit.o obj-$(CONFIG_BRIDGE_EBT_MARK) += ebt_mark_m.o obj-$(CONFIG_BRIDGE_EBT_PKTTYPE) += ebt_pkttype.o diff --git a/net/bridge/netfilter/ebt_ip6.c b/net/bridge/netfilter/ebt_ip6.c new file mode 100644 index 000000000000..36efb3a75249 --- /dev/null +++ b/net/bridge/netfilter/ebt_ip6.c @@ -0,0 +1,144 @@ +/* + * ebt_ip6 + * + * Authors: + * Manohar Castelino <manohar.r.castelino@intel.com> + * Kuo-Lang Tseng <kuo-lang.tseng@intel.com> + * Jan Engelhardt <jengelh@computergmbh.de> + * + * Summary: + * This is just a modification of the IPv4 code written by + * Bart De Schuymer <bdschuym@pandora.be> + * with the changes required to support IPv6 + * + * Jan, 2008 + */ + +#include <linux/netfilter_bridge/ebtables.h> +#include <linux/netfilter_bridge/ebt_ip6.h> +#include <linux/ipv6.h> +#include <net/ipv6.h> +#include <linux/in.h> +#include <linux/module.h> +#include <net/dsfield.h> + +struct tcpudphdr { + __be16 src; + __be16 dst; +}; + +static int ebt_filter_ip6(const struct sk_buff *skb, + const struct net_device *in, + const struct net_device *out, const void *data, + unsigned int datalen) +{ + const struct ebt_ip6_info *info = (struct ebt_ip6_info *)data; + const struct ipv6hdr *ih6; + struct ipv6hdr _ip6h; + const struct tcpudphdr *pptr; + struct tcpudphdr _ports; + struct in6_addr tmp_addr; + int i; + + ih6 = skb_header_pointer(skb, 0, sizeof(_ip6h), &_ip6h); + if (ih6 == NULL) + return EBT_NOMATCH; + if (info->bitmask & EBT_IP6_TCLASS && + FWINV(info->tclass != ipv6_get_dsfield(ih6), EBT_IP6_TCLASS)) + return EBT_NOMATCH; + for (i = 0; i < 4; i++) + tmp_addr.in6_u.u6_addr32[i] = ih6->saddr.in6_u.u6_addr32[i] & + info->smsk.in6_u.u6_addr32[i]; + if (info->bitmask & EBT_IP6_SOURCE && + FWINV((ipv6_addr_cmp(&tmp_addr, &info->saddr) != 0), + EBT_IP6_SOURCE)) + return EBT_NOMATCH; + for (i = 0; i < 4; i++) + tmp_addr.in6_u.u6_addr32[i] = ih6->daddr.in6_u.u6_addr32[i] & + info->dmsk.in6_u.u6_addr32[i]; + if (info->bitmask & EBT_IP6_DEST && + FWINV((ipv6_addr_cmp(&tmp_addr, &info->daddr) != 0), EBT_IP6_DEST)) + return EBT_NOMATCH; + if (info->bitmask & EBT_IP6_PROTO) { + uint8_t nexthdr = ih6->nexthdr; + int offset_ph; + + offset_ph = ipv6_skip_exthdr(skb, sizeof(_ip6h), &nexthdr); + if (offset_ph == -1) + return EBT_NOMATCH; + if (FWINV(info->protocol != nexthdr, EBT_IP6_PROTO)) + return EBT_NOMATCH; + if (!(info->bitmask & EBT_IP6_DPORT) && + !(info->bitmask & EBT_IP6_SPORT)) + return EBT_MATCH; + pptr = skb_header_pointer(skb, offset_ph, sizeof(_ports), + &_ports); + if (pptr == NULL) + return EBT_NOMATCH; + if (info->bitmask & EBT_IP6_DPORT) { + u32 dst = ntohs(pptr->dst); + if (FWINV(dst < info->dport[0] || + dst > info->dport[1], EBT_IP6_DPORT)) + return EBT_NOMATCH; + } + if (info->bitmask & EBT_IP6_SPORT) { + u32 src = ntohs(pptr->src); + if (FWINV(src < info->sport[0] || + src > info->sport[1], EBT_IP6_SPORT)) + return EBT_NOMATCH; + } + return EBT_MATCH; + } + return EBT_MATCH; +} + +static int ebt_ip6_check(const char *tablename, unsigned int hookmask, + const struct ebt_entry *e, void *data, unsigned int datalen) +{ + struct ebt_ip6_info *info = (struct ebt_ip6_info *)data; + + if (datalen != EBT_ALIGN(sizeof(struct ebt_ip6_info))) + return -EINVAL; + if (e->ethproto != htons(ETH_P_IPV6) || e->invflags & EBT_IPROTO) + return -EINVAL; + if (info->bitmask & ~EBT_IP6_MASK || info->invflags & ~EBT_IP6_MASK) + return -EINVAL; + if (info->bitmask & (EBT_IP6_DPORT | EBT_IP6_SPORT)) { + if (info->invflags & EBT_IP6_PROTO) + return -EINVAL; + if (info->protocol != IPPROTO_TCP && + info->protocol != IPPROTO_UDP && + info->protocol != IPPROTO_UDPLITE && + info->protocol != IPPROTO_SCTP && + info->protocol != IPPROTO_DCCP) + return -EINVAL; + } + if (info->bitmask & EBT_IP6_DPORT && info->dport[0] > info->dport[1]) + return -EINVAL; + if (info->bitmask & EBT_IP6_SPORT && info->sport[0] > info->sport[1]) + return -EINVAL; + return 0; +} + +static struct ebt_match filter_ip6 = +{ + .name = EBT_IP6_MATCH, + .match = ebt_filter_ip6, + .check = ebt_ip6_check, + .me = THIS_MODULE, +}; + +static int __init ebt_ip6_init(void) +{ + return ebt_register_match(&filter_ip6); +} + +static void __exit ebt_ip6_fini(void) +{ + ebt_unregister_match(&filter_ip6); +} + +module_init(ebt_ip6_init); +module_exit(ebt_ip6_fini); +MODULE_DESCRIPTION("Ebtables: IPv6 protocol packet match"); +MODULE_LICENSE("GPL"); diff --git a/net/bridge/netfilter/ebt_log.c b/net/bridge/netfilter/ebt_log.c index 0b209e4aad0a..2f430d4ae911 100644 --- a/net/bridge/netfilter/ebt_log.c +++ b/net/bridge/netfilter/ebt_log.c @@ -18,6 +18,9 @@ #include <linux/if_arp.h> #include <linux/spinlock.h> #include <net/netfilter/nf_log.h> +#include <linux/ipv6.h> +#include <net/ipv6.h> +#include <linux/in6.h> static DEFINE_SPINLOCK(ebt_log_lock); @@ -58,6 +61,27 @@ static void print_MAC(const unsigned char *p) printk("%02x%c", *p, i == ETH_ALEN - 1 ? ' ':':'); } +static void +print_ports(const struct sk_buff *skb, uint8_t protocol, int offset) +{ + if (protocol == IPPROTO_TCP || + protocol == IPPROTO_UDP || + protocol == IPPROTO_UDPLITE || + protocol == IPPROTO_SCTP || + protocol == IPPROTO_DCCP) { + const struct tcpudphdr *pptr; + struct tcpudphdr _ports; + + pptr = skb_header_pointer(skb, offset, + sizeof(_ports), &_ports); + if (pptr == NULL) { + printk(" INCOMPLETE TCP/UDP header"); + return; + } + printk(" SPT=%u DPT=%u", ntohs(pptr->src), ntohs(pptr->dst)); + } +} + #define myNIPQUAD(a) a[0], a[1], a[2], a[3] static void ebt_log_packet(unsigned int pf, unsigned int hooknum, @@ -95,25 +119,35 @@ ebt_log_packet(unsigned int pf, unsigned int hooknum, printk(" IP SRC=%u.%u.%u.%u IP DST=%u.%u.%u.%u, IP " "tos=0x%02X, IP proto=%d", NIPQUAD(ih->saddr), NIPQUAD(ih->daddr), ih->tos, ih->protocol); - if (ih->protocol == IPPROTO_TCP || - ih->protocol == IPPROTO_UDP || - ih->protocol == IPPROTO_UDPLITE || - ih->protocol == IPPROTO_SCTP || - ih->protocol == IPPROTO_DCCP) { - const struct tcpudphdr *pptr; - struct tcpudphdr _ports; - - pptr = skb_header_pointer(skb, ih->ihl*4, - sizeof(_ports), &_ports); - if (pptr == NULL) { - printk(" INCOMPLETE TCP/UDP header"); - goto out; - } - printk(" SPT=%u DPT=%u", ntohs(pptr->src), - ntohs(pptr->dst)); + print_ports(skb, ih->protocol, ih->ihl*4); + goto out; + } + +#if defined(CONFIG_BRIDGE_EBT_IP6) || defined(CONFIG_BRIDGE_EBT_IP6_MODULE) + if ((bitmask & EBT_LOG_IP6) && eth_hdr(skb)->h_proto == + htons(ETH_P_IPV6)) { + const struct ipv6hdr *ih; + struct ipv6hdr _iph; + uint8_t nexthdr; + int offset_ph; + + ih = skb_header_pointer(skb, 0, sizeof(_iph), &_iph); + if (ih == NULL) { + printk(" INCOMPLETE IPv6 header"); + goto out; } + printk(" IPv6 SRC=%x:%x:%x:%x:%x:%x:%x:%x " + "IPv6 DST=%x:%x:%x:%x:%x:%x:%x:%x, IPv6 " + "priority=0x%01X, Next Header=%d", NIP6(ih->saddr), + NIP6(ih->daddr), ih->priority, ih->nexthdr); + nexthdr = ih->nexthdr; + offset_ph = ipv6_skip_exthdr(skb, sizeof(_iph), &nexthdr); + if (offset_ph == -1) + goto out; + print_ports(skb, nexthdr, offset_ph); goto out; } +#endif if ((bitmask & EBT_LOG_ARP) && ((eth_hdr(skb)->h_proto == htons(ETH_P_ARP)) || diff --git a/net/can/af_can.c b/net/can/af_can.c index 484bbf6dd032..8035fbf526ae 100644 --- a/net/can/af_can.c +++ b/net/can/af_can.c @@ -615,7 +615,7 @@ static int can_rcv(struct sk_buff *skb, struct net_device *dev, struct can_frame *cf = (struct can_frame *)skb->data; int matches; - if (dev->type != ARPHRD_CAN || dev_net(dev) != &init_net) { + if (dev->type != ARPHRD_CAN || !net_eq(dev_net(dev), &init_net)) { kfree_skb(skb); return 0; } @@ -728,7 +728,7 @@ static int can_notifier(struct notifier_block *nb, unsigned long msg, struct net_device *dev = (struct net_device *)data; struct dev_rcv_lists *d; - if (dev_net(dev) != &init_net) + if (!net_eq(dev_net(dev), &init_net)) return NOTIFY_DONE; if (dev->type != ARPHRD_CAN) diff --git a/net/can/bcm.c b/net/can/bcm.c index 72c2ce904f83..d0dd382001e2 100644 --- a/net/can/bcm.c +++ b/net/can/bcm.c @@ -1303,7 +1303,7 @@ static int bcm_notifier(struct notifier_block *nb, unsigned long msg, struct bcm_op *op; int notify_enodev = 0; - if (dev_net(dev) != &init_net) + if (!net_eq(dev_net(dev), &init_net)) return NOTIFY_DONE; if (dev->type != ARPHRD_CAN) diff --git a/net/can/raw.c b/net/can/raw.c index 3e46ee36a1aa..6e0663faaf9f 100644 --- a/net/can/raw.c +++ b/net/can/raw.c @@ -210,7 +210,7 @@ static int raw_notifier(struct notifier_block *nb, struct raw_sock *ro = container_of(nb, struct raw_sock, notifier); struct sock *sk = &ro->sk; - if (dev_net(dev) != &init_net) + if (!net_eq(dev_net(dev), &init_net)) return NOTIFY_DONE; if (dev->type != ARPHRD_CAN) diff --git a/net/compat.c b/net/compat.c index c823f6f290cb..6e1b03b51933 100644 --- a/net/compat.c +++ b/net/compat.c @@ -75,7 +75,7 @@ int get_compat_msghdr(struct msghdr *kmsg, struct compat_msghdr __user *umsg) /* I've named the args so it is easy to tell whose space the pointers are in. */ int verify_compat_iovec(struct msghdr *kern_msg, struct iovec *kern_iov, - char *kern_address, int mode) + struct sockaddr *kern_address, int mode) { int tot_len; diff --git a/net/core/dev.c b/net/core/dev.c index 821cb1628e5e..2eed17bcb2dd 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -90,6 +90,7 @@ #include <linux/if_ether.h> #include <linux/netdevice.h> #include <linux/etherdevice.h> +#include <linux/ethtool.h> #include <linux/notifier.h> #include <linux/skbuff.h> #include <net/net_namespace.h> @@ -120,6 +121,9 @@ #include <linux/ctype.h> #include <linux/if_arp.h> #include <linux/if_vlan.h> +#include <linux/ip.h> +#include <linux/ipv6.h> +#include <linux/in.h> #include "net-sysfs.h" @@ -257,7 +261,7 @@ DEFINE_PER_CPU(struct softnet_data, softnet_data); #ifdef CONFIG_DEBUG_LOCK_ALLOC /* - * register_netdevice() inits dev->_xmit_lock and sets lockdep class + * register_netdevice() inits txq->_xmit_lock and sets lockdep class * according to dev->type */ static const unsigned short netdev_lock_type[] = @@ -961,6 +965,12 @@ void netdev_state_change(struct net_device *dev) } } +void netdev_bonding_change(struct net_device *dev) +{ + call_netdevice_notifiers(NETDEV_BONDING_FAILOVER, dev); +} +EXPORT_SYMBOL(netdev_bonding_change); + /** * dev_load - load a network module * @net: the applicable net namespace @@ -1117,6 +1127,29 @@ int dev_close(struct net_device *dev) } +/** + * dev_disable_lro - disable Large Receive Offload on a device + * @dev: device + * + * Disable Large Receive Offload (LRO) on a net device. Must be + * called under RTNL. This is needed if received packets may be + * forwarded to another interface. + */ +void dev_disable_lro(struct net_device *dev) +{ + if (dev->ethtool_ops && dev->ethtool_ops->get_flags && + dev->ethtool_ops->set_flags) { + u32 flags = dev->ethtool_ops->get_flags(dev); + if (flags & ETH_FLAG_LRO) { + flags &= ~ETH_FLAG_LRO; + dev->ethtool_ops->set_flags(dev, flags); + } + } + WARN_ON(dev->features & NETIF_F_LRO); +} +EXPORT_SYMBOL(dev_disable_lro); + + static int dev_boot_phase = 1; /* @@ -1290,16 +1323,18 @@ static void dev_queue_xmit_nit(struct sk_buff *skb, struct net_device *dev) } -void __netif_schedule(struct net_device *dev) +void __netif_schedule(struct Qdisc *q) { - if (!test_and_set_bit(__LINK_STATE_SCHED, &dev->state)) { - unsigned long flags; + BUG_ON(q == &noop_qdisc); + + if (!test_and_set_bit(__QDISC_STATE_SCHED, &q->state)) { struct softnet_data *sd; + unsigned long flags; local_irq_save(flags); sd = &__get_cpu_var(softnet_data); - dev->next_sched = sd->output_queue; - sd->output_queue = dev; + q->next_sched = sd->output_queue; + sd->output_queue = q; raise_softirq_irqoff(NET_TX_SOFTIRQ); local_irq_restore(flags); } @@ -1566,7 +1601,8 @@ static int dev_gso_segment(struct sk_buff *skb) return 0; } -int dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) +int dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev, + struct netdev_queue *txq) { if (likely(!skb->next)) { if (!list_empty(&ptype_all)) @@ -1595,9 +1631,7 @@ gso: skb->next = nskb; return rc; } - if (unlikely((netif_queue_stopped(dev) || - netif_subqueue_stopped(dev, skb)) && - skb->next)) + if (unlikely(netif_tx_queue_stopped(txq) && skb->next)) return NETDEV_TX_BUSY; } while (skb->next); @@ -1634,9 +1668,71 @@ out_kfree_skb: * --BLG */ +static u16 simple_tx_hash(struct net_device *dev, struct sk_buff *skb) +{ + u32 *addr, *ports, hash, ihl; + u8 ip_proto; + int alen; + + switch (skb->protocol) { + case __constant_htons(ETH_P_IP): + ip_proto = ip_hdr(skb)->protocol; + addr = &ip_hdr(skb)->saddr; + ihl = ip_hdr(skb)->ihl; + alen = 2; + break; + case __constant_htons(ETH_P_IPV6): + ip_proto = ipv6_hdr(skb)->nexthdr; + addr = &ipv6_hdr(skb)->saddr.s6_addr32[0]; + ihl = (40 >> 2); + alen = 8; + break; + default: + return 0; + } + + ports = (u32 *) (skb_network_header(skb) + (ihl * 4)); + + hash = 0; + while (alen--) + hash ^= *addr++; + + switch (ip_proto) { + case IPPROTO_TCP: + case IPPROTO_UDP: + case IPPROTO_DCCP: + case IPPROTO_ESP: + case IPPROTO_AH: + case IPPROTO_SCTP: + case IPPROTO_UDPLITE: + hash ^= *ports; + break; + + default: + break; + } + + return hash % dev->real_num_tx_queues; +} + +static struct netdev_queue *dev_pick_tx(struct net_device *dev, + struct sk_buff *skb) +{ + u16 queue_index = 0; + + if (dev->select_queue) + queue_index = dev->select_queue(dev, skb); + else if (dev->real_num_tx_queues > 1) + queue_index = simple_tx_hash(dev, skb); + + skb_set_queue_mapping(skb, queue_index); + return netdev_get_tx_queue(dev, queue_index); +} + int dev_queue_xmit(struct sk_buff *skb) { struct net_device *dev = skb->dev; + struct netdev_queue *txq; struct Qdisc *q; int rc = -ENOMEM; @@ -1669,44 +1765,29 @@ int dev_queue_xmit(struct sk_buff *skb) } gso: - spin_lock_prefetch(&dev->queue_lock); - /* Disable soft irqs for various locks below. Also * stops preemption for RCU. */ rcu_read_lock_bh(); - /* Updates of qdisc are serialized by queue_lock. - * The struct Qdisc which is pointed to by qdisc is now a - * rcu structure - it may be accessed without acquiring - * a lock (but the structure may be stale.) The freeing of the - * qdisc will be deferred until it's known that there are no - * more references to it. - * - * If the qdisc has an enqueue function, we still need to - * hold the queue_lock before calling it, since queue_lock - * also serializes access to the device queue. - */ + txq = dev_pick_tx(dev, skb); + q = rcu_dereference(txq->qdisc); - q = rcu_dereference(dev->qdisc); #ifdef CONFIG_NET_CLS_ACT skb->tc_verd = SET_TC_AT(skb->tc_verd,AT_EGRESS); #endif if (q->enqueue) { - /* Grab device queue */ - spin_lock(&dev->queue_lock); - q = dev->qdisc; - if (q->enqueue) { - /* reset queue_mapping to zero */ - skb_set_queue_mapping(skb, 0); - rc = q->enqueue(skb, q); - qdisc_run(dev); - spin_unlock(&dev->queue_lock); - - rc = rc == NET_XMIT_BYPASS ? NET_XMIT_SUCCESS : rc; - goto out; - } - spin_unlock(&dev->queue_lock); + spinlock_t *root_lock = qdisc_root_lock(q); + + spin_lock(root_lock); + + rc = qdisc_enqueue_root(skb, q); + qdisc_run(q); + + spin_unlock(root_lock); + + rc = rc == NET_XMIT_BYPASS ? NET_XMIT_SUCCESS : rc; + goto out; } /* The device has no queue. Common case for software devices: @@ -1724,19 +1805,18 @@ gso: if (dev->flags & IFF_UP) { int cpu = smp_processor_id(); /* ok because BHs are off */ - if (dev->xmit_lock_owner != cpu) { + if (txq->xmit_lock_owner != cpu) { - HARD_TX_LOCK(dev, cpu); + HARD_TX_LOCK(dev, txq, cpu); - if (!netif_queue_stopped(dev) && - !netif_subqueue_stopped(dev, skb)) { + if (!netif_tx_queue_stopped(txq)) { rc = 0; - if (!dev_hard_start_xmit(skb, dev)) { - HARD_TX_UNLOCK(dev); + if (!dev_hard_start_xmit(skb, dev, txq)) { + HARD_TX_UNLOCK(dev, txq); goto out; } } - HARD_TX_UNLOCK(dev); + HARD_TX_UNLOCK(dev, txq); if (net_ratelimit()) printk(KERN_CRIT "Virtual device %s asks to " "queue packet!\n", dev->name); @@ -1880,7 +1960,7 @@ static void net_tx_action(struct softirq_action *h) } if (sd->output_queue) { - struct net_device *head; + struct Qdisc *head; local_irq_disable(); head = sd->output_queue; @@ -1888,17 +1968,20 @@ static void net_tx_action(struct softirq_action *h) local_irq_enable(); while (head) { - struct net_device *dev = head; + struct Qdisc *q = head; + spinlock_t *root_lock; + head = head->next_sched; smp_mb__before_clear_bit(); - clear_bit(__LINK_STATE_SCHED, &dev->state); + clear_bit(__QDISC_STATE_SCHED, &q->state); - if (spin_trylock(&dev->queue_lock)) { - qdisc_run(dev); - spin_unlock(&dev->queue_lock); + root_lock = qdisc_root_lock(q); + if (spin_trylock(root_lock)) { + qdisc_run(q); + spin_unlock(root_lock); } else { - netif_schedule(dev); + __netif_schedule(q); } } } @@ -1979,10 +2062,11 @@ static inline struct sk_buff *handle_macvlan(struct sk_buff *skb, */ static int ing_filter(struct sk_buff *skb) { - struct Qdisc *q; struct net_device *dev = skb->dev; - int result = TC_ACT_OK; u32 ttl = G_TC_RTTL(skb->tc_verd); + struct netdev_queue *rxq; + int result = TC_ACT_OK; + struct Qdisc *q; if (MAX_RED_LOOP < ttl++) { printk(KERN_WARNING @@ -1994,10 +2078,14 @@ static int ing_filter(struct sk_buff *skb) skb->tc_verd = SET_TC_RTTL(skb->tc_verd, ttl); skb->tc_verd = SET_TC_AT(skb->tc_verd, AT_INGRESS); - spin_lock(&dev->ingress_lock); - if ((q = dev->qdisc_ingress) != NULL) - result = q->enqueue(skb, q); - spin_unlock(&dev->ingress_lock); + rxq = &dev->rx_queue; + + q = rxq->qdisc; + if (q) { + spin_lock(qdisc_lock(q)); + result = qdisc_enqueue_root(skb, q); + spin_unlock(qdisc_lock(q)); + } return result; } @@ -2006,7 +2094,7 @@ static inline struct sk_buff *handle_ing(struct sk_buff *skb, struct packet_type **pt_prev, int *ret, struct net_device *orig_dev) { - if (!skb->dev->qdisc_ingress) + if (!skb->dev->rx_queue.qdisc) goto out; if (*pt_prev) { @@ -2030,6 +2118,33 @@ out: } #endif +/* + * netif_nit_deliver - deliver received packets to network taps + * @skb: buffer + * + * This function is used to deliver incoming packets to network + * taps. It should be used when the normal netif_receive_skb path + * is bypassed, for example because of VLAN acceleration. + */ +void netif_nit_deliver(struct sk_buff *skb) +{ + struct packet_type *ptype; + + if (list_empty(&ptype_all)) + return; + + skb_reset_network_header(skb); + skb_reset_transport_header(skb); + skb->mac_len = skb->network_header - skb->mac_header; + + rcu_read_lock(); + list_for_each_entry_rcu(ptype, &ptype_all, list) { + if (!ptype->dev || ptype->dev == skb->dev) + deliver_skb(skb, ptype, skb->dev); + } + rcu_read_unlock(); +} + /** * netif_receive_skb - process receive buffer from network * @skb: buffer to process @@ -2769,16 +2884,29 @@ int netdev_set_master(struct net_device *slave, struct net_device *master) return 0; } -static void __dev_set_promiscuity(struct net_device *dev, int inc) +static int __dev_set_promiscuity(struct net_device *dev, int inc) { unsigned short old_flags = dev->flags; ASSERT_RTNL(); - if ((dev->promiscuity += inc) == 0) - dev->flags &= ~IFF_PROMISC; - else - dev->flags |= IFF_PROMISC; + dev->flags |= IFF_PROMISC; + dev->promiscuity += inc; + if (dev->promiscuity == 0) { + /* + * Avoid overflow. + * If inc causes overflow, untouch promisc and return error. + */ + if (inc < 0) + dev->flags &= ~IFF_PROMISC; + else { + dev->promiscuity -= inc; + printk(KERN_WARNING "%s: promiscuity touches roof, " + "set promiscuity failed, promiscuity feature " + "of device might be broken.\n", dev->name); + return -EOVERFLOW; + } + } if (dev->flags != old_flags) { printk(KERN_INFO "device %s %s promiscuous mode\n", dev->name, (dev->flags & IFF_PROMISC) ? "entered" : @@ -2796,6 +2924,7 @@ static void __dev_set_promiscuity(struct net_device *dev, int inc) if (dev->change_rx_flags) dev->change_rx_flags(dev, IFF_PROMISC); } + return 0; } /** @@ -2807,14 +2936,19 @@ static void __dev_set_promiscuity(struct net_device *dev, int inc) * remains above zero the interface remains promiscuous. Once it hits zero * the device reverts back to normal filtering operation. A negative inc * value is used to drop promiscuity on the device. + * Return 0 if successful or a negative errno code on error. */ -void dev_set_promiscuity(struct net_device *dev, int inc) +int dev_set_promiscuity(struct net_device *dev, int inc) { unsigned short old_flags = dev->flags; + int err; - __dev_set_promiscuity(dev, inc); + err = __dev_set_promiscuity(dev, inc); + if (err < 0) + return err; if (dev->flags != old_flags) dev_set_rx_mode(dev); + return err; } /** @@ -2827,22 +2961,38 @@ void dev_set_promiscuity(struct net_device *dev, int inc) * to all interfaces. Once it hits zero the device reverts back to normal * filtering operation. A negative @inc value is used to drop the counter * when releasing a resource needing all multicasts. + * Return 0 if successful or a negative errno code on error. */ -void dev_set_allmulti(struct net_device *dev, int inc) +int dev_set_allmulti(struct net_device *dev, int inc) { unsigned short old_flags = dev->flags; ASSERT_RTNL(); dev->flags |= IFF_ALLMULTI; - if ((dev->allmulti += inc) == 0) - dev->flags &= ~IFF_ALLMULTI; + dev->allmulti += inc; + if (dev->allmulti == 0) { + /* + * Avoid overflow. + * If inc causes overflow, untouch allmulti and return error. + */ + if (inc < 0) + dev->flags &= ~IFF_ALLMULTI; + else { + dev->allmulti -= inc; + printk(KERN_WARNING "%s: allmulti touches roof, " + "set allmulti failed, allmulti feature of " + "device might be broken.\n", dev->name); + return -EOVERFLOW; + } + } if (dev->flags ^ old_flags) { if (dev->change_rx_flags) dev->change_rx_flags(dev, IFF_ALLMULTI); dev_set_rx_mode(dev); } + return 0; } /* @@ -2881,9 +3031,9 @@ void __dev_set_rx_mode(struct net_device *dev) void dev_set_rx_mode(struct net_device *dev) { - netif_tx_lock_bh(dev); + netif_addr_lock_bh(dev); __dev_set_rx_mode(dev); - netif_tx_unlock_bh(dev); + netif_addr_unlock_bh(dev); } int __dev_addr_delete(struct dev_addr_list **list, int *count, @@ -2961,11 +3111,11 @@ int dev_unicast_delete(struct net_device *dev, void *addr, int alen) ASSERT_RTNL(); - netif_tx_lock_bh(dev); + netif_addr_lock_bh(dev); err = __dev_addr_delete(&dev->uc_list, &dev->uc_count, addr, alen, 0); if (!err) __dev_set_rx_mode(dev); - netif_tx_unlock_bh(dev); + netif_addr_unlock_bh(dev); return err; } EXPORT_SYMBOL(dev_unicast_delete); @@ -2987,11 +3137,11 @@ int dev_unicast_add(struct net_device *dev, void *addr, int alen) ASSERT_RTNL(); - netif_tx_lock_bh(dev); + netif_addr_lock_bh(dev); err = __dev_addr_add(&dev->uc_list, &dev->uc_count, addr, alen, 0); if (!err) __dev_set_rx_mode(dev); - netif_tx_unlock_bh(dev); + netif_addr_unlock_bh(dev); return err; } EXPORT_SYMBOL(dev_unicast_add); @@ -3058,12 +3208,12 @@ int dev_unicast_sync(struct net_device *to, struct net_device *from) { int err = 0; - netif_tx_lock_bh(to); + netif_addr_lock_bh(to); err = __dev_addr_sync(&to->uc_list, &to->uc_count, &from->uc_list, &from->uc_count); if (!err) __dev_set_rx_mode(to); - netif_tx_unlock_bh(to); + netif_addr_unlock_bh(to); return err; } EXPORT_SYMBOL(dev_unicast_sync); @@ -3079,15 +3229,15 @@ EXPORT_SYMBOL(dev_unicast_sync); */ void dev_unicast_unsync(struct net_device *to, struct net_device *from) { - netif_tx_lock_bh(from); - netif_tx_lock_bh(to); + netif_addr_lock_bh(from); + netif_addr_lock(to); __dev_addr_unsync(&to->uc_list, &to->uc_count, &from->uc_list, &from->uc_count); __dev_set_rx_mode(to); - netif_tx_unlock_bh(to); - netif_tx_unlock_bh(from); + netif_addr_unlock(to); + netif_addr_unlock_bh(from); } EXPORT_SYMBOL(dev_unicast_unsync); @@ -3107,7 +3257,7 @@ static void __dev_addr_discard(struct dev_addr_list **list) static void dev_addr_discard(struct net_device *dev) { - netif_tx_lock_bh(dev); + netif_addr_lock_bh(dev); __dev_addr_discard(&dev->uc_list); dev->uc_count = 0; @@ -3115,7 +3265,7 @@ static void dev_addr_discard(struct net_device *dev) __dev_addr_discard(&dev->mc_list); dev->mc_count = 0; - netif_tx_unlock_bh(dev); + netif_addr_unlock_bh(dev); } unsigned dev_get_flags(const struct net_device *dev) @@ -3688,6 +3838,21 @@ static void rollback_registered(struct net_device *dev) dev_put(dev); } +static void __netdev_init_queue_locks_one(struct net_device *dev, + struct netdev_queue *dev_queue, + void *_unused) +{ + spin_lock_init(&dev_queue->_xmit_lock); + netdev_set_lockdep_class(&dev_queue->_xmit_lock, dev->type); + dev_queue->xmit_lock_owner = -1; +} + +static void netdev_init_queue_locks(struct net_device *dev) +{ + netdev_for_each_tx_queue(dev, __netdev_init_queue_locks_one, NULL); + __netdev_init_queue_locks_one(dev, &dev->rx_queue, NULL); +} + /** * register_netdevice - register a network device * @dev: device to register @@ -3722,11 +3887,8 @@ int register_netdevice(struct net_device *dev) BUG_ON(!dev_net(dev)); net = dev_net(dev); - spin_lock_init(&dev->queue_lock); - spin_lock_init(&dev->_xmit_lock); - netdev_set_lockdep_class(&dev->_xmit_lock, dev->type); - dev->xmit_lock_owner = -1; - spin_lock_init(&dev->ingress_lock); + spin_lock_init(&dev->addr_list_lock); + netdev_init_queue_locks(dev); dev->iflink = -1; @@ -4007,6 +4169,19 @@ static struct net_device_stats *internal_stats(struct net_device *dev) return &dev->stats; } +static void netdev_init_one_queue(struct net_device *dev, + struct netdev_queue *queue, + void *_unused) +{ + queue->dev = dev; +} + +static void netdev_init_queues(struct net_device *dev) +{ + netdev_init_one_queue(dev, &dev->rx_queue, NULL); + netdev_for_each_tx_queue(dev, netdev_init_one_queue, NULL); +} + /** * alloc_netdev_mq - allocate network device * @sizeof_priv: size of private data to allocate space for @@ -4021,14 +4196,14 @@ static struct net_device_stats *internal_stats(struct net_device *dev) struct net_device *alloc_netdev_mq(int sizeof_priv, const char *name, void (*setup)(struct net_device *), unsigned int queue_count) { - void *p; + struct netdev_queue *tx; struct net_device *dev; int alloc_size; + void *p; BUG_ON(strlen(name) >= sizeof(dev->name)); - alloc_size = sizeof(struct net_device) + - sizeof(struct net_device_subqueue) * (queue_count - 1); + 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; @@ -4043,22 +4218,33 @@ struct net_device *alloc_netdev_mq(int sizeof_priv, const char *name, return NULL; } + tx = kzalloc(sizeof(struct netdev_queue) * queue_count, GFP_KERNEL); + if (!tx) { + printk(KERN_ERR "alloc_netdev: Unable to allocate " + "tx qdiscs.\n"); + kfree(p); + return NULL; + } + dev = (struct net_device *) (((long)p + NETDEV_ALIGN_CONST) & ~NETDEV_ALIGN_CONST); dev->padded = (char *)dev - (char *)p; dev_net_set(dev, &init_net); + dev->_tx = tx; + dev->num_tx_queues = queue_count; + dev->real_num_tx_queues = queue_count; + if (sizeof_priv) { dev->priv = ((char *)dev + - ((sizeof(struct net_device) + - (sizeof(struct net_device_subqueue) * - (queue_count - 1)) + NETDEV_ALIGN_CONST) + ((sizeof(struct net_device) + NETDEV_ALIGN_CONST) & ~NETDEV_ALIGN_CONST)); } - dev->egress_subqueue_count = queue_count; dev->gso_max_size = GSO_MAX_SIZE; + netdev_init_queues(dev); + dev->get_stats = internal_stats; netpoll_netdev_init(dev); setup(dev); @@ -4079,6 +4265,8 @@ void free_netdev(struct net_device *dev) { release_net(dev_net(dev)); + kfree(dev->_tx); + /* Compatibility with error handling in drivers */ if (dev->reg_state == NETREG_UNINITIALIZED) { kfree((char *)dev - dev->padded); @@ -4260,7 +4448,7 @@ static int dev_cpu_callback(struct notifier_block *nfb, void *ocpu) { struct sk_buff **list_skb; - struct net_device **list_net; + struct Qdisc **list_net; struct sk_buff *skb; unsigned int cpu, oldcpu = (unsigned long)ocpu; struct softnet_data *sd, *oldsd; diff --git a/net/core/dev_mcast.c b/net/core/dev_mcast.c index f8a3455f4493..5402b3b38e0d 100644 --- a/net/core/dev_mcast.c +++ b/net/core/dev_mcast.c @@ -72,7 +72,7 @@ int dev_mc_delete(struct net_device *dev, void *addr, int alen, int glbl) { int err; - netif_tx_lock_bh(dev); + netif_addr_lock_bh(dev); err = __dev_addr_delete(&dev->mc_list, &dev->mc_count, addr, alen, glbl); if (!err) { @@ -83,7 +83,7 @@ int dev_mc_delete(struct net_device *dev, void *addr, int alen, int glbl) __dev_set_rx_mode(dev); } - netif_tx_unlock_bh(dev); + netif_addr_unlock_bh(dev); return err; } @@ -95,11 +95,11 @@ int dev_mc_add(struct net_device *dev, void *addr, int alen, int glbl) { int err; - netif_tx_lock_bh(dev); + netif_addr_lock_bh(dev); err = __dev_addr_add(&dev->mc_list, &dev->mc_count, addr, alen, glbl); if (!err) __dev_set_rx_mode(dev); - netif_tx_unlock_bh(dev); + netif_addr_unlock_bh(dev); return err; } @@ -119,12 +119,12 @@ int dev_mc_sync(struct net_device *to, struct net_device *from) { int err = 0; - netif_tx_lock_bh(to); + netif_addr_lock_bh(to); err = __dev_addr_sync(&to->mc_list, &to->mc_count, &from->mc_list, &from->mc_count); if (!err) __dev_set_rx_mode(to); - netif_tx_unlock_bh(to); + netif_addr_unlock_bh(to); return err; } @@ -143,15 +143,15 @@ EXPORT_SYMBOL(dev_mc_sync); */ void dev_mc_unsync(struct net_device *to, struct net_device *from) { - netif_tx_lock_bh(from); - netif_tx_lock_bh(to); + netif_addr_lock_bh(from); + netif_addr_lock(to); __dev_addr_unsync(&to->mc_list, &to->mc_count, &from->mc_list, &from->mc_count); __dev_set_rx_mode(to); - netif_tx_unlock_bh(to); - netif_tx_unlock_bh(from); + netif_addr_unlock(to); + netif_addr_unlock_bh(from); } EXPORT_SYMBOL(dev_mc_unsync); @@ -164,7 +164,7 @@ static int dev_mc_seq_show(struct seq_file *seq, void *v) if (v == SEQ_START_TOKEN) return 0; - netif_tx_lock_bh(dev); + netif_addr_lock_bh(dev); for (m = dev->mc_list; m; m = m->next) { int i; @@ -176,7 +176,7 @@ static int dev_mc_seq_show(struct seq_file *seq, void *v) seq_putc(seq, '\n'); } - netif_tx_unlock_bh(dev); + netif_addr_unlock_bh(dev); return 0; } diff --git a/net/core/ethtool.c b/net/core/ethtool.c index 0133b5ebd545..14ada537f895 100644 --- a/net/core/ethtool.c +++ b/net/core/ethtool.c @@ -209,6 +209,36 @@ static int ethtool_get_drvinfo(struct net_device *dev, void __user *useraddr) return 0; } +static int ethtool_set_rxhash(struct net_device *dev, void __user *useraddr) +{ + struct ethtool_rxnfc cmd; + + if (!dev->ethtool_ops->set_rxhash) + return -EOPNOTSUPP; + + if (copy_from_user(&cmd, useraddr, sizeof(cmd))) + return -EFAULT; + + return dev->ethtool_ops->set_rxhash(dev, &cmd); +} + +static int ethtool_get_rxhash(struct net_device *dev, void __user *useraddr) +{ + struct ethtool_rxnfc info; + + if (!dev->ethtool_ops->get_rxhash) + return -EOPNOTSUPP; + + if (copy_from_user(&info, useraddr, sizeof(info))) + return -EFAULT; + + dev->ethtool_ops->get_rxhash(dev, &info); + + if (copy_to_user(useraddr, &info, sizeof(info))) + return -EFAULT; + return 0; +} + static int ethtool_get_regs(struct net_device *dev, char __user *useraddr) { struct ethtool_regs regs; @@ -826,6 +856,7 @@ int dev_ethtool(struct net *net, struct ifreq *ifr) case ETHTOOL_GGSO: case ETHTOOL_GFLAGS: case ETHTOOL_GPFLAGS: + case ETHTOOL_GRXFH: break; default: if (!capable(CAP_NET_ADMIN)) @@ -977,6 +1008,12 @@ int dev_ethtool(struct net *net, struct ifreq *ifr) rc = ethtool_set_value(dev, useraddr, dev->ethtool_ops->set_priv_flags); break; + case ETHTOOL_GRXFH: + rc = ethtool_get_rxhash(dev, useraddr); + break; + case ETHTOOL_SRXFH: + rc = ethtool_set_rxhash(dev, useraddr); + break; default: rc = -EOPNOTSUPP; } diff --git a/net/core/fib_rules.c b/net/core/fib_rules.c index 277a2302eb3a..79de3b14a8d1 100644 --- a/net/core/fib_rules.c +++ b/net/core/fib_rules.c @@ -69,7 +69,7 @@ static void rules_ops_put(struct fib_rules_ops *ops) static void flush_route_cache(struct fib_rules_ops *ops) { if (ops->flush_cache) - ops->flush_cache(); + ops->flush_cache(ops); } int fib_rules_register(struct fib_rules_ops *ops) diff --git a/net/core/iovec.c b/net/core/iovec.c index 755c37fdaee7..4c9c0121c9da 100644 --- a/net/core/iovec.c +++ b/net/core/iovec.c @@ -36,7 +36,7 @@ * in any case. */ -int verify_iovec(struct msghdr *m, struct iovec *iov, char *address, int mode) +int verify_iovec(struct msghdr *m, struct iovec *iov, struct sockaddr *address, int mode) { int size, err, ct; diff --git a/net/core/link_watch.c b/net/core/link_watch.c index a5e372b9ec4d..bf8f7af699d7 100644 --- a/net/core/link_watch.c +++ b/net/core/link_watch.c @@ -77,10 +77,10 @@ static void rfc2863_policy(struct net_device *dev) } -static int linkwatch_urgent_event(struct net_device *dev) +static bool linkwatch_urgent_event(struct net_device *dev) { return netif_running(dev) && netif_carrier_ok(dev) && - dev->qdisc != dev->qdisc_sleeping; + qdisc_tx_changing(dev); } @@ -180,10 +180,9 @@ static void __linkwatch_run_queue(int urgent_only) rfc2863_policy(dev); if (dev->flags & IFF_UP) { - if (netif_carrier_ok(dev)) { - WARN_ON(dev->qdisc_sleeping == &noop_qdisc); + if (netif_carrier_ok(dev)) dev_activate(dev); - } else + else dev_deactivate(dev); netdev_state_change(dev); @@ -214,7 +213,7 @@ static void linkwatch_event(struct work_struct *dummy) void linkwatch_fire_event(struct net_device *dev) { - int urgent = linkwatch_urgent_event(dev); + bool urgent = linkwatch_urgent_event(dev); if (!test_and_set_bit(__LINK_STATE_LINKWATCH_PENDING, &dev->state)) { dev_hold(dev); diff --git a/net/core/neighbour.c b/net/core/neighbour.c index 65f01f71b3f3..f62c8af85d38 100644 --- a/net/core/neighbour.c +++ b/net/core/neighbour.c @@ -930,6 +930,7 @@ int __neigh_event_send(struct neighbour *neigh, struct sk_buff *skb) buff = neigh->arp_queue.next; __skb_unlink(buff, &neigh->arp_queue); kfree_skb(buff); + NEIGH_CACHE_STAT_INC(neigh->tbl, unres_discards); } __skb_queue_tail(&neigh->arp_queue, skb); } @@ -2462,12 +2463,12 @@ static int neigh_stat_seq_show(struct seq_file *seq, void *v) struct neigh_statistics *st = v; if (v == SEQ_START_TOKEN) { - seq_printf(seq, "entries allocs destroys hash_grows lookups hits res_failed rcv_probes_mcast rcv_probes_ucast periodic_gc_runs forced_gc_runs\n"); + seq_printf(seq, "entries allocs destroys hash_grows lookups hits res_failed rcv_probes_mcast rcv_probes_ucast periodic_gc_runs forced_gc_runs unresolved_discards\n"); return 0; } seq_printf(seq, "%08x %08lx %08lx %08lx %08lx %08lx %08lx " - "%08lx %08lx %08lx %08lx\n", + "%08lx %08lx %08lx %08lx %08lx\n", atomic_read(&tbl->entries), st->allocs, @@ -2483,7 +2484,8 @@ static int neigh_stat_seq_show(struct seq_file *seq, void *v) st->rcv_probes_ucast, st->periodic_gc_runs, - st->forced_gc_runs + st->forced_gc_runs, + st->unres_discards ); return 0; diff --git a/net/core/net-sysfs.c b/net/core/net-sysfs.c index 90e2177af081..c1f4e0d428c0 100644 --- a/net/core/net-sysfs.c +++ b/net/core/net-sysfs.c @@ -242,11 +242,11 @@ static ssize_t netstat_show(const struct device *d, offset % sizeof(unsigned long) != 0); read_lock(&dev_base_lock); - if (dev_isalive(dev) && dev->get_stats && - (stats = (*dev->get_stats)(dev))) + if (dev_isalive(dev)) { + stats = dev->get_stats(dev); ret = sprintf(buf, fmt_ulong, *(unsigned long *)(((u8 *) stats) + offset)); - + } read_unlock(&dev_base_lock); return ret; } @@ -318,7 +318,7 @@ static struct attribute_group netstat_group = { .attrs = netstat_attrs, }; -#ifdef CONFIG_WIRELESS_EXT +#ifdef CONFIG_WIRELESS_EXT_SYSFS /* helper function that does all the locking etc for wireless stats */ static ssize_t wireless_show(struct device *d, char *buf, ssize_t (*format)(const struct iw_statistics *, @@ -457,10 +457,9 @@ int netdev_register_kobject(struct net_device *net) strlcpy(dev->bus_id, net->name, BUS_ID_SIZE); #ifdef CONFIG_SYSFS - if (net->get_stats) - *groups++ = &netstat_group; + *groups++ = &netstat_group; -#ifdef CONFIG_WIRELESS_EXT +#ifdef CONFIG_WIRELESS_EXT_SYSFS if (net->wireless_handlers && net->wireless_handlers->get_wireless_stats) *groups++ = &wireless_group; #endif @@ -469,6 +468,19 @@ int netdev_register_kobject(struct net_device *net) return device_add(dev); } +int netdev_class_create_file(struct class_attribute *class_attr) +{ + return class_create_file(&net_class, class_attr); +} + +void netdev_class_remove_file(struct class_attribute *class_attr) +{ + class_remove_file(&net_class, class_attr); +} + +EXPORT_SYMBOL(netdev_class_create_file); +EXPORT_SYMBOL(netdev_class_remove_file); + void netdev_initialize_kobject(struct net_device *net) { struct device *device = &(net->dev); diff --git a/net/core/netpoll.c b/net/core/netpoll.c index 8fb134da0346..c12720895ecf 100644 --- a/net/core/netpoll.c +++ b/net/core/netpoll.c @@ -58,25 +58,27 @@ static void queue_process(struct work_struct *work) while ((skb = skb_dequeue(&npinfo->txq))) { struct net_device *dev = skb->dev; + struct netdev_queue *txq; if (!netif_device_present(dev) || !netif_running(dev)) { __kfree_skb(skb); continue; } + txq = netdev_get_tx_queue(dev, skb_get_queue_mapping(skb)); + local_irq_save(flags); - netif_tx_lock(dev); - if ((netif_queue_stopped(dev) || - netif_subqueue_stopped(dev, skb)) || - dev->hard_start_xmit(skb, dev) != NETDEV_TX_OK) { + __netif_tx_lock(txq, smp_processor_id()); + if (netif_tx_queue_stopped(txq) || + dev->hard_start_xmit(skb, dev) != NETDEV_TX_OK) { skb_queue_head(&npinfo->txq, skb); - netif_tx_unlock(dev); + __netif_tx_unlock(txq); local_irq_restore(flags); schedule_delayed_work(&npinfo->tx_work, HZ/10); return; } - netif_tx_unlock(dev); + __netif_tx_unlock(txq); local_irq_restore(flags); } } @@ -278,17 +280,19 @@ static void netpoll_send_skb(struct netpoll *np, struct sk_buff *skb) /* don't get messages out of order, and no recursion */ if (skb_queue_len(&npinfo->txq) == 0 && !netpoll_owner_active(dev)) { + struct netdev_queue *txq; unsigned long flags; + txq = netdev_get_tx_queue(dev, skb_get_queue_mapping(skb)); + local_irq_save(flags); /* try until next clock tick */ for (tries = jiffies_to_usecs(1)/USEC_PER_POLL; tries > 0; --tries) { - if (netif_tx_trylock(dev)) { - if (!netif_queue_stopped(dev) && - !netif_subqueue_stopped(dev, skb)) + if (__netif_tx_trylock(txq)) { + if (!netif_tx_queue_stopped(txq)) status = dev->hard_start_xmit(skb, dev); - netif_tx_unlock(dev); + __netif_tx_unlock(txq); if (status == NETDEV_TX_OK) break; diff --git a/net/core/pktgen.c b/net/core/pktgen.c index fdf537707e51..c7d484f7e1c4 100644 --- a/net/core/pktgen.c +++ b/net/core/pktgen.c @@ -1875,7 +1875,7 @@ static int pktgen_device_event(struct notifier_block *unused, { struct net_device *dev = ptr; - if (dev_net(dev) != &init_net) + if (!net_eq(dev_net(dev), &init_net)) return NOTIFY_DONE; /* It is OK that we do not hold the group lock right now, @@ -2123,6 +2123,24 @@ static void get_ipsec_sa(struct pktgen_dev *pkt_dev, int flow) } } #endif +static void set_cur_queue_map(struct pktgen_dev *pkt_dev) +{ + if (pkt_dev->queue_map_min < pkt_dev->queue_map_max) { + __u16 t; + if (pkt_dev->flags & F_QUEUE_MAP_RND) { + t = random32() % + (pkt_dev->queue_map_max - + pkt_dev->queue_map_min + 1) + + pkt_dev->queue_map_min; + } else { + t = pkt_dev->cur_queue_map + 1; + if (t > pkt_dev->queue_map_max) + t = pkt_dev->queue_map_min; + } + pkt_dev->cur_queue_map = t; + } +} + /* Increment/randomize headers according to flags and current values * for IP src/dest, UDP src/dst port, MAC-Addr src/dst */ @@ -2325,19 +2343,7 @@ static void mod_cur_headers(struct pktgen_dev *pkt_dev) pkt_dev->cur_pkt_size = t; } - if (pkt_dev->queue_map_min < pkt_dev->queue_map_max) { - __u16 t; - if (pkt_dev->flags & F_QUEUE_MAP_RND) { - t = random32() % - (pkt_dev->queue_map_max - pkt_dev->queue_map_min + 1) - + pkt_dev->queue_map_min; - } else { - t = pkt_dev->cur_queue_map + 1; - if (t > pkt_dev->queue_map_max) - t = pkt_dev->queue_map_min; - } - pkt_dev->cur_queue_map = t; - } + set_cur_queue_map(pkt_dev); pkt_dev->flows[flow].count++; } @@ -2458,7 +2464,7 @@ static struct sk_buff *fill_packet_ipv4(struct net_device *odev, __be16 *vlan_encapsulated_proto = NULL; /* packet type ID field (or len) for VLAN tag */ __be16 *svlan_tci = NULL; /* Encapsulates priority and SVLAN ID */ __be16 *svlan_encapsulated_proto = NULL; /* packet type ID field (or len) for SVLAN tag */ - + u16 queue_map; if (pkt_dev->nr_labels) protocol = htons(ETH_P_MPLS_UC); @@ -2469,6 +2475,7 @@ static struct sk_buff *fill_packet_ipv4(struct net_device *odev, /* Update any of the values, used when we're incrementing various * fields. */ + queue_map = pkt_dev->cur_queue_map; mod_cur_headers(pkt_dev); datalen = (odev->hard_header_len + 16) & ~0xf; @@ -2507,7 +2514,7 @@ static struct sk_buff *fill_packet_ipv4(struct net_device *odev, skb->network_header = skb->tail; skb->transport_header = skb->network_header + sizeof(struct iphdr); skb_put(skb, sizeof(struct iphdr) + sizeof(struct udphdr)); - skb_set_queue_mapping(skb, pkt_dev->cur_queue_map); + skb_set_queue_mapping(skb, queue_map); iph = ip_hdr(skb); udph = udp_hdr(skb); @@ -2797,6 +2804,7 @@ static struct sk_buff *fill_packet_ipv6(struct net_device *odev, __be16 *vlan_encapsulated_proto = NULL; /* packet type ID field (or len) for VLAN tag */ __be16 *svlan_tci = NULL; /* Encapsulates priority and SVLAN ID */ __be16 *svlan_encapsulated_proto = NULL; /* packet type ID field (or len) for SVLAN tag */ + u16 queue_map; if (pkt_dev->nr_labels) protocol = htons(ETH_P_MPLS_UC); @@ -2807,6 +2815,7 @@ static struct sk_buff *fill_packet_ipv6(struct net_device *odev, /* Update any of the values, used when we're incrementing various * fields. */ + queue_map = pkt_dev->cur_queue_map; mod_cur_headers(pkt_dev); skb = alloc_skb(pkt_dev->cur_pkt_size + 64 + 16 + @@ -2844,7 +2853,7 @@ static struct sk_buff *fill_packet_ipv6(struct net_device *odev, skb->network_header = skb->tail; skb->transport_header = skb->network_header + sizeof(struct ipv6hdr); skb_put(skb, sizeof(struct ipv6hdr) + sizeof(struct udphdr)); - skb_set_queue_mapping(skb, pkt_dev->cur_queue_map); + skb_set_queue_mapping(skb, queue_map); iph = ipv6_hdr(skb); udph = udp_hdr(skb); @@ -3263,7 +3272,9 @@ static void pktgen_rem_thread(struct pktgen_thread *t) static __inline__ void pktgen_xmit(struct pktgen_dev *pkt_dev) { struct net_device *odev = NULL; + struct netdev_queue *txq; __u64 idle_start = 0; + u16 queue_map; int ret; odev = pkt_dev->odev; @@ -3285,9 +3296,15 @@ static __inline__ void pktgen_xmit(struct pktgen_dev *pkt_dev) } } - if ((netif_queue_stopped(odev) || - (pkt_dev->skb && - netif_subqueue_stopped(odev, pkt_dev->skb))) || + if (!pkt_dev->skb) { + set_cur_queue_map(pkt_dev); + queue_map = pkt_dev->cur_queue_map; + } else { + queue_map = skb_get_queue_mapping(pkt_dev->skb); + } + + txq = netdev_get_tx_queue(odev, queue_map); + if (netif_tx_queue_stopped(txq) || need_resched()) { idle_start = getCurUs(); @@ -3303,8 +3320,7 @@ static __inline__ void pktgen_xmit(struct pktgen_dev *pkt_dev) pkt_dev->idle_acc += getCurUs() - idle_start; - if (netif_queue_stopped(odev) || - netif_subqueue_stopped(odev, pkt_dev->skb)) { + if (netif_tx_queue_stopped(txq)) { pkt_dev->next_tx_us = getCurUs(); /* TODO */ pkt_dev->next_tx_ns = 0; goto out; /* Try the next interface */ @@ -3331,9 +3347,12 @@ static __inline__ void pktgen_xmit(struct pktgen_dev *pkt_dev) } } - netif_tx_lock_bh(odev); - if (!netif_queue_stopped(odev) && - !netif_subqueue_stopped(odev, pkt_dev->skb)) { + /* fill_packet() might have changed the queue */ + queue_map = skb_get_queue_mapping(pkt_dev->skb); + txq = netdev_get_tx_queue(odev, queue_map); + + __netif_tx_lock_bh(txq); + if (!netif_tx_queue_stopped(txq)) { atomic_inc(&(pkt_dev->skb->users)); retry_now: @@ -3377,7 +3396,7 @@ static __inline__ void pktgen_xmit(struct pktgen_dev *pkt_dev) pkt_dev->next_tx_ns = 0; } - netif_tx_unlock_bh(odev); + __netif_tx_unlock_bh(txq); /* If pkt_dev->count is zero, then run forever */ if ((pkt_dev->count != 0) && (pkt_dev->sofar >= pkt_dev->count)) { diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index a9a77216310e..71edb8b36341 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c @@ -605,8 +605,11 @@ static int rtnl_fill_ifinfo(struct sk_buff *skb, struct net_device *dev, int type, u32 pid, u32 seq, u32 change, unsigned int flags) { + struct netdev_queue *txq; struct ifinfomsg *ifm; struct nlmsghdr *nlh; + struct net_device_stats *stats; + struct nlattr *attr; nlh = nlmsg_put(skb, pid, seq, type, sizeof(*ifm), flags); if (nlh == NULL) @@ -633,8 +636,9 @@ static int rtnl_fill_ifinfo(struct sk_buff *skb, struct net_device *dev, if (dev->master) NLA_PUT_U32(skb, IFLA_MASTER, dev->master->ifindex); - if (dev->qdisc_sleeping) - NLA_PUT_STRING(skb, IFLA_QDISC, dev->qdisc_sleeping->ops->id); + txq = netdev_get_tx_queue(dev, 0); + if (txq->qdisc_sleeping) + NLA_PUT_STRING(skb, IFLA_QDISC, txq->qdisc_sleeping->ops->id); if (1) { struct rtnl_link_ifmap map = { @@ -653,19 +657,13 @@ static int rtnl_fill_ifinfo(struct sk_buff *skb, struct net_device *dev, NLA_PUT(skb, IFLA_BROADCAST, dev->addr_len, dev->broadcast); } - if (dev->get_stats) { - struct net_device_stats *stats = dev->get_stats(dev); - if (stats) { - struct nlattr *attr; + attr = nla_reserve(skb, IFLA_STATS, + sizeof(struct rtnl_link_stats)); + if (attr == NULL) + goto nla_put_failure; - attr = nla_reserve(skb, IFLA_STATS, - sizeof(struct rtnl_link_stats)); - if (attr == NULL) - goto nla_put_failure; - - copy_rtnl_link_stats(nla_data(attr), stats); - } - } + stats = dev->get_stats(dev); + copy_rtnl_link_stats(nla_data(attr), stats); if (dev->rtnl_link_ops) { if (rtnl_link_fill(skb, dev) < 0) diff --git a/net/core/skbuff.c b/net/core/skbuff.c index 366621610e76..e4115672b6cf 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -4,8 +4,6 @@ * Authors: Alan Cox <iiitac@pyr.swan.ac.uk> * Florian La Roche <rzsfl@rz.uni-sb.de> * - * Version: $Id: skbuff.c,v 1.90 2001/11/07 05:56:19 davem Exp $ - * * Fixes: * Alan Cox : Fixed the worst of the load * balancer bugs. @@ -461,6 +459,8 @@ static void __copy_skb_header(struct sk_buff *new, const struct sk_buff *old) new->tc_verd = old->tc_verd; #endif #endif + new->vlan_tci = old->vlan_tci; + skb_copy_secmark(new, old); } @@ -1282,114 +1282,83 @@ static inline int spd_fill_page(struct splice_pipe_desc *spd, struct page *page, return 0; } -/* - * Map linear and fragment data from the skb to spd. Returns number of - * pages mapped. - */ -static int __skb_splice_bits(struct sk_buff *skb, unsigned int *offset, - unsigned int *total_len, - struct splice_pipe_desc *spd) -{ - unsigned int nr_pages = spd->nr_pages; - unsigned int poff, plen, len, toff, tlen; - int headlen, seg, error = 0; - - toff = *offset; - tlen = *total_len; - if (!tlen) { - error = 1; - goto err; +static inline void __segment_seek(struct page **page, unsigned int *poff, + unsigned int *plen, unsigned int off) +{ + *poff += off; + *page += *poff / PAGE_SIZE; + *poff = *poff % PAGE_SIZE; + *plen -= off; +} + +static inline int __splice_segment(struct page *page, unsigned int poff, + unsigned int plen, unsigned int *off, + unsigned int *len, struct sk_buff *skb, + struct splice_pipe_desc *spd) +{ + if (!*len) + return 1; + + /* skip this segment if already processed */ + if (*off >= plen) { + *off -= plen; + return 0; } - /* - * if the offset is greater than the linear part, go directly to - * the fragments. - */ - headlen = skb_headlen(skb); - if (toff >= headlen) { - toff -= headlen; - goto map_frag; + /* ignore any bits we already processed */ + if (*off) { + __segment_seek(&page, &poff, &plen, *off); + *off = 0; } - /* - * first map the linear region into the pages/partial map, skipping - * any potential initial offset. - */ - len = 0; - while (len < headlen) { - void *p = skb->data + len; - - poff = (unsigned long) p & (PAGE_SIZE - 1); - plen = min_t(unsigned int, headlen - len, PAGE_SIZE - poff); - len += plen; - - if (toff) { - if (plen <= toff) { - toff -= plen; - continue; - } - plen -= toff; - poff += toff; - toff = 0; - } + do { + unsigned int flen = min(*len, plen); - plen = min(plen, tlen); - if (!plen) - break; + /* the linear region may spread across several pages */ + flen = min_t(unsigned int, flen, PAGE_SIZE - poff); - /* - * just jump directly to update and return, no point - * in going over fragments when the output is full. - */ - error = spd_fill_page(spd, virt_to_page(p), plen, poff, skb); - if (error) - goto done; + if (spd_fill_page(spd, page, flen, poff, skb)) + return 1; - tlen -= plen; - } + __segment_seek(&page, &poff, &plen, flen); + *len -= flen; + + } while (*len && plen); + + return 0; +} + +/* + * Map linear and fragment data from the skb to spd. It reports failure if the + * pipe is full or if we already spliced the requested length. + */ +static int __skb_splice_bits(struct sk_buff *skb, unsigned int *offset, + unsigned int *len, + struct splice_pipe_desc *spd) +{ + int seg; + + /* + * map the linear part + */ + if (__splice_segment(virt_to_page(skb->data), + (unsigned long) skb->data & (PAGE_SIZE - 1), + skb_headlen(skb), + offset, len, skb, spd)) + return 1; /* * then map the fragments */ -map_frag: for (seg = 0; seg < skb_shinfo(skb)->nr_frags; seg++) { const skb_frag_t *f = &skb_shinfo(skb)->frags[seg]; - plen = f->size; - poff = f->page_offset; - - if (toff) { - if (plen <= toff) { - toff -= plen; - continue; - } - plen -= toff; - poff += toff; - toff = 0; - } - - plen = min(plen, tlen); - if (!plen) - break; - - error = spd_fill_page(spd, f->page, plen, poff, skb); - if (error) - break; - - tlen -= plen; + if (__splice_segment(f->page, f->page_offset, f->size, + offset, len, skb, spd)) + return 1; } -done: - if (spd->nr_pages - nr_pages) { - *offset = 0; - *total_len = tlen; - return 0; - } -err: - /* update the offset to reflect the linear part skip, if any */ - if (!error) - *offset = toff; - return error; + return 0; } /* @@ -2288,6 +2257,7 @@ struct sk_buff *skb_segment(struct sk_buff *skb, int features) skb_copy_queue_mapping(nskb, skb); nskb->priority = skb->priority; nskb->protocol = skb->protocol; + nskb->vlan_tci = skb->vlan_tci; nskb->dst = dst_clone(skb->dst); memcpy(nskb->cb, skb->cb, sizeof(skb->cb)); nskb->pkt_type = skb->pkt_type; @@ -2592,6 +2562,13 @@ bool skb_partial_csum_set(struct sk_buff *skb, u16 start, u16 off) return true; } +void __skb_warn_lro_forwarding(const struct sk_buff *skb) +{ + if (net_ratelimit()) + pr_warning("%s: received packets cannot be forwarded" + " while LRO is enabled\n", skb->dev->name); +} + EXPORT_SYMBOL(___pskb_trim); EXPORT_SYMBOL(__kfree_skb); EXPORT_SYMBOL(kfree_skb); @@ -2625,6 +2602,7 @@ EXPORT_SYMBOL(skb_seq_read); EXPORT_SYMBOL(skb_abort_seq_read); EXPORT_SYMBOL(skb_find_text); EXPORT_SYMBOL(skb_append_datato_frags); +EXPORT_SYMBOL(__skb_warn_lro_forwarding); EXPORT_SYMBOL_GPL(skb_to_sgvec); EXPORT_SYMBOL_GPL(skb_cow_data); diff --git a/net/core/sock.c b/net/core/sock.c index 88094cb09c06..10a64d57078c 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -7,8 +7,6 @@ * handler for protocols to use and generic option handler. * * - * Version: $Id: sock.c,v 1.117 2002/02/01 22:01:03 davem Exp $ - * * Authors: Ross Biro * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG> * Florian La Roche, <flla@stud.uni-sb.de> @@ -1068,7 +1066,7 @@ struct sock *sk_clone(const struct sock *sk, const gfp_t priority) * to be taken into account in all callers. -acme */ sk_refcnt_debug_inc(newsk); - newsk->sk_socket = NULL; + sk_set_socket(newsk, NULL); newsk->sk_sleep = NULL; if (newsk->sk_prot->sockets_allocated) @@ -1444,7 +1442,7 @@ int __sk_mem_schedule(struct sock *sk, int size, int kind) /* Under pressure. */ if (allocated > prot->sysctl_mem[1]) if (prot->enter_memory_pressure) - prot->enter_memory_pressure(); + prot->enter_memory_pressure(sk); /* Over hard limit. */ if (allocated > prot->sysctl_mem[2]) @@ -1704,7 +1702,7 @@ void sock_init_data(struct socket *sock, struct sock *sk) sk->sk_rcvbuf = sysctl_rmem_default; sk->sk_sndbuf = sysctl_wmem_default; sk->sk_state = TCP_CLOSE; - sk->sk_socket = sock; + sk_set_socket(sk, sock); sock_set_flag(sk, SOCK_ZAPPED); diff --git a/net/core/sysctl_net_core.c b/net/core/sysctl_net_core.c index 5fc801057244..a570e2af22cb 100644 --- a/net/core/sysctl_net_core.c +++ b/net/core/sysctl_net_core.c @@ -125,14 +125,6 @@ static struct ctl_table net_core_table[] = { #endif /* CONFIG_XFRM */ #endif /* CONFIG_NET */ { - .ctl_name = NET_CORE_SOMAXCONN, - .procname = "somaxconn", - .data = &init_net.core.sysctl_somaxconn, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = &proc_dointvec - }, - { .ctl_name = NET_CORE_BUDGET, .procname = "netdev_budget", .data = &netdev_budget, @@ -151,6 +143,18 @@ static struct ctl_table net_core_table[] = { { .ctl_name = 0 } }; +static struct ctl_table netns_core_table[] = { + { + .ctl_name = NET_CORE_SOMAXCONN, + .procname = "somaxconn", + .data = &init_net.core.sysctl_somaxconn, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &proc_dointvec + }, + { .ctl_name = 0 } +}; + static __net_initdata struct ctl_path net_core_path[] = { { .procname = "net", .ctl_name = CTL_NET, }, { .procname = "core", .ctl_name = NET_CORE, }, @@ -159,23 +163,17 @@ static __net_initdata struct ctl_path net_core_path[] = { static __net_init int sysctl_core_net_init(struct net *net) { - struct ctl_table *tbl, *tmp; + struct ctl_table *tbl; net->core.sysctl_somaxconn = SOMAXCONN; - tbl = net_core_table; + tbl = netns_core_table; if (net != &init_net) { - tbl = kmemdup(tbl, sizeof(net_core_table), GFP_KERNEL); + tbl = kmemdup(tbl, sizeof(netns_core_table), GFP_KERNEL); if (tbl == NULL) goto err_dup; - for (tmp = tbl; tmp->procname; tmp++) { - if (tmp->data >= (void *)&init_net && - tmp->data < (void *)(&init_net + 1)) - tmp->data += (char *)net - (char *)&init_net; - else - tmp->mode &= ~0222; - } + tbl[0].data = &net->core.sysctl_somaxconn; } net->core.sysctl_hdr = register_net_sysctl_table(net, @@ -186,7 +184,7 @@ static __net_init int sysctl_core_net_init(struct net *net) return 0; err_reg: - if (tbl != net_core_table) + if (tbl != netns_core_table) kfree(tbl); err_dup: return -ENOMEM; @@ -198,7 +196,7 @@ static __net_exit void sysctl_core_net_exit(struct net *net) tbl = net->core.sysctl_hdr->ctl_table_arg; unregister_net_sysctl_table(net->core.sysctl_hdr); - BUG_ON(tbl == net_core_table); + BUG_ON(tbl == netns_core_table); kfree(tbl); } @@ -209,6 +207,7 @@ static __net_initdata struct pernet_operations sysctl_core_ops = { static __init int sysctl_core_init(void) { + register_net_sysctl_rotable(net_core_path, net_core_table); return register_pernet_subsys(&sysctl_core_ops); } diff --git a/net/dccp/ccids/ccid3.c b/net/dccp/ccids/ccid3.c index a1929f33d703..f6756e0c9e69 100644 --- a/net/dccp/ccids/ccid3.c +++ b/net/dccp/ccids/ccid3.c @@ -794,7 +794,7 @@ static void ccid3_hc_rx_packet_recv(struct sock *sk, struct sk_buff *skb) { struct ccid3_hc_rx_sock *hcrx = ccid3_hc_rx_sk(sk); enum ccid3_fback_type do_feedback = CCID3_FBACK_NONE; - const u32 ndp = dccp_sk(sk)->dccps_options_received.dccpor_ndp; + const u64 ndp = dccp_sk(sk)->dccps_options_received.dccpor_ndp; const bool is_data_packet = dccp_data_packet(skb); if (unlikely(hcrx->ccid3hcrx_state == TFRC_RSTATE_NO_DATA)) { @@ -825,18 +825,16 @@ static void ccid3_hc_rx_packet_recv(struct sock *sk, struct sk_buff *skb) } /* - * Handle pending losses and otherwise check for new loss + * Perform loss detection and handle pending losses */ - if (tfrc_rx_hist_loss_pending(&hcrx->ccid3hcrx_hist) && - tfrc_rx_handle_loss(&hcrx->ccid3hcrx_hist, - &hcrx->ccid3hcrx_li_hist, - skb, ndp, ccid3_first_li, sk) ) { + if (tfrc_rx_handle_loss(&hcrx->ccid3hcrx_hist, &hcrx->ccid3hcrx_li_hist, + skb, ndp, ccid3_first_li, sk)) { do_feedback = CCID3_FBACK_PARAM_CHANGE; goto done_receiving; } - if (tfrc_rx_hist_new_loss_indicated(&hcrx->ccid3hcrx_hist, skb, ndp)) - goto update_records; + if (tfrc_rx_hist_loss_pending(&hcrx->ccid3hcrx_hist)) + return; /* done receiving */ /* * Handle data packets: RTT sampling and monitoring p diff --git a/net/dccp/ccids/lib/loss_interval.c b/net/dccp/ccids/lib/loss_interval.c index 849e181e698f..bcd6ac415bb9 100644 --- a/net/dccp/ccids/lib/loss_interval.c +++ b/net/dccp/ccids/lib/loss_interval.c @@ -90,14 +90,14 @@ u8 tfrc_lh_update_i_mean(struct tfrc_loss_hist *lh, struct sk_buff *skb) { struct tfrc_loss_interval *cur = tfrc_lh_peek(lh); u32 old_i_mean = lh->i_mean; - s64 length; + s64 len; if (cur == NULL) /* not initialised */ return 0; - length = dccp_delta_seqno(cur->li_seqno, DCCP_SKB_CB(skb)->dccpd_seq); + len = dccp_delta_seqno(cur->li_seqno, DCCP_SKB_CB(skb)->dccpd_seq) + 1; - if (length - cur->li_length <= 0) /* duplicate or reordered */ + if (len - (s64)cur->li_length <= 0) /* duplicate or reordered */ return 0; if (SUB16(dccp_hdr(skb)->dccph_ccval, cur->li_ccval) > 4) @@ -114,7 +114,7 @@ u8 tfrc_lh_update_i_mean(struct tfrc_loss_hist *lh, struct sk_buff *skb) if (tfrc_lh_length(lh) == 1) /* due to RFC 3448, 6.3.1 */ return 0; - cur->li_length = length; + cur->li_length = len; tfrc_lh_calc_i_mean(lh); return (lh->i_mean < old_i_mean); @@ -159,7 +159,7 @@ int tfrc_lh_interval_add(struct tfrc_loss_hist *lh, struct tfrc_rx_hist *rh, else { cur->li_length = dccp_delta_seqno(cur->li_seqno, new->li_seqno); new->li_length = dccp_delta_seqno(new->li_seqno, - tfrc_rx_hist_last_rcv(rh)->tfrchrx_seqno); + tfrc_rx_hist_last_rcv(rh)->tfrchrx_seqno) + 1; if (lh->counter > (2*LIH_SIZE)) lh->counter -= LIH_SIZE; diff --git a/net/dccp/ccids/lib/packet_history.c b/net/dccp/ccids/lib/packet_history.c index 20af1a693427..6cc108afdc3b 100644 --- a/net/dccp/ccids/lib/packet_history.c +++ b/net/dccp/ccids/lib/packet_history.c @@ -153,7 +153,7 @@ void tfrc_rx_packet_history_exit(void) static inline void tfrc_rx_hist_entry_from_skb(struct tfrc_rx_hist_entry *entry, const struct sk_buff *skb, - const u32 ndp) + const u64 ndp) { const struct dccp_hdr *dh = dccp_hdr(skb); @@ -166,7 +166,7 @@ static inline void tfrc_rx_hist_entry_from_skb(struct tfrc_rx_hist_entry *entry, void tfrc_rx_hist_add_packet(struct tfrc_rx_hist *h, const struct sk_buff *skb, - const u32 ndp) + const u64 ndp) { struct tfrc_rx_hist_entry *entry = tfrc_rx_hist_last_rcv(h); @@ -206,31 +206,39 @@ static void tfrc_rx_hist_swap(struct tfrc_rx_hist *h, const u8 a, const u8 b) * * In the descriptions, `Si' refers to the sequence number of entry number i, * whose NDP count is `Ni' (lower case is used for variables). - * Note: All __after_loss functions expect that a test against duplicates has - * been performed already: the seqno of the skb must not be less than the - * seqno of loss_prev; and it must not equal that of any valid hist_entry. + * Note: All __xxx_loss functions expect that a test against duplicates has been + * performed already: the seqno of the skb must not be less than the seqno + * of loss_prev; and it must not equal that of any valid history entry. */ +static void __do_track_loss(struct tfrc_rx_hist *h, struct sk_buff *skb, u64 n1) +{ + u64 s0 = tfrc_rx_hist_loss_prev(h)->tfrchrx_seqno, + s1 = DCCP_SKB_CB(skb)->dccpd_seq; + + if (!dccp_loss_free(s0, s1, n1)) { /* gap between S0 and S1 */ + h->loss_count = 1; + tfrc_rx_hist_entry_from_skb(tfrc_rx_hist_entry(h, 1), skb, n1); + } +} + static void __one_after_loss(struct tfrc_rx_hist *h, struct sk_buff *skb, u32 n2) { u64 s0 = tfrc_rx_hist_loss_prev(h)->tfrchrx_seqno, s1 = tfrc_rx_hist_entry(h, 1)->tfrchrx_seqno, s2 = DCCP_SKB_CB(skb)->dccpd_seq; - int n1 = tfrc_rx_hist_entry(h, 1)->tfrchrx_ndp, - d12 = dccp_delta_seqno(s1, s2), d2; - if (d12 > 0) { /* S1 < S2 */ + if (likely(dccp_delta_seqno(s1, s2) > 0)) { /* S1 < S2 */ h->loss_count = 2; tfrc_rx_hist_entry_from_skb(tfrc_rx_hist_entry(h, 2), skb, n2); return; } /* S0 < S2 < S1 */ - d2 = dccp_delta_seqno(s0, s2); - if (d2 == 1 || n2 >= d2) { /* S2 is direct successor of S0 */ - int d21 = -d12; + if (dccp_loss_free(s0, s2, n2)) { + u64 n1 = tfrc_rx_hist_entry(h, 1)->tfrchrx_ndp; - if (d21 == 1 || n1 >= d21) { + if (dccp_loss_free(s2, s1, n1)) { /* hole is filled: S0, S2, and S1 are consecutive */ h->loss_count = 0; h->loss_start = tfrc_rx_hist_index(h, 1); @@ -238,9 +246,9 @@ static void __one_after_loss(struct tfrc_rx_hist *h, struct sk_buff *skb, u32 n2 /* gap between S2 and S1: just update loss_prev */ tfrc_rx_hist_entry_from_skb(tfrc_rx_hist_loss_prev(h), skb, n2); - } else { /* hole between S0 and S2 */ + } else { /* gap between S0 and S2 */ /* - * Reorder history to insert S2 between S0 and s1 + * Reorder history to insert S2 between S0 and S1 */ tfrc_rx_hist_swap(h, 0, 3); h->loss_start = tfrc_rx_hist_index(h, 3); @@ -256,22 +264,18 @@ static int __two_after_loss(struct tfrc_rx_hist *h, struct sk_buff *skb, u32 n3) s1 = tfrc_rx_hist_entry(h, 1)->tfrchrx_seqno, s2 = tfrc_rx_hist_entry(h, 2)->tfrchrx_seqno, s3 = DCCP_SKB_CB(skb)->dccpd_seq; - int n1 = tfrc_rx_hist_entry(h, 1)->tfrchrx_ndp, - d23 = dccp_delta_seqno(s2, s3), d13, d3, d31; - if (d23 > 0) { /* S2 < S3 */ + if (likely(dccp_delta_seqno(s2, s3) > 0)) { /* S2 < S3 */ h->loss_count = 3; tfrc_rx_hist_entry_from_skb(tfrc_rx_hist_entry(h, 3), skb, n3); return 1; } /* S3 < S2 */ - d13 = dccp_delta_seqno(s1, s3); - if (d13 > 0) { + if (dccp_delta_seqno(s1, s3) > 0) { /* S1 < S3 < S2 */ /* - * The sequence number order is S1, S3, S2 - * Reorder history to insert entry between S1 and S2 + * Reorder history to insert S3 between S1 and S2 */ tfrc_rx_hist_swap(h, 2, 3); tfrc_rx_hist_entry_from_skb(tfrc_rx_hist_entry(h, 2), skb, n3); @@ -280,17 +284,15 @@ static int __two_after_loss(struct tfrc_rx_hist *h, struct sk_buff *skb, u32 n3) } /* S0 < S3 < S1 */ - d31 = -d13; - d3 = dccp_delta_seqno(s0, s3); - if (d3 == 1 || n3 >= d3) { /* S3 is a successor of S0 */ + if (dccp_loss_free(s0, s3, n3)) { + u64 n1 = tfrc_rx_hist_entry(h, 1)->tfrchrx_ndp; - if (d31 == 1 || n1 >= d31) { + if (dccp_loss_free(s3, s1, n1)) { /* hole between S0 and S1 filled by S3 */ - int d2 = dccp_delta_seqno(s1, s2), - n2 = tfrc_rx_hist_entry(h, 2)->tfrchrx_ndp; + u64 n2 = tfrc_rx_hist_entry(h, 2)->tfrchrx_ndp; - if (d2 == 1 || n2 >= d2) { + if (dccp_loss_free(s1, s2, n2)) { /* entire hole filled by S0, S3, S1, S2 */ h->loss_start = tfrc_rx_hist_index(h, 2); h->loss_count = 0; @@ -307,8 +309,8 @@ static int __two_after_loss(struct tfrc_rx_hist *h, struct sk_buff *skb, u32 n3) } /* - * The remaining case: S3 is not a successor of S0. - * Sequence order is S0, S3, S1, S2; reorder to insert between S0 and S1 + * The remaining case: S0 < S3 < S1 < S2; gap between S0 and S3 + * Reorder history to insert S3 between S0 and S1. */ tfrc_rx_hist_swap(h, 0, 3); h->loss_start = tfrc_rx_hist_index(h, 3); @@ -318,33 +320,25 @@ static int __two_after_loss(struct tfrc_rx_hist *h, struct sk_buff *skb, u32 n3) return 1; } -/* return the signed modulo-2^48 sequence number distance from entry e1 to e2 */ -static s64 tfrc_rx_hist_delta_seqno(struct tfrc_rx_hist *h, u8 e1, u8 e2) -{ - DCCP_BUG_ON(e1 > h->loss_count || e2 > h->loss_count); - - return dccp_delta_seqno(tfrc_rx_hist_entry(h, e1)->tfrchrx_seqno, - tfrc_rx_hist_entry(h, e2)->tfrchrx_seqno); -} - /* recycle RX history records to continue loss detection if necessary */ static void __three_after_loss(struct tfrc_rx_hist *h) { /* - * The distance between S0 and S1 is always greater than 1 and the NDP - * count of S1 is smaller than this distance. Otherwise there would - * have been no loss. Hence it is only necessary to see whether there - * are further missing data packets between S1/S2 and S2/S3. + * At this stage we know already that there is a gap between S0 and S1 + * (since S0 was the highest sequence number received before detecting + * the loss). To recycle the loss record, it is thus only necessary to + * check for other possible gaps between S1/S2 and between S2/S3. */ - int d2 = tfrc_rx_hist_delta_seqno(h, 1, 2), - d3 = tfrc_rx_hist_delta_seqno(h, 2, 3), - n2 = tfrc_rx_hist_entry(h, 2)->tfrchrx_ndp, + u64 s1 = tfrc_rx_hist_entry(h, 1)->tfrchrx_seqno, + s2 = tfrc_rx_hist_entry(h, 2)->tfrchrx_seqno, + s3 = tfrc_rx_hist_entry(h, 3)->tfrchrx_seqno; + u64 n2 = tfrc_rx_hist_entry(h, 2)->tfrchrx_ndp, n3 = tfrc_rx_hist_entry(h, 3)->tfrchrx_ndp; - if (d2 == 1 || n2 >= d2) { /* S2 is successor to S1 */ + if (dccp_loss_free(s1, s2, n2)) { - if (d3 == 1 || n3 >= d3) { - /* S3 is successor of S2: entire hole is filled */ + if (dccp_loss_free(s2, s3, n3)) { + /* no gap between S2 and S3: entire hole is filled */ h->loss_start = tfrc_rx_hist_index(h, 3); h->loss_count = 0; } else { @@ -353,7 +347,7 @@ static void __three_after_loss(struct tfrc_rx_hist *h) h->loss_count = 1; } - } else { /* gap between S1 and S2 */ + } else { /* gap between S1 and S2 */ h->loss_start = tfrc_rx_hist_index(h, 1); h->loss_count = 2; } @@ -370,15 +364,20 @@ static void __three_after_loss(struct tfrc_rx_hist *h) * Chooses action according to pending loss, updates LI database when a new * loss was detected, and does required post-processing. Returns 1 when caller * should send feedback, 0 otherwise. + * Since it also takes care of reordering during loss detection and updates the + * records accordingly, the caller should not perform any more RX history + * operations when loss_count is greater than 0 after calling this function. */ int tfrc_rx_handle_loss(struct tfrc_rx_hist *h, struct tfrc_loss_hist *lh, - struct sk_buff *skb, u32 ndp, + struct sk_buff *skb, const u64 ndp, u32 (*calc_first_li)(struct sock *), struct sock *sk) { int is_new_loss = 0; - if (h->loss_count == 1) { + if (h->loss_count == 0) { + __do_track_loss(h, skb, ndp); + } else if (h->loss_count == 1) { __one_after_loss(h, skb, ndp); } else if (h->loss_count != 2) { DCCP_BUG("invalid loss_count %d", h->loss_count); diff --git a/net/dccp/ccids/lib/packet_history.h b/net/dccp/ccids/lib/packet_history.h index c7eeda49cb20..461cc91cce88 100644 --- a/net/dccp/ccids/lib/packet_history.h +++ b/net/dccp/ccids/lib/packet_history.h @@ -64,7 +64,7 @@ struct tfrc_rx_hist_entry { u64 tfrchrx_seqno:48, tfrchrx_ccval:4, tfrchrx_type:4; - u32 tfrchrx_ndp; /* In fact it is from 8 to 24 bits */ + u64 tfrchrx_ndp:48; ktime_t tfrchrx_tstamp; }; @@ -118,41 +118,21 @@ static inline struct tfrc_rx_hist_entry * return h->ring[h->loss_start]; } -/* initialise loss detection and disable RTT sampling */ -static inline void tfrc_rx_hist_loss_indicated(struct tfrc_rx_hist *h) -{ - h->loss_count = 1; -} - /* indicate whether previously a packet was detected missing */ -static inline int tfrc_rx_hist_loss_pending(const struct tfrc_rx_hist *h) -{ - return h->loss_count; -} - -/* any data packets missing between last reception and skb ? */ -static inline int tfrc_rx_hist_new_loss_indicated(struct tfrc_rx_hist *h, - const struct sk_buff *skb, - u32 ndp) +static inline bool tfrc_rx_hist_loss_pending(const struct tfrc_rx_hist *h) { - int delta = dccp_delta_seqno(tfrc_rx_hist_last_rcv(h)->tfrchrx_seqno, - DCCP_SKB_CB(skb)->dccpd_seq); - - if (delta > 1 && ndp < delta) - tfrc_rx_hist_loss_indicated(h); - - return tfrc_rx_hist_loss_pending(h); + return h->loss_count > 0; } extern void tfrc_rx_hist_add_packet(struct tfrc_rx_hist *h, - const struct sk_buff *skb, const u32 ndp); + const struct sk_buff *skb, const u64 ndp); extern int tfrc_rx_hist_duplicate(struct tfrc_rx_hist *h, struct sk_buff *skb); struct tfrc_loss_hist; extern int tfrc_rx_handle_loss(struct tfrc_rx_hist *h, struct tfrc_loss_hist *lh, - struct sk_buff *skb, u32 ndp, + struct sk_buff *skb, const u64 ndp, u32 (*first_li)(struct sock *sk), struct sock *sk); extern u32 tfrc_rx_hist_sample_rtt(struct tfrc_rx_hist *h, diff --git a/net/dccp/dccp.h b/net/dccp/dccp.h index f44d492d3b74..32617e0576cb 100644 --- a/net/dccp/dccp.h +++ b/net/dccp/dccp.h @@ -153,6 +153,21 @@ static inline u64 max48(const u64 seq1, const u64 seq2) return after48(seq1, seq2) ? seq1 : seq2; } +/** + * dccp_loss_free - Evaluates condition for data loss from RFC 4340, 7.7.1 + * @s1: start sequence number + * @s2: end sequence number + * @ndp: NDP count on packet with sequence number @s2 + * Returns true if the sequence range s1...s2 has no data loss. + */ +static inline bool dccp_loss_free(const u64 s1, const u64 s2, const u64 ndp) +{ + s64 delta = dccp_delta_seqno(s1, s2); + + BUG_TRAP(delta >= 0); + return (u64)delta <= ndp + 1; +} + enum { DCCP_MIB_NUM = 0, DCCP_MIB_ACTIVEOPENS, /* ActiveOpens */ @@ -262,7 +277,7 @@ extern int dccp_rcv_established(struct sock *sk, struct sk_buff *skb, const struct dccp_hdr *dh, const unsigned len); extern int dccp_init_sock(struct sock *sk, const __u8 ctl_sock_initialized); -extern int dccp_destroy_sock(struct sock *sk); +extern void dccp_destroy_sock(struct sock *sk); extern void dccp_close(struct sock *sk, long timeout); extern struct sk_buff *dccp_make_response(struct sock *sk, diff --git a/net/dccp/ipv4.c b/net/dccp/ipv4.c index 37d27bcb361f..2622ace17c46 100644 --- a/net/dccp/ipv4.c +++ b/net/dccp/ipv4.c @@ -205,17 +205,18 @@ static void dccp_v4_err(struct sk_buff *skb, u32 info) struct sock *sk; __u64 seq; int err; + struct net *net = dev_net(skb->dev); if (skb->len < (iph->ihl << 2) + 8) { - ICMP_INC_STATS_BH(ICMP_MIB_INERRORS); + ICMP_INC_STATS_BH(net, ICMP_MIB_INERRORS); return; } - sk = inet_lookup(dev_net(skb->dev), &dccp_hashinfo, + sk = inet_lookup(net, &dccp_hashinfo, iph->daddr, dh->dccph_dport, iph->saddr, dh->dccph_sport, inet_iif(skb)); if (sk == NULL) { - ICMP_INC_STATS_BH(ICMP_MIB_INERRORS); + ICMP_INC_STATS_BH(net, ICMP_MIB_INERRORS); return; } @@ -229,7 +230,7 @@ static void dccp_v4_err(struct sk_buff *skb, u32 info) * servers this needs to be solved differently. */ if (sock_owned_by_user(sk)) - NET_INC_STATS_BH(LINUX_MIB_LOCKDROPPEDICMPS); + NET_INC_STATS_BH(net, LINUX_MIB_LOCKDROPPEDICMPS); if (sk->sk_state == DCCP_CLOSED) goto out; @@ -238,7 +239,7 @@ static void dccp_v4_err(struct sk_buff *skb, u32 info) seq = dccp_hdr_seq(dh); if ((1 << sk->sk_state) & ~(DCCPF_REQUESTING | DCCPF_LISTEN) && !between48(seq, dp->dccps_swl, dp->dccps_swh)) { - NET_INC_STATS_BH(LINUX_MIB_OUTOFWINDOWICMPS); + NET_INC_STATS_BH(net, LINUX_MIB_OUTOFWINDOWICMPS); goto out; } @@ -285,7 +286,7 @@ static void dccp_v4_err(struct sk_buff *skb, u32 info) BUG_TRAP(!req->sk); if (seq != dccp_rsk(req)->dreq_iss) { - NET_INC_STATS_BH(LINUX_MIB_OUTOFWINDOWICMPS); + NET_INC_STATS_BH(net, LINUX_MIB_OUTOFWINDOWICMPS); goto out; } /* @@ -408,9 +409,9 @@ struct sock *dccp_v4_request_recv_sock(struct sock *sk, struct sk_buff *skb, return newsk; exit_overflow: - NET_INC_STATS_BH(LINUX_MIB_LISTENOVERFLOWS); + NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_LISTENOVERFLOWS); exit: - NET_INC_STATS_BH(LINUX_MIB_LISTENDROPS); + NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_LISTENDROPS); dst_release(dst); return NULL; } @@ -464,7 +465,7 @@ static struct dst_entry* dccp_v4_route_skb(struct net *net, struct sock *sk, security_skb_classify_flow(skb, &fl); if (ip_route_output_flow(net, &rt, &fl, sk, 0)) { - IP_INC_STATS_BH(IPSTATS_MIB_OUTNOROUTES); + IP_INC_STATS_BH(net, IPSTATS_MIB_OUTNOROUTES); return NULL; } diff --git a/net/dccp/ipv6.c b/net/dccp/ipv6.c index f7fe2a572d7b..b74e8b2cbe55 100644 --- a/net/dccp/ipv6.c +++ b/net/dccp/ipv6.c @@ -93,8 +93,9 @@ static void dccp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, struct sock *sk; int err; __u64 seq; + struct net *net = dev_net(skb->dev); - sk = inet6_lookup(dev_net(skb->dev), &dccp_hashinfo, + sk = inet6_lookup(net, &dccp_hashinfo, &hdr->daddr, dh->dccph_dport, &hdr->saddr, dh->dccph_sport, inet6_iif(skb)); @@ -110,7 +111,7 @@ static void dccp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, bh_lock_sock(sk); if (sock_owned_by_user(sk)) - NET_INC_STATS_BH(LINUX_MIB_LOCKDROPPEDICMPS); + NET_INC_STATS_BH(net, LINUX_MIB_LOCKDROPPEDICMPS); if (sk->sk_state == DCCP_CLOSED) goto out; @@ -188,7 +189,7 @@ static void dccp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, BUG_TRAP(req->sk == NULL); if (seq != dccp_rsk(req)->dreq_iss) { - NET_INC_STATS_BH(LINUX_MIB_OUTOFWINDOWICMPS); + NET_INC_STATS_BH(net, LINUX_MIB_OUTOFWINDOWICMPS); goto out; } @@ -629,9 +630,9 @@ static struct sock *dccp_v6_request_recv_sock(struct sock *sk, return newsk; out_overflow: - NET_INC_STATS_BH(LINUX_MIB_LISTENOVERFLOWS); + NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_LISTENOVERFLOWS); out: - NET_INC_STATS_BH(LINUX_MIB_LISTENDROPS); + NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_LISTENDROPS); if (opt != NULL && opt != np->opt) sock_kfree_s(sk, opt, opt->tot_len); dst_release(dst); @@ -1091,10 +1092,10 @@ static int dccp_v6_init_sock(struct sock *sk) return err; } -static int dccp_v6_destroy_sock(struct sock *sk) +static void dccp_v6_destroy_sock(struct sock *sk) { dccp_destroy_sock(sk); - return inet6_destroy_sock(sk); + inet6_destroy_sock(sk); } static struct timewait_sock_ops dccp6_timewait_sock_ops = { diff --git a/net/dccp/options.c b/net/dccp/options.c index 43bc24e761d0..dc7c158a2f4b 100644 --- a/net/dccp/options.c +++ b/net/dccp/options.c @@ -124,12 +124,12 @@ int dccp_parse_options(struct sock *sk, struct dccp_request_sock *dreq, mandatory = 1; break; case DCCPO_NDP_COUNT: - if (len > 3) + if (len > 6) goto out_invalid_option; opt_recv->dccpor_ndp = dccp_decode_value_var(value, len); - dccp_pr_debug("%s rx opt: NDP count=%d\n", dccp_role(sk), - opt_recv->dccpor_ndp); + dccp_pr_debug("%s opt: NDP count=%llu\n", dccp_role(sk), + (unsigned long long)opt_recv->dccpor_ndp); break; case DCCPO_CHANGE_L: /* fall through */ @@ -307,9 +307,11 @@ static void dccp_encode_value_var(const u32 value, unsigned char *to, *to++ = (value & 0xFF); } -static inline int dccp_ndp_len(const int ndp) +static inline u8 dccp_ndp_len(const u64 ndp) { - return likely(ndp <= 0xFF) ? 1 : ndp <= 0xFFFF ? 2 : 3; + if (likely(ndp <= 0xFF)) + return 1; + return likely(ndp <= USHORT_MAX) ? 2 : (ndp <= UINT_MAX ? 4 : 6); } int dccp_insert_option(struct sock *sk, struct sk_buff *skb, @@ -336,7 +338,7 @@ EXPORT_SYMBOL_GPL(dccp_insert_option); static int dccp_insert_option_ndp(struct sock *sk, struct sk_buff *skb) { struct dccp_sock *dp = dccp_sk(sk); - int ndp = dp->dccps_ndp_count; + u64 ndp = dp->dccps_ndp_count; if (dccp_non_data_packet(skb)) ++dp->dccps_ndp_count; diff --git a/net/dccp/proto.c b/net/dccp/proto.c index 9dfe2470962c..a0b56009611f 100644 --- a/net/dccp/proto.c +++ b/net/dccp/proto.c @@ -237,7 +237,7 @@ int dccp_init_sock(struct sock *sk, const __u8 ctl_sock_initialized) EXPORT_SYMBOL_GPL(dccp_init_sock); -int dccp_destroy_sock(struct sock *sk) +void dccp_destroy_sock(struct sock *sk) { struct dccp_sock *dp = dccp_sk(sk); struct dccp_minisock *dmsk = dccp_msk(sk); @@ -268,8 +268,6 @@ int dccp_destroy_sock(struct sock *sk) /* clean up feature negotiation state */ dccp_feat_clean(dmsk); - - return 0; } EXPORT_SYMBOL_GPL(dccp_destroy_sock); diff --git a/net/dccp/timer.c b/net/dccp/timer.c index 8703a792b560..3608d5342ca2 100644 --- a/net/dccp/timer.c +++ b/net/dccp/timer.c @@ -224,7 +224,7 @@ static void dccp_delack_timer(unsigned long data) if (sock_owned_by_user(sk)) { /* Try again later. */ icsk->icsk_ack.blocked = 1; - NET_INC_STATS_BH(LINUX_MIB_DELAYEDACKLOCKED); + NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_DELAYEDACKLOCKED); sk_reset_timer(sk, &icsk->icsk_delack_timer, jiffies + TCP_DELACK_MIN); goto out; @@ -254,7 +254,7 @@ static void dccp_delack_timer(unsigned long data) icsk->icsk_ack.ato = TCP_ATO_MIN; } dccp_send_ack(sk); - NET_INC_STATS_BH(LINUX_MIB_DELAYEDACKS); + NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_DELAYEDACKS); } out: bh_unlock_sock(sk); diff --git a/net/decnet/af_decnet.c b/net/decnet/af_decnet.c index fc2efe899e91..3c23ab33dbc0 100644 --- a/net/decnet/af_decnet.c +++ b/net/decnet/af_decnet.c @@ -451,7 +451,7 @@ static void dn_destruct(struct sock *sk) static int dn_memory_pressure; -static void dn_enter_memory_pressure(void) +static void dn_enter_memory_pressure(struct sock *sk) { if (!dn_memory_pressure) { dn_memory_pressure = 1; @@ -1719,6 +1719,8 @@ static int dn_recvmsg(struct kiocb *iocb, struct socket *sock, * See if there is data ready to read, sleep if there isn't */ for(;;) { + DEFINE_WAIT(wait); + if (sk->sk_err) goto out; @@ -1748,14 +1750,11 @@ static int dn_recvmsg(struct kiocb *iocb, struct socket *sock, goto out; } - set_bit(SOCK_ASYNC_WAITDATA, &sock->flags); - SOCK_SLEEP_PRE(sk) - - if (!dn_data_ready(sk, queue, flags, target)) - schedule(); - - SOCK_SLEEP_POST(sk) - clear_bit(SOCK_ASYNC_WAITDATA, &sock->flags); + prepare_to_wait(sk->sk_sleep, &wait, TASK_INTERRUPTIBLE); + set_bit(SOCK_ASYNC_WAITDATA, &sk->sk_socket->flags); + sk_wait_event(sk, &timeo, dn_data_ready(sk, queue, flags, target)); + clear_bit(SOCK_ASYNC_WAITDATA, &sk->sk_socket->flags); + finish_wait(sk->sk_sleep, &wait); } for(skb = queue->next; skb != (struct sk_buff *)queue; skb = nskb) { @@ -2002,18 +2001,19 @@ static int dn_sendmsg(struct kiocb *iocb, struct socket *sock, * size. */ if (dn_queue_too_long(scp, queue, flags)) { + DEFINE_WAIT(wait); + if (flags & MSG_DONTWAIT) { err = -EWOULDBLOCK; goto out; } - SOCK_SLEEP_PRE(sk) - - if (dn_queue_too_long(scp, queue, flags)) - schedule(); - - SOCK_SLEEP_POST(sk) - + prepare_to_wait(sk->sk_sleep, &wait, TASK_INTERRUPTIBLE); + set_bit(SOCK_ASYNC_WAITDATA, &sk->sk_socket->flags); + sk_wait_event(sk, &timeo, + !dn_queue_too_long(scp, queue, flags)); + clear_bit(SOCK_ASYNC_WAITDATA, &sk->sk_socket->flags); + finish_wait(sk->sk_sleep, &wait); continue; } @@ -2089,7 +2089,7 @@ static int dn_device_event(struct notifier_block *this, unsigned long event, { struct net_device *dev = (struct net_device *)ptr; - if (dev_net(dev) != &init_net) + if (!net_eq(dev_net(dev), &init_net)) return NOTIFY_DONE; switch(event) { diff --git a/net/decnet/dn_route.c b/net/decnet/dn_route.c index f50e88bf2661..821bd1cdec04 100644 --- a/net/decnet/dn_route.c +++ b/net/decnet/dn_route.c @@ -580,7 +580,7 @@ int dn_route_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type struct dn_dev *dn = (struct dn_dev *)dev->dn_ptr; unsigned char padlen = 0; - if (dev_net(dev) != &init_net) + if (!net_eq(dev_net(dev), &init_net)) goto dump_it; if (dn == NULL) diff --git a/net/decnet/dn_rules.c b/net/decnet/dn_rules.c index 5b7539b7fe0c..14fbca55e908 100644 --- a/net/decnet/dn_rules.c +++ b/net/decnet/dn_rules.c @@ -229,7 +229,7 @@ static u32 dn_fib_rule_default_pref(struct fib_rules_ops *ops) return 0; } -static void dn_fib_rule_flush_cache(void) +static void dn_fib_rule_flush_cache(struct fib_rules_ops *ops) { dn_rt_cache_flush(-1); } diff --git a/net/econet/af_econet.c b/net/econet/af_econet.c index 7c9bb13b1539..8789d2bb1b06 100644 --- a/net/econet/af_econet.c +++ b/net/econet/af_econet.c @@ -573,9 +573,7 @@ static int econet_release(struct socket *sock) sk->sk_state_change(sk); /* It is useless. Just for sanity. */ - sock->sk = NULL; - sk->sk_socket = NULL; - sock_set_flag(sk, SOCK_DEAD); + sock_orphan(sk); /* Purge queues */ @@ -1064,7 +1062,7 @@ static int econet_rcv(struct sk_buff *skb, struct net_device *dev, struct packet struct sock *sk; struct ec_device *edev = dev->ec_ptr; - if (dev_net(dev) != &init_net) + if (!net_eq(dev_net(dev), &init_net)) goto drop; if (skb->pkt_type == PACKET_OTHERHOST) @@ -1121,7 +1119,7 @@ static int econet_notifier(struct notifier_block *this, unsigned long msg, void struct net_device *dev = (struct net_device *)data; struct ec_device *edev; - if (dev_net(dev) != &init_net) + if (!net_eq(dev_net(dev), &init_net)) return NOTIFY_DONE; switch (msg) { diff --git a/net/ieee80211/ieee80211_rx.c b/net/ieee80211/ieee80211_rx.c index 200ee1e63728..69dbc342a464 100644 --- a/net/ieee80211/ieee80211_rx.c +++ b/net/ieee80211/ieee80211_rx.c @@ -391,7 +391,7 @@ int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb, wstats.updated = 0; if (rx_stats->mask & IEEE80211_STATMASK_RSSI) { - wstats.level = rx_stats->rssi; + wstats.level = rx_stats->signal; wstats.updated |= IW_QUAL_LEVEL_UPDATED; } else wstats.updated |= IW_QUAL_LEVEL_INVALID; diff --git a/net/ieee80211/ieee80211_tx.c b/net/ieee80211/ieee80211_tx.c index d8b02603cbe5..d996547f7a62 100644 --- a/net/ieee80211/ieee80211_tx.c +++ b/net/ieee80211/ieee80211_tx.c @@ -542,90 +542,4 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev) return 1; } -/* Incoming 802.11 strucure is converted to a TXB - * a block of 802.11 fragment packets (stored as skbs) */ -int ieee80211_tx_frame(struct ieee80211_device *ieee, - struct ieee80211_hdr *frame, int hdr_len, int total_len, - int encrypt_mpdu) -{ - struct ieee80211_txb *txb = NULL; - unsigned long flags; - struct net_device_stats *stats = &ieee->stats; - struct sk_buff *skb_frag; - int priority = -1; - int fraglen = total_len; - int headroom = ieee->tx_headroom; - struct ieee80211_crypt_data *crypt = ieee->crypt[ieee->tx_keyidx]; - - spin_lock_irqsave(&ieee->lock, flags); - - if (encrypt_mpdu && (!ieee->sec.encrypt || !crypt)) - encrypt_mpdu = 0; - - /* If there is no driver handler to take the TXB, dont' bother - * creating it... */ - if (!ieee->hard_start_xmit) { - printk(KERN_WARNING "%s: No xmit handler.\n", ieee->dev->name); - goto success; - } - - if (unlikely(total_len < 24)) { - printk(KERN_WARNING "%s: skb too small (%d).\n", - ieee->dev->name, total_len); - goto success; - } - - if (encrypt_mpdu) { - frame->frame_ctl |= cpu_to_le16(IEEE80211_FCTL_PROTECTED); - fraglen += crypt->ops->extra_mpdu_prefix_len + - crypt->ops->extra_mpdu_postfix_len; - headroom += crypt->ops->extra_mpdu_prefix_len; - } - - /* When we allocate the TXB we allocate enough space for the reserve - * and full fragment bytes (bytes_per_frag doesn't include prefix, - * postfix, header, FCS, etc.) */ - txb = ieee80211_alloc_txb(1, fraglen, headroom, GFP_ATOMIC); - if (unlikely(!txb)) { - printk(KERN_WARNING "%s: Could not allocate TXB\n", - ieee->dev->name); - goto failed; - } - txb->encrypted = 0; - txb->payload_size = fraglen; - - skb_frag = txb->fragments[0]; - - memcpy(skb_put(skb_frag, total_len), frame, total_len); - - if (ieee->config & - (CFG_IEEE80211_COMPUTE_FCS | CFG_IEEE80211_RESERVE_FCS)) - skb_put(skb_frag, 4); - - /* To avoid overcomplicating things, we do the corner-case frame - * encryption in software. The only real situation where encryption is - * needed here is during software-based shared key authentication. */ - if (encrypt_mpdu) - ieee80211_encrypt_fragment(ieee, skb_frag, hdr_len); - - success: - spin_unlock_irqrestore(&ieee->lock, flags); - - if (txb) { - if ((*ieee->hard_start_xmit) (txb, ieee->dev, priority) == 0) { - stats->tx_packets++; - stats->tx_bytes += txb->payload_size; - return 0; - } - ieee80211_txb_free(txb); - } - return 0; - - failed: - spin_unlock_irqrestore(&ieee->lock, flags); - stats->tx_errors++; - return 1; -} - -EXPORT_SYMBOL(ieee80211_tx_frame); EXPORT_SYMBOL(ieee80211_txb_free); diff --git a/net/ieee80211/ieee80211_wx.c b/net/ieee80211/ieee80211_wx.c index 623489afa62c..973832dd7faf 100644 --- a/net/ieee80211/ieee80211_wx.c +++ b/net/ieee80211/ieee80211_wx.c @@ -43,8 +43,9 @@ static const char *ieee80211_modes[] = { #define MAX_CUSTOM_LEN 64 static char *ieee80211_translate_scan(struct ieee80211_device *ieee, - char *start, char *stop, - struct ieee80211_network *network) + char *start, char *stop, + struct ieee80211_network *network, + struct iw_request_info *info) { char custom[MAX_CUSTOM_LEN]; char *p; @@ -57,7 +58,7 @@ static char *ieee80211_translate_scan(struct ieee80211_device *ieee, iwe.cmd = SIOCGIWAP; iwe.u.ap_addr.sa_family = ARPHRD_ETHER; memcpy(iwe.u.ap_addr.sa_data, network->bssid, ETH_ALEN); - start = iwe_stream_add_event(start, stop, &iwe, IW_EV_ADDR_LEN); + start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_ADDR_LEN); /* Remaining entries will be displayed in the order we provide them */ @@ -66,17 +67,19 @@ static char *ieee80211_translate_scan(struct ieee80211_device *ieee, iwe.u.data.flags = 1; if (network->flags & NETWORK_EMPTY_ESSID) { iwe.u.data.length = sizeof("<hidden>"); - start = iwe_stream_add_point(start, stop, &iwe, "<hidden>"); + start = iwe_stream_add_point(info, start, stop, + &iwe, "<hidden>"); } else { iwe.u.data.length = min(network->ssid_len, (u8) 32); - start = iwe_stream_add_point(start, stop, &iwe, network->ssid); + start = iwe_stream_add_point(info, start, stop, + &iwe, network->ssid); } /* Add the protocol name */ iwe.cmd = SIOCGIWNAME; snprintf(iwe.u.name, IFNAMSIZ, "IEEE 802.11%s", ieee80211_modes[network->mode]); - start = iwe_stream_add_event(start, stop, &iwe, IW_EV_CHAR_LEN); + start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_CHAR_LEN); /* Add mode */ iwe.cmd = SIOCGIWMODE; @@ -86,7 +89,8 @@ static char *ieee80211_translate_scan(struct ieee80211_device *ieee, else iwe.u.mode = IW_MODE_ADHOC; - start = iwe_stream_add_event(start, stop, &iwe, IW_EV_UINT_LEN); + start = iwe_stream_add_event(info, start, stop, + &iwe, IW_EV_UINT_LEN); } /* Add channel and frequency */ @@ -95,7 +99,7 @@ static char *ieee80211_translate_scan(struct ieee80211_device *ieee, iwe.u.freq.m = ieee80211_channel_to_freq(ieee, network->channel); iwe.u.freq.e = 6; iwe.u.freq.i = 0; - start = iwe_stream_add_event(start, stop, &iwe, IW_EV_FREQ_LEN); + start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_FREQ_LEN); /* Add encryption capability */ iwe.cmd = SIOCGIWENCODE; @@ -104,12 +108,13 @@ static char *ieee80211_translate_scan(struct ieee80211_device *ieee, else iwe.u.data.flags = IW_ENCODE_DISABLED; iwe.u.data.length = 0; - start = iwe_stream_add_point(start, stop, &iwe, network->ssid); + start = iwe_stream_add_point(info, start, stop, + &iwe, network->ssid); /* Add basic and extended rates */ /* Rate : stuffing multiple values in a single event require a bit * more of magic - Jean II */ - current_val = start + IW_EV_LCP_LEN; + current_val = start + iwe_stream_lcp_len(info); iwe.cmd = SIOCGIWRATE; /* Those two flags are ignored... */ iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0; @@ -124,17 +129,19 @@ static char *ieee80211_translate_scan(struct ieee80211_device *ieee, /* Bit rate given in 500 kb/s units (+ 0x80) */ iwe.u.bitrate.value = ((rate & 0x7f) * 500000); /* Add new value to event */ - current_val = iwe_stream_add_value(start, current_val, stop, &iwe, IW_EV_PARAM_LEN); + current_val = iwe_stream_add_value(info, start, current_val, + stop, &iwe, IW_EV_PARAM_LEN); } for (; j < network->rates_ex_len; j++) { rate = network->rates_ex[j] & 0x7F; /* Bit rate given in 500 kb/s units (+ 0x80) */ iwe.u.bitrate.value = ((rate & 0x7f) * 500000); /* Add new value to event */ - current_val = iwe_stream_add_value(start, current_val, stop, &iwe, IW_EV_PARAM_LEN); + current_val = iwe_stream_add_value(info, start, current_val, + stop, &iwe, IW_EV_PARAM_LEN); } /* Check if we added any rate */ - if((current_val - start) > IW_EV_LCP_LEN) + if ((current_val - start) > iwe_stream_lcp_len(info)) start = current_val; /* Add quality statistics */ @@ -181,14 +188,14 @@ static char *ieee80211_translate_scan(struct ieee80211_device *ieee, iwe.u.qual.level = network->stats.signal; } - start = iwe_stream_add_event(start, stop, &iwe, IW_EV_QUAL_LEN); + start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_QUAL_LEN); iwe.cmd = IWEVCUSTOM; p = custom; iwe.u.data.length = p - custom; if (iwe.u.data.length) - start = iwe_stream_add_point(start, stop, &iwe, custom); + start = iwe_stream_add_point(info, start, stop, &iwe, custom); memset(&iwe, 0, sizeof(iwe)); if (network->wpa_ie_len) { @@ -196,7 +203,7 @@ static char *ieee80211_translate_scan(struct ieee80211_device *ieee, memcpy(buf, network->wpa_ie, network->wpa_ie_len); iwe.cmd = IWEVGENIE; iwe.u.data.length = network->wpa_ie_len; - start = iwe_stream_add_point(start, stop, &iwe, buf); + start = iwe_stream_add_point(info, start, stop, &iwe, buf); } memset(&iwe, 0, sizeof(iwe)); @@ -205,7 +212,7 @@ static char *ieee80211_translate_scan(struct ieee80211_device *ieee, memcpy(buf, network->rsn_ie, network->rsn_ie_len); iwe.cmd = IWEVGENIE; iwe.u.data.length = network->rsn_ie_len; - start = iwe_stream_add_point(start, stop, &iwe, buf); + start = iwe_stream_add_point(info, start, stop, &iwe, buf); } /* Add EXTRA: Age to display seconds since last beacon/probe response @@ -217,7 +224,7 @@ static char *ieee80211_translate_scan(struct ieee80211_device *ieee, jiffies_to_msecs(jiffies - network->last_scanned)); iwe.u.data.length = p - custom; if (iwe.u.data.length) - start = iwe_stream_add_point(start, stop, &iwe, custom); + start = iwe_stream_add_point(info, start, stop, &iwe, custom); /* Add spectrum management information */ iwe.cmd = -1; @@ -238,7 +245,7 @@ static char *ieee80211_translate_scan(struct ieee80211_device *ieee, if (iwe.cmd == IWEVCUSTOM) { iwe.u.data.length = p - custom; - start = iwe_stream_add_point(start, stop, &iwe, custom); + start = iwe_stream_add_point(info, start, stop, &iwe, custom); } return start; @@ -272,7 +279,8 @@ int ieee80211_wx_get_scan(struct ieee80211_device *ieee, if (ieee->scan_age == 0 || time_after(network->last_scanned + ieee->scan_age, jiffies)) - ev = ieee80211_translate_scan(ieee, ev, stop, network); + ev = ieee80211_translate_scan(ieee, ev, stop, network, + info); else IEEE80211_DEBUG_SCAN("Not showing network '%s (" "%s)' due to age (%dms).\n", @@ -744,98 +752,9 @@ int ieee80211_wx_get_encodeext(struct ieee80211_device *ieee, return 0; } -int ieee80211_wx_set_auth(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct ieee80211_device *ieee = netdev_priv(dev); - unsigned long flags; - int err = 0; - - spin_lock_irqsave(&ieee->lock, flags); - - switch (wrqu->param.flags & IW_AUTH_INDEX) { - case IW_AUTH_WPA_VERSION: - case IW_AUTH_CIPHER_PAIRWISE: - case IW_AUTH_CIPHER_GROUP: - case IW_AUTH_KEY_MGMT: - /* - * Host AP driver does not use these parameters and allows - * wpa_supplicant to control them internally. - */ - break; - case IW_AUTH_TKIP_COUNTERMEASURES: - break; /* FIXME */ - case IW_AUTH_DROP_UNENCRYPTED: - ieee->drop_unencrypted = !!wrqu->param.value; - break; - case IW_AUTH_80211_AUTH_ALG: - break; /* FIXME */ - case IW_AUTH_WPA_ENABLED: - ieee->privacy_invoked = ieee->wpa_enabled = !!wrqu->param.value; - break; - case IW_AUTH_RX_UNENCRYPTED_EAPOL: - ieee->ieee802_1x = !!wrqu->param.value; - break; - case IW_AUTH_PRIVACY_INVOKED: - ieee->privacy_invoked = !!wrqu->param.value; - break; - default: - err = -EOPNOTSUPP; - break; - } - spin_unlock_irqrestore(&ieee->lock, flags); - return err; -} - -int ieee80211_wx_get_auth(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct ieee80211_device *ieee = netdev_priv(dev); - unsigned long flags; - int err = 0; - - spin_lock_irqsave(&ieee->lock, flags); - - switch (wrqu->param.flags & IW_AUTH_INDEX) { - case IW_AUTH_WPA_VERSION: - case IW_AUTH_CIPHER_PAIRWISE: - case IW_AUTH_CIPHER_GROUP: - case IW_AUTH_KEY_MGMT: - case IW_AUTH_TKIP_COUNTERMEASURES: /* FIXME */ - case IW_AUTH_80211_AUTH_ALG: /* FIXME */ - /* - * Host AP driver does not use these parameters and allows - * wpa_supplicant to control them internally. - */ - err = -EOPNOTSUPP; - break; - case IW_AUTH_DROP_UNENCRYPTED: - wrqu->param.value = ieee->drop_unencrypted; - break; - case IW_AUTH_WPA_ENABLED: - wrqu->param.value = ieee->wpa_enabled; - break; - case IW_AUTH_RX_UNENCRYPTED_EAPOL: - wrqu->param.value = ieee->ieee802_1x; - break; - default: - err = -EOPNOTSUPP; - break; - } - spin_unlock_irqrestore(&ieee->lock, flags); - return err; -} - EXPORT_SYMBOL(ieee80211_wx_set_encodeext); EXPORT_SYMBOL(ieee80211_wx_get_encodeext); EXPORT_SYMBOL(ieee80211_wx_get_scan); EXPORT_SYMBOL(ieee80211_wx_set_encode); EXPORT_SYMBOL(ieee80211_wx_get_encode); - -EXPORT_SYMBOL_GPL(ieee80211_wx_set_auth); -EXPORT_SYMBOL_GPL(ieee80211_wx_get_auth); diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c index 24eca23c2db3..dd919d84285f 100644 --- a/net/ipv4/af_inet.c +++ b/net/ipv4/af_inet.c @@ -5,8 +5,6 @@ * * PF_INET protocol family socket handler. * - * Version: $Id: af_inet.c,v 1.137 2002/02/01 22:01:03 davem Exp $ - * * Authors: Ross Biro * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG> * Florian La Roche, <flla@stud.uni-sb.de> @@ -112,12 +110,11 @@ #include <net/ipip.h> #include <net/inet_common.h> #include <net/xfrm.h> +#include <net/net_namespace.h> #ifdef CONFIG_IP_MROUTE #include <linux/mroute.h> #endif -DEFINE_SNMP_STAT(struct linux_mib, net_statistics) __read_mostly; - extern void ip_mc_drop_socket(struct sock *sk); /* The inetsw table contains everything that inet_create needs to @@ -1341,50 +1338,70 @@ static struct net_protocol icmp_protocol = { .netns_ok = 1, }; -static int __init init_ipv4_mibs(void) +static __net_init int ipv4_mib_init_net(struct net *net) { - if (snmp_mib_init((void **)net_statistics, - sizeof(struct linux_mib)) < 0) - goto err_net_mib; - if (snmp_mib_init((void **)ip_statistics, - sizeof(struct ipstats_mib)) < 0) - goto err_ip_mib; - if (snmp_mib_init((void **)icmp_statistics, - sizeof(struct icmp_mib)) < 0) - goto err_icmp_mib; - if (snmp_mib_init((void **)icmpmsg_statistics, - sizeof(struct icmpmsg_mib)) < 0) - goto err_icmpmsg_mib; - if (snmp_mib_init((void **)tcp_statistics, + if (snmp_mib_init((void **)net->mib.tcp_statistics, sizeof(struct tcp_mib)) < 0) goto err_tcp_mib; - if (snmp_mib_init((void **)udp_statistics, + if (snmp_mib_init((void **)net->mib.ip_statistics, + sizeof(struct ipstats_mib)) < 0) + goto err_ip_mib; + if (snmp_mib_init((void **)net->mib.net_statistics, + sizeof(struct linux_mib)) < 0) + goto err_net_mib; + if (snmp_mib_init((void **)net->mib.udp_statistics, sizeof(struct udp_mib)) < 0) goto err_udp_mib; - if (snmp_mib_init((void **)udplite_statistics, + if (snmp_mib_init((void **)net->mib.udplite_statistics, sizeof(struct udp_mib)) < 0) goto err_udplite_mib; + if (snmp_mib_init((void **)net->mib.icmp_statistics, + sizeof(struct icmp_mib)) < 0) + goto err_icmp_mib; + if (snmp_mib_init((void **)net->mib.icmpmsg_statistics, + sizeof(struct icmpmsg_mib)) < 0) + goto err_icmpmsg_mib; - tcp_mib_init(); - + tcp_mib_init(net); return 0; -err_udplite_mib: - snmp_mib_free((void **)udp_statistics); -err_udp_mib: - snmp_mib_free((void **)tcp_statistics); -err_tcp_mib: - snmp_mib_free((void **)icmpmsg_statistics); err_icmpmsg_mib: - snmp_mib_free((void **)icmp_statistics); + snmp_mib_free((void **)net->mib.icmp_statistics); err_icmp_mib: - snmp_mib_free((void **)ip_statistics); -err_ip_mib: - snmp_mib_free((void **)net_statistics); + snmp_mib_free((void **)net->mib.udplite_statistics); +err_udplite_mib: + snmp_mib_free((void **)net->mib.udp_statistics); +err_udp_mib: + snmp_mib_free((void **)net->mib.net_statistics); err_net_mib: + snmp_mib_free((void **)net->mib.ip_statistics); +err_ip_mib: + snmp_mib_free((void **)net->mib.tcp_statistics); +err_tcp_mib: return -ENOMEM; } +static __net_exit void ipv4_mib_exit_net(struct net *net) +{ + snmp_mib_free((void **)net->mib.icmpmsg_statistics); + snmp_mib_free((void **)net->mib.icmp_statistics); + snmp_mib_free((void **)net->mib.udplite_statistics); + snmp_mib_free((void **)net->mib.udp_statistics); + snmp_mib_free((void **)net->mib.net_statistics); + snmp_mib_free((void **)net->mib.ip_statistics); + snmp_mib_free((void **)net->mib.tcp_statistics); +} + +static __net_initdata struct pernet_operations ipv4_mib_ops = { + .init = ipv4_mib_init_net, + .exit = ipv4_mib_exit_net, +}; + +static int __init init_ipv4_mibs(void) +{ + return register_pernet_subsys(&ipv4_mib_ops); +} + static int ipv4_proc_init(void); /* @@ -1481,14 +1498,15 @@ static int __init inet_init(void) * Initialise the multicast router */ #if defined(CONFIG_IP_MROUTE) - ip_mr_init(); + if (ip_mr_init()) + printk(KERN_CRIT "inet_init: Cannot init ipv4 mroute\n"); #endif /* * Initialise per-cpu ipv4 mibs */ if (init_ipv4_mibs()) - printk(KERN_CRIT "inet_init: Cannot init ipv4 mibs\n"); ; + printk(KERN_CRIT "inet_init: Cannot init ipv4 mibs\n"); ipv4_proc_init(); @@ -1560,5 +1578,4 @@ EXPORT_SYMBOL(inet_sock_destruct); EXPORT_SYMBOL(inet_stream_connect); EXPORT_SYMBOL(inet_stream_ops); EXPORT_SYMBOL(inet_unregister_protosw); -EXPORT_SYMBOL(net_statistics); EXPORT_SYMBOL(sysctl_ip_nonlocal_bind); diff --git a/net/ipv4/arp.c b/net/ipv4/arp.c index 9b539fa9fe18..b043eda60b04 100644 --- a/net/ipv4/arp.c +++ b/net/ipv4/arp.c @@ -1,7 +1,5 @@ /* linux/net/ipv4/arp.c * - * Version: $Id: arp.c,v 1.99 2001/08/30 22:55:42 davem Exp $ - * * Copyright (C) 1994 by Florian La Roche * * This module implements the Address Resolution Protocol ARP (RFC 826), @@ -423,11 +421,12 @@ static int arp_filter(__be32 sip, __be32 tip, struct net_device *dev) struct rtable *rt; int flag = 0; /*unsigned long now; */ + struct net *net = dev_net(dev); - if (ip_route_output_key(dev_net(dev), &rt, &fl) < 0) + if (ip_route_output_key(net, &rt, &fl) < 0) return 1; if (rt->u.dst.dev != dev) { - NET_INC_STATS_BH(LINUX_MIB_ARPFILTER); + NET_INC_STATS_BH(net, LINUX_MIB_ARPFILTER); flag = 1; } ip_rt_put(rt); @@ -1199,7 +1198,7 @@ static int arp_netdev_event(struct notifier_block *this, unsigned long event, vo switch (event) { case NETDEV_CHANGEADDR: neigh_changeaddr(&arp_tbl, dev); - rt_cache_flush(0); + rt_cache_flush(dev_net(dev), 0); break; default: break; diff --git a/net/ipv4/datagram.c b/net/ipv4/datagram.c index 0c0c73f368ce..5e6c5a0f3fde 100644 --- a/net/ipv4/datagram.c +++ b/net/ipv4/datagram.c @@ -52,7 +52,7 @@ int ip4_datagram_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len) inet->sport, usin->sin_port, sk, 1); if (err) { if (err == -ENETUNREACH) - IP_INC_STATS_BH(IPSTATS_MIB_OUTNOROUTES); + IP_INC_STATS_BH(sock_net(sk), IPSTATS_MIB_OUTNOROUTES); return err; } diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c index 79a7ef6209ff..2e667e2f90df 100644 --- a/net/ipv4/devinet.c +++ b/net/ipv4/devinet.c @@ -1,8 +1,6 @@ /* * NET3 IP device support routines. * - * Version: $Id: devinet.c,v 1.44 2001/10/31 21:55:54 davem Exp $ - * * 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 @@ -170,6 +168,8 @@ static struct in_device *inetdev_init(struct net_device *dev) in_dev->dev = dev; if ((in_dev->arp_parms = neigh_parms_alloc(dev, &arp_tbl)) == NULL) goto out_kfree; + if (IPV4_DEVCONF(in_dev->cnf, FORWARDING)) + dev_disable_lro(dev); /* Reference in_dev->dev */ dev_hold(dev); /* Account for reference dev->ip_ptr (below) */ @@ -1013,7 +1013,7 @@ static void inetdev_changename(struct net_device *dev, struct in_device *in_dev) memcpy(old, ifa->ifa_label, IFNAMSIZ); memcpy(ifa->ifa_label, dev->name, IFNAMSIZ); if (named++ == 0) - continue; + goto skip; dot = strchr(old, ':'); if (dot == NULL) { sprintf(old, ":%d", named); @@ -1024,6 +1024,8 @@ static void inetdev_changename(struct net_device *dev, struct in_device *in_dev) } else { strcpy(ifa->ifa_label + (IFNAMSIZ - strlen(dot) - 1), dot); } +skip: + rtmsg_ifa(RTM_NEWADDR, ifa, NULL, 0); } } @@ -1241,6 +1243,8 @@ static void inet_forward_change(struct net *net) read_lock(&dev_base_lock); for_each_netdev(net, dev) { struct in_device *in_dev; + if (on) + dev_disable_lro(dev); rcu_read_lock(); in_dev = __in_dev_get_rcu(dev); if (in_dev) @@ -1248,8 +1252,6 @@ static void inet_forward_change(struct net *net) rcu_read_unlock(); } read_unlock(&dev_base_lock); - - rt_cache_flush(0); } static int devinet_conf_proc(ctl_table *ctl, int write, @@ -1335,10 +1337,19 @@ static int devinet_sysctl_forward(ctl_table *ctl, int write, if (write && *valp != val) { struct net *net = ctl->extra2; - if (valp == &IPV4_DEVCONF_ALL(net, FORWARDING)) - inet_forward_change(net); - else if (valp != &IPV4_DEVCONF_DFLT(net, FORWARDING)) - rt_cache_flush(0); + if (valp != &IPV4_DEVCONF_DFLT(net, FORWARDING)) { + rtnl_lock(); + if (valp == &IPV4_DEVCONF_ALL(net, FORWARDING)) { + inet_forward_change(net); + } else if (*valp) { + struct ipv4_devconf *cnf = ctl->extra1; + struct in_device *idev = + container_of(cnf, struct in_device, cnf); + dev_disable_lro(idev->dev); + } + rtnl_unlock(); + rt_cache_flush(net, 0); + } } return ret; @@ -1351,9 +1362,10 @@ int ipv4_doint_and_flush(ctl_table *ctl, int write, int *valp = ctl->data; int val = *valp; int ret = proc_dointvec(ctl, write, filp, buffer, lenp, ppos); + struct net *net = ctl->extra2; if (write && *valp != val) - rt_cache_flush(0); + rt_cache_flush(net, 0); return ret; } @@ -1364,9 +1376,10 @@ int ipv4_doint_and_flush_strategy(ctl_table *table, int __user *name, int nlen, { int ret = devinet_conf_sysctl(table, name, nlen, oldval, oldlenp, newval, newlen); + struct net *net = table->extra2; if (ret == 1) - rt_cache_flush(0); + rt_cache_flush(net, 0); return ret; } diff --git a/net/ipv4/fib_frontend.c b/net/ipv4/fib_frontend.c index 0b2ac6a3d903..65c1503f8cc8 100644 --- a/net/ipv4/fib_frontend.c +++ b/net/ipv4/fib_frontend.c @@ -5,8 +5,6 @@ * * IPv4 Forwarding Information Base: FIB frontend. * - * Version: $Id: fib_frontend.c,v 1.26 2001/10/31 21:55:54 davem Exp $ - * * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru> * * This program is free software; you can redistribute it and/or @@ -146,7 +144,7 @@ static void fib_flush(struct net *net) } if (flushed) - rt_cache_flush(-1); + rt_cache_flush(net, -1); } /* @@ -899,21 +897,22 @@ static void fib_disable_ip(struct net_device *dev, int force) { if (fib_sync_down_dev(dev, force)) fib_flush(dev_net(dev)); - rt_cache_flush(0); + rt_cache_flush(dev_net(dev), 0); arp_ifdown(dev); } static int fib_inetaddr_event(struct notifier_block *this, unsigned long event, void *ptr) { struct in_ifaddr *ifa = (struct in_ifaddr*)ptr; + struct net_device *dev = ifa->ifa_dev->dev; switch (event) { case NETDEV_UP: fib_add_ifaddr(ifa); #ifdef CONFIG_IP_ROUTE_MULTIPATH - fib_sync_up(ifa->ifa_dev->dev); + fib_sync_up(dev); #endif - rt_cache_flush(-1); + rt_cache_flush(dev_net(dev), -1); break; case NETDEV_DOWN: fib_del_ifaddr(ifa); @@ -921,9 +920,9 @@ static int fib_inetaddr_event(struct notifier_block *this, unsigned long event, /* Last address was deleted from this interface. Disable IP. */ - fib_disable_ip(ifa->ifa_dev->dev, 1); + fib_disable_ip(dev, 1); } else { - rt_cache_flush(-1); + rt_cache_flush(dev_net(dev), -1); } break; } @@ -951,14 +950,14 @@ static int fib_netdev_event(struct notifier_block *this, unsigned long event, vo #ifdef CONFIG_IP_ROUTE_MULTIPATH fib_sync_up(dev); #endif - rt_cache_flush(-1); + rt_cache_flush(dev_net(dev), -1); break; case NETDEV_DOWN: fib_disable_ip(dev, 0); break; case NETDEV_CHANGEMTU: case NETDEV_CHANGE: - rt_cache_flush(0); + rt_cache_flush(dev_net(dev), 0); break; } return NOTIFY_DONE; diff --git a/net/ipv4/fib_hash.c b/net/ipv4/fib_hash.c index 2e2fc3376ac9..c8cac6c7f881 100644 --- a/net/ipv4/fib_hash.c +++ b/net/ipv4/fib_hash.c @@ -5,8 +5,6 @@ * * IPv4 FIB: lookup engine and maintenance routines. * - * Version: $Id: fib_hash.c,v 1.13 2001/10/31 21:55:54 davem Exp $ - * * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru> * * This program is free software; you can redistribute it and/or @@ -474,7 +472,7 @@ static int fn_hash_insert(struct fib_table *tb, struct fib_config *cfg) fib_release_info(fi_drop); if (state & FA_S_ACCESSED) - rt_cache_flush(-1); + rt_cache_flush(cfg->fc_nlinfo.nl_net, -1); rtmsg_fib(RTM_NEWROUTE, key, fa, cfg->fc_dst_len, tb->tb_id, &cfg->fc_nlinfo, NLM_F_REPLACE); return 0; @@ -534,7 +532,7 @@ static int fn_hash_insert(struct fib_table *tb, struct fib_config *cfg) if (new_f) fz->fz_nent++; - rt_cache_flush(-1); + rt_cache_flush(cfg->fc_nlinfo.nl_net, -1); rtmsg_fib(RTM_NEWROUTE, key, new_fa, cfg->fc_dst_len, tb->tb_id, &cfg->fc_nlinfo, 0); @@ -616,7 +614,7 @@ static int fn_hash_delete(struct fib_table *tb, struct fib_config *cfg) write_unlock_bh(&fib_hash_lock); if (fa->fa_state & FA_S_ACCESSED) - rt_cache_flush(-1); + rt_cache_flush(cfg->fc_nlinfo.nl_net, -1); fn_free_alias(fa, f); if (kill_fn) { fn_free_node(f); diff --git a/net/ipv4/fib_rules.c b/net/ipv4/fib_rules.c index 1fb56876be54..6080d7120821 100644 --- a/net/ipv4/fib_rules.c +++ b/net/ipv4/fib_rules.c @@ -258,9 +258,9 @@ static size_t fib4_rule_nlmsg_payload(struct fib_rule *rule) + nla_total_size(4); /* flow */ } -static void fib4_rule_flush_cache(void) +static void fib4_rule_flush_cache(struct fib_rules_ops *ops) { - rt_cache_flush(-1); + rt_cache_flush(ops->fro_net, -1); } static struct fib_rules_ops fib4_rules_ops_template = { diff --git a/net/ipv4/fib_semantics.c b/net/ipv4/fib_semantics.c index 0d4d72827e4b..ded2ae34eab1 100644 --- a/net/ipv4/fib_semantics.c +++ b/net/ipv4/fib_semantics.c @@ -5,8 +5,6 @@ * * IPv4 Forwarding Information Base: semantics. * - * Version: $Id: fib_semantics.c,v 1.19 2002/01/12 07:54:56 davem Exp $ - * * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru> * * This program is free software; you can redistribute it and/or diff --git a/net/ipv4/fib_trie.c b/net/ipv4/fib_trie.c index e1600ad8fb0e..5cb72786a8af 100644 --- a/net/ipv4/fib_trie.c +++ b/net/ipv4/fib_trie.c @@ -22,8 +22,6 @@ * IP-address lookup using LC-tries. Stefan Nilsson and Gunnar Karlsson * IEEE Journal on Selected Areas in Communications, 17(6):1083-1092, June 1999 * - * Version: $Id: fib_trie.c,v 1.3 2005/06/08 14:20:01 robert Exp $ - * * * Code from fib_hash has been reused which includes the following header: * @@ -1273,7 +1271,7 @@ static int fn_trie_insert(struct fib_table *tb, struct fib_config *cfg) fib_release_info(fi_drop); if (state & FA_S_ACCESSED) - rt_cache_flush(-1); + rt_cache_flush(cfg->fc_nlinfo.nl_net, -1); rtmsg_fib(RTM_NEWROUTE, htonl(key), new_fa, plen, tb->tb_id, &cfg->fc_nlinfo, NLM_F_REPLACE); @@ -1318,7 +1316,7 @@ static int fn_trie_insert(struct fib_table *tb, struct fib_config *cfg) list_add_tail_rcu(&new_fa->fa_list, (fa ? &fa->fa_list : fa_head)); - rt_cache_flush(-1); + rt_cache_flush(cfg->fc_nlinfo.nl_net, -1); rtmsg_fib(RTM_NEWROUTE, htonl(key), new_fa, plen, tb->tb_id, &cfg->fc_nlinfo, 0); succeeded: @@ -1661,7 +1659,7 @@ static int fn_trie_delete(struct fib_table *tb, struct fib_config *cfg) trie_leaf_remove(t, l); if (fa->fa_state & FA_S_ACCESSED) - rt_cache_flush(-1); + rt_cache_flush(cfg->fc_nlinfo.nl_net, -1); fib_release_info(fa->fa_info); alias_free_mem_rcu(fa); @@ -2253,25 +2251,7 @@ static int fib_triestat_seq_show(struct seq_file *seq, void *v) static int fib_triestat_seq_open(struct inode *inode, struct file *file) { - int err; - struct net *net; - - net = get_proc_net(inode); - if (net == NULL) - return -ENXIO; - err = single_open(file, fib_triestat_seq_show, net); - if (err < 0) { - put_net(net); - return err; - } - return 0; -} - -static int fib_triestat_seq_release(struct inode *ino, struct file *f) -{ - struct seq_file *seq = f->private_data; - put_net(seq->private); - return single_release(ino, f); + return single_open_net(inode, file, fib_triestat_seq_show); } static const struct file_operations fib_triestat_fops = { @@ -2279,7 +2259,7 @@ static const struct file_operations fib_triestat_fops = { .open = fib_triestat_seq_open, .read = seq_read, .llseek = seq_lseek, - .release = fib_triestat_seq_release, + .release = single_release_net, }; static struct node *fib_trie_get_idx(struct seq_file *seq, loff_t pos) diff --git a/net/ipv4/icmp.c b/net/ipv4/icmp.c index 87397351ddac..860558633b2c 100644 --- a/net/ipv4/icmp.c +++ b/net/ipv4/icmp.c @@ -3,8 +3,6 @@ * * Alan Cox, <alan@redhat.com> * - * Version: $Id: icmp.c,v 1.85 2002/02/01 22:01:03 davem Exp $ - * * 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 @@ -113,12 +111,6 @@ struct icmp_bxm { unsigned char optbuf[40]; }; -/* - * Statistics - */ -DEFINE_SNMP_STAT(struct icmp_mib, icmp_statistics) __read_mostly; -DEFINE_SNMP_STAT(struct icmpmsg_mib, icmpmsg_statistics) __read_mostly; - /* An array of errno for error messages from dest unreach. */ /* RFC 1122: 3.2.2.1 States that NET_UNREACH, HOST_UNREACH and SR_FAILED MUST be considered 'transient errs'. */ @@ -298,10 +290,10 @@ out: /* * Maintain the counters used in the SNMP statistics for outgoing ICMP */ -void icmp_out_count(unsigned char type) +void icmp_out_count(struct net *net, unsigned char type) { - ICMPMSGOUT_INC_STATS(type); - ICMP_INC_STATS(ICMP_MIB_OUTMSGS); + ICMPMSGOUT_INC_STATS(net, type); + ICMP_INC_STATS(net, ICMP_MIB_OUTMSGS); } /* @@ -765,7 +757,7 @@ static void icmp_unreach(struct sk_buff *skb) out: return; out_err: - ICMP_INC_STATS_BH(ICMP_MIB_INERRORS); + ICMP_INC_STATS_BH(net, ICMP_MIB_INERRORS); goto out; } @@ -805,7 +797,7 @@ static void icmp_redirect(struct sk_buff *skb) out: return; out_err: - ICMP_INC_STATS_BH(ICMP_MIB_INERRORS); + ICMP_INC_STATS_BH(dev_net(skb->dev), ICMP_MIB_INERRORS); goto out; } @@ -876,7 +868,7 @@ static void icmp_timestamp(struct sk_buff *skb) out: return; out_err: - ICMP_INC_STATS_BH(ICMP_MIB_INERRORS); + ICMP_INC_STATS_BH(dev_net(skb->dst->dev), ICMP_MIB_INERRORS); goto out; } @@ -975,6 +967,7 @@ int icmp_rcv(struct sk_buff *skb) { struct icmphdr *icmph; struct rtable *rt = skb->rtable; + struct net *net = dev_net(rt->u.dst.dev); if (!xfrm4_policy_check(NULL, XFRM_POLICY_IN, skb)) { int nh; @@ -995,7 +988,7 @@ int icmp_rcv(struct sk_buff *skb) skb_set_network_header(skb, nh); } - ICMP_INC_STATS_BH(ICMP_MIB_INMSGS); + ICMP_INC_STATS_BH(net, ICMP_MIB_INMSGS); switch (skb->ip_summed) { case CHECKSUM_COMPLETE: @@ -1013,7 +1006,7 @@ int icmp_rcv(struct sk_buff *skb) icmph = icmp_hdr(skb); - ICMPMSGIN_INC_STATS_BH(icmph->type); + ICMPMSGIN_INC_STATS_BH(net, icmph->type); /* * 18 is the highest 'known' ICMP type. Anything else is a mystery * @@ -1029,9 +1022,6 @@ int icmp_rcv(struct sk_buff *skb) */ if (rt->rt_flags & (RTCF_BROADCAST | RTCF_MULTICAST)) { - struct net *net; - - net = dev_net(rt->u.dst.dev); /* * RFC 1122: 3.2.2.6 An ICMP_ECHO to broadcast MAY be * silently ignored (we let user decide with a sysctl). @@ -1057,7 +1047,7 @@ drop: kfree_skb(skb); return 0; error: - ICMP_INC_STATS_BH(ICMP_MIB_INERRORS); + ICMP_INC_STATS_BH(net, ICMP_MIB_INERRORS); goto drop; } @@ -1217,5 +1207,4 @@ int __init icmp_init(void) EXPORT_SYMBOL(icmp_err_convert); EXPORT_SYMBOL(icmp_send); -EXPORT_SYMBOL(icmp_statistics); EXPORT_SYMBOL(xrlim_allow); diff --git a/net/ipv4/igmp.c b/net/ipv4/igmp.c index 2769dc4a4c84..6203ece53606 100644 --- a/net/ipv4/igmp.c +++ b/net/ipv4/igmp.c @@ -8,8 +8,6 @@ * the older version didn't come out right using gcc 2.5.8, the newer one * seems to fall out with gcc 2.6.2. * - * Version: $Id: igmp.c,v 1.47 2002/02/01 22:01:03 davem Exp $ - * * Authors: * Alan Cox <Alan.Cox@linux.org> * @@ -1198,7 +1196,7 @@ void ip_mc_inc_group(struct in_device *in_dev, __be32 addr) ASSERT_RTNL(); - if (dev_net(in_dev->dev) != &init_net) + if (!net_eq(dev_net(in_dev->dev), &init_net)) return; for (im=in_dev->mc_list; im; im=im->next) { @@ -1280,7 +1278,7 @@ void ip_mc_dec_group(struct in_device *in_dev, __be32 addr) ASSERT_RTNL(); - if (dev_net(in_dev->dev) != &init_net) + if (!net_eq(dev_net(in_dev->dev), &init_net)) return; for (ip=&in_dev->mc_list; (i=*ip)!=NULL; ip=&i->next) { @@ -1310,7 +1308,7 @@ void ip_mc_down(struct in_device *in_dev) ASSERT_RTNL(); - if (dev_net(in_dev->dev) != &init_net) + if (!net_eq(dev_net(in_dev->dev), &init_net)) return; for (i=in_dev->mc_list; i; i=i->next) @@ -1333,7 +1331,7 @@ void ip_mc_init_dev(struct in_device *in_dev) { ASSERT_RTNL(); - if (dev_net(in_dev->dev) != &init_net) + if (!net_eq(dev_net(in_dev->dev), &init_net)) return; in_dev->mc_tomb = NULL; @@ -1359,7 +1357,7 @@ void ip_mc_up(struct in_device *in_dev) ASSERT_RTNL(); - if (dev_net(in_dev->dev) != &init_net) + if (!net_eq(dev_net(in_dev->dev), &init_net)) return; ip_mc_inc_group(in_dev, IGMP_ALL_HOSTS); @@ -1378,7 +1376,7 @@ void ip_mc_destroy_dev(struct in_device *in_dev) ASSERT_RTNL(); - if (dev_net(in_dev->dev) != &init_net) + if (!net_eq(dev_net(in_dev->dev), &init_net)) return; /* Deactivate timers */ @@ -1762,7 +1760,7 @@ int ip_mc_join_group(struct sock *sk , struct ip_mreqn *imr) if (!ipv4_is_multicast(addr)) return -EINVAL; - if (sock_net(sk) != &init_net) + if (!net_eq(sock_net(sk), &init_net)) return -EPROTONOSUPPORT; rtnl_lock(); @@ -1833,7 +1831,7 @@ int ip_mc_leave_group(struct sock *sk, struct ip_mreqn *imr) u32 ifindex; int ret = -EADDRNOTAVAIL; - if (sock_net(sk) != &init_net) + if (!net_eq(sock_net(sk), &init_net)) return -EPROTONOSUPPORT; rtnl_lock(); @@ -1881,7 +1879,7 @@ int ip_mc_source(int add, int omode, struct sock *sk, struct if (!ipv4_is_multicast(addr)) return -EINVAL; - if (sock_net(sk) != &init_net) + if (!net_eq(sock_net(sk), &init_net)) return -EPROTONOSUPPORT; rtnl_lock(); @@ -2017,7 +2015,7 @@ int ip_mc_msfilter(struct sock *sk, struct ip_msfilter *msf, int ifindex) msf->imsf_fmode != MCAST_EXCLUDE) return -EINVAL; - if (sock_net(sk) != &init_net) + if (!net_eq(sock_net(sk), &init_net)) return -EPROTONOSUPPORT; rtnl_lock(); @@ -2100,7 +2098,7 @@ int ip_mc_msfget(struct sock *sk, struct ip_msfilter *msf, if (!ipv4_is_multicast(addr)) return -EINVAL; - if (sock_net(sk) != &init_net) + if (!net_eq(sock_net(sk), &init_net)) return -EPROTONOSUPPORT; rtnl_lock(); @@ -2165,7 +2163,7 @@ int ip_mc_gsfget(struct sock *sk, struct group_filter *gsf, if (!ipv4_is_multicast(addr)) return -EINVAL; - if (sock_net(sk) != &init_net) + if (!net_eq(sock_net(sk), &init_net)) return -EPROTONOSUPPORT; rtnl_lock(); @@ -2252,7 +2250,7 @@ void ip_mc_drop_socket(struct sock *sk) if (inet->mc_list == NULL) return; - if (sock_net(sk) != &init_net) + if (!net_eq(sock_net(sk), &init_net)) return; rtnl_lock(); diff --git a/net/ipv4/inet_connection_sock.c b/net/ipv4/inet_connection_sock.c index ec834480abe7..bb81c958b744 100644 --- a/net/ipv4/inet_connection_sock.c +++ b/net/ipv4/inet_connection_sock.c @@ -103,7 +103,8 @@ int inet_csk_get_port(struct sock *sk, unsigned short snum) rover = net_random() % remaining + low; do { - head = &hashinfo->bhash[inet_bhashfn(rover, hashinfo->bhash_size)]; + head = &hashinfo->bhash[inet_bhashfn(net, rover, + hashinfo->bhash_size)]; spin_lock(&head->lock); inet_bind_bucket_for_each(tb, node, &head->chain) if (tb->ib_net == net && tb->port == rover) @@ -130,7 +131,8 @@ int inet_csk_get_port(struct sock *sk, unsigned short snum) */ snum = rover; } else { - head = &hashinfo->bhash[inet_bhashfn(snum, hashinfo->bhash_size)]; + head = &hashinfo->bhash[inet_bhashfn(net, snum, + hashinfo->bhash_size)]; spin_lock(&head->lock); inet_bind_bucket_for_each(tb, node, &head->chain) if (tb->ib_net == net && tb->port == snum) @@ -336,15 +338,16 @@ struct dst_entry* inet_csk_route_req(struct sock *sk, .uli_u = { .ports = { .sport = inet_sk(sk)->sport, .dport = ireq->rmt_port } } }; + struct net *net = sock_net(sk); security_req_classify_flow(req, &fl); - if (ip_route_output_flow(sock_net(sk), &rt, &fl, sk, 0)) { - IP_INC_STATS_BH(IPSTATS_MIB_OUTNOROUTES); + if (ip_route_output_flow(net, &rt, &fl, sk, 0)) { + IP_INC_STATS_BH(net, IPSTATS_MIB_OUTNOROUTES); return NULL; } if (opt && opt->is_strictroute && rt->rt_dst != rt->rt_gateway) { ip_rt_put(rt); - IP_INC_STATS_BH(IPSTATS_MIB_OUTNOROUTES); + IP_INC_STATS_BH(net, IPSTATS_MIB_OUTNOROUTES); return NULL; } return &rt->u.dst; diff --git a/net/ipv4/inet_diag.c b/net/ipv4/inet_diag.c index da97695e7096..c10036e7a463 100644 --- a/net/ipv4/inet_diag.c +++ b/net/ipv4/inet_diag.c @@ -1,8 +1,6 @@ /* * inet_diag.c Module for monitoring INET transport protocols sockets. * - * Version: $Id: inet_diag.c,v 1.3 2002/02/01 22:01:04 davem Exp $ - * * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru> * * This program is free software; you can redistribute it and/or diff --git a/net/ipv4/inet_hashtables.c b/net/ipv4/inet_hashtables.c index 2023d37b2708..115f53722d20 100644 --- a/net/ipv4/inet_hashtables.c +++ b/net/ipv4/inet_hashtables.c @@ -70,7 +70,8 @@ void inet_bind_hash(struct sock *sk, struct inet_bind_bucket *tb, static void __inet_put_port(struct sock *sk) { struct inet_hashinfo *hashinfo = sk->sk_prot->h.hashinfo; - const int bhash = inet_bhashfn(inet_sk(sk)->num, hashinfo->bhash_size); + const int bhash = inet_bhashfn(sock_net(sk), inet_sk(sk)->num, + hashinfo->bhash_size); struct inet_bind_hashbucket *head = &hashinfo->bhash[bhash]; struct inet_bind_bucket *tb; @@ -95,7 +96,8 @@ EXPORT_SYMBOL(inet_put_port); void __inet_inherit_port(struct sock *sk, struct sock *child) { struct inet_hashinfo *table = sk->sk_prot->h.hashinfo; - const int bhash = inet_bhashfn(inet_sk(child)->num, table->bhash_size); + const int bhash = inet_bhashfn(sock_net(sk), inet_sk(child)->num, + table->bhash_size); struct inet_bind_hashbucket *head = &table->bhash[bhash]; struct inet_bind_bucket *tb; @@ -192,7 +194,7 @@ struct sock *__inet_lookup_listener(struct net *net, const struct hlist_head *head; read_lock(&hashinfo->lhash_lock); - head = &hashinfo->listening_hash[inet_lhashfn(hnum)]; + head = &hashinfo->listening_hash[inet_lhashfn(net, hnum)]; if (!hlist_empty(head)) { const struct inet_sock *inet = inet_sk((sk = __sk_head(head))); @@ -225,7 +227,7 @@ struct sock * __inet_lookup_established(struct net *net, /* Optimize here for direct hit, only listening connections can * have wildcards anyways. */ - unsigned int hash = inet_ehashfn(daddr, hnum, saddr, sport); + unsigned int hash = inet_ehashfn(net, daddr, hnum, saddr, sport); struct inet_ehash_bucket *head = inet_ehash_bucket(hashinfo, hash); rwlock_t *lock = inet_ehash_lockp(hashinfo, hash); @@ -265,13 +267,13 @@ static int __inet_check_established(struct inet_timewait_death_row *death_row, int dif = sk->sk_bound_dev_if; INET_ADDR_COOKIE(acookie, saddr, daddr) const __portpair ports = INET_COMBINED_PORTS(inet->dport, lport); - unsigned int hash = inet_ehashfn(daddr, lport, saddr, inet->dport); + struct net *net = sock_net(sk); + unsigned int hash = inet_ehashfn(net, daddr, lport, saddr, inet->dport); struct inet_ehash_bucket *head = inet_ehash_bucket(hinfo, hash); rwlock_t *lock = inet_ehash_lockp(hinfo, hash); struct sock *sk2; const struct hlist_node *node; struct inet_timewait_sock *tw; - struct net *net = sock_net(sk); prefetch(head->chain.first); write_lock(lock); @@ -310,11 +312,11 @@ unique: if (twp) { *twp = tw; - NET_INC_STATS_BH(LINUX_MIB_TIMEWAITRECYCLED); + NET_INC_STATS_BH(net, LINUX_MIB_TIMEWAITRECYCLED); } else if (tw) { /* Silly. Should hash-dance instead... */ inet_twsk_deschedule(tw, death_row); - NET_INC_STATS_BH(LINUX_MIB_TIMEWAITRECYCLED); + NET_INC_STATS_BH(net, LINUX_MIB_TIMEWAITRECYCLED); inet_twsk_put(tw); } @@ -438,7 +440,8 @@ int __inet_hash_connect(struct inet_timewait_death_row *death_row, local_bh_disable(); for (i = 1; i <= remaining; i++) { port = low + (i + offset) % remaining; - head = &hinfo->bhash[inet_bhashfn(port, hinfo->bhash_size)]; + head = &hinfo->bhash[inet_bhashfn(net, port, + hinfo->bhash_size)]; spin_lock(&head->lock); /* Does not bother with rcv_saddr checks, @@ -493,7 +496,7 @@ ok: goto out; } - head = &hinfo->bhash[inet_bhashfn(snum, hinfo->bhash_size)]; + head = &hinfo->bhash[inet_bhashfn(net, snum, hinfo->bhash_size)]; tb = inet_csk(sk)->icsk_bind_hash; spin_lock_bh(&head->lock); if (sk_head(&tb->owners) == sk && !sk->sk_bind_node.next) { diff --git a/net/ipv4/inet_timewait_sock.c b/net/ipv4/inet_timewait_sock.c index ce16e9ac24c1..75c2def8f9a0 100644 --- a/net/ipv4/inet_timewait_sock.c +++ b/net/ipv4/inet_timewait_sock.c @@ -32,7 +32,8 @@ static void __inet_twsk_kill(struct inet_timewait_sock *tw, write_unlock(lock); /* Disassociate with bind bucket. */ - bhead = &hashinfo->bhash[inet_bhashfn(tw->tw_num, hashinfo->bhash_size)]; + bhead = &hashinfo->bhash[inet_bhashfn(twsk_net(tw), tw->tw_num, + hashinfo->bhash_size)]; spin_lock(&bhead->lock); tb = tw->tw_tb; __hlist_del(&tw->tw_bind_node); @@ -81,7 +82,8 @@ void __inet_twsk_hashdance(struct inet_timewait_sock *tw, struct sock *sk, Note, that any socket with inet->num != 0 MUST be bound in binding cache, even if it is closed. */ - bhead = &hashinfo->bhash[inet_bhashfn(inet->num, hashinfo->bhash_size)]; + bhead = &hashinfo->bhash[inet_bhashfn(twsk_net(tw), inet->num, + hashinfo->bhash_size)]; spin_lock(&bhead->lock); tw->tw_tb = icsk->icsk_bind_hash; BUG_TRAP(icsk->icsk_bind_hash); @@ -158,6 +160,9 @@ rescan: __inet_twsk_del_dead_node(tw); spin_unlock(&twdr->death_lock); __inet_twsk_kill(tw, twdr->hashinfo); +#ifdef CONFIG_NET_NS + NET_INC_STATS_BH(twsk_net(tw), LINUX_MIB_TIMEWAITED); +#endif inet_twsk_put(tw); killed++; spin_lock(&twdr->death_lock); @@ -176,8 +181,9 @@ rescan: } twdr->tw_count -= killed; - NET_ADD_STATS_BH(LINUX_MIB_TIMEWAITED, killed); - +#ifndef CONFIG_NET_NS + NET_ADD_STATS_BH(&init_net, LINUX_MIB_TIMEWAITED, killed); +#endif return ret; } @@ -370,6 +376,9 @@ void inet_twdr_twcal_tick(unsigned long data) &twdr->twcal_row[slot]) { __inet_twsk_del_dead_node(tw); __inet_twsk_kill(tw, twdr->hashinfo); +#ifdef CONFIG_NET_NS + NET_INC_STATS_BH(twsk_net(tw), LINUX_MIB_TIMEWAITKILLED); +#endif inet_twsk_put(tw); killed++; } @@ -393,7 +402,9 @@ void inet_twdr_twcal_tick(unsigned long data) out: if ((twdr->tw_count -= killed) == 0) del_timer(&twdr->tw_timer); - NET_ADD_STATS_BH(LINUX_MIB_TIMEWAITKILLED, killed); +#ifndef CONFIG_NET_NS + NET_ADD_STATS_BH(&init_net, LINUX_MIB_TIMEWAITKILLED, killed); +#endif spin_unlock(&twdr->death_lock); } diff --git a/net/ipv4/inetpeer.c b/net/ipv4/inetpeer.c index af995198f643..a456ceeac3f2 100644 --- a/net/ipv4/inetpeer.c +++ b/net/ipv4/inetpeer.c @@ -3,8 +3,6 @@ * * This source is covered by the GNU GPL, the same as all kernel sources. * - * Version: $Id: inetpeer.c,v 1.7 2001/09/20 21:22:50 davem Exp $ - * * Authors: Andrey V. Savochkin <saw@msu.ru> */ diff --git a/net/ipv4/ip_forward.c b/net/ipv4/ip_forward.c index 4813c39b438b..450016b89a18 100644 --- a/net/ipv4/ip_forward.c +++ b/net/ipv4/ip_forward.c @@ -5,8 +5,6 @@ * * The IP forwarding functionality. * - * Version: $Id: ip_forward.c,v 1.48 2000/12/13 18:31:48 davem Exp $ - * * Authors: see ip.c * * Fixes: @@ -44,7 +42,7 @@ static int ip_forward_finish(struct sk_buff *skb) { struct ip_options * opt = &(IPCB(skb)->opt); - IP_INC_STATS_BH(IPSTATS_MIB_OUTFORWDATAGRAMS); + IP_INC_STATS_BH(dev_net(skb->dst->dev), IPSTATS_MIB_OUTFORWDATAGRAMS); if (unlikely(opt->optlen)) ip_forward_options(skb); @@ -58,6 +56,9 @@ int ip_forward(struct sk_buff *skb) struct rtable *rt; /* Route we use */ struct ip_options * opt = &(IPCB(skb)->opt); + if (skb_warn_if_lro(skb)) + goto drop; + if (!xfrm4_policy_check(NULL, XFRM_POLICY_FWD, skb)) goto drop; @@ -87,7 +88,7 @@ int ip_forward(struct sk_buff *skb) if (unlikely(skb->len > dst_mtu(&rt->u.dst) && !skb_is_gso(skb) && (ip_hdr(skb)->frag_off & htons(IP_DF))) && !skb->local_df) { - IP_INC_STATS(IPSTATS_MIB_FRAGFAILS); + IP_INC_STATS(dev_net(rt->u.dst.dev), IPSTATS_MIB_FRAGFAILS); icmp_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED, htonl(dst_mtu(&rt->u.dst))); goto drop; @@ -122,7 +123,7 @@ sr_failed: too_many_hops: /* Tell the sender its packet died... */ - IP_INC_STATS_BH(IPSTATS_MIB_INHDRERRORS); + IP_INC_STATS_BH(dev_net(skb->dst->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 37221f659159..38d38f058018 100644 --- a/net/ipv4/ip_fragment.c +++ b/net/ipv4/ip_fragment.c @@ -5,8 +5,6 @@ * * The IP fragmentation functionality. * - * Version: $Id: ip_fragment.c,v 1.59 2002/01/12 07:54:56 davem Exp $ - * * Authors: Fred N. van Kempen <waltje@uWalt.NL.Mugnet.ORG> * Alan Cox <Alan.Cox@linux.org> * @@ -180,7 +178,7 @@ static void ip_evictor(struct net *net) evicted = inet_frag_evictor(&net->ipv4.frags, &ip4_frags); if (evicted) - IP_ADD_STATS_BH(IPSTATS_MIB_REASMFAILS, evicted); + IP_ADD_STATS_BH(net, IPSTATS_MIB_REASMFAILS, evicted); } /* @@ -189,8 +187,10 @@ static void ip_evictor(struct net *net) static void ip_expire(unsigned long arg) { struct ipq *qp; + struct net *net; qp = container_of((struct inet_frag_queue *) arg, struct ipq, q); + net = container_of(qp->q.net, struct net, ipv4.frags); spin_lock(&qp->q.lock); @@ -199,14 +199,12 @@ static void ip_expire(unsigned long arg) ipq_kill(qp); - IP_INC_STATS_BH(IPSTATS_MIB_REASMTIMEOUT); - IP_INC_STATS_BH(IPSTATS_MIB_REASMFAILS); + IP_INC_STATS_BH(net, IPSTATS_MIB_REASMTIMEOUT); + IP_INC_STATS_BH(net, IPSTATS_MIB_REASMFAILS); if ((qp->q.last_in & INET_FRAG_FIRST_IN) && qp->q.fragments != NULL) { struct sk_buff *head = qp->q.fragments; - struct net *net; - net = container_of(qp->q.net, struct net, ipv4.frags); /* Send an ICMP "Fragment Reassembly Timeout" message. */ if ((head->dev = dev_get_by_index(net, qp->iif)) != NULL) { icmp_send(head, ICMP_TIME_EXCEEDED, ICMP_EXC_FRAGTIME, 0); @@ -263,7 +261,10 @@ static inline int ip_frag_too_far(struct ipq *qp) rc = qp->q.fragments && (end - start) > max; if (rc) { - IP_INC_STATS_BH(IPSTATS_MIB_REASMFAILS); + struct net *net; + + net = container_of(qp->q.net, struct net, ipv4.frags); + IP_INC_STATS_BH(net, IPSTATS_MIB_REASMFAILS); } return rc; @@ -547,7 +548,7 @@ static int ip_frag_reasm(struct ipq *qp, struct sk_buff *prev, iph = ip_hdr(head); iph->frag_off = 0; iph->tot_len = htons(len); - IP_INC_STATS_BH(IPSTATS_MIB_REASMOKS); + IP_INC_STATS_BH(dev_net(dev), IPSTATS_MIB_REASMOKS); qp->q.fragments = NULL; return 0; @@ -562,7 +563,7 @@ out_oversize: "Oversized IP packet from " NIPQUAD_FMT ".\n", NIPQUAD(qp->saddr)); out_fail: - IP_INC_STATS_BH(IPSTATS_MIB_REASMFAILS); + IP_INC_STATS_BH(dev_net(dev), IPSTATS_MIB_REASMFAILS); return err; } @@ -572,9 +573,9 @@ int ip_defrag(struct sk_buff *skb, u32 user) struct ipq *qp; struct net *net; - IP_INC_STATS_BH(IPSTATS_MIB_REASMREQDS); - net = skb->dev ? dev_net(skb->dev) : dev_net(skb->dst->dev); + IP_INC_STATS_BH(net, IPSTATS_MIB_REASMREQDS); + /* Start by cleaning up the memory. */ if (atomic_read(&net->ipv4.frags.mem) > net->ipv4.frags.high_thresh) ip_evictor(net); @@ -592,7 +593,7 @@ int ip_defrag(struct sk_buff *skb, u32 user) return ret; } - IP_INC_STATS_BH(IPSTATS_MIB_REASMFAILS); + IP_INC_STATS_BH(net, IPSTATS_MIB_REASMFAILS); kfree_skb(skb); return -ENOMEM; } @@ -600,7 +601,7 @@ int ip_defrag(struct sk_buff *skb, u32 user) #ifdef CONFIG_SYSCTL static int zero; -static struct ctl_table ip4_frags_ctl_table[] = { +static struct ctl_table ip4_frags_ns_ctl_table[] = { { .ctl_name = NET_IPV4_IPFRAG_HIGH_THRESH, .procname = "ipfrag_high_thresh", @@ -626,6 +627,10 @@ static struct ctl_table ip4_frags_ctl_table[] = { .proc_handler = &proc_dointvec_jiffies, .strategy = &sysctl_jiffies }, + { } +}; + +static struct ctl_table ip4_frags_ctl_table[] = { { .ctl_name = NET_IPV4_IPFRAG_SECRET_INTERVAL, .procname = "ipfrag_secret_interval", @@ -646,22 +651,20 @@ static struct ctl_table ip4_frags_ctl_table[] = { { } }; -static int ip4_frags_ctl_register(struct net *net) +static int ip4_frags_ns_ctl_register(struct net *net) { struct ctl_table *table; struct ctl_table_header *hdr; - table = ip4_frags_ctl_table; + table = ip4_frags_ns_ctl_table; if (net != &init_net) { - table = kmemdup(table, sizeof(ip4_frags_ctl_table), GFP_KERNEL); + table = kmemdup(table, sizeof(ip4_frags_ns_ctl_table), GFP_KERNEL); if (table == NULL) goto err_alloc; table[0].data = &net->ipv4.frags.high_thresh; table[1].data = &net->ipv4.frags.low_thresh; table[2].data = &net->ipv4.frags.timeout; - table[3].mode &= ~0222; - table[4].mode &= ~0222; } hdr = register_net_sysctl_table(net, net_ipv4_ctl_path, table); @@ -678,7 +681,7 @@ err_alloc: return -ENOMEM; } -static void ip4_frags_ctl_unregister(struct net *net) +static void ip4_frags_ns_ctl_unregister(struct net *net) { struct ctl_table *table; @@ -686,13 +689,22 @@ static void ip4_frags_ctl_unregister(struct net *net) unregister_net_sysctl_table(net->ipv4.frags_hdr); kfree(table); } + +static void ip4_frags_ctl_register(void) +{ + register_net_sysctl_rotable(net_ipv4_ctl_path, ip4_frags_ctl_table); +} #else -static inline int ip4_frags_ctl_register(struct net *net) +static inline int ip4_frags_ns_ctl_register(struct net *net) { return 0; } -static inline void ip4_frags_ctl_unregister(struct net *net) +static inline void ip4_frags_ns_ctl_unregister(struct net *net) +{ +} + +static inline void ip4_frags_ctl_register(void) { } #endif @@ -716,12 +728,12 @@ static int ipv4_frags_init_net(struct net *net) inet_frags_init_net(&net->ipv4.frags); - return ip4_frags_ctl_register(net); + return ip4_frags_ns_ctl_register(net); } static void ipv4_frags_exit_net(struct net *net) { - ip4_frags_ctl_unregister(net); + ip4_frags_ns_ctl_unregister(net); inet_frags_exit_net(&net->ipv4.frags, &ip4_frags); } @@ -732,6 +744,7 @@ static struct pernet_operations ip4_frags_ops = { void __init ipfrag_init(void) { + ip4_frags_ctl_register(); register_pernet_subsys(&ip4_frags_ops); ip4_frags.hashfn = ip4_hashfn; ip4_frags.constructor = ip4_frag_init; diff --git a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c index 4342cba4ff82..2a61158ea722 100644 --- a/net/ipv4/ip_gre.c +++ b/net/ipv4/ip_gre.c @@ -473,6 +473,8 @@ static int ipgre_rcv(struct sk_buff *skb) read_lock(&ipgre_lock); if ((tunnel = ipgre_tunnel_lookup(dev_net(skb->dev), iph->saddr, iph->daddr, key)) != NULL) { + struct net_device_stats *stats = &tunnel->dev->stats; + secpath_reset(skb); skb->protocol = *(__be16*)(h + 2); @@ -497,28 +499,28 @@ static int ipgre_rcv(struct sk_buff *skb) /* Looped back packet, drop it! */ if (skb->rtable->fl.iif == 0) goto drop; - tunnel->stat.multicast++; + stats->multicast++; skb->pkt_type = PACKET_BROADCAST; } #endif if (((flags&GRE_CSUM) && csum) || (!(flags&GRE_CSUM) && tunnel->parms.i_flags&GRE_CSUM)) { - tunnel->stat.rx_crc_errors++; - tunnel->stat.rx_errors++; + stats->rx_crc_errors++; + stats->rx_errors++; goto drop; } if (tunnel->parms.i_flags&GRE_SEQ) { if (!(flags&GRE_SEQ) || (tunnel->i_seqno && (s32)(seqno - tunnel->i_seqno) < 0)) { - tunnel->stat.rx_fifo_errors++; - tunnel->stat.rx_errors++; + stats->rx_fifo_errors++; + stats->rx_errors++; goto drop; } tunnel->i_seqno = seqno + 1; } - tunnel->stat.rx_packets++; - tunnel->stat.rx_bytes += skb->len; + stats->rx_packets++; + stats->rx_bytes += skb->len; skb->dev = tunnel->dev; dst_release(skb->dst); skb->dst = NULL; @@ -540,7 +542,7 @@ drop_nolock: static int ipgre_tunnel_xmit(struct sk_buff *skb, struct net_device *dev) { struct ip_tunnel *tunnel = netdev_priv(dev); - struct net_device_stats *stats = &tunnel->stat; + struct net_device_stats *stats = &tunnel->dev->stats; struct iphdr *old_iph = ip_hdr(skb); struct iphdr *tiph; u8 tos; @@ -554,7 +556,7 @@ static int ipgre_tunnel_xmit(struct sk_buff *skb, struct net_device *dev) int mtu; if (tunnel->recursion++) { - tunnel->stat.collisions++; + stats->collisions++; goto tx_error; } @@ -570,7 +572,7 @@ static int ipgre_tunnel_xmit(struct sk_buff *skb, struct net_device *dev) /* NBMA tunnel */ if (skb->dst == NULL) { - tunnel->stat.tx_fifo_errors++; + stats->tx_fifo_errors++; goto tx_error; } @@ -621,7 +623,7 @@ static int ipgre_tunnel_xmit(struct sk_buff *skb, struct net_device *dev) .tos = RT_TOS(tos) } }, .proto = IPPROTO_GRE }; if (ip_route_output_key(dev_net(dev), &rt, &fl)) { - tunnel->stat.tx_carrier_errors++; + stats->tx_carrier_errors++; goto tx_error; } } @@ -629,7 +631,7 @@ static int ipgre_tunnel_xmit(struct sk_buff *skb, struct net_device *dev) if (tdev == dev) { ip_rt_put(rt); - tunnel->stat.collisions++; + stats->collisions++; goto tx_error; } @@ -954,11 +956,6 @@ done: return err; } -static struct net_device_stats *ipgre_tunnel_get_stats(struct net_device *dev) -{ - return &(((struct ip_tunnel*)netdev_priv(dev))->stat); -} - static int ipgre_tunnel_change_mtu(struct net_device *dev, int new_mtu) { struct ip_tunnel *tunnel = netdev_priv(dev); @@ -1084,7 +1081,6 @@ static void ipgre_tunnel_setup(struct net_device *dev) dev->uninit = ipgre_tunnel_uninit; dev->destructor = free_netdev; dev->hard_start_xmit = ipgre_tunnel_xmit; - dev->get_stats = ipgre_tunnel_get_stats; dev->do_ioctl = ipgre_tunnel_ioctl; dev->change_mtu = ipgre_tunnel_change_mtu; diff --git a/net/ipv4/ip_input.c b/net/ipv4/ip_input.c index ff77a4a7f9ec..e0bed56c51f1 100644 --- a/net/ipv4/ip_input.c +++ b/net/ipv4/ip_input.c @@ -5,8 +5,6 @@ * * The Internet Protocol (IP) module. * - * Version: $Id: ip_input.c,v 1.55 2002/01/12 07:39:45 davem Exp $ - * * Authors: Ross Biro * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG> * Donald Becker, <becker@super.org> @@ -147,12 +145,6 @@ #include <linux/netlink.h> /* - * SNMP management statistics - */ - -DEFINE_SNMP_STAT(struct ipstats_mib, ip_statistics) __read_mostly; - -/* * Process Router Attention IP option */ int ip_call_ra_chain(struct sk_buff *skb) @@ -232,16 +224,16 @@ static int ip_local_deliver_finish(struct sk_buff *skb) protocol = -ret; goto resubmit; } - IP_INC_STATS_BH(IPSTATS_MIB_INDELIVERS); + IP_INC_STATS_BH(net, IPSTATS_MIB_INDELIVERS); } else { if (!raw) { if (xfrm4_policy_check(NULL, XFRM_POLICY_IN, skb)) { - IP_INC_STATS_BH(IPSTATS_MIB_INUNKNOWNPROTOS); + IP_INC_STATS_BH(net, IPSTATS_MIB_INUNKNOWNPROTOS); icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PROT_UNREACH, 0); } } else - IP_INC_STATS_BH(IPSTATS_MIB_INDELIVERS); + IP_INC_STATS_BH(net, IPSTATS_MIB_INDELIVERS); kfree_skb(skb); } } @@ -283,7 +275,7 @@ static inline int ip_rcv_options(struct sk_buff *skb) --ANK (980813) */ if (skb_cow(skb, skb_headroom(skb))) { - IP_INC_STATS_BH(IPSTATS_MIB_INDISCARDS); + IP_INC_STATS_BH(dev_net(dev), IPSTATS_MIB_INDISCARDS); goto drop; } @@ -292,7 +284,7 @@ static inline int ip_rcv_options(struct sk_buff *skb) opt->optlen = iph->ihl*4 - sizeof(struct iphdr); if (ip_options_compile(dev_net(dev), opt, skb)) { - IP_INC_STATS_BH(IPSTATS_MIB_INHDRERRORS); + IP_INC_STATS_BH(dev_net(dev), IPSTATS_MIB_INHDRERRORS); goto drop; } @@ -336,9 +328,11 @@ static int ip_rcv_finish(struct sk_buff *skb) skb->dev); if (unlikely(err)) { if (err == -EHOSTUNREACH) - IP_INC_STATS_BH(IPSTATS_MIB_INADDRERRORS); + IP_INC_STATS_BH(dev_net(skb->dev), + IPSTATS_MIB_INADDRERRORS); else if (err == -ENETUNREACH) - IP_INC_STATS_BH(IPSTATS_MIB_INNOROUTES); + IP_INC_STATS_BH(dev_net(skb->dev), + IPSTATS_MIB_INNOROUTES); goto drop; } } @@ -359,9 +353,9 @@ static int ip_rcv_finish(struct sk_buff *skb) rt = skb->rtable; if (rt->rt_type == RTN_MULTICAST) - IP_INC_STATS_BH(IPSTATS_MIB_INMCASTPKTS); + IP_INC_STATS_BH(dev_net(rt->u.dst.dev), IPSTATS_MIB_INMCASTPKTS); else if (rt->rt_type == RTN_BROADCAST) - IP_INC_STATS_BH(IPSTATS_MIB_INBCASTPKTS); + IP_INC_STATS_BH(dev_net(rt->u.dst.dev), IPSTATS_MIB_INBCASTPKTS); return dst_input(skb); @@ -384,10 +378,10 @@ 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(IPSTATS_MIB_INRECEIVES); + IP_INC_STATS_BH(dev_net(dev), IPSTATS_MIB_INRECEIVES); if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL) { - IP_INC_STATS_BH(IPSTATS_MIB_INDISCARDS); + IP_INC_STATS_BH(dev_net(dev), IPSTATS_MIB_INDISCARDS); goto out; } @@ -420,7 +414,7 @@ int ip_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt, len = ntohs(iph->tot_len); if (skb->len < len) { - IP_INC_STATS_BH(IPSTATS_MIB_INTRUNCATEDPKTS); + IP_INC_STATS_BH(dev_net(dev), IPSTATS_MIB_INTRUNCATEDPKTS); goto drop; } else if (len < (iph->ihl*4)) goto inhdr_error; @@ -430,7 +424,7 @@ int ip_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt, * Note this now means skb->len holds ntohs(iph->tot_len). */ if (pskb_trim_rcsum(skb, len)) { - IP_INC_STATS_BH(IPSTATS_MIB_INDISCARDS); + IP_INC_STATS_BH(dev_net(dev), IPSTATS_MIB_INDISCARDS); goto drop; } @@ -441,11 +435,9 @@ int ip_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt, ip_rcv_finish); inhdr_error: - IP_INC_STATS_BH(IPSTATS_MIB_INHDRERRORS); + IP_INC_STATS_BH(dev_net(dev), IPSTATS_MIB_INHDRERRORS); drop: kfree_skb(skb); out: return NET_RX_DROP; } - -EXPORT_SYMBOL(ip_statistics); diff --git a/net/ipv4/ip_options.c b/net/ipv4/ip_options.c index 33126ad2cfdc..be3f18a7a40e 100644 --- a/net/ipv4/ip_options.c +++ b/net/ipv4/ip_options.c @@ -5,8 +5,6 @@ * * The options processing module for ip.c * - * Version: $Id: ip_options.c,v 1.21 2001/09/01 00:31:50 davem Exp $ - * * Authors: A.N.Kuznetsov * */ diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c index e527628f56cf..465544f6281a 100644 --- a/net/ipv4/ip_output.c +++ b/net/ipv4/ip_output.c @@ -5,8 +5,6 @@ * * The Internet Protocol (IP) output module. * - * Version: $Id: ip_output.c,v 1.100 2002/02/01 22:01:03 davem Exp $ - * * Authors: Ross Biro * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG> * Donald Becker, <becker@super.org> @@ -184,9 +182,9 @@ static inline int ip_finish_output2(struct sk_buff *skb) unsigned int hh_len = LL_RESERVED_SPACE(dev); if (rt->rt_type == RTN_MULTICAST) - IP_INC_STATS(IPSTATS_MIB_OUTMCASTPKTS); + IP_INC_STATS(dev_net(dev), IPSTATS_MIB_OUTMCASTPKTS); else if (rt->rt_type == RTN_BROADCAST) - IP_INC_STATS(IPSTATS_MIB_OUTBCASTPKTS); + IP_INC_STATS(dev_net(dev), IPSTATS_MIB_OUTBCASTPKTS); /* Be paranoid, rather than too clever. */ if (unlikely(skb_headroom(skb) < hh_len && dev->header_ops)) { @@ -246,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(IPSTATS_MIB_OUTREQUESTS); + IP_INC_STATS(dev_net(dev), IPSTATS_MIB_OUTREQUESTS); skb->dev = dev; skb->protocol = htons(ETH_P_IP); @@ -300,7 +298,7 @@ int ip_output(struct sk_buff *skb) { struct net_device *dev = skb->dst->dev; - IP_INC_STATS(IPSTATS_MIB_OUTREQUESTS); + IP_INC_STATS(dev_net(dev), IPSTATS_MIB_OUTREQUESTS); skb->dev = dev; skb->protocol = htons(ETH_P_IP); @@ -391,7 +389,7 @@ packet_routed: return ip_local_out(skb); no_route: - IP_INC_STATS(IPSTATS_MIB_OUTNOROUTES); + IP_INC_STATS(sock_net(sk), IPSTATS_MIB_OUTNOROUTES); kfree_skb(skb); return -EHOSTUNREACH; } @@ -453,7 +451,7 @@ int ip_fragment(struct sk_buff *skb, int (*output)(struct sk_buff*)) iph = ip_hdr(skb); if (unlikely((iph->frag_off & htons(IP_DF)) && !skb->local_df)) { - IP_INC_STATS(IPSTATS_MIB_FRAGFAILS); + IP_INC_STATS(dev_net(dev), IPSTATS_MIB_FRAGFAILS); icmp_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED, htonl(ip_skb_dst_mtu(skb))); kfree_skb(skb); @@ -544,7 +542,7 @@ int ip_fragment(struct sk_buff *skb, int (*output)(struct sk_buff*)) err = output(skb); if (!err) - IP_INC_STATS(IPSTATS_MIB_FRAGCREATES); + IP_INC_STATS(dev_net(dev), IPSTATS_MIB_FRAGCREATES); if (err || !frag) break; @@ -554,7 +552,7 @@ int ip_fragment(struct sk_buff *skb, int (*output)(struct sk_buff*)) } if (err == 0) { - IP_INC_STATS(IPSTATS_MIB_FRAGOKS); + IP_INC_STATS(dev_net(dev), IPSTATS_MIB_FRAGOKS); return 0; } @@ -563,7 +561,7 @@ int ip_fragment(struct sk_buff *skb, int (*output)(struct sk_buff*)) kfree_skb(frag); frag = skb; } - IP_INC_STATS(IPSTATS_MIB_FRAGFAILS); + IP_INC_STATS(dev_net(dev), IPSTATS_MIB_FRAGFAILS); return err; } @@ -675,15 +673,15 @@ slow_path: if (err) goto fail; - IP_INC_STATS(IPSTATS_MIB_FRAGCREATES); + IP_INC_STATS(dev_net(dev), IPSTATS_MIB_FRAGCREATES); } kfree_skb(skb); - IP_INC_STATS(IPSTATS_MIB_FRAGOKS); + IP_INC_STATS(dev_net(dev), IPSTATS_MIB_FRAGOKS); return err; fail: kfree_skb(skb); - IP_INC_STATS(IPSTATS_MIB_FRAGFAILS); + IP_INC_STATS(dev_net(dev), IPSTATS_MIB_FRAGFAILS); return err; } @@ -1049,7 +1047,7 @@ alloc_new_skb: error: inet->cork.length -= length; - IP_INC_STATS(IPSTATS_MIB_OUTDISCARDS); + IP_INC_STATS(sock_net(sk), IPSTATS_MIB_OUTDISCARDS); return err; } @@ -1191,7 +1189,7 @@ ssize_t ip_append_page(struct sock *sk, struct page *page, error: inet->cork.length -= size; - IP_INC_STATS(IPSTATS_MIB_OUTDISCARDS); + IP_INC_STATS(sock_net(sk), IPSTATS_MIB_OUTDISCARDS); return err; } @@ -1213,6 +1211,7 @@ int ip_push_pending_frames(struct sock *sk) struct sk_buff *skb, *tmp_skb; struct sk_buff **tail_skb; struct inet_sock *inet = inet_sk(sk); + struct net *net = sock_net(sk); struct ip_options *opt = NULL; struct rtable *rt = (struct rtable *)inet->cork.dst; struct iphdr *iph; @@ -1282,7 +1281,7 @@ int ip_push_pending_frames(struct sock *sk) skb->dst = dst_clone(&rt->u.dst); if (iph->protocol == IPPROTO_ICMP) - icmp_out_count(((struct icmphdr *) + icmp_out_count(net, ((struct icmphdr *) skb_transport_header(skb))->type); /* Netfilter gets whole the not fragmented skb. */ @@ -1299,7 +1298,7 @@ out: return err; error: - IP_INC_STATS(IPSTATS_MIB_OUTDISCARDS); + IP_INC_STATS(net, IPSTATS_MIB_OUTDISCARDS); goto out; } diff --git a/net/ipv4/ip_sockglue.c b/net/ipv4/ip_sockglue.c index e0514e82308e..105d92a039b9 100644 --- a/net/ipv4/ip_sockglue.c +++ b/net/ipv4/ip_sockglue.c @@ -5,8 +5,6 @@ * * The IP to API glue. * - * Version: $Id: ip_sockglue.c,v 1.62 2002/02/01 22:01:04 davem Exp $ - * * Authors: see ip.c * * Fixes: diff --git a/net/ipv4/ipconfig.c b/net/ipv4/ipconfig.c index ed45037ce9be..42065fff46c4 100644 --- a/net/ipv4/ipconfig.c +++ b/net/ipv4/ipconfig.c @@ -1,6 +1,4 @@ /* - * $Id: ipconfig.c,v 1.46 2002/02/01 22:01:04 davem Exp $ - * * Automatic Configuration of IP -- use DHCP, BOOTP, RARP, or * user-supplied information to configure own IP address and routes. * @@ -434,7 +432,7 @@ ic_rarp_recv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt unsigned char *sha, *tha; /* s for "source", t for "target" */ struct ic_device *d; - if (dev_net(dev) != &init_net) + if (!net_eq(dev_net(dev), &init_net)) goto drop; if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL) @@ -854,7 +852,7 @@ static int __init ic_bootp_recv(struct sk_buff *skb, struct net_device *dev, str struct ic_device *d; int len, ext_len; - if (dev_net(dev) != &init_net) + if (!net_eq(dev_net(dev), &init_net)) goto drop; /* Perform verifications before taking the lock. */ diff --git a/net/ipv4/ipip.c b/net/ipv4/ipip.c index af5cb53da5cc..4c6d2caf9203 100644 --- a/net/ipv4/ipip.c +++ b/net/ipv4/ipip.c @@ -1,8 +1,6 @@ /* * Linux NET3: IP/IP protocol decoder. * - * Version: $Id: ipip.c,v 1.50 2001/10/02 02:22:36 davem Exp $ - * * Authors: * Sam Lantinga (slouken@cs.ucdavis.edu) 02/01/95 * @@ -368,8 +366,8 @@ static int ipip_rcv(struct sk_buff *skb) skb->protocol = htons(ETH_P_IP); skb->pkt_type = PACKET_HOST; - tunnel->stat.rx_packets++; - tunnel->stat.rx_bytes += skb->len; + tunnel->dev->stats.rx_packets++; + tunnel->dev->stats.rx_bytes += skb->len; skb->dev = tunnel->dev; dst_release(skb->dst); skb->dst = NULL; @@ -392,7 +390,7 @@ static int ipip_rcv(struct sk_buff *skb) static int ipip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev) { struct ip_tunnel *tunnel = netdev_priv(dev); - struct net_device_stats *stats = &tunnel->stat; + struct net_device_stats *stats = &tunnel->dev->stats; struct iphdr *tiph = &tunnel->parms.iph; u8 tos = tunnel->parms.iph.tos; __be16 df = tiph->frag_off; @@ -405,7 +403,7 @@ static int ipip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev) int mtu; if (tunnel->recursion++) { - tunnel->stat.collisions++; + stats->collisions++; goto tx_error; } @@ -418,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) { - tunnel->stat.tx_fifo_errors++; + stats->tx_fifo_errors++; goto tx_error; } if ((dst = rt->rt_gateway) == 0) @@ -433,7 +431,7 @@ static int ipip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev) .tos = RT_TOS(tos) } }, .proto = IPPROTO_IPIP }; if (ip_route_output_key(dev_net(dev), &rt, &fl)) { - tunnel->stat.tx_carrier_errors++; + stats->tx_carrier_errors++; goto tx_error_icmp; } } @@ -441,7 +439,7 @@ static int ipip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev) if (tdev == dev) { ip_rt_put(rt); - tunnel->stat.collisions++; + stats->collisions++; goto tx_error; } @@ -451,7 +449,7 @@ static int ipip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev) mtu = skb->dst ? dst_mtu(skb->dst) : dev->mtu; if (mtu < 68) { - tunnel->stat.collisions++; + stats->collisions++; ip_rt_put(rt); goto tx_error; } @@ -685,11 +683,6 @@ done: return err; } -static struct net_device_stats *ipip_tunnel_get_stats(struct net_device *dev) -{ - return &(((struct ip_tunnel*)netdev_priv(dev))->stat); -} - static int ipip_tunnel_change_mtu(struct net_device *dev, int new_mtu) { if (new_mtu < 68 || new_mtu > 0xFFF8 - sizeof(struct iphdr)) @@ -702,7 +695,6 @@ static void ipip_tunnel_setup(struct net_device *dev) { dev->uninit = ipip_tunnel_uninit; dev->hard_start_xmit = ipip_tunnel_xmit; - dev->get_stats = ipip_tunnel_get_stats; dev->do_ioctl = ipip_tunnel_ioctl; dev->change_mtu = ipip_tunnel_change_mtu; dev->destructor = free_netdev; diff --git a/net/ipv4/ipmr.c b/net/ipv4/ipmr.c index 11700a4dcd95..c519b8d30eee 100644 --- a/net/ipv4/ipmr.c +++ b/net/ipv4/ipmr.c @@ -9,8 +9,6 @@ * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. * - * Version: $Id: ipmr.c,v 1.65 2001/10/31 21:55:54 davem Exp $ - * * Fixes: * Michael Chastain : Incorrect size of copying. * Alan Cox : Added the cache manager code @@ -120,6 +118,31 @@ static struct timer_list ipmr_expire_timer; /* Service routines creating virtual interfaces: DVMRP tunnels and PIMREG */ +static void ipmr_del_tunnel(struct net_device *dev, struct vifctl *v) +{ + dev_close(dev); + + dev = __dev_get_by_name(&init_net, "tunl0"); + if (dev) { + struct ifreq ifr; + mm_segment_t oldfs; + struct ip_tunnel_parm p; + + memset(&p, 0, sizeof(p)); + p.iph.daddr = v->vifc_rmt_addr.s_addr; + p.iph.saddr = v->vifc_lcl_addr.s_addr; + p.iph.version = 4; + p.iph.ihl = 5; + p.iph.protocol = IPPROTO_IPIP; + sprintf(p.name, "dvmrp%d", v->vifc_vifi); + ifr.ifr_ifru.ifru_data = (__force void __user *)&p; + + oldfs = get_fs(); set_fs(KERNEL_DS); + dev->do_ioctl(dev, &ifr, SIOCDELTUNNEL); + set_fs(oldfs); + } +} + static struct net_device *ipmr_new_tunnel(struct vifctl *v) { @@ -161,6 +184,7 @@ struct net_device *ipmr_new_tunnel(struct vifctl *v) if (dev_open(dev)) goto failure; + dev_hold(dev); } } return dev; @@ -181,26 +205,20 @@ static int reg_vif_num = -1; static int reg_vif_xmit(struct sk_buff *skb, struct net_device *dev) { read_lock(&mrt_lock); - ((struct net_device_stats*)netdev_priv(dev))->tx_bytes += skb->len; - ((struct net_device_stats*)netdev_priv(dev))->tx_packets++; + dev->stats.tx_bytes += skb->len; + dev->stats.tx_packets++; ipmr_cache_report(skb, reg_vif_num, IGMPMSG_WHOLEPKT); read_unlock(&mrt_lock); kfree_skb(skb); return 0; } -static struct net_device_stats *reg_vif_get_stats(struct net_device *dev) -{ - return (struct net_device_stats*)netdev_priv(dev); -} - static void reg_vif_setup(struct net_device *dev) { dev->type = ARPHRD_PIMREG; dev->mtu = ETH_DATA_LEN - sizeof(struct iphdr) - 8; dev->flags = IFF_NOARP; dev->hard_start_xmit = reg_vif_xmit; - dev->get_stats = reg_vif_get_stats; dev->destructor = free_netdev; } @@ -209,8 +227,7 @@ static struct net_device *ipmr_reg_vif(void) struct net_device *dev; struct in_device *in_dev; - dev = alloc_netdev(sizeof(struct net_device_stats), "pimreg", - reg_vif_setup); + dev = alloc_netdev(0, "pimreg", reg_vif_setup); if (dev == NULL) return NULL; @@ -234,6 +251,8 @@ static struct net_device *ipmr_reg_vif(void) if (dev_open(dev)) goto failure; + dev_hold(dev); + return dev; failure: @@ -248,9 +267,10 @@ failure: /* * Delete a VIF entry + * @notify: Set to 1, if the caller is a notifier_call */ -static int vif_delete(int vifi) +static int vif_delete(int vifi, int notify) { struct vif_device *v; struct net_device *dev; @@ -293,7 +313,7 @@ static int vif_delete(int vifi) ip_rt_multicast_event(in_dev); } - if (v->flags&(VIFF_TUNNEL|VIFF_REGISTER)) + if (v->flags&(VIFF_TUNNEL|VIFF_REGISTER) && !notify) unregister_netdevice(dev); dev_put(dev); @@ -398,6 +418,7 @@ static int vif_add(struct vifctl *vifc, int mrtsock) struct vif_device *v = &vif_table[vifi]; struct net_device *dev; struct in_device *in_dev; + int err; /* Is vif busy ? */ if (VIF_EXISTS(vifi)) @@ -415,18 +436,34 @@ static int vif_add(struct vifctl *vifc, int mrtsock) dev = ipmr_reg_vif(); if (!dev) return -ENOBUFS; + err = dev_set_allmulti(dev, 1); + if (err) { + unregister_netdevice(dev); + dev_put(dev); + return err; + } break; #endif case VIFF_TUNNEL: dev = ipmr_new_tunnel(vifc); if (!dev) return -ENOBUFS; + err = dev_set_allmulti(dev, 1); + if (err) { + ipmr_del_tunnel(dev, vifc); + dev_put(dev); + return err; + } break; case 0: dev = ip_dev_find(&init_net, vifc->vifc_lcl_addr.s_addr); if (!dev) return -EADDRNOTAVAIL; - dev_put(dev); + err = dev_set_allmulti(dev, 1); + if (err) { + dev_put(dev); + return err; + } break; default: return -EINVAL; @@ -435,7 +472,6 @@ static int vif_add(struct vifctl *vifc, int mrtsock) if ((in_dev = __in_dev_get_rtnl(dev)) == NULL) return -EADDRNOTAVAIL; IPV4_DEVCONF(in_dev->cnf, MC_FORWARDING)++; - dev_set_allmulti(dev, +1); ip_rt_multicast_event(in_dev); /* @@ -458,7 +494,6 @@ static int vif_add(struct vifctl *vifc, int mrtsock) /* And finish update writing critical data */ write_lock_bh(&mrt_lock); - dev_hold(dev); v->dev=dev; #ifdef CONFIG_IP_PIMSM if (v->flags&VIFF_REGISTER) @@ -805,7 +840,7 @@ static void mroute_clean_tables(struct sock *sk) */ for (i=0; i<maxvif; i++) { if (!(vif_table[i].flags&VIFF_STATIC)) - vif_delete(i); + vif_delete(i, 0); } /* @@ -918,7 +953,7 @@ int ip_mroute_setsockopt(struct sock *sk,int optname,char __user *optval,int opt if (optname==MRT_ADD_VIF) { ret = vif_add(&vif, sk==mroute_socket); } else { - ret = vif_delete(vif.vifc_vifi); + ret = vif_delete(vif.vifc_vifi, 0); } rtnl_unlock(); return ret; @@ -1089,7 +1124,7 @@ static int ipmr_device_event(struct notifier_block *this, unsigned long event, v struct vif_device *v; int ct; - if (dev_net(dev) != &init_net) + if (!net_eq(dev_net(dev), &init_net)) return NOTIFY_DONE; if (event != NETDEV_UNREGISTER) @@ -1097,7 +1132,7 @@ static int ipmr_device_event(struct notifier_block *this, unsigned long event, v v=&vif_table[0]; for (ct=0;ct<maxvif;ct++,v++) { if (v->dev==dev) - vif_delete(ct); + vif_delete(ct, 1); } return NOTIFY_DONE; } @@ -1143,7 +1178,7 @@ static inline int ipmr_forward_finish(struct sk_buff *skb) { struct ip_options * opt = &(IPCB(skb)->opt); - IP_INC_STATS_BH(IPSTATS_MIB_OUTFORWDATAGRAMS); + IP_INC_STATS_BH(dev_net(skb->dst->dev), IPSTATS_MIB_OUTFORWDATAGRAMS); if (unlikely(opt->optlen)) ip_forward_options(skb); @@ -1170,8 +1205,8 @@ static void ipmr_queue_xmit(struct sk_buff *skb, struct mfc_cache *c, int vifi) if (vif->flags & VIFF_REGISTER) { vif->pkt_out++; vif->bytes_out+=skb->len; - ((struct net_device_stats*)netdev_priv(vif->dev))->tx_bytes += skb->len; - ((struct net_device_stats*)netdev_priv(vif->dev))->tx_packets++; + vif->dev->stats.tx_bytes += skb->len; + vif->dev->stats.tx_packets++; ipmr_cache_report(skb, vifi, IGMPMSG_WHOLEPKT); kfree_skb(skb); return; @@ -1206,7 +1241,7 @@ static void ipmr_queue_xmit(struct sk_buff *skb, struct mfc_cache *c, int vifi) to blackhole. */ - IP_INC_STATS_BH(IPSTATS_MIB_FRAGFAILS); + IP_INC_STATS_BH(dev_net(dev), IPSTATS_MIB_FRAGFAILS); ip_rt_put(rt); goto out_free; } @@ -1230,8 +1265,8 @@ static void ipmr_queue_xmit(struct sk_buff *skb, struct mfc_cache *c, int vifi) if (vif->flags & VIFF_TUNNEL) { ip_encap(skb, vif->local, vif->remote); /* FIXME: extra output firewall step used to be here. --RR */ - ((struct ip_tunnel *)netdev_priv(vif->dev))->stat.tx_packets++; - ((struct ip_tunnel *)netdev_priv(vif->dev))->stat.tx_bytes+=skb->len; + vif->dev->stats.tx_packets++; + vif->dev->stats.tx_bytes += skb->len; } IPCB(skb)->flags |= IPSKB_FORWARDED; @@ -1487,8 +1522,8 @@ int pim_rcv_v1(struct sk_buff * skb) skb->pkt_type = PACKET_HOST; dst_release(skb->dst); skb->dst = NULL; - ((struct net_device_stats*)netdev_priv(reg_dev))->rx_bytes += skb->len; - ((struct net_device_stats*)netdev_priv(reg_dev))->rx_packets++; + reg_dev->stats.rx_bytes += skb->len; + reg_dev->stats.rx_packets++; nf_reset(skb); netif_rx(skb); dev_put(reg_dev); @@ -1542,8 +1577,8 @@ static int pim_rcv(struct sk_buff * skb) skb->ip_summed = 0; skb->pkt_type = PACKET_HOST; dst_release(skb->dst); - ((struct net_device_stats*)netdev_priv(reg_dev))->rx_bytes += skb->len; - ((struct net_device_stats*)netdev_priv(reg_dev))->rx_packets++; + reg_dev->stats.rx_bytes += skb->len; + reg_dev->stats.rx_packets++; skb->dst = NULL; nf_reset(skb); netif_rx(skb); @@ -1887,16 +1922,36 @@ static struct net_protocol pim_protocol = { * Setup for IP multicast routing */ -void __init ip_mr_init(void) +int __init ip_mr_init(void) { + int err; + mrt_cachep = kmem_cache_create("ip_mrt_cache", sizeof(struct mfc_cache), 0, SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL); + if (!mrt_cachep) + return -ENOMEM; + setup_timer(&ipmr_expire_timer, ipmr_expire_process, 0); - register_netdevice_notifier(&ip_mr_notifier); + err = register_netdevice_notifier(&ip_mr_notifier); + if (err) + goto reg_notif_fail; #ifdef CONFIG_PROC_FS - proc_net_fops_create(&init_net, "ip_mr_vif", 0, &ipmr_vif_fops); - proc_net_fops_create(&init_net, "ip_mr_cache", 0, &ipmr_mfc_fops); + err = -ENOMEM; + if (!proc_net_fops_create(&init_net, "ip_mr_vif", 0, &ipmr_vif_fops)) + goto proc_vif_fail; + if (!proc_net_fops_create(&init_net, "ip_mr_cache", 0, &ipmr_mfc_fops)) + goto proc_cache_fail; #endif + return 0; +reg_notif_fail: + kmem_cache_destroy(mrt_cachep); +#ifdef CONFIG_PROC_FS +proc_vif_fail: + unregister_netdevice_notifier(&ip_mr_notifier); +proc_cache_fail: + proc_net_remove(&init_net, "ip_mr_vif"); +#endif + return err; } diff --git a/net/ipv4/ipvs/ip_vs_app.c b/net/ipv4/ipvs/ip_vs_app.c index 535abe0c45e7..1f1897a1a702 100644 --- a/net/ipv4/ipvs/ip_vs_app.c +++ b/net/ipv4/ipvs/ip_vs_app.c @@ -1,8 +1,6 @@ /* * ip_vs_app.c: Application module support for IPVS * - * Version: $Id: ip_vs_app.c,v 1.17 2003/03/22 06:31:21 wensong Exp $ - * * Authors: Wensong Zhang <wensong@linuxvirtualserver.org> * * This program is free software; you can redistribute it and/or diff --git a/net/ipv4/ipvs/ip_vs_conn.c b/net/ipv4/ipvs/ip_vs_conn.c index 65f1ba112752..f8bdae47a77f 100644 --- a/net/ipv4/ipvs/ip_vs_conn.c +++ b/net/ipv4/ipvs/ip_vs_conn.c @@ -5,8 +5,6 @@ * high-performance and highly available server based on a * cluster of servers. * - * Version: $Id: ip_vs_conn.c,v 1.31 2003/04/18 09:03:16 wensong Exp $ - * * Authors: Wensong Zhang <wensong@linuxvirtualserver.org> * Peter Kese <peter.kese@ijs.si> * Julian Anastasov <ja@ssi.bg> diff --git a/net/ipv4/ipvs/ip_vs_core.c b/net/ipv4/ipvs/ip_vs_core.c index 963981a9d501..a7879eafc3b5 100644 --- a/net/ipv4/ipvs/ip_vs_core.c +++ b/net/ipv4/ipvs/ip_vs_core.c @@ -5,8 +5,6 @@ * high-performance and highly available server based on a * cluster of servers. * - * Version: $Id: ip_vs_core.c,v 1.34 2003/05/10 03:05:23 wensong Exp $ - * * Authors: Wensong Zhang <wensong@linuxvirtualserver.org> * Peter Kese <peter.kese@ijs.si> * Julian Anastasov <ja@ssi.bg> @@ -993,7 +991,8 @@ ip_vs_in(unsigned int hooknum, struct sk_buff *skb, == sysctl_ip_vs_sync_threshold[0])) || ((cp->protocol == IPPROTO_TCP) && (cp->old_state != cp->state) && ((cp->state == IP_VS_TCP_S_FIN_WAIT) || - (cp->state == IP_VS_TCP_S_CLOSE))))) + (cp->state == IP_VS_TCP_S_CLOSE_WAIT) || + (cp->state == IP_VS_TCP_S_TIME_WAIT))))) ip_vs_sync_conn(cp); cp->old_state = cp->state; diff --git a/net/ipv4/ipvs/ip_vs_ctl.c b/net/ipv4/ipvs/ip_vs_ctl.c index 94c5767c8e01..9a5ace0b4dd6 100644 --- a/net/ipv4/ipvs/ip_vs_ctl.c +++ b/net/ipv4/ipvs/ip_vs_ctl.c @@ -5,8 +5,6 @@ * high-performance and highly available server based on a * cluster of servers. * - * Version: $Id: ip_vs_ctl.c,v 1.36 2003/06/08 09:31:19 wensong Exp $ - * * Authors: Wensong Zhang <wensong@linuxvirtualserver.org> * Peter Kese <peter.kese@ijs.si> * Julian Anastasov <ja@ssi.bg> diff --git a/net/ipv4/ipvs/ip_vs_dh.c b/net/ipv4/ipvs/ip_vs_dh.c index dcf5d46aaa5e..8afc1503ed20 100644 --- a/net/ipv4/ipvs/ip_vs_dh.c +++ b/net/ipv4/ipvs/ip_vs_dh.c @@ -1,8 +1,6 @@ /* * IPVS: Destination Hashing scheduling module * - * Version: $Id: ip_vs_dh.c,v 1.5 2002/09/15 08:14:08 wensong Exp $ - * * Authors: Wensong Zhang <wensong@gnuchina.org> * * Inspired by the consistent hashing scheduler patch from diff --git a/net/ipv4/ipvs/ip_vs_est.c b/net/ipv4/ipvs/ip_vs_est.c index dfa0d713c801..bc04eedd6dbb 100644 --- a/net/ipv4/ipvs/ip_vs_est.c +++ b/net/ipv4/ipvs/ip_vs_est.c @@ -1,8 +1,6 @@ /* * ip_vs_est.c: simple rate estimator for IPVS * - * Version: $Id: ip_vs_est.c,v 1.4 2002/11/30 01:50:35 wensong Exp $ - * * Authors: Wensong Zhang <wensong@linuxvirtualserver.org> * * This program is free software; you can redistribute it and/or diff --git a/net/ipv4/ipvs/ip_vs_ftp.c b/net/ipv4/ipvs/ip_vs_ftp.c index 59aa166b7678..c1c758e4f733 100644 --- a/net/ipv4/ipvs/ip_vs_ftp.c +++ b/net/ipv4/ipvs/ip_vs_ftp.c @@ -1,8 +1,6 @@ /* * ip_vs_ftp.c: IPVS ftp application module * - * Version: $Id: ip_vs_ftp.c,v 1.13 2002/09/15 08:14:08 wensong Exp $ - * * Authors: Wensong Zhang <wensong@linuxvirtualserver.org> * * Changes: diff --git a/net/ipv4/ipvs/ip_vs_lblc.c b/net/ipv4/ipvs/ip_vs_lblc.c index 3888642706ad..0efa3db4b180 100644 --- a/net/ipv4/ipvs/ip_vs_lblc.c +++ b/net/ipv4/ipvs/ip_vs_lblc.c @@ -1,8 +1,6 @@ /* * IPVS: Locality-Based Least-Connection scheduling module * - * Version: $Id: ip_vs_lblc.c,v 1.10 2002/09/15 08:14:08 wensong Exp $ - * * Authors: Wensong Zhang <wensong@gnuchina.org> * * This program is free software; you can redistribute it and/or diff --git a/net/ipv4/ipvs/ip_vs_lblcr.c b/net/ipv4/ipvs/ip_vs_lblcr.c index daa260eb21cf..8e3bbeb45138 100644 --- a/net/ipv4/ipvs/ip_vs_lblcr.c +++ b/net/ipv4/ipvs/ip_vs_lblcr.c @@ -1,8 +1,6 @@ /* * IPVS: Locality-Based Least-Connection with Replication scheduler * - * Version: $Id: ip_vs_lblcr.c,v 1.11 2002/09/15 08:14:08 wensong Exp $ - * * Authors: Wensong Zhang <wensong@gnuchina.org> * * This program is free software; you can redistribute it and/or diff --git a/net/ipv4/ipvs/ip_vs_lc.c b/net/ipv4/ipvs/ip_vs_lc.c index d88fef90a641..ac9f08e065d5 100644 --- a/net/ipv4/ipvs/ip_vs_lc.c +++ b/net/ipv4/ipvs/ip_vs_lc.c @@ -1,8 +1,6 @@ /* * IPVS: Least-Connection Scheduling module * - * Version: $Id: ip_vs_lc.c,v 1.10 2003/04/18 09:03:16 wensong Exp $ - * * Authors: Wensong Zhang <wensong@linuxvirtualserver.org> * * This program is free software; you can redistribute it and/or diff --git a/net/ipv4/ipvs/ip_vs_nq.c b/net/ipv4/ipvs/ip_vs_nq.c index bc2a9e5f2a7b..a46bf258d420 100644 --- a/net/ipv4/ipvs/ip_vs_nq.c +++ b/net/ipv4/ipvs/ip_vs_nq.c @@ -1,8 +1,6 @@ /* * IPVS: Never Queue scheduling module * - * Version: $Id: ip_vs_nq.c,v 1.2 2003/06/08 09:31:19 wensong Exp $ - * * Authors: Wensong Zhang <wensong@linuxvirtualserver.org> * * This program is free software; you can redistribute it and/or diff --git a/net/ipv4/ipvs/ip_vs_proto.c b/net/ipv4/ipvs/ip_vs_proto.c index 4b1c16cbb16b..876714f23d65 100644 --- a/net/ipv4/ipvs/ip_vs_proto.c +++ b/net/ipv4/ipvs/ip_vs_proto.c @@ -1,8 +1,6 @@ /* * ip_vs_proto.c: transport protocol load balancing support for IPVS * - * Version: $Id: ip_vs_proto.c,v 1.2 2003/04/18 09:03:16 wensong Exp $ - * * Authors: Wensong Zhang <wensong@linuxvirtualserver.org> * Julian Anastasov <ja@ssi.bg> * diff --git a/net/ipv4/ipvs/ip_vs_proto_ah.c b/net/ipv4/ipvs/ip_vs_proto_ah.c index 4bf835e1d86d..73e0ea87c1f5 100644 --- a/net/ipv4/ipvs/ip_vs_proto_ah.c +++ b/net/ipv4/ipvs/ip_vs_proto_ah.c @@ -1,8 +1,6 @@ /* * ip_vs_proto_ah.c: AH IPSec load balancing support for IPVS * - * Version: $Id: ip_vs_proto_ah.c,v 1.1 2003/07/04 15:04:37 wensong Exp $ - * * Authors: Julian Anastasov <ja@ssi.bg>, February 2002 * Wensong Zhang <wensong@linuxvirtualserver.org> * diff --git a/net/ipv4/ipvs/ip_vs_proto_esp.c b/net/ipv4/ipvs/ip_vs_proto_esp.c index db6a6b7b1a0b..21d70c8ffa54 100644 --- a/net/ipv4/ipvs/ip_vs_proto_esp.c +++ b/net/ipv4/ipvs/ip_vs_proto_esp.c @@ -1,8 +1,6 @@ /* * ip_vs_proto_esp.c: ESP IPSec load balancing support for IPVS * - * Version: $Id: ip_vs_proto_esp.c,v 1.1 2003/07/04 15:04:37 wensong Exp $ - * * Authors: Julian Anastasov <ja@ssi.bg>, February 2002 * Wensong Zhang <wensong@linuxvirtualserver.org> * diff --git a/net/ipv4/ipvs/ip_vs_proto_tcp.c b/net/ipv4/ipvs/ip_vs_proto_tcp.c index b83dc14b0a4d..d0ea467986a0 100644 --- a/net/ipv4/ipvs/ip_vs_proto_tcp.c +++ b/net/ipv4/ipvs/ip_vs_proto_tcp.c @@ -1,8 +1,6 @@ /* * ip_vs_proto_tcp.c: TCP load balancing support for IPVS * - * Version: $Id: ip_vs_proto_tcp.c,v 1.3 2002/11/30 01:50:35 wensong Exp $ - * * Authors: Wensong Zhang <wensong@linuxvirtualserver.org> * Julian Anastasov <ja@ssi.bg> * diff --git a/net/ipv4/ipvs/ip_vs_proto_udp.c b/net/ipv4/ipvs/ip_vs_proto_udp.c index 75771cb3cd6f..c6be5d56823f 100644 --- a/net/ipv4/ipvs/ip_vs_proto_udp.c +++ b/net/ipv4/ipvs/ip_vs_proto_udp.c @@ -1,8 +1,6 @@ /* * ip_vs_proto_udp.c: UDP load balancing support for IPVS * - * Version: $Id: ip_vs_proto_udp.c,v 1.3 2002/11/30 01:50:35 wensong Exp $ - * * Authors: Wensong Zhang <wensong@linuxvirtualserver.org> * Julian Anastasov <ja@ssi.bg> * diff --git a/net/ipv4/ipvs/ip_vs_rr.c b/net/ipv4/ipvs/ip_vs_rr.c index 433f8a947924..c8db12d39e61 100644 --- a/net/ipv4/ipvs/ip_vs_rr.c +++ b/net/ipv4/ipvs/ip_vs_rr.c @@ -1,8 +1,6 @@ /* * IPVS: Round-Robin Scheduling module * - * Version: $Id: ip_vs_rr.c,v 1.9 2002/09/15 08:14:08 wensong Exp $ - * * Authors: Wensong Zhang <wensong@linuxvirtualserver.org> * Peter Kese <peter.kese@ijs.si> * diff --git a/net/ipv4/ipvs/ip_vs_sched.c b/net/ipv4/ipvs/ip_vs_sched.c index 121a32b1b756..b64767309855 100644 --- a/net/ipv4/ipvs/ip_vs_sched.c +++ b/net/ipv4/ipvs/ip_vs_sched.c @@ -5,8 +5,6 @@ * high-performance and highly available server based on a * cluster of servers. * - * Version: $Id: ip_vs_sched.c,v 1.13 2003/05/10 03:05:23 wensong Exp $ - * * Authors: Wensong Zhang <wensong@linuxvirtualserver.org> * Peter Kese <peter.kese@ijs.si> * diff --git a/net/ipv4/ipvs/ip_vs_sed.c b/net/ipv4/ipvs/ip_vs_sed.c index dd7c128f9db3..2a7d31358181 100644 --- a/net/ipv4/ipvs/ip_vs_sed.c +++ b/net/ipv4/ipvs/ip_vs_sed.c @@ -1,8 +1,6 @@ /* * IPVS: Shortest Expected Delay scheduling module * - * Version: $Id: ip_vs_sed.c,v 1.1 2003/05/10 03:06:08 wensong Exp $ - * * Authors: Wensong Zhang <wensong@linuxvirtualserver.org> * * This program is free software; you can redistribute it and/or diff --git a/net/ipv4/ipvs/ip_vs_sh.c b/net/ipv4/ipvs/ip_vs_sh.c index 1b25b00ef1e1..b8fdfac65001 100644 --- a/net/ipv4/ipvs/ip_vs_sh.c +++ b/net/ipv4/ipvs/ip_vs_sh.c @@ -1,8 +1,6 @@ /* * IPVS: Source Hashing scheduling module * - * Version: $Id: ip_vs_sh.c,v 1.5 2002/09/15 08:14:08 wensong Exp $ - * * Authors: Wensong Zhang <wensong@gnuchina.org> * * This program is free software; you can redistribute it and/or diff --git a/net/ipv4/ipvs/ip_vs_sync.c b/net/ipv4/ipvs/ip_vs_sync.c index eff54efe0351..45e9bd96c286 100644 --- a/net/ipv4/ipvs/ip_vs_sync.c +++ b/net/ipv4/ipvs/ip_vs_sync.c @@ -5,8 +5,6 @@ * high-performance and highly available server based on a * cluster of servers. * - * Version: $Id: ip_vs_sync.c,v 1.13 2003/06/08 09:31:19 wensong Exp $ - * * Authors: Wensong Zhang <wensong@linuxvirtualserver.org> * * ip_vs_sync: sync connection info from master load balancer to backups @@ -29,10 +27,12 @@ #include <linux/in.h> #include <linux/igmp.h> /* for ip_mc_join_group */ #include <linux/udp.h> +#include <linux/err.h> +#include <linux/kthread.h> +#include <linux/wait.h> #include <net/ip.h> #include <net/sock.h> -#include <asm/uaccess.h> /* for get_fs and set_fs */ #include <net/ip_vs.h> @@ -68,8 +68,8 @@ struct ip_vs_sync_conn_options { }; struct ip_vs_sync_thread_data { - struct completion *startup; - int state; + struct socket *sock; + char *buf; }; #define SIMPLE_CONN_SIZE (sizeof(struct ip_vs_sync_conn)) @@ -140,18 +140,19 @@ volatile int ip_vs_backup_syncid = 0; char ip_vs_master_mcast_ifn[IP_VS_IFNAME_MAXLEN]; char ip_vs_backup_mcast_ifn[IP_VS_IFNAME_MAXLEN]; +/* sync daemon tasks */ +static struct task_struct *sync_master_thread; +static struct task_struct *sync_backup_thread; + /* multicast addr */ -static struct sockaddr_in mcast_addr; +static struct sockaddr_in mcast_addr = { + .sin_family = AF_INET, + .sin_port = __constant_htons(IP_VS_SYNC_PORT), + .sin_addr.s_addr = __constant_htonl(IP_VS_SYNC_GROUP), +}; -static inline void sb_queue_tail(struct ip_vs_sync_buff *sb) -{ - spin_lock(&ip_vs_sync_lock); - list_add_tail(&sb->list, &ip_vs_sync_queue); - spin_unlock(&ip_vs_sync_lock); -} - -static inline struct ip_vs_sync_buff * sb_dequeue(void) +static inline struct ip_vs_sync_buff *sb_dequeue(void) { struct ip_vs_sync_buff *sb; @@ -195,6 +196,16 @@ static inline void ip_vs_sync_buff_release(struct ip_vs_sync_buff *sb) kfree(sb); } +static inline void sb_queue_tail(struct ip_vs_sync_buff *sb) +{ + spin_lock(&ip_vs_sync_lock); + if (ip_vs_sync_state & IP_VS_STATE_MASTER) + list_add_tail(&sb->list, &ip_vs_sync_queue); + else + ip_vs_sync_buff_release(sb); + spin_unlock(&ip_vs_sync_lock); +} + /* * Get the current sync buffer if it has been created for more * than the specified time or the specified time is zero. @@ -574,14 +585,17 @@ static int bind_mcastif_addr(struct socket *sock, char *ifname) static struct socket * make_send_sock(void) { struct socket *sock; + int result; /* First create a socket */ - if (sock_create_kern(PF_INET, SOCK_DGRAM, IPPROTO_UDP, &sock) < 0) { + result = sock_create_kern(PF_INET, SOCK_DGRAM, IPPROTO_UDP, &sock); + if (result < 0) { IP_VS_ERR("Error during creation of socket; terminating\n"); - return NULL; + return ERR_PTR(result); } - if (set_mcast_if(sock->sk, ip_vs_master_mcast_ifn) < 0) { + result = set_mcast_if(sock->sk, ip_vs_master_mcast_ifn); + if (result < 0) { IP_VS_ERR("Error setting outbound mcast interface\n"); goto error; } @@ -589,14 +603,15 @@ static struct socket * make_send_sock(void) set_mcast_loop(sock->sk, 0); set_mcast_ttl(sock->sk, 1); - if (bind_mcastif_addr(sock, ip_vs_master_mcast_ifn) < 0) { + result = bind_mcastif_addr(sock, ip_vs_master_mcast_ifn); + if (result < 0) { IP_VS_ERR("Error binding address of the mcast interface\n"); goto error; } - if (sock->ops->connect(sock, - (struct sockaddr*)&mcast_addr, - sizeof(struct sockaddr), 0) < 0) { + result = sock->ops->connect(sock, (struct sockaddr *) &mcast_addr, + sizeof(struct sockaddr), 0); + if (result < 0) { IP_VS_ERR("Error connecting to the multicast addr\n"); goto error; } @@ -605,7 +620,7 @@ static struct socket * make_send_sock(void) error: sock_release(sock); - return NULL; + return ERR_PTR(result); } @@ -615,27 +630,30 @@ static struct socket * make_send_sock(void) static struct socket * make_receive_sock(void) { struct socket *sock; + int result; /* First create a socket */ - if (sock_create_kern(PF_INET, SOCK_DGRAM, IPPROTO_UDP, &sock) < 0) { + result = sock_create_kern(PF_INET, SOCK_DGRAM, IPPROTO_UDP, &sock); + if (result < 0) { IP_VS_ERR("Error during creation of socket; terminating\n"); - return NULL; + return ERR_PTR(result); } /* it is equivalent to the REUSEADDR option in user-space */ sock->sk->sk_reuse = 1; - if (sock->ops->bind(sock, - (struct sockaddr*)&mcast_addr, - sizeof(struct sockaddr)) < 0) { + result = sock->ops->bind(sock, (struct sockaddr *) &mcast_addr, + sizeof(struct sockaddr)); + if (result < 0) { IP_VS_ERR("Error binding to the multicast addr\n"); goto error; } /* join the multicast group */ - if (join_mcast_group(sock->sk, - (struct in_addr*)&mcast_addr.sin_addr, - ip_vs_backup_mcast_ifn) < 0) { + result = join_mcast_group(sock->sk, + (struct in_addr *) &mcast_addr.sin_addr, + ip_vs_backup_mcast_ifn); + if (result < 0) { IP_VS_ERR("Error joining to the multicast group\n"); goto error; } @@ -644,7 +662,7 @@ static struct socket * make_receive_sock(void) error: sock_release(sock); - return NULL; + return ERR_PTR(result); } @@ -702,44 +720,29 @@ ip_vs_receive(struct socket *sock, char *buffer, const size_t buflen) } -static DECLARE_WAIT_QUEUE_HEAD(sync_wait); -static pid_t sync_master_pid = 0; -static pid_t sync_backup_pid = 0; - -static DECLARE_WAIT_QUEUE_HEAD(stop_sync_wait); -static int stop_master_sync = 0; -static int stop_backup_sync = 0; - -static void sync_master_loop(void) +static int sync_thread_master(void *data) { - struct socket *sock; + struct ip_vs_sync_thread_data *tinfo = data; struct ip_vs_sync_buff *sb; - /* create the sending multicast socket */ - sock = make_send_sock(); - if (!sock) - return; - IP_VS_INFO("sync thread started: state = MASTER, mcast_ifn = %s, " "syncid = %d\n", ip_vs_master_mcast_ifn, ip_vs_master_syncid); - for (;;) { - while ((sb=sb_dequeue())) { - ip_vs_send_sync_msg(sock, sb->mesg); + while (!kthread_should_stop()) { + while ((sb = sb_dequeue())) { + ip_vs_send_sync_msg(tinfo->sock, sb->mesg); ip_vs_sync_buff_release(sb); } /* check if entries stay in curr_sb for 2 seconds */ - if ((sb = get_curr_sync_buff(2*HZ))) { - ip_vs_send_sync_msg(sock, sb->mesg); + sb = get_curr_sync_buff(2 * HZ); + if (sb) { + ip_vs_send_sync_msg(tinfo->sock, sb->mesg); ip_vs_sync_buff_release(sb); } - if (stop_master_sync) - break; - - msleep_interruptible(1000); + schedule_timeout_interruptible(HZ); } /* clean up the sync_buff queue */ @@ -753,267 +756,175 @@ static void sync_master_loop(void) } /* release the sending multicast socket */ - sock_release(sock); + sock_release(tinfo->sock); + kfree(tinfo); + + return 0; } -static void sync_backup_loop(void) +static int sync_thread_backup(void *data) { - struct socket *sock; - char *buf; + struct ip_vs_sync_thread_data *tinfo = data; int len; - if (!(buf = kmalloc(sync_recv_mesg_maxlen, GFP_ATOMIC))) { - IP_VS_ERR("sync_backup_loop: kmalloc error\n"); - return; - } - - /* create the receiving multicast socket */ - sock = make_receive_sock(); - if (!sock) - goto out; - IP_VS_INFO("sync thread started: state = BACKUP, mcast_ifn = %s, " "syncid = %d\n", ip_vs_backup_mcast_ifn, ip_vs_backup_syncid); - for (;;) { - /* do you have data now? */ - while (!skb_queue_empty(&(sock->sk->sk_receive_queue))) { - if ((len = - ip_vs_receive(sock, buf, - sync_recv_mesg_maxlen)) <= 0) { + while (!kthread_should_stop()) { + wait_event_interruptible(*tinfo->sock->sk->sk_sleep, + !skb_queue_empty(&tinfo->sock->sk->sk_receive_queue) + || kthread_should_stop()); + + /* do we have data now? */ + while (!skb_queue_empty(&(tinfo->sock->sk->sk_receive_queue))) { + len = ip_vs_receive(tinfo->sock, tinfo->buf, + sync_recv_mesg_maxlen); + if (len <= 0) { IP_VS_ERR("receiving message error\n"); break; } - /* disable bottom half, because it accessed the data + + /* disable bottom half, because it accesses the data shared by softirq while getting/creating conns */ local_bh_disable(); - ip_vs_process_message(buf, len); + ip_vs_process_message(tinfo->buf, len); local_bh_enable(); } - - if (stop_backup_sync) - break; - - msleep_interruptible(1000); } /* release the sending multicast socket */ - sock_release(sock); + sock_release(tinfo->sock); + kfree(tinfo->buf); + kfree(tinfo); - out: - kfree(buf); + return 0; } -static void set_sync_pid(int sync_state, pid_t sync_pid) -{ - if (sync_state == IP_VS_STATE_MASTER) - sync_master_pid = sync_pid; - else if (sync_state == IP_VS_STATE_BACKUP) - sync_backup_pid = sync_pid; -} - -static void set_stop_sync(int sync_state, int set) +int start_sync_thread(int state, char *mcast_ifn, __u8 syncid) { - if (sync_state == IP_VS_STATE_MASTER) - stop_master_sync = set; - else if (sync_state == IP_VS_STATE_BACKUP) - stop_backup_sync = set; - else { - stop_master_sync = set; - stop_backup_sync = set; - } -} + struct ip_vs_sync_thread_data *tinfo; + struct task_struct **realtask, *task; + struct socket *sock; + char *name, *buf = NULL; + int (*threadfn)(void *data); + int result = -ENOMEM; -static int sync_thread(void *startup) -{ - DECLARE_WAITQUEUE(wait, current); - mm_segment_t oldmm; - int state; - const char *name; - struct ip_vs_sync_thread_data *tinfo = startup; + IP_VS_DBG(7, "%s: pid %d\n", __func__, task_pid_nr(current)); + IP_VS_DBG(7, "Each ip_vs_sync_conn entry needs %Zd bytes\n", + sizeof(struct ip_vs_sync_conn)); - /* increase the module use count */ - ip_vs_use_count_inc(); + if (state == IP_VS_STATE_MASTER) { + if (sync_master_thread) + return -EEXIST; - if (ip_vs_sync_state & IP_VS_STATE_MASTER && !sync_master_pid) { - state = IP_VS_STATE_MASTER; + strlcpy(ip_vs_master_mcast_ifn, mcast_ifn, + sizeof(ip_vs_master_mcast_ifn)); + ip_vs_master_syncid = syncid; + realtask = &sync_master_thread; name = "ipvs_syncmaster"; - } else if (ip_vs_sync_state & IP_VS_STATE_BACKUP && !sync_backup_pid) { - state = IP_VS_STATE_BACKUP; + threadfn = sync_thread_master; + sock = make_send_sock(); + } else if (state == IP_VS_STATE_BACKUP) { + if (sync_backup_thread) + return -EEXIST; + + strlcpy(ip_vs_backup_mcast_ifn, mcast_ifn, + sizeof(ip_vs_backup_mcast_ifn)); + ip_vs_backup_syncid = syncid; + realtask = &sync_backup_thread; name = "ipvs_syncbackup"; + threadfn = sync_thread_backup; + sock = make_receive_sock(); } else { - IP_VS_BUG(); - ip_vs_use_count_dec(); return -EINVAL; } - daemonize(name); - - oldmm = get_fs(); - set_fs(KERNEL_DS); - - /* Block all signals */ - spin_lock_irq(¤t->sighand->siglock); - siginitsetinv(¤t->blocked, 0); - recalc_sigpending(); - spin_unlock_irq(¤t->sighand->siglock); + if (IS_ERR(sock)) { + result = PTR_ERR(sock); + goto out; + } - /* set the maximum length of sync message */ set_sync_mesg_maxlen(state); + if (state == IP_VS_STATE_BACKUP) { + buf = kmalloc(sync_recv_mesg_maxlen, GFP_KERNEL); + if (!buf) + goto outsocket; + } - /* set up multicast address */ - mcast_addr.sin_family = AF_INET; - mcast_addr.sin_port = htons(IP_VS_SYNC_PORT); - mcast_addr.sin_addr.s_addr = htonl(IP_VS_SYNC_GROUP); - - add_wait_queue(&sync_wait, &wait); - - set_sync_pid(state, task_pid_nr(current)); - complete(tinfo->startup); - - /* - * once we call the completion queue above, we should - * null out that reference, since its allocated on the - * stack of the creating kernel thread - */ - tinfo->startup = NULL; - - /* processing master/backup loop here */ - if (state == IP_VS_STATE_MASTER) - sync_master_loop(); - else if (state == IP_VS_STATE_BACKUP) - sync_backup_loop(); - else IP_VS_BUG(); - - remove_wait_queue(&sync_wait, &wait); - - /* thread exits */ - - /* - * If we weren't explicitly stopped, then we - * exited in error, and should undo our state - */ - if ((!stop_master_sync) && (!stop_backup_sync)) - ip_vs_sync_state -= tinfo->state; + tinfo = kmalloc(sizeof(*tinfo), GFP_KERNEL); + if (!tinfo) + goto outbuf; - set_sync_pid(state, 0); - IP_VS_INFO("sync thread stopped!\n"); + tinfo->sock = sock; + tinfo->buf = buf; - set_fs(oldmm); + task = kthread_run(threadfn, tinfo, name); + if (IS_ERR(task)) { + result = PTR_ERR(task); + goto outtinfo; + } - /* decrease the module use count */ - ip_vs_use_count_dec(); + /* mark as active */ + *realtask = task; + ip_vs_sync_state |= state; - set_stop_sync(state, 0); - wake_up(&stop_sync_wait); + /* increase the module use count */ + ip_vs_use_count_inc(); - /* - * we need to free the structure that was allocated - * for us in start_sync_thread - */ - kfree(tinfo); return 0; -} - - -static int fork_sync_thread(void *startup) -{ - pid_t pid; - - /* fork the sync thread here, then the parent process of the - sync thread is the init process after this thread exits. */ - repeat: - if ((pid = kernel_thread(sync_thread, startup, 0)) < 0) { - IP_VS_ERR("could not create sync_thread due to %d... " - "retrying.\n", pid); - msleep_interruptible(1000); - goto repeat; - } - return 0; +outtinfo: + kfree(tinfo); +outbuf: + kfree(buf); +outsocket: + sock_release(sock); +out: + return result; } -int start_sync_thread(int state, char *mcast_ifn, __u8 syncid) +int stop_sync_thread(int state) { - DECLARE_COMPLETION_ONSTACK(startup); - pid_t pid; - struct ip_vs_sync_thread_data *tinfo; - - if ((state == IP_VS_STATE_MASTER && sync_master_pid) || - (state == IP_VS_STATE_BACKUP && sync_backup_pid)) - return -EEXIST; - - /* - * Note that tinfo will be freed in sync_thread on exit - */ - tinfo = kmalloc(sizeof(struct ip_vs_sync_thread_data), GFP_KERNEL); - if (!tinfo) - return -ENOMEM; - IP_VS_DBG(7, "%s: pid %d\n", __func__, task_pid_nr(current)); - IP_VS_DBG(7, "Each ip_vs_sync_conn entry need %Zd bytes\n", - sizeof(struct ip_vs_sync_conn)); - ip_vs_sync_state |= state; if (state == IP_VS_STATE_MASTER) { - strlcpy(ip_vs_master_mcast_ifn, mcast_ifn, - sizeof(ip_vs_master_mcast_ifn)); - ip_vs_master_syncid = syncid; - } else { - strlcpy(ip_vs_backup_mcast_ifn, mcast_ifn, - sizeof(ip_vs_backup_mcast_ifn)); - ip_vs_backup_syncid = syncid; - } - - tinfo->state = state; - tinfo->startup = &startup; - - repeat: - if ((pid = kernel_thread(fork_sync_thread, tinfo, 0)) < 0) { - IP_VS_ERR("could not create fork_sync_thread due to %d... " - "retrying.\n", pid); - msleep_interruptible(1000); - goto repeat; - } - - wait_for_completion(&startup); - - return 0; -} + if (!sync_master_thread) + return -ESRCH; + IP_VS_INFO("stopping master sync thread %d ...\n", + task_pid_nr(sync_master_thread)); -int stop_sync_thread(int state) -{ - DECLARE_WAITQUEUE(wait, current); + /* + * The lock synchronizes with sb_queue_tail(), so that we don't + * add sync buffers to the queue, when we are already in + * progress of stopping the master sync daemon. + */ - if ((state == IP_VS_STATE_MASTER && !sync_master_pid) || - (state == IP_VS_STATE_BACKUP && !sync_backup_pid)) - return -ESRCH; + spin_lock(&ip_vs_sync_lock); + ip_vs_sync_state &= ~IP_VS_STATE_MASTER; + spin_unlock(&ip_vs_sync_lock); + kthread_stop(sync_master_thread); + sync_master_thread = NULL; + } else if (state == IP_VS_STATE_BACKUP) { + if (!sync_backup_thread) + return -ESRCH; + + IP_VS_INFO("stopping backup sync thread %d ...\n", + task_pid_nr(sync_backup_thread)); + + ip_vs_sync_state &= ~IP_VS_STATE_BACKUP; + kthread_stop(sync_backup_thread); + sync_backup_thread = NULL; + } else { + return -EINVAL; + } - IP_VS_DBG(7, "%s: pid %d\n", __func__, task_pid_nr(current)); - IP_VS_INFO("stopping sync thread %d ...\n", - (state == IP_VS_STATE_MASTER) ? - sync_master_pid : sync_backup_pid); - - __set_current_state(TASK_UNINTERRUPTIBLE); - add_wait_queue(&stop_sync_wait, &wait); - set_stop_sync(state, 1); - ip_vs_sync_state -= state; - wake_up(&sync_wait); - schedule(); - __set_current_state(TASK_RUNNING); - remove_wait_queue(&stop_sync_wait, &wait); - - /* Note: no need to reap the sync thread, because its parent - process is the init process */ - - if ((state == IP_VS_STATE_MASTER && stop_master_sync) || - (state == IP_VS_STATE_BACKUP && stop_backup_sync)) - IP_VS_BUG(); + /* decrease the module use count */ + ip_vs_use_count_dec(); return 0; } diff --git a/net/ipv4/ipvs/ip_vs_wlc.c b/net/ipv4/ipvs/ip_vs_wlc.c index 8a9d913261d8..772c3cb4eca1 100644 --- a/net/ipv4/ipvs/ip_vs_wlc.c +++ b/net/ipv4/ipvs/ip_vs_wlc.c @@ -1,8 +1,6 @@ /* * IPVS: Weighted Least-Connection Scheduling module * - * Version: $Id: ip_vs_wlc.c,v 1.13 2003/04/18 09:03:16 wensong Exp $ - * * Authors: Wensong Zhang <wensong@linuxvirtualserver.org> * Peter Kese <peter.kese@ijs.si> * diff --git a/net/ipv4/ipvs/ip_vs_wrr.c b/net/ipv4/ipvs/ip_vs_wrr.c index 85c680add6df..1d6932d7dc97 100644 --- a/net/ipv4/ipvs/ip_vs_wrr.c +++ b/net/ipv4/ipvs/ip_vs_wrr.c @@ -1,8 +1,6 @@ /* * IPVS: Weighted Round-Robin Scheduling module * - * Version: $Id: ip_vs_wrr.c,v 1.12 2002/09/15 08:14:08 wensong Exp $ - * * Authors: Wensong Zhang <wensong@linuxvirtualserver.org> * * This program is free software; you can redistribute it and/or diff --git a/net/ipv4/ipvs/ip_vs_xmit.c b/net/ipv4/ipvs/ip_vs_xmit.c index f63006caea03..9892d4aca42e 100644 --- a/net/ipv4/ipvs/ip_vs_xmit.c +++ b/net/ipv4/ipvs/ip_vs_xmit.c @@ -1,8 +1,6 @@ /* * ip_vs_xmit.c: various packet transmitters for IPVS * - * Version: $Id: ip_vs_xmit.c,v 1.2 2002/11/30 01:50:35 wensong Exp $ - * * Authors: Wensong Zhang <wensong@linuxvirtualserver.org> * Julian Anastasov <ja@ssi.bg> * diff --git a/net/ipv4/netfilter/Kconfig b/net/ipv4/netfilter/Kconfig index 2767841a8cef..f23e60c93ef9 100644 --- a/net/ipv4/netfilter/Kconfig +++ b/net/ipv4/netfilter/Kconfig @@ -213,8 +213,7 @@ config IP_NF_TARGET_NETMAP help NETMAP is an implementation of static 1:1 NAT mapping of network addresses. It maps the network address part, while keeping the host - address part intact. It is similar to Fast NAT, except that - Netfilter's connection tracking doesn't work well with Fast NAT. + address part intact. To compile it as a module, choose M here. If unsure, say N. @@ -365,6 +364,18 @@ config IP_NF_RAW If you want to compile it as a module, say M here and read <file:Documentation/kbuild/modules.txt>. If unsure, say `N'. +# security table for MAC policy +config IP_NF_SECURITY + tristate "Security table" + depends on IP_NF_IPTABLES + depends on SECURITY + default m if NETFILTER_ADVANCED=n + help + This option adds a `security' table to iptables, for use + with Mandatory Access Control (MAC) policy. + + If unsure, say N. + # ARP tables config IP_NF_ARPTABLES tristate "ARP tables support" diff --git a/net/ipv4/netfilter/Makefile b/net/ipv4/netfilter/Makefile index d9b92fbf5579..3f31291f37ce 100644 --- a/net/ipv4/netfilter/Makefile +++ b/net/ipv4/netfilter/Makefile @@ -42,6 +42,7 @@ obj-$(CONFIG_IP_NF_FILTER) += iptable_filter.o obj-$(CONFIG_IP_NF_MANGLE) += iptable_mangle.o obj-$(CONFIG_NF_NAT) += iptable_nat.o obj-$(CONFIG_IP_NF_RAW) += iptable_raw.o +obj-$(CONFIG_IP_NF_SECURITY) += iptable_security.o # matches obj-$(CONFIG_IP_NF_MATCH_ADDRTYPE) += ipt_addrtype.o diff --git a/net/ipv4/netfilter/ip_queue.c b/net/ipv4/netfilter/ip_queue.c index 26a37cedcf2e..432ce9d1c11c 100644 --- a/net/ipv4/netfilter/ip_queue.c +++ b/net/ipv4/netfilter/ip_queue.c @@ -156,7 +156,6 @@ ipq_build_packet_message(struct nf_queue_entry *entry, int *errp) case IPQ_COPY_META: case IPQ_COPY_NONE: size = NLMSG_SPACE(sizeof(*pmsg)); - data_len = 0; break; case IPQ_COPY_PACKET: @@ -224,8 +223,6 @@ ipq_build_packet_message(struct nf_queue_entry *entry, int *errp) return skb; nlmsg_failure: - if (skb) - kfree_skb(skb); *errp = -EINVAL; printk(KERN_ERR "ip_queue: error creating packet message\n"); return NULL; @@ -480,7 +477,7 @@ ipq_rcv_dev_event(struct notifier_block *this, { struct net_device *dev = ptr; - if (dev_net(dev) != &init_net) + if (!net_eq(dev_net(dev), &init_net)) return NOTIFY_DONE; /* Drop any packets associated with the downed device */ diff --git a/net/ipv4/netfilter/ipt_MASQUERADE.c b/net/ipv4/netfilter/ipt_MASQUERADE.c index 84c26dd27d81..0841aefaa503 100644 --- a/net/ipv4/netfilter/ipt_MASQUERADE.c +++ b/net/ipv4/netfilter/ipt_MASQUERADE.c @@ -120,7 +120,7 @@ static int masq_device_event(struct notifier_block *this, { const struct net_device *dev = ptr; - if (dev_net(dev) != &init_net) + if (!net_eq(dev_net(dev), &init_net)) return NOTIFY_DONE; if (event == NETDEV_DOWN) { diff --git a/net/ipv4/netfilter/iptable_security.c b/net/ipv4/netfilter/iptable_security.c new file mode 100644 index 000000000000..2b472ac2263a --- /dev/null +++ b/net/ipv4/netfilter/iptable_security.c @@ -0,0 +1,180 @@ +/* + * "security" table + * + * This is for use by Mandatory Access Control (MAC) security models, + * which need to be able to manage security policy in separate context + * to DAC. + * + * Based on iptable_mangle.c + * + * Copyright (C) 1999 Paul `Rusty' Russell & Michael J. Neuling + * Copyright (C) 2000-2004 Netfilter Core Team <coreteam <at> netfilter.org> + * Copyright (C) 2008 Red Hat, Inc., James Morris <jmorris <at> redhat.com> + * + * 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 <linux/module.h> +#include <linux/netfilter_ipv4/ip_tables.h> +#include <net/ip.h> + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("James Morris <jmorris <at> redhat.com>"); +MODULE_DESCRIPTION("iptables security table, for MAC rules"); + +#define SECURITY_VALID_HOOKS (1 << NF_INET_LOCAL_IN) | \ + (1 << NF_INET_FORWARD) | \ + (1 << NF_INET_LOCAL_OUT) + +static struct +{ + struct ipt_replace repl; + struct ipt_standard entries[3]; + struct ipt_error term; +} initial_table __initdata = { + .repl = { + .name = "security", + .valid_hooks = SECURITY_VALID_HOOKS, + .num_entries = 4, + .size = sizeof(struct ipt_standard) * 3 + sizeof(struct ipt_error), + .hook_entry = { + [NF_INET_LOCAL_IN] = 0, + [NF_INET_FORWARD] = sizeof(struct ipt_standard), + [NF_INET_LOCAL_OUT] = sizeof(struct ipt_standard) * 2, + }, + .underflow = { + [NF_INET_LOCAL_IN] = 0, + [NF_INET_FORWARD] = sizeof(struct ipt_standard), + [NF_INET_LOCAL_OUT] = sizeof(struct ipt_standard) * 2, + }, + }, + .entries = { + IPT_STANDARD_INIT(NF_ACCEPT), /* LOCAL_IN */ + IPT_STANDARD_INIT(NF_ACCEPT), /* FORWARD */ + IPT_STANDARD_INIT(NF_ACCEPT), /* LOCAL_OUT */ + }, + .term = IPT_ERROR_INIT, /* ERROR */ +}; + +static struct xt_table security_table = { + .name = "security", + .valid_hooks = SECURITY_VALID_HOOKS, + .lock = __RW_LOCK_UNLOCKED(security_table.lock), + .me = THIS_MODULE, + .af = AF_INET, +}; + +static unsigned int +ipt_local_in_hook(unsigned int hook, + struct sk_buff *skb, + const struct net_device *in, + const struct net_device *out, + int (*okfn)(struct sk_buff *)) +{ + return ipt_do_table(skb, hook, in, out, + nf_local_in_net(in, out)->ipv4.iptable_security); +} + +static unsigned int +ipt_forward_hook(unsigned int hook, + struct sk_buff *skb, + const struct net_device *in, + const struct net_device *out, + int (*okfn)(struct sk_buff *)) +{ + return ipt_do_table(skb, hook, in, out, + nf_forward_net(in, out)->ipv4.iptable_security); +} + +static unsigned int +ipt_local_out_hook(unsigned int hook, + struct sk_buff *skb, + const struct net_device *in, + const struct net_device *out, + int (*okfn)(struct sk_buff *)) +{ + /* Somebody is playing with raw sockets. */ + if (skb->len < sizeof(struct iphdr) + || ip_hdrlen(skb) < sizeof(struct iphdr)) { + if (net_ratelimit()) + printk(KERN_INFO "iptable_security: ignoring short " + "SOCK_RAW packet.\n"); + return NF_ACCEPT; + } + return ipt_do_table(skb, hook, in, out, + nf_local_out_net(in, out)->ipv4.iptable_security); +} + +static struct nf_hook_ops ipt_ops[] __read_mostly = { + { + .hook = ipt_local_in_hook, + .owner = THIS_MODULE, + .pf = PF_INET, + .hooknum = NF_INET_LOCAL_IN, + .priority = NF_IP_PRI_SECURITY, + }, + { + .hook = ipt_forward_hook, + .owner = THIS_MODULE, + .pf = PF_INET, + .hooknum = NF_INET_FORWARD, + .priority = NF_IP_PRI_SECURITY, + }, + { + .hook = ipt_local_out_hook, + .owner = THIS_MODULE, + .pf = PF_INET, + .hooknum = NF_INET_LOCAL_OUT, + .priority = NF_IP_PRI_SECURITY, + }, +}; + +static int __net_init iptable_security_net_init(struct net *net) +{ + net->ipv4.iptable_security = + ipt_register_table(net, &security_table, &initial_table.repl); + + if (IS_ERR(net->ipv4.iptable_security)) + return PTR_ERR(net->ipv4.iptable_security); + + return 0; +} + +static void __net_exit iptable_security_net_exit(struct net *net) +{ + ipt_unregister_table(net->ipv4.iptable_security); +} + +static struct pernet_operations iptable_security_net_ops = { + .init = iptable_security_net_init, + .exit = iptable_security_net_exit, +}; + +static int __init iptable_security_init(void) +{ + int ret; + + ret = register_pernet_subsys(&iptable_security_net_ops); + if (ret < 0) + return ret; + + ret = nf_register_hooks(ipt_ops, ARRAY_SIZE(ipt_ops)); + if (ret < 0) + goto cleanup_table; + + return ret; + +cleanup_table: + unregister_pernet_subsys(&iptable_security_net_ops); + return ret; +} + +static void __exit iptable_security_fini(void) +{ + nf_unregister_hooks(ipt_ops, ARRAY_SIZE(ipt_ops)); + unregister_pernet_subsys(&iptable_security_net_ops); +} + +module_init(iptable_security_init); +module_exit(iptable_security_fini); diff --git a/net/ipv4/netfilter/nf_conntrack_proto_icmp.c b/net/ipv4/netfilter/nf_conntrack_proto_icmp.c index 78ab19accace..97791048fa9b 100644 --- a/net/ipv4/netfilter/nf_conntrack_proto_icmp.c +++ b/net/ipv4/netfilter/nf_conntrack_proto_icmp.c @@ -87,9 +87,8 @@ static int icmp_packet(struct nf_conn *ct, 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) - && del_timer(&ct->timeout)) - ct->timeout.function((unsigned long)ct); + if (atomic_dec_and_test(&ct->proto.icmp.count)) + nf_ct_kill_acct(ct, ctinfo, skb); } else { atomic_inc(&ct->proto.icmp.count); nf_conntrack_event_cache(IPCT_PROTOINFO_VOLATILE, skb); diff --git a/net/ipv4/netfilter/nf_nat_proto_sctp.c b/net/ipv4/netfilter/nf_nat_proto_sctp.c index 82e4c0e286b8..65e470bc6123 100644 --- a/net/ipv4/netfilter/nf_nat_proto_sctp.c +++ b/net/ipv4/netfilter/nf_nat_proto_sctp.c @@ -36,7 +36,7 @@ sctp_manip_pkt(struct sk_buff *skb, sctp_sctphdr_t *hdr; unsigned int hdroff = iphdroff + iph->ihl*4; __be32 oldip, newip; - u32 crc32; + __be32 crc32; if (!skb_make_writable(skb, hdroff + sizeof(*hdr))) return false; @@ -61,7 +61,7 @@ sctp_manip_pkt(struct sk_buff *skb, crc32 = sctp_update_cksum((u8 *)skb->data, skb_headlen(skb), crc32); crc32 = sctp_end_cksum(crc32); - hdr->checksum = htonl(crc32); + hdr->checksum = crc32; return true; } diff --git a/net/ipv4/proc.c b/net/ipv4/proc.c index 552169b41b16..834356ea99df 100644 --- a/net/ipv4/proc.c +++ b/net/ipv4/proc.c @@ -7,8 +7,6 @@ * PROC file system. It is mainly used for debugging and * statistics. * - * Version: $Id: proc.c,v 1.45 2001/05/16 16:45:35 davem Exp $ - * * Authors: Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG> * Gerald J. Heim, <heim@peanuts.informatik.uni-tuebingen.de> * Fred Baumgarten, <dc6iq@insu1.etec.uni-karlsruhe.de> @@ -73,32 +71,7 @@ static int sockstat_seq_show(struct seq_file *seq, void *v) static int sockstat_seq_open(struct inode *inode, struct file *file) { - int err; - struct net *net; - - err = -ENXIO; - net = get_proc_net(inode); - if (net == NULL) - goto err_net; - - err = single_open(file, sockstat_seq_show, net); - if (err < 0) - goto err_open; - - return 0; - -err_open: - put_net(net); -err_net: - return err; -} - -static int sockstat_seq_release(struct inode *inode, struct file *file) -{ - struct net *net = ((struct seq_file *)file->private_data)->private; - - put_net(net); - return single_release(inode, file); + return single_open_net(inode, file, sockstat_seq_show); } static const struct file_operations sockstat_seq_fops = { @@ -106,7 +79,7 @@ static const struct file_operations sockstat_seq_fops = { .open = sockstat_seq_open, .read = seq_read, .llseek = seq_lseek, - .release = sockstat_seq_release, + .release = single_release_net, }; /* snmp items */ @@ -268,11 +241,12 @@ static void icmpmsg_put(struct seq_file *seq) int j, i, count; static int out[PERLINE]; + struct net *net = seq->private; count = 0; for (i = 0; i < ICMPMSG_MIB_MAX; i++) { - if (snmp_fold_field((void **) icmpmsg_statistics, i)) + if (snmp_fold_field((void **) net->mib.icmpmsg_statistics, i)) out[count++] = i; if (count < PERLINE) continue; @@ -284,7 +258,7 @@ static void icmpmsg_put(struct seq_file *seq) seq_printf(seq, "\nIcmpMsg: "); for (j = 0; j < PERLINE; ++j) seq_printf(seq, " %lu", - snmp_fold_field((void **) icmpmsg_statistics, + snmp_fold_field((void **) net->mib.icmpmsg_statistics, out[j])); seq_putc(seq, '\n'); } @@ -296,7 +270,7 @@ static void icmpmsg_put(struct seq_file *seq) seq_printf(seq, "\nIcmpMsg:"); for (j = 0; j < count; ++j) seq_printf(seq, " %lu", snmp_fold_field((void **) - icmpmsg_statistics, out[j])); + net->mib.icmpmsg_statistics, out[j])); } #undef PERLINE @@ -305,6 +279,7 @@ static void icmpmsg_put(struct seq_file *seq) static void icmp_put(struct seq_file *seq) { int i; + struct net *net = seq->private; seq_puts(seq, "\nIcmp: InMsgs InErrors"); for (i=0; icmpmibmap[i].name != NULL; i++) @@ -313,18 +288,18 @@ static void icmp_put(struct seq_file *seq) for (i=0; icmpmibmap[i].name != NULL; i++) seq_printf(seq, " Out%s", icmpmibmap[i].name); seq_printf(seq, "\nIcmp: %lu %lu", - snmp_fold_field((void **) icmp_statistics, ICMP_MIB_INMSGS), - snmp_fold_field((void **) icmp_statistics, ICMP_MIB_INERRORS)); + snmp_fold_field((void **) net->mib.icmp_statistics, ICMP_MIB_INMSGS), + snmp_fold_field((void **) net->mib.icmp_statistics, ICMP_MIB_INERRORS)); for (i=0; icmpmibmap[i].name != NULL; i++) seq_printf(seq, " %lu", - snmp_fold_field((void **) icmpmsg_statistics, + snmp_fold_field((void **) net->mib.icmpmsg_statistics, icmpmibmap[i].index)); seq_printf(seq, " %lu %lu", - snmp_fold_field((void **) icmp_statistics, ICMP_MIB_OUTMSGS), - snmp_fold_field((void **) icmp_statistics, ICMP_MIB_OUTERRORS)); + snmp_fold_field((void **) net->mib.icmp_statistics, ICMP_MIB_OUTMSGS), + snmp_fold_field((void **) net->mib.icmp_statistics, ICMP_MIB_OUTERRORS)); for (i=0; icmpmibmap[i].name != NULL; i++) seq_printf(seq, " %lu", - snmp_fold_field((void **) icmpmsg_statistics, + snmp_fold_field((void **) net->mib.icmpmsg_statistics, icmpmibmap[i].index | 0x100)); } @@ -334,6 +309,7 @@ static void icmp_put(struct seq_file *seq) static int snmp_seq_show(struct seq_file *seq, void *v) { int i; + struct net *net = seq->private; seq_puts(seq, "Ip: Forwarding DefaultTTL"); @@ -341,12 +317,12 @@ static int snmp_seq_show(struct seq_file *seq, void *v) seq_printf(seq, " %s", snmp4_ipstats_list[i].name); seq_printf(seq, "\nIp: %d %d", - IPV4_DEVCONF_ALL(&init_net, FORWARDING) ? 1 : 2, + IPV4_DEVCONF_ALL(net, FORWARDING) ? 1 : 2, sysctl_ip_default_ttl); for (i = 0; snmp4_ipstats_list[i].name != NULL; i++) seq_printf(seq, " %lu", - snmp_fold_field((void **)ip_statistics, + snmp_fold_field((void **)net->mib.ip_statistics, snmp4_ipstats_list[i].entry)); icmp_put(seq); /* RFC 2011 compatibility */ @@ -361,11 +337,11 @@ static int snmp_seq_show(struct seq_file *seq, void *v) /* MaxConn field is signed, RFC 2012 */ if (snmp4_tcp_list[i].entry == TCP_MIB_MAXCONN) seq_printf(seq, " %ld", - snmp_fold_field((void **)tcp_statistics, + snmp_fold_field((void **)net->mib.tcp_statistics, snmp4_tcp_list[i].entry)); else seq_printf(seq, " %lu", - snmp_fold_field((void **)tcp_statistics, + snmp_fold_field((void **)net->mib.tcp_statistics, snmp4_tcp_list[i].entry)); } @@ -376,7 +352,7 @@ static int snmp_seq_show(struct seq_file *seq, void *v) seq_puts(seq, "\nUdp:"); for (i = 0; snmp4_udp_list[i].name != NULL; i++) seq_printf(seq, " %lu", - snmp_fold_field((void **)udp_statistics, + snmp_fold_field((void **)net->mib.udp_statistics, snmp4_udp_list[i].entry)); /* the UDP and UDP-Lite MIBs are the same */ @@ -387,7 +363,7 @@ static int snmp_seq_show(struct seq_file *seq, void *v) seq_puts(seq, "\nUdpLite:"); for (i = 0; snmp4_udp_list[i].name != NULL; i++) seq_printf(seq, " %lu", - snmp_fold_field((void **)udplite_statistics, + snmp_fold_field((void **)net->mib.udplite_statistics, snmp4_udp_list[i].entry)); seq_putc(seq, '\n'); @@ -396,7 +372,7 @@ static int snmp_seq_show(struct seq_file *seq, void *v) static int snmp_seq_open(struct inode *inode, struct file *file) { - return single_open(file, snmp_seq_show, NULL); + return single_open_net(inode, file, snmp_seq_show); } static const struct file_operations snmp_seq_fops = { @@ -404,7 +380,7 @@ static const struct file_operations snmp_seq_fops = { .open = snmp_seq_open, .read = seq_read, .llseek = seq_lseek, - .release = single_release, + .release = single_release_net, }; @@ -415,6 +391,7 @@ static const struct file_operations snmp_seq_fops = { static int netstat_seq_show(struct seq_file *seq, void *v) { int i; + struct net *net = seq->private; seq_puts(seq, "TcpExt:"); for (i = 0; snmp4_net_list[i].name != NULL; i++) @@ -423,7 +400,7 @@ static int netstat_seq_show(struct seq_file *seq, void *v) seq_puts(seq, "\nTcpExt:"); for (i = 0; snmp4_net_list[i].name != NULL; i++) seq_printf(seq, " %lu", - snmp_fold_field((void **)net_statistics, + snmp_fold_field((void **)net->mib.net_statistics, snmp4_net_list[i].entry)); seq_puts(seq, "\nIpExt:"); @@ -433,7 +410,7 @@ static int netstat_seq_show(struct seq_file *seq, void *v) seq_puts(seq, "\nIpExt:"); for (i = 0; snmp4_ipextstats_list[i].name != NULL; i++) seq_printf(seq, " %lu", - snmp_fold_field((void **)ip_statistics, + snmp_fold_field((void **)net->mib.ip_statistics, snmp4_ipextstats_list[i].entry)); seq_putc(seq, '\n'); @@ -442,7 +419,7 @@ static int netstat_seq_show(struct seq_file *seq, void *v) static int netstat_seq_open(struct inode *inode, struct file *file) { - return single_open(file, netstat_seq_show, NULL); + return single_open_net(inode, file, netstat_seq_show); } static const struct file_operations netstat_seq_fops = { @@ -450,18 +427,32 @@ static const struct file_operations netstat_seq_fops = { .open = netstat_seq_open, .read = seq_read, .llseek = seq_lseek, - .release = single_release, + .release = single_release_net, }; static __net_init int ip_proc_init_net(struct net *net) { if (!proc_net_fops_create(net, "sockstat", S_IRUGO, &sockstat_seq_fops)) - return -ENOMEM; + goto out_sockstat; + if (!proc_net_fops_create(net, "netstat", S_IRUGO, &netstat_seq_fops)) + goto out_netstat; + if (!proc_net_fops_create(net, "snmp", S_IRUGO, &snmp_seq_fops)) + goto out_snmp; + return 0; + +out_snmp: + proc_net_remove(net, "netstat"); +out_netstat: + proc_net_remove(net, "sockstat"); +out_sockstat: + return -ENOMEM; } static __net_exit void ip_proc_exit_net(struct net *net) { + proc_net_remove(net, "snmp"); + proc_net_remove(net, "netstat"); proc_net_remove(net, "sockstat"); } @@ -472,24 +463,6 @@ static __net_initdata struct pernet_operations ip_proc_ops = { int __init ip_misc_proc_init(void) { - int rc = 0; - - if (register_pernet_subsys(&ip_proc_ops)) - goto out_pernet; - - if (!proc_net_fops_create(&init_net, "netstat", S_IRUGO, &netstat_seq_fops)) - goto out_netstat; - - if (!proc_net_fops_create(&init_net, "snmp", S_IRUGO, &snmp_seq_fops)) - goto out_snmp; -out: - return rc; -out_snmp: - proc_net_remove(&init_net, "netstat"); -out_netstat: - unregister_pernet_subsys(&ip_proc_ops); -out_pernet: - rc = -ENOMEM; - goto out; + return register_pernet_subsys(&ip_proc_ops); } diff --git a/net/ipv4/protocol.c b/net/ipv4/protocol.c index 971ab9356e51..ea50da0649fd 100644 --- a/net/ipv4/protocol.c +++ b/net/ipv4/protocol.c @@ -5,8 +5,6 @@ * * INET protocol dispatch tables. * - * Version: $Id: protocol.c,v 1.14 2001/05/18 02:25:49 davem Exp $ - * * Authors: Ross Biro * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG> * diff --git a/net/ipv4/raw.c b/net/ipv4/raw.c index 37a1ecd9d600..cd975743bcd2 100644 --- a/net/ipv4/raw.c +++ b/net/ipv4/raw.c @@ -5,8 +5,6 @@ * * RAW - implementation of IP "raw" sockets. * - * Version: $Id: raw.c,v 1.64 2002/02/01 22:01:04 davem Exp $ - * * Authors: Ross Biro * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG> * @@ -322,6 +320,7 @@ static int raw_send_hdrinc(struct sock *sk, void *from, size_t length, unsigned int flags) { struct inet_sock *inet = inet_sk(sk); + struct net *net = sock_net(sk); struct iphdr *iph; struct sk_buff *skb; unsigned int iphlen; @@ -370,7 +369,7 @@ static int raw_send_hdrinc(struct sock *sk, void *from, size_t length, iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl); } if (iph->protocol == IPPROTO_ICMP) - icmp_out_count(((struct icmphdr *) + icmp_out_count(net, ((struct icmphdr *) skb_transport_header(skb))->type); err = NF_HOOK(PF_INET, NF_INET_LOCAL_OUT, skb, NULL, rt->u.dst.dev, @@ -386,7 +385,7 @@ error_fault: err = -EFAULT; kfree_skb(skb); error: - IP_INC_STATS(IPSTATS_MIB_OUTDISCARDS); + IP_INC_STATS(net, IPSTATS_MIB_OUTDISCARDS); return err; } @@ -608,12 +607,11 @@ static void raw_close(struct sock *sk, long timeout) sk_common_release(sk); } -static int raw_destroy(struct sock *sk) +static void raw_destroy(struct sock *sk) { lock_sock(sk); ip_flush_pending_frames(sk); release_sock(sk); - return 0; } /* This gets rid of all the nasties in af_inet. -DaveM */ @@ -947,7 +945,7 @@ static int raw_seq_show(struct seq_file *seq, void *v) if (v == SEQ_START_TOKEN) seq_printf(seq, " sl local_address rem_address st tx_queue " "rx_queue tr tm->when retrnsmt uid timeout " - "inode drops\n"); + "inode ref pointer drops\n"); else raw_sock_seq_show(seq, v, raw_seq_private(seq)->bucket); return 0; diff --git a/net/ipv4/route.c b/net/ipv4/route.c index 96be336064fb..e4ab0ac94f92 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c @@ -5,8 +5,6 @@ * * ROUTE - implementation of the IP router. * - * Version: $Id: route.c,v 1.103 2002/01/12 07:44:09 davem Exp $ - * * Authors: Ross Biro * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG> * Alan Cox, <gw4pts@gw4pts.ampr.org> @@ -134,7 +132,6 @@ static int ip_rt_secret_interval __read_mostly = 10 * 60 * HZ; static void rt_worker_func(struct work_struct *work); static DECLARE_DELAYED_WORK(expires_work, rt_worker_func); -static struct timer_list rt_secret_timer; /* * Interface to generic destination cache. @@ -253,20 +250,25 @@ static inline void rt_hash_lock_init(void) static struct rt_hash_bucket *rt_hash_table __read_mostly; static unsigned rt_hash_mask __read_mostly; static unsigned int rt_hash_log __read_mostly; -static atomic_t rt_genid __read_mostly; static DEFINE_PER_CPU(struct rt_cache_stat, rt_cache_stat); #define RT_CACHE_STAT_INC(field) \ (__raw_get_cpu_var(rt_cache_stat).field++) -static inline unsigned int rt_hash(__be32 daddr, __be32 saddr, int idx) +static inline unsigned int rt_hash(__be32 daddr, __be32 saddr, int idx, + int genid) { return jhash_3words((__force u32)(__be32)(daddr), (__force u32)(__be32)(saddr), - idx, atomic_read(&rt_genid)) + idx, genid) & rt_hash_mask; } +static inline int rt_genid(struct net *net) +{ + return atomic_read(&net->ipv4.rt_genid); +} + #ifdef CONFIG_PROC_FS struct rt_cache_iter_state { struct seq_net_private p; @@ -336,7 +338,7 @@ static void *rt_cache_seq_start(struct seq_file *seq, loff_t *pos) struct rt_cache_iter_state *st = seq->private; if (*pos) return rt_cache_get_idx(seq, *pos - 1); - st->genid = atomic_read(&rt_genid); + st->genid = rt_genid(seq_file_net(seq)); return SEQ_START_TOKEN; } @@ -683,6 +685,11 @@ static inline int compare_netns(struct rtable *rt1, struct rtable *rt2) return dev_net(rt1->u.dst.dev) == dev_net(rt2->u.dst.dev); } +static inline int rt_is_expired(struct rtable *rth) +{ + return rth->rt_genid != rt_genid(dev_net(rth->u.dst.dev)); +} + /* * Perform a full scan of hash table and free all entries. * Can be called by a softirq or a process. @@ -692,6 +699,7 @@ static void rt_do_flush(int process_context) { unsigned int i; struct rtable *rth, *next; + struct rtable * tail; for (i = 0; i <= rt_hash_mask; i++) { if (process_context && need_resched()) @@ -701,11 +709,39 @@ static void rt_do_flush(int process_context) continue; spin_lock_bh(rt_hash_lock_addr(i)); +#ifdef CONFIG_NET_NS + { + struct rtable ** prev, * p; + + rth = rt_hash_table[i].chain; + + /* defer releasing the head of the list after spin_unlock */ + for (tail = rth; tail; tail = tail->u.dst.rt_next) + if (!rt_is_expired(tail)) + break; + if (rth != tail) + rt_hash_table[i].chain = tail; + + /* call rt_free on entries after the tail requiring flush */ + prev = &rt_hash_table[i].chain; + for (p = *prev; p; p = next) { + next = p->u.dst.rt_next; + if (!rt_is_expired(p)) { + prev = &p->u.dst.rt_next; + } else { + *prev = next; + rt_free(p); + } + } + } +#else rth = rt_hash_table[i].chain; rt_hash_table[i].chain = NULL; + tail = NULL; +#endif spin_unlock_bh(rt_hash_lock_addr(i)); - for (; rth; rth = next) { + for (; rth != tail; rth = next) { next = rth->u.dst.rt_next; rt_free(rth); } @@ -738,7 +774,7 @@ static void rt_check_expire(void) continue; spin_lock_bh(rt_hash_lock_addr(i)); while ((rth = *rthp) != NULL) { - if (rth->rt_genid != atomic_read(&rt_genid)) { + if (rt_is_expired(rth)) { *rthp = rth->u.dst.rt_next; rt_free(rth); continue; @@ -781,21 +817,21 @@ static void rt_worker_func(struct work_struct *work) * many times (2^24) without giving recent rt_genid. * Jenkins hash is strong enough that litle changes of rt_genid are OK. */ -static void rt_cache_invalidate(void) +static void rt_cache_invalidate(struct net *net) { unsigned char shuffle; get_random_bytes(&shuffle, sizeof(shuffle)); - atomic_add(shuffle + 1U, &rt_genid); + atomic_add(shuffle + 1U, &net->ipv4.rt_genid); } /* * delay < 0 : invalidate cache (fast : entries will be deleted later) * delay >= 0 : invalidate & flush cache (can be long) */ -void rt_cache_flush(int delay) +void rt_cache_flush(struct net *net, int delay) { - rt_cache_invalidate(); + rt_cache_invalidate(net); if (delay >= 0) rt_do_flush(!in_softirq()); } @@ -803,10 +839,11 @@ void rt_cache_flush(int delay) /* * We change rt_genid and let gc do the cleanup */ -static void rt_secret_rebuild(unsigned long dummy) +static void rt_secret_rebuild(unsigned long __net) { - rt_cache_invalidate(); - mod_timer(&rt_secret_timer, jiffies + ip_rt_secret_interval); + struct net *net = (struct net *)__net; + rt_cache_invalidate(net); + mod_timer(&net->ipv4.rt_secret_timer, jiffies + ip_rt_secret_interval); } /* @@ -882,7 +919,7 @@ static int rt_garbage_collect(struct dst_ops *ops) rthp = &rt_hash_table[k].chain; spin_lock_bh(rt_hash_lock_addr(k)); while ((rth = *rthp) != NULL) { - if (rth->rt_genid == atomic_read(&rt_genid) && + if (!rt_is_expired(rth) && !rt_may_expire(rth, tmo, expire)) { tmo >>= 1; rthp = &rth->u.dst.rt_next; @@ -964,7 +1001,7 @@ restart: spin_lock_bh(rt_hash_lock_addr(hash)); while ((rth = *rthp) != NULL) { - if (rth->rt_genid != atomic_read(&rt_genid)) { + if (rt_is_expired(rth)) { *rthp = rth->u.dst.rt_next; rt_free(rth); continue; @@ -1140,7 +1177,7 @@ static void rt_del(unsigned hash, struct rtable *rt) spin_lock_bh(rt_hash_lock_addr(hash)); ip_rt_put(rt); while ((aux = *rthp) != NULL) { - if (aux == rt || (aux->rt_genid != atomic_read(&rt_genid))) { + if (aux == rt || rt_is_expired(aux)) { *rthp = aux->u.dst.rt_next; rt_free(aux); continue; @@ -1182,7 +1219,8 @@ void ip_rt_redirect(__be32 old_gw, __be32 daddr, __be32 new_gw, for (i = 0; i < 2; i++) { for (k = 0; k < 2; k++) { - unsigned hash = rt_hash(daddr, skeys[i], ikeys[k]); + unsigned hash = rt_hash(daddr, skeys[i], ikeys[k], + rt_genid(net)); rthp=&rt_hash_table[hash].chain; @@ -1194,7 +1232,7 @@ void ip_rt_redirect(__be32 old_gw, __be32 daddr, __be32 new_gw, rth->fl.fl4_src != skeys[i] || rth->fl.oif != ikeys[k] || rth->fl.iif != 0 || - rth->rt_genid != atomic_read(&rt_genid) || + rt_is_expired(rth) || !net_eq(dev_net(rth->u.dst.dev), net)) { rthp = &rth->u.dst.rt_next; continue; @@ -1233,7 +1271,7 @@ void ip_rt_redirect(__be32 old_gw, __be32 daddr, __be32 new_gw, rt->u.dst.neighbour = NULL; rt->u.dst.hh = NULL; rt->u.dst.xfrm = NULL; - rt->rt_genid = atomic_read(&rt_genid); + rt->rt_genid = rt_genid(net); rt->rt_flags |= RTCF_REDIRECTED; /* Gateway is different ... */ @@ -1297,7 +1335,8 @@ static struct dst_entry *ipv4_negative_advice(struct dst_entry *dst) } else if ((rt->rt_flags & RTCF_REDIRECTED) || rt->u.dst.expires) { unsigned hash = rt_hash(rt->fl.fl4_dst, rt->fl.fl4_src, - rt->fl.oif); + rt->fl.oif, + rt_genid(dev_net(dst->dev))); #if RT_CACHE_DEBUG >= 1 printk(KERN_DEBUG "ipv4_negative_advice: redirect to " NIPQUAD_FMT "/%02x dropped\n", @@ -1390,7 +1429,8 @@ static int ip_error(struct sk_buff *skb) break; case ENETUNREACH: code = ICMP_NET_UNREACH; - IP_INC_STATS_BH(IPSTATS_MIB_INNOROUTES); + IP_INC_STATS_BH(dev_net(rt->u.dst.dev), + IPSTATS_MIB_INNOROUTES); break; case EACCES: code = ICMP_PKT_FILTERED; @@ -1446,7 +1486,8 @@ unsigned short ip_rt_frag_needed(struct net *net, struct iphdr *iph, for (k = 0; k < 2; k++) { for (i = 0; i < 2; i++) { - unsigned hash = rt_hash(daddr, skeys[i], ikeys[k]); + unsigned hash = rt_hash(daddr, skeys[i], ikeys[k], + rt_genid(net)); rcu_read_lock(); for (rth = rcu_dereference(rt_hash_table[hash].chain); rth; @@ -1461,7 +1502,7 @@ unsigned short ip_rt_frag_needed(struct net *net, struct iphdr *iph, rth->fl.iif != 0 || dst_metric_locked(&rth->u.dst, RTAX_MTU) || !net_eq(dev_net(rth->u.dst.dev), net) || - rth->rt_genid != atomic_read(&rt_genid)) + !rt_is_expired(rth)) continue; if (new_mtu < 68 || new_mtu >= old_mtu) { @@ -1696,7 +1737,7 @@ static int ip_route_input_mc(struct sk_buff *skb, __be32 daddr, __be32 saddr, rth->fl.oif = 0; rth->rt_gateway = daddr; rth->rt_spec_dst= spec_dst; - rth->rt_genid = atomic_read(&rt_genid); + rth->rt_genid = rt_genid(dev_net(dev)); rth->rt_flags = RTCF_MULTICAST; rth->rt_type = RTN_MULTICAST; if (our) { @@ -1711,7 +1752,7 @@ static int ip_route_input_mc(struct sk_buff *skb, __be32 daddr, __be32 saddr, RT_CACHE_STAT_INC(in_slow_mc); in_dev_put(in_dev); - hash = rt_hash(daddr, saddr, dev->ifindex); + hash = rt_hash(daddr, saddr, dev->ifindex, rt_genid(dev_net(dev))); return rt_intern_hash(hash, rth, &skb->rtable); e_nobufs: @@ -1837,7 +1878,7 @@ static int __mkroute_input(struct sk_buff *skb, rth->u.dst.input = ip_forward; rth->u.dst.output = ip_output; - rth->rt_genid = atomic_read(&rt_genid); + rth->rt_genid = rt_genid(dev_net(rth->u.dst.dev)); rt_set_nexthop(rth, res, itag); @@ -1872,7 +1913,8 @@ static int ip_mkroute_input(struct sk_buff *skb, return err; /* put it into the cache */ - hash = rt_hash(daddr, saddr, fl->iif); + hash = rt_hash(daddr, saddr, fl->iif, + rt_genid(dev_net(rth->u.dst.dev))); return rt_intern_hash(hash, rth, &skb->rtable); } @@ -1998,7 +2040,7 @@ local_input: goto e_nobufs; rth->u.dst.output= ip_rt_bug; - rth->rt_genid = atomic_read(&rt_genid); + rth->rt_genid = rt_genid(net); atomic_set(&rth->u.dst.__refcnt, 1); rth->u.dst.flags= DST_HOST; @@ -2028,7 +2070,7 @@ local_input: rth->rt_flags &= ~RTCF_LOCAL; } rth->rt_type = res.type; - hash = rt_hash(daddr, saddr, fl.iif); + hash = rt_hash(daddr, saddr, fl.iif, rt_genid(net)); err = rt_intern_hash(hash, rth, &skb->rtable); goto done; @@ -2079,7 +2121,7 @@ int ip_route_input(struct sk_buff *skb, __be32 daddr, __be32 saddr, net = dev_net(dev); tos &= IPTOS_RT_MASK; - hash = rt_hash(daddr, saddr, iif); + hash = rt_hash(daddr, saddr, iif, rt_genid(net)); rcu_read_lock(); for (rth = rcu_dereference(rt_hash_table[hash].chain); rth; @@ -2091,7 +2133,7 @@ int ip_route_input(struct sk_buff *skb, __be32 daddr, __be32 saddr, (rth->fl.fl4_tos ^ tos)) == 0 && rth->fl.mark == skb->mark && net_eq(dev_net(rth->u.dst.dev), net) && - rth->rt_genid == atomic_read(&rt_genid)) { + !rt_is_expired(rth)) { dst_use(&rth->u.dst, jiffies); RT_CACHE_STAT_INC(in_hit); rcu_read_unlock(); @@ -2219,7 +2261,7 @@ static int __mkroute_output(struct rtable **result, rth->rt_spec_dst= fl->fl4_src; rth->u.dst.output=ip_output; - rth->rt_genid = atomic_read(&rt_genid); + rth->rt_genid = rt_genid(dev_net(dev_out)); RT_CACHE_STAT_INC(out_slow_tot); @@ -2268,7 +2310,8 @@ static int ip_mkroute_output(struct rtable **rp, int err = __mkroute_output(&rth, res, fl, oldflp, dev_out, flags); unsigned hash; if (err == 0) { - hash = rt_hash(oldflp->fl4_dst, oldflp->fl4_src, oldflp->oif); + hash = rt_hash(oldflp->fl4_dst, oldflp->fl4_src, oldflp->oif, + rt_genid(dev_net(dev_out))); err = rt_intern_hash(hash, rth, rp); } @@ -2480,7 +2523,7 @@ int __ip_route_output_key(struct net *net, struct rtable **rp, unsigned hash; struct rtable *rth; - hash = rt_hash(flp->fl4_dst, flp->fl4_src, flp->oif); + hash = rt_hash(flp->fl4_dst, flp->fl4_src, flp->oif, rt_genid(net)); rcu_read_lock_bh(); for (rth = rcu_dereference(rt_hash_table[hash].chain); rth; @@ -2493,7 +2536,7 @@ int __ip_route_output_key(struct net *net, struct rtable **rp, !((rth->fl.fl4_tos ^ flp->fl4_tos) & (IPTOS_RT_MASK | RTO_ONLINK)) && net_eq(dev_net(rth->u.dst.dev), net) && - rth->rt_genid == atomic_read(&rt_genid)) { + !rt_is_expired(rth)) { dst_use(&rth->u.dst, jiffies); RT_CACHE_STAT_INC(out_hit); rcu_read_unlock_bh(); @@ -2524,7 +2567,7 @@ static struct dst_ops ipv4_dst_blackhole_ops = { }; -static int ipv4_dst_blackhole(struct rtable **rp, struct flowi *flp) +static int ipv4_dst_blackhole(struct net *net, struct rtable **rp, struct flowi *flp) { struct rtable *ort = *rp; struct rtable *rt = (struct rtable *) @@ -2548,7 +2591,7 @@ static int ipv4_dst_blackhole(struct rtable **rp, struct flowi *flp) rt->idev = ort->idev; if (rt->idev) in_dev_hold(rt->idev); - rt->rt_genid = atomic_read(&rt_genid); + rt->rt_genid = rt_genid(net); rt->rt_flags = ort->rt_flags; rt->rt_type = ort->rt_type; rt->rt_dst = ort->rt_dst; @@ -2584,7 +2627,7 @@ int ip_route_output_flow(struct net *net, struct rtable **rp, struct flowi *flp, err = __xfrm_lookup((struct dst_entry **)rp, flp, sk, flags ? XFRM_LOOKUP_WAIT : 0); if (err == -EREMOTE) - err = ipv4_dst_blackhole(rp, flp); + err = ipv4_dst_blackhole(net, rp, flp); return err; } @@ -2803,7 +2846,7 @@ int ip_rt_dump(struct sk_buff *skb, struct netlink_callback *cb) rt = rcu_dereference(rt->u.dst.rt_next), idx++) { if (!net_eq(dev_net(rt->u.dst.dev), net) || idx < s_idx) continue; - if (rt->rt_genid != atomic_read(&rt_genid)) + if (rt_is_expired(rt)) continue; skb->dst = dst_clone(&rt->u.dst); if (rt_fill_info(skb, NETLINK_CB(cb->skb).pid, @@ -2827,19 +2870,25 @@ done: void ip_rt_multicast_event(struct in_device *in_dev) { - rt_cache_flush(0); + rt_cache_flush(dev_net(in_dev->dev), 0); } #ifdef CONFIG_SYSCTL -static int flush_delay; - -static int ipv4_sysctl_rtcache_flush(ctl_table *ctl, int write, +static int ipv4_sysctl_rtcache_flush(ctl_table *__ctl, int write, struct file *filp, void __user *buffer, size_t *lenp, loff_t *ppos) { if (write) { - proc_dointvec(ctl, write, filp, buffer, lenp, ppos); - rt_cache_flush(flush_delay); + int flush_delay; + ctl_table ctl; + struct net *net; + + memcpy(&ctl, __ctl, sizeof(ctl)); + ctl.data = &flush_delay; + proc_dointvec(&ctl, write, filp, buffer, lenp, ppos); + + net = (struct net *)__ctl->extra1; + rt_cache_flush(net, flush_delay); return 0; } @@ -2855,25 +2904,18 @@ static int ipv4_sysctl_rtcache_flush_strategy(ctl_table *table, size_t newlen) { int delay; + struct net *net; if (newlen != sizeof(int)) return -EINVAL; if (get_user(delay, (int __user *)newval)) return -EFAULT; - rt_cache_flush(delay); + net = (struct net *)table->extra1; + rt_cache_flush(net, delay); return 0; } ctl_table ipv4_route_table[] = { { - .ctl_name = NET_IPV4_ROUTE_FLUSH, - .procname = "flush", - .data = &flush_delay, - .maxlen = sizeof(int), - .mode = 0200, - .proc_handler = &ipv4_sysctl_rtcache_flush, - .strategy = &ipv4_sysctl_rtcache_flush_strategy, - }, - { .ctl_name = NET_IPV4_ROUTE_GC_THRESH, .procname = "gc_thresh", .data = &ipv4_dst_ops.gc_thresh, @@ -3011,8 +3053,97 @@ ctl_table ipv4_route_table[] = { }, { .ctl_name = 0 } }; + +static __net_initdata struct ctl_path ipv4_route_path[] = { + { .procname = "net", .ctl_name = CTL_NET, }, + { .procname = "ipv4", .ctl_name = NET_IPV4, }, + { .procname = "route", .ctl_name = NET_IPV4_ROUTE, }, + { }, +}; + + +static struct ctl_table ipv4_route_flush_table[] = { + { + .ctl_name = NET_IPV4_ROUTE_FLUSH, + .procname = "flush", + .maxlen = sizeof(int), + .mode = 0200, + .proc_handler = &ipv4_sysctl_rtcache_flush, + .strategy = &ipv4_sysctl_rtcache_flush_strategy, + }, + { .ctl_name = 0 }, +}; + +static __net_init int sysctl_route_net_init(struct net *net) +{ + struct ctl_table *tbl; + + tbl = ipv4_route_flush_table; + if (net != &init_net) { + tbl = kmemdup(tbl, sizeof(ipv4_route_flush_table), GFP_KERNEL); + if (tbl == NULL) + goto err_dup; + } + tbl[0].extra1 = net; + + net->ipv4.route_hdr = + register_net_sysctl_table(net, ipv4_route_path, tbl); + if (net->ipv4.route_hdr == NULL) + goto err_reg; + return 0; + +err_reg: + if (tbl != ipv4_route_flush_table) + kfree(tbl); +err_dup: + return -ENOMEM; +} + +static __net_exit void sysctl_route_net_exit(struct net *net) +{ + struct ctl_table *tbl; + + tbl = net->ipv4.route_hdr->ctl_table_arg; + unregister_net_sysctl_table(net->ipv4.route_hdr); + BUG_ON(tbl == ipv4_route_flush_table); + kfree(tbl); +} + +static __net_initdata struct pernet_operations sysctl_route_ops = { + .init = sysctl_route_net_init, + .exit = sysctl_route_net_exit, +}; #endif + +static __net_init int rt_secret_timer_init(struct net *net) +{ + atomic_set(&net->ipv4.rt_genid, + (int) ((num_physpages ^ (num_physpages>>8)) ^ + (jiffies ^ (jiffies >> 7)))); + + net->ipv4.rt_secret_timer.function = rt_secret_rebuild; + net->ipv4.rt_secret_timer.data = (unsigned long)net; + init_timer_deferrable(&net->ipv4.rt_secret_timer); + + net->ipv4.rt_secret_timer.expires = + jiffies + net_random() % ip_rt_secret_interval + + ip_rt_secret_interval; + add_timer(&net->ipv4.rt_secret_timer); + return 0; +} + +static __net_exit void rt_secret_timer_exit(struct net *net) +{ + del_timer_sync(&net->ipv4.rt_secret_timer); +} + +static __net_initdata struct pernet_operations rt_secret_timer_ops = { + .init = rt_secret_timer_init, + .exit = rt_secret_timer_exit, +}; + + #ifdef CONFIG_NET_CLS_ROUTE struct ip_rt_acct *ip_rt_acct __read_mostly; #endif /* CONFIG_NET_CLS_ROUTE */ @@ -3031,9 +3162,6 @@ int __init ip_rt_init(void) { int rc = 0; - atomic_set(&rt_genid, (int) ((num_physpages ^ (num_physpages>>8)) ^ - (jiffies ^ (jiffies >> 7)))); - #ifdef CONFIG_NET_CLS_ROUTE ip_rt_acct = __alloc_percpu(256 * sizeof(struct ip_rt_acct)); if (!ip_rt_acct) @@ -3065,19 +3193,14 @@ int __init ip_rt_init(void) devinet_init(); ip_fib_init(); - rt_secret_timer.function = rt_secret_rebuild; - rt_secret_timer.data = 0; - init_timer_deferrable(&rt_secret_timer); - /* All the timers, started at system startup tend to synchronize. Perturb it a bit. */ schedule_delayed_work(&expires_work, net_random() % ip_rt_gc_interval + ip_rt_gc_interval); - rt_secret_timer.expires = jiffies + net_random() % ip_rt_secret_interval + - ip_rt_secret_interval; - add_timer(&rt_secret_timer); + if (register_pernet_subsys(&rt_secret_timer_ops)) + printk(KERN_ERR "Unable to setup rt_secret_timer\n"); if (ip_rt_proc_init()) printk(KERN_ERR "Unable to create route proc files\n"); @@ -3087,6 +3210,9 @@ int __init ip_rt_init(void) #endif rtnl_register(PF_INET, RTM_GETROUTE, inet_rtm_getroute, NULL); +#ifdef CONFIG_SYSCTL + register_pernet_subsys(&sysctl_route_ops); +#endif return rc; } diff --git a/net/ipv4/syncookies.c b/net/ipv4/syncookies.c index d182a2a26291..51bc24d3b8a7 100644 --- a/net/ipv4/syncookies.c +++ b/net/ipv4/syncookies.c @@ -8,8 +8,6 @@ * 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. - * - * $Id: syncookies.c,v 1.18 2002/02/01 22:01:04 davem Exp $ */ #include <linux/tcp.h> @@ -175,7 +173,7 @@ __u32 cookie_v4_init_sequence(struct sock *sk, struct sk_buff *skb, __u16 *mssp) ; *mssp = msstab[mssind] + 1; - NET_INC_STATS_BH(LINUX_MIB_SYNCOOKIESSENT); + NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_SYNCOOKIESSENT); return secure_tcp_syn_cookie(iph->saddr, iph->daddr, th->source, th->dest, ntohl(th->seq), @@ -271,11 +269,11 @@ struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb, if (time_after(jiffies, tp->last_synq_overflow + TCP_TIMEOUT_INIT) || (mss = cookie_check(skb, cookie)) == 0) { - NET_INC_STATS_BH(LINUX_MIB_SYNCOOKIESFAILED); + NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_SYNCOOKIESFAILED); goto out; } - NET_INC_STATS_BH(LINUX_MIB_SYNCOOKIESRECV); + NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_SYNCOOKIESRECV); /* check for timestamp cookie support */ memset(&tcp_opt, 0, sizeof(tcp_opt)); diff --git a/net/ipv4/sysctl_net_ipv4.c b/net/ipv4/sysctl_net_ipv4.c index c437f804ee38..14ef202a2254 100644 --- a/net/ipv4/sysctl_net_ipv4.c +++ b/net/ipv4/sysctl_net_ipv4.c @@ -1,8 +1,6 @@ /* * sysctl_net_ipv4.c: sysctl interface to net IPV4 subsystem. * - * $Id: sysctl_net_ipv4.c,v 1.50 2001/10/20 00:00:11 davem Exp $ - * * Begun April 1, 1996, Mike Shaver. * Added /proc/sys/net/ipv4 directory entry (empty =) ). [MS] */ @@ -795,7 +793,8 @@ static struct ctl_table ipv4_net_table[] = { .data = &init_net.ipv4.sysctl_icmp_ratelimit, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec + .proc_handler = &proc_dointvec_ms_jiffies, + .strategy = &sysctl_ms_jiffies }, { .ctl_name = NET_IPV4_ICMP_RATEMASK, diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index 1d723de18686..0b491bf03db4 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -5,8 +5,6 @@ * * Implementation of the Transmission Control Protocol(TCP). * - * Version: $Id: tcp.c,v 1.216 2002/02/01 22:01:04 davem Exp $ - * * Authors: Ross Biro * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG> * Mark Evans, <evansmp@uhura.aston.ac.uk> @@ -279,8 +277,6 @@ int sysctl_tcp_fin_timeout __read_mostly = TCP_FIN_TIMEOUT; -DEFINE_SNMP_STAT(struct tcp_mib, tcp_statistics) __read_mostly; - atomic_t tcp_orphan_count = ATOMIC_INIT(0); EXPORT_SYMBOL_GPL(tcp_orphan_count); @@ -318,10 +314,10 @@ int tcp_memory_pressure __read_mostly; EXPORT_SYMBOL(tcp_memory_pressure); -void tcp_enter_memory_pressure(void) +void tcp_enter_memory_pressure(struct sock *sk) { if (!tcp_memory_pressure) { - NET_INC_STATS(LINUX_MIB_TCPMEMORYPRESSURES); + NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPMEMORYPRESSURES); tcp_memory_pressure = 1; } } @@ -346,8 +342,8 @@ unsigned int tcp_poll(struct file *file, struct socket *sock, poll_table *wait) return inet_csk_listen_poll(sk); /* Socket is not locked. We are protected from async events - by poll logic and correct handling of state changes - made by another threads is impossible in any case. + * by poll logic and correct handling of state changes + * made by other threads is impossible in any case. */ mask = 0; @@ -373,10 +369,10 @@ unsigned int tcp_poll(struct file *file, struct socket *sock, poll_table *wait) * in state CLOSE_WAIT. One solution is evident --- to set POLLHUP * if and only if shutdown has been made in both directions. * Actually, it is interesting to look how Solaris and DUX - * solve this dilemma. I would prefer, if PULLHUP were maskable, + * solve this dilemma. I would prefer, if POLLHUP were maskable, * then we could set it on SND_SHUTDOWN. BTW examples given * in Stevens' books assume exactly this behaviour, it explains - * why PULLHUP is incompatible with POLLOUT. --ANK + * why POLLHUP is incompatible with POLLOUT. --ANK * * NOTE. Check for TCP_CLOSE is added. The goal is to prevent * blocking on fresh not-connected or disconnected socket. --ANK @@ -651,7 +647,7 @@ struct sk_buff *sk_stream_alloc_skb(struct sock *sk, int size, gfp_t gfp) } __kfree_skb(skb); } else { - sk->sk_prot->enter_memory_pressure(); + sk->sk_prot->enter_memory_pressure(sk); sk_stream_moderate_sndbuf(sk); } return NULL; @@ -1155,7 +1151,7 @@ static void tcp_prequeue_process(struct sock *sk) struct sk_buff *skb; struct tcp_sock *tp = tcp_sk(sk); - NET_INC_STATS_USER(LINUX_MIB_TCPPREQUEUED); + NET_INC_STATS_USER(sock_net(sk), LINUX_MIB_TCPPREQUEUED); /* RX process wants to run with disabled BHs, though it is not * necessary */ @@ -1477,7 +1473,7 @@ int tcp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, /* __ Restore normal policy in scheduler __ */ if ((chunk = len - tp->ucopy.len) != 0) { - NET_ADD_STATS_USER(LINUX_MIB_TCPDIRECTCOPYFROMBACKLOG, chunk); + NET_ADD_STATS_USER(sock_net(sk), LINUX_MIB_TCPDIRECTCOPYFROMBACKLOG, chunk); len -= chunk; copied += chunk; } @@ -1488,7 +1484,7 @@ do_prequeue: tcp_prequeue_process(sk); if ((chunk = len - tp->ucopy.len) != 0) { - NET_ADD_STATS_USER(LINUX_MIB_TCPDIRECTCOPYFROMPREQUEUE, chunk); + NET_ADD_STATS_USER(sock_net(sk), LINUX_MIB_TCPDIRECTCOPYFROMPREQUEUE, chunk); len -= chunk; copied += chunk; } @@ -1603,7 +1599,7 @@ skip_copy: tcp_prequeue_process(sk); if (copied > 0 && (chunk = len - tp->ucopy.len) != 0) { - NET_ADD_STATS_USER(LINUX_MIB_TCPDIRECTCOPYFROMPREQUEUE, chunk); + NET_ADD_STATS_USER(sock_net(sk), LINUX_MIB_TCPDIRECTCOPYFROMPREQUEUE, chunk); len -= chunk; copied += chunk; } @@ -1670,12 +1666,12 @@ void tcp_set_state(struct sock *sk, int state) switch (state) { case TCP_ESTABLISHED: if (oldstate != TCP_ESTABLISHED) - TCP_INC_STATS(TCP_MIB_CURRESTAB); + TCP_INC_STATS(sock_net(sk), TCP_MIB_CURRESTAB); break; case TCP_CLOSE: if (oldstate == TCP_CLOSE_WAIT || oldstate == TCP_ESTABLISHED) - TCP_INC_STATS(TCP_MIB_ESTABRESETS); + TCP_INC_STATS(sock_net(sk), TCP_MIB_ESTABRESETS); sk->sk_prot->unhash(sk); if (inet_csk(sk)->icsk_bind_hash && @@ -1684,7 +1680,7 @@ void tcp_set_state(struct sock *sk, int state) /* fall through */ default: if (oldstate==TCP_ESTABLISHED) - TCP_DEC_STATS(TCP_MIB_CURRESTAB); + TCP_DEC_STATS(sock_net(sk), TCP_MIB_CURRESTAB); } /* Change state AFTER socket is unhashed to avoid closed @@ -1795,13 +1791,13 @@ void tcp_close(struct sock *sk, long timeout) */ if (data_was_unread) { /* Unread data was tossed, zap the connection. */ - NET_INC_STATS_USER(LINUX_MIB_TCPABORTONCLOSE); + NET_INC_STATS_USER(sock_net(sk), LINUX_MIB_TCPABORTONCLOSE); tcp_set_state(sk, TCP_CLOSE); tcp_send_active_reset(sk, GFP_KERNEL); } else if (sock_flag(sk, SOCK_LINGER) && !sk->sk_lingertime) { /* Check zero linger _after_ checking for unread data. */ sk->sk_prot->disconnect(sk, 0); - NET_INC_STATS_USER(LINUX_MIB_TCPABORTONDATA); + NET_INC_STATS_USER(sock_net(sk), LINUX_MIB_TCPABORTONDATA); } else if (tcp_close_state(sk)) { /* We FIN if the application ate all the data before * zapping the connection. @@ -1873,7 +1869,8 @@ adjudge_to_death: if (tp->linger2 < 0) { tcp_set_state(sk, TCP_CLOSE); tcp_send_active_reset(sk, GFP_ATOMIC); - NET_INC_STATS_BH(LINUX_MIB_TCPABORTONLINGER); + NET_INC_STATS_BH(sock_net(sk), + LINUX_MIB_TCPABORTONLINGER); } else { const int tmo = tcp_fin_time(sk); @@ -1895,7 +1892,8 @@ adjudge_to_death: "sockets\n"); tcp_set_state(sk, TCP_CLOSE); tcp_send_active_reset(sk, GFP_ATOMIC); - NET_INC_STATS_BH(LINUX_MIB_TCPABORTONMEMORY); + NET_INC_STATS_BH(sock_net(sk), + LINUX_MIB_TCPABORTONMEMORY); } } @@ -2590,12 +2588,69 @@ void __tcp_put_md5sig_pool(void) } EXPORT_SYMBOL(__tcp_put_md5sig_pool); + +int tcp_md5_hash_header(struct tcp_md5sig_pool *hp, + struct tcphdr *th) +{ + struct scatterlist sg; + int err; + + __sum16 old_checksum = th->check; + th->check = 0; + /* options aren't included in the hash */ + sg_init_one(&sg, th, sizeof(struct tcphdr)); + err = crypto_hash_update(&hp->md5_desc, &sg, sizeof(struct tcphdr)); + th->check = old_checksum; + return err; +} + +EXPORT_SYMBOL(tcp_md5_hash_header); + +int tcp_md5_hash_skb_data(struct tcp_md5sig_pool *hp, + struct sk_buff *skb, unsigned header_len) +{ + struct scatterlist sg; + const struct tcphdr *tp = tcp_hdr(skb); + struct hash_desc *desc = &hp->md5_desc; + unsigned i; + const unsigned head_data_len = skb_headlen(skb) > header_len ? + skb_headlen(skb) - header_len : 0; + const struct skb_shared_info *shi = skb_shinfo(skb); + + sg_init_table(&sg, 1); + + sg_set_buf(&sg, ((u8 *) tp) + header_len, head_data_len); + if (crypto_hash_update(desc, &sg, head_data_len)) + return 1; + + for (i = 0; i < shi->nr_frags; ++i) { + const struct skb_frag_struct *f = &shi->frags[i]; + sg_set_page(&sg, f->page, f->size, f->page_offset); + if (crypto_hash_update(desc, &sg, f->size)) + return 1; + } + + return 0; +} + +EXPORT_SYMBOL(tcp_md5_hash_skb_data); + +int tcp_md5_hash_key(struct tcp_md5sig_pool *hp, struct tcp_md5sig_key *key) +{ + struct scatterlist sg; + + sg_init_one(&sg, key->key, key->keylen); + return crypto_hash_update(&hp->md5_desc, &sg, key->keylen); +} + +EXPORT_SYMBOL(tcp_md5_hash_key); + #endif void tcp_done(struct sock *sk) { if(sk->sk_state == TCP_SYN_SENT || sk->sk_state == TCP_SYN_RECV) - TCP_INC_STATS_BH(TCP_MIB_ATTEMPTFAILS); + TCP_INC_STATS_BH(sock_net(sk), TCP_MIB_ATTEMPTFAILS); tcp_set_state(sk, TCP_CLOSE); tcp_clear_xmit_timers(sk); @@ -2732,4 +2787,3 @@ EXPORT_SYMBOL(tcp_splice_read); EXPORT_SYMBOL(tcp_sendpage); EXPORT_SYMBOL(tcp_setsockopt); EXPORT_SYMBOL(tcp_shutdown); -EXPORT_SYMBOL(tcp_statistics); diff --git a/net/ipv4/tcp_diag.c b/net/ipv4/tcp_diag.c index 2fbcc7d1b1a0..838d491dfda7 100644 --- a/net/ipv4/tcp_diag.c +++ b/net/ipv4/tcp_diag.c @@ -1,8 +1,6 @@ /* * tcp_diag.c Module for monitoring TCP transport protocols sockets. * - * Version: $Id: tcp_diag.c,v 1.3 2002/02/01 22:01:04 davem Exp $ - * * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru> * * This program is free software; you can redistribute it and/or diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index cad73b7dfef0..1f5e6049883e 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -5,8 +5,6 @@ * * Implementation of the Transmission Control Protocol(TCP). * - * Version: $Id: tcp_input.c,v 1.243 2002/02/01 22:01:04 davem Exp $ - * * Authors: Ross Biro * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG> * Mark Evans, <evansmp@uhura.aston.ac.uk> @@ -604,7 +602,7 @@ static u32 tcp_rto_min(struct sock *sk) u32 rto_min = TCP_RTO_MIN; if (dst && dst_metric_locked(dst, RTAX_RTO_MIN)) - rto_min = dst_metric(dst, RTAX_RTO_MIN); + rto_min = dst_metric_rtt(dst, RTAX_RTO_MIN); return rto_min; } @@ -731,6 +729,7 @@ void tcp_update_metrics(struct sock *sk) if (dst && (dst->flags & DST_HOST)) { const struct inet_connection_sock *icsk = inet_csk(sk); int m; + unsigned long rtt; if (icsk->icsk_backoff || !tp->srtt) { /* This session failed to estimate rtt. Why? @@ -742,7 +741,8 @@ void tcp_update_metrics(struct sock *sk) return; } - m = dst_metric(dst, RTAX_RTT) - tp->srtt; + rtt = dst_metric_rtt(dst, RTAX_RTT); + m = rtt - tp->srtt; /* If newly calculated rtt larger than stored one, * store new one. Otherwise, use EWMA. Remember, @@ -750,12 +750,13 @@ void tcp_update_metrics(struct sock *sk) */ if (!(dst_metric_locked(dst, RTAX_RTT))) { if (m <= 0) - dst->metrics[RTAX_RTT - 1] = tp->srtt; + set_dst_metric_rtt(dst, RTAX_RTT, tp->srtt); else - dst->metrics[RTAX_RTT - 1] -= (m >> 3); + set_dst_metric_rtt(dst, RTAX_RTT, rtt - (m >> 3)); } if (!(dst_metric_locked(dst, RTAX_RTTVAR))) { + unsigned long var; if (m < 0) m = -m; @@ -764,11 +765,13 @@ void tcp_update_metrics(struct sock *sk) if (m < tp->mdev) m = tp->mdev; - if (m >= dst_metric(dst, RTAX_RTTVAR)) - dst->metrics[RTAX_RTTVAR - 1] = m; + var = dst_metric_rtt(dst, RTAX_RTTVAR); + if (m >= var) + var = m; else - dst->metrics[RTAX_RTTVAR-1] -= - (dst_metric(dst, RTAX_RTTVAR) - m)>>2; + var -= (var - m) >> 2; + + set_dst_metric_rtt(dst, RTAX_RTTVAR, var); } if (tp->snd_ssthresh >= 0xFFFF) { @@ -899,7 +902,7 @@ static void tcp_init_metrics(struct sock *sk) if (dst_metric(dst, RTAX_RTT) == 0) goto reset; - if (!tp->srtt && dst_metric(dst, RTAX_RTT) < (TCP_TIMEOUT_INIT << 3)) + if (!tp->srtt && dst_metric_rtt(dst, RTAX_RTT) < (TCP_TIMEOUT_INIT << 3)) goto reset; /* Initial rtt is determined from SYN,SYN-ACK. @@ -916,12 +919,12 @@ static void tcp_init_metrics(struct sock *sk) * to low value, and then abruptly stops to do it and starts to delay * ACKs, wait for troubles. */ - if (dst_metric(dst, RTAX_RTT) > tp->srtt) { - tp->srtt = dst_metric(dst, RTAX_RTT); + if (dst_metric_rtt(dst, RTAX_RTT) > tp->srtt) { + tp->srtt = dst_metric_rtt(dst, RTAX_RTT); tp->rtt_seq = tp->snd_nxt; } - if (dst_metric(dst, RTAX_RTTVAR) > tp->mdev) { - tp->mdev = dst_metric(dst, RTAX_RTTVAR); + if (dst_metric_rtt(dst, RTAX_RTTVAR) > tp->mdev) { + tp->mdev = dst_metric_rtt(dst, RTAX_RTTVAR); tp->mdev_max = tp->rttvar = max(tp->mdev, tcp_rto_min(sk)); } tcp_set_rto(sk); @@ -949,17 +952,21 @@ static void tcp_update_reordering(struct sock *sk, const int metric, { struct tcp_sock *tp = tcp_sk(sk); if (metric > tp->reordering) { + int mib_idx; + tp->reordering = min(TCP_MAX_REORDERING, metric); /* This exciting event is worth to be remembered. 8) */ if (ts) - NET_INC_STATS_BH(LINUX_MIB_TCPTSREORDER); + mib_idx = LINUX_MIB_TCPTSREORDER; else if (tcp_is_reno(tp)) - NET_INC_STATS_BH(LINUX_MIB_TCPRENOREORDER); + mib_idx = LINUX_MIB_TCPRENOREORDER; else if (tcp_is_fack(tp)) - NET_INC_STATS_BH(LINUX_MIB_TCPFACKREORDER); + mib_idx = LINUX_MIB_TCPFACKREORDER; else - NET_INC_STATS_BH(LINUX_MIB_TCPSACKREORDER); + mib_idx = LINUX_MIB_TCPSACKREORDER; + + NET_INC_STATS_BH(sock_net(sk), mib_idx); #if FASTRETRANS_DEBUG > 1 printk(KERN_DEBUG "Disorder%d %d %u f%u s%u rr%d\n", tp->rx_opt.sack_ok, inet_csk(sk)->icsk_ca_state, @@ -1155,7 +1162,7 @@ static void tcp_mark_lost_retrans(struct sock *sk) tp->lost_out += tcp_skb_pcount(skb); TCP_SKB_CB(skb)->sacked |= TCPCB_LOST; } - NET_INC_STATS_BH(LINUX_MIB_TCPLOSTRETRANSMIT); + NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_TCPLOSTRETRANSMIT); } else { if (before(ack_seq, new_low_seq)) new_low_seq = ack_seq; @@ -1167,10 +1174,11 @@ static void tcp_mark_lost_retrans(struct sock *sk) tp->lost_retrans_low = new_low_seq; } -static int tcp_check_dsack(struct tcp_sock *tp, struct sk_buff *ack_skb, +static int tcp_check_dsack(struct sock *sk, struct sk_buff *ack_skb, struct tcp_sack_block_wire *sp, int num_sacks, u32 prior_snd_una) { + struct tcp_sock *tp = tcp_sk(sk); u32 start_seq_0 = get_unaligned_be32(&sp[0].start_seq); u32 end_seq_0 = get_unaligned_be32(&sp[0].end_seq); int dup_sack = 0; @@ -1178,7 +1186,7 @@ static int tcp_check_dsack(struct tcp_sock *tp, struct sk_buff *ack_skb, if (before(start_seq_0, TCP_SKB_CB(ack_skb)->ack_seq)) { dup_sack = 1; tcp_dsack_seen(tp); - NET_INC_STATS_BH(LINUX_MIB_TCPDSACKRECV); + NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_TCPDSACKRECV); } else if (num_sacks > 1) { u32 end_seq_1 = get_unaligned_be32(&sp[1].end_seq); u32 start_seq_1 = get_unaligned_be32(&sp[1].start_seq); @@ -1187,7 +1195,8 @@ static int tcp_check_dsack(struct tcp_sock *tp, struct sk_buff *ack_skb, !before(start_seq_0, start_seq_1)) { dup_sack = 1; tcp_dsack_seen(tp); - NET_INC_STATS_BH(LINUX_MIB_TCPDSACKOFORECV); + NET_INC_STATS_BH(sock_net(sk), + LINUX_MIB_TCPDSACKOFORECV); } } @@ -1414,10 +1423,10 @@ tcp_sacktag_write_queue(struct sock *sk, struct sk_buff *ack_skb, unsigned char *ptr = (skb_transport_header(ack_skb) + TCP_SKB_CB(ack_skb)->sacked); struct tcp_sack_block_wire *sp_wire = (struct tcp_sack_block_wire *)(ptr+2); - struct tcp_sack_block sp[4]; + struct tcp_sack_block sp[TCP_NUM_SACKS]; struct tcp_sack_block *cache; struct sk_buff *skb; - int num_sacks = (ptr[1] - TCPOLEN_SACK_BASE) >> 3; + int num_sacks = min(TCP_NUM_SACKS, (ptr[1] - TCPOLEN_SACK_BASE) >> 3); int used_sacks; int reord = tp->packets_out; int flag = 0; @@ -1432,7 +1441,7 @@ tcp_sacktag_write_queue(struct sock *sk, struct sk_buff *ack_skb, tcp_highest_sack_reset(sk); } - found_dup_sack = tcp_check_dsack(tp, ack_skb, sp_wire, + found_dup_sack = tcp_check_dsack(sk, ack_skb, sp_wire, num_sacks, prior_snd_una); if (found_dup_sack) flag |= FLAG_DSACKING_ACK; @@ -1458,18 +1467,22 @@ tcp_sacktag_write_queue(struct sock *sk, struct sk_buff *ack_skb, if (!tcp_is_sackblock_valid(tp, dup_sack, sp[used_sacks].start_seq, sp[used_sacks].end_seq)) { + int mib_idx; + if (dup_sack) { if (!tp->undo_marker) - NET_INC_STATS_BH(LINUX_MIB_TCPDSACKIGNOREDNOUNDO); + mib_idx = LINUX_MIB_TCPDSACKIGNOREDNOUNDO; else - NET_INC_STATS_BH(LINUX_MIB_TCPDSACKIGNOREDOLD); + mib_idx = LINUX_MIB_TCPDSACKIGNOREDOLD; } else { /* Don't count olds caused by ACK reordering */ if ((TCP_SKB_CB(ack_skb)->ack_seq != tp->snd_una) && !after(sp[used_sacks].end_seq, tp->snd_una)) continue; - NET_INC_STATS_BH(LINUX_MIB_TCPSACKDISCARD); + mib_idx = LINUX_MIB_TCPSACKDISCARD; } + + NET_INC_STATS_BH(sock_net(sk), mib_idx); if (i == 0) first_sack_index = -1; continue; @@ -1962,7 +1975,7 @@ static int tcp_check_sack_reneging(struct sock *sk, int flag) { if (flag & FLAG_SACK_RENEGING) { struct inet_connection_sock *icsk = inet_csk(sk); - NET_INC_STATS_BH(LINUX_MIB_TCPSACKRENEGING); + NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_TCPSACKRENEGING); tcp_enter_loss(sk, 1); icsk->icsk_retransmits++; @@ -2382,15 +2395,19 @@ static int tcp_try_undo_recovery(struct sock *sk) struct tcp_sock *tp = tcp_sk(sk); if (tcp_may_undo(tp)) { + int mib_idx; + /* Happy end! We did not retransmit anything * or our original transmission succeeded. */ DBGUNDO(sk, inet_csk(sk)->icsk_ca_state == TCP_CA_Loss ? "loss" : "retrans"); tcp_undo_cwr(sk, 1); if (inet_csk(sk)->icsk_ca_state == TCP_CA_Loss) - NET_INC_STATS_BH(LINUX_MIB_TCPLOSSUNDO); + mib_idx = LINUX_MIB_TCPLOSSUNDO; else - NET_INC_STATS_BH(LINUX_MIB_TCPFULLUNDO); + mib_idx = LINUX_MIB_TCPFULLUNDO; + + NET_INC_STATS_BH(sock_net(sk), mib_idx); tp->undo_marker = 0; } if (tp->snd_una == tp->high_seq && tcp_is_reno(tp)) { @@ -2413,7 +2430,7 @@ static void tcp_try_undo_dsack(struct sock *sk) DBGUNDO(sk, "D-SACK"); tcp_undo_cwr(sk, 1); tp->undo_marker = 0; - NET_INC_STATS_BH(LINUX_MIB_TCPDSACKUNDO); + NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_TCPDSACKUNDO); } } @@ -2436,7 +2453,7 @@ static int tcp_try_undo_partial(struct sock *sk, int acked) DBGUNDO(sk, "Hoe"); tcp_undo_cwr(sk, 0); - NET_INC_STATS_BH(LINUX_MIB_TCPPARTIALUNDO); + NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_TCPPARTIALUNDO); /* So... Do not make Hoe's retransmit yet. * If the first packet was delayed, the rest @@ -2465,7 +2482,7 @@ static int tcp_try_undo_loss(struct sock *sk) DBGUNDO(sk, "partial loss"); tp->lost_out = 0; tcp_undo_cwr(sk, 1); - NET_INC_STATS_BH(LINUX_MIB_TCPLOSSUNDO); + NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_TCPLOSSUNDO); inet_csk(sk)->icsk_retransmits = 0; tp->undo_marker = 0; if (tcp_is_sack(tp)) @@ -2562,7 +2579,7 @@ static void tcp_fastretrans_alert(struct sock *sk, int pkts_acked, int flag) int is_dupack = !(flag & (FLAG_SND_UNA_ADVANCED | FLAG_NOT_DUP)); int do_lost = is_dupack || ((flag & FLAG_DATA_SACKED) && (tcp_fackets_out(tp) > tp->reordering)); - int fast_rexmit = 0; + int fast_rexmit = 0, mib_idx; if (WARN_ON(!tp->packets_out && tp->sacked_out)) tp->sacked_out = 0; @@ -2584,7 +2601,7 @@ static void tcp_fastretrans_alert(struct sock *sk, int pkts_acked, int flag) icsk->icsk_ca_state != TCP_CA_Open && tp->fackets_out > tp->reordering) { tcp_mark_head_lost(sk, tp->fackets_out - tp->reordering); - NET_INC_STATS_BH(LINUX_MIB_TCPLOSS); + NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_TCPLOSS); } /* D. Check consistency of the current state. */ @@ -2685,9 +2702,11 @@ static void tcp_fastretrans_alert(struct sock *sk, int pkts_acked, int flag) /* Otherwise enter Recovery state */ if (tcp_is_reno(tp)) - NET_INC_STATS_BH(LINUX_MIB_TCPRENORECOVERY); + mib_idx = LINUX_MIB_TCPRENORECOVERY; else - NET_INC_STATS_BH(LINUX_MIB_TCPSACKRECOVERY); + mib_idx = LINUX_MIB_TCPSACKRECOVERY; + + NET_INC_STATS_BH(sock_net(sk), mib_idx); tp->high_seq = tp->snd_nxt; tp->prior_ssthresh = 0; @@ -3198,7 +3217,7 @@ static int tcp_process_frto(struct sock *sk, int flag) } tp->frto_counter = 0; tp->undo_marker = 0; - NET_INC_STATS_BH(LINUX_MIB_TCPSPURIOUSRTOS); + NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_TCPSPURIOUSRTOS); } return 0; } @@ -3251,12 +3270,12 @@ static int tcp_ack(struct sock *sk, struct sk_buff *skb, int flag) tcp_ca_event(sk, CA_EVENT_FAST_ACK); - NET_INC_STATS_BH(LINUX_MIB_TCPHPACKS); + NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_TCPHPACKS); } else { if (ack_seq != TCP_SKB_CB(skb)->end_seq) flag |= FLAG_DATA; else - NET_INC_STATS_BH(LINUX_MIB_TCPPUREACKS); + NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_TCPPUREACKS); flag |= tcp_ack_update_window(sk, skb, ack, ack_seq); @@ -3450,6 +3469,43 @@ static int tcp_fast_parse_options(struct sk_buff *skb, struct tcphdr *th, return 1; } +#ifdef CONFIG_TCP_MD5SIG +/* + * Parse MD5 Signature option + */ +u8 *tcp_parse_md5sig_option(struct tcphdr *th) +{ + int length = (th->doff << 2) - sizeof (*th); + u8 *ptr = (u8*)(th + 1); + + /* If the TCP option is too short, we can short cut */ + if (length < TCPOLEN_MD5SIG) + return NULL; + + while (length > 0) { + int opcode = *ptr++; + int opsize; + + switch(opcode) { + case TCPOPT_EOL: + return NULL; + case TCPOPT_NOP: + length--; + continue; + default: + opsize = *ptr++; + if (opsize < 2 || opsize > length) + return NULL; + if (opcode == TCPOPT_MD5SIG) + return ptr; + } + ptr += opsize - 2; + length -= opsize; + } + return NULL; +} +#endif + static inline void tcp_store_ts_recent(struct tcp_sock *tp) { tp->rx_opt.ts_recent = tp->rx_opt.rcv_tsval; @@ -3662,26 +3718,33 @@ static inline int tcp_sack_extend(struct tcp_sack_block *sp, u32 seq, return 0; } -static void tcp_dsack_set(struct tcp_sock *tp, u32 seq, u32 end_seq) +static void tcp_dsack_set(struct sock *sk, u32 seq, u32 end_seq) { + struct tcp_sock *tp = tcp_sk(sk); + if (tcp_is_sack(tp) && sysctl_tcp_dsack) { + int mib_idx; + if (before(seq, tp->rcv_nxt)) - NET_INC_STATS_BH(LINUX_MIB_TCPDSACKOLDSENT); + mib_idx = LINUX_MIB_TCPDSACKOLDSENT; else - NET_INC_STATS_BH(LINUX_MIB_TCPDSACKOFOSENT); + mib_idx = LINUX_MIB_TCPDSACKOFOSENT; + + NET_INC_STATS_BH(sock_net(sk), mib_idx); tp->rx_opt.dsack = 1; tp->duplicate_sack[0].start_seq = seq; tp->duplicate_sack[0].end_seq = end_seq; - tp->rx_opt.eff_sacks = min(tp->rx_opt.num_sacks + 1, - 4 - tp->rx_opt.tstamp_ok); + tp->rx_opt.eff_sacks = tp->rx_opt.num_sacks + 1; } } -static void tcp_dsack_extend(struct tcp_sock *tp, u32 seq, u32 end_seq) +static void tcp_dsack_extend(struct sock *sk, u32 seq, u32 end_seq) { + struct tcp_sock *tp = tcp_sk(sk); + if (!tp->rx_opt.dsack) - tcp_dsack_set(tp, seq, end_seq); + tcp_dsack_set(sk, seq, end_seq); else tcp_sack_extend(tp->duplicate_sack, seq, end_seq); } @@ -3692,7 +3755,7 @@ static void tcp_send_dupack(struct sock *sk, struct sk_buff *skb) if (TCP_SKB_CB(skb)->end_seq != TCP_SKB_CB(skb)->seq && before(TCP_SKB_CB(skb)->seq, tp->rcv_nxt)) { - NET_INC_STATS_BH(LINUX_MIB_DELAYEDACKLOST); + NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_DELAYEDACKLOST); tcp_enter_quickack_mode(sk); if (tcp_is_sack(tp) && sysctl_tcp_dsack) { @@ -3700,7 +3763,7 @@ static void tcp_send_dupack(struct sock *sk, struct sk_buff *skb) if (after(TCP_SKB_CB(skb)->end_seq, tp->rcv_nxt)) end_seq = tp->rcv_nxt; - tcp_dsack_set(tp, TCP_SKB_CB(skb)->seq, end_seq); + tcp_dsack_set(sk, TCP_SKB_CB(skb)->seq, end_seq); } } @@ -3727,9 +3790,8 @@ static void tcp_sack_maybe_coalesce(struct tcp_sock *tp) * Decrease num_sacks. */ tp->rx_opt.num_sacks--; - tp->rx_opt.eff_sacks = min(tp->rx_opt.num_sacks + - tp->rx_opt.dsack, - 4 - tp->rx_opt.tstamp_ok); + tp->rx_opt.eff_sacks = tp->rx_opt.num_sacks + + tp->rx_opt.dsack; for (i = this_sack; i < tp->rx_opt.num_sacks; i++) sp[i] = sp[i + 1]; continue; @@ -3779,7 +3841,7 @@ static void tcp_sack_new_ofo_skb(struct sock *sk, u32 seq, u32 end_seq) * * If the sack array is full, forget about the last one. */ - if (this_sack >= 4) { + if (this_sack >= TCP_NUM_SACKS) { this_sack--; tp->rx_opt.num_sacks--; sp--; @@ -3792,8 +3854,7 @@ new_sack: sp->start_seq = seq; sp->end_seq = end_seq; tp->rx_opt.num_sacks++; - tp->rx_opt.eff_sacks = min(tp->rx_opt.num_sacks + tp->rx_opt.dsack, - 4 - tp->rx_opt.tstamp_ok); + tp->rx_opt.eff_sacks = tp->rx_opt.num_sacks + tp->rx_opt.dsack; } /* RCV.NXT advances, some SACKs should be eaten. */ @@ -3830,9 +3891,8 @@ static void tcp_sack_remove(struct tcp_sock *tp) } if (num_sacks != tp->rx_opt.num_sacks) { tp->rx_opt.num_sacks = num_sacks; - tp->rx_opt.eff_sacks = min(tp->rx_opt.num_sacks + - tp->rx_opt.dsack, - 4 - tp->rx_opt.tstamp_ok); + tp->rx_opt.eff_sacks = tp->rx_opt.num_sacks + + tp->rx_opt.dsack; } } @@ -3853,7 +3913,7 @@ static void tcp_ofo_queue(struct sock *sk) __u32 dsack = dsack_high; if (before(TCP_SKB_CB(skb)->end_seq, dsack_high)) dsack_high = TCP_SKB_CB(skb)->end_seq; - tcp_dsack_extend(tp, TCP_SKB_CB(skb)->seq, dsack); + tcp_dsack_extend(sk, TCP_SKB_CB(skb)->seq, dsack); } if (!after(TCP_SKB_CB(skb)->end_seq, tp->rcv_nxt)) { @@ -3911,8 +3971,7 @@ static void tcp_data_queue(struct sock *sk, struct sk_buff *skb) if (tp->rx_opt.dsack) { tp->rx_opt.dsack = 0; - tp->rx_opt.eff_sacks = min_t(unsigned int, tp->rx_opt.num_sacks, - 4 - tp->rx_opt.tstamp_ok); + tp->rx_opt.eff_sacks = tp->rx_opt.num_sacks; } /* Queue data for delivery to the user. @@ -3981,8 +4040,8 @@ queue_and_out: if (!after(TCP_SKB_CB(skb)->end_seq, tp->rcv_nxt)) { /* A retransmit, 2nd most common case. Force an immediate ack. */ - NET_INC_STATS_BH(LINUX_MIB_DELAYEDACKLOST); - tcp_dsack_set(tp, TCP_SKB_CB(skb)->seq, TCP_SKB_CB(skb)->end_seq); + NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_DELAYEDACKLOST); + tcp_dsack_set(sk, TCP_SKB_CB(skb)->seq, TCP_SKB_CB(skb)->end_seq); out_of_window: tcp_enter_quickack_mode(sk); @@ -4004,7 +4063,7 @@ drop: tp->rcv_nxt, TCP_SKB_CB(skb)->seq, TCP_SKB_CB(skb)->end_seq); - tcp_dsack_set(tp, TCP_SKB_CB(skb)->seq, tp->rcv_nxt); + tcp_dsack_set(sk, TCP_SKB_CB(skb)->seq, tp->rcv_nxt); /* If window is closed, drop tail of packet. But after * remembering D-SACK for its head made in previous line. @@ -4069,12 +4128,12 @@ drop: if (!after(end_seq, TCP_SKB_CB(skb1)->end_seq)) { /* All the bits are present. Drop. */ __kfree_skb(skb); - tcp_dsack_set(tp, seq, end_seq); + tcp_dsack_set(sk, seq, end_seq); goto add_sack; } if (after(seq, TCP_SKB_CB(skb1)->seq)) { /* Partial overlap. */ - tcp_dsack_set(tp, seq, + tcp_dsack_set(sk, seq, TCP_SKB_CB(skb1)->end_seq); } else { skb1 = skb1->prev; @@ -4087,12 +4146,12 @@ drop: (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)) { - tcp_dsack_extend(tp, TCP_SKB_CB(skb1)->seq, + tcp_dsack_extend(sk, TCP_SKB_CB(skb1)->seq, end_seq); break; } __skb_unlink(skb1, &tp->out_of_order_queue); - tcp_dsack_extend(tp, TCP_SKB_CB(skb1)->seq, + tcp_dsack_extend(sk, TCP_SKB_CB(skb1)->seq, TCP_SKB_CB(skb1)->end_seq); __kfree_skb(skb1); } @@ -4123,7 +4182,7 @@ tcp_collapse(struct sock *sk, struct sk_buff_head *list, struct sk_buff *next = skb->next; __skb_unlink(skb, list); __kfree_skb(skb); - NET_INC_STATS_BH(LINUX_MIB_TCPRCVCOLLAPSED); + NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_TCPRCVCOLLAPSED); skb = next; continue; } @@ -4191,7 +4250,7 @@ tcp_collapse(struct sock *sk, struct sk_buff_head *list, struct sk_buff *next = skb->next; __skb_unlink(skb, list); __kfree_skb(skb); - NET_INC_STATS_BH(LINUX_MIB_TCPRCVCOLLAPSED); + NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_TCPRCVCOLLAPSED); skb = next; if (skb == tail || tcp_hdr(skb)->syn || @@ -4254,7 +4313,7 @@ static int tcp_prune_ofo_queue(struct sock *sk) int res = 0; if (!skb_queue_empty(&tp->out_of_order_queue)) { - NET_INC_STATS_BH(LINUX_MIB_OFOPRUNED); + NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_OFOPRUNED); __skb_queue_purge(&tp->out_of_order_queue); /* Reset SACK state. A conforming SACK implementation will @@ -4283,7 +4342,7 @@ static int tcp_prune_queue(struct sock *sk) SOCK_DEBUG(sk, "prune_queue: c=%x\n", tp->copied_seq); - NET_INC_STATS_BH(LINUX_MIB_PRUNECALLED); + NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_PRUNECALLED); if (atomic_read(&sk->sk_rmem_alloc) >= sk->sk_rcvbuf) tcp_clamp_window(sk); @@ -4312,7 +4371,7 @@ static int tcp_prune_queue(struct sock *sk) * drop receive data on the floor. It will get retransmitted * and hopefully then we'll have sufficient space. */ - NET_INC_STATS_BH(LINUX_MIB_RCVPRUNED); + NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_RCVPRUNED); /* Massive buffer overcommit. */ tp->pred_flags = 0; @@ -4742,7 +4801,7 @@ int tcp_rcv_established(struct sock *sk, struct sk_buff *skb, tcp_data_snd_check(sk); return 0; } else { /* Header too small */ - TCP_INC_STATS_BH(TCP_MIB_INERRS); + TCP_INC_STATS_BH(sock_net(sk), TCP_MIB_INERRS); goto discard; } } else { @@ -4779,7 +4838,7 @@ int tcp_rcv_established(struct sock *sk, struct sk_buff *skb, __skb_pull(skb, tcp_header_len); tp->rcv_nxt = TCP_SKB_CB(skb)->end_seq; - NET_INC_STATS_BH(LINUX_MIB_TCPHPHITSTOUSER); + NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_TCPHPHITSTOUSER); } if (copied_early) tcp_cleanup_rbuf(sk, skb->len); @@ -4802,7 +4861,7 @@ int tcp_rcv_established(struct sock *sk, struct sk_buff *skb, if ((int)skb->truesize > sk->sk_forward_alloc) goto step5; - NET_INC_STATS_BH(LINUX_MIB_TCPHPHITS); + NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_TCPHPHITS); /* Bulk data transfer: receiver */ __skb_pull(skb, tcp_header_len); @@ -4846,7 +4905,7 @@ slow_path: if (tcp_fast_parse_options(skb, th, tp) && tp->rx_opt.saw_tstamp && tcp_paws_discard(sk, skb)) { if (!th->rst) { - NET_INC_STATS_BH(LINUX_MIB_PAWSESTABREJECTED); + NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_PAWSESTABREJECTED); tcp_send_dupack(sk, skb); goto discard; } @@ -4881,8 +4940,8 @@ slow_path: tcp_replace_ts_recent(tp, TCP_SKB_CB(skb)->seq); if (th->syn && !before(TCP_SKB_CB(skb)->seq, tp->rcv_nxt)) { - TCP_INC_STATS_BH(TCP_MIB_INERRS); - NET_INC_STATS_BH(LINUX_MIB_TCPABORTONSYN); + TCP_INC_STATS_BH(sock_net(sk), TCP_MIB_INERRS); + NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_TCPABORTONSYN); tcp_reset(sk); return 1; } @@ -4904,7 +4963,7 @@ step5: return 0; csum_error: - TCP_INC_STATS_BH(TCP_MIB_INERRS); + TCP_INC_STATS_BH(sock_net(sk), TCP_MIB_INERRS); discard: __kfree_skb(skb); @@ -4938,7 +4997,7 @@ static int tcp_rcv_synsent_state_process(struct sock *sk, struct sk_buff *skb, if (tp->rx_opt.saw_tstamp && tp->rx_opt.rcv_tsecr && !between(tp->rx_opt.rcv_tsecr, tp->retrans_stamp, tcp_time_stamp)) { - NET_INC_STATS_BH(LINUX_MIB_PAWSACTIVEREJECTED); + NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_PAWSACTIVEREJECTED); goto reset_and_undo; } @@ -5222,7 +5281,7 @@ int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb, if (tcp_fast_parse_options(skb, th, tp) && tp->rx_opt.saw_tstamp && tcp_paws_discard(sk, skb)) { if (!th->rst) { - NET_INC_STATS_BH(LINUX_MIB_PAWSESTABREJECTED); + NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_PAWSESTABREJECTED); tcp_send_dupack(sk, skb); goto discard; } @@ -5251,7 +5310,7 @@ int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb, * Check for a SYN in window. */ if (th->syn && !before(TCP_SKB_CB(skb)->seq, tp->rcv_nxt)) { - NET_INC_STATS_BH(LINUX_MIB_TCPABORTONSYN); + NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_TCPABORTONSYN); tcp_reset(sk); return 1; } @@ -5333,7 +5392,7 @@ int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb, (TCP_SKB_CB(skb)->end_seq != TCP_SKB_CB(skb)->seq && after(TCP_SKB_CB(skb)->end_seq - th->fin, tp->rcv_nxt))) { tcp_done(sk); - NET_INC_STATS_BH(LINUX_MIB_TCPABORTONDATA); + NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_TCPABORTONDATA); return 1; } @@ -5393,7 +5452,7 @@ int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb, if (sk->sk_shutdown & RCV_SHUTDOWN) { if (TCP_SKB_CB(skb)->end_seq != TCP_SKB_CB(skb)->seq && after(TCP_SKB_CB(skb)->end_seq - th->fin, tp->rcv_nxt)) { - NET_INC_STATS_BH(LINUX_MIB_TCPABORTONDATA); + NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_TCPABORTONDATA); tcp_reset(sk); return 1; } @@ -5422,6 +5481,9 @@ EXPORT_SYMBOL(sysctl_tcp_ecn); EXPORT_SYMBOL(sysctl_tcp_reordering); EXPORT_SYMBOL(sysctl_tcp_adv_win_scale); EXPORT_SYMBOL(tcp_parse_options); +#ifdef CONFIG_TCP_MD5SIG +EXPORT_SYMBOL(tcp_parse_md5sig_option); +#endif EXPORT_SYMBOL(tcp_rcv_established); EXPORT_SYMBOL(tcp_rcv_state_process); EXPORT_SYMBOL(tcp_initialize_rcv_mss); diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index ffe869ac1bcf..a82df6307567 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -5,8 +5,6 @@ * * Implementation of the Transmission Control Protocol(TCP). * - * Version: $Id: tcp_ipv4.c,v 1.240 2002/02/01 22:01:04 davem Exp $ - * * IPv4 specific functions * * @@ -89,10 +87,14 @@ int sysctl_tcp_low_latency __read_mostly; #ifdef CONFIG_TCP_MD5SIG static struct tcp_md5sig_key *tcp_v4_md5_do_lookup(struct sock *sk, __be32 addr); -static int tcp_v4_do_calc_md5_hash(char *md5_hash, struct tcp_md5sig_key *key, - __be32 saddr, __be32 daddr, - struct tcphdr *th, int protocol, - unsigned int tcplen); +static int tcp_v4_md5_hash_hdr(char *md5_hash, struct tcp_md5sig_key *key, + __be32 daddr, __be32 saddr, struct tcphdr *th); +#else +static inline +struct tcp_md5sig_key *tcp_v4_md5_do_lookup(struct sock *sk, __be32 addr) +{ + return NULL; +} #endif struct inet_hashinfo __cacheline_aligned tcp_hashinfo = { @@ -172,7 +174,7 @@ int tcp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len) inet->sport, usin->sin_port, sk, 1); if (tmp < 0) { if (tmp == -ENETUNREACH) - IP_INC_STATS_BH(IPSTATS_MIB_OUTNOROUTES); + IP_INC_STATS_BH(sock_net(sk), IPSTATS_MIB_OUTNOROUTES); return tmp; } @@ -340,16 +342,17 @@ void tcp_v4_err(struct sk_buff *skb, u32 info) struct sock *sk; __u32 seq; int err; + struct net *net = dev_net(skb->dev); if (skb->len < (iph->ihl << 2) + 8) { - ICMP_INC_STATS_BH(ICMP_MIB_INERRORS); + ICMP_INC_STATS_BH(net, ICMP_MIB_INERRORS); return; } - sk = inet_lookup(dev_net(skb->dev), &tcp_hashinfo, iph->daddr, th->dest, + sk = inet_lookup(net, &tcp_hashinfo, iph->daddr, th->dest, iph->saddr, th->source, inet_iif(skb)); if (!sk) { - ICMP_INC_STATS_BH(ICMP_MIB_INERRORS); + ICMP_INC_STATS_BH(net, ICMP_MIB_INERRORS); return; } if (sk->sk_state == TCP_TIME_WAIT) { @@ -362,7 +365,7 @@ void tcp_v4_err(struct sk_buff *skb, u32 info) * servers this needs to be solved differently. */ if (sock_owned_by_user(sk)) - NET_INC_STATS_BH(LINUX_MIB_LOCKDROPPEDICMPS); + NET_INC_STATS_BH(net, LINUX_MIB_LOCKDROPPEDICMPS); if (sk->sk_state == TCP_CLOSE) goto out; @@ -371,7 +374,7 @@ void tcp_v4_err(struct sk_buff *skb, u32 info) seq = ntohl(th->seq); if (sk->sk_state != TCP_LISTEN && !between(seq, tp->snd_una, tp->snd_nxt)) { - NET_INC_STATS_BH(LINUX_MIB_OUTOFWINDOWICMPS); + NET_INC_STATS_BH(net, LINUX_MIB_OUTOFWINDOWICMPS); goto out; } @@ -418,7 +421,7 @@ void tcp_v4_err(struct sk_buff *skb, u32 info) BUG_TRAP(!req->sk); if (seq != tcp_rsk(req)->snt_isn) { - NET_INC_STATS_BH(LINUX_MIB_OUTOFWINDOWICMPS); + NET_INC_STATS_BH(net, LINUX_MIB_OUTOFWINDOWICMPS); goto out; } @@ -540,6 +543,7 @@ static void tcp_v4_send_reset(struct sock *sk, struct sk_buff *skb) #ifdef CONFIG_TCP_MD5SIG struct tcp_md5sig_key *key; #endif + struct net *net; /* Never send a reset in response to a reset. */ if (th->rst) @@ -578,12 +582,9 @@ static void tcp_v4_send_reset(struct sock *sk, struct sk_buff *skb) arg.iov[0].iov_len += TCPOLEN_MD5SIG_ALIGNED; rep.th.doff = arg.iov[0].iov_len / 4; - tcp_v4_do_calc_md5_hash((__u8 *)&rep.opt[1], - key, - ip_hdr(skb)->daddr, - ip_hdr(skb)->saddr, - &rep.th, IPPROTO_TCP, - arg.iov[0].iov_len); + tcp_v4_md5_hash_hdr((__u8 *) &rep.opt[1], + key, ip_hdr(skb)->daddr, + ip_hdr(skb)->saddr, &rep.th); } #endif arg.csum = csum_tcpudp_nofold(ip_hdr(skb)->daddr, @@ -591,20 +592,21 @@ static void tcp_v4_send_reset(struct sock *sk, struct sk_buff *skb) sizeof(struct tcphdr), IPPROTO_TCP, 0); arg.csumoffset = offsetof(struct tcphdr, check) / 2; - ip_send_reply(dev_net(skb->dst->dev)->ipv4.tcp_sock, skb, + net = dev_net(skb->dst->dev); + ip_send_reply(net->ipv4.tcp_sock, skb, &arg, arg.iov[0].iov_len); - TCP_INC_STATS_BH(TCP_MIB_OUTSEGS); - TCP_INC_STATS_BH(TCP_MIB_OUTRSTS); + TCP_INC_STATS_BH(net, TCP_MIB_OUTSEGS); + TCP_INC_STATS_BH(net, TCP_MIB_OUTRSTS); } /* The code following below sending ACKs in SYN-RECV and TIME-WAIT states outside socket context is ugly, certainly. What can I do? */ -static void tcp_v4_send_ack(struct tcp_timewait_sock *twsk, - struct sk_buff *skb, u32 seq, u32 ack, - u32 win, u32 ts) +static void tcp_v4_send_ack(struct sk_buff *skb, u32 seq, u32 ack, + u32 win, u32 ts, int oif, + struct tcp_md5sig_key *key) { struct tcphdr *th = tcp_hdr(skb); struct { @@ -616,10 +618,7 @@ static void tcp_v4_send_ack(struct tcp_timewait_sock *twsk, ]; } rep; struct ip_reply_arg arg; -#ifdef CONFIG_TCP_MD5SIG - struct tcp_md5sig_key *key; - struct tcp_md5sig_key tw_key; -#endif + struct net *net = dev_net(skb->dev); memset(&rep.th, 0, sizeof(struct tcphdr)); memset(&arg, 0, sizeof(arg)); @@ -645,23 +644,6 @@ static void tcp_v4_send_ack(struct tcp_timewait_sock *twsk, rep.th.window = htons(win); #ifdef CONFIG_TCP_MD5SIG - /* - * The SKB holds an imcoming packet, but may not have a valid ->sk - * pointer. This is especially the case when we're dealing with a - * TIME_WAIT ack, because the sk structure is long gone, and only - * the tcp_timewait_sock remains. So the md5 key is stashed in that - * structure, and we use it in preference. I believe that (twsk || - * skb->sk) holds true, but we program defensively. - */ - if (!twsk && skb->sk) { - key = tcp_v4_md5_do_lookup(skb->sk, ip_hdr(skb)->daddr); - } else if (twsk && twsk->tw_md5_keylen) { - tw_key.key = twsk->tw_md5_key; - tw_key.keylen = twsk->tw_md5_keylen; - key = &tw_key; - } else - key = NULL; - if (key) { int offset = (ts) ? 3 : 0; @@ -672,25 +654,22 @@ static void tcp_v4_send_ack(struct tcp_timewait_sock *twsk, arg.iov[0].iov_len += TCPOLEN_MD5SIG_ALIGNED; rep.th.doff = arg.iov[0].iov_len/4; - tcp_v4_do_calc_md5_hash((__u8 *)&rep.opt[offset], - key, - ip_hdr(skb)->daddr, - ip_hdr(skb)->saddr, - &rep.th, IPPROTO_TCP, - arg.iov[0].iov_len); + tcp_v4_md5_hash_hdr((__u8 *) &rep.opt[offset], + key, ip_hdr(skb)->daddr, + ip_hdr(skb)->saddr, &rep.th); } #endif arg.csum = csum_tcpudp_nofold(ip_hdr(skb)->daddr, ip_hdr(skb)->saddr, /* XXX */ arg.iov[0].iov_len, IPPROTO_TCP, 0); arg.csumoffset = offsetof(struct tcphdr, check) / 2; - if (twsk) - arg.bound_dev_if = twsk->tw_sk.tw_bound_dev_if; + if (oif) + arg.bound_dev_if = oif; - ip_send_reply(dev_net(skb->dev)->ipv4.tcp_sock, skb, + ip_send_reply(net->ipv4.tcp_sock, skb, &arg, arg.iov[0].iov_len); - TCP_INC_STATS_BH(TCP_MIB_OUTSEGS); + TCP_INC_STATS_BH(net, TCP_MIB_OUTSEGS); } static void tcp_v4_timewait_ack(struct sock *sk, struct sk_buff *skb) @@ -698,9 +677,12 @@ static void tcp_v4_timewait_ack(struct sock *sk, struct sk_buff *skb) struct inet_timewait_sock *tw = inet_twsk(sk); struct tcp_timewait_sock *tcptw = tcp_twsk(sk); - tcp_v4_send_ack(tcptw, skb, tcptw->tw_snd_nxt, tcptw->tw_rcv_nxt, + tcp_v4_send_ack(skb, tcptw->tw_snd_nxt, tcptw->tw_rcv_nxt, tcptw->tw_rcv_wnd >> tw->tw_rcv_wscale, - tcptw->tw_ts_recent); + tcptw->tw_ts_recent, + tw->tw_bound_dev_if, + tcp_twsk_md5_key(tcptw) + ); inet_twsk_put(tw); } @@ -708,9 +690,11 @@ static void tcp_v4_timewait_ack(struct sock *sk, struct sk_buff *skb) static void tcp_v4_reqsk_send_ack(struct sk_buff *skb, struct request_sock *req) { - tcp_v4_send_ack(NULL, skb, tcp_rsk(req)->snt_isn + 1, + tcp_v4_send_ack(skb, tcp_rsk(req)->snt_isn + 1, tcp_rsk(req)->rcv_isn + 1, req->rcv_wnd, - req->ts_recent); + req->ts_recent, + 0, + tcp_v4_md5_do_lookup(skb->sk, ip_hdr(skb)->daddr)); } /* @@ -1000,32 +984,13 @@ static int tcp_v4_parse_md5_keys(struct sock *sk, char __user *optval, newkey, cmd.tcpm_keylen); } -static int tcp_v4_do_calc_md5_hash(char *md5_hash, struct tcp_md5sig_key *key, - __be32 saddr, __be32 daddr, - struct tcphdr *th, int protocol, - unsigned int tcplen) +static int tcp_v4_md5_hash_pseudoheader(struct tcp_md5sig_pool *hp, + __be32 daddr, __be32 saddr, int nbytes) { - struct scatterlist sg[4]; - __u16 data_len; - int block = 0; - __sum16 old_checksum; - struct tcp_md5sig_pool *hp; struct tcp4_pseudohdr *bp; - struct hash_desc *desc; - int err; - unsigned int nbytes = 0; - - /* - * Okay, so RFC2385 is turned on for this connection, - * so we need to generate the MD5 hash for the packet now. - */ - - hp = tcp_get_md5sig_pool(); - if (!hp) - goto clear_hash_noput; + struct scatterlist sg; bp = &hp->md5_blk.ip4; - desc = &hp->md5_desc; /* * 1. the TCP pseudo-header (in the order: source IP address, @@ -1035,86 +1000,96 @@ static int tcp_v4_do_calc_md5_hash(char *md5_hash, struct tcp_md5sig_key *key, bp->saddr = saddr; bp->daddr = daddr; bp->pad = 0; - bp->protocol = protocol; - bp->len = htons(tcplen); - - sg_init_table(sg, 4); - - sg_set_buf(&sg[block++], bp, sizeof(*bp)); - nbytes += sizeof(*bp); - - /* 2. the TCP header, excluding options, and assuming a - * checksum of zero/ - */ - old_checksum = th->check; - th->check = 0; - sg_set_buf(&sg[block++], th, sizeof(struct tcphdr)); - nbytes += sizeof(struct tcphdr); + bp->protocol = IPPROTO_TCP; + bp->len = cpu_to_be16(nbytes); - /* 3. the TCP segment data (if any) */ - data_len = tcplen - (th->doff << 2); - if (data_len > 0) { - unsigned char *data = (unsigned char *)th + (th->doff << 2); - sg_set_buf(&sg[block++], data, data_len); - nbytes += data_len; - } + sg_init_one(&sg, bp, sizeof(*bp)); + return crypto_hash_update(&hp->md5_desc, &sg, sizeof(*bp)); +} - /* 4. an independently-specified key or password, known to both - * TCPs and presumably connection-specific - */ - sg_set_buf(&sg[block++], key->key, key->keylen); - nbytes += key->keylen; +static int tcp_v4_md5_hash_hdr(char *md5_hash, struct tcp_md5sig_key *key, + __be32 daddr, __be32 saddr, struct tcphdr *th) +{ + struct tcp_md5sig_pool *hp; + struct hash_desc *desc; - sg_mark_end(&sg[block - 1]); + hp = tcp_get_md5sig_pool(); + if (!hp) + goto clear_hash_noput; + desc = &hp->md5_desc; - /* Now store the Hash into the packet */ - err = crypto_hash_init(desc); - if (err) + if (crypto_hash_init(desc)) goto clear_hash; - err = crypto_hash_update(desc, sg, nbytes); - if (err) + if (tcp_v4_md5_hash_pseudoheader(hp, daddr, saddr, th->doff << 2)) goto clear_hash; - err = crypto_hash_final(desc, md5_hash); - if (err) + if (tcp_md5_hash_header(hp, th)) + goto clear_hash; + if (tcp_md5_hash_key(hp, key)) + goto clear_hash; + if (crypto_hash_final(desc, md5_hash)) goto clear_hash; - /* Reset header, and free up the crypto */ tcp_put_md5sig_pool(); - th->check = old_checksum; - -out: return 0; + clear_hash: tcp_put_md5sig_pool(); clear_hash_noput: memset(md5_hash, 0, 16); - goto out; + return 1; } -int tcp_v4_calc_md5_hash(char *md5_hash, struct tcp_md5sig_key *key, - struct sock *sk, - struct dst_entry *dst, - struct request_sock *req, - struct tcphdr *th, int protocol, - unsigned int tcplen) +int tcp_v4_md5_hash_skb(char *md5_hash, struct tcp_md5sig_key *key, + struct sock *sk, struct request_sock *req, + struct sk_buff *skb) { + struct tcp_md5sig_pool *hp; + struct hash_desc *desc; + struct tcphdr *th = tcp_hdr(skb); __be32 saddr, daddr; if (sk) { saddr = inet_sk(sk)->saddr; daddr = inet_sk(sk)->daddr; + } else if (req) { + saddr = inet_rsk(req)->loc_addr; + daddr = inet_rsk(req)->rmt_addr; } else { - struct rtable *rt = (struct rtable *)dst; - BUG_ON(!rt); - saddr = rt->rt_src; - daddr = rt->rt_dst; + const struct iphdr *iph = ip_hdr(skb); + saddr = iph->saddr; + daddr = iph->daddr; } - return tcp_v4_do_calc_md5_hash(md5_hash, key, - saddr, daddr, - th, protocol, tcplen); + + hp = tcp_get_md5sig_pool(); + if (!hp) + goto clear_hash_noput; + desc = &hp->md5_desc; + + if (crypto_hash_init(desc)) + goto clear_hash; + + if (tcp_v4_md5_hash_pseudoheader(hp, daddr, saddr, skb->len)) + goto clear_hash; + if (tcp_md5_hash_header(hp, th)) + goto clear_hash; + if (tcp_md5_hash_skb_data(hp, skb, th->doff << 2)) + goto clear_hash; + if (tcp_md5_hash_key(hp, key)) + goto clear_hash; + if (crypto_hash_final(desc, md5_hash)) + goto clear_hash; + + tcp_put_md5sig_pool(); + return 0; + +clear_hash: + tcp_put_md5sig_pool(); +clear_hash_noput: + memset(md5_hash, 0, 16); + return 1; } -EXPORT_SYMBOL(tcp_v4_calc_md5_hash); +EXPORT_SYMBOL(tcp_v4_md5_hash_skb); static int tcp_v4_inbound_md5_hash(struct sock *sk, struct sk_buff *skb) { @@ -1130,52 +1105,12 @@ static int tcp_v4_inbound_md5_hash(struct sock *sk, struct sk_buff *skb) struct tcp_md5sig_key *hash_expected; const struct iphdr *iph = ip_hdr(skb); struct tcphdr *th = tcp_hdr(skb); - int length = (th->doff << 2) - sizeof(struct tcphdr); int genhash; - unsigned char *ptr; unsigned char newhash[16]; hash_expected = tcp_v4_md5_do_lookup(sk, iph->saddr); + hash_location = tcp_parse_md5sig_option(th); - /* - * If the TCP option length is less than the TCP_MD5SIG - * option length, then we can shortcut - */ - if (length < TCPOLEN_MD5SIG) { - if (hash_expected) - return 1; - else - return 0; - } - - /* Okay, we can't shortcut - we have to grub through the options */ - ptr = (unsigned char *)(th + 1); - while (length > 0) { - int opcode = *ptr++; - int opsize; - - switch (opcode) { - case TCPOPT_EOL: - goto done_opts; - case TCPOPT_NOP: - length--; - continue; - default: - opsize = *ptr++; - if (opsize < 2) - goto done_opts; - if (opsize > length) - goto done_opts; - - if (opcode == TCPOPT_MD5SIG) { - hash_location = ptr; - goto done_opts; - } - } - ptr += opsize-2; - length -= opsize; - } -done_opts: /* We've parsed the options - do we have a hash? */ if (!hash_expected && !hash_location) return 0; @@ -1199,11 +1134,9 @@ done_opts: /* Okay, so this is hash_expected and hash_location - * so we need to calculate the checksum. */ - genhash = tcp_v4_do_calc_md5_hash(newhash, - hash_expected, - iph->saddr, iph->daddr, - th, sk->sk_protocol, - skb->len); + genhash = tcp_v4_md5_hash_skb(newhash, + hash_expected, + NULL, NULL, skb); if (genhash || memcmp(hash_location, newhash, 16) != 0) { if (net_ratelimit()) { @@ -1347,7 +1280,7 @@ int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb) if (get_seconds() < peer->tcp_ts_stamp + TCP_PAWS_MSL && (s32)(peer->tcp_ts - req->ts_recent) > TCP_PAWS_WINDOW) { - NET_INC_STATS_BH(LINUX_MIB_PAWSPASSIVEREJECTED); + NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_PAWSPASSIVEREJECTED); goto drop_and_release; } } @@ -1452,6 +1385,7 @@ struct sock *tcp_v4_syn_recv_sock(struct sock *sk, struct sk_buff *skb, if (newkey != NULL) tcp_v4_md5_do_add(newsk, inet_sk(sk)->daddr, newkey, key->keylen); + newsk->sk_route_caps &= ~NETIF_F_GSO_MASK; } #endif @@ -1461,9 +1395,9 @@ struct sock *tcp_v4_syn_recv_sock(struct sock *sk, struct sk_buff *skb, return newsk; exit_overflow: - NET_INC_STATS_BH(LINUX_MIB_LISTENOVERFLOWS); + NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_LISTENOVERFLOWS); exit: - NET_INC_STATS_BH(LINUX_MIB_LISTENDROPS); + NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_LISTENDROPS); dst_release(dst); return NULL; } @@ -1590,7 +1524,7 @@ discard: return 0; csum_err: - TCP_INC_STATS_BH(TCP_MIB_INERRS); + TCP_INC_STATS_BH(sock_net(sk), TCP_MIB_INERRS); goto discard; } @@ -1604,12 +1538,13 @@ int tcp_v4_rcv(struct sk_buff *skb) struct tcphdr *th; struct sock *sk; int ret; + struct net *net = dev_net(skb->dev); if (skb->pkt_type != PACKET_HOST) goto discard_it; /* Count it even if it's bad */ - TCP_INC_STATS_BH(TCP_MIB_INSEGS); + TCP_INC_STATS_BH(net, TCP_MIB_INSEGS); if (!pskb_may_pull(skb, sizeof(struct tcphdr))) goto discard_it; @@ -1638,7 +1573,7 @@ int tcp_v4_rcv(struct sk_buff *skb) TCP_SKB_CB(skb)->flags = iph->tos; TCP_SKB_CB(skb)->sacked = 0; - sk = __inet_lookup(dev_net(skb->dev), &tcp_hashinfo, iph->saddr, + sk = __inet_lookup(net, &tcp_hashinfo, iph->saddr, th->source, iph->daddr, th->dest, inet_iif(skb)); if (!sk) goto no_tcp_socket; @@ -1685,7 +1620,7 @@ no_tcp_socket: if (skb->len < (th->doff << 2) || tcp_checksum_complete(skb)) { bad_packet: - TCP_INC_STATS_BH(TCP_MIB_INERRS); + TCP_INC_STATS_BH(net, TCP_MIB_INERRS); } else { tcp_v4_send_reset(NULL, skb); } @@ -1706,7 +1641,7 @@ do_time_wait: } if (skb->len < (th->doff << 2) || tcp_checksum_complete(skb)) { - TCP_INC_STATS_BH(TCP_MIB_INERRS); + TCP_INC_STATS_BH(net, TCP_MIB_INERRS); inet_twsk_put(inet_twsk(sk)); goto discard_it; } @@ -1814,7 +1749,7 @@ struct inet_connection_sock_af_ops ipv4_specific = { #ifdef CONFIG_TCP_MD5SIG static struct tcp_sock_af_ops tcp_sock_ipv4_specific = { .md5_lookup = tcp_v4_md5_lookup, - .calc_md5_hash = tcp_v4_calc_md5_hash, + .calc_md5_hash = tcp_v4_md5_hash_skb, .md5_add = tcp_v4_md5_add_func, .md5_parse = tcp_v4_parse_md5_keys, }; @@ -1871,7 +1806,7 @@ static int tcp_v4_init_sock(struct sock *sk) return 0; } -int tcp_v4_destroy_sock(struct sock *sk) +void tcp_v4_destroy_sock(struct sock *sk) { struct tcp_sock *tp = tcp_sk(sk); @@ -1915,8 +1850,6 @@ int tcp_v4_destroy_sock(struct sock *sk) } atomic_dec(&tcp_sockets_allocated); - - return 0; } EXPORT_SYMBOL(tcp_v4_destroy_sock); @@ -1959,8 +1892,7 @@ static void *listening_get_next(struct seq_file *seq, void *cur) req = req->dl_next; while (1) { while (req) { - if (req->rsk_ops->family == st->family && - net_eq(sock_net(req->sk), net)) { + if (req->rsk_ops->family == st->family) { cur = req; goto out; } diff --git a/net/ipv4/tcp_minisocks.c b/net/ipv4/tcp_minisocks.c index 8245247a6ceb..204c42162660 100644 --- a/net/ipv4/tcp_minisocks.c +++ b/net/ipv4/tcp_minisocks.c @@ -5,8 +5,6 @@ * * Implementation of the Transmission Control Protocol(TCP). * - * Version: $Id: tcp_minisocks.c,v 1.15 2002/02/01 22:01:04 davem Exp $ - * * Authors: Ross Biro * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG> * Mark Evans, <evansmp@uhura.aston.ac.uk> @@ -246,7 +244,7 @@ kill: } if (paws_reject) - NET_INC_STATS_BH(LINUX_MIB_PAWSESTABREJECTED); + NET_INC_STATS_BH(twsk_net(tw), LINUX_MIB_PAWSESTABREJECTED); if (!th->rst) { /* In this case we must reset the TIMEWAIT timer. @@ -482,7 +480,7 @@ struct sock *tcp_create_openreq_child(struct sock *sk, struct request_sock *req, newtp->rx_opt.mss_clamp = req->mss; TCP_ECN_openreq_child(newtp, req); - TCP_INC_STATS_BH(TCP_MIB_PASSIVEOPENS); + TCP_INC_STATS_BH(sock_net(sk), TCP_MIB_PASSIVEOPENS); } return newsk; } @@ -613,7 +611,7 @@ struct sock *tcp_check_req(struct sock *sk,struct sk_buff *skb, if (!(flg & TCP_FLAG_RST)) req->rsk_ops->send_ack(skb, req); if (paws_reject) - NET_INC_STATS_BH(LINUX_MIB_PAWSESTABREJECTED); + NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_PAWSESTABREJECTED); return NULL; } @@ -632,7 +630,7 @@ struct sock *tcp_check_req(struct sock *sk,struct sk_buff *skb, * "fourth, check the SYN bit" */ if (flg & (TCP_FLAG_RST|TCP_FLAG_SYN)) { - TCP_INC_STATS_BH(TCP_MIB_ATTEMPTFAILS); + TCP_INC_STATS_BH(sock_net(sk), TCP_MIB_ATTEMPTFAILS); goto embryonic_reset; } @@ -697,7 +695,7 @@ struct sock *tcp_check_req(struct sock *sk,struct sk_buff *skb, } embryonic_reset: - NET_INC_STATS_BH(LINUX_MIB_EMBRYONICRSTS); + NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_EMBRYONICRSTS); if (!(flg & TCP_FLAG_RST)) req->rsk_ops->send_reset(sk, skb); diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index ad993ecb4810..1fa683c0ba9b 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c @@ -5,8 +5,6 @@ * * Implementation of the Transmission Control Protocol(TCP). * - * Version: $Id: tcp_output.c,v 1.146 2002/02/01 22:01:04 davem Exp $ - * * Authors: Ross Biro * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG> * Mark Evans, <evansmp@uhura.aston.ac.uk> @@ -347,28 +345,82 @@ static void tcp_init_nondata_skb(struct sk_buff *skb, u32 seq, u8 flags) TCP_SKB_CB(skb)->end_seq = seq; } -static void tcp_build_and_update_options(__be32 *ptr, struct tcp_sock *tp, - __u32 tstamp, __u8 **md5_hash) -{ - if (tp->rx_opt.tstamp_ok) { +#define OPTION_SACK_ADVERTISE (1 << 0) +#define OPTION_TS (1 << 1) +#define OPTION_MD5 (1 << 2) + +struct tcp_out_options { + u8 options; /* bit field of OPTION_* */ + u8 ws; /* window scale, 0 to disable */ + u8 num_sack_blocks; /* number of SACK blocks to include */ + u16 mss; /* 0 to disable */ + __u32 tsval, tsecr; /* need to include OPTION_TS */ +}; + +static void tcp_options_write(__be32 *ptr, struct tcp_sock *tp, + const struct tcp_out_options *opts, + __u8 **md5_hash) { + if (unlikely(OPTION_MD5 & opts->options)) { + *ptr++ = htonl((TCPOPT_NOP << 24) | + (TCPOPT_NOP << 16) | + (TCPOPT_MD5SIG << 8) | + TCPOLEN_MD5SIG); + *md5_hash = (__u8 *)ptr; + ptr += 4; + } else { + *md5_hash = NULL; + } + + if (likely(OPTION_TS & opts->options)) { + if (unlikely(OPTION_SACK_ADVERTISE & opts->options)) { + *ptr++ = htonl((TCPOPT_SACK_PERM << 24) | + (TCPOLEN_SACK_PERM << 16) | + (TCPOPT_TIMESTAMP << 8) | + TCPOLEN_TIMESTAMP); + } else { + *ptr++ = htonl((TCPOPT_NOP << 24) | + (TCPOPT_NOP << 16) | + (TCPOPT_TIMESTAMP << 8) | + TCPOLEN_TIMESTAMP); + } + *ptr++ = htonl(opts->tsval); + *ptr++ = htonl(opts->tsecr); + } + + if (unlikely(opts->mss)) { + *ptr++ = htonl((TCPOPT_MSS << 24) | + (TCPOLEN_MSS << 16) | + opts->mss); + } + + if (unlikely(OPTION_SACK_ADVERTISE & opts->options && + !(OPTION_TS & opts->options))) { *ptr++ = htonl((TCPOPT_NOP << 24) | (TCPOPT_NOP << 16) | - (TCPOPT_TIMESTAMP << 8) | - TCPOLEN_TIMESTAMP); - *ptr++ = htonl(tstamp); - *ptr++ = htonl(tp->rx_opt.ts_recent); + (TCPOPT_SACK_PERM << 8) | + TCPOLEN_SACK_PERM); + } + + if (unlikely(opts->ws)) { + *ptr++ = htonl((TCPOPT_NOP << 24) | + (TCPOPT_WINDOW << 16) | + (TCPOLEN_WINDOW << 8) | + opts->ws); } - if (tp->rx_opt.eff_sacks) { - struct tcp_sack_block *sp = tp->rx_opt.dsack ? tp->duplicate_sack : tp->selective_acks; + + if (unlikely(opts->num_sack_blocks)) { + struct tcp_sack_block *sp = tp->rx_opt.dsack ? + tp->duplicate_sack : tp->selective_acks; int this_sack; *ptr++ = htonl((TCPOPT_NOP << 24) | (TCPOPT_NOP << 16) | (TCPOPT_SACK << 8) | - (TCPOLEN_SACK_BASE + (tp->rx_opt.eff_sacks * + (TCPOLEN_SACK_BASE + (opts->num_sack_blocks * TCPOLEN_SACK_PERBLOCK))); - for (this_sack = 0; this_sack < tp->rx_opt.eff_sacks; this_sack++) { + for (this_sack = 0; this_sack < opts->num_sack_blocks; + ++this_sack) { *ptr++ = htonl(sp[this_sack].start_seq); *ptr++ = htonl(sp[this_sack].end_seq); } @@ -378,81 +430,137 @@ static void tcp_build_and_update_options(__be32 *ptr, struct tcp_sock *tp, tp->rx_opt.eff_sacks--; } } +} + +static unsigned tcp_syn_options(struct sock *sk, struct sk_buff *skb, + struct tcp_out_options *opts, + struct tcp_md5sig_key **md5) { + struct tcp_sock *tp = tcp_sk(sk); + unsigned size = 0; + #ifdef CONFIG_TCP_MD5SIG - if (md5_hash) { - *ptr++ = htonl((TCPOPT_NOP << 24) | - (TCPOPT_NOP << 16) | - (TCPOPT_MD5SIG << 8) | - TCPOLEN_MD5SIG); - *md5_hash = (__u8 *)ptr; + *md5 = tp->af_specific->md5_lookup(sk, sk); + if (*md5) { + opts->options |= OPTION_MD5; + size += TCPOLEN_MD5SIG_ALIGNED; } +#else + *md5 = NULL; #endif + + /* We always get an MSS option. The option bytes which will be seen in + * normal data packets should timestamps be used, must be in the MSS + * advertised. But we subtract them from tp->mss_cache so that + * calculations in tcp_sendmsg are simpler etc. So account for this + * fact here if necessary. If we don't do this correctly, as a + * receiver we won't recognize data packets as being full sized when we + * should, and thus we won't abide by the delayed ACK rules correctly. + * SACKs don't matter, we never delay an ACK when we have any of those + * going out. */ + opts->mss = tcp_advertise_mss(sk); + size += TCPOLEN_MSS_ALIGNED; + + if (likely(sysctl_tcp_timestamps && *md5 == NULL)) { + opts->options |= OPTION_TS; + opts->tsval = TCP_SKB_CB(skb)->when; + opts->tsecr = tp->rx_opt.ts_recent; + size += TCPOLEN_TSTAMP_ALIGNED; + } + if (likely(sysctl_tcp_window_scaling)) { + opts->ws = tp->rx_opt.rcv_wscale; + size += TCPOLEN_WSCALE_ALIGNED; + } + if (likely(sysctl_tcp_sack)) { + opts->options |= OPTION_SACK_ADVERTISE; + if (unlikely(!OPTION_TS & opts->options)) + size += TCPOLEN_SACKPERM_ALIGNED; + } + + return size; } -/* Construct a tcp options header for a SYN or SYN_ACK packet. - * If this is every changed make sure to change the definition of - * MAX_SYN_SIZE to match the new maximum number of options that you - * can generate. - * - * Note - that with the RFC2385 TCP option, we make room for the - * 16 byte MD5 hash. This will be filled in later, so the pointer for the - * location to be filled is passed back up. - */ -static void tcp_syn_build_options(__be32 *ptr, int mss, int ts, int sack, - int offer_wscale, int wscale, __u32 tstamp, - __u32 ts_recent, __u8 **md5_hash) -{ - /* We always get an MSS option. - * The option bytes which will be seen in normal data - * packets should timestamps be used, must be in the MSS - * advertised. But we subtract them from tp->mss_cache so - * that calculations in tcp_sendmsg are simpler etc. - * So account for this fact here if necessary. If we - * don't do this correctly, as a receiver we won't - * recognize data packets as being full sized when we - * should, and thus we won't abide by the delayed ACK - * rules correctly. - * SACKs don't matter, we never delay an ACK when we - * have any of those going out. - */ - *ptr++ = htonl((TCPOPT_MSS << 24) | (TCPOLEN_MSS << 16) | mss); - if (ts) { - if (sack) - *ptr++ = htonl((TCPOPT_SACK_PERM << 24) | - (TCPOLEN_SACK_PERM << 16) | - (TCPOPT_TIMESTAMP << 8) | - TCPOLEN_TIMESTAMP); - else - *ptr++ = htonl((TCPOPT_NOP << 24) | - (TCPOPT_NOP << 16) | - (TCPOPT_TIMESTAMP << 8) | - TCPOLEN_TIMESTAMP); - *ptr++ = htonl(tstamp); /* TSVAL */ - *ptr++ = htonl(ts_recent); /* TSECR */ - } else if (sack) - *ptr++ = htonl((TCPOPT_NOP << 24) | - (TCPOPT_NOP << 16) | - (TCPOPT_SACK_PERM << 8) | - TCPOLEN_SACK_PERM); - if (offer_wscale) - *ptr++ = htonl((TCPOPT_NOP << 24) | - (TCPOPT_WINDOW << 16) | - (TCPOLEN_WINDOW << 8) | - (wscale)); +static unsigned tcp_synack_options(struct sock *sk, + struct request_sock *req, + unsigned mss, struct sk_buff *skb, + struct tcp_out_options *opts, + struct tcp_md5sig_key **md5) { + unsigned size = 0; + struct inet_request_sock *ireq = inet_rsk(req); + char doing_ts; + #ifdef CONFIG_TCP_MD5SIG - /* - * If MD5 is enabled, then we set the option, and include the size - * (always 18). The actual MD5 hash is added just before the - * packet is sent. - */ - if (md5_hash) { - *ptr++ = htonl((TCPOPT_NOP << 24) | - (TCPOPT_NOP << 16) | - (TCPOPT_MD5SIG << 8) | - TCPOLEN_MD5SIG); - *md5_hash = (__u8 *)ptr; + *md5 = tcp_rsk(req)->af_specific->md5_lookup(sk, req); + if (*md5) { + opts->options |= OPTION_MD5; + size += TCPOLEN_MD5SIG_ALIGNED; } +#else + *md5 = NULL; #endif + + /* we can't fit any SACK blocks in a packet with MD5 + TS + options. There was discussion about disabling SACK rather than TS in + order to fit in better with old, buggy kernels, but that was deemed + to be unnecessary. */ + doing_ts = ireq->tstamp_ok && !(*md5 && ireq->sack_ok); + + opts->mss = mss; + size += TCPOLEN_MSS_ALIGNED; + + if (likely(ireq->wscale_ok)) { + opts->ws = ireq->rcv_wscale; + size += TCPOLEN_WSCALE_ALIGNED; + } + if (likely(doing_ts)) { + opts->options |= OPTION_TS; + opts->tsval = TCP_SKB_CB(skb)->when; + opts->tsecr = req->ts_recent; + size += TCPOLEN_TSTAMP_ALIGNED; + } + if (likely(ireq->sack_ok)) { + opts->options |= OPTION_SACK_ADVERTISE; + if (unlikely(!doing_ts)) + size += TCPOLEN_SACKPERM_ALIGNED; + } + + return size; +} + +static unsigned tcp_established_options(struct sock *sk, struct sk_buff *skb, + struct tcp_out_options *opts, + struct tcp_md5sig_key **md5) { + struct tcp_skb_cb *tcb = skb ? TCP_SKB_CB(skb) : NULL; + struct tcp_sock *tp = tcp_sk(sk); + unsigned size = 0; + +#ifdef CONFIG_TCP_MD5SIG + *md5 = tp->af_specific->md5_lookup(sk, sk); + if (unlikely(*md5)) { + opts->options |= OPTION_MD5; + size += TCPOLEN_MD5SIG_ALIGNED; + } +#else + *md5 = NULL; +#endif + + if (likely(tp->rx_opt.tstamp_ok)) { + opts->options |= OPTION_TS; + opts->tsval = tcb ? tcb->when : 0; + opts->tsecr = tp->rx_opt.ts_recent; + size += TCPOLEN_TSTAMP_ALIGNED; + } + + if (unlikely(tp->rx_opt.eff_sacks)) { + const unsigned remaining = MAX_TCP_OPTION_SPACE - size; + opts->num_sack_blocks = + min_t(unsigned, tp->rx_opt.eff_sacks, + (remaining - TCPOLEN_SACK_BASE_ALIGNED) / + TCPOLEN_SACK_PERBLOCK); + size += TCPOLEN_SACK_BASE_ALIGNED + + opts->num_sack_blocks * TCPOLEN_SACK_PERBLOCK; + } + + return size; } /* This routine actually transmits TCP packets queued in by @@ -473,13 +581,11 @@ static int tcp_transmit_skb(struct sock *sk, struct sk_buff *skb, int clone_it, struct inet_sock *inet; struct tcp_sock *tp; struct tcp_skb_cb *tcb; - int tcp_header_size; -#ifdef CONFIG_TCP_MD5SIG + struct tcp_out_options opts; + unsigned tcp_options_size, tcp_header_size; struct tcp_md5sig_key *md5; __u8 *md5_hash_location; -#endif struct tcphdr *th; - int sysctl_flags; int err; BUG_ON(!skb || !tcp_skb_pcount(skb)); @@ -502,50 +608,18 @@ static int tcp_transmit_skb(struct sock *sk, struct sk_buff *skb, int clone_it, inet = inet_sk(sk); tp = tcp_sk(sk); tcb = TCP_SKB_CB(skb); - tcp_header_size = tp->tcp_header_len; - -#define SYSCTL_FLAG_TSTAMPS 0x1 -#define SYSCTL_FLAG_WSCALE 0x2 -#define SYSCTL_FLAG_SACK 0x4 + memset(&opts, 0, sizeof(opts)); - sysctl_flags = 0; - if (unlikely(tcb->flags & TCPCB_FLAG_SYN)) { - tcp_header_size = sizeof(struct tcphdr) + TCPOLEN_MSS; - if (sysctl_tcp_timestamps) { - tcp_header_size += TCPOLEN_TSTAMP_ALIGNED; - sysctl_flags |= SYSCTL_FLAG_TSTAMPS; - } - if (sysctl_tcp_window_scaling) { - tcp_header_size += TCPOLEN_WSCALE_ALIGNED; - sysctl_flags |= SYSCTL_FLAG_WSCALE; - } - if (sysctl_tcp_sack) { - sysctl_flags |= SYSCTL_FLAG_SACK; - if (!(sysctl_flags & SYSCTL_FLAG_TSTAMPS)) - tcp_header_size += TCPOLEN_SACKPERM_ALIGNED; - } - } else if (unlikely(tp->rx_opt.eff_sacks)) { - /* A SACK is 2 pad bytes, a 2 byte header, plus - * 2 32-bit sequence numbers for each SACK block. - */ - tcp_header_size += (TCPOLEN_SACK_BASE_ALIGNED + - (tp->rx_opt.eff_sacks * - TCPOLEN_SACK_PERBLOCK)); - } + if (unlikely(tcb->flags & TCPCB_FLAG_SYN)) + tcp_options_size = tcp_syn_options(sk, skb, &opts, &md5); + else + tcp_options_size = tcp_established_options(sk, skb, &opts, + &md5); + tcp_header_size = tcp_options_size + sizeof(struct tcphdr); if (tcp_packets_in_flight(tp) == 0) tcp_ca_event(sk, CA_EVENT_TX_START); -#ifdef CONFIG_TCP_MD5SIG - /* - * Are we doing MD5 on this segment? If so - make - * room for it. - */ - md5 = tp->af_specific->md5_lookup(sk, sk); - if (md5) - tcp_header_size += TCPOLEN_MD5SIG_ALIGNED; -#endif - skb_push(skb, tcp_header_size); skb_reset_transport_header(skb); skb_set_owner_w(skb, sk); @@ -576,39 +650,16 @@ static int tcp_transmit_skb(struct sock *sk, struct sk_buff *skb, int clone_it, th->urg = 1; } - if (unlikely(tcb->flags & TCPCB_FLAG_SYN)) { - tcp_syn_build_options((__be32 *)(th + 1), - tcp_advertise_mss(sk), - (sysctl_flags & SYSCTL_FLAG_TSTAMPS), - (sysctl_flags & SYSCTL_FLAG_SACK), - (sysctl_flags & SYSCTL_FLAG_WSCALE), - tp->rx_opt.rcv_wscale, - tcb->when, - tp->rx_opt.ts_recent, - -#ifdef CONFIG_TCP_MD5SIG - md5 ? &md5_hash_location : -#endif - NULL); - } else { - tcp_build_and_update_options((__be32 *)(th + 1), - tp, tcb->when, -#ifdef CONFIG_TCP_MD5SIG - md5 ? &md5_hash_location : -#endif - NULL); + tcp_options_write((__be32 *)(th + 1), tp, &opts, &md5_hash_location); + if (likely((tcb->flags & TCPCB_FLAG_SYN) == 0)) TCP_ECN_send(sk, skb, tcp_header_size); - } #ifdef CONFIG_TCP_MD5SIG /* Calculate the MD5 hash, as we have all we need now */ if (md5) { + sk->sk_route_caps &= ~NETIF_F_GSO_MASK; tp->af_specific->calc_md5_hash(md5_hash_location, - md5, - sk, NULL, NULL, - tcp_hdr(skb), - sk->sk_protocol, - skb->len); + md5, sk, NULL, skb); } #endif @@ -621,7 +672,7 @@ static int tcp_transmit_skb(struct sock *sk, struct sk_buff *skb, int clone_it, tcp_event_data_sent(tp, skb, sk); if (after(tcb->end_seq, tp->snd_nxt) || tcb->seq == tcb->end_seq) - TCP_INC_STATS(TCP_MIB_OUTSEGS); + TCP_INC_STATS(sock_net(sk), TCP_MIB_OUTSEGS); err = icsk->icsk_af_ops->queue_xmit(skb, 0); if (likely(err <= 0)) @@ -630,10 +681,6 @@ static int tcp_transmit_skb(struct sock *sk, struct sk_buff *skb, int clone_it, tcp_enter_cwr(sk, 1); return net_xmit_eval(err); - -#undef SYSCTL_FLAG_TSTAMPS -#undef SYSCTL_FLAG_WSCALE -#undef SYSCTL_FLAG_SACK } /* This routine just queue's the buffer @@ -974,6 +1021,9 @@ unsigned int tcp_current_mss(struct sock *sk, int large_allowed) u32 mss_now; u16 xmit_size_goal; int doing_tso = 0; + unsigned header_len; + struct tcp_out_options opts; + struct tcp_md5sig_key *md5; mss_now = tp->mss_cache; @@ -986,14 +1036,16 @@ unsigned int tcp_current_mss(struct sock *sk, int large_allowed) mss_now = tcp_sync_mss(sk, mtu); } - if (tp->rx_opt.eff_sacks) - mss_now -= (TCPOLEN_SACK_BASE_ALIGNED + - (tp->rx_opt.eff_sacks * TCPOLEN_SACK_PERBLOCK)); - -#ifdef CONFIG_TCP_MD5SIG - if (tp->af_specific->md5_lookup(sk, sk)) - mss_now -= TCPOLEN_MD5SIG_ALIGNED; -#endif + header_len = tcp_established_options(sk, NULL, &opts, &md5) + + sizeof(struct tcphdr); + /* The mss_cache is sized based on tp->tcp_header_len, which assumes + * some common options. If this is an odd packet (because we have SACK + * blocks etc) then our calculated header_len will be different, and + * we have to adjust mss_now correspondingly */ + if (header_len != tp->tcp_header_len) { + int delta = (int) header_len - tp->tcp_header_len; + mss_now -= delta; + } xmit_size_goal = mss_now; @@ -1913,7 +1965,7 @@ int tcp_retransmit_skb(struct sock *sk, struct sk_buff *skb) if (err == 0) { /* Update global TCP statistics. */ - TCP_INC_STATS(TCP_MIB_RETRANSSEGS); + TCP_INC_STATS(sock_net(sk), TCP_MIB_RETRANSSEGS); tp->total_retrans++; @@ -1988,14 +2040,17 @@ void tcp_xmit_retransmit_queue(struct sock *sk) if (sacked & TCPCB_LOST) { if (!(sacked & (TCPCB_SACKED_ACKED|TCPCB_SACKED_RETRANS))) { + int mib_idx; + if (tcp_retransmit_skb(sk, skb)) { tp->retransmit_skb_hint = NULL; return; } if (icsk->icsk_ca_state != TCP_CA_Loss) - NET_INC_STATS_BH(LINUX_MIB_TCPFASTRETRANS); + mib_idx = LINUX_MIB_TCPFASTRETRANS; else - NET_INC_STATS_BH(LINUX_MIB_TCPSLOWSTARTRETRANS); + mib_idx = LINUX_MIB_TCPSLOWSTARTRETRANS; + NET_INC_STATS_BH(sock_net(sk), mib_idx); if (skb == tcp_write_queue_head(sk)) inet_csk_reset_xmit_timer(sk, ICSK_TIME_RETRANS, @@ -2065,7 +2120,7 @@ void tcp_xmit_retransmit_queue(struct sock *sk) inet_csk(sk)->icsk_rto, TCP_RTO_MAX); - NET_INC_STATS_BH(LINUX_MIB_TCPFORWARDRETRANS); + NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_TCPFORWARDRETRANS); } } @@ -2119,7 +2174,7 @@ void tcp_send_active_reset(struct sock *sk, gfp_t priority) /* NOTE: No TCP options attached and we never retransmit this. */ skb = alloc_skb(MAX_TCP_HEADER, priority); if (!skb) { - NET_INC_STATS(LINUX_MIB_TCPABORTFAILED); + NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPABORTFAILED); return; } @@ -2130,9 +2185,9 @@ void tcp_send_active_reset(struct sock *sk, gfp_t priority) /* Send it off. */ TCP_SKB_CB(skb)->when = tcp_time_stamp; if (tcp_transmit_skb(sk, skb, 0, priority)) - NET_INC_STATS(LINUX_MIB_TCPABORTFAILED); + NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPABORTFAILED); - TCP_INC_STATS(TCP_MIB_OUTRSTS); + TCP_INC_STATS(sock_net(sk), TCP_MIB_OUTRSTS); } /* WARNING: This routine must only be called when we have already sent @@ -2180,11 +2235,10 @@ struct sk_buff *tcp_make_synack(struct sock *sk, struct dst_entry *dst, struct tcp_sock *tp = tcp_sk(sk); struct tcphdr *th; int tcp_header_size; + struct tcp_out_options opts; struct sk_buff *skb; -#ifdef CONFIG_TCP_MD5SIG struct tcp_md5sig_key *md5; __u8 *md5_hash_location; -#endif skb = sock_wmalloc(sk, MAX_TCP_HEADER + 15, 1, GFP_ATOMIC); if (skb == NULL) @@ -2195,18 +2249,27 @@ struct sk_buff *tcp_make_synack(struct sock *sk, struct dst_entry *dst, skb->dst = dst_clone(dst); - tcp_header_size = (sizeof(struct tcphdr) + TCPOLEN_MSS + - (ireq->tstamp_ok ? TCPOLEN_TSTAMP_ALIGNED : 0) + - (ireq->wscale_ok ? TCPOLEN_WSCALE_ALIGNED : 0) + - /* SACK_PERM is in the place of NOP NOP of TS */ - ((ireq->sack_ok && !ireq->tstamp_ok) ? TCPOLEN_SACKPERM_ALIGNED : 0)); + if (req->rcv_wnd == 0) { /* ignored for retransmitted syns */ + __u8 rcv_wscale; + /* Set this up on the first call only */ + req->window_clamp = tp->window_clamp ? : dst_metric(dst, RTAX_WINDOW); + /* tcp_full_space because it is guaranteed to be the first packet */ + tcp_select_initial_window(tcp_full_space(sk), + dst_metric(dst, RTAX_ADVMSS) - (ireq->tstamp_ok ? TCPOLEN_TSTAMP_ALIGNED : 0), + &req->rcv_wnd, + &req->window_clamp, + ireq->wscale_ok, + &rcv_wscale); + ireq->rcv_wscale = rcv_wscale; + } + + memset(&opts, 0, sizeof(opts)); + TCP_SKB_CB(skb)->when = tcp_time_stamp; + tcp_header_size = tcp_synack_options(sk, req, + dst_metric(dst, RTAX_ADVMSS), + skb, &opts, &md5) + + sizeof(struct tcphdr); -#ifdef CONFIG_TCP_MD5SIG - /* Are we doing MD5 on this segment? If so - make room for it */ - md5 = tcp_rsk(req)->af_specific->md5_lookup(sk, req); - if (md5) - tcp_header_size += TCPOLEN_MD5SIG_ALIGNED; -#endif skb_push(skb, tcp_header_size); skb_reset_transport_header(skb); @@ -2224,19 +2287,6 @@ struct sk_buff *tcp_make_synack(struct sock *sk, struct dst_entry *dst, TCPCB_FLAG_SYN | TCPCB_FLAG_ACK); th->seq = htonl(TCP_SKB_CB(skb)->seq); th->ack_seq = htonl(tcp_rsk(req)->rcv_isn + 1); - if (req->rcv_wnd == 0) { /* ignored for retransmitted syns */ - __u8 rcv_wscale; - /* Set this up on the first call only */ - req->window_clamp = tp->window_clamp ? : dst_metric(dst, RTAX_WINDOW); - /* tcp_full_space because it is guaranteed to be the first packet */ - tcp_select_initial_window(tcp_full_space(sk), - dst_metric(dst, RTAX_ADVMSS) - (ireq->tstamp_ok ? TCPOLEN_TSTAMP_ALIGNED : 0), - &req->rcv_wnd, - &req->window_clamp, - ireq->wscale_ok, - &rcv_wscale); - ireq->rcv_wscale = rcv_wscale; - } /* RFC1323: The window in SYN & SYN/ACK segments is never scaled. */ th->window = htons(min(req->rcv_wnd, 65535U)); @@ -2245,29 +2295,15 @@ struct sk_buff *tcp_make_synack(struct sock *sk, struct dst_entry *dst, TCP_SKB_CB(skb)->when = cookie_init_timestamp(req); else #endif - TCP_SKB_CB(skb)->when = tcp_time_stamp; - tcp_syn_build_options((__be32 *)(th + 1), dst_metric(dst, RTAX_ADVMSS), ireq->tstamp_ok, - ireq->sack_ok, ireq->wscale_ok, ireq->rcv_wscale, - TCP_SKB_CB(skb)->when, - req->ts_recent, - ( -#ifdef CONFIG_TCP_MD5SIG - md5 ? &md5_hash_location : -#endif - NULL) - ); - + tcp_options_write((__be32 *)(th + 1), tp, &opts, &md5_hash_location); th->doff = (tcp_header_size >> 2); - TCP_INC_STATS(TCP_MIB_OUTSEGS); + TCP_INC_STATS(sock_net(sk), TCP_MIB_OUTSEGS); #ifdef CONFIG_TCP_MD5SIG /* Okay, we have all we need - do the md5 hash if needed */ if (md5) { tp->af_specific->calc_md5_hash(md5_hash_location, - md5, - NULL, dst, req, - tcp_hdr(skb), sk->sk_protocol, - skb->len); + md5, NULL, req, skb); } #endif @@ -2367,7 +2403,7 @@ int tcp_connect(struct sock *sk) */ tp->snd_nxt = tp->write_seq; tp->pushed_seq = tp->write_seq; - TCP_INC_STATS(TCP_MIB_ACTIVEOPENS); + TCP_INC_STATS(sock_net(sk), TCP_MIB_ACTIVEOPENS); /* Timer for repeating the SYN until an answer. */ inet_csk_reset_xmit_timer(sk, ICSK_TIME_RETRANS, diff --git a/net/ipv4/tcp_timer.c b/net/ipv4/tcp_timer.c index 63ed9d6830e7..328e0cf42b3c 100644 --- a/net/ipv4/tcp_timer.c +++ b/net/ipv4/tcp_timer.c @@ -5,8 +5,6 @@ * * Implementation of the Transmission Control Protocol(TCP). * - * Version: $Id: tcp_timer.c,v 1.88 2002/02/01 22:01:04 davem Exp $ - * * Authors: Ross Biro * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG> * Mark Evans, <evansmp@uhura.aston.ac.uk> @@ -50,7 +48,7 @@ static void tcp_write_err(struct sock *sk) sk->sk_error_report(sk); tcp_done(sk); - NET_INC_STATS_BH(LINUX_MIB_TCPABORTONTIMEOUT); + NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_TCPABORTONTIMEOUT); } /* Do not allow orphaned sockets to eat all our resources. @@ -91,7 +89,7 @@ static int tcp_out_of_resources(struct sock *sk, int do_reset) if (do_reset) tcp_send_active_reset(sk, GFP_ATOMIC); tcp_done(sk); - NET_INC_STATS_BH(LINUX_MIB_TCPABORTONMEMORY); + NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_TCPABORTONMEMORY); return 1; } return 0; @@ -181,7 +179,7 @@ static void tcp_delack_timer(unsigned long data) if (sock_owned_by_user(sk)) { /* Try again later. */ icsk->icsk_ack.blocked = 1; - NET_INC_STATS_BH(LINUX_MIB_DELAYEDACKLOCKED); + NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_DELAYEDACKLOCKED); sk_reset_timer(sk, &icsk->icsk_delack_timer, jiffies + TCP_DELACK_MIN); goto out_unlock; } @@ -200,7 +198,7 @@ static void tcp_delack_timer(unsigned long data) if (!skb_queue_empty(&tp->ucopy.prequeue)) { struct sk_buff *skb; - NET_INC_STATS_BH(LINUX_MIB_TCPSCHEDULERFAILED); + NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_TCPSCHEDULERFAILED); while ((skb = __skb_dequeue(&tp->ucopy.prequeue)) != NULL) sk->sk_backlog_rcv(sk, skb); @@ -220,7 +218,7 @@ static void tcp_delack_timer(unsigned long data) icsk->icsk_ack.ato = TCP_ATO_MIN; } tcp_send_ack(sk); - NET_INC_STATS_BH(LINUX_MIB_DELAYEDACKS); + NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_DELAYEDACKS); } TCP_CHECK_TIMER(sk); @@ -328,24 +326,27 @@ static void tcp_retransmit_timer(struct sock *sk) goto out; if (icsk->icsk_retransmits == 0) { + int mib_idx; + if (icsk->icsk_ca_state == TCP_CA_Disorder || icsk->icsk_ca_state == TCP_CA_Recovery) { if (tcp_is_sack(tp)) { if (icsk->icsk_ca_state == TCP_CA_Recovery) - NET_INC_STATS_BH(LINUX_MIB_TCPSACKRECOVERYFAIL); + mib_idx = LINUX_MIB_TCPSACKRECOVERYFAIL; else - NET_INC_STATS_BH(LINUX_MIB_TCPSACKFAILURES); + mib_idx = LINUX_MIB_TCPSACKFAILURES; } else { if (icsk->icsk_ca_state == TCP_CA_Recovery) - NET_INC_STATS_BH(LINUX_MIB_TCPRENORECOVERYFAIL); + mib_idx = LINUX_MIB_TCPRENORECOVERYFAIL; else - NET_INC_STATS_BH(LINUX_MIB_TCPRENOFAILURES); + mib_idx = LINUX_MIB_TCPRENOFAILURES; } } else if (icsk->icsk_ca_state == TCP_CA_Loss) { - NET_INC_STATS_BH(LINUX_MIB_TCPLOSSFAILURES); + mib_idx = LINUX_MIB_TCPLOSSFAILURES; } else { - NET_INC_STATS_BH(LINUX_MIB_TCPTIMEOUTS); + mib_idx = LINUX_MIB_TCPTIMEOUTS; } + NET_INC_STATS_BH(sock_net(sk), mib_idx); } if (tcp_use_frto(sk)) { diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index 56fcda3694ba..a751770947a3 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c @@ -5,8 +5,6 @@ * * The User Datagram Protocol (UDP). * - * Version: $Id: udp.c,v 1.102 2002/02/01 22:01:04 davem Exp $ - * * Authors: Ross Biro * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG> * Arnt Gulbrandsen, <agulbra@nvg.unit.no> @@ -110,9 +108,6 @@ * Snmp MIB for the UDP layer */ -DEFINE_SNMP_STAT(struct udp_mib, udp_statistics) __read_mostly; -EXPORT_SYMBOL(udp_statistics); - DEFINE_SNMP_STAT(struct udp_mib, udp_stats_in6) __read_mostly; EXPORT_SYMBOL(udp_stats_in6); @@ -136,7 +131,7 @@ static inline int __udp_lib_lport_inuse(struct net *net, __u16 num, struct sock *sk; struct hlist_node *node; - sk_for_each(sk, node, &udptable[num & (UDP_HTABLE_SIZE - 1)]) + sk_for_each(sk, node, &udptable[udp_hashfn(net, num)]) if (net_eq(sock_net(sk), net) && sk->sk_hash == num) return 1; return 0; @@ -176,7 +171,7 @@ int udp_lib_get_port(struct sock *sk, unsigned short snum, for (i = 0; i < UDP_HTABLE_SIZE; i++) { int size = 0; - head = &udptable[rover & (UDP_HTABLE_SIZE - 1)]; + head = &udptable[udp_hashfn(net, rover)]; if (hlist_empty(head)) goto gotit; @@ -213,7 +208,7 @@ int udp_lib_get_port(struct sock *sk, unsigned short snum, gotit: snum = rover; } else { - head = &udptable[snum & (UDP_HTABLE_SIZE - 1)]; + head = &udptable[udp_hashfn(net, snum)]; sk_for_each(sk2, node, head) if (sk2->sk_hash == snum && @@ -229,7 +224,7 @@ gotit: inet_sk(sk)->num = snum; sk->sk_hash = snum; if (sk_unhashed(sk)) { - head = &udptable[snum & (UDP_HTABLE_SIZE - 1)]; + head = &udptable[udp_hashfn(net, snum)]; sk_add_node(sk, head); sock_prot_inuse_add(sock_net(sk), sk->sk_prot, 1); } @@ -266,7 +261,7 @@ static struct sock *__udp4_lib_lookup(struct net *net, __be32 saddr, int badness = -1; read_lock(&udp_hash_lock); - sk_for_each(sk, node, &udptable[hnum & (UDP_HTABLE_SIZE - 1)]) { + sk_for_each(sk, node, &udptable[udp_hashfn(net, hnum)]) { struct inet_sock *inet = inet_sk(sk); if (net_eq(sock_net(sk), net) && sk->sk_hash == hnum && @@ -356,11 +351,12 @@ void __udp4_lib_err(struct sk_buff *skb, u32 info, struct hlist_head udptable[]) struct sock *sk; int harderr; int err; + struct net *net = dev_net(skb->dev); - sk = __udp4_lib_lookup(dev_net(skb->dev), iph->daddr, uh->dest, + sk = __udp4_lib_lookup(net, iph->daddr, uh->dest, iph->saddr, uh->source, skb->dev->ifindex, udptable); if (sk == NULL) { - ICMP_INC_STATS_BH(ICMP_MIB_INERRORS); + ICMP_INC_STATS_BH(net, ICMP_MIB_INERRORS); return; /* No socket for error */ } @@ -528,7 +524,8 @@ out: up->len = 0; up->pending = 0; if (!err) - UDP_INC_STATS_USER(UDP_MIB_OUTDATAGRAMS, is_udplite); + UDP_INC_STATS_USER(sock_net(sk), + UDP_MIB_OUTDATAGRAMS, is_udplite); return err; } @@ -656,11 +653,13 @@ int udp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, .uli_u = { .ports = { .sport = inet->sport, .dport = dport } } }; + struct net *net = sock_net(sk); + security_sk_classify_flow(sk, &fl); - err = ip_route_output_flow(sock_net(sk), &rt, &fl, sk, 1); + err = ip_route_output_flow(net, &rt, &fl, sk, 1); if (err) { if (err == -ENETUNREACH) - IP_INC_STATS_BH(IPSTATS_MIB_OUTNOROUTES); + IP_INC_STATS_BH(net, IPSTATS_MIB_OUTNOROUTES); goto out; } @@ -727,7 +726,8 @@ out: * seems like overkill. */ if (err == -ENOBUFS || test_bit(SOCK_NOSPACE, &sk->sk_socket->flags)) { - UDP_INC_STATS_USER(UDP_MIB_SNDBUFERRORS, is_udplite); + UDP_INC_STATS_USER(sock_net(sk), + UDP_MIB_SNDBUFERRORS, is_udplite); } return err; @@ -890,7 +890,8 @@ try_again: goto out_free; if (!peeked) - UDP_INC_STATS_USER(UDP_MIB_INDATAGRAMS, is_udplite); + UDP_INC_STATS_USER(sock_net(sk), + UDP_MIB_INDATAGRAMS, is_udplite); sock_recv_timestamp(msg, sk, skb); @@ -919,7 +920,7 @@ out: csum_copy_err: lock_sock(sk); if (!skb_kill_datagram(sk, skb, flags)) - UDP_INC_STATS_USER(UDP_MIB_INERRORS, is_udplite); + UDP_INC_STATS_USER(sock_net(sk), UDP_MIB_INERRORS, is_udplite); release_sock(sk); if (noblock) @@ -990,7 +991,8 @@ int udp_queue_rcv_skb(struct sock * sk, struct sk_buff *skb) ret = (*up->encap_rcv)(sk, skb); if (ret <= 0) { - UDP_INC_STATS_BH(UDP_MIB_INDATAGRAMS, + UDP_INC_STATS_BH(sock_net(sk), + UDP_MIB_INDATAGRAMS, is_udplite); return -ret; } @@ -1042,15 +1044,18 @@ int udp_queue_rcv_skb(struct sock * sk, struct sk_buff *skb) if ((rc = sock_queue_rcv_skb(sk,skb)) < 0) { /* Note that an ENOMEM error is charged twice */ - if (rc == -ENOMEM) - UDP_INC_STATS_BH(UDP_MIB_RCVBUFERRORS, is_udplite); + if (rc == -ENOMEM) { + UDP_INC_STATS_BH(sock_net(sk), + UDP_MIB_RCVBUFERRORS, is_udplite); + atomic_inc(&sk->sk_drops); + } goto drop; } return 0; drop: - UDP_INC_STATS_BH(UDP_MIB_INERRORS, is_udplite); + UDP_INC_STATS_BH(sock_net(sk), UDP_MIB_INERRORS, is_udplite); kfree_skb(skb); return -1; } @@ -1061,7 +1066,7 @@ drop: * Note: called only from the BH handler context, * so we don't need to lock the hashes. */ -static int __udp4_lib_mcast_deliver(struct sk_buff *skb, +static int __udp4_lib_mcast_deliver(struct net *net, struct sk_buff *skb, struct udphdr *uh, __be32 saddr, __be32 daddr, struct hlist_head udptable[]) @@ -1070,7 +1075,7 @@ static int __udp4_lib_mcast_deliver(struct sk_buff *skb, int dif; read_lock(&udp_hash_lock); - sk = sk_head(&udptable[ntohs(uh->dest) & (UDP_HTABLE_SIZE - 1)]); + sk = sk_head(&udptable[udp_hashfn(net, ntohs(uh->dest))]); dif = skb->dev->ifindex; sk = udp_v4_mcast_next(sk, uh->dest, daddr, uh->source, saddr, dif); if (sk) { @@ -1158,6 +1163,7 @@ int __udp4_lib_rcv(struct sk_buff *skb, struct hlist_head udptable[], struct rtable *rt = (struct rtable*)skb->dst; __be32 saddr = ip_hdr(skb)->saddr; __be32 daddr = ip_hdr(skb)->daddr; + struct net *net = dev_net(skb->dev); /* * Validate the packet. @@ -1180,9 +1186,10 @@ int __udp4_lib_rcv(struct sk_buff *skb, struct hlist_head udptable[], goto csum_error; if (rt->rt_flags & (RTCF_BROADCAST|RTCF_MULTICAST)) - return __udp4_lib_mcast_deliver(skb, uh, saddr, daddr, udptable); + return __udp4_lib_mcast_deliver(net, skb, uh, + saddr, daddr, udptable); - sk = __udp4_lib_lookup(dev_net(skb->dev), saddr, uh->source, daddr, + sk = __udp4_lib_lookup(net, saddr, uh->source, daddr, uh->dest, inet_iif(skb), udptable); if (sk != NULL) { @@ -1211,7 +1218,7 @@ int __udp4_lib_rcv(struct sk_buff *skb, struct hlist_head udptable[], if (udp_lib_checksum_complete(skb)) goto csum_error; - UDP_INC_STATS_BH(UDP_MIB_NOPORTS, proto == IPPROTO_UDPLITE); + UDP_INC_STATS_BH(net, UDP_MIB_NOPORTS, proto == IPPROTO_UDPLITE); icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0); /* @@ -1245,7 +1252,7 @@ csum_error: ntohs(uh->dest), ulen); drop: - UDP_INC_STATS_BH(UDP_MIB_INERRORS, proto == IPPROTO_UDPLITE); + UDP_INC_STATS_BH(net, UDP_MIB_INERRORS, proto == IPPROTO_UDPLITE); kfree_skb(skb); return 0; } @@ -1255,12 +1262,11 @@ int udp_rcv(struct sk_buff *skb) return __udp4_lib_rcv(skb, udp_hash, IPPROTO_UDP); } -int udp_destroy_sock(struct sock *sk) +void udp_destroy_sock(struct sock *sk) { lock_sock(sk); udp_flush_pending_frames(sk); release_sock(sk); - return 0; } /* @@ -1453,7 +1459,8 @@ unsigned int udp_poll(struct file *file, struct socket *sock, poll_table *wait) spin_lock_bh(&rcvq->lock); while ((skb = skb_peek(rcvq)) != NULL && udp_lib_checksum_complete(skb)) { - UDP_INC_STATS_BH(UDP_MIB_INERRORS, is_lite); + UDP_INC_STATS_BH(sock_net(sk), + UDP_MIB_INERRORS, is_lite); __skb_unlink(skb, rcvq); kfree_skb(skb); } @@ -1629,12 +1636,13 @@ static void udp4_format_sock(struct sock *sp, struct seq_file *f, __u16 srcp = ntohs(inet->sport); seq_printf(f, "%4d: %08X:%04X %08X:%04X" - " %02X %08X:%08X %02X:%08lX %08X %5d %8d %lu %d %p%n", + " %02X %08X:%08X %02X:%08lX %08X %5d %8d %lu %d %p %d%n", bucket, src, srcp, dest, destp, sp->sk_state, atomic_read(&sp->sk_wmem_alloc), atomic_read(&sp->sk_rmem_alloc), 0, 0L, 0, sock_i_uid(sp), 0, sock_i_ino(sp), - atomic_read(&sp->sk_refcnt), sp, len); + atomic_read(&sp->sk_refcnt), sp, + atomic_read(&sp->sk_drops), len); } int udp4_seq_show(struct seq_file *seq, void *v) @@ -1643,7 +1651,7 @@ int udp4_seq_show(struct seq_file *seq, void *v) seq_printf(seq, "%-127s\n", " sl local_address rem_address st tx_queue " "rx_queue tr tm->when retrnsmt uid timeout " - "inode"); + "inode ref pointer drops"); else { struct udp_iter_state *state = seq->private; int len; diff --git a/net/ipv4/udp_impl.h b/net/ipv4/udp_impl.h index 7288bf7977fb..2e9bad2fa1bc 100644 --- a/net/ipv4/udp_impl.h +++ b/net/ipv4/udp_impl.h @@ -26,7 +26,7 @@ extern int udp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, extern int udp_sendpage(struct sock *sk, struct page *page, int offset, size_t size, int flags); extern int udp_queue_rcv_skb(struct sock * sk, struct sk_buff *skb); -extern int udp_destroy_sock(struct sock *sk); +extern void udp_destroy_sock(struct sock *sk); #ifdef CONFIG_PROC_FS extern int udp4_seq_show(struct seq_file *seq, void *v); diff --git a/net/ipv4/udplite.c b/net/ipv4/udplite.c index 72ce26b6c4d3..3c807964da96 100644 --- a/net/ipv4/udplite.c +++ b/net/ipv4/udplite.c @@ -1,8 +1,6 @@ /* * UDPLITE An implementation of the UDP-Lite protocol (RFC 3828). * - * Version: $Id: udplite.c,v 1.25 2006/10/19 07:22:36 gerrit Exp $ - * * Authors: Gerrit Renker <gerrit@erg.abdn.ac.uk> * * Changes: @@ -13,7 +11,6 @@ * 2 of the License, or (at your option) any later version. */ #include "udp_impl.h" -DEFINE_SNMP_STAT(struct udp_mib, udplite_statistics) __read_mostly; struct hlist_head udplite_hash[UDP_HTABLE_SIZE]; diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index ff61a5cdb0b3..9f4fcce6379b 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -6,8 +6,6 @@ * Pedro Roque <roque@di.fc.ul.pt> * Alexey Kuznetsov <kuznet@ms2.inr.ac.ru> * - * $Id: addrconf.c,v 1.69 2001/10/31 21:55:54 davem Exp $ - * * 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 @@ -121,6 +119,7 @@ static void ipv6_regen_rndid(unsigned long data); static int desync_factor = MAX_DESYNC_FACTOR * HZ; #endif +static int ipv6_generate_eui64(u8 *eui, struct net_device *dev); static int ipv6_count_addresses(struct inet6_dev *idev); /* @@ -185,6 +184,8 @@ struct ipv6_devconf ipv6_devconf __read_mostly = { #endif .proxy_ndp = 0, .accept_source_route = 0, /* we do not accept RH0 by default. */ + .disable_ipv6 = 0, + .accept_dad = 1, }; static struct ipv6_devconf ipv6_devconf_dflt __read_mostly = { @@ -217,6 +218,8 @@ static struct ipv6_devconf ipv6_devconf_dflt __read_mostly = { #endif .proxy_ndp = 0, .accept_source_route = 0, /* we do not accept RH0 by default. */ + .disable_ipv6 = 0, + .accept_dad = 1, }; /* IPv6 Wildcard Address and Loopback Address defined by RFC2553 */ @@ -226,9 +229,15 @@ const struct in6_addr in6addr_linklocal_allnodes = IN6ADDR_LINKLOCAL_ALLNODES_IN const struct in6_addr in6addr_linklocal_allrouters = IN6ADDR_LINKLOCAL_ALLROUTERS_INIT; /* Check if a valid qdisc is available */ -static inline int addrconf_qdisc_ok(struct net_device *dev) +static inline bool addrconf_qdisc_ok(const struct net_device *dev) +{ + return !qdisc_tx_is_noop(dev); +} + +/* Check if a route is valid prefix route */ +static inline int addrconf_is_prefix_route(const struct rt6_info *rt) { - return (dev->qdisc != &noop_qdisc); + return ((rt->rt6i_flags & (RTF_GATEWAY | RTF_DEFAULT)) == 0); } static void addrconf_del_timer(struct inet6_ifaddr *ifp) @@ -344,6 +353,8 @@ static struct inet6_dev * ipv6_add_dev(struct net_device *dev) kfree(ndev); return NULL; } + if (ndev->cnf.forwarding) + dev_disable_lro(dev); /* We refer to the device */ dev_hold(dev); @@ -372,6 +383,9 @@ static struct inet6_dev * ipv6_add_dev(struct net_device *dev) */ in6_dev_hold(ndev); + if (dev->flags & (IFF_NOARP | IFF_LOOPBACK)) + ndev->cnf.accept_dad = -1; + #if defined(CONFIG_IPV6_SIT) || defined(CONFIG_IPV6_SIT_MODULE) if (dev->type == ARPHRD_SIT && (dev->priv_flags & IFF_ISATAP)) { printk(KERN_INFO @@ -438,6 +452,8 @@ static void dev_forward_change(struct inet6_dev *idev) if (!idev) return; dev = idev->dev; + if (idev->cnf.forwarding) + dev_disable_lro(dev); if (dev && (dev->flags & IFF_MULTICAST)) { if (idev->cnf.forwarding) ipv6_dev_mc_inc(dev, &in6addr_linklocal_allrouters); @@ -483,12 +499,14 @@ static void addrconf_fixup_forwarding(struct ctl_table *table, int *p, int old) if (p == &net->ipv6.devconf_dflt->forwarding) return; + rtnl_lock(); if (p == &net->ipv6.devconf_all->forwarding) { __s32 newf = net->ipv6.devconf_all->forwarding; net->ipv6.devconf_dflt->forwarding = newf; addrconf_forward_change(net, newf); } else if ((!*p) ^ (!old)) dev_forward_change((struct inet6_dev *)table->extra1); + rtnl_unlock(); if (*p) rt6_purge_dflt_routers(net); @@ -568,6 +586,13 @@ ipv6_add_addr(struct inet6_dev *idev, const struct in6_addr *addr, int pfxlen, struct rt6_info *rt; int hash; int err = 0; + int addr_type = ipv6_addr_type(addr); + + if (addr_type == IPV6_ADDR_ANY || + addr_type & IPV6_ADDR_MULTICAST || + (!(idev->dev->flags & IFF_LOOPBACK) && + addr_type & IPV6_ADDR_LOOPBACK)) + return ERR_PTR(-EADDRNOTAVAIL); rcu_read_lock_bh(); if (idev->dead) { @@ -777,7 +802,7 @@ static void ipv6_del_addr(struct inet6_ifaddr *ifp) ipv6_addr_prefix(&prefix, &ifp->addr, ifp->prefix_len); rt = rt6_lookup(net, &prefix, NULL, ifp->idev->dev->ifindex, 1); - if (rt && ((rt->rt6i_flags & (RTF_GATEWAY | RTF_DEFAULT)) == 0)) { + if (rt && addrconf_is_prefix_route(rt)) { if (onlink == 0) { ip6_del_rt(rt); rt = NULL; @@ -958,7 +983,8 @@ static inline int ipv6_saddr_preferred(int type) return 0; } -static int ipv6_get_saddr_eval(struct ipv6_saddr_score *score, +static int ipv6_get_saddr_eval(struct net *net, + struct ipv6_saddr_score *score, struct ipv6_saddr_dst *dst, int i) { @@ -1037,7 +1063,8 @@ static int ipv6_get_saddr_eval(struct ipv6_saddr_score *score, break; case IPV6_SADDR_RULE_LABEL: /* Rule 6: Prefer matching label */ - ret = ipv6_addr_label(&score->ifa->addr, score->addr_type, + ret = ipv6_addr_label(net, + &score->ifa->addr, score->addr_type, score->ifa->idev->dev->ifindex) == dst->label; break; #ifdef CONFIG_IPV6_PRIVACY @@ -1091,7 +1118,7 @@ int ipv6_dev_get_saddr(struct net_device *dst_dev, dst.addr = daddr; dst.ifindex = dst_dev ? dst_dev->ifindex : 0; dst.scope = __ipv6_addr_src_scope(dst_type); - dst.label = ipv6_addr_label(daddr, dst_type, dst.ifindex); + dst.label = ipv6_addr_label(net, daddr, dst_type, dst.ifindex); dst.prefs = prefs; hiscore->rule = -1; @@ -1159,8 +1186,8 @@ int ipv6_dev_get_saddr(struct net_device *dst_dev, for (i = 0; i < IPV6_SADDR_RULE_MAX; i++) { int minihiscore, miniscore; - minihiscore = ipv6_get_saddr_eval(hiscore, &dst, i); - miniscore = ipv6_get_saddr_eval(score, &dst, i); + minihiscore = ipv6_get_saddr_eval(net, hiscore, &dst, i); + miniscore = ipv6_get_saddr_eval(net, score, &dst, i); if (minihiscore > miniscore) { if (i == IPV6_SADDR_RULE_SCOPE && @@ -1400,6 +1427,20 @@ static void addrconf_dad_stop(struct inet6_ifaddr *ifp) void addrconf_dad_failure(struct inet6_ifaddr *ifp) { + struct inet6_dev *idev = ifp->idev; + if (idev->cnf.accept_dad > 1 && !idev->cnf.disable_ipv6) { + struct in6_addr addr; + + addr.s6_addr32[0] = htonl(0xfe800000); + addr.s6_addr32[1] = 0; + + if (!ipv6_generate_eui64(addr.s6_addr + 8, idev->dev) && + ipv6_addr_equal(&ifp->addr, &addr)) { + /* DAD failed for link-local based on MAC address */ + idev->cnf.disable_ipv6 = 1; + } + } + if (net_ratelimit()) printk(KERN_INFO "%s: duplicate address detected!\n", ifp->idev->dev->name); addrconf_dad_stop(ifp); @@ -1788,7 +1829,7 @@ void addrconf_prefix_rcv(struct net_device *dev, u8 *opt, int len) rt = rt6_lookup(dev_net(dev), &pinfo->prefix, NULL, dev->ifindex, 1); - if (rt && ((rt->rt6i_flags & (RTF_GATEWAY | RTF_DEFAULT)) == 0)) { + if (rt && addrconf_is_prefix_route(rt)) { /* Autoconf prefix route */ if (valid_lft == 0) { ip6_del_rt(rt); @@ -1822,6 +1863,7 @@ 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); @@ -1840,7 +1882,7 @@ void addrconf_prefix_rcv(struct net_device *dev, u8 *opt, int len) ok: - ifp = ipv6_get_ifaddr(dev_net(dev), &addr, dev, 1); + ifp = ipv6_get_ifaddr(net, &addr, dev, 1); if (ifp == NULL && valid_lft) { int max_addresses = in6_dev->cnf.max_addresses; @@ -1848,7 +1890,7 @@ ok: #ifdef CONFIG_IPV6_OPTIMISTIC_DAD if (in6_dev->cnf.optimistic_dad && - !ipv6_devconf.forwarding) + !net->ipv6.devconf_all->forwarding) addr_flags = IFA_F_OPTIMISTIC; #endif @@ -2277,7 +2319,7 @@ static void addrconf_add_linklocal(struct inet6_dev *idev, struct in6_addr *addr #ifdef CONFIG_IPV6_OPTIMISTIC_DAD if (idev->cnf.optimistic_dad && - !ipv6_devconf.forwarding) + !dev_net(idev->dev)->ipv6.devconf_all->forwarding) addr_flags |= IFA_F_OPTIMISTIC; #endif @@ -2732,6 +2774,7 @@ static void addrconf_dad_start(struct inet6_ifaddr *ifp, u32 flags) spin_lock_bh(&ifp->lock); if (dev->flags&(IFF_NOARP|IFF_LOOPBACK) || + idev->cnf.accept_dad < 1 || !(ifp->flags&IFA_F_TENTATIVE) || ifp->flags & IFA_F_NODAD) { ifp->flags &= ~(IFA_F_TENTATIVE|IFA_F_OPTIMISTIC); @@ -2779,6 +2822,11 @@ static void addrconf_dad_timer(unsigned long data) read_unlock_bh(&idev->lock); goto out; } + if (idev->cnf.accept_dad > 1 && idev->cnf.disable_ipv6) { + read_unlock_bh(&idev->lock); + addrconf_dad_failure(ifp); + return; + } spin_lock_bh(&ifp->lock); if (ifp->probes == 0) { /* @@ -3638,6 +3686,8 @@ static inline void ipv6_store_devconf(struct ipv6_devconf *cnf, #ifdef CONFIG_IPV6_MROUTE array[DEVCONF_MC_FORWARDING] = cnf->mc_forwarding; #endif + array[DEVCONF_DISABLE_IPV6] = cnf->disable_ipv6; + array[DEVCONF_ACCEPT_DAD] = cnf->accept_dad; } static inline size_t inet6_if_nlmsg_size(void) @@ -4197,6 +4247,22 @@ static struct addrconf_sysctl_table }, #endif { + .ctl_name = CTL_UNNUMBERED, + .procname = "disable_ipv6", + .data = &ipv6_devconf.disable_ipv6, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &proc_dointvec, + }, + { + .ctl_name = CTL_UNNUMBERED, + .procname = "accept_dad", + .data = &ipv6_devconf.accept_dad, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &proc_dointvec, + }, + { .ctl_name = 0, /* sentinel */ } }, diff --git a/net/ipv6/addrlabel.c b/net/ipv6/addrlabel.c index 9bfa8846f262..08909039d87b 100644 --- a/net/ipv6/addrlabel.c +++ b/net/ipv6/addrlabel.c @@ -29,6 +29,9 @@ */ struct ip6addrlbl_entry { +#ifdef CONFIG_NET_NS + struct net *lbl_net; +#endif struct in6_addr prefix; int prefixlen; int ifindex; @@ -46,6 +49,16 @@ static struct ip6addrlbl_table u32 seq; } ip6addrlbl_table; +static inline +struct net *ip6addrlbl_net(const struct ip6addrlbl_entry *lbl) +{ +#ifdef CONFIG_NET_NS + return lbl->lbl_net; +#else + return &init_net; +#endif +} + /* * Default policy table (RFC3484 + extensions) * @@ -65,7 +78,7 @@ static struct ip6addrlbl_table #define IPV6_ADDR_LABEL_DEFAULT 0xffffffffUL -static const __initdata struct ip6addrlbl_init_table +static const __net_initdata struct ip6addrlbl_init_table { const struct in6_addr *prefix; int prefixlen; @@ -108,6 +121,9 @@ static const __initdata struct ip6addrlbl_init_table /* Object management */ static inline void ip6addrlbl_free(struct ip6addrlbl_entry *p) { +#ifdef CONFIG_NET_NS + release_net(p->lbl_net); +#endif kfree(p); } @@ -128,10 +144,13 @@ static inline void ip6addrlbl_put(struct ip6addrlbl_entry *p) } /* Find label */ -static int __ip6addrlbl_match(struct ip6addrlbl_entry *p, +static int __ip6addrlbl_match(struct net *net, + struct ip6addrlbl_entry *p, const struct in6_addr *addr, int addrtype, int ifindex) { + if (!net_eq(ip6addrlbl_net(p), net)) + return 0; if (p->ifindex && p->ifindex != ifindex) return 0; if (p->addrtype && p->addrtype != addrtype) @@ -141,19 +160,21 @@ static int __ip6addrlbl_match(struct ip6addrlbl_entry *p, return 1; } -static struct ip6addrlbl_entry *__ipv6_addr_label(const struct in6_addr *addr, +static struct ip6addrlbl_entry *__ipv6_addr_label(struct net *net, + const struct in6_addr *addr, int type, int ifindex) { struct hlist_node *pos; struct ip6addrlbl_entry *p; hlist_for_each_entry_rcu(p, pos, &ip6addrlbl_table.head, list) { - if (__ip6addrlbl_match(p, addr, type, ifindex)) + if (__ip6addrlbl_match(net, p, addr, type, ifindex)) return p; } return NULL; } -u32 ipv6_addr_label(const struct in6_addr *addr, int type, int ifindex) +u32 ipv6_addr_label(struct net *net, + const struct in6_addr *addr, int type, int ifindex) { u32 label; struct ip6addrlbl_entry *p; @@ -161,7 +182,7 @@ u32 ipv6_addr_label(const struct in6_addr *addr, int type, int ifindex) type &= IPV6_ADDR_MAPPED | IPV6_ADDR_COMPATv4 | IPV6_ADDR_LOOPBACK; rcu_read_lock(); - p = __ipv6_addr_label(addr, type, ifindex); + p = __ipv6_addr_label(net, addr, type, ifindex); label = p ? p->label : IPV6_ADDR_LABEL_DEFAULT; rcu_read_unlock(); @@ -174,7 +195,8 @@ u32 ipv6_addr_label(const struct in6_addr *addr, int type, int ifindex) } /* allocate one entry */ -static struct ip6addrlbl_entry *ip6addrlbl_alloc(const struct in6_addr *prefix, +static struct ip6addrlbl_entry *ip6addrlbl_alloc(struct net *net, + const struct in6_addr *prefix, int prefixlen, int ifindex, u32 label) { @@ -216,6 +238,9 @@ static struct ip6addrlbl_entry *ip6addrlbl_alloc(const struct in6_addr *prefix, newp->addrtype = addrtype; newp->label = label; INIT_HLIST_NODE(&newp->list); +#ifdef CONFIG_NET_NS + newp->lbl_net = hold_net(net); +#endif atomic_set(&newp->refcnt, 1); return newp; } @@ -237,6 +262,7 @@ static int __ip6addrlbl_add(struct ip6addrlbl_entry *newp, int replace) hlist_for_each_entry_safe(p, pos, n, &ip6addrlbl_table.head, list) { if (p->prefixlen == newp->prefixlen && + net_eq(ip6addrlbl_net(p), ip6addrlbl_net(newp)) && p->ifindex == newp->ifindex && ipv6_addr_equal(&p->prefix, &newp->prefix)) { if (!replace) { @@ -261,7 +287,8 @@ out: } /* add a label */ -static int ip6addrlbl_add(const struct in6_addr *prefix, int prefixlen, +static int ip6addrlbl_add(struct net *net, + const struct in6_addr *prefix, int prefixlen, int ifindex, u32 label, int replace) { struct ip6addrlbl_entry *newp; @@ -274,7 +301,7 @@ static int ip6addrlbl_add(const struct in6_addr *prefix, int prefixlen, (unsigned int)label, replace); - newp = ip6addrlbl_alloc(prefix, prefixlen, ifindex, label); + newp = ip6addrlbl_alloc(net, prefix, prefixlen, ifindex, label); if (IS_ERR(newp)) return PTR_ERR(newp); spin_lock(&ip6addrlbl_table.lock); @@ -286,7 +313,8 @@ static int ip6addrlbl_add(const struct in6_addr *prefix, int prefixlen, } /* remove a label */ -static int __ip6addrlbl_del(const struct in6_addr *prefix, int prefixlen, +static int __ip6addrlbl_del(struct net *net, + const struct in6_addr *prefix, int prefixlen, int ifindex) { struct ip6addrlbl_entry *p = NULL; @@ -300,6 +328,7 @@ static int __ip6addrlbl_del(const struct in6_addr *prefix, int prefixlen, hlist_for_each_entry_safe(p, pos, n, &ip6addrlbl_table.head, list) { if (p->prefixlen == prefixlen && + net_eq(ip6addrlbl_net(p), net) && p->ifindex == ifindex && ipv6_addr_equal(&p->prefix, prefix)) { hlist_del_rcu(&p->list); @@ -311,7 +340,8 @@ static int __ip6addrlbl_del(const struct in6_addr *prefix, int prefixlen, return ret; } -static int ip6addrlbl_del(const struct in6_addr *prefix, int prefixlen, +static int ip6addrlbl_del(struct net *net, + const struct in6_addr *prefix, int prefixlen, int ifindex) { struct in6_addr prefix_buf; @@ -324,13 +354,13 @@ static int ip6addrlbl_del(const struct in6_addr *prefix, int prefixlen, ipv6_addr_prefix(&prefix_buf, prefix, prefixlen); spin_lock(&ip6addrlbl_table.lock); - ret = __ip6addrlbl_del(&prefix_buf, prefixlen, ifindex); + ret = __ip6addrlbl_del(net, &prefix_buf, prefixlen, ifindex); spin_unlock(&ip6addrlbl_table.lock); return ret; } /* add default label */ -static __init int ip6addrlbl_init(void) +static int __net_init ip6addrlbl_net_init(struct net *net) { int err = 0; int i; @@ -338,7 +368,8 @@ static __init int ip6addrlbl_init(void) ADDRLABEL(KERN_DEBUG "%s()\n", __func__); for (i = 0; i < ARRAY_SIZE(ip6addrlbl_init_table); i++) { - int ret = ip6addrlbl_add(ip6addrlbl_init_table[i].prefix, + int ret = ip6addrlbl_add(net, + ip6addrlbl_init_table[i].prefix, ip6addrlbl_init_table[i].prefixlen, 0, ip6addrlbl_init_table[i].label, 0); @@ -349,11 +380,32 @@ static __init int ip6addrlbl_init(void) return err; } +static void __net_exit ip6addrlbl_net_exit(struct net *net) +{ + struct ip6addrlbl_entry *p = NULL; + struct hlist_node *pos, *n; + + /* Remove all labels belonging to the exiting net */ + spin_lock(&ip6addrlbl_table.lock); + hlist_for_each_entry_safe(p, pos, n, &ip6addrlbl_table.head, list) { + if (net_eq(ip6addrlbl_net(p), net)) { + hlist_del_rcu(&p->list); + ip6addrlbl_put(p); + } + } + spin_unlock(&ip6addrlbl_table.lock); +} + +static struct pernet_operations ipv6_addr_label_ops = { + .init = ip6addrlbl_net_init, + .exit = ip6addrlbl_net_exit, +}; + int __init ipv6_addr_label_init(void) { spin_lock_init(&ip6addrlbl_table.lock); - return ip6addrlbl_init(); + return register_pernet_subsys(&ipv6_addr_label_ops); } static const struct nla_policy ifal_policy[IFAL_MAX+1] = { @@ -371,9 +423,6 @@ static int ip6addrlbl_newdel(struct sk_buff *skb, struct nlmsghdr *nlh, u32 label; int err = 0; - if (net != &init_net) - return 0; - err = nlmsg_parse(nlh, sizeof(*ifal), tb, IFAL_MAX, ifal_policy); if (err < 0) return err; @@ -385,7 +434,7 @@ static int ip6addrlbl_newdel(struct sk_buff *skb, struct nlmsghdr *nlh, return -EINVAL; if (ifal->ifal_index && - !__dev_get_by_index(&init_net, ifal->ifal_index)) + !__dev_get_by_index(net, ifal->ifal_index)) return -EINVAL; if (!tb[IFAL_ADDRESS]) @@ -403,12 +452,12 @@ static int ip6addrlbl_newdel(struct sk_buff *skb, struct nlmsghdr *nlh, switch(nlh->nlmsg_type) { case RTM_NEWADDRLABEL: - err = ip6addrlbl_add(pfx, ifal->ifal_prefixlen, + err = ip6addrlbl_add(net, pfx, ifal->ifal_prefixlen, ifal->ifal_index, label, nlh->nlmsg_flags & NLM_F_REPLACE); break; case RTM_DELADDRLABEL: - err = ip6addrlbl_del(pfx, ifal->ifal_prefixlen, + err = ip6addrlbl_del(net, pfx, ifal->ifal_prefixlen, ifal->ifal_index); break; default: @@ -458,12 +507,10 @@ static int ip6addrlbl_dump(struct sk_buff *skb, struct netlink_callback *cb) int idx = 0, s_idx = cb->args[0]; int err; - if (net != &init_net) - return 0; - rcu_read_lock(); hlist_for_each_entry_rcu(p, pos, &ip6addrlbl_table.head, list) { - if (idx >= s_idx) { + if (idx >= s_idx && + net_eq(ip6addrlbl_net(p), net)) { if ((err = ip6addrlbl_fill(skb, p, ip6addrlbl_table.seq, NETLINK_CB(cb->skb).pid, @@ -499,9 +546,6 @@ static int ip6addrlbl_get(struct sk_buff *in_skb, struct nlmsghdr* nlh, struct ip6addrlbl_entry *p; struct sk_buff *skb; - if (net != &init_net) - return 0; - err = nlmsg_parse(nlh, sizeof(*ifal), tb, IFAL_MAX, ifal_policy); if (err < 0) return err; @@ -513,7 +557,7 @@ static int ip6addrlbl_get(struct sk_buff *in_skb, struct nlmsghdr* nlh, return -EINVAL; if (ifal->ifal_index && - !__dev_get_by_index(&init_net, ifal->ifal_index)) + !__dev_get_by_index(net, ifal->ifal_index)) return -EINVAL; if (!tb[IFAL_ADDRESS]) @@ -524,7 +568,7 @@ static int ip6addrlbl_get(struct sk_buff *in_skb, struct nlmsghdr* nlh, return -EINVAL; rcu_read_lock(); - p = __ipv6_addr_label(addr, ipv6_addr_type(addr), ifal->ifal_index); + p = __ipv6_addr_label(net, addr, ipv6_addr_type(addr), ifal->ifal_index); if (p && ip6addrlbl_hold(p)) p = NULL; lseq = ip6addrlbl_table.seq; @@ -552,7 +596,7 @@ static int ip6addrlbl_get(struct sk_buff *in_skb, struct nlmsghdr* nlh, goto out; } - err = rtnl_unicast(skb, &init_net, NETLINK_CB(in_skb).pid); + err = rtnl_unicast(skb, net, NETLINK_CB(in_skb).pid); out: return err; } diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c index e84b3fd17fb4..3d828bc4b1cf 100644 --- a/net/ipv6/af_inet6.c +++ b/net/ipv6/af_inet6.c @@ -7,8 +7,6 @@ * * Adapted from linux/net/ipv4/af_inet.c * - * $Id: af_inet6.c,v 1.66 2002/02/01 22:01:04 davem Exp $ - * * Fixes: * piggy, Karl Knutson : Socket protocol table * Hideaki YOSHIFUJI : sin6_scope_id support @@ -61,9 +59,7 @@ #include <asm/uaccess.h> #include <asm/system.h> -#ifdef CONFIG_IPV6_MROUTE #include <linux/mroute6.h> -#endif MODULE_AUTHOR("Cast of dozens"); MODULE_DESCRIPTION("IPv6 protocol stack for Linux"); @@ -373,7 +369,7 @@ int inet6_release(struct socket *sock) EXPORT_SYMBOL(inet6_release); -int inet6_destroy_sock(struct sock *sk) +void inet6_destroy_sock(struct sock *sk) { struct ipv6_pinfo *np = inet6_sk(sk); struct sk_buff *skb; @@ -391,8 +387,6 @@ int inet6_destroy_sock(struct sock *sk) if ((opt = xchg(&np->opt, NULL)) != NULL) sock_kfree_s(sk, opt, opt->tot_len); - - return 0; } EXPORT_SYMBOL_GPL(inet6_destroy_sock); @@ -956,9 +950,9 @@ static int __init inet6_init(void) err = icmpv6_init(); if (err) goto icmp_fail; -#ifdef CONFIG_IPV6_MROUTE - ip6_mr_init(); -#endif + err = ip6_mr_init(); + if (err) + goto ipmr_fail; err = ndisc_init(); if (err) goto ndisc_fail; @@ -1061,6 +1055,8 @@ netfilter_fail: igmp_fail: ndisc_cleanup(); ndisc_fail: + ip6_mr_cleanup(); +ipmr_fail: icmpv6_cleanup(); icmp_fail: unregister_pernet_subsys(&inet6_net_ops); @@ -1115,6 +1111,7 @@ static void __exit inet6_exit(void) ipv6_netfilter_fini(); igmp6_cleanup(); ndisc_cleanup(); + ip6_mr_cleanup(); icmpv6_cleanup(); rawv6_exit(); diff --git a/net/ipv6/anycast.c b/net/ipv6/anycast.c index 4e1b29fabdf0..8336cd81cb4f 100644 --- a/net/ipv6/anycast.c +++ b/net/ipv6/anycast.c @@ -60,7 +60,7 @@ int ipv6_sock_ac_join(struct sock *sk, int ifindex, struct in6_addr *addr) struct inet6_dev *idev; struct ipv6_ac_socklist *pac; struct net *net = sock_net(sk); - int ishost = !ipv6_devconf.forwarding; + int ishost = !net->ipv6.devconf_all->forwarding; int err = 0; if (!capable(CAP_NET_ADMIN)) diff --git a/net/ipv6/datagram.c b/net/ipv6/datagram.c index 0f0f94a40335..f7b535dec860 100644 --- a/net/ipv6/datagram.c +++ b/net/ipv6/datagram.c @@ -5,8 +5,6 @@ * Authors: * Pedro Roque <roque@di.fc.ul.pt> * - * $Id: datagram.c,v 1.24 2002/02/01 22:01:04 davem Exp $ - * * 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 diff --git a/net/ipv6/exthdrs.c b/net/ipv6/exthdrs.c index dcf94fdfb863..837c830d6d8e 100644 --- a/net/ipv6/exthdrs.c +++ b/net/ipv6/exthdrs.c @@ -7,8 +7,6 @@ * Andi Kleen <ak@muc.de> * Alexey Kuznetsov <kuznet@ms2.inr.ac.ru> * - * $Id: exthdrs.c,v 1.13 2001/06/19 15:58:56 davem Exp $ - * * 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 @@ -321,7 +319,7 @@ static int ipv6_rthdr_rcv(struct sk_buff *skb) int n, i; struct ipv6_rt_hdr *hdr; struct rt0_hdr *rthdr; - int accept_source_route = ipv6_devconf.accept_source_route; + int accept_source_route = dev_net(skb->dev)->ipv6.devconf_all->accept_source_route; idev = in6_dev_get(skb->dev); if (idev) { diff --git a/net/ipv6/icmp.c b/net/ipv6/icmp.c index d42dd16d3487..abedf95fdf2d 100644 --- a/net/ipv6/icmp.c +++ b/net/ipv6/icmp.c @@ -5,8 +5,6 @@ * Authors: * Pedro Roque <roque@di.fc.ul.pt> * - * $Id: icmp.c,v 1.38 2002/02/08 03:57:19 davem Exp $ - * * Based on net/ipv4/icmp.c * * RFC 1885 @@ -956,7 +954,8 @@ ctl_table ipv6_icmp_table_template[] = { .data = &init_net.ipv6.sysctl.icmpv6_time, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec + .proc_handler = &proc_dointvec_ms_jiffies, + .strategy = &sysctl_ms_jiffies }, { .ctl_name = 0 }, }; diff --git a/net/ipv6/inet6_hashtables.c b/net/ipv6/inet6_hashtables.c index 580014aea4d6..00a8a5f9380c 100644 --- a/net/ipv6/inet6_hashtables.c +++ b/net/ipv6/inet6_hashtables.c @@ -68,7 +68,7 @@ struct sock *__inet6_lookup_established(struct net *net, /* Optimize here for direct hit, only listening connections can * have wildcards anyways. */ - unsigned int hash = inet6_ehashfn(daddr, hnum, saddr, sport); + unsigned int hash = inet6_ehashfn(net, daddr, hnum, saddr, sport); struct inet_ehash_bucket *head = inet_ehash_bucket(hashinfo, hash); rwlock_t *lock = inet_ehash_lockp(hashinfo, hash); @@ -104,7 +104,8 @@ struct sock *inet6_lookup_listener(struct net *net, int score, hiscore = 0; read_lock(&hashinfo->lhash_lock); - sk_for_each(sk, node, &hashinfo->listening_hash[inet_lhashfn(hnum)]) { + sk_for_each(sk, node, + &hashinfo->listening_hash[inet_lhashfn(net, hnum)]) { if (net_eq(sock_net(sk), net) && inet_sk(sk)->num == hnum && sk->sk_family == PF_INET6) { const struct ipv6_pinfo *np = inet6_sk(sk); @@ -165,14 +166,14 @@ static int __inet6_check_established(struct inet_timewait_death_row *death_row, const struct in6_addr *saddr = &np->daddr; const int dif = sk->sk_bound_dev_if; const __portpair ports = INET_COMBINED_PORTS(inet->dport, lport); - const unsigned int hash = inet6_ehashfn(daddr, lport, saddr, + struct net *net = sock_net(sk); + const unsigned int hash = inet6_ehashfn(net, daddr, lport, saddr, inet->dport); struct inet_ehash_bucket *head = inet_ehash_bucket(hinfo, hash); rwlock_t *lock = inet_ehash_lockp(hinfo, hash); struct sock *sk2; const struct hlist_node *node; struct inet_timewait_sock *tw; - struct net *net = sock_net(sk); prefetch(head->chain.first); write_lock(lock); @@ -209,11 +210,11 @@ unique: if (twp != NULL) { *twp = tw; - NET_INC_STATS_BH(LINUX_MIB_TIMEWAITRECYCLED); + NET_INC_STATS_BH(twsk_net(tw), LINUX_MIB_TIMEWAITRECYCLED); } else if (tw != NULL) { /* Silly. Should hash-dance instead... */ inet_twsk_deschedule(tw, death_row); - NET_INC_STATS_BH(LINUX_MIB_TIMEWAITRECYCLED); + NET_INC_STATS_BH(twsk_net(tw), LINUX_MIB_TIMEWAITRECYCLED); inet_twsk_put(tw); } diff --git a/net/ipv6/ip6_fib.c b/net/ipv6/ip6_fib.c index 1ee4fa17c129..4de2b9efcacb 100644 --- a/net/ipv6/ip6_fib.c +++ b/net/ipv6/ip6_fib.c @@ -5,8 +5,6 @@ * Authors: * Pedro Roque <roque@di.fc.ul.pt> * - * $Id: ip6_fib.c,v 1.25 2001/10/31 21:55:55 davem Exp $ - * * 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 diff --git a/net/ipv6/ip6_input.c b/net/ipv6/ip6_input.c index 17eb48b8e329..7e14cccd0561 100644 --- a/net/ipv6/ip6_input.c +++ b/net/ipv6/ip6_input.c @@ -6,8 +6,6 @@ * Pedro Roque <roque@di.fc.ul.pt> * Ian P. Morris <I.P.Morris@soton.ac.uk> * - * $Id: ip6_input.c,v 1.19 2000/12/13 18:31:50 davem Exp $ - * * Based in linux/net/ipv4/ip_input.c * * This program is free software; you can redistribute it and/or @@ -73,7 +71,8 @@ int ipv6_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt IP6_INC_STATS_BH(idev, IPSTATS_MIB_INRECEIVES); - if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL) { + if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL || + !idev || unlikely(idev->cnf.disable_ipv6)) { IP6_INC_STATS_BH(idev, IPSTATS_MIB_INDISCARDS); rcu_read_unlock(); goto out; @@ -250,7 +249,7 @@ int ip6_mc_input(struct sk_buff *skb) /* * IPv6 multicast router mode is now supported ;) */ - if (ipv6_devconf.mc_forwarding && + if (dev_net(skb->dev)->ipv6.devconf_all->mc_forwarding && likely(!(IP6CB(skb)->flags & IP6SKB_FORWARDED))) { /* * Okay, we try to forward - split and duplicate diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index 48cdce9c696c..6407c64ea4a5 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c @@ -5,8 +5,6 @@ * Authors: * Pedro Roque <roque@di.fc.ul.pt> * - * $Id: ip6_output.c,v 1.34 2002/02/01 22:01:04 davem Exp $ - * * Based on linux/net/ipv4/ip_output.c * * This program is free software; you can redistribute it and/or @@ -175,6 +173,13 @@ static inline int ip6_skb_dst_mtu(struct sk_buff *skb) int ip6_output(struct sk_buff *skb) { + struct inet6_dev *idev = ip6_dst_idev(skb->dst); + if (unlikely(idev->cnf.disable_ipv6)) { + IP6_INC_STATS(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)) return ip6_fragment(skb, ip6_output2); @@ -406,9 +411,12 @@ int ip6_forward(struct sk_buff *skb) struct inet6_skb_parm *opt = IP6CB(skb); struct net *net = dev_net(dst->dev); - if (ipv6_devconf.forwarding == 0) + if (net->ipv6.devconf_all->forwarding == 0) goto error; + if (skb_warn_if_lro(skb)) + goto drop; + if (!xfrm6_policy_check(NULL, XFRM_POLICY_FWD, skb)) { IP6_INC_STATS(ip6_dst_idev(dst), IPSTATS_MIB_INDISCARDS); goto drop; @@ -450,7 +458,7 @@ int ip6_forward(struct sk_buff *skb) } /* XXX: idev->cnf.proxy_ndp? */ - if (ipv6_devconf.proxy_ndp && + if (net->ipv6.devconf_all->proxy_ndp && pneigh_lookup(&nd_tbl, net, &hdr->daddr, skb->dev, 0)) { int proxied = ip6_forward_proxy_check(skb); if (proxied > 0) @@ -497,7 +505,8 @@ int ip6_forward(struct sk_buff *skb) int addrtype = ipv6_addr_type(&hdr->saddr); /* This check is security critical. */ - if (addrtype & (IPV6_ADDR_MULTICAST|IPV6_ADDR_LOOPBACK)) + if (addrtype == IPV6_ADDR_ANY || + addrtype & (IPV6_ADDR_MULTICAST | IPV6_ADDR_LOOPBACK)) goto error; if (addrtype & IPV6_ADDR_LINKLOCAL) { icmpv6_send(skb, ICMPV6_DEST_UNREACH, diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c index 2bda3ba100b1..17c7b098cdb0 100644 --- a/net/ipv6/ip6_tunnel.c +++ b/net/ipv6/ip6_tunnel.c @@ -6,8 +6,6 @@ * Ville Nuorvala <vnuorval@tcs.hut.fi> * Yasuyuki Kozakai <kozakai@linux-ipv6.org> * - * $Id$ - * * Based on: * linux/net/ipv6/sit.c and linux/net/ipv4/ipip.c * @@ -711,7 +709,7 @@ static int ip6_tnl_rcv(struct sk_buff *skb, __u16 protocol, } if (!ip6_tnl_rcv_ctl(t)) { - t->stat.rx_dropped++; + t->dev->stats.rx_dropped++; read_unlock(&ip6_tnl_lock); goto discard; } @@ -728,8 +726,8 @@ static int ip6_tnl_rcv(struct sk_buff *skb, __u16 protocol, dscp_ecn_decapsulate(t, ipv6h, skb); - t->stat.rx_packets++; - t->stat.rx_bytes += skb->len; + t->dev->stats.rx_packets++; + t->dev->stats.rx_bytes += skb->len; netif_rx(skb); read_unlock(&ip6_tnl_lock); return 0; @@ -849,7 +847,7 @@ static int ip6_tnl_xmit2(struct sk_buff *skb, __u32 *pmtu) { struct ip6_tnl *t = netdev_priv(dev); - struct net_device_stats *stats = &t->stat; + struct net_device_stats *stats = &t->dev->stats; struct ipv6hdr *ipv6h = ipv6_hdr(skb); struct ipv6_tel_txoption opt; struct dst_entry *dst; @@ -1043,11 +1041,11 @@ static int ip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev) { struct ip6_tnl *t = netdev_priv(dev); - struct net_device_stats *stats = &t->stat; + struct net_device_stats *stats = &t->dev->stats; int ret; if (t->recursion++) { - t->stat.collisions++; + stats->collisions++; goto tx_err; } @@ -1289,19 +1287,6 @@ ip6_tnl_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) } /** - * ip6_tnl_get_stats - return the stats for tunnel device - * @dev: virtual device associated with tunnel - * - * Return: stats for device - **/ - -static struct net_device_stats * -ip6_tnl_get_stats(struct net_device *dev) -{ - return &(((struct ip6_tnl *)netdev_priv(dev))->stat); -} - -/** * ip6_tnl_change_mtu - change mtu manually for tunnel device * @dev: virtual device associated with tunnel * @new_mtu: the new mtu @@ -1334,7 +1319,6 @@ static void ip6_tnl_dev_setup(struct net_device *dev) dev->uninit = ip6_tnl_dev_uninit; dev->destructor = free_netdev; dev->hard_start_xmit = ip6_tnl_xmit; - dev->get_stats = ip6_tnl_get_stats; dev->do_ioctl = ip6_tnl_ioctl; dev->change_mtu = ip6_tnl_change_mtu; diff --git a/net/ipv6/ip6mr.c b/net/ipv6/ip6mr.c index 14796181e8b5..095bc453ff4c 100644 --- a/net/ipv6/ip6mr.c +++ b/net/ipv6/ip6mr.c @@ -388,8 +388,8 @@ static int pim6_rcv(struct sk_buff *skb) skb->ip_summed = 0; skb->pkt_type = PACKET_HOST; dst_release(skb->dst); - ((struct net_device_stats *)netdev_priv(reg_dev))->rx_bytes += skb->len; - ((struct net_device_stats *)netdev_priv(reg_dev))->rx_packets++; + reg_dev->stats.rx_bytes += skb->len; + reg_dev->stats.rx_packets++; skb->dst = NULL; nf_reset(skb); netif_rx(skb); @@ -409,26 +409,20 @@ static struct inet6_protocol pim6_protocol = { static int reg_vif_xmit(struct sk_buff *skb, struct net_device *dev) { read_lock(&mrt_lock); - ((struct net_device_stats *)netdev_priv(dev))->tx_bytes += skb->len; - ((struct net_device_stats *)netdev_priv(dev))->tx_packets++; + dev->stats.tx_bytes += skb->len; + dev->stats.tx_packets++; ip6mr_cache_report(skb, reg_vif_num, MRT6MSG_WHOLEPKT); read_unlock(&mrt_lock); kfree_skb(skb); return 0; } -static struct net_device_stats *reg_vif_get_stats(struct net_device *dev) -{ - return (struct net_device_stats *)netdev_priv(dev); -} - static void reg_vif_setup(struct net_device *dev) { dev->type = ARPHRD_PIMREG; dev->mtu = 1500 - sizeof(struct ipv6hdr) - 8; dev->flags = IFF_NOARP; dev->hard_start_xmit = reg_vif_xmit; - dev->get_stats = reg_vif_get_stats; dev->destructor = free_netdev; } @@ -436,9 +430,7 @@ static struct net_device *ip6mr_reg_vif(void) { struct net_device *dev; - dev = alloc_netdev(sizeof(struct net_device_stats), "pim6reg", - reg_vif_setup); - + dev = alloc_netdev(0, "pim6reg", reg_vif_setup); if (dev == NULL) return NULL; @@ -451,6 +443,7 @@ static struct net_device *ip6mr_reg_vif(void) if (dev_open(dev)) goto failure; + dev_hold(dev); return dev; failure: @@ -603,6 +596,7 @@ static int mif6_add(struct mif6ctl *vifc, int mrtsock) int vifi = vifc->mif6c_mifi; struct mif_device *v = &vif6_table[vifi]; struct net_device *dev; + int err; /* Is vif busy ? */ if (MIF_EXISTS(vifi)) @@ -620,20 +614,28 @@ static int mif6_add(struct mif6ctl *vifc, int mrtsock) dev = ip6mr_reg_vif(); if (!dev) return -ENOBUFS; + err = dev_set_allmulti(dev, 1); + if (err) { + unregister_netdevice(dev); + dev_put(dev); + return err; + } break; #endif case 0: dev = dev_get_by_index(&init_net, vifc->mif6c_pifi); if (!dev) return -EADDRNOTAVAIL; - dev_put(dev); + err = dev_set_allmulti(dev, 1); + if (err) { + dev_put(dev); + return err; + } break; default: return -EINVAL; } - dev_set_allmulti(dev, 1); - /* * Fill in the VIF structures */ @@ -652,7 +654,6 @@ static int mif6_add(struct mif6ctl *vifc, int mrtsock) /* And finish update writing critical data */ write_lock_bh(&mrt_lock); - dev_hold(dev); v->dev = dev; #ifdef CONFIG_IPV6_PIMSM_V2 if (v->flags & MIFF_REGISTER) @@ -934,7 +935,7 @@ static int ip6mr_device_event(struct notifier_block *this, struct mif_device *v; int ct; - if (dev_net(dev) != &init_net) + if (!net_eq(dev_net(dev), &init_net)) return NOTIFY_DONE; if (event != NETDEV_UNREGISTER) @@ -956,23 +957,51 @@ static struct notifier_block ip6_mr_notifier = { * Setup for IP multicast routing */ -void __init ip6_mr_init(void) +int __init ip6_mr_init(void) { + int err; + mrt_cachep = kmem_cache_create("ip6_mrt_cache", sizeof(struct mfc6_cache), 0, SLAB_HWCACHE_ALIGN, NULL); if (!mrt_cachep) - panic("cannot allocate ip6_mrt_cache"); + return -ENOMEM; setup_timer(&ipmr_expire_timer, ipmr_expire_process, 0); - register_netdevice_notifier(&ip6_mr_notifier); + err = register_netdevice_notifier(&ip6_mr_notifier); + if (err) + goto reg_notif_fail; +#ifdef CONFIG_PROC_FS + err = -ENOMEM; + if (!proc_net_fops_create(&init_net, "ip6_mr_vif", 0, &ip6mr_vif_fops)) + goto proc_vif_fail; + if (!proc_net_fops_create(&init_net, "ip6_mr_cache", + 0, &ip6mr_mfc_fops)) + goto proc_cache_fail; +#endif + return 0; +reg_notif_fail: + kmem_cache_destroy(mrt_cachep); #ifdef CONFIG_PROC_FS - proc_net_fops_create(&init_net, "ip6_mr_vif", 0, &ip6mr_vif_fops); - proc_net_fops_create(&init_net, "ip6_mr_cache", 0, &ip6mr_mfc_fops); +proc_vif_fail: + unregister_netdevice_notifier(&ip6_mr_notifier); +proc_cache_fail: + proc_net_remove(&init_net, "ip6_mr_vif"); #endif + return err; } +void ip6_mr_cleanup(void) +{ +#ifdef CONFIG_PROC_FS + proc_net_remove(&init_net, "ip6_mr_cache"); + proc_net_remove(&init_net, "ip6_mr_vif"); +#endif + unregister_netdevice_notifier(&ip6_mr_notifier); + del_timer(&ipmr_expire_timer); + kmem_cache_destroy(mrt_cachep); +} static int ip6mr_mfc_add(struct mf6cctl *mfc, int mrtsock) { @@ -1248,7 +1277,7 @@ int ip6_mroute_setsockopt(struct sock *sk, int optname, char __user *optval, int #endif /* - * Spurious command, or MRT_VERSION which you cannot + * Spurious command, or MRT6_VERSION which you cannot * set. */ default: @@ -1377,8 +1406,8 @@ static int ip6mr_forward2(struct sk_buff *skb, struct mfc6_cache *c, int vifi) if (vif->flags & MIFF_REGISTER) { vif->pkt_out++; vif->bytes_out += skb->len; - ((struct net_device_stats *)netdev_priv(vif->dev))->tx_bytes += skb->len; - ((struct net_device_stats *)netdev_priv(vif->dev))->tx_packets++; + vif->dev->stats.tx_bytes += skb->len; + vif->dev->stats.tx_packets++; ip6mr_cache_report(skb, vifi, MRT6MSG_WHOLEPKT); kfree_skb(skb); return 0; diff --git a/net/ipv6/ipv6_sockglue.c b/net/ipv6/ipv6_sockglue.c index 86e28a75267f..ea33b26512c2 100644 --- a/net/ipv6/ipv6_sockglue.c +++ b/net/ipv6/ipv6_sockglue.c @@ -7,8 +7,6 @@ * * Based on linux/net/ipv4/ip_sockglue.c * - * $Id: ipv6_sockglue.c,v 1.41 2002/02/01 22:01:04 davem Exp $ - * * 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 @@ -61,7 +59,7 @@ DEFINE_SNMP_STAT(struct ipstats_mib, ipv6_statistics) __read_mostly; struct ip6_ra_chain *ip6_ra_chain; DEFINE_RWLOCK(ip6_ra_lock); -int ip6_ra_control(struct sock *sk, int sel, void (*destructor)(struct sock *)) +int ip6_ra_control(struct sock *sk, int sel) { struct ip6_ra_chain *ra, *new_ra, **rap; @@ -83,8 +81,6 @@ int ip6_ra_control(struct sock *sk, int sel, void (*destructor)(struct sock *)) *rap = ra->next; write_unlock_bh(&ip6_ra_lock); - if (ra->destructor) - ra->destructor(sk); sock_put(sk); kfree(ra); return 0; @@ -96,7 +92,6 @@ int ip6_ra_control(struct sock *sk, int sel, void (*destructor)(struct sock *)) } new_ra->sk = sk; new_ra->sel = sel; - new_ra->destructor = destructor; new_ra->next = ra; *rap = new_ra; sock_hold(sk); @@ -634,7 +629,7 @@ done: case IPV6_ROUTER_ALERT: if (optlen < sizeof(int)) goto e_inval; - retv = ip6_ra_control(sk, val, NULL); + retv = ip6_ra_control(sk, val); break; case IPV6_MTU_DISCOVER: if (optlen < sizeof(int)) @@ -1043,7 +1038,7 @@ static int do_ipv6_getsockopt(struct sock *sk, int level, int optname, dst_release(dst); } if (val < 0) - val = ipv6_devconf.hop_limit; + val = sock_net(sk)->ipv6.devconf_all->hop_limit; break; } diff --git a/net/ipv6/mcast.c b/net/ipv6/mcast.c index fd632dd7f98d..e7c03bcc2788 100644 --- a/net/ipv6/mcast.c +++ b/net/ipv6/mcast.c @@ -5,8 +5,6 @@ * Authors: * Pedro Roque <roque@di.fc.ul.pt> * - * $Id: mcast.c,v 1.40 2002/02/08 03:57:19 davem Exp $ - * * Based on linux/ipv4/igmp.c and linux/ipv4/ip_sockglue.c * * This program is free software; you can redistribute it and/or @@ -153,7 +151,7 @@ static int ip6_mc_leave_src(struct sock *sk, struct ipv6_mc_socklist *iml, #define IGMP6_UNSOLICITED_IVAL (10*HZ) #define MLD_QRV_DEFAULT 2 -#define MLD_V1_SEEN(idev) (ipv6_devconf.force_mld_version == 1 || \ +#define MLD_V1_SEEN(idev) (dev_net((idev)->dev)->ipv6.devconf_all->force_mld_version == 1 || \ (idev)->cnf.force_mld_version == 1 || \ ((idev)->mc_v1_seen && \ time_before(jiffies, (idev)->mc_v1_seen))) @@ -164,7 +162,6 @@ static int ip6_mc_leave_src(struct sock *sk, struct ipv6_mc_socklist *iml, ((MLDV2_MASK(value, nbmant) | (1<<(nbmant))) << \ (MLDV2_MASK((value) >> (nbmant), nbexp) + (nbexp)))) -#define MLDV2_QQIC(value) MLDV2_EXP(0x80, 4, 3, value) #define MLDV2_MRC(value) MLDV2_EXP(0x8000, 12, 3, value) #define IPV6_MLD_MAX_MSF 64 @@ -370,10 +367,6 @@ int ip6_mc_source(int add, int omode, struct sock *sk, int pmclocked = 0; int err; - if (pgsr->gsr_group.ss_family != AF_INET6 || - pgsr->gsr_source.ss_family != AF_INET6) - return -EINVAL; - source = &((struct sockaddr_in6 *)&pgsr->gsr_source)->sin6_addr; group = &((struct sockaddr_in6 *)&pgsr->gsr_group)->sin6_addr; diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c index 282fdb31f8ed..beb48e3f038a 100644 --- a/net/ipv6/ndisc.c +++ b/net/ipv6/ndisc.c @@ -784,15 +784,17 @@ static void ndisc_recv_ns(struct sk_buff *skb) idev = ifp->idev; } else { + struct net *net = dev_net(dev); + idev = in6_dev_get(dev); if (!idev) { /* XXX: count this drop? */ return; } - if (ipv6_chk_acast_addr(dev_net(dev), dev, &msg->target) || + if (ipv6_chk_acast_addr(net, dev, &msg->target) || (idev->cnf.forwarding && - (ipv6_devconf.proxy_ndp || idev->cnf.proxy_ndp) && + (net->ipv6.devconf_all->proxy_ndp || idev->cnf.proxy_ndp) && (is_router = pndisc_is_router(&msg->target, dev)) >= 0)) { if (!(NEIGH_CB(skb)->flags & LOCALLY_ENQUEUED) && skb->pkt_type != PACKET_HOST && @@ -921,6 +923,7 @@ static void ndisc_recv_na(struct sk_buff *skb) if (neigh) { u8 old_flags = neigh->flags; + struct net *net = dev_net(dev); if (neigh->nud_state & NUD_FAILED) goto out; @@ -931,8 +934,8 @@ static void ndisc_recv_na(struct sk_buff *skb) * has already sent a NA to us. */ if (lladdr && !memcmp(lladdr, dev->dev_addr, dev->addr_len) && - ipv6_devconf.forwarding && ipv6_devconf.proxy_ndp && - pneigh_lookup(&nd_tbl, dev_net(dev), &msg->target, dev, 0)) { + net->ipv6.devconf_all->forwarding && net->ipv6.devconf_all->proxy_ndp && + pneigh_lookup(&nd_tbl, net, &msg->target, dev, 0)) { /* XXX: idev->cnf.prixy_ndp */ goto out; } diff --git a/net/ipv6/netfilter/Kconfig b/net/ipv6/netfilter/Kconfig index 6cae5475737e..689dec899c57 100644 --- a/net/ipv6/netfilter/Kconfig +++ b/net/ipv6/netfilter/Kconfig @@ -208,5 +208,17 @@ config IP6_NF_RAW If you want to compile it as a module, say M here and read <file:Documentation/kbuild/modules.txt>. If unsure, say `N'. +# security table for MAC policy +config IP6_NF_SECURITY + tristate "Security table" + depends on IP6_NF_IPTABLES + depends on SECURITY + default m if NETFILTER_ADVANCED=n + help + This option adds a `security' table to iptables, for use + with Mandatory Access Control (MAC) policy. + + If unsure, say N. + endmenu diff --git a/net/ipv6/netfilter/Makefile b/net/ipv6/netfilter/Makefile index fbf2c14ed887..3f17c948eefb 100644 --- a/net/ipv6/netfilter/Makefile +++ b/net/ipv6/netfilter/Makefile @@ -8,6 +8,7 @@ obj-$(CONFIG_IP6_NF_FILTER) += ip6table_filter.o obj-$(CONFIG_IP6_NF_MANGLE) += ip6table_mangle.o obj-$(CONFIG_IP6_NF_QUEUE) += ip6_queue.o obj-$(CONFIG_IP6_NF_RAW) += ip6table_raw.o +obj-$(CONFIG_IP6_NF_SECURITY) += ip6table_security.o # objects for l3 independent conntrack nf_conntrack_ipv6-objs := nf_conntrack_l3proto_ipv6.o nf_conntrack_proto_icmpv6.o nf_conntrack_reasm.o diff --git a/net/ipv6/netfilter/ip6_queue.c b/net/ipv6/netfilter/ip6_queue.c index 2eff3ae8977d..5859c046cbc4 100644 --- a/net/ipv6/netfilter/ip6_queue.c +++ b/net/ipv6/netfilter/ip6_queue.c @@ -159,7 +159,6 @@ ipq_build_packet_message(struct nf_queue_entry *entry, int *errp) case IPQ_COPY_META: case IPQ_COPY_NONE: size = NLMSG_SPACE(sizeof(*pmsg)); - data_len = 0; break; case IPQ_COPY_PACKET: @@ -226,8 +225,6 @@ ipq_build_packet_message(struct nf_queue_entry *entry, int *errp) return skb; nlmsg_failure: - if (skb) - kfree_skb(skb); *errp = -EINVAL; printk(KERN_ERR "ip6_queue: error creating packet message\n"); return NULL; @@ -483,7 +480,7 @@ ipq_rcv_dev_event(struct notifier_block *this, { struct net_device *dev = ptr; - if (dev_net(dev) != &init_net) + if (!net_eq(dev_net(dev), &init_net)) return NOTIFY_DONE; /* Drop any packets associated with the downed device */ diff --git a/net/ipv6/netfilter/ip6table_filter.c b/net/ipv6/netfilter/ip6table_filter.c index f979e48b469b..55a2c290bad4 100644 --- a/net/ipv6/netfilter/ip6table_filter.c +++ b/net/ipv6/netfilter/ip6table_filter.c @@ -61,13 +61,25 @@ static struct xt_table packet_filter = { /* The work comes in here from netfilter.c. */ static unsigned int -ip6t_hook(unsigned int hook, - struct sk_buff *skb, - const struct net_device *in, - const struct net_device *out, - int (*okfn)(struct sk_buff *)) +ip6t_local_in_hook(unsigned int hook, + struct sk_buff *skb, + const struct net_device *in, + const struct net_device *out, + int (*okfn)(struct sk_buff *)) +{ + return ip6t_do_table(skb, hook, in, out, + nf_local_in_net(in, out)->ipv6.ip6table_filter); +} + +static unsigned int +ip6t_forward_hook(unsigned int hook, + struct sk_buff *skb, + const struct net_device *in, + const struct net_device *out, + int (*okfn)(struct sk_buff *)) { - return ip6t_do_table(skb, hook, in, out, init_net.ipv6.ip6table_filter); + return ip6t_do_table(skb, hook, in, out, + nf_forward_net(in, out)->ipv6.ip6table_filter); } static unsigned int @@ -87,19 +99,20 @@ ip6t_local_out_hook(unsigned int hook, } #endif - return ip6t_do_table(skb, hook, in, out, init_net.ipv6.ip6table_filter); + return ip6t_do_table(skb, hook, in, out, + nf_local_out_net(in, out)->ipv6.ip6table_filter); } static struct nf_hook_ops ip6t_ops[] __read_mostly = { { - .hook = ip6t_hook, + .hook = ip6t_local_in_hook, .owner = THIS_MODULE, .pf = PF_INET6, .hooknum = NF_INET_LOCAL_IN, .priority = NF_IP6_PRI_FILTER, }, { - .hook = ip6t_hook, + .hook = ip6t_forward_hook, .owner = THIS_MODULE, .pf = PF_INET6, .hooknum = NF_INET_FORWARD, diff --git a/net/ipv6/netfilter/ip6table_security.c b/net/ipv6/netfilter/ip6table_security.c new file mode 100644 index 000000000000..a07abee30497 --- /dev/null +++ b/net/ipv6/netfilter/ip6table_security.c @@ -0,0 +1,172 @@ +/* + * "security" table for IPv6 + * + * This is for use by Mandatory Access Control (MAC) security models, + * which need to be able to manage security policy in separate context + * to DAC. + * + * Based on iptable_mangle.c + * + * Copyright (C) 1999 Paul `Rusty' Russell & Michael J. Neuling + * Copyright (C) 2000-2004 Netfilter Core Team <coreteam <at> netfilter.org> + * Copyright (C) 2008 Red Hat, Inc., James Morris <jmorris <at> redhat.com> + * + * 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 <linux/module.h> +#include <linux/netfilter_ipv6/ip6_tables.h> + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("James Morris <jmorris <at> redhat.com>"); +MODULE_DESCRIPTION("ip6tables security table, for MAC rules"); + +#define SECURITY_VALID_HOOKS (1 << NF_INET_LOCAL_IN) | \ + (1 << NF_INET_FORWARD) | \ + (1 << NF_INET_LOCAL_OUT) + +static struct +{ + struct ip6t_replace repl; + struct ip6t_standard entries[3]; + struct ip6t_error term; +} initial_table __initdata = { + .repl = { + .name = "security", + .valid_hooks = SECURITY_VALID_HOOKS, + .num_entries = 4, + .size = sizeof(struct ip6t_standard) * 3 + sizeof(struct ip6t_error), + .hook_entry = { + [NF_INET_LOCAL_IN] = 0, + [NF_INET_FORWARD] = sizeof(struct ip6t_standard), + [NF_INET_LOCAL_OUT] = sizeof(struct ip6t_standard) * 2, + }, + .underflow = { + [NF_INET_LOCAL_IN] = 0, + [NF_INET_FORWARD] = sizeof(struct ip6t_standard), + [NF_INET_LOCAL_OUT] = sizeof(struct ip6t_standard) * 2, + }, + }, + .entries = { + IP6T_STANDARD_INIT(NF_ACCEPT), /* LOCAL_IN */ + IP6T_STANDARD_INIT(NF_ACCEPT), /* FORWARD */ + IP6T_STANDARD_INIT(NF_ACCEPT), /* LOCAL_OUT */ + }, + .term = IP6T_ERROR_INIT, /* ERROR */ +}; + +static struct xt_table security_table = { + .name = "security", + .valid_hooks = SECURITY_VALID_HOOKS, + .lock = __RW_LOCK_UNLOCKED(security_table.lock), + .me = THIS_MODULE, + .af = AF_INET6, +}; + +static unsigned int +ip6t_local_in_hook(unsigned int hook, + struct sk_buff *skb, + const struct net_device *in, + const struct net_device *out, + int (*okfn)(struct sk_buff *)) +{ + return ip6t_do_table(skb, hook, in, out, + nf_local_in_net(in, out)->ipv6.ip6table_security); +} + +static unsigned int +ip6t_forward_hook(unsigned int hook, + struct sk_buff *skb, + const struct net_device *in, + const struct net_device *out, + int (*okfn)(struct sk_buff *)) +{ + return ip6t_do_table(skb, hook, in, out, + nf_forward_net(in, out)->ipv6.ip6table_security); +} + +static unsigned int +ip6t_local_out_hook(unsigned int hook, + struct sk_buff *skb, + const struct net_device *in, + const struct net_device *out, + int (*okfn)(struct sk_buff *)) +{ + /* TBD: handle short packets via raw socket */ + return ip6t_do_table(skb, hook, in, out, + nf_local_out_net(in, out)->ipv6.ip6table_security); +} + +static struct nf_hook_ops ip6t_ops[] __read_mostly = { + { + .hook = ip6t_local_in_hook, + .owner = THIS_MODULE, + .pf = PF_INET6, + .hooknum = NF_INET_LOCAL_IN, + .priority = NF_IP6_PRI_SECURITY, + }, + { + .hook = ip6t_forward_hook, + .owner = THIS_MODULE, + .pf = PF_INET6, + .hooknum = NF_INET_FORWARD, + .priority = NF_IP6_PRI_SECURITY, + }, + { + .hook = ip6t_local_out_hook, + .owner = THIS_MODULE, + .pf = PF_INET6, + .hooknum = NF_INET_LOCAL_OUT, + .priority = NF_IP6_PRI_SECURITY, + }, +}; + +static int __net_init ip6table_security_net_init(struct net *net) +{ + net->ipv6.ip6table_security = + ip6t_register_table(net, &security_table, &initial_table.repl); + + if (IS_ERR(net->ipv6.ip6table_security)) + return PTR_ERR(net->ipv6.ip6table_security); + + return 0; +} + +static void __net_exit ip6table_security_net_exit(struct net *net) +{ + ip6t_unregister_table(net->ipv6.ip6table_security); +} + +static struct pernet_operations ip6table_security_net_ops = { + .init = ip6table_security_net_init, + .exit = ip6table_security_net_exit, +}; + +static int __init ip6table_security_init(void) +{ + int ret; + + ret = register_pernet_subsys(&ip6table_security_net_ops); + if (ret < 0) + return ret; + + ret = nf_register_hooks(ip6t_ops, ARRAY_SIZE(ip6t_ops)); + if (ret < 0) + goto cleanup_table; + + return ret; + +cleanup_table: + unregister_pernet_subsys(&ip6table_security_net_ops); + return ret; +} + +static void __exit ip6table_security_fini(void) +{ + nf_unregister_hooks(ip6t_ops, ARRAY_SIZE(ip6t_ops)); + unregister_pernet_subsys(&ip6table_security_net_ops); +} + +module_init(ip6table_security_init); +module_exit(ip6table_security_fini); diff --git a/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c b/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c index ee713b03e9ec..14d47d833545 100644 --- a/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c +++ b/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c @@ -89,9 +89,8 @@ static int icmpv6_packet(struct nf_conn *ct, 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) - && del_timer(&ct->timeout)) - ct->timeout.function((unsigned long)ct); + if (atomic_dec_and_test(&ct->proto.icmp.count)) + nf_ct_kill_acct(ct, ctinfo, skb); } else { atomic_inc(&ct->proto.icmp.count); nf_conntrack_event_cache(IPCT_PROTOINFO_VOLATILE, skb); diff --git a/net/ipv6/proc.c b/net/ipv6/proc.c index df0736a4cafa..f82f6074cf85 100644 --- a/net/ipv6/proc.c +++ b/net/ipv6/proc.c @@ -7,8 +7,6 @@ * PROC file system. This is very similar to the IPv4 version, * except it reports the sockets in the INET6 address family. * - * Version: $Id: proc.c,v 1.17 2002/02/01 22:01:04 davem Exp $ - * * Authors: David S. Miller (davem@caip.rutgers.edu) * YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org> * @@ -185,32 +183,7 @@ static int snmp6_seq_show(struct seq_file *seq, void *v) static int sockstat6_seq_open(struct inode *inode, struct file *file) { - int err; - struct net *net; - - err = -ENXIO; - net = get_proc_net(inode); - if (net == NULL) - goto err_net; - - err = single_open(file, sockstat6_seq_show, net); - if (err < 0) - goto err_open; - - return 0; - -err_open: - put_net(net); -err_net: - return err; -} - -static int sockstat6_seq_release(struct inode *inode, struct file *file) -{ - struct net *net = ((struct seq_file *)file->private_data)->private; - - put_net(net); - return single_release(inode, file); + return single_open_net(inode, file, sockstat6_seq_show); } static const struct file_operations sockstat6_seq_fops = { @@ -218,7 +191,7 @@ static const struct file_operations sockstat6_seq_fops = { .open = sockstat6_seq_open, .read = seq_read, .llseek = seq_lseek, - .release = sockstat6_seq_release, + .release = single_release_net, }; static int snmp6_seq_open(struct inode *inode, struct file *file) @@ -241,7 +214,7 @@ int snmp6_register_dev(struct inet6_dev *idev) if (!idev || !idev->dev) return -EINVAL; - if (dev_net(idev->dev) != &init_net) + if (!net_eq(dev_net(idev->dev), &init_net)) return 0; if (!proc_net_devsnmp6) diff --git a/net/ipv6/protocol.c b/net/ipv6/protocol.c index f929f47b925e..9ab789159913 100644 --- a/net/ipv6/protocol.c +++ b/net/ipv6/protocol.c @@ -5,8 +5,6 @@ * * PF_INET6 protocol dispatch tables. * - * Version: $Id: protocol.c,v 1.10 2001/05/18 02:25:49 davem Exp $ - * * Authors: Pedro Roque <roque@di.fc.ul.pt> * * This program is free software; you can redistribute it and/or diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c index 3aee12310d94..01d47674f7e5 100644 --- a/net/ipv6/raw.c +++ b/net/ipv6/raw.c @@ -7,8 +7,6 @@ * * Adapted from linux/net/ipv4/raw.c * - * $Id: raw.c,v 1.51 2002/02/01 22:01:04 davem Exp $ - * * Fixes: * Hideaki YOSHIFUJI : sin6_scope_id support * YOSHIFUJI,H.@USAGI : raw checksum (RFC2292(bis) compliance) @@ -1159,18 +1157,18 @@ static int rawv6_ioctl(struct sock *sk, int cmd, unsigned long arg) static void rawv6_close(struct sock *sk, long timeout) { if (inet_sk(sk)->num == IPPROTO_RAW) - ip6_ra_control(sk, -1, NULL); + ip6_ra_control(sk, -1); ip6mr_sk_done(sk); sk_common_release(sk); } -static int raw6_destroy(struct sock *sk) +static void raw6_destroy(struct sock *sk) { lock_sock(sk); ip6_flush_pending_frames(sk); release_sock(sk); - return inet6_destroy_sock(sk); + inet6_destroy_sock(sk); } static int rawv6_init_sk(struct sock *sk) @@ -1253,7 +1251,7 @@ static int raw6_seq_show(struct seq_file *seq, void *v) "local_address " "remote_address " "st tx_queue rx_queue tr tm->when retrnsmt" - " uid timeout inode drops\n"); + " uid timeout inode ref pointer drops\n"); else raw6_sock_seq_show(seq, v, raw_seq_private(seq)->bucket); return 0; diff --git a/net/ipv6/reassembly.c b/net/ipv6/reassembly.c index a60d7d129713..6ab957ec2dd6 100644 --- a/net/ipv6/reassembly.c +++ b/net/ipv6/reassembly.c @@ -5,8 +5,6 @@ * Authors: * Pedro Roque <roque@di.fc.ul.pt> * - * $Id: reassembly.c,v 1.26 2001/03/07 22:00:57 davem Exp $ - * * Based on: net/ipv4/ip_fragment.c * * This program is free software; you can redistribute it and/or @@ -634,7 +632,7 @@ static struct inet6_protocol frag_protocol = }; #ifdef CONFIG_SYSCTL -static struct ctl_table ip6_frags_ctl_table[] = { +static struct ctl_table ip6_frags_ns_ctl_table[] = { { .ctl_name = NET_IPV6_IP6FRAG_HIGH_THRESH, .procname = "ip6frag_high_thresh", @@ -660,6 +658,10 @@ static struct ctl_table ip6_frags_ctl_table[] = { .proc_handler = &proc_dointvec_jiffies, .strategy = &sysctl_jiffies, }, + { } +}; + +static struct ctl_table ip6_frags_ctl_table[] = { { .ctl_name = NET_IPV6_IP6FRAG_SECRET_INTERVAL, .procname = "ip6frag_secret_interval", @@ -672,21 +674,20 @@ static struct ctl_table ip6_frags_ctl_table[] = { { } }; -static int ip6_frags_sysctl_register(struct net *net) +static int ip6_frags_ns_sysctl_register(struct net *net) { struct ctl_table *table; struct ctl_table_header *hdr; - table = ip6_frags_ctl_table; + table = ip6_frags_ns_ctl_table; if (net != &init_net) { - table = kmemdup(table, sizeof(ip6_frags_ctl_table), GFP_KERNEL); + table = kmemdup(table, sizeof(ip6_frags_ns_ctl_table), GFP_KERNEL); if (table == NULL) goto err_alloc; table[0].data = &net->ipv6.frags.high_thresh; table[1].data = &net->ipv6.frags.low_thresh; table[2].data = &net->ipv6.frags.timeout; - table[3].mode &= ~0222; } hdr = register_net_sysctl_table(net, net_ipv6_ctl_path, table); @@ -703,7 +704,7 @@ err_alloc: return -ENOMEM; } -static void ip6_frags_sysctl_unregister(struct net *net) +static void ip6_frags_ns_sysctl_unregister(struct net *net) { struct ctl_table *table; @@ -711,13 +712,36 @@ static void ip6_frags_sysctl_unregister(struct net *net) unregister_net_sysctl_table(net->ipv6.sysctl.frags_hdr); kfree(table); } + +static struct ctl_table_header *ip6_ctl_header; + +static int ip6_frags_sysctl_register(void) +{ + ip6_ctl_header = register_net_sysctl_rotable(net_ipv6_ctl_path, + ip6_frags_ctl_table); + return ip6_ctl_header == NULL ? -ENOMEM : 0; +} + +static void ip6_frags_sysctl_unregister(void) +{ + unregister_net_sysctl_table(ip6_ctl_header); +} #else -static inline int ip6_frags_sysctl_register(struct net *net) +static inline int ip6_frags_ns_sysctl_register(struct net *net) { return 0; } -static inline void ip6_frags_sysctl_unregister(struct net *net) +static inline void ip6_frags_ns_sysctl_unregister(struct net *net) +{ +} + +static inline int ip6_frags_sysctl_register(void) +{ + return 0; +} + +static inline void ip6_frags_sysctl_unregister(void) { } #endif @@ -730,12 +754,12 @@ static int ipv6_frags_init_net(struct net *net) inet_frags_init_net(&net->ipv6.frags); - return ip6_frags_sysctl_register(net); + return ip6_frags_ns_sysctl_register(net); } static void ipv6_frags_exit_net(struct net *net) { - ip6_frags_sysctl_unregister(net); + ip6_frags_ns_sysctl_unregister(net); inet_frags_exit_net(&net->ipv6.frags, &ip6_frags); } @@ -752,7 +776,13 @@ int __init ipv6_frag_init(void) if (ret) goto out; - register_pernet_subsys(&ip6_frags_ops); + ret = ip6_frags_sysctl_register(); + if (ret) + goto err_sysctl; + + ret = register_pernet_subsys(&ip6_frags_ops); + if (ret) + goto err_pernet; ip6_frags.hashfn = ip6_hashfn; ip6_frags.constructor = ip6_frag_init; @@ -765,11 +795,18 @@ int __init ipv6_frag_init(void) inet_frags_init(&ip6_frags); out: return ret; + +err_pernet: + ip6_frags_sysctl_unregister(); +err_sysctl: + inet6_del_protocol(&frag_protocol, IPPROTO_FRAGMENT); + goto out; } void ipv6_frag_exit(void) { inet_frags_fini(&ip6_frags); + ip6_frags_sysctl_unregister(); unregister_pernet_subsys(&ip6_frags_ops); inet6_del_protocol(&frag_protocol, IPPROTO_FRAGMENT); } diff --git a/net/ipv6/route.c b/net/ipv6/route.c index 7ff687020fa9..615b328de251 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -5,8 +5,6 @@ * Authors: * Pedro Roque <roque@di.fc.ul.pt> * - * $Id: route.c,v 1.56 2001/10/31 21:55:55 davem Exp $ - * * 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 @@ -230,7 +228,7 @@ static __inline__ int rt6_check_expired(const struct rt6_info *rt) static inline int rt6_need_strict(struct in6_addr *daddr) { return (ipv6_addr_type(daddr) & - (IPV6_ADDR_MULTICAST | IPV6_ADDR_LINKLOCAL)); + (IPV6_ADDR_MULTICAST | IPV6_ADDR_LINKLOCAL | IPV6_ADDR_LOOPBACK)); } /* @@ -239,15 +237,20 @@ static inline int rt6_need_strict(struct in6_addr *daddr) static inline struct rt6_info *rt6_device_match(struct net *net, struct rt6_info *rt, + struct in6_addr *saddr, int oif, int flags) { struct rt6_info *local = NULL; struct rt6_info *sprt; - if (oif) { - for (sprt = rt; sprt; sprt = sprt->u.dst.rt6_next) { - struct net_device *dev = sprt->rt6i_dev; + if (!oif && ipv6_addr_any(saddr)) + goto out; + + for (sprt = rt; sprt; sprt = sprt->u.dst.rt6_next) { + struct net_device *dev = sprt->rt6i_dev; + + if (oif) { if (dev->ifindex == oif) return sprt; if (dev->flags & IFF_LOOPBACK) { @@ -261,14 +264,21 @@ static inline struct rt6_info *rt6_device_match(struct net *net, } local = sprt; } + } else { + if (ipv6_chk_addr(net, saddr, dev, + flags & RT6_LOOKUP_F_IFACE)) + return sprt; } + } + if (oif) { if (local) return local; if (flags & RT6_LOOKUP_F_IFACE) return net->ipv6.ip6_null_entry; } +out: return rt; } @@ -541,7 +551,7 @@ static struct rt6_info *ip6_pol_route_lookup(struct net *net, fn = fib6_lookup(&table->tb6_root, &fl->fl6_dst, &fl->fl6_src); restart: rt = fn->leaf; - rt = rt6_device_match(net, rt, fl->oif, flags); + rt = rt6_device_match(net, rt, &fl->fl6_src, fl->oif, flags); BACKTRACK(net, &fl->fl6_src); out: dst_use(&rt->u.dst, jiffies); @@ -666,7 +676,7 @@ static struct rt6_info *ip6_pol_route(struct net *net, struct fib6_table *table, int strict = 0; int attempts = 3; int err; - int reachable = ipv6_devconf.forwarding ? 0 : RT6_LOOKUP_F_REACHABLE; + int reachable = net->ipv6.devconf_all->forwarding ? 0 : RT6_LOOKUP_F_REACHABLE; strict |= flags & RT6_LOOKUP_F_IFACE; @@ -1048,7 +1058,7 @@ int ip6_dst_hoplimit(struct dst_entry *dst) hoplimit = idev->cnf.hop_limit; in6_dev_put(idev); } else - hoplimit = ipv6_devconf.hop_limit; + hoplimit = dev_net(dev)->ipv6.devconf_all->hop_limit; } return hoplimit; } @@ -2406,26 +2416,7 @@ static int ipv6_route_show(struct seq_file *m, void *v) static int ipv6_route_open(struct inode *inode, struct file *file) { - int err; - struct net *net = get_proc_net(inode); - if (!net) - return -ENXIO; - - err = single_open(file, ipv6_route_show, net); - if (err < 0) { - put_net(net); - return err; - } - - return 0; -} - -static int ipv6_route_release(struct inode *inode, struct file *file) -{ - struct seq_file *seq = file->private_data; - struct net *net = seq->private; - put_net(net); - return single_release(inode, file); + return single_open_net(inode, file, ipv6_route_show); } static const struct file_operations ipv6_route_proc_fops = { @@ -2433,7 +2424,7 @@ static const struct file_operations ipv6_route_proc_fops = { .open = ipv6_route_open, .read = seq_read, .llseek = seq_lseek, - .release = ipv6_route_release, + .release = single_release_net, }; static int rt6_stats_seq_show(struct seq_file *seq, void *v) @@ -2453,26 +2444,7 @@ static int rt6_stats_seq_show(struct seq_file *seq, void *v) static int rt6_stats_seq_open(struct inode *inode, struct file *file) { - int err; - struct net *net = get_proc_net(inode); - if (!net) - return -ENXIO; - - err = single_open(file, rt6_stats_seq_show, net); - if (err < 0) { - put_net(net); - return err; - } - - return 0; -} - -static int rt6_stats_seq_release(struct inode *inode, struct file *file) -{ - struct seq_file *seq = file->private_data; - struct net *net = (struct net *)seq->private; - put_net(net); - return single_release(inode, file); + return single_open_net(inode, file, rt6_stats_seq_show); } static const struct file_operations rt6_stats_seq_fops = { @@ -2480,7 +2452,7 @@ static const struct file_operations rt6_stats_seq_fops = { .open = rt6_stats_seq_open, .read = seq_read, .llseek = seq_lseek, - .release = rt6_stats_seq_release, + .release = single_release_net, }; #endif /* CONFIG_PROC_FS */ diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c index 32e871a6c25a..b7a50e968506 100644 --- a/net/ipv6/sit.c +++ b/net/ipv6/sit.c @@ -6,8 +6,6 @@ * Pedro Roque <roque@di.fc.ul.pt> * Alexey Kuznetsov <kuznet@ms2.inr.ac.ru> * - * $Id: sit.c,v 1.53 2001/09/25 05:09:53 davem Exp $ - * * 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 @@ -493,13 +491,13 @@ static int ipip6_rcv(struct sk_buff *skb) if ((tunnel->dev->priv_flags & IFF_ISATAP) && !isatap_chksrc(skb, iph, tunnel)) { - tunnel->stat.rx_errors++; + tunnel->dev->stats.rx_errors++; read_unlock(&ipip6_lock); kfree_skb(skb); return 0; } - tunnel->stat.rx_packets++; - tunnel->stat.rx_bytes += skb->len; + tunnel->dev->stats.rx_packets++; + tunnel->dev->stats.rx_bytes += skb->len; skb->dev = tunnel->dev; dst_release(skb->dst); skb->dst = NULL; @@ -539,7 +537,7 @@ static inline __be32 try_6to4(struct in6_addr *v6dst) static int ipip6_tunnel_xmit(struct sk_buff *skb, struct net_device *dev) { struct ip_tunnel *tunnel = netdev_priv(dev); - struct net_device_stats *stats = &tunnel->stat; + struct net_device_stats *stats = &tunnel->dev->stats; struct iphdr *tiph = &tunnel->parms.iph; struct ipv6hdr *iph6 = ipv6_hdr(skb); u8 tos = tunnel->parms.iph.tos; @@ -553,7 +551,7 @@ static int ipip6_tunnel_xmit(struct sk_buff *skb, struct net_device *dev) int addr_type; if (tunnel->recursion++) { - tunnel->stat.collisions++; + stats->collisions++; goto tx_error; } @@ -620,20 +618,20 @@ static int ipip6_tunnel_xmit(struct sk_buff *skb, struct net_device *dev) .oif = tunnel->parms.link, .proto = IPPROTO_IPV6 }; if (ip_route_output_key(dev_net(dev), &rt, &fl)) { - tunnel->stat.tx_carrier_errors++; + stats->tx_carrier_errors++; goto tx_error_icmp; } } if (rt->rt_type != RTN_UNICAST) { ip_rt_put(rt); - tunnel->stat.tx_carrier_errors++; + stats->tx_carrier_errors++; goto tx_error_icmp; } tdev = rt->u.dst.dev; if (tdev == dev) { ip_rt_put(rt); - tunnel->stat.collisions++; + stats->collisions++; goto tx_error; } @@ -643,7 +641,7 @@ static int ipip6_tunnel_xmit(struct sk_buff *skb, struct net_device *dev) mtu = skb->dst ? dst_mtu(skb->dst) : dev->mtu; if (mtu < 68) { - tunnel->stat.collisions++; + stats->collisions++; ip_rt_put(rt); goto tx_error; } @@ -920,11 +918,6 @@ done: return err; } -static struct net_device_stats *ipip6_tunnel_get_stats(struct net_device *dev) -{ - return &(((struct ip_tunnel*)netdev_priv(dev))->stat); -} - static int ipip6_tunnel_change_mtu(struct net_device *dev, int new_mtu) { if (new_mtu < IPV6_MIN_MTU || new_mtu > 0xFFF8 - sizeof(struct iphdr)) @@ -938,7 +931,6 @@ static void ipip6_tunnel_setup(struct net_device *dev) dev->uninit = ipip6_tunnel_uninit; dev->destructor = free_netdev; dev->hard_start_xmit = ipip6_tunnel_xmit; - dev->get_stats = ipip6_tunnel_get_stats; dev->do_ioctl = ipip6_tunnel_ioctl; dev->change_mtu = ipip6_tunnel_change_mtu; diff --git a/net/ipv6/syncookies.c b/net/ipv6/syncookies.c index 3ecc1157994e..6a68eeb7bbf8 100644 --- a/net/ipv6/syncookies.c +++ b/net/ipv6/syncookies.c @@ -137,7 +137,7 @@ __u32 cookie_v6_init_sequence(struct sock *sk, struct sk_buff *skb, __u16 *mssp) ; *mssp = msstab[mssind] + 1; - NET_INC_STATS_BH(LINUX_MIB_SYNCOOKIESSENT); + NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_SYNCOOKIESSENT); return secure_tcp_syn_cookie(&iph->saddr, &iph->daddr, th->source, th->dest, ntohl(th->seq), @@ -177,11 +177,11 @@ struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb) if (time_after(jiffies, tp->last_synq_overflow + TCP_TIMEOUT_INIT) || (mss = cookie_check(skb, cookie)) == 0) { - NET_INC_STATS_BH(LINUX_MIB_SYNCOOKIESFAILED); + NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_SYNCOOKIESFAILED); goto out; } - NET_INC_STATS_BH(LINUX_MIB_SYNCOOKIESRECV); + NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_SYNCOOKIESRECV); /* check for timestamp cookie support */ memset(&tcp_opt, 0, sizeof(tcp_opt)); diff --git a/net/ipv6/sysctl_net_ipv6.c b/net/ipv6/sysctl_net_ipv6.c index 3804dcbbfab0..5c99274558bf 100644 --- a/net/ipv6/sysctl_net_ipv6.c +++ b/net/ipv6/sysctl_net_ipv6.c @@ -37,6 +37,10 @@ static ctl_table ipv6_table_template[] = { .mode = 0644, .proc_handler = &proc_dointvec }, + { .ctl_name = 0 } +}; + +static ctl_table ipv6_table[] = { { .ctl_name = NET_IPV6_MLD_MAX_MSF, .procname = "mld_max_msf", @@ -80,12 +84,6 @@ static int ipv6_sysctl_net_init(struct net *net) ipv6_table[2].data = &net->ipv6.sysctl.bindv6only; - /* We don't want this value to be per namespace, it should be global - to all namespaces, so make it read-only when we are not in the - init network namespace */ - if (net != &init_net) - ipv6_table[3].mode = 0444; - net->ipv6.sysctl.table = register_net_sysctl_table(net, net_ipv6_ctl_path, ipv6_table); if (!net->ipv6.sysctl.table) @@ -126,12 +124,29 @@ static struct pernet_operations ipv6_sysctl_net_ops = { .exit = ipv6_sysctl_net_exit, }; +static struct ctl_table_header *ip6_header; + int ipv6_sysctl_register(void) { - return register_pernet_subsys(&ipv6_sysctl_net_ops); + int err = -ENOMEM;; + + ip6_header = register_net_sysctl_rotable(net_ipv6_ctl_path, ipv6_table); + if (ip6_header == NULL) + goto out; + + err = register_pernet_subsys(&ipv6_sysctl_net_ops); + if (err) + goto err_pernet; +out: + return err; + +err_pernet: + unregister_net_sysctl_table(ip6_header); + goto out; } void ipv6_sysctl_unregister(void) { + unregister_net_sysctl_table(ip6_header); unregister_pernet_subsys(&ipv6_sysctl_net_ops); } diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index 40ea9c36d24b..ae45f9835014 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -5,8 +5,6 @@ * Authors: * Pedro Roque <roque@di.fc.ul.pt> * - * $Id: tcp_ipv6.c,v 1.144 2002/02/01 22:01:04 davem Exp $ - * * Based on: * linux/net/ipv4/tcp.c * linux/net/ipv4/tcp_input.c @@ -72,8 +70,6 @@ static void tcp_v6_send_reset(struct sock *sk, struct sk_buff *skb); static void tcp_v6_reqsk_send_ack(struct sk_buff *skb, struct request_sock *req); -static void tcp_v6_send_check(struct sock *sk, int len, - struct sk_buff *skb); static int tcp_v6_do_rcv(struct sock *sk, struct sk_buff *skb); @@ -82,6 +78,12 @@ static struct inet_connection_sock_af_ops ipv6_specific; #ifdef CONFIG_TCP_MD5SIG static struct tcp_sock_af_ops tcp_sock_ipv6_specific; static struct tcp_sock_af_ops tcp_sock_ipv6_mapped_specific; +#else +static struct tcp_md5sig_key *tcp_v6_md5_do_lookup(struct sock *sk, + struct in6_addr *addr) +{ + return NULL; +} #endif static void tcp_v6_hash(struct sock *sk) @@ -321,8 +323,9 @@ static void tcp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, int err; struct tcp_sock *tp; __u32 seq; + struct net *net = dev_net(skb->dev); - sk = inet6_lookup(dev_net(skb->dev), &tcp_hashinfo, &hdr->daddr, + sk = inet6_lookup(net, &tcp_hashinfo, &hdr->daddr, th->dest, &hdr->saddr, th->source, skb->dev->ifindex); if (sk == NULL) { @@ -337,7 +340,7 @@ static void tcp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, bh_lock_sock(sk); if (sock_owned_by_user(sk)) - NET_INC_STATS_BH(LINUX_MIB_LOCKDROPPEDICMPS); + NET_INC_STATS_BH(net, LINUX_MIB_LOCKDROPPEDICMPS); if (sk->sk_state == TCP_CLOSE) goto out; @@ -346,7 +349,7 @@ static void tcp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, seq = ntohl(th->seq); if (sk->sk_state != TCP_LISTEN && !between(seq, tp->snd_una, tp->snd_nxt)) { - NET_INC_STATS_BH(LINUX_MIB_OUTOFWINDOWICMPS); + NET_INC_STATS_BH(net, LINUX_MIB_OUTOFWINDOWICMPS); goto out; } @@ -421,7 +424,7 @@ static void tcp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, BUG_TRAP(req->sk == NULL); if (seq != tcp_rsk(req)->snt_isn) { - NET_INC_STATS_BH(LINUX_MIB_OUTOFWINDOWICMPS); + NET_INC_STATS_BH(net, LINUX_MIB_OUTOFWINDOWICMPS); goto out; } @@ -733,109 +736,105 @@ static int tcp_v6_parse_md5_keys (struct sock *sk, char __user *optval, return tcp_v6_md5_do_add(sk, &sin6->sin6_addr, newkey, cmd.tcpm_keylen); } -static int tcp_v6_do_calc_md5_hash(char *md5_hash, struct tcp_md5sig_key *key, - struct in6_addr *saddr, - struct in6_addr *daddr, - struct tcphdr *th, int protocol, - unsigned int tcplen) +static int tcp_v6_md5_hash_pseudoheader(struct tcp_md5sig_pool *hp, + struct in6_addr *daddr, + struct in6_addr *saddr, int nbytes) { - struct scatterlist sg[4]; - __u16 data_len; - int block = 0; - __sum16 cksum; - struct tcp_md5sig_pool *hp; struct tcp6_pseudohdr *bp; - struct hash_desc *desc; - int err; - unsigned int nbytes = 0; + struct scatterlist sg; - hp = tcp_get_md5sig_pool(); - if (!hp) { - printk(KERN_WARNING "%s(): hash pool not found...\n", __func__); - goto clear_hash_noput; - } bp = &hp->md5_blk.ip6; - desc = &hp->md5_desc; - /* 1. TCP pseudo-header (RFC2460) */ ipv6_addr_copy(&bp->saddr, saddr); ipv6_addr_copy(&bp->daddr, daddr); - bp->len = htonl(tcplen); - bp->protocol = htonl(protocol); - - sg_init_table(sg, 4); - - sg_set_buf(&sg[block++], bp, sizeof(*bp)); - nbytes += sizeof(*bp); + bp->protocol = cpu_to_be32(IPPROTO_TCP); + bp->len = cpu_to_be16(nbytes); - /* 2. TCP header, excluding options */ - cksum = th->check; - th->check = 0; - sg_set_buf(&sg[block++], th, sizeof(*th)); - nbytes += sizeof(*th); - - /* 3. TCP segment data (if any) */ - data_len = tcplen - (th->doff << 2); - if (data_len > 0) { - u8 *data = (u8 *)th + (th->doff << 2); - sg_set_buf(&sg[block++], data, data_len); - nbytes += data_len; - } + sg_init_one(&sg, bp, sizeof(*bp)); + return crypto_hash_update(&hp->md5_desc, &sg, sizeof(*bp)); +} - /* 4. shared key */ - sg_set_buf(&sg[block++], key->key, key->keylen); - nbytes += key->keylen; +static int tcp_v6_md5_hash_hdr(char *md5_hash, struct tcp_md5sig_key *key, + struct in6_addr *daddr, struct in6_addr *saddr, + struct tcphdr *th) +{ + struct tcp_md5sig_pool *hp; + struct hash_desc *desc; - sg_mark_end(&sg[block - 1]); + hp = tcp_get_md5sig_pool(); + if (!hp) + goto clear_hash_noput; + desc = &hp->md5_desc; - /* Now store the hash into the packet */ - err = crypto_hash_init(desc); - if (err) { - printk(KERN_WARNING "%s(): hash_init failed\n", __func__); + if (crypto_hash_init(desc)) goto clear_hash; - } - err = crypto_hash_update(desc, sg, nbytes); - if (err) { - printk(KERN_WARNING "%s(): hash_update failed\n", __func__); + if (tcp_v6_md5_hash_pseudoheader(hp, daddr, saddr, th->doff << 2)) goto clear_hash; - } - err = crypto_hash_final(desc, md5_hash); - if (err) { - printk(KERN_WARNING "%s(): hash_final failed\n", __func__); + if (tcp_md5_hash_header(hp, th)) + goto clear_hash; + if (tcp_md5_hash_key(hp, key)) + goto clear_hash; + if (crypto_hash_final(desc, md5_hash)) goto clear_hash; - } - /* Reset header, and free up the crypto */ tcp_put_md5sig_pool(); - th->check = cksum; -out: return 0; + clear_hash: tcp_put_md5sig_pool(); clear_hash_noput: memset(md5_hash, 0, 16); - goto out; + return 1; } -static int tcp_v6_calc_md5_hash(char *md5_hash, struct tcp_md5sig_key *key, - struct sock *sk, - struct dst_entry *dst, - struct request_sock *req, - struct tcphdr *th, int protocol, - unsigned int tcplen) +static int tcp_v6_md5_hash_skb(char *md5_hash, struct tcp_md5sig_key *key, + struct sock *sk, struct request_sock *req, + struct sk_buff *skb) { struct in6_addr *saddr, *daddr; + struct tcp_md5sig_pool *hp; + struct hash_desc *desc; + struct tcphdr *th = tcp_hdr(skb); if (sk) { saddr = &inet6_sk(sk)->saddr; daddr = &inet6_sk(sk)->daddr; - } else { + } else if (req) { saddr = &inet6_rsk(req)->loc_addr; daddr = &inet6_rsk(req)->rmt_addr; + } else { + struct ipv6hdr *ip6h = ipv6_hdr(skb); + saddr = &ip6h->saddr; + daddr = &ip6h->daddr; } - return tcp_v6_do_calc_md5_hash(md5_hash, key, - saddr, daddr, - th, protocol, tcplen); + + hp = tcp_get_md5sig_pool(); + if (!hp) + goto clear_hash_noput; + desc = &hp->md5_desc; + + if (crypto_hash_init(desc)) + goto clear_hash; + + if (tcp_v6_md5_hash_pseudoheader(hp, daddr, saddr, skb->len)) + goto clear_hash; + if (tcp_md5_hash_header(hp, th)) + goto clear_hash; + if (tcp_md5_hash_skb_data(hp, skb, th->doff << 2)) + goto clear_hash; + if (tcp_md5_hash_key(hp, key)) + goto clear_hash; + if (crypto_hash_final(desc, md5_hash)) + goto clear_hash; + + tcp_put_md5sig_pool(); + return 0; + +clear_hash: + tcp_put_md5sig_pool(); +clear_hash_noput: + memset(md5_hash, 0, 16); + return 1; } static int tcp_v6_inbound_md5_hash (struct sock *sk, struct sk_buff *skb) @@ -844,43 +843,12 @@ static int tcp_v6_inbound_md5_hash (struct sock *sk, struct sk_buff *skb) struct tcp_md5sig_key *hash_expected; struct ipv6hdr *ip6h = ipv6_hdr(skb); struct tcphdr *th = tcp_hdr(skb); - int length = (th->doff << 2) - sizeof (*th); int genhash; - u8 *ptr; u8 newhash[16]; hash_expected = tcp_v6_md5_do_lookup(sk, &ip6h->saddr); + hash_location = tcp_parse_md5sig_option(th); - /* If the TCP option is too short, we can short cut */ - if (length < TCPOLEN_MD5SIG) - return hash_expected ? 1 : 0; - - /* parse options */ - ptr = (u8*)(th + 1); - while (length > 0) { - int opcode = *ptr++; - int opsize; - - switch(opcode) { - case TCPOPT_EOL: - goto done_opts; - case TCPOPT_NOP: - length--; - continue; - default: - opsize = *ptr++; - if (opsize < 2 || opsize > length) - goto done_opts; - if (opcode == TCPOPT_MD5SIG) { - hash_location = ptr; - goto done_opts; - } - } - ptr += opsize - 2; - length -= opsize; - } - -done_opts: /* do we have a hash as expected? */ if (!hash_expected) { if (!hash_location) @@ -907,11 +875,10 @@ done_opts: } /* check the signature */ - genhash = tcp_v6_do_calc_md5_hash(newhash, - hash_expected, - &ip6h->saddr, &ip6h->daddr, - th, sk->sk_protocol, - skb->len); + genhash = tcp_v6_md5_hash_skb(newhash, + hash_expected, + NULL, NULL, skb); + if (genhash || memcmp(hash_location, newhash, 16) != 0) { if (net_ratelimit()) { printk(KERN_INFO "MD5 Hash %s for " @@ -1048,10 +1015,9 @@ static void tcp_v6_send_reset(struct sock *sk, struct sk_buff *skb) (TCPOPT_NOP << 16) | (TCPOPT_MD5SIG << 8) | TCPOLEN_MD5SIG); - tcp_v6_do_calc_md5_hash((__u8 *)&opt[1], key, - &ipv6_hdr(skb)->daddr, - &ipv6_hdr(skb)->saddr, - t1, IPPROTO_TCP, tot_len); + tcp_v6_md5_hash_hdr((__u8 *)&opt[1], key, + &ipv6_hdr(skb)->daddr, + &ipv6_hdr(skb)->saddr, t1); } #endif @@ -1079,8 +1045,8 @@ static void tcp_v6_send_reset(struct sock *sk, struct sk_buff *skb) if (xfrm_lookup(&buff->dst, &fl, NULL, 0) >= 0) { ip6_xmit(ctl_sk, buff, &fl, NULL, 0); - TCP_INC_STATS_BH(TCP_MIB_OUTSEGS); - TCP_INC_STATS_BH(TCP_MIB_OUTRSTS); + TCP_INC_STATS_BH(net, TCP_MIB_OUTSEGS); + TCP_INC_STATS_BH(net, TCP_MIB_OUTRSTS); return; } } @@ -1088,8 +1054,8 @@ static void tcp_v6_send_reset(struct sock *sk, struct sk_buff *skb) kfree_skb(buff); } -static void tcp_v6_send_ack(struct tcp_timewait_sock *tw, - struct sk_buff *skb, u32 seq, u32 ack, u32 win, u32 ts) +static void tcp_v6_send_ack(struct sk_buff *skb, u32 seq, u32 ack, u32 win, u32 ts, + struct tcp_md5sig_key *key) { struct tcphdr *th = tcp_hdr(skb), *t1; struct sk_buff *buff; @@ -1098,22 +1064,6 @@ static void tcp_v6_send_ack(struct tcp_timewait_sock *tw, struct sock *ctl_sk = net->ipv6.tcp_sk; unsigned int tot_len = sizeof(struct tcphdr); __be32 *topt; -#ifdef CONFIG_TCP_MD5SIG - struct tcp_md5sig_key *key; - struct tcp_md5sig_key tw_key; -#endif - -#ifdef CONFIG_TCP_MD5SIG - if (!tw && skb->sk) { - key = tcp_v6_md5_do_lookup(skb->sk, &ipv6_hdr(skb)->daddr); - } else if (tw && tw->tw_md5_keylen) { - tw_key.key = tw->tw_md5_key; - tw_key.keylen = tw->tw_md5_keylen; - key = &tw_key; - } else { - key = NULL; - } -#endif if (ts) tot_len += TCPOLEN_TSTAMP_ALIGNED; @@ -1154,10 +1104,9 @@ static void tcp_v6_send_ack(struct tcp_timewait_sock *tw, if (key) { *topt++ = htonl((TCPOPT_NOP << 24) | (TCPOPT_NOP << 16) | (TCPOPT_MD5SIG << 8) | TCPOLEN_MD5SIG); - tcp_v6_do_calc_md5_hash((__u8 *)topt, key, - &ipv6_hdr(skb)->daddr, - &ipv6_hdr(skb)->saddr, - t1, IPPROTO_TCP, tot_len); + tcp_v6_md5_hash_hdr((__u8 *)topt, key, + &ipv6_hdr(skb)->daddr, + &ipv6_hdr(skb)->saddr, t1); } #endif @@ -1180,7 +1129,7 @@ static void tcp_v6_send_ack(struct tcp_timewait_sock *tw, if (!ip6_dst_lookup(ctl_sk, &buff->dst, &fl)) { if (xfrm_lookup(&buff->dst, &fl, NULL, 0) >= 0) { ip6_xmit(ctl_sk, buff, &fl, NULL, 0); - TCP_INC_STATS_BH(TCP_MIB_OUTSEGS); + TCP_INC_STATS_BH(net, TCP_MIB_OUTSEGS); return; } } @@ -1193,16 +1142,17 @@ static void tcp_v6_timewait_ack(struct sock *sk, struct sk_buff *skb) struct inet_timewait_sock *tw = inet_twsk(sk); struct tcp_timewait_sock *tcptw = tcp_twsk(sk); - tcp_v6_send_ack(tcptw, skb, tcptw->tw_snd_nxt, tcptw->tw_rcv_nxt, + tcp_v6_send_ack(skb, tcptw->tw_snd_nxt, tcptw->tw_rcv_nxt, tcptw->tw_rcv_wnd >> tw->tw_rcv_wscale, - tcptw->tw_ts_recent); + tcptw->tw_ts_recent, tcp_twsk_md5_key(tcptw)); inet_twsk_put(tw); } static void tcp_v6_reqsk_send_ack(struct sk_buff *skb, struct request_sock *req) { - tcp_v6_send_ack(NULL, skb, tcp_rsk(req)->snt_isn + 1, tcp_rsk(req)->rcv_isn + 1, req->rcv_wnd, req->ts_recent); + tcp_v6_send_ack(skb, tcp_rsk(req)->snt_isn + 1, tcp_rsk(req)->rcv_isn + 1, req->rcv_wnd, req->ts_recent, + tcp_v6_md5_do_lookup(skb->sk, &ipv6_hdr(skb)->daddr)); } @@ -1538,9 +1488,9 @@ static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb, return newsk; out_overflow: - NET_INC_STATS_BH(LINUX_MIB_LISTENOVERFLOWS); + NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_LISTENOVERFLOWS); out: - NET_INC_STATS_BH(LINUX_MIB_LISTENDROPS); + NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_LISTENDROPS); if (opt && opt != np->opt) sock_kfree_s(sk, opt, opt->tot_len); dst_release(dst); @@ -1669,7 +1619,7 @@ discard: kfree_skb(skb); return 0; csum_err: - TCP_INC_STATS_BH(TCP_MIB_INERRS); + TCP_INC_STATS_BH(sock_net(sk), TCP_MIB_INERRS); goto discard; @@ -1707,6 +1657,7 @@ static int tcp_v6_rcv(struct sk_buff *skb) struct tcphdr *th; struct sock *sk; int ret; + struct net *net = dev_net(skb->dev); if (skb->pkt_type != PACKET_HOST) goto discard_it; @@ -1714,7 +1665,7 @@ static int tcp_v6_rcv(struct sk_buff *skb) /* * Count it even if it's bad. */ - TCP_INC_STATS_BH(TCP_MIB_INSEGS); + TCP_INC_STATS_BH(net, TCP_MIB_INSEGS); if (!pskb_may_pull(skb, sizeof(struct tcphdr))) goto discard_it; @@ -1738,7 +1689,7 @@ static int tcp_v6_rcv(struct sk_buff *skb) TCP_SKB_CB(skb)->flags = ipv6_get_dsfield(ipv6_hdr(skb)); TCP_SKB_CB(skb)->sacked = 0; - sk = __inet6_lookup(dev_net(skb->dev), &tcp_hashinfo, + sk = __inet6_lookup(net, &tcp_hashinfo, &ipv6_hdr(skb)->saddr, th->source, &ipv6_hdr(skb)->daddr, ntohs(th->dest), inet6_iif(skb)); @@ -1786,7 +1737,7 @@ no_tcp_socket: if (skb->len < (th->doff<<2) || tcp_checksum_complete(skb)) { bad_packet: - TCP_INC_STATS_BH(TCP_MIB_INERRS); + TCP_INC_STATS_BH(net, TCP_MIB_INERRS); } else { tcp_v6_send_reset(NULL, skb); } @@ -1811,7 +1762,7 @@ do_time_wait: } if (skb->len < (th->doff<<2) || tcp_checksum_complete(skb)) { - TCP_INC_STATS_BH(TCP_MIB_INERRS); + TCP_INC_STATS_BH(net, TCP_MIB_INERRS); inet_twsk_put(inet_twsk(sk)); goto discard_it; } @@ -1871,7 +1822,7 @@ static struct inet_connection_sock_af_ops ipv6_specific = { #ifdef CONFIG_TCP_MD5SIG static struct tcp_sock_af_ops tcp_sock_ipv6_specific = { .md5_lookup = tcp_v6_md5_lookup, - .calc_md5_hash = tcp_v6_calc_md5_hash, + .calc_md5_hash = tcp_v6_md5_hash_skb, .md5_add = tcp_v6_md5_add_func, .md5_parse = tcp_v6_parse_md5_keys, }; @@ -1903,7 +1854,7 @@ static struct inet_connection_sock_af_ops ipv6_mapped = { #ifdef CONFIG_TCP_MD5SIG static struct tcp_sock_af_ops tcp_sock_ipv6_mapped_specific = { .md5_lookup = tcp_v4_md5_lookup, - .calc_md5_hash = tcp_v4_calc_md5_hash, + .calc_md5_hash = tcp_v4_md5_hash_skb, .md5_add = tcp_v6_md5_add_func, .md5_parse = tcp_v6_parse_md5_keys, }; @@ -1960,7 +1911,7 @@ static int tcp_v6_init_sock(struct sock *sk) return 0; } -static int tcp_v6_destroy_sock(struct sock *sk) +static void tcp_v6_destroy_sock(struct sock *sk) { #ifdef CONFIG_TCP_MD5SIG /* Clean up the MD5 key list */ @@ -1968,7 +1919,7 @@ static int tcp_v6_destroy_sock(struct sock *sk) tcp_v6_clear_md5_list(sk); #endif tcp_v4_destroy_sock(sk); - return inet6_destroy_sock(sk); + inet6_destroy_sock(sk); } #ifdef CONFIG_PROC_FS diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c index dd309626ae9a..d1477b350f76 100644 --- a/net/ipv6/udp.c +++ b/net/ipv6/udp.c @@ -7,8 +7,6 @@ * * Based on linux/ipv4/udp.c * - * $Id: udp.c,v 1.65 2002/02/01 22:01:04 davem Exp $ - * * Fixes: * Hideaki YOSHIFUJI : sin6_scope_id support * YOSHIFUJI Hideaki @USAGI and: Support IPV6_V6ONLY socket option, which @@ -67,7 +65,7 @@ static struct sock *__udp6_lib_lookup(struct net *net, int badness = -1; read_lock(&udp_hash_lock); - sk_for_each(sk, node, &udptable[hnum & (UDP_HTABLE_SIZE - 1)]) { + sk_for_each(sk, node, &udptable[udp_hashfn(net, hnum)]) { struct inet_sock *inet = inet_sk(sk); if (net_eq(sock_net(sk), net) && sk->sk_hash == hnum && @@ -168,7 +166,8 @@ try_again: goto out_free; if (!peeked) - UDP6_INC_STATS_USER(UDP_MIB_INDATAGRAMS, is_udplite); + UDP6_INC_STATS_USER(sock_net(sk), + UDP_MIB_INDATAGRAMS, is_udplite); sock_recv_timestamp(msg, sk, skb); @@ -215,7 +214,7 @@ out: csum_copy_err: lock_sock(sk); if (!skb_kill_datagram(sk, skb, flags)) - UDP6_INC_STATS_USER(UDP_MIB_INERRORS, is_udplite); + UDP6_INC_STATS_USER(sock_net(sk), UDP_MIB_INERRORS, is_udplite); release_sock(sk); if (flags & MSG_DONTWAIT) @@ -299,14 +298,17 @@ int udpv6_queue_rcv_skb(struct sock * sk, struct sk_buff *skb) if ((rc = sock_queue_rcv_skb(sk,skb)) < 0) { /* Note that an ENOMEM error is charged twice */ - if (rc == -ENOMEM) - UDP6_INC_STATS_BH(UDP_MIB_RCVBUFERRORS, is_udplite); + if (rc == -ENOMEM) { + UDP6_INC_STATS_BH(sock_net(sk), + UDP_MIB_RCVBUFERRORS, is_udplite); + atomic_inc(&sk->sk_drops); + } goto drop; } return 0; drop: - UDP6_INC_STATS_BH(UDP_MIB_INERRORS, is_udplite); + UDP6_INC_STATS_BH(sock_net(sk), UDP_MIB_INERRORS, is_udplite); kfree_skb(skb); return -1; } @@ -355,15 +357,16 @@ static struct sock *udp_v6_mcast_next(struct sock *sk, * Note: called only from the BH handler context, * so we don't need to lock the hashes. */ -static int __udp6_lib_mcast_deliver(struct sk_buff *skb, struct in6_addr *saddr, - struct in6_addr *daddr, struct hlist_head udptable[]) +static int __udp6_lib_mcast_deliver(struct net *net, struct sk_buff *skb, + struct in6_addr *saddr, struct in6_addr *daddr, + struct hlist_head udptable[]) { struct sock *sk, *sk2; const struct udphdr *uh = udp_hdr(skb); int dif; read_lock(&udp_hash_lock); - sk = sk_head(&udptable[ntohs(uh->dest) & (UDP_HTABLE_SIZE - 1)]); + sk = sk_head(&udptable[udp_hashfn(net, ntohs(uh->dest))]); dif = inet6_iif(skb); sk = udp_v6_mcast_next(sk, uh->dest, daddr, uh->source, saddr, dif); if (!sk) { @@ -437,6 +440,7 @@ int __udp6_lib_rcv(struct sk_buff *skb, struct hlist_head udptable[], struct net_device *dev = skb->dev; struct in6_addr *saddr, *daddr; u32 ulen = 0; + struct net *net = dev_net(skb->dev); if (!pskb_may_pull(skb, sizeof(struct udphdr))) goto short_packet; @@ -475,7 +479,8 @@ int __udp6_lib_rcv(struct sk_buff *skb, struct hlist_head udptable[], * Multicast receive code */ if (ipv6_addr_is_multicast(daddr)) - return __udp6_lib_mcast_deliver(skb, saddr, daddr, udptable); + return __udp6_lib_mcast_deliver(net, skb, + saddr, daddr, udptable); /* Unicast */ @@ -483,7 +488,7 @@ int __udp6_lib_rcv(struct sk_buff *skb, struct hlist_head udptable[], * check socket cache ... must talk to Alan about his plans * for sock caches... i'll skip this for now. */ - sk = __udp6_lib_lookup(dev_net(skb->dev), saddr, uh->source, + sk = __udp6_lib_lookup(net, saddr, uh->source, daddr, uh->dest, inet6_iif(skb), udptable); if (sk == NULL) { @@ -492,7 +497,8 @@ int __udp6_lib_rcv(struct sk_buff *skb, struct hlist_head udptable[], if (udp_lib_checksum_complete(skb)) goto discard; - UDP6_INC_STATS_BH(UDP_MIB_NOPORTS, proto == IPPROTO_UDPLITE); + UDP6_INC_STATS_BH(net, UDP_MIB_NOPORTS, + proto == IPPROTO_UDPLITE); icmpv6_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_PORT_UNREACH, 0, dev); @@ -517,7 +523,7 @@ short_packet: ulen, skb->len); discard: - UDP6_INC_STATS_BH(UDP_MIB_INERRORS, proto == IPPROTO_UDPLITE); + UDP6_INC_STATS_BH(net, UDP_MIB_INERRORS, proto == IPPROTO_UDPLITE); kfree_skb(skb); return 0; } @@ -587,7 +593,8 @@ out: up->len = 0; up->pending = 0; if (!err) - UDP6_INC_STATS_USER(UDP_MIB_OUTDATAGRAMS, is_udplite); + UDP6_INC_STATS_USER(sock_net(sk), + UDP_MIB_OUTDATAGRAMS, is_udplite); return err; } @@ -869,7 +876,8 @@ out: * seems like overkill. */ if (err == -ENOBUFS || test_bit(SOCK_NOSPACE, &sk->sk_socket->flags)) { - UDP6_INC_STATS_USER(UDP_MIB_SNDBUFERRORS, is_udplite); + UDP6_INC_STATS_USER(sock_net(sk), + UDP_MIB_SNDBUFERRORS, is_udplite); } return err; @@ -881,15 +889,13 @@ do_confirm: goto out; } -int udpv6_destroy_sock(struct sock *sk) +void udpv6_destroy_sock(struct sock *sk) { lock_sock(sk); udp_v6_flush_pending_frames(sk); release_sock(sk); inet6_destroy_sock(sk); - - return 0; } /* @@ -955,7 +961,7 @@ static void udp6_sock_seq_show(struct seq_file *seq, struct sock *sp, int bucket srcp = ntohs(inet->sport); seq_printf(seq, "%4d: %08X%08X%08X%08X:%04X %08X%08X%08X%08X:%04X " - "%02X %08X:%08X %02X:%08lX %08X %5d %8d %lu %d %p\n", + "%02X %08X:%08X %02X:%08lX %08X %5d %8d %lu %d %p %d\n", bucket, src->s6_addr32[0], src->s6_addr32[1], src->s6_addr32[2], src->s6_addr32[3], srcp, @@ -967,7 +973,8 @@ static void udp6_sock_seq_show(struct seq_file *seq, struct sock *sp, int bucket 0, 0L, 0, sock_i_uid(sp), 0, sock_i_ino(sp), - atomic_read(&sp->sk_refcnt), sp); + atomic_read(&sp->sk_refcnt), sp, + atomic_read(&sp->sk_drops)); } int udp6_seq_show(struct seq_file *seq, void *v) @@ -978,7 +985,7 @@ int udp6_seq_show(struct seq_file *seq, void *v) "local_address " "remote_address " "st tx_queue rx_queue tr tm->when retrnsmt" - " uid timeout inode\n"); + " uid timeout inode ref pointer drops\n"); else udp6_sock_seq_show(seq, v, ((struct udp_iter_state *)seq->private)->bucket); return 0; diff --git a/net/ipv6/udp_impl.h b/net/ipv6/udp_impl.h index 321b81a4d418..92dd7da766d8 100644 --- a/net/ipv6/udp_impl.h +++ b/net/ipv6/udp_impl.h @@ -29,7 +29,7 @@ extern int udpv6_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, size_t len, int noblock, int flags, int *addr_len); extern int udpv6_queue_rcv_skb(struct sock * sk, struct sk_buff *skb); -extern int udpv6_destroy_sock(struct sock *sk); +extern void udpv6_destroy_sock(struct sock *sk); #ifdef CONFIG_PROC_FS extern int udp6_seq_show(struct seq_file *seq, void *v); diff --git a/net/ipv6/udplite.c b/net/ipv6/udplite.c index 491efd00a866..f6cdcb348e05 100644 --- a/net/ipv6/udplite.c +++ b/net/ipv6/udplite.c @@ -2,8 +2,6 @@ * UDPLITEv6 An implementation of the UDP-Lite protocol over IPv6. * See also net/ipv4/udplite.c * - * Version: $Id: udplite.c,v 1.9 2006/10/19 08:28:10 gerrit Exp $ - * * Authors: Gerrit Renker <gerrit@erg.abdn.ac.uk> * * Changes: diff --git a/net/ipx/af_ipx.c b/net/ipx/af_ipx.c index 81ae8735f5e3..b6e70f92e7fb 100644 --- a/net/ipx/af_ipx.c +++ b/net/ipx/af_ipx.c @@ -335,7 +335,7 @@ static int ipxitf_device_event(struct notifier_block *notifier, struct net_device *dev = ptr; struct ipx_interface *i, *tmp; - if (dev_net(dev) != &init_net) + if (!net_eq(dev_net(dev), &init_net)) return NOTIFY_DONE; if (event != NETDEV_DOWN && event != NETDEV_UP) @@ -1636,7 +1636,7 @@ static int ipx_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_ty u16 ipx_pktsize; int rc = 0; - if (dev_net(dev) != &init_net) + if (!net_eq(dev_net(dev), &init_net)) goto drop; /* Not ours */ diff --git a/net/irda/ircomm/ircomm_tty.c b/net/irda/ircomm/ircomm_tty.c index 76c3057d0179..e4e2caeb9d82 100644 --- a/net/irda/ircomm/ircomm_tty.c +++ b/net/irda/ircomm/ircomm_tty.c @@ -650,12 +650,7 @@ static void ircomm_tty_do_softint(struct work_struct *work) } /* Check if user (still) wants to be waken up */ - if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && - tty->ldisc.write_wakeup) - { - (tty->ldisc.write_wakeup)(tty); - } - wake_up_interruptible(&tty->write_wait); + tty_wakeup(tty); } /* @@ -1141,6 +1136,7 @@ static int ircomm_tty_data_indication(void *instance, void *sap, struct sk_buff *skb) { struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) instance; + struct tty_ldisc *ld; IRDA_DEBUG(2, "%s()\n", __func__ ); @@ -1173,7 +1169,11 @@ static int ircomm_tty_data_indication(void *instance, void *sap, * involve the flip buffers, since we are not running in an interrupt * handler */ - self->tty->ldisc.receive_buf(self->tty, skb->data, NULL, skb->len); + + ld = tty_ldisc_ref(self->tty); + if (ld) + ld->ops->receive_buf(self->tty, skb->data, NULL, skb->len); + tty_ldisc_deref(ld); /* No need to kfree_skb - see ircomm_ttp_data_indication() */ diff --git a/net/irda/irlap_frame.c b/net/irda/irlap_frame.c index 90894534f3cc..f17b65af9c9b 100644 --- a/net/irda/irlap_frame.c +++ b/net/irda/irlap_frame.c @@ -1326,7 +1326,7 @@ int irlap_driver_rcv(struct sk_buff *skb, struct net_device *dev, int command; __u8 control; - if (dev_net(dev) != &init_net) + if (!net_eq(dev_net(dev), &init_net)) goto out; /* FIXME: should we get our own field? */ diff --git a/net/irda/irnet/irnet_ppp.c b/net/irda/irnet/irnet_ppp.c index e84a70dd346b..6d8ae03c14f5 100644 --- a/net/irda/irnet/irnet_ppp.c +++ b/net/irda/irnet/irnet_ppp.c @@ -631,8 +631,8 @@ dev_irnet_poll(struct file * file, * This is the way pppd configure us and control us while the PPP * instance is active. */ -static int -dev_irnet_ioctl(struct inode * inode, +static long +dev_irnet_ioctl( struct file * file, unsigned int cmd, unsigned long arg) @@ -663,6 +663,7 @@ dev_irnet_ioctl(struct inode * inode, { DEBUG(FS_INFO, "Entering PPP discipline.\n"); /* PPP channel setup (ap->chan in configued in dev_irnet_open())*/ + lock_kernel(); err = ppp_register_channel(&ap->chan); if(err == 0) { @@ -675,12 +676,14 @@ dev_irnet_ioctl(struct inode * inode, } else DERROR(FS_ERROR, "Can't setup PPP channel...\n"); + unlock_kernel(); } else { /* In theory, should be N_TTY */ DEBUG(FS_INFO, "Exiting PPP discipline.\n"); /* Disconnect from the generic PPP layer */ + lock_kernel(); if(ap->ppp_open) { ap->ppp_open = 0; @@ -689,24 +692,20 @@ dev_irnet_ioctl(struct inode * inode, else DERROR(FS_ERROR, "Channel not registered !\n"); err = 0; + unlock_kernel(); } break; /* Query PPP channel and unit number */ case PPPIOCGCHAN: - if(!ap->ppp_open) - break; - if(put_user(ppp_channel_index(&ap->chan), (int __user *)argp)) - break; - DEBUG(FS_INFO, "Query channel.\n"); - err = 0; + if(ap->ppp_open && !put_user(ppp_channel_index(&ap->chan), + (int __user *)argp)) + err = 0; break; case PPPIOCGUNIT: - if(!ap->ppp_open) - break; - if(put_user(ppp_unit_number(&ap->chan), (int __user *)argp)) - break; - DEBUG(FS_INFO, "Query unit number.\n"); + lock_kernel(); + if(ap->ppp_open && !put_user(ppp_unit_number(&ap->chan), + (int __user *)argp)) err = 0; break; @@ -726,34 +725,39 @@ dev_irnet_ioctl(struct inode * inode, DEBUG(FS_INFO, "Standard PPP ioctl.\n"); if(!capable(CAP_NET_ADMIN)) err = -EPERM; - else + else { + lock_kernel(); err = ppp_irnet_ioctl(&ap->chan, cmd, arg); + unlock_kernel(); + } break; /* TTY IOCTLs : Pretend that we are a tty, to keep pppd happy */ /* Get termios */ case TCGETS: DEBUG(FS_INFO, "Get termios.\n"); + lock_kernel(); #ifndef TCGETS2 - if(kernel_termios_to_user_termios((struct termios __user *)argp, &ap->termios)) - break; + if(!kernel_termios_to_user_termios((struct termios __user *)argp, &ap->termios)) + err = 0; #else if(kernel_termios_to_user_termios_1((struct termios __user *)argp, &ap->termios)) - break; + err = 0; #endif - err = 0; + unlock_kernel(); break; /* Set termios */ case TCSETSF: DEBUG(FS_INFO, "Set termios.\n"); + lock_kernel(); #ifndef TCGETS2 - if(user_termios_to_kernel_termios(&ap->termios, (struct termios __user *)argp)) - break; + if(!user_termios_to_kernel_termios(&ap->termios, (struct termios __user *)argp)) + err = 0; #else - if(user_termios_to_kernel_termios_1(&ap->termios, (struct termios __user *)argp)) - break; + if(!user_termios_to_kernel_termios_1(&ap->termios, (struct termios __user *)argp)) + err = 0; #endif - err = 0; + unlock_kernel(); break; /* Set DTR/RTS */ @@ -776,7 +780,9 @@ dev_irnet_ioctl(struct inode * inode, * We should also worry that we don't accept junk here and that * we get rid of our own buffers */ #ifdef FLUSH_TO_PPP + lock_kernel(); ppp_output_wakeup(&ap->chan); + unlock_kernel(); #endif /* FLUSH_TO_PPP */ err = 0; break; @@ -791,7 +797,7 @@ dev_irnet_ioctl(struct inode * inode, default: DERROR(FS_ERROR, "Unsupported ioctl (0x%X)\n", cmd); - err = -ENOIOCTLCMD; + err = -ENOTTY; } DEXIT(FS_TRACE, " - err = 0x%X\n", err); diff --git a/net/irda/irnet/irnet_ppp.h b/net/irda/irnet/irnet_ppp.h index d2beb7df8f7f..d9f8bd4ebd05 100644 --- a/net/irda/irnet/irnet_ppp.h +++ b/net/irda/irnet/irnet_ppp.h @@ -76,9 +76,8 @@ static ssize_t static unsigned int dev_irnet_poll(struct file *, poll_table *); -static int - dev_irnet_ioctl(struct inode *, - struct file *, +static long + dev_irnet_ioctl(struct file *, unsigned int, unsigned long); /* ------------------------ PPP INTERFACE ------------------------ */ @@ -102,7 +101,7 @@ static struct file_operations irnet_device_fops = .read = dev_irnet_read, .write = dev_irnet_write, .poll = dev_irnet_poll, - .ioctl = dev_irnet_ioctl, + .unlocked_ioctl = dev_irnet_ioctl, .open = dev_irnet_open, .release = dev_irnet_close /* Also : llseek, readdir, mmap, flush, fsync, fasync, lock, readv, writev */ diff --git a/net/iucv/af_iucv.c b/net/iucv/af_iucv.c index bda71015885c..29f7baa25110 100644 --- a/net/iucv/af_iucv.c +++ b/net/iucv/af_iucv.c @@ -644,6 +644,7 @@ static int iucv_sock_sendmsg(struct kiocb *iocb, struct socket *sock, } txmsg.class = 0; + memcpy(&txmsg.class, skb->data, skb->len >= 4 ? 4 : skb->len); txmsg.tag = iucv->send_tag++; memcpy(skb->cb, &txmsg.tag, 4); skb_queue_tail(&iucv->send_skb_q, skb); diff --git a/net/iucv/iucv.c b/net/iucv/iucv.c index cc34ac769a3c..265b1b289a32 100644 --- a/net/iucv/iucv.c +++ b/net/iucv/iucv.c @@ -474,14 +474,14 @@ static void iucv_setmask_mp(void) { int cpu; - preempt_disable(); + get_online_cpus(); for_each_online_cpu(cpu) /* Enable all cpus with a declared buffer. */ if (cpu_isset(cpu, iucv_buffer_cpumask) && !cpu_isset(cpu, iucv_irq_cpumask)) smp_call_function_single(cpu, iucv_allow_cpu, NULL, 1); - preempt_enable(); + put_online_cpus(); } /** @@ -521,16 +521,18 @@ static int iucv_enable(void) goto out; /* Declare per cpu buffers. */ rc = -EIO; - preempt_disable(); + get_online_cpus(); for_each_online_cpu(cpu) smp_call_function_single(cpu, iucv_declare_cpu, NULL, 1); preempt_enable(); if (cpus_empty(iucv_buffer_cpumask)) /* No cpu could declare an iucv buffer. */ goto out_path; + put_online_cpus(); return 0; out_path: + put_online_cpus(); kfree(iucv_path_table); out: return rc; @@ -564,8 +566,11 @@ static int __cpuinit iucv_cpu_notify(struct notifier_block *self, return NOTIFY_BAD; iucv_param[cpu] = kmalloc_node(sizeof(union iucv_param), GFP_KERNEL|GFP_DMA, cpu_to_node(cpu)); - if (!iucv_param[cpu]) + if (!iucv_param[cpu]) { + kfree(iucv_irq_data[cpu]); + iucv_irq_data[cpu] = NULL; return NOTIFY_BAD; + } break; case CPU_UP_CANCELED: case CPU_UP_CANCELED_FROZEN: @@ -598,7 +603,7 @@ static int __cpuinit iucv_cpu_notify(struct notifier_block *self, return NOTIFY_OK; } -static struct notifier_block __cpuinitdata iucv_cpu_notifier = { +static struct notifier_block __refdata iucv_cpu_notifier = { .notifier_call = iucv_cpu_notify, }; diff --git a/net/key/af_key.c b/net/key/af_key.c index 7470e367272b..f0fc46c8038d 100644 --- a/net/key/af_key.c +++ b/net/key/af_key.c @@ -579,25 +579,43 @@ static uint8_t pfkey_proto_from_xfrm(uint8_t proto) return (proto ? proto : IPSEC_PROTO_ANY); } -static int pfkey_sadb_addr2xfrm_addr(struct sadb_address *addr, - xfrm_address_t *xaddr) +static inline int pfkey_sockaddr_len(sa_family_t family) { - switch (((struct sockaddr*)(addr + 1))->sa_family) { + switch (family) { + case AF_INET: + return sizeof(struct sockaddr_in); +#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) + case AF_INET6: + return sizeof(struct sockaddr_in6); +#endif + } + return 0; +} + +static +int pfkey_sockaddr_extract(const struct sockaddr *sa, xfrm_address_t *xaddr) +{ + switch (sa->sa_family) { case AF_INET: xaddr->a4 = - ((struct sockaddr_in *)(addr + 1))->sin_addr.s_addr; + ((struct sockaddr_in *)sa)->sin_addr.s_addr; return AF_INET; #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) case AF_INET6: memcpy(xaddr->a6, - &((struct sockaddr_in6 *)(addr + 1))->sin6_addr, + &((struct sockaddr_in6 *)sa)->sin6_addr, sizeof(struct in6_addr)); return AF_INET6; #endif - default: - return 0; } - /* NOTREACHED */ + return 0; +} + +static +int pfkey_sadb_addr2xfrm_addr(struct sadb_address *addr, xfrm_address_t *xaddr) +{ + return pfkey_sockaddr_extract((struct sockaddr *)(addr + 1), + xaddr); } static struct xfrm_state *pfkey_xfrm_state_lookup(struct sadb_msg *hdr, void **ext_hdrs) @@ -642,20 +660,11 @@ static struct xfrm_state *pfkey_xfrm_state_lookup(struct sadb_msg *hdr, void ** } #define PFKEY_ALIGN8(a) (1 + (((a) - 1) | (8 - 1))) + static int pfkey_sockaddr_size(sa_family_t family) { - switch (family) { - case AF_INET: - return PFKEY_ALIGN8(sizeof(struct sockaddr_in)); -#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) - case AF_INET6: - return PFKEY_ALIGN8(sizeof(struct sockaddr_in6)); -#endif - default: - return 0; - } - /* NOTREACHED */ + return PFKEY_ALIGN8(pfkey_sockaddr_len(family)); } static inline int pfkey_mode_from_xfrm(int mode) @@ -687,6 +696,36 @@ static inline int pfkey_mode_to_xfrm(int mode) } } +static unsigned int pfkey_sockaddr_fill(xfrm_address_t *xaddr, __be16 port, + struct sockaddr *sa, + unsigned short family) +{ + switch (family) { + case AF_INET: + { + struct sockaddr_in *sin = (struct sockaddr_in *)sa; + sin->sin_family = AF_INET; + sin->sin_port = port; + sin->sin_addr.s_addr = xaddr->a4; + memset(sin->sin_zero, 0, sizeof(sin->sin_zero)); + return 32; + } +#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) + case AF_INET6: + { + struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa; + sin6->sin6_family = AF_INET6; + sin6->sin6_port = port; + sin6->sin6_flowinfo = 0; + ipv6_addr_copy(&sin6->sin6_addr, (struct in6_addr *)xaddr->a6); + sin6->sin6_scope_id = 0; + return 128; + } +#endif + } + return 0; +} + static struct sk_buff *__pfkey_xfrm_state2msg(struct xfrm_state *x, int add_keys, int hsc) { @@ -697,13 +736,9 @@ static struct sk_buff *__pfkey_xfrm_state2msg(struct xfrm_state *x, struct sadb_address *addr; struct sadb_key *key; struct sadb_x_sa2 *sa2; - struct sockaddr_in *sin; struct sadb_x_sec_ctx *sec_ctx; struct xfrm_sec_ctx *xfrm_ctx; int ctx_size = 0; -#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) - struct sockaddr_in6 *sin6; -#endif int size; int auth_key_size = 0; int encrypt_key_size = 0; @@ -732,14 +767,7 @@ static struct sk_buff *__pfkey_xfrm_state2msg(struct xfrm_state *x, } /* identity & sensitivity */ - - if ((x->props.family == AF_INET && - x->sel.saddr.a4 != x->props.saddr.a4) -#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) - || (x->props.family == AF_INET6 && - memcmp (x->sel.saddr.a6, x->props.saddr.a6, sizeof (struct in6_addr))) -#endif - ) + if (xfrm_addr_cmp(&x->sel.saddr, &x->props.saddr, x->props.family)) size += sizeof(struct sadb_address) + sockaddr_size; if (add_keys) { @@ -861,29 +889,12 @@ static struct sk_buff *__pfkey_xfrm_state2msg(struct xfrm_state *x, protocol's number." - RFC2367 */ addr->sadb_address_proto = 0; addr->sadb_address_reserved = 0; - if (x->props.family == AF_INET) { - addr->sadb_address_prefixlen = 32; - sin = (struct sockaddr_in *) (addr + 1); - sin->sin_family = AF_INET; - sin->sin_addr.s_addr = x->props.saddr.a4; - sin->sin_port = 0; - memset(sin->sin_zero, 0, sizeof(sin->sin_zero)); - } -#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) - else if (x->props.family == AF_INET6) { - addr->sadb_address_prefixlen = 128; - - sin6 = (struct sockaddr_in6 *) (addr + 1); - sin6->sin6_family = AF_INET6; - sin6->sin6_port = 0; - sin6->sin6_flowinfo = 0; - memcpy(&sin6->sin6_addr, x->props.saddr.a6, - sizeof(struct in6_addr)); - sin6->sin6_scope_id = 0; - } -#endif - else + addr->sadb_address_prefixlen = + pfkey_sockaddr_fill(&x->props.saddr, 0, + (struct sockaddr *) (addr + 1), + x->props.family); + if (!addr->sadb_address_prefixlen) BUG(); /* dst address */ @@ -894,70 +905,32 @@ static struct sk_buff *__pfkey_xfrm_state2msg(struct xfrm_state *x, sizeof(uint64_t); addr->sadb_address_exttype = SADB_EXT_ADDRESS_DST; addr->sadb_address_proto = 0; - addr->sadb_address_prefixlen = 32; /* XXX */ addr->sadb_address_reserved = 0; - if (x->props.family == AF_INET) { - sin = (struct sockaddr_in *) (addr + 1); - sin->sin_family = AF_INET; - sin->sin_addr.s_addr = x->id.daddr.a4; - sin->sin_port = 0; - memset(sin->sin_zero, 0, sizeof(sin->sin_zero)); - if (x->sel.saddr.a4 != x->props.saddr.a4) { - addr = (struct sadb_address*) skb_put(skb, - sizeof(struct sadb_address)+sockaddr_size); - addr->sadb_address_len = - (sizeof(struct sadb_address)+sockaddr_size)/ - sizeof(uint64_t); - addr->sadb_address_exttype = SADB_EXT_ADDRESS_PROXY; - addr->sadb_address_proto = - pfkey_proto_from_xfrm(x->sel.proto); - addr->sadb_address_prefixlen = x->sel.prefixlen_s; - addr->sadb_address_reserved = 0; - - sin = (struct sockaddr_in *) (addr + 1); - sin->sin_family = AF_INET; - sin->sin_addr.s_addr = x->sel.saddr.a4; - sin->sin_port = x->sel.sport; - memset(sin->sin_zero, 0, sizeof(sin->sin_zero)); - } - } -#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) - else if (x->props.family == AF_INET6) { - addr->sadb_address_prefixlen = 128; + addr->sadb_address_prefixlen = + pfkey_sockaddr_fill(&x->id.daddr, 0, + (struct sockaddr *) (addr + 1), + x->props.family); + if (!addr->sadb_address_prefixlen) + BUG(); - sin6 = (struct sockaddr_in6 *) (addr + 1); - sin6->sin6_family = AF_INET6; - sin6->sin6_port = 0; - sin6->sin6_flowinfo = 0; - memcpy(&sin6->sin6_addr, x->id.daddr.a6, sizeof(struct in6_addr)); - sin6->sin6_scope_id = 0; + if (xfrm_addr_cmp(&x->sel.saddr, &x->props.saddr, + x->props.family)) { + addr = (struct sadb_address*) skb_put(skb, + sizeof(struct sadb_address)+sockaddr_size); + addr->sadb_address_len = + (sizeof(struct sadb_address)+sockaddr_size)/ + sizeof(uint64_t); + addr->sadb_address_exttype = SADB_EXT_ADDRESS_PROXY; + addr->sadb_address_proto = + pfkey_proto_from_xfrm(x->sel.proto); + addr->sadb_address_prefixlen = x->sel.prefixlen_s; + addr->sadb_address_reserved = 0; - if (memcmp (x->sel.saddr.a6, x->props.saddr.a6, - sizeof(struct in6_addr))) { - addr = (struct sadb_address *) skb_put(skb, - sizeof(struct sadb_address)+sockaddr_size); - addr->sadb_address_len = - (sizeof(struct sadb_address)+sockaddr_size)/ - sizeof(uint64_t); - addr->sadb_address_exttype = SADB_EXT_ADDRESS_PROXY; - addr->sadb_address_proto = - pfkey_proto_from_xfrm(x->sel.proto); - addr->sadb_address_prefixlen = x->sel.prefixlen_s; - addr->sadb_address_reserved = 0; - - sin6 = (struct sockaddr_in6 *) (addr + 1); - sin6->sin6_family = AF_INET6; - sin6->sin6_port = x->sel.sport; - sin6->sin6_flowinfo = 0; - memcpy(&sin6->sin6_addr, x->sel.saddr.a6, - sizeof(struct in6_addr)); - sin6->sin6_scope_id = 0; - } + pfkey_sockaddr_fill(&x->sel.saddr, x->sel.sport, + (struct sockaddr *) (addr + 1), + x->props.family); } -#endif - else - BUG(); /* auth key */ if (add_keys && auth_key_size) { @@ -1853,10 +1826,6 @@ static int parse_ipsecrequest(struct xfrm_policy *xp, struct sadb_x_ipsecrequest *rq) { struct xfrm_tmpl *t = xp->xfrm_vec + xp->xfrm_nr; - struct sockaddr_in *sin; -#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) - struct sockaddr_in6 *sin6; -#endif int mode; if (xp->xfrm_nr >= XFRM_MAX_DEPTH) @@ -1881,31 +1850,19 @@ parse_ipsecrequest(struct xfrm_policy *xp, struct sadb_x_ipsecrequest *rq) /* addresses present only in tunnel mode */ if (t->mode == XFRM_MODE_TUNNEL) { - struct sockaddr *sa; - sa = (struct sockaddr *)(rq+1); - switch(sa->sa_family) { - case AF_INET: - sin = (struct sockaddr_in*)sa; - t->saddr.a4 = sin->sin_addr.s_addr; - sin++; - if (sin->sin_family != AF_INET) - return -EINVAL; - t->id.daddr.a4 = sin->sin_addr.s_addr; - break; -#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) - case AF_INET6: - sin6 = (struct sockaddr_in6*)sa; - memcpy(t->saddr.a6, &sin6->sin6_addr, sizeof(struct in6_addr)); - sin6++; - if (sin6->sin6_family != AF_INET6) - return -EINVAL; - memcpy(t->id.daddr.a6, &sin6->sin6_addr, sizeof(struct in6_addr)); - break; -#endif - default: + u8 *sa = (u8 *) (rq + 1); + int family, socklen; + + family = pfkey_sockaddr_extract((struct sockaddr *)sa, + &t->saddr); + if (!family) return -EINVAL; - } - t->encap_family = sa->sa_family; + + socklen = pfkey_sockaddr_len(family); + if (pfkey_sockaddr_extract((struct sockaddr *)(sa + socklen), + &t->id.daddr) != family) + return -EINVAL; + t->encap_family = family; } else t->encap_family = xp->family; @@ -1952,9 +1909,7 @@ static int pfkey_xfrm_policy2msg_size(struct xfrm_policy *xp) for (i=0; i<xp->xfrm_nr; i++) { t = xp->xfrm_vec + i; - socklen += (t->encap_family == AF_INET ? - sizeof(struct sockaddr_in) : - sizeof(struct sockaddr_in6)); + socklen += pfkey_sockaddr_len(t->encap_family); } return sizeof(struct sadb_msg) + @@ -1987,18 +1942,12 @@ static int pfkey_xfrm_policy2msg(struct sk_buff *skb, struct xfrm_policy *xp, in struct sadb_address *addr; struct sadb_lifetime *lifetime; struct sadb_x_policy *pol; - struct sockaddr_in *sin; struct sadb_x_sec_ctx *sec_ctx; struct xfrm_sec_ctx *xfrm_ctx; -#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) - struct sockaddr_in6 *sin6; -#endif int i; int size; int sockaddr_size = pfkey_sockaddr_size(xp->family); - int socklen = (xp->family == AF_INET ? - sizeof(struct sockaddr_in) : - sizeof(struct sockaddr_in6)); + int socklen = pfkey_sockaddr_len(xp->family); size = pfkey_xfrm_policy2msg_size(xp); @@ -2016,26 +1965,10 @@ static int pfkey_xfrm_policy2msg(struct sk_buff *skb, struct xfrm_policy *xp, in addr->sadb_address_proto = pfkey_proto_from_xfrm(xp->selector.proto); addr->sadb_address_prefixlen = xp->selector.prefixlen_s; addr->sadb_address_reserved = 0; - /* src address */ - if (xp->family == AF_INET) { - sin = (struct sockaddr_in *) (addr + 1); - sin->sin_family = AF_INET; - sin->sin_addr.s_addr = xp->selector.saddr.a4; - sin->sin_port = xp->selector.sport; - memset(sin->sin_zero, 0, sizeof(sin->sin_zero)); - } -#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) - else if (xp->family == AF_INET6) { - sin6 = (struct sockaddr_in6 *) (addr + 1); - sin6->sin6_family = AF_INET6; - sin6->sin6_port = xp->selector.sport; - sin6->sin6_flowinfo = 0; - memcpy(&sin6->sin6_addr, xp->selector.saddr.a6, - sizeof(struct in6_addr)); - sin6->sin6_scope_id = 0; - } -#endif - else + if (!pfkey_sockaddr_fill(&xp->selector.saddr, + xp->selector.sport, + (struct sockaddr *) (addr + 1), + xp->family)) BUG(); /* dst address */ @@ -2048,26 +1981,10 @@ static int pfkey_xfrm_policy2msg(struct sk_buff *skb, struct xfrm_policy *xp, in addr->sadb_address_proto = pfkey_proto_from_xfrm(xp->selector.proto); addr->sadb_address_prefixlen = xp->selector.prefixlen_d; addr->sadb_address_reserved = 0; - if (xp->family == AF_INET) { - sin = (struct sockaddr_in *) (addr + 1); - sin->sin_family = AF_INET; - sin->sin_addr.s_addr = xp->selector.daddr.a4; - sin->sin_port = xp->selector.dport; - memset(sin->sin_zero, 0, sizeof(sin->sin_zero)); - } -#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) - else if (xp->family == AF_INET6) { - sin6 = (struct sockaddr_in6 *) (addr + 1); - sin6->sin6_family = AF_INET6; - sin6->sin6_port = xp->selector.dport; - sin6->sin6_flowinfo = 0; - memcpy(&sin6->sin6_addr, xp->selector.daddr.a6, - sizeof(struct in6_addr)); - sin6->sin6_scope_id = 0; - } -#endif - else - BUG(); + + pfkey_sockaddr_fill(&xp->selector.daddr, xp->selector.dport, + (struct sockaddr *) (addr + 1), + xp->family); /* hard time */ lifetime = (struct sadb_lifetime *) skb_put(skb, @@ -2121,12 +2038,13 @@ static int pfkey_xfrm_policy2msg(struct sk_buff *skb, struct xfrm_policy *xp, in int mode; req_size = sizeof(struct sadb_x_ipsecrequest); - if (t->mode == XFRM_MODE_TUNNEL) - req_size += ((t->encap_family == AF_INET ? - sizeof(struct sockaddr_in) : - sizeof(struct sockaddr_in6)) * 2); - else + if (t->mode == XFRM_MODE_TUNNEL) { + socklen = pfkey_sockaddr_len(t->encap_family); + req_size += socklen * 2; + } else { size -= 2*socklen; + socklen = 0; + } rq = (void*)skb_put(skb, req_size); pol->sadb_x_policy_len += req_size/8; memset(rq, 0, sizeof(*rq)); @@ -2141,42 +2059,15 @@ static int pfkey_xfrm_policy2msg(struct sk_buff *skb, struct xfrm_policy *xp, in if (t->optional) rq->sadb_x_ipsecrequest_level = IPSEC_LEVEL_USE; rq->sadb_x_ipsecrequest_reqid = t->reqid; + if (t->mode == XFRM_MODE_TUNNEL) { - switch (t->encap_family) { - case AF_INET: - sin = (void*)(rq+1); - sin->sin_family = AF_INET; - sin->sin_addr.s_addr = t->saddr.a4; - sin->sin_port = 0; - memset(sin->sin_zero, 0, sizeof(sin->sin_zero)); - sin++; - sin->sin_family = AF_INET; - sin->sin_addr.s_addr = t->id.daddr.a4; - sin->sin_port = 0; - memset(sin->sin_zero, 0, sizeof(sin->sin_zero)); - break; -#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) - case AF_INET6: - sin6 = (void*)(rq+1); - sin6->sin6_family = AF_INET6; - sin6->sin6_port = 0; - sin6->sin6_flowinfo = 0; - memcpy(&sin6->sin6_addr, t->saddr.a6, - sizeof(struct in6_addr)); - sin6->sin6_scope_id = 0; - - sin6++; - sin6->sin6_family = AF_INET6; - sin6->sin6_port = 0; - sin6->sin6_flowinfo = 0; - memcpy(&sin6->sin6_addr, t->id.daddr.a6, - sizeof(struct in6_addr)); - sin6->sin6_scope_id = 0; - break; -#endif - default: - break; - } + u8 *sa = (void *)(rq + 1); + pfkey_sockaddr_fill(&t->saddr, 0, + (struct sockaddr *)sa, + t->encap_family); + pfkey_sockaddr_fill(&t->id.daddr, 0, + (struct sockaddr *) (sa + socklen), + t->encap_family); } } @@ -2459,61 +2350,31 @@ out: #ifdef CONFIG_NET_KEY_MIGRATE static int pfkey_sockaddr_pair_size(sa_family_t family) { - switch (family) { - case AF_INET: - return PFKEY_ALIGN8(sizeof(struct sockaddr_in) * 2); -#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) - case AF_INET6: - return PFKEY_ALIGN8(sizeof(struct sockaddr_in6) * 2); -#endif - default: - return 0; - } - /* NOTREACHED */ + return PFKEY_ALIGN8(pfkey_sockaddr_len(family) * 2); } static int parse_sockaddr_pair(struct sadb_x_ipsecrequest *rq, xfrm_address_t *saddr, xfrm_address_t *daddr, u16 *family) { - struct sockaddr *sa = (struct sockaddr *)(rq + 1); + u8 *sa = (u8 *) (rq + 1); + int af, socklen; + if (rq->sadb_x_ipsecrequest_len < - pfkey_sockaddr_pair_size(sa->sa_family)) + pfkey_sockaddr_pair_size(((struct sockaddr *)sa)->sa_family)) return -EINVAL; - switch (sa->sa_family) { - case AF_INET: - { - struct sockaddr_in *sin; - sin = (struct sockaddr_in *)sa; - if ((sin+1)->sin_family != AF_INET) - return -EINVAL; - memcpy(&saddr->a4, &sin->sin_addr, sizeof(saddr->a4)); - sin++; - memcpy(&daddr->a4, &sin->sin_addr, sizeof(daddr->a4)); - *family = AF_INET; - break; - } -#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) - case AF_INET6: - { - struct sockaddr_in6 *sin6; - sin6 = (struct sockaddr_in6 *)sa; - if ((sin6+1)->sin6_family != AF_INET6) - return -EINVAL; - memcpy(&saddr->a6, &sin6->sin6_addr, - sizeof(saddr->a6)); - sin6++; - memcpy(&daddr->a6, &sin6->sin6_addr, - sizeof(daddr->a6)); - *family = AF_INET6; - break; - } -#endif - default: + af = pfkey_sockaddr_extract((struct sockaddr *) sa, + saddr); + if (!af) return -EINVAL; - } + socklen = pfkey_sockaddr_len(af); + if (pfkey_sockaddr_extract((struct sockaddr *) (sa + socklen), + daddr) != af) + return -EINVAL; + + *family = af; return 0; } @@ -3094,10 +2955,6 @@ static int pfkey_send_acquire(struct xfrm_state *x, struct xfrm_tmpl *t, struct struct sadb_msg *hdr; struct sadb_address *addr; struct sadb_x_policy *pol; - struct sockaddr_in *sin; -#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) - struct sockaddr_in6 *sin6; -#endif int sockaddr_size; int size; struct sadb_x_sec_ctx *sec_ctx; @@ -3146,29 +3003,11 @@ static int pfkey_send_acquire(struct xfrm_state *x, struct xfrm_tmpl *t, struct addr->sadb_address_exttype = SADB_EXT_ADDRESS_SRC; addr->sadb_address_proto = 0; addr->sadb_address_reserved = 0; - if (x->props.family == AF_INET) { - addr->sadb_address_prefixlen = 32; - - sin = (struct sockaddr_in *) (addr + 1); - sin->sin_family = AF_INET; - sin->sin_addr.s_addr = x->props.saddr.a4; - sin->sin_port = 0; - memset(sin->sin_zero, 0, sizeof(sin->sin_zero)); - } -#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) - else if (x->props.family == AF_INET6) { - addr->sadb_address_prefixlen = 128; - - sin6 = (struct sockaddr_in6 *) (addr + 1); - sin6->sin6_family = AF_INET6; - sin6->sin6_port = 0; - sin6->sin6_flowinfo = 0; - memcpy(&sin6->sin6_addr, - x->props.saddr.a6, sizeof(struct in6_addr)); - sin6->sin6_scope_id = 0; - } -#endif - else + addr->sadb_address_prefixlen = + pfkey_sockaddr_fill(&x->props.saddr, 0, + (struct sockaddr *) (addr + 1), + x->props.family); + if (!addr->sadb_address_prefixlen) BUG(); /* dst address */ @@ -3180,29 +3019,11 @@ static int pfkey_send_acquire(struct xfrm_state *x, struct xfrm_tmpl *t, struct addr->sadb_address_exttype = SADB_EXT_ADDRESS_DST; addr->sadb_address_proto = 0; addr->sadb_address_reserved = 0; - if (x->props.family == AF_INET) { - addr->sadb_address_prefixlen = 32; - - sin = (struct sockaddr_in *) (addr + 1); - sin->sin_family = AF_INET; - sin->sin_addr.s_addr = x->id.daddr.a4; - sin->sin_port = 0; - memset(sin->sin_zero, 0, sizeof(sin->sin_zero)); - } -#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) - else if (x->props.family == AF_INET6) { - addr->sadb_address_prefixlen = 128; - - sin6 = (struct sockaddr_in6 *) (addr + 1); - sin6->sin6_family = AF_INET6; - sin6->sin6_port = 0; - sin6->sin6_flowinfo = 0; - memcpy(&sin6->sin6_addr, - x->id.daddr.a6, sizeof(struct in6_addr)); - sin6->sin6_scope_id = 0; - } -#endif - else + addr->sadb_address_prefixlen = + pfkey_sockaddr_fill(&x->id.daddr, 0, + (struct sockaddr *) (addr + 1), + x->props.family); + if (!addr->sadb_address_prefixlen) BUG(); pol = (struct sadb_x_policy *) skb_put(skb, sizeof(struct sadb_x_policy)); @@ -3328,10 +3149,6 @@ static int pfkey_send_new_mapping(struct xfrm_state *x, xfrm_address_t *ipaddr, struct sadb_sa *sa; struct sadb_address *addr; struct sadb_x_nat_t_port *n_port; - struct sockaddr_in *sin; -#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) - struct sockaddr_in6 *sin6; -#endif int sockaddr_size; int size; __u8 satype = (x->id.proto == IPPROTO_ESP ? SADB_SATYPE_ESP : 0); @@ -3395,29 +3212,11 @@ static int pfkey_send_new_mapping(struct xfrm_state *x, xfrm_address_t *ipaddr, addr->sadb_address_exttype = SADB_EXT_ADDRESS_SRC; addr->sadb_address_proto = 0; addr->sadb_address_reserved = 0; - if (x->props.family == AF_INET) { - addr->sadb_address_prefixlen = 32; - - sin = (struct sockaddr_in *) (addr + 1); - sin->sin_family = AF_INET; - sin->sin_addr.s_addr = x->props.saddr.a4; - sin->sin_port = 0; - memset(sin->sin_zero, 0, sizeof(sin->sin_zero)); - } -#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) - else if (x->props.family == AF_INET6) { - addr->sadb_address_prefixlen = 128; - - sin6 = (struct sockaddr_in6 *) (addr + 1); - sin6->sin6_family = AF_INET6; - sin6->sin6_port = 0; - sin6->sin6_flowinfo = 0; - memcpy(&sin6->sin6_addr, - x->props.saddr.a6, sizeof(struct in6_addr)); - sin6->sin6_scope_id = 0; - } -#endif - else + addr->sadb_address_prefixlen = + pfkey_sockaddr_fill(&x->props.saddr, 0, + (struct sockaddr *) (addr + 1), + x->props.family); + if (!addr->sadb_address_prefixlen) BUG(); /* NAT_T_SPORT (old port) */ @@ -3436,28 +3235,11 @@ static int pfkey_send_new_mapping(struct xfrm_state *x, xfrm_address_t *ipaddr, addr->sadb_address_exttype = SADB_EXT_ADDRESS_DST; addr->sadb_address_proto = 0; addr->sadb_address_reserved = 0; - if (x->props.family == AF_INET) { - addr->sadb_address_prefixlen = 32; - - sin = (struct sockaddr_in *) (addr + 1); - sin->sin_family = AF_INET; - sin->sin_addr.s_addr = ipaddr->a4; - sin->sin_port = 0; - memset(sin->sin_zero, 0, sizeof(sin->sin_zero)); - } -#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) - else if (x->props.family == AF_INET6) { - addr->sadb_address_prefixlen = 128; - - sin6 = (struct sockaddr_in6 *) (addr + 1); - sin6->sin6_family = AF_INET6; - sin6->sin6_port = 0; - sin6->sin6_flowinfo = 0; - memcpy(&sin6->sin6_addr, &ipaddr->a6, sizeof(struct in6_addr)); - sin6->sin6_scope_id = 0; - } -#endif - else + addr->sadb_address_prefixlen = + pfkey_sockaddr_fill(ipaddr, 0, + (struct sockaddr *) (addr + 1), + x->props.family); + if (!addr->sadb_address_prefixlen) BUG(); /* NAT_T_DPORT (new port) */ @@ -3475,10 +3257,6 @@ static int set_sadb_address(struct sk_buff *skb, int sasize, int type, struct xfrm_selector *sel) { struct sadb_address *addr; - struct sockaddr_in *sin; -#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) - struct sockaddr_in6 *sin6; -#endif addr = (struct sadb_address *)skb_put(skb, sizeof(struct sadb_address) + sasize); addr->sadb_address_len = (sizeof(struct sadb_address) + sasize)/8; addr->sadb_address_exttype = type; @@ -3487,50 +3265,16 @@ static int set_sadb_address(struct sk_buff *skb, int sasize, int type, switch (type) { case SADB_EXT_ADDRESS_SRC: - if (sel->family == AF_INET) { - addr->sadb_address_prefixlen = sel->prefixlen_s; - sin = (struct sockaddr_in *)(addr + 1); - sin->sin_family = AF_INET; - memcpy(&sin->sin_addr.s_addr, &sel->saddr, - sizeof(sin->sin_addr.s_addr)); - sin->sin_port = 0; - memset(sin->sin_zero, 0, sizeof(sin->sin_zero)); - } -#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) - else if (sel->family == AF_INET6) { - addr->sadb_address_prefixlen = sel->prefixlen_s; - sin6 = (struct sockaddr_in6 *)(addr + 1); - sin6->sin6_family = AF_INET6; - sin6->sin6_port = 0; - sin6->sin6_flowinfo = 0; - sin6->sin6_scope_id = 0; - memcpy(&sin6->sin6_addr.s6_addr, &sel->saddr, - sizeof(sin6->sin6_addr.s6_addr)); - } -#endif + addr->sadb_address_prefixlen = sel->prefixlen_s; + pfkey_sockaddr_fill(&sel->saddr, 0, + (struct sockaddr *)(addr + 1), + sel->family); break; case SADB_EXT_ADDRESS_DST: - if (sel->family == AF_INET) { - addr->sadb_address_prefixlen = sel->prefixlen_d; - sin = (struct sockaddr_in *)(addr + 1); - sin->sin_family = AF_INET; - memcpy(&sin->sin_addr.s_addr, &sel->daddr, - sizeof(sin->sin_addr.s_addr)); - sin->sin_port = 0; - memset(sin->sin_zero, 0, sizeof(sin->sin_zero)); - } -#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) - else if (sel->family == AF_INET6) { - addr->sadb_address_prefixlen = sel->prefixlen_d; - sin6 = (struct sockaddr_in6 *)(addr + 1); - sin6->sin6_family = AF_INET6; - sin6->sin6_port = 0; - sin6->sin6_flowinfo = 0; - sin6->sin6_scope_id = 0; - memcpy(&sin6->sin6_addr.s6_addr, &sel->daddr, - sizeof(sin6->sin6_addr.s6_addr)); - } -#endif + addr->sadb_address_prefixlen = sel->prefixlen_d; + pfkey_sockaddr_fill(&sel->daddr, 0, + (struct sockaddr *)(addr + 1), + sel->family); break; default: return -EINVAL; @@ -3545,10 +3289,8 @@ static int set_ipsecrequest(struct sk_buff *skb, xfrm_address_t *src, xfrm_address_t *dst) { struct sadb_x_ipsecrequest *rq; - struct sockaddr_in *sin; -#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) - struct sockaddr_in6 *sin6; -#endif + u8 *sa; + int socklen = pfkey_sockaddr_len(family); int size_req; size_req = sizeof(struct sadb_x_ipsecrequest) + @@ -3562,38 +3304,10 @@ static int set_ipsecrequest(struct sk_buff *skb, rq->sadb_x_ipsecrequest_level = level; rq->sadb_x_ipsecrequest_reqid = reqid; - switch (family) { - case AF_INET: - sin = (struct sockaddr_in *)(rq + 1); - sin->sin_family = AF_INET; - memcpy(&sin->sin_addr.s_addr, src, - sizeof(sin->sin_addr.s_addr)); - sin++; - sin->sin_family = AF_INET; - memcpy(&sin->sin_addr.s_addr, dst, - sizeof(sin->sin_addr.s_addr)); - break; -#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) - case AF_INET6: - sin6 = (struct sockaddr_in6 *)(rq + 1); - sin6->sin6_family = AF_INET6; - sin6->sin6_port = 0; - sin6->sin6_flowinfo = 0; - sin6->sin6_scope_id = 0; - memcpy(&sin6->sin6_addr.s6_addr, src, - sizeof(sin6->sin6_addr.s6_addr)); - sin6++; - sin6->sin6_family = AF_INET6; - sin6->sin6_port = 0; - sin6->sin6_flowinfo = 0; - sin6->sin6_scope_id = 0; - memcpy(&sin6->sin6_addr.s6_addr, dst, - sizeof(sin6->sin6_addr.s6_addr)); - break; -#endif - default: + sa = (u8 *) (rq + 1); + if (!pfkey_sockaddr_fill(src, 0, (struct sockaddr *)sa, family) || + !pfkey_sockaddr_fill(dst, 0, (struct sockaddr *)(sa + socklen), family)) return -EINVAL; - } return 0; } diff --git a/net/llc/af_llc.c b/net/llc/af_llc.c index 97101dcde4c0..5bcc452a247f 100644 --- a/net/llc/af_llc.c +++ b/net/llc/af_llc.c @@ -128,10 +128,8 @@ static int llc_ui_send_data(struct sock* sk, struct sk_buff *skb, int noblock) static void llc_ui_sk_init(struct socket *sock, struct sock *sk) { + sock_graft(sk, sock); sk->sk_type = sock->type; - sk->sk_sleep = &sock->wait; - sk->sk_socket = sock; - sock->sk = sk; sock->ops = &llc_ui_ops; } diff --git a/net/llc/llc_input.c b/net/llc/llc_input.c index 1c45f172991e..57ad974e4d94 100644 --- a/net/llc/llc_input.c +++ b/net/llc/llc_input.c @@ -150,7 +150,7 @@ int llc_rcv(struct sk_buff *skb, struct net_device *dev, int (*rcv)(struct sk_buff *, struct net_device *, struct packet_type *, struct net_device *); - if (dev_net(dev) != &init_net) + if (!net_eq(dev_net(dev), &init_net)) goto drop; /* diff --git a/net/mac80211/Kconfig b/net/mac80211/Kconfig index a24b459dd45a..80d693392b0f 100644 --- a/net/mac80211/Kconfig +++ b/net/mac80211/Kconfig @@ -7,7 +7,6 @@ config MAC80211 select CRC32 select WIRELESS_EXT select CFG80211 - select NET_SCH_FIFO ---help--- This option enables the hardware independent IEEE 802.11 networking stack. @@ -15,6 +14,14 @@ config MAC80211 menu "Rate control algorithm selection" depends on MAC80211 != n +config MAC80211_RC_PID + bool "PID controller based rate control algorithm" if EMBEDDED + default y + ---help--- + This option enables a TX rate control algorithm for + mac80211 that uses a PID controller to select the TX + rate. + choice prompt "Default rate control algorithm" default MAC80211_RC_DEFAULT_PID @@ -26,40 +33,19 @@ choice config MAC80211_RC_DEFAULT_PID bool "PID controller based rate control algorithm" - select MAC80211_RC_PID + depends on MAC80211_RC_PID ---help--- Select the PID controller based rate control as the default rate control algorithm. You should choose this unless you know what you are doing. -config MAC80211_RC_DEFAULT_NONE - bool "No default algorithm" - depends on EMBEDDED - help - Selecting this option will select no default algorithm - and allow you to not build any. Do not choose this - option unless you know your driver comes with another - suitable algorithm. endchoice -comment "Selecting 'y' for an algorithm will" -comment "build the algorithm into mac80211." - config MAC80211_RC_DEFAULT string default "pid" if MAC80211_RC_DEFAULT_PID default "" -config MAC80211_RC_PID - tristate "PID controller based rate control algorithm" - ---help--- - This option enables a TX rate control algorithm for - mac80211 that uses a PID controller to select the TX - rate. - - Say Y or M unless you're sure you want to use a - different rate control algorithm. - endmenu config MAC80211_MESH @@ -89,10 +75,16 @@ config MAC80211_DEBUGFS Say N unless you know you need this. +menuconfig MAC80211_DEBUG_MENU + bool "Select mac80211 debugging features" + depends on MAC80211 + ---help--- + This option collects various mac80211 debug settings. + config MAC80211_DEBUG_PACKET_ALIGNMENT bool "Enable packet alignment debugging" - depends on MAC80211 - help + depends on MAC80211_DEBUG_MENU + ---help--- This option is recommended for driver authors and strongly discouraged for everybody else, it will trigger a warning when a driver hands mac80211 a buffer that is aligned in @@ -101,33 +93,95 @@ config MAC80211_DEBUG_PACKET_ALIGNMENT Say N unless you're writing a mac80211 based driver. -config MAC80211_DEBUG - bool "Enable debugging output" - depends on MAC80211 +config MAC80211_NOINLINE + bool "Do not inline TX/RX handlers" + depends on MAC80211_DEBUG_MENU ---help--- - This option will enable debug tracing output for the - ieee80211 network stack. + This option affects code generation in mac80211, when + selected some functions are marked "noinline" to allow + easier debugging of problems in the transmit and receive + paths. + + This option increases code size a bit and inserts a lot + of function calls in the code, but is otherwise safe to + enable. - If you are not trying to debug or develop the ieee80211 - subsystem, you most likely want to say N here. + If unsure, say N unless you expect to be finding problems + in mac80211. + +config MAC80211_VERBOSE_DEBUG + bool "Verbose debugging output" + depends on MAC80211_DEBUG_MENU + ---help--- + Selecting this option causes mac80211 to print out + many debugging messages. It should not be selected + on production systems as some of the messages are + remotely triggerable. + + Do not select this option. config MAC80211_HT_DEBUG - bool "Enable HT debugging output" - depends on MAC80211_DEBUG + bool "Verbose HT debugging" + depends on MAC80211_DEBUG_MENU ---help--- This option enables 802.11n High Throughput features debug tracing output. - If you are not trying to debug of develop the ieee80211 - subsystem, you most likely want to say N here. + It should not be selected on production systems as some + of the messages are remotely triggerable. -config MAC80211_VERBOSE_DEBUG - bool "Verbose debugging output" - depends on MAC80211_DEBUG + Do not select this option. + +config MAC80211_TKIP_DEBUG + bool "Verbose TKIP debugging" + depends on MAC80211_DEBUG_MENU + ---help--- + Selecting this option causes mac80211 to print out + very verbose TKIP debugging messages. It should not + be selected on production systems as those messages + are remotely triggerable. + + Do not select this option. + +config MAC80211_IBSS_DEBUG + bool "Verbose IBSS debugging" + depends on MAC80211_DEBUG_MENU + ---help--- + Selecting this option causes mac80211 to print out + very verbose IBSS debugging messages. It should not + be selected on production systems as those messages + are remotely triggerable. + + Do not select this option. + +config MAC80211_VERBOSE_PS_DEBUG + bool "Verbose powersave mode debugging" + depends on MAC80211_DEBUG_MENU + ---help--- + Selecting this option causes mac80211 to print out very + verbose power save mode debugging messages (when mac80211 + is an AP and has power saving stations.) + It should not be selected on production systems as those + messages are remotely triggerable. + + Do not select this option. + +config MAC80211_VERBOSE_MPL_DEBUG + bool "Verbose mesh peer link debugging" + depends on MAC80211_DEBUG_MENU + depends on MAC80211_MESH + ---help--- + Selecting this option causes mac80211 to print out very + verbose mesh peer link debugging messages (when mac80211 + is taking part in a mesh network). + It should not be selected on production systems as those + messages are remotely triggerable. + + Do not select this option. config MAC80211_LOWTX_FRAME_DUMP bool "Debug frame dumping" - depends on MAC80211_DEBUG + depends on MAC80211_DEBUG_MENU ---help--- Selecting this option will cause the stack to print a message for each frame that is handed @@ -138,30 +192,20 @@ config MAC80211_LOWTX_FRAME_DUMP If unsure, say N and insert the debugging code you require into the driver you are debugging. -config TKIP_DEBUG - bool "TKIP debugging" - depends on MAC80211_DEBUG - config MAC80211_DEBUG_COUNTERS bool "Extra statistics for TX/RX debugging" - depends on MAC80211_DEBUG - -config MAC80211_IBSS_DEBUG - bool "Support for IBSS testing" - depends on MAC80211_DEBUG + depends on MAC80211_DEBUG_MENU + depends on MAC80211_DEBUGFS ---help--- - Say Y here if you intend to debug the IBSS code. + Selecting this option causes mac80211 to keep additional + and very verbose statistics about TX and RX handler use + and show them in debugfs. -config MAC80211_VERBOSE_PS_DEBUG - bool "Verbose powersave mode debugging" - depends on MAC80211_DEBUG - ---help--- - Say Y here to print out verbose powersave - mode debug messages. + If unsure, say N. -config MAC80211_VERBOSE_MPL_DEBUG - bool "Verbose mesh peer link debugging" - depends on MAC80211_DEBUG && MAC80211_MESH +config MAC80211_VERBOSE_SPECT_MGMT_DEBUG + bool "Verbose Spectrum Management (IEEE 802.11h)debugging" + depends on MAC80211_DEBUG_MENU ---help--- - Say Y here to print out verbose mesh peer link + Say Y here to print out verbose Spectrum Management (IEEE 802.11h) debug messages. diff --git a/net/mac80211/Makefile b/net/mac80211/Makefile index 4e5847fd316c..a169b0201d61 100644 --- a/net/mac80211/Makefile +++ b/net/mac80211/Makefile @@ -1,13 +1,5 @@ obj-$(CONFIG_MAC80211) += mac80211.o -# objects for PID algorithm -rc80211_pid-y := rc80211_pid_algo.o -rc80211_pid-$(CONFIG_MAC80211_DEBUGFS) += rc80211_pid_debugfs.o - -# build helper for PID algorithm -rc-pid-y := $(rc80211_pid-y) -rc-pid-m := rc80211_pid.o - # mac80211 objects mac80211-y := \ main.o \ @@ -26,10 +18,10 @@ mac80211-y := \ tx.o \ key.o \ util.o \ + wme.o \ event.o mac80211-$(CONFIG_MAC80211_LEDS) += led.o -mac80211-$(CONFIG_NET_SCHED) += wme.o mac80211-$(CONFIG_MAC80211_DEBUGFS) += \ debugfs.o \ debugfs_sta.o \ @@ -42,10 +34,8 @@ mac80211-$(CONFIG_MAC80211_MESH) += \ mesh_plink.o \ mesh_hwmp.o +# objects for PID algorithm +rc80211_pid-y := rc80211_pid_algo.o +rc80211_pid-$(CONFIG_MAC80211_DEBUGFS) += rc80211_pid_debugfs.o -# Build rate control algorithm(s) -CFLAGS_rc80211_pid_algo.o += -DRC80211_PID_COMPILE -mac80211-$(CONFIG_MAC80211_RC_PID) += $(rc-pid-$(CONFIG_MAC80211_RC_PID)) - -# Modular rate algorithms are assigned to mac80211-m - make separate modules -obj-m += $(mac80211-m) +mac80211-$(CONFIG_MAC80211_RC_PID) += $(rc80211_pid-y) diff --git a/net/mac80211/aes_ccm.c b/net/mac80211/aes_ccm.c index 59f1691f62c8..a87cb3ba2df6 100644 --- a/net/mac80211/aes_ccm.c +++ b/net/mac80211/aes_ccm.c @@ -16,31 +16,28 @@ #include "key.h" #include "aes_ccm.h" - -static void ieee80211_aes_encrypt(struct crypto_cipher *tfm, - const u8 pt[16], u8 ct[16]) -{ - crypto_cipher_encrypt_one(tfm, ct, pt); -} - - -static inline void aes_ccm_prepare(struct crypto_cipher *tfm, u8 *b_0, u8 *aad, - u8 *b, u8 *s_0, u8 *a) +static void aes_ccm_prepare(struct crypto_cipher *tfm, u8 *scratch, u8 *a) { int i; + u8 *b_0, *aad, *b, *s_0; - ieee80211_aes_encrypt(tfm, b_0, b); + b_0 = scratch + 3 * AES_BLOCK_LEN; + aad = scratch + 4 * AES_BLOCK_LEN; + b = scratch; + s_0 = scratch + AES_BLOCK_LEN; + + crypto_cipher_encrypt_one(tfm, b, b_0); /* Extra Authenticate-only data (always two AES blocks) */ for (i = 0; i < AES_BLOCK_LEN; i++) aad[i] ^= b[i]; - ieee80211_aes_encrypt(tfm, aad, b); + crypto_cipher_encrypt_one(tfm, b, aad); aad += AES_BLOCK_LEN; for (i = 0; i < AES_BLOCK_LEN; i++) aad[i] ^= b[i]; - ieee80211_aes_encrypt(tfm, aad, a); + crypto_cipher_encrypt_one(tfm, a, aad); /* Mask out bits from auth-only-b_0 */ b_0[0] &= 0x07; @@ -48,24 +45,26 @@ static inline void aes_ccm_prepare(struct crypto_cipher *tfm, u8 *b_0, u8 *aad, /* S_0 is used to encrypt T (= MIC) */ b_0[14] = 0; b_0[15] = 0; - ieee80211_aes_encrypt(tfm, b_0, s_0); + crypto_cipher_encrypt_one(tfm, s_0, b_0); } void ieee80211_aes_ccm_encrypt(struct crypto_cipher *tfm, u8 *scratch, - u8 *b_0, u8 *aad, u8 *data, size_t data_len, + u8 *data, size_t data_len, u8 *cdata, u8 *mic) { int i, j, last_len, num_blocks; - u8 *pos, *cpos, *b, *s_0, *e; + u8 *pos, *cpos, *b, *s_0, *e, *b_0, *aad; b = scratch; s_0 = scratch + AES_BLOCK_LEN; e = scratch + 2 * AES_BLOCK_LEN; + b_0 = scratch + 3 * AES_BLOCK_LEN; + aad = scratch + 4 * AES_BLOCK_LEN; num_blocks = DIV_ROUND_UP(data_len, AES_BLOCK_LEN); last_len = data_len % AES_BLOCK_LEN; - aes_ccm_prepare(tfm, b_0, aad, b, s_0, b); + aes_ccm_prepare(tfm, scratch, b); /* Process payload blocks */ pos = data; @@ -77,11 +76,11 @@ void ieee80211_aes_ccm_encrypt(struct crypto_cipher *tfm, u8 *scratch, /* Authentication followed by encryption */ for (i = 0; i < blen; i++) b[i] ^= pos[i]; - ieee80211_aes_encrypt(tfm, b, b); + crypto_cipher_encrypt_one(tfm, b, b); b_0[14] = (j >> 8) & 0xff; b_0[15] = j & 0xff; - ieee80211_aes_encrypt(tfm, b_0, e); + crypto_cipher_encrypt_one(tfm, e, b_0); for (i = 0; i < blen; i++) *cpos++ = *pos++ ^ e[i]; } @@ -92,19 +91,20 @@ void ieee80211_aes_ccm_encrypt(struct crypto_cipher *tfm, u8 *scratch, int ieee80211_aes_ccm_decrypt(struct crypto_cipher *tfm, u8 *scratch, - u8 *b_0, u8 *aad, u8 *cdata, size_t data_len, - u8 *mic, u8 *data) + u8 *cdata, size_t data_len, u8 *mic, u8 *data) { int i, j, last_len, num_blocks; - u8 *pos, *cpos, *b, *s_0, *a; + u8 *pos, *cpos, *b, *s_0, *a, *b_0, *aad; b = scratch; s_0 = scratch + AES_BLOCK_LEN; a = scratch + 2 * AES_BLOCK_LEN; + b_0 = scratch + 3 * AES_BLOCK_LEN; + aad = scratch + 4 * AES_BLOCK_LEN; num_blocks = DIV_ROUND_UP(data_len, AES_BLOCK_LEN); last_len = data_len % AES_BLOCK_LEN; - aes_ccm_prepare(tfm, b_0, aad, b, s_0, a); + aes_ccm_prepare(tfm, scratch, a); /* Process payload blocks */ cpos = cdata; @@ -116,13 +116,12 @@ int ieee80211_aes_ccm_decrypt(struct crypto_cipher *tfm, u8 *scratch, /* Decryption followed by authentication */ b_0[14] = (j >> 8) & 0xff; b_0[15] = j & 0xff; - ieee80211_aes_encrypt(tfm, b_0, b); + crypto_cipher_encrypt_one(tfm, b, b_0); for (i = 0; i < blen; i++) { *pos = *cpos++ ^ b[i]; a[i] ^= *pos++; } - - ieee80211_aes_encrypt(tfm, a, a); + crypto_cipher_encrypt_one(tfm, a, a); } for (i = 0; i < CCMP_MIC_LEN; i++) { @@ -134,7 +133,7 @@ int ieee80211_aes_ccm_decrypt(struct crypto_cipher *tfm, u8 *scratch, } -struct crypto_cipher * ieee80211_aes_key_setup_encrypt(const u8 key[]) +struct crypto_cipher *ieee80211_aes_key_setup_encrypt(const u8 key[]) { struct crypto_cipher *tfm; diff --git a/net/mac80211/aes_ccm.h b/net/mac80211/aes_ccm.h index 885f19030b29..6e7820ef3448 100644 --- a/net/mac80211/aes_ccm.h +++ b/net/mac80211/aes_ccm.h @@ -14,12 +14,12 @@ #define AES_BLOCK_LEN 16 -struct crypto_cipher * ieee80211_aes_key_setup_encrypt(const u8 key[]); +struct crypto_cipher *ieee80211_aes_key_setup_encrypt(const u8 key[]); void ieee80211_aes_ccm_encrypt(struct crypto_cipher *tfm, u8 *scratch, - u8 *b_0, u8 *aad, u8 *data, size_t data_len, + u8 *data, size_t data_len, u8 *cdata, u8 *mic); int ieee80211_aes_ccm_decrypt(struct crypto_cipher *tfm, u8 *scratch, - u8 *b_0, u8 *aad, u8 *cdata, size_t data_len, + u8 *cdata, size_t data_len, u8 *mic, u8 *data); void ieee80211_aes_key_free(struct crypto_cipher *tfm); diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index a9fce4afdf21..8e7ba0e62cf5 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -50,14 +50,11 @@ static int ieee80211_add_iface(struct wiphy *wiphy, char *name, struct ieee80211_sub_if_data *sdata; int err; - if (unlikely(local->reg_state != IEEE80211_DEV_REGISTERED)) - return -ENODEV; - itype = nl80211_type_to_mac80211_type(type); if (itype == IEEE80211_IF_TYPE_INVALID) return -EINVAL; - err = ieee80211_if_add(local->mdev, name, &dev, itype, params); + err = ieee80211_if_add(local, name, &dev, itype, params); if (err || itype != IEEE80211_IF_TYPE_MNTR || !flags) return err; @@ -68,54 +65,41 @@ static int ieee80211_add_iface(struct wiphy *wiphy, char *name, static int ieee80211_del_iface(struct wiphy *wiphy, int ifindex) { - struct ieee80211_local *local = wiphy_priv(wiphy); struct net_device *dev; - char *name; - - if (unlikely(local->reg_state != IEEE80211_DEV_REGISTERED)) - return -ENODEV; /* we're under RTNL */ dev = __dev_get_by_index(&init_net, ifindex); if (!dev) - return 0; + return -ENODEV; - name = dev->name; + ieee80211_if_remove(dev); - return ieee80211_if_remove(local->mdev, name, -1); + return 0; } static int ieee80211_change_iface(struct wiphy *wiphy, int ifindex, enum nl80211_iftype type, u32 *flags, struct vif_params *params) { - struct ieee80211_local *local = wiphy_priv(wiphy); struct net_device *dev; enum ieee80211_if_types itype; struct ieee80211_sub_if_data *sdata; - - if (unlikely(local->reg_state != IEEE80211_DEV_REGISTERED)) - return -ENODEV; + int ret; /* we're under RTNL */ dev = __dev_get_by_index(&init_net, ifindex); if (!dev) return -ENODEV; - if (netif_running(dev)) - return -EBUSY; - itype = nl80211_type_to_mac80211_type(type); if (itype == IEEE80211_IF_TYPE_INVALID) return -EINVAL; sdata = IEEE80211_DEV_TO_SUB_IF(dev); - if (sdata->vif.type == IEEE80211_IF_TYPE_VLAN) - return -EOPNOTSUPP; - - ieee80211_if_reinit(dev); - ieee80211_if_set_type(dev, itype); + ret = ieee80211_if_change_type(sdata, itype); + if (ret) + return ret; if (ieee80211_vif_is_mesh(&sdata->vif) && params->mesh_id_len) ieee80211_if_sta_set_mesh_id(&sdata->u.sta, @@ -256,8 +240,8 @@ static int ieee80211_get_key(struct wiphy *wiphy, struct net_device *dev, case ALG_TKIP: params.cipher = WLAN_CIPHER_SUITE_TKIP; - iv32 = key->u.tkip.iv32; - iv16 = key->u.tkip.iv16; + 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) @@ -485,7 +469,7 @@ static int ieee80211_config_beacon(struct ieee80211_sub_if_data *sdata, kfree(old); - return ieee80211_if_config_beacon(sdata->dev); + return ieee80211_if_config(sdata, IEEE80211_IFCC_BEACON); } static int ieee80211_add_beacon(struct wiphy *wiphy, struct net_device *dev, @@ -539,7 +523,7 @@ static int ieee80211_del_beacon(struct wiphy *wiphy, struct net_device *dev) synchronize_rcu(); kfree(old); - return ieee80211_if_config_beacon(dev); + return ieee80211_if_config(sdata, IEEE80211_IFCC_BEACON); } /* Layer 2 Update frame (802.2 Type 1 LLC XID Update response) */ @@ -602,6 +586,7 @@ static void sta_apply_parameters(struct ieee80211_local *local, */ if (params->station_flags & STATION_FLAG_CHANGED) { + spin_lock_bh(&sta->lock); sta->flags &= ~WLAN_STA_AUTHORIZED; if (params->station_flags & STATION_FLAG_AUTHORIZED) sta->flags |= WLAN_STA_AUTHORIZED; @@ -613,6 +598,7 @@ static void sta_apply_parameters(struct ieee80211_local *local, sta->flags &= ~WLAN_STA_WME; if (params->station_flags & STATION_FLAG_WME) sta->flags |= WLAN_STA_WME; + spin_unlock_bh(&sta->lock); } /* diff --git a/net/mac80211/debugfs.c b/net/mac80211/debugfs.c index 1cccbfd781f6..ee509f1109e2 100644 --- a/net/mac80211/debugfs.c +++ b/net/mac80211/debugfs.c @@ -70,16 +70,6 @@ DEBUGFS_READONLY_FILE(rate_ctrl_alg, 100, "%s", /* statistics stuff */ -static inline int rtnl_lock_local(struct ieee80211_local *local) -{ - rtnl_lock(); - if (unlikely(local->reg_state != IEEE80211_DEV_REGISTERED)) { - rtnl_unlock(); - return -ENODEV; - } - return 0; -} - #define DEBUGFS_STATS_FILE(name, buflen, fmt, value...) \ DEBUGFS_READONLY_FILE(stats_ ##name, buflen, fmt, ##value) @@ -96,10 +86,7 @@ static ssize_t format_devstat_counter(struct ieee80211_local *local, if (!local->ops->get_stats) return -EOPNOTSUPP; - res = rtnl_lock_local(local); - if (res) - return res; - + rtnl_lock(); res = local->ops->get_stats(local_to_hw(local), &stats); rtnl_unlock(); if (!res) @@ -197,45 +184,6 @@ DEBUGFS_STATS_FILE(rx_handlers_fragments, 20, "%u", DEBUGFS_STATS_FILE(tx_status_drop, 20, "%u", local->tx_status_drop); -static ssize_t stats_wme_rx_queue_read(struct file *file, - char __user *userbuf, - size_t count, loff_t *ppos) -{ - struct ieee80211_local *local = file->private_data; - char buf[NUM_RX_DATA_QUEUES*15], *p = buf; - int i; - - for (i = 0; i < NUM_RX_DATA_QUEUES; i++) - p += scnprintf(p, sizeof(buf)+buf-p, - "%u\n", local->wme_rx_queue[i]); - - return simple_read_from_buffer(userbuf, count, ppos, buf, p-buf); -} - -static const struct file_operations stats_wme_rx_queue_ops = { - .read = stats_wme_rx_queue_read, - .open = mac80211_open_file_generic, -}; - -static ssize_t stats_wme_tx_queue_read(struct file *file, - char __user *userbuf, - size_t count, loff_t *ppos) -{ - struct ieee80211_local *local = file->private_data; - char buf[NUM_TX_DATA_QUEUES*15], *p = buf; - int i; - - for (i = 0; i < NUM_TX_DATA_QUEUES; i++) - p += scnprintf(p, sizeof(buf)+buf-p, - "%u\n", local->wme_tx_queue[i]); - - return simple_read_from_buffer(userbuf, count, ppos, buf, p-buf); -} - -static const struct file_operations stats_wme_tx_queue_ops = { - .read = stats_wme_tx_queue_read, - .open = mac80211_open_file_generic, -}; #endif DEBUGFS_DEVSTATS_FILE(dot11ACKFailureCount); @@ -303,8 +251,6 @@ void debugfs_hw_add(struct ieee80211_local *local) DEBUGFS_STATS_ADD(rx_expand_skb_head2); DEBUGFS_STATS_ADD(rx_handlers_fragments); DEBUGFS_STATS_ADD(tx_status_drop); - DEBUGFS_STATS_ADD(wme_tx_queue); - DEBUGFS_STATS_ADD(wme_rx_queue); #endif DEBUGFS_STATS_ADD(dot11ACKFailureCount); DEBUGFS_STATS_ADD(dot11RTSFailureCount); @@ -356,8 +302,6 @@ void debugfs_hw_del(struct ieee80211_local *local) DEBUGFS_STATS_DEL(rx_expand_skb_head2); DEBUGFS_STATS_DEL(rx_handlers_fragments); DEBUGFS_STATS_DEL(tx_status_drop); - DEBUGFS_STATS_DEL(wme_tx_queue); - DEBUGFS_STATS_DEL(wme_rx_queue); #endif DEBUGFS_STATS_DEL(dot11ACKFailureCount); DEBUGFS_STATS_DEL(dot11RTSFailureCount); diff --git a/net/mac80211/debugfs_key.c b/net/mac80211/debugfs_key.c index 19efc3a6a932..7439b63df5d0 100644 --- a/net/mac80211/debugfs_key.c +++ b/net/mac80211/debugfs_key.c @@ -97,8 +97,8 @@ static ssize_t key_tx_spec_read(struct file *file, char __user *userbuf, break; case ALG_TKIP: len = scnprintf(buf, sizeof(buf), "%08x %04x\n", - key->u.tkip.iv32, - key->u.tkip.iv16); + key->u.tkip.tx.iv32, + key->u.tkip.tx.iv16); break; case ALG_CCMP: tpn = key->u.ccmp.tx_pn; @@ -128,8 +128,8 @@ static ssize_t key_rx_spec_read(struct file *file, char __user *userbuf, for (i = 0; i < NUM_RX_DATA_QUEUES; i++) p += scnprintf(p, sizeof(buf)+buf-p, "%08x %04x\n", - key->u.tkip.iv32_rx[i], - key->u.tkip.iv16_rx[i]); + key->u.tkip.rx[i].iv32, + key->u.tkip.rx[i].iv16); len = p - buf; break; case ALG_CCMP: diff --git a/net/mac80211/debugfs_netdev.c b/net/mac80211/debugfs_netdev.c index e3326d046944..475f89a8aee1 100644 --- a/net/mac80211/debugfs_netdev.c +++ b/net/mac80211/debugfs_netdev.c @@ -155,8 +155,9 @@ static const struct file_operations name##_ops = { \ __IEEE80211_IF_WFILE(name) /* common attributes */ -IEEE80211_IF_FILE(channel_use, channel_use, DEC); IEEE80211_IF_FILE(drop_unencrypted, drop_unencrypted, DEC); +IEEE80211_IF_FILE(force_unicast_rateidx, force_unicast_rateidx, DEC); +IEEE80211_IF_FILE(max_ratectrl_rateidx, max_ratectrl_rateidx, DEC); /* STA/IBSS attributes */ IEEE80211_IF_FILE(state, u.sta.state, DEC); @@ -192,8 +193,6 @@ __IEEE80211_IF_FILE(flags); IEEE80211_IF_FILE(num_sta_ps, u.ap.num_sta_ps, ATOMIC); IEEE80211_IF_FILE(dtim_count, u.ap.dtim_count, DEC); IEEE80211_IF_FILE(num_beacons, u.ap.num_beacons, DEC); -IEEE80211_IF_FILE(force_unicast_rateidx, u.ap.force_unicast_rateidx, DEC); -IEEE80211_IF_FILE(max_ratectrl_rateidx, u.ap.max_ratectrl_rateidx, DEC); static ssize_t ieee80211_if_fmt_num_buffered_multicast( const struct ieee80211_sub_if_data *sdata, char *buf, int buflen) @@ -248,8 +247,10 @@ IEEE80211_IF_WFILE(min_discovery_timeout, static void add_sta_files(struct ieee80211_sub_if_data *sdata) { - DEBUGFS_ADD(channel_use, sta); DEBUGFS_ADD(drop_unencrypted, sta); + DEBUGFS_ADD(force_unicast_rateidx, ap); + DEBUGFS_ADD(max_ratectrl_rateidx, ap); + DEBUGFS_ADD(state, sta); DEBUGFS_ADD(bssid, sta); DEBUGFS_ADD(prev_bssid, sta); @@ -269,27 +270,30 @@ static void add_sta_files(struct ieee80211_sub_if_data *sdata) static void add_ap_files(struct ieee80211_sub_if_data *sdata) { - DEBUGFS_ADD(channel_use, ap); DEBUGFS_ADD(drop_unencrypted, ap); + DEBUGFS_ADD(force_unicast_rateidx, ap); + DEBUGFS_ADD(max_ratectrl_rateidx, ap); + DEBUGFS_ADD(num_sta_ps, ap); DEBUGFS_ADD(dtim_count, ap); DEBUGFS_ADD(num_beacons, ap); - DEBUGFS_ADD(force_unicast_rateidx, ap); - DEBUGFS_ADD(max_ratectrl_rateidx, ap); DEBUGFS_ADD(num_buffered_multicast, ap); } static void add_wds_files(struct ieee80211_sub_if_data *sdata) { - DEBUGFS_ADD(channel_use, wds); DEBUGFS_ADD(drop_unencrypted, wds); + DEBUGFS_ADD(force_unicast_rateidx, ap); + DEBUGFS_ADD(max_ratectrl_rateidx, ap); + DEBUGFS_ADD(peer, wds); } static void add_vlan_files(struct ieee80211_sub_if_data *sdata) { - DEBUGFS_ADD(channel_use, vlan); DEBUGFS_ADD(drop_unencrypted, vlan); + DEBUGFS_ADD(force_unicast_rateidx, ap); + DEBUGFS_ADD(max_ratectrl_rateidx, ap); } static void add_monitor_files(struct ieee80211_sub_if_data *sdata) @@ -376,8 +380,10 @@ static void add_files(struct ieee80211_sub_if_data *sdata) static void del_sta_files(struct ieee80211_sub_if_data *sdata) { - DEBUGFS_DEL(channel_use, sta); DEBUGFS_DEL(drop_unencrypted, sta); + DEBUGFS_DEL(force_unicast_rateidx, ap); + DEBUGFS_DEL(max_ratectrl_rateidx, ap); + DEBUGFS_DEL(state, sta); DEBUGFS_DEL(bssid, sta); DEBUGFS_DEL(prev_bssid, sta); @@ -397,27 +403,30 @@ static void del_sta_files(struct ieee80211_sub_if_data *sdata) static void del_ap_files(struct ieee80211_sub_if_data *sdata) { - DEBUGFS_DEL(channel_use, ap); DEBUGFS_DEL(drop_unencrypted, ap); + DEBUGFS_DEL(force_unicast_rateidx, ap); + DEBUGFS_DEL(max_ratectrl_rateidx, ap); + DEBUGFS_DEL(num_sta_ps, ap); DEBUGFS_DEL(dtim_count, ap); DEBUGFS_DEL(num_beacons, ap); - DEBUGFS_DEL(force_unicast_rateidx, ap); - DEBUGFS_DEL(max_ratectrl_rateidx, ap); DEBUGFS_DEL(num_buffered_multicast, ap); } static void del_wds_files(struct ieee80211_sub_if_data *sdata) { - DEBUGFS_DEL(channel_use, wds); DEBUGFS_DEL(drop_unencrypted, wds); + DEBUGFS_DEL(force_unicast_rateidx, ap); + DEBUGFS_DEL(max_ratectrl_rateidx, ap); + DEBUGFS_DEL(peer, wds); } static void del_vlan_files(struct ieee80211_sub_if_data *sdata) { - DEBUGFS_DEL(channel_use, vlan); DEBUGFS_DEL(drop_unencrypted, vlan); + DEBUGFS_DEL(force_unicast_rateidx, ap); + DEBUGFS_DEL(max_ratectrl_rateidx, ap); } static void del_monitor_files(struct ieee80211_sub_if_data *sdata) @@ -467,12 +476,12 @@ static void del_mesh_config(struct ieee80211_sub_if_data *sdata) } #endif -static void del_files(struct ieee80211_sub_if_data *sdata, int type) +static void del_files(struct ieee80211_sub_if_data *sdata) { if (!sdata->debugfsdir) return; - switch (type) { + switch (sdata->vif.type) { case IEEE80211_IF_TYPE_MESH_POINT: #ifdef CONFIG_MAC80211_MESH del_mesh_stats(sdata); @@ -512,29 +521,23 @@ void ieee80211_debugfs_add_netdev(struct ieee80211_sub_if_data *sdata) sprintf(buf, "netdev:%s", sdata->dev->name); sdata->debugfsdir = debugfs_create_dir(buf, sdata->local->hw.wiphy->debugfsdir); + add_files(sdata); } void ieee80211_debugfs_remove_netdev(struct ieee80211_sub_if_data *sdata) { - del_files(sdata, sdata->vif.type); + del_files(sdata); debugfs_remove(sdata->debugfsdir); sdata->debugfsdir = NULL; } -void ieee80211_debugfs_change_if_type(struct ieee80211_sub_if_data *sdata, - int oldtype) -{ - del_files(sdata, oldtype); - add_files(sdata); -} - -static int netdev_notify(struct notifier_block * nb, +static int netdev_notify(struct notifier_block *nb, unsigned long state, void *ndev) { struct net_device *dev = ndev; struct dentry *dir; - struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + struct ieee80211_sub_if_data *sdata; char buf[10+IFNAMSIZ]; if (state != NETDEV_CHANGENAME) @@ -546,6 +549,8 @@ static int netdev_notify(struct notifier_block * nb, if (dev->ieee80211_ptr->wiphy->privid != mac80211_wiphy_privid) return 0; + sdata = IEEE80211_DEV_TO_SUB_IF(dev); + sprintf(buf, "netdev:%s", dev->name); dir = sdata->debugfsdir; if (!debugfs_rename(dir->d_parent, dir, dir->d_parent, buf)) diff --git a/net/mac80211/debugfs_netdev.h b/net/mac80211/debugfs_netdev.h index a690071fde8a..7af731f0b731 100644 --- a/net/mac80211/debugfs_netdev.h +++ b/net/mac80211/debugfs_netdev.h @@ -6,8 +6,6 @@ #ifdef CONFIG_MAC80211_DEBUGFS void ieee80211_debugfs_add_netdev(struct ieee80211_sub_if_data *sdata); void ieee80211_debugfs_remove_netdev(struct ieee80211_sub_if_data *sdata); -void ieee80211_debugfs_change_if_type(struct ieee80211_sub_if_data *sdata, - int oldtype); void ieee80211_debugfs_netdev_init(void); void ieee80211_debugfs_netdev_exit(void); #else @@ -17,9 +15,6 @@ static inline void ieee80211_debugfs_add_netdev( static inline void ieee80211_debugfs_remove_netdev( struct ieee80211_sub_if_data *sdata) {} -static inline void ieee80211_debugfs_change_if_type( - struct ieee80211_sub_if_data *sdata, int oldtype) -{} static inline void ieee80211_debugfs_netdev_init(void) {} diff --git a/net/mac80211/debugfs_sta.c b/net/mac80211/debugfs_sta.c index 6d47a1d31b37..79a062782d52 100644 --- a/net/mac80211/debugfs_sta.c +++ b/net/mac80211/debugfs_sta.c @@ -63,10 +63,9 @@ STA_FILE(tx_fragments, tx_fragments, LU); STA_FILE(tx_filtered, tx_filtered_count, LU); STA_FILE(tx_retry_failed, tx_retry_failed, LU); STA_FILE(tx_retry_count, tx_retry_count, LU); -STA_FILE(last_rssi, last_rssi, D); STA_FILE(last_signal, last_signal, D); +STA_FILE(last_qual, last_qual, D); STA_FILE(last_noise, last_noise, D); -STA_FILE(channel_use, channel_use, D); STA_FILE(wep_weak_iv_count, wep_weak_iv_count, LU); static ssize_t sta_flags_read(struct file *file, char __user *userbuf, @@ -74,14 +73,15 @@ static ssize_t sta_flags_read(struct file *file, char __user *userbuf, { char buf[100]; struct sta_info *sta = file->private_data; + u32 staflags = get_sta_flags(sta); int res = scnprintf(buf, sizeof(buf), "%s%s%s%s%s%s%s", - sta->flags & WLAN_STA_AUTH ? "AUTH\n" : "", - sta->flags & WLAN_STA_ASSOC ? "ASSOC\n" : "", - sta->flags & WLAN_STA_PS ? "PS\n" : "", - sta->flags & WLAN_STA_AUTHORIZED ? "AUTHORIZED\n" : "", - sta->flags & WLAN_STA_SHORT_PREAMBLE ? "SHORT PREAMBLE\n" : "", - sta->flags & WLAN_STA_WME ? "WME\n" : "", - sta->flags & WLAN_STA_WDS ? "WDS\n" : ""); + staflags & WLAN_STA_AUTH ? "AUTH\n" : "", + staflags & WLAN_STA_ASSOC ? "ASSOC\n" : "", + staflags & WLAN_STA_PS ? "PS\n" : "", + staflags & WLAN_STA_AUTHORIZED ? "AUTHORIZED\n" : "", + staflags & WLAN_STA_SHORT_PREAMBLE ? "SHORT PREAMBLE\n" : "", + staflags & WLAN_STA_WME ? "WME\n" : "", + staflags & WLAN_STA_WDS ? "WDS\n" : ""); return simple_read_from_buffer(userbuf, count, ppos, buf, res); } STA_OPS(flags); @@ -123,36 +123,6 @@ static ssize_t sta_last_seq_ctrl_read(struct file *file, char __user *userbuf, } STA_OPS(last_seq_ctrl); -#ifdef CONFIG_MAC80211_DEBUG_COUNTERS -static ssize_t sta_wme_rx_queue_read(struct file *file, char __user *userbuf, - size_t count, loff_t *ppos) -{ - char buf[15*NUM_RX_DATA_QUEUES], *p = buf; - int i; - struct sta_info *sta = file->private_data; - for (i = 0; i < NUM_RX_DATA_QUEUES; i++) - p += scnprintf(p, sizeof(buf)+buf-p, "%u ", - sta->wme_rx_queue[i]); - p += scnprintf(p, sizeof(buf)+buf-p, "\n"); - return simple_read_from_buffer(userbuf, count, ppos, buf, p - buf); -} -STA_OPS(wme_rx_queue); - -static ssize_t sta_wme_tx_queue_read(struct file *file, char __user *userbuf, - size_t count, loff_t *ppos) -{ - char buf[15*NUM_TX_DATA_QUEUES], *p = buf; - int i; - struct sta_info *sta = file->private_data; - for (i = 0; i < NUM_TX_DATA_QUEUES; i++) - p += scnprintf(p, sizeof(buf)+buf-p, "%u ", - sta->wme_tx_queue[i]); - p += scnprintf(p, sizeof(buf)+buf-p, "\n"); - return simple_read_from_buffer(userbuf, count, ppos, buf, p - buf); -} -STA_OPS(wme_tx_queue); -#endif - static ssize_t sta_agg_status_read(struct file *file, char __user *userbuf, size_t count, loff_t *ppos) { @@ -293,10 +263,6 @@ void ieee80211_sta_debugfs_add(struct sta_info *sta) DEBUGFS_ADD(num_ps_buf_frames); DEBUGFS_ADD(inactive_ms); DEBUGFS_ADD(last_seq_ctrl); -#ifdef CONFIG_MAC80211_DEBUG_COUNTERS - DEBUGFS_ADD(wme_rx_queue); - DEBUGFS_ADD(wme_tx_queue); -#endif DEBUGFS_ADD(agg_status); } @@ -306,10 +272,6 @@ void ieee80211_sta_debugfs_remove(struct sta_info *sta) DEBUGFS_DEL(num_ps_buf_frames); DEBUGFS_DEL(inactive_ms); DEBUGFS_DEL(last_seq_ctrl); -#ifdef CONFIG_MAC80211_DEBUG_COUNTERS - DEBUGFS_DEL(wme_rx_queue); - DEBUGFS_DEL(wme_tx_queue); -#endif DEBUGFS_DEL(agg_status); debugfs_remove(sta->debugfs.dir); diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 006486b26726..a4f9a832722a 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -2,6 +2,7 @@ * Copyright 2002-2005, Instant802 Networks, Inc. * Copyright 2005, Devicescape Software, Inc. * Copyright 2006-2007 Jiri Benc <jbenc@suse.cz> + * Copyright 2007-2008 Johannes Berg <johannes@sipsolutions.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -23,6 +24,8 @@ #include <linux/spinlock.h> #include <linux/etherdevice.h> #include <net/wireless.h> +#include <net/iw_handler.h> +#include <net/mac80211.h> #include "key.h" #include "sta_info.h" @@ -82,7 +85,7 @@ struct ieee80211_sta_bss { u16 capability; /* host byte order */ enum ieee80211_band band; int freq; - int rssi, signal, noise; + int signal, noise, qual; u8 *wpa_ie; size_t wpa_ie_len; u8 *rsn_ie; @@ -91,6 +94,8 @@ struct ieee80211_sta_bss { size_t wmm_ie_len; u8 *ht_ie; size_t ht_ie_len; + u8 *ht_add_ie; + size_t ht_add_ie_len; #ifdef CONFIG_MAC80211_MESH u8 *mesh_id; size_t mesh_id_len; @@ -147,7 +152,6 @@ typedef unsigned __bitwise__ ieee80211_tx_result; #define IEEE80211_TX_UNICAST BIT(1) #define IEEE80211_TX_PS_BUFFERED BIT(2) #define IEEE80211_TX_PROBE_LAST_FRAG BIT(3) -#define IEEE80211_TX_INJECTED BIT(4) struct ieee80211_tx_data { struct sk_buff *skb; @@ -157,13 +161,12 @@ struct ieee80211_tx_data { struct sta_info *sta; struct ieee80211_key *key; - struct ieee80211_tx_control *control; struct ieee80211_channel *channel; - struct ieee80211_rate *rate; + s8 rate_idx; /* use this rate (if set) for last fragment; rate can * be set to lower rate for the first fragments, e.g., * when using CTS protection with IEEE 802.11g. */ - struct ieee80211_rate *last_frag_rate; + s8 last_frag_rate_idx; /* Extra fragments (in addition to the first fragment * in skb) */ @@ -202,32 +205,16 @@ struct ieee80211_rx_data { unsigned int flags; int sent_ps_buffered; int queue; - int load; u32 tkip_iv32; u16 tkip_iv16; }; -/* flags used in struct ieee80211_tx_packet_data.flags */ -#define IEEE80211_TXPD_REQ_TX_STATUS BIT(0) -#define IEEE80211_TXPD_DO_NOT_ENCRYPT BIT(1) -#define IEEE80211_TXPD_REQUEUE BIT(2) -#define IEEE80211_TXPD_EAPOL_FRAME BIT(3) -#define IEEE80211_TXPD_AMPDU BIT(4) -/* Stored in sk_buff->cb */ -struct ieee80211_tx_packet_data { - int ifindex; - unsigned long jiffies; - unsigned int flags; - u8 queue; -}; - struct ieee80211_tx_stored_packet { - struct ieee80211_tx_control control; struct sk_buff *skb; struct sk_buff **extra_frag; - struct ieee80211_rate *last_frag_rate; + s8 last_frag_rate_idx; int num_extra_frag; - unsigned int last_frag_rate_ctrl_probe; + bool last_frag_rate_ctrl_probe; }; struct beacon_data { @@ -251,8 +238,6 @@ struct ieee80211_if_ap { struct sk_buff_head ps_bc_buf; atomic_t num_sta_ps; /* number of stations in PS mode */ int dtim_count; - int force_unicast_rateidx; /* forced TX rateidx for unicast frames */ - int max_ratectrl_rateidx; /* max TX rateidx for rate control */ int num_beacons; /* number of TXed beacon frames for this BSS */ }; @@ -262,7 +247,6 @@ struct ieee80211_if_wds { }; struct ieee80211_if_vlan { - struct ieee80211_sub_if_data *ap; struct list_head list; }; @@ -436,8 +420,6 @@ struct ieee80211_sub_if_data { */ u64 basic_rates; - u16 sequence; - /* Fragment table for host-based reassembly */ struct ieee80211_fragment_entry fragments[IEEE80211_FRAGMENT_MAX]; unsigned int fragment_next; @@ -446,16 +428,18 @@ struct ieee80211_sub_if_data { struct ieee80211_key *keys[NUM_DEFAULT_KEYS]; struct ieee80211_key *default_key; + /* BSS configuration for this interface. */ + struct ieee80211_bss_conf bss_conf; + /* - * BSS configuration for this interface. - * - * FIXME: I feel bad putting this here when we already have a - * bss pointer, but the bss pointer is just wrong when - * you have multiple virtual STA mode interfaces... - * This needs to be fixed. + * AP this belongs to: self in AP mode and + * corresponding AP in VLAN mode, NULL for + * all others (might be needed later in IBSS) */ - struct ieee80211_bss_conf bss_conf; - struct ieee80211_if_ap *bss; /* BSS that this device belongs to */ + struct ieee80211_if_ap *bss; + + int force_unicast_rateidx; /* forced TX rateidx for unicast frames */ + int max_ratectrl_rateidx; /* max TX rateidx for rate control */ union { struct ieee80211_if_ap ap; @@ -464,14 +448,11 @@ struct ieee80211_sub_if_data { struct ieee80211_if_sta sta; u32 mntr_flags; } u; - int channel_use; - int channel_use_raw; #ifdef CONFIG_MAC80211_DEBUGFS struct dentry *debugfsdir; union { struct { - struct dentry *channel_use; struct dentry *drop_unencrypted; struct dentry *state; struct dentry *bssid; @@ -490,7 +471,6 @@ struct ieee80211_sub_if_data { struct dentry *num_beacons_sta; } sta; struct { - struct dentry *channel_use; struct dentry *drop_unencrypted; struct dentry *num_sta_ps; struct dentry *dtim_count; @@ -500,12 +480,10 @@ struct ieee80211_sub_if_data { struct dentry *num_buffered_multicast; } ap; struct { - struct dentry *channel_use; struct dentry *drop_unencrypted; struct dentry *peer; } wds; struct { - struct dentry *channel_use; struct dentry *drop_unencrypted; } vlan; struct { @@ -553,8 +531,6 @@ struct ieee80211_sub_if_data *vif_to_sdata(struct ieee80211_vif *p) return container_of(p, struct ieee80211_sub_if_data, vif); } -#define IEEE80211_DEV_TO_SUB_IF(dev) netdev_priv(dev) - enum { IEEE80211_RX_MSG = 1, IEEE80211_TX_STATUS_MSG = 2, @@ -562,6 +538,9 @@ enum { IEEE80211_ADDBA_MSG = 4, }; +/* maximum number of hardware queues we support. */ +#define QD_MAX_QUEUES (IEEE80211_MAX_AMPDU_QUEUES + IEEE80211_MAX_QUEUES) + struct ieee80211_local { /* embed the driver visible part. * don't cast (use the static inlines below), but we keep @@ -570,6 +549,8 @@ struct ieee80211_local { const struct ieee80211_ops *ops; + unsigned long queue_pool[BITS_TO_LONGS(QD_MAX_QUEUES)]; + struct net_device *mdev; /* wmaster# - "master" 802.11 device */ int open_count; int monitors, cooked_mntrs; @@ -581,12 +562,6 @@ struct ieee80211_local { bool tim_in_locked_section; /* see ieee80211_beacon_get() */ int tx_headroom; /* required headroom for hardware/radiotap */ - enum { - IEEE80211_DEV_UNINITIALIZED = 0, - IEEE80211_DEV_REGISTERED, - IEEE80211_DEV_UNREGISTERED, - } reg_state; - /* Tasklet and skb queue to process calls from IRQ mode. All frames * added to skb_queue will be processed, but frames in * skb_queue_unreliable may be dropped if the total length of these @@ -610,8 +585,8 @@ struct ieee80211_local { struct sta_info *sta_hash[STA_HASH_SIZE]; struct timer_list sta_cleanup; - unsigned long state[NUM_TX_DATA_QUEUES_AMPDU]; - struct ieee80211_tx_stored_packet pending_packet[NUM_TX_DATA_QUEUES_AMPDU]; + unsigned long queues_pending[BITS_TO_LONGS(IEEE80211_MAX_QUEUES)]; + struct ieee80211_tx_stored_packet pending_packet[IEEE80211_MAX_QUEUES]; struct tasklet_struct tx_pending_tasklet; /* number of interfaces with corresponding IFF_ flags */ @@ -677,9 +652,6 @@ struct ieee80211_local { assoc_led_name[32], radio_led_name[32]; #endif - u32 channel_use; - u32 channel_use_raw; - #ifdef CONFIG_MAC80211_DEBUGFS struct work_struct sta_debugfs_add; #endif @@ -705,8 +677,6 @@ struct ieee80211_local { unsigned int rx_expand_skb_head2; unsigned int rx_handlers_fragments; unsigned int tx_status_drop; - unsigned int wme_rx_queue[NUM_RX_DATA_QUEUES]; - unsigned int wme_tx_queue[NUM_RX_DATA_QUEUES]; #define I802_DEBUG_INC(c) (c)++ #else /* CONFIG_MAC80211_DEBUG_COUNTERS */ #define I802_DEBUG_INC(c) do { } while (0) @@ -764,8 +734,6 @@ struct ieee80211_local { struct dentry *rx_expand_skb_head2; struct dentry *rx_handlers_fragments; struct dentry *tx_status_drop; - struct dentry *wme_tx_queue; - struct dentry *wme_rx_queue; #endif struct dentry *dot11ACKFailureCount; struct dentry *dot11RTSFailureCount; @@ -778,6 +746,16 @@ struct ieee80211_local { #endif }; +static inline struct ieee80211_sub_if_data * +IEEE80211_DEV_TO_SUB_IF(struct net_device *dev) +{ + struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); + + BUG_ON(!local || local->mdev == dev); + + return netdev_priv(dev); +} + /* this struct represents 802.11n's RA/TID combination */ struct ieee80211_ra_tid { u8 ra[ETH_ALEN]; @@ -809,6 +787,10 @@ struct ieee802_11_elems { u8 *preq; u8 *prep; u8 *perr; + u8 *ch_switch_elem; + u8 *country_elem; + u8 *pwr_constr_elem; + u8 *quiet_elem; /* first quite element */ /* length of them, respectively */ u8 ssid_len; @@ -833,6 +815,11 @@ struct ieee802_11_elems { u8 preq_len; u8 prep_len; u8 perr_len; + u8 ch_switch_elem_len; + u8 country_elem_len; + u8 pwr_constr_elem_len; + u8 quiet_elem_len; + u8 num_of_quiet_elem; /* can be more the one */ }; static inline struct ieee80211_local *hw_to_local( @@ -847,11 +834,6 @@ static inline struct ieee80211_hw *local_to_hw( return &local->hw; } -enum ieee80211_link_state_t { - IEEE80211_LINK_STATE_XOFF = 0, - IEEE80211_LINK_STATE_PENDING, -}; - struct sta_attribute { struct attribute attr; ssize_t (*show)(const struct sta_info *, char *buf); @@ -867,39 +849,16 @@ static inline int ieee80211_bssid_match(const u8 *raddr, const u8 *addr) /* ieee80211.c */ int ieee80211_hw_config(struct ieee80211_local *local); -int ieee80211_if_config(struct net_device *dev); -int ieee80211_if_config_beacon(struct net_device *dev); +int ieee80211_if_config(struct ieee80211_sub_if_data *sdata, u32 changed); void ieee80211_tx_set_protected(struct ieee80211_tx_data *tx); -void ieee80211_if_setup(struct net_device *dev); u32 ieee80211_handle_ht(struct ieee80211_local *local, int enable_ht, struct ieee80211_ht_info *req_ht_cap, struct ieee80211_ht_bss_info *req_bss_cap); /* ieee80211_ioctl.c */ extern const struct iw_handler_def ieee80211_iw_handler_def; - - -/* Least common multiple of the used rates (in 100 kbps). This is used to - * calculate rate_inv values for each rate so that only integers are needed. */ -#define CHAN_UTIL_RATE_LCM 95040 -/* 1 usec is 1/8 * (95040/10) = 1188 */ -#define CHAN_UTIL_PER_USEC 1188 -/* Amount of bits to shift the result right to scale the total utilization - * to values that will not wrap around 32-bit integers. */ -#define CHAN_UTIL_SHIFT 9 -/* Theoretical maximum of channel utilization counter in 10 ms (stat_time=1): - * (CHAN_UTIL_PER_USEC * 10000) >> CHAN_UTIL_SHIFT = 23203. So dividing the - * raw value with about 23 should give utilization in 10th of a percentage - * (1/1000). However, utilization is only estimated and not all intervals - * between frames etc. are calculated. 18 seems to give numbers that are closer - * to the real maximum. */ -#define CHAN_UTIL_PER_10MS 18 -#define CHAN_UTIL_HDR_LONG (202 * CHAN_UTIL_PER_USEC) -#define CHAN_UTIL_HDR_SHORT (40 * CHAN_UTIL_PER_USEC) - - -/* ieee80211_ioctl.c */ int ieee80211_set_freq(struct net_device *dev, int freq); + /* ieee80211_sta.c */ void ieee80211_sta_timer(unsigned long data); void ieee80211_sta_work(struct work_struct *work); @@ -912,21 +871,23 @@ int ieee80211_sta_set_bssid(struct net_device *dev, u8 *bssid); int ieee80211_sta_req_scan(struct net_device *dev, u8 *ssid, size_t ssid_len); void ieee80211_sta_req_auth(struct net_device *dev, struct ieee80211_if_sta *ifsta); -int ieee80211_sta_scan_results(struct net_device *dev, char *buf, size_t len); +int ieee80211_sta_scan_results(struct net_device *dev, + struct iw_request_info *info, + char *buf, size_t len); ieee80211_rx_result ieee80211_sta_rx_scan( struct net_device *dev, struct sk_buff *skb, struct ieee80211_rx_status *rx_status); -void ieee80211_rx_bss_list_init(struct net_device *dev); -void ieee80211_rx_bss_list_deinit(struct net_device *dev); +void ieee80211_rx_bss_list_init(struct ieee80211_local *local); +void ieee80211_rx_bss_list_deinit(struct ieee80211_local *local); int ieee80211_sta_set_extra_ie(struct net_device *dev, char *ie, size_t len); -struct sta_info * ieee80211_ibss_add_sta(struct net_device *dev, - struct sk_buff *skb, u8 *bssid, - u8 *addr); +struct sta_info *ieee80211_ibss_add_sta(struct net_device *dev, + struct sk_buff *skb, u8 *bssid, + u8 *addr, u64 supp_rates); int ieee80211_sta_deauthenticate(struct net_device *dev, u16 reason); int ieee80211_sta_disassociate(struct net_device *dev, u16 reason); void ieee80211_bss_info_change_notify(struct ieee80211_sub_if_data *sdata, u32 changed); -void ieee80211_reset_erp_info(struct net_device *dev); +u32 ieee80211_reset_erp_info(struct net_device *dev); int ieee80211_ht_cap_ie_to_ht_info(struct ieee80211_ht_cap *ht_cap_ie, struct ieee80211_ht_info *ht_info); int ieee80211_ht_addt_info_ie_to_ht_bss_info( @@ -937,10 +898,10 @@ void ieee80211_send_addba_request(struct net_device *dev, const u8 *da, u16 agg_size, u16 timeout); void ieee80211_send_delba(struct net_device *dev, const u8 *da, u16 tid, u16 initiator, u16 reason_code); +void ieee80211_send_bar(struct net_device *dev, u8 *ra, u16 tid, u16 ssn); void ieee80211_sta_stop_rx_ba_session(struct net_device *dev, u8 *da, u16 tid, u16 initiator, u16 reason); -void sta_rx_agg_session_timer_expired(unsigned long data); void sta_addba_resp_timer_expired(unsigned long data); void ieee80211_sta_tear_down_BA_sessions(struct net_device *dev, u8 *addr); u64 ieee80211_sta_get_rates(struct ieee80211_local *local, @@ -958,17 +919,15 @@ static inline void ieee80211_start_mesh(struct net_device *dev) {} #endif -/* ieee80211_iface.c */ -int ieee80211_if_add(struct net_device *dev, const char *name, - struct net_device **new_dev, int type, +/* interface handling */ +void ieee80211_if_setup(struct net_device *dev); +int ieee80211_if_add(struct ieee80211_local *local, const char *name, + struct net_device **new_dev, enum ieee80211_if_types type, struct vif_params *params); -void ieee80211_if_set_type(struct net_device *dev, int type); -void ieee80211_if_reinit(struct net_device *dev); -void __ieee80211_if_del(struct ieee80211_local *local, - struct ieee80211_sub_if_data *sdata); -int ieee80211_if_remove(struct net_device *dev, const char *name, int id); -void ieee80211_if_free(struct net_device *dev); -void ieee80211_if_sdata_init(struct ieee80211_sub_if_data *sdata); +int ieee80211_if_change_type(struct ieee80211_sub_if_data *sdata, + enum ieee80211_if_types type); +void ieee80211_if_remove(struct net_device *dev); +void ieee80211_remove_interfaces(struct ieee80211_local *local); /* tx handling */ void ieee80211_clear_tx_pending(struct ieee80211_local *local); @@ -988,4 +947,10 @@ int ieee80211_frame_duration(struct ieee80211_local *local, size_t len, void mac80211_ev_michael_mic_failure(struct net_device *dev, int keyidx, struct ieee80211_hdr *hdr); +#ifdef CONFIG_MAC80211_NOINLINE +#define debug_noinline noinline +#else +#define debug_noinline +#endif + #endif /* IEEE80211_I_H */ diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index 06e88a5a036d..610ed1d9893a 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -2,6 +2,7 @@ * Copyright 2002-2005, Instant802 Networks, Inc. * Copyright 2005-2006, Devicescape Software, Inc. * Copyright (c) 2006 Jiri Benc <jbenc@suse.cz> + * Copyright 2008, Johannes Berg <johannes@sipsolutions.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -17,38 +18,164 @@ #include "debugfs_netdev.h" #include "mesh.h" -void ieee80211_if_sdata_init(struct ieee80211_sub_if_data *sdata) +/* + * Called when the netdev is removed or, by the code below, before + * the interface type changes. + */ +static void ieee80211_teardown_sdata(struct net_device *dev) { + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + struct ieee80211_local *local = sdata->local; + struct beacon_data *beacon; + struct sk_buff *skb; + int flushed; int i; - /* Default values for sub-interface parameters */ - sdata->drop_unencrypted = 0; + ieee80211_debugfs_remove_netdev(sdata); + + /* free extra data */ + ieee80211_free_keys(sdata); + for (i = 0; i < IEEE80211_FRAGMENT_MAX; i++) - skb_queue_head_init(&sdata->fragments[i].skb_list); + __skb_queue_purge(&sdata->fragments[i].skb_list); + sdata->fragment_next = 0; - INIT_LIST_HEAD(&sdata->key_list); + switch (sdata->vif.type) { + case IEEE80211_IF_TYPE_AP: + beacon = sdata->u.ap.beacon; + rcu_assign_pointer(sdata->u.ap.beacon, NULL); + synchronize_rcu(); + kfree(beacon); + + while ((skb = skb_dequeue(&sdata->u.ap.ps_bc_buf))) { + local->total_ps_buffered--; + dev_kfree_skb(skb); + } + + break; + case IEEE80211_IF_TYPE_MESH_POINT: + /* Allow compiler to elide mesh_rmc_free call. */ + if (ieee80211_vif_is_mesh(&sdata->vif)) + mesh_rmc_free(dev); + /* fall through */ + case IEEE80211_IF_TYPE_STA: + case IEEE80211_IF_TYPE_IBSS: + kfree(sdata->u.sta.extra_ie); + kfree(sdata->u.sta.assocreq_ies); + kfree(sdata->u.sta.assocresp_ies); + kfree_skb(sdata->u.sta.probe_resp); + break; + case IEEE80211_IF_TYPE_WDS: + case IEEE80211_IF_TYPE_VLAN: + case IEEE80211_IF_TYPE_MNTR: + break; + case IEEE80211_IF_TYPE_INVALID: + BUG(); + break; + } + + flushed = sta_info_flush(local, sdata); + WARN_ON(flushed); } -static void ieee80211_if_sdata_deinit(struct ieee80211_sub_if_data *sdata) +/* + * Helper function to initialise an interface to a specific type. + */ +static void ieee80211_setup_sdata(struct ieee80211_sub_if_data *sdata, + enum ieee80211_if_types type) { - int i; + struct ieee80211_if_sta *ifsta; - for (i = 0; i < IEEE80211_FRAGMENT_MAX; i++) { - __skb_queue_purge(&sdata->fragments[i].skb_list); + /* clear type-dependent union */ + memset(&sdata->u, 0, sizeof(sdata->u)); + + /* and set some type-dependent values */ + sdata->vif.type = type; + + /* only monitor differs */ + sdata->dev->type = ARPHRD_ETHER; + + switch (type) { + case IEEE80211_IF_TYPE_AP: + skb_queue_head_init(&sdata->u.ap.ps_bc_buf); + INIT_LIST_HEAD(&sdata->u.ap.vlans); + break; + case IEEE80211_IF_TYPE_MESH_POINT: + case IEEE80211_IF_TYPE_STA: + case IEEE80211_IF_TYPE_IBSS: + ifsta = &sdata->u.sta; + INIT_WORK(&ifsta->work, ieee80211_sta_work); + setup_timer(&ifsta->timer, ieee80211_sta_timer, + (unsigned long) sdata); + skb_queue_head_init(&ifsta->skb_queue); + + ifsta->capab = WLAN_CAPABILITY_ESS; + ifsta->auth_algs = IEEE80211_AUTH_ALG_OPEN | + IEEE80211_AUTH_ALG_SHARED_KEY; + ifsta->flags |= IEEE80211_STA_CREATE_IBSS | + IEEE80211_STA_AUTO_BSSID_SEL | + IEEE80211_STA_AUTO_CHANNEL_SEL; + if (ieee80211_num_regular_queues(&sdata->local->hw) >= 4) + ifsta->flags |= IEEE80211_STA_WMM_ENABLED; + + if (ieee80211_vif_is_mesh(&sdata->vif)) + ieee80211_mesh_init_sdata(sdata); + break; + case IEEE80211_IF_TYPE_MNTR: + sdata->dev->type = ARPHRD_IEEE80211_RADIOTAP; + sdata->dev->hard_start_xmit = ieee80211_monitor_start_xmit; + sdata->u.mntr_flags = MONITOR_FLAG_CONTROL | + MONITOR_FLAG_OTHER_BSS; + break; + case IEEE80211_IF_TYPE_WDS: + case IEEE80211_IF_TYPE_VLAN: + break; + case IEEE80211_IF_TYPE_INVALID: + BUG(); + break; } + + ieee80211_debugfs_add_netdev(sdata); +} + +int ieee80211_if_change_type(struct ieee80211_sub_if_data *sdata, + enum ieee80211_if_types type) +{ + ASSERT_RTNL(); + + if (type == sdata->vif.type) + return 0; + + /* + * We could, here, on changes between IBSS/STA/MESH modes, + * invoke an MLME function instead that disassociates etc. + * and goes into the requested mode. + */ + + if (netif_running(sdata->dev)) + return -EBUSY; + + /* Purge and reset type-dependent state. */ + ieee80211_teardown_sdata(sdata->dev); + ieee80211_setup_sdata(sdata, type); + + /* reset some values that shouldn't be kept across type changes */ + sdata->basic_rates = 0; + sdata->drop_unencrypted = 0; + + return 0; } -/* Must be called with rtnl lock held. */ -int ieee80211_if_add(struct net_device *dev, const char *name, - struct net_device **new_dev, int type, +int ieee80211_if_add(struct ieee80211_local *local, const char *name, + struct net_device **new_dev, enum ieee80211_if_types type, struct vif_params *params) { struct net_device *ndev; - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); struct ieee80211_sub_if_data *sdata = NULL; - int ret; + int ret, i; ASSERT_RTNL(); + ndev = alloc_netdev(sizeof(*sdata) + local->hw.vif_data_size, name, ieee80211_if_setup); if (!ndev) @@ -68,26 +195,33 @@ int ieee80211_if_add(struct net_device *dev, const char *name, goto fail; memcpy(ndev->dev_addr, local->hw.wiphy->perm_addr, ETH_ALEN); - ndev->base_addr = dev->base_addr; - ndev->irq = dev->irq; - ndev->mem_start = dev->mem_start; - ndev->mem_end = dev->mem_end; SET_NETDEV_DEV(ndev, wiphy_dev(local->hw.wiphy)); - sdata = IEEE80211_DEV_TO_SUB_IF(ndev); + /* don't use IEEE80211_DEV_TO_SUB_IF because it checks too much */ + sdata = netdev_priv(ndev); ndev->ieee80211_ptr = &sdata->wdev; + + /* initialise type-independent data */ sdata->wdev.wiphy = local->hw.wiphy; - sdata->vif.type = IEEE80211_IF_TYPE_AP; - sdata->dev = ndev; sdata->local = local; - ieee80211_if_sdata_init(sdata); + sdata->dev = ndev; + + for (i = 0; i < IEEE80211_FRAGMENT_MAX; i++) + skb_queue_head_init(&sdata->fragments[i].skb_list); + + INIT_LIST_HEAD(&sdata->key_list); + + sdata->force_unicast_rateidx = -1; + sdata->max_ratectrl_rateidx = -1; + + /* setup type-dependent data */ + ieee80211_setup_sdata(sdata, type); ret = register_netdevice(ndev); if (ret) goto fail; - ieee80211_debugfs_add_netdev(sdata); - ieee80211_if_set_type(ndev, type); + ndev->uninit = ieee80211_teardown_sdata; if (ieee80211_vif_is_mesh(&sdata->vif) && params && params->mesh_id_len) @@ -95,11 +229,6 @@ int ieee80211_if_add(struct net_device *dev, const char *name, params->mesh_id_len, params->mesh_id); - /* we're under RTNL so all this is fine */ - if (unlikely(local->reg_state == IEEE80211_DEV_UNREGISTERED)) { - __ieee80211_if_del(local, sdata); - return -ENODEV; - } list_add_tail_rcu(&sdata->list, &local->interfaces); if (new_dev) @@ -107,217 +236,34 @@ int ieee80211_if_add(struct net_device *dev, const char *name, return 0; -fail: + fail: free_netdev(ndev); return ret; } -void ieee80211_if_set_type(struct net_device *dev, int type) -{ - struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); - int oldtype = sdata->vif.type; - - /* - * We need to call this function on the master interface - * which already has a hard_start_xmit routine assigned - * which must not be changed. - */ - if (dev != sdata->local->mdev) - dev->hard_start_xmit = ieee80211_subif_start_xmit; - - /* - * Called even when register_netdevice fails, it would - * oops if assigned before initialising the rest. - */ - dev->uninit = ieee80211_if_reinit; - - /* most have no BSS pointer */ - sdata->bss = NULL; - sdata->vif.type = type; - - sdata->basic_rates = 0; - - switch (type) { - case IEEE80211_IF_TYPE_WDS: - /* nothing special */ - break; - case IEEE80211_IF_TYPE_VLAN: - sdata->u.vlan.ap = NULL; - break; - case IEEE80211_IF_TYPE_AP: - sdata->u.ap.force_unicast_rateidx = -1; - sdata->u.ap.max_ratectrl_rateidx = -1; - skb_queue_head_init(&sdata->u.ap.ps_bc_buf); - sdata->bss = &sdata->u.ap; - INIT_LIST_HEAD(&sdata->u.ap.vlans); - break; - case IEEE80211_IF_TYPE_MESH_POINT: - case IEEE80211_IF_TYPE_STA: - case IEEE80211_IF_TYPE_IBSS: { - struct ieee80211_sub_if_data *msdata; - struct ieee80211_if_sta *ifsta; - - ifsta = &sdata->u.sta; - INIT_WORK(&ifsta->work, ieee80211_sta_work); - setup_timer(&ifsta->timer, ieee80211_sta_timer, - (unsigned long) sdata); - skb_queue_head_init(&ifsta->skb_queue); - - ifsta->capab = WLAN_CAPABILITY_ESS; - ifsta->auth_algs = IEEE80211_AUTH_ALG_OPEN | - IEEE80211_AUTH_ALG_SHARED_KEY; - ifsta->flags |= IEEE80211_STA_CREATE_IBSS | - IEEE80211_STA_WMM_ENABLED | - IEEE80211_STA_AUTO_BSSID_SEL | - IEEE80211_STA_AUTO_CHANNEL_SEL; - - msdata = IEEE80211_DEV_TO_SUB_IF(sdata->local->mdev); - sdata->bss = &msdata->u.ap; - - if (ieee80211_vif_is_mesh(&sdata->vif)) - ieee80211_mesh_init_sdata(sdata); - break; - } - case IEEE80211_IF_TYPE_MNTR: - dev->type = ARPHRD_IEEE80211_RADIOTAP; - dev->hard_start_xmit = ieee80211_monitor_start_xmit; - sdata->u.mntr_flags = MONITOR_FLAG_CONTROL | - MONITOR_FLAG_OTHER_BSS; - break; - default: - printk(KERN_WARNING "%s: %s: Unknown interface type 0x%x", - dev->name, __func__, type); - } - ieee80211_debugfs_change_if_type(sdata, oldtype); -} - -/* Must be called with rtnl lock held. */ -void ieee80211_if_reinit(struct net_device *dev) +void ieee80211_if_remove(struct net_device *dev) { - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); - struct sk_buff *skb; - int flushed; ASSERT_RTNL(); - ieee80211_free_keys(sdata); - - ieee80211_if_sdata_deinit(sdata); - - /* Need to handle mesh specially to allow eliding the function call */ - if (ieee80211_vif_is_mesh(&sdata->vif)) - mesh_rmc_free(dev); - - switch (sdata->vif.type) { - case IEEE80211_IF_TYPE_INVALID: - /* cannot happen */ - WARN_ON(1); - break; - case IEEE80211_IF_TYPE_AP: { - /* Remove all virtual interfaces that use this BSS - * as their sdata->bss */ - struct ieee80211_sub_if_data *tsdata, *n; - struct beacon_data *beacon; - - list_for_each_entry_safe(tsdata, n, &local->interfaces, list) { - if (tsdata != sdata && tsdata->bss == &sdata->u.ap) { - printk(KERN_DEBUG "%s: removing virtual " - "interface %s because its BSS interface" - " is being removed\n", - sdata->dev->name, tsdata->dev->name); - list_del_rcu(&tsdata->list); - /* - * We have lots of time and can afford - * to sync for each interface - */ - synchronize_rcu(); - __ieee80211_if_del(local, tsdata); - } - } - - beacon = sdata->u.ap.beacon; - rcu_assign_pointer(sdata->u.ap.beacon, NULL); - synchronize_rcu(); - kfree(beacon); - - while ((skb = skb_dequeue(&sdata->u.ap.ps_bc_buf))) { - local->total_ps_buffered--; - dev_kfree_skb(skb); - } - - break; - } - case IEEE80211_IF_TYPE_WDS: - /* nothing to do */ - break; - case IEEE80211_IF_TYPE_MESH_POINT: - case IEEE80211_IF_TYPE_STA: - case IEEE80211_IF_TYPE_IBSS: - kfree(sdata->u.sta.extra_ie); - sdata->u.sta.extra_ie = NULL; - kfree(sdata->u.sta.assocreq_ies); - sdata->u.sta.assocreq_ies = NULL; - kfree(sdata->u.sta.assocresp_ies); - sdata->u.sta.assocresp_ies = NULL; - if (sdata->u.sta.probe_resp) { - dev_kfree_skb(sdata->u.sta.probe_resp); - sdata->u.sta.probe_resp = NULL; - } - - break; - case IEEE80211_IF_TYPE_MNTR: - dev->type = ARPHRD_ETHER; - break; - case IEEE80211_IF_TYPE_VLAN: - sdata->u.vlan.ap = NULL; - break; - } - - flushed = sta_info_flush(local, sdata); - WARN_ON(flushed); - - memset(&sdata->u, 0, sizeof(sdata->u)); - ieee80211_if_sdata_init(sdata); -} - -/* Must be called with rtnl lock held. */ -void __ieee80211_if_del(struct ieee80211_local *local, - struct ieee80211_sub_if_data *sdata) -{ - struct net_device *dev = sdata->dev; - - ieee80211_debugfs_remove_netdev(sdata); + list_del_rcu(&sdata->list); + synchronize_rcu(); unregister_netdevice(dev); - /* Except master interface, the net_device will be freed by - * net_device->destructor (i. e. ieee80211_if_free). */ } -/* Must be called with rtnl lock held. */ -int ieee80211_if_remove(struct net_device *dev, const char *name, int id) +/* + * Remove all interfaces, may only be called at hardware unregistration + * time because it doesn't do RCU-safe list removals. + */ +void ieee80211_remove_interfaces(struct ieee80211_local *local) { - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - struct ieee80211_sub_if_data *sdata, *n; + struct ieee80211_sub_if_data *sdata, *tmp; ASSERT_RTNL(); - list_for_each_entry_safe(sdata, n, &local->interfaces, list) { - if ((sdata->vif.type == id || id == -1) && - strcmp(name, sdata->dev->name) == 0 && - sdata->dev != local->mdev) { - list_del_rcu(&sdata->list); - synchronize_rcu(); - __ieee80211_if_del(local, sdata); - return 0; - } + list_for_each_entry_safe(sdata, tmp, &local->interfaces, list) { + list_del(&sdata->list); + unregister_netdevice(sdata->dev); } - return -ENODEV; -} - -void ieee80211_if_free(struct net_device *dev) -{ - struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); - - ieee80211_if_sdata_deinit(sdata); - free_netdev(dev); } diff --git a/net/mac80211/key.c b/net/mac80211/key.c index 220e83be3ef4..6597c779e35a 100644 --- a/net/mac80211/key.c +++ b/net/mac80211/key.c @@ -321,8 +321,15 @@ void ieee80211_key_link(struct ieee80211_key *key, * some hardware cannot handle TKIP with QoS, so * we indicate whether QoS could be in use. */ - if (sta->flags & WLAN_STA_WME) + if (test_sta_flags(sta, WLAN_STA_WME)) key->conf.flags |= IEEE80211_KEY_FLAG_WMM_STA; + + /* + * This key is for a specific sta interface, + * inform the driver that it should try to store + * this key as pairwise key. + */ + key->conf.flags |= IEEE80211_KEY_FLAG_PAIRWISE; } else { if (sdata->vif.type == IEEE80211_IF_TYPE_STA) { struct sta_info *ap; @@ -335,7 +342,7 @@ void ieee80211_key_link(struct ieee80211_key *key, /* same here, the AP could be using QoS */ ap = sta_info_get(key->local, key->sdata->u.sta.bssid); if (ap) { - if (ap->flags & WLAN_STA_WME) + if (test_sta_flags(ap, WLAN_STA_WME)) key->conf.flags |= IEEE80211_KEY_FLAG_WMM_STA; } diff --git a/net/mac80211/key.h b/net/mac80211/key.h index f52c3df1fe9a..425816e0996c 100644 --- a/net/mac80211/key.h +++ b/net/mac80211/key.h @@ -16,31 +16,18 @@ #include <linux/rcupdate.h> #include <net/mac80211.h> -/* ALG_TKIP - * struct ieee80211_key::key is encoded as a 256-bit (32 byte) data block: - * Temporal Encryption Key (128 bits) - * Temporal Authenticator Tx MIC Key (64 bits) - * Temporal Authenticator Rx MIC Key (64 bits) - */ - -#define WEP_IV_LEN 4 -#define WEP_ICV_LEN 4 - -#define ALG_TKIP_KEY_LEN 32 -/* Starting offsets for each key */ -#define ALG_TKIP_TEMP_ENCR_KEY 0 -#define ALG_TKIP_TEMP_AUTH_TX_MIC_KEY 16 -#define ALG_TKIP_TEMP_AUTH_RX_MIC_KEY 24 -#define TKIP_IV_LEN 8 -#define TKIP_ICV_LEN 4 - -#define ALG_CCMP_KEY_LEN 16 -#define CCMP_HDR_LEN 8 -#define CCMP_MIC_LEN 8 -#define CCMP_TK_LEN 16 -#define CCMP_PN_LEN 6 - -#define NUM_RX_DATA_QUEUES 17 +#define WEP_IV_LEN 4 +#define WEP_ICV_LEN 4 +#define ALG_TKIP_KEY_LEN 32 +#define ALG_CCMP_KEY_LEN 16 +#define CCMP_HDR_LEN 8 +#define CCMP_MIC_LEN 8 +#define CCMP_TK_LEN 16 +#define CCMP_PN_LEN 6 +#define TKIP_IV_LEN 8 +#define TKIP_ICV_LEN 4 + +#define NUM_RX_DATA_QUEUES 17 struct ieee80211_local; struct ieee80211_sub_if_data; @@ -69,6 +56,13 @@ enum ieee80211_internal_key_flags { KEY_FLAG_TODO_ADD_DEBUGFS = BIT(5), }; +struct tkip_ctx { + u32 iv32; + u16 iv16; + u16 p1k[5]; + int initialized; +}; + struct ieee80211_key { struct ieee80211_local *local; struct ieee80211_sub_if_data *sdata; @@ -85,16 +79,10 @@ struct ieee80211_key { union { struct { /* last used TSC */ - u32 iv32; - u16 iv16; - u16 p1k[5]; - int tx_initialized; + struct tkip_ctx tx; /* last received RSC */ - u32 iv32_rx[NUM_RX_DATA_QUEUES]; - u16 iv16_rx[NUM_RX_DATA_QUEUES]; - u16 p1k_rx[NUM_RX_DATA_QUEUES][5]; - int rx_initialized[NUM_RX_DATA_QUEUES]; + struct tkip_ctx rx[NUM_RX_DATA_QUEUES]; } tkip; struct { u8 tx_pn[6]; diff --git a/net/mac80211/main.c b/net/mac80211/main.c index df0836ff1a20..f1a83d450ea0 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -35,8 +35,6 @@ #include "debugfs.h" #include "debugfs_netdev.h" -#define SUPP_MCS_SET_LEN 16 - /* * For seeing transmitted packets on monitor interfaces * we have a radiotap header too. @@ -107,12 +105,18 @@ static int ieee80211_master_open(struct net_device *dev) /* we hold the RTNL here so can safely walk the list */ list_for_each_entry(sdata, &local->interfaces, list) { - if (sdata->dev != dev && netif_running(sdata->dev)) { + if (netif_running(sdata->dev)) { res = 0; break; } } - return res; + + if (res) + return res; + + netif_tx_start_all_queues(local->mdev); + + return 0; } static int ieee80211_master_stop(struct net_device *dev) @@ -122,7 +126,7 @@ static int ieee80211_master_stop(struct net_device *dev) /* we hold the RTNL here so can safely walk the list */ list_for_each_entry(sdata, &local->interfaces, list) - if (sdata->dev != dev && netif_running(sdata->dev)) + if (netif_running(sdata->dev)) dev_close(sdata->dev); return 0; @@ -147,9 +151,7 @@ static int ieee80211_change_mtu(struct net_device *dev, int new_mtu) /* FIX: what would be proper limits for MTU? * This interface uses 802.3 frames. */ if (new_mtu < 256 || - new_mtu > IEEE80211_MAX_DATA_LEN - 24 - 6 - meshhdrlen) { - printk(KERN_WARNING "%s: invalid MTU %d\n", - dev->name, new_mtu); + new_mtu > IEEE80211_MAX_DATA_LEN - 24 - 6 - meshhdrlen) { return -EINVAL; } @@ -180,10 +182,11 @@ static int ieee80211_open(struct net_device *dev) { struct ieee80211_sub_if_data *sdata, *nsdata; struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); + struct sta_info *sta; struct ieee80211_if_init_conf conf; + u32 changed = 0; int res; bool need_hw_reconfig = 0; - struct sta_info *sta; sdata = IEEE80211_DEV_TO_SUB_IF(dev); @@ -191,7 +194,7 @@ static int ieee80211_open(struct net_device *dev) list_for_each_entry(nsdata, &local->interfaces, list) { struct net_device *ndev = nsdata->dev; - if (ndev != dev && ndev != local->mdev && netif_running(ndev)) { + if (ndev != dev && netif_running(ndev)) { /* * Allow only a single IBSS interface to be up at any * time. This is restricted because beacon distribution @@ -207,30 +210,6 @@ static int ieee80211_open(struct net_device *dev) return -EBUSY; /* - * Disallow multiple IBSS/STA mode interfaces. - * - * This is a technical restriction, it is possible although - * most likely not IEEE 802.11 compliant to have multiple - * STAs with just a single hardware (the TSF timer will not - * be adjusted properly.) - * - * However, because mac80211 uses the master device's BSS - * information for each STA/IBSS interface, doing this will - * currently corrupt that BSS information completely, unless, - * a not very useful case, both STAs are associated to the - * same BSS. - * - * To remove this restriction, the BSS information needs to - * be embedded in the STA/IBSS mode sdata instead of using - * the master device's BSS structure. - */ - if ((sdata->vif.type == IEEE80211_IF_TYPE_STA || - sdata->vif.type == IEEE80211_IF_TYPE_IBSS) && - (nsdata->vif.type == IEEE80211_IF_TYPE_STA || - nsdata->vif.type == IEEE80211_IF_TYPE_IBSS)) - return -EBUSY; - - /* * The remaining checks are only performed for interfaces * with the same MAC address. */ @@ -249,7 +228,7 @@ static int ieee80211_open(struct net_device *dev) */ if (sdata->vif.type == IEEE80211_IF_TYPE_VLAN && nsdata->vif.type == IEEE80211_IF_TYPE_AP) - sdata->u.vlan.ap = nsdata; + sdata->bss = &nsdata->u.ap; } } @@ -259,10 +238,13 @@ static int ieee80211_open(struct net_device *dev) return -ENOLINK; break; case IEEE80211_IF_TYPE_VLAN: - if (!sdata->u.vlan.ap) + if (!sdata->bss) return -ENOLINK; + list_add(&sdata->u.vlan.list, &sdata->bss->vlans); break; case IEEE80211_IF_TYPE_AP: + sdata->bss = &sdata->u.ap; + break; case IEEE80211_IF_TYPE_STA: case IEEE80211_IF_TYPE_MNTR: case IEEE80211_IF_TYPE_IBSS: @@ -280,14 +262,13 @@ static int ieee80211_open(struct net_device *dev) if (local->ops->start) res = local->ops->start(local_to_hw(local)); if (res) - return res; + goto err_del_bss; need_hw_reconfig = 1; ieee80211_led_radio(local, local->hw.conf.radio_enabled); } switch (sdata->vif.type) { case IEEE80211_IF_TYPE_VLAN: - list_add(&sdata->u.vlan.list, &sdata->u.vlan.ap->u.ap.vlans); /* no need to tell driver */ break; case IEEE80211_IF_TYPE_MNTR: @@ -310,9 +291,9 @@ static int ieee80211_open(struct net_device *dev) if (sdata->u.mntr_flags & MONITOR_FLAG_OTHER_BSS) local->fif_other_bss++; - netif_tx_lock_bh(local->mdev); + netif_addr_lock_bh(local->mdev); ieee80211_configure_filter(local); - netif_tx_unlock_bh(local->mdev); + netif_addr_unlock_bh(local->mdev); break; case IEEE80211_IF_TYPE_STA: case IEEE80211_IF_TYPE_IBSS: @@ -326,8 +307,10 @@ static int ieee80211_open(struct net_device *dev) if (res) goto err_stop; - ieee80211_if_config(dev); - ieee80211_reset_erp_info(dev); + if (ieee80211_vif_is_mesh(&sdata->vif)) + ieee80211_start_mesh(sdata->dev); + changed |= ieee80211_reset_erp_info(dev); + ieee80211_bss_info_change_notify(sdata, changed); ieee80211_enable_keys(sdata); if (sdata->vif.type == IEEE80211_IF_TYPE_STA && @@ -346,6 +329,7 @@ static int ieee80211_open(struct net_device *dev) goto err_del_interface; } + /* no locking required since STA is not live yet */ sta->flags |= WLAN_STA_AUTHORIZED; res = sta_info_insert(sta); @@ -385,13 +369,13 @@ static int ieee80211_open(struct net_device *dev) * yet be effective. Trigger execution of ieee80211_sta_work * to fix this. */ - if(sdata->vif.type == IEEE80211_IF_TYPE_STA || - sdata->vif.type == IEEE80211_IF_TYPE_IBSS) { + if (sdata->vif.type == IEEE80211_IF_TYPE_STA || + sdata->vif.type == IEEE80211_IF_TYPE_IBSS) { struct ieee80211_if_sta *ifsta = &sdata->u.sta; queue_work(local->hw.workqueue, &ifsta->work); } - netif_start_queue(dev); + netif_tx_start_all_queues(dev); return 0; err_del_interface: @@ -399,6 +383,10 @@ static int ieee80211_open(struct net_device *dev) err_stop: if (!local->open_count && local->ops->stop) local->ops->stop(local_to_hw(local)); + err_del_bss: + sdata->bss = NULL; + if (sdata->vif.type == IEEE80211_IF_TYPE_VLAN) + list_del(&sdata->u.vlan.list); return res; } @@ -412,7 +400,7 @@ static int ieee80211_stop(struct net_device *dev) /* * Stop TX on this interface first. */ - netif_stop_queue(dev); + netif_tx_stop_all_queues(dev); /* * Now delete all active aggregation sessions. @@ -481,7 +469,6 @@ static int ieee80211_stop(struct net_device *dev) switch (sdata->vif.type) { case IEEE80211_IF_TYPE_VLAN: list_del(&sdata->u.vlan.list); - sdata->u.vlan.ap = NULL; /* no need to tell driver */ break; case IEEE80211_IF_TYPE_MNTR: @@ -503,9 +490,9 @@ static int ieee80211_stop(struct net_device *dev) if (sdata->u.mntr_flags & MONITOR_FLAG_OTHER_BSS) local->fif_other_bss--; - netif_tx_lock_bh(local->mdev); + netif_addr_lock_bh(local->mdev); ieee80211_configure_filter(local); - netif_tx_unlock_bh(local->mdev); + netif_addr_unlock_bh(local->mdev); break; case IEEE80211_IF_TYPE_MESH_POINT: case IEEE80211_IF_TYPE_STA: @@ -544,6 +531,8 @@ static int ieee80211_stop(struct net_device *dev) local->ops->remove_interface(local_to_hw(local), &conf); } + sdata->bss = NULL; + if (local->open_count == 0) { if (netif_running(local->mdev)) dev_close(local->mdev); @@ -584,17 +573,19 @@ int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid) sta = sta_info_get(local, ra); if (!sta) { +#ifdef CONFIG_MAC80211_HT_DEBUG printk(KERN_DEBUG "Could not find the station\n"); - rcu_read_unlock(); - return -ENOENT; +#endif + ret = -ENOENT; + goto exit; } - spin_lock_bh(&sta->ampdu_mlme.ampdu_tx); + spin_lock_bh(&sta->lock); /* we have tried too many times, receiver does not want A-MPDU */ if (sta->ampdu_mlme.addba_req_num[tid] > HT_AGG_MAX_RETRIES) { ret = -EBUSY; - goto start_ba_exit; + goto err_unlock_sta; } state = &sta->ampdu_mlme.tid_state_tx[tid]; @@ -605,18 +596,20 @@ int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid) "idle on tid %u\n", tid); #endif /* CONFIG_MAC80211_HT_DEBUG */ ret = -EAGAIN; - goto start_ba_exit; + goto err_unlock_sta; } /* prepare A-MPDU MLME for Tx aggregation */ sta->ampdu_mlme.tid_tx[tid] = kmalloc(sizeof(struct tid_ampdu_tx), GFP_ATOMIC); if (!sta->ampdu_mlme.tid_tx[tid]) { +#ifdef CONFIG_MAC80211_HT_DEBUG if (net_ratelimit()) printk(KERN_ERR "allocate tx mlme to tid %d failed\n", tid); +#endif ret = -ENOMEM; - goto start_ba_exit; + goto err_unlock_sta; } /* Tx timer */ sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer.function = @@ -625,10 +618,6 @@ int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid) (unsigned long)&sta->timer_to_tid[tid]; init_timer(&sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer); - /* ensure that TX flow won't interrupt us - * until the end of the call to requeue function */ - spin_lock_bh(&local->mdev->queue_lock); - /* create a new queue for this aggregation */ ret = ieee80211_ht_agg_queue_add(local, sta, tid); @@ -639,7 +628,7 @@ int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid) printk(KERN_DEBUG "BA request denied - queue unavailable for" " tid %d\n", tid); #endif /* CONFIG_MAC80211_HT_DEBUG */ - goto start_ba_err; + goto err_unlock_queue; } sdata = sta->sdata; @@ -655,18 +644,18 @@ int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid) /* No need to requeue the packets in the agg queue, since we * held the tx lock: no packet could be enqueued to the newly * allocated queue */ - ieee80211_ht_agg_queue_remove(local, sta, tid, 0); + ieee80211_ht_agg_queue_remove(local, sta, tid, 0); #ifdef CONFIG_MAC80211_HT_DEBUG printk(KERN_DEBUG "BA request denied - HW unavailable for" " tid %d\n", tid); #endif /* CONFIG_MAC80211_HT_DEBUG */ *state = HT_AGG_STATE_IDLE; - goto start_ba_err; + goto err_unlock_queue; } /* Will put all the packets in the new SW queue */ ieee80211_requeue(local, ieee802_1d_to_ac[tid]); - spin_unlock_bh(&local->mdev->queue_lock); + spin_unlock_bh(&sta->lock); /* send an addBA request */ sta->ampdu_mlme.dialog_token_allocator++; @@ -674,25 +663,27 @@ int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid) sta->ampdu_mlme.dialog_token_allocator; sta->ampdu_mlme.tid_tx[tid]->ssn = start_seq_num; + ieee80211_send_addba_request(sta->sdata->dev, ra, tid, sta->ampdu_mlme.tid_tx[tid]->dialog_token, sta->ampdu_mlme.tid_tx[tid]->ssn, 0x40, 5000); - /* activate the timer for the recipient's addBA response */ sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer.expires = jiffies + ADDBA_RESP_INTERVAL; add_timer(&sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer); +#ifdef CONFIG_MAC80211_HT_DEBUG printk(KERN_DEBUG "activated addBA response timer on tid %d\n", tid); - goto start_ba_exit; +#endif + goto exit; -start_ba_err: +err_unlock_queue: kfree(sta->ampdu_mlme.tid_tx[tid]); sta->ampdu_mlme.tid_tx[tid] = NULL; - spin_unlock_bh(&local->mdev->queue_lock); ret = -EBUSY; -start_ba_exit: - spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx); +err_unlock_sta: + spin_unlock_bh(&sta->lock); +exit: rcu_read_unlock(); return ret; } @@ -720,7 +711,7 @@ int ieee80211_stop_tx_ba_session(struct ieee80211_hw *hw, /* check if the TID is in aggregation */ state = &sta->ampdu_mlme.tid_state_tx[tid]; - spin_lock_bh(&sta->ampdu_mlme.ampdu_tx); + spin_lock_bh(&sta->lock); if (*state != HT_AGG_STATE_OPERATIONAL) { ret = -ENOENT; @@ -750,7 +741,7 @@ int ieee80211_stop_tx_ba_session(struct ieee80211_hw *hw, } stop_BA_exit: - spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx); + spin_unlock_bh(&sta->lock); rcu_read_unlock(); return ret; } @@ -764,8 +755,10 @@ void ieee80211_start_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u16 tid) DECLARE_MAC_BUF(mac); if (tid >= STA_TID_NUM) { +#ifdef CONFIG_MAC80211_HT_DEBUG printk(KERN_DEBUG "Bad TID value: tid = %d (>= %d)\n", tid, STA_TID_NUM); +#endif return; } @@ -773,18 +766,22 @@ void ieee80211_start_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u16 tid) sta = sta_info_get(local, ra); if (!sta) { rcu_read_unlock(); +#ifdef CONFIG_MAC80211_HT_DEBUG printk(KERN_DEBUG "Could not find station: %s\n", print_mac(mac, ra)); +#endif return; } state = &sta->ampdu_mlme.tid_state_tx[tid]; - spin_lock_bh(&sta->ampdu_mlme.ampdu_tx); + spin_lock_bh(&sta->lock); if (!(*state & HT_ADDBA_REQUESTED_MSK)) { +#ifdef CONFIG_MAC80211_HT_DEBUG printk(KERN_DEBUG "addBA was not requested yet, state is %d\n", *state); - spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx); +#endif + spin_unlock_bh(&sta->lock); rcu_read_unlock(); return; } @@ -794,10 +791,12 @@ void ieee80211_start_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u16 tid) *state |= HT_ADDBA_DRV_READY_MSK; if (*state == HT_AGG_STATE_OPERATIONAL) { +#ifdef CONFIG_MAC80211_HT_DEBUG printk(KERN_DEBUG "Aggregation is on for tid %d \n", tid); +#endif ieee80211_wake_queue(hw, sta->tid_to_tx_q[tid]); } - spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx); + spin_unlock_bh(&sta->lock); rcu_read_unlock(); } EXPORT_SYMBOL(ieee80211_start_tx_ba_cb); @@ -811,8 +810,10 @@ void ieee80211_stop_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u8 tid) DECLARE_MAC_BUF(mac); if (tid >= STA_TID_NUM) { +#ifdef CONFIG_MAC80211_HT_DEBUG printk(KERN_DEBUG "Bad TID value: tid = %d (>= %d)\n", tid, STA_TID_NUM); +#endif return; } @@ -824,17 +825,23 @@ void ieee80211_stop_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u8 tid) rcu_read_lock(); sta = sta_info_get(local, ra); if (!sta) { +#ifdef CONFIG_MAC80211_HT_DEBUG printk(KERN_DEBUG "Could not find station: %s\n", print_mac(mac, ra)); +#endif rcu_read_unlock(); return; } state = &sta->ampdu_mlme.tid_state_tx[tid]; - spin_lock_bh(&sta->ampdu_mlme.ampdu_tx); + /* NOTE: no need to use sta->lock in this state check, as + * ieee80211_stop_tx_ba_session will let only one stop call to + * pass through per sta/tid + */ if ((*state & HT_AGG_STATE_REQ_STOP_BA_MSK) == 0) { +#ifdef CONFIG_MAC80211_HT_DEBUG printk(KERN_DEBUG "unexpected callback to A-MPDU stop\n"); - spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx); +#endif rcu_read_unlock(); return; } @@ -845,23 +852,20 @@ void ieee80211_stop_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u8 tid) agg_queue = sta->tid_to_tx_q[tid]; - /* avoid ordering issues: we are the only one that can modify - * the content of the qdiscs */ - spin_lock_bh(&local->mdev->queue_lock); - /* remove the queue for this aggregation */ ieee80211_ht_agg_queue_remove(local, sta, tid, 1); - spin_unlock_bh(&local->mdev->queue_lock); - /* we just requeued the all the frames that were in the removed - * queue, and since we might miss a softirq we do netif_schedule. - * ieee80211_wake_queue is not used here as this queue is not - * necessarily stopped */ - netif_schedule(local->mdev); + /* We just requeued the all the frames that were in the + * removed queue, and since we might miss a softirq we do + * netif_schedule_queue. ieee80211_wake_queue is not used + * here as this queue is not necessarily stopped + */ + netif_schedule_queue(netdev_get_tx_queue(local->mdev, agg_queue)); + spin_lock_bh(&sta->lock); *state = HT_AGG_STATE_IDLE; sta->ampdu_mlme.addba_req_num[tid] = 0; kfree(sta->ampdu_mlme.tid_tx[tid]); sta->ampdu_mlme.tid_tx[tid] = NULL; - spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx); + spin_unlock_bh(&sta->lock); rcu_read_unlock(); } @@ -875,9 +879,11 @@ void ieee80211_start_tx_ba_cb_irqsafe(struct ieee80211_hw *hw, struct sk_buff *skb = dev_alloc_skb(0); if (unlikely(!skb)) { +#ifdef CONFIG_MAC80211_HT_DEBUG if (net_ratelimit()) printk(KERN_WARNING "%s: Not enough memory, " "dropping start BA session", skb->dev->name); +#endif return; } ra_tid = (struct ieee80211_ra_tid *) &skb->cb; @@ -898,9 +904,11 @@ void ieee80211_stop_tx_ba_cb_irqsafe(struct ieee80211_hw *hw, struct sk_buff *skb = dev_alloc_skb(0); if (unlikely(!skb)) { +#ifdef CONFIG_MAC80211_HT_DEBUG if (net_ratelimit()) printk(KERN_WARNING "%s: Not enough memory, " "dropping stop BA session", skb->dev->name); +#endif return; } ra_tid = (struct ieee80211_ra_tid *) &skb->cb; @@ -951,7 +959,6 @@ static const struct header_ops ieee80211_header_ops = { .cache_update = eth_header_cache_update, }; -/* Must not be called for mdev */ void ieee80211_if_setup(struct net_device *dev) { ether_setup(dev); @@ -961,67 +968,52 @@ void ieee80211_if_setup(struct net_device *dev) dev->change_mtu = ieee80211_change_mtu; dev->open = ieee80211_open; dev->stop = ieee80211_stop; - dev->destructor = ieee80211_if_free; + dev->destructor = free_netdev; } /* everything else */ -static int __ieee80211_if_config(struct net_device *dev, - struct sk_buff *beacon, - struct ieee80211_tx_control *control) +int ieee80211_if_config(struct ieee80211_sub_if_data *sdata, u32 changed) { - struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); + struct ieee80211_local *local = sdata->local; struct ieee80211_if_conf conf; - if (!local->ops->config_interface || !netif_running(dev)) + if (WARN_ON(!netif_running(sdata->dev))) + return 0; + + if (!local->ops->config_interface) return 0; memset(&conf, 0, sizeof(conf)); - conf.type = sdata->vif.type; + conf.changed = changed; + if (sdata->vif.type == IEEE80211_IF_TYPE_STA || sdata->vif.type == IEEE80211_IF_TYPE_IBSS) { conf.bssid = sdata->u.sta.bssid; conf.ssid = sdata->u.sta.ssid; conf.ssid_len = sdata->u.sta.ssid_len; - } else if (ieee80211_vif_is_mesh(&sdata->vif)) { - conf.beacon = beacon; - conf.beacon_control = control; - ieee80211_start_mesh(dev); } else if (sdata->vif.type == IEEE80211_IF_TYPE_AP) { + conf.bssid = sdata->dev->dev_addr; conf.ssid = sdata->u.ap.ssid; conf.ssid_len = sdata->u.ap.ssid_len; - conf.beacon = beacon; - conf.beacon_control = control; + } else if (ieee80211_vif_is_mesh(&sdata->vif)) { + u8 zero[ETH_ALEN] = { 0 }; + conf.bssid = zero; + conf.ssid = zero; + conf.ssid_len = 0; + } else { + WARN_ON(1); + return -EINVAL; } - return local->ops->config_interface(local_to_hw(local), - &sdata->vif, &conf); -} -int ieee80211_if_config(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); - if (sdata->vif.type == IEEE80211_IF_TYPE_MESH_POINT && - (local->hw.flags & IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE)) - return ieee80211_if_config_beacon(dev); - return __ieee80211_if_config(dev, NULL, NULL); -} + if (WARN_ON(!conf.bssid && (changed & IEEE80211_IFCC_BSSID))) + return -EINVAL; -int ieee80211_if_config_beacon(struct net_device *dev) -{ - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - struct ieee80211_tx_control control; - struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); - struct sk_buff *skb; + if (WARN_ON(!conf.ssid && (changed & IEEE80211_IFCC_SSID))) + return -EINVAL; - if (!(local->hw.flags & IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE)) - return 0; - skb = ieee80211_beacon_get(local_to_hw(local), &sdata->vif, - &control); - if (!skb) - return -ENOMEM; - return __ieee80211_if_config(dev, skb, &control); + return local->ops->config_interface(local_to_hw(local), + &sdata->vif, &conf); } int ieee80211_hw_config(struct ieee80211_local *local) @@ -1068,56 +1060,84 @@ u32 ieee80211_handle_ht(struct ieee80211_local *local, int enable_ht, struct ieee80211_supported_band *sband; struct ieee80211_ht_info ht_conf; struct ieee80211_ht_bss_info ht_bss_conf; - int i; u32 changed = 0; + int i; + u8 max_tx_streams = IEEE80211_HT_CAP_MAX_STREAMS; + u8 tx_mcs_set_cap; sband = local->hw.wiphy->bands[conf->channel->band]; + memset(&ht_conf, 0, sizeof(struct ieee80211_ht_info)); + memset(&ht_bss_conf, 0, sizeof(struct ieee80211_ht_bss_info)); + /* HT is not supported */ if (!sband->ht_info.ht_supported) { conf->flags &= ~IEEE80211_CONF_SUPPORT_HT_MODE; - return 0; + goto out; } - memset(&ht_conf, 0, sizeof(struct ieee80211_ht_info)); - memset(&ht_bss_conf, 0, sizeof(struct ieee80211_ht_bss_info)); - - if (enable_ht) { - if (!(conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE)) + /* disable HT */ + if (!enable_ht) { + if (conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE) changed |= BSS_CHANGED_HT; + conf->flags &= ~IEEE80211_CONF_SUPPORT_HT_MODE; + conf->ht_conf.ht_supported = 0; + goto out; + } - conf->flags |= IEEE80211_CONF_SUPPORT_HT_MODE; - ht_conf.ht_supported = 1; - ht_conf.cap = req_ht_cap->cap & sband->ht_info.cap; - ht_conf.cap &= ~(IEEE80211_HT_CAP_MIMO_PS); - ht_conf.cap |= sband->ht_info.cap & IEEE80211_HT_CAP_MIMO_PS; + if (!(conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE)) + changed |= BSS_CHANGED_HT; - for (i = 0; i < SUPP_MCS_SET_LEN; i++) - ht_conf.supp_mcs_set[i] = - sband->ht_info.supp_mcs_set[i] & - req_ht_cap->supp_mcs_set[i]; + conf->flags |= IEEE80211_CONF_SUPPORT_HT_MODE; + ht_conf.ht_supported = 1; - ht_bss_conf.primary_channel = req_bss_cap->primary_channel; - ht_bss_conf.bss_cap = req_bss_cap->bss_cap; - ht_bss_conf.bss_op_mode = req_bss_cap->bss_op_mode; + ht_conf.cap = req_ht_cap->cap & sband->ht_info.cap; + ht_conf.cap &= ~(IEEE80211_HT_CAP_MIMO_PS); + ht_conf.cap |= sband->ht_info.cap & IEEE80211_HT_CAP_MIMO_PS; + ht_bss_conf.primary_channel = req_bss_cap->primary_channel; + ht_bss_conf.bss_cap = req_bss_cap->bss_cap; + ht_bss_conf.bss_op_mode = req_bss_cap->bss_op_mode; - ht_conf.ampdu_factor = req_ht_cap->ampdu_factor; - ht_conf.ampdu_density = req_ht_cap->ampdu_density; + ht_conf.ampdu_factor = req_ht_cap->ampdu_factor; + ht_conf.ampdu_density = req_ht_cap->ampdu_density; - /* if bss configuration changed store the new one */ - if (memcmp(&conf->ht_conf, &ht_conf, sizeof(ht_conf)) || - memcmp(&conf->ht_bss_conf, &ht_bss_conf, sizeof(ht_bss_conf))) { - changed |= BSS_CHANGED_HT; - memcpy(&conf->ht_conf, &ht_conf, sizeof(ht_conf)); - memcpy(&conf->ht_bss_conf, &ht_bss_conf, sizeof(ht_bss_conf)); - } - } else { - if (conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE) - changed |= BSS_CHANGED_HT; - conf->flags &= ~IEEE80211_CONF_SUPPORT_HT_MODE; - } + /* Bits 96-100 */ + tx_mcs_set_cap = sband->ht_info.supp_mcs_set[12]; + + /* configure suppoerted Tx MCS according to requested MCS + * (based in most cases on Rx capabilities of peer) and self + * Tx MCS capabilities (as defined by low level driver HW + * Tx capabilities) */ + if (!(tx_mcs_set_cap & IEEE80211_HT_CAP_MCS_TX_DEFINED)) + goto check_changed; + /* Counting from 0 therfore + 1 */ + if (tx_mcs_set_cap & IEEE80211_HT_CAP_MCS_TX_RX_DIFF) + max_tx_streams = ((tx_mcs_set_cap & + IEEE80211_HT_CAP_MCS_TX_STREAMS) >> 2) + 1; + + for (i = 0; i < max_tx_streams; i++) + ht_conf.supp_mcs_set[i] = + sband->ht_info.supp_mcs_set[i] & + req_ht_cap->supp_mcs_set[i]; + + if (tx_mcs_set_cap & IEEE80211_HT_CAP_MCS_TX_UEQM) + for (i = IEEE80211_SUPP_MCS_SET_UEQM; + i < IEEE80211_SUPP_MCS_SET_LEN; i++) + ht_conf.supp_mcs_set[i] = + sband->ht_info.supp_mcs_set[i] & + req_ht_cap->supp_mcs_set[i]; + +check_changed: + /* if bss configuration changed store the new one */ + if (memcmp(&conf->ht_conf, &ht_conf, sizeof(ht_conf)) || + memcmp(&conf->ht_bss_conf, &ht_bss_conf, sizeof(ht_bss_conf))) { + changed |= BSS_CHANGED_HT; + memcpy(&conf->ht_conf, &ht_conf, sizeof(ht_conf)); + memcpy(&conf->ht_bss_conf, &ht_bss_conf, sizeof(ht_bss_conf)); + } +out: return changed; } @@ -1136,50 +1156,30 @@ void ieee80211_bss_info_change_notify(struct ieee80211_sub_if_data *sdata, changed); } -void ieee80211_reset_erp_info(struct net_device *dev) +u32 ieee80211_reset_erp_info(struct net_device *dev) { struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); sdata->bss_conf.use_cts_prot = 0; sdata->bss_conf.use_short_preamble = 0; - ieee80211_bss_info_change_notify(sdata, - BSS_CHANGED_ERP_CTS_PROT | - BSS_CHANGED_ERP_PREAMBLE); + return BSS_CHANGED_ERP_CTS_PROT | BSS_CHANGED_ERP_PREAMBLE; } void ieee80211_tx_status_irqsafe(struct ieee80211_hw *hw, - struct sk_buff *skb, - struct ieee80211_tx_status *status) + struct sk_buff *skb) { struct ieee80211_local *local = hw_to_local(hw); - struct ieee80211_tx_status *saved; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); int tmp; skb->dev = local->mdev; - saved = kmalloc(sizeof(struct ieee80211_tx_status), GFP_ATOMIC); - if (unlikely(!saved)) { - if (net_ratelimit()) - printk(KERN_WARNING "%s: Not enough memory, " - "dropping tx status", skb->dev->name); - /* should be dev_kfree_skb_irq, but due to this function being - * named _irqsafe instead of just _irq we can't be sure that - * people won't call it from non-irq contexts */ - dev_kfree_skb_any(skb); - return; - } - memcpy(saved, status, sizeof(struct ieee80211_tx_status)); - /* copy pointer to saved status into skb->cb for use by tasklet */ - memcpy(skb->cb, &saved, sizeof(saved)); - skb->pkt_type = IEEE80211_TX_STATUS_MSG; - skb_queue_tail(status->control.flags & IEEE80211_TXCTL_REQ_TX_STATUS ? + skb_queue_tail(info->flags & IEEE80211_TX_CTL_REQ_TX_STATUS ? &local->skb_queue : &local->skb_queue_unreliable, skb); tmp = skb_queue_len(&local->skb_queue) + skb_queue_len(&local->skb_queue_unreliable); while (tmp > IEEE80211_IRQSAFE_QUEUE_LIMIT && (skb = skb_dequeue(&local->skb_queue_unreliable))) { - memcpy(&saved, skb->cb, sizeof(saved)); - kfree(saved); dev_kfree_skb_irq(skb); tmp--; I802_DEBUG_INC(local->tx_status_drop); @@ -1193,7 +1193,6 @@ static void ieee80211_tasklet_handler(unsigned long data) struct ieee80211_local *local = (struct ieee80211_local *) data; struct sk_buff *skb; struct ieee80211_rx_status rx_status; - struct ieee80211_tx_status *tx_status; struct ieee80211_ra_tid *ra_tid; while ((skb = skb_dequeue(&local->skb_queue)) || @@ -1208,12 +1207,8 @@ static void ieee80211_tasklet_handler(unsigned long data) __ieee80211_rx(local_to_hw(local), skb, &rx_status); break; case IEEE80211_TX_STATUS_MSG: - /* get pointer to saved status out of skb->cb */ - memcpy(&tx_status, skb->cb, sizeof(tx_status)); skb->pkt_type = 0; - ieee80211_tx_status(local_to_hw(local), - skb, tx_status); - kfree(tx_status); + ieee80211_tx_status(local_to_hw(local), skb); break; case IEEE80211_DELBA_MSG: ra_tid = (struct ieee80211_ra_tid *) &skb->cb; @@ -1227,9 +1222,8 @@ static void ieee80211_tasklet_handler(unsigned long data) ra_tid->ra, ra_tid->tid); dev_kfree_skb(skb); break ; - default: /* should never get here! */ - printk(KERN_ERR "%s: Unknown message type (%d)\n", - wiphy_name(local->hw.wiphy), skb->pkt_type); + default: + WARN_ON(1); dev_kfree_skb(skb); break; } @@ -1242,24 +1236,15 @@ static void ieee80211_tasklet_handler(unsigned long data) * Also, tx_packet_data in cb is restored from tx_control. */ static void ieee80211_remove_tx_extra(struct ieee80211_local *local, struct ieee80211_key *key, - struct sk_buff *skb, - struct ieee80211_tx_control *control) + struct sk_buff *skb) { int hdrlen, iv_len, mic_len; - struct ieee80211_tx_packet_data *pkt_data; - - pkt_data = (struct ieee80211_tx_packet_data *)skb->cb; - pkt_data->ifindex = vif_to_sdata(control->vif)->dev->ifindex; - pkt_data->flags = 0; - if (control->flags & IEEE80211_TXCTL_REQ_TX_STATUS) - pkt_data->flags |= IEEE80211_TXPD_REQ_TX_STATUS; - if (control->flags & IEEE80211_TXCTL_DO_NOT_ENCRYPT) - pkt_data->flags |= IEEE80211_TXPD_DO_NOT_ENCRYPT; - if (control->flags & IEEE80211_TXCTL_REQUEUE) - pkt_data->flags |= IEEE80211_TXPD_REQUEUE; - if (control->flags & IEEE80211_TXCTL_EAPOL_FRAME) - pkt_data->flags |= IEEE80211_TXPD_EAPOL_FRAME; - pkt_data->queue = control->queue; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + + info->flags &= IEEE80211_TX_CTL_REQ_TX_STATUS | + IEEE80211_TX_CTL_DO_NOT_ENCRYPT | + IEEE80211_TX_CTL_REQUEUE | + IEEE80211_TX_CTL_EAPOL_FRAME; hdrlen = ieee80211_get_hdrlen_from_skb(skb); @@ -1306,9 +1291,10 @@ no_key: static void ieee80211_handle_filtered_frame(struct ieee80211_local *local, struct sta_info *sta, - struct sk_buff *skb, - struct ieee80211_tx_status *status) + struct sk_buff *skb) { + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + sta->tx_filtered_count++; /* @@ -1316,7 +1302,7 @@ static void ieee80211_handle_filtered_frame(struct ieee80211_local *local, * packet. If the STA went to power save mode, this will happen * when it wakes up for the next time. */ - sta->flags |= WLAN_STA_CLEAR_PS_FILT; + set_sta_flags(sta, WLAN_STA_CLEAR_PS_FILT); /* * This code races in the following way: @@ -1348,84 +1334,89 @@ static void ieee80211_handle_filtered_frame(struct ieee80211_local *local, * can be unknown, for example with different interrupt status * bits. */ - if (sta->flags & WLAN_STA_PS && + 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, - &status->control); + ieee80211_remove_tx_extra(local, sta->key, skb); skb_queue_tail(&sta->tx_filtered, skb); return; } - if (!(sta->flags & WLAN_STA_PS) && - !(status->control.flags & IEEE80211_TXCTL_REQUEUE)) { + if (!test_sta_flags(sta, WLAN_STA_PS) && + !(info->flags & IEEE80211_TX_CTL_REQUEUE)) { /* Software retry the packet once */ - status->control.flags |= IEEE80211_TXCTL_REQUEUE; - ieee80211_remove_tx_extra(local, sta->key, skb, - &status->control); + info->flags |= IEEE80211_TX_CTL_REQUEUE; + ieee80211_remove_tx_extra(local, sta->key, skb); dev_queue_xmit(skb); return; } +#ifdef CONFIG_MAC80211_VERBOSE_DEBUG if (net_ratelimit()) printk(KERN_DEBUG "%s: dropped TX filtered frame, " "queue_len=%d PS=%d @%lu\n", wiphy_name(local->hw.wiphy), skb_queue_len(&sta->tx_filtered), - !!(sta->flags & WLAN_STA_PS), jiffies); + !!test_sta_flags(sta, WLAN_STA_PS), jiffies); +#endif dev_kfree_skb(skb); } -void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb, - struct ieee80211_tx_status *status) +void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb) { struct sk_buff *skb2; struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; struct ieee80211_local *local = hw_to_local(hw); + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); u16 frag, type; + __le16 fc; struct ieee80211_tx_status_rtap_hdr *rthdr; struct ieee80211_sub_if_data *sdata; struct net_device *prev_dev = NULL; - - if (!status) { - printk(KERN_ERR - "%s: ieee80211_tx_status called with NULL status\n", - wiphy_name(local->hw.wiphy)); - dev_kfree_skb(skb); - return; - } + struct sta_info *sta; rcu_read_lock(); - if (status->excessive_retries) { - struct sta_info *sta; + if (info->status.excessive_retries) { sta = sta_info_get(local, hdr->addr1); if (sta) { - if (sta->flags & WLAN_STA_PS) { + if (test_sta_flags(sta, WLAN_STA_PS)) { /* * The STA is in power save mode, so assume * that this TX packet failed because of that. */ - status->excessive_retries = 0; - status->flags |= IEEE80211_TX_STATUS_TX_FILTERED; - ieee80211_handle_filtered_frame(local, sta, - skb, status); + ieee80211_handle_filtered_frame(local, sta, skb); rcu_read_unlock(); return; } } } - if (status->flags & IEEE80211_TX_STATUS_TX_FILTERED) { - struct sta_info *sta; + fc = hdr->frame_control; + + if ((info->flags & IEEE80211_TX_STAT_AMPDU_NO_BACK) && + (ieee80211_is_data_qos(fc))) { + u16 tid, ssn; + u8 *qc; sta = sta_info_get(local, hdr->addr1); if (sta) { - ieee80211_handle_filtered_frame(local, sta, skb, - status); + qc = ieee80211_get_qos_ctl(hdr); + tid = qc[0] & 0xf; + ssn = ((le16_to_cpu(hdr->seq_ctrl) + 0x10) + & IEEE80211_SCTL_SEQ); + ieee80211_send_bar(sta->sdata->dev, hdr->addr1, + tid, ssn); + } + } + + if (info->flags & IEEE80211_TX_STAT_TX_FILTERED) { + sta = sta_info_get(local, hdr->addr1); + if (sta) { + ieee80211_handle_filtered_frame(local, sta, skb); rcu_read_unlock(); return; } } else - rate_control_tx_status(local->mdev, skb, status); + rate_control_tx_status(local->mdev, skb); rcu_read_unlock(); @@ -1439,14 +1430,14 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb, frag = le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_FRAG; type = le16_to_cpu(hdr->frame_control) & IEEE80211_FCTL_FTYPE; - if (status->flags & IEEE80211_TX_STATUS_ACK) { + if (info->flags & IEEE80211_TX_STAT_ACK) { if (frag == 0) { local->dot11TransmittedFrameCount++; if (is_multicast_ether_addr(hdr->addr1)) local->dot11MulticastTransmittedFrameCount++; - if (status->retry_count > 0) + if (info->status.retry_count > 0) local->dot11RetryCount++; - if (status->retry_count > 1) + if (info->status.retry_count > 1) local->dot11MultipleRetryCount++; } @@ -1483,7 +1474,7 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb, return; } - rthdr = (struct ieee80211_tx_status_rtap_hdr*) + rthdr = (struct ieee80211_tx_status_rtap_hdr *) skb_push(skb, sizeof(*rthdr)); memset(rthdr, 0, sizeof(*rthdr)); @@ -1492,17 +1483,17 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb, cpu_to_le32((1 << IEEE80211_RADIOTAP_TX_FLAGS) | (1 << IEEE80211_RADIOTAP_DATA_RETRIES)); - if (!(status->flags & IEEE80211_TX_STATUS_ACK) && + if (!(info->flags & IEEE80211_TX_STAT_ACK) && !is_multicast_ether_addr(hdr->addr1)) rthdr->tx_flags |= cpu_to_le16(IEEE80211_RADIOTAP_F_TX_FAIL); - if ((status->control.flags & IEEE80211_TXCTL_USE_RTS_CTS) && - (status->control.flags & IEEE80211_TXCTL_USE_CTS_PROTECT)) + if ((info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) && + (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT)) rthdr->tx_flags |= cpu_to_le16(IEEE80211_RADIOTAP_F_TX_CTS); - else if (status->control.flags & IEEE80211_TXCTL_USE_RTS_CTS) + else if (info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) rthdr->tx_flags |= cpu_to_le16(IEEE80211_RADIOTAP_F_TX_RTS); - rthdr->data_retries = status->retry_count; + rthdr->data_retries = info->status.retry_count; /* XXX: is this sufficient for BPF? */ skb_set_mac_header(skb, 0); @@ -1628,7 +1619,7 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) int result; enum ieee80211_band band; struct net_device *mdev; - struct ieee80211_sub_if_data *sdata; + struct wireless_dev *mwdev; /* * generic code guarantees at least one band, @@ -1652,19 +1643,30 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) if (result < 0) return result; - /* for now, mdev needs sub_if_data :/ */ - mdev = alloc_netdev(sizeof(struct ieee80211_sub_if_data), - "wmaster%d", ether_setup); + /* + * We use the number of queues for feature tests (QoS, HT) internally + * so restrict them appropriately. + */ + if (hw->queues > IEEE80211_MAX_QUEUES) + hw->queues = IEEE80211_MAX_QUEUES; + if (hw->ampdu_queues > IEEE80211_MAX_AMPDU_QUEUES) + hw->ampdu_queues = IEEE80211_MAX_AMPDU_QUEUES; + if (hw->queues < 4) + hw->ampdu_queues = 0; + + mdev = alloc_netdev_mq(sizeof(struct wireless_dev), + "wmaster%d", ether_setup, + ieee80211_num_queues(hw)); if (!mdev) goto fail_mdev_alloc; - sdata = IEEE80211_DEV_TO_SUB_IF(mdev); - mdev->ieee80211_ptr = &sdata->wdev; - sdata->wdev.wiphy = local->hw.wiphy; + mwdev = netdev_priv(mdev); + mdev->ieee80211_ptr = mwdev; + mwdev->wiphy = local->hw.wiphy; local->mdev = mdev; - ieee80211_rx_bss_list_init(mdev); + ieee80211_rx_bss_list_init(local); mdev->hard_start_xmit = ieee80211_master_start_xmit; mdev->open = ieee80211_master_open; @@ -1673,18 +1675,8 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) mdev->header_ops = &ieee80211_header_ops; mdev->set_multicast_list = ieee80211_master_set_multicast_list; - sdata->vif.type = IEEE80211_IF_TYPE_AP; - sdata->dev = mdev; - sdata->local = local; - sdata->u.ap.force_unicast_rateidx = -1; - sdata->u.ap.max_ratectrl_rateidx = -1; - ieee80211_if_sdata_init(sdata); - - /* no RCU needed since we're still during init phase */ - list_add_tail(&sdata->list, &local->interfaces); - name = wiphy_dev(local->hw.wiphy)->driver->name; - local->hw.workqueue = create_singlethread_workqueue(name); + local->hw.workqueue = create_freezeable_workqueue(name); if (!local->hw.workqueue) { result = -ENOMEM; goto fail_workqueue; @@ -1700,15 +1692,16 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) debugfs_hw_add(local); - local->hw.conf.beacon_int = 1000; + if (local->hw.conf.beacon_int < 10) + local->hw.conf.beacon_int = 100; - local->wstats_flags |= local->hw.max_rssi ? - IW_QUAL_LEVEL_UPDATED : IW_QUAL_LEVEL_INVALID; - local->wstats_flags |= local->hw.max_signal ? + local->wstats_flags |= local->hw.flags & (IEEE80211_HW_SIGNAL_UNSPEC | + IEEE80211_HW_SIGNAL_DB | + IEEE80211_HW_SIGNAL_DBM) ? IW_QUAL_QUAL_UPDATED : IW_QUAL_QUAL_INVALID; - local->wstats_flags |= local->hw.max_noise ? + local->wstats_flags |= local->hw.flags & IEEE80211_HW_NOISE_DBM ? IW_QUAL_NOISE_UPDATED : IW_QUAL_NOISE_INVALID; - if (local->hw.max_rssi < 0 || local->hw.max_noise < 0) + if (local->hw.flags & IEEE80211_HW_SIGNAL_DBM) local->wstats_flags |= IW_QUAL_DBM; result = sta_info_start(local); @@ -1727,9 +1720,6 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) if (result < 0) goto fail_dev; - ieee80211_debugfs_add_netdev(IEEE80211_DEV_TO_SUB_IF(local->mdev)); - ieee80211_if_set_type(local->mdev, IEEE80211_IF_TYPE_AP); - result = ieee80211_init_rate_ctrl_alg(local, hw->rate_control_algorithm); if (result < 0) { @@ -1746,16 +1736,15 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) goto fail_wep; } - ieee80211_install_qdisc(local->mdev); + local->mdev->select_queue = ieee80211_select_queue; /* add one default STA interface */ - result = ieee80211_if_add(local->mdev, "wlan%d", NULL, + result = ieee80211_if_add(local, "wlan%d", NULL, IEEE80211_IF_TYPE_STA, NULL); if (result) printk(KERN_WARNING "%s: Failed to add default virtual iface\n", wiphy_name(local->hw.wiphy)); - local->reg_state = IEEE80211_DEV_REGISTERED; rtnl_unlock(); ieee80211_led_init(local); @@ -1765,7 +1754,6 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) fail_wep: rate_control_deinitialize(local); fail_rate: - ieee80211_debugfs_remove_netdev(IEEE80211_DEV_TO_SUB_IF(local->mdev)); unregister_netdevice(local->mdev); local->mdev = NULL; fail_dev: @@ -1775,10 +1763,8 @@ fail_sta_info: debugfs_hw_del(local); destroy_workqueue(local->hw.workqueue); fail_workqueue: - if (local->mdev != NULL) { - ieee80211_if_free(local->mdev); - local->mdev = NULL; - } + if (local->mdev) + free_netdev(local->mdev); fail_mdev_alloc: wiphy_unregister(local->hw.wiphy); return result; @@ -1788,42 +1774,27 @@ EXPORT_SYMBOL(ieee80211_register_hw); void ieee80211_unregister_hw(struct ieee80211_hw *hw) { struct ieee80211_local *local = hw_to_local(hw); - struct ieee80211_sub_if_data *sdata, *tmp; tasklet_kill(&local->tx_pending_tasklet); tasklet_kill(&local->tasklet); rtnl_lock(); - BUG_ON(local->reg_state != IEEE80211_DEV_REGISTERED); - - local->reg_state = IEEE80211_DEV_UNREGISTERED; - /* * At this point, interface list manipulations are fine * because the driver cannot be handing us frames any * more and the tasklet is killed. */ - /* - * First, we remove all non-master interfaces. Do this because they - * may have bss pointer dependency on the master, and when we free - * the master these would be freed as well, breaking our list - * iteration completely. - */ - list_for_each_entry_safe(sdata, tmp, &local->interfaces, list) { - if (sdata->dev == local->mdev) - continue; - list_del(&sdata->list); - __ieee80211_if_del(local, sdata); - } + /* First, we remove all virtual interfaces. */ + ieee80211_remove_interfaces(local); /* then, finally, remove the master interface */ - __ieee80211_if_del(local, IEEE80211_DEV_TO_SUB_IF(local->mdev)); + unregister_netdevice(local->mdev); rtnl_unlock(); - ieee80211_rx_bss_list_deinit(local->mdev); + ieee80211_rx_bss_list_deinit(local); ieee80211_clear_tx_pending(local); sta_info_stop(local); rate_control_deinitialize(local); @@ -1840,8 +1811,7 @@ void ieee80211_unregister_hw(struct ieee80211_hw *hw) wiphy_unregister(local->hw.wiphy); ieee80211_wep_free(local); ieee80211_led_exit(local); - ieee80211_if_free(local->mdev); - local->mdev = NULL; + free_netdev(local->mdev); } EXPORT_SYMBOL(ieee80211_unregister_hw); @@ -1858,27 +1828,17 @@ static int __init ieee80211_init(void) struct sk_buff *skb; int ret; - BUILD_BUG_ON(sizeof(struct ieee80211_tx_packet_data) > sizeof(skb->cb)); + BUILD_BUG_ON(sizeof(struct ieee80211_tx_info) > sizeof(skb->cb)); + BUILD_BUG_ON(offsetof(struct ieee80211_tx_info, driver_data) + + IEEE80211_TX_INFO_DRIVER_DATA_SIZE > sizeof(skb->cb)); ret = rc80211_pid_init(); if (ret) - goto out; - - ret = ieee80211_wme_register(); - if (ret) { - printk(KERN_DEBUG "ieee80211_init: failed to " - "initialize WME (err=%d)\n", ret); - goto out_cleanup_pid; - } + return ret; ieee80211_debugfs_netdev_init(); return 0; - - out_cleanup_pid: - rc80211_pid_exit(); - out: - return ret; } static void __exit ieee80211_exit(void) @@ -1894,7 +1854,6 @@ static void __exit ieee80211_exit(void) if (mesh_allocated) ieee80211s_stop(); - ieee80211_wme_unregister(); ieee80211_debugfs_netdev_exit(); } diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c index 697ef67f96b6..b5933b271491 100644 --- a/net/mac80211/mesh.c +++ b/net/mac80211/mesh.c @@ -315,6 +315,13 @@ struct mesh_table *mesh_table_alloc(int size_order) return newtbl; } +static void __mesh_table_free(struct mesh_table *tbl) +{ + kfree(tbl->hash_buckets); + kfree(tbl->hashwlock); + kfree(tbl); +} + void mesh_table_free(struct mesh_table *tbl, bool free_leafs) { struct hlist_head *mesh_hash; @@ -330,9 +337,7 @@ void mesh_table_free(struct mesh_table *tbl, bool free_leafs) } spin_unlock(&tbl->hashwlock[i]); } - kfree(tbl->hash_buckets); - kfree(tbl->hashwlock); - kfree(tbl); + __mesh_table_free(tbl); } static void ieee80211_mesh_path_timer(unsigned long data) @@ -349,21 +354,16 @@ struct mesh_table *mesh_table_grow(struct mesh_table *tbl) { struct mesh_table *newtbl; struct hlist_head *oldhash; - struct hlist_node *p; - int err = 0; + struct hlist_node *p, *q; int i; if (atomic_read(&tbl->entries) - < tbl->mean_chain_len * (tbl->hash_mask + 1)) { - err = -EPERM; + < tbl->mean_chain_len * (tbl->hash_mask + 1)) goto endgrow; - } newtbl = mesh_table_alloc(tbl->size_order + 1); - if (!newtbl) { - err = -ENOMEM; + if (!newtbl) goto endgrow; - } newtbl->free_node = tbl->free_node; newtbl->mean_chain_len = tbl->mean_chain_len; @@ -373,13 +373,19 @@ struct mesh_table *mesh_table_grow(struct mesh_table *tbl) oldhash = tbl->hash_buckets; for (i = 0; i <= tbl->hash_mask; i++) hlist_for_each(p, &oldhash[i]) - tbl->copy_node(p, newtbl); + if (tbl->copy_node(p, newtbl) < 0) + goto errcopy; + return newtbl; + +errcopy: + for (i = 0; i <= newtbl->hash_mask; i++) { + hlist_for_each_safe(p, q, &newtbl->hash_buckets[i]) + tbl->free_node(p, 0); + } + __mesh_table_free(tbl); endgrow: - if (err) - return NULL; - else - return newtbl; + return NULL; } /** diff --git a/net/mac80211/mesh.h b/net/mac80211/mesh.h index 2e161f6d8288..669eafafe497 100644 --- a/net/mac80211/mesh.h +++ b/net/mac80211/mesh.h @@ -109,7 +109,7 @@ struct mesh_table { __u32 hash_rnd; /* Used for hash generation */ atomic_t entries; /* Up to MAX_MESH_NEIGHBOURS */ void (*free_node) (struct hlist_node *p, bool free_leafs); - void (*copy_node) (struct hlist_node *p, struct mesh_table *newtbl); + int (*copy_node) (struct hlist_node *p, struct mesh_table *newtbl); int size_order; int mean_chain_len; }; diff --git a/net/mac80211/mesh_hwmp.c b/net/mac80211/mesh_hwmp.c index af0cd1e3e213..7fa149e230e6 100644 --- a/net/mac80211/mesh_hwmp.c +++ b/net/mac80211/mesh_hwmp.c @@ -26,7 +26,7 @@ static inline u32 u32_field_get(u8 *preq_elem, int offset, bool ae) { if (ae) offset += 6; - return le32_to_cpu(get_unaligned((__le32 *) (preq_elem + offset))); + return get_unaligned_le32(preq_elem + offset); } /* HWMP IE processing macros */ diff --git a/net/mac80211/mesh_pathtbl.c b/net/mac80211/mesh_pathtbl.c index 99c2d360888e..5f88a2e6ee50 100644 --- a/net/mac80211/mesh_pathtbl.c +++ b/net/mac80211/mesh_pathtbl.c @@ -158,19 +158,14 @@ int mesh_path_add(u8 *dst, struct net_device *dev) if (atomic_add_unless(&sdata->u.sta.mpaths, 1, MESH_MAX_MPATHS) == 0) return -ENOSPC; + err = -ENOMEM; new_mpath = kzalloc(sizeof(struct mesh_path), GFP_KERNEL); - if (!new_mpath) { - atomic_dec(&sdata->u.sta.mpaths); - err = -ENOMEM; - goto endadd2; - } + if (!new_mpath) + goto err_path_alloc; + new_node = kmalloc(sizeof(struct mpath_node), GFP_KERNEL); - if (!new_node) { - kfree(new_mpath); - atomic_dec(&sdata->u.sta.mpaths); - err = -ENOMEM; - goto endadd2; - } + if (!new_node) + goto err_node_alloc; read_lock(&pathtbl_resize_lock); memcpy(new_mpath->dst, dst, ETH_ALEN); @@ -189,16 +184,11 @@ int mesh_path_add(u8 *dst, struct net_device *dev) spin_lock(&mesh_paths->hashwlock[hash_idx]); + err = -EEXIST; hlist_for_each_entry(node, n, bucket, list) { mpath = node->mpath; - if (mpath->dev == dev && memcmp(dst, mpath->dst, ETH_ALEN) - == 0) { - err = -EEXIST; - atomic_dec(&sdata->u.sta.mpaths); - kfree(new_node); - kfree(new_mpath); - goto endadd; - } + if (mpath->dev == dev && memcmp(dst, mpath->dst, ETH_ALEN) == 0) + goto err_exists; } hlist_add_head_rcu(&new_node->list, bucket); @@ -206,10 +196,9 @@ int mesh_path_add(u8 *dst, struct net_device *dev) mesh_paths->mean_chain_len * (mesh_paths->hash_mask + 1)) grow = 1; -endadd: spin_unlock(&mesh_paths->hashwlock[hash_idx]); read_unlock(&pathtbl_resize_lock); - if (!err && grow) { + if (grow) { struct mesh_table *oldtbl, *newtbl; write_lock(&pathtbl_resize_lock); @@ -217,7 +206,7 @@ endadd: newtbl = mesh_table_grow(mesh_paths); if (!newtbl) { write_unlock(&pathtbl_resize_lock); - return -ENOMEM; + return 0; } rcu_assign_pointer(mesh_paths, newtbl); write_unlock(&pathtbl_resize_lock); @@ -225,7 +214,16 @@ endadd: synchronize_rcu(); mesh_table_free(oldtbl, false); } -endadd2: + return 0; + +err_exists: + spin_unlock(&mesh_paths->hashwlock[hash_idx]); + read_unlock(&pathtbl_resize_lock); + kfree(new_node); +err_node_alloc: + kfree(new_mpath); +err_path_alloc: + atomic_dec(&sdata->u.sta.mpaths); return err; } @@ -264,7 +262,6 @@ void mesh_plink_broken(struct sta_info *sta) } rcu_read_unlock(); } -EXPORT_SYMBOL(mesh_plink_broken); /** * mesh_path_flush_by_nexthop - Deletes mesh paths if their next hop matches @@ -460,25 +457,28 @@ static void mesh_path_node_free(struct hlist_node *p, bool free_leafs) struct mpath_node *node = hlist_entry(p, struct mpath_node, list); mpath = node->mpath; hlist_del_rcu(p); - synchronize_rcu(); if (free_leafs) kfree(mpath); kfree(node); } -static void mesh_path_node_copy(struct hlist_node *p, struct mesh_table *newtbl) +static int mesh_path_node_copy(struct hlist_node *p, struct mesh_table *newtbl) { struct mesh_path *mpath; struct mpath_node *node, *new_node; u32 hash_idx; + new_node = kmalloc(sizeof(struct mpath_node), GFP_ATOMIC); + if (new_node == NULL) + return -ENOMEM; + node = hlist_entry(p, struct mpath_node, list); mpath = node->mpath; - new_node = kmalloc(sizeof(struct mpath_node), GFP_KERNEL); new_node->mpath = mpath; hash_idx = mesh_table_hash(mpath->dst, mpath->dev, newtbl); hlist_add_head(&new_node->list, &newtbl->hash_buckets[hash_idx]); + return 0; } int mesh_pathtbl_init(void) diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c index 37f0c2b94ae7..9efeb1f07025 100644 --- a/net/mac80211/mesh_plink.c +++ b/net/mac80211/mesh_plink.c @@ -79,7 +79,7 @@ void mesh_plink_dec_estab_count(struct ieee80211_sub_if_data *sdata) * * @sta: mes peer link to restart * - * Locking: this function must be called holding sta->plink_lock + * Locking: this function must be called holding sta->lock */ static inline void mesh_plink_fsm_restart(struct sta_info *sta) { @@ -105,7 +105,7 @@ static struct sta_info *mesh_plink_alloc(struct ieee80211_sub_if_data *sdata, if (!sta) return NULL; - sta->flags |= WLAN_STA_AUTHORIZED; + sta->flags = WLAN_STA_AUTHORIZED; sta->supp_rates[local->hw.conf.channel->band] = rates; return sta; @@ -118,7 +118,7 @@ static struct sta_info *mesh_plink_alloc(struct ieee80211_sub_if_data *sdata, * * All mesh paths with this peer as next hop will be flushed * - * Locking: the caller must hold sta->plink_lock + * Locking: the caller must hold sta->lock */ static void __mesh_plink_deactivate(struct sta_info *sta) { @@ -139,9 +139,9 @@ static void __mesh_plink_deactivate(struct sta_info *sta) */ void mesh_plink_deactivate(struct sta_info *sta) { - spin_lock_bh(&sta->plink_lock); + spin_lock_bh(&sta->lock); __mesh_plink_deactivate(sta); - spin_unlock_bh(&sta->plink_lock); + spin_unlock_bh(&sta->lock); } static int mesh_plink_frame_tx(struct net_device *dev, @@ -270,10 +270,10 @@ static void mesh_plink_timer(unsigned long data) */ sta = (struct sta_info *) data; - spin_lock_bh(&sta->plink_lock); + spin_lock_bh(&sta->lock); if (sta->ignore_plink_timer) { sta->ignore_plink_timer = false; - spin_unlock_bh(&sta->plink_lock); + spin_unlock_bh(&sta->lock); return; } mpl_dbg("Mesh plink timer for %s fired on state %d\n", @@ -298,7 +298,7 @@ static void mesh_plink_timer(unsigned long data) rand % sta->plink_timeout; ++sta->plink_retries; mod_plink_timer(sta, sta->plink_timeout); - spin_unlock_bh(&sta->plink_lock); + spin_unlock_bh(&sta->lock); mesh_plink_frame_tx(dev, PLINK_OPEN, sta->addr, llid, 0, 0); break; @@ -311,7 +311,7 @@ static void mesh_plink_timer(unsigned long data) reason = cpu_to_le16(MESH_CONFIRM_TIMEOUT); sta->plink_state = PLINK_HOLDING; mod_plink_timer(sta, dot11MeshHoldingTimeout(sdata)); - spin_unlock_bh(&sta->plink_lock); + spin_unlock_bh(&sta->lock); mesh_plink_frame_tx(dev, PLINK_CLOSE, sta->addr, llid, plid, reason); break; @@ -319,10 +319,10 @@ static void mesh_plink_timer(unsigned long data) /* holding timer */ del_timer(&sta->plink_timer); mesh_plink_fsm_restart(sta); - spin_unlock_bh(&sta->plink_lock); + spin_unlock_bh(&sta->lock); break; default: - spin_unlock_bh(&sta->plink_lock); + spin_unlock_bh(&sta->lock); break; } } @@ -344,16 +344,16 @@ int mesh_plink_open(struct sta_info *sta) DECLARE_MAC_BUF(mac); #endif - spin_lock_bh(&sta->plink_lock); + spin_lock_bh(&sta->lock); get_random_bytes(&llid, 2); sta->llid = llid; if (sta->plink_state != PLINK_LISTEN) { - spin_unlock_bh(&sta->plink_lock); + spin_unlock_bh(&sta->lock); return -EBUSY; } sta->plink_state = PLINK_OPN_SNT; mesh_plink_timer_set(sta, dot11MeshRetryTimeout(sdata)); - spin_unlock_bh(&sta->plink_lock); + spin_unlock_bh(&sta->lock); mpl_dbg("Mesh plink: starting establishment with %s\n", print_mac(mac, sta->addr)); @@ -367,10 +367,10 @@ void mesh_plink_block(struct sta_info *sta) DECLARE_MAC_BUF(mac); #endif - spin_lock_bh(&sta->plink_lock); + spin_lock_bh(&sta->lock); __mesh_plink_deactivate(sta); sta->plink_state = PLINK_BLOCKED; - spin_unlock_bh(&sta->plink_lock); + spin_unlock_bh(&sta->lock); } int mesh_plink_close(struct sta_info *sta) @@ -383,14 +383,14 @@ int mesh_plink_close(struct sta_info *sta) mpl_dbg("Mesh plink: closing link with %s\n", print_mac(mac, sta->addr)); - spin_lock_bh(&sta->plink_lock); + spin_lock_bh(&sta->lock); sta->reason = cpu_to_le16(MESH_LINK_CANCELLED); reason = sta->reason; if (sta->plink_state == PLINK_LISTEN || sta->plink_state == PLINK_BLOCKED) { mesh_plink_fsm_restart(sta); - spin_unlock_bh(&sta->plink_lock); + spin_unlock_bh(&sta->lock); return 0; } else if (sta->plink_state == PLINK_ESTAB) { __mesh_plink_deactivate(sta); @@ -402,7 +402,7 @@ int mesh_plink_close(struct sta_info *sta) sta->plink_state = PLINK_HOLDING; llid = sta->llid; plid = sta->plid; - spin_unlock_bh(&sta->plink_lock); + spin_unlock_bh(&sta->lock); mesh_plink_frame_tx(sta->sdata->dev, PLINK_CLOSE, sta->addr, llid, plid, reason); return 0; @@ -490,7 +490,7 @@ void mesh_rx_plink_frame(struct net_device *dev, struct ieee80211_mgmt *mgmt, /* avoid warning */ break; } - spin_lock_bh(&sta->plink_lock); + spin_lock_bh(&sta->lock); } else if (!sta) { /* ftype == PLINK_OPEN */ u64 rates; @@ -512,9 +512,9 @@ void mesh_rx_plink_frame(struct net_device *dev, struct ieee80211_mgmt *mgmt, return; } event = OPN_ACPT; - spin_lock_bh(&sta->plink_lock); + spin_lock_bh(&sta->lock); } else { - spin_lock_bh(&sta->plink_lock); + spin_lock_bh(&sta->lock); switch (ftype) { case PLINK_OPEN: if (!mesh_plink_free_count(sdata) || @@ -551,7 +551,7 @@ void mesh_rx_plink_frame(struct net_device *dev, struct ieee80211_mgmt *mgmt, break; default: mpl_dbg("Mesh plink: unknown frame subtype\n"); - spin_unlock_bh(&sta->plink_lock); + spin_unlock_bh(&sta->lock); rcu_read_unlock(); return; } @@ -568,7 +568,7 @@ void mesh_rx_plink_frame(struct net_device *dev, struct ieee80211_mgmt *mgmt, switch (event) { case CLS_ACPT: mesh_plink_fsm_restart(sta); - spin_unlock_bh(&sta->plink_lock); + spin_unlock_bh(&sta->lock); break; case OPN_ACPT: sta->plink_state = PLINK_OPN_RCVD; @@ -576,14 +576,14 @@ void mesh_rx_plink_frame(struct net_device *dev, struct ieee80211_mgmt *mgmt, get_random_bytes(&llid, 2); sta->llid = llid; mesh_plink_timer_set(sta, dot11MeshRetryTimeout(sdata)); - spin_unlock_bh(&sta->plink_lock); + spin_unlock_bh(&sta->lock); mesh_plink_frame_tx(dev, PLINK_OPEN, sta->addr, llid, 0, 0); mesh_plink_frame_tx(dev, PLINK_CONFIRM, sta->addr, llid, plid, 0); break; default: - spin_unlock_bh(&sta->plink_lock); + spin_unlock_bh(&sta->lock); break; } break; @@ -603,7 +603,7 @@ void mesh_rx_plink_frame(struct net_device *dev, struct ieee80211_mgmt *mgmt, sta->ignore_plink_timer = true; llid = sta->llid; - spin_unlock_bh(&sta->plink_lock); + spin_unlock_bh(&sta->lock); mesh_plink_frame_tx(dev, PLINK_CLOSE, sta->addr, llid, plid, reason); break; @@ -612,7 +612,7 @@ void mesh_rx_plink_frame(struct net_device *dev, struct ieee80211_mgmt *mgmt, sta->plink_state = PLINK_OPN_RCVD; sta->plid = plid; llid = sta->llid; - spin_unlock_bh(&sta->plink_lock); + spin_unlock_bh(&sta->lock); mesh_plink_frame_tx(dev, PLINK_CONFIRM, sta->addr, llid, plid, 0); break; @@ -622,10 +622,10 @@ void mesh_rx_plink_frame(struct net_device *dev, struct ieee80211_mgmt *mgmt, dot11MeshConfirmTimeout(sdata))) sta->ignore_plink_timer = true; - spin_unlock_bh(&sta->plink_lock); + spin_unlock_bh(&sta->lock); break; default: - spin_unlock_bh(&sta->plink_lock); + spin_unlock_bh(&sta->lock); break; } break; @@ -645,13 +645,13 @@ void mesh_rx_plink_frame(struct net_device *dev, struct ieee80211_mgmt *mgmt, sta->ignore_plink_timer = true; llid = sta->llid; - spin_unlock_bh(&sta->plink_lock); + spin_unlock_bh(&sta->lock); mesh_plink_frame_tx(dev, PLINK_CLOSE, sta->addr, llid, plid, reason); break; case OPN_ACPT: llid = sta->llid; - spin_unlock_bh(&sta->plink_lock); + spin_unlock_bh(&sta->lock); mesh_plink_frame_tx(dev, PLINK_CONFIRM, sta->addr, llid, plid, 0); break; @@ -659,12 +659,12 @@ void mesh_rx_plink_frame(struct net_device *dev, struct ieee80211_mgmt *mgmt, del_timer(&sta->plink_timer); sta->plink_state = PLINK_ESTAB; mesh_plink_inc_estab_count(sdata); - spin_unlock_bh(&sta->plink_lock); + spin_unlock_bh(&sta->lock); mpl_dbg("Mesh plink with %s ESTABLISHED\n", print_mac(mac, sta->addr)); break; default: - spin_unlock_bh(&sta->plink_lock); + spin_unlock_bh(&sta->lock); break; } break; @@ -684,7 +684,7 @@ void mesh_rx_plink_frame(struct net_device *dev, struct ieee80211_mgmt *mgmt, sta->ignore_plink_timer = true; llid = sta->llid; - spin_unlock_bh(&sta->plink_lock); + spin_unlock_bh(&sta->lock); mesh_plink_frame_tx(dev, PLINK_CLOSE, sta->addr, llid, plid, reason); break; @@ -692,14 +692,14 @@ void mesh_rx_plink_frame(struct net_device *dev, struct ieee80211_mgmt *mgmt, del_timer(&sta->plink_timer); sta->plink_state = PLINK_ESTAB; mesh_plink_inc_estab_count(sdata); - spin_unlock_bh(&sta->plink_lock); + spin_unlock_bh(&sta->lock); mpl_dbg("Mesh plink with %s ESTABLISHED\n", print_mac(mac, sta->addr)); mesh_plink_frame_tx(dev, PLINK_CONFIRM, sta->addr, llid, plid, 0); break; default: - spin_unlock_bh(&sta->plink_lock); + spin_unlock_bh(&sta->lock); break; } break; @@ -713,18 +713,18 @@ void mesh_rx_plink_frame(struct net_device *dev, struct ieee80211_mgmt *mgmt, sta->plink_state = PLINK_HOLDING; llid = sta->llid; mod_plink_timer(sta, dot11MeshHoldingTimeout(sdata)); - spin_unlock_bh(&sta->plink_lock); + spin_unlock_bh(&sta->lock); mesh_plink_frame_tx(dev, PLINK_CLOSE, sta->addr, llid, plid, reason); break; case OPN_ACPT: llid = sta->llid; - spin_unlock_bh(&sta->plink_lock); + spin_unlock_bh(&sta->lock); mesh_plink_frame_tx(dev, PLINK_CONFIRM, sta->addr, llid, plid, 0); break; default: - spin_unlock_bh(&sta->plink_lock); + spin_unlock_bh(&sta->lock); break; } break; @@ -734,7 +734,7 @@ void mesh_rx_plink_frame(struct net_device *dev, struct ieee80211_mgmt *mgmt, if (del_timer(&sta->plink_timer)) sta->ignore_plink_timer = 1; mesh_plink_fsm_restart(sta); - spin_unlock_bh(&sta->plink_lock); + spin_unlock_bh(&sta->lock); break; case OPN_ACPT: case CNF_ACPT: @@ -742,19 +742,19 @@ void mesh_rx_plink_frame(struct net_device *dev, struct ieee80211_mgmt *mgmt, case CNF_RJCT: llid = sta->llid; reason = sta->reason; - spin_unlock_bh(&sta->plink_lock); + spin_unlock_bh(&sta->lock); mesh_plink_frame_tx(dev, PLINK_CLOSE, sta->addr, llid, plid, reason); break; default: - spin_unlock_bh(&sta->plink_lock); + spin_unlock_bh(&sta->lock); } break; default: /* should not get here, PLINK_BLOCKED is dealt with at the * beggining of the function */ - spin_unlock_bh(&sta->plink_lock); + spin_unlock_bh(&sta->lock); break; } diff --git a/net/mac80211/michael.c b/net/mac80211/michael.c index 0f844f7895f1..408649bd4702 100644 --- a/net/mac80211/michael.c +++ b/net/mac80211/michael.c @@ -6,85 +6,68 @@ * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ - #include <linux/types.h> +#include <linux/bitops.h> +#include <linux/ieee80211.h> +#include <asm/unaligned.h> #include "michael.h" -static inline u32 rotr(u32 val, int bits) -{ - return (val >> bits) | (val << (32 - bits)); -} - - -static inline u32 rotl(u32 val, int bits) -{ - return (val << bits) | (val >> (32 - bits)); -} - - -static inline u32 xswap(u32 val) -{ - return ((val & 0xff00ff00) >> 8) | ((val & 0x00ff00ff) << 8); -} - - -#define michael_block(l, r) \ -do { \ - r ^= rotl(l, 17); \ - l += r; \ - r ^= xswap(l); \ - l += r; \ - r ^= rotl(l, 3); \ - l += r; \ - r ^= rotr(l, 2); \ - l += r; \ -} while (0) - - -static inline u32 michael_get32(u8 *data) +static void michael_block(struct michael_mic_ctx *mctx, u32 val) { - return data[0] | (data[1] << 8) | (data[2] << 16) | (data[3] << 24); + mctx->l ^= val; + mctx->r ^= rol32(mctx->l, 17); + mctx->l += mctx->r; + mctx->r ^= ((mctx->l & 0xff00ff00) >> 8) | + ((mctx->l & 0x00ff00ff) << 8); + mctx->l += mctx->r; + mctx->r ^= rol32(mctx->l, 3); + mctx->l += mctx->r; + mctx->r ^= ror32(mctx->l, 2); + mctx->l += mctx->r; } - -static inline void michael_put32(u32 val, u8 *data) +static void michael_mic_hdr(struct michael_mic_ctx *mctx, const u8 *key, + struct ieee80211_hdr *hdr) { - data[0] = val & 0xff; - data[1] = (val >> 8) & 0xff; - data[2] = (val >> 16) & 0xff; - data[3] = (val >> 24) & 0xff; + u8 *da, *sa, tid; + + da = ieee80211_get_DA(hdr); + sa = ieee80211_get_SA(hdr); + if (ieee80211_is_data_qos(hdr->frame_control)) + tid = *ieee80211_get_qos_ctl(hdr) & IEEE80211_QOS_CTL_TID_MASK; + else + tid = 0; + + mctx->l = get_unaligned_le32(key); + mctx->r = get_unaligned_le32(key + 4); + + /* + * A pseudo header (DA, SA, Priority, 0, 0, 0) is used in Michael MIC + * calculation, but it is _not_ transmitted + */ + michael_block(mctx, get_unaligned_le32(da)); + michael_block(mctx, get_unaligned_le16(&da[4]) | + (get_unaligned_le16(sa) << 16)); + michael_block(mctx, get_unaligned_le32(&sa[2])); + michael_block(mctx, tid); } - -void michael_mic(u8 *key, u8 *da, u8 *sa, u8 priority, - u8 *data, size_t data_len, u8 *mic) +void michael_mic(const u8 *key, struct ieee80211_hdr *hdr, + const u8 *data, size_t data_len, u8 *mic) { - u32 l, r, val; + u32 val; size_t block, blocks, left; + struct michael_mic_ctx mctx; - l = michael_get32(key); - r = michael_get32(key + 4); - - /* A pseudo header (DA, SA, Priority, 0, 0, 0) is used in Michael MIC - * calculation, but it is _not_ transmitted */ - l ^= michael_get32(da); - michael_block(l, r); - l ^= da[4] | (da[5] << 8) | (sa[0] << 16) | (sa[1] << 24); - michael_block(l, r); - l ^= michael_get32(&sa[2]); - michael_block(l, r); - l ^= priority; - michael_block(l, r); + michael_mic_hdr(&mctx, key, hdr); /* Real data */ blocks = data_len / 4; left = data_len % 4; - for (block = 0; block < blocks; block++) { - l ^= michael_get32(&data[block * 4]); - michael_block(l, r); - } + for (block = 0; block < blocks; block++) + michael_block(&mctx, get_unaligned_le32(&data[block * 4])); /* Partial block of 0..3 bytes and padding: 0x5a + 4..7 zeros to make * total length a multiple of 4. */ @@ -94,11 +77,10 @@ void michael_mic(u8 *key, u8 *da, u8 *sa, u8 priority, left--; val |= data[blocks * 4 + left]; } - l ^= val; - michael_block(l, r); - /* last block is zero, so l ^ 0 = l */ - michael_block(l, r); - michael_put32(l, mic); - michael_put32(r, mic + 4); + michael_block(&mctx, val); + michael_block(&mctx, 0); + + put_unaligned_le32(mctx.l, mic); + put_unaligned_le32(mctx.r, mic + 4); } diff --git a/net/mac80211/michael.h b/net/mac80211/michael.h index 2e6aebabeea1..3b848dad9587 100644 --- a/net/mac80211/michael.h +++ b/net/mac80211/michael.h @@ -14,7 +14,11 @@ #define MICHAEL_MIC_LEN 8 -void michael_mic(u8 *key, u8 *da, u8 *sa, u8 priority, - u8 *data, size_t data_len, u8 *mic); +struct michael_mic_ctx { + u32 l, r; +}; + +void michael_mic(const u8 *key, struct ieee80211_hdr *hdr, + const u8 *data, size_t data_len, u8 *mic); #endif /* MICHAEL_H */ diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index b404537c0bcd..d7c371e36bf0 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -78,7 +78,7 @@ static void ieee80211_send_probe_req(struct net_device *dev, u8 *dst, static struct ieee80211_sta_bss * ieee80211_rx_bss_get(struct net_device *dev, u8 *bssid, int freq, u8 *ssid, u8 ssid_len); -static void ieee80211_rx_bss_put(struct net_device *dev, +static void ieee80211_rx_bss_put(struct ieee80211_local *local, struct ieee80211_sta_bss *bss); static int ieee80211_sta_find_ibss(struct net_device *dev, struct ieee80211_if_sta *ifsta); @@ -87,6 +87,7 @@ static int ieee80211_sta_start_scan(struct net_device *dev, u8 *ssid, size_t ssid_len); static int ieee80211_sta_config_auth(struct net_device *dev, struct ieee80211_if_sta *ifsta); +static void sta_rx_agg_session_timer_expired(unsigned long data); void ieee802_11_parse_elems(u8 *start, size_t len, @@ -203,6 +204,25 @@ void ieee802_11_parse_elems(u8 *start, size_t len, elems->perr = pos; elems->perr_len = elen; break; + case WLAN_EID_CHANNEL_SWITCH: + elems->ch_switch_elem = pos; + elems->ch_switch_elem_len = elen; + break; + case WLAN_EID_QUIET: + if (!elems->quiet_elem) { + elems->quiet_elem = pos; + elems->quiet_elem_len = elen; + } + elems->num_of_quiet_elem++; + break; + case WLAN_EID_COUNTRY: + elems->country_elem = pos; + elems->country_elem_len = elen; + break; + case WLAN_EID_PWR_CONSTRAINT: + elems->pwr_constr_elem = pos; + elems->pwr_constr_elem_len = elen; + break; default: break; } @@ -256,19 +276,8 @@ static void ieee80211_sta_def_wmm_params(struct net_device *dev, qparam.cw_max = 1023; qparam.txop = 0; - for (i = IEEE80211_TX_QUEUE_DATA0; i < NUM_TX_DATA_QUEUES; i++) - local->ops->conf_tx(local_to_hw(local), - i + IEEE80211_TX_QUEUE_DATA0, - &qparam); - - if (ibss) { - /* IBSS uses different parameters for Beacon sending */ - qparam.cw_min++; - qparam.cw_min *= 2; - qparam.cw_min--; - local->ops->conf_tx(local_to_hw(local), - IEEE80211_TX_QUEUE_BEACON, &qparam); - } + for (i = 0; i < local_to_hw(local)->queues; i++) + local->ops->conf_tx(local_to_hw(local), i, &qparam); } } @@ -282,6 +291,12 @@ static void ieee80211_sta_wmm_params(struct net_device *dev, int count; u8 *pos; + if (!(ifsta->flags & IEEE80211_STA_WMM_ENABLED)) + return; + + if (!wmm_param) + return; + if (wmm_param_len < 8 || wmm_param[5] /* version */ != 1) return; count = wmm_param[6] & 0x0f; @@ -305,37 +320,33 @@ static void ieee80211_sta_wmm_params(struct net_device *dev, switch (aci) { case 1: - queue = IEEE80211_TX_QUEUE_DATA3; - if (acm) { + queue = 3; + if (acm) local->wmm_acm |= BIT(0) | BIT(3); - } break; case 2: - queue = IEEE80211_TX_QUEUE_DATA1; - if (acm) { + queue = 1; + if (acm) local->wmm_acm |= BIT(4) | BIT(5); - } break; case 3: - queue = IEEE80211_TX_QUEUE_DATA0; - if (acm) { + queue = 0; + if (acm) local->wmm_acm |= BIT(6) | BIT(7); - } break; case 0: default: - queue = IEEE80211_TX_QUEUE_DATA2; - if (acm) { + queue = 2; + if (acm) local->wmm_acm |= BIT(1) | BIT(2); - } break; } params.aifs = pos[0] & 0x0f; params.cw_max = ecw2cw((pos[1] & 0xf0) >> 4); params.cw_min = ecw2cw(pos[1] & 0x0f); - params.txop = pos[2] | (pos[3] << 8); -#ifdef CONFIG_MAC80211_DEBUG + params.txop = get_unaligned_le16(pos + 2); +#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", dev->name, queue, aci, acm, params.aifs, params.cw_min, @@ -355,11 +366,14 @@ static u32 ieee80211_handle_protect_preamb(struct ieee80211_sub_if_data *sdata, bool use_short_preamble) { struct ieee80211_bss_conf *bss_conf = &sdata->bss_conf; +#ifdef CONFIG_MAC80211_VERBOSE_DEBUG struct ieee80211_if_sta *ifsta = &sdata->u.sta; DECLARE_MAC_BUF(mac); +#endif u32 changed = 0; if (use_protection != bss_conf->use_cts_prot) { +#ifdef CONFIG_MAC80211_VERBOSE_DEBUG if (net_ratelimit()) { printk(KERN_DEBUG "%s: CTS protection %s (BSSID=" "%s)\n", @@ -367,11 +381,13 @@ static u32 ieee80211_handle_protect_preamb(struct ieee80211_sub_if_data *sdata, use_protection ? "enabled" : "disabled", print_mac(mac, ifsta->bssid)); } +#endif bss_conf->use_cts_prot = use_protection; changed |= BSS_CHANGED_ERP_CTS_PROT; } if (use_short_preamble != bss_conf->use_short_preamble) { +#ifdef CONFIG_MAC80211_VERBOSE_DEBUG if (net_ratelimit()) { printk(KERN_DEBUG "%s: switched to %s barker preamble" " (BSSID=%s)\n", @@ -379,6 +395,7 @@ static u32 ieee80211_handle_protect_preamb(struct ieee80211_sub_if_data *sdata, use_short_preamble ? "short" : "long", print_mac(mac, ifsta->bssid)); } +#endif bss_conf->use_short_preamble = use_short_preamble; changed |= BSS_CHANGED_ERP_PREAMBLE; } @@ -537,7 +554,7 @@ static void ieee80211_set_associated(struct net_device *dev, changed |= ieee80211_handle_bss_capability(sdata, bss); - ieee80211_rx_bss_put(dev, bss); + ieee80211_rx_bss_put(local, bss); } if (conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE) { @@ -555,7 +572,7 @@ static void ieee80211_set_associated(struct net_device *dev, netif_carrier_off(dev); ieee80211_sta_tear_down_BA_sessions(dev, ifsta->bssid); ifsta->flags &= ~IEEE80211_STA_ASSOCIATED; - ieee80211_reset_erp_info(dev); + changed |= ieee80211_reset_erp_info(dev); sdata->bss_conf.assoc_ht = 0; sdata->bss_conf.ht_conf = NULL; @@ -589,7 +606,7 @@ void ieee80211_sta_tx(struct net_device *dev, struct sk_buff *skb, int encrypt) { struct ieee80211_sub_if_data *sdata; - struct ieee80211_tx_packet_data *pkt_data; + struct ieee80211_tx_info *info; sdata = IEEE80211_DEV_TO_SUB_IF(dev); skb->dev = sdata->local->mdev; @@ -597,11 +614,11 @@ void ieee80211_sta_tx(struct net_device *dev, struct sk_buff *skb, skb_set_network_header(skb, 0); skb_set_transport_header(skb, 0); - pkt_data = (struct ieee80211_tx_packet_data *) skb->cb; - memset(pkt_data, 0, sizeof(struct ieee80211_tx_packet_data)); - pkt_data->ifindex = sdata->dev->ifindex; + info = IEEE80211_SKB_CB(skb); + memset(info, 0, sizeof(struct ieee80211_tx_info)); + info->control.ifindex = sdata->dev->ifindex; if (!encrypt) - pkt_data->flags |= IEEE80211_TXPD_DO_NOT_ENCRYPT; + info->flags |= IEEE80211_TX_CTL_DO_NOT_ENCRYPT; dev_queue_xmit(skb); } @@ -730,9 +747,8 @@ static void ieee80211_send_assoc(struct net_device *dev, if (bss) { if (bss->capability & WLAN_CAPABILITY_PRIVACY) capab |= WLAN_CAPABILITY_PRIVACY; - if (bss->wmm_ie) { + if (bss->wmm_ie) wmm = 1; - } /* get all rates supported by the device and the AP as * some APs don't like getting a superset of their rates @@ -740,7 +756,11 @@ static void ieee80211_send_assoc(struct net_device *dev, * b-only mode) */ rates_len = ieee80211_compatible_rates(bss, sband, &rates); - ieee80211_rx_bss_put(dev, bss); + if ((bss->capability & WLAN_CAPABILITY_SPECTRUM_MGMT) && + (local->hw.flags & IEEE80211_HW_SPECTRUM_MGMT)) + capab |= WLAN_CAPABILITY_SPECTRUM_MGMT; + + ieee80211_rx_bss_put(local, bss); } else { rates = ~0; rates_len = sband->n_bitrates; @@ -807,6 +827,26 @@ static void ieee80211_send_assoc(struct net_device *dev, } } + if (capab & WLAN_CAPABILITY_SPECTRUM_MGMT) { + /* 1. power capabilities */ + pos = skb_put(skb, 4); + *pos++ = WLAN_EID_PWR_CAPABILITY; + *pos++ = 2; + *pos++ = 0; /* min tx power */ + *pos++ = local->hw.conf.channel->max_power; /* max tx power */ + + /* 2. supported channels */ + /* TODO: get this in reg domain format */ + pos = skb_put(skb, 2 * sband->n_channels + 2); + *pos++ = WLAN_EID_SUPPORTED_CHANNELS; + *pos++ = 2 * sband->n_channels; + for (i = 0; i < sband->n_channels; i++) { + *pos++ = ieee80211_frequency_to_channel( + sband->channels[i].center_freq); + *pos++ = 1; /* one channel in the subband*/ + } + } + if (ifsta->extra_ie) { pos = skb_put(skb, ifsta->extra_ie_len); memcpy(pos, ifsta->extra_ie, ifsta->extra_ie_len); @@ -824,9 +864,32 @@ static void ieee80211_send_assoc(struct net_device *dev, *pos++ = 1; /* WME ver */ *pos++ = 0; } + /* wmm support is a must to HT */ - if (wmm && sband->ht_info.ht_supported) { - __le16 tmp = cpu_to_le16(sband->ht_info.cap); + if (wmm && (ifsta->flags & IEEE80211_STA_WMM_ENABLED) && + sband->ht_info.ht_supported && bss->ht_add_ie) { + struct ieee80211_ht_addt_info *ht_add_info = + (struct ieee80211_ht_addt_info *)bss->ht_add_ie; + u16 cap = sband->ht_info.cap; + __le16 tmp; + u32 flags = local->hw.conf.channel->flags; + + switch (ht_add_info->ht_param & IEEE80211_HT_IE_CHA_SEC_OFFSET) { + case IEEE80211_HT_IE_CHA_SEC_ABOVE: + if (flags & IEEE80211_CHAN_NO_FAT_ABOVE) { + cap &= ~IEEE80211_HT_CAP_SUP_WIDTH; + cap &= ~IEEE80211_HT_CAP_SGI_40; + } + break; + case IEEE80211_HT_IE_CHA_SEC_BELOW: + if (flags & IEEE80211_CHAN_NO_FAT_BELOW) { + cap &= ~IEEE80211_HT_CAP_SUP_WIDTH; + cap &= ~IEEE80211_HT_CAP_SGI_40; + } + break; + } + + tmp = cpu_to_le16(cap); pos = skb_put(skb, sizeof(struct ieee80211_ht_cap)+2); *pos++ = WLAN_EID_HT_CAPABILITY; *pos++ = sizeof(struct ieee80211_ht_cap); @@ -929,7 +992,7 @@ static int ieee80211_privacy_mismatch(struct net_device *dev, wep_privacy = !!ieee80211_sta_wep_configured(dev); privacy_invoked = !!(ifsta->flags & IEEE80211_STA_PRIVACY_INVOKED); - ieee80211_rx_bss_put(dev, bss); + ieee80211_rx_bss_put(local, bss); if ((bss_privacy == wep_privacy) || (bss_privacy == privacy_invoked)) return 0; @@ -1121,14 +1184,10 @@ static void ieee80211_auth_challenge(struct net_device *dev, u8 *pos; struct ieee802_11_elems elems; - printk(KERN_DEBUG "%s: replying to auth challenge\n", dev->name); pos = mgmt->u.auth.variable; ieee802_11_parse_elems(pos, len - (pos - (u8 *) mgmt), &elems); - if (!elems.challenge) { - printk(KERN_DEBUG "%s: no challenge IE in shared key auth " - "frame\n", dev->name); + if (!elems.challenge) return; - } ieee80211_send_auth(dev, ifsta, 3, elems.challenge - 2, elems.challenge_len + 2, 1); } @@ -1144,8 +1203,8 @@ static void ieee80211_send_addba_resp(struct net_device *dev, u8 *da, u16 tid, struct ieee80211_mgmt *mgmt; u16 capab; - skb = dev_alloc_skb(sizeof(*mgmt) + local->hw.extra_tx_headroom + 1 + - sizeof(mgmt->u.action.u.addba_resp)); + skb = dev_alloc_skb(sizeof(*mgmt) + local->hw.extra_tx_headroom); + if (!skb) { printk(KERN_DEBUG "%s: failed to allocate buffer " "for addba resp frame\n", dev->name); @@ -1193,9 +1252,7 @@ void ieee80211_send_addba_request(struct net_device *dev, const u8 *da, struct ieee80211_mgmt *mgmt; u16 capab; - skb = dev_alloc_skb(sizeof(*mgmt) + local->hw.extra_tx_headroom + 1 + - sizeof(mgmt->u.action.u.addba_req)); - + skb = dev_alloc_skb(sizeof(*mgmt) + local->hw.extra_tx_headroom); if (!skb) { printk(KERN_ERR "%s: failed to allocate buffer " @@ -1296,7 +1353,7 @@ static void ieee80211_sta_process_addba_request(struct net_device *dev, /* examine state machine */ - spin_lock_bh(&sta->ampdu_mlme.ampdu_rx); + spin_lock_bh(&sta->lock); if (sta->ampdu_mlme.tid_state_rx[tid] != HT_AGG_STATE_IDLE) { #ifdef CONFIG_MAC80211_HT_DEBUG @@ -1312,9 +1369,11 @@ static void ieee80211_sta_process_addba_request(struct net_device *dev, sta->ampdu_mlme.tid_rx[tid] = kmalloc(sizeof(struct tid_ampdu_rx), GFP_ATOMIC); if (!sta->ampdu_mlme.tid_rx[tid]) { +#ifdef CONFIG_MAC80211_HT_DEBUG if (net_ratelimit()) printk(KERN_ERR "allocate rx mlme to tid %d failed\n", tid); +#endif goto end; } /* rx timer */ @@ -1330,9 +1389,11 @@ static void ieee80211_sta_process_addba_request(struct net_device *dev, tid_agg_rx->reorder_buf = kmalloc(buf_size * sizeof(struct sk_buff *), GFP_ATOMIC); if (!tid_agg_rx->reorder_buf) { +#ifdef CONFIG_MAC80211_HT_DEBUG if (net_ratelimit()) printk(KERN_ERR "can not allocate reordering buffer " "to tid %d\n", tid); +#endif kfree(sta->ampdu_mlme.tid_rx[tid]); goto end; } @@ -1363,7 +1424,7 @@ static void ieee80211_sta_process_addba_request(struct net_device *dev, tid_agg_rx->stored_mpdu_num = 0; status = WLAN_STATUS_SUCCESS; end: - spin_unlock_bh(&sta->ampdu_mlme.ampdu_rx); + spin_unlock_bh(&sta->lock); end_no_lock: ieee80211_send_addba_resp(sta->sdata->dev, sta->addr, tid, @@ -1395,18 +1456,16 @@ static void ieee80211_sta_process_addba_resp(struct net_device *dev, state = &sta->ampdu_mlme.tid_state_tx[tid]; - spin_lock_bh(&sta->ampdu_mlme.ampdu_tx); + spin_lock_bh(&sta->lock); if (!(*state & HT_ADDBA_REQUESTED_MSK)) { - spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx); - printk(KERN_DEBUG "state not HT_ADDBA_REQUESTED_MSK:" - "%d\n", *state); + spin_unlock_bh(&sta->lock); goto addba_resp_exit; } if (mgmt->u.action.u.addba_resp.dialog_token != sta->ampdu_mlme.tid_tx[tid]->dialog_token) { - spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx); + spin_unlock_bh(&sta->lock); #ifdef CONFIG_MAC80211_HT_DEBUG printk(KERN_DEBUG "wrong addBA response token, tid %d\n", tid); #endif /* CONFIG_MAC80211_HT_DEBUG */ @@ -1419,26 +1478,18 @@ static void ieee80211_sta_process_addba_resp(struct net_device *dev, #endif /* CONFIG_MAC80211_HT_DEBUG */ if (le16_to_cpu(mgmt->u.action.u.addba_resp.status) == WLAN_STATUS_SUCCESS) { - if (*state & HT_ADDBA_RECEIVED_MSK) - printk(KERN_DEBUG "double addBA response\n"); - *state |= HT_ADDBA_RECEIVED_MSK; sta->ampdu_mlme.addba_req_num[tid] = 0; - if (*state == HT_AGG_STATE_OPERATIONAL) { - printk(KERN_DEBUG "Aggregation on for tid %d \n", tid); + if (*state == HT_AGG_STATE_OPERATIONAL) ieee80211_wake_queue(hw, sta->tid_to_tx_q[tid]); - } - spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx); - printk(KERN_DEBUG "recipient accepted agg: tid %d \n", tid); + spin_unlock_bh(&sta->lock); } else { - printk(KERN_DEBUG "recipient rejected agg: tid %d \n", tid); - sta->ampdu_mlme.addba_req_num[tid]++; /* this will allow the state check in stop_BA_session */ *state = HT_AGG_STATE_OPERATIONAL; - spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx); + spin_unlock_bh(&sta->lock); ieee80211_stop_tx_ba_session(hw, sta->addr, tid, WLAN_BACK_INITIATOR); } @@ -1457,8 +1508,7 @@ void ieee80211_send_delba(struct net_device *dev, const u8 *da, u16 tid, struct ieee80211_mgmt *mgmt; u16 params; - skb = dev_alloc_skb(sizeof(*mgmt) + local->hw.extra_tx_headroom + 1 + - sizeof(mgmt->u.action.u.delba)); + skb = dev_alloc_skb(sizeof(*mgmt) + local->hw.extra_tx_headroom); if (!skb) { printk(KERN_ERR "%s: failed to allocate buffer " @@ -1491,6 +1541,35 @@ void ieee80211_send_delba(struct net_device *dev, const u8 *da, u16 tid, ieee80211_sta_tx(dev, skb, 0); } +void ieee80211_send_bar(struct net_device *dev, u8 *ra, u16 tid, u16 ssn) +{ + struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); + struct sk_buff *skb; + struct ieee80211_bar *bar; + u16 bar_control = 0; + + skb = dev_alloc_skb(sizeof(*bar) + local->hw.extra_tx_headroom); + if (!skb) { + printk(KERN_ERR "%s: failed to allocate buffer for " + "bar frame\n", dev->name); + return; + } + skb_reserve(skb, local->hw.extra_tx_headroom); + bar = (struct ieee80211_bar *)skb_put(skb, sizeof(*bar)); + memset(bar, 0, sizeof(*bar)); + bar->frame_control = IEEE80211_FC(IEEE80211_FTYPE_CTL, + IEEE80211_STYPE_BACK_REQ); + memcpy(bar->ra, ra, ETH_ALEN); + memcpy(bar->ta, dev->dev_addr, ETH_ALEN); + bar_control |= (u16)IEEE80211_BAR_CTRL_ACK_POLICY_NORMAL; + bar_control |= (u16)IEEE80211_BAR_CTRL_CBMTID_COMPRESSED_BA; + bar_control |= (u16)(tid << 12); + bar->control = cpu_to_le16(bar_control); + bar->start_seq_num = cpu_to_le16(ssn); + + ieee80211_sta_tx(dev, skb, 0); +} + void ieee80211_sta_stop_rx_ba_session(struct net_device *dev, u8 *ra, u16 tid, u16 initiator, u16 reason) { @@ -1509,17 +1588,17 @@ void ieee80211_sta_stop_rx_ba_session(struct net_device *dev, u8 *ra, u16 tid, } /* check if TID is in operational state */ - spin_lock_bh(&sta->ampdu_mlme.ampdu_rx); + spin_lock_bh(&sta->lock); if (sta->ampdu_mlme.tid_state_rx[tid] != HT_AGG_STATE_OPERATIONAL) { - spin_unlock_bh(&sta->ampdu_mlme.ampdu_rx); + spin_unlock_bh(&sta->lock); rcu_read_unlock(); return; } sta->ampdu_mlme.tid_state_rx[tid] = HT_AGG_STATE_REQ_STOP_BA_MSK | (initiator << HT_AGG_STATE_INITIATOR_SHIFT); - spin_unlock_bh(&sta->ampdu_mlme.ampdu_rx); + spin_unlock_bh(&sta->lock); /* stop HW Rx aggregation. ampdu_action existence * already verified in session init so we add the BUG_ON */ @@ -1534,7 +1613,7 @@ void ieee80211_sta_stop_rx_ba_session(struct net_device *dev, u8 *ra, u16 tid, ra, tid, NULL); if (ret) printk(KERN_DEBUG "HW problem - can not stop rx " - "aggergation for tid %d\n", tid); + "aggregation for tid %d\n", tid); /* shutdown timer has not expired */ if (initiator != WLAN_BACK_TIMER) @@ -1596,10 +1675,10 @@ static void ieee80211_sta_process_delba(struct net_device *dev, ieee80211_sta_stop_rx_ba_session(dev, sta->addr, tid, WLAN_BACK_INITIATOR, 0); else { /* WLAN_BACK_RECIPIENT */ - spin_lock_bh(&sta->ampdu_mlme.ampdu_tx); + spin_lock_bh(&sta->lock); sta->ampdu_mlme.tid_state_tx[tid] = HT_AGG_STATE_OPERATIONAL; - spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx); + spin_unlock_bh(&sta->lock); ieee80211_stop_tx_ba_session(&local->hw, sta->addr, tid, WLAN_BACK_RECIPIENT); } @@ -1636,20 +1715,24 @@ void sta_addba_resp_timer_expired(unsigned long data) state = &sta->ampdu_mlme.tid_state_tx[tid]; /* check if the TID waits for addBA response */ - spin_lock_bh(&sta->ampdu_mlme.ampdu_tx); + spin_lock_bh(&sta->lock); if (!(*state & HT_ADDBA_REQUESTED_MSK)) { - spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx); + spin_unlock_bh(&sta->lock); *state = HT_AGG_STATE_IDLE; +#ifdef CONFIG_MAC80211_HT_DEBUG printk(KERN_DEBUG "timer expired on tid %d but we are not " "expecting addBA response there", tid); +#endif goto timer_expired_exit; } +#ifdef CONFIG_MAC80211_HT_DEBUG printk(KERN_DEBUG "addBA response timer expired on tid %d\n", tid); +#endif /* go through the state check in stop_BA_session */ *state = HT_AGG_STATE_OPERATIONAL; - spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx); + spin_unlock_bh(&sta->lock); ieee80211_stop_tx_ba_session(hw, temp_sta->addr, tid, WLAN_BACK_INITIATOR); @@ -1662,7 +1745,7 @@ timer_expired_exit: * resetting it after each frame that arrives from the originator. * if this timer expires ieee80211_sta_stop_rx_ba_session will be executed. */ -void sta_rx_agg_session_timer_expired(unsigned long data) +static void sta_rx_agg_session_timer_expired(unsigned long data) { /* not an elegant detour, but there is no choice as the timer passes * only one argument, and various sta_info are needed here, so init @@ -1673,7 +1756,9 @@ void sta_rx_agg_session_timer_expired(unsigned long data) struct sta_info *sta = container_of(timer_to_id, struct sta_info, timer_to_tid[0]); +#ifdef CONFIG_MAC80211_HT_DEBUG printk(KERN_DEBUG "rx session timer expired on tid %d\n", (u16)*ptid); +#endif ieee80211_sta_stop_rx_ba_session(sta->sdata->dev, sta->addr, (u16)*ptid, WLAN_BACK_TIMER, WLAN_REASON_QSTA_TIMEOUT); @@ -1693,6 +1778,71 @@ void ieee80211_sta_tear_down_BA_sessions(struct net_device *dev, u8 *addr) } } +static void ieee80211_send_refuse_measurement_request(struct net_device *dev, + struct ieee80211_msrment_ie *request_ie, + const u8 *da, const u8 *bssid, + u8 dialog_token) +{ + struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); + struct sk_buff *skb; + struct ieee80211_mgmt *msr_report; + + skb = dev_alloc_skb(sizeof(*msr_report) + local->hw.extra_tx_headroom + + sizeof(struct ieee80211_msrment_ie)); + + if (!skb) { + printk(KERN_ERR "%s: failed to allocate buffer for " + "measurement report frame\n", dev->name); + return; + } + + skb_reserve(skb, local->hw.extra_tx_headroom); + msr_report = (struct ieee80211_mgmt *)skb_put(skb, 24); + memset(msr_report, 0, 24); + memcpy(msr_report->da, da, ETH_ALEN); + memcpy(msr_report->sa, dev->dev_addr, ETH_ALEN); + memcpy(msr_report->bssid, bssid, ETH_ALEN); + msr_report->frame_control = IEEE80211_FC(IEEE80211_FTYPE_MGMT, + IEEE80211_STYPE_ACTION); + + skb_put(skb, 1 + sizeof(msr_report->u.action.u.measurement)); + msr_report->u.action.category = WLAN_CATEGORY_SPECTRUM_MGMT; + msr_report->u.action.u.measurement.action_code = + WLAN_ACTION_SPCT_MSR_RPRT; + msr_report->u.action.u.measurement.dialog_token = dialog_token; + + msr_report->u.action.u.measurement.element_id = WLAN_EID_MEASURE_REPORT; + msr_report->u.action.u.measurement.length = + sizeof(struct ieee80211_msrment_ie); + + memset(&msr_report->u.action.u.measurement.msr_elem, 0, + sizeof(struct ieee80211_msrment_ie)); + msr_report->u.action.u.measurement.msr_elem.token = request_ie->token; + msr_report->u.action.u.measurement.msr_elem.mode |= + IEEE80211_SPCT_MSR_RPRT_MODE_REFUSED; + msr_report->u.action.u.measurement.msr_elem.type = request_ie->type; + + ieee80211_sta_tx(dev, skb, 0); +} + +static void ieee80211_sta_process_measurement_req(struct net_device *dev, + struct ieee80211_mgmt *mgmt, + size_t len) +{ + /* + * Ignoring measurement request is spec violation. + * Mandatory measurements must be reported optional + * measurements might be refused or reported incapable + * For now just refuse + * TODO: Answer basic measurement as unmeasured + */ + ieee80211_send_refuse_measurement_request(dev, + &mgmt->u.action.u.measurement.msr_elem, + mgmt->sa, mgmt->bssid, + mgmt->u.action.u.measurement.dialog_token); +} + + static void ieee80211_rx_mgmt_auth(struct net_device *dev, struct ieee80211_if_sta *ifsta, struct ieee80211_mgmt *mgmt, @@ -1703,73 +1853,41 @@ static void ieee80211_rx_mgmt_auth(struct net_device *dev, DECLARE_MAC_BUF(mac); if (ifsta->state != IEEE80211_AUTHENTICATE && - sdata->vif.type != IEEE80211_IF_TYPE_IBSS) { - printk(KERN_DEBUG "%s: authentication frame received from " - "%s, but not in authenticate state - ignored\n", - dev->name, print_mac(mac, mgmt->sa)); + sdata->vif.type != IEEE80211_IF_TYPE_IBSS) return; - } - if (len < 24 + 6) { - printk(KERN_DEBUG "%s: too short (%zd) authentication frame " - "received from %s - ignored\n", - dev->name, len, print_mac(mac, mgmt->sa)); + if (len < 24 + 6) return; - } if (sdata->vif.type != IEEE80211_IF_TYPE_IBSS && - memcmp(ifsta->bssid, mgmt->sa, ETH_ALEN) != 0) { - printk(KERN_DEBUG "%s: authentication frame received from " - "unknown AP (SA=%s BSSID=%s) - " - "ignored\n", dev->name, print_mac(mac, mgmt->sa), - print_mac(mac, mgmt->bssid)); + memcmp(ifsta->bssid, mgmt->sa, ETH_ALEN) != 0) return; - } if (sdata->vif.type != IEEE80211_IF_TYPE_IBSS && - memcmp(ifsta->bssid, mgmt->bssid, ETH_ALEN) != 0) { - printk(KERN_DEBUG "%s: authentication frame received from " - "unknown BSSID (SA=%s BSSID=%s) - " - "ignored\n", dev->name, print_mac(mac, mgmt->sa), - print_mac(mac, mgmt->bssid)); + memcmp(ifsta->bssid, mgmt->bssid, ETH_ALEN) != 0) return; - } auth_alg = le16_to_cpu(mgmt->u.auth.auth_alg); auth_transaction = le16_to_cpu(mgmt->u.auth.auth_transaction); status_code = le16_to_cpu(mgmt->u.auth.status_code); - printk(KERN_DEBUG "%s: RX authentication from %s (alg=%d " - "transaction=%d status=%d)\n", - dev->name, print_mac(mac, mgmt->sa), auth_alg, - auth_transaction, status_code); - if (sdata->vif.type == IEEE80211_IF_TYPE_IBSS) { - /* IEEE 802.11 standard does not require authentication in IBSS + /* + * IEEE 802.11 standard does not require authentication in IBSS * networks and most implementations do not seem to use it. * However, try to reply to authentication attempts if someone * has actually implemented this. - * TODO: Could implement shared key authentication. */ - if (auth_alg != WLAN_AUTH_OPEN || auth_transaction != 1) { - printk(KERN_DEBUG "%s: unexpected IBSS authentication " - "frame (alg=%d transaction=%d)\n", - dev->name, auth_alg, auth_transaction); + */ + if (auth_alg != WLAN_AUTH_OPEN || auth_transaction != 1) return; - } ieee80211_send_auth(dev, ifsta, 2, NULL, 0, 0); } if (auth_alg != ifsta->auth_alg || - auth_transaction != ifsta->auth_transaction) { - printk(KERN_DEBUG "%s: unexpected authentication frame " - "(alg=%d transaction=%d)\n", - dev->name, auth_alg, auth_transaction); + auth_transaction != ifsta->auth_transaction) return; - } if (status_code != WLAN_STATUS_SUCCESS) { - printk(KERN_DEBUG "%s: AP denied authentication (auth_alg=%d " - "code=%d)\n", dev->name, ifsta->auth_alg, status_code); if (status_code == WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG) { u8 algs[3]; const int num_algs = ARRAY_SIZE(algs); @@ -1798,9 +1916,6 @@ static void ieee80211_rx_mgmt_auth(struct net_device *dev, !ieee80211_sta_wep_configured(dev)) continue; ifsta->auth_alg = algs[pos]; - printk(KERN_DEBUG "%s: set auth_alg=%d for " - "next try\n", - dev->name, ifsta->auth_alg); break; } } @@ -1830,30 +1945,16 @@ static void ieee80211_rx_mgmt_deauth(struct net_device *dev, u16 reason_code; DECLARE_MAC_BUF(mac); - if (len < 24 + 2) { - printk(KERN_DEBUG "%s: too short (%zd) deauthentication frame " - "received from %s - ignored\n", - dev->name, len, print_mac(mac, mgmt->sa)); + if (len < 24 + 2) return; - } - if (memcmp(ifsta->bssid, mgmt->sa, ETH_ALEN) != 0) { - printk(KERN_DEBUG "%s: deauthentication frame received from " - "unknown AP (SA=%s BSSID=%s) - " - "ignored\n", dev->name, print_mac(mac, mgmt->sa), - print_mac(mac, mgmt->bssid)); + if (memcmp(ifsta->bssid, mgmt->sa, ETH_ALEN)) return; - } reason_code = le16_to_cpu(mgmt->u.deauth.reason_code); - printk(KERN_DEBUG "%s: RX deauthentication from %s" - " (reason=%d)\n", - dev->name, print_mac(mac, mgmt->sa), reason_code); - - if (ifsta->flags & IEEE80211_STA_AUTHENTICATED) { + if (ifsta->flags & IEEE80211_STA_AUTHENTICATED) printk(KERN_DEBUG "%s: deauthenticated\n", dev->name); - } if (ifsta->state == IEEE80211_AUTHENTICATE || ifsta->state == IEEE80211_ASSOCIATE || @@ -1876,27 +1977,14 @@ static void ieee80211_rx_mgmt_disassoc(struct net_device *dev, u16 reason_code; DECLARE_MAC_BUF(mac); - if (len < 24 + 2) { - printk(KERN_DEBUG "%s: too short (%zd) disassociation frame " - "received from %s - ignored\n", - dev->name, len, print_mac(mac, mgmt->sa)); + if (len < 24 + 2) return; - } - if (memcmp(ifsta->bssid, mgmt->sa, ETH_ALEN) != 0) { - printk(KERN_DEBUG "%s: disassociation frame received from " - "unknown AP (SA=%s BSSID=%s) - " - "ignored\n", dev->name, print_mac(mac, mgmt->sa), - print_mac(mac, mgmt->bssid)); + if (memcmp(ifsta->bssid, mgmt->sa, ETH_ALEN)) return; - } reason_code = le16_to_cpu(mgmt->u.disassoc.reason_code); - printk(KERN_DEBUG "%s: RX disassociation from %s" - " (reason=%d)\n", - dev->name, print_mac(mac, mgmt->sa), reason_code); - if (ifsta->flags & IEEE80211_STA_ASSOCIATED) printk(KERN_DEBUG "%s: disassociated\n", dev->name); @@ -1932,27 +2020,14 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, /* AssocResp and ReassocResp have identical structure, so process both * of them in this function. */ - if (ifsta->state != IEEE80211_ASSOCIATE) { - printk(KERN_DEBUG "%s: association frame received from " - "%s, but not in associate state - ignored\n", - dev->name, print_mac(mac, mgmt->sa)); + if (ifsta->state != IEEE80211_ASSOCIATE) return; - } - if (len < 24 + 6) { - printk(KERN_DEBUG "%s: too short (%zd) association frame " - "received from %s - ignored\n", - dev->name, len, print_mac(mac, mgmt->sa)); + if (len < 24 + 6) return; - } - if (memcmp(ifsta->bssid, mgmt->sa, ETH_ALEN) != 0) { - printk(KERN_DEBUG "%s: association frame received from " - "unknown AP (SA=%s BSSID=%s) - " - "ignored\n", dev->name, print_mac(mac, mgmt->sa), - print_mac(mac, mgmt->bssid)); + if (memcmp(ifsta->bssid, mgmt->sa, ETH_ALEN) != 0) return; - } capab_info = le16_to_cpu(mgmt->u.assoc_resp.capab_info); status_code = le16_to_cpu(mgmt->u.assoc_resp.status_code); @@ -2016,10 +2091,10 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, local->hw.conf.channel->center_freq, ifsta->ssid, ifsta->ssid_len); if (bss) { - sta->last_rssi = bss->rssi; sta->last_signal = bss->signal; + sta->last_qual = bss->qual; sta->last_noise = bss->noise; - ieee80211_rx_bss_put(dev, bss); + ieee80211_rx_bss_put(local, bss); } err = sta_info_insert(sta); @@ -2041,8 +2116,8 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, * to between the sta_info_alloc() and sta_info_insert() above. */ - sta->flags |= 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 | + WLAN_STA_AUTHORIZED); rates = 0; basic_rates = 0; @@ -2086,7 +2161,8 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, else sdata->flags &= ~IEEE80211_SDATA_OPERATING_GMODE; - if (elems.ht_cap_elem && elems.ht_info_elem && elems.wmm_param) { + if (elems.ht_cap_elem && elems.ht_info_elem && elems.wmm_param && + (ifsta->flags & IEEE80211_STA_WMM_ENABLED)) { struct ieee80211_ht_bss_info bss_info; ieee80211_ht_cap_ie_to_ht_info( (struct ieee80211_ht_cap *) @@ -2099,8 +2175,8 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, rate_control_rate_init(sta, local); - if (elems.wmm_param && (ifsta->flags & IEEE80211_STA_WMM_ENABLED)) { - sta->flags |= WLAN_STA_WME; + if (elems.wmm_param) { + set_sta_flags(sta, WLAN_STA_WME); rcu_read_unlock(); ieee80211_sta_wmm_params(dev, ifsta, elems.wmm_param, elems.wmm_param_len); @@ -2136,10 +2212,9 @@ static void __ieee80211_rx_bss_hash_add(struct net_device *dev, /* Caller must hold local->sta_bss_lock */ -static void __ieee80211_rx_bss_hash_del(struct net_device *dev, +static void __ieee80211_rx_bss_hash_del(struct ieee80211_local *local, struct ieee80211_sta_bss *bss) { - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); struct ieee80211_sta_bss *b, *prev = NULL; b = local->sta_bss_hash[STA_HASH(bss->bssid)]; while (b) { @@ -2284,45 +2359,42 @@ static void ieee80211_rx_bss_free(struct ieee80211_sta_bss *bss) kfree(bss->rsn_ie); kfree(bss->wmm_ie); kfree(bss->ht_ie); + kfree(bss->ht_add_ie); kfree(bss_mesh_id(bss)); kfree(bss_mesh_cfg(bss)); kfree(bss); } -static void ieee80211_rx_bss_put(struct net_device *dev, +static void ieee80211_rx_bss_put(struct ieee80211_local *local, struct ieee80211_sta_bss *bss) { - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - local_bh_disable(); if (!atomic_dec_and_lock(&bss->users, &local->sta_bss_lock)) { local_bh_enable(); return; } - __ieee80211_rx_bss_hash_del(dev, bss); + __ieee80211_rx_bss_hash_del(local, bss); list_del(&bss->list); spin_unlock_bh(&local->sta_bss_lock); ieee80211_rx_bss_free(bss); } -void ieee80211_rx_bss_list_init(struct net_device *dev) +void ieee80211_rx_bss_list_init(struct ieee80211_local *local) { - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); spin_lock_init(&local->sta_bss_lock); INIT_LIST_HEAD(&local->sta_bss_list); } -void ieee80211_rx_bss_list_deinit(struct net_device *dev) +void ieee80211_rx_bss_list_deinit(struct ieee80211_local *local) { - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); struct ieee80211_sta_bss *bss, *tmp; list_for_each_entry_safe(bss, tmp, &local->sta_bss_list, list) - ieee80211_rx_bss_put(dev, bss); + ieee80211_rx_bss_put(local, bss); } @@ -2334,8 +2406,6 @@ static int ieee80211_sta_join_ibss(struct net_device *dev, int res, rates, i, j; struct sk_buff *skb; struct ieee80211_mgmt *mgmt; - struct ieee80211_tx_control control; - struct rate_selection ratesel; u8 *pos; struct ieee80211_sub_if_data *sdata; struct ieee80211_supported_band *sband; @@ -2353,7 +2423,7 @@ static int ieee80211_sta_join_ibss(struct net_device *dev, local->ops->reset_tsf(local_to_hw(local)); } memcpy(ifsta->bssid, bss->bssid, ETH_ALEN); - res = ieee80211_if_config(dev); + res = ieee80211_if_config(sdata, IEEE80211_IFCC_BSSID); if (res) return res; @@ -2367,24 +2437,22 @@ static int ieee80211_sta_join_ibss(struct net_device *dev, if (res) return res; - /* Set beacon template */ + /* Build IBSS probe response */ skb = dev_alloc_skb(local->hw.extra_tx_headroom + 400); - do { - if (!skb) - break; - + if (skb) { skb_reserve(skb, local->hw.extra_tx_headroom); mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24 + sizeof(mgmt->u.beacon)); memset(mgmt, 0, 24 + sizeof(mgmt->u.beacon)); mgmt->frame_control = IEEE80211_FC(IEEE80211_FTYPE_MGMT, - IEEE80211_STYPE_BEACON); + IEEE80211_STYPE_PROBE_RESP); memset(mgmt->da, 0xff, ETH_ALEN); memcpy(mgmt->sa, dev->dev_addr, ETH_ALEN); memcpy(mgmt->bssid, ifsta->bssid, ETH_ALEN); mgmt->u.beacon.beacon_int = cpu_to_le16(local->hw.conf.beacon_int); + mgmt->u.beacon.timestamp = cpu_to_le64(bss->timestamp); mgmt->u.beacon.capab_info = cpu_to_le16(bss->capability); pos = skb_put(skb, 2 + ifsta->ssid_len); @@ -2422,60 +2490,22 @@ static int ieee80211_sta_join_ibss(struct net_device *dev, memcpy(pos, &bss->supp_rates[8], rates); } - memset(&control, 0, sizeof(control)); - rate_control_get_rate(dev, sband, skb, &ratesel); - if (!ratesel.rate) { - printk(KERN_DEBUG "%s: Failed to determine TX rate " - "for IBSS beacon\n", dev->name); - break; - } - control.vif = &sdata->vif; - control.tx_rate = ratesel.rate; - if (sdata->bss_conf.use_short_preamble && - ratesel.rate->flags & IEEE80211_RATE_SHORT_PREAMBLE) - control.flags |= IEEE80211_TXCTL_SHORT_PREAMBLE; - control.antenna_sel_tx = local->hw.conf.antenna_sel_tx; - control.flags |= IEEE80211_TXCTL_NO_ACK; - control.retry_limit = 1; - - ifsta->probe_resp = skb_copy(skb, GFP_ATOMIC); - if (ifsta->probe_resp) { - mgmt = (struct ieee80211_mgmt *) - ifsta->probe_resp->data; - mgmt->frame_control = - IEEE80211_FC(IEEE80211_FTYPE_MGMT, - IEEE80211_STYPE_PROBE_RESP); - } else { - printk(KERN_DEBUG "%s: Could not allocate ProbeResp " - "template for IBSS\n", dev->name); - } - - if (local->ops->beacon_update && - local->ops->beacon_update(local_to_hw(local), - skb, &control) == 0) { - printk(KERN_DEBUG "%s: Configured IBSS beacon " - "template\n", dev->name); - skb = NULL; - } - - rates = 0; - sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; - for (i = 0; i < bss->supp_rates_len; i++) { - int bitrate = (bss->supp_rates[i] & 0x7f) * 5; - for (j = 0; j < sband->n_bitrates; j++) - if (sband->bitrates[j].bitrate == bitrate) - rates |= BIT(j); - } - ifsta->supp_rates_bits[local->hw.conf.channel->band] = rates; + ifsta->probe_resp = skb; - ieee80211_sta_def_wmm_params(dev, bss, 1); - } while (0); + ieee80211_if_config(sdata, IEEE80211_IFCC_BEACON); + } - if (skb) { - printk(KERN_DEBUG "%s: Failed to configure IBSS beacon " - "template\n", dev->name); - dev_kfree_skb(skb); + rates = 0; + sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; + for (i = 0; i < bss->supp_rates_len; i++) { + int bitrate = (bss->supp_rates[i] & 0x7f) * 5; + for (j = 0; j < sband->n_bitrates; j++) + if (sband->bitrates[j].bitrate == bitrate) + rates |= BIT(j); } + ifsta->supp_rates_bits[local->hw.conf.channel->band] = rates; + + ieee80211_sta_def_wmm_params(dev, bss, 1); ifsta->state = IEEE80211_IBSS_JOINED; mod_timer(&ifsta->timer, jiffies + IEEE80211_IBSS_MERGE_INTERVAL); @@ -2528,11 +2558,10 @@ static void ieee80211_rx_bss_info(struct net_device *dev, struct ieee80211_mgmt *mgmt, size_t len, struct ieee80211_rx_status *rx_status, + struct ieee802_11_elems *elems, int beacon) { struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - struct ieee802_11_elems elems; - size_t baselen; int freq, clen; struct ieee80211_sta_bss *bss; struct sta_info *sta; @@ -2545,35 +2574,24 @@ static void ieee80211_rx_bss_info(struct net_device *dev, if (!beacon && memcmp(mgmt->da, dev->dev_addr, ETH_ALEN)) return; /* ignore ProbeResp to foreign address */ -#if 0 - printk(KERN_DEBUG "%s: RX %s from %s to %s\n", - dev->name, beacon ? "Beacon" : "Probe Response", - print_mac(mac, mgmt->sa), print_mac(mac2, mgmt->da)); -#endif - - baselen = (u8 *) mgmt->u.beacon.variable - (u8 *) mgmt; - if (baselen > len) - return; - beacon_timestamp = le64_to_cpu(mgmt->u.beacon.timestamp); - ieee802_11_parse_elems(mgmt->u.beacon.variable, len - baselen, &elems); - if (ieee80211_vif_is_mesh(&sdata->vif) && elems.mesh_id && - elems.mesh_config && mesh_matches_local(&elems, dev)) { - u64 rates = ieee80211_sta_get_rates(local, &elems, + if (ieee80211_vif_is_mesh(&sdata->vif) && elems->mesh_id && + elems->mesh_config && mesh_matches_local(elems, dev)) { + u64 rates = ieee80211_sta_get_rates(local, elems, rx_status->band); mesh_neighbour_update(mgmt->sa, rates, dev, - mesh_peer_accepts_plinks(&elems, dev)); + mesh_peer_accepts_plinks(elems, dev)); } rcu_read_lock(); - if (sdata->vif.type == IEEE80211_IF_TYPE_IBSS && elems.supp_rates && + if (sdata->vif.type == IEEE80211_IF_TYPE_IBSS && elems->supp_rates && memcmp(mgmt->bssid, sdata->u.sta.bssid, ETH_ALEN) == 0 && (sta = sta_info_get(local, mgmt->sa))) { u64 prev_rates; - u64 supp_rates = ieee80211_sta_get_rates(local, &elems, + u64 supp_rates = ieee80211_sta_get_rates(local, elems, rx_status->band); prev_rates = sta->supp_rates[rx_status->band]; @@ -2585,21 +2603,12 @@ static void ieee80211_rx_bss_info(struct net_device *dev, sta->supp_rates[rx_status->band] = sdata->u.sta.supp_rates_bits[rx_status->band]; } - if (sta->supp_rates[rx_status->band] != prev_rates) { - printk(KERN_DEBUG "%s: updated supp_rates set for " - "%s based on beacon info (0x%llx & 0x%llx -> " - "0x%llx)\n", - dev->name, print_mac(mac, sta->addr), - (unsigned long long) prev_rates, - (unsigned long long) supp_rates, - (unsigned long long) sta->supp_rates[rx_status->band]); - } } rcu_read_unlock(); - if (elems.ds_params && elems.ds_params_len == 1) - freq = ieee80211_channel_to_frequency(elems.ds_params[0]); + if (elems->ds_params && elems->ds_params_len == 1) + freq = ieee80211_channel_to_frequency(elems->ds_params[0]); else freq = rx_status->freq; @@ -2609,23 +2618,23 @@ static void ieee80211_rx_bss_info(struct net_device *dev, return; #ifdef CONFIG_MAC80211_MESH - if (elems.mesh_config) - bss = ieee80211_rx_mesh_bss_get(dev, elems.mesh_id, - elems.mesh_id_len, elems.mesh_config, freq); + if (elems->mesh_config) + bss = ieee80211_rx_mesh_bss_get(dev, elems->mesh_id, + elems->mesh_id_len, elems->mesh_config, freq); else #endif bss = ieee80211_rx_bss_get(dev, mgmt->bssid, freq, - elems.ssid, elems.ssid_len); + elems->ssid, elems->ssid_len); if (!bss) { #ifdef CONFIG_MAC80211_MESH - if (elems.mesh_config) - bss = ieee80211_rx_mesh_bss_add(dev, elems.mesh_id, - elems.mesh_id_len, elems.mesh_config, - elems.mesh_config_len, freq); + if (elems->mesh_config) + bss = ieee80211_rx_mesh_bss_add(dev, elems->mesh_id, + elems->mesh_id_len, elems->mesh_config, + elems->mesh_config_len, freq); else #endif bss = ieee80211_rx_bss_add(dev, mgmt->bssid, freq, - elems.ssid, elems.ssid_len); + elems->ssid, elems->ssid_len); if (!bss) return; } else { @@ -2638,46 +2647,66 @@ static void ieee80211_rx_bss_info(struct net_device *dev, } /* save the ERP value so that it is available at association time */ - if (elems.erp_info && elems.erp_info_len >= 1) { - bss->erp_value = elems.erp_info[0]; + if (elems->erp_info && elems->erp_info_len >= 1) { + bss->erp_value = elems->erp_info[0]; bss->has_erp_value = 1; } - if (elems.ht_cap_elem && - (!bss->ht_ie || bss->ht_ie_len != elems.ht_cap_elem_len || - memcmp(bss->ht_ie, elems.ht_cap_elem, elems.ht_cap_elem_len))) { + if (elems->ht_cap_elem && + (!bss->ht_ie || bss->ht_ie_len != elems->ht_cap_elem_len || + memcmp(bss->ht_ie, elems->ht_cap_elem, elems->ht_cap_elem_len))) { kfree(bss->ht_ie); - bss->ht_ie = kmalloc(elems.ht_cap_elem_len + 2, GFP_ATOMIC); + bss->ht_ie = kmalloc(elems->ht_cap_elem_len + 2, GFP_ATOMIC); if (bss->ht_ie) { - memcpy(bss->ht_ie, elems.ht_cap_elem - 2, - elems.ht_cap_elem_len + 2); - bss->ht_ie_len = elems.ht_cap_elem_len + 2; + memcpy(bss->ht_ie, elems->ht_cap_elem - 2, + elems->ht_cap_elem_len + 2); + bss->ht_ie_len = elems->ht_cap_elem_len + 2; } else bss->ht_ie_len = 0; - } else if (!elems.ht_cap_elem && bss->ht_ie) { + } else if (!elems->ht_cap_elem && bss->ht_ie) { kfree(bss->ht_ie); bss->ht_ie = NULL; bss->ht_ie_len = 0; } + if (elems->ht_info_elem && + (!bss->ht_add_ie || + bss->ht_add_ie_len != elems->ht_info_elem_len || + memcmp(bss->ht_add_ie, elems->ht_info_elem, + elems->ht_info_elem_len))) { + kfree(bss->ht_add_ie); + bss->ht_add_ie = + kmalloc(elems->ht_info_elem_len + 2, GFP_ATOMIC); + if (bss->ht_add_ie) { + memcpy(bss->ht_add_ie, elems->ht_info_elem - 2, + elems->ht_info_elem_len + 2); + bss->ht_add_ie_len = elems->ht_info_elem_len + 2; + } else + bss->ht_add_ie_len = 0; + } else if (!elems->ht_info_elem && bss->ht_add_ie) { + kfree(bss->ht_add_ie); + bss->ht_add_ie = NULL; + bss->ht_add_ie_len = 0; + } + bss->beacon_int = le16_to_cpu(mgmt->u.beacon.beacon_int); bss->capability = le16_to_cpu(mgmt->u.beacon.capab_info); bss->supp_rates_len = 0; - if (elems.supp_rates) { + if (elems->supp_rates) { clen = IEEE80211_MAX_SUPP_RATES - bss->supp_rates_len; - if (clen > elems.supp_rates_len) - clen = elems.supp_rates_len; - memcpy(&bss->supp_rates[bss->supp_rates_len], elems.supp_rates, + if (clen > elems->supp_rates_len) + clen = elems->supp_rates_len; + memcpy(&bss->supp_rates[bss->supp_rates_len], elems->supp_rates, clen); bss->supp_rates_len += clen; } - if (elems.ext_supp_rates) { + if (elems->ext_supp_rates) { clen = IEEE80211_MAX_SUPP_RATES - bss->supp_rates_len; - if (clen > elems.ext_supp_rates_len) - clen = elems.ext_supp_rates_len; + if (clen > elems->ext_supp_rates_len) + clen = elems->ext_supp_rates_len; memcpy(&bss->supp_rates[bss->supp_rates_len], - elems.ext_supp_rates, clen); + elems->ext_supp_rates, clen); bss->supp_rates_len += clen; } @@ -2685,9 +2714,9 @@ static void ieee80211_rx_bss_info(struct net_device *dev, bss->timestamp = beacon_timestamp; bss->last_update = jiffies; - bss->rssi = rx_status->ssi; bss->signal = rx_status->signal; bss->noise = rx_status->noise; + bss->qual = rx_status->qual; if (!beacon && !bss->probe_resp) bss->probe_resp = true; @@ -2697,37 +2726,37 @@ static void ieee80211_rx_bss_info(struct net_device *dev, */ if (sdata->vif.type != IEEE80211_IF_TYPE_IBSS && bss->probe_resp && beacon) { - ieee80211_rx_bss_put(dev, bss); + ieee80211_rx_bss_put(local, bss); return; } - if (elems.wpa && - (!bss->wpa_ie || bss->wpa_ie_len != elems.wpa_len || - memcmp(bss->wpa_ie, elems.wpa, elems.wpa_len))) { + if (elems->wpa && + (!bss->wpa_ie || bss->wpa_ie_len != elems->wpa_len || + memcmp(bss->wpa_ie, elems->wpa, elems->wpa_len))) { kfree(bss->wpa_ie); - bss->wpa_ie = kmalloc(elems.wpa_len + 2, GFP_ATOMIC); + bss->wpa_ie = kmalloc(elems->wpa_len + 2, GFP_ATOMIC); if (bss->wpa_ie) { - memcpy(bss->wpa_ie, elems.wpa - 2, elems.wpa_len + 2); - bss->wpa_ie_len = elems.wpa_len + 2; + memcpy(bss->wpa_ie, elems->wpa - 2, elems->wpa_len + 2); + bss->wpa_ie_len = elems->wpa_len + 2; } else bss->wpa_ie_len = 0; - } else if (!elems.wpa && bss->wpa_ie) { + } else if (!elems->wpa && bss->wpa_ie) { kfree(bss->wpa_ie); bss->wpa_ie = NULL; bss->wpa_ie_len = 0; } - if (elems.rsn && - (!bss->rsn_ie || bss->rsn_ie_len != elems.rsn_len || - memcmp(bss->rsn_ie, elems.rsn, elems.rsn_len))) { + if (elems->rsn && + (!bss->rsn_ie || bss->rsn_ie_len != elems->rsn_len || + memcmp(bss->rsn_ie, elems->rsn, elems->rsn_len))) { kfree(bss->rsn_ie); - bss->rsn_ie = kmalloc(elems.rsn_len + 2, GFP_ATOMIC); + bss->rsn_ie = kmalloc(elems->rsn_len + 2, GFP_ATOMIC); if (bss->rsn_ie) { - memcpy(bss->rsn_ie, elems.rsn - 2, elems.rsn_len + 2); - bss->rsn_ie_len = elems.rsn_len + 2; + memcpy(bss->rsn_ie, elems->rsn - 2, elems->rsn_len + 2); + bss->rsn_ie_len = elems->rsn_len + 2; } else bss->rsn_ie_len = 0; - } else if (!elems.rsn && bss->rsn_ie) { + } else if (!elems->rsn && bss->rsn_ie) { kfree(bss->rsn_ie); bss->rsn_ie = NULL; bss->rsn_ie_len = 0; @@ -2747,20 +2776,21 @@ static void ieee80211_rx_bss_info(struct net_device *dev, * inclusion of the WMM Parameters in beacons, however, is optional. */ - if (elems.wmm_param && - (!bss->wmm_ie || bss->wmm_ie_len != elems.wmm_param_len || - memcmp(bss->wmm_ie, elems.wmm_param, elems.wmm_param_len))) { + if (elems->wmm_param && + (!bss->wmm_ie || bss->wmm_ie_len != elems->wmm_param_len || + memcmp(bss->wmm_ie, elems->wmm_param, elems->wmm_param_len))) { kfree(bss->wmm_ie); - bss->wmm_ie = kmalloc(elems.wmm_param_len + 2, GFP_ATOMIC); + bss->wmm_ie = kmalloc(elems->wmm_param_len + 2, GFP_ATOMIC); if (bss->wmm_ie) { - memcpy(bss->wmm_ie, elems.wmm_param - 2, - elems.wmm_param_len + 2); - bss->wmm_ie_len = elems.wmm_param_len + 2; + memcpy(bss->wmm_ie, elems->wmm_param - 2, + elems->wmm_param_len + 2); + bss->wmm_ie_len = elems->wmm_param_len + 2; } else bss->wmm_ie_len = 0; - } else if (elems.wmm_info && - (!bss->wmm_ie || bss->wmm_ie_len != elems.wmm_info_len || - memcmp(bss->wmm_ie, elems.wmm_info, elems.wmm_info_len))) { + } else if (elems->wmm_info && + (!bss->wmm_ie || bss->wmm_ie_len != elems->wmm_info_len || + memcmp(bss->wmm_ie, elems->wmm_info, + elems->wmm_info_len))) { /* As for certain AP's Fifth bit is not set in WMM IE in * beacon frames.So while parsing the beacon frame the * wmm_info structure is used instead of wmm_param. @@ -2770,14 +2800,14 @@ static void ieee80211_rx_bss_info(struct net_device *dev, * n-band association. */ kfree(bss->wmm_ie); - bss->wmm_ie = kmalloc(elems.wmm_info_len + 2, GFP_ATOMIC); + bss->wmm_ie = kmalloc(elems->wmm_info_len + 2, GFP_ATOMIC); if (bss->wmm_ie) { - memcpy(bss->wmm_ie, elems.wmm_info - 2, - elems.wmm_info_len + 2); - bss->wmm_ie_len = elems.wmm_info_len + 2; + memcpy(bss->wmm_ie, elems->wmm_info - 2, + elems->wmm_info_len + 2); + bss->wmm_ie_len = elems->wmm_info_len + 2; } else bss->wmm_ie_len = 0; - } else if (!elems.wmm_param && !elems.wmm_info && bss->wmm_ie) { + } else if (!elems->wmm_param && !elems->wmm_info && bss->wmm_ie) { kfree(bss->wmm_ie); bss->wmm_ie = NULL; bss->wmm_ie_len = 0; @@ -2788,8 +2818,9 @@ static void ieee80211_rx_bss_info(struct net_device *dev, !local->sta_sw_scanning && !local->sta_hw_scanning && bss->capability & WLAN_CAPABILITY_IBSS && bss->freq == local->oper_channel->center_freq && - elems.ssid_len == sdata->u.sta.ssid_len && - memcmp(elems.ssid, sdata->u.sta.ssid, sdata->u.sta.ssid_len) == 0) { + elems->ssid_len == sdata->u.sta.ssid_len && + memcmp(elems->ssid, sdata->u.sta.ssid, + sdata->u.sta.ssid_len) == 0) { if (rx_status->flag & RX_FLAG_TSFT) { /* in order for correct IBSS merging we need mactime * @@ -2827,18 +2858,18 @@ static void ieee80211_rx_bss_info(struct net_device *dev, #endif /* CONFIG_MAC80211_IBSS_DEBUG */ if (beacon_timestamp > rx_timestamp) { #ifndef CONFIG_MAC80211_IBSS_DEBUG - if (net_ratelimit()) + printk(KERN_DEBUG "%s: beacon TSF higher than " + "local TSF - IBSS merge with BSSID %s\n", + dev->name, print_mac(mac, mgmt->bssid)); #endif - printk(KERN_DEBUG "%s: beacon TSF higher than " - "local TSF - IBSS merge with BSSID %s\n", - dev->name, print_mac(mac, mgmt->bssid)); ieee80211_sta_join_ibss(dev, &sdata->u.sta, bss); ieee80211_ibss_add_sta(dev, NULL, - mgmt->bssid, mgmt->sa); + mgmt->bssid, mgmt->sa, + BIT(rx_status->rate_idx)); } } - ieee80211_rx_bss_put(dev, bss); + ieee80211_rx_bss_put(local, bss); } @@ -2847,7 +2878,17 @@ static void ieee80211_rx_mgmt_probe_resp(struct net_device *dev, size_t len, struct ieee80211_rx_status *rx_status) { - ieee80211_rx_bss_info(dev, mgmt, len, rx_status, 0); + size_t baselen; + struct ieee802_11_elems elems; + + baselen = (u8 *) mgmt->u.probe_resp.variable - (u8 *) mgmt; + if (baselen > len) + return; + + ieee802_11_parse_elems(mgmt->u.probe_resp.variable, len - baselen, + &elems); + + ieee80211_rx_bss_info(dev, mgmt, len, rx_status, &elems, 0); } @@ -2864,7 +2905,14 @@ static void ieee80211_rx_mgmt_beacon(struct net_device *dev, struct ieee80211_conf *conf = &local->hw.conf; u32 changed = 0; - ieee80211_rx_bss_info(dev, mgmt, len, rx_status, 1); + /* 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(dev, mgmt, len, rx_status, &elems, 1); sdata = IEEE80211_DEV_TO_SUB_IF(dev); if (sdata->vif.type != IEEE80211_IF_TYPE_STA) @@ -2875,17 +2923,8 @@ static void ieee80211_rx_mgmt_beacon(struct net_device *dev, memcmp(ifsta->bssid, mgmt->bssid, ETH_ALEN) != 0) return; - /* 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); - - if (elems.wmm_param && (ifsta->flags & IEEE80211_STA_WMM_ENABLED)) { - ieee80211_sta_wmm_params(dev, ifsta, elems.wmm_param, - elems.wmm_param_len); - } + ieee80211_sta_wmm_params(dev, ifsta, elems.wmm_param, + elems.wmm_param_len); /* Do not send changes to driver if we are scanning. This removes * requirement that driver's bss_info_changed function needs to be @@ -2962,11 +3001,11 @@ static void ieee80211_rx_mgmt_probe_req(struct net_device *dev, pos = mgmt->u.probe_req.variable; if (pos[0] != WLAN_EID_SSID || pos + 2 + pos[1] > end) { - if (net_ratelimit()) { - printk(KERN_DEBUG "%s: Invalid SSID IE in ProbeReq " - "from %s\n", - dev->name, print_mac(mac, mgmt->sa)); - } +#ifdef CONFIG_MAC80211_IBSS_DEBUG + printk(KERN_DEBUG "%s: Invalid SSID IE in ProbeReq " + "from %s\n", + dev->name, print_mac(mac, mgmt->sa)); +#endif return; } if (pos[1] != 0 && @@ -2997,11 +3036,24 @@ static void ieee80211_rx_mgmt_action(struct net_device *dev, struct ieee80211_rx_status *rx_status) { struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); if (len < IEEE80211_MIN_ACTION_SIZE) return; switch (mgmt->u.action.category) { + case WLAN_CATEGORY_SPECTRUM_MGMT: + if (local->hw.conf.channel->band != IEEE80211_BAND_5GHZ) + break; + switch (mgmt->u.action.u.chan_switch.action_code) { + case WLAN_ACTION_SPCT_MSR_REQ: + if (len < (IEEE80211_MIN_ACTION_SIZE + + sizeof(mgmt->u.action.u.measurement))) + break; + ieee80211_sta_process_measurement_req(dev, mgmt, len); + break; + } + break; case WLAN_CATEGORY_BACK: switch (mgmt->u.action.u.addba_req.action_code) { case WLAN_ACTION_ADDBA_REQ: @@ -3022,11 +3074,6 @@ static void ieee80211_rx_mgmt_action(struct net_device *dev, break; ieee80211_sta_process_delba(dev, mgmt, len); break; - default: - if (net_ratelimit()) - printk(KERN_DEBUG "%s: Rx unknown A-MPDU action\n", - dev->name); - break; } break; case PLINK_CATEGORY: @@ -3037,11 +3084,6 @@ static void ieee80211_rx_mgmt_action(struct net_device *dev, if (ieee80211_vif_is_mesh(&sdata->vif)) mesh_rx_path_sel_frame(dev, mgmt, len); break; - default: - if (net_ratelimit()) - printk(KERN_DEBUG "%s: Rx unknown action frame - " - "category=%d\n", dev->name, mgmt->u.action.category); - break; } } @@ -3077,11 +3119,6 @@ void ieee80211_sta_rx_mgmt(struct net_device *dev, struct sk_buff *skb, skb_queue_tail(&ifsta->skb_queue, skb); queue_work(local->hw.workqueue, &ifsta->work); return; - default: - printk(KERN_DEBUG "%s: received unknown management frame - " - "stype=%d\n", dev->name, - (fc & IEEE80211_FCTL_STYPE) >> 4); - break; } fail: @@ -3145,33 +3182,32 @@ ieee80211_sta_rx_scan(struct net_device *dev, struct sk_buff *skb, struct ieee80211_rx_status *rx_status) { struct ieee80211_mgmt *mgmt; - u16 fc; + __le16 fc; if (skb->len < 2) return RX_DROP_UNUSABLE; mgmt = (struct ieee80211_mgmt *) skb->data; - fc = le16_to_cpu(mgmt->frame_control); + fc = mgmt->frame_control; - if ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_CTL) + if (ieee80211_is_ctl(fc)) return RX_CONTINUE; if (skb->len < 24) return RX_DROP_MONITOR; - if ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT) { - if ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_PROBE_RESP) { - ieee80211_rx_mgmt_probe_resp(dev, mgmt, - skb->len, rx_status); - dev_kfree_skb(skb); - return RX_QUEUED; - } else if ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_BEACON) { - ieee80211_rx_mgmt_beacon(dev, mgmt, skb->len, - rx_status); - dev_kfree_skb(skb); - return RX_QUEUED; - } + if (ieee80211_is_probe_resp(fc)) { + ieee80211_rx_mgmt_probe_resp(dev, mgmt, skb->len, rx_status); + dev_kfree_skb(skb); + return RX_QUEUED; + } + + if (ieee80211_is_beacon(fc)) { + ieee80211_rx_mgmt_beacon(dev, mgmt, skb->len, rx_status); + dev_kfree_skb(skb); + return RX_QUEUED; } + return RX_CONTINUE; } @@ -3211,8 +3247,10 @@ static void ieee80211_sta_expire(struct net_device *dev, unsigned long exp_time) spin_lock_irqsave(&local->sta_lock, flags); list_for_each_entry_safe(sta, tmp, &local->sta_list, list) if (time_after(jiffies, sta->last_rx + exp_time)) { +#ifdef CONFIG_MAC80211_IBSS_DEBUG printk(KERN_DEBUG "%s: expiring inactive STA %s\n", dev->name, print_mac(mac, sta->addr)); +#endif __sta_info_unlink(&sta); if (sta) list_add(&sta->list, &tmp_list); @@ -3251,7 +3289,7 @@ static void ieee80211_mesh_housekeeping(struct net_device *dev, free_plinks = mesh_plink_availables(sdata); if (free_plinks != sdata->u.sta.accepting_plinks) - ieee80211_if_config_beacon(dev); + ieee80211_if_config(sdata, IEEE80211_IFCC_BEACON); mod_timer(&ifsta->timer, jiffies + IEEE80211_MESH_HOUSEKEEPING_INTERVAL); @@ -3295,13 +3333,10 @@ void ieee80211_sta_work(struct work_struct *work) if (local->sta_sw_scanning || local->sta_hw_scanning) return; - if (sdata->vif.type != IEEE80211_IF_TYPE_STA && - sdata->vif.type != IEEE80211_IF_TYPE_IBSS && - sdata->vif.type != IEEE80211_IF_TYPE_MESH_POINT) { - printk(KERN_DEBUG "%s: ieee80211_sta_work: non-STA interface " - "(type=%d)\n", dev->name, sdata->vif.type); + if (WARN_ON(sdata->vif.type != IEEE80211_IF_TYPE_STA && + sdata->vif.type != IEEE80211_IF_TYPE_IBSS && + sdata->vif.type != IEEE80211_IF_TYPE_MESH_POINT)) return; - } ifsta = &sdata->u.sta; while ((skb = skb_dequeue(&ifsta->skb_queue))) @@ -3355,8 +3390,7 @@ void ieee80211_sta_work(struct work_struct *work) break; #endif default: - printk(KERN_DEBUG "ieee80211_sta_work: Unknown state %d\n", - ifsta->state); + WARN_ON(1); break; } @@ -3391,8 +3425,6 @@ static void ieee80211_sta_reset_auth(struct net_device *dev, ifsta->auth_alg = WLAN_AUTH_LEAP; else ifsta->auth_alg = WLAN_AUTH_OPEN; - printk(KERN_DEBUG "%s: Initial auth_alg=%d\n", dev->name, - ifsta->auth_alg); ifsta->auth_transaction = -1; ifsta->flags &= ~IEEE80211_STA_ASSOCIATED; ifsta->auth_tries = ifsta->assoc_tries = 0; @@ -3481,9 +3513,9 @@ static int ieee80211_sta_config_auth(struct net_device *dev, !ieee80211_sta_match_ssid(ifsta, bss->ssid, bss->ssid_len)) continue; - if (!selected || top_rssi < bss->rssi) { + if (!selected || top_rssi < bss->signal) { selected = bss; - top_rssi = bss->rssi; + top_rssi = bss->signal; } } if (selected) @@ -3497,7 +3529,7 @@ static int ieee80211_sta_config_auth(struct net_device *dev, selected->ssid_len); ieee80211_sta_set_bssid(dev, selected->bssid); ieee80211_sta_def_wmm_params(dev, selected, 0); - ieee80211_rx_bss_put(dev, selected); + ieee80211_rx_bss_put(local, selected); ifsta->state = IEEE80211_AUTHENTICATE; ieee80211_sta_reset_auth(dev, ifsta); return 0; @@ -3556,14 +3588,16 @@ static int ieee80211_sta_create_ibss(struct net_device *dev, sband = local->hw.wiphy->bands[bss->band]; if (local->hw.conf.beacon_int == 0) - local->hw.conf.beacon_int = 10000; + local->hw.conf.beacon_int = 100; bss->beacon_int = local->hw.conf.beacon_int; bss->last_update = jiffies; bss->capability = WLAN_CAPABILITY_IBSS; - if (sdata->default_key) { + + if (sdata->default_key) bss->capability |= WLAN_CAPABILITY_PRIVACY; - } else + else sdata->drop_unencrypted = 0; + bss->supp_rates_len = sband->n_bitrates; pos = bss->supp_rates; for (i = 0; i < sband->n_bitrates; i++) { @@ -3572,7 +3606,7 @@ static int ieee80211_sta_create_ibss(struct net_device *dev, } ret = ieee80211_sta_join_ibss(dev, ifsta, bss); - ieee80211_rx_bss_put(dev, bss); + ieee80211_rx_bss_put(local, bss); return ret; } @@ -3628,7 +3662,7 @@ static int ieee80211_sta_find_ibss(struct net_device *dev, " based on configured SSID\n", dev->name, print_mac(mac, bssid)); ret = ieee80211_sta_join_ibss(dev, ifsta, bss); - ieee80211_rx_bss_put(dev, bss); + ieee80211_rx_bss_put(local, bss); return ret; } #ifdef CONFIG_MAC80211_IBSS_DEBUG @@ -3679,28 +3713,45 @@ int ieee80211_sta_set_ssid(struct net_device *dev, char *ssid, size_t len) { struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); struct ieee80211_if_sta *ifsta; + int res; if (len > IEEE80211_MAX_SSID_LEN) return -EINVAL; ifsta = &sdata->u.sta; - if (ifsta->ssid_len != len || memcmp(ifsta->ssid, ssid, len) != 0) + if (ifsta->ssid_len != len || memcmp(ifsta->ssid, ssid, len) != 0) { + memset(ifsta->ssid, 0, sizeof(ifsta->ssid)); + memcpy(ifsta->ssid, ssid, len); + ifsta->ssid_len = len; ifsta->flags &= ~IEEE80211_STA_PREV_BSSID_SET; - memcpy(ifsta->ssid, ssid, len); - memset(ifsta->ssid + len, 0, IEEE80211_MAX_SSID_LEN - len); - ifsta->ssid_len = len; + + res = 0; + /* + * Hack! MLME code needs to be cleaned up to have different + * entry points for configuration and internal selection change + */ + if (netif_running(sdata->dev)) + res = ieee80211_if_config(sdata, IEEE80211_IFCC_SSID); + if (res) { + printk(KERN_DEBUG "%s: Failed to config new SSID to " + "the low-level driver\n", dev->name); + return res; + } + } if (len) ifsta->flags |= IEEE80211_STA_SSID_SET; else ifsta->flags &= ~IEEE80211_STA_SSID_SET; + if (sdata->vif.type == IEEE80211_IF_TYPE_IBSS && !(ifsta->flags & IEEE80211_STA_BSSID_SET)) { ifsta->ibss_join_req = jiffies; ifsta->state = IEEE80211_IBSS_SEARCH; return ieee80211_sta_find_ibss(dev, ifsta); } + return 0; } @@ -3726,7 +3777,12 @@ int ieee80211_sta_set_bssid(struct net_device *dev, u8 *bssid) if (memcmp(ifsta->bssid, bssid, ETH_ALEN) != 0) { memcpy(ifsta->bssid, bssid, ETH_ALEN); - res = ieee80211_if_config(dev); + res = 0; + /* + * Hack! See also ieee80211_sta_set_ssid. + */ + if (netif_running(sdata->dev)) + res = ieee80211_if_config(sdata, IEEE80211_IFCC_BSSID); if (res) { printk(KERN_DEBUG "%s: Failed to config new BSSID to " "the low-level driver\n", dev->name); @@ -3749,7 +3805,7 @@ static void ieee80211_send_nullfunc(struct ieee80211_local *local, { struct sk_buff *skb; struct ieee80211_hdr *nullfunc; - u16 fc; + __le16 fc; skb = dev_alloc_skb(local->hw.extra_tx_headroom + 24); if (!skb) { @@ -3761,11 +3817,11 @@ static void ieee80211_send_nullfunc(struct ieee80211_local *local, nullfunc = (struct ieee80211_hdr *) skb_put(skb, 24); memset(nullfunc, 0, 24); - fc = IEEE80211_FTYPE_DATA | IEEE80211_STYPE_NULLFUNC | - IEEE80211_FCTL_TODS; + fc = cpu_to_le16(IEEE80211_FTYPE_DATA | IEEE80211_STYPE_NULLFUNC | + IEEE80211_FCTL_TODS); if (powersave) - fc |= IEEE80211_FCTL_PM; - nullfunc->frame_control = cpu_to_le16(fc); + fc |= cpu_to_le16(IEEE80211_FCTL_PM); + nullfunc->frame_control = fc; memcpy(nullfunc->addr1, sdata->u.sta.bssid, ETH_ALEN); memcpy(nullfunc->addr2, sdata->dev->dev_addr, ETH_ALEN); memcpy(nullfunc->addr3, sdata->u.sta.bssid, ETH_ALEN); @@ -3813,6 +3869,7 @@ void ieee80211_scan_completed(struct ieee80211_hw *hw) 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, @@ -3820,15 +3877,11 @@ void ieee80211_scan_completed(struct ieee80211_hw *hw) local->mdev->mc_count, local->mdev->mc_list); + netif_addr_unlock(local->mdev); netif_tx_unlock_bh(local->mdev); rcu_read_lock(); list_for_each_entry_rcu(sdata, &local->interfaces, list) { - - /* No need to wake the master device. */ - if (sdata->dev == local->mdev) - continue; - /* Tell AP we're back */ if (sdata->vif.type == IEEE80211_IF_TYPE_STA && sdata->u.sta.flags & IEEE80211_STA_ASSOCIATED) @@ -3994,12 +4047,6 @@ static int ieee80211_sta_start_scan(struct net_device *dev, rcu_read_lock(); list_for_each_entry_rcu(sdata, &local->interfaces, list) { - - /* Don't stop the master interface, otherwise we can't transmit - * probes! */ - if (sdata->dev == local->mdev) - continue; - netif_stop_queue(sdata->dev); if (sdata->vif.type == IEEE80211_IF_TYPE_STA && (sdata->u.sta.flags & IEEE80211_STA_ASSOCIATED)) @@ -4017,14 +4064,14 @@ static int ieee80211_sta_start_scan(struct net_device *dev, local->scan_band = IEEE80211_BAND_2GHZ; local->scan_dev = dev; - netif_tx_lock_bh(local->mdev); + 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_tx_unlock_bh(local->mdev); + 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, @@ -4059,6 +4106,7 @@ int ieee80211_sta_req_scan(struct net_device *dev, u8 *ssid, size_t ssid_len) static char * ieee80211_sta_scan_result(struct net_device *dev, + struct iw_request_info *info, struct ieee80211_sta_bss *bss, char *current_ev, char *end_buf) { @@ -4073,7 +4121,7 @@ ieee80211_sta_scan_result(struct net_device *dev, iwe.cmd = SIOCGIWAP; iwe.u.ap_addr.sa_family = ARPHRD_ETHER; memcpy(iwe.u.ap_addr.sa_data, bss->bssid, ETH_ALEN); - current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, + current_ev = iwe_stream_add_event(info, current_ev, end_buf, &iwe, IW_EV_ADDR_LEN); memset(&iwe, 0, sizeof(iwe)); @@ -4081,13 +4129,13 @@ ieee80211_sta_scan_result(struct net_device *dev, if (bss_mesh_cfg(bss)) { iwe.u.data.length = bss_mesh_id_len(bss); iwe.u.data.flags = 1; - current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, - bss_mesh_id(bss)); + current_ev = iwe_stream_add_point(info, current_ev, end_buf, + &iwe, bss_mesh_id(bss)); } else { iwe.u.data.length = bss->ssid_len; iwe.u.data.flags = 1; - current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, - bss->ssid); + current_ev = iwe_stream_add_point(info, current_ev, end_buf, + &iwe, bss->ssid); } if (bss->capability & (WLAN_CAPABILITY_ESS | WLAN_CAPABILITY_IBSS) @@ -4100,30 +4148,30 @@ ieee80211_sta_scan_result(struct net_device *dev, iwe.u.mode = IW_MODE_MASTER; else iwe.u.mode = IW_MODE_ADHOC; - current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, - IW_EV_UINT_LEN); + current_ev = iwe_stream_add_event(info, current_ev, end_buf, + &iwe, IW_EV_UINT_LEN); } memset(&iwe, 0, sizeof(iwe)); iwe.cmd = SIOCGIWFREQ; iwe.u.freq.m = ieee80211_frequency_to_channel(bss->freq); iwe.u.freq.e = 0; - current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, + current_ev = iwe_stream_add_event(info, current_ev, end_buf, &iwe, IW_EV_FREQ_LEN); memset(&iwe, 0, sizeof(iwe)); iwe.cmd = SIOCGIWFREQ; iwe.u.freq.m = bss->freq; iwe.u.freq.e = 6; - current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, + current_ev = iwe_stream_add_event(info, current_ev, end_buf, &iwe, IW_EV_FREQ_LEN); memset(&iwe, 0, sizeof(iwe)); iwe.cmd = IWEVQUAL; - iwe.u.qual.qual = bss->signal; - iwe.u.qual.level = bss->rssi; + iwe.u.qual.qual = bss->qual; + iwe.u.qual.level = bss->signal; iwe.u.qual.noise = bss->noise; iwe.u.qual.updated = local->wstats_flags; - current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, + current_ev = iwe_stream_add_event(info, current_ev, end_buf, &iwe, IW_EV_QUAL_LEN); memset(&iwe, 0, sizeof(iwe)); @@ -4133,27 +4181,36 @@ ieee80211_sta_scan_result(struct net_device *dev, else iwe.u.data.flags = IW_ENCODE_DISABLED; iwe.u.data.length = 0; - current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, ""); + current_ev = iwe_stream_add_point(info, current_ev, end_buf, + &iwe, ""); if (bss && bss->wpa_ie) { memset(&iwe, 0, sizeof(iwe)); iwe.cmd = IWEVGENIE; iwe.u.data.length = bss->wpa_ie_len; - current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, - bss->wpa_ie); + current_ev = iwe_stream_add_point(info, current_ev, end_buf, + &iwe, bss->wpa_ie); } if (bss && bss->rsn_ie) { memset(&iwe, 0, sizeof(iwe)); iwe.cmd = IWEVGENIE; iwe.u.data.length = bss->rsn_ie_len; - current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, - bss->rsn_ie); + current_ev = iwe_stream_add_point(info, current_ev, end_buf, + &iwe, bss->rsn_ie); + } + + if (bss && bss->ht_ie) { + memset(&iwe, 0, sizeof(iwe)); + iwe.cmd = IWEVGENIE; + iwe.u.data.length = bss->ht_ie_len; + current_ev = iwe_stream_add_point(info, current_ev, end_buf, + &iwe, bss->ht_ie); } if (bss && bss->supp_rates_len > 0) { /* display all supported rates in readable format */ - char *p = current_ev + IW_EV_LCP_LEN; + char *p = current_ev + iwe_stream_lcp_len(info); int i; memset(&iwe, 0, sizeof(iwe)); @@ -4164,7 +4221,7 @@ ieee80211_sta_scan_result(struct net_device *dev, for (i = 0; i < bss->supp_rates_len; i++) { iwe.u.bitrate.value = ((bss->supp_rates[i] & 0x7f) * 500000); - p = iwe_stream_add_value(current_ev, p, + p = iwe_stream_add_value(info, current_ev, p, end_buf, &iwe, IW_EV_PARAM_LEN); } current_ev = p; @@ -4178,8 +4235,16 @@ ieee80211_sta_scan_result(struct net_device *dev, iwe.cmd = IWEVCUSTOM; sprintf(buf, "tsf=%016llx", (unsigned long long)(bss->timestamp)); iwe.u.data.length = strlen(buf); - current_ev = iwe_stream_add_point(current_ev, end_buf, + current_ev = iwe_stream_add_point(info, current_ev, + end_buf, &iwe, buf); + memset(&iwe, 0, sizeof(iwe)); + iwe.cmd = IWEVCUSTOM; + sprintf(buf, " Last beacon: %dms ago", + jiffies_to_msecs(jiffies - bss->last_update)); + iwe.u.data.length = strlen(buf); + current_ev = iwe_stream_add_point(info, current_ev, + end_buf, &iwe, buf); kfree(buf); } } @@ -4193,31 +4258,36 @@ ieee80211_sta_scan_result(struct net_device *dev, iwe.cmd = IWEVCUSTOM; sprintf(buf, "Mesh network (version %d)", cfg[0]); iwe.u.data.length = strlen(buf); - current_ev = iwe_stream_add_point(current_ev, end_buf, + current_ev = iwe_stream_add_point(info, current_ev, + end_buf, &iwe, buf); sprintf(buf, "Path Selection Protocol ID: " "0x%02X%02X%02X%02X", cfg[1], cfg[2], cfg[3], cfg[4]); iwe.u.data.length = strlen(buf); - current_ev = iwe_stream_add_point(current_ev, end_buf, + current_ev = iwe_stream_add_point(info, current_ev, + end_buf, &iwe, buf); sprintf(buf, "Path Selection Metric ID: " "0x%02X%02X%02X%02X", cfg[5], cfg[6], cfg[7], cfg[8]); iwe.u.data.length = strlen(buf); - current_ev = iwe_stream_add_point(current_ev, end_buf, + current_ev = iwe_stream_add_point(info, current_ev, + end_buf, &iwe, buf); sprintf(buf, "Congestion Control Mode ID: " "0x%02X%02X%02X%02X", cfg[9], cfg[10], cfg[11], cfg[12]); iwe.u.data.length = strlen(buf); - current_ev = iwe_stream_add_point(current_ev, end_buf, + current_ev = iwe_stream_add_point(info, current_ev, + end_buf, &iwe, buf); sprintf(buf, "Channel Precedence: " "0x%02X%02X%02X%02X", cfg[13], cfg[14], cfg[15], cfg[16]); iwe.u.data.length = strlen(buf); - current_ev = iwe_stream_add_point(current_ev, end_buf, + current_ev = iwe_stream_add_point(info, current_ev, + end_buf, &iwe, buf); kfree(buf); } @@ -4227,7 +4297,9 @@ ieee80211_sta_scan_result(struct net_device *dev, } -int ieee80211_sta_scan_results(struct net_device *dev, char *buf, size_t len) +int ieee80211_sta_scan_results(struct net_device *dev, + struct iw_request_info *info, + char *buf, size_t len) { struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); char *current_ev = buf; @@ -4240,8 +4312,8 @@ int ieee80211_sta_scan_results(struct net_device *dev, char *buf, size_t len) spin_unlock_bh(&local->sta_bss_lock); return -E2BIG; } - current_ev = ieee80211_sta_scan_result(dev, bss, current_ev, - end_buf); + current_ev = ieee80211_sta_scan_result(dev, info, bss, + current_ev, end_buf); } spin_unlock_bh(&local->sta_bss_lock); return current_ev - buf; @@ -4252,6 +4324,7 @@ int ieee80211_sta_set_extra_ie(struct net_device *dev, char *ie, size_t len) { struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); struct ieee80211_if_sta *ifsta = &sdata->u.sta; + kfree(ifsta->extra_ie); if (len == 0) { ifsta->extra_ie = NULL; @@ -4269,14 +4342,15 @@ int ieee80211_sta_set_extra_ie(struct net_device *dev, char *ie, size_t len) } -struct sta_info * ieee80211_ibss_add_sta(struct net_device *dev, - struct sk_buff *skb, u8 *bssid, - u8 *addr) +struct sta_info *ieee80211_ibss_add_sta(struct net_device *dev, + struct sk_buff *skb, u8 *bssid, + u8 *addr, u64 supp_rates) { struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); struct sta_info *sta; struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); DECLARE_MAC_BUF(mac); + int band = local->hw.conf.channel->band; /* TODO: Could consider removing the least recently used entry and * allow new one to be added. */ @@ -4288,17 +4362,24 @@ struct sta_info * ieee80211_ibss_add_sta(struct net_device *dev, return NULL; } + if (compare_ether_addr(bssid, sdata->u.sta.bssid)) + return NULL; + +#ifdef CONFIG_MAC80211_VERBOSE_DEBUG printk(KERN_DEBUG "%s: Adding new IBSS station %s (dev=%s)\n", wiphy_name(local->hw.wiphy), print_mac(mac, addr), dev->name); +#endif sta = sta_info_alloc(sdata, addr, GFP_ATOMIC); if (!sta) return NULL; - sta->flags |= WLAN_STA_AUTHORIZED; + set_sta_flags(sta, WLAN_STA_AUTHORIZED); - sta->supp_rates[local->hw.conf.channel->band] = - sdata->u.sta.supp_rates_bits[local->hw.conf.channel->band]; + if (supp_rates) + sta->supp_rates[band] = supp_rates; + else + sta->supp_rates[band] = sdata->u.sta.supp_rates_bits[band]; rate_control_rate_init(sta, local); @@ -4314,7 +4395,7 @@ int ieee80211_sta_deauthenticate(struct net_device *dev, u16 reason) struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); struct ieee80211_if_sta *ifsta = &sdata->u.sta; - printk(KERN_DEBUG "%s: deauthenticate(reason=%d)\n", + printk(KERN_DEBUG "%s: deauthenticating by local choice (reason=%d)\n", dev->name, reason); if (sdata->vif.type != IEEE80211_IF_TYPE_STA && @@ -4332,7 +4413,7 @@ int ieee80211_sta_disassociate(struct net_device *dev, u16 reason) struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); struct ieee80211_if_sta *ifsta = &sdata->u.sta; - printk(KERN_DEBUG "%s: disassociate(reason=%d)\n", + printk(KERN_DEBUG "%s: disassociating by local choice (reason=%d)\n", dev->name, reason); if (sdata->vif.type != IEEE80211_IF_TYPE_STA) @@ -4356,12 +4437,10 @@ void ieee80211_notify_mac(struct ieee80211_hw *hw, case IEEE80211_NOTIFY_RE_ASSOC: rcu_read_lock(); list_for_each_entry_rcu(sdata, &local->interfaces, list) { + if (sdata->vif.type != IEEE80211_IF_TYPE_STA) + continue; - if (sdata->vif.type == IEEE80211_IF_TYPE_STA) { - ieee80211_sta_req_auth(sdata->dev, - &sdata->u.sta); - } - + ieee80211_sta_req_auth(sdata->dev, &sdata->u.sta); } rcu_read_unlock(); break; diff --git a/net/mac80211/rate.c b/net/mac80211/rate.c index 841df93807fc..0388c090dfe9 100644 --- a/net/mac80211/rate.c +++ b/net/mac80211/rate.c @@ -176,20 +176,24 @@ void rate_control_get_rate(struct net_device *dev, rcu_read_lock(); sta = sta_info_get(local, hdr->addr1); - memset(sel, 0, sizeof(struct rate_selection)); + sel->rate_idx = -1; + sel->nonerp_idx = -1; + sel->probe_idx = -1; ref->ops->get_rate(ref->priv, dev, sband, skb, sel); + BUG_ON(sel->rate_idx < 0); + /* Select a non-ERP backup rate. */ - if (!sel->nonerp) { + if (sel->nonerp_idx < 0) { for (i = 0; i < sband->n_bitrates; i++) { struct ieee80211_rate *rate = &sband->bitrates[i]; - if (sel->rate->bitrate < rate->bitrate) + if (sband->bitrates[sel->rate_idx].bitrate < rate->bitrate) break; if (rate_supported(sta, sband->band, i) && !(rate->flags & IEEE80211_RATE_ERP_G)) - sel->nonerp = rate; + sel->nonerp_idx = i; } } diff --git a/net/mac80211/rate.h b/net/mac80211/rate.h index 5b45f33cb766..ede7ab56f65b 100644 --- a/net/mac80211/rate.h +++ b/net/mac80211/rate.h @@ -19,22 +19,22 @@ #include "ieee80211_i.h" #include "sta_info.h" -/* TODO: kdoc */ +/** + * struct rate_selection - rate selection for rate control algos + * @rate: selected transmission rate index + * @nonerp: Non-ERP rate to use instead if ERP cannot be used + * @probe: rate for probing (or -1) + * + */ struct rate_selection { - /* Selected transmission rate */ - struct ieee80211_rate *rate; - /* Non-ERP rate to use if mac80211 decides it cannot use an ERP rate */ - struct ieee80211_rate *nonerp; - /* probe with this rate, or NULL for no probing */ - struct ieee80211_rate *probe; + s8 rate_idx, nonerp_idx, probe_idx; }; struct rate_control_ops { struct module *module; const char *name; void (*tx_status)(void *priv, struct net_device *dev, - struct sk_buff *skb, - struct ieee80211_tx_status *status); + struct sk_buff *skb); void (*get_rate)(void *priv, struct net_device *dev, struct ieee80211_supported_band *band, struct sk_buff *skb, @@ -76,13 +76,12 @@ struct rate_control_ref *rate_control_get(struct rate_control_ref *ref); void rate_control_put(struct rate_control_ref *ref); static inline void rate_control_tx_status(struct net_device *dev, - struct sk_buff *skb, - struct ieee80211_tx_status *status) + struct sk_buff *skb) { struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); struct rate_control_ref *ref = local->rate_ctrl; - ref->ops->tx_status(ref->priv, dev, skb, status); + ref->ops->tx_status(ref->priv, dev, skb); } @@ -138,7 +137,7 @@ static inline int rate_supported(struct sta_info *sta, return (sta == NULL || sta->supp_rates[band] & BIT(index)); } -static inline int +static inline s8 rate_lowest_index(struct ieee80211_local *local, struct ieee80211_supported_band *sband, struct sta_info *sta) @@ -155,14 +154,6 @@ rate_lowest_index(struct ieee80211_local *local, return 0; } -static inline struct ieee80211_rate * -rate_lowest(struct ieee80211_local *local, - struct ieee80211_supported_band *sband, - struct sta_info *sta) -{ - return &sband->bitrates[rate_lowest_index(local, sband, sta)]; -} - /* functions for rate control related to a device */ int ieee80211_init_rate_ctrl_alg(struct ieee80211_local *local, @@ -171,9 +162,7 @@ void rate_control_deinitialize(struct ieee80211_local *local); /* Rate control algorithms */ -#if defined(RC80211_PID_COMPILE) || \ - (defined(CONFIG_MAC80211_RC_PID) && \ - !defined(CONFIG_MAC80211_RC_PID_MODULE)) +#ifdef CONFIG_MAC80211_RC_PID extern int rc80211_pid_init(void); extern void rc80211_pid_exit(void); #else diff --git a/net/mac80211/rc80211_pid.h b/net/mac80211/rc80211_pid.h index 4ea7b97d1af1..0a9135b974b5 100644 --- a/net/mac80211/rc80211_pid.h +++ b/net/mac80211/rc80211_pid.h @@ -61,7 +61,7 @@ enum rc_pid_event_type { union rc_pid_event_data { /* RC_PID_EVENT_TX_STATUS */ struct { - struct ieee80211_tx_status tx_status; + struct ieee80211_tx_info tx_status; }; /* RC_PID_EVENT_TYPE_RATE_CHANGE */ /* RC_PID_EVENT_TYPE_TX_RATE */ @@ -156,7 +156,7 @@ struct rc_pid_debugfs_entries { }; void rate_control_pid_event_tx_status(struct rc_pid_event_buffer *buf, - struct ieee80211_tx_status *stat); + struct ieee80211_tx_info *stat); void rate_control_pid_event_rate_change(struct rc_pid_event_buffer *buf, int index, int rate); diff --git a/net/mac80211/rc80211_pid_algo.c b/net/mac80211/rc80211_pid_algo.c index bcd27c1d7594..a914ba73ccf5 100644 --- a/net/mac80211/rc80211_pid_algo.c +++ b/net/mac80211/rc80211_pid_algo.c @@ -237,8 +237,7 @@ static void rate_control_pid_sample(struct rc_pid_info *pinfo, } static void rate_control_pid_tx_status(void *priv, struct net_device *dev, - struct sk_buff *skb, - struct ieee80211_tx_status *status) + struct sk_buff *skb) { struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; @@ -248,6 +247,7 @@ static void rate_control_pid_tx_status(void *priv, struct net_device *dev, struct rc_pid_sta_info *spinfo; unsigned long period; struct ieee80211_supported_band *sband; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); rcu_read_lock(); @@ -259,35 +259,35 @@ static void rate_control_pid_tx_status(void *priv, struct net_device *dev, /* Don't update the state if we're not controlling the rate. */ sdata = sta->sdata; - if (sdata->bss && sdata->bss->force_unicast_rateidx > -1) { - sta->txrate_idx = sdata->bss->max_ratectrl_rateidx; + if (sdata->force_unicast_rateidx > -1) { + sta->txrate_idx = sdata->max_ratectrl_rateidx; goto unlock; } /* Ignore all frames that were sent with a different rate than the rate * we currently advise mac80211 to use. */ - if (status->control.tx_rate != &sband->bitrates[sta->txrate_idx]) + if (info->tx_rate_idx != sta->txrate_idx) goto unlock; spinfo = sta->rate_ctrl_priv; spinfo->tx_num_xmit++; #ifdef CONFIG_MAC80211_DEBUGFS - rate_control_pid_event_tx_status(&spinfo->events, status); + rate_control_pid_event_tx_status(&spinfo->events, info); #endif /* We count frames that totally failed to be transmitted as two bad * frames, those that made it out but had some retries as one good and * one bad frame. */ - if (status->excessive_retries) { + if (info->status.excessive_retries) { spinfo->tx_num_failed += 2; spinfo->tx_num_xmit++; - } else if (status->retry_count) { + } else if (info->status.retry_count) { spinfo->tx_num_failed++; spinfo->tx_num_xmit++; } - if (status->excessive_retries) { + if (info->status.excessive_retries) { sta->tx_retry_failed++; sta->tx_num_consecutive_failures++; sta->tx_num_mpdu_fail++; @@ -295,8 +295,8 @@ static void rate_control_pid_tx_status(void *priv, struct net_device *dev, sta->tx_num_consecutive_failures = 0; sta->tx_num_mpdu_ok++; } - sta->tx_retry_count += status->retry_count; - sta->tx_num_mpdu_fail += status->retry_count; + sta->tx_retry_count += info->status.retry_count; + sta->tx_num_mpdu_fail += info->status.retry_count; /* Update PID controller state. */ period = (HZ * pinfo->sampling_period + 500) / 1000; @@ -330,15 +330,15 @@ static void rate_control_pid_get_rate(void *priv, struct net_device *dev, fc = le16_to_cpu(hdr->frame_control); if ((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA || is_multicast_ether_addr(hdr->addr1) || !sta) { - sel->rate = rate_lowest(local, sband, sta); + sel->rate_idx = rate_lowest_index(local, sband, sta); rcu_read_unlock(); return; } /* If a forced rate is in effect, select it. */ sdata = IEEE80211_DEV_TO_SUB_IF(dev); - if (sdata->bss && sdata->bss->force_unicast_rateidx > -1) - sta->txrate_idx = sdata->bss->force_unicast_rateidx; + if (sdata->force_unicast_rateidx > -1) + sta->txrate_idx = sdata->force_unicast_rateidx; rateidx = sta->txrate_idx; @@ -349,7 +349,7 @@ static void rate_control_pid_get_rate(void *priv, struct net_device *dev, rcu_read_unlock(); - sel->rate = &sband->bitrates[rateidx]; + sel->rate_idx = rateidx; #ifdef CONFIG_MAC80211_DEBUGFS rate_control_pid_event_tx_rate( @@ -535,11 +535,6 @@ static struct rate_control_ops mac80211_rcpid = { #endif }; -MODULE_DESCRIPTION("PID controller based rate control algorithm"); -MODULE_AUTHOR("Stefano Brivio"); -MODULE_AUTHOR("Mattias Nissler"); -MODULE_LICENSE("GPL"); - int __init rc80211_pid_init(void) { return ieee80211_rate_control_register(&mac80211_rcpid); @@ -549,8 +544,3 @@ void rc80211_pid_exit(void) { ieee80211_rate_control_unregister(&mac80211_rcpid); } - -#ifdef CONFIG_MAC80211_RC_PID_MODULE -module_init(rc80211_pid_init); -module_exit(rc80211_pid_exit); -#endif diff --git a/net/mac80211/rc80211_pid_debugfs.c b/net/mac80211/rc80211_pid_debugfs.c index ff5c380f3c13..8121d3bc6835 100644 --- a/net/mac80211/rc80211_pid_debugfs.c +++ b/net/mac80211/rc80211_pid_debugfs.c @@ -39,11 +39,11 @@ static void rate_control_pid_event(struct rc_pid_event_buffer *buf, } void rate_control_pid_event_tx_status(struct rc_pid_event_buffer *buf, - struct ieee80211_tx_status *stat) + struct ieee80211_tx_info *stat) { union rc_pid_event_data evd; - memcpy(&evd.tx_status, stat, sizeof(struct ieee80211_tx_status)); + memcpy(&evd.tx_status, stat, sizeof(struct ieee80211_tx_info)); rate_control_pid_event(buf, RC_PID_EVENT_TYPE_TX_STATUS, &evd); } @@ -167,8 +167,8 @@ static ssize_t rate_control_pid_events_read(struct file *file, char __user *buf, switch (ev->type) { case RC_PID_EVENT_TYPE_TX_STATUS: p += snprintf(pb + p, length - p, "tx_status %u %u", - ev->data.tx_status.excessive_retries, - ev->data.tx_status.retry_count); + ev->data.tx_status.status.excessive_retries, + ev->data.tx_status.status.retry_count); break; case RC_PID_EVENT_TYPE_RATE_CHANGE: p += snprintf(pb + p, length - p, "rate_change %d %d", diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 0941e5d6a522..6d9ae67c27ca 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -61,22 +61,147 @@ static inline int should_drop_frame(struct ieee80211_rx_status *status, int present_fcs_len, int radiotap_len) { - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; if (status->flag & (RX_FLAG_FAILED_FCS_CRC | RX_FLAG_FAILED_PLCP_CRC)) return 1; if (unlikely(skb->len < 16 + present_fcs_len + radiotap_len)) return 1; - if (((hdr->frame_control & cpu_to_le16(IEEE80211_FCTL_FTYPE)) == - cpu_to_le16(IEEE80211_FTYPE_CTL)) && - ((hdr->frame_control & cpu_to_le16(IEEE80211_FCTL_STYPE)) != - cpu_to_le16(IEEE80211_STYPE_PSPOLL)) && - ((hdr->frame_control & cpu_to_le16(IEEE80211_FCTL_STYPE)) != - cpu_to_le16(IEEE80211_STYPE_BACK_REQ))) + if (ieee80211_is_ctl(hdr->frame_control) && + !ieee80211_is_pspoll(hdr->frame_control) && + !ieee80211_is_back_req(hdr->frame_control)) return 1; return 0; } +static int +ieee80211_rx_radiotap_len(struct ieee80211_local *local, + struct ieee80211_rx_status *status) +{ + int len; + + /* always present fields */ + len = sizeof(struct ieee80211_radiotap_header) + 9; + + if (status->flag & RX_FLAG_TSFT) + len += 8; + if (local->hw.flags & IEEE80211_HW_SIGNAL_DB || + local->hw.flags & IEEE80211_HW_SIGNAL_DBM) + len += 1; + if (local->hw.flags & IEEE80211_HW_NOISE_DBM) + len += 1; + + if (len & 1) /* padding for RX_FLAGS if necessary */ + len++; + + /* make sure radiotap starts at a naturally aligned address */ + if (len % 8) + len = roundup(len, 8); + + return len; +} + +/** + * ieee80211_add_rx_radiotap_header - add radiotap header + * + * add a radiotap header containing all the fields which the hardware provided. + */ +static void +ieee80211_add_rx_radiotap_header(struct ieee80211_local *local, + struct sk_buff *skb, + struct ieee80211_rx_status *status, + struct ieee80211_rate *rate, + int rtap_len) +{ + struct ieee80211_radiotap_header *rthdr; + unsigned char *pos; + + rthdr = (struct ieee80211_radiotap_header *)skb_push(skb, rtap_len); + memset(rthdr, 0, rtap_len); + + /* radiotap header, set always present flags */ + rthdr->it_present = + cpu_to_le32((1 << IEEE80211_RADIOTAP_FLAGS) | + (1 << IEEE80211_RADIOTAP_RATE) | + (1 << IEEE80211_RADIOTAP_CHANNEL) | + (1 << IEEE80211_RADIOTAP_ANTENNA) | + (1 << IEEE80211_RADIOTAP_RX_FLAGS)); + rthdr->it_len = cpu_to_le16(rtap_len); + + pos = (unsigned char *)(rthdr+1); + + /* the order of the following fields is important */ + + /* IEEE80211_RADIOTAP_TSFT */ + if (status->flag & RX_FLAG_TSFT) { + *(__le64 *)pos = cpu_to_le64(status->mactime); + rthdr->it_present |= + cpu_to_le32(1 << IEEE80211_RADIOTAP_TSFT); + pos += 8; + } + + /* IEEE80211_RADIOTAP_FLAGS */ + if (local->hw.flags & IEEE80211_HW_RX_INCLUDES_FCS) + *pos |= IEEE80211_RADIOTAP_F_FCS; + pos++; + + /* IEEE80211_RADIOTAP_RATE */ + *pos = rate->bitrate / 5; + pos++; + + /* IEEE80211_RADIOTAP_CHANNEL */ + *(__le16 *)pos = cpu_to_le16(status->freq); + pos += 2; + if (status->band == IEEE80211_BAND_5GHZ) + *(__le16 *)pos = cpu_to_le16(IEEE80211_CHAN_OFDM | + IEEE80211_CHAN_5GHZ); + else + *(__le16 *)pos = cpu_to_le16(IEEE80211_CHAN_DYN | + IEEE80211_CHAN_2GHZ); + pos += 2; + + /* IEEE80211_RADIOTAP_DBM_ANTSIGNAL */ + if (local->hw.flags & IEEE80211_HW_SIGNAL_DBM) { + *pos = status->signal; + rthdr->it_present |= + cpu_to_le32(1 << IEEE80211_RADIOTAP_DBM_ANTSIGNAL); + pos++; + } + + /* IEEE80211_RADIOTAP_DBM_ANTNOISE */ + if (local->hw.flags & IEEE80211_HW_NOISE_DBM) { + *pos = status->noise; + rthdr->it_present |= + cpu_to_le32(1 << IEEE80211_RADIOTAP_DBM_ANTNOISE); + pos++; + } + + /* IEEE80211_RADIOTAP_LOCK_QUALITY is missing */ + + /* IEEE80211_RADIOTAP_ANTENNA */ + *pos = status->antenna; + pos++; + + /* IEEE80211_RADIOTAP_DB_ANTSIGNAL */ + if (local->hw.flags & IEEE80211_HW_SIGNAL_DB) { + *pos = status->signal; + rthdr->it_present |= + cpu_to_le32(1 << IEEE80211_RADIOTAP_DB_ANTSIGNAL); + pos++; + } + + /* IEEE80211_RADIOTAP_DB_ANTNOISE is not used */ + + /* IEEE80211_RADIOTAP_RX_FLAGS */ + /* ensure 2 byte alignment for the 2 byte field as required */ + if ((pos - (unsigned char *)rthdr) & 1) + pos++; + /* FIXME: when radiotap gets a 'bad PLCP' flag use it here */ + if (status->flag & (RX_FLAG_FAILED_FCS_CRC | RX_FLAG_FAILED_PLCP_CRC)) + *(__le16 *)pos |= cpu_to_le16(IEEE80211_RADIOTAP_F_RX_BADFCS); + pos += 2; +} + /* * This function copies a received frame to all monitor interfaces and * returns a cleaned-up SKB that no longer includes the FCS nor the @@ -89,17 +214,6 @@ ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb, { struct ieee80211_sub_if_data *sdata; int needed_headroom = 0; - struct ieee80211_radiotap_header *rthdr; - __le64 *rttsft = NULL; - struct ieee80211_rtap_fixed_data { - u8 flags; - u8 rate; - __le16 chan_freq; - __le16 chan_flags; - u8 antsignal; - u8 padding_for_rxflags; - __le16 rx_flags; - } __attribute__ ((packed)) *rtfixed; struct sk_buff *skb, *skb2; struct net_device *prev_dev = NULL; int present_fcs_len = 0; @@ -116,8 +230,8 @@ ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb, if (status->flag & RX_FLAG_RADIOTAP) rtap_len = ieee80211_get_radiotap_len(origskb->data); else - /* room for radiotap header, always present fields and TSFT */ - needed_headroom = sizeof(*rthdr) + sizeof(*rtfixed) + 8; + /* room for the radiotap header based on driver features */ + needed_headroom = ieee80211_rx_radiotap_len(local, status); if (local->hw.flags & IEEE80211_HW_RX_INCLUDES_FCS) present_fcs_len = FCS_LEN; @@ -163,55 +277,9 @@ ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb, } /* if necessary, prepend radiotap information */ - if (!(status->flag & RX_FLAG_RADIOTAP)) { - rtfixed = (void *) skb_push(skb, sizeof(*rtfixed)); - rtap_len = sizeof(*rthdr) + sizeof(*rtfixed); - if (status->flag & RX_FLAG_TSFT) { - rttsft = (void *) skb_push(skb, sizeof(*rttsft)); - rtap_len += 8; - } - rthdr = (void *) skb_push(skb, sizeof(*rthdr)); - memset(rthdr, 0, sizeof(*rthdr)); - memset(rtfixed, 0, sizeof(*rtfixed)); - rthdr->it_present = - cpu_to_le32((1 << IEEE80211_RADIOTAP_FLAGS) | - (1 << IEEE80211_RADIOTAP_RATE) | - (1 << IEEE80211_RADIOTAP_CHANNEL) | - (1 << IEEE80211_RADIOTAP_DB_ANTSIGNAL) | - (1 << IEEE80211_RADIOTAP_RX_FLAGS)); - rtfixed->flags = 0; - if (local->hw.flags & IEEE80211_HW_RX_INCLUDES_FCS) - rtfixed->flags |= IEEE80211_RADIOTAP_F_FCS; - - if (rttsft) { - *rttsft = cpu_to_le64(status->mactime); - rthdr->it_present |= - cpu_to_le32(1 << IEEE80211_RADIOTAP_TSFT); - } - - /* FIXME: when radiotap gets a 'bad PLCP' flag use it here */ - rtfixed->rx_flags = 0; - if (status->flag & - (RX_FLAG_FAILED_FCS_CRC | RX_FLAG_FAILED_PLCP_CRC)) - rtfixed->rx_flags |= - cpu_to_le16(IEEE80211_RADIOTAP_F_RX_BADFCS); - - rtfixed->rate = rate->bitrate / 5; - - rtfixed->chan_freq = cpu_to_le16(status->freq); - - if (status->band == IEEE80211_BAND_5GHZ) - rtfixed->chan_flags = - cpu_to_le16(IEEE80211_CHAN_OFDM | - IEEE80211_CHAN_5GHZ); - else - rtfixed->chan_flags = - cpu_to_le16(IEEE80211_CHAN_DYN | - IEEE80211_CHAN_2GHZ); - - rtfixed->antsignal = status->ssi; - rthdr->it_len = cpu_to_le16(rtap_len); - } + if (!(status->flag & RX_FLAG_RADIOTAP)) + ieee80211_add_rx_radiotap_header(local, skb, status, rate, + needed_headroom); skb_reset_mac_header(skb); skb->ip_summed = CHECKSUM_UNNECESSARY; @@ -253,33 +321,33 @@ ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb, static void ieee80211_parse_qos(struct ieee80211_rx_data *rx) { - u8 *data = rx->skb->data; + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data; int tid; /* does the frame have a qos control field? */ - if (WLAN_FC_IS_QOS_DATA(rx->fc)) { - u8 *qc = data + ieee80211_get_hdrlen(rx->fc) - QOS_CONTROL_LEN; + if (ieee80211_is_data_qos(hdr->frame_control)) { + u8 *qc = ieee80211_get_qos_ctl(hdr); /* frame has qos control */ - tid = qc[0] & QOS_CONTROL_TID_MASK; - if (qc[0] & IEEE80211_QOS_CONTROL_A_MSDU_PRESENT) + tid = *qc & IEEE80211_QOS_CTL_TID_MASK; + if (*qc & IEEE80211_QOS_CONTROL_A_MSDU_PRESENT) rx->flags |= IEEE80211_RX_AMSDU; else rx->flags &= ~IEEE80211_RX_AMSDU; } else { - if (unlikely((rx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT)) { - /* Separate TID for management frames */ - tid = NUM_RX_DATA_QUEUES - 1; - } else { - /* no qos control present */ - tid = 0; /* 802.1d - Best Effort */ - } + /* + * IEEE 802.11-2007, 7.1.3.4.1 ("Sequence Number field"): + * + * Sequence numbers for management frames, QoS data + * frames with a broadcast/multicast address in the + * Address 1 field, and all non-QoS data frames sent + * by QoS STAs are assigned using an additional single + * modulo-4096 counter, [...] + * + * We also use that counter for non-QoS STAs. + */ + tid = NUM_RX_DATA_QUEUES - 1; } - I802_DEBUG_INC(rx->local->wme_rx_queue[tid]); - /* only a debug counter, sta might not be assigned properly yet */ - if (rx->sta) - I802_DEBUG_INC(rx->sta->wme_rx_queue[tid]); - rx->queue = tid; /* Set skb->priority to 1d tag if highest order bit of TID is not set. * For now, set skb->priority to 0 for other cases. */ @@ -289,9 +357,10 @@ static void ieee80211_parse_qos(struct ieee80211_rx_data *rx) static void ieee80211_verify_ip_alignment(struct ieee80211_rx_data *rx) { #ifdef CONFIG_MAC80211_DEBUG_PACKET_ALIGNMENT + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data; int hdrlen; - if (!WLAN_FC_DATA_PRESENT(rx->fc)) + if (!ieee80211_is_data_present(hdr->frame_control)) return; /* @@ -313,7 +382,7 @@ static void ieee80211_verify_ip_alignment(struct ieee80211_rx_data *rx) * header and the payload is not supported, the driver is required * to move the 802.11 header further back in that case. */ - hdrlen = ieee80211_get_hdrlen(rx->fc); + hdrlen = ieee80211_hdrlen(hdr->frame_control); if (rx->flags & IEEE80211_RX_AMSDU) hdrlen += ETH_HLEN; WARN_ON_ONCE(((unsigned long)(rx->skb->data + hdrlen)) & 3); @@ -321,51 +390,9 @@ static void ieee80211_verify_ip_alignment(struct ieee80211_rx_data *rx) } -static u32 ieee80211_rx_load_stats(struct ieee80211_local *local, - struct sk_buff *skb, - struct ieee80211_rx_status *status, - struct ieee80211_rate *rate) -{ - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; - u32 load = 0, hdrtime; - - /* Estimate total channel use caused by this frame */ - - /* 1 bit at 1 Mbit/s takes 1 usec; in channel_use values, - * 1 usec = 1/8 * (1080 / 10) = 13.5 */ - - if (status->band == IEEE80211_BAND_5GHZ || - (status->band == IEEE80211_BAND_5GHZ && - rate->flags & IEEE80211_RATE_ERP_G)) - hdrtime = CHAN_UTIL_HDR_SHORT; - else - hdrtime = CHAN_UTIL_HDR_LONG; - - load = hdrtime; - if (!is_multicast_ether_addr(hdr->addr1)) - load += hdrtime; - - /* TODO: optimise again */ - load += skb->len * CHAN_UTIL_RATE_LCM / rate->bitrate; - - /* Divide channel_use by 8 to avoid wrapping around the counter */ - load >>= CHAN_UTIL_SHIFT; - - return load; -} - /* rx handlers */ -static ieee80211_rx_result -ieee80211_rx_h_if_stats(struct ieee80211_rx_data *rx) -{ - if (rx->sta) - rx->sta->channel_use_raw += rx->load; - rx->sdata->channel_use_raw += rx->load; - return RX_CONTINUE; -} - -static ieee80211_rx_result +static ieee80211_rx_result debug_noinline ieee80211_rx_h_passive_scan(struct ieee80211_rx_data *rx) { struct ieee80211_local *local = rx->local; @@ -394,14 +421,11 @@ ieee80211_rx_h_passive_scan(struct ieee80211_rx_data *rx) static ieee80211_rx_result ieee80211_rx_mesh_check(struct ieee80211_rx_data *rx) { - int hdrlen = ieee80211_get_hdrlen(rx->fc); - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) rx->skb->data; + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data; + unsigned int hdrlen = ieee80211_hdrlen(hdr->frame_control); -#define msh_h_get(h, l) ((struct ieee80211s_hdr *) ((u8 *)h + l)) - - if ((rx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA) { - if (!((rx->fc & IEEE80211_FCTL_FROMDS) && - (rx->fc & IEEE80211_FCTL_TODS))) + if (ieee80211_is_data(hdr->frame_control)) { + if (!ieee80211_has_a4(hdr->frame_control)) return RX_DROP_MONITOR; if (memcmp(hdr->addr4, rx->dev->dev_addr, ETH_ALEN) == 0) return RX_DROP_MONITOR; @@ -414,27 +438,30 @@ ieee80211_rx_mesh_check(struct ieee80211_rx_data *rx) if (!rx->sta || sta_plink_state(rx->sta) != PLINK_ESTAB) { struct ieee80211_mgmt *mgmt; - if ((rx->fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_MGMT) + if (!ieee80211_is_mgmt(hdr->frame_control)) return RX_DROP_MONITOR; - switch (rx->fc & IEEE80211_FCTL_STYPE) { - case IEEE80211_STYPE_ACTION: + if (ieee80211_is_action(hdr->frame_control)) { mgmt = (struct ieee80211_mgmt *)hdr; if (mgmt->u.action.category != PLINK_CATEGORY) return RX_DROP_MONITOR; - /* fall through on else */ - case IEEE80211_STYPE_PROBE_REQ: - case IEEE80211_STYPE_PROBE_RESP: - case IEEE80211_STYPE_BEACON: return RX_CONTINUE; - break; - default: - return RX_DROP_MONITOR; } - } else if ((rx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA && - is_multicast_ether_addr(hdr->addr1) && - mesh_rmc_check(hdr->addr4, msh_h_get(hdr, hdrlen), rx->dev)) + if (ieee80211_is_probe_req(hdr->frame_control) || + ieee80211_is_probe_resp(hdr->frame_control) || + ieee80211_is_beacon(hdr->frame_control)) + return RX_CONTINUE; + + return RX_DROP_MONITOR; + + } + +#define msh_h_get(h, l) ((struct ieee80211s_hdr *) ((u8 *)h + l)) + + if (ieee80211_is_data(hdr->frame_control) && + is_multicast_ether_addr(hdr->addr1) && + mesh_rmc_check(hdr->addr4, msh_h_get(hdr, hdrlen), rx->dev)) return RX_DROP_MONITOR; #undef msh_h_get @@ -442,16 +469,14 @@ ieee80211_rx_mesh_check(struct ieee80211_rx_data *rx) } -static ieee80211_rx_result +static ieee80211_rx_result debug_noinline ieee80211_rx_h_check(struct ieee80211_rx_data *rx) { - struct ieee80211_hdr *hdr; - - hdr = (struct ieee80211_hdr *) rx->skb->data; + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data; /* Drop duplicate 802.11 retransmissions (IEEE 802.11 Chap. 9.2.9) */ if (rx->sta && !is_multicast_ether_addr(hdr->addr1)) { - if (unlikely(rx->fc & IEEE80211_FCTL_RETRY && + if (unlikely(ieee80211_has_retry(hdr->frame_control) && rx->sta->last_seq_ctrl[rx->queue] == hdr->seq_ctrl)) { if (rx->flags & IEEE80211_RX_RA_MATCH) { @@ -480,15 +505,14 @@ ieee80211_rx_h_check(struct ieee80211_rx_data *rx) if (ieee80211_vif_is_mesh(&rx->sdata->vif)) return ieee80211_rx_mesh_check(rx); - if (unlikely(((rx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA || - ((rx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_CTL && - (rx->fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_PSPOLL)) && + if (unlikely((ieee80211_is_data(hdr->frame_control) || + ieee80211_is_pspoll(hdr->frame_control)) && rx->sdata->vif.type != IEEE80211_IF_TYPE_IBSS && - (!rx->sta || !(rx->sta->flags & WLAN_STA_ASSOC)))) { - if ((!(rx->fc & IEEE80211_FCTL_FROMDS) && - !(rx->fc & IEEE80211_FCTL_TODS) && - (rx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA) - || !(rx->flags & IEEE80211_RX_RA_MATCH)) { + (!rx->sta || !test_sta_flags(rx->sta, WLAN_STA_ASSOC)))) { + if ((!ieee80211_has_fromds(hdr->frame_control) && + !ieee80211_has_tods(hdr->frame_control) && + ieee80211_is_data(hdr->frame_control)) || + !(rx->flags & IEEE80211_RX_RA_MATCH)) { /* Drop IBSS frames and frames for other hosts * silently. */ return RX_DROP_MONITOR; @@ -501,10 +525,10 @@ ieee80211_rx_h_check(struct ieee80211_rx_data *rx) } -static ieee80211_rx_result +static ieee80211_rx_result debug_noinline ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx) { - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) rx->skb->data; + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data; int keyidx; int hdrlen; ieee80211_rx_result result = RX_DROP_UNUSABLE; @@ -536,7 +560,7 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx) * possible. */ - if (!(rx->fc & IEEE80211_FCTL_PROTECTED)) + if (!ieee80211_has_protected(hdr->frame_control)) return RX_CONTINUE; /* @@ -565,7 +589,7 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx) (rx->status->flag & RX_FLAG_IV_STRIPPED)) return RX_CONTINUE; - hdrlen = ieee80211_get_hdrlen(rx->fc); + hdrlen = ieee80211_hdrlen(hdr->frame_control); if (rx->skb->len < 8 + hdrlen) return RX_DROP_UNUSABLE; /* TODO: count this? */ @@ -592,17 +616,12 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx) rx->key->tx_rx_count++; /* TODO: add threshold stuff again */ } else { -#ifdef CONFIG_MAC80211_DEBUG - if (net_ratelimit()) - printk(KERN_DEBUG "%s: RX protected frame," - " but have no key\n", rx->dev->name); -#endif /* CONFIG_MAC80211_DEBUG */ return RX_DROP_MONITOR; } /* Check for weak IVs if possible */ if (rx->sta && rx->key->conf.alg == ALG_WEP && - ((rx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA) && + ieee80211_is_data(hdr->frame_control) && (!(rx->status->flag & RX_FLAG_IV_STRIPPED) || !(rx->status->flag & RX_FLAG_DECRYPTED)) && ieee80211_wep_is_weak_iv(rx->skb, rx->key)) @@ -633,10 +652,8 @@ static void ap_sta_ps_start(struct net_device *dev, struct sta_info *sta) sdata = sta->sdata; - if (sdata->bss) - atomic_inc(&sdata->bss->num_sta_ps); - sta->flags |= WLAN_STA_PS; - sta->flags &= ~WLAN_STA_PSPOLL; + atomic_inc(&sdata->bss->num_sta_ps); + set_and_clear_sta_flags(sta, WLAN_STA_PS, WLAN_STA_PSPOLL); #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG printk(KERN_DEBUG "%s: STA %s aid %d enters power save mode\n", dev->name, print_mac(mac, sta->addr), sta->aid); @@ -649,15 +666,14 @@ static int ap_sta_ps_end(struct net_device *dev, struct sta_info *sta) struct sk_buff *skb; int sent = 0; struct ieee80211_sub_if_data *sdata; - struct ieee80211_tx_packet_data *pkt_data; + struct ieee80211_tx_info *info; DECLARE_MAC_BUF(mac); sdata = sta->sdata; - if (sdata->bss) - atomic_dec(&sdata->bss->num_sta_ps); + atomic_dec(&sdata->bss->num_sta_ps); - sta->flags &= ~(WLAN_STA_PS | WLAN_STA_PSPOLL); + clear_sta_flags(sta, WLAN_STA_PS | WLAN_STA_PSPOLL); if (!skb_queue_empty(&sta->ps_tx_buf)) sta_info_clear_tim_bit(sta); @@ -669,13 +685,13 @@ static int ap_sta_ps_end(struct net_device *dev, struct sta_info *sta) /* Send all buffered frames to the station */ while ((skb = skb_dequeue(&sta->tx_filtered)) != NULL) { - pkt_data = (struct ieee80211_tx_packet_data *) skb->cb; + info = IEEE80211_SKB_CB(skb); sent++; - pkt_data->flags |= IEEE80211_TXPD_REQUEUE; + info->flags |= IEEE80211_TX_CTL_REQUEUE; dev_queue_xmit(skb); } while ((skb = skb_dequeue(&sta->ps_tx_buf)) != NULL) { - pkt_data = (struct ieee80211_tx_packet_data *) skb->cb; + info = IEEE80211_SKB_CB(skb); local->total_ps_buffered--; sent++; #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG @@ -683,19 +699,19 @@ static int ap_sta_ps_end(struct net_device *dev, struct sta_info *sta) "since STA not sleeping anymore\n", dev->name, print_mac(mac, sta->addr), sta->aid); #endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */ - pkt_data->flags |= IEEE80211_TXPD_REQUEUE; + info->flags |= IEEE80211_TX_CTL_REQUEUE; dev_queue_xmit(skb); } return sent; } -static ieee80211_rx_result +static ieee80211_rx_result debug_noinline ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx) { struct sta_info *sta = rx->sta; struct net_device *dev = rx->dev; - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) rx->skb->data; + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data; if (!sta) return RX_CONTINUE; @@ -725,24 +741,26 @@ ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx) sta->rx_fragments++; sta->rx_bytes += rx->skb->len; - sta->last_rssi = rx->status->ssi; sta->last_signal = rx->status->signal; + sta->last_qual = rx->status->qual; sta->last_noise = rx->status->noise; - if (!(rx->fc & IEEE80211_FCTL_MOREFRAGS)) { + if (!ieee80211_has_morefrags(hdr->frame_control) && + (rx->sdata->vif.type == IEEE80211_IF_TYPE_AP || + rx->sdata->vif.type == IEEE80211_IF_TYPE_VLAN)) { /* Change STA power saving mode only in the end of a frame * exchange sequence */ - if ((sta->flags & WLAN_STA_PS) && !(rx->fc & IEEE80211_FCTL_PM)) + if (test_sta_flags(sta, WLAN_STA_PS) && + !ieee80211_has_pm(hdr->frame_control)) rx->sent_ps_buffered += ap_sta_ps_end(dev, sta); - else if (!(sta->flags & WLAN_STA_PS) && - (rx->fc & IEEE80211_FCTL_PM)) + else if (!test_sta_flags(sta, WLAN_STA_PS) && + ieee80211_has_pm(hdr->frame_control)) ap_sta_ps_start(dev, sta); } /* Drop data::nullfunc frames silently, since they are used only to * control station power saving mode. */ - if ((rx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA && - (rx->fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_NULLFUNC) { + if (ieee80211_is_nullfunc(hdr->frame_control)) { I802_DEBUG_INC(rx->local->rx_handlers_drop_nullfunc); /* Update counter and free packet here to avoid counting this * as a dropped packed. */ @@ -768,7 +786,7 @@ ieee80211_reassemble_add(struct ieee80211_sub_if_data *sdata, sdata->fragment_next = 0; if (!skb_queue_empty(&entry->skb_list)) { -#ifdef CONFIG_MAC80211_DEBUG +#ifdef CONFIG_MAC80211_VERBOSE_DEBUG struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) entry->skb_list.next->data; DECLARE_MAC_BUF(mac); @@ -780,7 +798,7 @@ ieee80211_reassemble_add(struct ieee80211_sub_if_data *sdata, jiffies - entry->first_frag_time, entry->seq, entry->last_frag, print_mac(mac, hdr->addr1), print_mac(mac2, hdr->addr2)); -#endif /* CONFIG_MAC80211_DEBUG */ +#endif __skb_queue_purge(&entry->skb_list); } @@ -837,7 +855,7 @@ ieee80211_reassemble_find(struct ieee80211_sub_if_data *sdata, return NULL; } -static ieee80211_rx_result +static ieee80211_rx_result debug_noinline ieee80211_rx_h_defragment(struct ieee80211_rx_data *rx) { struct ieee80211_hdr *hdr; @@ -901,18 +919,8 @@ ieee80211_rx_h_defragment(struct ieee80211_rx_data *rx) break; } rpn = rx->key->u.ccmp.rx_pn[rx->queue]; - if (memcmp(pn, rpn, CCMP_PN_LEN) != 0) { - if (net_ratelimit()) - printk(KERN_DEBUG "%s: defrag: CCMP PN not " - "sequential A2=%s" - " PN=%02x%02x%02x%02x%02x%02x " - "(expected %02x%02x%02x%02x%02x%02x)\n", - rx->dev->name, print_mac(mac, hdr->addr2), - rpn[0], rpn[1], rpn[2], rpn[3], rpn[4], - rpn[5], pn[0], pn[1], pn[2], pn[3], - pn[4], pn[5]); + if (memcmp(pn, rpn, CCMP_PN_LEN)) return RX_DROP_UNUSABLE; - } memcpy(entry->last_pn, pn, CCMP_PN_LEN); } @@ -953,7 +961,7 @@ ieee80211_rx_h_defragment(struct ieee80211_rx_data *rx) return RX_CONTINUE; } -static ieee80211_rx_result +static ieee80211_rx_result debug_noinline ieee80211_rx_h_ps_poll(struct ieee80211_rx_data *rx) { struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(rx->dev); @@ -988,7 +996,7 @@ ieee80211_rx_h_ps_poll(struct ieee80211_rx_data *rx) * Tell TX path to send one frame even though the STA may * still remain is PS mode after this frame exchange. */ - rx->sta->flags |= WLAN_STA_PSPOLL; + set_sta_flags(rx->sta, WLAN_STA_PSPOLL); #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG printk(KERN_DEBUG "STA %s aid %d: PS Poll (entries after %d)\n", @@ -1016,7 +1024,7 @@ ieee80211_rx_h_ps_poll(struct ieee80211_rx_data *rx) * have nothing buffered for it? */ printk(KERN_DEBUG "%s: STA %s sent PS Poll even " - "though there is no buffered frames for it\n", + "though there are no buffered frames for it\n", rx->dev->name, print_mac(mac, rx->sta->addr)); #endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */ } @@ -1028,22 +1036,22 @@ ieee80211_rx_h_ps_poll(struct ieee80211_rx_data *rx) return RX_QUEUED; } -static ieee80211_rx_result +static ieee80211_rx_result debug_noinline ieee80211_rx_h_remove_qos_control(struct ieee80211_rx_data *rx) { - u16 fc = rx->fc; u8 *data = rx->skb->data; - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) data; + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)data; - if (!WLAN_FC_IS_QOS_DATA(fc)) + if (!ieee80211_is_data_qos(hdr->frame_control)) return RX_CONTINUE; /* remove the qos control field, update frame type and meta-data */ - memmove(data + 2, data, ieee80211_get_hdrlen(fc) - 2); - hdr = (struct ieee80211_hdr *) skb_pull(rx->skb, 2); + memmove(data + IEEE80211_QOS_CTL_LEN, data, + ieee80211_hdrlen(hdr->frame_control) - IEEE80211_QOS_CTL_LEN); + hdr = (struct ieee80211_hdr *)skb_pull(rx->skb, IEEE80211_QOS_CTL_LEN); /* change frame type to non QOS */ - rx->fc = fc &= ~IEEE80211_STYPE_QOS_DATA; - hdr->frame_control = cpu_to_le16(fc); + rx->fc &= ~IEEE80211_STYPE_QOS_DATA; + hdr->frame_control &= ~cpu_to_le16(IEEE80211_STYPE_QOS_DATA); return RX_CONTINUE; } @@ -1051,14 +1059,9 @@ ieee80211_rx_h_remove_qos_control(struct ieee80211_rx_data *rx) static int ieee80211_802_1x_port_control(struct ieee80211_rx_data *rx) { - if (unlikely(!rx->sta || !(rx->sta->flags & WLAN_STA_AUTHORIZED))) { -#ifdef CONFIG_MAC80211_DEBUG - if (net_ratelimit()) - printk(KERN_DEBUG "%s: dropped frame " - "(unauthorized port)\n", rx->dev->name); -#endif /* CONFIG_MAC80211_DEBUG */ + if (unlikely(!rx->sta || + !test_sta_flags(rx->sta, WLAN_STA_AUTHORIZED))) return -EACCES; - } return 0; } @@ -1138,16 +1141,8 @@ ieee80211_data_to_8023(struct ieee80211_rx_data *rx) memcpy(src, hdr->addr2, ETH_ALEN); if (unlikely(sdata->vif.type != IEEE80211_IF_TYPE_AP && - sdata->vif.type != IEEE80211_IF_TYPE_VLAN)) { - if (net_ratelimit()) - printk(KERN_DEBUG "%s: dropped ToDS frame " - "(BSSID=%s SA=%s DA=%s)\n", - dev->name, - print_mac(mac, hdr->addr1), - print_mac(mac2, hdr->addr2), - print_mac(mac3, hdr->addr3)); + sdata->vif.type != IEEE80211_IF_TYPE_VLAN)) return -1; - } break; case (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS): /* RA TA DA SA */ @@ -1155,17 +1150,8 @@ ieee80211_data_to_8023(struct ieee80211_rx_data *rx) memcpy(src, hdr->addr4, ETH_ALEN); if (unlikely(sdata->vif.type != IEEE80211_IF_TYPE_WDS && - sdata->vif.type != IEEE80211_IF_TYPE_MESH_POINT)) { - if (net_ratelimit()) - printk(KERN_DEBUG "%s: dropped FromDS&ToDS " - "frame (RA=%s TA=%s DA=%s SA=%s)\n", - rx->dev->name, - print_mac(mac, hdr->addr1), - print_mac(mac2, hdr->addr2), - print_mac(mac3, hdr->addr3), - print_mac(mac4, hdr->addr4)); + sdata->vif.type != IEEE80211_IF_TYPE_MESH_POINT)) return -1; - } break; case IEEE80211_FCTL_FROMDS: /* DA BSSID SA */ @@ -1182,27 +1168,13 @@ ieee80211_data_to_8023(struct ieee80211_rx_data *rx) memcpy(dst, hdr->addr1, ETH_ALEN); memcpy(src, hdr->addr2, ETH_ALEN); - if (sdata->vif.type != IEEE80211_IF_TYPE_IBSS) { - if (net_ratelimit()) { - printk(KERN_DEBUG "%s: dropped IBSS frame " - "(DA=%s SA=%s BSSID=%s)\n", - dev->name, - print_mac(mac, hdr->addr1), - print_mac(mac2, hdr->addr2), - print_mac(mac3, hdr->addr3)); - } + if (sdata->vif.type != IEEE80211_IF_TYPE_IBSS) return -1; - } break; } - if (unlikely(skb->len - hdrlen < 8)) { - if (net_ratelimit()) { - printk(KERN_DEBUG "%s: RX too short data frame " - "payload\n", dev->name); - } + if (unlikely(skb->len - hdrlen < 8)) return -1; - } payload = skb->data + hdrlen; ethertype = (payload[6] << 8) | payload[7]; @@ -1345,7 +1317,7 @@ ieee80211_deliver_skb(struct ieee80211_rx_data *rx) } } -static ieee80211_rx_result +static ieee80211_rx_result debug_noinline ieee80211_rx_h_amsdu(struct ieee80211_rx_data *rx) { struct net_device *dev = rx->dev; @@ -1394,10 +1366,8 @@ ieee80211_rx_h_amsdu(struct ieee80211_rx_data *rx) padding = ((4 - subframe_len) & 0x3); /* the last MSDU has no padding */ - if (subframe_len > remaining) { - printk(KERN_DEBUG "%s: wrong buffer size\n", dev->name); + if (subframe_len > remaining) return RX_DROP_UNUSABLE; - } skb_pull(skb, sizeof(struct ethhdr)); /* if last subframe reuse skb */ @@ -1418,8 +1388,6 @@ ieee80211_rx_h_amsdu(struct ieee80211_rx_data *rx) eth = (struct ethhdr *) skb_pull(skb, ntohs(len) + padding); if (!eth) { - printk(KERN_DEBUG "%s: wrong buffer size\n", - dev->name); dev_kfree_skb(frame); return RX_DROP_UNUSABLE; } @@ -1462,7 +1430,7 @@ ieee80211_rx_h_amsdu(struct ieee80211_rx_data *rx) return RX_QUEUED; } -static ieee80211_rx_result +static ieee80211_rx_result debug_noinline ieee80211_rx_h_data(struct ieee80211_rx_data *rx) { struct net_device *dev = rx->dev; @@ -1493,21 +1461,21 @@ ieee80211_rx_h_data(struct ieee80211_rx_data *rx) return RX_QUEUED; } -static ieee80211_rx_result +static ieee80211_rx_result debug_noinline ieee80211_rx_h_ctrl(struct ieee80211_rx_data *rx) { struct ieee80211_local *local = rx->local; struct ieee80211_hw *hw = &local->hw; struct sk_buff *skb = rx->skb; - struct ieee80211_bar *bar = (struct ieee80211_bar *) skb->data; + struct ieee80211_bar *bar = (struct ieee80211_bar *)skb->data; struct tid_ampdu_rx *tid_agg_rx; u16 start_seq_num; u16 tid; - if (likely((rx->fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_CTL)) + if (likely(!ieee80211_is_ctl(bar->frame_control))) return RX_CONTINUE; - if ((rx->fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_BACK_REQ) { + if (ieee80211_is_back_req(bar->frame_control)) { if (!rx->sta) return RX_CONTINUE; tid = le16_to_cpu(bar->control) >> 12; @@ -1537,7 +1505,7 @@ ieee80211_rx_h_ctrl(struct ieee80211_rx_data *rx) return RX_CONTINUE; } -static ieee80211_rx_result +static ieee80211_rx_result debug_noinline ieee80211_rx_h_mgmt(struct ieee80211_rx_data *rx) { struct ieee80211_sub_if_data *sdata; @@ -1561,41 +1529,27 @@ static void ieee80211_rx_michael_mic_report(struct net_device *dev, struct ieee80211_hdr *hdr, struct ieee80211_rx_data *rx) { - int keyidx, hdrlen; + int keyidx; + unsigned int hdrlen; DECLARE_MAC_BUF(mac); DECLARE_MAC_BUF(mac2); - hdrlen = ieee80211_get_hdrlen_from_skb(rx->skb); + hdrlen = ieee80211_hdrlen(hdr->frame_control); if (rx->skb->len >= hdrlen + 4) keyidx = rx->skb->data[hdrlen + 3] >> 6; else keyidx = -1; - if (net_ratelimit()) - printk(KERN_DEBUG "%s: TKIP hwaccel reported Michael MIC " - "failure from %s to %s keyidx=%d\n", - dev->name, print_mac(mac, hdr->addr2), - print_mac(mac2, hdr->addr1), keyidx); - if (!rx->sta) { /* * Some hardware seem to generate incorrect Michael MIC * reports; ignore them to avoid triggering countermeasures. */ - if (net_ratelimit()) - printk(KERN_DEBUG "%s: ignored spurious Michael MIC " - "error for unknown address %s\n", - dev->name, print_mac(mac, hdr->addr2)); goto ignore; } - if (!(rx->fc & IEEE80211_FCTL_PROTECTED)) { - if (net_ratelimit()) - printk(KERN_DEBUG "%s: ignored spurious Michael MIC " - "error for a frame with no PROTECTED flag (src " - "%s)\n", dev->name, print_mac(mac, hdr->addr2)); + if (!ieee80211_has_protected(hdr->frame_control)) goto ignore; - } if (rx->sdata->vif.type == IEEE80211_IF_TYPE_AP && keyidx) { /* @@ -1604,24 +1558,12 @@ static void ieee80211_rx_michael_mic_report(struct net_device *dev, * group keys and only the AP is sending real multicast * frames in the BSS. */ - if (net_ratelimit()) - printk(KERN_DEBUG "%s: ignored Michael MIC error for " - "a frame with non-zero keyidx (%d)" - " (src %s)\n", dev->name, keyidx, - print_mac(mac, hdr->addr2)); goto ignore; } - if ((rx->fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA && - ((rx->fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_MGMT || - (rx->fc & IEEE80211_FCTL_STYPE) != IEEE80211_STYPE_AUTH)) { - if (net_ratelimit()) - printk(KERN_DEBUG "%s: ignored spurious Michael MIC " - "error for a frame that cannot be encrypted " - "(fc=0x%04x) (src %s)\n", - dev->name, rx->fc, print_mac(mac, hdr->addr2)); + if (!ieee80211_is_data(hdr->frame_control) && + !ieee80211_is_auth(hdr->frame_control)) goto ignore; - } mac80211_ev_michael_mic_failure(rx->dev, keyidx, hdr); ignore: @@ -1710,67 +1652,57 @@ static void ieee80211_rx_cooked_monitor(struct ieee80211_rx_data *rx) dev_kfree_skb(skb); } -typedef ieee80211_rx_result (*ieee80211_rx_handler)(struct ieee80211_rx_data *); -static ieee80211_rx_handler ieee80211_rx_handlers[] = -{ - ieee80211_rx_h_if_stats, - ieee80211_rx_h_passive_scan, - ieee80211_rx_h_check, - ieee80211_rx_h_decrypt, - ieee80211_rx_h_sta_process, - ieee80211_rx_h_defragment, - ieee80211_rx_h_ps_poll, - ieee80211_rx_h_michael_mic_verify, - /* this must be after decryption - so header is counted in MPDU mic - * must be before pae and data, so QOS_DATA format frames - * are not passed to user space by these functions - */ - ieee80211_rx_h_remove_qos_control, - ieee80211_rx_h_amsdu, - ieee80211_rx_h_data, - ieee80211_rx_h_ctrl, - ieee80211_rx_h_mgmt, - NULL -}; static void ieee80211_invoke_rx_handlers(struct ieee80211_sub_if_data *sdata, struct ieee80211_rx_data *rx, struct sk_buff *skb) { - ieee80211_rx_handler *handler; ieee80211_rx_result res = RX_DROP_MONITOR; rx->skb = skb; rx->sdata = sdata; rx->dev = sdata->dev; - for (handler = ieee80211_rx_handlers; *handler != NULL; handler++) { - res = (*handler)(rx); - - switch (res) { - case RX_CONTINUE: - continue; - case RX_DROP_UNUSABLE: - case RX_DROP_MONITOR: - I802_DEBUG_INC(sdata->local->rx_handlers_drop); - if (rx->sta) - rx->sta->rx_dropped++; - break; - case RX_QUEUED: - I802_DEBUG_INC(sdata->local->rx_handlers_queued); - break; - } - break; - } - +#define CALL_RXH(rxh) \ + res = rxh(rx); \ + if (res != RX_CONTINUE) \ + goto rxh_done; + + CALL_RXH(ieee80211_rx_h_passive_scan) + CALL_RXH(ieee80211_rx_h_check) + CALL_RXH(ieee80211_rx_h_decrypt) + CALL_RXH(ieee80211_rx_h_sta_process) + CALL_RXH(ieee80211_rx_h_defragment) + CALL_RXH(ieee80211_rx_h_ps_poll) + CALL_RXH(ieee80211_rx_h_michael_mic_verify) + /* must be after MMIC verify so header is counted in MPDU mic */ + CALL_RXH(ieee80211_rx_h_remove_qos_control) + CALL_RXH(ieee80211_rx_h_amsdu) + CALL_RXH(ieee80211_rx_h_data) + CALL_RXH(ieee80211_rx_h_ctrl) + CALL_RXH(ieee80211_rx_h_mgmt) + +#undef CALL_RXH + + rxh_done: switch (res) { - case RX_CONTINUE: case RX_DROP_MONITOR: + I802_DEBUG_INC(sdata->local->rx_handlers_drop); + if (rx->sta) + rx->sta->rx_dropped++; + /* fall through */ + case RX_CONTINUE: ieee80211_rx_cooked_monitor(rx); break; case RX_DROP_UNUSABLE: + I802_DEBUG_INC(sdata->local->rx_handlers_drop); + if (rx->sta) + rx->sta->rx_dropped++; dev_kfree_skb(rx->skb); break; + case RX_QUEUED: + I802_DEBUG_INC(sdata->local->rx_handlers_queued); + break; } } @@ -1801,9 +1733,13 @@ static int prepare_for_handlers(struct ieee80211_sub_if_data *sdata, case IEEE80211_IF_TYPE_IBSS: if (!bssid) return 0; - if ((rx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT && - (rx->fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_BEACON) + if (ieee80211_is_beacon(hdr->frame_control)) { + if (!rx->sta) + rx->sta = ieee80211_ibss_add_sta(sdata->dev, + rx->skb, bssid, hdr->addr2, + BIT(rx->status->rate_idx)); return 1; + } else if (!ieee80211_bssid_match(bssid, sdata->u.sta.bssid)) { if (!(rx->flags & IEEE80211_RX_IN_SCAN)) return 0; @@ -1816,7 +1752,8 @@ static int prepare_for_handlers(struct ieee80211_sub_if_data *sdata, rx->flags &= ~IEEE80211_RX_RA_MATCH; } else if (!rx->sta) rx->sta = ieee80211_ibss_add_sta(sdata->dev, rx->skb, - bssid, hdr->addr2); + bssid, hdr->addr2, + BIT(rx->status->rate_idx)); break; case IEEE80211_IF_TYPE_MESH_POINT: if (!multicast && @@ -1840,15 +1777,9 @@ static int prepare_for_handlers(struct ieee80211_sub_if_data *sdata, return 0; rx->flags &= ~IEEE80211_RX_RA_MATCH; } - if (sdata->dev == sdata->local->mdev && - !(rx->flags & IEEE80211_RX_IN_SCAN)) - /* do not receive anything via - * master device when not scanning */ - return 0; break; case IEEE80211_IF_TYPE_WDS: - if (bssid || - (rx->fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA) + if (bssid || !ieee80211_is_data(hdr->frame_control)) return 0; if (compare_ether_addr(sdata->u.wds.remote_addr, hdr->addr2)) return 0; @@ -1872,7 +1803,6 @@ static int prepare_for_handlers(struct ieee80211_sub_if_data *sdata, static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw, struct sk_buff *skb, struct ieee80211_rx_status *status, - u32 load, struct ieee80211_rate *rate) { struct ieee80211_local *local = hw_to_local(hw); @@ -1891,7 +1821,6 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw, rx.local = local; rx.status = status; - rx.load = load; rx.rate = rate; rx.fc = le16_to_cpu(hdr->frame_control); type = rx.fc & IEEE80211_FCTL_FTYPE; @@ -2000,7 +1929,6 @@ u8 ieee80211_sta_manage_reorder_buf(struct ieee80211_hw *hw, struct ieee80211_rx_status status; u16 head_seq_num, buf_size; int index; - u32 pkt_load; struct ieee80211_supported_band *sband; struct ieee80211_rate *rate; @@ -2035,12 +1963,9 @@ u8 ieee80211_sta_manage_reorder_buf(struct ieee80211_hw *hw, sizeof(status)); sband = local->hw.wiphy->bands[status.band]; rate = &sband->bitrates[status.rate_idx]; - pkt_load = ieee80211_rx_load_stats(local, - tid_agg_rx->reorder_buf[index], - &status, rate); __ieee80211_rx_handle_packet(hw, tid_agg_rx->reorder_buf[index], - &status, pkt_load, rate); + &status, rate); tid_agg_rx->stored_mpdu_num--; tid_agg_rx->reorder_buf[index] = NULL; } @@ -2082,11 +2007,8 @@ u8 ieee80211_sta_manage_reorder_buf(struct ieee80211_hw *hw, sizeof(status)); sband = local->hw.wiphy->bands[status.band]; rate = &sband->bitrates[status.rate_idx]; - pkt_load = ieee80211_rx_load_stats(local, - tid_agg_rx->reorder_buf[index], - &status, rate); __ieee80211_rx_handle_packet(hw, tid_agg_rx->reorder_buf[index], - &status, pkt_load, rate); + &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); @@ -2103,32 +2025,29 @@ static u8 ieee80211_rx_reorder_ampdu(struct ieee80211_local *local, struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; struct sta_info *sta; struct tid_ampdu_rx *tid_agg_rx; - u16 fc, sc; + u16 sc; u16 mpdu_seq_num; - u8 ret = 0, *qc; + u8 ret = 0; int tid; sta = sta_info_get(local, hdr->addr2); if (!sta) return ret; - fc = le16_to_cpu(hdr->frame_control); - /* filter the QoS data rx stream according to * STA/TID and check if this STA/TID is on aggregation */ - if (!WLAN_FC_IS_QOS_DATA(fc)) + if (!ieee80211_is_data_qos(hdr->frame_control)) goto end_reorder; - qc = skb->data + ieee80211_get_hdrlen(fc) - QOS_CONTROL_LEN; - tid = qc[0] & QOS_CONTROL_TID_MASK; + tid = *ieee80211_get_qos_ctl(hdr) & IEEE80211_QOS_CTL_TID_MASK; if (sta->ampdu_mlme.tid_state_rx[tid] != HT_AGG_STATE_OPERATIONAL) goto end_reorder; tid_agg_rx = sta->ampdu_mlme.tid_rx[tid]; - /* null data frames are excluded */ - if (unlikely(fc & IEEE80211_STYPE_NULLFUNC)) + /* qos null data frames are excluded */ + if (unlikely(hdr->frame_control & cpu_to_le16(IEEE80211_STYPE_NULLFUNC))) goto end_reorder; /* new un-ordered ampdu frame - process it */ @@ -2165,7 +2084,6 @@ void __ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb, struct ieee80211_rx_status *status) { struct ieee80211_local *local = hw_to_local(hw); - u32 pkt_load; struct ieee80211_rate *rate = NULL; struct ieee80211_supported_band *sband; @@ -2205,11 +2123,8 @@ void __ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb, return; } - pkt_load = ieee80211_rx_load_stats(local, skb, status, rate); - local->channel_use_raw += pkt_load; - if (!ieee80211_rx_reorder_ampdu(local, skb)) - __ieee80211_rx_handle_packet(hw, skb, status, pkt_load, rate); + __ieee80211_rx_handle_packet(hw, skb, status, rate); rcu_read_unlock(); } diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index 7d4fe4a52929..f2ba653b9d69 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c @@ -135,6 +135,7 @@ struct sta_info *sta_info_get_by_idx(struct ieee80211_local *local, int idx, /** * __sta_info_free - internal STA free helper * + * @local: pointer to the global information * @sta: STA info to free * * This function must undo everything done by sta_info_alloc() @@ -202,14 +203,12 @@ void sta_info_destroy(struct sta_info *sta) dev_kfree_skb_any(skb); for (i = 0; i < STA_TID_NUM; i++) { - spin_lock_bh(&sta->ampdu_mlme.ampdu_rx); + spin_lock_bh(&sta->lock); if (sta->ampdu_mlme.tid_rx[i]) del_timer_sync(&sta->ampdu_mlme.tid_rx[i]->session_timer); - spin_unlock_bh(&sta->ampdu_mlme.ampdu_rx); - spin_lock_bh(&sta->ampdu_mlme.ampdu_tx); if (sta->ampdu_mlme.tid_tx[i]) del_timer_sync(&sta->ampdu_mlme.tid_tx[i]->addba_resp_timer); - spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx); + spin_unlock_bh(&sta->lock); } __sta_info_free(local, sta); @@ -236,6 +235,9 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata, if (!sta) return NULL; + spin_lock_init(&sta->lock); + spin_lock_init(&sta->flaglock); + memcpy(sta->addr, addr, ETH_ALEN); sta->local = local; sta->sdata = sdata; @@ -249,15 +251,13 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata, return NULL; } - spin_lock_init(&sta->ampdu_mlme.ampdu_rx); - spin_lock_init(&sta->ampdu_mlme.ampdu_tx); for (i = 0; i < STA_TID_NUM; i++) { /* timer_to_tid must be initialized with identity mapping to * enable session_timer's data differentiation. refer to * sta_rx_agg_session_timer_expired for useage */ sta->timer_to_tid[i] = i; /* tid to tx queue: initialize according to HW (0 is valid) */ - sta->tid_to_tx_q[i] = local->hw.queues; + sta->tid_to_tx_q[i] = ieee80211_num_queues(&local->hw); /* rx */ sta->ampdu_mlme.tid_state_rx[i] = HT_AGG_STATE_IDLE; sta->ampdu_mlme.tid_rx[i] = NULL; @@ -276,7 +276,6 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata, #ifdef CONFIG_MAC80211_MESH sta->plink_state = PLINK_LISTEN; - spin_lock_init(&sta->plink_lock); init_timer(&sta->plink_timer); #endif @@ -321,7 +320,9 @@ int sta_info_insert(struct sta_info *sta) /* notify driver */ if (local->ops->sta_notify) { if (sdata->vif.type == IEEE80211_IF_TYPE_VLAN) - sdata = sdata->u.vlan.ap; + sdata = container_of(sdata->bss, + struct ieee80211_sub_if_data, + u.ap); local->ops->sta_notify(local_to_hw(local), &sdata->vif, STA_NOTIFY_ADD, sta->addr); @@ -376,8 +377,10 @@ static inline void __bss_tim_clear(struct ieee80211_if_ap *bss, u16 aid) static void __sta_info_set_tim_bit(struct ieee80211_if_ap *bss, struct sta_info *sta) { - if (bss) - __bss_tim_set(bss, sta->aid); + BUG_ON(!bss); + + __bss_tim_set(bss, sta->aid); + if (sta->local->ops->set_tim) { sta->local->tim_in_locked_section = true; sta->local->ops->set_tim(local_to_hw(sta->local), sta->aid, 1); @@ -389,6 +392,8 @@ void sta_info_set_tim_bit(struct sta_info *sta) { unsigned long flags; + BUG_ON(!sta->sdata->bss); + spin_lock_irqsave(&sta->local->sta_lock, flags); __sta_info_set_tim_bit(sta->sdata->bss, sta); spin_unlock_irqrestore(&sta->local->sta_lock, flags); @@ -397,8 +402,10 @@ void sta_info_set_tim_bit(struct sta_info *sta) static void __sta_info_clear_tim_bit(struct ieee80211_if_ap *bss, struct sta_info *sta) { - if (bss) - __bss_tim_clear(bss, sta->aid); + BUG_ON(!bss); + + __bss_tim_clear(bss, sta->aid); + if (sta->local->ops->set_tim) { sta->local->tim_in_locked_section = true; sta->local->ops->set_tim(local_to_hw(sta->local), sta->aid, 0); @@ -410,6 +417,8 @@ void sta_info_clear_tim_bit(struct sta_info *sta) { unsigned long flags; + BUG_ON(!sta->sdata->bss); + spin_lock_irqsave(&sta->local->sta_lock, flags); __sta_info_clear_tim_bit(sta->sdata->bss, sta); spin_unlock_irqrestore(&sta->local->sta_lock, flags); @@ -437,10 +446,10 @@ void __sta_info_unlink(struct sta_info **sta) list_del(&(*sta)->list); - if ((*sta)->flags & WLAN_STA_PS) { - (*sta)->flags &= ~WLAN_STA_PS; - if (sdata->bss) - atomic_dec(&sdata->bss->num_sta_ps); + if (test_and_clear_sta_flags(*sta, WLAN_STA_PS)) { + BUG_ON(!sdata->bss); + + atomic_dec(&sdata->bss->num_sta_ps); __sta_info_clear_tim_bit(sdata->bss, *sta); } @@ -448,7 +457,9 @@ void __sta_info_unlink(struct sta_info **sta) if (local->ops->sta_notify) { if (sdata->vif.type == IEEE80211_IF_TYPE_VLAN) - sdata = sdata->u.vlan.ap; + sdata = container_of(sdata->bss, + struct ieee80211_sub_if_data, + u.ap); local->ops->sta_notify(local_to_hw(local), &sdata->vif, STA_NOTIFY_REMOVE, (*sta)->addr); @@ -515,20 +526,20 @@ static inline int sta_info_buffer_expired(struct ieee80211_local *local, struct sta_info *sta, struct sk_buff *skb) { - struct ieee80211_tx_packet_data *pkt_data; + struct ieee80211_tx_info *info; int timeout; if (!skb) return 0; - pkt_data = (struct ieee80211_tx_packet_data *) skb->cb; + 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; if (timeout < STA_TX_BUFFER_EXPIRE) timeout = STA_TX_BUFFER_EXPIRE; - return time_after(jiffies, pkt_data->jiffies + timeout); + return time_after(jiffies, info->control.jiffies + timeout); } @@ -557,8 +568,10 @@ static void sta_info_cleanup_expire_buffered(struct ieee80211_local *local, sdata = sta->sdata; local->total_ps_buffered--; +#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG printk(KERN_DEBUG "Buffered frame expired (STA " "%s)\n", print_mac(mac, sta->addr)); +#endif dev_kfree_skb(skb); if (skb_queue_empty(&sta->ps_tx_buf)) diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index f8c95bc9659c..109db787ccb7 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h @@ -32,7 +32,7 @@ * @WLAN_STA_WDS: Station is one of our WDS peers. * @WLAN_STA_PSPOLL: Station has just PS-polled us. * @WLAN_STA_CLEAR_PS_FILT: Clear PS filter in hardware (using the - * IEEE80211_TXCTL_CLEAR_PS_FILT control flag) when the next + * IEEE80211_TX_CTL_CLEAR_PS_FILT control flag) when the next * frame to this station is transmitted. */ enum ieee80211_sta_info_flags { @@ -129,23 +129,19 @@ enum plink_state { * * @tid_state_rx: TID's state in Rx session state machine. * @tid_rx: aggregation info for Rx per TID - * @ampdu_rx: for locking sections in aggregation Rx flow * @tid_state_tx: TID's state in Tx session state machine. * @tid_tx: aggregation info for Tx per TID * @addba_req_num: number of times addBA request has been sent. - * @ampdu_tx: for locking sectionsi in aggregation Tx flow * @dialog_token_allocator: dialog token enumerator for each new session; */ struct sta_ampdu_mlme { /* rx */ u8 tid_state_rx[STA_TID_NUM]; struct tid_ampdu_rx *tid_rx[STA_TID_NUM]; - spinlock_t ampdu_rx; /* tx */ u8 tid_state_tx[STA_TID_NUM]; struct tid_ampdu_tx *tid_tx[STA_TID_NUM]; u8 addba_req_num[STA_TID_NUM]; - spinlock_t ampdu_tx; u8 dialog_token_allocator; }; @@ -164,9 +160,20 @@ struct sta_ampdu_mlme { * @list: global linked list entry * @hnext: hash table linked list pointer * @local: pointer to the global information + * @sdata: TBD + * @key: TBD + * @rate_ctrl: TBD + * @rate_ctrl_priv: TBD + * @lock: used for locking all fields that require locking, see comments + * in the header file. + * @flaglock: spinlock for flags accesses + * @ht_info: HT capabilities of this STA + * @supp_rates: Bitmap of supported rates (per band) * @addr: MAC address of this STA * @aid: STA's unique AID (1..2007, 0 = not assigned yet), * only used in AP (and IBSS?) mode + * @listen_interval: TBD + * @pin_status: TBD * @flags: STA flags, see &enum ieee80211_sta_info_flags * @ps_tx_buf: buffer of frames to transmit to this station * when it leaves power saving state @@ -175,8 +182,41 @@ struct sta_ampdu_mlme { * power saving state * @rx_packets: Number of MSDUs received from this STA * @rx_bytes: Number of bytes received from this STA - * @supp_rates: Bitmap of supported rates (per band) - * @ht_info: HT capabilities of this STA + * @wep_weak_iv_count: TBD + * @last_rx: TBD + * @num_duplicates: number of duplicate frames received from this STA + * @rx_fragments: number of received MPDUs + * @rx_dropped: number of dropped MPDUs from this STA + * @last_signal: signal of last received frame from this STA + * @last_qual: qual of last received frame from this STA + * @last_noise: noise of last received frame from this STA + * @last_seq_ctrl: last received seq/frag number from this STA (per RX queue) + * @wme_rx_queue: TBD + * @tx_filtered_count: TBD + * @tx_retry_failed: TBD + * @tx_retry_count: TBD + * @tx_num_consecutive_failures: TBD + * @tx_num_mpdu_ok: TBD + * @tx_num_mpdu_fail: TBD + * @fail_avg: moving percentage of failed MSDUs + * @tx_packets: number of RX/TX MSDUs + * @tx_bytes: TBD + * @tx_fragments: number of transmitted MPDUs + * @txrate_idx: TBD + * @last_txrate_idx: TBD + * @wme_tx_queue: TBD + * @ampdu_mlme: TBD + * @timer_to_tid: identity mapping to ID timers + * @tid_to_tx_q: map tid to tx queue + * @llid: Local link ID + * @plid: Peer link ID + * @reason: Cancel reason on PLINK_HOLDING state + * @plink_retries: Retries in establishment + * @ignore_plink_timer: TBD + * @plink_state plink_state: TBD + * @plink_timeout: TBD + * @plink_timer: TBD + * @debugfs: debug filesystem info */ struct sta_info { /* General information, mostly static */ @@ -187,6 +227,8 @@ struct sta_info { struct ieee80211_key *key; struct rate_control_ref *rate_ctrl; void *rate_ctrl_priv; + spinlock_t lock; + spinlock_t flaglock; struct ieee80211_ht_info ht_info; u64 supp_rates[IEEE80211_NUM_BANDS]; u8 addr[ETH_ALEN]; @@ -199,7 +241,10 @@ struct sta_info { */ u8 pin_status; - /* frequently updated information, needs locking? */ + /* + * frequently updated, locked with own spinlock (flaglock), + * use the accessors defined below + */ u32 flags; /* @@ -213,14 +258,12 @@ struct sta_info { unsigned long rx_packets, rx_bytes; unsigned long wep_weak_iv_count; unsigned long last_rx; - unsigned long num_duplicates; /* number of duplicate frames received - * from this STA */ - unsigned long rx_fragments; /* number of received MPDUs */ - unsigned long rx_dropped; /* number of dropped MPDUs from this STA */ - int last_rssi; /* RSSI of last received frame from this STA */ - int last_signal; /* signal of last received frame from this STA */ - int last_noise; /* noise of last received frame from this STA */ - /* last received seq/frag number from this STA (per RX queue) */ + unsigned long num_duplicates; + unsigned long rx_fragments; + unsigned long rx_dropped; + int last_signal; + int last_qual; + int last_noise; __le16 last_seq_ctrl[NUM_RX_DATA_QUEUES]; #ifdef CONFIG_MAC80211_DEBUG_COUNTERS unsigned int wme_rx_queue[NUM_RX_DATA_QUEUES]; @@ -237,42 +280,36 @@ struct sta_info { unsigned int fail_avg; /* Updated from TX path only, no locking requirements */ - unsigned long tx_packets; /* number of RX/TX MSDUs */ + unsigned long tx_packets; unsigned long tx_bytes; - unsigned long tx_fragments; /* number of transmitted MPDUs */ + unsigned long tx_fragments; int txrate_idx; int last_txrate_idx; + u16 tid_seq[IEEE80211_QOS_CTL_TID_MASK + 1]; #ifdef CONFIG_MAC80211_DEBUG_COUNTERS unsigned int wme_tx_queue[NUM_RX_DATA_QUEUES]; #endif - /* Debug counters, no locking doesn't matter */ - int channel_use; - int channel_use_raw; - /* - * Aggregation information, comes with own locking. + * Aggregation information, locked with lock. */ struct sta_ampdu_mlme ampdu_mlme; - u8 timer_to_tid[STA_TID_NUM]; /* identity mapping to ID timers */ - u8 tid_to_tx_q[STA_TID_NUM]; /* map tid to tx queue */ + u8 timer_to_tid[STA_TID_NUM]; + u8 tid_to_tx_q[STA_TID_NUM]; #ifdef CONFIG_MAC80211_MESH /* * Mesh peer link attributes * TODO: move to a sub-structure that is referenced with pointer? */ - __le16 llid; /* Local link ID */ - __le16 plid; /* Peer link ID */ - __le16 reason; /* Cancel reason on PLINK_HOLDING state */ - u8 plink_retries; /* Retries in establishment */ + __le16 llid; + __le16 plid; + __le16 reason; + u8 plink_retries; bool ignore_plink_timer; enum plink_state plink_state; u32 plink_timeout; struct timer_list plink_timer; - spinlock_t plink_lock; /* For peer_state reads / updates and other - updates in the structure. Ensures robust - transitions for the peerlink FSM */ #endif #ifdef CONFIG_MAC80211_DEBUGFS @@ -299,6 +336,73 @@ static inline enum plink_state sta_plink_state(struct sta_info *sta) return PLINK_LISTEN; } +static inline void set_sta_flags(struct sta_info *sta, const u32 flags) +{ + unsigned long irqfl; + + spin_lock_irqsave(&sta->flaglock, irqfl); + sta->flags |= flags; + spin_unlock_irqrestore(&sta->flaglock, irqfl); +} + +static inline void clear_sta_flags(struct sta_info *sta, const u32 flags) +{ + unsigned long irqfl; + + spin_lock_irqsave(&sta->flaglock, irqfl); + sta->flags &= ~flags; + spin_unlock_irqrestore(&sta->flaglock, irqfl); +} + +static inline void set_and_clear_sta_flags(struct sta_info *sta, + const u32 set, const u32 clear) +{ + unsigned long irqfl; + + spin_lock_irqsave(&sta->flaglock, irqfl); + sta->flags |= set; + sta->flags &= ~clear; + spin_unlock_irqrestore(&sta->flaglock, irqfl); +} + +static inline u32 test_sta_flags(struct sta_info *sta, const u32 flags) +{ + u32 ret; + unsigned long irqfl; + + spin_lock_irqsave(&sta->flaglock, irqfl); + ret = sta->flags & flags; + spin_unlock_irqrestore(&sta->flaglock, irqfl); + + return ret; +} + +static inline u32 test_and_clear_sta_flags(struct sta_info *sta, + const u32 flags) +{ + u32 ret; + unsigned long irqfl; + + spin_lock_irqsave(&sta->flaglock, irqfl); + ret = sta->flags & flags; + sta->flags &= ~flags; + spin_unlock_irqrestore(&sta->flaglock, irqfl); + + return ret; +} + +static inline u32 get_sta_flags(struct sta_info *sta) +{ + u32 ret; + unsigned long irqfl; + + spin_lock_irqsave(&sta->flaglock, irqfl); + ret = sta->flags; + spin_unlock_irqrestore(&sta->flaglock, irqfl); + + return ret; +} + /* Maximum number of concurrently registered stations */ #define MAX_STA_COUNT 2007 diff --git a/net/mac80211/tkip.c b/net/mac80211/tkip.c index 09093da24af6..995f7af3d25e 100644 --- a/net/mac80211/tkip.c +++ b/net/mac80211/tkip.c @@ -6,25 +6,23 @@ * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ - #include <linux/kernel.h> +#include <linux/bitops.h> #include <linux/types.h> #include <linux/netdevice.h> +#include <asm/unaligned.h> #include <net/mac80211.h> #include "key.h" #include "tkip.h" #include "wep.h" - -/* TKIP key mixing functions */ - - #define PHASE1_LOOP_COUNT 8 - -/* 2-byte by 2-byte subset of the full AES S-box table; second part of this - * table is identical to first part but byte-swapped */ +/* + * 2-byte by 2-byte subset of the full AES S-box table; second part of this + * table is identical to first part but byte-swapped + */ static const u16 tkip_sbox[256] = { 0xC6A5, 0xF884, 0xEE99, 0xF68D, 0xFF0D, 0xD6BD, 0xDEB1, 0x9154, @@ -61,84 +59,54 @@ static const u16 tkip_sbox[256] = 0x82C3, 0x29B0, 0x5A77, 0x1E11, 0x7BCB, 0xA8FC, 0x6DD6, 0x2C3A, }; - -static inline u16 Mk16(u8 x, u8 y) +static u16 tkipS(u16 val) { - return ((u16) x << 8) | (u16) y; + return tkip_sbox[val & 0xff] ^ swab16(tkip_sbox[val >> 8]); } - -static inline u8 Hi8(u16 v) -{ - return v >> 8; -} - - -static inline u8 Lo8(u16 v) -{ - return v & 0xff; -} - - -static inline u16 Hi16(u32 v) -{ - return v >> 16; -} - - -static inline u16 Lo16(u32 v) -{ - return v & 0xffff; -} - - -static inline u16 RotR1(u16 v) -{ - return (v >> 1) | ((v & 0x0001) << 15); -} - - -static inline u16 tkip_S(u16 val) +static u8 *write_tkip_iv(u8 *pos, u16 iv16) { - u16 a = tkip_sbox[Hi8(val)]; - - return tkip_sbox[Lo8(val)] ^ Hi8(a) ^ (Lo8(a) << 8); + *pos++ = iv16 >> 8; + *pos++ = ((iv16 >> 8) | 0x20) & 0x7f; + *pos++ = iv16 & 0xFF; + return pos; } - - -/* P1K := Phase1(TA, TK, TSC) +/* + * P1K := Phase1(TA, TK, TSC) * TA = transmitter address (48 bits) * TK = dot11DefaultKeyValue or dot11KeyMappingValue (128 bits) * TSC = TKIP sequence counter (48 bits, only 32 msb bits used) * P1K: 80 bits */ -static void tkip_mixing_phase1(const u8 *ta, const u8 *tk, u32 tsc_IV32, - u16 *p1k) +static void tkip_mixing_phase1(const u8 *tk, struct tkip_ctx *ctx, + const u8 *ta, u32 tsc_IV32) { int i, j; + u16 *p1k = ctx->p1k; - p1k[0] = Lo16(tsc_IV32); - p1k[1] = Hi16(tsc_IV32); - p1k[2] = Mk16(ta[1], ta[0]); - p1k[3] = Mk16(ta[3], ta[2]); - p1k[4] = Mk16(ta[5], ta[4]); + p1k[0] = tsc_IV32 & 0xFFFF; + p1k[1] = tsc_IV32 >> 16; + p1k[2] = get_unaligned_le16(ta + 0); + p1k[3] = get_unaligned_le16(ta + 2); + p1k[4] = get_unaligned_le16(ta + 4); for (i = 0; i < PHASE1_LOOP_COUNT; i++) { j = 2 * (i & 1); - p1k[0] += tkip_S(p1k[4] ^ Mk16(tk[ 1 + j], tk[ 0 + j])); - p1k[1] += tkip_S(p1k[0] ^ Mk16(tk[ 5 + j], tk[ 4 + j])); - p1k[2] += tkip_S(p1k[1] ^ Mk16(tk[ 9 + j], tk[ 8 + j])); - p1k[3] += tkip_S(p1k[2] ^ Mk16(tk[13 + j], tk[12 + j])); - p1k[4] += tkip_S(p1k[3] ^ Mk16(tk[ 1 + j], tk[ 0 + j])) + i; + p1k[0] += tkipS(p1k[4] ^ get_unaligned_le16(tk + 0 + j)); + p1k[1] += tkipS(p1k[0] ^ get_unaligned_le16(tk + 4 + j)); + p1k[2] += tkipS(p1k[1] ^ get_unaligned_le16(tk + 8 + j)); + p1k[3] += tkipS(p1k[2] ^ get_unaligned_le16(tk + 12 + j)); + p1k[4] += tkipS(p1k[3] ^ get_unaligned_le16(tk + 0 + j)) + i; } + ctx->initialized = 1; } - -static void tkip_mixing_phase2(const u16 *p1k, const u8 *tk, u16 tsc_IV16, - u8 *rc4key) +static void tkip_mixing_phase2(const u8 *tk, struct tkip_ctx *ctx, + u16 tsc_IV16, u8 *rc4key) { u16 ppk[6]; + const u16 *p1k = ctx->p1k; int i; ppk[0] = p1k[0]; @@ -148,70 +116,35 @@ static void tkip_mixing_phase2(const u16 *p1k, const u8 *tk, u16 tsc_IV16, ppk[4] = p1k[4]; ppk[5] = p1k[4] + tsc_IV16; - ppk[0] += tkip_S(ppk[5] ^ Mk16(tk[ 1], tk[ 0])); - ppk[1] += tkip_S(ppk[0] ^ Mk16(tk[ 3], tk[ 2])); - ppk[2] += tkip_S(ppk[1] ^ Mk16(tk[ 5], tk[ 4])); - ppk[3] += tkip_S(ppk[2] ^ Mk16(tk[ 7], tk[ 6])); - ppk[4] += tkip_S(ppk[3] ^ Mk16(tk[ 9], tk[ 8])); - ppk[5] += tkip_S(ppk[4] ^ Mk16(tk[11], tk[10])); - ppk[0] += RotR1(ppk[5] ^ Mk16(tk[13], tk[12])); - ppk[1] += RotR1(ppk[0] ^ Mk16(tk[15], tk[14])); - ppk[2] += RotR1(ppk[1]); - ppk[3] += RotR1(ppk[2]); - ppk[4] += RotR1(ppk[3]); - ppk[5] += RotR1(ppk[4]); - - rc4key[0] = Hi8(tsc_IV16); - rc4key[1] = (Hi8(tsc_IV16) | 0x20) & 0x7f; - rc4key[2] = Lo8(tsc_IV16); - rc4key[3] = Lo8((ppk[5] ^ Mk16(tk[1], tk[0])) >> 1); - - for (i = 0; i < 6; i++) { - rc4key[4 + 2 * i] = Lo8(ppk[i]); - rc4key[5 + 2 * i] = Hi8(ppk[i]); - } + ppk[0] += tkipS(ppk[5] ^ get_unaligned_le16(tk + 0)); + ppk[1] += tkipS(ppk[0] ^ get_unaligned_le16(tk + 2)); + ppk[2] += tkipS(ppk[1] ^ get_unaligned_le16(tk + 4)); + ppk[3] += tkipS(ppk[2] ^ get_unaligned_le16(tk + 6)); + ppk[4] += tkipS(ppk[3] ^ get_unaligned_le16(tk + 8)); + ppk[5] += tkipS(ppk[4] ^ get_unaligned_le16(tk + 10)); + ppk[0] += ror16(ppk[5] ^ get_unaligned_le16(tk + 12), 1); + ppk[1] += ror16(ppk[0] ^ get_unaligned_le16(tk + 14), 1); + ppk[2] += ror16(ppk[1], 1); + ppk[3] += ror16(ppk[2], 1); + ppk[4] += ror16(ppk[3], 1); + ppk[5] += ror16(ppk[4], 1); + + rc4key = write_tkip_iv(rc4key, tsc_IV16); + *rc4key++ = ((ppk[5] ^ get_unaligned_le16(tk)) >> 1) & 0xFF; + + for (i = 0; i < 6; i++) + put_unaligned_le16(ppk[i], rc4key + 2 * i); } - /* Add TKIP IV and Ext. IV at @pos. @iv0, @iv1, and @iv2 are the first octets * of the IV. Returns pointer to the octet following IVs (i.e., beginning of * the packet payload). */ -u8 * ieee80211_tkip_add_iv(u8 *pos, struct ieee80211_key *key, - u8 iv0, u8 iv1, u8 iv2) +u8 *ieee80211_tkip_add_iv(u8 *pos, struct ieee80211_key *key, u16 iv16) { - *pos++ = iv0; - *pos++ = iv1; - *pos++ = iv2; + pos = write_tkip_iv(pos, iv16); *pos++ = (key->conf.keyidx << 6) | (1 << 5) /* Ext IV */; - *pos++ = key->u.tkip.iv32 & 0xff; - *pos++ = (key->u.tkip.iv32 >> 8) & 0xff; - *pos++ = (key->u.tkip.iv32 >> 16) & 0xff; - *pos++ = (key->u.tkip.iv32 >> 24) & 0xff; - return pos; -} - - -void ieee80211_tkip_gen_phase1key(struct ieee80211_key *key, u8 *ta, - u16 *phase1key) -{ - tkip_mixing_phase1(ta, &key->conf.key[ALG_TKIP_TEMP_ENCR_KEY], - key->u.tkip.iv32, phase1key); -} - -void ieee80211_tkip_gen_rc4key(struct ieee80211_key *key, u8 *ta, - u8 *rc4key) -{ - /* Calculate per-packet key */ - if (key->u.tkip.iv16 == 0 || !key->u.tkip.tx_initialized) { - /* IV16 wrapped around - perform TKIP phase 1 */ - tkip_mixing_phase1(ta, &key->conf.key[ALG_TKIP_TEMP_ENCR_KEY], - key->u.tkip.iv32, key->u.tkip.p1k); - key->u.tkip.tx_initialized = 1; - } - - tkip_mixing_phase2(key->u.tkip.p1k, - &key->conf.key[ALG_TKIP_TEMP_ENCR_KEY], - key->u.tkip.iv16, rc4key); + put_unaligned_le32(key->u.tkip.tx.iv32, pos); + return pos + 4; } void ieee80211_get_tkip_key(struct ieee80211_key_conf *keyconf, @@ -220,48 +153,44 @@ void ieee80211_get_tkip_key(struct ieee80211_key_conf *keyconf, { struct ieee80211_key *key = (struct ieee80211_key *) container_of(keyconf, struct ieee80211_key, conf); - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; - u8 *data = (u8 *) hdr; - u16 fc = le16_to_cpu(hdr->frame_control); - int hdr_len = ieee80211_get_hdrlen(fc); - u8 *ta = hdr->addr2; + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; + u8 *data; + const u8 *tk; + struct tkip_ctx *ctx; u16 iv16; u32 iv32; - iv16 = data[hdr_len] << 8; - iv16 += data[hdr_len + 2]; - iv32 = data[hdr_len + 4] | (data[hdr_len + 5] << 8) | - (data[hdr_len + 6] << 16) | (data[hdr_len + 7] << 24); + data = (u8 *)hdr + ieee80211_hdrlen(hdr->frame_control); + iv16 = data[2] | (data[0] << 8); + iv32 = get_unaligned_le32(&data[4]); + + tk = &key->conf.key[NL80211_TKIP_DATA_OFFSET_ENCR_KEY]; + ctx = &key->u.tkip.tx; -#ifdef CONFIG_TKIP_DEBUG +#ifdef CONFIG_MAC80211_TKIP_DEBUG printk(KERN_DEBUG "TKIP encrypt: iv16 = 0x%04x, iv32 = 0x%08x\n", iv16, iv32); - if (iv32 != key->u.tkip.iv32) { + if (iv32 != ctx->iv32) { printk(KERN_DEBUG "skb: iv32 = 0x%08x key: iv32 = 0x%08x\n", - iv32, key->u.tkip.iv32); + iv32, ctx->iv32); printk(KERN_DEBUG "Wrap around of iv16 in the middle of a " "fragmented packet\n"); } -#endif /* CONFIG_TKIP_DEBUG */ +#endif /* Update the p1k only when the iv16 in the packet wraps around, this * might occur after the wrap around of iv16 in the key in case of * fragmented packets. */ - if (iv16 == 0 || !key->u.tkip.tx_initialized) { - /* IV16 wrapped around - perform TKIP phase 1 */ - tkip_mixing_phase1(ta, &key->conf.key[ALG_TKIP_TEMP_ENCR_KEY], - iv32, key->u.tkip.p1k); - key->u.tkip.tx_initialized = 1; - } + if (iv16 == 0 || !ctx->initialized) + tkip_mixing_phase1(tk, ctx, hdr->addr2, iv32); if (type == IEEE80211_TKIP_P1_KEY) { - memcpy(outkey, key->u.tkip.p1k, sizeof(u16) * 5); + memcpy(outkey, ctx->p1k, sizeof(u16) * 5); return; } - tkip_mixing_phase2(key->u.tkip.p1k, - &key->conf.key[ALG_TKIP_TEMP_ENCR_KEY], iv16, outkey); + tkip_mixing_phase2(tk, ctx, iv16, outkey); } EXPORT_SYMBOL(ieee80211_get_tkip_key); @@ -275,13 +204,19 @@ void ieee80211_tkip_encrypt_data(struct crypto_blkcipher *tfm, u8 *pos, size_t payload_len, u8 *ta) { u8 rc4key[16]; + struct tkip_ctx *ctx = &key->u.tkip.tx; + const u8 *tk = &key->conf.key[NL80211_TKIP_DATA_OFFSET_ENCR_KEY]; + + /* Calculate per-packet key */ + if (ctx->iv16 == 0 || !ctx->initialized) + tkip_mixing_phase1(tk, ctx, ta, ctx->iv32); + + tkip_mixing_phase2(tk, ctx, ctx->iv16, rc4key); - ieee80211_tkip_gen_rc4key(key, ta, rc4key); - pos = ieee80211_tkip_add_iv(pos, key, rc4key[0], rc4key[1], rc4key[2]); + pos = ieee80211_tkip_add_iv(pos, key, key->u.tkip.tx.iv16); ieee80211_wep_encrypt_data(tfm, rc4key, 16, pos, payload_len); } - /* Decrypt packet payload with TKIP using @key. @pos is a pointer to the * beginning of the buffer containing IEEE 802.11 header payload, i.e., * including IV, Ext. IV, real data, Michael MIC, ICV. @payload_len is the @@ -296,15 +231,16 @@ int ieee80211_tkip_decrypt_data(struct crypto_blkcipher *tfm, u32 iv16; u8 rc4key[16], keyid, *pos = payload; int res; + const u8 *tk = &key->conf.key[NL80211_TKIP_DATA_OFFSET_ENCR_KEY]; if (payload_len < 12) return -1; iv16 = (pos[0] << 8) | pos[2]; keyid = pos[3]; - iv32 = pos[4] | (pos[5] << 8) | (pos[6] << 16) | (pos[7] << 24); + iv32 = get_unaligned_le32(pos + 4); pos += 8; -#ifdef CONFIG_TKIP_DEBUG +#ifdef CONFIG_MAC80211_TKIP_DEBUG { int i; printk(KERN_DEBUG "TKIP decrypt: data(len=%zd)", payload_len); @@ -314,7 +250,7 @@ int ieee80211_tkip_decrypt_data(struct crypto_blkcipher *tfm, printk(KERN_DEBUG "TKIP decrypt: iv16=%04x iv32=%08x\n", iv16, iv32); } -#endif /* CONFIG_TKIP_DEBUG */ +#endif if (!(keyid & (1 << 5))) return TKIP_DECRYPT_NO_EXT_IV; @@ -322,50 +258,48 @@ int ieee80211_tkip_decrypt_data(struct crypto_blkcipher *tfm, if ((keyid >> 6) != key->conf.keyidx) return TKIP_DECRYPT_INVALID_KEYIDX; - if (key->u.tkip.rx_initialized[queue] && - (iv32 < key->u.tkip.iv32_rx[queue] || - (iv32 == key->u.tkip.iv32_rx[queue] && - iv16 <= key->u.tkip.iv16_rx[queue]))) { -#ifdef CONFIG_TKIP_DEBUG + if (key->u.tkip.rx[queue].initialized && + (iv32 < key->u.tkip.rx[queue].iv32 || + (iv32 == key->u.tkip.rx[queue].iv32 && + iv16 <= key->u.tkip.rx[queue].iv16))) { +#ifdef CONFIG_MAC80211_TKIP_DEBUG DECLARE_MAC_BUF(mac); printk(KERN_DEBUG "TKIP replay detected for RX frame from " "%s (RX IV (%04x,%02x) <= prev. IV (%04x,%02x)\n", print_mac(mac, ta), - iv32, iv16, key->u.tkip.iv32_rx[queue], - key->u.tkip.iv16_rx[queue]); -#endif /* CONFIG_TKIP_DEBUG */ + iv32, iv16, key->u.tkip.rx[queue].iv32, + key->u.tkip.rx[queue].iv16); +#endif return TKIP_DECRYPT_REPLAY; } if (only_iv) { res = TKIP_DECRYPT_OK; - key->u.tkip.rx_initialized[queue] = 1; + key->u.tkip.rx[queue].initialized = 1; goto done; } - if (!key->u.tkip.rx_initialized[queue] || - key->u.tkip.iv32_rx[queue] != iv32) { - key->u.tkip.rx_initialized[queue] = 1; + if (!key->u.tkip.rx[queue].initialized || + key->u.tkip.rx[queue].iv32 != iv32) { /* IV16 wrapped around - perform TKIP phase 1 */ - tkip_mixing_phase1(ta, &key->conf.key[ALG_TKIP_TEMP_ENCR_KEY], - iv32, key->u.tkip.p1k_rx[queue]); -#ifdef CONFIG_TKIP_DEBUG + tkip_mixing_phase1(tk, &key->u.tkip.rx[queue], ta, iv32); +#ifdef CONFIG_MAC80211_TKIP_DEBUG { int i; + u8 key_offset = NL80211_TKIP_DATA_OFFSET_ENCR_KEY; DECLARE_MAC_BUF(mac); printk(KERN_DEBUG "TKIP decrypt: Phase1 TA=%s" " TK=", print_mac(mac, ta)); for (i = 0; i < 16; i++) printk("%02x ", - key->conf.key[ - ALG_TKIP_TEMP_ENCR_KEY + i]); + key->conf.key[key_offset + i]); printk("\n"); printk(KERN_DEBUG "TKIP decrypt: P1K="); for (i = 0; i < 5; i++) - printk("%04x ", key->u.tkip.p1k_rx[queue][i]); + printk("%04x ", key->u.tkip.rx[queue].p1k[i]); printk("\n"); } -#endif /* CONFIG_TKIP_DEBUG */ +#endif if (key->local->ops->update_tkip_key && key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) { u8 bcast[ETH_ALEN] = @@ -377,14 +311,12 @@ int ieee80211_tkip_decrypt_data(struct crypto_blkcipher *tfm, key->local->ops->update_tkip_key( local_to_hw(key->local), &key->conf, - sta_addr, iv32, key->u.tkip.p1k_rx[queue]); + sta_addr, iv32, key->u.tkip.rx[queue].p1k); } } - tkip_mixing_phase2(key->u.tkip.p1k_rx[queue], - &key->conf.key[ALG_TKIP_TEMP_ENCR_KEY], - iv16, rc4key); -#ifdef CONFIG_TKIP_DEBUG + tkip_mixing_phase2(tk, &key->u.tkip.rx[queue], iv16, rc4key); +#ifdef CONFIG_MAC80211_TKIP_DEBUG { int i; printk(KERN_DEBUG "TKIP decrypt: Phase2 rc4key="); @@ -392,7 +324,7 @@ int ieee80211_tkip_decrypt_data(struct crypto_blkcipher *tfm, printk("%02x ", rc4key[i]); printk("\n"); } -#endif /* CONFIG_TKIP_DEBUG */ +#endif res = ieee80211_wep_decrypt_data(tfm, rc4key, 16, pos, payload_len - 12); done: @@ -409,5 +341,3 @@ int ieee80211_tkip_decrypt_data(struct crypto_blkcipher *tfm, return res; } - - diff --git a/net/mac80211/tkip.h b/net/mac80211/tkip.h index b7c2ee763d9d..d4714383f5fc 100644 --- a/net/mac80211/tkip.h +++ b/net/mac80211/tkip.h @@ -13,12 +13,8 @@ #include <linux/crypto.h> #include "key.h" -u8 * ieee80211_tkip_add_iv(u8 *pos, struct ieee80211_key *key, - u8 iv0, u8 iv1, u8 iv2); -void ieee80211_tkip_gen_phase1key(struct ieee80211_key *key, u8 *ta, - u16 *phase1key); -void ieee80211_tkip_gen_rc4key(struct ieee80211_key *key, u8 *ta, - u8 *rc4key); +u8 *ieee80211_tkip_add_iv(u8 *pos, struct ieee80211_key *key, u16 iv16); + void ieee80211_tkip_encrypt_data(struct crypto_blkcipher *tfm, struct ieee80211_key *key, u8 *pos, size_t payload_len, u8 *ta); diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index c80d5899f279..0fbadd8b983c 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -38,23 +38,12 @@ /* misc utils */ -static inline void ieee80211_include_sequence(struct ieee80211_sub_if_data *sdata, - struct ieee80211_hdr *hdr) -{ - /* Set the sequence number for this frame. */ - hdr->seq_ctrl = cpu_to_le16(sdata->sequence); - - /* Increase the sequence number. */ - sdata->sequence = (sdata->sequence + 0x10) & IEEE80211_SCTL_SEQ; -} - #ifdef CONFIG_MAC80211_LOWTX_FRAME_DUMP static void ieee80211_dump_frame(const char *ifname, const char *title, const struct sk_buff *skb) { - const struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; - u16 fc; - int hdrlen; + const struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; + unsigned int hdrlen; DECLARE_MAC_BUF(mac); printk(KERN_DEBUG "%s: %s (len=%d)", ifname, title, skb->len); @@ -63,13 +52,12 @@ static void ieee80211_dump_frame(const char *ifname, const char *title, return; } - fc = le16_to_cpu(hdr->frame_control); - hdrlen = ieee80211_get_hdrlen(fc); + hdrlen = ieee80211_hdrlen(hdr->frame_control); if (hdrlen > skb->len) hdrlen = skb->len; if (hdrlen >= 4) printk(" FC=0x%04x DUR=0x%04x", - fc, le16_to_cpu(hdr->duration_id)); + le16_to_cpu(hdr->frame_control), le16_to_cpu(hdr->duration_id)); if (hdrlen >= 10) printk(" A1=%s", print_mac(mac, hdr->addr1)); if (hdrlen >= 16) @@ -87,15 +75,16 @@ static inline void ieee80211_dump_frame(const char *ifname, const char *title, } #endif /* CONFIG_MAC80211_LOWTX_FRAME_DUMP */ -static u16 ieee80211_duration(struct ieee80211_tx_data *tx, int group_addr, - int next_frag_len) +static __le16 ieee80211_duration(struct ieee80211_tx_data *tx, int group_addr, + int next_frag_len) { int rate, mrate, erp, dur, i; - struct ieee80211_rate *txrate = tx->rate; + struct ieee80211_rate *txrate; struct ieee80211_local *local = tx->local; struct ieee80211_supported_band *sband; - sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; + sband = local->hw.wiphy->bands[tx->channel->band]; + txrate = &sband->bitrates[tx->rate_idx]; erp = 0; if (tx->sdata->flags & IEEE80211_SDATA_OPERATING_GMODE) @@ -139,7 +128,7 @@ static u16 ieee80211_duration(struct ieee80211_tx_data *tx, int group_addr, /* data/mgmt */ if (0 /* FIX: data/mgmt during CFP */) - return 32768; + return cpu_to_le16(32768); if (group_addr) /* Group address as the destination - no ACK */ return 0; @@ -209,19 +198,7 @@ static u16 ieee80211_duration(struct ieee80211_tx_data *tx, int group_addr, tx->sdata->bss_conf.use_short_preamble); } - return dur; -} - -static inline int __ieee80211_queue_stopped(const struct ieee80211_local *local, - int queue) -{ - return test_bit(IEEE80211_LINK_STATE_XOFF, &local->state[queue]); -} - -static inline int __ieee80211_queue_pending(const struct ieee80211_local *local, - int queue) -{ - return test_bit(IEEE80211_LINK_STATE_PENDING, &local->state[queue]); + return cpu_to_le16(dur); } static int inline is_ieee80211_device(struct net_device *dev, @@ -233,16 +210,16 @@ static int inline is_ieee80211_device(struct net_device *dev, /* tx handlers */ -static ieee80211_tx_result +static ieee80211_tx_result debug_noinline ieee80211_tx_h_check_assoc(struct ieee80211_tx_data *tx) { #ifdef CONFIG_MAC80211_VERBOSE_DEBUG - struct sk_buff *skb = tx->skb; - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)tx->skb->data; #endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb); u32 sta_flags; - if (unlikely(tx->flags & IEEE80211_TX_INJECTED)) + if (unlikely(info->flags & IEEE80211_TX_CTL_INJECTED)) return TX_CONTINUE; if (unlikely(tx->local->sta_sw_scanning) && @@ -256,7 +233,7 @@ ieee80211_tx_h_check_assoc(struct ieee80211_tx_data *tx) if (tx->flags & IEEE80211_TX_PS_BUFFERED) return TX_CONTINUE; - sta_flags = tx->sta ? tx->sta->flags : 0; + sta_flags = tx->sta ? get_sta_flags(tx->sta) : 0; if (likely(tx->flags & IEEE80211_TX_UNICAST)) { if (unlikely(!(sta_flags & WLAN_STA_ASSOC) && @@ -287,17 +264,6 @@ ieee80211_tx_h_check_assoc(struct ieee80211_tx_data *tx) return TX_CONTINUE; } -static ieee80211_tx_result -ieee80211_tx_h_sequence(struct ieee80211_tx_data *tx) -{ - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)tx->skb->data; - - if (ieee80211_get_hdrlen(le16_to_cpu(hdr->frame_control)) >= 24) - ieee80211_include_sequence(tx->sdata, hdr); - - return TX_CONTINUE; -} - /* This function is called whenever the AP is about to exceed the maximum limit * of buffered frames for power saving STAs. This situation should not really * happen often during normal operation, so dropping the oldest buffered packet @@ -316,8 +282,7 @@ static void purge_old_ps_buffers(struct ieee80211_local *local) list_for_each_entry_rcu(sdata, &local->interfaces, list) { struct ieee80211_if_ap *ap; - if (sdata->dev == local->mdev || - sdata->vif.type != IEEE80211_IF_TYPE_AP) + if (sdata->vif.type != IEEE80211_IF_TYPE_AP) continue; ap = &sdata->u.ap; skb = skb_dequeue(&ap->ps_bc_buf); @@ -340,13 +305,17 @@ static void purge_old_ps_buffers(struct ieee80211_local *local) rcu_read_unlock(); local->total_ps_buffered = total; +#ifdef MAC80211_VERBOSE_PS_DEBUG printk(KERN_DEBUG "%s: PS buffers full - purged %d frames\n", wiphy_name(local->hw.wiphy), purged); +#endif } static ieee80211_tx_result ieee80211_tx_h_multicast_ps_buf(struct ieee80211_tx_data *tx) { + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb); + /* * broadcast/multicast frame * @@ -355,8 +324,12 @@ ieee80211_tx_h_multicast_ps_buf(struct ieee80211_tx_data *tx) * This is done either by the hardware or us. */ - /* not AP/IBSS or ordered frame */ - if (!tx->sdata->bss || (tx->fc & IEEE80211_FCTL_ORDER)) + /* powersaving STAs only in AP/VLAN mode */ + if (!tx->sdata->bss) + return TX_CONTINUE; + + /* no buffering for ordered frames */ + if (tx->fc & IEEE80211_FCTL_ORDER) return TX_CONTINUE; /* no stations in PS mode */ @@ -369,11 +342,13 @@ ieee80211_tx_h_multicast_ps_buf(struct ieee80211_tx_data *tx) purge_old_ps_buffers(tx->local); if (skb_queue_len(&tx->sdata->bss->ps_bc_buf) >= AP_MAX_BC_BUFFER) { +#ifdef MAC80211_VERBOSE_PS_DEBUG if (net_ratelimit()) { printk(KERN_DEBUG "%s: BC TX buffer full - " "dropping the oldest frame\n", tx->dev->name); } +#endif dev_kfree_skb(skb_dequeue(&tx->sdata->bss->ps_bc_buf)); } else tx->local->total_ps_buffered++; @@ -382,7 +357,7 @@ ieee80211_tx_h_multicast_ps_buf(struct ieee80211_tx_data *tx) } /* buffered in hardware */ - tx->control->flags |= IEEE80211_TXCTL_SEND_AFTER_DTIM; + info->flags |= IEEE80211_TX_CTL_SEND_AFTER_DTIM; return TX_CONTINUE; } @@ -391,6 +366,8 @@ static ieee80211_tx_result ieee80211_tx_h_unicast_ps_buf(struct ieee80211_tx_data *tx) { struct sta_info *sta = tx->sta; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb); + u32 staflags; DECLARE_MAC_BUF(mac); if (unlikely(!sta || @@ -398,9 +375,10 @@ ieee80211_tx_h_unicast_ps_buf(struct ieee80211_tx_data *tx) (tx->fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_PROBE_RESP))) return TX_CONTINUE; - if (unlikely((sta->flags & WLAN_STA_PS) && - !(sta->flags & WLAN_STA_PSPOLL))) { - struct ieee80211_tx_packet_data *pkt_data; + staflags = get_sta_flags(sta); + + if (unlikely((staflags & WLAN_STA_PS) && + !(staflags & WLAN_STA_PSPOLL))) { #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG printk(KERN_DEBUG "STA %s aid %d: PS buffer (entries " "before %d)\n", @@ -411,11 +389,13 @@ ieee80211_tx_h_unicast_ps_buf(struct ieee80211_tx_data *tx) purge_old_ps_buffers(tx->local); if (skb_queue_len(&sta->ps_tx_buf) >= STA_MAX_TX_BUFFER) { struct sk_buff *old = skb_dequeue(&sta->ps_tx_buf); +#ifdef MAC80211_VERBOSE_PS_DEBUG if (net_ratelimit()) { printk(KERN_DEBUG "%s: STA %s TX " "buffer full - dropping oldest frame\n", tx->dev->name, print_mac(mac, sta->addr)); } +#endif dev_kfree_skb(old); } else tx->local->total_ps_buffered++; @@ -424,24 +404,23 @@ ieee80211_tx_h_unicast_ps_buf(struct ieee80211_tx_data *tx) if (skb_queue_empty(&sta->ps_tx_buf)) sta_info_set_tim_bit(sta); - pkt_data = (struct ieee80211_tx_packet_data *)tx->skb->cb; - pkt_data->jiffies = jiffies; + info->control.jiffies = jiffies; skb_queue_tail(&sta->ps_tx_buf, tx->skb); return TX_QUEUED; } #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG - else if (unlikely(sta->flags & WLAN_STA_PS)) { + else if (unlikely(test_sta_flags(sta, WLAN_STA_PS))) { printk(KERN_DEBUG "%s: STA %s in PS mode, but pspoll " "set -> send frame\n", tx->dev->name, print_mac(mac, sta->addr)); } #endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */ - sta->flags &= ~WLAN_STA_PSPOLL; + clear_sta_flags(sta, WLAN_STA_PSPOLL); return TX_CONTINUE; } -static ieee80211_tx_result +static ieee80211_tx_result debug_noinline ieee80211_tx_h_ps_buf(struct ieee80211_tx_data *tx) { if (unlikely(tx->flags & IEEE80211_TX_PS_BUFFERED)) @@ -453,21 +432,22 @@ ieee80211_tx_h_ps_buf(struct ieee80211_tx_data *tx) return ieee80211_tx_h_multicast_ps_buf(tx); } -static ieee80211_tx_result +static ieee80211_tx_result debug_noinline ieee80211_tx_h_select_key(struct ieee80211_tx_data *tx) { struct ieee80211_key *key; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb); u16 fc = tx->fc; - if (unlikely(tx->control->flags & IEEE80211_TXCTL_DO_NOT_ENCRYPT)) + if (unlikely(info->flags & IEEE80211_TX_CTL_DO_NOT_ENCRYPT)) tx->key = NULL; else if (tx->sta && (key = rcu_dereference(tx->sta->key))) tx->key = key; else if ((key = rcu_dereference(tx->sdata->default_key))) tx->key = key; else if (tx->sdata->drop_unencrypted && - !(tx->control->flags & IEEE80211_TXCTL_EAPOL_FRAME) && - !(tx->flags & IEEE80211_TX_INJECTED)) { + !(info->flags & IEEE80211_TX_CTL_EAPOL_FRAME) && + !(info->flags & IEEE80211_TX_CTL_INJECTED)) { I802_DEBUG_INC(tx->local->tx_handlers_drop_unencrypted); return TX_DROP; } else @@ -496,15 +476,197 @@ ieee80211_tx_h_select_key(struct ieee80211_tx_data *tx) } if (!tx->key || !(tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE)) - tx->control->flags |= IEEE80211_TXCTL_DO_NOT_ENCRYPT; + info->flags |= IEEE80211_TX_CTL_DO_NOT_ENCRYPT; return TX_CONTINUE; } -static ieee80211_tx_result +static ieee80211_tx_result debug_noinline +ieee80211_tx_h_rate_ctrl(struct ieee80211_tx_data *tx) +{ + struct rate_selection rsel; + struct ieee80211_supported_band *sband; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb); + + sband = tx->local->hw.wiphy->bands[tx->channel->band]; + + if (likely(tx->rate_idx < 0)) { + rate_control_get_rate(tx->dev, sband, tx->skb, &rsel); + tx->rate_idx = rsel.rate_idx; + if (unlikely(rsel.probe_idx >= 0)) { + info->flags |= IEEE80211_TX_CTL_RATE_CTRL_PROBE; + tx->flags |= IEEE80211_TX_PROBE_LAST_FRAG; + info->control.alt_retry_rate_idx = tx->rate_idx; + tx->rate_idx = rsel.probe_idx; + } else + info->control.alt_retry_rate_idx = -1; + + if (unlikely(tx->rate_idx < 0)) + return TX_DROP; + } else + info->control.alt_retry_rate_idx = -1; + + if (tx->sdata->bss_conf.use_cts_prot && + (tx->flags & IEEE80211_TX_FRAGMENTED) && (rsel.nonerp_idx >= 0)) { + tx->last_frag_rate_idx = tx->rate_idx; + if (rsel.probe_idx >= 0) + tx->flags &= ~IEEE80211_TX_PROBE_LAST_FRAG; + else + tx->flags |= IEEE80211_TX_PROBE_LAST_FRAG; + tx->rate_idx = rsel.nonerp_idx; + info->tx_rate_idx = rsel.nonerp_idx; + info->flags &= ~IEEE80211_TX_CTL_RATE_CTRL_PROBE; + } else { + tx->last_frag_rate_idx = tx->rate_idx; + info->tx_rate_idx = tx->rate_idx; + } + info->tx_rate_idx = tx->rate_idx; + + return TX_CONTINUE; +} + +static ieee80211_tx_result debug_noinline +ieee80211_tx_h_misc(struct ieee80211_tx_data *tx) +{ + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)tx->skb->data; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb); + struct ieee80211_supported_band *sband; + + sband = tx->local->hw.wiphy->bands[tx->channel->band]; + + if (tx->sta) + info->control.aid = tx->sta->aid; + + if (!info->control.retry_limit) { + if (!is_multicast_ether_addr(hdr->addr1)) { + int len = min_t(int, tx->skb->len + FCS_LEN, + tx->local->fragmentation_threshold); + if (len > tx->local->rts_threshold + && tx->local->rts_threshold < + IEEE80211_MAX_RTS_THRESHOLD) { + info->flags |= IEEE80211_TX_CTL_USE_RTS_CTS; + info->flags |= + IEEE80211_TX_CTL_LONG_RETRY_LIMIT; + info->control.retry_limit = + tx->local->long_retry_limit; + } else { + info->control.retry_limit = + tx->local->short_retry_limit; + } + } else { + info->control.retry_limit = 1; + } + } + + if (tx->flags & IEEE80211_TX_FRAGMENTED) { + /* Do not use multiple retry rates when sending fragmented + * frames. + * TODO: The last fragment could still use multiple retry + * rates. */ + info->control.alt_retry_rate_idx = -1; + } + + /* Use CTS protection for unicast frames sent using extended rates if + * there are associated non-ERP stations and RTS/CTS is not configured + * for the frame. */ + if ((tx->sdata->flags & IEEE80211_SDATA_OPERATING_GMODE) && + (sband->bitrates[tx->rate_idx].flags & IEEE80211_RATE_ERP_G) && + (tx->flags & IEEE80211_TX_UNICAST) && + tx->sdata->bss_conf.use_cts_prot && + !(info->flags & IEEE80211_TX_CTL_USE_RTS_CTS)) + info->flags |= IEEE80211_TX_CTL_USE_CTS_PROTECT; + + /* Transmit data frames using short preambles if the driver supports + * short preambles at the selected rate and short preambles are + * available on the network at the current point in time. */ + if (ieee80211_is_data(hdr->frame_control) && + (sband->bitrates[tx->rate_idx].flags & IEEE80211_RATE_SHORT_PREAMBLE) && + tx->sdata->bss_conf.use_short_preamble && + (!tx->sta || test_sta_flags(tx->sta, WLAN_STA_SHORT_PREAMBLE))) { + info->flags |= IEEE80211_TX_CTL_SHORT_PREAMBLE; + } + + if ((info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) || + (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT)) { + struct ieee80211_rate *rate; + s8 baserate = -1; + int idx; + + /* Do not use multiple retry rates when using RTS/CTS */ + info->control.alt_retry_rate_idx = -1; + + /* Use min(data rate, max base rate) as CTS/RTS rate */ + rate = &sband->bitrates[tx->rate_idx]; + + for (idx = 0; idx < sband->n_bitrates; idx++) { + if (sband->bitrates[idx].bitrate > rate->bitrate) + continue; + if (tx->sdata->basic_rates & BIT(idx) && + (baserate < 0 || + (sband->bitrates[baserate].bitrate + < sband->bitrates[idx].bitrate))) + baserate = idx; + } + + if (baserate >= 0) + info->control.rts_cts_rate_idx = baserate; + else + info->control.rts_cts_rate_idx = 0; + } + + if (tx->sta) + info->control.aid = tx->sta->aid; + + return TX_CONTINUE; +} + +static ieee80211_tx_result debug_noinline +ieee80211_tx_h_sequence(struct ieee80211_tx_data *tx) +{ + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb); + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)tx->skb->data; + u16 *seq; + u8 *qc; + int tid; + + /* only for injected frames */ + if (unlikely(ieee80211_is_ctl(hdr->frame_control))) + return TX_CONTINUE; + + if (ieee80211_hdrlen(hdr->frame_control) < 24) + return TX_CONTINUE; + + if (!ieee80211_is_data_qos(hdr->frame_control)) { + info->flags |= IEEE80211_TX_CTL_ASSIGN_SEQ; + return TX_CONTINUE; + } + + /* + * This should be true for injected/management frames only, for + * management frames we have set the IEEE80211_TX_CTL_ASSIGN_SEQ + * above since they are not QoS-data frames. + */ + if (!tx->sta) + return TX_CONTINUE; + + /* include per-STA, per-TID sequence counter */ + + qc = ieee80211_get_qos_ctl(hdr); + tid = *qc & IEEE80211_QOS_CTL_TID_MASK; + seq = &tx->sta->tid_seq[tid]; + + hdr->seq_ctrl = cpu_to_le16(*seq); + + /* Increase the sequence number. */ + *seq = (*seq + 0x10) & IEEE80211_SCTL_SEQ; + + return TX_CONTINUE; +} + +static ieee80211_tx_result debug_noinline ieee80211_tx_h_fragment(struct ieee80211_tx_data *tx) { - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) tx->skb->data; + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)tx->skb->data; size_t hdrlen, per_fragm, num_fragm, payload_len, left; struct sk_buff **frags, *first, *frag; int i; @@ -515,9 +677,19 @@ ieee80211_tx_h_fragment(struct ieee80211_tx_data *tx) if (!(tx->flags & IEEE80211_TX_FRAGMENTED)) return TX_CONTINUE; + /* + * Warn when submitting a fragmented A-MPDU frame and drop it. + * This scenario is handled in __ieee80211_tx_prepare but extra + * caution taken here as fragmented ampdu may cause Tx stop. + */ + if (WARN_ON(tx->flags & IEEE80211_TX_CTL_AMPDU || + skb_get_queue_mapping(tx->skb) >= + ieee80211_num_regular_queues(&tx->local->hw))) + return TX_DROP; + first = tx->skb; - hdrlen = ieee80211_get_hdrlen(tx->fc); + hdrlen = ieee80211_hdrlen(hdr->frame_control); payload_len = first->len - hdrlen; per_fragm = frag_threshold - hdrlen - FCS_LEN; num_fragm = DIV_ROUND_UP(payload_len, per_fragm); @@ -558,6 +730,8 @@ ieee80211_tx_h_fragment(struct ieee80211_tx_data *tx) fhdr->seq_ctrl = cpu_to_le16(seq | ((i + 1) & IEEE80211_SCTL_FRAG)); copylen = left > per_fragm ? per_fragm : left; memcpy(skb_put(frag, copylen), pos, copylen); + memcpy(frag->cb, first->cb, sizeof(frag->cb)); + skb_copy_queue_mapping(frag, first); pos += copylen; left -= copylen; @@ -570,7 +744,6 @@ ieee80211_tx_h_fragment(struct ieee80211_tx_data *tx) return TX_CONTINUE; fail: - printk(KERN_DEBUG "%s: failed to fragment frame\n", tx->dev->name); if (frags) { for (i = 0; i < num_fragm - 1; i++) if (frags[i]) @@ -581,7 +754,7 @@ ieee80211_tx_h_fragment(struct ieee80211_tx_data *tx) return TX_DROP; } -static ieee80211_tx_result +static ieee80211_tx_result debug_noinline ieee80211_tx_h_encrypt(struct ieee80211_tx_data *tx) { if (!tx->key) @@ -601,236 +774,57 @@ ieee80211_tx_h_encrypt(struct ieee80211_tx_data *tx) return TX_DROP; } -static ieee80211_tx_result -ieee80211_tx_h_rate_ctrl(struct ieee80211_tx_data *tx) +static ieee80211_tx_result debug_noinline +ieee80211_tx_h_calculate_duration(struct ieee80211_tx_data *tx) { - struct rate_selection rsel; - struct ieee80211_supported_band *sband; - - sband = tx->local->hw.wiphy->bands[tx->local->hw.conf.channel->band]; - - if (likely(!tx->rate)) { - rate_control_get_rate(tx->dev, sband, tx->skb, &rsel); - tx->rate = rsel.rate; - if (unlikely(rsel.probe)) { - tx->control->flags |= - IEEE80211_TXCTL_RATE_CTRL_PROBE; - tx->flags |= IEEE80211_TX_PROBE_LAST_FRAG; - tx->control->alt_retry_rate = tx->rate; - tx->rate = rsel.probe; - } else - tx->control->alt_retry_rate = NULL; - - if (!tx->rate) - return TX_DROP; - } else - tx->control->alt_retry_rate = NULL; + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)tx->skb->data; + int next_len, i; + int group_addr = is_multicast_ether_addr(hdr->addr1); - if (tx->sdata->bss_conf.use_cts_prot && - (tx->flags & IEEE80211_TX_FRAGMENTED) && rsel.nonerp) { - tx->last_frag_rate = tx->rate; - if (rsel.probe) - tx->flags &= ~IEEE80211_TX_PROBE_LAST_FRAG; - else - tx->flags |= IEEE80211_TX_PROBE_LAST_FRAG; - tx->rate = rsel.nonerp; - tx->control->tx_rate = rsel.nonerp; - tx->control->flags &= ~IEEE80211_TXCTL_RATE_CTRL_PROBE; - } else { - tx->last_frag_rate = tx->rate; - tx->control->tx_rate = tx->rate; + if (!(tx->flags & IEEE80211_TX_FRAGMENTED)) { + hdr->duration_id = ieee80211_duration(tx, group_addr, 0); + return TX_CONTINUE; } - tx->control->tx_rate = tx->rate; - - return TX_CONTINUE; -} -static ieee80211_tx_result -ieee80211_tx_h_misc(struct ieee80211_tx_data *tx) -{ - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) tx->skb->data; - u16 fc = le16_to_cpu(hdr->frame_control); - u16 dur; - struct ieee80211_tx_control *control = tx->control; + hdr->duration_id = ieee80211_duration(tx, group_addr, + tx->extra_frag[0]->len); - if (!control->retry_limit) { - if (!is_multicast_ether_addr(hdr->addr1)) { - if (tx->skb->len + FCS_LEN > tx->local->rts_threshold - && tx->local->rts_threshold < - IEEE80211_MAX_RTS_THRESHOLD) { - control->flags |= - IEEE80211_TXCTL_USE_RTS_CTS; - control->flags |= - IEEE80211_TXCTL_LONG_RETRY_LIMIT; - control->retry_limit = - tx->local->long_retry_limit; - } else { - control->retry_limit = - tx->local->short_retry_limit; - } + for (i = 0; i < tx->num_extra_frag; i++) { + if (i + 1 < tx->num_extra_frag) { + next_len = tx->extra_frag[i + 1]->len; } else { - control->retry_limit = 1; - } - } - - if (tx->flags & IEEE80211_TX_FRAGMENTED) { - /* Do not use multiple retry rates when sending fragmented - * frames. - * TODO: The last fragment could still use multiple retry - * rates. */ - control->alt_retry_rate = NULL; - } - - /* Use CTS protection for unicast frames sent using extended rates if - * there are associated non-ERP stations and RTS/CTS is not configured - * for the frame. */ - if ((tx->sdata->flags & IEEE80211_SDATA_OPERATING_GMODE) && - (tx->rate->flags & IEEE80211_RATE_ERP_G) && - (tx->flags & IEEE80211_TX_UNICAST) && - tx->sdata->bss_conf.use_cts_prot && - !(control->flags & IEEE80211_TXCTL_USE_RTS_CTS)) - control->flags |= IEEE80211_TXCTL_USE_CTS_PROTECT; - - /* Transmit data frames using short preambles if the driver supports - * short preambles at the selected rate and short preambles are - * available on the network at the current point in time. */ - if (((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA) && - (tx->rate->flags & IEEE80211_RATE_SHORT_PREAMBLE) && - tx->sdata->bss_conf.use_short_preamble && - (!tx->sta || (tx->sta->flags & WLAN_STA_SHORT_PREAMBLE))) { - tx->control->flags |= IEEE80211_TXCTL_SHORT_PREAMBLE; - } - - /* Setup duration field for the first fragment of the frame. Duration - * for remaining fragments will be updated when they are being sent - * to low-level driver in ieee80211_tx(). */ - dur = ieee80211_duration(tx, is_multicast_ether_addr(hdr->addr1), - (tx->flags & IEEE80211_TX_FRAGMENTED) ? - tx->extra_frag[0]->len : 0); - hdr->duration_id = cpu_to_le16(dur); - - if ((control->flags & IEEE80211_TXCTL_USE_RTS_CTS) || - (control->flags & IEEE80211_TXCTL_USE_CTS_PROTECT)) { - struct ieee80211_supported_band *sband; - struct ieee80211_rate *rate, *baserate; - int idx; - - sband = tx->local->hw.wiphy->bands[ - tx->local->hw.conf.channel->band]; - - /* Do not use multiple retry rates when using RTS/CTS */ - control->alt_retry_rate = NULL; - - /* Use min(data rate, max base rate) as CTS/RTS rate */ - rate = tx->rate; - baserate = NULL; - - for (idx = 0; idx < sband->n_bitrates; idx++) { - if (sband->bitrates[idx].bitrate > rate->bitrate) - continue; - if (tx->sdata->basic_rates & BIT(idx) && - (!baserate || - (baserate->bitrate < sband->bitrates[idx].bitrate))) - baserate = &sband->bitrates[idx]; + next_len = 0; + tx->rate_idx = tx->last_frag_rate_idx; } - if (baserate) - control->rts_cts_rate = baserate; - else - control->rts_cts_rate = &sband->bitrates[0]; - } - - if (tx->sta) { - control->aid = tx->sta->aid; - tx->sta->tx_packets++; - tx->sta->tx_fragments++; - tx->sta->tx_bytes += tx->skb->len; - if (tx->extra_frag) { - int i; - tx->sta->tx_fragments += tx->num_extra_frag; - for (i = 0; i < tx->num_extra_frag; i++) { - tx->sta->tx_bytes += - tx->extra_frag[i]->len; - } - } + hdr = (struct ieee80211_hdr *)tx->extra_frag[i]->data; + hdr->duration_id = ieee80211_duration(tx, 0, next_len); } return TX_CONTINUE; } -static ieee80211_tx_result -ieee80211_tx_h_load_stats(struct ieee80211_tx_data *tx) +static ieee80211_tx_result debug_noinline +ieee80211_tx_h_stats(struct ieee80211_tx_data *tx) { - struct ieee80211_local *local = tx->local; - struct sk_buff *skb = tx->skb; - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; - u32 load = 0, hdrtime; - struct ieee80211_rate *rate = tx->rate; - - /* TODO: this could be part of tx_status handling, so that the number - * of retries would be known; TX rate should in that case be stored - * somewhere with the packet */ - - /* Estimate total channel use caused by this frame */ - - /* 1 bit at 1 Mbit/s takes 1 usec; in channel_use values, - * 1 usec = 1/8 * (1080 / 10) = 13.5 */ - - if (tx->channel->band == IEEE80211_BAND_5GHZ || - (tx->channel->band == IEEE80211_BAND_2GHZ && - rate->flags & IEEE80211_RATE_ERP_G)) - hdrtime = CHAN_UTIL_HDR_SHORT; - else - hdrtime = CHAN_UTIL_HDR_LONG; - - load = hdrtime; - if (!is_multicast_ether_addr(hdr->addr1)) - load += hdrtime; - - if (tx->control->flags & IEEE80211_TXCTL_USE_RTS_CTS) - load += 2 * hdrtime; - else if (tx->control->flags & IEEE80211_TXCTL_USE_CTS_PROTECT) - load += hdrtime; + int i; - /* TODO: optimise again */ - load += skb->len * CHAN_UTIL_RATE_LCM / rate->bitrate; + if (!tx->sta) + return TX_CONTINUE; + tx->sta->tx_packets++; + tx->sta->tx_fragments++; + tx->sta->tx_bytes += tx->skb->len; if (tx->extra_frag) { - int i; - for (i = 0; i < tx->num_extra_frag; i++) { - load += 2 * hdrtime; - load += tx->extra_frag[i]->len * - tx->rate->bitrate; - } + tx->sta->tx_fragments += tx->num_extra_frag; + for (i = 0; i < tx->num_extra_frag; i++) + tx->sta->tx_bytes += tx->extra_frag[i]->len; } - /* Divide channel_use by 8 to avoid wrapping around the counter */ - load >>= CHAN_UTIL_SHIFT; - local->channel_use_raw += load; - if (tx->sta) - tx->sta->channel_use_raw += load; - tx->sdata->channel_use_raw += load; - return TX_CONTINUE; } -typedef ieee80211_tx_result (*ieee80211_tx_handler)(struct ieee80211_tx_data *); -static ieee80211_tx_handler ieee80211_tx_handlers[] = -{ - ieee80211_tx_h_check_assoc, - ieee80211_tx_h_sequence, - ieee80211_tx_h_ps_buf, - ieee80211_tx_h_select_key, - ieee80211_tx_h_michael_mic_add, - ieee80211_tx_h_fragment, - ieee80211_tx_h_encrypt, - ieee80211_tx_h_rate_ctrl, - ieee80211_tx_h_misc, - ieee80211_tx_h_load_stats, - NULL -}; - /* actual transmit path */ /* @@ -854,12 +848,12 @@ __ieee80211_parse_tx_radiotap(struct ieee80211_tx_data *tx, (struct ieee80211_radiotap_header *) skb->data; struct ieee80211_supported_band *sband; int ret = ieee80211_radiotap_iterator_init(&iterator, rthdr, skb->len); - struct ieee80211_tx_control *control = tx->control; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); - sband = tx->local->hw.wiphy->bands[tx->local->hw.conf.channel->band]; + sband = tx->local->hw.wiphy->bands[tx->channel->band]; - control->flags |= IEEE80211_TXCTL_DO_NOT_ENCRYPT; - tx->flags |= IEEE80211_TX_INJECTED; + info->flags |= IEEE80211_TX_CTL_DO_NOT_ENCRYPT; + info->flags |= IEEE80211_TX_CTL_INJECTED; tx->flags &= ~IEEE80211_TX_FRAGMENTED; /* @@ -896,7 +890,7 @@ __ieee80211_parse_tx_radiotap(struct ieee80211_tx_data *tx, r = &sband->bitrates[i]; if (r->bitrate == target_rate) { - tx->rate = r; + tx->rate_idx = i; break; } } @@ -907,7 +901,7 @@ __ieee80211_parse_tx_radiotap(struct ieee80211_tx_data *tx, * radiotap uses 0 for 1st ant, mac80211 is 1 for * 1st ant */ - control->antenna_sel_tx = (*iterator.this_arg) + 1; + info->antenna_sel_tx = (*iterator.this_arg) + 1; break; #if 0 @@ -931,8 +925,8 @@ __ieee80211_parse_tx_radiotap(struct ieee80211_tx_data *tx, skb_trim(skb, skb->len - FCS_LEN); } if (*iterator.this_arg & IEEE80211_RADIOTAP_F_WEP) - control->flags &= - ~IEEE80211_TXCTL_DO_NOT_ENCRYPT; + info->flags &= + ~IEEE80211_TX_CTL_DO_NOT_ENCRYPT; if (*iterator.this_arg & IEEE80211_RADIOTAP_F_FRAG) tx->flags |= IEEE80211_TX_FRAGMENTED; break; @@ -967,12 +961,12 @@ __ieee80211_parse_tx_radiotap(struct ieee80211_tx_data *tx, static ieee80211_tx_result __ieee80211_tx_prepare(struct ieee80211_tx_data *tx, struct sk_buff *skb, - struct net_device *dev, - struct ieee80211_tx_control *control) + struct net_device *dev) { struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); struct ieee80211_hdr *hdr; struct ieee80211_sub_if_data *sdata; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); int hdrlen; @@ -981,7 +975,9 @@ __ieee80211_tx_prepare(struct ieee80211_tx_data *tx, tx->dev = dev; /* use original interface */ tx->local = local; tx->sdata = IEEE80211_DEV_TO_SUB_IF(dev); - tx->control = control; + tx->channel = local->hw.conf.channel; + tx->rate_idx = -1; + tx->last_frag_rate_idx = -1; /* * Set this flag (used below to indicate "automatic fragmentation"), * it will be cleared/left by radiotap as desired. @@ -1008,34 +1004,33 @@ __ieee80211_tx_prepare(struct ieee80211_tx_data *tx, if (is_multicast_ether_addr(hdr->addr1)) { tx->flags &= ~IEEE80211_TX_UNICAST; - control->flags |= IEEE80211_TXCTL_NO_ACK; + info->flags |= IEEE80211_TX_CTL_NO_ACK; } else { tx->flags |= IEEE80211_TX_UNICAST; - control->flags &= ~IEEE80211_TXCTL_NO_ACK; + info->flags &= ~IEEE80211_TX_CTL_NO_ACK; } if (tx->flags & IEEE80211_TX_FRAGMENTED) { if ((tx->flags & IEEE80211_TX_UNICAST) && skb->len + FCS_LEN > local->fragmentation_threshold && - !local->ops->set_frag_threshold) + !local->ops->set_frag_threshold && + !(info->flags & IEEE80211_TX_CTL_AMPDU)) tx->flags |= IEEE80211_TX_FRAGMENTED; else tx->flags &= ~IEEE80211_TX_FRAGMENTED; } if (!tx->sta) - control->flags |= IEEE80211_TXCTL_CLEAR_PS_FILT; - else if (tx->sta->flags & WLAN_STA_CLEAR_PS_FILT) { - control->flags |= IEEE80211_TXCTL_CLEAR_PS_FILT; - tx->sta->flags &= ~WLAN_STA_CLEAR_PS_FILT; - } + info->flags |= IEEE80211_TX_CTL_CLEAR_PS_FILT; + else if (test_and_clear_sta_flags(tx->sta, WLAN_STA_CLEAR_PS_FILT)) + info->flags |= IEEE80211_TX_CTL_CLEAR_PS_FILT; hdrlen = ieee80211_get_hdrlen(tx->fc); if (skb->len > hdrlen + sizeof(rfc1042_header) + 2) { u8 *pos = &skb->data[hdrlen + sizeof(rfc1042_header)]; tx->ethertype = (pos[0] << 8) | pos[1]; } - control->flags |= IEEE80211_TXCTL_FIRST_FRAGMENT; + info->flags |= IEEE80211_TX_CTL_FIRST_FRAGMENT; return TX_CONTINUE; } @@ -1045,14 +1040,12 @@ __ieee80211_tx_prepare(struct ieee80211_tx_data *tx, */ static int ieee80211_tx_prepare(struct ieee80211_tx_data *tx, struct sk_buff *skb, - struct net_device *mdev, - struct ieee80211_tx_control *control) + struct net_device *mdev) { - struct ieee80211_tx_packet_data *pkt_data; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct net_device *dev; - pkt_data = (struct ieee80211_tx_packet_data *)skb->cb; - dev = dev_get_by_index(&init_net, pkt_data->ifindex); + dev = dev_get_by_index(&init_net, info->control.ifindex); if (unlikely(dev && !is_ieee80211_device(dev, mdev))) { dev_put(dev); dev = NULL; @@ -1060,7 +1053,7 @@ static int ieee80211_tx_prepare(struct ieee80211_tx_data *tx, if (unlikely(!dev)) return -ENODEV; /* initialises tx with control */ - __ieee80211_tx_prepare(tx, skb, dev, control); + __ieee80211_tx_prepare(tx, skb, dev); dev_put(dev); return 0; } @@ -1068,50 +1061,49 @@ static int ieee80211_tx_prepare(struct ieee80211_tx_data *tx, static int __ieee80211_tx(struct ieee80211_local *local, struct sk_buff *skb, struct ieee80211_tx_data *tx) { - struct ieee80211_tx_control *control = tx->control; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); int ret, i; - if (!ieee80211_qdisc_installed(local->mdev) && - __ieee80211_queue_stopped(local, 0)) { - netif_stop_queue(local->mdev); + if (netif_subqueue_stopped(local->mdev, skb)) return IEEE80211_TX_AGAIN; - } + if (skb) { ieee80211_dump_frame(wiphy_name(local->hw.wiphy), "TX to low-level driver", skb); - ret = local->ops->tx(local_to_hw(local), skb, control); + ret = local->ops->tx(local_to_hw(local), skb); if (ret) return IEEE80211_TX_AGAIN; local->mdev->trans_start = jiffies; ieee80211_led_tx(local, 1); } if (tx->extra_frag) { - control->flags &= ~(IEEE80211_TXCTL_USE_RTS_CTS | - IEEE80211_TXCTL_USE_CTS_PROTECT | - IEEE80211_TXCTL_CLEAR_PS_FILT | - IEEE80211_TXCTL_FIRST_FRAGMENT); for (i = 0; i < tx->num_extra_frag; i++) { if (!tx->extra_frag[i]) continue; - if (__ieee80211_queue_stopped(local, control->queue)) + info = IEEE80211_SKB_CB(tx->extra_frag[i]); + info->flags &= ~(IEEE80211_TX_CTL_USE_RTS_CTS | + IEEE80211_TX_CTL_USE_CTS_PROTECT | + IEEE80211_TX_CTL_CLEAR_PS_FILT | + IEEE80211_TX_CTL_FIRST_FRAGMENT); + if (netif_subqueue_stopped(local->mdev, + tx->extra_frag[i])) return IEEE80211_TX_FRAG_AGAIN; if (i == tx->num_extra_frag) { - control->tx_rate = tx->last_frag_rate; + info->tx_rate_idx = tx->last_frag_rate_idx; if (tx->flags & IEEE80211_TX_PROBE_LAST_FRAG) - control->flags |= - IEEE80211_TXCTL_RATE_CTRL_PROBE; + info->flags |= + IEEE80211_TX_CTL_RATE_CTRL_PROBE; else - control->flags &= - ~IEEE80211_TXCTL_RATE_CTRL_PROBE; + info->flags &= + ~IEEE80211_TX_CTL_RATE_CTRL_PROBE; } ieee80211_dump_frame(wiphy_name(local->hw.wiphy), "TX to low-level driver", tx->extra_frag[i]); ret = local->ops->tx(local_to_hw(local), - tx->extra_frag[i], - control); + tx->extra_frag[i]); if (ret) return IEEE80211_TX_FRAG_AGAIN; local->mdev->trans_start = jiffies; @@ -1124,17 +1116,65 @@ static int __ieee80211_tx(struct ieee80211_local *local, struct sk_buff *skb, return IEEE80211_TX_OK; } -static int ieee80211_tx(struct net_device *dev, struct sk_buff *skb, - struct ieee80211_tx_control *control) +/* + * Invoke TX handlers, return 0 on success and non-zero if the + * frame was dropped or queued. + */ +static int invoke_tx_handlers(struct ieee80211_tx_data *tx) +{ + struct sk_buff *skb = tx->skb; + ieee80211_tx_result res = TX_DROP; + int i; + +#define CALL_TXH(txh) \ + res = txh(tx); \ + if (res != TX_CONTINUE) \ + goto txh_done; + + CALL_TXH(ieee80211_tx_h_check_assoc) + CALL_TXH(ieee80211_tx_h_ps_buf) + CALL_TXH(ieee80211_tx_h_select_key) + CALL_TXH(ieee80211_tx_h_michael_mic_add) + CALL_TXH(ieee80211_tx_h_rate_ctrl) + CALL_TXH(ieee80211_tx_h_misc) + CALL_TXH(ieee80211_tx_h_sequence) + CALL_TXH(ieee80211_tx_h_fragment) + /* handlers after fragment must be aware of tx info fragmentation! */ + CALL_TXH(ieee80211_tx_h_encrypt) + CALL_TXH(ieee80211_tx_h_calculate_duration) + CALL_TXH(ieee80211_tx_h_stats) +#undef CALL_TXH + + txh_done: + if (unlikely(res == TX_DROP)) { + I802_DEBUG_INC(tx->local->tx_handlers_drop); + dev_kfree_skb(skb); + for (i = 0; i < tx->num_extra_frag; i++) + if (tx->extra_frag[i]) + dev_kfree_skb(tx->extra_frag[i]); + kfree(tx->extra_frag); + return -1; + } else if (unlikely(res == TX_QUEUED)) { + I802_DEBUG_INC(tx->local->tx_handlers_queued); + return -1; + } + + return 0; +} + +static int ieee80211_tx(struct net_device *dev, struct sk_buff *skb) { struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); struct sta_info *sta; - ieee80211_tx_handler *handler; struct ieee80211_tx_data tx; - ieee80211_tx_result res = TX_DROP, res_prepare; - int ret, i, retries = 0; + ieee80211_tx_result res_prepare; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + int ret, i; + u16 queue; + + queue = skb_get_queue_mapping(skb); - WARN_ON(__ieee80211_queue_pending(local, control->queue)); + WARN_ON(test_bit(queue, local->queues_pending)); if (unlikely(skb->len < 10)) { dev_kfree_skb(skb); @@ -1144,7 +1184,7 @@ static int ieee80211_tx(struct net_device *dev, struct sk_buff *skb, rcu_read_lock(); /* initialises tx */ - res_prepare = __ieee80211_tx_prepare(&tx, skb, dev, control); + res_prepare = __ieee80211_tx_prepare(&tx, skb, dev); if (res_prepare == TX_DROP) { dev_kfree_skb(skb); @@ -1154,86 +1194,53 @@ static int ieee80211_tx(struct net_device *dev, struct sk_buff *skb, sta = tx.sta; tx.channel = local->hw.conf.channel; + info->band = tx.channel->band; - for (handler = ieee80211_tx_handlers; *handler != NULL; - handler++) { - res = (*handler)(&tx); - if (res != TX_CONTINUE) - break; - } - - skb = tx.skb; /* handlers are allowed to change skb */ - - if (unlikely(res == TX_DROP)) { - I802_DEBUG_INC(local->tx_handlers_drop); - goto drop; - } - - if (unlikely(res == TX_QUEUED)) { - I802_DEBUG_INC(local->tx_handlers_queued); - rcu_read_unlock(); - return 0; - } - - if (tx.extra_frag) { - for (i = 0; i < tx.num_extra_frag; i++) { - int next_len, dur; - struct ieee80211_hdr *hdr = - (struct ieee80211_hdr *) - tx.extra_frag[i]->data; - - if (i + 1 < tx.num_extra_frag) { - next_len = tx.extra_frag[i + 1]->len; - } else { - next_len = 0; - tx.rate = tx.last_frag_rate; - } - dur = ieee80211_duration(&tx, 0, next_len); - hdr->duration_id = cpu_to_le16(dur); - } - } + if (invoke_tx_handlers(&tx)) + goto out; retry: ret = __ieee80211_tx(local, skb, &tx); if (ret) { - struct ieee80211_tx_stored_packet *store = - &local->pending_packet[control->queue]; + struct ieee80211_tx_stored_packet *store; + + /* + * Since there are no fragmented frames on A-MPDU + * queues, there's no reason for a driver to reject + * a frame there, warn and drop it. + */ + if (WARN_ON(queue >= ieee80211_num_regular_queues(&local->hw))) + goto drop; + + store = &local->pending_packet[queue]; if (ret == IEEE80211_TX_FRAG_AGAIN) skb = NULL; - set_bit(IEEE80211_LINK_STATE_PENDING, - &local->state[control->queue]); + set_bit(queue, local->queues_pending); smp_mb(); - /* When the driver gets out of buffers during sending of - * fragments and calls ieee80211_stop_queue, there is - * a small window between IEEE80211_LINK_STATE_XOFF and - * IEEE80211_LINK_STATE_PENDING flags are set. If a buffer + /* + * When the driver gets out of buffers during sending of + * fragments and calls ieee80211_stop_queue, the netif + * subqueue is stopped. There is, however, a small window + * in which the PENDING bit is not yet set. If a buffer * gets available in that window (i.e. driver calls * ieee80211_wake_queue), we would end up with ieee80211_tx - * called with IEEE80211_LINK_STATE_PENDING. Prevent this by + * called with the PENDING bit still set. Prevent this by * continuing transmitting here when that situation is - * possible to have happened. */ - if (!__ieee80211_queue_stopped(local, control->queue)) { - clear_bit(IEEE80211_LINK_STATE_PENDING, - &local->state[control->queue]); - retries++; - /* - * Driver bug, it's rejecting packets but - * not stopping queues. - */ - if (WARN_ON_ONCE(retries > 5)) - goto drop; + * possible to have happened. + */ + if (!__netif_subqueue_stopped(local->mdev, queue)) { + clear_bit(queue, local->queues_pending); goto retry; } - memcpy(&store->control, control, - sizeof(struct ieee80211_tx_control)); store->skb = skb; store->extra_frag = tx.extra_frag; store->num_extra_frag = tx.num_extra_frag; - store->last_frag_rate = tx.last_frag_rate; + store->last_frag_rate_idx = tx.last_frag_rate_idx; store->last_frag_rate_ctrl_probe = !!(tx.flags & IEEE80211_TX_PROBE_LAST_FRAG); } + out: rcu_read_unlock(); return 0; @@ -1250,24 +1257,57 @@ retry: /* device xmit handlers */ +static int ieee80211_skb_resize(struct ieee80211_local *local, + struct sk_buff *skb, + int head_need, bool may_encrypt) +{ + int tail_need = 0; + + /* + * This could be optimised, devices that do full hardware + * crypto (including TKIP MMIC) need no tailroom... But we + * have no drivers for such devices currently. + */ + if (may_encrypt) { + tail_need = IEEE80211_ENCRYPT_TAILROOM; + tail_need -= skb_tailroom(skb); + tail_need = max_t(int, tail_need, 0); + } + + if (head_need || tail_need) { + /* Sorry. Can't account for this any more */ + skb_orphan(skb); + } + + if (skb_header_cloned(skb)) + I802_DEBUG_INC(local->tx_expand_skb_head_cloned); + else + I802_DEBUG_INC(local->tx_expand_skb_head); + + if (pskb_expand_head(skb, head_need, tail_need, GFP_ATOMIC)) { + printk(KERN_DEBUG "%s: failed to reallocate TX buffer\n", + wiphy_name(local->hw.wiphy)); + return -ENOMEM; + } + + /* update truesize too */ + skb->truesize += head_need + tail_need; + + return 0; +} + int ieee80211_master_start_xmit(struct sk_buff *skb, struct net_device *dev) { - struct ieee80211_tx_control control; - struct ieee80211_tx_packet_data *pkt_data; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct net_device *odev = NULL; struct ieee80211_sub_if_data *osdata; int headroom; + bool may_encrypt; int ret; - /* - * copy control out of the skb so other people can use skb->cb - */ - pkt_data = (struct ieee80211_tx_packet_data *)skb->cb; - memset(&control, 0, sizeof(struct ieee80211_tx_control)); - - if (pkt_data->ifindex) - odev = dev_get_by_index(&init_net, pkt_data->ifindex); + if (info->control.ifindex) + odev = dev_get_by_index(&init_net, info->control.ifindex); if (unlikely(odev && !is_ieee80211_device(odev, dev))) { dev_put(odev); odev = NULL; @@ -1280,32 +1320,25 @@ int ieee80211_master_start_xmit(struct sk_buff *skb, dev_kfree_skb(skb); return 0; } + osdata = IEEE80211_DEV_TO_SUB_IF(odev); - headroom = osdata->local->tx_headroom + IEEE80211_ENCRYPT_HEADROOM; - if (skb_headroom(skb) < headroom) { - if (pskb_expand_head(skb, headroom, 0, GFP_ATOMIC)) { - dev_kfree_skb(skb); - dev_put(odev); - return 0; - } + may_encrypt = !(info->flags & IEEE80211_TX_CTL_DO_NOT_ENCRYPT); + + headroom = osdata->local->tx_headroom; + if (may_encrypt) + headroom += IEEE80211_ENCRYPT_HEADROOM; + headroom -= skb_headroom(skb); + headroom = max_t(int, 0, headroom); + + if (ieee80211_skb_resize(osdata->local, skb, headroom, may_encrypt)) { + dev_kfree_skb(skb); + dev_put(odev); + return 0; } - control.vif = &osdata->vif; - control.type = osdata->vif.type; - if (pkt_data->flags & IEEE80211_TXPD_REQ_TX_STATUS) - control.flags |= IEEE80211_TXCTL_REQ_TX_STATUS; - if (pkt_data->flags & IEEE80211_TXPD_DO_NOT_ENCRYPT) - control.flags |= IEEE80211_TXCTL_DO_NOT_ENCRYPT; - if (pkt_data->flags & IEEE80211_TXPD_REQUEUE) - control.flags |= IEEE80211_TXCTL_REQUEUE; - if (pkt_data->flags & IEEE80211_TXPD_EAPOL_FRAME) - control.flags |= IEEE80211_TXCTL_EAPOL_FRAME; - if (pkt_data->flags & IEEE80211_TXPD_AMPDU) - control.flags |= IEEE80211_TXCTL_AMPDU; - control.queue = pkt_data->queue; - - ret = ieee80211_tx(odev, skb, &control); + info->control.vif = &osdata->vif; + ret = ieee80211_tx(odev, skb); dev_put(odev); return ret; @@ -1315,7 +1348,7 @@ int ieee80211_monitor_start_xmit(struct sk_buff *skb, struct net_device *dev) { struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - struct ieee80211_tx_packet_data *pkt_data; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct ieee80211_radiotap_header *prthdr = (struct ieee80211_radiotap_header *)skb->data; u16 len_rthdr; @@ -1337,12 +1370,12 @@ int ieee80211_monitor_start_xmit(struct sk_buff *skb, skb->dev = local->mdev; - pkt_data = (struct ieee80211_tx_packet_data *)skb->cb; - memset(pkt_data, 0, sizeof(*pkt_data)); /* needed because we set skb device to master */ - pkt_data->ifindex = dev->ifindex; + info->control.ifindex = dev->ifindex; - pkt_data->flags |= IEEE80211_TXPD_DO_NOT_ENCRYPT; + info->flags |= IEEE80211_TX_CTL_DO_NOT_ENCRYPT; + /* Interfaces should always request a status report */ + info->flags |= IEEE80211_TX_CTL_REQ_TX_STATUS; /* * fix up the pointers accounting for the radiotap @@ -1386,10 +1419,11 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb, struct net_device *dev) { struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - struct ieee80211_tx_packet_data *pkt_data; + struct ieee80211_tx_info *info; struct ieee80211_sub_if_data *sdata; int ret = 1, head_need; - u16 ethertype, hdrlen, meshhdrlen = 0, fc; + u16 ethertype, hdrlen, meshhdrlen = 0; + __le16 fc; struct ieee80211_hdr hdr; struct ieee80211s_hdr mesh_hdr; const u8 *encaps_data; @@ -1400,8 +1434,6 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb, sdata = IEEE80211_DEV_TO_SUB_IF(dev); if (unlikely(skb->len < ETH_HLEN)) { - printk(KERN_DEBUG "%s: short skb (len=%d)\n", - dev->name, skb->len); ret = 0; goto fail; } @@ -1412,12 +1444,12 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb, /* convert Ethernet header to proper 802.11 header (based on * operation mode) */ ethertype = (skb->data[12] << 8) | skb->data[13]; - fc = IEEE80211_FTYPE_DATA | IEEE80211_STYPE_DATA; + fc = cpu_to_le16(IEEE80211_FTYPE_DATA | IEEE80211_STYPE_DATA); switch (sdata->vif.type) { case IEEE80211_IF_TYPE_AP: case IEEE80211_IF_TYPE_VLAN: - fc |= IEEE80211_FCTL_FROMDS; + fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS); /* DA BSSID SA */ memcpy(hdr.addr1, skb->data, ETH_ALEN); memcpy(hdr.addr2, dev->dev_addr, ETH_ALEN); @@ -1425,7 +1457,7 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb, hdrlen = 24; break; case IEEE80211_IF_TYPE_WDS: - fc |= IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS; + fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS); /* RA TA DA SA */ memcpy(hdr.addr1, sdata->u.wds.remote_addr, ETH_ALEN); memcpy(hdr.addr2, dev->dev_addr, ETH_ALEN); @@ -1435,7 +1467,7 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb, break; #ifdef CONFIG_MAC80211_MESH case IEEE80211_IF_TYPE_MESH_POINT: - fc |= IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS; + fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS); /* RA TA DA SA */ if (is_multicast_ether_addr(skb->data)) memcpy(hdr.addr1, skb->data, ETH_ALEN); @@ -1465,7 +1497,7 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb, break; #endif case IEEE80211_IF_TYPE_STA: - fc |= IEEE80211_FCTL_TODS; + fc |= cpu_to_le16(IEEE80211_FCTL_TODS); /* BSSID SA DA */ memcpy(hdr.addr1, sdata->u.sta.bssid, ETH_ALEN); memcpy(hdr.addr2, skb->data + ETH_ALEN, ETH_ALEN); @@ -1493,13 +1525,14 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb, rcu_read_lock(); sta = sta_info_get(local, hdr.addr1); if (sta) - sta_flags = sta->flags; + sta_flags = get_sta_flags(sta); rcu_read_unlock(); } - /* receiver is QoS enabled, use a QoS type frame */ - if (sta_flags & WLAN_STA_WME) { - fc |= IEEE80211_STYPE_QOS_DATA; + /* receiver and we are QoS enabled, use a QoS type frame */ + if (sta_flags & WLAN_STA_WME && + ieee80211_num_regular_queues(&local->hw) >= 4) { + fc |= cpu_to_le16(IEEE80211_STYPE_QOS_DATA); hdrlen += 2; } @@ -1527,7 +1560,7 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb, goto fail; } - hdr.frame_control = cpu_to_le16(fc); + hdr.frame_control = fc; hdr.duration_id = 0; hdr.seq_ctrl = 0; @@ -1562,32 +1595,26 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb, * build in headroom in __dev_alloc_skb() (linux/skbuff.h) and * alloc_skb() (net/core/skbuff.c) */ - head_need = hdrlen + encaps_len + meshhdrlen + local->tx_headroom; - head_need -= skb_headroom(skb); + head_need = hdrlen + encaps_len + meshhdrlen - skb_headroom(skb); - /* We are going to modify skb data, so make a copy of it if happens to - * be cloned. This could happen, e.g., with Linux bridge code passing - * us broadcast frames. */ + /* + * So we need to modify the skb header and hence need a copy of + * that. The head_need variable above doesn't, so far, include + * the needed header space that we don't need right away. If we + * can, then we don't reallocate right now but only after the + * frame arrives at the master device (if it does...) + * + * If we cannot, however, then we will reallocate to include all + * the ever needed space. Also, if we need to reallocate it anyway, + * make it big enough for everything we may ever need. + */ if (head_need > 0 || skb_cloned(skb)) { -#if 0 - printk(KERN_DEBUG "%s: need to reallocate buffer for %d bytes " - "of headroom\n", dev->name, head_need); -#endif - - if (skb_cloned(skb)) - I802_DEBUG_INC(local->tx_expand_skb_head_cloned); - else - I802_DEBUG_INC(local->tx_expand_skb_head); - /* Since we have to reallocate the buffer, make sure that there - * is enough room for possible WEP IV/ICV and TKIP (8 bytes - * before payload and 12 after). */ - if (pskb_expand_head(skb, (head_need > 0 ? head_need + 8 : 8), - 12, GFP_ATOMIC)) { - printk(KERN_DEBUG "%s: failed to reallocate TX buffer" - "\n", dev->name); + head_need += IEEE80211_ENCRYPT_HEADROOM; + head_need += local->tx_headroom; + head_need = max_t(int, 0, head_need); + if (ieee80211_skb_resize(local, skb, head_need, true)) goto fail; - } } if (encaps_data) { @@ -1602,7 +1629,7 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb, h_pos += meshhdrlen; } - if (fc & IEEE80211_STYPE_QOS_DATA) { + if (ieee80211_is_data_qos(fc)) { __le16 *qos_control; qos_control = (__le16*) skb_push(skb, 2); @@ -1618,11 +1645,14 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb, nh_pos += hdrlen; h_pos += hdrlen; - pkt_data = (struct ieee80211_tx_packet_data *)skb->cb; - memset(pkt_data, 0, sizeof(struct ieee80211_tx_packet_data)); - pkt_data->ifindex = dev->ifindex; + info = IEEE80211_SKB_CB(skb); + memset(info, 0, sizeof(*info)); + info->control.ifindex = dev->ifindex; if (ethertype == ETH_P_PAE) - pkt_data->flags |= IEEE80211_TXPD_EAPOL_FRAME; + info->flags |= IEEE80211_TX_CTL_EAPOL_FRAME; + + /* Interfaces should always request a status report */ + info->flags |= IEEE80211_TX_CTL_REQ_TX_STATUS; skb->dev = local->mdev; dev->stats.tx_packets++; @@ -1647,46 +1677,55 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb, return ret; } -/* helper functions for pending packets for when queues are stopped */ +/* + * ieee80211_clear_tx_pending may not be called in a context where + * it is possible that it packets could come in again. + */ void ieee80211_clear_tx_pending(struct ieee80211_local *local) { int i, j; struct ieee80211_tx_stored_packet *store; - for (i = 0; i < local->hw.queues; i++) { - if (!__ieee80211_queue_pending(local, i)) + for (i = 0; i < ieee80211_num_regular_queues(&local->hw); i++) { + if (!test_bit(i, local->queues_pending)) continue; store = &local->pending_packet[i]; kfree_skb(store->skb); for (j = 0; j < store->num_extra_frag; j++) kfree_skb(store->extra_frag[j]); kfree(store->extra_frag); - clear_bit(IEEE80211_LINK_STATE_PENDING, &local->state[i]); + clear_bit(i, local->queues_pending); } } +/* + * Transmit all pending packets. Called from tasklet, locks master device + * TX lock so that no new packets can come in. + */ void ieee80211_tx_pending(unsigned long data) { struct ieee80211_local *local = (struct ieee80211_local *)data; struct net_device *dev = local->mdev; struct ieee80211_tx_stored_packet *store; struct ieee80211_tx_data tx; - int i, ret, reschedule = 0; + int i, ret; netif_tx_lock_bh(dev); - for (i = 0; i < local->hw.queues; i++) { - if (__ieee80211_queue_stopped(local, i)) + for (i = 0; i < ieee80211_num_regular_queues(&local->hw); i++) { + /* Check that this queue is ok */ + if (__netif_subqueue_stopped(local->mdev, i)) continue; - if (!__ieee80211_queue_pending(local, i)) { - reschedule = 1; + + if (!test_bit(i, local->queues_pending)) { + ieee80211_wake_queue(&local->hw, i); continue; } + store = &local->pending_packet[i]; - tx.control = &store->control; tx.extra_frag = store->extra_frag; tx.num_extra_frag = store->num_extra_frag; - tx.last_frag_rate = store->last_frag_rate; + tx.last_frag_rate_idx = store->last_frag_rate_idx; tx.flags = 0; if (store->last_frag_rate_ctrl_probe) tx.flags |= IEEE80211_TX_PROBE_LAST_FRAG; @@ -1695,19 +1734,11 @@ void ieee80211_tx_pending(unsigned long data) if (ret == IEEE80211_TX_FRAG_AGAIN) store->skb = NULL; } else { - clear_bit(IEEE80211_LINK_STATE_PENDING, - &local->state[i]); - reschedule = 1; + clear_bit(i, local->queues_pending); + ieee80211_wake_queue(&local->hw, i); } } netif_tx_unlock_bh(dev); - if (reschedule) { - if (!ieee80211_qdisc_installed(dev)) { - if (!__ieee80211_queue_stopped(local, 0)) - netif_wake_queue(dev); - } else - netif_schedule(dev); - } } /* functions for drivers to get certain frames */ @@ -1776,23 +1807,24 @@ static void ieee80211_beacon_add_tim(struct ieee80211_local *local, } struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct ieee80211_tx_control *control) + struct ieee80211_vif *vif) { struct ieee80211_local *local = hw_to_local(hw); - struct sk_buff *skb; + struct sk_buff *skb = NULL; + struct ieee80211_tx_info *info; struct net_device *bdev; struct ieee80211_sub_if_data *sdata = NULL; struct ieee80211_if_ap *ap = NULL; + struct ieee80211_if_sta *ifsta = NULL; struct rate_selection rsel; struct beacon_data *beacon; struct ieee80211_supported_band *sband; struct ieee80211_mgmt *mgmt; int *num_beacons; - bool err = true; + enum ieee80211_band band = local->hw.conf.channel->band; u8 *pos; - sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; + sband = local->hw.wiphy->bands[band]; rcu_read_lock(); @@ -1817,9 +1849,6 @@ struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw, memcpy(skb_put(skb, beacon->head_len), beacon->head, beacon->head_len); - ieee80211_include_sequence(sdata, - (struct ieee80211_hdr *)skb->data); - /* * Not very nice, but we want to allow the driver to call * ieee80211_beacon_get() as a response to the set_tim() @@ -1842,9 +1871,24 @@ struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw, beacon->tail, beacon->tail_len); num_beacons = &ap->num_beacons; + } else + goto out; + } else if (sdata->vif.type == IEEE80211_IF_TYPE_IBSS) { + struct ieee80211_hdr *hdr; + ifsta = &sdata->u.sta; - err = false; - } + if (!ifsta->probe_resp) + goto out; + + skb = skb_copy(ifsta->probe_resp, GFP_ATOMIC); + if (!skb) + goto out; + + hdr = (struct ieee80211_hdr *) skb->data; + hdr->frame_control = IEEE80211_FC(IEEE80211_FTYPE_MGMT, + IEEE80211_STYPE_BEACON); + + num_beacons = &ifsta->num_beacons; } else if (ieee80211_vif_is_mesh(&sdata->vif)) { /* headroom, head length, tail length and maximum TIM length */ skb = dev_alloc_skb(local->tx_headroom + 400); @@ -1855,8 +1899,8 @@ struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw, mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24 + sizeof(mgmt->u.beacon)); memset(mgmt, 0, 24 + sizeof(mgmt->u.beacon)); - mgmt->frame_control = IEEE80211_FC(IEEE80211_FTYPE_MGMT, - IEEE80211_STYPE_BEACON); + mgmt->frame_control = + cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_BEACON); memset(mgmt->da, 0xff, ETH_ALEN); memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN); /* BSSID is left zeroed, wildcard value */ @@ -1871,44 +1915,41 @@ struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw, mesh_mgmt_ies_add(skb, sdata->dev); num_beacons = &sdata->u.sta.num_beacons; - - err = false; + } else { + WARN_ON(1); + goto out; } - if (err) { -#ifdef CONFIG_MAC80211_VERBOSE_DEBUG - if (net_ratelimit()) - printk(KERN_DEBUG "no beacon data avail for %s\n", - bdev->name); -#endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ + info = IEEE80211_SKB_CB(skb); + + info->band = band; + rate_control_get_rate(local->mdev, sband, skb, &rsel); + + if (unlikely(rsel.rate_idx < 0)) { + if (net_ratelimit()) { + printk(KERN_DEBUG "%s: ieee80211_beacon_get: " + "no rate found\n", + wiphy_name(local->hw.wiphy)); + } + dev_kfree_skb(skb); skb = NULL; goto out; } - if (control) { - rate_control_get_rate(local->mdev, sband, skb, &rsel); - if (!rsel.rate) { - if (net_ratelimit()) { - printk(KERN_DEBUG "%s: ieee80211_beacon_get: " - "no rate found\n", - wiphy_name(local->hw.wiphy)); - } - dev_kfree_skb(skb); - skb = NULL; - goto out; - } + info->control.vif = vif; + info->tx_rate_idx = rsel.rate_idx; + + info->flags |= IEEE80211_TX_CTL_NO_ACK; + info->flags |= IEEE80211_TX_CTL_DO_NOT_ENCRYPT; + info->flags |= IEEE80211_TX_CTL_CLEAR_PS_FILT; + info->flags |= IEEE80211_TX_CTL_ASSIGN_SEQ; + if (sdata->bss_conf.use_short_preamble && + sband->bitrates[rsel.rate_idx].flags & IEEE80211_RATE_SHORT_PREAMBLE) + info->flags |= IEEE80211_TX_CTL_SHORT_PREAMBLE; + + info->antenna_sel_tx = local->hw.conf.antenna_sel_tx; + info->control.retry_limit = 1; - control->vif = vif; - control->tx_rate = rsel.rate; - if (sdata->bss_conf.use_short_preamble && - rsel.rate->flags & IEEE80211_RATE_SHORT_PREAMBLE) - control->flags |= IEEE80211_TXCTL_SHORT_PREAMBLE; - control->antenna_sel_tx = local->hw.conf.antenna_sel_tx; - control->flags |= IEEE80211_TXCTL_NO_ACK; - control->flags |= IEEE80211_TXCTL_DO_NOT_ENCRYPT; - control->retry_limit = 1; - control->flags |= IEEE80211_TXCTL_CLEAR_PS_FILT; - } (*num_beacons)++; out: rcu_read_unlock(); @@ -1918,14 +1959,13 @@ EXPORT_SYMBOL(ieee80211_beacon_get); void ieee80211_rts_get(struct ieee80211_hw *hw, struct ieee80211_vif *vif, const void *frame, size_t frame_len, - const struct ieee80211_tx_control *frame_txctl, + const struct ieee80211_tx_info *frame_txctl, struct ieee80211_rts *rts) { const struct ieee80211_hdr *hdr = frame; - u16 fctl; - fctl = IEEE80211_FTYPE_CTL | IEEE80211_STYPE_RTS; - rts->frame_control = cpu_to_le16(fctl); + rts->frame_control = + cpu_to_le16(IEEE80211_FTYPE_CTL | IEEE80211_STYPE_RTS); rts->duration = ieee80211_rts_duration(hw, vif, frame_len, frame_txctl); memcpy(rts->ra, hdr->addr1, sizeof(rts->ra)); @@ -1935,14 +1975,13 @@ EXPORT_SYMBOL(ieee80211_rts_get); void ieee80211_ctstoself_get(struct ieee80211_hw *hw, struct ieee80211_vif *vif, const void *frame, size_t frame_len, - const struct ieee80211_tx_control *frame_txctl, + const struct ieee80211_tx_info *frame_txctl, struct ieee80211_cts *cts) { const struct ieee80211_hdr *hdr = frame; - u16 fctl; - fctl = IEEE80211_FTYPE_CTL | IEEE80211_STYPE_CTS; - cts->frame_control = cpu_to_le16(fctl); + cts->frame_control = + cpu_to_le16(IEEE80211_FTYPE_CTL | IEEE80211_STYPE_CTS); cts->duration = ieee80211_ctstoself_duration(hw, vif, frame_len, frame_txctl); memcpy(cts->ra, hdr->addr1, sizeof(cts->ra)); @@ -1951,23 +1990,21 @@ EXPORT_SYMBOL(ieee80211_ctstoself_get); struct sk_buff * ieee80211_get_buffered_bc(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct ieee80211_tx_control *control) + struct ieee80211_vif *vif) { struct ieee80211_local *local = hw_to_local(hw); - struct sk_buff *skb; + struct sk_buff *skb = NULL; struct sta_info *sta; - ieee80211_tx_handler *handler; struct ieee80211_tx_data tx; - ieee80211_tx_result res = TX_DROP; struct net_device *bdev; struct ieee80211_sub_if_data *sdata; struct ieee80211_if_ap *bss = NULL; struct beacon_data *beacon; + struct ieee80211_tx_info *info; sdata = vif_to_sdata(vif); bdev = sdata->dev; - + bss = &sdata->u.ap; if (!bss) return NULL; @@ -1975,19 +2012,16 @@ ieee80211_get_buffered_bc(struct ieee80211_hw *hw, rcu_read_lock(); beacon = rcu_dereference(bss->beacon); - if (sdata->vif.type != IEEE80211_IF_TYPE_AP || !beacon || - !beacon->head) { - rcu_read_unlock(); - return NULL; - } + if (sdata->vif.type != IEEE80211_IF_TYPE_AP || !beacon || !beacon->head) + goto out; if (bss->dtim_count != 0) - return NULL; /* send buffered bc/mc only after DTIM beacon */ - memset(control, 0, sizeof(*control)); + goto out; /* send buffered bc/mc only after DTIM beacon */ + while (1) { skb = skb_dequeue(&bss->ps_bc_buf); if (!skb) - return NULL; + goto out; local->total_ps_buffered--; if (!skb_queue_empty(&bss->ps_bc_buf) && skb->len >= 2) { @@ -2000,30 +2034,21 @@ ieee80211_get_buffered_bc(struct ieee80211_hw *hw, cpu_to_le16(IEEE80211_FCTL_MOREDATA); } - if (!ieee80211_tx_prepare(&tx, skb, local->mdev, control)) + if (!ieee80211_tx_prepare(&tx, skb, local->mdev)) break; dev_kfree_skb_any(skb); } + + info = IEEE80211_SKB_CB(skb); + sta = tx.sta; tx.flags |= IEEE80211_TX_PS_BUFFERED; tx.channel = local->hw.conf.channel; + info->band = tx.channel->band; - for (handler = ieee80211_tx_handlers; *handler != NULL; handler++) { - res = (*handler)(&tx); - if (res == TX_DROP || res == TX_QUEUED) - break; - } - skb = tx.skb; /* handlers are allowed to change skb */ - - if (res == TX_DROP) { - I802_DEBUG_INC(local->tx_handlers_drop); - dev_kfree_skb(skb); - skb = NULL; - } else if (res == TX_QUEUED) { - I802_DEBUG_INC(local->tx_handlers_queued); + if (invoke_tx_handlers(&tx)) skb = NULL; - } - + out: rcu_read_unlock(); return skb; diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 4e97b266f907..19f85e1b3695 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -45,38 +45,37 @@ const unsigned char bridge_tunnel_header[] __aligned(2) = u8 *ieee80211_get_bssid(struct ieee80211_hdr *hdr, size_t len, enum ieee80211_if_types type) { - u16 fc; + __le16 fc = hdr->frame_control; /* drop ACK/CTS frames and incorrect hdr len (ctrl) */ if (len < 16) return NULL; - fc = le16_to_cpu(hdr->frame_control); - - switch (fc & IEEE80211_FCTL_FTYPE) { - case IEEE80211_FTYPE_DATA: + if (ieee80211_is_data(fc)) { if (len < 24) /* drop incorrect hdr len (data) */ return NULL; - switch (fc & (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) { - case IEEE80211_FCTL_TODS: - return hdr->addr1; - case (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS): + + if (ieee80211_has_a4(fc)) return NULL; - case IEEE80211_FCTL_FROMDS: + if (ieee80211_has_tods(fc)) + return hdr->addr1; + if (ieee80211_has_fromds(fc)) return hdr->addr2; - case 0: - return hdr->addr3; - } - break; - case IEEE80211_FTYPE_MGMT: + + return hdr->addr3; + } + + if (ieee80211_is_mgmt(fc)) { if (len < 24) /* drop incorrect hdr len (mgmt) */ return NULL; return hdr->addr3; - case IEEE80211_FTYPE_CTL: - if ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_PSPOLL) + } + + if (ieee80211_is_ctl(fc)) { + if(ieee80211_is_pspoll(fc)) return hdr->addr1; - else if ((fc & IEEE80211_FCTL_STYPE) == - IEEE80211_STYPE_BACK_REQ) { + + if (ieee80211_is_back_req(fc)) { switch (type) { case IEEE80211_IF_TYPE_STA: return hdr->addr2; @@ -84,11 +83,9 @@ u8 *ieee80211_get_bssid(struct ieee80211_hdr *hdr, size_t len, case IEEE80211_IF_TYPE_VLAN: return hdr->addr1; default: - return NULL; + break; /* fall through to the return */ } } - else - return NULL; } return NULL; @@ -133,14 +130,46 @@ int ieee80211_get_hdrlen(u16 fc) } EXPORT_SYMBOL(ieee80211_get_hdrlen); -int ieee80211_get_hdrlen_from_skb(const struct sk_buff *skb) +unsigned int ieee80211_hdrlen(__le16 fc) { - const struct ieee80211_hdr *hdr = (const struct ieee80211_hdr *) skb->data; - int hdrlen; + 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_get_hdrlen(le16_to_cpu(hdr->frame_control)); + hdrlen = ieee80211_hdrlen(hdr->frame_control); if (unlikely(hdrlen > skb->len)) return 0; return hdrlen; @@ -258,7 +287,7 @@ EXPORT_SYMBOL(ieee80211_generic_frame_duration); __le16 ieee80211_rts_duration(struct ieee80211_hw *hw, struct ieee80211_vif *vif, size_t frame_len, - const struct ieee80211_tx_control *frame_txctl) + const struct ieee80211_tx_info *frame_txctl) { struct ieee80211_local *local = hw_to_local(hw); struct ieee80211_rate *rate; @@ -266,10 +295,13 @@ __le16 ieee80211_rts_duration(struct ieee80211_hw *hw, bool short_preamble; int erp; u16 dur; + struct ieee80211_supported_band *sband; + + sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; short_preamble = sdata->bss_conf.use_short_preamble; - rate = frame_txctl->rts_cts_rate; + rate = &sband->bitrates[frame_txctl->control.rts_cts_rate_idx]; erp = 0; if (sdata->flags & IEEE80211_SDATA_OPERATING_GMODE) @@ -292,7 +324,7 @@ EXPORT_SYMBOL(ieee80211_rts_duration); __le16 ieee80211_ctstoself_duration(struct ieee80211_hw *hw, struct ieee80211_vif *vif, size_t frame_len, - const struct ieee80211_tx_control *frame_txctl) + const struct ieee80211_tx_info *frame_txctl) { struct ieee80211_local *local = hw_to_local(hw); struct ieee80211_rate *rate; @@ -300,10 +332,13 @@ __le16 ieee80211_ctstoself_duration(struct ieee80211_hw *hw, bool short_preamble; int erp; u16 dur; + struct ieee80211_supported_band *sband; + + sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; short_preamble = sdata->bss_conf.use_short_preamble; - rate = frame_txctl->rts_cts_rate; + rate = &sband->bitrates[frame_txctl->control.rts_cts_rate_idx]; erp = 0; if (sdata->flags & IEEE80211_SDATA_OPERATING_GMODE) erp = rate->flags & IEEE80211_RATE_ERP_G; @@ -311,7 +346,7 @@ __le16 ieee80211_ctstoself_duration(struct ieee80211_hw *hw, /* Data frame duration */ dur = ieee80211_frame_duration(local, frame_len, rate->bitrate, erp, short_preamble); - if (!(frame_txctl->flags & IEEE80211_TXCTL_NO_ACK)) { + if (!(frame_txctl->flags & IEEE80211_TX_CTL_NO_ACK)) { /* ACK duration */ dur += ieee80211_frame_duration(local, 10, rate->bitrate, erp, short_preamble); @@ -325,17 +360,10 @@ void ieee80211_wake_queue(struct ieee80211_hw *hw, int queue) { struct ieee80211_local *local = hw_to_local(hw); - if (test_and_clear_bit(IEEE80211_LINK_STATE_XOFF, - &local->state[queue])) { - if (test_bit(IEEE80211_LINK_STATE_PENDING, - &local->state[queue])) - tasklet_schedule(&local->tx_pending_tasklet); - else - if (!ieee80211_qdisc_installed(local->mdev)) { - if (queue == 0) - netif_wake_queue(local->mdev); - } else - __netif_schedule(local->mdev); + if (test_bit(queue, local->queues_pending)) { + tasklet_schedule(&local->tx_pending_tasklet); + } else { + netif_wake_subqueue(local->mdev, queue); } } EXPORT_SYMBOL(ieee80211_wake_queue); @@ -344,29 +372,15 @@ void ieee80211_stop_queue(struct ieee80211_hw *hw, int queue) { struct ieee80211_local *local = hw_to_local(hw); - if (!ieee80211_qdisc_installed(local->mdev) && queue == 0) - netif_stop_queue(local->mdev); - set_bit(IEEE80211_LINK_STATE_XOFF, &local->state[queue]); + netif_stop_subqueue(local->mdev, queue); } EXPORT_SYMBOL(ieee80211_stop_queue); -void ieee80211_start_queues(struct ieee80211_hw *hw) -{ - struct ieee80211_local *local = hw_to_local(hw); - int i; - - for (i = 0; i < local->hw.queues; i++) - clear_bit(IEEE80211_LINK_STATE_XOFF, &local->state[i]); - if (!ieee80211_qdisc_installed(local->mdev)) - netif_start_queue(local->mdev); -} -EXPORT_SYMBOL(ieee80211_start_queues); - void ieee80211_stop_queues(struct ieee80211_hw *hw) { int i; - for (i = 0; i < hw->queues; i++) + for (i = 0; i < ieee80211_num_queues(hw); i++) ieee80211_stop_queue(hw, i); } EXPORT_SYMBOL(ieee80211_stop_queues); @@ -375,7 +389,7 @@ void ieee80211_wake_queues(struct ieee80211_hw *hw) { int i; - for (i = 0; i < hw->queues; i++) + for (i = 0; i < hw->queues + hw->ampdu_queues; i++) ieee80211_wake_queue(hw, i); } EXPORT_SYMBOL(ieee80211_wake_queues); @@ -404,8 +418,6 @@ void ieee80211_iterate_active_interfaces( case IEEE80211_IF_TYPE_MESH_POINT: break; } - if (sdata->dev == local->mdev) - continue; if (netif_running(sdata->dev)) iterator(data, sdata->dev->dev_addr, &sdata->vif); @@ -439,8 +451,6 @@ void ieee80211_iterate_active_interfaces_atomic( case IEEE80211_IF_TYPE_MESH_POINT: break; } - if (sdata->dev == local->mdev) - continue; if (netif_running(sdata->dev)) iterator(data, sdata->dev->dev_addr, &sdata->vif); diff --git a/net/mac80211/wep.c b/net/mac80211/wep.c index affcecd78c10..872d2fcd1a5b 100644 --- a/net/mac80211/wep.c +++ b/net/mac80211/wep.c @@ -84,24 +84,17 @@ static u8 *ieee80211_wep_add_iv(struct ieee80211_local *local, struct sk_buff *skb, struct ieee80211_key *key) { - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; - u16 fc; - int hdrlen; + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; + unsigned int hdrlen; u8 *newhdr; - fc = le16_to_cpu(hdr->frame_control); - fc |= IEEE80211_FCTL_PROTECTED; - hdr->frame_control = cpu_to_le16(fc); + hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_PROTECTED); - if ((skb_headroom(skb) < WEP_IV_LEN || - skb_tailroom(skb) < WEP_ICV_LEN)) { - I802_DEBUG_INC(local->tx_expand_skb_head); - if (unlikely(pskb_expand_head(skb, WEP_IV_LEN, WEP_ICV_LEN, - GFP_ATOMIC))) - return NULL; - } + if (WARN_ON(skb_tailroom(skb) < WEP_ICV_LEN || + skb_headroom(skb) < WEP_IV_LEN)) + return NULL; - hdrlen = ieee80211_get_hdrlen(fc); + hdrlen = ieee80211_hdrlen(hdr->frame_control); newhdr = skb_push(skb, WEP_IV_LEN); memmove(newhdr, newhdr + WEP_IV_LEN, hdrlen); ieee80211_wep_get_iv(local, key, newhdr + hdrlen); @@ -113,12 +106,10 @@ static void ieee80211_wep_remove_iv(struct ieee80211_local *local, struct sk_buff *skb, struct ieee80211_key *key) { - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; - u16 fc; - int hdrlen; + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; + unsigned int hdrlen; - fc = le16_to_cpu(hdr->frame_control); - hdrlen = ieee80211_get_hdrlen(fc); + hdrlen = ieee80211_hdrlen(hdr->frame_control); memmove(skb->data + WEP_IV_LEN, skb->data, hdrlen); skb_pull(skb, WEP_IV_LEN); } @@ -228,17 +219,15 @@ int ieee80211_wep_decrypt(struct ieee80211_local *local, struct sk_buff *skb, u32 klen; u8 *rc4key; u8 keyidx; - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; - u16 fc; - int hdrlen; + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; + unsigned int hdrlen; size_t len; int ret = 0; - fc = le16_to_cpu(hdr->frame_control); - if (!(fc & IEEE80211_FCTL_PROTECTED)) + if (!ieee80211_has_protected(hdr->frame_control)) return -1; - hdrlen = ieee80211_get_hdrlen(fc); + hdrlen = ieee80211_hdrlen(hdr->frame_control); if (skb->len < 8 + hdrlen) return -1; @@ -264,11 +253,8 @@ int ieee80211_wep_decrypt(struct ieee80211_local *local, struct sk_buff *skb, if (ieee80211_wep_decrypt_data(local->wep_rx_tfm, rc4key, klen, skb->data + hdrlen + WEP_IV_LEN, - len)) { - if (net_ratelimit()) - printk(KERN_DEBUG "WEP decrypt failed (ICV)\n"); + len)) ret = -1; - } kfree(rc4key); @@ -285,17 +271,15 @@ int ieee80211_wep_decrypt(struct ieee80211_local *local, struct sk_buff *skb, u8 * ieee80211_wep_is_weak_iv(struct sk_buff *skb, struct ieee80211_key *key) { - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; - u16 fc; - int hdrlen; + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; + unsigned int hdrlen; u8 *ivpos; u32 iv; - fc = le16_to_cpu(hdr->frame_control); - if (!(fc & IEEE80211_FCTL_PROTECTED)) + if (!ieee80211_has_protected(hdr->frame_control)) return NULL; - hdrlen = ieee80211_get_hdrlen(fc); + hdrlen = ieee80211_hdrlen(hdr->frame_control); ivpos = skb->data + hdrlen; iv = (ivpos[0] << 16) | (ivpos[1] << 8) | ivpos[2]; @@ -314,14 +298,8 @@ ieee80211_crypto_wep_decrypt(struct ieee80211_rx_data *rx) return RX_CONTINUE; if (!(rx->status->flag & RX_FLAG_DECRYPTED)) { - if (ieee80211_wep_decrypt(rx->local, rx->skb, rx->key)) { -#ifdef CONFIG_MAC80211_DEBUG - if (net_ratelimit()) - printk(KERN_DEBUG "%s: RX WEP frame, decrypt " - "failed\n", rx->dev->name); -#endif /* CONFIG_MAC80211_DEBUG */ + if (ieee80211_wep_decrypt(rx->local, rx->skb, rx->key)) return RX_DROP_UNUSABLE; - } } else if (!(rx->status->flag & RX_FLAG_IV_STRIPPED)) { ieee80211_wep_remove_iv(rx->local, rx->skb, rx->key); /* remove ICV */ @@ -333,11 +311,16 @@ ieee80211_crypto_wep_decrypt(struct ieee80211_rx_data *rx) static int wep_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb) { + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + + info->control.iv_len = WEP_IV_LEN; + info->control.icv_len = WEP_ICV_LEN; + if (!(tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE)) { if (ieee80211_wep_encrypt(tx->local, skb, tx->key)) return -1; } else { - tx->control->key_idx = tx->key->conf.hw_key_idx; + info->control.hw_key = &tx->key->conf; if (tx->key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV) { if (!ieee80211_wep_add_iv(tx->local, skb, tx->key)) return -1; @@ -349,8 +332,6 @@ static int wep_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb) ieee80211_tx_result ieee80211_crypto_wep_encrypt(struct ieee80211_tx_data *tx) { - tx->control->iv_len = WEP_IV_LEN; - tx->control->icv_len = WEP_ICV_LEN; ieee80211_tx_set_protected(tx); if (wep_encrypt_skb(tx, tx->skb) < 0) { diff --git a/net/mac80211/wep.h b/net/mac80211/wep.h index 363779c50658..e587172115b8 100644 --- a/net/mac80211/wep.h +++ b/net/mac80211/wep.h @@ -26,7 +26,7 @@ int ieee80211_wep_encrypt(struct ieee80211_local *local, struct sk_buff *skb, struct ieee80211_key *key); int ieee80211_wep_decrypt(struct ieee80211_local *local, struct sk_buff *skb, struct ieee80211_key *key); -u8 * ieee80211_wep_is_weak_iv(struct sk_buff *skb, struct ieee80211_key *key); +u8 *ieee80211_wep_is_weak_iv(struct sk_buff *skb, struct ieee80211_key *key); ieee80211_rx_result ieee80211_crypto_wep_decrypt(struct ieee80211_rx_data *rx); diff --git a/net/mac80211/wext.c b/net/mac80211/wext.c index e8404212ad57..34fa8ed1e784 100644 --- a/net/mac80211/wext.c +++ b/net/mac80211/wext.c @@ -142,7 +142,39 @@ static int ieee80211_ioctl_giwname(struct net_device *dev, struct iw_request_info *info, char *name, char *extra) { + struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); + struct ieee80211_supported_band *sband; + u8 is_ht = 0, is_a = 0, is_b = 0, is_g = 0; + + + sband = local->hw.wiphy->bands[IEEE80211_BAND_5GHZ]; + if (sband) { + is_a = 1; + is_ht |= sband->ht_info.ht_supported; + } + + sband = local->hw.wiphy->bands[IEEE80211_BAND_2GHZ]; + if (sband) { + int i; + /* Check for mandatory rates */ + for (i = 0; i < sband->n_bitrates; i++) { + if (sband->bitrates[i].bitrate == 10) + is_b = 1; + if (sband->bitrates[i].bitrate == 60) + is_g = 1; + } + is_ht |= sband->ht_info.ht_supported; + } + strcpy(name, "IEEE 802.11"); + if (is_a) + strcat(name, "a"); + if (is_b) + strcat(name, "b"); + if (is_g) + strcat(name, "g"); + if (is_ht) + strcat(name, "n"); return 0; } @@ -176,14 +208,26 @@ static int ieee80211_ioctl_giwrange(struct net_device *dev, range->num_encoding_sizes = 2; range->max_encoding_tokens = NUM_DEFAULT_KEYS; - range->max_qual.qual = local->hw.max_signal; - range->max_qual.level = local->hw.max_rssi; - range->max_qual.noise = local->hw.max_noise; + if (local->hw.flags & IEEE80211_HW_SIGNAL_UNSPEC || + local->hw.flags & IEEE80211_HW_SIGNAL_DB) + range->max_qual.level = local->hw.max_signal; + else if (local->hw.flags & IEEE80211_HW_SIGNAL_DBM) + range->max_qual.level = -110; + else + range->max_qual.level = 0; + + if (local->hw.flags & IEEE80211_HW_NOISE_DBM) + range->max_qual.noise = -110; + else + range->max_qual.noise = 0; + + range->max_qual.qual = 100; range->max_qual.updated = local->wstats_flags; - range->avg_qual.qual = local->hw.max_signal/2; - range->avg_qual.level = 0; - range->avg_qual.noise = 0; + range->avg_qual.qual = 50; + /* not always true but better than nothing */ + range->avg_qual.level = range->max_qual.level / 2; + range->avg_qual.noise = range->max_qual.noise / 2; range->avg_qual.updated = local->wstats_flags; range->enc_capa = IW_ENC_CAPA_WPA | IW_ENC_CAPA_WPA2 | @@ -252,15 +296,7 @@ static int ieee80211_ioctl_siwmode(struct net_device *dev, return -EINVAL; } - if (type == sdata->vif.type) - return 0; - if (netif_running(dev)) - return -EBUSY; - - ieee80211_if_reinit(dev); - ieee80211_if_set_type(dev, type); - - return 0; + return ieee80211_if_change_type(sdata, type); } @@ -408,7 +444,7 @@ static int ieee80211_ioctl_siwessid(struct net_device *dev, memset(sdata->u.ap.ssid + len, 0, IEEE80211_MAX_SSID_LEN - len); sdata->u.ap.ssid_len = len; - return ieee80211_if_config(dev); + return ieee80211_if_config(sdata, IEEE80211_IFCC_SSID); } return -EOPNOTSUPP; } @@ -562,7 +598,7 @@ static int ieee80211_ioctl_giwscan(struct net_device *dev, if (local->sta_sw_scanning || local->sta_hw_scanning) return -EAGAIN; - res = ieee80211_sta_scan_results(dev, extra, data->length); + res = ieee80211_sta_scan_results(dev, info, extra, data->length); if (res >= 0) { data->length = res; return 0; @@ -583,16 +619,14 @@ static int ieee80211_ioctl_siwrate(struct net_device *dev, struct ieee80211_supported_band *sband; sdata = IEEE80211_DEV_TO_SUB_IF(dev); - if (!sdata->bss) - return -ENODEV; sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; /* target_rate = -1, rate->fixed = 0 means auto only, so use all rates * target_rate = X, rate->fixed = 1 means only rate X * target_rate = X, rate->fixed = 0 means all rates <= X */ - sdata->bss->max_ratectrl_rateidx = -1; - sdata->bss->force_unicast_rateidx = -1; + sdata->max_ratectrl_rateidx = -1; + sdata->force_unicast_rateidx = -1; if (rate->value < 0) return 0; @@ -601,9 +635,9 @@ static int ieee80211_ioctl_siwrate(struct net_device *dev, int this_rate = brate->bitrate; if (target_rate == this_rate) { - sdata->bss->max_ratectrl_rateidx = i; + sdata->max_ratectrl_rateidx = i; if (rate->fixed) - sdata->bss->force_unicast_rateidx = i; + sdata->force_unicast_rateidx = i; err = 0; break; } @@ -716,6 +750,9 @@ static int ieee80211_ioctl_siwrts(struct net_device *dev, 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 @@ -753,6 +790,8 @@ static int ieee80211_ioctl_siwfrag(struct net_device *dev, 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; @@ -944,6 +983,58 @@ static int ieee80211_ioctl_giwencode(struct net_device *dev, erq->length = sdata->keys[idx]->conf.keylen; erq->flags |= IW_ENCODE_ENABLED; + if (sdata->vif.type == IEEE80211_IF_TYPE_STA) { + struct ieee80211_if_sta *ifsta = &sdata->u.sta; + switch (ifsta->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, + char *extra) +{ + struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); + struct ieee80211_conf *conf = &local->hw.conf; + + if (wrq->disabled) { + conf->flags &= ~IEEE80211_CONF_PS; + return ieee80211_hw_config(local); + } + + switch (wrq->flags & IW_POWER_MODE) { + case IW_POWER_ON: /* If not specified */ + case IW_POWER_MODE: /* If set all mask */ + case IW_POWER_ALL_R: /* If explicitely state all */ + conf->flags |= IEEE80211_CONF_PS; + break; + default: /* Otherwise we don't support it */ + return -EINVAL; + } + + return ieee80211_hw_config(local); +} + +static int ieee80211_ioctl_giwpower(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); + struct ieee80211_conf *conf = &local->hw.conf; + + wrqu->power.disabled = !(conf->flags & IEEE80211_CONF_PS); + return 0; } @@ -1015,8 +1106,8 @@ static struct iw_statistics *ieee80211_get_wireless_stats(struct net_device *dev wstats->qual.noise = 0; wstats->qual.updated = IW_QUAL_ALL_INVALID; } else { - wstats->qual.level = sta->last_rssi; - wstats->qual.qual = sta->last_signal; + wstats->qual.level = sta->last_signal; + wstats->qual.qual = sta->last_qual; wstats->qual.noise = sta->last_noise; wstats->qual.updated = local->wstats_flags; } @@ -1149,8 +1240,8 @@ static const iw_handler ieee80211_handler[] = (iw_handler) ieee80211_ioctl_giwretry, /* SIOCGIWRETRY */ (iw_handler) ieee80211_ioctl_siwencode, /* SIOCSIWENCODE */ (iw_handler) ieee80211_ioctl_giwencode, /* SIOCGIWENCODE */ - (iw_handler) NULL, /* SIOCSIWPOWER */ - (iw_handler) NULL, /* SIOCGIWPOWER */ + (iw_handler) ieee80211_ioctl_siwpower, /* SIOCSIWPOWER */ + (iw_handler) ieee80211_ioctl_giwpower, /* SIOCGIWPOWER */ (iw_handler) NULL, /* -- hole -- */ (iw_handler) NULL, /* -- hole -- */ (iw_handler) ieee80211_ioctl_siwgenie, /* SIOCSIWGENIE */ diff --git a/net/mac80211/wme.c b/net/mac80211/wme.c index 5d09e8698b57..07edda0b8a5c 100644 --- a/net/mac80211/wme.c +++ b/net/mac80211/wme.c @@ -18,61 +18,42 @@ #include "ieee80211_i.h" #include "wme.h" -/* maximum number of hardware queues we support. */ -#define TC_80211_MAX_QUEUES 16 - +/* Default mapping in classifier to work with default + * queue setup. + */ const int ieee802_1d_to_ac[8] = { 2, 3, 3, 2, 1, 1, 0, 0 }; -struct ieee80211_sched_data -{ - unsigned long qdisc_pool[BITS_TO_LONGS(TC_80211_MAX_QUEUES)]; - struct tcf_proto *filter_list; - struct Qdisc *queues[TC_80211_MAX_QUEUES]; - struct sk_buff_head requeued[TC_80211_MAX_QUEUES]; -}; - 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 inline unsigned classify_1d(struct sk_buff *skb, struct Qdisc *qd) +/* Given a data frame determine the 802.1p/1d tag to use. */ +static unsigned int classify_1d(struct sk_buff *skb) { - struct iphdr *ip; - int dscp; - int offset; - - struct ieee80211_sched_data *q = qdisc_priv(qd); - struct tcf_result res = { -1, 0 }; - - /* if there is a user set filter list, call out to that */ - if (q->filter_list) { - tc_classify(skb, q->filter_list, &res); - if (res.class != -1) - return res.class; - } + 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. */ + * 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; - /* check there is a valid IP header present */ - offset = ieee80211_get_hdrlen_from_skb(skb); - if (skb->len < offset + sizeof(llc_ip_hdr) + sizeof(*ip) || - memcmp(skb->data + offset, llc_ip_hdr, sizeof(llc_ip_hdr))) - return 0; + switch (skb->protocol) { + case __constant_htons(ETH_P_IP): + dscp = ip_hdr(skb)->tos & 0xfc; + break; - ip = (struct iphdr *) (skb->data + offset + sizeof(llc_ip_hdr)); + default: + return 0; + } - dscp = ip->tos & 0xfc; if (dscp & 0x1c) return 0; return dscp >> 5; } -static inline int wme_downgrade_ac(struct sk_buff *skb) +static int wme_downgrade_ac(struct sk_buff *skb) { switch (skb->priority) { case 6: @@ -93,43 +74,38 @@ static inline int wme_downgrade_ac(struct sk_buff *skb) } -/* positive return value indicates which queue to use - * negative return value indicates to drop the frame */ -static inline int classify80211(struct sk_buff *skb, struct Qdisc *qd) +/* Indicate which queue to use. */ +static u16 classify80211(struct sk_buff *skb, struct net_device *dev) { - struct ieee80211_local *local = wdev_priv(qd->dev->ieee80211_ptr); + struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; - unsigned short fc = le16_to_cpu(hdr->frame_control); - int qos; - /* see if frame is data or non data frame */ - if (unlikely((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA)) { + if (!ieee80211_is_data(hdr->frame_control)) { /* management frames go on AC_VO queue, but are sent * without QoS control fields */ - return IEEE80211_TX_QUEUE_DATA0; + return 0; } if (0 /* injected */) { /* use AC from radiotap */ } - /* is this a QoS frame? */ - qos = fc & IEEE80211_STYPE_QOS_DATA; - - if (!qos) { + if (!ieee80211_is_data_qos(hdr->frame_control)) { skb->priority = 0; /* required for correct WPA/11i MIC */ return ieee802_1d_to_ac[skb->priority]; } /* use the data classifier to determine what 802.1d tag the * data frame has */ - skb->priority = classify_1d(skb, qd); + skb->priority = classify_1d(skb); /* in case we are a client verify acm is not set for this ac */ while (unlikely(local->wmm_acm & BIT(skb->priority))) { if (wme_downgrade_ac(skb)) { - /* No AC with lower priority has acm=0, drop packet. */ - return -1; + /* The old code would drop the packet in this + * case. + */ + return 0; } } @@ -137,55 +113,52 @@ static inline int classify80211(struct sk_buff *skb, struct Qdisc *qd) return ieee802_1d_to_ac[skb->priority]; } - -static int wme_qdiscop_enqueue(struct sk_buff *skb, struct Qdisc* qd) +u16 ieee80211_select_queue(struct net_device *dev, struct sk_buff *skb) { - struct ieee80211_local *local = wdev_priv(qd->dev->ieee80211_ptr); - struct ieee80211_sched_data *q = qdisc_priv(qd); - struct ieee80211_tx_packet_data *pkt_data = - (struct ieee80211_tx_packet_data *) skb->cb; struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; - unsigned short fc = le16_to_cpu(hdr->frame_control); - struct Qdisc *qdisc; - int err, queue; + struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct sta_info *sta; + u16 queue; u8 tid; - if (pkt_data->flags & IEEE80211_TXPD_REQUEUE) { - queue = pkt_data->queue; + queue = classify80211(skb, dev); + if (unlikely(queue >= local->hw.queues)) + queue = local->hw.queues - 1; + + if (info->flags & IEEE80211_TX_CTL_REQUEUE) { rcu_read_lock(); sta = sta_info_get(local, hdr->addr1); - tid = skb->priority & QOS_CONTROL_TAG1D_MASK; + tid = skb->priority & IEEE80211_QOS_CTL_TAG1D_MASK; if (sta) { + struct ieee80211_hw *hw = &local->hw; int ampdu_queue = sta->tid_to_tx_q[tid]; - if ((ampdu_queue < local->hw.queues) && - test_bit(ampdu_queue, q->qdisc_pool)) { + + if ((ampdu_queue < ieee80211_num_queues(hw)) && + test_bit(ampdu_queue, local->queue_pool)) { queue = ampdu_queue; - pkt_data->flags |= IEEE80211_TXPD_AMPDU; + info->flags |= IEEE80211_TX_CTL_AMPDU; } else { - pkt_data->flags &= ~IEEE80211_TXPD_AMPDU; + info->flags &= ~IEEE80211_TX_CTL_AMPDU; } } rcu_read_unlock(); - skb_queue_tail(&q->requeued[queue], skb); - qd->q.qlen++; - return 0; - } - queue = classify80211(skb, qd); + return queue; + } - /* now we know the 1d priority, fill in the QoS header if there is one + /* Now we know the 1d priority, fill in the QoS header if + * there is one. */ - if (WLAN_FC_IS_QOS_DATA(fc)) { - u8 *p = skb->data + ieee80211_get_hdrlen(fc) - 2; + if (ieee80211_is_data_qos(hdr->frame_control)) { + u8 *p = ieee80211_get_qos_ctl(hdr); u8 ack_policy = 0; - tid = skb->priority & QOS_CONTROL_TAG1D_MASK; + tid = skb->priority & IEEE80211_QOS_CTL_TAG1D_MASK; if (local->wifi_wme_noack_test) ack_policy |= QOS_CONTROL_ACK_POLICY_NOACK << QOS_CONTROL_ACK_POLICY_SHIFT; /* qos header is 2 bytes, second reserved */ - *p = ack_policy | tid; - p++; + *p++ = ack_policy | tid; *p = 0; rcu_read_lock(); @@ -193,475 +166,37 @@ static int wme_qdiscop_enqueue(struct sk_buff *skb, struct Qdisc* qd) sta = sta_info_get(local, hdr->addr1); if (sta) { int ampdu_queue = sta->tid_to_tx_q[tid]; - if ((ampdu_queue < local->hw.queues) && - test_bit(ampdu_queue, q->qdisc_pool)) { + struct ieee80211_hw *hw = &local->hw; + + if ((ampdu_queue < ieee80211_num_queues(hw)) && + test_bit(ampdu_queue, local->queue_pool)) { queue = ampdu_queue; - pkt_data->flags |= IEEE80211_TXPD_AMPDU; + info->flags |= IEEE80211_TX_CTL_AMPDU; } else { - pkt_data->flags &= ~IEEE80211_TXPD_AMPDU; + info->flags &= ~IEEE80211_TX_CTL_AMPDU; } } rcu_read_unlock(); } - if (unlikely(queue >= local->hw.queues)) { -#if 0 - if (net_ratelimit()) { - printk(KERN_DEBUG "%s - queue=%d (hw does not " - "support) -> %d\n", - __func__, queue, local->hw.queues - 1); - } -#endif - queue = local->hw.queues - 1; - } - - if (unlikely(queue < 0)) { - kfree_skb(skb); - err = NET_XMIT_DROP; - } else { - tid = skb->priority & QOS_CONTROL_TAG1D_MASK; - pkt_data->queue = (unsigned int) queue; - qdisc = q->queues[queue]; - err = qdisc->enqueue(skb, qdisc); - if (err == NET_XMIT_SUCCESS) { - qd->q.qlen++; - qd->bstats.bytes += skb->len; - qd->bstats.packets++; - return NET_XMIT_SUCCESS; - } - } - qd->qstats.drops++; - return err; -} - - -/* TODO: clean up the cases where master_hard_start_xmit - * returns non 0 - it shouldn't ever do that. Once done we - * can remove this function */ -static int wme_qdiscop_requeue(struct sk_buff *skb, struct Qdisc* qd) -{ - struct ieee80211_sched_data *q = qdisc_priv(qd); - struct ieee80211_tx_packet_data *pkt_data = - (struct ieee80211_tx_packet_data *) skb->cb; - struct Qdisc *qdisc; - int err; - - /* we recorded which queue to use earlier! */ - qdisc = q->queues[pkt_data->queue]; - - if ((err = qdisc->ops->requeue(skb, qdisc)) == 0) { - qd->q.qlen++; - return 0; - } - qd->qstats.drops++; - return err; -} - - -static struct sk_buff *wme_qdiscop_dequeue(struct Qdisc* qd) -{ - struct ieee80211_sched_data *q = qdisc_priv(qd); - struct net_device *dev = qd->dev; - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - struct ieee80211_hw *hw = &local->hw; - struct sk_buff *skb; - struct Qdisc *qdisc; - int queue; - - /* check all the h/w queues in numeric/priority order */ - for (queue = 0; queue < hw->queues; queue++) { - /* see if there is room in this hardware queue */ - if ((test_bit(IEEE80211_LINK_STATE_XOFF, - &local->state[queue])) || - (test_bit(IEEE80211_LINK_STATE_PENDING, - &local->state[queue])) || - (!test_bit(queue, q->qdisc_pool))) - continue; - - /* there is space - try and get a frame */ - skb = skb_dequeue(&q->requeued[queue]); - if (skb) { - qd->q.qlen--; - return skb; - } - - qdisc = q->queues[queue]; - skb = qdisc->dequeue(qdisc); - if (skb) { - qd->q.qlen--; - return skb; - } - } - /* returning a NULL here when all the h/w queues are full means we - * never need to call netif_stop_queue in the driver */ - return NULL; -} - - -static void wme_qdiscop_reset(struct Qdisc* qd) -{ - struct ieee80211_sched_data *q = qdisc_priv(qd); - struct ieee80211_local *local = wdev_priv(qd->dev->ieee80211_ptr); - struct ieee80211_hw *hw = &local->hw; - int queue; - - /* QUESTION: should we have some hardware flush functionality here? */ - - for (queue = 0; queue < hw->queues; queue++) { - skb_queue_purge(&q->requeued[queue]); - qdisc_reset(q->queues[queue]); - } - qd->q.qlen = 0; -} - - -static void wme_qdiscop_destroy(struct Qdisc* qd) -{ - struct ieee80211_sched_data *q = qdisc_priv(qd); - struct ieee80211_local *local = wdev_priv(qd->dev->ieee80211_ptr); - struct ieee80211_hw *hw = &local->hw; - int queue; - - tcf_destroy_chain(&q->filter_list); - - for (queue=0; queue < hw->queues; queue++) { - skb_queue_purge(&q->requeued[queue]); - qdisc_destroy(q->queues[queue]); - q->queues[queue] = &noop_qdisc; - } -} - - -/* called whenever parameters are updated on existing qdisc */ -static int wme_qdiscop_tune(struct Qdisc *qd, struct nlattr *opt) -{ -/* struct ieee80211_sched_data *q = qdisc_priv(qd); -*/ - /* check our options block is the right size */ - /* copy any options to our local structure */ -/* Ignore options block for now - always use static mapping - struct tc_ieee80211_qopt *qopt = nla_data(opt); - - if (opt->nla_len < nla_attr_size(sizeof(*qopt))) - return -EINVAL; - memcpy(q->tag2queue, qopt->tag2queue, sizeof(qopt->tag2queue)); -*/ - return 0; -} - - -/* called during initial creation of qdisc on device */ -static int wme_qdiscop_init(struct Qdisc *qd, struct nlattr *opt) -{ - struct ieee80211_sched_data *q = qdisc_priv(qd); - struct net_device *dev = qd->dev; - struct ieee80211_local *local; - int queues; - int err = 0, i; - - /* check that device is a mac80211 device */ - if (!dev->ieee80211_ptr || - dev->ieee80211_ptr->wiphy->privid != mac80211_wiphy_privid) - return -EINVAL; - - /* check this device is an ieee80211 master type device */ - if (dev->type != ARPHRD_IEEE80211) - return -EINVAL; - - /* check that there is no qdisc currently attached to device - * this ensures that we will be the root qdisc. (I can't find a better - * way to test this explicitly) */ - if (dev->qdisc_sleeping != &noop_qdisc) - return -EINVAL; - - if (qd->flags & TCQ_F_INGRESS) - return -EINVAL; - - local = wdev_priv(dev->ieee80211_ptr); - queues = local->hw.queues; - - /* if options were passed in, set them */ - if (opt) { - err = wme_qdiscop_tune(qd, opt); - } - - /* create child queues */ - for (i = 0; i < queues; i++) { - skb_queue_head_init(&q->requeued[i]); - q->queues[i] = qdisc_create_dflt(qd->dev, &pfifo_qdisc_ops, - qd->handle); - if (!q->queues[i]) { - q->queues[i] = &noop_qdisc; - printk(KERN_ERR "%s child qdisc %i creation failed\n", - dev->name, i); - } - } - - /* reserve all legacy QoS queues */ - for (i = 0; i < min(IEEE80211_TX_QUEUE_DATA4, queues); i++) - set_bit(i, q->qdisc_pool); - - return err; -} - -static int wme_qdiscop_dump(struct Qdisc *qd, struct sk_buff *skb) -{ -/* struct ieee80211_sched_data *q = qdisc_priv(qd); - unsigned char *p = skb->tail; - struct tc_ieee80211_qopt opt; - - memcpy(&opt.tag2queue, q->tag2queue, TC_80211_MAX_TAG + 1); - NLA_PUT(skb, TCA_OPTIONS, sizeof(opt), &opt); -*/ return skb->len; -/* -nla_put_failure: - skb_trim(skb, p - skb->data);*/ - return -1; -} - - -static int wme_classop_graft(struct Qdisc *qd, unsigned long arg, - struct Qdisc *new, struct Qdisc **old) -{ - struct ieee80211_sched_data *q = qdisc_priv(qd); - struct ieee80211_local *local = wdev_priv(qd->dev->ieee80211_ptr); - struct ieee80211_hw *hw = &local->hw; - unsigned long queue = arg - 1; - - if (queue >= hw->queues) - return -EINVAL; - - if (!new) - new = &noop_qdisc; - - sch_tree_lock(qd); - *old = q->queues[queue]; - q->queues[queue] = new; - qdisc_reset(*old); - sch_tree_unlock(qd); - - return 0; -} - - -static struct Qdisc * -wme_classop_leaf(struct Qdisc *qd, unsigned long arg) -{ - struct ieee80211_sched_data *q = qdisc_priv(qd); - struct ieee80211_local *local = wdev_priv(qd->dev->ieee80211_ptr); - struct ieee80211_hw *hw = &local->hw; - unsigned long queue = arg - 1; - - if (queue >= hw->queues) - return NULL; - - return q->queues[queue]; -} - - -static unsigned long wme_classop_get(struct Qdisc *qd, u32 classid) -{ - struct ieee80211_local *local = wdev_priv(qd->dev->ieee80211_ptr); - struct ieee80211_hw *hw = &local->hw; - unsigned long queue = TC_H_MIN(classid); - - if (queue - 1 >= hw->queues) - return 0; - return queue; } - -static unsigned long wme_classop_bind(struct Qdisc *qd, unsigned long parent, - u32 classid) -{ - return wme_classop_get(qd, classid); -} - - -static void wme_classop_put(struct Qdisc *q, unsigned long cl) -{ -} - - -static int wme_classop_change(struct Qdisc *qd, u32 handle, u32 parent, - struct nlattr **tca, unsigned long *arg) -{ - unsigned long cl = *arg; - struct ieee80211_local *local = wdev_priv(qd->dev->ieee80211_ptr); - struct ieee80211_hw *hw = &local->hw; - - if (cl - 1 > hw->queues) - return -ENOENT; - - /* TODO: put code to program hardware queue parameters here, - * to allow programming from tc command line */ - - return 0; -} - - -/* we don't support deleting hardware queues - * when we add WMM-SA support - TSPECs may be deleted here */ -static int wme_classop_delete(struct Qdisc *qd, unsigned long cl) -{ - struct ieee80211_local *local = wdev_priv(qd->dev->ieee80211_ptr); - struct ieee80211_hw *hw = &local->hw; - - if (cl - 1 > hw->queues) - return -ENOENT; - return 0; -} - - -static int wme_classop_dump_class(struct Qdisc *qd, unsigned long cl, - struct sk_buff *skb, struct tcmsg *tcm) -{ - struct ieee80211_sched_data *q = qdisc_priv(qd); - struct ieee80211_local *local = wdev_priv(qd->dev->ieee80211_ptr); - struct ieee80211_hw *hw = &local->hw; - - if (cl - 1 > hw->queues) - return -ENOENT; - tcm->tcm_handle = TC_H_MIN(cl); - tcm->tcm_parent = qd->handle; - tcm->tcm_info = q->queues[cl-1]->handle; /* do we need this? */ - return 0; -} - - -static void wme_classop_walk(struct Qdisc *qd, struct qdisc_walker *arg) -{ - struct ieee80211_local *local = wdev_priv(qd->dev->ieee80211_ptr); - struct ieee80211_hw *hw = &local->hw; - int queue; - - if (arg->stop) - return; - - for (queue = 0; queue < hw->queues; queue++) { - if (arg->count < arg->skip) { - arg->count++; - continue; - } - /* we should return classids for our internal queues here - * as well as the external ones */ - if (arg->fn(qd, queue+1, arg) < 0) { - arg->stop = 1; - break; - } - arg->count++; - } -} - - -static struct tcf_proto ** wme_classop_find_tcf(struct Qdisc *qd, - unsigned long cl) -{ - struct ieee80211_sched_data *q = qdisc_priv(qd); - - if (cl) - return NULL; - - return &q->filter_list; -} - - -/* this qdisc is classful (i.e. has classes, some of which may have leaf qdiscs attached) - * - these are the operations on the classes */ -static const struct Qdisc_class_ops class_ops = -{ - .graft = wme_classop_graft, - .leaf = wme_classop_leaf, - - .get = wme_classop_get, - .put = wme_classop_put, - .change = wme_classop_change, - .delete = wme_classop_delete, - .walk = wme_classop_walk, - - .tcf_chain = wme_classop_find_tcf, - .bind_tcf = wme_classop_bind, - .unbind_tcf = wme_classop_put, - - .dump = wme_classop_dump_class, -}; - - -/* queueing discipline operations */ -static struct Qdisc_ops wme_qdisc_ops __read_mostly = -{ - .next = NULL, - .cl_ops = &class_ops, - .id = "ieee80211", - .priv_size = sizeof(struct ieee80211_sched_data), - - .enqueue = wme_qdiscop_enqueue, - .dequeue = wme_qdiscop_dequeue, - .requeue = wme_qdiscop_requeue, - .drop = NULL, /* drop not needed since we are always the root qdisc */ - - .init = wme_qdiscop_init, - .reset = wme_qdiscop_reset, - .destroy = wme_qdiscop_destroy, - .change = wme_qdiscop_tune, - - .dump = wme_qdiscop_dump, -}; - - -void ieee80211_install_qdisc(struct net_device *dev) -{ - struct Qdisc *qdisc; - - qdisc = qdisc_create_dflt(dev, &wme_qdisc_ops, TC_H_ROOT); - if (!qdisc) { - printk(KERN_ERR "%s: qdisc installation failed\n", dev->name); - return; - } - - /* same handle as would be allocated by qdisc_alloc_handle() */ - qdisc->handle = 0x80010000; - - qdisc_lock_tree(dev); - list_add_tail(&qdisc->list, &dev->qdisc_list); - dev->qdisc_sleeping = qdisc; - qdisc_unlock_tree(dev); -} - - -int ieee80211_qdisc_installed(struct net_device *dev) -{ - return dev->qdisc_sleeping->ops == &wme_qdisc_ops; -} - - -int ieee80211_wme_register(void) -{ - return register_qdisc(&wme_qdisc_ops); -} - - -void ieee80211_wme_unregister(void) -{ - unregister_qdisc(&wme_qdisc_ops); -} - int ieee80211_ht_agg_queue_add(struct ieee80211_local *local, - struct sta_info *sta, u16 tid) + struct sta_info *sta, u16 tid) { int i; - struct ieee80211_sched_data *q = - qdisc_priv(local->mdev->qdisc_sleeping); - DECLARE_MAC_BUF(mac); /* prepare the filter and save it for the SW queue - * matching the recieved HW queue */ + * matching the received HW queue */ + + if (!local->hw.ampdu_queues) + return -EPERM; /* try to get a Qdisc from the pool */ - for (i = IEEE80211_TX_QUEUE_BEACON; i < local->hw.queues; i++) - if (!test_and_set_bit(i, q->qdisc_pool)) { + for (i = local->hw.queues; i < ieee80211_num_queues(&local->hw); i++) + if (!test_and_set_bit(i, local->queue_pool)) { ieee80211_stop_queue(local_to_hw(local), i); sta->tid_to_tx_q[tid] = i; @@ -670,11 +205,13 @@ int ieee80211_ht_agg_queue_add(struct ieee80211_local *local, * on the previous queue * since HT is strict in order */ #ifdef CONFIG_MAC80211_HT_DEBUG - if (net_ratelimit()) + if (net_ratelimit()) { + DECLARE_MAC_BUF(mac); printk(KERN_DEBUG "allocated aggregation queue" " %d tid %d addr %s pool=0x%lX\n", i, tid, print_mac(mac, sta->addr), - q->qdisc_pool[0]); + local->queue_pool[0]); + } #endif /* CONFIG_MAC80211_HT_DEBUG */ return 0; } @@ -683,44 +220,79 @@ int ieee80211_ht_agg_queue_add(struct ieee80211_local *local, } /** - * the caller needs to hold local->mdev->queue_lock + * the caller needs to hold netdev_get_tx_queue(local->mdev, X)->lock */ void ieee80211_ht_agg_queue_remove(struct ieee80211_local *local, struct sta_info *sta, u16 tid, u8 requeue) { - struct ieee80211_sched_data *q = - qdisc_priv(local->mdev->qdisc_sleeping); int agg_queue = sta->tid_to_tx_q[tid]; + struct ieee80211_hw *hw = &local->hw; /* return the qdisc to the pool */ - clear_bit(agg_queue, q->qdisc_pool); - sta->tid_to_tx_q[tid] = local->hw.queues; + clear_bit(agg_queue, local->queue_pool); + sta->tid_to_tx_q[tid] = ieee80211_num_queues(hw); - if (requeue) + if (requeue) { ieee80211_requeue(local, agg_queue); - else - q->queues[agg_queue]->ops->reset(q->queues[agg_queue]); + } else { + struct netdev_queue *txq; + spinlock_t *root_lock; + + txq = netdev_get_tx_queue(local->mdev, agg_queue); + root_lock = qdisc_root_lock(txq->qdisc); + + spin_lock_bh(root_lock); + qdisc_reset(txq->qdisc); + spin_unlock_bh(root_lock); + } } void ieee80211_requeue(struct ieee80211_local *local, int queue) { - struct Qdisc *root_qd = local->mdev->qdisc_sleeping; - struct ieee80211_sched_data *q = qdisc_priv(root_qd); - struct Qdisc *qdisc = q->queues[queue]; - struct sk_buff *skb = NULL; + struct netdev_queue *txq = netdev_get_tx_queue(local->mdev, queue); + struct sk_buff_head list; + spinlock_t *root_lock; + struct Qdisc *qdisc; u32 len; + rcu_read_lock_bh(); + + qdisc = rcu_dereference(txq->qdisc); if (!qdisc || !qdisc->dequeue) - return; + goto out_unlock; + + skb_queue_head_init(&list); - printk(KERN_DEBUG "requeue: qlen = %d\n", qdisc->q.qlen); + root_lock = qdisc_root_lock(qdisc); + spin_lock(root_lock); for (len = qdisc->q.qlen; len > 0; len--) { - skb = qdisc->dequeue(qdisc); - root_qd->q.qlen--; - /* packet will be classified again and */ - /* skb->packet_data->queue will be overridden if needed */ + struct sk_buff *skb = qdisc->dequeue(qdisc); + if (skb) - wme_qdiscop_enqueue(skb, root_qd); + __skb_queue_tail(&list, skb); + } + spin_unlock(root_lock); + + for (len = list.qlen; len > 0; len--) { + struct sk_buff *skb = __skb_dequeue(&list); + u16 new_queue; + + BUG_ON(!skb); + new_queue = ieee80211_select_queue(local->mdev, skb); + skb_set_queue_mapping(skb, new_queue); + + txq = netdev_get_tx_queue(local->mdev, new_queue); + + + qdisc = rcu_dereference(txq->qdisc); + root_lock = qdisc_root_lock(qdisc); + + spin_lock(root_lock); + qdisc_enqueue_root(skb, qdisc); + spin_unlock(root_lock); } + +out_unlock: + rcu_read_unlock_bh(); } diff --git a/net/mac80211/wme.h b/net/mac80211/wme.h index fcc6b05508cc..04de28c071a6 100644 --- a/net/mac80211/wme.h +++ b/net/mac80211/wme.h @@ -19,57 +19,16 @@ #define QOS_CONTROL_ACK_POLICY_NORMAL 0 #define QOS_CONTROL_ACK_POLICY_NOACK 1 -#define QOS_CONTROL_TID_MASK 0x0f #define QOS_CONTROL_ACK_POLICY_SHIFT 5 -#define QOS_CONTROL_TAG1D_MASK 0x07 - extern const int ieee802_1d_to_ac[8]; -static inline int WLAN_FC_IS_QOS_DATA(u16 fc) -{ - return (fc & 0x8C) == 0x88; -} - -#ifdef CONFIG_NET_SCHED -void ieee80211_install_qdisc(struct net_device *dev); -int ieee80211_qdisc_installed(struct net_device *dev); +u16 ieee80211_select_queue(struct net_device *dev, struct sk_buff *skb); int ieee80211_ht_agg_queue_add(struct ieee80211_local *local, struct sta_info *sta, u16 tid); void ieee80211_ht_agg_queue_remove(struct ieee80211_local *local, struct sta_info *sta, u16 tid, u8 requeue); void ieee80211_requeue(struct ieee80211_local *local, int queue); -int ieee80211_wme_register(void); -void ieee80211_wme_unregister(void); -#else -static inline void ieee80211_install_qdisc(struct net_device *dev) -{ -} -static inline int ieee80211_qdisc_installed(struct net_device *dev) -{ - return 0; -} -static inline int ieee80211_ht_agg_queue_add(struct ieee80211_local *local, - struct sta_info *sta, u16 tid) -{ - return -EAGAIN; -} -static inline void ieee80211_ht_agg_queue_remove(struct ieee80211_local *local, - struct sta_info *sta, u16 tid, - u8 requeue) -{ -} -static inline void ieee80211_requeue(struct ieee80211_local *local, int queue) -{ -} -static inline int ieee80211_wme_register(void) -{ - return 0; -} -static inline void ieee80211_wme_unregister(void) -{ -} -#endif /* CONFIG_NET_SCHED */ #endif /* _WME_H */ diff --git a/net/mac80211/wpa.c b/net/mac80211/wpa.c index 45709ada8fee..2f33df0dcccf 100644 --- a/net/mac80211/wpa.c +++ b/net/mac80211/wpa.c @@ -11,6 +11,8 @@ #include <linux/slab.h> #include <linux/skbuff.h> #include <linux/compiler.h> +#include <linux/ieee80211.h> +#include <asm/unaligned.h> #include <net/mac80211.h> #include "ieee80211_i.h" @@ -19,76 +21,30 @@ #include "aes_ccm.h" #include "wpa.h" -static int ieee80211_get_hdr_info(const struct sk_buff *skb, u8 **sa, u8 **da, - u8 *qos_tid, u8 **data, size_t *data_len) -{ - struct ieee80211_hdr *hdr; - size_t hdrlen; - u16 fc; - int a4_included; - u8 *pos; - - hdr = (struct ieee80211_hdr *) skb->data; - fc = le16_to_cpu(hdr->frame_control); - - hdrlen = 24; - if ((fc & (IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS)) == - (IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS)) { - hdrlen += ETH_ALEN; - *sa = hdr->addr4; - *da = hdr->addr3; - } else if (fc & IEEE80211_FCTL_FROMDS) { - *sa = hdr->addr3; - *da = hdr->addr1; - } else if (fc & IEEE80211_FCTL_TODS) { - *sa = hdr->addr2; - *da = hdr->addr3; - } else { - *sa = hdr->addr2; - *da = hdr->addr1; - } - - if (fc & 0x80) - hdrlen += 2; - - *data = skb->data + hdrlen; - *data_len = skb->len - hdrlen; - - a4_included = (fc & (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) == - (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS); - if ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA && - fc & IEEE80211_STYPE_QOS_DATA) { - pos = (u8 *) &hdr->addr4; - if (a4_included) - pos += 6; - *qos_tid = pos[0] & 0x0f; - *qos_tid |= 0x80; /* qos_included flag */ - } else - *qos_tid = 0; - - return skb->len < hdrlen ? -1 : 0; -} - - ieee80211_tx_result ieee80211_tx_h_michael_mic_add(struct ieee80211_tx_data *tx) { - u8 *data, *sa, *da, *key, *mic, qos_tid; + u8 *data, *key, *mic, key_offset; size_t data_len; - u16 fc; + unsigned int hdrlen; + struct ieee80211_hdr *hdr; struct sk_buff *skb = tx->skb; int authenticator; int wpa_test = 0; + int tail; - fc = tx->fc; - + hdr = (struct ieee80211_hdr *)skb->data; if (!tx->key || tx->key->conf.alg != ALG_TKIP || skb->len < 24 || - !WLAN_FC_DATA_PRESENT(fc)) + !ieee80211_is_data_present(hdr->frame_control)) return TX_CONTINUE; - if (ieee80211_get_hdr_info(skb, &sa, &da, &qos_tid, &data, &data_len)) + hdrlen = ieee80211_hdrlen(hdr->frame_control); + if (skb->len < hdrlen) return TX_DROP; + data = skb->data + hdrlen; + data_len = skb->len - hdrlen; + if ((tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) && !(tx->flags & IEEE80211_TX_FRAGMENTED) && !(tx->key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_MMIC) && @@ -98,26 +54,27 @@ ieee80211_tx_h_michael_mic_add(struct ieee80211_tx_data *tx) return TX_CONTINUE; } - if (skb_tailroom(skb) < MICHAEL_MIC_LEN) { - I802_DEBUG_INC(tx->local->tx_expand_skb_head); - if (unlikely(pskb_expand_head(skb, TKIP_IV_LEN, - MICHAEL_MIC_LEN + TKIP_ICV_LEN, - GFP_ATOMIC))) { - printk(KERN_DEBUG "%s: failed to allocate more memory " - "for Michael MIC\n", tx->dev->name); - return TX_DROP; - } - } + tail = MICHAEL_MIC_LEN; + if (!(tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE)) + tail += TKIP_ICV_LEN; + + if (WARN_ON(skb_tailroom(skb) < tail || + skb_headroom(skb) < TKIP_IV_LEN)) + return TX_DROP; #if 0 authenticator = fc & IEEE80211_FCTL_FROMDS; /* FIX */ #else authenticator = 1; #endif - key = &tx->key->conf.key[authenticator ? ALG_TKIP_TEMP_AUTH_TX_MIC_KEY : - ALG_TKIP_TEMP_AUTH_RX_MIC_KEY]; + /* At this point we know we're using ALG_TKIP. To get the MIC key + * we now will rely on the offset from the ieee80211_key_conf::key */ + key_offset = authenticator ? + NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY : + NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY; + key = &tx->key->conf.key[key_offset]; mic = skb_put(skb, MICHAEL_MIC_LEN); - michael_mic(key, da, sa, qos_tid & 0x0f, data, data_len, mic); + michael_mic(key, hdr, data, data_len, mic); return TX_CONTINUE; } @@ -126,47 +83,50 @@ ieee80211_tx_h_michael_mic_add(struct ieee80211_tx_data *tx) ieee80211_rx_result ieee80211_rx_h_michael_mic_verify(struct ieee80211_rx_data *rx) { - u8 *data, *sa, *da, *key = NULL, qos_tid; + u8 *data, *key = NULL, key_offset; size_t data_len; - u16 fc; + unsigned int hdrlen; + struct ieee80211_hdr *hdr; u8 mic[MICHAEL_MIC_LEN]; struct sk_buff *skb = rx->skb; int authenticator = 1, wpa_test = 0; DECLARE_MAC_BUF(mac); - fc = rx->fc; - /* * No way to verify the MIC if the hardware stripped it */ if (rx->status->flag & RX_FLAG_MMIC_STRIPPED) return RX_CONTINUE; + hdr = (struct ieee80211_hdr *)skb->data; if (!rx->key || rx->key->conf.alg != ALG_TKIP || - !(rx->fc & IEEE80211_FCTL_PROTECTED) || !WLAN_FC_DATA_PRESENT(fc)) + !ieee80211_has_protected(hdr->frame_control) || + !ieee80211_is_data_present(hdr->frame_control)) return RX_CONTINUE; - if (ieee80211_get_hdr_info(skb, &sa, &da, &qos_tid, &data, &data_len) - || data_len < MICHAEL_MIC_LEN) + hdrlen = ieee80211_hdrlen(hdr->frame_control); + if (skb->len < hdrlen + MICHAEL_MIC_LEN) return RX_DROP_UNUSABLE; - data_len -= MICHAEL_MIC_LEN; + data = skb->data + hdrlen; + data_len = skb->len - hdrlen - MICHAEL_MIC_LEN; #if 0 authenticator = fc & IEEE80211_FCTL_TODS; /* FIX */ #else authenticator = 1; #endif - key = &rx->key->conf.key[authenticator ? ALG_TKIP_TEMP_AUTH_RX_MIC_KEY : - ALG_TKIP_TEMP_AUTH_TX_MIC_KEY]; - michael_mic(key, da, sa, qos_tid & 0x0f, data, data_len, mic); + /* At this point we know we're using ALG_TKIP. To get the MIC key + * we now will rely on the offset from the ieee80211_key_conf::key */ + key_offset = authenticator ? + NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY : + NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY; + key = &rx->key->conf.key[key_offset]; + michael_mic(key, hdr, data, data_len, mic); if (memcmp(mic, data + data_len, MICHAEL_MIC_LEN) != 0 || wpa_test) { if (!(rx->flags & IEEE80211_RX_RA_MATCH)) return RX_DROP_UNUSABLE; - printk(KERN_DEBUG "%s: invalid Michael MIC in data frame from " - "%s\n", rx->dev->name, print_mac(mac, sa)); - mac80211_ev_michael_mic_failure(rx->dev, rx->key->conf.keyidx, (void *) skb->data); return RX_DROP_UNUSABLE; @@ -176,59 +136,58 @@ ieee80211_rx_h_michael_mic_verify(struct ieee80211_rx_data *rx) skb_trim(skb, skb->len - MICHAEL_MIC_LEN); /* update IV in key information to be able to detect replays */ - rx->key->u.tkip.iv32_rx[rx->queue] = rx->tkip_iv32; - rx->key->u.tkip.iv16_rx[rx->queue] = rx->tkip_iv16; + rx->key->u.tkip.rx[rx->queue].iv32 = rx->tkip_iv32; + rx->key->u.tkip.rx[rx->queue].iv16 = rx->tkip_iv16; return RX_CONTINUE; } -static int tkip_encrypt_skb(struct ieee80211_tx_data *tx, - struct sk_buff *skb, int test) +static int tkip_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb) { struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; struct ieee80211_key *key = tx->key; - int hdrlen, len, tailneed; - u16 fc; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + unsigned int hdrlen; + int len, tail; u8 *pos; - fc = le16_to_cpu(hdr->frame_control); - hdrlen = ieee80211_get_hdrlen(fc); + info->control.icv_len = TKIP_ICV_LEN; + info->control.iv_len = TKIP_IV_LEN; + + if ((tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) && + !(tx->key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV)) { + /* hwaccel - with no need for preallocated room for IV/ICV */ + info->control.hw_key = &tx->key->conf; + return 0; + } + + hdrlen = ieee80211_hdrlen(hdr->frame_control); len = skb->len - hdrlen; if (tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) - tailneed = 0; + tail = 0; else - tailneed = TKIP_ICV_LEN; - - if ((skb_headroom(skb) < TKIP_IV_LEN || - skb_tailroom(skb) < tailneed)) { - I802_DEBUG_INC(tx->local->tx_expand_skb_head); - if (unlikely(pskb_expand_head(skb, TKIP_IV_LEN, tailneed, - GFP_ATOMIC))) - return -1; - } + tail = TKIP_ICV_LEN; + + if (WARN_ON(skb_tailroom(skb) < tail || + skb_headroom(skb) < TKIP_IV_LEN)) + return -1; pos = skb_push(skb, TKIP_IV_LEN); memmove(pos, pos + TKIP_IV_LEN, hdrlen); pos += hdrlen; /* Increase IV for the frame */ - key->u.tkip.iv16++; - if (key->u.tkip.iv16 == 0) - key->u.tkip.iv32++; + key->u.tkip.tx.iv16++; + if (key->u.tkip.tx.iv16 == 0) + key->u.tkip.tx.iv32++; if (tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) { - hdr = (struct ieee80211_hdr *)skb->data; - /* hwaccel - with preallocated room for IV */ - ieee80211_tkip_add_iv(pos, key, - (u8) (key->u.tkip.iv16 >> 8), - (u8) (((key->u.tkip.iv16 >> 8) | 0x20) & - 0x7f), - (u8) key->u.tkip.iv16); + ieee80211_tkip_add_iv(pos, key, key->u.tkip.tx.iv16); - tx->control->key_idx = tx->key->conf.hw_key_idx; + info->control.hw_key = &tx->key->conf; return 0; } @@ -246,28 +205,16 @@ ieee80211_tx_result ieee80211_crypto_tkip_encrypt(struct ieee80211_tx_data *tx) { struct sk_buff *skb = tx->skb; - int wpa_test = 0, test = 0; - tx->control->icv_len = TKIP_ICV_LEN; - tx->control->iv_len = TKIP_IV_LEN; ieee80211_tx_set_protected(tx); - if ((tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) && - !(tx->key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV) && - !wpa_test) { - /* hwaccel - with no need for preallocated room for IV/ICV */ - tx->control->key_idx = tx->key->conf.hw_key_idx; - return TX_CONTINUE; - } - - if (tkip_encrypt_skb(tx, skb, test) < 0) + if (tkip_encrypt_skb(tx, skb) < 0) return TX_DROP; if (tx->extra_frag) { int i; for (i = 0; i < tx->num_extra_frag; i++) { - if (tkip_encrypt_skb(tx, tx->extra_frag[i], test) - < 0) + if (tkip_encrypt_skb(tx, tx->extra_frag[i]) < 0) return TX_DROP; } } @@ -280,16 +227,14 @@ ieee80211_rx_result ieee80211_crypto_tkip_decrypt(struct ieee80211_rx_data *rx) { struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) rx->skb->data; - u16 fc; int hdrlen, res, hwaccel = 0, wpa_test = 0; struct ieee80211_key *key = rx->key; struct sk_buff *skb = rx->skb; DECLARE_MAC_BUF(mac); - fc = le16_to_cpu(hdr->frame_control); - hdrlen = ieee80211_get_hdrlen(fc); + hdrlen = ieee80211_hdrlen(hdr->frame_control); - if ((rx->fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA) + if (!ieee80211_is_data(hdr->frame_control)) return RX_CONTINUE; if (!rx->sta || skb->len - hdrlen < 12) @@ -315,15 +260,8 @@ ieee80211_crypto_tkip_decrypt(struct ieee80211_rx_data *rx) hdr->addr1, hwaccel, rx->queue, &rx->tkip_iv32, &rx->tkip_iv16); - if (res != TKIP_DECRYPT_OK || wpa_test) { -#ifdef CONFIG_MAC80211_DEBUG - if (net_ratelimit()) - printk(KERN_DEBUG "%s: TKIP decrypt failed for RX " - "frame from %s (res=%d)\n", rx->dev->name, - print_mac(mac, rx->sta->addr), res); -#endif /* CONFIG_MAC80211_DEBUG */ + if (res != TKIP_DECRYPT_OK || wpa_test) return RX_DROP_UNUSABLE; - } /* Trim ICV */ skb_trim(skb, skb->len - TKIP_ICV_LEN); @@ -336,70 +274,68 @@ ieee80211_crypto_tkip_decrypt(struct ieee80211_rx_data *rx) } -static void ccmp_special_blocks(struct sk_buff *skb, u8 *pn, u8 *b_0, u8 *aad, +static void ccmp_special_blocks(struct sk_buff *skb, u8 *pn, u8 *scratch, int encrypted) { - u16 fc; - int a4_included, qos_included; - u8 qos_tid, *fc_pos, *data, *sa, *da; - int len_a; - size_t data_len; - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; + __le16 mask_fc; + int a4_included; + u8 qos_tid; + u8 *b_0, *aad; + u16 data_len, len_a; + unsigned int hdrlen; + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; - fc_pos = (u8 *) &hdr->frame_control; - fc = fc_pos[0] ^ (fc_pos[1] << 8); - a4_included = (fc & (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) == - (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS); - - ieee80211_get_hdr_info(skb, &sa, &da, &qos_tid, &data, &data_len); - data_len -= CCMP_HDR_LEN + (encrypted ? CCMP_MIC_LEN : 0); - if (qos_tid & 0x80) { - qos_included = 1; - qos_tid &= 0x0f; - } else - qos_included = 0; - /* First block, b_0 */ + b_0 = scratch + 3 * AES_BLOCK_LEN; + aad = scratch + 4 * AES_BLOCK_LEN; + + /* + * Mask FC: zero subtype b4 b5 b6 + * Retry, PwrMgt, MoreData; set Protected + */ + mask_fc = hdr->frame_control; + mask_fc &= ~cpu_to_le16(0x0070 | IEEE80211_FCTL_RETRY | + IEEE80211_FCTL_PM | IEEE80211_FCTL_MOREDATA); + mask_fc |= cpu_to_le16(IEEE80211_FCTL_PROTECTED); + + hdrlen = ieee80211_hdrlen(hdr->frame_control); + len_a = hdrlen - 2; + a4_included = ieee80211_has_a4(hdr->frame_control); + + if (ieee80211_is_data_qos(hdr->frame_control)) + qos_tid = *ieee80211_get_qos_ctl(hdr) & IEEE80211_QOS_CTL_TID_MASK; + else + qos_tid = 0; + + data_len = skb->len - hdrlen - CCMP_HDR_LEN; + if (encrypted) + data_len -= CCMP_MIC_LEN; + /* First block, b_0 */ b_0[0] = 0x59; /* flags: Adata: 1, M: 011, L: 001 */ /* Nonce: QoS Priority | A2 | PN */ b_0[1] = qos_tid; - memcpy(&b_0[2], hdr->addr2, 6); + memcpy(&b_0[2], hdr->addr2, ETH_ALEN); memcpy(&b_0[8], pn, CCMP_PN_LEN); /* l(m) */ - b_0[14] = (data_len >> 8) & 0xff; - b_0[15] = data_len & 0xff; - + put_unaligned_be16(data_len, &b_0[14]); /* AAD (extra authenticate-only data) / masked 802.11 header * FC | A1 | A2 | A3 | SC | [A4] | [QC] */ - - len_a = a4_included ? 28 : 22; - if (qos_included) - len_a += 2; - - aad[0] = 0; /* (len_a >> 8) & 0xff; */ - aad[1] = len_a & 0xff; - /* Mask FC: zero subtype b4 b5 b6 */ - aad[2] = fc_pos[0] & ~(BIT(4) | BIT(5) | BIT(6)); - /* Retry, PwrMgt, MoreData; set Protected */ - aad[3] = (fc_pos[1] & ~(BIT(3) | BIT(4) | BIT(5))) | BIT(6); - memcpy(&aad[4], &hdr->addr1, 18); + put_unaligned_be16(len_a, &aad[0]); + put_unaligned(mask_fc, (__le16 *)&aad[2]); + memcpy(&aad[4], &hdr->addr1, 3 * ETH_ALEN); /* Mask Seq#, leave Frag# */ aad[22] = *((u8 *) &hdr->seq_ctrl) & 0x0f; aad[23] = 0; + if (a4_included) { - memcpy(&aad[24], hdr->addr4, 6); - aad[30] = 0; + memcpy(&aad[24], hdr->addr4, ETH_ALEN); + aad[30] = qos_tid; aad[31] = 0; - } else - memset(&aad[24], 0, 8); - if (qos_included) { - u8 *dpos = &aad[a4_included ? 30 : 24]; - - /* Mask QoS Control field */ - dpos[0] = qos_tid; - dpos[1] = 0; + } else { + memset(&aad[24], 0, ETH_ALEN + IEEE80211_QOS_CTL_LEN); + aad[24] = qos_tid; } } @@ -429,36 +365,37 @@ static inline int ccmp_hdr2pn(u8 *pn, u8 *hdr) } -static int ccmp_encrypt_skb(struct ieee80211_tx_data *tx, - struct sk_buff *skb, int test) +static int ccmp_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb) { struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; struct ieee80211_key *key = tx->key; - int hdrlen, len, tailneed; - u16 fc; - u8 *pos, *pn, *b_0, *aad, *scratch; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + int hdrlen, len, tail; + u8 *pos, *pn; int i; - scratch = key->u.ccmp.tx_crypto_buf; - b_0 = scratch + 3 * AES_BLOCK_LEN; - aad = scratch + 4 * AES_BLOCK_LEN; + info->control.icv_len = CCMP_MIC_LEN; + info->control.iv_len = CCMP_HDR_LEN; - fc = le16_to_cpu(hdr->frame_control); - hdrlen = ieee80211_get_hdrlen(fc); + if ((tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) && + !(tx->key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV)) { + /* hwaccel - with no need for preallocated room for CCMP " + * header or MIC fields */ + info->control.hw_key = &tx->key->conf; + return 0; + } + + hdrlen = ieee80211_hdrlen(hdr->frame_control); len = skb->len - hdrlen; if (key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) - tailneed = 0; + tail = 0; else - tailneed = CCMP_MIC_LEN; - - if ((skb_headroom(skb) < CCMP_HDR_LEN || - skb_tailroom(skb) < tailneed)) { - I802_DEBUG_INC(tx->local->tx_expand_skb_head); - if (unlikely(pskb_expand_head(skb, CCMP_HDR_LEN, tailneed, - GFP_ATOMIC))) - return -1; - } + tail = CCMP_MIC_LEN; + + if (WARN_ON(skb_tailroom(skb) < tail || + skb_headroom(skb) < CCMP_HDR_LEN)) + return -1; pos = skb_push(skb, CCMP_HDR_LEN); memmove(pos, pos + CCMP_HDR_LEN, hdrlen); @@ -478,13 +415,13 @@ static int ccmp_encrypt_skb(struct ieee80211_tx_data *tx, if (key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) { /* hwaccel - with preallocated room for CCMP header */ - tx->control->key_idx = key->conf.hw_key_idx; + info->control.hw_key = &tx->key->conf; return 0; } pos += CCMP_HDR_LEN; - ccmp_special_blocks(skb, pn, b_0, aad, 0); - ieee80211_aes_ccm_encrypt(key->u.ccmp.tfm, scratch, b_0, aad, pos, len, + ccmp_special_blocks(skb, pn, key->u.ccmp.tx_crypto_buf, 0); + ieee80211_aes_ccm_encrypt(key->u.ccmp.tfm, key->u.ccmp.tx_crypto_buf, pos, len, pos, skb_put(skb, CCMP_MIC_LEN)); return 0; @@ -495,28 +432,16 @@ ieee80211_tx_result ieee80211_crypto_ccmp_encrypt(struct ieee80211_tx_data *tx) { struct sk_buff *skb = tx->skb; - int test = 0; - tx->control->icv_len = CCMP_MIC_LEN; - tx->control->iv_len = CCMP_HDR_LEN; ieee80211_tx_set_protected(tx); - if ((tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) && - !(tx->key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV)) { - /* hwaccel - with no need for preallocated room for CCMP " - * header or MIC fields */ - tx->control->key_idx = tx->key->conf.hw_key_idx; - return TX_CONTINUE; - } - - if (ccmp_encrypt_skb(tx, skb, test) < 0) + if (ccmp_encrypt_skb(tx, skb) < 0) return TX_DROP; if (tx->extra_frag) { int i; for (i = 0; i < tx->num_extra_frag; i++) { - if (ccmp_encrypt_skb(tx, tx->extra_frag[i], test) - < 0) + if (ccmp_encrypt_skb(tx, tx->extra_frag[i]) < 0) return TX_DROP; } } @@ -528,8 +453,7 @@ ieee80211_crypto_ccmp_encrypt(struct ieee80211_tx_data *tx) ieee80211_rx_result ieee80211_crypto_ccmp_decrypt(struct ieee80211_rx_data *rx) { - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) rx->skb->data; - u16 fc; + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data; int hdrlen; struct ieee80211_key *key = rx->key; struct sk_buff *skb = rx->skb; @@ -537,10 +461,9 @@ ieee80211_crypto_ccmp_decrypt(struct ieee80211_rx_data *rx) int data_len; DECLARE_MAC_BUF(mac); - fc = le16_to_cpu(hdr->frame_control); - hdrlen = ieee80211_get_hdrlen(fc); + hdrlen = ieee80211_hdrlen(hdr->frame_control); - if ((rx->fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA) + if (!ieee80211_is_data(hdr->frame_control)) return RX_CONTINUE; data_len = skb->len - hdrlen - CCMP_HDR_LEN - CCMP_MIC_LEN; @@ -554,41 +477,19 @@ ieee80211_crypto_ccmp_decrypt(struct ieee80211_rx_data *rx) (void) ccmp_hdr2pn(pn, skb->data + hdrlen); if (memcmp(pn, key->u.ccmp.rx_pn[rx->queue], CCMP_PN_LEN) <= 0) { -#ifdef CONFIG_MAC80211_DEBUG - u8 *ppn = key->u.ccmp.rx_pn[rx->queue]; - - printk(KERN_DEBUG "%s: CCMP replay detected for RX frame from " - "%s (RX PN %02x%02x%02x%02x%02x%02x <= prev. PN " - "%02x%02x%02x%02x%02x%02x)\n", rx->dev->name, - print_mac(mac, rx->sta->addr), - pn[0], pn[1], pn[2], pn[3], pn[4], pn[5], - ppn[0], ppn[1], ppn[2], ppn[3], ppn[4], ppn[5]); -#endif /* CONFIG_MAC80211_DEBUG */ key->u.ccmp.replays++; return RX_DROP_UNUSABLE; } if (!(rx->status->flag & RX_FLAG_DECRYPTED)) { /* hardware didn't decrypt/verify MIC */ - u8 *scratch, *b_0, *aad; - - scratch = key->u.ccmp.rx_crypto_buf; - b_0 = scratch + 3 * AES_BLOCK_LEN; - aad = scratch + 4 * AES_BLOCK_LEN; - - ccmp_special_blocks(skb, pn, b_0, aad, 1); + ccmp_special_blocks(skb, pn, key->u.ccmp.rx_crypto_buf, 1); if (ieee80211_aes_ccm_decrypt( - key->u.ccmp.tfm, scratch, b_0, aad, + key->u.ccmp.tfm, key->u.ccmp.rx_crypto_buf, skb->data + hdrlen + CCMP_HDR_LEN, data_len, skb->data + skb->len - CCMP_MIC_LEN, skb->data + hdrlen + CCMP_HDR_LEN)) { -#ifdef CONFIG_MAC80211_DEBUG - if (net_ratelimit()) - printk(KERN_DEBUG "%s: CCMP decrypt failed " - "for RX frame from %s\n", rx->dev->name, - print_mac(mac, rx->sta->addr)); -#endif /* CONFIG_MAC80211_DEBUG */ return RX_DROP_UNUSABLE; } } diff --git a/net/netfilter/Kconfig b/net/netfilter/Kconfig index aa8d80c35e28..316c7af1d2b1 100644 --- a/net/netfilter/Kconfig +++ b/net/netfilter/Kconfig @@ -33,9 +33,8 @@ config NF_CONNTRACK into connections. This is required to do Masquerading or other kinds of Network - Address Translation (except for Fast NAT). It can also be used to - enhance packet filtering (see `Connection state match support' - below). + Address Translation. It can also be used to enhance packet + filtering (see `Connection state match support' below). To compile it as a module, choose M here. If unsure, say N. diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c index 662c1ccfee26..28d03e64200b 100644 --- a/net/netfilter/nf_conntrack_core.c +++ b/net/netfilter/nf_conntrack_core.c @@ -464,7 +464,8 @@ static noinline int early_drop(unsigned int hash) } struct nf_conn *nf_conntrack_alloc(const struct nf_conntrack_tuple *orig, - const struct nf_conntrack_tuple *repl) + const struct nf_conntrack_tuple *repl, + gfp_t gfp) { struct nf_conn *ct = NULL; @@ -489,7 +490,7 @@ struct nf_conn *nf_conntrack_alloc(const struct nf_conntrack_tuple *orig, } } - ct = kmem_cache_zalloc(nf_conntrack_cachep, GFP_ATOMIC); + ct = kmem_cache_zalloc(nf_conntrack_cachep, gfp); if (ct == NULL) { pr_debug("nf_conntrack_alloc: Can't alloc conntrack.\n"); atomic_dec(&nf_conntrack_count); @@ -542,7 +543,7 @@ init_conntrack(const struct nf_conntrack_tuple *tuple, return NULL; } - ct = nf_conntrack_alloc(tuple, &repl_tuple); + ct = nf_conntrack_alloc(tuple, &repl_tuple, GFP_ATOMIC); if (ct == NULL || IS_ERR(ct)) { pr_debug("Can't allocate conntrack.\n"); return (struct nf_conntrack_tuple_hash *)ct; @@ -847,6 +848,28 @@ acct: } EXPORT_SYMBOL_GPL(__nf_ct_refresh_acct); +bool __nf_ct_kill_acct(struct nf_conn *ct, + enum ip_conntrack_info ctinfo, + const struct sk_buff *skb, + int do_acct) +{ +#ifdef CONFIG_NF_CT_ACCT + if (do_acct) { + spin_lock_bh(&nf_conntrack_lock); + ct->counters[CTINFO2DIR(ctinfo)].packets++; + ct->counters[CTINFO2DIR(ctinfo)].bytes += + skb->len - skb_network_offset(skb); + spin_unlock_bh(&nf_conntrack_lock); + } +#endif + if (del_timer(&ct->timeout)) { + ct->timeout.function((unsigned long)ct); + return true; + } + return false; +} +EXPORT_SYMBOL_GPL(__nf_ct_kill_acct); + #if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE) #include <linux/netfilter/nfnetlink.h> diff --git a/net/netfilter/nf_conntrack_extend.c b/net/netfilter/nf_conntrack_extend.c index 8a3f8b34e466..3469bc71a385 100644 --- a/net/netfilter/nf_conntrack_extend.c +++ b/net/netfilter/nf_conntrack_extend.c @@ -95,13 +95,11 @@ void *__nf_ct_ext_add(struct nf_conn *ct, enum nf_ct_ext_id id, gfp_t gfp) newlen = newoff + t->len; rcu_read_unlock(); - if (newlen >= ksize(ct->ext)) { - new = kmalloc(newlen, gfp); - if (!new) - return NULL; - - memcpy(new, ct->ext, ct->ext->len); + new = krealloc(ct->ext, newlen, gfp); + if (!new) + return NULL; + if (new != ct->ext) { for (i = 0; i < NF_CT_EXT_NUM; i++) { if (!nf_ct_ext_exist(ct, i)) continue; diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c index 077bcd228799..95a7967731f9 100644 --- a/net/netfilter/nf_conntrack_netlink.c +++ b/net/netfilter/nf_conntrack_netlink.c @@ -4,7 +4,7 @@ * (C) 2001 by Jay Schulist <jschlst@samba.org> * (C) 2002-2006 by Harald Welte <laforge@gnumonks.org> * (C) 2003 by Patrick Mchardy <kaber@trash.net> - * (C) 2005-2007 by Pablo Neira Ayuso <pablo@netfilter.org> + * (C) 2005-2008 by Pablo Neira Ayuso <pablo@netfilter.org> * * Initial connection tracking via netlink development funded and * generally made possible by Network Robots, Inc. (www.networkrobots.com) @@ -476,14 +476,14 @@ static int ctnetlink_conntrack_event(struct notifier_block *this, if (ctnetlink_dump_id(skb, ct) < 0) goto nla_put_failure; + if (ctnetlink_dump_status(skb, ct) < 0) + goto nla_put_failure; + if (events & 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; } else { - if (ctnetlink_dump_status(skb, ct) < 0) - goto nla_put_failure; - if (ctnetlink_dump_timeout(skb, ct) < 0) goto nla_put_failure; @@ -813,9 +813,8 @@ ctnetlink_del_conntrack(struct sock *ctnl, struct sk_buff *skb, return -ENOENT; } } - if (del_timer(&ct->timeout)) - ct->timeout.function((unsigned long)ct); + nf_ct_kill(ct); nf_ct_put(ct); return 0; @@ -892,20 +891,19 @@ ctnetlink_change_status(struct nf_conn *ct, struct nlattr *cda[]) if (d & (IPS_EXPECTED|IPS_CONFIRMED|IPS_DYING)) /* unchangeable */ - return -EINVAL; + return -EBUSY; if (d & IPS_SEEN_REPLY && !(status & IPS_SEEN_REPLY)) /* SEEN_REPLY bit can only be set */ - return -EINVAL; - + return -EBUSY; if (d & IPS_ASSURED && !(status & IPS_ASSURED)) /* ASSURED bit can only be set */ - return -EINVAL; + return -EBUSY; if (cda[CTA_NAT_SRC] || cda[CTA_NAT_DST]) { #ifndef CONFIG_NF_NAT_NEEDED - return -EINVAL; + return -EOPNOTSUPP; #else struct nf_nat_range range; @@ -946,7 +944,7 @@ ctnetlink_change_helper(struct nf_conn *ct, struct nlattr *cda[]) /* don't change helper of sibling connections */ if (ct->master) - return -EINVAL; + return -EBUSY; err = ctnetlink_parse_help(cda[CTA_HELP], &helpname); if (err < 0) @@ -964,7 +962,7 @@ ctnetlink_change_helper(struct nf_conn *ct, struct nlattr *cda[]) helper = __nf_conntrack_helper_find_byname(helpname); if (helper == NULL) - return -EINVAL; + return -EOPNOTSUPP; if (help) { if (help->helper == helper) @@ -1131,7 +1129,7 @@ ctnetlink_create_conntrack(struct nlattr *cda[], struct nf_conn_help *help; struct nf_conntrack_helper *helper; - ct = nf_conntrack_alloc(otuple, rtuple); + ct = nf_conntrack_alloc(otuple, rtuple, GFP_KERNEL); if (ct == NULL || IS_ERR(ct)) return -ENOMEM; @@ -1259,12 +1257,12 @@ ctnetlink_new_conntrack(struct sock *ctnl, struct sk_buff *skb, if (!(nlh->nlmsg_flags & NLM_F_EXCL)) { /* we only allow nat config for new conntracks */ if (cda[CTA_NAT_SRC] || cda[CTA_NAT_DST]) { - err = -EINVAL; + err = -EOPNOTSUPP; goto out_unlock; } /* can't link an existing conntrack to a master */ if (cda[CTA_TUPLE_MASTER]) { - err = -EINVAL; + err = -EOPNOTSUPP; goto out_unlock; } err = ctnetlink_change_conntrack(nf_ct_tuplehash_to_ctrack(h), @@ -1609,7 +1607,7 @@ ctnetlink_del_expect(struct sock *ctnl, struct sk_buff *skb, h = __nf_conntrack_helper_find_byname(name); if (!h) { spin_unlock_bh(&nf_conntrack_lock); - return -EINVAL; + return -EOPNOTSUPP; } for (i = 0; i < nf_ct_expect_hsize; i++) { hlist_for_each_entry_safe(exp, n, next, diff --git a/net/netfilter/nf_conntrack_proto_dccp.c b/net/netfilter/nf_conntrack_proto_dccp.c index afb4a1861d2c..e7866dd3cde6 100644 --- a/net/netfilter/nf_conntrack_proto_dccp.c +++ b/net/netfilter/nf_conntrack_proto_dccp.c @@ -475,8 +475,7 @@ static int dccp_packet(struct nf_conn *ct, const struct sk_buff *skb, if (type == DCCP_PKT_RESET && !test_bit(IPS_SEEN_REPLY_BIT, &ct->status)) { /* Tear down connection immediately if only reply is a RESET */ - if (del_timer(&ct->timeout)) - ct->timeout.function((unsigned long)ct); + nf_ct_kill_acct(ct, ctinfo, skb); return NF_ACCEPT; } diff --git a/net/netfilter/nf_conntrack_proto_sctp.c b/net/netfilter/nf_conntrack_proto_sctp.c index cbf2e27a22b2..41183a4d2d62 100644 --- a/net/netfilter/nf_conntrack_proto_sctp.c +++ b/net/netfilter/nf_conntrack_proto_sctp.c @@ -463,6 +463,82 @@ static bool sctp_new(struct nf_conn *ct, const struct sk_buff *skb, return true; } +#if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE) + +#include <linux/netfilter/nfnetlink.h> +#include <linux/netfilter/nfnetlink_conntrack.h> + +static int sctp_to_nlattr(struct sk_buff *skb, struct nlattr *nla, + const struct nf_conn *ct) +{ + struct nlattr *nest_parms; + + read_lock_bh(&sctp_lock); + nest_parms = nla_nest_start(skb, CTA_PROTOINFO_SCTP | NLA_F_NESTED); + if (!nest_parms) + goto nla_put_failure; + + NLA_PUT_U8(skb, CTA_PROTOINFO_SCTP_STATE, ct->proto.sctp.state); + + NLA_PUT_BE32(skb, + CTA_PROTOINFO_SCTP_VTAG_ORIGINAL, + htonl(ct->proto.sctp.vtag[IP_CT_DIR_ORIGINAL])); + + NLA_PUT_BE32(skb, + CTA_PROTOINFO_SCTP_VTAG_REPLY, + htonl(ct->proto.sctp.vtag[IP_CT_DIR_REPLY])); + + read_unlock_bh(&sctp_lock); + + nla_nest_end(skb, nest_parms); + + return 0; + +nla_put_failure: + read_unlock_bh(&sctp_lock); + return -1; +} + +static const struct nla_policy sctp_nla_policy[CTA_PROTOINFO_SCTP_MAX+1] = { + [CTA_PROTOINFO_SCTP_STATE] = { .type = NLA_U8 }, + [CTA_PROTOINFO_SCTP_VTAG_ORIGINAL] = { .type = NLA_U32 }, + [CTA_PROTOINFO_SCTP_VTAG_REPLY] = { .type = NLA_U32 }, +}; + +static int nlattr_to_sctp(struct nlattr *cda[], struct nf_conn *ct) +{ + struct nlattr *attr = cda[CTA_PROTOINFO_SCTP]; + struct nlattr *tb[CTA_PROTOINFO_SCTP_MAX+1]; + int err; + + /* updates may not contain the internal protocol info, skip parsing */ + if (!attr) + return 0; + + err = nla_parse_nested(tb, + CTA_PROTOINFO_SCTP_MAX, + attr, + sctp_nla_policy); + if (err < 0) + return err; + + if (!tb[CTA_PROTOINFO_SCTP_STATE] || + !tb[CTA_PROTOINFO_SCTP_VTAG_ORIGINAL] || + !tb[CTA_PROTOINFO_SCTP_VTAG_REPLY]) + return -EINVAL; + + write_lock_bh(&sctp_lock); + ct->proto.sctp.state = nla_get_u8(tb[CTA_PROTOINFO_SCTP_STATE]); + ct->proto.sctp.vtag[IP_CT_DIR_ORIGINAL] = + ntohl(nla_get_be32(tb[CTA_PROTOINFO_SCTP_VTAG_ORIGINAL])); + ct->proto.sctp.vtag[IP_CT_DIR_REPLY] = + ntohl(nla_get_be32(tb[CTA_PROTOINFO_SCTP_VTAG_REPLY])); + write_unlock_bh(&sctp_lock); + + return 0; +} +#endif + #ifdef CONFIG_SYSCTL static unsigned int sctp_sysctl_table_users; static struct ctl_table_header *sctp_sysctl_header; @@ -591,6 +667,8 @@ static struct nf_conntrack_l4proto nf_conntrack_l4proto_sctp4 __read_mostly = { .new = sctp_new, .me = THIS_MODULE, #if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE) + .to_nlattr = sctp_to_nlattr, + .from_nlattr = nlattr_to_sctp, .tuple_to_nlattr = nf_ct_port_tuple_to_nlattr, .nlattr_to_tuple = nf_ct_port_nlattr_to_tuple, .nla_policy = nf_ct_port_nla_policy, @@ -617,6 +695,8 @@ static struct nf_conntrack_l4proto nf_conntrack_l4proto_sctp6 __read_mostly = { .new = sctp_new, .me = THIS_MODULE, #if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE) + .to_nlattr = sctp_to_nlattr, + .from_nlattr = nlattr_to_sctp, .tuple_to_nlattr = nf_ct_port_tuple_to_nlattr, .nlattr_to_tuple = nf_ct_port_nlattr_to_tuple, .nla_policy = nf_ct_port_nla_policy, diff --git a/net/netfilter/nf_conntrack_proto_tcp.c b/net/netfilter/nf_conntrack_proto_tcp.c index dd28fb239a60..420a10d8eb1e 100644 --- a/net/netfilter/nf_conntrack_proto_tcp.c +++ b/net/netfilter/nf_conntrack_proto_tcp.c @@ -844,14 +844,13 @@ static int tcp_packet(struct nf_conn *ct, /* Attempt to reopen a closed/aborted connection. * Delete this connection and look up again. */ write_unlock_bh(&tcp_lock); + /* Only repeat if we can actually remove the timer. * Destruction may already be in progress in process * context and we must give it a chance to terminate. */ - if (del_timer(&ct->timeout)) { - ct->timeout.function((unsigned long)ct); + if (nf_ct_kill(ct)) return -NF_REPEAT; - } return -NF_DROP; } /* Fall through */ @@ -884,8 +883,7 @@ static int tcp_packet(struct nf_conn *ct, if (LOG_INVALID(IPPROTO_TCP)) nf_log_packet(pf, 0, skb, NULL, NULL, NULL, "nf_ct_tcp: killing out of sync session "); - if (del_timer(&ct->timeout)) - ct->timeout.function((unsigned long)ct); + nf_ct_kill(ct); return -NF_DROP; } ct->proto.tcp.last_index = index; @@ -968,8 +966,7 @@ static int tcp_packet(struct nf_conn *ct, problem case, so we can delete the conntrack immediately. --RR */ if (th->rst) { - if (del_timer(&ct->timeout)) - ct->timeout.function((unsigned long)ct); + nf_ct_kill_acct(ct, ctinfo, skb); return NF_ACCEPT; } } else if (!test_bit(IPS_ASSURED_BIT, &ct->status) diff --git a/net/netfilter/nf_sockopt.c b/net/netfilter/nf_sockopt.c index 69d699f95f4c..01489681fa96 100644 --- a/net/netfilter/nf_sockopt.c +++ b/net/netfilter/nf_sockopt.c @@ -65,7 +65,7 @@ static struct nf_sockopt_ops *nf_sockopt_find(struct sock *sk, int pf, { struct nf_sockopt_ops *ops; - if (sock_net(sk) != &init_net) + if (!net_eq(sock_net(sk), &init_net)) return ERR_PTR(-ENOPROTOOPT); if (mutex_lock_interruptible(&nf_sockopt_mutex) != 0) diff --git a/net/netfilter/nfnetlink_queue.c b/net/netfilter/nfnetlink_queue.c index 3447025ce068..8c860112ce05 100644 --- a/net/netfilter/nfnetlink_queue.c +++ b/net/netfilter/nfnetlink_queue.c @@ -243,7 +243,6 @@ nfqnl_build_packet_message(struct nfqnl_instance *queue, switch ((enum nfqnl_config_mode)queue->copy_mode) { case NFQNL_COPY_META: case NFQNL_COPY_NONE: - data_len = 0; break; case NFQNL_COPY_PACKET: @@ -556,7 +555,7 @@ nfqnl_rcv_dev_event(struct notifier_block *this, { struct net_device *dev = ptr; - if (dev_net(dev) != &init_net) + if (!net_eq(dev_net(dev), &init_net)) return NOTIFY_DONE; /* Drop any packets associated with the downed device */ diff --git a/net/netfilter/xt_CONNSECMARK.c b/net/netfilter/xt_CONNSECMARK.c index 211189eb2b67..76ca1f2421eb 100644 --- a/net/netfilter/xt_CONNSECMARK.c +++ b/net/netfilter/xt_CONNSECMARK.c @@ -8,7 +8,7 @@ * Copyright (C) 2002,2004 MARA Systems AB <http://www.marasystems.com> * by Henrik Nordstrom <hno@marasystems.com> * - * (C) 2006 Red Hat, Inc., James Morris <jmorris@redhat.com> + * (C) 2006,2008 Red Hat, Inc., James Morris <jmorris@redhat.com> * * 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 @@ -94,6 +94,12 @@ connsecmark_tg_check(const char *tablename, const void *entry, { const struct xt_connsecmark_target_info *info = targinfo; + if (strcmp(tablename, "mangle") && strcmp(tablename, "security")) { + printk(KERN_INFO PFX "target only valid in the \'mangle\' " + "or \'security\' tables, not \'%s\'.\n", tablename); + return false; + } + switch (info->mode) { case CONNSECMARK_SAVE: case CONNSECMARK_RESTORE: @@ -126,7 +132,6 @@ static struct xt_target connsecmark_tg_reg[] __read_mostly = { .destroy = connsecmark_tg_destroy, .target = connsecmark_tg, .targetsize = sizeof(struct xt_connsecmark_target_info), - .table = "mangle", .me = THIS_MODULE, }, { @@ -136,7 +141,6 @@ static struct xt_target connsecmark_tg_reg[] __read_mostly = { .destroy = connsecmark_tg_destroy, .target = connsecmark_tg, .targetsize = sizeof(struct xt_connsecmark_target_info), - .table = "mangle", .me = THIS_MODULE, }, }; diff --git a/net/netfilter/xt_SECMARK.c b/net/netfilter/xt_SECMARK.c index c0284856ccd4..94f87ee7552b 100644 --- a/net/netfilter/xt_SECMARK.c +++ b/net/netfilter/xt_SECMARK.c @@ -5,7 +5,7 @@ * Based on the nfmark match by: * (C) 1999-2001 Marc Boucher <marc@mbsi.ca> * - * (C) 2006 Red Hat, Inc., James Morris <jmorris@redhat.com> + * (C) 2006,2008 Red Hat, Inc., James Morris <jmorris@redhat.com> * * 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 @@ -89,6 +89,12 @@ secmark_tg_check(const char *tablename, const void *entry, { struct xt_secmark_target_info *info = targinfo; + if (strcmp(tablename, "mangle") && strcmp(tablename, "security")) { + printk(KERN_INFO PFX "target only valid in the \'mangle\' " + "or \'security\' tables, not \'%s\'.\n", tablename); + return false; + } + if (mode && mode != info->mode) { printk(KERN_INFO PFX "mode already set to %hu cannot mix with " "rules for mode %hu\n", mode, info->mode); @@ -127,7 +133,6 @@ static struct xt_target secmark_tg_reg[] __read_mostly = { .destroy = secmark_tg_destroy, .target = secmark_tg, .targetsize = sizeof(struct xt_secmark_target_info), - .table = "mangle", .me = THIS_MODULE, }, { @@ -137,7 +142,6 @@ static struct xt_target secmark_tg_reg[] __read_mostly = { .destroy = secmark_tg_destroy, .target = secmark_tg, .targetsize = sizeof(struct xt_secmark_target_info), - .table = "mangle", .me = THIS_MODULE, }, }; diff --git a/net/netfilter/xt_string.c b/net/netfilter/xt_string.c index 72f694d947f4..4903182a062b 100644 --- a/net/netfilter/xt_string.c +++ b/net/netfilter/xt_string.c @@ -29,12 +29,16 @@ string_mt(const struct sk_buff *skb, const struct net_device *in, { const struct xt_string_info *conf = matchinfo; struct ts_state state; + int invert; memset(&state, 0, sizeof(struct ts_state)); + invert = (match->revision == 0 ? conf->u.v0.invert : + conf->u.v1.flags & XT_STRING_FLAG_INVERT); + return (skb_find_text((struct sk_buff *)skb, conf->from_offset, conf->to_offset, conf->config, &state) - != UINT_MAX) ^ conf->invert; + != UINT_MAX) ^ invert; } #define STRING_TEXT_PRIV(m) ((struct xt_string_info *)(m)) @@ -46,6 +50,7 @@ string_mt_check(const char *tablename, const void *ip, { struct xt_string_info *conf = matchinfo; struct ts_config *ts_conf; + int flags = TS_AUTOLOAD; /* Damn, can't handle this case properly with iptables... */ if (conf->from_offset > conf->to_offset) @@ -54,8 +59,15 @@ string_mt_check(const char *tablename, const void *ip, return false; if (conf->patlen > XT_STRING_MAX_PATTERN_SIZE) return false; + if (match->revision == 1) { + if (conf->u.v1.flags & + ~(XT_STRING_FLAG_IGNORECASE | XT_STRING_FLAG_INVERT)) + return false; + if (conf->u.v1.flags & XT_STRING_FLAG_IGNORECASE) + flags |= TS_IGNORECASE; + } ts_conf = textsearch_prepare(conf->algo, conf->pattern, conf->patlen, - GFP_KERNEL, TS_AUTOLOAD); + GFP_KERNEL, flags); if (IS_ERR(ts_conf)) return false; @@ -72,6 +84,17 @@ static void string_mt_destroy(const struct xt_match *match, void *matchinfo) static struct xt_match string_mt_reg[] __read_mostly = { { .name = "string", + .revision = 0, + .family = AF_INET, + .checkentry = string_mt_check, + .match = string_mt, + .destroy = string_mt_destroy, + .matchsize = sizeof(struct xt_string_info), + .me = THIS_MODULE + }, + { + .name = "string", + .revision = 1, .family = AF_INET, .checkentry = string_mt_check, .match = string_mt, @@ -81,6 +104,17 @@ static struct xt_match string_mt_reg[] __read_mostly = { }, { .name = "string", + .revision = 0, + .family = AF_INET6, + .checkentry = string_mt_check, + .match = string_mt, + .destroy = string_mt_destroy, + .matchsize = sizeof(struct xt_string_info), + .me = THIS_MODULE + }, + { + .name = "string", + .revision = 1, .family = AF_INET6, .checkentry = string_mt_check, .match = string_mt, diff --git a/net/netlabel/netlabel_cipso_v4.c b/net/netlabel/netlabel_cipso_v4.c index 9080c61b71a5..0aec318bf0ef 100644 --- a/net/netlabel/netlabel_cipso_v4.c +++ b/net/netlabel/netlabel_cipso_v4.c @@ -591,7 +591,7 @@ list_retry: if (nlsze_mult < 4) { rcu_read_unlock(); kfree_skb(ans_skb); - nlsze_mult++; + nlsze_mult *= 2; goto list_start; } list_failure_lock: diff --git a/net/netlabel/netlabel_unlabeled.c b/net/netlabel/netlabel_unlabeled.c index 56f80872924e..921c118ead89 100644 --- a/net/netlabel/netlabel_unlabeled.c +++ b/net/netlabel/netlabel_unlabeled.c @@ -954,7 +954,7 @@ static int netlbl_unlhsh_netdev_handler(struct notifier_block *this, struct net_device *dev = ptr; struct netlbl_unlhsh_iface *iface = NULL; - if (dev_net(dev) != &init_net) + if (!net_eq(dev_net(dev), &init_net)) return NOTIFY_DONE; /* XXX - should this be a check for NETDEV_DOWN or _UNREGISTER? */ diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c index 349aba189558..98bfe277eab2 100644 --- a/net/netlink/af_netlink.c +++ b/net/netlink/af_netlink.c @@ -759,7 +759,7 @@ struct sock *netlink_getsockbyfilp(struct file *filp) * 0: continue * 1: repeat lookup - reference dropped while waiting for socket memory. */ -int netlink_attachskb(struct sock *sk, struct sk_buff *skb, int nonblock, +int netlink_attachskb(struct sock *sk, struct sk_buff *skb, long *timeo, struct sock *ssk) { struct netlink_sock *nlk; @@ -892,7 +892,7 @@ retry: return err; } - err = netlink_attachskb(sk, skb, nonblock, &timeo, ssk); + err = netlink_attachskb(sk, skb, &timeo, ssk); if (err == 1) goto retry; if (err) diff --git a/net/netrom/af_netrom.c b/net/netrom/af_netrom.c index 4bae8b998cab..fccc250f95f5 100644 --- a/net/netrom/af_netrom.c +++ b/net/netrom/af_netrom.c @@ -74,6 +74,18 @@ static const struct proto_ops nr_proto_ops; */ static struct lock_class_key nr_netdev_xmit_lock_key; +static void nr_set_lockdep_one(struct net_device *dev, + struct netdev_queue *txq, + void *_unused) +{ + lockdep_set_class(&txq->_xmit_lock, &nr_netdev_xmit_lock_key); +} + +static void nr_set_lockdep_key(struct net_device *dev) +{ + netdev_for_each_tx_queue(dev, nr_set_lockdep_one, NULL); +} + /* * Socket removal during an interrupt is now safe. */ @@ -106,7 +118,7 @@ static int nr_device_event(struct notifier_block *this, unsigned long event, voi { struct net_device *dev = (struct net_device *)ptr; - if (dev_net(dev) != &init_net) + if (!net_eq(dev_net(dev), &init_net)) return NOTIFY_DONE; if (event != NETDEV_DOWN) @@ -475,13 +487,11 @@ static struct sock *nr_make_new(struct sock *osk) sock_init_data(NULL, sk); sk->sk_type = osk->sk_type; - sk->sk_socket = osk->sk_socket; sk->sk_priority = osk->sk_priority; sk->sk_protocol = osk->sk_protocol; sk->sk_rcvbuf = osk->sk_rcvbuf; sk->sk_sndbuf = osk->sk_sndbuf; sk->sk_state = TCP_ESTABLISHED; - sk->sk_sleep = osk->sk_sleep; sock_copy_flags(sk, osk); skb_queue_head_init(&nr->ack_queue); @@ -538,11 +548,9 @@ static int nr_release(struct socket *sock) sk->sk_state_change(sk); sock_orphan(sk); sock_set_flag(sk, SOCK_DESTROY); - sk->sk_socket = NULL; break; default: - sk->sk_socket = NULL; break; } @@ -810,13 +818,11 @@ static int nr_accept(struct socket *sock, struct socket *newsock, int flags) goto out_release; newsk = skb->sk; - newsk->sk_socket = newsock; - newsk->sk_sleep = &newsock->wait; + sock_graft(newsk, newsock); /* Now attach up the new socket */ kfree_skb(skb); sk_acceptq_removed(sk); - newsock->sk = newsk; out_release: release_sock(sk); @@ -1436,7 +1442,7 @@ static int __init nr_proto_init(void) free_netdev(dev); goto fail; } - lockdep_set_class(&dev->_xmit_lock, &nr_netdev_xmit_lock_key); + nr_set_lockdep_key(dev); dev_nr[i] = dev; } diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c index 2cee87da4441..d56cae112dc8 100644 --- a/net/packet/af_packet.c +++ b/net/packet/af_packet.c @@ -5,8 +5,6 @@ * * PACKET - implements raw packet sockets. * - * Version: $Id: af_packet.c,v 1.61 2002/02/08 03:57:19 davem Exp $ - * * Authors: Ross Biro * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG> * Alan Cox, <gw4pts@gw4pts.ampr.org> @@ -188,6 +186,9 @@ struct packet_sock { 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; #endif }; @@ -203,14 +204,52 @@ struct packet_skb_cb { #ifdef CONFIG_PACKET_MMAP -static inline struct tpacket_hdr *packet_lookup_frame(struct packet_sock *po, unsigned int position) +static void *packet_lookup_frame(struct packet_sock *po, 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 / po->frames_per_block; frame_offset = position % po->frames_per_block; - return (struct tpacket_hdr *)(po->pg_vec[pg_vec_pos] + (frame_offset * po->frame_size)); + h.raw = po->pg_vec[pg_vec_pos] + (frame_offset * po->frame_size); + switch (po->tp_version) { + case TPACKET_V1: + if (status != h.h1->tp_status ? TP_STATUS_USER : + TP_STATUS_KERNEL) + return NULL; + break; + case TPACKET_V2: + if (status != h.h2->tp_status ? TP_STATUS_USER : + TP_STATUS_KERNEL) + return NULL; + break; + } + return h.raw; +} + +static void __packet_set_status(struct packet_sock *po, void *frame, int status) +{ + union { + struct tpacket_hdr *h1; + struct tpacket2_hdr *h2; + void *raw; + } h; + + h.raw = frame; + switch (po->tp_version) { + case TPACKET_V1: + h.h1->tp_status = status; + break; + case TPACKET_V2: + h.h2->tp_status = status; + break; + } } #endif @@ -553,14 +592,19 @@ static int tpacket_rcv(struct sk_buff *skb, struct net_device *dev, struct packe struct sock *sk; struct packet_sock *po; struct sockaddr_ll *sll; - struct tpacket_hdr *h; + union { + struct tpacket_hdr *h1; + struct tpacket2_hdr *h2; + void *raw; + } h; u8 * skb_head = skb->data; int skb_len = skb->len; unsigned int snaplen, res; unsigned long status = TP_STATUS_LOSING|TP_STATUS_USER; - unsigned short macoff, netoff; + unsigned short macoff, netoff, hdrlen; struct sk_buff *copy_skb = NULL; struct timeval tv; + struct timespec ts; if (skb->pkt_type == PACKET_LOOPBACK) goto drop; @@ -592,10 +636,13 @@ static int tpacket_rcv(struct sk_buff *skb, struct net_device *dev, struct packe snaplen = res; if (sk->sk_type == SOCK_DGRAM) { - macoff = netoff = TPACKET_ALIGN(TPACKET_HDRLEN) + 16; + macoff = netoff = TPACKET_ALIGN(po->tp_hdrlen) + 16 + + po->tp_reserve; } else { unsigned maclen = skb_network_offset(skb); - netoff = TPACKET_ALIGN(TPACKET_HDRLEN + (maclen < 16 ? 16 : maclen)); + netoff = TPACKET_ALIGN(po->tp_hdrlen + + (maclen < 16 ? 16 : maclen)) + + po->tp_reserve; macoff = netoff - maclen; } @@ -618,9 +665,8 @@ static int tpacket_rcv(struct sk_buff *skb, struct net_device *dev, struct packe } spin_lock(&sk->sk_receive_queue.lock); - h = packet_lookup_frame(po, po->head); - - if (h->tp_status) + h.raw = packet_lookup_frame(po, po->head, TP_STATUS_KERNEL); + if (!h.raw) goto ring_is_full; po->head = po->head != po->frame_max ? po->head+1 : 0; po->stats.tp_packets++; @@ -632,20 +678,41 @@ static int tpacket_rcv(struct sk_buff *skb, struct net_device *dev, struct packe status &= ~TP_STATUS_LOSING; spin_unlock(&sk->sk_receive_queue.lock); - skb_copy_bits(skb, 0, (u8*)h + macoff, snaplen); + skb_copy_bits(skb, 0, h.raw + macoff, snaplen); - h->tp_len = skb->len; - h->tp_snaplen = snaplen; - h->tp_mac = macoff; - h->tp_net = netoff; - if (skb->tstamp.tv64) - tv = ktime_to_timeval(skb->tstamp); - else - do_gettimeofday(&tv); - h->tp_sec = tv.tv_sec; - h->tp_usec = tv.tv_usec; + switch (po->tp_version) { + case TPACKET_V1: + h.h1->tp_len = skb->len; + h.h1->tp_snaplen = snaplen; + h.h1->tp_mac = macoff; + h.h1->tp_net = netoff; + if (skb->tstamp.tv64) + tv = ktime_to_timeval(skb->tstamp); + else + do_gettimeofday(&tv); + h.h1->tp_sec = tv.tv_sec; + h.h1->tp_usec = tv.tv_usec; + hdrlen = sizeof(*h.h1); + break; + case TPACKET_V2: + h.h2->tp_len = skb->len; + h.h2->tp_snaplen = snaplen; + h.h2->tp_mac = macoff; + h.h2->tp_net = netoff; + if (skb->tstamp.tv64) + ts = ktime_to_timespec(skb->tstamp); + else + getnstimeofday(&ts); + h.h2->tp_sec = ts.tv_sec; + h.h2->tp_nsec = ts.tv_nsec; + h.h2->tp_vlan_tci = skb->vlan_tci; + hdrlen = sizeof(*h.h2); + break; + default: + BUG(); + } - sll = (struct sockaddr_ll*)((u8*)h + TPACKET_ALIGN(sizeof(*h))); + sll = h.raw + TPACKET_ALIGN(hdrlen); sll->sll_halen = dev_parse_header(skb, sll->sll_addr); sll->sll_family = AF_PACKET; sll->sll_hatype = dev->type; @@ -656,14 +723,14 @@ static int tpacket_rcv(struct sk_buff *skb, struct net_device *dev, struct packe else sll->sll_ifindex = dev->ifindex; - h->tp_status = status; + __packet_set_status(po, h.raw, status); smp_mb(); { struct page *p_start, *p_end; - u8 *h_end = (u8 *)h + macoff + snaplen - 1; + u8 *h_end = h.raw + macoff + snaplen - 1; - p_start = virt_to_page(h); + p_start = virt_to_page(h.raw); p_end = virt_to_page(h_end); while (p_start <= p_end) { flush_dcache_page(p_start); @@ -1109,6 +1176,7 @@ static int packet_recvmsg(struct kiocb *iocb, struct socket *sock, aux.tp_snaplen = skb->len; aux.tp_mac = 0; aux.tp_net = skb_network_offset(skb); + aux.tp_vlan_tci = skb->vlan_tci; put_cmsg(msg, SOL_PACKET, PACKET_AUXDATA, sizeof(aux), &aux); } @@ -1175,7 +1243,8 @@ static int packet_getname(struct socket *sock, struct sockaddr *uaddr, return 0; } -static void packet_dev_mc(struct net_device *dev, struct packet_mclist *i, int what) +static int packet_dev_mc(struct net_device *dev, struct packet_mclist *i, + int what) { switch (i->type) { case PACKET_MR_MULTICAST: @@ -1185,13 +1254,14 @@ static void packet_dev_mc(struct net_device *dev, struct packet_mclist *i, int w dev_mc_delete(dev, i->addr, i->alen, 0); break; case PACKET_MR_PROMISC: - dev_set_promiscuity(dev, what); + return dev_set_promiscuity(dev, what); break; case PACKET_MR_ALLMULTI: - dev_set_allmulti(dev, what); + return dev_set_allmulti(dev, what); break; default:; } + return 0; } static void packet_dev_mclist(struct net_device *dev, struct packet_mclist *i, int what) @@ -1245,7 +1315,11 @@ static int packet_mc_add(struct sock *sk, struct packet_mreq_max *mreq) i->count = 1; i->next = po->mclist; po->mclist = i; - packet_dev_mc(dev, i, +1); + err = packet_dev_mc(dev, i, 1); + if (err) { + po->mclist = i->next; + kfree(i); + } done: rtnl_unlock(); @@ -1358,6 +1432,38 @@ packet_setsockopt(struct socket *sock, int level, int optname, char __user *optv pkt_sk(sk)->copy_thresh = val; return 0; } + case PACKET_VERSION: + { + int val; + + if (optlen != sizeof(val)) + return -EINVAL; + if (po->pg_vec) + return -EBUSY; + if (copy_from_user(&val, optval, sizeof(val))) + return -EFAULT; + switch (val) { + case TPACKET_V1: + case TPACKET_V2: + po->tp_version = val; + return 0; + default: + return -EINVAL; + } + } + case PACKET_RESERVE: + { + unsigned int val; + + if (optlen != sizeof(val)) + return -EINVAL; + if (po->pg_vec) + return -EBUSY; + if (copy_from_user(&val, optval, sizeof(val))) + return -EFAULT; + po->tp_reserve = val; + return 0; + } #endif case PACKET_AUXDATA: { @@ -1433,6 +1539,37 @@ static int packet_getsockopt(struct socket *sock, int level, int optname, data = &val; break; +#ifdef CONFIG_PACKET_MMAP + case PACKET_VERSION: + if (len > sizeof(int)) + len = sizeof(int); + val = po->tp_version; + data = &val; + break; + case PACKET_HDRLEN: + if (len > sizeof(int)) + len = sizeof(int); + if (copy_from_user(&val, optval, len)) + return -EFAULT; + switch (val) { + case TPACKET_V1: + val = sizeof(struct tpacket_hdr); + break; + case TPACKET_V2: + val = sizeof(struct tpacket2_hdr); + break; + default: + return -EINVAL; + } + data = &val; + break; + case PACKET_RESERVE: + if (len > sizeof(unsigned int)) + len = sizeof(unsigned int); + val = po->tp_reserve; + data = &val; + break; +#endif default: return -ENOPROTOOPT; } @@ -1540,7 +1677,7 @@ static int packet_ioctl(struct socket *sock, unsigned int cmd, case SIOCGIFDSTADDR: case SIOCSIFDSTADDR: case SIOCSIFFLAGS: - if (sock_net(sk) != &init_net) + if (!net_eq(sock_net(sk), &init_net)) return -ENOIOCTLCMD; return inet_dgram_ops.ioctl(sock, cmd, arg); #endif @@ -1566,11 +1703,8 @@ static unsigned int packet_poll(struct file * file, struct socket *sock, spin_lock_bh(&sk->sk_receive_queue.lock); if (po->pg_vec) { unsigned last = po->head ? po->head-1 : po->frame_max; - struct tpacket_hdr *h; - - h = packet_lookup_frame(po, last); - if (h->tp_status) + if (packet_lookup_frame(po, last, TP_STATUS_USER)) mask |= POLLIN | POLLRDNORM; } spin_unlock_bh(&sk->sk_receive_queue.lock); @@ -1665,11 +1799,21 @@ static int packet_set_ring(struct sock *sk, struct tpacket_req *req, int closing if (unlikely(po->pg_vec)) return -EBUSY; + switch (po->tp_version) { + case TPACKET_V1: + po->tp_hdrlen = TPACKET_HDRLEN; + break; + case TPACKET_V2: + po->tp_hdrlen = TPACKET2_HDRLEN; + break; + } + if (unlikely((int)req->tp_block_size <= 0)) return -EINVAL; if (unlikely(req->tp_block_size & (PAGE_SIZE - 1))) return -EINVAL; - if (unlikely(req->tp_frame_size < TPACKET_HDRLEN)) + if (unlikely(req->tp_frame_size < po->tp_hdrlen + + po->tp_reserve)) return -EINVAL; if (unlikely(req->tp_frame_size & (TPACKET_ALIGNMENT - 1))) return -EINVAL; @@ -1688,13 +1832,11 @@ static int packet_set_ring(struct sock *sk, struct tpacket_req *req, int closing goto out; for (i = 0; i < req->tp_block_nr; i++) { - char *ptr = pg_vec[i]; - struct tpacket_hdr *header; + void *ptr = pg_vec[i]; int k; for (k = 0; k < po->frames_per_block; k++) { - header = (struct tpacket_hdr *) ptr; - header->tp_status = TP_STATUS_KERNEL; + __packet_set_status(po, ptr, TP_STATUS_KERNEL); ptr += req->tp_frame_size; } } diff --git a/net/rfkill/rfkill-input.c b/net/rfkill/rfkill-input.c index e4b051dbed61..8aa822730145 100644 --- a/net/rfkill/rfkill-input.c +++ b/net/rfkill/rfkill-input.c @@ -30,39 +30,62 @@ struct rfkill_task { spinlock_t lock; /* for accessing last and desired state */ unsigned long last; /* last schedule */ enum rfkill_state desired_state; /* on/off */ - enum rfkill_state current_state; /* on/off */ }; static void rfkill_task_handler(struct work_struct *work) { struct rfkill_task *task = container_of(work, struct rfkill_task, work); - enum rfkill_state state; mutex_lock(&task->mutex); - /* - * Use temp variable to fetch desired state to keep it - * consistent even if rfkill_schedule_toggle() runs in - * another thread or interrupts us. - */ - state = task->desired_state; + rfkill_switch_all(task->type, task->desired_state); - if (state != task->current_state) { - rfkill_switch_all(task->type, state); - task->current_state = state; + mutex_unlock(&task->mutex); +} + +static void rfkill_task_epo_handler(struct work_struct *work) +{ + rfkill_epo(); +} + +static DECLARE_WORK(epo_work, rfkill_task_epo_handler); + +static void rfkill_schedule_epo(void) +{ + schedule_work(&epo_work); +} + +static void rfkill_schedule_set(struct rfkill_task *task, + enum rfkill_state desired_state) +{ + unsigned long flags; + + if (unlikely(work_pending(&epo_work))) + return; + + spin_lock_irqsave(&task->lock, flags); + + if (time_after(jiffies, task->last + msecs_to_jiffies(200))) { + task->desired_state = desired_state; + task->last = jiffies; + schedule_work(&task->work); } - mutex_unlock(&task->mutex); + spin_unlock_irqrestore(&task->lock, flags); } static void rfkill_schedule_toggle(struct rfkill_task *task) { unsigned long flags; + if (unlikely(work_pending(&epo_work))) + return; + spin_lock_irqsave(&task->lock, flags); if (time_after(jiffies, task->last + msecs_to_jiffies(200))) { - task->desired_state = !task->desired_state; + task->desired_state = + rfkill_state_complement(task->desired_state); task->last = jiffies; schedule_work(&task->work); } @@ -70,26 +93,26 @@ static void rfkill_schedule_toggle(struct rfkill_task *task) spin_unlock_irqrestore(&task->lock, flags); } -#define DEFINE_RFKILL_TASK(n, t) \ - struct rfkill_task n = { \ - .work = __WORK_INITIALIZER(n.work, \ - rfkill_task_handler), \ - .type = t, \ - .mutex = __MUTEX_INITIALIZER(n.mutex), \ - .lock = __SPIN_LOCK_UNLOCKED(n.lock), \ - .desired_state = RFKILL_STATE_ON, \ - .current_state = RFKILL_STATE_ON, \ +#define DEFINE_RFKILL_TASK(n, t) \ + struct rfkill_task n = { \ + .work = __WORK_INITIALIZER(n.work, \ + rfkill_task_handler), \ + .type = t, \ + .mutex = __MUTEX_INITIALIZER(n.mutex), \ + .lock = __SPIN_LOCK_UNLOCKED(n.lock), \ + .desired_state = RFKILL_STATE_UNBLOCKED, \ } static DEFINE_RFKILL_TASK(rfkill_wlan, RFKILL_TYPE_WLAN); static DEFINE_RFKILL_TASK(rfkill_bt, RFKILL_TYPE_BLUETOOTH); static DEFINE_RFKILL_TASK(rfkill_uwb, RFKILL_TYPE_UWB); static DEFINE_RFKILL_TASK(rfkill_wimax, RFKILL_TYPE_WIMAX); +static DEFINE_RFKILL_TASK(rfkill_wwan, RFKILL_TYPE_WWAN); static void rfkill_event(struct input_handle *handle, unsigned int type, - unsigned int code, int down) + unsigned int code, int data) { - if (type == EV_KEY && down == 1) { + if (type == EV_KEY && data == 1) { switch (code) { case KEY_WLAN: rfkill_schedule_toggle(&rfkill_wlan); @@ -106,6 +129,28 @@ static void rfkill_event(struct input_handle *handle, unsigned int type, default: break; } + } else if (type == EV_SW) { + switch (code) { + case SW_RFKILL_ALL: + /* EVERY radio type. data != 0 means radios ON */ + /* handle EPO (emergency power off) through shortcut */ + if (data) { + rfkill_schedule_set(&rfkill_wwan, + RFKILL_STATE_UNBLOCKED); + rfkill_schedule_set(&rfkill_wimax, + RFKILL_STATE_UNBLOCKED); + rfkill_schedule_set(&rfkill_uwb, + RFKILL_STATE_UNBLOCKED); + rfkill_schedule_set(&rfkill_bt, + RFKILL_STATE_UNBLOCKED); + rfkill_schedule_set(&rfkill_wlan, + RFKILL_STATE_UNBLOCKED); + } else + rfkill_schedule_epo(); + break; + default: + break; + } } } @@ -168,6 +213,11 @@ static const struct input_device_id rfkill_ids[] = { .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) }, + }, { } }; diff --git a/net/rfkill/rfkill-input.h b/net/rfkill/rfkill-input.h index 4dae5006fc77..f63d05045685 100644 --- a/net/rfkill/rfkill-input.h +++ b/net/rfkill/rfkill-input.h @@ -12,5 +12,6 @@ #define __RFKILL_INPUT_H void rfkill_switch_all(enum rfkill_type type, enum rfkill_state state); +void rfkill_epo(void); #endif /* __RFKILL_INPUT_H */ diff --git a/net/rfkill/rfkill.c b/net/rfkill/rfkill.c index 4e10a95de832..7a560b785097 100644 --- a/net/rfkill/rfkill.c +++ b/net/rfkill/rfkill.c @@ -39,8 +39,56 @@ MODULE_LICENSE("GPL"); static LIST_HEAD(rfkill_list); /* list of registered rf switches */ static DEFINE_MUTEX(rfkill_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"); + static enum rfkill_state rfkill_states[RFKILL_TYPE_MAX]; +static BLOCKING_NOTIFIER_HEAD(rfkill_notifier_list); + + +/** + * register_rfkill_notifier - Add notifier to rfkill notifier chain + * @nb: pointer to the new entry to add to the chain + * + * See blocking_notifier_chain_register() for return value and further + * observations. + * + * Adds a notifier to the rfkill notifier chain. The chain will be + * called with a pointer to the relevant rfkill structure as a parameter, + * refer to include/linux/rfkill.h for the possible events. + * + * Notifiers added to this chain are to always return NOTIFY_DONE. This + * chain is a blocking notifier chain: notifiers can sleep. + * + * Calls to this chain may have been done through a workqueue. One must + * assume unordered asynchronous behaviour, there is no way to know if + * actions related to the event that generated the notification have been + * carried out already. + */ +int register_rfkill_notifier(struct notifier_block *nb) +{ + return blocking_notifier_chain_register(&rfkill_notifier_list, nb); +} +EXPORT_SYMBOL_GPL(register_rfkill_notifier); + +/** + * unregister_rfkill_notifier - remove notifier from rfkill notifier chain + * @nb: pointer to the entry to remove from the chain + * + * See blocking_notifier_chain_unregister() for return value and further + * observations. + * + * Removes a notifier from the rfkill notifier chain. + */ +int unregister_rfkill_notifier(struct notifier_block *nb) +{ + return blocking_notifier_chain_unregister(&rfkill_notifier_list, nb); +} +EXPORT_SYMBOL_GPL(unregister_rfkill_notifier); + static void rfkill_led_trigger(struct rfkill *rfkill, enum rfkill_state state) @@ -50,24 +98,101 @@ static void rfkill_led_trigger(struct rfkill *rfkill, if (!led->name) return; - if (state == RFKILL_STATE_OFF) + if (state != RFKILL_STATE_UNBLOCKED) led_trigger_event(led, LED_OFF); else led_trigger_event(led, LED_FULL); #endif /* CONFIG_RFKILL_LEDS */ } +static void notify_rfkill_state_change(struct rfkill *rfkill) +{ + blocking_notifier_call_chain(&rfkill_notifier_list, + RFKILL_STATE_CHANGED, + rfkill); +} + +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) + notify_rfkill_state_change(rfkill); + } + mutex_unlock(&rfkill->mutex); + } +} + +/** + * 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. + * + * Note that @force 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 aquired rfkill_mutex. + */ static int rfkill_toggle_radio(struct rfkill *rfkill, - enum rfkill_state state) + enum rfkill_state state, + int force) { int retval = 0; + enum rfkill_state oldstate, newstate; + + 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; + } - if (state != rfkill->state) { + if (force || state != rfkill->state) { retval = rfkill->toggle_radio(rfkill->data, state); - if (!retval) { + /* never allow a HARD->SOFT downgrade! */ + if (!retval && rfkill->state != RFKILL_STATE_HARD_BLOCKED) rfkill->state = state; - rfkill_led_trigger(rfkill, state); - } + } + + if (force || rfkill->state != oldstate) { + rfkill_led_trigger(rfkill, rfkill->state); + notify_rfkill_state_change(rfkill); } return retval; @@ -82,7 +207,6 @@ static int rfkill_toggle_radio(struct rfkill *rfkill, * a specific switch is claimed by userspace in which case it is * left alone. */ - void rfkill_switch_all(enum rfkill_type type, enum rfkill_state state) { struct rfkill *rfkill; @@ -93,13 +217,66 @@ void rfkill_switch_all(enum rfkill_type type, enum rfkill_state state) list_for_each_entry(rfkill, &rfkill_list, node) { if ((!rfkill->user_claim) && (rfkill->type == type)) - rfkill_toggle_radio(rfkill, state); + rfkill_toggle_radio(rfkill, state, 0); } mutex_unlock(&rfkill_mutex); } EXPORT_SYMBOL(rfkill_switch_all); +/** + * rfkill_epo - emergency power off all transmitters + * + * This kicks all rfkill devices to RFKILL_STATE_SOFT_BLOCKED, ignoring + * everything in its path but rfkill_mutex. + */ +void rfkill_epo(void) +{ + struct rfkill *rfkill; + + mutex_lock(&rfkill_mutex); + list_for_each_entry(rfkill, &rfkill_list, node) { + rfkill_toggle_radio(rfkill, RFKILL_STATE_SOFT_BLOCKED, 1); + } + mutex_unlock(&rfkill_mutex); +} +EXPORT_SYMBOL_GPL(rfkill_epo); + +/** + * 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. + * + * It may not be called from an atomic context. + */ +int rfkill_force_state(struct rfkill *rfkill, enum rfkill_state state) +{ + enum rfkill_state oldstate; + + if (state != RFKILL_STATE_SOFT_BLOCKED && + state != RFKILL_STATE_UNBLOCKED && + state != RFKILL_STATE_HARD_BLOCKED) + return -EINVAL; + + mutex_lock(&rfkill->mutex); + + oldstate = rfkill->state; + rfkill->state = state; + + if (state != oldstate) + notify_rfkill_state_change(rfkill); + + mutex_unlock(&rfkill->mutex); + + return 0; +} +EXPORT_SYMBOL(rfkill_force_state); + static ssize_t rfkill_name_show(struct device *dev, struct device_attribute *attr, char *buf) @@ -109,31 +286,31 @@ static ssize_t rfkill_name_show(struct device *dev, return sprintf(buf, "%s\n", rfkill->name); } -static ssize_t rfkill_type_show(struct device *dev, - struct device_attribute *attr, - char *buf) +static const char *rfkill_get_type_str(enum rfkill_type type) { - struct rfkill *rfkill = to_rfkill(dev); - const char *type; - - switch (rfkill->type) { + switch (type) { case RFKILL_TYPE_WLAN: - type = "wlan"; - break; + return "wlan"; case RFKILL_TYPE_BLUETOOTH: - type = "bluetooth"; - break; + return "bluetooth"; case RFKILL_TYPE_UWB: - type = "ultrawideband"; - break; + return "ultrawideband"; case RFKILL_TYPE_WIMAX: - type = "wimax"; - break; + 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", type); + return sprintf(buf, "%s\n", rfkill_get_type_str(rfkill->type)); } static ssize_t rfkill_state_show(struct device *dev, @@ -142,6 +319,7 @@ static ssize_t rfkill_state_show(struct device *dev, { struct rfkill *rfkill = to_rfkill(dev); + update_rfkill_state(rfkill); return sprintf(buf, "%d\n", rfkill->state); } @@ -156,10 +334,14 @@ static ssize_t rfkill_state_store(struct device *dev, if (!capable(CAP_NET_ADMIN)) return -EPERM; + /* RFKILL_STATE_HARD_BLOCKED is illegal here... */ + if (state != RFKILL_STATE_UNBLOCKED && + state != RFKILL_STATE_SOFT_BLOCKED) + return -EINVAL; + if (mutex_lock_interruptible(&rfkill->mutex)) return -ERESTARTSYS; - error = rfkill_toggle_radio(rfkill, - state ? RFKILL_STATE_ON : RFKILL_STATE_OFF); + error = rfkill_toggle_radio(rfkill, state, 0); mutex_unlock(&rfkill->mutex); return error ? error : count; @@ -200,7 +382,8 @@ static ssize_t rfkill_claim_store(struct device *dev, if (rfkill->user_claim != claim) { if (!claim) rfkill_toggle_radio(rfkill, - rfkill_states[rfkill->type]); + rfkill_states[rfkill->type], + 0); rfkill->user_claim = claim; } @@ -233,12 +416,12 @@ static int rfkill_suspend(struct device *dev, pm_message_t state) if (dev->power.power_state.event != state.event) { if (state.event & PM_EVENT_SLEEP) { - mutex_lock(&rfkill->mutex); - - if (rfkill->state == RFKILL_STATE_ON) - rfkill->toggle_radio(rfkill->data, - RFKILL_STATE_OFF); + /* Stop transmitter, keep state, no notifies */ + update_rfkill_state(rfkill); + mutex_lock(&rfkill->mutex); + rfkill->toggle_radio(rfkill->data, + RFKILL_STATE_SOFT_BLOCKED); mutex_unlock(&rfkill->mutex); } @@ -255,8 +438,8 @@ static int rfkill_resume(struct device *dev) if (dev->power.power_state.event != PM_EVENT_ON) { mutex_lock(&rfkill->mutex); - if (rfkill->state == RFKILL_STATE_ON) - rfkill->toggle_radio(rfkill->data, RFKILL_STATE_ON); + /* restore radio state AND notify everybody */ + rfkill_toggle_radio(rfkill, rfkill->state, 1); mutex_unlock(&rfkill->mutex); } @@ -269,34 +452,71 @@ static int rfkill_resume(struct device *dev) #define rfkill_resume NULL #endif +static int rfkill_blocking_uevent_notifier(struct notifier_block *nb, + unsigned long eventid, + void *data) +{ + struct rfkill *rfkill = (struct rfkill *)data; + + switch (eventid) { + case RFKILL_STATE_CHANGED: + kobject_uevent(&rfkill->dev.kobj, KOBJ_CHANGE); + break; + default: + break; + } + + return NOTIFY_DONE; +} + +static struct notifier_block rfkill_blocking_uevent_nb = { + .notifier_call = rfkill_blocking_uevent_notifier, + .priority = 0, +}; + +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_add_switch(struct rfkill *rfkill) { - int error; - mutex_lock(&rfkill_mutex); - error = rfkill_toggle_radio(rfkill, rfkill_states[rfkill->type]); - if (!error) - list_add_tail(&rfkill->node, &rfkill_list); + rfkill_toggle_radio(rfkill, rfkill_states[rfkill->type], 0); + + list_add_tail(&rfkill->node, &rfkill_list); mutex_unlock(&rfkill_mutex); - return error; + return 0; } static void rfkill_remove_switch(struct rfkill *rfkill) { mutex_lock(&rfkill_mutex); list_del_init(&rfkill->node); - rfkill_toggle_radio(rfkill, RFKILL_STATE_OFF); + rfkill_toggle_radio(rfkill, RFKILL_STATE_SOFT_BLOCKED, 1); mutex_unlock(&rfkill_mutex); } @@ -412,7 +632,7 @@ int rfkill_register(struct rfkill *rfkill) EXPORT_SYMBOL(rfkill_register); /** - * rfkill_unregister - Uegister a rfkill structure. + * rfkill_unregister - Unregister a rfkill structure. * @rfkill: rfkill structure to be unregistered * * This function should be called by the network driver during device @@ -436,8 +656,13 @@ 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 < ARRAY_SIZE(rfkill_states); i++) - rfkill_states[i] = RFKILL_STATE_ON; + rfkill_states[i] = rfkill_default_state; error = class_register(&rfkill_class); if (error) { @@ -445,11 +670,14 @@ static int __init rfkill_init(void) return error; } + register_rfkill_notifier(&rfkill_blocking_uevent_nb); + return 0; } static void __exit rfkill_exit(void) { + unregister_rfkill_notifier(&rfkill_blocking_uevent_nb); class_unregister(&rfkill_class); } diff --git a/net/rose/af_rose.c b/net/rose/af_rose.c index 1ebf65294405..dbc963b4f5fb 100644 --- a/net/rose/af_rose.c +++ b/net/rose/af_rose.c @@ -75,6 +75,18 @@ ax25_address rose_callsign; */ static struct lock_class_key rose_netdev_xmit_lock_key; +static void rose_set_lockdep_one(struct net_device *dev, + struct netdev_queue *txq, + void *_unused) +{ + lockdep_set_class(&txq->_xmit_lock, &rose_netdev_xmit_lock_key); +} + +static void rose_set_lockdep_key(struct net_device *dev) +{ + netdev_for_each_tx_queue(dev, rose_set_lockdep_one, NULL); +} + /* * Convert a ROSE address into text. */ @@ -197,7 +209,7 @@ static int rose_device_event(struct notifier_block *this, unsigned long event, { struct net_device *dev = (struct net_device *)ptr; - if (dev_net(dev) != &init_net) + if (!net_eq(dev_net(dev), &init_net)) return NOTIFY_DONE; if (event != NETDEV_DOWN) @@ -566,13 +578,11 @@ static struct sock *rose_make_new(struct sock *osk) #endif sk->sk_type = osk->sk_type; - sk->sk_socket = osk->sk_socket; sk->sk_priority = osk->sk_priority; sk->sk_protocol = osk->sk_protocol; sk->sk_rcvbuf = osk->sk_rcvbuf; sk->sk_sndbuf = osk->sk_sndbuf; sk->sk_state = TCP_ESTABLISHED; - sk->sk_sleep = osk->sk_sleep; sock_copy_flags(sk, osk); init_timer(&rose->timer); @@ -759,7 +769,7 @@ static int rose_connect(struct socket *sock, struct sockaddr *uaddr, int addr_le sock->state = SS_UNCONNECTED; rose->neighbour = rose_get_neigh(&addr->srose_addr, &cause, - &diagnostic); + &diagnostic, 0); if (!rose->neighbour) { err = -ENETUNREACH; goto out_release; @@ -855,7 +865,7 @@ rose_try_next_neigh: if (sk->sk_state != TCP_ESTABLISHED) { /* Try next neighbour */ - rose->neighbour = rose_get_neigh(&addr->srose_addr, &cause, &diagnostic); + rose->neighbour = rose_get_neigh(&addr->srose_addr, &cause, &diagnostic, 0); if (rose->neighbour) goto rose_try_next_neigh; @@ -924,14 +934,12 @@ static int rose_accept(struct socket *sock, struct socket *newsock, int flags) goto out_release; newsk = skb->sk; - newsk->sk_socket = newsock; - newsk->sk_sleep = &newsock->wait; + sock_graft(newsk, newsock); /* Now attach up the new socket */ skb->sk = NULL; kfree_skb(skb); sk->sk_ack_backlog--; - newsock->sk = newsk; out_release: release_sock(sk); @@ -1580,7 +1588,7 @@ static int __init rose_proto_init(void) free_netdev(dev); goto fail; } - lockdep_set_class(&dev->_xmit_lock, &rose_netdev_xmit_lock_key); + rose_set_lockdep_key(dev); dev_rose[i] = dev; } diff --git a/net/rose/rose_route.c b/net/rose/rose_route.c index bd593871c81e..a81066a1010a 100644 --- a/net/rose/rose_route.c +++ b/net/rose/rose_route.c @@ -662,27 +662,34 @@ struct rose_route *rose_route_free_lci(unsigned int lci, struct rose_neigh *neig } /* - * Find a neighbour given a ROSE address. + * Find a neighbour or a route given a ROSE address. */ struct rose_neigh *rose_get_neigh(rose_address *addr, unsigned char *cause, - unsigned char *diagnostic) + unsigned char *diagnostic, int new) { struct rose_neigh *res = NULL; struct rose_node *node; int failed = 0; int i; - spin_lock_bh(&rose_node_list_lock); + if (!new) spin_lock_bh(&rose_node_list_lock); for (node = rose_node_list; node != NULL; node = node->next) { if (rosecmpm(addr, &node->address, node->mask) == 0) { for (i = 0; i < node->count; i++) { - if (!rose_ftimer_running(node->neighbour[i])) { - res = node->neighbour[i]; - goto out; - } else - failed = 1; + if (new) { + if (node->neighbour[i]->restarted) { + res = node->neighbour[i]; + goto out; + } + } + else { + if (!rose_ftimer_running(node->neighbour[i])) { + res = node->neighbour[i]; + goto out; + } else + failed = 1; + } } - break; } } @@ -695,7 +702,7 @@ struct rose_neigh *rose_get_neigh(rose_address *addr, unsigned char *cause, } out: - spin_unlock_bh(&rose_node_list_lock); + if (!new) spin_unlock_bh(&rose_node_list_lock); return res; } @@ -1018,7 +1025,7 @@ int rose_route_frame(struct sk_buff *skb, ax25_cb *ax25) rose_route = rose_route->next; } - if ((new_neigh = rose_get_neigh(dest_addr, &cause, &diagnostic)) == NULL) { + if ((new_neigh = rose_get_neigh(dest_addr, &cause, &diagnostic, 1)) == NULL) { rose_transmit_clear_request(rose_neigh, lci, cause, diagnostic); goto out; } diff --git a/net/rxrpc/ar-input.c b/net/rxrpc/ar-input.c index f8a699e92962..f98c8027e5c1 100644 --- a/net/rxrpc/ar-input.c +++ b/net/rxrpc/ar-input.c @@ -21,6 +21,7 @@ #include <net/af_rxrpc.h> #include <net/ip.h> #include <net/udp.h> +#include <net/net_namespace.h> #include "ar-internal.h" unsigned long rxrpc_ack_timeout = 1; @@ -708,12 +709,12 @@ void rxrpc_data_ready(struct sock *sk, int count) if (skb_checksum_complete(skb)) { rxrpc_free_skb(skb); rxrpc_put_local(local); - UDP_INC_STATS_BH(UDP_MIB_INERRORS, 0); + UDP_INC_STATS_BH(&init_net, UDP_MIB_INERRORS, 0); _leave(" [CSUM failed]"); return; } - UDP_INC_STATS_BH(UDP_MIB_INDATAGRAMS, 0); + UDP_INC_STATS_BH(&init_net, UDP_MIB_INDATAGRAMS, 0); /* the socket buffer we have is owned by UDP, with UDP's data all over * it, but we really want our own */ diff --git a/net/sched/act_gact.c b/net/sched/act_gact.c index 422872c4f14b..ac04289da5d7 100644 --- a/net/sched/act_gact.c +++ b/net/sched/act_gact.c @@ -139,7 +139,7 @@ static int tcf_gact(struct sk_buff *skb, struct tc_action *a, struct tcf_result #else action = gact->tcf_action; #endif - gact->tcf_bstats.bytes += skb->len; + gact->tcf_bstats.bytes += qdisc_pkt_len(skb); gact->tcf_bstats.packets++; if (action == TC_ACT_SHOT) gact->tcf_qstats.drops++; diff --git a/net/sched/act_ipt.c b/net/sched/act_ipt.c index da696fd3e341..d1263b3c96c3 100644 --- a/net/sched/act_ipt.c +++ b/net/sched/act_ipt.c @@ -205,7 +205,7 @@ static int tcf_ipt(struct sk_buff *skb, struct tc_action *a, spin_lock(&ipt->tcf_lock); ipt->tcf_tm.lastuse = jiffies; - ipt->tcf_bstats.bytes += skb->len; + ipt->tcf_bstats.bytes += qdisc_pkt_len(skb); ipt->tcf_bstats.packets++; /* yes, we have to worry about both in and out dev diff --git a/net/sched/act_mirred.c b/net/sched/act_mirred.c index 1aff005d95cd..70341c020b6d 100644 --- a/net/sched/act_mirred.c +++ b/net/sched/act_mirred.c @@ -164,7 +164,7 @@ bad_mirred: if (skb2 != NULL) kfree_skb(skb2); m->tcf_qstats.overlimits++; - m->tcf_bstats.bytes += skb->len; + m->tcf_bstats.bytes += qdisc_pkt_len(skb); m->tcf_bstats.packets++; spin_unlock(&m->tcf_lock); /* should we be asking for packet to be dropped? @@ -184,7 +184,7 @@ bad_mirred: goto bad_mirred; } - m->tcf_bstats.bytes += skb2->len; + m->tcf_bstats.bytes += qdisc_pkt_len(skb2); m->tcf_bstats.packets++; if (!(at & AT_EGRESS)) if (m->tcfm_ok_push) diff --git a/net/sched/act_nat.c b/net/sched/act_nat.c index 0a3c8339767a..7b39ed485bca 100644 --- a/net/sched/act_nat.c +++ b/net/sched/act_nat.c @@ -124,7 +124,7 @@ static int tcf_nat(struct sk_buff *skb, struct tc_action *a, egress = p->flags & TCA_NAT_FLAG_EGRESS; action = p->tcf_action; - p->tcf_bstats.bytes += skb->len; + p->tcf_bstats.bytes += qdisc_pkt_len(skb); p->tcf_bstats.packets++; spin_unlock(&p->tcf_lock); diff --git a/net/sched/act_pedit.c b/net/sched/act_pedit.c index 3cc4cb9e500e..d5f4e3404864 100644 --- a/net/sched/act_pedit.c +++ b/net/sched/act_pedit.c @@ -182,7 +182,7 @@ static int tcf_pedit(struct sk_buff *skb, struct tc_action *a, bad: p->tcf_qstats.overlimits++; done: - p->tcf_bstats.bytes += skb->len; + p->tcf_bstats.bytes += qdisc_pkt_len(skb); p->tcf_bstats.packets++; spin_unlock(&p->tcf_lock); return p->tcf_action; diff --git a/net/sched/act_police.c b/net/sched/act_police.c index 0898120bbcc0..32c3f9d9fb7a 100644 --- a/net/sched/act_police.c +++ b/net/sched/act_police.c @@ -272,7 +272,7 @@ static int tcf_act_police(struct sk_buff *skb, struct tc_action *a, spin_lock(&police->tcf_lock); - police->tcf_bstats.bytes += skb->len; + police->tcf_bstats.bytes += qdisc_pkt_len(skb); police->tcf_bstats.packets++; if (police->tcfp_ewma_rate && @@ -282,7 +282,7 @@ static int tcf_act_police(struct sk_buff *skb, struct tc_action *a, return police->tcf_action; } - if (skb->len <= police->tcfp_mtu) { + if (qdisc_pkt_len(skb) <= police->tcfp_mtu) { if (police->tcfp_R_tab == NULL) { spin_unlock(&police->tcf_lock); return police->tcfp_result; @@ -295,12 +295,12 @@ static int tcf_act_police(struct sk_buff *skb, struct tc_action *a, ptoks = toks + police->tcfp_ptoks; if (ptoks > (long)L2T_P(police, police->tcfp_mtu)) ptoks = (long)L2T_P(police, police->tcfp_mtu); - ptoks -= L2T_P(police, skb->len); + ptoks -= L2T_P(police, qdisc_pkt_len(skb)); } toks += police->tcfp_toks; if (toks > (long)police->tcfp_burst) toks = police->tcfp_burst; - toks -= L2T(police, skb->len); + toks -= L2T(police, qdisc_pkt_len(skb)); if ((toks|ptoks) >= 0) { police->tcfp_t_c = now; police->tcfp_toks = toks; diff --git a/net/sched/act_simple.c b/net/sched/act_simple.c index 1d421d059caf..e7851ce92cfe 100644 --- a/net/sched/act_simple.c +++ b/net/sched/act_simple.c @@ -41,7 +41,7 @@ static int tcf_simp(struct sk_buff *skb, struct tc_action *a, struct tcf_result spin_lock(&d->tcf_lock); d->tcf_tm.lastuse = jiffies; - d->tcf_bstats.bytes += skb->len; + d->tcf_bstats.bytes += qdisc_pkt_len(skb); d->tcf_bstats.packets++; /* print policy string followed by _ then packet count diff --git a/net/sched/cls_api.c b/net/sched/cls_api.c index 9360fc81e8c7..d2b6f54a6261 100644 --- a/net/sched/cls_api.c +++ b/net/sched/cls_api.c @@ -120,6 +120,7 @@ static int tc_ctl_tfilter(struct sk_buff *skb, struct nlmsghdr *n, void *arg) { struct net *net = sock_net(skb->sk); struct nlattr *tca[TCA_MAX + 1]; + spinlock_t *root_lock; struct tcmsg *t; u32 protocol; u32 prio; @@ -166,7 +167,8 @@ replay: /* Find qdisc */ if (!parent) { - q = dev->qdisc_sleeping; + struct netdev_queue *dev_queue = netdev_get_tx_queue(dev, 0); + q = dev_queue->qdisc_sleeping; parent = q->handle; } else { q = qdisc_lookup(dev, TC_H_MAJ(t->tcm_parent)); @@ -203,6 +205,8 @@ replay: } } + root_lock = qdisc_root_lock(q); + if (tp == NULL) { /* Proto-tcf does not exist, create new one */ @@ -262,10 +266,10 @@ replay: goto errout; } - qdisc_lock_tree(dev); + spin_lock_bh(root_lock); tp->next = *back; *back = tp; - qdisc_unlock_tree(dev); + spin_unlock_bh(root_lock); } else if (tca[TCA_KIND] && nla_strcmp(tca[TCA_KIND], tp->ops->kind)) goto errout; @@ -274,9 +278,9 @@ replay: if (fh == 0) { if (n->nlmsg_type == RTM_DELTFILTER && t->tcm_handle == 0) { - qdisc_lock_tree(dev); + spin_lock_bh(root_lock); *back = tp->next; - qdisc_unlock_tree(dev); + spin_lock_bh(root_lock); tfilter_notify(skb, n, tp, fh, RTM_DELTFILTER); tcf_destroy(tp); @@ -334,7 +338,7 @@ static int tcf_fill_node(struct sk_buff *skb, struct tcf_proto *tp, tcm->tcm_family = AF_UNSPEC; tcm->tcm__pad1 = 0; tcm->tcm__pad1 = 0; - tcm->tcm_ifindex = tp->q->dev->ifindex; + tcm->tcm_ifindex = qdisc_dev(tp->q)->ifindex; tcm->tcm_parent = tp->classid; tcm->tcm_info = TC_H_MAKE(tp->prio, tp->protocol); NLA_PUT_STRING(skb, TCA_KIND, tp->ops->kind); @@ -390,6 +394,7 @@ static int tcf_node_dump(struct tcf_proto *tp, unsigned long n, static int tc_dump_tfilter(struct sk_buff *skb, struct netlink_callback *cb) { struct net *net = sock_net(skb->sk); + struct netdev_queue *dev_queue; int t; int s_t; struct net_device *dev; @@ -408,8 +413,9 @@ static int tc_dump_tfilter(struct sk_buff *skb, struct netlink_callback *cb) if ((dev = dev_get_by_index(&init_net, tcm->tcm_ifindex)) == NULL) return skb->len; + dev_queue = netdev_get_tx_queue(dev, 0); if (!tcm->tcm_parent) - q = dev->qdisc_sleeping; + q = dev_queue->qdisc_sleeping; else q = qdisc_lookup(dev, TC_H_MAJ(tcm->tcm_parent)); if (!q) diff --git a/net/sched/cls_flow.c b/net/sched/cls_flow.c index 971b867e0484..8f63a1a94014 100644 --- a/net/sched/cls_flow.c +++ b/net/sched/cls_flow.c @@ -36,6 +36,8 @@ struct flow_filter { struct list_head list; struct tcf_exts exts; struct tcf_ematch_tree ematches; + struct timer_list perturb_timer; + u32 perturb_period; u32 handle; u32 nkeys; @@ -47,11 +49,9 @@ struct flow_filter { u32 addend; u32 divisor; u32 baseclass; + u32 hashrnd; }; -static u32 flow_hashrnd __read_mostly; -static int flow_hashrnd_initted __read_mostly; - static const struct tcf_ext_map flow_ext_map = { .action = TCA_FLOW_ACT, .police = TCA_FLOW_POLICE, @@ -348,7 +348,7 @@ static int flow_classify(struct sk_buff *skb, struct tcf_proto *tp, } if (f->mode == FLOW_MODE_HASH) - classid = jhash2(keys, f->nkeys, flow_hashrnd); + classid = jhash2(keys, f->nkeys, f->hashrnd); else { classid = keys[0]; classid = (classid & f->mask) ^ f->xor; @@ -369,6 +369,15 @@ static int flow_classify(struct sk_buff *skb, struct tcf_proto *tp, return -1; } +static void flow_perturbation(unsigned long arg) +{ + struct flow_filter *f = (struct flow_filter *)arg; + + get_random_bytes(&f->hashrnd, 4); + if (f->perturb_period) + mod_timer(&f->perturb_timer, jiffies + f->perturb_period); +} + static const struct nla_policy flow_policy[TCA_FLOW_MAX + 1] = { [TCA_FLOW_KEYS] = { .type = NLA_U32 }, [TCA_FLOW_MODE] = { .type = NLA_U32 }, @@ -381,6 +390,7 @@ static const struct nla_policy flow_policy[TCA_FLOW_MAX + 1] = { [TCA_FLOW_ACT] = { .type = NLA_NESTED }, [TCA_FLOW_POLICE] = { .type = NLA_NESTED }, [TCA_FLOW_EMATCHES] = { .type = NLA_NESTED }, + [TCA_FLOW_PERTURB] = { .type = NLA_U32 }, }; static int flow_change(struct tcf_proto *tp, unsigned long base, @@ -394,6 +404,7 @@ static int flow_change(struct tcf_proto *tp, unsigned long base, struct tcf_exts e; struct tcf_ematch_tree t; unsigned int nkeys = 0; + unsigned int perturb_period = 0; u32 baseclass = 0; u32 keymask = 0; u32 mode; @@ -442,6 +453,14 @@ static int flow_change(struct tcf_proto *tp, unsigned long base, mode = nla_get_u32(tb[TCA_FLOW_MODE]); if (mode != FLOW_MODE_HASH && nkeys > 1) goto err2; + + if (mode == FLOW_MODE_HASH) + perturb_period = f->perturb_period; + if (tb[TCA_FLOW_PERTURB]) { + if (mode != FLOW_MODE_HASH) + goto err2; + perturb_period = nla_get_u32(tb[TCA_FLOW_PERTURB]) * HZ; + } } else { err = -EINVAL; if (!handle) @@ -455,6 +474,12 @@ static int flow_change(struct tcf_proto *tp, unsigned long base, if (mode != FLOW_MODE_HASH && nkeys > 1) goto err2; + if (tb[TCA_FLOW_PERTURB]) { + if (mode != FLOW_MODE_HASH) + goto err2; + perturb_period = nla_get_u32(tb[TCA_FLOW_PERTURB]) * HZ; + } + if (TC_H_MAJ(baseclass) == 0) baseclass = TC_H_MAKE(tp->q->handle, baseclass); if (TC_H_MIN(baseclass) == 0) @@ -467,6 +492,11 @@ static int flow_change(struct tcf_proto *tp, unsigned long base, f->handle = handle; f->mask = ~0U; + + get_random_bytes(&f->hashrnd, 4); + f->perturb_timer.function = flow_perturbation; + f->perturb_timer.data = (unsigned long)f; + init_timer_deferrable(&f->perturb_timer); } tcf_exts_change(tp, &f->exts, &e); @@ -495,6 +525,11 @@ static int flow_change(struct tcf_proto *tp, unsigned long base, if (baseclass) f->baseclass = baseclass; + f->perturb_period = perturb_period; + del_timer(&f->perturb_timer); + if (perturb_period) + mod_timer(&f->perturb_timer, jiffies + perturb_period); + if (*arg == 0) list_add_tail(&f->list, &head->filters); @@ -512,6 +547,7 @@ err1: static void flow_destroy_filter(struct tcf_proto *tp, struct flow_filter *f) { + del_timer_sync(&f->perturb_timer); tcf_exts_destroy(tp, &f->exts); tcf_em_tree_destroy(tp, &f->ematches); kfree(f); @@ -532,11 +568,6 @@ static int flow_init(struct tcf_proto *tp) { struct flow_head *head; - if (!flow_hashrnd_initted) { - get_random_bytes(&flow_hashrnd, 4); - flow_hashrnd_initted = 1; - } - head = kzalloc(sizeof(*head), GFP_KERNEL); if (head == NULL) return -ENOBUFS; @@ -605,6 +636,9 @@ static int flow_dump(struct tcf_proto *tp, unsigned long fh, if (f->baseclass) NLA_PUT_U32(skb, TCA_FLOW_BASECLASS, f->baseclass); + if (f->perturb_period) + NLA_PUT_U32(skb, TCA_FLOW_PERTURB, f->perturb_period / HZ); + if (tcf_exts_dump(skb, &f->exts, &flow_ext_map) < 0) goto nla_put_failure; #ifdef CONFIG_NET_EMATCH diff --git a/net/sched/cls_route.c b/net/sched/cls_route.c index 784dcb870b98..481260a4f10f 100644 --- a/net/sched/cls_route.c +++ b/net/sched/cls_route.c @@ -73,11 +73,13 @@ static __inline__ int route4_fastmap_hash(u32 id, int iif) } static inline -void route4_reset_fastmap(struct net_device *dev, struct route4_head *head, u32 id) +void route4_reset_fastmap(struct Qdisc *q, struct route4_head *head, u32 id) { - qdisc_lock_tree(dev); + spinlock_t *root_lock = qdisc_root_lock(q); + + spin_lock_bh(root_lock); memset(head->fastmap, 0, sizeof(head->fastmap)); - qdisc_unlock_tree(dev); + spin_unlock_bh(root_lock); } static inline void @@ -302,7 +304,7 @@ static int route4_delete(struct tcf_proto *tp, unsigned long arg) *fp = f->next; tcf_tree_unlock(tp); - route4_reset_fastmap(tp->q->dev, head, f->id); + route4_reset_fastmap(tp->q, head, f->id); route4_delete_filter(tp, f); /* Strip tree */ @@ -500,7 +502,7 @@ reinsert: } tcf_tree_unlock(tp); - route4_reset_fastmap(tp->q->dev, head, f->id); + route4_reset_fastmap(tp->q, head, f->id); *arg = (unsigned long)f; return 0; diff --git a/net/sched/cls_u32.c b/net/sched/cls_u32.c index 4d755444c449..527db2559dd2 100644 --- a/net/sched/cls_u32.c +++ b/net/sched/cls_u32.c @@ -75,7 +75,6 @@ struct tc_u_hnode struct tc_u_common { - struct tc_u_common *next; struct tc_u_hnode *hlist; struct Qdisc *q; int refcnt; @@ -87,8 +86,6 @@ static const struct tcf_ext_map u32_ext_map = { .police = TCA_U32_POLICE }; -static struct tc_u_common *u32_list; - static __inline__ unsigned u32_hash_fold(__be32 key, struct tc_u32_sel *sel, u8 fshift) { unsigned h = ntohl(key & sel->hmask)>>fshift; @@ -287,9 +284,7 @@ static int u32_init(struct tcf_proto *tp) struct tc_u_hnode *root_ht; struct tc_u_common *tp_c; - for (tp_c = u32_list; tp_c; tp_c = tp_c->next) - if (tp_c->q == tp->q) - break; + tp_c = tp->q->u32_node; root_ht = kzalloc(sizeof(*root_ht), GFP_KERNEL); if (root_ht == NULL) @@ -307,8 +302,7 @@ static int u32_init(struct tcf_proto *tp) return -ENOBUFS; } tp_c->q = tp->q; - tp_c->next = u32_list; - u32_list = tp_c; + tp->q->u32_node = tp_c; } tp_c->refcnt++; @@ -402,14 +396,8 @@ static void u32_destroy(struct tcf_proto *tp) if (--tp_c->refcnt == 0) { struct tc_u_hnode *ht; - struct tc_u_common **tp_cp; - for (tp_cp = &u32_list; *tp_cp; tp_cp = &(*tp_cp)->next) { - if (*tp_cp == tp_c) { - *tp_cp = tp_c->next; - break; - } - } + tp->q->u32_node = NULL; for (ht = tp_c->hlist; ht; ht = ht->next) { ht->refcnt--; diff --git a/net/sched/sch_api.c b/net/sched/sch_api.c index 10f01ad04380..5219d5f9d754 100644 --- a/net/sched/sch_api.c +++ b/net/sched/sch_api.c @@ -99,7 +99,7 @@ static int tclass_notify(struct sk_buff *oskb, struct nlmsghdr *n, ---requeue requeues once dequeued packet. It is used for non-standard or - just buggy devices, which can defer output even if dev->tbusy=0. + just buggy devices, which can defer output even if netif_queue_stopped()=0. ---reset @@ -185,11 +185,20 @@ EXPORT_SYMBOL(unregister_qdisc); struct Qdisc *qdisc_lookup(struct net_device *dev, u32 handle) { - struct Qdisc *q; + unsigned int i; + + for (i = 0; i < dev->num_tx_queues; i++) { + struct netdev_queue *txq = netdev_get_tx_queue(dev, i); + struct Qdisc *q, *txq_root = txq->qdisc; + + if (!(txq_root->flags & TCQ_F_BUILTIN) && + txq_root->handle == handle) + return txq_root; - list_for_each_entry(q, &dev->qdisc_list, list) { - if (q->handle == handle) - return q; + list_for_each_entry(q, &txq_root->list, list) { + if (q->handle == handle) + return q; + } } return NULL; } @@ -277,15 +286,137 @@ void qdisc_put_rtab(struct qdisc_rate_table *tab) } EXPORT_SYMBOL(qdisc_put_rtab); +static LIST_HEAD(qdisc_stab_list); +static DEFINE_SPINLOCK(qdisc_stab_lock); + +static const struct nla_policy stab_policy[TCA_STAB_MAX + 1] = { + [TCA_STAB_BASE] = { .len = sizeof(struct tc_sizespec) }, + [TCA_STAB_DATA] = { .type = NLA_BINARY }, +}; + +static struct qdisc_size_table *qdisc_get_stab(struct nlattr *opt) +{ + struct nlattr *tb[TCA_STAB_MAX + 1]; + struct qdisc_size_table *stab; + struct tc_sizespec *s; + unsigned int tsize = 0; + u16 *tab = NULL; + int err; + + err = nla_parse_nested(tb, TCA_STAB_MAX, opt, stab_policy); + if (err < 0) + return ERR_PTR(err); + if (!tb[TCA_STAB_BASE]) + return ERR_PTR(-EINVAL); + + s = nla_data(tb[TCA_STAB_BASE]); + + if (s->tsize > 0) { + if (!tb[TCA_STAB_DATA]) + return ERR_PTR(-EINVAL); + tab = nla_data(tb[TCA_STAB_DATA]); + tsize = nla_len(tb[TCA_STAB_DATA]) / sizeof(u16); + } + + if (!s || tsize != s->tsize || (!tab && tsize > 0)) + return ERR_PTR(-EINVAL); + + spin_lock(&qdisc_stab_lock); + + list_for_each_entry(stab, &qdisc_stab_list, list) { + if (memcmp(&stab->szopts, s, sizeof(*s))) + continue; + if (tsize > 0 && memcmp(stab->data, tab, tsize * sizeof(u16))) + continue; + stab->refcnt++; + spin_unlock(&qdisc_stab_lock); + return stab; + } + + spin_unlock(&qdisc_stab_lock); + + stab = kmalloc(sizeof(*stab) + tsize * sizeof(u16), GFP_KERNEL); + if (!stab) + return ERR_PTR(-ENOMEM); + + stab->refcnt = 1; + stab->szopts = *s; + if (tsize > 0) + memcpy(stab->data, tab, tsize * sizeof(u16)); + + spin_lock(&qdisc_stab_lock); + list_add_tail(&stab->list, &qdisc_stab_list); + spin_unlock(&qdisc_stab_lock); + + return stab; +} + +void qdisc_put_stab(struct qdisc_size_table *tab) +{ + if (!tab) + return; + + spin_lock(&qdisc_stab_lock); + + if (--tab->refcnt == 0) { + list_del(&tab->list); + kfree(tab); + } + + spin_unlock(&qdisc_stab_lock); +} +EXPORT_SYMBOL(qdisc_put_stab); + +static int qdisc_dump_stab(struct sk_buff *skb, struct qdisc_size_table *stab) +{ + struct nlattr *nest; + + nest = nla_nest_start(skb, TCA_STAB); + NLA_PUT(skb, TCA_STAB_BASE, sizeof(stab->szopts), &stab->szopts); + nla_nest_end(skb, nest); + + return skb->len; + +nla_put_failure: + return -1; +} + +void qdisc_calculate_pkt_len(struct sk_buff *skb, struct qdisc_size_table *stab) +{ + int pkt_len, slot; + + pkt_len = skb->len + stab->szopts.overhead; + if (unlikely(!stab->szopts.tsize)) + goto out; + + slot = pkt_len + stab->szopts.cell_align; + if (unlikely(slot < 0)) + slot = 0; + + slot >>= stab->szopts.cell_log; + if (likely(slot < stab->szopts.tsize)) + pkt_len = stab->data[slot]; + else + pkt_len = stab->data[stab->szopts.tsize - 1] * + (slot / stab->szopts.tsize) + + stab->data[slot % stab->szopts.tsize]; + + pkt_len <<= stab->szopts.size_log; +out: + if (unlikely(pkt_len < 1)) + pkt_len = 1; + qdisc_skb_cb(skb)->pkt_len = pkt_len; +} +EXPORT_SYMBOL(qdisc_calculate_pkt_len); + static enum hrtimer_restart qdisc_watchdog(struct hrtimer *timer) { struct qdisc_watchdog *wd = container_of(timer, struct qdisc_watchdog, timer); - struct net_device *dev = wd->qdisc->dev; wd->qdisc->flags &= ~TCQ_F_THROTTLED; smp_wmb(); - netif_schedule(dev); + __netif_schedule(wd->qdisc); return HRTIMER_NORESTART; } @@ -316,6 +447,110 @@ void qdisc_watchdog_cancel(struct qdisc_watchdog *wd) } EXPORT_SYMBOL(qdisc_watchdog_cancel); +struct hlist_head *qdisc_class_hash_alloc(unsigned int n) +{ + unsigned int size = n * sizeof(struct hlist_head), i; + struct hlist_head *h; + + if (size <= PAGE_SIZE) + h = kmalloc(size, GFP_KERNEL); + else + h = (struct hlist_head *) + __get_free_pages(GFP_KERNEL, get_order(size)); + + if (h != NULL) { + for (i = 0; i < n; i++) + INIT_HLIST_HEAD(&h[i]); + } + return h; +} + +static void qdisc_class_hash_free(struct hlist_head *h, unsigned int n) +{ + unsigned int size = n * sizeof(struct hlist_head); + + if (size <= PAGE_SIZE) + kfree(h); + else + free_pages((unsigned long)h, get_order(size)); +} + +void qdisc_class_hash_grow(struct Qdisc *sch, struct Qdisc_class_hash *clhash) +{ + struct Qdisc_class_common *cl; + struct hlist_node *n, *next; + struct hlist_head *nhash, *ohash; + unsigned int nsize, nmask, osize; + unsigned int i, h; + + /* Rehash when load factor exceeds 0.75 */ + if (clhash->hashelems * 4 <= clhash->hashsize * 3) + return; + nsize = clhash->hashsize * 2; + nmask = nsize - 1; + nhash = qdisc_class_hash_alloc(nsize); + if (nhash == NULL) + return; + + ohash = clhash->hash; + osize = clhash->hashsize; + + sch_tree_lock(sch); + for (i = 0; i < osize; i++) { + hlist_for_each_entry_safe(cl, n, next, &ohash[i], hnode) { + h = qdisc_class_hash(cl->classid, nmask); + hlist_add_head(&cl->hnode, &nhash[h]); + } + } + clhash->hash = nhash; + clhash->hashsize = nsize; + clhash->hashmask = nmask; + sch_tree_unlock(sch); + + qdisc_class_hash_free(ohash, osize); +} +EXPORT_SYMBOL(qdisc_class_hash_grow); + +int qdisc_class_hash_init(struct Qdisc_class_hash *clhash) +{ + unsigned int size = 4; + + clhash->hash = qdisc_class_hash_alloc(size); + if (clhash->hash == NULL) + return -ENOMEM; + clhash->hashsize = size; + clhash->hashmask = size - 1; + clhash->hashelems = 0; + return 0; +} +EXPORT_SYMBOL(qdisc_class_hash_init); + +void qdisc_class_hash_destroy(struct Qdisc_class_hash *clhash) +{ + qdisc_class_hash_free(clhash->hash, clhash->hashsize); +} +EXPORT_SYMBOL(qdisc_class_hash_destroy); + +void qdisc_class_hash_insert(struct Qdisc_class_hash *clhash, + struct Qdisc_class_common *cl) +{ + unsigned int h; + + INIT_HLIST_NODE(&cl->hnode); + h = qdisc_class_hash(cl->classid, clhash->hashmask); + hlist_add_head(&cl->hnode, &clhash->hash[h]); + clhash->hashelems++; +} +EXPORT_SYMBOL(qdisc_class_hash_insert); + +void qdisc_class_hash_remove(struct Qdisc_class_hash *clhash, + struct Qdisc_class_common *cl) +{ + hlist_del(&cl->hnode); + clhash->hashelems--; +} +EXPORT_SYMBOL(qdisc_class_hash_remove); + /* Allocate an unique handle from space managed by kernel */ static u32 qdisc_alloc_handle(struct net_device *dev) @@ -332,32 +567,39 @@ static u32 qdisc_alloc_handle(struct net_device *dev) return i>0 ? autohandle : 0; } -/* Attach toplevel qdisc to device dev */ +/* Attach toplevel qdisc to device queue. */ -static struct Qdisc * -dev_graft_qdisc(struct net_device *dev, struct Qdisc *qdisc) +static struct Qdisc *dev_graft_qdisc(struct netdev_queue *dev_queue, + struct Qdisc *qdisc) { + spinlock_t *root_lock; struct Qdisc *oqdisc; + int ingress; + + ingress = 0; + if (qdisc && qdisc->flags&TCQ_F_INGRESS) + ingress = 1; + + if (ingress) { + oqdisc = dev_queue->qdisc; + } else { + oqdisc = dev_queue->qdisc_sleeping; + } - if (dev->flags & IFF_UP) - dev_deactivate(dev); + root_lock = qdisc_root_lock(oqdisc); + spin_lock_bh(root_lock); - qdisc_lock_tree(dev); - if (qdisc && qdisc->flags&TCQ_F_INGRESS) { - oqdisc = dev->qdisc_ingress; + if (ingress) { /* Prune old scheduler */ if (oqdisc && atomic_read(&oqdisc->refcnt) <= 1) { /* delete */ qdisc_reset(oqdisc); - dev->qdisc_ingress = NULL; + dev_queue->qdisc = NULL; } else { /* new */ - dev->qdisc_ingress = qdisc; + dev_queue->qdisc = qdisc; } } else { - - oqdisc = dev->qdisc_sleeping; - /* Prune old scheduler */ if (oqdisc && atomic_read(&oqdisc->refcnt) <= 1) qdisc_reset(oqdisc); @@ -365,14 +607,11 @@ dev_graft_qdisc(struct net_device *dev, struct Qdisc *qdisc) /* ... and graft new one */ if (qdisc == NULL) qdisc = &noop_qdisc; - dev->qdisc_sleeping = qdisc; - dev->qdisc = &noop_qdisc; + dev_queue->qdisc_sleeping = qdisc; + dev_queue->qdisc = &noop_qdisc; } - qdisc_unlock_tree(dev); - - if (dev->flags & IFF_UP) - dev_activate(dev); + spin_unlock_bh(root_lock); return oqdisc; } @@ -389,7 +628,7 @@ void qdisc_tree_decrease_qlen(struct Qdisc *sch, unsigned int n) if (TC_H_MAJ(parentid) == TC_H_MAJ(TC_H_INGRESS)) return; - sch = qdisc_lookup(sch->dev, TC_H_MAJ(parentid)); + sch = qdisc_lookup(qdisc_dev(sch), TC_H_MAJ(parentid)); if (sch == NULL) { WARN_ON(parentid != TC_H_ROOT); return; @@ -405,26 +644,66 @@ void qdisc_tree_decrease_qlen(struct Qdisc *sch, unsigned int n) } EXPORT_SYMBOL(qdisc_tree_decrease_qlen); -/* Graft qdisc "new" to class "classid" of qdisc "parent" or - to device "dev". +static void notify_and_destroy(struct sk_buff *skb, struct nlmsghdr *n, u32 clid, + struct Qdisc *old, struct Qdisc *new) +{ + if (new || old) + qdisc_notify(skb, n, clid, old, new); + + if (old) { + spin_lock_bh(&old->q.lock); + qdisc_destroy(old); + spin_unlock_bh(&old->q.lock); + } +} - Old qdisc is not destroyed but returned in *old. +/* Graft qdisc "new" to class "classid" of qdisc "parent" or + * to device "dev". + * + * When appropriate send a netlink notification using 'skb' + * and "n". + * + * On success, destroy old qdisc. */ static int qdisc_graft(struct net_device *dev, struct Qdisc *parent, - u32 classid, - struct Qdisc *new, struct Qdisc **old) + struct sk_buff *skb, struct nlmsghdr *n, u32 classid, + struct Qdisc *new, struct Qdisc *old) { + struct Qdisc *q = old; int err = 0; - struct Qdisc *q = *old; - if (parent == NULL) { - if (q && q->flags&TCQ_F_INGRESS) { - *old = dev_graft_qdisc(dev, q); - } else { - *old = dev_graft_qdisc(dev, new); + unsigned int i, num_q, ingress; + + ingress = 0; + num_q = dev->num_tx_queues; + if (q && q->flags & TCQ_F_INGRESS) { + num_q = 1; + ingress = 1; + } + + if (dev->flags & IFF_UP) + dev_deactivate(dev); + + for (i = 0; i < num_q; i++) { + struct netdev_queue *dev_queue = &dev->rx_queue; + + if (!ingress) + dev_queue = netdev_get_tx_queue(dev, i); + + if (ingress) { + old = dev_graft_qdisc(dev_queue, q); + } else { + old = dev_graft_qdisc(dev_queue, new); + if (new && i > 0) + atomic_inc(&new->refcnt); + } + notify_and_destroy(skb, n, classid, old, new); } + + if (dev->flags & IFF_UP) + dev_activate(dev); } else { const struct Qdisc_class_ops *cops = parent->ops->cl_ops; @@ -433,10 +712,12 @@ static int qdisc_graft(struct net_device *dev, struct Qdisc *parent, if (cops) { unsigned long cl = cops->get(parent, classid); if (cl) { - err = cops->graft(parent, cl, new, old); + err = cops->graft(parent, cl, new, &old); cops->put(parent, cl); } } + if (!err) + notify_and_destroy(skb, n, classid, old, new); } return err; } @@ -448,13 +729,14 @@ static int qdisc_graft(struct net_device *dev, struct Qdisc *parent, */ static struct Qdisc * -qdisc_create(struct net_device *dev, u32 parent, u32 handle, - struct nlattr **tca, int *errp) +qdisc_create(struct net_device *dev, struct netdev_queue *dev_queue, + u32 parent, u32 handle, struct nlattr **tca, int *errp) { int err; struct nlattr *kind = tca[TCA_KIND]; struct Qdisc *sch; struct Qdisc_ops *ops; + struct qdisc_size_table *stab; ops = qdisc_lookup_ops(kind); #ifdef CONFIG_KMOD @@ -489,7 +771,7 @@ qdisc_create(struct net_device *dev, u32 parent, u32 handle, if (ops == NULL) goto err_out; - sch = qdisc_alloc(dev, ops); + sch = qdisc_alloc(dev_queue, ops); if (IS_ERR(sch)) { err = PTR_ERR(sch); goto err_out2; @@ -499,10 +781,8 @@ qdisc_create(struct net_device *dev, u32 parent, u32 handle, if (handle == TC_H_INGRESS) { sch->flags |= TCQ_F_INGRESS; - sch->stats_lock = &dev->ingress_lock; handle = TC_H_MAKE(TC_H_INGRESS, 0); } else { - sch->stats_lock = &dev->queue_lock; if (handle == 0) { handle = qdisc_alloc_handle(dev); err = -ENOMEM; @@ -514,9 +794,17 @@ qdisc_create(struct net_device *dev, u32 parent, u32 handle, sch->handle = handle; if (!ops->init || (err = ops->init(sch, tca[TCA_OPTIONS])) == 0) { + if (tca[TCA_STAB]) { + stab = qdisc_get_stab(tca[TCA_STAB]); + if (IS_ERR(stab)) { + err = PTR_ERR(stab); + goto err_out3; + } + sch->stab = stab; + } if (tca[TCA_RATE]) { err = gen_new_estimator(&sch->bstats, &sch->rate_est, - sch->stats_lock, + qdisc_root_lock(sch), tca[TCA_RATE]); if (err) { /* @@ -529,13 +817,13 @@ qdisc_create(struct net_device *dev, u32 parent, u32 handle, goto err_out3; } } - qdisc_lock_tree(dev); - list_add_tail(&sch->list, &dev->qdisc_list); - qdisc_unlock_tree(dev); + if (parent) + list_add_tail(&sch->list, &dev_queue->qdisc->list); return sch; } err_out3: + qdisc_put_stab(sch->stab); dev_put(dev); kfree((char *) sch - sch->padded); err_out2: @@ -547,18 +835,29 @@ err_out: static int qdisc_change(struct Qdisc *sch, struct nlattr **tca) { - if (tca[TCA_OPTIONS]) { - int err; + struct qdisc_size_table *stab = NULL; + int err = 0; + if (tca[TCA_OPTIONS]) { if (sch->ops->change == NULL) return -EINVAL; err = sch->ops->change(sch, tca[TCA_OPTIONS]); if (err) return err; } + + if (tca[TCA_STAB]) { + stab = qdisc_get_stab(tca[TCA_STAB]); + if (IS_ERR(stab)) + return PTR_ERR(stab); + } + + qdisc_put_stab(sch->stab); + sch->stab = stab; + if (tca[TCA_RATE]) gen_replace_estimator(&sch->bstats, &sch->rate_est, - sch->stats_lock, tca[TCA_RATE]); + qdisc_root_lock(sch), tca[TCA_RATE]); return 0; } @@ -634,10 +933,12 @@ static int tc_get_qdisc(struct sk_buff *skb, struct nlmsghdr *n, void *arg) return -ENOENT; q = qdisc_leaf(p, clid); } else { /* ingress */ - q = dev->qdisc_ingress; + q = dev->rx_queue.qdisc; } } else { - q = dev->qdisc_sleeping; + struct netdev_queue *dev_queue; + dev_queue = netdev_get_tx_queue(dev, 0); + q = dev_queue->qdisc_sleeping; } if (!q) return -ENOENT; @@ -657,14 +958,8 @@ static int tc_get_qdisc(struct sk_buff *skb, struct nlmsghdr *n, void *arg) return -EINVAL; if (q->handle == 0) return -ENOENT; - if ((err = qdisc_graft(dev, p, clid, NULL, &q)) != 0) + if ((err = qdisc_graft(dev, p, skb, n, clid, NULL, q)) != 0) return err; - if (q) { - qdisc_notify(skb, n, clid, q, NULL); - qdisc_lock_tree(dev); - qdisc_destroy(q); - qdisc_unlock_tree(dev); - } } else { qdisc_notify(skb, n, clid, NULL, q); } @@ -708,10 +1003,12 @@ replay: return -ENOENT; q = qdisc_leaf(p, clid); } else { /*ingress */ - q = dev->qdisc_ingress; + q = dev->rx_queue.qdisc; } } else { - q = dev->qdisc_sleeping; + struct netdev_queue *dev_queue; + dev_queue = netdev_get_tx_queue(dev, 0); + q = dev_queue->qdisc_sleeping; } /* It may be default qdisc, ignore it */ @@ -788,10 +1085,12 @@ create_n_graft: if (!(n->nlmsg_flags&NLM_F_CREATE)) return -ENOENT; if (clid == TC_H_INGRESS) - q = qdisc_create(dev, tcm->tcm_parent, tcm->tcm_parent, + q = qdisc_create(dev, &dev->rx_queue, + tcm->tcm_parent, tcm->tcm_parent, tca, &err); else - q = qdisc_create(dev, tcm->tcm_parent, tcm->tcm_handle, + q = qdisc_create(dev, netdev_get_tx_queue(dev, 0), + tcm->tcm_parent, tcm->tcm_handle, tca, &err); if (q == NULL) { if (err == -EAGAIN) @@ -801,22 +1100,18 @@ create_n_graft: graft: if (1) { - struct Qdisc *old_q = NULL; - err = qdisc_graft(dev, p, clid, q, &old_q); + spinlock_t *root_lock; + + err = qdisc_graft(dev, p, skb, n, clid, q, NULL); if (err) { if (q) { - qdisc_lock_tree(dev); + root_lock = qdisc_root_lock(q); + spin_lock_bh(root_lock); qdisc_destroy(q); - qdisc_unlock_tree(dev); + spin_unlock_bh(root_lock); } return err; } - qdisc_notify(skb, n, clid, old_q, q); - if (old_q) { - qdisc_lock_tree(dev); - qdisc_destroy(old_q); - qdisc_unlock_tree(dev); - } } return 0; } @@ -834,7 +1129,7 @@ static int tc_fill_qdisc(struct sk_buff *skb, struct Qdisc *q, u32 clid, tcm->tcm_family = AF_UNSPEC; tcm->tcm__pad1 = 0; tcm->tcm__pad2 = 0; - tcm->tcm_ifindex = q->dev->ifindex; + tcm->tcm_ifindex = qdisc_dev(q)->ifindex; tcm->tcm_parent = clid; tcm->tcm_handle = q->handle; tcm->tcm_info = atomic_read(&q->refcnt); @@ -843,8 +1138,11 @@ static int tc_fill_qdisc(struct sk_buff *skb, struct Qdisc *q, u32 clid, goto nla_put_failure; q->qstats.qlen = q->q.qlen; + if (q->stab && qdisc_dump_stab(skb, q->stab) < 0) + goto nla_put_failure; + if (gnet_stats_start_copy_compat(skb, TCA_STATS2, TCA_STATS, - TCA_XSTATS, q->stats_lock, &d) < 0) + TCA_XSTATS, qdisc_root_lock(q), &d) < 0) goto nla_put_failure; if (q->ops->dump_stats && q->ops->dump_stats(q, &d) < 0) @@ -894,13 +1192,57 @@ err_out: return -EINVAL; } +static bool tc_qdisc_dump_ignore(struct Qdisc *q) +{ + return (q->flags & TCQ_F_BUILTIN) ? true : false; +} + +static int tc_dump_qdisc_root(struct Qdisc *root, struct sk_buff *skb, + struct netlink_callback *cb, + int *q_idx_p, int s_q_idx) +{ + int ret = 0, q_idx = *q_idx_p; + struct Qdisc *q; + + if (!root) + return 0; + + q = root; + if (q_idx < s_q_idx) { + q_idx++; + } else { + if (!tc_qdisc_dump_ignore(q) && + tc_fill_qdisc(skb, q, q->parent, NETLINK_CB(cb->skb).pid, + cb->nlh->nlmsg_seq, NLM_F_MULTI, RTM_NEWQDISC) <= 0) + goto done; + q_idx++; + } + list_for_each_entry(q, &root->list, list) { + if (q_idx < s_q_idx) { + q_idx++; + continue; + } + if (!tc_qdisc_dump_ignore(q) && + tc_fill_qdisc(skb, q, q->parent, NETLINK_CB(cb->skb).pid, + cb->nlh->nlmsg_seq, NLM_F_MULTI, RTM_NEWQDISC) <= 0) + goto done; + q_idx++; + } + +out: + *q_idx_p = q_idx; + return ret; +done: + ret = -1; + goto out; +} + static int tc_dump_qdisc(struct sk_buff *skb, struct netlink_callback *cb) { struct net *net = sock_net(skb->sk); int idx, q_idx; int s_idx, s_q_idx; struct net_device *dev; - struct Qdisc *q; if (net != &init_net) return 0; @@ -910,21 +1252,22 @@ static int tc_dump_qdisc(struct sk_buff *skb, struct netlink_callback *cb) read_lock(&dev_base_lock); idx = 0; for_each_netdev(&init_net, dev) { + struct netdev_queue *dev_queue; + if (idx < s_idx) goto cont; if (idx > s_idx) s_q_idx = 0; q_idx = 0; - list_for_each_entry(q, &dev->qdisc_list, list) { - if (q_idx < s_q_idx) { - q_idx++; - continue; - } - if (tc_fill_qdisc(skb, q, q->parent, NETLINK_CB(cb->skb).pid, - cb->nlh->nlmsg_seq, NLM_F_MULTI, RTM_NEWQDISC) <= 0) - goto done; - q_idx++; - } + + dev_queue = netdev_get_tx_queue(dev, 0); + if (tc_dump_qdisc_root(dev_queue->qdisc, skb, cb, &q_idx, s_q_idx) < 0) + goto done; + + dev_queue = &dev->rx_queue; + if (tc_dump_qdisc_root(dev_queue->qdisc, skb, cb, &q_idx, s_q_idx) < 0) + goto done; + cont: idx++; } @@ -949,6 +1292,7 @@ done: static int tc_ctl_tclass(struct sk_buff *skb, struct nlmsghdr *n, void *arg) { struct net *net = sock_net(skb->sk); + struct netdev_queue *dev_queue; struct tcmsg *tcm = NLMSG_DATA(n); struct nlattr *tca[TCA_MAX + 1]; struct net_device *dev; @@ -986,6 +1330,7 @@ static int tc_ctl_tclass(struct sk_buff *skb, struct nlmsghdr *n, void *arg) /* Step 1. Determine qdisc handle X:0 */ + dev_queue = netdev_get_tx_queue(dev, 0); if (pid != TC_H_ROOT) { u32 qid1 = TC_H_MAJ(pid); @@ -996,7 +1341,7 @@ static int tc_ctl_tclass(struct sk_buff *skb, struct nlmsghdr *n, void *arg) } else if (qid1) { qid = qid1; } else if (qid == 0) - qid = dev->qdisc_sleeping->handle; + qid = dev_queue->qdisc_sleeping->handle; /* Now qid is genuine qdisc handle consistent both with parent and child. @@ -1007,7 +1352,7 @@ static int tc_ctl_tclass(struct sk_buff *skb, struct nlmsghdr *n, void *arg) pid = TC_H_MAKE(qid, pid); } else { if (qid == 0) - qid = dev->qdisc_sleeping->handle; + qid = dev_queue->qdisc_sleeping->handle; } /* OK. Locate qdisc */ @@ -1080,7 +1425,7 @@ static int tc_fill_tclass(struct sk_buff *skb, struct Qdisc *q, nlh = NLMSG_NEW(skb, pid, seq, event, sizeof(*tcm), flags); tcm = NLMSG_DATA(nlh); tcm->tcm_family = AF_UNSPEC; - tcm->tcm_ifindex = q->dev->ifindex; + tcm->tcm_ifindex = qdisc_dev(q)->ifindex; tcm->tcm_parent = q->handle; tcm->tcm_handle = q->handle; tcm->tcm_info = 0; @@ -1089,7 +1434,7 @@ static int tc_fill_tclass(struct sk_buff *skb, struct Qdisc *q, goto nla_put_failure; if (gnet_stats_start_copy_compat(skb, TCA_STATS2, TCA_STATS, - TCA_XSTATS, q->stats_lock, &d) < 0) + TCA_XSTATS, qdisc_root_lock(q), &d) < 0) goto nla_put_failure; if (cl_ops->dump_stats && cl_ops->dump_stats(q, cl, &d) < 0) @@ -1140,15 +1485,62 @@ static int qdisc_class_dump(struct Qdisc *q, unsigned long cl, struct qdisc_walk a->cb->nlh->nlmsg_seq, NLM_F_MULTI, RTM_NEWTCLASS); } +static int tc_dump_tclass_qdisc(struct Qdisc *q, struct sk_buff *skb, + struct tcmsg *tcm, struct netlink_callback *cb, + int *t_p, int s_t) +{ + struct qdisc_dump_args arg; + + if (tc_qdisc_dump_ignore(q) || + *t_p < s_t || !q->ops->cl_ops || + (tcm->tcm_parent && + TC_H_MAJ(tcm->tcm_parent) != q->handle)) { + (*t_p)++; + return 0; + } + if (*t_p > s_t) + memset(&cb->args[1], 0, sizeof(cb->args)-sizeof(cb->args[0])); + arg.w.fn = qdisc_class_dump; + arg.skb = skb; + arg.cb = cb; + arg.w.stop = 0; + arg.w.skip = cb->args[1]; + arg.w.count = 0; + q->ops->cl_ops->walk(q, &arg.w); + cb->args[1] = arg.w.count; + if (arg.w.stop) + return -1; + (*t_p)++; + return 0; +} + +static int tc_dump_tclass_root(struct Qdisc *root, struct sk_buff *skb, + struct tcmsg *tcm, struct netlink_callback *cb, + int *t_p, int s_t) +{ + struct Qdisc *q; + + if (!root) + return 0; + + if (tc_dump_tclass_qdisc(root, skb, tcm, cb, t_p, s_t) < 0) + return -1; + + list_for_each_entry(q, &root->list, list) { + if (tc_dump_tclass_qdisc(q, skb, tcm, cb, t_p, s_t) < 0) + return -1; + } + + return 0; +} + static int tc_dump_tclass(struct sk_buff *skb, struct netlink_callback *cb) { + struct tcmsg *tcm = (struct tcmsg*)NLMSG_DATA(cb->nlh); struct net *net = sock_net(skb->sk); - int t; - int s_t; + struct netdev_queue *dev_queue; struct net_device *dev; - struct Qdisc *q; - struct tcmsg *tcm = (struct tcmsg*)NLMSG_DATA(cb->nlh); - struct qdisc_dump_args arg; + int t, s_t; if (net != &init_net) return 0; @@ -1161,28 +1553,15 @@ static int tc_dump_tclass(struct sk_buff *skb, struct netlink_callback *cb) s_t = cb->args[0]; t = 0; - list_for_each_entry(q, &dev->qdisc_list, list) { - if (t < s_t || !q->ops->cl_ops || - (tcm->tcm_parent && - TC_H_MAJ(tcm->tcm_parent) != q->handle)) { - t++; - continue; - } - if (t > s_t) - memset(&cb->args[1], 0, sizeof(cb->args)-sizeof(cb->args[0])); - arg.w.fn = qdisc_class_dump; - arg.skb = skb; - arg.cb = cb; - arg.w.stop = 0; - arg.w.skip = cb->args[1]; - arg.w.count = 0; - q->ops->cl_ops->walk(q, &arg.w); - cb->args[1] = arg.w.count; - if (arg.w.stop) - break; - t++; - } + dev_queue = netdev_get_tx_queue(dev, 0); + if (tc_dump_tclass_root(dev_queue->qdisc, skb, tcm, cb, &t, s_t) < 0) + goto done; + dev_queue = &dev->rx_queue; + if (tc_dump_tclass_root(dev_queue->qdisc, skb, tcm, cb, &t, s_t) < 0) + goto done; + +done: cb->args[0] = t; dev_put(dev); diff --git a/net/sched/sch_atm.c b/net/sched/sch_atm.c index db0e23ae85f8..04faa835be17 100644 --- a/net/sched/sch_atm.c +++ b/net/sched/sch_atm.c @@ -296,7 +296,8 @@ static int atm_tc_change(struct Qdisc *sch, u32 classid, u32 parent, goto err_out; } flow->filter_list = NULL; - flow->q = qdisc_create_dflt(sch->dev, &pfifo_qdisc_ops, classid); + flow->q = qdisc_create_dflt(qdisc_dev(sch), sch->dev_queue, + &pfifo_qdisc_ops, classid); if (!flow->q) flow->q = &noop_qdisc; pr_debug("atm_tc_change: qdisc %p\n", flow->q); @@ -428,7 +429,7 @@ static int atm_tc_enqueue(struct sk_buff *skb, struct Qdisc *sch) #endif } - ret = flow->q->enqueue(skb, flow->q); + ret = qdisc_enqueue(skb, flow->q); if (ret != 0) { drop: __maybe_unused sch->qstats.drops++; @@ -436,9 +437,9 @@ drop: __maybe_unused flow->qstats.drops++; return ret; } - sch->bstats.bytes += skb->len; + sch->bstats.bytes += qdisc_pkt_len(skb); sch->bstats.packets++; - flow->bstats.bytes += skb->len; + flow->bstats.bytes += qdisc_pkt_len(skb); flow->bstats.packets++; /* * Okay, this may seem weird. We pretend we've dropped the packet if @@ -555,7 +556,8 @@ static int atm_tc_init(struct Qdisc *sch, struct nlattr *opt) pr_debug("atm_tc_init(sch %p,[qdisc %p],opt %p)\n", sch, p, opt); p->flows = &p->link; - p->link.q = qdisc_create_dflt(sch->dev, &pfifo_qdisc_ops, sch->handle); + p->link.q = qdisc_create_dflt(qdisc_dev(sch), sch->dev_queue, + &pfifo_qdisc_ops, sch->handle); if (!p->link.q) p->link.q = &noop_qdisc; pr_debug("atm_tc_init: link (%p) qdisc %p\n", &p->link, p->link.q); diff --git a/net/sched/sch_cbq.c b/net/sched/sch_cbq.c index 2a3c97f7dc63..f1d2f8ec8b4c 100644 --- a/net/sched/sch_cbq.c +++ b/net/sched/sch_cbq.c @@ -73,11 +73,10 @@ struct cbq_sched_data; struct cbq_class { - struct cbq_class *next; /* hash table link */ + struct Qdisc_class_common common; struct cbq_class *next_alive; /* next class with backlog in this priority band */ /* Parameters */ - u32 classid; unsigned char priority; /* class priority */ unsigned char priority2; /* priority to be used after overlimit */ unsigned char ewma_log; /* time constant for idle time calculation */ @@ -144,7 +143,7 @@ struct cbq_class struct cbq_sched_data { - struct cbq_class *classes[16]; /* Hash table of all classes */ + struct Qdisc_class_hash clhash; /* Hash table of all classes */ int nclasses[TC_CBQ_MAXPRIO+1]; unsigned quanta[TC_CBQ_MAXPRIO+1]; @@ -177,23 +176,15 @@ struct cbq_sched_data #define L2T(cl,len) qdisc_l2t((cl)->R_tab,len) - -static __inline__ unsigned cbq_hash(u32 h) -{ - h ^= h>>8; - h ^= h>>4; - return h&0xF; -} - static __inline__ struct cbq_class * cbq_class_lookup(struct cbq_sched_data *q, u32 classid) { - struct cbq_class *cl; + struct Qdisc_class_common *clc; - for (cl = q->classes[cbq_hash(classid)]; cl; cl = cl->next) - if (cl->classid == classid) - return cl; - return NULL; + clc = qdisc_class_find(&q->clhash, classid); + if (clc == NULL) + return NULL; + return container_of(clc, struct cbq_class, common); } #ifdef CONFIG_NET_CLS_ACT @@ -379,7 +370,6 @@ static int cbq_enqueue(struct sk_buff *skb, struct Qdisc *sch) { struct cbq_sched_data *q = qdisc_priv(sch); - int len = skb->len; int uninitialized_var(ret); struct cbq_class *cl = cbq_classify(skb, sch, &ret); @@ -396,10 +386,11 @@ cbq_enqueue(struct sk_buff *skb, struct Qdisc *sch) #ifdef CONFIG_NET_CLS_ACT cl->q->__parent = sch; #endif - if ((ret = cl->q->enqueue(skb, cl->q)) == NET_XMIT_SUCCESS) { + ret = qdisc_enqueue(skb, cl->q); + if (ret == NET_XMIT_SUCCESS) { sch->q.qlen++; sch->bstats.packets++; - sch->bstats.bytes+=len; + sch->bstats.bytes += qdisc_pkt_len(skb); cbq_mark_toplevel(q, cl); if (!cl->next_alive) cbq_activate_class(cl); @@ -659,14 +650,13 @@ static enum hrtimer_restart cbq_undelay(struct hrtimer *timer) } sch->flags &= ~TCQ_F_THROTTLED; - netif_schedule(sch->dev); + __netif_schedule(sch); return HRTIMER_NORESTART; } #ifdef CONFIG_NET_CLS_ACT static int cbq_reshape_fail(struct sk_buff *skb, struct Qdisc *child) { - int len = skb->len; struct Qdisc *sch = child->__parent; struct cbq_sched_data *q = qdisc_priv(sch); struct cbq_class *cl = q->rx_class; @@ -680,10 +670,10 @@ static int cbq_reshape_fail(struct sk_buff *skb, struct Qdisc *child) q->rx_class = cl; cl->q->__parent = sch; - if (cl->q->enqueue(skb, cl->q) == 0) { + if (qdisc_enqueue(skb, cl->q) == 0) { sch->q.qlen++; sch->bstats.packets++; - sch->bstats.bytes+=len; + sch->bstats.bytes += qdisc_pkt_len(skb); if (!cl->next_alive) cbq_activate_class(cl); return 0; @@ -889,7 +879,7 @@ cbq_dequeue_prio(struct Qdisc *sch, int prio) if (skb == NULL) goto skip_class; - cl->deficit -= skb->len; + cl->deficit -= qdisc_pkt_len(skb); q->tx_class = cl; q->tx_borrowed = borrow; if (borrow != cl) { @@ -897,11 +887,11 @@ cbq_dequeue_prio(struct Qdisc *sch, int prio) borrow->xstats.borrows++; cl->xstats.borrows++; #else - borrow->xstats.borrows += skb->len; - cl->xstats.borrows += skb->len; + borrow->xstats.borrows += qdisc_pkt_len(skb); + cl->xstats.borrows += qdisc_pkt_len(skb); #endif } - q->tx_len = skb->len; + q->tx_len = qdisc_pkt_len(skb); if (cl->deficit <= 0) { q->active[prio] = cl; @@ -1071,13 +1061,14 @@ static void cbq_adjust_levels(struct cbq_class *this) static void cbq_normalize_quanta(struct cbq_sched_data *q, int prio) { struct cbq_class *cl; - unsigned h; + struct hlist_node *n; + unsigned int h; if (q->quanta[prio] == 0) return; - for (h=0; h<16; h++) { - for (cl = q->classes[h]; cl; cl = cl->next) { + for (h = 0; h < q->clhash.hashsize; h++) { + hlist_for_each_entry(cl, n, &q->clhash.hash[h], common.hnode) { /* BUGGGG... Beware! This expression suffer of arithmetic overflows! */ @@ -1085,9 +1076,9 @@ static void cbq_normalize_quanta(struct cbq_sched_data *q, int prio) cl->quantum = (cl->weight*cl->allot*q->nclasses[prio])/ q->quanta[prio]; } - if (cl->quantum <= 0 || cl->quantum>32*cl->qdisc->dev->mtu) { - printk(KERN_WARNING "CBQ: class %08x has bad quantum==%ld, repaired.\n", cl->classid, cl->quantum); - cl->quantum = cl->qdisc->dev->mtu/2 + 1; + if (cl->quantum <= 0 || cl->quantum>32*qdisc_dev(cl->qdisc)->mtu) { + printk(KERN_WARNING "CBQ: class %08x has bad quantum==%ld, repaired.\n", cl->common.classid, cl->quantum); + cl->quantum = qdisc_dev(cl->qdisc)->mtu/2 + 1; } } } @@ -1114,10 +1105,12 @@ static void cbq_sync_defmap(struct cbq_class *cl) if (split->defaults[i]) continue; - for (h=0; h<16; h++) { + for (h = 0; h < q->clhash.hashsize; h++) { + struct hlist_node *n; struct cbq_class *c; - for (c = q->classes[h]; c; c = c->next) { + hlist_for_each_entry(c, n, &q->clhash.hash[h], + common.hnode) { if (c->split == split && c->level < level && c->defmap&(1<<i)) { split->defaults[i] = c; @@ -1135,12 +1128,12 @@ static void cbq_change_defmap(struct cbq_class *cl, u32 splitid, u32 def, u32 ma if (splitid == 0) { if ((split = cl->split) == NULL) return; - splitid = split->classid; + splitid = split->common.classid; } - if (split == NULL || split->classid != splitid) { + if (split == NULL || split->common.classid != splitid) { for (split = cl->tparent; split; split = split->tparent) - if (split->classid == splitid) + if (split->common.classid == splitid) break; } @@ -1163,13 +1156,7 @@ static void cbq_unlink_class(struct cbq_class *this) struct cbq_class *cl, **clp; struct cbq_sched_data *q = qdisc_priv(this->qdisc); - for (clp = &q->classes[cbq_hash(this->classid)]; (cl = *clp) != NULL; clp = &cl->next) { - if (cl == this) { - *clp = cl->next; - cl->next = NULL; - break; - } - } + qdisc_class_hash_remove(&q->clhash, &this->common); if (this->tparent) { clp=&this->sibling; @@ -1195,12 +1182,10 @@ static void cbq_unlink_class(struct cbq_class *this) static void cbq_link_class(struct cbq_class *this) { struct cbq_sched_data *q = qdisc_priv(this->qdisc); - unsigned h = cbq_hash(this->classid); struct cbq_class *parent = this->tparent; this->sibling = this; - this->next = q->classes[h]; - q->classes[h] = this; + qdisc_class_hash_insert(&q->clhash, &this->common); if (parent == NULL) return; @@ -1242,6 +1227,7 @@ cbq_reset(struct Qdisc* sch) { struct cbq_sched_data *q = qdisc_priv(sch); struct cbq_class *cl; + struct hlist_node *n; int prio; unsigned h; @@ -1258,8 +1244,8 @@ cbq_reset(struct Qdisc* sch) for (prio = 0; prio <= TC_CBQ_MAXPRIO; prio++) q->active[prio] = NULL; - for (h = 0; h < 16; h++) { - for (cl = q->classes[h]; cl; cl = cl->next) { + for (h = 0; h < q->clhash.hashsize; h++) { + hlist_for_each_entry(cl, n, &q->clhash.hash[h], common.hnode) { qdisc_reset(cl->q); cl->next_alive = NULL; @@ -1406,11 +1392,16 @@ static int cbq_init(struct Qdisc *sch, struct nlattr *opt) if ((q->link.R_tab = qdisc_get_rtab(r, tb[TCA_CBQ_RTAB])) == NULL) return -EINVAL; + err = qdisc_class_hash_init(&q->clhash); + if (err < 0) + goto put_rtab; + q->link.refcnt = 1; q->link.sibling = &q->link; - q->link.classid = sch->handle; + q->link.common.classid = sch->handle; q->link.qdisc = sch; - if (!(q->link.q = qdisc_create_dflt(sch->dev, &pfifo_qdisc_ops, + if (!(q->link.q = qdisc_create_dflt(qdisc_dev(sch), sch->dev_queue, + &pfifo_qdisc_ops, sch->handle))) q->link.q = &noop_qdisc; @@ -1419,7 +1410,7 @@ static int cbq_init(struct Qdisc *sch, struct nlattr *opt) q->link.cpriority = TC_CBQ_MAXPRIO-1; q->link.ovl_strategy = TC_CBQ_OVL_CLASSIC; q->link.overlimit = cbq_ovl_classic; - q->link.allot = psched_mtu(sch->dev); + q->link.allot = psched_mtu(qdisc_dev(sch)); q->link.quantum = q->link.allot; q->link.weight = q->link.R_tab->rate.rate; @@ -1441,6 +1432,10 @@ static int cbq_init(struct Qdisc *sch, struct nlattr *opt) cbq_addprio(q, &q->link); return 0; + +put_rtab: + qdisc_put_rtab(q->link.R_tab); + return err; } static __inline__ int cbq_dump_rate(struct sk_buff *skb, struct cbq_class *cl) @@ -1521,7 +1516,7 @@ static __inline__ int cbq_dump_fopt(struct sk_buff *skb, struct cbq_class *cl) struct tc_cbq_fopt opt; if (cl->split || cl->defmap) { - opt.split = cl->split ? cl->split->classid : 0; + opt.split = cl->split ? cl->split->common.classid : 0; opt.defmap = cl->defmap; opt.defchange = ~0; NLA_PUT(skb, TCA_CBQ_FOPT, sizeof(opt), &opt); @@ -1602,10 +1597,10 @@ cbq_dump_class(struct Qdisc *sch, unsigned long arg, struct nlattr *nest; if (cl->tparent) - tcm->tcm_parent = cl->tparent->classid; + tcm->tcm_parent = cl->tparent->common.classid; else tcm->tcm_parent = TC_H_ROOT; - tcm->tcm_handle = cl->classid; + tcm->tcm_handle = cl->common.classid; tcm->tcm_info = cl->q->handle; nest = nla_nest_start(skb, TCA_OPTIONS); @@ -1650,8 +1645,10 @@ static int cbq_graft(struct Qdisc *sch, unsigned long arg, struct Qdisc *new, if (cl) { if (new == NULL) { - if ((new = qdisc_create_dflt(sch->dev, &pfifo_qdisc_ops, - cl->classid)) == NULL) + new = qdisc_create_dflt(qdisc_dev(sch), sch->dev_queue, + &pfifo_qdisc_ops, + cl->common.classid); + if (new == NULL) return -ENOBUFS; } else { #ifdef CONFIG_NET_CLS_ACT @@ -1716,6 +1713,7 @@ static void cbq_destroy(struct Qdisc* sch) { struct cbq_sched_data *q = qdisc_priv(sch); + struct hlist_node *n, *next; struct cbq_class *cl; unsigned h; @@ -1727,18 +1725,16 @@ cbq_destroy(struct Qdisc* sch) * classes from root to leafs which means that filters can still * be bound to classes which have been destroyed already. --TGR '04 */ - for (h = 0; h < 16; h++) { - for (cl = q->classes[h]; cl; cl = cl->next) + for (h = 0; h < q->clhash.hashsize; h++) { + hlist_for_each_entry(cl, n, &q->clhash.hash[h], common.hnode) tcf_destroy_chain(&cl->filter_list); } - for (h = 0; h < 16; h++) { - struct cbq_class *next; - - for (cl = q->classes[h]; cl; cl = next) { - next = cl->next; + for (h = 0; h < q->clhash.hashsize; h++) { + hlist_for_each_entry_safe(cl, n, next, &q->clhash.hash[h], + common.hnode) cbq_destroy_class(sch, cl); - } } + qdisc_class_hash_destroy(&q->clhash); } static void cbq_put(struct Qdisc *sch, unsigned long arg) @@ -1747,12 +1743,13 @@ static void cbq_put(struct Qdisc *sch, unsigned long arg) if (--cl->refcnt == 0) { #ifdef CONFIG_NET_CLS_ACT + spinlock_t *root_lock = qdisc_root_lock(sch); struct cbq_sched_data *q = qdisc_priv(sch); - spin_lock_bh(&sch->dev->queue_lock); + spin_lock_bh(root_lock); if (q->rx_class == cl) q->rx_class = NULL; - spin_unlock_bh(&sch->dev->queue_lock); + spin_unlock_bh(root_lock); #endif cbq_destroy_class(sch, cl); @@ -1781,7 +1778,8 @@ cbq_change_class(struct Qdisc *sch, u32 classid, u32 parentid, struct nlattr **t if (cl) { /* Check parent */ if (parentid) { - if (cl->tparent && cl->tparent->classid != parentid) + if (cl->tparent && + cl->tparent->common.classid != parentid) return -EINVAL; if (!cl->tparent && parentid != TC_H_ROOT) return -EINVAL; @@ -1830,7 +1828,7 @@ cbq_change_class(struct Qdisc *sch, u32 classid, u32 parentid, struct nlattr **t if (tca[TCA_RATE]) gen_replace_estimator(&cl->bstats, &cl->rate_est, - &sch->dev->queue_lock, + qdisc_root_lock(sch), tca[TCA_RATE]); return 0; } @@ -1881,9 +1879,10 @@ cbq_change_class(struct Qdisc *sch, u32 classid, u32 parentid, struct nlattr **t cl->R_tab = rtab; rtab = NULL; cl->refcnt = 1; - if (!(cl->q = qdisc_create_dflt(sch->dev, &pfifo_qdisc_ops, classid))) + if (!(cl->q = qdisc_create_dflt(qdisc_dev(sch), sch->dev_queue, + &pfifo_qdisc_ops, classid))) cl->q = &noop_qdisc; - cl->classid = classid; + cl->common.classid = classid; cl->tparent = parent; cl->qdisc = sch; cl->allot = parent->allot; @@ -1916,9 +1915,11 @@ cbq_change_class(struct Qdisc *sch, u32 classid, u32 parentid, struct nlattr **t cbq_set_fopt(cl, nla_data(tb[TCA_CBQ_FOPT])); sch_tree_unlock(sch); + qdisc_class_hash_grow(sch, &q->clhash); + if (tca[TCA_RATE]) gen_new_estimator(&cl->bstats, &cl->rate_est, - &sch->dev->queue_lock, tca[TCA_RATE]); + qdisc_root_lock(sch), tca[TCA_RATE]); *arg = (unsigned long)cl; return 0; @@ -2008,15 +2009,15 @@ static void cbq_unbind_filter(struct Qdisc *sch, unsigned long arg) static void cbq_walk(struct Qdisc *sch, struct qdisc_walker *arg) { struct cbq_sched_data *q = qdisc_priv(sch); + struct cbq_class *cl; + struct hlist_node *n; unsigned h; if (arg->stop) return; - for (h = 0; h < 16; h++) { - struct cbq_class *cl; - - for (cl = q->classes[h]; cl; cl = cl->next) { + for (h = 0; h < q->clhash.hashsize; h++) { + hlist_for_each_entry(cl, n, &q->clhash.hash[h], common.hnode) { if (arg->count < arg->skip) { arg->count++; continue; diff --git a/net/sched/sch_dsmark.c b/net/sched/sch_dsmark.c index c4c1317cd47d..a935676987e2 100644 --- a/net/sched/sch_dsmark.c +++ b/net/sched/sch_dsmark.c @@ -60,7 +60,8 @@ static int dsmark_graft(struct Qdisc *sch, unsigned long arg, sch, p, new, old); if (new == NULL) { - new = qdisc_create_dflt(sch->dev, &pfifo_qdisc_ops, + new = qdisc_create_dflt(qdisc_dev(sch), sch->dev_queue, + &pfifo_qdisc_ops, sch->handle); if (new == NULL) new = &noop_qdisc; @@ -251,13 +252,13 @@ static int dsmark_enqueue(struct sk_buff *skb, struct Qdisc *sch) } } - err = p->q->enqueue(skb, p->q); + err = qdisc_enqueue(skb, p->q); if (err != NET_XMIT_SUCCESS) { sch->qstats.drops++; return err; } - sch->bstats.bytes += skb->len; + sch->bstats.bytes += qdisc_pkt_len(skb); sch->bstats.packets++; sch->q.qlen++; @@ -390,7 +391,8 @@ static int dsmark_init(struct Qdisc *sch, struct nlattr *opt) p->default_index = default_index; p->set_tc_index = nla_get_flag(tb[TCA_DSMARK_SET_TC_INDEX]); - p->q = qdisc_create_dflt(sch->dev, &pfifo_qdisc_ops, sch->handle); + p->q = qdisc_create_dflt(qdisc_dev(sch), sch->dev_queue, + &pfifo_qdisc_ops, sch->handle); if (p->q == NULL) p->q = &noop_qdisc; diff --git a/net/sched/sch_fifo.c b/net/sched/sch_fifo.c index 95ed48221652..23d258bfe8ac 100644 --- a/net/sched/sch_fifo.c +++ b/net/sched/sch_fifo.c @@ -27,7 +27,7 @@ static int bfifo_enqueue(struct sk_buff *skb, struct Qdisc* sch) { struct fifo_sched_data *q = qdisc_priv(sch); - if (likely(sch->qstats.backlog + skb->len <= q->limit)) + if (likely(sch->qstats.backlog + qdisc_pkt_len(skb) <= q->limit)) return qdisc_enqueue_tail(skb, sch); return qdisc_reshape_fail(skb, sch); @@ -48,10 +48,10 @@ static int fifo_init(struct Qdisc *sch, struct nlattr *opt) struct fifo_sched_data *q = qdisc_priv(sch); if (opt == NULL) { - u32 limit = sch->dev->tx_queue_len ? : 1; + u32 limit = qdisc_dev(sch)->tx_queue_len ? : 1; if (sch->ops == &bfifo_qdisc_ops) - limit *= sch->dev->mtu; + limit *= qdisc_dev(sch)->mtu; q->limit = limit; } else { @@ -107,3 +107,46 @@ struct Qdisc_ops bfifo_qdisc_ops __read_mostly = { .owner = THIS_MODULE, }; EXPORT_SYMBOL(bfifo_qdisc_ops); + +/* Pass size change message down to embedded FIFO */ +int fifo_set_limit(struct Qdisc *q, unsigned int limit) +{ + struct nlattr *nla; + int ret = -ENOMEM; + + /* Hack to avoid sending change message to non-FIFO */ + if (strncmp(q->ops->id + 1, "fifo", 4) != 0) + return 0; + + nla = kmalloc(nla_attr_size(sizeof(struct tc_fifo_qopt)), GFP_KERNEL); + if (nla) { + nla->nla_type = RTM_NEWQDISC; + nla->nla_len = nla_attr_size(sizeof(struct tc_fifo_qopt)); + ((struct tc_fifo_qopt *)nla_data(nla))->limit = limit; + + ret = q->ops->change(q, nla); + kfree(nla); + } + return ret; +} +EXPORT_SYMBOL(fifo_set_limit); + +struct Qdisc *fifo_create_dflt(struct Qdisc *sch, struct Qdisc_ops *ops, + unsigned int limit) +{ + struct Qdisc *q; + int err = -ENOMEM; + + q = qdisc_create_dflt(qdisc_dev(sch), sch->dev_queue, + ops, TC_H_MAKE(sch->handle, 1)); + if (q) { + err = fifo_set_limit(q, limit); + if (err < 0) { + qdisc_destroy(q); + q = NULL; + } + } + + return q ? : ERR_PTR(err); +} +EXPORT_SYMBOL(fifo_create_dflt); diff --git a/net/sched/sch_generic.c b/net/sched/sch_generic.c index 13afa7214392..0ddf69286f92 100644 --- a/net/sched/sch_generic.c +++ b/net/sched/sch_generic.c @@ -29,58 +29,36 @@ /* Main transmission queue. */ /* Modifications to data participating in scheduling must be protected with - * dev->queue_lock spinlock. + * qdisc_root_lock(qdisc) spinlock. * * The idea is the following: - * - enqueue, dequeue are serialized via top level device - * spinlock dev->queue_lock. - * - ingress filtering is serialized via top level device - * spinlock dev->ingress_lock. + * - enqueue, dequeue are serialized via qdisc root lock + * - ingress filtering is also serialized via qdisc root lock * - updates to tree and tree walking are only done under the rtnl mutex. */ -void qdisc_lock_tree(struct net_device *dev) - __acquires(dev->queue_lock) - __acquires(dev->ingress_lock) -{ - spin_lock_bh(&dev->queue_lock); - spin_lock(&dev->ingress_lock); -} -EXPORT_SYMBOL(qdisc_lock_tree); - -void qdisc_unlock_tree(struct net_device *dev) - __releases(dev->ingress_lock) - __releases(dev->queue_lock) -{ - spin_unlock(&dev->ingress_lock); - spin_unlock_bh(&dev->queue_lock); -} -EXPORT_SYMBOL(qdisc_unlock_tree); - static inline int qdisc_qlen(struct Qdisc *q) { return q->q.qlen; } -static inline int dev_requeue_skb(struct sk_buff *skb, struct net_device *dev, - struct Qdisc *q) +static inline int dev_requeue_skb(struct sk_buff *skb, struct Qdisc *q) { if (unlikely(skb->next)) - dev->gso_skb = skb; + q->gso_skb = skb; else q->ops->requeue(skb, q); - netif_schedule(dev); + __netif_schedule(q); return 0; } -static inline struct sk_buff *dev_dequeue_skb(struct net_device *dev, - struct Qdisc *q) +static inline struct sk_buff *dequeue_skb(struct Qdisc *q) { struct sk_buff *skb; - if ((skb = dev->gso_skb)) - dev->gso_skb = NULL; + if ((skb = q->gso_skb)) + q->gso_skb = NULL; else skb = q->dequeue(q); @@ -88,12 +66,12 @@ static inline struct sk_buff *dev_dequeue_skb(struct net_device *dev, } static inline int handle_dev_cpu_collision(struct sk_buff *skb, - struct net_device *dev, + struct netdev_queue *dev_queue, struct Qdisc *q) { int ret; - if (unlikely(dev->xmit_lock_owner == smp_processor_id())) { + if (unlikely(dev_queue->xmit_lock_owner == smp_processor_id())) { /* * Same CPU holding the lock. It may be a transient * configuration error, when hard_start_xmit() recurses. We @@ -103,7 +81,7 @@ static inline int handle_dev_cpu_collision(struct sk_buff *skb, kfree_skb(skb); if (net_ratelimit()) printk(KERN_WARNING "Dead loop on netdevice %s, " - "fix it urgently!\n", dev->name); + "fix it urgently!\n", dev_queue->dev->name); ret = qdisc_qlen(q); } else { /* @@ -111,22 +89,22 @@ static inline int handle_dev_cpu_collision(struct sk_buff *skb, * some time. */ __get_cpu_var(netdev_rx_stat).cpu_collision++; - ret = dev_requeue_skb(skb, dev, q); + ret = dev_requeue_skb(skb, q); } return ret; } /* - * NOTE: Called under dev->queue_lock with locally disabled BH. + * NOTE: Called under qdisc_lock(q) with locally disabled BH. * - * __LINK_STATE_QDISC_RUNNING guarantees only one CPU can process this - * device at a time. dev->queue_lock serializes queue accesses for - * this device AND dev->qdisc pointer itself. + * __QDISC_STATE_RUNNING guarantees only one CPU can process + * this qdisc at a time. qdisc_lock(q) serializes queue accesses for + * this queue. * * netif_tx_lock serializes accesses to device driver. * - * dev->queue_lock and netif_tx_lock are mutually exclusive, + * qdisc_lock(q) and netif_tx_lock are mutually exclusive, * if one is grabbed, another must be free. * * Note, that this procedure can be called by a watchdog timer @@ -136,27 +114,32 @@ static inline int handle_dev_cpu_collision(struct sk_buff *skb, * >0 - queue is not empty. * */ -static inline int qdisc_restart(struct net_device *dev) +static inline int qdisc_restart(struct Qdisc *q) { - struct Qdisc *q = dev->qdisc; - struct sk_buff *skb; + struct netdev_queue *txq; int ret = NETDEV_TX_BUSY; + struct net_device *dev; + spinlock_t *root_lock; + struct sk_buff *skb; /* Dequeue packet */ - if (unlikely((skb = dev_dequeue_skb(dev, q)) == NULL)) + if (unlikely((skb = dequeue_skb(q)) == NULL)) return 0; + root_lock = qdisc_root_lock(q); - /* And release queue */ - spin_unlock(&dev->queue_lock); + /* And release qdisc */ + spin_unlock(root_lock); - HARD_TX_LOCK(dev, smp_processor_id()); + dev = qdisc_dev(q); + txq = netdev_get_tx_queue(dev, skb_get_queue_mapping(skb)); + + HARD_TX_LOCK(dev, txq, smp_processor_id()); if (!netif_subqueue_stopped(dev, skb)) - ret = dev_hard_start_xmit(skb, dev); - HARD_TX_UNLOCK(dev); + ret = dev_hard_start_xmit(skb, dev, txq); + HARD_TX_UNLOCK(dev, txq); - spin_lock(&dev->queue_lock); - q = dev->qdisc; + spin_lock(root_lock); switch (ret) { case NETDEV_TX_OK: @@ -166,7 +149,7 @@ static inline int qdisc_restart(struct net_device *dev) case NETDEV_TX_LOCKED: /* Driver try lock failed */ - ret = handle_dev_cpu_collision(skb, dev, q); + ret = handle_dev_cpu_collision(skb, txq, q); break; default: @@ -175,33 +158,33 @@ static inline int qdisc_restart(struct net_device *dev) printk(KERN_WARNING "BUG %s code %d qlen %d\n", dev->name, ret, q->q.qlen); - ret = dev_requeue_skb(skb, dev, q); + ret = dev_requeue_skb(skb, q); break; } + if (ret && netif_tx_queue_stopped(txq)) + ret = 0; + return ret; } -void __qdisc_run(struct net_device *dev) +void __qdisc_run(struct Qdisc *q) { unsigned long start_time = jiffies; - while (qdisc_restart(dev)) { - if (netif_queue_stopped(dev)) - break; - + while (qdisc_restart(q)) { /* * Postpone processing if * 1. another process needs the CPU; * 2. we've been doing it for too long. */ if (need_resched() || jiffies != start_time) { - netif_schedule(dev); + __netif_schedule(q); break; } } - clear_bit(__LINK_STATE_QDISC_RUNNING, &dev->state); + clear_bit(__QDISC_STATE_RUNNING, &q->state); } static void dev_watchdog(unsigned long arg) @@ -209,19 +192,35 @@ static void dev_watchdog(unsigned long arg) struct net_device *dev = (struct net_device *)arg; netif_tx_lock(dev); - if (dev->qdisc != &noop_qdisc) { + if (!qdisc_tx_is_noop(dev)) { if (netif_device_present(dev) && netif_running(dev) && netif_carrier_ok(dev)) { - if (netif_queue_stopped(dev) && - time_after(jiffies, dev->trans_start + dev->watchdog_timeo)) { + int some_queue_stopped = 0; + unsigned int i; + + 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; + break; + } + } - printk(KERN_INFO "NETDEV WATCHDOG: %s: transmit timed out\n", + if (some_queue_stopped && + time_after(jiffies, (dev->trans_start + + dev->watchdog_timeo))) { + printk(KERN_INFO "NETDEV WATCHDOG: %s: " + "transmit timed out\n", dev->name); dev->tx_timeout(dev); WARN_ON_ONCE(1); } - if (!mod_timer(&dev->watchdog_timer, round_jiffies(jiffies + dev->watchdog_timeo))) + if (!mod_timer(&dev->watchdog_timer, + round_jiffies(jiffies + + dev->watchdog_timeo))) dev_hold(dev); } } @@ -317,12 +316,18 @@ struct Qdisc_ops noop_qdisc_ops __read_mostly = { .owner = THIS_MODULE, }; +static struct netdev_queue noop_netdev_queue = { + .qdisc = &noop_qdisc, +}; + struct Qdisc noop_qdisc = { .enqueue = noop_enqueue, .dequeue = noop_dequeue, .flags = TCQ_F_BUILTIN, .ops = &noop_qdisc_ops, .list = LIST_HEAD_INIT(noop_qdisc.list), + .q.lock = __SPIN_LOCK_UNLOCKED(noop_qdisc.q.lock), + .dev_queue = &noop_netdev_queue, }; EXPORT_SYMBOL(noop_qdisc); @@ -335,112 +340,65 @@ static struct Qdisc_ops noqueue_qdisc_ops __read_mostly = { .owner = THIS_MODULE, }; +static struct Qdisc noqueue_qdisc; +static struct netdev_queue noqueue_netdev_queue = { + .qdisc = &noqueue_qdisc, +}; + static struct Qdisc noqueue_qdisc = { .enqueue = NULL, .dequeue = noop_dequeue, .flags = TCQ_F_BUILTIN, .ops = &noqueue_qdisc_ops, .list = LIST_HEAD_INIT(noqueue_qdisc.list), + .q.lock = __SPIN_LOCK_UNLOCKED(noqueue_qdisc.q.lock), + .dev_queue = &noqueue_netdev_queue, }; -static const u8 prio2band[TC_PRIO_MAX+1] = - { 1, 2, 2, 2, 1, 2, 0, 0 , 1, 1, 1, 1, 1, 1, 1, 1 }; - -/* 3-band FIFO queue: old style, but should be a bit faster than - generic prio+fifo combination. - */ - -#define PFIFO_FAST_BANDS 3 - -static inline struct sk_buff_head *prio2list(struct sk_buff *skb, - struct Qdisc *qdisc) +static int fifo_fast_enqueue(struct sk_buff *skb, struct Qdisc* qdisc) { - struct sk_buff_head *list = qdisc_priv(qdisc); - return list + prio2band[skb->priority & TC_PRIO_MAX]; -} - -static int pfifo_fast_enqueue(struct sk_buff *skb, struct Qdisc* qdisc) -{ - struct sk_buff_head *list = prio2list(skb, qdisc); + struct sk_buff_head *list = &qdisc->q; - if (skb_queue_len(list) < qdisc->dev->tx_queue_len) { - qdisc->q.qlen++; + if (skb_queue_len(list) < qdisc_dev(qdisc)->tx_queue_len) return __qdisc_enqueue_tail(skb, qdisc, list); - } return qdisc_drop(skb, qdisc); } -static struct sk_buff *pfifo_fast_dequeue(struct Qdisc* qdisc) +static struct sk_buff *fifo_fast_dequeue(struct Qdisc* qdisc) { - int prio; - struct sk_buff_head *list = qdisc_priv(qdisc); + struct sk_buff_head *list = &qdisc->q; - for (prio = 0; prio < PFIFO_FAST_BANDS; prio++) { - if (!skb_queue_empty(list + prio)) { - qdisc->q.qlen--; - return __qdisc_dequeue_head(qdisc, list + prio); - } - } + if (!skb_queue_empty(list)) + return __qdisc_dequeue_head(qdisc, list); return NULL; } -static int pfifo_fast_requeue(struct sk_buff *skb, struct Qdisc* qdisc) +static int fifo_fast_requeue(struct sk_buff *skb, struct Qdisc* qdisc) { - qdisc->q.qlen++; - return __qdisc_requeue(skb, qdisc, prio2list(skb, qdisc)); + return __qdisc_requeue(skb, qdisc, &qdisc->q); } -static void pfifo_fast_reset(struct Qdisc* qdisc) +static void fifo_fast_reset(struct Qdisc* qdisc) { - int prio; - struct sk_buff_head *list = qdisc_priv(qdisc); - - for (prio = 0; prio < PFIFO_FAST_BANDS; prio++) - __qdisc_reset_queue(qdisc, list + prio); - + __qdisc_reset_queue(qdisc, &qdisc->q); qdisc->qstats.backlog = 0; - qdisc->q.qlen = 0; -} - -static int pfifo_fast_dump(struct Qdisc *qdisc, struct sk_buff *skb) -{ - struct tc_prio_qopt opt = { .bands = PFIFO_FAST_BANDS }; - - memcpy(&opt.priomap, prio2band, TC_PRIO_MAX+1); - NLA_PUT(skb, TCA_OPTIONS, sizeof(opt), &opt); - return skb->len; - -nla_put_failure: - return -1; } -static int pfifo_fast_init(struct Qdisc *qdisc, struct nlattr *opt) -{ - int prio; - struct sk_buff_head *list = qdisc_priv(qdisc); - - for (prio = 0; prio < PFIFO_FAST_BANDS; prio++) - skb_queue_head_init(list + prio); - - return 0; -} - -static struct Qdisc_ops pfifo_fast_ops __read_mostly = { - .id = "pfifo_fast", - .priv_size = PFIFO_FAST_BANDS * sizeof(struct sk_buff_head), - .enqueue = pfifo_fast_enqueue, - .dequeue = pfifo_fast_dequeue, - .requeue = pfifo_fast_requeue, - .init = pfifo_fast_init, - .reset = pfifo_fast_reset, - .dump = pfifo_fast_dump, +static struct Qdisc_ops fifo_fast_ops __read_mostly = { + .id = "fifo_fast", + .priv_size = 0, + .enqueue = fifo_fast_enqueue, + .dequeue = fifo_fast_dequeue, + .requeue = fifo_fast_requeue, + .reset = fifo_fast_reset, .owner = THIS_MODULE, }; -struct Qdisc *qdisc_alloc(struct net_device *dev, struct Qdisc_ops *ops) +struct Qdisc *qdisc_alloc(struct netdev_queue *dev_queue, + struct Qdisc_ops *ops) { void *p; struct Qdisc *sch; @@ -462,8 +420,8 @@ struct Qdisc *qdisc_alloc(struct net_device *dev, struct Qdisc_ops *ops) sch->ops = ops; sch->enqueue = ops->enqueue; sch->dequeue = ops->dequeue; - sch->dev = dev; - dev_hold(dev); + sch->dev_queue = dev_queue; + dev_hold(qdisc_dev(sch)); atomic_set(&sch->refcnt, 1); return sch; @@ -471,15 +429,16 @@ errout: return ERR_PTR(err); } -struct Qdisc * qdisc_create_dflt(struct net_device *dev, struct Qdisc_ops *ops, +struct Qdisc * qdisc_create_dflt(struct net_device *dev, + struct netdev_queue *dev_queue, + struct Qdisc_ops *ops, unsigned int parentid) { struct Qdisc *sch; - sch = qdisc_alloc(dev, ops); + sch = qdisc_alloc(dev_queue, ops); if (IS_ERR(sch)) goto errout; - sch->stats_lock = &dev->queue_lock; sch->parent = parentid; if (!ops->init || ops->init(sch, NULL) == 0) @@ -491,7 +450,7 @@ errout: } EXPORT_SYMBOL(qdisc_create_dflt); -/* Under dev->queue_lock and BH! */ +/* Under qdisc_root_lock(qdisc) and BH! */ void qdisc_reset(struct Qdisc *qdisc) { @@ -508,86 +467,164 @@ EXPORT_SYMBOL(qdisc_reset); static void __qdisc_destroy(struct rcu_head *head) { struct Qdisc *qdisc = container_of(head, struct Qdisc, q_rcu); + const struct Qdisc_ops *ops = qdisc->ops; + +#ifdef CONFIG_NET_SCHED + qdisc_put_stab(qdisc->stab); +#endif + gen_kill_estimator(&qdisc->bstats, &qdisc->rate_est); + if (ops->reset) + ops->reset(qdisc); + if (ops->destroy) + ops->destroy(qdisc); + + module_put(ops->owner); + dev_put(qdisc_dev(qdisc)); + + kfree_skb(qdisc->gso_skb); + kfree((char *) qdisc - qdisc->padded); } -/* Under dev->queue_lock and BH! */ +/* Under qdisc_root_lock(qdisc) and BH! */ void qdisc_destroy(struct Qdisc *qdisc) { - const struct Qdisc_ops *ops = qdisc->ops; - if (qdisc->flags & TCQ_F_BUILTIN || !atomic_dec_and_test(&qdisc->refcnt)) return; - list_del(&qdisc->list); - gen_kill_estimator(&qdisc->bstats, &qdisc->rate_est); - if (ops->reset) - ops->reset(qdisc); - if (ops->destroy) - ops->destroy(qdisc); + if (qdisc->parent) + list_del(&qdisc->list); - module_put(ops->owner); - dev_put(qdisc->dev); call_rcu(&qdisc->q_rcu, __qdisc_destroy); } EXPORT_SYMBOL(qdisc_destroy); +static bool dev_all_qdisc_sleeping_noop(struct net_device *dev) +{ + unsigned int i; + + for (i = 0; i < dev->num_tx_queues; i++) { + struct netdev_queue *txq = netdev_get_tx_queue(dev, i); + + if (txq->qdisc_sleeping != &noop_qdisc) + return false; + } + return true; +} + +static void attach_one_default_qdisc(struct net_device *dev, + struct netdev_queue *dev_queue, + void *_unused) +{ + struct Qdisc *qdisc; + + if (dev->tx_queue_len) { + qdisc = qdisc_create_dflt(dev, dev_queue, + &fifo_fast_ops, TC_H_ROOT); + if (!qdisc) { + printk(KERN_INFO "%s: activation failed\n", dev->name); + return; + } + } else { + qdisc = &noqueue_qdisc; + } + dev_queue->qdisc_sleeping = qdisc; +} + +static void transition_one_qdisc(struct net_device *dev, + struct netdev_queue *dev_queue, + void *_need_watchdog) +{ + struct Qdisc *new_qdisc = dev_queue->qdisc_sleeping; + int *need_watchdog_p = _need_watchdog; + + rcu_assign_pointer(dev_queue->qdisc, new_qdisc); + if (new_qdisc != &noqueue_qdisc) + *need_watchdog_p = 1; +} + void dev_activate(struct net_device *dev) { + int need_watchdog; + /* No queueing discipline is attached to device; - create default one i.e. pfifo_fast for devices, - which need queueing and noqueue_qdisc for - virtual interfaces + * create default one i.e. fifo_fast for devices, + * which need queueing and noqueue_qdisc for + * virtual interfaces. */ - if (dev->qdisc_sleeping == &noop_qdisc) { - struct Qdisc *qdisc; - if (dev->tx_queue_len) { - qdisc = qdisc_create_dflt(dev, &pfifo_fast_ops, - TC_H_ROOT); - if (qdisc == NULL) { - printk(KERN_INFO "%s: activation failed\n", dev->name); - return; - } - list_add_tail(&qdisc->list, &dev->qdisc_list); - } else { - qdisc = &noqueue_qdisc; - } - dev->qdisc_sleeping = qdisc; - } + if (dev_all_qdisc_sleeping_noop(dev)) + netdev_for_each_tx_queue(dev, attach_one_default_qdisc, NULL); if (!netif_carrier_ok(dev)) /* Delay activation until next carrier-on event */ return; - spin_lock_bh(&dev->queue_lock); - rcu_assign_pointer(dev->qdisc, dev->qdisc_sleeping); - if (dev->qdisc != &noqueue_qdisc) { + need_watchdog = 0; + netdev_for_each_tx_queue(dev, transition_one_qdisc, &need_watchdog); + + if (need_watchdog) { dev->trans_start = jiffies; dev_watchdog_up(dev); } - spin_unlock_bh(&dev->queue_lock); } -void dev_deactivate(struct net_device *dev) +static void dev_deactivate_queue(struct net_device *dev, + struct netdev_queue *dev_queue, + void *_qdisc_default) { + struct Qdisc *qdisc_default = _qdisc_default; + struct sk_buff *skb = NULL; struct Qdisc *qdisc; - struct sk_buff *skb; - int running; - spin_lock_bh(&dev->queue_lock); - qdisc = dev->qdisc; - dev->qdisc = &noop_qdisc; + qdisc = dev_queue->qdisc; + if (qdisc) { + spin_lock_bh(qdisc_lock(qdisc)); - qdisc_reset(qdisc); + dev_queue->qdisc = qdisc_default; + qdisc_reset(qdisc); - skb = dev->gso_skb; - dev->gso_skb = NULL; - spin_unlock_bh(&dev->queue_lock); + spin_unlock_bh(qdisc_lock(qdisc)); + } kfree_skb(skb); +} + +static bool some_qdisc_is_running(struct net_device *dev, int lock) +{ + unsigned int i; + + for (i = 0; i < dev->num_tx_queues; i++) { + struct netdev_queue *dev_queue; + spinlock_t *root_lock; + struct Qdisc *q; + int val; + + dev_queue = netdev_get_tx_queue(dev, i); + q = dev_queue->qdisc; + root_lock = qdisc_root_lock(q); + + if (lock) + spin_lock_bh(root_lock); + + val = test_bit(__QDISC_STATE_RUNNING, &q->state); + + if (lock) + spin_unlock_bh(root_lock); + + if (val) + return true; + } + return false; +} + +void dev_deactivate(struct net_device *dev) +{ + bool running; + + netdev_for_each_tx_queue(dev, dev_deactivate_queue, &noop_qdisc); dev_watchdog_down(dev); @@ -596,16 +633,14 @@ void dev_deactivate(struct net_device *dev) /* Wait for outstanding qdisc_run calls. */ do { - while (test_bit(__LINK_STATE_QDISC_RUNNING, &dev->state)) + while (some_qdisc_is_running(dev, 0)) yield(); /* * Double-check inside queue lock to ensure that all effects * of the queue run are visible when we return. */ - spin_lock_bh(&dev->queue_lock); - running = test_bit(__LINK_STATE_QDISC_RUNNING, &dev->state); - spin_unlock_bh(&dev->queue_lock); + running = some_qdisc_is_running(dev, 1); /* * The running flag should never be set at this point because @@ -618,32 +653,46 @@ void dev_deactivate(struct net_device *dev) } while (WARN_ON_ONCE(running)); } +static void dev_init_scheduler_queue(struct net_device *dev, + struct netdev_queue *dev_queue, + void *_qdisc) +{ + struct Qdisc *qdisc = _qdisc; + + dev_queue->qdisc = qdisc; + dev_queue->qdisc_sleeping = qdisc; +} + void dev_init_scheduler(struct net_device *dev) { - qdisc_lock_tree(dev); - dev->qdisc = &noop_qdisc; - dev->qdisc_sleeping = &noop_qdisc; - INIT_LIST_HEAD(&dev->qdisc_list); - qdisc_unlock_tree(dev); + netdev_for_each_tx_queue(dev, dev_init_scheduler_queue, &noop_qdisc); + dev_init_scheduler_queue(dev, &dev->rx_queue, NULL); setup_timer(&dev->watchdog_timer, dev_watchdog, (unsigned long)dev); } -void dev_shutdown(struct net_device *dev) +static void shutdown_scheduler_queue(struct net_device *dev, + struct netdev_queue *dev_queue, + void *_qdisc_default) { - struct Qdisc *qdisc; + struct Qdisc *qdisc = dev_queue->qdisc_sleeping; + struct Qdisc *qdisc_default = _qdisc_default; - qdisc_lock_tree(dev); - qdisc = dev->qdisc_sleeping; - dev->qdisc = &noop_qdisc; - dev->qdisc_sleeping = &noop_qdisc; - qdisc_destroy(qdisc); -#if defined(CONFIG_NET_SCH_INGRESS) || defined(CONFIG_NET_SCH_INGRESS_MODULE) - if ((qdisc = dev->qdisc_ingress) != NULL) { - dev->qdisc_ingress = NULL; + if (qdisc) { + spinlock_t *root_lock = qdisc_root_lock(qdisc); + + dev_queue->qdisc = qdisc_default; + dev_queue->qdisc_sleeping = qdisc_default; + + spin_lock(root_lock); qdisc_destroy(qdisc); + spin_unlock(root_lock); } -#endif +} + +void dev_shutdown(struct net_device *dev) +{ + netdev_for_each_tx_queue(dev, shutdown_scheduler_queue, &noop_qdisc); + shutdown_scheduler_queue(dev, &dev->rx_queue, NULL); BUG_TRAP(!timer_pending(&dev->watchdog_timer)); - qdisc_unlock_tree(dev); } diff --git a/net/sched/sch_gred.c b/net/sched/sch_gred.c index c89fba56db56..c1ad6b8de105 100644 --- a/net/sched/sch_gred.c +++ b/net/sched/sch_gred.c @@ -164,7 +164,7 @@ static int gred_enqueue(struct sk_buff *skb, struct Qdisc* sch) * if no default DP has been configured. This * allows for DP flows to be left untouched. */ - if (skb_queue_len(&sch->q) < sch->dev->tx_queue_len) + if (skb_queue_len(&sch->q) < qdisc_dev(sch)->tx_queue_len) return qdisc_enqueue_tail(skb, sch); else goto drop; @@ -188,7 +188,7 @@ static int gred_enqueue(struct sk_buff *skb, struct Qdisc* sch) } q->packetsin++; - q->bytesin += skb->len; + q->bytesin += qdisc_pkt_len(skb); if (gred_wred_mode(t)) gred_load_wred_set(t, q); @@ -226,8 +226,8 @@ static int gred_enqueue(struct sk_buff *skb, struct Qdisc* sch) break; } - if (q->backlog + skb->len <= q->limit) { - q->backlog += skb->len; + if (q->backlog + qdisc_pkt_len(skb) <= q->limit) { + q->backlog += qdisc_pkt_len(skb); return qdisc_enqueue_tail(skb, sch); } @@ -254,7 +254,7 @@ static int gred_requeue(struct sk_buff *skb, struct Qdisc* sch) } else { if (red_is_idling(&q->parms)) red_end_of_idle_period(&q->parms); - q->backlog += skb->len; + q->backlog += qdisc_pkt_len(skb); } return qdisc_requeue(skb, sch); @@ -277,7 +277,7 @@ static struct sk_buff *gred_dequeue(struct Qdisc* sch) "VQ 0x%x after dequeue, screwing up " "backlog.\n", tc_index_to_dp(skb)); } else { - q->backlog -= skb->len; + q->backlog -= qdisc_pkt_len(skb); if (!q->backlog && !gred_wred_mode(t)) red_start_of_idle_period(&q->parms); @@ -299,7 +299,7 @@ static unsigned int gred_drop(struct Qdisc* sch) skb = qdisc_dequeue_tail(sch); if (skb) { - unsigned int len = skb->len; + unsigned int len = qdisc_pkt_len(skb); struct gred_sched_data *q; u16 dp = tc_index_to_dp(skb); diff --git a/net/sched/sch_hfsc.c b/net/sched/sch_hfsc.c index e817aa00441d..0ae7d19dcba8 100644 --- a/net/sched/sch_hfsc.c +++ b/net/sched/sch_hfsc.c @@ -113,7 +113,7 @@ enum hfsc_class_flags struct hfsc_class { - u32 classid; /* class id */ + struct Qdisc_class_common cl_common; unsigned int refcnt; /* usage count */ struct gnet_stats_basic bstats; @@ -134,7 +134,6 @@ struct hfsc_class struct rb_node vt_node; /* parent's vt_tree member */ struct rb_root cf_tree; /* active children sorted by cl_f */ struct rb_node cf_node; /* parent's cf_heap member */ - struct list_head hlist; /* hash list member */ struct list_head dlist; /* drop list member */ u64 cl_total; /* total work in bytes */ @@ -177,13 +176,11 @@ struct hfsc_class unsigned long cl_nactive; /* number of active children */ }; -#define HFSC_HSIZE 16 - struct hfsc_sched { u16 defcls; /* default class id */ struct hfsc_class root; /* root class */ - struct list_head clhash[HFSC_HSIZE]; /* class hash */ + struct Qdisc_class_hash clhash; /* class hash */ struct rb_root eligible; /* eligible tree */ struct list_head droplist; /* active leaf class list (for dropping) */ @@ -898,7 +895,7 @@ qdisc_peek_len(struct Qdisc *sch) printk("qdisc_peek_len: non work-conserving qdisc ?\n"); return 0; } - len = skb->len; + len = qdisc_pkt_len(skb); if (unlikely(sch->ops->requeue(skb, sch) != NET_XMIT_SUCCESS)) { if (net_ratelimit()) printk("qdisc_peek_len: failed to requeue\n"); @@ -933,26 +930,16 @@ hfsc_adjust_levels(struct hfsc_class *cl) } while ((cl = cl->cl_parent) != NULL); } -static inline unsigned int -hfsc_hash(u32 h) -{ - h ^= h >> 8; - h ^= h >> 4; - - return h & (HFSC_HSIZE - 1); -} - static inline struct hfsc_class * hfsc_find_class(u32 classid, struct Qdisc *sch) { struct hfsc_sched *q = qdisc_priv(sch); - struct hfsc_class *cl; + struct Qdisc_class_common *clc; - list_for_each_entry(cl, &q->clhash[hfsc_hash(classid)], hlist) { - if (cl->classid == classid) - return cl; - } - return NULL; + clc = qdisc_class_find(&q->clhash, classid); + if (clc == NULL) + return NULL; + return container_of(clc, struct hfsc_class, cl_common); } static void @@ -1032,7 +1019,8 @@ hfsc_change_class(struct Qdisc *sch, u32 classid, u32 parentid, if (cl != NULL) { if (parentid) { - if (cl->cl_parent && cl->cl_parent->classid != parentid) + if (cl->cl_parent && + cl->cl_parent->cl_common.classid != parentid) return -EINVAL; if (cl->cl_parent == NULL && parentid != TC_H_ROOT) return -EINVAL; @@ -1057,7 +1045,7 @@ hfsc_change_class(struct Qdisc *sch, u32 classid, u32 parentid, if (tca[TCA_RATE]) gen_replace_estimator(&cl->bstats, &cl->rate_est, - &sch->dev->queue_lock, + qdisc_root_lock(sch), tca[TCA_RATE]); return 0; } @@ -1091,11 +1079,12 @@ hfsc_change_class(struct Qdisc *sch, u32 classid, u32 parentid, if (usc != NULL) hfsc_change_usc(cl, usc, 0); + cl->cl_common.classid = classid; cl->refcnt = 1; - cl->classid = classid; cl->sched = q; cl->cl_parent = parent; - cl->qdisc = qdisc_create_dflt(sch->dev, &pfifo_qdisc_ops, classid); + cl->qdisc = qdisc_create_dflt(qdisc_dev(sch), sch->dev_queue, + &pfifo_qdisc_ops, classid); if (cl->qdisc == NULL) cl->qdisc = &noop_qdisc; INIT_LIST_HEAD(&cl->children); @@ -1103,7 +1092,7 @@ hfsc_change_class(struct Qdisc *sch, u32 classid, u32 parentid, cl->cf_tree = RB_ROOT; sch_tree_lock(sch); - list_add_tail(&cl->hlist, &q->clhash[hfsc_hash(classid)]); + qdisc_class_hash_insert(&q->clhash, &cl->cl_common); list_add_tail(&cl->siblings, &parent->children); if (parent->level == 0) hfsc_purge_queue(sch, parent); @@ -1111,9 +1100,11 @@ hfsc_change_class(struct Qdisc *sch, u32 classid, u32 parentid, cl->cl_pcvtoff = parent->cl_cvtoff; sch_tree_unlock(sch); + qdisc_class_hash_grow(sch, &q->clhash); + if (tca[TCA_RATE]) gen_new_estimator(&cl->bstats, &cl->rate_est, - &sch->dev->queue_lock, tca[TCA_RATE]); + qdisc_root_lock(sch), tca[TCA_RATE]); *arg = (unsigned long)cl; return 0; } @@ -1145,7 +1136,7 @@ hfsc_delete_class(struct Qdisc *sch, unsigned long arg) hfsc_adjust_levels(cl->cl_parent); hfsc_purge_queue(sch, cl); - list_del(&cl->hlist); + qdisc_class_hash_remove(&q->clhash, &cl->cl_common); if (--cl->refcnt == 0) hfsc_destroy_class(sch, cl); @@ -1211,8 +1202,9 @@ hfsc_graft_class(struct Qdisc *sch, unsigned long arg, struct Qdisc *new, if (cl->level > 0) return -EINVAL; if (new == NULL) { - new = qdisc_create_dflt(sch->dev, &pfifo_qdisc_ops, - cl->classid); + new = qdisc_create_dflt(qdisc_dev(sch), sch->dev_queue, + &pfifo_qdisc_ops, + cl->cl_common.classid); if (new == NULL) new = &noop_qdisc; } @@ -1345,8 +1337,9 @@ hfsc_dump_class(struct Qdisc *sch, unsigned long arg, struct sk_buff *skb, struct hfsc_class *cl = (struct hfsc_class *)arg; struct nlattr *nest; - tcm->tcm_parent = cl->cl_parent ? cl->cl_parent->classid : TC_H_ROOT; - tcm->tcm_handle = cl->classid; + tcm->tcm_parent = cl->cl_parent ? cl->cl_parent->cl_common.classid : + TC_H_ROOT; + tcm->tcm_handle = cl->cl_common.classid; if (cl->level == 0) tcm->tcm_info = cl->qdisc->handle; @@ -1390,14 +1383,16 @@ static void hfsc_walk(struct Qdisc *sch, struct qdisc_walker *arg) { struct hfsc_sched *q = qdisc_priv(sch); + struct hlist_node *n; struct hfsc_class *cl; unsigned int i; if (arg->stop) return; - for (i = 0; i < HFSC_HSIZE; i++) { - list_for_each_entry(cl, &q->clhash[i], hlist) { + for (i = 0; i < q->clhash.hashsize; i++) { + hlist_for_each_entry(cl, n, &q->clhash.hash[i], + cl_common.hnode) { if (arg->count < arg->skip) { arg->count++; continue; @@ -1433,23 +1428,25 @@ hfsc_init_qdisc(struct Qdisc *sch, struct nlattr *opt) { struct hfsc_sched *q = qdisc_priv(sch); struct tc_hfsc_qopt *qopt; - unsigned int i; + int err; if (opt == NULL || nla_len(opt) < sizeof(*qopt)) return -EINVAL; qopt = nla_data(opt); q->defcls = qopt->defcls; - for (i = 0; i < HFSC_HSIZE; i++) - INIT_LIST_HEAD(&q->clhash[i]); + err = qdisc_class_hash_init(&q->clhash); + if (err < 0) + return err; q->eligible = RB_ROOT; INIT_LIST_HEAD(&q->droplist); skb_queue_head_init(&q->requeue); + q->root.cl_common.classid = sch->handle; q->root.refcnt = 1; - q->root.classid = sch->handle; q->root.sched = q; - q->root.qdisc = qdisc_create_dflt(sch->dev, &pfifo_qdisc_ops, + q->root.qdisc = qdisc_create_dflt(qdisc_dev(sch), sch->dev_queue, + &pfifo_qdisc_ops, sch->handle); if (q->root.qdisc == NULL) q->root.qdisc = &noop_qdisc; @@ -1457,7 +1454,8 @@ hfsc_init_qdisc(struct Qdisc *sch, struct nlattr *opt) q->root.vt_tree = RB_ROOT; q->root.cf_tree = RB_ROOT; - list_add(&q->root.hlist, &q->clhash[hfsc_hash(q->root.classid)]); + qdisc_class_hash_insert(&q->clhash, &q->root.cl_common); + qdisc_class_hash_grow(sch, &q->clhash); qdisc_watchdog_init(&q->watchdog, sch); @@ -1520,10 +1518,11 @@ hfsc_reset_qdisc(struct Qdisc *sch) { struct hfsc_sched *q = qdisc_priv(sch); struct hfsc_class *cl; + struct hlist_node *n; unsigned int i; - for (i = 0; i < HFSC_HSIZE; i++) { - list_for_each_entry(cl, &q->clhash[i], hlist) + for (i = 0; i < q->clhash.hashsize; i++) { + hlist_for_each_entry(cl, n, &q->clhash.hash[i], cl_common.hnode) hfsc_reset_class(cl); } __skb_queue_purge(&q->requeue); @@ -1537,17 +1536,20 @@ static void hfsc_destroy_qdisc(struct Qdisc *sch) { struct hfsc_sched *q = qdisc_priv(sch); - struct hfsc_class *cl, *next; + struct hlist_node *n, *next; + struct hfsc_class *cl; unsigned int i; - for (i = 0; i < HFSC_HSIZE; i++) { - list_for_each_entry(cl, &q->clhash[i], hlist) + for (i = 0; i < q->clhash.hashsize; i++) { + hlist_for_each_entry(cl, n, &q->clhash.hash[i], cl_common.hnode) tcf_destroy_chain(&cl->filter_list); } - for (i = 0; i < HFSC_HSIZE; i++) { - list_for_each_entry_safe(cl, next, &q->clhash[i], hlist) + for (i = 0; i < q->clhash.hashsize; i++) { + hlist_for_each_entry_safe(cl, n, next, &q->clhash.hash[i], + cl_common.hnode) hfsc_destroy_class(sch, cl); } + qdisc_class_hash_destroy(&q->clhash); __skb_queue_purge(&q->requeue); qdisc_watchdog_cancel(&q->watchdog); } @@ -1572,7 +1574,6 @@ static int hfsc_enqueue(struct sk_buff *skb, struct Qdisc *sch) { struct hfsc_class *cl; - unsigned int len; int err; cl = hfsc_classify(skb, sch, &err); @@ -1583,8 +1584,7 @@ hfsc_enqueue(struct sk_buff *skb, struct Qdisc *sch) return err; } - len = skb->len; - err = cl->qdisc->enqueue(skb, cl->qdisc); + err = qdisc_enqueue(skb, cl->qdisc); if (unlikely(err != NET_XMIT_SUCCESS)) { cl->qstats.drops++; sch->qstats.drops++; @@ -1592,12 +1592,12 @@ hfsc_enqueue(struct sk_buff *skb, struct Qdisc *sch) } if (cl->qdisc->q.qlen == 1) - set_active(cl, len); + set_active(cl, qdisc_pkt_len(skb)); cl->bstats.packets++; - cl->bstats.bytes += len; + cl->bstats.bytes += qdisc_pkt_len(skb); sch->bstats.packets++; - sch->bstats.bytes += len; + sch->bstats.bytes += qdisc_pkt_len(skb); sch->q.qlen++; return NET_XMIT_SUCCESS; @@ -1647,9 +1647,9 @@ hfsc_dequeue(struct Qdisc *sch) return NULL; } - update_vf(cl, skb->len, cur_time); + update_vf(cl, qdisc_pkt_len(skb), cur_time); if (realtime) - cl->cl_cumul += skb->len; + cl->cl_cumul += qdisc_pkt_len(skb); if (cl->qdisc->q.qlen != 0) { if (cl->cl_flags & HFSC_RSC) { diff --git a/net/sched/sch_htb.c b/net/sched/sch_htb.c index 3fb58f428f72..30c999c61b01 100644 --- a/net/sched/sch_htb.c +++ b/net/sched/sch_htb.c @@ -24,8 +24,6 @@ * Jiri Fojtasek * fixed requeue routine * and many others. thanks. - * - * $Id: sch_htb.c,v 1.25 2003/12/07 11:08:25 devik Exp devik $ */ #include <linux/module.h> #include <linux/moduleparam.h> @@ -53,7 +51,6 @@ one less than their parent. */ -#define HTB_HSIZE 16 /* classid hash size */ static int htb_hysteresis __read_mostly = 0; /* whether to use mode hysteresis for speedup */ #define HTB_VER 0x30011 /* major must be matched with number suplied by TC as version */ @@ -74,8 +71,8 @@ enum htb_cmode { /* interior & leaf nodes; props specific to leaves are marked L: */ struct htb_class { + struct Qdisc_class_common common; /* general class parameters */ - u32 classid; struct gnet_stats_basic bstats; struct gnet_stats_queue qstats; struct gnet_stats_rate_est rate_est; @@ -84,10 +81,8 @@ struct htb_class { /* topology */ int level; /* our level (see above) */ + unsigned int children; struct htb_class *parent; /* parent class */ - struct hlist_node hlist; /* classid hash list item */ - struct list_head sibling; /* sibling list item */ - struct list_head children; /* children list */ union { struct htb_class_leaf { @@ -142,8 +137,7 @@ static inline long L2T(struct htb_class *cl, struct qdisc_rate_table *rate, } struct htb_sched { - struct list_head root; /* root classes list */ - struct hlist_head hash[HTB_HSIZE]; /* hashed by classid */ + struct Qdisc_class_hash clhash; struct list_head drops[TC_HTB_NUMPRIO];/* active leaves (for drops) */ /* self list - roots of self generating tree */ @@ -165,7 +159,6 @@ struct htb_sched { /* filters for qdisc itself */ struct tcf_proto *filter_list; - int filter_cnt; int rate2quantum; /* quant = rate / rate2quantum */ psched_time_t now; /* cached dequeue time */ @@ -178,32 +171,16 @@ struct htb_sched { long direct_pkts; }; -/* compute hash of size HTB_HSIZE for given handle */ -static inline int htb_hash(u32 h) -{ -#if HTB_HSIZE != 16 -#error "Declare new hash for your HTB_HSIZE" -#endif - h ^= h >> 8; /* stolen from cbq_hash */ - h ^= h >> 4; - return h & 0xf; -} - /* find class in global hash table using given handle */ static inline struct htb_class *htb_find(u32 handle, struct Qdisc *sch) { struct htb_sched *q = qdisc_priv(sch); - struct hlist_node *p; - struct htb_class *cl; + struct Qdisc_class_common *clc; - if (TC_H_MAJ(handle) != sch->handle) + clc = qdisc_class_find(&q->clhash, handle); + if (clc == NULL) return NULL; - - hlist_for_each_entry(cl, p, q->hash + htb_hash(handle), hlist) { - if (cl->classid == handle) - return cl; - } - return NULL; + return container_of(clc, struct htb_class, common); } /** @@ -284,7 +261,7 @@ static void htb_add_to_id_tree(struct rb_root *root, parent = *p; c = rb_entry(parent, struct htb_class, node[prio]); - if (cl->classid > c->classid) + if (cl->common.classid > c->common.classid) p = &parent->rb_right; else p = &parent->rb_left; @@ -448,7 +425,7 @@ static void htb_deactivate_prios(struct htb_sched *q, struct htb_class *cl) /* we are removing child which is pointed to from parent feed - forget the pointer but remember classid */ - p->un.inner.last_ptr_id[prio] = cl->classid; + p->un.inner.last_ptr_id[prio] = cl->common.classid; p->un.inner.ptr[prio] = NULL; } @@ -595,21 +572,20 @@ static int htb_enqueue(struct sk_buff *skb, struct Qdisc *sch) kfree_skb(skb); return ret; #endif - } else if (cl->un.leaf.q->enqueue(skb, cl->un.leaf.q) != - NET_XMIT_SUCCESS) { + } else if (qdisc_enqueue(skb, cl->un.leaf.q) != NET_XMIT_SUCCESS) { sch->qstats.drops++; cl->qstats.drops++; return NET_XMIT_DROP; } else { cl->bstats.packets += skb_is_gso(skb)?skb_shinfo(skb)->gso_segs:1; - cl->bstats.bytes += skb->len; + cl->bstats.bytes += qdisc_pkt_len(skb); htb_activate(q, cl); } sch->q.qlen++; sch->bstats.packets += skb_is_gso(skb)?skb_shinfo(skb)->gso_segs:1; - sch->bstats.bytes += skb->len; + sch->bstats.bytes += qdisc_pkt_len(skb); return NET_XMIT_SUCCESS; } @@ -666,7 +642,7 @@ static int htb_requeue(struct sk_buff *skb, struct Qdisc *sch) static void htb_charge_class(struct htb_sched *q, struct htb_class *cl, int level, struct sk_buff *skb) { - int bytes = skb->len; + int bytes = qdisc_pkt_len(skb); long toks, diff; enum htb_cmode old_mode; @@ -753,10 +729,10 @@ static struct rb_node *htb_id_find_next_upper(int prio, struct rb_node *n, while (n) { struct htb_class *cl = rb_entry(n, struct htb_class, node[prio]); - if (id == cl->classid) + if (id == cl->common.classid) return n; - if (id > cl->classid) { + if (id > cl->common.classid) { n = n->rb_right; } else { r = n; @@ -866,7 +842,7 @@ next: if (!cl->warned) { printk(KERN_WARNING "htb: class %X isn't work conserving ?!\n", - cl->classid); + cl->common.classid); cl->warned = 1; } q->nwc_hit++; @@ -879,7 +855,8 @@ next: } while (cl != start); if (likely(skb != NULL)) { - if ((cl->un.leaf.deficit[level] -= skb->len) < 0) { + cl->un.leaf.deficit[level] -= qdisc_pkt_len(skb); + if (cl->un.leaf.deficit[level] < 0) { cl->un.leaf.deficit[level] += cl->un.leaf.quantum; htb_next_rb_node((level ? cl->parent->un.inner.ptr : q-> ptr[0]) + prio); @@ -977,13 +954,12 @@ static unsigned int htb_drop(struct Qdisc *sch) static void htb_reset(struct Qdisc *sch) { struct htb_sched *q = qdisc_priv(sch); - int i; - - for (i = 0; i < HTB_HSIZE; i++) { - struct hlist_node *p; - struct htb_class *cl; + struct htb_class *cl; + struct hlist_node *n; + unsigned int i; - hlist_for_each_entry(cl, p, q->hash + i, hlist) { + for (i = 0; i < q->clhash.hashsize; i++) { + hlist_for_each_entry(cl, n, &q->clhash.hash[i], common.hnode) { if (cl->level) memset(&cl->un.inner, 0, sizeof(cl->un.inner)); else { @@ -1041,16 +1017,16 @@ static int htb_init(struct Qdisc *sch, struct nlattr *opt) return -EINVAL; } - INIT_LIST_HEAD(&q->root); - for (i = 0; i < HTB_HSIZE; i++) - INIT_HLIST_HEAD(q->hash + i); + err = qdisc_class_hash_init(&q->clhash); + if (err < 0) + return err; for (i = 0; i < TC_HTB_NUMPRIO; i++) INIT_LIST_HEAD(q->drops + i); qdisc_watchdog_init(&q->watchdog, sch); skb_queue_head_init(&q->direct_queue); - q->direct_qlen = sch->dev->tx_queue_len; + q->direct_qlen = qdisc_dev(sch)->tx_queue_len; if (q->direct_qlen < 2) /* some devices have zero tx_queue_len */ q->direct_qlen = 2; @@ -1063,11 +1039,12 @@ static int htb_init(struct Qdisc *sch, struct nlattr *opt) static int htb_dump(struct Qdisc *sch, struct sk_buff *skb) { + spinlock_t *root_lock = qdisc_root_lock(sch); struct htb_sched *q = qdisc_priv(sch); struct nlattr *nest; struct tc_htb_glob gopt; - spin_lock_bh(&sch->dev->queue_lock); + spin_lock_bh(root_lock); gopt.direct_pkts = q->direct_pkts; gopt.version = HTB_VER; @@ -1081,11 +1058,11 @@ static int htb_dump(struct Qdisc *sch, struct sk_buff *skb) NLA_PUT(skb, TCA_HTB_INIT, sizeof(gopt), &gopt); nla_nest_end(skb, nest); - spin_unlock_bh(&sch->dev->queue_lock); + spin_unlock_bh(root_lock); return skb->len; nla_put_failure: - spin_unlock_bh(&sch->dev->queue_lock); + spin_unlock_bh(root_lock); nla_nest_cancel(skb, nest); return -1; } @@ -1094,12 +1071,13 @@ static int htb_dump_class(struct Qdisc *sch, unsigned long arg, struct sk_buff *skb, struct tcmsg *tcm) { struct htb_class *cl = (struct htb_class *)arg; + spinlock_t *root_lock = qdisc_root_lock(sch); struct nlattr *nest; struct tc_htb_opt opt; - spin_lock_bh(&sch->dev->queue_lock); - tcm->tcm_parent = cl->parent ? cl->parent->classid : TC_H_ROOT; - tcm->tcm_handle = cl->classid; + spin_lock_bh(root_lock); + tcm->tcm_parent = cl->parent ? cl->parent->common.classid : TC_H_ROOT; + tcm->tcm_handle = cl->common.classid; if (!cl->level && cl->un.leaf.q) tcm->tcm_info = cl->un.leaf.q->handle; @@ -1119,11 +1097,11 @@ static int htb_dump_class(struct Qdisc *sch, unsigned long arg, NLA_PUT(skb, TCA_HTB_PARMS, sizeof(opt), &opt); nla_nest_end(skb, nest); - spin_unlock_bh(&sch->dev->queue_lock); + spin_unlock_bh(root_lock); return skb->len; nla_put_failure: - spin_unlock_bh(&sch->dev->queue_lock); + spin_unlock_bh(root_lock); nla_nest_cancel(skb, nest); return -1; } @@ -1153,8 +1131,9 @@ static int htb_graft(struct Qdisc *sch, unsigned long arg, struct Qdisc *new, if (cl && !cl->level) { if (new == NULL && - (new = qdisc_create_dflt(sch->dev, &pfifo_qdisc_ops, - cl->classid)) + (new = qdisc_create_dflt(qdisc_dev(sch), sch->dev_queue, + &pfifo_qdisc_ops, + cl->common.classid)) == NULL) return -ENOBUFS; sch_tree_lock(sch); @@ -1195,12 +1174,9 @@ static inline int htb_parent_last_child(struct htb_class *cl) if (!cl->parent) /* the root class */ return 0; - - if (!(cl->parent->children.next == &cl->sibling && - cl->parent->children.prev == &cl->sibling)) + if (cl->parent->children > 1) /* not the last child */ return 0; - return 1; } @@ -1228,8 +1204,6 @@ static void htb_parent_to_leaf(struct htb_sched *q, struct htb_class *cl, static void htb_destroy_class(struct Qdisc *sch, struct htb_class *cl) { - struct htb_sched *q = qdisc_priv(sch); - if (!cl->level) { BUG_TRAP(cl->un.leaf.q); qdisc_destroy(cl->un.leaf.q); @@ -1239,21 +1213,6 @@ static void htb_destroy_class(struct Qdisc *sch, struct htb_class *cl) qdisc_put_rtab(cl->ceil); tcf_destroy_chain(&cl->filter_list); - - while (!list_empty(&cl->children)) - htb_destroy_class(sch, list_entry(cl->children.next, - struct htb_class, sibling)); - - /* note: this delete may happen twice (see htb_delete) */ - hlist_del_init(&cl->hlist); - list_del(&cl->sibling); - - if (cl->prio_activity) - htb_deactivate(q, cl); - - if (cl->cmode != HTB_CAN_SEND) - htb_safe_rb_erase(&cl->pq_node, q->wait_pq + cl->level); - kfree(cl); } @@ -1261,6 +1220,9 @@ static void htb_destroy_class(struct Qdisc *sch, struct htb_class *cl) static void htb_destroy(struct Qdisc *sch) { struct htb_sched *q = qdisc_priv(sch); + struct hlist_node *n, *next; + struct htb_class *cl; + unsigned int i; qdisc_watchdog_cancel(&q->watchdog); /* This line used to be after htb_destroy_class call below @@ -1269,10 +1231,16 @@ static void htb_destroy(struct Qdisc *sch) unbind_filter on it (without Oops). */ tcf_destroy_chain(&q->filter_list); - while (!list_empty(&q->root)) - htb_destroy_class(sch, list_entry(q->root.next, - struct htb_class, sibling)); - + for (i = 0; i < q->clhash.hashsize; i++) { + hlist_for_each_entry(cl, n, &q->clhash.hash[i], common.hnode) + tcf_destroy_chain(&cl->filter_list); + } + for (i = 0; i < q->clhash.hashsize; i++) { + hlist_for_each_entry_safe(cl, n, next, &q->clhash.hash[i], + common.hnode) + htb_destroy_class(sch, cl); + } + qdisc_class_hash_destroy(&q->clhash); __skb_queue_purge(&q->direct_queue); } @@ -1287,12 +1255,13 @@ static int htb_delete(struct Qdisc *sch, unsigned long arg) // TODO: why don't allow to delete subtree ? references ? does // tc subsys quarantee us that in htb_destroy it holds no class // refs so that we can remove children safely there ? - if (!list_empty(&cl->children) || cl->filter_cnt) + if (cl->children || cl->filter_cnt) return -EBUSY; if (!cl->level && htb_parent_last_child(cl)) { - new_q = qdisc_create_dflt(sch->dev, &pfifo_qdisc_ops, - cl->parent->classid); + new_q = qdisc_create_dflt(qdisc_dev(sch), sch->dev_queue, + &pfifo_qdisc_ops, + cl->parent->common.classid); last_child = 1; } @@ -1305,11 +1274,15 @@ static int htb_delete(struct Qdisc *sch, unsigned long arg) } /* delete from hash and active; remainder in destroy_class */ - hlist_del_init(&cl->hlist); + qdisc_class_hash_remove(&q->clhash, &cl->common); + cl->parent->children--; if (cl->prio_activity) htb_deactivate(q, cl); + if (cl->cmode != HTB_CAN_SEND) + htb_safe_rb_erase(&cl->pq_node, q->wait_pq + cl->level); + if (last_child) htb_parent_to_leaf(q, cl, new_q); @@ -1394,12 +1367,10 @@ static int htb_change_class(struct Qdisc *sch, u32 classid, goto failure; gen_new_estimator(&cl->bstats, &cl->rate_est, - &sch->dev->queue_lock, + qdisc_root_lock(sch), tca[TCA_RATE] ? : &est.nla); cl->refcnt = 1; - INIT_LIST_HEAD(&cl->sibling); - INIT_HLIST_NODE(&cl->hlist); - INIT_LIST_HEAD(&cl->children); + cl->children = 0; INIT_LIST_HEAD(&cl->un.leaf.drop_list); RB_CLEAR_NODE(&cl->pq_node); @@ -1409,7 +1380,8 @@ static int htb_change_class(struct Qdisc *sch, u32 classid, /* create leaf qdisc early because it uses kmalloc(GFP_KERNEL) so that can't be used inside of sch_tree_lock -- thanks to Karlis Peisenieks */ - new_q = qdisc_create_dflt(sch->dev, &pfifo_qdisc_ops, classid); + new_q = qdisc_create_dflt(qdisc_dev(sch), sch->dev_queue, + &pfifo_qdisc_ops, classid); sch_tree_lock(sch); if (parent && !parent->level) { unsigned int qlen = parent->un.leaf.q->q.qlen; @@ -1433,7 +1405,7 @@ static int htb_change_class(struct Qdisc *sch, u32 classid, /* leaf (we) needs elementary qdisc */ cl->un.leaf.q = new_q ? new_q : &noop_qdisc; - cl->classid = classid; + cl->common.classid = classid; cl->parent = parent; /* set class to be in HTB_CAN_SEND state */ @@ -1444,13 +1416,13 @@ static int htb_change_class(struct Qdisc *sch, u32 classid, cl->cmode = HTB_CAN_SEND; /* attach to the hash list and parent's family */ - hlist_add_head(&cl->hlist, q->hash + htb_hash(classid)); - list_add_tail(&cl->sibling, - parent ? &parent->children : &q->root); + qdisc_class_hash_insert(&q->clhash, &cl->common); + if (parent) + parent->children++; } else { if (tca[TCA_RATE]) gen_replace_estimator(&cl->bstats, &cl->rate_est, - &sch->dev->queue_lock, + qdisc_root_lock(sch), tca[TCA_RATE]); sch_tree_lock(sch); } @@ -1462,13 +1434,13 @@ static int htb_change_class(struct Qdisc *sch, u32 classid, if (!hopt->quantum && cl->un.leaf.quantum < 1000) { printk(KERN_WARNING "HTB: quantum of class %X is small. Consider r2q change.\n", - cl->classid); + cl->common.classid); cl->un.leaf.quantum = 1000; } if (!hopt->quantum && cl->un.leaf.quantum > 200000) { printk(KERN_WARNING "HTB: quantum of class %X is big. Consider r2q change.\n", - cl->classid); + cl->common.classid); cl->un.leaf.quantum = 200000; } if (hopt->quantum) @@ -1491,6 +1463,8 @@ static int htb_change_class(struct Qdisc *sch, u32 classid, cl->ceil = ctab; sch_tree_unlock(sch); + qdisc_class_hash_grow(sch, &q->clhash); + *arg = (unsigned long)cl; return 0; @@ -1514,7 +1488,6 @@ static struct tcf_proto **htb_find_tcf(struct Qdisc *sch, unsigned long arg) static unsigned long htb_bind_filter(struct Qdisc *sch, unsigned long parent, u32 classid) { - struct htb_sched *q = qdisc_priv(sch); struct htb_class *cl = htb_find(classid, sch); /*if (cl && !cl->level) return 0; @@ -1528,35 +1501,29 @@ static unsigned long htb_bind_filter(struct Qdisc *sch, unsigned long parent, */ if (cl) cl->filter_cnt++; - else - q->filter_cnt++; return (unsigned long)cl; } static void htb_unbind_filter(struct Qdisc *sch, unsigned long arg) { - struct htb_sched *q = qdisc_priv(sch); struct htb_class *cl = (struct htb_class *)arg; if (cl) cl->filter_cnt--; - else - q->filter_cnt--; } static void htb_walk(struct Qdisc *sch, struct qdisc_walker *arg) { struct htb_sched *q = qdisc_priv(sch); - int i; + struct htb_class *cl; + struct hlist_node *n; + unsigned int i; if (arg->stop) return; - for (i = 0; i < HTB_HSIZE; i++) { - struct hlist_node *p; - struct htb_class *cl; - - hlist_for_each_entry(cl, p, q->hash + i, hlist) { + for (i = 0; i < q->clhash.hashsize; i++) { + hlist_for_each_entry(cl, n, &q->clhash.hash[i], common.hnode) { if (arg->count < arg->skip) { arg->count++; continue; diff --git a/net/sched/sch_ingress.c b/net/sched/sch_ingress.c index 956c80ad5965..4a2b77374358 100644 --- a/net/sched/sch_ingress.c +++ b/net/sched/sch_ingress.c @@ -77,7 +77,7 @@ static int ingress_enqueue(struct sk_buff *skb, struct Qdisc *sch) result = tc_classify(skb, p->filter_list, &res); sch->bstats.packets++; - sch->bstats.bytes += skb->len; + sch->bstats.bytes += qdisc_pkt_len(skb); switch (result) { case TC_ACT_SHOT: result = TC_ACT_SHOT; diff --git a/net/sched/sch_netem.c b/net/sched/sch_netem.c index c9c649b26eaa..a59085700678 100644 --- a/net/sched/sch_netem.c +++ b/net/sched/sch_netem.c @@ -82,6 +82,13 @@ struct netem_skb_cb { psched_time_t time_to_send; }; +static inline struct netem_skb_cb *netem_skb_cb(struct sk_buff *skb) +{ + BUILD_BUG_ON(sizeof(skb->cb) < + sizeof(struct qdisc_skb_cb) + sizeof(struct netem_skb_cb)); + return (struct netem_skb_cb *)qdisc_skb_cb(skb)->data; +} + /* init_crandom - initialize correlated random number generator * Use entropy source for initial seed. */ @@ -180,11 +187,11 @@ static int netem_enqueue(struct sk_buff *skb, struct Qdisc *sch) * skb will be queued. */ if (count > 1 && (skb2 = skb_clone(skb, GFP_ATOMIC)) != NULL) { - struct Qdisc *rootq = sch->dev->qdisc; + struct Qdisc *rootq = qdisc_root(sch); u32 dupsave = q->duplicate; /* prevent duplicating a dup... */ q->duplicate = 0; - rootq->enqueue(skb2, rootq); + qdisc_enqueue_root(skb2, rootq); q->duplicate = dupsave; } @@ -205,7 +212,7 @@ static int netem_enqueue(struct sk_buff *skb, struct Qdisc *sch) skb->data[net_random() % skb_headlen(skb)] ^= 1<<(net_random() % 8); } - cb = (struct netem_skb_cb *)skb->cb; + cb = netem_skb_cb(skb); if (q->gap == 0 /* not doing reordering */ || q->counter < q->gap /* inside last reordering gap */ || q->reorder < get_crandom(&q->reorder_cor)) { @@ -218,7 +225,7 @@ static int netem_enqueue(struct sk_buff *skb, struct Qdisc *sch) now = psched_get_time(); cb->time_to_send = now + delay; ++q->counter; - ret = q->qdisc->enqueue(skb, q->qdisc); + ret = qdisc_enqueue(skb, q->qdisc); } else { /* * Do re-ordering by putting one out of N packets at the front @@ -231,7 +238,7 @@ static int netem_enqueue(struct sk_buff *skb, struct Qdisc *sch) if (likely(ret == NET_XMIT_SUCCESS)) { sch->q.qlen++; - sch->bstats.bytes += skb->len; + sch->bstats.bytes += qdisc_pkt_len(skb); sch->bstats.packets++; } else sch->qstats.drops++; @@ -277,8 +284,7 @@ static struct sk_buff *netem_dequeue(struct Qdisc *sch) skb = q->qdisc->dequeue(q->qdisc); if (skb) { - const struct netem_skb_cb *cb - = (const struct netem_skb_cb *)skb->cb; + const struct netem_skb_cb *cb = netem_skb_cb(skb); psched_time_t now = psched_get_time(); /* if more time remaining? */ @@ -310,28 +316,6 @@ static void netem_reset(struct Qdisc *sch) qdisc_watchdog_cancel(&q->watchdog); } -/* Pass size change message down to embedded FIFO */ -static int set_fifo_limit(struct Qdisc *q, int limit) -{ - struct nlattr *nla; - int ret = -ENOMEM; - - /* Hack to avoid sending change message to non-FIFO */ - if (strncmp(q->ops->id + 1, "fifo", 4) != 0) - return 0; - - nla = kmalloc(nla_attr_size(sizeof(struct tc_fifo_qopt)), GFP_KERNEL); - if (nla) { - nla->nla_type = RTM_NEWQDISC; - nla->nla_len = nla_attr_size(sizeof(struct tc_fifo_qopt)); - ((struct tc_fifo_qopt *)nla_data(nla))->limit = limit; - - ret = q->ops->change(q, nla); - kfree(nla); - } - return ret; -} - /* * Distribution data is a variable size payload containing * signed 16 bit values. @@ -341,6 +325,7 @@ static int get_dist_table(struct Qdisc *sch, const struct nlattr *attr) struct netem_sched_data *q = qdisc_priv(sch); unsigned long n = nla_len(attr)/sizeof(__s16); const __s16 *data = nla_data(attr); + spinlock_t *root_lock; struct disttable *d; int i; @@ -355,9 +340,11 @@ static int get_dist_table(struct Qdisc *sch, const struct nlattr *attr) for (i = 0; i < n; i++) d->table[i] = data[i]; - spin_lock_bh(&sch->dev->queue_lock); + root_lock = qdisc_root_lock(sch); + + spin_lock_bh(root_lock); d = xchg(&q->delay_dist, d); - spin_unlock_bh(&sch->dev->queue_lock); + spin_unlock_bh(root_lock); kfree(d); return 0; @@ -416,7 +403,7 @@ static int netem_change(struct Qdisc *sch, struct nlattr *opt) if (ret < 0) return ret; - ret = set_fifo_limit(q->qdisc, qopt->limit); + ret = fifo_set_limit(q->qdisc, qopt->limit); if (ret) { pr_debug("netem: can't set fifo limit\n"); return ret; @@ -476,7 +463,7 @@ static int tfifo_enqueue(struct sk_buff *nskb, struct Qdisc *sch) { struct fifo_sched_data *q = qdisc_priv(sch); struct sk_buff_head *list = &sch->q; - psched_time_t tnext = ((struct netem_skb_cb *)nskb->cb)->time_to_send; + psched_time_t tnext = netem_skb_cb(nskb)->time_to_send; struct sk_buff *skb; if (likely(skb_queue_len(list) < q->limit)) { @@ -487,8 +474,7 @@ static int tfifo_enqueue(struct sk_buff *nskb, struct Qdisc *sch) } skb_queue_reverse_walk(list, skb) { - const struct netem_skb_cb *cb - = (const struct netem_skb_cb *)skb->cb; + const struct netem_skb_cb *cb = netem_skb_cb(skb); if (tnext >= cb->time_to_send) break; @@ -496,8 +482,8 @@ static int tfifo_enqueue(struct sk_buff *nskb, struct Qdisc *sch) __skb_queue_after(list, skb, nskb); - sch->qstats.backlog += nskb->len; - sch->bstats.bytes += nskb->len; + sch->qstats.backlog += qdisc_pkt_len(nskb); + sch->bstats.bytes += qdisc_pkt_len(nskb); sch->bstats.packets++; return NET_XMIT_SUCCESS; @@ -517,7 +503,7 @@ static int tfifo_init(struct Qdisc *sch, struct nlattr *opt) q->limit = ctl->limit; } else - q->limit = max_t(u32, sch->dev->tx_queue_len, 1); + q->limit = max_t(u32, qdisc_dev(sch)->tx_queue_len, 1); q->oldest = PSCHED_PASTPERFECT; return 0; @@ -558,7 +544,8 @@ static int netem_init(struct Qdisc *sch, struct nlattr *opt) qdisc_watchdog_init(&q->watchdog, sch); - q->qdisc = qdisc_create_dflt(sch->dev, &tfifo_qdisc_ops, + q->qdisc = qdisc_create_dflt(qdisc_dev(sch), sch->dev_queue, + &tfifo_qdisc_ops, TC_H_MAKE(sch->handle, 1)); if (!q->qdisc) { pr_debug("netem: qdisc create failed\n"); diff --git a/net/sched/sch_prio.c b/net/sched/sch_prio.c index 5532f1031ab5..f849243eb095 100644 --- a/net/sched/sch_prio.c +++ b/net/sched/sch_prio.c @@ -24,11 +24,9 @@ struct prio_sched_data { int bands; - int curband; /* for round-robin */ struct tcf_proto *filter_list; u8 prio2band[TC_PRIO_MAX+1]; struct Qdisc *queues[TCQ_PRIO_BANDS]; - int mq; }; @@ -55,17 +53,14 @@ prio_classify(struct sk_buff *skb, struct Qdisc *sch, int *qerr) if (!q->filter_list || err < 0) { if (TC_H_MAJ(band)) band = 0; - band = q->prio2band[band&TC_PRIO_MAX]; - goto out; + return q->queues[q->prio2band[band&TC_PRIO_MAX]]; } band = res.classid; } band = TC_H_MIN(band) - 1; if (band >= q->bands) - band = q->prio2band[0]; -out: - if (q->mq) - skb_set_queue_mapping(skb, band); + return q->queues[q->prio2band[0]]; + return q->queues[band]; } @@ -86,8 +81,9 @@ prio_enqueue(struct sk_buff *skb, struct Qdisc *sch) } #endif - if ((ret = qdisc->enqueue(skb, qdisc)) == NET_XMIT_SUCCESS) { - sch->bstats.bytes += skb->len; + ret = qdisc_enqueue(skb, qdisc); + if (ret == NET_XMIT_SUCCESS) { + sch->bstats.bytes += qdisc_pkt_len(skb); sch->bstats.packets++; sch->q.qlen++; return NET_XMIT_SUCCESS; @@ -123,67 +119,23 @@ prio_requeue(struct sk_buff *skb, struct Qdisc* sch) } -static struct sk_buff * -prio_dequeue(struct Qdisc* sch) +static struct sk_buff *prio_dequeue(struct Qdisc* sch) { - struct sk_buff *skb; struct prio_sched_data *q = qdisc_priv(sch); int prio; - struct Qdisc *qdisc; for (prio = 0; prio < q->bands; prio++) { - /* Check if the target subqueue is available before - * pulling an skb. This way we avoid excessive requeues - * for slower queues. - */ - if (!__netif_subqueue_stopped(sch->dev, (q->mq ? prio : 0))) { - qdisc = q->queues[prio]; - skb = qdisc->dequeue(qdisc); - if (skb) { - sch->q.qlen--; - return skb; - } + struct Qdisc *qdisc = q->queues[prio]; + struct sk_buff *skb = qdisc->dequeue(qdisc); + if (skb) { + sch->q.qlen--; + return skb; } } return NULL; } -static struct sk_buff *rr_dequeue(struct Qdisc* sch) -{ - struct sk_buff *skb; - struct prio_sched_data *q = qdisc_priv(sch); - struct Qdisc *qdisc; - int bandcount; - - /* Only take one pass through the queues. If nothing is available, - * return nothing. - */ - for (bandcount = 0; bandcount < q->bands; bandcount++) { - /* Check if the target subqueue is available before - * pulling an skb. This way we avoid excessive requeues - * for slower queues. If the queue is stopped, try the - * next queue. - */ - if (!__netif_subqueue_stopped(sch->dev, - (q->mq ? q->curband : 0))) { - qdisc = q->queues[q->curband]; - skb = qdisc->dequeue(qdisc); - if (skb) { - sch->q.qlen--; - q->curband++; - if (q->curband >= q->bands) - q->curband = 0; - return skb; - } - } - q->curband++; - if (q->curband >= q->bands) - q->curband = 0; - } - return NULL; -} - static unsigned int prio_drop(struct Qdisc* sch) { struct prio_sched_data *q = qdisc_priv(sch); @@ -228,45 +180,22 @@ static int prio_tune(struct Qdisc *sch, struct nlattr *opt) { struct prio_sched_data *q = qdisc_priv(sch); struct tc_prio_qopt *qopt; - struct nlattr *tb[TCA_PRIO_MAX + 1]; - int err; int i; - err = nla_parse_nested_compat(tb, TCA_PRIO_MAX, opt, NULL, qopt, - sizeof(*qopt)); - if (err < 0) - return err; - - q->bands = qopt->bands; - /* If we're multiqueue, make sure the number of incoming bands - * matches the number of queues on the device we're associating with. - * If the number of bands requested is zero, then set q->bands to - * dev->egress_subqueue_count. Also, the root qdisc must be the - * only one that is enabled for multiqueue, since it's the only one - * that interacts with the underlying device. - */ - q->mq = nla_get_flag(tb[TCA_PRIO_MQ]); - if (q->mq) { - if (sch->parent != TC_H_ROOT) - return -EINVAL; - if (netif_is_multiqueue(sch->dev)) { - if (q->bands == 0) - q->bands = sch->dev->egress_subqueue_count; - else if (q->bands != sch->dev->egress_subqueue_count) - return -EINVAL; - } else - return -EOPNOTSUPP; - } + if (nla_len(opt) < sizeof(*qopt)) + return -EINVAL; + qopt = nla_data(opt); - if (q->bands > TCQ_PRIO_BANDS || q->bands < 2) + if (qopt->bands > TCQ_PRIO_BANDS || qopt->bands < 2) return -EINVAL; for (i=0; i<=TC_PRIO_MAX; i++) { - if (qopt->priomap[i] >= q->bands) + if (qopt->priomap[i] >= qopt->bands) return -EINVAL; } sch_tree_lock(sch); + q->bands = qopt->bands; memcpy(q->prio2band, qopt->priomap, TC_PRIO_MAX+1); for (i=q->bands; i<TCQ_PRIO_BANDS; i++) { @@ -281,7 +210,8 @@ static int prio_tune(struct Qdisc *sch, struct nlattr *opt) for (i=0; i<q->bands; i++) { if (q->queues[i] == &noop_qdisc) { struct Qdisc *child; - child = qdisc_create_dflt(sch->dev, &pfifo_qdisc_ops, + child = qdisc_create_dflt(qdisc_dev(sch), sch->dev_queue, + &pfifo_qdisc_ops, TC_H_MAKE(sch->handle, i + 1)); if (child) { sch_tree_lock(sch); @@ -331,10 +261,6 @@ static int prio_dump(struct Qdisc *sch, struct sk_buff *skb) nest = nla_nest_compat_start(skb, TCA_OPTIONS, sizeof(opt), &opt); if (nest == NULL) goto nla_put_failure; - if (q->mq) { - if (nla_put_flag(skb, TCA_PRIO_MQ) < 0) - goto nla_put_failure; - } nla_nest_compat_end(skb, nest); return skb->len; @@ -507,44 +433,17 @@ static struct Qdisc_ops prio_qdisc_ops __read_mostly = { .owner = THIS_MODULE, }; -static struct Qdisc_ops rr_qdisc_ops __read_mostly = { - .next = NULL, - .cl_ops = &prio_class_ops, - .id = "rr", - .priv_size = sizeof(struct prio_sched_data), - .enqueue = prio_enqueue, - .dequeue = rr_dequeue, - .requeue = prio_requeue, - .drop = prio_drop, - .init = prio_init, - .reset = prio_reset, - .destroy = prio_destroy, - .change = prio_tune, - .dump = prio_dump, - .owner = THIS_MODULE, -}; - static int __init prio_module_init(void) { - int err; - - err = register_qdisc(&prio_qdisc_ops); - if (err < 0) - return err; - err = register_qdisc(&rr_qdisc_ops); - if (err < 0) - unregister_qdisc(&prio_qdisc_ops); - return err; + return register_qdisc(&prio_qdisc_ops); } static void __exit prio_module_exit(void) { unregister_qdisc(&prio_qdisc_ops); - unregister_qdisc(&rr_qdisc_ops); } module_init(prio_module_init) module_exit(prio_module_exit) MODULE_LICENSE("GPL"); -MODULE_ALIAS("sch_rr"); diff --git a/net/sched/sch_red.c b/net/sched/sch_red.c index 5c569853b9c0..3f2d1d7f3bbd 100644 --- a/net/sched/sch_red.c +++ b/net/sched/sch_red.c @@ -92,9 +92,9 @@ static int red_enqueue(struct sk_buff *skb, struct Qdisc* sch) break; } - ret = child->enqueue(skb, child); + ret = qdisc_enqueue(skb, child); if (likely(ret == NET_XMIT_SUCCESS)) { - sch->bstats.bytes += skb->len; + sch->bstats.bytes += qdisc_pkt_len(skb); sch->bstats.packets++; sch->q.qlen++; } else { @@ -174,33 +174,6 @@ static void red_destroy(struct Qdisc *sch) qdisc_destroy(q->qdisc); } -static struct Qdisc *red_create_dflt(struct Qdisc *sch, u32 limit) -{ - struct Qdisc *q; - struct nlattr *nla; - int ret; - - q = qdisc_create_dflt(sch->dev, &bfifo_qdisc_ops, - TC_H_MAKE(sch->handle, 1)); - if (q) { - nla = kmalloc(nla_attr_size(sizeof(struct tc_fifo_qopt)), - GFP_KERNEL); - if (nla) { - nla->nla_type = RTM_NEWQDISC; - nla->nla_len = nla_attr_size(sizeof(struct tc_fifo_qopt)); - ((struct tc_fifo_qopt *)nla_data(nla))->limit = limit; - - ret = q->ops->change(q, nla); - kfree(nla); - - if (ret == 0) - return q; - } - qdisc_destroy(q); - } - return NULL; -} - static const struct nla_policy red_policy[TCA_RED_MAX + 1] = { [TCA_RED_PARMS] = { .len = sizeof(struct tc_red_qopt) }, [TCA_RED_STAB] = { .len = RED_STAB_SIZE }, @@ -228,9 +201,9 @@ static int red_change(struct Qdisc *sch, struct nlattr *opt) ctl = nla_data(tb[TCA_RED_PARMS]); if (ctl->limit > 0) { - child = red_create_dflt(sch, ctl->limit); - if (child == NULL) - return -ENOMEM; + child = fifo_create_dflt(sch, &bfifo_qdisc_ops, ctl->limit); + if (IS_ERR(child)) + return PTR_ERR(child); } sch_tree_lock(sch); diff --git a/net/sched/sch_sfq.c b/net/sched/sch_sfq.c index 6a97afbfb952..8589da666568 100644 --- a/net/sched/sch_sfq.c +++ b/net/sched/sch_sfq.c @@ -245,7 +245,7 @@ static unsigned int sfq_drop(struct Qdisc *sch) if (d > 1) { sfq_index x = q->dep[d + SFQ_DEPTH].next; skb = q->qs[x].prev; - len = skb->len; + len = qdisc_pkt_len(skb); __skb_unlink(skb, &q->qs[x]); kfree_skb(skb); sfq_dec(q, x); @@ -261,7 +261,7 @@ static unsigned int sfq_drop(struct Qdisc *sch) q->next[q->tail] = q->next[d]; q->allot[q->next[d]] += q->quantum; skb = q->qs[d].prev; - len = skb->len; + len = qdisc_pkt_len(skb); __skb_unlink(skb, &q->qs[d]); kfree_skb(skb); sfq_dec(q, d); @@ -305,7 +305,7 @@ sfq_enqueue(struct sk_buff *skb, struct Qdisc *sch) if (q->qs[x].qlen >= q->limit) return qdisc_drop(skb, sch); - sch->qstats.backlog += skb->len; + sch->qstats.backlog += qdisc_pkt_len(skb); __skb_queue_tail(&q->qs[x], skb); sfq_inc(q, x); if (q->qs[x].qlen == 1) { /* The flow is new */ @@ -320,7 +320,7 @@ sfq_enqueue(struct sk_buff *skb, struct Qdisc *sch) } } if (++sch->q.qlen <= q->limit) { - sch->bstats.bytes += skb->len; + sch->bstats.bytes += qdisc_pkt_len(skb); sch->bstats.packets++; return 0; } @@ -352,7 +352,7 @@ sfq_requeue(struct sk_buff *skb, struct Qdisc *sch) q->hash[x] = hash; } - sch->qstats.backlog += skb->len; + sch->qstats.backlog += qdisc_pkt_len(skb); __skb_queue_head(&q->qs[x], skb); /* If selected queue has length q->limit+1, this means that * all another queues are empty and we do simple tail drop. @@ -363,7 +363,7 @@ sfq_requeue(struct sk_buff *skb, struct Qdisc *sch) skb = q->qs[x].prev; __skb_unlink(skb, &q->qs[x]); sch->qstats.drops++; - sch->qstats.backlog -= skb->len; + sch->qstats.backlog -= qdisc_pkt_len(skb); kfree_skb(skb); return NET_XMIT_CN; } @@ -411,7 +411,7 @@ sfq_dequeue(struct Qdisc *sch) skb = __skb_dequeue(&q->qs[a]); sfq_dec(q, a); sch->q.qlen--; - sch->qstats.backlog -= skb->len; + sch->qstats.backlog -= qdisc_pkt_len(skb); /* Is the slot empty? */ if (q->qs[a].qlen == 0) { @@ -423,7 +423,7 @@ sfq_dequeue(struct Qdisc *sch) } q->next[q->tail] = a; q->allot[a] += q->quantum; - } else if ((q->allot[a] -= skb->len) <= 0) { + } else if ((q->allot[a] -= qdisc_pkt_len(skb)) <= 0) { q->tail = a; a = q->next[a]; q->allot[a] += q->quantum; @@ -461,7 +461,7 @@ static int sfq_change(struct Qdisc *sch, struct nlattr *opt) return -EINVAL; sch_tree_lock(sch); - q->quantum = ctl->quantum ? : psched_mtu(sch->dev); + q->quantum = ctl->quantum ? : psched_mtu(qdisc_dev(sch)); q->perturb_period = ctl->perturb_period * HZ; if (ctl->limit) q->limit = min_t(u32, ctl->limit, SFQ_DEPTH - 1); @@ -502,7 +502,7 @@ static int sfq_init(struct Qdisc *sch, struct nlattr *opt) q->max_depth = 0; q->tail = SFQ_DEPTH; if (opt == NULL) { - q->quantum = psched_mtu(sch->dev); + q->quantum = psched_mtu(qdisc_dev(sch)); q->perturb_period = 0; q->perturbation = net_random(); } else { diff --git a/net/sched/sch_tbf.c b/net/sched/sch_tbf.c index 0b7d78f59d8c..b296672f7632 100644 --- a/net/sched/sch_tbf.c +++ b/net/sched/sch_tbf.c @@ -123,7 +123,7 @@ static int tbf_enqueue(struct sk_buff *skb, struct Qdisc* sch) struct tbf_sched_data *q = qdisc_priv(sch); int ret; - if (skb->len > q->max_size) { + if (qdisc_pkt_len(skb) > q->max_size) { sch->qstats.drops++; #ifdef CONFIG_NET_CLS_ACT if (sch->reshape_fail == NULL || sch->reshape_fail(skb, sch)) @@ -133,13 +133,14 @@ static int tbf_enqueue(struct sk_buff *skb, struct Qdisc* sch) return NET_XMIT_DROP; } - if ((ret = q->qdisc->enqueue(skb, q->qdisc)) != 0) { + ret = qdisc_enqueue(skb, q->qdisc); + if (ret != 0) { sch->qstats.drops++; return ret; } sch->q.qlen++; - sch->bstats.bytes += skb->len; + sch->bstats.bytes += qdisc_pkt_len(skb); sch->bstats.packets++; return 0; } @@ -180,7 +181,7 @@ static struct sk_buff *tbf_dequeue(struct Qdisc* sch) psched_time_t now; long toks; long ptoks = 0; - unsigned int len = skb->len; + unsigned int len = qdisc_pkt_len(skb); now = psched_get_time(); toks = psched_tdiff_bounded(now, q->t_c, q->buffer); @@ -242,34 +243,6 @@ static void tbf_reset(struct Qdisc* sch) qdisc_watchdog_cancel(&q->watchdog); } -static struct Qdisc *tbf_create_dflt_qdisc(struct Qdisc *sch, u32 limit) -{ - struct Qdisc *q; - struct nlattr *nla; - int ret; - - q = qdisc_create_dflt(sch->dev, &bfifo_qdisc_ops, - TC_H_MAKE(sch->handle, 1)); - if (q) { - nla = kmalloc(nla_attr_size(sizeof(struct tc_fifo_qopt)), - GFP_KERNEL); - if (nla) { - nla->nla_type = RTM_NEWQDISC; - nla->nla_len = nla_attr_size(sizeof(struct tc_fifo_qopt)); - ((struct tc_fifo_qopt *)nla_data(nla))->limit = limit; - - ret = q->ops->change(q, nla); - kfree(nla); - - if (ret == 0) - return q; - } - qdisc_destroy(q); - } - - return NULL; -} - static const struct nla_policy tbf_policy[TCA_TBF_MAX + 1] = { [TCA_TBF_PARMS] = { .len = sizeof(struct tc_tbf_qopt) }, [TCA_TBF_RTAB] = { .type = NLA_BINARY, .len = TC_RTAB_SIZE }, @@ -322,8 +295,11 @@ static int tbf_change(struct Qdisc* sch, struct nlattr *opt) goto done; if (qopt->limit > 0) { - if ((child = tbf_create_dflt_qdisc(sch, qopt->limit)) == NULL) + child = fifo_create_dflt(sch, &bfifo_qdisc_ops, qopt->limit); + if (IS_ERR(child)) { + err = PTR_ERR(child); goto done; + } } sch_tree_lock(sch); diff --git a/net/sched/sch_teql.c b/net/sched/sch_teql.c index 0444fd0f0d22..537223642b6e 100644 --- a/net/sched/sch_teql.c +++ b/net/sched/sch_teql.c @@ -78,12 +78,12 @@ struct teql_sched_data static int teql_enqueue(struct sk_buff *skb, struct Qdisc* sch) { - struct net_device *dev = sch->dev; + struct net_device *dev = qdisc_dev(sch); struct teql_sched_data *q = qdisc_priv(sch); if (q->q.qlen < dev->tx_queue_len) { __skb_queue_tail(&q->q, skb); - sch->bstats.bytes += skb->len; + sch->bstats.bytes += qdisc_pkt_len(skb); sch->bstats.packets++; return 0; } @@ -107,17 +107,19 @@ static struct sk_buff * teql_dequeue(struct Qdisc* sch) { struct teql_sched_data *dat = qdisc_priv(sch); + struct netdev_queue *dat_queue; struct sk_buff *skb; skb = __skb_dequeue(&dat->q); + dat_queue = netdev_get_tx_queue(dat->m->dev, 0); if (skb == NULL) { - struct net_device *m = dat->m->dev->qdisc->dev; + struct net_device *m = qdisc_dev(dat_queue->qdisc); if (m) { dat->m->slaves = sch; netif_wake_queue(m); } } - sch->q.qlen = dat->q.qlen + dat->m->dev->qdisc->q.qlen; + sch->q.qlen = dat->q.qlen + dat_queue->qdisc->q.qlen; return skb; } @@ -153,10 +155,16 @@ teql_destroy(struct Qdisc* sch) if (q == master->slaves) { master->slaves = NEXT_SLAVE(q); if (q == master->slaves) { + struct netdev_queue *txq; + spinlock_t *root_lock; + + txq = netdev_get_tx_queue(master->dev, 0); master->slaves = NULL; - spin_lock_bh(&master->dev->queue_lock); - qdisc_reset(master->dev->qdisc); - spin_unlock_bh(&master->dev->queue_lock); + + root_lock = qdisc_root_lock(txq->qdisc); + spin_lock_bh(root_lock); + qdisc_reset(txq->qdisc); + spin_unlock_bh(root_lock); } } skb_queue_purge(&dat->q); @@ -170,7 +178,7 @@ teql_destroy(struct Qdisc* sch) static int teql_qdisc_init(struct Qdisc *sch, struct nlattr *opt) { - struct net_device *dev = sch->dev; + struct net_device *dev = qdisc_dev(sch); struct teql_master *m = (struct teql_master*)sch->ops; struct teql_sched_data *q = qdisc_priv(sch); @@ -216,7 +224,8 @@ static int teql_qdisc_init(struct Qdisc *sch, struct nlattr *opt) static int __teql_resolve(struct sk_buff *skb, struct sk_buff *skb_res, struct net_device *dev) { - struct teql_sched_data *q = qdisc_priv(dev->qdisc); + 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 *n = q->ncache; @@ -252,7 +261,8 @@ __teql_resolve(struct sk_buff *skb, struct sk_buff *skb_res, struct net_device * static inline int teql_resolve(struct sk_buff *skb, struct sk_buff *skb_res, struct net_device *dev) { - if (dev->qdisc == &noop_qdisc) + struct netdev_queue *txq = netdev_get_tx_queue(dev, 0); + if (txq->qdisc == &noop_qdisc) return -ENODEV; if (dev->header_ops == NULL || @@ -268,7 +278,6 @@ static int teql_master_xmit(struct sk_buff *skb, struct net_device *dev) struct Qdisc *start, *q; int busy; int nores; - int len = skb->len; int subq = skb_get_queue_mapping(skb); struct sk_buff *skb_res = NULL; @@ -282,12 +291,13 @@ restart: goto drop; do { - struct net_device *slave = q->dev; + struct net_device *slave = qdisc_dev(q); + struct netdev_queue *slave_txq; - if (slave->qdisc_sleeping != q) + slave_txq = netdev_get_tx_queue(slave, 0); + if (slave_txq->qdisc_sleeping != q) continue; - if (netif_queue_stopped(slave) || - __netif_subqueue_stopped(slave, subq) || + if (__netif_subqueue_stopped(slave, subq) || !netif_running(slave)) { busy = 1; continue; @@ -296,14 +306,14 @@ restart: switch (teql_resolve(skb, skb_res, slave)) { case 0: if (netif_tx_trylock(slave)) { - if (!netif_queue_stopped(slave) && - !__netif_subqueue_stopped(slave, subq) && + if (!__netif_subqueue_stopped(slave, subq) && slave->hard_start_xmit(skb, slave) == 0) { netif_tx_unlock(slave); master->slaves = NEXT_SLAVE(q); netif_wake_queue(dev); master->stats.tx_packets++; - master->stats.tx_bytes += len; + master->stats.tx_bytes += + qdisc_pkt_len(skb); return 0; } netif_tx_unlock(slave); @@ -352,7 +362,7 @@ static int teql_master_open(struct net_device *dev) q = m->slaves; do { - struct net_device *slave = q->dev; + struct net_device *slave = qdisc_dev(q); if (slave == NULL) return -EUNATCH; @@ -403,7 +413,7 @@ static int teql_master_mtu(struct net_device *dev, int new_mtu) q = m->slaves; if (q) { do { - if (new_mtu > q->dev->mtu) + if (new_mtu > qdisc_dev(q)->mtu) return -EINVAL; } while ((q=NEXT_SLAVE(q)) != m->slaves); } diff --git a/net/sctp/Kconfig b/net/sctp/Kconfig index 0b79f869c4ea..58b3e882a187 100644 --- a/net/sctp/Kconfig +++ b/net/sctp/Kconfig @@ -47,11 +47,11 @@ config SCTP_DBG_MSG config SCTP_DBG_OBJCNT bool "SCTP: Debug object counts" + depends on PROC_FS help If you say Y, this will enable debugging support for counting the type of objects that are currently allocated. This is useful for - identifying memory leaks. If the /proc filesystem is enabled this - debug information can be viewed by + identifying memory leaks. This debug information can be viewed by 'cat /proc/net/sctp/sctp_dbg_objcnt' If unsure, say N diff --git a/net/sctp/Makefile b/net/sctp/Makefile index f5356b9d5ee3..6b794734380a 100644 --- a/net/sctp/Makefile +++ b/net/sctp/Makefile @@ -9,10 +9,10 @@ sctp-y := sm_statetable.o sm_statefuns.o sm_sideeffect.o \ transport.o chunk.o sm_make_chunk.o ulpevent.o \ inqueue.o outqueue.o ulpqueue.o command.o \ tsnmap.o bind_addr.o socket.o primitive.o \ - output.o input.o debug.o ssnmap.o proc.o \ - auth.o + output.o input.o debug.o ssnmap.o auth.o sctp-$(CONFIG_SCTP_DBG_OBJCNT) += objcnt.o +sctp-$(CONFIG_PROC_FS) += proc.o sctp-$(CONFIG_SYSCTL) += sysctl.o sctp-$(subst m,y,$(CONFIG_IPV6)) += ipv6.o diff --git a/net/sctp/associola.c b/net/sctp/associola.c index 024c3ebd9661..ec2a0a33fd78 100644 --- a/net/sctp/associola.c +++ b/net/sctp/associola.c @@ -136,6 +136,7 @@ static struct sctp_association *sctp_association_init(struct sctp_association *a /* Set association default SACK delay */ asoc->sackdelay = msecs_to_jiffies(sp->sackdelay); + asoc->sackfreq = sp->sackfreq; /* Set the association default flags controlling * Heartbeat, SACK delay, and Path MTU Discovery. @@ -261,6 +262,7 @@ static struct sctp_association *sctp_association_init(struct sctp_association *a * already received one packet.] */ asoc->peer.sack_needed = 1; + asoc->peer.sack_cnt = 0; /* Assume that the peer will tell us if he recognizes ASCONF * as part of INIT exchange. @@ -624,6 +626,7 @@ struct sctp_transport *sctp_assoc_add_peer(struct sctp_association *asoc, * association configured value. */ peer->sackdelay = asoc->sackdelay; + peer->sackfreq = asoc->sackfreq; /* Enable/disable heartbeat, SACK delay, and path MTU discovery * based on association setting. @@ -650,6 +653,7 @@ struct sctp_transport *sctp_assoc_add_peer(struct sctp_association *asoc, SCTP_DEBUG_PRINTK("sctp_assoc_add_peer:association %p PMTU set to " "%d\n", asoc, asoc->pathmtu); + peer->pmtu_pending = 0; asoc->frag_point = sctp_frag_point(sp, asoc->pathmtu); diff --git a/net/sctp/bind_addr.c b/net/sctp/bind_addr.c index 80e6df06967a..f62bc2468935 100644 --- a/net/sctp/bind_addr.c +++ b/net/sctp/bind_addr.c @@ -348,6 +348,43 @@ int sctp_bind_addr_match(struct sctp_bind_addr *bp, return match; } +/* Does the address 'addr' conflict with any addresses in + * the bp. + */ +int sctp_bind_addr_conflict(struct sctp_bind_addr *bp, + const union sctp_addr *addr, + struct sctp_sock *bp_sp, + struct sctp_sock *addr_sp) +{ + struct sctp_sockaddr_entry *laddr; + int conflict = 0; + struct sctp_sock *sp; + + /* Pick the IPv6 socket as the basis of comparison + * since it's usually a superset of the IPv4. + * If there is no IPv6 socket, then default to bind_addr. + */ + if (sctp_opt2sk(bp_sp)->sk_family == AF_INET6) + sp = bp_sp; + else if (sctp_opt2sk(addr_sp)->sk_family == AF_INET6) + sp = addr_sp; + else + sp = bp_sp; + + rcu_read_lock(); + list_for_each_entry_rcu(laddr, &bp->address_list, list) { + if (!laddr->valid) + continue; + + conflict = sp->pf->cmp_addr(&laddr->a, addr, sp); + if (conflict) + break; + } + rcu_read_unlock(); + + return conflict; +} + /* Get the state of the entry in the bind_addr_list */ int sctp_bind_addr_state(const struct sctp_bind_addr *bp, const union sctp_addr *addr) diff --git a/net/sctp/input.c b/net/sctp/input.c index ca6b022b1df2..a49fa80b57b9 100644 --- a/net/sctp/input.c +++ b/net/sctp/input.c @@ -61,6 +61,7 @@ #include <net/sctp/sctp.h> #include <net/sctp/sm.h> #include <net/sctp/checksum.h> +#include <net/net_namespace.h> /* Forward declarations for internal helpers. */ static int sctp_rcv_ootb(struct sk_buff *); @@ -82,8 +83,8 @@ 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); - __u32 cmp = ntohl(sh->checksum); - __u32 val = sctp_start_cksum((__u8 *)sh, skb_headlen(skb)); + __be32 cmp = sh->checksum; + __be32 val = sctp_start_cksum((__u8 *)sh, skb_headlen(skb)); for (; list; list = list->next) val = sctp_update_cksum((__u8 *)list->data, skb_headlen(list), @@ -430,6 +431,9 @@ struct sock *sctp_err_lookup(int family, struct sk_buff *skb, struct sock *sk = NULL; struct sctp_association *asoc; struct sctp_transport *transport = NULL; + struct sctp_init_chunk *chunkhdr; + __u32 vtag = ntohl(sctphdr->vtag); + int len = skb->len - ((void *)sctphdr - (void *)skb->data); *app = NULL; *tpp = NULL; @@ -451,8 +455,28 @@ struct sock *sctp_err_lookup(int family, struct sk_buff *skb, sk = asoc->base.sk; - if (ntohl(sctphdr->vtag) != asoc->c.peer_vtag) { - ICMP_INC_STATS_BH(ICMP_MIB_INERRORS); + /* RFC 4960, Appendix C. ICMP Handling + * + * ICMP6) An implementation MUST validate that the Verification Tag + * contained in the ICMP message matches the Verification Tag of + * the peer. If the Verification Tag is not 0 and does NOT + * match, discard the ICMP message. If it is 0 and the ICMP + * message contains enough bytes to verify that the chunk type is + * an INIT chunk and that the Initiate Tag matches the tag of the + * peer, continue with ICMP7. If the ICMP message is too short + * or the chunk type or the Initiate Tag does not match, silently + * discard the packet. + */ + if (vtag == 0) { + chunkhdr = (struct sctp_init_chunk *)((void *)sctphdr + + sizeof(struct sctphdr)); + if (len < sizeof(struct sctphdr) + sizeof(sctp_chunkhdr_t) + + sizeof(__be32) || + chunkhdr->chunk_hdr.type != SCTP_CID_INIT || + ntohl(chunkhdr->init_hdr.init_tag) != asoc->c.my_vtag) { + goto out; + } + } else if (vtag != asoc->c.peer_vtag) { goto out; } @@ -462,7 +486,7 @@ struct sock *sctp_err_lookup(int family, struct sk_buff *skb, * servers this needs to be solved differently. */ if (sock_owned_by_user(sk)) - NET_INC_STATS_BH(LINUX_MIB_LOCKDROPPEDICMPS); + NET_INC_STATS_BH(&init_net, LINUX_MIB_LOCKDROPPEDICMPS); *app = asoc; *tpp = transport; @@ -511,7 +535,7 @@ void sctp_v4_err(struct sk_buff *skb, __u32 info) int err; if (skb->len < ihlen + 8) { - ICMP_INC_STATS_BH(ICMP_MIB_INERRORS); + ICMP_INC_STATS_BH(&init_net, ICMP_MIB_INERRORS); return; } @@ -525,7 +549,7 @@ void sctp_v4_err(struct sk_buff *skb, __u32 info) skb->network_header = saveip; skb->transport_header = savesctp; if (!sk) { - ICMP_INC_STATS_BH(ICMP_MIB_INERRORS); + ICMP_INC_STATS_BH(&init_net, ICMP_MIB_INERRORS); return; } /* Warning: The sock lock is held. Remember to call diff --git a/net/sctp/ipv6.c b/net/sctp/ipv6.c index a2f4d4d51593..a238d6834b33 100644 --- a/net/sctp/ipv6.c +++ b/net/sctp/ipv6.c @@ -818,7 +818,7 @@ static int sctp_inet6_af_supported(sa_family_t family, struct sctp_sock *sp) return 1; /* v4-mapped-v6 addresses */ case AF_INET: - if (!__ipv6_only_sock(sctp_opt2sk(sp)) && sp->v4mapped) + if (!__ipv6_only_sock(sctp_opt2sk(sp))) return 1; default: return 0; @@ -840,6 +840,11 @@ static int sctp_inet6_cmp_addr(const union sctp_addr *addr1, if (!af1 || !af2) return 0; + + /* If the socket is IPv6 only, v4 addrs will not match */ + if (__ipv6_only_sock(sctp_opt2sk(opt)) && af1 != af2) + return 0; + /* Today, wildcard AF_INET/AF_INET6. */ if (sctp_is_any(addr1) || sctp_is_any(addr2)) return 1; @@ -876,7 +881,11 @@ static int sctp_inet6_bind_verify(struct sctp_sock *opt, union sctp_addr *addr) return 0; } dev_put(dev); + } else if (type == IPV6_ADDR_MAPPED) { + if (!opt->v4mapped) + return 0; } + af = opt->pf->af; } return af->available(addr, opt); @@ -919,9 +928,12 @@ static int sctp_inet6_send_verify(struct sctp_sock *opt, union sctp_addr *addr) static int sctp_inet6_supported_addrs(const struct sctp_sock *opt, __be16 *types) { - types[0] = SCTP_PARAM_IPV4_ADDRESS; - types[1] = SCTP_PARAM_IPV6_ADDRESS; - return 2; + types[0] = SCTP_PARAM_IPV6_ADDRESS; + if (!opt || !ipv6_only_sock(sctp_opt2sk(opt))) { + types[1] = SCTP_PARAM_IPV4_ADDRESS; + return 2; + } + return 1; } static const struct proto_ops inet6_seqpacket_ops = { diff --git a/net/sctp/output.c b/net/sctp/output.c index 6d45bae93b46..45684646b1db 100644 --- a/net/sctp/output.c +++ b/net/sctp/output.c @@ -50,6 +50,7 @@ #include <linux/init.h> #include <net/inet_ecn.h> #include <net/icmp.h> +#include <net/net_namespace.h> #ifndef TEST_FRAME #include <net/tcp.h> @@ -157,7 +158,8 @@ void sctp_packet_free(struct sctp_packet *packet) * packet can be sent only after receiving the COOKIE_ACK. */ sctp_xmit_t sctp_packet_transmit_chunk(struct sctp_packet *packet, - struct sctp_chunk *chunk) + struct sctp_chunk *chunk, + int one_packet) { sctp_xmit_t retval; int error = 0; @@ -175,7 +177,9 @@ sctp_xmit_t sctp_packet_transmit_chunk(struct sctp_packet *packet, /* If we have an empty packet, then we can NOT ever * return PMTU_FULL. */ - retval = sctp_packet_append_chunk(packet, chunk); + if (!one_packet) + retval = sctp_packet_append_chunk(packet, + chunk); } break; @@ -361,7 +365,7 @@ int sctp_packet_transmit(struct sctp_packet *packet) struct sctp_transport *tp = packet->transport; struct sctp_association *asoc = tp->asoc; struct sctphdr *sh; - __u32 crc32 = 0; + __be32 crc32 = __constant_cpu_to_be32(0); struct sk_buff *nskb; struct sctp_chunk *chunk, *tmp; struct sock *sk; @@ -534,7 +538,7 @@ int sctp_packet_transmit(struct sctp_packet *packet) /* 3) Put the resultant value into the checksum field in the * common header, and leave the rest of the bits unchanged. */ - sh->checksum = htonl(crc32); + sh->checksum = crc32; /* IP layer ECN support * From RFC 2481 @@ -592,7 +596,7 @@ out: return err; no_route: kfree_skb(nskb); - IP_INC_STATS_BH(IPSTATS_MIB_OUTNOROUTES); + IP_INC_STATS_BH(&init_net, IPSTATS_MIB_OUTNOROUTES); /* FIXME: Returning the 'err' will effect all the associations * associated with a socket, although only one of the paths of the diff --git a/net/sctp/outqueue.c b/net/sctp/outqueue.c index ace6770e9048..70ead8dc3485 100644 --- a/net/sctp/outqueue.c +++ b/net/sctp/outqueue.c @@ -702,6 +702,7 @@ int sctp_outq_uncork(struct sctp_outq *q) return error; } + /* * Try to flush an outqueue. * @@ -725,6 +726,7 @@ int sctp_outq_flush(struct sctp_outq *q, int rtx_timeout) sctp_xmit_t status; int error = 0; int start_timer = 0; + int one_packet = 0; /* These transports have chunks to send. */ struct list_head transport_list; @@ -830,20 +832,33 @@ int sctp_outq_flush(struct sctp_outq *q, int rtx_timeout) if (sctp_test_T_bit(chunk)) { packet->vtag = asoc->c.my_vtag; } - case SCTP_CID_SACK: - case SCTP_CID_HEARTBEAT: + /* The following chunks are "response" chunks, i.e. + * they are generated in response to something we + * received. If we are sending these, then we can + * send only 1 packet containing these chunks. + */ case SCTP_CID_HEARTBEAT_ACK: - case SCTP_CID_SHUTDOWN: case SCTP_CID_SHUTDOWN_ACK: - case SCTP_CID_ERROR: - case SCTP_CID_COOKIE_ECHO: case SCTP_CID_COOKIE_ACK: - case SCTP_CID_ECN_ECNE: + case SCTP_CID_COOKIE_ECHO: + case SCTP_CID_ERROR: case SCTP_CID_ECN_CWR: - case SCTP_CID_ASCONF: case SCTP_CID_ASCONF_ACK: + one_packet = 1; + /* Fall throught */ + + case SCTP_CID_SACK: + case SCTP_CID_HEARTBEAT: + case SCTP_CID_SHUTDOWN: + case SCTP_CID_ECN_ECNE: + case SCTP_CID_ASCONF: case SCTP_CID_FWD_TSN: - sctp_packet_transmit_chunk(packet, chunk); + status = sctp_packet_transmit_chunk(packet, chunk, + one_packet); + if (status != SCTP_XMIT_OK) { + /* put the chunk back */ + list_add(&chunk->list, &q->control_chunk_list); + } break; default: @@ -974,7 +989,7 @@ int sctp_outq_flush(struct sctp_outq *q, int rtx_timeout) atomic_read(&chunk->skb->users) : -1); /* Add the chunk to the packet. */ - status = sctp_packet_transmit_chunk(packet, chunk); + status = sctp_packet_transmit_chunk(packet, chunk, 0); switch (status) { case SCTP_XMIT_PMTU_FULL: @@ -1239,7 +1254,6 @@ int sctp_outq_sack(struct sctp_outq *q, struct sctp_sackhdr *sack) * Make sure the empty queue handler will get run later. */ q->empty = (list_empty(&q->out_chunk_list) && - list_empty(&q->control_chunk_list) && list_empty(&q->retransmit)); if (!q->empty) goto finish; diff --git a/net/sctp/proc.c b/net/sctp/proc.c index 0aba759cb9b7..5dd89831eceb 100644 --- a/net/sctp/proc.c +++ b/net/sctp/proc.c @@ -383,3 +383,144 @@ void sctp_assocs_proc_exit(void) { remove_proc_entry("assocs", proc_net_sctp); } + +static void *sctp_remaddr_seq_start(struct seq_file *seq, loff_t *pos) +{ + if (*pos >= sctp_assoc_hashsize) + return NULL; + + if (*pos < 0) + *pos = 0; + + if (*pos == 0) + seq_printf(seq, "ADDR ASSOC_ID HB_ACT RTO MAX_PATH_RTX " + "REM_ADDR_RTX START\n"); + + return (void *)pos; +} + +static void *sctp_remaddr_seq_next(struct seq_file *seq, void *v, loff_t *pos) +{ + if (++*pos >= sctp_assoc_hashsize) + return NULL; + + return pos; +} + +static void sctp_remaddr_seq_stop(struct seq_file *seq, void *v) +{ + return; +} + +static int sctp_remaddr_seq_show(struct seq_file *seq, void *v) +{ + struct sctp_hashbucket *head; + struct sctp_ep_common *epb; + struct sctp_association *assoc; + struct hlist_node *node; + struct sctp_transport *tsp; + int hash = *(loff_t *)v; + + if (hash >= sctp_assoc_hashsize) + return -ENOMEM; + + head = &sctp_assoc_hashtable[hash]; + sctp_local_bh_disable(); + read_lock(&head->lock); + sctp_for_each_hentry(epb, node, &head->chain) { + assoc = sctp_assoc(epb); + list_for_each_entry(tsp, &assoc->peer.transport_addr_list, + transports) { + /* + * The remote address (ADDR) + */ + tsp->af_specific->seq_dump_addr(seq, &tsp->ipaddr); + seq_printf(seq, " "); + + /* + * The association ID (ASSOC_ID) + */ + seq_printf(seq, "%d ", tsp->asoc->assoc_id); + + /* + * If the Heartbeat is active (HB_ACT) + * Note: 1 = Active, 0 = Inactive + */ + seq_printf(seq, "%d ", timer_pending(&tsp->hb_timer)); + + /* + * Retransmit time out (RTO) + */ + seq_printf(seq, "%lu ", tsp->rto); + + /* + * Maximum path retransmit count (PATH_MAX_RTX) + */ + seq_printf(seq, "%d ", tsp->pathmaxrxt); + + /* + * remote address retransmit count (REM_ADDR_RTX) + * Note: We don't have a way to tally this at the moment + * so lets just leave it as zero for the moment + */ + seq_printf(seq, "0 "); + + /* + * remote address start time (START). This is also not + * currently implemented, but we can record it with a + * jiffies marker in a subsequent patch + */ + seq_printf(seq, "0"); + + seq_printf(seq, "\n"); + } + } + + read_unlock(&head->lock); + sctp_local_bh_enable(); + + return 0; + +} + +static const struct seq_operations sctp_remaddr_ops = { + .start = sctp_remaddr_seq_start, + .next = sctp_remaddr_seq_next, + .stop = sctp_remaddr_seq_stop, + .show = sctp_remaddr_seq_show, +}; + +/* Cleanup the proc fs entry for 'remaddr' object. */ +void sctp_remaddr_proc_exit(void) +{ + remove_proc_entry("remaddr", proc_net_sctp); +} + +static int sctp_remaddr_seq_open(struct inode *inode, struct file *file) +{ + return seq_open(file, &sctp_remaddr_ops); +} + +static const struct file_operations sctp_remaddr_seq_fops = { + .open = sctp_remaddr_seq_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release, +}; + +int __init sctp_remaddr_proc_init(void) +{ + struct proc_dir_entry *p; + + p = create_proc_entry("remaddr", S_IRUGO, proc_net_sctp); + if (!p) + return -ENOMEM; + p->proc_fops = &sctp_remaddr_seq_fops; + + return 0; +} + +void sctp_assoc_proc_exit(void) +{ + remove_proc_entry("remaddr", proc_net_sctp); +} diff --git a/net/sctp/protocol.c b/net/sctp/protocol.c index 9258dfe784ae..a6e0818bcff5 100644 --- a/net/sctp/protocol.c +++ b/net/sctp/protocol.c @@ -52,6 +52,8 @@ #include <linux/inetdevice.h> #include <linux/seq_file.h> #include <linux/bootmem.h> +#include <linux/highmem.h> +#include <linux/swap.h> #include <net/net_namespace.h> #include <net/protocol.h> #include <net/ip.h> @@ -64,9 +66,12 @@ /* Global data structures. */ struct sctp_globals sctp_globals __read_mostly; -struct proc_dir_entry *proc_net_sctp; DEFINE_SNMP_STAT(struct sctp_mib, sctp_statistics) __read_mostly; +#ifdef CONFIG_PROC_FS +struct proc_dir_entry *proc_net_sctp; +#endif + struct idr sctp_assocs_id; DEFINE_SPINLOCK(sctp_assocs_id_lock); @@ -97,6 +102,7 @@ struct sock *sctp_get_ctl_sock(void) /* Set up the proc fs entry for the SCTP protocol. */ static __init int sctp_proc_init(void) { +#ifdef CONFIG_PROC_FS if (!proc_net_sctp) { struct proc_dir_entry *ent; ent = proc_mkdir("sctp", init_net.proc_net); @@ -113,9 +119,13 @@ static __init int sctp_proc_init(void) goto out_eps_proc_init; if (sctp_assocs_proc_init()) goto out_assocs_proc_init; + if (sctp_remaddr_proc_init()) + goto out_remaddr_proc_init; return 0; +out_remaddr_proc_init: + sctp_assocs_proc_exit(); out_assocs_proc_init: sctp_eps_proc_exit(); out_eps_proc_init: @@ -127,6 +137,9 @@ out_snmp_proc_init: } out_nomem: return -ENOMEM; +#else + return 0; +#endif /* CONFIG_PROC_FS */ } /* Clean up the proc fs entry for the SCTP protocol. @@ -135,14 +148,17 @@ out_nomem: */ static void sctp_proc_exit(void) { +#ifdef CONFIG_PROC_FS sctp_snmp_proc_exit(); sctp_eps_proc_exit(); sctp_assocs_proc_exit(); + sctp_remaddr_proc_exit(); if (proc_net_sctp) { proc_net_sctp = NULL; remove_proc_entry("sctp", init_net.proc_net); } +#endif } /* Private helper to extract ipv4 address and stash them in @@ -367,6 +383,10 @@ static int sctp_v4_addr_valid(union sctp_addr *addr, struct sctp_sock *sp, const struct sk_buff *skb) { + /* IPv4 addresses not allowed */ + if (sp && ipv6_only_sock(sctp_opt2sk(sp))) + return 0; + /* Is this a non-unicast address or a unusable SCTP address? */ if (IS_IPV4_UNUSABLE_ADDRESS(addr->v4.sin_addr.s_addr)) return 0; @@ -390,6 +410,9 @@ static int sctp_v4_available(union sctp_addr *addr, struct sctp_sock *sp) !sysctl_ip_nonlocal_bind) return 0; + if (ipv6_only_sock(sctp_opt2sk(sp))) + return 0; + return 1; } @@ -645,7 +668,7 @@ static int sctp_inetaddr_event(struct notifier_block *this, unsigned long ev, struct sctp_sockaddr_entry *temp; int found = 0; - if (dev_net(ifa->ifa_dev->dev) != &init_net) + if (!net_eq(dev_net(ifa->ifa_dev->dev), &init_net)) return NOTIFY_DONE; switch (ev) { @@ -1059,6 +1082,7 @@ SCTP_STATIC __init int sctp_init(void) int status = -EINVAL; unsigned long goal; unsigned long limit; + unsigned long nr_pages; int max_share; int order; @@ -1154,8 +1178,9 @@ SCTP_STATIC __init int sctp_init(void) * Note this initalizes the data in sctpv6_prot too * Unabashedly stolen from tcp_init */ - limit = min(num_physpages, 1UL<<(28-PAGE_SHIFT)) >> (20-PAGE_SHIFT); - limit = (limit * (num_physpages >> (20-PAGE_SHIFT))) >> (PAGE_SHIFT-11); + nr_pages = totalram_pages - totalhigh_pages; + limit = min(nr_pages, 1UL<<(28-PAGE_SHIFT)) >> (20-PAGE_SHIFT); + limit = (limit * (nr_pages >> (20-PAGE_SHIFT))) >> (PAGE_SHIFT-11); limit = max(limit, 128UL); sysctl_sctp_mem[0] = limit / 4 * 3; sysctl_sctp_mem[1] = limit; @@ -1165,7 +1190,7 @@ SCTP_STATIC __init int sctp_init(void) limit = (sysctl_sctp_mem[1]) << (PAGE_SHIFT - 7); max_share = min(4UL*1024*1024, limit); - sysctl_sctp_rmem[0] = PAGE_SIZE; /* give each asoc 1 page min */ + sysctl_sctp_rmem[0] = SK_MEM_QUANTUM; /* give each asoc 1 page min */ sysctl_sctp_rmem[1] = (1500 *(sizeof(struct sk_buff) + 1)); sysctl_sctp_rmem[2] = max(sysctl_sctp_rmem[1], max_share); diff --git a/net/sctp/sm_make_chunk.c b/net/sctp/sm_make_chunk.c index bbc7107c86cf..e8ca4e54981f 100644 --- a/net/sctp/sm_make_chunk.c +++ b/net/sctp/sm_make_chunk.c @@ -2364,8 +2364,13 @@ static int sctp_process_param(struct sctp_association *asoc, case SCTP_PARAM_IPV6_ADDRESS: if (PF_INET6 != asoc->base.sk->sk_family) break; - /* Fall through. */ + goto do_addr_param; + case SCTP_PARAM_IPV4_ADDRESS: + /* v4 addresses are not allowed on v6-only socket */ + if (ipv6_only_sock(asoc->base.sk)) + break; +do_addr_param: af = sctp_get_af_specific(param_type2af(param.p->type)); af->from_addr_param(&addr, param.addr, htons(asoc->peer.port), 0); scope = sctp_scope(peer_addr); diff --git a/net/sctp/sm_sideeffect.c b/net/sctp/sm_sideeffect.c index 23a9f1a95b7d..9732c797e8ed 100644 --- a/net/sctp/sm_sideeffect.c +++ b/net/sctp/sm_sideeffect.c @@ -190,20 +190,28 @@ static int sctp_gen_sack(struct sctp_association *asoc, int force, * unacknowledged DATA chunk. ... */ if (!asoc->peer.sack_needed) { - /* We will need a SACK for the next packet. */ - asoc->peer.sack_needed = 1; + asoc->peer.sack_cnt++; /* Set the SACK delay timeout based on the * SACK delay for the last transport * data was received from, or the default * for the association. */ - if (trans) + if (trans) { + /* We will need a SACK for the next packet. */ + if (asoc->peer.sack_cnt >= trans->sackfreq - 1) + asoc->peer.sack_needed = 1; + asoc->timeouts[SCTP_EVENT_TIMEOUT_SACK] = trans->sackdelay; - else + } else { + /* We will need a SACK for the next packet. */ + if (asoc->peer.sack_cnt >= asoc->sackfreq - 1) + asoc->peer.sack_needed = 1; + asoc->timeouts[SCTP_EVENT_TIMEOUT_SACK] = asoc->sackdelay; + } /* Restart the SACK timer. */ sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_RESTART, @@ -216,6 +224,7 @@ static int sctp_gen_sack(struct sctp_association *asoc, int force, goto nomem; asoc->peer.sack_needed = 0; + asoc->peer.sack_cnt = 0; sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(sack)); @@ -655,7 +664,7 @@ static int sctp_cmd_process_sack(sctp_cmd_seq_t *cmds, struct sctp_association *asoc, struct sctp_sackhdr *sackh) { - int err; + int err = 0; if (sctp_outq_sack(&asoc->outqueue, sackh)) { /* There are no more TSNs awaiting SACK. */ @@ -663,11 +672,6 @@ static int sctp_cmd_process_sack(sctp_cmd_seq_t *cmds, SCTP_ST_OTHER(SCTP_EVENT_NO_PENDING_TSN), asoc->state, asoc->ep, asoc, NULL, GFP_ATOMIC); - } else { - /* Windows may have opened, so we need - * to check if we have DATA to transmit - */ - err = sctp_outq_flush(&asoc->outqueue, 0); } return err; @@ -1472,8 +1476,15 @@ static int sctp_cmd_interpreter(sctp_event_t event_type, break; case SCTP_CMD_DISCARD_PACKET: - /* We need to discard the whole packet. */ + /* We need to discard the whole packet. + * Uncork the queue since there might be + * responses pending + */ chunk->pdiscard = 1; + if (asoc) { + sctp_outq_uncork(&asoc->outqueue); + local_cork = 0; + } break; case SCTP_CMD_RTO_PENDING: @@ -1544,8 +1555,15 @@ static int sctp_cmd_interpreter(sctp_event_t event_type, } out: - if (local_cork) - sctp_outq_uncork(&asoc->outqueue); + /* If this is in response to a received chunk, wait until + * we are done with the packet to open the queue so that we don't + * send multiple packets in response to a single request. + */ + if (asoc && SCTP_EVENT_T_CHUNK == event_type && chunk) { + if (chunk->end_of_packet || chunk->singleton) + sctp_outq_uncork(&asoc->outqueue); + } else if (local_cork) + sctp_outq_uncork(&asoc->outqueue); return error; nomem: error = -ENOMEM; diff --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c index fcdb45d1071b..8848d329aa2c 100644 --- a/net/sctp/sm_statefuns.c +++ b/net/sctp/sm_statefuns.c @@ -795,8 +795,6 @@ sctp_disposition_t sctp_sf_do_5_1D_ce(const struct sctp_endpoint *ep, sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_START, SCTP_TO(SCTP_EVENT_TIMEOUT_AUTOCLOSE)); - sctp_add_cmd_sf(commands, SCTP_CMD_TRANSMIT, SCTP_NULL()); - /* This will send the COOKIE ACK */ sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(repl)); @@ -883,7 +881,6 @@ sctp_disposition_t sctp_sf_do_5_1E_ca(const struct sctp_endpoint *ep, if (asoc->autoclose) sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_START, SCTP_TO(SCTP_EVENT_TIMEOUT_AUTOCLOSE)); - sctp_add_cmd_sf(commands, SCTP_CMD_TRANSMIT, SCTP_NULL()); /* It may also notify its ULP about the successful * establishment of the association with a Communication Up @@ -1781,7 +1778,6 @@ static sctp_disposition_t sctp_sf_do_dupcook_b(const struct sctp_endpoint *ep, goto nomem; sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(repl)); - sctp_add_cmd_sf(commands, SCTP_CMD_TRANSMIT, SCTP_NULL()); /* RFC 2960 5.1 Normal Establishment of an Association * @@ -1898,12 +1894,13 @@ static sctp_disposition_t sctp_sf_do_dupcook_d(const struct sctp_endpoint *ep, } } - sctp_add_cmd_sf(commands, SCTP_CMD_TRANSMIT, SCTP_NULL()); repl = sctp_make_cookie_ack(new_asoc, chunk); if (!repl) goto nomem; + sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(repl)); + if (ev) sctp_add_cmd_sf(commands, SCTP_CMD_EVENT_ULP, SCTP_ULPEVENT(ev)); @@ -1911,9 +1908,6 @@ static sctp_disposition_t sctp_sf_do_dupcook_d(const struct sctp_endpoint *ep, sctp_add_cmd_sf(commands, SCTP_CMD_EVENT_ULP, SCTP_ULPEVENT(ai_ev)); - sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(repl)); - sctp_add_cmd_sf(commands, SCTP_CMD_TRANSMIT, SCTP_NULL()); - return SCTP_DISPOSITION_CONSUME; nomem: @@ -3970,9 +3964,6 @@ sctp_disposition_t sctp_sf_unk_chunk(const struct sctp_endpoint *ep, return sctp_sf_pdiscard(ep, asoc, type, arg, commands); break; case SCTP_CID_ACTION_DISCARD_ERR: - /* Discard the packet. */ - sctp_sf_pdiscard(ep, asoc, type, arg, commands); - /* Generate an ERROR chunk as response. */ hdr = unk_chunk->chunk_hdr; err_chunk = sctp_make_op_error(asoc, unk_chunk, @@ -3982,6 +3973,9 @@ sctp_disposition_t sctp_sf_unk_chunk(const struct sctp_endpoint *ep, sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(err_chunk)); } + + /* Discard the packet. */ + sctp_sf_pdiscard(ep, asoc, type, arg, commands); return SCTP_DISPOSITION_CONSUME; break; case SCTP_CID_ACTION_SKIP: diff --git a/net/sctp/socket.c b/net/sctp/socket.c index 0dbcde6758ea..79bece16aede 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c @@ -116,7 +116,7 @@ static int sctp_memory_pressure; static atomic_t sctp_memory_allocated; static atomic_t sctp_sockets_allocated; -static void sctp_enter_memory_pressure(void) +static void sctp_enter_memory_pressure(struct sock *sk) { sctp_memory_pressure = 1; } @@ -308,9 +308,16 @@ static struct sctp_af *sctp_sockaddr_af(struct sctp_sock *opt, if (len < sizeof (struct sockaddr)) return NULL; - /* Does this PF support this AF? */ - if (!opt->pf->af_supported(addr->sa.sa_family, opt)) - return NULL; + /* V4 mapped address are really of AF_INET family */ + if (addr->sa.sa_family == AF_INET6 && + ipv6_addr_v4mapped(&addr->v6.sin6_addr)) { + if (!opt->pf->af_supported(AF_INET, opt)) + return NULL; + } else { + /* Does this PF support this AF? */ + if (!opt->pf->af_supported(addr->sa.sa_family, opt)) + return NULL; + } /* If we get this far, af is valid. */ af = sctp_get_af_specific(addr->sa.sa_family); @@ -370,18 +377,19 @@ SCTP_STATIC int sctp_do_bind(struct sock *sk, union sctp_addr *addr, int len) if (snum && snum < PROT_SOCK && !capable(CAP_NET_BIND_SERVICE)) return -EACCES; + /* See if the address matches any of the addresses we may have + * already bound before checking against other endpoints. + */ + if (sctp_bind_addr_match(bp, addr, sp)) + return -EINVAL; + /* Make sure we are allowed to bind here. * The function sctp_get_port_local() does duplicate address * detection. */ addr->v4.sin_port = htons(snum); if ((ret = sctp_get_port_local(sk, addr))) { - if (ret == (long) sk) { - /* This endpoint has a conflicting address. */ - return -EINVAL; - } else { - return -EADDRINUSE; - } + return -EADDRINUSE; } /* Refresh ephemeral port. */ @@ -956,7 +964,8 @@ out: */ static int __sctp_connect(struct sock* sk, struct sockaddr *kaddrs, - int addrs_size) + int addrs_size, + sctp_assoc_t *assoc_id) { struct sctp_sock *sp; struct sctp_endpoint *ep; @@ -1111,6 +1120,8 @@ 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) + *assoc_id = asoc->assoc_id; /* Don't free association on exit. */ asoc = NULL; @@ -1128,7 +1139,8 @@ out_free: /* Helper for tunneling sctp_connectx() requests through sctp_setsockopt() * * API 8.9 - * int sctp_connectx(int sd, struct sockaddr *addrs, int addrcnt); + * int sctp_connectx(int sd, struct sockaddr *addrs, int addrcnt, + * sctp_assoc_t *asoc); * * If sd is an IPv4 socket, the addresses passed must be IPv4 addresses. * If the sd is an IPv6 socket, the addresses passed can either be IPv4 @@ -1144,8 +1156,10 @@ out_free: * representation is termed a "packed array" of addresses). The caller * specifies the number of addresses in the array with addrcnt. * - * On success, sctp_connectx() returns 0. On failure, sctp_connectx() returns - * -1, and sets errno to the appropriate error code. + * On success, sctp_connectx() returns 0. It also sets the assoc_id to + * the association id of the new association. On failure, sctp_connectx() + * returns -1, and sets errno to the appropriate error code. The assoc_id + * is not touched by the kernel. * * For SCTP, the port given in each socket address must be the same, or * sctp_connectx() will fail, setting errno to EINVAL. @@ -1182,11 +1196,12 @@ out_free: * addrs The pointer to the addresses in user land * addrssize Size of the addrs buffer * - * Returns 0 if ok, <0 errno code on error. + * Returns >=0 if ok, <0 errno code on error. */ -SCTP_STATIC int sctp_setsockopt_connectx(struct sock* sk, +SCTP_STATIC int __sctp_setsockopt_connectx(struct sock* sk, struct sockaddr __user *addrs, - int addrs_size) + int addrs_size, + sctp_assoc_t *assoc_id) { int err = 0; struct sockaddr *kaddrs; @@ -1209,13 +1224,46 @@ SCTP_STATIC int sctp_setsockopt_connectx(struct sock* sk, if (__copy_from_user(kaddrs, addrs, addrs_size)) { err = -EFAULT; } else { - err = __sctp_connect(sk, kaddrs, addrs_size); + err = __sctp_connect(sk, kaddrs, addrs_size, assoc_id); } kfree(kaddrs); + return err; } +/* + * This is an older interface. It's kept for backward compatibility + * to the option that doesn't provide association id. + */ +SCTP_STATIC int sctp_setsockopt_connectx_old(struct sock* sk, + struct sockaddr __user *addrs, + int addrs_size) +{ + return __sctp_setsockopt_connectx(sk, addrs, addrs_size, NULL); +} + +/* + * New interface for the API. The since the API is done with a socket + * option, to make it simple we feed back the association id is as a return + * indication to the call. Error is always negative and association id is + * always positive. + */ +SCTP_STATIC int sctp_setsockopt_connectx(struct sock* sk, + struct sockaddr __user *addrs, + int addrs_size) +{ + sctp_assoc_t assoc_id = 0; + int err = 0; + + err = __sctp_setsockopt_connectx(sk, addrs, addrs_size, &assoc_id); + + if (err) + return err; + else + return assoc_id; +} + /* 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 @@ -2305,74 +2353,98 @@ static int sctp_setsockopt_peer_addr_params(struct sock *sk, return 0; } -/* 7.1.23. Delayed Ack Timer (SCTP_DELAYED_ACK_TIME) - * - * This options will get or set the delayed ack timer. The time is set - * in milliseconds. If the assoc_id is 0, then this sets or gets the - * endpoints default delayed ack timer value. If the assoc_id field is - * non-zero, then the set or get effects the specified association. - * - * struct sctp_assoc_value { - * sctp_assoc_t assoc_id; - * uint32_t assoc_value; - * }; +/* + * 7.1.23. Get or set delayed ack timer (SCTP_DELAYED_SACK) + * + * This option will effect the way delayed acks are performed. This + * option allows you to get or set the delayed ack time, in + * milliseconds. It also allows changing the delayed ack frequency. + * Changing the frequency to 1 disables the delayed sack algorithm. If + * the assoc_id is 0, then this sets or gets the endpoints default + * values. If the assoc_id field is non-zero, then the set or get + * effects the specified association for the one to many model (the + * assoc_id field is ignored by the one to one model). Note that if + * sack_delay or sack_freq are 0 when setting this option, then the + * current values will remain unchanged. + * + * struct sctp_sack_info { + * sctp_assoc_t sack_assoc_id; + * uint32_t sack_delay; + * uint32_t sack_freq; + * }; * - * assoc_id - This parameter, indicates which association the - * user is preforming an action upon. Note that if - * this field's value is zero then the endpoints - * default value is changed (effecting future - * associations only). + * sack_assoc_id - This parameter, indicates which association the user + * is performing an action upon. Note that if this field's value is + * zero then the endpoints default value is changed (effecting future + * associations only). * - * assoc_value - This parameter contains the number of milliseconds - * that the user is requesting the delayed ACK timer - * be set to. Note that this value is defined in - * the standard to be between 200 and 500 milliseconds. + * sack_delay - This parameter contains the number of milliseconds that + * the user is requesting the delayed ACK timer be set to. Note that + * this value is defined in the standard to be between 200 and 500 + * milliseconds. * - * Note: a value of zero will leave the value alone, - * but disable SACK delay. A non-zero value will also - * enable SACK delay. + * sack_freq - This parameter contains the number of packets that must + * be received before a sack is sent without waiting for the delay + * timer to expire. The default value for this is 2, setting this + * value to 1 will disable the delayed sack algorithm. */ -static int sctp_setsockopt_delayed_ack_time(struct sock *sk, +static int sctp_setsockopt_delayed_ack(struct sock *sk, char __user *optval, int optlen) { - struct sctp_assoc_value params; + struct sctp_sack_info params; struct sctp_transport *trans = NULL; struct sctp_association *asoc = NULL; struct sctp_sock *sp = sctp_sk(sk); - if (optlen != sizeof(struct sctp_assoc_value)) - return - EINVAL; + if (optlen == sizeof(struct sctp_sack_info)) { + if (copy_from_user(¶ms, optval, optlen)) + return -EFAULT; - if (copy_from_user(¶ms, optval, optlen)) - return -EFAULT; + if (params.sack_delay == 0 && params.sack_freq == 0) + return 0; + } else if (optlen == sizeof(struct sctp_assoc_value)) { + printk(KERN_WARNING "SCTP: Use of struct sctp_sack_info " + "in delayed_ack socket option deprecated\n"); + printk(KERN_WARNING "SCTP: struct sctp_sack_info instead\n"); + if (copy_from_user(¶ms, optval, optlen)) + return -EFAULT; + + if (params.sack_delay == 0) + params.sack_freq = 1; + else + params.sack_freq = 0; + } else + return - EINVAL; /* Validate value parameter. */ - if (params.assoc_value > 500) + if (params.sack_delay > 500) return -EINVAL; - /* Get association, if assoc_id != 0 and the socket is a one + /* Get association, if sack_assoc_id != 0 and the socket is a one * to many style socket, and an association was not found, then * the id was invalid. */ - asoc = sctp_id2assoc(sk, params.assoc_id); - if (!asoc && params.assoc_id && sctp_style(sk, UDP)) + asoc = sctp_id2assoc(sk, params.sack_assoc_id); + if (!asoc && params.sack_assoc_id && sctp_style(sk, UDP)) return -EINVAL; - if (params.assoc_value) { + if (params.sack_delay) { if (asoc) { asoc->sackdelay = - msecs_to_jiffies(params.assoc_value); + msecs_to_jiffies(params.sack_delay); asoc->param_flags = (asoc->param_flags & ~SPP_SACKDELAY) | SPP_SACKDELAY_ENABLE; } else { - sp->sackdelay = params.assoc_value; + sp->sackdelay = params.sack_delay; sp->param_flags = (sp->param_flags & ~SPP_SACKDELAY) | SPP_SACKDELAY_ENABLE; } - } else { + } + + if (params.sack_freq == 1) { if (asoc) { asoc->param_flags = (asoc->param_flags & ~SPP_SACKDELAY) | @@ -2382,22 +2454,40 @@ static int sctp_setsockopt_delayed_ack_time(struct sock *sk, (sp->param_flags & ~SPP_SACKDELAY) | SPP_SACKDELAY_DISABLE; } + } else if (params.sack_freq > 1) { + if (asoc) { + asoc->sackfreq = params.sack_freq; + asoc->param_flags = + (asoc->param_flags & ~SPP_SACKDELAY) | + SPP_SACKDELAY_ENABLE; + } else { + sp->sackfreq = params.sack_freq; + sp->param_flags = + (sp->param_flags & ~SPP_SACKDELAY) | + SPP_SACKDELAY_ENABLE; + } } /* If change is for association, also apply to each transport. */ if (asoc) { list_for_each_entry(trans, &asoc->peer.transport_addr_list, transports) { - if (params.assoc_value) { + if (params.sack_delay) { trans->sackdelay = - msecs_to_jiffies(params.assoc_value); + msecs_to_jiffies(params.sack_delay); trans->param_flags = (trans->param_flags & ~SPP_SACKDELAY) | SPP_SACKDELAY_ENABLE; - } else { + } + if (params.sack_freq == 1) { trans->param_flags = (trans->param_flags & ~SPP_SACKDELAY) | SPP_SACKDELAY_DISABLE; + } else if (params.sack_freq > 1) { + trans->sackfreq = params.sack_freq; + trans->param_flags = + (trans->param_flags & ~SPP_SACKDELAY) | + SPP_SACKDELAY_ENABLE; } } } @@ -3164,10 +3254,18 @@ SCTP_STATIC int sctp_setsockopt(struct sock *sk, int level, int optname, optlen, SCTP_BINDX_REM_ADDR); break; + case SCTP_SOCKOPT_CONNECTX_OLD: + /* 'optlen' is the size of the addresses buffer. */ + retval = sctp_setsockopt_connectx_old(sk, + (struct sockaddr __user *)optval, + optlen); + break; + case SCTP_SOCKOPT_CONNECTX: /* 'optlen' is the size of the addresses buffer. */ - retval = sctp_setsockopt_connectx(sk, (struct sockaddr __user *)optval, - optlen); + retval = sctp_setsockopt_connectx(sk, + (struct sockaddr __user *)optval, + optlen); break; case SCTP_DISABLE_FRAGMENTS: @@ -3186,8 +3284,8 @@ SCTP_STATIC int sctp_setsockopt(struct sock *sk, int level, int optname, retval = sctp_setsockopt_peer_addr_params(sk, optval, optlen); break; - case SCTP_DELAYED_ACK_TIME: - retval = sctp_setsockopt_delayed_ack_time(sk, optval, optlen); + case SCTP_DELAYED_ACK: + retval = sctp_setsockopt_delayed_ack(sk, optval, optlen); break; case SCTP_PARTIAL_DELIVERY_POINT: retval = sctp_setsockopt_partial_delivery_point(sk, optval, optlen); @@ -3294,7 +3392,7 @@ SCTP_STATIC int sctp_connect(struct sock *sk, struct sockaddr *addr, /* Pass correct addr len to common routine (so it knows there * is only one address being passed. */ - err = __sctp_connect(sk, addr, af->sockaddr_len); + err = __sctp_connect(sk, addr, af->sockaddr_len, NULL); } sctp_release_sock(sk); @@ -3446,6 +3544,7 @@ SCTP_STATIC int sctp_init_sock(struct sock *sk) sp->pathmaxrxt = sctp_max_retrans_path; sp->pathmtu = 0; // allow default discovery sp->sackdelay = sctp_sack_timeout; + sp->sackfreq = 2; sp->param_flags = SPP_HB_ENABLE | SPP_PMTUD_ENABLE | SPP_SACKDELAY_ENABLE; @@ -3497,7 +3596,7 @@ SCTP_STATIC int sctp_init_sock(struct sock *sk) } /* Cleanup any SCTP per socket resources. */ -SCTP_STATIC int sctp_destroy_sock(struct sock *sk) +SCTP_STATIC void sctp_destroy_sock(struct sock *sk) { struct sctp_endpoint *ep; @@ -3507,7 +3606,6 @@ SCTP_STATIC int sctp_destroy_sock(struct sock *sk) ep = sctp_sk(sk)->ep; sctp_endpoint_free(ep); atomic_dec(&sctp_sockets_allocated); - return 0; } /* API 4.1.7 shutdown() - TCP Style Syntax @@ -3999,70 +4097,91 @@ static int sctp_getsockopt_peer_addr_params(struct sock *sk, int len, return 0; } -/* 7.1.23. Delayed Ack Timer (SCTP_DELAYED_ACK_TIME) - * - * This options will get or set the delayed ack timer. The time is set - * in milliseconds. If the assoc_id is 0, then this sets or gets the - * endpoints default delayed ack timer value. If the assoc_id field is - * non-zero, then the set or get effects the specified association. - * - * struct sctp_assoc_value { - * sctp_assoc_t assoc_id; - * uint32_t assoc_value; - * }; +/* + * 7.1.23. Get or set delayed ack timer (SCTP_DELAYED_SACK) + * + * This option will effect the way delayed acks are performed. This + * option allows you to get or set the delayed ack time, in + * milliseconds. It also allows changing the delayed ack frequency. + * Changing the frequency to 1 disables the delayed sack algorithm. If + * the assoc_id is 0, then this sets or gets the endpoints default + * values. If the assoc_id field is non-zero, then the set or get + * effects the specified association for the one to many model (the + * assoc_id field is ignored by the one to one model). Note that if + * sack_delay or sack_freq are 0 when setting this option, then the + * current values will remain unchanged. + * + * struct sctp_sack_info { + * sctp_assoc_t sack_assoc_id; + * uint32_t sack_delay; + * uint32_t sack_freq; + * }; * - * assoc_id - This parameter, indicates which association the - * user is preforming an action upon. Note that if - * this field's value is zero then the endpoints - * default value is changed (effecting future - * associations only). + * sack_assoc_id - This parameter, indicates which association the user + * is performing an action upon. Note that if this field's value is + * zero then the endpoints default value is changed (effecting future + * associations only). * - * assoc_value - This parameter contains the number of milliseconds - * that the user is requesting the delayed ACK timer - * be set to. Note that this value is defined in - * the standard to be between 200 and 500 milliseconds. + * sack_delay - This parameter contains the number of milliseconds that + * the user is requesting the delayed ACK timer be set to. Note that + * this value is defined in the standard to be between 200 and 500 + * milliseconds. * - * Note: a value of zero will leave the value alone, - * but disable SACK delay. A non-zero value will also - * enable SACK delay. + * sack_freq - This parameter contains the number of packets that must + * be received before a sack is sent without waiting for the delay + * timer to expire. The default value for this is 2, setting this + * value to 1 will disable the delayed sack algorithm. */ -static int sctp_getsockopt_delayed_ack_time(struct sock *sk, int len, +static int sctp_getsockopt_delayed_ack(struct sock *sk, int len, char __user *optval, int __user *optlen) { - struct sctp_assoc_value params; + struct sctp_sack_info params; struct sctp_association *asoc = NULL; struct sctp_sock *sp = sctp_sk(sk); - if (len < sizeof(struct sctp_assoc_value)) - return - EINVAL; + if (len >= sizeof(struct sctp_sack_info)) { + len = sizeof(struct sctp_sack_info); - len = sizeof(struct sctp_assoc_value); - - if (copy_from_user(¶ms, optval, len)) - return -EFAULT; + if (copy_from_user(¶ms, optval, len)) + return -EFAULT; + } else if (len == sizeof(struct sctp_assoc_value)) { + printk(KERN_WARNING "SCTP: Use of struct sctp_sack_info " + "in delayed_ack socket option deprecated\n"); + printk(KERN_WARNING "SCTP: struct sctp_sack_info instead\n"); + if (copy_from_user(¶ms, optval, len)) + return -EFAULT; + } else + return - EINVAL; - /* Get association, if assoc_id != 0 and the socket is a one + /* Get association, if sack_assoc_id != 0 and the socket is a one * to many style socket, and an association was not found, then * the id was invalid. */ - asoc = sctp_id2assoc(sk, params.assoc_id); - if (!asoc && params.assoc_id && sctp_style(sk, UDP)) + asoc = sctp_id2assoc(sk, params.sack_assoc_id); + if (!asoc && params.sack_assoc_id && sctp_style(sk, UDP)) return -EINVAL; if (asoc) { /* Fetch association values. */ - if (asoc->param_flags & SPP_SACKDELAY_ENABLE) - params.assoc_value = jiffies_to_msecs( + if (asoc->param_flags & SPP_SACKDELAY_ENABLE) { + params.sack_delay = jiffies_to_msecs( asoc->sackdelay); - else - params.assoc_value = 0; + params.sack_freq = asoc->sackfreq; + + } else { + params.sack_delay = 0; + params.sack_freq = 1; + } } else { /* Fetch socket values. */ - if (sp->param_flags & SPP_SACKDELAY_ENABLE) - params.assoc_value = sp->sackdelay; - else - params.assoc_value = 0; + if (sp->param_flags & SPP_SACKDELAY_ENABLE) { + params.sack_delay = sp->sackdelay; + params.sack_freq = sp->sackfreq; + } else { + params.sack_delay = 0; + params.sack_freq = 1; + } } if (copy_to_user(optval, ¶ms, len)) @@ -4112,6 +4231,8 @@ static int sctp_getsockopt_peer_addrs_num_old(struct sock *sk, int len, if (copy_from_user(&id, optval, sizeof(sctp_assoc_t))) return -EFAULT; + printk(KERN_WARNING "SCTP: Use of SCTP_GET_PEER_ADDRS_NUM_OLD " + "socket option deprecated\n"); /* For UDP-style sockets, id specifies the association to query. */ asoc = sctp_id2assoc(sk, id); if (!asoc) @@ -4151,6 +4272,9 @@ static int sctp_getsockopt_peer_addrs_old(struct sock *sk, int len, if (getaddrs.addr_num <= 0) return -EINVAL; + printk(KERN_WARNING "SCTP: Use of SCTP_GET_PEER_ADDRS_OLD " + "socket option deprecated\n"); + /* For UDP-style sockets, id specifies the association to query. */ asoc = sctp_id2assoc(sk, getaddrs.assoc_id); if (!asoc) @@ -4244,6 +4368,9 @@ static int sctp_getsockopt_local_addrs_num_old(struct sock *sk, int len, if (copy_from_user(&id, optval, sizeof(sctp_assoc_t))) return -EFAULT; + printk(KERN_WARNING "SCTP: Use of SCTP_GET_LOCAL_ADDRS_NUM_OLD " + "socket option deprecated\n"); + /* * For UDP-style sockets, id specifies the association to query. * If the id field is set to the value '0' then the locally bound @@ -4276,6 +4403,11 @@ static int sctp_getsockopt_local_addrs_num_old(struct sock *sk, int len, (AF_INET6 == addr->a.sa.sa_family)) continue; + if ((PF_INET6 == sk->sk_family) && + inet_v6_ipv6only(sk) && + (AF_INET == addr->a.sa.sa_family)) + continue; + cnt++; } rcu_read_unlock(); @@ -4316,6 +4448,10 @@ static int sctp_copy_laddrs_old(struct sock *sk, __u16 port, if ((PF_INET == sk->sk_family) && (AF_INET6 == addr->a.sa.sa_family)) continue; + if ((PF_INET6 == sk->sk_family) && + inet_v6_ipv6only(sk) && + (AF_INET == addr->a.sa.sa_family)) + continue; memcpy(&temp, &addr->a, sizeof(temp)); if (!temp.v4.sin_port) temp.v4.sin_port = htons(port); @@ -4351,6 +4487,10 @@ static int sctp_copy_laddrs(struct sock *sk, __u16 port, void *to, if ((PF_INET == sk->sk_family) && (AF_INET6 == addr->a.sa.sa_family)) continue; + if ((PF_INET6 == sk->sk_family) && + inet_v6_ipv6only(sk) && + (AF_INET == addr->a.sa.sa_family)) + continue; memcpy(&temp, &addr->a, sizeof(temp)); if (!temp.v4.sin_port) temp.v4.sin_port = htons(port); @@ -4404,6 +4544,10 @@ static int sctp_getsockopt_local_addrs_old(struct sock *sk, int len, if (getaddrs.addr_num <= 0 || getaddrs.addr_num >= (INT_MAX / sizeof(union sctp_addr))) return -EINVAL; + + printk(KERN_WARNING "SCTP: Use of SCTP_GET_LOCAL_ADDRS_OLD " + "socket option deprecated\n"); + /* * For UDP-style sockets, id specifies the association to query. * If the id field is set to the value '0' then the locally bound @@ -5220,8 +5364,8 @@ SCTP_STATIC int sctp_getsockopt(struct sock *sk, int level, int optname, retval = sctp_getsockopt_peer_addr_params(sk, len, optval, optlen); break; - case SCTP_DELAYED_ACK_TIME: - retval = sctp_getsockopt_delayed_ack_time(sk, len, optval, + case SCTP_DELAYED_ACK: + retval = sctp_getsockopt_delayed_ack(sk, len, optval, optlen); break; case SCTP_INITMSG: @@ -5441,12 +5585,13 @@ pp_found: struct sctp_endpoint *ep2; ep2 = sctp_sk(sk2)->ep; - if (reuse && sk2->sk_reuse && - sk2->sk_state != SCTP_SS_LISTENING) + if (sk == sk2 || + (reuse && sk2->sk_reuse && + sk2->sk_state != SCTP_SS_LISTENING)) continue; - if (sctp_bind_addr_match(&ep2->base.bind_addr, addr, - sctp_sk(sk))) { + if (sctp_bind_addr_conflict(&ep2->base.bind_addr, addr, + sctp_sk(sk2), sctp_sk(sk))) { ret = (long)sk2; goto fail_unlock; } @@ -5559,8 +5704,13 @@ SCTP_STATIC int sctp_seqpacket_listen(struct sock *sk, int backlog) if (!ep->base.bind_addr.port) { if (sctp_autobind(sk)) return -EAGAIN; - } else + } else { + if (sctp_get_port(sk, inet_sk(sk)->num)) { + sk->sk_state = SCTP_SS_CLOSED; + return -EADDRINUSE; + } sctp_sk(sk)->bind_hash->fastreuse = 0; + } sctp_hash_endpoint(ep); return 0; @@ -5630,7 +5780,7 @@ int sctp_inet_listen(struct socket *sock, int backlog) goto out; /* Allocate HMAC for generating cookie. */ - if (sctp_hmac_alg) { + if (!sctp_sk(sk)->hmac && sctp_hmac_alg) { tfm = crypto_alloc_hash(sctp_hmac_alg, 0, CRYPTO_ALG_ASYNC); if (IS_ERR(tfm)) { if (net_ratelimit()) { @@ -5658,7 +5808,8 @@ int sctp_inet_listen(struct socket *sock, int backlog) goto cleanup; /* Store away the transform reference. */ - sctp_sk(sk)->hmac = tfm; + if (!sctp_sk(sk)->hmac) + sctp_sk(sk)->hmac = tfm; out: sctp_release_sock(sk); return err; diff --git a/net/sctp/transport.c b/net/sctp/transport.c index 3f34f61221ec..e745c118f239 100644 --- a/net/sctp/transport.c +++ b/net/sctp/transport.c @@ -100,6 +100,9 @@ static struct sctp_transport *sctp_transport_init(struct sctp_transport *peer, INIT_LIST_HEAD(&peer->send_ready); INIT_LIST_HEAD(&peer->transports); + peer->T3_rtx_timer.expires = 0; + peer->hb_timer.expires = 0; + setup_timer(&peer->T3_rtx_timer, sctp_generate_t3_rtx_event, (unsigned long)peer); setup_timer(&peer->hb_timer, sctp_generate_heartbeat_event, diff --git a/net/socket.c b/net/socket.c index 66c4a8cf6db9..1ba57d888981 100644 --- a/net/socket.c +++ b/net/socket.c @@ -90,6 +90,7 @@ #include <asm/unistd.h> #include <net/compat.h> +#include <net/wext.h> #include <net/sock.h> #include <linux/netfilter.h> @@ -179,9 +180,9 @@ static DEFINE_PER_CPU(int, sockets_in_use) = 0; * invalid addresses -EFAULT is returned. On a success 0 is returned. */ -int move_addr_to_kernel(void __user *uaddr, int ulen, void *kaddr) +int move_addr_to_kernel(void __user *uaddr, int ulen, struct sockaddr *kaddr) { - if (ulen < 0 || ulen > MAX_SOCK_ADDR) + if (ulen < 0 || ulen > sizeof(struct sockaddr_storage)) return -EINVAL; if (ulen == 0) return 0; @@ -207,7 +208,7 @@ int move_addr_to_kernel(void __user *uaddr, int ulen, void *kaddr) * specified. Zero is returned for a success. */ -int move_addr_to_user(void *kaddr, int klen, void __user *uaddr, +int move_addr_to_user(struct sockaddr *kaddr, int klen, void __user *uaddr, int __user *ulen) { int err; @@ -218,7 +219,7 @@ int move_addr_to_user(void *kaddr, int klen, void __user *uaddr, return err; if (len > klen) len = klen; - if (len < 0 || len > MAX_SOCK_ADDR) + if (len < 0 || len > sizeof(struct sockaddr_storage)) return -EINVAL; if (len) { if (audit_sockaddr(klen, kaddr)) @@ -1341,20 +1342,20 @@ out_fd: asmlinkage long sys_bind(int fd, struct sockaddr __user *umyaddr, int addrlen) { struct socket *sock; - char address[MAX_SOCK_ADDR]; + struct sockaddr_storage address; int err, fput_needed; sock = sockfd_lookup_light(fd, &err, &fput_needed); if (sock) { - err = move_addr_to_kernel(umyaddr, addrlen, address); + err = move_addr_to_kernel(umyaddr, addrlen, (struct sockaddr *)&address); if (err >= 0) { err = security_socket_bind(sock, - (struct sockaddr *)address, + (struct sockaddr *)&address, addrlen); if (!err) err = sock->ops->bind(sock, (struct sockaddr *) - address, addrlen); + &address, addrlen); } fput_light(sock->file, fput_needed); } @@ -1406,7 +1407,7 @@ asmlinkage long sys_accept(int fd, struct sockaddr __user *upeer_sockaddr, struct socket *sock, *newsock; struct file *newfile; int err, len, newfd, fput_needed; - char address[MAX_SOCK_ADDR]; + struct sockaddr_storage address; sock = sockfd_lookup_light(fd, &err, &fput_needed); if (!sock) @@ -1445,13 +1446,13 @@ asmlinkage long sys_accept(int fd, struct sockaddr __user *upeer_sockaddr, goto out_fd; if (upeer_sockaddr) { - if (newsock->ops->getname(newsock, (struct sockaddr *)address, + if (newsock->ops->getname(newsock, (struct sockaddr *)&address, &len, 2) < 0) { err = -ECONNABORTED; goto out_fd; } - err = move_addr_to_user(address, len, upeer_sockaddr, - upeer_addrlen); + err = move_addr_to_user((struct sockaddr *)&address, + len, upeer_sockaddr, upeer_addrlen); if (err < 0) goto out_fd; } @@ -1494,22 +1495,22 @@ asmlinkage long sys_connect(int fd, struct sockaddr __user *uservaddr, int addrlen) { struct socket *sock; - char address[MAX_SOCK_ADDR]; + struct sockaddr_storage address; int err, fput_needed; sock = sockfd_lookup_light(fd, &err, &fput_needed); if (!sock) goto out; - err = move_addr_to_kernel(uservaddr, addrlen, address); + err = move_addr_to_kernel(uservaddr, addrlen, (struct sockaddr *)&address); if (err < 0) goto out_put; err = - security_socket_connect(sock, (struct sockaddr *)address, addrlen); + security_socket_connect(sock, (struct sockaddr *)&address, addrlen); if (err) goto out_put; - err = sock->ops->connect(sock, (struct sockaddr *)address, addrlen, + err = sock->ops->connect(sock, (struct sockaddr *)&address, addrlen, sock->file->f_flags); out_put: fput_light(sock->file, fput_needed); @@ -1526,7 +1527,7 @@ asmlinkage long sys_getsockname(int fd, struct sockaddr __user *usockaddr, int __user *usockaddr_len) { struct socket *sock; - char address[MAX_SOCK_ADDR]; + struct sockaddr_storage address; int len, err, fput_needed; sock = sockfd_lookup_light(fd, &err, &fput_needed); @@ -1537,10 +1538,10 @@ asmlinkage long sys_getsockname(int fd, struct sockaddr __user *usockaddr, if (err) goto out_put; - err = sock->ops->getname(sock, (struct sockaddr *)address, &len, 0); + err = sock->ops->getname(sock, (struct sockaddr *)&address, &len, 0); if (err) goto out_put; - err = move_addr_to_user(address, len, usockaddr, usockaddr_len); + err = move_addr_to_user((struct sockaddr *)&address, len, usockaddr, usockaddr_len); out_put: fput_light(sock->file, fput_needed); @@ -1557,7 +1558,7 @@ asmlinkage long sys_getpeername(int fd, struct sockaddr __user *usockaddr, int __user *usockaddr_len) { struct socket *sock; - char address[MAX_SOCK_ADDR]; + struct sockaddr_storage address; int len, err, fput_needed; sock = sockfd_lookup_light(fd, &err, &fput_needed); @@ -1569,10 +1570,10 @@ asmlinkage long sys_getpeername(int fd, struct sockaddr __user *usockaddr, } err = - sock->ops->getname(sock, (struct sockaddr *)address, &len, + sock->ops->getname(sock, (struct sockaddr *)&address, &len, 1); if (!err) - err = move_addr_to_user(address, len, usockaddr, + err = move_addr_to_user((struct sockaddr *)&address, len, usockaddr, usockaddr_len); fput_light(sock->file, fput_needed); } @@ -1590,7 +1591,7 @@ asmlinkage long sys_sendto(int fd, void __user *buff, size_t len, int addr_len) { struct socket *sock; - char address[MAX_SOCK_ADDR]; + struct sockaddr_storage address; int err; struct msghdr msg; struct iovec iov; @@ -1609,10 +1610,10 @@ asmlinkage long sys_sendto(int fd, void __user *buff, size_t len, msg.msg_controllen = 0; msg.msg_namelen = 0; if (addr) { - err = move_addr_to_kernel(addr, addr_len, address); + err = move_addr_to_kernel(addr, addr_len, (struct sockaddr *)&address); if (err < 0) goto out_put; - msg.msg_name = address; + msg.msg_name = (struct sockaddr *)&address; msg.msg_namelen = addr_len; } if (sock->file->f_flags & O_NONBLOCK) @@ -1648,7 +1649,7 @@ asmlinkage long sys_recvfrom(int fd, void __user *ubuf, size_t size, struct socket *sock; struct iovec iov; struct msghdr msg; - char address[MAX_SOCK_ADDR]; + struct sockaddr_storage address; int err, err2; int fput_needed; @@ -1662,14 +1663,15 @@ asmlinkage long sys_recvfrom(int fd, void __user *ubuf, size_t size, msg.msg_iov = &iov; iov.iov_len = size; iov.iov_base = ubuf; - msg.msg_name = address; - msg.msg_namelen = MAX_SOCK_ADDR; + msg.msg_name = (struct sockaddr *)&address; + msg.msg_namelen = sizeof(address); if (sock->file->f_flags & O_NONBLOCK) flags |= MSG_DONTWAIT; err = sock_recvmsg(sock, &msg, size, flags); if (err >= 0 && addr != NULL) { - err2 = move_addr_to_user(address, msg.msg_namelen, addr, addr_len); + err2 = move_addr_to_user((struct sockaddr *)&address, + msg.msg_namelen, addr, addr_len); if (err2 < 0) err = err2; } @@ -1789,7 +1791,7 @@ asmlinkage long sys_sendmsg(int fd, struct msghdr __user *msg, unsigned flags) struct compat_msghdr __user *msg_compat = (struct compat_msghdr __user *)msg; struct socket *sock; - char address[MAX_SOCK_ADDR]; + struct sockaddr_storage address; struct iovec iovstack[UIO_FASTIOV], *iov = iovstack; unsigned char ctl[sizeof(struct cmsghdr) + 20] __attribute__ ((aligned(sizeof(__kernel_size_t)))); @@ -1827,9 +1829,13 @@ asmlinkage long sys_sendmsg(int fd, struct msghdr __user *msg, unsigned flags) /* This will also move the address data into kernel space */ if (MSG_CMSG_COMPAT & flags) { - err = verify_compat_iovec(&msg_sys, iov, address, VERIFY_READ); + err = verify_compat_iovec(&msg_sys, iov, + (struct sockaddr *)&address, + VERIFY_READ); } else - err = verify_iovec(&msg_sys, iov, address, VERIFY_READ); + err = verify_iovec(&msg_sys, iov, + (struct sockaddr *)&address, + VERIFY_READ); if (err < 0) goto out_freeiov; total_len = err; @@ -1900,7 +1906,7 @@ asmlinkage long sys_recvmsg(int fd, struct msghdr __user *msg, int fput_needed; /* kernel mode address */ - char addr[MAX_SOCK_ADDR]; + struct sockaddr_storage addr; /* user mode address pointers */ struct sockaddr __user *uaddr; @@ -1938,9 +1944,13 @@ asmlinkage long sys_recvmsg(int fd, struct msghdr __user *msg, uaddr = (__force void __user *)msg_sys.msg_name; uaddr_len = COMPAT_NAMELEN(msg); if (MSG_CMSG_COMPAT & flags) { - err = verify_compat_iovec(&msg_sys, iov, addr, VERIFY_WRITE); + err = verify_compat_iovec(&msg_sys, iov, + (struct sockaddr *)&addr, + VERIFY_WRITE); } else - err = verify_iovec(&msg_sys, iov, addr, VERIFY_WRITE); + err = verify_iovec(&msg_sys, iov, + (struct sockaddr *)&addr, + VERIFY_WRITE); if (err < 0) goto out_freeiov; total_len = err; @@ -1956,7 +1966,8 @@ asmlinkage long sys_recvmsg(int fd, struct msghdr __user *msg, len = err; if (uaddr != NULL) { - err = move_addr_to_user(addr, msg_sys.msg_namelen, uaddr, + err = move_addr_to_user((struct sockaddr *)&addr, + msg_sys.msg_namelen, uaddr, uaddr_len); if (err < 0) goto out_freeiov; @@ -2210,10 +2221,19 @@ static long compat_sock_ioctl(struct file *file, unsigned cmd, { struct socket *sock = file->private_data; int ret = -ENOIOCTLCMD; + struct sock *sk; + struct net *net; + + sk = sock->sk; + net = sock_net(sk); if (sock->ops->compat_ioctl) ret = sock->ops->compat_ioctl(sock, cmd, arg); + if (ret == -ENOIOCTLCMD && + (cmd >= SIOCIWFIRST && cmd <= SIOCIWLAST)) + ret = compat_wext_handle_ioctl(net, cmd, arg); + return ret; } #endif diff --git a/net/sunrpc/auth_gss/Makefile b/net/sunrpc/auth_gss/Makefile index f3431a7e33da..4de8bcf26fa7 100644 --- a/net/sunrpc/auth_gss/Makefile +++ b/net/sunrpc/auth_gss/Makefile @@ -5,12 +5,12 @@ obj-$(CONFIG_SUNRPC_GSS) += auth_rpcgss.o auth_rpcgss-objs := auth_gss.o gss_generic_token.o \ - gss_mech_switch.o svcauth_gss.o gss_krb5_crypto.o + gss_mech_switch.o svcauth_gss.o obj-$(CONFIG_RPCSEC_GSS_KRB5) += rpcsec_gss_krb5.o rpcsec_gss_krb5-objs := gss_krb5_mech.o gss_krb5_seal.o gss_krb5_unseal.o \ - gss_krb5_seqnum.o gss_krb5_wrap.o + gss_krb5_seqnum.o gss_krb5_wrap.o gss_krb5_crypto.o obj-$(CONFIG_RPCSEC_GSS_SPKM3) += rpcsec_gss_spkm3.o diff --git a/net/sunrpc/auth_gss/auth_gss.c b/net/sunrpc/auth_gss/auth_gss.c index 834a83199bdf..853a4142cea1 100644 --- a/net/sunrpc/auth_gss/auth_gss.c +++ b/net/sunrpc/auth_gss/auth_gss.c @@ -33,8 +33,6 @@ * 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. - * - * $Id$ */ diff --git a/net/sunrpc/auth_gss/gss_krb5_crypto.c b/net/sunrpc/auth_gss/gss_krb5_crypto.c index 1d52308ca324..c93fca204558 100644 --- a/net/sunrpc/auth_gss/gss_krb5_crypto.c +++ b/net/sunrpc/auth_gss/gss_krb5_crypto.c @@ -83,8 +83,6 @@ out: return ret; } -EXPORT_SYMBOL(krb5_encrypt); - u32 krb5_decrypt( struct crypto_blkcipher *tfm, @@ -118,8 +116,6 @@ out: return ret; } -EXPORT_SYMBOL(krb5_decrypt); - static int checksummer(struct scatterlist *sg, void *data) { @@ -161,8 +157,6 @@ out: return err ? GSS_S_FAILURE : 0; } -EXPORT_SYMBOL(make_checksum); - struct encryptor_desc { u8 iv[8]; /* XXX hard-coded blocksize */ struct blkcipher_desc desc; @@ -262,8 +256,6 @@ gss_encrypt_xdr_buf(struct crypto_blkcipher *tfm, struct xdr_buf *buf, return ret; } -EXPORT_SYMBOL(gss_encrypt_xdr_buf); - struct decryptor_desc { u8 iv[8]; /* XXX hard-coded blocksize */ struct blkcipher_desc desc; @@ -334,5 +326,3 @@ gss_decrypt_xdr_buf(struct crypto_blkcipher *tfm, struct xdr_buf *buf, return xdr_process_buf(buf, offset, buf->len - offset, decryptor, &desc); } - -EXPORT_SYMBOL(gss_decrypt_xdr_buf); diff --git a/net/sunrpc/auth_gss/gss_krb5_seal.c b/net/sunrpc/auth_gss/gss_krb5_seal.c index 5f1d36dfbcf7..b8f42ef7178e 100644 --- a/net/sunrpc/auth_gss/gss_krb5_seal.c +++ b/net/sunrpc/auth_gss/gss_krb5_seal.c @@ -78,7 +78,7 @@ gss_get_mic_kerberos(struct gss_ctx *gss_ctx, struct xdr_buf *text, struct krb5_ctx *ctx = gss_ctx->internal_ctx_id; char cksumdata[16]; struct xdr_netobj md5cksum = {.len = 0, .data = cksumdata}; - unsigned char *ptr, *krb5_hdr, *msg_start; + unsigned char *ptr, *msg_start; s32 now; u32 seq_send; @@ -87,36 +87,36 @@ gss_get_mic_kerberos(struct gss_ctx *gss_ctx, struct xdr_buf *text, now = get_seconds(); - token->len = g_token_size(&ctx->mech_used, 24); + token->len = g_token_size(&ctx->mech_used, GSS_KRB5_TOK_HDR_LEN + 8); ptr = token->data; - g_make_token_header(&ctx->mech_used, 24, &ptr); + g_make_token_header(&ctx->mech_used, GSS_KRB5_TOK_HDR_LEN + 8, &ptr); - *ptr++ = (unsigned char) ((KG_TOK_MIC_MSG>>8)&0xff); - *ptr++ = (unsigned char) (KG_TOK_MIC_MSG&0xff); + /* ptr now at header described in rfc 1964, section 1.2.1: */ + ptr[0] = (unsigned char) ((KG_TOK_MIC_MSG >> 8) & 0xff); + ptr[1] = (unsigned char) (KG_TOK_MIC_MSG & 0xff); - /* ptr now at byte 2 of header described in rfc 1964, section 1.2.1: */ - krb5_hdr = ptr - 2; - msg_start = krb5_hdr + 24; + msg_start = ptr + GSS_KRB5_TOK_HDR_LEN + 8; - *(__be16 *)(krb5_hdr + 2) = htons(SGN_ALG_DES_MAC_MD5); - memset(krb5_hdr + 4, 0xff, 4); + *(__be16 *)(ptr + 2) = htons(SGN_ALG_DES_MAC_MD5); + memset(ptr + 4, 0xff, 4); - if (make_checksum("md5", krb5_hdr, 8, text, 0, &md5cksum)) + if (make_checksum("md5", ptr, 8, text, 0, &md5cksum)) return GSS_S_FAILURE; if (krb5_encrypt(ctx->seq, NULL, md5cksum.data, md5cksum.data, md5cksum.len)) return GSS_S_FAILURE; - memcpy(krb5_hdr + 16, md5cksum.data + md5cksum.len - 8, 8); + memcpy(ptr + GSS_KRB5_TOK_HDR_LEN, md5cksum.data + md5cksum.len - 8, 8); spin_lock(&krb5_seq_lock); seq_send = ctx->seq_send++; spin_unlock(&krb5_seq_lock); if (krb5_make_seq_num(ctx->seq, ctx->initiate ? 0 : 0xff, - seq_send, krb5_hdr + 16, krb5_hdr + 8)) + seq_send, ptr + GSS_KRB5_TOK_HDR_LEN, + ptr + 8)) return GSS_S_FAILURE; return (ctx->endtime < now) ? GSS_S_CONTEXT_EXPIRED : GSS_S_COMPLETE; diff --git a/net/sunrpc/auth_gss/gss_krb5_unseal.c b/net/sunrpc/auth_gss/gss_krb5_unseal.c index d91a5d004803..066ec73c84d6 100644 --- a/net/sunrpc/auth_gss/gss_krb5_unseal.c +++ b/net/sunrpc/auth_gss/gss_krb5_unseal.c @@ -92,30 +92,30 @@ gss_verify_mic_kerberos(struct gss_ctx *gss_ctx, read_token->len)) return GSS_S_DEFECTIVE_TOKEN; - if ((*ptr++ != ((KG_TOK_MIC_MSG>>8)&0xff)) || - (*ptr++ != ( KG_TOK_MIC_MSG &0xff)) ) + if ((ptr[0] != ((KG_TOK_MIC_MSG >> 8) & 0xff)) || + (ptr[1] != (KG_TOK_MIC_MSG & 0xff))) return GSS_S_DEFECTIVE_TOKEN; /* XXX sanity-check bodysize?? */ - signalg = ptr[0] + (ptr[1] << 8); + signalg = ptr[2] + (ptr[3] << 8); if (signalg != SGN_ALG_DES_MAC_MD5) return GSS_S_DEFECTIVE_TOKEN; - sealalg = ptr[2] + (ptr[3] << 8); + sealalg = ptr[4] + (ptr[5] << 8); if (sealalg != SEAL_ALG_NONE) return GSS_S_DEFECTIVE_TOKEN; - if ((ptr[4] != 0xff) || (ptr[5] != 0xff)) + if ((ptr[6] != 0xff) || (ptr[7] != 0xff)) return GSS_S_DEFECTIVE_TOKEN; - if (make_checksum("md5", ptr - 2, 8, message_buffer, 0, &md5cksum)) + if (make_checksum("md5", ptr, 8, message_buffer, 0, &md5cksum)) return GSS_S_FAILURE; if (krb5_encrypt(ctx->seq, NULL, md5cksum.data, md5cksum.data, 16)) return GSS_S_FAILURE; - if (memcmp(md5cksum.data + 8, ptr + 14, 8)) + if (memcmp(md5cksum.data + 8, ptr + GSS_KRB5_TOK_HDR_LEN, 8)) return GSS_S_BAD_SIG; /* it got through unscathed. Make sure the context is unexpired */ @@ -127,7 +127,7 @@ gss_verify_mic_kerberos(struct gss_ctx *gss_ctx, /* do sequencing checks */ - if (krb5_get_seq_num(ctx->seq, ptr + 14, ptr + 6, &direction, &seqnum)) + if (krb5_get_seq_num(ctx->seq, ptr + GSS_KRB5_TOK_HDR_LEN, ptr + 8, &direction, &seqnum)) return GSS_S_FAILURE; if ((ctx->initiate && direction != 0xff) || diff --git a/net/sunrpc/auth_gss/gss_krb5_wrap.c b/net/sunrpc/auth_gss/gss_krb5_wrap.c index b00b1b426301..ae8e69b59c4c 100644 --- a/net/sunrpc/auth_gss/gss_krb5_wrap.c +++ b/net/sunrpc/auth_gss/gss_krb5_wrap.c @@ -87,8 +87,8 @@ out: return 0; } -static inline void -make_confounder(char *p, int blocksize) +static void +make_confounder(char *p, u32 conflen) { static u64 i = 0; u64 *q = (u64 *)p; @@ -102,8 +102,22 @@ make_confounder(char *p, int blocksize) * uniqueness would mean worrying about atomicity and rollover, and I * don't care enough. */ - BUG_ON(blocksize != 8); - *q = i++; + /* initialize to random value */ + if (i == 0) { + i = random32(); + i = (i << 32) | random32(); + } + + switch (conflen) { + case 16: + *q++ = i++; + /* fall through */ + case 8: + *q++ = i++; + break; + default: + BUG(); + } } /* Assumptions: the head and tail of inbuf are ours to play with. @@ -122,7 +136,7 @@ gss_wrap_kerberos(struct gss_ctx *ctx, int offset, char cksumdata[16]; struct xdr_netobj md5cksum = {.len = 0, .data = cksumdata}; int blocksize = 0, plainlen; - unsigned char *ptr, *krb5_hdr, *msg_start; + unsigned char *ptr, *msg_start; s32 now; int headlen; struct page **tmp_pages; @@ -149,26 +163,26 @@ gss_wrap_kerberos(struct gss_ctx *ctx, int offset, buf->len += headlen; BUG_ON((buf->len - offset - headlen) % blocksize); - g_make_token_header(&kctx->mech_used, 24 + plainlen, &ptr); + g_make_token_header(&kctx->mech_used, + GSS_KRB5_TOK_HDR_LEN + 8 + plainlen, &ptr); - *ptr++ = (unsigned char) ((KG_TOK_WRAP_MSG>>8)&0xff); - *ptr++ = (unsigned char) (KG_TOK_WRAP_MSG&0xff); + /* ptr now at header described in rfc 1964, section 1.2.1: */ + ptr[0] = (unsigned char) ((KG_TOK_WRAP_MSG >> 8) & 0xff); + ptr[1] = (unsigned char) (KG_TOK_WRAP_MSG & 0xff); - /* ptr now at byte 2 of header described in rfc 1964, section 1.2.1: */ - krb5_hdr = ptr - 2; - msg_start = krb5_hdr + 24; + msg_start = ptr + 24; - *(__be16 *)(krb5_hdr + 2) = htons(SGN_ALG_DES_MAC_MD5); - memset(krb5_hdr + 4, 0xff, 4); - *(__be16 *)(krb5_hdr + 4) = htons(SEAL_ALG_DES); + *(__be16 *)(ptr + 2) = htons(SGN_ALG_DES_MAC_MD5); + memset(ptr + 4, 0xff, 4); + *(__be16 *)(ptr + 4) = htons(SEAL_ALG_DES); make_confounder(msg_start, blocksize); /* XXXJBF: UGH!: */ tmp_pages = buf->pages; buf->pages = pages; - if (make_checksum("md5", krb5_hdr, 8, buf, + if (make_checksum("md5", ptr, 8, buf, offset + headlen - blocksize, &md5cksum)) return GSS_S_FAILURE; buf->pages = tmp_pages; @@ -176,7 +190,7 @@ gss_wrap_kerberos(struct gss_ctx *ctx, int offset, if (krb5_encrypt(kctx->seq, NULL, md5cksum.data, md5cksum.data, md5cksum.len)) return GSS_S_FAILURE; - memcpy(krb5_hdr + 16, md5cksum.data + md5cksum.len - 8, 8); + memcpy(ptr + GSS_KRB5_TOK_HDR_LEN, md5cksum.data + md5cksum.len - 8, 8); spin_lock(&krb5_seq_lock); seq_send = kctx->seq_send++; @@ -185,7 +199,7 @@ gss_wrap_kerberos(struct gss_ctx *ctx, int offset, /* XXX would probably be more efficient to compute checksum * and encrypt at the same time: */ if ((krb5_make_seq_num(kctx->seq, kctx->initiate ? 0 : 0xff, - seq_send, krb5_hdr + 16, krb5_hdr + 8))) + seq_send, ptr + GSS_KRB5_TOK_HDR_LEN, ptr + 8))) return GSS_S_FAILURE; if (gss_encrypt_xdr_buf(kctx->enc, buf, offset + headlen - blocksize, @@ -219,38 +233,38 @@ gss_unwrap_kerberos(struct gss_ctx *ctx, int offset, struct xdr_buf *buf) buf->len - offset)) return GSS_S_DEFECTIVE_TOKEN; - if ((*ptr++ != ((KG_TOK_WRAP_MSG>>8)&0xff)) || - (*ptr++ != (KG_TOK_WRAP_MSG &0xff)) ) + if ((ptr[0] != ((KG_TOK_WRAP_MSG >> 8) & 0xff)) || + (ptr[1] != (KG_TOK_WRAP_MSG & 0xff))) return GSS_S_DEFECTIVE_TOKEN; /* XXX sanity-check bodysize?? */ /* get the sign and seal algorithms */ - signalg = ptr[0] + (ptr[1] << 8); + signalg = ptr[2] + (ptr[3] << 8); if (signalg != SGN_ALG_DES_MAC_MD5) return GSS_S_DEFECTIVE_TOKEN; - sealalg = ptr[2] + (ptr[3] << 8); + sealalg = ptr[4] + (ptr[5] << 8); if (sealalg != SEAL_ALG_DES) return GSS_S_DEFECTIVE_TOKEN; - if ((ptr[4] != 0xff) || (ptr[5] != 0xff)) + if ((ptr[6] != 0xff) || (ptr[7] != 0xff)) return GSS_S_DEFECTIVE_TOKEN; if (gss_decrypt_xdr_buf(kctx->enc, buf, - ptr + 22 - (unsigned char *)buf->head[0].iov_base)) + ptr + GSS_KRB5_TOK_HDR_LEN + 8 - (unsigned char *)buf->head[0].iov_base)) return GSS_S_DEFECTIVE_TOKEN; - if (make_checksum("md5", ptr - 2, 8, buf, - ptr + 22 - (unsigned char *)buf->head[0].iov_base, &md5cksum)) + if (make_checksum("md5", ptr, 8, buf, + ptr + GSS_KRB5_TOK_HDR_LEN + 8 - (unsigned char *)buf->head[0].iov_base, &md5cksum)) return GSS_S_FAILURE; if (krb5_encrypt(kctx->seq, NULL, md5cksum.data, md5cksum.data, md5cksum.len)) return GSS_S_FAILURE; - if (memcmp(md5cksum.data + 8, ptr + 14, 8)) + if (memcmp(md5cksum.data + 8, ptr + GSS_KRB5_TOK_HDR_LEN, 8)) return GSS_S_BAD_SIG; /* it got through unscathed. Make sure the context is unexpired */ @@ -262,8 +276,8 @@ gss_unwrap_kerberos(struct gss_ctx *ctx, int offset, struct xdr_buf *buf) /* do sequencing checks */ - if (krb5_get_seq_num(kctx->seq, ptr + 14, ptr + 6, &direction, - &seqnum)) + if (krb5_get_seq_num(kctx->seq, ptr + GSS_KRB5_TOK_HDR_LEN, ptr + 8, + &direction, &seqnum)) return GSS_S_BAD_SIG; if ((kctx->initiate && direction != 0xff) || @@ -274,7 +288,7 @@ gss_unwrap_kerberos(struct gss_ctx *ctx, int offset, struct xdr_buf *buf) * better to copy and encrypt at the same time. */ blocksize = crypto_blkcipher_blocksize(kctx->enc); - data_start = ptr + 22 + blocksize; + data_start = ptr + GSS_KRB5_TOK_HDR_LEN + 8 + blocksize; orig_start = buf->head[0].iov_base + offset; data_len = (buf->head[0].iov_base + buf->head[0].iov_len) - data_start; memmove(orig_start, data_start, data_len); diff --git a/net/sunrpc/svc.c b/net/sunrpc/svc.c index 01c7e311b904..5a32cb7c4bb4 100644 --- a/net/sunrpc/svc.c +++ b/net/sunrpc/svc.c @@ -18,6 +18,7 @@ #include <linux/mm.h> #include <linux/interrupt.h> #include <linux/module.h> +#include <linux/kthread.h> #include <linux/sunrpc/types.h> #include <linux/sunrpc/xdr.h> @@ -291,15 +292,14 @@ svc_pool_map_put(void) /* - * Set the current thread's cpus_allowed mask so that it + * Set the given thread's cpus_allowed mask so that it * will only run on cpus in the given pool. - * - * Returns 1 and fills in oldmask iff a cpumask was applied. */ -static inline int -svc_pool_map_set_cpumask(unsigned int pidx, cpumask_t *oldmask) +static inline void +svc_pool_map_set_cpumask(struct task_struct *task, unsigned int pidx) { struct svc_pool_map *m = &svc_pool_map; + unsigned int node = m->pool_to[pidx]; /* * The caller checks for sv_nrpools > 1, which @@ -307,26 +307,17 @@ svc_pool_map_set_cpumask(unsigned int pidx, cpumask_t *oldmask) */ BUG_ON(m->count == 0); - switch (m->mode) - { - default: - return 0; + switch (m->mode) { case SVC_POOL_PERCPU: { - unsigned int cpu = m->pool_to[pidx]; - - *oldmask = current->cpus_allowed; - set_cpus_allowed_ptr(current, &cpumask_of_cpu(cpu)); - return 1; + set_cpus_allowed_ptr(task, &cpumask_of_cpu(node)); + break; } case SVC_POOL_PERNODE: { - unsigned int node = m->pool_to[pidx]; node_to_cpumask_ptr(nodecpumask, node); - - *oldmask = current->cpus_allowed; - set_cpus_allowed_ptr(current, nodecpumask); - return 1; + set_cpus_allowed_ptr(task, nodecpumask); + break; } } } @@ -443,7 +434,7 @@ EXPORT_SYMBOL(svc_create); struct svc_serv * svc_create_pooled(struct svc_program *prog, unsigned int bufsize, void (*shutdown)(struct svc_serv *serv), - svc_thread_fn func, int sig, struct module *mod) + svc_thread_fn func, struct module *mod) { struct svc_serv *serv; unsigned int npools = svc_pool_map_get(); @@ -452,7 +443,6 @@ svc_create_pooled(struct svc_program *prog, unsigned int bufsize, if (serv != NULL) { serv->sv_function = func; - serv->sv_kill_signal = sig; serv->sv_module = mod; } @@ -461,7 +451,8 @@ svc_create_pooled(struct svc_program *prog, unsigned int bufsize, EXPORT_SYMBOL(svc_create_pooled); /* - * Destroy an RPC service. Should be called with the BKL held + * Destroy an RPC service. Should be called with appropriate locking to + * protect the sv_nrthreads, sv_permsocks and sv_tempsocks. */ void svc_destroy(struct svc_serv *serv) @@ -578,46 +569,6 @@ out_enomem: EXPORT_SYMBOL(svc_prepare_thread); /* - * Create a thread in the given pool. Caller must hold BKL. - * On a NUMA or SMP machine, with a multi-pool serv, the thread - * will be restricted to run on the cpus belonging to the pool. - */ -static int -__svc_create_thread(svc_thread_fn func, struct svc_serv *serv, - struct svc_pool *pool) -{ - struct svc_rqst *rqstp; - int error = -ENOMEM; - int have_oldmask = 0; - cpumask_t uninitialized_var(oldmask); - - rqstp = svc_prepare_thread(serv, pool); - if (IS_ERR(rqstp)) { - error = PTR_ERR(rqstp); - goto out; - } - - if (serv->sv_nrpools > 1) - have_oldmask = svc_pool_map_set_cpumask(pool->sp_id, &oldmask); - - error = kernel_thread((int (*)(void *)) func, rqstp, 0); - - if (have_oldmask) - set_cpus_allowed(current, oldmask); - - if (error < 0) - goto out_thread; - svc_sock_update_bufs(serv); - error = 0; -out: - return error; - -out_thread: - svc_exit_thread(rqstp); - goto out; -} - -/* * Choose a pool in which to create a new thread, for svc_set_num_threads */ static inline struct svc_pool * @@ -674,7 +625,7 @@ found_pool: * of threads the given number. If `pool' is non-NULL, applies * only to threads in that pool, otherwise round-robins between * all pools. Must be called with a svc_get() reference and - * the BKL held. + * the BKL or another lock to protect access to svc_serv fields. * * Destroying threads relies on the service threads filling in * rqstp->rq_task, which only the nfs ones do. Assumes the serv @@ -686,7 +637,9 @@ found_pool: int svc_set_num_threads(struct svc_serv *serv, struct svc_pool *pool, int nrservs) { - struct task_struct *victim; + struct svc_rqst *rqstp; + struct task_struct *task; + struct svc_pool *chosen_pool; int error = 0; unsigned int state = serv->sv_nrthreads-1; @@ -702,18 +655,34 @@ svc_set_num_threads(struct svc_serv *serv, struct svc_pool *pool, int nrservs) /* create new threads */ while (nrservs > 0) { nrservs--; + chosen_pool = choose_pool(serv, pool, &state); + + rqstp = svc_prepare_thread(serv, chosen_pool); + if (IS_ERR(rqstp)) { + error = PTR_ERR(rqstp); + break; + } + __module_get(serv->sv_module); - error = __svc_create_thread(serv->sv_function, serv, - choose_pool(serv, pool, &state)); - if (error < 0) { + task = kthread_create(serv->sv_function, rqstp, serv->sv_name); + if (IS_ERR(task)) { + error = PTR_ERR(task); module_put(serv->sv_module); + svc_exit_thread(rqstp); break; } + + rqstp->rq_task = task; + if (serv->sv_nrpools > 1) + svc_pool_map_set_cpumask(task, chosen_pool->sp_id); + + svc_sock_update_bufs(serv); + wake_up_process(task); } /* destroy old threads */ while (nrservs < 0 && - (victim = choose_victim(serv, pool, &state)) != NULL) { - send_sig(serv->sv_kill_signal, victim, 1); + (task = choose_victim(serv, pool, &state)) != NULL) { + send_sig(SIGINT, task, 1); nrservs++; } @@ -722,7 +691,8 @@ svc_set_num_threads(struct svc_serv *serv, struct svc_pool *pool, int nrservs) EXPORT_SYMBOL(svc_set_num_threads); /* - * Called from a server thread as it's exiting. Caller must hold BKL. + * Called from a server thread as it's exiting. Caller must hold the BKL or + * the "service mutex", whichever is appropriate for the service. */ void svc_exit_thread(struct svc_rqst *rqstp) diff --git a/net/sunrpc/xprtrdma/svc_rdma.c b/net/sunrpc/xprtrdma/svc_rdma.c index 88c0ca20bb1e..87101177825b 100644 --- a/net/sunrpc/xprtrdma/svc_rdma.c +++ b/net/sunrpc/xprtrdma/svc_rdma.c @@ -69,6 +69,10 @@ atomic_t rdma_stat_rq_prod; atomic_t rdma_stat_sq_poll; atomic_t rdma_stat_sq_prod; +/* Temporary NFS request map and context caches */ +struct kmem_cache *svc_rdma_map_cachep; +struct kmem_cache *svc_rdma_ctxt_cachep; + /* * This function implements reading and resetting an atomic_t stat * variable through read/write to a proc file. Any write to the file @@ -236,11 +240,14 @@ static ctl_table svcrdma_root_table[] = { void svc_rdma_cleanup(void) { dprintk("SVCRDMA Module Removed, deregister RPC RDMA transport\n"); + flush_scheduled_work(); if (svcrdma_table_header) { unregister_sysctl_table(svcrdma_table_header); svcrdma_table_header = NULL; } svc_unreg_xprt_class(&svc_rdma_class); + kmem_cache_destroy(svc_rdma_map_cachep); + kmem_cache_destroy(svc_rdma_ctxt_cachep); } int svc_rdma_init(void) @@ -255,9 +262,37 @@ int svc_rdma_init(void) svcrdma_table_header = register_sysctl_table(svcrdma_root_table); + /* Create the temporary map cache */ + svc_rdma_map_cachep = kmem_cache_create("svc_rdma_map_cache", + sizeof(struct svc_rdma_req_map), + 0, + SLAB_HWCACHE_ALIGN, + NULL); + if (!svc_rdma_map_cachep) { + printk(KERN_INFO "Could not allocate map cache.\n"); + goto err0; + } + + /* Create the temporary context cache */ + svc_rdma_ctxt_cachep = + kmem_cache_create("svc_rdma_ctxt_cache", + sizeof(struct svc_rdma_op_ctxt), + 0, + SLAB_HWCACHE_ALIGN, + NULL); + if (!svc_rdma_ctxt_cachep) { + printk(KERN_INFO "Could not allocate WR ctxt cache.\n"); + goto err1; + } + /* Register RDMA with the SVC transport switch */ svc_reg_xprt_class(&svc_rdma_class); return 0; + err1: + kmem_cache_destroy(svc_rdma_map_cachep); + err0: + unregister_sysctl_table(svcrdma_table_header); + return -ENOMEM; } MODULE_AUTHOR("Tom Tucker <tom@opengridcomputing.com>"); MODULE_DESCRIPTION("SVC RDMA Transport"); diff --git a/net/sunrpc/xprtrdma/svc_rdma_recvfrom.c b/net/sunrpc/xprtrdma/svc_rdma_recvfrom.c index 06ab4841537b..b4b17f44cb29 100644 --- a/net/sunrpc/xprtrdma/svc_rdma_recvfrom.c +++ b/net/sunrpc/xprtrdma/svc_rdma_recvfrom.c @@ -112,11 +112,6 @@ static void rdma_build_arg_xdr(struct svc_rqst *rqstp, rqstp->rq_arg.tail[0].iov_len = 0; } -struct chunk_sge { - int start; /* sge no for this chunk */ - int count; /* sge count for this chunk */ -}; - /* Encode a read-chunk-list as an array of IB SGE * * Assumptions: @@ -134,8 +129,8 @@ static int rdma_rcl_to_sge(struct svcxprt_rdma *xprt, struct svc_rqst *rqstp, struct svc_rdma_op_ctxt *head, struct rpcrdma_msg *rmsgp, - struct ib_sge *sge, - struct chunk_sge *ch_sge_ary, + struct svc_rdma_req_map *rpl_map, + struct svc_rdma_req_map *chl_map, int ch_count, int byte_count) { @@ -156,22 +151,18 @@ static int rdma_rcl_to_sge(struct svcxprt_rdma *xprt, head->arg.head[0] = rqstp->rq_arg.head[0]; head->arg.tail[0] = rqstp->rq_arg.tail[0]; head->arg.pages = &head->pages[head->count]; - head->sge[0].length = head->count; /* save count of hdr pages */ + head->hdr_count = head->count; /* save count of hdr pages */ head->arg.page_base = 0; head->arg.page_len = ch_bytes; head->arg.len = rqstp->rq_arg.len + ch_bytes; head->arg.buflen = rqstp->rq_arg.buflen + ch_bytes; head->count++; - ch_sge_ary[0].start = 0; + chl_map->ch[0].start = 0; while (byte_count) { + rpl_map->sge[sge_no].iov_base = + page_address(rqstp->rq_arg.pages[page_no]) + page_off; sge_bytes = min_t(int, PAGE_SIZE-page_off, ch_bytes); - sge[sge_no].addr = - ib_dma_map_page(xprt->sc_cm_id->device, - rqstp->rq_arg.pages[page_no], - page_off, sge_bytes, - DMA_FROM_DEVICE); - sge[sge_no].length = sge_bytes; - sge[sge_no].lkey = xprt->sc_phys_mr->lkey; + rpl_map->sge[sge_no].iov_len = sge_bytes; /* * Don't bump head->count here because the same page * may be used by multiple SGE. @@ -187,11 +178,11 @@ static int rdma_rcl_to_sge(struct svcxprt_rdma *xprt, * SGE, move to the next SGE */ if (ch_bytes == 0) { - ch_sge_ary[ch_no].count = - sge_no - ch_sge_ary[ch_no].start; + chl_map->ch[ch_no].count = + sge_no - chl_map->ch[ch_no].start; ch_no++; ch++; - ch_sge_ary[ch_no].start = sge_no; + chl_map->ch[ch_no].start = sge_no; ch_bytes = ch->rc_target.rs_length; /* If bytes remaining account for next chunk */ if (byte_count) { @@ -220,18 +211,25 @@ static int rdma_rcl_to_sge(struct svcxprt_rdma *xprt, return sge_no; } -static void rdma_set_ctxt_sge(struct svc_rdma_op_ctxt *ctxt, - struct ib_sge *sge, +static void rdma_set_ctxt_sge(struct svcxprt_rdma *xprt, + struct svc_rdma_op_ctxt *ctxt, + struct kvec *vec, u64 *sgl_offset, int count) { int i; ctxt->count = count; + ctxt->direction = DMA_FROM_DEVICE; for (i = 0; i < count; i++) { - ctxt->sge[i].addr = sge[i].addr; - ctxt->sge[i].length = sge[i].length; - *sgl_offset = *sgl_offset + sge[i].length; + atomic_inc(&xprt->sc_dma_used); + ctxt->sge[i].addr = + ib_dma_map_single(xprt->sc_cm_id->device, + vec[i].iov_base, vec[i].iov_len, + DMA_FROM_DEVICE); + ctxt->sge[i].length = vec[i].iov_len; + ctxt->sge[i].lkey = xprt->sc_phys_mr->lkey; + *sgl_offset = *sgl_offset + vec[i].iov_len; } } @@ -282,34 +280,29 @@ static int rdma_read_xdr(struct svcxprt_rdma *xprt, struct ib_send_wr read_wr; int err = 0; int ch_no; - struct ib_sge *sge; int ch_count; int byte_count; int sge_count; u64 sgl_offset; struct rpcrdma_read_chunk *ch; struct svc_rdma_op_ctxt *ctxt = NULL; - struct svc_rdma_op_ctxt *tmp_sge_ctxt; - struct svc_rdma_op_ctxt *tmp_ch_ctxt; - struct chunk_sge *ch_sge_ary; + struct svc_rdma_req_map *rpl_map; + struct svc_rdma_req_map *chl_map; /* If no read list is present, return 0 */ ch = svc_rdma_get_read_chunk(rmsgp); if (!ch) return 0; - /* Allocate temporary contexts to keep SGE */ - BUG_ON(sizeof(struct ib_sge) < sizeof(struct chunk_sge)); - tmp_sge_ctxt = svc_rdma_get_context(xprt); - sge = tmp_sge_ctxt->sge; - tmp_ch_ctxt = svc_rdma_get_context(xprt); - ch_sge_ary = (struct chunk_sge *)tmp_ch_ctxt->sge; + /* Allocate temporary reply and chunk maps */ + rpl_map = svc_rdma_get_req_map(); + chl_map = svc_rdma_get_req_map(); svc_rdma_rcl_chunk_counts(ch, &ch_count, &byte_count); if (ch_count > RPCSVC_MAXPAGES) return -EINVAL; sge_count = rdma_rcl_to_sge(xprt, rqstp, hdr_ctxt, rmsgp, - sge, ch_sge_ary, + rpl_map, chl_map, ch_count, byte_count); sgl_offset = 0; ch_no = 0; @@ -331,14 +324,15 @@ next_sge: read_wr.wr.rdma.remote_addr = get_unaligned(&(ch->rc_target.rs_offset)) + sgl_offset; - read_wr.sg_list = &sge[ch_sge_ary[ch_no].start]; + read_wr.sg_list = ctxt->sge; read_wr.num_sge = - rdma_read_max_sge(xprt, ch_sge_ary[ch_no].count); - rdma_set_ctxt_sge(ctxt, &sge[ch_sge_ary[ch_no].start], + rdma_read_max_sge(xprt, chl_map->ch[ch_no].count); + rdma_set_ctxt_sge(xprt, ctxt, + &rpl_map->sge[chl_map->ch[ch_no].start], &sgl_offset, read_wr.num_sge); if (((ch+1)->rc_discrim == 0) && - (read_wr.num_sge == ch_sge_ary[ch_no].count)) { + (read_wr.num_sge == chl_map->ch[ch_no].count)) { /* * Mark the last RDMA_READ with a bit to * indicate all RPC data has been fetched from @@ -358,9 +352,9 @@ next_sge: } atomic_inc(&rdma_stat_read); - if (read_wr.num_sge < ch_sge_ary[ch_no].count) { - ch_sge_ary[ch_no].count -= read_wr.num_sge; - ch_sge_ary[ch_no].start += read_wr.num_sge; + if (read_wr.num_sge < chl_map->ch[ch_no].count) { + chl_map->ch[ch_no].count -= read_wr.num_sge; + chl_map->ch[ch_no].start += read_wr.num_sge; goto next_sge; } sgl_offset = 0; @@ -368,8 +362,8 @@ next_sge: } out: - svc_rdma_put_context(tmp_sge_ctxt, 0); - svc_rdma_put_context(tmp_ch_ctxt, 0); + svc_rdma_put_req_map(rpl_map); + svc_rdma_put_req_map(chl_map); /* Detach arg pages. svc_recv will replenish them */ for (ch_no = 0; &rqstp->rq_pages[ch_no] < rqstp->rq_respages; ch_no++) @@ -399,7 +393,7 @@ static int rdma_read_complete(struct svc_rqst *rqstp, rqstp->rq_pages[page_no] = head->pages[page_no]; } /* Point rq_arg.pages past header */ - rqstp->rq_arg.pages = &rqstp->rq_pages[head->sge[0].length]; + rqstp->rq_arg.pages = &rqstp->rq_pages[head->hdr_count]; rqstp->rq_arg.page_len = head->arg.page_len; rqstp->rq_arg.page_base = head->arg.page_base; diff --git a/net/sunrpc/xprtrdma/svc_rdma_sendto.c b/net/sunrpc/xprtrdma/svc_rdma_sendto.c index fb82b1b683f8..a19b22b452a3 100644 --- a/net/sunrpc/xprtrdma/svc_rdma_sendto.c +++ b/net/sunrpc/xprtrdma/svc_rdma_sendto.c @@ -63,52 +63,44 @@ * SGE[2..sge_count-2] data from xdr->pages[] * SGE[sge_count-1] data from xdr->tail. * + * The max SGE we need is the length of the XDR / pagesize + one for + * head + one for tail + one for RPCRDMA header. Since RPCSVC_MAXPAGES + * reserves a page for both the request and the reply header, and this + * array is only concerned with the reply we are assured that we have + * on extra page for the RPCRMDA header. */ -static struct ib_sge *xdr_to_sge(struct svcxprt_rdma *xprt, - struct xdr_buf *xdr, - struct ib_sge *sge, - int *sge_count) +static void xdr_to_sge(struct svcxprt_rdma *xprt, + struct xdr_buf *xdr, + struct svc_rdma_req_map *vec) { - /* Max we need is the length of the XDR / pagesize + one for - * head + one for tail + one for RPCRDMA header - */ int sge_max = (xdr->len+PAGE_SIZE-1) / PAGE_SIZE + 3; int sge_no; - u32 byte_count = xdr->len; u32 sge_bytes; u32 page_bytes; - int page_off; + u32 page_off; int page_no; + BUG_ON(xdr->len != + (xdr->head[0].iov_len + xdr->page_len + xdr->tail[0].iov_len)); + /* Skip the first sge, this is for the RPCRDMA header */ sge_no = 1; /* Head SGE */ - sge[sge_no].addr = ib_dma_map_single(xprt->sc_cm_id->device, - xdr->head[0].iov_base, - xdr->head[0].iov_len, - DMA_TO_DEVICE); - sge_bytes = min_t(u32, byte_count, xdr->head[0].iov_len); - byte_count -= sge_bytes; - sge[sge_no].length = sge_bytes; - sge[sge_no].lkey = xprt->sc_phys_mr->lkey; + vec->sge[sge_no].iov_base = xdr->head[0].iov_base; + vec->sge[sge_no].iov_len = xdr->head[0].iov_len; sge_no++; /* pages SGE */ page_no = 0; page_bytes = xdr->page_len; page_off = xdr->page_base; - while (byte_count && page_bytes) { - sge_bytes = min_t(u32, byte_count, (PAGE_SIZE-page_off)); - sge[sge_no].addr = - ib_dma_map_page(xprt->sc_cm_id->device, - xdr->pages[page_no], page_off, - sge_bytes, DMA_TO_DEVICE); - sge_bytes = min(sge_bytes, page_bytes); - byte_count -= sge_bytes; + while (page_bytes) { + vec->sge[sge_no].iov_base = + page_address(xdr->pages[page_no]) + page_off; + sge_bytes = min_t(u32, page_bytes, (PAGE_SIZE - page_off)); page_bytes -= sge_bytes; - sge[sge_no].length = sge_bytes; - sge[sge_no].lkey = xprt->sc_phys_mr->lkey; + vec->sge[sge_no].iov_len = sge_bytes; sge_no++; page_no++; @@ -116,36 +108,24 @@ static struct ib_sge *xdr_to_sge(struct svcxprt_rdma *xprt, } /* Tail SGE */ - if (byte_count && xdr->tail[0].iov_len) { - sge[sge_no].addr = - ib_dma_map_single(xprt->sc_cm_id->device, - xdr->tail[0].iov_base, - xdr->tail[0].iov_len, - DMA_TO_DEVICE); - sge_bytes = min_t(u32, byte_count, xdr->tail[0].iov_len); - byte_count -= sge_bytes; - sge[sge_no].length = sge_bytes; - sge[sge_no].lkey = xprt->sc_phys_mr->lkey; + if (xdr->tail[0].iov_len) { + vec->sge[sge_no].iov_base = xdr->tail[0].iov_base; + vec->sge[sge_no].iov_len = xdr->tail[0].iov_len; sge_no++; } BUG_ON(sge_no > sge_max); - BUG_ON(byte_count != 0); - - *sge_count = sge_no; - return sge; + vec->count = sge_no; } - /* Assumptions: * - The specified write_len can be represented in sc_max_sge * PAGE_SIZE */ static int send_write(struct svcxprt_rdma *xprt, struct svc_rqst *rqstp, u32 rmr, u64 to, u32 xdr_off, int write_len, - struct ib_sge *xdr_sge, int sge_count) + struct svc_rdma_req_map *vec) { - struct svc_rdma_op_ctxt *tmp_sge_ctxt; struct ib_send_wr write_wr; struct ib_sge *sge; int xdr_sge_no; @@ -154,25 +134,23 @@ static int send_write(struct svcxprt_rdma *xprt, struct svc_rqst *rqstp, int sge_off; int bc; struct svc_rdma_op_ctxt *ctxt; - int ret = 0; - BUG_ON(sge_count > RPCSVC_MAXPAGES); + BUG_ON(vec->count > RPCSVC_MAXPAGES); dprintk("svcrdma: RDMA_WRITE rmr=%x, to=%llx, xdr_off=%d, " - "write_len=%d, xdr_sge=%p, sge_count=%d\n", + "write_len=%d, vec->sge=%p, vec->count=%lu\n", rmr, (unsigned long long)to, xdr_off, - write_len, xdr_sge, sge_count); + write_len, vec->sge, vec->count); ctxt = svc_rdma_get_context(xprt); - ctxt->count = 0; - tmp_sge_ctxt = svc_rdma_get_context(xprt); - sge = tmp_sge_ctxt->sge; + ctxt->direction = DMA_TO_DEVICE; + sge = ctxt->sge; /* Find the SGE associated with xdr_off */ - for (bc = xdr_off, xdr_sge_no = 1; bc && xdr_sge_no < sge_count; + for (bc = xdr_off, xdr_sge_no = 1; bc && xdr_sge_no < vec->count; xdr_sge_no++) { - if (xdr_sge[xdr_sge_no].length > bc) + if (vec->sge[xdr_sge_no].iov_len > bc) break; - bc -= xdr_sge[xdr_sge_no].length; + bc -= vec->sge[xdr_sge_no].iov_len; } sge_off = bc; @@ -180,21 +158,28 @@ static int send_write(struct svcxprt_rdma *xprt, struct svc_rqst *rqstp, sge_no = 0; /* Copy the remaining SGE */ - while (bc != 0 && xdr_sge_no < sge_count) { - sge[sge_no].addr = xdr_sge[xdr_sge_no].addr + sge_off; - sge[sge_no].lkey = xdr_sge[xdr_sge_no].lkey; + while (bc != 0 && xdr_sge_no < vec->count) { + sge[sge_no].lkey = xprt->sc_phys_mr->lkey; sge_bytes = min((size_t)bc, - (size_t)(xdr_sge[xdr_sge_no].length-sge_off)); + (size_t)(vec->sge[xdr_sge_no].iov_len-sge_off)); sge[sge_no].length = sge_bytes; - + atomic_inc(&xprt->sc_dma_used); + sge[sge_no].addr = + ib_dma_map_single(xprt->sc_cm_id->device, + (void *) + vec->sge[xdr_sge_no].iov_base + sge_off, + sge_bytes, DMA_TO_DEVICE); + if (dma_mapping_error(sge[sge_no].addr)) + goto err; sge_off = 0; sge_no++; + ctxt->count++; xdr_sge_no++; bc -= sge_bytes; } BUG_ON(bc != 0); - BUG_ON(xdr_sge_no > sge_count); + BUG_ON(xdr_sge_no > vec->count); /* Prepare WRITE WR */ memset(&write_wr, 0, sizeof write_wr); @@ -209,21 +194,20 @@ static int send_write(struct svcxprt_rdma *xprt, struct svc_rqst *rqstp, /* Post It */ atomic_inc(&rdma_stat_write); - if (svc_rdma_send(xprt, &write_wr)) { - svc_rdma_put_context(ctxt, 1); - /* Fatal error, close transport */ - ret = -EIO; - } - svc_rdma_put_context(tmp_sge_ctxt, 0); - return ret; + if (svc_rdma_send(xprt, &write_wr)) + goto err; + return 0; + err: + svc_rdma_put_context(ctxt, 0); + /* Fatal error, close transport */ + return -EIO; } static int send_write_chunks(struct svcxprt_rdma *xprt, struct rpcrdma_msg *rdma_argp, struct rpcrdma_msg *rdma_resp, struct svc_rqst *rqstp, - struct ib_sge *sge, - int sge_count) + struct svc_rdma_req_map *vec) { u32 xfer_len = rqstp->rq_res.page_len + rqstp->rq_res.tail[0].iov_len; int write_len; @@ -269,8 +253,7 @@ static int send_write_chunks(struct svcxprt_rdma *xprt, rs_offset + chunk_off, xdr_off, this_write, - sge, - sge_count); + vec); if (ret) { dprintk("svcrdma: RDMA_WRITE failed, ret=%d\n", ret); @@ -292,8 +275,7 @@ static int send_reply_chunks(struct svcxprt_rdma *xprt, struct rpcrdma_msg *rdma_argp, struct rpcrdma_msg *rdma_resp, struct svc_rqst *rqstp, - struct ib_sge *sge, - int sge_count) + struct svc_rdma_req_map *vec) { u32 xfer_len = rqstp->rq_res.len; int write_len; @@ -341,8 +323,7 @@ static int send_reply_chunks(struct svcxprt_rdma *xprt, rs_offset + chunk_off, xdr_off, this_write, - sge, - sge_count); + vec); if (ret) { dprintk("svcrdma: RDMA_WRITE failed, ret=%d\n", ret); @@ -380,7 +361,7 @@ static int send_reply(struct svcxprt_rdma *rdma, struct page *page, struct rpcrdma_msg *rdma_resp, struct svc_rdma_op_ctxt *ctxt, - int sge_count, + struct svc_rdma_req_map *vec, int byte_count) { struct ib_send_wr send_wr; @@ -405,6 +386,7 @@ static int send_reply(struct svcxprt_rdma *rdma, ctxt->count = 1; /* Prepare the SGE for the RPCRDMA Header */ + atomic_inc(&rdma->sc_dma_used); ctxt->sge[0].addr = ib_dma_map_page(rdma->sc_cm_id->device, page, 0, PAGE_SIZE, DMA_TO_DEVICE); @@ -413,10 +395,16 @@ static int send_reply(struct svcxprt_rdma *rdma, ctxt->sge[0].lkey = rdma->sc_phys_mr->lkey; /* Determine how many of our SGE are to be transmitted */ - for (sge_no = 1; byte_count && sge_no < sge_count; sge_no++) { - sge_bytes = min((size_t)ctxt->sge[sge_no].length, - (size_t)byte_count); + for (sge_no = 1; byte_count && sge_no < vec->count; sge_no++) { + sge_bytes = min_t(size_t, vec->sge[sge_no].iov_len, byte_count); byte_count -= sge_bytes; + atomic_inc(&rdma->sc_dma_used); + ctxt->sge[sge_no].addr = + ib_dma_map_single(rdma->sc_cm_id->device, + vec->sge[sge_no].iov_base, + sge_bytes, DMA_TO_DEVICE); + ctxt->sge[sge_no].length = sge_bytes; + ctxt->sge[sge_no].lkey = rdma->sc_phys_mr->lkey; } BUG_ON(byte_count != 0); @@ -428,8 +416,10 @@ static int send_reply(struct svcxprt_rdma *rdma, ctxt->pages[page_no+1] = rqstp->rq_respages[page_no]; ctxt->count++; rqstp->rq_respages[page_no] = NULL; + /* If there are more pages than SGE, terminate SGE list */ + if (page_no+1 >= sge_no) + ctxt->sge[page_no+1].length = 0; } - BUG_ON(sge_no > rdma->sc_max_sge); memset(&send_wr, 0, sizeof send_wr); ctxt->wr_op = IB_WR_SEND; @@ -473,20 +463,20 @@ int svc_rdma_sendto(struct svc_rqst *rqstp) enum rpcrdma_proc reply_type; int ret; int inline_bytes; - struct ib_sge *sge; - int sge_count = 0; struct page *res_page; struct svc_rdma_op_ctxt *ctxt; + struct svc_rdma_req_map *vec; dprintk("svcrdma: sending response for rqstp=%p\n", rqstp); /* Get the RDMA request header. */ rdma_argp = xdr_start(&rqstp->rq_arg); - /* Build an SGE for the XDR */ + /* Build an req vec for the XDR */ ctxt = svc_rdma_get_context(rdma); ctxt->direction = DMA_TO_DEVICE; - sge = xdr_to_sge(rdma, &rqstp->rq_res, ctxt->sge, &sge_count); + vec = svc_rdma_get_req_map(); + xdr_to_sge(rdma, &rqstp->rq_res, vec); inline_bytes = rqstp->rq_res.len; @@ -503,7 +493,7 @@ int svc_rdma_sendto(struct svc_rqst *rqstp) /* Send any write-chunk data and build resp write-list */ ret = send_write_chunks(rdma, rdma_argp, rdma_resp, - rqstp, sge, sge_count); + rqstp, vec); if (ret < 0) { printk(KERN_ERR "svcrdma: failed to send write chunks, rc=%d\n", ret); @@ -513,7 +503,7 @@ int svc_rdma_sendto(struct svc_rqst *rqstp) /* Send any reply-list data and update resp reply-list */ ret = send_reply_chunks(rdma, rdma_argp, rdma_resp, - rqstp, sge, sge_count); + rqstp, vec); if (ret < 0) { printk(KERN_ERR "svcrdma: failed to send reply chunks, rc=%d\n", ret); @@ -521,11 +511,13 @@ int svc_rdma_sendto(struct svc_rqst *rqstp) } inline_bytes -= ret; - ret = send_reply(rdma, rqstp, res_page, rdma_resp, ctxt, sge_count, + ret = send_reply(rdma, rqstp, res_page, rdma_resp, ctxt, vec, inline_bytes); + svc_rdma_put_req_map(vec); dprintk("svcrdma: send_reply returns %d\n", ret); return ret; error: + svc_rdma_put_req_map(vec); svc_rdma_put_context(ctxt, 0); put_page(res_page); return ret; diff --git a/net/sunrpc/xprtrdma/svc_rdma_transport.c b/net/sunrpc/xprtrdma/svc_rdma_transport.c index e132509d1db0..19ddc382b777 100644 --- a/net/sunrpc/xprtrdma/svc_rdma_transport.c +++ b/net/sunrpc/xprtrdma/svc_rdma_transport.c @@ -84,70 +84,37 @@ struct svc_xprt_class svc_rdma_class = { .xcl_max_payload = RPCSVC_MAXPAYLOAD_TCP, }; -static int rdma_bump_context_cache(struct svcxprt_rdma *xprt) +/* WR context cache. Created in svc_rdma.c */ +extern struct kmem_cache *svc_rdma_ctxt_cachep; + +struct svc_rdma_op_ctxt *svc_rdma_get_context(struct svcxprt_rdma *xprt) { - int target; - int at_least_one = 0; struct svc_rdma_op_ctxt *ctxt; - target = min(xprt->sc_ctxt_cnt + xprt->sc_ctxt_bump, - xprt->sc_ctxt_max); - - spin_lock_bh(&xprt->sc_ctxt_lock); - while (xprt->sc_ctxt_cnt < target) { - xprt->sc_ctxt_cnt++; - spin_unlock_bh(&xprt->sc_ctxt_lock); - - ctxt = kmalloc(sizeof(*ctxt), GFP_KERNEL); - - spin_lock_bh(&xprt->sc_ctxt_lock); - if (ctxt) { - at_least_one = 1; - INIT_LIST_HEAD(&ctxt->free_list); - list_add(&ctxt->free_list, &xprt->sc_ctxt_free); - } else { - /* kmalloc failed...give up for now */ - xprt->sc_ctxt_cnt--; + while (1) { + ctxt = kmem_cache_alloc(svc_rdma_ctxt_cachep, GFP_KERNEL); + if (ctxt) break; - } + schedule_timeout_uninterruptible(msecs_to_jiffies(500)); } - spin_unlock_bh(&xprt->sc_ctxt_lock); - dprintk("svcrdma: sc_ctxt_max=%d, sc_ctxt_cnt=%d\n", - xprt->sc_ctxt_max, xprt->sc_ctxt_cnt); - return at_least_one; + ctxt->xprt = xprt; + INIT_LIST_HEAD(&ctxt->dto_q); + ctxt->count = 0; + atomic_inc(&xprt->sc_ctxt_used); + return ctxt; } -struct svc_rdma_op_ctxt *svc_rdma_get_context(struct svcxprt_rdma *xprt) +static void svc_rdma_unmap_dma(struct svc_rdma_op_ctxt *ctxt) { - struct svc_rdma_op_ctxt *ctxt; - - while (1) { - spin_lock_bh(&xprt->sc_ctxt_lock); - if (unlikely(list_empty(&xprt->sc_ctxt_free))) { - /* Try to bump my cache. */ - spin_unlock_bh(&xprt->sc_ctxt_lock); - - if (rdma_bump_context_cache(xprt)) - continue; - - printk(KERN_INFO "svcrdma: sleeping waiting for " - "context memory on xprt=%p\n", - xprt); - schedule_timeout_uninterruptible(msecs_to_jiffies(500)); - continue; - } - ctxt = list_entry(xprt->sc_ctxt_free.next, - struct svc_rdma_op_ctxt, - free_list); - list_del_init(&ctxt->free_list); - spin_unlock_bh(&xprt->sc_ctxt_lock); - ctxt->xprt = xprt; - INIT_LIST_HEAD(&ctxt->dto_q); - ctxt->count = 0; - atomic_inc(&xprt->sc_ctxt_used); - break; + struct svcxprt_rdma *xprt = ctxt->xprt; + int i; + for (i = 0; i < ctxt->count && ctxt->sge[i].length; i++) { + atomic_dec(&xprt->sc_dma_used); + ib_dma_unmap_single(xprt->sc_cm_id->device, + ctxt->sge[i].addr, + ctxt->sge[i].length, + ctxt->direction); } - return ctxt; } void svc_rdma_put_context(struct svc_rdma_op_ctxt *ctxt, int free_pages) @@ -161,18 +128,36 @@ void svc_rdma_put_context(struct svc_rdma_op_ctxt *ctxt, int free_pages) for (i = 0; i < ctxt->count; i++) put_page(ctxt->pages[i]); - for (i = 0; i < ctxt->count; i++) - ib_dma_unmap_single(xprt->sc_cm_id->device, - ctxt->sge[i].addr, - ctxt->sge[i].length, - ctxt->direction); - - spin_lock_bh(&xprt->sc_ctxt_lock); - list_add(&ctxt->free_list, &xprt->sc_ctxt_free); - spin_unlock_bh(&xprt->sc_ctxt_lock); + kmem_cache_free(svc_rdma_ctxt_cachep, ctxt); atomic_dec(&xprt->sc_ctxt_used); } +/* Temporary NFS request map cache. Created in svc_rdma.c */ +extern struct kmem_cache *svc_rdma_map_cachep; + +/* + * Temporary NFS req mappings are shared across all transport + * instances. These are short lived and should be bounded by the number + * of concurrent server threads * depth of the SQ. + */ +struct svc_rdma_req_map *svc_rdma_get_req_map(void) +{ + struct svc_rdma_req_map *map; + while (1) { + map = kmem_cache_alloc(svc_rdma_map_cachep, GFP_KERNEL); + if (map) + break; + schedule_timeout_uninterruptible(msecs_to_jiffies(500)); + } + map->count = 0; + return map; +} + +void svc_rdma_put_req_map(struct svc_rdma_req_map *map) +{ + kmem_cache_free(svc_rdma_map_cachep, map); +} + /* ib_cq event handler */ static void cq_event_handler(struct ib_event *event, void *context) { @@ -302,6 +287,7 @@ static void rq_cq_reap(struct svcxprt_rdma *xprt) ctxt = (struct svc_rdma_op_ctxt *)(unsigned long)wc.wr_id; ctxt->wc_status = wc.status; ctxt->byte_len = wc.byte_len; + svc_rdma_unmap_dma(ctxt); if (wc.status != IB_WC_SUCCESS) { /* Close the transport */ dprintk("svcrdma: transport closing putting ctxt %p\n", ctxt); @@ -351,6 +337,7 @@ static void sq_cq_reap(struct svcxprt_rdma *xprt) ctxt = (struct svc_rdma_op_ctxt *)(unsigned long)wc.wr_id; xprt = ctxt->xprt; + svc_rdma_unmap_dma(ctxt); if (wc.status != IB_WC_SUCCESS) /* Close the transport */ set_bit(XPT_CLOSE, &xprt->sc_xprt.xpt_flags); @@ -361,10 +348,13 @@ static void sq_cq_reap(struct svcxprt_rdma *xprt) switch (ctxt->wr_op) { case IB_WR_SEND: - case IB_WR_RDMA_WRITE: svc_rdma_put_context(ctxt, 1); break; + case IB_WR_RDMA_WRITE: + svc_rdma_put_context(ctxt, 0); + break; + case IB_WR_RDMA_READ: if (test_bit(RDMACTXT_F_LAST_CTXT, &ctxt->flags)) { struct svc_rdma_op_ctxt *read_hdr = ctxt->read_hdr; @@ -423,40 +413,6 @@ static void sq_comp_handler(struct ib_cq *cq, void *cq_context) tasklet_schedule(&dto_tasklet); } -static void create_context_cache(struct svcxprt_rdma *xprt, - int ctxt_count, int ctxt_bump, int ctxt_max) -{ - struct svc_rdma_op_ctxt *ctxt; - int i; - - xprt->sc_ctxt_max = ctxt_max; - xprt->sc_ctxt_bump = ctxt_bump; - xprt->sc_ctxt_cnt = 0; - atomic_set(&xprt->sc_ctxt_used, 0); - - INIT_LIST_HEAD(&xprt->sc_ctxt_free); - for (i = 0; i < ctxt_count; i++) { - ctxt = kmalloc(sizeof(*ctxt), GFP_KERNEL); - if (ctxt) { - INIT_LIST_HEAD(&ctxt->free_list); - list_add(&ctxt->free_list, &xprt->sc_ctxt_free); - xprt->sc_ctxt_cnt++; - } - } -} - -static void destroy_context_cache(struct svcxprt_rdma *xprt) -{ - while (!list_empty(&xprt->sc_ctxt_free)) { - struct svc_rdma_op_ctxt *ctxt; - ctxt = list_entry(xprt->sc_ctxt_free.next, - struct svc_rdma_op_ctxt, - free_list); - list_del_init(&ctxt->free_list); - kfree(ctxt); - } -} - static struct svcxprt_rdma *rdma_create_xprt(struct svc_serv *serv, int listener) { @@ -473,7 +429,6 @@ static struct svcxprt_rdma *rdma_create_xprt(struct svc_serv *serv, spin_lock_init(&cma_xprt->sc_lock); spin_lock_init(&cma_xprt->sc_read_complete_lock); - spin_lock_init(&cma_xprt->sc_ctxt_lock); spin_lock_init(&cma_xprt->sc_rq_dto_lock); cma_xprt->sc_ord = svcrdma_ord; @@ -482,21 +437,9 @@ static struct svcxprt_rdma *rdma_create_xprt(struct svc_serv *serv, cma_xprt->sc_max_requests = svcrdma_max_requests; cma_xprt->sc_sq_depth = svcrdma_max_requests * RPCRDMA_SQ_DEPTH_MULT; atomic_set(&cma_xprt->sc_sq_count, 0); + atomic_set(&cma_xprt->sc_ctxt_used, 0); - if (!listener) { - int reqs = cma_xprt->sc_max_requests; - create_context_cache(cma_xprt, - reqs << 1, /* starting size */ - reqs, /* bump amount */ - reqs + - cma_xprt->sc_sq_depth + - RPCRDMA_MAX_THREADS + 1); /* max */ - if (list_empty(&cma_xprt->sc_ctxt_free)) { - kfree(cma_xprt); - return NULL; - } - clear_bit(XPT_LISTENER, &cma_xprt->sc_xprt.xpt_flags); - } else + if (listener) set_bit(XPT_LISTENER, &cma_xprt->sc_xprt.xpt_flags); return cma_xprt; @@ -532,6 +475,7 @@ int svc_rdma_post_recv(struct svcxprt_rdma *xprt) BUG_ON(sge_no >= xprt->sc_max_sge); page = svc_rdma_get_page(); ctxt->pages[sge_no] = page; + atomic_inc(&xprt->sc_dma_used); pa = ib_dma_map_page(xprt->sc_cm_id->device, page, 0, PAGE_SIZE, DMA_FROM_DEVICE); @@ -566,7 +510,7 @@ int svc_rdma_post_recv(struct svcxprt_rdma *xprt) * will call the recvfrom method on the listen xprt which will accept the new * connection. */ -static void handle_connect_req(struct rdma_cm_id *new_cma_id) +static void handle_connect_req(struct rdma_cm_id *new_cma_id, size_t client_ird) { struct svcxprt_rdma *listen_xprt = new_cma_id->context; struct svcxprt_rdma *newxprt; @@ -583,6 +527,9 @@ static void handle_connect_req(struct rdma_cm_id *new_cma_id) dprintk("svcrdma: Creating newxprt=%p, cm_id=%p, listenxprt=%p\n", newxprt, newxprt->sc_cm_id, listen_xprt); + /* Save client advertised inbound read limit for use later in accept. */ + newxprt->sc_ord = client_ird; + /* Set the local and remote addresses in the transport */ sa = (struct sockaddr *)&newxprt->sc_cm_id->route.addr.dst_addr; svc_xprt_set_remote(&newxprt->sc_xprt, sa, svc_addr_len(sa)); @@ -619,7 +566,8 @@ static int rdma_listen_handler(struct rdma_cm_id *cma_id, case RDMA_CM_EVENT_CONNECT_REQUEST: dprintk("svcrdma: Connect request on cma_id=%p, xprt = %p, " "event=%d\n", cma_id, cma_id->context, event->event); - handle_connect_req(cma_id); + handle_connect_req(cma_id, + event->param.conn.responder_resources); break; case RDMA_CM_EVENT_ESTABLISHED: @@ -793,8 +741,12 @@ static struct svc_xprt *svc_rdma_accept(struct svc_xprt *xprt) (size_t)svcrdma_max_requests); newxprt->sc_sq_depth = RPCRDMA_SQ_DEPTH_MULT * newxprt->sc_max_requests; - newxprt->sc_ord = min((size_t)devattr.max_qp_rd_atom, - (size_t)svcrdma_ord); + /* + * Limit ORD based on client limit, local device limit, and + * configured svcrdma limit. + */ + newxprt->sc_ord = min_t(size_t, devattr.max_qp_rd_atom, newxprt->sc_ord); + newxprt->sc_ord = min_t(size_t, svcrdma_ord, newxprt->sc_ord); newxprt->sc_pd = ib_alloc_pd(newxprt->sc_cm_id->device); if (IS_ERR(newxprt->sc_pd)) { @@ -987,7 +939,6 @@ static void __svc_rdma_free(struct work_struct *work) * cm_id because the device ptr is needed to unmap the dma in * svc_rdma_put_context. */ - spin_lock_bh(&rdma->sc_read_complete_lock); while (!list_empty(&rdma->sc_read_complete_q)) { struct svc_rdma_op_ctxt *ctxt; ctxt = list_entry(rdma->sc_read_complete_q.next, @@ -996,10 +947,8 @@ static void __svc_rdma_free(struct work_struct *work) list_del_init(&ctxt->dto_q); svc_rdma_put_context(ctxt, 1); } - spin_unlock_bh(&rdma->sc_read_complete_lock); /* Destroy queued, but not processed recv completions */ - spin_lock_bh(&rdma->sc_rq_dto_lock); while (!list_empty(&rdma->sc_rq_dto_q)) { struct svc_rdma_op_ctxt *ctxt; ctxt = list_entry(rdma->sc_rq_dto_q.next, @@ -1008,10 +957,10 @@ static void __svc_rdma_free(struct work_struct *work) list_del_init(&ctxt->dto_q); svc_rdma_put_context(ctxt, 1); } - spin_unlock_bh(&rdma->sc_rq_dto_lock); /* Warn if we leaked a resource or under-referenced */ WARN_ON(atomic_read(&rdma->sc_ctxt_used) != 0); + WARN_ON(atomic_read(&rdma->sc_dma_used) != 0); /* Destroy the QP if present (not a listener) */ if (rdma->sc_qp && !IS_ERR(rdma->sc_qp)) @@ -1032,7 +981,6 @@ static void __svc_rdma_free(struct work_struct *work) /* Destroy the CM ID */ rdma_destroy_id(rdma->sc_cm_id); - destroy_context_cache(rdma); kfree(rdma); } @@ -1132,6 +1080,7 @@ void svc_rdma_send_error(struct svcxprt_rdma *xprt, struct rpcrdma_msg *rmsgp, length = svc_rdma_xdr_encode_error(xprt, rmsgp, err, va); /* Prepare SGE for local address */ + atomic_inc(&xprt->sc_dma_used); sge.addr = ib_dma_map_page(xprt->sc_cm_id->device, p, 0, PAGE_SIZE, DMA_FROM_DEVICE); sge.lkey = xprt->sc_phys_mr->lkey; diff --git a/net/sysctl_net.c b/net/sysctl_net.c index b4f0525f91af..007c1a6708ee 100644 --- a/net/sysctl_net.c +++ b/net/sysctl_net.c @@ -4,7 +4,6 @@ * Begun April 1, 1996, Mike Shaver. * Added /proc/sys/net directories for each protocol family. [MS] * - * $Log: sysctl_net.c,v $ * Revision 1.2 1996/05/08 20:24:40 shaver * Added bits for NET_BRIDGE and the NET_IPV4_ARP stuff and * NET_IPV4_IP_FORWARD. @@ -40,6 +39,27 @@ static struct ctl_table_root net_sysctl_root = { .lookup = net_ctl_header_lookup, }; +static LIST_HEAD(net_sysctl_ro_tables); +static struct list_head *net_ctl_ro_header_lookup(struct ctl_table_root *root, + struct nsproxy *namespaces) +{ + return &net_sysctl_ro_tables; +} + +static int net_ctl_ro_header_perms(struct ctl_table_root *root, + struct nsproxy *namespaces, struct ctl_table *table) +{ + if (namespaces->net_ns == &init_net) + return table->mode; + else + return table->mode & ~0222; +} + +static struct ctl_table_root net_sysctl_ro_root = { + .lookup = net_ctl_ro_header_lookup, + .permissions = net_ctl_ro_header_perms, +}; + static int sysctl_net_init(struct net *net) { INIT_LIST_HEAD(&net->sysctl_table_headers); @@ -64,6 +84,7 @@ static __init int sysctl_init(void) if (ret) goto out; register_sysctl_root(&net_sysctl_root); + register_sysctl_root(&net_sysctl_ro_root); out: return ret; } @@ -80,6 +101,14 @@ struct ctl_table_header *register_net_sysctl_table(struct net *net, } EXPORT_SYMBOL_GPL(register_net_sysctl_table); +struct ctl_table_header *register_net_sysctl_rotable(const + struct ctl_path *path, struct ctl_table *table) +{ + return __register_sysctl_paths(&net_sysctl_ro_root, + &init_nsproxy, path, table); +} +EXPORT_SYMBOL_GPL(register_net_sysctl_rotable); + void unregister_net_sysctl_table(struct ctl_table_header *header) { unregister_sysctl_table(header); diff --git a/net/tipc/bcast.c b/net/tipc/bcast.c index e7880172ef19..b1ff16aa4bdb 100644 --- a/net/tipc/bcast.c +++ b/net/tipc/bcast.c @@ -276,7 +276,7 @@ static void bclink_send_nack(struct node *n_ptr) if (buf) { msg = buf_msg(buf); msg_init(msg, BCAST_PROTOCOL, STATE_MSG, - TIPC_OK, INT_H_SIZE, n_ptr->addr); + INT_H_SIZE, n_ptr->addr); msg_set_mc_netid(msg, tipc_net_id); msg_set_bcast_ack(msg, mod(n_ptr->bclink.last_in)); msg_set_bcgap_after(msg, n_ptr->bclink.gap_after); @@ -571,7 +571,7 @@ static int tipc_bcbearer_send(struct sk_buff *buf, assert(tipc_cltr_bcast_nodes.count != 0); bcbuf_set_acks(buf, tipc_cltr_bcast_nodes.count); msg = buf_msg(buf); - msg_set_non_seq(msg); + msg_set_non_seq(msg, 1); msg_set_mc_netid(msg, tipc_net_id); } @@ -611,7 +611,7 @@ swap: bcbearer->bpairs[bp_index].secondary = p; update: if (bcbearer->remains_new.count == 0) - return TIPC_OK; + return 0; bcbearer->remains = bcbearer->remains_new; } @@ -620,7 +620,7 @@ update: bcbearer->bearer.publ.blocked = 1; bcl->stats.bearer_congs++; - return ~TIPC_OK; + return 1; } /** @@ -756,7 +756,7 @@ int tipc_bclink_reset_stats(void) spin_lock_bh(&bc_lock); memset(&bcl->stats, 0, sizeof(bcl->stats)); spin_unlock_bh(&bc_lock); - return TIPC_OK; + return 0; } int tipc_bclink_set_queue_limits(u32 limit) @@ -769,7 +769,7 @@ int tipc_bclink_set_queue_limits(u32 limit) spin_lock_bh(&bc_lock); tipc_link_set_queue_limits(bcl, limit); spin_unlock_bh(&bc_lock); - return TIPC_OK; + return 0; } int tipc_bclink_init(void) @@ -810,7 +810,7 @@ int tipc_bclink_init(void) tipc_printbuf_init(&bcl->print_buf, pb, BCLINK_LOG_BUF_SIZE); } - return TIPC_OK; + return 0; } void tipc_bclink_stop(void) diff --git a/net/tipc/bearer.c b/net/tipc/bearer.c index 271a375b49b7..6a9aba3edd08 100644 --- a/net/tipc/bearer.c +++ b/net/tipc/bearer.c @@ -370,7 +370,7 @@ void tipc_bearer_remove_dest(struct bearer *b_ptr, u32 dest) */ static int bearer_push(struct bearer *b_ptr) { - u32 res = TIPC_OK; + u32 res = 0; struct link *ln, *tln; if (b_ptr->publ.blocked) @@ -607,7 +607,7 @@ int tipc_block_bearer(const char *name) } spin_unlock_bh(&b_ptr->publ.lock); read_unlock_bh(&tipc_net_lock); - return TIPC_OK; + return 0; } /** @@ -645,7 +645,7 @@ static int bearer_disable(const char *name) } spin_unlock_bh(&b_ptr->publ.lock); memset(b_ptr, 0, sizeof(struct bearer)); - return TIPC_OK; + return 0; } int tipc_disable_bearer(const char *name) @@ -668,7 +668,7 @@ int tipc_bearer_init(void) tipc_bearers = kcalloc(MAX_BEARERS, sizeof(struct bearer), GFP_ATOMIC); media_list = kcalloc(MAX_MEDIA, sizeof(struct media), GFP_ATOMIC); if (tipc_bearers && media_list) { - res = TIPC_OK; + res = 0; } else { kfree(tipc_bearers); kfree(media_list); diff --git a/net/tipc/cluster.c b/net/tipc/cluster.c index 4bb3404f610b..46ee6c58532d 100644 --- a/net/tipc/cluster.c +++ b/net/tipc/cluster.c @@ -238,7 +238,7 @@ static struct sk_buff *tipc_cltr_prepare_routing_msg(u32 data_size, u32 dest) if (buf) { msg = buf_msg(buf); memset((char *)msg, 0, size); - msg_init(msg, ROUTE_DISTRIBUTOR, 0, TIPC_OK, INT_H_SIZE, dest); + msg_init(msg, ROUTE_DISTRIBUTOR, 0, INT_H_SIZE, dest); } return buf; } @@ -571,6 +571,6 @@ exit: int tipc_cltr_init(void) { tipc_highest_allowed_slave = LOWEST_SLAVE + tipc_max_slaves; - return tipc_cltr_create(tipc_own_addr) ? TIPC_OK : -ENOMEM; + return tipc_cltr_create(tipc_own_addr) ? 0 : -ENOMEM; } diff --git a/net/tipc/config.c b/net/tipc/config.c index c71337a22d33..ca3544d030c7 100644 --- a/net/tipc/config.c +++ b/net/tipc/config.c @@ -2,7 +2,7 @@ * net/tipc/config.c: TIPC configuration management code * * Copyright (c) 2002-2006, Ericsson AB - * Copyright (c) 2004-2006, Wind River Systems + * Copyright (c) 2004-2007, Wind River Systems * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -293,7 +293,6 @@ static struct sk_buff *cfg_set_own_addr(void) if (tipc_mode == TIPC_NET_MODE) return tipc_cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED " (cannot change node address once assigned)"); - tipc_own_addr = addr; /* * Must release all spinlocks before calling start_net() because @@ -306,7 +305,7 @@ static struct sk_buff *cfg_set_own_addr(void) */ spin_unlock_bh(&config_lock); - tipc_core_start_net(); + tipc_core_start_net(addr); spin_lock_bh(&config_lock); return tipc_cfg_reply_none(); } @@ -529,7 +528,7 @@ struct sk_buff *tipc_cfg_do_cmd(u32 orig_node, u16 cmd, const void *request_area break; #endif case TIPC_CMD_SET_LOG_SIZE: - rep_tlv_buf = tipc_log_resize(req_tlv_area, req_tlv_space); + rep_tlv_buf = tipc_log_resize_cmd(req_tlv_area, req_tlv_space); break; case TIPC_CMD_DUMP_LOG: rep_tlv_buf = tipc_log_dump(); @@ -602,6 +601,10 @@ struct sk_buff *tipc_cfg_do_cmd(u32 orig_node, u16 cmd, const void *request_area case TIPC_CMD_GET_NETID: rep_tlv_buf = tipc_cfg_reply_unsigned(tipc_net_id); break; + case TIPC_CMD_NOT_NET_ADMIN: + rep_tlv_buf = + tipc_cfg_reply_error_string(TIPC_CFG_NOT_NET_ADMIN); + break; default: rep_tlv_buf = tipc_cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED " (unknown command)"); diff --git a/net/tipc/core.c b/net/tipc/core.c index 740aac5cdfb6..3256bd7d398f 100644 --- a/net/tipc/core.c +++ b/net/tipc/core.c @@ -49,7 +49,7 @@ #include "config.h" -#define TIPC_MOD_VER "1.6.3" +#define TIPC_MOD_VER "1.6.4" #ifndef CONFIG_TIPC_ZONES #define CONFIG_TIPC_ZONES 3 @@ -117,11 +117,11 @@ void tipc_core_stop_net(void) * start_net - start TIPC networking sub-systems */ -int tipc_core_start_net(void) +int tipc_core_start_net(unsigned long addr) { int res; - if ((res = tipc_net_start()) || + if ((res = tipc_net_start(addr)) || (res = tipc_eth_media_start())) { tipc_core_stop_net(); } @@ -164,8 +164,7 @@ int tipc_core_start(void) tipc_mode = TIPC_NODE_MODE; if ((res = tipc_handler_start()) || - (res = tipc_ref_table_init(tipc_max_ports + tipc_max_subscriptions, - tipc_random)) || + (res = tipc_ref_table_init(tipc_max_ports, tipc_random)) || (res = tipc_reg_start()) || (res = tipc_nametbl_init()) || (res = tipc_k_signal((Handler)tipc_subscr_start, 0)) || @@ -182,7 +181,7 @@ static int __init tipc_init(void) { int res; - tipc_log_reinit(CONFIG_TIPC_LOG); + tipc_log_resize(CONFIG_TIPC_LOG); info("Activated (version " TIPC_MOD_VER " compiled " __DATE__ " " __TIME__ ")\n"); @@ -209,7 +208,7 @@ static void __exit tipc_exit(void) tipc_core_stop_net(); tipc_core_stop(); info("Deactivated\n"); - tipc_log_stop(); + tipc_log_resize(0); } module_init(tipc_init); diff --git a/net/tipc/core.h b/net/tipc/core.h index 5a0e4878d3b7..a881f92a8537 100644 --- a/net/tipc/core.h +++ b/net/tipc/core.h @@ -2,7 +2,7 @@ * net/tipc/core.h: Include file for TIPC global declarations * * Copyright (c) 2005-2006, Ericsson AB - * Copyright (c) 2005-2006, Wind River Systems + * Copyright (c) 2005-2007, Wind River Systems * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -59,84 +59,108 @@ #include <linux/vmalloc.h> /* - * TIPC debugging code + * TIPC sanity test macros */ #define assert(i) BUG_ON(!(i)) -struct tipc_msg; -extern struct print_buf *TIPC_NULL, *TIPC_CONS, *TIPC_LOG; -extern struct print_buf *TIPC_TEE(struct print_buf *, struct print_buf *); -void tipc_msg_print(struct print_buf*,struct tipc_msg *,const char*); -void tipc_printf(struct print_buf *, const char *fmt, ...); -void tipc_dump(struct print_buf*,const char *fmt, ...); - -#ifdef CONFIG_TIPC_DEBUG - /* - * TIPC debug support included: - * - system messages are printed to TIPC_OUTPUT print buffer - * - debug messages are printed to DBG_OUTPUT print buffer + * TIPC system monitoring code */ -#define err(fmt, arg...) tipc_printf(TIPC_OUTPUT, KERN_ERR "TIPC: " fmt, ## arg) -#define warn(fmt, arg...) tipc_printf(TIPC_OUTPUT, KERN_WARNING "TIPC: " fmt, ## arg) -#define info(fmt, arg...) tipc_printf(TIPC_OUTPUT, KERN_NOTICE "TIPC: " fmt, ## arg) +/* + * TIPC's print buffer subsystem supports the following print buffers: + * + * TIPC_NULL : null buffer (i.e. print nowhere) + * TIPC_CONS : system console + * TIPC_LOG : TIPC log buffer + * &buf : user-defined buffer (struct print_buf *) + * + * Note: TIPC_LOG is configured to echo its output to the system console; + * user-defined buffers can be configured to do the same thing. + */ -#define dbg(fmt, arg...) do {if (DBG_OUTPUT != TIPC_NULL) tipc_printf(DBG_OUTPUT, fmt, ## arg);} while(0) -#define msg_dbg(msg, txt) do {if (DBG_OUTPUT != TIPC_NULL) tipc_msg_print(DBG_OUTPUT, msg, txt);} while(0) -#define dump(fmt, arg...) do {if (DBG_OUTPUT != TIPC_NULL) tipc_dump(DBG_OUTPUT, fmt, ##arg);} while(0) +extern struct print_buf *const TIPC_NULL; +extern struct print_buf *const TIPC_CONS; +extern struct print_buf *const TIPC_LOG; +void tipc_printf(struct print_buf *, const char *fmt, ...); /* - * By default, TIPC_OUTPUT is defined to be system console and TIPC log buffer, - * while DBG_OUTPUT is the null print buffer. These defaults can be changed - * here, or on a per .c file basis, by redefining these symbols. The following - * print buffer options are available: - * - * TIPC_NULL : null buffer (i.e. print nowhere) - * TIPC_CONS : system console - * TIPC_LOG : TIPC log buffer - * &buf : user-defined buffer (struct print_buf *) - * TIPC_TEE(&buf_a,&buf_b) : list of buffers (eg. TIPC_TEE(TIPC_CONS,TIPC_LOG)) + * TIPC_OUTPUT is the destination print buffer for system messages. */ #ifndef TIPC_OUTPUT -#define TIPC_OUTPUT TIPC_TEE(TIPC_CONS,TIPC_LOG) -#endif - -#ifndef DBG_OUTPUT -#define DBG_OUTPUT TIPC_NULL +#define TIPC_OUTPUT TIPC_LOG #endif -#else - /* - * TIPC debug support not included: - * - system messages are printed to system console - * - debug messages are not printed + * TIPC can be configured to send system messages to TIPC_OUTPUT + * or to the system console only. */ +#ifdef CONFIG_TIPC_DEBUG + +#define err(fmt, arg...) tipc_printf(TIPC_OUTPUT, \ + KERN_ERR "TIPC: " fmt, ## arg) +#define warn(fmt, arg...) tipc_printf(TIPC_OUTPUT, \ + KERN_WARNING "TIPC: " fmt, ## arg) +#define info(fmt, arg...) tipc_printf(TIPC_OUTPUT, \ + KERN_NOTICE "TIPC: " fmt, ## arg) + +#else + #define err(fmt, arg...) printk(KERN_ERR "TIPC: " fmt , ## arg) #define info(fmt, arg...) printk(KERN_INFO "TIPC: " fmt , ## arg) #define warn(fmt, arg...) printk(KERN_WARNING "TIPC: " fmt , ## arg) -#define dbg(fmt, arg...) do {} while (0) -#define msg_dbg(msg,txt) do {} while (0) -#define dump(fmt,arg...) do {} while (0) +#endif +/* + * DBG_OUTPUT is the destination print buffer for debug messages. + * It defaults to the the null print buffer, but can be redefined + * (typically in the individual .c files being debugged) to allow + * selected debug messages to be generated where needed. + */ + +#ifndef DBG_OUTPUT +#define DBG_OUTPUT TIPC_NULL +#endif /* - * TIPC_OUTPUT is defined to be the system console, while DBG_OUTPUT is - * the null print buffer. Thes ensures that any system or debug messages - * that are generated without using the above macros are handled correctly. + * TIPC can be configured to send debug messages to the specified print buffer + * (typically DBG_OUTPUT) or to suppress them entirely. */ -#undef TIPC_OUTPUT -#define TIPC_OUTPUT TIPC_CONS +#ifdef CONFIG_TIPC_DEBUG -#undef DBG_OUTPUT -#define DBG_OUTPUT TIPC_NULL +#define dbg(fmt, arg...) \ + do { \ + if (DBG_OUTPUT != TIPC_NULL) \ + tipc_printf(DBG_OUTPUT, fmt, ## arg); \ + } while (0) +#define msg_dbg(msg, txt) \ + do { \ + if (DBG_OUTPUT != TIPC_NULL) \ + tipc_msg_dbg(DBG_OUTPUT, msg, txt); \ + } while (0) +#define dump(fmt, arg...) \ + do { \ + if (DBG_OUTPUT != TIPC_NULL) \ + tipc_dump_dbg(DBG_OUTPUT, fmt, ##arg); \ + } while (0) + +void tipc_msg_dbg(struct print_buf *, struct tipc_msg *, const char *); +void tipc_dump_dbg(struct print_buf *, const char *fmt, ...); + +#else + +#define dbg(fmt, arg...) do {} while (0) +#define msg_dbg(msg, txt) do {} while (0) +#define dump(fmt, arg...) do {} while (0) + +#define tipc_msg_dbg(...) do {} while (0) +#define tipc_dump_dbg(...) do {} while (0) #endif @@ -178,7 +202,7 @@ extern atomic_t tipc_user_count; extern int tipc_core_start(void); extern void tipc_core_stop(void); -extern int tipc_core_start_net(void); +extern int tipc_core_start_net(unsigned long addr); extern void tipc_core_stop_net(void); extern int tipc_handler_start(void); extern void tipc_handler_stop(void); diff --git a/net/tipc/dbg.c b/net/tipc/dbg.c index e809d2a2ce06..29ecae851668 100644 --- a/net/tipc/dbg.c +++ b/net/tipc/dbg.c @@ -2,7 +2,7 @@ * net/tipc/dbg.c: TIPC print buffer routines for debugging * * Copyright (c) 1996-2006, Ericsson AB - * Copyright (c) 2005-2006, Wind River Systems + * Copyright (c) 2005-2007, Wind River Systems * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -38,17 +38,43 @@ #include "config.h" #include "dbg.h" -static char print_string[TIPC_PB_MAX_STR]; -static DEFINE_SPINLOCK(print_lock); +/* + * TIPC pre-defines the following print buffers: + * + * TIPC_NULL : null buffer (i.e. print nowhere) + * TIPC_CONS : system console + * TIPC_LOG : TIPC log buffer + * + * Additional user-defined print buffers are also permitted. + */ -static struct print_buf null_buf = { NULL, 0, NULL, NULL }; -struct print_buf *TIPC_NULL = &null_buf; +static struct print_buf null_buf = { NULL, 0, NULL, 0 }; +struct print_buf *const TIPC_NULL = &null_buf; -static struct print_buf cons_buf = { NULL, 0, NULL, NULL }; -struct print_buf *TIPC_CONS = &cons_buf; +static struct print_buf cons_buf = { NULL, 0, NULL, 1 }; +struct print_buf *const TIPC_CONS = &cons_buf; -static struct print_buf log_buf = { NULL, 0, NULL, NULL }; -struct print_buf *TIPC_LOG = &log_buf; +static struct print_buf log_buf = { NULL, 0, NULL, 1 }; +struct print_buf *const TIPC_LOG = &log_buf; + +/* + * Locking policy when using print buffers. + * + * 1) tipc_printf() uses 'print_lock' to protect against concurrent access to + * 'print_string' when writing to a print buffer. This also protects against + * concurrent writes to the print buffer being written to. + * + * 2) tipc_dump() and tipc_log_XXX() leverage the aforementioned + * use of 'print_lock' to protect against all types of concurrent operations + * on their associated print buffer (not just write operations). + * + * Note: All routines of the form tipc_printbuf_XXX() are lock-free, and rely + * on the caller to prevent simultaneous use of the print buffer(s) being + * manipulated. + */ + +static char print_string[TIPC_PB_MAX_STR]; +static DEFINE_SPINLOCK(print_lock); #define FORMAT(PTR,LEN,FMT) \ @@ -60,27 +86,14 @@ struct print_buf *TIPC_LOG = &log_buf; *(PTR + LEN) = '\0';\ } -/* - * Locking policy when using print buffers. - * - * The following routines use 'print_lock' for protection: - * 1) tipc_printf() - to protect its print buffer(s) and 'print_string' - * 2) TIPC_TEE() - to protect its print buffer(s) - * 3) tipc_dump() - to protect its print buffer(s) and 'print_string' - * 4) tipc_log_XXX() - to protect TIPC_LOG - * - * All routines of the form tipc_printbuf_XXX() rely on the caller to prevent - * simultaneous use of the print buffer(s) being manipulated. - */ - /** * tipc_printbuf_init - initialize print buffer to empty * @pb: pointer to print buffer structure * @raw: pointer to character array used by print buffer * @size: size of character array * - * Makes the print buffer a null device that discards anything written to it - * if the character array is too small (or absent). + * Note: If the character array is too small (or absent), the print buffer + * becomes a null device that discards anything written to it. */ void tipc_printbuf_init(struct print_buf *pb, char *raw, u32 size) @@ -88,13 +101,13 @@ void tipc_printbuf_init(struct print_buf *pb, char *raw, u32 size) pb->buf = raw; pb->crs = raw; pb->size = size; - pb->next = NULL; + pb->echo = 0; if (size < TIPC_PB_MIN_SIZE) { pb->buf = NULL; } else if (raw) { pb->buf[0] = 0; - pb->buf[size-1] = ~0; + pb->buf[size - 1] = ~0; } } @@ -105,7 +118,11 @@ void tipc_printbuf_init(struct print_buf *pb, char *raw, u32 size) void tipc_printbuf_reset(struct print_buf *pb) { - tipc_printbuf_init(pb, pb->buf, pb->size); + if (pb->buf) { + pb->crs = pb->buf; + pb->buf[0] = 0; + pb->buf[pb->size - 1] = ~0; + } } /** @@ -141,7 +158,7 @@ int tipc_printbuf_validate(struct print_buf *pb) if (pb->buf[pb->size - 1] == 0) { cp_buf = kmalloc(pb->size, GFP_ATOMIC); - if (cp_buf != NULL){ + if (cp_buf) { tipc_printbuf_init(&cb, cp_buf, pb->size); tipc_printbuf_move(&cb, pb); tipc_printbuf_move(pb, &cb); @@ -179,15 +196,16 @@ void tipc_printbuf_move(struct print_buf *pb_to, struct print_buf *pb_from) } if (pb_to->size < pb_from->size) { - tipc_printbuf_reset(pb_to); - tipc_printf(pb_to, "*** PRINT BUFFER MOVE ERROR ***"); + strcpy(pb_to->buf, "*** PRINT BUFFER MOVE ERROR ***"); + pb_to->buf[pb_to->size - 1] = ~0; + pb_to->crs = strchr(pb_to->buf, 0); return; } /* Copy data from char after cursor to end (if used) */ len = pb_from->buf + pb_from->size - pb_from->crs - 2; - if ((pb_from->buf[pb_from->size-1] == 0) && (len > 0)) { + if ((pb_from->buf[pb_from->size - 1] == 0) && (len > 0)) { strcpy(pb_to->buf, pb_from->crs + 1); pb_to->crs = pb_to->buf + len; } else @@ -203,8 +221,8 @@ void tipc_printbuf_move(struct print_buf *pb_to, struct print_buf *pb_from) } /** - * tipc_printf - append formatted output to print buffer chain - * @pb: pointer to chain of print buffers (may be NULL) + * tipc_printf - append formatted output to print buffer + * @pb: pointer to print buffer * @fmt: formatted info to be printed */ @@ -213,68 +231,40 @@ void tipc_printf(struct print_buf *pb, const char *fmt, ...) int chars_to_add; int chars_left; char save_char; - struct print_buf *pb_next; spin_lock_bh(&print_lock); + FORMAT(print_string, chars_to_add, fmt); if (chars_to_add >= TIPC_PB_MAX_STR) strcpy(print_string, "*** PRINT BUFFER STRING TOO LONG ***"); - while (pb) { - if (pb == TIPC_CONS) - printk(print_string); - else if (pb->buf) { - chars_left = pb->buf + pb->size - pb->crs - 1; - if (chars_to_add <= chars_left) { - strcpy(pb->crs, print_string); - pb->crs += chars_to_add; - } else if (chars_to_add >= (pb->size - 1)) { - strcpy(pb->buf, print_string + chars_to_add + 1 - - pb->size); - pb->crs = pb->buf + pb->size - 1; - } else { - strcpy(pb->buf, print_string + chars_left); - save_char = print_string[chars_left]; - print_string[chars_left] = 0; - strcpy(pb->crs, print_string); - print_string[chars_left] = save_char; - pb->crs = pb->buf + chars_to_add - chars_left; - } + if (pb->buf) { + chars_left = pb->buf + pb->size - pb->crs - 1; + if (chars_to_add <= chars_left) { + strcpy(pb->crs, print_string); + pb->crs += chars_to_add; + } else if (chars_to_add >= (pb->size - 1)) { + strcpy(pb->buf, print_string + chars_to_add + 1 + - pb->size); + pb->crs = pb->buf + pb->size - 1; + } else { + strcpy(pb->buf, print_string + chars_left); + save_char = print_string[chars_left]; + print_string[chars_left] = 0; + strcpy(pb->crs, print_string); + print_string[chars_left] = save_char; + pb->crs = pb->buf + chars_to_add - chars_left; } - pb_next = pb->next; - pb->next = NULL; - pb = pb_next; } - spin_unlock_bh(&print_lock); -} -/** - * TIPC_TEE - perform next output operation on both print buffers - * @b0: pointer to chain of print buffers (may be NULL) - * @b1: pointer to print buffer to add to chain - * - * Returns pointer to print buffer chain. - */ + if (pb->echo) + printk(print_string); -struct print_buf *TIPC_TEE(struct print_buf *b0, struct print_buf *b1) -{ - struct print_buf *pb = b0; - - if (!b0 || (b0 == b1)) - return b1; - - spin_lock_bh(&print_lock); - while (pb->next) { - if ((pb->next == b1) || (pb->next == b0)) - pb->next = pb->next->next; - else - pb = pb->next; - } - pb->next = b1; spin_unlock_bh(&print_lock); - return b0; } +#ifdef CONFIG_TIPC_DEBUG + /** * print_to_console - write string of bytes to console in multiple chunks */ @@ -321,72 +311,66 @@ static void printbuf_dump(struct print_buf *pb) } /** - * tipc_dump - dump non-console print buffer(s) to console - * @pb: pointer to chain of print buffers + * tipc_dump_dbg - dump (non-console) print buffer to console + * @pb: pointer to print buffer */ -void tipc_dump(struct print_buf *pb, const char *fmt, ...) +void tipc_dump_dbg(struct print_buf *pb, const char *fmt, ...) { - struct print_buf *pb_next; int len; + if (pb == TIPC_CONS) + return; + spin_lock_bh(&print_lock); + FORMAT(print_string, len, fmt); printk(print_string); - for (; pb; pb = pb->next) { - if (pb != TIPC_CONS) { - printk("\n---- Start of %s log dump ----\n\n", - (pb == TIPC_LOG) ? "global" : "local"); - printbuf_dump(pb); - tipc_printbuf_reset(pb); - printk("\n---- End of dump ----\n"); - } - pb_next = pb->next; - pb->next = NULL; - pb = pb_next; - } + printk("\n---- Start of %s log dump ----\n\n", + (pb == TIPC_LOG) ? "global" : "local"); + printbuf_dump(pb); + tipc_printbuf_reset(pb); + printk("\n---- End of dump ----\n"); + spin_unlock_bh(&print_lock); } +#endif + /** - * tipc_log_stop - free up TIPC log print buffer + * tipc_log_resize - change the size of the TIPC log buffer + * @log_size: print buffer size to use */ -void tipc_log_stop(void) +int tipc_log_resize(int log_size) { + int res = 0; + spin_lock_bh(&print_lock); if (TIPC_LOG->buf) { kfree(TIPC_LOG->buf); TIPC_LOG->buf = NULL; } - spin_unlock_bh(&print_lock); -} - -/** - * tipc_log_reinit - (re)initialize TIPC log print buffer - * @log_size: print buffer size to use - */ - -void tipc_log_reinit(int log_size) -{ - tipc_log_stop(); - if (log_size) { if (log_size < TIPC_PB_MIN_SIZE) log_size = TIPC_PB_MIN_SIZE; - spin_lock_bh(&print_lock); + res = TIPC_LOG->echo; tipc_printbuf_init(TIPC_LOG, kmalloc(log_size, GFP_ATOMIC), log_size); - spin_unlock_bh(&print_lock); + TIPC_LOG->echo = res; + res = !TIPC_LOG->buf; } + spin_unlock_bh(&print_lock); + + return res; } /** - * tipc_log_resize - reconfigure size of TIPC log buffer + * tipc_log_resize_cmd - reconfigure size of TIPC log buffer */ -struct sk_buff *tipc_log_resize(const void *req_tlv_area, int req_tlv_space) +struct sk_buff *tipc_log_resize_cmd(const void *req_tlv_area, int req_tlv_space) { u32 value; @@ -397,7 +381,9 @@ struct sk_buff *tipc_log_resize(const void *req_tlv_area, int req_tlv_space) if (value != delimit(value, 0, 32768)) return tipc_cfg_reply_error_string(TIPC_CFG_INVALID_VALUE " (log size must be 0-32768)"); - tipc_log_reinit(value); + if (tipc_log_resize(value)) + return tipc_cfg_reply_error_string( + "unable to create specified log (log size is now 0)"); return tipc_cfg_reply_none(); } @@ -410,27 +396,32 @@ struct sk_buff *tipc_log_dump(void) struct sk_buff *reply; spin_lock_bh(&print_lock); - if (!TIPC_LOG->buf) + if (!TIPC_LOG->buf) { + spin_unlock_bh(&print_lock); reply = tipc_cfg_reply_ultra_string("log not activated\n"); - else if (tipc_printbuf_empty(TIPC_LOG)) + } else if (tipc_printbuf_empty(TIPC_LOG)) { + spin_unlock_bh(&print_lock); reply = tipc_cfg_reply_ultra_string("log is empty\n"); + } else { struct tlv_desc *rep_tlv; struct print_buf pb; int str_len; str_len = min(TIPC_LOG->size, 32768u); + spin_unlock_bh(&print_lock); reply = tipc_cfg_reply_alloc(TLV_SPACE(str_len)); if (reply) { rep_tlv = (struct tlv_desc *)reply->data; tipc_printbuf_init(&pb, TLV_DATA(rep_tlv), str_len); + spin_lock_bh(&print_lock); tipc_printbuf_move(&pb, TIPC_LOG); + spin_unlock_bh(&print_lock); str_len = strlen(TLV_DATA(rep_tlv)) + 1; skb_put(reply, TLV_SPACE(str_len)); TLV_SET(rep_tlv, TIPC_TLV_ULTRA_STRING, NULL, str_len); } } - spin_unlock_bh(&print_lock); return reply; } diff --git a/net/tipc/dbg.h b/net/tipc/dbg.h index c01b085000e0..5ef1bc8f64ef 100644 --- a/net/tipc/dbg.h +++ b/net/tipc/dbg.h @@ -2,7 +2,7 @@ * net/tipc/dbg.h: Include file for TIPC print buffer routines * * Copyright (c) 1997-2006, Ericsson AB - * Copyright (c) 2005-2006, Wind River Systems + * Copyright (c) 2005-2007, Wind River Systems * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -42,14 +42,14 @@ * @buf: pointer to character array containing print buffer contents * @size: size of character array * @crs: pointer to first unused space in character array (i.e. final NUL) - * @next: used to link print buffers when printing to more than one at a time + * @echo: echo output to system console if non-zero */ struct print_buf { char *buf; u32 size; char *crs; - struct print_buf *next; + int echo; }; #define TIPC_PB_MIN_SIZE 64 /* minimum size for a print buffer's array */ @@ -61,10 +61,10 @@ int tipc_printbuf_empty(struct print_buf *pb); int tipc_printbuf_validate(struct print_buf *pb); void tipc_printbuf_move(struct print_buf *pb_to, struct print_buf *pb_from); -void tipc_log_reinit(int log_size); -void tipc_log_stop(void); +int tipc_log_resize(int log_size); -struct sk_buff *tipc_log_resize(const void *req_tlv_area, int req_tlv_space); +struct sk_buff *tipc_log_resize_cmd(const void *req_tlv_area, + int req_tlv_space); struct sk_buff *tipc_log_dump(void); #endif diff --git a/net/tipc/discover.c b/net/tipc/discover.c index 5d643e5721eb..1657f0e795ff 100644 --- a/net/tipc/discover.c +++ b/net/tipc/discover.c @@ -120,9 +120,8 @@ static struct sk_buff *tipc_disc_init_msg(u32 type, if (buf) { msg = buf_msg(buf); - msg_init(msg, LINK_CONFIG, type, TIPC_OK, DSC_H_SIZE, - dest_domain); - msg_set_non_seq(msg); + msg_init(msg, LINK_CONFIG, type, DSC_H_SIZE, dest_domain); + msg_set_non_seq(msg, 1); msg_set_req_links(msg, req_links); msg_set_dest_domain(msg, dest_domain); msg_set_bc_netid(msg, tipc_net_id); @@ -156,11 +155,11 @@ static void disc_dupl_alert(struct bearer *b_ptr, u32 node_addr, /** * tipc_disc_recv_msg - handle incoming link setup message (request or response) * @buf: buffer containing message + * @b_ptr: bearer that message arrived on */ -void tipc_disc_recv_msg(struct sk_buff *buf) +void tipc_disc_recv_msg(struct sk_buff *buf, struct bearer *b_ptr) { - struct bearer *b_ptr = (struct bearer *)TIPC_SKB_CB(buf)->handle; struct link *link; struct tipc_media_addr media_addr; struct tipc_msg *msg = buf_msg(buf); @@ -200,9 +199,8 @@ void tipc_disc_recv_msg(struct sk_buff *buf) dbg(" in own cluster\n"); if (n_ptr == NULL) { n_ptr = tipc_node_create(orig); - } - if (n_ptr == NULL) { - return; + if (!n_ptr) + return; } spin_lock_bh(&n_ptr->lock); link = n_ptr->links[b_ptr->identity]; diff --git a/net/tipc/discover.h b/net/tipc/discover.h index 9fd7587b143a..c36eaeb7d5d0 100644 --- a/net/tipc/discover.h +++ b/net/tipc/discover.h @@ -48,7 +48,7 @@ struct link_req *tipc_disc_init_link_req(struct bearer *b_ptr, void tipc_disc_update_link_req(struct link_req *req); void tipc_disc_stop_link_req(struct link_req *req); -void tipc_disc_recv_msg(struct sk_buff *buf); +void tipc_disc_recv_msg(struct sk_buff *buf, struct bearer *b_ptr); void tipc_disc_link_event(u32 addr, char *name, int up); #if 0 diff --git a/net/tipc/eth_media.c b/net/tipc/eth_media.c index 9cd35eec3e7f..fe43ef7dd7e3 100644 --- a/net/tipc/eth_media.c +++ b/net/tipc/eth_media.c @@ -82,7 +82,7 @@ static int send_msg(struct sk_buff *buf, struct tipc_bearer *tb_ptr, dev->dev_addr, clone->len); dev_queue_xmit(clone); } - return TIPC_OK; + return 0; } /** @@ -101,7 +101,7 @@ static int recv_msg(struct sk_buff *buf, struct net_device *dev, struct eth_bearer *eb_ptr = (struct eth_bearer *)pt->af_packet_priv; u32 size; - if (dev_net(dev) != &init_net) { + if (!net_eq(dev_net(dev), &init_net)) { kfree_skb(buf); return 0; } @@ -113,12 +113,12 @@ static int recv_msg(struct sk_buff *buf, struct net_device *dev, if (likely(buf->len == size)) { buf->next = NULL; tipc_recv_msg(buf, eb_ptr->bearer); - return TIPC_OK; + return 0; } } } kfree_skb(buf); - return TIPC_OK; + return 0; } /** @@ -198,7 +198,7 @@ static int recv_notification(struct notifier_block *nb, unsigned long evt, struct eth_bearer *eb_ptr = ð_bearers[0]; struct eth_bearer *stop = ð_bearers[MAX_ETH_BEARERS]; - if (dev_net(dev) != &init_net) + if (!net_eq(dev_net(dev), &init_net)) return NOTIFY_DONE; while ((eb_ptr->dev != dev)) { diff --git a/net/tipc/link.c b/net/tipc/link.c index 2a26a16e269f..d60113ba4b1b 100644 --- a/net/tipc/link.c +++ b/net/tipc/link.c @@ -51,6 +51,12 @@ /* + * Out-of-range value for link session numbers + */ + +#define INVALID_SESSION 0x10000 + +/* * Limit for deferred reception queue: */ @@ -147,9 +153,21 @@ static void link_print(struct link *l_ptr, struct print_buf *buf, #define LINK_LOG_BUF_SIZE 0 -#define dbg_link(fmt, arg...) do {if (LINK_LOG_BUF_SIZE) tipc_printf(&l_ptr->print_buf, fmt, ## arg); } while(0) -#define dbg_link_msg(msg, txt) do {if (LINK_LOG_BUF_SIZE) tipc_msg_print(&l_ptr->print_buf, msg, txt); } while(0) -#define dbg_link_state(txt) do {if (LINK_LOG_BUF_SIZE) link_print(l_ptr, &l_ptr->print_buf, txt); } while(0) +#define dbg_link(fmt, arg...) \ + do { \ + if (LINK_LOG_BUF_SIZE) \ + tipc_printf(&l_ptr->print_buf, fmt, ## arg); \ + } while (0) +#define dbg_link_msg(msg, txt) \ + do { \ + if (LINK_LOG_BUF_SIZE) \ + tipc_msg_dbg(&l_ptr->print_buf, msg, txt); \ + } while (0) +#define dbg_link_state(txt) \ + do { \ + if (LINK_LOG_BUF_SIZE) \ + link_print(l_ptr, &l_ptr->print_buf, txt); \ + } while (0) #define dbg_link_dump() do { \ if (LINK_LOG_BUF_SIZE) { \ tipc_printf(LOG, "\n\nDumping link <%s>:\n", l_ptr->name); \ @@ -450,9 +468,9 @@ struct link *tipc_link_create(struct bearer *b_ptr, const u32 peer, l_ptr->pmsg = (struct tipc_msg *)&l_ptr->proto_msg; msg = l_ptr->pmsg; - msg_init(msg, LINK_PROTOCOL, RESET_MSG, TIPC_OK, INT_H_SIZE, l_ptr->addr); + msg_init(msg, LINK_PROTOCOL, RESET_MSG, INT_H_SIZE, l_ptr->addr); msg_set_size(msg, sizeof(l_ptr->proto_msg)); - msg_set_session(msg, tipc_random); + msg_set_session(msg, (tipc_random & 0xffff)); msg_set_bearer_id(msg, b_ptr->identity); strcpy((char *)msg_data(msg), if_name); @@ -693,10 +711,10 @@ void tipc_link_reset(struct link *l_ptr) u32 checkpoint = l_ptr->next_in_no; int was_active_link = tipc_link_is_active(l_ptr); - msg_set_session(l_ptr->pmsg, msg_session(l_ptr->pmsg) + 1); + msg_set_session(l_ptr->pmsg, ((msg_session(l_ptr->pmsg) + 1) & 0xffff)); - /* Link is down, accept any session: */ - l_ptr->peer_session = 0; + /* Link is down, accept any session */ + l_ptr->peer_session = INVALID_SESSION; /* Prepare for max packet size negotiation */ link_init_max_pkt(l_ptr); @@ -1110,7 +1128,7 @@ int tipc_link_send_buf(struct link *l_ptr, struct sk_buff *buf) if (bundler) { msg_init(&bundler_hdr, MSG_BUNDLER, OPEN_MSG, - TIPC_OK, INT_H_SIZE, l_ptr->addr); + INT_H_SIZE, l_ptr->addr); skb_copy_to_linear_data(bundler, &bundler_hdr, INT_H_SIZE); skb_trim(bundler, INT_H_SIZE); @@ -1374,7 +1392,7 @@ again: msg_dbg(hdr, ">FRAGMENTING>"); msg_init(&fragm_hdr, MSG_FRAGMENTER, FIRST_FRAGMENT, - TIPC_OK, INT_H_SIZE, msg_destnode(hdr)); + INT_H_SIZE, msg_destnode(hdr)); msg_set_link_selector(&fragm_hdr, sender->publ.ref); msg_set_size(&fragm_hdr, max_pkt); msg_set_fragm_no(&fragm_hdr, 1); @@ -1543,7 +1561,7 @@ u32 tipc_link_push_packet(struct link *l_ptr) l_ptr->retransm_queue_head = mod(++r_q_head); l_ptr->retransm_queue_size = --r_q_size; l_ptr->stats.retransmitted++; - return TIPC_OK; + return 0; } else { l_ptr->stats.bearer_congs++; msg_dbg(buf_msg(buf), "|>DEF-RETR>"); @@ -1562,7 +1580,7 @@ u32 tipc_link_push_packet(struct link *l_ptr) l_ptr->unacked_window = 0; buf_discard(buf); l_ptr->proto_msg_queue = NULL; - return TIPC_OK; + return 0; } else { msg_dbg(buf_msg(buf), "|>DEF-PROT>"); l_ptr->stats.bearer_congs++; @@ -1586,7 +1604,7 @@ u32 tipc_link_push_packet(struct link *l_ptr) msg_set_type(msg, CLOSED_MSG); msg_dbg(msg, ">PUSH-DATA>"); l_ptr->next_out = buf->next; - return TIPC_OK; + return 0; } else { msg_dbg(msg, "|PUSH-DATA|"); l_ptr->stats.bearer_congs++; @@ -1610,8 +1628,8 @@ void tipc_link_push_queue(struct link *l_ptr) do { res = tipc_link_push_packet(l_ptr); - } - while (res == TIPC_OK); + } while (!res); + if (res == PUSH_FAILED) tipc_bearer_schedule(l_ptr->b_ptr, l_ptr); } @@ -1651,7 +1669,7 @@ static void link_retransmit_failure(struct link *l_ptr, struct sk_buff *buf) struct tipc_msg *msg = buf_msg(buf); warn("Retransmission failure on link <%s>\n", l_ptr->name); - tipc_msg_print(TIPC_OUTPUT, msg, ">RETR-FAIL>"); + tipc_msg_dbg(TIPC_OUTPUT, msg, ">RETR-FAIL>"); if (l_ptr->addr) { @@ -1748,21 +1766,6 @@ void tipc_link_retransmit(struct link *l_ptr, struct sk_buff *buf, l_ptr->retransm_queue_head = l_ptr->retransm_queue_size = 0; } -/* - * link_recv_non_seq: Receive packets which are outside - * the link sequence flow - */ - -static void link_recv_non_seq(struct sk_buff *buf) -{ - struct tipc_msg *msg = buf_msg(buf); - - if (msg_user(msg) == LINK_CONFIG) - tipc_disc_recv_msg(buf); - else - tipc_bclink_recv_pkt(buf); -} - /** * link_insert_deferred_queue - insert deferred messages back into receive chain */ @@ -1839,7 +1842,7 @@ void tipc_recv_msg(struct sk_buff *head, struct tipc_bearer *tb_ptr) { read_lock_bh(&tipc_net_lock); while (head) { - struct bearer *b_ptr; + struct bearer *b_ptr = (struct bearer *)tb_ptr; struct node *n_ptr; struct link *l_ptr; struct sk_buff *crs; @@ -1850,9 +1853,6 @@ void tipc_recv_msg(struct sk_buff *head, struct tipc_bearer *tb_ptr) u32 released = 0; int type; - b_ptr = (struct bearer *)tb_ptr; - TIPC_SKB_CB(buf)->handle = b_ptr; - head = head->next; /* Ensure message is well-formed */ @@ -1871,7 +1871,10 @@ void tipc_recv_msg(struct sk_buff *head, struct tipc_bearer *tb_ptr) msg = buf_msg(buf); if (unlikely(msg_non_seq(msg))) { - link_recv_non_seq(buf); + if (msg_user(msg) == LINK_CONFIG) + tipc_disc_recv_msg(buf, b_ptr); + else + tipc_bclink_recv_pkt(buf); continue; } @@ -1978,8 +1981,6 @@ deliver: if (link_recv_changeover_msg(&l_ptr, &buf)) { msg = buf_msg(buf); seq_no = msg_seqno(msg); - TIPC_SKB_CB(buf)->handle - = b_ptr; if (type == ORIGINAL_MSG) goto deliver; goto protocol_check; @@ -2263,7 +2264,8 @@ static void link_recv_proto_msg(struct link *l_ptr, struct sk_buff *buf) switch (msg_type(msg)) { case RESET_MSG: - if (!link_working_unknown(l_ptr) && l_ptr->peer_session) { + if (!link_working_unknown(l_ptr) && + (l_ptr->peer_session != INVALID_SESSION)) { if (msg_session(msg) == l_ptr->peer_session) { dbg("Duplicate RESET: %u<->%u\n", msg_session(msg), l_ptr->peer_session); @@ -2424,7 +2426,7 @@ void tipc_link_changeover(struct link *l_ptr) } msg_init(&tunnel_hdr, CHANGEOVER_PROTOCOL, - ORIGINAL_MSG, TIPC_OK, INT_H_SIZE, l_ptr->addr); + ORIGINAL_MSG, INT_H_SIZE, l_ptr->addr); msg_set_bearer_id(&tunnel_hdr, l_ptr->peer_bearer_id); msg_set_msgcnt(&tunnel_hdr, msgcount); dbg("Link changeover requires %u tunnel messages\n", msgcount); @@ -2479,7 +2481,7 @@ void tipc_link_send_duplicate(struct link *l_ptr, struct link *tunnel) struct tipc_msg tunnel_hdr; msg_init(&tunnel_hdr, CHANGEOVER_PROTOCOL, - DUPLICATE_MSG, TIPC_OK, INT_H_SIZE, l_ptr->addr); + DUPLICATE_MSG, INT_H_SIZE, l_ptr->addr); msg_set_msgcnt(&tunnel_hdr, l_ptr->out_queue_size); msg_set_bearer_id(&tunnel_hdr, l_ptr->peer_bearer_id); iter = l_ptr->first_out; @@ -2672,10 +2674,12 @@ int tipc_link_send_long_buf(struct link *l_ptr, struct sk_buff *buf) u32 pack_sz = link_max_pkt(l_ptr); u32 fragm_sz = pack_sz - INT_H_SIZE; u32 fragm_no = 1; - u32 destaddr = msg_destnode(inmsg); + u32 destaddr; if (msg_short(inmsg)) destaddr = l_ptr->addr; + else + destaddr = msg_destnode(inmsg); if (msg_routed(inmsg)) msg_set_prevnode(inmsg, tipc_own_addr); @@ -2683,7 +2687,7 @@ int tipc_link_send_long_buf(struct link *l_ptr, struct sk_buff *buf) /* Prepare reusable fragment header: */ msg_init(&fragm_hdr, MSG_FRAGMENTER, FIRST_FRAGMENT, - TIPC_OK, INT_H_SIZE, destaddr); + INT_H_SIZE, destaddr); msg_set_link_selector(&fragm_hdr, msg_link_selector(inmsg)); msg_set_long_msgno(&fragm_hdr, mod(l_ptr->long_msg_seq_no++)); msg_set_fragm_no(&fragm_hdr, fragm_no); @@ -2994,7 +2998,7 @@ struct sk_buff *tipc_link_cmd_config(const void *req_tlv_area, int req_tlv_space link_set_supervision_props(l_ptr, new_value); tipc_link_send_proto_msg(l_ptr, STATE_MSG, 0, 0, new_value, 0, 0); - res = TIPC_OK; + res = 0; } break; case TIPC_CMD_SET_LINK_PRI: @@ -3003,14 +3007,14 @@ struct sk_buff *tipc_link_cmd_config(const void *req_tlv_area, int req_tlv_space l_ptr->priority = new_value; tipc_link_send_proto_msg(l_ptr, STATE_MSG, 0, 0, 0, new_value, 0); - res = TIPC_OK; + res = 0; } break; case TIPC_CMD_SET_LINK_WINDOW: if ((new_value >= TIPC_MIN_LINK_WIN) && (new_value <= TIPC_MAX_LINK_WIN)) { tipc_link_set_queue_limits(l_ptr, new_value); - res = TIPC_OK; + res = 0; } break; } @@ -3226,7 +3230,7 @@ int link_control(const char *name, u32 op, u32 val) if (op == TIPC_CMD_UNBLOCK_LINK) { l_ptr->blocked = 0; } - res = TIPC_OK; + res = 0; } tipc_node_unlock(node); } diff --git a/net/tipc/msg.c b/net/tipc/msg.c index 696a8633df75..73dcd00d674e 100644 --- a/net/tipc/msg.c +++ b/net/tipc/msg.c @@ -41,7 +41,9 @@ #include "bearer.h" -void tipc_msg_print(struct print_buf *buf, struct tipc_msg *msg, const char *str) +#ifdef CONFIG_TIPC_DEBUG + +void tipc_msg_dbg(struct print_buf *buf, struct tipc_msg *msg, const char *str) { u32 usr = msg_user(msg); tipc_printf(buf, str); @@ -228,13 +230,10 @@ void tipc_msg_print(struct print_buf *buf, struct tipc_msg *msg, const char *str switch (usr) { case CONN_MANAGER: - case NAME_DISTRIBUTOR: case TIPC_LOW_IMPORTANCE: case TIPC_MEDIUM_IMPORTANCE: case TIPC_HIGH_IMPORTANCE: case TIPC_CRITICAL_IMPORTANCE: - if (msg_short(msg)) - break; /* No error */ switch (msg_errcode(msg)) { case TIPC_OK: break; @@ -315,9 +314,11 @@ void tipc_msg_print(struct print_buf *buf, struct tipc_msg *msg, const char *str } tipc_printf(buf, "\n"); if ((usr == CHANGEOVER_PROTOCOL) && (msg_msgcnt(msg))) { - tipc_msg_print(buf,msg_get_wrapped(msg)," /"); + tipc_msg_dbg(buf, msg_get_wrapped(msg), " /"); } if ((usr == MSG_FRAGMENTER) && (msg_type(msg) == FIRST_FRAGMENT)) { - tipc_msg_print(buf,msg_get_wrapped(msg)," /"); + tipc_msg_dbg(buf, msg_get_wrapped(msg), " /"); } } + +#endif diff --git a/net/tipc/msg.h b/net/tipc/msg.h index ad487e8abcc2..7ee6ae238147 100644 --- a/net/tipc/msg.h +++ b/net/tipc/msg.h @@ -2,7 +2,7 @@ * net/tipc/msg.h: Include file for TIPC message header routines * * Copyright (c) 2000-2007, Ericsson AB - * Copyright (c) 2005-2007, Wind River Systems + * Copyright (c) 2005-2008, Wind River Systems * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -75,6 +75,14 @@ static inline void msg_set_bits(struct tipc_msg *m, u32 w, m->hdr[w] |= htonl(val); } +static inline void msg_swap_words(struct tipc_msg *msg, u32 a, u32 b) +{ + u32 temp = msg->hdr[a]; + + msg->hdr[a] = msg->hdr[b]; + msg->hdr[b] = temp; +} + /* * Word 0 */ @@ -119,9 +127,9 @@ static inline int msg_non_seq(struct tipc_msg *m) return msg_bits(m, 0, 20, 1); } -static inline void msg_set_non_seq(struct tipc_msg *m) +static inline void msg_set_non_seq(struct tipc_msg *m, u32 n) { - msg_set_bits(m, 0, 20, 1, 1); + msg_set_bits(m, 0, 20, 1, n); } static inline int msg_dest_droppable(struct tipc_msg *m) @@ -224,6 +232,25 @@ static inline void msg_set_seqno(struct tipc_msg *m, u32 n) msg_set_bits(m, 2, 0, 0xffff, n); } +/* + * TIPC may utilize the "link ack #" and "link seq #" fields of a short + * message header to hold the destination node for the message, since the + * normal "dest node" field isn't present. This cache is only referenced + * when required, so populating the cache of a longer message header is + * harmless (as long as the header has the two link sequence fields present). + * + * Note: Host byte order is OK here, since the info never goes off-card. + */ + +static inline u32 msg_destnode_cache(struct tipc_msg *m) +{ + return m->hdr[2]; +} + +static inline void msg_set_destnode_cache(struct tipc_msg *m, u32 dnode) +{ + m->hdr[2] = dnode; +} /* * Words 3-10 @@ -325,7 +352,7 @@ static inline struct tipc_msg *msg_get_wrapped(struct tipc_msg *m) +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ w0:|vers |msg usr|hdr sz |n|resrv| packet size | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - w1:|m typ|rsv=0| sequence gap | broadcast ack no | + w1:|m typ| sequence gap | broadcast ack no | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ w2:| link level ack no/bc_gap_from | seq no / bcast_gap_to | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ @@ -388,12 +415,12 @@ static inline struct tipc_msg *msg_get_wrapped(struct tipc_msg *m) static inline u32 msg_seq_gap(struct tipc_msg *m) { - return msg_bits(m, 1, 16, 0xff); + return msg_bits(m, 1, 16, 0x1fff); } static inline void msg_set_seq_gap(struct tipc_msg *m, u32 n) { - msg_set_bits(m, 1, 16, 0xff, n); + msg_set_bits(m, 1, 16, 0x1fff, n); } static inline u32 msg_req_links(struct tipc_msg *m) @@ -696,7 +723,7 @@ static inline u32 msg_tot_importance(struct tipc_msg *m) static inline void msg_init(struct tipc_msg *m, u32 user, u32 type, - u32 err, u32 hsize, u32 destnode) + u32 hsize, u32 destnode) { memset(m, 0, hsize); msg_set_version(m); @@ -705,7 +732,6 @@ static inline void msg_init(struct tipc_msg *m, u32 user, u32 type, msg_set_size(m, hsize); msg_set_prevnode(m, tipc_own_addr); msg_set_type(m, type); - msg_set_errcode(m, err); if (!msg_short(m)) { msg_set_orignode(m, tipc_own_addr); msg_set_destnode(m, destnode); diff --git a/net/tipc/name_distr.c b/net/tipc/name_distr.c index 39fd1619febf..10a69894e2fd 100644 --- a/net/tipc/name_distr.c +++ b/net/tipc/name_distr.c @@ -41,9 +41,6 @@ #include "msg.h" #include "name_distr.h" -#undef DBG_OUTPUT -#define DBG_OUTPUT NULL - #define ITEM_SIZE sizeof(struct distr_item) /** @@ -106,8 +103,7 @@ static struct sk_buff *named_prepare_buf(u32 type, u32 size, u32 dest) if (buf != NULL) { msg = buf_msg(buf); - msg_init(msg, NAME_DISTRIBUTOR, type, TIPC_OK, - LONG_H_SIZE, dest); + msg_init(msg, NAME_DISTRIBUTOR, type, LONG_H_SIZE, dest); msg_set_size(msg, LONG_H_SIZE + size); } return buf; diff --git a/net/tipc/name_table.c b/net/tipc/name_table.c index ac7dfdda7973..cd72e22b132b 100644 --- a/net/tipc/name_table.c +++ b/net/tipc/name_table.c @@ -2,7 +2,7 @@ * net/tipc/name_table.c: TIPC name table code * * Copyright (c) 2000-2006, Ericsson AB - * Copyright (c) 2004-2005, Wind River Systems + * Copyright (c) 2004-2008, Wind River Systems * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -52,9 +52,16 @@ static int tipc_nametbl_size = 1024; /* must be a power of 2 */ * struct sub_seq - container for all published instances of a name sequence * @lower: name sequence lower bound * @upper: name sequence upper bound - * @node_list: circular list of matching publications with >= node scope - * @cluster_list: circular list of matching publications with >= cluster scope - * @zone_list: circular list of matching publications with >= zone scope + * @node_list: circular list of publications made by own node + * @cluster_list: circular list of publications made by own cluster + * @zone_list: circular list of publications made by own zone + * @node_list_size: number of entries in "node_list" + * @cluster_list_size: number of entries in "cluster_list" + * @zone_list_size: number of entries in "zone_list" + * + * Note: The zone list always contains at least one entry, since all + * publications of the associated name sequence belong to it. + * (The cluster and node lists may be empty.) */ struct sub_seq { @@ -63,6 +70,9 @@ struct sub_seq { struct publication *node_list; struct publication *cluster_list; struct publication *zone_list; + u32 node_list_size; + u32 cluster_list_size; + u32 zone_list_size; }; /** @@ -74,7 +84,7 @@ struct sub_seq { * @first_free: array index of first unused sub-sequence entry * @ns_list: links to adjacent name sequences in hash chain * @subscriptions: list of subscriptions for this 'type' - * @lock: spinlock controlling access to name sequence structure + * @lock: spinlock controlling access to publication lists of all sub-sequences */ struct name_seq { @@ -317,6 +327,7 @@ static struct publication *tipc_nameseq_insert_publ(struct name_seq *nseq, dbg("inserting publ %p, node=0x%x publ->node=0x%x, subscr->node=%p\n", publ, node, publ->node, publ->subscr.node); + sseq->zone_list_size++; if (!sseq->zone_list) sseq->zone_list = publ->zone_list_next = publ; else { @@ -325,6 +336,7 @@ static struct publication *tipc_nameseq_insert_publ(struct name_seq *nseq, } if (in_own_cluster(node)) { + sseq->cluster_list_size++; if (!sseq->cluster_list) sseq->cluster_list = publ->cluster_list_next = publ; else { @@ -335,6 +347,7 @@ static struct publication *tipc_nameseq_insert_publ(struct name_seq *nseq, } if (node == tipc_own_addr) { + sseq->node_list_size++; if (!sseq->node_list) sseq->node_list = publ->node_list_next = publ; else { @@ -411,6 +424,7 @@ static struct publication *tipc_nameseq_remove_publ(struct name_seq *nseq, u32 i } else { sseq->zone_list = NULL; } + sseq->zone_list_size--; /* Remove publication from cluster scope list, if present */ @@ -439,6 +453,7 @@ static struct publication *tipc_nameseq_remove_publ(struct name_seq *nseq, u32 i } else { sseq->cluster_list = NULL; } + sseq->cluster_list_size--; } end_cluster: @@ -469,6 +484,7 @@ end_cluster: } else { sseq->node_list = NULL; } + sseq->node_list_size--; } end_node: @@ -709,15 +725,18 @@ int tipc_nametbl_mc_translate(u32 type, u32 lower, u32 upper, u32 limit, if (sseq->lower > upper) break; - publ = sseq->cluster_list; - if (publ && (publ->scope <= limit)) + + publ = sseq->node_list; + if (publ) { do { - if (publ->node == tipc_own_addr) + if (publ->scope <= limit) tipc_port_list_add(dports, publ->ref); - else - res = 1; - publ = publ->cluster_list_next; - } while (publ != sseq->cluster_list); + publ = publ->node_list_next; + } while (publ != sseq->node_list); + } + + if (sseq->cluster_list_size != sseq->node_list_size) + res = 1; } spin_unlock_bh(&seq->lock); @@ -905,6 +924,9 @@ static void nameseq_list(struct name_seq *seq, struct print_buf *buf, u32 depth, struct sub_seq *sseq; char typearea[11]; + if (seq->first_free == 0) + return; + sprintf(typearea, "%-10u", seq->type); if (depth == 1) { @@ -915,7 +937,9 @@ static void nameseq_list(struct name_seq *seq, struct print_buf *buf, u32 depth, for (sseq = seq->sseqs; sseq != &seq->sseqs[seq->first_free]; sseq++) { if ((lowbound <= sseq->upper) && (upbound >= sseq->lower)) { tipc_printf(buf, "%s ", typearea); + spin_lock_bh(&seq->lock); subseq_list(sseq, buf, depth, index); + spin_unlock_bh(&seq->lock); sprintf(typearea, "%10s", " "); } } @@ -1050,15 +1074,12 @@ void tipc_nametbl_dump(void) int tipc_nametbl_init(void) { - int array_size = sizeof(struct hlist_head) * tipc_nametbl_size; - - table.types = kzalloc(array_size, GFP_ATOMIC); + table.types = kcalloc(tipc_nametbl_size, sizeof(struct hlist_head), + GFP_ATOMIC); if (!table.types) return -ENOMEM; - write_lock_bh(&tipc_nametbl_lock); table.local_publ_count = 0; - write_unlock_bh(&tipc_nametbl_lock); return 0; } diff --git a/net/tipc/net.c b/net/tipc/net.c index c39c76201e8e..ec7b04fbdc43 100644 --- a/net/tipc/net.c +++ b/net/tipc/net.c @@ -165,7 +165,7 @@ static int net_init(void) if (!tipc_net.zones) { return -ENOMEM; } - return TIPC_OK; + return 0; } static void net_stop(void) @@ -266,7 +266,7 @@ void tipc_net_route_msg(struct sk_buff *buf) tipc_link_send(buf, dnode, msg_link_selector(msg)); } -int tipc_net_start(void) +int tipc_net_start(u32 addr) { char addr_string[16]; int res; @@ -274,6 +274,10 @@ int tipc_net_start(void) if (tipc_mode != TIPC_NODE_MODE) return -ENOPROTOOPT; + tipc_subscr_stop(); + tipc_cfg_stop(); + + tipc_own_addr = addr; tipc_mode = TIPC_NET_MODE; tipc_named_reinit(); tipc_port_reinit(); @@ -284,14 +288,14 @@ int tipc_net_start(void) (res = tipc_bclink_init())) { return res; } - tipc_subscr_stop(); - tipc_cfg_stop(); + tipc_k_signal((Handler)tipc_subscr_start, 0); tipc_k_signal((Handler)tipc_cfg_init, 0); + info("Started in network mode\n"); info("Own node address %s, network identity %u\n", addr_string_fill(addr_string, tipc_own_addr), tipc_net_id); - return TIPC_OK; + return 0; } void tipc_net_stop(void) diff --git a/net/tipc/net.h b/net/tipc/net.h index a6a0e9976ac9..d154ac2bda9a 100644 --- a/net/tipc/net.h +++ b/net/tipc/net.h @@ -58,7 +58,7 @@ void tipc_net_route_msg(struct sk_buff *buf); struct node *tipc_net_select_remote_node(u32 addr, u32 ref); u32 tipc_net_select_router(u32 addr, u32 ref); -int tipc_net_start(void); +int tipc_net_start(u32 addr); void tipc_net_stop(void); #endif diff --git a/net/tipc/netlink.c b/net/tipc/netlink.c index 6a7f7b4c2595..c387217bb230 100644 --- a/net/tipc/netlink.c +++ b/net/tipc/netlink.c @@ -2,7 +2,7 @@ * net/tipc/netlink.c: TIPC configuration handling * * Copyright (c) 2005-2006, Ericsson AB - * Copyright (c) 2005, Wind River Systems + * Copyright (c) 2005-2007, Wind River Systems * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -45,15 +45,17 @@ static int handle_cmd(struct sk_buff *skb, struct genl_info *info) struct nlmsghdr *req_nlh = info->nlhdr; struct tipc_genlmsghdr *req_userhdr = info->userhdr; int hdr_space = NLMSG_SPACE(GENL_HDRLEN + TIPC_GENL_HDRLEN); + u16 cmd; if ((req_userhdr->cmd & 0xC000) && (!capable(CAP_NET_ADMIN))) - rep_buf = tipc_cfg_reply_error_string(TIPC_CFG_NOT_NET_ADMIN); + cmd = TIPC_CMD_NOT_NET_ADMIN; else - rep_buf = tipc_cfg_do_cmd(req_userhdr->dest, - req_userhdr->cmd, - NLMSG_DATA(req_nlh) + GENL_HDRLEN + TIPC_GENL_HDRLEN, - NLMSG_PAYLOAD(req_nlh, GENL_HDRLEN + TIPC_GENL_HDRLEN), - hdr_space); + cmd = req_userhdr->cmd; + + rep_buf = tipc_cfg_do_cmd(req_userhdr->dest, cmd, + NLMSG_DATA(req_nlh) + GENL_HDRLEN + TIPC_GENL_HDRLEN, + NLMSG_PAYLOAD(req_nlh, GENL_HDRLEN + TIPC_GENL_HDRLEN), + hdr_space); if (rep_buf) { skb_push(rep_buf, hdr_space); diff --git a/net/tipc/node.c b/net/tipc/node.c index 598f4d3a0098..ee952ad60218 100644 --- a/net/tipc/node.c +++ b/net/tipc/node.c @@ -52,16 +52,40 @@ static void node_established_contact(struct node *n_ptr); struct node *tipc_nodes = NULL; /* sorted list of nodes within cluster */ +static DEFINE_SPINLOCK(node_create_lock); + u32 tipc_own_tag = 0; +/** + * tipc_node_create - create neighboring node + * + * Currently, this routine is called by neighbor discovery code, which holds + * net_lock for reading only. We must take node_create_lock to ensure a node + * isn't created twice if two different bearers discover the node at the same + * time. (It would be preferable to switch to holding net_lock in write mode, + * but this is a non-trivial change.) + */ + struct node *tipc_node_create(u32 addr) { struct cluster *c_ptr; struct node *n_ptr; struct node **curr_node; + spin_lock_bh(&node_create_lock); + + for (n_ptr = tipc_nodes; n_ptr; n_ptr = n_ptr->next) { + if (addr < n_ptr->addr) + break; + if (addr == n_ptr->addr) { + spin_unlock_bh(&node_create_lock); + return n_ptr; + } + } + n_ptr = kzalloc(sizeof(*n_ptr),GFP_ATOMIC); if (!n_ptr) { + spin_unlock_bh(&node_create_lock); warn("Node creation failed, no memory\n"); return NULL; } @@ -71,6 +95,7 @@ struct node *tipc_node_create(u32 addr) c_ptr = tipc_cltr_create(addr); } if (!c_ptr) { + spin_unlock_bh(&node_create_lock); kfree(n_ptr); return NULL; } @@ -91,6 +116,7 @@ struct node *tipc_node_create(u32 addr) } } (*curr_node) = n_ptr; + spin_unlock_bh(&node_create_lock); return n_ptr; } @@ -574,12 +600,14 @@ u32 tipc_available_nodes(const u32 domain) struct node *n_ptr; u32 cnt = 0; + read_lock_bh(&tipc_net_lock); for (n_ptr = tipc_nodes; n_ptr; n_ptr = n_ptr->next) { if (!in_scope(domain, n_ptr->addr)) continue; if (tipc_node_is_up(n_ptr)) cnt++; } + read_unlock_bh(&tipc_net_lock); return cnt; } @@ -599,19 +627,26 @@ struct sk_buff *tipc_node_get_nodes(const void *req_tlv_area, int req_tlv_space) return tipc_cfg_reply_error_string(TIPC_CFG_INVALID_VALUE " (network address)"); - if (!tipc_nodes) + read_lock_bh(&tipc_net_lock); + if (!tipc_nodes) { + read_unlock_bh(&tipc_net_lock); return tipc_cfg_reply_none(); + } /* For now, get space for all other nodes (will need to modify this when slave nodes are supported */ payload_size = TLV_SPACE(sizeof(node_info)) * (tipc_max_nodes - 1); - if (payload_size > 32768u) + if (payload_size > 32768u) { + read_unlock_bh(&tipc_net_lock); return tipc_cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED " (too many nodes)"); + } buf = tipc_cfg_reply_alloc(payload_size); - if (!buf) + if (!buf) { + read_unlock_bh(&tipc_net_lock); return NULL; + } /* Add TLVs for all nodes in scope */ @@ -624,6 +659,7 @@ struct sk_buff *tipc_node_get_nodes(const void *req_tlv_area, int req_tlv_space) &node_info, sizeof(node_info)); } + read_unlock_bh(&tipc_net_lock); return buf; } @@ -646,16 +682,22 @@ struct sk_buff *tipc_node_get_links(const void *req_tlv_area, int req_tlv_space) if (tipc_mode != TIPC_NET_MODE) return tipc_cfg_reply_none(); + read_lock_bh(&tipc_net_lock); + /* Get space for all unicast links + multicast link */ payload_size = TLV_SPACE(sizeof(link_info)) * (tipc_net.zones[tipc_zone(tipc_own_addr)]->links + 1); - if (payload_size > 32768u) + if (payload_size > 32768u) { + read_unlock_bh(&tipc_net_lock); return tipc_cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED " (too many links)"); + } buf = tipc_cfg_reply_alloc(payload_size); - if (!buf) + if (!buf) { + read_unlock_bh(&tipc_net_lock); return NULL; + } /* Add TLV for broadcast link */ @@ -671,6 +713,7 @@ struct sk_buff *tipc_node_get_links(const void *req_tlv_area, int req_tlv_space) if (!in_scope(domain, n_ptr->addr)) continue; + tipc_node_lock(n_ptr); for (i = 0; i < MAX_BEARERS; i++) { if (!n_ptr->links[i]) continue; @@ -680,7 +723,9 @@ struct sk_buff *tipc_node_get_links(const void *req_tlv_area, int req_tlv_space) tipc_cfg_append_tlv(buf, TIPC_TLV_LINK_INFO, &link_info, sizeof(link_info)); } + tipc_node_unlock(n_ptr); } + read_unlock_bh(&tipc_net_lock); return buf; } diff --git a/net/tipc/port.c b/net/tipc/port.c index 2f5806410c64..e70d27ea6578 100644 --- a/net/tipc/port.c +++ b/net/tipc/port.c @@ -2,7 +2,7 @@ * net/tipc/port.c: TIPC port code * * Copyright (c) 1992-2007, Ericsson AB - * Copyright (c) 2004-2007, Wind River Systems + * Copyright (c) 2004-2008, Wind River Systems * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -211,12 +211,12 @@ exit: } /** - * tipc_createport_raw - create a native TIPC port + * tipc_createport_raw - create a generic TIPC port * - * Returns local port reference + * Returns pointer to (locked) TIPC port, or NULL if unable to create it */ -u32 tipc_createport_raw(void *usr_handle, +struct tipc_port *tipc_createport_raw(void *usr_handle, u32 (*dispatcher)(struct tipc_port *, struct sk_buff *), void (*wakeup)(struct tipc_port *), const u32 importance) @@ -228,26 +228,21 @@ u32 tipc_createport_raw(void *usr_handle, p_ptr = kzalloc(sizeof(*p_ptr), GFP_ATOMIC); if (!p_ptr) { warn("Port creation failed, no memory\n"); - return 0; + return NULL; } ref = tipc_ref_acquire(p_ptr, &p_ptr->publ.lock); if (!ref) { warn("Port creation failed, reference table exhausted\n"); kfree(p_ptr); - return 0; + return NULL; } - tipc_port_lock(ref); p_ptr->publ.usr_handle = usr_handle; p_ptr->publ.max_pkt = MAX_PKT_DEFAULT; p_ptr->publ.ref = ref; msg = &p_ptr->publ.phdr; - msg_init(msg, TIPC_LOW_IMPORTANCE, TIPC_NAMED_MSG, TIPC_OK, LONG_H_SIZE, - 0); - msg_set_orignode(msg, tipc_own_addr); - msg_set_prevnode(msg, tipc_own_addr); + msg_init(msg, importance, TIPC_NAMED_MSG, LONG_H_SIZE, 0); msg_set_origport(msg, ref); - msg_set_importance(msg,importance); p_ptr->last_in_seqno = 41; p_ptr->sent = 1; INIT_LIST_HEAD(&p_ptr->wait_list); @@ -262,8 +257,7 @@ u32 tipc_createport_raw(void *usr_handle, INIT_LIST_HEAD(&p_ptr->port_list); list_add_tail(&p_ptr->port_list, &ports); spin_unlock_bh(&tipc_port_list_lock); - tipc_port_unlock(p_ptr); - return ref; + return &(p_ptr->publ); } int tipc_deleteport(u32 ref) @@ -297,7 +291,7 @@ int tipc_deleteport(u32 ref) kfree(p_ptr); dbg("Deleted port %u\n", ref); tipc_net_route_msg(buf); - return TIPC_OK; + return 0; } /** @@ -342,7 +336,7 @@ int tipc_portunreliable(u32 ref, unsigned int *isunreliable) return -EINVAL; *isunreliable = port_unreliable(p_ptr); tipc_port_unlock(p_ptr); - return TIPC_OK; + return 0; } int tipc_set_portunreliable(u32 ref, unsigned int isunreliable) @@ -354,7 +348,7 @@ int tipc_set_portunreliable(u32 ref, unsigned int isunreliable) return -EINVAL; msg_set_src_droppable(&p_ptr->publ.phdr, (isunreliable != 0)); tipc_port_unlock(p_ptr); - return TIPC_OK; + return 0; } static int port_unreturnable(struct port *p_ptr) @@ -371,7 +365,7 @@ int tipc_portunreturnable(u32 ref, unsigned int *isunrejectable) return -EINVAL; *isunrejectable = port_unreturnable(p_ptr); tipc_port_unlock(p_ptr); - return TIPC_OK; + return 0; } int tipc_set_portunreturnable(u32 ref, unsigned int isunrejectable) @@ -383,7 +377,7 @@ int tipc_set_portunreturnable(u32 ref, unsigned int isunrejectable) return -EINVAL; msg_set_dest_droppable(&p_ptr->publ.phdr, (isunrejectable != 0)); tipc_port_unlock(p_ptr); - return TIPC_OK; + return 0; } /* @@ -402,10 +396,10 @@ static struct sk_buff *port_build_proto_msg(u32 destport, u32 destnode, buf = buf_acquire(LONG_H_SIZE); if (buf) { msg = buf_msg(buf); - msg_init(msg, usr, type, err, LONG_H_SIZE, destnode); + msg_init(msg, usr, type, LONG_H_SIZE, destnode); + msg_set_errcode(msg, err); msg_set_destport(msg, destport); msg_set_origport(msg, origport); - msg_set_destnode(msg, destnode); msg_set_orignode(msg, orignode); msg_set_transp_seqno(msg, seqno); msg_set_msgcnt(msg, ack); @@ -446,17 +440,19 @@ int tipc_reject_msg(struct sk_buff *buf, u32 err) return data_sz; } rmsg = buf_msg(rbuf); - msg_init(rmsg, imp, msg_type(msg), err, hdr_sz, msg_orignode(msg)); + msg_init(rmsg, imp, msg_type(msg), hdr_sz, msg_orignode(msg)); + msg_set_errcode(rmsg, err); msg_set_destport(rmsg, msg_origport(msg)); - msg_set_prevnode(rmsg, tipc_own_addr); msg_set_origport(rmsg, msg_destport(msg)); - if (msg_short(msg)) + if (msg_short(msg)) { msg_set_orignode(rmsg, tipc_own_addr); - else + /* leave name type & instance as zeroes */ + } else { msg_set_orignode(rmsg, msg_destnode(msg)); + msg_set_nametype(rmsg, msg_nametype(msg)); + msg_set_nameinst(rmsg, msg_nameinst(msg)); + } msg_set_size(rmsg, data_sz + hdr_sz); - msg_set_nametype(rmsg, msg_nametype(msg)); - msg_set_nameinst(rmsg, msg_nameinst(msg)); skb_copy_to_linear_data_offset(rbuf, hdr_sz, msg_data(msg), data_sz); /* send self-abort message when rejecting on a connected port */ @@ -778,6 +774,7 @@ void tipc_port_reinit(void) msg = &p_ptr->publ.phdr; if (msg_orignode(msg) == tipc_own_addr) break; + msg_set_prevnode(msg, tipc_own_addr); msg_set_orignode(msg, tipc_own_addr); } spin_unlock_bh(&tipc_port_list_lock); @@ -838,16 +835,13 @@ static void port_dispatcher_sigh(void *dummy) u32 peer_node = port_peernode(p_ptr); tipc_port_unlock(p_ptr); + if (unlikely(!cb)) + goto reject; if (unlikely(!connected)) { - if (unlikely(published)) + if (tipc_connect2port(dref, &orig)) goto reject; - tipc_connect2port(dref,&orig); - } - if (unlikely(msg_origport(msg) != peer_port)) - goto reject; - if (unlikely(msg_orignode(msg) != peer_node)) - goto reject; - if (unlikely(!cb)) + } else if ((msg_origport(msg) != peer_port) || + (msg_orignode(msg) != peer_node)) goto reject; if (unlikely(++p_ptr->publ.conn_unacked >= TIPC_FLOW_CONTROL_WIN)) @@ -862,9 +856,7 @@ static void port_dispatcher_sigh(void *dummy) tipc_msg_event cb = up_ptr->msg_cb; tipc_port_unlock(p_ptr); - if (unlikely(connected)) - goto reject; - if (unlikely(!cb)) + if (unlikely(!cb || connected)) goto reject; skb_pull(buf, msg_hdr_sz(msg)); cb(usr_handle, dref, &buf, msg_data(msg), @@ -877,11 +869,7 @@ static void port_dispatcher_sigh(void *dummy) tipc_named_msg_event cb = up_ptr->named_msg_cb; tipc_port_unlock(p_ptr); - if (unlikely(connected)) - goto reject; - if (unlikely(!cb)) - goto reject; - if (unlikely(!published)) + if (unlikely(!cb || connected || !published)) goto reject; dseq.type = msg_nametype(msg); dseq.lower = msg_nameinst(msg); @@ -908,11 +896,10 @@ err: u32 peer_node = port_peernode(p_ptr); tipc_port_unlock(p_ptr); - if (!connected || !cb) - break; - if (msg_origport(msg) != peer_port) + if (!cb || !connected) break; - if (msg_orignode(msg) != peer_node) + if ((msg_origport(msg) != peer_port) || + (msg_orignode(msg) != peer_node)) break; tipc_disconnect(dref); skb_pull(buf, msg_hdr_sz(msg)); @@ -924,7 +911,7 @@ err: tipc_msg_err_event cb = up_ptr->err_cb; tipc_port_unlock(p_ptr); - if (connected || !cb) + if (!cb || connected) break; skb_pull(buf, msg_hdr_sz(msg)); cb(usr_handle, dref, &buf, msg_data(msg), @@ -937,7 +924,7 @@ err: up_ptr->named_err_cb; tipc_port_unlock(p_ptr); - if (connected || !cb) + if (!cb || connected) break; dseq.type = msg_nametype(msg); dseq.lower = msg_nameinst(msg); @@ -976,7 +963,7 @@ static u32 port_dispatcher(struct tipc_port *dummy, struct sk_buff *buf) tipc_k_signal((Handler)port_dispatcher_sigh, 0); } spin_unlock_bh(&queue_lock); - return TIPC_OK; + return 0; } /* @@ -1053,15 +1040,14 @@ int tipc_createport(u32 user_ref, { struct user_port *up_ptr; struct port *p_ptr; - u32 ref; up_ptr = kmalloc(sizeof(*up_ptr), GFP_ATOMIC); if (!up_ptr) { warn("Port creation failed, no memory\n"); return -ENOMEM; } - ref = tipc_createport_raw(NULL, port_dispatcher, port_wakeup, importance); - p_ptr = tipc_port_lock(ref); + p_ptr = (struct port *)tipc_createport_raw(NULL, port_dispatcher, + port_wakeup, importance); if (!p_ptr) { kfree(up_ptr); return -ENOMEM; @@ -1081,16 +1067,15 @@ int tipc_createport(u32 user_ref, INIT_LIST_HEAD(&up_ptr->uport_list); tipc_reg_add_port(up_ptr); *portref = p_ptr->publ.ref; - dbg(" tipc_createport: %x with ref %u\n", p_ptr, p_ptr->publ.ref); tipc_port_unlock(p_ptr); - return TIPC_OK; + return 0; } int tipc_ownidentity(u32 ref, struct tipc_portid *id) { id->ref = ref; id->node = tipc_own_addr; - return TIPC_OK; + return 0; } int tipc_portimportance(u32 ref, unsigned int *importance) @@ -1102,7 +1087,7 @@ int tipc_portimportance(u32 ref, unsigned int *importance) return -EINVAL; *importance = (unsigned int)msg_importance(&p_ptr->publ.phdr); tipc_port_unlock(p_ptr); - return TIPC_OK; + return 0; } int tipc_set_portimportance(u32 ref, unsigned int imp) @@ -1117,7 +1102,7 @@ int tipc_set_portimportance(u32 ref, unsigned int imp) return -EINVAL; msg_set_importance(&p_ptr->publ.phdr, (u32)imp); tipc_port_unlock(p_ptr); - return TIPC_OK; + return 0; } @@ -1152,7 +1137,7 @@ int tipc_publish(u32 ref, unsigned int scope, struct tipc_name_seq const *seq) list_add(&publ->pport_list, &p_ptr->publications); p_ptr->pub_count++; p_ptr->publ.published = 1; - res = TIPC_OK; + res = 0; } exit: tipc_port_unlock(p_ptr); @@ -1175,7 +1160,7 @@ int tipc_withdraw(u32 ref, unsigned int scope, struct tipc_name_seq const *seq) tipc_nametbl_withdraw(publ->type, publ->lower, publ->ref, publ->key); } - res = TIPC_OK; + res = 0; } else { list_for_each_entry_safe(publ, tpubl, &p_ptr->publications, pport_list) { @@ -1189,7 +1174,7 @@ int tipc_withdraw(u32 ref, unsigned int scope, struct tipc_name_seq const *seq) break; tipc_nametbl_withdraw(publ->type, publ->lower, publ->ref, publ->key); - res = TIPC_OK; + res = 0; break; } } @@ -1233,7 +1218,7 @@ int tipc_connect2port(u32 ref, struct tipc_portid const *peer) tipc_nodesub_subscribe(&p_ptr->subscription,peer->node, (void *)(unsigned long)ref, (net_ev_handler)port_handle_node_down); - res = TIPC_OK; + res = 0; exit: tipc_port_unlock(p_ptr); p_ptr->publ.max_pkt = tipc_link_get_max_pkt(peer->node, ref); @@ -1255,7 +1240,7 @@ int tipc_disconnect_port(struct tipc_port *tp_ptr) /* let timer expire on it's own to avoid deadlock! */ tipc_nodesub_unsubscribe( &((struct port *)tp_ptr)->subscription); - res = TIPC_OK; + res = 0; } else { res = -ENOTCONN; } @@ -1320,7 +1305,7 @@ int tipc_isconnected(u32 ref, int *isconnected) return -EINVAL; *isconnected = p_ptr->publ.connected; tipc_port_unlock(p_ptr); - return TIPC_OK; + return 0; } int tipc_peer(u32 ref, struct tipc_portid *peer) @@ -1334,7 +1319,7 @@ int tipc_peer(u32 ref, struct tipc_portid *peer) if (p_ptr->publ.connected) { peer->ref = port_peerport(p_ptr); peer->node = port_peernode(p_ptr); - res = TIPC_OK; + res = 0; } else res = -ENOTCONN; tipc_port_unlock(p_ptr); diff --git a/net/tipc/ref.c b/net/tipc/ref.c index 89cbab24d08f..414fc34b8bea 100644 --- a/net/tipc/ref.c +++ b/net/tipc/ref.c @@ -123,7 +123,7 @@ int tipc_ref_table_init(u32 requested_size, u32 start) tipc_ref_table.index_mask = actual_size - 1; tipc_ref_table.start_mask = start & ~tipc_ref_table.index_mask; - return TIPC_OK; + return 0; } /** @@ -142,9 +142,13 @@ void tipc_ref_table_stop(void) /** * tipc_ref_acquire - create reference to an object * - * Return a unique reference value which can be translated back to the pointer - * 'object' at a later time. Also, pass back a pointer to the lock protecting - * the object, but without locking it. + * Register an object pointer in reference table and lock the object. + * Returns a unique reference value that is used from then on to retrieve the + * object pointer, or to determine that the object has been deregistered. + * + * Note: The object is returned in the locked state so that the caller can + * register a partially initialized object, without running the risk that + * the object will be accessed before initialization is complete. */ u32 tipc_ref_acquire(void *object, spinlock_t **lock) @@ -178,13 +182,13 @@ u32 tipc_ref_acquire(void *object, spinlock_t **lock) ref = (next_plus_upper & ~index_mask) + index; entry->ref = ref; entry->object = object; - spin_unlock_bh(&entry->lock); *lock = &entry->lock; } else if (tipc_ref_table.init_point < tipc_ref_table.capacity) { index = tipc_ref_table.init_point++; entry = &(tipc_ref_table.entries[index]); spin_lock_init(&entry->lock); + spin_lock_bh(&entry->lock); ref = tipc_ref_table.start_mask + index; entry->ref = ref; entry->object = object; diff --git a/net/tipc/socket.c b/net/tipc/socket.c index 230f9ca2ad6b..1848693ebb82 100644 --- a/net/tipc/socket.c +++ b/net/tipc/socket.c @@ -2,7 +2,7 @@ * net/tipc/socket.c: TIPC socket API * * Copyright (c) 2001-2007, Ericsson AB - * Copyright (c) 2004-2007, Wind River Systems + * Copyright (c) 2004-2008, Wind River Systems * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -63,6 +63,7 @@ struct tipc_sock { struct sock sk; struct tipc_port *p; + struct tipc_portid peer_name; }; #define tipc_sk(sk) ((struct tipc_sock *)(sk)) @@ -188,7 +189,7 @@ static int tipc_create(struct net *net, struct socket *sock, int protocol) const struct proto_ops *ops; socket_state state; struct sock *sk; - u32 portref; + struct tipc_port *tp_ptr; /* Validate arguments */ @@ -224,9 +225,9 @@ static int tipc_create(struct net *net, struct socket *sock, int protocol) /* Allocate TIPC port for socket to use */ - portref = tipc_createport_raw(sk, &dispatch, &wakeupdispatch, - TIPC_LOW_IMPORTANCE); - if (unlikely(portref == 0)) { + tp_ptr = tipc_createport_raw(sk, &dispatch, &wakeupdispatch, + TIPC_LOW_IMPORTANCE); + if (unlikely(!tp_ptr)) { sk_free(sk); return -ENOMEM; } @@ -239,12 +240,14 @@ static int tipc_create(struct net *net, struct socket *sock, int protocol) sock_init_data(sock, sk); sk->sk_rcvtimeo = msecs_to_jiffies(CONN_TIMEOUT_DEFAULT); sk->sk_backlog_rcv = backlog_rcv; - tipc_sk(sk)->p = tipc_get_port(portref); + tipc_sk(sk)->p = tp_ptr; + + spin_unlock_bh(tp_ptr->lock); if (sock->state == SS_READY) { - tipc_set_portunreturnable(portref, 1); + tipc_set_portunreturnable(tp_ptr->ref, 1); if (sock->type == SOCK_DGRAM) - tipc_set_portunreliable(portref, 1); + tipc_set_portunreliable(tp_ptr->ref, 1); } atomic_inc(&tipc_user_count); @@ -375,27 +378,29 @@ static int bind(struct socket *sock, struct sockaddr *uaddr, int uaddr_len) * @sock: socket structure * @uaddr: area for returned socket address * @uaddr_len: area for returned length of socket address - * @peer: 0 to obtain socket name, 1 to obtain peer socket name + * @peer: 0 = own ID, 1 = current peer ID, 2 = current/former peer ID * * Returns 0 on success, errno otherwise * - * NOTE: This routine doesn't need to take the socket lock since it doesn't - * access any non-constant socket information. + * NOTE: This routine doesn't need to take the socket lock since it only + * accesses socket information that is unchanging (or which changes in + * a completely predictable manner). */ static int get_name(struct socket *sock, struct sockaddr *uaddr, int *uaddr_len, int peer) { struct sockaddr_tipc *addr = (struct sockaddr_tipc *)uaddr; - u32 portref = tipc_sk_port(sock->sk)->ref; - u32 res; + struct tipc_sock *tsock = tipc_sk(sock->sk); if (peer) { - res = tipc_peer(portref, &addr->addr.id); - if (res) - return res; + if ((sock->state != SS_CONNECTED) && + ((peer != 2) || (sock->state != SS_DISCONNECTING))) + return -ENOTCONN; + addr->addr.id.ref = tsock->peer_name.ref; + addr->addr.id.node = tsock->peer_name.node; } else { - tipc_ownidentity(portref, &addr->addr.id); + tipc_ownidentity(tsock->p->ref, &addr->addr.id); } *uaddr_len = sizeof(*addr); @@ -764,18 +769,17 @@ exit: static int auto_connect(struct socket *sock, struct tipc_msg *msg) { - struct tipc_port *tport = tipc_sk_port(sock->sk); - struct tipc_portid peer; + struct tipc_sock *tsock = tipc_sk(sock->sk); if (msg_errcode(msg)) { sock->state = SS_DISCONNECTING; return -ECONNREFUSED; } - peer.ref = msg_origport(msg); - peer.node = msg_orignode(msg); - tipc_connect2port(tport->ref, &peer); - tipc_set_portimportance(tport->ref, msg_importance(msg)); + tsock->peer_name.ref = msg_origport(msg); + tsock->peer_name.node = msg_orignode(msg); + tipc_connect2port(tsock->p->ref, &tsock->peer_name); + tipc_set_portimportance(tsock->p->ref, msg_importance(msg)); sock->state = SS_CONNECTED; return 0; } @@ -1131,7 +1135,7 @@ restart: /* Loop around if more data is required */ if ((sz_copied < buf_len) /* didn't get all requested data */ - && (!skb_queue_empty(&sock->sk->sk_receive_queue) || + && (!skb_queue_empty(&sk->sk_receive_queue) || (flags & MSG_WAITALL)) /* ... and more is ready or required */ && (!(flags & MSG_PEEK)) /* ... and aren't just peeking at data */ @@ -1527,9 +1531,9 @@ static int accept(struct socket *sock, struct socket *new_sock, int flags) res = tipc_create(sock_net(sock->sk), new_sock, 0); if (!res) { struct sock *new_sk = new_sock->sk; - struct tipc_port *new_tport = tipc_sk_port(new_sk); + struct tipc_sock *new_tsock = tipc_sk(new_sk); + struct tipc_port *new_tport = new_tsock->p; u32 new_ref = new_tport->ref; - struct tipc_portid id; struct tipc_msg *msg = buf_msg(buf); lock_sock(new_sk); @@ -1543,9 +1547,9 @@ static int accept(struct socket *sock, struct socket *new_sock, int flags) /* Connect new socket to it's peer */ - id.ref = msg_origport(msg); - id.node = msg_orignode(msg); - tipc_connect2port(new_ref, &id); + new_tsock->peer_name.ref = msg_origport(msg); + new_tsock->peer_name.node = msg_orignode(msg); + tipc_connect2port(new_ref, &new_tsock->peer_name); new_sock->state = SS_CONNECTED; tipc_set_portimportance(new_ref, msg_importance(msg)); diff --git a/net/tipc/subscr.c b/net/tipc/subscr.c index 8c01ccd3626c..0326d3060bc7 100644 --- a/net/tipc/subscr.c +++ b/net/tipc/subscr.c @@ -1,8 +1,8 @@ /* - * net/tipc/subscr.c: TIPC subscription service + * net/tipc/subscr.c: TIPC network topology service * * Copyright (c) 2000-2006, Ericsson AB - * Copyright (c) 2005, Wind River Systems + * Copyright (c) 2005-2007, Wind River Systems * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -36,27 +36,24 @@ #include "core.h" #include "dbg.h" -#include "subscr.h" #include "name_table.h" +#include "port.h" #include "ref.h" +#include "subscr.h" /** * struct subscriber - TIPC network topology subscriber - * @ref: object reference to subscriber object itself - * @lock: pointer to spinlock controlling access to subscriber object + * @port_ref: object reference to server port connecting to subscriber + * @lock: pointer to spinlock controlling access to subscriber's server port * @subscriber_list: adjacent subscribers in top. server's list of subscribers * @subscription_list: list of subscription objects for this subscriber - * @port_ref: object reference to port used to communicate with subscriber - * @swap: indicates if subscriber uses opposite endianness in its messages */ struct subscriber { - u32 ref; + u32 port_ref; spinlock_t *lock; struct list_head subscriber_list; struct list_head subscription_list; - u32 port_ref; - int swap; }; /** @@ -88,13 +85,14 @@ static struct top_srv topsrv = { 0 }; static u32 htohl(u32 in, int swap) { - char *c = (char *)∈ - - return swap ? ((c[3] << 3) + (c[2] << 2) + (c[1] << 1) + c[0]) : in; + return swap ? (u32)___constant_swab32(in) : in; } /** * subscr_send_event - send a message containing a tipc_event to the subscriber + * + * Note: Must not hold subscriber's server port lock, since tipc_send() will + * try to take the lock if the message is rejected and returned! */ static void subscr_send_event(struct subscription *sub, @@ -109,12 +107,12 @@ static void subscr_send_event(struct subscription *sub, msg_sect.iov_base = (void *)&sub->evt; msg_sect.iov_len = sizeof(struct tipc_event); - sub->evt.event = htohl(event, sub->owner->swap); - sub->evt.found_lower = htohl(found_lower, sub->owner->swap); - sub->evt.found_upper = htohl(found_upper, sub->owner->swap); - sub->evt.port.ref = htohl(port_ref, sub->owner->swap); - sub->evt.port.node = htohl(node, sub->owner->swap); - tipc_send(sub->owner->port_ref, 1, &msg_sect); + sub->evt.event = htohl(event, sub->swap); + sub->evt.found_lower = htohl(found_lower, sub->swap); + sub->evt.found_upper = htohl(found_upper, sub->swap); + sub->evt.port.ref = htohl(port_ref, sub->swap); + sub->evt.port.node = htohl(node, sub->swap); + tipc_send(sub->server_ref, 1, &msg_sect); } /** @@ -151,13 +149,12 @@ void tipc_subscr_report_overlap(struct subscription *sub, u32 node, int must) { - dbg("Rep overlap %u:%u,%u<->%u,%u\n", sub->seq.type, sub->seq.lower, - sub->seq.upper, found_lower, found_upper); if (!tipc_subscr_overlap(sub, found_lower, found_upper)) return; if (!must && !(sub->filter & TIPC_SUB_PORTS)) return; - subscr_send_event(sub, found_lower, found_upper, event, port_ref, node); + + sub->event_cb(sub, found_lower, found_upper, event, port_ref, node); } /** @@ -166,20 +163,18 @@ void tipc_subscr_report_overlap(struct subscription *sub, static void subscr_timeout(struct subscription *sub) { - struct subscriber *subscriber; - u32 subscriber_ref; + struct port *server_port; - /* Validate subscriber reference (in case subscriber is terminating) */ + /* Validate server port reference (in case subscriber is terminating) */ - subscriber_ref = sub->owner->ref; - subscriber = (struct subscriber *)tipc_ref_lock(subscriber_ref); - if (subscriber == NULL) + server_port = tipc_port_lock(sub->server_ref); + if (server_port == NULL) return; /* Validate timeout (in case subscription is being cancelled) */ if (sub->timeout == TIPC_WAIT_FOREVER) { - tipc_ref_unlock(subscriber_ref); + tipc_port_unlock(server_port); return; } @@ -187,19 +182,21 @@ static void subscr_timeout(struct subscription *sub) tipc_nametbl_unsubscribe(sub); - /* Notify subscriber of timeout, then unlink subscription */ + /* Unlink subscription from subscriber */ - subscr_send_event(sub, - sub->evt.s.seq.lower, - sub->evt.s.seq.upper, - TIPC_SUBSCR_TIMEOUT, - 0, - 0); list_del(&sub->subscription_list); + /* Release subscriber's server port */ + + tipc_port_unlock(server_port); + + /* Notify subscriber of timeout */ + + subscr_send_event(sub, sub->evt.s.seq.lower, sub->evt.s.seq.upper, + TIPC_SUBSCR_TIMEOUT, 0, 0); + /* Now destroy subscription */ - tipc_ref_unlock(subscriber_ref); k_term_timer(&sub->timer); kfree(sub); atomic_dec(&topsrv.subscription_count); @@ -208,7 +205,7 @@ static void subscr_timeout(struct subscription *sub) /** * subscr_del - delete a subscription within a subscription list * - * Called with subscriber locked. + * Called with subscriber port locked. */ static void subscr_del(struct subscription *sub) @@ -222,7 +219,7 @@ static void subscr_del(struct subscription *sub) /** * subscr_terminate - terminate communication with a subscriber * - * Called with subscriber locked. Routine must temporarily release this lock + * Called with subscriber port locked. Routine must temporarily release lock * to enable subscription timeout routine(s) to finish without deadlocking; * the lock is then reclaimed to allow caller to release it upon return. * (This should work even in the unlikely event some other thread creates @@ -232,14 +229,21 @@ static void subscr_del(struct subscription *sub) static void subscr_terminate(struct subscriber *subscriber) { + u32 port_ref; struct subscription *sub; struct subscription *sub_temp; /* Invalidate subscriber reference */ - tipc_ref_discard(subscriber->ref); + port_ref = subscriber->port_ref; + subscriber->port_ref = 0; spin_unlock_bh(subscriber->lock); + /* Sever connection to subscriber */ + + tipc_shutdown(port_ref); + tipc_deleteport(port_ref); + /* Destroy any existing subscriptions for subscriber */ list_for_each_entry_safe(sub, sub_temp, &subscriber->subscription_list, @@ -253,27 +257,25 @@ static void subscr_terminate(struct subscriber *subscriber) subscr_del(sub); } - /* Sever connection to subscriber */ - - tipc_shutdown(subscriber->port_ref); - tipc_deleteport(subscriber->port_ref); - /* Remove subscriber from topology server's subscriber list */ spin_lock_bh(&topsrv.lock); list_del(&subscriber->subscriber_list); spin_unlock_bh(&topsrv.lock); - /* Now destroy subscriber */ + /* Reclaim subscriber lock */ spin_lock_bh(subscriber->lock); + + /* Now destroy subscriber */ + kfree(subscriber); } /** * subscr_cancel - handle subscription cancellation request * - * Called with subscriber locked. Routine must temporarily release this lock + * Called with subscriber port locked. Routine must temporarily release lock * to enable the subscription timeout routine to finish without deadlocking; * the lock is then reclaimed to allow caller to release it upon return. * @@ -316,27 +318,25 @@ static void subscr_cancel(struct tipc_subscr *s, /** * subscr_subscribe - create subscription for subscriber * - * Called with subscriber locked + * Called with subscriber port locked. */ -static void subscr_subscribe(struct tipc_subscr *s, - struct subscriber *subscriber) +static struct subscription *subscr_subscribe(struct tipc_subscr *s, + struct subscriber *subscriber) { struct subscription *sub; + int swap; - /* Determine/update subscriber's endianness */ + /* Determine subscriber's endianness */ - if (s->filter & (TIPC_SUB_PORTS | TIPC_SUB_SERVICE)) - subscriber->swap = 0; - else - subscriber->swap = 1; + swap = !(s->filter & (TIPC_SUB_PORTS | TIPC_SUB_SERVICE)); /* Detect & process a subscription cancellation request */ - if (s->filter & htohl(TIPC_SUB_CANCEL, subscriber->swap)) { - s->filter &= ~htohl(TIPC_SUB_CANCEL, subscriber->swap); + if (s->filter & htohl(TIPC_SUB_CANCEL, swap)) { + s->filter &= ~htohl(TIPC_SUB_CANCEL, swap); subscr_cancel(s, subscriber); - return; + return NULL; } /* Refuse subscription if global limit exceeded */ @@ -345,63 +345,66 @@ static void subscr_subscribe(struct tipc_subscr *s, warn("Subscription rejected, subscription limit reached (%u)\n", tipc_max_subscriptions); subscr_terminate(subscriber); - return; + return NULL; } /* Allocate subscription object */ - sub = kzalloc(sizeof(*sub), GFP_ATOMIC); + sub = kmalloc(sizeof(*sub), GFP_ATOMIC); if (!sub) { warn("Subscription rejected, no memory\n"); subscr_terminate(subscriber); - return; + return NULL; } /* Initialize subscription object */ - sub->seq.type = htohl(s->seq.type, subscriber->swap); - sub->seq.lower = htohl(s->seq.lower, subscriber->swap); - sub->seq.upper = htohl(s->seq.upper, subscriber->swap); - sub->timeout = htohl(s->timeout, subscriber->swap); - sub->filter = htohl(s->filter, subscriber->swap); + sub->seq.type = htohl(s->seq.type, swap); + sub->seq.lower = htohl(s->seq.lower, swap); + sub->seq.upper = htohl(s->seq.upper, swap); + sub->timeout = htohl(s->timeout, swap); + sub->filter = htohl(s->filter, swap); if ((!(sub->filter & TIPC_SUB_PORTS) == !(sub->filter & TIPC_SUB_SERVICE)) || (sub->seq.lower > sub->seq.upper)) { warn("Subscription rejected, illegal request\n"); kfree(sub); subscr_terminate(subscriber); - return; + return NULL; } - memcpy(&sub->evt.s, s, sizeof(struct tipc_subscr)); - INIT_LIST_HEAD(&sub->subscription_list); + sub->event_cb = subscr_send_event; INIT_LIST_HEAD(&sub->nameseq_list); list_add(&sub->subscription_list, &subscriber->subscription_list); + sub->server_ref = subscriber->port_ref; + sub->swap = swap; + memcpy(&sub->evt.s, s, sizeof(struct tipc_subscr)); atomic_inc(&topsrv.subscription_count); if (sub->timeout != TIPC_WAIT_FOREVER) { k_init_timer(&sub->timer, (Handler)subscr_timeout, (unsigned long)sub); k_start_timer(&sub->timer, sub->timeout); } - sub->owner = subscriber; - tipc_nametbl_subscribe(sub); + + return sub; } /** * subscr_conn_shutdown_event - handle termination request from subscriber + * + * Called with subscriber's server port unlocked. */ static void subscr_conn_shutdown_event(void *usr_handle, - u32 portref, + u32 port_ref, struct sk_buff **buf, unsigned char const *data, unsigned int size, int reason) { - struct subscriber *subscriber; + struct subscriber *subscriber = usr_handle; spinlock_t *subscriber_lock; - subscriber = tipc_ref_lock((u32)(unsigned long)usr_handle); - if (subscriber == NULL) + if (tipc_port_lock(port_ref) == NULL) return; subscriber_lock = subscriber->lock; @@ -411,6 +414,8 @@ static void subscr_conn_shutdown_event(void *usr_handle, /** * subscr_conn_msg_event - handle new subscription request from subscriber + * + * Called with subscriber's server port unlocked. */ static void subscr_conn_msg_event(void *usr_handle, @@ -419,20 +424,46 @@ static void subscr_conn_msg_event(void *usr_handle, const unchar *data, u32 size) { - struct subscriber *subscriber; + struct subscriber *subscriber = usr_handle; spinlock_t *subscriber_lock; + struct subscription *sub; + + /* + * Lock subscriber's server port (& make a local copy of lock pointer, + * in case subscriber is deleted while processing subscription request) + */ - subscriber = tipc_ref_lock((u32)(unsigned long)usr_handle); - if (subscriber == NULL) + if (tipc_port_lock(port_ref) == NULL) return; subscriber_lock = subscriber->lock; - if (size != sizeof(struct tipc_subscr)) - subscr_terminate(subscriber); - else - subscr_subscribe((struct tipc_subscr *)data, subscriber); - spin_unlock_bh(subscriber_lock); + if (size != sizeof(struct tipc_subscr)) { + subscr_terminate(subscriber); + spin_unlock_bh(subscriber_lock); + } else { + sub = subscr_subscribe((struct tipc_subscr *)data, subscriber); + spin_unlock_bh(subscriber_lock); + if (sub != NULL) { + + /* + * We must release the server port lock before adding a + * subscription to the name table since TIPC needs to be + * able to (re)acquire the port lock if an event message + * issued by the subscription process is rejected and + * returned. The subscription cannot be deleted while + * it is being added to the name table because: + * a) the single-threading of the native API port code + * ensures the subscription cannot be cancelled and + * the subscriber connection cannot be broken, and + * b) the name table lock ensures the subscription + * timeout code cannot delete the subscription, + * so the subscription object is still protected. + */ + + tipc_nametbl_subscribe(sub); + } + } } /** @@ -448,16 +479,10 @@ static void subscr_named_msg_event(void *usr_handle, struct tipc_portid const *orig, struct tipc_name_seq const *dest) { - struct subscriber *subscriber; - struct iovec msg_sect = {NULL, 0}; - spinlock_t *subscriber_lock; + static struct iovec msg_sect = {NULL, 0}; - dbg("subscr_named_msg_event: orig = %x own = %x,\n", - orig->node, tipc_own_addr); - if (size && (size != sizeof(struct tipc_subscr))) { - warn("Subscriber rejected, invalid subscription size\n"); - return; - } + struct subscriber *subscriber; + u32 server_port_ref; /* Create subscriber object */ @@ -468,17 +493,11 @@ static void subscr_named_msg_event(void *usr_handle, } INIT_LIST_HEAD(&subscriber->subscription_list); INIT_LIST_HEAD(&subscriber->subscriber_list); - subscriber->ref = tipc_ref_acquire(subscriber, &subscriber->lock); - if (subscriber->ref == 0) { - warn("Subscriber rejected, reference table exhausted\n"); - kfree(subscriber); - return; - } - /* Establish a connection to subscriber */ + /* Create server port & establish connection to subscriber */ tipc_createport(topsrv.user_ref, - (void *)(unsigned long)subscriber->ref, + subscriber, importance, NULL, NULL, @@ -490,32 +509,36 @@ static void subscr_named_msg_event(void *usr_handle, &subscriber->port_ref); if (subscriber->port_ref == 0) { warn("Subscriber rejected, unable to create port\n"); - tipc_ref_discard(subscriber->ref); kfree(subscriber); return; } tipc_connect2port(subscriber->port_ref, orig); + /* Lock server port (& save lock address for future use) */ + + subscriber->lock = tipc_port_lock(subscriber->port_ref)->publ.lock; /* Add subscriber to topology server's subscriber list */ - tipc_ref_lock(subscriber->ref); spin_lock_bh(&topsrv.lock); list_add(&subscriber->subscriber_list, &topsrv.subscriber_list); spin_unlock_bh(&topsrv.lock); - /* - * Subscribe now if message contains a subscription, - * otherwise send an empty response to complete connection handshaking - */ + /* Unlock server port */ - subscriber_lock = subscriber->lock; - if (size) - subscr_subscribe((struct tipc_subscr *)data, subscriber); - else - tipc_send(subscriber->port_ref, 1, &msg_sect); + server_port_ref = subscriber->port_ref; + spin_unlock_bh(subscriber->lock); - spin_unlock_bh(subscriber_lock); + /* Send an ACK- to complete connection handshaking */ + + tipc_send(server_port_ref, 1, &msg_sect); + + /* Handle optional subscription request */ + + if (size != 0) { + subscr_conn_msg_event(subscriber, server_port_ref, + buf, data, size); + } } int tipc_subscr_start(void) @@ -574,8 +597,8 @@ void tipc_subscr_stop(void) list_for_each_entry_safe(subscriber, subscriber_temp, &topsrv.subscriber_list, subscriber_list) { - tipc_ref_lock(subscriber->ref); subscriber_lock = subscriber->lock; + spin_lock_bh(subscriber_lock); subscr_terminate(subscriber); spin_unlock_bh(subscriber_lock); } diff --git a/net/tipc/subscr.h b/net/tipc/subscr.h index 93a8e674fac1..45d89bf4d202 100644 --- a/net/tipc/subscr.h +++ b/net/tipc/subscr.h @@ -1,8 +1,8 @@ /* - * net/tipc/subscr.h: Include file for TIPC subscription service + * net/tipc/subscr.h: Include file for TIPC network topology service * * Copyright (c) 2003-2006, Ericsson AB - * Copyright (c) 2005, Wind River Systems + * Copyright (c) 2005-2007, Wind River Systems * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -37,34 +37,44 @@ #ifndef _TIPC_SUBSCR_H #define _TIPC_SUBSCR_H +struct subscription; + +typedef void (*tipc_subscr_event) (struct subscription *sub, + u32 found_lower, u32 found_upper, + u32 event, u32 port_ref, u32 node); + /** * struct subscription - TIPC network topology subscription object * @seq: name sequence associated with subscription * @timeout: duration of subscription (in ms) * @filter: event filtering to be done for subscription - * @evt: template for events generated by subscription - * @subscription_list: adjacent subscriptions in subscriber's subscription list + * @event_cb: routine invoked when a subscription event is detected + * @timer: timer governing subscription duration (optional) * @nameseq_list: adjacent subscriptions in name sequence's subscription list - * @timer_ref: reference to timer governing subscription duration (may be NULL) - * @owner: pointer to subscriber object associated with this subscription + * @subscription_list: adjacent subscriptions in subscriber's subscription list + * @server_ref: object reference of server port associated with subscription + * @swap: indicates if subscriber uses opposite endianness in its messages + * @evt: template for events generated by subscription */ struct subscription { struct tipc_name_seq seq; u32 timeout; u32 filter; - struct tipc_event evt; - struct list_head subscription_list; - struct list_head nameseq_list; + tipc_subscr_event event_cb; struct timer_list timer; - struct subscriber *owner; + struct list_head nameseq_list; + struct list_head subscription_list; + u32 server_ref; + int swap; + struct tipc_event evt; }; -int tipc_subscr_overlap(struct subscription * sub, +int tipc_subscr_overlap(struct subscription *sub, u32 found_lower, u32 found_upper); -void tipc_subscr_report_overlap(struct subscription * sub, +void tipc_subscr_report_overlap(struct subscription *sub, u32 found_lower, u32 found_upper, u32 event, diff --git a/net/tipc/user_reg.c b/net/tipc/user_reg.c index 4146c40cd20b..506928803162 100644 --- a/net/tipc/user_reg.c +++ b/net/tipc/user_reg.c @@ -91,7 +91,7 @@ static int reg_init(void) } } spin_unlock_bh(®_lock); - return users ? TIPC_OK : -ENOMEM; + return users ? 0 : -ENOMEM; } /** @@ -129,7 +129,7 @@ int tipc_reg_start(void) tipc_k_signal((Handler)reg_callback, (unsigned long)&users[u]); } - return TIPC_OK; + return 0; } /** @@ -184,7 +184,7 @@ int tipc_attach(u32 *userid, tipc_mode_event cb, void *usr_handle) if (cb && (tipc_mode != TIPC_NOT_RUNNING)) tipc_k_signal((Handler)reg_callback, (unsigned long)user_ptr); - return TIPC_OK; + return 0; } /** @@ -230,7 +230,7 @@ int tipc_reg_add_port(struct user_port *up_ptr) struct tipc_user *user_ptr; if (up_ptr->user_ref == 0) - return TIPC_OK; + return 0; if (up_ptr->user_ref > MAX_USERID) return -EINVAL; if ((tipc_mode == TIPC_NOT_RUNNING) || !users ) @@ -240,7 +240,7 @@ int tipc_reg_add_port(struct user_port *up_ptr) user_ptr = &users[up_ptr->user_ref]; list_add(&up_ptr->uport_list, &user_ptr->ports); spin_unlock_bh(®_lock); - return TIPC_OK; + return 0; } /** @@ -250,7 +250,7 @@ int tipc_reg_add_port(struct user_port *up_ptr) int tipc_reg_remove_port(struct user_port *up_ptr) { if (up_ptr->user_ref == 0) - return TIPC_OK; + return 0; if (up_ptr->user_ref > MAX_USERID) return -EINVAL; if (!users ) @@ -259,6 +259,6 @@ int tipc_reg_remove_port(struct user_port *up_ptr) spin_lock_bh(®_lock); list_del_init(&up_ptr->uport_list); spin_unlock_bh(®_lock); - return TIPC_OK; + return 0; } diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c index 783317dacd30..70ceb1604ad8 100644 --- a/net/unix/af_unix.c +++ b/net/unix/af_unix.c @@ -8,8 +8,6 @@ * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. * - * Version: $Id: af_unix.c,v 1.133 2002/02/08 03:57:19 davem Exp $ - * * Fixes: * Linus Torvalds : Assorted bug cures. * Niibe Yutaka : async I/O support. diff --git a/net/wanrouter/Kconfig b/net/wanrouter/Kconfig index 1debe1cb054e..61ceae0b9566 100644 --- a/net/wanrouter/Kconfig +++ b/net/wanrouter/Kconfig @@ -20,8 +20,6 @@ config WAN_ROUTER wish to use your Linux box as a WAN router, say Y here and also to the WAN driver for your card, below. You will then need the wan-tools package which is available from <ftp://ftp.sangoma.com/>. - Read <file:Documentation/networking/wan-router.txt> for more - information. To compile WAN routing support as a module, choose M here: the module will be called wanrouter. diff --git a/net/wanrouter/wanmain.c b/net/wanrouter/wanmain.c index 9ab31a3ce3ad..b210a88d0960 100644 --- a/net/wanrouter/wanmain.c +++ b/net/wanrouter/wanmain.c @@ -350,9 +350,9 @@ __be16 wanrouter_type_trans(struct sk_buff *skb, struct net_device *dev) * o execute requested action or pass command to the device driver */ -int wanrouter_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg) +long wanrouter_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { + struct inode *inode = file->f_path.dentry->d_inode; int err = 0; struct proc_dir_entry *dent; struct wan_device *wandev; @@ -372,6 +372,7 @@ int wanrouter_ioctl(struct inode *inode, struct file *file, if (wandev->magic != ROUTER_MAGIC) return -EINVAL; + lock_kernel(); switch (cmd) { case ROUTER_SETUP: err = wanrouter_device_setup(wandev, data); @@ -403,6 +404,7 @@ int wanrouter_ioctl(struct inode *inode, struct file *file, err = wandev->ioctl(wandev, cmd, arg); else err = -EINVAL; } + unlock_kernel(); return err; } diff --git a/net/wanrouter/wanproc.c b/net/wanrouter/wanproc.c index 5bebe40bf4e6..267f7ff49827 100644 --- a/net/wanrouter/wanproc.c +++ b/net/wanrouter/wanproc.c @@ -278,7 +278,7 @@ static const struct file_operations wandev_fops = { .read = seq_read, .llseek = seq_lseek, .release = single_release, - .ioctl = wanrouter_ioctl, + .unlocked_ioctl = wanrouter_ioctl, }; /* diff --git a/net/wireless/Kconfig b/net/wireless/Kconfig index 79270903bda6..ab015c62d561 100644 --- a/net/wireless/Kconfig +++ b/net/wireless/Kconfig @@ -29,3 +29,14 @@ config WIRELESS_EXT Say N (if you can) unless you know you need wireless extensions for external modules. + +config WIRELESS_EXT_SYSFS + bool "Wireless extensions sysfs files" + default y + depends on WIRELESS_EXT && SYSFS + help + This option enables the deprecated wireless statistics + files in /sys/class/net/*/wireless/. The same information + is available via the ioctls as well. + + Say Y if you have programs using it (we don't know of any). diff --git a/net/wireless/core.c b/net/wireless/core.c index 80afacdae46c..f1da0b93bc56 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c @@ -143,8 +143,11 @@ void cfg80211_put_dev(struct cfg80211_registered_device *drv) int cfg80211_dev_rename(struct cfg80211_registered_device *rdev, char *newname) { + struct cfg80211_registered_device *drv; int idx, taken = -1, result, digits; + mutex_lock(&cfg80211_drv_mutex); + /* prohibit calling the thing phy%d when %d is not its number */ sscanf(newname, PHY_NAME "%d%n", &idx, &taken); if (taken == strlen(newname) && idx != rdev->idx) { @@ -156,14 +159,30 @@ int cfg80211_dev_rename(struct cfg80211_registered_device *rdev, * deny the name if it is phy<idx> where <idx> is printed * without leading zeroes. taken == strlen(newname) here */ + result = -EINVAL; if (taken == strlen(PHY_NAME) + digits) - return -EINVAL; + goto out_unlock; + } + + + /* Ignore nop renames */ + result = 0; + if (strcmp(newname, dev_name(&rdev->wiphy.dev)) == 0) + goto out_unlock; + + /* Ensure another device does not already have this name. */ + list_for_each_entry(drv, &cfg80211_drv_list, list) { + result = -EINVAL; + if (strcmp(newname, dev_name(&drv->wiphy.dev)) == 0) + goto out_unlock; } - /* this will check for collisions */ + /* this will only check for collisions in sysfs + * which is not even always compiled in. + */ result = device_rename(&rdev->wiphy.dev, newname); if (result) - return result; + goto out_unlock; if (!debugfs_rename(rdev->wiphy.debugfsdir->d_parent, rdev->wiphy.debugfsdir, @@ -172,9 +191,13 @@ int cfg80211_dev_rename(struct cfg80211_registered_device *rdev, printk(KERN_ERR "cfg80211: failed to rename debugfs dir to %s!\n", newname); - nl80211_notify_dev_rename(rdev); + result = 0; +out_unlock: + mutex_unlock(&cfg80211_drv_mutex); + if (result == 0) + nl80211_notify_dev_rename(rdev); - return 0; + return result; } /* exported functions */ diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index fb75f265b39c..b7fefffd2d0d 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -199,12 +199,14 @@ static int nl80211_dump_wiphy(struct sk_buff *skb, struct netlink_callback *cb) mutex_lock(&cfg80211_drv_mutex); list_for_each_entry(dev, &cfg80211_drv_list, list) { - if (++idx < start) + if (++idx <= start) continue; if (nl80211_send_wiphy(skb, NETLINK_CB(cb->skb).pid, cb->nlh->nlmsg_seq, NLM_F_MULTI, - dev) < 0) + dev) < 0) { + idx--; break; + } } mutex_unlock(&cfg80211_drv_mutex); diff --git a/net/wireless/radiotap.c b/net/wireless/radiotap.c index 28fbd0b0b568..f591871a7b4f 100644 --- a/net/wireless/radiotap.c +++ b/net/wireless/radiotap.c @@ -59,23 +59,21 @@ int ieee80211_radiotap_iterator_init( return -EINVAL; /* sanity check for allowed length and radiotap length field */ - if (max_length < le16_to_cpu(get_unaligned(&radiotap_header->it_len))) + if (max_length < get_unaligned_le16(&radiotap_header->it_len)) return -EINVAL; iterator->rtheader = radiotap_header; - iterator->max_length = le16_to_cpu(get_unaligned( - &radiotap_header->it_len)); + iterator->max_length = get_unaligned_le16(&radiotap_header->it_len); iterator->arg_index = 0; - iterator->bitmap_shifter = le32_to_cpu(get_unaligned( - &radiotap_header->it_present)); + iterator->bitmap_shifter = get_unaligned_le32(&radiotap_header->it_present); iterator->arg = (u8 *)radiotap_header + sizeof(*radiotap_header); iterator->this_arg = NULL; /* find payload start allowing for extended bitmap(s) */ if (unlikely(iterator->bitmap_shifter & (1<<IEEE80211_RADIOTAP_EXT))) { - while (le32_to_cpu(get_unaligned((__le32 *)iterator->arg)) & - (1<<IEEE80211_RADIOTAP_EXT)) { + while (get_unaligned_le32(iterator->arg) & + (1 << IEEE80211_RADIOTAP_EXT)) { iterator->arg += sizeof(u32); /* @@ -241,8 +239,8 @@ int ieee80211_radiotap_iterator_next( if (iterator->bitmap_shifter & 1) { /* b31 was set, there is more */ /* move to next u32 bitmap */ - iterator->bitmap_shifter = le32_to_cpu( - get_unaligned(iterator->next_bitmap)); + iterator->bitmap_shifter = + get_unaligned_le32(iterator->next_bitmap); iterator->next_bitmap++; } else /* no more bitmaps: end */ diff --git a/net/wireless/wext.c b/net/wireless/wext.c index 947188a5b937..df5b3886c36b 100644 --- a/net/wireless/wext.c +++ b/net/wireless/wext.c @@ -500,7 +500,7 @@ static int call_commit_handler(struct net_device *dev) /* * Calculate size of private arguments */ -static inline int get_priv_size(__u16 args) +static int get_priv_size(__u16 args) { int num = args & IW_PRIV_SIZE_MASK; int type = (args & IW_PRIV_TYPE_MASK) >> 12; @@ -512,10 +512,9 @@ static inline int get_priv_size(__u16 args) /* * Re-calculate the size of private arguments */ -static inline int adjust_priv_size(__u16 args, - union iwreq_data * wrqu) +static int adjust_priv_size(__u16 args, struct iw_point *iwp) { - int num = wrqu->data.length; + int num = iwp->length; int max = args & IW_PRIV_SIZE_MASK; int type = (args & IW_PRIV_TYPE_MASK) >> 12; @@ -695,19 +694,150 @@ void wext_proc_exit(struct net *net) */ /* ---------------------------------------------------------------- */ +static int ioctl_standard_iw_point(struct iw_point *iwp, unsigned int cmd, + const struct iw_ioctl_description *descr, + iw_handler handler, struct net_device *dev, + struct iw_request_info *info) +{ + int err, extra_size, user_length = 0, essid_compat = 0; + char *extra; + + /* Calculate space needed by arguments. Always allocate + * for max space. + */ + extra_size = descr->max_tokens * descr->token_size; + + /* Check need for ESSID compatibility for WE < 21 */ + switch (cmd) { + case SIOCSIWESSID: + case SIOCGIWESSID: + case SIOCSIWNICKN: + case SIOCGIWNICKN: + if (iwp->length == descr->max_tokens + 1) + essid_compat = 1; + else if (IW_IS_SET(cmd) && (iwp->length != 0)) { + char essid[IW_ESSID_MAX_SIZE + 1]; + + err = copy_from_user(essid, iwp->pointer, + iwp->length * + descr->token_size); + if (err) + return -EFAULT; + + if (essid[iwp->length - 1] == '\0') + essid_compat = 1; + } + break; + default: + break; + } + + iwp->length -= essid_compat; + + /* Check what user space is giving us */ + if (IW_IS_SET(cmd)) { + /* Check NULL pointer */ + if (!iwp->pointer && iwp->length != 0) + return -EFAULT; + /* Check if number of token fits within bounds */ + if (iwp->length > descr->max_tokens) + return -E2BIG; + if (iwp->length < descr->min_tokens) + return -EINVAL; + } else { + /* Check NULL pointer */ + if (!iwp->pointer) + return -EFAULT; + /* Save user space buffer size for checking */ + user_length = iwp->length; + + /* Don't check if user_length > max to allow forward + * compatibility. The test user_length < min is + * implied by the test at the end. + */ + + /* Support for very large requests */ + if ((descr->flags & IW_DESCR_FLAG_NOMAX) && + (user_length > descr->max_tokens)) { + /* Allow userspace to GET more than max so + * we can support any size GET requests. + * There is still a limit : -ENOMEM. + */ + extra_size = user_length * descr->token_size; + + /* Note : user_length is originally a __u16, + * and token_size is controlled by us, + * so extra_size won't get negative and + * won't overflow... + */ + } + } + + /* kzalloc() ensures NULL-termination for essid_compat. */ + extra = kzalloc(extra_size, GFP_KERNEL); + if (!extra) + return -ENOMEM; + + /* If it is a SET, get all the extra data in here */ + if (IW_IS_SET(cmd) && (iwp->length != 0)) { + if (copy_from_user(extra, iwp->pointer, + iwp->length * + descr->token_size)) { + err = -EFAULT; + goto out; + } + } + + err = handler(dev, info, (union iwreq_data *) iwp, extra); + + iwp->length += essid_compat; + + /* If we have something to return to the user */ + if (!err && IW_IS_GET(cmd)) { + /* Check if there is enough buffer up there */ + if (user_length < iwp->length) { + err = -E2BIG; + goto out; + } + + if (copy_to_user(iwp->pointer, extra, + iwp->length * + descr->token_size)) { + err = -EFAULT; + goto out; + } + } + + /* Generate an event to notify listeners of the change */ + if ((descr->flags & IW_DESCR_FLAG_EVENT) && err == -EIWCOMMIT) { + union iwreq_data *data = (union iwreq_data *) iwp; + + if (descr->flags & IW_DESCR_FLAG_RESTRICT) + /* If the event is restricted, don't + * export the payload. + */ + wireless_send_event(dev, cmd, data, NULL); + else + wireless_send_event(dev, cmd, data, extra); + } + +out: + kfree(extra); + return err; +} + /* * Wrapper to call a standard Wireless Extension handler. * We do various checks and also take care of moving data between * user space and kernel space. */ static int ioctl_standard_call(struct net_device * dev, - struct ifreq * ifr, + struct iwreq *iwr, unsigned int cmd, + struct iw_request_info *info, iw_handler handler) { - struct iwreq * iwr = (struct iwreq *) ifr; const struct iw_ioctl_description * descr; - struct iw_request_info info; int ret = -EINVAL; /* Get the description of the IOCTL */ @@ -715,145 +845,19 @@ static int ioctl_standard_call(struct net_device * dev, return -EOPNOTSUPP; descr = &(standard_ioctl[cmd - SIOCIWFIRST]); - /* Prepare the call */ - info.cmd = cmd; - info.flags = 0; - /* Check if we have a pointer to user space data or not */ if (descr->header_type != IW_HEADER_TYPE_POINT) { /* No extra arguments. Trivial to handle */ - ret = handler(dev, &info, &(iwr->u), NULL); + ret = handler(dev, info, &(iwr->u), NULL); /* Generate an event to notify listeners of the change */ if ((descr->flags & IW_DESCR_FLAG_EVENT) && ((ret == 0) || (ret == -EIWCOMMIT))) wireless_send_event(dev, cmd, &(iwr->u), NULL); } else { - char * extra; - int extra_size; - int user_length = 0; - int err; - int essid_compat = 0; - - /* Calculate space needed by arguments. Always allocate - * for max space. Easier, and won't last long... */ - extra_size = descr->max_tokens * descr->token_size; - - /* Check need for ESSID compatibility for WE < 21 */ - switch (cmd) { - case SIOCSIWESSID: - case SIOCGIWESSID: - case SIOCSIWNICKN: - case SIOCGIWNICKN: - if (iwr->u.data.length == descr->max_tokens + 1) - essid_compat = 1; - else if (IW_IS_SET(cmd) && (iwr->u.data.length != 0)) { - char essid[IW_ESSID_MAX_SIZE + 1]; - - err = copy_from_user(essid, iwr->u.data.pointer, - iwr->u.data.length * - descr->token_size); - if (err) - return -EFAULT; - - if (essid[iwr->u.data.length - 1] == '\0') - essid_compat = 1; - } - break; - default: - break; - } - - iwr->u.data.length -= essid_compat; - - /* Check what user space is giving us */ - if (IW_IS_SET(cmd)) { - /* Check NULL pointer */ - if ((iwr->u.data.pointer == NULL) && - (iwr->u.data.length != 0)) - return -EFAULT; - /* Check if number of token fits within bounds */ - if (iwr->u.data.length > descr->max_tokens) - return -E2BIG; - if (iwr->u.data.length < descr->min_tokens) - return -EINVAL; - } else { - /* Check NULL pointer */ - if (iwr->u.data.pointer == NULL) - return -EFAULT; - /* Save user space buffer size for checking */ - user_length = iwr->u.data.length; - - /* Don't check if user_length > max to allow forward - * compatibility. The test user_length < min is - * implied by the test at the end. */ - - /* Support for very large requests */ - if ((descr->flags & IW_DESCR_FLAG_NOMAX) && - (user_length > descr->max_tokens)) { - /* Allow userspace to GET more than max so - * we can support any size GET requests. - * There is still a limit : -ENOMEM. */ - extra_size = user_length * descr->token_size; - /* Note : user_length is originally a __u16, - * and token_size is controlled by us, - * so extra_size won't get negative and - * won't overflow... */ - } - } - - /* Create the kernel buffer */ - /* kzalloc ensures NULL-termination for essid_compat */ - extra = kzalloc(extra_size, GFP_KERNEL); - if (extra == NULL) - return -ENOMEM; - - /* If it is a SET, get all the extra data in here */ - if (IW_IS_SET(cmd) && (iwr->u.data.length != 0)) { - err = copy_from_user(extra, iwr->u.data.pointer, - iwr->u.data.length * - descr->token_size); - if (err) { - kfree(extra); - return -EFAULT; - } - } - - /* Call the handler */ - ret = handler(dev, &info, &(iwr->u), extra); - - iwr->u.data.length += essid_compat; - - /* If we have something to return to the user */ - if (!ret && IW_IS_GET(cmd)) { - /* Check if there is enough buffer up there */ - if (user_length < iwr->u.data.length) { - kfree(extra); - return -E2BIG; - } - - err = copy_to_user(iwr->u.data.pointer, extra, - iwr->u.data.length * - descr->token_size); - if (err) - ret = -EFAULT; - } - - /* Generate an event to notify listeners of the change */ - if ((descr->flags & IW_DESCR_FLAG_EVENT) && - ((ret == 0) || (ret == -EIWCOMMIT))) { - if (descr->flags & IW_DESCR_FLAG_RESTRICT) - /* If the event is restricted, don't - * export the payload */ - wireless_send_event(dev, cmd, &(iwr->u), NULL); - else - wireless_send_event(dev, cmd, &(iwr->u), - extra); - } - - /* Cleanup - I told you it wasn't that long ;-) */ - kfree(extra); + ret = ioctl_standard_iw_point(&iwr->u.data, cmd, descr, + handler, dev, info); } /* Call commit handler if needed and defined */ @@ -881,25 +885,22 @@ static int ioctl_standard_call(struct net_device * dev, * a iw_handler but process it in your ioctl handler (i.e. use the * old driver API). */ -static int ioctl_private_call(struct net_device *dev, struct ifreq *ifr, - unsigned int cmd, iw_handler handler) +static int get_priv_descr_and_size(struct net_device *dev, unsigned int cmd, + const struct iw_priv_args **descrp) { - struct iwreq * iwr = (struct iwreq *) ifr; - const struct iw_priv_args * descr = NULL; - struct iw_request_info info; - int extra_size = 0; - int i; - int ret = -EINVAL; + const struct iw_priv_args *descr; + int i, extra_size; - /* Get the description of the IOCTL */ - for (i = 0; i < dev->wireless_handlers->num_private_args; i++) + descr = NULL; + for (i = 0; i < dev->wireless_handlers->num_private_args; i++) { if (cmd == dev->wireless_handlers->private_args[i].cmd) { - descr = &(dev->wireless_handlers->private_args[i]); + descr = &dev->wireless_handlers->private_args[i]; break; } + } - /* Compute the size of the set/get arguments */ - if (descr != NULL) { + extra_size = 0; + if (descr) { if (IW_IS_SET(cmd)) { int offset = 0; /* For sub-ioctls */ /* Check for sub-ioctl handler */ @@ -924,72 +925,77 @@ static int ioctl_private_call(struct net_device *dev, struct ifreq *ifr, extra_size = 0; } } + *descrp = descr; + return extra_size; +} - /* Prepare the call */ - info.cmd = cmd; - info.flags = 0; +static int ioctl_private_iw_point(struct iw_point *iwp, unsigned int cmd, + const struct iw_priv_args *descr, + iw_handler handler, struct net_device *dev, + struct iw_request_info *info, int extra_size) +{ + char *extra; + int err; - /* Check if we have a pointer to user space data or not. */ - if (extra_size == 0) { - /* No extra arguments. Trivial to handle */ - ret = handler(dev, &info, &(iwr->u), (char *) &(iwr->u)); - } else { - char * extra; - int err; + /* Check what user space is giving us */ + if (IW_IS_SET(cmd)) { + if (!iwp->pointer && iwp->length != 0) + return -EFAULT; - /* Check what user space is giving us */ - if (IW_IS_SET(cmd)) { - /* Check NULL pointer */ - if ((iwr->u.data.pointer == NULL) && - (iwr->u.data.length != 0)) - return -EFAULT; + if (iwp->length > (descr->set_args & IW_PRIV_SIZE_MASK)) + return -E2BIG; + } else if (!iwp->pointer) + return -EFAULT; - /* Does it fits within bounds ? */ - if (iwr->u.data.length > (descr->set_args & - IW_PRIV_SIZE_MASK)) - return -E2BIG; - } else if (iwr->u.data.pointer == NULL) - return -EFAULT; + extra = kmalloc(extra_size, GFP_KERNEL); + if (!extra) + return -ENOMEM; - /* Always allocate for max space. Easier, and won't last - * long... */ - extra = kmalloc(extra_size, GFP_KERNEL); - if (extra == NULL) - return -ENOMEM; - - /* If it is a SET, get all the extra data in here */ - if (IW_IS_SET(cmd) && (iwr->u.data.length != 0)) { - err = copy_from_user(extra, iwr->u.data.pointer, - extra_size); - if (err) { - kfree(extra); - return -EFAULT; - } + /* If it is a SET, get all the extra data in here */ + if (IW_IS_SET(cmd) && (iwp->length != 0)) { + if (copy_from_user(extra, iwp->pointer, extra_size)) { + err = -EFAULT; + goto out; } + } - /* Call the handler */ - ret = handler(dev, &info, &(iwr->u), extra); + /* Call the handler */ + err = handler(dev, info, (union iwreq_data *) iwp, extra); - /* If we have something to return to the user */ - if (!ret && IW_IS_GET(cmd)) { + /* If we have something to return to the user */ + if (!err && IW_IS_GET(cmd)) { + /* Adjust for the actual length if it's variable, + * avoid leaking kernel bits outside. + */ + if (!(descr->get_args & IW_PRIV_SIZE_FIXED)) + extra_size = adjust_priv_size(descr->get_args, iwp); - /* Adjust for the actual length if it's variable, - * avoid leaking kernel bits outside. */ - if (!(descr->get_args & IW_PRIV_SIZE_FIXED)) { - extra_size = adjust_priv_size(descr->get_args, - &(iwr->u)); - } + if (copy_to_user(iwp->pointer, extra, extra_size)) + err = -EFAULT; + } - err = copy_to_user(iwr->u.data.pointer, extra, - extra_size); - if (err) - ret = -EFAULT; - } +out: + kfree(extra); + return err; +} - /* Cleanup - I told you it wasn't that long ;-) */ - kfree(extra); - } +static int ioctl_private_call(struct net_device *dev, struct iwreq *iwr, + unsigned int cmd, struct iw_request_info *info, + iw_handler handler) +{ + int extra_size = 0, ret = -EINVAL; + const struct iw_priv_args *descr; + extra_size = get_priv_descr_and_size(dev, cmd, &descr); + + /* Check if we have a pointer to user space data or not. */ + if (extra_size == 0) { + /* No extra arguments. Trivial to handle */ + ret = handler(dev, info, &(iwr->u), (char *) &(iwr->u)); + } else { + ret = ioctl_private_iw_point(&iwr->u.data, cmd, descr, + handler, dev, info, extra_size); + } /* Call commit handler if needed and defined */ if (ret == -EIWCOMMIT) @@ -999,12 +1005,21 @@ static int ioctl_private_call(struct net_device *dev, struct ifreq *ifr, } /* ---------------------------------------------------------------- */ +typedef int (*wext_ioctl_func)(struct net_device *, struct iwreq *, + unsigned int, struct iw_request_info *, + iw_handler); + /* * Main IOCTl dispatcher. * Check the type of IOCTL and call the appropriate wrapper... */ -static int wireless_process_ioctl(struct net *net, struct ifreq *ifr, unsigned int cmd) +static int wireless_process_ioctl(struct net *net, struct ifreq *ifr, + unsigned int cmd, + struct iw_request_info *info, + wext_ioctl_func standard, + wext_ioctl_func private) { + struct iwreq *iwr = (struct iwreq *) ifr; struct net_device *dev; iw_handler handler; @@ -1019,12 +1034,12 @@ static int wireless_process_ioctl(struct net *net, struct ifreq *ifr, unsigned i * Note that 'cmd' is already filtered in dev_ioctl() with * (cmd >= SIOCIWFIRST && cmd <= SIOCIWLAST) */ if (cmd == SIOCGIWSTATS) - return ioctl_standard_call(dev, ifr, cmd, - &iw_handler_get_iwstats); + return standard(dev, iwr, cmd, info, + &iw_handler_get_iwstats); if (cmd == SIOCGIWPRIV && dev->wireless_handlers) - return ioctl_standard_call(dev, ifr, cmd, - &iw_handler_get_private); + return standard(dev, iwr, cmd, info, + &iw_handler_get_private); /* Basic check */ if (!netif_device_present(dev)) @@ -1035,9 +1050,9 @@ static int wireless_process_ioctl(struct net *net, struct ifreq *ifr, unsigned i if (handler) { /* Standard and private are not the same */ if (cmd < SIOCIWFIRSTPRIV) - return ioctl_standard_call(dev, ifr, cmd, handler); + return standard(dev, iwr, cmd, info, handler); else - return ioctl_private_call(dev, ifr, cmd, handler); + return private(dev, iwr, cmd, info, handler); } /* Old driver API : call driver ioctl handler */ if (dev->do_ioctl) @@ -1045,27 +1060,154 @@ static int wireless_process_ioctl(struct net *net, struct ifreq *ifr, unsigned i return -EOPNOTSUPP; } -/* entry point from dev ioctl */ -int wext_handle_ioctl(struct net *net, struct ifreq *ifr, unsigned int cmd, - void __user *arg) +/* If command is `set a parameter', or `get the encoding parameters', + * check if the user has the right to do it. + */ +static int wext_permission_check(unsigned int cmd) { - int ret; - - /* If command is `set a parameter', or - * `get the encoding parameters', check if - * the user has the right to do it */ if ((IW_IS_SET(cmd) || cmd == SIOCGIWENCODE || cmd == SIOCGIWENCODEEXT) && !capable(CAP_NET_ADMIN)) return -EPERM; + return 0; +} + +/* entry point from dev ioctl */ +static int wext_ioctl_dispatch(struct net *net, struct ifreq *ifr, + unsigned int cmd, struct iw_request_info *info, + wext_ioctl_func standard, + wext_ioctl_func private) +{ + int ret = wext_permission_check(cmd); + + if (ret) + return ret; + dev_load(net, ifr->ifr_name); rtnl_lock(); - ret = wireless_process_ioctl(net, ifr, cmd); + ret = wireless_process_ioctl(net, ifr, cmd, info, standard, private); rtnl_unlock(); - if (IW_IS_GET(cmd) && copy_to_user(arg, ifr, sizeof(struct iwreq))) + + return ret; +} + +int wext_handle_ioctl(struct net *net, struct ifreq *ifr, unsigned int cmd, + void __user *arg) +{ + struct iw_request_info info = { .cmd = cmd, .flags = 0 }; + int ret; + + ret = wext_ioctl_dispatch(net, ifr, cmd, &info, + ioctl_standard_call, + ioctl_private_call); + if (ret >= 0 && + IW_IS_GET(cmd) && + copy_to_user(arg, ifr, sizeof(struct iwreq))) + return -EFAULT; + + return ret; +} + +#ifdef CONFIG_COMPAT +static int compat_standard_call(struct net_device *dev, + struct iwreq *iwr, + unsigned int cmd, + struct iw_request_info *info, + iw_handler handler) +{ + const struct iw_ioctl_description *descr; + struct compat_iw_point *iwp_compat; + struct iw_point iwp; + int err; + + descr = standard_ioctl + (cmd - SIOCIWFIRST); + + if (descr->header_type != IW_HEADER_TYPE_POINT) + return ioctl_standard_call(dev, iwr, cmd, info, handler); + + iwp_compat = (struct compat_iw_point *) &iwr->u.data; + iwp.pointer = compat_ptr(iwp_compat->pointer); + iwp.length = iwp_compat->length; + iwp.flags = iwp_compat->flags; + + err = ioctl_standard_iw_point(&iwp, cmd, descr, handler, dev, info); + + iwp_compat->pointer = ptr_to_compat(iwp.pointer); + iwp_compat->length = iwp.length; + iwp_compat->flags = iwp.flags; + + return err; +} + +static int compat_private_call(struct net_device *dev, struct iwreq *iwr, + unsigned int cmd, struct iw_request_info *info, + iw_handler handler) +{ + const struct iw_priv_args *descr; + int ret, extra_size; + + extra_size = get_priv_descr_and_size(dev, cmd, &descr); + + /* Check if we have a pointer to user space data or not. */ + if (extra_size == 0) { + /* No extra arguments. Trivial to handle */ + ret = handler(dev, info, &(iwr->u), (char *) &(iwr->u)); + } else { + struct compat_iw_point *iwp_compat; + struct iw_point iwp; + + iwp_compat = (struct compat_iw_point *) &iwr->u.data; + iwp.pointer = compat_ptr(iwp_compat->pointer); + iwp.length = iwp_compat->length; + iwp.flags = iwp_compat->flags; + + ret = ioctl_private_iw_point(&iwp, cmd, descr, + handler, dev, info, extra_size); + + iwp_compat->pointer = ptr_to_compat(iwp.pointer); + iwp_compat->length = iwp.length; + iwp_compat->flags = iwp.flags; + } + + /* Call commit handler if needed and defined */ + if (ret == -EIWCOMMIT) + ret = call_commit_handler(dev); + + return ret; +} + +int compat_wext_handle_ioctl(struct net *net, unsigned int cmd, + unsigned long arg) +{ + void __user *argp = (void __user *)arg; + struct iw_request_info info; + struct iwreq iwr; + char *colon; + int ret; + + if (copy_from_user(&iwr, argp, sizeof(struct iwreq))) + return -EFAULT; + + iwr.ifr_name[IFNAMSIZ-1] = 0; + colon = strchr(iwr.ifr_name, ':'); + if (colon) + *colon = 0; + + info.cmd = cmd; + info.flags = IW_REQUEST_FLAG_COMPAT; + + ret = wext_ioctl_dispatch(net, (struct ifreq *) &iwr, cmd, &info, + compat_standard_call, + compat_private_call); + + if (ret >= 0 && + IW_IS_GET(cmd) && + copy_to_user(argp, &iwr, sizeof(struct iwreq))) return -EFAULT; + return ret; } +#endif /************************* EVENT PROCESSING *************************/ /* @@ -1157,7 +1299,7 @@ static void rtmsg_iwinfo(struct net_device *dev, char *event, int event_len) struct sk_buff *skb; int err; - if (dev_net(dev) != &init_net) + if (!net_eq(dev_net(dev), &init_net)) return; skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC); diff --git a/net/x25/af_x25.c b/net/x25/af_x25.c index 6ba67c523c16..9fc5b023d111 100644 --- a/net/x25/af_x25.c +++ b/net/x25/af_x25.c @@ -191,7 +191,7 @@ static int x25_device_event(struct notifier_block *this, unsigned long event, struct net_device *dev = ptr; struct x25_neigh *nb; - if (dev_net(dev) != &init_net) + if (!net_eq(dev_net(dev), &init_net)) return NOTIFY_DONE; if (dev->type == ARPHRD_X25 @@ -555,13 +555,11 @@ static struct sock *x25_make_new(struct sock *osk) x25 = x25_sk(sk); sk->sk_type = osk->sk_type; - sk->sk_socket = osk->sk_socket; sk->sk_priority = osk->sk_priority; sk->sk_protocol = osk->sk_protocol; sk->sk_rcvbuf = osk->sk_rcvbuf; sk->sk_sndbuf = osk->sk_sndbuf; sk->sk_state = TCP_ESTABLISHED; - sk->sk_sleep = osk->sk_sleep; sk->sk_backlog_rcv = osk->sk_backlog_rcv; sock_copy_flags(sk, osk); @@ -614,8 +612,7 @@ static int x25_release(struct socket *sock) break; } - sock->sk = NULL; - sk->sk_socket = NULL; /* Not used, but we should do this */ + sock_orphan(sk); out: return 0; } @@ -808,14 +805,12 @@ static int x25_accept(struct socket *sock, struct socket *newsock, int flags) if (!skb->sk) goto out2; newsk = skb->sk; - newsk->sk_socket = newsock; - newsk->sk_sleep = &newsock->wait; + sock_graft(newsk, newsock); /* Now attach up the new socket */ skb->sk = NULL; kfree_skb(skb); sk->sk_ack_backlog--; - newsock->sk = newsk; newsock->state = SS_CONNECTED; rc = 0; out2: diff --git a/net/x25/x25_dev.c b/net/x25/x25_dev.c index 3ff206c0ae94..3e1efe534645 100644 --- a/net/x25/x25_dev.c +++ b/net/x25/x25_dev.c @@ -95,7 +95,7 @@ int x25_lapb_receive_frame(struct sk_buff *skb, struct net_device *dev, struct sk_buff *nskb; struct x25_neigh *nb; - if (dev_net(dev) != &init_net) + if (!net_eq(dev_net(dev), &init_net)) goto drop; nskb = skb_copy(skb, GFP_ATOMIC); diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c index cae9fd815543..841b32a2e680 100644 --- a/net/xfrm/xfrm_policy.c +++ b/net/xfrm/xfrm_policy.c @@ -2360,7 +2360,7 @@ static int xfrm_dev_event(struct notifier_block *this, unsigned long event, void { struct net_device *dev = ptr; - if (dev_net(dev) != &init_net) + if (!net_eq(dev_net(dev), &init_net)) return NOTIFY_DONE; switch (event) { diff --git a/virt/kvm/coalesced_mmio.c b/virt/kvm/coalesced_mmio.c new file mode 100644 index 000000000000..5ae620d32fac --- /dev/null +++ b/virt/kvm/coalesced_mmio.c @@ -0,0 +1,156 @@ +/* + * KVM coalesced MMIO + * + * Copyright (c) 2008 Bull S.A.S. + * + * Author: Laurent Vivier <Laurent.Vivier@bull.net> + * + */ + +#include "iodev.h" + +#include <linux/kvm_host.h> +#include <linux/kvm.h> + +#include "coalesced_mmio.h" + +static int coalesced_mmio_in_range(struct kvm_io_device *this, + gpa_t addr, int len, int is_write) +{ + struct kvm_coalesced_mmio_dev *dev = + (struct kvm_coalesced_mmio_dev*)this->private; + struct kvm_coalesced_mmio_zone *zone; + int next; + int i; + + if (!is_write) + return 0; + + /* kvm->lock is taken by the caller and must be not released before + * dev.read/write + */ + + /* Are we able to batch it ? */ + + /* last is the first free entry + * check if we don't meet the first used entry + * there is always one unused entry in the buffer + */ + + next = (dev->kvm->coalesced_mmio_ring->last + 1) % + KVM_COALESCED_MMIO_MAX; + if (next == dev->kvm->coalesced_mmio_ring->first) { + /* full */ + return 0; + } + + /* is it in a batchable area ? */ + + for (i = 0; i < dev->nb_zones; i++) { + zone = &dev->zone[i]; + + /* (addr,len) is fully included in + * (zone->addr, zone->size) + */ + + if (zone->addr <= addr && + addr + len <= zone->addr + zone->size) + return 1; + } + return 0; +} + +static void coalesced_mmio_write(struct kvm_io_device *this, + gpa_t addr, int len, const void *val) +{ + struct kvm_coalesced_mmio_dev *dev = + (struct kvm_coalesced_mmio_dev*)this->private; + struct kvm_coalesced_mmio_ring *ring = dev->kvm->coalesced_mmio_ring; + + /* kvm->lock must be taken by caller before call to in_range()*/ + + /* copy data in first free entry of the ring */ + + ring->coalesced_mmio[ring->last].phys_addr = addr; + ring->coalesced_mmio[ring->last].len = len; + memcpy(ring->coalesced_mmio[ring->last].data, val, len); + smp_wmb(); + ring->last = (ring->last + 1) % KVM_COALESCED_MMIO_MAX; +} + +static void coalesced_mmio_destructor(struct kvm_io_device *this) +{ + kfree(this); +} + +int kvm_coalesced_mmio_init(struct kvm *kvm) +{ + struct kvm_coalesced_mmio_dev *dev; + + dev = kzalloc(sizeof(struct kvm_coalesced_mmio_dev), GFP_KERNEL); + if (!dev) + return -ENOMEM; + dev->dev.write = coalesced_mmio_write; + dev->dev.in_range = coalesced_mmio_in_range; + dev->dev.destructor = coalesced_mmio_destructor; + dev->dev.private = dev; + dev->kvm = kvm; + kvm->coalesced_mmio_dev = dev; + kvm_io_bus_register_dev(&kvm->mmio_bus, &dev->dev); + + return 0; +} + +int kvm_vm_ioctl_register_coalesced_mmio(struct kvm *kvm, + struct kvm_coalesced_mmio_zone *zone) +{ + struct kvm_coalesced_mmio_dev *dev = kvm->coalesced_mmio_dev; + + if (dev == NULL) + return -EINVAL; + + mutex_lock(&kvm->lock); + if (dev->nb_zones >= KVM_COALESCED_MMIO_ZONE_MAX) { + mutex_unlock(&kvm->lock); + return -ENOBUFS; + } + + dev->zone[dev->nb_zones] = *zone; + dev->nb_zones++; + + mutex_unlock(&kvm->lock); + return 0; +} + +int kvm_vm_ioctl_unregister_coalesced_mmio(struct kvm *kvm, + struct kvm_coalesced_mmio_zone *zone) +{ + int i; + struct kvm_coalesced_mmio_dev *dev = kvm->coalesced_mmio_dev; + struct kvm_coalesced_mmio_zone *z; + + if (dev == NULL) + return -EINVAL; + + mutex_lock(&kvm->lock); + + i = dev->nb_zones; + while(i) { + z = &dev->zone[i - 1]; + + /* unregister all zones + * included in (zone->addr, zone->size) + */ + + if (zone->addr <= z->addr && + z->addr + z->size <= zone->addr + zone->size) { + dev->nb_zones--; + *z = dev->zone[dev->nb_zones]; + } + i--; + } + + mutex_unlock(&kvm->lock); + + return 0; +} diff --git a/virt/kvm/coalesced_mmio.h b/virt/kvm/coalesced_mmio.h new file mode 100644 index 000000000000..5ac0ec628461 --- /dev/null +++ b/virt/kvm/coalesced_mmio.h @@ -0,0 +1,23 @@ +/* + * KVM coalesced MMIO + * + * Copyright (c) 2008 Bull S.A.S. + * + * Author: Laurent Vivier <Laurent.Vivier@bull.net> + * + */ + +#define KVM_COALESCED_MMIO_ZONE_MAX 100 + +struct kvm_coalesced_mmio_dev { + struct kvm_io_device dev; + struct kvm *kvm; + int nb_zones; + struct kvm_coalesced_mmio_zone zone[KVM_COALESCED_MMIO_ZONE_MAX]; +}; + +int kvm_coalesced_mmio_init(struct kvm *kvm); +int kvm_vm_ioctl_register_coalesced_mmio(struct kvm *kvm, + struct kvm_coalesced_mmio_zone *zone); +int kvm_vm_ioctl_unregister_coalesced_mmio(struct kvm *kvm, + struct kvm_coalesced_mmio_zone *zone); diff --git a/virt/kvm/ioapic.c b/virt/kvm/ioapic.c index 44589088941f..c0d22870ee9c 100644 --- a/virt/kvm/ioapic.c +++ b/virt/kvm/ioapic.c @@ -146,6 +146,11 @@ static int ioapic_inj_irq(struct kvm_ioapic *ioapic, return kvm_apic_set_irq(vcpu, vector, trig_mode); } +static void ioapic_inj_nmi(struct kvm_vcpu *vcpu) +{ + kvm_inject_nmi(vcpu); +} + static u32 ioapic_get_delivery_bitmask(struct kvm_ioapic *ioapic, u8 dest, u8 dest_mode) { @@ -239,8 +244,19 @@ static int ioapic_deliver(struct kvm_ioapic *ioapic, int irq) } } break; - - /* TODO: NMI */ + case IOAPIC_NMI: + for (vcpu_id = 0; deliver_bitmask != 0; vcpu_id++) { + if (!(deliver_bitmask & (1 << vcpu_id))) + continue; + deliver_bitmask &= ~(1 << vcpu_id); + vcpu = ioapic->kvm->vcpus[vcpu_id]; + if (vcpu) + ioapic_inj_nmi(vcpu); + else + ioapic_debug("NMI to vcpu %d failed\n", + vcpu->vcpu_id); + } + break; default: printk(KERN_WARNING "Unsupported delivery mode %d\n", delivery_mode); @@ -291,7 +307,8 @@ void kvm_ioapic_update_eoi(struct kvm *kvm, int vector) __kvm_ioapic_update_eoi(ioapic, i); } -static int ioapic_in_range(struct kvm_io_device *this, gpa_t addr) +static int ioapic_in_range(struct kvm_io_device *this, gpa_t addr, + int len, int is_write) { struct kvm_ioapic *ioapic = (struct kvm_ioapic *)this->private; diff --git a/virt/kvm/iodev.h b/virt/kvm/iodev.h index c14e642027b2..55e8846ac3a6 100644 --- a/virt/kvm/iodev.h +++ b/virt/kvm/iodev.h @@ -27,7 +27,8 @@ struct kvm_io_device { gpa_t addr, int len, const void *val); - int (*in_range)(struct kvm_io_device *this, gpa_t addr); + int (*in_range)(struct kvm_io_device *this, gpa_t addr, int len, + int is_write); void (*destructor)(struct kvm_io_device *this); void *private; @@ -49,9 +50,10 @@ static inline void kvm_iodevice_write(struct kvm_io_device *dev, dev->write(dev, addr, len, val); } -static inline int kvm_iodevice_inrange(struct kvm_io_device *dev, gpa_t addr) +static inline int kvm_iodevice_inrange(struct kvm_io_device *dev, + gpa_t addr, int len, int is_write) { - return dev->in_range(dev, addr); + return dev->in_range(dev, addr, len, is_write); } static inline void kvm_iodevice_destructor(struct kvm_io_device *dev) diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c index d4eae6af0738..904d7b7bd780 100644 --- a/virt/kvm/kvm_main.c +++ b/virt/kvm/kvm_main.c @@ -47,6 +47,10 @@ #include <asm/uaccess.h> #include <asm/pgtable.h> +#ifdef KVM_COALESCED_MMIO_PAGE_OFFSET +#include "coalesced_mmio.h" +#endif + MODULE_AUTHOR("Qumranet"); MODULE_LICENSE("GPL"); @@ -65,6 +69,8 @@ struct dentry *kvm_debugfs_dir; static long kvm_vcpu_ioctl(struct file *file, unsigned int ioctl, unsigned long arg); +bool kvm_rebooting; + static inline int valid_vcpu(int n) { return likely(n >= 0 && n < KVM_MAX_VCPUS); @@ -99,10 +105,11 @@ static void ack_flush(void *_completed) void kvm_flush_remote_tlbs(struct kvm *kvm) { - int i, cpu; + int i, cpu, me; cpumask_t cpus; struct kvm_vcpu *vcpu; + me = get_cpu(); cpus_clear(cpus); for (i = 0; i < KVM_MAX_VCPUS; ++i) { vcpu = kvm->vcpus[i]; @@ -111,21 +118,24 @@ void kvm_flush_remote_tlbs(struct kvm *kvm) if (test_and_set_bit(KVM_REQ_TLB_FLUSH, &vcpu->requests)) continue; cpu = vcpu->cpu; - if (cpu != -1 && cpu != raw_smp_processor_id()) + if (cpu != -1 && cpu != me) cpu_set(cpu, cpus); } if (cpus_empty(cpus)) - return; + goto out; ++kvm->stat.remote_tlb_flush; smp_call_function_mask(cpus, ack_flush, NULL, 1); +out: + put_cpu(); } void kvm_reload_remote_mmus(struct kvm *kvm) { - int i, cpu; + int i, cpu, me; cpumask_t cpus; struct kvm_vcpu *vcpu; + me = get_cpu(); cpus_clear(cpus); for (i = 0; i < KVM_MAX_VCPUS; ++i) { vcpu = kvm->vcpus[i]; @@ -134,12 +144,14 @@ void kvm_reload_remote_mmus(struct kvm *kvm) if (test_and_set_bit(KVM_REQ_MMU_RELOAD, &vcpu->requests)) continue; cpu = vcpu->cpu; - if (cpu != -1 && cpu != raw_smp_processor_id()) + if (cpu != -1 && cpu != me) cpu_set(cpu, cpus); } if (cpus_empty(cpus)) - return; + goto out; smp_call_function_mask(cpus, ack_flush, NULL, 1); +out: + put_cpu(); } @@ -183,10 +195,23 @@ EXPORT_SYMBOL_GPL(kvm_vcpu_uninit); static struct kvm *kvm_create_vm(void) { struct kvm *kvm = kvm_arch_create_vm(); +#ifdef KVM_COALESCED_MMIO_PAGE_OFFSET + struct page *page; +#endif if (IS_ERR(kvm)) goto out; +#ifdef KVM_COALESCED_MMIO_PAGE_OFFSET + page = alloc_page(GFP_KERNEL | __GFP_ZERO); + if (!page) { + kfree(kvm); + return ERR_PTR(-ENOMEM); + } + kvm->coalesced_mmio_ring = + (struct kvm_coalesced_mmio_ring *)page_address(page); +#endif + kvm->mm = current->mm; atomic_inc(&kvm->mm->mm_count); spin_lock_init(&kvm->mmu_lock); @@ -198,6 +223,9 @@ static struct kvm *kvm_create_vm(void) spin_lock(&kvm_lock); list_add(&kvm->vm_list, &vm_list); spin_unlock(&kvm_lock); +#ifdef KVM_COALESCED_MMIO_PAGE_OFFSET + kvm_coalesced_mmio_init(kvm); +#endif out: return kvm; } @@ -240,6 +268,10 @@ static void kvm_destroy_vm(struct kvm *kvm) spin_unlock(&kvm_lock); kvm_io_bus_destroy(&kvm->pio_bus); kvm_io_bus_destroy(&kvm->mmio_bus); +#ifdef KVM_COALESCED_MMIO_PAGE_OFFSET + if (kvm->coalesced_mmio_ring != NULL) + free_page((unsigned long)kvm->coalesced_mmio_ring); +#endif kvm_arch_destroy_vm(kvm); mmdrop(mm); } @@ -333,6 +365,7 @@ int __kvm_set_memory_region(struct kvm *kvm, r = -ENOMEM; /* Allocate if a slot is being created */ +#ifndef CONFIG_S390 if (npages && !new.rmap) { new.rmap = vmalloc(npages * sizeof(struct page *)); @@ -373,10 +406,14 @@ int __kvm_set_memory_region(struct kvm *kvm, goto out_free; memset(new.dirty_bitmap, 0, dirty_bytes); } +#endif /* not defined CONFIG_S390 */ if (mem->slot >= kvm->nmemslots) kvm->nmemslots = mem->slot + 1; + if (!npages) + kvm_arch_flush_shadow(kvm); + *memslot = new; r = kvm_arch_set_memory_region(kvm, mem, old, user_alloc); @@ -532,6 +569,7 @@ pfn_t gfn_to_pfn(struct kvm *kvm, gfn_t gfn) struct page *page[1]; unsigned long addr; int npages; + pfn_t pfn; might_sleep(); @@ -544,19 +582,38 @@ pfn_t gfn_to_pfn(struct kvm *kvm, gfn_t gfn) npages = get_user_pages(current, current->mm, addr, 1, 1, 1, page, NULL); - if (npages != 1) { - get_page(bad_page); - return page_to_pfn(bad_page); - } + if (unlikely(npages != 1)) { + struct vm_area_struct *vma; - return page_to_pfn(page[0]); + vma = find_vma(current->mm, addr); + if (vma == NULL || addr < vma->vm_start || + !(vma->vm_flags & VM_PFNMAP)) { + get_page(bad_page); + return page_to_pfn(bad_page); + } + + pfn = ((addr - vma->vm_start) >> PAGE_SHIFT) + vma->vm_pgoff; + BUG_ON(pfn_valid(pfn)); + } else + pfn = page_to_pfn(page[0]); + + return pfn; } EXPORT_SYMBOL_GPL(gfn_to_pfn); struct page *gfn_to_page(struct kvm *kvm, gfn_t gfn) { - return pfn_to_page(gfn_to_pfn(kvm, gfn)); + pfn_t pfn; + + pfn = gfn_to_pfn(kvm, gfn); + if (pfn_valid(pfn)) + return pfn_to_page(pfn); + + WARN_ON(!pfn_valid(pfn)); + + get_page(bad_page); + return bad_page; } EXPORT_SYMBOL_GPL(gfn_to_page); @@ -569,7 +626,8 @@ EXPORT_SYMBOL_GPL(kvm_release_page_clean); void kvm_release_pfn_clean(pfn_t pfn) { - put_page(pfn_to_page(pfn)); + if (pfn_valid(pfn)) + put_page(pfn_to_page(pfn)); } EXPORT_SYMBOL_GPL(kvm_release_pfn_clean); @@ -594,21 +652,25 @@ EXPORT_SYMBOL_GPL(kvm_set_page_dirty); void kvm_set_pfn_dirty(pfn_t pfn) { - struct page *page = pfn_to_page(pfn); - if (!PageReserved(page)) - SetPageDirty(page); + if (pfn_valid(pfn)) { + struct page *page = pfn_to_page(pfn); + if (!PageReserved(page)) + SetPageDirty(page); + } } EXPORT_SYMBOL_GPL(kvm_set_pfn_dirty); void kvm_set_pfn_accessed(pfn_t pfn) { - mark_page_accessed(pfn_to_page(pfn)); + if (pfn_valid(pfn)) + mark_page_accessed(pfn_to_page(pfn)); } EXPORT_SYMBOL_GPL(kvm_set_pfn_accessed); void kvm_get_pfn(pfn_t pfn) { - get_page(pfn_to_page(pfn)); + if (pfn_valid(pfn)) + get_page(pfn_to_page(pfn)); } EXPORT_SYMBOL_GPL(kvm_get_pfn); @@ -799,6 +861,10 @@ static int kvm_vcpu_fault(struct vm_area_struct *vma, struct vm_fault *vmf) else if (vmf->pgoff == KVM_PIO_PAGE_OFFSET) page = virt_to_page(vcpu->arch.pio_data); #endif +#ifdef KVM_COALESCED_MMIO_PAGE_OFFSET + else if (vmf->pgoff == KVM_COALESCED_MMIO_PAGE_OFFSET) + page = virt_to_page(vcpu->kvm->coalesced_mmio_ring); +#endif else return VM_FAULT_SIGBUS; get_page(page); @@ -1121,6 +1187,32 @@ static long kvm_vm_ioctl(struct file *filp, goto out; break; } +#ifdef KVM_COALESCED_MMIO_PAGE_OFFSET + case KVM_REGISTER_COALESCED_MMIO: { + struct kvm_coalesced_mmio_zone zone; + r = -EFAULT; + if (copy_from_user(&zone, argp, sizeof zone)) + goto out; + r = -ENXIO; + r = kvm_vm_ioctl_register_coalesced_mmio(kvm, &zone); + if (r) + goto out; + r = 0; + break; + } + case KVM_UNREGISTER_COALESCED_MMIO: { + struct kvm_coalesced_mmio_zone zone; + r = -EFAULT; + if (copy_from_user(&zone, argp, sizeof zone)) + goto out; + r = -ENXIO; + r = kvm_vm_ioctl_unregister_coalesced_mmio(kvm, &zone); + if (r) + goto out; + r = 0; + break; + } +#endif default: r = kvm_arch_vm_ioctl(filp, ioctl, arg); } @@ -1179,7 +1271,6 @@ static int kvm_dev_ioctl_create_vm(void) static long kvm_dev_ioctl(struct file *filp, unsigned int ioctl, unsigned long arg) { - void __user *argp = (void __user *)arg; long r = -EINVAL; switch (ioctl) { @@ -1196,7 +1287,7 @@ static long kvm_dev_ioctl(struct file *filp, r = kvm_dev_ioctl_create_vm(); break; case KVM_CHECK_EXTENSION: - r = kvm_dev_ioctl_check_extension((long)argp); + r = kvm_dev_ioctl_check_extension(arg); break; case KVM_GET_VCPU_MMAP_SIZE: r = -EINVAL; @@ -1206,6 +1297,9 @@ static long kvm_dev_ioctl(struct file *filp, #ifdef CONFIG_X86 r += PAGE_SIZE; /* pio data page */ #endif +#ifdef KVM_COALESCED_MMIO_PAGE_OFFSET + r += PAGE_SIZE; /* coalesced mmio ring page */ +#endif break; case KVM_TRACE_ENABLE: case KVM_TRACE_PAUSE: @@ -1247,7 +1341,6 @@ static void hardware_disable(void *junk) if (!cpu_isset(cpu, cpus_hardware_enabled)) return; cpu_clear(cpu, cpus_hardware_enabled); - decache_vcpus_on_cpu(cpu); kvm_arch_hardware_disable(NULL); } @@ -1277,6 +1370,18 @@ static int kvm_cpu_hotplug(struct notifier_block *notifier, unsigned long val, return NOTIFY_OK; } + +asmlinkage void kvm_handle_fault_on_reboot(void) +{ + if (kvm_rebooting) + /* spin while reset goes on */ + while (true) + ; + /* Fault while not rebooting. We want the trace. */ + BUG(); +} +EXPORT_SYMBOL_GPL(kvm_handle_fault_on_reboot); + static int kvm_reboot(struct notifier_block *notifier, unsigned long val, void *v) { @@ -1286,6 +1391,7 @@ static int kvm_reboot(struct notifier_block *notifier, unsigned long val, * in vmx root mode. */ printk(KERN_INFO "kvm: exiting hardware virtualization\n"); + kvm_rebooting = true; on_each_cpu(hardware_disable, NULL, 1); } return NOTIFY_OK; @@ -1312,14 +1418,15 @@ void kvm_io_bus_destroy(struct kvm_io_bus *bus) } } -struct kvm_io_device *kvm_io_bus_find_dev(struct kvm_io_bus *bus, gpa_t addr) +struct kvm_io_device *kvm_io_bus_find_dev(struct kvm_io_bus *bus, + gpa_t addr, int len, int is_write) { int i; for (i = 0; i < bus->dev_count; i++) { struct kvm_io_device *pos = bus->devs[i]; - if (pos->in_range(pos, addr)) + if (pos->in_range(pos, addr, len, is_write)) return pos; } diff --git a/virt/kvm/kvm_trace.c b/virt/kvm/kvm_trace.c index 0e495470788d..58141f31ea8f 100644 --- a/virt/kvm/kvm_trace.c +++ b/virt/kvm/kvm_trace.c @@ -72,11 +72,7 @@ static void kvm_add_trace(void *probe_private, void *call_data, rec.cycle_in = p->cycle_in; if (rec.cycle_in) { - u64 cycle = 0; - - cycle = get_cycles(); - rec.u.cycle.cycle_lo = (u32)cycle; - rec.u.cycle.cycle_hi = (u32)(cycle >> 32); + rec.u.cycle.cycle_u64 = get_cycles(); for (i = 0; i < rec.extra_u32; i++) rec.u.cycle.extra_u32[i] = va_arg(*args, u32); @@ -114,8 +110,18 @@ static int kvm_subbuf_start_callback(struct rchan_buf *buf, void *subbuf, { struct kvm_trace *kt; - if (!relay_buf_full(buf)) + if (!relay_buf_full(buf)) { + if (!prev_subbuf) { + /* + * executed only once when the channel is opened + * save metadata as first record + */ + subbuf_start_reserve(buf, sizeof(u32)); + *(u32 *)subbuf = 0x12345678; + } + return 1; + } kt = buf->chan->private_data; atomic_inc(&kt->lost_records); |